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>2022-11-17 14:33:21 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-11-17 14:33:21 +0300
commit7021455bd1ed7b125c55eb1b33c5a01f2bc55ee0 (patch)
tree5bdc2229f5198d516781f8d24eace62fc7e589e9
parent185b095e93520f96e9cfc31d9c3e69b498cdab7c (diff)
Add latest changes from gitlab-org/gitlab@15-6-stable-eev15.6.0-rc42
-rw-r--r--.eslintignore2
-rw-r--r--.eslintrc.yml1
-rw-r--r--.gitlab-ci.yml14
-rw-r--r--.gitlab/CODEOWNERS589
-rw-r--r--.gitlab/ci/as-if-jh.gitlab-ci.yml63
-rw-r--r--.gitlab/ci/build-images.gitlab-ci.yml12
-rw-r--r--.gitlab/ci/dev-fixtures.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/docs.gitlab-ci.yml40
-rw-r--r--.gitlab/ci/frontend.gitlab-ci.yml22
-rw-r--r--.gitlab/ci/glfm.gitlab-ci.yml16
-rw-r--r--.gitlab/ci/global.gitlab-ci.yml54
-rw-r--r--.gitlab/ci/notify.gitlab-ci.yml35
-rw-r--r--.gitlab/ci/package-and-test/main.gitlab-ci.yml34
-rw-r--r--.gitlab/ci/package-and-test/rules.gitlab-ci.yml33
-rw-r--r--.gitlab/ci/package-and-test/variables.gitlab-ci.yml2
-rw-r--r--.gitlab/ci/pages.gitlab-ci.yml17
-rw-r--r--.gitlab/ci/qa.gitlab-ci.yml5
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml70
-rw-r--r--.gitlab/ci/rails/shared.gitlab-ci.yml18
-rw-r--r--.gitlab/ci/reports.gitlab-ci.yml16
-rw-r--r--.gitlab/ci/review-apps/dast-api.gitlab-ci.yml29
-rw-r--r--.gitlab/ci/review-apps/main.gitlab-ci.yml31
-rw-r--r--.gitlab/ci/review-apps/qa.gitlab-ci.yml22
-rw-r--r--.gitlab/ci/review-apps/rules.gitlab-ci.yml35
-rw-r--r--.gitlab/ci/review.gitlab-ci.yml8
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml350
-rw-r--r--.gitlab/ci/static-analysis.gitlab-ci.yml11
-rw-r--r--.gitlab/ci/workhorse.gitlab-ci.yml2
-rw-r--r--.gitlab/issue_templates/Deprecations.md4
-rw-r--r--.gitlab/issue_templates/Experiment Implementation.md2
-rw-r--r--.gitlab/issue_templates/Feature Flag Roll Out.md19
-rw-r--r--.gitlab/issue_templates/Geo Replicate a new Git repository type.md68
-rw-r--r--.gitlab/issue_templates/Geo Replicate a new blob type.md64
-rw-r--r--.gitlab/issue_templates/Security developer workflow.md1
-rw-r--r--.gitlab/merge_request_templates/Documentation.md4
-rw-r--r--.gitlab/merge_request_templates/Pipeline Configuration.md4
-rw-r--r--.gitlab/merge_request_templates/Quarantine End to End Test.md2
-rw-r--r--.gitlab/merge_request_templates/Removals.md2
-rw-r--r--.gitpod.yml49
-rw-r--r--.haml-lint.yml1
-rw-r--r--.haml-lint_todo.yml16
-rw-r--r--.rubocop.yml69
-rw-r--r--.rubocop_todo/api/ensure_string_detail.yml5
-rw-r--r--.rubocop_todo/gitlab/json.yml465
-rw-r--r--.rubocop_todo/gitlab/namespaced_class.yml1
-rw-r--r--.rubocop_todo/gitlab/no_code_coverage_comment.yml1
-rw-r--r--.rubocop_todo/gitlab/service_response.yml1
-rw-r--r--.rubocop_todo/graphql/enum_names.yml37
-rw-r--r--.rubocop_todo/graphql/enum_values.yml37
-rw-r--r--.rubocop_todo/layout/argument_alignment.yml1
-rw-r--r--.rubocop_todo/layout/first_array_element_indentation.yml1
-rw-r--r--.rubocop_todo/layout/line_length.yml18
-rw-r--r--.rubocop_todo/layout/space_in_lambda_literal.yml1
-rw-r--r--.rubocop_todo/layout/space_inside_parens.yml212
-rw-r--r--.rubocop_todo/layout/trailing_whitespace.yml1
-rw-r--r--.rubocop_todo/lint/missing_cop_enable_directive.yml2
-rw-r--r--.rubocop_todo/performance/method_object_as_block.yml1
-rw-r--r--.rubocop_todo/rails/active_record_callbacks_order.yml1
-rw-r--r--.rubocop_todo/rails/content_tag.yml62
-rw-r--r--.rubocop_todo/rails/create_table_with_timestamps.yml69
-rw-r--r--.rubocop_todo/rails/file_path.yml1
-rw-r--r--.rubocop_todo/rails/has_many_or_has_one_dependent.yml154
-rw-r--r--.rubocop_todo/rails/helper_instance_variable.yml1
-rw-r--r--.rubocop_todo/rails/index_with.yml1
-rw-r--r--.rubocop_todo/rails/inverse_of.yml1
-rw-r--r--.rubocop_todo/rails/lexically_scoped_action_filter.yml11
-rw-r--r--.rubocop_todo/rails/negate_include.yml14
-rw-r--r--.rubocop_todo/rails/redundant_foreign_key.yml1
-rw-r--r--.rubocop_todo/rails/skips_model_validations.yml730
-rw-r--r--.rubocop_todo/rails/squished_sql_heredocs.yml215
-rw-r--r--.rubocop_todo/rails/where_exists.yml44
-rw-r--r--.rubocop_todo/rake/require.yml26
-rw-r--r--.rubocop_todo/rspec/context_wording.yml8
-rw-r--r--.rubocop_todo/rspec/empty_line_after_hook.yml1
-rw-r--r--.rubocop_todo/rspec/expect_change.yml2
-rw-r--r--.rubocop_todo/rspec/factory_bot/avoid_create.yml80
-rw-r--r--.rubocop_todo/rspec/factory_bot/strategy_in_callback.yml54
-rw-r--r--.rubocop_todo/rspec/file_path.yml2
-rw-r--r--.rubocop_todo/rspec/multiple_memoized_helpers.yml1
-rw-r--r--.rubocop_todo/rspec/scattered_let.yml1
-rw-r--r--.rubocop_todo/rspec/timecop_travel.yml1
-rw-r--r--.rubocop_todo/style/accessor_grouping.yml1
-rw-r--r--.rubocop_todo/style/bare_percent_literals.yml1
-rw-r--r--.rubocop_todo/style/case_like_if.yml63
-rw-r--r--.rubocop_todo/style/empty_method.yml1
-rw-r--r--.rubocop_todo/style/explicit_block_argument.yml1
-rw-r--r--.rubocop_todo/style/guard_clause.yml2
-rw-r--r--.rubocop_todo/style/if_unless_modifier.yml3
-rw-r--r--.rubocop_todo/style/keyword_parameters_order.yml2
-rw-r--r--.rubocop_todo/style/lambda.yml295
-rw-r--r--.rubocop_todo/style/next.yml28
-rw-r--r--.rubocop_todo/style/numeric_literal_prefix.yml1
-rw-r--r--.rubocop_todo/style/percent_literal_delimiters.yml1
-rw-r--r--.rubocop_todo/style/redundant_begin.yml1
-rw-r--r--.rubocop_todo/style/redundant_interpolation.yml79
-rw-r--r--.rubocop_todo/style/single_argument_dig.yml1
-rw-r--r--.rubocop_todo/style/sole_nested_conditional.yml1
-rw-r--r--.rubocop_todo/style/special_global_vars.yml4
-rw-r--r--.rubocop_todo/style/string_concatenation.yml2
-rw-r--r--.rubocop_todo/style/string_literals_in_interpolation.yml1
-rw-r--r--.secretsignore66
-rw-r--r--CHANGELOG.md49
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--GITLAB_ELASTICSEARCH_INDEXER_VERSION2
-rw-r--r--GITLAB_KAS_VERSION2
-rw-r--r--GITLAB_METRICS_EXPORTER_VERSION2
-rw-r--r--GITLAB_PAGES_VERSION2
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--Gemfile71
-rw-r--r--Gemfile.checksum133
-rw-r--r--Gemfile.lock247
-rw-r--r--app/assets/javascripts/access_tokens/components/new_access_token_app.vue7
-rw-r--r--app/assets/javascripts/admin/application_settings/runner_token_expiration/index.js2
-rw-r--r--app/assets/javascripts/admin/users/components/actions/delete.vue4
-rw-r--r--app/assets/javascripts/admin/users/components/actions/delete_with_contributions.vue48
-rw-r--r--app/assets/javascripts/admin/users/components/associations/associations_list.vue65
-rw-r--r--app/assets/javascripts/admin/users/components/associations/associations_list_item.vue27
-rw-r--r--app/assets/javascripts/admin/users/components/modals/delete_user_modal.vue17
-rw-r--r--app/assets/javascripts/admin/users/components/user_actions.vue1
-rw-r--r--app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue2
-rw-r--r--app/assets/javascripts/analytics/shared/components/daterange.vue4
-rw-r--r--app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue2
-rw-r--r--app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue36
-rw-r--r--app/assets/javascripts/analytics/shared/utils.js28
-rw-r--r--app/assets/javascripts/api/groups_api.js8
-rw-r--r--app/assets/javascripts/api/user_api.js6
-rw-r--r--app/assets/javascripts/artifacts/components/artifact_delete_modal.vue54
-rw-r--r--app/assets/javascripts/artifacts/components/artifact_row.vue87
-rw-r--r--app/assets/javascripts/artifacts/components/artifacts_table_row_details.vue118
-rw-r--r--app/assets/javascripts/artifacts/components/job_artifacts_table.vue337
-rw-r--r--app/assets/javascripts/artifacts/constants.js55
-rw-r--r--app/assets/javascripts/artifacts/graphql/cache_update.js30
-rw-r--r--app/assets/javascripts/artifacts/graphql/mutations/destroy_artifact.mutation.graphql7
-rw-r--r--app/assets/javascripts/artifacts/graphql/queries/get_job_artifacts.query.graphql57
-rw-r--r--app/assets/javascripts/artifacts/index.js29
-rw-r--r--app/assets/javascripts/artifacts/utils.js26
-rw-r--r--app/assets/javascripts/behaviors/copy_code.js3
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_gfm.js2
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js129
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/keybindings.js7
-rw-r--r--app/assets/javascripts/behaviors/shortcuts/shortcuts.js4
-rw-r--r--app/assets/javascripts/blob/blob_blame_link.js14
-rw-r--r--app/assets/javascripts/blob/blob_file_dropzone.js96
-rw-r--r--app/assets/javascripts/blob/blob_line_permalink_updater.js6
-rw-r--r--app/assets/javascripts/blob/components/blob_edit_content.vue66
-rw-r--r--app/assets/javascripts/blob/utils.js26
-rw-r--r--app/assets/javascripts/blob_edit/blob_bundle.js22
-rw-r--r--app/assets/javascripts/blob_edit/edit_blob.js53
-rw-r--r--app/assets/javascripts/boards/components/board_app.vue4
-rw-r--r--app/assets/javascripts/boards/components/board_card.vue4
-rw-r--r--app/assets/javascripts/boards/components/board_card_inner.vue9
-rw-r--r--app/assets/javascripts/boards/components/board_card_move_to_position.vue15
-rw-r--r--app/assets/javascripts/boards/components/board_content.vue99
-rw-r--r--app/assets/javascripts/boards/components/board_filtered_search.vue85
-rw-r--r--app/assets/javascripts/boards/components/board_form.vue2
-rw-r--r--app/assets/javascripts/boards/components/board_list.vue20
-rw-r--r--app/assets/javascripts/boards/components/board_list_header.vue8
-rw-r--r--app/assets/javascripts/boards/components/board_settings_sidebar.vue6
-rw-r--r--app/assets/javascripts/boards/components/board_top_bar.vue10
-rw-r--r--app/assets/javascripts/boards/components/issue_board_filtered_search.vue68
-rw-r--r--app/assets/javascripts/boards/graphql.js15
-rw-r--r--app/assets/javascripts/boards/graphql/board_lists_deferred.query.graphql2
-rw-r--r--app/assets/javascripts/boards/index.js8
-rw-r--r--app/assets/javascripts/boards/stores/actions.js5
-rw-r--r--app/assets/javascripts/branches/components/delete_merged_branches.vue171
-rw-r--r--app/assets/javascripts/branches/init_delete_merged_branches.js23
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/delete_pipeline_schedule_modal.vue45
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue256
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue (renamed from app/assets/javascripts/pipeline_schedules/components/pipeline_schedules_form.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue68
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline.vue (renamed from app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run.vue (renamed from app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_next_run.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner.vue (renamed from app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_owner.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue (renamed from app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue102
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal.vue54
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue (renamed from app/assets/javascripts/pipeline_schedules/components/take_ownership_modal.vue)0
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/delete_pipeline_schedule.mutation.graphql (renamed from app/assets/javascripts/pipeline_schedules/graphql/mutations/delete_pipeline_schedule.mutation.graphql)0
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/take_ownership.mutation.graphql12
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql41
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/mount_pipeline_schedules_app.js34
-rw-r--r--app/assets/javascripts/ci/pipeline_schedules/mount_pipeline_schedules_form_app.js (renamed from app/assets/javascripts/pipeline_schedules/mount_pipeline_schedules_form_app.js)0
-rw-r--r--app/assets/javascripts/ci/runner/admin_runner_show/admin_runner_show_app.vue (renamed from app/assets/javascripts/runner/admin_runner_show/admin_runner_show_app.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/admin_runner_show/index.js (renamed from app/assets/javascripts/runner/admin_runner_show/index.js)0
-rw-r--r--app/assets/javascripts/ci/runner/admin_runners/admin_runners_app.vue229
-rw-r--r--app/assets/javascripts/ci/runner/admin_runners/index.js66
-rw-r--r--app/assets/javascripts/ci/runner/components/cells/link_cell.vue (renamed from app/assets/javascripts/runner/components/cells/link_cell.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/cells/runner_actions_cell.vue (renamed from app/assets/javascripts/runner/components/cells/runner_actions_cell.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/cells/runner_owner_cell.vue (renamed from app/assets/javascripts/runner/components/cells/runner_owner_cell.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/cells/runner_stacked_summary_cell.vue112
-rw-r--r--app/assets/javascripts/ci/runner/components/cells/runner_status_cell.vue46
-rw-r--r--app/assets/javascripts/ci/runner/components/cells/runner_summary_field.vue (renamed from app/assets/javascripts/runner/components/cells/runner_summary_field.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/registration_dropdown.vue (renamed from app/assets/javascripts/runner/components/registration/registration_dropdown.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/registration_token.vue (renamed from app/assets/javascripts/runner/components/registration/registration_token.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/registration/registration_token_reset_dropdown_item.vue141
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_assigned_item.vue (renamed from app/assets/javascripts/runner/components/runner_assigned_item.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_bulk_delete.vue199
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_bulk_delete_checkbox.vue (renamed from app/assets/javascripts/runner/components/runner_bulk_delete_checkbox.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_delete_button.vue156
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_delete_modal.vue (renamed from app/assets/javascripts/runner/components/runner_delete_modal.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_detail.vue (renamed from app/assets/javascripts/runner/components/runner_detail.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_details.vue159
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_edit_button.vue (renamed from app/assets/javascripts/runner/components/runner_edit_button.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_filtered_search_bar.vue100
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_groups.vue (renamed from app/assets/javascripts/runner/components/runner_groups.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_header.vue (renamed from app/assets/javascripts/runner/components/runner_header.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_jobs.vue (renamed from app/assets/javascripts/runner/components/runner_jobs.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_jobs_table.vue114
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_list.vue (renamed from app/assets/javascripts/runner/components/runner_list.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_list_empty_state.vue (renamed from app/assets/javascripts/runner/components/runner_list_empty_state.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_membership_toggle.vue (renamed from app/assets/javascripts/runner/components/runner_membership_toggle.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_name.vue (renamed from app/assets/javascripts/runner/components/runner_name.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_pagination.vue (renamed from app/assets/javascripts/runner/components/runner_pagination.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_pause_button.vue120
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_paused_badge.vue (renamed from app/assets/javascripts/runner/components/runner_paused_badge.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_projects.vue (renamed from app/assets/javascripts/runner/components/runner_projects.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_status_badge.vue (renamed from app/assets/javascripts/runner/components/runner_status_badge.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_status_popover.vue75
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_tag.vue (renamed from app/assets/javascripts/runner/components/runner_tag.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_tags.vue (renamed from app/assets/javascripts/runner/components/runner_tags.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_type_badge.vue (renamed from app/assets/javascripts/runner/components/runner_type_badge.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_type_tabs.vue123
-rw-r--r--app/assets/javascripts/ci/runner/components/runner_update_form.vue225
-rw-r--r--app/assets/javascripts/ci/runner/components/search_tokens/paused_token_config.js (renamed from app/assets/javascripts/runner/components/search_tokens/paused_token_config.js)0
-rw-r--r--app/assets/javascripts/ci/runner/components/search_tokens/status_token_config.js42
-rw-r--r--app/assets/javascripts/ci/runner/components/search_tokens/tag_token.vue (renamed from app/assets/javascripts/runner/components/search_tokens/tag_token.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/search_tokens/tag_token_config.js (renamed from app/assets/javascripts/runner/components/search_tokens/tag_token_config.js)0
-rw-r--r--app/assets/javascripts/ci/runner/components/search_tokens/upgrade_status_token_config.js (renamed from app/assets/javascripts/runner/components/search_tokens/upgrade_status_token_config.js)0
-rw-r--r--app/assets/javascripts/ci/runner/components/stat/runner_count.vue104
-rw-r--r--app/assets/javascripts/ci/runner/components/stat/runner_single_stat.vue (renamed from app/assets/javascripts/runner/components/stat/runner_single_stat.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/components/stat/runner_stats.vue89
-rw-r--r--app/assets/javascripts/ci/runner/constants.js (renamed from app/assets/javascripts/runner/constants.js)0
-rw-r--r--app/assets/javascripts/ci/runner/graphql/edit/runner_fields.fragment.graphql (renamed from app/assets/javascripts/runner/graphql/edit/runner_fields.fragment.graphql)0
-rw-r--r--app/assets/javascripts/ci/runner/graphql/edit/runner_fields_shared.fragment.graphql (renamed from app/assets/javascripts/runner/graphql/edit/runner_fields_shared.fragment.graphql)0
-rw-r--r--app/assets/javascripts/ci/runner/graphql/edit/runner_form.query.graphql7
-rw-r--r--app/assets/javascripts/ci/runner/graphql/edit/runner_update.mutation.graphql13
-rw-r--r--app/assets/javascripts/ci/runner/graphql/list/all_runners.query.graphql29
-rw-r--r--app/assets/javascripts/ci/runner/graphql/list/all_runners_connection.fragment.graphql13
-rw-r--r--app/assets/javascripts/ci/runner/graphql/list/all_runners_count.query.graphql (renamed from app/assets/javascripts/runner/graphql/list/all_runners_count.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/runner/graphql/list/bulk_runner_delete.mutation.graphql (renamed from app/assets/javascripts/runner/graphql/list/bulk_runner_delete.mutation.graphql)0
-rw-r--r--app/assets/javascripts/ci/runner/graphql/list/checked_runner_ids.query.graphql (renamed from app/assets/javascripts/runner/graphql/list/checked_runner_ids.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/runner/graphql/list/group_runner_connection.fragment.graphql16
-rw-r--r--app/assets/javascripts/ci/runner/graphql/list/group_runners.query.graphql35
-rw-r--r--app/assets/javascripts/ci/runner/graphql/list/group_runners_count.query.graphql (renamed from app/assets/javascripts/runner/graphql/list/group_runners_count.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/runner/graphql/list/list_item.fragment.graphql (renamed from app/assets/javascripts/runner/graphql/list/list_item.fragment.graphql)0
-rw-r--r--app/assets/javascripts/ci/runner/graphql/list/list_item_shared.fragment.graphql (renamed from app/assets/javascripts/runner/graphql/list/list_item_shared.fragment.graphql)0
-rw-r--r--app/assets/javascripts/ci/runner/graphql/list/local_state.js75
-rw-r--r--app/assets/javascripts/ci/runner/graphql/list/runners_registration_token_reset.mutation.graphql (renamed from app/assets/javascripts/runner/graphql/list/runners_registration_token_reset.mutation.graphql)0
-rw-r--r--app/assets/javascripts/ci/runner/graphql/list/typedefs.graphql (renamed from app/assets/javascripts/runner/graphql/list/typedefs.graphql)0
-rw-r--r--app/assets/javascripts/ci/runner/graphql/shared/runner_delete.mutation.graphql (renamed from app/assets/javascripts/runner/graphql/shared/runner_delete.mutation.graphql)0
-rw-r--r--app/assets/javascripts/ci/runner/graphql/shared/runner_toggle_active.mutation.graphql (renamed from app/assets/javascripts/runner/graphql/shared/runner_toggle_active.mutation.graphql)0
-rw-r--r--app/assets/javascripts/ci/runner/graphql/show/runner.query.graphql7
-rw-r--r--app/assets/javascripts/ci/runner/graphql/show/runner_details.fragment.graphql (renamed from app/assets/javascripts/runner/graphql/show/runner_details.fragment.graphql)0
-rw-r--r--app/assets/javascripts/ci/runner/graphql/show/runner_details_shared.fragment.graphql (renamed from app/assets/javascripts/runner/graphql/show/runner_details_shared.fragment.graphql)0
-rw-r--r--app/assets/javascripts/ci/runner/graphql/show/runner_jobs.query.graphql38
-rw-r--r--app/assets/javascripts/ci/runner/graphql/show/runner_projects.query.graphql (renamed from app/assets/javascripts/runner/graphql/show/runner_projects.query.graphql)0
-rw-r--r--app/assets/javascripts/ci/runner/group_runner_show/group_runner_show_app.vue (renamed from app/assets/javascripts/runner/group_runner_show/group_runner_show_app.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/group_runner_show/index.js (renamed from app/assets/javascripts/runner/group_runner_show/index.js)0
-rw-r--r--app/assets/javascripts/ci/runner/group_runners/group_runners_app.vue278
-rw-r--r--app/assets/javascripts/ci/runner/group_runners/index.js (renamed from app/assets/javascripts/runner/group_runners/index.js)0
-rw-r--r--app/assets/javascripts/ci/runner/local_storage_alert/constants.js (renamed from app/assets/javascripts/runner/local_storage_alert/constants.js)0
-rw-r--r--app/assets/javascripts/ci/runner/local_storage_alert/save_alert_to_local_storage.js (renamed from app/assets/javascripts/runner/local_storage_alert/save_alert_to_local_storage.js)0
-rw-r--r--app/assets/javascripts/ci/runner/local_storage_alert/show_alert_from_local_storage.js (renamed from app/assets/javascripts/runner/local_storage_alert/show_alert_from_local_storage.js)0
-rw-r--r--app/assets/javascripts/ci/runner/runner_edit/index.js (renamed from app/assets/javascripts/runner/runner_edit/index.js)0
-rw-r--r--app/assets/javascripts/ci/runner/runner_edit/runner_edit_app.vue (renamed from app/assets/javascripts/runner/runner_edit/runner_edit_app.vue)0
-rw-r--r--app/assets/javascripts/ci/runner/runner_search_utils.js (renamed from app/assets/javascripts/runner/runner_search_utils.js)0
-rw-r--r--app/assets/javascripts/ci/runner/runner_update_form_utils.js (renamed from app/assets/javascripts/runner/runner_update_form_utils.js)0
-rw-r--r--app/assets/javascripts/ci/runner/sentry_utils.js (renamed from app/assets/javascripts/runner/sentry_utils.js)0
-rw-r--r--app/assets/javascripts/ci/runner/utils.js (renamed from app/assets/javascripts/runner/utils.js)0
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_admin_variables.vue139
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_group_variables.vue132
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_project_variables.vue159
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue62
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_popover.vue58
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_settings.vue6
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_shared.vue232
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue116
-rw-r--r--app/assets/javascripts/ci_variable_list/components/legacy_ci_environments_dropdown.vue81
-rw-r--r--app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_modal.vue428
-rw-r--r--app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_settings.vue32
-rw-r--r--app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_table.vue199
-rw-r--r--app/assets/javascripts/ci_variable_list/graphql/mutations/admin_add_variable.mutation.graphql2
-rw-r--r--app/assets/javascripts/ci_variable_list/graphql/mutations/admin_delete_variable.mutation.graphql2
-rw-r--r--app/assets/javascripts/ci_variable_list/graphql/mutations/admin_update_variable.mutation.graphql2
-rw-r--r--app/assets/javascripts/ci_variable_list/graphql/mutations/group_add_variable.mutation.graphql11
-rw-r--r--app/assets/javascripts/ci_variable_list/graphql/mutations/group_delete_variable.mutation.graphql11
-rw-r--r--app/assets/javascripts/ci_variable_list/graphql/mutations/group_update_variable.mutation.graphql11
-rw-r--r--app/assets/javascripts/ci_variable_list/graphql/mutations/project_add_variable.mutation.graphql11
-rw-r--r--app/assets/javascripts/ci_variable_list/graphql/mutations/project_delete_variable.mutation.graphql6
-rw-r--r--app/assets/javascripts/ci_variable_list/graphql/mutations/project_update_variable.mutation.graphql6
-rw-r--r--app/assets/javascripts/ci_variable_list/graphql/settings.js60
-rw-r--r--app/assets/javascripts/ci_variable_list/index.js62
-rw-r--r--app/assets/javascripts/ci_variable_list/store/actions.js208
-rw-r--r--app/assets/javascripts/ci_variable_list/store/getters.js6
-rw-r--r--app/assets/javascripts/ci_variable_list/store/index.js19
-rw-r--r--app/assets/javascripts/ci_variable_list/store/mutation_types.js33
-rw-r--r--app/assets/javascripts/ci_variable_list/store/mutations.js128
-rw-r--r--app/assets/javascripts/ci_variable_list/store/state.js26
-rw-r--r--app/assets/javascripts/ci_variable_list/store/utils.js45
-rw-r--r--app/assets/javascripts/clusters_list/components/delete_agent_button.vue7
-rw-r--r--app/assets/javascripts/content_editor/components/bubble_menus/formatting_bubble_menu.vue10
-rw-r--r--app/assets/javascripts/content_editor/components/suggestions_dropdown.vue8
-rw-r--r--app/assets/javascripts/content_editor/components/toolbar_button.vue2
-rw-r--r--app/assets/javascripts/content_editor/content_editor.stories.js1
-rw-r--r--app/assets/javascripts/content_editor/extensions/highlight.js19
-rw-r--r--app/assets/javascripts/content_editor/extensions/html_marks.js1
-rw-r--r--app/assets/javascripts/content_editor/extensions/suggestions.js2
-rw-r--r--app/assets/javascripts/content_editor/services/create_content_editor.js2
-rw-r--r--app/assets/javascripts/content_editor/services/markdown_serializer.js2
-rw-r--r--app/assets/javascripts/cycle_analytics/components/filter_bar.vue13
-rw-r--r--app/assets/javascripts/deploy_tokens/components/new_deploy_token.vue17
-rw-r--r--app/assets/javascripts/design_management/pages/index.vue2
-rw-r--r--app/assets/javascripts/diffs/components/app.vue10
-rw-r--r--app/assets/javascripts/diffs/components/diff_discussions.vue1
-rw-r--r--app/assets/javascripts/diffs/components/diff_file.vue4
-rw-r--r--app/assets/javascripts/diffs/components/diff_row_utils.js25
-rw-r--r--app/assets/javascripts/diffs/store/actions.js14
-rw-r--r--app/assets/javascripts/diffs/store/utils.js11
-rw-r--r--app/assets/javascripts/diffs/utils/tree_worker_utils.js9
-rw-r--r--app/assets/javascripts/dirty_submit/dirty_submit_form.js2
-rw-r--r--app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js58
-rw-r--r--app/assets/javascripts/editor/schema/ci.json214
-rw-r--r--app/assets/javascripts/environments/components/environment_actions.vue3
-rw-r--r--app/assets/javascripts/environments/components/environment_rollback.vue15
-rw-r--r--app/assets/javascripts/environments/graphql/queries/environment_to_rollback.query.graphql1
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_user.js3
-rw-r--r--app/assets/javascripts/filtered_search/droplab/plugins/ajax_filter.js3
-rw-r--r--app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js24
-rw-r--r--app/assets/javascripts/flash.js3
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js43
-rw-r--r--app/assets/javascripts/gitlab_version_check.js20
-rw-r--r--app/assets/javascripts/gitlab_version_check/components/gitlab_version_check_badge.vue73
-rw-r--r--app/assets/javascripts/gitlab_version_check/constants.js9
-rw-r--r--app/assets/javascripts/gitlab_version_check/index.js50
-rw-r--r--app/assets/javascripts/gl_field_errors.js11
-rw-r--r--app/assets/javascripts/google_cloud/service_accounts/list.vue12
-rw-r--r--app/assets/javascripts/google_tag_manager/index.js29
-rw-r--r--app/assets/javascripts/graphql_shared/issuable_client.js38
-rw-r--r--app/assets/javascripts/graphql_shared/possible_types.json7
-rw-r--r--app/assets/javascripts/groups/components/overview_tabs.vue5
-rw-r--r--app/assets/javascripts/groups/components/transfer_group_form.vue52
-rw-r--r--app/assets/javascripts/groups/init_transfer_group_form.js22
-rw-r--r--app/assets/javascripts/groups_projects/components/transfer_locations.vue282
-rw-r--r--app/assets/javascripts/groups_select.js37
-rw-r--r--app/assets/javascripts/ide/components/ide.vue14
-rw-r--r--app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue15
-rw-r--r--app/assets/javascripts/ide/components/panes/right.vue17
-rw-r--r--app/assets/javascripts/ide/components/switch_editors/switch_editors_view.vue103
-rw-r--r--app/assets/javascripts/ide/constants.js1
-rw-r--r--app/assets/javascripts/ide/index.js4
-rw-r--r--app/assets/javascripts/ide/stores/mutations.js2
-rw-r--r--app/assets/javascripts/ide/stores/state.js2
-rw-r--r--app/assets/javascripts/import_entities/import_groups/components/import_table.vue19
-rw-r--r--app/assets/javascripts/import_entities/import_projects/components/advanced_settings.vue2
-rw-r--r--app/assets/javascripts/import_entities/import_projects/index.js2
-rw-r--r--app/assets/javascripts/integrations/constants.js2
-rw-r--r--app/assets/javascripts/integrations/edit/components/integration_form.vue19
-rw-r--r--app/assets/javascripts/integrations/edit/components/reset_confirmation_modal.vue22
-rw-r--r--app/assets/javascripts/integrations/edit/components/trigger_fields.vue4
-rw-r--r--app/assets/javascripts/integrations/edit/index.js4
-rw-r--r--app/assets/javascripts/invite_members/components/invite_members_modal.vue36
-rw-r--r--app/assets/javascripts/invite_members/components/invite_modal_base.vue164
-rw-r--r--app/assets/javascripts/invite_members/components/user_limit_notification.vue105
-rw-r--r--app/assets/javascripts/invite_members/constants.js16
-rw-r--r--app/assets/javascripts/issuable/bulk_update_sidebar/components/graphql/mutations/move_issue.mutation.graphql5
-rw-r--r--app/assets/javascripts/issuable/bulk_update_sidebar/components/move_issues_button.vue171
-rw-r--r--app/assets/javascripts/issuable/bulk_update_sidebar/index.js31
-rw-r--r--app/assets/javascripts/issuable/bulk_update_sidebar/issuable_bulk_update_sidebar.js33
-rw-r--r--app/assets/javascripts/issuable/components/related_issuable_item.vue1
-rw-r--r--app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue56
-rw-r--r--app/assets/javascripts/issues/dashboard/index.js25
-rw-r--r--app/assets/javascripts/issues/index.js4
-rw-r--r--app/assets/javascripts/issues/list/components/issues_list_app.vue56
-rw-r--r--app/assets/javascripts/issues/list/constants.js37
-rw-r--r--app/assets/javascripts/issues/list/graphql.js25
-rw-r--r--app/assets/javascripts/issues/list/index.js27
-rw-r--r--app/assets/javascripts/issues/list/queries/get_issues.query.graphql3
-rw-r--r--app/assets/javascripts/issues/list/queries/get_issues_counts.query.graphql7
-rw-r--r--app/assets/javascripts/issues/list/utils.js33
-rw-r--r--app/assets/javascripts/issues/show/components/fields/description.vue2
-rw-r--r--app/assets/javascripts/issues/show/components/fields/type.vue2
-rw-r--r--app/assets/javascripts/issues/show/components/header_actions.vue5
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/constants.js6
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue29
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/legacy_sidebar_header.vue9
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/sidebar.vue13
-rw-r--r--app/assets/javascripts/jobs/components/table/cells/duration_cell.vue27
-rw-r--r--app/assets/javascripts/jobs/constants.js1
-rw-r--r--app/assets/javascripts/lazy_loader.js3
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js60
-rw-r--r--app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_action.js57
-rw-r--r--app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal.js78
-rw-r--r--app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js19
-rw-r--r--app/assets/javascripts/lib/utils/dom_utils.js12
-rw-r--r--app/assets/javascripts/lib/utils/unit_format/index.js17
-rw-r--r--app/assets/javascripts/lib/utils/url_utility.js2
-rw-r--r--app/assets/javascripts/members/components/action_buttons/access_request_action_buttons.vue9
-rw-r--r--app/assets/javascripts/members/components/members_tabs.vue16
-rw-r--r--app/assets/javascripts/members/index.js2
-rw-r--r--app/assets/javascripts/merge_request_tabs.js41
-rw-r--r--app/assets/javascripts/milestones/milestone_select.js273
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/components/experiment.vue36
-rw-r--r--app/assets/javascripts/ml/experiment_tracking/components/incubation_alert.vue48
-rw-r--r--app/assets/javascripts/notebook/cells/markdown.vue7
-rw-r--r--app/assets/javascripts/notebook/cells/output/index.vue9
-rw-r--r--app/assets/javascripts/notebook/cells/output/markdown.vue42
-rw-r--r--app/assets/javascripts/notes/components/discussion_notes.vue7
-rw-r--r--app/assets/javascripts/notes/components/note_header.vue2
-rw-r--r--app/assets/javascripts/notes/components/noteable_discussion.vue6
-rw-r--r--app/assets/javascripts/notes/components/noteable_note.vue7
-rw-r--r--app/assets/javascripts/notes/components/notes_activity_header.vue2
-rw-r--r--app/assets/javascripts/notes/components/notes_app.vue12
-rw-r--r--app/assets/javascripts/notes/mixins/discussion_navigation.js14
-rw-r--r--app/assets/javascripts/notes/stores/getters.js6
-rw-r--r--app/assets/javascripts/observability/components/observability_app.vue42
-rw-r--r--app/assets/javascripts/observability/index.js28
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue22
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue9
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/index.js18
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue8
-rw-r--r--app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list.vue46
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/delete_modal.vue61
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/details/package_versions_list.vue57
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/list/package_list_row.vue26
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list.vue112
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/constants.js10
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/graphql/mutations/destroy_packages.mutation.graphql5
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql16
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/index.js1
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue62
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/pages/list.vue98
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/group/components/forwarding_settings.vue91
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/group/components/group_settings_app.vue8
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/group/components/packages_forwarding_settings.vue190
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/group/constants.js56
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/group/graphql/fragments/package_settings_fields.fragment.graphql15
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql7
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/group/graphql/mutations/update_package_forwarding_settings.mutation.graphql16
-rw-r--r--app/assets/javascripts/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql7
-rw-r--r--app/assets/javascripts/packages_and_registries/shared/components/delete_package_modal.vue83
-rw-r--r--app/assets/javascripts/packages_and_registries/shared/constants/package_registry.js6
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/general/components/signup_form.vue47
-rw-r--r--app/assets/javascripts/pages/admin/jobs/index/components/constants.js11
-rw-r--r--app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue31
-rw-r--r--app/assets/javascripts/pages/admin/jobs/index/index.js8
-rw-r--r--app/assets/javascripts/pages/admin/runners/edit/index.js2
-rw-r--r--app/assets/javascripts/pages/admin/runners/index/index.js2
-rw-r--r--app/assets/javascripts/pages/admin/runners/show/index.js2
-rw-r--r--app/assets/javascripts/pages/dashboard/issues/index.js3
-rw-r--r--app/assets/javascripts/pages/groups/observability/dashboards/index.js3
-rw-r--r--app/assets/javascripts/pages/groups/observability/explore/index.js3
-rw-r--r--app/assets/javascripts/pages/groups/observability/manage/index.js3
-rw-r--r--app/assets/javascripts/pages/groups/runners/edit/index.js2
-rw-r--r--app/assets/javascripts/pages/groups/runners/index/index.js2
-rw-r--r--app/assets/javascripts/pages/groups/runners/show/index.js2
-rw-r--r--app/assets/javascripts/pages/groups/shared/group_details.js13
-rw-r--r--app/assets/javascripts/pages/groups/shared/group_tabs.js136
-rw-r--r--app/assets/javascripts/pages/profiles/init_timezone_dropdown.js4
-rw-r--r--app/assets/javascripts/pages/projects/artifacts/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/branches/index/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/hooks/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/init_blob.js3
-rw-r--r--app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue1
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js4
-rw-r--r--app/assets/javascripts/pages/projects/ml/experiments/show/index.js31
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js6
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js2
-rw-r--r--app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js11
-rw-r--r--app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue25
-rw-r--r--app/assets/javascripts/pages/projects/show/index.js8
-rw-r--r--app/assets/javascripts/pages/projects/tree/show/index.js2
-rw-r--r--app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue2
-rw-r--r--app/assets/javascripts/persistent_user_callouts.js6
-rw-r--r--app/assets/javascripts/pipeline_editor/components/pipeline_editor_tabs.vue1
-rw-r--r--app/assets/javascripts/pipeline_schedules/components/pipeline_schedules.vue134
-rw-r--r--app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue66
-rw-r--r--app/assets/javascripts/pipeline_schedules/components/table/pipeline_schedules_table.vue95
-rw-r--r--app/assets/javascripts/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql40
-rw-r--r--app/assets/javascripts/pipeline_schedules/mount_pipeline_schedules_app.js32
-rw-r--r--app/assets/javascripts/pipelines/components/dag/dag.vue4
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_mini_graph/pipeline_stage.vue15
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_tabs.vue62
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue16
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue14
-rw-r--r--app/assets/javascripts/pipelines/components/test_reports/test_case_details.vue1
-rw-r--r--app/assets/javascripts/pipelines/components/test_reports/test_suite_table.vue8
-rw-r--r--app/assets/javascripts/pipelines/constants.js3
-rw-r--r--app/assets/javascripts/pipelines/pipeline_details_bundle.js10
-rw-r--r--app/assets/javascripts/pipelines/pipeline_tabs.js15
-rw-r--r--app/assets/javascripts/pipelines/routes.js20
-rw-r--r--app/assets/javascripts/pipelines/utils.js17
-rw-r--r--app/assets/javascripts/projects/commit_box/info/components/commit_box_pipeline_mini_graph.vue2
-rw-r--r--app/assets/javascripts/projects/commits/store/actions.js3
-rw-r--r--app/assets/javascripts/projects/compare/components/app.vue4
-rw-r--r--app/assets/javascripts/projects/components/shared/delete_button.vue17
-rw-r--r--app/assets/javascripts/projects/new/components/new_project_push_tip_popover.vue2
-rw-r--r--app/assets/javascripts/projects/pipelines/charts/components/app.vue26
-rw-r--r--app/assets/javascripts/projects/pipelines/charts/constants.js4
-rw-r--r--app/assets/javascripts/projects/settings/api/access_dropdown_api.js3
-rw-r--r--app/assets/javascripts/projects/settings/branch_rules/components/view/constants.js9
-rw-r--r--app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue43
-rw-r--r--app/assets/javascripts/projects/settings/branch_rules/components/view/protection.vue14
-rw-r--r--app/assets/javascripts/projects/settings/branch_rules/components/view/protection_row.vue13
-rw-r--r--app/assets/javascripts/projects/settings/branch_rules/mount_branch_rules.js3
-rw-r--r--app/assets/javascripts/projects/settings/branch_rules/queries/branch_rules_details.query.graphql24
-rw-r--r--app/assets/javascripts/projects/settings/components/transfer_project_form.vue161
-rw-r--r--app/assets/javascripts/projects/settings/init_transfer_project_form.js6
-rw-r--r--app/assets/javascripts/projects/settings/repository/branch_rules/app.vue10
-rw-r--r--app/assets/javascripts/projects/settings/repository/branch_rules/components/branch_rule.vue62
-rw-r--r--app/assets/javascripts/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql15
-rw-r--r--app/assets/javascripts/projects/settings_service_desk/components/service_desk_setting.vue23
-rw-r--r--app/assets/javascripts/related_issues/components/related_issues_block.vue56
-rw-r--r--app/assets/javascripts/related_issues/components/related_issues_root.vue10
-rw-r--r--app/assets/javascripts/related_issues/constants.js5
-rw-r--r--app/assets/javascripts/related_issues/index.js1
-rw-r--r--app/assets/javascripts/releases/components/app_edit_new.vue4
-rw-r--r--app/assets/javascripts/releases/components/asset_links_form.vue16
-rw-r--r--app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue84
-rw-r--r--app/assets/javascripts/reports/components/issue_body.js2
-rw-r--r--app/assets/javascripts/reports/components/report_section.vue9
-rw-r--r--app/assets/javascripts/reports/grouped_test_report/components/modal.vue74
-rw-r--r--app/assets/javascripts/reports/grouped_test_report/components/test_issue_body.vue64
-rw-r--r--app/assets/javascripts/reports/grouped_test_report/grouped_test_reports_app.vue204
-rw-r--r--app/assets/javascripts/reports/grouped_test_report/store/actions.js82
-rw-r--r--app/assets/javascripts/reports/grouped_test_report/store/getters.js13
-rw-r--r--app/assets/javascripts/reports/grouped_test_report/store/index.js17
-rw-r--r--app/assets/javascripts/reports/grouped_test_report/store/mutation_types.js7
-rw-r--r--app/assets/javascripts/reports/grouped_test_report/store/mutations.js79
-rw-r--r--app/assets/javascripts/reports/grouped_test_report/store/state.js71
-rw-r--r--app/assets/javascripts/reports/grouped_test_report/store/utils.js111
-rw-r--r--app/assets/javascripts/repository/components/blob_content_viewer.vue2
-rw-r--r--app/assets/javascripts/repository/constants.js4
-rw-r--r--app/assets/javascripts/runner/admin_runners/admin_runners_app.vue233
-rw-r--r--app/assets/javascripts/runner/admin_runners/index.js66
-rw-r--r--app/assets/javascripts/runner/components/cells/runner_stacked_summary_cell.vue112
-rw-r--r--app/assets/javascripts/runner/components/cells/runner_status_cell.vue46
-rw-r--r--app/assets/javascripts/runner/components/registration/registration_token_reset_dropdown_item.vue141
-rw-r--r--app/assets/javascripts/runner/components/runner_bulk_delete.vue196
-rw-r--r--app/assets/javascripts/runner/components/runner_delete_button.vue153
-rw-r--r--app/assets/javascripts/runner/components/runner_details.vue159
-rw-r--r--app/assets/javascripts/runner/components/runner_filtered_search_bar.vue100
-rw-r--r--app/assets/javascripts/runner/components/runner_jobs_table.vue95
-rw-r--r--app/assets/javascripts/runner/components/runner_pause_button.vue120
-rw-r--r--app/assets/javascripts/runner/components/runner_stacked_layout_banner.vue58
-rw-r--r--app/assets/javascripts/runner/components/runner_status_popover.vue75
-rw-r--r--app/assets/javascripts/runner/components/runner_type_tabs.vue123
-rw-r--r--app/assets/javascripts/runner/components/runner_update_form.vue225
-rw-r--r--app/assets/javascripts/runner/components/search_tokens/status_token_config.js40
-rw-r--r--app/assets/javascripts/runner/components/stat/runner_count.vue104
-rw-r--r--app/assets/javascripts/runner/components/stat/runner_stats.vue89
-rw-r--r--app/assets/javascripts/runner/graphql/edit/runner_form.query.graphql7
-rw-r--r--app/assets/javascripts/runner/graphql/edit/runner_update.mutation.graphql13
-rw-r--r--app/assets/javascripts/runner/graphql/list/all_runners.query.graphql29
-rw-r--r--app/assets/javascripts/runner/graphql/list/all_runners_connection.fragment.graphql13
-rw-r--r--app/assets/javascripts/runner/graphql/list/group_runner_connection.fragment.graphql16
-rw-r--r--app/assets/javascripts/runner/graphql/list/group_runners.query.graphql35
-rw-r--r--app/assets/javascripts/runner/graphql/list/local_state.js75
-rw-r--r--app/assets/javascripts/runner/graphql/show/runner.query.graphql7
-rw-r--r--app/assets/javascripts/runner/graphql/show/runner_jobs.query.graphql36
-rw-r--r--app/assets/javascripts/runner/group_runners/group_runners_app.vue277
-rw-r--r--app/assets/javascripts/search/sidebar/components/app.vue49
-rw-r--r--app/assets/javascripts/search/sidebar/components/results_filters.vue49
-rw-r--r--app/assets/javascripts/search/sidebar/components/scope_navigation.vue66
-rw-r--r--app/assets/javascripts/search/sidebar/constants/index.js11
-rw-r--r--app/assets/javascripts/search/store/actions.js18
-rw-r--r--app/assets/javascripts/search/store/index.js4
-rw-r--r--app/assets/javascripts/search/store/mutation_types.js1
-rw-r--r--app/assets/javascripts/search/store/mutations.js4
-rw-r--r--app/assets/javascripts/search/store/state.js3
-rw-r--r--app/assets/javascripts/self_monitor/components/self_monitor_form.vue16
-rw-r--r--app/assets/javascripts/self_monitor/store/actions.js4
-rw-r--r--app/assets/javascripts/sentry/constants.js43
-rw-r--r--app/assets/javascripts/sentry/sentry_config.js45
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignee_title.vue1
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignees.vue1
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue1
-rw-r--r--app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue115
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue35
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers_inputs.vue34
-rw-r--r--app/assets/javascripts/sidebar/components/sidebar_dropdown.vue252
-rw-r--r--app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue185
-rw-r--r--app/assets/javascripts/sidebar/constants.js11
-rw-r--r--app/assets/javascripts/sidebar/mount_milestone_sidebar.js2
-rw-r--r--app/assets/javascripts/sidebar/mount_sidebar.js344
-rw-r--r--app/assets/javascripts/sidebar/stores/sidebar_store.js4
-rw-r--r--app/assets/javascripts/token_access/components/token_access.vue6
-rw-r--r--app/assets/javascripts/token_access/components/token_projects_table.vue21
-rw-r--r--app/assets/javascripts/token_access/graphql/queries/get_projects_with_ci_job_token_scope.query.graphql4
-rw-r--r--app/assets/javascripts/tracking/tracker.js6
-rw-r--r--app/assets/javascripts/users_select/constants.js11
-rw-r--r--app/assets/javascripts/users_select/index.js214
-rw-r--r--app/assets/javascripts/users_select/utils.js14
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_info.vue28
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_list.vue1
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_view_button.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/extensions/container.js42
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue4
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_container.vue8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/report_widget_container.vue18
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/state_container.vue21
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/merge_checks_failed.vue3
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue53
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue8
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue54
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue15
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue26
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/new_ready_to_merge.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/ready_to_merge.vue155
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue22
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/work_in_progress.vue44
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/widget/dynamic_content.vue1
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/widget/status_icon.vue36
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/widget/widget.vue94
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue83
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/constants.js1
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue90
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/stores/mr_widget_store.js21
-rw-r--r--app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue7
-rw-r--r--app/assets/javascripts/vue_shared/alert_details/index.js12
-rw-r--r--app/assets/javascripts/vue_shared/alert_details/router.js21
-rw-r--r--app/assets/javascripts/vue_shared/components/blob_viewers/rich_viewer.vue8
-rw-r--r--app/assets/javascripts/vue_shared/components/code_block.stories.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.stories.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.stories.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js28
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue8
-rw-r--r--app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/gitlab_version_check.vue89
-rw-r--r--app/assets/javascripts/vue_shared/components/group_select/constants.js6
-rw-r--r--app/assets/javascripts/vue_shared/components/group_select/group_select.vue195
-rw-r--r--app/assets/javascripts/vue_shared/components/help_popover.vue7
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue26
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown_drawer/makrdown_drawer.stories.js54
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown_drawer/markdown_drawer.vue117
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown_drawer/utils/fetch.js32
-rw-r--r--app/assets/javascripts/vue_shared/components/namespace_select/namespace_select_deprecated.vue212
-rw-r--r--app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/pagination_bar/pagination_bar.stories.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/epics_select/epics_select_bundle.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/health_status_select/health_status_bundle.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/issuable_move_dropdown.vue9
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/iterations_dropdown_bundle.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/label_item.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue5
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/queries/merge_request_reviewers.subscription.graphql22
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/todo_toggle/todo_button.stories.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue90
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue10
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/plugins/link_dependencies.js8
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/composer_json_linker.js49
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/dependency_linker_util.js22
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/gemfile_linker.js25
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/godeps_json_linker.js64
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker.js32
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/plugins/wrap_child_nodes.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue5
-rw-r--r--app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.stories.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/user_deletion_obstacles/user_deletion_obstacles_list.stories.js2
-rw-r--r--app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue11
-rw-r--r--app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue8
-rw-r--r--app/assets/javascripts/vue_shared/security_reports/store/utils.js2
-rw-r--r--app/assets/javascripts/webhooks/components/form_url_app.vue92
-rw-r--r--app/assets/javascripts/webhooks/components/form_url_mask_item.vue46
-rw-r--r--app/assets/javascripts/webhooks/components/push_events.vue112
-rw-r--r--app/assets/javascripts/webhooks/constants.js19
-rw-r--r--app/assets/javascripts/webhooks/index.js2
-rw-r--r--app/assets/javascripts/webhooks/webhook.js23
-rw-r--r--app/assets/javascripts/work_items/components/work_item_description.vue203
-rw-r--r--app/assets/javascripts/work_items/components/work_item_description_rendered.vue117
-rw-r--r--app/assets/javascripts/work_items/components/work_item_detail.vue91
-rw-r--r--app/assets/javascripts/work_items/components/work_item_due_date.vue4
-rw-r--r--app/assets/javascripts/work_items/components/work_item_labels.vue22
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/index.js6
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue56
-rw-r--r--app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue192
-rw-r--r--app/assets/javascripts/work_items/components/work_item_milestone.vue37
-rw-r--r--app/assets/javascripts/work_items/constants.js5
-rw-r--r--app/assets/javascripts/work_items/graphql/get_issue_details.query.graphql3
-rw-r--r--app/assets/javascripts/work_items/graphql/milestone.fragment.graphql5
-rw-r--r--app/assets/javascripts/work_items/graphql/project_work_items.query.graphql19
-rw-r--r--app/assets/javascripts/work_items/graphql/typedefs.graphql11
-rw-r--r--app/assets/javascripts/work_items/graphql/work_item.fragment.graphql1
-rw-r--r--app/assets/javascripts/work_items/graphql/work_item.query.graphql11
-rw-r--r--app/assets/javascripts/work_items/graphql/work_item_by_iid.query.graphql12
-rw-r--r--app/assets/javascripts/work_items/graphql/work_item_description.subscription.graphql20
-rw-r--r--app/assets/javascripts/work_items/graphql/work_item_milestone.subscription.graphql17
-rw-r--r--app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql7
-rw-r--r--app/assets/javascripts/work_items/index.js9
-rw-r--r--app/assets/javascripts/work_items/pages/create_work_item.vue46
-rw-r--r--app/assets/javascripts/work_items/pages/work_item_root.vue8
-rw-r--r--app/assets/javascripts/work_items/router/index.js2
-rw-r--r--app/assets/javascripts/work_items/router/routes.js35
-rw-r--r--app/assets/javascripts/work_items/utils.js6
-rw-r--r--app/assets/javascripts/work_items_hierarchy/components/app.vue2
-rw-r--r--app/assets/stylesheets/_page_specific_files.scss3
-rw-r--r--app/assets/stylesheets/framework/calendar.scss2
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss4
-rw-r--r--app/assets/stylesheets/framework/emojis.scss1
-rw-r--r--app/assets/stylesheets/framework/files.scss4
-rw-r--r--app/assets/stylesheets/framework/layout.scss2
-rw-r--r--app/assets/stylesheets/framework/selects.scss16
-rw-r--r--app/assets/stylesheets/framework/snippets.scss4
-rw-r--r--app/assets/stylesheets/framework/variables.scss95
-rw-r--r--app/assets/stylesheets/highlight/themes/dark.scss8
-rw-r--r--app/assets/stylesheets/highlight/themes/monokai.scss10
-rw-r--r--app/assets/stylesheets/highlight/themes/solarized-dark.scss10
-rw-r--r--app/assets/stylesheets/highlight/themes/solarized-light.scss12
-rw-r--r--app/assets/stylesheets/highlight/themes/white.scss11
-rw-r--r--app/assets/stylesheets/page_bundles/boards.scss29
-rw-r--r--app/assets/stylesheets/page_bundles/branches.scss41
-rw-r--r--app/assets/stylesheets/page_bundles/clusters.scss4
-rw-r--r--app/assets/stylesheets/page_bundles/dashboard.scss5
-rw-r--r--app/assets/stylesheets/page_bundles/design_management.scss215
-rw-r--r--app/assets/stylesheets/page_bundles/ide.scss5
-rw-r--r--app/assets/stylesheets/page_bundles/issues_show.scss214
-rw-r--r--app/assets/stylesheets/page_bundles/merge_requests.scss74
-rw-r--r--app/assets/stylesheets/page_bundles/notifications.scss31
-rw-r--r--app/assets/stylesheets/pages/branches.scss39
-rw-r--r--app/assets/stylesheets/pages/issuable.scss4
-rw-r--r--app/assets/stylesheets/pages/issues.scss10
-rw-r--r--app/assets/stylesheets/pages/ml_experiment_tracking.scss16
-rw-r--r--app/assets/stylesheets/pages/notes.scss6
-rw-r--r--app/assets/stylesheets/pages/notifications.scss29
-rw-r--r--app/assets/stylesheets/pages/projects.scss181
-rw-r--r--app/assets/stylesheets/pages/search.scss7
-rw-r--r--app/assets/stylesheets/startup/startup-dark.scss276
-rw-r--r--app/assets/stylesheets/startup/startup-general.scss142
-rw-r--r--app/assets/stylesheets/startup/startup-signin.scss94
-rw-r--r--app/assets/stylesheets/themes/_dark.scss28
-rw-r--r--app/assets/stylesheets/themes/theme_helper.scss10
-rw-r--r--app/components/pajamas/avatar_component.rb4
-rw-r--r--app/components/pajamas/badge_component.rb4
-rw-r--r--app/components/pajamas/banner_component.rb4
-rw-r--r--app/components/pajamas/spinner_component.html.haml7
-rw-r--r--app/components/pajamas/spinner_component.rb17
-rw-r--r--app/controllers/admin/application_settings_controller.rb6
-rw-r--r--app/controllers/admin/broadcast_messages_controller.rb64
-rw-r--r--app/controllers/admin/groups_controller.rb7
-rw-r--r--app/controllers/admin/users_controller.rb33
-rw-r--r--app/controllers/application_controller.rb9
-rw-r--r--app/controllers/concerns/access_tokens_actions.rb16
-rw-r--r--app/controllers/concerns/authenticates_with_two_factor.rb2
-rw-r--r--app/controllers/concerns/integrations/params.rb4
-rw-r--r--app/controllers/concerns/issuable_actions.rb58
-rw-r--r--app/controllers/concerns/issuable_collections_action.rb1
-rw-r--r--app/controllers/concerns/preferred_language_switcher.rb18
-rw-r--r--app/controllers/concerns/preview_markdown.rb2
-rw-r--r--app/controllers/concerns/product_analytics_tracking.rb2
-rw-r--r--app/controllers/concerns/render_access_tokens.rb31
-rw-r--r--app/controllers/concerns/send_file_upload.rb12
-rw-r--r--app/controllers/concerns/verifies_with_email.rb11
-rw-r--r--app/controllers/concerns/web_hooks/hook_actions.rb8
-rw-r--r--app/controllers/concerns/web_hooks/hook_execution_notice.rb2
-rw-r--r--app/controllers/confirmations_controller.rb1
-rw-r--r--app/controllers/dashboard/projects_controller.rb7
-rw-r--r--app/controllers/explore/groups_controller.rb4
-rw-r--r--app/controllers/graphql_controller.rb3
-rw-r--r--app/controllers/groups/boards_controller.rb2
-rw-r--r--app/controllers/groups/dependency_proxy/application_controller.rb5
-rw-r--r--app/controllers/groups/observability_controller.rb32
-rw-r--r--app/controllers/groups/registry/repositories_controller.rb4
-rw-r--r--app/controllers/groups/settings/access_tokens_controller.rb1
-rw-r--r--app/controllers/groups/settings/ci_cd_controller.rb3
-rw-r--r--app/controllers/groups/settings/packages_and_registries_controller.rb4
-rw-r--r--app/controllers/groups/settings/repository_controller.rb3
-rw-r--r--app/controllers/groups_controller.rb7
-rw-r--r--app/controllers/jira_connect/application_controller.rb26
-rw-r--r--app/controllers/jira_connect/cors_preflight_checks_controller.rb16
-rw-r--r--app/controllers/jira_connect/oauth_application_ids_controller.rb6
-rw-r--r--app/controllers/jira_connect/subscriptions_controller.rb6
-rw-r--r--app/controllers/oauth/authorizations_controller.rb17
-rw-r--r--app/controllers/passwords_controller.rb3
-rw-r--r--app/controllers/profiles/passwords_controller.rb6
-rw-r--r--app/controllers/profiles/personal_access_tokens_controller.rb33
-rw-r--r--app/controllers/projects/alerting/notifications_controller.rb3
-rw-r--r--app/controllers/projects/application_controller.rb6
-rw-r--r--app/controllers/projects/artifacts_controller.rb8
-rw-r--r--app/controllers/projects/boards_controller.rb2
-rw-r--r--app/controllers/projects/commit_controller.rb2
-rw-r--r--app/controllers/projects/environments_controller.rb2
-rw-r--r--app/controllers/projects/google_cloud/configuration_controller.rb2
-rw-r--r--app/controllers/projects/google_cloud/databases_controller.rb9
-rw-r--r--app/controllers/projects/google_cloud/deployments_controller.rb2
-rw-r--r--app/controllers/projects/google_cloud/gcp_regions_controller.rb2
-rw-r--r--app/controllers/projects/google_cloud/service_accounts_controller.rb2
-rw-r--r--app/controllers/projects/graphs_controller.rb2
-rw-r--r--app/controllers/projects/incidents_controller.rb1
-rw-r--r--app/controllers/projects/issues_controller.rb16
-rw-r--r--app/controllers/projects/labels_controller.rb5
-rw-r--r--app/controllers/projects/learn_gitlab_controller.rb1
-rw-r--r--app/controllers/projects/merge_requests/diffs_controller.rb22
-rw-r--r--app/controllers/projects/merge_requests_controller.rb40
-rw-r--r--app/controllers/projects/ml/experiments_controller.rb32
-rw-r--r--app/controllers/projects/notes_controller.rb2
-rw-r--r--app/controllers/projects/packages/infrastructure_registry_controller.rb2
-rw-r--r--app/controllers/projects/pipeline_schedules_controller.rb2
-rw-r--r--app/controllers/projects/pipelines_controller.rb23
-rw-r--r--app/controllers/projects/product_analytics_controller.rb61
-rw-r--r--app/controllers/projects/prometheus/alerts_controller.rb19
-rw-r--r--app/controllers/projects/registry/repositories_controller.rb10
-rw-r--r--app/controllers/projects/settings/access_tokens_controller.rb1
-rw-r--r--app/controllers/projects/settings/ci_cd_controller.rb10
-rw-r--r--app/controllers/projects/settings/repository_controller.rb30
-rw-r--r--app/controllers/projects/starrers_controller.rb10
-rw-r--r--app/controllers/projects/templates_controller.rb4
-rw-r--r--app/controllers/projects/usage_quotas_controller.rb2
-rw-r--r--app/controllers/projects/work_items_controller.rb6
-rw-r--r--app/controllers/projects_controller.rb7
-rw-r--r--app/controllers/registrations_controller.rb26
-rw-r--r--app/controllers/search_controller.rb15
-rw-r--r--app/controllers/sessions_controller.rb2
-rw-r--r--app/controllers/terraform/services_controller.rb2
-rw-r--r--app/controllers/users_controller.rb2
-rw-r--r--app/experiments/application_experiment.rb19
-rw-r--r--app/experiments/require_verification_for_namespace_creation_experiment.rb10
-rw-r--r--app/experiments/security_reports_mr_widget_prompt_experiment.rb6
-rw-r--r--app/finders/access_requests_finder.rb2
-rw-r--r--app/finders/autocomplete/users_finder.rb6
-rw-r--r--app/finders/clusters/agent_authorizations_finder.rb30
-rw-r--r--app/finders/clusters/agent_tokens_finder.rb25
-rw-r--r--app/finders/incident_management/timeline_event_tags_finder.rb25
-rw-r--r--app/finders/issuable_finder.rb12
-rw-r--r--app/finders/issues_finder.rb12
-rw-r--r--app/finders/license_template_finder.rb6
-rw-r--r--app/finders/projects_finder.rb7
-rw-r--r--app/finders/users_star_projects_finder.rb2
-rw-r--r--app/finders/work_items/work_items_finder.rb24
-rw-r--r--app/graphql/graphql_triggers.rb4
-rw-r--r--app/graphql/mutations/ci/job/artifacts_destroy.rb2
-rw-r--r--app/graphql/mutations/ci/job/base.rb2
-rw-r--r--app/graphql/mutations/ci/job_artifact/destroy.rb2
-rw-r--r--app/graphql/mutations/ci/pipeline_schedule/take_ownership.rb27
-rw-r--r--app/graphql/mutations/ci/runner/bulk_delete.rb16
-rw-r--r--app/graphql/mutations/ci/runner/update.rb2
-rw-r--r--app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb3
-rw-r--r--app/graphql/mutations/container_repositories/destroy.rb8
-rw-r--r--app/graphql/mutations/incident_management/timeline_event/create.rb4
-rw-r--r--app/graphql/mutations/incident_management/timeline_event_tag/base.rb25
-rw-r--r--app/graphql/mutations/incident_management/timeline_event_tag/create.rb29
-rw-r--r--app/graphql/mutations/work_items/create.rb9
-rw-r--r--app/graphql/mutations/work_items/create_from_task.rb7
-rw-r--r--app/graphql/mutations/work_items/delete.rb7
-rw-r--r--app/graphql/mutations/work_items/delete_task.rb7
-rw-r--r--app/graphql/mutations/work_items/update.rb7
-rw-r--r--app/graphql/mutations/work_items/update_task.rb7
-rw-r--r--app/graphql/resolvers/base_issues_resolver.rb64
-rw-r--r--app/graphql/resolvers/blobs_resolver.rb2
-rw-r--r--app/graphql/resolvers/bulk_labels_resolver.rb2
-rw-r--r--app/graphql/resolvers/concerns/board_item_filterable.rb18
-rw-r--r--app/graphql/resolvers/concerns/issue_resolver_arguments.rb167
-rw-r--r--app/graphql/resolvers/concerns/issues/look_ahead_preloads.rb35
-rw-r--r--app/graphql/resolvers/concerns/issues/sort_arguments.rb26
-rw-r--r--app/graphql/resolvers/concerns/project_search_arguments.rb1
-rw-r--r--app/graphql/resolvers/concerns/search_arguments.rb10
-rw-r--r--app/graphql/resolvers/group_issues_resolver.rb5
-rw-r--r--app/graphql/resolvers/incident_management/timeline_event_tags_resolver.rb15
-rw-r--r--app/graphql/resolvers/incident_management/timeline_events_resolver.rb8
-rw-r--r--app/graphql/resolvers/issue_status_counts_resolver.rb26
-rw-r--r--app/graphql/resolvers/issues/base_parent_resolver.rb48
-rw-r--r--app/graphql/resolvers/issues/base_resolver.rb186
-rw-r--r--app/graphql/resolvers/issues_resolver.rb29
-rw-r--r--app/graphql/resolvers/project_issues_resolver.rb9
-rw-r--r--app/graphql/resolvers/work_item_resolver.rb5
-rw-r--r--app/graphql/resolvers/work_items/types_resolver.rb10
-rw-r--r--app/graphql/resolvers/work_items_resolver.rb5
-rw-r--r--app/graphql/types/base_argument.rb4
-rw-r--r--app/graphql/types/base_enum.rb4
-rw-r--r--app/graphql/types/base_field.rb4
-rw-r--r--app/graphql/types/boards/board_issue_input_type.rb4
-rw-r--r--app/graphql/types/branch_protections/merge_access_level_type.rb2
-rw-r--r--app/graphql/types/branch_protections/push_access_level_type.rb2
-rw-r--r--app/graphql/types/ci/job_need_union.rb5
-rw-r--r--app/graphql/types/commit_signature_interface.rb37
-rw-r--r--app/graphql/types/commit_signatures/gpg_signature_type.rb29
-rw-r--r--app/graphql/types/commit_signatures/verification_status_enum.rb18
-rw-r--r--app/graphql/types/commit_signatures/x509_signature_type.rb22
-rw-r--r--app/graphql/types/commit_type.rb7
-rw-r--r--app/graphql/types/concerns/gitlab_style_deprecations.rb18
-rw-r--r--app/graphql/types/deployment_details_type.rb4
-rw-r--r--app/graphql/types/deployment_type.rb2
-rw-r--r--app/graphql/types/group_type.rb4
-rw-r--r--app/graphql/types/incident_management/timeline_event_tag_type.rb23
-rw-r--r--app/graphql/types/incident_management/timeline_event_type.rb7
-rw-r--r--app/graphql/types/issue_connection.rb15
-rw-r--r--app/graphql/types/issue_type.rb10
-rw-r--r--app/graphql/types/issue_type_enum.rb6
-rw-r--r--app/graphql/types/issues/unioned_issue_filter_input_type.rb16
-rw-r--r--app/graphql/types/merge_request_type.rb5
-rw-r--r--app/graphql/types/metadata_type.rb2
-rw-r--r--app/graphql/types/mutation_type.rb4
-rw-r--r--app/graphql/types/packages/package_base_type.rb2
-rw-r--r--app/graphql/types/packages/package_links_type.rb19
-rw-r--r--app/graphql/types/permission_types/ci/runner.rb2
-rw-r--r--app/graphql/types/project_type.rb25
-rw-r--r--app/graphql/types/projects/branch_rule_type.rb12
-rw-r--r--app/graphql/types/projects/repository_language_type.rb20
-rw-r--r--app/graphql/types/query_type.rb9
-rw-r--r--app/graphql/types/release_links_type.rb10
-rw-r--r--app/graphql/types/release_source_type.rb2
-rw-r--r--app/graphql/types/release_type.rb2
-rw-r--r--app/graphql/types/repository_type.rb2
-rw-r--r--app/graphql/types/subscription_type.rb3
-rw-r--r--app/graphql/types/work_items/widget_interface.rb5
-rw-r--r--app/graphql/types/work_items/widgets/milestone_input_type.rb17
-rw-r--r--app/graphql/types/work_items/widgets/milestone_type.rb23
-rw-r--r--app/graphql/types/x509_certificate_type.rb39
-rw-r--r--app/graphql/types/x509_issuer_type.rb29
-rw-r--r--app/helpers/appearances_helper.rb2
-rw-r--r--app/helpers/application_helper.rb26
-rw-r--r--app/helpers/application_settings_helper.rb8
-rw-r--r--app/helpers/avatars_helper.rb5
-rw-r--r--app/helpers/blob_helper.rb26
-rw-r--r--app/helpers/broadcast_messages_helper.rb5
-rw-r--r--app/helpers/diff_helper.rb18
-rw-r--r--app/helpers/events_helper.rb2
-rw-r--r--app/helpers/form_helper.rb9
-rw-r--r--app/helpers/gitlab_routing_helper.rb1
-rw-r--r--app/helpers/graph_helper.rb6
-rw-r--r--app/helpers/groups/group_members_helper.rb7
-rw-r--r--app/helpers/groups/observability_helper.rb50
-rw-r--r--app/helpers/groups_helper.rb27
-rw-r--r--app/helpers/hooks_helper.rb2
-rw-r--r--app/helpers/icons_helper.rb22
-rw-r--r--app/helpers/ide_helper.rb2
-rw-r--r--app/helpers/integrations_helper.rb25
-rw-r--r--app/helpers/issuables_helper.rb15
-rw-r--r--app/helpers/issues_helper.rb6
-rw-r--r--app/helpers/json_helper.rb14
-rw-r--r--app/helpers/markup_helper.rb93
-rw-r--r--app/helpers/merge_requests_helper.rb6
-rw-r--r--app/helpers/nav/top_nav_helper.rb78
-rw-r--r--app/helpers/projects/alert_management_helper.rb1
-rw-r--r--app/helpers/projects/ml/experiments_helper.rb24
-rw-r--r--app/helpers/projects/pipeline_helper.rb1
-rw-r--r--app/helpers/projects/project_members_helper.rb3
-rw-r--r--app/helpers/projects_helper.rb12
-rw-r--r--app/helpers/recaptcha_helper.rb14
-rw-r--r--app/helpers/reminder_emails_helper.rb2
-rw-r--r--app/helpers/routing/packages_helper.rb9
-rw-r--r--app/helpers/routing/projects_helper.rb13
-rw-r--r--app/helpers/routing/pseudonymization_helper.rb7
-rw-r--r--app/helpers/search_helper.rb82
-rw-r--r--app/helpers/selects_helper.rb40
-rw-r--r--app/helpers/todos_helper.rb42
-rw-r--r--app/mailers/emails/identity_verification.rb16
-rw-r--r--app/mailers/emails/releases.rb2
-rw-r--r--app/mailers/previews/notify_preview.rb2
-rw-r--r--app/models/active_session.rb40
-rw-r--r--app/models/alert_management/http_integration.rb3
-rw-r--r--app/models/appearance.rb20
-rw-r--r--app/models/application_setting.rb22
-rw-r--r--app/models/application_setting_implementation.rb2
-rw-r--r--app/models/awareness_session.rb49
-rw-r--r--app/models/broadcast_message.rb4
-rw-r--r--app/models/ci/bridge.rb33
-rw-r--r--app/models/ci/build.rb95
-rw-r--r--app/models/ci/build_metadata.rb16
-rw-r--r--app/models/ci/build_trace_chunk.rb2
-rw-r--r--app/models/ci/group_variable.rb1
-rw-r--r--app/models/ci/instance_variable.rb1
-rw-r--r--app/models/ci/job_variable.rb1
-rw-r--r--app/models/ci/pipeline.rb8
-rw-r--r--app/models/ci/pipeline_metadata.rb2
-rw-r--r--app/models/ci/pipeline_schedule_variable.rb1
-rw-r--r--app/models/ci/pipeline_variable.rb1
-rw-r--r--app/models/ci/processable.rb1
-rw-r--r--app/models/ci/secure_file.rb2
-rw-r--r--app/models/ci/variable.rb1
-rw-r--r--app/models/clusters/applications/cert_manager.rb11
-rw-r--r--app/models/clusters/applications/crossplane.rb7
-rw-r--r--app/models/clusters/applications/helm.rb2
-rw-r--r--app/models/clusters/applications/ingress.rb5
-rw-r--r--app/models/clusters/applications/jupyter.rb2
-rw-r--r--app/models/clusters/applications/knative.rb2
-rw-r--r--app/models/clusters/applications/prometheus.rb8
-rw-r--r--app/models/clusters/applications/runner.rb2
-rw-r--r--app/models/clusters/cluster.rb2
-rw-r--r--app/models/clusters/integrations/prometheus.rb6
-rw-r--r--app/models/clusters/platforms/kubernetes.rb30
-rw-r--r--app/models/clusters/providers/aws.rb6
-rw-r--r--app/models/clusters/providers/gcp.rb8
-rw-r--r--app/models/commit_collection.rb7
-rw-r--r--app/models/commit_signatures/gpg_signature.rb4
-rw-r--r--app/models/commit_status.rb13
-rw-r--r--app/models/concerns/ci/has_status.rb4
-rw-r--r--app/models/concerns/ci/metadatable.rb10
-rw-r--r--app/models/concerns/ci/partitionable.rb9
-rw-r--r--app/models/concerns/ci/partitionable/switch.rb57
-rw-r--r--app/models/concerns/ci/raw_variable.rb17
-rw-r--r--app/models/concerns/ci/track_environment_usage.rb2
-rw-r--r--app/models/concerns/encrypted_user_password.rb82
-rw-r--r--app/models/concerns/enums/sbom.rb15
-rw-r--r--app/models/concerns/file_store_mounter.rb34
-rw-r--r--app/models/concerns/issuable.rb17
-rw-r--r--app/models/concerns/milestoneable.rb2
-rw-r--r--app/models/concerns/mirror_authentication.rb2
-rw-r--r--app/models/concerns/noteable.rb22
-rw-r--r--app/models/concerns/packages/debian/distribution.rb9
-rw-r--r--app/models/concerns/pg_full_text_searchable.rb47
-rw-r--r--app/models/concerns/project_features_compatibility.rb4
-rw-r--r--app/models/concerns/protected_ref.rb1
-rw-r--r--app/models/concerns/protected_ref_access.rb4
-rw-r--r--app/models/concerns/redis_cacheable.rb10
-rw-r--r--app/models/concerns/repository_storage_movable.rb4
-rw-r--r--app/models/concerns/subquery.rb24
-rw-r--r--app/models/concerns/ttl_expirable.rb2
-rw-r--r--app/models/container_repository.rb23
-rw-r--r--app/models/cycle_analytics/project_level_stage_adapter.rb2
-rw-r--r--app/models/dependency_proxy/group_setting.rb4
-rw-r--r--app/models/deploy_token.rb2
-rw-r--r--app/models/deployment.rb5
-rw-r--r--app/models/diff_discussion.rb8
-rw-r--r--app/models/diff_viewer/server_side.rb8
-rw-r--r--app/models/error_tracking/project_error_tracking_setting.rb11
-rw-r--r--app/models/event.rb4
-rw-r--r--app/models/event_collection.rb25
-rw-r--r--app/models/experiment.rb77
-rw-r--r--app/models/experiment_subject.rb32
-rw-r--r--app/models/experiment_user.rb14
-rw-r--r--app/models/group.rb21
-rw-r--r--app/models/hooks/active_hook_filter.rb28
-rw-r--r--app/models/hooks/system_hook.rb6
-rw-r--r--app/models/hooks/web_hook.rb48
-rw-r--r--app/models/hooks/web_hook_log.rb2
-rw-r--r--app/models/incident_management/timeline_event.rb2
-rw-r--r--app/models/incident_management/timeline_event_tag.rb11
-rw-r--r--app/models/instance_metadata.rb5
-rw-r--r--app/models/integration.rb32
-rw-r--r--app/models/integrations/assembla.rb5
-rw-r--r--app/models/integrations/bamboo.rb9
-rw-r--r--app/models/integrations/base_chat_notification.rb8
-rw-r--r--app/models/integrations/base_ci.rb2
-rw-r--r--app/models/integrations/base_issue_tracker.rb2
-rw-r--r--app/models/integrations/base_monitoring.rb2
-rw-r--r--app/models/integrations/base_slack_notification.rb62
-rw-r--r--app/models/integrations/base_slash_commands.rb2
-rw-r--r--app/models/integrations/base_third_party_wiki.rb2
-rw-r--r--app/models/integrations/buildkite.rb2
-rw-r--r--app/models/integrations/chat_message/pipeline_message.rb9
-rw-r--r--app/models/integrations/datadog.rb7
-rw-r--r--app/models/integrations/discord.rb3
-rw-r--r--app/models/integrations/drone_ci.rb1
-rw-r--r--app/models/integrations/hangouts_chat.rb6
-rw-r--r--app/models/integrations/jenkins.rb20
-rw-r--r--app/models/integrations/jira.rb6
-rw-r--r--app/models/integrations/mattermost.rb3
-rw-r--r--app/models/integrations/microsoft_teams.rb6
-rw-r--r--app/models/integrations/packagist.rb7
-rw-r--r--app/models/integrations/pivotaltracker.rb2
-rw-r--r--app/models/integrations/pumble.rb4
-rw-r--r--app/models/integrations/slack.rb63
-rw-r--r--app/models/integrations/teamcity.rb9
-rw-r--r--app/models/integrations/unify_circuit.rb8
-rw-r--r--app/models/integrations/webex_teams.rb4
-rw-r--r--app/models/issue.rb41
-rw-r--r--app/models/iteration.rb3
-rw-r--r--app/models/label.rb3
-rw-r--r--app/models/member.rb2
-rw-r--r--app/models/members/group_member.rb2
-rw-r--r--app/models/members/last_group_owner_assigner.rb2
-rw-r--r--app/models/members/member_task.rb5
-rw-r--r--app/models/members/project_member.rb2
-rw-r--r--app/models/merge_request.rb22
-rw-r--r--app/models/merge_request_assignee.rb3
-rw-r--r--app/models/merge_request_diff.rb16
-rw-r--r--app/models/merge_request_diff_commit.rb2
-rw-r--r--app/models/merge_request_diff_file.rb7
-rw-r--r--app/models/merge_request_reviewer.rb3
-rw-r--r--app/models/ml/candidate.rb9
-rw-r--r--app/models/ml/candidate_metric.rb2
-rw-r--r--app/models/ml/experiment.rb2
-rw-r--r--app/models/namespace.rb14
-rw-r--r--app/models/namespace_setting.rb5
-rw-r--r--app/models/network/graph.rb2
-rw-r--r--app/models/note.rb13
-rw-r--r--app/models/notification_setting.rb4
-rw-r--r--app/models/oauth_access_token.rb4
-rw-r--r--app/models/operations/feature_flag.rb4
-rw-r--r--app/models/packages/go/module_version.rb5
-rw-r--r--app/models/pages_domain.rb12
-rw-r--r--app/models/personal_access_token.rb33
-rw-r--r--app/models/postgresql/detached_partition.rb4
-rw-r--r--app/models/preloaders/project_root_ancestor_preloader.rb2
-rw-r--r--app/models/preloaders/user_max_access_level_in_projects_preloader.rb6
-rw-r--r--app/models/project.rb31
-rw-r--r--app/models/project_authorization.rb10
-rw-r--r--app/models/project_ci_cd_setting.rb4
-rw-r--r--app/models/project_feature.rb1
-rw-r--r--app/models/project_setting.rb6
-rw-r--r--app/models/project_statistics.rb7
-rw-r--r--app/models/projects/import_export/relation_export.rb15
-rw-r--r--app/models/projects/wiki_repository.rb13
-rw-r--r--app/models/protected_branch.rb16
-rw-r--r--app/models/protected_tag.rb1
-rw-r--r--app/models/repository.rb7
-rw-r--r--app/models/serverless/domain_cluster.rb8
-rw-r--r--app/models/terraform/state.rb2
-rw-r--r--app/models/terraform/state_version.rb2
-rw-r--r--app/models/time_tracking/timelog_category.rb3
-rw-r--r--app/models/todo.rb2
-rw-r--r--app/models/user.rb73
-rw-r--r--app/models/users/callout.rb3
-rw-r--r--app/models/users/ghost_user_migration.rb2
-rw-r--r--app/models/users/namespace_commit_email.rb14
-rw-r--r--app/models/users_star_project.rb16
-rw-r--r--app/models/wiki.rb108
-rw-r--r--app/models/work_item.rb10
-rw-r--r--app/models/work_items/type.rb15
-rw-r--r--app/models/work_items/widgets/hierarchy.rb4
-rw-r--r--app/models/work_items/widgets/milestone.rb9
-rw-r--r--app/policies/blob_policy.rb2
-rw-r--r--app/policies/ci/build_policy.rb8
-rw-r--r--app/policies/commit_policy.rb2
-rw-r--r--app/policies/commit_signatures/gpg_signature_policy.rb7
-rw-r--r--app/policies/commit_signatures/x509_commit_signature_policy.rb7
-rw-r--r--app/policies/concerns/member_policy_helpers.rb19
-rw-r--r--app/policies/global_policy.rb2
-rw-r--r--app/policies/group_member_policy.rb14
-rw-r--r--app/policies/group_policy.rb7
-rw-r--r--app/policies/incident_management/timeline_event_tag_policy.rb7
-rw-r--r--app/policies/issuable_policy.rb2
-rw-r--r--app/policies/note_policy.rb2
-rw-r--r--app/policies/packages/policies/project_policy.rb2
-rw-r--r--app/policies/project_member_policy.rb15
-rw-r--r--app/policies/project_policy.rb31
-rw-r--r--app/policies/user_policy.rb1
-rw-r--r--app/presenters/blob_presenter.rb30
-rw-r--r--app/presenters/ci/build_runner_presenter.rb8
-rw-r--r--app/presenters/ci/pipeline_presenter.rb2
-rw-r--r--app/presenters/commit_status_presenter.rb2
-rw-r--r--app/presenters/deployments/deployment_presenter.rb7
-rw-r--r--app/presenters/release_presenter.rb10
-rw-r--r--app/serializers/ci/pipeline_entity.rb6
-rw-r--r--app/serializers/codequality_degradation_entity.rb2
-rw-r--r--app/serializers/detailed_status_entity.rb37
-rw-r--r--app/serializers/diff_file_entity.rb21
-rw-r--r--app/serializers/diffs_entity.rb2
-rw-r--r--app/serializers/diffs_metadata_entity.rb2
-rw-r--r--app/serializers/environment_serializer.rb8
-rw-r--r--app/serializers/group_child_serializer.rb5
-rw-r--r--app/serializers/integrations/event_entity.rb3
-rw-r--r--app/serializers/integrations/field_entity.rb2
-rw-r--r--app/serializers/merge_request_noteable_entity.rb2
-rw-r--r--app/serializers/merge_request_poll_cached_widget_entity.rb9
-rw-r--r--app/serializers/merge_request_poll_widget_entity.rb10
-rw-r--r--app/serializers/merge_requests/pipeline_entity.rb9
-rw-r--r--app/serializers/paginated_diff_entity.rb2
-rw-r--r--app/serializers/pipeline_serializer.rb1
-rw-r--r--app/serializers/project_entity.rb8
-rw-r--r--app/serializers/project_import_entity.rb10
-rw-r--r--app/serializers/test_case_entity.rb23
-rw-r--r--app/serializers/test_report_entity.rb14
-rw-r--r--app/serializers/test_report_summary_entity.rb2
-rw-r--r--app/serializers/test_suite_entity.rb19
-rw-r--r--app/serializers/test_suite_summary_entity.rb5
-rw-r--r--app/services/bulk_imports/create_pipeline_trackers_service.rb2
-rw-r--r--app/services/bulk_imports/lfs_objects_export_service.rb2
-rw-r--r--app/services/ci/after_requeue_job_service.rb20
-rw-r--r--app/services/ci/archive_trace_service.rb2
-rw-r--r--app/services/ci/build_erase_service.rb4
-rw-r--r--app/services/ci/create_pipeline_service.rb12
-rw-r--r--app/services/ci/job_artifacts/destroy_associations_service.rb2
-rw-r--r--app/services/ci/job_artifacts/destroy_batch_service.rb59
-rw-r--r--app/services/ci/job_artifacts/track_artifact_report_service.rb2
-rw-r--r--app/services/ci/list_config_variables_service.rb2
-rw-r--r--app/services/ci/pipeline_artifacts/coverage_report_service.rb2
-rw-r--r--app/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service.rb4
-rw-r--r--app/services/ci/pipeline_schedules/take_ownership_service.rb34
-rw-r--r--app/services/ci/pipeline_trigger_service.rb2
-rw-r--r--app/services/ci/play_build_service.rb24
-rw-r--r--app/services/ci/process_build_service.rb4
-rw-r--r--app/services/ci/register_job_service.rb4
-rw-r--r--app/services/ci/retry_job_service.rb16
-rw-r--r--app/services/ci/runners/bulk_delete_runners_service.rb54
-rw-r--r--app/services/ci/runners/set_runner_associated_projects_service.rb2
-rw-r--r--app/services/clusters/applications/check_ingress_ip_address_service.rb46
-rw-r--r--app/services/clusters/applications/check_installation_progress_service.rb42
-rw-r--r--app/services/clusters/applications/check_uninstall_progress_service.rb42
-rw-r--r--app/services/clusters/applications/check_upgrade_progress_service.rb71
-rw-r--r--app/services/clusters/applications/create_service.rb18
-rw-r--r--app/services/clusters/applications/patch_service.rb32
-rw-r--r--app/services/clusters/applications/prometheus_update_service.rb38
-rw-r--r--app/services/clusters/applications/update_service.rb17
-rw-r--r--app/services/clusters/kubernetes/configure_istio_ingress_service.rb112
-rw-r--r--app/services/concerns/alert_management/responses.rb4
-rw-r--r--app/services/dependency_proxy/find_cached_manifest_service.rb1
-rw-r--r--app/services/deployments/create_for_build_service.rb66
-rw-r--r--app/services/environments/create_for_build_service.rb40
-rw-r--r--app/services/environments/schedule_to_delete_review_apps_service.rb2
-rw-r--r--app/services/event_create_service.rb67
-rw-r--r--app/services/git/base_hooks_service.rb14
-rw-r--r--app/services/google_cloud/create_service_accounts_service.rb4
-rw-r--r--app/services/google_cloud/generate_pipeline_service.rb7
-rw-r--r--app/services/google_cloud/setup_cloudsql_instance_service.rb8
-rw-r--r--app/services/groups/create_service.rb11
-rw-r--r--app/services/groups/update_service.rb4
-rw-r--r--app/services/incident_management/timeline_event_tags/base_service.rb27
-rw-r--r--app/services/incident_management/timeline_event_tags/create_service.rb32
-rw-r--r--app/services/incident_management/timeline_events/create_service.rb66
-rw-r--r--app/services/incident_management/timeline_events/update_service.rb9
-rw-r--r--app/services/issuable/bulk_update_service.rb5
-rw-r--r--app/services/issuable/discussions_list_service.rb70
-rw-r--r--app/services/issues/update_service.rb1
-rw-r--r--app/services/jira_import/start_import_service.rb2
-rw-r--r--app/services/labels/transfer_service.rb4
-rw-r--r--app/services/loose_foreign_keys/process_deleted_records_service.rb18
-rw-r--r--app/services/markup/rendering_service.rb79
-rw-r--r--app/services/members/approve_access_request_service.rb6
-rw-r--r--app/services/members/destroy_service.rb12
-rw-r--r--app/services/members/update_service.rb89
-rw-r--r--app/services/merge_requests/add_context_service.rb2
-rw-r--r--app/services/merge_requests/after_create_service.rb2
-rw-r--r--app/services/merge_requests/approval_service.rb2
-rw-r--r--app/services/merge_requests/base_service.rb6
-rw-r--r--app/services/merge_requests/create_service.rb21
-rw-r--r--app/services/merge_requests/mergeability/run_checks_service.rb3
-rw-r--r--app/services/merge_requests/mergeability_check_service.rb3
-rw-r--r--app/services/merge_requests/remove_approval_service.rb2
-rw-r--r--app/services/merge_requests/update_assignees_service.rb13
-rw-r--r--app/services/metrics/dashboard/self_monitoring_dashboard_service.rb2
-rw-r--r--app/services/milestones/transfer_service.rb2
-rw-r--r--app/services/namespaces/statistics_refresher_service.rb1
-rw-r--r--app/services/notes/create_service.rb2
-rw-r--r--app/services/notification_service.rb10
-rw-r--r--app/services/packages/debian/create_distribution_service.rb2
-rw-r--r--app/services/packages/debian/update_distribution_service.rb2
-rw-r--r--app/services/packages/maven/metadata/base_create_xml_service.rb5
-rw-r--r--app/services/packages/maven/metadata/create_versions_xml_service.rb15
-rw-r--r--app/services/packages/npm/create_package_service.rb2
-rw-r--r--app/services/packages/rpm/parse_package_service.rb3
-rw-r--r--app/services/packages/rpm/repository_metadata/base_builder.rb46
-rw-r--r--app/services/packages/rpm/repository_metadata/build_filelist_xml.rb14
-rw-r--r--app/services/packages/rpm/repository_metadata/build_filelist_xml_service.rb39
-rw-r--r--app/services/packages/rpm/repository_metadata/build_other_xml.rb14
-rw-r--r--app/services/packages/rpm/repository_metadata/build_other_xml_service.rb31
-rw-r--r--app/services/packages/rpm/repository_metadata/build_primary_xml.rb88
-rw-r--r--app/services/packages/rpm/repository_metadata/build_primary_xml_service.rb78
-rw-r--r--app/services/packages/rpm/repository_metadata/build_repomd_xml.rb60
-rw-r--r--app/services/packages/rpm/repository_metadata/build_repomd_xml_service.rb56
-rw-r--r--app/services/packages/rpm/repository_metadata/build_xml_base_service.rb22
-rw-r--r--app/services/packages/rpm/repository_metadata/update_xml_service.rb62
-rw-r--r--app/services/personal_access_tokens/revoke_service.rb2
-rw-r--r--app/services/projects/lfs_pointers/lfs_download_link_list_service.rb6
-rw-r--r--app/services/projects/move_users_star_projects_service.rb4
-rw-r--r--app/services/projects/prometheus/alerts/notify_service.rb10
-rw-r--r--app/services/projects/unlink_fork_service.rb2
-rw-r--r--app/services/protected_branches/api_service.rb33
-rw-r--r--app/services/protected_branches/cache_service.rb29
-rw-r--r--app/services/protected_refs/access_level_params.rb4
-rw-r--r--app/services/resource_events/base_change_timebox_service.rb4
-rw-r--r--app/services/resource_events/change_milestone_service.rb6
-rw-r--r--app/services/service_ping/submit_service.rb2
-rw-r--r--app/services/snippets/create_service.rb2
-rw-r--r--app/services/spam/spam_verdict_service.rb2
-rw-r--r--app/services/system_notes/issuables_service.rb8
-rw-r--r--app/services/tags/create_service.rb2
-rw-r--r--app/services/todo_service.rb7
-rw-r--r--app/services/two_factor/base_service.rb4
-rw-r--r--app/services/two_factor/destroy_service.rb6
-rw-r--r--app/services/user_project_access_changed_service.rb5
-rw-r--r--app/services/users/build_service.rb5
-rw-r--r--app/services/users/destroy_service.rb65
-rw-r--r--app/services/users/migrate_records_to_ghost_user_in_batches_service.rb25
-rw-r--r--app/services/users/migrate_to_ghost_user_service.rb113
-rw-r--r--app/services/web_hook_service.rb15
-rw-r--r--app/services/work_items/create_service.rb7
-rw-r--r--app/services/work_items/widgets/hierarchy_service/base_service.rb11
-rw-r--r--app/services/work_items/widgets/milestone_service/base_service.rb39
-rw-r--r--app/services/work_items/widgets/milestone_service/create_service.rb13
-rw-r--r--app/services/work_items/widgets/milestone_service/update_service.rb13
-rw-r--r--app/uploaders/object_storage/cdn.rb10
-rw-r--r--app/uploaders/object_storage/cdn/google_cdn.rb18
-rw-r--r--app/validators/branch_filter_validator.rb37
-rw-r--r--app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json305
-rw-r--r--app/validators/json_schemas/web_hooks_url_variables.json2
-rw-r--r--app/validators/nested_attributes_duplicates_validator.rb10
-rw-r--r--app/validators/web_hooks/wildcard_branch_filter_validator.rb34
-rw-r--r--app/views/admin/application_settings/_account_and_limit.html.haml2
-rw-r--r--app/views/admin/application_settings/_jira_connect.html.haml27
-rw-r--r--app/views/admin/application_settings/_jira_connect_application_key.html.haml21
-rw-r--r--app/views/admin/application_settings/_package_registry.html.haml2
-rw-r--r--app/views/admin/application_settings/_repository_check.html.haml4
-rw-r--r--app/views/admin/application_settings/_user_restrictions.html.haml2
-rw-r--r--app/views/admin/application_settings/_visibility_and_access.html.haml3
-rw-r--r--app/views/admin/application_settings/appearances/_form.html.haml2
-rw-r--r--app/views/admin/application_settings/general.html.haml3
-rw-r--r--app/views/admin/application_settings/service_usage_data.html.haml2
-rw-r--r--app/views/admin/dashboard/index.html.haml2
-rw-r--r--app/views/admin/groups/show.html.haml5
-rw-r--r--app/views/admin/users/_form.html.haml4
-rw-r--r--app/views/admin/users/_head.html.haml6
-rw-r--r--app/views/admin/users/_projects.html.haml4
-rw-r--r--app/views/admin/users/_users.html.haml2
-rw-r--r--app/views/award_emoji/_awards_block.html.haml2
-rw-r--r--app/views/ci/variables/_index.html.haml2
-rw-r--r--app/views/ci/variables/_url_query_variable_row.html.haml28
-rw-r--r--app/views/dashboard/_groups_head.html.haml2
-rw-r--r--app/views/dashboard/issues.html.haml25
-rw-r--r--app/views/dashboard/todos/_todo.html.haml3
-rw-r--r--app/views/devise/confirmations/almost_there.haml2
-rw-r--r--app/views/devise/sessions/new.html.haml3
-rw-r--r--app/views/doorkeeper/authorizations/forbidden.html.haml5
-rw-r--r--app/views/errors/request_conflict.html.haml2
-rw-r--r--app/views/groups/_archived_projects.html.haml7
-rw-r--r--app/views/groups/_shared_projects.html.haml7
-rw-r--r--app/views/groups/_subgroups_and_projects.html.haml4
-rw-r--r--app/views/groups/group_members/index.html.haml2
-rw-r--r--app/views/groups/observability/index.html.haml2
-rw-r--r--app/views/groups/observability/observability.html.haml3
-rw-r--r--app/views/groups/settings/_remove.html.haml2
-rw-r--r--app/views/groups/settings/_transfer.html.haml2
-rw-r--r--app/views/groups/settings/access_tokens/index.html.haml3
-rw-r--r--app/views/groups/show.html.haml35
-rw-r--r--app/views/help/index.html.haml2
-rw-r--r--app/views/import/_githubish_status.html.haml2
-rw-r--r--app/views/layouts/_img_loader.html.haml3
-rw-r--r--app/views/layouts/_page.html.haml2
-rw-r--r--app/views/layouts/component_preview.html.haml17
-rw-r--r--app/views/layouts/group.html.haml2
-rw-r--r--app/views/layouts/header/_default.html.haml64
-rw-r--r--app/views/layouts/header/_gitlab_version.html.haml13
-rw-r--r--app/views/layouts/header/_new_dropdown.html.haml2
-rw-r--r--app/views/layouts/project.html.haml1
-rw-r--r--app/views/notify/pipeline_failed_email.html.haml23
-rw-r--r--app/views/notify/unknown_sign_in_email.html.haml2
-rw-r--r--app/views/profiles/keys/_form.html.haml6
-rw-r--r--app/views/profiles/notifications/show.html.haml1
-rw-r--r--app/views/profiles/personal_access_tokens/index.html.haml2
-rw-r--r--app/views/profiles/show.html.haml2
-rw-r--r--app/views/projects/_files.html.haml2
-rw-r--r--app/views/projects/_import_project_pane.html.haml55
-rw-r--r--app/views/projects/_last_push.html.haml2
-rw-r--r--app/views/projects/_merge_request_merge_checks_settings.html.haml1
-rw-r--r--app/views/projects/_transfer.html.haml3
-rw-r--r--app/views/projects/_visibility_modal.html.haml29
-rw-r--r--app/views/projects/artifacts/_artifact.html.haml61
-rw-r--r--app/views/projects/artifacts/_table.html.haml16
-rw-r--r--app/views/projects/artifacts/index.html.haml13
-rw-r--r--app/views/projects/blob/_blob.html.haml2
-rw-r--r--app/views/projects/blob/_editor.html.haml4
-rw-r--r--app/views/projects/blob/viewers/_loading.html.haml2
-rw-r--r--app/views/projects/branch_defaults/_branch_names_fields.html.haml14
-rw-r--r--app/views/projects/branch_defaults/_default_branch_fields.html.haml16
-rw-r--r--app/views/projects/branch_defaults/_show.html.haml17
-rw-r--r--app/views/projects/branches/_branch.html.haml13
-rw-r--r--app/views/projects/branches/_panel.html.haml2
-rw-r--r--app/views/projects/branches/index.html.haml16
-rw-r--r--app/views/projects/buttons/_download.html.haml2
-rw-r--r--app/views/projects/commit/_commit_box.html.haml2
-rw-r--r--app/views/projects/commits/_commit.html.haml4
-rw-r--r--app/views/projects/commits/_commits.html.haml7
-rw-r--r--app/views/projects/default_branch/_show.html.haml29
-rw-r--r--app/views/projects/deployments/_actions.haml4
-rw-r--r--app/views/projects/deployments/_rollback.haml2
-rw-r--r--app/views/projects/empty.html.haml4
-rw-r--r--app/views/projects/hooks/edit.html.haml2
-rw-r--r--app/views/projects/hooks/index.html.haml4
-rw-r--r--app/views/projects/incidents/show.html.haml1
-rw-r--r--app/views/projects/issues/_related_issues.html.haml3
-rw-r--r--app/views/projects/issues/_work_item_links.html.haml3
-rw-r--r--app/views/projects/issues/show.html.haml1
-rw-r--r--app/views/projects/merge_requests/_awards_block.html.haml2
-rw-r--r--app/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml8
-rw-r--r--app/views/projects/merge_requests/_code_dropdown.html.haml6
-rw-r--r--app/views/projects/merge_requests/_commits.html.haml5
-rw-r--r--app/views/projects/merge_requests/_mr_box.html.haml2
-rw-r--r--app/views/projects/merge_requests/_mr_title.html.haml4
-rw-r--r--app/views/projects/merge_requests/creations/_new_submit.html.haml8
-rw-r--r--app/views/projects/merge_requests/dropdowns/_branch.html.haml2
-rw-r--r--app/views/projects/merge_requests/dropdowns/_project.html.haml2
-rw-r--r--app/views/projects/merge_requests/show.html.haml5
-rw-r--r--app/views/projects/milestones/_form.html.haml4
-rw-r--r--app/views/projects/mirrors/_authentication_method.html.haml4
-rw-r--r--app/views/projects/mirrors/_disabled_mirror_badge.html.haml2
-rw-r--r--app/views/projects/mirrors/_mirror_repos.html.haml4
-rw-r--r--app/views/projects/mirrors/_mirror_repos_form.html.haml2
-rw-r--r--app/views/projects/mirrors/_mirror_repos_list.html.haml10
-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/index.html.haml11
-rw-r--r--app/views/projects/ml/experiments/show.html.haml14
-rw-r--r--app/views/projects/network/show.html.haml3
-rw-r--r--app/views/projects/no_repo.html.haml2
-rw-r--r--app/views/projects/notes/_actions.html.haml8
-rw-r--r--app/views/projects/pipeline_schedules/_form.html.haml8
-rw-r--r--app/views/projects/pipelines/_info.html.haml29
-rw-r--r--app/views/projects/pipelines/show.html.haml2
-rw-r--r--app/views/projects/product_analytics/_graph.html.haml6
-rw-r--r--app/views/projects/product_analytics/_links.html.haml5
-rw-r--r--app/views/projects/product_analytics/_tracker.html.erb10
-rw-r--r--app/views/projects/product_analytics/graphs.html.haml16
-rw-r--r--app/views/projects/product_analytics/index.html.haml16
-rw-r--r--app/views/projects/product_analytics/setup.html.haml12
-rw-r--r--app/views/projects/product_analytics/test.html.haml17
-rw-r--r--app/views/projects/project_members/index.html.haml1
-rw-r--r--app/views/projects/protected_branches/shared/_dropdown.html.haml8
-rw-r--r--app/views/projects/protected_branches/shared/_index.html.haml2
-rw-r--r--app/views/projects/protected_tags/shared/_dropdown.html.haml8
-rw-r--r--app/views/projects/protected_tags/shared/_tags_list.html.haml13
-rw-r--r--app/views/projects/settings/_archive.html.haml2
-rw-r--r--app/views/projects/settings/access_tokens/index.html.haml2
-rw-r--r--app/views/projects/settings/branch_rules/index.html.haml2
-rw-r--r--app/views/projects/settings/ci_cd/_form.html.haml6
-rw-r--r--app/views/projects/settings/ci_cd/show.html.haml2
-rw-r--r--app/views/projects/settings/repository/show.html.haml2
-rw-r--r--app/views/projects/show.html.haml1
-rw-r--r--app/views/projects/snippets/show.html.haml4
-rw-r--r--app/views/projects/triggers/_form.html.haml4
-rw-r--r--app/views/registrations/welcome/show.html.haml1
-rw-r--r--app/views/search/_category.html.haml2
-rw-r--r--app/views/search/_results.html.haml3
-rw-r--r--app/views/search/_results_status.html.haml5
-rw-r--r--app/views/search/results/_blob_highlight.html.haml3
-rw-r--r--app/views/shared/_file_picker_button.html.haml3
-rw-r--r--app/views/shared/_flash_user_callout.html.haml2
-rw-r--r--app/views/shared/_label.html.haml6
-rw-r--r--app/views/shared/_md_preview.html.haml2
-rw-r--r--app/views/shared/access_tokens/_created_container.html.haml12
-rw-r--r--app/views/shared/access_tokens/_table.html.haml51
-rw-r--r--app/views/shared/deploy_tokens/_form.html.haml2
-rw-r--r--app/views/shared/deploy_tokens/_index.html.haml21
-rw-r--r--app/views/shared/empty_states/_snippets.html.haml4
-rw-r--r--app/views/shared/issuable/_bulk_update_sidebar.html.haml6
-rw-r--r--app/views/shared/issuable/_form.html.haml5
-rw-r--r--app/views/shared/issuable/_milestone_dropdown.html.haml24
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml32
-rw-r--r--app/views/shared/issuable/_sidebar_assignees.html.haml4
-rw-r--r--app/views/shared/issuable/_sidebar_reviewers.html.haml12
-rw-r--r--app/views/shared/issuable/form/_metadata.html.haml3
-rw-r--r--app/views/shared/issue_type/_emoji_block.html.haml4
-rw-r--r--app/views/shared/labels/_form.html.haml8
-rw-r--r--app/views/shared/members/_access_request_links.html.haml7
-rw-r--r--app/views/shared/milestones/_delete_button.html.haml8
-rw-r--r--app/views/shared/milestones/_sidebar.html.haml2
-rw-r--r--app/views/shared/projects/_list.html.haml2
-rw-r--r--app/views/shared/projects/_project.html.haml146
-rw-r--r--app/views/shared/web_hooks/_form.html.haml20
-rw-r--r--app/views/snippets/show.html.haml2
-rw-r--r--app/views/users/show.html.haml43
-rw-r--r--app/workers/all_queues.yml49
-rw-r--r--app/workers/authorized_keys_worker.rb2
-rw-r--r--app/workers/bulk_imports/entity_worker.rb45
-rw-r--r--app/workers/bulk_imports/export_request_worker.rb79
-rw-r--r--app/workers/bulk_imports/pipeline_worker.rb79
-rw-r--r--app/workers/cluster_configure_istio_worker.rb9
-rw-r--r--app/workers/cluster_install_app_worker.rb9
-rw-r--r--app/workers/cluster_patch_app_worker.rb9
-rw-r--r--app/workers/cluster_update_app_worker.rb36
-rw-r--r--app/workers/cluster_upgrade_app_worker.rb9
-rw-r--r--app/workers/cluster_wait_for_app_installation_worker.rb9
-rw-r--r--app/workers/cluster_wait_for_app_update_worker.rb9
-rw-r--r--app/workers/cluster_wait_for_ingress_ip_address_worker.rb9
-rw-r--r--app/workers/clusters/applications/deactivate_integration_worker.rb2
-rw-r--r--app/workers/clusters/applications/wait_for_uninstall_app_worker.rb9
-rw-r--r--app/workers/concerns/limited_capacity/job_tracker.rb2
-rw-r--r--app/workers/container_registry/cleanup_worker.rb59
-rw-r--r--app/workers/container_registry/delete_container_repository_worker.rb81
-rw-r--r--app/workers/database/batched_background_migration/execution_worker.rb75
-rw-r--r--app/workers/database/batched_background_migration/single_database_worker.rb11
-rw-r--r--app/workers/gitlab/github_import/advance_stage_worker.rb1
-rw-r--r--app/workers/gitlab/github_import/pull_requests/import_review_request_worker.rb25
-rw-r--r--app/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker.rb2
-rw-r--r--app/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker.rb33
-rw-r--r--app/workers/gitlab_performance_bar_stats_worker.rb6
-rw-r--r--app/workers/gitlab_shell_worker.rb12
-rw-r--r--app/workers/incident_management/add_severity_system_note_worker.rb5
-rw-r--r--app/workers/loose_foreign_keys/cleanup_worker.rb6
-rw-r--r--app/workers/mail_scheduler/notification_service_worker.rb6
-rw-r--r--app/workers/merge_requests/delete_branch_worker.rb27
-rw-r--r--app/workers/merge_requests/delete_source_branch_worker.rb13
-rw-r--r--app/workers/namespaces/root_statistics_worker.rb3
-rw-r--r--app/workers/onboarding/issue_created_worker.rb3
-rw-r--r--app/workers/onboarding/pipeline_created_worker.rb3
-rw-r--r--app/workers/onboarding/progress_worker.rb3
-rw-r--r--app/workers/onboarding/user_added_worker.rb3
-rw-r--r--app/workers/pages_worker.rb2
-rw-r--r--app/workers/projects/inactive_projects_deletion_cron_worker.rb10
-rw-r--r--app/workers/projects/post_creation_worker.rb15
-rw-r--r--app/workers/repository_import_worker.rb6
-rw-r--r--app/workers/run_pipeline_schedule_worker.rb13
-rw-r--r--app/workers/update_highest_role_worker.rb2
-rw-r--r--app/workers/users/deactivate_dormant_users_worker.rb2
-rw-r--r--app/workers/users/migrate_records_to_ghost_user_in_batches_worker.rb2
-rwxr-xr-xbin/audit-event-type354
-rw-r--r--config/application.rb24
-rw-r--r--config/audit_events/types/policy_project_updated.yml8
-rw-r--r--config/environments/development.rb4
-rw-r--r--config/events/1658833247_integrations_class_perform_integrations_action.yml3
-rw-r--r--config/events/1666038724_Gitlab__Tracking__Helpers__WeakPasswordErrorEvent_track_weak_password_error.yml29
-rw-r--r--config/events/202109151015_cluster_services_prometheus_disabled_manual_prometheus.yml2
-rw-r--r--config/events/202109151015_cluster_services_prometheus_enabled_manual_prometheus.yml2
-rw-r--r--config/events/20210915205112_packages_delete_package.yml4
-rw-r--r--config/feature_categories.yml15
-rw-r--r--config/feature_flags/development/actors_aware_gitaly_calls.yml8
-rw-r--r--config/feature_flags/development/add_delete_branch_worker.yml8
-rw-r--r--config/feature_flags/development/agent_authorization_include_descendants.yml8
-rw-r--r--config/feature_flags/development/ai_assist_api.yml8
-rw-r--r--config/feature_flags/development/ai_assist_flag.yml8
-rw-r--r--config/feature_flags/development/ajax_new_deploy_token.yml8
-rw-r--r--config/feature_flags/development/allow_audit_event_type_filtering.yml8
-rw-r--r--config/feature_flags/development/apollo_boards.yml8
-rw-r--r--config/feature_flags/development/approval_rules_eligible_filter.yml8
-rw-r--r--config/feature_flags/development/async_merge_request_diff_creation.yml8
-rw-r--r--config/feature_flags/development/audit_invalid_approver_rules.yml8
-rw-r--r--config/feature_flags/development/board_grouped_by_epic_performance.yml8
-rw-r--r--config/feature_flags/development/bulk_update_membership_roles.yml8
-rw-r--r--config/feature_flags/development/cache_unleash_client_api.yml8
-rw-r--r--config/feature_flags/development/cascade_package_forwarding_settings.yml8
-rw-r--r--config/feature_flags/development/check_etags_diffs_batch_before_write_cache.yml8
-rw-r--r--config/feature_flags/development/ci_assign_job_token_on_scheduling.yml8
-rw-r--r--config/feature_flags/development/ci_detect_wrongly_expired_artifacts.yml8
-rw-r--r--config/feature_flags/development/ci_job_artifacts_cdn.yml8
-rw-r--r--config/feature_flags/development/ci_job_jwt.yml8
-rw-r--r--config/feature_flags/development/ci_partitioning_use_ci_builds_metadata_routing_table.yml8
-rw-r--r--config/feature_flags/development/ci_raw_variables_in_yaml_config.yml8
-rw-r--r--config/feature_flags/development/ci_recreate_downstream_pipeline.yml8
-rw-r--r--config/feature_flags/development/ci_requeue_with_dag_object_hierarchy.yml8
-rw-r--r--config/feature_flags/development/ci_retry_job_fix.yml8
-rw-r--r--config/feature_flags/development/ci_stop_expanding_file_vars_for_runners.yml8
-rw-r--r--config/feature_flags/development/ci_variable_settings_graphql.yml8
-rw-r--r--config/feature_flags/development/container_registry_delete_repository_with_cron_worker.yml8
-rw-r--r--config/feature_flags/development/container_registry_show_shortened_path.yml8
-rw-r--r--config/feature_flags/development/cube_api_proxy.yml8
-rw-r--r--config/feature_flags/development/dast_api_scanner.yml2
-rw-r--r--config/feature_flags/development/disable_load_entire_blob_for_diff_viewer.yml8
-rw-r--r--config/feature_flags/development/enable_new_sentry_clientside_integration.yml8
-rw-r--r--config/feature_flags/development/enhanced_webhook_support_regex.yml8
-rw-r--r--config/feature_flags/development/error_tracking_sentry_limit.yml8
-rw-r--r--config/feature_flags/development/externally_stored_diffs_caching_export.yml8
-rw-r--r--config/feature_flags/development/group_overview_tabs_vue.yml8
-rw-r--r--config/feature_flags/development/hash_oauth_tokens.yml8
-rw-r--r--config/feature_flags/development/incident_declare_slash_command.yml8
-rw-r--r--config/feature_flags/development/integration_slack_app_notifications.yml2
-rw-r--r--config/feature_flags/development/ipynb_semantic_diff.yml8
-rw-r--r--config/feature_flags/development/jira_connect_oauth_self_managed_setting.yml8
-rw-r--r--config/feature_flags/development/job_webhook_retries_count.yml8
-rw-r--r--config/feature_flags/development/lazy_load_commits.yml2
-rw-r--r--config/feature_flags/development/limit_assignees_per_issuable.yml8
-rw-r--r--config/feature_flags/development/merge_request_widget_graphql.yml8
-rw-r--r--config/feature_flags/development/mergeability_caching.yml8
-rw-r--r--config/feature_flags/development/ml_experiment_tracking.yml3
-rw-r--r--config/feature_flags/development/new_navbar_layout.yml8
-rw-r--r--config/feature_flags/development/observability_group_tab.yml2
-rw-r--r--config/feature_flags/development/optimized_project_and_group_activity_queries.yml8
-rw-r--r--config/feature_flags/development/pbkdf2_password_encryption.yml8
-rw-r--r--config/feature_flags/development/pbkdf2_password_encryption_write.yml8
-rw-r--r--config/feature_flags/development/preferred_language_switcher.yml7
-rw-r--r--config/feature_flags/development/product_analytics.yml8
-rw-r--r--config/feature_flags/development/projects_preloader_fix.yml8
-rw-r--r--config/feature_flags/development/realtime_labels.yml8
-rw-r--r--config/feature_flags/development/realtime_reviewers.yml8
-rw-r--r--config/feature_flags/development/refactor_code_quality_extension.yml8
-rw-r--r--config/feature_flags/development/refactor_mr_widget_test_summary.yml8
-rw-r--r--config/feature_flags/development/remove_extra_primary_submenu_options.yml8
-rw-r--r--config/feature_flags/development/require_approval_on_scan_removal.yml8
-rw-r--r--config/feature_flags/development/root_level_issues_query.yml8
-rw-r--r--config/feature_flags/development/root_statistics_worker_read_replica.yml8
-rw-r--r--config/feature_flags/development/saml_group_sync_retain_default_membership.yml8
-rw-r--r--config/feature_flags/development/scan_result_role_action.yml8
-rw-r--r--config/feature_flags/development/search_index_curation.yml8
-rw-r--r--config/feature_flags/development/split_operations_visibility_permissions.yml2
-rw-r--r--config/feature_flags/development/track_delete_source_errors.yml8
-rw-r--r--config/feature_flags/development/trigger_mr_subscription_on_merge_status_change.yml8
-rw-r--r--config/feature_flags/development/usage_data_ci_i_testing_coverage_report_uploaded.yml8
-rw-r--r--config/feature_flags/development/use_iid_in_work_items_path.yml8
-rw-r--r--config/feature_flags/development/user_destroy_with_limited_execution_time_worker.yml8
-rw-r--r--config/feature_flags/development/verify_gitlab_shell_worker_method_names.yml8
-rw-r--r--config/feature_flags/development/verify_mail_scheduler_notification_service_worker_method_names.yml8
-rw-r--r--config/feature_flags/development/vue_group_select.yml8
-rw-r--r--config/feature_flags/development/vue_issues_dashboard.yml8
-rw-r--r--config/feature_flags/development/work_items_hierarchy.yml8
-rw-r--r--config/feature_flags/development/work_items_mvc.yml8
-rw-r--r--config/feature_flags/development/workhorse_google_client.yml8
-rw-r--r--config/feature_flags/experiment/disable_network_graph_notes_count.yml8
-rw-r--r--config/feature_flags/experiment/generic_explore_groups.yml8
-rw-r--r--config/feature_flags/experiment/logged_out_marketing_header.yml8
-rw-r--r--config/feature_flags/ops/ci_partitioning_analyze_queries_partition_id_check.yml8
-rw-r--r--config/feature_flags/ops/purge_stale_security_findings.yml2
-rw-r--r--config/gitlab.yml.example10
-rw-r--r--config/gitlab_loose_foreign_keys.yml8
-rw-r--r--config/initializers/0_inject_enterprise_edition_module.rb6
-rw-r--r--config/initializers/0_marginalia.rb3
-rw-r--r--config/initializers/1_settings.rb10
-rw-r--r--config/initializers/8_devise.rb8
-rw-r--r--config/initializers/active_support_json.rb23
-rw-r--r--config/initializers/database_query_analyzers.rb20
-rw-r--r--config/initializers/google_api_client_patch.rb3
-rw-r--r--config/initializers/hashie_mash_permitted_patch.rb53
-rw-r--r--config/initializers/memory_watchdog.rb31
-rw-r--r--config/initializers/sawyer_patch.rb48
-rw-r--r--config/initializers/sidekiq.rb19
-rw-r--r--config/initializers/sidekiq_cluster.rb2
-rw-r--r--config/initializers/types.rb3
-rw-r--r--config/initializers/zz_metrics.rb5
-rw-r--r--config/initializers_before_autoloader/000_inflections.rb2
-rw-r--r--config/locales/doorkeeper.zh-cn.yml122
-rw-r--r--config/metrics/counts_28d/20210216180745_action_monthly_active_users_design_management.yml4
-rw-r--r--config/metrics/counts_28d/20210216180747_action_monthly_active_users_wiki_repo.yml4
-rw-r--r--config/metrics/counts_28d/20210216181150_projects_jira_active.yml2
-rw-r--r--config/metrics/counts_28d/20210216181152_projects_jira_dvcs_cloud_active.yml2
-rw-r--r--config/metrics/counts_28d/20210216181154_projects_jira_dvcs_server_active.yml2
-rw-r--r--config/metrics/counts_28d/20210216182040_action_monthly_active_users_project_repo.yml4
-rw-r--r--config/metrics/counts_28d/20210216182041_action_monthly_active_users_git_write.yml4
-rw-r--r--config/metrics/counts_28d/20210216184941_i_ecosystem_jira_service_close_issue_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216184945_i_ecosystem_jira_service_cross_reference_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210216184957_ecosystem_total_unique_counts_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210303150507_i_ecosystem_slack_service_issue_notification_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210303150654_i_ecosystem_slack_service_push_notification_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210303150912_i_ecosystem_slack_service_deployment_notification_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210303151609_i_ecosystem_slack_service_wiki_page_notification_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210303151831_i_ecosystem_slack_service_merge_request_notification_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210303151946_i_ecosystem_slack_service_note_notification_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210303152049_i_ecosystem_slack_service_tag_push_notification_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210303152144_i_ecosystem_slack_service_confidential_note_notification_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20210303152233_i_ecosystem_slack_service_confidential_issue_notification_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20220222215951_xmau_plan.yml2
-rw-r--r--config/metrics/counts_28d/20220222215952_xmau_project_management.yml2
-rw-r--r--config/metrics/counts_28d/20220222215955_users_work_items.yml2
-rw-r--r--config/metrics/counts_28d/20220621085114_unique_active_users_monthly.yml2
-rw-r--r--config/metrics/counts_28d/20220707022802_users_updating_weight_estimate_monthly.yml26
-rw-r--r--config/metrics/counts_28d/20221031070329_users_updating_work_item_milestone_monthly.yml25
-rw-r--r--config/metrics/counts_28d/20221101190915_i_testing_coverage_report_uploaded_monthly.yml26
-rw-r--r--config/metrics/counts_28d/20221108101211_merge_request_authors_monthly.yml22
-rw-r--r--config/metrics/counts_7d/20210216180620_incident_management_total_unique_counts_weekly.yml5
-rw-r--r--config/metrics/counts_7d/20210216184848_deploy_token_packages_total_unique_counts_weekly.yml1
-rw-r--r--config/metrics/counts_7d/20210216184939_i_ecosystem_jira_service_close_issue_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210216184943_i_ecosystem_jira_service_cross_reference_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210216184955_ecosystem_total_unique_counts_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210302103002_i_ecosystem_slack_service_issue_notification_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210302103629_i_ecosystem_slack_service_push_notification_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210302103755_i_ecosystem_slack_service_deployment_notification_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210302103907_i_ecosystem_slack_service_wiki_page_notification_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210302104007_i_ecosystem_slack_service_merge_request_notification_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210302104047_i_ecosystem_slack_service_note_notification_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210302104144_i_ecosystem_slack_service_tag_push_notification_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210302104556_i_ecosystem_slack_service_confidential_note_notification_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210302104814_i_ecosystem_slack_service_confidential_issue_notification_weekly.yml2
-rw-r--r--config/metrics/counts_7d/20210916102312_templates_gitlab_slack_application_active.yml2
-rw-r--r--config/metrics/counts_7d/20220222215851_xmau_plan.yml2
-rw-r--r--config/metrics/counts_7d/20220222215852_xmau_project_management.yml2
-rw-r--r--config/metrics/counts_7d/20220222215855_users_work_items.yml2
-rw-r--r--config/metrics/counts_7d/20220707022758_users_updating_weight_estimate_weekly.yml26
-rw-r--r--config/metrics/counts_7d/20220909143617_i_package_rpm_user_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20220913104805_i_package_rpm_deploy_token_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20221031065930_users_updating_work_item_milestone_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20221101190913_i_testing_coverage_report_uploaded_weekly.yml26
-rw-r--r--config/metrics/counts_all/20210216175621_web_hooks.yml2
-rw-r--r--config/metrics/counts_all/20210216175623_projects_asana_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175625_groups_asana_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175627_templates_asana_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175628_instances_asana_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175630_projects_inheriting_asana_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175632_groups_inheriting_asana_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175634_projects_assembla_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175636_groups_assembla_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175638_templates_assembla_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175640_instances_assembla_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175642_projects_inheriting_assembla_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175644_groups_inheriting_assembla_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175645_projects_bamboo_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175647_groups_bamboo_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175649_templates_bamboo_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175651_instances_bamboo_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175653_projects_inheriting_bamboo_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175655_groups_inheriting_bamboo_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175657_projects_bugzilla_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175659_groups_bugzilla_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175701_templates_bugzilla_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175702_instances_bugzilla_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175704_projects_inheriting_bugzilla_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175706_groups_inheriting_bugzilla_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175708_projects_buildkite_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175710_groups_buildkite_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175712_templates_buildkite_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175714_instances_buildkite_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175716_projects_inheriting_buildkite_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175717_groups_inheriting_buildkite_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175719_projects_campfire_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175721_groups_campfire_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175723_templates_campfire_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175725_instances_campfire_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175727_projects_inheriting_campfire_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175729_groups_inheriting_campfire_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175731_projects_confluence_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175733_groups_confluence_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175734_templates_confluence_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175736_instances_confluence_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175738_projects_inheriting_confluence_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175740_groups_inheriting_confluence_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175742_projects_custom_issue_tracker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175744_groups_custom_issue_tracker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175745_templates_custom_issue_tracker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175747_instances_custom_issue_tracker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175749_projects_inheriting_custom_issue_tracker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175751_groups_inheriting_custom_issue_tracker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175753_projects_discord_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175755_groups_discord_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175756_templates_discord_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175758_instances_discord_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175800_projects_inheriting_discord_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175802_groups_inheriting_discord_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175804_projects_drone_ci_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175806_groups_drone_ci_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175807_templates_drone_ci_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175809_instances_drone_ci_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175811_projects_inheriting_drone_ci_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175813_groups_inheriting_drone_ci_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175815_projects_emails_on_push_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175817_groups_emails_on_push_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175818_templates_emails_on_push_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175820_instances_emails_on_push_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175822_projects_inheriting_emails_on_push_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175824_groups_inheriting_emails_on_push_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175826_projects_external_wiki_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175828_groups_external_wiki_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175829_templates_external_wiki_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175831_instances_external_wiki_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175833_projects_inheriting_external_wiki_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175835_groups_inheriting_external_wiki_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175837_projects_flowdock_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175839_groups_flowdock_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175840_templates_flowdock_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175842_instances_flowdock_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175844_projects_inheriting_flowdock_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175846_groups_inheriting_flowdock_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175859_projects_hangouts_chat_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175901_groups_hangouts_chat_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175902_templates_hangouts_chat_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175904_instances_hangouts_chat_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175906_projects_inheriting_hangouts_chat_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175908_groups_inheriting_hangouts_chat_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175910_projects_hipchat_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175912_groups_hipchat_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175913_templates_hipchat_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175915_instances_hipchat_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175917_projects_inheriting_hipchat_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175919_groups_inheriting_hipchat_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175921_projects_irker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175923_groups_irker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175924_templates_irker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175926_instances_irker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175928_projects_inheriting_irker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175930_groups_inheriting_irker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175932_projects_jenkins_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175934_groups_jenkins_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175935_templates_jenkins_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175937_instances_jenkins_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175939_projects_inheriting_jenkins_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175941_groups_inheriting_jenkins_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175943_projects_jira_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175945_groups_jira_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175946_templates_jira_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175948_instances_jira_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175950_projects_inheriting_jira_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175952_groups_inheriting_jira_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175954_projects_mattermost_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175956_groups_mattermost_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175957_templates_mattermost_active.yml2
-rw-r--r--config/metrics/counts_all/20210216175959_instances_mattermost_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180001_projects_inheriting_mattermost_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180003_groups_inheriting_mattermost_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180005_projects_mattermost_slash_commands_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180006_groups_mattermost_slash_commands_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180008_templates_mattermost_slash_commands_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180010_instances_mattermost_slash_commands_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180012_projects_inheriting_mattermost_slash_commands_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180014_groups_inheriting_mattermost_slash_commands_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180016_projects_microsoft_teams_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180018_groups_microsoft_teams_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180019_templates_microsoft_teams_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180021_instances_microsoft_teams_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180023_projects_inheriting_microsoft_teams_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180025_groups_inheriting_microsoft_teams_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180027_projects_packagist_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180029_groups_packagist_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180030_templates_packagist_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180032_instances_packagist_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180034_projects_inheriting_packagist_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180036_groups_inheriting_packagist_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180038_projects_pipelines_email_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180040_groups_pipelines_email_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180041_templates_pipelines_email_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180043_instances_pipelines_email_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180045_projects_inheriting_pipelines_email_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180047_groups_inheriting_pipelines_email_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180049_projects_pivotaltracker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180051_groups_pivotaltracker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180052_templates_pivotaltracker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180054_instances_pivotaltracker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180056_projects_inheriting_pivotaltracker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180058_groups_inheriting_pivotaltracker_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180100_projects_pushover_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180102_groups_pushover_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180104_templates_pushover_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180105_instances_pushover_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180107_projects_inheriting_pushover_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180109_groups_inheriting_pushover_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180111_projects_redmine_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180113_groups_redmine_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180115_templates_redmine_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180116_instances_redmine_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180118_projects_inheriting_redmine_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180120_groups_inheriting_redmine_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180122_projects_slack_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180124_groups_slack_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180126_templates_slack_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180127_instances_slack_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180129_projects_inheriting_slack_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180131_groups_inheriting_slack_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180133_projects_slack_slash_commands_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180135_groups_slack_slash_commands_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180137_templates_slack_slash_commands_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180138_instances_slack_slash_commands_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180140_projects_inheriting_slack_slash_commands_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180142_groups_inheriting_slack_slash_commands_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180144_projects_teamcity_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180146_groups_teamcity_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180148_templates_teamcity_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180149_instances_teamcity_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180151_projects_inheriting_teamcity_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180153_groups_inheriting_teamcity_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180155_projects_unify_circuit_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180157_groups_unify_circuit_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180159_templates_unify_circuit_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180201_instances_unify_circuit_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180203_projects_inheriting_unify_circuit_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180204_groups_inheriting_unify_circuit_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180206_projects_webex_teams_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180208_groups_webex_teams_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180210_templates_webex_teams_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180212_instances_webex_teams_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180214_projects_inheriting_webex_teams_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180215_groups_inheriting_webex_teams_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180217_projects_youtrack_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180219_groups_youtrack_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180221_templates_youtrack_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180223_instances_youtrack_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180225_projects_inheriting_youtrack_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180226_groups_inheriting_youtrack_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180228_projects_jira_server_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180230_projects_jira_cloud_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180232_projects_jira_dvcs_cloud_active.yml2
-rw-r--r--config/metrics/counts_all/20210216180234_projects_jira_dvcs_server_active.yml2
-rw-r--r--config/metrics/counts_all/20210216181014_projects_with_expiration_policy_disabled.yml4
-rw-r--r--config/metrics/counts_all/20210216181016_projects_with_expiration_policy_enabled.yml3
-rw-r--r--config/metrics/counts_all/20210216181018_projects_with_expiration_policy_enabled_with_keep_n_set_to_1.yml4
-rw-r--r--config/metrics/counts_all/20210216181020_projects_with_expiration_policy_enabled_with_keep_n_set_to_5.yml4
-rw-r--r--config/metrics/counts_all/20210216181022_projects_with_expiration_policy_enabled_with_keep_n_set_to_10.yml4
-rw-r--r--config/metrics/counts_all/20210216181024_projects_with_expiration_policy_enabled_with_keep_n_set_to_25.yml4
-rw-r--r--config/metrics/counts_all/20210216181025_projects_with_expiration_policy_enabled_with_keep_n_set_to_50.yml4
-rw-r--r--config/metrics/counts_all/20210216181027_projects_with_expiration_policy_enabled_with_keep_n_set_to_100.yml4
-rw-r--r--config/metrics/counts_all/20210216181029_projects_with_expiration_policy_enabled_with_cadence_set_to_1d.yml4
-rw-r--r--config/metrics/counts_all/20210216181031_projects_with_expiration_policy_enabled_with_cadence_set_to_7d.yml4
-rw-r--r--config/metrics/counts_all/20210216181033_projects_with_expiration_policy_enabled_with_cadence_set_to_14d.yml4
-rw-r--r--config/metrics/counts_all/20210216181035_projects_with_expiration_policy_enabled_with_cadence_set_to_1month.yml4
-rw-r--r--config/metrics/counts_all/20210216181037_projects_with_expiration_policy_enabled_with_cadence_set_to_3month.yml4
-rw-r--r--config/metrics/counts_all/20210216181046_projects_with_expiration_policy_enabled_with_keep_n_unset.yml4
-rw-r--r--config/metrics/counts_all/20210216181126_projects_jira_active.yml2
-rw-r--r--config/metrics/counts_all/20210216181128_projects_jira_dvcs_cloud_active.yml2
-rw-r--r--config/metrics/counts_all/20210216181130_projects_jira_dvcs_server_active.yml2
-rw-r--r--config/metrics/counts_all/20210216181258_jira_imports_total_imported_count.yml2
-rw-r--r--config/metrics/counts_all/20210216181259_jira_imports_projects_count.yml2
-rw-r--r--config/metrics/counts_all/20210216181301_jira_imports_total_imported_issues_count.yml2
-rw-r--r--config/metrics/counts_all/20210216182547_projects_datadog_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182549_groups_datadog_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182551_templates_datadog_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182553_instances_datadog_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182555_projects_inheriting_datadog_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182557_groups_inheriting_datadog_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182614_projects_ewm_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182616_groups_ewm_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182618_templates_ewm_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182620_instances_ewm_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182622_projects_inheriting_ewm_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182623_groups_inheriting_ewm_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182722_projects_mock_ci_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182724_groups_mock_ci_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182726_templates_mock_ci_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182728_instances_mock_ci_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182730_projects_inheriting_mock_ci_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182732_groups_inheriting_mock_ci_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182734_projects_mock_monitoring_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182736_groups_mock_monitoring_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182738_templates_mock_monitoring_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182739_instances_mock_monitoring_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182741_projects_inheriting_mock_monitoring_active.yml2
-rw-r--r--config/metrics/counts_all/20210216182743_groups_inheriting_mock_monitoring_active.yml2
-rw-r--r--config/metrics/counts_all/20210216183000_package_events_i_package_pull_package_by_guest.yml2
-rw-r--r--config/metrics/counts_all/20210216183005_package_events_i_package_push_package_by_deploy_token.yml2
-rw-r--r--config/metrics/counts_all/20210510201537_in_product_marketing_email_create_0_sent.yml4
-rw-r--r--config/metrics/counts_all/20210510201919_in_product_marketing_email_create_0_cta_clicked.yml4
-rw-r--r--config/metrics/counts_all/20210510202148_in_product_marketing_email_create_1_sent.yml4
-rw-r--r--config/metrics/counts_all/20210510202356_in_product_marketing_email_create_1_cta_clicked.yml4
-rw-r--r--config/metrics/counts_all/20210510202604_in_product_marketing_email_create_2_sent.yml4
-rw-r--r--config/metrics/counts_all/20210510202724_in_product_marketing_email_create_2_cta_clicked.yml4
-rw-r--r--config/metrics/counts_all/20210510202807_in_product_marketing_email_verify_0_sent.yml4
-rw-r--r--config/metrics/counts_all/20210510202943_in_product_marketing_email_verify_0_cta_clicked.yml4
-rw-r--r--config/metrics/counts_all/20210510202955_in_product_marketing_email_verify_1_sent.yml4
-rw-r--r--config/metrics/counts_all/20210510203005_in_product_marketing_email_verify_1_cta_clicked.yml4
-rw-r--r--config/metrics/counts_all/20210510203015_in_product_marketing_email_verify_2_sent.yml4
-rw-r--r--config/metrics/counts_all/20210510203025_in_product_marketing_email_verify_2_cta_clicked.yml4
-rw-r--r--config/metrics/counts_all/20210510203035_in_product_marketing_email_trial_0_sent.yml4
-rw-r--r--config/metrics/counts_all/20210510203044_in_product_marketing_email_trial_0_cta_clicked.yml4
-rw-r--r--config/metrics/counts_all/20210510203054_in_product_marketing_email_trial_1_sent.yml4
-rw-r--r--config/metrics/counts_all/20210510203104_in_product_marketing_email_trial_1_cta_clicked.yml4
-rw-r--r--config/metrics/counts_all/20210510203114_in_product_marketing_email_trial_2_sent.yml4
-rw-r--r--config/metrics/counts_all/20210510203124_in_product_marketing_email_trial_2_cta_clicked.yml4
-rw-r--r--config/metrics/counts_all/20210510203134_in_product_marketing_email_team_0_sent.yml4
-rw-r--r--config/metrics/counts_all/20210510203143_in_product_marketing_email_team_0_cta_clicked.yml4
-rw-r--r--config/metrics/counts_all/20210510203153_in_product_marketing_email_team_1_sent.yml4
-rw-r--r--config/metrics/counts_all/20210510203203_in_product_marketing_email_team_1_cta_clicked.yml4
-rw-r--r--config/metrics/counts_all/20210510203213_in_product_marketing_email_team_2_sent.yml4
-rw-r--r--config/metrics/counts_all/20210510203223_in_product_marketing_email_team_2_cta_clicked.yml4
-rw-r--r--config/metrics/counts_all/20210727095918_in_product_marketing_email_team_short_0_cta_clicked.yml4
-rw-r--r--config/metrics/counts_all/20210727095923_in_product_marketing_email_team_short_0_sent.yml4
-rw-r--r--config/metrics/counts_all/20210727170553_in_product_marketing_email_trial_short_0_cta_clicked.yml4
-rw-r--r--config/metrics/counts_all/20210727170558_in_product_marketing_email_trial_short_0_sent.yml4
-rw-r--r--config/metrics/counts_all/20210729140021_in_product_marketing_email_admin_verify_0_cta_clicked.yml4
-rw-r--r--config/metrics/counts_all/20210729140423_in_product_marketing_email_admin_verify_0_sent.yml4
-rw-r--r--config/metrics/counts_all/20210730011801_projects_zentao_active.yml2
-rw-r--r--config/metrics/counts_all/20210730011802_groups_zentao_active.yml2
-rw-r--r--config/metrics/counts_all/20210730011804_instances_zentao_active.yml2
-rw-r--r--config/metrics/counts_all/20210730011805_projects_inheriting_zentao_active.yml2
-rw-r--r--config/metrics/counts_all/20210730011806_groups_inheriting_zentao_active.yml2
-rw-r--r--config/metrics/counts_all/20210916100524_groups_gitlab_slack_application_active.yml2
-rw-r--r--config/metrics/counts_all/20210916101641_projects_gitlab_slack_application_active.yml2
-rw-r--r--config/metrics/counts_all/20210916101837_instances_gitlab_slack_application_active.yml2
-rw-r--r--config/metrics/counts_all/20210917040700_groups_inheriting_gitlab_slack_application_active.yml2
-rw-r--r--config/metrics/counts_all/20210917040956_projects_inheriting_gitlab_slack_application_active.yml2
-rw-r--r--config/metrics/counts_all/20211028210001_projects_shimo_active.yml2
-rw-r--r--config/metrics/counts_all/20211028210002_groups_shimo_active.yml2
-rw-r--r--config/metrics/counts_all/20211028210003_instances_shimo_active.yml2
-rw-r--r--config/metrics/counts_all/20211028210004_projects_inheriting_shimo_active.yml2
-rw-r--r--config/metrics/counts_all/20211028210005_groups_inheriting_shimo_active.yml2
-rw-r--r--config/metrics/counts_all/20220315180122_projects_harbor_active.yml2
-rw-r--r--config/metrics/counts_all/20220315180124_groups_harbor_active.yml2
-rw-r--r--config/metrics/counts_all/20220315180127_instances_harbor_active.yml2
-rw-r--r--config/metrics/counts_all/20220315180129_projects_inheriting_harbor_active.yml2
-rw-r--r--config/metrics/counts_all/20220315180131_groups_inheriting_harbor_active.yml2
-rw-r--r--config/metrics/counts_all/20220802141715_groups_inheriting_pumble_active.yml2
-rw-r--r--config/metrics/counts_all/20220802141715_groups_pumble_active.yml2
-rw-r--r--config/metrics/counts_all/20220802141715_instances_pumble_active.yml2
-rw-r--r--config/metrics/counts_all/20220802141715_projects_inheriting_pumble_active.yml2
-rw-r--r--config/metrics/counts_all/20220802141715_projects_pumble_active.yml2
-rw-r--r--config/metrics/counts_all/20220906074055_package_events_i_package_rpm_pull_package.yml25
-rw-r--r--config/metrics/counts_all/20220906074525_package_events_i_package_rpm_push_package.yml25
-rw-r--r--config/metrics/counts_all/20220912145754_gitlab_for_jira_app_direct_installations.yml2
-rw-r--r--config/metrics/counts_all/20220913083454_gitlab_for_jira_app_proxy_installations.yml2
-rw-r--r--config/metrics/settings/20210204124908_mattermost_enabled.yml2
-rw-r--r--config/metrics/settings/20221015152126_deactivate_dormant_users_enabled.yml23
-rw-r--r--config/metrics/settings/20221015161233_deactivate_dormant_users_period.yml23
-rw-r--r--config/open_api.yml93
-rw-r--r--config/puma.example.development.rb5
-rw-r--r--config/puma.rb.example5
-rw-r--r--config/routes.rb8
-rw-r--r--config/routes/group.rb6
-rw-r--r--config/routes/project.rb18
-rw-r--r--config/sidekiq_queues.yml6
-rw-r--r--danger/architecture/Dangerfile27
-rw-r--r--danger/documentation/Dangerfile6
-rw-r--r--danger/pajamas/Dangerfile2
-rw-r--r--danger/pipeline/Dangerfile2
-rw-r--r--danger/rubygems/Dangerfile11
-rw-r--r--data/deprecations/14-3-serverless.yml4
-rw-r--r--data/deprecations/14-7-deprecate-merged_by-api-field.yml6
-rw-r--r--data/deprecations/14-7-deprecate-static-site-editor.yml4
-rw-r--r--data/deprecations/14-8-Elasticsearch-6-8.yml2
-rw-r--r--data/deprecations/14-8-graphql-ids.yml2
-rw-r--r--data/deprecations/14-8-request-profiling.yml4
-rw-r--r--data/deprecations/14-8-sast-analyzer-removals.yml6
-rw-r--r--data/deprecations/15-1-jira-github-enterprise-dvcs.yml2
-rw-r--r--data/deprecations/15-2-job_age-deprecation.yml2
-rw-r--r--data/deprecations/15-3-deprecate-redis-5.yml2
-rw-r--r--data/deprecations/15-4-create-deprecation-draft-quick-action-toggle.yml6
-rw-r--r--data/deprecations/15-5-disable-file-type-var-expansion-ci-pipeline.yml13
-rw-r--r--data/deprecations/15-6-deprecate-config-fields-runner-helm-chart.yml13
-rw-r--r--data/deprecations/15-6-deprecate-merge_status-api-field.yml15
-rw-r--r--data/deprecations/15-6-deprecate-post-api-v4-runner.yml24
-rw-r--r--data/deprecations/15-6-deprecate-runner-reg-token-helm.yml19
-rw-r--r--data/deprecations/15-6-deprecate-runner-register-command.yml18
-rw-r--r--data/deprecations/15-6-deprecate-runner-register-token-k8s-operator.yml21
-rw-r--r--data/deprecations/templates/example.yml6
-rw-r--r--data/removals/14_0/release_remove_redundant_keyvalue_pair_from_the_payload_of_dora.yml2
-rw-r--r--data/removals/14_0/removals-14-testing-team.yml4
-rw-r--r--data/removals/15_0/15-0-advanced-search-elasticsearch-6-8.yml2
-rw-r--r--data/removals/15_0/15-0-request-profiling.yml2
-rw-r--r--data/removals/15_0/15-0-static-site-editor.yml4
-rw-r--r--data/removals/16_0/source_code-approvals-endpoint.yml20
-rw-r--r--data/whats_new/202011230001_13_06.yml2
-rw-r--r--data/whats_new/202103220001_13_10.yml4
-rw-r--r--data/whats_new/202105220001_13_12.yml2
-rw-r--r--data/whats_new/202205220001_15_0.yml2
-rw-r--r--data/whats_new/202206220001_15_1.yml4
-rw-r--r--data/whats_new/202207220001_15_2.yml26
-rw-r--r--data/whats_new/202209220001_15_04.yml126
-rw-r--r--db/docs/approval_merge_request_rule_sources.yml2
-rw-r--r--db/docs/approval_merge_request_rules.yml2
-rw-r--r--db/docs/approval_merge_request_rules_groups.yml2
-rw-r--r--db/docs/approval_merge_request_rules_users.yml2
-rw-r--r--db/docs/approval_project_rules.yml2
-rw-r--r--db/docs/approval_project_rules_groups.yml2
-rw-r--r--db/docs/approval_project_rules_protected_branches.yml2
-rw-r--r--db/docs/approval_project_rules_users.yml2
-rw-r--r--db/docs/approvals.yml2
-rw-r--r--db/docs/approver_groups.yml5
-rw-r--r--db/docs/approvers.yml1
-rw-r--r--db/docs/audit_events_streaming_event_type_filters.yml9
-rw-r--r--db/docs/ci_build_report_results.yml2
-rw-r--r--db/docs/ci_daily_build_group_report_results.yml2
-rw-r--r--db/docs/ci_deleted_objects.yml2
-rw-r--r--db/docs/ci_job_artifacts.yml2
-rw-r--r--db/docs/ci_pipeline_artifacts.yml2
-rw-r--r--db/docs/ci_unit_test_failures.yml2
-rw-r--r--db/docs/ci_unit_tests.yml2
-rw-r--r--db/docs/content_blocked_states.yml2
-rw-r--r--db/docs/dependency_proxy_blob_states.yml9
-rw-r--r--db/docs/diff_note_positions.yml2
-rw-r--r--db/docs/experiment_users.yml9
-rw-r--r--db/docs/external_approval_rules_protected_branches.yml4
-rw-r--r--db/docs/external_status_checks.yml4
-rw-r--r--db/docs/external_status_checks_protected_branches.yml4
-rw-r--r--db/docs/fork_network_members.yml4
-rw-r--r--db/docs/gpg_key_subkeys.yml4
-rw-r--r--db/docs/gpg_keys.yml4
-rw-r--r--db/docs/gpg_signatures.yml4
-rw-r--r--db/docs/group_merge_request_approval_settings.yml2
-rw-r--r--db/docs/merge_request_blocks.yml6
-rw-r--r--db/docs/merge_request_context_commit_diff_files.yml4
-rw-r--r--db/docs/namespace_aggregation_schedules.yml6
-rw-r--r--db/docs/namespace_commit_emails.yml9
-rw-r--r--db/docs/p_ci_builds_metadata.yml9
-rw-r--r--db/docs/path_locks.yml2
-rw-r--r--db/docs/project_aliases.yml2
-rw-r--r--db/docs/project_build_artifacts_size_refreshes.yml2
-rw-r--r--db/docs/project_ci_feature_usages.yml2
-rw-r--r--db/docs/project_daily_statistics.yml4
-rw-r--r--db/docs/project_repositories.yml2
-rw-r--r--db/docs/project_repository_states.yml4
-rw-r--r--db/docs/project_repository_storage_moves.yml4
-rw-r--r--db/docs/project_wiki_repositories.yml9
-rw-r--r--db/docs/protected_branch_merge_access_levels.yml2
-rw-r--r--db/docs/protected_branch_push_access_levels.yml2
-rw-r--r--db/docs/protected_branch_unprotect_access_levels.yml2
-rw-r--r--db/docs/protected_branches.yml2
-rw-r--r--db/docs/protected_tag_create_access_levels.yml2
-rw-r--r--db/docs/protected_tags.yml4
-rw-r--r--db/docs/push_event_payloads.yml6
-rw-r--r--db/docs/remote_mirrors.yml4
-rw-r--r--db/docs/repository_languages.yml4
-rw-r--r--db/docs/required_code_owners_sections.yml2
-rw-r--r--db/docs/software_license_policies.yml2
-rw-r--r--db/docs/software_licenses.yml2
-rw-r--r--db/docs/trending_projects.yml4
-rw-r--r--db/docs/x509_certificates.yml2
-rw-r--r--db/docs/x509_commit_signatures.yml2
-rw-r--r--db/docs/x509_issuers.yml2
-rw-r--r--db/fixtures/development/17_cycle_analytics.rb7
-rw-r--r--db/fixtures/development/98_gitlab_instance_administration_project.rb7
-rw-r--r--db/fixtures/production/998_gitlab_instance_administration_project.rb4
-rw-r--r--db/migrate/20210305031822_create_dast_site_profile_variables.rb2
-rw-r--r--db/migrate/20210317035357_create_dast_profiles_pipelines.rb2
-rw-r--r--db/migrate/20210412111213_create_security_orchestration_policy_rule_schedule.rb2
-rw-r--r--db/migrate/20210423054022_create_dast_site_profiles_pipelines.rb2
-rw-r--r--db/migrate/20210604032738_create_dast_site_profiles_builds.rb2
-rw-r--r--db/migrate/20210604051330_create_dast_scanner_profiles_builds.rb2
-rw-r--r--db/migrate/20210713123345_create_dast_profile_schedule.rb2
-rw-r--r--db/migrate/20220613112029_add_namespace_id_to_protected_branches.rb9
-rw-r--r--db/migrate/20220613112030_add_namespace_id_indexes_foreign_key_to_protected_branches.rb19
-rw-r--r--db/migrate/20220613112031_add_group_or_project_constraint_in_protected_branches.rb18
-rw-r--r--db/migrate/20220613112032_change_project_id_null_in_protected_branches.rb13
-rw-r--r--db/migrate/20220721065723_add_issue_branch_template_to_project_settings.rb17
-rw-r--r--db/migrate/20220919062640_add_mirror_branch_regex_to_remote_mirrors.rb15
-rw-r--r--db/migrate/20220920135632_add_jira_connect_proxy_url_setting.rb10
-rw-r--r--db/migrate/20220920135717_add_textlimit_to_jira_connect_proxy_url_setting.rb13
-rw-r--r--db/migrate/20220926023734_add_mirror_branch_regex_to_project_settings.rb12
-rw-r--r--db/migrate/20221003151747_create_audit_events_streaming_event_type_filters.rb18
-rw-r--r--db/migrate/20221010103207_add_product_analytics_enabled_to_application_settings.rb7
-rw-r--r--db/migrate/20221010184839_add_new_amount_used_to_ci_project_monthly_usages.rb24
-rw-r--r--db/migrate/20221010201815_add_purl_type_to_sbom_components.rb7
-rw-r--r--db/migrate/20221010202339_remove_unique_index_on_sbom_components_type_and_name.rb15
-rw-r--r--db/migrate/20221010202408_add_unique_index_on_sbom_components_type_name_and_purl_type.rb15
-rw-r--r--db/migrate/20221013103738_add_disable_admin_oauth_scopes.rb7
-rw-r--r--db/migrate/20221015000511_add_email_confirmation_setting_to_application_settings.rb7
-rw-r--r--db/migrate/20221017084208_rename_ci_pipeline_metadata_title.rb13
-rw-r--r--db/migrate/20221018050323_add_objective_and_keyresult_to_work_item_types.rb56
-rw-r--r--db/migrate/20221018092552_add_file_name_index_to_packages_rpm_repository_files.rb18
-rw-r--r--db/migrate/20221018124029_add_consume_after_to_ghost_user_migrations.rb7
-rw-r--r--db/migrate/20221018124035_add_consume_after_index_to_ghost_user_migrations.rb15
-rw-r--r--db/migrate/20221018202524_create_dependency_proxy_blob_states.rb49
-rw-r--r--db/migrate/20221020124018_add_delete_started_at_to_container_repositories.rb11
-rw-r--r--db/migrate/20221021213216_create_namespace_commit_emails.rb14
-rw-r--r--db/migrate/20221022213505_add_namespace_commit_emails_namespace_fk.rb15
-rw-r--r--db/migrate/20221022213521_add_namespace_commit_emails_email_fk.rb15
-rw-r--r--db/migrate/20221025043930_change_default_value_on_password_last_changed_at_to_user_details.rb13
-rw-r--r--db/migrate/20221025105205_add_status_and_id_index_to_container_repositories.rb15
-rw-r--r--db/migrate/20221025145452_change_vulnerability_feedback_unique_idx.rb25
-rw-r--r--db/migrate/20221025150202_add_index_for_finding_uuid_and_feedback_type_on_feedback.rb15
-rw-r--r--db/migrate/20221027124848_add_text_limit_to_project_settings_mirror_branch_regex.rb13
-rw-r--r--db/migrate/20221028015347_add_commit_committer_name_check_to_push_rules.rb7
-rw-r--r--db/migrate/20221028152422_add_finding_data_column_to_security_findings.rb13
-rw-r--r--db/migrate/20221031102916_add_users_foreign_key_to_projects.rb15
-rw-r--r--db/migrate/20221101032521_add_default_preferred_language_to_application_settings.rb10
-rw-r--r--db/migrate/20221101032600_add_text_limit_to_default_preferred_language_on_application_settings.rb15
-rw-r--r--db/migrate/20221101195903_change_email_confirmation_setting_default.rb7
-rw-r--r--db/migrate/20221101201031_set_email_confirmation_setting_from_send_user_confirmation_email_setting.rb22
-rw-r--r--db/migrate/20221102202130_extend_x509_subject_limit.rb11
-rw-r--r--db/migrate/20221102225800_add_max_seats_used_changed_at_index_to_gitlab_subscriptions.rb15
-rw-r--r--db/migrate/20221103131409_add_partial_index_on_primary_key_of_security_scans.rb15
-rw-r--r--db/migrate/20221104061320_add_disable_download_button_into_application_settings.rb8
-rw-r--r--db/migrate/20221104094042_remove_users_foreign_key_to_projects.rb15
-rw-r--r--db/migrate/20221107115247_change_scim_identity_group_id_remove_null.rb10
-rw-r--r--db/migrate/20221107115413_change_scim_oauth_access_token_group_id_remove_null.rb10
-rw-r--r--db/migrate/20221107183222_create_project_wiki_repositories.rb11
-rw-r--r--db/migrate/20221107184542_add_new_amount_used_to_ci_namespace_monthly_usages.rb24
-rw-r--r--db/migrate/20221108015813_add_telesign_to_application_settings.rb11
-rw-r--r--db/migrate/20221108185442_add_project_wiki_repository_id_to_project_wiki_repository_states.rb35
-rw-r--r--db/migrate/20221110105857_add_index_for_in_product_marketing_email_metrics.rb15
-rw-r--r--db/migrate/20221110150942_add_project_id_lower_name_index_remove_old_index.rb26
-rw-r--r--db/post_migrate/20210311120155_backfill_events_id_for_bigint_conversion.rb2
-rw-r--r--db/post_migrate/20210311120156_backfill_push_event_payload_event_id_for_bigint_conversion.rb2
-rw-r--r--db/post_migrate/20210415101228_backfill_ci_build_needs_for_bigint_conversion.rb2
-rw-r--r--db/post_migrate/20210420121149_backfill_conversion_of_ci_job_artifacts.rb2
-rw-r--r--db/post_migrate/20210422023046_backfill_ci_sources_pipelines_source_job_id_for_bigint_conversion.rb2
-rw-r--r--db/post_migrate/20210615234935_fix_batched_migrations_old_format_job_arguments.rb4
-rw-r--r--db/post_migrate/20210818185845_backfill_projects_with_coverage.rb23
-rw-r--r--db/post_migrate/20220802112102_schedule_migrate_shared_vulnerability_scanners.rb24
-rw-r--r--db/post_migrate/20220919080303_delete_migrate_shared_vulnerability_scanners.rb44
-rw-r--r--db/post_migrate/20220919080304_reschedule_migrate_shared_vulnerability_scanners.rb29
-rw-r--r--db/post_migrate/20220927171740_prepare_for_vulnerability_occurrences_uuid_type_transition.rb26
-rw-r--r--db/post_migrate/20221004074910_routing_table_prepare_constraint_for_builds_metadata.rb30
-rw-r--r--db/post_migrate/20221004074914_create_routing_table_for_builds_metadata.rb7
-rw-r--r--db/post_migrate/20221006070927_finalize_invalid_member_cleanup.rb22
-rw-r--r--db/post_migrate/20221006172302_adjust_task_note_rename_background_migration_values.rb2
-rw-r--r--db/post_migrate/20221010141500_add_index_author_id_target_project_id_on_merge_requests.rb15
-rw-r--r--db/post_migrate/20221010162137_add_index_author_id_and_id_on_merge_requests.rb15
-rw-r--r--db/post_migrate/20221011062254_sync_new_amount_used_for_ci_project_monthly_usages.rb19
-rw-r--r--db/post_migrate/20221013215832_cleanup_vulnerability_state_transitions_with_same_from_state_to_state.rb19
-rw-r--r--db/post_migrate/20221017084227_cleanup_rename_ci_pipeline_metadata_title.rb13
-rw-r--r--db/post_migrate/20221018062308_schedule_backfill_project_namespace_details.rb29
-rw-r--r--db/post_migrate/20221018193635_ensure_task_note_renaming_background_migration_finished.rb22
-rw-r--r--db/post_migrate/20221018193827_drop_tmp_index_system_note_metadata_on_id_where_task.rb15
-rw-r--r--db/post_migrate/20221018232820_add_temp_index_for_user_details_fields.rb22
-rw-r--r--db/post_migrate/20221019002459_queue_backfill_user_details_fields.rb16
-rw-r--r--db/post_migrate/20221019102426_remove_tmp_index_approval_merge_request_rules_on_report_type.rb18
-rw-r--r--db/post_migrate/20221019105041_queue_populate_projects_star_count.rb22
-rw-r--r--db/post_migrate/20221019141508_add_index_to_test_reports_issue_id_created_at_and_id.rb16
-rw-r--r--db/post_migrate/20221019194751_disable_fastupdate_on_issues_title_gin_index.rb23
-rw-r--r--db/post_migrate/20221019195754_disable_fastupdate_on_issues_description_gin_index.rb23
-rw-r--r--db/post_migrate/20221019200033_disable_fastupdate_on_merge_requests_title_gin_index.rb23
-rw-r--r--db/post_migrate/20221019200206_disable_fastupdate_on_merge_requests_description_gin_index.rb23
-rw-r--r--db/post_migrate/20221021082255_add_unique_index_on_ci_runners_token.rb20
-rw-r--r--db/post_migrate/20221021082312_add_unique_index_on_ci_runners_token_encrypted.rb20
-rw-r--r--db/post_migrate/20221021082720_drop_index_on_ci_runners_token.rb17
-rw-r--r--db/post_migrate/20221021082734_drop_index_on_ci_runners_token_encrypted.rb17
-rw-r--r--db/post_migrate/20221021145820_create_routing_table_for_builds_metadata_v2.rb41
-rw-r--r--db/post_migrate/20221021160735_add_index_for_common_finder_query_desc_with_namespace_id.rb18
-rw-r--r--db/post_migrate/20221024034228_remove_sprints_project_id_column.rb38
-rw-r--r--db/post_migrate/20221024121500_drop_fingerprint_from_sbom_sources.rb9
-rw-r--r--db/post_migrate/20221025115006_check_vulnerabilities_state_transition_from_state_not_equal_to_state.rb19
-rw-r--r--db/post_migrate/20221025220607_add_index_id_on_scan_finding_approval_merge_request_rules.rb17
-rw-r--r--db/post_migrate/20221027203556_delete_experiment_user_foreign_keys.rb20
-rw-r--r--db/post_migrate/20221027203951_drop_experiment_users_table.rb21
-rw-r--r--db/post_migrate/20221028000041_remove_invalid_partial_trigram_indexes_for_issues.rb15
-rw-r--r--db/post_migrate/20221028000603_prepare_partial_trigram_indexes_for_issues_attempt_3.rb25
-rw-r--r--db/post_migrate/20221028022627_add_index_on_password_last_changed_at_to_user_details.rb15
-rw-r--r--db/post_migrate/20221102090940_create_next_ci_partitions_record.rb29
-rw-r--r--db/post_migrate/20221102090943_create_second_partition_for_builds_metadata.rb62
-rw-r--r--db/post_migrate/20221103073328_change_member_namespace_id_not_null.rb16
-rw-r--r--db/post_migrate/20221103084213_remove_tmp_index_members_on_id_where_namespace_id_null.rb15
-rw-r--r--db/post_migrate/20221103150250_migrate_sidekiq_queued_jobs.rb11
-rw-r--r--db/post_migrate/20221104042137_add_partial_trigram_index_for_issue_title_attempt_2.rb19
-rw-r--r--db/post_migrate/20221104042159_add_partial_trigram_index_for_issue_description_attempt_2.rb19
-rw-r--r--db/post_migrate/20221104074652_add_temp_index_for_project_statistics_upload_size_migration.rb19
-rw-r--r--db/post_migrate/20221104100203_recreate_async_trigram_index_for_vulnerability_reads_container_images.rb21
-rw-r--r--db/post_migrate/20221104170500_add_vulnerability_reads_all_status_index.rb14
-rw-r--r--db/post_migrate/20221104190203_validate_environment_id_on_deployments.rb11
-rw-r--r--db/post_migrate/20221107094359_recount_epic_cache_counts.rb29
-rw-r--r--db/post_migrate/20221107184758_sync_new_amount_used_for_ci_namespace_monthly_usages.rb19
-rw-r--r--db/post_migrate/20221107220420_validate_not_null_constraint_on_member_namespace_id.rb15
-rw-r--r--db/post_migrate/20221107220526_validate_fk_member_namespace_id.rb13
-rw-r--r--db/post_migrate/20221107222213_remove_old_member_namespace_id_fk.rb28
-rw-r--r--db/post_migrate/20221108045019_truncate_timeline_event_tags_table.rb13
-rw-r--r--db/post_migrate/20221108121322_add_supporting_index_for_vulnerabilities_feedback_migration.rb24
-rw-r--r--db/post_migrate/20221108222015_remove_temp_index_on_project_features_where_releases_access_level_gt_repository.rb18
-rw-r--r--db/post_migrate/20221110045406_sanitize_confidential_note_todos.rb31
-rw-r--r--db/post_migrate/20221111070314_prepare_removal_of_issue_trigram_indexes.rb16
-rw-r--r--db/schema_migrations/202206131120291
-rw-r--r--db/schema_migrations/202206131120301
-rw-r--r--db/schema_migrations/202206131120311
-rw-r--r--db/schema_migrations/202206131120321
-rw-r--r--db/schema_migrations/202207210657231
-rw-r--r--db/schema_migrations/202209190626401
-rw-r--r--db/schema_migrations/202209190803031
-rw-r--r--db/schema_migrations/202209190803041
-rw-r--r--db/schema_migrations/202209201356321
-rw-r--r--db/schema_migrations/202209201357171
-rw-r--r--db/schema_migrations/202209260237341
-rw-r--r--db/schema_migrations/202209271717401
-rw-r--r--db/schema_migrations/202210031517471
-rw-r--r--db/schema_migrations/202210040749101
-rw-r--r--db/schema_migrations/202210040749141
-rw-r--r--db/schema_migrations/202210060709271
-rw-r--r--db/schema_migrations/202210101032071
-rw-r--r--db/schema_migrations/202210101415001
-rw-r--r--db/schema_migrations/202210101621371
-rw-r--r--db/schema_migrations/202210101848391
-rw-r--r--db/schema_migrations/202210102018151
-rw-r--r--db/schema_migrations/202210102023391
-rw-r--r--db/schema_migrations/202210102024081
-rw-r--r--db/schema_migrations/202210110622541
-rw-r--r--db/schema_migrations/202210131037381
-rw-r--r--db/schema_migrations/202210132158321
-rw-r--r--db/schema_migrations/202210150005111
-rw-r--r--db/schema_migrations/202210170842081
-rw-r--r--db/schema_migrations/202210170842271
-rw-r--r--db/schema_migrations/202210180503231
-rw-r--r--db/schema_migrations/202210180623081
-rw-r--r--db/schema_migrations/202210180925521
-rw-r--r--db/schema_migrations/202210181240291
-rw-r--r--db/schema_migrations/202210181240351
-rw-r--r--db/schema_migrations/202210181936351
-rw-r--r--db/schema_migrations/202210181938271
-rw-r--r--db/schema_migrations/202210182025241
-rw-r--r--db/schema_migrations/202210182328201
-rw-r--r--db/schema_migrations/202210190024591
-rw-r--r--db/schema_migrations/202210191024261
-rw-r--r--db/schema_migrations/202210191050411
-rw-r--r--db/schema_migrations/202210191415081
-rw-r--r--db/schema_migrations/202210191947511
-rw-r--r--db/schema_migrations/202210191957541
-rw-r--r--db/schema_migrations/202210192000331
-rw-r--r--db/schema_migrations/202210192002061
-rw-r--r--db/schema_migrations/202210201240181
-rw-r--r--db/schema_migrations/202210210822551
-rw-r--r--db/schema_migrations/202210210823121
-rw-r--r--db/schema_migrations/202210210827201
-rw-r--r--db/schema_migrations/202210210827341
-rw-r--r--db/schema_migrations/202210211458201
-rw-r--r--db/schema_migrations/202210211607351
-rw-r--r--db/schema_migrations/202210212132161
-rw-r--r--db/schema_migrations/202210222135051
-rw-r--r--db/schema_migrations/202210222135211
-rw-r--r--db/schema_migrations/202210240342281
-rw-r--r--db/schema_migrations/202210241215001
-rw-r--r--db/schema_migrations/202210250439301
-rw-r--r--db/schema_migrations/202210251052051
-rw-r--r--db/schema_migrations/202210251150061
-rw-r--r--db/schema_migrations/202210251454521
-rw-r--r--db/schema_migrations/202210251502021
-rw-r--r--db/schema_migrations/202210252206071
-rw-r--r--db/schema_migrations/202210271248481
-rw-r--r--db/schema_migrations/202210272035561
-rw-r--r--db/schema_migrations/202210272039511
-rw-r--r--db/schema_migrations/202210280000411
-rw-r--r--db/schema_migrations/202210280006031
-rw-r--r--db/schema_migrations/202210280153471
-rw-r--r--db/schema_migrations/202210280226271
-rw-r--r--db/schema_migrations/202210281524221
-rw-r--r--db/schema_migrations/202210311029161
-rw-r--r--db/schema_migrations/202211010325211
-rw-r--r--db/schema_migrations/202211010326001
-rw-r--r--db/schema_migrations/202211011959031
-rw-r--r--db/schema_migrations/202211012010311
-rw-r--r--db/schema_migrations/202211020909401
-rw-r--r--db/schema_migrations/202211020909431
-rw-r--r--db/schema_migrations/202211022021301
-rw-r--r--db/schema_migrations/202211022258001
-rw-r--r--db/schema_migrations/202211030733281
-rw-r--r--db/schema_migrations/202211030842131
-rw-r--r--db/schema_migrations/202211031314091
-rw-r--r--db/schema_migrations/202211031502501
-rw-r--r--db/schema_migrations/202211040421371
-rw-r--r--db/schema_migrations/202211040421591
-rw-r--r--db/schema_migrations/202211040613201
-rw-r--r--db/schema_migrations/202211040746521
-rw-r--r--db/schema_migrations/202211040940421
-rw-r--r--db/schema_migrations/202211041002031
-rw-r--r--db/schema_migrations/202211041705001
-rw-r--r--db/schema_migrations/202211041902031
-rw-r--r--db/schema_migrations/202211070943591
-rw-r--r--db/schema_migrations/202211071152471
-rw-r--r--db/schema_migrations/202211071154131
-rw-r--r--db/schema_migrations/202211071832221
-rw-r--r--db/schema_migrations/202211071845421
-rw-r--r--db/schema_migrations/202211071847581
-rw-r--r--db/schema_migrations/202211072204201
-rw-r--r--db/schema_migrations/202211072205261
-rw-r--r--db/schema_migrations/202211072222131
-rw-r--r--db/schema_migrations/202211080158131
-rw-r--r--db/schema_migrations/202211080450191
-rw-r--r--db/schema_migrations/202211081213221
-rw-r--r--db/schema_migrations/202211081854421
-rw-r--r--db/schema_migrations/202211082220151
-rw-r--r--db/schema_migrations/202211100454061
-rw-r--r--db/schema_migrations/202211101058571
-rw-r--r--db/schema_migrations/202211101509421
-rw-r--r--db/schema_migrations/202211110703141
-rw-r--r--db/structure.sql403
-rw-r--r--doc/.markdownlint/require_helper.js14
-rw-r--r--doc/.markdownlint/rules/tabs_blank_lines.js26
-rw-r--r--doc/.markdownlint/rules/tabs_title_markup.js31
-rw-r--r--doc/.markdownlint/rules/tabs_title_text.js23
-rw-r--r--doc/.markdownlint/rules/tabs_wrapper_tags.js21
-rw-r--r--doc/.vale/gitlab/Admin.yml13
-rw-r--r--doc/.vale/gitlab/AlertBoxStyle.yml8
-rw-r--r--doc/.vale/gitlab/BadPlurals.yml6
-rw-r--r--doc/.vale/gitlab/BadgeCapitalization.yml4
-rw-r--r--doc/.vale/gitlab/British.yml4
-rw-r--r--doc/.vale/gitlab/CIConfigFile.yml4
-rw-r--r--doc/.vale/gitlab/CodeblockFences.yml4
-rw-r--r--doc/.vale/gitlab/CurlStringsQuoted.yml4
-rw-r--r--doc/.vale/gitlab/CurrentStatus.yml6
-rw-r--r--doc/.vale/gitlab/DefaultBranch.yml8
-rw-r--r--doc/.vale/gitlab/Dropdown.yml6
-rw-r--r--doc/.vale/gitlab/EOLWhitespace.yml4
-rw-r--r--doc/.vale/gitlab/ElementDescriptors.yml4
-rw-r--r--doc/.vale/gitlab/FirstPerson.yml6
-rw-r--r--doc/.vale/gitlab/FutureTense.yml6
-rw-r--r--doc/.vale/gitlab/HeadingContent.yml6
-rw-r--r--doc/.vale/gitlab/HeadingDepth.yml2
-rw-r--r--doc/.vale/gitlab/InclusionAbleism.yml6
-rw-r--r--doc/.vale/gitlab/InclusionCultural.yml6
-rw-r--r--doc/.vale/gitlab/InclusionGender.yml6
-rw-r--r--doc/.vale/gitlab/InternalLinkCase.yml6
-rw-r--r--doc/.vale/gitlab/InternalLinkExtension.yml6
-rw-r--r--doc/.vale/gitlab/InternalLinkFormat.yml10
-rw-r--r--doc/.vale/gitlab/LatinTerms.yml6
-rw-r--r--doc/.vale/gitlab/Markdown_emoji.yml4
-rw-r--r--doc/.vale/gitlab/MeaningfulLinkWords.yml6
-rw-r--r--doc/.vale/gitlab/MergeConflictMarkers.yml4
-rw-r--r--doc/.vale/gitlab/MultiLineLinks.yml6
-rw-r--r--doc/.vale/gitlab/NonStandardQuotes.yml6
-rw-r--r--doc/.vale/gitlab/OutdatedVersions.yml6
-rw-r--r--doc/.vale/gitlab/OxfordComma.yml4
-rw-r--r--doc/.vale/gitlab/Possessive.yml6
-rw-r--r--doc/.vale/gitlab/ReadingLevel.yml4
-rw-r--r--doc/.vale/gitlab/ReferenceLinks.yml6
-rw-r--r--doc/.vale/gitlab/RelativeLinks.yml8
-rw-r--r--doc/.vale/gitlab/RelativeLinksDoubleSlashes.yml6
-rw-r--r--doc/.vale/gitlab/Repetition.yml4
-rw-r--r--doc/.vale/gitlab/SentenceLength.yml4
-rw-r--r--doc/.vale/gitlab/SentenceSpacing.yml4
-rw-r--r--doc/.vale/gitlab/Simplicity.yml6
-rw-r--r--doc/.vale/gitlab/Spelling.yml4
-rw-r--r--doc/.vale/gitlab/SubstitutionSuggestions.yml33
-rw-r--r--doc/.vale/gitlab/SubstitutionWarning.yml36
-rw-r--r--doc/.vale/gitlab/Substitutions.yml4
-rw-r--r--doc/.vale/gitlab/ToDo.yml6
-rw-r--r--doc/.vale/gitlab/UnclearAntecedent.yml4
-rw-r--r--doc/.vale/gitlab/Units.yml15
-rw-r--r--doc/.vale/gitlab/Uppercase.yml6
-rw-r--r--doc/.vale/gitlab/VersionText.yml4
-rw-r--r--doc/.vale/gitlab/VersionTextSingleLine.yml4
-rw-r--r--doc/.vale/gitlab/Wordy.yml14
-rw-r--r--doc/.vale/gitlab/spelling-exceptions.txt3
-rw-r--r--doc/.vale/vale-json.tmpl65
-rw-r--r--doc/administration/audit_event_streaming.md5
-rw-r--r--doc/administration/audit_events.md41
-rw-r--r--doc/administration/auth/authentiq.md2
-rw-r--r--doc/administration/auth/jwt.md2
-rw-r--r--doc/administration/auth/ldap/google_secure_ldap.md2
-rw-r--r--doc/administration/auth/ldap/index.md6
-rw-r--r--doc/administration/auth/ldap/ldap-troubleshooting.md18
-rw-r--r--doc/administration/auth/ldap/ldap_synchronization.md10
-rw-r--r--doc/administration/auth/oidc.md4
-rw-r--r--doc/administration/auth/smartcard.md2
-rw-r--r--doc/administration/cicd.md2
-rw-r--r--doc/administration/compliance.md4
-rw-r--r--doc/administration/configure.md6
-rw-r--r--doc/administration/consul.md10
-rw-r--r--doc/administration/environment_variables.md2
-rw-r--r--doc/administration/feature_flags.md4
-rw-r--r--doc/administration/file_hooks.md6
-rw-r--r--doc/administration/geo/disaster_recovery/background_verification.md2
-rw-r--r--doc/administration/geo/disaster_recovery/index.md2
-rw-r--r--doc/administration/geo/disaster_recovery/planned_failover.md4
-rw-r--r--doc/administration/geo/index.md10
-rw-r--r--doc/administration/geo/replication/configuration.md7
-rw-r--r--doc/administration/geo/replication/datatypes.md3
-rw-r--r--doc/administration/geo/replication/disable_geo.md4
-rw-r--r--doc/administration/geo/replication/docker_registry.md11
-rw-r--r--doc/administration/geo/replication/faq.md10
-rw-r--r--doc/administration/geo/replication/geo_validation_tests.md4
-rw-r--r--doc/administration/geo/replication/location_aware_git_url.md2
-rw-r--r--doc/administration/geo/replication/remove_geo_site.md5
-rw-r--r--doc/administration/geo/replication/security_review.md10
-rw-r--r--doc/administration/geo/replication/troubleshooting.md429
-rw-r--r--doc/administration/geo/secondary_proxy/location_aware_external_url.md37
-rw-r--r--doc/administration/geo/setup/database.md14
-rw-r--r--doc/administration/geo/setup/external_database.md4
-rw-r--r--doc/administration/git_protocol.md4
-rw-r--r--doc/administration/gitaly/configure_gitaly.md67
-rw-r--r--doc/administration/gitaly/index.md56
-rw-r--r--doc/administration/gitaly/monitoring.md3
-rw-r--r--doc/administration/gitaly/praefect.md40
-rw-r--r--doc/administration/gitaly/recovery.md62
-rw-r--r--doc/administration/gitaly/reference.md3
-rw-r--r--doc/administration/gitaly/troubleshooting.md30
-rw-r--r--doc/administration/housekeeping.md229
-rw-r--r--doc/administration/incoming_email.md2
-rw-r--r--doc/administration/index.md5
-rw-r--r--doc/administration/instance_limits.md20
-rw-r--r--doc/administration/integration/kroki.md2
-rw-r--r--doc/administration/integration/mailgun.md2
-rw-r--r--doc/administration/issue_closing_pattern.md2
-rw-r--r--doc/administration/job_artifacts.md127
-rw-r--r--doc/administration/lfs/index.md5
-rw-r--r--doc/administration/libravatar.md2
-rw-r--r--doc/administration/logs.md11
-rw-r--r--doc/administration/logs/index.md42
-rw-r--r--doc/administration/logs/tracing_correlation_id.md2
-rw-r--r--doc/administration/maintenance_mode/index.md6
-rw-r--r--doc/administration/monitoring/gitlab_self_monitoring_project/index.md30
-rw-r--r--doc/administration/monitoring/ip_allowlist.md3
-rw-r--r--doc/administration/monitoring/performance/grafana_configuration.md6
-rw-r--r--doc/administration/monitoring/performance/index.md2
-rw-r--r--doc/administration/monitoring/prometheus/gitlab_metrics.md19
-rw-r--r--doc/administration/nfs.md10
-rw-r--r--doc/administration/object_storage.md10
-rw-r--r--doc/administration/operations/moving_repositories.md11
-rw-r--r--doc/administration/operations/rails_console.md36
-rw-r--r--doc/administration/package_information/defaults.md4
-rw-r--r--doc/administration/package_information/omnibus_packages.md2
-rw-r--r--doc/administration/package_information/postgresql_versions.md1
-rw-r--r--doc/administration/package_information/signed_packages.md2
-rw-r--r--doc/administration/packages/container_registry.md7
-rw-r--r--doc/administration/packages/dependency_proxy.md9
-rw-r--r--doc/administration/packages/index.md5
-rw-r--r--doc/administration/pages/index.md12
-rw-r--r--doc/administration/pages/source.md2
-rw-r--r--doc/administration/polling.md4
-rw-r--r--doc/administration/postgresql/database_load_balancing.md1
-rw-r--r--doc/administration/postgresql/replication_and_failover.md4
-rw-r--r--doc/administration/raketasks/uploads/migrate.md5
-rw-r--r--doc/administration/redis/replication_and_failover.md4
-rw-r--r--doc/administration/redis/replication_and_failover_external.md2
-rw-r--r--doc/administration/redis/troubleshooting.md4
-rw-r--r--doc/administration/reference_architectures/10k_users.md178
-rw-r--r--doc/administration/reference_architectures/1k_users.md15
-rw-r--r--doc/administration/reference_architectures/25k_users.md165
-rw-r--r--doc/administration/reference_architectures/2k_users.md195
-rw-r--r--doc/administration/reference_architectures/3k_users.md160
-rw-r--r--doc/administration/reference_architectures/50k_users.md168
-rw-r--r--doc/administration/reference_architectures/5k_users.md169
-rw-r--r--doc/administration/reference_architectures/index.md17
-rw-r--r--doc/administration/reference_architectures/troubleshooting.md11
-rw-r--r--doc/administration/repository_storage_paths.md4
-rw-r--r--doc/administration/server_hooks.md14
-rw-r--r--doc/administration/sidekiq/sidekiq_memory_killer.md2
-rw-r--r--doc/administration/snippets/index.md2
-rw-r--r--doc/administration/system_hooks.md28
-rw-r--r--doc/administration/terraform_state.md5
-rw-r--r--doc/administration/troubleshooting/debug.md11
-rw-r--r--doc/administration/troubleshooting/defcon.md11
-rw-r--r--doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md663
-rw-r--r--doc/administration/troubleshooting/group_saml_scim.md11
-rw-r--r--doc/administration/troubleshooting/index.md8
-rw-r--r--doc/administration/troubleshooting/kubernetes_cheat_sheet.md11
-rw-r--r--doc/administration/troubleshooting/linux_cheat_sheet.md4
-rw-r--r--doc/administration/troubleshooting/log_parsing.md11
-rw-r--r--doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md11
-rw-r--r--doc/administration/troubleshooting/postgresql.md146
-rw-r--r--doc/administration/troubleshooting/ssl.md266
-rw-r--r--doc/administration/troubleshooting/test_environments.md4
-rw-r--r--doc/administration/user_settings.md2
-rw-r--r--doc/api/award_emoji.md10
-rw-r--r--doc/api/broadcast_messages.md13
-rw-r--r--doc/api/commits.md72
-rw-r--r--doc/api/container_registry.md2
-rw-r--r--doc/api/dependency_proxy.md2
-rw-r--r--doc/api/deploy_tokens.md2
-rw-r--r--doc/api/deployments.md13
-rw-r--r--doc/api/environments.md4
-rw-r--r--doc/api/error_tracking.md2
-rw-r--r--doc/api/events.md2
-rw-r--r--doc/api/feature_flag_specs.md6
-rw-r--r--doc/api/feature_flag_user_lists.md8
-rw-r--r--doc/api/feature_flags.md8
-rw-r--r--doc/api/features.md25
-rw-r--r--doc/api/freeze_periods.md34
-rw-r--r--doc/api/geo_nodes.md39
-rw-r--r--doc/api/graphql/custom_emoji.md43
-rw-r--r--doc/api/graphql/getting_started.md22
-rw-r--r--doc/api/graphql/index.md28
-rw-r--r--doc/api/graphql/reference/index.md880
-rw-r--r--doc/api/group_iterations.md2
-rw-r--r--doc/api/group_level_variables.md7
-rw-r--r--doc/api/group_protected_environments.md6
-rw-r--r--doc/api/groups.md4
-rw-r--r--doc/api/index.md2
-rw-r--r--doc/api/instance_level_ci_variables.md17
-rw-r--r--doc/api/integrations.md2
-rw-r--r--doc/api/issues.md4
-rw-r--r--doc/api/iterations.md2
-rw-r--r--doc/api/job_artifacts.md4
-rw-r--r--doc/api/lint.md2
-rw-r--r--doc/api/members.md3
-rw-r--r--doc/api/merge_request_approvals.md17
-rw-r--r--doc/api/merge_requests.md136
-rw-r--r--doc/api/merge_trains.md70
-rw-r--r--doc/api/metadata.md4
-rw-r--r--doc/api/milestones.md8
-rw-r--r--doc/api/oauth2.md2
-rw-r--r--doc/api/openapi/openapi.yaml642
-rw-r--r--doc/api/openapi/openapi_v2.yaml343
-rw-r--r--doc/api/openapi/v4/access_requests.yaml381
-rw-r--r--doc/api/openapi/v4/access_tokens.yaml170
-rw-r--r--doc/api/openapi/v4/metadata.yaml43
-rw-r--r--doc/api/openapi/v4/version.yaml28
-rw-r--r--doc/api/packages.md2
-rw-r--r--doc/api/packages/composer.md2
-rw-r--r--doc/api/packages/conan.md14
-rw-r--r--doc/api/packages/debian.md4
-rw-r--r--doc/api/packages/debian_group_distributions.md2
-rw-r--r--doc/api/packages/debian_project_distributions.md2
-rw-r--r--doc/api/packages/go_proxy.md2
-rw-r--r--doc/api/packages/helm.md2
-rw-r--r--doc/api/packages/maven.md2
-rw-r--r--doc/api/packages/npm.md6
-rw-r--r--doc/api/packages/nuget.md10
-rw-r--r--doc/api/packages/pypi.md8
-rw-r--r--doc/api/packages/rubygems.md2
-rw-r--r--doc/api/packages/terraform-modules.md2
-rw-r--r--doc/api/pipeline_triggers.md2
-rw-r--r--doc/api/pipelines.md61
-rw-r--r--doc/api/product_analytics.md2
-rw-r--r--doc/api/project_level_variables.md7
-rw-r--r--doc/api/projects.md46
-rw-r--r--doc/api/protected_branches.md124
-rw-r--r--doc/api/protected_environments.md4
-rw-r--r--doc/api/protected_tags.md3
-rw-r--r--doc/api/releases/index.md65
-rw-r--r--doc/api/releases/links.md20
-rw-r--r--doc/api/remote_mirrors.md31
-rw-r--r--doc/api/repositories.md2
-rw-r--r--doc/api/repository_files.md104
-rw-r--r--doc/api/runners.md101
-rw-r--r--doc/api/scim.md10
-rw-r--r--doc/api/secure_files.md34
-rw-r--r--doc/api/settings.md6
-rw-r--r--doc/api/status_checks.md10
-rw-r--r--doc/api/suggestions.md54
-rw-r--r--doc/api/templates/dockerfiles.md2
-rw-r--r--doc/api/templates/gitignores.md2
-rw-r--r--doc/api/templates/gitlab_ci_ymls.md2
-rw-r--r--doc/api/templates/licenses.md2
-rw-r--r--doc/api/users.md40
-rw-r--r--doc/api/vulnerability_exports.md21
-rw-r--r--doc/architecture/blueprints/_template.md7
-rw-r--r--doc/architecture/blueprints/ci_data_decay/index.md60
-rw-r--r--doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md48
-rw-r--r--doc/architecture/blueprints/ci_pipeline_components/index.md58
-rw-r--r--doc/architecture/blueprints/cloud_native_build_logs/index.md38
-rw-r--r--doc/architecture/blueprints/cloud_native_gitlab_pages/index.md47
-rw-r--r--doc/architecture/blueprints/composable_codebase_using_rails_engines/index.md46
-rw-r--r--doc/architecture/blueprints/consolidating_groups_and_projects/index.md40
-rw-r--r--doc/architecture/blueprints/container_registry_metadata_database/index.md33
-rw-r--r--doc/architecture/blueprints/database/scalability/patterns/read_mostly.md2
-rw-r--r--doc/architecture/blueprints/database/scalability/patterns/time_decay.md2
-rw-r--r--doc/architecture/blueprints/database_scaling/size-limits.md2
-rw-r--r--doc/architecture/blueprints/database_testing/index.md35
-rw-r--r--doc/architecture/blueprints/feature_flags_development/index.md35
-rw-r--r--doc/architecture/blueprints/gitlab_to_kubernetes_communication/index.md37
-rw-r--r--doc/architecture/blueprints/graphql_api/index.md51
-rw-r--r--doc/architecture/blueprints/image_resizing/index.md12
-rw-r--r--doc/architecture/blueprints/object_storage/index.md32
-rw-r--r--doc/architecture/blueprints/pods/images/iteration0-organizations-introduction.pngbin0 -> 67160 bytes
-rw-r--r--doc/architecture/blueprints/pods/images/pods-and-fulfillment.pngbin0 -> 75803 bytes
-rw-r--r--doc/architecture/blueprints/pods/images/term-cluster.pngbin0 -> 63268 bytes
-rw-r--r--doc/architecture/blueprints/pods/images/term-organization.pngbin0 -> 7150 bytes
-rw-r--r--doc/architecture/blueprints/pods/images/term-pod.png (renamed from doc/architecture/blueprints/pods/term-pod.png)bin16104 -> 16104 bytes
-rw-r--r--doc/architecture/blueprints/pods/images/term-top-level-namespace.png (renamed from doc/architecture/blueprints/pods/term-top-level-namespace.png)bin11451 -> 11451 bytes
-rw-r--r--doc/architecture/blueprints/pods/index.md122
-rw-r--r--doc/architecture/blueprints/pods/iteration0-organizations-introduction.pngbin326285 -> 0 bytes
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-data-migration.md82
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-database-sequences.md94
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-git-access.md163
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-graphql.md94
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-organizations.md58
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-router-endpoints-classification.md46
-rw-r--r--doc/architecture/blueprints/pods/pods-feature-template.md29
-rw-r--r--doc/architecture/blueprints/pods/proposal-stateless-router-with-buffering-requests.md648
-rw-r--r--doc/architecture/blueprints/pods/proposal-stateless-router-with-routes-learning.md672
-rw-r--r--doc/architecture/blueprints/pods/term-cluster.pngbin271291 -> 0 bytes
-rw-r--r--doc/architecture/blueprints/pods/term-organization.pngbin22575 -> 0 bytes
-rw-r--r--doc/architecture/blueprints/rate_limiting/index.md84
-rw-r--r--doc/architecture/blueprints/runner_scaling/index.md47
-rw-r--r--doc/architecture/blueprints/runner_tokens/index.md227
-rw-r--r--doc/architecture/blueprints/work_items/index.md66
-rw-r--r--doc/architecture/index.md6
-rw-r--r--doc/ci/chatops/index.md2
-rw-r--r--doc/ci/ci_cd_for_external_repos/bitbucket_integration.md27
-rw-r--r--doc/ci/ci_cd_for_external_repos/github_integration.md2
-rw-r--r--doc/ci/cloud_deployment/index.md2
-rw-r--r--doc/ci/cloud_services/azure/index.md20
-rw-r--r--doc/ci/directed_acyclic_graph/index.md2
-rw-r--r--doc/ci/docker/using_docker_build.md4
-rw-r--r--doc/ci/docker/using_docker_images.md2
-rw-r--r--doc/ci/enable_or_disable_ci.md2
-rw-r--r--doc/ci/environments/deployment_approvals.md19
-rw-r--r--doc/ci/environments/deployment_safety.md64
-rw-r--r--doc/ci/environments/environments_dashboard.md2
-rw-r--r--doc/ci/environments/incremental_rollouts.md2
-rw-r--r--doc/ci/environments/index.md15
-rw-r--r--doc/ci/environments/protected_environments.md4
-rw-r--r--doc/ci/examples/authenticating-with-hashicorp-vault/index.md32
-rw-r--r--doc/ci/examples/deployment/composer-npm-deploy.md2
-rw-r--r--doc/ci/examples/end_to_end_testing_webdriverio/index.md2
-rw-r--r--doc/ci/examples/laravel_with_gitlab_and_envoy/index.md8
-rw-r--r--doc/ci/examples/semantic-release.md2
-rw-r--r--doc/ci/git_submodules.md15
-rw-r--r--doc/ci/interactive_web_terminal/index.md2
-rw-r--r--doc/ci/jobs/ci_job_token.md4
-rw-r--r--doc/ci/jobs/index.md4
-rw-r--r--doc/ci/jobs/job_control.md31
-rw-r--r--doc/ci/migration/circleci.md2
-rw-r--r--doc/ci/migration/jenkins.md8
-rw-r--r--doc/ci/pipelines/cicd_minutes.md12
-rw-r--r--doc/ci/pipelines/downstream_pipelines.md370
-rw-r--r--doc/ci/pipelines/img/merge_train_cancel_v12_0.pngbin7654 -> 0 bytes
-rw-r--r--doc/ci/pipelines/img/merge_train_failure.pngbin23899 -> 0 bytes
-rw-r--r--doc/ci/pipelines/img/merge_train_immediate_merge_v12_6.pngbin18607 -> 0 bytes
-rw-r--r--doc/ci/pipelines/img/merge_train_position_v12_0.pngbin6152 -> 0 bytes
-rw-r--r--doc/ci/pipelines/img/merge_train_start_v12_0.pngbin3548 -> 0 bytes
-rw-r--r--doc/ci/pipelines/img/merge_train_start_when_pipeline_succeeds_v12_0.pngbin4337 -> 0 bytes
-rw-r--r--doc/ci/pipelines/index.md9
-rw-r--r--doc/ci/pipelines/job_artifacts.md70
-rw-r--r--doc/ci/pipelines/merge_trains.md306
-rw-r--r--doc/ci/pipelines/pipeline_architectures.md7
-rw-r--r--doc/ci/pipelines/pipeline_efficiency.md2
-rw-r--r--doc/ci/pipelines/schedules.md2
-rw-r--r--doc/ci/pipelines/settings.md86
-rw-r--r--doc/ci/quick_start/index.md147
-rw-r--r--doc/ci/resource_groups/index.md3
-rw-r--r--doc/ci/review_apps/index.md70
-rw-r--r--doc/ci/runners/configure_runners.md57
-rw-r--r--doc/ci/runners/index.md2
-rw-r--r--doc/ci/runners/runners_scope.md19
-rw-r--r--doc/ci/runners/saas/linux_saas_runner.md2
-rw-r--r--doc/ci/runners/saas/macos_saas_runner.md2
-rw-r--r--doc/ci/secrets/index.md12
-rw-r--r--doc/ci/services/index.md42
-rw-r--r--doc/ci/testing/code_quality.md14
-rw-r--r--doc/ci/testing/load_performance_testing.md2
-rw-r--r--doc/ci/testing/test_coverage_visualization.md2
-rw-r--r--doc/ci/testing/unit_test_report_examples.md3
-rw-r--r--doc/ci/triggers/index.md8
-rw-r--r--doc/ci/troubleshooting.md83
-rw-r--r--doc/ci/variables/index.md111
-rw-r--r--doc/ci/variables/predefined_variables.md2
-rw-r--r--doc/ci/variables/where_variables_can_be_used.md4
-rw-r--r--doc/ci/yaml/artifacts_reports.md2
-rw-r--r--doc/ci/yaml/index.md149
-rw-r--r--doc/cloud_seed/index.md3
-rw-r--r--doc/development/api_graphql_styleguide.md65
-rw-r--r--doc/development/application_limits.md2
-rw-r--r--doc/development/audit_event_guide/index.md12
-rw-r--r--doc/development/backend/ruby_style_guide.md87
-rw-r--r--doc/development/cached_queries.md2
-rw-r--r--doc/development/cascading_settings.md2
-rw-r--r--doc/development/changelog.md4
-rw-r--r--doc/development/chatops_on_gitlabcom.md4
-rw-r--r--doc/development/cicd/index.md2
-rw-r--r--doc/development/cicd/templates.md2
-rw-r--r--doc/development/code_review.md24
-rw-r--r--doc/development/contributing/design.md4
-rw-r--r--doc/development/contributing/index.md2
-rw-r--r--doc/development/contributing/merge_request_workflow.md4
-rw-r--r--doc/development/contributing/style_guides.md115
-rw-r--r--doc/development/database/adding_database_indexes.md36
-rw-r--r--doc/development/database/background_migrations.md4
-rw-r--r--doc/development/database/batched_background_migrations.md13
-rw-r--r--doc/development/database/database_debugging.md8
-rw-r--r--doc/development/database/database_migration_pipeline.md52
-rw-r--r--doc/development/database/loose_foreign_keys.md8
-rw-r--r--doc/development/database/not_null_constraints.md10
-rw-r--r--doc/development/database/query_recorder.md9
-rw-r--r--doc/development/database/single_table_inheritance.md2
-rw-r--r--doc/development/database/table_partitioning.md19
-rw-r--r--doc/development/database_review.md13
-rw-r--r--doc/development/deprecation_guidelines/index.md6
-rw-r--r--doc/development/development_processes.md2
-rw-r--r--doc/development/distributed_tracing.md2
-rw-r--r--doc/development/documentation/drawers.md59
-rw-r--r--doc/development/documentation/feature_flags.md7
-rw-r--r--doc/development/documentation/index.md67
-rw-r--r--doc/development/documentation/restful_api_styleguide.md4
-rw-r--r--doc/development/documentation/review_apps.md55
-rw-r--r--doc/development/documentation/site_architecture/deployment_process.md16
-rw-r--r--doc/development/documentation/site_architecture/global_nav.md2
-rw-r--r--doc/development/documentation/styleguide/index.md113
-rw-r--r--doc/development/documentation/styleguide/word_list.md122
-rw-r--r--doc/development/documentation/testing.md4
-rw-r--r--doc/development/documentation/topic_types/concept.md6
-rw-r--r--doc/development/documentation/topic_types/index.md69
-rw-r--r--doc/development/documentation/topic_types/reference.md6
-rw-r--r--doc/development/documentation/topic_types/task.md13
-rw-r--r--doc/development/documentation/topic_types/troubleshooting.md19
-rw-r--r--doc/development/documentation/topic_types/tutorial.md102
-rw-r--r--doc/development/documentation/versions.md2
-rw-r--r--doc/development/documentation/workflow.md2
-rw-r--r--doc/development/ee_features.md38
-rw-r--r--doc/development/event_store.md6
-rw-r--r--doc/development/fe_guide/graphql.md6
-rw-r--r--doc/development/fe_guide/merge_request_widget_extensions.md2
-rw-r--r--doc/development/fe_guide/registry_architecture.md2
-rw-r--r--doc/development/fe_guide/style/scss.md2
-rw-r--r--doc/development/fe_guide/view_component.md10
-rw-r--r--doc/development/fe_guide/vue.md3
-rw-r--r--doc/development/fe_guide/vue3_migration.md229
-rw-r--r--doc/development/fe_guide/vuex.md2
-rw-r--r--doc/development/feature_development.md1
-rw-r--r--doc/development/feature_flags/controls.md6
-rw-r--r--doc/development/feature_flags/index.md2
-rw-r--r--doc/development/fips_compliance.md4
-rw-r--r--doc/development/gemfile.md2
-rw-r--r--doc/development/github_importer.md23
-rw-r--r--doc/development/gitlab_flavored_markdown/specification_guide/index.md267
-rw-r--r--doc/development/go_guide/index.md2
-rw-r--r--doc/development/graphql_guide/pagination.md4
-rw-r--r--doc/development/i18n/externalization.md30
-rw-r--r--doc/development/i18n/merging_translations.md2
-rw-r--r--doc/development/i18n/proofreader.md1
-rw-r--r--doc/development/import_export.md108
-rw-r--r--doc/development/integrations/index.md4
-rw-r--r--doc/development/integrations/jira_connect.md2
-rw-r--r--doc/development/integrations/secure.md4
-rw-r--r--doc/development/integrations/secure_partner_integration.md2
-rw-r--r--doc/development/internal_api/index.md4
-rw-r--r--doc/development/kubernetes.md8
-rw-r--r--doc/development/licensed_feature_availability.md11
-rw-r--r--doc/development/merge_request_concepts/widget_extensions.md11
-rw-r--r--doc/development/migration_style_guide.md34
-rw-r--r--doc/development/multi_version_compatibility.md2
-rw-r--r--doc/development/packages/cleanup_policies.md122
-rw-r--r--doc/development/packages/debian_repository.md2
-rw-r--r--doc/development/packages/dependency_proxy.md4
-rw-r--r--doc/development/packages/index.md20
-rw-r--r--doc/development/packages/new_format_development.md2
-rw-r--r--doc/development/packages/settings.md2
-rw-r--r--doc/development/packages/structure.md2
-rw-r--r--doc/development/performance.md4
-rw-r--r--doc/development/pipelines.md874
-rw-r--r--doc/development/pipelines/index.md631
-rw-r--r--doc/development/pipelines/internals.md216
-rw-r--r--doc/development/pipelines/performance.md151
-rw-r--r--doc/development/prometheus_metrics.md2
-rw-r--r--doc/development/rake_tasks.md14
-rw-r--r--doc/development/reusing_abstractions.md3
-rw-r--r--doc/development/routing.md2
-rw-r--r--doc/development/rubocop_development_guide.md114
-rw-r--r--doc/development/sec/analyzer_development_guide.md20
-rw-r--r--doc/development/sec/img/primary_identifier_changed_v15_6.pngbin0 -> 12665 bytes
-rw-r--r--doc/development/sec/index.md90
-rw-r--r--doc/development/sec/security_report_ingestion_overview.md74
-rw-r--r--doc/development/secure_coding_guidelines.md8
-rw-r--r--doc/development/service_ping/implement.md132
-rw-r--r--doc/development/service_ping/index.md4
-rw-r--r--doc/development/service_ping/metrics_instrumentation.md15
-rw-r--r--doc/development/service_ping/metrics_lifecycle.md7
-rw-r--r--doc/development/service_ping/review_guidelines.md1
-rw-r--r--doc/development/service_ping/troubleshooting.md42
-rw-r--r--doc/development/service_ping/usage_data.md1
-rw-r--r--doc/development/shell_commands.md2
-rw-r--r--doc/development/sidekiq/index.md25
-rw-r--r--doc/development/sidekiq/worker_attributes.md2
-rw-r--r--doc/development/snowplow/event_dictionary_guide.md36
-rw-r--r--doc/development/snowplow/implementation.md24
-rw-r--r--doc/development/snowplow/index.md17
-rw-r--r--doc/development/snowplow/review_guidelines.md2
-rw-r--r--doc/development/snowplow/schemas.md19
-rw-r--r--doc/development/spam_protection_and_captcha/exploratory_testing.md2
-rw-r--r--doc/development/sql.md4
-rw-r--r--doc/development/stage_group_observability/dashboards/index.md4
-rw-r--r--doc/development/stage_group_observability/dashboards/stage_group_dashboard.md2
-rw-r--r--doc/development/testing_guide/best_practices.md27
-rw-r--r--doc/development/testing_guide/contract/consumer_tests.md2
-rw-r--r--doc/development/testing_guide/end_to_end/best_practices.md4
-rw-r--r--doc/development/testing_guide/end_to_end/feature_flags.md2
-rw-r--r--doc/development/testing_guide/end_to_end/index.md23
-rw-r--r--doc/development/testing_guide/end_to_end/rspec_metadata_tests.md2
-rw-r--r--doc/development/testing_guide/end_to_end/style_guide.md8
-rw-r--r--doc/development/testing_guide/flaky_tests.md139
-rw-r--r--doc/development/testing_guide/frontend_testing.md332
-rw-r--r--doc/development/testing_guide/index.md7
-rw-r--r--doc/development/testing_guide/review_apps.md70
-rw-r--r--doc/development/utilities.md18
-rw-r--r--doc/development/windows.md2
-rw-r--r--doc/development/work_items.md31
-rw-r--r--doc/development/workhorse/index.md2
-rw-r--r--doc/drawers/advanced_search_syntax.md45
-rw-r--r--doc/gitlab-basics/add-file.md2
-rw-r--r--doc/gitlab-basics/command-line-commands.md2
-rw-r--r--doc/gitlab-basics/start-using-git.md2
-rw-r--r--doc/install/aws/gitlab_hybrid_on_aws.md2
-rw-r--r--doc/install/aws/manual_install_aws.md4
-rw-r--r--doc/install/docker.md6
-rw-r--r--doc/install/google_cloud_platform/index.md2
-rw-r--r--doc/install/installation.md26
-rw-r--r--doc/install/migrate/compare_sm_to_saas.md4
-rw-r--r--doc/install/relative_url.md2
-rw-r--r--doc/install/requirements.md6
-rw-r--r--doc/integration/advanced_search/elasticsearch.md2
-rw-r--r--doc/integration/advanced_search/elasticsearch_troubleshooting.md4
-rw-r--r--doc/integration/bitbucket.md2
-rw-r--r--doc/integration/gitlab.md9
-rw-r--r--doc/integration/gitpod.md2
-rw-r--r--doc/integration/index.md108
-rw-r--r--doc/integration/jenkins_deprecated.md13
-rw-r--r--doc/integration/jira/configure.md2
-rw-r--r--doc/integration/jira/index.md99
-rw-r--r--doc/integration/jira/jira_server_configuration.md2
-rw-r--r--doc/integration/jira/troubleshooting.md110
-rw-r--r--doc/integration/oauth_provider.md16
-rw-r--r--doc/integration/omniauth.md66
-rw-r--r--doc/integration/saml.md18
-rw-r--r--doc/integration/slash_commands.md2
-rw-r--r--doc/integration/vault.md10
-rw-r--r--doc/legal/corporate_contributor_license_agreement.md9
-rw-r--r--doc/legal/developer_certificate_of_origin.md1
-rw-r--r--doc/legal/individual_contributor_license_agreement.md9
-rw-r--r--doc/operations/error_tracking.md19
-rw-r--r--doc/operations/feature_flags.md2
-rw-r--r--doc/operations/incident_management/alerts.md89
-rw-r--r--doc/operations/incident_management/img/timeline_event_for_severity_change_v15_6.pngbin0 -> 10377 bytes
-rw-r--r--doc/operations/incident_management/incident_timeline_events.md11
-rw-r--r--doc/operations/incident_management/incidents.md2
-rw-r--r--doc/operations/incident_management/integrations.md4
-rw-r--r--doc/operations/incident_management/linked_resources.md8
-rw-r--r--doc/operations/incident_management/paging.md4
-rw-r--r--doc/operations/index.md30
-rw-r--r--doc/operations/metrics/dashboards/index.md4
-rw-r--r--doc/operations/metrics/dashboards/templating_variables.md10
-rw-r--r--doc/operations/metrics/index.md4
-rw-r--r--doc/operations/product_analytics.md45
-rw-r--r--doc/operations/tracing.md51
-rw-r--r--doc/raketasks/backup_gitlab.md2
-rw-r--r--doc/raketasks/cleanup.md6
-rw-r--r--doc/raketasks/index.md2
-rw-r--r--doc/security/crime_vulnerability.md2
-rw-r--r--doc/security/index.md2
-rw-r--r--doc/security/information_exclusivity.md2
-rw-r--r--doc/security/password_length_limits.md46
-rw-r--r--doc/security/password_storage.md25
-rw-r--r--doc/security/passwords_for_integrated_authentication_methods.md2
-rw-r--r--doc/security/ssh_keys_restrictions.md2
-rw-r--r--doc/security/two_factor_authentication.md8
-rw-r--r--doc/security/unlock_user.md4
-rw-r--r--doc/security/user_email_confirmation.md2
-rw-r--r--doc/security/user_file_uploads.md2
-rw-r--r--doc/security/webhooks.md2
-rw-r--r--doc/subscriptions/gitlab_com/index.md39
-rw-r--r--doc/subscriptions/gitlab_dedicated/index.md2
-rw-r--r--doc/subscriptions/index.md18
-rw-r--r--doc/subscriptions/self_managed/index.md39
-rw-r--r--doc/topics/autodevops/cloud_deployments/auto_devops_with_gke.md11
-rw-r--r--doc/topics/autodevops/customize.md3
-rw-r--r--doc/topics/autodevops/multiple_clusters_auto_devops.md2
-rw-r--r--doc/topics/autodevops/stages.md2
-rw-r--r--doc/topics/awesome_co.md2
-rw-r--r--doc/topics/git/how_to_install_git/index.md2
-rw-r--r--doc/topics/git/lfs/index.md18
-rw-r--r--doc/topics/git/lfs/migrate_to_git_lfs.md4
-rw-r--r--doc/topics/git/merge_conflicts.md72
-rw-r--r--doc/topics/git/numerous_undo_possibilities_in_git/index.md2
-rw-r--r--doc/topics/git/useful_git_commands.md2
-rw-r--r--doc/topics/release_your_application.md2
-rw-r--r--doc/tutorials/agile_sprint.md101
-rw-r--r--doc/tutorials/index.md7
-rw-r--r--doc/tutorials/make_your_first_git_commit.md18
-rw-r--r--doc/tutorials/move_personal_project_to_a_group.md2
-rw-r--r--doc/update/deprecations.md148
-rw-r--r--doc/update/index.md32
-rw-r--r--doc/update/patch_versions.md5
-rw-r--r--doc/update/removals.md24
-rw-r--r--doc/update/upgrading_from_ce_to_ee.md3
-rw-r--r--doc/update/upgrading_from_source.md11
-rw-r--r--doc/update/zero_downtime.md2
-rw-r--r--doc/user/admin_area/appearance.md2
-rw-r--r--doc/user/admin_area/broadcast_messages.md2
-rw-r--r--doc/user/admin_area/custom_project_templates.md2
-rw-r--r--doc/user/admin_area/diff_limits.md2
-rw-r--r--doc/user/admin_area/email_from_gitlab.md2
-rw-r--r--doc/user/admin_area/geo_nodes.md11
-rw-r--r--doc/user/admin_area/geo_sites.md2
-rw-r--r--doc/user/admin_area/img/minimum_password_length_settings_v12_6.pngbin10385 -> 0 bytes
-rw-r--r--doc/user/admin_area/index.md8
-rw-r--r--doc/user/admin_area/labels.md2
-rw-r--r--doc/user/admin_area/license.md17
-rw-r--r--doc/user/admin_area/license_file.md80
-rw-r--r--doc/user/admin_area/moderate_users.md81
-rw-r--r--doc/user/admin_area/monitoring/health_check.md2
-rw-r--r--doc/user/admin_area/reporting/git_abuse_rate_limit.md27
-rw-r--r--doc/user/admin_area/review_abuse_reports.md2
-rw-r--r--doc/user/admin_area/settings/account_and_limit_settings.md18
-rw-r--r--doc/user/admin_area/settings/continuous_integration.md16
-rw-r--r--doc/user/admin_area/settings/deprecated_api_rate_limits.md4
-rw-r--r--doc/user/admin_area/settings/email.md2
-rw-r--r--doc/user/admin_area/settings/external_authorization.md2
-rw-r--r--doc/user/admin_area/settings/files_api_rate_limits.md4
-rw-r--r--doc/user/admin_area/settings/floc.md2
-rw-r--r--doc/user/admin_area/settings/help_page.md4
-rw-r--r--doc/user/admin_area/settings/index.md4
-rw-r--r--doc/user/admin_area/settings/instance_template_repository.md8
-rw-r--r--doc/user/admin_area/settings/package_registry_rate_limits.md2
-rw-r--r--doc/user/admin_area/settings/sign_in_restrictions.md75
-rw-r--r--doc/user/admin_area/settings/sign_up_restrictions.md4
-rw-r--r--doc/user/admin_area/settings/terms.md2
-rw-r--r--doc/user/admin_area/settings/third_party_offers.md2
-rw-r--r--doc/user/admin_area/settings/usage_statistics.md4
-rw-r--r--doc/user/admin_area/settings/user_and_ip_rate_limits.md2
-rw-r--r--doc/user/admin_area/settings/visibility_and_access_controls.md28
-rw-r--r--doc/user/analytics/ci_cd_analytics.md18
-rw-r--r--doc/user/analytics/dora_metrics.md127
-rw-r--r--doc/user/analytics/index.md89
-rw-r--r--doc/user/application_security/api_fuzzing/create_har_files.md4
-rw-r--r--doc/user/application_security/api_fuzzing/index.md261
-rw-r--r--doc/user/application_security/configuration/index.md2
-rw-r--r--doc/user/application_security/container_scanning/index.md44
-rw-r--r--doc/user/application_security/dast/browser_based.md6
-rw-r--r--doc/user/application_security/dast/dast_troubleshooting.md2
-rw-r--r--doc/user/application_security/dast/index.md1438
-rw-r--r--doc/user/application_security/dast/proxy-based.md1247
-rw-r--r--doc/user/application_security/dast_api/index.md246
-rw-r--r--doc/user/application_security/dependency_scanning/index.md21
-rw-r--r--doc/user/application_security/get-started-security.md2
-rw-r--r--doc/user/application_security/iac_scanning/index.md158
-rw-r--r--doc/user/application_security/img/secure_tools_and_cicd_stages.pngbin42240 -> 11849 bytes
-rw-r--r--doc/user/application_security/index.md12
-rw-r--r--doc/user/application_security/policies/index.md2
-rw-r--r--doc/user/application_security/policies/scan-execution-policies.md12
-rw-r--r--doc/user/application_security/policies/scan-result-policies.md8
-rw-r--r--doc/user/application_security/sast/analyzers.md10
-rw-r--r--doc/user/application_security/sast/index.md214
-rw-r--r--doc/user/application_security/secret_detection/index.md99
-rw-r--r--doc/user/application_security/security_dashboard/index.md2
-rw-r--r--doc/user/application_security/terminology/index.md2
-rw-r--r--doc/user/application_security/vulnerabilities/severities.md4
-rw-r--r--doc/user/application_security/vulnerability_report/index.md4
-rw-r--r--doc/user/award_emojis.md26
-rw-r--r--doc/user/clusters/agent/ci_cd_workflow.md55
-rw-r--r--doc/user/clusters/agent/gitops/helm.md40
-rw-r--r--doc/user/clusters/agent/index.md7
-rw-r--r--doc/user/clusters/agent/install/index.md4
-rw-r--r--doc/user/clusters/agent/troubleshooting.md21
-rw-r--r--doc/user/clusters/management_project.md2
-rw-r--r--doc/user/clusters/management_project_template.md1
-rw-r--r--doc/user/compliance/compliance_report/index.md8
-rw-r--r--doc/user/crm/index.md24
-rw-r--r--doc/user/discussions/index.md30
-rw-r--r--doc/user/feature_highlight.md11
-rw-r--r--doc/user/free_user_limit.md28
-rw-r--r--doc/user/group/access_and_permissions.md20
-rw-r--r--doc/user/group/clusters/index.md2
-rw-r--r--doc/user/group/compliance_frameworks.md262
-rw-r--r--doc/user/group/contribution_analytics/index.md10
-rw-r--r--doc/user/group/custom_project_templates.md2
-rw-r--r--doc/user/group/epics/epic_boards.md6
-rw-r--r--doc/user/group/epics/index.md10
-rw-r--r--doc/user/group/epics/manage_epics.md56
-rw-r--r--doc/user/group/import/index.md10
-rw-r--r--doc/user/group/insights/index.md2
-rw-r--r--doc/user/group/issues_analytics/index.md2
-rw-r--r--doc/user/group/iterations/index.md6
-rw-r--r--doc/user/group/manage.md253
-rw-r--r--doc/user/group/planning_hierarchy/index.md4
-rw-r--r--doc/user/group/reporting/git_abuse_rate_limit.md36
-rw-r--r--doc/user/group/repositories_analytics/index.md4
-rw-r--r--doc/user/group/roadmap/img/roadmap_blocked_icon_v15_5.pngbin25453 -> 8248 bytes
-rw-r--r--doc/user/group/roadmap/index.md2
-rw-r--r--doc/user/group/saml_sso/group_sync.md8
-rw-r--r--doc/user/group/saml_sso/img/member_enterprise_badge_v14_0.pngbin31502 -> 0 bytes
-rw-r--r--doc/user/group/saml_sso/index.md28
-rw-r--r--doc/user/group/saml_sso/scim_setup.md50
-rw-r--r--doc/user/group/saml_sso/troubleshooting.md38
-rw-r--r--doc/user/group/saml_sso/troubleshooting_scim.md156
-rw-r--r--doc/user/group/subgroups/index.md2
-rw-r--r--doc/user/group/value_stream_analytics/index.md2
-rw-r--r--doc/user/infrastructure/clusters/connect/new_civo_cluster.md2
-rw-r--r--doc/user/infrastructure/clusters/connect/new_eks_cluster.md2
-rw-r--r--doc/user/infrastructure/clusters/connect/new_gke_cluster.md6
-rw-r--r--doc/user/infrastructure/clusters/manage/management_project_applications/ingress.md2
-rw-r--r--doc/user/infrastructure/clusters/manage/management_project_applications/vault.md12
-rw-r--r--doc/user/infrastructure/iac/index.md4
-rw-r--r--doc/user/infrastructure/iac/terraform_state.md2
-rw-r--r--doc/user/infrastructure/iac/troubleshooting.md10
-rw-r--r--doc/user/markdown.md18
-rw-r--r--doc/user/packages/composer_repository/index.md59
-rw-r--r--doc/user/packages/conan_repository/index.md114
-rw-r--r--doc/user/packages/container_registry/index.md12
-rw-r--r--doc/user/packages/container_registry/reduce_container_registry_data_transfer.md4
-rw-r--r--doc/user/packages/container_registry/reduce_container_registry_storage.md2
-rw-r--r--doc/user/packages/debian_repository/index.md2
-rw-r--r--doc/user/packages/dependency_proxy/index.md4
-rw-r--r--doc/user/packages/dependency_proxy/reduce_dependency_proxy_storage.md2
-rw-r--r--doc/user/packages/generic_packages/index.md2
-rw-r--r--doc/user/packages/go_proxy/index.md2
-rw-r--r--doc/user/packages/harbor_container_registry/index.md2
-rw-r--r--doc/user/packages/helm_repository/index.md4
-rw-r--r--doc/user/packages/index.md2
-rw-r--r--doc/user/packages/infrastructure_registry/index.md4
-rw-r--r--doc/user/packages/maven_repository/index.md206
-rw-r--r--doc/user/packages/npm_registry/index.md103
-rw-r--r--doc/user/packages/nuget_repository/index.md46
-rw-r--r--doc/user/packages/package_registry/index.md2
-rw-r--r--doc/user/packages/package_registry/reduce_package_registry_storage.md2
-rw-r--r--doc/user/packages/pypi_repository/index.md145
-rw-r--r--doc/user/packages/rubygems_registry/index.md2
-rw-r--r--doc/user/packages/terraform_module_registry/index.md12
-rw-r--r--doc/user/packages/workflows/build_packages.md504
-rw-r--r--doc/user/packages/workflows/project_registry.md2
-rw-r--r--doc/user/packages/workflows/working_with_monorepos.md2
-rw-r--r--doc/user/permissions.md43
-rw-r--r--doc/user/product_analytics/index.md48
-rw-r--r--doc/user/profile/account/create_accounts.md16
-rw-r--r--doc/user/profile/account/two_factor_authentication.md4
-rw-r--r--doc/user/profile/active_sessions.md2
-rw-r--r--doc/user/profile/contributions_calendar.md136
-rw-r--r--doc/user/profile/img/contributions_calendar_v15_6.pngbin0 -> 60252 bytes
-rw-r--r--doc/user/profile/index.md81
-rw-r--r--doc/user/profile/notifications.md49
-rw-r--r--doc/user/profile/personal_access_tokens.md36
-rw-r--r--doc/user/profile/preferences.md4
-rw-r--r--doc/user/profile/user_passwords.md3
-rw-r--r--doc/user/project/badges.md2
-rw-r--r--doc/user/project/clusters/add_existing_cluster.md2
-rw-r--r--doc/user/project/clusters/deploy_to_cluster.md2
-rw-r--r--doc/user/project/clusters/kubernetes_pod_logs.md12
-rw-r--r--doc/user/project/clusters/runbooks/index.md4
-rw-r--r--doc/user/project/import/clearcase.md2
-rw-r--r--doc/user/project/import/github.md143
-rw-r--r--doc/user/project/import/tfvc.md2
-rw-r--r--doc/user/project/integrations/gitlab_slack_application.md64
-rw-r--r--doc/user/project/integrations/hangouts_chat.md2
-rw-r--r--doc/user/project/integrations/mlflow_client.md81
-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/servicenow.md4
-rw-r--r--doc/user/project/integrations/slack.md16
-rw-r--r--doc/user/project/integrations/slack_slash_commands.md2
-rw-r--r--doc/user/project/integrations/unify_circuit.md2
-rw-r--r--doc/user/project/integrations/webex_teams.md2
-rw-r--r--doc/user/project/integrations/webhook_events.md19
-rw-r--r--doc/user/project/integrations/webhooks.md24
-rw-r--r--doc/user/project/issue_board.md8
-rw-r--r--doc/user/project/issues/confidential_issues.md6
-rw-r--r--doc/user/project/issues/design_management.md2
-rw-r--r--doc/user/project/issues/due_dates.md2
-rw-r--r--doc/user/project/issues/managing_issues.md46
-rw-r--r--doc/user/project/issues/related_issues.md2
-rw-r--r--doc/user/project/labels.md32
-rw-r--r--doc/user/project/members/index.md58
-rw-r--r--doc/user/project/merge_requests/approvals/index.md2
-rw-r--r--doc/user/project/merge_requests/authorization_for_merge_requests.md2
-rw-r--r--doc/user/project/merge_requests/changes.md6
-rw-r--r--doc/user/project/merge_requests/conflicts.md2
-rw-r--r--doc/user/project/merge_requests/drafts.md2
-rw-r--r--doc/user/project/merge_requests/img/conflict_ui_v14_0.pngbin8371 -> 0 bytes
-rw-r--r--doc/user/project/merge_requests/img/conflict_ui_v15_6.pngbin0 -> 14089 bytes
-rw-r--r--doc/user/project/merge_requests/index.md95
-rw-r--r--doc/user/project/merge_requests/revert_changes.md2
-rw-r--r--doc/user/project/merge_requests/reviews/data_usage.md2
-rw-r--r--doc/user/project/merge_requests/reviews/index.md2
-rw-r--r--doc/user/project/merge_requests/reviews/suggestions.md7
-rw-r--r--doc/user/project/merge_requests/squash_and_merge.md2
-rw-r--r--doc/user/project/merge_requests/versions.md8
-rw-r--r--doc/user/project/milestones/burndown_and_burnup_charts.md2
-rw-r--r--doc/user/project/milestones/index.md2
-rw-r--r--doc/user/project/ml/experiment_tracking/img/candidates.pngbin0 -> 62281 bytes
-rw-r--r--doc/user/project/ml/experiment_tracking/img/experiments.pngbin0 -> 45022 bytes
-rw-r--r--doc/user/project/ml/experiment_tracking/index.md76
-rw-r--r--doc/user/project/pages/custom_domains_ssl_tls_certification/index.md2
-rw-r--r--doc/user/project/pages/getting_started/pages_ci_cd_template.md10
-rw-r--r--doc/user/project/pages/getting_started/pages_forked_sample_project.md4
-rw-r--r--doc/user/project/pages/getting_started/pages_from_scratch.md6
-rw-r--r--doc/user/project/pages/getting_started/pages_new_project_template.md4
-rw-r--r--doc/user/project/pages/getting_started/pages_ui.md4
-rw-r--r--doc/user/project/pages/img/remove_pages_v15_3.pngbin4432 -> 0 bytes
-rw-r--r--doc/user/project/pages/index.md2
-rw-r--r--doc/user/project/pages/introduction.md67
-rw-r--r--doc/user/project/pages/pages_access_control.md2
-rw-r--r--doc/user/project/pages/public_folder.md2
-rw-r--r--doc/user/project/protected_branches.md2
-rw-r--r--doc/user/project/protected_tags.md2
-rw-r--r--doc/user/project/quick_actions.md14
-rw-r--r--doc/user/project/releases/index.md14
-rw-r--r--doc/user/project/releases/release_fields.md4
-rw-r--r--doc/user/project/remote_development/index.md12
-rw-r--r--doc/user/project/repository/branches/index.md2
-rw-r--r--doc/user/project/repository/gpg_signed_commits/index.md16
-rw-r--r--doc/user/project/repository/index.md2
-rw-r--r--doc/user/project/repository/jupyter_notebooks/index.md12
-rw-r--r--doc/user/project/repository/mirror/index.md3
-rw-r--r--doc/user/project/repository/push_rules.md4
-rw-r--r--doc/user/project/repository/reducing_the_repo_size_using_git.md45
-rw-r--r--doc/user/project/repository/web_editor.md33
-rw-r--r--doc/user/project/repository/x509_signed_commits/index.md5
-rw-r--r--doc/user/project/requirements/index.md6
-rw-r--r--doc/user/project/settings/import_export.md165
-rw-r--r--doc/user/project/settings/import_export_troubleshooting.md280
-rw-r--r--doc/user/project/settings/index.md9
-rw-r--r--doc/user/project/web_ide/index.md13
-rw-r--r--doc/user/project/working_with_projects.md6
-rw-r--r--doc/user/public_access.md12
-rw-r--r--doc/user/reserved_names.md4
-rw-r--r--doc/user/search/advanced_search.md38
-rw-r--r--doc/user/search/global_search/advanced_search_syntax.md55
-rw-r--r--doc/user/shortcuts.md3
-rw-r--r--doc/user/ssh.md25
-rw-r--r--doc/user/tasks.md43
-rw-r--r--doc/user/usage_quotas.md99
-rw-r--r--doc/user/workspace/index.md2
-rw-r--r--generator_templates/usage_metric_definition/metric_definition.yml2
-rw-r--r--glfm_specification/example_snapshots/examples_index.yml2086
-rw-r--r--glfm_specification/example_snapshots/html.yml7955
-rw-r--r--glfm_specification/input/gitlab_flavored_markdown/glfm_internal_extension_examples.md111
-rw-r--r--glfm_specification/input/gitlab_flavored_markdown/glfm_internal_extensions.md113
-rw-r--r--glfm_specification/input/gitlab_flavored_markdown/glfm_intro.md3
-rw-r--r--glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification.md283
-rw-r--r--glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification_examples.md277
-rw-r--r--glfm_specification/output/spec.html9219
-rw-r--r--glfm_specification/output/spec.txt10330
-rw-r--r--glfm_specification/output_example_snapshots/examples_index.yml2086
-rw-r--r--glfm_specification/output_example_snapshots/html.yml7944
-rw-r--r--glfm_specification/output_example_snapshots/markdown.yml (renamed from glfm_specification/example_snapshots/markdown.yml)0
-rw-r--r--glfm_specification/output_example_snapshots/prosemirror_json.yml (renamed from glfm_specification/example_snapshots/prosemirror_json.yml)0
-rw-r--r--glfm_specification/output_example_snapshots/snapshot_spec.html10245
-rw-r--r--glfm_specification/output_example_snapshots/snapshot_spec.md9986
-rw-r--r--glfm_specification/output_spec/spec.html304
-rw-r--r--glfm_specification/output_spec/spec.txt287
-rw-r--r--jest.config.base.js4
-rw-r--r--lefthook.yml6
-rw-r--r--lib/api/access_requests.rb39
-rw-r--r--lib/api/admin/ci/variables.rb49
-rw-r--r--lib/api/admin/instance_clusters.rb52
-rw-r--r--lib/api/admin/plan_limits.rb28
-rw-r--r--lib/api/alert_management_alerts.rb2
-rw-r--r--lib/api/api.rb185
-rw-r--r--lib/api/appearance.rb1
-rw-r--r--lib/api/applications.rb21
-rw-r--r--lib/api/badges.rb9
-rw-r--r--lib/api/boards.rb2
-rw-r--r--lib/api/branches.rb45
-rw-r--r--lib/api/bulk_imports.rb48
-rw-r--r--lib/api/ci/helpers/runner.rb30
-rw-r--r--lib/api/ci/job_artifacts.rb6
-rw-r--r--lib/api/ci/jobs.rb94
-rw-r--r--lib/api/ci/pipeline_schedules.rb144
-rw-r--r--lib/api/ci/pipelines.rb151
-rw-r--r--lib/api/ci/resource_groups.rb54
-rw-r--r--lib/api/ci/runner.rb75
-rw-r--r--lib/api/ci/runners.rb292
-rw-r--r--lib/api/ci/secure_files.rb4
-rw-r--r--lib/api/ci/triggers.rb66
-rw-r--r--lib/api/ci/variables.rb39
-rw-r--r--lib/api/clusters/agent_tokens.rb20
-rw-r--r--lib/api/clusters/agents.rb22
-rw-r--r--lib/api/commit_statuses.rb55
-rw-r--r--lib/api/commits.rb204
-rw-r--r--lib/api/concerns/packages/conan_endpoints.rb6
-rw-r--r--lib/api/container_registry_event.rb14
-rw-r--r--lib/api/container_repositories.rb2
-rw-r--r--lib/api/debian_project_packages.rb4
-rw-r--r--lib/api/dependency_proxy.rb13
-rw-r--r--lib/api/deploy_keys.rb75
-rw-r--r--lib/api/deploy_tokens.rb100
-rw-r--r--lib/api/deployments.rb113
-rw-r--r--lib/api/discussions.rb95
-rw-r--r--lib/api/entities/application.rb10
-rw-r--r--lib/api/entities/application_statistics.rb32
-rw-r--r--lib/api/entities/application_with_secret.rb3
-rw-r--r--lib/api/entities/basic_project_details.rb23
-rw-r--r--lib/api/entities/basic_ref.rb3
-rw-r--r--lib/api/entities/basic_release_details.rb12
-rw-r--r--lib/api/entities/basic_repository_storage_move.rb10
-rw-r--r--lib/api/entities/basic_snippet.rb26
-rw-r--r--lib/api/entities/branch.rb44
-rw-r--r--lib/api/entities/bulk_import.rb12
-rw-r--r--lib/api/entities/bulk_imports/entity.rb28
-rw-r--r--lib/api/entities/bulk_imports/entity_failure.rb18
-rw-r--r--lib/api/entities/bulk_imports/export_status.rb8
-rw-r--r--lib/api/entities/ci/job.rb13
-rw-r--r--lib/api/entities/ci/job_artifact.rb7
-rw-r--r--lib/api/entities/ci/job_artifact_file.rb4
-rw-r--r--lib/api/entities/ci/job_basic.rb27
-rw-r--r--lib/api/entities/ci/lint/result.rb17
-rw-r--r--lib/api/entities/ci/pipeline.rb18
-rw-r--r--lib/api/entities/ci/pipeline_basic.rb17
-rw-r--r--lib/api/entities/ci/pipeline_schedule.rb12
-rw-r--r--lib/api/entities/ci/resource_group.rb6
-rw-r--r--lib/api/entities/ci/runner.rb22
-rw-r--r--lib/api/entities/ci/secure_file.rb2
-rw-r--r--lib/api/entities/ci/variable.rb14
-rw-r--r--lib/api/entities/commit.rb27
-rw-r--r--lib/api/entities/commit_detail.rb6
-rw-r--r--lib/api/entities/commit_note.rb20
-rw-r--r--lib/api/entities/commit_signature.rb4
-rw-r--r--lib/api/entities/commit_stats.rb4
-rw-r--r--lib/api/entities/commit_status.rb18
-rw-r--r--lib/api/entities/compare.rb13
-rw-r--r--lib/api/entities/container_registry.rb14
-rw-r--r--lib/api/entities/contributor.rb6
-rw-r--r--lib/api/entities/custom_attribute.rb4
-rw-r--r--lib/api/entities/deploy_key.rb12
-rw-r--r--lib/api/entities/deploy_keys_project.rb2
-rw-r--r--lib/api/entities/deploy_token.rb9
-rw-r--r--lib/api/entities/deploy_token_with_token.rb2
-rw-r--r--lib/api/entities/deployment.rb9
-rw-r--r--lib/api/entities/diff.rb16
-rw-r--r--lib/api/entities/entity_helpers.rb4
-rw-r--r--lib/api/entities/environment.rb4
-rw-r--r--lib/api/entities/environment_basic.rb7
-rw-r--r--lib/api/entities/error_tracking.rb18
-rw-r--r--lib/api/entities/feature.rb4
-rw-r--r--lib/api/entities/feature_flag.rb12
-rw-r--r--lib/api/entities/feature_flag/scope.rb4
-rw-r--r--lib/api/entities/feature_flag/strategy.rb6
-rw-r--r--lib/api/entities/feature_flag/user_list.rb14
-rw-r--r--lib/api/entities/feature_gate.rb4
-rw-r--r--lib/api/entities/freeze_period.rb8
-rw-r--r--lib/api/entities/go_module_version.rb4
-rw-r--r--lib/api/entities/hook.rb16
-rw-r--r--lib/api/entities/issuable_entity.rb14
-rw-r--r--lib/api/entities/issue_basic.rb16
-rw-r--r--lib/api/entities/license.rb25
-rw-r--r--lib/api/entities/license_basic.rb6
-rw-r--r--lib/api/entities/markdown.rb9
-rw-r--r--lib/api/entities/merge_request_approvals.rb6
-rw-r--r--lib/api/entities/merge_request_basic.rb7
-rw-r--r--lib/api/entities/merge_request_simple.rb7
-rw-r--r--lib/api/entities/metadata.rb9
-rw-r--r--lib/api/entities/metrics/dashboard/annotation.rb14
-rw-r--r--lib/api/entities/metrics/user_starred_dashboard.rb5
-rw-r--r--lib/api/entities/ml/mlflow/run.rb2
-rw-r--r--lib/api/entities/ml/mlflow/run_info.rb2
-rw-r--r--lib/api/entities/ml/mlflow/update_run.rb8
-rw-r--r--lib/api/entities/package.rb29
-rw-r--r--lib/api/entities/package_file.rb11
-rw-r--r--lib/api/entities/personal_access_token.rb13
-rw-r--r--lib/api/entities/plan_limit.rb34
-rw-r--r--lib/api/entities/project.rb159
-rw-r--r--lib/api/entities/project_daily_fetches.rb4
-rw-r--r--lib/api/entities/project_daily_statistics.rb4
-rw-r--r--lib/api/entities/project_export_status.rb14
-rw-r--r--lib/api/entities/project_group_link.rb6
-rw-r--r--lib/api/entities/project_hook.rb15
-rw-r--r--lib/api/entities/project_identity.rb11
-rw-r--r--lib/api/entities/project_import_failed_relation.rb11
-rw-r--r--lib/api/entities/project_import_status.rb16
-rw-r--r--lib/api/entities/project_integration.rb2
-rw-r--r--lib/api/entities/project_integration_basic.rb25
-rw-r--r--lib/api/entities/project_repository_storage.rb10
-rw-r--r--lib/api/entities/project_with_access.rb36
-rw-r--r--lib/api/entities/protected_branch.rb10
-rw-r--r--lib/api/entities/protected_ref_access.rb10
-rw-r--r--lib/api/entities/protected_tag.rb2
-rw-r--r--lib/api/entities/pull_mirror.rb19
-rw-r--r--lib/api/entities/release.rb18
-rw-r--r--lib/api/entities/releases/evidence.rb6
-rw-r--r--lib/api/entities/releases/link.rb20
-rw-r--r--lib/api/entities/releases/source.rb4
-rw-r--r--lib/api/entities/remote_mirror.rb20
-rw-r--r--lib/api/entities/resource_access_token.rb7
-rw-r--r--lib/api/entities/resource_milestone_event.rb12
-rw-r--r--lib/api/entities/snippet.rb8
-rw-r--r--lib/api/entities/snippets/repository_storage_move.rb2
-rw-r--r--lib/api/entities/ssh_key.rb11
-rw-r--r--lib/api/entities/tag.rb6
-rw-r--r--lib/api/entities/tag_release.rb4
-rw-r--r--lib/api/entities/templates_list.rb4
-rw-r--r--lib/api/entities/tree_object.rb7
-rw-r--r--lib/api/entities/trigger.rb10
-rw-r--r--lib/api/entities/user_agent_detail.rb6
-rw-r--r--lib/api/entities/user_associations_count.rb23
-rw-r--r--lib/api/entities/user_basic.rb19
-rw-r--r--lib/api/entities/user_counts.rb25
-rw-r--r--lib/api/entities/user_public.rb24
-rw-r--r--lib/api/entities/user_safe.rb5
-rw-r--r--lib/api/entities/wiki_attachment.rb14
-rw-r--r--lib/api/entities/wiki_page.rb6
-rw-r--r--lib/api/entities/wiki_page_basic.rb6
-rw-r--r--lib/api/entities/x509_certificate.rb17
-rw-r--r--lib/api/entities/x509_issuer.rb11
-rw-r--r--lib/api/entities/x509_signature.rb2
-rw-r--r--lib/api/environments.rb102
-rw-r--r--lib/api/error_tracking/client_keys.rb23
-rw-r--r--lib/api/error_tracking/collector.rb4
-rw-r--r--lib/api/error_tracking/project_settings.rb30
-rw-r--r--lib/api/feature_flags.rb77
-rw-r--r--lib/api/feature_flags_user_lists.rb56
-rw-r--r--lib/api/features.rb45
-rw-r--r--lib/api/files.rb77
-rw-r--r--lib/api/freeze_periods.rb64
-rw-r--r--lib/api/generic_packages.rb4
-rw-r--r--lib/api/geo.rb7
-rwxr-xr-xlib/api/go_proxy.rb52
-rw-r--r--lib/api/group_avatar.rb4
-rw-r--r--lib/api/group_clusters.rb42
-rw-r--r--lib/api/group_container_repositories.rb13
-rw-r--r--lib/api/group_export.rb45
-rw-r--r--lib/api/group_import.rb11
-rw-r--r--lib/api/group_packages.rb19
-rw-r--r--lib/api/group_variables.rb38
-rw-r--r--lib/api/helpers.rb13
-rw-r--r--lib/api/helpers/internal_helpers.rb7
-rw-r--r--lib/api/helpers/label_helpers.rb5
-rw-r--r--lib/api/helpers/merge_requests_helpers.rb5
-rw-r--r--lib/api/helpers/packages/dependency_proxy_helpers.rb2
-rw-r--r--lib/api/helpers/packages/npm.rb2
-rw-r--r--lib/api/helpers/packages_helpers.rb30
-rw-r--r--lib/api/helpers/projects_helpers.rb4
-rw-r--r--lib/api/helpers/users_helpers.rb7
-rw-r--r--lib/api/helpers/web_hooks_helpers.rb6
-rw-r--r--lib/api/import_bitbucket_server.rb8
-rw-r--r--lib/api/import_github.rb24
-rw-r--r--lib/api/integrations.rb51
-rw-r--r--lib/api/internal/kubernetes.rb28
-rw-r--r--lib/api/internal/pages.rb1
-rw-r--r--lib/api/invitations.rb20
-rw-r--r--lib/api/issue_links.rb55
-rw-r--r--lib/api/issues.rb2
-rw-r--r--lib/api/keys.rb12
-rw-r--r--lib/api/labels.rb2
-rw-r--r--lib/api/lint.rb43
-rw-r--r--lib/api/markdown.rb16
-rw-r--r--lib/api/maven_packages.rb14
-rw-r--r--lib/api/merge_request_approvals.rb28
-rw-r--r--lib/api/merge_request_diffs.rb11
-rw-r--r--lib/api/merge_requests.rb2
-rw-r--r--lib/api/metadata.rb57
-rw-r--r--lib/api/metrics/dashboard/annotations.rb25
-rw-r--r--lib/api/metrics/user_starred_dashboards.rb22
-rw-r--r--lib/api/ml/mlflow.rb24
-rw-r--r--lib/api/npm_project_packages.rb2
-rw-r--r--lib/api/nuget_project_packages.rb4
-rw-r--r--lib/api/package_files.rb22
-rw-r--r--lib/api/pages.rb2
-rw-r--r--lib/api/pages_domains.rb2
-rw-r--r--lib/api/pagination_params.rb5
-rw-r--r--lib/api/personal_access_tokens.rb60
-rw-r--r--lib/api/personal_access_tokens/self_information.rb18
-rw-r--r--lib/api/project_clusters.rb49
-rw-r--r--lib/api/project_container_repositories.rb8
-rw-r--r--lib/api/project_debian_distributions.rb2
-rw-r--r--lib/api/project_events.rb9
-rw-r--r--lib/api/project_export.rb61
-rw-r--r--lib/api/project_hooks.rb45
-rw-r--r--lib/api/project_import.rb48
-rw-r--r--lib/api/project_milestones.rb2
-rw-r--r--lib/api/project_packages.rb2
-rw-r--r--lib/api/project_repository_storage_moves.rb17
-rw-r--r--lib/api/project_snapshots.rb5
-rw-r--r--lib/api/project_snippets.rb52
-rw-r--r--lib/api/project_statistics.rb12
-rw-r--r--lib/api/project_templates.rb27
-rw-r--r--lib/api/projects.rb7
-rw-r--r--lib/api/projects_relation_builder.rb4
-rw-r--r--lib/api/protected_branches.rb72
-rw-r--r--lib/api/protected_tags.rb46
-rw-r--r--lib/api/pypi_packages.rb33
-rw-r--r--lib/api/release/links.rb75
-rw-r--r--lib/api/releases.rb197
-rw-r--r--lib/api/remote_mirrors.rb58
-rw-r--r--lib/api/repositories.rb76
-rw-r--r--lib/api/resource_access_tokens.rb35
-rw-r--r--lib/api/resource_milestone_events.rb17
-rw-r--r--lib/api/rpm_project_packages.rb27
-rw-r--r--lib/api/rubygem_packages.rb2
-rw-r--r--lib/api/search.rb8
-rw-r--r--lib/api/settings.rb1
-rw-r--r--lib/api/snippet_repository_storage_moves.rb15
-rw-r--r--lib/api/snippets.rb46
-rw-r--r--lib/api/statistics.rb2
-rw-r--r--lib/api/submodules.rb31
-rw-r--r--lib/api/suggestions.rb6
-rw-r--r--lib/api/system_hooks.rb54
-rw-r--r--lib/api/tags.rb45
-rw-r--r--lib/api/terraform/modules/v1/packages.rb72
-rw-r--r--lib/api/terraform/state.rb76
-rw-r--r--lib/api/terraform/state_version.rb22
-rw-r--r--lib/api/topics.rb10
-rw-r--r--lib/api/unleash.rb34
-rw-r--r--lib/api/user_counts.rb9
-rw-r--r--lib/api/users.rb57
-rw-r--r--lib/api/v3/github.rb2
-rw-r--r--lib/api/validations/validators/email_or_email_list.rb7
-rw-r--r--lib/api/wikis.rb34
-rw-r--r--lib/atlassian/jira_connect/jwt/asymmetric.rb20
-rw-r--r--lib/backup/manager.rb14
-rw-r--r--lib/banzai/filter/external_link_filter.rb12
-rw-r--r--lib/banzai/filter/footnote_filter.rb28
-rw-r--r--lib/banzai/filter/kroki_filter.rb21
-rw-r--r--lib/banzai/filter/math_filter.rb36
-rw-r--r--lib/banzai/filter/plantuml_filter.rb10
-rw-r--r--lib/banzai/filter/repository_link_filter.rb1
-rw-r--r--lib/banzai/filter/syntax_highlight_filter.rb50
-rw-r--r--lib/banzai/filter/table_of_contents_filter.rb16
-rw-r--r--lib/banzai/pipeline/ascii_doc_pipeline.rb2
-rw-r--r--lib/banzai/pipeline/gfm_pipeline.rb4
-rw-r--r--lib/banzai/reference_parser/base_parser.rb10
-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/bulk_imports/clients/http.rb11
-rw-r--r--lib/bulk_imports/common/pipelines/entity_finisher.rb8
-rw-r--r--lib/bulk_imports/common/pipelines/wiki_pipeline.rb2
-rw-r--r--lib/bulk_imports/pipeline/runner.rb39
-rw-r--r--lib/bulk_imports/projects/pipelines/references_pipeline.rb103
-rw-r--r--lib/bulk_imports/projects/stage.rb4
-rw-r--r--lib/error_tracking/sentry_client.rb9
-rw-r--r--lib/error_tracking/sentry_client/issue.rb4
-rw-r--r--lib/feature.rb15
-rw-r--r--lib/feature/gitaly.rb46
-rw-r--r--lib/gitlab/application_context.rb7
-rw-r--r--lib/gitlab/application_rate_limiter/increment_per_actioned_resource.rb2
-rw-r--r--lib/gitlab/asciidoc.rb1
-rw-r--r--lib/gitlab/audit/type/definition.rb13
-rw-r--r--lib/gitlab/audit/type/shared.rb25
-rw-r--r--lib/gitlab/background_migration/backfill_cluster_agents_has_vulnerabilities.rb7
-rw-r--r--lib/gitlab/background_migration/backfill_group_features.rb2
-rw-r--r--lib/gitlab/background_migration/backfill_imported_issue_search_data.rb6
-rw-r--r--lib/gitlab/background_migration/backfill_internal_on_notes.rb3
-rw-r--r--lib/gitlab/background_migration/backfill_namespace_details.rb4
-rw-r--r--lib/gitlab/background_migration/backfill_namespace_id_of_vulnerability_reads.rb4
-rw-r--r--lib/gitlab/background_migration/backfill_project_feature_package_registry_access_level.rb4
-rw-r--r--lib/gitlab/background_migration/backfill_project_import_level.rb4
-rw-r--r--lib/gitlab/background_migration/backfill_project_namespace_details.rb27
-rw-r--r--lib/gitlab/background_migration/backfill_project_namespace_on_issues.rb40
-rw-r--r--lib/gitlab/background_migration/backfill_projects_with_coverage.rb41
-rw-r--r--lib/gitlab/background_migration/backfill_user_details_fields.rb61
-rw-r--r--lib/gitlab/background_migration/backfill_vulnerability_reads_cluster_agent.rb4
-rw-r--r--lib/gitlab/background_migration/backfill_work_item_type_id_for_issues.rb2
-rw-r--r--lib/gitlab/background_migration/batched_migration_job.rb14
-rw-r--r--lib/gitlab/background_migration/copy_column_using_background_migration_job.rb3
-rw-r--r--lib/gitlab/background_migration/delete_orphaned_operational_vulnerabilities.rb3
-rw-r--r--lib/gitlab/background_migration/destroy_invalid_group_members.rb4
-rw-r--r--lib/gitlab/background_migration/destroy_invalid_members.rb3
-rw-r--r--lib/gitlab/background_migration/destroy_invalid_project_members.rb3
-rw-r--r--lib/gitlab/background_migration/disable_legacy_open_source_licence_for_recent_public_projects.rb3
-rw-r--r--lib/gitlab/background_migration/disable_legacy_open_source_license_for_inactive_public_projects.rb3
-rw-r--r--lib/gitlab/background_migration/disable_legacy_open_source_license_for_no_issues_no_repo_projects.rb3
-rw-r--r--lib/gitlab/background_migration/disable_legacy_open_source_license_for_one_member_no_repo_projects.rb3
-rw-r--r--lib/gitlab/background_migration/disable_legacy_open_source_license_for_projects_less_than_one_mb.rb3
-rw-r--r--lib/gitlab/background_migration/encrypt_static_object_token.rb8
-rw-r--r--lib/gitlab/background_migration/expire_o_auth_tokens.rb3
-rw-r--r--lib/gitlab/background_migration/populate_operation_visibility_permissions_from_operations.rb4
-rw-r--r--lib/gitlab/background_migration/populate_projects_star_count.rb58
-rw-r--r--lib/gitlab/background_migration/recount_epic_cache_counts.rb18
-rw-r--r--lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at.rb6
-rw-r--r--lib/gitlab/background_migration/remove_self_managed_wiki_notes.rb6
-rw-r--r--lib/gitlab/background_migration/rename_task_system_note_to_checklist_item.rb4
-rw-r--r--lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values.rb4
-rw-r--r--lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values.rb4
-rw-r--r--lib/gitlab/background_migration/sanitize_confidential_todos.rb52
-rw-r--r--lib/gitlab/background_migration/set_correct_vulnerability_state.rb3
-rw-r--r--lib/gitlab/background_migration/set_legacy_open_source_license_available_for_non_public_projects.rb3
-rw-r--r--lib/gitlab/background_migration/update_delayed_project_removal_to_null_for_user_namespaces.rb6
-rw-r--r--lib/gitlab/cache/ci/project_pipeline_status.rb12
-rw-r--r--lib/gitlab/cache/import/caching.rb42
-rw-r--r--lib/gitlab/cache/metrics.rb87
-rw-r--r--lib/gitlab/ci/ansi2html.rb5
-rw-r--r--lib/gitlab/ci/ansi2json/converter.rb5
-rw-r--r--lib/gitlab/ci/build/image.rb5
-rw-r--r--lib/gitlab/ci/build/rules/rule/clause/exists.rb31
-rw-r--r--lib/gitlab/ci/config.rb4
-rw-r--r--lib/gitlab/ci/config/entry/bridge.rb2
-rw-r--r--lib/gitlab/ci/config/entry/job.rb2
-rw-r--r--lib/gitlab/ci/config/entry/processable.rb1
-rw-r--r--lib/gitlab/ci/config/entry/root.rb2
-rw-r--r--lib/gitlab/ci/config/entry/variable.rb42
-rw-r--r--lib/gitlab/ci/config/entry/variables.rb6
-rw-r--r--lib/gitlab/ci/config/external/file/artifact.rb33
-rw-r--r--lib/gitlab/ci/config/external/file/base.rb39
-rw-r--r--lib/gitlab/ci/config/external/file/local.rb10
-rw-r--r--lib/gitlab/ci/config/external/file/project.rb14
-rw-r--r--lib/gitlab/ci/config/external/file/remote.rb4
-rw-r--r--lib/gitlab/ci/config/external/file/template.rb4
-rw-r--r--lib/gitlab/ci/config/external/mapper.rb16
-rw-r--r--lib/gitlab/ci/parsers/codequality/code_climate.rb21
-rw-r--r--lib/gitlab/ci/parsers/coverage/sax_document.rb7
-rw-r--r--lib/gitlab/ci/parsers/sbom/cyclonedx.rb16
-rw-r--r--lib/gitlab/ci/parsers/security/common.rb10
-rw-r--r--lib/gitlab/ci/parsers/security/validators/schema_validator.rb16
-rw-r--r--lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/cluster-image-scanning-report-format.json984
-rw-r--r--lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/container-scanning-report-format.json916
-rw-r--r--lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/coverage-fuzzing-report-format.json874
-rw-r--r--lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/dast-report-format.json1279
-rw-r--r--lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/dependency-scanning-report-format.json982
-rw-r--r--lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/sast-report-format.json869
-rw-r--r--lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/secret-detection-report-format.json893
-rw-r--r--lib/gitlab/ci/pipeline/chain/command.rb2
-rw-r--r--lib/gitlab/ci/pipeline/chain/ensure_environments.rb13
-rw-r--r--lib/gitlab/ci/pipeline/chain/limit/active_jobs.rb5
-rw-r--r--lib/gitlab/ci/pipeline/chain/populate.rb11
-rw-r--r--lib/gitlab/ci/pipeline/chain/populate_metadata.rb42
-rw-r--r--lib/gitlab/ci/pipeline/seed/deployment.rb59
-rw-r--r--lib/gitlab/ci/pipeline/seed/environment.rb53
-rw-r--r--lib/gitlab/ci/pipeline/seed/pipeline.rb4
-rw-r--r--lib/gitlab/ci/reports/codequality_reports.rb2
-rw-r--r--lib/gitlab/ci/reports/sbom/component.rb25
-rw-r--r--lib/gitlab/ci/reports/sbom/report.rb4
-rw-r--r--lib/gitlab/ci/reports/security/finding.rb12
-rw-r--r--lib/gitlab/ci/reports/security/flag.rb4
-rw-r--r--lib/gitlab/ci/reports/security/reports.rb8
-rw-r--r--lib/gitlab/ci/templates/Bash.gitlab-ci.yml1
-rw-r--r--lib/gitlab/ci/templates/Grails.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.latest.gitlab-ci.yml2
-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/DAST-Default-Branch-Deploy.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.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.yml14
-rw-r--r--lib/gitlab/ci/templates/Jobs/Secret-Detection.latest.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Security/DAST-On-Demand-API-Scan.gitlab-ci.yml3
-rw-r--r--lib/gitlab/ci/templates/Security/DAST-On-Demand-Scan.gitlab-ci.yml3
-rw-r--r--lib/gitlab/ci/templates/Security/DAST-Runner-Validation.gitlab-ci.yml3
-rw-r--r--lib/gitlab/ci/templates/Terraform.gitlab-ci.yml1
-rw-r--r--lib/gitlab/ci/templates/Terraform.latest.gitlab-ci.yml1
-rw-r--r--lib/gitlab/ci/templates/Terraform/Base.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml17
-rw-r--r--lib/gitlab/ci/templates/ThemeKit.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Verify/Browser-Performance.latest.gitlab-ci.yml2
-rw-r--r--lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml4
-rw-r--r--lib/gitlab/ci/templates/dotNET.gitlab-ci.yml1
-rw-r--r--lib/gitlab/ci/variables/builder.rb10
-rw-r--r--lib/gitlab/ci/variables/collection.rb38
-rw-r--r--lib/gitlab/ci/variables/collection/item.rb10
-rw-r--r--lib/gitlab/ci/yaml_processor/result.rb53
-rw-r--r--lib/gitlab/cluster/lifecycle_events.rb17
-rw-r--r--lib/gitlab/cluster/puma_worker_killer_initializer.rb4
-rw-r--r--lib/gitlab/config_checker/external_database_checker.rb16
-rw-r--r--lib/gitlab/container_repository/tags/cache.rb8
-rw-r--r--lib/gitlab/content_security_policy/config_loader.rb2
-rw-r--r--lib/gitlab/data_builder/build.rb8
-rw-r--r--lib/gitlab/data_builder/pipeline.rb7
-rw-r--r--lib/gitlab/database.rb14
-rw-r--r--lib/gitlab/database/background_migration/batched_job.rb8
-rw-r--r--lib/gitlab/database/background_migration/batched_migration.rb15
-rw-r--r--lib/gitlab/database/gitlab_schemas.yml6
-rw-r--r--lib/gitlab/database/load_balancing/configuration.rb3
-rw-r--r--lib/gitlab/database/load_balancing/load_balancer.rb7
-rw-r--r--lib/gitlab/database/load_balancing/service_discovery.rb13
-rw-r--r--lib/gitlab/database/load_balancing/service_discovery/sampler.rb56
-rw-r--r--lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb2
-rw-r--r--lib/gitlab/database/lock_writes_manager.rb7
-rw-r--r--lib/gitlab/database/migration_helpers.rb664
-rw-r--r--lib/gitlab/database/migration_helpers/v2.rb11
-rw-r--r--lib/gitlab/database/migrations/batched_background_migration_helpers.rb37
-rw-r--r--lib/gitlab/database/migrations/constraints_helpers.rb337
-rw-r--r--lib/gitlab/database/migrations/extension_helpers.rb66
-rw-r--r--lib/gitlab/database/migrations/lock_retries_helpers.rb57
-rw-r--r--lib/gitlab/database/migrations/runner.rb6
-rw-r--r--lib/gitlab/database/migrations/timeout_helpers.rb61
-rw-r--r--lib/gitlab/database/partitioning/convert_table_to_first_list_partition.rb31
-rw-r--r--lib/gitlab/database/partitioning/detached_partition_dropper.rb20
-rw-r--r--lib/gitlab/database/partitioning_migration_helpers/index_helpers.rb52
-rw-r--r--lib/gitlab/database/partitioning_migration_helpers/table_management_helpers.rb5
-rw-r--r--lib/gitlab/database/postgres_partition.rb14
-rw-r--r--lib/gitlab/database/query_analyzer.rb6
-rw-r--r--lib/gitlab/database/query_analyzers/base.rb4
-rw-r--r--lib/gitlab/database/query_analyzers/ci/partitioning_analyzer.rb41
-rw-r--r--lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer.rb79
-rw-r--r--lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer.rb39
-rw-r--r--lib/gitlab/database/query_analyzers/query_recorder.rb45
-rw-r--r--lib/gitlab/database/tables_truncate.rb9
-rw-r--r--lib/gitlab/database/type/symbolized_jsonb.rb28
-rw-r--r--lib/gitlab/database_importers/self_monitoring/project/create_service.rb2
-rw-r--r--lib/gitlab/database_importers/self_monitoring/project/delete_service.rb2
-rw-r--r--lib/gitlab/diff/file.rb6
-rw-r--r--lib/gitlab/diff/file_collection/base.rb4
-rw-r--r--lib/gitlab/diff/highlight_cache.rb12
-rw-r--r--lib/gitlab/discussions_diff/highlight_cache.rb20
-rw-r--r--lib/gitlab/doorkeeper_secret_storing/token/pbkdf2_sha512.rb2
-rw-r--r--lib/gitlab/email/common.rb59
-rw-r--r--lib/gitlab/email/handler/create_issue_handler.rb2
-rw-r--r--lib/gitlab/email/handler/unsubscribe_handler.rb4
-rw-r--r--lib/gitlab/email/receiver.rb11
-rw-r--r--lib/gitlab/environment.rb4
-rw-r--r--lib/gitlab/error_tracking.rb3
-rw-r--r--lib/gitlab/etag_caching/store.rb10
-rw-r--r--lib/gitlab/experimentation/group_types.rb10
-rw-r--r--lib/gitlab/external_authorization/cache.rb8
-rw-r--r--lib/gitlab/feature_categories.rb8
-rw-r--r--lib/gitlab/git/repository.rb22
-rw-r--r--lib/gitlab/git_ref_validator.rb2
-rw-r--r--lib/gitlab/gitaly_client.rb24
-rw-r--r--lib/gitlab/gitaly_client/blob_service.rb17
-rw-r--r--lib/gitlab/gitaly_client/cleanup_service.rb6
-rw-r--r--lib/gitlab/gitaly_client/commit_service.rb57
-rw-r--r--lib/gitlab/gitaly_client/conflicts_service.rb7
-rw-r--r--lib/gitlab/gitaly_client/object_pool_service.rb20
-rw-r--r--lib/gitlab/gitaly_client/operation_service.rb70
-rw-r--r--lib/gitlab/gitaly_client/praefect_info_service.rb6
-rw-r--r--lib/gitlab/gitaly_client/ref_service.rb45
-rw-r--r--lib/gitlab/gitaly_client/remote_service.rb5
-rw-r--r--lib/gitlab/gitaly_client/repository_service.rb89
-rw-r--r--lib/gitlab/gitaly_client/with_feature_flag_actors.rb103
-rw-r--r--lib/gitlab/github_import/client.rb4
-rw-r--r--lib/gitlab/github_import/importer/events/changed_assignee.rb10
-rw-r--r--lib/gitlab/github_import/importer/events/changed_label.rb1
-rw-r--r--lib/gitlab/github_import/importer/protected_branch_importer.rb26
-rw-r--r--lib/gitlab/github_import/importer/protected_branches_importer.rb6
-rw-r--r--lib/gitlab/github_import/importer/pull_request_review_importer.rb19
-rw-r--r--lib/gitlab/github_import/importer/pull_requests/review_request_importer.rb38
-rw-r--r--lib/gitlab/github_import/importer/pull_requests/review_requests_importer.rb70
-rw-r--r--lib/gitlab/github_import/importer/pull_requests_importer.rb2
-rw-r--r--lib/gitlab/github_import/importer/repository_importer.rb2
-rw-r--r--lib/gitlab/github_import/representation/protected_branch.rb6
-rw-r--r--lib/gitlab/github_import/representation/pull_requests/review_requests.rb46
-rw-r--r--lib/gitlab/gon_helper.rb13
-rw-r--r--lib/gitlab/grape_logging/loggers/filter_parameters.rb33
-rw-r--r--lib/gitlab/highlight.rb4
-rw-r--r--lib/gitlab/hook_data/merge_request_builder.rb9
-rw-r--r--lib/gitlab/i18n.rb20
-rw-r--r--lib/gitlab/identifier.rb5
-rw-r--r--lib/gitlab/import_export/attributes_permitter.rb8
-rw-r--r--lib/gitlab/import_export/base/relation_object_saver.rb8
-rw-r--r--lib/gitlab/import_export/decompressed_archive_size_validator.rb1
-rw-r--r--lib/gitlab/import_export/project/exported_relations_merger.rb56
-rw-r--r--lib/gitlab/import_export/project/import_export.yml4
-rw-r--r--lib/gitlab/import_export/project/relation_saver.rb2
-rw-r--r--lib/gitlab/import_export/recursive_merge_folders.rb74
-rw-r--r--lib/gitlab/incoming_email.rb40
-rw-r--r--lib/gitlab/instrumentation/redis_base.rb4
-rw-r--r--lib/gitlab/instrumentation/redis_cluster_validator.rb223
-rw-r--r--lib/gitlab/instrumentation/redis_interceptor.rb11
-rw-r--r--lib/gitlab/issues/rebalancing/state.rb33
-rw-r--r--lib/gitlab/json.rb33
-rw-r--r--lib/gitlab/json_logger.rb57
-rw-r--r--lib/gitlab/kas.rb2
-rw-r--r--lib/gitlab/kroki.rb1
-rw-r--r--lib/gitlab/manifest_import/metadata.rb8
-rw-r--r--lib/gitlab/marginalia/comment.rb12
-rw-r--r--lib/gitlab/markdown_cache/redis/store.rb16
-rw-r--r--lib/gitlab/memory/watchdog.rb13
-rw-r--r--lib/gitlab/memory/watchdog/configuration.rb9
-rw-r--r--lib/gitlab/memory/watchdog/configurator.rb63
-rw-r--r--lib/gitlab/memory/watchdog/monitor/heap_fragmentation.rb2
-rw-r--r--lib/gitlab/memory/watchdog/monitor/rss_memory_limit.rb35
-rw-r--r--lib/gitlab/memory/watchdog/monitor/unique_memory_growth.rb2
-rw-r--r--lib/gitlab/merge_requests/mergeability/check_result.rb4
-rw-r--r--lib/gitlab/merge_requests/mergeability/redis_interface.rb10
-rw-r--r--lib/gitlab/metrics/dashboard/finder.rb2
-rw-r--r--lib/gitlab/metrics/global_search_slis.rb10
-rw-r--r--lib/gitlab/metrics/loose_foreign_keys_slis.rb46
-rw-r--r--lib/gitlab/metrics/method_call.rb1
-rw-r--r--lib/gitlab/metrics/samplers/base_sampler.rb8
-rw-r--r--lib/gitlab/metrics/samplers/ruby_sampler.rb7
-rw-r--r--lib/gitlab/metrics/system.rb33
-rw-r--r--lib/gitlab/nav/top_nav_view_model_builder.rb5
-rw-r--r--lib/gitlab/observability.rb15
-rw-r--r--lib/gitlab/octokit/middleware.rb6
-rw-r--r--lib/gitlab/pagination/gitaly_keyset_pager.rb14
-rw-r--r--lib/gitlab/pagination/keyset/in_operator_optimization/strategies/record_loader_strategy.rb10
-rw-r--r--lib/gitlab/pagination_delegate.rb67
-rw-r--r--lib/gitlab/patch/sidekiq_cron_poller.rb26
-rw-r--r--lib/gitlab/performance_bar/redis_adapter_when_peek_enabled.rb2
-rw-r--r--lib/gitlab/project_search_results.rb4
-rw-r--r--lib/gitlab/project_template.rb8
-rw-r--r--lib/gitlab/qa.rb17
-rw-r--r--lib/gitlab/query_limiting/transaction.rb4
-rw-r--r--lib/gitlab/quick_actions/issuable_actions.rb60
-rw-r--r--lib/gitlab/quick_actions/issue_actions.rb17
-rw-r--r--lib/gitlab/quick_actions/issue_and_merge_request_actions.rb6
-rw-r--r--lib/gitlab/redis/multi_store.rb1
-rw-r--r--lib/gitlab/reference_extractor.rb8
-rw-r--r--lib/gitlab/request_forgery_protection.rb8
-rw-r--r--lib/gitlab/runtime.rb4
-rw-r--r--lib/gitlab/search/recent_items.rb2
-rw-r--r--lib/gitlab/service_desk_email.rb18
-rw-r--r--lib/gitlab/set_cache.rb2
-rw-r--r--lib/gitlab/shard_health_cache.rb16
-rw-r--r--lib/gitlab/shell.rb5
-rw-r--r--lib/gitlab/sidekiq_config.rb2
-rw-r--r--lib/gitlab/sidekiq_daemon/memory_killer.rb6
-rw-r--r--lib/gitlab/sidekiq_middleware/arguments_logger.rb4
-rw-r--r--lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb159
-rw-r--r--lib/gitlab/sidekiq_middleware/retry_error.rb9
-rw-r--r--lib/gitlab/sidekiq_middleware/server_metrics.rb2
-rw-r--r--lib/gitlab/sidekiq_middleware/size_limiter/compressor.rb2
-rw-r--r--lib/gitlab/sidekiq_migrate_jobs.rb66
-rw-r--r--lib/gitlab/slash_commands/application_help.rb13
-rw-r--r--lib/gitlab/slash_commands/command.rb12
-rw-r--r--lib/gitlab/slash_commands/incident_management/incident_command.rb19
-rw-r--r--lib/gitlab/slash_commands/incident_management/incident_new.rb29
-rw-r--r--lib/gitlab/slash_commands/presenters/help.rb11
-rw-r--r--lib/gitlab/slash_commands/presenters/incident_management/incident_new.rb15
-rw-r--r--lib/gitlab/sql/pattern.rb28
-rw-r--r--lib/gitlab/template/base_template.rb2
-rw-r--r--lib/gitlab/tracking/helpers/weak_password_error_event.rb26
-rw-r--r--lib/gitlab/url_builder.rb13
-rw-r--r--lib/gitlab/usage/metric_definition.rb8
-rw-r--r--lib/gitlab/usage/metrics/aggregates.rb3
-rw-r--r--lib/gitlab/usage/metrics/aggregates/aggregate.rb36
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/aggregated_metric.rb11
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/count_merge_request_authors_metric.rb15
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/database_metric.rb12
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_disabled_metric.rb20
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_metric.rb24
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/dormant_user_period_setting_metric.rb15
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/dormant_user_setting_enabled_metric.rb15
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_cta_clicked_metric.rb54
-rw-r--r--lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_sent_metric.rb54
-rw-r--r--lib/gitlab/usage/metrics/name_suggestion.rb30
-rw-r--r--lib/gitlab/usage/metrics/names_suggestions/relation_parsers/constraints.rb31
-rw-r--r--lib/gitlab/usage/metrics/names_suggestions/relation_parsers/having_constraints.rb31
-rw-r--r--lib/gitlab/usage/metrics/names_suggestions/relation_parsers/where_constraints.rb31
-rw-r--r--lib/gitlab/usage_data.rb102
-rw-r--r--lib/gitlab/usage_data_counters.rb16
-rw-r--r--lib/gitlab/usage_data_counters/ci_template_unique_counter.rb12
-rw-r--r--lib/gitlab/usage_data_counters/counter_events/package_events.yml2
-rw-r--r--lib/gitlab/usage_data_counters/known_events/common.yml5
-rw-r--r--lib/gitlab/usage_data_counters/known_events/package_events.yml8
-rw-r--r--lib/gitlab/usage_data_counters/known_events/work_items.yml13
-rw-r--r--lib/gitlab/usage_data_counters/kubernetes_agent_counter.rb2
-rw-r--r--lib/gitlab/usage_data_counters/work_item_activity_unique_counter.rb5
-rw-r--r--lib/gitlab/utils.rb15
-rw-r--r--lib/gitlab/utils/measuring.rb2
-rw-r--r--lib/gitlab/utils/strong_memoize.rb44
-rw-r--r--lib/gitlab/web_hooks/recursion_detection.rb2
-rw-r--r--lib/gitlab/workhorse.rb14
-rw-r--r--lib/object_storage/direct_upload.rb28
-rw-r--r--lib/product_analytics/collector_app.rb40
-rw-r--r--lib/rouge/formatters/html_gitlab.rb8
-rw-r--r--lib/sbom/package_url.rb122
-rw-r--r--lib/sbom/package_url/argument_validator.rb90
-rw-r--r--lib/sbom/package_url/decoder.rb181
-rw-r--r--lib/sbom/package_url/encoder.rb137
-rw-r--r--lib/sbom/package_url/normalizer.rb47
-rw-r--r--lib/sbom/package_url/string_utils.rb77
-rw-r--r--lib/serializers/symbolized_json.rb18
-rw-r--r--lib/sidebars/groups/menus/observability_menu.rb38
-rw-r--r--lib/sidebars/groups/menus/settings_menu.rb4
-rw-r--r--lib/sidebars/projects/menus/deployments_menu.rb2
-rw-r--r--lib/sidebars/projects/menus/infrastructure_menu.rb10
-rw-r--r--lib/sidebars/projects/menus/monitor_menu.rb15
-rw-r--r--lib/tasks/contracts/pipelines.rake6
-rw-r--r--lib/tasks/gitlab/assets.rake24
-rw-r--r--lib/tasks/gitlab/db/validate_config.rake18
-rw-r--r--lib/tasks/gitlab/openapi.rake9
-rw-r--r--lib/tasks/gitlab/seed.rake54
-rw-r--r--lib/tasks/gitlab/sidekiq.rake15
-rw-r--r--lib/tasks/gitlab/tw/codeowners.rake33
-rw-r--r--lib/tasks/gitlab/update_templates.rake4
-rw-r--r--lib/unnested_in_filters/rewriter.rb87
-rw-r--r--locale/am_ET/gitlab.po1626
-rw-r--r--locale/ar_SA/gitlab.po1678
-rw-r--r--locale/as_IN/gitlab.po1626
-rw-r--r--locale/az_AZ/gitlab.po1626
-rw-r--r--locale/ba_RU/gitlab.po1613
-rw-r--r--locale/bg/gitlab.po1626
-rw-r--r--locale/bn_BD/gitlab.po1626
-rw-r--r--locale/bn_IN/gitlab.po1626
-rw-r--r--locale/br_FR/gitlab.po1665
-rw-r--r--locale/bs_BA/gitlab.po1645
-rw-r--r--locale/ca_ES/gitlab.po1626
-rw-r--r--locale/cs_CZ/gitlab.po1652
-rw-r--r--locale/cy_GB/gitlab.po1678
-rw-r--r--locale/da_DK/gitlab.po1682
-rw-r--r--locale/de/gitlab.po1662
-rw-r--r--locale/el_GR/gitlab.po1626
-rw-r--r--locale/en_GB/gitlab.po1636
-rw-r--r--locale/eo/gitlab.po1626
-rw-r--r--locale/es/gitlab.po1668
-rw-r--r--locale/et_EE/gitlab.po1626
-rw-r--r--locale/fa_IR/gitlab.po1626
-rw-r--r--locale/fi_FI/gitlab.po1626
-rw-r--r--locale/fil_PH/gitlab.po1626
-rw-r--r--locale/fr/gitlab.po6540
-rw-r--r--locale/gitlab.pot1406
-rw-r--r--locale/gl_ES/gitlab.po1626
-rw-r--r--locale/he_IL/gitlab.po1652
-rw-r--r--locale/hi_IN/gitlab.po1626
-rw-r--r--locale/hr_HR/gitlab.po1639
-rw-r--r--locale/hu_HU/gitlab.po1626
-rw-r--r--locale/hy_AM/gitlab.po1626
-rw-r--r--locale/id_ID/gitlab.po1613
-rw-r--r--locale/ig_NG/gitlab.po1613
-rw-r--r--locale/is_IS/gitlab.po1626
-rw-r--r--locale/it/gitlab.po1626
-rw-r--r--locale/ja/gitlab.po1755
-rw-r--r--locale/ka_GE/gitlab.po1626
-rw-r--r--locale/kab/gitlab.po1626
-rw-r--r--locale/ko/gitlab.po2015
-rw-r--r--locale/ku_TR/gitlab.po1626
-rw-r--r--locale/ky_KG/gitlab.po1626
-rw-r--r--locale/lt_LT/gitlab.po1652
-rw-r--r--locale/mk_MK/gitlab.po1626
-rw-r--r--locale/ml_IN/gitlab.po1626
-rw-r--r--locale/mn_MN/gitlab.po1626
-rw-r--r--locale/nb_NO/gitlab.po1658
-rw-r--r--locale/nl_NL/gitlab.po1626
-rw-r--r--locale/or_IN/gitlab.po1626
-rw-r--r--locale/pa_IN/gitlab.po1626
-rw-r--r--locale/pa_PK/gitlab.po1626
-rw-r--r--locale/pl_PL/gitlab.po1656
-rw-r--r--locale/pt_BR/gitlab.po2002
-rw-r--r--locale/pt_PT/gitlab.po1632
-rw-r--r--locale/ro_RO/gitlab.po1909
-rw-r--r--locale/ru/gitlab.po1682
-rw-r--r--locale/si_LK/gitlab.po1638
-rw-r--r--locale/sk_SK/gitlab.po1652
-rw-r--r--locale/sl_SI/gitlab.po1652
-rw-r--r--locale/sq_AL/gitlab.po1626
-rw-r--r--locale/sr_CS/gitlab.po1639
-rw-r--r--locale/sr_SP/gitlab.po1639
-rw-r--r--locale/sv_SE/gitlab.po1626
-rw-r--r--locale/sw_KE/gitlab.po1626
-rw-r--r--locale/ta_IN/gitlab.po1626
-rw-r--r--locale/th_TH/gitlab.po1613
-rw-r--r--locale/tr_TR/gitlab.po1634
-rw-r--r--locale/uk/gitlab.po2772
-rw-r--r--locale/ur_PK/gitlab.po1626
-rw-r--r--locale/uz_UZ/gitlab.po1626
-rw-r--r--locale/vi_VN/gitlab.po1613
-rw-r--r--locale/zh_CN/gitlab.po1895
-rw-r--r--locale/zh_HK/gitlab.po1615
-rw-r--r--locale/zh_TW/gitlab.po1971
-rw-r--r--package.json20
-rw-r--r--qa/Dockerfile5
-rw-r--r--qa/Gemfile31
-rw-r--r--qa/Gemfile.lock86
-rw-r--r--qa/lib/gitlab/page/group/settings/usage_quota.stub.rb515
-rw-r--r--qa/lib/gitlab/page/group/settings/usage_quotas.rb5
-rw-r--r--qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb635
-rw-r--r--qa/qa/fixtures/package_managers/helm/helm_install_package.yaml.erb3
-rw-r--r--qa/qa/fixtures/package_managers/helm/helm_upload_package.yaml.erb3
-rw-r--r--qa/qa/flow/sign_up.rb4
-rw-r--r--qa/qa/git/repository.rb5
-rw-r--r--qa/qa/mobile/page/base.rb16
-rw-r--r--qa/qa/page/admin/overview/users/index.rb4
-rw-r--r--qa/qa/page/base.rb71
-rw-r--r--qa/qa/page/component/access_tokens.rb18
-rw-r--r--qa/qa/page/component/delete_modal.rb35
-rw-r--r--qa/qa/page/component/groups_filter.rb23
-rw-r--r--qa/qa/page/component/issuable/sidebar.rb74
-rw-r--r--qa/qa/page/component/lazy_loader.rb4
-rw-r--r--qa/qa/page/component/legacy_clone_panel.rb2
-rw-r--r--qa/qa/page/component/namespace_select.rb9
-rw-r--r--qa/qa/page/component/users_select.rb14
-rw-r--r--qa/qa/page/component/wiki.rb2
-rw-r--r--qa/qa/page/file/edit.rb4
-rw-r--r--qa/qa/page/file/form.rb4
-rw-r--r--qa/qa/page/file/shared/editor.rb4
-rw-r--r--qa/qa/page/group/members.rb1
-rw-r--r--qa/qa/page/group/new.rb2
-rw-r--r--qa/qa/page/issuable/new.rb9
-rw-r--r--qa/qa/page/label/index.rb2
-rw-r--r--qa/qa/page/main/menu.rb14
-rw-r--r--qa/qa/page/profile/two_factor_auth.rb7
-rw-r--r--qa/qa/page/project/branches/show.rb38
-rw-r--r--qa/qa/page/project/import/github.rb9
-rw-r--r--qa/qa/page/project/new.rb2
-rw-r--r--qa/qa/page/project/pipeline/show.rb10
-rw-r--r--qa/qa/page/project/pipeline_editor/show.rb10
-rw-r--r--qa/qa/page/project/settings/advanced.rb44
-rw-r--r--qa/qa/page/project/settings/ci_variables.rb7
-rw-r--r--qa/qa/page/project/settings/default_branch.rb6
-rw-r--r--qa/qa/page/project/settings/mirroring_repositories.rb47
-rw-r--r--qa/qa/page/project/settings/protected_branches.rb6
-rw-r--r--qa/qa/page/project/settings/repository.rb2
-rw-r--r--qa/qa/page/project/show.rb14
-rw-r--r--qa/qa/page/project/sub_menus/ci_cd.rb2
-rw-r--r--qa/qa/page/project/sub_menus/issues.rb2
-rw-r--r--qa/qa/resource/approval_configuration.rb55
-rw-r--r--qa/qa/resource/base.rb16
-rw-r--r--qa/qa/resource/group.rb10
-rw-r--r--qa/qa/resource/members.rb7
-rw-r--r--qa/qa/resource/merge_request.rb30
-rw-r--r--qa/qa/resource/project.rb11
-rw-r--r--qa/qa/resource/project_imported_from_github.rb5
-rw-r--r--qa/qa/resource/sandbox.rb4
-rw-r--r--qa/qa/resource/user.rb15
-rw-r--r--qa/qa/runtime/allure_report.rb9
-rw-r--r--qa/qa/runtime/browser.rb2
-rw-r--r--qa/qa/runtime/env.rb6
-rw-r--r--qa/qa/runtime/key/ed25519.rb4
-rw-r--r--qa/qa/scenario/bootable.rb5
-rw-r--r--qa/qa/scenario/test/instance/gitlab_pages.rb13
-rw-r--r--qa/qa/specs/features/api/12_systems/gitaly/automatic_failover_and_recovery_spec.rb2
-rw-r--r--qa/qa/specs/features/api/12_systems/gitaly/backend_node_recovery_spec.rb2
-rw-r--r--qa/qa/specs/features/api/12_systems/gitaly/changing_repository_storage_spec.rb2
-rw-r--r--qa/qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb8
-rw-r--r--qa/qa/specs/features/api/12_systems/gitaly/gitaly_mtls_spec.rb2
-rw-r--r--qa/qa/specs/features/api/12_systems/gitaly/praefect_connectivity_spec.rb2
-rw-r--r--qa/qa/specs/features/api/12_systems/gitaly/praefect_dataloss_spec.rb2
-rw-r--r--qa/qa/specs/features/api/12_systems/gitaly/praefect_replication_queue_spec.rb2
-rw-r--r--qa/qa/specs/features/api/12_systems/gitaly/praefect_repo_sync_spec.rb2
-rw-r--r--qa/qa/specs/features/api/1_manage/group_access_token_spec.rb2
-rw-r--r--qa/qa/specs/features/api/1_manage/import/import_github_repo_spec.rb312
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_issue_spec.rb2
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb15
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb2
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb79
-rw-r--r--qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb2
-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/migration/gitlab_migration_release_spec.rb2
-rw-r--r--qa/qa/specs/features/api/1_manage/project_access_token_spec.rb2
-rw-r--r--qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb2
-rw-r--r--qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb2
-rw-r--r--qa/qa/specs/features/api/3_create/repository/storage_size_spec.rb1
-rw-r--r--qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb2
-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/cancel_pipeline_when_block_user_spec.rb2
-rw-r--r--qa/qa/specs/features/api/4_verify/file_variable_spec.rb70
-rw-r--r--qa/qa/specs/features/api/4_verify/remove_runner_spec.rb2
-rw-r--r--qa/qa/specs/features/api/5_package/container_registry_spec.rb2
-rw-r--r--qa/qa/specs/features/api/8_monitor/metrics_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/14_analytics/performance_bar_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/14_analytics/service_ping_default_enabled_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/14_analytics/service_ping_disabled_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/group/group_access_token_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb114
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/project/project_access_token_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/user/parent_group_access_termination_spec.rb18
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb17
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/custom_issue_template_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb38
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_from_push_notification_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/rebase_merge_request_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_creation_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_manipulation_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_directory_management_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_file_upload_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_list_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_page_deletion_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb5
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb11
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb9
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_with_multiple_files_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_with_multiple_files_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb7
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/snippet/snippet_index_page_spec.rb9
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/add_file_template_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/add_new_directory_in_web_ide_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/create_first_file_in_web_ide_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/link_to_line_in_web_ide_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/open_fork_in_web_ide_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/open_web_ide_from_diff_tab_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/review_merge_request_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/server_hooks_custom_error_message_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/upload_new_file_in_web_ide_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/3_create/web_ide/web_terminal_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_remove_ci_variable_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/custom_variable_spec.rb86
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/pipeline_with_protected_variable_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/prefill_variables_spec.rb71
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb148
-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/create_and_process_pipeline_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/include_local_config_file_paths_with_wildcard_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb4
-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/merge_mr_when_pipline_is_blocked_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/mr_event_rule_pipeline_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_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/pipeline/pipeline_editor_branch_switcher_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb21
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_via_web_only_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_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/container_registry/container_registry_omnibus_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/helm_registry_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb6
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/maven_gradle_repository_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_group_level_spec.rb14
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_project_level_spec.rb3
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_key/clone_using_deploy_key_spec.rb4
-rw-r--r--qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb2
-rw-r--r--qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb4
-rw-r--r--qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb46
-rw-r--r--qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb (renamed from qa/qa/specs/features/api/1_manage/migration/gitlab_project_migration_common.rb)0
-rw-r--r--qa/qa/specs/helpers/context_selector.rb1
-rw-r--r--qa/qa/specs/runner.rb2
-rw-r--r--qa/qa/specs/spec_helper.rb10
-rw-r--r--qa/qa/support/fips.rb2
-rw-r--r--qa/qa/support/formatters/allure_metadata_formatter.rb16
-rw-r--r--qa/qa/support/formatters/context_formatter.rb1
-rw-r--r--qa/qa/support/formatters/test_metrics_formatter.rb242
-rw-r--r--qa/qa/support/formatters/test_stats_formatter.rb179
-rw-r--r--qa/qa/support/influxdb_tools.rb4
-rw-r--r--qa/qa/support/loglinking.rb28
-rw-r--r--qa/qa/support/page/logging.rb15
-rw-r--r--qa/qa/tools/ci/qa_changes.rb2
-rw-r--r--qa/qa/tools/ci/test_metrics.rb52
-rw-r--r--qa/qa/tools/delete_subgroups.rb137
-rw-r--r--qa/spec/resource/api_fabricator_spec.rb4
-rw-r--r--qa/spec/resource/base_spec.rb36
-rw-r--r--qa/spec/resource/user_spec.rb27
-rw-r--r--qa/spec/specs/runner_spec.rb2
-rw-r--r--qa/spec/support/formatters/test_metrics_formatter_spec.rb336
-rw-r--r--qa/spec/support/formatters/test_stats_formatter_spec.rb290
-rw-r--r--qa/spec/support/loglinking_spec.rb62
-rw-r--r--qa/spec/support/repeater_spec.rb302
-rw-r--r--qa/spec/tools/ci/qa_changes_spec.rb8
-rw-r--r--qa/spec/tools/ci/test_metrics_spec.rb54
-rw-r--r--qa/spec/tools/test_resources_data_processor_spec.rb2
-rw-r--r--qa/tasks/ci.rake37
-rw-r--r--qa/tasks/knapsack.rake20
-rw-r--r--rubocop/cop/api/ensure_string_detail.rb51
-rw-r--r--rubocop/cop/gitlab/duplicate_spec_location.rb67
-rw-r--r--rubocop/cop/gitlab/feature_available_usage.rb1
-rw-r--r--rubocop/cop/gitlab/json.rb33
-rw-r--r--rubocop/cop/gitlab/mark_used_feature_flags.rb2
-rw-r--r--rubocop/cop/gitlab/rspec/avoid_setup.rb82
-rw-r--r--rubocop/cop/graphql/enum_names.rb87
-rw-r--r--rubocop/cop/graphql/enum_values.rb79
-rw-r--r--rubocop/cop/migration/schema_addition_methods_no_post.rb35
-rw-r--r--rubocop/cop/rake/require.rb84
-rw-r--r--rubocop/cop/rspec/duplicate_spec_location.rb67
-rw-r--r--rubocop/cop/rspec/factory_bot/strategy_in_callback.rb45
-rw-r--r--rubocop/migration_helpers.rb12
-rw-r--r--scripts/api/create_issue.rb29
-rw-r--r--scripts/api/pipeline_failed_jobs.rb2
-rwxr-xr-xscripts/build_qa_image31
-rwxr-xr-xscripts/create-pipeline-failure-incident.rb174
-rwxr-xr-xscripts/generate-e2e-pipeline7
-rwxr-xr-xscripts/generate-failed-pipeline-slack-message.rb143
-rwxr-xr-xscripts/glfm/run-snapshot-tests.sh3
-rw-r--r--scripts/lib/glfm/constants.rb34
-rw-r--r--scripts/lib/glfm/parse_examples.rb10
-rw-r--r--scripts/lib/glfm/update_example_snapshots.rb12
-rw-r--r--scripts/lib/glfm/update_specification.rb161
-rw-r--r--scripts/lib/glfm/verify_all_generated_files_are_up_to_date.rb18
-rwxr-xr-xscripts/license-check.sh3
-rwxr-xr-xscripts/lint-doc.sh2
-rwxr-xr-xscripts/lint_templates_bash.rb6
-rwxr-xr-xscripts/merge-reports2
-rwxr-xr-xscripts/perf/gc/print_gc_stats.rb2
-rwxr-xr-xscripts/perf/query_limiting_report.rb26
-rwxr-xr-xscripts/qa/quarantine-types-check18
-rwxr-xr-xscripts/qa/testcases-check3
-rwxr-xr-xscripts/review_apps/automated_cleanup.rb6
-rw-r--r--scripts/review_apps/base-config.yaml108
-rwxr-xr-xscripts/review_apps/review-apps.sh63
-rw-r--r--scripts/rspec_helpers.sh15
-rwxr-xr-xscripts/rubocop-parse44
-rwxr-xr-xscripts/security-harness1
-rwxr-xr-xscripts/setup/as-if-jh.sh28
-rwxr-xr-xscripts/used-feature-flags4
-rw-r--r--scripts/utils.sh2
-rw-r--r--spec/bin/audit_event_type_spec.rb293
-rw-r--r--spec/components/pajamas/spinner_component_spec.rb4
-rw-r--r--spec/components/previews/pajamas/alert_component_preview.rb2
-rw-r--r--spec/components/previews/pajamas/avatar_component_preview.rb6
-rw-r--r--spec/components/previews/pajamas/badge_component_preview.rb4
-rw-r--r--spec/components/previews/pajamas/banner_component_preview.rb2
-rw-r--r--spec/components/previews/pajamas/button_component_preview.rb8
-rw-r--r--spec/components/previews/pajamas/progress_component_preview.rb4
-rw-r--r--spec/components/previews/pajamas/spinner_component_preview.rb22
-rw-r--r--spec/config/inject_enterprise_edition_module_spec.rb18
-rw-r--r--spec/config/metrics/aggregates/aggregated_metrics_spec.rb95
-rw-r--r--spec/contracts/contracts/project/pipeline/index/pipelines#index-get_list_project_pipelines.json6
-rw-r--r--spec/contracts/provider/helpers/publish_contract_helper.rb17
-rw-r--r--spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_batch_helper.rb2
-rw-r--r--spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_metadata_helper.rb4
-rw-r--r--spec/contracts/provider/pact_helpers/project/merge_request/show/discussions_helper.rb4
-rw-r--r--spec/contracts/provider/pact_helpers/project/pipeline/index/create_a_new_pipeline_helper.rb4
-rw-r--r--spec/contracts/provider/pact_helpers/project/pipeline/index/get_list_project_pipelines_helper.rb4
-rw-r--r--spec/contracts/provider/pact_helpers/project/pipeline/show/delete_pipeline_helper.rb5
-rw-r--r--spec/contracts/provider/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb6
-rw-r--r--spec/contracts/provider/pact_helpers/project/pipeline_schedule/update_pipeline_schedule_helper.rb4
-rw-r--r--spec/contracts/publish-contracts.sh23
-rw-r--r--spec/controllers/admin/groups_controller_spec.rb8
-rw-r--r--spec/controllers/admin/hooks_controller_spec.rb24
-rw-r--r--spec/controllers/admin/integrations_controller_spec.rb2
-rw-r--r--spec/controllers/admin/spam_logs_controller_spec.rb35
-rw-r--r--spec/controllers/admin/topics_controller_spec.rb2
-rw-r--r--spec/controllers/admin/users_controller_spec.rb313
-rw-r--r--spec/controllers/concerns/issuable_actions_spec.rb13
-rw-r--r--spec/controllers/concerns/preferred_language_switcher_spec.rb51
-rw-r--r--spec/controllers/concerns/renders_commits_spec.rb4
-rw-r--r--spec/controllers/concerns/send_file_upload_spec.rb29
-rw-r--r--spec/controllers/confirmations_controller_spec.rb31
-rw-r--r--spec/controllers/dashboard_controller_spec.rb14
-rw-r--r--spec/controllers/explore/groups_controller_spec.rb46
-rw-r--r--spec/controllers/explore/projects_controller_spec.rb25
-rw-r--r--spec/controllers/graphql_controller_spec.rb114
-rw-r--r--spec/controllers/groups/children_controller_spec.rb2
-rw-r--r--spec/controllers/groups/group_members_controller_spec.rb35
-rw-r--r--spec/controllers/groups/registry/repositories_controller_spec.rb2
-rw-r--r--spec/controllers/groups/releases_controller_spec.rb4
-rw-r--r--spec/controllers/groups/runners_controller_spec.rb12
-rw-r--r--spec/controllers/groups/settings/repository_controller_spec.rb117
-rw-r--r--spec/controllers/groups_controller_spec.rb28
-rw-r--r--spec/controllers/oauth/authorizations_controller_spec.rb69
-rw-r--r--spec/controllers/omniauth_callbacks_controller_spec.rb2
-rw-r--r--spec/controllers/passwords_controller_spec.rb16
-rw-r--r--spec/controllers/profiles/personal_access_tokens_controller_spec.rb95
-rw-r--r--spec/controllers/projects/alerting/notifications_controller_spec.rb20
-rw-r--r--spec/controllers/projects/artifacts_controller_spec.rb70
-rw-r--r--spec/controllers/projects/environments_controller_spec.rb8
-rw-r--r--spec/controllers/projects/hooks_controller_spec.rb59
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb114
-rw-r--r--spec/controllers/projects/jobs_controller_spec.rb90
-rw-r--r--spec/controllers/projects/learn_gitlab_controller_spec.rb11
-rw-r--r--spec/controllers/projects/merge_requests/diffs_controller_spec.rb12
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb32
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb65
-rw-r--r--spec/controllers/projects/product_analytics_controller_spec.rb95
-rw-r--r--spec/controllers/projects/prometheus/alerts_controller_spec.rb11
-rw-r--r--spec/controllers/projects/registry/repositories_controller_spec.rb25
-rw-r--r--spec/controllers/projects/releases_controller_spec.rb2
-rw-r--r--spec/controllers/projects/runners_controller_spec.rb2
-rw-r--r--spec/controllers/projects/settings/integrations_controller_spec.rb17
-rw-r--r--spec/controllers/projects/settings/repository_controller_spec.rb172
-rw-r--r--spec/controllers/projects/starrers_controller_spec.rb6
-rw-r--r--spec/controllers/projects_controller_spec.rb1
-rw-r--r--spec/controllers/registrations_controller_spec.rb73
-rw-r--r--spec/controllers/search_controller_spec.rb9
-rw-r--r--spec/controllers/sessions_controller_spec.rb2
-rw-r--r--spec/db/schema_spec.rb9
-rw-r--r--spec/experiments/application_experiment_spec.rb66
-rw-r--r--spec/experiments/require_verification_for_namespace_creation_experiment_spec.rb28
-rw-r--r--spec/experiments/security_reports_mr_widget_prompt_experiment_spec.rb6
-rw-r--r--spec/factories/ci/builds.rb25
-rw-r--r--spec/factories/ci/job_artifacts.rb2
-rw-r--r--spec/factories/ci/pipeline_metadata.rb2
-rw-r--r--spec/factories/ci/pipelines.rb10
-rw-r--r--spec/factories/ci/processable.rb2
-rw-r--r--spec/factories/ci/reports/codequality_degradations.rb9
-rw-r--r--spec/factories/ci/reports/sbom/components.rb14
-rw-r--r--spec/factories/ci/reports/sbom/reports.rb6
-rw-r--r--spec/factories/ci/secure_files.rb9
-rw-r--r--spec/factories/ci/stages.rb2
-rw-r--r--spec/factories/container_repositories.rb4
-rw-r--r--spec/factories/dependency_proxy.rb9
-rw-r--r--spec/factories/experiment_subjects.rb9
-rw-r--r--spec/factories/experiment_users.rb10
-rw-r--r--spec/factories/experiments.rb7
-rw-r--r--spec/factories/integrations.rb13
-rw-r--r--spec/factories/member_roles.rb2
-rw-r--r--spec/factories/merge_request_reviewers.rb9
-rw-r--r--spec/factories/packages/rpm/rpm_repository_files.rb9
-rw-r--r--spec/factories/project_hooks.rb4
-rw-r--r--spec/factories/projects.rb13
-rw-r--r--spec/factories/projects/import_export/export_relation.rb11
-rw-r--r--spec/factories/projects/import_export/relation_export.rb27
-rw-r--r--spec/factories/projects/import_export/relation_export_upload.rb8
-rw-r--r--spec/factories/projects/wiki_repositories.rb7
-rw-r--r--spec/factories/protected_branches.rb37
-rw-r--r--spec/factories/user_statuses.rb4
-rw-r--r--spec/factories/users.rb4
-rw-r--r--spec/factories/users/ghost_user_migrations.rb1
-rw-r--r--spec/factories/users/namespace_commit_emails.rb9
-rw-r--r--spec/features/admin/admin_dev_ops_reports_spec.rb4
-rw-r--r--spec/features/admin/admin_hook_logs_spec.rb7
-rw-r--r--spec/features/admin/admin_hooks_spec.rb2
-rw-r--r--spec/features/admin/admin_mode/workers_spec.rb54
-rw-r--r--spec/features/admin/admin_runners_spec.rb15
-rw-r--r--spec/features/admin/admin_settings_spec.rb18
-rw-r--r--spec/features/admin/admin_users_impersonation_tokens_spec.rb31
-rw-r--r--spec/features/admin/users/user_spec.rb79
-rw-r--r--spec/features/admin_variables_spec.rb18
-rw-r--r--spec/features/boards/board_filters_spec.rb5
-rw-r--r--spec/features/boards/boards_spec.rb35
-rw-r--r--spec/features/boards/issue_ordering_spec.rb1
-rw-r--r--spec/features/boards/sidebar_labels_spec.rb1
-rw-r--r--spec/features/boards/sidebar_spec.rb1
-rw-r--r--spec/features/boards/user_adds_lists_to_board_spec.rb6
-rw-r--r--spec/features/boards/user_visits_board_spec.rb5
-rw-r--r--spec/features/broadcast_messages_spec.rb3
-rw-r--r--spec/features/commits_spec.rb4
-rw-r--r--spec/features/cycle_analytics_spec.rb8
-rw-r--r--spec/features/dashboard/datetime_on_tooltips_spec.rb4
-rw-r--r--spec/features/dashboard/projects_spec.rb6
-rw-r--r--spec/features/global_search_spec.rb15
-rw-r--r--spec/features/graphql_known_operations_spec.rb2
-rw-r--r--spec/features/group_variables_spec.rb18
-rw-r--r--spec/features/groups/activity_spec.rb2
-rw-r--r--spec/features/groups/board_sidebar_spec.rb3
-rw-r--r--spec/features/groups/empty_states_spec.rb2
-rw-r--r--spec/features/groups/group_runners_spec.rb46
-rw-r--r--spec/features/groups/group_settings_spec.rb27
-rw-r--r--spec/features/groups/issues_spec.rb12
-rw-r--r--spec/features/groups/milestone_spec.rb2
-rw-r--r--spec/features/groups/milestones_sorting_spec.rb2
-rw-r--r--spec/features/groups/settings/repository_spec.rb23
-rw-r--r--spec/features/help_pages_spec.rb2
-rw-r--r--spec/features/ide/user_opens_merge_request_spec.rb2
-rw-r--r--spec/features/ide_spec.rb95
-rw-r--r--spec/features/incidents/user_views_incident_spec.rb60
-rw-r--r--spec/features/issuables/markdown_references/internal_references_spec.rb18
-rw-r--r--spec/features/issues/confidential_notes_spec.rb13
-rw-r--r--spec/features/issues/filtered_search/dropdown_assignee_spec.rb4
-rw-r--r--spec/features/issues/filtered_search/dropdown_author_spec.rb1
-rw-r--r--spec/features/issues/filtered_search/dropdown_hint_spec.rb1
-rw-r--r--spec/features/issues/filtered_search/filter_issues_spec.rb1
-rw-r--r--spec/features/issues/filtered_search/visual_tokens_spec.rb1
-rw-r--r--spec/features/issues/form_spec.rb23
-rw-r--r--spec/features/issues/user_bulk_edits_issues_labels_spec.rb2
-rw-r--r--spec/features/issues/user_bulk_edits_issues_spec.rb4
-rw-r--r--spec/features/issues/user_comments_on_issue_spec.rb6
-rw-r--r--spec/features/issues/user_creates_issue_spec.rb6
-rw-r--r--spec/features/issues/user_edits_issue_spec.rb33
-rw-r--r--spec/features/issues/user_interacts_with_awards_spec.rb7
-rw-r--r--spec/features/issues/user_sees_empty_state_spec.rb4
-rw-r--r--spec/features/issues/user_sorts_issues_spec.rb2
-rw-r--r--spec/features/jira_connect/subscriptions_spec.rb2
-rw-r--r--spec/features/markdown/sandboxed_mermaid_spec.rb60
-rw-r--r--spec/features/merge_request/user_accepts_merge_request_spec.rb2
-rw-r--r--spec/features/merge_request/user_edits_assignees_sidebar_spec.rb2
-rw-r--r--spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb4
-rw-r--r--spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb2
-rw-r--r--spec/features/merge_request/user_sees_deployment_widget_spec.rb19
-rw-r--r--spec/features/merge_request/user_sees_diff_spec.rb14
-rw-r--r--spec/features/merge_request/user_sees_discussions_navigation_spec.rb222
-rw-r--r--spec/features/merge_request/user_sees_merge_widget_spec.rb141
-rw-r--r--spec/features/merge_requests/user_mass_updates_spec.rb2
-rw-r--r--spec/features/monitor_sidebar_link_spec.rb5
-rw-r--r--spec/features/nav/top_nav_tooltip_spec.rb3
-rw-r--r--spec/features/one_trust_spec.rb2
-rw-r--r--spec/features/profile_spec.rb41
-rw-r--r--spec/features/profiles/password_spec.rb44
-rw-r--r--spec/features/profiles/personal_access_tokens_spec.rb39
-rw-r--r--spec/features/profiles/two_factor_auths_spec.rb2
-rw-r--r--spec/features/project_variables_spec.rb63
-rw-r--r--spec/features/projects/branches/user_views_branches_spec.rb2
-rw-r--r--spec/features/projects/branches_spec.rb42
-rw-r--r--spec/features/projects/container_registry_spec.rb5
-rw-r--r--spec/features/projects/environments/environment_spec.rb28
-rw-r--r--spec/features/projects/environments/environments_spec.rb5
-rw-r--r--spec/features/projects/fork_spec.rb4
-rw-r--r--spec/features/projects/import_export/import_file_spec.rb2
-rw-r--r--spec/features/projects/integrations/user_activates_issue_tracker_spec.rb2
-rw-r--r--spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb10
-rw-r--r--spec/features/projects/jobs/permissions_spec.rb44
-rw-r--r--spec/features/projects/jobs/user_browses_jobs_spec.rb6
-rw-r--r--spec/features/projects/jobs_spec.rb4
-rw-r--r--spec/features/projects/members/manage_members_spec.rb2
-rw-r--r--spec/features/projects/network_graph_spec.rb138
-rw-r--r--spec/features/projects/pipeline_schedules_spec.rb10
-rw-r--r--spec/features/projects/pipelines/legacy_pipeline_spec.rb7
-rw-r--r--spec/features/projects/pipelines/legacy_pipelines_spec.rb1
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb52
-rw-r--r--spec/features/projects/pipelines/pipelines_spec.rb5
-rw-r--r--spec/features/projects/product_analytics/events_spec.rb30
-rw-r--r--spec/features/projects/product_analytics/graphs_spec.rb25
-rw-r--r--spec/features/projects/product_analytics/setup_spec.rb19
-rw-r--r--spec/features/projects/product_analytics/test_spec.rb27
-rw-r--r--spec/features/projects/releases/user_views_edit_release_spec.rb2
-rw-r--r--spec/features/projects/releases/user_views_releases_spec.rb2
-rw-r--r--spec/features/projects/settings/branch_names_settings_spec.rb48
-rw-r--r--spec/features/projects/settings/repository_settings_spec.rb1
-rw-r--r--spec/features/projects/settings/user_changes_default_branch_spec.rb4
-rw-r--r--spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb1
-rw-r--r--spec/features/projects/settings/webhooks_settings_spec.rb51
-rw-r--r--spec/features/projects/user_changes_project_visibility_spec.rb3
-rw-r--r--spec/features/search/user_searches_for_code_spec.rb323
-rw-r--r--spec/features/search/user_searches_for_comments_spec.rb61
-rw-r--r--spec/features/search/user_searches_for_commits_spec.rb74
-rw-r--r--spec/features/search/user_searches_for_issues_spec.rb177
-rw-r--r--spec/features/search/user_searches_for_merge_requests_spec.rb84
-rw-r--r--spec/features/search/user_searches_for_milestones_spec.rb67
-rw-r--r--spec/features/search/user_searches_for_projects_spec.rb5
-rw-r--r--spec/features/search/user_searches_for_users_spec.rb118
-rw-r--r--spec/features/search/user_searches_for_wiki_pages_spec.rb70
-rw-r--r--spec/features/search/user_uses_header_search_field_spec.rb6
-rw-r--r--spec/features/snippets/search_snippets_spec.rb6
-rw-r--r--spec/features/user_sees_marketing_header_spec.rb52
-rw-r--r--spec/features/users/active_sessions_spec.rb4
-rw-r--r--spec/features/work_items/work_item_children_spec.rb30
-rw-r--r--spec/finders/autocomplete/users_finder_spec.rb49
-rw-r--r--spec/finders/branches_finder_spec.rb2
-rw-r--r--spec/finders/clusters/agent_authorizations_finder_spec.rb16
-rw-r--r--spec/finders/clusters/agent_tokens_finder_spec.rb48
-rw-r--r--spec/finders/incident_management/timeline_event_tags_finder_spec.rb58
-rw-r--r--spec/finders/projects_finder_spec.rb46
-rw-r--r--spec/finders/users_star_projects_finder_spec.rb10
-rw-r--r--spec/fixtures/api/schemas/entities/codequality_degradation.json5
-rw-r--r--spec/fixtures/api/schemas/entities/codequality_reports_comparer.json16
-rw-r--r--spec/fixtures/api/schemas/entities/protected_ref_access.json25
-rw-r--r--spec/fixtures/api/schemas/graphql/packages/package_details.json12
-rw-r--r--spec/fixtures/api/schemas/ml/run.json46
-rw-r--r--spec/fixtures/api/schemas/pipeline_schedule_variable.json17
-rw-r--r--spec/fixtures/api/schemas/project_mirror.json48
-rw-r--r--spec/fixtures/api/schemas/protected_branch.json33
-rw-r--r--spec/fixtures/api/schemas/protected_branches.json6
-rw-r--r--spec/fixtures/api/schemas/protected_tag.json19
-rw-r--r--spec/fixtures/api/schemas/protected_tags.json6
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/metadata.json34
-rw-r--r--spec/fixtures/gitlab/import_export/project.tar.gzbin0 -> 1113 bytes
-rw-r--r--spec/fixtures/gitlab/import_export/uploads.tar.gzbin0 -> 1843 bytes
-rw-r--r--spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric.yml2
-rw-r--r--spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_ee.yml2
-rw-r--r--spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_name_suggestions.yml2
-rw-r--r--spec/fixtures/lib/gitlab/import_export/complex/project.json2
-rw-r--r--spec/fixtures/lib/gitlab/import_export/complex/tree/project/ci_pipelines.ndjson2
-rw-r--r--spec/fixtures/lib/sbom/package-url-test-cases.json502
-rw-r--r--spec/fixtures/markdown/markdown_golden_master_examples.yml14
-rw-r--r--spec/fixtures/packages/rpm/payload.json18
-rw-r--r--spec/fixtures/packages/rpm/repodata/364c77dd49e8f814d56e621d0b3306c4fd0696dcad506f527329b818eb0f5db3-repomd.xml30
-rw-r--r--spec/fixtures/packages/rpm/repodata/repomd.xml27
-rw-r--r--spec/frontend/__helpers__/raw_transformer.js6
-rw-r--r--spec/frontend/access_tokens/components/__snapshots__/expires_at_field_spec.js.snap1
-rw-r--r--spec/frontend/access_tokens/components/new_access_token_app_spec.js1
-rw-r--r--spec/frontend/admin/signup_restrictions/components/signup_form_spec.js18
-rw-r--r--spec/frontend/admin/signup_restrictions/mock_data.js6
-rw-r--r--spec/frontend/admin/users/components/actions/actions_spec.js57
-rw-r--r--spec/frontend/admin/users/components/actions/delete_with_contributions_spec.js107
-rw-r--r--spec/frontend/admin/users/components/associations/__snapshots__/associations_list_item_spec.js.snap3
-rw-r--r--spec/frontend/admin/users/components/associations/__snapshots__/associations_list_spec.js.snap34
-rw-r--r--spec/frontend/admin/users/components/associations/associations_list_item_spec.js25
-rw-r--r--spec/frontend/admin/users/components/associations/associations_list_spec.js78
-rw-r--r--spec/frontend/admin/users/components/modals/delete_user_modal_spec.js22
-rw-r--r--spec/frontend/admin/users/components/user_actions_spec.js7
-rw-r--r--spec/frontend/admin/users/mock_data.js14
-rw-r--r--spec/frontend/analytics/shared/components/daterange_spec.js2
-rw-r--r--spec/frontend/api/groups_api_spec.js27
-rw-r--r--spec/frontend/api/user_api_spec.js17
-rw-r--r--spec/frontend/artifacts/components/artifact_row_spec.js67
-rw-r--r--spec/frontend/artifacts/components/artifacts_table_row_details_spec.js122
-rw-r--r--spec/frontend/artifacts/components/job_artifacts_table_spec.js341
-rw-r--r--spec/frontend/artifacts/graphql/cache_update_spec.js67
-rw-r--r--spec/frontend/behaviors/markdown/render_sandboxed_mermaid_spec.js145
-rw-r--r--spec/frontend/blob/blob_blame_link_spec.js12
-rw-r--r--spec/frontend/blob/components/__snapshots__/blob_edit_content_spec.js.snap18
-rw-r--r--spec/frontend/blob/components/blob_edit_content_spec.js105
-rw-r--r--spec/frontend/blob/utils_spec.js62
-rw-r--r--spec/frontend/blob_edit/edit_blob_spec.js48
-rw-r--r--spec/frontend/boards/board_card_inner_spec.js241
-rw-r--r--spec/frontend/boards/board_list_helper.js2
-rw-r--r--spec/frontend/boards/board_list_spec.js6
-rw-r--r--spec/frontend/boards/components/board_add_new_column_spec.js2
-rw-r--r--spec/frontend/boards/components/board_app_spec.js1
-rw-r--r--spec/frontend/boards/components/board_card_move_to_position_spec.js1
-rw-r--r--spec/frontend/boards/components/board_card_spec.js2
-rw-r--r--spec/frontend/boards/components/board_content_spec.js84
-rw-r--r--spec/frontend/boards/components/board_filtered_search_spec.js44
-rw-r--r--spec/frontend/boards/components/board_list_header_spec.js2
-rw-r--r--spec/frontend/boards/components/board_settings_sidebar_spec.js1
-rw-r--r--spec/frontend/boards/components/board_top_bar_spec.js11
-rw-r--r--spec/frontend/boards/mock_data.js81
-rw-r--r--spec/frontend/boards/stores/actions_spec.js18
-rw-r--r--spec/frontend/branches/components/__snapshots__/delete_merged_branches_spec.js.snap139
-rw-r--r--spec/frontend/branches/components/delete_merged_branches_spec.js143
-rw-r--r--spec/frontend/branches/mock_data.js7
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/delete_pipeline_schedule_modal_spec.js38
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js25
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js280
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js64
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js42
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js43
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js40
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js41
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js39
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js44
-rw-r--r--spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_spec.js40
-rw-r--r--spec/frontend/ci/pipeline_schedules/mock_data.js62
-rw-r--r--spec/frontend/ci/runner/admin_runner_show/admin_runner_show_app_spec.js266
-rw-r--r--spec/frontend/ci/runner/admin_runners/admin_runners_app_spec.js473
-rw-r--r--spec/frontend/ci/runner/components/__snapshots__/runner_status_popover_spec.js.snap (renamed from spec/frontend/runner/components/__snapshots__/runner_status_popover_spec.js.snap)0
-rw-r--r--spec/frontend/ci/runner/components/cells/link_cell_spec.js72
-rw-r--r--spec/frontend/ci/runner/components/cells/runner_actions_cell_spec.js138
-rw-r--r--spec/frontend/ci/runner/components/cells/runner_owner_cell_spec.js111
-rw-r--r--spec/frontend/ci/runner/components/cells/runner_stacked_summary_cell_spec.js164
-rw-r--r--spec/frontend/ci/runner/components/cells/runner_status_cell_spec.js77
-rw-r--r--spec/frontend/ci/runner/components/cells/runner_summary_field_spec.js49
-rw-r--r--spec/frontend/ci/runner/components/registration/registration_dropdown_spec.js198
-rw-r--r--spec/frontend/ci/runner/components/registration/registration_token_reset_dropdown_item_spec.js209
-rw-r--r--spec/frontend/ci/runner/components/registration/registration_token_spec.js62
-rw-r--r--spec/frontend/ci/runner/components/runner_assigned_item_spec.js68
-rw-r--r--spec/frontend/ci/runner/components/runner_bulk_delete_checkbox_spec.js140
-rw-r--r--spec/frontend/ci/runner/components/runner_bulk_delete_spec.js295
-rw-r--r--spec/frontend/ci/runner/components/runner_delete_button_spec.js275
-rw-r--r--spec/frontend/ci/runner/components/runner_delete_modal_spec.js60
-rw-r--r--spec/frontend/ci/runner/components/runner_details_spec.js130
-rw-r--r--spec/frontend/ci/runner/components/runner_edit_button_spec.js41
-rw-r--r--spec/frontend/ci/runner/components/runner_filtered_search_bar_spec.js188
-rw-r--r--spec/frontend/ci/runner/components/runner_groups_spec.js67
-rw-r--r--spec/frontend/ci/runner/components/runner_header_spec.js124
-rw-r--r--spec/frontend/ci/runner/components/runner_jobs_spec.js155
-rw-r--r--spec/frontend/ci/runner/components/runner_jobs_table_spec.js137
-rw-r--r--spec/frontend/ci/runner/components/runner_list_empty_state_spec.js103
-rw-r--r--spec/frontend/ci/runner/components/runner_list_spec.js231
-rw-r--r--spec/frontend/ci/runner/components/runner_membership_toggle_spec.js57
-rw-r--r--spec/frontend/ci/runner/components/runner_pagination_spec.js115
-rw-r--r--spec/frontend/ci/runner/components/runner_pause_button_spec.js263
-rw-r--r--spec/frontend/ci/runner/components/runner_paused_badge_spec.js46
-rw-r--r--spec/frontend/ci/runner/components/runner_projects_spec.js251
-rw-r--r--spec/frontend/ci/runner/components/runner_status_badge_spec.js133
-rw-r--r--spec/frontend/ci/runner/components/runner_status_popover_spec.js36
-rw-r--r--spec/frontend/ci/runner/components/runner_tag_spec.js79
-rw-r--r--spec/frontend/ci/runner/components/runner_tags_spec.js54
-rw-r--r--spec/frontend/ci/runner/components/runner_type_badge_spec.js66
-rw-r--r--spec/frontend/ci/runner/components/runner_type_tabs_spec.js214
-rw-r--r--spec/frontend/ci/runner/components/runner_update_form_spec.js288
-rw-r--r--spec/frontend/ci/runner/components/search_tokens/tag_token_spec.js208
-rw-r--r--spec/frontend/ci/runner/components/stat/runner_count_spec.js148
-rw-r--r--spec/frontend/ci/runner/components/stat/runner_single_stat_spec.js61
-rw-r--r--spec/frontend/ci/runner/components/stat/runner_stats_spec.js81
-rw-r--r--spec/frontend/ci/runner/graphql/local_state_spec.js167
-rw-r--r--spec/frontend/ci/runner/group_runner_show/group_runner_show_app_spec.js215
-rw-r--r--spec/frontend/ci/runner/group_runners/group_runners_app_spec.js492
-rw-r--r--spec/frontend/ci/runner/local_storage_alert/save_alert_to_local_storage_spec.js24
-rw-r--r--spec/frontend/ci/runner/local_storage_alert/show_alert_from_local_storage_spec.js40
-rw-r--r--spec/frontend/ci/runner/mock_data.js322
-rw-r--r--spec/frontend/ci/runner/runner_edit/runner_edit_app_spec.js114
-rw-r--r--spec/frontend/ci/runner/runner_search_utils_spec.js138
-rw-r--r--spec/frontend/ci/runner/runner_update_form_utils_spec.js96
-rw-r--r--spec/frontend/ci/runner/sentry_utils_spec.js39
-rw-r--r--spec/frontend/ci/runner/utils_spec.js85
-rw-r--r--spec/frontend/ci_variable_list/components/ci_admin_variables_spec.js175
-rw-r--r--spec/frontend/ci_variable_list/components/ci_group_variables_spec.js181
-rw-r--r--spec/frontend/ci_variable_list/components/ci_project_variables_spec.js202
-rw-r--r--spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js90
-rw-r--r--spec/frontend/ci_variable_list/components/ci_variable_popover_spec.js48
-rw-r--r--spec/frontend/ci_variable_list/components/ci_variable_settings_spec.js2
-rw-r--r--spec/frontend/ci_variable_list/components/ci_variable_shared_spec.js428
-rw-r--r--spec/frontend/ci_variable_list/components/legacy_ci_environments_dropdown_spec.js119
-rw-r--r--spec/frontend/ci_variable_list/components/legacy_ci_variable_modal_spec.js323
-rw-r--r--spec/frontend/ci_variable_list/components/legacy_ci_variable_settings_spec.js38
-rw-r--r--spec/frontend/ci_variable_list/components/legacy_ci_variable_table_spec.js86
-rw-r--r--spec/frontend/ci_variable_list/mocks.js77
-rw-r--r--spec/frontend/ci_variable_list/store/actions_spec.js319
-rw-r--r--spec/frontend/ci_variable_list/store/getters_spec.js21
-rw-r--r--spec/frontend/ci_variable_list/store/mutations_spec.js136
-rw-r--r--spec/frontend/ci_variable_list/store/utils_spec.js49
-rw-r--r--spec/frontend/content_editor/components/bubble_menus/formatting_bubble_menu_spec.js1
-rw-r--r--spec/frontend/content_editor/markdown_snapshot_spec.js9
-rw-r--r--spec/frontend/content_editor/markdown_snapshot_spec_helper.js26
-rw-r--r--spec/frontend/content_editor/render_html_and_json_for_all_examples.js83
-rw-r--r--spec/frontend/content_editor/services/markdown_serializer_spec.js55
-rw-r--r--spec/frontend/content_editor/test_utils.js85
-rw-r--r--spec/frontend/deploy_tokens/components/new_deploy_token_spec.js67
-rw-r--r--spec/frontend/deprecated_jquery_dropdown_spec.js14
-rw-r--r--spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap4
-rw-r--r--spec/frontend/diffs/components/diff_row_utils_spec.js56
-rw-r--r--spec/frontend/diffs/mock_data/diff_file.js30
-rw-r--r--spec/frontend/diffs/store/actions_spec.js38
-rw-r--r--spec/frontend/diffs/store/utils_spec.js54
-rw-r--r--spec/frontend/diffs/utils/tree_worker_utils_spec.js64
-rw-r--r--spec/frontend/editor/schema/ci/ci_schema_spec.js71
-rw-r--r--spec/frontend/editor/schema/ci/json_tests/negative_tests/default_no_additional_properties.json2
-rw-r--r--spec/frontend/editor/schema/ci/json_tests/negative_tests/inherit_default_no_additional_properties.json6
-rw-r--r--spec/frontend/editor/schema/ci/json_tests/negative_tests/job_variables_must_not_contain_objects.json6
-rw-r--r--spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links.json44
-rw-r--r--spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links_empty.json13
-rw-r--r--spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links_invalid_link_type.json24
-rw-r--r--spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links_missing.json11
-rw-r--r--spec/frontend/editor/schema/ci/json_tests/negative_tests/retry_unknown_when.json2
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/cache.yml63
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/include.yml3
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/job_when.yml11
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/empty.yml5
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/invalid_variable.yml5
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/leading_slash.yml5
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/no_slash.yml5
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/tailing_slash.yml5
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/empty.yml2
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/invalid_variable.yml2
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/leading_slash.yml2
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/no_slash.yml2
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/tailing_slash.yml2
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/empty.yml3
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/invalid_variable.yml3
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/leading_slash.yml3
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/no_slash.yml3
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/tailing_slash.yml3
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/trigger.yml64
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/variables.yml5
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/variables/invalid_syntax_desc.yml4
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/variables/wrong_syntax_usage_expand.yml4
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/positive_tests/cache.yml112
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/positive_tests/job_when.yml10
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/positive_tests/variables.yml10
-rw-r--r--spec/frontend/editor/source_editor_markdown_livepreview_ext_spec.js9
-rw-r--r--spec/frontend/environments/environment_actions_spec.js6
-rw-r--r--spec/frontend/environments/environment_rollback_spec.js2
-rw-r--r--spec/frontend/environments/graphql/mock_data.js1
-rw-r--r--spec/frontend/filtered_search/droplab/plugins/ajax_filter_spec.js7
-rw-r--r--spec/frontend/fixtures/api_merge_requests.rb2
-rw-r--r--spec/frontend/fixtures/api_projects.rb2
-rw-r--r--spec/frontend/fixtures/application_settings.rb2
-rw-r--r--spec/frontend/fixtures/blob.rb2
-rw-r--r--spec/frontend/fixtures/branches.rb2
-rw-r--r--spec/frontend/fixtures/clusters.rb2
-rw-r--r--spec/frontend/fixtures/deploy_keys.rb2
-rw-r--r--spec/frontend/fixtures/freeze_period.rb2
-rw-r--r--spec/frontend/fixtures/integrations.rb2
-rw-r--r--spec/frontend/fixtures/issues.rb2
-rw-r--r--spec/frontend/fixtures/job_artifacts.rb28
-rw-r--r--spec/frontend/fixtures/jobs.rb2
-rw-r--r--spec/frontend/fixtures/labels.rb2
-rw-r--r--spec/frontend/fixtures/merge_requests.rb16
-rw-r--r--spec/frontend/fixtures/merge_requests_diffs.rb2
-rw-r--r--spec/frontend/fixtures/metrics_dashboard.rb2
-rw-r--r--spec/frontend/fixtures/namespaces.rb20
-rw-r--r--spec/frontend/fixtures/pipeline_schedules.rb13
-rw-r--r--spec/frontend/fixtures/pipelines.rb2
-rw-r--r--spec/frontend/fixtures/projects.rb2
-rw-r--r--spec/frontend/fixtures/prometheus_integration.rb2
-rw-r--r--spec/frontend/fixtures/raw.rb2
-rw-r--r--spec/frontend/fixtures/runner.rb4
-rw-r--r--spec/frontend/fixtures/snippet.rb2
-rw-r--r--spec/frontend/fixtures/static/gl_field_errors.html3
-rw-r--r--spec/frontend/fixtures/todos.rb2
-rw-r--r--spec/frontend/flash_spec.js14
-rw-r--r--spec/frontend/gfm_auto_complete/mock_data.js57
-rw-r--r--spec/frontend/gfm_auto_complete_spec.js95
-rw-r--r--spec/frontend/gitlab_version_check/components/gitlab_version_check_badge_spec.js102
-rw-r--r--spec/frontend/gitlab_version_check/index_spec.js116
-rw-r--r--spec/frontend/gl_field_errors_spec.js2
-rw-r--r--spec/frontend/google_cloud/service_accounts/list_spec.js29
-rw-r--r--spec/frontend/groups/components/overview_tabs_spec.js48
-rw-r--r--spec/frontend/groups/components/transfer_group_form_spec.js56
-rw-r--r--spec/frontend/groups_projects/components/transfer_locations_spec.js377
-rw-r--r--spec/frontend/ide/components/ide_spec.js31
-rw-r--r--spec/frontend/ide/components/panes/collapsible_sidebar_spec.js26
-rw-r--r--spec/frontend/ide/components/panes/right_spec.js45
-rw-r--r--spec/frontend/ide/components/switch_editors/switch_editors_view_spec.js214
-rw-r--r--spec/frontend/ide/stores/mutations_spec.js2
-rw-r--r--spec/frontend/import_entities/import_groups/components/import_table_spec.js27
-rw-r--r--spec/frontend/integrations/edit/components/integration_form_spec.js86
-rw-r--r--spec/frontend/integrations/edit/components/trigger_fields_spec.js45
-rw-r--r--spec/frontend/invite_members/components/invite_members_modal_spec.js76
-rw-r--r--spec/frontend/invite_members/components/invite_modal_base_spec.js57
-rw-r--r--spec/frontend/invite_members/components/user_limit_notification_spec.js60
-rw-r--r--spec/frontend/invite_members/mock_data/member_modal.js2
-rw-r--r--spec/frontend/issuable/bulk_update_sidebar/components/move_issues_button_spec.js554
-rw-r--r--spec/frontend/issuable/related_issues/components/related_issues_block_spec.js48
-rw-r--r--spec/frontend/issuable/related_issues/components/related_issues_root_spec.js8
-rw-r--r--spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js58
-rw-r--r--spec/frontend/issues/list/components/issues_list_app_spec.js86
-rw-r--r--spec/frontend/issues/list/mock_data.js117
-rw-r--r--spec/frontend/issues/show/components/fields/description_spec.js2
-rw-r--r--spec/frontend/issues/show/components/incidents/timeline_events_form_spec.js30
-rw-r--r--spec/frontend/jobs/components/job/legacy_sidebar_header_spec.js20
-rw-r--r--spec/frontend/jobs/components/job/sidebar_spec.js72
-rw-r--r--spec/frontend/jobs/mock_data.js24
-rw-r--r--spec/frontend/lib/utils/common_utils_spec.js39
-rw-r--r--spec/frontend/lib/utils/confirm_via_gl_modal/confirm_action_spec.js103
-rw-r--r--spec/frontend/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal_spec.js80
-rw-r--r--spec/frontend/lib/utils/datetime/date_calculation_utility_spec.js37
-rw-r--r--spec/frontend/lib/utils/dom_utils_spec.js28
-rw-r--r--spec/frontend/lib/utils/unit_format/index_spec.js6
-rw-r--r--spec/frontend/members/components/action_buttons/access_request_action_buttons_spec.js90
-rw-r--r--spec/frontend/members/components/members_tabs_spec.js5
-rw-r--r--spec/frontend/ml/experiment_tracking/components/__snapshots__/experiment_spec.js.snap223
-rw-r--r--spec/frontend/ml/experiment_tracking/components/experiment_spec.js44
-rw-r--r--spec/frontend/ml/experiment_tracking/components/incubation_alert_spec.js27
-rw-r--r--spec/frontend/notebook/cells/markdown_spec.js101
-rw-r--r--spec/frontend/notebook/cells/output/index_spec.js14
-rw-r--r--spec/frontend/notebook/cells/output/markdown_spec.js44
-rw-r--r--spec/frontend/notebook/mock_data.js2
-rw-r--r--spec/frontend/notes/components/__snapshots__/notes_app_spec.js.snap4
-rw-r--r--spec/frontend/notes/components/note_actions_spec.js74
-rw-r--r--spec/frontend/notes/components/note_header_spec.js2
-rw-r--r--spec/frontend/notes/mixins/discussion_navigation_spec.js2
-rw-r--r--spec/frontend/notes/stores/getters_spec.js22
-rw-r--r--spec/frontend/observability/observability_app_spec.js73
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/image_list_row_spec.js60
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/list_page/registry_header_spec.js6
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/pages/details_spec.js24
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_spec.js57
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js71
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/details/package_versions_list_spec.js152
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/package_list_row_spec.js.snap9
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/list/package_list_row_spec.js43
-rw-r--r--spec/frontend/packages_and_registries/package_registry/components/list/packages_list_spec.js104
-rw-r--r--spec/frontend/packages_and_registries/package_registry/mock_data.js34
-rw-r--r--spec/frontend/packages_and_registries/package_registry/pages/__snapshots__/list_spec.js.snap54
-rw-r--r--spec/frontend/packages_and_registries/package_registry/pages/details_spec.js33
-rw-r--r--spec/frontend/packages_and_registries/package_registry/pages/list_spec.js158
-rw-r--r--spec/frontend/packages_and_registries/settings/group/components/forwarding_settings_spec.js78
-rw-r--r--spec/frontend/packages_and_registries/settings/group/components/group_settings_app_spec.js17
-rw-r--r--spec/frontend/packages_and_registries/settings/group/components/package_settings_spec.js14
-rw-r--r--spec/frontend/packages_and_registries/settings/group/components/packages_forwarding_settings_spec.js280
-rw-r--r--spec/frontend/packages_and_registries/settings/group/mock_data.js75
-rw-r--r--spec/frontend/packages_and_registries/shared/components/delete_package_modal_spec.js82
-rw-r--r--spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_spec.js.snap7
-rw-r--r--spec/frontend/pages/projects/pipeline_schedules/shared/components/timezone_dropdown_spec.js134
-rw-r--r--spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js20
-rw-r--r--spec/frontend/pages/shared/wikis/components/wiki_form_spec.js2
-rw-r--r--spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js2
-rw-r--r--spec/frontend/pipeline_schedules/components/pipeline_schedules_form_spec.js25
-rw-r--r--spec/frontend/pipeline_schedules/components/pipeline_schedules_spec.js161
-rw-r--r--spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js49
-rw-r--r--spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js42
-rw-r--r--spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js43
-rw-r--r--spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js40
-rw-r--r--spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js41
-rw-r--r--spec/frontend/pipeline_schedules/components/table/pipeline_schedules_table_spec.js39
-rw-r--r--spec/frontend/pipeline_schedules/components/take_ownership_modal_spec.js54
-rw-r--r--spec/frontend/pipeline_schedules/mock_data.js35
-rw-r--r--spec/frontend/pipelines/components/pipeline_tabs_spec.js26
-rw-r--r--spec/frontend/pipelines/mock_data.js4
-rw-r--r--spec/frontend/pipelines/pipeline_graph/utils_spec.js17
-rw-r--r--spec/frontend/pipelines/pipeline_tabs_spec.js32
-rw-r--r--spec/frontend/pipelines/pipeline_url_spec.js16
-rw-r--r--spec/frontend/pipelines/pipelines_actions_spec.js6
-rw-r--r--spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap2
-rw-r--r--spec/frontend/projects/components/shared/__snapshots__/delete_button_spec.js.snap2
-rw-r--r--spec/frontend/projects/new/components/new_project_push_tip_popover_spec.js2
-rw-r--r--spec/frontend/projects/pipelines/charts/components/app_spec.js68
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/view/index_spec.js24
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/view/mock_data.js47
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/view/protection_row_spec.js5
-rw-r--r--spec/frontend/projects/settings/branch_rules/components/view/protection_spec.js11
-rw-r--r--spec/frontend/projects/settings/components/transfer_project_form_spec.js268
-rw-r--r--spec/frontend/projects/settings/repository/branch_rules/app_spec.js4
-rw-r--r--spec/frontend/projects/settings/repository/branch_rules/components/branch_rule_spec.js37
-rw-r--r--spec/frontend/projects/settings/repository/branch_rules/mock_data.js45
-rw-r--r--spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js20
-rw-r--r--spec/frontend/releases/components/asset_links_form_spec.js42
-rw-r--r--spec/frontend/reports/codequality_report/grouped_codequality_reports_app_spec.js151
-rw-r--r--spec/frontend/reports/codequality_report/store/actions_spec.js1
-rw-r--r--spec/frontend/reports/components/__snapshots__/grouped_issues_list_spec.js.snap2
-rw-r--r--spec/frontend/reports/components/grouped_issues_list_spec.js2
-rw-r--r--spec/frontend/reports/components/report_item_spec.js4
-rw-r--r--spec/frontend/reports/grouped_test_report/components/modal_spec.js68
-rw-r--r--spec/frontend/reports/grouped_test_report/components/test_issue_body_spec.js96
-rw-r--r--spec/frontend/reports/grouped_test_report/grouped_test_reports_app_spec.js355
-rw-r--r--spec/frontend/reports/grouped_test_report/store/actions_spec.js168
-rw-r--r--spec/frontend/reports/grouped_test_report/store/mutations_spec.js162
-rw-r--r--spec/frontend/reports/grouped_test_report/store/utils_spec.js255
-rw-r--r--spec/frontend/runner/admin_runner_show/admin_runner_show_app_spec.js266
-rw-r--r--spec/frontend/runner/admin_runners/admin_runners_app_spec.js480
-rw-r--r--spec/frontend/runner/components/cells/link_cell_spec.js72
-rw-r--r--spec/frontend/runner/components/cells/runner_actions_cell_spec.js138
-rw-r--r--spec/frontend/runner/components/cells/runner_owner_cell_spec.js111
-rw-r--r--spec/frontend/runner/components/cells/runner_stacked_summary_cell_spec.js164
-rw-r--r--spec/frontend/runner/components/cells/runner_status_cell_spec.js77
-rw-r--r--spec/frontend/runner/components/cells/runner_summary_field_spec.js49
-rw-r--r--spec/frontend/runner/components/registration/registration_dropdown_spec.js198
-rw-r--r--spec/frontend/runner/components/registration/registration_token_reset_dropdown_item_spec.js209
-rw-r--r--spec/frontend/runner/components/registration/registration_token_spec.js62
-rw-r--r--spec/frontend/runner/components/runner_assigned_item_spec.js68
-rw-r--r--spec/frontend/runner/components/runner_bulk_delete_checkbox_spec.js140
-rw-r--r--spec/frontend/runner/components/runner_bulk_delete_spec.js243
-rw-r--r--spec/frontend/runner/components/runner_delete_button_spec.js266
-rw-r--r--spec/frontend/runner/components/runner_delete_modal_spec.js60
-rw-r--r--spec/frontend/runner/components/runner_details_spec.js130
-rw-r--r--spec/frontend/runner/components/runner_edit_button_spec.js41
-rw-r--r--spec/frontend/runner/components/runner_filtered_search_bar_spec.js188
-rw-r--r--spec/frontend/runner/components/runner_groups_spec.js67
-rw-r--r--spec/frontend/runner/components/runner_header_spec.js119
-rw-r--r--spec/frontend/runner/components/runner_jobs_spec.js155
-rw-r--r--spec/frontend/runner/components/runner_jobs_table_spec.js119
-rw-r--r--spec/frontend/runner/components/runner_list_empty_state_spec.js103
-rw-r--r--spec/frontend/runner/components/runner_list_spec.js231
-rw-r--r--spec/frontend/runner/components/runner_membership_toggle_spec.js57
-rw-r--r--spec/frontend/runner/components/runner_pagination_spec.js115
-rw-r--r--spec/frontend/runner/components/runner_pause_button_spec.js263
-rw-r--r--spec/frontend/runner/components/runner_paused_badge_spec.js46
-rw-r--r--spec/frontend/runner/components/runner_projects_spec.js251
-rw-r--r--spec/frontend/runner/components/runner_stacked_layout_banner_spec.js41
-rw-r--r--spec/frontend/runner/components/runner_status_badge_spec.js133
-rw-r--r--spec/frontend/runner/components/runner_status_popover_spec.js36
-rw-r--r--spec/frontend/runner/components/runner_tag_spec.js79
-rw-r--r--spec/frontend/runner/components/runner_tags_spec.js54
-rw-r--r--spec/frontend/runner/components/runner_type_badge_spec.js66
-rw-r--r--spec/frontend/runner/components/runner_type_tabs_spec.js214
-rw-r--r--spec/frontend/runner/components/runner_update_form_spec.js288
-rw-r--r--spec/frontend/runner/components/search_tokens/tag_token_spec.js208
-rw-r--r--spec/frontend/runner/components/stat/runner_count_spec.js148
-rw-r--r--spec/frontend/runner/components/stat/runner_single_stat_spec.js61
-rw-r--r--spec/frontend/runner/components/stat/runner_stats_spec.js81
-rw-r--r--spec/frontend/runner/graphql/local_state_spec.js167
-rw-r--r--spec/frontend/runner/group_runner_show/group_runner_show_app_spec.js215
-rw-r--r--spec/frontend/runner/group_runners/group_runners_app_spec.js499
-rw-r--r--spec/frontend/runner/local_storage_alert/save_alert_to_local_storage_spec.js24
-rw-r--r--spec/frontend/runner/local_storage_alert/show_alert_from_local_storage_spec.js40
-rw-r--r--spec/frontend/runner/mock_data.js322
-rw-r--r--spec/frontend/runner/runner_edit/runner_edit_app_spec.js114
-rw-r--r--spec/frontend/runner/runner_search_utils_spec.js138
-rw-r--r--spec/frontend/runner/runner_update_form_utils_spec.js93
-rw-r--r--spec/frontend/runner/sentry_utils_spec.js39
-rw-r--r--spec/frontend/runner/utils_spec.js80
-rw-r--r--spec/frontend/search/mock_data.js84
-rw-r--r--spec/frontend/search/sidebar/components/app_spec.js120
-rw-r--r--spec/frontend/search/sidebar/components/filters_spec.js132
-rw-r--r--spec/frontend/search/sidebar/components/scope_navigation_spec.js80
-rw-r--r--spec/frontend/search/store/actions_spec.js35
-rw-r--r--spec/frontend/search/store/mutations_spec.js22
-rw-r--r--spec/frontend/self_monitor/components/__snapshots__/self_monitor_form_spec.js.snap16
-rw-r--r--spec/frontend/self_monitor/components/self_monitor_form_spec.js10
-rw-r--r--spec/frontend/self_monitor/store/actions_spec.js6
-rw-r--r--spec/frontend/self_monitor/store/mutations_spec.js2
-rw-r--r--spec/frontend/sidebar/components/milestone/milestone_dropdown_spec.js93
-rw-r--r--spec/frontend/sidebar/components/reviewers/sidebar_reviewers_inputs_spec.js36
-rw-r--r--spec/frontend/sidebar/components/sidebar_dropdown_spec.js285
-rw-r--r--spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js202
-rw-r--r--spec/frontend/token_access/mock_data.js12
-rw-r--r--spec/frontend/token_access/token_access_spec.js7
-rw-r--r--spec/frontend/token_access/token_projects_table_spec.js13
-rw-r--r--spec/frontend/users_select/utils_spec.js13
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_container_spec.js2
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js2
-rw-r--r--spec/frontend/vue_merge_request_widget/components/mr_widget_rebase_spec.js425
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap202
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/merge_checks_failed_spec.js8
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled_spec.js182
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed_spec.js60
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_conflicts_spec.js342
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_missing_branch_spec.js43
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_ready_to_merge_spec.js70
-rw-r--r--spec/frontend/vue_merge_request_widget/components/states/mr_widget_wip_spec.js109
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap6
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/dynamic_content_spec.js4
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/widget_content_row_spec.js37
-rw-r--r--spec/frontend/vue_merge_request_widget/components/widget/widget_spec.js129
-rw-r--r--spec/frontend/vue_merge_request_widget/deployment/deployment_actions_spec.js6
-rw-r--r--spec/frontend/vue_merge_request_widget/deployment/deployment_info_spec.js42
-rw-r--r--spec/frontend/vue_merge_request_widget/mr_widget_options_spec.js72
-rw-r--r--spec/frontend/vue_merge_request_widget/stores/mr_widget_store_spec.js13
-rw-r--r--spec/frontend/vue_shared/alert_details/alert_details_spec.js4
-rw-r--r--spec/frontend/vue_shared/alert_details/router_spec.js35
-rw-r--r--spec/frontend/vue_shared/components/file_row_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/gitlab_version_check_spec.js135
-rw-r--r--spec/frontend/vue_shared/components/group_select/group_select_spec.js202
-rw-r--r--spec/frontend/vue_shared/components/help_popover_spec.js14
-rw-r--r--spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js29
-rw-r--r--spec/frontend/vue_shared/components/markdown_drawer/markdown_drawer_spec.js205
-rw-r--r--spec/frontend/vue_shared/components/markdown_drawer/mock_data.js42
-rw-r--r--spec/frontend/vue_shared/components/markdown_drawer/utils/fetch_spec.js43
-rw-r--r--spec/frontend/vue_shared/components/namespace_select/mock_data.js6
-rw-r--r--spec/frontend/vue_shared/components/namespace_select/namespace_select_deprecated_spec.js236
-rw-r--r--spec/frontend/vue_shared/components/sidebar/issuable_move_dropdown_spec.js24
-rw-r--r--spec/frontend/vue_shared/components/sidebar/labels_select_widget/labels_select_root_spec.js13
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/components/chunk_spec.js43
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/plugins/link_dependencies_spec.js38
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/plugins/mock_data.js30
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/plugins/utils/composer_json_linker_spec.js38
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/plugins/utils/dependency_linker_util_spec.js14
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/plugins/utils/gemfile_linker_spec.js13
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/plugins/utils/gemspec_linker_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/plugins/utils/godeps_json_linker_spec.js27
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/plugins/utils/package_json_linker_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker_spec.js14
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/plugins/wrap_child_nodes_spec.js3
-rw-r--r--spec/frontend/vue_shared/components/source_viewer/source_viewer_spec.js54
-rw-r--r--spec/frontend/vue_shared/issuable/list/components/issuable_item_spec.js18
-rw-r--r--spec/frontend/vue_shared/issuable/list/components/issuable_list_root_spec.js12
-rw-r--r--spec/frontend/webhooks/components/__snapshots__/push_events_spec.js.snap453
-rw-r--r--spec/frontend/webhooks/components/form_url_app_spec.js125
-rw-r--r--spec/frontend/webhooks/components/form_url_mask_item_spec.js78
-rw-r--r--spec/frontend/webhooks/components/push_events_spec.js117
-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.js108
-rw-r--r--spec/frontend/work_items/components/work_item_description_spec.js295
-rw-r--r--spec/frontend/work_items/components/work_item_detail_modal_spec.js1
-rw-r--r--spec/frontend/work_items/components/work_item_detail_spec.js103
-rw-r--r--spec/frontend/work_items/components/work_item_due_date_spec.js2
-rw-r--r--spec/frontend/work_items/components/work_item_labels_spec.js25
-rw-r--r--spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js205
-rw-r--r--spec/frontend/work_items/components/work_item_links/work_item_links_spec.js31
-rw-r--r--spec/frontend/work_items/components/work_item_milestone_spec.js32
-rw-r--r--spec/frontend/work_items/mock_data.js118
-rw-r--r--spec/frontend/work_items/pages/create_work_item_spec.js39
-rw-r--r--spec/frontend/work_items/pages/work_item_root_spec.js11
-rw-r--r--spec/frontend/work_items/router_spec.js28
-rw-r--r--spec/graphql/graphql_triggers_spec.rb69
-rw-r--r--spec/graphql/mutations/ci/runner/bulk_delete_spec.rb73
-rw-r--r--spec/graphql/mutations/ci/runner/update_spec.rb46
-rw-r--r--spec/graphql/mutations/commits/create_spec.rb2
-rw-r--r--spec/graphql/mutations/concerns/mutations/resolves_group_spec.rb2
-rw-r--r--spec/graphql/mutations/container_repositories/destroy_spec.rb22
-rw-r--r--spec/graphql/mutations/incident_management/timeline_event/create_spec.rb101
-rw-r--r--spec/graphql/mutations/incident_management/timeline_event_tag/create_spec.rb52
-rw-r--r--spec/graphql/mutations/security/ci_configuration/base_security_analyzer_spec.rb2
-rw-r--r--spec/graphql/mutations/todos/restore_many_spec.rb2
-rw-r--r--spec/graphql/resolvers/board_list_issues_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/board_lists_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/board_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/boards_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/container_repositories_resolver_spec.rb4
-rw-r--r--spec/graphql/resolvers/group_packages_resolver_spec.rb8
-rw-r--r--spec/graphql/resolvers/incident_management/timeline_event_tags_resolver_spec.rb92
-rw-r--r--spec/graphql/resolvers/issues_resolver_spec.rb677
-rw-r--r--spec/graphql/resolvers/project_issues_resolver_spec.rb677
-rw-r--r--spec/graphql/resolvers/projects_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/recent_boards_resolver_spec.rb2
-rw-r--r--spec/graphql/resolvers/users_resolver_spec.rb14
-rw-r--r--spec/graphql/resolvers/work_item_resolver_spec.rb8
-rw-r--r--spec/graphql/resolvers/work_items/types_resolver_spec.rb20
-rw-r--r--spec/graphql/types/ci/pipeline_schedule_status_enum_spec.rb2
-rw-r--r--spec/graphql/types/ci/pipeline_type_spec.rb5
-rw-r--r--spec/graphql/types/commit_signature_interface_spec.rb25
-rw-r--r--spec/graphql/types/commit_signatures/gpg_signature_type_spec.rb18
-rw-r--r--spec/graphql/types/commit_signatures/verification_status_enum_spec.rb16
-rw-r--r--spec/graphql/types/commit_signatures/x509_signature_type_spec.rb18
-rw-r--r--spec/graphql/types/commit_type_spec.rb4
-rw-r--r--spec/graphql/types/deployment_details_type_spec.rb2
-rw-r--r--spec/graphql/types/incident_management/timeline_event_tag_type_spec.rb18
-rw-r--r--spec/graphql/types/incident_management/timeline_event_type_spec.rb1
-rw-r--r--spec/graphql/types/issue_type_enum_spec.rb4
-rw-r--r--spec/graphql/types/issue_type_spec.rb2
-rw-r--r--spec/graphql/types/permission_types/ci/runner_spec.rb2
-rw-r--r--spec/graphql/types/project_type_spec.rb127
-rw-r--r--spec/graphql/types/projects/branch_rule_type_spec.rb5
-rw-r--r--spec/graphql/types/projects/repository_language_type_spec.rb15
-rw-r--r--spec/graphql/types/release_links_type_spec.rb10
-rw-r--r--spec/graphql/types/release_source_type_spec.rb2
-rw-r--r--spec/graphql/types/repository_type_spec.rb2
-rw-r--r--spec/graphql/types/subscription_type_spec.rb1
-rw-r--r--spec/graphql/types/x509_certificate_type_spec.rb14
-rw-r--r--spec/graphql/types/x509_issuer_type_spec.rb13
-rw-r--r--spec/helpers/appearances_helper_spec.rb9
-rw-r--r--spec/helpers/application_helper_spec.rb83
-rw-r--r--spec/helpers/application_settings_helper_spec.rb4
-rw-r--r--spec/helpers/diff_helper_spec.rb61
-rw-r--r--spec/helpers/environments_helper_spec.rb2
-rw-r--r--spec/helpers/events_helper_spec.rb24
-rw-r--r--spec/helpers/form_helper_spec.rb42
-rw-r--r--spec/helpers/groups/group_members_helper_spec.rb15
-rw-r--r--spec/helpers/groups/observability_helper_spec.rb92
-rw-r--r--spec/helpers/groups_helper_spec.rb72
-rw-r--r--spec/helpers/hooks_helper_spec.rb35
-rw-r--r--spec/helpers/icons_helper_spec.rb2
-rw-r--r--spec/helpers/ide_helper_spec.rb2
-rw-r--r--spec/helpers/integrations_helper_spec.rb50
-rw-r--r--spec/helpers/json_helper_spec.rb36
-rw-r--r--spec/helpers/markup_helper_spec.rb149
-rw-r--r--spec/helpers/nav/top_nav_helper_spec.rb126
-rw-r--r--spec/helpers/projects/alert_management_helper_spec.rb2
-rw-r--r--spec/helpers/projects/ml/experiments_helper_spec.rb49
-rw-r--r--spec/helpers/projects/pipeline_helper_spec.rb1
-rw-r--r--spec/helpers/projects/project_members_helper_spec.rb3
-rw-r--r--spec/helpers/projects_helper_spec.rb3
-rw-r--r--spec/helpers/recaptcha_helper_spec.rb25
-rw-r--r--spec/helpers/routing/packages_helper_spec.rb13
-rw-r--r--spec/helpers/search_helper_spec.rb179
-rw-r--r--spec/helpers/snippets_helper_spec.rb4
-rw-r--r--spec/helpers/todos_helper_spec.rb45
-rw-r--r--spec/initializers/hashie_mash_permitted_patch_spec.rb29
-rw-r--r--spec/initializers/memory_watchdog_spec.rb126
-rw-r--r--spec/initializers/sawyer_patch_spec.rb70
-rw-r--r--spec/lib/api/entities/merge_request_basic_spec.rb16
-rw-r--r--spec/lib/api/entities/ml/mlflow/run_info_spec.rb4
-rw-r--r--spec/lib/api/entities/release_spec.rb8
-rw-r--r--spec/lib/api/entities/user_counts_spec.rb24
-rw-r--r--spec/lib/api/helpers/packages/dependency_proxy_helpers_spec.rb17
-rw-r--r--spec/lib/api/helpers/packages_helpers_spec.rb119
-rw-r--r--spec/lib/api/helpers_spec.rb6
-rw-r--r--spec/lib/api/validations/validators/email_or_email_list_spec.rb2
-rw-r--r--spec/lib/api/validations/validators/git_ref_spec.rb2
-rw-r--r--spec/lib/api/validations/validators/limit_spec.rb4
-rw-r--r--spec/lib/atlassian/jira_connect/jwt/asymmetric_spec.rb35
-rw-r--r--spec/lib/backup/database_backup_error_spec.rb8
-rw-r--r--spec/lib/backup/file_backup_error_spec.rb4
-rw-r--r--spec/lib/banzai/filter/autolink_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/issuable_reference_expansion_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/math_filter_spec.rb13
-rw-r--r--spec/lib/banzai/filter/references/alert_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/references/commit_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/references/issue_reference_filter_spec.rb4
-rw-r--r--spec/lib/banzai/filter/references/label_reference_filter_spec.rb10
-rw-r--r--spec/lib/banzai/filter/references/milestone_reference_filter_spec.rb10
-rw-r--r--spec/lib/banzai/filter/references/project_reference_filter_spec.rb4
-rw-r--r--spec/lib/banzai/filter/references/user_reference_filter_spec.rb2
-rw-r--r--spec/lib/banzai/filter/repository_link_filter_spec.rb1
-rw-r--r--spec/lib/banzai/filter/syntax_highlight_filter_spec.rb43
-rw-r--r--spec/lib/banzai/reference_parser/base_parser_spec.rb2
-rw-r--r--spec/lib/banzai/reference_parser/commit_parser_spec.rb26
-rw-r--r--spec/lib/banzai/reference_parser/commit_range_parser_spec.rb40
-rw-r--r--spec/lib/banzai/reference_parser/issue_parser_spec.rb8
-rw-r--r--spec/lib/bulk_imports/clients/http_spec.rb16
-rw-r--r--spec/lib/bulk_imports/common/pipelines/entity_finisher_spec.rb2
-rw-r--r--spec/lib/bulk_imports/pipeline/runner_spec.rb25
-rw-r--r--spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb131
-rw-r--r--spec/lib/error_tracking/sentry_client/issue_spec.rb2
-rw-r--r--spec/lib/feature/gitaly_spec.rb229
-rw-r--r--spec/lib/feature_spec.rb48
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb2
-rw-r--r--spec/lib/gitlab/app_logger_spec.rb7
-rw-r--r--spec/lib/gitlab/application_context_spec.rb8
-rw-r--r--spec/lib/gitlab/asciidoc_spec.rb23
-rw-r--r--spec/lib/gitlab/auth/auth_finders_spec.rb5
-rw-r--r--spec/lib/gitlab/background_migration/backfill_project_namespace_details_spec.rb62
-rw-r--r--spec/lib/gitlab/background_migration/backfill_project_namespace_on_issues_spec.rb17
-rw-r--r--spec/lib/gitlab/background_migration/backfill_projects_with_coverage_spec.rb95
-rw-r--r--spec/lib/gitlab/background_migration/backfill_user_details_fields_spec.rb222
-rw-r--r--spec/lib/gitlab/background_migration/batched_migration_job_spec.rb77
-rw-r--r--spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/populate_projects_star_count_spec.rb72
-rw-r--r--spec/lib/gitlab/background_migration/populate_vulnerability_reads_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at_spec.rb5
-rw-r--r--spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values_spec.rb70
-rw-r--r--spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values_spec.rb70
-rw-r--r--spec/lib/gitlab/background_migration/sanitize_confidential_todos_spec.rb89
-rw-r--r--spec/lib/gitlab/background_migration/update_ci_pipeline_artifacts_unknown_locked_status_spec.rb4
-rw-r--r--spec/lib/gitlab/bitbucket_import/importer_spec.rb1
-rw-r--r--spec/lib/gitlab/cache/metrics_spec.rb118
-rw-r--r--spec/lib/gitlab/checks/lfs_integrity_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb42
-rw-r--r--spec/lib/gitlab/ci/config/entry/bridge_spec.rb36
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb22
-rw-r--r--spec/lib/gitlab/ci/config/entry/processable_spec.rb27
-rw-r--r--spec/lib/gitlab/ci/config/entry/root_spec.rb29
-rw-r--r--spec/lib/gitlab/ci/config/entry/variable_spec.rb118
-rw-r--r--spec/lib/gitlab/ci/config/entry/variables_spec.rb34
-rw-r--r--spec/lib/gitlab/ci/config/external/file/base_spec.rb22
-rw-r--r--spec/lib/gitlab/ci/config/external/mapper_spec.rb16
-rw-r--r--spec/lib/gitlab/ci/config_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/parsers/codequality/code_climate_spec.rb62
-rw-r--r--spec/lib/gitlab/ci/parsers/coverage/sax_document_spec.rb31
-rw-r--r--spec/lib/gitlab/ci/parsers/sbom/cyclonedx_properties_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb41
-rw-r--r--spec/lib/gitlab/ci/parsers/security/common_spec.rb37
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/command_spec.rb17
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/limit/active_jobs_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb136
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb43
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb119
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb224
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/reports/sbom/component_spec.rb70
-rw-r--r--spec/lib/gitlab/ci/reports/sbom/report_spec.rb15
-rw-r--r--spec/lib/gitlab/ci/reports/security/flag_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/reports/security/reports_spec.rb26
-rw-r--r--spec/lib/gitlab/ci/reports/test_suite_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/5_minute_production_app_ci_yaml_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/AWS/deploy_ecs_gitlab_ci_yaml_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/Jobs/build_gitlab_ci_yaml_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/templates/Jobs/code_quality_gitlab_ci_yaml_spec.rb11
-rw-r--r--spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb15
-rw-r--r--spec/lib/gitlab/ci/templates/Jobs/sast_iac_gitlab_ci_yaml_spec.rb10
-rw-r--r--spec/lib/gitlab/ci/templates/Jobs/sast_iac_latest_gitlab_ci_yaml_spec.rb10
-rw-r--r--spec/lib/gitlab/ci/templates/Jobs/test_gitlab_ci_yaml_spec.rb11
-rw-r--r--spec/lib/gitlab/ci/templates/MATLAB_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/Terraform/base_gitlab_ci_yaml_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/Terraform/base_latest_gitlab_ci_yaml_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/Verify/load_performance_testing_gitlab_ci_yaml_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/flutter_gitlab_ci_yaml_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/kaniko_gitlab_ci_yaml_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/katalon_gitlab_ci_yaml_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/templates/npm_spec.rb5
-rw-r--r--spec/lib/gitlab/ci/templates/terraform_gitlab_ci_yaml_spec.rb23
-rw-r--r--spec/lib/gitlab/ci/templates/terraform_latest_gitlab_ci_yaml_spec.rb38
-rw-r--r--spec/lib/gitlab/ci/templates/themekit_gitlab_ci_yaml_spec.rb7
-rw-r--r--spec/lib/gitlab/ci/variables/collection/item_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/variables/collection_spec.rb53
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb77
-rw-r--r--spec/lib/gitlab/cluster/lifecycle_events_spec.rb59
-rw-r--r--spec/lib/gitlab/cluster/puma_worker_killer_initializer_spec.rb30
-rw-r--r--spec/lib/gitlab/config_checker/external_database_checker_spec.rb21
-rw-r--r--spec/lib/gitlab/conflict/file_spec.rb25
-rw-r--r--spec/lib/gitlab/content_security_policy/config_loader_spec.rb12
-rw-r--r--spec/lib/gitlab/data_builder/build_spec.rb98
-rw-r--r--spec/lib/gitlab/data_builder/pipeline_spec.rb1
-rw-r--r--spec/lib/gitlab/database/background_migration/batched_job_spec.rb18
-rw-r--r--spec/lib/gitlab/database/background_migration/batched_migration_spec.rb96
-rw-r--r--spec/lib/gitlab/database/batch_count_spec.rb2
-rw-r--r--spec/lib/gitlab/database/load_balancing/configuration_spec.rb12
-rw-r--r--spec/lib/gitlab/database/load_balancing/connection_proxy_spec.rb4
-rw-r--r--spec/lib/gitlab/database/load_balancing/service_discovery/sampler_spec.rb80
-rw-r--r--spec/lib/gitlab/database/load_balancing/service_discovery_spec.rb34
-rw-r--r--spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb2
-rw-r--r--spec/lib/gitlab/database/load_balancing/transaction_leaking_spec.rb15
-rw-r--r--spec/lib/gitlab/database/load_balancing_spec.rb5
-rw-r--r--spec/lib/gitlab/database/migration_helpers/v2_spec.rb94
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb1276
-rw-r--r--spec/lib/gitlab/database/migrations/background_migration_helpers_spec.rb3
-rw-r--r--spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb95
-rw-r--r--spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb679
-rw-r--r--spec/lib/gitlab/database/migrations/extension_helpers_spec.rb65
-rw-r--r--spec/lib/gitlab/database/migrations/lock_retries_helpers_spec.rb52
-rw-r--r--spec/lib/gitlab/database/migrations/runner_spec.rb63
-rw-r--r--spec/lib/gitlab/database/migrations/timeout_helpers_spec.rb91
-rw-r--r--spec/lib/gitlab/database/partitioning/convert_table_to_first_list_partition_spec.rb14
-rw-r--r--spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb8
-rw-r--r--spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb170
-rw-r--r--spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb9
-rw-r--r--spec/lib/gitlab/database/postgres_partition_spec.rb32
-rw-r--r--spec/lib/gitlab/database/query_analyzer_spec.rb8
-rw-r--r--spec/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer_spec.rb78
-rw-r--r--spec/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer_spec.rb121
-rw-r--r--spec/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer_spec.rb70
-rw-r--r--spec/lib/gitlab/database/query_analyzers/query_recorder_spec.rb38
-rw-r--r--spec/lib/gitlab/database/tables_truncate_spec.rb20
-rw-r--r--spec/lib/gitlab/database/type/symbolized_jsonb_spec.rb64
-rw-r--r--spec/lib/gitlab/database_importers/self_monitoring/project/delete_service_spec.rb4
-rw-r--r--spec/lib/gitlab/database_spec.rb6
-rw-r--r--spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb3
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb32
-rw-r--r--spec/lib/gitlab/doorkeeper_secret_storing/token/pbkdf2_sha512_spec.rb10
-rw-r--r--spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb10
-rw-r--r--spec/lib/gitlab/email/handler_spec.rb2
-rw-r--r--spec/lib/gitlab/email/receiver_spec.rb62
-rw-r--r--spec/lib/gitlab/error_tracking_spec.rb19
-rw-r--r--spec/lib/gitlab/experimentation/group_types_spec.rb13
-rw-r--r--spec/lib/gitlab/feature_categories_spec.rb24
-rw-r--r--spec/lib/gitlab/git/object_pool_spec.rb66
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb12
-rw-r--r--spec/lib/gitlab/git/tree_spec.rb2
-rw-r--r--spec/lib/gitlab/git_ref_validator_spec.rb4
-rw-r--r--spec/lib/gitlab/gitaly_client/object_pool_service_spec.rb33
-rw-r--r--spec/lib/gitlab/gitaly_client/operation_service_spec.rb227
-rw-r--r--spec/lib/gitlab/gitaly_client/ref_service_spec.rb20
-rw-r--r--spec/lib/gitlab/gitaly_client/with_feature_flag_actors_spec.rb275
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb134
-rw-r--r--spec/lib/gitlab/github_import/attachments_downloader_spec.rb2
-rw-r--r--spec/lib/gitlab/github_import/client_spec.rb118
-rw-r--r--spec/lib/gitlab/github_import/importer/events/changed_label_spec.rb75
-rw-r--r--spec/lib/gitlab/github_import/importer/protected_branch_importer_spec.rb149
-rw-r--r--spec/lib/gitlab/github_import/importer/protected_branches_importer_spec.rb16
-rw-r--r--spec/lib/gitlab/github_import/importer/pull_request_review_importer_spec.rb83
-rw-r--r--spec/lib/gitlab/github_import/importer/pull_requests/review_request_importer_spec.rb35
-rw-r--r--spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb141
-rw-r--r--spec/lib/gitlab/github_import/representation/protected_branch_spec.rb15
-rw-r--r--spec/lib/gitlab/github_import/representation/pull_requests/review_requests_spec.rb49
-rw-r--r--spec/lib/gitlab/gon_helper_spec.rb52
-rw-r--r--spec/lib/gitlab/grape_logging/loggers/filter_parameters_spec.rb62
-rw-r--r--spec/lib/gitlab/health_checks/gitaly_check_spec.rb4
-rw-r--r--spec/lib/gitlab/hook_data/merge_request_builder_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml6
-rw-r--r--spec/lib/gitlab/import_export/decompressed_archive_size_validator_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/design_repo_restorer_spec.rb8
-rw-r--r--spec/lib/gitlab/import_export/fork_spec.rb6
-rw-r--r--spec/lib/gitlab/import_export/group/tree_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/import_test_coverage_spec.rb10
-rw-r--r--spec/lib/gitlab/import_export/merge_request_parser_spec.rb4
-rw-r--r--spec/lib/gitlab/import_export/project/exported_relations_merger_spec.rb75
-rw-r--r--spec/lib/gitlab/import_export/project/relation_saver_spec.rb8
-rw-r--r--spec/lib/gitlab/import_export/project/tree_restorer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/recursive_merge_folders_spec.rb54
-rw-r--r--spec/lib/gitlab/import_export/repo_restorer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml4
-rw-r--r--spec/lib/gitlab/import_export/snippets_repo_restorer_spec.rb2
-rw-r--r--spec/lib/gitlab/inactive_projects_deletion_warning_tracker_spec.rb4
-rw-r--r--spec/lib/gitlab/incoming_email_spec.rb99
-rw-r--r--spec/lib/gitlab/instrumentation/redis_cluster_validator_spec.rb29
-rw-r--r--spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb19
-rw-r--r--spec/lib/gitlab/json_logger_spec.rb20
-rw-r--r--spec/lib/gitlab/json_spec.rb56
-rw-r--r--spec/lib/gitlab/kas_spec.rb12
-rw-r--r--spec/lib/gitlab/kroki_spec.rb3
-rw-r--r--spec/lib/gitlab/memory/watchdog/configuration_spec.rb61
-rw-r--r--spec/lib/gitlab/memory/watchdog/configurator_spec.rb199
-rw-r--r--spec/lib/gitlab/memory/watchdog/monitor/rss_memory_limit_spec.rb39
-rw-r--r--spec/lib/gitlab/memory/watchdog_spec.rb10
-rw-r--r--spec/lib/gitlab/merge_requests/mergeability/check_result_spec.rb4
-rw-r--r--spec/lib/gitlab/merge_requests/mergeability/redis_interface_spec.rb2
-rw-r--r--spec/lib/gitlab/merge_requests/mergeability/results_store_spec.rb6
-rw-r--r--spec/lib/gitlab/metrics/dashboard/finder_spec.rb6
-rw-r--r--spec/lib/gitlab/metrics/dashboard/service_selector_spec.rb2
-rw-r--r--spec/lib/gitlab/metrics/dashboard/url_spec.rb2
-rw-r--r--spec/lib/gitlab/metrics/global_search_slis_spec.rb8
-rw-r--r--spec/lib/gitlab/metrics/loose_foreign_keys_slis_spec.rb81
-rw-r--r--spec/lib/gitlab/metrics/method_call_spec.rb47
-rw-r--r--spec/lib/gitlab/metrics/samplers/ruby_sampler_spec.rb20
-rw-r--r--spec/lib/gitlab/metrics/system_spec.rb25
-rw-r--r--spec/lib/gitlab/observability_spec.rb33
-rw-r--r--spec/lib/gitlab/octokit/middleware_spec.rb8
-rw-r--r--spec/lib/gitlab/pagination/gitaly_keyset_pager_spec.rb2
-rw-r--r--spec/lib/gitlab/pagination_delegate_spec.rb157
-rw-r--r--spec/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled_spec.rb4
-rw-r--r--spec/lib/gitlab/project_template_spec.rb14
-rw-r--r--spec/lib/gitlab/qa_spec.rb29
-rw-r--r--spec/lib/gitlab/query_limiting/transaction_spec.rb3
-rw-r--r--spec/lib/gitlab/redis/multi_store_spec.rb544
-rw-r--r--spec/lib/gitlab/request_forgery_protection_spec.rb6
-rw-r--r--spec/lib/gitlab/runtime_spec.rb2
-rw-r--r--spec/lib/gitlab/service_desk_email_spec.rb40
-rw-r--r--spec/lib/gitlab/sidekiq_config_spec.rb2
-rw-r--r--spec/lib/gitlab/sidekiq_daemon/memory_killer_spec.rb4
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/client_spec.rb3
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb312
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb4
-rw-r--r--spec/lib/gitlab/sidekiq_middleware_spec.rb2
-rw-r--r--spec/lib/gitlab/sidekiq_migrate_jobs_spec.rb322
-rw-r--r--spec/lib/gitlab/slash_commands/application_help_spec.rb22
-rw-r--r--spec/lib/gitlab/slash_commands/command_spec.rb20
-rw-r--r--spec/lib/gitlab/slash_commands/presenters/incident_management/incident_new_spec.rb15
-rw-r--r--spec/lib/gitlab/sql/pattern_spec.rb45
-rw-r--r--spec/lib/gitlab/tracking/helpers/weak_password_error_event_spec.rb45
-rw-r--r--spec/lib/gitlab/url_builder_spec.rb51
-rw-r--r--spec/lib/gitlab/usage/metric_definition_spec.rb20
-rw-r--r--spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb434
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/count_merge_request_authors_metric_spec.rb25
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/database_metric_spec.rb63
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_disabled_metric_spec.rb19
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_metric_spec.rb33
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/dormant_user_period_setting_metric_spec.rb21
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/dormant_user_setting_enabled_metric_spec.rb21
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_cta_clicked_metric_spec.rb55
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_sent_metric_spec.rb52
-rw-r--r--spec/lib/gitlab/usage/metrics/instrumentations/work_items_activity_aggregated_metric_spec.rb24
-rw-r--r--spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb13
-rw-r--r--spec/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/constraints_spec.rb17
-rw-r--r--spec/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/having_constraints_spec.rb19
-rw-r--r--spec/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/where_constraints_spec.rb18
-rw-r--r--spec/lib/gitlab/usage_data_counters/ci_template_unique_counter_spec.rb35
-rw-r--r--spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb1
-rw-r--r--spec/lib/gitlab/usage_data_counters/kubernetes_agent_counter_spec.rb6
-rw-r--r--spec/lib/gitlab/usage_data_counters/work_item_activity_unique_counter_spec.rb8
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb196
-rw-r--r--spec/lib/gitlab/utils/strong_memoize_spec.rb57
-rw-r--r--spec/lib/gitlab/utils_spec.rb14
-rw-r--r--spec/lib/gitlab/webpack/file_loader_spec.rb4
-rw-r--r--spec/lib/grafana/client_spec.rb2
-rw-r--r--spec/lib/object_storage/direct_upload_spec.rb147
-rw-r--r--spec/lib/omni_auth/strategies/jwt_spec.rb2
-rw-r--r--spec/lib/rouge/formatters/html_gitlab_spec.rb10
-rw-r--r--spec/lib/sbom/package_url/argument_validator_spec.rb51
-rw-r--r--spec/lib/sbom/package_url/decoder_spec.rb121
-rw-r--r--spec/lib/sbom/package_url/encoder_spec.rb29
-rw-r--r--spec/lib/sbom/package_url/normalizer_spec.rb76
-rw-r--r--spec/lib/sbom/package_url_spec.rb162
-rw-r--r--spec/lib/serializers/symbolized_json_spec.rb42
-rw-r--r--spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb46
-rw-r--r--spec/lib/sidebars/projects/menus/monitor_menu_spec.rb14
-rw-r--r--spec/lib/unnested_in_filters/rewriter_spec.rb91
-rw-r--r--spec/mailers/emails/identity_verification_spec.rb42
-rw-r--r--spec/mailers/emails/releases_spec.rb1
-rw-r--r--spec/mailers/notify_spec.rb2
-rw-r--r--spec/migrations/20210818185845_backfill_projects_with_coverage_spec.rb71
-rw-r--r--spec/migrations/20220107064845_populate_vulnerability_reads_spec.rb2
-rw-r--r--spec/migrations/20220921144258_remove_orphan_group_token_users_spec.rb9
-rw-r--r--spec/migrations/20221018050323_add_objective_and_keyresult_to_work_item_types_spec.rb66
-rw-r--r--spec/migrations/20221018062308_schedule_backfill_project_namespace_details_spec.rb37
-rw-r--r--spec/migrations/20221018193635_ensure_task_note_renaming_background_migration_finished_spec.rb91
-rw-r--r--spec/migrations/20221021145820_create_routing_table_for_builds_metadata_v2_spec.rb36
-rw-r--r--spec/migrations/20221025043930_change_default_value_on_password_last_changed_at_to_user_details_spec.rb37
-rw-r--r--spec/migrations/20221028022627_add_index_on_password_last_changed_at_to_user_details_spec.rb16
-rw-r--r--spec/migrations/20221101032521_add_default_preferred_language_to_application_settings_spec.rb27
-rw-r--r--spec/migrations/20221101032600_add_text_limit_to_default_preferred_language_on_application_settings_spec.rb29
-rw-r--r--spec/migrations/20221102090940_create_next_ci_partitions_record_spec.rb63
-rw-r--r--spec/migrations/20221102090943_create_second_partition_for_builds_metadata_spec.rb61
-rw-r--r--spec/migrations/cleanup_vulnerability_state_transitions_with_same_from_state_to_state_spec.rb49
-rw-r--r--spec/migrations/delete_migrate_shared_vulnerability_scanners_spec.rb69
-rw-r--r--spec/migrations/finalize_invalid_member_cleanup_spec.rb72
-rw-r--r--spec/migrations/queue_backfill_user_details_fields_spec.rb24
-rw-r--r--spec/migrations/queue_populate_projects_star_count_spec.rb24
-rw-r--r--spec/migrations/recount_epic_cache_counts_spec.rb32
-rw-r--r--spec/migrations/reschedule_migrate_shared_vulnerability_scanners_spec.rb41
-rw-r--r--spec/migrations/sanitize_confidential_note_todos_spec.rb33
-rw-r--r--spec/migrations/schedule_migrate_shared_vulnerability_scanners_spec.rb59
-rw-r--r--spec/migrations/set_email_confirmation_setting_from_send_user_confirmation_email_setting_spec.rb41
-rw-r--r--spec/migrations/sync_new_amount_used_for_ci_namespace_monthly_usages_spec.rb42
-rw-r--r--spec/migrations/sync_new_amount_used_for_ci_project_monthly_usages_spec.rb42
-rw-r--r--spec/models/active_session_spec.rb22
-rw-r--r--spec/models/alert_management/http_integration_spec.rb9
-rw-r--r--spec/models/appearance_spec.rb14
-rw-r--r--spec/models/application_setting_spec.rb17
-rw-r--r--spec/models/broadcast_message_spec.rb7
-rw-r--r--spec/models/ci/bridge_spec.rb93
-rw-r--r--spec/models/ci/build_metadata_spec.rb32
-rw-r--r--spec/models/ci/build_runner_session_spec.rb6
-rw-r--r--spec/models/ci/build_spec.rb121
-rw-r--r--spec/models/ci/build_trace_chunk_spec.rb5
-rw-r--r--spec/models/ci/build_trace_spec.rb4
-rw-r--r--spec/models/ci/pipeline_metadata_spec.rb2
-rw-r--r--spec/models/ci/pipeline_spec.rb39
-rw-r--r--spec/models/ci/processable_spec.rb22
-rw-r--r--spec/models/ci/secure_file_spec.rb11
-rw-r--r--spec/models/ci/sources/pipeline_spec.rb4
-rw-r--r--spec/models/ci/stage_spec.rb2
-rw-r--r--spec/models/ci/trigger_request_spec.rb2
-rw-r--r--spec/models/ci/unit_test_spec.rb2
-rw-r--r--spec/models/clusters/applications/cert_manager_spec.rb5
-rw-r--r--spec/models/clusters/applications/crossplane_spec.rb5
-rw-r--r--spec/models/clusters/applications/helm_spec.rb4
-rw-r--r--spec/models/clusters/applications/ingress_spec.rb5
-rw-r--r--spec/models/clusters/applications/jupyter_spec.rb4
-rw-r--r--spec/models/clusters/applications/knative_spec.rb4
-rw-r--r--spec/models/clusters/applications/prometheus_spec.rb11
-rw-r--r--spec/models/clusters/applications/runner_spec.rb4
-rw-r--r--spec/models/clusters/cluster_spec.rb4
-rw-r--r--spec/models/clusters/integrations/prometheus_spec.rb10
-rw-r--r--spec/models/clusters/platforms/kubernetes_spec.rb57
-rw-r--r--spec/models/clusters/providers/aws_spec.rb2
-rw-r--r--spec/models/clusters/providers/gcp_spec.rb3
-rw-r--r--spec/models/commit_signatures/gpg_signature_spec.rb6
-rw-r--r--spec/models/commit_status_spec.rb1
-rw-r--r--spec/models/concerns/bulk_insert_safe_spec.rb6
-rw-r--r--spec/models/concerns/ci/has_variable_spec.rb1
-rw-r--r--spec/models/concerns/ci/partitionable/switch_spec.rb316
-rw-r--r--spec/models/concerns/ci/partitionable_spec.rb21
-rw-r--r--spec/models/concerns/encrypted_user_password_spec.rb138
-rw-r--r--spec/models/concerns/file_store_mounter_spec.rb93
-rw-r--r--spec/models/concerns/has_user_type_spec.rb42
-rw-r--r--spec/models/concerns/issuable_spec.rb41
-rw-r--r--spec/models/concerns/pg_full_text_searchable_spec.rb38
-rw-r--r--spec/models/concerns/project_features_compatibility_spec.rb2
-rw-r--r--spec/models/concerns/sha_attribute_spec.rb10
-rw-r--r--spec/models/concerns/subquery_spec.rb61
-rw-r--r--spec/models/concerns/token_authenticatable_spec.rb10
-rw-r--r--spec/models/container_repository_spec.rb32
-rw-r--r--spec/models/dependency_proxy/group_setting_spec.rb5
-rw-r--r--spec/models/deploy_token_spec.rb2
-rw-r--r--spec/models/deployment_spec.rb26
-rw-r--r--spec/models/diff_discussion_spec.rb2
-rw-r--r--spec/models/diff_viewer/server_side_spec.rb28
-rw-r--r--spec/models/environment_spec.rb4
-rw-r--r--spec/models/environment_status_spec.rb2
-rw-r--r--spec/models/error_tracking/project_error_tracking_setting_spec.rb28
-rw-r--r--spec/models/event_collection_spec.rb254
-rw-r--r--spec/models/event_spec.rb8
-rw-r--r--spec/models/experiment_spec.rb428
-rw-r--r--spec/models/experiment_subject_spec.rb72
-rw-r--r--spec/models/experiment_user_spec.rb14
-rw-r--r--spec/models/exported_protected_branch_spec.rb2
-rw-r--r--spec/models/factories_spec.rb136
-rw-r--r--spec/models/group_spec.rb180
-rw-r--r--spec/models/hooks/active_hook_filter_spec.rb113
-rw-r--r--spec/models/hooks/project_hook_spec.rb20
-rw-r--r--spec/models/hooks/system_hook_spec.rb11
-rw-r--r--spec/models/hooks/web_hook_log_spec.rb19
-rw-r--r--spec/models/hooks/web_hook_spec.rb142
-rw-r--r--spec/models/incident_management/timeline_event_spec.rb1
-rw-r--r--spec/models/incident_management/timeline_event_tag_spec.rb37
-rw-r--r--spec/models/instance_metadata_spec.rb3
-rw-r--r--spec/models/integration_spec.rb55
-rw-r--r--spec/models/integrations/assembla_spec.rb4
-rw-r--r--spec/models/integrations/bamboo_spec.rb46
-rw-r--r--spec/models/integrations/base_chat_notification_spec.rb22
-rw-r--r--spec/models/integrations/base_issue_tracker_spec.rb4
-rw-r--r--spec/models/integrations/base_third_party_wiki_spec.rb4
-rw-r--r--spec/models/integrations/buildkite_spec.rb6
-rw-r--r--spec/models/integrations/campfire_spec.rb4
-rw-r--r--spec/models/integrations/chat_message/pipeline_message_spec.rb41
-rw-r--r--spec/models/integrations/confluence_spec.rb5
-rw-r--r--spec/models/integrations/datadog_spec.rb8
-rw-r--r--spec/models/integrations/discord_spec.rb2
-rw-r--r--spec/models/integrations/drone_ci_spec.rb7
-rw-r--r--spec/models/integrations/emails_on_push_spec.rb2
-rw-r--r--spec/models/integrations/hangouts_chat_spec.rb6
-rw-r--r--spec/models/integrations/harbor_spec.rb11
-rw-r--r--spec/models/integrations/jenkins_spec.rb142
-rw-r--r--spec/models/integrations/jira_spec.rb77
-rw-r--r--spec/models/integrations/mattermost_slash_commands_spec.rb4
-rw-r--r--spec/models/integrations/microsoft_teams_spec.rb36
-rw-r--r--spec/models/integrations/mock_ci_spec.rb2
-rw-r--r--spec/models/integrations/packagist_spec.rb84
-rw-r--r--spec/models/integrations/pipelines_email_spec.rb2
-rw-r--r--spec/models/integrations/prometheus_spec.rb8
-rw-r--r--spec/models/integrations/pushover_spec.rb4
-rw-r--r--spec/models/integrations/shimo_spec.rb6
-rw-r--r--spec/models/integrations/slack_slash_commands_spec.rb2
-rw-r--r--spec/models/integrations/slack_spec.rb140
-rw-r--r--spec/models/integrations/teamcity_spec.rb50
-rw-r--r--spec/models/integrations/zentao_spec.rb6
-rw-r--r--spec/models/issue_spec.rb32
-rw-r--r--spec/models/jira_connect_installation_spec.rb16
-rw-r--r--spec/models/member_spec.rb8
-rw-r--r--spec/models/members/group_member_spec.rb6
-rw-r--r--spec/models/members/last_group_owner_assigner_spec.rb88
-rw-r--r--spec/models/members/project_member_spec.rb4
-rw-r--r--spec/models/merge_request_diff_file_spec.rb10
-rw-r--r--spec/models/merge_request_diff_spec.rb13
-rw-r--r--spec/models/merge_request_spec.rb73
-rw-r--r--spec/models/metrics/dashboard/annotation_spec.rb2
-rw-r--r--spec/models/ml/candidate_metric_spec.rb13
-rw-r--r--spec/models/ml/candidate_spec.rb36
-rw-r--r--spec/models/namespace_setting_spec.rb6
-rw-r--r--spec/models/namespace_spec.rb20
-rw-r--r--spec/models/network/graph_spec.rb24
-rw-r--r--spec/models/note_spec.rb68
-rw-r--r--spec/models/notification_setting_spec.rb6
-rw-r--r--spec/models/oauth_access_token_spec.rb31
-rw-r--r--spec/models/operations/feature_flag_spec.rb5
-rw-r--r--spec/models/packages/package_file_spec.rb2
-rw-r--r--spec/models/packages/package_spec.rb12
-rw-r--r--spec/models/pages_domain_spec.rb4
-rw-r--r--spec/models/personal_access_token_spec.rb57
-rw-r--r--spec/models/preloaders/labels_preloader_spec.rb5
-rw-r--r--spec/models/preloaders/project_root_ancestor_preloader_spec.rb8
-rw-r--r--spec/models/preloaders/user_max_access_level_in_projects_preloader_spec.rb58
-rw-r--r--spec/models/project_authorization_spec.rb77
-rw-r--r--spec/models/project_ci_cd_setting_spec.rb6
-rw-r--r--spec/models/project_setting_spec.rb9
-rw-r--r--spec/models/project_spec.rb108
-rw-r--r--spec/models/projects/wiki_repository_spec.rb16
-rw-r--r--spec/models/protected_branch_spec.rb45
-rw-r--r--spec/models/repository_spec.rb7
-rw-r--r--spec/models/serverless/domain_cluster_spec.rb10
-rw-r--r--spec/models/spam_log_spec.rb37
-rw-r--r--spec/models/terraform/state_spec.rb6
-rw-r--r--spec/models/terraform/state_version_spec.rb9
-rw-r--r--spec/models/time_tracking/timelog_category_spec.rb4
-rw-r--r--spec/models/todo_spec.rb2
-rw-r--r--spec/models/user_spec.rb274
-rw-r--r--spec/models/users/calloutable_spec.rb4
-rw-r--r--spec/models/users/ghost_user_migration_spec.rb13
-rw-r--r--spec/models/users/namespace_commit_email_spec.rb21
-rw-r--r--spec/models/users_star_project_spec.rb80
-rw-r--r--spec/models/work_items/type_spec.rb7
-rw-r--r--spec/models/work_items/widgets/hierarchy_spec.rb32
-rw-r--r--spec/models/work_items/widgets/milestone_spec.rb27
-rw-r--r--spec/policies/global_policy_spec.rb30
-rw-r--r--spec/policies/group_member_policy_spec.rb130
-rw-r--r--spec/policies/group_policy_spec.rb13
-rw-r--r--spec/policies/issuable_policy_spec.rb8
-rw-r--r--spec/policies/note_policy_spec.rb24
-rw-r--r--spec/policies/project_member_policy_spec.rb32
-rw-r--r--spec/policies/project_policy_spec.rb138
-rw-r--r--spec/policies/user_policy_spec.rb44
-rw-r--r--spec/presenters/blob_presenter_spec.rb12
-rw-r--r--spec/presenters/ci/build_runner_presenter_spec.rb41
-rw-r--r--spec/presenters/ci/pipeline_presenter_spec.rb4
-rw-r--r--spec/presenters/deployments/deployment_presenter_spec.rb2
-rw-r--r--spec/presenters/issue_presenter_spec.rb36
-rw-r--r--spec/presenters/packages/npm/package_presenter_spec.rb8
-rw-r--r--spec/presenters/project_presenter_spec.rb8
-rw-r--r--spec/rack_servers/configs/config.ru2
-rw-r--r--spec/requests/admin/broadcast_messages_controller_spec.rb89
-rw-r--r--spec/requests/api/admin/ci/variables_spec.rb27
-rw-r--r--spec/requests/api/alert_management_alerts_spec.rb8
-rw-r--r--spec/requests/api/boards_spec.rb4
-rw-r--r--spec/requests/api/ci/job_artifacts_spec.rb16
-rw-r--r--spec/requests/api/ci/jobs_spec.rb26
-rw-r--r--spec/requests/api/ci/pipelines_spec.rb14
-rw-r--r--spec/requests/api/ci/resource_groups_spec.rb44
-rw-r--r--spec/requests/api/ci/runner/jobs_artifacts_spec.rb24
-rw-r--r--spec/requests/api/ci/runner/jobs_request_post_spec.rb2
-rw-r--r--spec/requests/api/ci/runners_reset_registration_token_spec.rb2
-rw-r--r--spec/requests/api/ci/runners_spec.rb2
-rw-r--r--spec/requests/api/ci/secure_files_spec.rb12
-rw-r--r--spec/requests/api/ci/triggers_spec.rb2
-rw-r--r--spec/requests/api/ci/variables_spec.rb25
-rw-r--r--spec/requests/api/clusters/agent_tokens_spec.rb12
-rw-r--r--spec/requests/api/dependency_proxy_spec.rb2
-rw-r--r--spec/requests/api/deployments_spec.rb4
-rw-r--r--spec/requests/api/features_spec.rb39
-rw-r--r--spec/requests/api/files_spec.rb35
-rw-r--r--spec/requests/api/go_proxy_spec.rb31
-rw-r--r--spec/requests/api/graphql/boards/board_list_issues_query_spec.rb40
-rw-r--r--spec/requests/api/graphql/boards/board_lists_query_spec.rb63
-rw-r--r--spec/requests/api/graphql/ci/jobs_spec.rb4
-rw-r--r--spec/requests/api/graphql/ci/pipelines_spec.rb6
-rw-r--r--spec/requests/api/graphql/ci/runner_spec.rb3
-rw-r--r--spec/requests/api/graphql/group/work_item_types_spec.rb11
-rw-r--r--spec/requests/api/graphql/issues_spec.rb117
-rw-r--r--spec/requests/api/graphql/metadata_query_spec.rb3
-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/pipeline_schedule_take_ownership_spec.rb41
-rw-r--r--spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb23
-rw-r--r--spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb32
-rw-r--r--spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb2
-rw-r--r--spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb12
-rw-r--r--spec/requests/api/graphql/mutations/incident_management/timeline_event_tag/create_spec.rb57
-rw-r--r--spec/requests/api/graphql/mutations/issues/create_spec.rb33
-rw-r--r--spec/requests/api/graphql/mutations/work_items/create_from_task_spec.rb14
-rw-r--r--spec/requests/api/graphql/mutations/work_items/create_spec.rb64
-rw-r--r--spec/requests/api/graphql/mutations/work_items/delete_spec.rb14
-rw-r--r--spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb14
-rw-r--r--spec/requests/api/graphql/mutations/work_items/update_spec.rb105
-rw-r--r--spec/requests/api/graphql/mutations/work_items/update_task_spec.rb16
-rw-r--r--spec/requests/api/graphql/packages/package_spec.rb20
-rw-r--r--spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb104
-rw-r--r--spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb104
-rw-r--r--spec/requests/api/graphql/project/branch_rules_spec.rb143
-rw-r--r--spec/requests/api/graphql/project/incident_management/timeline_events_spec.rb43
-rw-r--r--spec/requests/api/graphql/project/issues_spec.rb286
-rw-r--r--spec/requests/api/graphql/project/languages_spec.rb62
-rw-r--r--spec/requests/api/graphql/project/tree/tree_spec.rb86
-rw-r--r--spec/requests/api/graphql/project/work_item_types_spec.rb11
-rw-r--r--spec/requests/api/graphql/project/work_items_spec.rb25
-rw-r--r--spec/requests/api/graphql/work_item_spec.rb46
-rw-r--r--spec/requests/api/group_boards_spec.rb2
-rw-r--r--spec/requests/api/group_container_repositories_spec.rb8
-rw-r--r--spec/requests/api/group_variables_spec.rb25
-rw-r--r--spec/requests/api/groups_spec.rb26
-rw-r--r--spec/requests/api/import_github_spec.rb22
-rw-r--r--spec/requests/api/internal/kubernetes_spec.rb42
-rw-r--r--spec/requests/api/invitations_spec.rb133
-rw-r--r--spec/requests/api/issues/issues_spec.rb4
-rw-r--r--spec/requests/api/issues/post_projects_issues_spec.rb4
-rw-r--r--spec/requests/api/labels_spec.rb2
-rw-r--r--spec/requests/api/markdown_spec.rb2
-rw-r--r--spec/requests/api/maven_packages_spec.rb10
-rw-r--r--spec/requests/api/members_spec.rb125
-rw-r--r--spec/requests/api/merge_requests_spec.rb6
-rw-r--r--spec/requests/api/metrics/dashboard/annotations_spec.rb2
-rw-r--r--spec/requests/api/ml/mlflow_spec.rb7
-rw-r--r--spec/requests/api/npm_project_packages_spec.rb33
-rw-r--r--spec/requests/api/pages/pages_spec.rb2
-rw-r--r--spec/requests/api/personal_access_tokens_spec.rb19
-rw-r--r--spec/requests/api/project_attributes.yml1
-rw-r--r--spec/requests/api/project_container_repositories_spec.rb22
-rw-r--r--spec/requests/api/project_import_spec.rb4
-rw-r--r--spec/requests/api/project_milestones_spec.rb2
-rw-r--r--spec/requests/api/project_snippets_spec.rb2
-rw-r--r--spec/requests/api/projects_spec.rb64
-rw-r--r--spec/requests/api/protected_branches_spec.rb55
-rw-r--r--spec/requests/api/protected_tags_spec.rb8
-rw-r--r--spec/requests/api/pypi_packages_spec.rb3
-rw-r--r--spec/requests/api/release/links_spec.rb18
-rw-r--r--spec/requests/api/resource_access_tokens_spec.rb101
-rw-r--r--spec/requests/api/rpm_project_packages_spec.rb70
-rw-r--r--spec/requests/api/rubygem_packages_spec.rb5
-rw-r--r--spec/requests/api/search_spec.rb64
-rw-r--r--spec/requests/api/snippets_spec.rb10
-rw-r--r--spec/requests/api/submodules_spec.rb2
-rw-r--r--spec/requests/api/suggestions_spec.rb15
-rw-r--r--spec/requests/api/tags_spec.rb2
-rw-r--r--spec/requests/api/terraform/modules/v1/packages_spec.rb5
-rw-r--r--spec/requests/api/terraform/state_spec.rb37
-rw-r--r--spec/requests/api/todos_spec.rb2
-rw-r--r--spec/requests/api/unleash_spec.rb12
-rw-r--r--spec/requests/api/user_counts_spec.rb26
-rw-r--r--spec/requests/api/users_spec.rb188
-rw-r--r--spec/requests/groups/observability_controller_spec.rb218
-rw-r--r--spec/requests/groups/settings/access_tokens_controller_spec.rb25
-rw-r--r--spec/requests/jira_connect/cors_preflight_checks_controller_spec.rb59
-rw-r--r--spec/requests/jira_connect/oauth_application_ids_controller_spec.rb34
-rw-r--r--spec/requests/jira_connect/subscriptions_controller_spec.rb42
-rw-r--r--spec/requests/oauth/tokens_controller_spec.rb7
-rw-r--r--spec/requests/product_analytics/collector_app_attack_spec.rb41
-rw-r--r--spec/requests/product_analytics/collector_app_spec.rb58
-rw-r--r--spec/requests/projects/cycle_analytics_events_spec.rb4
-rw-r--r--spec/requests/projects/google_cloud/deployments_controller_spec.rb6
-rw-r--r--spec/requests/projects/google_cloud/service_accounts_controller_spec.rb2
-rw-r--r--spec/requests/projects/issue_links_controller_spec.rb20
-rw-r--r--spec/requests/projects/merge_requests/context_commit_diffs_spec.rb2
-rw-r--r--spec/requests/projects/merge_requests/diffs_spec.rb18
-rw-r--r--spec/requests/projects/ml/experiments_controller_spec.rb100
-rw-r--r--spec/requests/projects/settings/access_tokens_controller_spec.rb25
-rw-r--r--spec/requests/projects/work_items_spec.rb20
-rw-r--r--spec/requests/search_controller_spec.rb14
-rw-r--r--spec/requests/self_monitoring_project_spec.rb8
-rw-r--r--spec/requests/verifies_with_email_spec.rb152
-rw-r--r--spec/routing/group_routing_spec.rb12
-rw-r--r--spec/routing/project_routing_spec.rb4
-rw-r--r--spec/rubocop/cop/api/ensure_string_detail_spec.rb136
-rw-r--r--spec/rubocop/cop/gitlab/duplicate_spec_location_spec.rb98
-rw-r--r--spec/rubocop/cop/gitlab/json_spec.rb45
-rw-r--r--spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb4
-rw-r--r--spec/rubocop/cop/gitlab/rspec/avoid_setup_spec.rb36
-rw-r--r--spec/rubocop/cop/graphql/enum_names_spec.rb52
-rw-r--r--spec/rubocop/cop/graphql/enum_values_spec.rb79
-rw-r--r--spec/rubocop/cop/migration/schema_addition_methods_no_post_spec.rb24
-rw-r--r--spec/rubocop/cop/rake/require_spec.rb60
-rw-r--r--spec/rubocop/cop/rspec/duplicate_spec_location_spec.rb98
-rw-r--r--spec/rubocop/cop/rspec/factory_bot/strategy_in_callback_spec.rb71
-rw-r--r--spec/rubocop/migration_helpers_spec.rb17
-rw-r--r--spec/rubocop_spec_helper.rb5
-rw-r--r--spec/scripts/failed_tests_spec.rb2
-rw-r--r--spec/scripts/lib/glfm/update_example_snapshots_spec.rb57
-rw-r--r--spec/scripts/lib/glfm/update_specification_spec.rb240
-rw-r--r--spec/scripts/lib/glfm/verify_all_generated_files_are_up_to_date_spec.rb9
-rw-r--r--spec/scripts/pipeline_test_report_builder_spec.rb2
-rw-r--r--spec/serializers/ci/pipeline_entity_spec.rb20
-rw-r--r--spec/serializers/codequality_degradation_entity_spec.rb3
-rw-r--r--spec/serializers/diff_file_entity_spec.rb44
-rw-r--r--spec/serializers/diffs_entity_spec.rb73
-rw-r--r--spec/serializers/diffs_metadata_entity_spec.rb53
-rw-r--r--spec/serializers/integrations/event_entity_spec.rb1
-rw-r--r--spec/serializers/integrations/field_entity_spec.rb34
-rw-r--r--spec/serializers/issue_board_entity_spec.rb14
-rw-r--r--spec/serializers/issue_entity_spec.rb16
-rw-r--r--spec/serializers/linked_project_issue_entity_spec.rb16
-rw-r--r--spec/serializers/merge_request_poll_cached_widget_entity_spec.rb16
-rw-r--r--spec/serializers/merge_request_poll_widget_entity_spec.rb6
-rw-r--r--spec/serializers/merge_requests/pipeline_entity_spec.rb21
-rw-r--r--spec/serializers/paginated_diff_entity_spec.rb76
-rw-r--r--spec/serializers/pipeline_serializer_spec.rb3
-rw-r--r--spec/serializers/remote_mirror_entity_spec.rb3
-rw-r--r--spec/services/admin/set_feature_flag_service_spec.rb9
-rw-r--r--spec/services/auto_merge/merge_when_pipeline_succeeds_service_spec.rb2
-rw-r--r--spec/services/boards/issues/list_service_spec.rb4
-rw-r--r--spec/services/branches/create_service_spec.rb23
-rw-r--r--spec/services/bulk_imports/create_pipeline_trackers_service_spec.rb4
-rw-r--r--spec/services/ci/after_requeue_job_service_spec.rb36
-rw-r--r--spec/services/ci/compare_test_reports_service_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service/partitioning_spec.rb5
-rw-r--r--spec/services/ci/create_pipeline_service/rules_spec.rb38
-rw-r--r--spec/services/ci/create_pipeline_service/variables_spec.rb136
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb47
-rw-r--r--spec/services/ci/job_artifacts/create_service_spec.rb6
-rw-r--r--spec/services/ci/job_artifacts/destroy_batch_service_spec.rb81
-rw-r--r--spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb127
-rw-r--r--spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb2
-rw-r--r--spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb23
-rw-r--r--spec/services/ci/pipeline_processing/test_cases/stage_one_test_succeeds_one_manual_test_fails_and_retry_manual_build.yml54
-rw-r--r--spec/services/ci/pipeline_processing/test_cases/stage_one_test_succeeds_one_manual_test_fails_and_retry_pipeline.yml53
-rw-r--r--spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb63
-rw-r--r--spec/services/ci/play_build_service_spec.rb10
-rw-r--r--spec/services/ci/process_build_service_spec.rb189
-rw-r--r--spec/services/ci/register_job_service_spec.rb13
-rw-r--r--spec/services/ci/retry_job_service_spec.rb284
-rw-r--r--spec/services/ci/retry_pipeline_service_spec.rb23
-rw-r--r--spec/services/ci/runners/bulk_delete_runners_service_spec.rb170
-rw-r--r--spec/services/ci/runners/set_runner_associated_projects_service_spec.rb13
-rw-r--r--spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb44
-rw-r--r--spec/services/clusters/applications/check_installation_progress_service_spec.rb204
-rw-r--r--spec/services/clusters/applications/check_uninstall_progress_service_spec.rb155
-rw-r--r--spec/services/clusters/applications/check_upgrade_progress_service_spec.rb94
-rw-r--r--spec/services/clusters/applications/create_service_spec.rb279
-rw-r--r--spec/services/clusters/applications/patch_service_spec.rb80
-rw-r--r--spec/services/clusters/applications/prometheus_update_service_spec.rb111
-rw-r--r--spec/services/clusters/applications/update_service_spec.rb91
-rw-r--r--spec/services/clusters/gcp/provision_service_spec.rb2
-rw-r--r--spec/services/clusters/gcp/verify_provision_status_service_spec.rb10
-rw-r--r--spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb223
-rw-r--r--spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb2
-rw-r--r--spec/services/dependency_proxy/find_cached_manifest_service_spec.rb30
-rw-r--r--spec/services/deployments/create_for_build_service_spec.rb87
-rw-r--r--spec/services/environments/create_for_build_service_spec.rb304
-rw-r--r--spec/services/event_create_service_spec.rb107
-rw-r--r--spec/services/git/base_hooks_service_spec.rb94
-rw-r--r--spec/services/git/tag_push_service_spec.rb1
-rw-r--r--spec/services/google_cloud/generate_pipeline_service_spec.rb11
-rw-r--r--spec/services/groups/create_service_spec.rb29
-rw-r--r--spec/services/groups/destroy_service_spec.rb40
-rw-r--r--spec/services/groups/transfer_service_spec.rb4
-rw-r--r--spec/services/groups/update_service_spec.rb9
-rw-r--r--spec/services/groups/update_shared_runners_service_spec.rb2
-rw-r--r--spec/services/import/fogbugz_service_spec.rb2
-rw-r--r--spec/services/import/gitlab_projects/file_acquisition_strategies/file_upload_spec.rb2
-rw-r--r--spec/services/incident_management/timeline_event_tags/create_service_spec.rb71
-rw-r--r--spec/services/incident_management/timeline_events/create_service_spec.rb107
-rw-r--r--spec/services/incident_management/timeline_events/update_service_spec.rb6
-rw-r--r--spec/services/issuable/discussions_list_service_spec.rb27
-rw-r--r--spec/services/issues/close_service_spec.rb21
-rw-r--r--spec/services/issues/create_service_spec.rb61
-rw-r--r--spec/services/issues/export_csv_service_spec.rb2
-rw-r--r--spec/services/issues/move_service_spec.rb48
-rw-r--r--spec/services/issues/relative_position_rebalancing_service_spec.rb12
-rw-r--r--spec/services/issues/reopen_service_spec.rb20
-rw-r--r--spec/services/issues/update_service_spec.rb33
-rw-r--r--spec/services/labels/promote_service_spec.rb2
-rw-r--r--spec/services/loose_foreign_keys/process_deleted_records_service_spec.rb198
-rw-r--r--spec/services/markup/rendering_service_spec.rb163
-rw-r--r--spec/services/members/destroy_service_spec.rb25
-rw-r--r--spec/services/members/invite_service_spec.rb6
-rw-r--r--spec/services/members/update_service_spec.rb356
-rw-r--r--spec/services/merge_requests/approval_service_spec.rb32
-rw-r--r--spec/services/merge_requests/build_service_spec.rb14
-rw-r--r--spec/services/merge_requests/create_service_spec.rb43
-rw-r--r--spec/services/merge_requests/mergeability/run_checks_service_spec.rb22
-rw-r--r--spec/services/merge_requests/mergeability_check_service_spec.rb30
-rw-r--r--spec/services/merge_requests/remove_approval_service_spec.rb16
-rw-r--r--spec/services/merge_requests/squash_service_spec.rb9
-rw-r--r--spec/services/merge_requests/update_service_spec.rb4
-rw-r--r--spec/services/milestones/transfer_service_spec.rb4
-rw-r--r--spec/services/namespaces/statistics_refresher_service_spec.rb19
-rw-r--r--spec/services/notes/build_service_spec.rb8
-rw-r--r--spec/services/notes/update_service_spec.rb2
-rw-r--r--spec/services/notification_service_spec.rb17
-rw-r--r--spec/services/packages/composer/composer_json_service_spec.rb2
-rw-r--r--spec/services/packages/maven/metadata/create_versions_xml_service_spec.rb17
-rw-r--r--spec/services/packages/npm/create_package_service_spec.rb4
-rw-r--r--spec/services/packages/rpm/repository_metadata/base_builder_spec.rb33
-rw-r--r--spec/services/packages/rpm/repository_metadata/build_filelist_xml_service_spec.rb54
-rw-r--r--spec/services/packages/rpm/repository_metadata/build_filelist_xml_spec.rb21
-rw-r--r--spec/services/packages/rpm/repository_metadata/build_other_xml_service_spec.rb27
-rw-r--r--spec/services/packages/rpm/repository_metadata/build_other_xml_spec.rb21
-rw-r--r--spec/services/packages/rpm/repository_metadata/build_primary_xml_service_spec.rb23
-rw-r--r--spec/services/packages/rpm/repository_metadata/build_primary_xml_spec.rb35
-rw-r--r--spec/services/packages/rpm/repository_metadata/build_repomd_xml_service_spec.rb86
-rw-r--r--spec/services/packages/rpm/repository_metadata/build_repomd_xml_spec.rb86
-rw-r--r--spec/services/packages/rpm/repository_metadata/update_xml_service_spec.rb177
-rw-r--r--spec/services/projects/hashed_storage/migrate_repository_service_spec.rb2
-rw-r--r--spec/services/projects/lfs_pointers/lfs_download_service_spec.rb2
-rw-r--r--spec/services/projects/move_users_star_projects_service_spec.rb5
-rw-r--r--spec/services/projects/prometheus/alerts/notify_service_spec.rb10
-rw-r--r--spec/services/protected_branches/api_service_spec.rb34
-rw-r--r--spec/services/protected_branches/cache_service_spec.rb11
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb15
-rw-r--r--spec/services/resource_access_tokens/revoke_service_spec.rb34
-rw-r--r--spec/services/resource_events/change_milestone_service_spec.rb31
-rw-r--r--spec/services/resource_events/change_state_service_spec.rb10
-rw-r--r--spec/services/search/group_service_spec.rb2
-rw-r--r--spec/services/search_service_spec.rb154
-rw-r--r--spec/services/security/ci_configuration/sast_parser_service_spec.rb8
-rw-r--r--spec/services/security/merge_reports_service_spec.rb4
-rw-r--r--spec/services/system_notes/issuables_service_spec.rb4
-rw-r--r--spec/services/tags/create_service_spec.rb20
-rw-r--r--spec/services/todo_service_spec.rb2
-rw-r--r--spec/services/todos/destroy/entity_leave_service_spec.rb6
-rw-r--r--spec/services/topics/merge_service_spec.rb8
-rw-r--r--spec/services/users/approve_service_spec.rb2
-rw-r--r--spec/services/users/ban_service_spec.rb2
-rw-r--r--spec/services/users/destroy_service_spec.rb620
-rw-r--r--spec/services/users/migrate_records_to_ghost_user_in_batches_service_spec.rb29
-rw-r--r--spec/services/users/migrate_records_to_ghost_user_service_spec.rb92
-rw-r--r--spec/services/users/migrate_to_ghost_user_service_spec.rb97
-rw-r--r--spec/services/users/reject_service_spec.rb31
-rw-r--r--spec/services/users/unban_service_spec.rb2
-rw-r--r--spec/services/web_hook_service_spec.rb43
-rw-r--r--spec/services/work_items/create_service_spec.rb10
-rw-r--r--spec/services/work_items/update_service_spec.rb28
-rw-r--r--spec/services/work_items/widgets/hierarchy_service/update_service_spec.rb22
-rw-r--r--spec/services/work_items/widgets/milestone_service/create_service_spec.rb28
-rw-r--r--spec/services/work_items/widgets/milestone_service/update_service_spec.rb58
-rw-r--r--spec/services/x509_certificate_revoke_service_spec.rb6
-rw-r--r--spec/spec_helper.rb11
-rw-r--r--spec/support/database/multiple_databases.rb161
-rw-r--r--spec/support/database/query_recorder.rb9
-rw-r--r--spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb4
-rw-r--r--spec/support/google_api/cloud_platform_helpers.rb2
-rw-r--r--spec/support/helpers/bare_repo_operations.rb44
-rw-r--r--spec/support/helpers/ci/template_helpers.rb45
-rw-r--r--spec/support/helpers/content_security_policy_helpers.rb20
-rw-r--r--spec/support/helpers/database/multiple_databases_helpers.rb112
-rw-r--r--spec/support/helpers/features/access_token_helpers.rb19
-rw-r--r--spec/support/helpers/features/releases_helpers.rb2
-rw-r--r--spec/support/helpers/filter_spec_helper.rb5
-rw-r--r--spec/support/helpers/filtered_search_helpers.rb4
-rw-r--r--spec/support/helpers/full_name_helper.rb9
-rw-r--r--spec/support/helpers/git_helpers.rb11
-rw-r--r--spec/support/helpers/graphql_helpers.rb2
-rw-r--r--spec/support/helpers/kubernetes_helpers.rb25
-rw-r--r--spec/support/helpers/navbar_structure_helper.rb6
-rw-r--r--spec/support/helpers/reference_parser_helpers.rb4
-rw-r--r--spec/support/helpers/search_helpers.rb4
-rw-r--r--spec/support/helpers/stub_configuration.rb4
-rw-r--r--spec/support/helpers/stub_feature_flags.rb4
-rw-r--r--spec/support/helpers/test_env.rb42
-rw-r--r--spec/support/helpers/usage_data_helpers.rb12
-rw-r--r--spec/support/matchers/exceed_query_limit.rb2
-rw-r--r--spec/support/matchers/graphql_matchers.rb6
-rw-r--r--spec/support/migration.rb36
-rw-r--r--spec/support/models/ci/partitioning_testing/cascade_check.rb27
-rw-r--r--spec/support/models/ci/partitioning_testing/partition_identifiers.rb13
-rw-r--r--spec/support/models/ci/partitioning_testing/rspec_hooks.rb19
-rw-r--r--spec/support/models/ci/partitioning_testing/schema_helpers.rb86
-rw-r--r--spec/support/models/partitionable_check.rb46
-rw-r--r--spec/support/multiple_databases.rb25
-rw-r--r--spec/support/rate_limiter.rb7
-rw-r--r--spec/support/redis.rb6
-rw-r--r--spec/support/rspec.rb3
-rw-r--r--spec/support/rspec_order_todo.yml27
-rw-r--r--spec/support/services/issuable_update_service_shared_examples.rb40
-rw-r--r--spec/support/services/migrate_to_ghost_user_service_shared_examples.rb3
-rw-r--r--spec/support/shared_contexts/container_repositories_shared_context.rb1
-rw-r--r--spec/support/shared_contexts/graphql/resolvers/runners_resolver_shared_context.rb2
-rw-r--r--spec/support/shared_contexts/jobs/handling_retried_jobs_shared_context.rb26
-rw-r--r--spec/support/shared_contexts/lib/sbom/package_url_shared_contexts.rb26
-rw-r--r--spec/support/shared_contexts/navbar_structure_context.rb5
-rw-r--r--spec/support/shared_contexts/policies/group_policy_shared_context.rb1
-rw-r--r--spec/support/shared_contexts/policies/project_policy_shared_context.rb4
-rw-r--r--spec/support/shared_contexts/policies/project_policy_table_shared_context.rb57
-rw-r--r--spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/bulk_imports/common/pipelines/wiki_pipeline_examples.rb4
-rw-r--r--spec/support/shared_examples/ci/retryable_shared_examples.rb16
-rw-r--r--spec/support/shared_examples/controllers/preferred_language_switcher_shared_examples.rb22
-rw-r--r--spec/support/shared_examples/features/access_tokens_shared_examples.rb34
-rw-r--r--spec/support/shared_examples/features/confidential_notes_shared_examples.rb34
-rw-r--r--spec/support/shared_examples/features/content_editor_shared_examples.rb16
-rw-r--r--spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb11
-rw-r--r--spec/support/shared_examples/features/editable_merge_request_shared_examples.rb10
-rw-r--r--spec/support/shared_examples/features/packages_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/features/runners_shared_examples.rb19
-rw-r--r--spec/support/shared_examples/features/search/redacted_search_results_shared_examples.rb304
-rw-r--r--spec/support/shared_examples/features/search/search_timeouts_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/features/variable_list_shared_examples.rb19
-rw-r--r--spec/support/shared_examples/finders/issues_finder_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/graphql/mutations/incident_management/timeline_events_shared_examples.rb10
-rw-r--r--spec/support/shared_examples/graphql/notes_creation_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/graphql/resolvers/packages_resolvers_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/graphql/types/gitlab_style_deprecations_shared_examples.rb21
-rw-r--r--spec/support/shared_examples/lib/cache_helpers_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/lib/email/email_shared_examples.rb140
-rw-r--r--spec/support/shared_examples/lib/gitlab/database/reestablished_connection_stack_shared_examples.rb3
-rw-r--r--spec/support/shared_examples/lib/gitlab/event_store_shared_examples.rb10
-rw-r--r--spec/support/shared_examples/lib/gitlab/experimentation_shared_examples.rb22
-rw-r--r--spec/support/shared_examples/lib/gitlab/gitaly_client_shared_examples.rb46
-rw-r--r--spec/support/shared_examples/lib/gitlab/template/template_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/lib/sentry/client_shared_examples.rb37
-rw-r--r--spec/support/shared_examples/mailers/notify_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/metrics/active_record_subscriber_shared_examples.rb5
-rw-r--r--spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb150
-rw-r--r--spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb34
-rw-r--r--spec/support/shared_examples/models/concerns/limitable_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/models/concerns/ttl_expirable_shared_examples.rb7
-rw-r--r--spec/support/shared_examples/models/integrations/base_ci_shared_examples.rb7
-rw-r--r--spec/support/shared_examples/models/integrations/base_monitoring_shared_examples.rb7
-rw-r--r--spec/support/shared_examples/models/integrations/base_slash_commands_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/models/integrations/has_web_hook_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/models/packages/debian/component_file_shared_example.rb2
-rw-r--r--spec/support/shared_examples/models/wiki_shared_examples.rb84
-rw-r--r--spec/support/shared_examples/quick_actions/issuable/max_issuable_examples.rb75
-rw-r--r--spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb119
-rw-r--r--spec/support/shared_examples/requests/api/discussions_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/graphql/issuable_search_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb170
-rw-r--r--spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/graphql/projects/branch_protections/access_level_request_examples.rb77
-rw-r--r--spec/support/shared_examples/requests/api/issues_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/requests/api/members_shared_examples.rb8
-rw-r--r--spec/support/shared_examples/requests/api/multiple_and_scoped_issue_boards_shared_examples.rb1
-rw-r--r--spec/support/shared_examples/requests/api/notes_shared_examples.rb7
-rw-r--r--spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb21
-rw-r--r--spec/support/shared_examples/requests/api/terraform/modules/v1/packages_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/services/alert_management_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/services/base_rpm_service_shared_examples.rb52
-rw-r--r--spec/support/shared_examples/services/issuable/discussions_list_shared_examples.rb112
-rw-r--r--spec/support/shared_examples/services/merge_status_updated_trigger_shared_examples.rb17
-rw-r--r--spec/support/shared_examples/services/users/dismiss_user_callout_service_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/work_items/widgets/milestone_service_shared_examples.rb42
-rw-r--r--spec/support/shared_examples/uploaders/object_storage_shared_examples.rb5
-rw-r--r--spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb56
-rw-r--r--spec/support/sidekiq_middleware.rb9
-rw-r--r--spec/support/webmock.rb7
-rw-r--r--spec/support_specs/database/multiple_databases_helpers_spec.rb121
-rw-r--r--spec/support_specs/database/multiple_databases_spec.rb120
-rw-r--r--spec/support_specs/graphql/arguments_spec.rb4
-rw-r--r--spec/tasks/gitlab/sidekiq_rake_spec.rb42
-rw-r--r--spec/tasks/gitlab/update_templates_rake_spec.rb7
-rw-r--r--spec/tooling/danger/project_helper_spec.rb6
-rw-r--r--spec/tooling/lib/tooling/find_codeowners_spec.rb4
-rw-r--r--spec/tooling/lib/tooling/helm3_client_spec.rb26
-rw-r--r--spec/tooling/rspec_flaky/example_spec.rb9
-rw-r--r--spec/tooling/rspec_flaky/flaky_example_spec.rb79
-rw-r--r--spec/tooling/rspec_flaky/flaky_examples_collection_spec.rb3
-rw-r--r--spec/tooling/rspec_flaky/listener_spec.rb2
-rw-r--r--spec/tooling/rspec_flaky/report_spec.rb1
-rw-r--r--spec/uploaders/job_artifact_uploader_spec.rb2
-rw-r--r--spec/uploaders/object_storage/cdn/google_cdn_spec.rb46
-rw-r--r--spec/uploaders/object_storage/cdn_spec.rb27
-rw-r--r--spec/validators/branch_filter_validator_spec.rb44
-rw-r--r--spec/validators/web_hooks/wildcard_branch_filter_validator_spec.rb44
-rw-r--r--spec/views/admin/application_settings/_jira_connect.html.haml_spec.rb23
-rw-r--r--spec/views/admin/application_settings/general.html.haml_spec.rb10
-rw-r--r--spec/views/admin/dashboard/index.html.haml_spec.rb2
-rw-r--r--spec/views/devise/confirmations/almost_there.html.haml_spec.rb37
-rw-r--r--spec/views/events/event/_common.html.haml_spec.rb17
-rw-r--r--spec/views/groups/observability.html.haml_spec.rb18
-rw-r--r--spec/views/groups/observability/observability.html.haml_spec.rb18
-rw-r--r--spec/views/layouts/header/_gitlab_version.html.haml_spec.rb17
-rw-r--r--spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb18
-rw-r--r--spec/views/projects/artifacts/_artifact.html.haml_spec.rb85
-rw-r--r--spec/views/projects/commit/_commit_box.html.haml_spec.rb2
-rw-r--r--spec/views/projects/commit/show.html.haml_spec.rb8
-rw-r--r--spec/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml_spec.rb4
-rw-r--r--spec/views/projects/merge_requests/_commits.html.haml_spec.rb12
-rw-r--r--spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb13
-rw-r--r--spec/views/projects/merge_requests/edit.html.haml_spec.rb4
-rw-r--r--spec/views/search/show.html.haml_spec.rb10
-rw-r--r--spec/views/shared/access_tokens/_table.html.haml_spec.rb151
-rw-r--r--spec/views/shared/deploy_tokens/_form.html.haml_spec.rb62
-rw-r--r--spec/views/shared/issuable/_sidebar.html.haml_spec.rb6
-rw-r--r--spec/workers/bulk_imports/entity_worker_spec.rb25
-rw-r--r--spec/workers/bulk_imports/export_request_worker_spec.rb95
-rw-r--r--spec/workers/bulk_imports/pipeline_worker_spec.rb54
-rw-r--r--spec/workers/ci/job_artifacts/track_artifact_report_worker_spec.rb23
-rw-r--r--spec/workers/cluster_configure_istio_worker_spec.rb41
-rw-r--r--spec/workers/cluster_update_app_worker_spec.rb112
-rw-r--r--spec/workers/cluster_wait_for_app_update_worker_spec.rb27
-rw-r--r--spec/workers/cluster_wait_for_ingress_ip_address_worker_spec.rb32
-rw-r--r--spec/workers/clusters/applications/wait_for_uninstall_app_worker_spec.rb32
-rw-r--r--spec/workers/concerns/reenqueuer_spec.rb21
-rw-r--r--spec/workers/container_registry/cleanup_worker_spec.rb81
-rw-r--r--spec/workers/container_registry/delete_container_repository_worker_spec.rb146
-rw-r--r--spec/workers/database/batched_background_migration/execution_worker_spec.rb141
-rw-r--r--spec/workers/every_sidekiq_worker_spec.rb5
-rw-r--r--spec/workers/gitlab/github_import/pull_requests/import_review_request_worker_spec.rb46
-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.rb31
-rw-r--r--spec/workers/gitlab/github_import/stage/import_pull_requests_reviews_worker_spec.rb3
-rw-r--r--spec/workers/gitlab_shell_worker_spec.rb50
-rw-r--r--spec/workers/incident_management/add_severity_system_note_worker_spec.rb25
-rw-r--r--spec/workers/loose_foreign_keys/cleanup_worker_spec.rb36
-rw-r--r--spec/workers/mail_scheduler/notification_service_worker_spec.rb39
-rw-r--r--spec/workers/merge_requests/delete_branch_worker_spec.rb65
-rw-r--r--spec/workers/merge_requests/delete_source_branch_worker_spec.rb120
-rw-r--r--spec/workers/namespaces/root_statistics_worker_spec.rb13
-rw-r--r--spec/workers/pages/invalidate_domain_cache_worker_spec.rb61
-rw-r--r--spec/workers/pages_worker_spec.rb24
-rw-r--r--spec/workers/projects/after_import_worker_spec.rb2
-rw-r--r--spec/workers/projects/post_creation_worker_spec.rb34
-rw-r--r--spec/workers/remove_expired_members_worker_spec.rb26
-rw-r--r--spec/workers/repository_check/single_repository_worker_spec.rb62
-rw-r--r--spec/workers/repository_import_worker_spec.rb32
-rw-r--r--spec/workers/run_pipeline_schedule_worker_spec.rb53
-rw-r--r--spec/workers/users/migrate_records_to_ghost_user_in_batches_worker_spec.rb12
-rw-r--r--storybook/config/webpack.config.js22
-rw-r--r--tests.yml5
-rw-r--r--tooling/config/CODEOWNERS.yml5
-rw-r--r--tooling/danger/project_helper.rb7
-rw-r--r--tooling/lib/tooling/helm3_client.rb2
-rw-r--r--tooling/rspec_flaky/example.rb7
-rw-r--r--tooling/rspec_flaky/flaky_example.rb12
-rw-r--r--tooling/rspec_flaky/listener.rb2
-rw-r--r--vendor/gems/bundler-checksum/lib/bundler/checksum.rb3
-rw-r--r--vendor/gems/ipynbdiff/lib/transformer.rb2
-rw-r--r--vendor/gems/ipynbdiff/spec/transformer_spec.rb11
-rw-r--r--vendor/project_templates/cluster_management.tar.gzbin14040 -> 13552 bytes
-rw-r--r--workhorse/config.toml.example11
-rw-r--r--workhorse/go.mod76
-rw-r--r--workhorse/go.sum1586
-rw-r--r--workhorse/internal/config/config.go99
-rw-r--r--workhorse/internal/config/config_test.go99
-rw-r--r--workhorse/internal/config/url_openers.go51
-rw-r--r--workhorse/internal/config/url_openers_test.go117
-rw-r--r--workhorse/internal/upload/artifacts_store_test.go2
-rw-r--r--workhorse/internal/upload/destination/objectstore/gocloud_object.go7
-rw-r--r--workhorse/internal/upstream/routes.go2
-rw-r--r--workhorse/testdata/google_dummy_credentials.json12
-rw-r--r--workhorse/upload_test.go2
-rw-r--r--yarn.lock235
5877 files changed, 239027 insertions, 138025 deletions
diff --git a/.eslintignore b/.eslintignore
index 1d069e19385..5428964b1ce 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -8,4 +8,6 @@
/vendor/
/sitespeed-result/
/fixtures/**/*.graphql
+# Storybook build artifacts
+/storybook/public
spec/fixtures/**/*.graphql
diff --git a/.eslintrc.yml b/.eslintrc.yml
index 659ed2a0010..f814bdc6434 100644
--- a/.eslintrc.yml
+++ b/.eslintrc.yml
@@ -163,6 +163,7 @@ overrides:
- '*.stories.js'
rules:
filenames/match-regex: off
+ '@gitlab/require-i18n-strings': off
- files:
- '*.graphql'
plugins:
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 689c05f4874..edbbe90a774 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -45,13 +45,14 @@ workflow:
RUBY_VERSION: "3.0"
# For (detached) merge request pipelines.
- if: '$CI_MERGE_REQUEST_IID'
- # For the maintenance scheduled pipelines, we set specific variables.
- - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "schedule" && $SCHEDULE_TYPE == "maintenance"'
+ # For the scheduled pipelines, we set specific variables.
+ - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PIPELINE_SOURCE == "schedule"'
variables:
CRYSTALBALL: "true"
+ CREATE_INCIDENT_FOR_PIPELINE_FAILURE: "true"
NOTIFY_PIPELINE_FAILURE_CHANNEL: "master-broken"
# Run pipelines for ruby3 branch
- - if: '$CI_COMMIT_BRANCH == "ruby3"'
+ - if: '$CI_COMMIT_BRANCH == "ruby3" && $CI_PIPELINE_SOURCE == "schedule"'
variables:
RUBY_VERSION: "3.0"
NOTIFY_PIPELINE_FAILURE_CHANNEL: "f_ruby3"
@@ -62,9 +63,12 @@ workflow:
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $GITLAB_USER_LOGIN =~ /project_\d+_bot\d*/'
variables:
GITLAB_DEPENDENCY_PROXY_ADDRESS: ""
+ CREATE_INCIDENT_FOR_PIPELINE_FAILURE: "true"
+ NOTIFY_PIPELINE_FAILURE_CHANNEL: "master-broken"
# For `$CI_DEFAULT_BRANCH` branch, create a pipeline (this includes on schedules, pushes, merges, etc.).
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
variables:
+ CREATE_INCIDENT_FOR_PIPELINE_FAILURE: "true"
NOTIFY_PIPELINE_FAILURE_CHANNEL: "master-broken"
# For tags, create a pipeline.
- if: '$CI_COMMIT_TAG'
@@ -95,7 +99,7 @@ variables:
GIT_SUBMODULE_STRATEGY: "none"
GET_SOURCES_ATTEMPTS: "3"
DEBIAN_VERSION: "bullseye"
- CHROME_VERSION: "103"
+ CHROME_VERSION: "106"
DOCKER_VERSION: "20.10.14"
RUBY_VERSION: "2.7"
GO_VERSION: "1.18"
@@ -127,7 +131,7 @@ variables:
# Run with decomposed databases by default
DECOMPOSED_DB: "true"
- DOCS_REVIEW_APPS_DOMAIN: "35.193.151.162.nip.io"
+ DOCS_REVIEW_APPS_DOMAIN: "docs.gitlab-review.app"
DOCS_GITLAB_REPO_SUFFIX: "ee"
REVIEW_APPS_IMAGE: "${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/ruby-3.0:gcloud-383-kubectl-1.23-helm-3.5"
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index 1ea65fe4de5..2bb47c77ba5 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -2,7 +2,7 @@
# project here: https://gitlab.com/gitlab-org/gitlab/-/project_members
# As described in https://docs.gitlab.com/ee/user/project/code_owners.html
-* @gitlab-org/maintainers/rails-backend @gitlab-org/maintainers/frontend @gitlab-org/maintainers/database @gl-quality/qe-maintainers @gitlab-org/delivery @gitlab-org/maintainers/cicd-templates @kwiebers @nolith @jacobvosmaer-gitlab @gitlab-org/tw-leadership
+* @gitlab-org/maintainers/rails-backend @gitlab-org/maintainers/frontend @gitlab-org/maintainers/database @gl-quality/qe-maintainers @gl-quality/tooling-maintainers @gitlab-org/delivery @gitlab-org/maintainers/cicd-templates @nolith @jacobvosmaer-gitlab @gitlab-org/tw-leadership
CODEOWNERS @gitlab-org/development-leaders @gitlab-org/tw-leadership
docs/CODEOWNERS @gitlab-org/development-leaders @gitlab-org/tw-leadership
@@ -49,7 +49,6 @@ GITALY_SERVER_VERSION @project_278964_bot6 @gitlab-org/maintainers/rails-backend
/ee/lib/ee/gitlab/background_migration/ @gitlab-org/maintainers/database
/lib/gitlab/database/ @gitlab-org/maintainers/database
/lib/gitlab/sql/ @gitlab-org/maintainers/database
-/lib/gitlab/github_import/ @gitlab-org/maintainers/database
/app/finders/ @gitlab-org/maintainers/database
/ee/app/finders/ @gitlab-org/maintainers/database
/rubocop/rubocop-migrations.yml @gitlab-org/maintainers/database
@@ -82,90 +81,28 @@ Dangerfile @gl-quality/eng-prod
/ee/lib/ee/gitlab/auth/ldap/ @dblessing @mkozono
/lib/gitlab/auth/ldap/ @dblessing @mkozono
-^[Verify]
-/app/**/ci/ @gitlab-org/maintainers/cicd-verify
-/app/controllers/admin/jobs_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/controllers/admin/runner_projects_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/controllers/admin/runners_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/controllers/projects/artifacts_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/controllers/projects/build_artifacts_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/controllers/projects/builds_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/controllers/projects/jobs_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/controllers/runner_setup_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/controllers/projects/pipeline_schedules_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/controllers/projects/pipelines_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/controllers/projects/pipelines_settings_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/controllers/projects/runner_projects_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/controllers/projects/runners_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/controllers/projects/triggers_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/controllers/projects/usage_quotas_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/controllers/projects/variables_controller.rb @gitlab-org/maintainers/cicd-verify
-/app/models/commit_status.rb @gitlab-org/maintainers/cicd-verify
-/app/models/external_pull_request.rb @gitlab-org/maintainers/cicd-verify
-/app/models/generic_commit_status.rb @gitlab-org/maintainers/cicd-verify
-/app/models/namespace_ci_cd_setting.rb @gitlab-org/maintainers/cicd-verify
-/app/models/project_ci_cd_setting.rb @gitlab-org/maintainers/cicd-verify
-/app/presenters/commit_status_presenter.rb @gitlab-org/maintainers/cicd-verify
-/app/presenters/generic_commit_status_presenter.rb @gitlab-org/maintainers/cicd-verify
-/app/views/projects/artifacts/ @gitlab-org/maintainers/cicd-verify
-/app/views/projects/generic_commit_statuses/ @gitlab-org/maintainers/cicd-verify
-/app/views/projects/jobs/ @gitlab-org/maintainers/cicd-verify
-/app/views/projects/pipeline_schedules/ @gitlab-org/maintainers/cicd-verify
-/app/views/projects/pipelines/ @gitlab-org/maintainers/cicd-verify
-/app/views/projects/triggers/ @gitlab-org/maintainers/cicd-verify
-/app/workers/build_hooks_worker.rb @gitlab-org/maintainers/cicd-verify
-/app/workers/build_queue_worker.rb @gitlab-org/maintainers/cicd-verify
-/app/workers/build_success_worker.rb @gitlab-org/maintainers/cicd-verify
-/app/workers/ci_platform_metrics_update_cron_worker.rb @gitlab-org/maintainers/cicd-verify
-/app/workers/create_pipeline_worker.rb @gitlab-org/maintainers/cicd-verify
-/app/workers/expire_build_artifacts_worker.rb @gitlab-org/maintainers/cicd-verify
-/app/workers/pipeline_hooks_worker.rb @gitlab-org/maintainers/cicd-verify
-/app/workers/pipeline_metrics_worker.rb @gitlab-org/maintainers/cicd-verify
-/app/workers/pipeline_notification_worker.rb @gitlab-org/maintainers/cicd-verify
-/app/workers/pipeline_process_worker.rb @gitlab-org/maintainers/cicd-verify
-/app/workers/pipeline_schedule_worker.rb @gitlab-org/maintainers/cicd-verify
-/app/workers/run_pipeline_schedule_worker.rb @gitlab-org/maintainers/cicd-verify
-/app/workers/stuck_ci_jobs_worker.rb @gitlab-org/maintainers/cicd-verify
-/app/workers/update_external_pull_requests_worker.rb @gitlab-org/maintainers/cicd-verify
-/lib/**/ci/ @gitlab-org/maintainers/cicd-verify
-/lib/api/commit_statuses.rb @gitlab-org/maintainers/cicd-verify
-/ee/app/**/ci/ @gitlab-org/maintainers/cicd-verify
-/ee/app/**/merge_trains/ @gitlab-org/maintainers/cicd-verify
-/ee/app/models/merge_train.rb @gitlab-org/maintainers/cicd-verify
-/ee/app/finders/merge_trains_finder.rb @gitlab-org/maintainers/cicd-verify
-/ee/app/services/auto_merge/add_to_merge_train_when_pipeline_succeeds_service.rb @gitlab-org/maintainers/cicd-verify
-/ee/app/services/auto_merge/merge_train_service.rb @gitlab-org/maintainers/cicd-verify
-/ee/app/services/system_notes/merge_train_service.rb @gitlab-org/maintainers/cicd-verify
-/ee/app/controllers/ee/admin/runners_controller.rb @gitlab-org/maintainers/cicd-verify
-/ee/app/controllers/ee/projects/pipelines_controller.rb @gitlab-org/maintainers/cicd-verify
-/ee/app/controllers/projects/pipelines/ @gitlab-org/maintainers/cicd-verify
-/ee/app/controllers/projects/subscriptions_controller.rb @gitlab-org/maintainers/cicd-verify
-/ee/app/models/merge_train.rb @gitlab-org/maintainers/cicd-verify
-/ee/app/helpers/ee/projects/pipeline_helper.rb @gitlab-org/maintainers/cicd-verify
-/ee/app/views/ci_minutes_usage_mailer/ @gitlab-org/maintainers/cicd-verify
-/ee/app/views/projects/pipelines/ @gitlab-org/maintainers/cicd-verify
-/ee/app/views/projects/settings/ci_cd/ @gitlab-org/maintainers/cicd-verify
-/ee/app/workers/clear_shared_runners_minutes_worker.rb @gitlab-org/maintainers/cicd-verify
-/ee/lib/**/ci/ @gitlab-org/maintainers/cicd-verify
-/ee/lib/ee/api/entities/merge_train.rb @gitlab-org/maintainers/cicd-verify
-/**/javascripts/jobs/ @gitlab-org/ci-cd/verify/frontend
-/**/javascripts/pipelines/ @gitlab-org/ci-cd/verify/frontend
-/app/assets/javascripts/pipeline_new/ @gitlab-org/ci-cd/verify/frontend
-/app/assets/javascripts/ci_lint/ @gitlab-org/ci-cd/verify/frontend
-/app/assets/javascripts/ci_variable_list/ @gitlab-org/ci-cd/verify/frontend
-/app/assets/javascripts/pipeline_schedules/ @gitlab-org/ci-cd/verify/frontend
-/app/assets/javascripts/pipeline_editor/ @gitlab-org/ci-cd/verify/frontend
-/app/assets/javascripts/runner/ @gitlab-org/ci-cd/verify/frontend
-/ee/app/assets/javascripts/ci_minutes_usage/ @gitlab-org/ci-cd/verify/frontend
-/ee/app/assets/javascripts/usage_quotas/ci_minutes_usage/ @gitlab-org/ci-cd/verify/frontend
-/ee/app/assets/javascripts/usage_quotas/pipelines/ @gitlab-org/ci-cd/verify/frontend
-/ee/app/assets/javascripts/reports/ @gitlab-org/ci-cd/verify/frontend
-
^[Templates]
/lib/gitlab/ci/templates/ @gitlab-org/maintainers/cicd-templates
/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @DylanGriffith @mayra-cabrera @tkuah
/lib/gitlab/ci/templates/Security/ @gonzoyumo @twoodham @sethgitlab @thiagocsf
-/lib/gitlab/ci/templates/Security/Container-Scanning.*.yml @gitlab-org/govern/security-policies-backend
+/lib/gitlab/ci/templates/Security/API-Fuzzing.*.yml @gitlab-org/secure/dynamic-analysis
+/lib/gitlab/ci/templates/Security/Container-Scanning.*.yml @gitlab-org/secure/composition-analysis-be
+/lib/gitlab/ci/templates/Security/Coverage-Fuzzing.*.yml @gitlab-org/secure/dynamic-analysis
+/lib/gitlab/ci/templates/Security/DAST.*.yml @gitlab-org/secure/dynamic-analysis
+/lib/gitlab/ci/templates/Security/Dependency-Scanning.*.yml @gitlab-org/secure/composition-analysis-be
+/lib/gitlab/ci/templates/Security/License-Scanning.*.yml @gitlab-org/secure/composition-analysis-be
+/lib/gitlab/ci/templates/Security/SAST.*.yml @gitlab-org/secure/static-analysis
+/lib/gitlab/ci/templates/Security/Secret-Detection.*.yml @gitlab-org/secure/static-analysis
+/lib/gitlab/ci/templates/Security/Secure-Binaries.*.yml @gitlab-org/secure/static-analysis @gitlab-org/secure/composition-analysis-be @gitlab-org/secure/dynamic-analysis
+# Note: The `Fortify-FoD-sast.gitlab-ci.yml` template is provided and maintained by Fortify, an official Technology Partner with GitLab.
+/lib/gitlab/ci/templates/Jobs/API-Fuzzing.*.yml @gitlab-org/secure/dynamic-analysis
+/lib/gitlab/ci/templates/Jobs/Container-Scanning.*.yml @gitlab-org/secure/composition-analysis-be
+/lib/gitlab/ci/templates/Jobs/Coverage-Fuzzing.*.yml @gitlab-org/secure/dynamic-analysis
+/lib/gitlab/ci/templates/Jobs/DAST.*.yml @gitlab-org/secure/dynamic-analysis
+/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.*.yml @gitlab-org/secure/composition-analysis-be
+/lib/gitlab/ci/templates/Jobs/License-Scanning.*.yml @gitlab-org/secure/composition-analysis-be
+/lib/gitlab/ci/templates/Jobs/SAST.*.yml @gitlab-org/secure/static-analysis
+/lib/gitlab/ci/templates/Jobs/Secret-Detection.*.yml @gitlab-org/secure/static-analysis
^[Project Alias]
/ee/app/models/project_alias.rb @patrickbajao
@@ -186,6 +123,8 @@ Dangerfile @gl-quality/eng-prod
/ee/spec/policies/vulnerabilities/ @gitlab-org/govern/threat-insights-backend-team
/ee/spec/policies/vulnerability*.rb @gitlab-org/govern/threat-insights-backend-team
/ee/spec/presenters/projects/security/ @gitlab-org/govern/threat-insights-backend-team
+/ee/app/assets/javascripts/license_compliance/components/detected_licenses_table.vue @gitlab-org/govern/threat-insights-frontend-team
+/ee/spec/frontend/license_compliance/components/detected_licenses_table_spec.js @gitlab-org/govern/threat-insights-frontend-team
^[Secure]
/ee/lib/gitlab/ci/parsers/license_compliance/ @gitlab-org/secure/composition-analysis-be
@@ -196,24 +135,120 @@ Dangerfile @gl-quality/eng-prod
/ee/lib/gitlab/ci/reports/security/ @gitlab-org/secure/composition-analysis-be @gitlab-org/secure/dynamic-analysis-be @gitlab-org/secure/static-analysis-be @gitlab-org/secure/fuzzing-be
/ee/app/services/app_sec/dast/ @gitlab-org/secure/dynamic-analysis-be
-^[Container Security]
-/ee/app/views/projects/threat_monitoring/** @gitlab-org/govern/security-policies-frontend
+^[Security Policies]
+/ee/app/assets/javascripts/approvals/components/license_compliance/** @gitlab-org/govern/security-policies-frontend
+/ee/app/assets/javascripts/approvals/stores/modules/license_compliance/** @gitlab-org/govern/security-policies-frontend
+/ee/app/assets/javascripts/license_compliance/** @gitlab-org/govern/security-policies-frontend
+/ee/app/assets/javascripts/pages/projects/licenses/** @gitlab-org/govern/security-policies-frontend
+/ee/app/assets/javascripts/pages/projects/pipelines/licenses/** @gitlab-org/govern/security-policies-frontend
+/ee/app/assets/javascripts/pages/projects/pipelines/show/license_report.js
+/ee/app/assets/javascripts/vue_merge_request_widget/extensions/license_compliance/** @gitlab-org/govern/security-policies-frontend
+/ee/app/assets/javascripts/vue_shared/license_compliance/** @gitlab-org/govern/security-policies-frontend
+/ee/app/views/projects/licenses/** @gitlab-org/govern/security-policies-frontend
+/ee/spec/frontend/approvals/components/license_compliance/** @gitlab-org/govern/security-policies-frontend
+/ee/spec/frontend/approvals/stores/modules/license_compliance/** @gitlab-org/govern/security-policies-frontend
+/ee/spec/frontend/license_compliance/** @gitlab-org/govern/security-policies-frontend
+/ee/spec/frontend/vue_merge_request_widget/extensions/license_compliance/** @gitlab-org/govern/security-policies-frontend
+/ee/spec/frontend/vue_shared/license_compliance/** @gitlab-org/govern/security-policies-frontend
+
+/ee/app/assets/javascripts/approvals/components/security_orchestration/** @gitlab-org/govern/security-policies-frontend
+/ee/app/assets/javascripts/approvals/stores/modules/security_orchestration/** @gitlab-org/govern/security-policies-frontend
+/ee/app/assets/javascripts/pages/groups/security/policies/** @gitlab-org/govern/security-policies-frontend
+/ee/app/assets/javascripts/pages/projects/security/policies/** @gitlab-org/govern/security-policies-frontend
+/ee/app/assets/javascripts/security_orchestration/** @gitlab-org/govern/security-policies-frontend
+/ee/app/views/groups/security/policies @gitlab-org/govern/security-policies-frontend
/ee/app/views/projects/security/policies/** @gitlab-org/govern/security-policies-frontend
+/ee/spec/frontend/approvals/components/security_orchestration/** @gitlab-org/govern/security-policies-frontend
+/ee/spec/frontend/approvals/stores/modules/security_orchestration/** @gitlab-org/govern/security-policies-frontend
+/ee/spec/frontend/security_orchestration/** @gitlab-org/govern/security-policies-frontend
/ee/spec/views/projects/security/policies/** @gitlab-org/govern/security-policies-frontend
-/ee/app/assets/javascripts/pages/projects/threat_monitoring/** @gitlab-org/govern/security-policies-frontend
-/ee/app/assets/javascripts/threat_monitoring/** @gitlab-org/govern/security-policies-frontend
-/ee/spec/frontend/threat_monitoring/** @gitlab-org/govern/security-policies-frontend
-/ee/app/controllers/projects/threat_monitoring_controller.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/controllers/projects/threat_monitoring_controller_spec.rb @gitlab-org/govern/container-security-backend
+/app/models/clusters/applications/cilium.rb @gitlab-org/govern/security-policies-backend
+/ee/app/controllers/groups/security/policies_controller.rb @gitlab-org/govern/security-policies-backend
/ee/app/controllers/projects/security/policies_controller.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/requests/projects/security/policies_controller_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/app/graphql/mutations/concerns/mutations/finds_project_or_group_for_security_policies.rb @gitlab-org/govern/security-policies-backend
+/ee/app/graphql/mutations/security_policy/** @gitlab-org/govern/security-policies-backend
+/ee/app/graphql/resolvers/concerns/resolves_orchestration_policy.rb @gitlab-org/govern/security-policies-backend
+/ee/app/graphql/resolvers/security_orchestration/** @gitlab-org/govern/security-policies-backend
+/ee/app/graphql/types/security_orchestration/** @gitlab-org/govern/security-policies-backend
+/ee/app/helpers/ee/security_orchestration_helper.rb @gitlab-org/govern/security-policies-backend
/ee/app/models/security/orchestration_policy_configuration.rb @gitlab-org/govern/security-policies-backend
-/ee/spec/models/security/orchestration_policy_configuration_spec.rb @gitlab-org/govern/security-policies-backend
-/app/models/clusters/applications/cilium.rb @gitlab-org/govern/security-policies-backend
-/spec/models/clusters/applications/cilium_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/app/models/security/orchestration_policy_rule_schedule.rb @gitlab-org/govern/security-policies-backend
/ee/app/services/security/orchestration/** @gitlab-org/govern/security-policies-backend
+/ee/app/services/security/security_orchestration_policies/** @gitlab-org/govern/security-policies-backend
+/ee/app/validators/json_schemas/security_orchestration_policy.json @gitlab-org/govern/security-policies-backend
+/ee/app/workers/concerns/update_orchestration_policy_configuration.rb @gitlab-org/govern/security-policies-backend
+/ee/app/workers/security/create_orchestration_policy_worker.rb @gitlab-org/govern/security-policies-backend
+/ee/app/workers/security/orchestration_policy_rule_schedule_namespace_worker.rb @gitlab-org/govern/security-policies-backend
+/ee/app/workers/security/orchestration_policy_rule_schedule_worker.rb @gitlab-org/govern/security-policies-backend
+/ee/lib/ee/gitlab/ci/pipeline/chain/validate/security_orchestration_policy.rb @gitlab-org/govern/security-policies-backend
+/ee/lib/gitlab/ci/config/security_orchestration_policies/** @gitlab-org/govern/security-policies-backend
+/ee/lib/gitlab/graphql/aggregations/security_orchestration_policies/** @gitlab-org/govern/security-policies-backend
+/ee/spec/controllers/groups/security/policies_controller_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/factories/security_orchestration_policy_configurations.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/factories/security_orchestration_policy_rule_schedules.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/factories/security/policies.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/graphql/mutations/security_policy/** @gitlab-org/govern/security-policies-backend
+/ee/spec/graphql/resolvers/security_orchestration/** @gitlab-org/govern/security-policies-backend
+/ee/spec/graphql/types/security_orchestration/** @gitlab-org/govern/security-policies-backend
+/ee/spec/helpers/ee/security_orchestration_helper_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/lib/ee/gitlab/ci/pipeline/chain/validate/security_orchestration_policy_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/lib/gitlab/ci/config/security_orchestration_policies/** @gitlab-org/govern/security-policies-backend
+/ee/spec/lib/gitlab/graphql/aggregations/security_orchestration_policies/** @gitlab-org/govern/security-policies-backend
+/ee/spec/models/security/orchestration_policy_configuration_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/models/security/orchestration_policy_rule_schedule_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/requests/api/graphql/mutations/security_policy/** @gitlab-org/govern/security-policies-backend
+/ee/spec/requests/api/graphql/project/security_orchestration/** @gitlab-org/govern/security-policies-backend
+/ee/spec/requests/projects/security/policies_controller_spec.rb @gitlab-org/govern/security-policies-backend
/ee/spec/services/security/orchestration/** @gitlab-org/govern/security-policies-backend
+/ee/spec/services/security/security_orchestration_policies/** @gitlab-org/govern/security-policies-backend
+/ee/spec/support/shared_contexts/graphql/resolvers/security_orchestration/** @gitlab-org/govern/security-policies-backend
+/ee/spec/views/projects/security/policies/index.html.haml_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/workers/concerns/update_orchestration_policy_configuration_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/workers/security/create_orchestration_policy_worker_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/workers/security/orchestration_policy_rule_schedule_namespace_worker_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/workers/security/orchestration_policy_rule_schedule_worker_spec.rb @gitlab-org/govern/security-policies-backend
+/lib/gitlab/ci/pipeline/chain/validate/security_orchestration_policy.rb @gitlab-org/govern/security-policies-backend
+/spec/models/clusters/applications/cilium_spec.rb @gitlab-org/govern/security-policies-backend
+
+/app/finders/security/license_compliance_jobs_finder.rb @gitlab-org/govern/security-policies-backend
+/ee/app/controllers/projects/licenses_controller.rb @gitlab-org/govern/security-policies-backend
+/ee/app/finders/software_license_policies_finder.rb @gitlab-org/govern/security-policies-backend
+/ee/app/models/sca/license_compliance.rb @gitlab-org/govern/security-policies-backend @gitlab-org/secure/composition-analysis-be
+/ee/app/models/sca/license_policy.rb @gitlab-org/govern/security-policies-backend
+/ee/app/models/software_license_policy.rb @gitlab-org/govern/security-policies-backend
+/ee/app/models/software_license.rb @gitlab-org/govern/security-policies-backend
+/ee/app/serializers/license_compliance/** @gitlab-org/govern/security-policies-backend
+/ee/app/serializers/license_entity.rb @gitlab-org/govern/security-policies-backend
+/ee/app/serializers/license_serializer.rb @gitlab-org/govern/security-policies-backend
+/ee/app/serializers/licenses_list_entity.rb @gitlab-org/govern/security-policies-backend
+/ee/app/serializers/licenses_list_serializer.rb @gitlab-org/govern/security-policies-backend
+/ee/app/serializers/security/license_policy_entity.rb @gitlab-org/govern/security-policies-backend
+/ee/app/services/ci/compare_license_scanning_reports_collapsed_service.rb @gitlab-org/govern/security-policies-backend
+/ee/app/services/ci/compare_license_scanning_reports_service.rb @gitlab-org/govern/security-policies-backend
+/ee/app/services/projects/licenses/** @gitlab-org/govern/security-policies-backend
+/ee/app/services/software_license_policies/** @gitlab-org/govern/security-policies-backend
+/ee/app/services/software_license_policies/update_service.rb @gitlab-org/govern/security-policies-backend
+/ee/app/workers/refresh_license_compliance_checks_worker.rb @gitlab-org/govern/security-policies-backend
+/ee/lib/api/managed_licenses.rb @gitlab-org/govern/security-policies-backend
+/ee/lib/ee/api/entities/managed_license.rb @gitlab-org/govern/security-policies-backend
+/ee/lib/gitlab/spdx/license.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/factories/software_license_policy.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/factories/software_license.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/factories/spdx_license.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/finders/software_license_policies_finder_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/lib/gitlab/ci/parsers/license_compliance/** @gitlab-org/govern/security-policies-backend
+/ee/spec/models/sca/license_compliance_spec.rb @gitlab-org/govern/security-policies-backend @gitlab-org/secure/composition-analysis-be
+/ee/spec/models/sca/license_policy_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/models/software_license_policy_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/models/software_license_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/requests/api/managed_licenses_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/serializers/license_compliance/** @gitlab-org/govern/security-policies-backend
+/ee/spec/services/ci/compare_license_scanning_reports_collapsed_service_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/services/ci/compare_license_scanning_reports_service_spec.rb @gitlab-org/govern/security-policies-backend
+/ee/spec/services/projects/licenses/** @gitlab-org/govern/security-policies-backend
+/ee/spec/services/software_license_policies/** @gitlab-org/govern/security-policies-backend
+/spec/finders/security/license_compliance_jobs_finder_spec.rb @gitlab-org/govern/security-policies-backend
^[Code Owners]
/ee/lib/gitlab/code_owners.rb @reprazent @kerrizor @garyh
@@ -253,10 +288,25 @@ Dangerfile @gl-quality/eng-prod
/spec/frontend/batch_comments/ @viktomas @jboyson @iamphill @thomasrandolph
^[Product Intelligence]
-/ee/lib/gitlab/usage_data_counters/ @gitlab-org/growth/product-intelligence/engineers
-/ee/lib/ee/gitlab/usage_data.rb @gitlab-org/growth/product-intelligence/engineers
-/lib/gitlab/usage_data.rb @gitlab-org/growth/product_intelligence/engineers
-/lib/gitlab/usage_data_counters/ @gitlab-org/growth/product-intelligence/engineers
+/ee/lib/gitlab/usage_data_counters/ @gitlab-org/analytics-section/product-intelligence/engineers
+/ee/lib/ee/gitlab/usage_data.rb @gitlab-org/analytics-section/product-intelligence/engineers
+/lib/gitlab/usage_data.rb @gitlab-org/analytics-section/product-intelligence/engineers
+/lib/gitlab/usage_data_counters/ @gitlab-org/analytics-section/product-intelligence/engineers
+/lib/gitlab/usage/ @gitlab-org/analytics-section/product-intelligence/engineers
+/ee/lib/ee/gitlab/usage_data_counters/ @gitlab-org/analytics-section/product-intelligence/engineers
+/ee/lib/ee/gitlab/usage/ @gitlab-org/analytics-section/product-intelligence/engineers
+/config/metrics/ @gitlab-org/analytics-section/product-intelligence/engineers
+/ee/config/metrics/ @gitlab-org/analytics-section/product-intelligence/engineers
+/app/workers/gitlab_service_ping_worker.rb @gitlab-org/analytics-section/product-intelligence/engineers
+/spec/workers/gitlab_service_ping_worker_spec.rb @gitlab-org/analytics-section/product-intelligence/engineers
+/ee/spec/lib/gitlab/usage_data_counters/ @gitlab-org/analytics-section/product-intelligence/engineers
+/ee/spec/lib/ee/gitlab/usage_data_spec.rb @gitlab-org/analytics-section/product-intelligence/engineers
+/spec/lib/gitlab/usage_data_spec.rb @gitlab-org/analytics-section/product-intelligence/engineers
+/spec/lib/gitlab/usage_data_counters/ @gitlab-org/analytics-section/product-intelligence/engineers
+/spec/lib/gitlab/usage/ @gitlab-org/analytics-section/product-intelligence/engineers
+/ee/spec/lib/ee/gitlab/usage_data_counters/ @gitlab-org/analytics-section/product-intelligence/engineers
+/ee/spec/lib/ee/gitlab/usage/ @gitlab-org/analytics-section/product-intelligence/engineers
+/ee/spec/config/metrics/ @gitlab-org/analytics-section/product-intelligence/engineers
^[Growth Experiments]
/app/experiments/ @gitlab-org/growth/experiment-devs
@@ -315,7 +365,7 @@ Dangerfile @gl-quality/eng-prod
/config/dependency_decisions.yml @gitlab-org/legal-reviewers
^[Workhorse]
-/workhorse/ @jacobvosmaer-gitlab @nolith @patrickbajao
+/workhorse/ @jacobvosmaer-gitlab @nolith @patrickbajao @igor.drozdov
[Application Security]
/app/assets/javascripts/lib/dompurify.js @gitlab-com/gl-security/appsec
@@ -347,7 +397,9 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/data/removals/ @gl-docsteam
^[Documentation Pages]
-/doc/administration/application_settings_cache.md @sselhorn
+# This block is managed by the rake script at lib/tasks/gitlab/tw/codeowners.rake, manual updates will be overwritten!
+# Begin rake-managed-docs-block
+/doc/administration/application_settings_cache.md @jglassman1
/doc/administration/audit_event_streaming.md @eread
/doc/administration/audit_events.md @eread
/doc/administration/audit_reports.md @eread
@@ -373,7 +425,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/administration/geo/setup/ @axil
/doc/administration/git_protocol.md @aqualls
/doc/administration/gitaly/ @eread
-/doc/administration/housekeeping.md @axil
+/doc/administration/housekeeping.md @eread
/doc/administration/inactive_project_deletion.md @eread
/doc/administration/incoming_email.md @msedlakjakubowski
/doc/administration/index.md @axil
@@ -386,7 +438,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/administration/invalidate_markdown_cache.md @msedlakjakubowski
/doc/administration/issue_closing_pattern.md @aqualls
/doc/administration/job_artifacts.md @marcel.amirault
-/doc/administration/job_logs.md @sselhorn
+/doc/administration/job_logs.md @fneill
/doc/administration/lfs/ @aqualls
/doc/administration/libravatar.md @axil
/doc/administration/load_balancer.md @axil
@@ -396,11 +448,11 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/administration/merge_request_diffs.md @ashrafkhamis
/doc/administration/monitoring/ @msedlakjakubowski
/doc/administration/monitoring/gitlab_self_monitoring_project/ @msedlakjakubowski
-/doc/administration/monitoring/ip_allowlist.md @sselhorn
+/doc/administration/monitoring/ip_allowlist.md @jglassman1
/doc/administration/monitoring/performance/ @msedlakjakubowski
/doc/administration/monitoring/prometheus/ @msedlakjakubowski
/doc/administration/monitoring/prometheus/index.md @axil
-/doc/administration/monitoring/prometheus/web_exporter.md @sselhorn
+/doc/administration/monitoring/prometheus/web_exporter.md @jglassman1
/doc/administration/nfs.md @axil
/doc/administration/object_storage.md @axil
/doc/administration/operations/ @axil
@@ -426,7 +478,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/administration/restart_gitlab.md @axil
/doc/administration/server_hooks.md @eread
/doc/administration/sidekiq/ @axil
-/doc/administration/sidekiq/sidekiq_memory_killer.md @sselhorn
+/doc/administration/sidekiq/sidekiq_memory_killer.md @jglassman1
/doc/administration/smime_signing_email.md @axil
/doc/administration/snippets/ @ashrafkhamis
/doc/administration/static_objects_external_storage.md @ashrafkhamis
@@ -461,7 +513,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/deploy_tokens.md @rdickenson
/doc/api/deployments.md @rdickenson
/doc/api/discussions.md @aqualls
-/doc/api/dora/ @fneill
+/doc/api/dora/ @lciutacu
/doc/api/environments.md @rdickenson
/doc/api/epic_issues.md @msedlakjakubowski
/doc/api/epic_links.md @msedlakjakubowski
@@ -484,8 +536,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/graphql/sample_issue_boards.md @msedlakjakubowski
/doc/api/graphql/users_example.md @jglassman1
/doc/api/group_access_tokens.md @jglassman1
-/doc/api/group_activity_analytics.md @fneill
-/doc/api/group_badges.md @fneill
+/doc/api/group_activity_analytics.md @lciutacu
+/doc/api/group_badges.md @lciutacu
/doc/api/group_boards.md @msedlakjakubowski
/doc/api/group_clusters.md @phillipwells
/doc/api/group_import_export.md @eread
@@ -498,7 +550,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/group_releases.md @rdickenson
/doc/api/group_repository_storage_moves.md @ashrafkhamis
/doc/api/group_wikis.md @ashrafkhamis
-/doc/api/groups.md @fneill
+/doc/api/groups.md @lciutacu
/doc/api/import.md @eread
/doc/api/index.md @ashrafkhamis
/doc/api/instance_clusters.md @phillipwells
@@ -569,7 +621,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/resource_milestone_events.md @msedlakjakubowski
/doc/api/resource_state_events.md @msedlakjakubowski
/doc/api/resource_weight_events.md @msedlakjakubowski
-/doc/api/runners.md @sselhorn
+/doc/api/runners.md @fneill
/doc/api/saml.md @jglassman1
/doc/api/scim.md @jglassman1
/doc/api/search.md @ashrafkhamis
@@ -588,7 +640,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/templates/gitlab_ci_ymls.md @marcel.amirault
/doc/api/templates/licenses.md @rdickenson
/doc/api/todos.md @msedlakjakubowski
-/doc/api/topics.md @fneill
+/doc/api/topics.md @lciutacu
/doc/api/usage_data.md @claytoncornell
/doc/api/users.md @jglassman1
/doc/api/version.md @phillipwells
@@ -597,12 +649,9 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/api/vulnerability_exports.md @claytoncornell
/doc/api/vulnerability_findings.md @claytoncornell
/doc/api/wikis.md @ashrafkhamis
-/doc/architecture/blueprints/ci_pipeline_components/ @marcel.amirault
-/doc/architecture/blueprints/container_registry_metadata_database/ @claytoncornell
/doc/architecture/blueprints/database/scalability/patterns/ @aqualls
/doc/architecture/blueprints/database_scaling/ @aqualls
-/doc/architecture/blueprints/gitlab_to_kubernetes_communication/ @phillipwells
-/doc/architecture/blueprints/work_items/ @msedlakjakubowski
+/doc/architecture/blueprints/runner_tokens/ @fneill
/doc/ci/ @marcel.amirault
/doc/ci/caching/ @marcel.amirault
/doc/ci/chatops/ @phillipwells
@@ -615,7 +664,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/ci/cloud_services/google_cloud/ @marcel.amirault
/doc/ci/directed_acyclic_graph/ @marcel.amirault
/doc/ci/docker/ @marcel.amirault
-/doc/ci/docker/using_docker_images.md @sselhorn
+/doc/ci/docker/using_docker_images.md @fneill
/doc/ci/environments/ @rdickenson
/doc/ci/examples/ @marcel.amirault
/doc/ci/examples/authenticating-with-hashicorp-vault/ @marcel.amirault
@@ -623,22 +672,22 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/ci/examples/end_to_end_testing_webdriverio/ @marcel.amirault
/doc/ci/examples/laravel_with_gitlab_and_envoy/ @marcel.amirault
/doc/ci/examples/semantic-release.md @claytoncornell
-/doc/ci/interactive_web_terminal/ @sselhorn
+/doc/ci/interactive_web_terminal/ @fneill
/doc/ci/introduction/ @marcel.amirault
/doc/ci/jobs/ @marcel.amirault
-/doc/ci/large_repositories/ @sselhorn
+/doc/ci/large_repositories/ @fneill
/doc/ci/migration/ @marcel.amirault
/doc/ci/pipeline_editor/ @marcel.amirault
/doc/ci/pipelines/ @marcel.amirault
/doc/ci/quick_start/ @marcel.amirault
/doc/ci/resource_groups/ @rdickenson
/doc/ci/review_apps/ @marcel.amirault
-/doc/ci/runners/ @sselhorn
-/doc/ci/runners/saas/ @sselhorn
-/doc/ci/runners/saas/macos/ @sselhorn
+/doc/ci/runners/ @fneill
+/doc/ci/runners/saas/ @fneill
+/doc/ci/runners/saas/macos/ @fneill
/doc/ci/secrets/ @marcel.amirault
/doc/ci/secure_files/ @marcel.amirault
-/doc/ci/services/ @sselhorn
+/doc/ci/services/ @fneill
/doc/ci/ssh_keys/ @marcel.amirault
/doc/ci/test_cases/ @msedlakjakubowski
/doc/ci/testing/ @marcel.amirault
@@ -654,7 +703,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/backend/create_source_code_be/ @aqualls
/doc/development/build_test_package.md @axil
/doc/development/bulk_import.md @eread
-/doc/development/cached_queries.md @sselhorn
+/doc/development/cached_queries.md @jglassman1
/doc/development/cascading_settings.md @jglassman1
/doc/development/chatops_on_gitlabcom.md @phillipwells
/doc/development/cicd/ @marcel.amirault
@@ -662,7 +711,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/contributing/ @sselhorn
/doc/development/database/ @aqualls
/doc/development/database/filtering_by_label.md @msedlakjakubowski
-/doc/development/database/multiple_databases.md @sselhorn
+/doc/development/database/multiple_databases.md @jglassman1
/doc/development/database_review.md @aqualls
/doc/development/developing_with_solargraph.md @aqualls
/doc/development/development_processes.md @sselhorn
@@ -694,7 +743,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/graphql_guide/ @ashrafkhamis
/doc/development/graphql_guide/batchloader.md @aqualls
/doc/development/i18n/ @eread
-/doc/development/image_scaling.md @sselhorn
+/doc/development/image_scaling.md @jglassman1
/doc/development/import_export.md @eread
/doc/development/index.md @sselhorn
/doc/development/integrations/codesandbox.md @sselhorn
@@ -718,10 +767,11 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/permissions.md @jglassman1
/doc/development/policies.md @jglassman1
/doc/development/product_qualified_lead_guide/ @phillipwells
-/doc/development/project_templates.md @fneill
+/doc/development/project_templates.md @lciutacu
/doc/development/prometheus_metrics.md @msedlakjakubowski
/doc/development/real_time.md @msedlakjakubowski
/doc/development/sec/ @rdickenson
+/doc/development/sec/security_report_ingestion_overview.md @claytoncornell
/doc/development/secure_coding_guidelines.md @sselhorn
/doc/development/service_ping/ @claytoncornell
/doc/development/snowplow/ @claytoncornell
@@ -730,8 +780,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/development/testing_guide/ @sselhorn
/doc/development/testing_guide/contract/ @sselhorn
/doc/development/testing_guide/end_to_end/ @sselhorn
-/doc/development/value_stream_analytics.md @fneill
-/doc/development/value_stream_analytics/ @fneill
+/doc/development/value_stream_analytics.md @lciutacu
+/doc/development/value_stream_analytics/ @lciutacu
/doc/development/wikis.md @ashrafkhamis
/doc/development/work_items.md @msedlakjakubowski
/doc/development/work_items_widgets.md @msedlakjakubowski
@@ -763,14 +813,11 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/integration/sourcegraph.md @aqualls
/doc/integration/trello_power_up.md @ashrafkhamis
/doc/integration/vault.md @phillipwells
-/doc/operations/error_tracking.md msedlakjakubowski
+/doc/operations/ @msedlakjakubowski
/doc/operations/feature_flags.md @rdickenson
/doc/operations/incident_management/ @msedlakjakubowski
-/doc/operations/index.md @msedlakjakubowski
/doc/operations/metrics/ @msedlakjakubowski
/doc/operations/metrics/dashboards/ @msedlakjakubowski
-/doc/operations/product_analytics.md @lciutacu
-/doc/operations/tracing.md @msedlakjakubowski
/doc/policy/ @axil
/doc/raketasks/ @axil
/doc/raketasks/generate_sample_prometheus_data.md @msedlakjakubowski
@@ -798,7 +845,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/update/mysql_to_postgresql.md @aqualls
/doc/update/package/ @axil
/doc/update/upgrading_postgresql_using_slony.md @aqualls
-/doc/user/admin_area/analytics/ @fneill
+/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
@@ -833,10 +880,10 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/admin_area/settings/rate_limit_on_notes_creation.md @msedlakjakubowski
/doc/user/admin_area/settings/rate_limit_on_pipelines_creation.md @marcel.amirault
/doc/user/admin_area/settings/rate_limit_on_users_api.md @jglassman1
-/doc/user/admin_area/settings/third_party_offers.md @fneill
+/doc/user/admin_area/settings/third_party_offers.md @lciutacu
/doc/user/admin_area/settings/usage_statistics.md @claytoncornell
/doc/user/admin_area/settings/visibility_and_access_controls.md @aqualls
-/doc/user/analytics/ @fneill
+/doc/user/analytics/ @lciutacu
/doc/user/analytics/ci_cd_analytics.md @rdickenson
/doc/user/application_security/api_fuzzing/ @rdickenson
/doc/user/application_security/configuration/ @rdickenson
@@ -873,14 +920,14 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/discussions/ @aqualls
/doc/user/feature_flags.md @sselhorn
/doc/user/free_user_limit.md @phillipwells
-/doc/user/group/ @fneill
+/doc/user/group/ @lciutacu
/doc/user/group/clusters/ @phillipwells
-/doc/user/group/contribution_analytics/ @fneill
+/doc/user/group/contribution_analytics/ @lciutacu
/doc/user/group/custom_project_templates.md @eread
-/doc/user/group/devops_adoption/ @fneill
+/doc/user/group/devops_adoption/ @lciutacu
/doc/user/group/epics/ @msedlakjakubowski
/doc/user/group/import/ @eread
-/doc/user/group/insights/ @fneill
+/doc/user/group/insights/ @lciutacu
/doc/user/group/issues_analytics/ @msedlakjakubowski
/doc/user/group/iterations/ @msedlakjakubowski
/doc/user/group/planning_hierarchy/ @msedlakjakubowski
@@ -889,18 +936,18 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/group/saml_sso/ @jglassman1
/doc/user/group/settings/group_access_tokens.md @jglassman1
/doc/user/group/settings/import_export.md @eread
-/doc/user/group/subgroups/ @fneill
-/doc/user/group/value_stream_analytics/ @fneill
+/doc/user/group/subgroups/ @lciutacu
+/doc/user/group/value_stream_analytics/ @lciutacu
/doc/user/infrastructure/ @phillipwells
/doc/user/infrastructure/clusters/ @phillipwells
/doc/user/infrastructure/clusters/connect/ @phillipwells
/doc/user/infrastructure/clusters/deploy/ @phillipwells
/doc/user/infrastructure/clusters/manage/ @phillipwells
/doc/user/infrastructure/clusters/manage/management_project_applications/ @phillipwells
-/doc/user/infrastructure/clusters/manage/management_project_applications/runner.md @sselhorn
+/doc/user/infrastructure/clusters/manage/management_project_applications/runner.md @fneill
/doc/user/infrastructure/iac/ @phillipwells
/doc/user/markdown.md @aqualls
-/doc/user/namespace/ @fneill
+/doc/user/namespace/ @lciutacu
/doc/user/packages/ @claytoncornell
/doc/user/packages/composer_repository/ @claytoncornell
/doc/user/packages/conan_repository/ @claytoncornell
@@ -911,18 +958,19 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/packages/go_proxy/ @claytoncornell
/doc/user/packages/harbor_container_registry/ @claytoncornell
/doc/user/packages/helm_repository/ @claytoncornell
-/doc/user/packages/infrastructure_registry/ @phillipwells
+/doc/user/packages/infrastructure_registry/ @claytoncornell
/doc/user/packages/maven_repository/ @claytoncornell
/doc/user/packages/npm_registry/ @claytoncornell
/doc/user/packages/nuget_repository/ @claytoncornell
/doc/user/packages/package_registry/ @claytoncornell
/doc/user/packages/pypi_repository/ @claytoncornell
/doc/user/packages/rubygems_registry/ @claytoncornell
-/doc/user/packages/terraform_module_registry/ @phillipwells
+/doc/user/packages/terraform_module_registry/ @claytoncornell
/doc/user/packages/workflows/ @claytoncornell
/doc/user/permissions.md @jglassman1
/doc/user/profile/ @jglassman1
/doc/user/profile/account/ @jglassman1
+/doc/user/profile/contributions_calendar.md @lciutacu
/doc/user/profile/notifications.md @msedlakjakubowski
/doc/user/project/ @aqualls
/doc/user/project/clusters/ @phillipwells
@@ -933,8 +981,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/project/description_templates.md @msedlakjakubowski
/doc/user/project/import/ @eread
/doc/user/project/import/jira.md @msedlakjakubowski
-/doc/user/project/index.md @fneill
-/doc/user/project/insights/ @fneill
+/doc/user/project/index.md @lciutacu
+/doc/user/project/insights/ @lciutacu
/doc/user/project/integrations/ @ashrafkhamis
/doc/user/project/integrations/prometheus.md @msedlakjakubowski
/doc/user/project/integrations/prometheus_library/ @msedlakjakubowski
@@ -942,7 +990,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/project/issues/ @msedlakjakubowski
/doc/user/project/issues/csv_import.md @eread
/doc/user/project/labels.md @msedlakjakubowski
-/doc/user/project/members/ @fneill
+/doc/user/project/members/ @lciutacu
/doc/user/project/merge_requests/ @aqualls
/doc/user/project/merge_requests/approvals/ @aqualls
/doc/user/project/merge_requests/csv_export.md @eread
@@ -955,6 +1003,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/project/pages/getting_started/ @ashrafkhamis
/doc/user/project/quick_actions.md @msedlakjakubowski
/doc/user/project/releases/ @rdickenson
+/doc/user/project/remote_development/ @ashrafkhamis
/doc/user/project/repository/ @aqualls
/doc/user/project/repository/branches/ @aqualls
/doc/user/project/repository/file_finder.md @ashrafkhamis
@@ -968,14 +1017,14 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/doc/user/project/requirements/ @msedlakjakubowski
/doc/user/project/service_desk.md @msedlakjakubowski
/doc/user/project/settings/import_export.md @eread
-/doc/user/project/settings/index.md @fneill
+/doc/user/project/settings/index.md @lciutacu
/doc/user/project/settings/project_access_tokens.md @jglassman1
/doc/user/project/time_tracking.md @msedlakjakubowski
/doc/user/project/web_ide/ @ashrafkhamis
/doc/user/project/wiki/ @ashrafkhamis
-/doc/user/project/working_with_projects.md @fneill
-/doc/user/public_access.md @fneill
-/doc/user/reserved_names.md @fneill
+/doc/user/project/working_with_projects.md @lciutacu
+/doc/user/public_access.md @lciutacu
+/doc/user/reserved_names.md @lciutacu
/doc/user/search/ @ashrafkhamis
/doc/user/search/global_search/ @ashrafkhamis
/doc/user/shortcuts.md @ashrafkhamis
@@ -984,7 +1033,8 @@ 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/ @fneill
+/doc/user/workspace/ @lciutacu
+# End rake-managed-docs-block
[Authentication and Authorization]
/app/assets/javascripts/access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
@@ -1003,18 +1053,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/app/assets/javascripts/pages/profiles/two_factor_auths/ @gitlab-org/manage/authentication-and-authorization/approvers
/app/assets/javascripts/pages/projects/settings/access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
/app/assets/javascripts/pages/sessions/new/oauth_remember_me.js @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/pipelines/components/pipelines_list/tokens/constants.js @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_branch_name_token.vue @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_source_token.vue @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_status_token.vue @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/pipelines/components/pipelines_list/tokens/pipeline_tag_name_token.vue @gitlab-org/manage/authentication-and-authorization/approvers
/app/assets/javascripts/projects/settings/topics/components/ @gitlab-org/manage/authentication-and-authorization/approvers
/app/assets/javascripts/related_issues/components/issue_token.vue @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/runner/components/registration/registration_token.vue @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/runner/components/registration/registration_token_reset_dropdown_item.vue @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/runner/components/search_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/token_access/components/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/assets/javascripts/token_access/index.js @gitlab-org/manage/authentication-and-authorization/approvers
/app/assets/stylesheets/page_bundles/profile_two_factor_auth.scss @gitlab-org/manage/authentication-and-authorization/approvers
/app/controllers/admin/impersonation_tokens_controller.rb @gitlab-org/manage/authentication-and-authorization/approvers
/app/controllers/concerns/access_tokens_actions.rb @gitlab-org/manage/authentication-and-authorization/approvers
@@ -1054,6 +1094,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/app/models/token_with_iv.rb @gitlab-org/manage/authentication-and-authorization/approvers
/app/models/webauthn_registration.rb @gitlab-org/manage/authentication-and-authorization/approvers
/app/policies/personal_access_token_policy.rb @gitlab-org/manage/authentication-and-authorization/approvers
+/app/serializers/access_token_entity_base.rb @gitlab-org/manage/authentication-and-authorization/approvers
/app/serializers/group_access_token_entity.rb @gitlab-org/manage/authentication-and-authorization/approvers
/app/serializers/group_access_token_serializer.rb @gitlab-org/manage/authentication-and-authorization/approvers
/app/serializers/impersonation_access_token_entity.rb @gitlab-org/manage/authentication-and-authorization/approvers
@@ -1081,7 +1122,6 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/app/views/admin/application_settings/_external_authorization_service_form.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
/app/views/admin/impersonation_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
/app/views/authentication/ @gitlab-org/manage/authentication-and-authorization/approvers
-/app/views/ci/token_access/ @gitlab-org/manage/authentication-and-authorization/approvers
/app/views/dashboard/projects/_zero_authorized_projects.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
/app/views/devise/mailer/password_change.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
/app/views/devise/mailer/password_change.text.erb @gitlab-org/manage/authentication-and-authorization/approvers
@@ -1107,6 +1147,8 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/app/views/notify/access_token_created_email.text.erb @gitlab-org/manage/authentication-and-authorization/approvers
/app/views/notify/access_token_expired_email.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
/app/views/notify/access_token_expired_email.text.erb @gitlab-org/manage/authentication-and-authorization/approvers
+/app/views/notify/access_token_revoked_email.html.haml @gitlab-org/manage/authentication-and-authorization/approvers
+/app/views/notify/access_token_revoked_email.text.erb @gitlab-org/manage/authentication-and-authorization/approvers
/app/views/profiles/passwords/ @gitlab-org/manage/authentication-and-authorization/approvers
/app/views/profiles/personal_access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
/app/views/profiles/two_factor_auths/ @gitlab-org/manage/authentication-and-authorization/approvers
@@ -1131,6 +1173,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/config/initializers/webauthn.rb @gitlab-org/manage/authentication-and-authorization/approvers
/config/initializers_before_autoloader/100_patch_omniauth_oauth2.rb @gitlab-org/manage/authentication-and-authorization/approvers
/config/initializers_before_autoloader/100_patch_omniauth_saml.rb @gitlab-org/manage/authentication-and-authorization/approvers
+/config/weak_password_digests.yml @gitlab-org/manage/authentication-and-authorization/approvers
/ee/app/assets/javascripts/access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
/ee/app/assets/javascripts/audit_events/components/tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
/ee/app/assets/javascripts/audit_events/token_utils.js @gitlab-org/manage/authentication-and-authorization/approvers
@@ -1141,9 +1184,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/ee/app/assets/javascripts/pages/passwords/ @gitlab-org/manage/authentication-and-authorization/approvers
/ee/app/assets/javascripts/pages/profiles/passwords/ @gitlab-org/manage/authentication-and-authorization/approvers
/ee/app/assets/javascripts/password/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/pipelines/components/pipelines_list/ @gitlab-org/manage/authentication-and-authorization/approvers
/ee/app/assets/javascripts/requirements/components/tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/app/assets/javascripts/runner/components/search_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
/ee/app/assets/javascripts/saml_providers/scim_token_service.js @gitlab-org/manage/authentication-and-authorization/approvers
/ee/app/assets/javascripts/saml_sso/components/ @gitlab-org/manage/authentication-and-authorization/approvers
/ee/app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals_auth.vue @gitlab-org/manage/authentication-and-authorization/approvers
@@ -1166,6 +1207,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/ee/app/models/ee/project_authorization.rb @gitlab-org/manage/authentication-and-authorization/approvers
/ee/app/models/scim_oauth_access_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
/ee/app/serializers/scim_oauth_access_token_entity.rb @gitlab-org/manage/authentication-and-authorization/approvers
+/ee/app/services/arkose/token_verification_service.rb @gitlab-org/manage/authentication-and-authorization/approvers
/ee/app/services/ee/auth/ @gitlab-org/manage/authentication-and-authorization/approvers
/ee/app/services/ee/personal_access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
/ee/app/services/ee/resource_access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
@@ -1191,23 +1233,22 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/ee/lib/ee/gitlab/auth/ @gitlab-org/manage/authentication-and-authorization/approvers
/ee/lib/ee/gitlab/omniauth_initializer.rb @gitlab-org/manage/authentication-and-authorization/approvers
/ee/lib/gitlab/auth/ @gitlab-org/manage/authentication-and-authorization/approvers
-/ee/lib/gitlab/auth_logger.rb @gitlab-org/manage/authentication-and-authorization/approvers
/ee/lib/gitlab/authority_analyzer.rb @gitlab-org/manage/authentication-and-authorization/approvers
/ee/lib/gitlab/geo/oauth/ @gitlab-org/manage/authentication-and-authorization/approvers
/ee/lib/gitlab/kerberos/ @gitlab-org/manage/authentication-and-authorization/approvers
/ee/lib/omni_auth/ @gitlab-org/manage/authentication-and-authorization/approvers
/ee/lib/system_check/geo/authorized_keys_check.rb @gitlab-org/manage/authentication-and-authorization/approvers
/ee/lib/system_check/geo/authorized_keys_flag_check.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/api/entities/ci/reset_token_result.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/api/entities/impersonation_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/api/entities/impersonation_token_with_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/api/entities/personal_access_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/api/entities/personal_access_token_with_details.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/api/entities/personal_access_token_with_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/api/entities/resource_access_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/api/entities/resource_access_token_with_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/api/helpers/authentication.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/api/helpers/packages/basic_auth_helpers.rb @gitlab-org/manage/authentication-and-authorization/approvers
+/lib/api/helpers/personal_access_tokens_helpers.rb @gitlab-org/manage/authentication-and-authorization/approvers
+/lib/api/personal_access_tokens/ @gitlab-org/manage/authentication-and-authorization/approvers
/lib/api/personal_access_tokens.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/api/resource_access_tokens.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/api/support/token_with_expiration.rb @gitlab-org/manage/authentication-and-authorization/approvers
@@ -1221,8 +1262,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/lib/gitlab/background_migration/migrate_u2f_webauthn.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/gitlab/background_migration/update_users_where_two_factor_auth_required_from_group.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/gitlab/chat_name_token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/ci/pipeline/expression/token.rb @gitlab-org/manage/authentication-and-authorization/approvers
-/lib/gitlab/cleanup/unused_personal_access_tokens.rb @gitlab-org/manage/authentication-and-authorization/approvers
+/lib/gitlab/cleanup/personal_access_tokens.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/gitlab/external_authorization/ @gitlab-org/manage/authentication-and-authorization/approvers
/lib/gitlab/external_authorization.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/gitlab/grape_logging/loggers/token_logger.rb @gitlab-org/manage/authentication-and-authorization/approvers
@@ -1235,11 +1275,90 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/lib/gitlab/project_authorizations.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/json_web_token/ @gitlab-org/manage/authentication-and-authorization/approvers
/lib/omni_auth/ @gitlab-org/manage/authentication-and-authorization/approvers
+/lib/security/weak_passwords.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/system_check/app/authorized_keys_permission_check.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/system_check/incoming_email/imap_authentication_check.rb @gitlab-org/manage/authentication-and-authorization/approvers
/lib/tasks/gitlab/password.rake @gitlab-org/manage/authentication-and-authorization/approvers
/lib/tasks/tokens.rake @gitlab-org/manage/authentication-and-authorization/approvers
+^[Verify]
+/app/**/ci/ @gitlab-org/maintainers/cicd-verify
+/app/controllers/admin/jobs_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/controllers/admin/runner_projects_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/controllers/admin/runners_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/controllers/projects/artifacts_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/controllers/projects/build_artifacts_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/controllers/projects/builds_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/controllers/projects/jobs_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/controllers/runner_setup_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/controllers/projects/pipeline_schedules_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/controllers/projects/pipelines_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/controllers/projects/pipelines_settings_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/controllers/projects/runner_projects_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/controllers/projects/runners_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/controllers/projects/triggers_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/controllers/projects/usage_quotas_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/controllers/projects/variables_controller.rb @gitlab-org/maintainers/cicd-verify
+/app/models/commit_status.rb @gitlab-org/maintainers/cicd-verify
+/app/models/external_pull_request.rb @gitlab-org/maintainers/cicd-verify
+/app/models/generic_commit_status.rb @gitlab-org/maintainers/cicd-verify
+/app/models/namespace_ci_cd_setting.rb @gitlab-org/maintainers/cicd-verify
+/app/models/project_ci_cd_setting.rb @gitlab-org/maintainers/cicd-verify
+/app/presenters/commit_status_presenter.rb @gitlab-org/maintainers/cicd-verify
+/app/presenters/generic_commit_status_presenter.rb @gitlab-org/maintainers/cicd-verify
+/app/views/projects/artifacts/ @gitlab-org/maintainers/cicd-verify
+/app/views/projects/generic_commit_statuses/ @gitlab-org/maintainers/cicd-verify
+/app/views/projects/jobs/ @gitlab-org/maintainers/cicd-verify
+/app/views/projects/pipeline_schedules/ @gitlab-org/maintainers/cicd-verify
+/app/views/projects/pipelines/ @gitlab-org/maintainers/cicd-verify
+/app/views/projects/triggers/ @gitlab-org/maintainers/cicd-verify
+/app/workers/build_hooks_worker.rb @gitlab-org/maintainers/cicd-verify
+/app/workers/build_queue_worker.rb @gitlab-org/maintainers/cicd-verify
+/app/workers/build_success_worker.rb @gitlab-org/maintainers/cicd-verify
+/app/workers/ci_platform_metrics_update_cron_worker.rb @gitlab-org/maintainers/cicd-verify
+/app/workers/create_pipeline_worker.rb @gitlab-org/maintainers/cicd-verify
+/app/workers/expire_build_artifacts_worker.rb @gitlab-org/maintainers/cicd-verify
+/app/workers/pipeline_hooks_worker.rb @gitlab-org/maintainers/cicd-verify
+/app/workers/pipeline_metrics_worker.rb @gitlab-org/maintainers/cicd-verify
+/app/workers/pipeline_notification_worker.rb @gitlab-org/maintainers/cicd-verify
+/app/workers/pipeline_process_worker.rb @gitlab-org/maintainers/cicd-verify
+/app/workers/pipeline_schedule_worker.rb @gitlab-org/maintainers/cicd-verify
+/app/workers/run_pipeline_schedule_worker.rb @gitlab-org/maintainers/cicd-verify
+/app/workers/stuck_ci_jobs_worker.rb @gitlab-org/maintainers/cicd-verify
+/app/workers/update_external_pull_requests_worker.rb @gitlab-org/maintainers/cicd-verify
+/lib/**/ci/ @gitlab-org/maintainers/cicd-verify
+/lib/api/commit_statuses.rb @gitlab-org/maintainers/cicd-verify
+/ee/app/**/ci/ @gitlab-org/maintainers/cicd-verify
+/ee/app/**/merge_trains/ @gitlab-org/maintainers/cicd-verify
+/ee/app/models/merge_train.rb @gitlab-org/maintainers/cicd-verify
+/ee/app/finders/merge_trains_finder.rb @gitlab-org/maintainers/cicd-verify
+/ee/app/services/auto_merge/add_to_merge_train_when_pipeline_succeeds_service.rb @gitlab-org/maintainers/cicd-verify
+/ee/app/services/auto_merge/merge_train_service.rb @gitlab-org/maintainers/cicd-verify
+/ee/app/services/system_notes/merge_train_service.rb @gitlab-org/maintainers/cicd-verify
+/ee/app/controllers/ee/admin/runners_controller.rb @gitlab-org/maintainers/cicd-verify
+/ee/app/controllers/ee/projects/pipelines_controller.rb @gitlab-org/maintainers/cicd-verify
+/ee/app/controllers/projects/pipelines/ @gitlab-org/maintainers/cicd-verify
+/ee/app/controllers/projects/subscriptions_controller.rb @gitlab-org/maintainers/cicd-verify
+/ee/app/models/merge_train.rb @gitlab-org/maintainers/cicd-verify
+/ee/app/helpers/ee/projects/pipeline_helper.rb @gitlab-org/maintainers/cicd-verify
+/ee/app/views/ci_minutes_usage_mailer/ @gitlab-org/maintainers/cicd-verify
+/ee/app/views/projects/pipelines/ @gitlab-org/maintainers/cicd-verify
+/ee/app/views/projects/settings/ci_cd/ @gitlab-org/maintainers/cicd-verify
+/ee/app/workers/clear_shared_runners_minutes_worker.rb @gitlab-org/maintainers/cicd-verify
+/ee/lib/**/ci/ @gitlab-org/maintainers/cicd-verify
+/ee/lib/ee/api/entities/merge_train.rb @gitlab-org/maintainers/cicd-verify
+/**/javascripts/jobs/ @gitlab-org/ci-cd/verify/frontend
+/**/javascripts/pipelines/ @gitlab-org/ci-cd/verify/frontend
+/app/assets/javascripts/ci/ @gitlab-org/ci-cd/verify/frontend
+/app/assets/javascripts/pipeline_new/ @gitlab-org/ci-cd/verify/frontend
+/app/assets/javascripts/ci_lint/ @gitlab-org/ci-cd/verify/frontend
+/app/assets/javascripts/ci_variable_list/ @gitlab-org/ci-cd/verify/frontend
+/app/assets/javascripts/ci/pipeline_schedules/ @gitlab-org/ci-cd/verify/frontend
+/app/assets/javascripts/pipeline_editor/ @gitlab-org/ci-cd/verify/frontend
+/ee/app/assets/javascripts/ci/ @gitlab-org/ci-cd/verify/frontend
+/ee/app/assets/javascripts/reports/ @gitlab-org/ci-cd/verify/frontend
+/app/assets/javascripts/token_access/ @gitlab-org/ci-cd/verify/frontend
+
[Manage::Workspace]
lib/api/entities/basic_project_details.rb @gitlab-org/manage/manage-workspace/backend-approvers
lib/api/entities/project_with_access.rb @gitlab-org/manage/manage-workspace/backend-approvers
@@ -1248,68 +1367,68 @@ lib/api/entities/project.rb @gitlab-org/manage/manage-workspace/backend-approver
ee/lib/ee/api/entities/project.rb @gitlab-org/manage/manage-workspace/backend-approvers
[Compliance]
-/ee/app/services/audit_events/build_service.rb @gitlab-org/manage/compliance
-/ee/spec/services/audit_events/custom_audit_event_service_spec.rb @gitlab-org/manage/compliance
-/app/models/audit_event.rb @gitlab-org/manage/compliance
-/app/services/audit_event_service.rb @gitlab-org/manage/compliance
-/app/services/concerns/audit_event_save_type.rb @gitlab-org/manage/compliance
-/app/views/profiles/audit_log.html.haml @gitlab-org/manage/compliance
-/ee/app/assets/javascripts/audit_events/components/audit_events_app.vue @gitlab-org/manage/compliance
-/ee/app/assets/javascripts/audit_events/components/audit_events_export_button.vue @gitlab-org/manage/compliance
-/ee/app/assets/javascripts/audit_events/components/audit_events_filter.vue @gitlab-org/manage/compliance
-/ee/app/assets/javascripts/audit_events/components/audit_events_log.vue @gitlab-org/manage/compliance
-/ee/app/assets/javascripts/audit_events/components/audit_events_stream.vue @gitlab-org/manage/compliance
-/ee/app/assets/javascripts/audit_events/components/audit_events_table.vue @gitlab-org/manage/compliance
-/ee/app/assets/javascripts/audit_events/components/tokens/shared/ @gitlab-org/manage/compliance
-/ee/app/assets/javascripts/audit_events/init_audit_events.js @gitlab-org/manage/compliance
-/ee/app/controllers/admin/audit_log_reports_controller.rb @gitlab-org/manage/compliance
-/ee/app/controllers/admin/audit_logs_controller.rb @gitlab-org/manage/compliance
-/ee/app/controllers/concerns/audit_events/audit_events_params.rb @gitlab-org/manage/compliance
-/ee/app/controllers/groups/audit_events_controller.rb @gitlab-org/manage/compliance
-/ee/app/controllers/projects/audit_events_controller.rb @gitlab-org/manage/compliance
-/ee/app/finders/audit_event_finder.rb @gitlab-org/manage/compliance
-/ee/app/graphql/types/audit_events/external_audit_event_destination_type.rb @gitlab-org/manage/compliance
-/ee/app/helpers/audit_events_helper.rb @gitlab-org/manage/compliance
-/ee/app/helpers/auditor_user_helper.rb @gitlab-org/manage/compliance
-/ee/app/models/audit_events/external_audit_event_destination.rb @gitlab-org/manage/compliance
-/ee/app/models/concerns/auditable.rb @gitlab-org/manage/compliance
-/ee/app/models/ee/audit_event.rb @gitlab-org/manage/compliance
-/ee/app/policies/audit_events/external_audit_event_destination_policy.rb @gitlab-org/manage/compliance
-/ee/app/presenters/audit_event_presenter.rb @gitlab-org/manage/compliance
-/ee/app/serializers/audit_event_entity.rb @gitlab-org/manage/compliance
-/ee/app/serializers/audit_event_serializer.rb @gitlab-org/manage/compliance
-/ee/app/services/ci/audit_variable_change_service.rb @gitlab-org/manage/compliance
-/ee/app/services/ee/audit_event_service.rb @gitlab-org/manage/compliance
-/ee/app/views/admin/users/_auditor_access_level_radio.html.haml @gitlab-org/manage/compliance
-/ee/app/views/admin/users/_auditor_user_badge.html.haml @gitlab-org/manage/compliance
-/ee/app/views/shared/icons/_icon_audit_events_purple.svg @gitlab-org/manage/compliance
-/ee/app/views/shared/promotions/_promote_audit_events.html.haml @gitlab-org/manage/compliance
-/ee/app/workers/audit_events/audit_event_streaming_worker.rb @gitlab-org/manage/compliance
-/ee/config/events/1652263097_groups__audit_events__index_click_streams_tab.yml @gitlab-org/manage/compliance
-/ee/config/events/202108302307_admin_audit_logs_index_click_date_range_button.yml @gitlab-org/manage/compliance
-/ee/config/events/202108302307_groups__audit_events_controller_search_audit_event.yml @gitlab-org/manage/compliance
-/ee/config/events/202108302307_profiles_controller_search_audit_event.yml @gitlab-org/manage/compliance
-/ee/config/events/202108302307_projects__audit_events_controller_search_audit_event.yml @gitlab-org/manage/compliance
-/ee/config/events/202111041910_admin__audit_logs_controller_search_audit_event.yml @gitlab-org/manage/compliance
-/ee/config/feature_flags/development/audit_event_streaming_git_operations.yml @gitlab-org/manage/compliance
-/ee/config/feature_flags/development/audit_log_group_level.yml @gitlab-org/manage/compliance
-/ee/config/metrics/counts_28d/20210216183930_g_compliance_audit_events_monthly.yml @gitlab-org/manage/compliance
-/ee/config/metrics/counts_28d/20210216183934_i_compliance_audit_events_monthly.yml @gitlab-org/manage/compliance
-/ee/config/metrics/counts_28d/20210216183942_a_compliance_audit_events_api_monthly.yml @gitlab-org/manage/compliance
-/ee/config/metrics/counts_28d/20211130085433_g_manage_compliance_audit_event_destinations.yml @gitlab-org/manage/compliance
-/ee/config/metrics/counts_7d/20210216183906_g_compliance_audit_events.yml @gitlab-org/manage/compliance
-/ee/config/metrics/counts_7d/20210216183908_i_compliance_audit_events.yml @gitlab-org/manage/compliance
-/ee/config/metrics/counts_7d/20210216183912_a_compliance_audit_events_api.yml @gitlab-org/manage/compliance
-/ee/config/metrics/counts_7d/20210216183928_g_compliance_audit_events_weekly.yml @gitlab-org/manage/compliance
-/ee/config/metrics/counts_7d/20210216183932_i_compliance_audit_events_weekly.yml @gitlab-org/manage/compliance
-/ee/config/metrics/counts_7d/20210216183940_a_compliance_audit_events_api_weekly.yml @gitlab-org/manage/compliance
-/ee/config/metrics/counts_all/20211130085433_g_manage_compliance_audit_event_destinations.yml @gitlab-org/manage/compliance
-/ee/lib/api/audit_events.rb @gitlab-org/manage/compliance
-/ee/lib/audit/external_status_check_changes_auditor.rb @gitlab-org/manage/compliance
-/ee/lib/audit/group_merge_request_approval_setting_changes_auditor.rb @gitlab-org/manage/compliance
-/ee/lib/audit/group_push_rules_changes_auditor.rb @gitlab-org/manage/compliance
-/ee/lib/ee/api/entities/audit_event.rb @gitlab-org/manage/compliance
-/ee/lib/ee/audit/ @gitlab-org/manage/compliance
-/ee/lib/ee/gitlab/audit/ @gitlab-org/manage/compliance
-/lib/gitlab/audit/auditor.rb @gitlab-org/manage/compliance
-/lib/gitlab/audit_json_logger.rb @gitlab-org/manage/compliance
+/ee/app/services/audit_events/build_service.rb @gitlab-org/govern/compliance
+/ee/spec/services/audit_events/custom_audit_event_service_spec.rb @gitlab-org/govern/compliance
+/app/models/audit_event.rb @gitlab-org/govern/compliance
+/app/services/audit_event_service.rb @gitlab-org/govern/compliance
+/app/services/concerns/audit_event_save_type.rb @gitlab-org/govern/compliance
+/app/views/profiles/audit_log.html.haml @gitlab-org/govern/compliance
+/ee/app/assets/javascripts/audit_events/components/audit_events_app.vue @gitlab-org/govern/compliance
+/ee/app/assets/javascripts/audit_events/components/audit_events_export_button.vue @gitlab-org/govern/compliance
+/ee/app/assets/javascripts/audit_events/components/audit_events_filter.vue @gitlab-org/govern/compliance
+/ee/app/assets/javascripts/audit_events/components/audit_events_log.vue @gitlab-org/govern/compliance
+/ee/app/assets/javascripts/audit_events/components/audit_events_stream.vue @gitlab-org/govern/compliance
+/ee/app/assets/javascripts/audit_events/components/audit_events_table.vue @gitlab-org/govern/compliance
+/ee/app/assets/javascripts/audit_events/components/tokens/shared/ @gitlab-org/govern/compliance
+/ee/app/assets/javascripts/audit_events/init_audit_events.js @gitlab-org/govern/compliance
+/ee/app/controllers/admin/audit_log_reports_controller.rb @gitlab-org/govern/compliance
+/ee/app/controllers/admin/audit_logs_controller.rb @gitlab-org/govern/compliance
+/ee/app/controllers/concerns/audit_events/audit_events_params.rb @gitlab-org/govern/compliance
+/ee/app/controllers/groups/audit_events_controller.rb @gitlab-org/govern/compliance
+/ee/app/controllers/projects/audit_events_controller.rb @gitlab-org/govern/compliance
+/ee/app/finders/audit_event_finder.rb @gitlab-org/govern/compliance
+/ee/app/graphql/types/audit_events/external_audit_event_destination_type.rb @gitlab-org/govern/compliance
+/ee/app/helpers/audit_events_helper.rb @gitlab-org/govern/compliance
+/ee/app/helpers/auditor_user_helper.rb @gitlab-org/govern/compliance
+/ee/app/models/audit_events/external_audit_event_destination.rb @gitlab-org/govern/compliance
+/ee/app/models/concerns/auditable.rb @gitlab-org/govern/compliance
+/ee/app/models/ee/audit_event.rb @gitlab-org/govern/compliance
+/ee/app/policies/audit_events/external_audit_event_destination_policy.rb @gitlab-org/govern/compliance
+/ee/app/presenters/audit_event_presenter.rb @gitlab-org/govern/compliance
+/ee/app/serializers/audit_event_entity.rb @gitlab-org/govern/compliance
+/ee/app/serializers/audit_event_serializer.rb @gitlab-org/govern/compliance
+/ee/app/services/ci/audit_variable_change_service.rb @gitlab-org/govern/compliance
+/ee/app/services/ee/audit_event_service.rb @gitlab-org/govern/compliance
+/ee/app/views/admin/users/_auditor_access_level_radio.html.haml @gitlab-org/govern/compliance
+/ee/app/views/admin/users/_auditor_user_badge.html.haml @gitlab-org/govern/compliance
+/ee/app/views/shared/icons/_icon_audit_events_purple.svg @gitlab-org/govern/compliance
+/ee/app/views/shared/promotions/_promote_audit_events.html.haml @gitlab-org/govern/compliance
+/ee/app/workers/audit_events/audit_event_streaming_worker.rb @gitlab-org/govern/compliance
+/ee/config/events/1652263097_groups__audit_events__index_click_streams_tab.yml @gitlab-org/govern/compliance
+/ee/config/events/202108302307_admin_audit_logs_index_click_date_range_button.yml @gitlab-org/govern/compliance
+/ee/config/events/202108302307_groups__audit_events_controller_search_audit_event.yml @gitlab-org/govern/compliance
+/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_event_streaming_git_operations.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
+/ee/config/metrics/counts_28d/20211130085433_g_manage_compliance_audit_event_destinations.yml @gitlab-org/govern/compliance
+/ee/config/metrics/counts_7d/20210216183906_g_compliance_audit_events.yml @gitlab-org/govern/compliance
+/ee/config/metrics/counts_7d/20210216183908_i_compliance_audit_events.yml @gitlab-org/govern/compliance
+/ee/config/metrics/counts_7d/20210216183912_a_compliance_audit_events_api.yml @gitlab-org/govern/compliance
+/ee/config/metrics/counts_7d/20210216183928_g_compliance_audit_events_weekly.yml @gitlab-org/govern/compliance
+/ee/config/metrics/counts_7d/20210216183932_i_compliance_audit_events_weekly.yml @gitlab-org/govern/compliance
+/ee/config/metrics/counts_7d/20210216183940_a_compliance_audit_events_api_weekly.yml @gitlab-org/govern/compliance
+/ee/config/metrics/counts_all/20211130085433_g_manage_compliance_audit_event_destinations.yml @gitlab-org/govern/compliance
+/ee/lib/api/audit_events.rb @gitlab-org/govern/compliance
+/ee/lib/audit/external_status_check_changes_auditor.rb @gitlab-org/govern/compliance
+/ee/lib/audit/group_merge_request_approval_setting_changes_auditor.rb @gitlab-org/govern/compliance
+/ee/lib/audit/group_push_rules_changes_auditor.rb @gitlab-org/govern/compliance
+/ee/lib/ee/api/entities/audit_event.rb @gitlab-org/govern/compliance
+/ee/lib/ee/audit/ @gitlab-org/govern/compliance
+/ee/lib/ee/gitlab/audit/ @gitlab-org/govern/compliance
+/lib/gitlab/audit/auditor.rb @gitlab-org/govern/compliance
+/lib/gitlab/audit_json_logger.rb @gitlab-org/govern/compliance
diff --git a/.gitlab/ci/as-if-jh.gitlab-ci.yml b/.gitlab/ci/as-if-jh.gitlab-ci.yml
new file mode 100644
index 00000000000..6019c8a9649
--- /dev/null
+++ b/.gitlab/ci/as-if-jh.gitlab-ci.yml
@@ -0,0 +1,63 @@
+.shared-as-if-jh:
+ variables:
+ SANDBOX_PROJECT: "gitlab-org-sandbox/gitlab-jh-validation"
+ SANDBOX_REPOSITORY: "https://dummy:${AS_IF_JH_TOKEN}@gitlab.com/${SANDBOX_PROJECT}.git"
+ GITLAB_JH_MIRROR_PROJECT: "33019816"
+ AS_IF_JH_BRANCH: "as-if-jh/${CI_COMMIT_REF_NAME}"
+ JH_FILES_TO_COMMIT: "jh package.json yarn.lock"
+
+add-jh-files:
+ extends:
+ - .shared-as-if-jh
+ - .as-if-jh:rules:prepare-as-if-jh
+ image: ${GITLAB_DEPENDENCY_PROXY}ruby:${RUBY_VERSION}
+ stage: prepare
+ before_script:
+ - source ./scripts/utils.sh
+ - source ./scripts/setup/as-if-jh.sh
+ - install_gitlab_gem
+ script:
+ - prepare_jh_branch
+ - download_jh_path ${JH_FILES_TO_COMMIT}
+ - echoinfo "Changes after downloading JiHu files:"
+ - git diff
+ - git status
+ artifacts:
+ expire_in: 2d
+ paths:
+ # This should match JH_FILES_TO_COMMIT
+ - jh/
+ - package.json
+ - yarn.lock
+
+prepare-as-if-jh-branch:
+ extends:
+ - .shared-as-if-jh
+ - .as-if-jh:rules:prepare-as-if-jh
+ stage: prepare
+ needs:
+ - add-jh-files
+ script:
+ - git checkout -b "${AS_IF_JH_BRANCH}"
+ - git add ${JH_FILES_TO_COMMIT}
+ - git commit -m 'Add JH files' # TODO: Mark which SHA we add
+ # 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_REF_NAME}"
+ - git push -f "${SANDBOX_REPOSITORY}" "${AS_IF_JH_BRANCH}"
+
+start-as-if-jh:
+ extends:
+ - .shared-as-if-jh
+ - .as-if-jh:rules:start-as-if-jh
+ stage: prepare
+ needs: ["prepare-as-if-jh-branch"]
+ inherit:
+ variables: false
+ variables:
+ AS_IF_EDITION: "jh"
+ FORCE_GITLAB_CI: "true" # TODO: Trigger a merge request pipeline
+ trigger:
+ project: gitlab-org-sandbox/gitlab-jh-validation # ${SANDBOX_PROJECT} does not work here
+ branch: as-if-jh/${CI_COMMIT_REF_NAME} # ${AS_IF_JH_BRANCH} does not work here
+ strategy: depend
diff --git a/.gitlab/ci/build-images.gitlab-ci.yml b/.gitlab/ci/build-images.gitlab-ci.yml
index 3c7056a92c1..a60a5f6040c 100644
--- a/.gitlab/ci/build-images.gitlab-ci.yml
+++ b/.gitlab/ci/build-images.gitlab-ci.yml
@@ -1,7 +1,13 @@
.base-image-build:
extends: .use-kaniko
variables:
- GIT_LFS_SKIP_SMUDGE: 1
+ GIT_LFS_SKIP_SMUDGE: 1 # disable pulling objects from lfs
+ retry: 2
+
+.base-image-build-buildx:
+ extends: .use-buildx
+ variables:
+ GIT_LFS_SKIP_SMUDGE: 1 # disable pulling objects from lfs
retry: 2
# This image is used by:
@@ -10,12 +16,12 @@
# See https://docs.gitlab.com/ee/development/testing_guide/end_to_end/index.html#testing-code-in-merge-requests for more details.
build-qa-image:
extends:
- - .base-image-build
+ - .base-image-build-buildx
- .build-images:rules:build-qa-image
stage: build-images
needs: []
script:
- - ./scripts/build_qa_image
+ - run_timed_command "scripts/build_qa_image"
# This image is used by:
# - The `CNG` pipelines (via the `review-build-cng` job): https://gitlab.com/gitlab-org/build/CNG/-/blob/cfc67136d711e1c8c409bf8e57427a644393da2f/.gitlab-ci.yml#L335
diff --git a/.gitlab/ci/dev-fixtures.gitlab-ci.yml b/.gitlab/ci/dev-fixtures.gitlab-ci.yml
index 21eae3f23e9..ea868ada621 100644
--- a/.gitlab/ci/dev-fixtures.gitlab-ci.yml
+++ b/.gitlab/ci/dev-fixtures.gitlab-ci.yml
@@ -29,7 +29,7 @@ run-dev-fixtures-ee:
extends:
- .run-dev-fixtures
- .dev-fixtures:rules:ee-only
- - .use-pg12-ee
+ - .use-pg12-es7-ee
script:
- cp ee/db/fixtures/development/* $FIXTURE_PATH
- *run-dev-fixtures-script
diff --git a/.gitlab/ci/docs.gitlab-ci.yml b/.gitlab/ci/docs.gitlab-ci.yml
index 022f1c17a93..c6d2b30046c 100644
--- a/.gitlab/ci/docs.gitlab-ci.yml
+++ b/.gitlab/ci/docs.gitlab-ci.yml
@@ -39,17 +39,6 @@ review-docs-cleanup:
script:
- ./scripts/trigger-build.rb docs cleanup
-docs-lint markdown:
- extends:
- - .default-retry
- - .docs:rules:docs-lint
- # 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.20.1-markdownlint-0.32.2
- stage: lint
- needs: []
- script:
- - scripts/lint-doc.sh
-
docs-lint links:
extends:
- .docs:rules:docs-lint
@@ -67,6 +56,35 @@ docs-lint links:
# Check the internal links and anchors (in parallel)
- "parallel time bundle exec nanoc check ::: internal_links internal_anchors"
+.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.20.1-markdownlint-0.32.2
+
+docs-lint markdown:
+ extends:
+ - .default-retry
+ - .docs:rules:docs-lint
+ - .docs-markdown-lint-image
+ stage: lint
+ needs: []
+ script:
+ - scripts/lint-doc.sh
+
+docs-code-quality:
+ extends:
+ - .docs:rules:docs-code-quality
+ - .docs-markdown-lint-image
+ stage: lint
+ needs: []
+ script:
+ - vale --output=doc/.vale/vale-json.tmpl --minAlertLevel warning doc > gl-code-quality-report-docs.json || exit_code=$?
+ artifacts:
+ reports:
+ codequality: gl-code-quality-report-docs.json
+ paths:
+ - gl-code-quality-report-docs.json
+ expire_in: 1 week
+
ui-docs-links lint:
extends:
- .docs:rules:docs-lint
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml
index 085c0aa890d..6be77fe52c8 100644
--- a/.gitlab/ci/frontend.gitlab-ci.yml
+++ b/.gitlab/ci/frontend.gitlab-ci.yml
@@ -20,7 +20,12 @@
- |
if [[ "${CACHE_ASSETS_AS_PACKAGE}" == "true" ]]; then
source scripts/gitlab_component_helpers.sh
- gitlab_assets_archive_doesnt_exist || run_timed_command "download_and_extract_gitlab_assets"
+
+ if ! gitlab_assets_archive_doesnt_exist; then
+ # We remove all assets from the native cache as they could pollute the fresh assets from the package
+ rm -rf public/assets/ app/assets/javascripts/locale/**/app.js
+ run_timed_command "download_and_extract_gitlab_assets"
+ fi
fi
- assets_compile_script
@@ -84,17 +89,6 @@ update-assets-compile-test-cache:
- echo -n "${GITLAB_ASSETS_HASH}" > "cached-assets-hash.txt"
artifacts: {} # This job's purpose is only to update the cache.
-# TODO: Remove this as it's duplicating update-assets-compile-*-cache
-update-yarn-cache:
- extends:
- - .default-retry
- - .default-utils-before_script
- - .yarn-cache-push
- - .shared:rules:update-cache
- stage: prepare
- script:
- - yarn_install_script
-
update-storybook-yarn-cache:
extends:
- .default-retry
@@ -171,7 +165,7 @@ graphql-schema-dump:
graphql-schema-dump as-if-foss:
extends:
- graphql-schema-dump
- - .frontend:rules:eslint-as-if-foss
+ - .frontend:rules:default-frontend-jobs-as-if-foss
- .as-if-foss
.frontend-test-base:
@@ -399,5 +393,5 @@ compile-storybook as-if-foss:
- .as-if-foss
- .frontend:rules:default-frontend-jobs-as-if-foss
needs:
- - !reference [.compile-storybook-base, needs]
+ - job: "graphql-schema-dump as-if-foss"
- job: "rspec-all frontend_fixture as-if-foss"
diff --git a/.gitlab/ci/glfm.gitlab-ci.yml b/.gitlab/ci/glfm.gitlab-ci.yml
new file mode 100644
index 00000000000..6ff60f24730
--- /dev/null
+++ b/.gitlab/ci/glfm.gitlab-ci.yml
@@ -0,0 +1,16 @@
+glfm-verify:
+ extends:
+ - .rails-job-base
+ - .glfm:rules:glfm-verify
+ - .use-pg12
+ stage: test
+ needs: ["setup-test-env"]
+ script:
+ - !reference [.base-script, script]
+ - bundle exec scripts/glfm/verify-all-generated-files-are-up-to-date.rb
+ artifacts:
+ name: changed-files
+ when: on_failure
+ expire_in: 31d
+ paths:
+ - glfm_specification/
diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml
index ed59a0dd8fe..add728a9983 100644
--- a/.gitlab/ci/global.gitlab-ci.yml
+++ b/.gitlab/ci/global.gitlab-ci.yml
@@ -219,23 +219,16 @@
- *node-modules-cache
- *assets-tmp-cache
-# TODO: Remove this as it's duplicating .assets-compile-cache-push
-.yarn-cache-push:
- cache:
- - *node-modules-cache-push
-
.assets-compile-cache:
cache:
- *ruby-gems-cache
- *node-modules-cache
- - *assets-cache
- *assets-tmp-cache
.assets-compile-cache-push:
cache:
- *ruby-gems-cache # We don't push this cache as it's already rebuilt by `update-setup-test-env-cache`
- *node-modules-cache-push
- - *assets-cache-push
- *assets-tmp-cache-push
.storybook-yarn-cache:
@@ -245,7 +238,7 @@
.storybook-yarn-cache-push:
cache:
- - *node-modules-cache # We don't push this cache as it's already rebuilt by `update-yarn-cache`
+ - *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:
@@ -275,34 +268,34 @@
POSTGRES_HOST_AUTH_METHOD: trust
PG_VERSION: "13"
-.use-pg11-ee:
+.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.0
+ - name: elasticsearch:7.17.6
command: ["elasticsearch", "-E", "discovery.type=single-node", "-E", "xpack.security.enabled=false"]
variables:
POSTGRES_HOST_AUTH_METHOD: trust
PG_VERSION: "11"
-.use-pg12-ee:
+.use-pg12-es7-ee:
services:
- name: postgres:12
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:6.0-alpine
- - name: elasticsearch:7.17.0
+ - name: elasticsearch:7.17.6
command: ["elasticsearch", "-E", "discovery.type=single-node", "-E", "xpack.security.enabled=false"]
variables:
POSTGRES_HOST_AUTH_METHOD: trust
PG_VERSION: "12"
-.use-pg13-ee:
+.use-pg13-es7-ee:
services:
- name: postgres:13
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:6.2-alpine
- - name: elasticsearch:7.17.0
+ - name: elasticsearch:7.17.6
command: ["elasticsearch", "-E", "discovery.type=single-node", "-E", "xpack.security.enabled=false"]
variables:
POSTGRES_HOST_AUTH_METHOD: trust
@@ -313,7 +306,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.3.3
+ - name: elasticsearch:8.4.1
variables:
POSTGRES_HOST_AUTH_METHOD: trust
PG_VERSION: "12"
@@ -325,7 +318,19 @@
- name: postgres:12
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:6.0-alpine
- - name: opensearchproject/opensearch:1.2.4
+ - name: opensearchproject/opensearch:1.3.5
+ alias: elasticsearch
+ command: ["bin/opensearch", "-E", "discovery.type=single-node", "-E", "plugins.security.disabled=true"]
+ variables:
+ POSTGRES_HOST_AUTH_METHOD: trust
+ PG_VERSION: "12"
+
+.use-pg12-opensearch2-ee:
+ services:
+ - name: postgres:12
+ command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
+ - name: redis:6.0-alpine
+ - name: opensearchproject/opensearch:2.2.1
alias: elasticsearch
command: ["bin/opensearch", "-E", "discovery.type=single-node", "-E", "plugins.security.disabled=true"]
variables:
@@ -356,3 +361,20 @@
tags:
# See https://gitlab.com/gitlab-com/www-gitlab-com/-/issues/7019 for tag descriptions
- gitlab-org-docker
+
+.use-buildx:
+ extends: .use-docker-in-docker
+ image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-bullseye-slim:docker-${DOCKER_VERSION}-buildx-0.8
+ variables:
+ QEMU_IMAGE: tonistiigi/binfmt:qemu-v7.0.0
+ before_script:
+ - source scripts/utils.sh
+ - echo "$CI_REGISTRY_PASSWORD" | docker login "$CI_REGISTRY" -u "$CI_REGISTRY_USER" --password-stdin
+ - |
+ if [[ "${ARCH}" =~ arm64 ]]; then
+ echo -e "\033[1;33mInstalling latest qemu emulators\033[0m"
+ docker pull -q ${QEMU_IMAGE};
+ docker run --rm --privileged ${QEMU_IMAGE} --uninstall qemu-*;
+ docker run --rm --privileged ${QEMU_IMAGE} --install all;
+ fi
+ - docker buildx create --use # creates and set's to active buildkit builder
diff --git a/.gitlab/ci/notify.gitlab-ci.yml b/.gitlab/ci/notify.gitlab-ci.yml
index 51b0f4071eb..ae77caa140a 100644
--- a/.gitlab/ci/notify.gitlab-ci.yml
+++ b/.gitlab/ci/notify.gitlab-ci.yml
@@ -1,8 +1,12 @@
-.notify-slack:
- image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}alpine/curl
+.notify-defaults:
stage: notify
dependencies: []
cache: {}
+
+.notify-slack:
+ extends:
+ - .notify-defaults
+ image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}alpine/curl
variables:
MERGE_REQUEST_URL: ${CI_MERGE_REQUEST_PROJECT_URL}/-/merge_requests/${CI_MERGE_REQUEST_IID}
before_script:
@@ -34,28 +38,31 @@ notify-security-pipeline:
- scripts/slack ${NOTIFY_CHANNEL} "<!subteam^S0127FU8PDE> â˜ ï¸ Pipeline for merged result failed! â˜ ï¸ See ${CI_PIPELINE_URL} (triggered from ${MERGE_REQUEST_URL})" ci_failing "GitLab Release Tools Bot"
notify-pipeline-failure:
- extends: .notify-slack
+ extends:
+ - .notify-defaults
+ - .notify:rules:notify-pipeline-failure
image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}ruby:${RUBY_VERSION}
- rules:
- # Don't report child pipeline failures
- - if: '$CI_PIPELINE_SOURCE == "parent_pipeline"'
- when: never
- - if: '$CI_SLACK_WEBHOOK_URL && $NOTIFY_PIPELINE_FAILURE_CHANNEL'
- when: on_failure
- allow_failure: true
variables:
+ BROKEN_MASTER_INCIDENTS_PROJECT: "gitlab-org/quality/engineering-productivity/master-broken-incidents"
+ BROKEN_MASTER_INCIDENT_JSON: "${CI_PROJECT_DIR}/incident.json"
SLACK_CHANNEL: "${NOTIFY_PIPELINE_FAILURE_CHANNEL}"
- FAILED_PIPELINE_REPORT_FILE: "failed_pipeline_report.json"
+ FAILED_PIPELINE_SLACK_MESSAGE_FILE: "${CI_PROJECT_DIR}/failed_pipeline_slack_message.json"
before_script:
- source scripts/utils.sh
- apt-get update && apt-get install -y jq
- install_gitlab_gem
script:
- - scripts/generate-failed-pipeline-slack-message.rb
- |
- curl -X POST -H 'Content-Type: application/json' --data @${FAILED_PIPELINE_REPORT_FILE} "$CI_SLACK_WEBHOOK_URL"
+ if [[ "${CREATE_INCIDENT_FOR_PIPELINE_FAILURE}" == "true" ]]; then
+ scripts/create-pipeline-failure-incident.rb -p ${BROKEN_MASTER_INCIDENTS_PROJECT} -f ${BROKEN_MASTER_INCIDENT_JSON} -t ${BROKEN_MASTER_INCIDENTS_PROJECT_TOKEN};
+ echosuccess "Created incident $(jq '.web_url' ${BROKEN_MASTER_INCIDENT_JSON})";
+ fi
+ - |
+ scripts/generate-failed-pipeline-slack-message.rb -i ${BROKEN_MASTER_INCIDENT_JSON} -f ${FAILED_PIPELINE_SLACK_MESSAGE_FILE};
+ curl -X POST -H 'Content-Type: application/json' --data @${FAILED_PIPELINE_SLACK_MESSAGE_FILE} "$CI_SLACK_WEBHOOK_URL";
artifacts:
paths:
- - ${FAILED_PIPELINE_REPORT_FILE}
+ - ${BROKEN_MASTER_INCIDENT_JSON}
+ - ${FAILED_PIPELINE_SLACK_MESSAGE_FILE}
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 1a1c67bf572..f0bf79f009d 100644
--- a/.gitlab/ci/package-and-test/main.gitlab-ci.yml
+++ b/.gitlab/ci/package-and-test/main.gitlab-ci.yml
@@ -7,7 +7,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: 1.3.0
+ ref: 1.7.0
file:
- /ci/base.gitlab-ci.yml
- /ci/allure-report.yml
@@ -27,6 +27,8 @@ stages:
QA_KNAPSACK_REPORT_PATH: $CI_PROJECT_DIR/qa/knapsack
.ruby-image:
+ # Because this pipeline template can be included directly in other projects,
+ # image path and registry needs to be defined explicitly
image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-bullseye-ruby-${RUBY_VERSION}:bundler-2.3
.qa-install:
@@ -161,7 +163,7 @@ cache-gems:
extends:
- .qa-install
- .ruby-image
- - .rules:prepare
+ - .rules:update-cache
stage: .pre
tags:
- e2e
@@ -206,7 +208,6 @@ ee:instance-parallel-ff-inverse:
QA_KNAPSACK_REPORT_NAME: ee-instance-parallel
GITLAB_QA_OPTS: --set-feature-flags $QA_FEATURE_FLAGS
rules:
- - !reference [.rules:test:feature-flags-deleted, rules] # skip job when only change is ff deletion
- !reference [.rules:test:feature-flags-set, rules]
# ------------------------------------------
@@ -224,7 +225,7 @@ ee:instance-parallel:
- .parallel
- ee:instance
rules:
- - !reference [.rules:test:feature-flags-set, rules] # always run instance-parallel to validate ff change
+ - !reference [.rules:test:feature-flags-set, rules] # always run instance-parallel to validate ff change
- !reference [.rules:test:qa-parallel, rules]
- if: $QA_SUITES =~ /Test::Instance::All/
@@ -378,6 +379,15 @@ ee:update-major:
- if: $QA_SUITES =~ /Test::Instance::Smoke/
- !reference [.rules:test:manual, rules]
+ee:gitab-pages:
+ extends: .qa
+ variables:
+ QA_SCENARIO: Test::Integration::GitlabPages
+ rules:
+ - !reference [.rules:test:qa, rules]
+ - if: $QA_SUITES =~ /Test::Integration::GitlabPages/
+ - !reference [.rules:test:manual, rules]
+
ee:gitaly-cluster:
extends: .qa
variables:
@@ -548,7 +558,7 @@ ee:elasticsearch:
variables:
QA_SCENARIO: "Test::Integration::Elasticsearch"
before_script:
- - unset ELASTIC_URL # unset url which is globally defined in .gitlab-ci.yml
+ - unset ELASTIC_URL # unset url which is globally defined in .gitlab-ci.yml
- !reference [.qa, before_script]
rules:
- !reference [.rules:test:qa, rules]
@@ -577,7 +587,7 @@ e2e-test-report:
ALLURE_MERGE_REQUEST_IID: $CI_MERGE_REQUEST_IID
ALLURE_JOB_NAME: e2e-package-and-test
GIT_STRATEGY: none
- artifacts: # save rspec results for displaying in parent pipeline
+ artifacts: # save rspec results for displaying in parent pipeline
expire_in: 1 day
when: always
paths:
@@ -592,6 +602,16 @@ upload-knapsack-report:
stage: report
when: always
+export-test-metrics:
+ extends:
+ - .qa-install
+ - .ruby-image
+ - .rules:report:process-results
+ stage: report
+ when: always
+ script:
+ - bundle exec rake "ci:export_test_metrics[$CI_PROJECT_DIR/gitlab-qa-run-*/**/test-metrics-*.json]"
+
relate-test-failures:
extends:
- .qa-install
@@ -647,5 +667,5 @@ notify-slack:
TYPE: "(package-and-test) "
when: on_failure
script:
- - bundle exec gitlab-qa-report --prepare-stage-reports "$CI_PROJECT_DIR/gitlab-qa-run-*/**/rspec-*.xml" # generate summary
+ - bundle exec gitlab-qa-report --prepare-stage-reports "$CI_PROJECT_DIR/gitlab-qa-run-*/**/rspec-*.xml" # generate summary
- !reference [.notify-slack-qa, script]
diff --git a/.gitlab/ci/package-and-test/rules.gitlab-ci.yml b/.gitlab/ci/package-and-test/rules.gitlab-ci.yml
index 47625340a3a..64d56cec21a 100644
--- a/.gitlab/ci/package-and-test/rules.gitlab-ci.yml
+++ b/.gitlab/ci/package-and-test/rules.gitlab-ci.yml
@@ -8,11 +8,8 @@
# FF changes
.feature-flags-set: &feature-flags-set
- if: $QA_FEATURE_FLAGS != ""
+ if: $QA_FEATURE_FLAGS =~ /enabled|disabled/
-# Only deleted feature flags
-.feature-flags-deleted: &feature-flags-deleted
- if: $QA_FEATURE_FLAGS != "" && $QA_FEATURE_FLAGS !~ /enabled|disabled/
# Manually trigger job on ff changes but with default ff state instead of inverted
.feature-flags-set-manual: &feature-flags-set-manual
@@ -20,14 +17,17 @@
when: manual
allow_failure: true
-# QA framework changes present
-.qa-framework-changes: &qa-framework-changes
- if: $QA_FRAMEWORK_CHANGES == "true"
+# Run all tests when framework changes present, full suite execution is explicitly enabled or a feature flag file is removed
+.qa-run-all-tests: &qa-run-all-tests
+ if: $QA_FRAMEWORK_CHANGES == "true" || $QA_RUN_ALL_TESTS == "true" || $QA_FEATURE_FLAGS =~ /deleted/
# Process test results (notify failure to slack, create test session report, relate test failures)
.process-test-results: &process-test-results
if: $PROCESS_TEST_RESULTS == "true"
+.not-canonical-project: &not-canonical-project
+ if: '$CI_PROJECT_PATH != "gitlab-org/gitlab" && $CI_PROJECT_PATH != "gitlab-cn/gitlab"'
+
# Selective test execution against omnibus instance have following execution scenarios:
# * only e2e spec files changed - runs only changed specs
# * qa framework changes - runs full test suite
@@ -55,6 +55,12 @@
when: never
- when: always
+.rules:update-cache:
+ rules:
+ - <<: *not-canonical-project
+ when: never
+ - when: always
+
# ------------------------------------------
# Test
# ------------------------------------------
@@ -72,17 +78,12 @@
variables:
QA_TESTS: ""
-.rules:test:feature-flags-deleted:
- rules:
- - <<: *feature-flags-deleted
- when: never
-
# parallel and non parallel rules are used for jobs that require parallel execution and thus need to switch
# between parallel and non parallel when only certain specs are executed
.rules:test:qa-non-parallel:
rules:
# always run parallel with full suite when framework changes present or ff state changed
- - <<: *qa-framework-changes
+ - <<: *qa-run-all-tests
when: never
- <<: *all-specs
when: never
@@ -91,7 +92,7 @@
.rules:test:qa-parallel:
rules:
- - *qa-framework-changes
+ - *qa-run-all-tests
- <<: *specific-specs
when: manual
allow_failure: true
@@ -102,7 +103,7 @@
# general qa job rule for jobs without the need to run in parallel
.rules:test:qa:
rules:
- - *qa-framework-changes
+ - *qa-run-all-tests
- *feature-flags-set-manual
.rules:test:update:
@@ -124,4 +125,6 @@
.rules:report:process-results:
rules:
+ - <<: *not-canonical-project
+ when: never
- *process-test-results
diff --git a/.gitlab/ci/package-and-test/variables.gitlab-ci.yml b/.gitlab/ci/package-and-test/variables.gitlab-ci.yml
index cd22fa0e6e4..838de6bdd3a 100644
--- a/.gitlab/ci/package-and-test/variables.gitlab-ci.yml
+++ b/.gitlab/ci/package-and-test/variables.gitlab-ci.yml
@@ -1,6 +1,8 @@
# Default variables for package-and-test
variables:
+ REGISTRY_HOST: "registry.gitlab.com"
+ REGISTRY_GROUP: "gitlab-org"
SKIP_REPORT_IN_ISSUES: "true"
OMNIBUS_GITLAB_CACHE_UPDATE: "false"
OMNIBUS_GITLAB_RUBY3_BUILD: "false"
diff --git a/.gitlab/ci/pages.gitlab-ci.yml b/.gitlab/ci/pages.gitlab-ci.yml
index 1f9f57cfc22..ea4319809f9 100644
--- a/.gitlab/ci/pages.gitlab-ci.yml
+++ b/.gitlab/ci/pages.gitlab-ci.yml
@@ -10,20 +10,18 @@ pages:
environment: pages
resource_group: pages
needs:
- - job: "rspec:coverage"
- - job: "coverage-frontend"
- - job: "compile-production-assets"
- - job: "compile-storybook"
- # `update-tests-metadata` only runs on GitLab.com's EE schedules pipelines
- # while `pages` runs for all the maintenance scheduled pipelines.
- - job: "update-tests-metadata"
- optional: true
+ - "rspec:coverage"
+ - "coverage-frontend"
+ - "compile-production-assets"
+ - "compile-storybook"
+ - "update-tests-metadata"
+ - "generate-frontend-fixtures-mapping"
before_script:
- apt-get update && apt-get -y install brotli gzip
script:
- mv public/ .public/
- mkdir public/
- - mkdir -p public/$(dirname "$KNAPSACK_RSPEC_SUITE_REPORT_PATH") public/$(dirname "$FLAKY_RSPEC_SUITE_REPORT_PATH") public/$(dirname "$RSPEC_PACKED_TESTS_MAPPING_PATH")
+ - mkdir -p public/$(dirname "$KNAPSACK_RSPEC_SUITE_REPORT_PATH") public/$(dirname "$FLAKY_RSPEC_SUITE_REPORT_PATH") public/$(dirname "$RSPEC_PACKED_TESTS_MAPPING_PATH") public/$(dirname "$FRONTEND_FIXTURES_MAPPING_PATH")
- mv coverage/ public/coverage-ruby/ || true
- mv coverage-frontend/ public/coverage-frontend/ || true
- mv storybook/public public/storybook || true
@@ -31,6 +29,7 @@ pages:
- mv $KNAPSACK_RSPEC_SUITE_REPORT_PATH public/$KNAPSACK_RSPEC_SUITE_REPORT_PATH || true
- mv $FLAKY_RSPEC_SUITE_REPORT_PATH public/$FLAKY_RSPEC_SUITE_REPORT_PATH || true
- mv $RSPEC_PACKED_TESTS_MAPPING_PATH.gz public/$RSPEC_PACKED_TESTS_MAPPING_PATH.gz || true
+ - mv $FRONTEND_FIXTURES_MAPPING_PATH public/$FRONTEND_FIXTURES_MAPPING_PATH || true
- *compress-public
artifacts:
paths:
diff --git a/.gitlab/ci/qa.gitlab-ci.yml b/.gitlab/ci/qa.gitlab-ci.yml
index bd587cb4418..8740a5fe17d 100644
--- a/.gitlab/ci/qa.gitlab-ci.yml
+++ b/.gitlab/ci/qa.gitlab-ci.yml
@@ -8,7 +8,6 @@
variables:
USE_BUNDLE_INSTALL: "false"
SETUP_DB: "false"
- QA_EXPORT_TEST_METRICS: "false"
before_script:
- !reference [.default-before_script, before_script]
- cd qa && bundle install
@@ -78,8 +77,8 @@ e2e:package-and-test:
SKIP_MESSAGE: Skipping package-and-test due to mr containing only quarantine changes!
RELEASE: "${REGISTRY_HOST}/${REGISTRY_GROUP}/build/omnibus-gitlab-mirror/gitlab-ee:${CI_COMMIT_SHA}"
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
+ 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
trigger:
strategy: depend
forward:
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml
index c60f85634b6..f4f832b84d0 100644
--- a/.gitlab/ci/rails.gitlab-ci.yml
+++ b/.gitlab/ci/rails.gitlab-ci.yml
@@ -574,11 +574,6 @@ rspec-ee unit pg12 es8:
- .rspec-ee-base-pg12-es8
- .rspec-ee-unit-parallel
-rspec-ee unit pg12 opensearch1:
- extends:
- - .rspec-ee-base-pg12-opensearch1
- - .rspec-ee-unit-parallel
-
rspec-ee unit pg12 minimal:
extends:
- rspec-ee unit pg12
@@ -602,11 +597,6 @@ rspec-ee integration pg12 es8:
- .rspec-ee-base-pg12-es8
- .rspec-ee-integration-parallel
-rspec-ee integration pg12 opensearch1:
- extends:
- - .rspec-ee-base-pg12-opensearch1
- - .rspec-ee-integration-parallel
-
rspec-ee integration pg12 minimal:
extends:
- rspec-ee integration pg12
@@ -630,11 +620,6 @@ rspec-ee system pg12 es8:
- .rspec-ee-base-pg12-es8
- .rspec-ee-system-parallel
-rspec-ee system pg12 opensearch1:
- extends:
- - .rspec-ee-base-pg12-opensearch1
- - .rspec-ee-system-parallel
-
rspec-ee system pg12 minimal:
extends:
- rspec-ee system pg12
@@ -743,6 +728,61 @@ rspec-ee system pg11:
- .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
- .rspec-ee-system-parallel
+# PG12
+rspec-ee unit pg12 es7:
+ extends:
+ - .rspec-ee-base-pg12-es7
+ - .rspec-ee-unit-parallel
+ - .rails:rules:default-branch-schedule-nightly--code-backstage-ee-only
+
+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 es7:
+ extends:
+ - .rspec-ee-base-pg12-es7
+ - .rspec-ee-integration-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 es7:
+ extends:
+ - .rspec-ee-base-pg12-es7
+ - .rspec-ee-system-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:
extends:
diff --git a/.gitlab/ci/rails/shared.gitlab-ci.yml b/.gitlab/ci/rails/shared.gitlab-ci.yml
index 60c9826abfe..d47bac5e433 100644
--- a/.gitlab/ci/rails/shared.gitlab-ci.yml
+++ b/.gitlab/ci/rails/shared.gitlab-ci.yml
@@ -109,12 +109,18 @@ include:
.rspec-ee-base-pg11:
extends:
- .rspec-base
- - .use-pg11-ee
+ - .use-pg11-es7-ee
.rspec-ee-base-pg12:
extends:
- .rspec-base
- - .use-pg12-ee
+ - .use-pg12-es7-ee
+
+.rspec-ee-base-pg12-es7:
+ extends:
+ - .rspec-base
+ - .use-pg12-es7-ee
+ - .rails:rules:run-search-tests
.rspec-ee-base-pg12-es8:
extends:
@@ -128,10 +134,16 @@ include:
- .use-pg12-opensearch1-ee
- .rails:rules:run-search-tests
+.rspec-ee-base-pg12-opensearch2:
+ extends:
+ - .rspec-base
+ - .use-pg12-opensearch2-ee
+ - .rails:rules:run-search-tests
+
.rspec-ee-base-pg13:
extends:
- .rspec-base
- - .use-pg13-ee
+ - .use-pg13-es7-ee
.db-job-base:
extends:
diff --git a/.gitlab/ci/reports.gitlab-ci.yml b/.gitlab/ci/reports.gitlab-ci.yml
index 52ed85190ec..5fdcdc12fc8 100644
--- a/.gitlab/ci/reports.gitlab-ci.yml
+++ b/.gitlab/ci/reports.gitlab-ci.yml
@@ -40,22 +40,6 @@ brakeman-sast:
semgrep-sast:
rules: !reference [".reports:rules:semgrep-sast", rules]
-gosec-sast:
- variables:
- GOPATH: "$CI_PROJECT_DIR/vendor/go"
- COMPILE: "false"
- GOSEC_GO_PKG_PATH: "$CI_PROJECT_DIR"
- SECURE_LOG_LEVEL: "debug"
- before_script:
- - mkdir -p $GOPATH
- - cd workhorse
- - go get -d ./...
- - cd ..
- cache:
- paths:
- - vendor/go
- rules: !reference [".reports:rules:gosec-sast", rules]
-
.secret-analyzer:
extends: .default-retry
stage: lint
diff --git a/.gitlab/ci/review-apps/dast-api.gitlab-ci.yml b/.gitlab/ci/review-apps/dast-api.gitlab-ci.yml
index e2f32f120af..4d35a282037 100644
--- a/.gitlab/ci/review-apps/dast-api.gitlab-ci.yml
+++ b/.gitlab/ci/review-apps/dast-api.gitlab-ci.yml
@@ -2,13 +2,34 @@ include:
- template: DAST-API.gitlab-ci.yml
dast_api:
+ needs: ["review-deploy"]
+ # Uncomment resource_group if DAST_API_PROFILE is changed to an active scan
+ # resource_group: dast_api_scan
+ rules:
+ - when: never
+
+dast_api_graphql:
+ extends: dast_api
variables:
- DAST_API_PROFILE: Passive
DAST_API_GRAPHQL: /api/graphql
+ DAST_API_PROFILE: Passive
+ DAST_API_TARGET_URL: ${CI_ENVIRONMENT_URL}
+ DAST_API_OVERRIDES_ENV: "{\"headers\":{\"Authorization\":\"Bearer $REVIEW_APPS_ROOT_TOKEN\"}}"
+ rules:
+ - !reference [".reports:rules:schedule-dast", rules]
+ #
+ # To run this job in an MR pipeline, use this rule:
+ # - !reference [".reports:rules:test-dast", rules]
+
+dast_api_rest:
+ extends: dast_api
+ variables:
+ DAST_API_OPENAPI: doc/api/openapi/openapi_v2.yaml
+ DAST_API_PROFILE: Passive
DAST_API_TARGET_URL: ${CI_ENVIRONMENT_URL}
DAST_API_OVERRIDES_ENV: "{\"headers\":{\"Authorization\":\"Bearer $REVIEW_APPS_ROOT_TOKEN\"}}"
- needs: ["review-deploy"]
- # Uncomment resource_group if DAST_API_PROFILE is changed to an active scan
- # resource_group: dast_api_scan
rules:
- !reference [".reports:rules:schedule-dast", rules]
+ #
+ # To run this job in an MR pipeline, use this rule:
+ # - !reference [".reports:rules:test-dast", rules]
diff --git a/.gitlab/ci/review-apps/main.gitlab-ci.yml b/.gitlab/ci/review-apps/main.gitlab-ci.yml
index d3f5d014464..85c5c7d1b1d 100644
--- a/.gitlab/ci/review-apps/main.gitlab-ci.yml
+++ b/.gitlab/ci/review-apps/main.gitlab-ci.yml
@@ -32,14 +32,15 @@ review-build-cng-env:
extends:
- .default-retry
- .review:rules:review-build-cng
- image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}ruby:3.0-alpine3.13
+ image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}:bundler-2.3
stage: prepare
needs: []
before_script:
- source ./scripts/utils.sh
- install_gitlab_gem
script:
- - 'ruby -r./scripts/trigger-build.rb -e "puts Trigger.variables_for_env_file(Trigger::CNG.new.variables)" > build.env'
+ - ruby -r./scripts/trigger-build.rb -e "puts Trigger.variables_for_env_file(Trigger::CNG.new.variables)" > build.env
+ - ruby -e 'puts "FULL_RUBY_VERSION=#{RUBY_VERSION}"' >> build.env
- cat build.env
artifacts:
reports:
@@ -70,12 +71,14 @@ review-build-cng:
FORCE_RAILS_IMAGE_BUILDS: "${FORCE_RAILS_IMAGE_BUILDS}"
CE_PIPELINE: "${CE_PIPELINE}" # Based on https://docs.gitlab.com/ee/ci/jobs/job_control.html#check-if-a-variable-exists, `if: '$CE_PIPELINE'` will evaluate to `false` when this variable is empty
EE_PIPELINE: "${EE_PIPELINE}" # Based on https://docs.gitlab.com/ee/ci/jobs/job_control.html#check-if-a-variable-exists, `if: '$EE_PIPELINE'` will evaluate to `false` when this variable is empty
- GITLAB_SHELL_VERSION: "${GITLAB_SHELL_VERSION}"
GITLAB_ELASTICSEARCH_INDEXER_VERSION: "${GITLAB_ELASTICSEARCH_INDEXER_VERSION}"
GITLAB_KAS_VERSION: "${GITLAB_KAS_VERSION}"
- GITLAB_WORKHORSE_VERSION: "${GITLAB_WORKHORSE_VERSION}"
+ GITLAB_METRICS_EXPORTER_VERSION: "${GITLAB_METRICS_EXPORTER_VERSION}"
GITLAB_PAGES_VERSION: "${GITLAB_PAGES_VERSION}"
+ GITLAB_SHELL_VERSION: "${GITLAB_SHELL_VERSION}"
+ GITLAB_WORKHORSE_VERSION: "${GITLAB_WORKHORSE_VERSION}"
GITALY_SERVER_VERSION: "${GITALY_SERVER_VERSION}"
+ RUBY_VERSION: "${FULL_RUBY_VERSION}"
trigger:
project: gitlab-org/build/CNG-mirror
branch: $TRIGGER_BRANCH
@@ -88,9 +91,9 @@ review-build-cng:
variables:
HOST_SUFFIX: "${CI_ENVIRONMENT_SLUG}"
DOMAIN: "-${CI_ENVIRONMENT_SLUG}.${REVIEW_APPS_DOMAIN}"
- GITLAB_HELM_CHART_REF: "138c146a5ba787942f66d4c7d795d224d6ba206a"
+ GITLAB_HELM_CHART_REF: "ed813953079c1d81aa69d4cb8171c69aa9741f01" # 6.5.4: https://gitlab.com/gitlab-org/charts/gitlab/-/commit/ed813953079c1d81aa69d4cb8171c69aa9741f01
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
+ 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}
on_stop: review-stop
auto_stop_in: 48 hours
@@ -113,11 +116,11 @@ review-deploy:
- echo "QA_GITLAB_URL=${CI_ENVIRONMENT_URL}" > environment.env
- *base-before_script
script:
- - check_kube_domain
- - download_chart
- - deploy || (display_deployment_debug && exit 1)
- - verify_deploy || exit 1
- - disable_sign_ups || (delete_release && exit 1)
+ - run_timed_command "check_kube_domain"
+ - run_timed_command "download_chart"
+ - run_timed_command "deploy" || (display_deployment_debug && exit 1)
+ - run_timed_command "verify_deploy"|| (display_deployment_debug && exit 1)
+ - run_timed_command "disable_sign_ups"
after_script:
# Run seed-dast-test-data.sh only when DAST_RUN is set to true. This is to pupulate review app with data for DAST scan.
# Set DAST_RUN to true when jobs are manually scheduled.
@@ -165,14 +168,14 @@ review-delete-deployment:
- .review:rules:review-delete-deployment
stage: prepare
script:
- - delete_release
+ - delete_helm_release
review-stop:
extends:
- .review-stop-base
- .review:rules:review-stop
- resource_group: review/${CI_COMMIT_REF_SLUG}${SCHEDULE_TYPE} # CI_ENVIRONMENT_SLUG is not available here and we want this to be the same as the environment
+ resource_group: review/${CI_COMMIT_REF_SLUG}${SCHEDULE_TYPE} # CI_ENVIRONMENT_SLUG is not available here and we want this to be the same as the environment
stage: deploy
needs: []
script:
- - delete_namespace
+ - delete_helm_release
diff --git a/.gitlab/ci/review-apps/qa.gitlab-ci.yml b/.gitlab/ci/review-apps/qa.gitlab-ci.yml
index 0214f5ef3f2..69ce028987a 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: 1.3.0
+ ref: 1.7.0
file:
- /ci/base.gitlab-ci.yml
- /ci/allure-report.yml
@@ -25,7 +25,7 @@ include:
- cd qa && bundle install
.review-qa-base:
- image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-bullseye-ruby-${RUBY_VERSION}:bundler-2.3-git-2.33-lfs-2.9-chrome-${CHROME_VERSION}-docker-${DOCKER_VERSION}-gcloud-383-kubectl-1.23
+ image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-bullseye-ruby-${RUBY_VERSION}:bundler-2.3-git-2.36-lfs-2.9-chrome-${CHROME_VERSION}-docker-${DOCKER_VERSION}-gcloud-383-kubectl-1.23
extends:
- .use-docker-in-docker
- .bundle-base
@@ -140,13 +140,13 @@ e2e-test-report:
variables:
ALLURE_JOB_NAME: e2e-review-qa
ALLURE_PROJECT_PATH: $CI_PROJECT_PATH
- ALLURE_RESULTS_GLOB: qa/tmp/allure-results/*
+ ALLURE_RESULTS_GLOB: qa/tmp/allure-results
ALLURE_MERGE_REQUEST_IID: $CI_MERGE_REQUEST_IID
GITLAB_AUTH_TOKEN: $GITLAB_QA_MR_ALLURE_REPORT_TOKEN
GIT_STRATEGY: none
allow_failure: true
when: always
- artifacts: # re-save rspec results for displaying in parent pipeline
+ artifacts: # re-save rspec results for displaying in parent pipeline
expire_in: 1 day
when: always
paths:
@@ -178,7 +178,7 @@ notify-slack:
extends:
- .notify-slack-qa
- .qa-cache
- - .rules:notify-slack
+ - .rules:main-run
stage: post-qa
variables:
RUN_WITH_BUNDLE: "true"
@@ -188,6 +188,16 @@ notify-slack:
STATUS_SYM: ☠ï¸
STATUS: failed
TYPE: "(review-app) "
+ when: on_failure
script:
- - bundle exec gitlab-qa-report --prepare-stage-reports "$CI_PROJECT_DIR/qa/tmp/rspec-*.xml" # generate summary
+ - bundle exec gitlab-qa-report --prepare-stage-reports "$CI_PROJECT_DIR/qa/tmp/rspec-*.xml" # generate summary
- !reference [.notify-slack-qa, script]
+
+export-test-metrics:
+ extends:
+ - .bundle-base
+ - .rules:main-run
+ stage: post-qa
+ when: always
+ script:
+ - bundle exec rake "ci:export_test_metrics[tmp/test-metrics-*.json]"
diff --git a/.gitlab/ci/review-apps/rules.gitlab-ci.yml b/.gitlab/ci/review-apps/rules.gitlab-ci.yml
index 4e07f381bc9..49343c98547 100644
--- a/.gitlab/ci/review-apps/rules.gitlab-ci.yml
+++ b/.gitlab/ci/review-apps/rules.gitlab-ci.yml
@@ -15,9 +15,9 @@
.app-changes: &app-changes
if: $APP_CHANGE_TRIGGER == "true"
-# QA framework changes present
-.qa-framework-changes: &qa-framework-changes
- if: $QA_FRAMEWORK_CHANGES == "true"
+# Run all tests when framework changes present or explicitly enabled full suite execution
+.qa-run-all-tests: &qa-run-all-tests
+ if: $QA_FRAMEWORK_CHANGES == "true" || $QA_RUN_ALL_TESTS == "true"
.default-branch: &default-branch
if: $CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH
@@ -28,19 +28,19 @@
variables:
QA_TESTS: ""
-.never-when-qa-framework-changes-or-no-specific-specs:
- - <<: *qa-framework-changes
+.never-when-qa-run-all-tests-or-no-specific-specs:
+ - <<: *qa-run-all-tests
when: never
- <<: *all-specs
when: never
-.never-when-specific-specs-always-when-qa-framework-changes:
+.never-when-specific-specs-always-when-qa-run-all-tests:
+ - *qa-run-all-tests
- <<: *specific-specs
when: manual
allow_failure: true
variables:
QA_TESTS: ""
- - *qa-framework-changes
# ------------------------------------------
# Prepare
@@ -61,8 +61,8 @@
# always trigger smoke suite if review pipeline got triggered by specific changes in application code
- <<: *app-changes
variables:
- QA_TESTS: "" # unset QA_TESTS even if specific tests were inferred from stage label
- - *qa-framework-changes
+ QA_TESTS: "" # unset QA_TESTS even if specific tests were inferred from stage label
+ - *qa-run-all-tests
- if: $QA_SUITES =~ /Test::Instance::Smoke/
- *qa-manual
@@ -70,25 +70,25 @@
rules:
- <<: *app-changes
when: never
- - !reference [.never-when-qa-framework-changes-or-no-specific-specs]
+ - !reference [.never-when-qa-run-all-tests-or-no-specific-specs]
- if: $QA_SUITES =~ /Test::Instance::ReviewBlocking/
.rules:qa-blocking-parallel:
rules:
# always trigger blocking suite if review pipeline got triggered by specific changes in application code
- <<: *app-changes
variables:
- QA_TESTS: "" # unset QA_TESTS even if specific tests were inferred from stage label
- - !reference [.never-when-specific-specs-always-when-qa-framework-changes]
+ QA_TESTS: "" # unset QA_TESTS even if specific tests were inferred from stage label
+ - !reference [.never-when-specific-specs-always-when-qa-run-all-tests]
- if: $QA_SUITES =~ /Test::Instance::ReviewBlocking/
.rules:qa-non-blocking:
rules:
- - !reference [.never-when-qa-framework-changes-or-no-specific-specs]
+ - !reference [.never-when-qa-run-all-tests-or-no-specific-specs]
- if: $QA_SUITES =~ /Test::Instance::ReviewNonBlocking/
.rules:qa-non-blocking-parallel:
rules:
- - !reference [.never-when-specific-specs-always-when-qa-framework-changes]
- - *all-specs-mr # set full suite to manual when no specific specs passed in mr
+ - !reference [.never-when-specific-specs-always-when-qa-run-all-tests]
+ - *all-specs-mr # set full suite to manual when no specific specs passed in mr
- if: $QA_SUITES =~ /Test::Instance::ReviewNonBlocking/
# ------------------------------------------
@@ -98,7 +98,6 @@
rules:
- when: always
-.rules:notify-slack:
+.rules:main-run:
rules:
- - <<: *default-branch
- when: on_failure
+ - *default-branch
diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml
index aefa96da159..35df4de6513 100644
--- a/.gitlab/ci/review.gitlab-ci.yml
+++ b/.gitlab/ci/review.gitlab-ci.yml
@@ -3,27 +3,23 @@ review-cleanup:
- .default-retry
- .review:rules:review-cleanup
image: ${REVIEW_APPS_IMAGE}
- resource_group: review/${CI_COMMIT_REF_SLUG}${SCHEDULE_TYPE} # CI_ENVIRONMENT_SLUG is not available here and we want this to be the same as the environment
stage: prepare
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
+ name: review/regular-cleanup
action: stop
before_script:
- source scripts/utils.sh
- - source scripts/review_apps/review-apps.sh
- source scripts/review_apps/gcp_cleanup.sh
- install_gitlab_gem
- setup_gcp_dependencies
script:
- - delete_release
- - delete_namespace
- scripts/review_apps/automated_cleanup.rb
- gcp_cleanup
start-review-app-pipeline:
extends:
- .review:rules:start-review-app-pipeline
- resource_group: review/${CI_COMMIT_REF_SLUG}${SCHEDULE_TYPE} # CI_ENVIRONMENT_SLUG is not available here and we want this to be the same as the environment
+ resource_group: review/${CI_COMMIT_REF_SLUG}${SCHEDULE_TYPE} # CI_ENVIRONMENT_SLUG is not available here and we want this to be the same as the environment
stage: review
needs:
- job: e2e-test-pipeline-generate
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index afe900f39a6..c6cfb491e61 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -5,19 +5,23 @@
if: '$CI_PROJECT_NAMESPACE !~ /^gitlab(-org)?($|\/)/'
.if-not-ee: &if-not-ee
- if: '$CI_PROJECT_NAME !~ /^gitlab(-ee)?$/'
+ # Only consider FOSS not EE
+ if: '$CI_PROJECT_NAME !~ /^gitlab(-ee)?$/ && $CI_PROJECT_NAME !~ /^gitlab-jh/'
.if-not-foss: &if-not-foss
if: '$CI_PROJECT_NAME != "gitlab-foss" && $CI_PROJECT_NAME != "gitlab-ce" && $CI_PROJECT_NAME != "gitlabhq"'
.if-jh: &if-jh
- if: '$CI_PROJECT_PATH =~ /^gitlab-(jh|cn)\/.*/'
+ # Example of these projects:
+ # https://jihulab.com/gitlab-cn/gitlab
+ # https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation
+ if: '$CI_PROJECT_PATH =~ /^gitlab-(jh|cn)\/.*/ || $CI_PROJECT_NAME =~ /^gitlab-jh/'
.if-force-ci: &if-force-ci
if: '$FORCE_GITLAB_CI'
.if-default-refs: &if-default-refs
- if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG || $FORCE_GITLAB_CI'
+ if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_COMMIT_REF_NAME == "ruby3" || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG || $FORCE_GITLAB_CI'
.if-default-branch-refs: &if-default-branch-refs
if: '$CI_COMMIT_REF_NAME == $CI_DEFAULT_BRANCH && $CI_MERGE_REQUEST_IID == null'
@@ -79,8 +83,11 @@
.if-merge-request-labels-group-global-search: &if-merge-request-labels-group-global-search
if: '$CI_MERGE_REQUEST_LABELS =~ /group::global search/'
-.if-merge-request-labels-pipeline-revert: &if-merge-request-labels-pipeline-revert
- if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:revert/'
+.if-merge-request-labels-pipeline-expedite-master-fixing: &if-merge-request-labels-pipeline-expedite-master-fixing
+ if: '$CI_MERGE_REQUEST_LABELS =~ /master:(foss-)?broken/ && $CI_MERGE_REQUEST_LABELS =~ /pipeline:expedite-master-fixing/'
+
+.if-merge-request-labels-frontend-and-feature-flag: &if-merge-request-labels-frontend-and-feature-flag
+ if: '$CI_MERGE_REQUEST_LABELS =~ /frontend/ && $CI_MERGE_REQUEST_LABELS =~ /feature flag/'
.if-security-merge-request: &if-security-merge-request
if: '$CI_PROJECT_NAMESPACE == "gitlab-org/security" && $CI_MERGE_REQUEST_IID'
@@ -206,6 +213,9 @@
- "scripts/lint-doc.sh"
- ".gitlab/ci/docs.gitlab-ci.yml"
+.docs-code-quality-patterns: &docs-code-quality-patterns
+ - "doc/**/*.md"
+
.docs-deprecations-and-removals-patterns: &docs-deprecations-and-removals-patterns
- "doc/update/deprecations.md"
- "doc/update/removals.md"
@@ -275,7 +285,7 @@
- "Dockerfile.assets"
- "config/**/*.js"
- "vendor/assets/**/*"
- - "{app/assets,app/components,app/helpers,app/presenters,app/views,locale,public,spec/frontend,symbol}/**/*"
+ - "{app/assets,app/components,app/helpers,app/presenters,app/views,locale,public,spec/frontend,storybook,symbol}/**/*"
.controllers-patterns: &controllers-patterns
- "{,ee/,jh/}{app/controllers}/**/*"
@@ -390,7 +400,7 @@
- "Rakefile"
- "tests.yml"
- "config.ru"
- - "{,ee/,jh/}{app,bin,config,db,generator_templates,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
+ - "{,ee/,jh/}{app,bin,config,db,generator_templates,haml_lint,lib,locale,public,scripts,storybook,symbol,vendor}/**/*"
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated
# CI changes
- ".gitlab-ci.yml"
@@ -447,7 +457,7 @@
- "Rakefile"
- "tests.yml"
- "config.ru"
- - "{,ee/,jh/}{app,bin,config,db,generator_templates,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
+ - "{,ee/,jh/}{app,bin,config,db,generator_templates,haml_lint,lib,locale,public,scripts,storybook,symbol,vendor}/**/*"
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated
# CI changes
- ".gitlab-ci.yml"
@@ -466,6 +476,9 @@
- "data/whats_new/*.yml"
# .code-backstage-qa-patterns + .workhorse-patterns
+# NOTE: `setup-test-env-patterns` intentionally does not include docs files, because this would
+# result in docs-only pipelines having failures of jobs which use `setup-test-env-patterns`
+# in their rules and thus require `setup-test-env`, which isn't present in docs-only pipelines.
.setup-test-env-patterns: &setup-test-env-patterns
- "{package.json,yarn.lock}"
- ".browserslistrc"
@@ -481,7 +494,7 @@
- "Rakefile"
- "tests.yml"
- "config.ru"
- - "{,ee/,jh/}{app,bin,config,db,generator_templates,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
+ - "{,ee/,jh/}{app,bin,config,db,generator_templates,haml_lint,lib,locale,public,scripts,storybook,symbol,vendor}/**/*"
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated
- "data/whats_new/*.yml"
# CI changes
@@ -504,6 +517,8 @@
# CI Templates changes
- "scripts/lint_templates_bash.rb"
- "lib/gitlab/ci/templates/**/*.gitlab-ci.yml"
+ # GLFM specification changes
+ - "glfm_specification/**/*"
.static-analysis-patterns: &static-analysis-patterns
- ".{codeclimate,eslintrc,haml-lint,haml-lint_todo}.yml"
@@ -535,9 +550,16 @@
.feature-flag-development-config-patterns: &feature-flag-development-config-patterns
- "{,ee/,jh/}config/feature_flags/{development,ops}/*.yml"
+.glfm-patterns: &glfm-patterns
+ - ".gitlab/ci/rules.gitlab-ci.yml"
+ - "glfm_specification/**/*"
+ - "scripts/glfm/**/*"
+ - "scripts/lib/glfm/**/*"
+
##################
# Conditions set #
##################
+
.strict-ee-only-rules:
rules:
- <<: *if-not-ee
@@ -545,6 +567,13 @@
- <<: *if-jh
when: never
+.as-if-jh-default-exclusion-rules:
+ rules:
+ - <<: *if-security-merge-request
+ when: never
+ - <<: *if-merge-request-targeting-stable-branch
+ when: never
+
.rails:rules:minimal-default-rules:
rules:
- <<: *if-merge-request-approved
@@ -558,6 +587,8 @@
rules:
- <<: *if-merge-request-labels-group-global-search
changes: *search-backend-patterns
+ - <<: *if-merge-request-labels-group-global-search
+ changes: *ci-patterns
.rails:rules:ee-and-foss-default-rules:
rules:
@@ -636,7 +667,8 @@
.shared:rules:update-gitaly-binaries-cache:
rules:
- <<: *if-merge-request-labels-update-caches
- - changes: *gitaly-patterns
+ - <<: *if-default-refs
+ changes: *gitaly-patterns
######################
# Build images rules #
@@ -653,7 +685,11 @@
changes: *code-qa-patterns
- <<: *if-auto-deploy-branches
- <<: *if-default-branch-or-tag
+ variables:
+ ARCH: amd64,arm64
- <<: *if-dot-com-gitlab-org-schedule
+ variables:
+ ARCH: amd64,arm64
- <<: *if-force-ci
- <<: *if-ruby3-branch
@@ -665,8 +701,10 @@
- <<: *if-merge-request-labels-run-review-app
- <<: *if-auto-deploy-branches
- <<: *if-ruby3-branch
- - changes: *ci-build-images-patterns
- - changes: *code-qa-patterns
+ - <<: *if-default-refs
+ changes: *ci-build-images-patterns
+ - <<: *if-default-refs
+ changes: *code-qa-patterns
#################
# Caching rules #
@@ -760,6 +798,12 @@
when: manual
allow_failure: true
+.docs:rules:docs-code-quality:
+ rules:
+ - <<: *if-default-branch-refs
+ - <<: *if-default-refs
+ changes: *docs-code-quality-patterns
+
.docs:rules:docs-lint:
rules:
- <<: *if-default-refs
@@ -771,6 +815,36 @@
changes: *docs-deprecations-and-removals-patterns
##################
+# GLFM rules #
+##################
+.glfm:rules:glfm-verify:
+ # NOTES ON RULES:
+ # 1. We only run this job in EE because some of the markdown examples in the generated files depend
+ # on EE-only features. This means that it may fail when it is first run in a full EE pipeline.
+ # 2. We run this job for the `.setup-test-env-patterns` subset of file changes because:
+ # A. There are potentially many different source files within the codebase which could
+ # change the contents of the generated GLFM files, and it is therefore safer to always
+ # run this job to ensure that no changes are missed.
+ # B. The `.setup-test-env-patterns` restriction is needed because the job `needs` the
+ # `setup-test-env` job.
+ # See more context on each rule in the inline comments below:
+ rules:
+ # The `glfm-verify` job has dependencies on EE, so only run it for EE
+ - !reference [".strict-ee-only-rules", rules]
+ # If any of the files that are DIRECTLY related to generating or managing the GLFM specification change,
+ # run `glfm-verify` to get quick feedback on any needed updates, even if the MR is not yet approved
+ - changes: *glfm-patterns
+ # Otherwise do not run `glfm-verify` if the MR is not approved
+ - <<: *if-merge-request-not-approved
+ when: never
+ # If we passed all the previous rules, run `glfm-verify` if there are any changes that could impact `glfm-verify`.
+ # This could potentially be a wide range of files, so we reuse `setup-test-env-patterns`, which includes
+ # almost all app files except docs files.
+ - changes: *setup-test-env-patterns
+ # If we are forcing all rspec to run, run this job too.
+ - <<: *if-merge-request-labels-run-all-rspec
+
+##################
# GraphQL rules #
##################
.graphql:rules:graphql-verify:
@@ -786,6 +860,8 @@
.frontend:rules:minimal-default-rules:
rules:
+ - <<: *if-merge-request-approved
+ when: never
- <<: *if-automated-merge-request
when: never
- <<: *if-security-merge-request
@@ -798,15 +874,21 @@
- <<: *if-merge-request-targeting-stable-branch
- <<: *if-merge-request-labels-run-review-app
- <<: *if-auto-deploy-branches
- - changes: *ci-build-images-patterns
- - changes: *code-qa-patterns
- - changes: *workhorse-patterns
+ - <<: *if-ruby3-branch
+ - <<: *if-default-refs
+ changes: *ci-build-images-patterns
+ - <<: *if-default-refs
+ changes: *code-qa-patterns
+ - <<: *if-default-refs
+ changes: *workhorse-patterns
.frontend:rules:compile-test-assets:
rules:
- <<: *if-merge-request-labels-run-all-rspec
- - changes: *code-backstage-qa-patterns
- - changes: *workhorse-patterns
+ - <<: *if-default-refs
+ changes: *code-backstage-qa-patterns
+ - <<: *if-default-refs
+ changes: *workhorse-patterns
.frontend:rules:compile-test-assets-as-if-foss:
rules:
@@ -814,14 +896,18 @@
when: never
- <<: *if-merge-request-labels-as-if-foss
- <<: *if-merge-request-labels-run-all-rspec
- - changes: *code-backstage-qa-patterns
- - changes: *startup-css-patterns
- - changes: *workhorse-patterns
+ - <<: *if-default-refs
+ changes: *code-backstage-qa-patterns
+ - <<: *if-default-refs
+ changes: *startup-css-patterns
+ - <<: *if-default-refs
+ changes: *workhorse-patterns
.frontend:rules:default-frontend-jobs:
rules:
- <<: *if-merge-request-labels-run-all-rspec
- - changes: *code-backstage-patterns
+ - <<: *if-default-refs
+ changes: *code-backstage-patterns
.frontend:rules:default-frontend-jobs-as-if-foss:
rules:
@@ -832,11 +918,14 @@
- <<: *if-merge-request-labels-run-all-rspec
- <<: *if-merge-request
changes: *startup-css-patterns
+ - <<: *if-merge-request
+ changes: *frontend-patterns-for-as-if-foss
.frontend:rules:frontend_fixture-as-if-foss:
rules:
- !reference [".strict-ee-only-rules", rules]
- !reference [".frontend:rules:default-frontend-jobs-as-if-foss", rules]
+ - <<: *if-merge-request-labels-run-all-jest
- <<: *if-merge-request
changes: *frontend-patterns-for-as-if-foss
@@ -845,13 +934,18 @@
- <<: *if-fork-merge-request
when: never
- <<: *if-merge-request-labels-run-all-jest
+ - <<: *if-merge-request-labels-frontend-and-feature-flag
+ - <<: *if-merge-request
+ changes: *frontend-dependency-patterns
- <<: *if-merge-request
changes: [".gitlab/ci/rules.gitlab-ci.yml", ".gitlab/ci/frontend.gitlab-ci.yml"]
- <<: *if-automated-merge-request
changes: *code-backstage-patterns
- <<: *if-security-merge-request
changes: *code-backstage-patterns
- - <<: *if-default-branch-refs
+ - <<: *if-merge-request-not-approved
+ when: never
+ - <<: *if-default-refs
changes: *code-backstage-patterns
.frontend:rules:jest:minimal:
@@ -861,10 +955,13 @@
- !reference [".frontend:rules:minimal-default-rules", rules]
- <<: *if-merge-request-labels-run-all-jest
when: never
- - changes: *core-frontend-patterns
+ - <<: *if-merge-request-labels-frontend-and-feature-flag
when: never
- <<: *if-merge-request
- changes: *ci-patterns
+ changes: *frontend-dependency-patterns
+ when: never
+ - <<: *if-merge-request
+ changes: [".gitlab/ci/rules.gitlab-ci.yml", ".gitlab/ci/frontend.gitlab-ci.yml"]
when: never
- <<: *if-merge-request
changes: *code-backstage-patterns
@@ -874,15 +971,26 @@
- !reference [".strict-ee-only-rules", rules]
- <<: *if-merge-request-labels-as-if-foss
- <<: *if-merge-request-labels-run-all-jest
+ - <<: *if-merge-request
+ changes: *frontend-dependency-patterns
- <<: *if-security-merge-request
changes: *code-backstage-patterns
+ - <<: *if-merge-request-not-approved
+ when: never
+ - <<: *if-merge-request
+ changes: *frontend-patterns-for-as-if-foss
.frontend:rules:jest:minimal:as-if-foss:
rules:
- !reference [".strict-ee-only-rules", rules]
- !reference [".frontend:rules:minimal-default-rules", rules]
+ - <<: *if-merge-request-labels-as-if-foss
+ when: never
- <<: *if-merge-request-labels-run-all-jest
when: never
+ - <<: *if-merge-request
+ changes: *frontend-dependency-patterns
+ when: never
- <<: *if-fork-merge-request
when: never
- <<: *if-merge-request
@@ -899,7 +1007,7 @@
rules:
- <<: *if-not-ee
when: never
- - <<: *if-merge-request-labels-pipeline-revert
+ - <<: *if-merge-request-labels-pipeline-expedite-master-fixing
when: never
- <<: *if-merge-request
changes: *code-backstage-patterns
@@ -941,6 +1049,18 @@
- <<: *if-default-refs
changes: *code-patterns
+##########
+# Notify #
+##########
+.notify:rules:notify-pipeline-failure:
+ rules:
+ # Don't report child pipeline failures
+ - if: '$CI_PIPELINE_SOURCE == "parent_pipeline"'
+ when: never
+ - if: '$CI_SLACK_WEBHOOK_URL && $NOTIFY_PIPELINE_FAILURE_CHANNEL'
+ when: on_failure
+ allow_failure: true
+
###############
# Pages rules #
###############
@@ -996,7 +1116,7 @@
when: never
- <<: *if-not-ee
when: never
- - <<: *if-merge-request-labels-pipeline-revert
+ - <<: *if-merge-request-labels-pipeline-expedite-master-fixing
when: never
- <<: *if-merge-request-targeting-stable-branch
allow_failure: true
@@ -1031,6 +1151,8 @@
SKIP_REPORT_IN_ISSUES: "false"
PROCESS_TEST_RESULTS: "true"
KNAPSACK_GENERATE_REPORT: "true"
+ QA_SAVE_TEST_METRICS: "true"
+ QA_EXPORT_TEST_METRICS: "false" # on main runs, metrics are exported to separate bucket via rake task for better consistency
- <<: *if-force-ci
when: manual
allow_failure: true
@@ -1040,7 +1162,8 @@
###############
.rails:rules:setup-test-env:
rules:
- - changes: *setup-test-env-patterns
+ - <<: *if-default-refs
+ changes: *setup-test-env-patterns
- <<: *if-merge-request-labels-run-all-rspec
.rails:rules:single-db:
@@ -1072,7 +1195,8 @@
changes: *db-patterns
- <<: *if-merge-request-not-approved
when: never
- - changes: *db-patterns
+ - <<: *if-default-refs
+ changes: *db-patterns
.rails:rules:ee-and-foss-migration:minimal:
rules:
@@ -1105,7 +1229,8 @@
- <<: *if-fork-merge-request
when: never
- !reference [".rails:rules:ee-and-foss-default-rules", rules]
- - changes: *backend-patterns
+ - <<: *if-default-refs
+ changes: *backend-patterns
.rails:rules:ee-and-foss-unit:minimal:
rules:
@@ -1121,7 +1246,8 @@
- <<: *if-fork-merge-request
when: never
- !reference [".rails:rules:ee-and-foss-default-rules", rules]
- - changes: *backend-patterns
+ - <<: *if-default-refs
+ changes: *backend-patterns
.rails:rules:ee-and-foss-integration:minimal:
rules:
@@ -1137,7 +1263,8 @@
- <<: *if-fork-merge-request
when: never
- !reference [".rails:rules:system-default-rules", rules]
- - changes: *code-backstage-patterns
+ - <<: *if-default-refs
+ changes: *code-backstage-patterns
.rails:rules:ee-and-foss-system:minimal:
rules:
@@ -1151,11 +1278,13 @@
- <<: *if-merge-request-labels-run-all-rspec
- <<: *if-merge-request
changes: *backend-patterns
- - changes: *core-backend-patterns
+ - <<: *if-default-refs
+ changes: *core-backend-patterns
.rails:rules:code-backstage-qa:
rules:
- - changes: *code-backstage-qa-patterns
+ - <<: *if-default-refs
+ changes: *code-backstage-qa-patterns
- <<: *if-merge-request-labels-run-all-rspec
.rails:rules:ee-only-migration:
@@ -1175,7 +1304,8 @@
changes: *db-patterns
- <<: *if-merge-request-not-approved
when: never
- - changes: *db-patterns
+ - <<: *if-default-refs
+ changes: *db-patterns
.rails:rules:ee-only-migration:minimal:
rules:
@@ -1196,7 +1326,8 @@
- <<: *if-fork-merge-request
when: never
- !reference [".rails:rules:ee-and-foss-default-rules", rules]
- - changes: *backend-patterns
+ - <<: *if-default-refs
+ changes: *backend-patterns
.rails:rules:ee-only-unit:minimal:
rules:
@@ -1216,7 +1347,8 @@
- <<: *if-fork-merge-request
when: never
- !reference [".rails:rules:ee-and-foss-default-rules", rules]
- - changes: *backend-patterns
+ - <<: *if-default-refs
+ changes: *backend-patterns
.rails:rules:ee-only-integration:minimal:
rules:
@@ -1236,7 +1368,8 @@
- <<: *if-fork-merge-request
when: never
- !reference [".rails:rules:system-default-rules", rules]
- - changes: *code-backstage-patterns
+ - <<: *if-default-refs
+ changes: *code-backstage-patterns
.rails:rules:ee-only-system:minimal:
rules:
@@ -1350,7 +1483,8 @@
.rails:rules:ee-and-foss-db-library-code:
rules:
- - changes: *db-library-patterns
+ - <<: *if-default-refs
+ changes: *db-library-patterns
- <<: *if-merge-request-labels-run-all-rspec
.rails:rules:ee-mr-and-default-branch-only:
@@ -1366,8 +1500,10 @@
.rails:rules:detect-tests:
rules:
- <<: *if-merge-request-labels-run-all-rspec
- - changes: *code-backstage-qa-patterns
- - changes: *workhorse-patterns
+ - <<: *if-default-refs
+ changes: *code-backstage-qa-patterns
+ - <<: *if-default-refs
+ changes: *workhorse-patterns
.rails:rules:detect-previous-failed-tests:
rules:
@@ -1419,7 +1555,7 @@
rules:
- <<: *if-not-ee
when: never
- - <<: *if-merge-request-labels-pipeline-revert
+ - <<: *if-merge-request-labels-pipeline-expedite-master-fixing
when: never
- <<: *if-merge-request
changes: *code-backstage-patterns
@@ -1430,7 +1566,7 @@
rules:
- <<: *if-not-ee
when: never
- - <<: *if-merge-request-labels-pipeline-revert
+ - <<: *if-merge-request-labels-pipeline-expedite-master-fixing
when: never
- <<: *if-merge-request-labels-skip-undercoverage
when: never
@@ -1458,13 +1594,14 @@
rules:
- <<: *if-not-ee
when: never
- - changes: *code-backstage-patterns
+ - <<: *if-default-refs
+ changes: *code-backstage-patterns
.rails:rules:flaky-tests-report:
rules:
- <<: *if-not-ee
when: never
- - <<: *if-merge-request-labels-pipeline-revert
+ - <<: *if-merge-request-labels-pipeline-expedite-master-fixing
when: never
- if: '$SKIP_FLAKY_TESTS_AUTOMATICALLY == "true" || $RETRY_FAILED_TESTS_IN_NEW_PROCESS == "true"'
changes: *code-backstage-patterns
@@ -1476,38 +1613,51 @@
.static-analysis:rules:static-analysis:
rules:
- - changes: *code-backstage-qa-patterns
- - changes: *static-analysis-patterns
+ - <<: *if-default-refs
+ changes: *code-backstage-qa-patterns
+ - <<: *if-default-refs
+ changes: *static-analysis-patterns
.static-analysis:rules:static-verification-with-database:
rules:
- - changes: *code-backstage-qa-patterns
+ - <<: *if-default-refs
+ changes: *code-backstage-qa-patterns
.static-analysis:rules:rubocop:
rules:
- - changes: *rubocop-patterns
+ - <<: *if-default-refs
+ changes: *rubocop-patterns
variables:
RUN_ALL_RUBOCOP: "true"
- - changes: *code-backstage-qa-patterns
+ - <<: *if-default-refs
+ changes: *code-backstage-qa-patterns
.static-analysis:rules:qa:metadata-lint:
rules:
- - changes: *qa-patterns
- - changes: [".gitlab/ci/static-analysis.gitlab-ci.yml"]
+ - <<: *if-default-refs
+ changes: *qa-patterns
+ - <<: *if-default-refs
+ changes: [".gitlab/ci/static-analysis.gitlab-ci.yml"]
.static-analysis:rules:haml-lint:
rules:
- - changes: *rubocop-patterns
- - changes: *static-analysis-patterns
- - changes: *code-backstage-qa-patterns
+ - <<: *if-default-refs
+ changes: *rubocop-patterns
+ - <<: *if-default-refs
+ changes: *static-analysis-patterns
+ - <<: *if-default-refs
+ changes: *code-backstage-qa-patterns
.static-analysis:rules:haml-lint-ee:
rules:
- <<: *if-not-ee
when: never
- - changes: *rubocop-patterns
- - changes: *static-analysis-patterns
- - changes: *code-backstage-qa-patterns
+ - <<: *if-default-refs
+ changes: *rubocop-patterns
+ - <<: *if-default-refs
+ changes: *static-analysis-patterns
+ - <<: *if-default-refs
+ changes: *code-backstage-qa-patterns
.static-analysis:rules:static-analysis-as-if-foss:
rules:
@@ -1614,8 +1764,10 @@
rules:
- if: '$CODE_QUALITY_DISABLED'
when: never
+ # Run code_quality on master until https://gitlab.com/gitlab-org/gitlab/-/issues/363747 is resolved
+ - <<: *if-default-branch-refs
- <<: *if-default-refs
- changes: *code-backstage-patterns
+ changes: *code-backstage-qa-patterns
.reports:rules:brakeman-sast:
rules:
@@ -1623,26 +1775,19 @@
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /brakeman/
when: never
- - changes:
+ - <<: *if-default-refs
+ changes:
- '**/*.rb'
- '**/Gemfile'
-.reports:rules:gosec-sast:
- rules:
- - if: $SAST_DISABLED
- when: never
- - if: $SAST_EXCLUDED_ANALYZERS =~ /gosec/
- when: never
- - changes:
- - '**/*.go'
-
.reports:rules:semgrep-sast:
rules:
- if: $SAST_DISABLED
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /semgrep/
when: never
- - changes:
+ - <<: *if-default-refs
+ changes:
- '**/*.py'
- '**/*.js'
- '**/*.jsx'
@@ -1658,7 +1803,8 @@
when: never
# Scan each commit on master to feed the Vulnerability Reports with detected secrets
- <<: *if-default-branch-refs
- - changes: *code-backstage-qa-patterns
+ - <<: *if-default-refs
+ changes: *code-backstage-qa-patterns
.reports:rules:gemnasium-dependency_scanning:
rules:
@@ -1666,7 +1812,8 @@
when: never
# Run Dependency Scanning on master until https://gitlab.com/gitlab-org/gitlab/-/issues/361657 is resolved
- <<: *if-default-branch-refs
- - changes: *dependency-patterns
+ - <<: *if-default-refs
+ changes: *dependency-patterns
.reports:rules:gemnasium-python-dependency_scanning:
rules:
@@ -1674,7 +1821,8 @@
when: never
# Run Dependency Scanning on master until https://gitlab.com/gitlab-org/gitlab/-/issues/361657 is resolved
- <<: *if-default-branch-refs
- - changes: *python-patterns
+ - <<: *if-default-refs
+ changes: *python-patterns
.reports:rules:yarn-audit-dependency_scanning:
rules:
@@ -1682,7 +1830,8 @@
when: never
# Run Dependency Scanning on master until https://gitlab.com/gitlab-org/gitlab/-/issues/361657 is resolved
- <<: *if-default-branch-refs
- - changes: *nodejs-patterns
+ - <<: *if-default-refs
+ changes: *nodejs-patterns
.reports:rules:schedule-dast:
rules:
@@ -1690,6 +1839,12 @@
when: never
- <<: *if-dot-com-ee-schedule-nightly-child-pipeline
+.reports:rules:test-dast:
+ rules:
+ - if: '$DAST_DISABLED || $GITLAB_FEATURES !~ /\bdast\b/'
+ when: never
+ - <<: *if-merge-request
+
.reports:rules:package_hunter-yarn:
rules:
- if: "$PACKAGE_HUNTER_USER == null || $PACKAGE_HUNTER_USER == ''"
@@ -1710,7 +1865,8 @@
rules:
- if: '$LICENSE_MANAGEMENT_DISABLED || $GITLAB_FEATURES !~ /\blicense_scanning\b/'
when: never
- - changes: *dependency-patterns
+ - <<: *if-default-refs
+ changes: *dependency-patterns
################
# Review rules #
@@ -1726,33 +1882,42 @@
rules:
- <<: *if-not-ee
when: never
- - <<: *if-merge-request-labels-pipeline-revert
+ - <<: *if-merge-request-labels-pipeline-expedite-master-fixing
when: never
- <<: *if-merge-request-labels-run-review-app
- <<: *if-dot-com-gitlab-org-merge-request
changes: *ci-review-patterns
+ when: never
- <<: *if-dot-com-gitlab-org-merge-request
changes: *frontend-build-patterns
variables: *review-change-pattern
+ when: never
- <<: *if-dot-com-gitlab-org-merge-request
changes: *controllers-patterns
variables: *review-change-pattern
+ when: never
- <<: *if-dot-com-gitlab-org-merge-request
changes: *models-patterns
variables: *review-change-pattern
+ when: never
- <<: *if-dot-com-gitlab-org-merge-request
changes: *lib-gitlab-patterns
variables: *review-change-pattern
+ when: never
- <<: *if-dot-com-gitlab-org-merge-request
changes: *qa-patterns
+ when: never
- <<: *if-dot-com-gitlab-org-merge-request
changes: *code-patterns
when: manual
allow_failure: true
- <<: *if-dot-com-gitlab-org-schedule
+ when: never
allow_failure: true
variables:
KNAPSACK_GENERATE_REPORT: "true"
+ QA_SAVE_TEST_METRICS: "true"
+ QA_EXPORT_TEST_METRICS: "false" # on main runs, metrics are exported to separate bucket via rake task for better consistency
.review:rules:review-build-cng:
rules:
@@ -1783,7 +1948,7 @@
rules:
- <<: *if-not-ee
when: never
- - <<: *if-merge-request-labels-pipeline-revert
+ - <<: *if-merge-request-labels-pipeline-expedite-master-fixing
when: never
- <<: *if-merge-request-labels-run-review-app
when: manual
@@ -1897,7 +2062,8 @@
- <<: *if-not-ee
when: never
- <<: *if-dot-com-ee-schedule-maintenance
- - changes:
+ - <<: *if-default-refs
+ changes:
- ".gitlab/ci/setup.gitlab-ci.yml"
- ".gitlab/ci/test-metadata.gitlab-ci.yml"
- "scripts/rspec_helpers.sh"
@@ -1907,8 +2073,10 @@
#######################
.test-metadata:rules:retrieve-tests-metadata:
rules:
- - changes: *code-backstage-patterns
- - changes: *workhorse-patterns
+ - <<: *if-default-refs
+ changes: *code-backstage-patterns
+ - <<: *if-default-refs
+ changes: *workhorse-patterns
- <<: *if-merge-request-labels-run-all-rspec
.test-metadata:rules:update-tests-metadata:
@@ -1916,7 +2084,8 @@
- <<: *if-not-ee
when: never
- <<: *if-dot-com-ee-schedule-maintenance
- - changes:
+ - <<: *if-default-refs
+ changes:
- ".gitlab/ci/test-metadata.gitlab-ci.yml"
- "scripts/rspec_helpers.sh"
@@ -1925,7 +2094,8 @@
###################
.workhorse:rules:workhorse:
rules:
- - changes: *workhorse-patterns
+ - <<: *if-default-refs
+ changes: *workhorse-patterns
###################
# yaml-lint rules #
@@ -1944,3 +2114,21 @@
rules:
- <<: *if-default-refs
changes: *lint-metrics-yaml-patterns
+
+##################
+# as-if-jh rules #
+##################
+.as-if-jh:rules:prepare-as-if-jh:
+ rules:
+ - !reference [".strict-ee-only-rules", rules]
+ - !reference [".as-if-jh-default-exclusion-rules", rules]
+ - <<: *if-merge-request-labels-as-if-jh
+
+# This rule should share the same logic with .as-if-jh:rules:prepare-as-if-jh
+# Because the jobs using this need jobs using the preparation rules
+.as-if-jh:rules:start-as-if-jh:
+ rules:
+ - !reference [".strict-ee-only-rules", rules]
+ - !reference [".as-if-jh-default-exclusion-rules", rules]
+ - <<: *if-merge-request-labels-as-if-jh
+ allow_failure: true # See https://gitlab.com/gitlab-org/gitlab/-/issues/351136
diff --git a/.gitlab/ci/static-analysis.gitlab-ci.yml b/.gitlab/ci/static-analysis.gitlab-ci.yml
index 59ea665ae07..0a310691cd7 100644
--- a/.gitlab/ci/static-analysis.gitlab-ci.yml
+++ b/.gitlab/ci/static-analysis.gitlab-ci.yml
@@ -122,6 +122,8 @@ rubocop:
needs:
- job: detect-tests
optional: true
+ variables:
+ RUBOCOP_TARGET_FILES: "tmp/rubocop_target_files.txt"
script:
- |
# For non-merge request, or when RUN_ALL_RUBOCOP is 'true', run all RuboCop rules
@@ -132,8 +134,13 @@ rubocop:
unset CI_SLACK_WEBHOOK_URL
run_timed_command "bundle exec rake rubocop:check:graceful"
else
- cat ${RSPEC_CHANGED_FILES_PATH} | ruby -e 'puts $stdin.read.split(" ").select { |f| File.exist?(f) }.join(" ")' > tmp/rubocop_target_files.txt
- run_timed_command "bundle exec rubocop --parallel --force-exclusion $(cat tmp/rubocop_target_files.txt)"
+ cat "${RSPEC_CHANGED_FILES_PATH}" | ruby -e 'print $stdin.read.split(" ").select { |f| File.exist?(f) }.join(" ")' > "$RUBOCOP_TARGET_FILES"
+ # Skip running RuboCop if there's no target files
+ if [ -s "${RUBOCOP_TARGET_FILES}" ]; then
+ run_timed_command "bundle exec rubocop --parallel --force-exclusion $(cat ${RUBOCOP_TARGET_FILES})"
+ else
+ echoinfo "Nothing interesting changed for RuboCop. Skipping."
+ fi
fi
qa:metadata-lint:
diff --git a/.gitlab/ci/workhorse.gitlab-ci.yml b/.gitlab/ci/workhorse.gitlab-ci.yml
index a11d5f000cf..3aa9eaee6f8 100644
--- a/.gitlab/ci/workhorse.gitlab-ci.yml
+++ b/.gitlab/ci/workhorse.gitlab-ci.yml
@@ -27,7 +27,7 @@ workhorse:test go:
extends: .workhorse:test
parallel:
matrix:
- - GO_VERSION: ["1.17", "1.18", "1.19"]
+ - GO_VERSION: ["1.18", "1.19"]
script:
- make -C workhorse test-coverage
coverage: '/\d+.\d+%/'
diff --git a/.gitlab/issue_templates/Deprecations.md b/.gitlab/issue_templates/Deprecations.md
index ef6764c3621..49f1129fe89 100644
--- a/.gitlab/issue_templates/Deprecations.md
+++ b/.gitlab/issue_templates/Deprecations.md
@@ -1,4 +1,4 @@
-For guidance on the overall deprecations, removals and breaking changes workflow, please visit [Breaking changes, deprecations, and removing features](https://about.gitlab.com/handbook/product/gitlab-the-product/#breaking-changes-deprecations-and-removing-features)
+For guidance on the overall deprecations, removals and breaking changes workflow, please visit [Breaking changes, deprecations, and removing features](https://about.gitlab.com/handbook/product/gitlab-the-product/#deprecations-removals-and-breaking-changes)
<!-- Use this template as a starting point for deprecations. -->
@@ -11,7 +11,7 @@ It is recommended that you link to the documentation.
The description of the deprecation should state what actions the user should take to rectify the behavior. If the deprecation is scheduled for an upcoming release, the content should remain in the deprecations documentation page until it has been completed. For example, if a deprecation is announced in 14.9 and scheduled to be completed in 15.0, the same content would be included in the documentation for 14.9, 14.10, and 15.0.
-**If this issue proposes a breaking change outside a major release XX.0, you need to get approval from your manager and request collaboration from Product Operations on communication. Be sure to follow the guidance [here](https://about.gitlab.com/handbook/product/gitlab-the-product/#breaking-changes-deprecations-and-removing-features.)**
+**If this issue proposes a breaking change outside a major release XX.0, you need to get approval from your manager and request collaboration from Product Operations on communication. Be sure to follow the guidance [here](https://about.gitlab.com/handbook/product/gitlab-the-product/#deprecations-removals-and-breaking-changes.)**
-->
diff --git a/.gitlab/issue_templates/Experiment Implementation.md b/.gitlab/issue_templates/Experiment Implementation.md
index fc6cfbb27fa..56202240ef5 100644
--- a/.gitlab/issue_templates/Experiment Implementation.md
+++ b/.gitlab/issue_templates/Experiment Implementation.md
@@ -18,7 +18,7 @@
# Tracking Details
- [json schema](https://gitlab.com/gitlab-org/iglu/-/blob/master/public/schemas/com.gitlab/gitlab_experiment/jsonschema/0-3-0) used in `gitlab-experiment` tracking.
-- see [taxonomy](https://docs.gitlab.com/ee/development/snowplow/index.html#structured-event-taxonomy) for a guide.
+- see [event schema](https://docs.gitlab.com/ee/development/snowplow/index.html#event-schema) for a guide.
| sequence | activity | category | action | label | property | value |
| -------- | -------- | ------ | ----- | ------- | -------- | ----- |
diff --git a/.gitlab/issue_templates/Feature Flag Roll Out.md b/.gitlab/issue_templates/Feature Flag Roll Out.md
index a9f96a61d29..40ee1c125da 100644
--- a/.gitlab/issue_templates/Feature Flag Roll Out.md
+++ b/.gitlab/issue_templates/Feature Flag Roll Out.md
@@ -1,8 +1,17 @@
<!-- Title suggestion: [Feature flag] Enable description of feature -->
+<!--
+Set the main issue link: The main issue is the one that describes the problem to solve,
+the one this feature flag is being added for. For example:
+
+[main-issue]: https://gitlab.com/gitlab-org/gitlab/-/issues/123456
+-->
+
+[main-issue]: MAIN-ISSUE-LINK
+
## Summary
-This issue is to rollout [the feature](ISSUE LINK) on production,
+This issue is to rollout [the feature][main-issue] on production,
that is currently behind the `<feature-flag-name>` feature flag.
<!-- Short description of what the feature is about and link to relevant other issues. -->
@@ -89,7 +98,7 @@ _Consider adding links to check for Sentry errors, Production logs for 5xx, 302s
- [ ] Ensure that you or a representative in development can be available for at least 2 hours after feature flag updates in production.
If a different developer will be covering, or an exception is needed, please inform the oncall SRE by using the `@sre-oncall` Slack alias.
- [ ] Ensure that documentation has been updated ([More info](https://docs.gitlab.com/ee/development/documentation/feature_flags.html#features-that-became-enabled-by-default)).
-- [ ] Announce on [the feature issue](ISSUE LINK) an estimated time this will be enabled on GitLab.com.
+- [ ] Leave a comment on [the feature issue][main-issue] announcing estimated time when this feature flag will be enabled on GitLab.com.
- [ ] Ensure that any breaking changes have been announced following the [release post process](https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations-removals-and-breaking-changes) to ensure GitLab customers are aware.
- [ ] Notify `#support_gitlab-com` and your team channel ([more guidance when this is necessary in the dev docs](https://docs.gitlab.com/ee/development/feature_flags/controls.html#communicate-the-change)).
@@ -104,7 +113,7 @@ For visibility, all `/chatops` commands that target production should be execute
- [ ] `/chatops run feature set <feature-flag-name> <rollout-percentage> --random`
- Enable the feature globally on production environment.
- [ ] `/chatops run feature set <feature-flag-name> true`
-- [ ] Announce on [the feature issue](ISSUE LINK) that the feature has been globally enabled.
+- [ ] Leave a comment on [the feature issue][main-issue] announcing that the feature has been globally enabled.
- [ ] Wait for [at least one day for the verification term](https://about.gitlab.com/handbook/product-development-flow/feature-flag-lifecycle/#including-a-feature-behind-feature-flag-in-the-final-release).
### (Optional) Release the feature with the feature flag
@@ -122,7 +131,7 @@ To do so, follow these steps:
- [ ] `/chatops run release check <merge-request-url> <milestone>`
- [ ] Consider cleaning up the feature flag from all environments by running these chatops command in `#production` channel. Otherwise these settings may override the default enabled.
- [ ] `/chatops run feature delete <feature-flag-name> --dev --staging --staging-ref --production`
-- [ ] Close [the feature issue](ISSUE LINK) to indicate the feature will be released in the current milestone.
+- [ ] Close [the feature issue][main-issue] to indicate the feature will be released in the current milestone.
- [ ] Set the next milestone to this rollout issue for scheduling [the flag removal](#release-the-feature).
- [ ] (Optional) You can [create a separate issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new?issuable_template=Feature%20Flag%20Cleanup) for scheduling the steps below to [Release the feature](#release-the-feature).
- [ ] Set the title to "[Feature flag] Cleanup `<feature-flag-name>`".
@@ -155,7 +164,7 @@ You can either [create a follow-up issue for Feature Flag Cleanup](https://gitla
If the merge request was deployed before [the monthly release was tagged](https://about.gitlab.com/handbook/engineering/releases/#self-managed-releases-1),
the feature can be officially announced in a release blog post.
- [ ] `/chatops run release check <merge-request-url> <milestone>`
-- [ ] Close [the feature issue](ISSUE LINK) to indicate the feature will be released in the current milestone.
+- [ ] Close [the feature issue][main-issue] to indicate the feature will be released in the current milestone.
- [ ] If not already done, clean up the feature flag from all environments by running these chatops command in `#production` channel:
- [ ] `/chatops run feature delete <feature-flag-name> --dev --staging --staging-ref --production`
- [ ] Close this rollout issue.
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 6c9b8bb6d78..2348fa5b86f 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
@@ -57,46 +57,38 @@ Geo secondary sites have a [Geo tracking database](https://gitlab.com/gitlab-org
# frozen_string_literal: true
class CreateCoolWidgetRegistry < Gitlab::Database::Migration[2.0]
- disable_ddl_transaction!
-
- def up
- Geo::TrackingBase.transaction do
- create_table :cool_widget_registry, id: :bigserial, force: :cascade do |t|
- t.bigint :cool_widget_id, null: false
- t.datetime_with_timezone :created_at, null: false
- t.datetime_with_timezone :last_synced_at
- t.datetime_with_timezone :retry_at
- t.datetime_with_timezone :verified_at
- t.datetime_with_timezone :verification_started_at
- t.datetime_with_timezone :verification_retry_at
- t.integer :state, default: 0, null: false, limit: 2
- t.integer :verification_state, default: 0, null: false, limit: 2
- t.integer :retry_count, default: 0, limit: 2, null: false
- t.integer :verification_retry_count, default: 0, limit: 2, null: false
- t.boolean :checksum_mismatch, default: false, null: false
- t.boolean :force_to_redownload, default: false, null: false
- t.boolean :missing_on_primary, default: false, null: false
- t.binary :verification_checksum
- t.binary :verification_checksum_mismatched
- t.text :verification_failure, limit: 255
- t.text :last_sync_failure, limit: 255
-
- t.index :cool_widget_id, name: :index_cool_widget_registry_on_cool_widget_id, unique: true
- 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))"
- # 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])))"
- # 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))"
- end
+ def change
+ create_table :cool_widget_registry, id: :bigserial, force: :cascade do |t|
+ t.bigint :cool_widget_id, null: false
+ t.datetime_with_timezone :created_at, null: false
+ t.datetime_with_timezone :last_synced_at
+ t.datetime_with_timezone :retry_at
+ t.datetime_with_timezone :verified_at
+ t.datetime_with_timezone :verification_started_at
+ t.datetime_with_timezone :verification_retry_at
+ t.integer :state, default: 0, null: false, limit: 2
+ t.integer :verification_state, default: 0, null: false, limit: 2
+ t.integer :retry_count, default: 0, limit: 2, null: false
+ t.integer :verification_retry_count, default: 0, limit: 2, null: false
+ t.boolean :checksum_mismatch, default: false, null: false
+ t.boolean :force_to_redownload, default: false, null: false
+ t.boolean :missing_on_primary, default: false, null: false
+ t.binary :verification_checksum
+ t.binary :verification_checksum_mismatched
+ t.text :verification_failure, limit: 255
+ t.text :last_sync_failure, limit: 255
+
+ t.index :cool_widget_id, name: :index_cool_widget_registry_on_cool_widget_id, unique: true
+ 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))"
+ # 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])))"
+ # 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))"
end
end
-
- def down
- drop_table :cool_widget_registry
- end
end
```
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 76fe1772921..2bb8918df60 100644
--- a/.gitlab/issue_templates/Geo Replicate a new blob type.md
+++ b/.gitlab/issue_templates/Geo Replicate a new blob type.md
@@ -59,44 +59,36 @@ Geo secondary sites have a [Geo tracking database](https://gitlab.com/gitlab-org
# frozen_string_literal: true
class CreateCoolWidgetRegistry < Gitlab::Database::Migration[2.0]
- disable_ddl_transaction!
-
- def up
- Geo::TrackingBase.transaction do
- create_table :cool_widget_registry, id: :bigserial, force: :cascade do |t|
- t.bigint :cool_widget_id, null: false
- t.datetime_with_timezone :created_at, null: false
- t.datetime_with_timezone :last_synced_at
- t.datetime_with_timezone :retry_at
- t.datetime_with_timezone :verified_at
- t.datetime_with_timezone :verification_started_at
- t.datetime_with_timezone :verification_retry_at
- t.integer :state, default: 0, null: false, limit: 2
- t.integer :verification_state, default: 0, null: false, limit: 2
- t.integer :retry_count, default: 0, limit: 2, null: false
- t.integer :verification_retry_count, default: 0, limit: 2, null: false
- t.boolean :checksum_mismatch, default: false, null: false
- t.binary :verification_checksum
- t.binary :verification_checksum_mismatched
- t.text :verification_failure, limit: 255
- t.text :last_sync_failure, limit: 255
-
- t.index :cool_widget_id, name: :index_cool_widget_registry_on_cool_widget_id, unique: true
- 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))"
- # 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])))"
- # 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))"
- end
+ def change
+ create_table :cool_widget_registry, id: :bigserial, force: :cascade do |t|
+ t.bigint :cool_widget_id, null: false
+ t.datetime_with_timezone :created_at, null: false
+ t.datetime_with_timezone :last_synced_at
+ t.datetime_with_timezone :retry_at
+ t.datetime_with_timezone :verified_at
+ t.datetime_with_timezone :verification_started_at
+ t.datetime_with_timezone :verification_retry_at
+ t.integer :state, default: 0, null: false, limit: 2
+ t.integer :verification_state, default: 0, null: false, limit: 2
+ t.integer :retry_count, default: 0, limit: 2, null: false
+ t.integer :verification_retry_count, default: 0, limit: 2, null: false
+ t.boolean :checksum_mismatch, default: false, null: false
+ t.binary :verification_checksum
+ t.binary :verification_checksum_mismatched
+ t.text :verification_failure, limit: 255
+ t.text :last_sync_failure, limit: 255
+
+ t.index :cool_widget_id, name: :index_cool_widget_registry_on_cool_widget_id, unique: true
+ 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))"
+ # 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])))"
+ # 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))"
end
end
-
- def down
- drop_table :cool_widget_registry
- end
end
```
diff --git a/.gitlab/issue_templates/Security developer workflow.md b/.gitlab/issue_templates/Security developer workflow.md
index 4cced5a25fe..daad4c19803 100644
--- a/.gitlab/issue_templates/Security developer workflow.md
+++ b/.gitlab/issue_templates/Security developer workflow.md
@@ -64,6 +64,7 @@ After your merge request has been approved according to our [approval guidelines
| Upgrade notes | | |
| GitLab Settings updated | Yes/No| |
| Migration required | Yes/No | |
+| Breaking change to UI or public API | Yes/No | <!-- How should the breaking change be communicated? --> |
| Thanks | | |
[security process for developers]: https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md
diff --git a/.gitlab/merge_request_templates/Documentation.md b/.gitlab/merge_request_templates/Documentation.md
index 2096b06d73b..bc736200046 100644
--- a/.gitlab/merge_request_templates/Documentation.md
+++ b/.gitlab/merge_request_templates/Documentation.md
@@ -14,7 +14,7 @@
- [Documentation guidelines](https://docs.gitlab.com/ee/development/documentation/).
- [Style Guide](https://docs.gitlab.com/ee/development/documentation/styleguide/).
- [ ] If you're adding or changing the main heading of the page (H1), ensure that the [product tier badge](https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#product-tier-badges) is added.
-- [ ] If you are a GitLab team member, [request a review](https://docs.gitlab.com/ee/development/code_review.html#dogfooding-the-attention-request-feature) based on:
+- [ ] If you are a GitLab team member, [request a review](https://docs.gitlab.com/ee/development/code_review.html#dogfooding-the-reviewers-feature) based on:
- The documentation page's [metadata](https://docs.gitlab.com/ee/development/documentation/#metadata).
- The [associated Technical Writer](https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments).
@@ -31,6 +31,8 @@ These labels cause the MR to be added to code verification QA issues.
Documentation-related MRs should be reviewed by a Technical Writer for a non-blocking review, based on [Documentation Guidelines](https://docs.gitlab.com/ee/development/documentation/) and the [Style Guide](https://docs.gitlab.com/ee/development/documentation/styleguide/).
+If you aren't sure which tech writer to ask, use [roulette](https://gitlab-org.gitlab.io/gitlab-roulette/?sortKey=stats.avg30&order=-1&hourFormat24=true&visible=maintainer%7Cdocs) or ask in the [#docs](https://gitlab.slack.com/archives/C16HYA2P5) Slack channel.
+
- [ ] If the content requires it, ensure the information is reviewed by a subject matter expert.
- Technical writer review items:
- [ ] Ensure docs metadata is present and up-to-date.
diff --git a/.gitlab/merge_request_templates/Pipeline Configuration.md b/.gitlab/merge_request_templates/Pipeline Configuration.md
index 336988d8bdf..255cb787d64 100644
--- a/.gitlab/merge_request_templates/Pipeline Configuration.md
+++ b/.gitlab/merge_request_templates/Pipeline Configuration.md
@@ -1,4 +1,4 @@
-<!-- See Pipelines for the GitLab project: https://docs.gitlab.com/ee/development/pipelines.html -->
+<!-- See Pipelines for the GitLab project: https://docs.gitlab.com/ee/development/pipelines -->
<!-- When in doubt about a Pipeline configuration change, feel free to ping @gl-quality/eng-prod. -->
## What does this MR do?
@@ -15,7 +15,7 @@
Consider the effect of the changes in this merge request on the following:
-- [ ] Different [pipeline types](https://docs.gitlab.com/ee/development/pipelines.html#pipelines-for-merge-requests)
+- [ ] Different [pipeline types](https://docs.gitlab.com/ee/development/pipelines/index.html#pipelines-types-for-merge-requests)
- Non-canonical projects:
- [ ] `gitlab-foss`
- [ ] `security`
diff --git a/.gitlab/merge_request_templates/Quarantine End to End Test.md b/.gitlab/merge_request_templates/Quarantine End to End Test.md
index c088fde857a..5f26f3ac74d 100644
--- a/.gitlab/merge_request_templates/Quarantine End to End Test.md
+++ b/.gitlab/merge_request_templates/Quarantine End to End Test.md
@@ -26,7 +26,7 @@ the noise (due to constantly failing tests, flaky tests, and so on) so that new
- [ ] Dequarantine test check-list
- [ ] Follow the [Dequarantining Tests guide](https://about.gitlab.com/handbook/engineering/quality/quality-engineering/debugging-qa-test-failures/#dequarantining-tests).
- [ ] Confirm the test consistently passes on the target GitLab environment(s).
-- [ ] To ensure a faster turnaround, ask in the `#quality` Slack channel for someone to review and merge the merge request, rather than assigning it directly.
+- [ ] To ensure a faster turnaround, ask in the `#quality_maintainers` Slack channel for someone to review and merge the merge request, rather than assigning it directly.
<!-- Base labels. -->
/label ~"Quality" ~"QA" ~"type::maintenance"
diff --git a/.gitlab/merge_request_templates/Removals.md b/.gitlab/merge_request_templates/Removals.md
index afe95f853bc..6f31f3cefd2 100644
--- a/.gitlab/merge_request_templates/Removals.md
+++ b/.gitlab/merge_request_templates/Removals.md
@@ -18,7 +18,7 @@ If there is no relevant deprecation issue, hit pause and:
Removals must be [announced as deprecations](https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations) at least 2 milestones in advance of the planned removal date.
-If the removal creates a [breaking change](https://about.gitlab.com/handbook/product/gitlab-the-product/#breaking-changes-deprecations-and-removing-features), it can only be removed in a major "XX.0" release.
+If the removal creates a [breaking change](https://about.gitlab.com/handbook/product/gitlab-the-product/#deprecations-removals-and-breaking-changes), it can only be removed in a major "XX.0" release.
**By the 10th**: Assign this MR to these team members as reviewers, and for approval:
diff --git a/.gitpod.yml b/.gitpod.yml
index 535c60b42c8..3522ea0fca2 100644
--- a/.gitpod.yml
+++ b/.gitpod.yml
@@ -1,28 +1,38 @@
+# Gitpod file reference
+# https://www.gitpod.io/docs/configure/workspaces/tasks
+
image: registry.gitlab.com/gitlab-org/gitlab-development-kit/gitpod-workspace:stable
tasks:
- name: GDK
+ # "command:" emits gitpod-start
+ before: |
+ START_UNIXTIME="$(date +%s)"
+ echo START_UNIXTIME="$(date +%s)" > /workspace/gitpod_start_time.sh
command: |
- echo START_TIME_IN_SECONDS="$(date +%s)" | tee /workspace/gitpod_start_time.sh
+ # send signal to other tasks that Gitpod started
gp sync-done gitpod-start
+ echo "Waiting for other task to copy GDK.."
gp sync-await gdk-copied && cd /workspace/gitlab-development-kit && gdk help
- - init: |
- echo "$(date) – Copying GDK" | tee -a /workspace/startup.log
- cp -r $HOME/gitlab-development-kit /workspace/
+ - name: GitLab
+ # "command:" emits gdk-copied
+ init: |
(
set -e
+ echo "$(date) – Copying GDK" | tee -a /workspace/startup.log
+ cp -r $HOME/gitlab-development-kit /workspace/
cd /workspace/gitlab-development-kit
- # Ensure GitLab directory is symlinked under the GDK
+ # ensure GitLab directory is symlinked under the GDK
ln -nfs "$GITPOD_REPO_ROOT" /workspace/gitlab-development-kit/gitlab
- mv /workspace/gitlab-development-kit/secrets.yml /workspace/gitlab-development-kit/gitlab/config
+ mv -v /workspace/gitlab-development-kit/secrets.yml /workspace/gitlab-development-kit/gitlab/config
# ensure gdk.yml has correct instance settings
- gdk config set gitlab.rails.port 443
- gdk config set gitlab.rails.https.enabled true
- gdk config set webpack.host 127.0.0.1
- gdk config set webpack.static false
- gdk config set webpack.live_reload false
+ gdk config set gitlab.rails.port 443 |& tee -a /workspace/startup.log
+ gdk config set gitlab.rails.https.enabled true |& tee -a /workspace/startup.log
+ gdk config set webpack.host 127.0.0.1 |& tee -a /workspace/startup.log
+ gdk config set webpack.static false |& tee -a /workspace/startup.log
+ gdk config set webpack.live_reload false |& tee -a /workspace/startup.log
# reconfigure GDK
echo "$(date) – Reconfiguring GDK" | tee -a /workspace/startup.log
gdk reconfigure
@@ -36,9 +46,9 @@ tasks:
)
command: |
(
- gp sync-await gitpod-start
set -e
gp sync-done gdk-copied
+ gp sync-await gitpod-start
[[ -f /workspace/gitpod_start_time.sh ]] && source /workspace/gitpod_start_time.sh
SECONDS=0
cd /workspace/gitlab-development-kit
@@ -67,15 +77,14 @@ tasks:
make gitlab-db-migrate
fi
cd /workspace/gitlab-development-kit/gitlab
- # Display which branch we're on
- git branch --show-current
- # Install Lefthook
+ echo "--- on branch: $(git branch --show-current)"
+ echo "--- installing lefthook"
bundle exec lefthook install
+ echo "--- resetting db/structure.sql"
git checkout db/structure.sql
- cd /workspace/gitlab-development-kit
- # Waiting for GitLab ...
+ echo "--- waiting for GitLab"
gp ports await 3000
- printf "Waiting for GitLab at $(gp url 3000) ..."
+ printf "Awaiting /-/readiness on $(gp url 3000) ..."
# Check /-/readiness which returns JSON, but we're only interested in the exit code
#
# We use http://localhost:3000 instead of the public hostname because
@@ -86,7 +95,7 @@ tasks:
printf "$(date) – GitLab is up (took ~%.1f minutes)\n" "$((10*$SECONDS/60))e-1" | tee -a /workspace/startup.log
gp preview $(gp url 3000) || true
PREBUILD_LOG=(/workspace/.gitpod/prebuild-log-*)
- [[ -f /workspace/gitpod_start_time.sh ]] && printf "Took %.1f minutes from https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitpod.yml being executed through to completion %s\n" "$((10*(($(date +%s)-${START_TIME_IN_SECONDS}))/60))e-1" "$([[ -f "$PREBUILD_LOG" ]] && echo "With Prebuilds")"
+ [[ -f /workspace/gitpod_start_time.sh ]] && printf "Took %.1f minutes from https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitpod.yml being executed through to completion %s\n" "$((10*(($(date +%s)-${START_UNIXTIME}))/60))e-1" "$([[ -f "$PREBUILD_LOG" ]] && echo "With Prebuilds")"
)
ports:
@@ -116,5 +125,5 @@ vscode:
- karunamurti.haml@1.4.1
- octref.vetur@0.36.0
- dbaeumer.vscode-eslint@2.2.6
- - GitLab.gitlab-workflow@3.48.1
+ - GitLab.gitlab-workflow@3.56.0
- DavidAnson.vscode-markdownlint@0.47.0
diff --git a/.haml-lint.yml b/.haml-lint.yml
index 60f86eb4158..3655ca44172 100644
--- a/.haml-lint.yml
+++ b/.haml-lint.yml
@@ -110,6 +110,7 @@ linters:
- Cop/LineBreakAfterGuardClauses
- Cop/ProjectPathHelper
- Gitlab/FeatureAvailableUsage
+ - Gitlab/Json
- GitlabSecurity/PublicSend
- Layout/EmptyLineAfterGuardClause
- Layout/LeadingCommentSpace
diff --git a/.haml-lint_todo.yml b/.haml-lint_todo.yml
index ce4f697300f..511aa29de58 100644
--- a/.haml-lint_todo.yml
+++ b/.haml-lint_todo.yml
@@ -1,19 +1,7 @@
# This configuration was generated by
# `haml-lint --auto-gen-config`
-# on 2022-09-15 12:13:31 +0000 using Haml-Lint version 0.40.1.
+# on 2022-10-19 13:09:51 +0200 using Haml-Lint version 0.40.1.
# The point is for the user to remove these configuration records
# one by one as the lints are removed from the code base.
# Note that changes in the inspected code, or installation of new
-# versions of Haml-Lint, may require this file to be generated again.
-
-linters:
-
- # Offense count: 11
- RuboCop:
- exclude:
- - "app/views/layouts/_page.html.haml"
- - "app/views/layouts/header/_default.html.haml"
- - "app/views/projects/merge_requests/dropdowns/_branch.html.haml"
- - "app/views/projects/merge_requests/dropdowns/_project.html.haml"
- - "app/views/shared/_flash_user_callout.html.haml"
- - "app/views/shared/_label.html.haml" \ No newline at end of file
+# versions of Haml-Lint, may require this file to be generated again. \ No newline at end of file
diff --git a/.rubocop.yml b/.rubocop.yml
index b84effd5b16..d0cf328e719 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -289,11 +289,6 @@ Rails/InverseOf:
Rails/UniqueValidationWithoutIndex:
Enabled: false
-Rails/HasManyOrHasOneDependent:
- Include:
- - app/models/**/*.rb
- - ee/app/models/**/*.rb
-
Rails/HelperInstanceVariable:
Include:
- app/helpers/**/*.rb
@@ -308,6 +303,26 @@ Rails/RakeEnvironment:
# Context on why it's disabled: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/93419#note_1048223982
Enabled: false
+# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/94064#note_1157289970
+Rails/SquishedSQLHeredocs:
+ Enabled: false
+
+# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96675#note_1094403693
+Rails/WhereExists:
+ Enabled: false
+
+# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/94061#note_1160343775
+Rails/SkipsModelValidations:
+ Enabled: false
+
+# See https://gitlab.com/gitlab-org/gitlab/-/issues/378105#note_1138487716
+Rails/HasManyOrHasOneDependent:
+ Enabled: false
+
+# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/94019#note_1139714728
+Rails/CreateTableWithTimestamps:
+ Enabled: false
+
# GitLab ###################################################################
Gitlab/ModuleWithInstanceVariables:
@@ -384,7 +399,13 @@ Database/MultipleDatabases:
- 'spec/lib/gitlab/background_migration/**/*.rb'
- 'spec/lib/gitlab/database/**/*.rb'
-Gitlab/DuplicateSpecLocation:
+# See https://gitlab.com/gitlab-org/gitlab/-/issues/373194
+Gitlab/RSpec/AvoidSetup:
+ Enabled: true
+ Include:
+ - 'ee/spec/features/registrations/saas/**/*'
+
+RSpec/DuplicateSpecLocation:
Enabled: true
Gitlab/PolicyRuleBoolean:
@@ -465,9 +486,17 @@ RSpec/FactoriesInMigrationSpecs:
RSpec/FactoryBot/AvoidCreate:
Enabled: true
Include:
+ - 'spec/presenters/**/*.rb'
- 'spec/serializers/**/*.rb'
+ - 'ee/spec/presenters/**/*.rb'
- 'ee/spec/serializers/**/*.rb'
+RSpec/FactoryBot/StrategyInCallback:
+ Enabled: true
+ Include:
+ - 'spec/factories/**/*.rb'
+ - 'ee/spec/factories/**/*.rb'
+
Cop/IncludeSidekiqWorker:
Enabled: true
Exclude:
@@ -582,6 +611,18 @@ Graphql/Descriptions:
- 'app/graphql/**/*'
- 'ee/app/graphql/**/*'
+Graphql/EnumNames:
+ Enabled: true
+ Include:
+ - 'app/graphql/**/*'
+ - 'ee/app/graphql/**/*'
+
+Graphql/EnumValues:
+ Enabled: true
+ Include:
+ - 'app/graphql/**/*'
+ - 'ee/app/graphql/**/*'
+
# Cops for upgrade to gitlab-styles 3.1.0
RSpec/ImplicitSubject:
Enabled: false
@@ -704,12 +745,17 @@ Migration/PreventIndexCreation:
- !ruby/regexp /\Adb\/(post_)?migrate\/2020.*\.rb\z/
- !ruby/regexp /\Adb\/(post_)?migrate\/20210[1-6].*\.rb\z/
+Migration/SchemaAdditionMethodsNoPost:
+ Enabled: true
+ Include:
+ - db/post_migrate/*.rb
+ EnforcedSince: 20221024034228
+
Gitlab/RailsLogger:
Exclude:
- 'spec/**/*.rb'
- 'ee/spec/**/*.rb'
-# WIP See https://gitlab.com/gitlab-org/gitlab/-/issues/267606
RSpec/FactoryBot/InlineAssociation:
Include:
- 'spec/factories/**/*.rb'
@@ -761,6 +807,10 @@ Style/RegexpLiteralMixedPreserve:
- mixed_preserve
EnforcedStyle: mixed_preserve
+# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/94317#note_1139610896
+Style/Lambda:
+ EnforcedStyle: literal
+
RSpec/TopLevelDescribePath:
Exclude:
- 'spec/fixtures/**/*.rb'
@@ -831,3 +881,8 @@ Cop/SidekiqApiUsage:
- 'lib/gitlab/sidekiq_queue.rb'
- 'config/initializers/sidekiq.rb'
- 'config/initializers/forbid_sidekiq_in_transactions.rb'
+
+Rake/Require:
+ Include:
+ - '{,ee/,jh/}lib/**/*.rake'
+ - 'qa/tasks/**/*.rake'
diff --git a/.rubocop_todo/api/ensure_string_detail.yml b/.rubocop_todo/api/ensure_string_detail.yml
new file mode 100644
index 00000000000..feac99aa569
--- /dev/null
+++ b/.rubocop_todo/api/ensure_string_detail.yml
@@ -0,0 +1,5 @@
+---
+API/EnsureStringDetail:
+ Details: grace period
+ Exclude:
+ - 'ee/lib/api/analytics/group_activity_analytics.rb'
diff --git a/.rubocop_todo/gitlab/json.yml b/.rubocop_todo/gitlab/json.yml
new file mode 100644
index 00000000000..190778a3de7
--- /dev/null
+++ b/.rubocop_todo/gitlab/json.yml
@@ -0,0 +1,465 @@
+---
+# Cop supports --autocorrect.
+Gitlab/Json:
+ Exclude:
+ - 'app/controllers/admin/application_settings_controller.rb'
+ - 'app/controllers/concerns/authenticates_with_two_factor.rb'
+ - 'app/controllers/projects/commit_controller.rb'
+ - 'app/controllers/projects/google_cloud/configuration_controller.rb'
+ - 'app/controllers/projects/google_cloud/databases_controller.rb'
+ - 'app/controllers/projects/google_cloud/deployments_controller.rb'
+ - 'app/controllers/projects/google_cloud/gcp_regions_controller.rb'
+ - 'app/controllers/projects/google_cloud/service_accounts_controller.rb'
+ - 'app/controllers/projects/graphs_controller.rb'
+ - 'app/controllers/projects/merge_requests_controller.rb'
+ - 'app/controllers/projects/notes_controller.rb'
+ - 'app/controllers/projects/settings/ci_cd_controller.rb'
+ - 'app/controllers/projects/templates_controller.rb'
+ - 'app/controllers/projects_controller.rb'
+ - 'app/controllers/search_controller.rb'
+ - 'app/helpers/access_tokens_helper.rb'
+ - 'app/helpers/application_settings_helper.rb'
+ - 'app/helpers/breadcrumbs_helper.rb'
+ - 'app/helpers/ci/builds_helper.rb'
+ - 'app/helpers/ci/pipelines_helper.rb'
+ - 'app/helpers/compare_helper.rb'
+ - 'app/helpers/emails_helper.rb'
+ - 'app/helpers/environment_helper.rb'
+ - 'app/helpers/groups_helper.rb'
+ - 'app/helpers/ide_helper.rb'
+ - 'app/helpers/integrations_helper.rb'
+ - 'app/helpers/invite_members_helper.rb'
+ - 'app/helpers/issuables_description_templates_helper.rb'
+ - 'app/helpers/issuables_helper.rb'
+ - 'app/helpers/jira_connect_helper.rb'
+ - 'app/helpers/learn_gitlab_helper.rb'
+ - 'app/helpers/namespaces_helper.rb'
+ - 'app/helpers/notes_helper.rb'
+ - 'app/helpers/operations_helper.rb'
+ - 'app/helpers/packages_helper.rb'
+ - 'app/helpers/projects/project_members_helper.rb'
+ - 'app/helpers/projects_helper.rb'
+ - 'app/helpers/search_helper.rb'
+ - 'app/helpers/terms_helper.rb'
+ - 'app/helpers/users_helper.rb'
+ - 'app/mailers/emails/members.rb'
+ - 'app/presenters/packages/composer/packages_presenter.rb'
+ - 'app/presenters/projects/security/configuration_presenter.rb'
+ - 'app/workers/google_cloud/create_cloudsql_instance_worker.rb'
+ - 'config/initializers/rack_multipart_patch.rb'
+ - 'ee/app/controllers/admin/geo/nodes_controller.rb'
+ - 'ee/app/controllers/ee/admin/application_settings_controller.rb'
+ - 'ee/app/controllers/ee/search_controller.rb'
+ - 'ee/app/controllers/subscriptions_controller.rb'
+ - 'ee/app/graphql/types/json_string_type.rb'
+ - 'ee/app/helpers/billing_plans_helper.rb'
+ - 'ee/app/helpers/ee/environments_helper.rb'
+ - 'ee/app/helpers/ee/geo_helper.rb'
+ - 'ee/app/helpers/ee/groups/analytics/cycle_analytics_helper.rb'
+ - 'ee/app/helpers/ee/invite_members_helper.rb'
+ - 'ee/app/helpers/ee/operations_helper.rb'
+ - 'ee/app/helpers/ee/projects/pipeline_helper.rb'
+ - 'ee/app/helpers/ee/projects_helper.rb'
+ - 'ee/app/helpers/ee/security_orchestration_helper.rb'
+ - 'ee/app/helpers/groups/ldap_sync_helper.rb'
+ - 'ee/app/helpers/groups/security_features_helper.rb'
+ - 'ee/app/helpers/incident_management/oncall_schedule_helper.rb'
+ - 'ee/app/helpers/projects/on_demand_scans_helper.rb'
+ - 'ee/app/helpers/projects/security/dast_profiles_helper.rb'
+ - 'ee/app/helpers/security_helper.rb'
+ - 'ee/app/helpers/subscriptions_helper.rb'
+ - 'ee/app/helpers/users/identity_verification_helper.rb'
+ - 'ee/app/helpers/vulnerabilities_helper.rb'
+ - 'ee/app/models/product_analytics/jitsu_authentication.rb'
+ - 'ee/app/presenters/epic_presenter.rb'
+ - 'ee/app/services/arkose/blocked_users_report_service.rb'
+ - 'ee/app/services/elastic/indexing_control_service.rb'
+ - 'ee/app/services/elastic/process_bookkeeping_service.rb'
+ - 'ee/app/services/security/token_revocation_service.rb'
+ - 'ee/app/services/status_page/publish_base_service.rb'
+ - 'ee/app/services/upcoming_reconciliations/update_service.rb'
+ - 'ee/app/services/vulnerabilities/create_service_base.rb'
+ - 'ee/app/workers/concerns/elastic/migration_state.rb'
+ - 'ee/app/workers/sync_seat_link_request_worker.rb'
+ - 'ee/db/fixtures/development/20_vulnerabilities.rb'
+ - 'ee/lib/api/analytics/product_analytics.rb'
+ - 'ee/lib/ee/gitlab/background_migration/update_vulnerability_occurrences_location.rb'
+ - 'ee/lib/gitlab/elastic/indexer.rb'
+ - 'ee/lib/gitlab/geo/signed_data.rb'
+ - 'ee/lib/gitlab/subscription_portal/clients/graphql.rb'
+ - 'ee/lib/gitlab/subscription_portal/clients/rest.rb'
+ - 'ee/lib/slack/api.rb'
+ - 'ee/lib/tasks/gitlab/elastic.rake'
+ - 'ee/lib/tasks/gitlab/spdx.rake'
+ - 'ee/spec/controllers/admin/application_settings_controller_spec.rb'
+ - 'ee/spec/controllers/countries_controller_spec.rb'
+ - 'ee/spec/controllers/country_states_controller_spec.rb'
+ - 'ee/spec/controllers/ee/search_controller_spec.rb'
+ - 'ee/spec/controllers/groups/analytics/cycle_analytics_controller_spec.rb'
+ - 'ee/spec/controllers/groups/security/policies_controller_spec.rb'
+ - 'ee/spec/controllers/projects/integrations/jira/issues_controller_spec.rb'
+ - 'ee/spec/controllers/subscriptions_controller_spec.rb'
+ - 'ee/spec/factories/vulnerabilities/findings.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/billings/qrtly_reconciliation_alert_spec.rb'
+ - 'ee/spec/features/projects/integrations/jira_issues_list_spec.rb'
+ - 'ee/spec/features/projects/integrations/user_activates_github_spec.rb'
+ - 'ee/spec/features/projects/integrations/user_activates_jira_spec.rb'
+ - 'ee/spec/frontend/fixtures/dast_profiles.rb'
+ - 'ee/spec/frontend/fixtures/epic.rb'
+ - 'ee/spec/graphql/api/vulnerabilities_spec.rb'
+ - 'ee/spec/graphql/types/json_string_type_spec.rb'
+ - 'ee/spec/helpers/ee/groups/group_members_helper_spec.rb'
+ - 'ee/spec/helpers/ee/projects/pipeline_helper_spec.rb'
+ - 'ee/spec/helpers/ee/security_orchestration_helper_spec.rb'
+ - 'ee/spec/helpers/incident_management/oncall_schedule_helper_spec.rb'
+ - 'ee/spec/helpers/projects/on_demand_scans_helper_spec.rb'
+ - 'ee/spec/helpers/projects/security/dast_profiles_helper_spec.rb'
+ - 'ee/spec/helpers/users/identity_verification_helper_spec.rb'
+ - 'ee/spec/lib/ee/gitlab/background_migration/drop_invalid_remediations_spec.rb'
+ - 'ee/spec/lib/ee/gitlab/background_migration/update_vulnerability_occurrences_location_spec.rb'
+ - 'ee/spec/lib/gitlab/analytics/cycle_analytics/request_params_spec.rb'
+ - 'ee/spec/lib/gitlab/ci/parsers/license_compliance/license_scanning_spec.rb'
+ - 'ee/spec/lib/gitlab/ci/parsers/security/dast_spec.rb'
+ - 'ee/spec/lib/gitlab/ci/parsers/security/dependency_scanning_spec.rb'
+ - 'ee/spec/lib/gitlab/elastic/bulk_indexer_spec.rb'
+ - 'ee/spec/lib/gitlab/elastic/indexer_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/replication/blob_downloader_spec.rb'
+ - 'ee/spec/lib/gitlab/tracking/standard_context_spec.rb'
+ - 'ee/spec/lib/slack/api_spec.rb'
+ - 'ee/spec/migrations/update_vulnerability_occurrences_location_spec.rb'
+ - 'ee/spec/models/ee/integrations/jira_spec.rb'
+ - 'ee/spec/models/gitlab/seat_link_data_spec.rb'
+ - 'ee/spec/models/group_member_spec.rb'
+ - 'ee/spec/models/integrations/github/status_notifier_spec.rb'
+ - 'ee/spec/models/integrations/github_spec.rb'
+ - 'ee/spec/models/license_spec.rb'
+ - 'ee/spec/models/product_analytics/jitsu_authentication_spec.rb'
+ - 'ee/spec/models/vulnerabilities/finding_spec.rb'
+ - 'ee/spec/presenters/audit_event_presenter_spec.rb'
+ - 'ee/spec/requests/api/analytics/product_analytics_spec.rb'
+ - 'ee/spec/requests/api/experiments_spec.rb'
+ - 'ee/spec/requests/api/geo_spec.rb'
+ - 'ee/spec/requests/api/graphql/mutations/alert_management/http_integration/create_spec.rb'
+ - 'ee/spec/requests/api/graphql/mutations/alert_management/http_integration/update_spec.rb'
+ - 'ee/spec/requests/api/graphql/mutations/vulnerabilities/create_external_issue_link_spec.rb'
+ - 'ee/spec/requests/api/graphql/project/alert_management/http_integrations_spec.rb'
+ - 'ee/spec/requests/api/graphql/vulnerabilities/external_issue_links_spec.rb'
+ - 'ee/spec/requests/api/graphql/vulnerabilities/location_spec.rb'
+ - 'ee/spec/requests/api/integrations/slack/events_spec.rb'
+ - 'ee/spec/requests/api/releases_spec.rb'
+ - 'ee/spec/requests/api/settings_spec.rb'
+ - 'ee/spec/requests/git_http_geo_spec.rb'
+ - 'ee/spec/requests/projects/on_demand_scans_controller_spec.rb'
+ - 'ee/spec/requests/projects/security/policies_controller_spec.rb'
+ - 'ee/spec/requests/users/identity_verification_controller_spec.rb'
+ - 'ee/spec/serializers/clusters/environment_entity_spec.rb'
+ - 'ee/spec/serializers/clusters/environment_serializer_spec.rb'
+ - 'ee/spec/serializers/dependency_list_serializer_spec.rb'
+ - 'ee/spec/serializers/epics/related_epic_entity_spec.rb'
+ - 'ee/spec/serializers/evidences/evidence_entity_spec.rb'
+ - 'ee/spec/serializers/issue_serializer_spec.rb'
+ - 'ee/spec/serializers/licenses_list_serializer_spec.rb'
+ - 'ee/spec/serializers/member_entity_spec.rb'
+ - 'ee/spec/serializers/member_user_entity_spec.rb'
+ - 'ee/spec/serializers/status_page/incident_entity_spec.rb'
+ - 'ee/spec/serializers/status_page/incident_serializer_spec.rb'
+ - 'ee/spec/serializers/test_reports_comparer_serializer_spec.rb'
+ - 'ee/spec/services/arkose/blocked_users_report_service_spec.rb'
+ - 'ee/spec/services/arkose/token_verification_service_spec.rb'
+ - 'ee/spec/services/gitlab_subscriptions/fetch_subscription_plans_service_spec.rb'
+ - 'ee/spec/services/integrations/slack_events/app_home_opened_service_spec.rb'
+ - 'ee/spec/services/jira/requests/issues/list_service_spec.rb'
+ - 'ee/spec/services/projects/slack_application_install_service_spec.rb'
+ - 'ee/spec/services/security/token_revocation_service_spec.rb'
+ - 'ee/spec/support/helpers/subscription_portal_helpers.rb'
+ - 'ee/spec/support/shared_examples/controllers/cluster_metrics_shared_examples.rb'
+ - 'ee/spec/support/shared_examples/requests/api/project_approval_rules_api_shared_examples.rb'
+ - 'ee/spec/support/shared_examples/status_page/publish_shared_examples.rb'
+ - 'ee/spec/tasks/gitlab/spdx_rake_spec.rb'
+ - 'ee/spec/workers/audit_events/audit_event_streaming_worker_spec.rb'
+ - 'ee/spec/workers/scan_security_report_secrets_worker_spec.rb'
+ - 'ee/spec/workers/sync_seat_link_request_worker_spec.rb'
+ - 'ee/spec/workers/vulnerability_exports/export_worker_spec.rb'
+ - 'lib/api/api.rb'
+ - 'lib/api/feature_flags_user_lists.rb'
+ - 'lib/api/helpers.rb'
+ - 'lib/api/terraform/state.rb'
+ - 'lib/atlassian/jira_connect/client.rb'
+ - 'lib/atlassian/jira_connect/serializers/base_entity.rb'
+ - 'lib/backup/gitaly_backup.rb'
+ - 'lib/bitbucket_server/client.rb'
+ - 'lib/bulk_imports/clients/graphql.rb'
+ - 'lib/error_tracking/sentry_client.rb'
+ - 'lib/gitlab/alert_management/payload/prometheus.rb'
+ - 'lib/gitlab/analytics/cycle_analytics/request_params.rb'
+ - 'lib/gitlab/auth/otp/strategies/forti_authenticator/manual_otp.rb'
+ - 'lib/gitlab/auth/otp/strategies/forti_authenticator/push_otp.rb'
+ - 'lib/gitlab/auth/otp/strategies/forti_token_cloud.rb'
+ - 'lib/gitlab/background_migration/fix_vulnerability_occurrences_with_hashes_as_raw_metadata.rb'
+ - 'lib/gitlab/bitbucket_import/importer.rb'
+ - 'lib/gitlab/bitbucket_server_import/importer.rb'
+ - 'lib/gitlab/chat/responder/mattermost.rb'
+ - 'lib/gitlab/chat/responder/slack.rb'
+ - 'lib/gitlab/chat_name_token.rb'
+ - 'lib/gitlab/ci/ansi2html.rb'
+ - 'lib/gitlab/ci/ansi2json/state.rb'
+ - 'lib/gitlab/ci/build/releaser.rb'
+ - 'lib/gitlab/ci/config/external/mapper.rb'
+ - 'lib/gitlab/ci/pipeline/chain/validate/external.rb'
+ - 'lib/gitlab/ci/reports/security/finding.rb'
+ - 'lib/gitlab/composer/cache.rb'
+ - 'lib/gitlab/database/background_migration/batched_migration.rb'
+ - 'lib/gitlab/database/background_migration_job.rb'
+ - 'lib/gitlab/database/migration_helpers.rb'
+ - 'lib/gitlab/database/migrations/batched_background_migration_helpers.rb'
+ - 'lib/gitlab/database/migrations/instrumentation.rb'
+ - 'lib/gitlab/database/migrations/runner.rb'
+ - 'lib/gitlab/database/postgres_hll/buckets.rb'
+ - 'lib/gitlab/database/reindexing/grafana_notifier.rb'
+ - 'lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base.rb'
+ - 'lib/gitlab/diff/highlight_cache.rb'
+ - 'lib/gitlab/discussions_diff/highlight_cache.rb'
+ - 'lib/gitlab/external_authorization/client.rb'
+ - 'lib/gitlab/file_hook.rb'
+ - 'lib/gitlab/gitaly_client/conflicts_service.rb'
+ - 'lib/gitlab/graphql/pagination/active_record_array_connection.rb'
+ - 'lib/gitlab/graphql/pagination/keyset/connection.rb'
+ - 'lib/gitlab/health_checks/middleware.rb'
+ - 'lib/gitlab/import_export/after_export_strategies/base_after_export_strategy.rb'
+ - 'lib/gitlab/import_export/json/legacy_writer.rb'
+ - 'lib/gitlab/import_export/json/ndjson_writer.rb'
+ - 'lib/gitlab/import_export/lfs_saver.rb'
+ - 'lib/gitlab/jira/http_client.rb'
+ - 'lib/gitlab/json_cache.rb'
+ - 'lib/gitlab/legacy_github_import/importer.rb'
+ - 'lib/gitlab/lfs/client.rb'
+ - 'lib/gitlab/merge_requests/mergeability/redis_interface.rb'
+ - 'lib/gitlab/middleware/read_only/controller.rb'
+ - 'lib/gitlab/patch/hangouts_chat_http_override.rb'
+ - 'lib/gitlab/puma_logging/json_formatter.rb'
+ - 'lib/gitlab/sidekiq_config.rb'
+ - 'lib/gitlab/sidekiq_daemon/monitor.rb'
+ - 'lib/gitlab/sidekiq_logging/json_formatter.rb'
+ - 'lib/gitlab/usage/metrics/aggregates/sources/postgres_hll.rb'
+ - 'lib/gitlab/utils/json_size_estimator.rb'
+ - 'lib/gitlab/version_info.rb'
+ - 'lib/gitlab/workhorse.rb'
+ - 'lib/mattermost/command.rb'
+ - 'lib/mattermost/team.rb'
+ - 'lib/microsoft_teams/notifier.rb'
+ - 'lib/tasks/gitlab/background_migrations.rake'
+ - 'lib/version_check.rb'
+ - 'spec/commands/diagnostic_reports/uploader_smoke_spec.rb'
+ - 'spec/controllers/admin/integrations_controller_spec.rb'
+ - 'spec/controllers/concerns/product_analytics_tracking_spec.rb'
+ - 'spec/controllers/groups/settings/integrations_controller_spec.rb'
+ - 'spec/controllers/jira_connect/subscriptions_controller_spec.rb'
+ - 'spec/controllers/profiles/personal_access_tokens_controller_spec.rb'
+ - 'spec/controllers/projects/alerting/notifications_controller_spec.rb'
+ - 'spec/controllers/projects/jobs_controller_spec.rb'
+ - 'spec/controllers/projects/merge_requests/drafts_controller_spec.rb'
+ - 'spec/factories/ci/pipeline_artifacts.rb'
+ - 'spec/features/dashboard/issues_spec.rb'
+ - 'spec/features/error_tracking/user_filters_errors_by_status_spec.rb'
+ - 'spec/features/file_uploads/graphql_add_design_spec.rb'
+ - 'spec/features/groups/dependency_proxy_for_containers_spec.rb'
+ - 'spec/features/markdown/copy_as_gfm_spec.rb'
+ - 'spec/features/markdown/metrics_spec.rb'
+ - 'spec/features/projects/integrations/user_activates_jira_spec.rb'
+ - 'spec/features/projects/settings/monitor_settings_spec.rb'
+ - 'spec/frontend/fixtures/timezones.rb'
+ - 'spec/helpers/access_tokens_helper_spec.rb'
+ - 'spec/helpers/breadcrumbs_helper_spec.rb'
+ - 'spec/helpers/ci/builds_helper_spec.rb'
+ - 'spec/helpers/environment_helper_spec.rb'
+ - 'spec/helpers/environments_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/invite_members_helper_spec.rb'
+ - 'spec/helpers/issuables_description_templates_helper_spec.rb'
+ - 'spec/helpers/listbox_helper_spec.rb'
+ - 'spec/helpers/namespaces_helper_spec.rb'
+ - 'spec/helpers/projects/project_members_helper_spec.rb'
+ - 'spec/helpers/projects_helper_spec.rb'
+ - 'spec/initializers/hangouts_chat_http_override_spec.rb'
+ - 'spec/lib/api/entities/merge_request_basic_spec.rb'
+ - 'spec/lib/api/helpers/caching_spec.rb'
+ - 'spec/lib/api/helpers/common_helpers_spec.rb'
+ - 'spec/lib/atlassian/jira_connect/client_spec.rb'
+ - 'spec/lib/atlassian/jira_connect/serializers/build_entity_spec.rb'
+ - 'spec/lib/atlassian/jira_connect/serializers/deployment_entity_spec.rb'
+ - 'spec/lib/atlassian/jira_connect/serializers/feature_flag_entity_spec.rb'
+ - 'spec/lib/atlassian/jira_connect/serializers/repository_entity_spec.rb'
+ - 'spec/lib/bitbucket_server/connection_spec.rb'
+ - 'spec/lib/bulk_imports/common/pipelines/lfs_objects_pipeline_spec.rb'
+ - 'spec/lib/bulk_imports/projects/pipelines/snippets_pipeline_spec.rb'
+ - 'spec/lib/container_registry/client_spec.rb'
+ - 'spec/lib/container_registry/gitlab_api_client_spec.rb'
+ - 'spec/lib/gitlab/background_migration/encrypt_integration_properties_spec.rb'
+ - 'spec/lib/gitlab/bitbucket_import/importer_spec.rb'
+ - 'spec/lib/gitlab/chat/responder/mattermost_spec.rb'
+ - 'spec/lib/gitlab/chat/responder/slack_spec.rb'
+ - 'spec/lib/gitlab/ci/build/releaser_spec.rb'
+ - 'spec/lib/gitlab/ci/parsers/accessibility/pa11y_spec.rb'
+ - 'spec/lib/gitlab/ci/parsers/codequality/code_climate_spec.rb'
+ - 'spec/lib/gitlab/ci/parsers/coverage/sax_document_spec.rb'
+ - 'spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb'
+ - 'spec/lib/gitlab/ci/parsers/security/common_spec.rb'
+ - 'spec/lib/gitlab/ci/parsers/test/junit_spec.rb'
+ - 'spec/lib/gitlab/ci/runner_upgrade_check_spec.rb'
+ - 'spec/lib/gitlab/composer/cache_spec.rb'
+ - 'spec/lib/gitlab/composer/version_index_spec.rb'
+ - 'spec/lib/gitlab/data_builder/pipeline_spec.rb'
+ - 'spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb'
+ - 'spec/lib/gitlab/database/postgres_hll/buckets_spec.rb'
+ - 'spec/lib/gitlab/database/reindexing/grafana_notifier_spec.rb'
+ - 'spec/lib/gitlab/diff/position_spec.rb'
+ - 'spec/lib/gitlab/diff/stats_cache_spec.rb'
+ - 'spec/lib/gitlab/discussions_diff/highlight_cache_spec.rb'
+ - 'spec/lib/gitlab/error_tracking/context_payload_generator_spec.rb'
+ - 'spec/lib/gitlab/error_tracking/processor/sidekiq_processor_spec.rb'
+ - 'spec/lib/gitlab/external_authorization/client_spec.rb'
+ - 'spec/lib/gitlab/external_authorization/response_spec.rb'
+ - 'spec/lib/gitlab/file_hook_spec.rb'
+ - 'spec/lib/gitlab/git/rugged_impl/use_rugged_spec.rb'
+ - 'spec/lib/gitlab/github_import/client_spec.rb'
+ - 'spec/lib/gitlab/gitlab_import/importer_spec.rb'
+ - 'spec/lib/gitlab/grape_logging/loggers/exception_logger_spec.rb'
+ - 'spec/lib/gitlab/harbor/client_spec.rb'
+ - 'spec/lib/gitlab/import_export/after_export_strategies/base_after_export_strategy_spec.rb'
+ - 'spec/lib/gitlab/import_export/json/streaming_serializer_spec.rb'
+ - 'spec/lib/gitlab/json_cache_spec.rb'
+ - 'spec/lib/gitlab/legacy_github_import/client_spec.rb'
+ - 'spec/lib/gitlab/legacy_github_import/importer_spec.rb'
+ - 'spec/lib/gitlab/lfs/client_spec.rb'
+ - 'spec/lib/gitlab/merge_requests/mergeability/redis_interface_spec.rb'
+ - 'spec/lib/gitlab/middleware/multipart_spec.rb'
+ - 'spec/lib/gitlab/sidekiq_migrate_jobs_spec.rb'
+ - 'spec/lib/gitlab/tracking/service_ping_context_spec.rb'
+ - 'spec/lib/gitlab/tracking/standard_context_spec.rb'
+ - 'spec/lib/gitlab/tracking_spec.rb'
+ - 'spec/lib/gitlab/usage/service_ping/legacy_metric_timing_decorator_spec.rb'
+ - 'spec/lib/gitlab/utils/json_size_estimator_spec.rb'
+ - 'spec/lib/gitlab/version_info_spec.rb'
+ - 'spec/lib/gitlab/webpack/manifest_spec.rb'
+ - 'spec/lib/gitlab/workhorse_spec.rb'
+ - 'spec/lib/gitlab/zentao/client_spec.rb'
+ - 'spec/lib/grafana/client_spec.rb'
+ - 'spec/lib/json_web_token/hmac_token_spec.rb'
+ - 'spec/lib/mattermost/command_spec.rb'
+ - 'spec/lib/mattermost/team_spec.rb'
+ - 'spec/lib/microsoft_teams/notifier_spec.rb'
+ - 'spec/lib/object_storage/direct_upload_spec.rb'
+ - 'spec/lib/service_ping/devops_report_spec.rb'
+ - 'spec/lib/version_check_spec.rb'
+ - 'spec/mailers/notify_spec.rb'
+ - 'spec/migrations/20220204194347_encrypt_integration_properties_spec.rb'
+ - 'spec/migrations/20220412143552_consume_remaining_encrypt_integration_property_jobs_spec.rb'
+ - 'spec/models/blob_viewer/package_json_spec.rb'
+ - 'spec/models/ci/runner_spec.rb'
+ - 'spec/models/concerns/prometheus_adapter_spec.rb'
+ - 'spec/models/concerns/redis_cacheable_spec.rb'
+ - 'spec/models/concerns/sensitive_serializable_hash_spec.rb'
+ - 'spec/models/diff_discussion_spec.rb'
+ - 'spec/models/diff_note_spec.rb'
+ - 'spec/models/hooks/web_hook_spec.rb'
+ - 'spec/models/integrations/datadog_spec.rb'
+ - 'spec/models/integrations/jira_spec.rb'
+ - 'spec/models/integrations/mattermost_slash_commands_spec.rb'
+ - 'spec/models/integrations/mock_ci_spec.rb'
+ - 'spec/models/merge_request_diff_commit_spec.rb'
+ - 'spec/models/packages/composer/metadatum_spec.rb'
+ - 'spec/models/terraform/state_spec.rb'
+ - 'spec/presenters/packages/composer/packages_presenter_spec.rb'
+ - 'spec/requests/api/ci/runner/jobs_request_post_spec.rb'
+ - 'spec/requests/api/composer_packages_spec.rb'
+ - 'spec/requests/api/conan_instance_packages_spec.rb'
+ - 'spec/requests/api/conan_project_packages_spec.rb'
+ - 'spec/requests/api/container_registry_event_spec.rb'
+ - 'spec/requests/api/graphql/mutations/design_management/upload_spec.rb'
+ - 'spec/requests/api/integrations/jira_connect/subscriptions_spec.rb'
+ - 'spec/requests/api/internal/base_spec.rb'
+ - 'spec/requests/api/merge_requests_spec.rb'
+ - 'spec/requests/api/namespaces_spec.rb'
+ - 'spec/requests/api/project_snapshots_spec.rb'
+ - 'spec/requests/groups/settings/access_tokens_controller_spec.rb'
+ - 'spec/requests/projects/incident_management/pagerduty_incidents_spec.rb'
+ - 'spec/requests/projects/settings/access_tokens_controller_spec.rb'
+ - 'spec/requests/users_controller_spec.rb'
+ - 'spec/requests/whats_new_controller_spec.rb'
+ - 'spec/scripts/pipeline_test_report_builder_spec.rb'
+ - 'spec/serializers/ci/dag_job_entity_spec.rb'
+ - 'spec/serializers/ci/dag_job_group_entity_spec.rb'
+ - 'spec/serializers/ci/dag_pipeline_entity_spec.rb'
+ - 'spec/serializers/ci/dag_pipeline_serializer_spec.rb'
+ - 'spec/serializers/ci/dag_stage_entity_spec.rb'
+ - 'spec/serializers/ci/daily_build_group_report_result_serializer_spec.rb'
+ - 'spec/serializers/ci/lint/result_serializer_spec.rb'
+ - 'spec/serializers/ci/trigger_entity_spec.rb'
+ - 'spec/serializers/ci/trigger_serializer_spec.rb'
+ - 'spec/serializers/diff_line_serializer_spec.rb'
+ - 'spec/serializers/evidences/evidence_entity_spec.rb'
+ - 'spec/serializers/feature_flags_client_serializer_spec.rb'
+ - 'spec/serializers/group_link/group_group_link_entity_spec.rb'
+ - 'spec/serializers/group_link/group_group_link_serializer_spec.rb'
+ - 'spec/serializers/group_link/group_link_entity_spec.rb'
+ - 'spec/serializers/group_link/project_group_link_entity_spec.rb'
+ - 'spec/serializers/group_link/project_group_link_serializer_spec.rb'
+ - 'spec/serializers/member_entity_spec.rb'
+ - 'spec/serializers/member_serializer_spec.rb'
+ - 'spec/serializers/member_user_entity_spec.rb'
+ - 'spec/serializers/test_reports_comparer_serializer_spec.rb'
+ - 'spec/services/ci/runners/process_runner_version_update_service_spec.rb'
+ - 'spec/services/draft_notes/create_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/list_issues_service_spec.rb'
+ - 'spec/services/git/branch_push_service_spec.rb'
+ - 'spec/services/jira/requests/projects/list_service_spec.rb'
+ - 'spec/services/metrics/dashboard/transient_embed_service_spec.rb'
+ - 'spec/services/packages/composer/create_package_service_spec.rb'
+ - 'spec/services/packages/rubygems/metadata_extraction_service_spec.rb'
+ - 'spec/services/projects/container_repository/third_party/cleanup_tags_service_spec.rb'
+ - 'spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb'
+ - 'spec/services/service_ping/submit_service_ping_service_spec.rb'
+ - 'spec/services/webauthn/authenticate_service_spec.rb'
+ - 'spec/services/webauthn/register_service_spec.rb'
+ - 'spec/support/frontend_fixtures.rb'
+ - 'spec/support/google_api/cloud_platform_helpers.rb'
+ - 'spec/support/helpers/ci_artifact_metadata_generator.rb'
+ - 'spec/support/helpers/dependency_proxy_helpers.rb'
+ - 'spec/support/helpers/fake_webauthn_device.rb'
+ - 'spec/support/helpers/features/two_factor_helpers.rb'
+ - 'spec/support/helpers/graphql_helpers.rb'
+ - 'spec/support/helpers/input_helper.rb'
+ - 'spec/support/helpers/jira_integration_helpers.rb'
+ - 'spec/support/helpers/kubernetes_helpers.rb'
+ - 'spec/support/helpers/prometheus_helpers.rb'
+ - 'spec/support/helpers/sentry_client_helpers.rb'
+ - 'spec/support/helpers/usage_data_helpers.rb'
+ - 'spec/support/import_export/configuration_helper.rb'
+ - 'spec/support/shared_contexts/bulk_imports_requests_shared_context.rb'
+ - 'spec/support/shared_contexts/features/error_tracking_shared_context.rb'
+ - 'spec/support/shared_contexts/prometheus/alert_shared_context.rb'
+ - 'spec/support/shared_contexts/services/projects/container_repository/delete_tags_service_shared_context.rb'
+ - 'spec/support/shared_examples/blocks_unsafe_serialization_shared_examples.rb'
+ - 'spec/support/shared_examples/controllers/rate_limited_endpoint_shared_examples.rb'
+ - 'spec/support/shared_examples/controllers/snowplow_event_tracking_examples.rb'
+ - 'spec/support/shared_examples/harbor/artifacts_controller_shared_examples.rb'
+ - 'spec/support/shared_examples/harbor/repositories_controller_shared_examples.rb'
+ - 'spec/support/shared_examples/harbor/tags_controller_shared_examples.rb'
+ - 'spec/support/shared_examples/models/diff_positionable_note_shared_examples.rb'
+ - 'spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb'
+ - 'spec/support/shared_examples/requests/rack_attack_shared_examples.rb'
+ - 'spec/support_specs/helpers/graphql_helpers_spec.rb'
+ - 'spec/tasks/gitlab/update_templates_rake_spec.rb'
+ - 'spec/tasks/gitlab/usage_data_rake_spec.rb'
+ - 'spec/tooling/lib/tooling/kubernetes_client_spec.rb'
+ - 'spec/tooling/rspec_flaky/listener_spec.rb'
+ - 'spec/workers/ci/runners/process_runner_version_update_worker_spec.rb'
+ - 'spec/workers/gitlab/jira_import/stage/import_labels_worker_spec.rb'
+ - 'spec/workers/packages/composer/cache_update_worker_spec.rb'
diff --git a/.rubocop_todo/gitlab/namespaced_class.yml b/.rubocop_todo/gitlab/namespaced_class.yml
index 230ef959153..3fb2df623e0 100644
--- a/.rubocop_todo/gitlab/namespaced_class.yml
+++ b/.rubocop_todo/gitlab/namespaced_class.yml
@@ -1283,7 +1283,6 @@ Gitlab/NamespacedClass:
- 'spec/models/concerns/batch_destroy_dependent_associations_spec.rb'
- 'spec/models/concerns/bulk_insertable_associations_spec.rb'
- 'spec/models/concerns/triggerable_hooks_spec.rb'
- - 'spec/support/helpers/bare_repo_operations.rb'
- 'spec/support/helpers/ci_artifact_metadata_generator.rb'
- 'spec/support/helpers/fake_migration_classes.rb'
- 'spec/support/helpers/fake_u2f_device.rb'
diff --git a/.rubocop_todo/gitlab/no_code_coverage_comment.yml b/.rubocop_todo/gitlab/no_code_coverage_comment.yml
index 0dcee5f32ee..195dfe5a81d 100644
--- a/.rubocop_todo/gitlab/no_code_coverage_comment.yml
+++ b/.rubocop_todo/gitlab/no_code_coverage_comment.yml
@@ -1,6 +1,5 @@
---
Gitlab/NoCodeCoverageComment:
- Details: grace period
Exclude:
- 'app/models/integration.rb'
- 'app/services/ci/job_artifacts/destroy_batch_service.rb'
diff --git a/.rubocop_todo/gitlab/service_response.yml b/.rubocop_todo/gitlab/service_response.yml
index ccf934e09b3..03b73d6491d 100644
--- a/.rubocop_todo/gitlab/service_response.yml
+++ b/.rubocop_todo/gitlab/service_response.yml
@@ -1,6 +1,5 @@
---
Gitlab/ServiceResponse:
- Details: grace period
Exclude:
- 'app/services/alert_management/metric_images/upload_service.rb'
- 'app/services/analytics/cycle_analytics/stages/base_service.rb'
diff --git a/.rubocop_todo/graphql/enum_names.yml b/.rubocop_todo/graphql/enum_names.yml
new file mode 100644
index 00000000000..18f485b6759
--- /dev/null
+++ b/.rubocop_todo/graphql/enum_names.yml
@@ -0,0 +1,37 @@
+---
+Graphql/EnumNames:
+ Details: grace period
+ Exclude:
+ - 'app/graphql/types/access_level_enum.rb'
+ - 'app/graphql/types/availability_enum.rb'
+ - 'app/graphql/types/ci/pipeline_config_source_enum.rb'
+ - 'app/graphql/types/ci/pipeline_scope_enum.rb'
+ - 'app/graphql/types/ci/pipeline_status_enum.rb'
+ - 'app/graphql/types/container_expiration_policy_cadence_enum.rb'
+ - 'app/graphql/types/container_expiration_policy_keep_enum.rb'
+ - 'app/graphql/types/container_expiration_policy_older_than_enum.rb'
+ - 'app/graphql/types/data_visualization_palette/color_enum.rb'
+ - 'app/graphql/types/data_visualization_palette/weight_enum.rb'
+ - 'app/graphql/types/merge_strategy_enum.rb'
+ - 'app/graphql/types/milestone_state_enum.rb'
+ - 'app/graphql/types/packages/cleanup/keep_duplicated_package_files_enum.rb'
+ - 'app/graphql/types/packages/conan/metadatum_file_type_enum.rb'
+ - 'app/graphql/types/packages/package_type_enum.rb'
+ - 'app/graphql/types/security/report_type_enum.rb'
+ - 'app/graphql/types/snippets/blob_action_enum.rb'
+ - 'app/graphql/types/snippets/type_enum.rb'
+ - 'app/graphql/types/snippets/visibility_scopes_enum.rb'
+ - 'app/graphql/types/sort_direction_enum.rb'
+ - 'app/graphql/types/todo_action_enum.rb'
+ - 'app/graphql/types/todo_state_enum.rb'
+ - 'app/graphql/types/todo_target_enum.rb'
+ - 'app/graphql/types/user_callout_feature_name_enum.rb'
+ - 'app/graphql/types/visibility_levels_enum.rb'
+ - 'ee/app/graphql/types/dast_scan_type_enum.rb'
+ - 'ee/app/graphql/types/dast_site_profile_validation_status_enum.rb'
+ - 'ee/app/graphql/types/dast_site_validation_status_enum.rb'
+ - 'ee/app/graphql/types/dast_site_validation_strategy_enum.rb'
+ - 'ee/app/graphql/types/dast_target_type_enum.rb'
+ - 'ee/app/graphql/types/geo/replication_state_enum.rb'
+ - 'ee/app/graphql/types/geo/verification_state_enum.rb'
+ - 'ee/app/graphql/types/incident_management/oncall_rotation_length_unit_enum.rb'
diff --git a/.rubocop_todo/graphql/enum_values.yml b/.rubocop_todo/graphql/enum_values.yml
new file mode 100644
index 00000000000..3984c54a9f2
--- /dev/null
+++ b/.rubocop_todo/graphql/enum_values.yml
@@ -0,0 +1,37 @@
+---
+Graphql/EnumValues:
+ Details: grace period
+ Exclude:
+ - 'app/graphql/types/alert_management/domain_filter_enum.rb'
+ - 'app/graphql/types/blob_viewers/type_enum.rb'
+ - 'app/graphql/types/ci/config/include_type_enum.rb'
+ - 'app/graphql/types/ci/test_case_status_enum.rb'
+ - 'app/graphql/types/container_expiration_policy_cadence_enum.rb'
+ - 'app/graphql/types/container_expiration_policy_keep_enum.rb'
+ - 'app/graphql/types/container_expiration_policy_older_than_enum.rb'
+ - 'app/graphql/types/customer_relations/contact_state_enum.rb'
+ - 'app/graphql/types/customer_relations/organization_state_enum.rb'
+ - 'app/graphql/types/design_management/design_version_event_enum.rb'
+ - 'app/graphql/types/issuable_state_enum.rb'
+ - 'app/graphql/types/merge_request_state_enum.rb'
+ - 'app/graphql/types/milestone_state_enum.rb'
+ - 'app/graphql/types/notes/position_type_enum.rb'
+ - 'app/graphql/types/packages/cleanup/keep_duplicated_package_files_enum.rb'
+ - 'app/graphql/types/snippets/blob_action_enum.rb'
+ - 'app/graphql/types/snippets/type_enum.rb'
+ - 'app/graphql/types/snippets/visibility_scopes_enum.rb'
+ - 'app/graphql/types/todo_action_enum.rb'
+ - 'app/graphql/types/todo_state_enum.rb'
+ - 'app/graphql/types/tree/type_enum.rb'
+ - 'app/graphql/types/user_state_enum.rb'
+ - 'app/graphql/types/visibility_levels_enum.rb'
+ - 'ee/app/graphql/ee/types/list_limit_metric_enum.rb'
+ - 'ee/app/graphql/types/epic_state_enum.rb'
+ - 'ee/app/graphql/types/health_status_enum.rb'
+ - 'ee/app/graphql/types/incident_management/issuable_resource_link_type_enum.rb'
+ - 'ee/app/graphql/types/iteration_state_enum.rb'
+ - 'ee/app/graphql/types/move_type_enum.rb'
+ - 'ee/app/graphql/types/network_policy_kind_enum.rb'
+ - 'ee/app/graphql/types/security_scanner_type_enum.rb'
+ - 'ee/app/graphql/types/vulnerability_report_type_enum.rb'
+ - 'ee/app/graphql/types/vulnerability_sort_enum.rb'
diff --git a/.rubocop_todo/layout/argument_alignment.yml b/.rubocop_todo/layout/argument_alignment.yml
index 195f3fee98e..4b5fb5ad1a6 100644
--- a/.rubocop_todo/layout/argument_alignment.yml
+++ b/.rubocop_todo/layout/argument_alignment.yml
@@ -655,7 +655,6 @@ Layout/ArgumentAlignment:
- 'spec/features/merge_request/user_sees_versions_spec.rb'
- 'spec/features/merge_requests/user_lists_merge_requests_spec.rb'
- 'spec/features/merge_requests/user_views_open_merge_requests_spec.rb'
- - 'spec/features/projects/branches_spec.rb'
- 'spec/features/projects/commit/mini_pipeline_graph_spec.rb'
- 'spec/features/projects/environments/environment_spec.rb'
- 'spec/features/projects/environments/environments_spec.rb'
diff --git a/.rubocop_todo/layout/first_array_element_indentation.yml b/.rubocop_todo/layout/first_array_element_indentation.yml
index cbe806fc16f..d4a3d2f5524 100644
--- a/.rubocop_todo/layout/first_array_element_indentation.yml
+++ b/.rubocop_todo/layout/first_array_element_indentation.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
Layout/FirstArrayElementIndentation:
- Details: grace period
Exclude:
- 'spec/lib/gitlab/github_import/importer/issues_importer_spec.rb'
- 'spec/lib/gitlab/search/found_blob_spec.rb'
diff --git a/.rubocop_todo/layout/line_length.yml b/.rubocop_todo/layout/line_length.yml
index fe9c0593f7d..b5fc199c0ca 100644
--- a/.rubocop_todo/layout/line_length.yml
+++ b/.rubocop_todo/layout/line_length.yml
@@ -371,7 +371,6 @@ Layout/LineLength:
- 'app/models/diff_note.rb'
- 'app/models/environment.rb'
- 'app/models/error_tracking/project_error_tracking_setting.rb'
- - 'app/models/event_collection.rb'
- 'app/models/exported_protected_branch.rb'
- 'app/models/group.rb'
- 'app/models/incident_management/project_incident_management_setting.rb'
@@ -597,7 +596,6 @@ Layout/LineLength:
- 'app/services/loose_foreign_keys/cleaner_service.rb'
- 'app/services/members/destroy_service.rb'
- 'app/services/members/invitation_reminder_email_service.rb'
- - 'app/services/members/update_service.rb'
- 'app/services/merge_requests/add_context_service.rb'
- 'app/services/merge_requests/assign_issues_service.rb'
- 'app/services/merge_requests/base_service.rb'
@@ -1817,7 +1815,6 @@ Layout/LineLength:
- 'ee/spec/features/groups/scim_token_spec.rb'
- 'ee/spec/features/groups/security/compliance_dashboards_spec.rb'
- 'ee/spec/features/groups/sso_spec.rb'
- - 'ee/spec/features/groups/usage_quotas_spec.rb'
- 'ee/spec/features/integrations/jira/jira_issues_list_spec.rb'
- 'ee/spec/features/invites_spec.rb'
- 'ee/spec/features/issues/filtered_search/filter_issues_weight_spec.rb'
@@ -1915,7 +1912,7 @@ Layout/LineLength:
- 'ee/spec/frontend/fixtures/projects.rb'
- 'ee/spec/graphql/ee/mutations/boards/lists/create_spec.rb'
- 'ee/spec/graphql/ee/resolvers/board_list_issues_resolver_spec.rb'
- - 'ee/spec/graphql/ee/resolvers/issues_resolver_spec.rb'
+ - 'ee/spec/graphql/ee/resolvers/project_issues_resolver_spec.rb'
- 'ee/spec/graphql/ee/types/board_type_spec.rb'
- 'ee/spec/graphql/ee/types/issue_sort_enum_spec.rb'
- 'ee/spec/graphql/ee/types/merge_request_type_spec.rb'
@@ -2855,7 +2852,6 @@ Layout/LineLength:
- 'ee/spec/views/registrations/welcome/show.html.haml_spec.rb'
- 'ee/spec/views/shared/_mirror_status.html.haml_spec.rb'
- 'ee/spec/views/shared/_namespace_user_cap_reached_alert.html.haml_spec.rb'
- - 'ee/spec/views/shared/access_tokens/_table.html.haml_spec.rb'
- 'ee/spec/views/shared/billings/_eoa_bronze_plan_banner.html.haml_spec.rb'
- 'ee/spec/views/shared/billings/_trial_status.html.haml_spec.rb'
- 'ee/spec/views/shared/credentials_inventory/personal_access_tokens/_personal_access_token.html.haml_spec.rb'
@@ -2910,7 +2906,6 @@ Layout/LineLength:
- 'ee/spec/workers/update_all_mirrors_worker_spec.rb'
- 'ee/spec/workers/vulnerability_exports/export_deletion_worker_spec.rb'
- 'lib/api/admin/instance_clusters.rb'
- - 'lib/api/admin/plan_limits.rb'
- 'lib/api/api.rb'
- 'lib/api/appearance.rb'
- 'lib/api/award_emoji.rb'
@@ -2946,19 +2941,15 @@ Layout/LineLength:
- 'lib/api/entities/issue_basic.rb'
- 'lib/api/entities/merge_request.rb'
- 'lib/api/entities/namespace.rb'
- - 'lib/api/entities/package.rb'
- 'lib/api/entities/project.rb'
- 'lib/api/entities/user.rb'
- 'lib/api/environments.rb'
- - 'lib/api/error_tracking/project_settings.rb'
- 'lib/api/feature_flags.rb'
- 'lib/api/files.rb'
- 'lib/api/generic_packages.rb'
- - 'lib/api/go_proxy.rb'
- 'lib/api/group_clusters.rb'
- 'lib/api/group_import.rb'
- 'lib/api/group_labels.rb'
- - 'lib/api/group_packages.rb'
- 'lib/api/group_variables.rb'
- 'lib/api/groups.rb'
- 'lib/api/helm_packages.rb'
@@ -2992,7 +2983,6 @@ Layout/LineLength:
- 'lib/api/members.rb'
- 'lib/api/merge_request_diffs.rb'
- 'lib/api/merge_requests.rb'
- - 'lib/api/metrics/dashboard/annotations.rb'
- 'lib/api/metrics/user_starred_dashboards.rb'
- 'lib/api/milestone_responses.rb'
- 'lib/api/namespaces.rb'
@@ -3921,7 +3911,6 @@ Layout/LineLength:
- 'spec/features/groups/settings/repository_spec.rb'
- 'spec/features/groups_spec.rb'
- 'spec/features/ide/static_object_external_storage_csp_spec.rb'
- - 'spec/features/incidents/user_views_incident_spec.rb'
- 'spec/features/invites_spec.rb'
- 'spec/features/issuables/issuable_list_spec.rb'
- 'spec/features/issuables/markdown_references/internal_references_spec.rb'
@@ -4012,7 +4001,6 @@ Layout/LineLength:
- 'spec/features/projects/blobs/shortcuts_blob_spec.rb'
- 'spec/features/projects/blobs/user_follows_pipeline_suggest_nudge_spec.rb'
- 'spec/features/projects/blobs/user_views_pipeline_editor_button_spec.rb'
- - 'spec/features/projects/branches_spec.rb'
- 'spec/features/projects/ci/editor_spec.rb'
- 'spec/features/projects/commit/cherry_pick_spec.rb'
- 'spec/features/projects/commit/user_reverts_commit_spec.rb'
@@ -4185,11 +4173,11 @@ Layout/LineLength:
- 'spec/graphql/resolvers/group_issues_resolver_spec.rb'
- 'spec/graphql/resolvers/group_labels_resolver_spec.rb'
- 'spec/graphql/resolvers/issue_status_counts_resolver_spec.rb'
- - 'spec/graphql/resolvers/issues_resolver_spec.rb'
- 'spec/graphql/resolvers/merge_requests_resolver_spec.rb'
- 'spec/graphql/resolvers/metrics/dashboard_resolver_spec.rb'
- 'spec/graphql/resolvers/metrics/dashboards/annotation_resolver_spec.rb'
- 'spec/graphql/resolvers/namespace_projects_resolver_spec.rb'
+ - 'spec/graphql/resolvers/project_issues_resolver_spec.rb'
- 'spec/graphql/resolvers/project_jobs_resolver_spec.rb'
- 'spec/graphql/resolvers/project_resolver_spec.rb'
- 'spec/graphql/resolvers/projects/jira_projects_resolver_spec.rb'
@@ -5543,7 +5531,6 @@ Layout/LineLength:
- 'spec/services/members/destroy_service_spec.rb'
- 'spec/services/members/invitation_reminder_email_service_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/after_create_service_spec.rb'
- 'spec/services/merge_requests/assign_issues_service_spec.rb'
@@ -5968,7 +5955,6 @@ Layout/LineLength:
- 'spec/views/projects/tags/index.html.haml_spec.rb'
- 'spec/views/projects/tree/show.html.haml_spec.rb'
- 'spec/views/search/_results.html.haml_spec.rb'
- - 'spec/views/shared/access_tokens/_table.html.haml_spec.rb'
- 'spec/views/shared/milestones/_issuable.html.haml_spec.rb'
- 'spec/views/shared/projects/_project.html.haml_spec.rb'
- 'spec/views/shared/snippets/_snippet.html.haml_spec.rb'
diff --git a/.rubocop_todo/layout/space_in_lambda_literal.yml b/.rubocop_todo/layout/space_in_lambda_literal.yml
index 9359939514b..f025680c209 100644
--- a/.rubocop_todo/layout/space_in_lambda_literal.yml
+++ b/.rubocop_todo/layout/space_in_lambda_literal.yml
@@ -69,7 +69,6 @@ Layout/SpaceInLambdaLiteral:
- 'app/models/diff_note.rb'
- 'app/models/environment.rb'
- 'app/models/error_tracking/error.rb'
- - 'app/models/event_collection.rb'
- 'app/models/external_pull_request.rb'
- 'app/models/group.rb'
- 'app/models/integration.rb'
diff --git a/.rubocop_todo/layout/space_inside_parens.yml b/.rubocop_todo/layout/space_inside_parens.yml
index 805a9791409..e6238992619 100644
--- a/.rubocop_todo/layout/space_inside_parens.yml
+++ b/.rubocop_todo/layout/space_inside_parens.yml
@@ -1,103 +1,20 @@
---
-# Cop supports --auto-correct.
+# Cop supports --autocorrect.
Layout/SpaceInsideParens:
# Offense count: 701
# Temporarily disabled due to too many offenses
Enabled: false
Exclude:
- - 'app/controllers/projects/environments_controller.rb'
- - 'app/controllers/projects/pipeline_schedules_controller.rb'
- - 'app/graphql/mutations/ci/job/base.rb'
- - 'app/helpers/icons_helper.rb'
- - 'app/helpers/projects_helper.rb'
- - 'app/helpers/reminder_emails_helper.rb'
- - 'app/models/alert_management/alert.rb'
- - 'app/models/ci/build_metadata.rb'
- - 'app/models/concerns/milestoneable.rb'
- - 'app/models/concerns/mirror_authentication.rb'
- - 'app/models/concerns/protected_ref_access.rb'
- - 'app/models/cycle_analytics/project_level_stage_adapter.rb'
- - 'app/models/merge_request.rb'
- - 'app/models/pages_domain.rb'
- - 'app/models/project.rb'
- - 'app/services/ci/archive_trace_service.rb'
- - 'app/services/jira_import/start_import_service.rb'
- - 'app/services/labels/transfer_service.rb'
- - 'app/services/packages/debian/create_distribution_service.rb'
- - 'app/services/packages/debian/update_distribution_service.rb'
- - 'app/services/packages/npm/create_package_service.rb'
- - 'app/services/personal_access_tokens/revoke_service.rb'
- - 'app/services/snippets/create_service.rb'
- - 'app/services/spam/spam_verdict_service.rb'
- 'config/initializers/wikicloth_redos_patch.rb'
- 'db/post_migrate/20210722042939_update_issuable_slas_where_issue_closed.rb'
- - 'ee/app/graphql/resolvers/external_issue_resolver.rb'
- - 'ee/app/helpers/billing_plans_helper.rb'
- - 'ee/app/helpers/ee/boards_helper.rb'
- - 'ee/app/models/ee/lfs_object.rb'
- - 'ee/app/models/ee/merge_request_diff.rb'
- - 'ee/app/models/ee/pages_deployment.rb'
- - 'ee/app/models/ee/upload.rb'
- - 'ee/app/models/requirements_management/requirement.rb'
- - 'ee/app/models/resource_iteration_event.rb'
- - 'ee/app/services/compliance_management/frameworks/create_service.rb'
- - 'ee/app/services/compliance_management/frameworks/destroy_service.rb'
- - 'ee/app/services/compliance_management/frameworks/update_service.rb'
- - 'ee/app/services/elastic/cluster_reindexing_service.rb'
- - 'ee/app/services/sitemap/create_service.rb'
- 'ee/lib/ee/gitlab/auth/ldap/access.rb'
- 'ee/lib/gitlab/auth/smartcard/session.rb'
- - 'ee/spec/controllers/admin/licenses_controller_spec.rb'
- - 'ee/spec/controllers/ee/groups_controller_spec.rb'
- - 'ee/spec/controllers/groups/analytics/productivity_analytics_controller_spec.rb'
- - 'ee/spec/controllers/projects/issues_controller_spec.rb'
- - 'ee/spec/controllers/projects/merge_requests/creations_controller_spec.rb'
- - 'ee/spec/controllers/projects/merge_requests_controller_spec.rb'
- - 'ee/spec/controllers/projects/security/vulnerabilities_controller_spec.rb'
- - 'ee/spec/controllers/projects/settings/operations_controller_spec.rb'
- - 'ee/spec/features/account_recovery_regular_check_spec.rb'
- - 'ee/spec/features/billings/billing_plans_spec.rb'
- - 'ee/spec/features/boards/board_filters_spec.rb'
- - 'ee/spec/features/boards/group_boards/board_deletion_spec.rb'
- - 'ee/spec/features/boards/user_visits_board_spec.rb'
- - 'ee/spec/features/groups/analytics/ci_cd_analytics_spec.rb'
- - 'ee/spec/features/groups/issues_spec.rb'
- - 'ee/spec/features/groups/iteration_spec.rb'
- - 'ee/spec/features/groups/iterations/user_creates_iteration_in_cadence_spec.rb'
- - 'ee/spec/features/groups/iterations/user_edits_iteration_cadence_spec.rb'
- - 'ee/spec/features/groups/iterations/user_edits_iteration_spec.rb'
- - 'ee/spec/features/merge_request/user_edits_multiple_reviewers_mr_spec.rb'
- - 'ee/spec/features/merge_requests/user_resets_approvers_spec.rb'
- - 'ee/spec/features/merge_requests/user_views_all_merge_requests_spec.rb'
- - 'ee/spec/features/merge_trains/two_merge_requests_on_train_spec.rb'
- 'ee/spec/finders/ee/alert_management/http_integrations_finder_spec.rb'
- 'ee/spec/finders/epics_finder_spec.rb'
- 'ee/spec/finders/security/pipeline_vulnerabilities_finder_spec.rb'
- 'ee/spec/frontend/fixtures/analytics/devops_reports/devops_adoption/enabled_namespaces.rb'
- 'ee/spec/frontend/fixtures/epic.rb'
- 'ee/spec/frontend/fixtures/projects.rb'
- - 'ee/spec/graphql/ee/resolvers/board_lists_resolver_spec.rb'
- - 'ee/spec/graphql/mutations/app_sec/fuzzing/coverage/corpus/create_spec.rb'
- - 'ee/spec/graphql/mutations/dast/profiles/create_spec.rb'
- - 'ee/spec/graphql/resolvers/epics_resolver_spec.rb'
- - 'ee/spec/lib/ee/gitlab/background_migration/drop_invalid_remediations_spec.rb'
- - 'ee/spec/lib/ee/gitlab/usage_data_spec.rb'
- - 'ee/spec/lib/gitlab/auth/group_saml/auth_hash_spec.rb'
- - 'ee/spec/lib/gitlab/auth/group_saml/dynamic_settings_spec.rb'
- - 'ee/spec/lib/gitlab/auth/group_saml/group_lookup_spec.rb'
- - 'ee/spec/lib/gitlab/auth/otp/session_enforcer_spec.rb'
- - 'ee/spec/lib/gitlab/auth/smartcard/ldap_certificate_spec.rb'
- - 'ee/spec/lib/gitlab/ci/templates/coverage_fuzzing_gitlab_ci_yaml_spec.rb'
- - 'ee/spec/lib/gitlab/ci/templates/dast_api_gitlab_ci_yaml_spec.rb'
- - 'ee/spec/lib/gitlab/ci/templates/dast_api_latest_gitlab_ci_yaml_spec.rb'
- - 'ee/spec/lib/gitlab/ci/templates/dast_gitlab_ci_yaml_spec.rb'
- - 'ee/spec/lib/gitlab/ci/templates/dast_latest_gitlab_ci_yaml_spec.rb'
- - 'ee/spec/lib/gitlab/ci/templates/dast_runner_validation_gitlab_ci_yaml_spec.rb'
- - 'ee/spec/lib/gitlab/ci/templates/secure_binaries_ci_yaml_spec.rb'
- - 'ee/spec/lib/gitlab/geo/git_ssh_proxy_spec.rb'
- - 'ee/spec/lib/gitlab/geo/log_cursor/events/event_spec.rb'
- - 'ee/spec/lib/gitlab/graphql/aggregations/epics/lazy_epic_aggregate_spec.rb'
- - 'ee/spec/lib/gitlab/status_page/storage/s3_client_spec.rb'
- 'ee/spec/mailers/notify_spec.rb'
- 'ee/spec/migrations/add_non_null_constraint_for_escalation_rule_on_pending_alert_escalations_spec.rb'
- 'ee/spec/migrations/drop_invalid_remediations_spec.rb'
@@ -171,70 +88,11 @@ Layout/SpaceInsideParens:
- 'qa/qa/tools/delete_subgroups.rb'
- 'qa/spec/runtime/feature_spec.rb'
- 'qa/spec/scenario/template_spec.rb'
- - 'spec/controllers/boards/issues_controller_spec.rb'
- - 'spec/controllers/groups/children_controller_spec.rb'
- - 'spec/controllers/groups/registry/repositories_controller_spec.rb'
- - 'spec/controllers/groups/releases_controller_spec.rb'
- - 'spec/controllers/groups/runners_controller_spec.rb'
- - 'spec/controllers/groups_controller_spec.rb'
- - 'spec/controllers/omniauth_callbacks_controller_spec.rb'
- - 'spec/controllers/projects/environments_controller_spec.rb'
- - 'spec/controllers/projects/issues_controller_spec.rb'
- - 'spec/controllers/projects/registry/repositories_controller_spec.rb'
- - 'spec/controllers/projects/runners_controller_spec.rb'
- 'spec/dependencies/omniauth_saml_spec.rb'
- 'spec/factories/usage_data.rb'
- - 'spec/features/boards/board_filters_spec.rb'
- - 'spec/features/boards/user_visits_board_spec.rb'
- - 'spec/features/dashboard/datetime_on_tooltips_spec.rb'
- - 'spec/features/graphql_known_operations_spec.rb'
- - 'spec/features/groups/activity_spec.rb'
- - 'spec/features/groups/board_sidebar_spec.rb'
- - 'spec/features/groups/empty_states_spec.rb'
- - 'spec/features/groups/issues_spec.rb'
- - 'spec/features/groups/milestone_spec.rb'
- - 'spec/features/groups/milestones_sorting_spec.rb'
- - 'spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb'
- - 'spec/features/merge_request/user_edits_assignees_sidebar_spec.rb'
- - 'spec/features/profiles/two_factor_auths_spec.rb'
- - 'spec/features/projects/branches/user_views_branches_spec.rb'
- - 'spec/features/projects/fork_spec.rb'
- - 'spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb'
- - 'spec/features/projects/jobs_spec.rb'
- - 'spec/features/projects/pipeline_schedules_spec.rb'
- - 'spec/features/projects/releases/user_views_edit_release_spec.rb'
- - 'spec/features/projects/releases/user_views_releases_spec.rb'
- 'spec/finders/alert_management/http_integrations_finder_spec.rb'
- 'spec/finders/events_finder_spec.rb'
- 'spec/finders/labels_finder_spec.rb'
- - 'spec/frontend/fixtures/api_merge_requests.rb'
- - 'spec/frontend/fixtures/api_projects.rb'
- - 'spec/frontend/fixtures/application_settings.rb'
- - 'spec/frontend/fixtures/blob.rb'
- - 'spec/frontend/fixtures/branches.rb'
- - 'spec/frontend/fixtures/clusters.rb'
- - 'spec/frontend/fixtures/deploy_keys.rb'
- - 'spec/frontend/fixtures/issues.rb'
- - 'spec/frontend/fixtures/jobs.rb'
- - 'spec/frontend/fixtures/labels.rb'
- - 'spec/frontend/fixtures/merge_requests.rb'
- - 'spec/frontend/fixtures/merge_requests_diffs.rb'
- - 'spec/frontend/fixtures/metrics_dashboard.rb'
- - 'spec/frontend/fixtures/pipeline_schedules.rb'
- - 'spec/frontend/fixtures/pipelines.rb'
- - 'spec/frontend/fixtures/projects.rb'
- - 'spec/frontend/fixtures/raw.rb'
- - 'spec/frontend/fixtures/snippet.rb'
- - 'spec/frontend/fixtures/todos.rb'
- - 'spec/graphql/mutations/todos/restore_many_spec.rb'
- - 'spec/graphql/resolvers/board_list_issues_resolver_spec.rb'
- - 'spec/graphql/resolvers/board_lists_resolver_spec.rb'
- - 'spec/graphql/resolvers/board_resolver_spec.rb'
- - 'spec/graphql/resolvers/boards_resolver_spec.rb'
- - 'spec/graphql/resolvers/group_packages_resolver_spec.rb'
- - 'spec/graphql/resolvers/projects_resolver_spec.rb'
- - 'spec/graphql/resolvers/recent_boards_resolver_spec.rb'
- - 'spec/graphql/resolvers/users_resolver_spec.rb'
- 'spec/helpers/badges_helper_spec.rb'
- 'spec/helpers/ci/builds_helper_spec.rb'
- 'spec/helpers/ci/runners_helper_spec.rb'
@@ -323,55 +181,9 @@ Layout/SpaceInsideParens:
- 'spec/migrations/20211130165043_backfill_sequence_column_for_sprints_table_spec.rb'
- 'spec/migrations/backfill_issues_upvotes_count_spec.rb'
- 'spec/migrations/schedule_copy_ci_builds_columns_to_security_scans2_spec.rb'
- - 'spec/models/ci/build_spec.rb'
- - 'spec/models/ci/build_trace_spec.rb'
- - 'spec/models/ci/pipeline_spec.rb'
- - 'spec/models/ci/trigger_request_spec.rb'
- - 'spec/models/clusters/applications/prometheus_spec.rb'
- - 'spec/models/deploy_token_spec.rb'
- - 'spec/models/environment_spec.rb'
- - 'spec/models/environment_status_spec.rb'
- - 'spec/models/experiment_spec.rb'
- - 'spec/models/exported_protected_branch_spec.rb'
- - 'spec/models/group_spec.rb'
- - 'spec/models/integrations/jira_spec.rb'
- - 'spec/models/member_spec.rb'
- - 'spec/models/metrics/dashboard/annotation_spec.rb'
- - 'spec/models/namespace_setting_spec.rb'
- - 'spec/models/namespace_spec.rb'
- - 'spec/models/network/graph_spec.rb'
- - 'spec/models/packages/package_spec.rb'
- - 'spec/models/project_spec.rb'
- - 'spec/models/repository_spec.rb'
- - 'spec/models/users/calloutable_spec.rb'
- 'spec/policies/clusters/agent_policy_spec.rb'
- 'spec/presenters/ci/build_presenter_spec.rb'
- 'spec/presenters/packages/conan/package_presenter_spec.rb'
- - 'spec/requests/api/boards_spec.rb'
- - 'spec/requests/api/ci/runner/jobs_artifacts_spec.rb'
- - 'spec/requests/api/ci/runner/jobs_request_post_spec.rb'
- - 'spec/requests/api/ci/runners_reset_registration_token_spec.rb'
- - 'spec/requests/api/ci/runners_spec.rb'
- - 'spec/requests/api/dependency_proxy_spec.rb'
- - 'spec/requests/api/deployments_spec.rb'
- - 'spec/requests/api/files_spec.rb'
- - 'spec/requests/api/go_proxy_spec.rb'
- - 'spec/requests/api/graphql/boards/board_list_issues_query_spec.rb'
- - 'spec/requests/api/graphql/ci/jobs_spec.rb'
- - 'spec/requests/api/graphql/ci/pipelines_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/ci/runners_registration_token/reset_spec.rb'
- - 'spec/requests/api/group_boards_spec.rb'
- - 'spec/requests/api/issues/issues_spec.rb'
- - 'spec/requests/api/issues/post_projects_issues_spec.rb'
- - 'spec/requests/api/labels_spec.rb'
- - 'spec/requests/api/merge_requests_spec.rb'
- - 'spec/requests/api/pages/pages_spec.rb'
- - 'spec/requests/api/project_milestones_spec.rb'
- - 'spec/requests/api/project_snippets_spec.rb'
- - 'spec/requests/api/snippets_spec.rb'
- - 'spec/requests/api/submodules_spec.rb'
- 'spec/requests/jwt_controller_spec.rb'
- 'spec/requests/projects/merge_requests/diffs_spec.rb'
- 'spec/requests/projects/merge_requests_spec.rb'
@@ -379,28 +191,6 @@ Layout/SpaceInsideParens:
- 'spec/requests/search_controller_spec.rb'
- 'spec/serializers/analytics_build_entity_spec.rb'
- 'spec/serializers/merge_request_user_entity_spec.rb'
- - 'spec/services/boards/issues/list_service_spec.rb'
- - 'spec/services/ci/compare_test_reports_service_spec.rb'
- - 'spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb'
- - 'spec/services/ci/retry_job_service_spec.rb'
- - 'spec/services/clusters/gcp/provision_service_spec.rb'
- - 'spec/services/clusters/gcp/verify_provision_status_service_spec.rb'
- - 'spec/services/groups/destroy_service_spec.rb'
- - 'spec/services/groups/update_shared_runners_service_spec.rb'
- - 'spec/services/import/gitlab_projects/file_acquisition_strategies/file_upload_spec.rb'
- - 'spec/services/issues/export_csv_service_spec.rb'
- - 'spec/services/labels/promote_service_spec.rb'
- - 'spec/services/members/invite_service_spec.rb'
- - 'spec/services/notes/update_service_spec.rb'
- - 'spec/services/packages/composer/composer_json_service_spec.rb'
- - 'spec/services/packages/npm/create_package_service_spec.rb'
- - 'spec/services/projects/lfs_pointers/lfs_download_service_spec.rb'
- - 'spec/services/search/group_service_spec.rb'
- - 'spec/services/security/merge_reports_service_spec.rb'
- - 'spec/services/suggestions/apply_service_spec.rb'
- - 'spec/services/system_notes/issuables_service_spec.rb'
- - 'spec/services/users/destroy_service_spec.rb'
- - 'spec/services/x509_certificate_revoke_service_spec.rb'
- 'spec/support/helpers/database/partitioning_helpers.rb'
- 'spec/support/helpers/dependency_proxy_helpers.rb'
- 'spec/support/helpers/javascript_fixtures_helpers.rb'
diff --git a/.rubocop_todo/layout/trailing_whitespace.yml b/.rubocop_todo/layout/trailing_whitespace.yml
index d9c88c989e0..8e3e0795c03 100644
--- a/.rubocop_todo/layout/trailing_whitespace.yml
+++ b/.rubocop_todo/layout/trailing_whitespace.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
Layout/TrailingWhitespace:
- Details: grace period
Exclude:
- 'app/models/concerns/analytics/cycle_analytics/stage_event_model.rb'
- 'db/migrate/20210611100359_rebuild_index_for_cadence_iterations_automation.rb'
diff --git a/.rubocop_todo/lint/missing_cop_enable_directive.yml b/.rubocop_todo/lint/missing_cop_enable_directive.yml
index 87ac47deaf5..5e1421c0f3e 100644
--- a/.rubocop_todo/lint/missing_cop_enable_directive.yml
+++ b/.rubocop_todo/lint/missing_cop_enable_directive.yml
@@ -3,8 +3,6 @@ Lint/MissingCopEnableDirective:
Exclude:
- 'app/controllers/admin/users_controller.rb'
- 'app/controllers/projects/forks_controller.rb'
- - 'app/graphql/resolvers/group_issues_resolver.rb'
- - 'app/graphql/resolvers/issues_resolver.rb'
- 'app/graphql/resolvers/project_members_resolver.rb'
- 'app/graphql/resolvers/project_milestones_resolver.rb'
- 'app/graphql/resolvers/projects/snippets_resolver.rb'
diff --git a/.rubocop_todo/performance/method_object_as_block.yml b/.rubocop_todo/performance/method_object_as_block.yml
index 1bc82ff05ec..acb1e2d621b 100644
--- a/.rubocop_todo/performance/method_object_as_block.yml
+++ b/.rubocop_todo/performance/method_object_as_block.yml
@@ -29,7 +29,6 @@ Performance/MethodObjectAsBlock:
- 'ee/app/services/security/findings/cleanup_service.rb'
- 'ee/app/services/security/ingestion/ingest_reports_service.rb'
- 'ee/app/services/security/ingestion/tasks/ingest_vulnerability_statistics.rb'
- - 'ee/app/services/security/store_findings_metadata_service.rb'
- 'ee/app/services/security/store_grouped_scans_service.rb'
- 'ee/lib/ee/container_registry/client.rb'
- 'ee/lib/ee/gitlab/ci/config_ee.rb'
diff --git a/.rubocop_todo/rails/active_record_callbacks_order.yml b/.rubocop_todo/rails/active_record_callbacks_order.yml
index 11ffff36e8d..baeba86c4b9 100644
--- a/.rubocop_todo/rails/active_record_callbacks_order.yml
+++ b/.rubocop_todo/rails/active_record_callbacks_order.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
Rails/ActiveRecordCallbacksOrder:
- Details: grace period
Exclude:
- 'app/models/award_emoji.rb'
- 'app/models/gpg_key.rb'
diff --git a/.rubocop_todo/rails/content_tag.yml b/.rubocop_todo/rails/content_tag.yml
index 33f6dd36008..d54bd97cc08 100644
--- a/.rubocop_todo/rails/content_tag.yml
+++ b/.rubocop_todo/rails/content_tag.yml
@@ -1,63 +1,9 @@
---
-# Cop supports --auto-correct.
+# Cop supports --autocorrect.
Rails/ContentTag:
- # Offense count: 163
- # Temporarily disabled due to too many offenses
- Enabled: false
+ Details: grace period
Exclude:
- - 'app/controllers/concerns/wiki_actions.rb'
- - 'app/helpers/appearances_helper.rb'
- - 'app/helpers/application_helper.rb'
- 'app/helpers/avatars_helper.rb'
- - 'app/helpers/blob_helper.rb'
- - 'app/helpers/breadcrumbs_helper.rb'
- - 'app/helpers/button_helper.rb'
- - 'app/helpers/ci/pipelines_helper.rb'
- - 'app/helpers/ci/runners_helper.rb'
- - 'app/helpers/ci/status_helper.rb'
- - 'app/helpers/clusters_helper.rb'
- - 'app/helpers/commits_helper.rb'
- - 'app/helpers/diff_helper.rb'
- - 'app/helpers/dropdowns_helper.rb'
- - 'app/helpers/emails_helper.rb'
- - 'app/helpers/environment_helper.rb'
- - 'app/helpers/events_helper.rb'
- - 'app/helpers/groups_helper.rb'
- - 'app/helpers/hooks_helper.rb'
- - 'app/helpers/icons_helper.rb'
- - 'app/helpers/issuables_helper.rb'
- - 'app/helpers/issues_helper.rb'
- - 'app/helpers/labels_helper.rb'
- - 'app/helpers/listbox_helper.rb'
- - 'app/helpers/markup_helper.rb'
- - 'app/helpers/notes_helper.rb'
- - 'app/helpers/projects_helper.rb'
- - 'app/helpers/repository_languages_helper.rb'
- - 'app/helpers/search_helper.rb'
- - 'app/helpers/tab_helper.rb'
- - 'app/helpers/timeboxes_helper.rb'
- - 'app/helpers/todos_helper.rb'
- - 'app/helpers/users_helper.rb'
- - 'app/helpers/version_check_helper.rb'
- - 'app/helpers/wiki_helper.rb'
- - 'app/presenters/ci/pipeline_presenter.rb'
- - 'app/presenters/merge_request_presenter.rb'
- - 'app/presenters/project_presenter.rb'
- - 'app/serializers/analytics/cycle_analytics/stage_entity.rb'
- - 'app/serializers/entity_date_helper.rb'
- - 'app/services/system_notes/base_service.rb'
- - 'app/services/system_notes/commit_service.rb'
- - 'ee/app/helpers/ee/button_helper.rb'
- - 'ee/app/helpers/ee/geo_helper.rb'
- - 'ee/app/helpers/ee/groups_helper.rb'
- - 'ee/app/helpers/ee/issuables_helper.rb'
- - 'ee/app/helpers/ee/lock_helper.rb'
- - 'ee/app/helpers/ee/namespaces_helper.rb'
- - 'ee/app/helpers/ee/search_helper.rb'
- - 'ee/lib/gitlab/expiring_subscription_message.rb'
- - 'lib/banzai/filter/autolink_filter.rb'
- - 'lib/banzai/filter/gollum_tags_filter.rb'
- - 'lib/gitlab/emoji.rb'
- - 'lib/gitlab/form_builders/gitlab_ui_form_builder.rb'
+ - 'app/helpers/page_layout_helper.rb'
- 'lib/gitlab/middleware/go.rb'
- - 'spec/frontend/fixtures/tabs.rb'
+ - 'spec/helpers/avatars_helper_spec.rb'
diff --git a/.rubocop_todo/rails/create_table_with_timestamps.yml b/.rubocop_todo/rails/create_table_with_timestamps.yml
deleted file mode 100644
index 6e60fa3e1d5..00000000000
--- a/.rubocop_todo/rails/create_table_with_timestamps.yml
+++ /dev/null
@@ -1,69 +0,0 @@
----
-Rails/CreateTableWithTimestamps:
- # Offense count: 63
- # Temporarily disabled due to too many offenses
- Enabled: false
- Exclude:
- - 'db/migrate/20210305180331_create_ci_unit_tests.rb'
- - 'db/migrate/20210305182855_create_ci_unit_test_failures.rb'
- - 'db/migrate/20210317035357_create_dast_profiles_pipelines.rb'
- - 'db/migrate/20210317104301_create_in_product_marketing_emails.rb'
- - 'db/migrate/20210323125809_create_status_check_responses_table.rb'
- - 'db/migrate/20210329191850_add_finding_signature_table.rb'
- - 'db/migrate/20210411212813_add_clusters_integrations_prometheus.rb'
- - 'db/migrate/20210423054022_create_dast_site_profiles_pipelines.rb'
- - 'db/migrate/20210429032320_add_escalation_rules.rb'
- - 'db/migrate/20210429131525_create_user_credit_card_validations.rb'
- - 'db/migrate/20210511104929_add_epic_board_recent_visits_table.rb'
- - 'db/migrate/20210512120122_add_pending_builds_table.rb'
- - 'db/migrate/20210527194558_create_ci_job_token_project_scope_links.rb'
- - 'db/migrate/20210601123341_add_running_builds_table.rb'
- - 'db/migrate/20210602122213_add_upcoming_reconciliations.rb'
- - 'db/migrate/20210604032738_create_dast_site_profiles_builds.rb'
- - 'db/migrate/20210604051330_create_dast_scanner_profiles_builds.rb'
- - 'db/migrate/20210604082145_create_external_status_checks_table.rb'
- - 'db/migrate/20210713211008_create_banned_users.rb'
- - 'db/migrate/20210729081739_create_project_topics.rb'
- - 'db/migrate/20210729202143_create_incident_management_issuable_escalation_statuses.rb'
- - 'db/migrate/20210730101609_create_analytics_cycle_analytics_stage_event_hashes.rb'
- - 'db/migrate/20210809014850_create_agent_group_authorizations.rb'
- - 'db/migrate/20210812171704_create_project_ci_feature_usages.rb'
- - 'db/migrate/20210813101742_create_zentao_tracker_data.rb'
- - 'db/migrate/20210813111909_create_ci_build_trace_metadata.rb'
- - 'db/migrate/20210819185500_create_external_audit_event_destinations_table.rb'
- - 'db/migrate/20210823172643_create_user_group_callout.rb'
- - 'db/migrate/20210823213417_create_dependency_proxy_image_ttl_group_policies.rb'
- - 'db/migrate/20210913010411_create_agent_project_authorizations.rb'
- - 'db/migrate/20210922215740_create_issue_customer_relations_contacts.rb'
- - 'db/migrate/20211004062942_create_coverage_fuzzing_corpuses.rb'
- - 'db/migrate/20211004122540_create_member_tasks.rb'
- - 'db/migrate/20211011004242_create_content_blocked_states.rb'
- - 'db/migrate/20211011140930_create_ci_namespace_mirrors.rb'
- - 'db/migrate/20211011140931_create_ci_project_mirrors.rb'
- - 'db/migrate/20211011140932_create_namespaces_sync_events.rb'
- - 'db/migrate/20211011141239_create_projects_sync_events.rb'
- - 'db/migrate/20211028132247_create_packages_npm_metadata.rb'
- - 'db/migrate/20211101132310_add_reindexing_queue.rb'
- - 'db/migrate/20211101165656_create_upload_states.rb'
- - 'db/migrate/20211110014701_create_agent_activity_events.rb'
- - 'db/migrate/20211110092710_create_issue_emails.rb'
- - 'db/migrate/20211111112425_create_merge_requests_compliance_violations.rb'
- - 'db/migrate/20211115132613_create_incident_management_timeline_events.rb'
- - 'db/migrate/20211117174209_create_vulnerability_reads.rb'
- - 'db/migrate/20211119111006_create_job_artifact_states.rb'
- - 'db/migrate/20211119154221_create_pages_deployment_states.rb'
- - 'db/migrate/20211119195201_create_deployment_approvals.rb'
- - 'db/migrate/20211201143042_create_lfs_object_states.rb'
- - 'db/migrate/20211216220939_add_group_crm_settings.rb'
- - 'db/migrate/20220110170953_create_ci_secure_files.rb'
- - 'db/migrate/20220112205111_create_security_training_providers.rb'
- - 'db/migrate/20220113125401_create_security_trainings.rb'
- - 'db/migrate/20220120033115_create_alert_management_alert_metric_images.rb'
- - 'db/migrate/20220204093120_create_analytics_cycle_analytics_aggregations.rb'
- - 'db/migrate/20220211125954_create_related_epic_links.rb'
- - 'db/migrate/20220216110023_create_saved_replies.rb'
- - 'db/migrate/20220301175426_create_project_build_artifacts_size_refresh.rb'
- - 'db/migrate/20220302110724_add_group_features_table.rb'
- - 'db/migrate/20220314184009_create_protected_environment_approval_rules.rb'
- - 'db/migrate/20220425120604_create_packages_cleanup_policies.rb'
- - 'db/migrate/20220503102855_add_namespace_ci_cd_settings_table.rb'
diff --git a/.rubocop_todo/rails/file_path.yml b/.rubocop_todo/rails/file_path.yml
index 24a08fa5ee2..898d303bd3d 100644
--- a/.rubocop_todo/rails/file_path.yml
+++ b/.rubocop_todo/rails/file_path.yml
@@ -1,6 +1,5 @@
---
Rails/FilePath:
- Details: grace period
Exclude:
- 'app/controllers/help_controller.rb'
- 'app/helpers/startupjs_helper.rb'
diff --git a/.rubocop_todo/rails/has_many_or_has_one_dependent.yml b/.rubocop_todo/rails/has_many_or_has_one_dependent.yml
deleted file mode 100644
index 92ba718bfff..00000000000
--- a/.rubocop_todo/rails/has_many_or_has_one_dependent.yml
+++ /dev/null
@@ -1,154 +0,0 @@
----
-Rails/HasManyOrHasOneDependent:
- # Offense count: 593
- # Temporarily disabled due to too many offenses
- Enabled: false
- Exclude:
- - 'app/models/alert_management/alert.rb'
- - 'app/models/analytics/cycle_analytics/project_value_stream.rb'
- - 'app/models/analytics/cycle_analytics/stage_event_hash.rb'
- - 'app/models/application_setting/term.rb'
- - 'app/models/bulk_import.rb'
- - 'app/models/bulk_imports/entity.rb'
- - 'app/models/bulk_imports/export.rb'
- - 'app/models/ci/bridge.rb'
- - 'app/models/ci/build.rb'
- - 'app/models/ci/pipeline.rb'
- - 'app/models/ci/pipeline_schedule.rb'
- - 'app/models/ci/processable.rb'
- - 'app/models/ci/ref.rb'
- - 'app/models/ci/resource_group.rb'
- - 'app/models/ci/runner.rb'
- - 'app/models/ci/stage.rb'
- - 'app/models/ci/trigger.rb'
- - 'app/models/ci/trigger_request.rb'
- - 'app/models/ci/unit_test.rb'
- - 'app/models/clusters/agent.rb'
- - 'app/models/clusters/applications/knative.rb'
- - 'app/models/clusters/cluster.rb'
- - 'app/models/clusters/project.rb'
- - 'app/models/commit_status.rb'
- - 'app/models/concerns/ci/metadatable.rb'
- - 'app/models/concerns/integrations/has_data_fields.rb'
- - 'app/models/concerns/issuable.rb'
- - 'app/models/concerns/label_eventable.rb'
- - 'app/models/concerns/milestone_eventable.rb'
- - 'app/models/concerns/packages/debian/distribution.rb'
- - 'app/models/concerns/protected_ref.rb'
- - 'app/models/concerns/state_eventable.rb'
- - 'app/models/concerns/timebox.rb'
- - 'app/models/concerns/versioned_description.rb'
- - 'app/models/concerns/with_uploads.rb'
- - 'app/models/customer_relations/contact.rb'
- - 'app/models/deploy_key.rb'
- - 'app/models/deploy_token.rb'
- - 'app/models/deployment.rb'
- - 'app/models/design_management/design.rb'
- - 'app/models/design_management/version.rb'
- - 'app/models/environment.rb'
- - 'app/models/error_tracking/error.rb'
- - 'app/models/event.rb'
- - 'app/models/experiment.rb'
- - 'app/models/fork_network.rb'
- - 'app/models/gpg_key.rb'
- - 'app/models/group.rb'
- - 'app/models/hooks/web_hook.rb'
- - 'app/models/integration.rb'
- - 'app/models/issue.rb'
- - 'app/models/jira_connect_installation.rb'
- - 'app/models/label.rb'
- - 'app/models/lfs_object.rb'
- - 'app/models/list.rb'
- - 'app/models/member.rb'
- - 'app/models/merge_request.rb'
- - 'app/models/merge_request_context_commit.rb'
- - 'app/models/milestone.rb'
- - 'app/models/namespace.rb'
- - 'app/models/namespaces/project_namespace.rb'
- - 'app/models/note.rb'
- - 'app/models/operations/feature_flag.rb'
- - 'app/models/operations/feature_flags/strategy.rb'
- - 'app/models/operations/feature_flags/user_list.rb'
- - 'app/models/packages/debian/project_distribution.rb'
- - 'app/models/packages/dependency.rb'
- - 'app/models/packages/dependency_link.rb'
- - 'app/models/packages/package.rb'
- - 'app/models/packages/package_file.rb'
- - 'app/models/pages_domain.rb'
- - 'app/models/plan.rb'
- - 'app/models/pool_repository.rb'
- - 'app/models/project.rb'
- - 'app/models/projects/topic.rb'
- - 'app/models/prometheus_alert.rb'
- - 'app/models/prometheus_metric.rb'
- - 'app/models/release.rb'
- - 'app/models/snippet.rb'
- - 'app/models/terraform/state.rb'
- - 'app/models/user.rb'
- - 'app/models/wiki_page/meta.rb'
- - 'app/models/work_items/type.rb'
- - 'app/models/x509_certificate.rb'
- - 'app/models/x509_issuer.rb'
- - 'ee/app/models/analytics/devops_adoption/enabled_namespace.rb'
- - 'ee/app/models/analytics/devops_adoption/snapshot.rb'
- - 'ee/app/models/approval_merge_request_rule.rb'
- - 'ee/app/models/approval_project_rule.rb'
- - 'ee/app/models/boards/epic_board.rb'
- - 'ee/app/models/boards/epic_list.rb'
- - 'ee/app/models/compliance_management/framework.rb'
- - 'ee/app/models/concerns/ee/iteration_eventable.rb'
- - 'ee/app/models/concerns/ee/protected_branch.rb'
- - 'ee/app/models/concerns/ee/protected_ref.rb'
- - 'ee/app/models/concerns/ee/weight_eventable.rb'
- - 'ee/app/models/concerns/geo/eventable.rb'
- - 'ee/app/models/concerns/issue_widgets/acts_like_requirement.rb'
- - 'ee/app/models/concerns/security/scan_execution_policy.rb'
- - 'ee/app/models/dast/profile.rb'
- - 'ee/app/models/dast_site.rb'
- - 'ee/app/models/dast_site_profile.rb'
- - 'ee/app/models/dast_site_validation.rb'
- - 'ee/app/models/ee/alert_management/alert.rb'
- - 'ee/app/models/ee/analytics/cycle_analytics/stage_event_hash.rb'
- - 'ee/app/models/ee/board.rb'
- - 'ee/app/models/ee/ci/build.rb'
- - 'ee/app/models/ee/ci/job_artifact.rb'
- - 'ee/app/models/ee/ci/pipeline.rb'
- - 'ee/app/models/ee/deployment.rb'
- - 'ee/app/models/ee/environment.rb'
- - 'ee/app/models/ee/epic.rb'
- - 'ee/app/models/ee/group.rb'
- - 'ee/app/models/ee/issue.rb'
- - 'ee/app/models/ee/iteration.rb'
- - 'ee/app/models/ee/label.rb'
- - 'ee/app/models/ee/lfs_object.rb'
- - 'ee/app/models/ee/merge_request.rb'
- - 'ee/app/models/ee/merge_request_diff.rb'
- - 'ee/app/models/ee/milestone.rb'
- - 'ee/app/models/ee/namespace.rb'
- - 'ee/app/models/ee/pages_deployment.rb'
- - 'ee/app/models/ee/plan.rb'
- - 'ee/app/models/ee/project.rb'
- - 'ee/app/models/ee/upload.rb'
- - 'ee/app/models/ee/user.rb'
- - 'ee/app/models/ee/vulnerability.rb'
- - 'ee/app/models/elastic/reindexing_subtask.rb'
- - 'ee/app/models/elastic/reindexing_task.rb'
- - 'ee/app/models/geo/event.rb'
- - 'ee/app/models/geo_node.rb'
- - 'ee/app/models/incident_management/escalation_policy.rb'
- - 'ee/app/models/incident_management/oncall_participant.rb'
- - 'ee/app/models/incident_management/oncall_rotation.rb'
- - 'ee/app/models/incident_management/oncall_schedule.rb'
- - 'ee/app/models/integrations/gitlab_slack_application.rb'
- - 'ee/app/models/iterations/cadence.rb'
- - 'ee/app/models/protected_environment.rb'
- - 'ee/app/models/protected_environments/approval_rule.rb'
- - 'ee/app/models/push_rule.rb'
- - 'ee/app/models/saml_provider.rb'
- - 'ee/app/models/security/finding.rb'
- - 'ee/app/models/security/scan.rb'
- - 'ee/app/models/security/training_provider.rb'
- - 'ee/app/models/vulnerabilities/finding.rb'
- - 'ee/app/models/vulnerabilities/identifier.rb'
- - 'ee/app/models/vulnerabilities/remediation.rb'
- - 'ee/app/models/vulnerabilities/scanner.rb'
diff --git a/.rubocop_todo/rails/helper_instance_variable.yml b/.rubocop_todo/rails/helper_instance_variable.yml
index 8f9197c9223..53e376730fd 100644
--- a/.rubocop_todo/rails/helper_instance_variable.yml
+++ b/.rubocop_todo/rails/helper_instance_variable.yml
@@ -1,6 +1,5 @@
---
Rails/HelperInstanceVariable:
- Details: grace period
Exclude:
- 'app/helpers/admin/user_actions_helper.rb'
- 'app/helpers/application_helper.rb'
diff --git a/.rubocop_todo/rails/index_with.yml b/.rubocop_todo/rails/index_with.yml
index 91a75e198f5..b7bc2a26959 100644
--- a/.rubocop_todo/rails/index_with.yml
+++ b/.rubocop_todo/rails/index_with.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
Rails/IndexWith:
- Details: grace period
Exclude:
- 'app/helpers/ci/jobs_helper.rb'
- 'app/models/ci/build_trace_chunk.rb'
diff --git a/.rubocop_todo/rails/inverse_of.yml b/.rubocop_todo/rails/inverse_of.yml
index 262804739bd..2ad8d6204c8 100644
--- a/.rubocop_todo/rails/inverse_of.yml
+++ b/.rubocop_todo/rails/inverse_of.yml
@@ -1,6 +1,5 @@
---
Rails/InverseOf:
- Details: grace period
Exclude:
- 'app/models/alert_management/alert.rb'
- 'app/models/alert_management/alert_assignee.rb'
diff --git a/.rubocop_todo/rails/lexically_scoped_action_filter.yml b/.rubocop_todo/rails/lexically_scoped_action_filter.yml
index 9edc8f7ce58..dde0da13d3c 100644
--- a/.rubocop_todo/rails/lexically_scoped_action_filter.yml
+++ b/.rubocop_todo/rails/lexically_scoped_action_filter.yml
@@ -1,15 +1,13 @@
---
Rails/LexicallyScopedActionFilter:
- # Offense count: 73
- # Temporarily disabled due to too many offenses
- Enabled: false
+ Details: grace period
Exclude:
- 'app/controllers/admin/groups_controller.rb'
+ - 'app/controllers/admin/hooks_controller.rb'
- 'app/controllers/clusters/base_controller.rb'
- 'app/controllers/clusters/clusters_controller.rb'
- 'app/controllers/concerns/enforces_two_factor_authentication.rb'
- 'app/controllers/concerns/integrations/actions.rb'
- - 'app/controllers/concerns/multiple_boards_actions.rb'
- 'app/controllers/concerns/oauth_applications.rb'
- 'app/controllers/concerns/spammable_actions/captcha_check/html_format_actions_support.rb'
- 'app/controllers/confirmations_controller.rb'
@@ -17,14 +15,17 @@ Rails/LexicallyScopedActionFilter:
- 'app/controllers/groups/group_members_controller.rb'
- 'app/controllers/groups/milestones_controller.rb'
- 'app/controllers/groups/runners_controller.rb'
+ - 'app/controllers/groups/settings/repository_controller.rb'
- 'app/controllers/groups/uploads_controller.rb'
- 'app/controllers/groups_controller.rb'
- 'app/controllers/import/base_controller.rb'
- 'app/controllers/oauth/applications_controller.rb'
- 'app/controllers/passwords_controller.rb'
+ - 'app/controllers/projects/analytics/cycle_analytics/stages_controller.rb'
- 'app/controllers/projects/badges_controller.rb'
- 'app/controllers/projects/branches_controller.rb'
- 'app/controllers/projects/environments_controller.rb'
+ - 'app/controllers/projects/hooks_controller.rb'
- 'app/controllers/projects/incidents_controller.rb'
- 'app/controllers/projects/issue_links_controller.rb'
- 'app/controllers/projects/issues_controller.rb'
@@ -36,6 +37,8 @@ Rails/LexicallyScopedActionFilter:
- 'app/controllers/projects/project_members_controller.rb'
- 'app/controllers/projects/prometheus/alerts_controller.rb'
- 'app/controllers/projects/releases_controller.rb'
+ - 'app/controllers/projects/settings/integration_hook_logs_controller.rb'
+ - 'app/controllers/projects/settings/merge_requests_controller.rb'
- 'app/controllers/projects/snippets_controller.rb'
- 'app/controllers/projects/tags_controller.rb'
- 'app/controllers/projects/todos_controller.rb'
diff --git a/.rubocop_todo/rails/negate_include.yml b/.rubocop_todo/rails/negate_include.yml
index 7bf78b82b60..c3f9ac25e7e 100644
--- a/.rubocop_todo/rails/negate_include.yml
+++ b/.rubocop_todo/rails/negate_include.yml
@@ -1,30 +1,28 @@
---
# Cop supports --auto-correct.
Rails/NegateInclude:
- # Offense count: 65
- # Temporarily disabled due to too many offenses
- Enabled: false
+ Details: grace period
Exclude:
- 'app/finders/projects_finder.rb'
- 'app/helpers/application_settings_helper.rb'
- 'app/helpers/projects_helper.rb'
- 'app/helpers/tree_helper.rb'
- - 'app/models/concerns/timebox.rb'
- 'app/models/integrations/chat_message/pipeline_message.rb'
+ - 'app/models/integrations/field.rb'
- 'app/models/label.rb'
- 'app/models/merge_request.rb'
+ - 'app/models/milestone.rb'
- 'app/services/todo_service.rb'
+ - 'app/services/work_items/parent_links/create_service.rb'
- 'config/application.rb'
- 'config/initializers/1_settings.rb'
- 'danger/roulette/Dangerfile'
- 'ee/app/finders/security/pipeline_vulnerabilities_finder.rb'
- - 'ee/app/models/ee/epic.rb'
- 'ee/app/models/ee/vulnerability.rb'
- 'ee/app/services/epic_issues/create_service.rb'
- 'ee/app/services/security/ingestion/tasks/ingest_remediations.rb'
- 'ee/app/services/security/security_orchestration_policies/validate_policy_service.rb'
- 'lib/api/maven_packages.rb'
- - 'lib/generators/gitlab/usage_metric_generator.rb'
- 'lib/gitlab/background_migration/legacy_upload_mover.rb'
- 'lib/gitlab/ci/build/rules/rule/clause/exists.rb'
- 'lib/gitlab/ci/parsers/coverage/sax_document.rb'
@@ -38,11 +36,10 @@ Rails/NegateInclude:
- 'lib/gitlab/task_helpers.rb'
- 'lib/gitlab/url_blocker.rb'
- 'lib/gitlab_edition.rb'
+ - 'qa/qa/page/merge_request/show.rb'
- 'qa/qa/runtime/ip_address.rb'
- 'qa/qa/support/run.rb'
- 'qa/qa/tools/delete_test_users.rb'
- - 'qa/qa/vendor/jenkins/page/configure_job.rb'
- - 'qa/qa/vendor/jenkins/page/last_job_console.rb'
- 'rubocop/cop/gitlab/feature_available_usage.rb'
- 'rubocop/cop/graphql/id_type.rb'
- 'rubocop/cop/migration/add_reference.rb'
@@ -56,3 +53,4 @@ Rails/NegateInclude:
- 'spec/support/matchers/pushed_frontend_feature_flags_matcher.rb'
- 'spec/support/shared_contexts/markdown_golden_master_shared_examples.rb'
- 'spec/uploaders/object_storage_spec.rb'
+ - 'tooling/danger/specs.rb'
diff --git a/.rubocop_todo/rails/redundant_foreign_key.yml b/.rubocop_todo/rails/redundant_foreign_key.yml
index 22af6131b33..0d23c51caae 100644
--- a/.rubocop_todo/rails/redundant_foreign_key.yml
+++ b/.rubocop_todo/rails/redundant_foreign_key.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
Rails/RedundantForeignKey:
- Details: grace period
Exclude:
- 'app/models/alert_management/metric_image.rb'
- 'app/models/ci/build.rb'
diff --git a/.rubocop_todo/rails/skips_model_validations.yml b/.rubocop_todo/rails/skips_model_validations.yml
deleted file mode 100644
index f5aa7411c89..00000000000
--- a/.rubocop_todo/rails/skips_model_validations.yml
+++ /dev/null
@@ -1,730 +0,0 @@
----
-Rails/SkipsModelValidations:
- # Offense count: 1424
- # Temporarily disabled due to too many offenses
- Enabled: false
- Exclude:
- - 'app/controllers/import/github_controller.rb'
- - 'app/controllers/projects/environments_controller.rb'
- - 'app/controllers/projects/notes_controller.rb'
- - 'app/models/alert_management/alert.rb'
- - 'app/models/analytics/cycle_analytics/aggregation.rb'
- - 'app/models/chat_name.rb'
- - 'app/models/ci/build.rb'
- - 'app/models/ci/build_trace_chunks/database.rb'
- - 'app/models/ci/build_trace_metadata.rb'
- - 'app/models/ci/daily_build_group_report_result.rb'
- - 'app/models/ci/deleted_object.rb'
- - 'app/models/ci/namespace_mirror.rb'
- - 'app/models/ci/pending_build.rb'
- - 'app/models/ci/pipeline_schedule.rb'
- - 'app/models/ci/processable.rb'
- - 'app/models/ci/project_mirror.rb'
- - 'app/models/ci/resource_group.rb'
- - 'app/models/ci/runner.rb'
- - 'app/models/ci/running_build.rb'
- - 'app/models/ci/unit_test.rb'
- - 'app/models/commit_status.rb'
- - 'app/models/concerns/batch_nullify_dependent_associations.rb'
- - 'app/models/concerns/board_recent_visit.rb'
- - 'app/models/concerns/cache_markdown_field.rb'
- - 'app/models/concerns/can_move_repository_storage.rb'
- - 'app/models/concerns/cascading_namespace_setting_attribute.rb'
- - 'app/models/concerns/counter_attribute.rb'
- - 'app/models/concerns/deprecated_assignee.rb'
- - 'app/models/concerns/file_store_mounter.rb'
- - 'app/models/concerns/has_wiki_page_meta_attributes.rb'
- - 'app/models/concerns/noteable.rb'
- - 'app/models/concerns/packages/debian/distribution.rb'
- - 'app/models/concerns/relative_positioning.rb'
- - 'app/models/concerns/repository_storage_movable.rb'
- - 'app/models/concerns/resolvable_note.rb'
- - 'app/models/concerns/schedulable.rb'
- - 'app/models/concerns/subscribable.rb'
- - 'app/models/container_expiration_policy.rb'
- - 'app/models/customer_relations/contact.rb'
- - 'app/models/customer_relations/organization.rb'
- - 'app/models/deployment.rb'
- - 'app/models/diff_note_position.rb'
- - 'app/models/environment.rb'
- - 'app/models/gpg_key.rb'
- - 'app/models/group.rb'
- - 'app/models/group_import_state.rb'
- - 'app/models/hooks/web_hook.rb'
- - 'app/models/internal_id.rb'
- - 'app/models/issue.rb'
- - 'app/models/jira_import_state.rb'
- - 'app/models/loose_foreign_keys/deleted_record.rb'
- - 'app/models/merge_request.rb'
- - 'app/models/merge_request/diff_commit_user.rb'
- - 'app/models/merge_request_diff.rb'
- - 'app/models/namespace.rb'
- - 'app/models/note.rb'
- - 'app/models/project.rb'
- - 'app/models/project_authorization.rb'
- - 'app/models/project_import_state.rb'
- - 'app/models/project_statistics.rb'
- - 'app/models/project_wiki.rb'
- - 'app/models/projects/ci_feature_usage.rb'
- - 'app/models/projects/repository_storage_move.rb'
- - 'app/models/projects/topic.rb'
- - 'app/models/raw_usage_data.rb'
- - 'app/models/remote_mirror.rb'
- - 'app/models/route.rb'
- - 'app/models/todo.rb'
- - 'app/models/u2f_registration.rb'
- - 'app/models/user.rb'
- - 'app/models/user_custom_attribute.rb'
- - 'app/models/user_interacted_project.rb'
- - 'app/services/boards/lists/base_destroy_service.rb'
- - 'app/services/boards/lists/move_service.rb'
- - 'app/services/bulk_create_integration_service.rb'
- - 'app/services/bulk_update_integration_service.rb'
- - 'app/services/ci/abort_pipelines_service.rb'
- - 'app/services/ci/disable_user_pipeline_schedules_service.rb'
- - 'app/services/ci/expire_pipeline_cache_service.rb'
- - 'app/services/ci/job_artifacts/create_service.rb'
- - 'app/services/ci/job_artifacts/destroy_batch_service.rb'
- - 'app/services/ci/job_artifacts/expire_project_build_artifacts_service.rb'
- - 'app/services/ci/job_artifacts/update_unknown_locked_status_service.rb'
- - 'app/services/ci/test_failure_history_service.rb'
- - 'app/services/ci/update_build_state_service.rb'
- - 'app/services/ci/update_pending_build_service.rb'
- - 'app/services/clusters/agent_tokens/track_usage_service.rb'
- - 'app/services/clusters/agents/refresh_authorization_service.rb'
- - 'app/services/clusters/integrations/prometheus_health_check_service.rb'
- - 'app/services/deployments/archive_in_project_service.rb'
- - 'app/services/event_create_service.rb'
- - 'app/services/groups/transfer_service.rb'
- - 'app/services/issuable_base_service.rb'
- - 'app/services/issues/move_service.rb'
- - 'app/services/issues/set_crm_contacts_service.rb'
- - 'app/services/keys/expiry_notification_service.rb'
- - 'app/services/keys/last_used_service.rb'
- - 'app/services/labels/promote_service.rb'
- - 'app/services/labels/transfer_service.rb'
- - 'app/services/merge_requests/bulk_remove_attention_requested_service.rb'
- - 'app/services/merge_requests/cleanup_refs_service.rb'
- - 'app/services/merge_requests/ff_merge_service.rb'
- - 'app/services/merge_requests/merge_service.rb'
- - 'app/services/merge_requests/rebase_service.rb'
- - 'app/services/merge_requests/reopen_service.rb'
- - 'app/services/milestones/promote_service.rb'
- - 'app/services/milestones/transfer_service.rb'
- - 'app/services/packages/composer/create_package_service.rb'
- - 'app/services/packages/debian/generate_distribution_service.rb'
- - 'app/services/packages/generic/create_package_file_service.rb'
- - 'app/services/packages/mark_package_files_for_destruction_service.rb'
- - 'app/services/packages/npm/create_tag_service.rb'
- - 'app/services/packages/pypi/create_package_service.rb'
- - 'app/services/packages/rubygems/create_dependencies_service.rb'
- - 'app/services/personal_access_tokens/last_used_service.rb'
- - 'app/services/projects/destroy_service.rb'
- - 'app/services/projects/detect_repository_languages_service.rb'
- - 'app/services/projects/move_deploy_keys_projects_service.rb'
- - 'app/services/projects/move_forks_service.rb'
- - 'app/services/projects/move_lfs_objects_projects_service.rb'
- - 'app/services/projects/move_notification_settings_service.rb'
- - 'app/services/projects/move_project_authorizations_service.rb'
- - 'app/services/projects/move_project_group_links_service.rb'
- - 'app/services/projects/move_project_members_service.rb'
- - 'app/services/projects/move_users_star_projects_service.rb'
- - 'app/services/projects/repository_languages_service.rb'
- - 'app/services/projects/unlink_fork_service.rb'
- - 'app/services/reset_project_cache_service.rb'
- - 'app/services/spam/akismet_mark_as_spam_service.rb'
- - 'app/services/spam/ham_service.rb'
- - 'app/services/suggestions/apply_service.rb'
- - 'app/services/suggestions/outdate_service.rb'
- - 'app/services/users/activity_service.rb'
- - 'app/services/users/migrate_to_ghost_user_service.rb'
- - 'app/services/users/respond_to_terms_service.rb'
- - 'app/services/users/set_status_service.rb'
- - 'app/services/users/upsert_credit_card_validation_service.rb'
- - 'app/services/x509_certificate_revoke_service.rb'
- - 'app/uploaders/file_mover.rb'
- - 'app/uploaders/object_storage.rb'
- - 'app/workers/analytics/usage_trends/counter_job_worker.rb'
- - 'app/workers/concerns/dependency_proxy/expireable.rb'
- - 'app/workers/concerns/packages/cleanup_artifact_worker.rb'
- - 'app/workers/container_expiration_policy_worker.rb'
- - 'app/workers/packages/helm/extraction_worker.rb'
- - 'app/workers/packages/nuget/extraction_worker.rb'
- - 'app/workers/packages/rubygems/extraction_worker.rb'
- - 'app/workers/personal_access_tokens/expired_notification_worker.rb'
- - 'app/workers/personal_access_tokens/expiring_worker.rb'
- - 'app/workers/pipeline_metrics_worker.rb'
- - 'app/workers/process_commit_worker.rb'
- - 'app/workers/repository_check/clear_worker.rb'
- - 'app/workers/repository_check/single_repository_worker.rb'
- - 'app/workers/stuck_merge_jobs_worker.rb'
- - 'app/workers/x509_issuer_crl_check_worker.rb'
- - 'db/migrate/20210428151144_update_invalid_web_hooks.rb'
- - 'db/migrate/20210629031900_associate_existing_dast_builds_with_variables.rb'
- - 'db/migrate/20210630224625_generate_customers_dot_jwt_signing_key.rb'
- - 'db/migrate/20210729123101_confirm_security_bot.rb'
- - 'db/migrate/20220413054910_backfill_delayed_group_deletion.rb'
- - 'db/post_migrate/20210303121224_update_gitlab_subscriptions_start_at_post_eoa.rb'
- - 'db/post_migrate/20210303165302_cleanup_cluster_tokens_with_null_name.rb'
- - 'db/post_migrate/20210406144743_backfill_total_tuple_count_for_batched_migrations.rb'
- - 'db/post_migrate/20210513155546_backfill_nuget_temporary_packages_to_processing_status.rb'
- - 'db/post_migrate/20210601073400_fix_total_stage_in_vsa.rb'
- - 'db/post_migrate/20210615234935_fix_batched_migrations_old_format_job_arguments.rb'
- - 'db/post_migrate/20210722042939_update_issuable_slas_where_issue_closed.rb'
- - 'db/post_migrate/20210731132939_backfill_stage_event_hash.rb'
- - 'db/post_migrate/20210809123658_orphaned_invite_tokens_cleanup.rb'
- - 'db/post_migrate/20210811122206_update_external_project_bots.rb'
- - 'db/post_migrate/20210825150212_cleanup_remaining_orphan_invites.rb'
- - 'db/post_migrate/20210826171758_initialize_throttle_unauthenticated_api_columns.rb'
- - 'db/post_migrate/20210901153324_slice_merge_request_diff_commit_migrations.rb'
- - 'db/post_migrate/20210908132335_disable_job_token_scope_when_unused.rb'
- - 'db/post_migrate/20210914095310_cleanup_orphan_project_access_tokens.rb'
- - 'db/post_migrate/20211217174331_mark_recalculate_finding_signatures_as_completed.rb'
- - 'db/post_migrate/20211220123956_update_invalid_member_states.rb'
- - 'db/post_migrate/20220305223212_add_security_training_providers.rb'
- - 'db/post_migrate/20220307203459_rename_user_email_lookup_limit_setting_to_search_settings_cleanup.rb'
- - 'db/post_migrate/20220322132242_update_pages_onboarding_state.rb'
- - 'ee/app/controllers/ee/clusters/clusters_controller.rb'
- - 'ee/app/models/approval_merge_request_rule.rb'
- - 'ee/app/models/ci/minutes/namespace_monthly_usage.rb'
- - 'ee/app/models/ci/minutes/project_monthly_usage.rb'
- - 'ee/app/models/concerns/deprecated_approvals_before_merge.rb'
- - 'ee/app/models/concerns/epic_tree_sorting.rb'
- - 'ee/app/models/concerns/geo/replicable_registry.rb'
- - 'ee/app/models/concerns/geo/verification_state.rb'
- - 'ee/app/models/ee/description_version.rb'
- - 'ee/app/models/ee/environment.rb'
- - 'ee/app/models/ee/epic.rb'
- - 'ee/app/models/ee/event.rb'
- - 'ee/app/models/ee/group.rb'
- - 'ee/app/models/ee/iteration.rb'
- - 'ee/app/models/ee/namespace_setting.rb'
- - 'ee/app/models/ee/project_wiki.rb'
- - 'ee/app/models/geo/container_repository_registry.rb'
- - 'ee/app/models/geo/design_registry.rb'
- - 'ee/app/models/geo/project_registry.rb'
- - 'ee/app/models/geo_node.rb'
- - 'ee/app/models/incident_management/oncall_rotation.rb'
- - 'ee/app/models/vulnerabilities/feedback.rb'
- - 'ee/app/services/app_sec/dast/profiles/create_associations_service.rb'
- - 'ee/app/services/ci/minutes/additional_packs/change_namespace_service.rb'
- - 'ee/app/services/ci/minutes/batch_reset_service.rb'
- - 'ee/app/services/ci/minutes/refresh_cached_data_service.rb'
- - 'ee/app/services/ci/minutes/reset_usage_service.rb'
- - 'ee/app/services/ci/minutes/update_project_and_namespace_usage_service.rb'
- - 'ee/app/services/ci/sync_reports_to_approval_rules_service.rb'
- - 'ee/app/services/ee/issues/move_service.rb'
- - 'ee/app/services/ee/labels/promote_service.rb'
- - 'ee/app/services/ee/milestones/promote_service.rb'
- - 'ee/app/services/ee/projects/transfer_service.rb'
- - 'ee/app/services/ee/users/migrate_to_ghost_user_service.rb'
- - 'ee/app/services/epics/strategies/due_date_inherited_strategy.rb'
- - 'ee/app/services/epics/strategies/start_date_inherited_strategy.rb'
- - 'ee/app/services/geo/repository_verification_reset.rb'
- - 'ee/app/services/incident_management/oncall_rotations/edit_service.rb'
- - 'ee/app/services/incident_management/oncall_rotations/remove_participant_service.rb'
- - 'ee/app/services/iterations/cadences/create_iterations_in_advance_service.rb'
- - 'ee/app/services/iterations/cadences/destroy_service.rb'
- - 'ee/app/services/iterations/delete_service.rb'
- - 'ee/app/services/iterations/roll_over_issues_service.rb'
- - 'ee/app/services/ldap_group_reset_service.rb'
- - 'ee/app/services/personal_access_tokens/revoke_invalid_tokens.rb'
- - 'ee/app/services/security/findings/cleanup_service.rb'
- - 'ee/app/services/security/ingestion/mark_as_resolved_service.rb'
- - 'ee/app/services/security/store_findings_metadata_service.rb'
- - 'ee/app/services/security/store_scan_service.rb'
- - 'ee/app/services/security/update_training_service.rb'
- - 'ee/app/services/vulnerabilities/starboard_vulnerability_resolve_service.rb'
- - 'ee/app/workers/import_software_licenses_worker.rb'
- - 'ee/app/workers/iterations_update_status_worker.rb'
- - 'ee/app/workers/sync_seat_link_request_worker.rb'
- - 'ee/lib/api/geo_replication.rb'
- - 'ee/lib/ee/api/protected_branches.rb'
- - 'ee/lib/ee/gitlab/auth/ldap/sync/group.rb'
- - 'ee/lib/ee/gitlab/background_migration/backfill_iteration_cadence_id_for_boards.rb'
- - 'ee/lib/ee/gitlab/background_migration/migrate_job_artifact_registry_to_ssf.rb'
- - 'ee/lib/ee/gitlab/background_migration/migrate_requirements_to_work_items.rb'
- - 'ee/lib/ee/gitlab/background_migration/populate_resolved_on_default_branch_column.rb'
- - 'ee/lib/ee/gitlab/background_migration/populate_uuids_for_security_findings.rb'
- - 'ee/lib/gitlab/geo/replicator.rb'
- - 'ee/lib/tasks/migrate/ldap.rake'
- - 'ee/spec/controllers/admin/geo/projects_controller_spec.rb'
- - 'ee/spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb'
- - 'ee/spec/controllers/groups/ldaps_controller_spec.rb'
- - 'ee/spec/controllers/projects/merge_requests_controller_spec.rb'
- - 'ee/spec/factories/import_states.rb'
- - 'ee/spec/features/admin/admin_settings_spec.rb'
- - 'ee/spec/features/epic_boards/epic_boards_sidebar_spec.rb'
- - 'ee/spec/features/projects/settings/ee/service_desk_setting_spec.rb'
- - 'ee/spec/features/projects/settings/issues_settings_spec.rb'
- - 'ee/spec/features/projects/settings/protected_environments_spec.rb'
- - 'ee/spec/features/projects/user_applies_custom_file_template_spec.rb'
- - 'ee/spec/features/trials/select_namespace_spec.rb'
- - 'ee/spec/finders/geo/repository_verification_finder_spec.rb'
- - 'ee/spec/finders/security/findings_finder_spec.rb'
- - 'ee/spec/finders/security/training_urls_finder_spec.rb'
- - 'ee/spec/finders/template_finder_spec.rb'
- - 'ee/spec/graphql/mutations/issues/set_epic_spec.rb'
- - 'ee/spec/graphql/mutations/issues/set_escalation_policy_spec.rb'
- - 'ee/spec/graphql/mutations/issues/set_iteration_spec.rb'
- - 'ee/spec/graphql/resolvers/boards/epic_lists_resolvers_spec.rb'
- - 'ee/spec/helpers/ee/blob_helper_spec.rb'
- - 'ee/spec/helpers/push_rules_helper_spec.rb'
- - 'ee/spec/lib/banzai/filter/references/epic_reference_filter_spec.rb'
- - 'ee/spec/lib/banzai/filter/references/iteration_reference_filter_spec.rb'
- - 'ee/spec/lib/banzai/filter/references/vulnerability_reference_filters_spec.rb'
- - 'ee/spec/lib/ee/api/helpers_spec.rb'
- - 'ee/spec/lib/ee/audit/group_changes_auditor_spec.rb'
- - 'ee/spec/lib/ee/audit/project_changes_auditor_spec.rb'
- - 'ee/spec/lib/ee/audit/project_ci_cd_setting_changes_auditor_spec.rb'
- - 'ee/spec/lib/ee/audit/project_feature_changes_auditor_spec.rb'
- - 'ee/spec/lib/ee/audit/protected_branches_changes_auditor_spec.rb'
- - 'ee/spec/lib/ee/gitlab/auth/ldap/sync/group_spec.rb'
- - 'ee/spec/lib/ee/gitlab/background_migration/fix_incorrect_max_seats_used_spec.rb'
- - 'ee/spec/lib/ee/gitlab/checks/push_rules/commit_check_spec.rb'
- - 'ee/spec/lib/gitlab/auth/ldap/access_spec.rb'
- - 'ee/spec/lib/gitlab/auth/saml/user_spec.rb'
- - 'ee/spec/lib/gitlab/custom_file_templates_spec.rb'
- - 'ee/spec/lib/gitlab/geo/geo_tasks_spec.rb'
- - 'ee/spec/lib/gitlab/geo/jwt_request_decoder_spec.rb'
- - 'ee/spec/lib/gitlab/geo/signed_data_spec.rb'
- - 'ee/spec/lib/gitlab/git_access_spec.rb'
- - 'ee/spec/models/application_setting_spec.rb'
- - 'ee/spec/models/ci/minutes/namespace_monthly_usage_spec.rb'
- - 'ee/spec/models/concerns/elastic/note_spec.rb'
- - 'ee/spec/models/concerns/geo/verification_state_spec.rb'
- - 'ee/spec/models/dast/profile_schedule_spec.rb'
- - 'ee/spec/models/ee/group_spec.rb'
- - 'ee/spec/models/ee/groups/feature_setting_spec.rb'
- - 'ee/spec/models/ee/iteration_spec.rb'
- - 'ee/spec/models/ee/iterations/cadence_spec.rb'
- - 'ee/spec/models/ee/vulnerability_spec.rb'
- - 'ee/spec/models/geo_node_spec.rb'
- - 'ee/spec/models/geo_node_status_spec.rb'
- - 'ee/spec/models/group_wiki_repository_spec.rb'
- - 'ee/spec/models/instance_security_dashboard_spec.rb'
- - 'ee/spec/models/merge_request/blocking_spec.rb'
- - 'ee/spec/models/merge_train_spec.rb'
- - 'ee/spec/models/packages/package_file_spec.rb'
- - 'ee/spec/models/project_feature_spec.rb'
- - 'ee/spec/models/project_import_state_spec.rb'
- - 'ee/spec/models/project_spec.rb'
- - 'ee/spec/models/project_team_spec.rb'
- - 'ee/spec/models/push_rule_spec.rb'
- - 'ee/spec/models/requirements_management/requirement_spec.rb'
- - 'ee/spec/models/security/scan_spec.rb'
- - 'ee/spec/models/snippet_repository_spec.rb'
- - 'ee/spec/models/vulnerabilities/feedback_spec.rb'
- - 'ee/spec/models/vulnerabilities/stat_diff_spec.rb'
- - 'ee/spec/policies/group_policy_spec.rb'
- - 'ee/spec/policies/project_policy_spec.rb'
- - 'ee/spec/requests/api/epic_issues_spec.rb'
- - 'ee/spec/requests/api/graphql/mutations/issues/promote_to_epic_spec.rb'
- - 'ee/spec/requests/api/graphql/mutations/issues/set_epic_spec.rb'
- - 'ee/spec/requests/api/groups_spec.rb'
- - 'ee/spec/requests/api/internal/app_sec/dast/site_validations_spec.rb'
- - 'ee/spec/requests/api/internal/kubernetes_spec.rb'
- - 'ee/spec/requests/api/namespaces_spec.rb'
- - 'ee/spec/requests/api/project_approvals_spec.rb'
- - 'ee/spec/requests/git_http_geo_spec.rb'
- - 'ee/spec/requests/projects/merge_requests_controller_spec.rb'
- - 'ee/spec/serializers/merge_request_widget_entity_spec.rb'
- - 'ee/spec/services/ci/create_pipeline_service_spec.rb'
- - 'ee/spec/services/ci/minutes/email_notification_service_spec.rb'
- - 'ee/spec/services/ci/register_job_service_spec.rb'
- - 'ee/spec/services/ci_cd/setup_project_spec.rb'
- - 'ee/spec/services/ee/boards/issues/list_service_spec.rb'
- - 'ee/spec/services/ee/notification_service_spec.rb'
- - 'ee/spec/services/ee/releases/create_evidence_service_spec.rb'
- - 'ee/spec/services/epic_issues/update_service_spec.rb'
- - 'ee/spec/services/epics/issue_promote_service_spec.rb'
- - 'ee/spec/services/epics/update_service_spec.rb'
- - 'ee/spec/services/geo/file_registry_removal_service_spec.rb'
- - 'ee/spec/services/geo/hashed_storage_migration_service_spec.rb'
- - 'ee/spec/services/groups/create_service_spec.rb'
- - 'ee/spec/services/groups/update_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/projects/setup_ci_cd_spec.rb'
- - 'ee/spec/services/projects/update_mirror_service_spec.rb'
- - 'ee/spec/services/security/ingestion/ingest_report_slice_service_spec.rb'
- - 'ee/spec/services/security/security_orchestration_policies/create_pipeline_service_spec.rb'
- - 'ee/spec/services/vulnerabilities/starboard_vulnerability_resolve_service_spec.rb'
- - 'ee/spec/services/vulnerabilities/statistics/adjustment_service_spec.rb'
- - 'ee/spec/services/vulnerabilities/statistics/update_service_spec.rb'
- - 'ee/spec/support/helpers/ee/geo_helpers.rb'
- - 'ee/spec/support/shared_examples/models/requirement_issues_examples.rb'
- - 'ee/spec/support/shared_examples/policies/protected_environments_shared_examples.rb'
- - 'ee/spec/workers/app_sec/dast/profile_schedule_worker_spec.rb'
- - 'ee/spec/workers/ee/repository_check/batch_worker_spec.rb'
- - 'ee/spec/workers/geo/repositories_clean_up_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/secondary/scheduler_worker_spec.rb'
- - 'ee/spec/workers/geo/repository_verification/secondary/single_worker_spec.rb'
- - 'ee/spec/workers/geo/verification_state_backfill_service_spec.rb'
- - 'ee/spec/workers/import_software_licenses_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/security/orchestration_policy_rule_schedule_namespace_worker_spec.rb'
- - 'ee/spec/workers/security/orchestration_policy_rule_schedule_worker_spec.rb'
- - 'ee/spec/workers/update_all_mirrors_worker_spec.rb'
- - 'lib/api/commit_statuses.rb'
- - 'lib/api/usage_data.rb'
- - 'lib/gitlab/background_migration/add_primary_email_to_emails_if_user_confirmed.rb'
- - 'lib/gitlab/background_migration/backfill_ci_queuing_tables.rb'
- - 'lib/gitlab/background_migration/backfill_draft_status_on_merge_requests.rb'
- - 'lib/gitlab/background_migration/backfill_jira_tracker_deployment_type2.rb'
- - 'lib/gitlab/background_migration/backfill_member_namespace_for_group_members.rb'
- - 'lib/gitlab/background_migration/backfill_namespace_id_for_namespace_route.rb'
- - 'lib/gitlab/background_migration/backfill_namespace_traversal_ids_roots.rb'
- - 'lib/gitlab/background_migration/backfill_projects_with_coverage.rb'
- - 'lib/gitlab/background_migration/backfill_topics_title.rb'
- - 'lib/gitlab/background_migration/backfill_user_namespace.rb'
- - 'lib/gitlab/background_migration/backfill_work_item_type_id_for_issues.rb'
- - 'lib/gitlab/background_migration/cleanup_draft_data_from_faulty_regex.rb'
- - 'lib/gitlab/background_migration/copy_column_using_background_migration_job.rb'
- - 'lib/gitlab/background_migration/legacy_upload_mover.rb'
- - 'lib/gitlab/background_migration/merge_topics_with_same_name.rb'
- - 'lib/gitlab/background_migration/migrate_merge_request_diff_commit_users.rb'
- - 'lib/gitlab/background_migration/migrate_null_private_profile_to_false.rb'
- - 'lib/gitlab/background_migration/migrate_personal_namespace_project_maintainer_to_owner.rb'
- - 'lib/gitlab/background_migration/migrate_project_taggings_context_from_tags_to_topics.rb'
- - 'lib/gitlab/background_migration/migrate_shimo_confluence_integration_category.rb'
- - 'lib/gitlab/background_migration/migrate_u2f_webauthn.rb'
- - 'lib/gitlab/background_migration/nullify_orphan_runner_id_on_ci_builds.rb'
- - 'lib/gitlab/background_migration/project_namespaces/backfill_project_namespaces.rb'
- - 'lib/gitlab/background_migration/remove_all_trace_expiration_dates.rb'
- - 'lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values_on_projects.rb'
- - 'lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values_on_projects.rb'
- - 'lib/gitlab/bitbucket_import/importer.rb'
- - 'lib/gitlab/bitbucket_server_import/importer.rb'
- - 'lib/gitlab/ci/tags/bulk_insert.rb'
- - 'lib/gitlab/ci/trace.rb'
- - 'lib/gitlab/composer/cache.rb'
- - 'lib/gitlab/database/background_migration_job.rb'
- - 'lib/gitlab/database/postgresql_adapter/dump_schema_versions_mixin.rb'
- - 'lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base.rb'
- - 'lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces.rb'
- - 'lib/gitlab/database/schema_migrations.rb'
- - 'lib/gitlab/etag_caching/middleware.rb'
- - 'lib/gitlab/fogbugz_import/importer.rb'
- - 'lib/gitlab/github_import/importer/pull_request_merged_by_importer.rb'
- - 'lib/gitlab/github_import/importer/pull_request_review_importer.rb'
- - 'lib/gitlab/import/set_async_jid.rb'
- - 'lib/gitlab/jira_import/handle_labels_service.rb'
- - 'lib/gitlab/job_waiter.rb'
- - 'lib/gitlab/legacy_github_import/importer.rb'
- - 'lib/gitlab/markdown_cache/active_record/extension.rb'
- - 'lib/gitlab/otp_key_rotator.rb'
- - 'lib/gitlab/seeder.rb'
- - 'lib/tasks/ci/cleanup.rake'
- - 'lib/tasks/gitlab/external_diffs.rake'
- - 'lib/tasks/gitlab/ldap.rake'
- - 'lib/tasks/gitlab/user_management.rake'
- - 'lib/tasks/migrate/migrate_iids.rake'
- - 'spec/controllers/groups/dependency_proxy_for_containers_controller_spec.rb'
- - 'spec/controllers/groups_controller_spec.rb'
- - 'spec/controllers/import/bitbucket_controller_spec.rb'
- - 'spec/controllers/import/gitlab_controller_spec.rb'
- - 'spec/controllers/omniauth_callbacks_controller_spec.rb'
- - 'spec/controllers/projects/forks_controller_spec.rb'
- - 'spec/controllers/projects/graphs_controller_spec.rb'
- - 'spec/controllers/projects/jobs_controller_spec.rb'
- - 'spec/controllers/projects/merge_requests/content_controller_spec.rb'
- - 'spec/controllers/projects/merge_requests_controller_spec.rb'
- - 'spec/controllers/projects/notes_controller_spec.rb'
- - 'spec/controllers/projects/pipelines/tests_controller_spec.rb'
- - 'spec/controllers/projects/repositories_controller_spec.rb'
- - 'spec/controllers/projects/settings/ci_cd_controller_spec.rb'
- - 'spec/controllers/projects/starrers_controller_spec.rb'
- - 'spec/controllers/projects_controller_spec.rb'
- - 'spec/controllers/uploads_controller_spec.rb'
- - 'spec/factories/alert_management/alerts.rb'
- - 'spec/factories/container_expiration_policies.rb'
- - 'spec/factories/design_management/versions.rb'
- - 'spec/factories/environments.rb'
- - 'spec/factories/import_states.rb'
- - 'spec/factories/projects.rb'
- - 'spec/factories/usage_data.rb'
- - 'spec/features/admin/admin_settings_spec.rb'
- - 'spec/features/admin/admin_uses_repository_checks_spec.rb'
- - 'spec/features/dashboard/projects_spec.rb'
- - 'spec/features/groups_spec.rb'
- - 'spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb'
- - 'spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb'
- - 'spec/features/issues/discussion_lock_spec.rb'
- - 'spec/features/merge_request/merge_request_discussion_lock_spec.rb'
- - 'spec/features/merge_request/user_creates_image_diff_notes_spec.rb'
- - 'spec/features/merge_request/user_locks_discussion_spec.rb'
- - 'spec/features/merge_request/user_merges_only_if_pipeline_succeeds_spec.rb'
- - 'spec/features/merge_request/user_sees_diff_spec.rb'
- - 'spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb'
- - 'spec/features/merge_request/user_sees_merge_widget_spec.rb'
- - 'spec/features/merge_request/user_sees_pipelines_spec.rb'
- - 'spec/features/merge_request/user_views_merge_request_from_deleted_fork_spec.rb'
- - 'spec/features/monitor_sidebar_link_spec.rb'
- - 'spec/features/password_reset_spec.rb'
- - 'spec/features/profiles/emails_spec.rb'
- - 'spec/features/projects/blobs/blob_show_spec.rb'
- - 'spec/features/projects/diffs/diff_show_spec.rb'
- - 'spec/features/projects/features_visibility_spec.rb'
- - 'spec/features/projects/fork_spec.rb'
- - 'spec/features/projects/jobs_spec.rb'
- - 'spec/features/projects/milestones/milestone_spec.rb'
- - 'spec/features/projects/pipeline_schedules_spec.rb'
- - 'spec/features/projects/pipelines/pipeline_spec.rb'
- - 'spec/features/projects/settings/service_desk_setting_spec.rb'
- - 'spec/features/projects/settings/user_manages_merge_requests_settings_spec.rb'
- - 'spec/features/projects/user_sees_sidebar_spec.rb'
- - 'spec/features/projects_spec.rb'
- - 'spec/features/u2f_spec.rb'
- - 'spec/features/users/show_spec.rb'
- - 'spec/features/webauthn_spec.rb'
- - 'spec/finders/groups_finder_spec.rb'
- - 'spec/finders/notes_finder_spec.rb'
- - 'spec/finders/packages/go/package_finder_spec.rb'
- - 'spec/finders/packages/maven/package_finder_spec.rb'
- - 'spec/finders/packages/npm/package_finder_spec.rb'
- - 'spec/finders/packages/nuget/package_finder_spec.rb'
- - 'spec/finders/packages/package_finder_spec.rb'
- - 'spec/finders/projects_finder_spec.rb'
- - 'spec/finders/releases/group_releases_finder_spec.rb'
- - 'spec/finders/releases_finder_spec.rb'
- - 'spec/finders/user_group_notification_settings_finder_spec.rb'
- - 'spec/graphql/mutations/custom_emoji/destroy_spec.rb'
- - 'spec/graphql/mutations/issues/set_escalation_status_spec.rb'
- - 'spec/graphql/mutations/issues/update_spec.rb'
- - 'spec/graphql/resolvers/ci/test_suite_resolver_spec.rb'
- - 'spec/graphql/types/project_type_spec.rb'
- - 'spec/helpers/auth_helper_spec.rb'
- - 'spec/helpers/events_helper_spec.rb'
- - 'spec/helpers/groups_helper_spec.rb'
- - 'spec/helpers/import_helper_spec.rb'
- - 'spec/helpers/members_helper_spec.rb'
- - 'spec/helpers/projects_helper_spec.rb'
- - 'spec/initializers/active_record_locking_spec.rb'
- - 'spec/lib/api/helpers_spec.rb'
- - 'spec/lib/backup/repositories_spec.rb'
- - 'spec/lib/banzai/filter/references/issue_reference_filter_spec.rb'
- - 'spec/lib/banzai/filter/references/merge_request_reference_filter_spec.rb'
- - 'spec/lib/banzai/filter/references/snippet_reference_filter_spec.rb'
- - 'spec/lib/banzai/reference_parser/merge_request_parser_spec.rb'
- - 'spec/lib/banzai/reference_parser/snippet_parser_spec.rb'
- - 'spec/lib/gitlab/asciidoc_spec.rb'
- - 'spec/lib/gitlab/auth/saml/user_spec.rb'
- - 'spec/lib/gitlab/background_migration/backfill_project_repositories_spec.rb'
- - 'spec/lib/gitlab/background_migration/batched_migration_job_spec.rb'
- - 'spec/lib/gitlab/background_migration/update_timelogs_null_spent_at_spec.rb'
- - 'spec/lib/gitlab/ci/variables/builder/group_spec.rb'
- - 'spec/lib/gitlab/ci/variables/builder/project_spec.rb'
- - 'spec/lib/gitlab/contributions_calendar_spec.rb'
- - 'spec/lib/gitlab/cycle_analytics/permissions_spec.rb'
- - 'spec/lib/gitlab/database/background_migration/batched_migration_runner_spec.rb'
- - 'spec/lib/gitlab/database/batch_count_spec.rb'
- - 'spec/lib/gitlab/database/consistency_checker_spec.rb'
- - 'spec/lib/gitlab/database/load_balancing/connection_proxy_spec.rb'
- - 'spec/lib/gitlab/database/load_balancing_spec.rb'
- - 'spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb'
- - 'spec/lib/gitlab/database/query_analyzers/prevent_cross_database_modification_spec.rb'
- - 'spec/lib/gitlab/database/schema_migrations/migrations_spec.rb'
- - 'spec/lib/gitlab/discussions_diff/file_collection_spec.rb'
- - 'spec/lib/gitlab/email/handler/create_note_handler_spec.rb'
- - 'spec/lib/gitlab/email/handler/create_note_on_issuable_handler_spec.rb'
- - 'spec/lib/gitlab/etag_caching/store_spec.rb'
- - 'spec/lib/gitlab/git_access_spec.rb'
- - 'spec/lib/gitlab/git_access_wiki_spec.rb'
- - 'spec/lib/gitlab/markdown_cache/active_record/extension_spec.rb'
- - 'spec/lib/gitlab/middleware/go_spec.rb'
- - 'spec/lib/gitlab/middleware/query_analyzer_spec.rb'
- - 'spec/lib/gitlab/object_hierarchy_spec.rb'
- - 'spec/lib/gitlab/sidekiq_middleware/query_analyzer_spec.rb'
- - 'spec/lib/sidebars/projects/menus/project_information_menu_spec.rb'
- - 'spec/mailers/notify_spec.rb'
- - 'spec/migrations/20211126115449_encrypt_static_objects_external_storage_auth_token_spec.rb'
- - 'spec/migrations/remove_duplicate_dast_site_tokens_spec.rb'
- - 'spec/migrations/schedule_update_timelogs_null_spent_at_spec.rb'
- - 'spec/models/application_setting_spec.rb'
- - 'spec/models/ci/build_dependencies_spec.rb'
- - 'spec/models/ci/build_spec.rb'
- - 'spec/models/ci/group_spec.rb'
- - 'spec/models/ci/pipeline_schedule_spec.rb'
- - 'spec/models/ci/pipeline_spec.rb'
- - 'spec/models/ci/processable_spec.rb'
- - 'spec/models/ci/resource_group_spec.rb'
- - 'spec/models/ci/runner_spec.rb'
- - 'spec/models/ci/stage_spec.rb'
- - 'spec/models/commit_signatures/gpg_signature_spec.rb'
- - 'spec/models/commit_status_spec.rb'
- - 'spec/models/concerns/cache_markdown_field_spec.rb'
- - 'spec/models/concerns/deployment_platform_spec.rb'
- - 'spec/models/concerns/deprecated_assignee_spec.rb'
- - 'spec/models/concerns/each_batch_spec.rb'
- - 'spec/models/concerns/pg_full_text_searchable_spec.rb'
- - 'spec/models/concerns/project_features_compatibility_spec.rb'
- - 'spec/models/concerns/spammable_spec.rb'
- - 'spec/models/container_repository_spec.rb'
- - 'spec/models/deploy_keys_project_spec.rb'
- - 'spec/models/deploy_token_spec.rb'
- - 'spec/models/diff_discussion_spec.rb'
- - 'spec/models/diff_note_spec.rb'
- - 'spec/models/environment_spec.rb'
- - 'spec/models/group_spec.rb'
- - 'spec/models/guest_spec.rb'
- - 'spec/models/integration_spec.rb'
- - 'spec/models/issue_spec.rb'
- - 'spec/models/loose_foreign_keys/deleted_record_spec.rb'
- - 'spec/models/member_spec.rb'
- - 'spec/models/members/group_member_spec.rb'
- - 'spec/models/members/project_member_spec.rb'
- - 'spec/models/merge_request_diff_spec.rb'
- - 'spec/models/merge_request_spec.rb'
- - 'spec/models/namespace/traversal_hierarchy_spec.rb'
- - 'spec/models/namespace_spec.rb'
- - 'spec/models/note_spec.rb'
- - 'spec/models/project_authorization_spec.rb'
- - 'spec/models/project_feature_spec.rb'
- - 'spec/models/project_spec.rb'
- - 'spec/models/project_statistics_spec.rb'
- - 'spec/models/projects/build_artifacts_size_refresh_spec.rb'
- - 'spec/models/projects/topic_spec.rb'
- - 'spec/models/remote_mirror_spec.rb'
- - 'spec/models/repository_spec.rb'
- - 'spec/models/route_spec.rb'
- - 'spec/models/snippet_repository_spec.rb'
- - 'spec/models/user_spec.rb'
- - 'spec/policies/ci/build_policy_spec.rb'
- - 'spec/policies/custom_emoji_policy_spec.rb'
- - 'spec/policies/note_policy_spec.rb'
- - 'spec/policies/project_policy_spec.rb'
- - 'spec/presenters/ci/build_presenter_spec.rb'
- - 'spec/presenters/project_presenter_spec.rb'
- - 'spec/requests/api/ci/job_artifacts_spec.rb'
- - 'spec/requests/api/ci/runner/jobs_request_post_spec.rb'
- - 'spec/requests/api/container_repositories_spec.rb'
- - 'spec/requests/api/graphql/container_repository/container_repository_details_spec.rb'
- - 'spec/requests/api/graphql/group/dependency_proxy_blobs_spec.rb'
- - 'spec/requests/api/graphql/group/dependency_proxy_group_setting_spec.rb'
- - 'spec/requests/api/graphql/group/dependency_proxy_image_ttl_policy_spec.rb'
- - 'spec/requests/api/graphql/group/dependency_proxy_manifests_spec.rb'
- - 'spec/requests/api/graphql/mutations/custom_emoji/destroy_spec.rb'
- - 'spec/requests/api/graphql/mutations/snippets/create_spec.rb'
- - 'spec/requests/api/graphql/mutations/snippets/destroy_spec.rb'
- - 'spec/requests/api/graphql/mutations/snippets/update_spec.rb'
- - 'spec/requests/api/helm_packages_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/merge_requests_spec.rb'
- - 'spec/requests/api/notes_spec.rb'
- - 'spec/requests/api/nuget_group_packages_spec.rb'
- - 'spec/requests/api/projects_spec.rb'
- - 'spec/requests/api/pypi_packages_spec.rb'
- - 'spec/requests/api/releases_spec.rb'
- - 'spec/requests/api/rubygem_packages_spec.rb'
- - 'spec/requests/api/snippets_spec.rb'
- - 'spec/requests/api/tags_spec.rb'
- - 'spec/requests/git_http_spec.rb'
- - 'spec/requests/groups/settings/access_tokens_controller_spec.rb'
- - 'spec/requests/jwt_controller_spec.rb'
- - 'spec/requests/lfs_http_spec.rb'
- - 'spec/requests/projects/merge_requests_spec.rb'
- - 'spec/requests/projects/settings/access_tokens_controller_spec.rb'
- - 'spec/services/alert_management/create_alert_issue_service_spec.rb'
- - 'spec/services/ci/compare_reports_base_service_spec.rb'
- - 'spec/services/ci/compare_test_reports_service_spec.rb'
- - 'spec/services/ci/job_artifacts/update_unknown_locked_status_service_spec.rb'
- - 'spec/services/ci/register_job_service_spec.rb'
- - 'spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb'
- - 'spec/services/ci/retry_job_service_spec.rb'
- - 'spec/services/ci/retry_pipeline_service_spec.rb'
- - 'spec/services/ci/test_failure_history_service_spec.rb'
- - 'spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb'
- - 'spec/services/container_expiration_policies/cleanup_service_spec.rb'
- - 'spec/services/dependency_proxy/find_cached_manifest_service_spec.rb'
- - 'spec/services/deployments/update_environment_service_spec.rb'
- - 'spec/services/groups/create_service_spec.rb'
- - 'spec/services/groups/transfer_service_spec.rb'
- - 'spec/services/groups/update_service_spec.rb'
- - 'spec/services/incident_management/pager_duty/process_webhook_service_spec.rb'
- - 'spec/services/issuable/common_system_notes_service_spec.rb'
- - 'spec/services/issues/clone_service_spec.rb'
- - 'spec/services/issues/close_service_spec.rb'
- - 'spec/services/issues/update_service_spec.rb'
- - 'spec/services/members/destroy_service_spec.rb'
- - 'spec/services/merge_requests/get_urls_service_spec.rb'
- - 'spec/services/merge_requests/merge_service_spec.rb'
- - 'spec/services/merge_requests/refresh_service_spec.rb'
- - 'spec/services/merge_requests/reopen_service_spec.rb'
- - 'spec/services/merge_requests/update_service_spec.rb'
- - 'spec/services/notes/update_service_spec.rb'
- - 'spec/services/notification_service_spec.rb'
- - 'spec/services/packages/maven/metadata/sync_service_spec.rb'
- - 'spec/services/packages/nuget/search_service_spec.rb'
- - 'spec/services/projects/container_repository/delete_tags_service_spec.rb'
- - 'spec/services/projects/create_service_spec.rb'
- - 'spec/services/projects/destroy_service_spec.rb'
- - 'spec/services/projects/fork_service_spec.rb'
- - 'spec/services/projects/refresh_build_artifacts_size_statistics_service_spec.rb'
- - 'spec/services/repositories/destroy_service_spec.rb'
- - 'spec/services/spam/ham_service_spec.rb'
- - 'spec/services/system_notes/design_management_service_spec.rb'
- - 'spec/services/system_notes/issuables_service_spec.rb'
- - 'spec/services/system_notes/time_tracking_service_spec.rb'
- - 'spec/services/users/repair_ldap_blocked_service_spec.rb'
- - 'spec/services/work_items/task_list_reference_replacement_service_spec.rb'
- - 'spec/support/helpers/access_matchers_helpers.rb'
- - 'spec/support/matchers/access_matchers_for_controller.rb'
- - 'spec/support/shared_contexts/email_shared_context.rb'
- - 'spec/support/shared_contexts/finders/packages/npm/package_finder_shared_context.rb'
- - 'spec/support/shared_contexts/mailers/notify_shared_context.rb'
- - 'spec/support/shared_contexts/requests/api/npm_packages_shared_context.rb'
- - 'spec/support/shared_examples/ci/stuck_builds_shared_examples.rb'
- - 'spec/support/shared_examples/controllers/create_notes_rate_limit_shared_examples.rb'
- - 'spec/support/shared_examples/controllers/githubish_import_controller_shared_examples.rb'
- - 'spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb'
- - 'spec/support/shared_examples/features/2fa_shared_examples.rb'
- - 'spec/support/shared_examples/features/access_tokens_shared_examples.rb'
- - 'spec/support/shared_examples/features/sidebar_shared_examples.rb'
- - 'spec/support/shared_examples/lib/banzai/reference_parser_shared_examples.rb'
- - 'spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb'
- - 'spec/support/shared_examples/models/concerns/featurable_shared_examples.rb'
- - 'spec/support/shared_examples/models/concerns/ttl_expirable_shared_examples.rb'
- - 'spec/support/shared_examples/models/members_notifications_shared_example.rb'
- - 'spec/support/shared_examples/models/packages/debian/distribution_shared_examples.rb'
- - 'spec/support/shared_examples/models/throttled_touch_shared_examples.rb'
- - 'spec/support/shared_examples/policies/resource_access_token_shared_examples.rb'
- - 'spec/support/shared_examples/requests/api/conan_packages_shared_examples.rb'
- - 'spec/support/shared_examples/requests/api/members_shared_examples.rb'
- - 'spec/support/shared_examples/requests/api/pypi_packages_shared_examples.rb'
- - 'spec/support/shared_examples/requests/user_activity_shared_examples.rb'
- - 'spec/support/shared_examples/services/boards/lists_list_service_shared_examples.rb'
- - 'spec/support/shared_examples/services/container_registry_auth_service_shared_examples.rb'
- - 'spec/support/shared_examples/services/notification_service_shared_examples.rb'
- - 'spec/support/shared_examples/views/pipeline_status_changes_email.rb'
- - 'spec/support/trace/trace_helpers.rb'
- - 'spec/support_specs/matchers/exceed_query_limit_helpers_spec.rb'
- - 'spec/tasks/gitlab/artifacts/check_rake_spec.rb'
- - 'spec/tasks/gitlab/external_diffs_rake_spec.rb'
- - 'spec/tasks/gitlab/uploads/check_rake_spec.rb'
- - 'spec/uploaders/job_artifact_uploader_spec.rb'
- - 'spec/views/groups/edit.html.haml_spec.rb'
- - 'spec/views/projects/environments/terminal.html.haml_spec.rb'
- - 'spec/workers/auto_devops/disable_worker_spec.rb'
- - 'spec/workers/build_finished_worker_spec.rb'
- - 'spec/workers/ci/merge_requests/add_todo_when_build_fails_worker_spec.rb'
- - 'spec/workers/concerns/gitlab/github_import/stage_methods_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/migration/guard_worker_spec.rb'
- - 'spec/workers/gitlab/github_import/advance_stage_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/pipeline_schedule_worker_spec.rb'
- - 'spec/workers/remote_mirror_notification_worker_spec.rb'
- - 'spec/workers/repository_check/batch_worker_spec.rb'
- - 'spec/workers/repository_check/clear_worker_spec.rb'
diff --git a/.rubocop_todo/rails/squished_sql_heredocs.yml b/.rubocop_todo/rails/squished_sql_heredocs.yml
deleted file mode 100644
index 9dcb989f571..00000000000
--- a/.rubocop_todo/rails/squished_sql_heredocs.yml
+++ /dev/null
@@ -1,215 +0,0 @@
----
-# Cop supports --auto-correct.
-Rails/SquishedSQLHeredocs:
- # Offense count: 356
- # Temporarily disabled due to too many offenses
- Enabled: false
- Exclude:
- - 'app/finders/members_finder.rb'
- - 'app/models/analytics/cycle_analytics/stage_event_hash.rb'
- - 'app/models/ci/resource_group.rb'
- - 'app/models/clusters/clusters_hierarchy.rb'
- - 'app/models/concerns/analytics/cycle_analytics/stage_event_model.rb'
- - 'app/models/concerns/has_environment_scope.rb'
- - 'app/models/customer_relations/contact.rb'
- - 'app/models/customer_relations/organization.rb'
- - 'app/models/deployment.rb'
- - 'app/models/issue/metrics.rb'
- - 'app/models/merge_request/metrics.rb'
- - 'app/models/namespace/traversal_hierarchy.rb'
- - 'app/models/namespaces/traversal/linear.rb'
- - 'app/models/project.rb'
- - 'app/models/user.rb'
- - 'app/services/issuable/destroy_label_links_service.rb'
- - 'app/services/issues/relative_position_rebalancing_service.rb'
- - 'app/services/projects/fetch_statistics_increment_service.rb'
- - 'app/services/todos/destroy/destroyed_issuable_service.rb'
- - 'app/workers/users/deactivate_dormant_users_worker.rb'
- - 'db/migrate/20210323155010_populate_dismissal_information_for_vulnerabilities.rb'
- - 'db/migrate/20210601080039_group_protected_environments_add_index_and_constraint.rb'
- - 'db/migrate/20210611100359_rebuild_index_for_cadence_iterations_automation.rb'
- - 'db/migrate/20210617022324_create_incident_management_pending_alert_escalations.rb'
- - 'db/migrate/20210621043337_rename_services_to_integrations.rb'
- - 'db/migrate/20210621044000_rename_services_indexes_to_integrations.rb'
- - 'db/migrate/20210706152139_add_index_type_to_postgres_indexes_view.rb'
- - 'db/migrate/20210719145532_add_foreign_keys_view.rb'
- - 'db/migrate/20210721135638_add_triggers_to_integrations_type_new.rb'
- - 'db/migrate/20210721174453_remove_schedule_and_status_null_constraints_from_pending_escalations_alert.rb'
- - 'db/migrate/20210722150102_operations_feature_flags_correct_flexible_rollout_values.rb'
- - 'db/migrate/20210730194555_create_incident_management_pending_issue_escalations.rb'
- - 'db/migrate/20210818175949_update_integrations_trigger_type_new_on_insert.rb'
- - 'db/migrate/20210825104656_create_analytics_cycle_analytics_merge_request_stage_events.rb'
- - 'db/migrate/20210825110016_create_analytics_cycle_analytics_issue_stage_events.rb'
- - 'db/migrate/20210826122748_create_loose_foreign_keys_deleted_records.rb'
- - 'db/migrate/20210826145509_add_function_for_inserting_deleted_records.rb'
- - 'db/migrate/20210903054158_recreate_stage_issue_events_table_with_bigints.rb'
- - 'db/migrate/20210906100021_delete_project_namespace_trigger.rb'
- - 'db/migrate/20210929032555_create_verification_codes.rb'
- - 'db/migrate/20211005092428_drop_time_range_partitioned_loose_fk.rb'
- - 'db/migrate/20211005093558_add_range_partitioned_loose_fk_table.rb'
- - 'db/migrate/20211005100112_recreate_loose_fk_insert_function.rb'
- - 'db/migrate/20211007090229_create_issue_search_table.rb'
- - 'db/migrate/20211011141242_create_namespaces_sync_trigger.rb'
- - 'db/migrate/20211011141243_create_projects_sync_trigger.rb'
- - 'db/migrate/20211012015903_next_traversal_ids_sibling_function.rb'
- - 'db/migrate/20211018161447_fix_double_entries_in_postgres_index_view.rb'
- - 'db/migrate/20211112155416_populate_default_value_for_personal_access_tokens_prefix.rb'
- - 'db/migrate/20211118103439_remove_hardcoded_partition_from_loose_fk_trigger_function.rb'
- - 'db/migrate/20211123135255_create_batched_background_migration_job_transition_logs.rb'
- - 'db/migrate/20220106111958_add_insert_or_update_vulnerability_reads_trigger.rb'
- - 'db/migrate/20220106112043_add_update_vulnerability_reads_trigger.rb'
- - 'db/migrate/20220106112085_add_update_vulnerability_reads_location_trigger.rb'
- - 'db/migrate/20220106163326_add_has_issues_on_vulnerability_reads_trigger.rb'
- - 'db/migrate/20220208171826_update_default_scan_method_of_dast_site_profile.rb'
- - 'db/migrate/20220211214605_update_integrations_trigger_type_new_on_insert_null_safe.rb'
- - 'db/migrate/20220213100000_remove_integration_type_triggers.rb'
- - 'db/migrate/20220304052335_remove_not_null_contraint_on_title_from_sprints.rb'
- - 'db/migrate/20220321234317_remove_all_issuable_escalation_statuses.rb'
- - 'db/migrate/20220329110630_add_ci_namespace_mirrors_unnest_index_on_traversal_ids.rb'
- - 'db/migrate/20220412060931_add_nullify_build_data_trigger_on_merge_request_metrics.rb'
- - 'db/migrate/20220413124200_add_view_for_per_table_autovacuum_status.rb'
- - 'db/migrate/20220415015143_replace_iterations_cadence_date_range_constraint.rb'
- - 'db/migrate/20220422200633_fix_view_for_per_table_autovacuum_status.rb'
- - 'db/migrate/20220422220507_remove_tmp_index_supporting_leaky_regex_cleanup.rb'
- - 'db/post_migrate/20210302074524_backfill_namespace_statistics_with_wiki_size.rb'
- - 'db/post_migrate/20210311045138_set_traversal_ids_for_gitlab_org_group_staging.rb'
- - 'db/post_migrate/20210311045139_set_traversal_ids_for_gitlab_org_group_com.rb'
- - 'db/post_migrate/20210311093723_add_partial_index_on_ci_pipelines_by_cancelable_status_and_users.rb'
- - 'db/post_migrate/20210317104032_set_iteration_cadence_automatic_to_false.rb'
- - 'db/post_migrate/20210331105335_drop_non_partitioned_audit_events.rb'
- - 'db/post_migrate/20210430134202_copy_adoption_snapshot_namespace.rb'
- - 'db/post_migrate/20210430135954_copy_adoption_segments_namespace.rb'
- - 'db/post_migrate/20210525075724_clean_up_pending_builds_table.rb'
- - 'db/post_migrate/20210609125005_drop_non_partitioned_web_hook_logs.rb'
- - 'db/post_migrate/20210610102413_migrate_protected_attribute_to_pending_builds.rb'
- - 'db/post_migrate/20210610141711_disable_expiration_policies_linked_to_no_container_images.rb'
- - 'db/post_migrate/20210708011426_finalize_ci_builds_metadata_bigint_conversion.rb'
- - 'db/post_migrate/20210721174521_add_non_null_constraint_for_escalation_rule_on_pending_alert_escalations.rb'
- - 'db/post_migrate/20210812013042_remove_duplicate_project_authorizations.rb'
- - 'db/post_migrate/20210907211557_finalize_ci_builds_bigint_conversion.rb'
- - 'db/post_migrate/20210910194952_update_report_type_for_existing_approval_project_rules.rb'
- - 'db/post_migrate/20211105135157_drop_ci_build_trace_sections.rb'
- - 'db/post_migrate/20211112113300_remove_ci_pipeline_chat_data_fk_on_chat_names.rb'
- - 'db/post_migrate/20211130165043_backfill_sequence_column_for_sprints_table.rb'
- - 'db/post_migrate/20211206161271_add_indexes_for_primary_email_cleanup_migration.rb'
- - 'db/post_migrate/20211220064757_drop_temporary_indexes_for_primary_email_migration.rb'
- - 'db/post_migrate/20220128155251_remove_dangling_running_builds.rb'
- - 'db/post_migrate/20220204095121_backfill_namespace_statistics_with_dependency_proxy_size.rb'
- - 'db/post_migrate/20220204110725_backfill_cycle_analytics_aggregations.rb'
- - 'db/post_migrate/20220213103859_remove_integrations_type.rb'
- - 'db/post_migrate/20220309084954_remove_leftover_external_pull_request_deletions.rb'
- - 'db/post_migrate/20220318111040_add_indexes_for_primary_email_second_cleanup_migration.rb'
- - 'db/post_migrate/20220318111949_drop_temporary_indexes_for_primary_email_migration_second_cleanup.rb'
- - 'db/post_migrate/20220329175119_remove_leftover_ci_job_artifact_deletions.rb'
- - 'db/post_migrate/20220420135946_update_batched_background_migration_arguments.rb'
- - 'ee/app/models/dora/daily_metrics.rb'
- - 'ee/app/models/ee/group.rb'
- - 'ee/app/models/ee/issue.rb'
- - 'ee/app/models/iterations/cadence.rb'
- - 'ee/app/models/vulnerabilities/statistic.rb'
- - 'ee/app/services/analytics/cycle_analytics/consistency_check_service.rb'
- - 'ee/app/services/security/ingestion/tasks/ingest_vulnerability_statistics.rb'
- - 'ee/app/services/vulnerabilities/historical_statistics/adjustment_service.rb'
- - 'ee/app/services/vulnerabilities/statistics/adjustment_service.rb'
- - 'ee/app/services/vulnerabilities/statistics/update_service.rb'
- - 'ee/db/geo/migrate/20170906174622_remove_duplicates_from_project_registry.rb'
- - 'ee/db/geo/migrate/20180510223634_set_resync_flag_for_retried_projects.rb'
- - 'ee/db/geo/post_migrate/20210217020154_add_unique_index_on_container_repository_registry.rb'
- - 'ee/db/geo/post_migrate/20210217020156_add_unique_index_on_terraform_state_version_registry.rb'
- - 'ee/lib/ee/gitlab/background_migration/backfill_iteration_cadence_id_for_boards.rb'
- - 'ee/lib/ee/gitlab/background_migration/create_security_setting.rb'
- - 'ee/lib/ee/gitlab/background_migration/populate_latest_pipeline_ids.rb'
- - 'ee/lib/ee/gitlab/background_migration/populate_resolved_on_default_branch_column.rb'
- - 'ee/lib/ee/gitlab/background_migration/populate_status_column_of_security_scans.rb'
- - 'ee/lib/ee/gitlab/background_migration/populate_test_reports_issue_id.rb'
- - 'ee/lib/ee/gitlab/background_migration/update_vulnerability_occurrences_location.rb'
- - 'ee/lib/ee/gitlab/usage_data.rb'
- - 'ee/lib/gitlab/geo/base_batcher.rb'
- - 'ee/spec/models/ee/user_spec.rb'
- - 'lib/gitlab/background_migration/backfill_ci_namespace_mirrors.rb'
- - 'lib/gitlab/background_migration/backfill_ci_project_mirrors.rb'
- - 'lib/gitlab/background_migration/backfill_group_features.rb'
- - 'lib/gitlab/background_migration/backfill_integrations_type_new.rb'
- - 'lib/gitlab/background_migration/backfill_issue_search_data.rb'
- - 'lib/gitlab/background_migration/backfill_namespace_id_for_project_route.rb'
- - 'lib/gitlab/background_migration/backfill_namespace_traversal_ids_children.rb'
- - 'lib/gitlab/background_migration/backfill_project_settings.rb'
- - 'lib/gitlab/background_migration/backfill_projects_with_coverage.rb'
- - 'lib/gitlab/background_migration/backfill_upvotes_count_on_issues.rb'
- - 'lib/gitlab/background_migration/disable_expiration_policies_linked_to_no_container_images.rb'
- - 'lib/gitlab/background_migration/encrypt_static_object_token.rb'
- - 'lib/gitlab/background_migration/fix_duplicate_project_name_and_path.rb'
- - 'lib/gitlab/background_migration/fix_first_mentioned_in_commit_at.rb'
- - 'lib/gitlab/background_migration/fix_projects_without_project_feature.rb'
- - 'lib/gitlab/background_migration/fix_projects_without_prometheus_service.rb'
- - 'lib/gitlab/background_migration/move_container_registry_enabled_to_project_feature.rb'
- - 'lib/gitlab/background_migration/populate_container_repository_migration_plan.rb'
- - 'lib/gitlab/background_migration/populate_topics_non_private_projects_count.rb'
- - 'lib/gitlab/background_migration/populate_topics_total_projects_count_cache.rb'
- - 'lib/gitlab/background_migration/populate_vulnerability_reads.rb'
- - 'lib/gitlab/background_migration/project_namespaces/backfill_project_namespaces.rb'
- - 'lib/gitlab/background_migration/update_timelogs_null_spent_at.rb'
- - 'lib/gitlab/background_migration/update_timelogs_project_id.rb'
- - 'lib/gitlab/background_migration/update_users_where_two_factor_auth_required_from_group.rb'
- - 'lib/gitlab/database/bulk_update.rb'
- - 'lib/gitlab/database/count/tablesample_count_strategy.rb'
- - 'lib/gitlab/database/load_balancing/load_balancer.rb'
- - 'lib/gitlab/database/migration_helpers.rb'
- - 'lib/gitlab/database/migration_helpers/loose_foreign_key_helpers.rb'
- - 'lib/gitlab/database/migration_helpers/v2.rb'
- - 'lib/gitlab/database/migrations/batched_background_migration_helpers.rb'
- - 'lib/gitlab/database/migrations/observers/query_statistics.rb'
- - 'lib/gitlab/database/partitioning/replace_table.rb'
- - 'lib/gitlab/database/partitioning/single_numeric_list_partition.rb'
- - 'lib/gitlab/database/partitioning/sliding_list_strategy.rb'
- - 'lib/gitlab/database/partitioning/time_partition.rb'
- - 'lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table.rb'
- - 'lib/gitlab/database/partitioning_migration_helpers/table_management_helpers.rb'
- - 'lib/gitlab/database/postgres_hll/batch_distinct_counter.rb'
- - 'lib/gitlab/database/schema_helpers.rb'
- - 'lib/gitlab/database/schema_migrations/migrations.rb'
- - 'lib/gitlab/database/unidirectional_copy_trigger.rb'
- - 'lib/gitlab/graphql/pagination/keyset/conditions/not_null_condition.rb'
- - 'lib/gitlab/graphql/pagination/keyset/conditions/null_condition.rb'
- - 'lib/gitlab/pagination/keyset/in_operator_optimization/query_builder.rb'
- - 'lib/gitlab/sql/glob.rb'
- - 'lib/tasks/dev.rake'
- - 'qa/qa/service/praefect_manager.rb'
- - 'spec/db/schema_spec.rb'
- - 'spec/initializers/00_rails_disable_joins_spec.rb'
- - 'spec/lib/gitlab/background_migration/copy_column_using_background_migration_job_spec.rb'
- - 'spec/lib/gitlab/database/migration_helpers/restrict_gitlab_schema_spec.rb'
- - 'spec/lib/gitlab/database/migration_helpers_spec.rb'
- - 'spec/lib/gitlab/database/migrations/observers/query_statistics_spec.rb'
- - 'spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb'
- - 'spec/lib/gitlab/database/partitioning/monthly_strategy_spec.rb'
- - 'spec/lib/gitlab/database/partitioning/partition_manager_spec.rb'
- - 'spec/lib/gitlab/database/partitioning/replace_table_spec.rb'
- - 'spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb'
- - 'spec/lib/gitlab/database/partitioning/time_partition_spec.rb'
- - 'spec/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table_spec.rb'
- - 'spec/lib/gitlab/database/partitioning_migration_helpers/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'
- - 'spec/lib/gitlab/database/postgres_foreign_key_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/reindexing/reindex_concurrently_spec.rb'
- - 'spec/lib/gitlab/database/reindexing_spec.rb'
- - 'spec/lib/gitlab/database/schema_migrations/migrations_spec.rb'
- - 'spec/lib/gitlab/database/similarity_score_spec.rb'
- - 'spec/lib/gitlab/database/unidirectional_copy_trigger_spec.rb'
- - 'spec/lib/gitlab/graphql/pagination/keyset/conditions/not_null_condition_spec.rb'
- - 'spec/lib/gitlab/graphql/pagination/keyset/conditions/null_condition_spec.rb'
- - 'spec/lib/gitlab/pagination/keyset/in_operator_optimization/strategies/record_loader_strategy_spec.rb'
- - 'spec/lib/gitlab/pagination/keyset/order_spec.rb'
- - 'spec/models/application_record_spec.rb'
- - 'spec/models/concerns/after_commit_queue_spec.rb'
- - 'spec/support/db_cleaner.rb'
- - 'spec/support/helpers/database/partitioning_helpers.rb'
- - 'spec/support/helpers/database/table_schema_helpers.rb'
- - 'spec/support/helpers/database/trigger_helpers.rb'
- - 'spec/support/shared_examples/loose_foreign_keys/have_loose_foreign_key.rb'
diff --git a/.rubocop_todo/rails/where_exists.yml b/.rubocop_todo/rails/where_exists.yml
deleted file mode 100644
index 77722549722..00000000000
--- a/.rubocop_todo/rails/where_exists.yml
+++ /dev/null
@@ -1,44 +0,0 @@
----
-# Cop supports --auto-correct.
-Rails/WhereExists:
- # Offense count: 48
- # Temporarily disabled due to too many offenses
- Enabled: false
- Exclude:
- - 'app/models/application_setting/term.rb'
- - 'app/models/ci/pipeline_artifact.rb'
- - 'app/models/ci/ref.rb'
- - 'app/models/clusters/agent.rb'
- - 'app/models/concerns/has_wiki.rb'
- - 'app/models/concerns/noteable.rb'
- - 'app/models/container_repository.rb'
- - 'app/models/design_management/design.rb'
- - 'app/models/group.rb'
- - 'app/models/group_deploy_token.rb'
- - 'app/models/label.rb'
- - 'app/models/lfs_object.rb'
- - 'app/models/merge_request_diff.rb'
- - 'app/models/namespace.rb'
- - 'app/models/project.rb'
- - 'app/models/protected_branch/push_access_level.rb'
- - 'app/services/projects/transfer_service.rb'
- - 'app/services/todos/destroy/unauthorized_features_service.rb'
- - 'db/migrate/20210422195929_create_elastic_reindexing_slices.rb'
- - 'ee/app/models/approval_merge_request_rule_source.rb'
- - 'ee/app/models/concerns/ee/protected_ref_access.rb'
- - 'ee/app/models/ee/epic.rb'
- - 'ee/app/models/ee/group_member.rb'
- - 'ee/app/models/ee/milestone_release.rb'
- - 'ee/app/models/geo_node.rb'
- - 'ee/app/models/merge_requests/external_status_check.rb'
- - 'ee/app/models/merge_train.rb'
- - 'ee/app/workers/concerns/elastic/indexing_control.rb'
- - 'lib/gitlab/auth.rb'
- - 'lib/gitlab/checks/matching_merge_request.rb'
- - 'lib/gitlab/database/partitioning/detached_partition_dropper.rb'
- - 'spec/lib/bulk_imports/projects/pipelines/snippets_repository_pipeline_spec.rb'
- - 'spec/migrations/recreate_index_security_ci_builds_on_name_and_id_parser_features_spec.rb'
- - 'spec/migrations/recreate_index_security_ci_builds_on_name_and_id_parser_with_new_features_spec.rb'
- - 'spec/models/user_spec.rb'
- - 'spec/services/clusters/cleanup/service_account_service_spec.rb'
- - 'spec/services/clusters/destroy_service_spec.rb'
diff --git a/.rubocop_todo/rake/require.yml b/.rubocop_todo/rake/require.yml
new file mode 100644
index 00000000000..5042f0d504e
--- /dev/null
+++ b/.rubocop_todo/rake/require.yml
@@ -0,0 +1,26 @@
+---
+Rake/Require:
+ Details: grace period
+ Exclude:
+ - 'ee/lib/tasks/gitlab/spdx.rake'
+ - 'lib/tasks/gitlab/artifacts/migrate.rake'
+ - 'lib/tasks/gitlab/assets.rake'
+ - 'lib/tasks/gitlab/backup.rake'
+ - 'lib/tasks/gitlab/cleanup.rake'
+ - 'lib/tasks/gitlab/dependency_proxy/migrate.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/ci.rake'
+ - 'qa/tasks/webdrivers.rake'
diff --git a/.rubocop_todo/rspec/context_wording.yml b/.rubocop_todo/rspec/context_wording.yml
index 79dfd85281c..5e9e80402b4 100644
--- a/.rubocop_todo/rspec/context_wording.yml
+++ b/.rubocop_todo/rspec/context_wording.yml
@@ -123,10 +123,8 @@ RSpec/ContextWording:
- 'ee/spec/features/groups/push_rules_spec.rb'
- 'ee/spec/features/groups/saml_enforcement_spec.rb'
- 'ee/spec/features/groups/saml_providers_spec.rb'
- - 'ee/spec/features/groups/seat_usage/seat_usage_spec.rb'
- 'ee/spec/features/groups/security/compliance_dashboards_spec.rb'
- 'ee/spec/features/groups/sso_spec.rb'
- - 'ee/spec/features/groups/usage_quotas_spec.rb'
- 'ee/spec/features/groups_spec.rb'
- 'ee/spec/features/ide/user_commits_changes_spec.rb'
- 'ee/spec/features/ide/user_opens_ide_spec.rb'
@@ -498,7 +496,6 @@ RSpec/ContextWording:
- 'ee/spec/models/ee/audit_event_spec.rb'
- 'ee/spec/models/ee/award_emoji_spec.rb'
- 'ee/spec/models/ee/ci/job_artifact_spec.rb'
- - 'ee/spec/models/ee/event_collection_spec.rb'
- 'ee/spec/models/ee/event_spec.rb'
- 'ee/spec/models/ee/group_group_link_spec.rb'
- 'ee/spec/models/ee/group_spec.rb'
@@ -1361,7 +1358,6 @@ RSpec/ContextWording:
- 'spec/features/projects/blobs/blob_show_spec.rb'
- 'spec/features/projects/blobs/edit_spec.rb'
- 'spec/features/projects/branches/user_views_branches_spec.rb'
- - 'spec/features/projects/branches_spec.rb'
- 'spec/features/projects/ci/lint_spec.rb'
- 'spec/features/projects/clusters_spec.rb'
- 'spec/features/projects/commit/comments/user_adds_comment_spec.rb'
@@ -1571,7 +1567,6 @@ RSpec/ContextWording:
- 'spec/graphql/resolvers/group_milestones_resolver_spec.rb'
- 'spec/graphql/resolvers/group_packages_resolver_spec.rb'
- 'spec/graphql/resolvers/issue_status_counts_resolver_spec.rb'
- - 'spec/graphql/resolvers/issues_resolver_spec.rb'
- 'spec/graphql/resolvers/kas/agent_configurations_resolver_spec.rb'
- 'spec/graphql/resolvers/kas/agent_connections_resolver_spec.rb'
- 'spec/graphql/resolvers/last_commit_resolver_spec.rb'
@@ -2401,7 +2396,6 @@ RSpec/ContextWording:
- 'spec/models/environment_spec.rb'
- 'spec/models/environment_status_spec.rb'
- 'spec/models/error_tracking/error_spec.rb'
- - 'spec/models/event_collection_spec.rb'
- 'spec/models/event_spec.rb'
- 'spec/models/experiment_spec.rb'
- 'spec/models/external_pull_request_spec.rb'
@@ -2777,7 +2771,6 @@ RSpec/ContextWording:
- 'spec/routing/project_routing_spec.rb'
- 'spec/rubocop/cop/gitlab/change_timezone_spec.rb'
- 'spec/rubocop/cop/gitlab/const_get_inherit_false_spec.rb'
- - 'spec/rubocop/cop/gitlab/duplicate_spec_location_spec.rb'
- 'spec/rubocop/cop/gitlab/event_store_subscriber_spec.rb'
- 'spec/rubocop/cop/gitlab/feature_available_usage_spec.rb'
- 'spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb'
@@ -2976,7 +2969,6 @@ RSpec/ContextWording:
- 'spec/services/members/destroy_service_spec.rb'
- 'spec/services/members/groups/creator_service_spec.rb'
- 'spec/services/members/projects/creator_service_spec.rb'
- - 'spec/services/members/update_service_spec.rb'
- 'spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb'
- 'spec/services/merge_requests/after_create_service_spec.rb'
- 'spec/services/merge_requests/approval_service_spec.rb'
diff --git a/.rubocop_todo/rspec/empty_line_after_hook.yml b/.rubocop_todo/rspec/empty_line_after_hook.yml
index 4b1c4299b20..125055044de 100644
--- a/.rubocop_todo/rspec/empty_line_after_hook.yml
+++ b/.rubocop_todo/rspec/empty_line_after_hook.yml
@@ -4,7 +4,6 @@ RSpec/EmptyLineAfterHook:
Exclude:
- 'ee/spec/controllers/projects/integrations/zentao/issues_controller_spec.rb'
- 'ee/spec/controllers/projects/push_rules_controller_spec.rb'
- - 'ee/spec/features/groups/usage_quotas_spec.rb'
- 'ee/spec/features/issues/user_bulk_edits_issues_spec.rb'
- 'ee/spec/features/profiles/usage_quotas_spec.rb'
- 'ee/spec/lib/ee/api/entities/user_with_admin_spec.rb'
diff --git a/.rubocop_todo/rspec/expect_change.yml b/.rubocop_todo/rspec/expect_change.yml
index 626ed1390ce..83892031a6c 100644
--- a/.rubocop_todo/rspec/expect_change.yml
+++ b/.rubocop_todo/rspec/expect_change.yml
@@ -293,7 +293,6 @@ RSpec/ExpectChange:
- 'ee/spec/services/security/orchestration/assign_service_spec.rb'
- 'ee/spec/services/security/override_uuids_service_spec.rb'
- 'ee/spec/services/security/security_orchestration_policies/sync_opened_merge_requests_service_spec.rb'
- - 'ee/spec/services/security/store_findings_metadata_service_spec.rb'
- 'ee/spec/services/security/store_scan_service_spec.rb'
- 'ee/spec/services/start_pull_mirroring_service_spec.rb'
- 'ee/spec/services/status_page/mark_for_publication_service_spec.rb'
@@ -712,6 +711,7 @@ RSpec/ExpectChange:
- 'spec/services/draft_notes/destroy_service_spec.rb'
- 'spec/services/draft_notes/publish_service_spec.rb'
- 'spec/services/emails/create_service_spec.rb'
+ - 'spec/services/environments/create_for_build_service_spec.rb'
- 'spec/services/error_tracking/collect_error_service_spec.rb'
- 'spec/services/error_tracking/list_projects_service_spec.rb'
- 'spec/services/event_create_service_spec.rb'
diff --git a/.rubocop_todo/rspec/factory_bot/avoid_create.yml b/.rubocop_todo/rspec/factory_bot/avoid_create.yml
index 2da0040f8ed..b41233d83af 100644
--- a/.rubocop_todo/rspec/factory_bot/avoid_create.yml
+++ b/.rubocop_todo/rspec/factory_bot/avoid_create.yml
@@ -1,7 +1,27 @@
---
RSpec/FactoryBot/AvoidCreate:
- Details: grace period
Exclude:
+ - 'ee/spec/presenters/approval_rule_presenter_spec.rb'
+ - 'ee/spec/presenters/audit_event_presenter_spec.rb'
+ - 'ee/spec/presenters/ci/build_runner_presenter_spec.rb'
+ - 'ee/spec/presenters/ci/minutes/usage_presenter_spec.rb'
+ - 'ee/spec/presenters/ci/pipeline_presenter_spec.rb'
+ - 'ee/spec/presenters/dast/site_profile_presenter_spec.rb'
+ - 'ee/spec/presenters/ee/blob_presenter_spec.rb'
+ - 'ee/spec/presenters/ee/clusters/cluster_presenter_spec.rb'
+ - 'ee/spec/presenters/ee/instance_clusterable_presenter_spec.rb'
+ - 'ee/spec/presenters/ee/issue_presenter_spec.rb'
+ - 'ee/spec/presenters/ee/projects/security/configuration_presenter_spec.rb'
+ - 'ee/spec/presenters/epic_issue_presenter_spec.rb'
+ - 'ee/spec/presenters/epic_presenter_spec.rb'
+ - 'ee/spec/presenters/group_clusterable_presenter_spec.rb'
+ - 'ee/spec/presenters/label_presenter_spec.rb'
+ - 'ee/spec/presenters/merge_request_approver_presenter_spec.rb'
+ - 'ee/spec/presenters/merge_request_presenter_spec.rb'
+ - 'ee/spec/presenters/project_clusterable_presenter_spec.rb'
+ - 'ee/spec/presenters/subscription_presenter_spec.rb'
+ - 'ee/spec/presenters/vulnerability_presenter_spec.rb'
+ - 'ee/spec/presenters/web_hooks/group/hook_presenter_spec.rb'
- 'ee/spec/serializers/analytics/cycle_analytics/stage_entity_spec.rb'
- 'ee/spec/serializers/analytics/cycle_analytics/value_stream_errors_serializer_spec.rb'
- 'ee/spec/serializers/audit_event_entity_spec.rb'
@@ -11,7 +31,6 @@ RSpec/FactoryBot/AvoidCreate:
- 'ee/spec/serializers/clusters/environment_entity_spec.rb'
- 'ee/spec/serializers/clusters/environment_serializer_spec.rb'
- 'ee/spec/serializers/dashboard_environment_entity_spec.rb'
- - 'ee/spec/serializers/dashboard_environments_project_entity_spec.rb'
- 'ee/spec/serializers/dashboard_environments_serializer_spec.rb'
- 'ee/spec/serializers/dashboard_operations_project_entity_spec.rb'
- 'ee/spec/serializers/dependency_entity_spec.rb'
@@ -73,6 +92,62 @@ RSpec/FactoryBot/AvoidCreate:
- 'ee/spec/serializers/vulnerabilities/scanner_entity_spec.rb'
- 'ee/spec/serializers/vulnerability_entity_spec.rb'
- 'ee/spec/serializers/vulnerability_note_entity_spec.rb'
+ - 'spec/presenters/alert_management/alert_presenter_spec.rb'
+ - 'spec/presenters/blob_presenter_spec.rb'
+ - 'spec/presenters/blobs/notebook_presenter_spec.rb'
+ - 'spec/presenters/ci/bridge_presenter_spec.rb'
+ - 'spec/presenters/ci/build_presenter_spec.rb'
+ - 'spec/presenters/ci/build_runner_presenter_spec.rb'
+ - 'spec/presenters/ci/group_variable_presenter_spec.rb'
+ - 'spec/presenters/ci/pipeline_artifacts/code_coverage_presenter_spec.rb'
+ - 'spec/presenters/ci/pipeline_artifacts/code_quality_mr_diff_presenter_spec.rb'
+ - 'spec/presenters/ci/pipeline_presenter_spec.rb'
+ - 'spec/presenters/ci/stage_presenter_spec.rb'
+ - 'spec/presenters/ci/trigger_presenter_spec.rb'
+ - '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/deployments/deployment_presenter_spec.rb'
+ - 'spec/presenters/event_presenter_spec.rb'
+ - 'spec/presenters/gitlab/blame_presenter_spec.rb'
+ - 'spec/presenters/group_clusterable_presenter_spec.rb'
+ - 'spec/presenters/instance_clusterable_presenter_spec.rb'
+ - 'spec/presenters/issue_presenter_spec.rb'
+ - 'spec/presenters/label_presenter_spec.rb'
+ - 'spec/presenters/merge_request_presenter_spec.rb'
+ - 'spec/presenters/milestone_presenter_spec.rb'
+ - 'spec/presenters/packages/composer/packages_presenter_spec.rb'
+ - 'spec/presenters/packages/conan/package_presenter_spec.rb'
+ - 'spec/presenters/packages/detail/package_presenter_spec.rb'
+ - 'spec/presenters/packages/helm/index_presenter_spec.rb'
+ - 'spec/presenters/packages/npm/package_presenter_spec.rb'
+ - 'spec/presenters/packages/nuget/package_metadata_presenter_spec.rb'
+ - 'spec/presenters/packages/nuget/packages_metadata_presenter_spec.rb'
+ - 'spec/presenters/packages/nuget/packages_versions_presenter_spec.rb'
+ - 'spec/presenters/packages/nuget/search_results_presenter_spec.rb'
+ - 'spec/presenters/packages/nuget/service_index_presenter_spec.rb'
+ - 'spec/presenters/packages/pypi/simple_index_presenter_spec.rb'
+ - 'spec/presenters/packages/pypi/simple_package_versions_presenter_spec.rb'
+ - 'spec/presenters/pages_domain_presenter_spec.rb'
+ - 'spec/presenters/project_clusterable_presenter_spec.rb'
+ - 'spec/presenters/project_hook_presenter_spec.rb'
+ - 'spec/presenters/project_presenter_spec.rb'
+ - 'spec/presenters/projects/import_export/project_export_presenter_spec.rb'
+ - 'spec/presenters/projects/security/configuration_presenter_spec.rb'
+ - 'spec/presenters/projects/settings/deploy_keys_presenter_spec.rb'
+ - 'spec/presenters/prometheus_alert_presenter_spec.rb'
+ - 'spec/presenters/release_presenter_spec.rb'
+ - 'spec/presenters/releases/link_presenter_spec.rb'
+ - 'spec/presenters/search_service_presenter_spec.rb'
+ - 'spec/presenters/service_hook_presenter_spec.rb'
+ - 'spec/presenters/snippet_blob_presenter_spec.rb'
+ - 'spec/presenters/snippet_presenter_spec.rb'
+ - 'spec/presenters/terraform/modules_presenter_spec.rb'
+ - 'spec/presenters/tree_entry_presenter_spec.rb'
+ - 'spec/presenters/user_presenter_spec.rb'
+ - 'spec/presenters/web_hook_log_presenter_spec.rb'
- 'spec/serializers/access_token_entity_base_spec.rb'
- 'spec/serializers/analytics_build_entity_spec.rb'
- 'spec/serializers/analytics_build_serializer_spec.rb'
@@ -192,7 +267,6 @@ RSpec/FactoryBot/AvoidCreate:
- 'spec/serializers/project_serializer_spec.rb'
- 'spec/serializers/prometheus_alert_entity_spec.rb'
- 'spec/serializers/release_serializer_spec.rb'
- - 'spec/serializers/remote_mirror_entity_spec.rb'
- 'spec/serializers/review_app_setup_entity_spec.rb'
- 'spec/serializers/runner_entity_spec.rb'
- 'spec/serializers/serverless/domain_entity_spec.rb'
diff --git a/.rubocop_todo/rspec/factory_bot/strategy_in_callback.yml b/.rubocop_todo/rspec/factory_bot/strategy_in_callback.yml
new file mode 100644
index 00000000000..456eca57804
--- /dev/null
+++ b/.rubocop_todo/rspec/factory_bot/strategy_in_callback.yml
@@ -0,0 +1,54 @@
+---
+RSpec/FactoryBot/StrategyInCallback:
+ Details: grace period
+ Exclude:
+ - 'ee/spec/factories/ci/builds.rb'
+ - 'ee/spec/factories/ci/pipelines.rb'
+ - 'ee/spec/factories/dast_scanner_profiles.rb'
+ - 'ee/spec/factories/description_version.rb'
+ - 'ee/spec/factories/elastic/reindexing_tasks.rb'
+ - 'ee/spec/factories/epic_issues.rb'
+ - 'ee/spec/factories/geo/design_registry.rb'
+ - 'ee/spec/factories/geo_nodes.rb'
+ - 'ee/spec/factories/groups.rb'
+ - 'ee/spec/factories/merge_requests.rb'
+ - 'ee/spec/factories/namespaces.rb'
+ - 'ee/spec/factories/projects.rb'
+ - 'ee/spec/factories/protected_environments.rb'
+ - 'ee/spec/factories/users.rb'
+ - 'ee/spec/factories/vulnerabilities.rb'
+ - 'ee/spec/factories/vulnerabilities/external_issue_links.rb'
+ - 'ee/spec/factories/vulnerabilities/findings.rb'
+ - 'ee/spec/factories/vulnerabilities/issue_links.rb'
+ - 'ee/spec/factories/work_items.rb'
+ - 'spec/factories/alert_management/alerts.rb'
+ - 'spec/factories/ci/builds.rb'
+ - 'spec/factories/ci/pipelines.rb'
+ - 'spec/factories/ci/processable.rb'
+ - 'spec/factories/ci/runner_namespaces.rb'
+ - 'spec/factories/ci/runner_projects.rb'
+ - 'spec/factories/ci/runners.rb'
+ - 'spec/factories/clusters/clusters.rb'
+ - 'spec/factories/commits.rb'
+ - 'spec/factories/container_expiration_policies.rb'
+ - 'spec/factories/design_management/designs.rb'
+ - 'spec/factories/design_management/versions.rb'
+ - 'spec/factories/environments.rb'
+ - 'spec/factories/group_members.rb'
+ - 'spec/factories/groups.rb'
+ - 'spec/factories/integrations.rb'
+ - 'spec/factories/issues.rb'
+ - 'spec/factories/merge_requests.rb'
+ - 'spec/factories/ml/candidates.rb'
+ - 'spec/factories/namespaces.rb'
+ - 'spec/factories/packages/dependency_links.rb'
+ - 'spec/factories/packages/package_files.rb'
+ - 'spec/factories/packages/packages.rb'
+ - 'spec/factories/pool_repositories.rb'
+ - 'spec/factories/project_members.rb'
+ - 'spec/factories/projects.rb'
+ - 'spec/factories/releases.rb'
+ - 'spec/factories/resource_label_events.rb'
+ - 'spec/factories/terraform/state.rb'
+ - 'spec/factories/users.rb'
+ - 'spec/factories/work_items/parent_links.rb'
diff --git a/.rubocop_todo/rspec/file_path.yml b/.rubocop_todo/rspec/file_path.yml
index 3cf0e969c34..8930b709bfd 100644
--- a/.rubocop_todo/rspec/file_path.yml
+++ b/.rubocop_todo/rspec/file_path.yml
@@ -1,6 +1,5 @@
---
RSpec/FilePath:
- Details: grace period
Exclude:
- 'ee/spec/frontend/fixtures/analytics/charts.rb'
- 'ee/spec/frontend/fixtures/analytics/devops_reports/devops_adoption/enabled_namespaces.rb'
@@ -65,3 +64,4 @@ RSpec/FilePath:
- 'spec/services/ci/create_pipeline_service/rate_limit_spec.rb'
- 'spec/services/ci/create_pipeline_service/rules_spec.rb'
- 'spec/services/ci/create_pipeline_service/tags_spec.rb'
+ - 'spec/services/ci/create_pipeline_service/variables_spec.rb'
diff --git a/.rubocop_todo/rspec/multiple_memoized_helpers.yml b/.rubocop_todo/rspec/multiple_memoized_helpers.yml
index 218ec3bb478..e939abd2886 100644
--- a/.rubocop_todo/rspec/multiple_memoized_helpers.yml
+++ b/.rubocop_todo/rspec/multiple_memoized_helpers.yml
@@ -1,6 +1,5 @@
---
RSpec/MultipleMemoizedHelpers:
- Details: grace period
Exclude:
- 'ee/spec/features/boards/swimlanes/epics_swimlanes_filtering_spec.rb'
- 'ee/spec/finders/epics_finder_spec.rb'
diff --git a/.rubocop_todo/rspec/scattered_let.yml b/.rubocop_todo/rspec/scattered_let.yml
index 61f1a09589f..9a272ec31cc 100644
--- a/.rubocop_todo/rspec/scattered_let.yml
+++ b/.rubocop_todo/rspec/scattered_let.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
RSpec/ScatteredLet:
- Details: grace period
Exclude:
- 'ee/spec/features/boards/user_visits_board_spec.rb'
- 'ee/spec/features/groups/group_roadmap_spec.rb'
diff --git a/.rubocop_todo/rspec/timecop_travel.yml b/.rubocop_todo/rspec/timecop_travel.yml
index a8ca3a5fad5..3a9ebc443fd 100644
--- a/.rubocop_todo/rspec/timecop_travel.yml
+++ b/.rubocop_todo/rspec/timecop_travel.yml
@@ -1,5 +1,4 @@
---
RSpec/TimecopTravel:
Exclude:
- - spec/workers/concerns/reenqueuer_spec.rb
- qa/spec/support/repeater_spec.rb
diff --git a/.rubocop_todo/style/accessor_grouping.yml b/.rubocop_todo/style/accessor_grouping.yml
index a2ba217dbcc..a4fae856953 100644
--- a/.rubocop_todo/style/accessor_grouping.yml
+++ b/.rubocop_todo/style/accessor_grouping.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
Style/AccessorGrouping:
- Details: grace period
Exclude:
- 'app/finders/template_finder.rb'
- 'app/models/commit.rb'
diff --git a/.rubocop_todo/style/bare_percent_literals.yml b/.rubocop_todo/style/bare_percent_literals.yml
index 1a155e3cca0..cb40669ca02 100644
--- a/.rubocop_todo/style/bare_percent_literals.yml
+++ b/.rubocop_todo/style/bare_percent_literals.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
Style/BarePercentLiterals:
- Details: grace period
Exclude:
- 'app/models/commit.rb'
- 'app/models/concerns/storage/legacy_namespace.rb'
diff --git a/.rubocop_todo/style/case_like_if.yml b/.rubocop_todo/style/case_like_if.yml
deleted file mode 100644
index 61f2e6bc238..00000000000
--- a/.rubocop_todo/style/case_like_if.yml
+++ /dev/null
@@ -1,63 +0,0 @@
----
-# Cop supports --auto-correct.
-Style/CaseLikeIf:
- Details: grace period
- Exclude:
- - 'app/controllers/concerns/issuable_actions.rb'
- - 'app/controllers/groups/dependency_proxy/application_controller.rb'
- - 'app/controllers/projects/labels_controller.rb'
- - 'app/graphql/types/ci/job_need_union.rb'
- - 'app/helpers/avatars_helper.rb'
- - 'app/helpers/broadcast_messages_helper.rb'
- - 'app/helpers/issues_helper.rb'
- - 'app/helpers/routing/pseudonymization_helper.rb'
- - 'app/helpers/todos_helper.rb'
- - 'app/models/integrations/jira.rb'
- - 'app/models/members/member_task.rb'
- - 'app/models/namespace.rb'
- - 'app/models/packages/go/module_version.rb'
- - 'app/serializers/group_child_serializer.rb'
- - 'app/services/google_cloud/generate_pipeline_service.rb'
- - 'app/services/issuable/bulk_update_service.rb'
- - 'app/services/todo_service.rb'
- - 'app/services/user_project_access_changed_service.rb'
- - 'ee/app/controllers/concerns/credentials_inventory_actions.rb'
- - 'ee/app/finders/ee/notes_finder.rb'
- - 'ee/app/finders/security/scan_execution_policies_finder.rb'
- - 'ee/app/finders/security/training_providers/secure_code_warrior_url_finder.rb'
- - 'ee/app/helpers/ee/branches_helper.rb'
- - 'ee/app/services/epics/tree_reorder_service.rb'
- - 'ee/app/services/merge_request_approval_settings/update_service.rb'
- - 'ee/lib/gitlab/alert_management/alert_payload_field_extractor.rb'
- - 'ee/spec/config/metrics/every_metric_definition_spec.rb'
- - 'ee/spec/features/boards/user_adds_lists_to_board_spec.rb'
- - 'ee/spec/features/issues/user_bulk_edits_issues_spec.rb'
- - 'ee/spec/features/projects/custom_projects_template_spec.rb'
- - 'ee/spec/support/matchers/ee/epic_aggregate_matchers.rb'
- - 'lib/api/helpers/label_helpers.rb'
- - 'lib/gitlab/ci/ansi2html.rb'
- - 'lib/gitlab/ci/ansi2json/converter.rb'
- - 'lib/gitlab/ci/build/image.rb'
- - 'lib/gitlab/identifier.rb'
- - 'lib/gitlab/issues/rebalancing/state.rb'
- - 'lib/gitlab/pagination/gitaly_keyset_pager.rb'
- - 'lib/gitlab/utils.rb'
- - 'lib/gitlab/utils/strong_memoize.rb'
- - 'qa/qa/git/repository.rb'
- - 'qa/qa/scenario/bootable.rb'
- - 'spec/features/boards/user_adds_lists_to_board_spec.rb'
- - 'spec/lib/gitlab/auth/auth_finders_spec.rb'
- - 'spec/lib/gitlab/database/load_balancing_spec.rb'
- - 'spec/lib/omni_auth/strategies/jwt_spec.rb'
- - 'spec/models/concerns/sha_attribute_spec.rb'
- - 'spec/models/preloaders/labels_preloader_spec.rb'
- - 'spec/requests/api/personal_access_tokens_spec.rb'
- - 'spec/requests/api/rubygem_packages_spec.rb'
- - 'spec/requests/api/terraform/modules/v1/packages_spec.rb'
- - 'spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb'
- - 'spec/services/resource_events/change_state_service_spec.rb'
- - 'spec/support/helpers/filter_spec_helper.rb'
- - 'spec/support/shared_examples/metrics/active_record_subscriber_shared_examples.rb'
- - 'spec/support/shared_examples/requests/api/notes_shared_examples.rb'
- - 'spec/support/shared_examples/uploaders/object_storage_shared_examples.rb'
- - 'spec/workers/loose_foreign_keys/cleanup_worker_spec.rb'
diff --git a/.rubocop_todo/style/empty_method.yml b/.rubocop_todo/style/empty_method.yml
index 7fbec98ead5..300d8678719 100644
--- a/.rubocop_todo/style/empty_method.yml
+++ b/.rubocop_todo/style/empty_method.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
Style/EmptyMethod:
- Details: grace period
Exclude:
- 'app/controllers/admin/application_settings/appearances_controller.rb'
- 'app/controllers/admin/applications_controller.rb'
diff --git a/.rubocop_todo/style/explicit_block_argument.yml b/.rubocop_todo/style/explicit_block_argument.yml
index 346be201322..20e8c976fb7 100644
--- a/.rubocop_todo/style/explicit_block_argument.yml
+++ b/.rubocop_todo/style/explicit_block_argument.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
Style/ExplicitBlockArgument:
- Details: grace period
Exclude:
- 'app/controllers/admin/background_migrations_controller.rb'
- 'app/controllers/admin/batched_jobs_controller.rb'
diff --git a/.rubocop_todo/style/guard_clause.yml b/.rubocop_todo/style/guard_clause.yml
index a4ae491b902..f46f8c8f4f6 100644
--- a/.rubocop_todo/style/guard_clause.yml
+++ b/.rubocop_todo/style/guard_clause.yml
@@ -693,7 +693,6 @@ Style/GuardClause:
- 'qa/qa/specs/helpers/feature_flag.rb'
- 'qa/qa/vendor/jenkins/job.rb'
- 'rubocop/cop/api/grape_array_missing_coerce.rb'
- - 'rubocop/cop/gitlab/duplicate_spec_location.rb'
- 'rubocop/cop/gitlab/event_store_subscriber.rb'
- 'rubocop/cop/gitlab/finder_with_find_by.rb'
- 'rubocop/cop/gitlab/keys_first_and_values_first.rb'
@@ -717,7 +716,6 @@ Style/GuardClause:
- 'spec/support/capybara.rb'
- 'spec/support/database/prevent_cross_joins.rb'
- 'spec/support/helpers/access_matchers_helpers.rb'
- - 'spec/support/helpers/bare_repo_operations.rb'
- 'spec/support/helpers/capybara_helpers.rb'
- 'spec/support/helpers/dropzone_helper.rb'
- 'spec/support/helpers/fake_blob_helpers.rb'
diff --git a/.rubocop_todo/style/if_unless_modifier.yml b/.rubocop_todo/style/if_unless_modifier.yml
index 8e295c68623..fc05a8bc163 100644
--- a/.rubocop_todo/style/if_unless_modifier.yml
+++ b/.rubocop_todo/style/if_unless_modifier.yml
@@ -309,7 +309,6 @@ Style/IfUnlessModifier:
- 'app/services/issues/update_service.rb'
- 'app/services/lfs/lock_file_service.rb'
- 'app/services/members/destroy_service.rb'
- - 'app/services/members/update_service.rb'
- 'app/services/merge_requests/add_context_service.rb'
- 'app/services/merge_requests/base_service.rb'
- 'app/services/merge_requests/build_service.rb'
@@ -743,7 +742,6 @@ Style/IfUnlessModifier:
- 'ee/spec/support/http_io/http_io_helpers.rb'
- 'ee/spec/support/shared_examples/requests/api/graphql/geo/registries_shared_examples.rb'
- 'ee/spec/views/layouts/header/help_dropdown/_cross_stage_fdm.html.haml_spec.rb'
- - 'ee/spec/views/shared/access_tokens/_table.html.haml_spec.rb'
- 'ee/spec/workers/elastic/migration_worker_spec.rb'
- 'lib/api/api_guard.rb'
- 'lib/api/boards_responses.rb'
@@ -1202,7 +1200,6 @@ Style/IfUnlessModifier:
- 'spec/views/groups/edit.html.haml_spec.rb'
- 'spec/views/profiles/keys/_key.html.haml_spec.rb'
- 'spec/views/projects/edit.html.haml_spec.rb'
- - 'spec/views/shared/access_tokens/_table.html.haml_spec.rb'
- 'spec/workers/analytics/usage_trends/counter_job_worker_spec.rb'
- 'tooling/danger/product_intelligence.rb'
- 'tooling/lib/tooling/find_codeowners.rb'
diff --git a/.rubocop_todo/style/keyword_parameters_order.yml b/.rubocop_todo/style/keyword_parameters_order.yml
index 3521f295cc1..ca6cb416b93 100644
--- a/.rubocop_todo/style/keyword_parameters_order.yml
+++ b/.rubocop_todo/style/keyword_parameters_order.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
Style/KeywordParametersOrder:
- Details: grace period
Exclude:
- 'app/controllers/concerns/product_analytics_tracking.rb'
- 'app/finders/group_descendants_finder.rb'
@@ -50,7 +49,6 @@ Style/KeywordParametersOrder:
- 'qa/qa/specs/features/ee/browser_ui/3_create/repository/file_locking_spec.rb'
- 'qa/qa/specs/features/ee/browser_ui/3_create/repository/push_rules_spec.rb'
- 'qa/spec/runtime/env_spec.rb'
- - 'spec/features/projects/branches_spec.rb'
- 'spec/graphql/types/ci/pipeline_counts_type_spec.rb'
- 'spec/lib/gitlab/background_migration/populate_vulnerability_reads_spec.rb'
- 'spec/lib/gitlab/background_migration/recalculate_vulnerabilities_occurrences_uuid_spec.rb'
diff --git a/.rubocop_todo/style/lambda.yml b/.rubocop_todo/style/lambda.yml
index f733af601ec..f37c2c4967e 100644
--- a/.rubocop_todo/style/lambda.yml
+++ b/.rubocop_todo/style/lambda.yml
@@ -1,273 +1,82 @@
---
-# Cop supports --auto-correct.
+# Cop supports --autocorrect.
Style/Lambda:
- # Offense count: 653
- # Temporarily disabled due to too many offenses
- Enabled: false
+ Details: grace period
Exclude:
- - 'app/controllers/concerns/notes_actions.rb'
- - 'app/controllers/concerns/spammable_actions/captcha_check/rest_api_actions_support.rb'
- - 'app/controllers/projects/issues_controller.rb'
- - 'app/controllers/search_controller.rb'
- - 'app/graphql/mutations/container_repositories/destroy_tags.rb'
- - 'app/graphql/mutations/design_management/delete.rb'
- - 'app/graphql/types/permission_types/base_permission_type.rb'
- - 'app/models/analytics/cycle_analytics/issue_stage_event.rb'
- - 'app/models/analytics/cycle_analytics/merge_request_stage_event.rb'
- - 'app/models/bulk_imports/tracker.rb'
- - 'app/models/ci/build.rb'
- - 'app/models/ci/deleted_object.rb'
- - 'app/models/ci/instance_variable.rb'
- - 'app/models/ci/job_artifact.rb'
- - 'app/models/ci/namespace_mirror.rb'
- - 'app/models/ci/pending_build.rb'
- - 'app/models/ci/pipeline.rb'
- - 'app/models/ci/processable.rb'
- - 'app/models/ci/runner.rb'
- - 'app/models/clusters/cluster.rb'
- - 'app/models/clusters/concerns/application_status.rb'
- - 'app/models/commit_status.rb'
- - 'app/models/concerns/analytics/cycle_analytics/stage_event_model.rb'
- - 'app/models/concerns/approvable_base.rb'
- - 'app/models/concerns/atomic_internal_id.rb'
- - 'app/models/concerns/ci/has_status.rb'
- - 'app/models/concerns/clusters/agents/authorization_config_scopes.rb'
- - 'app/models/concerns/has_environment_scope.rb'
- - 'app/models/concerns/has_wiki_page_meta_attributes.rb'
- - 'app/models/concerns/id_in_ordered.rb'
- - 'app/models/concerns/integrations/has_issue_tracker_fields.rb'
- - 'app/models/concerns/issuable.rb'
- - 'app/models/concerns/issue_resource_event.rb'
- - 'app/models/concerns/milestoneable.rb'
- - 'app/models/concerns/mirror_authentication.rb'
- - 'app/models/concerns/packages/debian/component_file.rb'
- - 'app/models/concerns/reactive_caching.rb'
- - 'app/models/concerns/timebox.rb'
- - 'app/models/container_repository.rb'
- - 'app/models/custom_emoji.rb'
- - 'app/models/deployment.rb'
- - 'app/models/design_management/action.rb'
- - 'app/models/design_management/design.rb'
- - 'app/models/design_management/version.rb'
- - 'app/models/environment.rb'
- - 'app/models/event.rb'
- - 'app/models/group.rb'
- - 'app/models/group_deploy_key.rb'
- - 'app/models/group_group_link.rb'
- - 'app/models/hooks/web_hook.rb'
- - 'app/models/identity.rb'
- - 'app/models/import_failure.rb'
- - 'app/models/integrations/zentao_tracker_data.rb'
- - 'app/models/internal_id.rb'
- - 'app/models/issue.rb'
- - 'app/models/issue/metrics.rb'
- - 'app/models/jira_connect_installation.rb'
- - 'app/models/label.rb'
- - 'app/models/label_link.rb'
- - 'app/models/loose_foreign_keys/deleted_record.rb'
- - 'app/models/member.rb'
- - 'app/models/members/project_member.rb'
- - 'app/models/merge_request.rb'
- - 'app/models/merge_request/cleanup_schedule.rb'
- - 'app/models/merge_request_diff.rb'
- - 'app/models/merge_request_diff_file.rb'
- - 'app/models/merge_requests_closing_issues.rb'
- - 'app/models/milestone.rb'
- - 'app/models/namespace.rb'
- - 'app/models/note.rb'
- - 'app/models/note_diff_file.rb'
- - 'app/models/notification_setting.rb'
- - 'app/models/onboarding/progress.rb'
- - 'app/models/operations/feature_flags/user_list.rb'
- - 'app/models/packages/package.rb'
- - 'app/models/packages/package_file.rb'
- - 'app/models/pages_domain.rb'
- - 'app/models/product_analytics_event.rb'
- - 'app/models/programming_language.rb'
- - 'app/models/project.rb'
+ - 'app/controllers/concerns/project_unauthorized.rb'
+ - 'app/controllers/profiles/two_factor_auths_controller.rb'
+ - 'app/models/concerns/featurable.rb'
- 'app/models/project_feature.rb'
- - 'app/models/project_feature_usage.rb'
- - 'app/models/projects/topic.rb'
- - 'app/models/prometheus_alert_event.rb'
- - 'app/models/raw_usage_data.rb'
- - 'app/models/redirect_route.rb'
- - 'app/models/release.rb'
- - 'app/models/remote_mirror.rb'
- - 'app/models/repository_language.rb'
- - 'app/models/snippet.rb'
- - 'app/models/timelog.rb'
- - 'app/models/todo.rb'
- - 'app/models/user.rb'
- - 'app/models/users/in_product_marketing_email.rb'
- 'app/serializers/ci/daily_build_group_report_result_entity.rb'
- 'app/serializers/group_child_entity.rb'
- 'app/serializers/issuable_sidebar_basic_entity.rb'
- 'app/serializers/merge_request_sidebar_basic_entity.rb'
- - 'app/services/issues/referenced_merge_requests_service.rb'
- - 'config/initializers/deprecations.rb'
- - 'config/initializers/rspec_profiling.rb'
+ - 'config/application.rb'
+ - 'config/initializers/0_license.rb'
+ - 'config/initializers/0_log_deprecations.rb'
+ - 'config/initializers/action_cable.rb'
+ - 'config/initializers/gitlab_experiment.rb'
+ - 'config/initializers/lograge.rb'
+ - 'config/routes.rb'
- 'config/routes/dashboard.rb'
- 'config/routes/group.rb'
- 'config/routes/issues.rb'
- - 'db/post_migrate/20210303121224_update_gitlab_subscriptions_start_at_post_eoa.rb'
- - 'db/post_migrate/20210513155546_backfill_nuget_temporary_packages_to_processing_status.rb'
- - 'db/post_migrate/20210823132600_remove_duplicate_dast_site_tokens.rb'
- - 'db/post_migrate/20220425121435_backfill_integrations_enable_ssl_verification.rb'
- - 'ee/app/controllers/groups/analytics/productivity_analytics_controller.rb'
- - 'ee/app/models/analytics/devops_adoption/enabled_namespace.rb'
- - 'ee/app/models/analytics/devops_adoption/snapshot.rb'
- - 'ee/app/models/app_sec/fuzzing/coverage/corpus.rb'
- - 'ee/app/models/approval_merge_request_rule.rb'
- - 'ee/app/models/boards/epic_board_position.rb'
- - 'ee/app/models/boards/epic_user_preference.rb'
- - 'ee/app/models/ci/minutes/project_monthly_usage.rb'
- - 'ee/app/models/concerns/ee/protected_ref.rb'
- - 'ee/app/models/concerns/geo/replicable_model.rb'
- - 'ee/app/models/concerns/issue_widgets/acts_like_requirement.rb'
- - 'ee/app/models/dast/profile.rb'
- - 'ee/app/models/dast_site_validation.rb'
- - 'ee/app/models/dora/daily_metrics.rb'
- - 'ee/app/models/ee/ci/build.rb'
- - 'ee/app/models/ee/ci/daily_build_group_report_result.rb'
- - 'ee/app/models/ee/ci/job_artifact.rb'
- - 'ee/app/models/ee/ci/pipeline.rb'
- - 'ee/app/models/ee/environment.rb'
- - 'ee/app/models/ee/epic.rb'
- - 'ee/app/models/ee/group.rb'
- - 'ee/app/models/ee/group_member.rb'
- - 'ee/app/models/ee/identity.rb'
- - 'ee/app/models/ee/issue.rb'
- - 'ee/app/models/ee/iteration.rb'
- - 'ee/app/models/ee/label.rb'
- - 'ee/app/models/ee/member.rb'
- - 'ee/app/models/ee/merge_request.rb'
- - 'ee/app/models/ee/namespace.rb'
- - 'ee/app/models/ee/namespace_ci_cd_setting.rb'
- - 'ee/app/models/ee/note.rb'
- - 'ee/app/models/ee/project.rb'
- - 'ee/app/models/ee/user.rb'
- - 'ee/app/models/ee/vulnerability.rb'
- - 'ee/app/models/gitlab_subscription.rb'
- - 'ee/app/models/incident_management/oncall_rotation.rb'
- - 'ee/app/models/incident_management/oncall_shift.rb'
- - 'ee/app/models/iterations/cadence.rb'
- - 'ee/app/models/merge_request_block.rb'
- - 'ee/app/models/merge_requests/external_status_check.rb'
- - 'ee/app/models/merge_train.rb'
- - 'ee/app/models/protected_environment.rb'
- - 'ee/app/models/requirements_management/requirement.rb'
- - 'ee/app/models/security/finding.rb'
- - 'ee/app/models/security/orchestration_policy_configuration.rb'
- - 'ee/app/models/security/orchestration_policy_rule_schedule.rb'
- - 'ee/app/models/security/scan.rb'
- - 'ee/app/models/security/training_provider.rb'
- - 'ee/app/models/software_license_policy.rb'
- - 'ee/app/models/vulnerabilities/feedback.rb'
- - 'ee/app/models/vulnerabilities/finding.rb'
- - 'ee/app/models/vulnerabilities/historical_statistic.rb'
- - 'ee/app/models/vulnerabilities/read.rb'
- - 'ee/app/models/vulnerabilities/scanner.rb'
+ - 'ee/app/controllers/concerns/ee/routable_actions/sso_enforcement_redirect.rb'
- 'ee/app/serializers/ee/group_child_entity.rb'
- - 'ee/lib/ee/api/entities/application_setting.rb'
- - 'ee/lib/ee/api/entities/geo_node_status.rb'
- - 'ee/lib/ee/api/entities/group.rb'
+ - 'ee/app/services/ee/issues/export_csv_service.rb'
+ - 'ee/lib/ee/api/entities/group_detail.rb'
- 'ee/lib/ee/api/entities/group_push_rule.rb'
- - 'ee/lib/ee/api/entities/project.rb'
- - 'ee/lib/ee/api/entities/vulnerability_issue_link.rb'
- - 'ee/lib/ee/gitlab/background_migration/populate_resolved_on_default_branch_column.rb'
+ - 'ee/lib/ee/banzai/filter/sanitization_filter.rb'
+ - 'ee/lib/ee/gitlab/checks/diff_check.rb'
+ - 'ee/lib/elastic/latest/application_class_proxy.rb'
- 'ee/lib/gem_extensions/elasticsearch/model/adapter/active_record/importing.rb'
- - 'ee/spec/migrations/backfill_delayed_group_deletion_spec.rb'
- - 'ee/spec/migrations/remove_schedule_and_status_null_constraints_from_pending_escalations_alert_spec.rb'
+ - 'ee/spec/elastic_integration/global_search_spec.rb'
+ - 'ee/spec/lib/gitlab/geo/event_gap_tracking_spec.rb'
- 'ee/spec/services/ee/groups/autocomplete_service_spec.rb'
- - 'ee/spec/services/ee/notes/create_service_spec.rb'
+ - 'ee/spec/support/helpers/elasticsearch_helpers.rb'
- 'ee/spec/support/shared_examples/lib/gitlab/middleware/maintenance_mode_gitlab_ee_instance_shared_examples.rb'
- 'ee/spec/support/shared_examples/lib/gitlab/middleware/read_only_gitlab_ee_instance_shared_examples.rb'
- - 'lib/api/ci/jobs.rb'
- - 'lib/api/ci/pipelines.rb'
- - 'lib/api/entities/group_detail.rb'
- - 'lib/api/entities/issue.rb'
- 'lib/api/entities/label.rb'
- - 'lib/api/entities/merge_request.rb'
- 'lib/api/entities/project.rb'
- 'lib/api/entities/project_export_status.rb'
- - 'lib/api/feature_flags_user_lists.rb'
- - 'lib/container_registry/base_client.rb'
- - 'lib/container_registry/client.rb'
- - 'lib/csv_builder.rb'
- - 'lib/event_filter.rb'
- - 'lib/gitlab/background_migration/backfill_ci_namespace_mirrors.rb'
- - 'lib/gitlab/background_migration/backfill_ci_project_mirrors.rb'
- - 'lib/gitlab/background_migration/backfill_ci_queuing_tables.rb'
- - 'lib/gitlab/background_migration/fix_projects_without_prometheus_service.rb'
- - 'lib/gitlab/background_migration/populate_latest_pipeline_ids.rb'
- - 'lib/gitlab/ci/config/entry/includes.rb'
- - 'lib/gitlab/ci/config/entry/trigger.rb'
- - 'lib/gitlab/config/entry/validatable.rb'
- - 'lib/gitlab/database/background_migration/batched_migration.rb'
- - 'lib/gitlab/database/background_migration_job.rb'
- - 'lib/gitlab/database/postgres_foreign_key.rb'
- - 'lib/gitlab/database/postgres_index.rb'
- - 'lib/gitlab/database/postgres_partition.rb'
- - 'lib/gitlab/database/postgres_partitioned_table.rb'
- - 'lib/gitlab/gl_repository.rb'
- - 'lib/gitlab/import_export/import_failure_service.rb'
- - 'lib/gitlab/merge_requests/commit_message_generator.rb'
- - 'lib/gitlab/seeder.rb'
+ - 'lib/api/validations/types/comma_separated_to_array.rb'
+ - 'lib/api/validations/types/comma_separated_to_integer_array.rb'
+ - 'lib/api/validations/types/hash_of_integer_values.rb'
+ - 'lib/api/validations/validators/check_assignees_count.rb'
+ - 'lib/banzai/filter/ascii_doc_sanitization_filter.rb'
+ - 'lib/banzai/filter/base_sanitization_filter.rb'
+ - 'lib/banzai/filter/sanitization_filter.rb'
+ - 'lib/gitlab/action_cable/request_store_callbacks.rb'
+ - 'lib/gitlab/checks/diff_check.rb'
+ - 'lib/gitlab/database/load_balancing/action_cable_callbacks.rb'
+ - 'lib/gitlab/memory/watchdog/configurator.rb'
+ - 'lib/gitlab/middleware/rack_multipart_tempfile_factory.rb'
+ - 'lib/gitlab/omniauth_initializer.rb'
+ - 'lib/gitlab/prometheus/queries/query_additional_metrics.rb'
+ - 'lib/gitlab/rack_attack.rb'
- 'lib/gitlab/sidekiq_config/worker_matcher.rb'
- - 'lib/gitlab/sidekiq_signals.rb'
- - 'lib/gitlab/utils/measuring.rb'
- - 'lib/gitlab/visibility_level.rb'
- - 'rubocop/cop/rspec/modify_sidekiq_middleware.rb'
- - 'rubocop/cop/rspec/timecop_freeze.rb'
- - 'rubocop/cop/rspec/timecop_travel.rb'
+ - 'lib/gitlab/sidekiq_middleware.rb'
+ - 'lib/gitlab/utils/usage_data.rb'
+ - 'qa/qa/page/base.rb'
+ - 'qa/qa/runtime/allure_report.rb'
+ - 'qa/qa/specs/features/api/1_manage/import/import_large_github_repo_spec.rb'
+ - 'qa/qa/support/api.rb'
+ - 'rubocop/cop/inject_enterprise_edition_module.rb'
+ - 'rubocop/cop/rspec/have_gitlab_http_status.rb'
- 'spec/controllers/concerns/routable_actions_spec.rb'
- - 'spec/deprecation_toolkit_env.rb'
- - 'spec/factories/design_management/designs.rb'
- - 'spec/features/projects/issues/design_management/user_views_designs_with_svg_xss_spec.rb'
- - 'spec/graphql/resolvers/concerns/resolves_groups_spec.rb'
+ - 'spec/features/groups/dependency_proxy_for_containers_spec.rb'
+ - 'spec/graphql/types/base_object_spec.rb'
+ - 'spec/lib/gitlab/action_cable/request_store_callbacks_spec.rb'
- 'spec/lib/gitlab/cross_project_access/class_methods_spec.rb'
- - 'spec/lib/gitlab/database/consistency_spec.rb'
- - 'spec/lib/gitlab/database/dynamic_model_helpers_spec.rb'
- 'spec/lib/gitlab/database/load_balancing/action_cable_callbacks_spec.rb'
- - 'spec/lib/gitlab/database/load_balancing_spec.rb'
- - 'spec/lib/gitlab/database/migration_helpers/restrict_gitlab_schema_spec.rb'
- - 'spec/lib/gitlab/database/migration_helpers_spec.rb'
- - 'spec/lib/gitlab/database/query_analyzers/gitlab_schemas_metrics_spec.rb'
+ - 'spec/lib/gitlab/graphql/tracers/application_context_tracer_spec.rb'
- 'spec/lib/gitlab/graphql/tracers/timer_tracer_spec.rb'
- - 'spec/lib/gitlab/import_export/members_mapper_spec.rb'
- - 'spec/lib/gitlab/sidekiq_middleware/size_limiter/validator_spec.rb'
- - 'spec/migrations/20210722150102_operations_feature_flags_correct_flexible_rollout_values_spec.rb'
- - 'spec/migrations/20210804150320_create_base_work_item_types_spec.rb'
- - 'spec/migrations/20210819145000_drop_temporary_columns_and_triggers_for_ci_builds_runner_session_spec.rb'
- - 'spec/migrations/20210831203408_upsert_base_work_item_types_spec.rb'
- - 'spec/migrations/20210902144144_drop_temporary_columns_and_triggers_for_ci_build_needs_spec.rb'
- - 'spec/migrations/20210906100316_drop_temporary_columns_and_triggers_for_ci_build_trace_chunks_spec.rb'
- - 'spec/migrations/20210906130643_drop_temporary_columns_and_triggers_for_taggings_spec.rb'
- - 'spec/migrations/20210907013944_cleanup_bigint_conversion_for_ci_builds_metadata_spec.rb'
- - 'spec/migrations/20210915022415_cleanup_bigint_conversion_for_ci_builds_spec.rb'
- - 'spec/migrations/20210922021816_drop_int4_columns_for_ci_job_artifacts_spec.rb'
- - 'spec/migrations/20210922025631_drop_int4_column_for_ci_sources_pipelines_spec.rb'
- - 'spec/migrations/20210922082019_drop_int4_column_for_events_spec.rb'
- - 'spec/migrations/20210922091402_drop_int4_column_for_push_event_payloads_spec.rb'
- - 'spec/migrations/20211126115449_encrypt_static_objects_external_storage_auth_token_spec.rb'
- - 'spec/migrations/20211203091642_add_index_to_projects_on_marked_for_deletion_at_spec.rb'
- - 'spec/migrations/20220120094340_drop_position_from_security_findings_spec.rb'
- - 'spec/migrations/20220128155814_fix_approval_rules_code_owners_rule_type_index_spec.rb'
- - 'spec/migrations/20220305223212_add_security_training_providers_spec.rb'
- - 'spec/migrations/20220505174658_update_index_on_alerts_to_exclude_null_fingerprints_spec.rb'
- - 'spec/migrations/generate_customers_dot_jwt_signing_key_spec.rb'
- - 'spec/migrations/insert_ci_daily_pipeline_schedule_triggers_plan_limits_spec.rb'
- - 'spec/migrations/recreate_index_security_ci_builds_on_name_and_id_parser_features_spec.rb'
- - 'spec/migrations/recreate_index_security_ci_builds_on_name_and_id_parser_with_new_features_spec.rb'
- - 'spec/migrations/remove_schedule_and_status_from_pending_alert_escalations_spec.rb'
- - 'spec/models/ability_spec.rb'
- - 'spec/models/broadcast_message_spec.rb'
- - 'spec/models/concerns/participable_spec.rb'
+ - 'spec/lib/gitlab/middleware/rack_multipart_tempfile_factory_spec.rb'
+ - 'spec/lib/gitlab/path_regex_spec.rb'
- 'spec/services/groups/autocomplete_service_spec.rb'
- - 'spec/services/notes/create_service_spec.rb'
+ - 'spec/services/issues/referenced_merge_requests_service_spec.rb'
- 'spec/services/projects/autocomplete_service_spec.rb'
- 'spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb'
- 'spec/support/helpers/email_helpers.rb'
+ - 'spec/support/helpers/reference_parser_helpers.rb'
- 'spec/support/shared_examples/lib/gitlab/middleware/read_only_gitlab_instance_shared_examples.rb'
- - 'spec/support/shared_examples/quick_actions/issuable/issuable_quick_actions_shared_examples.rb'
- - 'spec/workers/process_commit_worker_spec.rb'
diff --git a/.rubocop_todo/style/next.yml b/.rubocop_todo/style/next.yml
index 9570bd7b036..295aa2f6878 100644
--- a/.rubocop_todo/style/next.yml
+++ b/.rubocop_todo/style/next.yml
@@ -2,32 +2,4 @@
# Cop supports --auto-correct.
Style/Next:
Exclude:
- - 'app/models/concerns/integrations/slack_mattermost_notifier.rb'
- - 'app/validators/nested_attributes_duplicates_validator.rb'
- - 'ee/app/services/security/ingestion/tasks/update_vulnerability_uuids.rb'
- - 'ee/db/fixtures/development/20_vulnerabilities.rb'
- - 'ee/lib/ee/audit/protected_branches_changes_auditor.rb'
- - 'ee/lib/gitlab/elastic/search_results.rb'
- - 'ee/lib/system_check/geo/authorized_keys_check.rb'
- - 'lib/backup/manager.rb'
- - 'lib/banzai/filter/external_link_filter.rb'
- - 'lib/banzai/filter/footnote_filter.rb'
- - 'lib/banzai/filter/kroki_filter.rb'
- - 'lib/banzai/filter/math_filter.rb'
- - 'lib/banzai/filter/plantuml_filter.rb'
- - 'lib/banzai/filter/table_of_contents_filter.rb'
- - 'lib/gitlab/background_migration/encrypt_static_object_token.rb'
- - 'lib/gitlab/database.rb'
- 'lib/gitlab/fogbugz_import/importer.rb'
- - 'lib/gitlab/gitaly_client/repository_service.rb'
- - 'lib/gitlab/import_export/attributes_permitter.rb'
- - 'lib/gitlab/import_export/base/relation_object_saver.rb'
- - 'lib/gitlab/metrics/samplers/base_sampler.rb'
- - 'lib/gitlab/pagination/keyset/in_operator_optimization/strategies/record_loader_strategy.rb'
- - 'lib/gitlab/reference_extractor.rb'
- - 'lib/tasks/gitlab/assets.rake'
- - 'lib/tasks/gitlab/db/validate_config.rake'
- - 'scripts/perf/query_limiting_report.rb'
- - 'scripts/qa/quarantine-types-check'
- - 'spec/lib/gitlab/import_export/import_test_coverage_spec.rb'
- - 'spec/presenters/packages/npm/package_presenter_spec.rb'
diff --git a/.rubocop_todo/style/numeric_literal_prefix.yml b/.rubocop_todo/style/numeric_literal_prefix.yml
index 5de15180438..4e8b608e424 100644
--- a/.rubocop_todo/style/numeric_literal_prefix.yml
+++ b/.rubocop_todo/style/numeric_literal_prefix.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
Style/NumericLiteralPrefix:
- Details: grace period
Exclude:
- 'app/models/container_repository.rb'
- 'app/services/packages/debian/generate_distribution_key_service.rb'
diff --git a/.rubocop_todo/style/percent_literal_delimiters.yml b/.rubocop_todo/style/percent_literal_delimiters.yml
index 472a722ed22..bac2e807053 100644
--- a/.rubocop_todo/style/percent_literal_delimiters.yml
+++ b/.rubocop_todo/style/percent_literal_delimiters.yml
@@ -696,7 +696,6 @@ Style/PercentLiteralDelimiters:
- 'spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb'
- 'spec/features/projects/active_tabs_spec.rb'
- 'spec/features/projects/artifacts/user_downloads_artifacts_spec.rb'
- - 'spec/features/projects/branches_spec.rb'
- 'spec/features/projects/environments/environment_spec.rb'
- 'spec/features/projects/integrations/user_activates_jira_spec.rb'
- 'spec/features/projects/jobs_spec.rb'
diff --git a/.rubocop_todo/style/redundant_begin.yml b/.rubocop_todo/style/redundant_begin.yml
index e96cdb26b08..d2851de201b 100644
--- a/.rubocop_todo/style/redundant_begin.yml
+++ b/.rubocop_todo/style/redundant_begin.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
Style/RedundantBegin:
- Details: grace period
Exclude:
- 'app/controllers/concerns/membership_actions.rb'
- 'app/controllers/concerns/metrics_dashboard.rb'
diff --git a/.rubocop_todo/style/redundant_interpolation.yml b/.rubocop_todo/style/redundant_interpolation.yml
index 3747312f2c4..ca7e01ffa61 100644
--- a/.rubocop_todo/style/redundant_interpolation.yml
+++ b/.rubocop_todo/style/redundant_interpolation.yml
@@ -94,83 +94,4 @@ Style/RedundantInterpolation:
- 'qa/qa/tools/generate_perf_testdata.rb'
- 'scripts/perf/gc/print_gc_stats.rb'
- 'scripts/qa/testcases-check'
- - 'spec/controllers/admin/integrations_controller_spec.rb'
- - 'spec/features/commits_spec.rb'
- - 'spec/features/issues/user_edits_issue_spec.rb'
- - 'spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb'
- - 'spec/features/merge_request/user_sees_deployment_widget_spec.rb'
- - 'spec/features/one_trust_spec.rb'
- - 'spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb'
- - 'spec/features/projects/jobs/user_browses_jobs_spec.rb'
- - 'spec/graphql/resolvers/container_repositories_resolver_spec.rb'
- - 'spec/helpers/environments_helper_spec.rb'
- - 'spec/helpers/snippets_helper_spec.rb'
- - 'spec/lib/api/helpers/packages/dependency_proxy_helpers_spec.rb'
- - 'spec/lib/api/validations/validators/git_ref_spec.rb'
- - 'spec/lib/api/validations/validators/limit_spec.rb'
- - 'spec/lib/backup/database_backup_error_spec.rb'
- - 'spec/lib/backup/file_backup_error_spec.rb'
- - 'spec/lib/banzai/filter/autolink_filter_spec.rb'
- - 'spec/lib/banzai/filter/issuable_reference_expansion_filter_spec.rb'
- - 'spec/lib/banzai/filter/references/alert_reference_filter_spec.rb'
- - 'spec/lib/banzai/filter/references/commit_reference_filter_spec.rb'
- - 'spec/lib/banzai/filter/references/issue_reference_filter_spec.rb'
- - 'spec/lib/banzai/filter/references/label_reference_filter_spec.rb'
- - 'spec/lib/banzai/filter/references/milestone_reference_filter_spec.rb'
- - 'spec/lib/banzai/filter/references/project_reference_filter_spec.rb'
- - 'spec/lib/banzai/filter/references/user_reference_filter_spec.rb'
- - 'spec/lib/feature_spec.rb'
- - 'spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb'
- - 'spec/lib/gitlab/background_migration/populate_vulnerability_reads_spec.rb'
- - 'spec/lib/gitlab/ci/config/entry/job_spec.rb'
- - 'spec/lib/gitlab/ci/config/entry/processable_spec.rb'
- - 'spec/lib/gitlab/ci/reports/test_suite_spec.rb'
- - 'spec/lib/gitlab/database/batch_count_spec.rb'
- - 'spec/lib/gitlab/database/load_balancing/connection_proxy_spec.rb'
- - 'spec/lib/gitlab/import_export/group/tree_saver_spec.rb'
- - 'spec/lib/gitlab/inactive_projects_deletion_warning_tracker_spec.rb'
- - 'spec/lib/gitlab/metrics/dashboard/url_spec.rb'
- - 'spec/lib/gitlab/redis/multi_store_spec.rb'
- - 'spec/lib/grafana/client_spec.rb'
- - 'spec/mailers/notify_spec.rb'
- - 'spec/migrations/20220107064845_populate_vulnerability_reads_spec.rb'
- - 'spec/models/active_session_spec.rb'
- - 'spec/models/clusters/platforms/kubernetes_spec.rb'
- - 'spec/models/diff_discussion_spec.rb'
- - 'spec/models/namespace_spec.rb'
- - 'spec/presenters/project_presenter_spec.rb'
- - 'spec/rack_servers/configs/config.ru'
- - 'spec/requests/api/alert_management_alerts_spec.rb'
- - 'spec/requests/api/markdown_spec.rb'
- - 'spec/requests/api/merge_requests_spec.rb'
- - 'spec/requests/api/metrics/dashboard/annotations_spec.rb'
- - 'spec/requests/api/tags_spec.rb'
- - 'spec/requests/api/terraform/state_spec.rb'
- - 'spec/requests/projects/google_cloud/deployments_controller_spec.rb'
- - 'spec/requests/projects/google_cloud/service_accounts_controller_spec.rb'
- - 'spec/routing/project_routing_spec.rb'
- - 'spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb'
- - 'spec/services/groups/transfer_service_spec.rb'
- - 'spec/services/members/invite_service_spec.rb'
- - 'spec/services/todo_service_spec.rb'
- - 'spec/services/todos/destroy/entity_leave_service_spec.rb'
- - 'spec/services/users/approve_service_spec.rb'
- - 'spec/services/users/ban_service_spec.rb'
- - 'spec/services/users/reject_service_spec.rb'
- - 'spec/services/users/unban_service_spec.rb'
- - 'spec/support/google_api/cloud_platform_helpers.rb'
- - 'spec/support/helpers/features/releases_helpers.rb'
- - 'spec/support/helpers/graphql_helpers.rb'
- - 'spec/support/helpers/kubernetes_helpers.rb'
- - 'spec/support/matchers/exceed_query_limit.rb'
- - 'spec/support/shared_examples/graphql/notes_creation_shared_examples.rb'
- - 'spec/support/shared_examples/graphql/resolvers/packages_resolvers_shared_examples.rb'
- - 'spec/support/shared_examples/lib/sentry/client_shared_examples.rb'
- - 'spec/support/shared_examples/mailers/notify_shared_examples.rb'
- - 'spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb'
- - 'spec/support/shared_examples/requests/api/issues_shared_examples.rb'
- - 'spec/support/shared_examples/requests/api/notes_shared_examples.rb'
- - 'spec/support/shared_examples/services/users/dismiss_user_callout_service_shared_examples.rb'
- - 'spec/support_specs/graphql/arguments_spec.rb'
- - 'spec/views/projects/commit/_commit_box.html.haml_spec.rb'
- 'tooling/rspec_flaky/flaky_example.rb'
diff --git a/.rubocop_todo/style/single_argument_dig.yml b/.rubocop_todo/style/single_argument_dig.yml
index 3ffd27d26ae..a85039a45f5 100644
--- a/.rubocop_todo/style/single_argument_dig.yml
+++ b/.rubocop_todo/style/single_argument_dig.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
Style/SingleArgumentDig:
- Details: grace period
Exclude:
- 'app/graphql/resolvers/namespace_projects_resolver.rb'
- 'app/models/ci/build.rb'
diff --git a/.rubocop_todo/style/sole_nested_conditional.yml b/.rubocop_todo/style/sole_nested_conditional.yml
index 535b8d20765..3c663b5f89a 100644
--- a/.rubocop_todo/style/sole_nested_conditional.yml
+++ b/.rubocop_todo/style/sole_nested_conditional.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
Style/SoleNestedConditional:
- Details: grace period
Exclude:
- 'app/controllers/admin/application_settings_controller.rb'
- 'app/controllers/ldap/omniauth_callbacks_controller.rb'
diff --git a/.rubocop_todo/style/special_global_vars.yml b/.rubocop_todo/style/special_global_vars.yml
deleted file mode 100644
index df688872d71..00000000000
--- a/.rubocop_todo/style/special_global_vars.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-# Cop supports --auto-correct.
-Style/SpecialGlobalVars:
- Details: grace period
diff --git a/.rubocop_todo/style/string_concatenation.yml b/.rubocop_todo/style/string_concatenation.yml
index ec15edbc206..65389d798d3 100644
--- a/.rubocop_todo/style/string_concatenation.yml
+++ b/.rubocop_todo/style/string_concatenation.yml
@@ -100,7 +100,6 @@ Style/StringConcatenation:
- 'ee/spec/support/shared_examples/models/geo_framework_registry_shared_examples.rb'
- 'ee/spec/tasks/gitlab/license_rake_spec.rb'
- 'lib/api/entities/tree_object.rb'
- - 'lib/api/go_proxy.rb'
- 'lib/api/internal/kubernetes.rb'
- 'lib/backup/files.rb'
- 'lib/backup/manager.rb'
@@ -316,7 +315,6 @@ Style/StringConcatenation:
- 'spec/services/verify_pages_domain_service_spec.rb'
- 'spec/support/capybara.rb'
- 'spec/support/helpers/ci_artifact_metadata_generator.rb'
- - 'spec/support/helpers/git_helpers.rb'
- 'spec/support/helpers/gitaly_setup.rb'
- 'spec/support/helpers/javascript_fixtures_helpers.rb'
- 'spec/support/helpers/kubernetes_helpers.rb'
diff --git a/.rubocop_todo/style/string_literals_in_interpolation.yml b/.rubocop_todo/style/string_literals_in_interpolation.yml
index fc90e1ce6a6..29e94e77345 100644
--- a/.rubocop_todo/style/string_literals_in_interpolation.yml
+++ b/.rubocop_todo/style/string_literals_in_interpolation.yml
@@ -1,7 +1,6 @@
---
# Cop supports --auto-correct.
Style/StringLiteralsInInterpolation:
- Details: grace period
Exclude:
- 'app/graphql/mutations/base_mutation.rb'
- 'app/helpers/colors_helper.rb'
diff --git a/.secretsignore b/.secretsignore
new file mode 100644
index 00000000000..071423bd3c1
--- /dev/null
+++ b/.secretsignore
@@ -0,0 +1,66 @@
+# This file is for defining paths and secrets that will be ignored by ripsecret
+
+doc/*
+spec/*
+ee/spec/*
+qa/*
+*_spec.rb
+config/gitlab.yml.example
+workhorse/testdata/localhost.key
+db/fixtures/**/*.rb
+
+[secrets]
+AUTO_DEVOPS_DOMAIN
+BACKWARD_DIRECTION
+CI_BUILD_BEFORE_SHA
+CI_BUILD_REF_NAME
+CI_BUILD_REF_SLUG
+CI_COMMIT_BRANCH
+CI_COMMIT_REF_SLUG
+CI_DEFAULT_BRANCH
+CI_DEPLOY_FREEZE
+CI_DEPLOY_PASSWORD
+CI_ENVIRONMENT_SLUG
+CI_ENVIRONMENT_URL
+CI_GITLAB_FIPS_MODE
+CI_JOB_NAME_SLUG
+CI_JOB_STARTED_AT
+CI_PAGES_DOMAIN
+CI_PROJECT_NAME
+CI_PROJECT_PATH
+CI_PROJECT_PATH_SLUG
+CI_PROJECT_VISIBILITY
+CI_REGISTRY_IMAGE
+CI_REGISTRY_PASSWORD
+CI_REPOSITORY_URL
+CROWDIN_API_KEY
+DAST_API_PROFILE
+DAST_PASSWORD_BASE64
+DAST_SUBMIT_FIELD
+DAST_USERNAME_FIELD
+DORA_METRICS_KEYS
+ESCALATION_STATUS
+FIFTY_PACKAGE_FILES
+FORTY_PACKAGE_FILES
+FORWARD_DIRECTION
+GITLAB_FEATURES
+GITLAB_USER_EMAIL
+GITLAB_USER_LOGIN
+GITLAB_USER_NAME
+HARBOR_PASSWORD
+HARBOR_USERNAME
+KUBE_CA_PEM_FILE
+KUBE_SERVICE_ACCOUNT
+NAVSOURCE_VALUE
+ONE_HUNDRED_TAGS
+ONE_PACKAGE_FILE
+STAGING_ENABLED
+TEN_PACKAGE_FILES
+THIRTY_PACKAGE_FILES
+TRIGGER_PAYLOAD
+TWENTY_FIVE_TAGS
+TWENTY_PACKAGE_FILES
+YOUR-ACCESSKEYID
+YOUR-CLIENT-SECRET
+YOUR_AUTH0_CLIENT_SECRET
+sbdMsxcgW2Xs75Q2uHc9FhUCZSEV3fSg
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cc95a92c457..a8a1bce23c4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -698,6 +698,38 @@ entry.
- [Add environment keyword to pages job](gitlab-org/gitlab@73af406f9101da0a2f076ac023de5dfd60c85445) by @edith007 ([merge request](gitlab-org/gitlab!98283))
- [Remove feature flag ci_variables_refactoring_to_variable](gitlab-org/gitlab@f5d1e8277fb8c326082e58536aeae21ab3fd289c) ([merge request](gitlab-org/gitlab!97967))
+## 15.4.5 (2022-11-15)
+
+### Fixed (1 change)
+
+- [Revert Sidekiq default routing rules](gitlab-org/gitlab@b8b62286bc660decc83dad6295b121e134451924) ([merge request](gitlab-org/gitlab!103641))
+
+## 15.4.4 (2022-11-02)
+
+### Security (12 changes)
+
+- [Datadog API key leak by changing integration URL](gitlab-org/security/gitlab@15e90bacccbc5146411c7a4ac3400470d3985c18) ([merge request](gitlab-org/security/gitlab!2865))
+- [Redact confidential references in Jira issue descriptions](gitlab-org/security/gitlab@8b60fe8c3150348973a9d3ad79d781614db47103) ([merge request](gitlab-org/security/gitlab!2871))
+- [Forbid reading emojis on internal notes](gitlab-org/security/gitlab@ec9b40a9e9d3c91dc690d74d76187e41b5884ff9) ([merge request](gitlab-org/security/gitlab!2836))
+- [Same-site redirect vulnerability](gitlab-org/security/gitlab@de86e0b20c34d1475ab7535bc3ed0d7a21727a20) ([merge request](gitlab-org/security/gitlab!2879))
+- [BYPASS: Stored-XSS with CSP-bypass via scoped labels' color](gitlab-org/security/gitlab@52e8105445cdba63be5c4e866cb289d13b6d6e7c) ([merge request](gitlab-org/security/gitlab!2861))
+- [Fix Running Upstream Pipelines Jobs Without Permission](gitlab-org/security/gitlab@ad2fe7b8555fd568944718f5fb087de8de7b2425) ([merge request](gitlab-org/security/gitlab!2882))
+- [Add length limit to addressable URLs](gitlab-org/security/gitlab@8c44b371bd120979b339e4e5dbb7208fb048eadd) ([merge request](gitlab-org/security/gitlab!2829))
+- [Add a redirect wall before artifact redirect to pages](gitlab-org/security/gitlab@837c0f2245847c43d6cfd8f1d7860e46ffacfe18) ([merge request](gitlab-org/security/gitlab!2812))
+- [Sandbox swagger-ui to prevent injection attacks](gitlab-org/security/gitlab@90567191fae7f7d84d001e52f0adc11155dc564f) ([merge request](gitlab-org/security/gitlab!2849))
+- [Fix external project permission when using CI prefill variables](gitlab-org/security/gitlab@ae39f2b5a5a27b6e85ef642b768963b7ed018a14) ([merge request](gitlab-org/security/gitlab!2822))
+- [Resolve users can view audit events from other members](gitlab-org/security/gitlab@f819d033a190b2b5f7d635395575e5472b1fe8e7) ([merge request](gitlab-org/security/gitlab!2842))
+- [Path traversal fix for Secure Files](gitlab-org/security/gitlab@bd138464ee5fa71755f2b4d9b9aaaa3c8017a165) ([merge request](gitlab-org/security/gitlab!2848))
+
+## 15.4.3 (2022-10-19)
+
+### Fixed (4 changes)
+
+- [Sign in: use custom logo again](gitlab-org/gitlab@5822562c4c3508927e3b217749867736e91316f3) ([merge request](gitlab-org/gitlab!101235))
+- [Fix closing of external issues](gitlab-org/gitlab@1302f992e3706b698c983961f596fcab03704c3f) ([merge request](gitlab-org/gitlab!101235))
+- [Sign in: use custom logo again](gitlab-org/gitlab@d760473a022ef485be7e258ab5fc406f05a127a4) ([merge request](gitlab-org/gitlab!101235))
+- [Fix REST/GRAPHQL APIs handling TODOs WorkItem target](gitlab-org/gitlab@f4157b08596040bbc504292c4a75fe2100aa570c) ([merge request](gitlab-org/gitlab!100081))
+
## 15.4.2 (2022-10-04)
### Fixed (1 change)
@@ -1356,6 +1388,23 @@ entry.
- [Improve specs with shared examples](gitlab-org/gitlab@dd3f2ecd882e89511eaa927102fc4101f684a38f) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95539)) **GitLab Enterprise Edition**
- [Fix Style/Next offenses](gitlab-org/gitlab@bdf877063ba1d8d4df1216f7875905343d9e5e33) ([merge request](gitlab-org/gitlab!93329))
+## 15.3.5 (2022-11-02)
+
+### Security (12 changes)
+
+- [Datadog API key leak by changing integration URL](gitlab-org/security/gitlab@3a8868210a210f07e08324a328e937fd818e34d3) ([merge request](gitlab-org/security/gitlab!2864))
+- [Redact confidential references in Jira issue descriptions](gitlab-org/security/gitlab@97178d0d8e1af412b949e81b5f53d8d9cf07371b) ([merge request](gitlab-org/security/gitlab!2872))
+- [Forbid reading emojis on internal notes](gitlab-org/security/gitlab@7684247b947b946e2865ec61a2f7eddd9a25daf7) ([merge request](gitlab-org/security/gitlab!2838))
+- [Same-site redirect vulnerability](gitlab-org/security/gitlab@4c0737d57b9d9f5f86ffdd5b0c25f9805d05d5f7) ([merge request](gitlab-org/security/gitlab!2880))
+- [BYPASS: Stored-XSS with CSP-bypass via scoped labels' color](gitlab-org/security/gitlab@a72e2384e95ed083a139252d51b6638fe4128c14) ([merge request](gitlab-org/security/gitlab!2862))
+- [Fix Running Upstream Pipelines Jobs Without Permission](gitlab-org/security/gitlab@f6545466e181f3688d5ed67023cd0f1bd6220a7c) ([merge request](gitlab-org/security/gitlab!2883))
+- [Add length limit to addressable URLs](gitlab-org/security/gitlab@411bba8ac053211906d40d24b9fdb2c565d33f62) ([merge request](gitlab-org/security/gitlab!2830))
+- [Add a redirect wall before artifact redirect to pages](gitlab-org/security/gitlab@2b9a6ccddb77cab46217ef0fd633af2f32548313) ([merge request](gitlab-org/security/gitlab!2813))
+- [Sandbox swagger-ui to prevent injection attacks](gitlab-org/security/gitlab@3b8771478b8615d24794fc49195b5f2f8257df0c) ([merge request](gitlab-org/security/gitlab!2850))
+- [Fix external project permission when using CI prefill variables](gitlab-org/security/gitlab@107e583c97b39951c08728fdff1b44e8c6fa7f6f) ([merge request](gitlab-org/security/gitlab!2823))
+- [Resolve users can view audit events from other members](gitlab-org/security/gitlab@cdcd5ed72312dfddcd3e91ae824188a0dd88e745) ([merge request](gitlab-org/security/gitlab!2843))
+- [Path traversal fix for Secure Files](gitlab-org/security/gitlab@90bbaaa1ce2d0978cf89fabf1f302da1f9f938df) ([merge request](gitlab-org/security/gitlab!2847))
+
## 15.3.4 (2022-09-29)
### Security (15 changes)
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index 63a3b0b00ae..1f9ab02102a 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-15.5.4 \ No newline at end of file
+40398eb9e22e8cf09365f508f6779030ee90432a
diff --git a/GITLAB_ELASTICSEARCH_INDEXER_VERSION b/GITLAB_ELASTICSEARCH_INDEXER_VERSION
index 75a22a26ac4..fd2a01863fd 100644
--- a/GITLAB_ELASTICSEARCH_INDEXER_VERSION
+++ b/GITLAB_ELASTICSEARCH_INDEXER_VERSION
@@ -1 +1 @@
-3.0.3
+3.1.0
diff --git a/GITLAB_KAS_VERSION b/GITLAB_KAS_VERSION
index 2e0b428c416..9f6d8f2fdb4 100644
--- a/GITLAB_KAS_VERSION
+++ b/GITLAB_KAS_VERSION
@@ -1 +1 @@
-15.5.1
+15.6.0
diff --git a/GITLAB_METRICS_EXPORTER_VERSION b/GITLAB_METRICS_EXPORTER_VERSION
index f3e956091b9..6d47f7a2be5 100644
--- a/GITLAB_METRICS_EXPORTER_VERSION
+++ b/GITLAB_METRICS_EXPORTER_VERSION
@@ -1 +1 @@
-2c781b65ccfd6d016c7bfab1982ecb234c4e2cd0
+f2d7e32cb5e3d8886a2bac5da2703b31f6a38d88
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index 76d05362056..af92bdd9f58 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-1.62.0
+1.63.0
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 27fbdebd13c..ea212aadaf3 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-14.12.0
+14.13.0
diff --git a/Gemfile b/Gemfile
index 8a8c0a444a9..87869f6f1e4 100644
--- a/Gemfile
+++ b/Gemfile
@@ -31,7 +31,7 @@ gem 'responders', '~> 3.0'
gem 'sprockets', '~> 3.7.0'
-gem 'view_component', '~> 2.71.0'
+gem 'view_component', '~> 2.74.1'
# Default values for AR models
gem 'default_value_for', '~> 3.4.0'
@@ -86,7 +86,7 @@ gem 'timfel-krb5-auth', '~> 0.8', group: :kerberos
# Spam and anti-bot protection
gem 'recaptcha', '~> 4.11', require: 'recaptcha/rails'
gem 'akismet', '~> 3.0'
-gem 'invisible_captcha', '~> 1.1.0'
+gem 'invisible_captcha', '~> 2.0.0'
# Two-factor authentication
gem 'devise-two-factor', '~> 4.0.2'
@@ -101,7 +101,7 @@ gem 'rubyzip', '~> 2.3.2', require: 'zip'
gem 'acme-client', '~> 2.0'
# Browser detection
-gem 'browser', '~> 4.2'
+gem 'browser', '~> 5.3.1'
# OS detection for usage ping
gem 'ohai', '~> 16.10'
@@ -129,12 +129,10 @@ gem 'apollo_upload_server', '~> 2.1.0'
gem 'graphql-docs', '~> 2.1.0', group: [:development, :test]
gem 'graphlient', '~> 0.5.0' # Used by BulkImport feature (group::import)
-gem 'hashie'
-# Disable strong_params so that Mash does not respond to :permitted?
-gem 'hashie-forbidden_attributes'
+gem 'hashie', '~> 5.0.0'
# Pagination
-gem 'kaminari', '~> 1.0'
+gem 'kaminari', '~> 1.2.2'
# HAML
gem 'hamlit', '~> 2.15.0'
@@ -144,16 +142,16 @@ gem 'carrierwave', '~> 1.3'
gem 'mini_magick', '~> 4.10.1'
# for backups
-gem 'fog-aws', '~> 3.14'
+gem 'fog-aws', '~> 3.15'
# 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.15', require: 'fog/google'
-gem 'fog-local', '~> 0.6'
+gem 'fog-google', '~> 1.19', require: 'fog/google'
+gem 'fog-local', '~> 0.8'
gem 'fog-openstack', '~> 1.0'
gem 'fog-rackspace', '~> 0.1.1'
gem 'fog-aliyun', '~> 0.3'
-gem 'gitlab-fog-azure-rm', '~> 1.3.0', require: 'fog/azurerm'
+gem 'gitlab-fog-azure-rm', '~> 1.4.0', require: 'fog/azurerm'
# for Google storage
gem 'google-api-client', '~> 0.33'
@@ -168,17 +166,16 @@ 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.159.0'
+gem 'aws-sdk-core', '~> 3.167.0'
gem 'aws-sdk-cloudformation', '~> 1'
-gem 'aws-sdk-s3', '~> 1.114.0'
+gem 'aws-sdk-s3', '~> 1.117.1'
gem 'faraday_middleware-aws-sigv4', '~>0.3.0'
gem 'typhoeus', '~> 1.4.0' # Used with Elasticsearch to support http keep-alive connections
# Markdown and HTML processing
-gem 'html-pipeline', '~> 2.13.2'
-gem 'deckar01-task_list', '2.3.1'
-gem 'gitlab-markup', '~> 1.8.0'
-gem 'github-markup', '~> 1.7.0', require: 'github/markup'
+gem 'html-pipeline', '~> 2.14.3'
+gem 'deckar01-task_list', '2.3.2'
+gem 'gitlab-markup', '~> 1.8.0', require: 'github/markup'
gem 'commonmarker', '~> 0.23.6'
gem 'kramdown', '~> 2.3.1'
gem 'RedCloth', '~> 4.3.2'
@@ -189,11 +186,11 @@ gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 2.0.17'
gem 'asciidoctor-include-ext', '~> 0.4.0', require: false
gem 'asciidoctor-plantuml', '~> 0.0.16'
-gem 'asciidoctor-kroki', '~> 0.5.0', require: false
+gem 'asciidoctor-kroki', '~> 0.7.0', require: false
gem 'rouge', '~> 3.30.0'
gem 'truncato', '~> 0.7.12'
gem 'bootstrap_form', '~> 4.2.0'
-gem 'nokogiri', '~> 1.13.8'
+gem 'nokogiri', '~> 1.13.9'
# Calendar rendering
gem 'icalendar'
@@ -220,16 +217,16 @@ gem 'state_machines-activerecord', '~> 0.8.0'
gem 'acts-as-taggable-on', '~> 9.0'
# Background jobs
-gem 'sidekiq', '~> 6.4.0'
+gem 'sidekiq', '~> 6.5.7'
gem 'sidekiq-cron', '~> 1.8.0'
gem 'redis-namespace', '~> 1.9.0'
-gem 'gitlab-sidekiq-fetcher', '0.8.0', require: 'sidekiq-reliable-fetch'
+gem 'gitlab-sidekiq-fetcher', '0.9.0', require: 'sidekiq-reliable-fetch'
# Cron Parser
gem 'fugit', '~> 1.2.1'
# HTTP requests
-gem 'httparty', '~> 0.16.4'
+gem 'httparty', '~> 0.20.0'
# Colored output to console
gem 'rainbow', '~> 3.0'
@@ -241,20 +238,20 @@ gem 'ruby-progressbar', '~> 1.10'
gem 'settingslogic', '~> 2.0.9'
# Linear-time regex library for untrusted regular expressions
-gem 're2', '~> 1.5.0'
+gem 're2', '~> 1.6.0'
# Misc
gem 'version_sorter', '~> 2.2.4'
# Export Ruby Regex to Javascript
-gem 'js_regex', '~> 3.7'
+gem 'js_regex', '~> 3.8'
# User agent parsing
gem 'device_detector'
# Redis
-gem 'redis', '~> 4.7.0'
+gem 'redis', '~> 4.8.0'
gem 'connection_pool', '~> 2.0'
# Redis session store
@@ -280,7 +277,7 @@ gem 'hangouts-chat', '~> 0.0.5', require: 'hangouts_chat'
gem 'asana', '~> 0.10.13'
# FogBugz integration
-gem 'ruby-fogbugz', '~> 0.2.1'
+gem 'ruby-fogbugz', '~> 0.3.0'
# Kubernetes integration
gem 'kubeclient', '~> 4.9.3'
@@ -319,7 +316,7 @@ gem 'terser', '1.0.2'
gem 'addressable', '~> 2.8'
gem 'tanuki_emoji', '~> 0.6'
gem 'gon', '~> 6.4.0'
-gem 'request_store', '~> 1.5'
+gem 'request_store', '~> 1.5.1'
gem 'base32', '~> 0.3.0'
gem 'gitlab-license', '~> 2.2.1'
@@ -335,12 +332,12 @@ gem 'sentry-sidekiq', '~> 5.1.1'
# PostgreSQL query parsing
#
-gem 'pg_query', '~> 2.1.4'
+gem 'pg_query', '~> 2.2'
gem 'premailer-rails', '~> 1.10.3'
# LabKit: Tracing and Correlation
-gem 'gitlab-labkit', '~> 0.24.0'
+gem 'gitlab-labkit', '~> 0.28.0'
gem 'thrift', '>= 0.16.0'
# I18n
@@ -365,12 +362,12 @@ gem 'prometheus-client-mmap', '~> 0.16', require: 'prometheus/client'
gem 'warning', '~> 1.3.0'
group :development do
- gem 'lefthook', '~> 1.1.3', require: false
+ gem 'lefthook', '~> 1.2.0', require: false
gem 'rubocop'
gem 'solargraph', '~> 0.47.2', require: false
gem 'letter_opener_web', '~> 2.0.0'
- gem 'lookbook', '~> 1.0', '>= 1.0.8'
+ gem 'lookbook', '~> 1.2', '>= 1.2.1'
# Better errors handler
gem 'better_errors', '~> 2.9.1'
@@ -428,7 +425,7 @@ group :development, :test do
end
group :development, :test, :danger do
- gem 'gitlab-dangerfiles', '~> 3.5.2', require: false
+ gem 'gitlab-dangerfiles', '~> 3.6.2', require: false
end
group :development, :test, :coverage do
@@ -480,7 +477,7 @@ gem 'html2text'
gem 'stackprof', '~> 0.2.21', require: false
gem 'rbtrace', '~> 0.4', require: false
-gem 'memory_profiler', '~> 0.9', require: false
+gem 'memory_profiler', '~> 1.0', require: false
gem 'activerecord-explain-analyze', '~> 0.1', require: false
# OAuth
@@ -503,14 +500,14 @@ gem 'ssh_data', '~> 1.3'
gem 'spamcheck', '~> 1.0.0'
# Gitaly GRPC protocol definitions
-gem 'gitaly', '~> 15.4.0-rc2'
+gem 'gitaly', '~> 15.5.0'
# KAS GRPC protocol definitions
gem 'kas-grpc', '~> 0.0.2'
gem 'grpc', '~> 1.42.0'
-gem 'google-protobuf', '~> 3.21'
+gem 'google-protobuf', '~> 3.21', '>= 3.21.9'
gem 'toml-rb', '~> 2.2.0'
@@ -554,6 +551,7 @@ gem 'valid_email', '~> 0.1'
gem 'json', '~> 2.5.1'
gem 'json_schemer', '~> 0.2.18'
gem 'oj', '~> 3.13.21'
+gem 'oj-introspect', '~> 0.7'
gem 'multi_json', '~> 1.14.1'
gem 'yajl-ruby', '~> 1.4.3', require: 'yajl'
@@ -580,3 +578,6 @@ gem 'arr-pm', '~> 0.0.12'
# Apple plist parsing
gem 'CFPropertyList'
+
+# For phone verification
+gem 'telesignenterprise', '~> 2.2'
diff --git a/Gemfile.checksum b/Gemfile.checksum
index afcbc5a6a65..f8202c49abe 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -24,7 +24,7 @@
{"name":"asana","version":"0.10.13","platform":"ruby","checksum":"36d0d37f8dd6118a54580f1b80224875d7b6a9027598938e1722a508bfc2d7ac"},
{"name":"asciidoctor","version":"2.0.17","platform":"ruby","checksum":"ed5b5e399e8d64994cc16f0983f993d6e33990909a8415b6fc8b786cdeb00f3d"},
{"name":"asciidoctor-include-ext","version":"0.4.0","platform":"ruby","checksum":"406adb9d2fbfc25536609ca13b787ed704dc06a4e49d6709b83f3bad578f7878"},
-{"name":"asciidoctor-kroki","version":"0.5.0","platform":"ruby","checksum":"622c8b74796689bdaf8abdf89ad5295b11ce310e3d193e28f19e5baf58d45f12"},
+{"name":"asciidoctor-kroki","version":"0.7.0","platform":"ruby","checksum":"528ae4e49cae10e98c76e91f9aa40c67bf8540aa5ce4bbd44c5cd57af9f0b121"},
{"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"},
@@ -33,11 +33,11 @@
{"name":"awesome_print","version":"1.9.2","platform":"ruby","checksum":"e99b32b704acff16d768b3468680793ced40bfdc4537eb07e06a4be11133786e"},
{"name":"awrence","version":"1.1.1","platform":"ruby","checksum":"9be584c97408ed92d5e1ca11740853646fe270de675f2f8dd44e8233226dfc97"},
{"name":"aws-eventstream","version":"1.2.0","platform":"ruby","checksum":"ffa53482c92880b001ff2fb06919b9bb82fd847cbb0fa244985d2ebb6dd0d1df"},
-{"name":"aws-partitions","version":"1.644.0","platform":"ruby","checksum":"63791750839afff110c5b5a8805018c4275720d7a5c7ec79319d4d520c7da874"},
+{"name":"aws-partitions","version":"1.658.0","platform":"ruby","checksum":"bba2e21fc87c4e68c7ba5c09e3cd2b81d59ca86111ab236eaf9c5a8ae207b3fc"},
{"name":"aws-sdk-cloudformation","version":"1.41.0","platform":"ruby","checksum":"31e47539719734413671edf9b1a31f8673fbf9688549f50c41affabbcb1c6b26"},
-{"name":"aws-sdk-core","version":"3.159.0","platform":"ruby","checksum":"8863e2cdfd6816a0532ad9eb82a07b81b3d12667da747e9e82554e4dd7adb231"},
-{"name":"aws-sdk-kms","version":"1.57.0","platform":"ruby","checksum":"ffd7dbb9b4251f29d4f508af761d0addd7035a346a88e3481cdb4dc548e51bd5"},
-{"name":"aws-sdk-s3","version":"1.114.0","platform":"ruby","checksum":"ce0f71df1a7b0fb1f88d40a70636ef1a9b08e69fb560694c5dab3f4ac7efcde4"},
+{"name":"aws-sdk-core","version":"3.167.0","platform":"ruby","checksum":"d371856ad86f8bff08928059ee09b7cb9bca8ebf36bf5081f12424e4f491b624"},
+{"name":"aws-sdk-kms","version":"1.59.0","platform":"ruby","checksum":"6c002ebf8e404625c8338ca12ae69b1329399f9dc1b0ebca474e00ff06700153"},
+{"name":"aws-sdk-s3","version":"1.117.1","platform":"ruby","checksum":"76f6dac5baeb2b78616eb34c6af650c1b7a15c1078b169d1b27e8421904c509d"},
{"name":"aws-sigv4","version":"1.5.1","platform":"ruby","checksum":"d68c87fff4ee843b4b92b23c7f31f957f254ec6eb064181f7119124aab8b8bb4"},
{"name":"azure-storage-blob","version":"2.0.3","platform":"ruby","checksum":"61b76118843c91776bd24bee22c74adafeb7c4bb3a858a325047dae3b59d0363"},
{"name":"azure-storage-common","version":"2.0.4","platform":"ruby","checksum":"608f4daab0e06b583b73dcffd3246ea39e78056de31630286b0cf97af7d6956b"},
@@ -50,7 +50,7 @@
{"name":"benchmark","version":"0.2.0","platform":"ruby","checksum":"5f7087b794613abdd3ac9c13f4351f65b164bcb15ced2ad29508e365f9b28c77"},
{"name":"benchmark-ips","version":"2.3.0","platform":"ruby","checksum":"12443aa327d3129aa965244f79d7d5cb0f692f0f92ba7db76fba61526a40062e"},
{"name":"benchmark-malloc","version":"0.2.0","platform":"ruby","checksum":"37c68f0435261634026f584d79956a35325a3027e3e6b4cc8d7575aa10537e6b"},
-{"name":"benchmark-memory","version":"0.1.2","platform":"ruby","checksum":"aa7bfe6776174d0ddefe6fb39945d88fff6d76eac165690188391d9acd441c87"},
+{"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"},
@@ -59,7 +59,7 @@
{"name":"binding_ninja","version":"0.2.3","platform":"ruby","checksum":"4a85550a0066ee4721506b4e150857486808e50c9ddfeed04bdc896bb61eca9d"},
{"name":"bootsnap","version":"1.13.0","platform":"ruby","checksum":"c673282ec0f48506f093ca9acefe0f666d1ab9fda716e49fb95c9fe677653e78"},
{"name":"bootstrap_form","version":"4.2.0","platform":"ruby","checksum":"f578b3c900d2cf15fab641064d357318b29e285bd5fdf090f903727912889710"},
-{"name":"browser","version":"4.2.0","platform":"ruby","checksum":"fc194b422ea8b313f98443c6ec249ccf252e29007ce01bb99ebe828bd7fe3e60"},
+{"name":"browser","version":"5.3.1","platform":"ruby","checksum":"62745301701ff2c6c5d32d077bb12532b20be261929dcb52c6781ed0d5658b3c"},
{"name":"builder","version":"3.2.4","platform":"ruby","checksum":"99caf08af60c8d7f3a6b004029c4c3c0bdaebced6c949165fe98f1db27fbbc10"},
{"name":"bullet","version":"7.0.2","platform":"ruby","checksum":"4b7986b366f694bb05d5c1b4ea8ba949a99224d4511bf02f0c3944112f719c81"},
{"name":"bundler-audit","version":"0.7.0.1","platform":"ruby","checksum":"12d853cb0b92fa8868abbb539414d7a33da9e48b792e2ff28271d36c8ace8912"},
@@ -97,13 +97,13 @@
{"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":"deckar01-task_list","version":"2.3.1","platform":"ruby","checksum":"205a08c22a8f05c063d43c452aeada4214b58fdce1e55e92ec709e2cfb9e7ca1"},
+{"name":"deckar01-task_list","version":"2.3.2","platform":"ruby","checksum":"5a19092548d24309d8b2c2704d64cdc08a4a615823c9a722f4142edec1de8805"},
{"name":"declarative","version":"0.0.20","platform":"ruby","checksum":"8021dd6cb17ab2b61233c56903d3f5a259c5cf43c80ff332d447d395b17d9ff9"},
{"name":"declarative-option","version":"0.1.0","platform":"ruby","checksum":"17508349f51c5631e5ad4158c29f78a4b2de618abffa066d76c11953705f91bc"},
{"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.1","platform":"ruby","checksum":"25b0ba79dc52c715ea6cce35fd8afbbf84511ef1c7f2bbe1d8b7a30addc6aab3"},
+{"name":"derailed_benchmarks","version":"2.1.2","platform":"ruby","checksum":"eaadc6206ceeb5538ff8f5e04a0023d54ebdd95d04f33e8960fb95a5f189a14f"},
{"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"},
@@ -151,7 +151,7 @@
{"name":"faraday-em_http","version":"1.0.0","platform":"ruby","checksum":"7a3d4c7079789121054f57e08cd4ef7e40ad1549b63101f38c7093a9d6c59689"},
{"name":"faraday-em_synchrony","version":"1.0.0","platform":"ruby","checksum":"460dad1c30cc692d6e77d4c391ccadb4eca4854b315632cd7e560f74275cf9ed"},
{"name":"faraday-excon","version":"1.1.0","platform":"ruby","checksum":"b055c842376734d7f74350fe8611542ae2000c5387348d9ba9708109d6e40940"},
-{"name":"faraday-http-cache","version":"2.4.0","platform":"ruby","checksum":"388f901d63bd5903b470c5696bc886ed94fab0c4206b25c3761e7b9bdbbf6c90"},
+{"name":"faraday-http-cache","version":"2.4.1","platform":"ruby","checksum":"fb51b2e9ee72f89e81cc277ee574dbc5940f3db95431b3533de9882f92635ee3"},
{"name":"faraday-httpclient","version":"1.0.1","platform":"ruby","checksum":"4c8ff1f0973ff835be8d043ef16aaf54f47f25b7578f6d916deee8399a04d33b"},
{"name":"faraday-multipart","version":"1.0.4","platform":"ruby","checksum":"9012021ab57790f7d712f590b48d5f948b19b43cfa11ca83e6459f06090b0725"},
{"name":"faraday-net_http","version":"1.0.1","platform":"ruby","checksum":"3245ce406ebb77b40e17a77bfa66191dda04be2fd4e13a78d8a4305854d328ba"},
@@ -180,11 +180,11 @@
{"name":"flipper-active_support_cache_store","version":"0.25.0","platform":"ruby","checksum":"7282bf994b08d1a076b65c6f3b51e3dc04fcb00fa6e7b20089e60db25c7b531b"},
{"name":"flowdock","version":"0.7.1","platform":"ruby","checksum":"cfa95b2ac96e5f883f6e419d7a891f76cfcc17a28c416b6b714bbdffc8dbd912"},
{"name":"fog-aliyun","version":"0.3.3","platform":"ruby","checksum":"d0aa317f7c1473a1d684fff51699f216bb9cb78b9ee9ce55a81c9bcc93fb85ee"},
-{"name":"fog-aws","version":"3.14.0","platform":"ruby","checksum":"07442dff8ee2a314413f812d6f6052e7d4a444540df84c193c135c1994114bbf"},
+{"name":"fog-aws","version":"3.15.0","platform":"ruby","checksum":"09752931ea0c6165b018e1a89253248d86b246645086ccf19bc44fabe3381e8c"},
{"name":"fog-core","version":"2.1.0","platform":"ruby","checksum":"53e5d793554d7080d015ef13cd44b54027e421d924d9dba4ce3d83f95f37eda9"},
-{"name":"fog-google","version":"1.15.0","platform":"ruby","checksum":"2f840780fbf2384718e961b05ef2fc522b4213bbda6f25b28c1bbd875ff0b306"},
+{"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.6.0","platform":"ruby","checksum":"417473fe22a839af8f1388218d1843dbd09a5edfc8fcc59a893edb322ca5442d"},
+{"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"},
@@ -193,42 +193,52 @@
{"name":"fuubar","version":"2.2.0","platform":"ruby","checksum":"9b0263c4074f39c68b37f1e4e69a7d3cfc7523c41bea43601235daa723179b4a"},
{"name":"fuzzyurl","version":"0.9.0","platform":"ruby","checksum":"542efa80f2bcaadbdc402c2f0b572f2e335a1d53e375aecad68bbb3d86860c0f"},
{"name":"gemoji","version":"3.0.1","platform":"ruby","checksum":"80553f2f4932a7a95fb1b3c7c63f7dd937e7c8c610164bbdea28fd06eba5f36d"},
+{"name":"gems","version":"1.2.0","platform":"ruby","checksum":"343d74bd54d906f38193f3ccd983f9d08c4b54cd01ee7e5fe8467ab41a9946f0"},
{"name":"get_process_mem","version":"0.2.7","platform":"ruby","checksum":"4afd3c3641dd6a817c09806c7d6d509d8a9984512ac38dea8b917426bbf77eba"},
{"name":"gettext","version":"3.3.6","platform":"ruby","checksum":"ee6bbd1b2f833ee52d7797fa68acbfecc4726aec6b6280fd7eab92aa0190b413"},
{"name":"gettext_i18n_rails","version":"1.8.0","platform":"ruby","checksum":"95e5cf8440b1e08705b27f2bccb56143272c5a7a0dabcf54ea1bd701140a496f"},
{"name":"gettext_i18n_rails_js","version":"1.3.0","platform":"ruby","checksum":"5d10afe4be3639bff78c50a56768c20f39aecdabc580c08aa45573911c2bd687"},
{"name":"git","version":"1.11.0","platform":"ruby","checksum":"7e95ba4da8298a0373ef1a6862aa22007d761f3c8274b675aa787966fecea0f1"},
-{"name":"gitaly","version":"15.4.0.pre.rc2","platform":"ruby","checksum":"48764528a730605a46f00cf86c7cfcb92d25f4f3d8cb9e09557baac3e9f3f8e3"},
-{"name":"github-markup","version":"1.7.0","platform":"ruby","checksum":"97eb27c70662d9cc1d5997cd6c99832026fae5d4913b5dce1ce6c9f65078e69d"},
+{"name":"gitaly","version":"15.5.0","platform":"ruby","checksum":"d85dd4890a1f0fd95f935c848bcedf03f19b78872f20f04b9811e602bea4ef42"},
{"name":"gitlab","version":"4.16.1","platform":"ruby","checksum":"13fd7059cbdad5a1a21b15fa2cf9070b97d92e27f8c688581fe3d84dc038074f"},
{"name":"gitlab-chronic","version":"0.10.5","platform":"ruby","checksum":"f80f18dc699b708870a80685243331290bc10cfeedb6b99c92219722f729c875"},
-{"name":"gitlab-dangerfiles","version":"3.5.2","platform":"ruby","checksum":"fae28a55b83b6c7f8298b9b1d90354ae73636729fd829ad58326bef46bd2f01f"},
+{"name":"gitlab-dangerfiles","version":"3.6.2","platform":"ruby","checksum":"88585532bbb5c0e862ad0776b3804a32129eab06c6a8a7bc96b577baa7aac6c5"},
{"name":"gitlab-experiment","version":"0.7.1","platform":"ruby","checksum":"166dddb3aa83428bcaa93c35684ed01dc4d61f321fd2ae40b020806dc54a7824"},
-{"name":"gitlab-fog-azure-rm","version":"1.3.0","platform":"ruby","checksum":"2fef5317d6515f95f803099afa860fe3019ce6e1907bf49f66b5e06468a617b5"},
-{"name":"gitlab-labkit","version":"0.24.0","platform":"ruby","checksum":"8f16e5aa4e0a05be58958fe880bdd53c84b659a081ea9981d2b510922a4a0548"},
+{"name":"gitlab-fog-azure-rm","version":"1.4.0","platform":"ruby","checksum":"af4163c32b028aa5208814a3f4765a5817d50527e6c61931f766bf18a2e0eb7e"},
+{"name":"gitlab-labkit","version":"0.28.0","platform":"ruby","checksum":"a7ebf52336566f7607d280056acd64f390c9991f152fc3d6b1dd966a372d5654"},
{"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.8.1","platform":"ruby","checksum":"ab1f9fd016977497c2af25b76341dea670533014f406861834a0bd99f646707b"},
{"name":"gitlab-net-dns","version":"0.9.1","platform":"ruby","checksum":"bcd1a08dcb31b731e8ff602d828de619d2d9f53f5812f6abacf11c720873d4cb"},
{"name":"gitlab-omniauth-openid-connect","version":"0.10.0","platform":"ruby","checksum":"ea44a23ea93457057bba6a9912e883f5aefab36a941c6c58512c8a7095fb1153"},
-{"name":"gitlab-sidekiq-fetcher","version":"0.8.0","platform":"ruby","checksum":"9c564caa2a958d44a8d78672dc23b2a206102d0223b41b77b58626a945e37362"},
+{"name":"gitlab-sidekiq-fetcher","version":"0.9.0","platform":"ruby","checksum":"54041aec059f20c8e6dfce394e1b60e0c0a9c7cef32da912a58abbd333e13897"},
{"name":"gitlab-styles","version":"9.0.0","platform":"ruby","checksum":"ef0edfab8f807a5be2309ba24dfc44fec5ba52ed68b87167c051e9ffdadb3bad"},
{"name":"gitlab_chronic_duration","version":"0.10.6.2","platform":"ruby","checksum":"6dda4cfe7dca9b958f163ac8835c3d9cc70cf8df8cbb89bb2fbf9ba4375105fb"},
{"name":"gitlab_omniauth-ldap","version":"2.2.0","platform":"ruby","checksum":"bb4d20acb3b123ed654a8f6a47d3fac673ece7ed0b6992edb92dca14bad2838c"},
{"name":"globalid","version":"1.0.0","platform":"ruby","checksum":"1253641b1dc3392721c964351773755d75135d3d3c5cc65d88b0a3880a60bed8"},
{"name":"gon","version":"6.4.0","platform":"ruby","checksum":"e3a618d659392890f1aa7db420f17c75fd7d35aeb5f8fe003697d02c4b88d2f0"},
-{"name":"google-api-client","version":"0.50.0","platform":"ruby","checksum":"3ae45e972f293f3a66e53950ecc0fd350d85d6347c06a430bb971bd1ae5ad617"},
+{"name":"google-api-client","version":"0.53.0","platform":"ruby","checksum":"41006ef21fe02a70cff39a10aebf84fa7fb5f24c63566ab12b149ff1f1d9d7ff"},
+{"name":"google-apis-compute_v1","version":"0.53.0","platform":"ruby","checksum":"629537cf9efc1aeda0bb00d78c2a6ffa8488de833a8b19bdb150ce0a6a105f4b"},
+{"name":"google-apis-core","version":"0.9.1","platform":"ruby","checksum":"c012a364891a4602b4b1aa8468400dd3fa50b00e694edb4411af6b85aa3eb034"},
+{"name":"google-apis-discovery_v1","version":"0.12.0","platform":"ruby","checksum":"2e5accfe126884e5ebd8540b3a17a878a3a050d0dfdf0ece6b231846fc485a15"},
+{"name":"google-apis-dns_v1","version":"0.28.0","platform":"ruby","checksum":"f523631ea2737b67096e21eff25e426edb51ffefa9979a42f798936a950df34c"},
+{"name":"google-apis-generator","version":"0.11.0","platform":"ruby","checksum":"4656febed121b21e9071118c79ab67cbec9e40a39b6a38acc05d07fafa321279"},
+{"name":"google-apis-iamcredentials_v1","version":"0.15.0","platform":"ruby","checksum":"e9a256a6d80fbfc77d44bd7e65bc94b9e1e9863a00e6d413edc0102d6cb5551b"},
+{"name":"google-apis-monitoring_v3","version":"0.37.0","platform":"ruby","checksum":"2d9262ae8dfa83ac7db895b03c7deeaae9f13107e94c8781a432202fbc20736a"},
+{"name":"google-apis-pubsub_v1","version":"0.30.0","platform":"ruby","checksum":"b8905915388041bf54f9b7e988c8cc64fe00c2132475d5c753d10479415ee13d"},
+{"name":"google-apis-sqladmin_v1beta4","version":"0.38.0","platform":"ruby","checksum":"d00279cdcc5548bf4f4e40cc29cbd942b79708011e59c75a18726b6826be1665"},
+{"name":"google-apis-storage_v1","version":"0.20.0","platform":"ruby","checksum":"8a1ace07fc909966d6f76e777d6adc7d86dddd91a629fef8914ebd5baf86d850"},
{"name":"google-cloud-env","version":"1.6.0","platform":"ruby","checksum":"6179acb946975892c7908748df5722a4ebadfc8cf5bb7b0d8d933ca67183fa15"},
-{"name":"google-protobuf","version":"3.21.7","platform":"java","checksum":"e8a0d10014d18f741afc4882035badbd08558e6f46e09cd937b6ea254881314a"},
-{"name":"google-protobuf","version":"3.21.7","platform":"ruby","checksum":"8d501659c77d159fde20f983f7272ce4c28339f6412c480e4eb98c1ccb52cc62"},
-{"name":"google-protobuf","version":"3.21.7","platform":"x64-mingw-ucrt","checksum":"35dc328caf1c843ae25ec1a4825ded8a71b8f4750449bd8d8e1664ae0dcdc240"},
-{"name":"google-protobuf","version":"3.21.7","platform":"x64-mingw32","checksum":"c9ea241dc186823ceba2abf9952a609668d38a729dd92f0ec744ff67fb60ab30"},
-{"name":"google-protobuf","version":"3.21.7","platform":"x86-linux","checksum":"02a1212e6e62e5927649124bdc6315dd54256059b3a7aed119811ceaef85c310"},
-{"name":"google-protobuf","version":"3.21.7","platform":"x86-mingw32","checksum":"509529f9231a6b61c97c26e12938054007be8a1dacb83dcd3b3a385107ce60cc"},
-{"name":"google-protobuf","version":"3.21.7","platform":"x86_64-darwin","checksum":"93754c1366a3ecbd69bec241ab531a01aa05640577a2c0e52e671bdcb194f19f"},
-{"name":"google-protobuf","version":"3.21.7","platform":"x86_64-linux","checksum":"9c7a49bb1cdbb17c039297d9aff8515245868f3ad86ebf274e4c0fd6fd9263be"},
+{"name":"google-protobuf","version":"3.21.9","platform":"java","checksum":"8483ab2487170434f7a139d6534b3a166e4ec244a6fd8929f758d87abbb82fee"},
+{"name":"google-protobuf","version":"3.21.9","platform":"ruby","checksum":"5a656c159aa2c85008af7eab3f603cf22921b748e09438f6682dcf696d518adc"},
+{"name":"google-protobuf","version":"3.21.9","platform":"x64-mingw-ucrt","checksum":"7cb37b76241150212703f0ac582555f6fda1c7c66f58c1164667e783141e25fe"},
+{"name":"google-protobuf","version":"3.21.9","platform":"x64-mingw32","checksum":"54df7b9df435cc5c715261fbe8897fe03dd4b0e68e052aa0bb814c31bc66ef35"},
+{"name":"google-protobuf","version":"3.21.9","platform":"x86-linux","checksum":"11f28f344f6b6afa78fa0688379e39fbc86da4c199f04a51da7a29cf2db8205d"},
+{"name":"google-protobuf","version":"3.21.9","platform":"x86-mingw32","checksum":"a2dce43556196b6bb0fce2cf28df70fdca4255607fb9e1ffb7ee611953436a9a"},
+{"name":"google-protobuf","version":"3.21.9","platform":"x86_64-darwin","checksum":"9e948a08ee27cca8acf794c798db16d918ce503eae06525d7551dc05ac3324c0"},
+{"name":"google-protobuf","version":"3.21.9","platform":"x86_64-linux","checksum":"d4053012022f7bf47cd54c7c19416f600325e6cc1e1604a631c2fde69dd920a4"},
{"name":"googleapis-common-protos-types","version":"1.3.0","platform":"ruby","checksum":"c5411f3197cc3e02547ded1858303b1f830b4dc89c588c142ad6c8a231050671"},
-{"name":"googleauth","version":"0.14.0","platform":"ruby","checksum":"4659b563d5b2727e775ba9231e75485c1b55ac8fc319e0bf1bc87d5e9705a632"},
+{"name":"googleauth","version":"1.3.0","platform":"ruby","checksum":"51dd7362353cf1e90a2d01e1fb94321ae3926c776d4dc4a79db65230217ffcc2"},
{"name":"gpgme","version":"2.0.20","platform":"ruby","checksum":"fc194689cff40cd4ccafb3086031e930650b3efc15348bbfdf7a2f8b5a826f75"},
{"name":"grape","version":"1.5.2","platform":"ruby","checksum":"1df3b734c3862e235174232bc629587eddda9ef3df648230827575186700ae29"},
{"name":"grape-entity","version":"0.10.0","platform":"ruby","checksum":"9aed1e7cbbc96d9e73f72e5f32c776d4ba8a5baf54c3acda2682008dba2b2cfe"},
@@ -259,11 +269,10 @@
{"name":"hana","version":"1.3.7","platform":"ruby","checksum":"5425db42d651fea08859811c29d20446f16af196308162894db208cac5ce9b0d"},
{"name":"hangouts-chat","version":"0.0.5","platform":"ruby","checksum":"bdbeb6c6e4abc98f395cb273f53b39911b3aa9e248fbbf063242b021ced8b6b6"},
{"name":"hashdiff","version":"1.0.1","platform":"ruby","checksum":"2cd4d04f5080314ecc8403c4e2e00dbaa282dff395e2d031bc16c8d501bdd6db"},
-{"name":"hashie","version":"4.1.0","platform":"ruby","checksum":"7890dcb9ec18a4b66acec797018c73824b89cef5eb8cda36e8e8501845e87a09"},
-{"name":"hashie-forbidden_attributes","version":"0.1.1","platform":"ruby","checksum":"3a6ed37f3a314e4fb1dd1e2df6eb7721bcadd023a30bc0b951b2b5285a790fb2"},
+{"name":"hashie","version":"5.0.0","platform":"ruby","checksum":"9d6c4e51f2a36d4616cbc8a322d619a162d8f42815a792596039fc95595603da"},
{"name":"health_check","version":"3.1.0","platform":"ruby","checksum":"10146508237dc54ed7e24c292d8ba7fb8f9590cf26c66e325b947438c4103b57"},
{"name":"heapy","version":"0.2.0","platform":"ruby","checksum":"74141e845d61ffc7c1e8bf8b127c8cf94544ec7a1181aec613288682543585ea"},
-{"name":"html-pipeline","version":"2.13.2","platform":"ruby","checksum":"a1de83f7bd2d3464f3a068e391b661983fc6099d194c8d9ceb91ace02dadb803"},
+{"name":"html-pipeline","version":"2.14.3","platform":"ruby","checksum":"8a1d4d7128b2141913387cac0f8ba898bb6812557001acc0c2b46910f59413a0"},
{"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"},
@@ -272,13 +281,14 @@
{"name":"http-cookie","version":"1.0.5","platform":"ruby","checksum":"73756d46c7dbdc7023deecdb8a171348ea95a1b99810b31cfe8b4fb4e9a6318f"},
{"name":"http-form_data","version":"2.3.0","platform":"ruby","checksum":"cc4eeb1361d9876821e31d7b1cf0b68f1cf874b201d27903480479d86448a5f3"},
{"name":"http-parser","version":"1.2.3","platform":"ruby","checksum":"414dec1f443d68e1068509f184ee4b93e3442f626645071182ce49bc27db18a3"},
-{"name":"httparty","version":"0.16.4","platform":"ruby","checksum":"62c89d00f5e8933b2d397a49b57deb18ca18e16cb7d862ee4f53b73228dc3d81"},
+{"name":"httparty","version":"0.20.0","platform":"ruby","checksum":"490d2a028a5accc611f1685d479d80ef80b129140d24a93c53c119f578614867"},
{"name":"httpclient","version":"2.8.3","platform":"ruby","checksum":"2951e4991214464c3e92107e46438527d23048e634f3aee91c719e0bdfaebda6"},
{"name":"i18n","version":"1.12.0","platform":"ruby","checksum":"91e3cc1b97616d308707eedee413d82ee021d751c918661fb82152793e64aced"},
{"name":"i18n_data","version":"0.8.0","platform":"ruby","checksum":"92d942cc193dc4a54a95b68f44e52c79e024fa72e09f26a982bc61153b6f0c6c"},
-{"name":"icalendar","version":"2.4.1","platform":"ruby","checksum":"ade7384b3a78d302e01c0b93f66816b734c9abd85d1511b90200de2eee6d5ef7"},
+{"name":"icalendar","version":"2.8.0","platform":"ruby","checksum":"e404f970c7572bdebf6f09f9890970b68aab400ba9e609dc7d46098f28d0ee87"},
+{"name":"ice_cube","version":"0.16.4","platform":"ruby","checksum":"da117e5de24bdc33931be629f9b55048641924442c7e9b72fedc05e5592531b7"},
{"name":"imagen","version":"0.1.8","platform":"ruby","checksum":"fde7b727d4fe79c6bb5ac46c1f7184bf87a6d54df54d712ad2be039d2f93a162"},
-{"name":"invisible_captcha","version":"1.1.0","platform":"ruby","checksum":"3670294a998ab1430ff07cd1697d25c70e6367bdb0dff534df24a14fdee8b4d2"},
+{"name":"invisible_captcha","version":"2.0.0","platform":"ruby","checksum":"a381edcb1d1b8744e9dc398ecad142c3e2ab077604645f85eeb02f9ea535c042"},
{"name":"ipaddr","version":"1.2.2","platform":"ruby","checksum":"27916ee6367d549850d3675bc020f1f1ddafbbe1cfc58635f17dfa56c42f9f79"},
{"name":"ipaddress","version":"0.8.3","platform":"ruby","checksum":"85640c4f9194c26937afc8c78e3074a8e7c97d5d1210358d1440f01034d006f5"},
{"name":"jaeger-client","version":"1.1.0","platform":"ruby","checksum":"cb5e9b9bbee6ee8d6a82d03d947a5b04543d8c0a949c22e484254f18d8a458a8"},
@@ -286,24 +296,24 @@
{"name":"jaro_winkler","version":"1.5.4","platform":"ruby","checksum":"50c3e83c5a9e8769c1cf5b73c8b51bb6eebbf8852a0ee53bf6ad6e4dc63414f9"},
{"name":"jira-ruby","version":"2.1.4","platform":"ruby","checksum":"4267c095cac8323b9eef3ba866eb28bb1388b7623a5abb60c1e7caf12d4adb9e"},
{"name":"jmespath","version":"1.6.1","platform":"ruby","checksum":"40ca83f4141bdd1e503db5485de68b84237183d84cf7a159fbeebcc6005adbd6"},
-{"name":"js_regex","version":"3.7.0","platform":"ruby","checksum":"b13fac68c4416d1a5f21c3bab8a71b4530f424b7c4ff9f46d8e62b895dc05975"},
+{"name":"js_regex","version":"3.8.0","platform":"ruby","checksum":"7934bcdd5a0e6d5af4a520288fd4684a02a472ae55831d9178ccaf82356344b5"},
{"name":"json","version":"2.5.1","platform":"java","checksum":"be284a0c4a9d0373e81b0d5dfe71ed5b18d0479f05970e60a77be89a2978ce6c"},
{"name":"json","version":"2.5.1","platform":"ruby","checksum":"918d8c41dacb7cfdbe0c7bbd6014a5372f0cf1c454ca150e9f4010fe80cc3153"},
{"name":"json-jwt","version":"1.15.3","platform":"ruby","checksum":"66db4f14e538a774c15502a5b5b26b1f3e7585481bbb96df490aa74b5c2d6110"},
{"name":"json_schemer","version":"0.2.18","platform":"ruby","checksum":"3362c21efbefdd12ce994e541a1e7fdb86fd267a6541dd8715e8a580fe3b6be6"},
{"name":"jsonpath","version":"1.1.2","platform":"ruby","checksum":"6804124c244d04418218acb85b15c7caa79c592d7d6970195300428458946d3a"},
{"name":"jwt","version":"2.1.0","platform":"ruby","checksum":"7e7e7ffc1a5ebce628ac7da428341c50615a3a10ac47bb74c22c1cba325613f0"},
-{"name":"kaminari","version":"1.2.1","platform":"ruby","checksum":"03b26388ebb732b708e40b4f1d858c4cbc58d7cb18d12eeb9364176f23c3b3ef"},
-{"name":"kaminari-actionview","version":"1.2.1","platform":"ruby","checksum":"31a3dc6955e7dff95f6133e1f4c03b9dec36d714b632330034ee51b33d0c1770"},
-{"name":"kaminari-activerecord","version":"1.2.1","platform":"ruby","checksum":"8327823ddf8a8e059ce10d9da0c784ef44d5323e9f6d53054e03d26876efc50a"},
-{"name":"kaminari-core","version":"1.2.1","platform":"ruby","checksum":"9ff2f0fa5a454731943a847bbd9960f0b9f859dd6910df5f40d6c9e049660440"},
+{"name":"kaminari","version":"1.2.2","platform":"ruby","checksum":"c4076ff9adccc6109408333f87b5c4abbda5e39dc464bd4c66d06d9f73442a3e"},
+{"name":"kaminari-actionview","version":"1.2.2","platform":"ruby","checksum":"1330f6fc8b59a4a4ef6a549ff8a224797289ebf7a3a503e8c1652535287cc909"},
+{"name":"kaminari-activerecord","version":"1.2.2","platform":"ruby","checksum":"0dd3a67bab356a356f36b3b7236bcb81cef313095365befe8e98057dd2472430"},
+{"name":"kaminari-core","version":"1.2.2","platform":"ruby","checksum":"3bd26fec7370645af40ca73b9426a448d09b8a8ba7afa9ba3c3e0d39cdbb83ff"},
{"name":"kas-grpc","version":"0.0.2","platform":"ruby","checksum":"111ff7515952e939f491297ba4c69a218b72d9d0ef8e5bff80a5df6a56df9a16"},
{"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.9.3","platform":"ruby","checksum":"d5d38e719fbac44f396851aa57cd1b9f4f7dab4410ab680ccd21c9b741230046"},
{"name":"launchy","version":"2.5.0","platform":"ruby","checksum":"954243c4255920982ce682f89a42e76372dba94770bf09c23a523e204bdebef5"},
-{"name":"lefthook","version":"1.1.3","platform":"ruby","checksum":"3f8337b2176f49e6d4ab8f0f4494c8d1be0548d79bca898fbf2184d717092b75"},
+{"name":"lefthook","version":"1.2.0","platform":"ruby","checksum":"189e8c2c91eac4ed115ab67e4d9a3f6b7f280967c45c4ea5fdca7612088c73ab"},
{"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"},
@@ -314,14 +324,14 @@
{"name":"lockbox","version":"0.6.2","platform":"ruby","checksum":"0136677875c3d6e27cef87cd7bd66610404e2b3cd7f07f1ac8ed34e48f18dc3c"},
{"name":"lograge","version":"0.11.2","platform":"ruby","checksum":"4cbd1554b86f545d795eff15a0c24fd25057d2ac4e1caa5fc186168b3da932ef"},
{"name":"loofah","version":"2.19.0","platform":"ruby","checksum":"302791371f473611e342f9e469e7f2fbf1155bb1b3a978a83ac7df625298feba"},
-{"name":"lookbook","version":"1.0.8","platform":"ruby","checksum":"e4b8789c5ff25c6443394da1d6b62966642c324e19c42d7f4cf3b5da2fe75f77"},
+{"name":"lookbook","version":"1.2.1","platform":"ruby","checksum":"742844b625798b689215d1660f711aa79ff54084f5e8735fe674fe771fc165d7"},
{"name":"lru_redux","version":"1.1.0","platform":"ruby","checksum":"ee71d0ccab164c51de146c27b480a68b3631d5b4297b8ffe8eda1c72de87affb"},
{"name":"lumberjack","version":"1.2.7","platform":"ruby","checksum":"a5c6aae6b4234f1420dbcd80b23e3bca0817bd239440dde097ebe3fa63c63b1f"},
{"name":"mail","version":"2.7.1","platform":"ruby","checksum":"ec2a3d489f7510b90d8eaa3f6abaad7038cf1d663cdf8ee66d0214a0bdf99c03"},
{"name":"marcel","version":"1.0.2","platform":"ruby","checksum":"a013b677ef46cbcb49fd5c59b3d35803d2ee04dd75d8bfdc43533fc5a31f7e4e"},
{"name":"marginalia","version":"1.11.1","platform":"ruby","checksum":"cb63212ab63e42746e27595e912cb20408a1a28bcd0edde55d15b7c45fa289cf"},
{"name":"memoist","version":"0.16.2","platform":"ruby","checksum":"a52c53a3f25b5875151670b2f3fd44388633486dc0f09f9a7150ead1e3bf3c45"},
-{"name":"memory_profiler","version":"0.9.14","platform":"ruby","checksum":"de558cf6525d8d56d2c0ea465b1664517fbe45560f892dc7a898d3b8c2863b12"},
+{"name":"memory_profiler","version":"1.0.1","platform":"ruby","checksum":"38cdb42f22d9100df2eba0365c199724b58b05c38e765cd764a07392916901b1"},
{"name":"method_source","version":"1.0.0","platform":"ruby","checksum":"d779455a2b5666a079ce58577bfad8534f571af7cec8107f4dce328f0981dede"},
{"name":"mime-types","version":"3.4.1","platform":"ruby","checksum":"6bcf8b0e656b6ae9977bdc1351ef211d0383252d2f759a59ef4bcf254542fc46"},
{"name":"mime-types-data","version":"3.2022.0105","platform":"ruby","checksum":"d8c401ba9ea8b648b7145b90081789ec714e91fd625d82c5040079c5ea696f00"},
@@ -357,23 +367,24 @@
{"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.13.8","platform":"aarch64-linux","checksum":"d6b2c45a57738f12fe27783939fe1394e7049246288c7770d3b1fee7f49432a6"},
-{"name":"nokogiri","version":"1.13.8","platform":"arm64-darwin","checksum":"00217e48a6995e81dd83014325c0ea0b015023a8922c7bdb2ef1416aa87c1f43"},
-{"name":"nokogiri","version":"1.13.8","platform":"java","checksum":"9d04c616900e2b5118e501436ebb9bc48520d08f3695d012a314006e28082f72"},
-{"name":"nokogiri","version":"1.13.8","platform":"ruby","checksum":"79c279298b2f22fd4e760f49990c7930436bac1b1cfeff7bacff192f30edea3c"},
-{"name":"nokogiri","version":"1.13.8","platform":"x64-mingw-ucrt","checksum":"98f7dac7583f07a84ec3fcc01dc03a66fce10f412cd363fce7de749acdb2a42d"},
-{"name":"nokogiri","version":"1.13.8","platform":"x64-mingw32","checksum":"117a71b37f2e1d774a9f031d393e72d5d04b92af8036e0c1a8dd509c247b2013"},
-{"name":"nokogiri","version":"1.13.8","platform":"x86-linux","checksum":"6d04342456edfb8fbc041d0c2cf5a59baaa7aacdda414b2333100b02f85d441d"},
-{"name":"nokogiri","version":"1.13.8","platform":"x86-mingw32","checksum":"0529d558b4280a55bc7af500d3d4d590b7c059c814a0cea52e4e18cb30c25d15"},
-{"name":"nokogiri","version":"1.13.8","platform":"x86_64-darwin","checksum":"8966d79e687b271df87a4b240456597c43cd98584e3f783fc35de4f066486421"},
-{"name":"nokogiri","version":"1.13.8","platform":"x86_64-linux","checksum":"344f1bc66feac787e5b2053c6e9095d1f33605083e58ddf2b8d4eef257bccc5f"},
+{"name":"nokogiri","version":"1.13.9","platform":"aarch64-linux","checksum":"9b69829561d30c4461ea803baeaf3460e8b145cff7a26ce397119577a4083a02"},
+{"name":"nokogiri","version":"1.13.9","platform":"arm64-darwin","checksum":"e76ebb4b7b2e02c72b2d1541289f8b0679fb5984867cf199d89b8ef485764956"},
+{"name":"nokogiri","version":"1.13.9","platform":"java","checksum":"15bae7d08bddeaa898d8e3f558723300137c26a2dc2632a1f89c8574c4467165"},
+{"name":"nokogiri","version":"1.13.9","platform":"ruby","checksum":"96f37c1baf0234d3ae54c2c89aef7220d4a8a1b03d2675ff7723565b0a095531"},
+{"name":"nokogiri","version":"1.13.9","platform":"x64-mingw-ucrt","checksum":"f6a1dbc7229184357f3129503530af73cc59ceba4932c700a458a561edbe04b9"},
+{"name":"nokogiri","version":"1.13.9","platform":"x64-mingw32","checksum":"36d935d799baa4dc488024f71881ff0bc8b172cecdfc54781169c40ec02cbdb3"},
+{"name":"nokogiri","version":"1.13.9","platform":"x86-linux","checksum":"ebaf82aa9a11b8fafb67873d19ee48efb565040f04c898cdce8ca0cd53ff1a12"},
+{"name":"nokogiri","version":"1.13.9","platform":"x86-mingw32","checksum":"11789a2a11b28bc028ee111f23311461104d8c4468d5b901ab7536b282504154"},
+{"name":"nokogiri","version":"1.13.9","platform":"x86_64-darwin","checksum":"01830e1646803ff91c0fe94bc768ff40082c6de8cfa563dafd01b3f7d5f9d795"},
+{"name":"nokogiri","version":"1.13.9","platform":"x86_64-linux","checksum":"8e93b8adec22958013799c8690d81c2cdf8a90b6f6e8150ab22e11895844d781"},
{"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"},
{"name":"oauth2","version":"2.0.9","platform":"ruby","checksum":"b21f9defcf52dc1610e0dfab4c868342173dcd707fd15c777d9f4f04e153f7fb"},
{"name":"octokit","version":"4.25.1","platform":"ruby","checksum":"c02092ee82dcdfe84db0e0ea630a70d32becc54245a4f0bacfd21c010df09b96"},
{"name":"ohai","version":"16.10.6","platform":"ruby","checksum":"b835806e585faea4ac8346b68c722fb5fc29a29f73fd7e3a022f9073132dec22"},
-{"name":"oj","version":"3.13.21","platform":"ruby","checksum":"aef31a8dcc6f0b9b4bb5cc7ac6cc5272b2d851deb11a1804c2ed6b5501b50e46"},
+{"name":"oj","version":"3.13.23","platform":"ruby","checksum":"206dfdc4020ad9974705037f269cfba211d61b7662a58c717cce771829ccef51"},
+{"name":"oj-introspect","version":"0.7.1","platform":"ruby","checksum":"ea584e78495a62d5356aece7242bb55455d623ad3deb3cd778e623dd19e050c0"},
{"name":"omniauth","version":"2.1.0","platform":"ruby","checksum":"bff7234f5ec9323622b217c7f26d52f850de0b0e2b8c807c3358fc79fe572300"},
{"name":"omniauth-alicloud","version":"2.0.0","platform":"ruby","checksum":"8ecf369d51cd5317c1e7c6b80276891f76cff210a534ec654326af5c62265de3"},
{"name":"omniauth-atlassian-oauth2","version":"0.2.0","platform":"ruby","checksum":"eb07574a188ab8a03376ce288bce86bc2dd4a1382ffa5781cb5e2b7bc15d76c9"},
@@ -411,7 +422,7 @@
{"name":"pg","version":"1.4.3","platform":"x64-mingw-ucrt","checksum":"9f4d1d39af5ae5eea9f3c6b1e3092cbd5d26b716ff0e1283cf71c0690c69b36c"},
{"name":"pg","version":"1.4.3","platform":"x64-mingw32","checksum":"3265afd0e00331c7c70e50d4a13eea9083e5b683ebcd808bd671af70d92b189e"},
{"name":"pg","version":"1.4.3","platform":"x86-mingw32","checksum":"08a6ef4c702e313c1a04ad6b088b1843361ca8606843c7cd607e181e0d4e5508"},
-{"name":"pg_query","version":"2.1.4","platform":"ruby","checksum":"48f1363f88cf9d86fa11d76d1b0f839ca3723b8bd397b7cbc4b578e1ca82d0bb"},
+{"name":"pg_query","version":"2.2.0","platform":"ruby","checksum":"84a37548412f540061bcc52ee2915352297832816bca60e4524c716e03f1e950"},
{"name":"plist","version":"3.6.0","platform":"ruby","checksum":"f468bcf6b72ec6d1585ed6744eb4817c1932a5bf91895ed056e69b7f12ca10f2"},
{"name":"png_quantizator","version":"0.2.1","platform":"ruby","checksum":"6023d4d064125c3a7e02929c95b7320ed6ac0d7341f9e8de0c9ea6576ef3106b"},
{"name":"po_to_json","version":"1.0.1","platform":"ruby","checksum":"6a7188aa6c42a22c9718f9b39062862ef7f3d8f6a7b4177cae058c3308b56af7"},
@@ -455,11 +466,11 @@
{"name":"rbtree","version":"0.4.4","platform":"ruby","checksum":"c1277a502a96fe8fd8656cb619db1ac87145df809ea4db35f7242b50bb161d5c"},
{"name":"rchardet","version":"1.8.0","platform":"ruby","checksum":"693acd5253d5ade81a51940697955f6dd4bb2f0d245bda76a8e23deec70a52c7"},
{"name":"rdoc","version":"6.3.2","platform":"ruby","checksum":"def4a720235c27d56c176ae73555e647eb04ea58a8bbaa927f8f9f79de7805a6"},
-{"name":"re2","version":"1.5.0","platform":"ruby","checksum":"35fe8b408de9f1ef609b1e54e01ea1e55413ca3e9daf1e4b20756d9a02f630cc"},
+{"name":"re2","version":"1.6.0","platform":"ruby","checksum":"2e37f27971f6a76223eac688c04f3e48aea374f34b302ec22d75b4635cd64bc1"},
{"name":"recaptcha","version":"4.13.1","platform":"ruby","checksum":"dc6c2cb78afa87034358b7ba1c6f7175972b5709fdf7500e2550623e119e3788"},
{"name":"recursive-open-struct","version":"1.1.3","platform":"ruby","checksum":"a3538a72552fcebcd0ada657bdff313641a4a5fbc482c08cfb9a65acb1c9de5a"},
{"name":"redcarpet","version":"3.5.1","platform":"ruby","checksum":"717f64cb6ec11c8d9ec9b521ed26ca2eeda68b4fe1fc3388a641176dbd47732f"},
-{"name":"redis","version":"4.7.1","platform":"ruby","checksum":"ecb256d4e53ead3eca05bf394dd100e6a162c136f461fe752ddf5d35b64a2df6"},
+{"name":"redis","version":"4.8.0","platform":"ruby","checksum":"2000cf5014669c9dc821704b6d322a35a9a33852a95208911d9175d63b448a44"},
{"name":"redis-actionpack","version":"5.3.0","platform":"ruby","checksum":"3fb1ad0a8fd9d26a289c9399bb609dcaef38bf37711e6f677a53ca728fc19140"},
{"name":"redis-namespace","version":"1.9.0","platform":"ruby","checksum":"0923961f38cf15b86cb57d92507e0a3b32480729eb5033249f5de8b12e0d8612"},
{"name":"redis-rack","version":"2.1.4","platform":"ruby","checksum":"0872eecb303e483c3863d6bd0d47323d230640d41c1a4ac4a2c7596ec0b1774c"},
@@ -500,7 +511,7 @@
{"name":"rubocop-performance","version":"1.14.3","platform":"ruby","checksum":"ee45ae3e40388ff809d9c5e2ef6ef9d59dc86c59c97110f96d5540267f860751"},
{"name":"rubocop-rails","version":"2.15.2","platform":"ruby","checksum":"1891ab46a6eaf36b841ad27c9c8a22e77a2c3ae85bc334111d3f8075e417643c"},
{"name":"rubocop-rspec","version":"2.12.1","platform":"ruby","checksum":"9278d22d4525261caf30d591eef3d47910a125e74f75f41ffa470acd208423f9"},
-{"name":"ruby-fogbugz","version":"0.2.1","platform":"ruby","checksum":"15b2e7fe7e95b021a94ee6e9d8bb32fdad6ae44e820c2ce0dc312fe6e77d40ca"},
+{"name":"ruby-fogbugz","version":"0.3.0","platform":"ruby","checksum":"5e04cde474648f498a71cf1e1a7ab42c66b953862fbe224f793ec0a7a1d5f657"},
{"name":"ruby-magic","version":"0.5.4","platform":"ruby","checksum":"2c17b185130d10a83791f63a40baa358c4b138af37da3f4dab53690121c421d5"},
{"name":"ruby-progressbar","version":"1.11.0","platform":"ruby","checksum":"cc127db3866dc414ffccbf92928a241e585b3aa2b758a5563e74a6ee0f57d50a"},
{"name":"ruby-saml","version":"1.13.0","platform":"ruby","checksum":"d31cbdf5fb8fdd6aa3187e48dba3085cfeb751af30276a5739aa3659a66f069c"},
@@ -534,7 +545,7 @@
{"name":"sexp_processor","version":"4.15.1","platform":"ruby","checksum":"9291a0f2247f50d15068ee6965b67cd7b678b0d273e18adf3c0b2ea4a890125c"},
{"name":"shellany","version":"0.0.1","platform":"ruby","checksum":"0e127a9132698766d7e752e82cdac8250b6adbd09e6c0a7fbbb6f61964fedee7"},
{"name":"shoulda-matchers","version":"5.1.0","platform":"ruby","checksum":"a01d20589989e9653ab4a28c67d9db2b82bcf0a2496cf01d5e1a95a4aaaf5b07"},
-{"name":"sidekiq","version":"6.4.2","platform":"ruby","checksum":"0d3c05fecb5fbace5ff5efc63da707e02a9c4673fb8e33ceca10b5ec0e9f062c"},
+{"name":"sidekiq","version":"6.5.7","platform":"ruby","checksum":"7d966fd84d42a942615d6874be31e40f8bece841fdd9b96fc53cad22a590555c"},
{"name":"sidekiq-cron","version":"1.8.0","platform":"ruby","checksum":"47da72ca73ce5b71896aaf7e7c4391386ec517dd003f184c50c0b727d82eb0ca"},
{"name":"sigdump","version":"0.2.4","platform":"ruby","checksum":"0bf2176e55c1a262788623fe5ea57caddd6ba2abebe5e349d9d5e7c3a3010ed7"},
{"name":"signet","version":"0.17.0","platform":"ruby","checksum":"1d2831930dc28da32e34bec68cf7ded97ee2867b208f97c500ee293829cb0004"},
@@ -571,6 +582,8 @@
{"name":"sys-filesystem","version":"1.4.3","platform":"ruby","checksum":"390919de89822ad6d3ba3daf694d720be9d83ed95cdf7adf54d4573c98b17421"},
{"name":"sysexits","version":"1.2.0","platform":"ruby","checksum":"598241c4ae57baa403c125182dfdcc0d1ac4c0fb606dd47fbed57e4aaf795662"},
{"name":"tanuki_emoji","version":"0.6.0","platform":"ruby","checksum":"4ce91aefed2d076b73fba3eff50e89660c3d25691787a9fe4c0dfabb4218c12a"},
+{"name":"telesign","version":"2.2.4","platform":"ruby","checksum":"dcc6e96ea7bcb4da1e2ae786bfe7a4d670a4b5f94ae95dfcdde77d547c544c42"},
+{"name":"telesignenterprise","version":"2.2.2","platform":"ruby","checksum":"f147a03263a8c2fe0a0db1a7a9454a6ee37d9e8abd58eaca305bdd8081f9f1b3"},
{"name":"temple","version":"0.8.2","platform":"ruby","checksum":"c12071214346c606dbd219b4117276d04a9f2c20d65e66a66b2c4ec18efc1f18"},
{"name":"term-ansicolor","version":"1.7.1","platform":"ruby","checksum":"92339ffec77c4bddc786a29385c91601dd52fc68feda23609bba0491229b05f7"},
{"name":"terminal-table","version":"1.8.0","platform":"ruby","checksum":"13371f069af18e9baa4e44d404a4ada9301899ce0530c237ac1a96c19f652294"},
@@ -619,7 +632,7 @@
{"name":"validates_hostname","version":"1.0.11","platform":"ruby","checksum":"d506bae0342ec14c920eb319e057fc1886c321a59b85b4b6e966ee4b88fab8c3"},
{"name":"version_gem","version":"1.1.0","platform":"ruby","checksum":"6b009518020db57f51ec7b410213fae2bf692baea9f1b51770db97fbc93d9a80"},
{"name":"version_sorter","version":"2.2.4","platform":"ruby","checksum":"7ad071609edfaa3cf28c42d83b1a03096e43512244ae5a9e2fce1404f7e06d41"},
-{"name":"view_component","version":"2.71.0","platform":"ruby","checksum":"c1880647800d9cfb03ff4ba92313db624a4a4b3d5753e137effe86e5f2b3662b"},
+{"name":"view_component","version":"2.74.1","platform":"ruby","checksum":"0bbd47a9c11455a45043dc01aa604db708654718a4d8755c911425482e8392c0"},
{"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"},
diff --git a/Gemfile.lock b/Gemfile.lock
index 8bf67a41f45..c6345cb7f5d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -172,7 +172,7 @@ GEM
asciidoctor (2.0.17)
asciidoctor-include-ext (0.4.0)
asciidoctor (>= 1.5.6, < 3.0.0)
- asciidoctor-kroki (0.5.0)
+ asciidoctor-kroki (0.7.0)
asciidoctor (~> 2.0)
asciidoctor-plantuml (0.0.16)
asciidoctor (>= 2.0.17, < 3.0.0)
@@ -185,20 +185,20 @@ GEM
awesome_print (1.9.2)
awrence (1.1.1)
aws-eventstream (1.2.0)
- aws-partitions (1.644.0)
+ aws-partitions (1.658.0)
aws-sdk-cloudformation (1.41.0)
aws-sdk-core (~> 3, >= 3.99.0)
aws-sigv4 (~> 1.1)
- aws-sdk-core (3.159.0)
+ aws-sdk-core (3.167.0)
aws-eventstream (~> 1, >= 1.0.2)
- aws-partitions (~> 1, >= 1.525.0)
- aws-sigv4 (~> 1.1)
+ aws-partitions (~> 1, >= 1.651.0)
+ aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
- aws-sdk-kms (1.57.0)
- aws-sdk-core (~> 3, >= 3.127.0)
+ aws-sdk-kms (1.59.0)
+ aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.114.0)
- aws-sdk-core (~> 3, >= 3.127.0)
+ aws-sdk-s3 (1.117.1)
+ aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.1)
@@ -219,8 +219,8 @@ GEM
benchmark (0.2.0)
benchmark-ips (2.3.0)
benchmark-malloc (0.2.0)
- benchmark-memory (0.1.2)
- memory_profiler (~> 0.9)
+ benchmark-memory (0.2.0)
+ memory_profiler (~> 1)
benchmark-perf (0.6.0)
benchmark-trend (0.4.0)
better_errors (2.9.1)
@@ -234,7 +234,7 @@ GEM
bootstrap_form (4.2.0)
actionpack (>= 5.0)
activemodel (>= 5.0)
- browser (4.2.0)
+ browser (5.3.1)
builder (3.2.4)
bullet (7.0.2)
activesupport (>= 3.0.0)
@@ -321,7 +321,7 @@ GEM
gitlab (~> 4.2, >= 4.2.0)
database_cleaner (1.7.0)
dead_end (3.1.1)
- deckar01-task_list (2.3.1)
+ deckar01-task_list (2.3.2)
html-pipeline
declarative (0.0.20)
declarative-option (0.1.0)
@@ -330,7 +330,7 @@ GEM
activerecord (>= 3.2.0, < 7.0)
deprecation_toolkit (1.5.1)
activesupport (>= 4.2)
- derailed_benchmarks (2.1.1)
+ derailed_benchmarks (2.1.2)
benchmark-ips (~> 2)
dead_end
get_process_mem (~> 0)
@@ -448,7 +448,7 @@ GEM
faraday-em_http (1.0.0)
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
- faraday-http-cache (2.4.0)
+ faraday-http-cache (2.4.1)
faraday (>= 0.8)
faraday-httpclient (1.0.1)
faraday-multipart (1.0.4)
@@ -492,7 +492,7 @@ GEM
fog-json
ipaddress (~> 0.8)
xml-simple (~> 1.1)
- fog-aws (3.14.0)
+ fog-aws (3.15.0)
fog-core (~> 2.1)
fog-json (~> 1.1)
fog-xml (~> 0.1)
@@ -501,16 +501,22 @@ GEM
excon (~> 0.58)
formatador (~> 0.2)
mime-types
- fog-google (1.15.0)
- fog-core (<= 2.1.0)
+ fog-google (1.19.0)
+ fog-core (< 2.3)
fog-json (~> 1.2)
fog-xml (~> 0.1.0)
- google-api-client (>= 0.44.2, < 0.51)
+ google-apis-compute_v1 (~> 0.14)
+ google-apis-dns_v1 (~> 0.12)
+ google-apis-iamcredentials_v1 (~> 0.6)
+ google-apis-monitoring_v3 (~> 0.12)
+ google-apis-pubsub_v1 (~> 0.7)
+ google-apis-sqladmin_v1beta4 (~> 0.13)
+ google-apis-storage_v1 (~> 0.6)
google-cloud-env (~> 1.2)
fog-json (1.2.0)
fog-core
multi_json (~> 1.10)
- fog-local (0.6.0)
+ fog-local (0.8.0)
fog-core (>= 1.27, < 3.0)
fog-openstack (1.0.8)
fog-core (~> 2.1)
@@ -533,6 +539,7 @@ GEM
ruby-progressbar (~> 1.4)
fuzzyurl (0.9.0)
gemoji (3.0.1)
+ gems (1.2.0)
get_process_mem (0.2.7)
ffi (~> 1.0)
gettext (3.3.6)
@@ -547,36 +554,35 @@ GEM
rails (>= 3.2.0)
git (1.11.0)
rchardet (~> 1.8)
- gitaly (15.4.0.pre.rc2)
+ gitaly (15.5.0)
grpc (~> 1.0)
- github-markup (1.7.0)
gitlab (4.16.1)
httparty (~> 0.14, >= 0.14.0)
terminal-table (~> 1.5, >= 1.5.1)
gitlab-chronic (0.10.5)
numerizer (~> 0.2)
- gitlab-dangerfiles (3.5.2)
+ gitlab-dangerfiles (3.6.2)
danger (>= 8.4.5)
danger-gitlab (>= 8.0.0)
rake
gitlab-experiment (0.7.1)
activesupport (>= 3.0)
request_store (>= 1.0)
- gitlab-fog-azure-rm (1.3.0)
+ gitlab-fog-azure-rm (1.4.0)
azure-storage-blob (~> 2.0)
azure-storage-common (~> 2.0)
fog-core (= 2.1.0)
fog-json (~> 1.2.0)
mime-types
ms_rest_azure (~> 0.12.0)
- gitlab-labkit (0.24.0)
+ gitlab-labkit (0.28.0)
actionpack (>= 5.0.0, < 8.0.0)
activesupport (>= 5.0.0, < 8.0.0)
grpc (>= 1.37)
jaeger-client (~> 1.1.0)
opentracing (~> 0.4)
pg_query (~> 2.1)
- redis (> 3.0.0, < 5.0.0)
+ redis (> 3.0.0, < 6.0.0)
gitlab-license (2.2.1)
gitlab-mail_room (0.0.9)
gitlab-markup (1.8.1)
@@ -585,7 +591,8 @@ GEM
addressable (~> 2.7)
omniauth (>= 1.9, < 3)
openid_connect (~> 1.2)
- gitlab-sidekiq-fetcher (0.8.0)
+ gitlab-sidekiq-fetcher (0.9.0)
+ json (>= 2.5)
sidekiq (~> 6.1)
gitlab-styles (9.0.0)
rubocop (~> 1.36.0)
@@ -608,27 +615,52 @@ GEM
i18n (>= 0.7)
multi_json
request_store (>= 1.0)
- google-api-client (0.50.0)
+ google-api-client (0.53.0)
+ google-apis-core (~> 0.1)
+ google-apis-generator (~> 0.1)
+ google-apis-compute_v1 (0.53.0)
+ google-apis-core (>= 0.9.0, < 2.a)
+ google-apis-core (0.9.1)
addressable (~> 2.5, >= 2.5.1)
- googleauth (~> 0.9)
- httpclient (>= 2.8.1, < 3.0)
+ googleauth (>= 0.16.2, < 2.a)
+ httpclient (>= 2.8.1, < 3.a)
mini_mime (~> 1.0)
representable (~> 3.0)
- retriable (>= 2.0, < 4.0)
+ retriable (>= 2.0, < 4.a)
rexml
- signet (~> 0.12)
+ webrick
+ google-apis-discovery_v1 (0.12.0)
+ google-apis-core (>= 0.9.0, < 2.a)
+ google-apis-dns_v1 (0.28.0)
+ google-apis-core (>= 0.9.0, < 2.a)
+ google-apis-generator (0.11.0)
+ activesupport (>= 5.0)
+ gems (~> 1.2)
+ google-apis-core (>= 0.9.1, < 2.a)
+ google-apis-discovery_v1 (~> 0.5)
+ thor (>= 0.20, < 2.a)
+ google-apis-iamcredentials_v1 (0.15.0)
+ google-apis-core (>= 0.9.0, < 2.a)
+ google-apis-monitoring_v3 (0.37.0)
+ google-apis-core (>= 0.9.1, < 2.a)
+ google-apis-pubsub_v1 (0.30.0)
+ google-apis-core (>= 0.9.1, < 2.a)
+ google-apis-sqladmin_v1beta4 (0.38.0)
+ google-apis-core (>= 0.9.0, < 2.a)
+ google-apis-storage_v1 (0.20.0)
+ google-apis-core (>= 0.9.1, < 2.a)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
- google-protobuf (3.21.7)
+ google-protobuf (3.21.9)
googleapis-common-protos-types (1.3.0)
google-protobuf (~> 3.14)
- googleauth (0.14.0)
- faraday (>= 0.17.3, < 2.0)
+ 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.14)
+ signet (>= 0.16, < 2.a)
gpgme (2.0.20)
mini_portile2 (~> 2.3)
grape (1.5.2)
@@ -709,14 +741,12 @@ GEM
hana (1.3.7)
hangouts-chat (0.0.5)
hashdiff (1.0.1)
- hashie (4.1.0)
- hashie-forbidden_attributes (0.1.1)
- hashie (>= 3.0)
+ hashie (5.0.0)
health_check (3.1.0)
railties (>= 5.0)
heapy (0.2.0)
thor
- html-pipeline (2.13.2)
+ html-pipeline (2.14.3)
activesupport (>= 2)
nokogiri (>= 1.4)
html2text (0.2.0)
@@ -734,18 +764,20 @@ GEM
http-form_data (2.3.0)
http-parser (1.2.3)
ffi-compiler (>= 1.0, < 2.0)
- httparty (0.16.4)
+ httparty (0.20.0)
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
httpclient (2.8.3)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
i18n_data (0.8.0)
- icalendar (2.4.1)
+ icalendar (2.8.0)
+ ice_cube (~> 0.16)
+ ice_cube (0.16.4)
imagen (0.1.8)
parser (>= 2.5, != 2.5.1.1)
- invisible_captcha (1.1.0)
- rails (>= 4.2)
+ invisible_captcha (2.0.0)
+ rails (>= 5.0)
ipaddr (1.2.2)
ipaddress (0.8.3)
jaeger-client (1.1.0)
@@ -758,9 +790,9 @@ GEM
multipart-post
oauth (~> 0.5, >= 0.5.0)
jmespath (1.6.1)
- js_regex (3.7.0)
+ js_regex (3.8.0)
character_set (~> 1.4)
- regexp_parser (~> 2.1)
+ regexp_parser (~> 2.5)
regexp_property_values (~> 1.0)
json (2.5.1)
json-jwt (1.15.3)
@@ -776,18 +808,18 @@ GEM
jsonpath (1.1.2)
multi_json
jwt (2.1.0)
- kaminari (1.2.1)
+ kaminari (1.2.2)
activesupport (>= 4.1.0)
- kaminari-actionview (= 1.2.1)
- kaminari-activerecord (= 1.2.1)
- kaminari-core (= 1.2.1)
- kaminari-actionview (1.2.1)
+ kaminari-actionview (= 1.2.2)
+ kaminari-activerecord (= 1.2.2)
+ kaminari-core (= 1.2.2)
+ kaminari-actionview (1.2.2)
actionview
- kaminari-core (= 1.2.1)
- kaminari-activerecord (1.2.1)
+ kaminari-core (= 1.2.2)
+ kaminari-activerecord (1.2.2)
activerecord
- kaminari-core (= 1.2.1)
- kaminari-core (1.2.1)
+ kaminari-core (= 1.2.2)
+ kaminari-core (1.2.2)
kas-grpc (0.0.2)
grpc (~> 1.0)
knapsack (1.21.1)
@@ -803,7 +835,7 @@ GEM
rest-client (~> 2.0)
launchy (2.5.0)
addressable (~> 2.7)
- lefthook (1.1.3)
+ lefthook (1.2.0)
letter_opener (1.7.0)
launchy (~> 2.2)
letter_opener_web (2.0.0)
@@ -838,17 +870,19 @@ GEM
loofah (2.19.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
- lookbook (1.0.8)
+ lookbook (1.2.1)
actioncable
+ activemodel
css_parser
htmlbeautifier (~> 1.3)
htmlentities (~> 4.3.4)
listen (~> 3.0)
railties (>= 5.0)
redcarpet (~> 3.5)
- rouge (~> 3.26)
+ rouge (>= 3.26, < 5.0)
view_component (~> 2.0)
yard (~> 0.9.25)
+ zeitwerk (~> 2.5)
lru_redux (1.1.0)
lumberjack (1.2.7)
mail (2.7.1)
@@ -858,7 +892,7 @@ GEM
actionpack (>= 5.2)
activerecord (>= 5.2)
memoist (0.16.2)
- memory_profiler (0.9.14)
+ memory_profiler (1.0.1)
method_source (1.0.0)
mime-types (3.4.1)
mime-types-data (~> 3.2015)
@@ -904,7 +938,7 @@ GEM
netrc (0.11.0)
nio4r (2.5.8)
no_proxy_fix (0.1.2)
- nokogiri (1.13.8)
+ nokogiri (1.13.9)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
notiffany (0.1.3)
@@ -935,7 +969,9 @@ GEM
plist (~> 3.1)
train-core
wmi-lite (~> 1.0)
- oj (3.13.21)
+ oj (3.13.23)
+ oj-introspect (0.7.1)
+ oj (>= 3.13.23)
omniauth (2.1.0)
hashie (>= 3.4.6)
rack (>= 2.2.3)
@@ -1033,7 +1069,7 @@ GEM
peek (1.1.0)
railties (>= 4.0.0)
pg (1.4.3)
- pg_query (2.1.4)
+ pg_query (2.2.0)
google-protobuf (>= 3.19.2)
plist (3.6.0)
png_quantizator (0.2.1)
@@ -1137,12 +1173,12 @@ GEM
rbtree (0.4.4)
rchardet (1.8.0)
rdoc (6.3.2)
- re2 (1.5.0)
+ re2 (1.6.0)
recaptcha (4.13.1)
json
recursive-open-struct (1.1.3)
redcarpet (3.5.1)
- redis (4.7.1)
+ redis (4.8.0)
redis-actionpack (5.3.0)
actionpack (>= 5, < 8)
redis-rack (>= 2.1.0, < 3)
@@ -1247,8 +1283,9 @@ GEM
rubocop (>= 1.7.0, < 2.0)
rubocop-rspec (2.12.1)
rubocop (~> 1.31)
- ruby-fogbugz (0.2.1)
+ ruby-fogbugz (0.3.0)
crack (~> 0.4)
+ multipart-post (~> 2.0)
ruby-magic (0.5.4)
mini_portile2 (~> 2.6)
ruby-progressbar (1.11.0)
@@ -1312,10 +1349,10 @@ GEM
shellany (0.0.1)
shoulda-matchers (5.1.0)
activesupport (>= 5.2.0)
- sidekiq (6.4.2)
- connection_pool (>= 2.2.2)
+ sidekiq (6.5.7)
+ connection_pool (>= 2.2.5)
rack (~> 2.0)
- redis (>= 4.2.0)
+ redis (>= 4.5.0, < 5)
sidekiq-cron (1.8.0)
fugit (~> 1)
sidekiq (>= 4.2.1)
@@ -1398,6 +1435,10 @@ GEM
ffi (~> 1.1)
sysexits (1.2.0)
tanuki_emoji (0.6.0)
+ telesign (2.2.4)
+ net-http-persistent (>= 3.0.0, < 5.0)
+ telesignenterprise (2.2.2)
+ telesign (~> 2.2.3)
temple (0.8.2)
term-ansicolor (1.7.1)
tins (~> 1.0)
@@ -1486,7 +1527,7 @@ GEM
activesupport (>= 3.0)
version_gem (1.1.0)
version_sorter (2.2.4)
- view_component (2.71.0)
+ view_component (2.74.1)
activesupport (>= 5.0.0, < 8.0)
concurrent-ruby (~> 1.0)
method_source (~> 1.0)
@@ -1546,15 +1587,15 @@ DEPENDENCIES
asana (~> 0.10.13)
asciidoctor (~> 2.0.17)
asciidoctor-include-ext (~> 0.4.0)
- asciidoctor-kroki (~> 0.5.0)
+ asciidoctor-kroki (~> 0.7.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.159.0)
- aws-sdk-s3 (~> 1.114.0)
+ aws-sdk-core (~> 3.167.0)
+ aws-sdk-s3 (~> 1.117.1)
babosa (~> 1.0.4)
base32 (~> 0.3.0)
batch-loader (~> 2.0.1)
@@ -1564,7 +1605,7 @@ DEPENDENCIES
better_errors (~> 2.9.1)
bootsnap (~> 1.13.0)
bootstrap_form (~> 4.2.0)
- browser (~> 4.2)
+ browser (~> 5.3.1)
bullet (~> 7.0.2)
bundler-audit (~> 0.7.0.1)
bundler-checksum (~> 0.1.0)!
@@ -1580,7 +1621,7 @@ DEPENDENCIES
crystalball (~> 0.7.0)
cvss-suite (~> 3.0.1)
database_cleaner (~> 1.7.0)
- deckar01-task_list (= 2.3.1)
+ deckar01-task_list (= 2.3.2)
declarative_policy (~> 1.1.0)
default_value_for (~> 3.4.0)
deprecation_toolkit (~> 1.5.1)
@@ -1611,10 +1652,10 @@ DEPENDENCIES
flipper-active_support_cache_store (~> 0.25.0)
flowdock (~> 0.7)
fog-aliyun (~> 0.3)
- fog-aws (~> 3.14)
+ fog-aws (~> 3.15)
fog-core (= 2.1.0)
- fog-google (~> 1.15)
- fog-local (~> 0.6)
+ fog-google (~> 1.19)
+ fog-local (~> 0.8)
fog-openstack (~> 1.0)
fog-rackspace (~> 0.1.1)
fugit (~> 1.2.1)
@@ -1622,25 +1663,24 @@ DEPENDENCIES
gettext (~> 3.3)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)
- gitaly (~> 15.4.0.pre.rc2)
- github-markup (~> 1.7.0)
+ gitaly (~> 15.5.0)
gitlab-chronic (~> 0.10.5)
- gitlab-dangerfiles (~> 3.5.2)
+ gitlab-dangerfiles (~> 3.6.2)
gitlab-experiment (~> 0.7.1)
- gitlab-fog-azure-rm (~> 1.3.0)
- gitlab-labkit (~> 0.24.0)
+ gitlab-fog-azure-rm (~> 1.4.0)
+ gitlab-labkit (~> 0.28.0)
gitlab-license (~> 2.2.1)
gitlab-mail_room (~> 0.0.9)
gitlab-markup (~> 1.8.0)
gitlab-net-dns (~> 0.9.1)
gitlab-omniauth-openid-connect (~> 0.10.0)
- gitlab-sidekiq-fetcher (= 0.8.0)
+ gitlab-sidekiq-fetcher (= 0.9.0)
gitlab-styles (~> 9.0.0)
gitlab_chronic_duration (~> 0.10.6.2)
gitlab_omniauth-ldap (~> 2.2.0)
gon (~> 6.4.0)
google-api-client (~> 0.33)
- google-protobuf (~> 3.21)
+ google-protobuf (~> 3.21, >= 3.21.9)
gpgme (~> 2.0.19)
grape (~> 1.5.2)
grape-entity (~> 0.10.0)
@@ -1659,51 +1699,51 @@ DEPENDENCIES
haml_lint (~> 0.40.0)
hamlit (~> 2.15.0)
hangouts-chat (~> 0.0.5)
- hashie
- hashie-forbidden_attributes
+ hashie (~> 5.0.0)
health_check (~> 3.0)
- html-pipeline (~> 2.13.2)
+ html-pipeline (~> 2.14.3)
html2text
- httparty (~> 0.16.4)
+ httparty (~> 0.20.0)
icalendar
- invisible_captcha (~> 1.1.0)
+ invisible_captcha (~> 2.0.0)
ipaddr (= 1.2.2)
ipaddress (~> 0.8.3)
ipynbdiff!
jira-ruby (~> 2.1.4)
- js_regex (~> 3.7)
+ js_regex (~> 3.8)
json (~> 2.5.1)
json_schemer (~> 0.2.18)
jwt (~> 2.1.0)
- kaminari (~> 1.0)
+ kaminari (~> 1.2.2)
kas-grpc (~> 0.0.2)
knapsack (~> 1.21.1)
kramdown (~> 2.3.1)
kubeclient (~> 4.9.3)
- lefthook (~> 1.1.3)
+ lefthook (~> 1.2.0)
letter_opener_web (~> 2.0.0)
license_finder (~> 7.0)
licensee (~> 9.15)
lockbox (~> 0.6.2)
lograge (~> 0.5)
loofah (~> 2.19.0)
- lookbook (~> 1.0, >= 1.0.8)
+ lookbook (~> 1.2, >= 1.2.1)
lru_redux
mail (= 2.7.1)
mail-smtp_pool (~> 0.1.0)!
marginalia (~> 1.11.1)
- memory_profiler (~> 0.9)
+ memory_profiler (~> 1.0)
microsoft_graph_mailer (~> 0.1.0)!
mini_magick (~> 4.10.1)
minitest (~> 5.11.0)
multi_json (~> 1.14.1)
net-ldap (~> 0.16.3)
net-ntp
- nokogiri (~> 1.13.8)
+ nokogiri (~> 1.13.9)
oauth2 (~> 2.0)
octokit (~> 4.15)
ohai (~> 16.10)
oj (~> 3.13.21)
+ oj-introspect (~> 0.7)
omniauth (~> 2.1.0)
omniauth-alicloud (~> 2.0.0)
omniauth-atlassian-oauth2 (~> 0.2.0)
@@ -1730,7 +1770,7 @@ DEPENDENCIES
parslet (~> 1.8)
peek (~> 1.1)
pg (~> 1.4.3)
- pg_query (~> 2.1.4)
+ pg_query (~> 2.2)
png_quantizator (~> 0.2.1)
premailer-rails (~> 1.10.3)
prometheus-client-mmap (~> 0.16)
@@ -1751,12 +1791,12 @@ DEPENDENCIES
rainbow (~> 3.0)
rbtrace (~> 0.4)
rdoc (~> 6.3.2)
- re2 (~> 1.5.0)
+ re2 (~> 1.6.0)
recaptcha (~> 4.11)
- redis (~> 4.7.0)
+ redis (~> 4.8.0)
redis-actionpack (~> 5.3.0)
redis-namespace (~> 1.9.0)
- request_store (~> 1.5)
+ request_store (~> 1.5.1)
responders (~> 3.0)
retriable (~> 3.1.2)
rexml (~> 3.2.5)
@@ -1769,7 +1809,7 @@ DEPENDENCIES
rspec_junit_formatter
rspec_profiling (~> 0.0.6)
rubocop
- ruby-fogbugz (~> 0.2.1)
+ ruby-fogbugz (~> 0.3.0)
ruby-magic (~> 0.5)
ruby-progressbar (~> 1.10)
ruby-saml (~> 1.13.0)
@@ -1787,7 +1827,7 @@ DEPENDENCIES
sentry-sidekiq (~> 5.1.1)
settingslogic (~> 2.0.9)
shoulda-matchers (~> 5.1.0)
- sidekiq (~> 6.4.0)
+ sidekiq (~> 6.5.7)
sidekiq-cron (~> 1.8.0)
sigdump (~> 0.2.4)
simple_po_parser (~> 1.1.6)
@@ -1807,6 +1847,7 @@ DEPENDENCIES
state_machines-activerecord (~> 0.8.0)
sys-filesystem (~> 1.4.3)
tanuki_emoji (~> 0.6)
+ telesignenterprise (~> 2.2)
terser (= 1.0.2)
test-prof (~> 1.0.7)
test_file_finder (~> 0.1.3)
@@ -1823,7 +1864,7 @@ DEPENDENCIES
valid_email (~> 0.1)
validates_hostname (~> 1.0.11)
version_sorter (~> 2.2.4)
- view_component (~> 2.71.0)
+ view_component (~> 2.74.1)
vmstat (~> 2.3.0)
warning (~> 1.3.0)
webauthn (~> 2.3)
@@ -1833,4 +1874,4 @@ DEPENDENCIES
yajl-ruby (~> 1.4.3)
BUNDLED WITH
- 2.3.23
+ 2.3.25
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 ce5342ad1ea..d24285af5c3 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
@@ -104,18 +104,13 @@ export default {
@[$options.EVENT_ERROR]="onError"
@[$options.EVENT_SUCCESS]="onSuccess"
>
- <div ref="container">
+ <div ref="container" data-testid="access-token-section" data-qa-selector="access_token_section">
<template v-if="newToken">
- <!--
- After issue https://gitlab.com/gitlab-org/gitlab/-/issues/360921 is
- closed remove the `initial-visibility`.
- -->
<input-copy-toggle-visibility
:copy-button-title="copyButtonTitle"
:label="label"
:label-for="$options.tokenInputId"
:value="newToken"
- initial-visibility
:form-input-group-props="formInputGroupProps"
>
<template #description>
diff --git a/app/assets/javascripts/admin/application_settings/runner_token_expiration/index.js b/app/assets/javascripts/admin/application_settings/runner_token_expiration/index.js
index 79d7ff0451a..8c01a3bc607 100644
--- a/app/assets/javascripts/admin/application_settings/runner_token_expiration/index.js
+++ b/app/assets/javascripts/admin/application_settings/runner_token_expiration/index.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import { parseInterval } from '~/runner/utils';
+import { parseInterval } from '~/ci/runner/utils';
import ExpirationIntervals from './components/expiration_intervals.vue';
const initRunnerTokenExpirationIntervals = (selector = '#js-runner-token-expiration-intervals') => {
diff --git a/app/assets/javascripts/admin/users/components/actions/delete.vue b/app/assets/javascripts/admin/users/components/actions/delete.vue
index ae0c6731271..d4f9ff4e529 100644
--- a/app/assets/javascripts/admin/users/components/actions/delete.vue
+++ b/app/assets/javascripts/admin/users/components/actions/delete.vue
@@ -12,6 +12,10 @@ export default {
type: String,
required: true,
},
+ userId: {
+ type: Number,
+ required: true,
+ },
paths: {
type: Object,
required: true,
diff --git a/app/assets/javascripts/admin/users/components/actions/delete_with_contributions.vue b/app/assets/javascripts/admin/users/components/actions/delete_with_contributions.vue
index a39df1cbfb6..413804c9a3b 100644
--- a/app/assets/javascripts/admin/users/components/actions/delete_with_contributions.vue
+++ b/app/assets/javascripts/admin/users/components/actions/delete_with_contributions.vue
@@ -1,17 +1,26 @@
<script>
-import { GlDropdownItem } from '@gitlab/ui';
-import { s__ } from '~/locale';
+import { GlDropdownItem, GlLoadingIcon } from '@gitlab/ui';
+import { s__, __ } from '~/locale';
+import { associationsCount } from '~/api/user_api';
import eventHub, { EVENT_OPEN_DELETE_USER_MODAL } from '../modals/delete_user_modal_event_hub';
export default {
+ i18n: {
+ loading: __('Loading'),
+ },
components: {
GlDropdownItem,
+ GlLoadingIcon,
},
props: {
username: {
type: String,
required: true,
},
+ userId: {
+ type: Number,
+ required: true,
+ },
paths: {
type: Object,
required: true,
@@ -22,21 +31,38 @@ export default {
default: () => [],
},
},
+ data() {
+ return {
+ loading: false,
+ };
+ },
methods: {
- onClick() {
+ async onClick() {
+ this.loading = true;
+ try {
+ const { data: associationsCountData } = await associationsCount(this.userId);
+ this.openModal(associationsCountData);
+ } catch (error) {
+ this.openModal(new Error());
+ } finally {
+ this.loading = false;
+ }
+ },
+ openModal(associationsCountData) {
const { username, paths, userDeletionObstacles } = this;
eventHub.$emit(EVENT_OPEN_DELETE_USER_MODAL, {
username,
blockPath: paths.block,
deletePath: paths.deleteWithContributions,
userDeletionObstacles,
+ associationsCount: associationsCountData,
i18n: {
title: s__('AdminUsers|Delete User %{username} and contributions?'),
primaryButtonLabel: s__('AdminUsers|Delete user and contributions'),
- messageBody: s__(`AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues,
- merge requests, and groups linked to them. To avoid data loss,
- consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd},
- it cannot be undone or recovered.`),
+ messageBody: s__(`AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues,
+ merge requests, groups, and projects linked to them. To avoid data loss,
+ consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd},
+ you cannot undo this action or recover the data.`),
},
});
},
@@ -45,8 +71,12 @@ export default {
</script>
<template>
- <gl-dropdown-item @click="onClick">
- <span class="gl-text-red-500">
+ <gl-dropdown-item :disabled="loading" :aria-busy="loading" @click.capture.native.stop="onClick">
+ <div v-if="loading" class="gl-display-flex gl-align-items-center">
+ <gl-loading-icon class="gl-mr-3" />
+ {{ $options.i18n.loading }}
+ </div>
+ <span v-else class="gl-text-red-500">
<slot></slot>
</span>
</gl-dropdown-item>
diff --git a/app/assets/javascripts/admin/users/components/associations/associations_list.vue b/app/assets/javascripts/admin/users/components/associations/associations_list.vue
new file mode 100644
index 00000000000..12f98a02809
--- /dev/null
+++ b/app/assets/javascripts/admin/users/components/associations/associations_list.vue
@@ -0,0 +1,65 @@
+<script>
+import { GlAlert } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import AssociationsListItem from './associations_list_item.vue';
+
+export default {
+ i18n: {
+ errorMessage: s__(
+ "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted.",
+ ),
+ },
+ components: {
+ AssociationsListItem,
+ GlAlert,
+ },
+ props: {
+ associationsCount: {
+ type: [Object, Error],
+ required: true,
+ },
+ },
+ computed: {
+ hasError() {
+ return this.associationsCount instanceof Error;
+ },
+ hasAssociations() {
+ return Object.values(this.associationsCount).some((count) => count > 0);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-alert v-if="hasError" class="gl-mb-5" variant="danger" :dismissible="false">{{
+ $options.i18n.errorMessage
+ }}</gl-alert>
+ <ul v-else-if="hasAssociations" class="gl-mb-5">
+ <associations-list-item
+ v-if="associationsCount.groups_count"
+ :message="n__('%{count} group', '%{count} groups', associationsCount.groups_count)"
+ :count="associationsCount.groups_count"
+ />
+ <associations-list-item
+ v-if="associationsCount.projects_count"
+ :message="n__('%{count} project', '%{count} projects', associationsCount.projects_count)"
+ :count="associationsCount.projects_count"
+ />
+ <associations-list-item
+ v-if="associationsCount.issues_count"
+ :message="n__('%{count} issue', '%{count} issues', associationsCount.issues_count)"
+ :count="associationsCount.issues_count"
+ />
+ <associations-list-item
+ v-if="associationsCount.merge_requests_count"
+ :message="
+ n__(
+ '%{count} merge request',
+ '%{count} merge requests',
+ associationsCount.merge_requests_count,
+ )
+ "
+ :count="associationsCount.merge_requests_count"
+ />
+ </ul>
+</template>
diff --git a/app/assets/javascripts/admin/users/components/associations/associations_list_item.vue b/app/assets/javascripts/admin/users/components/associations/associations_list_item.vue
new file mode 100644
index 00000000000..88cb24aaf8f
--- /dev/null
+++ b/app/assets/javascripts/admin/users/components/associations/associations_list_item.vue
@@ -0,0 +1,27 @@
+<script>
+import { GlSprintf } from '@gitlab/ui';
+
+export default {
+ components: { GlSprintf },
+ props: {
+ message: {
+ type: String,
+ required: true,
+ },
+ count: {
+ type: Number,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <li>
+ <gl-sprintf :message="message">
+ <template #count>
+ <strong>{{ count }}</strong>
+ </template>
+ </gl-sprintf>
+ </li>
+</template>
diff --git a/app/assets/javascripts/admin/users/components/modals/delete_user_modal.vue b/app/assets/javascripts/admin/users/components/modals/delete_user_modal.vue
index 31fe86775ee..7f02d6dd5b1 100644
--- a/app/assets/javascripts/admin/users/components/modals/delete_user_modal.vue
+++ b/app/assets/javascripts/admin/users/components/modals/delete_user_modal.vue
@@ -2,6 +2,7 @@
import { GlModal, GlButton, GlFormInput, GlSprintf } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
import UserDeletionObstaclesList from '~/vue_shared/components/user_deletion_obstacles/user_deletion_obstacles_list.vue';
+import AssociationsList from '../associations/associations_list.vue';
import eventHub, { EVENT_OPEN_DELETE_USER_MODAL } from './delete_user_modal_event_hub';
export default {
@@ -11,6 +12,7 @@ export default {
GlFormInput,
GlSprintf,
UserDeletionObstaclesList,
+ AssociationsList,
},
props: {
csrfToken: {
@@ -25,6 +27,7 @@ export default {
blockPath: '',
deletePath: '',
userDeletionObstacles: [],
+ associationsCount: {},
i18n: {
title: '',
primaryButtonLabel: '',
@@ -53,11 +56,19 @@ export default {
eventHub.$off(EVENT_OPEN_DELETE_USER_MODAL, this.onOpenEvent);
},
methods: {
- onOpenEvent({ username, blockPath, deletePath, userDeletionObstacles, i18n }) {
+ onOpenEvent({
+ username,
+ blockPath,
+ deletePath,
+ userDeletionObstacles,
+ associationsCount = {},
+ i18n,
+ }) {
this.username = username;
this.blockPath = blockPath;
this.deletePath = deletePath;
this.userDeletionObstacles = userDeletionObstacles;
+ this.associationsCount = associationsCount;
this.i18n = i18n;
this.openModal();
},
@@ -100,8 +111,10 @@ export default {
:user-name="trimmedUsername"
/>
+ <associations-list :associations-count="associationsCount" />
+
<p>
- <gl-sprintf :message="s__('AdminUsers|To confirm, type %{username}')">
+ <gl-sprintf :message="s__('AdminUsers|To confirm, type %{username}.')">
<template #username>
<code data-testid="confirm-username" class="gl-white-space-pre-wrap">{{
trimmedUsername
diff --git a/app/assets/javascripts/admin/users/components/user_actions.vue b/app/assets/javascripts/admin/users/components/user_actions.vue
index 691a292673c..c1fb80959cf 100644
--- a/app/assets/javascripts/admin/users/components/user_actions.vue
+++ b/app/assets/javascripts/admin/users/components/user_actions.vue
@@ -139,6 +139,7 @@ export default {
:key="action"
:paths="userPaths"
:username="user.name"
+ :user-id="user.id"
:user-deletion-obstacles="obstaclesForUserDeletion"
:data-testid="`delete-${action}`"
>
diff --git a/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue b/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
index 6b5aac57f1c..03bc4b825ae 100644
--- a/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
+++ b/app/assets/javascripts/alerts_settings/components/alerts_settings_form.vue
@@ -612,7 +612,7 @@ export default {
>
<alert-settings-form-help-block
:message="viewCredentialsHelpMsg"
- link="https://docs.gitlab.com/ee/operations/incident_management/alert_integrations.html"
+ link="https://docs.gitlab.com/ee/operations/incident_management/integrations.html#configuration"
/>
<gl-form-group id="integration-webhook">
diff --git a/app/assets/javascripts/analytics/shared/components/daterange.vue b/app/assets/javascripts/analytics/shared/components/daterange.vue
index 92ccac59057..a14b0bafecf 100644
--- a/app/assets/javascripts/analytics/shared/components/daterange.vue
+++ b/app/assets/javascripts/analytics/shared/components/daterange.vue
@@ -49,7 +49,7 @@ export default {
return {
maxDateRangeTooltip: sprintf(
__(
- 'Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days.',
+ 'Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days.',
),
{
maxDateRange: this.maxDateRange,
@@ -89,6 +89,8 @@ export default {
:default-max-date="maxDate"
:same-day-selection="includeSelectedDate"
:tooltip="maxDateRangeTooltip"
+ :from-label="__('From')"
+ :to-label="__('To')"
theme="animate-picker"
start-picker-class="js-daterange-picker-from gl-display-flex gl-flex-direction-column gl-lg-flex-direction-row gl-lg-align-items-center gl-lg-mr-3 gl-mb-2 gl-lg-mb-0"
end-picker-class="js-daterange-picker-to gl-display-flex gl-flex-direction-column gl-lg-flex-direction-row gl-lg-align-items-center gl-mb-2 gl-lg-mb-0"
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 b2e554bc913..5bb60d91f1e 100644
--- a/app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue
+++ b/app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue
@@ -240,7 +240,7 @@ export default {
</template>
<template #header>
<gl-dropdown-section-header>{{ __('Projects') }}</gl-dropdown-section-header>
- <gl-search-box-by-type v-model.trim="searchTerm" />
+ <gl-search-box-by-type v-model.trim="searchTerm" :placeholder="__('Search')" />
</template>
<template #highlighted-items>
<gl-dropdown-item
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 ffb61230661..cc7b554f32c 100644
--- a/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue
+++ b/app/assets/javascripts/analytics/shared/components/value_stream_metrics.vue
@@ -1,33 +1,11 @@
<script>
import { GlSkeletonLoader } from '@gitlab/ui';
-import { flatten, isEqual, keyBy } from 'lodash';
+import { isEqual, keyBy } from 'lodash';
import { createAlert } from '~/flash';
import { sprintf, s__ } from '~/locale';
-import { METRICS_POPOVER_CONTENT } from '../constants';
-import { removeFlash, prepareTimeMetricsData } from '../utils';
+import { fetchMetricsData, removeFlash } from '../utils';
import MetricTile from './metric_tile.vue';
-const requestData = ({ request, endpoint, path, params, name }) => {
- return request({ endpoint, params, requestPath: path })
- .then(({ data }) => data)
- .catch(() => {
- const message = sprintf(
- s__(
- 'ValueStreamAnalytics|There was an error while fetching value stream analytics %{requestTypeName} data.',
- ),
- { requestTypeName: name },
- );
- createAlert({ message });
- });
-};
-
-const fetchMetricsData = (reqs = [], path, params) => {
- const promises = reqs.map((r) => requestData({ ...r, path, params }));
- return Promise.all(promises).then((responses) =>
- prepareTimeMetricsData(flatten(responses), METRICS_POPOVER_CONTENT),
- );
-};
-
const extractMetricsGroupData = (keyList = [], data = []) => {
if (!keyList.length || !data.length) return [];
const kv = keyBy(data, 'identifier');
@@ -111,7 +89,15 @@ export default {
this.isLoading = false;
})
- .catch(() => {
+ .catch((err) => {
+ const message = sprintf(
+ s__(
+ 'ValueStreamAnalytics|There was an error while fetching value stream analytics %{requestTypeName} data.',
+ ),
+ { requestTypeName: err.message },
+ );
+
+ createAlert({ message });
this.isLoading = false;
});
},
diff --git a/app/assets/javascripts/analytics/shared/utils.js b/app/assets/javascripts/analytics/shared/utils.js
index bc52e38fc81..71b719d1ed2 100644
--- a/app/assets/javascripts/analytics/shared/utils.js
+++ b/app/assets/javascripts/analytics/shared/utils.js
@@ -1,8 +1,9 @@
+import { flatten } from 'lodash';
import { hideFlash } from '~/flash';
import dateFormat from '~/lib/dateformat';
import { slugify } from '~/lib/utils/text_utility';
import { urlQueryToFilter } from '~/vue_shared/components/filtered_search_bar/filtered_search_utils';
-import { dateFormats } from './constants';
+import { dateFormats, METRICS_POPOVER_CONTENT } from './constants';
export const filterBySearchTerm = (data = [], searchTerm = '', filterByKey = 'name') => {
if (!searchTerm?.length) return data;
@@ -96,3 +97,28 @@ export const prepareTimeMetricsData = (data = [], popoverContent = {}) =>
description: popoverContent[metricIdentifier]?.description || '',
};
});
+
+const requestData = ({ request, endpoint, requestPath, params, name }) => {
+ return request({ endpoint, params, requestPath })
+ .then(({ data }) => data)
+ .catch(() => {
+ throw new Error(name);
+ });
+};
+
+/**
+ * Takes a configuration array of metrics requests (key metrics and DORA) and returns
+ * a flat array of all the responses. Different metrics are retrieved from different endpoints
+ * additionally we only support certain metrics for FOSS users.
+ *
+ * @param {Array} requests - array of metric api requests to be made
+ * @param {String} requestPath - path for the group / project we are requesting
+ * @param {Object} params - optional parameters to filter, including `created_after` and `created_before` dates
+ * @returns a flat array of metrics
+ */
+export const fetchMetricsData = (requests = [], requestPath, params) => {
+ const promises = requests.map((r) => requestData({ ...r, requestPath, params }));
+ return Promise.all(promises).then((responses) =>
+ prepareTimeMetricsData(flatten(responses), METRICS_POPOVER_CONTENT),
+ );
+};
diff --git a/app/assets/javascripts/api/groups_api.js b/app/assets/javascripts/api/groups_api.js
index 48cf346d0e6..e859160c2e7 100644
--- a/app/assets/javascripts/api/groups_api.js
+++ b/app/assets/javascripts/api/groups_api.js
@@ -5,6 +5,7 @@ import { buildApiUrl } from './api_utils';
const GROUP_PATH = '/api/:version/groups/:id';
const GROUPS_PATH = '/api/:version/groups.json';
const DESCENDANT_GROUPS_PATH = '/api/:version/groups/:id/descendant_groups';
+const GROUP_TRANSFER_LOCATIONS_PATH = 'api/:version/groups/:id/transfer_locations';
const axiosGet = (url, query, options, callback) => {
return axios
@@ -37,3 +38,10 @@ export function updateGroup(groupId, data = {}) {
return axios.put(url, data);
}
+
+export const getGroupTransferLocations = (groupId, params = {}) => {
+ const url = buildApiUrl(GROUP_TRANSFER_LOCATIONS_PATH).replace(':id', groupId);
+ const defaultParams = { per_page: DEFAULT_PER_PAGE };
+
+ return axios.get(url, { params: { ...defaultParams, ...params } });
+};
diff --git a/app/assets/javascripts/api/user_api.js b/app/assets/javascripts/api/user_api.js
index 369abe95d49..0f874e35684 100644
--- a/app/assets/javascripts/api/user_api.js
+++ b/app/assets/javascripts/api/user_api.js
@@ -12,6 +12,7 @@ const USER_PROJECTS_PATH = '/api/:version/users/:id/projects';
const USER_POST_STATUS_PATH = '/api/:version/user/status';
const USER_FOLLOW_PATH = '/api/:version/users/:id/follow';
const USER_UNFOLLOW_PATH = '/api/:version/users/:id/unfollow';
+const USER_ASSOCIATIONS_COUNT_PATH = '/api/:version/users/:id/associations_count';
export function getUsers(query, options) {
const url = buildApiUrl(USERS_PATH);
@@ -81,3 +82,8 @@ export function unfollowUser(userId) {
const url = buildApiUrl(USER_UNFOLLOW_PATH).replace(':id', encodeURIComponent(userId));
return axios.post(url);
}
+
+export function associationsCount(userId) {
+ const url = buildApiUrl(USER_ASSOCIATIONS_COUNT_PATH).replace(':id', encodeURIComponent(userId));
+ return axios.get(url);
+}
diff --git a/app/assets/javascripts/artifacts/components/artifact_delete_modal.vue b/app/assets/javascripts/artifacts/components/artifact_delete_modal.vue
new file mode 100644
index 00000000000..14edd73824e
--- /dev/null
+++ b/app/assets/javascripts/artifacts/components/artifact_delete_modal.vue
@@ -0,0 +1,54 @@
+<script>
+import { GlModal } from '@gitlab/ui';
+
+import {
+ I18N_MODAL_TITLE,
+ I18N_MODAL_BODY,
+ I18N_MODAL_PRIMARY,
+ I18N_MODAL_CANCEL,
+} from '../constants';
+
+export default {
+ components: {
+ GlModal,
+ },
+ props: {
+ artifactName: {
+ type: String,
+ required: true,
+ },
+ deleteInProgress: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ actionPrimary() {
+ return {
+ text: I18N_MODAL_PRIMARY,
+ attributes: { variant: 'danger', loading: this.deleteInProgress },
+ };
+ },
+ },
+ actionCancel: { text: I18N_MODAL_CANCEL },
+ i18n: {
+ title: I18N_MODAL_TITLE,
+ body: I18N_MODAL_BODY,
+ },
+};
+</script>
+
+<template>
+ <gl-modal
+ ref="modal"
+ modal-id="artifact-delete-modal"
+ size="sm"
+ :title="$options.i18n.title(artifactName)"
+ :action-primary="actionPrimary"
+ :action-cancel="$options.actionCancel"
+ v-bind="$attrs"
+ v-on="$listeners"
+ >
+ {{ $options.i18n.body }}
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/artifacts/components/artifact_row.vue b/app/assets/javascripts/artifacts/components/artifact_row.vue
new file mode 100644
index 00000000000..8c03db2acd1
--- /dev/null
+++ b/app/assets/javascripts/artifacts/components/artifact_row.vue
@@ -0,0 +1,87 @@
+<script>
+import { GlButtonGroup, GlButton, GlBadge, GlFriendlyWrap } from '@gitlab/ui';
+import { numberToHumanSize } from '~/lib/utils/number_utils';
+import { I18N_EXPIRED, I18N_DOWNLOAD, I18N_DELETE } from '../constants';
+
+export default {
+ name: 'ArtifactRow',
+ components: {
+ GlButtonGroup,
+ GlButton,
+ GlBadge,
+ GlFriendlyWrap,
+ },
+ props: {
+ artifact: {
+ type: Object,
+ required: true,
+ },
+ isLastRow: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ isExpired() {
+ if (!this.artifact.expireAt) {
+ return false;
+ }
+ return Date.now() > new Date(this.artifact.expireAt).getTime();
+ },
+ artifactSize() {
+ return numberToHumanSize(this.artifact.size);
+ },
+ },
+ i18n: {
+ expired: I18N_EXPIRED,
+ download: I18N_DOWNLOAD,
+ delete: I18N_DELETE,
+ },
+};
+</script>
+<template>
+ <div
+ class="gl-py-4"
+ :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
+ class="gl-w-half gl-pl-8 gl-display-flex gl-align-items-center"
+ data-testid="job-artifact-row-name"
+ >
+ <gl-friendly-wrap :text="artifact.name" />
+ <gl-badge size="sm" variant="neutral" class="gl-ml-2">
+ {{ artifact.fileType.toLowerCase() }}
+ </gl-badge>
+ <gl-badge v-if="isExpired" size="sm" variant="warning" icon="expire" class="gl-ml-2">
+ {{ $options.i18n.expired }}
+ </gl-badge>
+ </span>
+
+ <span class="gl-w-quarter gl-text-right gl-pr-5" data-testid="job-artifact-row-size">
+ {{ artifactSize }}
+ </span>
+
+ <span class="gl-w-quarter gl-text-right gl-pr-5">
+ <gl-button-group>
+ <gl-button
+ category="tertiary"
+ icon="download"
+ :title="$options.i18n.download"
+ :aria-label="$options.i18n.download"
+ :href="artifact.downloadPath"
+ data-testid="job-artifact-row-download-button"
+ />
+ <gl-button
+ category="tertiary"
+ icon="remove"
+ :title="$options.i18n.delete"
+ :aria-label="$options.i18n.delete"
+ data-testid="job-artifact-row-delete-button"
+ @click="$emit('delete')"
+ />
+ </gl-button-group>
+ </span>
+ </div>
+ </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
new file mode 100644
index 00000000000..4a826d0d462
--- /dev/null
+++ b/app/assets/javascripts/artifacts/components/artifacts_table_row_details.vue
@@ -0,0 +1,118 @@
+<script>
+import { createAlert } from '~/flash';
+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';
+import { removeArtifactFromStore } from '../graphql/cache_update';
+import {
+ I18N_DESTROY_ERROR,
+ ARTIFACT_ROW_HEIGHT,
+ ARTIFACTS_SHOWN_WITHOUT_SCROLLING,
+} from '../constants';
+import ArtifactRow from './artifact_row.vue';
+import ArtifactDeleteModal from './artifact_delete_modal.vue';
+
+export default {
+ name: 'ArtifactsTableRowDetails',
+ components: {
+ DynamicScroller,
+ DynamicScrollerItem,
+ ArtifactRow,
+ ArtifactDeleteModal,
+ },
+ props: {
+ artifacts: {
+ type: Object,
+ required: true,
+ },
+ queryVariables: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ isModalVisible: false,
+ deleteInProgress: false,
+ deletingArtifactId: null,
+ deletingArtifactName: '',
+ };
+ },
+ computed: {
+ scrollContainerStyle() {
+ /*
+ limit the height of the expanded artifacts container to a number of artifacts
+ if a job has more artifacts than ARTIFACTS_SHOWN_WITHOUT_SCROLLING, scroll to see the rest
+ add one pixel to row height to account for borders
+ */
+ return { maxHeight: `${ARTIFACTS_SHOWN_WITHOUT_SCROLLING * (ARTIFACT_ROW_HEIGHT + 1)}px` };
+ },
+ },
+ methods: {
+ isLastRow(index) {
+ return index === this.artifacts.nodes.length - 1;
+ },
+ showModal(item) {
+ this.deletingArtifactId = item.id;
+ this.deletingArtifactName = item.name;
+ this.isModalVisible = true;
+ },
+ hideModal() {
+ this.isModalVisible = false;
+ },
+ clearModal() {
+ this.deletingArtifactId = null;
+ this.deletingArtifactName = '';
+ },
+ destroyArtifact() {
+ const id = this.deletingArtifactId;
+ this.deleteInProgress = true;
+
+ this.$apollo
+ .mutate({
+ mutation: destroyArtifactMutation,
+ variables: { id },
+ update: (store) => {
+ removeArtifactFromStore(store, id, getJobArtifactsQuery, this.queryVariables);
+ },
+ })
+ .catch(() => {
+ createAlert({
+ message: I18N_DESTROY_ERROR,
+ });
+ this.$emit('refetch');
+ })
+ .finally(() => {
+ this.deleteInProgress = false;
+ this.clearModal();
+ });
+ },
+ },
+ ARTIFACT_ROW_HEIGHT,
+};
+</script>
+<template>
+ <div :style="scrollContainerStyle">
+ <dynamic-scroller :items="artifacts.nodes" :min-item-size="$options.ARTIFACT_ROW_HEIGHT">
+ <template #default="{ item, index, active }">
+ <dynamic-scroller-item :item="item" :active="active" :class="{ active }">
+ <artifact-row
+ :artifact="item"
+ :is-last-row="isLastRow(index)"
+ @delete="showModal(item)"
+ />
+ </dynamic-scroller-item>
+ </template>
+ </dynamic-scroller>
+ <artifact-delete-modal
+ :artifact-name="deletingArtifactName"
+ :visible="isModalVisible"
+ :delete-in-progress="deleteInProgress"
+ @primary="destroyArtifact"
+ @cancel="hideModal"
+ @close="hideModal"
+ @hide="hideModal"
+ @hidden="clearModal"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/artifacts/components/job_artifacts_table.vue b/app/assets/javascripts/artifacts/components/job_artifacts_table.vue
new file mode 100644
index 00000000000..34e443f4e58
--- /dev/null
+++ b/app/assets/javascripts/artifacts/components/job_artifacts_table.vue
@@ -0,0 +1,337 @@
+<script>
+import {
+ GlLoadingIcon,
+ GlTable,
+ GlLink,
+ GlButtonGroup,
+ GlButton,
+ GlBadge,
+ GlIcon,
+ GlPagination,
+} from '@gitlab/ui';
+import { createAlert } from '~/flash';
+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 getJobArtifactsQuery from '../graphql/queries/get_job_artifacts.query.graphql';
+import { totalArtifactsSizeForJob, mapArchivesToJobNodes, mapBooleansToJobNodes } from '../utils';
+import {
+ STATUS_BADGE_VARIANTS,
+ I18N_DOWNLOAD,
+ I18N_BROWSE,
+ I18N_DELETE,
+ I18N_EXPIRED,
+ I18N_DESTROY_ERROR,
+ I18N_FETCH_ERROR,
+ I18N_ARTIFACTS,
+ I18N_JOB,
+ I18N_SIZE,
+ I18N_CREATED,
+ I18N_ARTIFACTS_COUNT,
+ INITIAL_CURRENT_PAGE,
+ INITIAL_PREVIOUS_PAGE_CURSOR,
+ INITIAL_NEXT_PAGE_CURSOR,
+ JOBS_PER_PAGE,
+ INITIAL_LAST_PAGE_SIZE,
+} from '../constants';
+import ArtifactsTableRowDetails from './artifacts_table_row_details.vue';
+
+const INITIAL_PAGINATION_STATE = {
+ currentPage: INITIAL_CURRENT_PAGE,
+ prevPageCursor: INITIAL_PREVIOUS_PAGE_CURSOR,
+ nextPageCursor: INITIAL_NEXT_PAGE_CURSOR,
+ firstPageSize: JOBS_PER_PAGE,
+ lastPageSize: INITIAL_LAST_PAGE_SIZE,
+};
+
+export default {
+ name: 'JobArtifactsTable',
+ components: {
+ GlLoadingIcon,
+ GlTable,
+ GlLink,
+ GlButtonGroup,
+ GlButton,
+ GlBadge,
+ GlIcon,
+ GlPagination,
+ CiIcon,
+ TimeAgo,
+ ArtifactsTableRowDetails,
+ },
+ inject: ['projectPath'],
+ apollo: {
+ jobArtifacts: {
+ query: getJobArtifactsQuery,
+ variables() {
+ return this.queryVariables;
+ },
+ update({ project: { jobs: { nodes = [], pageInfo = {}, count = 0 } = {} } }) {
+ this.pageInfo = pageInfo;
+ this.count = count;
+ return nodes
+ .map(mapArchivesToJobNodes)
+ .map(mapBooleansToJobNodes)
+ .map((jobNode) => {
+ return {
+ ...jobNode,
+ // GlTable uses an item's _showDetails attribute to determine whether
+ // it should show the <template #row-details /> for its table row
+ _showDetails: this.expandedJobs.includes(jobNode.id),
+ };
+ });
+ },
+ error() {
+ createAlert({
+ message: I18N_FETCH_ERROR,
+ });
+ },
+ },
+ },
+ data() {
+ return {
+ jobArtifacts: [],
+ count: 0,
+ pageInfo: {},
+ expandedJobs: [],
+ pagination: INITIAL_PAGINATION_STATE,
+ };
+ },
+ computed: {
+ queryVariables() {
+ return {
+ projectPath: this.projectPath,
+ firstPageSize: this.pagination.firstPageSize,
+ lastPageSize: this.pagination.lastPageSize,
+ prevPageCursor: this.pagination.prevPageCursor,
+ nextPageCursor: this.pagination.nextPageCursor,
+ };
+ },
+ showPagination() {
+ return this.count > JOBS_PER_PAGE;
+ },
+ prevPage() {
+ return Number(this.pageInfo.hasPreviousPage);
+ },
+ nextPage() {
+ return Number(this.pageInfo.hasNextPage);
+ },
+ },
+ methods: {
+ refetchArtifacts() {
+ this.$apollo.queries.jobArtifacts.refetch();
+ },
+ artifactsSize(item) {
+ return totalArtifactsSizeForJob(item);
+ },
+ pipelineId(item) {
+ const id = getIdFromGraphQLId(item.pipeline.id);
+ return `#${id}`;
+ },
+ handlePageChange(page) {
+ const { startCursor, endCursor } = this.pageInfo;
+
+ if (page > this.pagination.currentPage) {
+ this.pagination = {
+ ...INITIAL_PAGINATION_STATE,
+ nextPageCursor: endCursor,
+ currentPage: page,
+ };
+ } else {
+ this.pagination = {
+ lastPageSize: JOBS_PER_PAGE,
+ firstPageSize: null,
+ prevPageCursor: startCursor,
+ currentPage: page,
+ };
+ }
+ },
+ handleRowToggle(toggleDetails, hasArtifacts, id, detailsShowing) {
+ if (!hasArtifacts) return;
+ toggleDetails();
+
+ if (!detailsShowing) {
+ this.expandedJobs.push(id);
+ } else {
+ this.expandedJobs.splice(this.expandedJobs.indexOf(id), 1);
+ }
+ },
+ downloadPath(job) {
+ return job.archive?.downloadPath;
+ },
+ downloadButtonDisabled(job) {
+ return !job.archive?.downloadPath;
+ },
+ browseButtonDisabled(job) {
+ return !job.browseArtifactsPath;
+ },
+ },
+ fields: [
+ {
+ key: 'artifacts',
+ label: I18N_ARTIFACTS,
+ thClass: 'gl-w-quarter',
+ },
+ {
+ key: 'job',
+ label: I18N_JOB,
+ thClass: 'gl-w-35p',
+ },
+ {
+ key: 'size',
+ label: I18N_SIZE,
+ thClass: 'gl-w-15p gl-text-right',
+ tdClass: 'gl-text-right',
+ },
+ {
+ key: 'created',
+ label: I18N_CREATED,
+ thClass: 'gl-w-eighth gl-text-center',
+ tdClass: 'gl-text-center',
+ },
+ {
+ key: 'actions',
+ label: '',
+ thClass: 'gl-w-eighth',
+ tdClass: 'gl-text-right',
+ },
+ ],
+ STATUS_BADGE_VARIANTS,
+ i18n: {
+ download: I18N_DOWNLOAD,
+ browse: I18N_BROWSE,
+ delete: I18N_DELETE,
+ expired: I18N_EXPIRED,
+ destroyArtifactError: I18N_DESTROY_ERROR,
+ fetchArtifactsError: I18N_FETCH_ERROR,
+ artifactsLabel: I18N_ARTIFACTS,
+ jobLabel: I18N_JOB,
+ sizeLabel: I18N_SIZE,
+ createdLabel: I18N_CREATED,
+ artifactsCount: I18N_ARTIFACTS_COUNT,
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-table
+ :items="jobArtifacts"
+ :fields="$options.fields"
+ :busy="$apollo.queries.jobArtifacts.loading"
+ stacked="sm"
+ details-td-class="gl-bg-gray-10! gl-p-0! gl-overflow-auto"
+ >
+ <template #table-busy>
+ <gl-loading-icon size="lg" />
+ </template>
+ <template
+ #cell(artifacts)="{ item: { id, artifacts, hasArtifacts }, toggleDetails, detailsShowing }"
+ >
+ <span
+ :class="{ 'gl-cursor-pointer': hasArtifacts }"
+ data-testid="job-artifacts-count"
+ @click="handleRowToggle(toggleDetails, hasArtifacts, id, detailsShowing)"
+ >
+ <gl-icon
+ v-if="hasArtifacts"
+ :name="detailsShowing ? 'chevron-down' : 'chevron-right'"
+ class="gl-mr-2"
+ />
+ <strong>
+ {{ $options.i18n.artifactsCount(artifacts.nodes.length) }}
+ </strong>
+ </span>
+ </template>
+ <template #cell(job)="{ item }">
+ <span class="gl-display-inline-flex gl-align-items-center gl-w-full gl-mb-4">
+ <span data-testid="job-artifacts-job-status">
+ <ci-icon v-if="item.succeeded" :status="item.detailedStatus" class="gl-mr-3" />
+ <gl-badge
+ v-else
+ :icon="item.detailedStatus.icon"
+ :variant="$options.STATUS_BADGE_VARIANTS[item.detailedStatus.group]"
+ class="gl-mr-3"
+ >
+ {{ item.detailedStatus.label }}
+ </gl-badge>
+ </span>
+ <gl-link :href="item.webPath" class="gl-font-weight-bold">
+ {{ item.name }}
+ </gl-link>
+ </span>
+ <span class="gl-display-inline-flex">
+ <gl-icon name="pipeline" class="gl-mr-2" />
+ <gl-link
+ :href="item.pipeline.path"
+ class="gl-text-black-normal gl-text-decoration-underline gl-mr-4"
+ >
+ {{ pipelineId(item) }}
+ </gl-link>
+ <gl-icon name="branch" class="gl-mr-2" />
+ <gl-link
+ :href="item.refPath"
+ class="gl-text-black-normal gl-text-decoration-underline gl-mr-4"
+ >
+ {{ item.refName }}
+ </gl-link>
+ <gl-icon name="commit" class="gl-mr-2" />
+ <gl-link
+ :href="item.commitPath"
+ class="gl-text-black-normal gl-text-decoration-underline gl-mr-4"
+ >
+ {{ item.shortSha }}
+ </gl-link>
+ </span>
+ </template>
+ <template #cell(size)="{ item }">
+ <span data-testid="job-artifacts-size">{{ artifactsSize(item) }}</span>
+ </template>
+ <template #cell(created)="{ item }">
+ <time-ago data-testid="job-artifacts-created" :time="item.finishedAt" />
+ </template>
+ <template #cell(actions)="{ item }">
+ <gl-button-group>
+ <gl-button
+ icon="download"
+ :disabled="downloadButtonDisabled(item)"
+ :href="downloadPath(item)"
+ :title="$options.i18n.download"
+ :aria-label="$options.i18n.download"
+ data-testid="job-artifacts-download-button"
+ />
+ <gl-button
+ icon="folder-open"
+ :disabled="browseButtonDisabled(item)"
+ :href="item.browseArtifactsPath"
+ :title="$options.i18n.browse"
+ :aria-label="$options.i18n.browse"
+ data-testid="job-artifacts-browse-button"
+ />
+ <gl-button
+ icon="remove"
+ :title="$options.i18n.delete"
+ :aria-label="$options.i18n.delete"
+ data-testid="job-artifacts-delete-button"
+ disabled
+ />
+ </gl-button-group>
+ </template>
+ <template #row-details="{ item: { artifacts } }">
+ <artifacts-table-row-details
+ :artifacts="artifacts"
+ :query-variables="queryVariables"
+ @refetch="refetchArtifacts"
+ />
+ </template>
+ </gl-table>
+ <gl-pagination
+ v-if="showPagination"
+ :value="pagination.currentPage"
+ :prev-page="prevPage"
+ :next-page="nextPage"
+ align="center"
+ class="gl-mt-3"
+ @input="handlePageChange"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/artifacts/constants.js b/app/assets/javascripts/artifacts/constants.js
new file mode 100644
index 00000000000..5fcc4f2b76e
--- /dev/null
+++ b/app/assets/javascripts/artifacts/constants.js
@@ -0,0 +1,55 @@
+import { __, s__, n__, sprintf } from '~/locale';
+
+export const JOB_STATUS_GROUP_SUCCESS = 'success';
+
+export const STATUS_BADGE_VARIANTS = {
+ success: 'success',
+ passed: 'success',
+ error: 'danger',
+ failed: 'danger',
+ pending: 'warning',
+ 'waiting-for-resource': 'warning',
+ 'failed-with-warnings': 'warning',
+ 'success-with-warnings': 'warning',
+ running: 'info',
+ canceled: 'neutral',
+ disabled: 'neutral',
+ scheduled: 'neutral',
+ manual: 'neutral',
+ notification: 'muted',
+ preparing: 'muted',
+ created: 'muted',
+ skipped: 'muted',
+ notfound: 'muted',
+};
+
+export const I18N_DOWNLOAD = __('Download');
+export const I18N_BROWSE = s__('Artifacts|Browse');
+export const I18N_DELETE = __('Delete');
+export const I18N_EXPIRED = __('Expired');
+export const I18N_DESTROY_ERROR = s__('Artifacts|An error occurred while deleting the artifact');
+export const I18N_FETCH_ERROR = s__('Artifacts|An error occurred while retrieving job artifacts');
+export const I18N_ARTIFACTS = __('Artifacts');
+export const I18N_JOB = __('Job');
+export const I18N_SIZE = __('Size');
+export const I18N_CREATED = __('Created');
+export const I18N_ARTIFACTS_COUNT = (count) => n__('%d file', '%d files', count);
+
+export const I18N_MODAL_TITLE = (artifactName) =>
+ sprintf(s__('Artifacts|Delete %{name}?'), { name: artifactName });
+export const I18N_MODAL_BODY = s__(
+ 'Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty.',
+);
+export const I18N_MODAL_PRIMARY = s__('Artifacts|Delete artifact');
+export const I18N_MODAL_CANCEL = __('Cancel');
+
+export const INITIAL_CURRENT_PAGE = 1;
+export const INITIAL_PREVIOUS_PAGE_CURSOR = '';
+export const INITIAL_NEXT_PAGE_CURSOR = '';
+export const JOBS_PER_PAGE = 20;
+export const INITIAL_LAST_PAGE_SIZE = null;
+
+export const ARCHIVE_FILE_TYPE = 'ARCHIVE';
+
+export const ARTIFACT_ROW_HEIGHT = 56;
+export const ARTIFACTS_SHOWN_WITHOUT_SCROLLING = 4;
diff --git a/app/assets/javascripts/artifacts/graphql/cache_update.js b/app/assets/javascripts/artifacts/graphql/cache_update.js
new file mode 100644
index 00000000000..9fa6114c7d4
--- /dev/null
+++ b/app/assets/javascripts/artifacts/graphql/cache_update.js
@@ -0,0 +1,30 @@
+import produce from 'immer';
+
+export const hasErrors = ({ errors = [] }) => errors?.length;
+
+export function removeArtifactFromStore(store, deletedArtifactId, query, variables) {
+ if (hasErrors(deletedArtifactId)) return;
+
+ const sourceData = store.readQuery({
+ query,
+ variables,
+ });
+
+ const data = produce(sourceData, (draftData) => {
+ draftData.project.jobs.nodes = draftData.project.jobs.nodes.map((jobNode) => {
+ return {
+ ...jobNode,
+ artifacts: {
+ ...jobNode.artifacts,
+ nodes: jobNode.artifacts.nodes.filter(({ id }) => id !== deletedArtifactId),
+ },
+ };
+ });
+ });
+
+ store.writeQuery({
+ query,
+ variables,
+ data,
+ });
+}
diff --git a/app/assets/javascripts/artifacts/graphql/mutations/destroy_artifact.mutation.graphql b/app/assets/javascripts/artifacts/graphql/mutations/destroy_artifact.mutation.graphql
new file mode 100644
index 00000000000..529224b47e6
--- /dev/null
+++ b/app/assets/javascripts/artifacts/graphql/mutations/destroy_artifact.mutation.graphql
@@ -0,0 +1,7 @@
+mutation destroyArtifact($id: CiJobArtifactID!) {
+ artifactDestroy(input: { id: $id }) {
+ artifact {
+ id
+ }
+ }
+}
diff --git a/app/assets/javascripts/artifacts/graphql/queries/get_job_artifacts.query.graphql b/app/assets/javascripts/artifacts/graphql/queries/get_job_artifacts.query.graphql
new file mode 100644
index 00000000000..89a24d7891e
--- /dev/null
+++ b/app/assets/javascripts/artifacts/graphql/queries/get_job_artifacts.query.graphql
@@ -0,0 +1,57 @@
+#import "~/graphql_shared/fragments/page_info.fragment.graphql"
+
+query getJobArtifacts(
+ $projectPath: ID!
+ $firstPageSize: Int
+ $lastPageSize: Int
+ $prevPageCursor: String = ""
+ $nextPageCursor: String = ""
+) {
+ project(fullPath: $projectPath) {
+ id
+ jobs(
+ statuses: [SUCCESS, FAILED]
+ first: $firstPageSize
+ last: $lastPageSize
+ after: $nextPageCursor
+ before: $prevPageCursor
+ ) {
+ count
+ nodes {
+ id
+ name
+ webPath
+ detailedStatus {
+ id
+ group
+ icon
+ label
+ }
+ pipeline {
+ id
+ iid
+ path
+ }
+ refName
+ refPath
+ shortSha
+ commitPath
+ finishedAt
+ browseArtifactsPath
+ artifacts {
+ nodes {
+ id
+ name
+ fileType
+ downloadPath
+ size
+ expireAt
+ }
+ }
+ }
+ pageInfo {
+ ...PageInfo
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/artifacts/index.js b/app/assets/javascripts/artifacts/index.js
new file mode 100644
index 00000000000..b5146e0f0e9
--- /dev/null
+++ b/app/assets/javascripts/artifacts/index.js
@@ -0,0 +1,29 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
+import JobArtifactsTable from './components/job_artifacts_table.vue';
+
+Vue.use(VueApollo);
+
+const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+});
+
+export const initArtifactsTable = () => {
+ const el = document.querySelector('#js-artifact-management');
+
+ if (!el) {
+ return false;
+ }
+
+ const { projectPath } = el.dataset;
+
+ return new Vue({
+ el,
+ apolloProvider,
+ provide: {
+ projectPath,
+ },
+ render: (createElement) => createElement(JobArtifactsTable),
+ });
+};
diff --git a/app/assets/javascripts/artifacts/utils.js b/app/assets/javascripts/artifacts/utils.js
new file mode 100644
index 00000000000..ebcf0af8d2a
--- /dev/null
+++ b/app/assets/javascripts/artifacts/utils.js
@@ -0,0 +1,26 @@
+import { numberToHumanSize } from '~/lib/utils/number_utils';
+import { ARCHIVE_FILE_TYPE, JOB_STATUS_GROUP_SUCCESS } from './constants';
+
+export const totalArtifactsSizeForJob = (job) =>
+ numberToHumanSize(
+ job.artifacts.nodes
+ .map((artifact) => artifact.size)
+ .reduce((total, artifact) => total + artifact, 0),
+ );
+
+export const mapArchivesToJobNodes = (jobNode) => {
+ return {
+ archive: {
+ ...jobNode.artifacts.nodes.find((artifact) => artifact.fileType === ARCHIVE_FILE_TYPE),
+ },
+ ...jobNode,
+ };
+};
+
+export const mapBooleansToJobNodes = (jobNode) => {
+ return {
+ succeeded: jobNode.detailedStatus.group === JOB_STATUS_GROUP_SUCCESS,
+ hasArtifacts: jobNode.artifacts.nodes.length > 0,
+ ...jobNode,
+ };
+};
diff --git a/app/assets/javascripts/behaviors/copy_code.js b/app/assets/javascripts/behaviors/copy_code.js
index a653769b60f..ae186aba32d 100644
--- a/app/assets/javascripts/behaviors/copy_code.js
+++ b/app/assets/javascripts/behaviors/copy_code.js
@@ -53,9 +53,10 @@ export const initCopyCodeButton = (selector = '#content-body') => {
customElements.define('copy-code', CopyCodeButton);
}
+ const exclude = document.querySelector('.file-content.code'); // this behavior is not needed when viewing raw file content, so excluding it as the unnecessary dom lookups can become expensive
const el = document.querySelector(selector);
- if (!el) return () => {};
+ if (!el || exclude) return () => {};
const observer = new MutationObserver(() => addCodeButton());
diff --git a/app/assets/javascripts/behaviors/markdown/render_gfm.js b/app/assets/javascripts/behaviors/markdown/render_gfm.js
index ee5c0fe5ef3..a08cf48c327 100644
--- a/app/assets/javascripts/behaviors/markdown/render_gfm.js
+++ b/app/assets/javascripts/behaviors/markdown/render_gfm.js
@@ -15,7 +15,7 @@ $.fn.renderGFM = function renderGFM() {
syntaxHighlight(this.find('.js-syntax-highlight').get());
renderKroki(this.find('.js-render-kroki[hidden]').get());
renderMath(this.find('.js-render-math'));
- renderSandboxedMermaid(this.find('.js-render-mermaid'));
+ renderSandboxedMermaid(this.find('.js-render-mermaid').get());
renderJSONTable(
Array.from(this.find('[lang="json"][data-lang-params="table"]').get()).map((e) => e.parentNode),
);
diff --git a/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js b/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js
index 077e96b2fee..66007aa9e3d 100644
--- a/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js
+++ b/app/assets/javascripts/behaviors/markdown/render_sandboxed_mermaid.js
@@ -1,5 +1,4 @@
-import $ from 'jquery';
-import { once, countBy } from 'lodash';
+import { countBy } from 'lodash';
import { __ } from '~/locale';
import {
getBaseURL,
@@ -8,7 +7,8 @@ import {
joinPaths,
} from '~/lib/utils/url_utility';
import { darkModeEnabled } from '~/lib/utils/color_utils';
-import { setAttributes } from '~/lib/utils/dom_utils';
+import { setAttributes, isElementVisible } from '~/lib/utils/dom_utils';
+import { createAlert, VARIANT_WARNING } from '~/flash';
import { unrestrictedPages } from './constants';
// Renders diagrams and flowcharts from text using Mermaid in any element with the
@@ -27,17 +27,30 @@ import { unrestrictedPages } from './constants';
const SANDBOX_FRAME_PATH = '/-/sandbox/mermaid';
// This is an arbitrary number; Can be iterated upon when suitable.
-const MAX_CHAR_LIMIT = 2000;
+export const MAX_CHAR_LIMIT = 2000;
// Max # of mermaid blocks that can be rendered in a page.
-const MAX_MERMAID_BLOCK_LIMIT = 50;
+export const MAX_MERMAID_BLOCK_LIMIT = 50;
// Max # of `&` allowed in Chaining of links syntax
const MAX_CHAINING_OF_LINKS_LIMIT = 30;
+
export const BUFFER_IFRAME_HEIGHT = 10;
export const SANDBOX_ATTRIBUTES = 'allow-scripts allow-popups';
+
+const ALERT_CONTAINER_CLASS = 'mermaid-alert-container';
+export const LAZY_ALERT_SHOWN_CLASS = 'lazy-alert-shown';
+
// Keep a map of mermaid blocks we've already rendered.
const elsProcessingMap = new WeakMap();
let renderedMermaidBlocks = 0;
+/**
+ * Determines whether a given Mermaid diagram is visible.
+ *
+ * @param {Element} el The Mermaid DOM node
+ * @returns
+ */
+const isVisibleMermaid = (el) => el.closest('details') === null && isElementVisible(el);
+
function shouldLazyLoadMermaidBlock(source) {
/**
* If source contains `&`, which means that it might
@@ -104,8 +117,8 @@ function renderMermaidEl(el, source) {
);
}
-function renderMermaids($els) {
- if (!$els.length) return;
+function renderMermaids(els) {
+ if (!els.length) return;
const pageName = document.querySelector('body').dataset.page;
@@ -114,7 +127,7 @@ function renderMermaids($els) {
let renderedChars = 0;
- $els.each((i, el) => {
+ els.forEach((el) => {
// Skipping all the elements which we've already queued in requestIdleCallback
if (elsProcessingMap.has(el)) {
return;
@@ -133,33 +146,29 @@ function renderMermaids($els) {
renderedMermaidBlocks >= MAX_MERMAID_BLOCK_LIMIT ||
shouldLazyLoadMermaidBlock(source))
) {
- const html = `
- <div class="alert gl-alert gl-alert-warning alert-dismissible lazy-render-mermaid-container js-lazy-render-mermaid-container fade show" role="alert">
- <div>
- <div>
- <div class="js-warning-text"></div>
- <div class="gl-alert-actions">
- <button type="button" class="js-lazy-render-mermaid btn gl-alert-action btn-confirm btn-md gl-button">Display</button>
- </div>
- </div>
- <button type="button" class="close" data-dismiss="alert" aria-label="Close">
- <span aria-hidden="true">&times;</span>
- </button>
- </div>
- </div>
- `;
-
- const $parent = $(el).parent();
-
- if (!$parent.hasClass('lazy-alert-shown')) {
- $parent.after(html);
- $parent
- .siblings()
- .find('.js-warning-text')
- .text(
- __('Warning: Displaying this diagram might cause performance issues on this page.'),
- );
- $parent.addClass('lazy-alert-shown');
+ const parent = el.parentNode;
+
+ if (!parent.classList.contains(LAZY_ALERT_SHOWN_CLASS)) {
+ const alertContainer = document.createElement('div');
+ alertContainer.classList.add(ALERT_CONTAINER_CLASS);
+ alertContainer.classList.add('gl-mb-5');
+ parent.after(alertContainer);
+ createAlert({
+ message: __(
+ 'Warning: Displaying this diagram might cause performance issues on this page.',
+ ),
+ variant: VARIANT_WARNING,
+ parent: parent.parentNode,
+ containerSelector: `.${ALERT_CONTAINER_CLASS}`,
+ primaryButton: {
+ text: __('Display'),
+ clickHandler: () => {
+ alertContainer.remove();
+ renderMermaidEl(el, source);
+ },
+ },
+ });
+ parent.classList.add(LAZY_ALERT_SHOWN_CLASS);
}
return;
@@ -176,37 +185,33 @@ function renderMermaids($els) {
});
}
-const hookLazyRenderMermaidEvent = once(() => {
- $(document.body).on('click', '.js-lazy-render-mermaid', function eventHandler() {
- const parent = $(this).closest('.js-lazy-render-mermaid-container');
- const pre = parent.prev();
-
- const el = pre.find('.js-render-mermaid');
-
- parent.remove();
-
- // sandbox update
- const element = el.get(0);
- const { source } = fixElementSource(element);
+export default function renderMermaid(els) {
+ if (!els.length) return;
- renderMermaidEl(element, source);
- });
-});
-
-export default function renderMermaid($els) {
- if (!$els.length) return;
+ const visibleMermaids = [];
+ const hiddenMermaids = [];
- const visibleMermaids = $els.filter(function filter() {
- return $(this).closest('details').length === 0 && $(this).is(':visible');
- });
+ for (const el of els) {
+ if (isVisibleMermaid(el)) {
+ visibleMermaids.push(el);
+ } else {
+ hiddenMermaids.push(el);
+ }
+ }
renderMermaids(visibleMermaids);
- $els.closest('details').one('toggle', function toggle() {
- if (this.open) {
- renderMermaids($(this).find('.js-render-mermaid'));
- }
+ hiddenMermaids.forEach((el) => {
+ el.closest('details')?.addEventListener(
+ 'toggle',
+ ({ target: details }) => {
+ if (details.open) {
+ renderMermaids([...details.querySelectorAll('.js-render-mermaid')]);
+ }
+ },
+ {
+ once: true,
+ },
+ );
});
-
- hookLazyRenderMermaidEvent();
}
diff --git a/app/assets/javascripts/behaviors/shortcuts/keybindings.js b/app/assets/javascripts/behaviors/shortcuts/keybindings.js
index 3239375bf7c..38ee02938cc 100644
--- a/app/assets/javascripts/behaviors/shortcuts/keybindings.js
+++ b/app/assets/javascripts/behaviors/shortcuts/keybindings.js
@@ -93,6 +93,12 @@ export const GO_TO_YOUR_MERGE_REQUESTS = {
defaultKeys: ['shift+m'],
};
+export const GO_TO_YOUR_REVIEW_REQUESTS = {
+ id: 'globalShortcuts.goToYourReviewRequests',
+ description: __('Go to your review requests'),
+ defaultKeys: ['shift+r'],
+};
+
export const GO_TO_YOUR_TODO_LIST = {
id: 'globalShortcuts.goToYourTodoList',
description: __('Go to your To-Do list'),
@@ -523,6 +529,7 @@ export const GLOBAL_SHORTCUTS_GROUP = {
FOCUS_FILTER_BAR,
GO_TO_YOUR_ISSUES,
GO_TO_YOUR_MERGE_REQUESTS,
+ GO_TO_YOUR_REVIEW_REQUESTS,
GO_TO_YOUR_TODO_LIST,
TOGGLE_PERFORMANCE_BAR,
HIDE_APPEARING_CONTENT,
diff --git a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
index 4d78c7b56a0..7a1577e97d5 100644
--- a/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
+++ b/app/assets/javascripts/behaviors/shortcuts/shortcuts.js
@@ -24,6 +24,7 @@ import {
GO_TO_MILESTONE_LIST,
GO_TO_YOUR_SNIPPETS,
GO_TO_PROJECT_FIND_FILE,
+ GO_TO_YOUR_REVIEW_REQUESTS,
} from './keybindings';
import { disableShortcuts, shouldDisableShortcuts } from './shortcuts_toggle';
@@ -94,6 +95,9 @@ export default class Shortcuts {
Mousetrap.bind(keysFor(GO_TO_YOUR_MERGE_REQUESTS), () =>
findAndFollowLink('.dashboard-shortcuts-merge_requests'),
);
+ Mousetrap.bind(keysFor(GO_TO_YOUR_REVIEW_REQUESTS), () =>
+ findAndFollowLink('.dashboard-shortcuts-review_requests'),
+ );
Mousetrap.bind(keysFor(GO_TO_YOUR_PROJECTS), () =>
findAndFollowLink('.dashboard-shortcuts-projects'),
);
diff --git a/app/assets/javascripts/blob/blob_blame_link.js b/app/assets/javascripts/blob/blob_blame_link.js
index 41dfd7b82b8..a5191a3d513 100644
--- a/app/assets/javascripts/blob/blob_blame_link.js
+++ b/app/assets/javascripts/blob/blob_blame_link.js
@@ -1,4 +1,6 @@
-function addBlameLink(containerSelector, linkClass) {
+import { getPageParamValue, getPageSearchString } from './utils';
+
+export function addBlameLink(containerSelector, linkClass) {
const containerEl = document.querySelector(containerSelector);
if (!containerEl) {
@@ -13,10 +15,14 @@ function addBlameLink(containerSelector, linkClass) {
lineLinkCopy.classList.remove(linkClass, 'diff-line-num');
const { lineNumber } = lineLink.dataset;
- const { blamePath } = document.querySelector('.line-numbers').dataset;
const blameLink = document.createElement('a');
+ const { blamePath } = document.querySelector('.line-numbers').dataset;
blameLink.classList.add('file-line-blame');
- blameLink.href = `${blamePath}#L${lineNumber}`;
+ const blamePerPage = document.querySelector('.js-per-page')?.dataset?.blamePerPage;
+ const pageNumber = getPageParamValue(lineNumber, blamePerPage);
+ const searchString = getPageSearchString(blamePath, pageNumber);
+
+ blameLink.href = `${blamePath}${searchString}#L${lineNumber}`;
const wrapper = document.createElement('div');
wrapper.classList.add('line-links', 'diff-line-num');
@@ -27,5 +33,3 @@ function addBlameLink(containerSelector, linkClass) {
}
});
}
-
-export default addBlameLink;
diff --git a/app/assets/javascripts/blob/blob_file_dropzone.js b/app/assets/javascripts/blob/blob_file_dropzone.js
deleted file mode 100644
index 387d6043315..00000000000
--- a/app/assets/javascripts/blob/blob_file_dropzone.js
+++ /dev/null
@@ -1,96 +0,0 @@
-/* eslint-disable func-names */
-
-import Dropzone from 'dropzone';
-import $ from 'jquery';
-import { sprintf, __ } from '~/locale';
-import { HIDDEN_CLASS } from '../lib/utils/constants';
-import csrf from '../lib/utils/csrf';
-import { visitUrl } from '../lib/utils/url_utility';
-
-Dropzone.autoDiscover = false;
-
-function toggleLoading($el, $icon, loading) {
- if (loading) {
- $el.disable();
- $icon.removeClass(HIDDEN_CLASS);
- } else {
- $el.enable();
- $icon.addClass(HIDDEN_CLASS);
- }
-}
-export default class BlobFileDropzone {
- constructor(form, method) {
- const formDropzone = form.find('.dropzone');
- const submitButton = form.find('#submit-all');
- const submitButtonLoadingIcon = submitButton.find('.js-loading-icon');
- const dropzoneMessage = form.find('.dz-message');
- Dropzone.autoDiscover = false;
-
- const dropzone = formDropzone.dropzone({
- autoDiscover: false,
- autoProcessQueue: false,
- url: form.attr('action'),
- // Rails uses a hidden input field for PUT
- method,
- clickable: true,
- uploadMultiple: false,
- paramName: 'file',
- maxFilesize: gon.max_file_size || 10,
- parallelUploads: 1,
- maxFiles: 1,
- addRemoveLinks: true,
- previewsContainer: '.dropzone-previews',
- headers: csrf.headers,
- init() {
- this.on('processing', function () {
- this.options.url = form.attr('action');
- });
-
- this.on('addedfile', () => {
- toggleLoading(submitButton, submitButtonLoadingIcon, false);
- dropzoneMessage.addClass(HIDDEN_CLASS);
- $('.dropzone-alerts').html('').hide();
- });
- this.on('removedfile', () => {
- toggleLoading(submitButton, submitButtonLoadingIcon, false);
- dropzoneMessage.removeClass(HIDDEN_CLASS);
- });
- this.on('success', (header, response) => {
- $('#modal-upload-blob').modal('hide');
- visitUrl(response.filePath);
- });
- this.on('maxfilesexceeded', function (file) {
- dropzoneMessage.addClass(HIDDEN_CLASS);
- this.removeFile(file);
- });
- this.on('sending', (file, xhr, formData) => {
- formData.append('branch_name', form.find('.js-branch-name').val());
- formData.append('create_merge_request', form.find('.js-create-merge-request').val());
- formData.append('commit_message', form.find('.js-commit-message').val());
- });
- },
- // Override behavior of adding error underneath preview
- error(file, errorMessage) {
- const stripped = $('<div/>').html(errorMessage).text();
- $('.dropzone-alerts')
- .html(sprintf(__('Error uploading file: %{stripped}'), { stripped }))
- .show();
- this.removeFile(file);
- },
- });
-
- submitButton.on('click', (e) => {
- e.preventDefault();
- e.stopPropagation();
-
- if (dropzone[0].dropzone.getQueuedFiles().length === 0) {
- // eslint-disable-next-line no-alert
- alert(__('Please select a file'));
- return false;
- }
- toggleLoading(submitButton, submitButtonLoadingIcon, true);
- dropzone[0].dropzone.processQueue();
- return false;
- });
- }
-}
diff --git a/app/assets/javascripts/blob/blob_line_permalink_updater.js b/app/assets/javascripts/blob/blob_line_permalink_updater.js
index df38c5400e2..928035d7c1e 100644
--- a/app/assets/javascripts/blob/blob_line_permalink_updater.js
+++ b/app/assets/javascripts/blob/blob_line_permalink_updater.js
@@ -1,4 +1,5 @@
import { getLocationHash } from '../lib/utils/url_utility';
+import { getPageParamValue, getPageSearchString } from './utils';
const lineNumberRe = /^(L|LC)[0-9]+/;
@@ -16,7 +17,10 @@ const updateLineNumbersOnBlobPermalinks = (linksToUpdate) => {
permalinkButton.dataset.originalHref = href;
return href;
})();
- permalinkButton.setAttribute('href', `${baseHref}${hashUrlString}`);
+ const lineNum = parseInt(hash.split('L')[1], 10);
+ const page = getPageParamValue(lineNum);
+ const searchString = getPageSearchString(baseHref, page);
+ permalinkButton.setAttribute('href', `${baseHref}${searchString}${hashUrlString}`);
});
}
};
diff --git a/app/assets/javascripts/blob/components/blob_edit_content.vue b/app/assets/javascripts/blob/components/blob_edit_content.vue
deleted file mode 100644
index 0e670bbd80a..00000000000
--- a/app/assets/javascripts/blob/components/blob_edit_content.vue
+++ /dev/null
@@ -1,66 +0,0 @@
-<script>
-import { debounce } from 'lodash';
-import { initSourceEditor } from '~/blob/utils';
-import { SNIPPET_MEASURE_BLOBS_CONTENT } from '~/performance/constants';
-
-import eventHub from './eventhub';
-
-export default {
- props: {
- value: {
- type: String,
- required: false,
- default: '',
- },
- fileName: {
- type: String,
- required: false,
- default: '',
- },
- // This is used to help uniquely create a monaco model
- // even if two blob's share a file path.
- fileGlobalId: {
- type: String,
- required: false,
- default: '',
- },
- },
- data() {
- return {
- editor: null,
- };
- },
- watch: {
- fileName(newVal) {
- this.editor.updateModelLanguage(newVal);
- },
- },
- mounted() {
- this.editor = initSourceEditor({
- el: this.$refs.editor,
- blobPath: this.fileName,
- blobContent: this.value,
- blobGlobalId: this.fileGlobalId,
- });
-
- this.editor.onDidChangeModelContent(debounce(this.onFileChange.bind(this), 250));
-
- eventHub.$emit(SNIPPET_MEASURE_BLOBS_CONTENT);
- },
- beforeDestroy() {
- this.editor.dispose();
- },
- methods: {
- onFileChange() {
- this.$emit('input', this.editor.getValue());
- },
- },
-};
-</script>
-<template>
- <div class="file-content code">
- <div id="editor" ref="editor" data-editor-loading>
- <pre class="editor-loading-content">{{ value }}</pre>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/blob/utils.js b/app/assets/javascripts/blob/utils.js
index bbc061dd36e..b2400a4b224 100644
--- a/app/assets/javascripts/blob/utils.js
+++ b/app/assets/javascripts/blob/utils.js
@@ -1,16 +1,18 @@
-import Editor from '~/editor/source_editor';
+import { getBaseURL } from '~/lib/utils/url_utility';
-export function initSourceEditor({ el, ...args }) {
- const editor = new Editor({
- scrollbar: {
- alwaysConsumeMouseWheel: false,
- },
- });
+const blameLinesPerPage = document.querySelector('.js-per-page')?.dataset?.blamePerPage;
- return editor.createInstance({
- el,
- ...args,
- });
-}
+export const getPageParamValue = (lineNum, blamePerPage = blameLinesPerPage) => {
+ if (!blamePerPage) return '';
+ const page = Math.ceil(parseInt(lineNum, 10) / parseInt(blamePerPage, 10));
+ return page <= 1 ? '' : page;
+};
+
+export const getPageSearchString = (path, page) => {
+ if (!page) return '';
+ const url = new URL(path, getBaseURL());
+ url.searchParams.set('page', page);
+ return url.search;
+};
export default () => ({});
diff --git a/app/assets/javascripts/blob_edit/blob_bundle.js b/app/assets/javascripts/blob_edit/blob_bundle.js
index 1c9c99dcc2f..4741dd53708 100644
--- a/app/assets/javascripts/blob_edit/blob_bundle.js
+++ b/app/assets/javascripts/blob_edit/blob_bundle.js
@@ -3,9 +3,8 @@
import $ from 'jquery';
import initPopover from '~/blob/suggest_gitlab_ci_yml';
import { createAlert } from '~/flash';
-import { disableButtonIfEmptyField, setCookie } from '~/lib/utils/common_utils';
+import { setCookie } from '~/lib/utils/common_utils';
import Tracking from '~/tracking';
-import BlobFileDropzone from '../blob/blob_file_dropzone';
import NewCommitForm from '../new_commit_form';
const initPopovers = () => {
@@ -38,21 +37,8 @@ const initPopovers = () => {
}
};
-export const initUploadForm = () => {
- const uploadBlobForm = $('.js-upload-blob-form');
- if (uploadBlobForm.length) {
- const method = uploadBlobForm.data('method');
-
- new BlobFileDropzone(uploadBlobForm, method);
- new NewCommitForm(uploadBlobForm);
-
- disableButtonIfEmptyField(uploadBlobForm.find('.js-commit-message'), '.btn-upload-file');
- }
-};
-
export default () => {
const editBlobForm = $('.js-edit-blob-form');
- const deleteBlobForm = $('.js-delete-blob-form');
if (editBlobForm.length) {
const urlRoot = editBlobForm.data('relativeUrlRoot');
@@ -99,10 +85,4 @@ export default () => {
// returning here blocks page navigation
window.onbeforeunload = () => '';
}
-
- initUploadForm();
-
- if (deleteBlobForm.length) {
- new NewCommitForm(deleteBlobForm);
- }
};
diff --git a/app/assets/javascripts/blob_edit/edit_blob.js b/app/assets/javascripts/blob_edit/edit_blob.js
index 78e3f934183..97d8b206307 100644
--- a/app/assets/javascripts/blob_edit/edit_blob.js
+++ b/app/assets/javascripts/blob_edit/edit_blob.js
@@ -16,8 +16,10 @@ export default class EditBlob {
constructor(options) {
this.options = options;
this.configureMonacoEditor();
+ this.isMarkdown = this.options.isMarkdown;
+ this.markdownLivePreviewOpened = false;
- if (this.options.isMarkdown) {
+ if (this.isMarkdown) {
this.fetchMarkdownExtension();
}
@@ -104,6 +106,13 @@ export default class EditBlob {
this.$editModeLinks.on('click', (e) => this.editModeLinkClickHandler(e));
}
+ toggleMarkdownPreview(toOpen) {
+ if (toOpen !== this.markdownLivePreviewOpened) {
+ this.editor.markdownPreview?.eventEmitter.fire();
+ this.markdownLivePreviewOpened = !this.markdownLivePreviewOpened;
+ }
+ }
+
editModeLinkClickHandler(e) {
e.preventDefault();
@@ -115,25 +124,29 @@ export default class EditBlob {
currentLink.parent().addClass('active hover');
- this.$editModePanes.hide();
-
- currentPane.show();
-
- if (paneId === '#preview') {
- this.$toggleButton.hide();
- axios
- .post(currentLink.data('previewUrl'), {
- content: this.editor.getValue(),
- })
- .then(({ data }) => {
- currentPane.empty().append(data);
- currentPane.renderGFM();
- })
- .catch(() =>
- createAlert({
- message: BLOB_PREVIEW_ERROR,
- }),
- );
+ if (this.isMarkdown) {
+ this.toggleMarkdownPreview(paneId === '#preview');
+ } else {
+ this.$editModePanes.hide();
+
+ currentPane.show();
+
+ if (paneId === '#preview') {
+ this.$toggleButton.hide();
+ axios
+ .post(currentLink.data('previewUrl'), {
+ content: this.editor.getValue(),
+ })
+ .then(({ data }) => {
+ currentPane.empty().append(data);
+ currentPane.renderGFM();
+ })
+ .catch(() =>
+ createAlert({
+ message: BLOB_PREVIEW_ERROR,
+ }),
+ );
+ }
}
this.$toggleButton.show();
diff --git a/app/assets/javascripts/boards/components/board_app.vue b/app/assets/javascripts/boards/components/board_app.vue
index af753151be8..1335a3b108b 100644
--- a/app/assets/javascripts/boards/components/board_app.vue
+++ b/app/assets/javascripts/boards/components/board_app.vue
@@ -11,7 +11,7 @@ export default {
BoardSettingsSidebar,
BoardTopBar,
},
- inject: ['disabled'],
+ inject: ['disabled', 'fullBoardId'],
computed: {
...mapGetters(['isSidebarOpen']),
},
@@ -27,7 +27,7 @@ export default {
<template>
<div class="boards-app gl-relative" :class="{ 'is-compact': isSidebarOpen }">
<board-top-bar />
- <board-content :disabled="disabled" />
+ <board-content :disabled="disabled" :board-id="fullBoardId" />
<board-settings-sidebar />
</div>
</template>
diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue
index 44c16324950..f3307977be9 100644
--- a/app/assets/javascripts/boards/components/board_card.vue
+++ b/app/assets/javascripts/boards/components/board_card.vue
@@ -109,6 +109,8 @@ export default {
:update-filters="true"
:index="index"
:show-work-item-type-icon="showWorkItemTypeIcon"
- />
+ >
+ <slot></slot>
+ </board-card-inner>
</li>
</template>
diff --git a/app/assets/javascripts/boards/components/board_card_inner.vue b/app/assets/javascripts/boards/components/board_card_inner.vue
index 3a2b11a649d..05c786ca61d 100644
--- a/app/assets/javascripts/boards/components/board_card_inner.vue
+++ b/app/assets/javascripts/boards/components/board_card_inner.vue
@@ -15,7 +15,6 @@ import { updateHistory } from '~/lib/utils/url_utility';
import { sprintf, __, n__ } from '~/locale';
import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
-import BoardCardMoveToPosition from '~/boards/components/board_card_move_to_position.vue';
import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue';
import IssuableBlockedIcon from '~/vue_shared/components/issuable_blocked_icon/issuable_blocked_icon.vue';
import { ListType } from '../constants';
@@ -36,7 +35,6 @@ export default {
IssueCardWeight: () => import('ee_component/boards/components/issue_card_weight.vue'),
IssuableBlockedIcon,
GlSprintf,
- BoardCardMoveToPosition,
WorkItemTypeIcon,
IssueHealthStatus: () =>
import('ee_component/related_items_tree/components/issue_health_status.vue'),
@@ -45,7 +43,7 @@ export default {
GlTooltip: GlTooltipDirective,
},
mixins: [boardCardInner],
- inject: ['rootPath', 'scopedLabelsAvailable'],
+ inject: ['rootPath', 'scopedLabelsAvailable', 'isEpicBoard'],
props: {
item: {
type: Object,
@@ -80,7 +78,7 @@ export default {
},
computed: {
...mapState(['isShowingLabels', 'issuableType', 'allowSubEpics']),
- ...mapGetters(['isEpicBoard', 'isProjectBoard']),
+ ...mapGetters(['isProjectBoard']),
cappedAssignees() {
// e.g. maxRender is 4,
// Render up to all 4 assignees if there are only 4 assigness
@@ -250,8 +248,7 @@ export default {
>{{ item.title }}</a
>
</h4>
- <!-- TODO: remove the condition when https://gitlab.com/gitlab-org/gitlab/-/issues/377862 is resolved -->
- <board-card-move-to-position v-if="!isEpicBoard" :item="item" :list="list" :index="index" />
+ <slot></slot>
</div>
<div v-if="showLabelFooter" class="board-card-labels gl-mt-2 gl-display-flex gl-flex-wrap">
<template v-for="label in orderedLabels">
diff --git a/app/assets/javascripts/boards/components/board_card_move_to_position.vue b/app/assets/javascripts/boards/components/board_card_move_to_position.vue
index ff938219475..706b453e868 100644
--- a/app/assets/javascripts/boards/components/board_card_move_to_position.vue
+++ b/app/assets/javascripts/boards/components/board_card_move_to_position.vue
@@ -1,6 +1,6 @@
<script>
import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
-import { mapActions, mapGetters, mapState } from 'vuex';
+import { mapActions, mapState } from 'vuex';
import { s__ } from '~/locale';
import Tracking from '~/tracking';
@@ -31,10 +31,13 @@ export default {
type: Number,
required: true,
},
+ listItemsLength: {
+ type: Number,
+ required: true,
+ },
},
computed: {
...mapState(['pageInfoByListId']),
- ...mapGetters(['getBoardItemsByList']),
tracking() {
return {
category: 'boards:list',
@@ -42,15 +45,9 @@ export default {
property: `type_card`,
};
},
- listItems() {
- return this.getBoardItemsByList(this.list.id);
- },
listHasNextPage() {
return this.pageInfoByListId[this.list.id]?.hasNextPage;
},
- lengthOfListItemsInBoard() {
- return this.listItems?.length;
- },
itemIdentifier() {
return `${this.item.id}-${this.item.iid}-${this.index}`;
},
@@ -58,7 +55,7 @@ export default {
return this.index === 0;
},
isLastItemInList() {
- return this.index === this.lengthOfListItemsInBoard - 1;
+ return this.index === this.listItemsLength - 1;
},
},
methods: {
diff --git a/app/assets/javascripts/boards/components/board_content.vue b/app/assets/javascripts/boards/components/board_content.vue
index d99afa8455d..150378f7a7d 100644
--- a/app/assets/javascripts/boards/components/board_content.vue
+++ b/app/assets/javascripts/boards/components/board_content.vue
@@ -1,14 +1,21 @@
<script>
import { GlAlert } from '@gitlab/ui';
-import { sortBy } from 'lodash';
+import { sortBy, throttle } from 'lodash';
import Draggable from 'vuedraggable';
import { mapState, mapGetters, mapActions } from 'vuex';
+import { s__ } from '~/locale';
+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';
-import { DraggableItemTypes } from '../constants';
+import { DraggableItemTypes, BoardType, listsQuery } from 'ee_else_ce/boards/constants';
import BoardColumn from './board_column.vue';
export default {
+ i18n: {
+ fetchError: s__(
+ 'Boards|An error occurred while fetching the board lists. Please reload the page.',
+ ),
+ },
draggableItemTypes: DraggableItemTypes,
components: {
BoardAddNewColumn,
@@ -19,21 +26,78 @@ export default {
EpicsSwimlanes: () => import('ee_component/boards/components/epics_swimlanes.vue'),
GlAlert,
},
- inject: ['canAdminList'],
+ inject: [
+ 'canAdminList',
+ 'boardType',
+ 'fullPath',
+ 'issuableType',
+ 'isIssueBoard',
+ 'isEpicBoard',
+ 'isApolloBoard',
+ ],
props: {
disabled: {
type: Boolean,
required: true,
},
+ boardId: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ boardHeight: null,
+ boardListsApollo: {},
+ apolloError: null,
+ updatedBoardId: this.boardId,
+ };
+ },
+ apollo: {
+ boardListsApollo: {
+ query() {
+ return listsQuery[this.issuableType].query;
+ },
+ variables() {
+ return this.queryVariables;
+ },
+ skip() {
+ return !this.isApolloBoard;
+ },
+ update(data) {
+ const { lists } = data[this.boardType].board;
+ return formatBoardLists(lists);
+ },
+ result() {
+ // this allows us to delay fetching lists when we switch a board to fetch the actual board lists
+ // instead of fetching lists for the "previous" board
+ this.updatedBoardId = this.boardId;
+ },
+ error() {
+ this.apolloError = this.$options.i18n.fetchError;
+ },
+ },
},
computed: {
...mapState(['boardLists', 'error', 'addColumnForm']),
- ...mapGetters(['isSwimlanesOn', 'isEpicBoard', 'isIssueBoard']),
+ ...mapGetters(['isSwimlanesOn']),
addColumnFormVisible() {
return this.addColumnForm?.visible;
},
+ queryVariables() {
+ return {
+ ...(this.isIssueBoard && {
+ isGroup: this.boardType === BoardType.group,
+ isProject: this.boardType === BoardType.project,
+ }),
+ fullPath: this.fullPath,
+ boardId: this.boardId,
+ filterParams: this.filterParams,
+ };
+ },
boardListsToUse() {
- return sortBy([...Object.values(this.boardLists)], 'position');
+ const lists = this.isApolloBoard ? this.boardListsApollo : this.boardLists;
+ return sortBy([...Object.values(lists)], 'position');
},
canDragColumns() {
return this.canAdminList;
@@ -54,6 +118,22 @@ export default {
return this.canDragColumns ? options : {};
},
+ errorToDisplay() {
+ return this.isApolloBoard ? this.apolloError : this.error;
+ },
+ },
+ mounted() {
+ this.setBoardHeight();
+
+ this.resizeObserver = new ResizeObserver(
+ throttle(() => {
+ this.setBoardHeight();
+ }, 150),
+ );
+ this.resizeObserver.observe(document.body);
+ },
+ unmounted() {
+ this.resizeObserver.disconnect();
},
methods: {
...mapActions(['moveList', 'unsetError']),
@@ -61,14 +141,17 @@ export default {
const el = this.canDragColumns ? this.$refs.list.$el : this.$refs.list;
el.scrollTo({ left: el.scrollWidth, behavior: 'smooth' });
},
+ setBoardHeight() {
+ this.boardHeight = `${window.innerHeight - this.$el.getBoundingClientRect().top}px`;
+ },
},
};
</script>
<template>
<div v-cloak data-qa-selector="boards_list">
- <gl-alert v-if="error" variant="danger" :dismissible="true" @dismiss="unsetError">
- {{ error }}
+ <gl-alert v-if="errorToDisplay" variant="danger" :dismissible="true" @dismiss="unsetError">
+ {{ errorToDisplay }}
</gl-alert>
<component
:is="boardColumnWrapper"
@@ -76,6 +159,7 @@ export default {
ref="list"
v-bind="draggableOptions"
class="boards-list gl-w-full gl-py-5 gl-pr-3 gl-white-space-nowrap gl-overflow-x-scroll"
+ :style="{ height: boardHeight }"
@end="moveList"
>
<board-column
@@ -99,6 +183,7 @@ export default {
:lists="boardListsToUse"
:can-admin-list="canAdminList"
:disabled="disabled"
+ :style="{ height: boardHeight }"
/>
<board-content-sidebar v-if="isIssueBoard" data-testid="issue-boards-sidebar" />
diff --git a/app/assets/javascripts/boards/components/board_filtered_search.vue b/app/assets/javascripts/boards/components/board_filtered_search.vue
index 11a5d89cc8c..97f52f21e7f 100644
--- a/app/assets/javascripts/boards/components/board_filtered_search.vue
+++ b/app/assets/javascripts/boards/components/board_filtered_search.vue
@@ -6,9 +6,20 @@ import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { updateHistory, setUrlParams, queryToObject } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
import {
- FILTERED_SEARCH_TERM,
FILTER_ANY,
+ FILTERED_SEARCH_TERM,
+ TOKEN_TYPE_ASSIGNEE,
+ TOKEN_TYPE_AUTHOR,
+ TOKEN_TYPE_CONFIDENTIAL,
+ TOKEN_TYPE_EPIC,
TOKEN_TYPE_HEALTH,
+ TOKEN_TYPE_ITERATION,
+ TOKEN_TYPE_LABEL,
+ TOKEN_TYPE_MILESTONE,
+ TOKEN_TYPE_MY_REACTION,
+ TOKEN_TYPE_RELEASE,
+ TOKEN_TYPE_TYPE,
+ TOKEN_TYPE_WEIGHT,
} 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';
@@ -17,8 +28,6 @@ import eventHub from '../eventhub';
export default {
i18n: {
search: __('Search'),
- label: __('Label'),
- author: __('Author'),
},
components: { FilteredSearch },
inject: ['initialFilterParams'],
@@ -62,28 +71,28 @@ export default {
if (authorUsername) {
filteredSearchValue.push({
- type: 'author',
+ type: TOKEN_TYPE_AUTHOR,
value: { data: authorUsername, operator: '=' },
});
}
if (assigneeUsername) {
filteredSearchValue.push({
- type: 'assignee',
+ type: TOKEN_TYPE_ASSIGNEE,
value: { data: assigneeUsername, operator: '=' },
});
}
if (assigneeId) {
filteredSearchValue.push({
- type: 'assignee',
+ type: TOKEN_TYPE_ASSIGNEE,
value: { data: assigneeId, operator: '=' },
});
}
if (types) {
filteredSearchValue.push({
- type: 'type',
+ type: TOKEN_TYPE_TYPE,
value: { data: types, operator: '=' },
});
}
@@ -91,7 +100,7 @@ export default {
if (labelName?.length) {
filteredSearchValue.push(
...labelName.map((label) => ({
- type: 'label',
+ type: TOKEN_TYPE_LABEL,
value: { data: label, operator: '=' },
})),
);
@@ -99,7 +108,7 @@ export default {
if (milestoneTitle) {
filteredSearchValue.push({
- type: 'milestone',
+ type: TOKEN_TYPE_MILESTONE,
value: { data: milestoneTitle, operator: '=' },
});
}
@@ -116,42 +125,42 @@ export default {
if (iterationData) {
filteredSearchValue.push({
- type: 'iteration',
+ type: TOKEN_TYPE_ITERATION,
value: { data: iterationData, operator: '=' },
});
}
if (weight) {
filteredSearchValue.push({
- type: 'weight',
+ type: TOKEN_TYPE_WEIGHT,
value: { data: weight, operator: '=' },
});
}
if (myReactionEmoji) {
filteredSearchValue.push({
- type: 'my-reaction',
+ type: TOKEN_TYPE_MY_REACTION,
value: { data: myReactionEmoji, operator: '=' },
});
}
if (releaseTag) {
filteredSearchValue.push({
- type: 'release',
+ type: TOKEN_TYPE_RELEASE,
value: { data: releaseTag, operator: '=' },
});
}
if (confidential !== undefined) {
filteredSearchValue.push({
- type: 'confidential',
+ type: TOKEN_TYPE_CONFIDENTIAL,
value: { data: confidential },
});
}
if (epicId) {
filteredSearchValue.push({
- type: 'epic',
+ type: TOKEN_TYPE_EPIC,
value: { data: epicId, operator: '=' },
});
}
@@ -165,35 +174,35 @@ export default {
if (this.filterParams['not[authorUsername]']) {
filteredSearchValue.push({
- type: 'author',
+ type: TOKEN_TYPE_AUTHOR,
value: { data: this.filterParams['not[authorUsername]'], operator: '!=' },
});
}
if (this.filterParams['not[milestoneTitle]']) {
filteredSearchValue.push({
- type: 'milestone',
+ type: TOKEN_TYPE_MILESTONE,
value: { data: this.filterParams['not[milestoneTitle]'], operator: '!=' },
});
}
if (this.filterParams['not[iterationId]']) {
filteredSearchValue.push({
- type: 'iteration',
+ type: TOKEN_TYPE_ITERATION,
value: { data: this.filterParams['not[iterationId]'], operator: '!=' },
});
}
if (this.filterParams['not[weight]']) {
filteredSearchValue.push({
- type: 'weight',
+ type: TOKEN_TYPE_WEIGHT,
value: { data: this.filterParams['not[weight]'], operator: '!=' },
});
}
if (this.filterParams['not[assigneeUsername]']) {
filteredSearchValue.push({
- type: 'assignee',
+ type: TOKEN_TYPE_ASSIGNEE,
value: { data: this.filterParams['not[assigneeUsername]'], operator: '!=' },
});
}
@@ -201,7 +210,7 @@ export default {
if (this.filterParams['not[labelName]']) {
filteredSearchValue.push(
...this.filterParams['not[labelName]'].map((label) => ({
- type: 'label',
+ type: TOKEN_TYPE_LABEL,
value: { data: label, operator: '!=' },
})),
);
@@ -209,28 +218,28 @@ export default {
if (this.filterParams['not[types]']) {
filteredSearchValue.push({
- type: 'type',
+ type: TOKEN_TYPE_TYPE,
value: { data: this.filterParams['not[types]'], operator: '!=' },
});
}
if (this.filterParams['not[epicId]']) {
filteredSearchValue.push({
- type: 'epic',
+ type: TOKEN_TYPE_EPIC,
value: { data: this.filterParams['not[epicId]'], operator: '!=' },
});
}
if (this.filterParams['not[myReactionEmoji]']) {
filteredSearchValue.push({
- type: 'my-reaction',
+ type: TOKEN_TYPE_MY_REACTION,
value: { data: this.filterParams['not[myReactionEmoji]'], operator: '!=' },
});
}
if (this.filterParams['not[releaseTag]']) {
filteredSearchValue.push({
- type: 'release',
+ type: TOKEN_TYPE_RELEASE,
value: { data: this.filterParams['not[releaseTag]'], operator: '!=' },
});
}
@@ -302,7 +311,7 @@ export default {
my_reaction_emoji: myReactionEmoji,
release_tag: releaseTag,
confidential,
- [TOKEN_TYPE_HEALTH]: healthStatus,
+ health_status: healthStatus,
},
(value) => {
if (value || value === false) {
@@ -361,44 +370,44 @@ export default {
filters.forEach((filter) => {
switch (filter.type) {
- case 'author':
+ case TOKEN_TYPE_AUTHOR:
filterParams.authorUsername = filter.value.data;
break;
- case 'assignee':
+ case TOKEN_TYPE_ASSIGNEE:
if (Object.values(AssigneeFilterType).includes(filter.value.data)) {
filterParams.assigneeId = filter.value.data;
} else {
filterParams.assigneeUsername = filter.value.data;
}
break;
- case 'type':
+ case TOKEN_TYPE_TYPE:
filterParams.types = filter.value.data;
break;
- case 'label':
+ case TOKEN_TYPE_LABEL:
labels.push(filter.value.data);
break;
- case 'milestone':
+ case TOKEN_TYPE_MILESTONE:
filterParams.milestoneTitle = filter.value.data;
break;
- case 'iteration':
+ case TOKEN_TYPE_ITERATION:
filterParams.iterationId = filter.value.data;
break;
- case 'weight':
+ case TOKEN_TYPE_WEIGHT:
filterParams.weight = filter.value.data;
break;
- case 'epic':
+ case TOKEN_TYPE_EPIC:
filterParams.epicId = filter.value.data;
break;
- case 'my-reaction':
+ case TOKEN_TYPE_MY_REACTION:
filterParams.myReactionEmoji = filter.value.data;
break;
- case 'release':
+ case TOKEN_TYPE_RELEASE:
filterParams.releaseTag = filter.value.data;
break;
- case 'confidential':
+ case TOKEN_TYPE_CONFIDENTIAL:
filterParams.confidential = filter.value.data;
break;
- case 'filtered-search-term':
+ case FILTERED_SEARCH_TERM:
if (filter.value.data) plainText.push(filter.value.data);
break;
case TOKEN_TYPE_HEALTH:
diff --git a/app/assets/javascripts/boards/components/board_form.vue b/app/assets/javascripts/boards/components/board_form.vue
index eb889344c1e..fcf026bbe00 100644
--- a/app/assets/javascripts/boards/components/board_form.vue
+++ b/app/assets/javascripts/boards/components/board_form.vue
@@ -84,7 +84,7 @@ export default {
},
computed: {
...mapState(['error']),
- ...mapGetters(['isIssueBoard', 'isGroupBoard', 'isProjectBoard']),
+ ...mapGetters(['isGroupBoard', 'isProjectBoard']),
isNewForm() {
return this.currentPage === formType.new;
},
diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue
index edf1a5ee7e6..816b22e4dc6 100644
--- a/app/assets/javascripts/boards/components/board_list.vue
+++ b/app/assets/javascripts/boards/components/board_list.vue
@@ -1,12 +1,13 @@
<script>
import { GlLoadingIcon, GlIntersectionObserver } from '@gitlab/ui';
import Draggable from 'vuedraggable';
-import { mapActions, mapGetters, mapState } from 'vuex';
+import { mapActions, mapState } from 'vuex';
import { sprintf, __ } from '~/locale';
import { defaultSortableOptions } from '~/sortable/constants';
import { sortableStart, sortableEnd } from '~/sortable/utils';
import Tracking from '~/tracking';
import listQuery from 'ee_else_ce/boards/graphql/board_lists_deferred.query.graphql';
+import BoardCardMoveToPosition from '~/boards/components/board_card_move_to_position.vue';
import { toggleFormEventPrefix, DraggableItemTypes } from '../constants';
import eventHub from '../eventhub';
import BoardCard from './board_card.vue';
@@ -27,8 +28,10 @@ export default {
BoardNewEpic: () => import('ee_component/boards/components/board_new_epic.vue'),
GlLoadingIcon,
GlIntersectionObserver,
+ BoardCardMoveToPosition,
},
mixins: [Tracking.mixin()],
+ inject: ['isEpicBoard'],
props: {
disabled: {
type: Boolean,
@@ -60,6 +63,9 @@ export default {
filters: this.filterParams,
};
},
+ context: {
+ isSingleRequest: true,
+ },
skip() {
return this.isEpicBoard;
},
@@ -67,7 +73,6 @@ export default {
},
computed: {
...mapState(['pageInfoByListId', 'listsFlags', 'filterParams', 'isUpdateIssueOrderInProgress']),
- ...mapGetters(['isEpicBoard']),
listItemsCount() {
return this.isEpicBoard ? this.list.epicsCount : this.boardList?.issuesCount;
},
@@ -309,7 +314,16 @@ export default {
:data-draggable-item-type="$options.draggableItemTypes.card"
:disabled="disabled"
:show-work-item-type-icon="!isEpicBoard"
- />
+ >
+ <!-- TODO: remove the condition when https://gitlab.com/gitlab-org/gitlab/-/issues/377862 is resolved -->
+ <board-card-move-to-position
+ v-if="!isEpicBoard"
+ :item="item"
+ :index="index"
+ :list="list"
+ :list-items-length="boardItems.length"
+ />
+ </board-card>
<gl-intersection-observer @appear="onReachingListBottom">
<li
v-if="showCount"
diff --git a/app/assets/javascripts/boards/components/board_list_header.vue b/app/assets/javascripts/boards/components/board_list_header.vue
index 230fa4e1e0f..bfc4b52baaf 100644
--- a/app/assets/javascripts/boards/components/board_list_header.vue
+++ b/app/assets/javascripts/boards/components/board_list_header.vue
@@ -57,6 +57,9 @@ export default {
canCreateEpic: {
default: false,
},
+ isEpicBoard: {
+ default: false,
+ },
},
props: {
list: {
@@ -76,7 +79,7 @@ export default {
},
computed: {
...mapState(['activeId', 'filterParams', 'boardId']),
- ...mapGetters(['isEpicBoard', 'isSwimlanesOn']),
+ ...mapGetters(['isSwimlanesOn']),
isLoggedIn() {
return Boolean(this.currentUserId);
},
@@ -168,6 +171,9 @@ export default {
filters: this.filterParams,
};
},
+ context: {
+ isSingleRequest: true,
+ },
skip() {
return this.isEpicBoard;
},
diff --git a/app/assets/javascripts/boards/components/board_settings_sidebar.vue b/app/assets/javascripts/boards/components/board_settings_sidebar.vue
index e93edad675c..c0c2699b63d 100644
--- a/app/assets/javascripts/boards/components/board_settings_sidebar.vue
+++ b/app/assets/javascripts/boards/components/board_settings_sidebar.vue
@@ -31,7 +31,7 @@ export default {
GlModal: GlModalDirective,
},
mixins: [glFeatureFlagMixin(), Tracking.mixin()],
- inject: ['canAdminList', 'scopedLabelsAvailable'],
+ inject: ['canAdminList', 'scopedLabelsAvailable', 'isIssueBoard'],
inheritAttrs: false,
data() {
return {
@@ -40,10 +40,10 @@ export default {
},
modalId: 'board-settings-sidebar-modal',
computed: {
- ...mapGetters(['isSidebarOpen', 'isEpicBoard']),
+ ...mapGetters(['isSidebarOpen']),
...mapState(['activeId', 'sidebarType', 'boardLists']),
isWipLimitsOn() {
- return this.glFeatures.wipLimits && !this.isEpicBoard;
+ return this.glFeatures.wipLimits && this.isIssueBoard;
},
activeList() {
return this.boardLists[this.activeId] || {};
diff --git a/app/assets/javascripts/boards/components/board_top_bar.vue b/app/assets/javascripts/boards/components/board_top_bar.vue
index 54a6e3000a4..368feba9a44 100644
--- a/app/assets/javascripts/boards/components/board_top_bar.vue
+++ b/app/assets/javascripts/boards/components/board_top_bar.vue
@@ -1,5 +1,4 @@
<script>
-import { mapGetters } from 'vuex';
import BoardAddNewColumnTrigger from '~/boards/components/board_add_new_column_trigger.vue';
import BoardsSelector from 'ee_else_ce/boards/components/boards_selector.vue';
import IssueBoardFilteredSearch from 'ee_else_ce/boards/components/issue_board_filtered_search.vue';
@@ -20,10 +19,7 @@ export default {
EpicBoardFilteredSearch: () =>
import('ee_component/boards/components/epic_filtered_search.vue'),
},
- inject: ['swimlanesFeatureAvailable', 'canAdminList', 'isSignedIn'],
- computed: {
- ...mapGetters(['isEpicBoard']),
- },
+ inject: ['swimlanesFeatureAvailable', 'canAdminList', 'isSignedIn', 'isIssueBoard'],
};
</script>
@@ -37,8 +33,8 @@ export default {
>
<boards-selector />
<new-board-button />
- <epic-board-filtered-search v-if="isEpicBoard" />
- <issue-board-filtered-search v-else />
+ <issue-board-filtered-search v-if="isIssueBoard" />
+ <epic-board-filtered-search v-else />
</div>
<div
class="filter-dropdown-container gl-md-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-align-items-flex-start"
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 bab6fe26978..605e11d1590 100644
--- a/app/assets/javascripts/boards/components/issue_board_filtered_search.vue
+++ b/app/assets/javascripts/boards/components/issue_board_filtered_search.vue
@@ -12,9 +12,24 @@ import { TYPE_USER } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { __ } from '~/locale';
import {
- TOKEN_TITLE_MY_REACTION,
OPERATOR_IS_AND_IS_NOT,
OPERATOR_IS_ONLY,
+ TOKEN_TITLE_ASSIGNEE,
+ TOKEN_TITLE_AUTHOR,
+ TOKEN_TITLE_CONFIDENTIAL,
+ TOKEN_TITLE_LABEL,
+ TOKEN_TITLE_MILESTONE,
+ TOKEN_TITLE_MY_REACTION,
+ TOKEN_TITLE_RELEASE,
+ TOKEN_TITLE_TYPE,
+ TOKEN_TYPE_ASSIGNEE,
+ TOKEN_TYPE_AUTHOR,
+ TOKEN_TYPE_CONFIDENTIAL,
+ TOKEN_TYPE_LABEL,
+ TOKEN_TYPE_MILESTONE,
+ TOKEN_TYPE_MY_REACTION,
+ TOKEN_TYPE_RELEASE,
+ TOKEN_TYPE_TYPE,
} from '~/vue_shared/components/filtered_search_bar/constants';
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue';
@@ -28,17 +43,8 @@ export default {
INCIDENT: 'INCIDENT',
},
i18n: {
- search: __('Search'),
- epic: __('Epic'),
- label: __('Label'),
- author: __('Author'),
- assignee: __('Assignee'),
- type: __('Type'),
incident: __('Incident'),
issue: __('Issue'),
- milestone: __('Milestone'),
- release: __('Release'),
- confidential: __('Confidential'),
},
components: { BoardFilteredSearch },
inject: ['isSignedIn', 'releasesFetchPath', 'fullPath', 'boardType'],
@@ -52,17 +58,7 @@ export default {
: this.fullPath.slice(0, this.fullPath.lastIndexOf('/'));
},
tokensCE() {
- const {
- label,
- author,
- assignee,
- issue,
- incident,
- type,
- milestone,
- release,
- confidential,
- } = this.$options.i18n;
+ const { issue, incident } = this.$options.i18n;
const { types } = this.$options;
const { fetchAuthors, fetchLabels } = issueBoardFilters(
this.$apollo,
@@ -73,8 +69,8 @@ export default {
const tokens = [
{
icon: 'user',
- title: assignee,
- type: 'assignee',
+ title: TOKEN_TITLE_ASSIGNEE,
+ type: TOKEN_TYPE_ASSIGNEE,
operators: OPERATOR_IS_AND_IS_NOT,
token: AuthorToken,
unique: true,
@@ -83,8 +79,8 @@ export default {
},
{
icon: 'pencil',
- title: author,
- type: 'author',
+ title: TOKEN_TITLE_AUTHOR,
+ type: TOKEN_TYPE_AUTHOR,
operators: OPERATOR_IS_AND_IS_NOT,
symbol: '@',
token: AuthorToken,
@@ -94,8 +90,8 @@ export default {
},
{
icon: 'labels',
- title: label,
- type: 'label',
+ title: TOKEN_TITLE_LABEL,
+ type: TOKEN_TYPE_LABEL,
operators: OPERATOR_IS_AND_IS_NOT,
token: LabelToken,
unique: false,
@@ -105,7 +101,7 @@ export default {
...(this.isSignedIn
? [
{
- type: 'my-reaction',
+ type: TOKEN_TYPE_MY_REACTION,
title: TOKEN_TITLE_MY_REACTION,
icon: 'thumb-up',
token: EmojiToken,
@@ -127,9 +123,9 @@ export default {
},
},
{
- type: 'confidential',
+ type: TOKEN_TYPE_CONFIDENTIAL,
icon: 'eye-slash',
- title: confidential,
+ title: TOKEN_TITLE_CONFIDENTIAL,
unique: true,
token: GlFilteredSearchToken,
operators: OPERATOR_IS_ONLY,
@@ -141,8 +137,8 @@ export default {
]
: []),
{
- type: 'milestone',
- title: milestone,
+ type: TOKEN_TYPE_MILESTONE,
+ title: TOKEN_TITLE_MILESTONE,
icon: 'clock',
symbol: '%',
token: MilestoneToken,
@@ -152,8 +148,8 @@ export default {
},
{
icon: 'issues',
- title: type,
- type: 'type',
+ title: TOKEN_TITLE_TYPE,
+ type: TOKEN_TYPE_TYPE,
token: GlFilteredSearchToken,
unique: true,
options: [
@@ -162,8 +158,8 @@ export default {
],
},
{
- type: 'release',
- title: release,
+ type: TOKEN_TYPE_RELEASE,
+ title: TOKEN_TITLE_RELEASE,
icon: 'rocket',
token: ReleaseToken,
fetchReleases: (search) => {
diff --git a/app/assets/javascripts/boards/graphql.js b/app/assets/javascripts/boards/graphql.js
deleted file mode 100644
index d066a5d002e..00000000000
--- a/app/assets/javascripts/boards/graphql.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { defaultDataIdFromObject } from '@apollo/client/core';
-import createDefaultClient from '~/lib/graphql';
-
-export const gqlClient = createDefaultClient(
- {},
- {
- cacheConfig: {
- dataIdFromObject: (object) => {
- // eslint-disable-next-line no-underscore-dangle
- return object.__typename === 'BoardList' ? object.iid : defaultDataIdFromObject(object);
- },
- },
- batchMax: 2,
- },
-);
diff --git a/app/assets/javascripts/boards/graphql/board_lists_deferred.query.graphql b/app/assets/javascripts/boards/graphql/board_lists_deferred.query.graphql
index f48383624c9..d5498f03e4b 100644
--- a/app/assets/javascripts/boards/graphql/board_lists_deferred.query.graphql
+++ b/app/assets/javascripts/boards/graphql/board_lists_deferred.query.graphql
@@ -1,4 +1,4 @@
-query BoardList($id: ListID!, $filters: BoardIssueInput) {
+query BoardListCount($id: ListID!, $filters: BoardIssueInput) {
boardList(id: $id, issueFilters: $filters) {
id
issuesCount
diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js
index a7003edba47..f8bd81e6b98 100644
--- a/app/assets/javascripts/boards/index.js
+++ b/app/assets/javascripts/boards/index.js
@@ -12,14 +12,14 @@ import {
convertObjectPropsToCamelCase,
} from '~/lib/utils/common_utils';
import { queryToObject } from '~/lib/utils/url_utility';
+import { defaultClient } from '~/graphql_shared/issuable_client';
import { fullBoardId } from './boards_util';
-import { gqlClient } from './graphql';
Vue.use(VueApollo);
Vue.use(PortalVue);
const apolloProvider = new VueApollo({
- defaultClient: gqlClient,
+ defaultClient,
});
function mountBoardApp(el) {
@@ -53,6 +53,8 @@ function mountBoardApp(el) {
store,
apolloProvider,
provide: {
+ isApolloBoard: window.gon?.features?.apolloBoards,
+ fullBoardId: fullBoardId(boardId),
disabled: parseBoolean(el.dataset.disabled),
groupId: Number(groupId),
rootPath,
@@ -70,6 +72,8 @@ function mountBoardApp(el) {
emailsDisabled: parseBoolean(el.dataset.emailsDisabled),
hasMissingBoards: parseBoolean(el.dataset.hasMissingBoards),
weights: el.dataset.weights ? JSON.parse(el.dataset.weights) : [],
+ isIssueBoard: true,
+ isEpicBoard: false,
// Permissions
canUpdate: parseBoolean(el.dataset.canUpdate),
canAdminList: parseBoolean(el.dataset.canAdminList),
diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js
index c2e346da606..e5437690fd4 100644
--- a/app/assets/javascripts/boards/stores/actions.js
+++ b/app/assets/javascripts/boards/stores/actions.js
@@ -34,11 +34,11 @@ import issueMoveListMutation from 'ee_else_ce/boards/graphql/issue_move_list.mut
import totalCountAndWeightQuery from 'ee_else_ce/boards/graphql/board_lists_deferred.query.graphql';
import { fetchPolicies } from '~/lib/graphql';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { defaultClient as gqlClient } from '~/graphql_shared/issuable_client';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { queryToObject } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import eventHub from '../eventhub';
-import { gqlClient } from '../graphql';
import projectBoardQuery from '../graphql/project_board.query.graphql';
import groupBoardQuery from '../graphql/group_board.query.graphql';
import boardLabelsQuery from '../graphql/board_labels.query.graphql';
@@ -149,6 +149,9 @@ export default {
query: listsQuery[issuableType].query,
variables,
...(resetLists ? { fetchPolicy: fetchPolicies.NO_CACHE } : {}),
+ context: {
+ isSingleRequest: true,
+ },
})
.then(({ data }) => {
const { lists, hideBacklogList } = data[boardType].board;
diff --git a/app/assets/javascripts/branches/components/delete_merged_branches.vue b/app/assets/javascripts/branches/components/delete_merged_branches.vue
new file mode 100644
index 00000000000..70974f2e725
--- /dev/null
+++ b/app/assets/javascripts/branches/components/delete_merged_branches.vue
@@ -0,0 +1,171 @@
+<script>
+import { GlButton, GlFormInput, GlModal, GlSprintf, GlTooltipDirective } from '@gitlab/ui';
+import csrf from '~/lib/utils/csrf';
+import { sprintf, s__, __ } from '~/locale';
+
+export const i18n = {
+ deleteButtonText: s__('Branches|Delete merged branches'),
+ buttonTooltipText: s__("Branches|Delete all branches that are merged into '%{defaultBranch}'"),
+ modalTitle: s__('Branches|Delete all merged branches?'),
+ modalMessage: s__(
+ 'Branches|You are about to %{strongStart}delete all branches%{strongEnd} that were merged into %{codeStart}%{defaultBranch}%{codeEnd}.',
+ ),
+ notVisibleBranchesWarning: s__(
+ 'Branches|This may include merged branches that are not visible on the current screen.',
+ ),
+ protectedBranchWarning: s__(
+ "Branches|A branch won't be deleted if it is protected or associated with an open merge request.",
+ ),
+ permanentEffectWarning: s__(
+ 'Branches|This bulk action is %{strongStart}permanent and cannot be undone or recovered%{strongEnd}.',
+ ),
+ confirmationMessage: s__(
+ 'Branches|Plese type the following to confirm: %{codeStart}delete%{codeEnd}.',
+ ),
+ cancelButtonText: __('Cancel'),
+};
+
+export default {
+ csrf,
+ components: {
+ GlModal,
+ GlButton,
+ GlFormInput,
+ GlSprintf,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ formPath: {
+ type: String,
+ required: true,
+ },
+ defaultBranch: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ areAllBranchesVisible: false,
+ enteredText: '',
+ };
+ },
+ computed: {
+ buttonTooltipText() {
+ return sprintf(this.$options.i18n.buttonTooltipText, { defaultBranch: this.defaultBranch });
+ },
+ modalMessage() {
+ return sprintf(this.$options.i18n.modalMessage, {
+ defaultBranch: this.defaultBranch,
+ });
+ },
+ isDeletingConfirmed() {
+ return this.enteredText.trim().toLowerCase() === 'delete';
+ },
+ isDeleteButtonDisabled() {
+ return !this.isDeletingConfirmed;
+ },
+ },
+ methods: {
+ openModal() {
+ this.$refs.modal.show();
+ },
+ submitForm() {
+ if (!this.isDeleteButtonDisabled) {
+ this.$refs.form.submit();
+ }
+ },
+ closeModal() {
+ this.$refs.modal.hide();
+ },
+ },
+ i18n,
+};
+</script>
+
+<template>
+ <div>
+ <gl-button
+ v-gl-tooltip="buttonTooltipText"
+ class="gl-mr-3"
+ data-qa-selector="delete_merged_branches_button"
+ category="secondary"
+ variant="danger"
+ @click="openModal"
+ >{{ $options.i18n.deleteButtonText }}
+ </gl-button>
+ <gl-modal
+ ref="modal"
+ size="sm"
+ modal-id="delete-merged-branches"
+ :title="$options.i18n.modalTitle"
+ >
+ <form ref="form" :action="formPath" method="post" @submit.prevent>
+ <p>
+ <gl-sprintf :message="modalMessage">
+ <template #strong="{ content }">
+ <strong>{{ content }}</strong>
+ </template>
+ <template #code="{ content }">
+ <code>{{ content }}</code>
+ </template>
+ </gl-sprintf>
+ </p>
+ <p>
+ {{ $options.i18n.notVisibleBranchesWarning }}
+ </p>
+ <p>
+ {{ $options.i18n.protectedBranchWarning }}
+ </p>
+ <p>
+ <gl-sprintf :message="$options.i18n.permanentEffectWarning">
+ <template #strong="{ content }">
+ <strong>{{ content }}</strong>
+ </template>
+ </gl-sprintf>
+ </p>
+ <p>
+ <gl-sprintf :message="$options.i18n.confirmationMessage">
+ <template #code="{ content }">
+ <code>{{ content }}</code>
+ </template>
+ </gl-sprintf>
+ <gl-form-input
+ v-model="enteredText"
+ data-qa-selector="delete_merged_branches_input"
+ type="text"
+ size="sm"
+ class="gl-mt-2"
+ aria-labelledby="input-label"
+ autocomplete="off"
+ @keyup.enter="submitForm"
+ />
+ </p>
+
+ <input ref="method" type="hidden" name="_method" value="delete" />
+ <input :value="$options.csrf.token" type="hidden" name="authenticity_token" />
+ </form>
+
+ <template #modal-footer>
+ <div
+ class="gl-display-flex gl-flex-direction-row gl-justify-content-end gl-flex-wrap gl-m-0 gl-mr-3"
+ >
+ <gl-button data-testid="delete-merged-branches-cancel-button" @click="closeModal">
+ {{ $options.i18n.cancelButtonText }}
+ </gl-button>
+ <gl-button
+ ref="deleteMergedBrancesButton"
+ :disabled="isDeleteButtonDisabled"
+ variant="danger"
+ data-qa-selector="delete_merged_branches_confirmation_button"
+ data-testid="delete-merged-branches-confirmation-button"
+ @click="submitForm"
+ >{{ $options.i18n.deleteButtonText }}</gl-button
+ >
+ </div>
+ </template>
+ </gl-modal>
+ </div>
+</template>
diff --git a/app/assets/javascripts/branches/init_delete_merged_branches.js b/app/assets/javascripts/branches/init_delete_merged_branches.js
new file mode 100644
index 00000000000..998db07d8de
--- /dev/null
+++ b/app/assets/javascripts/branches/init_delete_merged_branches.js
@@ -0,0 +1,23 @@
+import Vue from 'vue';
+import DeleteMergedBranches from '~/branches/components/delete_merged_branches.vue';
+
+export default function initDeleteMergedBranchesModal() {
+ const el = document.querySelector('.js-delete-merged-branches');
+ if (!el) {
+ return false;
+ }
+
+ const { formPath, defaultBranch } = el.dataset;
+
+ return new Vue({
+ el,
+ render(createComponent) {
+ return createComponent(DeleteMergedBranches, {
+ props: {
+ formPath,
+ defaultBranch,
+ },
+ });
+ },
+ });
+}
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
new file mode 100644
index 00000000000..16bfc7f3abe
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/delete_pipeline_schedule_modal.vue
@@ -0,0 +1,45 @@
+<script>
+import { GlModal } from '@gitlab/ui';
+import { s__, __ } from '~/locale';
+
+export default {
+ modal: {
+ id: 'delete-pipeline-schedule-modal',
+ deleteConfirmation: s__(
+ 'PipelineSchedules|Are you sure you want to delete this pipeline schedule?',
+ ),
+ actionPrimary: {
+ text: s__('PipelineSchedules|Delete pipeline schedule'),
+ attributes: [{ variant: 'danger' }],
+ },
+ actionCancel: {
+ text: __('Cancel'),
+ attributes: [],
+ },
+ },
+ components: {
+ GlModal,
+ },
+ props: {
+ visible: {
+ type: Boolean,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-modal
+ :visible="visible"
+ :title="$options.modal.actionPrimary.text"
+ :modal-id="$options.modal.id"
+ :action-primary="$options.modal.actionPrimary"
+ :action-cancel="$options.modal.actionCancel"
+ size="sm"
+ @primary="$emit('deleteSchedule')"
+ @hide="$emit('hideModal')"
+ >
+ {{ $options.modal.deleteConfirmation }}
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue
new file mode 100644
index 00000000000..fe16cb7a92e
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue
@@ -0,0 +1,256 @@
+<script>
+import { GlAlert, GlBadge, GlButton, GlLoadingIcon, GlTabs, GlTab } from '@gitlab/ui';
+import { s__, sprintf } from '~/locale';
+import { limitedCounterWithDelimiter } from '~/lib/utils/text_utility';
+import { queryToObject } from '~/lib/utils/url_utility';
+import deletePipelineScheduleMutation from '../graphql/mutations/delete_pipeline_schedule.mutation.graphql';
+import takeOwnershipMutation from '../graphql/mutations/take_ownership.mutation.graphql';
+import getPipelineSchedulesQuery from '../graphql/queries/get_pipeline_schedules.query.graphql';
+import PipelineSchedulesTable from './table/pipeline_schedules_table.vue';
+import TakeOwnershipModal from './take_ownership_modal.vue';
+import DeletePipelineScheduleModal from './delete_pipeline_schedule_modal.vue';
+
+export default {
+ i18n: {
+ schedulesFetchError: s__('PipelineSchedules|There was a problem fetching pipeline schedules.'),
+ scheduleDeleteError: s__(
+ 'PipelineSchedules|There was a problem deleting the pipeline schedule.',
+ ),
+ takeOwnershipError: s__(
+ 'PipelineSchedules|There was a problem taking ownership of the pipeline schedule.',
+ ),
+ newSchedule: s__('PipelineSchedules|New schedule'),
+ deleteSuccess: s__('PipelineSchedules|Pipeline schedule successfully deleted.'),
+ },
+ components: {
+ DeletePipelineScheduleModal,
+ GlAlert,
+ GlBadge,
+ GlButton,
+ GlLoadingIcon,
+ GlTabs,
+ GlTab,
+ PipelineSchedulesTable,
+ TakeOwnershipModal,
+ },
+ inject: {
+ fullPath: {
+ default: '',
+ },
+ },
+ apollo: {
+ schedules: {
+ query: getPipelineSchedulesQuery,
+ variables() {
+ return {
+ projectPath: this.fullPath,
+ status: this.scope,
+ };
+ },
+ update(data) {
+ const { pipelineSchedules: { nodes: list = [], count } = {} } = data.project || {};
+
+ return {
+ list,
+ count,
+ };
+ },
+ error() {
+ this.reportError(this.$options.i18n.schedulesFetchError);
+ },
+ },
+ },
+ data() {
+ const { scope } = queryToObject(window.location.search);
+ return {
+ schedules: {
+ list: [],
+ },
+ scope,
+ hasError: false,
+ errorMessage: '',
+ scheduleId: null,
+ showDeleteModal: false,
+ showTakeOwnershipModal: false,
+ count: 0,
+ };
+ },
+ computed: {
+ isLoading() {
+ return this.$apollo.queries.schedules.loading;
+ },
+ schedulesCount() {
+ return this.schedules.count;
+ },
+ tabs() {
+ return [
+ {
+ text: s__('PipelineSchedules|All'),
+ count: limitedCounterWithDelimiter(this.count),
+ scope: null,
+ showBadge: true,
+ attrs: { 'data-testid': 'pipeline-schedules-all-tab' },
+ },
+ {
+ text: s__('PipelineSchedules|Active'),
+ scope: 'ACTIVE',
+ showBadge: false,
+ attrs: { 'data-testid': 'pipeline-schedules-active-tab' },
+ },
+ {
+ text: s__('PipelineSchedules|Inactive'),
+ scope: 'INACTIVE',
+ showBadge: false,
+ attrs: { 'data-testid': 'pipeline-schedules-inactive-tab' },
+ },
+ ];
+ },
+ },
+ watch: {
+ // this watcher ensures that the count on the all tab
+ // is not updated when switching to other tabs
+ schedulesCount(newCount) {
+ if (!this.scope) {
+ this.count = newCount;
+ }
+ },
+ },
+ methods: {
+ reportError(error) {
+ this.hasError = true;
+ this.errorMessage = error;
+ },
+ setDeleteModal(id) {
+ this.showDeleteModal = true;
+ this.scheduleId = id;
+ },
+ setTakeOwnershipModal(id) {
+ this.showTakeOwnershipModal = true;
+ this.scheduleId = id;
+ },
+ hideModal() {
+ this.showDeleteModal = false;
+ this.showTakeOwnershipModal = false;
+ this.scheduleId = null;
+ },
+ async deleteSchedule() {
+ try {
+ const {
+ data: {
+ pipelineScheduleDelete: { errors },
+ },
+ } = await this.$apollo.mutate({
+ mutation: deletePipelineScheduleMutation,
+ variables: { id: this.scheduleId },
+ });
+
+ if (errors.length > 0) {
+ throw new Error();
+ } else {
+ this.$apollo.queries.schedules.refetch();
+ this.$toast.show(this.$options.i18n.deleteSuccess);
+ }
+ } catch {
+ this.reportError(this.$options.i18n.scheduleDeleteError);
+ }
+ },
+ async takeOwnership() {
+ try {
+ const {
+ data: {
+ pipelineScheduleTakeOwnership: { pipelineSchedule, errors },
+ },
+ } = await this.$apollo.mutate({
+ mutation: takeOwnershipMutation,
+ variables: { id: this.scheduleId },
+ });
+
+ if (errors.length > 0) {
+ throw new Error();
+ } else {
+ this.$apollo.queries.schedules.refetch();
+
+ if (pipelineSchedule?.owner?.name) {
+ const toastMsg = sprintf(
+ s__('PipelineSchedules|Successfully taken ownership from %{owner}.'),
+ {
+ owner: pipelineSchedule.owner.name,
+ },
+ );
+
+ this.$toast.show(toastMsg);
+ }
+ }
+ } catch {
+ this.reportError(this.$options.i18n.takeOwnershipError);
+ }
+ },
+ fetchPipelineSchedulesByStatus(scope) {
+ this.scope = scope;
+ this.$apollo.queries.schedules.refetch();
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-alert v-if="hasError" class="gl-mb-2" variant="danger" @dismiss="hasError = false">
+ {{ errorMessage }}
+ </gl-alert>
+
+ <template v-else>
+ <gl-tabs
+ sync-active-tab-with-query-params
+ query-param-name="scope"
+ nav-class="gl-flex-grow-1 gl-align-items-center"
+ >
+ <gl-tab
+ v-for="tab in tabs"
+ :key="tab.text"
+ :title-link-attributes="tab.attrs"
+ :query-param-value="tab.scope"
+ @click="fetchPipelineSchedulesByStatus(tab.scope)"
+ >
+ <template #title>
+ <span>{{ tab.text }}</span>
+
+ <template v-if="tab.showBadge">
+ <gl-loading-icon v-if="tab.scope === scope && isLoading" class="gl-ml-2" />
+
+ <gl-badge v-else-if="tab.count" size="sm" class="gl-tab-counter-badge">
+ {{ tab.count }}
+ </gl-badge>
+ </template>
+ </template>
+
+ <gl-loading-icon v-if="isLoading" size="lg" />
+ <pipeline-schedules-table
+ v-else
+ :schedules="schedules.list"
+ @showTakeOwnershipModal="setTakeOwnershipModal"
+ @showDeleteModal="setDeleteModal"
+ />
+ </gl-tab>
+
+ <template #tabs-end>
+ <gl-button variant="confirm" class="gl-ml-auto" data-testid="new-schedule-button">
+ {{ $options.i18n.newSchedule }}
+ </gl-button>
+ </template>
+ </gl-tabs>
+
+ <take-ownership-modal
+ :visible="showTakeOwnershipModal"
+ @takeOwnership="takeOwnership"
+ @hideModal="hideModal"
+ />
+
+ <delete-pipeline-schedule-modal
+ :visible="showDeleteModal"
+ @deleteSchedule="deleteSchedule"
+ @hideModal="hideModal"
+ />
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules_form.vue b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue
index 6e24ac6b8d4..6e24ac6b8d4 100644
--- a/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules_form.vue
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue
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
new file mode 100644
index 00000000000..8656e5d3536
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue
@@ -0,0 +1,68 @@
+<script>
+import { GlButton, GlButtonGroup, GlTooltipDirective as GlTooltip } from '@gitlab/ui';
+import { s__ } from '~/locale';
+
+export const i18n = {
+ playTooltip: s__('PipelineSchedules|Run pipeline schedule'),
+ editTooltip: s__('PipelineSchedules|Edit pipeline schedule'),
+ deleteTooltip: s__('PipelineSchedules|Delete pipeline schedule'),
+ takeOwnershipTooltip: s__('PipelineSchedules|Take ownership of pipeline schedule'),
+};
+
+export default {
+ i18n,
+ components: {
+ GlButton,
+ GlButtonGroup,
+ },
+ directives: {
+ GlTooltip,
+ },
+ props: {
+ schedule: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ canPlay() {
+ return this.schedule.userPermissions.playPipelineSchedule;
+ },
+ canTakeOwnership() {
+ return this.schedule.userPermissions.takeOwnershipPipelineSchedule;
+ },
+ canUpdate() {
+ return this.schedule.userPermissions.updatePipelineSchedule;
+ },
+ canRemove() {
+ return this.schedule.userPermissions.adminPipelineSchedule;
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-display-flex gl-justify-content-end">
+ <gl-button-group>
+ <gl-button v-if="canPlay" v-gl-tooltip :title="$options.i18n.playTooltip" icon="play" />
+ <gl-button
+ v-if="canTakeOwnership"
+ v-gl-tooltip
+ :title="$options.i18n.takeOwnershipTooltip"
+ icon="user"
+ data-testid="take-ownership-pipeline-schedule-btn"
+ @click="$emit('showTakeOwnershipModal', schedule.id)"
+ />
+ <gl-button v-if="canUpdate" v-gl-tooltip :title="$options.i18n.editTooltip" icon="pencil" />
+ <gl-button
+ v-if="canRemove"
+ v-gl-tooltip
+ :title="$options.i18n.deleteTooltip"
+ icon="remove"
+ variant="danger"
+ data-testid="delete-pipeline-schedule-btn"
+ @click="$emit('showDeleteModal', schedule.id)"
+ />
+ </gl-button-group>
+ </div>
+</template>
diff --git a/app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline.vue b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline.vue
index 216796b357c..216796b357c 100644
--- a/app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline.vue
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline.vue
diff --git a/app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_next_run.vue b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run.vue
index 48d59bf6e7c..48d59bf6e7c 100644
--- a/app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_next_run.vue
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run.vue
diff --git a/app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_owner.vue b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner.vue
index e7fa94eb7fc..e7fa94eb7fc 100644
--- a/app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_owner.vue
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner.vue
diff --git a/app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue
index 08efa794bcc..08efa794bcc 100644
--- a/app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue
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
new file mode 100644
index 00000000000..1b97a35a51e
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue
@@ -0,0 +1,102 @@
+<script>
+import { GlTableLite } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import PipelineScheduleActions from './cells/pipeline_schedule_actions.vue';
+import PipelineScheduleLastPipeline from './cells/pipeline_schedule_last_pipeline.vue';
+import PipelineScheduleNextRun from './cells/pipeline_schedule_next_run.vue';
+import PipelineScheduleOwner from './cells/pipeline_schedule_owner.vue';
+import PipelineScheduleTarget from './cells/pipeline_schedule_target.vue';
+
+export default {
+ fields: [
+ {
+ key: 'description',
+ label: s__('PipelineSchedules|Description'),
+ thClass: 'gl-border-t-none!',
+ columnClass: 'gl-w-40p',
+ },
+ {
+ key: 'target',
+ label: s__('PipelineSchedules|Target'),
+ thClass: 'gl-border-t-none!',
+ columnClass: 'gl-w-10p',
+ },
+ {
+ key: 'pipeline',
+ label: s__('PipelineSchedules|Last Pipeline'),
+ thClass: 'gl-border-t-none!',
+ columnClass: 'gl-w-10p',
+ },
+ {
+ key: 'next',
+ label: s__('PipelineSchedules|Next Run'),
+ thClass: 'gl-border-t-none!',
+ columnClass: 'gl-w-15p',
+ },
+ {
+ key: 'owner',
+ label: s__('PipelineSchedules|Owner'),
+ thClass: 'gl-border-t-none!',
+ columnClass: 'gl-w-10p',
+ },
+ {
+ key: 'actions',
+ label: '',
+ thClass: 'gl-border-t-none!',
+ columnClass: 'gl-w-15p',
+ },
+ ],
+ components: {
+ GlTableLite,
+ PipelineScheduleActions,
+ PipelineScheduleLastPipeline,
+ PipelineScheduleNextRun,
+ PipelineScheduleOwner,
+ PipelineScheduleTarget,
+ },
+ props: {
+ schedules: {
+ type: Array,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-table-lite :fields="$options.fields" :items="schedules" stacked="md">
+ <template #table-colgroup="{ fields }">
+ <col v-for="field in fields" :key="field.key" :class="field.columnClass" />
+ </template>
+
+ <template #cell(description)="{ item }">
+ <span data-testid="pipeline-schedule-description">
+ {{ item.description }}
+ </span>
+ </template>
+
+ <template #cell(target)="{ item }">
+ <pipeline-schedule-target :schedule="item" />
+ </template>
+
+ <template #cell(pipeline)="{ item }">
+ <pipeline-schedule-last-pipeline :schedule="item" />
+ </template>
+
+ <template #cell(next)="{ item }">
+ <pipeline-schedule-next-run :schedule="item" />
+ </template>
+
+ <template #cell(owner)="{ item }">
+ <pipeline-schedule-owner :schedule="item" />
+ </template>
+
+ <template #cell(actions)="{ item }">
+ <pipeline-schedule-actions
+ :schedule="item"
+ @showTakeOwnershipModal="$emit('showTakeOwnershipModal', $event)"
+ @showDeleteModal="$emit('showDeleteModal', $event)"
+ />
+ </template>
+ </gl-table-lite>
+</template>
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
new file mode 100644
index 00000000000..3ac52d4735d
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal.vue
@@ -0,0 +1,54 @@
+<script>
+import { GlModal } from '@gitlab/ui';
+import { __, s__ } from '~/locale';
+
+export default {
+ modalId: 'pipeline-take-ownership-modal',
+ i18n: {
+ takeOwnership: s__('PipelineSchedules|Take ownership'),
+ ownershipMessage: s__(
+ 'PipelineSchedules|Only the owner of a pipeline schedule can make changes to it. Do you want to take ownership of this schedule?',
+ ),
+ cancelLabel: __('Cancel'),
+ },
+ components: {
+ GlModal,
+ },
+ props: {
+ visible: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ actionCancel() {
+ return { text: this.$options.i18n.cancelLabel };
+ },
+ actionPrimary() {
+ return {
+ text: this.$options.i18n.takeOwnership,
+ attributes: [
+ {
+ variant: 'confirm',
+ category: 'primary',
+ },
+ ],
+ };
+ },
+ },
+};
+</script>
+<template>
+ <gl-modal
+ :visible="visible"
+ :modal-id="$options.modalId"
+ :action-primary="actionPrimary"
+ :action-cancel="actionCancel"
+ :title="$options.i18n.takeOwnership"
+ size="sm"
+ @primary="$emit('takeOwnership')"
+ @hide="$emit('hideModal')"
+ >
+ <p>{{ $options.i18n.ownershipMessage }}</p>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/pipeline_schedules/components/take_ownership_modal.vue b/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue
index 7ded3945a32..7ded3945a32 100644
--- a/app/assets/javascripts/pipeline_schedules/components/take_ownership_modal.vue
+++ b/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue
diff --git a/app/assets/javascripts/pipeline_schedules/graphql/mutations/delete_pipeline_schedule.mutation.graphql b/app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/delete_pipeline_schedule.mutation.graphql
index 8aab0b3fbde..8aab0b3fbde 100644
--- a/app/assets/javascripts/pipeline_schedules/graphql/mutations/delete_pipeline_schedule.mutation.graphql
+++ b/app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/delete_pipeline_schedule.mutation.graphql
diff --git a/app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/take_ownership.mutation.graphql b/app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/take_ownership.mutation.graphql
new file mode 100644
index 00000000000..e410ef91d8b
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/take_ownership.mutation.graphql
@@ -0,0 +1,12 @@
+mutation takeOwnership($id: CiPipelineScheduleID!) {
+ pipelineScheduleTakeOwnership(input: { id: $id }) {
+ pipelineSchedule {
+ id
+ owner {
+ id
+ name
+ }
+ }
+ errors
+ }
+}
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
new file mode 100644
index 00000000000..9f6cb429cca
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql
@@ -0,0 +1,41 @@
+query getPipelineSchedulesQuery($projectPath: ID!, $status: PipelineScheduleStatus) {
+ project(fullPath: $projectPath) {
+ id
+ pipelineSchedules(status: $status) {
+ count
+ nodes {
+ id
+ description
+ forTag
+ refPath
+ refForDisplay
+ lastPipeline {
+ id
+ detailedStatus {
+ id
+ group
+ icon
+ label
+ text
+ detailsPath
+ }
+ }
+ active
+ nextRunAt
+ realNextRun
+ owner {
+ id
+ avatarUrl
+ name
+ webPath
+ }
+ userPermissions {
+ playPipelineSchedule
+ takeOwnershipPipelineSchedule
+ updatePipelineSchedule
+ adminPipelineSchedule
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/ci/pipeline_schedules/mount_pipeline_schedules_app.js b/app/assets/javascripts/ci/pipeline_schedules/mount_pipeline_schedules_app.js
new file mode 100644
index 00000000000..4c06fa321e5
--- /dev/null
+++ b/app/assets/javascripts/ci/pipeline_schedules/mount_pipeline_schedules_app.js
@@ -0,0 +1,34 @@
+import { GlToast } from '@gitlab/ui';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
+import PipelineSchedules from './components/pipeline_schedules.vue';
+
+Vue.use(VueApollo);
+Vue.use(GlToast);
+
+const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+});
+
+export default () => {
+ const containerEl = document.querySelector('#pipeline-schedules-app');
+
+ if (!containerEl) {
+ return false;
+ }
+
+ const { fullPath } = containerEl.dataset;
+
+ return new Vue({
+ el: containerEl,
+ name: 'PipelineSchedulesRoot',
+ apolloProvider,
+ provide: {
+ fullPath,
+ },
+ render(createElement) {
+ return createElement(PipelineSchedules);
+ },
+ });
+};
diff --git a/app/assets/javascripts/pipeline_schedules/mount_pipeline_schedules_form_app.js b/app/assets/javascripts/ci/pipeline_schedules/mount_pipeline_schedules_form_app.js
index d83417ab84a..d83417ab84a 100644
--- a/app/assets/javascripts/pipeline_schedules/mount_pipeline_schedules_form_app.js
+++ b/app/assets/javascripts/ci/pipeline_schedules/mount_pipeline_schedules_form_app.js
diff --git a/app/assets/javascripts/runner/admin_runner_show/admin_runner_show_app.vue b/app/assets/javascripts/ci/runner/admin_runner_show/admin_runner_show_app.vue
index 9fa4b521ebc..9fa4b521ebc 100644
--- a/app/assets/javascripts/runner/admin_runner_show/admin_runner_show_app.vue
+++ b/app/assets/javascripts/ci/runner/admin_runner_show/admin_runner_show_app.vue
diff --git a/app/assets/javascripts/runner/admin_runner_show/index.js b/app/assets/javascripts/ci/runner/admin_runner_show/index.js
index ea455416648..ea455416648 100644
--- a/app/assets/javascripts/runner/admin_runner_show/index.js
+++ b/app/assets/javascripts/ci/runner/admin_runner_show/index.js
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
new file mode 100644
index 00000000000..2915e460085
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/admin_runners/admin_runners_app.vue
@@ -0,0 +1,229 @@
+<script>
+import { GlLink } from '@gitlab/ui';
+import { createAlert } from '~/flash';
+import { updateHistory } from '~/lib/utils/url_utility';
+import { fetchPolicies } from '~/lib/graphql';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { upgradeStatusTokenConfig } from 'ee_else_ce/ci/runner/components/search_tokens/upgrade_status_token_config';
+import {
+ fromUrlQueryToSearch,
+ fromSearchToUrl,
+ fromSearchToVariables,
+ isSearchFiltered,
+} from 'ee_else_ce/ci/runner/runner_search_utils';
+import allRunnersQuery from 'ee_else_ce/ci/runner/graphql/list/all_runners.query.graphql';
+import allRunnersCountQuery from 'ee_else_ce/ci/runner/graphql/list/all_runners_count.query.graphql';
+
+import RegistrationDropdown from '../components/registration/registration_dropdown.vue';
+import RunnerFilteredSearchBar from '../components/runner_filtered_search_bar.vue';
+import RunnerList from '../components/runner_list.vue';
+import RunnerListEmptyState from '../components/runner_list_empty_state.vue';
+import RunnerName from '../components/runner_name.vue';
+import RunnerStats from '../components/stat/runner_stats.vue';
+import RunnerPagination from '../components/runner_pagination.vue';
+import RunnerTypeTabs from '../components/runner_type_tabs.vue';
+import RunnerActionsCell from '../components/cells/runner_actions_cell.vue';
+
+import { pausedTokenConfig } from '../components/search_tokens/paused_token_config';
+import { statusTokenConfig } from '../components/search_tokens/status_token_config';
+import { tagTokenConfig } from '../components/search_tokens/tag_token_config';
+import {
+ ADMIN_FILTERED_SEARCH_NAMESPACE,
+ INSTANCE_TYPE,
+ I18N_FETCH_ERROR,
+ FILTER_CSS_CLASSES,
+} from '../constants';
+import { captureException } from '../sentry_utils';
+
+export default {
+ name: 'AdminRunnersApp',
+ components: {
+ GlLink,
+ RegistrationDropdown,
+ RunnerFilteredSearchBar,
+ RunnerList,
+ RunnerListEmptyState,
+ RunnerName,
+ RunnerStats,
+ RunnerPagination,
+ RunnerTypeTabs,
+ RunnerActionsCell,
+ },
+ mixins: [glFeatureFlagMixin()],
+ inject: ['emptyStateSvgPath', 'emptyStateFilteredSvgPath'],
+ props: {
+ registrationToken: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ search: fromUrlQueryToSearch(),
+ runners: {
+ items: [],
+ pageInfo: {},
+ },
+ };
+ },
+ apollo: {
+ runners: {
+ query: allRunnersQuery,
+ fetchPolicy: fetchPolicies.NETWORK_ONLY,
+ variables() {
+ return this.variables;
+ },
+ update(data) {
+ const { runners } = data;
+ return {
+ items: runners?.nodes || [],
+ pageInfo: runners?.pageInfo || {},
+ };
+ },
+ error(error) {
+ createAlert({ message: I18N_FETCH_ERROR });
+
+ this.reportToSentry(error);
+ },
+ },
+ },
+ computed: {
+ variables() {
+ return fromSearchToVariables(this.search);
+ },
+ countVariables() {
+ // Exclude pagination variables, leave only filters variables
+ const { sort, before, last, after, first, ...countVariables } = this.variables;
+ return countVariables;
+ },
+ runnersLoading() {
+ return this.$apollo.queries.runners.loading;
+ },
+ noRunnersFound() {
+ return !this.runnersLoading && !this.runners.items.length;
+ },
+ searchTokens() {
+ return [
+ pausedTokenConfig,
+ statusTokenConfig,
+ {
+ ...tagTokenConfig,
+ recentSuggestionsStorageKey: `${this.$options.filteredSearchNamespace}-recent-tags`,
+ },
+ upgradeStatusTokenConfig,
+ ];
+ },
+ isSearchFiltered() {
+ return isSearchFiltered(this.search);
+ },
+ },
+ watch: {
+ search: {
+ deep: true,
+ handler() {
+ // TODO Implement back button response using onpopstate
+ // See: https://gitlab.com/gitlab-org/gitlab/-/issues/333804
+ updateHistory({
+ url: fromSearchToUrl(this.search),
+ title: document.title,
+ });
+ },
+ },
+ },
+ errorCaptured(error) {
+ this.reportToSentry(error);
+ },
+ methods: {
+ onToggledPaused() {
+ // When a runner becomes Paused, the tab count can
+ // become stale, refetch outdated counts.
+ this.refetchCounts();
+ },
+ onDeleted({ message }) {
+ this.refetchCounts();
+ this.$root.$toast?.show(message);
+ },
+ refetchCounts() {
+ this.$apollo.getClient().refetchQueries({ include: [allRunnersCountQuery] });
+ },
+ reportToSentry(error) {
+ captureException({ error, component: this.$options.name });
+ },
+ onPaginationInput(value) {
+ this.search.pagination = value;
+ },
+ },
+ filteredSearchNamespace: ADMIN_FILTERED_SEARCH_NAMESPACE,
+ INSTANCE_TYPE,
+ FILTER_CSS_CLASSES,
+};
+</script>
+<template>
+ <div>
+ <div
+ class="gl-display-flex gl-align-items-center gl-flex-direction-column-reverse gl-md-flex-direction-row gl-mt-3 gl-md-mt-0"
+ >
+ <runner-type-tabs
+ v-model="search"
+ :count-scope="$options.INSTANCE_TYPE"
+ :count-variables="countVariables"
+ class="gl-w-full"
+ content-class="gl-display-none"
+ nav-class="gl-border-none!"
+ />
+
+ <registration-dropdown
+ class="gl-w-full gl-sm-w-auto gl-mr-auto"
+ :registration-token="registrationToken"
+ :type="$options.INSTANCE_TYPE"
+ right
+ />
+ </div>
+
+ <runner-filtered-search-bar
+ v-model="search"
+ :class="$options.FILTER_CSS_CLASSES"
+ :tokens="searchTokens"
+ :namespace="$options.filteredSearchNamespace"
+ />
+
+ <runner-stats :scope="$options.INSTANCE_TYPE" :variables="countVariables" />
+
+ <runner-list-empty-state
+ v-if="noRunnersFound"
+ :registration-token="registrationToken"
+ :is-search-filtered="isSearchFiltered"
+ :svg-path="emptyStateSvgPath"
+ :filtered-svg-path="emptyStateFilteredSvgPath"
+ />
+ <template v-else>
+ <runner-list
+ :runners="runners.items"
+ :loading="runnersLoading"
+ :checkable="true"
+ @deleted="onDeleted"
+ >
+ <template #runner-name="{ runner }">
+ <gl-link :href="runner.adminUrl">
+ <runner-name :runner="runner" />
+ </gl-link>
+ </template>
+ <template #runner-actions-cell="{ runner }">
+ <runner-actions-cell
+ :runner="runner"
+ :edit-url="runner.editAdminUrl"
+ @toggledPaused="onToggledPaused"
+ @deleted="onDeleted"
+ />
+ </template>
+ </runner-list>
+ </template>
+
+ <runner-pagination
+ class="gl-mt-3"
+ :disabled="runnersLoading"
+ :page-info="runners.pageInfo"
+ @input="onPaginationInput"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/runner/admin_runners/index.js b/app/assets/javascripts/ci/runner/admin_runners/index.js
new file mode 100644
index 00000000000..c6db7148eb1
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/admin_runners/index.js
@@ -0,0 +1,66 @@
+import { GlToast } from '@gitlab/ui';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { visitUrl } from '~/lib/utils/url_utility';
+import { updateOutdatedUrl } from '~/ci/runner/runner_search_utils';
+import createDefaultClient from '~/lib/graphql';
+import { createLocalState } from '../graphql/list/local_state';
+import { showAlertFromLocalStorage } from '../local_storage_alert/show_alert_from_local_storage';
+import AdminRunnersApp from './admin_runners_app.vue';
+
+Vue.use(GlToast);
+Vue.use(VueApollo);
+
+export const initAdminRunners = (selector = '#js-admin-runners') => {
+ showAlertFromLocalStorage();
+
+ const el = document.querySelector(selector);
+
+ if (!el) {
+ return null;
+ }
+
+ // Redirect outdated URLs
+ const updatedUrlQuery = updateOutdatedUrl();
+ if (updatedUrlQuery) {
+ visitUrl(updatedUrlQuery);
+
+ // Prevent mounting the rest of the app, redirecting now.
+ return null;
+ }
+
+ const {
+ runnerInstallHelpPage,
+ registrationToken,
+ onlineContactTimeoutSecs,
+ staleTimeoutSecs,
+ emptyStateSvgPath,
+ emptyStateFilteredSvgPath,
+ } = el.dataset;
+
+ const { cacheConfig, typeDefs, localMutations } = createLocalState();
+
+ const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient({}, { cacheConfig, typeDefs }),
+ });
+
+ return new Vue({
+ el,
+ apolloProvider,
+ provide: {
+ runnerInstallHelpPage,
+ localMutations,
+ onlineContactTimeoutSecs,
+ staleTimeoutSecs,
+ emptyStateSvgPath,
+ emptyStateFilteredSvgPath,
+ },
+ render(h) {
+ return h(AdminRunnersApp, {
+ props: {
+ registrationToken,
+ },
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/runner/components/cells/link_cell.vue b/app/assets/javascripts/ci/runner/components/cells/link_cell.vue
index 2843ddbacaf..2843ddbacaf 100644
--- a/app/assets/javascripts/runner/components/cells/link_cell.vue
+++ b/app/assets/javascripts/ci/runner/components/cells/link_cell.vue
diff --git a/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue b/app/assets/javascripts/ci/runner/components/cells/runner_actions_cell.vue
index 13f520c4edb..13f520c4edb 100644
--- a/app/assets/javascripts/runner/components/cells/runner_actions_cell.vue
+++ b/app/assets/javascripts/ci/runner/components/cells/runner_actions_cell.vue
diff --git a/app/assets/javascripts/runner/components/cells/runner_owner_cell.vue b/app/assets/javascripts/ci/runner/components/cells/runner_owner_cell.vue
index cb43760b2d6..cb43760b2d6 100644
--- a/app/assets/javascripts/runner/components/cells/runner_owner_cell.vue
+++ b/app/assets/javascripts/ci/runner/components/cells/runner_owner_cell.vue
diff --git a/app/assets/javascripts/ci/runner/components/cells/runner_stacked_summary_cell.vue b/app/assets/javascripts/ci/runner/components/cells/runner_stacked_summary_cell.vue
new file mode 100644
index 00000000000..1e44d5fccc2
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/cells/runner_stacked_summary_cell.vue
@@ -0,0 +1,112 @@
+<script>
+import { GlIcon, GlSprintf, GlTooltipDirective } from '@gitlab/ui';
+
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
+import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
+import RunnerName from '../runner_name.vue';
+import RunnerTags from '../runner_tags.vue';
+import RunnerTypeBadge from '../runner_type_badge.vue';
+
+import { formatJobCount } from '../../utils';
+import {
+ I18N_LOCKED_RUNNER_DESCRIPTION,
+ I18N_VERSION_LABEL,
+ I18N_LAST_CONTACT_LABEL,
+ I18N_CREATED_AT_LABEL,
+} from '../../constants';
+import RunnerSummaryField from './runner_summary_field.vue';
+
+export default {
+ components: {
+ GlIcon,
+ GlSprintf,
+ TimeAgo,
+ RunnerSummaryField,
+ RunnerName,
+ RunnerTags,
+ RunnerTypeBadge,
+ RunnerUpgradeStatusIcon: () =>
+ import('ee_component/ci/runner/components/runner_upgrade_status_icon.vue'),
+ TooltipOnTruncate,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ runner: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ jobCount() {
+ return formatJobCount(this.runner.jobCount);
+ },
+ },
+ i18n: {
+ I18N_LOCKED_RUNNER_DESCRIPTION,
+ I18N_VERSION_LABEL,
+ I18N_LAST_CONTACT_LABEL,
+ I18N_CREATED_AT_LABEL,
+ },
+};
+</script>
+
+<template>
+ <div>
+ <div>
+ <slot :runner="runner" name="runner-name">
+ <runner-name :runner="runner" />
+ </slot>
+ <gl-icon
+ v-if="runner.locked"
+ v-gl-tooltip
+ :title="$options.i18n.I18N_LOCKED_RUNNER_DESCRIPTION"
+ name="lock"
+ />
+ <runner-type-badge :type="runner.runnerType" size="sm" class="gl-vertical-align-middle" />
+ </div>
+
+ <div class="gl-ml-auto gl-display-inline-flex gl-max-w-full gl-py-2">
+ <div class="gl-flex-shrink-0">
+ <runner-upgrade-status-icon :runner="runner" />
+ <gl-sprintf v-if="runner.version" :message="$options.i18n.I18N_VERSION_LABEL">
+ <template #version>{{ runner.version }}</template>
+ </gl-sprintf>
+ </div>
+ <div class="gl-text-secondary gl-mx-2" aria-hidden="true">·</div>
+ <tooltip-on-truncate class="gl-text-truncate gl-display-block" :title="runner.description">
+ {{ runner.description }}
+ </tooltip-on-truncate>
+ </div>
+
+ <div>
+ <runner-summary-field icon="clock">
+ <gl-sprintf :message="$options.i18n.I18N_LAST_CONTACT_LABEL">
+ <template #timeAgo>
+ <time-ago v-if="runner.contactedAt" :time="runner.contactedAt" />
+ <template v-else>{{ __('Never') }}</template>
+ </template>
+ </gl-sprintf>
+ </runner-summary-field>
+
+ <runner-summary-field v-if="runner.ipAddress" icon="disk" :tooltip="__('IP Address')">
+ {{ runner.ipAddress }}
+ </runner-summary-field>
+
+ <runner-summary-field icon="pipeline" data-testid="job-count" :tooltip="__('Jobs')">
+ {{ jobCount }}
+ </runner-summary-field>
+
+ <runner-summary-field icon="calendar">
+ <gl-sprintf :message="$options.i18n.I18N_CREATED_AT_LABEL">
+ <template #timeAgo>
+ <time-ago v-if="runner.createdAt" :time="runner.createdAt" />
+ </template>
+ </gl-sprintf>
+ </runner-summary-field>
+ </div>
+
+ <runner-tags class="gl-display-block gl-pt-2" :tag-list="runner.tagList" size="sm" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ci/runner/components/cells/runner_status_cell.vue b/app/assets/javascripts/ci/runner/components/cells/runner_status_cell.vue
new file mode 100644
index 00000000000..67b9b0a266f
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/cells/runner_status_cell.vue
@@ -0,0 +1,46 @@
+<script>
+import { GlTooltipDirective } from '@gitlab/ui';
+
+import RunnerStatusBadge from '../runner_status_badge.vue';
+import RunnerPausedBadge from '../runner_paused_badge.vue';
+
+export default {
+ components: {
+ RunnerStatusBadge,
+ RunnerUpgradeStatusBadge: () =>
+ import('ee_component/ci/runner/components/runner_upgrade_status_badge.vue'),
+ RunnerPausedBadge,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ runner: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ paused() {
+ return !this.runner.active;
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <runner-status-badge
+ :runner="runner"
+ class="gl-display-inline-block gl-max-w-full gl-text-truncate"
+ />
+ <runner-upgrade-status-badge
+ :runner="runner"
+ class="gl-display-inline-block gl-max-w-full gl-text-truncate"
+ />
+ <runner-paused-badge
+ v-if="paused"
+ class="gl-display-inline-block gl-max-w-full gl-text-truncate"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/runner/components/cells/runner_summary_field.vue b/app/assets/javascripts/ci/runner/components/cells/runner_summary_field.vue
index 1bbbd55089a..1bbbd55089a 100644
--- a/app/assets/javascripts/runner/components/cells/runner_summary_field.vue
+++ b/app/assets/javascripts/ci/runner/components/cells/runner_summary_field.vue
diff --git a/app/assets/javascripts/runner/components/registration/registration_dropdown.vue b/app/assets/javascripts/ci/runner/components/registration/registration_dropdown.vue
index 212ad5fa5a0..212ad5fa5a0 100644
--- a/app/assets/javascripts/runner/components/registration/registration_dropdown.vue
+++ b/app/assets/javascripts/ci/runner/components/registration/registration_dropdown.vue
diff --git a/app/assets/javascripts/runner/components/registration/registration_token.vue b/app/assets/javascripts/ci/runner/components/registration/registration_token.vue
index 6b4e6a929b7..6b4e6a929b7 100644
--- a/app/assets/javascripts/runner/components/registration/registration_token.vue
+++ b/app/assets/javascripts/ci/runner/components/registration/registration_token.vue
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
new file mode 100644
index 00000000000..6740065e860
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/registration/registration_token_reset_dropdown_item.vue
@@ -0,0 +1,141 @@
+<script>
+import { GlDropdownItem, GlLoadingIcon, GlModal, GlModalDirective } from '@gitlab/ui';
+import { createAlert } from '~/flash';
+import { TYPE_GROUP, TYPE_PROJECT } from '~/graphql_shared/constants';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+import { __, s__ } from '~/locale';
+import runnersRegistrationTokenResetMutation from '~/ci/runner/graphql/list/runners_registration_token_reset.mutation.graphql';
+import { captureException } from '~/ci/runner/sentry_utils';
+import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '../../constants';
+
+const i18n = {
+ modalAction: s__('Runners|Reset token'),
+ modalCancel: __('Cancel'),
+ modalCopy: __('Are you sure you want to reset the registration token?'),
+ modalTitle: __('Reset registration token'),
+};
+
+export default {
+ name: 'RunnerRegistrationTokenReset',
+ i18n,
+ components: {
+ GlDropdownItem,
+ GlLoadingIcon,
+ GlModal,
+ },
+ directives: {
+ GlModal: GlModalDirective,
+ },
+ inject: {
+ groupId: {
+ default: null,
+ },
+ projectId: {
+ default: null,
+ },
+ },
+ modalId: 'token-reset-modal',
+ props: {
+ type: {
+ type: String,
+ required: true,
+ validator(type) {
+ return [INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE].includes(type);
+ },
+ },
+ },
+ data() {
+ return {
+ loading: false,
+ };
+ },
+ computed: {
+ resetTokenInput() {
+ switch (this.type) {
+ case INSTANCE_TYPE:
+ return {
+ type: this.type,
+ };
+ case GROUP_TYPE:
+ return {
+ id: convertToGraphQLId(TYPE_GROUP, this.groupId),
+ type: this.type,
+ };
+ case PROJECT_TYPE:
+ return {
+ id: convertToGraphQLId(TYPE_PROJECT, this.projectId),
+ type: this.type,
+ };
+ default:
+ return null;
+ }
+ },
+ actionPrimary() {
+ return {
+ text: i18n.modalAction,
+ attributes: [{ variant: 'danger' }],
+ };
+ },
+ actionSecondary() {
+ return {
+ text: i18n.modalCancel,
+ attributes: [{ variant: 'default' }],
+ };
+ },
+ },
+ methods: {
+ handleModalPrimary() {
+ this.resetToken();
+ },
+ async resetToken() {
+ this.loading = true;
+ try {
+ const {
+ data: {
+ runnersRegistrationTokenReset: { token, errors },
+ },
+ } = await this.$apollo.mutate({
+ mutation: runnersRegistrationTokenResetMutation,
+ variables: {
+ input: this.resetTokenInput,
+ },
+ });
+ if (errors && errors.length) {
+ throw new Error(errors.join(' '));
+ }
+ this.onSuccess(token);
+ } catch (e) {
+ this.onError(e);
+ } finally {
+ this.loading = false;
+ }
+ },
+ onError(error) {
+ const { message } = error;
+
+ createAlert({ message });
+ captureException({ error, component: this.$options.name });
+ },
+ onSuccess(token) {
+ this.$toast?.show(s__('Runners|New registration token generated!'));
+ this.$emit('tokenReset', token);
+ },
+ },
+};
+</script>
+<template>
+ <gl-dropdown-item v-gl-modal="$options.modalId">
+ {{ __('Reset registration token') }}
+ <gl-modal
+ size="sm"
+ :modal-id="$options.modalId"
+ :action-primary="actionPrimary"
+ :action-secondary="actionSecondary"
+ :title="$options.i18n.modalTitle"
+ @primary="handleModalPrimary"
+ >
+ <p>{{ $options.i18n.modalCopy }}</p>
+ </gl-modal>
+ <gl-loading-icon v-if="loading" inline />
+ </gl-dropdown-item>
+</template>
diff --git a/app/assets/javascripts/runner/components/runner_assigned_item.vue b/app/assets/javascripts/ci/runner/components/runner_assigned_item.vue
index 2fa87bdd776..2fa87bdd776 100644
--- a/app/assets/javascripts/runner/components/runner_assigned_item.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_assigned_item.vue
diff --git a/app/assets/javascripts/ci/runner/components/runner_bulk_delete.vue b/app/assets/javascripts/ci/runner/components/runner_bulk_delete.vue
new file mode 100644
index 00000000000..1ec3f8da7c3
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/runner_bulk_delete.vue
@@ -0,0 +1,199 @@
+<script>
+import { GlButton, GlModalDirective, GlModal, GlSprintf } from '@gitlab/ui';
+import { createAlert } from '~/flash';
+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';
+import { RUNNER_TYPENAME } from '../constants';
+
+export default {
+ components: {
+ GlButton,
+ GlModal,
+ GlSprintf,
+ },
+ directives: {
+ GlModal: GlModalDirective,
+ },
+ inject: ['localMutations'],
+ props: {
+ runners: {
+ type: Array,
+ default: () => [],
+ required: false,
+ },
+ },
+ data() {
+ return {
+ isDeleting: false,
+ checkedRunnerIds: [],
+ };
+ },
+ apollo: {
+ checkedRunnerIds: {
+ query: checkedRunnerIdsQuery,
+ },
+ },
+ computed: {
+ currentCheckedRunnerIds() {
+ return this.runners
+ .map(({ id }) => id)
+ .filter((id) => this.checkedRunnerIds.indexOf(id) >= 0);
+ },
+ checkedCount() {
+ return this.currentCheckedRunnerIds.length || 0;
+ },
+ bannerMessage() {
+ return sprintf(
+ n__(
+ 'Runners|%{strongStart}%{count}%{strongEnd} runner selected',
+ 'Runners|%{strongStart}%{count}%{strongEnd} runners selected',
+ this.checkedCount,
+ ),
+ {
+ count: this.checkedCount,
+ },
+ );
+ },
+ modalTitle() {
+ return n__('Runners|Delete %d runner', 'Runners|Delete %d runners', this.checkedCount);
+ },
+ modalActionPrimary() {
+ return {
+ text: n__(
+ 'Runners|Permanently delete %d runner',
+ 'Runners|Permanently delete %d runners',
+ this.checkedCount,
+ ),
+ attributes: {
+ loading: this.isDeleting,
+ variant: 'danger',
+ },
+ };
+ },
+ modalActionCancel() {
+ return {
+ text: __('Cancel'),
+ attributes: {
+ loading: this.isDeleting,
+ },
+ };
+ },
+ modalMessage() {
+ return sprintf(
+ n__(
+ 'Runners|%{strongStart}%{count}%{strongEnd} runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?',
+ 'Runners|%{strongStart}%{count}%{strongEnd} runners will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?',
+ this.checkedCount,
+ ),
+ { count: this.checkedCount },
+ );
+ },
+ },
+ methods: {
+ toastConfirmationMessage(deletedCount) {
+ return n__(
+ 'Runners|%d selected runner deleted',
+ 'Runners|%d selected runners deleted',
+ deletedCount,
+ );
+ },
+ onClearChecked() {
+ this.localMutations.clearChecked();
+ },
+ async onConfirmDelete(e) {
+ this.isDeleting = true;
+ e.preventDefault(); // don't close modal until deletion is complete
+
+ try {
+ await this.$apollo.mutate({
+ mutation: BulkRunnerDelete,
+ variables: {
+ input: {
+ ids: this.currentCheckedRunnerIds,
+ },
+ },
+ update: (cache, { data }) => {
+ const { errors, deletedIds } = data.bulkRunnerDelete;
+
+ if (errors?.length) {
+ createAlert({
+ message: s__(
+ 'Runners|An error occurred while deleting. Some runners may not have been deleted.',
+ ),
+ captureError: true,
+ error: new Error(errors.join(' ')),
+ });
+ }
+
+ if (deletedIds?.length) {
+ this.$emit('deleted', {
+ message: this.toastConfirmationMessage(deletedIds.length),
+ });
+
+ // Remove deleted runners from the cache
+ deletedIds.forEach((id) => {
+ const cacheId = cache.identify({ __typename: RUNNER_TYPENAME, id });
+ cache.evict({ id: cacheId });
+ });
+ cache.gc();
+ }
+ },
+ });
+ } catch (error) {
+ this.onError(error);
+ } finally {
+ this.isDeleting = false;
+ this.$refs.modal.hide();
+ }
+ },
+ onError(error) {
+ createAlert({
+ message: s__(
+ 'Runners|Something went wrong while deleting. Please refresh the page to try again.',
+ ),
+ captureError: true,
+ error,
+ });
+ },
+ },
+ BULK_DELETE_MODAL_ID: 'bulk-delete-modal',
+};
+</script>
+
+<template>
+ <div v-if="checkedCount" 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="bannerMessage">
+ <template #strong="{ content }">
+ <strong>{{ content }}</strong>
+ </template>
+ </gl-sprintf>
+ </div>
+ <div class="gl-ml-auto">
+ <gl-button variant="default" @click="onClearChecked">{{
+ s__('Runners|Clear selection')
+ }}</gl-button>
+ <gl-button v-gl-modal="$options.BULK_DELETE_MODAL_ID" variant="danger">{{
+ s__('Runners|Delete selected')
+ }}</gl-button>
+ </div>
+ </div>
+ <gl-modal
+ ref="modal"
+ size="sm"
+ :modal-id="$options.BULK_DELETE_MODAL_ID"
+ :title="modalTitle"
+ :action-primary="modalActionPrimary"
+ :action-cancel="modalActionCancel"
+ @primary="onConfirmDelete"
+ >
+ <gl-sprintf :message="modalMessage">
+ <template #strong="{ content }">
+ <strong>{{ content }}</strong>
+ </template>
+ </gl-sprintf>
+ </gl-modal>
+ </div>
+</template>
diff --git a/app/assets/javascripts/runner/components/runner_bulk_delete_checkbox.vue b/app/assets/javascripts/ci/runner/components/runner_bulk_delete_checkbox.vue
index 75afb7a00bc..75afb7a00bc 100644
--- a/app/assets/javascripts/runner/components/runner_bulk_delete_checkbox.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_bulk_delete_checkbox.vue
diff --git a/app/assets/javascripts/ci/runner/components/runner_delete_button.vue b/app/assets/javascripts/ci/runner/components/runner_delete_button.vue
new file mode 100644
index 00000000000..32d4076b00f
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/runner_delete_button.vue
@@ -0,0 +1,156 @@
+<script>
+import { GlButton, GlModalDirective, GlTooltipDirective } from '@gitlab/ui';
+import runnerDeleteMutation from '~/ci/runner/graphql/shared/runner_delete.mutation.graphql';
+import { createAlert } from '~/flash';
+import { sprintf, s__ } from '~/locale';
+import { captureException } from '~/ci/runner/sentry_utils';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { I18N_DELETE_RUNNER, I18N_DELETED_TOAST } from '../constants';
+import RunnerDeleteModal from './runner_delete_modal.vue';
+
+export default {
+ name: 'RunnerDeleteButton',
+ components: {
+ GlButton,
+ RunnerDeleteModal,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ GlModal: GlModalDirective,
+ },
+ props: {
+ runner: {
+ type: Object,
+ required: true,
+ validator: (runner) => {
+ return runner?.id && runner?.shortSha;
+ },
+ },
+ compact: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ emits: ['deleted'],
+ data() {
+ return {
+ deleting: false,
+ };
+ },
+ computed: {
+ runnerId() {
+ return getIdFromGraphQLId(this.runner.id);
+ },
+ runnerName() {
+ return `#${this.runnerId} (${this.runner.shortSha})`;
+ },
+ runnerDeleteModalId() {
+ return `delete-runner-modal-${this.runnerId}`;
+ },
+ icon() {
+ if (this.compact) {
+ return 'close';
+ }
+ return '';
+ },
+ buttonContent() {
+ if (this.compact) {
+ return null;
+ }
+ return I18N_DELETE_RUNNER;
+ },
+ buttonClass() {
+ // Ensure a square button is shown when compact: true.
+ // Without this class we will have distorted/rectangular button.
+ if (this.compact) {
+ return 'btn-icon';
+ }
+ return null;
+ },
+ ariaLabel() {
+ if (this.compact) {
+ return I18N_DELETE_RUNNER;
+ }
+ return null;
+ },
+ tooltip() {
+ // Only show basic "delete" tooltip when compact.
+ // Also prevent a "sticky" tooltip: If this button is
+ // loading, mouseout listeners don't run leaving the tooltip stuck
+ if (this.compact && !this.deleting) {
+ return I18N_DELETE_RUNNER;
+ }
+ return '';
+ },
+ },
+ methods: {
+ async onDelete() {
+ // Deleting stays "true" until this row is removed,
+ // should only change back if the operation fails.
+ this.deleting = true;
+ try {
+ await this.$apollo.mutate({
+ mutation: runnerDeleteMutation,
+ variables: {
+ input: {
+ id: this.runner.id,
+ },
+ },
+ update: (cache, { data }) => {
+ const { errors } = data.runnerDelete;
+
+ if (errors?.length) {
+ this.onError(new Error(errors.join(' ')));
+ return;
+ }
+
+ this.$emit('deleted', {
+ message: sprintf(I18N_DELETED_TOAST, { name: this.runnerName }),
+ });
+
+ // Remove deleted runner from the cache
+ const cacheId = cache.identify(this.runner);
+ cache.evict({ id: cacheId });
+ cache.gc();
+ },
+ });
+ } catch (e) {
+ this.onError(e);
+ }
+ },
+ onError(error) {
+ this.deleting = false;
+ const { message } = error;
+ const title = sprintf(s__('Runner|Runner %{runnerName} failed to delete'), {
+ runnerName: this.runnerName,
+ });
+
+ createAlert({ title, message });
+ captureException({ error, component: this.$options.name });
+ },
+ },
+};
+</script>
+
+<template>
+ <div v-gl-tooltip="tooltip" class="btn-group">
+ <gl-button
+ v-gl-modal="runnerDeleteModalId"
+ :aria-label="ariaLabel"
+ :icon="icon"
+ :class="buttonClass"
+ :loading="deleting"
+ variant="danger"
+ category="secondary"
+ v-bind="$attrs"
+ >
+ {{ buttonContent }}
+ </gl-button>
+ <runner-delete-modal
+ :modal-id="runnerDeleteModalId"
+ :runner-name="runnerName"
+ @primary="onDelete"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/runner/components/runner_delete_modal.vue b/app/assets/javascripts/ci/runner/components/runner_delete_modal.vue
index 8be216a7eb5..8be216a7eb5 100644
--- a/app/assets/javascripts/runner/components/runner_delete_modal.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_delete_modal.vue
diff --git a/app/assets/javascripts/runner/components/runner_detail.vue b/app/assets/javascripts/ci/runner/components/runner_detail.vue
index c260670b517..c260670b517 100644
--- a/app/assets/javascripts/runner/components/runner_detail.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_detail.vue
diff --git a/app/assets/javascripts/ci/runner/components/runner_details.vue b/app/assets/javascripts/ci/runner/components/runner_details.vue
new file mode 100644
index 00000000000..6eba8f2e49f
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/runner_details.vue
@@ -0,0 +1,159 @@
+<script>
+import { GlIntersperse, GlLink } from '@gitlab/ui';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { s__ } from '~/locale';
+import HelpPopover from '~/vue_shared/components/help_popover.vue';
+import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
+import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
+import { ACCESS_LEVEL_REF_PROTECTED, GROUP_TYPE, PROJECT_TYPE } from '../constants';
+import RunnerDetail from './runner_detail.vue';
+import RunnerGroups from './runner_groups.vue';
+import RunnerProjects from './runner_projects.vue';
+import RunnerTags from './runner_tags.vue';
+
+export default {
+ components: {
+ GlIntersperse,
+ GlLink,
+ HelpPopover,
+ RunnerDetail,
+ RunnerMaintenanceNoteDetail: () =>
+ import('ee_component/ci/runner/components/runner_maintenance_note_detail.vue'),
+ RunnerGroups,
+ RunnerProjects,
+ RunnerUpgradeStatusBadge: () =>
+ import('ee_component/ci/runner/components/runner_upgrade_status_badge.vue'),
+ RunnerUpgradeStatusAlert: () =>
+ import('ee_component/ci/runner/components/runner_upgrade_status_alert.vue'),
+ RunnerTags,
+ TimeAgo,
+ },
+ props: {
+ runner: {
+ type: Object,
+ required: false,
+ default: null,
+ },
+ },
+ computed: {
+ maximumTimeout() {
+ const { maximumTimeout } = this.runner;
+ if (typeof maximumTimeout !== 'number') {
+ return null;
+ }
+ return timeIntervalInWords(maximumTimeout);
+ },
+ configTextProtected() {
+ if (this.runner.accessLevel === ACCESS_LEVEL_REF_PROTECTED) {
+ return s__('Runners|Protected');
+ }
+ return null;
+ },
+ configTextUntagged() {
+ if (this.runner.runUntagged) {
+ return s__('Runners|Runs untagged jobs');
+ }
+ return null;
+ },
+ tagList() {
+ return this.runner.tagList || [];
+ },
+ isGroupRunner() {
+ return this.runner?.runnerType === GROUP_TYPE;
+ },
+ isProjectRunner() {
+ return this.runner?.runnerType === PROJECT_TYPE;
+ },
+ tokenExpirationHelpPopoverOptions() {
+ return {
+ title: s__('Runners|Runner authentication token expiration'),
+ };
+ },
+ tokenExpirationHelpUrl() {
+ return helpPagePath('ci/runners/configure_runners', {
+ anchor: 'authentication-token-security',
+ });
+ },
+ },
+ ACCESS_LEVEL_REF_PROTECTED,
+};
+</script>
+
+<template>
+ <div>
+ <runner-upgrade-status-alert class="gl-my-4" :runner="runner" />
+ <div class="gl-pt-4">
+ <dl
+ class="gl-mb-0 gl-display-grid runner-details-grid-template"
+ data-testid="runner-details-list"
+ >
+ <runner-detail :label="s__('Runners|Description')" :value="runner.description" />
+ <runner-detail
+ :label="s__('Runners|Last contact')"
+ :empty-value="s__('Runners|Never contacted')"
+ >
+ <template v-if="runner.contactedAt" #value>
+ <time-ago :time="runner.contactedAt" />
+ </template>
+ </runner-detail>
+ <runner-detail :label="s__('Runners|Version')">
+ <template v-if="runner.version" #value>
+ {{ runner.version }}
+ <runner-upgrade-status-badge size="sm" :runner="runner" />
+ </template>
+ </runner-detail>
+ <runner-detail :label="s__('Runners|IP Address')" :value="runner.ipAddress" />
+ <runner-detail :label="s__('Runners|Executor')" :value="runner.executorName" />
+ <runner-detail :label="s__('Runners|Architecture')" :value="runner.architectureName" />
+ <runner-detail :label="s__('Runners|Platform')" :value="runner.platformName" />
+ <runner-detail :label="s__('Runners|Configuration')">
+ <template v-if="configTextProtected || configTextUntagged" #value>
+ <gl-intersperse>
+ <span v-if="configTextProtected">{{ configTextProtected }}</span>
+ <span v-if="configTextUntagged">{{ configTextUntagged }}</span>
+ </gl-intersperse>
+ </template>
+ </runner-detail>
+ <runner-detail :label="s__('Runners|Maximum job timeout')" :value="maximumTimeout" />
+ <runner-detail :empty-value="s__('Runners|Never expires')">
+ <template #label>
+ {{ s__('Runners|Token expiry') }}
+ <help-popover :options="tokenExpirationHelpPopoverOptions">
+ <p>
+ {{
+ s__(
+ 'Runners|Runner authentication tokens will expire based on a set interval. They will automatically rotate once expired.',
+ )
+ }}
+ </p>
+ <p class="gl-mb-0">
+ <gl-link
+ :href="tokenExpirationHelpUrl"
+ target="_blank"
+ class="gl-reset-font-size"
+ >{{ __('Learn more') }}</gl-link
+ >
+ </p>
+ </help-popover>
+ </template>
+ <template v-if="runner.tokenExpiresAt" #value>
+ <time-ago :time="runner.tokenExpiresAt" />
+ </template>
+ </runner-detail>
+ <runner-detail :label="s__('Runners|Tags')">
+ <template v-if="tagList.length" #value>
+ <runner-tags class="gl-vertical-align-middle" :tag-list="tagList" size="sm" />
+ </template>
+ </runner-detail>
+
+ <runner-maintenance-note-detail
+ class="gl-pt-4 gl-border-t-gray-100 gl-border-t-1 gl-border-t-solid"
+ :value="runner.maintenanceNoteHtml"
+ />
+ </dl>
+ </div>
+
+ <runner-groups v-if="isGroupRunner" :runner="runner" />
+ <runner-projects v-if="isProjectRunner" :runner="runner" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/runner/components/runner_edit_button.vue b/app/assets/javascripts/ci/runner/components/runner_edit_button.vue
index 33e0acaf5c0..33e0acaf5c0 100644
--- a/app/assets/javascripts/runner/components/runner_edit_button.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_edit_button.vue
diff --git a/app/assets/javascripts/ci/runner/components/runner_filtered_search_bar.vue b/app/assets/javascripts/ci/runner/components/runner_filtered_search_bar.vue
new file mode 100644
index 00000000000..ee56fea8282
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/runner_filtered_search_bar.vue
@@ -0,0 +1,100 @@
+<script>
+import { cloneDeep } from 'lodash';
+import { __ } from '~/locale';
+import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
+import { searchValidator } from '~/ci/runner/runner_search_utils';
+import { CREATED_DESC, CREATED_ASC, CONTACTED_DESC, CONTACTED_ASC } from '../constants';
+
+const sortOptions = [
+ {
+ id: 1,
+ title: __('Created date'),
+ sortDirection: {
+ descending: CREATED_DESC,
+ ascending: CREATED_ASC,
+ },
+ },
+ {
+ id: 2,
+ title: __('Last contact'),
+ sortDirection: {
+ descending: CONTACTED_DESC,
+ ascending: CONTACTED_ASC,
+ },
+ },
+];
+
+export default {
+ components: {
+ FilteredSearch,
+ },
+ props: {
+ value: {
+ type: Object,
+ required: true,
+ validator: searchValidator,
+ },
+ tokens: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ namespace: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ // filtered_search_bar_root.vue may mutate the initial
+ // filters. Use `cloneDeep` to prevent those mutations
+ // from affecting this component
+ const { filters, sort } = cloneDeep(this.value);
+ return {
+ initialFilterValue: filters,
+ initialSortBy: sort,
+ };
+ },
+ computed: {
+ validTokens() {
+ // Some filters are only available in EE
+ // EE-only tokens are represented by `null` or `undefined`
+ // values when in CE
+ return this.tokens.filter(Boolean);
+ },
+ },
+ methods: {
+ onFilter(filters) {
+ // Apply new filters, resetting pagination
+ this.$emit('input', {
+ ...this.value,
+ filters,
+ pagination: {},
+ });
+ },
+ onSort(sort) {
+ // Apply new sort, resetting pagination
+ this.$emit('input', {
+ ...this.value,
+ sort,
+ pagination: {},
+ });
+ },
+ },
+ sortOptions,
+};
+</script>
+<template>
+ <filtered-search
+ v-bind="$attrs"
+ :namespace="namespace"
+ recent-searches-storage-key="runners-search"
+ :sort-options="$options.sortOptions"
+ :initial-filter-value="initialFilterValue"
+ :tokens="validTokens"
+ :initial-sort-by="initialSortBy"
+ :search-input-placeholder="__('Search or filter results...')"
+ data-testid="runners-filtered-search"
+ @onFilter="onFilter"
+ @onSort="onSort"
+ />
+</template>
diff --git a/app/assets/javascripts/runner/components/runner_groups.vue b/app/assets/javascripts/ci/runner/components/runner_groups.vue
index c3b35bd52a9..c3b35bd52a9 100644
--- a/app/assets/javascripts/runner/components/runner_groups.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_groups.vue
diff --git a/app/assets/javascripts/runner/components/runner_header.vue b/app/assets/javascripts/ci/runner/components/runner_header.vue
index 874c234ca4c..874c234ca4c 100644
--- a/app/assets/javascripts/runner/components/runner_header.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_header.vue
diff --git a/app/assets/javascripts/runner/components/runner_jobs.vue b/app/assets/javascripts/ci/runner/components/runner_jobs.vue
index 9003eba3636..9003eba3636 100644
--- a/app/assets/javascripts/runner/components/runner_jobs.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_jobs.vue
diff --git a/app/assets/javascripts/ci/runner/components/runner_jobs_table.vue b/app/assets/javascripts/ci/runner/components/runner_jobs_table.vue
new file mode 100644
index 00000000000..efa7909c913
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/runner_jobs_table.vue
@@ -0,0 +1,114 @@
+<script>
+import { GlTableLite } from '@gitlab/ui';
+import { __, s__ } from '~/locale';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { durationTimeFormatted } from '~/lib/utils/datetime_utility';
+import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
+import RunnerTags from '~/ci/runner/components/runner_tags.vue';
+import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
+import { tableField } from '../utils';
+import LinkCell from './cells/link_cell.vue';
+
+export default {
+ components: {
+ CiBadge,
+ GlTableLite,
+ LinkCell,
+ RunnerTags,
+ TimeAgo,
+ },
+ props: {
+ jobs: {
+ type: Array,
+ required: true,
+ },
+ },
+ methods: {
+ trAttr(job) {
+ if (job?.id) {
+ return { 'data-testid': `job-row-${getIdFromGraphQLId(job.id)}` };
+ }
+ return {};
+ },
+ jobId(job) {
+ return getIdFromGraphQLId(job.id);
+ },
+ jobPath(job) {
+ return job.detailedStatus?.detailsPath;
+ },
+ projectName(job) {
+ return job.pipeline?.project?.name;
+ },
+ projectWebUrl(job) {
+ return job.pipeline?.project?.webUrl;
+ },
+ commitShortSha(job) {
+ return job.shortSha;
+ },
+ commitPath(job) {
+ return job.commitPath;
+ },
+ duration(job) {
+ const { duration } = job;
+ return duration ? durationTimeFormatted(duration) : '';
+ },
+ queued(job) {
+ const { queuedDuration } = job;
+ return queuedDuration ? durationTimeFormatted(queuedDuration) : '';
+ },
+ },
+ fields: [
+ tableField({ key: 'status', label: s__('Job|Status') }),
+ tableField({ key: 'job', label: __('Job') }),
+ tableField({ key: 'project', label: __('Project') }),
+ tableField({ key: 'commit', label: __('Commit') }),
+ tableField({ key: 'finished_at', label: s__('Job|Finished at') }),
+ tableField({ key: 'duration', label: s__('Job|Duration') }),
+ tableField({ key: 'queued', label: s__('Job|Queued') }),
+ tableField({ key: 'tags', label: s__('Runners|Tags') }),
+ ],
+};
+</script>
+
+<template>
+ <gl-table-lite
+ :items="jobs"
+ :fields="$options.fields"
+ :tbody-tr-attr="trAttr"
+ primary-key="id"
+ stacked="md"
+ fixed
+ >
+ <template #cell(status)="{ item = {} }">
+ <ci-badge v-if="item.detailedStatus" :status="item.detailedStatus" />
+ </template>
+
+ <template #cell(job)="{ item = {} }">
+ <link-cell :href="jobPath(item)"> #{{ jobId(item) }} </link-cell>
+ </template>
+
+ <template #cell(project)="{ item = {} }">
+ <link-cell :href="projectWebUrl(item)">{{ projectName(item) }}</link-cell>
+ </template>
+
+ <template #cell(commit)="{ item = {} }">
+ <link-cell :href="commitPath(item)"> {{ commitShortSha(item) }}</link-cell>
+ </template>
+
+ <template #cell(finished_at)="{ item = {} }">
+ <time-ago v-if="item.finishedAt" :time="item.finishedAt" />
+ </template>
+
+ <template #cell(duration)="{ item = {} }">
+ {{ duration(item) }}
+ </template>
+
+ <template #cell(queued)="{ item = {} }">
+ {{ queued(item) }}
+ </template>
+
+ <template #cell(tags)="{ item = {} }">
+ <runner-tags :tag-list="item.tags" />
+ </template>
+ </gl-table-lite>
+</template>
diff --git a/app/assets/javascripts/runner/components/runner_list.vue b/app/assets/javascripts/ci/runner/components/runner_list.vue
index e895537dcdc..e895537dcdc 100644
--- a/app/assets/javascripts/runner/components/runner_list.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_list.vue
diff --git a/app/assets/javascripts/runner/components/runner_list_empty_state.vue b/app/assets/javascripts/ci/runner/components/runner_list_empty_state.vue
index e6576c83e69..e6576c83e69 100644
--- a/app/assets/javascripts/runner/components/runner_list_empty_state.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_list_empty_state.vue
diff --git a/app/assets/javascripts/runner/components/runner_membership_toggle.vue b/app/assets/javascripts/ci/runner/components/runner_membership_toggle.vue
index 2b37b1cc797..2b37b1cc797 100644
--- a/app/assets/javascripts/runner/components/runner_membership_toggle.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_membership_toggle.vue
diff --git a/app/assets/javascripts/runner/components/runner_name.vue b/app/assets/javascripts/ci/runner/components/runner_name.vue
index d4ecfd2d776..d4ecfd2d776 100644
--- a/app/assets/javascripts/runner/components/runner_name.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_name.vue
diff --git a/app/assets/javascripts/runner/components/runner_pagination.vue b/app/assets/javascripts/ci/runner/components/runner_pagination.vue
index a5bf3074dd1..a5bf3074dd1 100644
--- a/app/assets/javascripts/runner/components/runner_pagination.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_pagination.vue
diff --git a/app/assets/javascripts/ci/runner/components/runner_pause_button.vue b/app/assets/javascripts/ci/runner/components/runner_pause_button.vue
new file mode 100644
index 00000000000..2c80518e772
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/runner_pause_button.vue
@@ -0,0 +1,120 @@
+<script>
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
+import runnerToggleActiveMutation from '~/ci/runner/graphql/shared/runner_toggle_active.mutation.graphql';
+import { createAlert } from '~/flash';
+import { captureException } from '~/ci/runner/sentry_utils';
+import { I18N_PAUSE, I18N_PAUSE_TOOLTIP, I18N_RESUME, I18N_RESUME_TOOLTIP } from '../constants';
+
+export default {
+ name: 'RunnerPauseButton',
+ components: {
+ GlButton,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ runner: {
+ type: Object,
+ required: true,
+ },
+ compact: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ emits: ['toggledPaused'],
+ data() {
+ return {
+ updating: false,
+ };
+ },
+ computed: {
+ isActive() {
+ return this.runner.active;
+ },
+ icon() {
+ return this.isActive ? 'pause' : 'play';
+ },
+ label() {
+ return this.isActive ? I18N_PAUSE : I18N_RESUME;
+ },
+ buttonContent() {
+ if (this.compact) {
+ return null;
+ }
+ return this.label;
+ },
+ ariaLabel() {
+ if (this.compact) {
+ return this.label;
+ }
+ return null;
+ },
+ tooltip() {
+ // Prevent a "sticky" tooltip: If this button is disabled,
+ // mouseout listeners don't run leaving the tooltip stuck
+ if (!this.updating) {
+ return this.isActive ? I18N_PAUSE_TOOLTIP : I18N_RESUME_TOOLTIP;
+ }
+ return '';
+ },
+ },
+ methods: {
+ async onToggle() {
+ this.updating = true;
+ try {
+ const input = {
+ id: this.runner.id,
+ active: !this.isActive,
+ };
+
+ const {
+ data: {
+ runnerUpdate: { errors },
+ },
+ } = await this.$apollo.mutate({
+ mutation: runnerToggleActiveMutation,
+ variables: {
+ input,
+ },
+ });
+
+ if (errors && errors.length) {
+ throw new Error(errors.join(' '));
+ }
+ this.$emit('toggledPaused');
+ } catch (e) {
+ this.onError(e);
+ } finally {
+ this.updating = false;
+ }
+ },
+ onError(error) {
+ const { message } = error;
+
+ createAlert({ message });
+ captureException({ error, component: this.$options.name });
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-button
+ v-gl-tooltip="tooltip"
+ v-bind="$attrs"
+ :aria-label="ariaLabel"
+ :icon="icon"
+ :loading="updating"
+ @click="onToggle"
+ v-on="$listeners"
+ >
+ <!--
+ Use <template v-if> to ensure a square button is shown when compact: true.
+ Sending empty content will still show a distorted/rectangular button.
+ -->
+ <template v-if="buttonContent">{{ buttonContent }}</template>
+ </gl-button>
+</template>
diff --git a/app/assets/javascripts/runner/components/runner_paused_badge.vue b/app/assets/javascripts/ci/runner/components/runner_paused_badge.vue
index 00fd84a48d8..00fd84a48d8 100644
--- a/app/assets/javascripts/runner/components/runner_paused_badge.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_paused_badge.vue
diff --git a/app/assets/javascripts/runner/components/runner_projects.vue b/app/assets/javascripts/ci/runner/components/runner_projects.vue
index 84008e8eee8..84008e8eee8 100644
--- a/app/assets/javascripts/runner/components/runner_projects.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_projects.vue
diff --git a/app/assets/javascripts/runner/components/runner_status_badge.vue b/app/assets/javascripts/ci/runner/components/runner_status_badge.vue
index d084408781e..d084408781e 100644
--- a/app/assets/javascripts/runner/components/runner_status_badge.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_status_badge.vue
diff --git a/app/assets/javascripts/ci/runner/components/runner_status_popover.vue b/app/assets/javascripts/ci/runner/components/runner_status_popover.vue
new file mode 100644
index 00000000000..06174d39a59
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/runner_status_popover.vue
@@ -0,0 +1,75 @@
+<script>
+import { GlSprintf } from '@gitlab/ui';
+import { duration } from '~/lib/utils/datetime/timeago_utility';
+import HelpPopover from '~/vue_shared/components/help_popover.vue';
+import {
+ I18N_STATUS_POPOVER_TITLE,
+ I18N_STATUS_POPOVER_NEVER_CONTACTED,
+ I18N_STATUS_POPOVER_NEVER_CONTACTED_DESCRIPTION,
+ I18N_STATUS_POPOVER_ONLINE,
+ I18N_STATUS_POPOVER_ONLINE_DESCRIPTION,
+ I18N_STATUS_POPOVER_OFFLINE,
+ I18N_STATUS_POPOVER_OFFLINE_DESCRIPTION,
+ I18N_STATUS_POPOVER_STALE,
+ I18N_STATUS_POPOVER_STALE_DESCRIPTION,
+} from '~/ci/runner/constants';
+
+export default {
+ name: 'RunnerStatusPopover',
+ components: {
+ GlSprintf,
+ HelpPopover,
+ },
+ inject: ['onlineContactTimeoutSecs', 'staleTimeoutSecs'],
+ computed: {
+ onlineContactTimeoutDuration() {
+ return duration(this.onlineContactTimeoutSecs * 1000);
+ },
+ staleTimeoutDuration() {
+ return duration(this.staleTimeoutSecs * 1000);
+ },
+ },
+ I18N_STATUS_POPOVER_TITLE,
+ I18N_STATUS_POPOVER_NEVER_CONTACTED,
+ I18N_STATUS_POPOVER_NEVER_CONTACTED_DESCRIPTION,
+ I18N_STATUS_POPOVER_ONLINE,
+ I18N_STATUS_POPOVER_ONLINE_DESCRIPTION,
+ I18N_STATUS_POPOVER_OFFLINE,
+ I18N_STATUS_POPOVER_OFFLINE_DESCRIPTION,
+ I18N_STATUS_POPOVER_STALE,
+ I18N_STATUS_POPOVER_STALE_DESCRIPTION,
+};
+</script>
+
+<template>
+ <help-popover>
+ <template #title>{{ $options.I18N_STATUS_POPOVER_TITLE }}</template>
+
+ <p class="gl-mb-0">
+ <strong>{{ $options.I18N_STATUS_POPOVER_NEVER_CONTACTED }}</strong>
+ <gl-sprintf :message="$options.I18N_STATUS_POPOVER_NEVER_CONTACTED_DESCRIPTION">
+ <template #code="{ content }">
+ <code>{{ content }}</code>
+ </template>
+ </gl-sprintf>
+ </p>
+ <p class="gl-mb-0">
+ <strong>{{ $options.I18N_STATUS_POPOVER_ONLINE }}</strong>
+ <gl-sprintf :message="$options.I18N_STATUS_POPOVER_ONLINE_DESCRIPTION">
+ <template #elapsedTime>{{ onlineContactTimeoutDuration }}</template>
+ </gl-sprintf>
+ </p>
+ <p class="gl-mb-0">
+ <strong>{{ $options.I18N_STATUS_POPOVER_OFFLINE }}</strong>
+ <gl-sprintf :message="$options.I18N_STATUS_POPOVER_OFFLINE_DESCRIPTION">
+ <template #elapsedTime>{{ onlineContactTimeoutDuration }}</template>
+ </gl-sprintf>
+ </p>
+ <p class="gl-mb-0">
+ <strong>{{ $options.I18N_STATUS_POPOVER_STALE }}</strong>
+ <gl-sprintf :message="$options.I18N_STATUS_POPOVER_STALE_DESCRIPTION">
+ <template #elapsedTime>{{ staleTimeoutDuration }}</template>
+ </gl-sprintf>
+ </p>
+ </help-popover>
+</template>
diff --git a/app/assets/javascripts/runner/components/runner_tag.vue b/app/assets/javascripts/ci/runner/components/runner_tag.vue
index 6ad2023a866..6ad2023a866 100644
--- a/app/assets/javascripts/runner/components/runner_tag.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_tag.vue
diff --git a/app/assets/javascripts/runner/components/runner_tags.vue b/app/assets/javascripts/ci/runner/components/runner_tags.vue
index 38e566f9f53..38e566f9f53 100644
--- a/app/assets/javascripts/runner/components/runner_tags.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_tags.vue
diff --git a/app/assets/javascripts/runner/components/runner_type_badge.vue b/app/assets/javascripts/ci/runner/components/runner_type_badge.vue
index f568f914004..f568f914004 100644
--- a/app/assets/javascripts/runner/components/runner_type_badge.vue
+++ b/app/assets/javascripts/ci/runner/components/runner_type_badge.vue
diff --git a/app/assets/javascripts/ci/runner/components/runner_type_tabs.vue b/app/assets/javascripts/ci/runner/components/runner_type_tabs.vue
new file mode 100644
index 00000000000..584236168ac
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/runner_type_tabs.vue
@@ -0,0 +1,123 @@
+<script>
+import { GlBadge, GlTabs, GlTab } from '@gitlab/ui';
+import { searchValidator } from '~/ci/runner/runner_search_utils';
+import { formatNumber } from '~/locale';
+import {
+ INSTANCE_TYPE,
+ GROUP_TYPE,
+ PROJECT_TYPE,
+ I18N_ALL_TYPES,
+ I18N_INSTANCE_TYPE,
+ I18N_GROUP_TYPE,
+ I18N_PROJECT_TYPE,
+} from '../constants';
+import RunnerCount from './stat/runner_count.vue';
+
+const I18N_TAB_TITLES = {
+ [INSTANCE_TYPE]: I18N_INSTANCE_TYPE,
+ [GROUP_TYPE]: I18N_GROUP_TYPE,
+ [PROJECT_TYPE]: I18N_PROJECT_TYPE,
+};
+
+const TAB_COUNT_REF = 'tab-count';
+
+export default {
+ components: {
+ GlBadge,
+ GlTabs,
+ GlTab,
+ RunnerCount,
+ },
+ props: {
+ runnerTypes: {
+ type: Array,
+ required: false,
+ default: () => [INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE],
+ },
+ value: {
+ type: Object,
+ required: true,
+ validator: searchValidator,
+ },
+ countScope: {
+ type: String,
+ required: true,
+ },
+ countVariables: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ tabs() {
+ const tabs = this.runnerTypes.map((runnerType) => ({
+ title: I18N_TAB_TITLES[runnerType],
+ runnerType,
+ }));
+
+ // Always add a "All" tab that resets filters
+ return [
+ {
+ title: I18N_ALL_TYPES,
+ runnerType: null,
+ },
+ ...tabs,
+ ];
+ },
+ },
+ methods: {
+ onTabSelected({ runnerType }) {
+ this.$emit('input', {
+ ...this.value,
+ runnerType,
+ pagination: { page: 1 },
+ });
+ },
+ isTabActive({ runnerType }) {
+ return runnerType === this.value.runnerType;
+ },
+ tabBadgeCountVariables(runnerType) {
+ return { ...this.countVariables, type: runnerType };
+ },
+ tabCount(count) {
+ if (typeof count === 'number') {
+ return formatNumber(count);
+ }
+ return '';
+ },
+
+ // Component API
+ refetch() {
+ // Refresh all of the counts here, can be called by parent component
+ this.$refs[TAB_COUNT_REF].forEach((countComponent) => {
+ countComponent.refetch();
+ });
+ },
+ },
+ TAB_COUNT_REF,
+};
+</script>
+<template>
+ <gl-tabs v-bind="$attrs" data-testid="runner-type-tabs">
+ <gl-tab
+ v-for="tab in tabs"
+ :key="`${tab.runnerType}`"
+ :active="isTabActive(tab)"
+ @click="onTabSelected(tab)"
+ >
+ <template #title>
+ {{ tab.title }}
+ <runner-count
+ #default="{ count }"
+ :ref="$options.TAB_COUNT_REF"
+ :scope="countScope"
+ :variables="tabBadgeCountVariables(tab.runnerType)"
+ >
+ <gl-badge v-if="tabCount(count)" class="gl-ml-1" size="sm">
+ {{ tabCount(count) }}
+ </gl-badge>
+ </runner-count>
+ </template>
+ </gl-tab>
+ </gl-tabs>
+</template>
diff --git a/app/assets/javascripts/ci/runner/components/runner_update_form.vue b/app/assets/javascripts/ci/runner/components/runner_update_form.vue
new file mode 100644
index 00000000000..a9790d06ca7
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/runner_update_form.vue
@@ -0,0 +1,225 @@
+<script>
+import {
+ GlButton,
+ GlIcon,
+ GlForm,
+ GlFormCheckbox,
+ GlFormGroup,
+ GlFormInputGroup,
+ GlSkeletonLoader,
+ GlTooltipDirective,
+} from '@gitlab/ui';
+import {
+ modelToUpdateMutationVariables,
+ runnerToModel,
+} from 'ee_else_ce/ci/runner/runner_update_form_utils';
+import { createAlert, VARIANT_SUCCESS } from '~/flash';
+import { redirectTo } from '~/lib/utils/url_utility';
+import { __ } from '~/locale';
+import { captureException } from '~/ci/runner/sentry_utils';
+import { ACCESS_LEVEL_NOT_PROTECTED, ACCESS_LEVEL_REF_PROTECTED, PROJECT_TYPE } from '../constants';
+import runnerUpdateMutation from '../graphql/edit/runner_update.mutation.graphql';
+import { saveAlertToLocalStorage } from '../local_storage_alert/save_alert_to_local_storage';
+
+export default {
+ name: 'RunnerUpdateForm',
+ components: {
+ GlButton,
+ GlIcon,
+ GlForm,
+ GlFormCheckbox,
+ GlFormGroup,
+ GlFormInputGroup,
+ GlSkeletonLoader,
+ RunnerMaintenanceNoteField: () =>
+ import('ee_component/ci/runner/components/runner_maintenance_note_field.vue'),
+ RunnerUpdateCostFactorFields: () =>
+ import('ee_component/ci/runner/components/runner_update_cost_factor_fields.vue'),
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ runner: {
+ type: Object,
+ required: false,
+ default: null,
+ },
+ loading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ runnerPath: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+ data() {
+ return {
+ saving: false,
+ model: runnerToModel(this.runner),
+ };
+ },
+ computed: {
+ canBeLockedToProject() {
+ return this.runner?.runnerType === PROJECT_TYPE;
+ },
+ },
+ watch: {
+ runner(newVal, oldVal) {
+ if (oldVal === null) {
+ this.model = runnerToModel(newVal);
+ }
+ },
+ },
+ methods: {
+ async onSubmit() {
+ this.saving = true;
+
+ try {
+ const {
+ data: {
+ runnerUpdate: { errors },
+ },
+ } = await this.$apollo.mutate({
+ mutation: runnerUpdateMutation,
+ variables: modelToUpdateMutationVariables(this.model),
+ });
+
+ if (errors?.length) {
+ this.onError(errors[0]);
+ } else {
+ this.onSuccess();
+ }
+ } catch (error) {
+ const { message } = error;
+ this.onError(message);
+ captureException({ error, component: this.$options.name });
+ }
+ },
+ onSuccess() {
+ saveAlertToLocalStorage({ message: __('Changes saved.'), variant: VARIANT_SUCCESS });
+ redirectTo(this.runnerPath);
+ },
+ onError(message) {
+ this.saving = false;
+ createAlert({ message });
+ },
+ },
+ ACCESS_LEVEL_NOT_PROTECTED,
+ ACCESS_LEVEL_REF_PROTECTED,
+};
+</script>
+<template>
+ <gl-form @submit.prevent="onSubmit">
+ <h4 class="gl-font-lg gl-my-5">{{ s__('Runners|Details') }}</h4>
+
+ <gl-skeleton-loader v-if="loading" />
+
+ <template v-else>
+ <gl-form-group :label="__('Description')" data-testid="runner-field-description">
+ <gl-form-input-group v-model="model.description" />
+ </gl-form-group>
+ <runner-maintenance-note-field v-model="model.maintenanceNote" />
+ </template>
+
+ <hr />
+
+ <h4 class="gl-font-lg gl-my-5">{{ s__('Runners|Configuration') }}</h4>
+
+ <template v-if="loading">
+ <gl-skeleton-loader v-for="i in 3" :key="i" />
+ </template>
+ <template v-else>
+ <div class="gl-mb-5">
+ <gl-form-checkbox
+ v-model="model.active"
+ data-testid="runner-field-paused"
+ :value="false"
+ :unchecked-value="true"
+ >
+ {{ __('Paused') }}
+ <template #help>
+ {{ s__('Runners|Stop the runner from accepting new jobs.') }}
+ </template>
+ </gl-form-checkbox>
+
+ <gl-form-checkbox
+ v-model="model.accessLevel"
+ data-testid="runner-field-protected"
+ :value="$options.ACCESS_LEVEL_REF_PROTECTED"
+ :unchecked-value="$options.ACCESS_LEVEL_NOT_PROTECTED"
+ >
+ {{ __('Protected') }}
+ <template #help>
+ {{ s__('Runners|Use the runner on pipelines for protected branches only.') }}
+ </template>
+ </gl-form-checkbox>
+
+ <gl-form-checkbox v-model="model.runUntagged" data-testid="runner-field-run-untagged">
+ {{ __('Run untagged jobs') }}
+ <template #help>
+ {{ s__('Runners|Use the runner for jobs without tags, in addition to tagged jobs.') }}
+ </template>
+ </gl-form-checkbox>
+
+ <gl-form-checkbox
+ v-if="canBeLockedToProject"
+ v-model="model.locked"
+ data-testid="runner-field-locked"
+ >
+ {{ __('Lock to current projects') }} <gl-icon name="lock" />
+ <template #help>
+ {{
+ s__(
+ 'Runners|Use the runner for the currently assigned projects only. Only administrators can change the assigned projects.',
+ )
+ }}
+ </template>
+ </gl-form-checkbox>
+ </div>
+
+ <gl-form-group
+ data-testid="runner-field-max-timeout"
+ :label="__('Maximum job timeout')"
+ :description="
+ s__(
+ 'Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project.',
+ )
+ "
+ >
+ <gl-form-input-group v-model.number="model.maximumTimeout" type="number" />
+ </gl-form-group>
+
+ <gl-form-group
+ data-testid="runner-field-tags"
+ :label="__('Tags')"
+ :description="
+ __(
+ 'You can set up jobs to only use runners with specific tags. Separate tags with commas.',
+ )
+ "
+ >
+ <gl-form-input-group v-model="model.tagList" />
+ </gl-form-group>
+
+ <runner-update-cost-factor-fields v-model="model" />
+ </template>
+
+ <div class="gl-mt-6">
+ <gl-button
+ type="submit"
+ variant="confirm"
+ class="js-no-auto-disable"
+ :loading="loading || saving"
+ >
+ {{ __('Save changes') }}
+ </gl-button>
+ <gl-button :href="runnerPath">
+ {{ __('Cancel') }}
+ </gl-button>
+ </div>
+ </gl-form>
+</template>
diff --git a/app/assets/javascripts/runner/components/search_tokens/paused_token_config.js b/app/assets/javascripts/ci/runner/components/search_tokens/paused_token_config.js
index 97ee8ec3eef..97ee8ec3eef 100644
--- a/app/assets/javascripts/runner/components/search_tokens/paused_token_config.js
+++ b/app/assets/javascripts/ci/runner/components/search_tokens/paused_token_config.js
diff --git a/app/assets/javascripts/ci/runner/components/search_tokens/status_token_config.js b/app/assets/javascripts/ci/runner/components/search_tokens/status_token_config.js
new file mode 100644
index 00000000000..117a630719e
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/search_tokens/status_token_config.js
@@ -0,0 +1,42 @@
+import {
+ OPERATOR_IS_ONLY,
+ TOKEN_TITLE_STATUS,
+} from '~/vue_shared/components/filtered_search_bar/constants';
+import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
+import {
+ I18N_STATUS_ONLINE,
+ I18N_STATUS_NEVER_CONTACTED,
+ I18N_STATUS_OFFLINE,
+ I18N_STATUS_STALE,
+ STATUS_ONLINE,
+ STATUS_OFFLINE,
+ STATUS_NEVER_CONTACTED,
+ STATUS_STALE,
+ PARAM_KEY_STATUS,
+} from '../../constants';
+
+const options = [
+ { value: STATUS_ONLINE, title: I18N_STATUS_ONLINE },
+ { value: STATUS_OFFLINE, title: I18N_STATUS_OFFLINE },
+ { value: STATUS_NEVER_CONTACTED, title: I18N_STATUS_NEVER_CONTACTED },
+ { value: STATUS_STALE, title: I18N_STATUS_STALE },
+];
+
+export const statusTokenConfig = {
+ icon: 'status',
+ title: TOKEN_TITLE_STATUS,
+ type: PARAM_KEY_STATUS,
+ token: BaseToken,
+ unique: true,
+ options: options.map(({ value, title }) => ({
+ value,
+ // Replace whitespace with a special character to avoid
+ // splitting this value.
+ // Replacing in each option, as translations may also
+ // contain spaces!
+ // see: https://gitlab.com/gitlab-org/gitlab/-/issues/344142
+ // see: https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1438
+ title: title.replace(/\s/g, '\u00a0'),
+ })),
+ operators: OPERATOR_IS_ONLY,
+};
diff --git a/app/assets/javascripts/runner/components/search_tokens/tag_token.vue b/app/assets/javascripts/ci/runner/components/search_tokens/tag_token.vue
index 6e7c41885f8..6e7c41885f8 100644
--- a/app/assets/javascripts/runner/components/search_tokens/tag_token.vue
+++ b/app/assets/javascripts/ci/runner/components/search_tokens/tag_token.vue
diff --git a/app/assets/javascripts/runner/components/search_tokens/tag_token_config.js b/app/assets/javascripts/ci/runner/components/search_tokens/tag_token_config.js
index fdeba714385..fdeba714385 100644
--- a/app/assets/javascripts/runner/components/search_tokens/tag_token_config.js
+++ b/app/assets/javascripts/ci/runner/components/search_tokens/tag_token_config.js
diff --git a/app/assets/javascripts/runner/components/search_tokens/upgrade_status_token_config.js b/app/assets/javascripts/ci/runner/components/search_tokens/upgrade_status_token_config.js
index 17ee7073360..17ee7073360 100644
--- a/app/assets/javascripts/runner/components/search_tokens/upgrade_status_token_config.js
+++ b/app/assets/javascripts/ci/runner/components/search_tokens/upgrade_status_token_config.js
diff --git a/app/assets/javascripts/ci/runner/components/stat/runner_count.vue b/app/assets/javascripts/ci/runner/components/stat/runner_count.vue
new file mode 100644
index 00000000000..4ad9259f59d
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/stat/runner_count.vue
@@ -0,0 +1,104 @@
+<script>
+import { fetchPolicies } from '~/lib/graphql';
+import allRunnersCountQuery from 'ee_else_ce/ci/runner/graphql/list/all_runners_count.query.graphql';
+import groupRunnersCountQuery from 'ee_else_ce/ci/runner/graphql/list/group_runners_count.query.graphql';
+
+import { captureException } from '../../sentry_utils';
+import { INSTANCE_TYPE, GROUP_TYPE } from '../../constants';
+
+/**
+ * Renderless component that wraps a "count" query for the
+ * number of runners that follow a filter criteria.
+ *
+ * Example usage:
+ *
+ * Render the count of "online" runners in the instance in a
+ * <strong/> tag.
+ *
+ * ```vue
+ * <runner-count-stat
+ * #default="{ count }"
+ * :scope="INSTANCE_TYPE"
+ * :variables="{ status: 'ONLINE' }"
+ * >
+ * <strong>{{ count }}</strong>
+ * </runner-count-stat>
+ * ```
+ *
+ * Use `:skip="true"` to prevent data from being fetched and
+ * even rendered.
+ */
+export default {
+ name: 'RunnerCount',
+ props: {
+ scope: {
+ type: String,
+ required: true,
+ validator: (val) => [INSTANCE_TYPE, GROUP_TYPE].includes(val),
+ },
+ variables: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ skip: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ data() {
+ return { count: null };
+ },
+ apollo: {
+ count: {
+ query() {
+ if (this.scope === INSTANCE_TYPE) {
+ return allRunnersCountQuery;
+ } else if (this.scope === GROUP_TYPE) {
+ return groupRunnersCountQuery;
+ }
+ return null;
+ },
+ fetchPolicy: fetchPolicies.NETWORK_ONLY,
+ variables() {
+ return this.variables;
+ },
+ skip() {
+ if (this.skip) {
+ // Don't show data for skipped stats
+ this.count = null;
+ }
+ return this.skip;
+ },
+ update(data) {
+ if (this.scope === INSTANCE_TYPE) {
+ return data?.runners?.count;
+ } else if (this.scope === GROUP_TYPE) {
+ return data?.group?.runners?.count;
+ }
+ return null;
+ },
+ error(error) {
+ this.reportToSentry(error);
+ },
+ },
+ },
+ methods: {
+ reportToSentry(error) {
+ captureException({ error, component: this.$options.name });
+ },
+
+ // Component API
+ refetch() {
+ // Parent components can use this method to refresh the count
+ this.$apollo.queries.count.refetch();
+ },
+ },
+ render() {
+ return this.$scopedSlots.default({
+ count: this.count,
+ });
+ },
+};
+</script>
diff --git a/app/assets/javascripts/runner/components/stat/runner_single_stat.vue b/app/assets/javascripts/ci/runner/components/stat/runner_single_stat.vue
index ae732b052ac..ae732b052ac 100644
--- a/app/assets/javascripts/runner/components/stat/runner_single_stat.vue
+++ b/app/assets/javascripts/ci/runner/components/stat/runner_single_stat.vue
diff --git a/app/assets/javascripts/ci/runner/components/stat/runner_stats.vue b/app/assets/javascripts/ci/runner/components/stat/runner_stats.vue
new file mode 100644
index 00000000000..3965e5551f1
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/components/stat/runner_stats.vue
@@ -0,0 +1,89 @@
+<script>
+import RunnerSingleStat from '~/ci/runner/components/stat/runner_single_stat.vue';
+import {
+ I18N_STATUS_ONLINE,
+ I18N_STATUS_OFFLINE,
+ I18N_STATUS_STALE,
+ STATUS_ONLINE,
+ STATUS_OFFLINE,
+ STATUS_STALE,
+} from '../../constants';
+
+export default {
+ components: {
+ RunnerSingleStat,
+ RunnerUpgradeStatusStats: () =>
+ import('ee_component/ci/runner/components/stat/runner_upgrade_status_stats.vue'),
+ },
+ props: {
+ scope: {
+ type: String,
+ required: true,
+ },
+ variables: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ },
+ computed: {
+ stats() {
+ return [
+ {
+ key: STATUS_ONLINE,
+ props: {
+ skip: this.statusCountSkip(STATUS_ONLINE),
+ variables: { ...this.variables, status: STATUS_ONLINE },
+ variant: 'success',
+ title: I18N_STATUS_ONLINE,
+ metaIcon: 'status-active',
+ },
+ },
+ {
+ key: STATUS_OFFLINE,
+ props: {
+ skip: this.statusCountSkip(STATUS_OFFLINE),
+ variables: { ...this.variables, status: STATUS_OFFLINE },
+ variant: 'muted',
+ title: I18N_STATUS_OFFLINE,
+ metaIcon: 'status-waiting',
+ },
+ },
+ {
+ key: STATUS_STALE,
+ props: {
+ skip: this.statusCountSkip(STATUS_STALE),
+ variables: { ...this.variables, status: STATUS_STALE },
+ variant: 'warning',
+ title: I18N_STATUS_STALE,
+ metaIcon: 'time-out',
+ },
+ },
+ ];
+ },
+ },
+ methods: {
+ statusCountSkip(status) {
+ // Show an empty result when we already filter by another status
+ return this.variables.status && this.variables.status !== status;
+ },
+ },
+};
+</script>
+<template>
+ <div class="gl-display-flex gl-flex-wrap gl-py-6">
+ <runner-single-stat
+ v-for="stat in stats"
+ :key="stat.key"
+ :scope="scope"
+ v-bind="stat.props"
+ class="gl-px-5"
+ />
+
+ <runner-upgrade-status-stats
+ class="gl-display-contents"
+ :scope="scope"
+ :variables="variables"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/runner/constants.js b/app/assets/javascripts/ci/runner/constants.js
index dfc5f0c4152..dfc5f0c4152 100644
--- a/app/assets/javascripts/runner/constants.js
+++ b/app/assets/javascripts/ci/runner/constants.js
diff --git a/app/assets/javascripts/runner/graphql/edit/runner_fields.fragment.graphql b/app/assets/javascripts/ci/runner/graphql/edit/runner_fields.fragment.graphql
index b732d587d70..b732d587d70 100644
--- a/app/assets/javascripts/runner/graphql/edit/runner_fields.fragment.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/edit/runner_fields.fragment.graphql
diff --git a/app/assets/javascripts/runner/graphql/edit/runner_fields_shared.fragment.graphql b/app/assets/javascripts/ci/runner/graphql/edit/runner_fields_shared.fragment.graphql
index 29abddf84f5..29abddf84f5 100644
--- a/app/assets/javascripts/runner/graphql/edit/runner_fields_shared.fragment.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/edit/runner_fields_shared.fragment.graphql
diff --git a/app/assets/javascripts/ci/runner/graphql/edit/runner_form.query.graphql b/app/assets/javascripts/ci/runner/graphql/edit/runner_form.query.graphql
new file mode 100644
index 00000000000..5599c147c56
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/graphql/edit/runner_form.query.graphql
@@ -0,0 +1,7 @@
+#import "ee_else_ce/ci/runner/graphql/edit/runner_fields.fragment.graphql"
+
+query getRunnerForm($id: CiRunnerID!) {
+ runner(id: $id) {
+ ...RunnerFields
+ }
+}
diff --git a/app/assets/javascripts/ci/runner/graphql/edit/runner_update.mutation.graphql b/app/assets/javascripts/ci/runner/graphql/edit/runner_update.mutation.graphql
new file mode 100644
index 00000000000..9469078c317
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/graphql/edit/runner_update.mutation.graphql
@@ -0,0 +1,13 @@
+#import "ee_else_ce/ci/runner/graphql/edit/runner_fields.fragment.graphql"
+
+# Mutation for updates from the runner form, loads
+# attributes shown in the runner details.
+
+mutation runnerUpdate($input: RunnerUpdateInput!) {
+ runnerUpdate(input: $input) {
+ runner {
+ ...RunnerFields
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/ci/runner/graphql/list/all_runners.query.graphql b/app/assets/javascripts/ci/runner/graphql/list/all_runners.query.graphql
new file mode 100644
index 00000000000..15401c25c64
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/graphql/list/all_runners.query.graphql
@@ -0,0 +1,29 @@
+#import "~/ci/runner/graphql/list/all_runners_connection.fragment.graphql"
+
+query getAllRunners(
+ $before: String
+ $after: String
+ $first: Int
+ $last: Int
+ $paused: Boolean
+ $status: CiRunnerStatus
+ $type: CiRunnerType
+ $tagList: [String!]
+ $search: String
+ $sort: CiRunnerSort
+) {
+ runners(
+ before: $before
+ after: $after
+ first: $first
+ last: $last
+ paused: $paused
+ status: $status
+ type: $type
+ tagList: $tagList
+ search: $search
+ sort: $sort
+ ) {
+ ...AllRunnersConnection
+ }
+}
diff --git a/app/assets/javascripts/ci/runner/graphql/list/all_runners_connection.fragment.graphql b/app/assets/javascripts/ci/runner/graphql/list/all_runners_connection.fragment.graphql
new file mode 100644
index 00000000000..39d79df02e7
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/graphql/list/all_runners_connection.fragment.graphql
@@ -0,0 +1,13 @@
+#import "ee_else_ce/ci/runner/graphql/list/list_item.fragment.graphql"
+#import "~/graphql_shared/fragments/page_info.fragment.graphql"
+
+fragment AllRunnersConnection on CiRunnerConnection {
+ nodes {
+ ...ListItem
+ adminUrl
+ editAdminUrl
+ }
+ pageInfo {
+ ...PageInfo
+ }
+}
diff --git a/app/assets/javascripts/runner/graphql/list/all_runners_count.query.graphql b/app/assets/javascripts/ci/runner/graphql/list/all_runners_count.query.graphql
index 82591b88d3e..82591b88d3e 100644
--- a/app/assets/javascripts/runner/graphql/list/all_runners_count.query.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/list/all_runners_count.query.graphql
diff --git a/app/assets/javascripts/runner/graphql/list/bulk_runner_delete.mutation.graphql b/app/assets/javascripts/ci/runner/graphql/list/bulk_runner_delete.mutation.graphql
index b73c016b1de..b73c016b1de 100644
--- a/app/assets/javascripts/runner/graphql/list/bulk_runner_delete.mutation.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/list/bulk_runner_delete.mutation.graphql
diff --git a/app/assets/javascripts/runner/graphql/list/checked_runner_ids.query.graphql b/app/assets/javascripts/ci/runner/graphql/list/checked_runner_ids.query.graphql
index c01f1edb451..c01f1edb451 100644
--- a/app/assets/javascripts/runner/graphql/list/checked_runner_ids.query.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/list/checked_runner_ids.query.graphql
diff --git a/app/assets/javascripts/ci/runner/graphql/list/group_runner_connection.fragment.graphql b/app/assets/javascripts/ci/runner/graphql/list/group_runner_connection.fragment.graphql
new file mode 100644
index 00000000000..53be8fdc613
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/graphql/list/group_runner_connection.fragment.graphql
@@ -0,0 +1,16 @@
+#import "ee_else_ce/ci/runner/graphql/list/list_item.fragment.graphql"
+#import "~/graphql_shared/fragments/page_info.fragment.graphql"
+
+fragment GroupRunnerConnection on CiRunnerConnection {
+ edges {
+ webUrl
+ editUrl
+ node {
+ ...ListItem
+ projectCount # Used to determine why some project runners can't be deleted
+ }
+ }
+ pageInfo {
+ ...PageInfo
+ }
+}
diff --git a/app/assets/javascripts/ci/runner/graphql/list/group_runners.query.graphql b/app/assets/javascripts/ci/runner/graphql/list/group_runners.query.graphql
new file mode 100644
index 00000000000..08fd8974826
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/graphql/list/group_runners.query.graphql
@@ -0,0 +1,35 @@
+#import "~/ci/runner/graphql/list/group_runner_connection.fragment.graphql"
+
+query getGroupRunners(
+ $groupFullPath: ID!
+ $membership: CiRunnerMembershipFilter
+ $before: String
+ $after: String
+ $first: Int
+ $last: Int
+ $paused: Boolean
+ $status: CiRunnerStatus
+ $type: CiRunnerType
+ $tagList: [String!]
+ $search: String
+ $sort: CiRunnerSort
+) {
+ group(fullPath: $groupFullPath) {
+ id # Apollo required
+ runners(
+ membership: $membership
+ before: $before
+ after: $after
+ first: $first
+ last: $last
+ paused: $paused
+ status: $status
+ type: $type
+ tagList: $tagList
+ search: $search
+ sort: $sort
+ ) {
+ ...GroupRunnerConnection
+ }
+ }
+}
diff --git a/app/assets/javascripts/runner/graphql/list/group_runners_count.query.graphql b/app/assets/javascripts/ci/runner/graphql/list/group_runners_count.query.graphql
index e88a2c2e7e6..e88a2c2e7e6 100644
--- a/app/assets/javascripts/runner/graphql/list/group_runners_count.query.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/list/group_runners_count.query.graphql
diff --git a/app/assets/javascripts/runner/graphql/list/list_item.fragment.graphql b/app/assets/javascripts/ci/runner/graphql/list/list_item.fragment.graphql
index 19a5a48ea75..19a5a48ea75 100644
--- a/app/assets/javascripts/runner/graphql/list/list_item.fragment.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/list/list_item.fragment.graphql
diff --git a/app/assets/javascripts/runner/graphql/list/list_item_shared.fragment.graphql b/app/assets/javascripts/ci/runner/graphql/list/list_item_shared.fragment.graphql
index 0dff011daaa..0dff011daaa 100644
--- a/app/assets/javascripts/runner/graphql/list/list_item_shared.fragment.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/list/list_item_shared.fragment.graphql
diff --git a/app/assets/javascripts/ci/runner/graphql/list/local_state.js b/app/assets/javascripts/ci/runner/graphql/list/local_state.js
new file mode 100644
index 00000000000..ab53bfdbd5b
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/graphql/list/local_state.js
@@ -0,0 +1,75 @@
+import { makeVar } from '@apollo/client/core';
+import { RUNNER_TYPENAME } from '../../constants';
+import typeDefs from './typedefs.graphql';
+
+/**
+ * Local state for checkable runner items.
+ *
+ * Usage:
+ *
+ * ```
+ * import { createLocalState } from '~/ci/runner/graphql/list/local_state';
+ *
+ * // initialize local state
+ * const { cacheConfig, typeDefs, localMutations } = createLocalState();
+ *
+ * // configure the client
+ * apolloClient = createApolloClient({}, { cacheConfig, typeDefs });
+ *
+ * // modify local state
+ * localMutations.setRunnerChecked( ... )
+ * ```
+ *
+ * @returns {Object} An object to configure an Apollo client:
+ * contains cacheConfig, typeDefs, localMutations.
+ */
+export const createLocalState = () => {
+ const checkedRunnerIdsVar = makeVar({});
+
+ const cacheConfig = {
+ typePolicies: {
+ Query: {
+ fields: {
+ checkedRunnerIds(_, { canRead, toReference }) {
+ return Object.entries(checkedRunnerIdsVar())
+ .filter(([id]) => {
+ // Some runners may be deleted by the user separately.
+ // Skip dangling references, those not in the cache.
+ // See: https://www.apollographql.com/docs/react/caching/garbage-collection/#dangling-references
+ return canRead(toReference({ __typename: RUNNER_TYPENAME, id }));
+ })
+ .filter(([, isChecked]) => isChecked)
+ .map(([id]) => id);
+ },
+ },
+ },
+ },
+ };
+
+ const localMutations = {
+ setRunnerChecked({ runner, isChecked }) {
+ const { id, userPermissions } = runner;
+ if (userPermissions?.deleteRunner) {
+ checkedRunnerIdsVar({
+ ...checkedRunnerIdsVar(),
+ [id]: isChecked,
+ });
+ }
+ },
+ setRunnersChecked({ runners, isChecked }) {
+ const newVal = runners
+ .filter(({ userPermissions }) => userPermissions?.deleteRunner)
+ .reduce((acc, { id }) => ({ ...acc, [id]: isChecked }), checkedRunnerIdsVar());
+ checkedRunnerIdsVar(newVal);
+ },
+ clearChecked() {
+ checkedRunnerIdsVar({});
+ },
+ };
+
+ return {
+ cacheConfig,
+ typeDefs,
+ localMutations,
+ };
+};
diff --git a/app/assets/javascripts/runner/graphql/list/runners_registration_token_reset.mutation.graphql b/app/assets/javascripts/ci/runner/graphql/list/runners_registration_token_reset.mutation.graphql
index 9c2797732ad..9c2797732ad 100644
--- a/app/assets/javascripts/runner/graphql/list/runners_registration_token_reset.mutation.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/list/runners_registration_token_reset.mutation.graphql
diff --git a/app/assets/javascripts/runner/graphql/list/typedefs.graphql b/app/assets/javascripts/ci/runner/graphql/list/typedefs.graphql
index 24e9e20cc8c..24e9e20cc8c 100644
--- a/app/assets/javascripts/runner/graphql/list/typedefs.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/list/typedefs.graphql
diff --git a/app/assets/javascripts/runner/graphql/shared/runner_delete.mutation.graphql b/app/assets/javascripts/ci/runner/graphql/shared/runner_delete.mutation.graphql
index d580ea2785e..d580ea2785e 100644
--- a/app/assets/javascripts/runner/graphql/shared/runner_delete.mutation.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/shared/runner_delete.mutation.graphql
diff --git a/app/assets/javascripts/runner/graphql/shared/runner_toggle_active.mutation.graphql b/app/assets/javascripts/ci/runner/graphql/shared/runner_toggle_active.mutation.graphql
index 9b15570dbc0..9b15570dbc0 100644
--- a/app/assets/javascripts/runner/graphql/shared/runner_toggle_active.mutation.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/shared/runner_toggle_active.mutation.graphql
diff --git a/app/assets/javascripts/ci/runner/graphql/show/runner.query.graphql b/app/assets/javascripts/ci/runner/graphql/show/runner.query.graphql
new file mode 100644
index 00000000000..6375b4f35a4
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/graphql/show/runner.query.graphql
@@ -0,0 +1,7 @@
+#import "ee_else_ce/ci/runner/graphql/show/runner_details.fragment.graphql"
+
+query getRunner($id: CiRunnerID!) {
+ runner(id: $id) {
+ ...RunnerDetails
+ }
+}
diff --git a/app/assets/javascripts/runner/graphql/show/runner_details.fragment.graphql b/app/assets/javascripts/ci/runner/graphql/show/runner_details.fragment.graphql
index 2449ee0fc0f..2449ee0fc0f 100644
--- a/app/assets/javascripts/runner/graphql/show/runner_details.fragment.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/show/runner_details.fragment.graphql
diff --git a/app/assets/javascripts/runner/graphql/show/runner_details_shared.fragment.graphql b/app/assets/javascripts/ci/runner/graphql/show/runner_details_shared.fragment.graphql
index b5689ff7687..b5689ff7687 100644
--- a/app/assets/javascripts/runner/graphql/show/runner_details_shared.fragment.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/show/runner_details_shared.fragment.graphql
diff --git a/app/assets/javascripts/ci/runner/graphql/show/runner_jobs.query.graphql b/app/assets/javascripts/ci/runner/graphql/show/runner_jobs.query.graphql
new file mode 100644
index 00000000000..edfc22f644b
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/graphql/show/runner_jobs.query.graphql
@@ -0,0 +1,38 @@
+#import "~/graphql_shared/fragments/page_info.fragment.graphql"
+
+query getRunnerJobs($id: CiRunnerID!, $first: Int, $last: Int, $before: String, $after: String) {
+ runner(id: $id) {
+ id
+ projectCount
+ jobs(before: $before, after: $after, first: $first, last: $last) {
+ nodes {
+ id
+ detailedStatus {
+ # fields for `<ci-badge>`
+ id
+ detailsPath
+ group
+ icon
+ text
+ }
+ pipeline {
+ id
+ project {
+ id
+ name
+ webUrl
+ }
+ }
+ shortSha
+ commitPath
+ finishedAt
+ duration
+ queuedDuration
+ tags
+ }
+ pageInfo {
+ ...PageInfo
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/runner/graphql/show/runner_projects.query.graphql b/app/assets/javascripts/ci/runner/graphql/show/runner_projects.query.graphql
index e42648b3079..e42648b3079 100644
--- a/app/assets/javascripts/runner/graphql/show/runner_projects.query.graphql
+++ b/app/assets/javascripts/ci/runner/graphql/show/runner_projects.query.graphql
diff --git a/app/assets/javascripts/runner/group_runner_show/group_runner_show_app.vue b/app/assets/javascripts/ci/runner/group_runner_show/group_runner_show_app.vue
index 75138b1bd81..75138b1bd81 100644
--- a/app/assets/javascripts/runner/group_runner_show/group_runner_show_app.vue
+++ b/app/assets/javascripts/ci/runner/group_runner_show/group_runner_show_app.vue
diff --git a/app/assets/javascripts/runner/group_runner_show/index.js b/app/assets/javascripts/ci/runner/group_runner_show/index.js
index e75f337b38e..e75f337b38e 100644
--- a/app/assets/javascripts/runner/group_runner_show/index.js
+++ b/app/assets/javascripts/ci/runner/group_runner_show/index.js
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
new file mode 100644
index 00000000000..91c22923075
--- /dev/null
+++ b/app/assets/javascripts/ci/runner/group_runners/group_runners_app.vue
@@ -0,0 +1,278 @@
+<script>
+import { GlLink } from '@gitlab/ui';
+import { createAlert } from '~/flash';
+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';
+import {
+ fromUrlQueryToSearch,
+ fromSearchToUrl,
+ fromSearchToVariables,
+ isSearchFiltered,
+} from 'ee_else_ce/ci/runner/runner_search_utils';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import groupRunnersCountQuery from 'ee_else_ce/ci/runner/graphql/list/group_runners_count.query.graphql';
+import groupRunnersQuery from 'ee_else_ce/ci/runner/graphql/list/group_runners.query.graphql';
+
+import RegistrationDropdown from '../components/registration/registration_dropdown.vue';
+import RunnerFilteredSearchBar from '../components/runner_filtered_search_bar.vue';
+import RunnerList from '../components/runner_list.vue';
+import RunnerListEmptyState from '../components/runner_list_empty_state.vue';
+import RunnerName from '../components/runner_name.vue';
+import RunnerStats from '../components/stat/runner_stats.vue';
+import RunnerPagination from '../components/runner_pagination.vue';
+import RunnerTypeTabs from '../components/runner_type_tabs.vue';
+import RunnerActionsCell from '../components/cells/runner_actions_cell.vue';
+import RunnerMembershipToggle from '../components/runner_membership_toggle.vue';
+
+import { pausedTokenConfig } from '../components/search_tokens/paused_token_config';
+import { statusTokenConfig } from '../components/search_tokens/status_token_config';
+import { tagTokenConfig } from '../components/search_tokens/tag_token_config';
+import {
+ GROUP_FILTERED_SEARCH_NAMESPACE,
+ GROUP_TYPE,
+ PROJECT_TYPE,
+ I18N_FETCH_ERROR,
+ FILTER_CSS_CLASSES,
+} from '../constants';
+import { captureException } from '../sentry_utils';
+
+export default {
+ name: 'GroupRunnersApp',
+ components: {
+ GlLink,
+ RegistrationDropdown,
+ RunnerFilteredSearchBar,
+ RunnerList,
+ RunnerListEmptyState,
+ RunnerName,
+ RunnerMembershipToggle,
+ RunnerStats,
+ RunnerPagination,
+ RunnerTypeTabs,
+ RunnerActionsCell,
+ },
+ mixins: [glFeatureFlagMixin()],
+ inject: ['emptyStateSvgPath', 'emptyStateFilteredSvgPath'],
+ props: {
+ registrationToken: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ groupFullPath: {
+ type: String,
+ required: true,
+ },
+ groupRunnersLimitedCount: {
+ type: Number,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ search: fromUrlQueryToSearch(),
+ runners: {
+ items: [],
+ urlsById: {},
+ pageInfo: {},
+ },
+ };
+ },
+ apollo: {
+ runners: {
+ query: groupRunnersQuery,
+ fetchPolicy: fetchPolicies.NETWORK_ONLY,
+ variables() {
+ return this.variables;
+ },
+ update(data) {
+ const { edges = [], pageInfo = {} } = data?.group?.runners || {};
+
+ const items = [];
+ const urlsById = {};
+
+ edges.forEach(({ node, webUrl, editUrl }) => {
+ items.push(node);
+ urlsById[node.id] = {
+ web: webUrl,
+ edit: editUrl,
+ };
+ });
+
+ return {
+ items,
+ urlsById,
+ pageInfo,
+ };
+ },
+ error(error) {
+ createAlert({ message: I18N_FETCH_ERROR });
+
+ this.reportToSentry(error);
+ },
+ },
+ },
+ computed: {
+ variables() {
+ return {
+ ...fromSearchToVariables(this.search),
+ groupFullPath: this.groupFullPath,
+ };
+ },
+ countVariables() {
+ // Exclude pagination variables, leave only filters variables
+ const { sort, before, last, after, first, ...countVariables } = this.variables;
+ return countVariables;
+ },
+ runnersLoading() {
+ return this.$apollo.queries.runners.loading;
+ },
+ noRunnersFound() {
+ return !this.runnersLoading && !this.runners.items.length;
+ },
+ filteredSearchNamespace() {
+ return `${GROUP_FILTERED_SEARCH_NAMESPACE}/${this.groupFullPath}`;
+ },
+ searchTokens() {
+ return [
+ pausedTokenConfig,
+ statusTokenConfig,
+ {
+ ...tagTokenConfig,
+ suggestionsDisabled: true,
+ },
+ upgradeStatusTokenConfig,
+ ];
+ },
+ isSearchFiltered() {
+ return isSearchFiltered(this.search);
+ },
+ },
+ watch: {
+ search: {
+ deep: true,
+ handler() {
+ // TODO Implement back button reponse using onpopstate
+ // See https://gitlab.com/gitlab-org/gitlab/-/issues/333804
+ updateHistory({
+ url: fromSearchToUrl(this.search),
+ title: document.title,
+ });
+ },
+ },
+ },
+ errorCaptured(error) {
+ this.reportToSentry(error);
+ },
+ methods: {
+ webUrl(runner) {
+ return this.runners.urlsById[runner.id]?.web;
+ },
+ editUrl(runner) {
+ return this.runners.urlsById[runner.id]?.edit;
+ },
+ refetchCounts() {
+ this.$apollo.getClient().refetchQueries({ include: [groupRunnersCountQuery] });
+ },
+ onToggledPaused() {
+ // When a runner becomes Paused, the tab count can
+ // become stale, refetch outdated counts.
+ this.refetchCounts();
+ },
+ onDeleted({ message }) {
+ this.$root.$toast?.show(message);
+ this.refetchCounts();
+ },
+ reportToSentry(error) {
+ captureException({ error, component: this.$options.name });
+ },
+ onPaginationInput(value) {
+ this.search.pagination = value;
+ },
+ },
+ TABS_RUNNER_TYPES: [GROUP_TYPE, PROJECT_TYPE],
+ GROUP_TYPE,
+ FILTER_CSS_CLASSES,
+};
+</script>
+
+<template>
+ <div>
+ <div class="gl-display-flex gl-align-items-center">
+ <runner-type-tabs
+ ref="runner-type-tabs"
+ v-model="search"
+ :count-scope="$options.GROUP_TYPE"
+ :count-variables="countVariables"
+ :runner-types="$options.TABS_RUNNER_TYPES"
+ class="gl-w-full"
+ content-class="gl-display-none"
+ nav-class="gl-border-none!"
+ />
+
+ <registration-dropdown
+ v-if="registrationToken"
+ class="gl-ml-auto"
+ :registration-token="registrationToken"
+ :type="$options.GROUP_TYPE"
+ right
+ />
+ </div>
+
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-gap-3"
+ :class="$options.FILTER_CSS_CLASSES"
+ >
+ <runner-filtered-search-bar
+ v-model="search"
+ :tokens="searchTokens"
+ :namespace="filteredSearchNamespace"
+ class="gl-flex-grow-1 gl-align-self-stretch"
+ />
+ <runner-membership-toggle
+ v-model="search.membership"
+ class="gl-align-self-end gl-md-align-self-center"
+ />
+ </div>
+
+ <runner-stats :scope="$options.GROUP_TYPE" :variables="countVariables" />
+
+ <runner-list-empty-state
+ v-if="noRunnersFound"
+ :registration-token="registrationToken"
+ :is-search-filtered="isSearchFiltered"
+ :svg-path="emptyStateSvgPath"
+ :filtered-svg-path="emptyStateFilteredSvgPath"
+ />
+ <template v-else>
+ <runner-list
+ :runners="runners.items"
+ :checkable="true"
+ :loading="runnersLoading"
+ @deleted="onDeleted"
+ >
+ <template #runner-name="{ runner }">
+ <gl-link :href="webUrl(runner)">
+ <runner-name :runner="runner" />
+ </gl-link>
+ </template>
+ <template #runner-actions-cell="{ runner }">
+ <runner-actions-cell
+ :runner="runner"
+ :edit-url="editUrl(runner)"
+ @toggledPaused="onToggledPaused"
+ @deleted="onDeleted"
+ />
+ </template>
+ </runner-list>
+ </template>
+
+ <runner-pagination
+ class="gl-mt-3"
+ :disabled="runnersLoading"
+ :page-info="runners.pageInfo"
+ @input="onPaginationInput"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/runner/group_runners/index.js b/app/assets/javascripts/ci/runner/group_runners/index.js
index 0e7efd2b8a1..0e7efd2b8a1 100644
--- a/app/assets/javascripts/runner/group_runners/index.js
+++ b/app/assets/javascripts/ci/runner/group_runners/index.js
diff --git a/app/assets/javascripts/runner/local_storage_alert/constants.js b/app/assets/javascripts/ci/runner/local_storage_alert/constants.js
index 69b7418f898..69b7418f898 100644
--- a/app/assets/javascripts/runner/local_storage_alert/constants.js
+++ b/app/assets/javascripts/ci/runner/local_storage_alert/constants.js
diff --git a/app/assets/javascripts/runner/local_storage_alert/save_alert_to_local_storage.js b/app/assets/javascripts/ci/runner/local_storage_alert/save_alert_to_local_storage.js
index ca7c627459a..ca7c627459a 100644
--- a/app/assets/javascripts/runner/local_storage_alert/save_alert_to_local_storage.js
+++ b/app/assets/javascripts/ci/runner/local_storage_alert/save_alert_to_local_storage.js
diff --git a/app/assets/javascripts/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..d768a06494a 100644
--- a/app/assets/javascripts/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
diff --git a/app/assets/javascripts/runner/runner_edit/index.js b/app/assets/javascripts/ci/runner/runner_edit/index.js
index 5b2ddb8f68e..5b2ddb8f68e 100644
--- a/app/assets/javascripts/runner/runner_edit/index.js
+++ b/app/assets/javascripts/ci/runner/runner_edit/index.js
diff --git a/app/assets/javascripts/runner/runner_edit/runner_edit_app.vue b/app/assets/javascripts/ci/runner/runner_edit/runner_edit_app.vue
index 879162916a9..879162916a9 100644
--- a/app/assets/javascripts/runner/runner_edit/runner_edit_app.vue
+++ b/app/assets/javascripts/ci/runner/runner_edit/runner_edit_app.vue
diff --git a/app/assets/javascripts/runner/runner_search_utils.js b/app/assets/javascripts/ci/runner/runner_search_utils.js
index adc832b0600..adc832b0600 100644
--- a/app/assets/javascripts/runner/runner_search_utils.js
+++ b/app/assets/javascripts/ci/runner/runner_search_utils.js
diff --git a/app/assets/javascripts/runner/runner_update_form_utils.js b/app/assets/javascripts/ci/runner/runner_update_form_utils.js
index 3b519fa7d71..3b519fa7d71 100644
--- a/app/assets/javascripts/runner/runner_update_form_utils.js
+++ b/app/assets/javascripts/ci/runner/runner_update_form_utils.js
diff --git a/app/assets/javascripts/runner/sentry_utils.js b/app/assets/javascripts/ci/runner/sentry_utils.js
index 29de1f9adae..29de1f9adae 100644
--- a/app/assets/javascripts/runner/sentry_utils.js
+++ b/app/assets/javascripts/ci/runner/sentry_utils.js
diff --git a/app/assets/javascripts/runner/utils.js b/app/assets/javascripts/ci/runner/utils.js
index 1ca0a9e86b5..1ca0a9e86b5 100644
--- a/app/assets/javascripts/runner/utils.js
+++ b/app/assets/javascripts/ci/runner/utils.js
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_admin_variables.vue b/app/assets/javascripts/ci_variable_list/components/ci_admin_variables.vue
index 8d891ff1746..719696f682e 100644
--- a/app/assets/javascripts/ci_variable_list/components/ci_admin_variables.vue
+++ b/app/assets/javascripts/ci_variable_list/components/ci_admin_variables.vue
@@ -1,143 +1,36 @@
<script>
-import { createAlert } from '~/flash';
-import { __ } from '~/locale';
-import { reportMessageToSentry } from '../utils';
+import { ADD_MUTATION_ACTION, DELETE_MUTATION_ACTION, UPDATE_MUTATION_ACTION } from '../constants';
import getAdminVariables from '../graphql/queries/variables.query.graphql';
-import {
- ADD_MUTATION_ACTION,
- DELETE_MUTATION_ACTION,
- UPDATE_MUTATION_ACTION,
- genericMutationErrorText,
- variableFetchErrorText,
-} from '../constants';
import addAdminVariable from '../graphql/mutations/admin_add_variable.mutation.graphql';
import deleteAdminVariable from '../graphql/mutations/admin_delete_variable.mutation.graphql';
import updateAdminVariable from '../graphql/mutations/admin_update_variable.mutation.graphql';
-import CiVariableSettings from './ci_variable_settings.vue';
+import CiVariableShared from './ci_variable_shared.vue';
export default {
components: {
- CiVariableSettings,
+ CiVariableShared,
},
- inject: ['endpoint'],
- data() {
- return {
- adminVariables: [],
- hasNextPage: false,
- isInitialLoading: true,
- isLoadingMoreItems: false,
- loadingCounter: 0,
- pageInfo: {},
- };
+ mutationData: {
+ [ADD_MUTATION_ACTION]: addAdminVariable,
+ [UPDATE_MUTATION_ACTION]: updateAdminVariable,
+ [DELETE_MUTATION_ACTION]: deleteAdminVariable,
},
- apollo: {
- adminVariables: {
+ queryData: {
+ ciVariables: {
+ lookup: (data) => data?.ciVariables,
query: getAdminVariables,
- update(data) {
- return data?.ciVariables?.nodes || [];
- },
- result({ data }) {
- this.pageInfo = data?.ciVariables?.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.$options.componentName, this.$options.tooManyCallsError, {});
- }
- },
- error() {
- this.isLoadingMoreItems = false;
- this.hasNextPage = false;
- createAlert({ message: variableFetchErrorText });
- },
- watchLoading(flag) {
- if (!flag) {
- this.isInitialLoading = false;
- }
- },
- },
- },
- computed: {
- isLoading() {
- return (
- (this.$apollo.queries.adminVariables.loading && this.isInitialLoading) ||
- this.isLoadingMoreItems
- );
},
},
- methods: {
- addVariable(variable) {
- this.variableMutation(ADD_MUTATION_ACTION, variable);
- },
- deleteVariable(variable) {
- this.variableMutation(DELETE_MUTATION_ACTION, variable);
- },
- fetchMoreVariables() {
- this.isLoadingMoreItems = true;
-
- this.$apollo.queries.adminVariables.fetchMore({
- variables: {
- after: this.pageInfo.endCursor,
- },
- });
- },
- updateVariable(variable) {
- this.variableMutation(UPDATE_MUTATION_ACTION, variable);
- },
- async variableMutation(mutationAction, variable) {
- try {
- const currentMutation = this.$options.mutationData[mutationAction];
- const { data } = await this.$apollo.mutate({
- mutation: currentMutation.action,
- variables: {
- endpoint: this.endpoint,
- variable,
- },
- });
-
- if (data[currentMutation.name]?.errors?.length) {
- const { errors } = data[currentMutation.name];
- createAlert({ message: errors[0] });
- } else {
- // The writing to cache for admin variable is not working
- // because there is no ID in the cache at the top level.
- // We therefore need to manually refetch.
- this.$apollo.queries.adminVariables.refetch();
- }
- } catch {
- createAlert({ message: genericMutationErrorText });
- }
- },
- },
- componentName: 'InstanceVariables',
- i18n: {
- tooManyCallsError: __('Maximum number of variables loaded (2000)'),
- },
- mutationData: {
- [ADD_MUTATION_ACTION]: { action: addAdminVariable, name: 'addAdminVariable' },
- [UPDATE_MUTATION_ACTION]: { action: updateAdminVariable, name: 'updateAdminVariable' },
- [DELETE_MUTATION_ACTION]: { action: deleteAdminVariable, name: 'deleteAdminVariable' },
- },
};
</script>
<template>
- <ci-variable-settings
+ <ci-variable-shared
:are-scoped-variables-available="false"
- :is-loading="isLoading"
- :variables="adminVariables"
- @add-variable="addVariable"
- @delete-variable="deleteVariable"
- @update-variable="updateVariable"
+ component-name="InstanceVariables"
+ :hide-environment-scope="true"
+ :mutation-data="$options.mutationData"
+ :refetch-after-mutation="true"
+ :query-data="$options.queryData"
/>
</template>
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_group_variables.vue b/app/assets/javascripts/ci_variable_list/components/ci_group_variables.vue
index 4af696b8dab..c8f5ac1736d 100644
--- a/app/assets/javascripts/ci_variable_list/components/ci_group_variables.vue
+++ b/app/assets/javascripts/ci_variable_list/components/ci_group_variables.vue
@@ -1,143 +1,53 @@
<script>
-import { createAlert } from '~/flash';
-import { __ } from '~/locale';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { reportMessageToSentry } from '../utils';
-import getGroupVariables from '../graphql/queries/group_variables.query.graphql';
import {
ADD_MUTATION_ACTION,
DELETE_MUTATION_ACTION,
GRAPHQL_GROUP_TYPE,
UPDATE_MUTATION_ACTION,
- genericMutationErrorText,
- variableFetchErrorText,
} from '../constants';
+import getGroupVariables from '../graphql/queries/group_variables.query.graphql';
import addGroupVariable from '../graphql/mutations/group_add_variable.mutation.graphql';
import deleteGroupVariable from '../graphql/mutations/group_delete_variable.mutation.graphql';
import updateGroupVariable from '../graphql/mutations/group_update_variable.mutation.graphql';
-import CiVariableSettings from './ci_variable_settings.vue';
+import CiVariableShared from './ci_variable_shared.vue';
export default {
components: {
- CiVariableSettings,
+ CiVariableShared,
},
mixins: [glFeatureFlagsMixin()],
- inject: ['endpoint', 'groupPath', 'groupId'],
- data() {
- return {
- groupVariables: [],
- hasNextPage: false,
- isLoadingMoreItems: false,
- loadingCounter: 0,
- pageInfo: {},
- };
- },
- apollo: {
- groupVariables: {
- query: getGroupVariables,
- variables() {
- return {
- fullPath: this.groupPath,
- };
- },
- update(data) {
- return data?.group?.ciVariables?.nodes || [];
- },
- result({ data }) {
- this.pageInfo = data?.group?.ciVariables?.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.$options.componentName, this.$options.tooManyCallsError, {});
- }
- },
- error() {
- this.isLoadingMoreItems = false;
- this.hasNextPage = false;
- createAlert({ message: variableFetchErrorText });
- },
- },
- },
+ inject: ['groupPath', 'groupId'],
computed: {
areScopedVariablesAvailable() {
return this.glFeatures.groupScopedCiVariables;
},
- isLoading() {
- return this.$apollo.queries.groupVariables.loading || this.isLoadingMoreItems;
- },
- },
- methods: {
- addVariable(variable) {
- this.variableMutation(ADD_MUTATION_ACTION, variable);
- },
- deleteVariable(variable) {
- this.variableMutation(DELETE_MUTATION_ACTION, variable);
- },
- fetchMoreVariables() {
- this.isLoadingMoreItems = true;
-
- this.$apollo.queries.groupVariables.fetchMore({
- variables: {
- fullPath: this.groupPath,
- after: this.pageInfo.endCursor,
- },
- });
- },
- updateVariable(variable) {
- this.variableMutation(UPDATE_MUTATION_ACTION, variable);
- },
- async variableMutation(mutationAction, variable) {
- try {
- const currentMutation = this.$options.mutationData[mutationAction];
- const { data } = await this.$apollo.mutate({
- mutation: currentMutation.action,
- variables: {
- endpoint: this.endpoint,
- fullPath: this.groupPath,
- groupId: convertToGraphQLId(GRAPHQL_GROUP_TYPE, this.groupId),
- variable,
- },
- });
-
- if (data[currentMutation.name]?.errors?.length) {
- const { errors } = data[currentMutation.name];
- createAlert({ message: errors[0] });
- }
- } catch {
- createAlert({ message: genericMutationErrorText });
- }
+ graphqlId() {
+ return convertToGraphQLId(GRAPHQL_GROUP_TYPE, this.groupId);
},
},
- componentName: 'GroupVariables',
- i18n: {
- tooManyCallsError: __('Maximum number of variables loaded (2000)'),
- },
mutationData: {
- [ADD_MUTATION_ACTION]: { action: addGroupVariable, name: 'addGroupVariable' },
- [UPDATE_MUTATION_ACTION]: { action: updateGroupVariable, name: 'updateGroupVariable' },
- [DELETE_MUTATION_ACTION]: { action: deleteGroupVariable, name: 'deleteGroupVariable' },
+ [ADD_MUTATION_ACTION]: addGroupVariable,
+ [UPDATE_MUTATION_ACTION]: updateGroupVariable,
+ [DELETE_MUTATION_ACTION]: deleteGroupVariable,
+ },
+ queryData: {
+ ciVariables: {
+ lookup: (data) => data?.group?.ciVariables,
+ query: getGroupVariables,
+ },
},
};
</script>
<template>
- <ci-variable-settings
+ <ci-variable-shared
+ :id="graphqlId"
:are-scoped-variables-available="areScopedVariablesAvailable"
- :is-loading="isLoading"
- :variables="groupVariables"
- @add-variable="addVariable"
- @delete-variable="deleteVariable"
- @update-variable="updateVariable"
+ component-name="GroupVariables"
+ :full-path="groupPath"
+ :mutation-data="$options.mutationData"
+ :query-data="$options.queryData"
/>
</template>
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_project_variables.vue b/app/assets/javascripts/ci_variable_list/components/ci_project_variables.vue
index 6bd549817f8..2c4818e20c1 100644
--- a/app/assets/javascripts/ci_variable_list/components/ci_project_variables.vue
+++ b/app/assets/javascripts/ci_variable_list/components/ci_project_variables.vue
@@ -1,160 +1,55 @@
<script>
-import { createAlert } from '~/flash';
-import { __ } from '~/locale';
import { convertToGraphQLId } from '~/graphql_shared/utils';
-import getProjectEnvironments from '../graphql/queries/project_environments.query.graphql';
-import getProjectVariables from '../graphql/queries/project_variables.query.graphql';
-import { mapEnvironmentNames, reportMessageToSentry } from '../utils';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import {
ADD_MUTATION_ACTION,
DELETE_MUTATION_ACTION,
GRAPHQL_PROJECT_TYPE,
UPDATE_MUTATION_ACTION,
- environmentFetchErrorText,
- genericMutationErrorText,
- variableFetchErrorText,
} from '../constants';
+import getProjectEnvironments from '../graphql/queries/project_environments.query.graphql';
+import getProjectVariables from '../graphql/queries/project_variables.query.graphql';
import addProjectVariable from '../graphql/mutations/project_add_variable.mutation.graphql';
import deleteProjectVariable from '../graphql/mutations/project_delete_variable.mutation.graphql';
import updateProjectVariable from '../graphql/mutations/project_update_variable.mutation.graphql';
-import CiVariableSettings from './ci_variable_settings.vue';
+import CiVariableShared from './ci_variable_shared.vue';
export default {
components: {
- CiVariableSettings,
- },
- inject: ['endpoint', 'projectFullPath', 'projectId'],
- data() {
- return {
- hasNextPage: false,
- isLoadingMoreItems: false,
- loadingCounter: 0,
- pageInfo: {},
- projectEnvironments: [],
- projectVariables: [],
- };
- },
- apollo: {
- projectEnvironments: {
- query: getProjectEnvironments,
- variables() {
- return {
- fullPath: this.projectFullPath,
- };
- },
- update(data) {
- return mapEnvironmentNames(data?.project?.environments?.nodes);
- },
- error() {
- createAlert({ message: environmentFetchErrorText });
- },
- },
- projectVariables: {
- query: getProjectVariables,
- variables() {
- return {
- after: null,
- fullPath: this.projectFullPath,
- };
- },
- update(data) {
- return data?.project?.ciVariables?.nodes || [];
- },
- result({ data }) {
- this.pageInfo = data?.project?.ciVariables?.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.$options.componentName, this.$options.tooManyCallsError, {});
- }
- },
- error() {
- this.isLoadingMoreItems = false;
- this.hasNextPage = false;
- createAlert({ message: variableFetchErrorText });
- },
- },
+ CiVariableShared,
},
+ mixins: [glFeatureFlagsMixin()],
+ inject: ['projectFullPath', 'projectId'],
computed: {
- isLoading() {
- return (
- this.$apollo.queries.projectVariables.loading ||
- this.$apollo.queries.projectEnvironments.loading ||
- this.isLoadingMoreItems
- );
+ graphqlId() {
+ return convertToGraphQLId(GRAPHQL_PROJECT_TYPE, this.projectId);
},
},
- methods: {
- addVariable(variable) {
- this.variableMutation(ADD_MUTATION_ACTION, variable);
- },
- deleteVariable(variable) {
- this.variableMutation(DELETE_MUTATION_ACTION, variable);
- },
- fetchMoreVariables() {
- this.isLoadingMoreItems = true;
-
- this.$apollo.queries.projectVariables.fetchMore({
- variables: {
- fullPath: this.projectFullPath,
- after: this.pageInfo.endCursor,
- },
- });
- },
- updateVariable(variable) {
- this.variableMutation(UPDATE_MUTATION_ACTION, variable);
+ mutationData: {
+ [ADD_MUTATION_ACTION]: addProjectVariable,
+ [UPDATE_MUTATION_ACTION]: updateProjectVariable,
+ [DELETE_MUTATION_ACTION]: deleteProjectVariable,
+ },
+ queryData: {
+ ciVariables: {
+ lookup: (data) => data?.project?.ciVariables,
+ query: getProjectVariables,
},
- async variableMutation(mutationAction, variable) {
- try {
- const currentMutation = this.$options.mutationData[mutationAction];
- const { data } = await this.$apollo.mutate({
- mutation: currentMutation.action,
- variables: {
- endpoint: this.endpoint,
- fullPath: this.projectFullPath,
- projectId: convertToGraphQLId(GRAPHQL_PROJECT_TYPE, this.projectId),
- variable,
- },
- });
- if (data[currentMutation.name]?.errors?.length) {
- const { errors } = data[currentMutation.name];
- createAlert({ message: errors[0] });
- }
- } catch {
- createAlert({ message: genericMutationErrorText });
- }
+ environments: {
+ lookup: (data) => data?.project?.environments,
+ query: getProjectEnvironments,
},
},
- componentName: 'ProjectVariables',
- i18n: {
- tooManyCallsError: __('Maximum number of variables loaded (2000)'),
- },
- mutationData: {
- [ADD_MUTATION_ACTION]: { action: addProjectVariable, name: 'addProjectVariable' },
- [UPDATE_MUTATION_ACTION]: { action: updateProjectVariable, name: 'updateProjectVariable' },
- [DELETE_MUTATION_ACTION]: { action: deleteProjectVariable, name: 'deleteProjectVariable' },
- },
};
</script>
<template>
- <ci-variable-settings
+ <ci-variable-shared
+ :id="graphqlId"
:are-scoped-variables-available="true"
- :environments="projectEnvironments"
- :is-loading="isLoading"
- :variables="projectVariables"
- @add-variable="addVariable"
- @delete-variable="deleteVariable"
- @update-variable="updateVariable"
+ component-name="ProjectVariables"
+ :full-path="projectFullPath"
+ :mutation-data="$options.mutationData"
+ :query-data="$options.queryData"
/>
</template>
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue b/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
index 56c1804910a..94f8cb9e906 100644
--- a/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
+++ b/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
@@ -86,6 +86,11 @@ export default {
required: false,
default: () => [],
},
+ hideEnvironmentScope: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
mode: {
type: String,
required: true,
@@ -293,10 +298,11 @@ export default {
v-model="variable.value"
:state="variableValidationState"
rows="3"
- max-rows="6"
+ max-rows="10"
data-testid="pipeline-form-ci-variable-value"
data-qa-selector="ci_variable_value_field"
class="gl-font-monospace!"
+ spellcheck="false"
/>
</gl-form-group>
@@ -309,33 +315,35 @@ export default {
/>
</gl-form-group>
- <gl-form-group
- label-for="ci-variable-env"
- class="gl-w-half"
- data-testid="environment-scope"
- >
- <template #label>
- {{ __('Environment scope') }}
- <gl-link
- :title="$options.environmentScopeLinkTitle"
- :href="environmentScopeLink"
- target="_blank"
- data-testid="environment-scope-link"
- >
- <gl-icon name="question" :size="12" />
- </gl-link>
- </template>
- <ci-environments-dropdown
- v-if="areScopedVariablesAvailable"
- class="gl-w-full"
- :selected-environment-scope="variable.environmentScope"
- :environments="joinedEnvironments"
- @select-environment="setEnvironmentScope"
- @create-environment-scope="createEnvironmentScope"
- />
+ <template v-if="!hideEnvironmentScope">
+ <gl-form-group
+ label-for="ci-variable-env"
+ class="gl-w-half"
+ data-testid="environment-scope"
+ >
+ <template #label>
+ {{ __('Environment scope') }}
+ <gl-link
+ :title="$options.environmentScopeLinkTitle"
+ :href="environmentScopeLink"
+ target="_blank"
+ data-testid="environment-scope-link"
+ >
+ <gl-icon name="question" :size="12" />
+ </gl-link>
+ </template>
+ <ci-environments-dropdown
+ v-if="areScopedVariablesAvailable"
+ class="gl-w-full"
+ :selected-environment-scope="variable.environmentScope"
+ :environments="joinedEnvironments"
+ @select-environment="setEnvironmentScope"
+ @create-environment-scope="createEnvironmentScope"
+ />
- <gl-form-input v-else :value="$options.defaultScope" class="gl-w-full" readonly />
- </gl-form-group>
+ <gl-form-input v-else :value="$options.defaultScope" class="gl-w-full" readonly />
+ </gl-form-group>
+ </template>
</div>
<gl-form-group :label="__('Flags')" label-for="ci-variable-flags">
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_popover.vue b/app/assets/javascripts/ci_variable_list/components/ci_variable_popover.vue
deleted file mode 100644
index 605da5d9352..00000000000
--- a/app/assets/javascripts/ci_variable_list/components/ci_variable_popover.vue
+++ /dev/null
@@ -1,58 +0,0 @@
-<script>
-import { GlPopover, GlButton, GlTooltipDirective } from '@gitlab/ui';
-
-export default {
- maxTextLength: 95,
- components: {
- GlPopover,
- GlButton,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- target: {
- type: String,
- required: true,
- },
- value: {
- type: String,
- required: true,
- },
- tooltipText: {
- type: String,
- required: true,
- },
- },
- computed: {
- displayValue() {
- if (this.value.length > this.$options.maxTextLength) {
- return `${this.value.substring(0, this.$options.maxTextLength)}...`;
- }
- return this.value;
- },
- },
-};
-</script>
-
-<template>
- <div id="popover-container">
- <gl-popover :target="target" placement="top" container="popover-container">
- <div
- class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-word-break-all"
- >
- <div class="ci-popover-value gl-pr-3">
- {{ displayValue }}
- </div>
- <gl-button
- v-gl-tooltip
- category="tertiary"
- icon="copy-to-clipboard"
- :title="tooltipText"
- :data-clipboard-text="value"
- :aria-label="__('Copy to clipboard')"
- />
- </div>
- </gl-popover>
- </div>
-</template>
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_settings.vue b/app/assets/javascripts/ci_variable_list/components/ci_variable_settings.vue
index 81e3a983ea3..94fd6c3892c 100644
--- a/app/assets/javascripts/ci_variable_list/components/ci_variable_settings.vue
+++ b/app/assets/javascripts/ci_variable_list/components/ci_variable_settings.vue
@@ -19,6 +19,11 @@ export default {
required: false,
default: () => [],
},
+ hideEnvironmentScope: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
isLoading: {
type: Boolean,
required: false,
@@ -78,6 +83,7 @@ export default {
v-if="showModal"
:are-scoped-variables-available="areScopedVariablesAvailable"
:environments="environments"
+ :hide-environment-scope="hideEnvironmentScope"
:variables="variables"
:mode="mode"
:selected-variable="selectedVariable"
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_shared.vue b/app/assets/javascripts/ci_variable_list/components/ci_variable_shared.vue
new file mode 100644
index 00000000000..7ee250cea98
--- /dev/null
+++ b/app/assets/javascripts/ci_variable_list/components/ci_variable_shared.vue
@@ -0,0 +1,232 @@
+<script>
+import { createAlert } from '~/flash';
+import { __ } from '~/locale';
+import { mapEnvironmentNames, reportMessageToSentry } from '../utils';
+import {
+ ADD_MUTATION_ACTION,
+ DELETE_MUTATION_ACTION,
+ UPDATE_MUTATION_ACTION,
+ environmentFetchErrorText,
+ genericMutationErrorText,
+ variableFetchErrorText,
+} from '../constants';
+import CiVariableSettings from './ci_variable_settings.vue';
+
+export default {
+ components: {
+ CiVariableSettings,
+ },
+ inject: ['endpoint'],
+ props: {
+ areScopedVariablesAvailable: {
+ required: true,
+ type: Boolean,
+ },
+ componentName: {
+ required: true,
+ type: String,
+ },
+ fullPath: {
+ required: false,
+ type: String,
+ default: null,
+ },
+ hideEnvironmentScope: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ id: {
+ required: false,
+ type: String,
+ default: null,
+ },
+ mutationData: {
+ required: true,
+ type: Object,
+ validator: (obj) => {
+ const hasValidKeys = Object.keys(obj).includes(
+ ADD_MUTATION_ACTION,
+ UPDATE_MUTATION_ACTION,
+ DELETE_MUTATION_ACTION,
+ );
+
+ const hasValidValues = Object.values(obj).reduce((acc, val) => {
+ return acc && typeof val === 'object';
+ }, true);
+
+ return hasValidKeys && hasValidValues;
+ },
+ },
+ refetchAfterMutation: {
+ required: false,
+ type: Boolean,
+ default: false,
+ },
+ queryData: {
+ required: true,
+ type: Object,
+ validator: (obj) => {
+ const { ciVariables, environments } = obj;
+ const hasCiVariablesKey = Boolean(ciVariables);
+ let hasCorrectEnvData = true;
+
+ const hasCorrectVariablesData =
+ typeof ciVariables?.lookup === 'function' && typeof ciVariables.query === 'object';
+
+ if (environments) {
+ hasCorrectEnvData =
+ typeof environments?.lookup === 'function' && typeof environments.query === 'object';
+ }
+
+ return hasCiVariablesKey && hasCorrectVariablesData && hasCorrectEnvData;
+ },
+ },
+ },
+ data() {
+ return {
+ ciVariables: [],
+ hasNextPage: false,
+ isInitialLoading: true,
+ isLoadingMoreItems: false,
+ loadingCounter: 0,
+ pageInfo: {},
+ };
+ },
+ apollo: {
+ ciVariables: {
+ query() {
+ return this.queryData.ciVariables.query;
+ },
+ variables() {
+ return {
+ fullPath: this.fullPath || undefined,
+ };
+ },
+ update(data) {
+ return this.queryData.ciVariables.lookup(data)?.nodes || [];
+ },
+ result({ data }) {
+ 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, {});
+ }
+ },
+ error() {
+ this.isLoadingMoreItems = false;
+ this.hasNextPage = false;
+ createAlert({ message: variableFetchErrorText });
+ },
+ watchLoading(flag) {
+ if (!flag) {
+ this.isInitialLoading = false;
+ }
+ },
+ },
+ environments: {
+ query() {
+ return this.queryData?.environments?.query || {};
+ },
+ skip() {
+ return !this.queryData?.environments?.query;
+ },
+ variables() {
+ return {
+ fullPath: this.fullPath,
+ };
+ },
+ update(data) {
+ return mapEnvironmentNames(this.queryData.environments.lookup(data)?.nodes);
+ },
+ error() {
+ createAlert({ message: environmentFetchErrorText });
+ },
+ },
+ },
+ computed: {
+ isLoading() {
+ return (
+ (this.$apollo.queries.ciVariables.loading && this.isInitialLoading) ||
+ this.$apollo.queries.environments.loading ||
+ this.isLoadingMoreItems
+ );
+ },
+ },
+ methods: {
+ addVariable(variable) {
+ this.variableMutation(ADD_MUTATION_ACTION, variable);
+ },
+ deleteVariable(variable) {
+ this.variableMutation(DELETE_MUTATION_ACTION, variable);
+ },
+ fetchMoreVariables() {
+ this.isLoadingMoreItems = true;
+
+ this.$apollo.queries.ciVariables.fetchMore({
+ variables: {
+ after: this.pageInfo.endCursor,
+ },
+ });
+ },
+ updateVariable(variable) {
+ this.variableMutation(UPDATE_MUTATION_ACTION, variable);
+ },
+ async variableMutation(mutationAction, variable) {
+ try {
+ const currentMutation = this.mutationData[mutationAction];
+
+ const { data } = await this.$apollo.mutate({
+ mutation: currentMutation,
+ variables: {
+ endpoint: this.endpoint,
+ fullPath: this.fullPath || undefined,
+ id: this.id || undefined,
+ variable,
+ },
+ });
+
+ if (data.ciVariableMutation?.errors?.length) {
+ const { errors } = data.ciVariableMutation;
+ createAlert({ message: errors[0] });
+ } else if (this.refetchAfterMutation) {
+ // The writing to cache for admin variable is not working
+ // because there is no ID in the cache at the top level.
+ // We therefore need to manually refetch.
+ this.$apollo.queries.ciVariables.refetch();
+ }
+ } catch (e) {
+ createAlert({ message: genericMutationErrorText });
+ }
+ },
+ },
+ i18n: {
+ tooManyCallsError: __('Maximum number of variables loaded (2000)'),
+ },
+};
+</script>
+
+<template>
+ <ci-variable-settings
+ :are-scoped-variables-available="areScopedVariablesAvailable"
+ :hide-environment-scope="hideEnvironmentScope"
+ :is-loading="isLoading"
+ :variables="ciVariables"
+ :environments="environments"
+ @add-variable="addVariable"
+ @delete-variable="deleteVariable"
+ @update-variable="updateVariable"
+ />
+</template>
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue b/app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue
index 959ef6864fb..3cdcb68e919 100644
--- a/app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue
+++ b/app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue
@@ -1,71 +1,49 @@
<script>
-import {
- GlButton,
- GlIcon,
- GlLoadingIcon,
- GlModalDirective,
- GlTable,
- GlTooltipDirective,
-} from '@gitlab/ui';
+import { GlButton, GlLoadingIcon, GlModalDirective, GlTable, GlTooltipDirective } from '@gitlab/ui';
import { s__, __ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import { ADD_CI_VARIABLE_MODAL_ID, variableText } from '../constants';
import { convertEnvironmentScope } from '../utils';
-import CiVariablePopover from './ci_variable_popover.vue';
export default {
modalId: ADD_CI_VARIABLE_MODAL_ID,
- trueIcon: 'mobile-issue-close',
- falseIcon: 'close',
- iconSize: 16,
fields: [
{
key: 'variableType',
label: s__('CiVariables|Type'),
- customStyle: { width: '70px' },
+ thClass: 'gl-w-10p',
},
{
key: 'key',
label: s__('CiVariables|Key'),
tdClass: 'text-plain',
sortable: true,
- customStyle: { width: '40%' },
},
{
key: 'value',
label: s__('CiVariables|Value'),
- customStyle: { width: '40%' },
+ thClass: 'gl-w-15p',
},
{
- key: 'protected',
- label: s__('CiVariables|Protected'),
- customStyle: { width: '100px' },
- },
- {
- key: 'masked',
- label: s__('CiVariables|Masked'),
- customStyle: { width: '100px' },
+ key: 'options',
+ label: s__('CiVariables|Options'),
+ thClass: 'gl-w-10p',
},
{
key: 'environmentScope',
label: s__('CiVariables|Environments'),
- customStyle: { width: '20%' },
},
{
key: 'actions',
label: '',
tdClass: 'text-right',
- customStyle: { width: '35px' },
+ thClass: 'gl-w-5p',
},
],
components: {
- CiVariablePopover,
GlButton,
- GlIcon,
GlLoadingIcon,
GlTable,
- TooltipOnTruncate,
},
directives: {
GlModalDirective,
@@ -97,6 +75,13 @@ export default {
fields() {
return this.$options.fields;
},
+ variablesWithOptions() {
+ return this.variables?.map((item, index) => ({
+ ...item,
+ options: this.getOptions(item),
+ index,
+ }));
+ },
},
methods: {
convertEnvironmentScopeValue(env) {
@@ -108,8 +93,18 @@ export default {
toggleHiddenState() {
this.areValuesHidden = !this.areValuesHidden;
},
- setSelectedVariable(variable = null) {
- this.$emit('set-selected-variable', variable);
+ setSelectedVariable(index = -1) {
+ this.$emit('set-selected-variable', this.variables[index] ?? null);
+ },
+ getOptions(item) {
+ const options = [];
+ if (item.protected) {
+ options.push(s__('CiVariables|Protected'));
+ }
+ if (item.masked) {
+ options.push(s__('CiVariables|Masked'));
+ }
+ return options.join(', ');
},
},
};
@@ -121,7 +116,7 @@ export default {
<gl-table
v-else
:fields="fields"
- :items="variables"
+ :items="variablesWithOptions"
tbody-tr-class="js-ci-variable-row"
data-qa-selector="ci_variable_table_content"
sort-by="key"
@@ -137,23 +132,22 @@ export default {
<col v-for="field in scope.fields" :key="field.key" :style="field.customStyle" />
</template>
<template #cell(variableType)="{ item }">
- <div class="gl-pt-2">
- {{ generateTypeText(item) }}
- </div>
+ {{ generateTypeText(item) }}
</template>
<template #cell(key)="{ item }">
- <div class="gl-display-flex gl-align-items-center">
- <tooltip-on-truncate :title="item.key" truncate-target="child">
- <span
- :id="`ci-variable-key-${item.id}`"
- class="gl-display-inline-block gl-max-w-full gl-text-truncate"
- >{{ item.key }}</span
- >
- </tooltip-on-truncate>
+ <div
+ class="gl-display-flex gl-align-items-flex-start gl-justify-content-end gl-lg-justify-content-start gl-mr-n3"
+ >
+ <span
+ :id="`ci-variable-key-${item.id}`"
+ class="gl-display-inline-block gl-max-w-full gl-word-break-word"
+ >{{ item.key }}</span
+ >
<gl-button
v-gl-tooltip
category="tertiary"
icon="copy-to-clipboard"
+ class="gl-my-n3 gl-ml-2"
:title="__('Copy key')"
:data-clipboard-text="item.key"
:aria-label="__('Copy to clipboard')"
@@ -161,8 +155,10 @@ export default {
</div>
</template>
<template #cell(value)="{ item }">
- <div class="gl-display-flex gl-align-items-center">
- <span v-if="areValuesHidden" data-testid="hiddenValue">*********************</span>
+ <div
+ class="gl-display-flex gl-align-items-flex-start gl-justify-content-end gl-lg-justify-content-start gl-mr-n3"
+ >
+ <span v-if="areValuesHidden" data-testid="hiddenValue">*****</span>
<span
v-else
:id="`ci-variable-value-${item.id}`"
@@ -174,31 +170,33 @@ export default {
v-gl-tooltip
category="tertiary"
icon="copy-to-clipboard"
+ class="gl-my-n3 gl-ml-2"
:title="__('Copy value')"
:data-clipboard-text="item.value"
:aria-label="__('Copy to clipboard')"
/>
</div>
</template>
- <template #cell(protected)="{ item }">
- <gl-icon v-if="item.protected" :size="$options.iconSize" :name="$options.trueIcon" />
- <gl-icon v-else :size="$options.iconSize" :name="$options.falseIcon" />
- </template>
- <template #cell(masked)="{ item }">
- <gl-icon v-if="item.masked" :size="$options.iconSize" :name="$options.trueIcon" />
- <gl-icon v-else :size="$options.iconSize" :name="$options.falseIcon" />
+ <template #cell(options)="{ item }">
+ <span>{{ item.options }}</span>
</template>
<template #cell(environmentScope)="{ item }">
- <div class="gl-display-flex">
+ <div
+ class="gl-display-flex gl-align-items-flex-start gl-justify-content-end gl-lg-justify-content-start gl-mr-n3"
+ >
<span
:id="`ci-variable-env-${item.id}`"
- class="gl-display-inline-block gl-max-w-full gl-text-truncate"
+ class="gl-display-inline-block gl-max-w-full gl-word-break-word"
>{{ convertEnvironmentScopeValue(item.environmentScope) }}</span
>
- <ci-variable-popover
- :target="`ci-variable-env-${item.id}`"
- :value="convertEnvironmentScopeValue(item.environmentScope)"
- :tooltip-text="__('Copy environment')"
+ <gl-button
+ v-gl-tooltip
+ category="tertiary"
+ icon="copy-to-clipboard"
+ class="gl-my-n3 gl-ml-2"
+ :title="__('Copy environment')"
+ :data-clipboard-text="convertEnvironmentScopeValue(item.environmentScope)"
+ :aria-label="__('Copy to clipboard')"
/>
</div>
</template>
@@ -208,7 +206,7 @@ export default {
icon="pencil"
:aria-label="__('Edit')"
data-qa-selector="edit_ci_variable_button"
- @click="setSelectedVariable(item)"
+ @click="setSelectedVariable(item.index)"
/>
</template>
<template #empty>
diff --git a/app/assets/javascripts/ci_variable_list/components/legacy_ci_environments_dropdown.vue b/app/assets/javascripts/ci_variable_list/components/legacy_ci_environments_dropdown.vue
deleted file mode 100644
index ecb39f214ec..00000000000
--- a/app/assets/javascripts/ci_variable_list/components/legacy_ci_environments_dropdown.vue
+++ /dev/null
@@ -1,81 +0,0 @@
-<script>
-import { GlDropdown, GlDropdownItem, GlDropdownDivider, GlSearchBoxByType } from '@gitlab/ui';
-import { mapGetters } from 'vuex';
-import { __, sprintf } from '~/locale';
-
-export default {
- name: 'CiEnvironmentsDropdown',
- components: {
- GlDropdown,
- GlDropdownItem,
- GlDropdownDivider,
- GlSearchBoxByType,
- },
- props: {
- value: {
- type: String,
- required: false,
- default: '',
- },
- },
- data() {
- return {
- searchTerm: '',
- };
- },
- computed: {
- ...mapGetters(['joinedEnvironments']),
- composedCreateButtonLabel() {
- return sprintf(__('Create wildcard: %{searchTerm}'), { searchTerm: this.searchTerm });
- },
- shouldRenderCreateButton() {
- return this.searchTerm && !this.joinedEnvironments.includes(this.searchTerm);
- },
- filteredResults() {
- const lowerCasedSearchTerm = this.searchTerm.toLowerCase();
- return this.joinedEnvironments.filter((resultString) =>
- resultString.toLowerCase().includes(lowerCasedSearchTerm),
- );
- },
- },
- methods: {
- selectEnvironment(selected) {
- this.$emit('selectEnvironment', selected);
- this.searchTerm = '';
- },
- createClicked() {
- this.$emit('createClicked', this.searchTerm);
- this.searchTerm = '';
- },
- isSelected(env) {
- return this.value === env;
- },
- clearSearch() {
- this.searchTerm = '';
- },
- },
-};
-</script>
-<template>
- <gl-dropdown :text="value" @show="clearSearch">
- <gl-search-box-by-type v-model.trim="searchTerm" data-testid="ci-environment-search" />
- <gl-dropdown-item
- v-for="environment in filteredResults"
- :key="environment"
- :is-checked="isSelected(environment)"
- is-check-item
- @click="selectEnvironment(environment)"
- >
- {{ environment }}
- </gl-dropdown-item>
- <gl-dropdown-item v-if="!filteredResults.length" ref="noMatchingResults">{{
- __('No matching results')
- }}</gl-dropdown-item>
- <template v-if="shouldRenderCreateButton">
- <gl-dropdown-divider />
- <gl-dropdown-item data-testid="create-wildcard-button" @click="createClicked">
- {{ composedCreateButtonLabel }}
- </gl-dropdown-item>
- </template>
- </gl-dropdown>
-</template>
diff --git a/app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_modal.vue b/app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_modal.vue
deleted file mode 100644
index 1fbe52388c9..00000000000
--- a/app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_modal.vue
+++ /dev/null
@@ -1,428 +0,0 @@
-<script>
-import {
- GlAlert,
- GlButton,
- GlCollapse,
- GlFormCheckbox,
- GlFormCombobox,
- GlFormGroup,
- GlFormSelect,
- GlFormInput,
- GlFormTextarea,
- GlIcon,
- GlLink,
- GlModal,
- GlSprintf,
-} from '@gitlab/ui';
-import { mapActions, mapState } from 'vuex';
-import { getCookie, setCookie } from '~/lib/utils/common_utils';
-import { __ } from '~/locale';
-import Tracking from '~/tracking';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { mapComputed } from '~/vuex_shared/bindings';
-import {
- AWS_TOKEN_CONSTANTS,
- ADD_CI_VARIABLE_MODAL_ID,
- AWS_TIP_DISMISSED_COOKIE_NAME,
- AWS_TIP_MESSAGE,
- CONTAINS_VARIABLE_REFERENCE_MESSAGE,
- ENVIRONMENT_SCOPE_LINK_TITLE,
- EVENT_LABEL,
- EVENT_ACTION,
-} from '../constants';
-import LegacyCiEnvironmentsDropdown from './legacy_ci_environments_dropdown.vue';
-import { awsTokens, awsTokenList } from './ci_variable_autocomplete_tokens';
-
-const trackingMixin = Tracking.mixin({ label: EVENT_LABEL });
-
-export default {
- modalId: ADD_CI_VARIABLE_MODAL_ID,
- tokens: awsTokens,
- tokenList: awsTokenList,
- awsTipMessage: AWS_TIP_MESSAGE,
- containsVariableReferenceMessage: CONTAINS_VARIABLE_REFERENCE_MESSAGE,
- environmentScopeLinkTitle: ENVIRONMENT_SCOPE_LINK_TITLE,
- components: {
- LegacyCiEnvironmentsDropdown,
- GlAlert,
- GlButton,
- GlCollapse,
- GlFormCheckbox,
- GlFormCombobox,
- GlFormGroup,
- GlFormSelect,
- GlFormInput,
- GlFormTextarea,
- GlIcon,
- GlLink,
- GlModal,
- GlSprintf,
- },
- mixins: [glFeatureFlagsMixin(), trackingMixin],
- data() {
- return {
- isTipDismissed: getCookie(AWS_TIP_DISMISSED_COOKIE_NAME) === 'true',
- validationErrorEventProperty: '',
- };
- },
- computed: {
- ...mapState([
- 'projectId',
- 'environments',
- 'typeOptions',
- 'variable',
- 'variableBeingEdited',
- 'isGroup',
- 'maskableRegex',
- 'selectedEnvironment',
- 'isProtectedByDefault',
- 'awsLogoSvgPath',
- 'awsTipDeployLink',
- 'awsTipCommandsLink',
- 'awsTipLearnLink',
- 'containsVariableReferenceLink',
- 'protectedEnvironmentVariablesLink',
- 'maskedEnvironmentVariablesLink',
- 'environmentScopeLink',
- ]),
- ...mapComputed(
- [
- { key: 'key', updateFn: 'updateVariableKey' },
- { key: 'secret_value', updateFn: 'updateVariableValue' },
- { key: 'variable_type', updateFn: 'updateVariableType' },
- { key: 'environment_scope', updateFn: 'setEnvironmentScope' },
- { key: 'protected_variable', updateFn: 'updateVariableProtected' },
- { key: 'masked', updateFn: 'updateVariableMasked' },
- ],
- false,
- 'variable',
- ),
- isTipVisible() {
- return !this.isTipDismissed && AWS_TOKEN_CONSTANTS.includes(this.variable.key);
- },
- canSubmit() {
- return (
- this.variableValidationState &&
- this.variable.key !== '' &&
- this.variable.secret_value !== ''
- );
- },
- canMask() {
- const regex = RegExp(this.maskableRegex);
- return regex.test(this.variable.secret_value);
- },
- containsVariableReference() {
- const regex = /\$/;
- return regex.test(this.variable.secret_value);
- },
- displayMaskedError() {
- return !this.canMask && this.variable.masked;
- },
- maskedState() {
- if (this.displayMaskedError) {
- return false;
- }
- return true;
- },
- modalActionText() {
- return this.variableBeingEdited ? __('Update variable') : __('Add variable');
- },
- maskedFeedback() {
- return this.displayMaskedError ? __('This variable can not be masked.') : '';
- },
- tokenValidationFeedback() {
- const tokenSpecificFeedback = this.$options.tokens?.[this.variable.key]?.invalidMessage;
- if (!this.tokenValidationState && tokenSpecificFeedback) {
- return tokenSpecificFeedback;
- }
- return '';
- },
- tokenValidationState() {
- const validator = this.$options.tokens?.[this.variable.key]?.validation;
-
- if (validator) {
- return validator(this.variable.secret_value);
- }
-
- return true;
- },
- scopedVariablesAvailable() {
- return !this.isGroup || this.glFeatures.groupScopedCiVariables;
- },
- variableValidationFeedback() {
- return `${this.tokenValidationFeedback} ${this.maskedFeedback}`;
- },
- variableValidationState() {
- return this.variable.secret_value === '' || (this.tokenValidationState && this.maskedState);
- },
- },
- watch: {
- variable: {
- handler() {
- this.trackVariableValidationErrors();
- },
- deep: true,
- },
- },
- methods: {
- ...mapActions([
- 'addVariable',
- 'updateVariable',
- 'resetEditing',
- 'displayInputValue',
- 'clearModal',
- 'deleteVariable',
- 'setEnvironmentScope',
- 'addWildCardScope',
- 'resetSelectedEnvironment',
- 'setSelectedEnvironment',
- 'setVariableProtected',
- ]),
- dismissTip() {
- setCookie(AWS_TIP_DISMISSED_COOKIE_NAME, 'true', { expires: 90 });
- this.isTipDismissed = true;
- },
- deleteVarAndClose() {
- this.deleteVariable();
- this.hideModal();
- },
- hideModal() {
- this.$refs.modal.hide();
- },
- resetModalHandler() {
- if (this.variableBeingEdited) {
- this.resetEditing();
- }
-
- this.clearModal();
- this.resetSelectedEnvironment();
- this.resetValidationErrorEvents();
- },
- updateOrAddVariable() {
- if (this.variableBeingEdited) {
- this.updateVariable();
- } else {
- this.addVariable();
- }
- this.hideModal();
- },
- setVariableProtectedByDefault() {
- if (this.isProtectedByDefault && !this.variableBeingEdited) {
- this.setVariableProtected();
- }
- },
- trackVariableValidationErrors() {
- const property = this.getTrackingErrorProperty();
- if (!this.validationErrorEventProperty && property) {
- this.track(EVENT_ACTION, { property });
- this.validationErrorEventProperty = property;
- }
- },
- getTrackingErrorProperty() {
- let property;
- if (this.variable.secret_value?.length && !property) {
- if (this.displayMaskedError && this.maskableRegex?.length) {
- const supportedChars = this.maskableRegex.replace('^', '').replace(/{(\d,)}\$/, '');
- const regex = new RegExp(supportedChars, 'g');
- property = this.variable.secret_value.replace(regex, '');
- }
- if (this.containsVariableReference) {
- property = '$';
- }
- }
-
- return property;
- },
- resetValidationErrorEvents() {
- this.validationErrorEventProperty = '';
- },
- },
-};
-</script>
-
-<template>
- <gl-modal
- ref="modal"
- :modal-id="$options.modalId"
- :title="modalActionText"
- static
- lazy
- @hidden="resetModalHandler"
- @shown="setVariableProtectedByDefault"
- >
- <form>
- <gl-form-combobox
- v-model="key"
- :token-list="$options.tokenList"
- :label-text="__('Key')"
- data-testid="pipeline-form-ci-variable-key"
- data-qa-selector="ci_variable_key_field"
- />
-
- <gl-form-group
- :label="__('Value')"
- label-for="ci-variable-value"
- :state="variableValidationState"
- :invalid-feedback="variableValidationFeedback"
- >
- <gl-form-textarea
- id="ci-variable-value"
- ref="valueField"
- v-model="secret_value"
- :state="variableValidationState"
- rows="3"
- max-rows="6"
- data-testid="pipeline-form-ci-variable-value"
- data-qa-selector="ci_variable_value_field"
- class="gl-font-monospace!"
- />
- </gl-form-group>
-
- <div class="d-flex">
- <gl-form-group :label="__('Type')" label-for="ci-variable-type" class="w-50 gl-mr-5">
- <gl-form-select id="ci-variable-type" v-model="variable_type" :options="typeOptions" />
- </gl-form-group>
-
- <gl-form-group label-for="ci-variable-env" class="w-50" data-testid="environment-scope">
- <template #label>
- {{ __('Environment scope') }}
- <gl-link
- :title="$options.environmentScopeLinkTitle"
- :href="environmentScopeLink"
- target="_blank"
- data-testid="environment-scope-link"
- >
- <gl-icon name="question" :size="12" />
- </gl-link>
- </template>
- <legacy-ci-environments-dropdown
- v-if="scopedVariablesAvailable"
- class="w-100"
- :value="environment_scope"
- @selectEnvironment="setEnvironmentScope"
- @createClicked="addWildCardScope"
- />
-
- <gl-form-input v-else v-model="environment_scope" class="w-100" readonly />
- </gl-form-group>
- </div>
-
- <gl-form-group :label="__('Flags')" label-for="ci-variable-flags">
- <gl-form-checkbox
- v-model="protected_variable"
- class="mb-0"
- data-testid="ci-variable-protected-checkbox"
- >
- {{ __('Protect variable') }}
- <gl-link target="_blank" :href="protectedEnvironmentVariablesLink">
- <gl-icon name="question" :size="12" />
- </gl-link>
- <p class="gl-mt-2 text-secondary">
- {{ __('Export variable to pipelines running on protected branches and tags only.') }}
- </p>
- </gl-form-checkbox>
-
- <gl-form-checkbox
- ref="masked-ci-variable"
- v-model="masked"
- data-testid="ci-variable-masked-checkbox"
- >
- {{ __('Mask variable') }}
- <gl-link target="_blank" :href="maskedEnvironmentVariablesLink">
- <gl-icon name="question" :size="12" />
- </gl-link>
- <p class="gl-mt-2 gl-mb-0 text-secondary">
- {{ __('Variable will be masked in job logs.') }}
- <span
- :class="{
- 'bold text-plain': displayMaskedError,
- }"
- >
- {{ __('Requires values to meet regular expression requirements.') }}</span
- >
- <gl-link target="_blank" :href="maskedEnvironmentVariablesLink">{{
- __('More information')
- }}</gl-link>
- </p>
- </gl-form-checkbox>
- </gl-form-group>
- </form>
- <gl-collapse :visible="isTipVisible">
- <gl-alert
- :title="__('Deploying to AWS is easy with GitLab')"
- variant="tip"
- data-testid="aws-guidance-tip"
- @dismiss="dismissTip"
- >
- <div class="gl-display-flex gl-flex-direction-row">
- <div>
- <p>
- <gl-sprintf :message="$options.awsTipMessage">
- <template #deployLink="{ content }">
- <gl-link :href="awsTipDeployLink" target="_blank">{{ content }}</gl-link>
- </template>
- <template #commandsLink="{ content }">
- <gl-link :href="awsTipCommandsLink" target="_blank">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </p>
- <p>
- <gl-button
- :href="awsTipLearnLink"
- target="_blank"
- category="secondary"
- variant="info"
- class="gl-overflow-wrap-break"
- >{{ __('Learn more about deploying to AWS') }}</gl-button
- >
- </p>
- </div>
- <img
- class="gl-mt-3"
- :alt="__('Amazon Web Services Logo')"
- :src="awsLogoSvgPath"
- height="32"
- />
- </div>
- </gl-alert>
- </gl-collapse>
- <gl-alert
- v-if="containsVariableReference"
- :title="__('Value might contain a variable reference')"
- :dismissible="false"
- variant="warning"
- data-testid="contains-variable-reference"
- >
- <gl-sprintf :message="$options.containsVariableReferenceMessage">
- <template #code="{ content }">
- <code>{{ content }}</code>
- </template>
- <template #docsLink="{ content }">
- <gl-link :href="containsVariableReferenceLink" target="_blank">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </gl-alert>
- <template #modal-footer>
- <gl-button @click="hideModal">{{ __('Cancel') }}</gl-button>
- <gl-button
- v-if="variableBeingEdited"
- ref="deleteCiVariable"
- variant="danger"
- category="secondary"
- data-qa-selector="ci_variable_delete_button"
- @click="deleteVarAndClose"
- >{{ __('Delete variable') }}</gl-button
- >
- <gl-button
- ref="updateOrAddVariable"
- :disabled="!canSubmit"
- variant="confirm"
- category="primary"
- data-testid="ciUpdateOrAddVariableBtn"
- data-qa-selector="ci_variable_save_button"
- @click="updateOrAddVariable"
- >{{ modalActionText }}
- </gl-button>
- </template>
- </gl-modal>
-</template>
diff --git a/app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_settings.vue b/app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_settings.vue
deleted file mode 100644
index f1fe188348d..00000000000
--- a/app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_settings.vue
+++ /dev/null
@@ -1,32 +0,0 @@
-<script>
-import { mapState, mapActions } from 'vuex';
-import LegacyCiVariableModal from './legacy_ci_variable_modal.vue';
-import LegacyCiVariableTable from './legacy_ci_variable_table.vue';
-
-export default {
- components: {
- LegacyCiVariableModal,
- LegacyCiVariableTable,
- },
- computed: {
- ...mapState(['isGroup', 'isProject']),
- },
- mounted() {
- if (this.isProject) {
- this.fetchEnvironments();
- }
- },
- methods: {
- ...mapActions(['fetchEnvironments']),
- },
-};
-</script>
-
-<template>
- <div class="row">
- <div class="col-lg-12">
- <legacy-ci-variable-table />
- <legacy-ci-variable-modal />
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_table.vue b/app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_table.vue
deleted file mode 100644
index f078234829a..00000000000
--- a/app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_table.vue
+++ /dev/null
@@ -1,199 +0,0 @@
-<script>
-import { GlTable, GlButton, GlModalDirective, GlIcon, GlTooltipDirective } from '@gitlab/ui';
-import { mapState, mapActions } from 'vuex';
-import { s__, __ } from '~/locale';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
-import { ADD_CI_VARIABLE_MODAL_ID } from '../constants';
-import CiVariablePopover from './ci_variable_popover.vue';
-
-export default {
- modalId: ADD_CI_VARIABLE_MODAL_ID,
- trueIcon: 'mobile-issue-close',
- falseIcon: 'close',
- iconSize: 16,
- fields: [
- {
- key: 'variable_type',
- label: s__('CiVariables|Type'),
- customStyle: { width: '70px' },
- },
- {
- key: 'key',
- label: s__('CiVariables|Key'),
- tdClass: 'text-plain',
- sortable: true,
- customStyle: { width: '40%' },
- },
- {
- key: 'value',
- label: s__('CiVariables|Value'),
- customStyle: { width: '40%' },
- },
- {
- key: 'protected',
- label: s__('CiVariables|Protected'),
- customStyle: { width: '100px' },
- },
- {
- key: 'masked',
- label: s__('CiVariables|Masked'),
- customStyle: { width: '100px' },
- },
- {
- key: 'environment_scope',
- label: s__('CiVariables|Environments'),
- customStyle: { width: '20%' },
- },
- {
- key: 'actions',
- label: '',
- tdClass: 'text-right',
- customStyle: { width: '35px' },
- },
- ],
- components: {
- CiVariablePopover,
- GlButton,
- GlIcon,
- GlTable,
- TooltipOnTruncate,
- },
- directives: {
- GlModalDirective,
- GlTooltip: GlTooltipDirective,
- },
- mixins: [glFeatureFlagsMixin()],
- computed: {
- ...mapState(['variables', 'valuesHidden', 'isLoading', 'isDeleting']),
- valuesButtonText() {
- return this.valuesHidden ? __('Reveal values') : __('Hide values');
- },
- isTableEmpty() {
- return !this.variables || this.variables.length === 0;
- },
- fields() {
- return this.$options.fields;
- },
- },
- mounted() {
- this.fetchVariables();
- },
- methods: {
- ...mapActions(['fetchVariables', 'toggleValues', 'editVariable']),
- },
-};
-</script>
-
-<template>
- <div class="ci-variable-table" data-testid="ci-variable-table">
- <gl-table
- :fields="fields"
- :items="variables"
- tbody-tr-class="js-ci-variable-row"
- data-qa-selector="ci_variable_table_content"
- sort-by="key"
- sort-direction="asc"
- stacked="lg"
- table-class="text-secondary"
- fixed
- show-empty
- sort-icon-left
- no-sort-reset
- >
- <template #table-colgroup="scope">
- <col v-for="field in scope.fields" :key="field.key" :style="field.customStyle" />
- </template>
- <template #cell(key)="{ item }">
- <div class="gl-display-flex gl-align-items-center">
- <tooltip-on-truncate :title="item.key" truncate-target="child">
- <span
- :id="`ci-variable-key-${item.id}`"
- class="gl-display-inline-block gl-max-w-full gl-text-truncate"
- >{{ item.key }}</span
- >
- </tooltip-on-truncate>
- <gl-button
- v-gl-tooltip
- category="tertiary"
- icon="copy-to-clipboard"
- :title="__('Copy key')"
- :data-clipboard-text="item.key"
- :aria-label="__('Copy to clipboard')"
- />
- </div>
- </template>
- <template #cell(value)="{ item }">
- <div class="gl-display-flex gl-align-items-center">
- <span v-if="valuesHidden">*********************</span>
- <span
- v-else
- :id="`ci-variable-value-${item.id}`"
- class="gl-display-inline-block gl-max-w-full gl-text-truncate"
- >{{ item.value }}</span
- >
- <gl-button
- v-gl-tooltip
- category="tertiary"
- icon="copy-to-clipboard"
- :title="__('Copy value')"
- :data-clipboard-text="item.value"
- :aria-label="__('Copy to clipboard')"
- />
- </div>
- </template>
- <template #cell(protected)="{ item }">
- <gl-icon v-if="item.protected" :size="$options.iconSize" :name="$options.trueIcon" />
- <gl-icon v-else :size="$options.iconSize" :name="$options.falseIcon" />
- </template>
- <template #cell(masked)="{ item }">
- <gl-icon v-if="item.masked" :size="$options.iconSize" :name="$options.trueIcon" />
- <gl-icon v-else :size="$options.iconSize" :name="$options.falseIcon" />
- </template>
- <template #cell(environment_scope)="{ item }">
- <div class="gl-display-flex">
- <span
- :id="`ci-variable-env-${item.id}`"
- class="gl-display-inline-block gl-max-w-full gl-text-truncate"
- >{{ item.environment_scope }}</span
- >
- <ci-variable-popover
- :target="`ci-variable-env-${item.id}`"
- :value="item.environment_scope"
- :tooltip-text="__('Copy environment')"
- />
- </div>
- </template>
- <template #cell(actions)="{ item }">
- <gl-button
- v-gl-modal-directive="$options.modalId"
- icon="pencil"
- :aria-label="__('Edit')"
- data-qa-selector="edit_ci_variable_button"
- @click="editVariable(item)"
- />
- </template>
- <template #empty>
- <p class="gl-text-center gl-py-6 gl-text-black-normal gl-mb-0">
- {{ __('There are no variables yet.') }}
- </p>
- </template>
- </gl-table>
- <div class="ci-variable-actions gl-display-flex gl-mt-5">
- <gl-button
- v-gl-modal-directive="$options.modalId"
- class="gl-mr-3"
- data-qa-selector="add_ci_variable_button"
- variant="confirm"
- category="primary"
- >{{ __('Add variable') }}</gl-button
- >
- <gl-button
- v-if="!isTableEmpty"
- data-qa-selector="reveal_ci_variable_value_button"
- @click="toggleValues(!valuesHidden)"
- >{{ valuesButtonText }}</gl-button
- >
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/admin_add_variable.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/admin_add_variable.mutation.graphql
index eba4b0c32f8..9208c34f154 100644
--- a/app/assets/javascripts/ci_variable_list/graphql/mutations/admin_add_variable.mutation.graphql
+++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/admin_add_variable.mutation.graphql
@@ -1,7 +1,7 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
mutation addAdminVariable($variable: CiVariable!, $endpoint: String!) {
- addAdminVariable(variable: $variable, endpoint: $endpoint) @client {
+ ciVariableMutation: addAdminVariable(variable: $variable, endpoint: $endpoint) @client {
ciVariables {
nodes {
...BaseCiVariable
diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/admin_delete_variable.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/admin_delete_variable.mutation.graphql
index 96eb8c794bc..a79b98f5e95 100644
--- a/app/assets/javascripts/ci_variable_list/graphql/mutations/admin_delete_variable.mutation.graphql
+++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/admin_delete_variable.mutation.graphql
@@ -1,7 +1,7 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
mutation deleteAdminVariable($variable: CiVariable!, $endpoint: String!) {
- deleteAdminVariable(variable: $variable, endpoint: $endpoint) @client {
+ ciVariableMutation: deleteAdminVariable(variable: $variable, endpoint: $endpoint) @client {
ciVariables {
nodes {
...BaseCiVariable
diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/admin_update_variable.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/admin_update_variable.mutation.graphql
index c0388507bb8..ddea753bf90 100644
--- a/app/assets/javascripts/ci_variable_list/graphql/mutations/admin_update_variable.mutation.graphql
+++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/admin_update_variable.mutation.graphql
@@ -1,7 +1,7 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
mutation updateAdminVariable($variable: CiVariable!, $endpoint: String!) {
- updateAdminVariable(variable: $variable, endpoint: $endpoint) @client {
+ ciVariableMutation: updateAdminVariable(variable: $variable, endpoint: $endpoint) @client {
ciVariables {
nodes {
...BaseCiVariable
diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/group_add_variable.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/group_add_variable.mutation.graphql
index f8e4dc55fa4..c44ee2ecc1d 100644
--- a/app/assets/javascripts/ci_variable_list/graphql/mutations/group_add_variable.mutation.graphql
+++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/group_add_variable.mutation.graphql
@@ -1,16 +1,11 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
-mutation addGroupVariable(
- $variable: CiVariable!
- $endpoint: String!
- $fullPath: ID!
- $groupId: ID!
-) {
- addGroupVariable(
+mutation addGroupVariable($variable: CiVariable!, $endpoint: String!, $fullPath: ID!, $id: ID!) {
+ ciVariableMutation: addGroupVariable(
variable: $variable
endpoint: $endpoint
fullPath: $fullPath
- groupId: $groupId
+ id: $id
) @client {
group {
id
diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/group_delete_variable.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/group_delete_variable.mutation.graphql
index 310e4a6e551..53e9b411dd2 100644
--- a/app/assets/javascripts/ci_variable_list/graphql/mutations/group_delete_variable.mutation.graphql
+++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/group_delete_variable.mutation.graphql
@@ -1,16 +1,11 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
-mutation deleteGroupVariable(
- $variable: CiVariable!
- $endpoint: String!
- $fullPath: ID!
- $groupId: ID!
-) {
- deleteGroupVariable(
+mutation deleteGroupVariable($variable: CiVariable!, $endpoint: String!, $fullPath: ID!, $id: ID!) {
+ ciVariableMutation: deleteGroupVariable(
variable: $variable
endpoint: $endpoint
fullPath: $fullPath
- groupId: $groupId
+ id: $id
) @client {
group {
id
diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/group_update_variable.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/group_update_variable.mutation.graphql
index 5291942eb87..2dddca14bd8 100644
--- a/app/assets/javascripts/ci_variable_list/graphql/mutations/group_update_variable.mutation.graphql
+++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/group_update_variable.mutation.graphql
@@ -1,16 +1,11 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
-mutation updateGroupVariable(
- $variable: CiVariable!
- $endpoint: String!
- $fullPath: ID!
- $groupId: ID!
-) {
- updateGroupVariable(
+mutation updateGroupVariable($variable: CiVariable!, $endpoint: String!, $fullPath: ID!, $id: ID!) {
+ ciVariableMutation: updateGroupVariable(
variable: $variable
endpoint: $endpoint
fullPath: $fullPath
- groupId: $groupId
+ id: $id
) @client {
group {
id
diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/project_add_variable.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/project_add_variable.mutation.graphql
index ab3a46da854..39504770e33 100644
--- a/app/assets/javascripts/ci_variable_list/graphql/mutations/project_add_variable.mutation.graphql
+++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/project_add_variable.mutation.graphql
@@ -1,16 +1,11 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
-mutation addProjectVariable(
- $variable: CiVariable!
- $endpoint: String!
- $fullPath: ID!
- $projectId: ID!
-) {
- addProjectVariable(
+mutation addProjectVariable($variable: CiVariable!, $endpoint: String!, $fullPath: ID!, $id: ID!) {
+ ciVariableMutation: addProjectVariable(
variable: $variable
endpoint: $endpoint
fullPath: $fullPath
- projectId: $projectId
+ id: $id
) @client {
project {
id
diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/project_delete_variable.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/project_delete_variable.mutation.graphql
index e83dc9a5e5e..f55c255e332 100644
--- a/app/assets/javascripts/ci_variable_list/graphql/mutations/project_delete_variable.mutation.graphql
+++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/project_delete_variable.mutation.graphql
@@ -4,13 +4,13 @@ mutation deleteProjectVariable(
$variable: CiVariable!
$endpoint: String!
$fullPath: ID!
- $projectId: ID!
+ $id: ID!
) {
- deleteProjectVariable(
+ ciVariableMutation: deleteProjectVariable(
variable: $variable
endpoint: $endpoint
fullPath: $fullPath
- projectId: $projectId
+ id: $id
) @client {
project {
id
diff --git a/app/assets/javascripts/ci_variable_list/graphql/mutations/project_update_variable.mutation.graphql b/app/assets/javascripts/ci_variable_list/graphql/mutations/project_update_variable.mutation.graphql
index 4788911431b..fc589e8a939 100644
--- a/app/assets/javascripts/ci_variable_list/graphql/mutations/project_update_variable.mutation.graphql
+++ b/app/assets/javascripts/ci_variable_list/graphql/mutations/project_update_variable.mutation.graphql
@@ -4,13 +4,13 @@ mutation updateProjectVariable(
$variable: CiVariable!
$endpoint: String!
$fullPath: ID!
- $projectId: ID!
+ $id: ID!
) {
- updateProjectVariable(
+ ciVariableMutation: updateProjectVariable(
variable: $variable
endpoint: $endpoint
fullPath: $fullPath
- projectId: $projectId
+ id: $id
) @client {
project {
id
diff --git a/app/assets/javascripts/ci_variable_list/graphql/settings.js b/app/assets/javascripts/ci_variable_list/graphql/settings.js
index ecdc4f220bd..02f6c226b0f 100644
--- a/app/assets/javascripts/ci_variable_list/graphql/settings.js
+++ b/app/assets/javascripts/ci_variable_list/graphql/settings.js
@@ -36,12 +36,12 @@ const mapVariableTypes = (variables = [], kind) => {
});
};
-const prepareProjectGraphQLResponse = ({ data, projectId, errors = [] }) => {
+const prepareProjectGraphQLResponse = ({ data, id, errors = [] }) => {
return {
errors,
project: {
__typename: GRAPHQL_PROJECT_TYPE,
- id: convertToGraphQLId(GRAPHQL_PROJECT_TYPE, projectId),
+ id: convertToGraphQLId(GRAPHQL_PROJECT_TYPE, id),
ciVariables: {
__typename: `Ci${GRAPHQL_PROJECT_TYPE}VariableConnection`,
pageInfo: {
@@ -57,12 +57,12 @@ const prepareProjectGraphQLResponse = ({ data, projectId, errors = [] }) => {
};
};
-const prepareGroupGraphQLResponse = ({ data, groupId, errors = [] }) => {
+const prepareGroupGraphQLResponse = ({ data, id, errors = [] }) => {
return {
errors,
group: {
__typename: GRAPHQL_GROUP_TYPE,
- id: convertToGraphQLId(GRAPHQL_GROUP_TYPE, groupId),
+ id: convertToGraphQLId(GRAPHQL_GROUP_TYPE, id),
ciVariables: {
__typename: `Ci${GRAPHQL_GROUP_TYPE}VariableConnection`,
pageInfo: {
@@ -95,20 +95,13 @@ const prepareAdminGraphQLResponse = ({ data, errors = [] }) => {
};
};
-async function callProjectEndpoint({
- endpoint,
- fullPath,
- variable,
- projectId,
- cache,
- destroy = false,
-}) {
+async function callProjectEndpoint({ endpoint, fullPath, variable, id, cache, destroy = false }) {
try {
const { data } = await axios.patch(endpoint, {
variables_attributes: [prepareVariableForApi({ variable, destroy })],
});
- const graphqlData = prepareProjectGraphQLResponse({ data, projectId });
+ const graphqlData = prepareProjectGraphQLResponse({ data, id });
cache.writeQuery({
query: getProjectVariables,
@@ -122,26 +115,19 @@ async function callProjectEndpoint({
} catch (e) {
return prepareProjectGraphQLResponse({
data: cache.readQuery({ query: getProjectVariables, variables: { fullPath } }),
- projectId,
+ id,
errors: [...e.response.data],
});
}
}
-const callGroupEndpoint = async ({
- endpoint,
- fullPath,
- variable,
- groupId,
- cache,
- destroy = false,
-}) => {
+const callGroupEndpoint = async ({ endpoint, fullPath, variable, id, cache, destroy = false }) => {
try {
const { data } = await axios.patch(endpoint, {
variables_attributes: [prepareVariableForApi({ variable, destroy })],
});
- const graphqlData = prepareGroupGraphQLResponse({ data, groupId });
+ const graphqlData = prepareGroupGraphQLResponse({ data, id });
cache.writeQuery({
query: getGroupVariables,
@@ -152,7 +138,7 @@ const callGroupEndpoint = async ({
} catch (e) {
return prepareGroupGraphQLResponse({
data: cache.readQuery({ query: getGroupVariables, variables: { fullPath } }),
- groupId,
+ id,
errors: [...e.response.data],
});
}
@@ -182,23 +168,23 @@ const callAdminEndpoint = async ({ endpoint, variable, cache, destroy = false })
export const resolvers = {
Mutation: {
- addProjectVariable: async (_, { endpoint, fullPath, variable, projectId }, { cache }) => {
- return callProjectEndpoint({ endpoint, fullPath, variable, projectId, cache });
+ addProjectVariable: async (_, { endpoint, fullPath, variable, id }, { cache }) => {
+ return callProjectEndpoint({ endpoint, fullPath, variable, id, cache });
},
- updateProjectVariable: async (_, { endpoint, fullPath, variable, projectId }, { cache }) => {
- return callProjectEndpoint({ endpoint, fullPath, variable, projectId, cache });
+ updateProjectVariable: async (_, { endpoint, fullPath, variable, id }, { cache }) => {
+ return callProjectEndpoint({ endpoint, fullPath, variable, id, cache });
},
- deleteProjectVariable: async (_, { endpoint, fullPath, variable, projectId }, { cache }) => {
- return callProjectEndpoint({ endpoint, fullPath, variable, projectId, cache, destroy: true });
+ deleteProjectVariable: async (_, { endpoint, fullPath, variable, id }, { cache }) => {
+ return callProjectEndpoint({ endpoint, fullPath, variable, id, cache, destroy: true });
},
- addGroupVariable: async (_, { endpoint, fullPath, variable, groupId }, { cache }) => {
- return callGroupEndpoint({ endpoint, fullPath, variable, groupId, cache });
+ addGroupVariable: async (_, { endpoint, fullPath, variable, id }, { cache }) => {
+ return callGroupEndpoint({ endpoint, fullPath, variable, id, cache });
},
- updateGroupVariable: async (_, { endpoint, fullPath, variable, groupId }, { cache }) => {
- return callGroupEndpoint({ endpoint, fullPath, variable, groupId, cache });
+ updateGroupVariable: async (_, { endpoint, fullPath, variable, id }, { cache }) => {
+ return callGroupEndpoint({ endpoint, fullPath, variable, id, cache });
},
- deleteGroupVariable: async (_, { endpoint, fullPath, variable, groupId }, { cache }) => {
- return callGroupEndpoint({ endpoint, fullPath, variable, groupId, cache, destroy: true });
+ deleteGroupVariable: async (_, { endpoint, fullPath, variable, id }, { cache }) => {
+ return callGroupEndpoint({ endpoint, fullPath, variable, id, cache, destroy: true });
},
addAdminVariable: async (_, { endpoint, variable }, { cache }) => {
return callAdminEndpoint({ endpoint, variable, cache });
@@ -238,7 +224,7 @@ export const cacheConfig = {
Project: {
fields: {
ciVariables: {
- keyArgs: ['fullPath', 'endpoint', 'projectId'],
+ keyArgs: ['fullPath', 'endpoint', 'id'],
merge: mergeVariables,
},
},
diff --git a/app/assets/javascripts/ci_variable_list/index.js b/app/assets/javascripts/ci_variable_list/index.js
index 1b69da9e086..174a59aba42 100644
--- a/app/assets/javascripts/ci_variable_list/index.js
+++ b/app/assets/javascripts/ci_variable_list/index.js
@@ -5,9 +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 LegacyCiVariableSettings from './components/legacy_ci_variable_settings.vue';
import { cacheConfig, resolvers } from './graphql/settings';
-import createStore from './store';
const mountCiVariableListApp = (containerEl) => {
const {
@@ -76,62 +74,10 @@ const mountCiVariableListApp = (containerEl) => {
});
};
-const mountLegacyCiVariableListApp = (containerEl) => {
- const {
- endpoint,
- projectId,
- isGroup,
- isProject,
- maskableRegex,
- protectedByDefault,
- awsLogoSvgPath,
- awsTipDeployLink,
- awsTipCommandsLink,
- awsTipLearnLink,
- containsVariableReferenceLink,
- protectedEnvironmentVariablesLink,
- maskedEnvironmentVariablesLink,
- environmentScopeLink,
- } = containerEl.dataset;
-
- const parsedIsProject = parseBoolean(isProject);
- const parsedIsGroup = parseBoolean(isGroup);
- const isProtectedByDefault = parseBoolean(protectedByDefault);
-
- const store = createStore({
- endpoint,
- projectId,
- isGroup: parsedIsGroup,
- isProject: parsedIsProject,
- maskableRegex,
- isProtectedByDefault,
- awsLogoSvgPath,
- awsTipDeployLink,
- awsTipCommandsLink,
- awsTipLearnLink,
- containsVariableReferenceLink,
- protectedEnvironmentVariablesLink,
- maskedEnvironmentVariablesLink,
- environmentScopeLink,
- });
-
- return new Vue({
- el: containerEl,
- store,
- render(createElement) {
- return createElement(LegacyCiVariableSettings);
- },
- });
-};
-
-export default (containerId = 'js-ci-project-variables') => {
+export default (containerId = 'js-ci-variables') => {
const el = document.getElementById(containerId);
- if (el) {
- if (gon.features?.ciVariableSettingsGraphql) {
- mountCiVariableListApp(el);
- } else {
- mountLegacyCiVariableListApp(el);
- }
- }
+ if (!el) return;
+
+ mountCiVariableListApp(el);
};
diff --git a/app/assets/javascripts/ci_variable_list/store/actions.js b/app/assets/javascripts/ci_variable_list/store/actions.js
deleted file mode 100644
index ac31e845b0d..00000000000
--- a/app/assets/javascripts/ci_variable_list/store/actions.js
+++ /dev/null
@@ -1,208 +0,0 @@
-import Api from '~/api';
-import { createAlert } from '~/flash';
-import axios from '~/lib/utils/axios_utils';
-import { __ } from '~/locale';
-import * as types from './mutation_types';
-import { prepareDataForApi, prepareDataForDisplay, prepareEnvironments } from './utils';
-
-export const toggleValues = ({ commit }, valueState) => {
- commit(types.TOGGLE_VALUES, valueState);
-};
-
-export const clearModal = ({ commit }) => {
- commit(types.CLEAR_MODAL);
-};
-
-export const resetEditing = ({ commit, dispatch }) => {
- // fetch variables again if modal is being edited and then hidden
- // without saving changes, to cover use case of reactivity in the table
- dispatch('fetchVariables');
- commit(types.RESET_EDITING);
-};
-
-export const setVariableProtected = ({ commit }) => {
- commit(types.SET_VARIABLE_PROTECTED);
-};
-
-export const requestAddVariable = ({ commit }) => {
- commit(types.REQUEST_ADD_VARIABLE);
-};
-
-export const receiveAddVariableSuccess = ({ commit }) => {
- commit(types.RECEIVE_ADD_VARIABLE_SUCCESS);
-};
-
-export const receiveAddVariableError = ({ commit }, error) => {
- commit(types.RECEIVE_ADD_VARIABLE_ERROR, error);
-};
-
-export const addVariable = ({ state, dispatch }) => {
- dispatch('requestAddVariable');
-
- return axios
- .patch(state.endpoint, {
- variables_attributes: [prepareDataForApi(state.variable)],
- })
- .then(() => {
- dispatch('receiveAddVariableSuccess');
- dispatch('fetchVariables');
- })
- .catch((error) => {
- createAlert({
- message: error.response.data[0],
- });
- dispatch('receiveAddVariableError', error);
- });
-};
-
-export const requestUpdateVariable = ({ commit }) => {
- commit(types.REQUEST_UPDATE_VARIABLE);
-};
-
-export const receiveUpdateVariableSuccess = ({ commit }) => {
- commit(types.RECEIVE_UPDATE_VARIABLE_SUCCESS);
-};
-
-export const receiveUpdateVariableError = ({ commit }, error) => {
- commit(types.RECEIVE_UPDATE_VARIABLE_ERROR, error);
-};
-
-export const updateVariable = ({ state, dispatch }) => {
- dispatch('requestUpdateVariable');
-
- const updatedVariable = prepareDataForApi(state.variable);
- updatedVariable.secrect_value = updateVariable.value;
-
- return axios
- .patch(state.endpoint, { variables_attributes: [updatedVariable] })
- .then(() => {
- dispatch('receiveUpdateVariableSuccess');
- dispatch('fetchVariables');
- })
- .catch((error) => {
- createAlert({
- message: error.response.data[0],
- });
- dispatch('receiveUpdateVariableError', error);
- });
-};
-
-export const editVariable = ({ commit }, variable) => {
- const variableToEdit = variable;
- variableToEdit.secret_value = variableToEdit.value;
- commit(types.VARIABLE_BEING_EDITED, variableToEdit);
-};
-
-export const requestVariables = ({ commit }) => {
- commit(types.REQUEST_VARIABLES);
-};
-export const receiveVariablesSuccess = ({ commit }, variables) => {
- commit(types.RECEIVE_VARIABLES_SUCCESS, variables);
-};
-
-export const fetchVariables = ({ dispatch, state }) => {
- dispatch('requestVariables');
-
- return axios
- .get(state.endpoint)
- .then(({ data }) => {
- dispatch('receiveVariablesSuccess', prepareDataForDisplay(data.variables));
- })
- .catch(() => {
- createAlert({
- message: __('There was an error fetching the variables.'),
- });
- });
-};
-
-export const requestDeleteVariable = ({ commit }) => {
- commit(types.REQUEST_DELETE_VARIABLE);
-};
-
-export const receiveDeleteVariableSuccess = ({ commit }) => {
- commit(types.RECEIVE_DELETE_VARIABLE_SUCCESS);
-};
-
-export const receiveDeleteVariableError = ({ commit }, error) => {
- commit(types.RECEIVE_DELETE_VARIABLE_ERROR, error);
-};
-
-export const deleteVariable = ({ dispatch, state }) => {
- dispatch('requestDeleteVariable');
-
- const destroy = true;
-
- return axios
- .patch(state.endpoint, { variables_attributes: [prepareDataForApi(state.variable, destroy)] })
- .then(() => {
- dispatch('receiveDeleteVariableSuccess');
- dispatch('fetchVariables');
- })
- .catch((error) => {
- createAlert({
- message: error.response.data[0],
- });
- dispatch('receiveDeleteVariableError', error);
- });
-};
-
-export const requestEnvironments = ({ commit }) => {
- commit(types.REQUEST_ENVIRONMENTS);
-};
-
-export const receiveEnvironmentsSuccess = ({ commit }, environments) => {
- commit(types.RECEIVE_ENVIRONMENTS_SUCCESS, environments);
-};
-
-export const fetchEnvironments = ({ dispatch, state }) => {
- dispatch('requestEnvironments');
-
- return Api.environments(state.projectId)
- .then((res) => {
- dispatch('receiveEnvironmentsSuccess', prepareEnvironments(res.data));
- })
- .catch(() => {
- createAlert({
- message: __('There was an error fetching the environments information.'),
- });
- });
-};
-
-export const setEnvironmentScope = ({ commit, dispatch }, environment) => {
- commit(types.SET_ENVIRONMENT_SCOPE, environment);
- dispatch('setSelectedEnvironment', environment);
-};
-
-export const addWildCardScope = ({ commit, dispatch }, environment) => {
- commit(types.ADD_WILD_CARD_SCOPE, environment);
- commit(types.SET_ENVIRONMENT_SCOPE, environment);
- dispatch('setSelectedEnvironment', environment);
-};
-
-export const resetSelectedEnvironment = ({ commit }) => {
- commit(types.RESET_SELECTED_ENVIRONMENT);
-};
-
-export const setSelectedEnvironment = ({ commit }, environment) => {
- commit(types.SET_SELECTED_ENVIRONMENT, environment);
-};
-
-export const updateVariableKey = ({ commit }, { key }) => {
- commit(types.UPDATE_VARIABLE_KEY, key);
-};
-
-export const updateVariableValue = ({ commit }, { secret_value }) => {
- commit(types.UPDATE_VARIABLE_VALUE, secret_value);
-};
-
-export const updateVariableType = ({ commit }, { variable_type }) => {
- commit(types.UPDATE_VARIABLE_TYPE, variable_type);
-};
-
-export const updateVariableProtected = ({ commit }, { protected_variable }) => {
- commit(types.UPDATE_VARIABLE_PROTECTED, protected_variable);
-};
-
-export const updateVariableMasked = ({ commit }, { masked }) => {
- commit(types.UPDATE_VARIABLE_MASKED, masked);
-};
diff --git a/app/assets/javascripts/ci_variable_list/store/getters.js b/app/assets/javascripts/ci_variable_list/store/getters.js
deleted file mode 100644
index 6570f455541..00000000000
--- a/app/assets/javascripts/ci_variable_list/store/getters.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import { uniq } from 'lodash';
-
-export const joinedEnvironments = (state) => {
- const scopesFromVariables = (state.variables || []).map((variable) => variable.environment_scope);
- return uniq(state.environments.concat(scopesFromVariables)).sort();
-};
diff --git a/app/assets/javascripts/ci_variable_list/store/index.js b/app/assets/javascripts/ci_variable_list/store/index.js
deleted file mode 100644
index 83802f6a36f..00000000000
--- a/app/assets/javascripts/ci_variable_list/store/index.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import Vue from 'vue';
-import Vuex from 'vuex';
-import * as actions from './actions';
-import * as getters from './getters';
-import mutations from './mutations';
-import state from './state';
-
-Vue.use(Vuex);
-
-export default (initialState = {}) =>
- new Vuex.Store({
- actions,
- mutations,
- getters,
- state: {
- ...state(),
- ...initialState,
- },
- });
diff --git a/app/assets/javascripts/ci_variable_list/store/mutation_types.js b/app/assets/javascripts/ci_variable_list/store/mutation_types.js
deleted file mode 100644
index 5db8f610192..00000000000
--- a/app/assets/javascripts/ci_variable_list/store/mutation_types.js
+++ /dev/null
@@ -1,33 +0,0 @@
-export const TOGGLE_VALUES = 'TOGGLE_VALUES';
-export const VARIABLE_BEING_EDITED = 'VARIABLE_BEING_EDITED';
-export const RESET_EDITING = 'RESET_EDITING';
-export const CLEAR_MODAL = 'CLEAR_MODAL';
-export const SET_VARIABLE_PROTECTED = 'SET_VARIABLE_PROTECTED';
-
-export const REQUEST_VARIABLES = 'REQUEST_VARIABLES';
-export const RECEIVE_VARIABLES_SUCCESS = 'RECEIVE_VARIABLES_SUCCESS';
-
-export const REQUEST_DELETE_VARIABLE = 'REQUEST_DELETE_VARIABLE';
-export const RECEIVE_DELETE_VARIABLE_SUCCESS = 'RECEIVE_DELETE_VARIABLE_SUCCESS';
-export const RECEIVE_DELETE_VARIABLE_ERROR = 'RECEIVE_DELETE_VARIABLE_ERROR';
-
-export const REQUEST_ADD_VARIABLE = 'REQUEST_ADD_VARIABLE';
-export const RECEIVE_ADD_VARIABLE_SUCCESS = 'RECEIVE_ADD_VARIABLE_SUCCESS';
-export const RECEIVE_ADD_VARIABLE_ERROR = 'RECEIVE_ADD_VARIABLE_ERROR';
-
-export const REQUEST_UPDATE_VARIABLE = 'REQUEST_UPDATE_VARIABLE';
-export const RECEIVE_UPDATE_VARIABLE_SUCCESS = 'RECEIVE_UPDATE_VARIABLE_SUCCESS';
-export const RECEIVE_UPDATE_VARIABLE_ERROR = 'RECEIVE_UPDATE_VARIABLE_ERROR';
-
-export const REQUEST_ENVIRONMENTS = 'REQUEST_ENVIRONMENTS';
-export const RECEIVE_ENVIRONMENTS_SUCCESS = 'RECEIVE_ENVIRONMENTS_SUCCESS';
-export const SET_ENVIRONMENT_SCOPE = 'SET_ENVIRONMENT_SCOPE';
-export const ADD_WILD_CARD_SCOPE = 'ADD_WILD_CARD_SCOPE';
-export const RESET_SELECTED_ENVIRONMENT = 'RESET_SELECTED_ENVIRONMENT';
-export const SET_SELECTED_ENVIRONMENT = 'SET_SELECTED_ENVIRONMENT';
-
-export const UPDATE_VARIABLE_KEY = 'UPDATE_VARIABLE_KEY';
-export const UPDATE_VARIABLE_VALUE = 'UPDATE_VARIABLE_VALUE';
-export const UPDATE_VARIABLE_TYPE = 'UPDATE_VARIABLE_TYPE';
-export const UPDATE_VARIABLE_PROTECTED = 'UPDATE_VARIABLE_PROTECTED';
-export const UPDATE_VARIABLE_MASKED = 'UPDATE_VARIABLE_MASKED';
diff --git a/app/assets/javascripts/ci_variable_list/store/mutations.js b/app/assets/javascripts/ci_variable_list/store/mutations.js
deleted file mode 100644
index 0e7c61cecb8..00000000000
--- a/app/assets/javascripts/ci_variable_list/store/mutations.js
+++ /dev/null
@@ -1,128 +0,0 @@
-import { displayText } from '../constants';
-import * as types from './mutation_types';
-
-export default {
- [types.REQUEST_VARIABLES](state) {
- state.isLoading = true;
- },
-
- [types.RECEIVE_VARIABLES_SUCCESS](state, variables) {
- state.isLoading = false;
- state.variables = variables;
- },
-
- [types.REQUEST_DELETE_VARIABLE](state) {
- state.isDeleting = true;
- },
-
- [types.RECEIVE_DELETE_VARIABLE_SUCCESS](state) {
- state.isDeleting = false;
- },
-
- [types.RECEIVE_DELETE_VARIABLE_ERROR](state, error) {
- state.isDeleting = false;
- state.error = error;
- },
-
- [types.REQUEST_ADD_VARIABLE](state) {
- state.isLoading = true;
- },
-
- [types.RECEIVE_ADD_VARIABLE_SUCCESS](state) {
- state.isLoading = false;
- },
-
- [types.RECEIVE_ADD_VARIABLE_ERROR](state, error) {
- state.isLoading = false;
- state.error = error;
- },
-
- [types.REQUEST_UPDATE_VARIABLE](state) {
- state.isLoading = true;
- },
-
- [types.RECEIVE_UPDATE_VARIABLE_SUCCESS](state) {
- state.isLoading = false;
- },
-
- [types.RECEIVE_UPDATE_VARIABLE_ERROR](state, error) {
- state.isLoading = false;
- state.error = error;
- },
-
- [types.TOGGLE_VALUES](state, valueState) {
- state.valuesHidden = valueState;
- },
-
- [types.REQUEST_ENVIRONMENTS](state) {
- state.isLoading = true;
- },
-
- [types.RECEIVE_ENVIRONMENTS_SUCCESS](state, environments) {
- state.isLoading = false;
- state.environments = environments;
- state.environments.unshift(displayText.allEnvironmentsText);
- },
-
- [types.VARIABLE_BEING_EDITED](state, variable) {
- state.variableBeingEdited = true;
- state.variable = variable;
- },
-
- [types.CLEAR_MODAL](state) {
- state.variable = {
- variable_type: displayText.variableText,
- key: '',
- secret_value: '',
- protected_variable: false,
- masked: false,
- environment_scope: displayText.allEnvironmentsText,
- };
- },
-
- [types.RESET_EDITING](state) {
- state.variableBeingEdited = false;
- state.showInputValue = false;
- },
-
- [types.SET_ENVIRONMENT_SCOPE](state, environment) {
- state.variable.environment_scope = environment;
- },
-
- [types.ADD_WILD_CARD_SCOPE](state, environment) {
- state.environments.push(environment);
- state.environments.sort();
- },
-
- [types.RESET_SELECTED_ENVIRONMENT](state) {
- state.selectedEnvironment = '';
- },
-
- [types.SET_SELECTED_ENVIRONMENT](state, environment) {
- state.selectedEnvironment = environment;
- },
-
- [types.SET_VARIABLE_PROTECTED](state) {
- state.variable.protected_variable = true;
- },
-
- [types.UPDATE_VARIABLE_KEY](state, key) {
- state.variable.key = key;
- },
-
- [types.UPDATE_VARIABLE_VALUE](state, value) {
- state.variable.secret_value = value;
- },
-
- [types.UPDATE_VARIABLE_TYPE](state, type) {
- state.variable.variable_type = type;
- },
-
- [types.UPDATE_VARIABLE_PROTECTED](state, bool) {
- state.variable.protected_variable = bool;
- },
-
- [types.UPDATE_VARIABLE_MASKED](state, bool) {
- state.variable.masked = bool;
- },
-};
diff --git a/app/assets/javascripts/ci_variable_list/store/state.js b/app/assets/javascripts/ci_variable_list/store/state.js
deleted file mode 100644
index 96b27792664..00000000000
--- a/app/assets/javascripts/ci_variable_list/store/state.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import { displayText } from '../constants';
-
-export default () => ({
- endpoint: null,
- projectId: null,
- isGroup: null,
- maskableRegex: null,
- isProtectedByDefault: null,
- isLoading: false,
- isDeleting: false,
- variable: {
- variable_type: displayText.variableText,
- key: '',
- secret_value: '',
- protected_variable: false,
- masked: false,
- environment_scope: displayText.allEnvironmentsText,
- },
- variables: null,
- valuesHidden: true,
- error: null,
- environments: [],
- typeOptions: [displayText.variableText, displayText.fileText],
- variableBeingEdited: false,
- selectedEnvironment: '',
-});
diff --git a/app/assets/javascripts/ci_variable_list/store/utils.js b/app/assets/javascripts/ci_variable_list/store/utils.js
deleted file mode 100644
index f46a671ae7b..00000000000
--- a/app/assets/javascripts/ci_variable_list/store/utils.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import { cloneDeep } from 'lodash';
-import { displayText, types, allEnvironments } from '../constants';
-
-const variableTypeHandler = (type) =>
- type === displayText.variableText ? types.variableType : types.fileType;
-
-export const prepareDataForDisplay = (variables) => {
- const variablesToDisplay = [];
- variables.forEach((variable) => {
- const variableCopy = variable;
- if (variableCopy.variable_type === types.variableType) {
- variableCopy.variable_type = displayText.variableText;
- } else {
- variableCopy.variable_type = displayText.fileText;
- }
- variableCopy.secret_value = variableCopy.value;
-
- if (variableCopy.environment_scope === allEnvironments.type) {
- variableCopy.environment_scope = displayText.allEnvironmentsText;
- }
- variableCopy.protected_variable = variableCopy.protected;
- variablesToDisplay.push(variableCopy);
- });
- return variablesToDisplay;
-};
-
-export const prepareDataForApi = (variable, destroy = false) => {
- const variableCopy = cloneDeep(variable);
- variableCopy.protected = variableCopy.protected_variable.toString();
- delete variableCopy.protected_variable;
- variableCopy.masked = variableCopy.masked.toString();
- variableCopy.variable_type = variableTypeHandler(variableCopy.variable_type);
- if (variableCopy.environment_scope === displayText.allEnvironmentsText) {
- variableCopy.environment_scope = allEnvironments.type;
- }
-
- if (destroy) {
- // eslint-disable-next-line
- variableCopy._destroy = destroy;
- }
-
- return variableCopy;
-};
-
-export const prepareEnvironments = (environments) => environments.map((e) => e.name);
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 6f2c353a67b..7a028858d10 100644
--- a/app/assets/javascripts/clusters_list/components/delete_agent_button.vue
+++ b/app/assets/javascripts/clusters_list/components/delete_agent_button.vue
@@ -92,6 +92,9 @@ export default {
disableModalSubmit() {
return this.deleteConfirmText !== this.agent.name;
},
+ containerTabIndex() {
+ return this.canAdminCluster ? -1 : 0;
+ },
},
methods: {
async deleteAgent() {
@@ -156,8 +159,8 @@ export default {
<div>
<div
v-gl-tooltip="deleteButtonTooltip"
- class="gl-display-inline-block"
- tabindex="-1"
+ :tabindex="containerTabIndex"
+ class="cluster-button-container gl-rounded-base gl-display-inline-block"
data-testid="delete-agent-button-tooltip"
>
<gl-button
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 327b0967229..354db88f11c 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
@@ -108,6 +108,16 @@ export default {
@execute="trackToolbarControlExecution"
/>
<toolbar-button
+ data-testid="highlight"
+ content-type="highlight"
+ icon-name="highlight"
+ editor-command="toggleHighlight"
+ category="tertiary"
+ size="medium"
+ :label="__('Highlight')"
+ @execute="trackToolbarControlExecution"
+ />
+ <toolbar-button
data-testid="link"
content-type="link"
icon-name="link"
diff --git a/app/assets/javascripts/content_editor/components/suggestions_dropdown.vue b/app/assets/javascripts/content_editor/components/suggestions_dropdown.vue
index 987b7044272..001b34a00fa 100644
--- a/app/assets/javascripts/content_editor/components/suggestions_dropdown.vue
+++ b/app/assets/javascripts/content_editor/components/suggestions_dropdown.vue
@@ -90,6 +90,9 @@ export default {
items() {
this.selectedIndex = 0;
},
+ selectedIndex() {
+ this.scrollIntoView();
+ },
},
methods: {
@@ -182,6 +185,10 @@ export default {
this.selectItem(this.selectedIndex);
},
+ scrollIntoView() {
+ this.$refs.dropdownItems[this.selectedIndex].$el.scrollIntoView({ block: 'nearest' });
+ },
+
selectItem(index) {
const item = this.items[index];
@@ -209,6 +216,7 @@ export default {
<div class="gl-new-dropdown-inner gl-overflow-y-auto">
<gl-dropdown-item
v-for="(item, index) in items"
+ ref="dropdownItems"
:key="index"
:class="{ 'gl-bg-gray-50': index === selectedIndex }"
@click="selectItem(index)"
diff --git a/app/assets/javascripts/content_editor/components/toolbar_button.vue b/app/assets/javascripts/content_editor/components/toolbar_button.vue
index c16dc34e36f..cef026c5bc6 100644
--- a/app/assets/javascripts/content_editor/components/toolbar_button.vue
+++ b/app/assets/javascripts/content_editor/components/toolbar_button.vue
@@ -32,7 +32,7 @@ export default {
editorCommandParams: {
type: Object,
required: false,
- default: null,
+ default: undefined,
},
variant: {
type: String,
diff --git a/app/assets/javascripts/content_editor/content_editor.stories.js b/app/assets/javascripts/content_editor/content_editor.stories.js
index 2d4226ccd33..9e1a4bfe361 100644
--- a/app/assets/javascripts/content_editor/content_editor.stories.js
+++ b/app/assets/javascripts/content_editor/content_editor.stories.js
@@ -11,7 +11,6 @@ const Template = (_, { argTypes }) => ({
template: '<content-editor v-bind="$props" @initialized="loadContent" />',
methods: {
loadContent(contentEditor) {
- // eslint-disable-next-line @gitlab/require-i18n-strings
contentEditor.setSerializedContent('Hello content editor');
},
},
diff --git a/app/assets/javascripts/content_editor/extensions/highlight.js b/app/assets/javascripts/content_editor/extensions/highlight.js
new file mode 100644
index 00000000000..b84388d6285
--- /dev/null
+++ b/app/assets/javascripts/content_editor/extensions/highlight.js
@@ -0,0 +1,19 @@
+import { markInputRule } from '@tiptap/core';
+import { Highlight } from '@tiptap/extension-highlight';
+import { markInputRegex, extractMarkAttributesFromMatch } from '../services/mark_utils';
+
+export default Highlight.extend({
+ addInputRules() {
+ return [
+ markInputRule({
+ find: markInputRegex('mark'),
+ type: this.type,
+ getAttributes: extractMarkAttributesFromMatch,
+ }),
+ ];
+ },
+
+ addPasteRules() {
+ return [];
+ },
+});
diff --git a/app/assets/javascripts/content_editor/extensions/html_marks.js b/app/assets/javascripts/content_editor/extensions/html_marks.js
index 9579f3b06f6..79fc0eea2c7 100644
--- a/app/assets/javascripts/content_editor/extensions/html_marks.js
+++ b/app/assets/javascripts/content_editor/extensions/html_marks.js
@@ -8,7 +8,6 @@ const marks = [
'bdo',
'cite',
'dfn',
- 'mark',
'small',
'span',
'time',
diff --git a/app/assets/javascripts/content_editor/extensions/suggestions.js b/app/assets/javascripts/content_editor/extensions/suggestions.js
index 8976b9cafee..a9628c78add 100644
--- a/app/assets/javascripts/content_editor/extensions/suggestions.js
+++ b/app/assets/javascripts/content_editor/extensions/suggestions.js
@@ -17,7 +17,7 @@ function createSuggestionPlugin({
char,
dataSource,
search,
- limit = Infinity,
+ limit = 15,
nodeType,
nodeProps = {},
}) {
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 0d78390e769..ba9ce705c62 100644
--- a/app/assets/javascripts/content_editor/services/create_content_editor.js
+++ b/app/assets/javascripts/content_editor/services/create_content_editor.js
@@ -29,6 +29,7 @@ import Gapcursor from '../extensions/gapcursor';
import HardBreak from '../extensions/hard_break';
import Heading from '../extensions/heading';
import History from '../extensions/history';
+import Highlight from '../extensions/highlight';
import HorizontalRule from '../extensions/horizontal_rule';
import HTMLMarks from '../extensions/html_marks';
import HTMLNodes from '../extensions/html_nodes';
@@ -118,6 +119,7 @@ export const createContentEditor = ({
HardBreak,
Heading,
History,
+ Highlight,
HorizontalRule,
...HTMLMarks,
...HTMLNodes,
diff --git a/app/assets/javascripts/content_editor/services/markdown_serializer.js b/app/assets/javascripts/content_editor/services/markdown_serializer.js
index c990f6cf0b3..958c27c281a 100644
--- a/app/assets/javascripts/content_editor/services/markdown_serializer.js
+++ b/app/assets/javascripts/content_editor/services/markdown_serializer.js
@@ -22,6 +22,7 @@ import Frontmatter from '../extensions/frontmatter';
import HardBreak from '../extensions/hard_break';
import Heading from '../extensions/heading';
import HorizontalRule from '../extensions/horizontal_rule';
+import Highlight from '../extensions/highlight';
import HTMLMarks from '../extensions/html_marks';
import HTMLNodes from '../extensions/html_nodes';
import Image from '../extensions/image';
@@ -78,6 +79,7 @@ const defaultSerializerConfig = {
[Code.name]: code,
[Subscript.name]: { open: '<sub>', close: '</sub>', mixable: true },
[Superscript.name]: { open: '<sup>', close: '</sup>', mixable: true },
+ [Highlight.name]: { open: '<mark>', close: '</mark>', mixable: true },
[InlineDiff.name]: {
mixable: true,
open(_, mark) {
diff --git a/app/assets/javascripts/cycle_analytics/components/filter_bar.vue b/app/assets/javascripts/cycle_analytics/components/filter_bar.vue
index 016fea354fe..0ad325a8523 100644
--- a/app/assets/javascripts/cycle_analytics/components/filter_bar.vue
+++ b/app/assets/javascripts/cycle_analytics/components/filter_bar.vue
@@ -1,9 +1,12 @@
<script>
import { mapActions, mapState } from 'vuex';
-import { __ } from '~/locale';
import {
OPERATOR_IS_ONLY,
DEFAULT_NONE_ANY,
+ TOKEN_TITLE_ASSIGNEE,
+ TOKEN_TITLE_AUTHOR,
+ TOKEN_TITLE_LABEL,
+ TOKEN_TITLE_MILESTONE,
} from '~/vue_shared/components/filtered_search_bar/constants';
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import {
@@ -43,7 +46,7 @@ export default {
return [
{
icon: 'clock',
- title: __('Milestone'),
+ title: TOKEN_TITLE_MILESTONE,
type: 'milestone',
token: MilestoneToken,
initialMilestones: this.milestonesData,
@@ -54,7 +57,7 @@ export default {
},
{
icon: 'labels',
- title: __('Label'),
+ title: TOKEN_TITLE_LABEL,
type: 'labels',
token: LabelToken,
defaultLabels: DEFAULT_NONE_ANY,
@@ -66,7 +69,7 @@ export default {
},
{
icon: 'pencil',
- title: __('Author'),
+ title: TOKEN_TITLE_AUTHOR,
type: 'author',
token: AuthorToken,
initialAuthors: this.authorsData,
@@ -76,7 +79,7 @@ export default {
},
{
icon: 'user',
- title: __('Assignees'),
+ title: TOKEN_TITLE_ASSIGNEE,
type: 'assignees',
token: AuthorToken,
initialAuthors: this.assigneesData,
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 639dd21bd7b..81d74c64124 100644
--- a/app/assets/javascripts/deploy_tokens/components/new_deploy_token.vue
+++ b/app/assets/javascripts/deploy_tokens/components/new_deploy_token.vue
@@ -109,10 +109,11 @@ export default {
writePackageRegistryHelp: s__(
'DeployTokens|Allows read and write access to the package registry.',
),
+ createTokenFailedAlert: s__('DeployTokens|Failed to create a new deployment token'),
},
computed: {
formattedExpiryDate() {
- return formatDate(this.expiresAt, 'yyyy-mm-dd');
+ return this.expiresAt ? formatDate(this.expiresAt, 'yyyy-mm-dd') : '';
},
newTokenCreatedMessage() {
return this.tokenType === 'group'
@@ -129,6 +130,9 @@ export default {
name: this.name,
read_repository: this.readRepository,
read_registry: this.readRegistry,
+ write_registry: this.writeRegistry,
+ read_package_registry: this.readPackageRegistry,
+ write_package_registry: this.writePackageRegistry,
username: this.username,
},
})
@@ -142,7 +146,8 @@ export default {
})
.catch((error) => {
createAlert({
- message: error.response.data.message,
+ message:
+ error?.response?.data?.message || this.$options.translations.createTokenFailedAlert,
});
});
},
@@ -228,13 +233,7 @@ export default {
:description="$options.translations.addTokenNameDescription"
label-for="deploy_token_name"
>
- <gl-form-input
- id="deploy_token_name"
- v-model="name"
- name="deploy_token_name"
- class="qa-deploy-token-name"
- data-qa-selector="deploy_token_name_field"
- />
+ <gl-form-input id="deploy_token_name" v-model="name" name="deploy_token_name" />
</gl-form-group>
<gl-form-group
:label="$options.translations.addTokenExpiryLabel"
diff --git a/app/assets/javascripts/design_management/pages/index.vue b/app/assets/javascripts/design_management/pages/index.vue
index fba73cd4bec..ab003fb2879 100644
--- a/app/assets/javascripts/design_management/pages/index.vue
+++ b/app/assets/javascripts/design_management/pages/index.vue
@@ -349,7 +349,7 @@ export default {
<template>
<div
data-testid="designs-root"
- class="gl-mt-5"
+ class="gl-mt-4"
@mouseenter="toggleOnPasteListener"
@mouseleave="toggleOffPasteListener"
>
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index bc49464a560..7bc75127876 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -471,8 +471,14 @@ export default {
},
fetchData(toggleTree = true) {
this.fetchDiffFilesMeta()
- .then(({ real_size = 0 }) => {
- this.diffFilesLength = parseInt(real_size, 10) || 0;
+ .then((data) => {
+ let realSize = 0;
+
+ if (data) {
+ realSize = data.real_size;
+ }
+
+ this.diffFilesLength = parseInt(realSize, 10) || 0;
if (toggleTree) {
this.setTreeDisplay();
}
diff --git a/app/assets/javascripts/diffs/components/diff_discussions.vue b/app/assets/javascripts/diffs/components/diff_discussions.vue
index 25d3bda147b..9e399a642d0 100644
--- a/app/assets/javascripts/diffs/components/diff_discussions.vue
+++ b/app/assets/javascripts/diffs/components/diff_discussions.vue
@@ -88,6 +88,7 @@ export default {
:discussions-by-diff-order="true"
:line="line"
:help-page-path="helpPagePath"
+ :should-scroll-to-note="false"
@noteDeleted="deleteNoteHandler"
>
<template v-if="renderAvatarBadge" #avatar-badge>
diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue
index 422bf52a1fa..8f041d1e670 100644
--- a/app/assets/javascripts/diffs/components/diff_file.vue
+++ b/app/assets/javascripts/diffs/components/diff_file.vue
@@ -393,7 +393,7 @@ export default {
v-else-if="conflictResolutionPath"
:message="
__(
- 'You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}.',
+ 'You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve them locally%{resolveLocallyEnd}.',
)
"
>
@@ -415,7 +415,7 @@ export default {
</gl-sprintf>
<gl-sprintf
v-else
- :message="__('You can %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}.')"
+ :message="__('You can %{resolveLocallyStart}resolve them locally%{resolveLocallyEnd}.')"
>
<template #resolveLocally="{ content }">
<gl-button
diff --git a/app/assets/javascripts/diffs/components/diff_row_utils.js b/app/assets/javascripts/diffs/components/diff_row_utils.js
index 7732badde34..479853caae3 100644
--- a/app/assets/javascripts/diffs/components/diff_row_utils.js
+++ b/app/assets/javascripts/diffs/components/diff_row_utils.js
@@ -57,21 +57,32 @@ export const classNameMapCell = ({ line, hll, isLoggedIn, isHover }) => {
export const addCommentTooltip = (line) => {
let tooltip;
- if (!line) return tooltip;
+ if (!line) {
+ return tooltip;
+ }
tooltip = __('Add a comment to this line or drag for multiple lines');
- const brokenSymlinks = line.commentsDisabled;
- if (brokenSymlinks) {
- if (brokenSymlinks.wasSymbolic || brokenSymlinks.isSymbolic) {
+ if (!line.problems) {
+ return tooltip;
+ }
+
+ const { brokenSymlink, brokenLineCode, fileOnlyMoved } = line.problems;
+
+ if (brokenSymlink) {
+ if (brokenSymlink.wasSymbolic || brokenSymlink.isSymbolic) {
tooltip = __(
- 'Commenting on symbolic links that replace or are replaced by files is currently not supported.',
+ 'Commenting on symbolic links that replace or are replaced by files is not supported',
);
- } else if (brokenSymlinks.wasReal || brokenSymlinks.isReal) {
+ } else if (brokenSymlink.wasReal || brokenSymlink.isReal) {
tooltip = __(
- 'Commenting on files that replace or are replaced by symbolic links is currently not supported.',
+ 'Commenting on files that replace or are replaced by symbolic links is not supported',
);
}
+ } else if (fileOnlyMoved) {
+ tooltip = __('Commenting on files that are only moved or renamed is not supported');
+ } else if (brokenLineCode) {
+ tooltip = __('Commenting on this line is not supported');
}
return tooltip;
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index 5234be44b05..c73012527a2 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 } from '~/flash';
+import { createAlert, VARIANT_WARNING } from '~/flash';
import { diffViewerModes } from '~/ide/constants';
import axios from '~/lib/utils/axios_utils';
@@ -229,9 +229,17 @@ export const fetchDiffFilesMeta = ({ commit, state }) => {
return data;
})
- .catch(() => worker.terminate());
-};
+ .catch((error) => {
+ worker.terminate();
+ if (error.response.status === httpStatusCodes.NOT_FOUND) {
+ createAlert({
+ message: __('Building your merge request. Wait a few moments, then refresh this page.'),
+ variant: VARIANT_WARNING,
+ });
+ }
+ });
+};
export const fetchCoverageFiles = ({ commit, state }) => {
const coveragePoll = new Poll({
resource: {
diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js
index cf86ebea4a9..0519ca3d715 100644
--- a/app/assets/javascripts/diffs/store/utils.js
+++ b/app/assets/javascripts/diffs/store/utils.js
@@ -324,15 +324,24 @@ function cleanRichText(text) {
}
function prepareLine(line, file) {
+ const problems = {
+ brokenSymlink: file.brokenSymlink,
+ brokenLineCode: !line.line_code,
+ fileOnlyMoved: file.renamed_file && file.added_lines === 0 && file.removed_lines === 0,
+ };
+
if (!line.alreadyPrepared) {
Object.assign(line, {
- commentsDisabled: file.brokenSymlink,
+ commentsDisabled: Boolean(
+ problems.brokenSymlink || problems.fileOnlyMoved || problems.brokenLineCode,
+ ),
rich_text: cleanRichText(line.rich_text),
discussionsExpanded: true,
discussions: [],
hasForm: false,
text: undefined,
alreadyPrepared: true,
+ problems,
});
}
}
diff --git a/app/assets/javascripts/diffs/utils/tree_worker_utils.js b/app/assets/javascripts/diffs/utils/tree_worker_utils.js
index 985e75d1a17..a90c1a5c64e 100644
--- a/app/assets/javascripts/diffs/utils/tree_worker_utils.js
+++ b/app/assets/javascripts/diffs/utils/tree_worker_utils.js
@@ -62,10 +62,15 @@ export const generateTreeList = (files) => {
const split = file.new_path.split('/');
split.forEach((name, i) => {
- const parent = acc.treeEntries[split.slice(0, i).join('/')];
+ let parent = acc.treeEntries[split.slice(0, i).join('/')];
const path = `${parent ? `${parent.path}/` : ''}${name}`;
+ const child = acc.treeEntries[path];
- if (!acc.treeEntries[path]) {
+ if (parent && !parent.tree) {
+ parent = null;
+ }
+
+ if (!child || !child.tree) {
const type = path === file.new_path ? 'blob' : 'tree';
acc.treeEntries[path] = {
key: path,
diff --git a/app/assets/javascripts/dirty_submit/dirty_submit_form.js b/app/assets/javascripts/dirty_submit/dirty_submit_form.js
index 83dd4b0a124..941c42f75eb 100644
--- a/app/assets/javascripts/dirty_submit/dirty_submit_form.js
+++ b/app/assets/javascripts/dirty_submit/dirty_submit_form.js
@@ -1,4 +1,3 @@
-import $ from 'jquery';
import { memoize, throttle } from 'lodash';
import createEventHub from '~/helpers/event_hub_factory';
@@ -34,7 +33,6 @@ class DirtySubmitForm {
this.form.addEventListener('input', throttledUpdateDirtyInput);
this.form.addEventListener('change', throttledUpdateDirtyInput);
- $(this.form).on('change.select2', throttledUpdateDirtyInput);
this.form.addEventListener('submit', (event) => this.formSubmit(event));
}
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 999e91eed19..dd4a7a689d7 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,4 +1,4 @@
-import { KeyMod, KeyCode } from 'monaco-editor';
+import { KeyMod, KeyCode, Emitter } from 'monaco-editor';
import { debounce } from 'lodash';
import { BLOB_PREVIEW_ERROR } from '~/blob_edit/constants';
import { createAlert } from '~/flash';
@@ -56,6 +56,7 @@ export class EditorMarkdownPreviewExtension {
layoutChangeListener: undefined,
path: setupOptions.previewMarkdownPath,
actionShowPreviewCondition: instance.createContextKey('toggleLivePreview', true),
+ eventEmitter: new Emitter(),
};
this.toolbarButtons = [];
@@ -71,6 +72,8 @@ export class EditorMarkdownPreviewExtension {
EditorMarkdownPreviewExtension.resizePreviewLayout(instance, newWidth);
}
});
+
+ this.preview.eventEmitter.event(this.togglePreview.bind(this, instance));
}
onBeforeUnuse(instance) {
@@ -187,6 +190,31 @@ export class EditorMarkdownPreviewExtension {
});
}
+ togglePreview(instance) {
+ if (!this.preview?.el) {
+ this.preview.el = setupDomElement({ injectToEl: instance.getDomNode().parentElement });
+ }
+ this.togglePreviewLayout(instance);
+ this.togglePreviewPanel(instance);
+
+ this.preview.actionShowPreviewCondition.set(!this.preview.actionShowPreviewCondition.get());
+
+ if (!this.preview?.shown) {
+ this.preview.modelChangeListener = instance.onDidChangeModelContent(
+ debounce(this.fetchPreview.bind(this, instance), EXTENSION_MARKDOWN_PREVIEW_UPDATE_DELAY),
+ );
+ } else {
+ this.preview.modelChangeListener.dispose();
+ }
+
+ this.preview.shown = !this.preview?.shown;
+ if (instance.toolbar) {
+ instance.toolbar.updateItem(EXTENSION_MARKDOWN_PREVIEW_ACTION_ID, {
+ selected: this.preview.shown,
+ });
+ }
+ }
+
provides() {
return {
markdownPreview: this.preview,
@@ -195,33 +223,7 @@ export class EditorMarkdownPreviewExtension {
setupPreviewAction: (instance) => this.setupPreviewAction(instance),
- togglePreview: (instance) => {
- if (!this.preview?.el) {
- this.preview.el = setupDomElement({ injectToEl: instance.getDomNode().parentElement });
- }
- this.togglePreviewLayout(instance);
- this.togglePreviewPanel(instance);
-
- this.preview.actionShowPreviewCondition.set(!this.preview.actionShowPreviewCondition.get());
-
- if (!this.preview?.shown) {
- this.preview.modelChangeListener = instance.onDidChangeModelContent(
- debounce(
- this.fetchPreview.bind(this, instance),
- EXTENSION_MARKDOWN_PREVIEW_UPDATE_DELAY,
- ),
- );
- } else {
- this.preview.modelChangeListener.dispose();
- }
-
- this.preview.shown = !this.preview?.shown;
- if (instance.toolbar) {
- instance.toolbar.updateItem(EXTENSION_MARKDOWN_PREVIEW_ACTION_ID, {
- selected: this.preview.shown,
- });
- }
- },
+ togglePreview: (instance) => this.togglePreview(instance),
};
}
}
diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json
index e56932a9a31..45f063a2048 100644
--- a/app/assets/javascripts/editor/schema/ci.json
+++ b/app/assets/javascripts/editor/schema/ci.json
@@ -103,7 +103,9 @@
"workflow": {
"type": "object",
"properties": {
- "name": { "$ref": "#/definitions/workflowName" },
+ "name": {
+ "$ref": "#/definitions/workflowName"
+ },
"rules": {
"type": "array",
"items": {
@@ -130,7 +132,7 @@
"$ref": "#/definitions/exists"
},
"variables": {
- "$ref": "#/definitions/variables"
+ "$ref": "#/definitions/rulesVariables"
},
"when": {
"type": "string",
@@ -688,7 +690,7 @@
"$ref": "#/definitions/exists"
},
"variables": {
- "$ref": "#/definitions/variables"
+ "$ref": "#/definitions/rulesVariables"
},
"when": {
"$ref": "#/definitions/when"
@@ -742,6 +744,10 @@
"description": {
"type": "string",
"markdownDescription": "Explains what the variable is used for, what the acceptable values are. Variables with `description` are prefilled when running a pipeline manually. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#variablesdescription)."
+ },
+ "expand": {
+ "type": "boolean",
+ "markdownDescription": "If the variable is expandable or not. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#variablesexpand)."
}
},
"additionalProperties": false
@@ -751,6 +757,49 @@
"additionalProperties": false
}
},
+ "jobVariables": {
+ "markdownDescription": "Defines variables for a job. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#variables).",
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "oneOf": [
+ {
+ "type": [
+ "string",
+ "number"
+ ]
+ },
+ {
+ "type": "object",
+ "properties": {
+ "value": {
+ "type": "string"
+ },
+ "expand": {
+ "type": "boolean",
+ "markdownDescription": "Defines if the variable is expandable or not. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#variablesexpand)."
+ }
+ },
+ "additionalProperties": false
+ }
+ ]
+ },
+ "additionalProperties": false
+ }
+ },
+ "rulesVariables": {
+ "markdownDescription": "Defines variables for a rule result. [Learn More](https://docs.gitlab.com/ee/ci/yaml/index.html#rulesvariables).",
+ "type": "object",
+ "patternProperties": {
+ ".*": {
+ "type": [
+ "string",
+ "number"
+ ]
+ },
+ "additionalProperties": false
+ }
+ },
"if": {
"type": "string",
"markdownDescription": "Expression to evaluate whether additional attributes should be provided to the job. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#rulesif)."
@@ -793,19 +842,6 @@
"type": "string"
}
},
- "variables": {
- "markdownDescription": "Defines environment variables. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#variables).",
- "type": "object",
- "patternProperties": {
- ".*": {
- "type": [
- "string",
- "number"
- ]
- },
- "additionalProperties": false
- }
- },
"timeout": {
"type": "string",
"markdownDescription": "Allows you to configure a timeout for a specific job (e.g. `1 minute`, `1h 30m 12s`). [Learn More](https://docs.gitlab.com/ee/ci/yaml/index.html#timeout).",
@@ -858,137 +894,77 @@
]
},
"when": {
- "markdownDescription": "Describes the conditions for when to run the job. Defaults to 'on_success'.",
+ "markdownDescription": "Describes the conditions for when to run the job. Defaults to 'on_success'. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#when).",
"default": "on_success",
- "oneOf": [
- {
- "enum": [
- "on_success"
- ],
- "description": "Execute job only when all jobs from prior stages succeed."
- },
- {
- "enum": [
- "on_failure"
- ],
- "description": "Execute job when at least one job from prior stages fails."
- },
- {
- "enum": [
- "always"
- ],
- "description": "Execute job regardless of the status from prior stages."
- },
- {
- "enum": [
- "manual"
- ],
- "markdownDescription": "Execute the job manually from Gitlab UI or API. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#when)."
- },
- {
- "enum": [
- "delayed"
- ],
- "markdownDescription": "Execute a job after the time limit in 'start_in' expires. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#when)."
- },
- {
- "enum": [
- "never"
- ],
- "description": "Never execute the job."
- }
+ "type": "string",
+ "enum": [
+ "on_success",
+ "on_failure",
+ "always",
+ "never",
+ "manual",
+ "delayed"
]
},
"cache": {
+ "markdownDescription": "Use `cache` to specify a list of files and directories to cache between jobs. You can only use paths that are in the local working copy. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#cache)",
"properties": {
- "when": {
- "markdownDescription": "Defines when to save the cache, based on the status of the job. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#cachewhen).",
- "default": "on_success",
- "oneOf": [
- {
- "enum": [
- "on_success"
- ],
- "description": "Save the cache only when the job succeeds."
- },
- {
- "enum": [
- "on_failure"
- ],
- "description": "Save the cache only when the job fails. "
- },
- {
- "enum": [
- "always"
- ],
- "description": "Always save the cache. "
- }
- ]
- }
- }
- },
- "cache_entry": {
- "type": "object",
- "description": "Specify files or directories to cache between jobs. Can be set globally or per job.",
- "additionalProperties": false,
- "properties": {
- "paths": {
- "type": "array",
- "description": "List of files or paths to cache.",
- "items": {
- "type": "string"
- }
- },
"key": {
+ "markdownDescription": "Use the `cache:key` keyword to give each cache a unique identifying key. All jobs that use the same cache key use the same cache, including in different pipelines. Must be used with `cache:path`, or nothing is cached. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#cachekey).",
"oneOf": [
{
"type": "string",
- "description": "Unique cache ID, to allow e.g. specific branch or job cache. Environment variables can be used to set up unique keys (e.g. \"$CI_COMMIT_REF_SLUG\" for per branch cache)."
+ "pattern": "^(?!.*\\/)^(.*[^.]+.*)$"
},
{
"type": "object",
- "description": "When you include cache:key:files, you must also list the project files that will be used to generate the key, up to a maximum of two files. The cache key will be a SHA checksum computed from the most recent commits (up to two, if two files are listed) that changed the given files.",
"properties": {
"files": {
+ "markdownDescription": "Use the `cache:key:files` keyword to generate a new key when one or two specific files change. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#cachekeyfiles)",
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"maxItems": 2
+ },
+ "prefix": {
+ "markdownDescription": "Use `cache:key:prefix` to combine a prefix with the SHA computed for `cache:key:files`. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#cachekeyprefix)",
+ "type": "string"
}
}
}
]
},
- "untracked": {
- "type": "boolean",
- "description": "Set to `true` to cache untracked files.",
- "default": false
+ "paths": {
+ "type": "array",
+ "markdownDescription": "Use the `cache:paths` keyword to choose which files or directories to cache. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#cachepaths)",
+ "items": {
+ "type": "string"
+ }
},
"policy": {
"type": "string",
- "description": "Determines the strategy for downloading and updating the cache.",
+ "markdownDescription": "Determines the strategy for downloading and updating the cache. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#cachepolicy)",
"default": "pull-push",
- "oneOf": [
- {
- "enum": [
- "pull"
- ],
- "description": "Pull will download cache but skip uploading after job completes."
- },
- {
- "enum": [
- "push"
- ],
- "description": "Push will skip downloading cache and always recreate cache after job completes."
- },
- {
- "enum": [
- "pull-push"
- ],
- "description": "Pull-push will both download cache at job start and upload cache on job success."
- }
+ "enum": [
+ "pull",
+ "push",
+ "pull-push"
+ ]
+ },
+ "untracked": {
+ "type": "boolean",
+ "markdownDescription": "Use `untracked: true` to cache all files that are untracked in your Git repository. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#cacheuntracked)",
+ "default": false
+ },
+ "when": {
+ "markdownDescription": "Defines when to save the cache, based on the status of the job. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#cachewhen).",
+ "default": "on_success",
+ "enum": [
+ "on_success",
+ "on_failure",
+ "always"
]
}
}
@@ -1228,7 +1204,7 @@
"$ref": "#/definitions/rules"
},
"variables": {
- "$ref": "#/definitions/variables"
+ "$ref": "#/definitions/jobVariables"
},
"cache": {
"$ref": "#/definitions/cache"
diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue
index c7e024aadec..74eef50ebaf 100644
--- a/app/assets/javascripts/environments/components/environment_actions.vue
+++ b/app/assets/javascripts/environments/components/environment_actions.vue
@@ -57,7 +57,8 @@ export default {
this.isLoading = true;
if (this.graphql) {
- this.$apollo.mutate({ mutation: actionMutation, variables: { action } });
+ await this.$apollo.mutate({ mutation: actionMutation, variables: { action } });
+ this.isLoading = false;
} else {
eventHub.$emit('postAction', { endpoint: action.playPath });
}
diff --git a/app/assets/javascripts/environments/components/environment_rollback.vue b/app/assets/javascripts/environments/components/environment_rollback.vue
index f7f0cf4cb8d..f7a853f3128 100644
--- a/app/assets/javascripts/environments/components/environment_rollback.vue
+++ b/app/assets/javascripts/environments/components/environment_rollback.vue
@@ -51,17 +51,20 @@ export default {
methods: {
onClick() {
+ const rollbackEnvironmentData = {
+ ...this.environment,
+ retryUrl: this.retryUrl,
+ isLastDeployment: this.isLastDeployment,
+ };
if (this.graphql) {
this.$apollo.mutate({
mutation: setEnvironmentToRollback,
- variables: { environment: this.environment },
+ variables: {
+ environment: rollbackEnvironmentData,
+ },
});
} else {
- eventHub.$emit('requestRollbackEnvironment', {
- ...this.environment,
- retryUrl: this.retryUrl,
- isLastDeployment: this.isLastDeployment,
- });
+ eventHub.$emit('requestRollbackEnvironment', rollbackEnvironmentData);
}
},
},
diff --git a/app/assets/javascripts/environments/graphql/queries/environment_to_rollback.query.graphql b/app/assets/javascripts/environments/graphql/queries/environment_to_rollback.query.graphql
index f7586e27665..84c6998f234 100644
--- a/app/assets/javascripts/environments/graphql/queries/environment_to_rollback.query.graphql
+++ b/app/assets/javascripts/environments/graphql/queries/environment_to_rollback.query.graphql
@@ -3,5 +3,6 @@ query environmentToRollback {
id
name
lastDeployment
+ retryUrl
}
}
diff --git a/app/assets/javascripts/filtered_search/dropdown_user.js b/app/assets/javascripts/filtered_search/dropdown_user.js
index 26507a85fa8..fe580aab108 100644
--- a/app/assets/javascripts/filtered_search/dropdown_user.js
+++ b/app/assets/javascripts/filtered_search/dropdown_user.js
@@ -1,3 +1,4 @@
+import { ACTIVE_AND_BLOCKED_USER_STATES } from '~/users_select/constants';
import { addClassIfElementExists } from '../lib/utils/dom_utils';
import DropdownAjaxFilter from './dropdown_ajax_filter';
@@ -14,7 +15,7 @@ export default class DropdownUser extends DropdownAjaxFilter {
return {
...super.ajaxFilterConfig(),
params: {
- active: true,
+ states: ACTIVE_AND_BLOCKED_USER_STATES,
group_id: this.getGroupId(),
project_id: this.getProjectId(),
current_user: true,
diff --git a/app/assets/javascripts/filtered_search/droplab/plugins/ajax_filter.js b/app/assets/javascripts/filtered_search/droplab/plugins/ajax_filter.js
index d0f2d205bb6..d6abab4c9ed 100644
--- a/app/assets/javascripts/filtered_search/droplab/plugins/ajax_filter.js
+++ b/app/assets/javascripts/filtered_search/droplab/plugins/ajax_filter.js
@@ -1,6 +1,7 @@
/* eslint-disable */
import AjaxCache from '~/lib/utils/ajax_cache';
+import { mergeUrlParams } from '~/lib/utils/url_utility';
const AjaxFilter = {
init: function (hook) {
@@ -62,7 +63,7 @@ const AjaxFilter = {
this.loading = true;
var params = config.params || {};
params[config.searchKey] = searchValue;
- var url = config.endpoint + this.buildParams(params);
+ var url = mergeUrlParams(params, config.endpoint, { spreadArrays: true });
return AjaxCache.retrieve(url)
.then((data) => {
this._loadData(data, config);
diff --git a/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js b/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js
index acb7449f830..d6e7887f93f 100644
--- a/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js
+++ b/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js
@@ -1,10 +1,18 @@
import { flattenDeep } from 'lodash';
-import { __, s__ } from '~/locale';
+import { __ } from '~/locale';
+import {
+ TOKEN_TITLE_ASSIGNEE,
+ TOKEN_TITLE_AUTHOR,
+ TOKEN_TITLE_LABEL,
+ TOKEN_TITLE_MILESTONE,
+ TOKEN_TITLE_MY_REACTION,
+ TOKEN_TITLE_RELEASE,
+} from '~/vue_shared/components/filtered_search_bar/constants';
import FilteredSearchTokenKeys from './filtered_search_token_keys';
export const tokenKeys = [
{
- formattedKey: __('Author'),
+ formattedKey: TOKEN_TITLE_AUTHOR,
key: 'author',
type: 'string',
param: 'username',
@@ -13,7 +21,7 @@ export const tokenKeys = [
tag: '@author',
},
{
- formattedKey: s__('SearchToken|Assignee'),
+ formattedKey: TOKEN_TITLE_ASSIGNEE,
key: 'assignee',
type: 'string',
param: 'username',
@@ -22,7 +30,7 @@ export const tokenKeys = [
tag: '@assignee',
},
{
- formattedKey: __('Milestone'),
+ formattedKey: TOKEN_TITLE_MILESTONE,
key: 'milestone',
type: 'string',
param: 'title',
@@ -31,7 +39,7 @@ export const tokenKeys = [
tag: '%milestone',
},
{
- formattedKey: __('Release'),
+ formattedKey: TOKEN_TITLE_RELEASE,
key: 'release',
type: 'string',
param: 'tag',
@@ -40,7 +48,7 @@ export const tokenKeys = [
tag: __('tag name'),
},
{
- formattedKey: __('Label'),
+ formattedKey: TOKEN_TITLE_LABEL,
key: 'label',
type: 'array',
param: 'name[]',
@@ -53,7 +61,7 @@ export const tokenKeys = [
if (gon.current_user_id) {
// Appending tokenkeys only logged-in
tokenKeys.push({
- formattedKey: __('My-Reaction'),
+ formattedKey: TOKEN_TITLE_MY_REACTION,
key: 'my-reaction',
type: 'string',
param: 'emoji',
@@ -65,7 +73,7 @@ if (gon.current_user_id) {
export const alternativeTokenKeys = [
{
- formattedKey: __('Label'),
+ formattedKey: TOKEN_TITLE_LABEL,
key: 'label',
type: 'string',
param: 'name',
diff --git a/app/assets/javascripts/flash.js b/app/assets/javascripts/flash.js
index 5665231e613..dc6c4642e94 100644
--- a/app/assets/javascripts/flash.js
+++ b/app/assets/javascripts/flash.js
@@ -109,6 +109,7 @@ const addDismissFlashClickListener = (flashEl, fadeTransition) => {
*
* @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.
@@ -126,6 +127,7 @@ const addDismissFlashClickListener = (flashEl, fadeTransition) => {
*/
const createAlert = function createAlert({
message,
+ title,
variant = VARIANT_DANGER,
parent = document,
containerSelector = '.flash-container',
@@ -183,6 +185,7 @@ const createAlert = function createAlert({
GlAlert,
{
props: {
+ title,
dismissible: true,
dismissLabel: __('Dismiss'),
variant,
diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js
index 01d218438cf..49c47e9d778 100644
--- a/app/assets/javascripts/gfm_auto_complete.js
+++ b/app/assets/javascripts/gfm_auto_complete.js
@@ -20,7 +20,12 @@ const MERGEREQUESTS_ALIAS = 'mergerequests';
const LABELS_ALIAS = 'labels';
const SNIPPETS_ALIAS = 'snippets';
const CONTACTS_ALIAS = 'contacts';
+
export const AT_WHO_ACTIVE_CLASS = 'at-who-active';
+export const CONTACT_STATE_ACTIVE = 'active';
+export const CONTACTS_ADD_COMMAND = '/add_contacts';
+export const CONTACTS_REMOVE_COMMAND = '/remove_contacts';
+
/**
* Escapes user input before we pass it to at.js, which
* renders it as HTML in the autocomplete dropdown.
@@ -666,6 +671,9 @@ class GfmAutoComplete {
}
setupContacts($input) {
+ const fetchData = this.fetchData.bind(this);
+ let command = '';
+
$input.atwho({
at: '[contact:',
suffix: ']',
@@ -694,9 +702,44 @@ class GfmAutoComplete {
firstName: m.first_name,
lastName: m.last_name,
search: `${m.email}`,
+ state: m.state,
+ set: m.set,
};
});
},
+ matcher(flag, subtext) {
+ const subtextNodes = subtext.split(/\n+/g).pop().split(GfmAutoComplete.regexSubtext);
+
+ command = subtextNodes.find((node) => {
+ if (node === CONTACTS_ADD_COMMAND || node === CONTACTS_REMOVE_COMMAND) {
+ return node;
+ }
+ return null;
+ });
+
+ const match = GfmAutoComplete.defaultMatcher(flag, subtext, this.app.controllers);
+ return match?.length ? match[1] : null;
+ },
+ filter(query, data, searchKey) {
+ if (GfmAutoComplete.isLoading(data)) {
+ fetchData(this.$inputor, this.at);
+ return data;
+ }
+
+ if (data === GfmAutoComplete.defaultLoadingData) {
+ return $.fn.atwho.default.callbacks.filter(query, data, searchKey);
+ }
+
+ if (command === CONTACTS_ADD_COMMAND) {
+ // Return contacts that are active and not already on the issue
+ return data.filter((contact) => contact.state === CONTACT_STATE_ACTIVE && !contact.set);
+ } else if (command === CONTACTS_REMOVE_COMMAND) {
+ // Return contacts already on the issue
+ return data.filter((contact) => contact.set);
+ }
+
+ return data;
+ },
},
});
showAndHideHelper($input, CONTACTS_ALIAS);
diff --git a/app/assets/javascripts/gitlab_version_check.js b/app/assets/javascripts/gitlab_version_check.js
deleted file mode 100644
index 2892aded7c5..00000000000
--- a/app/assets/javascripts/gitlab_version_check.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import Vue from 'vue';
-import GitlabVersionCheck from '~/vue_shared/components/gitlab_version_check.vue';
-
-const mountGitlabVersionCheck = (el) => {
- const { size } = el.dataset;
-
- return new Vue({
- el,
- render(createElement) {
- return createElement(GitlabVersionCheck, {
- props: {
- size,
- },
- });
- },
- });
-};
-
-export default () =>
- [...document.querySelectorAll('.js-gitlab-version-check')].map(mountGitlabVersionCheck);
diff --git a/app/assets/javascripts/gitlab_version_check/components/gitlab_version_check_badge.vue b/app/assets/javascripts/gitlab_version_check/components/gitlab_version_check_badge.vue
new file mode 100644
index 00000000000..1536a9a525b
--- /dev/null
+++ b/app/assets/javascripts/gitlab_version_check/components/gitlab_version_check_badge.vue
@@ -0,0 +1,73 @@
+<script>
+import { GlBadge } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import Tracking from '~/tracking';
+import { STATUS_TYPES, UPGRADE_DOCS_URL } from '../constants';
+
+export default {
+ name: 'GitlabVersionCheckBadge',
+ components: {
+ GlBadge,
+ },
+ mixins: [Tracking.mixin()],
+ props: {
+ size: {
+ type: String,
+ required: false,
+ default: 'md',
+ },
+ actionable: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ status: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ title() {
+ if (this.status === STATUS_TYPES.SUCCESS) {
+ return s__('VersionCheck|Up to date');
+ } else if (this.status === STATUS_TYPES.WARNING) {
+ return s__('VersionCheck|Update available');
+ } else if (this.status === STATUS_TYPES.DANGER) {
+ return s__('VersionCheck|Update ASAP');
+ }
+
+ return null;
+ },
+ badgeUrl() {
+ return this.actionable ? UPGRADE_DOCS_URL : null;
+ },
+ },
+ mounted() {
+ this.track('render', {
+ label: 'version_badge',
+ property: this.title,
+ });
+ },
+ methods: {
+ onClick() {
+ if (!this.actionable) return;
+
+ this.track('click_link', {
+ label: 'version_badge',
+ property: this.title,
+ });
+ },
+ },
+ UPGRADE_DOCS_URL,
+};
+</script>
+
+<template>
+ <!-- TODO: remove the span element once bootstrap-vue is updated to version 2.21.1 -->
+ <!-- TODO: https://github.com/bootstrap-vue/bootstrap-vue/issues/6219 -->
+ <span data-testid="badge-click-wrapper" @click="onClick">
+ <gl-badge :href="badgeUrl" class="version-check-badge" :variant="status" :size="size">{{
+ title
+ }}</gl-badge>
+ </span>
+</template>
diff --git a/app/assets/javascripts/gitlab_version_check/constants.js b/app/assets/javascripts/gitlab_version_check/constants.js
new file mode 100644
index 00000000000..259723a4e22
--- /dev/null
+++ b/app/assets/javascripts/gitlab_version_check/constants.js
@@ -0,0 +1,9 @@
+import { helpPagePath } from '~/helpers/help_page_helper';
+
+export const STATUS_TYPES = {
+ SUCCESS: 'success',
+ WARNING: 'warning',
+ DANGER: 'danger',
+};
+
+export const UPGRADE_DOCS_URL = helpPagePath('update/index');
diff --git a/app/assets/javascripts/gitlab_version_check/index.js b/app/assets/javascripts/gitlab_version_check/index.js
new file mode 100644
index 00000000000..203ce10ef57
--- /dev/null
+++ b/app/assets/javascripts/gitlab_version_check/index.js
@@ -0,0 +1,50 @@
+import Vue from 'vue';
+import * as Sentry from '@sentry/browser';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import axios from '~/lib/utils/axios_utils';
+import { joinPaths } from '~/lib/utils/url_utility';
+import GitlabVersionCheckBadge from './components/gitlab_version_check_badge.vue';
+
+const mountGitlabVersionCheckBadge = ({ el, status }) => {
+ const { size } = el.dataset;
+ const actionable = parseBoolean(el.dataset.actionable);
+
+ return new Vue({
+ el,
+ render(createElement) {
+ return createElement(GitlabVersionCheckBadge, {
+ props: {
+ size,
+ actionable,
+ status,
+ },
+ });
+ },
+ });
+};
+
+export default async () => {
+ const versionCheckBadges = [...document.querySelectorAll('.js-gitlab-version-check-badge')];
+
+ // If there are no version check elements, exit out
+ if (versionCheckBadges?.length <= 0) {
+ return null;
+ }
+
+ const status = await axios
+ .get(joinPaths('/', gon.relative_url_root, '/admin/version_check.json'))
+ .then((res) => {
+ return res.data?.severity;
+ })
+ .catch((e) => {
+ Sentry.captureException(e);
+ return null;
+ });
+
+ // If we don't have a status there is nothing to render
+ if (status) {
+ return versionCheckBadges.map((el) => mountGitlabVersionCheckBadge({ el, status }));
+ }
+
+ return null;
+};
diff --git a/app/assets/javascripts/gl_field_errors.js b/app/assets/javascripts/gl_field_errors.js
index eec7a138ea7..28aa9906116 100644
--- a/app/assets/javascripts/gl_field_errors.js
+++ b/app/assets/javascripts/gl_field_errors.js
@@ -15,9 +15,14 @@ export default class GlFieldErrors {
initValidators() {
// register selectors here as needed
- const validateSelectors = [':text', ':password', '[type=email]', '[type=url]', '[type=number]']
- .map((selector) => `input${selector}`)
- .join(',');
+ const validateSelectors = [
+ 'input:text',
+ 'input:password',
+ 'input[type=email]',
+ 'input[type=url]',
+ 'input[type=number]',
+ 'textarea',
+ ].join(',');
this.state.inputs = this.form
.find(validateSelectors)
diff --git a/app/assets/javascripts/google_cloud/service_accounts/list.vue b/app/assets/javascripts/google_cloud/service_accounts/list.vue
index 4b580c594f5..c9d9a9a3e8c 100644
--- a/app/assets/javascripts/google_cloud/service_accounts/list.vue
+++ b/app/assets/javascripts/google_cloud/service_accounts/list.vue
@@ -1,7 +1,10 @@
<script>
import { GlAlert, GlButton, GlEmptyState, GlLink, GlSprintf, GlTable } from '@gitlab/ui';
+import { setUrlParams } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
+const GOOGLE_CONSOLE_URL = 'https://console.cloud.google.com/iam-admin/serviceaccounts';
+
export default {
components: { GlAlert, GlButton, GlEmptyState, GlLink, GlSprintf, GlTable },
props: {
@@ -40,6 +43,12 @@ export default {
'Enhance security by storing service account keys in secret managers - learn more about %{docLinkStart}secret management with GitLab%{docLinkEnd}',
),
},
+ methods: {
+ gcpProjectUrl(id) {
+ return setUrlParams({ project: id }, GOOGLE_CONSOLE_URL);
+ },
+ },
+ GOOGLE_CONSOLE_URL,
};
</script>
@@ -59,6 +68,9 @@ export default {
<p>{{ $options.i18n.serviceAccountsDescription }}</p>
<gl-table :items="list" :fields="$options.tableFields">
+ <template #cell(gcp_project)="{ value }">
+ <gl-link :href="gcpProjectUrl(value)">{{ value }}</gl-link>
+ </template>
<template #cell(service_account_exists)="{ value }">
{{ value ? $options.i18n.found : $options.i18n.notFound }}
</template>
diff --git a/app/assets/javascripts/google_tag_manager/index.js b/app/assets/javascripts/google_tag_manager/index.js
index 5b0bcfa963b..98c9db1fc9a 100644
--- a/app/assets/javascripts/google_tag_manager/index.js
+++ b/app/assets/javascripts/google_tag_manager/index.js
@@ -40,6 +40,11 @@ const generateProductInfo = (sku, quantity) => {
};
const isSupported = () => Boolean(window.dataLayer) && gon.features?.gitlabGtmDatalayer;
+// gon.features.gitlabGtmDatalayer is set by writing
+// `push_frontend_feature_flag(:gitlab_gtm_datalayer, type: :ops)`
+// to the appropriate controller
+// window.dataLayer is set by adding partials to the appropriate view found in
+// views/layouts/_google_tag_manager_body.html.haml and _google_tag_manager_head.html.haml
const pushEvent = (event, args = {}) => {
if (!window.dataLayer) {
@@ -287,3 +292,27 @@ export const trackCompanyForm = (aboutYourCompanyType) => {
pushEvent('aboutYourCompanyFormSubmit', { aboutYourCompanyType });
};
+
+export const saasTrialWelcome = () => {
+ if (!isSupported()) {
+ return;
+ }
+
+ const saasTrialWelcomeButton = document.querySelector('.js-trial-welcome-btn');
+
+ saasTrialWelcomeButton?.addEventListener('click', () => {
+ pushEvent('saasTrialWelcome');
+ });
+};
+
+export const saasTrialContinuousOnboarding = () => {
+ if (!isSupported()) {
+ return;
+ }
+
+ const getStartedButton = document.querySelector('.js-get-started-btn');
+
+ getStartedButton?.addEventListener('click', () => {
+ pushEvent('saasTrialContinuousOnboarding');
+ });
+};
diff --git a/app/assets/javascripts/graphql_shared/issuable_client.js b/app/assets/javascripts/graphql_shared/issuable_client.js
index 3b737dfff33..15e7ef7d62c 100644
--- a/app/assets/javascripts/graphql_shared/issuable_client.js
+++ b/app/assets/javascripts/graphql_shared/issuable_client.js
@@ -1,16 +1,18 @@
import produce from 'immer';
import VueApollo from 'vue-apollo';
+import { defaultDataIdFromObject } from '@apollo/client/core';
import { concatPagination } from '@apollo/client/utilities';
import getIssueStateQuery from '~/issues/show/queries/get_issue_state.query.graphql';
import createDefaultClient from '~/lib/graphql';
import typeDefs from '~/work_items/graphql/typedefs.graphql';
-import { WIDGET_TYPE_MILESTONE } from '~/work_items/constants';
-export const temporaryConfig = {
+export const config = {
typeDefs,
cacheConfig: {
- possibleTypes: {
- LocalWorkItemWidget: ['LocalWorkItemMilestone'],
+ // included temporarily until Vuex is removed from boards app
+ dataIdFromObject: (object) => {
+ // eslint-disable-next-line no-underscore-dangle
+ return object.__typename === 'BoardList' ? object.iid : defaultDataIdFromObject(object);
},
typePolicies: {
Project: {
@@ -22,35 +24,15 @@ export const temporaryConfig = {
},
WorkItem: {
fields: {
- mockWidgets: {
- read(widgets) {
- return (
- widgets || [
- {
- __typename: 'LocalWorkItemMilestone',
- type: WIDGET_TYPE_MILESTONE,
- nodes: [
- {
- dueDate: null,
- expired: false,
- id: 'gid://gitlab/Milestone/30',
- title: 'v4.0',
- // eslint-disable-next-line @gitlab/require-i18n-strings
- __typename: 'Milestone',
- },
- ],
- },
- ]
- );
- },
- },
widgets: {
merge(existing = [], incoming) {
if (existing.length === 0) {
return incoming;
}
return existing.map((existingWidget) => {
- const incomingWidget = incoming.find((w) => w.type === existingWidget.type);
+ const incomingWidget = incoming.find(
+ (w) => w.type && w.type === existingWidget.type,
+ );
return incomingWidget || existingWidget;
});
},
@@ -78,7 +60,7 @@ export const resolvers = {
},
};
-export const defaultClient = createDefaultClient(resolvers, temporaryConfig);
+export const defaultClient = createDefaultClient(resolvers, config);
export const apolloProvider = new VueApollo({
defaultClient,
diff --git a/app/assets/javascripts/graphql_shared/possible_types.json b/app/assets/javascripts/graphql_shared/possible_types.json
index 545c150e536..e8b0174b8f6 100644
--- a/app/assets/javascripts/graphql_shared/possible_types.json
+++ b/app/assets/javascripts/graphql_shared/possible_types.json
@@ -9,6 +9,10 @@
"CiManualVariable",
"CiProjectVariable"
],
+ "CommitSignature": [
+ "GpgSignature",
+ "X509Signature"
+ ],
"CurrentUserTodos": [
"BoardEpic",
"Design",
@@ -143,8 +147,9 @@
"WorkItemWidgetHierarchy",
"WorkItemWidgetIteration",
"WorkItemWidgetLabels",
+ "WorkItemWidgetMilestone",
"WorkItemWidgetStartAndDueDate",
"WorkItemWidgetStatus",
"WorkItemWidgetWeight"
]
-}
+} \ No newline at end of file
diff --git a/app/assets/javascripts/groups/components/overview_tabs.vue b/app/assets/javascripts/groups/components/overview_tabs.vue
index d0c5846ac88..46ab30367a0 100644
--- a/app/assets/javascripts/groups/components/overview_tabs.vue
+++ b/app/assets/javascripts/groups/components/overview_tabs.vue
@@ -15,6 +15,7 @@ import eventHub from '../event_hub';
import GroupsApp from './app.vue';
const [SORTING_ITEM_NAME] = OVERVIEW_TABS_SORTING_ITEMS;
+const MIN_SEARCH_LENGTH = 3;
export default {
components: { GlTabs, GlTab, GroupsApp, GlSearchBoxByType, GlSorting, GlSortingItem },
@@ -136,7 +137,9 @@ export default {
handleSearchInput(value) {
this.search = value;
- this.debouncedSearch();
+ if (!this.search || this.search.length >= MIN_SEARCH_LENGTH) {
+ this.debouncedSearch();
+ }
},
debouncedSearch: debounce(async function debouncedSearch() {
this.handleSearchOrSortChange();
diff --git a/app/assets/javascripts/groups/components/transfer_group_form.vue b/app/assets/javascripts/groups/components/transfer_group_form.vue
index e28459811d7..15a193f7cb8 100644
--- a/app/assets/javascripts/groups/components/transfer_group_form.vue
+++ b/app/assets/javascripts/groups/components/transfer_group_form.vue
@@ -1,29 +1,24 @@
<script>
-import { GlFormGroup } from '@gitlab/ui';
import { __, s__ } from '~/locale';
import ConfirmDanger from '~/vue_shared/components/confirm_danger/confirm_danger.vue';
-import NamespaceSelect from '~/vue_shared/components/namespace_select/namespace_select_deprecated.vue';
+import TransferLocations from '~/groups_projects/components/transfer_locations.vue';
+import { getGroupTransferLocations } from '~/api/groups_api';
export const i18n = {
confirmationMessage: __(
'You are going to transfer %{group_name} to another namespace. Are you ABSOLUTELY sure?',
),
emptyNamespaceTitle: __('No parent group'),
- dropdownTitle: s__('GroupSettings|Select parent group'),
+ dropdownLabel: s__('GroupSettings|Select parent group'),
};
export default {
name: 'TransferGroupForm',
components: {
ConfirmDanger,
- GlFormGroup,
- NamespaceSelect,
+ TransferLocations,
},
props: {
- groupNamespaces: {
- type: Array,
- required: true,
- },
isPaidGroup: {
type: Boolean,
required: true,
@@ -39,36 +34,41 @@ export default {
},
data() {
return {
- selectedId: null,
+ selectedTransferLocation: null,
};
},
computed: {
disableSubmitButton() {
- return this.isPaidGroup || !this.selectedId;
+ return this.isPaidGroup || !this.selectedTransferLocation;
+ },
+ selectedTransferLocationId() {
+ return this.selectedTransferLocation?.id;
},
},
methods: {
- handleSelected({ id }) {
- this.selectedId = id;
- },
+ getGroupTransferLocations,
},
i18n,
+ additionalDropdownItems: [
+ {
+ id: -1,
+ humanName: i18n.emptyNamespaceTitle,
+ },
+ ],
};
</script>
<template>
<div>
- <gl-form-group v-if="!isPaidGroup">
- <namespace-select
- :default-text="$options.i18n.dropdownTitle"
- :group-namespaces="groupNamespaces"
- :empty-namespace-title="$options.i18n.emptyNamespaceTitle"
- :include-headers="false"
- include-empty-namespace
- data-testid="transfer-group-namespace-select"
- @select="handleSelected"
- />
- <input type="hidden" name="new_parent_group_id" :value="selectedId" />
- </gl-form-group>
+ <input type="hidden" name="new_parent_group_id" :value="selectedTransferLocationId" />
+ <transfer-locations
+ v-if="!isPaidGroup"
+ v-model="selectedTransferLocation"
+ :show-user-transfer-locations="false"
+ data-testid="transfer-group-namespace"
+ :group-transfer-locations-api-method="getGroupTransferLocations"
+ :additional-dropdown-items="$options.additionalDropdownItems"
+ :label="$options.i18n.dropdownLabel"
+ />
<confirm-danger
:disabled="disableSubmitButton"
:phrase="confirmationPhrase"
diff --git a/app/assets/javascripts/groups/init_transfer_group_form.js b/app/assets/javascripts/groups/init_transfer_group_form.js
index f055b926918..503dad673dd 100644
--- a/app/assets/javascripts/groups/init_transfer_group_form.js
+++ b/app/assets/javascripts/groups/init_transfer_group_form.js
@@ -1,42 +1,38 @@
import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
import { sprintf } from '~/locale';
import { parseBoolean } from '~/lib/utils/common_utils';
import TransferGroupForm, { i18n } from './components/transfer_group_form.vue';
-const prepareGroups = (rawGroups) => {
- if (!rawGroups) {
- return [];
- }
-
- return JSON.parse(rawGroups).map(({ id, text: humanName }) => ({
- id,
- humanName,
- }));
-};
-
export default () => {
const el = document.querySelector('.js-transfer-group-form');
if (!el) {
return false;
}
+ Vue.use(VueApollo);
+
const {
targetFormId = null,
buttonText: confirmButtonText = '',
groupName = '',
- parentGroups,
+ groupId: resourceId,
isPaidGroup,
} = el.dataset;
return new Vue({
el,
+ apolloProvider: new VueApollo({
+ defaultClient: createDefaultClient(),
+ }),
provide: {
confirmDangerMessage: sprintf(i18n.confirmationMessage, { group_name: groupName }),
+ resourceId,
},
render(createElement) {
return createElement(TransferGroupForm, {
props: {
- groupNamespaces: prepareGroups(parentGroups),
isPaidGroup: parseBoolean(isPaidGroup),
confirmButtonText,
confirmationPhrase: groupName,
diff --git a/app/assets/javascripts/groups_projects/components/transfer_locations.vue b/app/assets/javascripts/groups_projects/components/transfer_locations.vue
new file mode 100644
index 00000000000..e0c8ce36e3c
--- /dev/null
+++ b/app/assets/javascripts/groups_projects/components/transfer_locations.vue
@@ -0,0 +1,282 @@
+<script>
+import {
+ GlAlert,
+ GlFormGroup,
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownSectionHeader,
+ GlDropdownDivider,
+ GlSearchBoxByType,
+ GlIntersectionObserver,
+ GlLoadingIcon,
+} from '@gitlab/ui';
+import { debounce } from 'lodash';
+import { s__, __ } from '~/locale';
+import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
+import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import currentUserNamespace from '~/projects/settings/graphql/queries/current_user_namespace.query.graphql';
+
+export const i18n = {
+ SELECT_A_NAMESPACE: __('Select a new namespace'),
+ GROUPS: __('Groups'),
+ USERS: __('Users'),
+ ERROR_MESSAGE: s__(
+ 'ProjectTransfer|An error occurred fetching the transfer locations, please refresh the page and try again.',
+ ),
+ ALERT_DISMISS_LABEL: __('Dismiss'),
+};
+
+export default {
+ name: 'TransferLocations',
+ components: {
+ GlAlert,
+ GlFormGroup,
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownSectionHeader,
+ GlDropdownDivider,
+ GlSearchBoxByType,
+ GlIntersectionObserver,
+ GlLoadingIcon,
+ },
+ inject: ['resourceId'],
+ props: {
+ value: {
+ type: Object,
+ required: false,
+ default: null,
+ },
+ groupTransferLocationsApiMethod: {
+ type: Function,
+ required: true,
+ },
+ showUserTransferLocations: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ additionalDropdownItems: {
+ type: Array,
+ required: false,
+ default() {
+ return [];
+ },
+ },
+ label: {
+ type: String,
+ required: false,
+ default: i18n.SELECT_A_NAMESPACE,
+ },
+ },
+ initialTransferLocationsLoaded: false,
+ data() {
+ return {
+ searchTerm: '',
+ userTransferLocations: [],
+ groupTransferLocations: [],
+ filteredAdditionalDropdownItems: this.additionalDropdownItems,
+ isLoading: false,
+ isSearchLoading: false,
+ hasError: false,
+ page: 1,
+ totalPages: 1,
+ };
+ },
+ computed: {
+ hasUserTransferLocations() {
+ return this.userTransferLocations.length;
+ },
+ hasGroupTransferLocations() {
+ return this.groupTransferLocations.length;
+ },
+ selectedText() {
+ return this.value?.humanName || this.label;
+ },
+ hasNextPageOfGroups() {
+ return this.page < this.totalPages;
+ },
+ showAdditionalDropdownItems() {
+ return !this.isLoading && this.filteredAdditionalDropdownItems.length;
+ },
+ },
+ watch: {
+ searchTerm() {
+ this.page = 1;
+
+ this.debouncedSearch();
+ },
+ },
+ methods: {
+ handleSelect(item) {
+ this.searchTerm = '';
+ this.$emit('input', item);
+ },
+ async handleShow() {
+ if (this.$options.initialTransferLocationsLoaded) {
+ return;
+ }
+
+ this.isLoading = true;
+
+ [this.groupTransferLocations, this.userTransferLocations] = await Promise.all([
+ this.getGroupTransferLocations(),
+ this.getUserTransferLocations(),
+ ]);
+
+ this.isLoading = false;
+ this.$options.initialTransferLocationsLoaded = true;
+ },
+ async getGroupTransferLocations() {
+ try {
+ const {
+ data: groupTransferLocations,
+ headers,
+ } = await this.groupTransferLocationsApiMethod(this.resourceId, {
+ page: this.page,
+ search: this.searchTerm,
+ });
+
+ const { totalPages } = parseIntPagination(normalizeHeaders(headers));
+ this.totalPages = totalPages;
+
+ return groupTransferLocations.map(({ id, full_name: humanName }) => ({
+ id,
+ humanName,
+ }));
+ } catch {
+ this.handleError();
+
+ return [];
+ }
+ },
+ async getUserTransferLocations() {
+ if (!this.showUserTransferLocations) {
+ return [];
+ }
+
+ try {
+ const {
+ data: {
+ currentUser: { namespace },
+ },
+ } = await this.$apollo.query({
+ query: currentUserNamespace,
+ });
+
+ if (!namespace) {
+ return [];
+ }
+
+ return [
+ {
+ id: getIdFromGraphQLId(namespace.id),
+ humanName: namespace.fullName,
+ },
+ ];
+ } catch {
+ this.handleError();
+
+ return [];
+ }
+ },
+ async handleLoadMoreGroups() {
+ this.isLoading = true;
+ this.page += 1;
+
+ const groupTransferLocations = await this.getGroupTransferLocations();
+ this.groupTransferLocations.push(...groupTransferLocations);
+
+ this.isLoading = false;
+ },
+ debouncedSearch: debounce(async function debouncedSearch() {
+ this.isSearchLoading = true;
+
+ this.groupTransferLocations = await this.getGroupTransferLocations();
+
+ this.filteredAdditionalDropdownItems = this.additionalDropdownItems.filter((dropdownItem) =>
+ dropdownItem.humanName.toLowerCase().includes(this.searchTerm.toLowerCase()),
+ );
+
+ this.isSearchLoading = false;
+ }, DEBOUNCE_DELAY),
+ handleError() {
+ this.hasError = true;
+ },
+ handleAlertDismiss() {
+ this.hasError = false;
+ },
+ },
+ i18n,
+};
+</script>
+<template>
+ <div>
+ <gl-alert
+ v-if="hasError"
+ variant="danger"
+ :dismiss-label="$options.i18n.ALERT_DISMISS_LABEL"
+ @dismiss="handleAlertDismiss"
+ >{{ $options.i18n.ERROR_MESSAGE }}</gl-alert
+ >
+ <gl-form-group :label="label">
+ <gl-dropdown
+ :text="selectedText"
+ data-qa-selector="namespaces_list"
+ data-testid="transfer-locations-dropdown"
+ block
+ toggle-class="gl-mb-0"
+ @show="handleShow"
+ >
+ <template #header>
+ <gl-search-box-by-type
+ v-model.trim="searchTerm"
+ :is-loading="isSearchLoading"
+ data-qa-selector="namespaces_list_search"
+ />
+ </template>
+ <template v-if="showAdditionalDropdownItems">
+ <gl-dropdown-item
+ v-for="item in filteredAdditionalDropdownItems"
+ :key="item.id"
+ @click="handleSelect(item)"
+ >{{ item.humanName }}</gl-dropdown-item
+ >
+ <gl-dropdown-divider />
+ </template>
+ <div
+ v-if="hasUserTransferLocations"
+ data-qa-selector="namespaces_list_users"
+ data-testid="user-transfer-locations"
+ >
+ <gl-dropdown-section-header>{{ $options.i18n.USERS }}</gl-dropdown-section-header>
+ <gl-dropdown-item
+ v-for="item in userTransferLocations"
+ :key="item.id"
+ data-qa-selector="namespaces_list_item"
+ @click="handleSelect(item)"
+ >{{ item.humanName }}</gl-dropdown-item
+ >
+ </div>
+ <div
+ v-if="hasGroupTransferLocations"
+ data-qa-selector="namespaces_list_groups"
+ data-testid="group-transfer-locations"
+ >
+ <gl-dropdown-section-header v-if="showUserTransferLocations">{{
+ $options.i18n.GROUPS
+ }}</gl-dropdown-section-header>
+ <gl-dropdown-item
+ v-for="item in groupTransferLocations"
+ :key="item.id"
+ data-qa-selector="namespaces_list_item"
+ @click="handleSelect(item)"
+ >{{ item.humanName }}</gl-dropdown-item
+ >
+ </div>
+ <gl-loading-icon v-if="isLoading" class="gl-mb-3" size="sm" />
+ <gl-intersection-observer v-if="hasNextPageOfGroups" @appear="handleLoadMoreGroups" />
+ </gl-dropdown>
+ </gl-form-group>
+ </div>
+</template>
diff --git a/app/assets/javascripts/groups_select.js b/app/assets/javascripts/groups_select.js
index 34e984a9bb9..fb0c47fe018 100644
--- a/app/assets/javascripts/groups_select.js
+++ b/app/assets/javascripts/groups_select.js
@@ -1,11 +1,38 @@
+import Vue from 'vue';
import $ from 'jquery';
import { escape } from 'lodash';
+import GroupSelect from '~/vue_shared/components/group_select/group_select.vue';
import { groupsPath } from '~/vue_shared/components/group_select/utils';
import { __ } from '~/locale';
import Api from './api';
import { loadCSSFile } from './lib/utils/css_utils';
import { select2AxiosTransport } from './lib/utils/select2_utils';
+const initVueSelect = () => {
+ [...document.querySelectorAll('.ajax-groups-select')].forEach((el) => {
+ const { parentId: parentGroupID, groupsFilter, inputId } = el.dataset;
+
+ return new Vue({
+ el,
+ components: {
+ GroupSelect,
+ },
+ render(createElement) {
+ return createElement(GroupSelect, {
+ props: {
+ inputName: el.name,
+ initialSelection: el.value || null,
+ parentGroupID,
+ groupsFilter,
+ inputId,
+ clearable: el.classList.contains('allowClear'),
+ },
+ });
+ },
+ });
+ });
+};
+
const groupsSelect = () => {
loadCSSFile(gon.select2_css_path)
.then(() => {
@@ -84,8 +111,12 @@ const groupsSelect = () => {
export default () => {
if ($('.ajax-groups-select').length) {
- import(/* webpackChunkName: 'select2' */ 'select2/select2')
- .then(groupsSelect)
- .catch(() => {});
+ if (gon.features?.vueGroupSelect) {
+ initVueSelect();
+ } else {
+ import(/* webpackChunkName: 'select2' */ 'select2/select2')
+ .then(groupsSelect)
+ .catch(() => {});
+ }
}
};
diff --git a/app/assets/javascripts/ide/components/ide.vue b/app/assets/javascripts/ide/components/ide.vue
index d589f56dd7c..838debf1ceb 100644
--- a/app/assets/javascripts/ide/components/ide.vue
+++ b/app/assets/javascripts/ide/components/ide.vue
@@ -47,6 +47,7 @@ export default {
data() {
return {
loadDeferred: false,
+ skipBeforeUnload: false,
};
},
computed: {
@@ -78,9 +79,14 @@ export default {
mounted() {
window.onbeforeunload = (e) => this.onBeforeUnload(e);
+ eventHub.$on('skip-beforeunload', this.handleSkipBeforeUnload);
+
if (this.themeName)
document.querySelector('.navbar-gitlab').classList.add(`theme-${this.themeName}`);
},
+ destroyed() {
+ eventHub.$off('skip-beforeunload', this.handleSkipBeforeUnload);
+ },
beforeCreate() {
performanceMarkAndMeasure({
mark: WEBIDE_MARK_APP_START,
@@ -94,6 +100,11 @@ export default {
methods: {
...mapActions(['toggleFileFinder']),
onBeforeUnload(e = {}) {
+ if (this.skipBeforeUnload) {
+ this.skipBeforeUnload = false;
+ return undefined;
+ }
+
const returnValue = __('Are you sure you want to lose unsaved changes?');
if (!this.someUncommittedChanges) return undefined;
@@ -103,6 +114,9 @@ export default {
});
return returnValue;
},
+ handleSkipBeforeUnload() {
+ this.skipBeforeUnload = true;
+ },
openFile(file) {
this.$router.push(this.getUrlForPath(file.path));
},
diff --git a/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue b/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue
index 6f42ae48cc9..bf99538a2ad 100644
--- a/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue
+++ b/app/assets/javascripts/ide/components/panes/collapsible_sidebar.vue
@@ -13,6 +13,11 @@ export default {
required: false,
default: () => [],
},
+ initOpenView: {
+ type: String,
+ required: false,
+ default: '',
+ },
side: {
type: String,
required: true,
@@ -44,6 +49,9 @@ export default {
return this.tabViews.filter((view) => this.isAliveView(view.name));
},
},
+ created() {
+ this.openViewByName(this.initOpenView);
+ },
methods: {
...mapActions({
toggleOpen(dispatch) {
@@ -53,6 +61,13 @@ export default {
return dispatch(`${this.namespace}/open`, view);
},
}),
+ openViewByName(viewName) {
+ const view = viewName && this.tabViews.find((x) => x.name === viewName);
+
+ if (view) {
+ this.open(view);
+ }
+ },
},
};
</script>
diff --git a/app/assets/javascripts/ide/components/panes/right.vue b/app/assets/javascripts/ide/components/panes/right.vue
index da2d4fbe7f0..c74a5052573 100644
--- a/app/assets/javascripts/ide/components/panes/right.vue
+++ b/app/assets/javascripts/ide/components/panes/right.vue
@@ -7,6 +7,7 @@ import PipelinesList from '../pipelines/list.vue';
import Clientside from '../preview/clientside.vue';
import ResizablePanel from '../resizable_panel.vue';
import TerminalView from '../terminal/view.vue';
+import SwitchEditorsView from '../switch_editors/switch_editors_view.vue';
import CollapsibleSidebar from './collapsible_sidebar.vue';
// Need to add the width of the nav buttons since the resizable container contains those as well
@@ -20,7 +21,7 @@ export default {
},
computed: {
...mapState('terminal', { isTerminalVisible: 'isVisible' }),
- ...mapState(['currentMergeRequestId', 'clientsidePreviewEnabled']),
+ ...mapState(['currentMergeRequestId', 'clientsidePreviewEnabled', 'canUseNewWebIde']),
...mapGetters(['packageJson']),
...mapState('rightPane', ['isOpen']),
showLivePreview() {
@@ -29,6 +30,12 @@ export default {
rightExtensionTabs() {
return [
{
+ show: this.canUseNewWebIde,
+ title: __('Switch editors'),
+ views: [{ component: SwitchEditorsView, ...rightSidebarViews.switchEditors }],
+ icon: 'bullhorn',
+ },
+ {
show: true,
title: __('Pipelines'),
views: [
@@ -53,6 +60,7 @@ export default {
},
},
WIDTH,
+ SWITCH_EDITORS_VIEW_NAME: rightSidebarViews.switchEditors.name,
};
</script>
@@ -64,6 +72,11 @@ export default {
:min-size="$options.WIDTH"
:resizable="isOpen"
>
- <collapsible-sidebar class="gl-w-full" :extension-tabs="rightExtensionTabs" side="right" />
+ <collapsible-sidebar
+ class="gl-w-full"
+ :extension-tabs="rightExtensionTabs"
+ :init-open-view="$options.SWITCH_EDITORS_VIEW_NAME"
+ side="right"
+ />
</resizable-panel>
</template>
diff --git a/app/assets/javascripts/ide/components/switch_editors/switch_editors_view.vue b/app/assets/javascripts/ide/components/switch_editors/switch_editors_view.vue
new file mode 100644
index 00000000000..00164f65e33
--- /dev/null
+++ b/app/assets/javascripts/ide/components/switch_editors/switch_editors_view.vue
@@ -0,0 +1,103 @@
+<script>
+import { GlButton, GlEmptyState, GlLink } from '@gitlab/ui';
+import { mapState } from 'vuex';
+import { createAlert } from '~/flash';
+import { logError } from '~/lib/logger';
+import axios from '~/lib/utils/axios_utils';
+import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
+import { ignoreWhilePending } from '~/lib/utils/ignore_while_pending';
+import { s__, __ } from '~/locale';
+import eventHub from '../../eventhub';
+
+export const MSG_DESCRIPTION = s__('WebIDE|You are invited to experience the new Web IDE.');
+export const MSG_BUTTON_TEXT = s__('WebIDE|Switch to new Web IDE');
+export const MSG_LEARN_MORE = __('Learn more');
+export const MSG_TITLE = s__('WebIDE|Ready for something new?');
+
+export const MSG_CONFIRM = s__(
+ 'WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes.',
+);
+export const MSG_ERROR_ALERT = s__(
+ 'WebIDE|Something went wrong while updating the user preferences. Please see developer console for details.',
+);
+
+export default {
+ components: {
+ GlButton,
+ GlEmptyState,
+ GlLink,
+ },
+ data() {
+ return {
+ loading: false,
+ };
+ },
+ computed: {
+ ...mapState(['switchEditorSvgPath', 'links', 'userPreferencesPath']),
+ },
+ methods: {
+ async submitSwitch() {
+ const confirmed = await confirmAction(MSG_CONFIRM, {
+ primaryBtnText: __('Switch editors'),
+ cancelBtnText: __('Cancel'),
+ });
+
+ if (!confirmed) {
+ return;
+ }
+
+ try {
+ await axios.put(this.userPreferencesPath, {
+ user: { use_legacy_web_ide: false },
+ });
+ } catch (e) {
+ // why: We do not want to translate console logs
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ logError('Error while updating user preferences', e);
+ createAlert({
+ message: MSG_ERROR_ALERT,
+ });
+ return;
+ }
+
+ eventHub.$emit('skip-beforeunload');
+ window.location.reload();
+ },
+ // what: ignoreWhilePending prevents double confirmation boxes
+ onSwitchClicked: ignoreWhilePending(async function onSwitchClicked() {
+ this.loading = true;
+
+ try {
+ await this.submitSwitch();
+ } finally {
+ this.loading = false;
+ }
+ }),
+ },
+ MSG_TITLE,
+ MSG_DESCRIPTION,
+ MSG_BUTTON_TEXT,
+ MSG_LEARN_MORE,
+};
+</script>
+
+<template>
+ <div class="gl-h-full gl-display-flex gl-flex-direction-column gl-justify-content-center">
+ <gl-empty-state :svg-path="switchEditorSvgPath" :svg-height="150" :title="$options.MSG_TITLE">
+ <template #description>
+ <span>{{ $options.MSG_DESCRIPTION }}</span>
+ <gl-link :href="links.newWebIDEHelpPagePath">{{ $options.MSG_LEARN_MORE }}</gl-link
+ >.
+ </template>
+ <template #actions>
+ <gl-button
+ category="primary"
+ variant="confirm"
+ :loading="loading"
+ @click="onSwitchClicked"
+ >{{ $options.MSG_BUTTON_TEXT }}</gl-button
+ >
+ </template>
+ </gl-empty-state>
+ </div>
+</template>
diff --git a/app/assets/javascripts/ide/constants.js b/app/assets/javascripts/ide/constants.js
index bfe4c3ac271..c8e737fa6f5 100644
--- a/app/assets/javascripts/ide/constants.js
+++ b/app/assets/javascripts/ide/constants.js
@@ -61,6 +61,7 @@ export const leftSidebarViews = {
};
export const rightSidebarViews = {
+ switchEditors: { name: 'switch-editors', keepAlive: true },
pipelines: { name: 'pipelines-list', keepAlive: true },
jobsDetail: { name: 'jobs-detail', keepAlive: false },
mergeRequestInfo: { name: 'merge-request-info', keepAlive: true },
diff --git a/app/assets/javascripts/ide/index.js b/app/assets/javascripts/ide/index.js
index 1a191f6f76f..dec282239d9 100644
--- a/app/assets/javascripts/ide/index.js
+++ b/app/assets/javascripts/ide/index.js
@@ -60,9 +60,11 @@ export const initLegacyWebIDE = (el, options = {}) => {
committedStateSvgPath: el.dataset.committedStateSvgPath,
pipelinesEmptyStateSvgPath: el.dataset.pipelinesEmptyStateSvgPath,
promotionSvgPath: el.dataset.promotionSvgPath,
+ switchEditorSvgPath: el.dataset.switchEditorSvgPath,
});
this.setLinks({
webIDEHelpPagePath: el.dataset.webIdeHelpPagePath,
+ newWebIDEHelpPagePath: el.dataset.newWebIdeHelpPagePath,
forkInfo: el.dataset.forkInfo ? JSON.parse(el.dataset.forkInfo) : null,
});
this.init({
@@ -72,6 +74,8 @@ export const initLegacyWebIDE = (el, options = {}) => {
codesandboxBundlerUrl: el.dataset.codesandboxBundlerUrl,
environmentsGuidanceAlertDismissed: !parseBoolean(el.dataset.enableEnvironmentsGuidance),
previewMarkdownPath: el.dataset.previewMarkdownPath,
+ canUseNewWebIde: parseBoolean(el.dataset.canUseNewWebIde),
+ userPreferencesPath: el.dataset.userPreferencesPath,
});
},
beforeDestroy() {
diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js
index 48648796e66..d11fc388d5e 100644
--- a/app/assets/javascripts/ide/stores/mutations.js
+++ b/app/assets/javascripts/ide/stores/mutations.js
@@ -110,6 +110,7 @@ export default {
committedStateSvgPath,
pipelinesEmptyStateSvgPath,
promotionSvgPath,
+ switchEditorSvgPath,
},
) {
Object.assign(state, {
@@ -118,6 +119,7 @@ export default {
committedStateSvgPath,
pipelinesEmptyStateSvgPath,
promotionSvgPath,
+ switchEditorSvgPath,
});
},
[types.TOGGLE_FILE_FINDER](state, fileFindVisible) {
diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js
index 526987c750a..70efda970bf 100644
--- a/app/assets/javascripts/ide/stores/state.js
+++ b/app/assets/javascripts/ide/stores/state.js
@@ -33,4 +33,6 @@ export default () => ({
environmentsGuidanceAlertDismissed: false,
environmentsGuidanceAlertDetected: false,
previewMarkdownPath: '',
+ userPreferencesPath: '',
+ canUseNewWebIde: false,
});
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 0cdd64b1b98..66dff77eef8 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
@@ -10,6 +10,7 @@ import {
GlSprintf,
GlTable,
GlFormCheckbox,
+ GlTooltipDirective,
} from '@gitlab/ui';
import { debounce } from 'lodash';
import { createAlert } from '~/flash';
@@ -60,7 +61,9 @@ export default {
PaginationBar,
HelpPopover,
},
-
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
props: {
sourceUrl: {
type: String,
@@ -118,14 +121,14 @@ export default {
},
{
key: 'webUrl',
- label: s__('BulkImport|From source group'),
+ label: s__('BulkImport|Source group'),
thClass: `${DEFAULT_TH_CLASSES} gl-pl-0! import-jobs-from-col`,
// eslint-disable-next-line @gitlab/require-i18n-strings
tdClass: `${DEFAULT_TD_CLASSES} gl-pl-0!`,
},
{
key: 'importTarget',
- label: s__('BulkImport|To new group'),
+ label: s__('BulkImport|New group'),
thClass: `${DEFAULT_TH_CLASSES} import-jobs-to-col`,
tdClass: DEFAULT_TD_CLASSES,
},
@@ -665,6 +668,16 @@ export default {
@change="hasAllAvailableGroupsSelected ? clearSelected() : selectAllRows()"
/>
</template>
+ <template #head(importTarget)="data">
+ <span data-test-id="new-path-col">
+ <span class="gl-mr-2">{{ data.label }}</span
+ ><gl-icon
+ v-gl-tooltip="s__('BulkImport|Path of the new group.')"
+ name="information"
+ :size="12"
+ />
+ </span>
+ </template>
<template #cell(selected)="{ rowSelected, selectRow, unselectRow, item: group }">
<gl-form-checkbox
class="gl-h-7 gl-pt-3"
diff --git a/app/assets/javascripts/import_entities/import_projects/components/advanced_settings.vue b/app/assets/javascripts/import_entities/import_projects/components/advanced_settings.vue
index a8fdf9b9ec5..cf1a4de68ed 100644
--- a/app/assets/javascripts/import_entities/import_projects/components/advanced_settings.vue
+++ b/app/assets/javascripts/import_entities/import_projects/components/advanced_settings.vue
@@ -40,6 +40,8 @@ export default {
v-for="{ name, label, details } in stages"
:key="name"
:checked="value[name]"
+ :data-qa-option-name="name"
+ data-qa-selector="advanced_settings_checkbox"
@change="$emit('input', { ...value, [name]: $event })"
>
{{ label }}
diff --git a/app/assets/javascripts/import_entities/import_projects/index.js b/app/assets/javascripts/import_entities/import_projects/index.js
index 4daa9e8a1b8..df26d6ac4f6 100644
--- a/app/assets/javascripts/import_entities/import_projects/index.js
+++ b/app/assets/javascripts/import_entities/import_projects/index.js
@@ -39,7 +39,7 @@ export function initStoreFromElement(element) {
export function initPropsFromElement(element) {
return {
- providerTitle: element.dataset.provider,
+ providerTitle: element.dataset.providerTitle,
filterable: parseBoolean(element.dataset.filterable),
paginatable: parseBoolean(element.dataset.paginatable),
optionalStages: JSON.parse(element.dataset.optionalStages),
diff --git a/app/assets/javascripts/integrations/constants.js b/app/assets/javascripts/integrations/constants.js
index 2806b785816..392dd63b089 100644
--- a/app/assets/javascripts/integrations/constants.js
+++ b/app/assets/javascripts/integrations/constants.js
@@ -85,10 +85,12 @@ export const billingPlanNames = {
};
const INTEGRATION_TYPE_SLACK = 'slack';
+const INTEGRATION_TYPE_SLACK_APPLICATION = 'gitlab_slack_application';
const INTEGRATION_TYPE_MATTERMOST = 'mattermost';
export const placeholderForType = {
[INTEGRATION_TYPE_SLACK]: __('#general, #development'),
+ [INTEGRATION_TYPE_SLACK_APPLICATION]: __('#general, #development'),
[INTEGRATION_TYPE_MATTERMOST]: __('my-channel'),
};
diff --git a/app/assets/javascripts/integrations/edit/components/integration_form.vue b/app/assets/javascripts/integrations/edit/components/integration_form.vue
index 15f76c16516..4bf2b8d4468 100644
--- a/app/assets/javascripts/integrations/edit/components/integration_form.vue
+++ b/app/assets/javascripts/integrations/edit/components/integration_form.vue
@@ -1,5 +1,6 @@
<script>
import {
+ GlAlert,
GlBadge,
GlButton,
GlModalDirective,
@@ -9,7 +10,7 @@ import {
import axios from 'axios';
import * as Sentry from '@sentry/browser';
import { mapState, mapActions, mapGetters } from 'vuex';
-
+import { s__ } from '~/locale';
import {
I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE,
I18N_DEFAULT_ERROR_MESSAGE,
@@ -59,6 +60,7 @@ export default {
import(
/* webpackChunkName: 'integrationSectionTrigger' */ '~/integrations/edit/components/sections/trigger.vue'
),
+ GlAlert,
GlBadge,
GlButton,
GlForm,
@@ -223,6 +225,12 @@ export default {
csrf,
integrationFormSectionComponents,
billingPlanNames,
+ slackUpgradeInfo: {
+ title: s__(
+ `SlackIntegration|Notifications only work if you're on the latest version of the GitLab for Slack app`,
+ ),
+ btnText: s__('SlackIntegration|Update to the latest version'),
+ },
};
</script>
@@ -277,6 +285,15 @@ export default {
</section>
<template v-if="hasSections">
+ <div v-if="customState.shouldUpgradeSlack && isSlackIntegration" class="gl-border-t">
+ <gl-alert
+ :title="$options.slackUpgradeInfo.title"
+ variant="warning"
+ :primary-button-link="customState.upgradeSlackUrl"
+ :primary-button-text="$options.slackUpgradeInfo.btnText"
+ class="gl-mb-8 gl-mt-5"
+ />
+ </div>
<div
v-for="(section, index) in customState.sections"
:key="section.type"
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 403bad3db11..41cd650f932 100644
--- a/app/assets/javascripts/integrations/edit/components/reset_confirmation_modal.vue
+++ b/app/assets/javascripts/integrations/edit/components/reset_confirmation_modal.vue
@@ -7,18 +7,12 @@ export default {
components: {
GlModal,
},
- computed: {
- primaryProps() {
- return {
- text: __('Reset'),
- attributes: [{ variant: 'danger' }, { category: 'primary' }],
- };
- },
- cancelProps() {
- return {
- text: __('Cancel'),
- };
- },
+ primaryProps: {
+ text: __('Reset'),
+ attributes: [{ variant: 'danger' }, { category: 'primary' }],
+ },
+ cancelProps: {
+ text: __('Cancel'),
},
methods: {
onReset() {
@@ -33,8 +27,8 @@ export default {
modal-id="confirmResetIntegration"
size="sm"
:title="s__('Integrations|Reset integration?')"
- :action-primary="primaryProps"
- :action-cancel="cancelProps"
+ :action-primary="$options.primaryProps"
+ :action-cancel="$options.cancelProps"
@primary="onReset"
>
<p>
diff --git a/app/assets/javascripts/integrations/edit/components/trigger_fields.vue b/app/assets/javascripts/integrations/edit/components/trigger_fields.vue
index 67647cadf19..3820a87e5ad 100644
--- a/app/assets/javascripts/integrations/edit/components/trigger_fields.vue
+++ b/app/assets/javascripts/integrations/edit/components/trigger_fields.vue
@@ -23,7 +23,7 @@ export default {
},
computed: {
...mapGetters(['isInheriting']),
- placeholder() {
+ defaultPlaceholder() {
return placeholderForType[this.type];
},
},
@@ -55,7 +55,7 @@ export default {
v-if="event.field"
v-model="event.field.value"
:name="fieldName(event.field.name)"
- :placeholder="placeholder"
+ :placeholder="event.field.placeholder || defaultPlaceholder"
:readonly="isInheriting"
/>
</gl-form-group>
diff --git a/app/assets/javascripts/integrations/edit/index.js b/app/assets/javascripts/integrations/edit/index.js
index 2360588ab39..f15ad5e052e 100644
--- a/app/assets/javascripts/integrations/edit/index.js
+++ b/app/assets/javascripts/integrations/edit/index.js
@@ -36,6 +36,7 @@ function parseDatasetToProps(data) {
jiraIssueTransitionAutomatic,
jiraIssueTransitionId,
redirectTo,
+ upgradeSlackUrl,
...booleanAttributes
} = data;
const {
@@ -51,6 +52,7 @@ function parseDatasetToProps(data) {
showJiraVulnerabilitiesIntegration,
enableJiraIssues,
enableJiraVulnerabilities,
+ shouldUpgradeSlack,
} = parseBooleanInData(booleanAttributes);
return {
@@ -89,6 +91,8 @@ function parseDatasetToProps(data) {
integrationLevel,
id: parseInt(id, 10),
redirectTo,
+ shouldUpgradeSlack,
+ upgradeSlackUrl,
};
}
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 a334f5e4bf7..f61e822bf7e 100644
--- a/app/assets/javascripts/invite_members/components/invite_members_modal.vue
+++ b/app/assets/javascripts/invite_members/components/invite_members_modal.vue
@@ -18,7 +18,8 @@ import { BV_SHOW_MODAL, BV_HIDE_MODAL } from '~/lib/utils/constants';
import { getParameterValues } from '~/lib/utils/url_utility';
import { n__, sprintf } from '~/locale';
import {
- CLOSE_TO_LIMIT_COUNT,
+ CLOSE_TO_LIMIT_VARIANT,
+ REACHED_LIMIT_VARIANT,
USERS_FILTER_ALL,
INVITE_MEMBERS_FOR_TASK,
MEMBER_MODAL_LABELS,
@@ -174,27 +175,11 @@ export default {
isOnLearnGitlab() {
return this.source === LEARN_GITLAB;
},
- closeToLimit() {
- if (this.usersLimitDataset.freeUsersLimit && this.usersLimitDataset.membersCount) {
- return (
- this.usersLimitDataset.membersCount >=
- this.usersLimitDataset.freeUsersLimit - CLOSE_TO_LIMIT_COUNT
- );
- }
-
- return false;
- },
- reachedLimit() {
- if (this.usersLimitDataset.freeUsersLimit && this.usersLimitDataset.membersCount) {
- return this.usersLimitDataset.membersCount >= this.usersLimitDataset.freeUsersLimit;
- }
-
- return false;
+ showUserLimitNotification() {
+ return this.usersLimitDataset.reachedLimit || this.usersLimitDataset.closeToDashboardLimit;
},
- formGroupDescription() {
- return this.reachedLimit
- ? this.$options.labels.placeHolderDisabled
- : this.$options.labels.placeHolder;
+ limitVariant() {
+ return this.usersLimitDataset.reachedLimit ? REACHED_LIMIT_VARIANT : CLOSE_TO_LIMIT_VARIANT;
},
errorList() {
return Object.entries(this.invalidMembers).map(([member, error]) => {
@@ -385,13 +370,11 @@ export default {
:help-link="helpLink"
:label-intro-text="labelIntroText"
:label-search-field="$options.labels.searchField"
- :form-group-description="formGroupDescription"
+ :form-group-description="$options.labels.placeHolder"
:invalid-feedback-message="invalidFeedbackMessage"
:is-loading="isLoading"
:new-users-to-invite="newUsersToInvite"
:root-group-id="rootId"
- :close-to-limit="closeToLimit"
- :reached-limit="reachedLimit"
:users-limit-dataset="usersLimitDataset"
@reset="resetFields"
@submit="sendInvite"
@@ -448,9 +431,8 @@ export default {
</template>
</gl-alert>
<user-limit-notification
- v-else
- :close-to-limit="closeToLimit"
- :reached-limit="reachedLimit"
+ v-else-if="showUserLimitNotification"
+ :limit-variant="limitVariant"
:users-limit-dataset="usersLimitDataset"
/>
</template>
diff --git a/app/assets/javascripts/invite_members/components/invite_modal_base.vue b/app/assets/javascripts/invite_members/components/invite_modal_base.vue
index f917ebc35c2..e3511a49fc5 100644
--- a/app/assets/javascripts/invite_members/components/invite_modal_base.vue
+++ b/app/assets/javascripts/invite_members/components/invite_modal_base.vue
@@ -8,7 +8,6 @@ import {
GlLink,
GlSprintf,
GlFormInput,
- GlIcon,
} from '@gitlab/ui';
import Tracking from '~/tracking';
import { sprintf } from '~/locale';
@@ -20,11 +19,8 @@ import {
INVITE_BUTTON_TEXT,
INVITE_BUTTON_TEXT_DISABLED,
CANCEL_BUTTON_TEXT,
- CANCEL_BUTTON_TEXT_DISABLED,
HEADER_CLOSE_LABEL,
ON_SHOW_TRACK_LABEL,
- ON_CLOSE_TRACK_LABEL,
- ON_SUBMIT_TRACK_LABEL,
} from '../constants';
const DEFAULT_SLOT = 'default';
@@ -48,7 +44,6 @@ export default {
GlDropdownItem,
GlSprintf,
GlFormInput,
- GlIcon,
ContentTransition,
},
mixins: [Tracking.mixin()],
@@ -131,16 +126,6 @@ export default {
required: false,
default: false,
},
- closeToLimit: {
- type: Boolean,
- required: false,
- default: false,
- },
- reachedLimit: {
- type: Boolean,
- required: false,
- default: false,
- },
usersLimitDataset: {
type: Object,
required: false,
@@ -175,20 +160,17 @@ export default {
},
actionPrimary() {
return {
- text: this.reachedLimit ? INVITE_BUTTON_TEXT_DISABLED : this.submitButtonText,
+ text: this.submitButtonText,
attributes: {
variant: 'confirm',
- disabled: this.reachedLimit ? false : this.submitDisabled,
- loading: this.reachedLimit ? false : this.isLoading,
+ disabled: this.submitDisabled,
+ loading: this.isLoading,
'data-qa-selector': 'invite_button',
- ...(this.reachedLimit && { href: this.usersLimitDataset.membersPath }),
},
};
},
actionCancel() {
- if (this.reachedLimit && this.usersLimitDataset.userNamespace) return undefined;
-
- if (this.closeToLimit && this.usersLimitDataset.userNamespace) {
+ if (this.usersLimitDataset.closeToDashboardLimit && this.usersLimitDataset.userNamespace) {
return {
text: INVITE_BUTTON_TEXT_DISABLED,
attributes: {
@@ -200,13 +182,9 @@ export default {
}
return {
- text: this.reachedLimit ? CANCEL_BUTTON_TEXT_DISABLED : this.cancelButtonText,
- ...(this.reachedLimit && { attributes: { href: this.usersLimitDataset.purchasePath } }),
+ text: this.cancelButtonText,
};
},
- selectLabelClass() {
- return `col-form-label ${this.reachedLimit ? 'gl-text-gray-500' : ''}`;
- },
},
watch: {
selectedAccessLevel: {
@@ -226,23 +204,19 @@ export default {
this.$emit('reset');
},
onShowModal() {
- if (this.reachedLimit) {
+ if (this.usersLimitDataset.reachedLimit) {
this.track('render', { category: 'default', label: ON_SHOW_TRACK_LABEL });
}
},
onCloseModal(e) {
- if (this.preventCancelDefault || this.reachedLimit) {
+ if (this.preventCancelDefault) {
e.preventDefault();
} else {
this.onReset();
this.$refs.modal.hide();
}
- if (this.reachedLimit) {
- this.track('click_button', { category: 'default', label: ON_CLOSE_TRACK_LABEL });
- } else {
- this.$emit('cancel');
- }
+ this.$emit('cancel');
},
changeSelectedItem(item) {
this.selectedAccessLevel = item;
@@ -251,14 +225,10 @@ export default {
// We never want to hide when submitting
e.preventDefault();
- if (this.reachedLimit) {
- this.track('click_button', { category: 'default', label: ON_SUBMIT_TRACK_LABEL });
- } else {
- this.$emit('submit', {
- accessLevel: this.selectedAccessLevel,
- expiresAt: this.selectedDate,
- });
- }
+ this.$emit('submit', {
+ accessLevel: this.selectedAccessLevel,
+ expiresAt: this.selectedDate,
+ });
},
},
HEADER_CLOSE_LABEL,
@@ -311,71 +281,63 @@ export default {
<gl-form-group
:invalid-feedback="invalidFeedbackMessage"
:state="exceptionState"
+ :description="formGroupDescription"
data-testid="members-form-group"
>
- <template #description>
- <gl-icon v-if="reachedLimit" name="lock" />
- {{ formGroupDescription }}
- </template>
-
- <label :id="selectLabelId" :class="selectLabelClass">{{ labelSearchField }}</label>
- <gl-form-input v-if="reachedLimit" data-testid="disabled-input" disabled />
- <slot v-else name="select" v-bind="{ exceptionState, labelId: selectLabelId }"></slot>
+ <label :id="selectLabelId" class="col-form-label">{{ labelSearchField }}</label>
+ <slot name="select" v-bind="{ exceptionState, labelId: selectLabelId }"></slot>
</gl-form-group>
- <template v-if="!reachedLimit">
- <label class="gl-font-weight-bold">{{ $options.ACCESS_LEVEL }}</label>
-
- <div class="gl-mt-2 gl-w-half gl-xs-w-full">
- <gl-dropdown
- class="gl-shadow-none gl-w-full"
- data-qa-selector="access_level_dropdown"
- v-bind="$attrs"
- :text="selectedRoleName"
- >
- <template v-for="(key, item) in accessLevels">
- <gl-dropdown-item
- :key="key"
- active-class="is-active"
- is-check-item
- :is-checked="key === selectedAccessLevel"
- @click="changeSelectedItem(key)"
- >
- <div>{{ item }}</div>
- </gl-dropdown-item>
- </template>
- </gl-dropdown>
- </div>
+ <label class="gl-font-weight-bold">{{ $options.ACCESS_LEVEL }}</label>
+ <div class="gl-mt-2 gl-w-half gl-xs-w-full">
+ <gl-dropdown
+ class="gl-shadow-none gl-w-full"
+ data-qa-selector="access_level_dropdown"
+ v-bind="$attrs"
+ :text="selectedRoleName"
+ >
+ <template v-for="(key, item) in accessLevels">
+ <gl-dropdown-item
+ :key="key"
+ active-class="is-active"
+ is-check-item
+ :is-checked="key === selectedAccessLevel"
+ @click="changeSelectedItem(key)"
+ >
+ <div>{{ item }}</div>
+ </gl-dropdown-item>
+ </template>
+ </gl-dropdown>
+ </div>
- <div class="gl-mt-2 gl-w-half gl-xs-w-full">
- <gl-sprintf :message="$options.READ_MORE_TEXT">
- <template #link="{ content }">
- <gl-link :href="helpLink" target="_blank">{{ content }}</gl-link>
- </template>
- </gl-sprintf>
- </div>
+ <div class="gl-mt-2 gl-w-half gl-xs-w-full">
+ <gl-sprintf :message="$options.READ_MORE_TEXT">
+ <template #link="{ content }">
+ <gl-link :href="helpLink" target="_blank">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </div>
- <label class="gl-mt-5 gl-display-block" for="expires_at">{{
- $options.ACCESS_EXPIRE_DATE
- }}</label>
- <div class="gl-mt-2 gl-w-half gl-xs-w-full gl-display-inline-block">
- <gl-datepicker
- v-model="selectedDate"
- class="gl-display-inline!"
- :min-date="minDate"
- :target="null"
- >
- <template #default="{ formattedDate }">
- <gl-form-input
- class="gl-w-full"
- :value="formattedDate"
- :placeholder="__(`YYYY-MM-DD`)"
- />
- </template>
- </gl-datepicker>
- </div>
- <slot name="form-after"></slot>
- </template>
+ <label class="gl-mt-5 gl-display-block" for="expires_at">{{
+ $options.ACCESS_EXPIRE_DATE
+ }}</label>
+ <div class="gl-mt-2 gl-w-half gl-xs-w-full gl-display-inline-block">
+ <gl-datepicker
+ v-model="selectedDate"
+ class="gl-display-inline!"
+ :min-date="minDate"
+ :target="null"
+ >
+ <template #default="{ formattedDate }">
+ <gl-form-input
+ class="gl-w-full"
+ :value="formattedDate"
+ :placeholder="__(`YYYY-MM-DD`)"
+ />
+ </template>
+ </gl-datepicker>
+ </div>
+ <slot name="form-after"></slot>
</template>
<template v-for="{ key } in extraSlots" #[key]>
diff --git a/app/assets/javascripts/invite_members/components/user_limit_notification.vue b/app/assets/javascripts/invite_members/components/user_limit_notification.vue
index c3d9d959ef6..515dd3de319 100644
--- a/app/assets/javascripts/invite_members/components/user_limit_notification.vue
+++ b/app/assets/javascripts/invite_members/components/user_limit_notification.vue
@@ -5,9 +5,10 @@ import { n__, sprintf } from '~/locale';
import {
WARNING_ALERT_TITLE,
DANGER_ALERT_TITLE,
- REACHED_LIMIT_MESSAGE,
REACHED_LIMIT_UPGRADE_SUGGESTION_MESSAGE,
+ REACHED_LIMIT_VARIANT,
CLOSE_TO_LIMIT_MESSAGE,
+ CLOSE_TO_LIMIT_VARIANT,
} from '../constants';
export default {
@@ -15,87 +16,71 @@ export default {
components: { GlAlert, GlSprintf, GlLink },
inject: ['name'],
props: {
- closeToLimit: {
- type: Boolean,
- required: true,
- },
- reachedLimit: {
- type: Boolean,
+ limitVariant: {
+ type: String,
required: true,
},
usersLimitDataset: {
type: Object,
- required: false,
- default: () => ({}),
+ required: true,
},
},
computed: {
- freeUsersLimit() {
- return this.usersLimitDataset.freeUsersLimit;
- },
- membersCount() {
- return this.usersLimitDataset.membersCount;
- },
- newTrialRegistrationPath() {
- return this.usersLimitDataset.newTrialRegistrationPath;
- },
- purchasePath() {
- return this.usersLimitDataset.purchasePath;
- },
- warningAlertTitle() {
- return sprintf(WARNING_ALERT_TITLE, {
- count: this.freeUsersLimit - this.membersCount,
- members: this.pluralMembers(this.freeUsersLimit - this.membersCount),
- name: this.name,
- });
- },
- dangerAlertTitle() {
- return sprintf(DANGER_ALERT_TITLE, {
- count: this.freeUsersLimit,
- members: this.pluralMembers(this.freeUsersLimit),
- name: this.name,
- });
- },
- variant() {
- return this.reachedLimit ? 'danger' : 'warning';
- },
- title() {
- return this.reachedLimit ? this.dangerAlertTitle : this.warningAlertTitle;
- },
- message() {
- if (this.reachedLimit) {
- return this.$options.i18n.reachedLimitUpgradeSuggestionMessage;
- }
-
- return this.$options.i18n.closeToLimitMessage;
+ limitAttributes() {
+ return {
+ [CLOSE_TO_LIMIT_VARIANT]: {
+ variant: 'warning',
+ title: this.title(WARNING_ALERT_TITLE, this.usersLimitDataset.remainingSeats),
+ message: CLOSE_TO_LIMIT_MESSAGE,
+ },
+ [REACHED_LIMIT_VARIANT]: {
+ variant: 'danger',
+ title: this.title(DANGER_ALERT_TITLE, this.usersLimitDataset.freeUsersLimit),
+ message: REACHED_LIMIT_UPGRADE_SUGGESTION_MESSAGE,
+ },
+ };
},
},
methods: {
- pluralMembers(count) {
- return n__('member', 'members', count);
+ title(titleTemplate, count) {
+ return sprintf(titleTemplate, {
+ count,
+ members: n__('member', 'members', count),
+ name: this.name,
+ });
},
},
- i18n: {
- reachedLimitMessage: REACHED_LIMIT_MESSAGE,
- reachedLimitUpgradeSuggestionMessage: REACHED_LIMIT_UPGRADE_SUGGESTION_MESSAGE,
- closeToLimitMessage: CLOSE_TO_LIMIT_MESSAGE,
- },
};
</script>
<template>
<gl-alert
- v-if="reachedLimit || closeToLimit"
- :variant="variant"
+ :variant="limitAttributes[limitVariant].variant"
:dismissible="false"
- :title="title"
+ :title="limitAttributes[limitVariant].title"
>
- <gl-sprintf :message="message">
+ <gl-sprintf :message="limitAttributes[limitVariant].message">
<template #trialLink="{ content }">
- <gl-link :href="newTrialRegistrationPath" class="gl-label-link">{{ content }}</gl-link>
+ <gl-link
+ :href="usersLimitDataset.newTrialRegistrationPath"
+ class="gl-label-link"
+ data-track-action="click_link"
+ :data-track-label="`start_trial_user_limit_notification_${limitVariant}`"
+ data-testid="trial-link"
+ >
+ {{ content }}
+ </gl-link>
</template>
<template #upgradeLink="{ content }">
- <gl-link :href="purchasePath" class="gl-label-link">{{ content }}</gl-link>
+ <gl-link
+ :href="usersLimitDataset.purchasePath"
+ class="gl-label-link"
+ data-track-action="click_link"
+ :data-track-label="`upgrade_user_limit_notification_${limitVariant}`"
+ data-testid="upgrade-link"
+ >
+ {{ content }}
+ </gl-link>
</template>
</gl-sprintf>
</gl-alert>
diff --git a/app/assets/javascripts/invite_members/constants.js b/app/assets/javascripts/invite_members/constants.js
index f502e1ea369..de7b1019782 100644
--- a/app/assets/javascripts/invite_members/constants.js
+++ b/app/assets/javascripts/invite_members/constants.js
@@ -1,6 +1,5 @@
import { s__ } from '~/locale';
-export const CLOSE_TO_LIMIT_COUNT = 2;
export const SEARCH_DELAY = 200;
export const VALID_TOKEN_BACKGROUND = 'gl-bg-green-100';
export const INVALID_TOKEN_BACKGROUND = 'gl-bg-red-100';
@@ -40,9 +39,6 @@ export const MEMBERS_TO_PROJECT_CELEBRATE_INTRO_TEXT = s__(
);
export const MEMBERS_SEARCH_FIELD = s__('InviteMembersModal|Username or email address');
export const MEMBERS_PLACEHOLDER = s__('InviteMembersModal|Select members or type email addresses');
-export const MEMBERS_PLACEHOLDER_DISABLED = s__(
- 'InviteMembersModal|This feature is disabled until this group has space for more members.',
-);
export const MEMBERS_TASKS_TO_BE_DONE_TITLE = s__(
'InviteMembersModal|Create issues for your new team member to work on (optional)',
);
@@ -110,7 +106,6 @@ export const MEMBER_MODAL_LABELS = {
},
searchField: MEMBERS_SEARCH_FIELD,
placeHolder: MEMBERS_PLACEHOLDER,
- placeHolderDisabled: MEMBERS_PLACEHOLDER_DISABLED,
tasksToBeDone: {
title: MEMBERS_TASKS_TO_BE_DONE_TITLE,
noProjects: MEMBERS_TASKS_TO_BE_DONE_NO_PROJECTS,
@@ -139,9 +134,7 @@ export const GROUP_MODAL_LABELS = {
};
export const LEARN_GITLAB = 'learn_gitlab';
-export const ON_SHOW_TRACK_LABEL = 'locked_modal_viewed';
-export const ON_CLOSE_TRACK_LABEL = 'explore_paid_plans_clicked';
-export const ON_SUBMIT_TRACK_LABEL = 'manage_members_clicked';
+export const ON_SHOW_TRACK_LABEL = 'over_limit_modal_viewed';
export const WARNING_ALERT_TITLE = s__(
'InviteMembersModal|You only have space for %{count} more %{members} in %{name}',
@@ -150,13 +143,16 @@ export const DANGER_ALERT_TITLE = s__(
"InviteMembersModal|You've reached your %{count} %{members} limit for %{name}",
);
+export const REACHED_LIMIT_VARIANT = 'reached';
+export const CLOSE_TO_LIMIT_VARIANT = 'close';
+
export const REACHED_LIMIT_MESSAGE = s__(
- 'InviteMembersModal|You cannot add more members, but you can remove members who no longer need access.',
+ 'InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users.',
);
export const REACHED_LIMIT_UPGRADE_SUGGESTION_MESSAGE = REACHED_LIMIT_MESSAGE.concat(
s__(
- 'InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier.',
+ 'InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier.',
),
);
diff --git a/app/assets/javascripts/issuable/bulk_update_sidebar/components/graphql/mutations/move_issue.mutation.graphql b/app/assets/javascripts/issuable/bulk_update_sidebar/components/graphql/mutations/move_issue.mutation.graphql
new file mode 100644
index 00000000000..d350072425b
--- /dev/null
+++ b/app/assets/javascripts/issuable/bulk_update_sidebar/components/graphql/mutations/move_issue.mutation.graphql
@@ -0,0 +1,5 @@
+mutation moveIssue($moveIssueInput: IssueMoveInput!) {
+ issueMove(input: $moveIssueInput) {
+ errors
+ }
+}
diff --git a/app/assets/javascripts/issuable/bulk_update_sidebar/components/move_issues_button.vue b/app/assets/javascripts/issuable/bulk_update_sidebar/components/move_issues_button.vue
new file mode 100644
index 00000000000..6e287ac3bb7
--- /dev/null
+++ b/app/assets/javascripts/issuable/bulk_update_sidebar/components/move_issues_button.vue
@@ -0,0 +1,171 @@
+<script>
+import { GlAlert } from '@gitlab/ui';
+import IssuableMoveDropdown from '~/vue_shared/components/sidebar/issuable_move_dropdown.vue';
+import createFlash from '~/flash';
+import { logError } from '~/lib/logger';
+import { s__ } from '~/locale';
+import {
+ WORK_ITEM_TYPE_ENUM_ISSUE,
+ WORK_ITEM_TYPE_ENUM_INCIDENT,
+ WORK_ITEM_TYPE_ENUM_TASK,
+ WORK_ITEM_TYPE_ENUM_TEST_CASE,
+} from '~/work_items/constants';
+import issuableEventHub from '~/issues/list/eventhub';
+import getIssuesQuery from 'ee_else_ce/issues/list/queries/get_issues.query.graphql';
+import getIssuesCountQuery from 'ee_else_ce/issues/list/queries/get_issues_counts.query.graphql';
+import moveIssueMutation from './graphql/mutations/move_issue.mutation.graphql';
+
+export default {
+ name: 'MoveIssuesButton',
+ components: {
+ IssuableMoveDropdown,
+ GlAlert,
+ },
+ props: {
+ projectFullPath: {
+ type: String,
+ required: true,
+ },
+ projectsFetchPath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ selectedIssuables: [],
+ moveInProgress: false,
+ };
+ },
+ computed: {
+ cannotMoveTasksWarningTitle() {
+ if (this.tasksSelected && this.testCasesSelected) {
+ return s__('Issues|Tasks and test cases can not be moved.');
+ }
+
+ if (this.testCasesSelected) {
+ return s__('Issues|Test cases can not be moved.');
+ }
+
+ return s__('Issues|Tasks can not be moved.');
+ },
+ issuesSelected() {
+ return this.selectedIssuables.some((item) => item.type === WORK_ITEM_TYPE_ENUM_ISSUE);
+ },
+ incidentsSelected() {
+ return this.selectedIssuables.some((item) => item.type === WORK_ITEM_TYPE_ENUM_INCIDENT);
+ },
+ tasksSelected() {
+ return this.selectedIssuables.some((item) => item.type === WORK_ITEM_TYPE_ENUM_TASK);
+ },
+ testCasesSelected() {
+ return this.selectedIssuables.some((item) => item.type === WORK_ITEM_TYPE_ENUM_TEST_CASE);
+ },
+ },
+ mounted() {
+ issuableEventHub.$on('issuables:issuableChecked', this.handleIssuableChecked);
+ },
+ beforeDestroy() {
+ issuableEventHub.$off('issuables:issuableChecked', this.handleIssuableChecked);
+ },
+ methods: {
+ handleIssuableChecked(issuable, value) {
+ if (value) {
+ this.selectedIssuables.push(issuable);
+ } else {
+ const index = this.selectedIssuables.indexOf(issuable);
+ if (index > -1) {
+ this.selectedIssuables.splice(index, 1);
+ }
+ }
+ },
+ moveIssues(targetProject) {
+ const iids = this.selectedIssuables.reduce((result, issueData) => {
+ if (
+ issueData.type === WORK_ITEM_TYPE_ENUM_ISSUE ||
+ issueData.type === WORK_ITEM_TYPE_ENUM_INCIDENT
+ ) {
+ result.push(issueData.iid);
+ }
+ return result;
+ }, []);
+
+ if (iids.length === 0) {
+ return;
+ }
+
+ this.moveInProgress = true;
+ issuableEventHub.$emit('issuables:bulkMoveStarted');
+
+ const promises = iids.map((id) => {
+ return this.moveIssue(id, targetProject);
+ });
+
+ Promise.all(promises)
+ .then((promisesResult) => {
+ let foundError = false;
+
+ for (const promiseResult of promisesResult) {
+ if (promiseResult.data.issueMove?.errors?.length) {
+ foundError = true;
+ logError(
+ `Error moving issue. Error message: ${promiseResult.data.issueMove.errors[0].message}`,
+ );
+ }
+ }
+
+ if (!foundError) {
+ const client = this.$apollo.provider.defaultClient;
+ client.refetchQueries({
+ include: [getIssuesQuery, getIssuesCountQuery],
+ });
+ this.moveInProgress = false;
+ this.selectedIssuables = [];
+ issuableEventHub.$emit('issuables:bulkMoveEnded');
+ } else {
+ throw new Error();
+ }
+ })
+ .catch(() => {
+ this.moveInProgress = false;
+ issuableEventHub.$emit('issuables:bulkMoveEnded');
+
+ createFlash({
+ message: s__(`Issues|There was an error while moving the issues.`),
+ });
+ });
+ },
+ moveIssue(issueIid, targetProject) {
+ return this.$apollo.mutate({
+ mutation: moveIssueMutation,
+ variables: {
+ moveIssueInput: {
+ projectPath: this.projectFullPath,
+ iid: issueIid,
+ targetProjectPath: targetProject.full_path,
+ },
+ },
+ });
+ },
+ },
+ i18n: {
+ dropdownButtonTitle: s__('Issues|Move selected'),
+ },
+};
+</script>
+<template>
+ <div>
+ <issuable-move-dropdown
+ :project-full-path="projectFullPath"
+ :projects-fetch-path="projectsFetchPath"
+ :move-in-progress="moveInProgress"
+ :disabled="!issuesSelected && !incidentsSelected"
+ :dropdown-header-title="$options.i18n.dropdownButtonTitle"
+ :dropdown-button-title="$options.i18n.dropdownButtonTitle"
+ @move-issuable="moveIssues"
+ />
+ <gl-alert v-if="tasksSelected || testCasesSelected" :dismissible="false" variant="warning">
+ {{ cannotMoveTasksWarningTitle }}
+ </gl-alert>
+ </div>
+</template>
diff --git a/app/assets/javascripts/issuable/bulk_update_sidebar/index.js b/app/assets/javascripts/issuable/bulk_update_sidebar/index.js
index 4657771353f..b7cb805ee37 100644
--- a/app/assets/javascripts/issuable/bulk_update_sidebar/index.js
+++ b/app/assets/javascripts/issuable/bulk_update_sidebar/index.js
@@ -1,6 +1,9 @@
import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { gqlClient } from '../../issues/list/graphql';
import StatusDropdown from './components/status_dropdown.vue';
import SubscriptionsDropdown from './components/subscriptions_dropdown.vue';
+import MoveIssuesButton from './components/move_issues_button.vue';
import issuableBulkUpdateActions from './issuable_bulk_update_actions';
import IssuableBulkUpdateSidebar from './issuable_bulk_update_sidebar';
@@ -42,3 +45,31 @@ export function initSubscriptionsDropdown() {
render: (createElement) => createElement(SubscriptionsDropdown),
});
}
+
+export function initMoveIssuesButton() {
+ const el = document.querySelector('.js-move-issues');
+
+ if (!el) {
+ return null;
+ }
+
+ const { dataset } = el;
+
+ Vue.use(VueApollo);
+ const apolloProvider = new VueApollo({
+ defaultClient: gqlClient,
+ });
+
+ return new Vue({
+ el,
+ name: 'MoveIssuesRoot',
+ apolloProvider,
+ render: (createElement) =>
+ createElement(MoveIssuesButton, {
+ props: {
+ projectFullPath: dataset.projectFullPath,
+ projectsFetchPath: dataset.projectsFetchPath,
+ },
+ }),
+ });
+}
diff --git a/app/assets/javascripts/issuable/bulk_update_sidebar/issuable_bulk_update_sidebar.js b/app/assets/javascripts/issuable/bulk_update_sidebar/issuable_bulk_update_sidebar.js
index a33c6ae8030..b46a95c7dfa 100644
--- a/app/assets/javascripts/issuable/bulk_update_sidebar/issuable_bulk_update_sidebar.js
+++ b/app/assets/javascripts/issuable/bulk_update_sidebar/issuable_bulk_update_sidebar.js
@@ -3,7 +3,7 @@
import $ from 'jquery';
import issuableEventHub from '~/issues/list/eventhub';
import LabelsSelect from '~/labels/labels_select';
-import MilestoneSelect from '~/milestones/milestone_select';
+import { mountMilestoneDropdown } from '~/sidebar/mount_sidebar';
import IssuableBulkUpdateActions from './issuable_bulk_update_actions';
const HIDDEN_CLASS = 'hidden';
@@ -46,35 +46,28 @@ export default class IssuableBulkUpdateSidebar {
// https://gitlab.com/gitlab-org/gitlab/-/issues/325874
issuableEventHub.$on('issuables:enableBulkEdit', () => this.toggleBulkEdit(null, true));
issuableEventHub.$on('issuables:updateBulkEdit', () => this.updateFormState());
+
+ // These events are connected to the logic inside `move_issues_button.vue`,
+ // so that only one action can be performed at a time
+ issuableEventHub.$on('issuables:bulkMoveStarted', () => this.toggleSubmitButtonDisabled(true));
+ issuableEventHub.$on('issuables:bulkMoveEnded', () => this.updateFormState());
}
initDropdowns() {
new LabelsSelect();
- new MilestoneSelect();
+ mountMilestoneDropdown();
// Checking IS_EE and using ee_else_ce is odd, but we do it here to satisfy
// the import/no-unresolved lint rule when FOSS_ONLY=1, even though at
// runtime this block won't execute.
if (IS_EE) {
- import('ee_else_ce/vue_shared/components/sidebar/health_status_select/health_status_bundle')
- .then(({ default: HealthStatusSelect }) => {
- HealthStatusSelect();
- })
- .catch(() => {});
-
- import('ee_else_ce/vue_shared/components/sidebar/epics_select/epics_select_bundle')
- .then(({ default: EpicSelect }) => {
- EpicSelect();
+ import('ee_else_ce/sidebar/mount_sidebar')
+ .then(({ mountEpicDropdown, mountHealthStatusDropdown, mountIterationDropdown }) => {
+ mountEpicDropdown();
+ mountHealthStatusDropdown();
+ mountIterationDropdown();
})
.catch(() => {});
-
- import('ee_else_ce/vue_shared/components/sidebar/iterations_dropdown_bundle')
- .then(({ default: iterationsDropdown }) => {
- iterationsDropdown();
- })
- .catch((e) => {
- throw e;
- });
}
}
@@ -89,6 +82,8 @@ export default class IssuableBulkUpdateSidebar {
this.updateSelectedIssuableIds();
IssuableBulkUpdateActions.setOriginalDropdownData();
+
+ issuableEventHub.$emit('issuables:selectionChanged', !noCheckedIssues);
}
prepForSubmit() {
diff --git a/app/assets/javascripts/issuable/components/related_issuable_item.vue b/app/assets/javascripts/issuable/components/related_issuable_item.vue
index 8894e8f63b8..254248ef1d4 100644
--- a/app/assets/javascripts/issuable/components/related_issuable_item.vue
+++ b/app/assets/javascripts/issuable/components/related_issuable_item.vue
@@ -141,6 +141,7 @@ export default {
<gl-link
:href="computedPath"
class="sortable-link gl-font-weight-normal"
+ target="_blank"
@click="handleTitleClick"
>
{{ title }}
diff --git a/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue b/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
new file mode 100644
index 00000000000..29f6aecca03
--- /dev/null
+++ b/app/assets/javascripts/issues/dashboard/components/issues_dashboard_app.vue
@@ -0,0 +1,56 @@
+<script>
+import { GlButton, GlEmptyState } from '@gitlab/ui';
+import { __ } from '~/locale';
+import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
+import { IssuableListTabs, IssuableStates } from '~/vue_shared/issuable/list/constants';
+
+export default {
+ i18n: {
+ calendarButtonText: __('Subscribe to calendar'),
+ emptyStateTitle: __('Please select at least one filter to see results'),
+ rssButtonText: __('Subscribe to RSS feed'),
+ searchInputPlaceholder: __('Search or filter results...'),
+ },
+ IssuableListTabs,
+ components: {
+ GlButton,
+ GlEmptyState,
+ IssuableList,
+ },
+ inject: ['calendarPath', 'emptyStateSvgPath', 'isSignedIn', 'rssPath'],
+ data() {
+ return {
+ issues: [],
+ searchTokens: [],
+ sortOptions: [],
+ state: IssuableStates.Opened,
+ };
+ },
+};
+</script>
+
+<template>
+ <issuable-list
+ namespace="dashboard"
+ recent-searches-storage-key="issues"
+ :search-input-placeholder="$options.i18n.searchInputPlaceholder"
+ :search-tokens="searchTokens"
+ :sort-options="sortOptions"
+ :issuables="issues"
+ :tabs="$options.IssuableListTabs"
+ :current-tab="state"
+ >
+ <template #nav-actions>
+ <gl-button :href="rssPath" icon="rss">
+ {{ $options.i18n.rssButtonText }}
+ </gl-button>
+ <gl-button :href="calendarPath" icon="calendar">
+ {{ $options.i18n.calendarButtonText }}
+ </gl-button>
+ </template>
+
+ <template #empty-state>
+ <gl-empty-state :svg-path="emptyStateSvgPath" :title="$options.i18n.emptyStateTitle" />
+ </template>
+ </issuable-list>
+</template>
diff --git a/app/assets/javascripts/issues/dashboard/index.js b/app/assets/javascripts/issues/dashboard/index.js
new file mode 100644
index 00000000000..a1ae3b93f7d
--- /dev/null
+++ b/app/assets/javascripts/issues/dashboard/index.js
@@ -0,0 +1,25 @@
+import Vue from 'vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import IssuesDashboardApp from './components/issues_dashboard_app.vue';
+
+export function mountIssuesDashboardApp() {
+ const el = document.querySelector('.js-issues-dashboard');
+
+ if (!el) {
+ return null;
+ }
+
+ const { calendarPath, emptyStateSvgPath, isSignedIn, rssPath } = el.dataset;
+
+ return new Vue({
+ el,
+ name: 'IssuesDashboardRoot',
+ provide: {
+ calendarPath,
+ emptyStateSvgPath,
+ isSignedIn: parseBoolean(isSignedIn),
+ rssPath,
+ },
+ render: (createComponent) => createComponent(IssuesDashboardApp),
+ });
+}
diff --git a/app/assets/javascripts/issues/index.js b/app/assets/javascripts/issues/index.js
index 22ac37656ea..a785790169d 100644
--- a/app/assets/javascripts/issues/index.js
+++ b/app/assets/javascripts/issues/index.js
@@ -18,9 +18,9 @@ import {
} from '~/issues/show';
import { parseIssuableData } from '~/issues/show/utils/parse_data';
import LabelsSelect from '~/labels/labels_select';
-import MilestoneSelect from '~/milestones/milestone_select';
import initNotesApp from '~/notes';
import { store } from '~/notes/stores';
+import { mountMilestoneDropdown } from '~/sidebar/mount_sidebar';
import ZenMode from '~/zen_mode';
import initAwardsApp from '~/emoji/awards_app';
import initLinkedResources from '~/linked_resources';
@@ -41,11 +41,11 @@ export function initForm() {
new IssuableForm($('.issue-form')); // eslint-disable-line no-new
new IssuableTemplateSelectors({ warnTemplateOverride: true }); // eslint-disable-line no-new
new LabelsSelect(); // eslint-disable-line no-new
- new MilestoneSelect(); // eslint-disable-line no-new
new ShortcutsNavigation(); // eslint-disable-line no-new
initTitleSuggestions();
initTypePopover();
+ mountMilestoneDropdown();
}
export function initShow() {
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 acb6aa93f0f..64de4b1947b 100644
--- a/app/assets/javascripts/issues/list/components/issues_list_app.vue
+++ b/app/assets/javascripts/issues/list/components/issues_list_app.vue
@@ -27,6 +27,7 @@ import { getParameterByName, joinPaths } from '~/lib/utils/url_utility';
import { helpPagePath } from '~/helpers/help_page_helper';
import {
DEFAULT_NONE_ANY,
+ FILTERED_SEARCH_TERM,
OPERATOR_IS_ONLY,
TOKEN_TITLE_ASSIGNEE,
TOKEN_TITLE_AUTHOR,
@@ -38,12 +39,22 @@ import {
TOKEN_TITLE_ORGANIZATION,
TOKEN_TITLE_RELEASE,
TOKEN_TITLE_TYPE,
- FILTERED_SEARCH_TERM,
+ OPERATOR_IS_NOT_OR,
+ OPERATOR_IS_AND_IS_NOT,
+ TOKEN_TYPE_ASSIGNEE,
+ TOKEN_TYPE_AUTHOR,
+ TOKEN_TYPE_CONFIDENTIAL,
+ TOKEN_TYPE_CONTACT,
+ TOKEN_TYPE_LABEL,
+ TOKEN_TYPE_MILESTONE,
+ TOKEN_TYPE_MY_REACTION,
+ TOKEN_TYPE_ORGANIZATION,
+ TOKEN_TYPE_RELEASE,
+ 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 glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { WORK_ITEM_TYPE_ENUM_TASK } from '~/work_items/constants';
import {
CREATED_DESC,
defaultTypeTokenOptions,
@@ -59,16 +70,6 @@ import {
PARAM_SORT,
PARAM_STATE,
RELATIVE_POSITION_ASC,
- TOKEN_TYPE_ASSIGNEE,
- TOKEN_TYPE_AUTHOR,
- TOKEN_TYPE_CONFIDENTIAL,
- TOKEN_TYPE_CONTACT,
- TOKEN_TYPE_LABEL,
- TOKEN_TYPE_MILESTONE,
- TOKEN_TYPE_MY_REACTION,
- TOKEN_TYPE_ORGANIZATION,
- TOKEN_TYPE_RELEASE,
- TOKEN_TYPE_TYPE,
TYPE_TOKEN_TASK_OPTION,
UPDATED_DESC,
urlSortParams,
@@ -140,7 +141,6 @@ export default {
'hasAnyProjects',
'hasBlockedIssuesFeature',
'hasIssueWeightsFeature',
- 'hasMultipleIssueAssigneesFeature',
'hasScopedLabelsFeature',
'initialEmail',
'initialSort',
@@ -239,21 +239,17 @@ export default {
state: this.state,
...this.pageParams,
...this.apiFilterParams,
- types: this.apiFilterParams.types || this.defaultWorkItemTypes,
+ types: this.apiFilterParams.types || defaultWorkItemTypes,
};
},
namespace() {
return this.isProject ? ITEM_TYPE.PROJECT : ITEM_TYPE.GROUP;
},
- defaultWorkItemTypes() {
- return this.isWorkItemsEnabled
- ? defaultWorkItemTypes
- : defaultWorkItemTypes.filter((type) => type !== WORK_ITEM_TYPE_ENUM_TASK);
- },
typeTokenOptions() {
- return this.isWorkItemsEnabled
- ? defaultTypeTokenOptions.concat(TYPE_TOKEN_TASK_OPTION)
- : defaultTypeTokenOptions;
+ return defaultTypeTokenOptions.concat(TYPE_TOKEN_TASK_OPTION);
+ },
+ hasOrFeature() {
+ return this.glFeatures.orIssuableQueries;
},
hasSearch() {
return (
@@ -272,9 +268,6 @@ export default {
isOpenTab() {
return this.state === IssuableStates.Opened;
},
- isWorkItemsEnabled() {
- return this.glFeatures.workItems;
- },
showCsvButtons() {
return this.isProject && this.isSignedIn;
},
@@ -324,8 +317,8 @@ export default {
icon: 'user',
token: AuthorToken,
dataType: 'user',
- unique: !this.hasMultipleIssueAssigneesFeature,
defaultAuthors: DEFAULT_NONE_ANY,
+ operators: this.hasOrFeature ? OPERATOR_IS_NOT_OR : OPERATOR_IS_AND_IS_NOT,
fetchAuthors: this.fetchUsers,
recentSuggestionsStorageKey: `${this.fullPath}-issues-recent-tokens-assignee`,
preloadedAuthors,
@@ -565,6 +558,7 @@ export default {
bulkUpdateSidebar.initBulkUpdateSidebar('issuable_');
bulkUpdateSidebar.initStatusDropdown();
bulkUpdateSidebar.initSubscriptionsDropdown();
+ bulkUpdateSidebar.initMoveIssuesButton();
const usersSelect = await import('~/users_select');
const UsersSelect = usersSelect.default;
@@ -793,6 +787,7 @@ export default {
:show-page-size-change-controls="showPageSizeControls"
:has-next-page="pageInfo.hasNextPage"
:has-previous-page="pageInfo.hasPreviousPage"
+ :show-filtered-search-friendly-text="hasOrFeature"
show-work-item-type-icon
@click-tab="handleClickTab"
@dismiss-alert="handleDismissAlert"
@@ -959,12 +954,17 @@ export default {
<gl-empty-state
v-else
- :description="$options.i18n.noIssuesSignedOutDescription"
:title="$options.i18n.noIssuesSignedOutTitle"
:svg-path="emptyStateSvgPath"
:primary-button-text="$options.i18n.noIssuesSignedOutButtonText"
:primary-button-link="signInPath"
- />
+ >
+ <template #description>
+ <gl-link :href="issuesHelpPagePath" target="_blank">{{
+ $options.i18n.noIssuesSignedOutDescription
+ }}</gl-link>
+ </template>
+ </gl-empty-state>
<issuable-by-email v-if="showIssuableByEmail" class="gl-text-center gl-pt-5 gl-pb-7" />
</div>
diff --git a/app/assets/javascripts/issues/list/constants.js b/app/assets/javascripts/issues/list/constants.js
index 9fe8899ab39..5ed9ceea856 100644
--- a/app/assets/javascripts/issues/list/constants.js
+++ b/app/assets/javascripts/issues/list/constants.js
@@ -7,7 +7,21 @@ import {
FILTER_UPCOMING,
OPERATOR_IS,
OPERATOR_IS_NOT,
+ OPERATOR_OR,
+ TOKEN_TYPE_ASSIGNEE,
+ TOKEN_TYPE_AUTHOR,
+ TOKEN_TYPE_CONFIDENTIAL,
+ TOKEN_TYPE_CONTACT,
+ TOKEN_TYPE_EPIC,
TOKEN_TYPE_HEALTH,
+ TOKEN_TYPE_ITERATION,
+ TOKEN_TYPE_LABEL,
+ TOKEN_TYPE_MILESTONE,
+ TOKEN_TYPE_MY_REACTION,
+ TOKEN_TYPE_ORGANIZATION,
+ TOKEN_TYPE_RELEASE,
+ TOKEN_TYPE_TYPE,
+ TOKEN_TYPE_WEIGHT,
} from '~/vue_shared/components/filtered_search_bar/constants';
import {
WORK_ITEM_TYPE_ENUM_INCIDENT,
@@ -46,10 +60,8 @@ export const i18n = {
noIssuesSignedInDescription: __('Learn more about issues.'),
noIssuesSignedInTitle: __('Use issues to collaborate on ideas, solve problems, and plan work'),
noIssuesSignedOutButtonText: __('Register / Sign In'),
- noIssuesSignedOutDescription: __(
- 'The Issue Tracker is the place to add things that need to be improved or solved in a project. You can register or sign in to create issues for this project.',
- ),
- noIssuesSignedOutTitle: __('There are no issues to show'),
+ noIssuesSignedOutDescription: __('Learn more about issues.'),
+ noIssuesSignedOutTitle: __('Use issues to collaborate on ideas, solve problems, and plan work'),
noSearchResultsDescription: __('To widen your search, change or remove filters above'),
noSearchResultsTitle: __('Sorry, your filter produced no results'),
relatedMergeRequests: __('Related merge requests'),
@@ -136,20 +148,6 @@ export const specialFilterValues = [
FILTER_STARTED,
];
-export const TOKEN_TYPE_AUTHOR = 'author_username';
-export const TOKEN_TYPE_ASSIGNEE = 'assignee_username';
-export const TOKEN_TYPE_MILESTONE = 'milestone';
-export const TOKEN_TYPE_LABEL = 'labels';
-export const TOKEN_TYPE_TYPE = 'type';
-export const TOKEN_TYPE_RELEASE = 'release';
-export const TOKEN_TYPE_MY_REACTION = 'my_reaction_emoji';
-export const TOKEN_TYPE_CONFIDENTIAL = 'confidential';
-export const TOKEN_TYPE_ITERATION = 'iteration';
-export const TOKEN_TYPE_EPIC = 'epic_id';
-export const TOKEN_TYPE_WEIGHT = 'weight';
-export const TOKEN_TYPE_CONTACT = 'crm_contact';
-export const TOKEN_TYPE_ORGANIZATION = 'crm_organization';
-
export const TYPE_TOKEN_TASK_OPTION = { icon: 'issue-type-task', title: 'task', value: 'task' };
// This should be consistent with Issue::TYPES_FOR_LIST in the backend
@@ -195,6 +193,9 @@ export const filters = {
[OPERATOR_IS_NOT]: {
[NORMAL_FILTER]: 'not[assignee_username][]',
},
+ [OPERATOR_OR]: {
+ [NORMAL_FILTER]: 'or[assignee_username][]',
+ },
},
},
[TOKEN_TYPE_MILESTONE]: {
diff --git a/app/assets/javascripts/issues/list/graphql.js b/app/assets/javascripts/issues/list/graphql.js
new file mode 100644
index 00000000000..5ef61727a3d
--- /dev/null
+++ b/app/assets/javascripts/issues/list/graphql.js
@@ -0,0 +1,25 @@
+import produce from 'immer';
+import createDefaultClient from '~/lib/graphql';
+import getIssuesQuery from 'ee_else_ce/issues/list/queries/get_issues.query.graphql';
+
+const resolvers = {
+ Mutation: {
+ reorderIssues: (_, { oldIndex, newIndex, namespace, serializedVariables }, { cache }) => {
+ const variables = JSON.parse(serializedVariables);
+ const sourceData = cache.readQuery({ query: getIssuesQuery, variables });
+
+ const data = produce(sourceData, (draftData) => {
+ const issues = draftData[namespace].issues.nodes.slice();
+ const issueToMove = issues[oldIndex];
+ issues.splice(oldIndex, 1);
+ issues.splice(newIndex, 0, issueToMove);
+
+ draftData[namespace].issues.nodes = issues;
+ });
+
+ cache.writeQuery({ query: getIssuesQuery, variables, data });
+ },
+ },
+};
+
+export const gqlClient = createDefaultClient(resolvers);
diff --git a/app/assets/javascripts/issues/list/index.js b/app/assets/javascripts/issues/list/index.js
index 93333c31b34..5e04dd1971c 100644
--- a/app/assets/javascripts/issues/list/index.js
+++ b/app/assets/javascripts/issues/list/index.js
@@ -1,12 +1,11 @@
-import produce from 'immer';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import VueRouter from 'vue-router';
-import getIssuesQuery from 'ee_else_ce/issues/list/queries/get_issues.query.graphql';
import IssuesListApp from 'ee_else_ce/issues/list/components/issues_list_app.vue';
import createDefaultClient from '~/lib/graphql';
import { parseBoolean } from '~/lib/utils/common_utils';
import JiraIssuesImportStatusRoot from './components/jira_issues_import_status_app.vue';
+import { gqlClient } from './graphql';
export function mountJiraIssuesListApp() {
const el = document.querySelector('.js-jira-issues-import-status');
@@ -56,26 +55,6 @@ export function mountIssuesListApp() {
Vue.use(VueApollo);
Vue.use(VueRouter);
- const resolvers = {
- Mutation: {
- reorderIssues: (_, { oldIndex, newIndex, namespace, serializedVariables }, { cache }) => {
- const variables = JSON.parse(serializedVariables);
- const sourceData = cache.readQuery({ query: getIssuesQuery, variables });
-
- const data = produce(sourceData, (draftData) => {
- const issues = draftData[namespace].issues.nodes.slice();
- const issueToMove = issues[oldIndex];
- issues.splice(oldIndex, 1);
- issues.splice(newIndex, 0, issueToMove);
-
- draftData[namespace].issues.nodes = issues;
- });
-
- cache.writeQuery({ query: getIssuesQuery, variables, data });
- },
- },
- };
-
const {
autocompleteAwardEmojisPath,
calendarPath,
@@ -97,7 +76,6 @@ export function mountIssuesListApp() {
hasIssuableHealthStatusFeature,
hasIssueWeightsFeature,
hasIterationsFeature,
- hasMultipleIssueAssigneesFeature,
hasScopedLabelsFeature,
importCsvIssuesPath,
initialEmail,
@@ -125,7 +103,7 @@ export function mountIssuesListApp() {
el,
name: 'IssuesListRoot',
apolloProvider: new VueApollo({
- defaultClient: createDefaultClient(resolvers),
+ defaultClient: gqlClient,
}),
router: new VueRouter({
base: window.location.pathname,
@@ -148,7 +126,6 @@ export function mountIssuesListApp() {
hasIssuableHealthStatusFeature: parseBoolean(hasIssuableHealthStatusFeature),
hasIssueWeightsFeature: parseBoolean(hasIssueWeightsFeature),
hasIterationsFeature: parseBoolean(hasIterationsFeature),
- hasMultipleIssueAssigneesFeature: parseBoolean(hasMultipleIssueAssigneesFeature),
hasScopedLabelsFeature: parseBoolean(hasScopedLabelsFeature),
initialSort,
isAnonymousSearchDisabled: parseBoolean(isAnonymousSearchDisabled),
diff --git a/app/assets/javascripts/issues/list/queries/get_issues.query.graphql b/app/assets/javascripts/issues/list/queries/get_issues.query.graphql
index df7016aeb74..b447289b425 100644
--- a/app/assets/javascripts/issues/list/queries/get_issues.query.graphql
+++ b/app/assets/javascripts/issues/list/queries/get_issues.query.graphql
@@ -24,6 +24,7 @@ query getIssues(
$crmContactId: String
$crmOrganizationId: String
$not: NegatedIssueFilterInput
+ $or: UnionedIssueFilterInput
$beforeCursor: String
$afterCursor: String
$firstPageSize: Int
@@ -49,6 +50,7 @@ query getIssues(
crmContactId: $crmContactId
crmOrganizationId: $crmOrganizationId
not: $not
+ or: $or
before: $beforeCursor
after: $afterCursor
first: $firstPageSize
@@ -84,6 +86,7 @@ query getIssues(
crmContactId: $crmContactId
crmOrganizationId: $crmOrganizationId
not: $not
+ or: $or
before: $beforeCursor
after: $afterCursor
first: $firstPageSize
diff --git a/app/assets/javascripts/issues/list/queries/get_issues_counts.query.graphql b/app/assets/javascripts/issues/list/queries/get_issues_counts.query.graphql
index c1aee772167..fdb0eeb5970 100644
--- a/app/assets/javascripts/issues/list/queries/get_issues_counts.query.graphql
+++ b/app/assets/javascripts/issues/list/queries/get_issues_counts.query.graphql
@@ -17,6 +17,7 @@ query getIssuesCount(
$crmContactId: String
$crmOrganizationId: String
$not: NegatedIssueFilterInput
+ $or: UnionedIssueFilterInput
) {
group(fullPath: $fullPath) @skip(if: $isProject) {
id
@@ -37,6 +38,7 @@ query getIssuesCount(
crmContactId: $crmContactId
crmOrganizationId: $crmOrganizationId
not: $not
+ or: $or
) {
count
}
@@ -57,6 +59,7 @@ query getIssuesCount(
crmContactId: $crmContactId
crmOrganizationId: $crmOrganizationId
not: $not
+ or: $or
) {
count
}
@@ -77,6 +80,7 @@ query getIssuesCount(
crmContactId: $crmContactId
crmOrganizationId: $crmOrganizationId
not: $not
+ or: $or
) {
count
}
@@ -101,6 +105,7 @@ query getIssuesCount(
crmContactId: $crmContactId
crmOrganizationId: $crmOrganizationId
not: $not
+ or: $or
) {
count
}
@@ -122,6 +127,7 @@ query getIssuesCount(
crmContactId: $crmContactId
crmOrganizationId: $crmOrganizationId
not: $not
+ or: $or
) {
count
}
@@ -143,6 +149,7 @@ query getIssuesCount(
crmContactId: $crmContactId
crmOrganizationId: $crmOrganizationId
not: $not
+ or: $or
) {
count
}
diff --git a/app/assets/javascripts/issues/list/utils.js b/app/assets/javascripts/issues/list/utils.js
index f02c7a23f51..2f9ab9d62ee 100644
--- a/app/assets/javascripts/issues/list/utils.js
+++ b/app/assets/javascripts/issues/list/utils.js
@@ -5,6 +5,13 @@ import { __ } from '~/locale';
import {
FILTERED_SEARCH_TERM,
OPERATOR_IS_NOT,
+ OPERATOR_OR,
+ TOKEN_TYPE_ASSIGNEE,
+ TOKEN_TYPE_CONFIDENTIAL,
+ TOKEN_TYPE_ITERATION,
+ TOKEN_TYPE_MILESTONE,
+ TOKEN_TYPE_RELEASE,
+ TOKEN_TYPE_TYPE,
} from '~/vue_shared/components/filtered_search_bar/constants';
import {
API_PARAM,
@@ -31,12 +38,6 @@ import {
specialFilterValues,
TITLE_ASC,
TITLE_DESC,
- TOKEN_TYPE_ASSIGNEE,
- TOKEN_TYPE_CONFIDENTIAL,
- TOKEN_TYPE_ITERATION,
- TOKEN_TYPE_MILESTONE,
- TOKEN_TYPE_RELEASE,
- TOKEN_TYPE_TYPE,
UPDATED_ASC,
UPDATED_DESC,
URL_PARAM,
@@ -252,20 +253,36 @@ const formatData = (token) => {
export const convertToApiParams = (filterTokens) => {
const params = {};
const not = {};
+ const or = {};
filterTokens
.filter((token) => token.type !== FILTERED_SEARCH_TERM)
.forEach((token) => {
const filterType = getFilterType(token.value.data, token.type);
const field = filters[token.type][API_PARAM][filterType];
- const obj = token.value.operator === OPERATOR_IS_NOT ? not : params;
+ let obj;
+ if (token.value.operator === OPERATOR_IS_NOT) {
+ obj = not;
+ } else if (token.value.operator === OPERATOR_OR) {
+ obj = or;
+ } else {
+ obj = params;
+ }
const data = formatData(token);
Object.assign(obj, {
[field]: obj[field] ? [obj[field], data].flat() : data,
});
});
- return Object.keys(not).length ? Object.assign(params, { not }) : params;
+ if (Object.keys(not).length) {
+ Object.assign(params, { not });
+ }
+
+ if (Object.keys(or).length) {
+ Object.assign(params, { or });
+ }
+
+ return params;
};
export const convertToUrlParams = (filterTokens) =>
diff --git a/app/assets/javascripts/issues/show/components/fields/description.vue b/app/assets/javascripts/issues/show/components/fields/description.vue
index dbe634e7295..180dea77003 100644
--- a/app/assets/javascripts/issues/show/components/fields/description.vue
+++ b/app/assets/javascripts/issues/show/components/fields/description.vue
@@ -67,7 +67,7 @@ export default {
:quick-actions-docs-path="quickActionsDocsPath"
:enable-autocomplete="enableAutocomplete"
supports-quick-actions
- init-on-autofocus
+ autofocus
@input="$emit('input', $event)"
@keydown.meta.enter="updateIssuable"
@keydown.ctrl.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 75d0b9e5e76..5695efd7114 100644
--- a/app/assets/javascripts/issues/show/components/fields/type.vue
+++ b/app/assets/javascripts/issues/show/components/fields/type.vue
@@ -42,7 +42,7 @@ export default {
const {
issueState: { issueType },
} = this;
- return capitalize(issueType);
+ return issuableTypes.find((type) => type.value === issueType)?.text || capitalize(issueType);
},
shouldShowIncident() {
return this.issueType === INCIDENT_TYPE || this.canCreateIncident;
diff --git a/app/assets/javascripts/issues/show/components/header_actions.vue b/app/assets/javascripts/issues/show/components/header_actions.vue
index 74d166f82bb..c01de63ced9 100644
--- a/app/assets/javascripts/issues/show/components/header_actions.vue
+++ b/app/assets/javascripts/issues/show/components/header_actions.vue
@@ -7,6 +7,7 @@ import {
GlLink,
GlModal,
GlModalDirective,
+ GlTooltipDirective,
} from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
import createFlash, { FLASH_TYPES } from '~/flash';
@@ -51,6 +52,7 @@ export default {
},
directives: {
GlModal: GlModalDirective,
+ GlTooltip: GlTooltipDirective,
},
mixins: [trackingMixin],
inject: {
@@ -287,12 +289,15 @@ export default {
<gl-dropdown
v-if="hasDesktopDropdown"
+ v-gl-tooltip.hover
class="gl-display-none gl-sm-display-inline-flex! gl-ml-3"
icon="ellipsis_v"
category="tertiary"
data-qa-selector="issue_actions_ellipsis_dropdown"
:text="dropdownText"
:text-sr-only="true"
+ :title="dropdownText"
+ :aria-label="dropdownText"
data-testid="desktop-dropdown"
no-caret
right
diff --git a/app/assets/javascripts/issues/show/components/incidents/constants.js b/app/assets/javascripts/issues/show/components/incidents/constants.js
index aa7b9805b5f..db846009409 100644
--- a/app/assets/javascripts/issues/show/components/incidents/constants.js
+++ b/app/assets/javascripts/issues/show/components/incidents/constants.js
@@ -1,4 +1,4 @@
-import { __, s__ } from '~/locale';
+import { __, n__, s__ } from '~/locale';
export const timelineTabI18n = Object.freeze({
title: s__('Incident|Timeline'),
@@ -15,6 +15,8 @@ export const timelineFormI18n = Object.freeze({
save: __('Save'),
cancel: __('Cancel'),
description: __('Description'),
+ hint: __('You can enter up to 280 characters'),
+ textRemaining: (count) => n__('%d character remaining', '%d characters remaining', count),
saveAndAdd: s__('Incident|Save and add another event'),
areaLabel: s__('Incident|Timeline text'),
});
@@ -38,3 +40,5 @@ export const timelineItemI18n = Object.freeze({
moreActions: __('More actions'),
timeUTC: __('%{time} UTC'),
});
+
+export const MAX_TEXT_LENGTH = 280;
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 55cd8b5f606..72dfccca467 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
@@ -2,7 +2,7 @@
import { GlDatepicker, GlFormInput, GlFormGroup, GlButton } from '@gitlab/ui';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
-import { timelineFormI18n } from './constants';
+import { MAX_TEXT_LENGTH, timelineFormI18n } from './constants';
import { getUtcShiftedDate } from './utils';
export default {
@@ -26,6 +26,7 @@ export default {
GlButton,
},
i18n: timelineFormI18n,
+ MAX_TEXT_LENGTH,
directives: {
autofocusonshow,
},
@@ -63,6 +64,9 @@ export default {
};
},
computed: {
+ isTimelineTextValid() {
+ return this.timelineTextCount > 0 && this.timelineTextRemainingCount >= 0;
+ },
occurredAtString() {
const year = this.datePickerInput.getFullYear();
const month = this.datePickerInput.getMonth();
@@ -74,8 +78,11 @@ export default {
return utcDate.toISOString();
},
- hasTimelineText() {
- return this.timelineText.length > 0;
+ timelineTextRemainingCount() {
+ return MAX_TEXT_LENGTH - this.timelineTextCount;
+ },
+ timelineTextCount() {
+ return this.timelineText.length;
},
},
mounted() {
@@ -158,9 +165,21 @@ export default {
dir="auto"
data-supports-quick-actions="false"
:aria-label="$options.i18n.description"
+ aria-describedby="timeline-form-hint"
:placeholder="$options.i18n.areaPlaceholder"
+ :maxlength="$options.MAX_TEXT_LENGTH"
>
</textarea>
+ <div id="timeline-form-hint" class="gl-sr-only">{{ $options.i18n.hint }}</div>
+ <div
+ aria-hidden="true"
+ class="gl-absolute gl-text-gray-500 gl-font-sm gl-line-height-14 gl-right-4 gl-bottom-3"
+ >
+ {{ timelineTextRemainingCount }}
+ </div>
+ <div role="status" class="gl-sr-only">
+ {{ $options.i18n.textRemaining(timelineTextRemainingCount) }}
+ </div>
</template>
</markdown-field>
</gl-form-group>
@@ -171,7 +190,7 @@ export default {
category="primary"
class="gl-mr-3"
data-testid="save-button"
- :disabled="!hasTimelineText"
+ :disabled="!isTimelineTextValid"
:loading="isEventProcessed"
@click="handleSave(false)"
>
@@ -183,7 +202,7 @@ export default {
category="secondary"
class="gl-mr-3 gl-ml-n2"
data-testid="save-and-add-button"
- :disabled="!hasTimelineText"
+ :disabled="!isTimelineTextValid"
:loading="isEventProcessed"
@click="handleSave(true)"
>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/legacy_sidebar_header.vue b/app/assets/javascripts/jobs/components/job/sidebar/legacy_sidebar_header.vue
index 263b2d141c9..64b497c3550 100644
--- a/app/assets/javascripts/jobs/components/job/sidebar/legacy_sidebar_header.vue
+++ b/app/assets/javascripts/jobs/components/job/sidebar/legacy_sidebar_header.vue
@@ -35,6 +35,11 @@ export default {
retryButtonCategory() {
return this.job.status && this.job.recoverable ? 'primary' : 'secondary';
},
+ buttonTitle() {
+ return this.job.status && this.job.status.text === 'passed'
+ ? this.$options.i18n.runAgainJobButtonLabel
+ : this.$options.i18n.retryJobButtonLabel;
+ },
},
methods: {
...mapActions(['toggleSidebar']),
@@ -66,8 +71,8 @@ export default {
<job-sidebar-retry-button
v-if="job.retry_path"
v-gl-tooltip.left
- :title="$options.i18n.retryJobButtonLabel"
- :aria-label="$options.i18n.retryJobButtonLabel"
+ :title="buttonTitle"
+ :aria-label="buttonTitle"
:category="retryButtonCategory"
:href="job.retry_path"
:modal-id="$options.forwardDeploymentFailureModalId"
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/sidebar.vue b/app/assets/javascripts/jobs/components/job/sidebar/sidebar.vue
index b0db48df01f..aac6a0ad6d3 100644
--- a/app/assets/javascripts/jobs/components/job/sidebar/sidebar.vue
+++ b/app/assets/javascripts/jobs/components/job/sidebar/sidebar.vue
@@ -63,10 +63,23 @@ export default {
commit() {
return this.job?.pipeline?.commit || {};
},
+ selectedStageData() {
+ return this.stages.find((val) => val.name === this.selectedStage);
+ },
shouldShowJobRetryForwardDeploymentModal() {
return this.job.retry_path && this.hasForwardDeploymentFailure;
},
},
+ watch: {
+ job(value, oldValue) {
+ const hasNewStatus = value.status.text !== oldValue.status.text;
+ const isCurrentStage = value?.stage === this.selectedStage;
+
+ if (hasNewStatus && isCurrentStage) {
+ this.fetchJobsForStage(this.selectedStageData);
+ }
+ },
+ },
methods: {
...mapActions(['fetchJobsForStage']),
},
diff --git a/app/assets/javascripts/jobs/components/table/cells/duration_cell.vue b/app/assets/javascripts/jobs/components/table/cells/duration_cell.vue
index 120f01db8f0..d1b2da4d115 100644
--- a/app/assets/javascripts/jobs/components/table/cells/duration_cell.vue
+++ b/app/assets/javascripts/jobs/components/table/cells/duration_cell.vue
@@ -1,15 +1,16 @@
<script>
-import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
-import { formatDate, getTimeago, durationTimeFormatted } from '~/lib/utils/datetime_utility';
+import { GlIcon } from '@gitlab/ui';
+import { durationTimeFormatted } from '~/lib/utils/datetime_utility';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import timeagoMixin from '~/vue_shared/mixins/timeago';
export default {
iconSize: 12,
- directives: {
- GlTooltip: GlTooltipDirective,
- },
components: {
GlIcon,
+ TimeAgoTooltip,
},
+ mixins: [timeagoMixin],
props: {
job: {
type: Object,
@@ -23,12 +24,6 @@ export default {
duration() {
return this.job?.duration;
},
- timeFormatted() {
- return getTimeago().format(this.finishedTime);
- },
- tooltipTitle() {
- return formatDate(this.finishedTime);
- },
durationFormatted() {
return durationTimeFormatted(this.duration);
},
@@ -44,15 +39,7 @@ export default {
</div>
<div v-if="finishedTime" data-testid="job-finished-time">
<gl-icon name="calendar" :size="$options.iconSize" data-testid="finished-time-icon" />
- <time
- v-gl-tooltip
- :title="tooltipTitle"
- :datetime="finishedTime"
- data-placement="top"
- data-container="body"
- >
- {{ timeFormatted }}
- </time>
+ <time-ago-tooltip :time="finishedTime" />
</div>
</div>
</template>
diff --git a/app/assets/javascripts/jobs/constants.js b/app/assets/javascripts/jobs/constants.js
index 50ee7bd20dd..e9475994e8b 100644
--- a/app/assets/javascripts/jobs/constants.js
+++ b/app/assets/javascripts/jobs/constants.js
@@ -15,6 +15,7 @@ export const JOB_SIDEBAR_COPY = {
retry: __('Retry'),
retryJobButtonLabel: s__('Job|Retry'),
toggleSidebar: __('Toggle Sidebar'),
+ runAgainJobButtonLabel: s__('Job|Run again'),
};
export const JOB_RETRY_FORWARD_DEPLOYMENT_MODAL = {
diff --git a/app/assets/javascripts/lazy_loader.js b/app/assets/javascripts/lazy_loader.js
index ba801082377..36f387205f8 100644
--- a/app/assets/javascripts/lazy_loader.js
+++ b/app/assets/javascripts/lazy_loader.js
@@ -169,7 +169,8 @@ export default class LazyLoader {
delete img.dataset.src;
img.classList.remove('lazy');
img.classList.add('js-lazy-loaded');
- img.classList.add('qa-js-lazy-loaded');
+ // eslint-disable-next-line no-param-reassign
+ img.dataset.qa_selector = 'js_lazy_loaded_content';
}
}
}
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index 4448a106bb6..beced4f9144 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -634,66 +634,6 @@ export const NavigationType = {
};
/**
- * Method to perform case-insensitive search for a string
- * within multiple properties and return object containing
- * properties in case there are multiple matches or `null`
- * if there's no match.
- *
- * Eg; Suppose we want to allow user to search using for a string
- * within `iid`, `title`, `url` or `reference` props of a target object;
- *
- * const objectToSearch = {
- * "iid": 1,
- * "title": "Error omnis quos consequatur ullam a vitae sed omnis libero cupiditate. &3",
- * "url": "/groups/gitlab-org/-/epics/1",
- * "reference": "&1",
- * };
- *
- * Following is how we call searchBy and the return values it will yield;
- *
- * - `searchBy('omnis', objectToSearch);`: This will return `{ title: ... }` as our
- * query was found within title prop we only return that.
- * - `searchBy('1', objectToSearch);`: This will return `{ "iid": ..., "reference": ..., "url": ... }`.
- * - `searchBy('https://gitlab.com/groups/gitlab-org/-/epics/1', objectToSearch);`:
- * This will return `{ "url": ... }`.
- * - `searchBy('foo', objectToSearch);`: This will return `null` as no property value
- * matched with our query.
- *
- * You can learn more about behaviour of this method by referring to tests
- * within `spec/frontend/lib/utils/common_utils_spec.js`.
- *
- * @param {string} query String to search for
- * @param {object} searchSpace Object containing properties to search in for `query`
- */
-export const searchBy = (query = '', searchSpace = {}) => {
- const targetKeys = searchSpace !== null ? Object.keys(searchSpace) : [];
-
- if (!query || !targetKeys.length) {
- return null;
- }
-
- const normalizedQuery = query.toLowerCase();
- const matches = targetKeys
- .filter((item) => {
- const searchItem = `${searchSpace[item]}`.toLowerCase();
-
- return (
- searchItem.indexOf(normalizedQuery) > -1 ||
- normalizedQuery.indexOf(searchItem) > -1 ||
- normalizedQuery === searchItem
- );
- })
- .reduce((acc, prop) => {
- const match = acc;
- match[prop] = searchSpace[prop];
-
- return acc;
- }, {});
-
- return Object.keys(matches).length ? matches : null;
-};
-
-/**
* Checks if the given Label has a special syntax `::` in
* it's title.
*
diff --git a/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_action.js b/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_action.js
new file mode 100644
index 00000000000..3bfbfea7f22
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_action.js
@@ -0,0 +1,57 @@
+import Vue from 'vue';
+
+export function confirmAction(
+ message,
+ {
+ primaryBtnVariant,
+ primaryBtnText,
+ secondaryBtnVariant,
+ secondaryBtnText,
+ cancelBtnVariant,
+ cancelBtnText,
+ modalHtmlMessage,
+ title,
+ hideCancel,
+ } = {},
+) {
+ return new Promise((resolve) => {
+ let confirmed = false;
+ let component;
+
+ const ConfirmAction = Vue.extend({
+ components: {
+ ConfirmModal: () => import('./confirm_modal.vue'),
+ },
+ render(h) {
+ return h(
+ 'confirm-modal',
+ {
+ props: {
+ secondaryText: secondaryBtnText,
+ secondaryVariant: secondaryBtnVariant,
+ primaryVariant: primaryBtnVariant,
+ primaryText: primaryBtnText,
+ cancelVariant: cancelBtnVariant,
+ cancelText: cancelBtnText,
+ title,
+ modalHtmlMessage,
+ hideCancel,
+ },
+ on: {
+ confirmed() {
+ confirmed = true;
+ },
+ closed() {
+ component.$destroy();
+ resolve(confirmed);
+ },
+ },
+ },
+ [message],
+ );
+ },
+ });
+
+ component = new ConfirmAction().$mount();
+ });
+}
diff --git a/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal.js b/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal.js
index 2dc479db80a..0e959e899e9 100644
--- a/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal.js
+++ b/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal.js
@@ -1,75 +1,21 @@
-import Vue from 'vue';
+import { confirmAction } from './confirm_action';
-export function confirmAction(
- message,
- {
- primaryBtnVariant,
- primaryBtnText,
- secondaryBtnVariant,
- secondaryBtnText,
- cancelBtnVariant,
- cancelBtnText,
- modalHtmlMessage,
- title,
- hideCancel,
- } = {},
-) {
- return new Promise((resolve) => {
- let confirmed = false;
-
- const component = new Vue({
- components: {
- ConfirmModal: () => import('./confirm_modal.vue'),
- },
- render(h) {
- return h(
- 'confirm-modal',
- {
- props: {
- secondaryText: secondaryBtnText,
- secondaryVariant: secondaryBtnVariant,
- primaryVariant: primaryBtnVariant,
- primaryText: primaryBtnText,
- cancelVariant: cancelBtnVariant,
- cancelText: cancelBtnText,
- title,
- modalHtmlMessage,
- hideCancel,
- },
- on: {
- confirmed() {
- confirmed = true;
- },
- closed() {
- component.$destroy();
- resolve(confirmed);
- },
- },
- },
- [message],
- );
- },
- }).$mount();
- });
-}
-
-export function confirmViaGlModal(message, element) {
- const primaryBtnConfig = {};
-
- const { confirmBtnVariant } = element.dataset;
-
- if (confirmBtnVariant) {
- primaryBtnConfig.primaryBtnVariant = confirmBtnVariant;
- }
+function confirmViaGlModal(message, element) {
+ const { confirmBtnVariant, title, isHtmlMessage } = element.dataset;
const screenReaderText =
element.querySelector('.gl-sr-only')?.textContent ||
element.querySelector('.sr-only')?.textContent ||
element.getAttribute('aria-label');
- if (screenReaderText) {
- primaryBtnConfig.primaryBtnText = screenReaderText;
- }
+ const config = {
+ ...(screenReaderText && { primaryBtnText: screenReaderText }),
+ ...(confirmBtnVariant && { primaryBtnVariant: confirmBtnVariant }),
+ ...(title && { title }),
+ ...(isHtmlMessage && { modalHtmlMessage: message }),
+ };
- return confirmAction(message, primaryBtnConfig);
+ return confirmAction(message, config);
}
+
+export { confirmAction, confirmViaGlModal };
diff --git a/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js b/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js
index c11cf1a7882..4e0a59d0a38 100644
--- a/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js
@@ -271,6 +271,25 @@ export const secondsToMilliseconds = (seconds) => seconds * 1000;
export const secondsToDays = (seconds) => Math.round(seconds / 86400);
/**
+ * Returns the date `n` seconds after the date provided
+ *
+ * @param {Date} date the initial date
+ * @param {Number} numberOfSeconds number of seconds after
+ * @return {Date} A `Date` object `n` seconds after the provided `Date`
+ */
+export const nSecondsAfter = (date, numberOfSeconds) =>
+ new Date(date.getTime() + numberOfSeconds * 1000);
+
+/**
+ * Returns the date `n` seconds before the date provided
+ *
+ * @param {Date} date the initial date
+ * @param {Number} numberOfSeconds number of seconds before
+ * @return {Date} A `Date` object `n` seconds before the provided `Date`
+ */
+export const nSecondsBefore = (date, numberOfSeconds) => nSecondsAfter(date, -numberOfSeconds);
+
+/**
* Returns the date `n` days after the date provided
*
* @param {Date} date the initial date
diff --git a/app/assets/javascripts/lib/utils/dom_utils.js b/app/assets/javascripts/lib/utils/dom_utils.js
index bca6978c206..cafee641174 100644
--- a/app/assets/javascripts/lib/utils/dom_utils.js
+++ b/app/assets/javascripts/lib/utils/dom_utils.js
@@ -106,3 +106,15 @@ export const setAttributes = (el, attributes) => {
el.setAttribute(key, attributes[key]);
});
};
+
+/**
+ * Get the height of the wrapper page element
+ * This height can be used to determine where the highest element goes in a page
+ * Useful for gl-drawer's header-height prop
+ * @param {String} contentWrapperClass the content wrapper class
+ * @returns {String} height in px
+ */
+export const getContentWrapperHeight = (contentWrapperClass) => {
+ const wrapperEl = document.querySelector(contentWrapperClass);
+ return wrapperEl ? `${wrapperEl.offsetTop}px` : '';
+};
diff --git a/app/assets/javascripts/lib/utils/unit_format/index.js b/app/assets/javascripts/lib/utils/unit_format/index.js
index 5c5210027e4..bec7e48addc 100644
--- a/app/assets/javascripts/lib/utils/unit_format/index.js
+++ b/app/assets/javascripts/lib/utils/unit_format/index.js
@@ -22,6 +22,7 @@ export const SUPPORTED_FORMATS = {
percentHundred: 'percentHundred',
// Duration
+ days: 'days',
seconds: 'seconds',
milliseconds: 'milliseconds',
@@ -65,6 +66,9 @@ export const getFormatter = (format = SUPPORTED_FORMATS.engineering) => {
}
// Durations
+ if (format === SUPPORTED_FORMATS.days) {
+ return suffixFormatter(s__('Units|d'));
+ }
if (format === SUPPORTED_FORMATS.seconds) {
return suffixFormatter(s__('Units|s'));
}
@@ -161,6 +165,19 @@ export const percent = getFormatter(SUPPORTED_FORMATS.percent);
export const percentHundred = getFormatter(SUPPORTED_FORMATS.percentHundred);
/**
+ * Formats a number of days
+ *
+ * @function
+ * @param {Number} value - Number to format, `1` is rendered as `1d`
+ * @param {Object} options - Formatting options
+ * @param {Number} options.fractionDigits - number of precision decimals
+ * @param {Number} options.maxLength - Max length of formatted number
+ * if length is exceeded, exponential format is used.
+ * @param {String} options.unitSeparator - Separator between value and unit
+ */
+export const days = getFormatter(SUPPORTED_FORMATS.days);
+
+/**
* Formats a number of seconds
*
* @function
diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js
index ca90eee69c7..b1a0baf8150 100644
--- a/app/assets/javascripts/lib/utils/url_utility.js
+++ b/app/assets/javascripts/lib/utils/url_utility.js
@@ -178,7 +178,7 @@ export function mergeUrlParams(params, url, options = {}) {
const mergedKeys = sort ? Object.keys(merged).sort() : Object.keys(merged);
const newQuery = mergedKeys
- .filter((key) => merged[key] !== null)
+ .filter((key) => merged[key] !== null && merged[key] !== undefined)
.map((key) => {
let value = merged[key];
const encodedKey = encodeURIComponent(key);
diff --git a/app/assets/javascripts/members/components/action_buttons/access_request_action_buttons.vue b/app/assets/javascripts/members/components/action_buttons/access_request_action_buttons.vue
index d092283338c..f4893721b9e 100644
--- a/app/assets/javascripts/members/components/action_buttons/access_request_action_buttons.vue
+++ b/app/assets/javascripts/members/components/action_buttons/access_request_action_buttons.vue
@@ -7,15 +7,12 @@ import RemoveMemberButton from './remove_member_button.vue';
export default {
name: 'AccessRequestActionButtons',
components: { ActionButtonGroup, RemoveMemberButton, ApproveAccessRequestButton },
+ inheritAttrs: false,
props: {
member: {
type: Object,
required: true,
},
- permissions: {
- type: Object,
- required: true,
- },
isCurrentUser: {
type: Boolean,
required: true,
@@ -43,10 +40,10 @@ export default {
<template>
<action-button-group>
- <div v-if="permissions.canUpdate" class="gl-px-1">
+ <div class="gl-px-1">
<approve-access-request-button :member-id="member.id" />
</div>
- <div v-if="permissions.canRemove" class="gl-px-1">
+ <div class="gl-px-1">
<remove-member-button
:member-id="member.id"
:message="message"
diff --git a/app/assets/javascripts/members/components/members_tabs.vue b/app/assets/javascripts/members/components/members_tabs.vue
index b824a013f3b..5ac8b30614d 100644
--- a/app/assets/javascripts/members/components/members_tabs.vue
+++ b/app/assets/javascripts/members/components/members_tabs.vue
@@ -27,13 +27,13 @@ export const TABS = [
{
namespace: MEMBER_TYPES.invite,
title: __('Invited'),
- canManageMembersPermissionsRequired: true,
+ requiredPermissions: ['canManageMembers'],
queryParamValue: TAB_QUERY_PARAM_VALUES.invite,
},
{
namespace: MEMBER_TYPES.accessRequest,
title: __('Access requests'),
- canManageMembersPermissionsRequired: true,
+ requiredPermissions: ['canManageAccessRequests'],
queryParamValue: TAB_QUERY_PARAM_VALUES.accessRequest,
},
...EE_TABS,
@@ -44,7 +44,7 @@ export default {
ACTIVE_TAB_QUERY_PARAM_NAME,
TABS,
components: { MembersApp, GlTabs, GlTab, GlBadge, GlButton },
- inject: ['canManageMembers', 'canExportMembers', 'exportCsvPath'],
+ inject: ['canManageMembers', 'canManageAccessRequests', 'canExportMembers', 'exportCsvPath'],
data() {
return {
selectedTabIndex: 0,
@@ -96,15 +96,13 @@ export default {
return true;
}
- const { canManageMembersPermissionsRequired = false } = tab;
+ const { requiredPermissions = [] } = tab;
const tabCanBeShown =
this.getTabCount(tab) > 0 || this.activeTabIndexCalculatedFromUrlParams === index;
- if (canManageMembersPermissionsRequired) {
- return this.canManageMembers && tabCanBeShown;
- }
-
- return tabCanBeShown;
+ return (
+ tabCanBeShown && requiredPermissions.every((requiredPermission) => this[requiredPermission])
+ );
},
},
};
diff --git a/app/assets/javascripts/members/index.js b/app/assets/javascripts/members/index.js
index 34660f8f499..359239c5c0c 100644
--- a/app/assets/javascripts/members/index.js
+++ b/app/assets/javascripts/members/index.js
@@ -17,6 +17,7 @@ export const initMembersApp = (el, options) => {
const {
sourceId,
canManageMembers,
+ canManageAccessRequests,
canExportMembers,
canFilterByEnterprise,
exportCsvPath,
@@ -61,6 +62,7 @@ export const initMembersApp = (el, options) => {
currentUserId: gon.current_user_id || null,
sourceId,
canManageMembers,
+ canManageAccessRequests,
canFilterByEnterprise,
canExportMembers,
exportCsvPath,
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
index 17ee2a0d8b6..0ddf5def8ee 100644
--- a/app/assets/javascripts/merge_request_tabs.js
+++ b/app/assets/javascripts/merge_request_tabs.js
@@ -260,7 +260,7 @@ export default class MergeRequestTabs {
}
}
- tabShown(action, href) {
+ tabShown(action, href, shouldScroll = true) {
if (action !== this.currentTab && this.mergeRequestTabs) {
this.currentTab = action;
@@ -289,7 +289,9 @@ export default class MergeRequestTabs {
}
if (action === 'commits') {
- this.loadCommits(href);
+ if (!this.commitsLoaded) {
+ this.loadCommits(href);
+ }
// this.hideSidebar();
this.resetViewContainer();
this.commitPipelinesTable = destroyPipelines(this.commitPipelinesTable);
@@ -334,7 +336,7 @@ export default class MergeRequestTabs {
$('.detail-page-description').renderGFM();
- this.recallScroll(action);
+ if (shouldScroll) this.recallScroll(action);
} else if (action === this.currentAction) {
// ContentTop is used to handle anything at the top of the page before the main content
const mainContentContainer = document.querySelector('.content-wrapper');
@@ -348,7 +350,7 @@ export default class MergeRequestTabs {
const scrollDestination = tabContentTop - mainContentTop - 51;
// scrollBehavior is only available in browsers that support scrollToOptions
- if ('scrollBehavior' in document.documentElement.style) {
+ if ('scrollBehavior' in document.documentElement.style && shouldScroll) {
window.scrollTo({
top: scrollDestination,
behavior: 'smooth',
@@ -423,28 +425,39 @@ export default class MergeRequestTabs {
return this.currentAction;
}
- loadCommits(source) {
- if (this.commitsLoaded) {
- return;
- }
-
+ loadCommits(source, page = 1) {
toggleLoader(true);
axios
- .get(`${source}.json`)
+ .get(`${source}.json`, { params: { page, per_page: 100 } })
.then(({ data }) => {
+ toggleLoader(false);
+
const commitsDiv = document.querySelector('div#commits');
// eslint-disable-next-line no-unsanitized/property
- commitsDiv.innerHTML = data.html;
+ commitsDiv.innerHTML += data.html;
localTimeAgo(commitsDiv.querySelectorAll('.js-timeago'));
this.commitsLoaded = true;
scrollToContainer('#commits');
- toggleLoader(false);
+ const loadMoreButton = document.querySelector('.js-load-more-commits');
+
+ if (loadMoreButton) {
+ loadMoreButton.addEventListener('click', (e) => {
+ e.preventDefault();
+
+ loadMoreButton.remove();
+ this.loadCommits(source, loadMoreButton.dataset.nextPage);
+ });
+ }
+
+ if (!data.next_page) {
+ return import('./add_context_commits_modal');
+ }
- return import('./add_context_commits_modal');
+ return null;
})
- .then((m) => m.default())
+ .then((m) => m?.default())
.catch(() => {
toggleLoader(false);
createAlert({
diff --git a/app/assets/javascripts/milestones/milestone_select.js b/app/assets/javascripts/milestones/milestone_select.js
deleted file mode 100644
index d4876c3dbe8..00000000000
--- a/app/assets/javascripts/milestones/milestone_select.js
+++ /dev/null
@@ -1,273 +0,0 @@
-/* eslint-disable one-var, no-self-compare, consistent-return, no-param-reassign, no-shadow */
-/* global Issuable */
-
-import $ from 'jquery';
-import { template, escape } from 'lodash';
-import Api from '~/api';
-import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
-import { __, sprintf } from '~/locale';
-import { sortMilestonesByDueDate } from '~/milestones/utils';
-import axios from '~/lib/utils/axios_utils';
-import { timeFor, parsePikadayDate, dateInWords } from '~/lib/utils/datetime_utility';
-
-export default class MilestoneSelect {
- constructor(currentProject, els, options = {}) {
- if (currentProject !== null) {
- this.currentProject =
- typeof currentProject === 'string' ? JSON.parse(currentProject) : currentProject;
- }
-
- MilestoneSelect.init(els, options);
- }
-
- static init(els, options) {
- let $els = $(els);
-
- if (!els) {
- $els = $('.js-milestone-select');
- }
-
- $els.each((i, dropdown) => {
- let milestoneLinkNoneTemplate,
- milestoneLinkTemplate,
- milestoneExpiredLinkTemplate,
- selectedMilestone,
- selectedMilestoneDefault;
- const $dropdown = $(dropdown);
- const issueUpdateURL = $dropdown.data('issueUpdate');
- const showNo = $dropdown.data('showNo');
- const showAny = $dropdown.data('showAny');
- const showMenuAbove = $dropdown.data('showMenuAbove');
- const showUpcoming = $dropdown.data('showUpcoming');
- const showStarted = $dropdown.data('showStarted');
- const useId = $dropdown.data('useId');
- const defaultLabel = $dropdown.data('defaultLabel');
- const defaultNo = $dropdown.data('defaultNo');
- const abilityName = $dropdown.data('abilityName');
- const $selectBox = $dropdown.closest('.selectbox');
- const $block = $selectBox.closest('.block');
- const $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon');
- const $value = $block.find('.value');
- const $loading = $block.find('.block-loading').addClass('gl-display-none');
- selectedMilestoneDefault = showAny ? '' : null;
- selectedMilestoneDefault =
- showNo && defaultNo ? __('No milestone') : selectedMilestoneDefault;
- selectedMilestone = $dropdown.data('selected') || selectedMilestoneDefault;
-
- if (issueUpdateURL) {
- milestoneLinkTemplate = template(
- '<a href="<%- web_url %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>',
- );
- milestoneExpiredLinkTemplate = template(
- '<a href="<%- web_url %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %> (Past due)</a>',
- );
- milestoneLinkNoneTemplate = `<span class="no-value">${__('None')}</span>`;
- }
- return initDeprecatedJQueryDropdown($dropdown, {
- showMenuAbove,
- data: (term, callback) => {
- let contextId = parseInt($dropdown.get(0).dataset.projectId, 10);
- let getMilestones = Api.projectMilestones.bind(Api);
- const reqParams = { state: 'active', include_parent_milestones: true };
-
- if (term) {
- reqParams.search = term.trim();
- }
-
- if (!contextId) {
- contextId = $dropdown.get(0).dataset.groupId;
- delete reqParams.include_parent_milestones;
- getMilestones = Api.groupMilestones.bind(Api);
- }
-
- // We don't use $.data() as it caches initial value and never updates!
- return getMilestones(contextId, reqParams)
- .then(({ data }) =>
- data
- .map((m) => ({
- ...m,
- // Public API includes `title` instead of `name`.
- name: m.title,
- }))
- .sort(sortMilestonesByDueDate),
- )
- .then((data) => {
- const extraOptions = [];
- if (showAny) {
- extraOptions.push({
- id: null,
- name: null,
- title: __('Any milestone'),
- });
- }
- if (showNo && term.trim() === '') {
- extraOptions.push({
- id: -1,
- name: __('No milestone'),
- title: __('No milestone'),
- });
- }
- if (showUpcoming) {
- extraOptions.push({
- id: -2,
- name: '#upcoming',
- title: __('Upcoming'),
- });
- }
- if (showStarted) {
- extraOptions.push({
- id: -3,
- name: '#started',
- title: __('Started'),
- });
- }
- if (extraOptions.length && data.length) {
- extraOptions.push({ type: 'divider' });
- }
-
- callback(extraOptions.concat(data));
- if (showMenuAbove) {
- $dropdown.data('deprecatedJQueryDropdown').positionMenuAbove();
- }
- $(`[data-milestone-id="${selectedMilestone}"] > a`).addClass('is-active');
- });
- },
- renderRow: (milestone) => {
- const milestoneName = milestone.title || milestone.name;
- let milestoneDisplayName = escape(milestoneName);
-
- if (milestone.expired) {
- milestoneDisplayName = sprintf(__('%{milestone} (expired)'), {
- milestone: milestoneDisplayName,
- });
- }
-
- return `
- <li data-milestone-id="${escape(milestoneName)}">
- <a href='#' class='dropdown-menu-milestone-link'>
- ${milestoneDisplayName}
- </a>
- </li>
- `;
- },
- filterable: true,
- filterRemote: true,
- search: {
- fields: ['title'],
- },
- selectable: true,
- toggleLabel: (selected, el) => {
- if (selected && 'id' in selected && $(el).hasClass('is-active')) {
- return selected.title;
- }
- return defaultLabel;
- },
- defaultLabel,
- fieldName: $dropdown.data('fieldName'),
- text: (milestone) => escape(milestone.title),
- id: (milestone) => {
- if (milestone !== undefined) {
- if (!useId && !$dropdown.is('.js-issuable-form-dropdown')) {
- return milestone.name;
- }
-
- return milestone.id;
- }
- },
- hidden: () => {
- $selectBox.hide();
- // display:block overrides the hide-collapse rule
- return $value.css('display', '');
- },
- opened: (e) => {
- const $el = $(e.currentTarget);
- if (options.handleClick) {
- selectedMilestone = $dropdown[0].dataset.selected || selectedMilestoneDefault;
- }
- $('a.is-active', $el).removeClass('is-active');
- $(`[data-milestone-id="${selectedMilestone}"] > a`, $el).addClass('is-active');
- },
- vue: false,
- clicked: (clickEvent) => {
- const { e } = clickEvent;
- let selected = clickEvent.selectedObj;
-
- if (!selected) return;
-
- if (options.handleClick) {
- e.preventDefault();
- options.handleClick(selected);
- return;
- }
-
- const page = $('body').attr('data-page');
- const isIssueIndex = page === 'projects:issues:index';
- const isMRIndex = page === page && page === 'projects:merge_requests:index';
- const isSelecting = selected.name !== selectedMilestone;
- selectedMilestone = isSelecting ? selected.name : selectedMilestoneDefault;
-
- if (
- $dropdown.hasClass('js-filter-bulk-update') ||
- $dropdown.hasClass('js-issuable-form-dropdown')
- ) {
- e.preventDefault();
- return;
- }
-
- if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
- return Issuable.filterResults($dropdown.closest('form'));
- } else if ($dropdown.hasClass('js-filter-submit')) {
- return $dropdown.closest('form').submit();
- }
-
- selected = $selectBox.find('input[type="hidden"]').val();
-
- const data = {};
- data[abilityName] = {};
- data[abilityName].milestone_id = selected != null ? selected : null;
- $loading.removeClass('gl-display-none');
- $dropdown.trigger('loading.gl.dropdown');
- return axios
- .put(issueUpdateURL, data)
- .then(({ data }) => {
- $dropdown.trigger('loaded.gl.dropdown');
- $loading.addClass('gl-display-none');
- $selectBox.hide();
- $value.css('display', '');
- if (data.milestone != null) {
- data.milestone.remaining = timeFor(data.milestone.due_date);
- data.milestone.name = data.milestone.title;
- $value.html(
- data.milestone.expired
- ? milestoneExpiredLinkTemplate({
- ...data.milestone,
- remaining: sprintf(__('%{due_date} (Past due)'), {
- due_date: dateInWords(parsePikadayDate(data.milestone.due_date)),
- }),
- })
- : milestoneLinkTemplate(data.milestone),
- );
- return $sidebarCollapsedValue
- .attr(
- 'data-original-title',
- `${data.milestone.name}<br />${data.milestone.remaining}`,
- )
- .find('span')
- .text(data.milestone.title);
- }
- $value.html(milestoneLinkNoneTemplate);
- return $sidebarCollapsedValue
- .attr('data-original-title', __('Milestone'))
- .find('span')
- .text(__('None'));
- })
- .catch(() => {
- $loading.addClass('gl-display-none');
- });
- },
- });
- });
- }
-}
-
-window.MilestoneSelect = MilestoneSelect;
diff --git a/app/assets/javascripts/ml/experiment_tracking/components/experiment.vue b/app/assets/javascripts/ml/experiment_tracking/components/experiment.vue
new file mode 100644
index 00000000000..73cdfbc44b0
--- /dev/null
+++ b/app/assets/javascripts/ml/experiment_tracking/components/experiment.vue
@@ -0,0 +1,36 @@
+<script>
+import { GlTable } from '@gitlab/ui';
+import IncubationAlert from './incubation_alert.vue';
+
+export default {
+ name: 'ShowMlExperiment',
+ components: {
+ GlTable,
+ IncubationAlert,
+ },
+ inject: ['candidates', 'metricNames', 'paramNames'],
+ computed: {
+ fields() {
+ return [...this.paramNames, ...this.metricNames];
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <incubation-alert />
+
+ <h3>
+ {{ __('Experiment Candidates') }}
+ </h3>
+
+ <gl-table
+ :fields="fields"
+ :items="candidates"
+ :empty-text="__('This Experiment has no logged Candidates')"
+ show-empty
+ class="gl-mt-0!"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/ml/experiment_tracking/components/incubation_alert.vue b/app/assets/javascripts/ml/experiment_tracking/components/incubation_alert.vue
new file mode 100644
index 00000000000..51c1e935677
--- /dev/null
+++ b/app/assets/javascripts/ml/experiment_tracking/components/incubation_alert.vue
@@ -0,0 +1,48 @@
+<script>
+import { GlAlert, GlLink } from '@gitlab/ui';
+import { __ } from '~/locale';
+
+export default {
+ i18n: {
+ titleLabel: __('Machine Learning Experiment Tracking is in Incubating Phase'),
+ contentLabel: __(
+ 'GitLab incubates features to explore new use cases. These features are updated regularly, and support is limited',
+ ),
+ learnMoreLabel: __('Learn More'),
+ feedbackLabel: __('Feedback and Updates'),
+ },
+ name: 'MlopsIncubationAlert',
+ components: { GlAlert, GlLink },
+ data() {
+ return {
+ isAlertDismissed: false,
+ };
+ },
+ computed: {
+ shouldShowAlert() {
+ return !this.isAlertDismissed;
+ },
+ },
+ methods: {
+ dismissAlert() {
+ this.isAlertDismissed = true;
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-alert
+ v-if="shouldShowAlert"
+ :title="$options.i18n.titleLabel"
+ variant="warning"
+ :primary-button-text="$options.i18n.feedbackLabel"
+ primary-button-link="https://gitlab.com/groups/gitlab-org/-/epics/8560"
+ @dismiss="dismissAlert"
+ >
+ {{ $options.i18n.contentLabel }}
+ <gl-link href="https://about.gitlab.com/handbook/engineering/incubation/" target="_blank">{{
+ $options.i18n.learnMoreLabel
+ }}</gl-link>
+ </gl-alert>
+</template>
diff --git a/app/assets/javascripts/notebook/cells/markdown.vue b/app/assets/javascripts/notebook/cells/markdown.vue
index 127e046b5a9..9aa6abd9d8c 100644
--- a/app/assets/javascripts/notebook/cells/markdown.vue
+++ b/app/assets/javascripts/notebook/cells/markdown.vue
@@ -148,6 +148,11 @@ export default {
type: Object,
required: true,
},
+ hidePrompt: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
computed: {
markdown() {
@@ -163,7 +168,7 @@ export default {
<template>
<div class="cell text-cell">
- <prompt />
+ <prompt v-if="!hidePrompt" />
<div v-safe-html:[$options.markdownConfig]="markdown" class="markdown"></div>
</div>
</template>
diff --git a/app/assets/javascripts/notebook/cells/output/index.vue b/app/assets/javascripts/notebook/cells/output/index.vue
index 88d01ffa659..bd01534089e 100644
--- a/app/assets/javascripts/notebook/cells/output/index.vue
+++ b/app/assets/javascripts/notebook/cells/output/index.vue
@@ -3,6 +3,9 @@ import CodeOutput from '../code/index.vue';
import HtmlOutput from './html.vue';
import ImageOutput from './image.vue';
import LatexOutput from './latex.vue';
+import MarkdownOutput from './markdown.vue';
+
+const TEXT_MARKDOWN = 'text/markdown';
export default {
props: {
@@ -35,6 +38,8 @@ export default {
return 'text/latex';
} else if (output.data['image/svg+xml']) {
return 'image/svg+xml';
+ } else if (output.data[TEXT_MARKDOWN]) {
+ return TEXT_MARKDOWN;
}
return 'text/plain';
@@ -42,7 +47,7 @@ export default {
dataForType(output, type) {
let data = output.data[type];
- if (typeof data === 'object') {
+ if (typeof data === 'object' && this.outputType(output) !== TEXT_MARKDOWN) {
data = data.join('');
}
@@ -61,6 +66,8 @@ export default {
return LatexOutput;
} else if (output.data['image/svg+xml']) {
return HtmlOutput;
+ } else if (output.data[TEXT_MARKDOWN]) {
+ return MarkdownOutput;
}
return CodeOutput;
diff --git a/app/assets/javascripts/notebook/cells/output/markdown.vue b/app/assets/javascripts/notebook/cells/output/markdown.vue
new file mode 100644
index 00000000000..5da057dee72
--- /dev/null
+++ b/app/assets/javascripts/notebook/cells/output/markdown.vue
@@ -0,0 +1,42 @@
+<script>
+import { GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
+import Prompt from '../prompt.vue';
+import Markdown from '../markdown.vue';
+
+export default {
+ name: 'MarkdownOutput',
+ components: {
+ Prompt,
+ Markdown,
+ },
+ directives: {
+ SafeHtml,
+ },
+ props: {
+ count: {
+ type: Number,
+ required: true,
+ },
+ rawCode: {
+ type: Array,
+ required: true,
+ },
+ index: {
+ type: Number,
+ required: true,
+ },
+ },
+ computed: {
+ markdownContent() {
+ return { source: this.rawCode };
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="output">
+ <prompt type="Out" :count="count" :show-output="index === 0" />
+ <markdown :cell="markdownContent" :hide-prompt="true" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/notes/components/discussion_notes.vue b/app/assets/javascripts/notes/components/discussion_notes.vue
index 2dbc9b10836..3e8cddc3174 100644
--- a/app/assets/javascripts/notes/components/discussion_notes.vue
+++ b/app/assets/javascripts/notes/components/discussion_notes.vue
@@ -52,6 +52,11 @@ export default {
required: false,
default: false,
},
+ shouldScrollToNote: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
},
computed: {
...mapGetters(['userCanReply']),
@@ -133,6 +138,7 @@ export default {
:discussion-root="true"
:discussion-resolve-path="discussion.resolve_path"
:is-overview-tab="isOverviewTab"
+ :should-scroll-to-note="shouldScrollToNote"
@handleDeleteNote="$emit('deleteNote')"
@startReplying="$emit('startReplying')"
>
@@ -183,6 +189,7 @@ export default {
:discussion-root="index === 0"
:discussion-resolve-path="discussion.resolve_path"
:is-overview-tab="isOverviewTab"
+ :should-scroll-to-note="shouldScrollToNote"
@handleDeleteNote="$emit('deleteNote')"
>
<template #avatar-badge>
diff --git a/app/assets/javascripts/notes/components/note_header.vue b/app/assets/javascripts/notes/components/note_header.vue
index f3530344181..63c7010983e 100644
--- a/app/assets/javascripts/notes/components/note_header.vue
+++ b/app/assets/javascripts/notes/components/note_header.vue
@@ -198,7 +198,7 @@ export default {
<gl-badge
v-if="isInternalNote"
v-gl-tooltip:tooltipcontainer.bottom
- data-testid="internalNoteIndicator"
+ data-testid="internal-note-indicator"
variant="warning"
size="sm"
class="gl-ml-2"
diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue
index 50d166b6db5..b668d6ec182 100644
--- a/app/assets/javascripts/notes/components/noteable_discussion.vue
+++ b/app/assets/javascripts/notes/components/noteable_discussion.vue
@@ -73,6 +73,11 @@ export default {
required: false,
default: false,
},
+ shouldScrollToNote: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
},
data() {
return {
@@ -288,6 +293,7 @@ export default {
:line="line"
:should-group-replies="shouldGroupReplies"
:is-overview-tab="isOverviewTab"
+ :should-scroll-to-note="shouldScrollToNote"
@startReplying="showReplyForm"
@deleteNote="deleteNoteHandler"
>
diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue
index c4b3111b919..8ce0c2f8648 100644
--- a/app/assets/javascripts/notes/components/noteable_note.vue
+++ b/app/assets/javascripts/notes/components/noteable_note.vue
@@ -91,6 +91,11 @@ export default {
required: false,
default: false,
},
+ shouldScrollToNote: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
},
data() {
return {
@@ -222,7 +227,7 @@ export default {
},
mounted() {
- if (this.isTarget) {
+ if (this.isTarget && this.shouldScrollToNote) {
this.scrollToNoteIfNeeded($(this.$el));
}
},
diff --git a/app/assets/javascripts/notes/components/notes_activity_header.vue b/app/assets/javascripts/notes/components/notes_activity_header.vue
index e4f88962731..9c3b2139a5d 100644
--- a/app/assets/javascripts/notes/components/notes_activity_header.vue
+++ b/app/assets/javascripts/notes/components/notes_activity_header.vue
@@ -27,7 +27,7 @@ export default {
<template>
<div
- class="gl-display-flex gl-sm-align-items-center gl-flex-direction-column gl-sm-flex-direction-row gl-justify-content-space-between gl-pt-5 gl-mt-5 gl-border-t"
+ class="gl-display-flex gl-sm-align-items-center gl-flex-direction-column gl-sm-flex-direction-row gl-justify-content-space-between gl-pt-5"
>
<h2 class="gl-font-size-h1 gl-m-0">{{ __('Activity') }}</h2>
<div class="gl-display-flex gl-gap-3 gl-w-full gl-sm-w-auto gl-mt-3 gl-sm-mt-0">
diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue
index 9c2ff2c3e7f..7bb1a1a1bfe 100644
--- a/app/assets/javascripts/notes/components/notes_app.vue
+++ b/app/assets/javascripts/notes/components/notes_app.vue
@@ -126,6 +126,9 @@ export default {
slotKeys() {
return this.sortDirDesc ? ['form', 'comments'] : ['comments', 'form'];
},
+ isAppReady() {
+ return !this.isLoading && !this.renderSkeleton && this.shouldShow;
+ },
},
watch: {
async isFetching() {
@@ -149,6 +152,15 @@ export default {
this.discussionsCount.textContent = val;
}
},
+ isAppReady: {
+ handler(isReady) {
+ if (!isReady) return;
+ this.$nextTick(() => {
+ window.mrTabs?.eventHub.$emit('NotesAppReady');
+ });
+ },
+ immediate: true,
+ },
},
created() {
this.discussionsCount = document.querySelector('.js-discussions-count');
diff --git a/app/assets/javascripts/notes/mixins/discussion_navigation.js b/app/assets/javascripts/notes/mixins/discussion_navigation.js
index d75a4158440..3dbcf28d11c 100644
--- a/app/assets/javascripts/notes/mixins/discussion_navigation.js
+++ b/app/assets/javascripts/notes/mixins/discussion_navigation.js
@@ -1,8 +1,12 @@
import { mapGetters, mapActions, mapState } from 'vuex';
import { scrollToElement, contentTop } from '~/lib/utils/common_utils';
+function isOverviewPage() {
+ return window.mrTabs?.currentAction === 'show';
+}
+
function getAllDiscussionElements() {
- const containerEl = window.mrTabs?.currentAction === 'diffs' ? '.diffs' : '.notes';
+ const containerEl = isOverviewPage() ? '.tab-pane.notes' : '.diffs';
return Array.from(
document.querySelectorAll(
`${containerEl} div[data-discussion-id]:not([data-discussion-resolved])`,
@@ -59,6 +63,14 @@ function getPreviousDiscussion() {
function handleJumpForBothPages(getDiscussion, ctx, fn, scrollOptions) {
const discussion = getDiscussion();
+ if (!isOverviewPage() && !discussion) {
+ window.mrTabs?.eventHub.$once('NotesAppReady', () => {
+ handleJumpForBothPages(getDiscussion, ctx, fn, scrollOptions);
+ });
+ window.mrTabs?.setCurrentAction('show');
+ window.mrTabs?.tabShown('show', undefined, false);
+ return;
+ }
const id = discussion.dataset.discussionId;
ctx.expandDiscussion({ discussionId: id });
scrollToElement(discussion, scrollOptions);
diff --git a/app/assets/javascripts/notes/stores/getters.js b/app/assets/javascripts/notes/stores/getters.js
index 6876220f75c..5ad7a811726 100644
--- a/app/assets/javascripts/notes/stores/getters.js
+++ b/app/assets/javascripts/notes/stores/getters.js
@@ -94,9 +94,9 @@ export const getUserDataByProp = (state) => (prop) => state.userData && state.us
export const descriptionVersions = (state) => state.descriptionVersions;
export const canUserAddIncidentTimelineEvents = (state) => {
- return (
- state.userData.can_add_timeline_events &&
- state.noteableData.type === constants.NOTEABLE_TYPE_MAPPING.Incident
+ return Boolean(
+ state.userData?.can_add_timeline_events &&
+ state.noteableData.type === constants.NOTEABLE_TYPE_MAPPING.Incident,
);
};
diff --git a/app/assets/javascripts/observability/components/observability_app.vue b/app/assets/javascripts/observability/components/observability_app.vue
new file mode 100644
index 00000000000..4f5e27be46f
--- /dev/null
+++ b/app/assets/javascripts/observability/components/observability_app.vue
@@ -0,0 +1,42 @@
+<script>
+export default {
+ props: {
+ observabilityIframeSrc: {
+ type: String,
+ required: true,
+ },
+ },
+ mounted() {
+ window.addEventListener('message', this.messageHandler);
+ },
+ methods: {
+ messageHandler(e) {
+ const isExpectedOrigin = e.origin === new URL(this.observabilityIframeSrc)?.origin;
+
+ const isNewObservabilityPath = this.$route?.query?.observability_path !== e.data?.url;
+
+ const shouldNotHandleMessage = !isExpectedOrigin || !e.data.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: e.data.url },
+ });
+ },
+ },
+};
+</script>
+
+<template>
+ <iframe
+ id="observability-ui-iframe"
+ data-testid="observability-ui-iframe"
+ frameborder="0"
+ height="100%"
+ :src="observabilityIframeSrc"
+ ></iframe>
+</template>
diff --git a/app/assets/javascripts/observability/index.js b/app/assets/javascripts/observability/index.js
new file mode 100644
index 00000000000..cd342ebee3e
--- /dev/null
+++ b/app/assets/javascripts/observability/index.js
@@ -0,0 +1,28 @@
+import Vue from 'vue';
+import VueRouter from 'vue-router';
+
+import ObservabilityApp from './components/observability_app.vue';
+
+Vue.use(VueRouter);
+
+export default () => {
+ const el = document.getElementById('js-observability-app');
+
+ if (!el) return false;
+
+ const router = new VueRouter({
+ mode: 'history',
+ });
+
+ return new Vue({
+ el,
+ router,
+ render(h) {
+ return h(ObservabilityApp, {
+ props: {
+ observabilityIframeSrc: el.dataset.observabilityIframeSrc,
+ },
+ });
+ },
+ });
+};
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 80bca536b7c..23d8e97dd79 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
@@ -3,7 +3,6 @@ import { GlTooltipDirective, GlIcon, GlSprintf, GlSkeletonLoader, GlButton } fro
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { n__ } from '~/locale';
import Tracking from '~/tracking';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
import { joinPaths } from '~/lib/utils/url_utility';
@@ -38,7 +37,7 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
- mixins: [Tracking.mixin(), glFeatureFlagsMixin()],
+ mixins: [Tracking.mixin()],
inject: ['config'],
props: {
item: {
@@ -91,17 +90,14 @@ export default {
);
},
imageName() {
- if (this.glFeatures.containerRegistryShowShortenedPath) {
- if (this.showFullPath) {
- return this.item.path;
- }
- const projectPath = this.item?.project?.path?.toLowerCase() ?? '';
- if (this.item.name) {
- return joinPaths(projectPath, this.item.name);
- }
- return projectPath;
+ if (this.showFullPath) {
+ return this.item.path;
}
- return this.item.path;
+ const projectPath = this.item?.project?.path?.toLowerCase() ?? '';
+ if (this.item.name) {
+ return joinPaths(projectPath, this.item.name);
+ }
+ return projectPath;
},
routerLinkEvent() {
return this.deleting ? '' : 'click';
@@ -136,7 +132,7 @@ export default {
>
<template #left-primary>
<gl-button
- v-if="glFeatures.containerRegistryShowShortenedPath && !showFullPath"
+ v-if="!showFullPath"
v-gl-tooltip="{
placement: 'top',
title: $options.i18n.IMAGE_FULL_PATH_LABEL,
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue
index 19d35a135fd..ba8caabb40a 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue
@@ -95,13 +95,8 @@ export default {
<template #right-actions>
<slot name="commands"></slot>
</template>
- <template #metadata-count>
- <metadata-item
- v-if="imagesCount"
- data-testid="images-count"
- icon="container-image"
- :text="imagesCountText"
- />
+ <template v-if="imagesCount" #metadata-count>
+ <metadata-item data-testid="images-count" icon="container-image" :text="imagesCountText" />
</template>
<template #metadata-exp-policies>
<metadata-item
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/index.js b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/index.js
index 9694bfd4e77..9b062024d03 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/index.js
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/index.js
@@ -4,11 +4,29 @@ import createDefaultClient from '~/lib/graphql';
Vue.use(VueApollo);
+export const mergeVariables = (existing, incoming) => {
+ if (!incoming) return existing;
+ if (!existing) return incoming;
+ return incoming;
+};
+
export const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(
{},
{
batchMax: 1,
+ cacheConfig: {
+ typePolicies: {
+ ContainerRepositoryDetails: {
+ fields: {
+ tags: {
+ keyArgs: ['id'],
+ merge: mergeVariables,
+ },
+ },
+ },
+ },
+ },
},
),
});
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 8b66165a57a..b339c8c8371 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
@@ -31,6 +31,7 @@ import {
import deleteContainerRepositoryTagsMutation from '../graphql/mutations/delete_container_repository_tags.mutation.graphql';
import getContainerRepositoryDetailsQuery from '../graphql/queries/get_container_repository_details.query.graphql';
import getContainerRepositoryTagsQuery from '../graphql/queries/get_container_repository_tags.query.graphql';
+import getContainerRepositoriesDetails from '../graphql/queries/get_container_repositories_details.query.graphql';
const REPOSITORY_IMPORTING_ERROR_MESSAGE = 'repository importing';
@@ -145,6 +146,13 @@ export default {
query: getContainerRepositoryTagsQuery,
variables: { ...this.queryVariables, first: GRAPHQL_PAGE_SIZE },
},
+ {
+ query: getContainerRepositoriesDetails,
+ variables: {
+ fullPath: this.config.isGroupPage ? this.config.groupPath : this.config.projectPath,
+ isGroupPage: this.config.isGroupPage,
+ },
+ },
],
});
diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list.vue b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list.vue
index 8b6a5c59847..707e8f09045 100644
--- a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list.vue
+++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list.vue
@@ -1,8 +1,8 @@
<script>
-import { GlPagination, GlModal, GlSprintf } from '@gitlab/ui';
+import { GlPagination } from '@gitlab/ui';
import { mapState, mapGetters } from 'vuex';
-import { __, s__ } from '~/locale';
import Tracking from '~/tracking';
+import DeletePackageModal from '~/packages_and_registries/shared/components/delete_package_modal.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 { TRACKING_ACTIONS } from '~/packages_and_registries/shared/constants';
@@ -11,8 +11,7 @@ import { TRACK_CATEGORY } from '~/packages_and_registries/infrastructure_registr
export default {
components: {
GlPagination,
- GlModal,
- GlSprintf,
+ DeletePackageModal,
PackagesListLoader,
PackagesListRow,
},
@@ -42,22 +41,6 @@ export default {
isListEmpty() {
return !this.list || this.list.length === 0;
},
- deletePackageName() {
- return this.itemToBeDeleted?.name ?? '';
- },
- deleteModalActionPrimaryProps() {
- return {
- text: this.$options.i18n.modalAction,
- attributes: {
- variant: 'danger',
- },
- };
- },
- deleteModalActionCancelProps() {
- return {
- text: __('Cancel'),
- };
- },
tracking() {
return {
category: TRACK_CATEGORY,
@@ -68,7 +51,6 @@ export default {
setItemToBeDeleted(item) {
this.itemToBeDeleted = { ...item };
this.track(TRACKING_ACTIONS.REQUEST_DELETE_PACKAGE);
- this.$refs.packageListDeleteModal.show();
},
deleteItemConfirmation() {
this.$emit('package:delete', this.itemToBeDeleted);
@@ -80,11 +62,6 @@ export default {
this.itemToBeDeleted = null;
},
},
- i18n: {
- deleteModalContent: s__('PackageRegistry|You are about to delete %{name}, are you sure?'),
- modalTitle: s__('PackageRegistry|Delete package'),
- modalAction: s__('PackageRegistry|Permanently delete'),
- },
};
</script>
@@ -116,22 +93,11 @@ export default {
class="gl-w-full gl-mt-3"
/>
- <gl-modal
- ref="packageListDeleteModal"
- size="sm"
- modal-id="confirm-delete-package"
- :action-primary="deleteModalActionPrimaryProps"
- :action-cancel="deleteModalActionCancelProps"
+ <delete-package-modal
+ :item-to-be-deleted="itemToBeDeleted"
@ok="deleteItemConfirmation"
@cancel="deleteItemCanceled"
- >
- <template #modal-title>{{ $options.i18n.modalTitle }}</template>
- <gl-sprintf :message="$options.i18n.deleteModalContent">
- <template #name>
- <strong>{{ deletePackageName }}</strong>
- </template>
- </gl-sprintf>
- </gl-modal>
+ />
</template>
</div>
</template>
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
new file mode 100644
index 00000000000..2a1de2ae4a7
--- /dev/null
+++ b/app/assets/javascripts/packages_and_registries/package_registry/components/delete_modal.vue
@@ -0,0 +1,61 @@
+<script>
+import { GlModal } from '@gitlab/ui';
+import { __, n__ } from '~/locale';
+import {
+ DELETE_PACKAGES_MODAL_TITLE,
+ DELETE_PACKAGE_MODAL_PRIMARY_ACTION,
+} from '~/packages_and_registries/package_registry/constants';
+
+export default {
+ name: 'DeleteModal',
+ i18n: {
+ DELETE_PACKAGES_MODAL_TITLE,
+ },
+ components: {
+ GlModal,
+ },
+ props: {
+ itemsToBeDeleted: {
+ type: Array,
+ required: true,
+ },
+ },
+ computed: {
+ description() {
+ return n__(
+ 'PackageRegistry|You are about to delete 1 package. This operation is irreversible.',
+ `PackageRegistry|You are about to delete %d packages. This operation is irreversible.`,
+ this.itemsToBeDeleted.length,
+ );
+ },
+ },
+ modal: {
+ packagesDeletePrimaryAction: {
+ text: DELETE_PACKAGE_MODAL_PRIMARY_ACTION,
+ attributes: [{ variant: 'danger' }, { category: 'primary' }],
+ },
+ cancelAction: {
+ text: __('Cancel'),
+ },
+ },
+ methods: {
+ show() {
+ this.$refs.deleteModal.show();
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-modal
+ ref="deleteModal"
+ size="sm"
+ modal-id="delete-packages-modal"
+ :action-primary="$options.modal.packagesDeletePrimaryAction"
+ :action-cancel="$options.modal.cancelAction"
+ :title="$options.i18n.DELETE_PACKAGES_MODAL_TITLE"
+ @primary="$emit('confirm')"
+ >
+ <span>{{ description }}</span>
+ </gl-modal>
+</template>
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
new file mode 100644
index 00000000000..efc60c9c037
--- /dev/null
+++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_versions_list.vue
@@ -0,0 +1,57 @@
+<script>
+import { GlKeysetPagination } from '@gitlab/ui';
+import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
+import PackagesListLoader from '~/packages_and_registries/shared/components/packages_list_loader.vue';
+
+export default {
+ components: {
+ VersionRow,
+ GlKeysetPagination,
+ PackagesListLoader,
+ },
+ props: {
+ versions: {
+ type: Array,
+ required: true,
+ default: () => [],
+ },
+ pageInfo: {
+ type: Object,
+ required: true,
+ },
+ isLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ showPagination() {
+ return this.pageInfo.hasPreviousPage || this.pageInfo.hasNextPage;
+ },
+ isListEmpty() {
+ return this.versions.length === 0;
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <div v-if="isLoading">
+ <packages-list-loader />
+ </div>
+ <slot v-else-if="isListEmpty" name="empty-state"></slot>
+ <div v-else>
+ <version-row v-for="version in versions" :key="version.id" :package-entity="version" />
+ <div class="gl-display-flex gl-justify-content-center">
+ <gl-keyset-pagination
+ v-if="showPagination"
+ v-bind="pageInfo"
+ class="gl-mt-3"
+ @prev="$emit('prev-page')"
+ @next="$emit('next-page')"
+ />
+ </div>
+ </div>
+ </div>
+</template>
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 7a000aca0f2..4553dd3421b 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
@@ -2,6 +2,7 @@
import {
GlDropdown,
GlDropdownItem,
+ GlFormCheckbox,
GlIcon,
GlSprintf,
GlTooltipDirective,
@@ -26,6 +27,7 @@ export default {
components: {
GlDropdown,
GlDropdownItem,
+ GlFormCheckbox,
GlIcon,
GlSprintf,
GlTruncate,
@@ -45,6 +47,11 @@ export default {
type: Object,
required: true,
},
+ selected: {
+ type: Boolean,
+ default: false,
+ required: false,
+ },
},
computed: {
packageType() {
@@ -90,7 +97,15 @@ export default {
</script>
<template>
- <list-item data-testid="package-row">
+ <list-item data-testid="package-row" v-bind="$attrs">
+ <template #left-action>
+ <gl-form-checkbox
+ v-if="packageEntity.canDestroy"
+ class="gl-m-0"
+ :checked="selected"
+ @change="$emit('select')"
+ />
+ </template>
<template #left-primary>
<div class="gl-display-flex gl-align-items-center gl-mr-3 gl-min-w-0">
<router-link
@@ -168,12 +183,9 @@ export default {
category="tertiary"
no-caret
>
- <gl-dropdown-item
- data-testid="action-delete"
- variant="danger"
- @click="$emit('packageToDelete', packageEntity)"
- >{{ $options.i18n.deletePackage }}</gl-dropdown-item
- >
+ <gl-dropdown-item data-testid="action-delete" variant="danger" @click="$emit('delete')">{{
+ $options.i18n.deletePackage
+ }}</gl-dropdown-item>
</gl-dropdown>
</template>
</list-item>
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list.vue
index c6583b8f09f..ddcddf80c15 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list.vue
+++ b/app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list.vue
@@ -1,8 +1,10 @@
<script>
-import { GlAlert, GlModal, GlSprintf, GlKeysetPagination } from '@gitlab/ui';
-import { __, s__, sprintf } from '~/locale';
+import { GlAlert } from '@gitlab/ui';
+import { s__, sprintf, n__ } from '~/locale';
+import DeletePackageModal from '~/packages_and_registries/shared/components/delete_package_modal.vue';
import PackagesListRow from '~/packages_and_registries/package_registry/components/list/package_list_row.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 {
DELETE_PACKAGE_TRACKING_ACTION,
REQUEST_DELETE_PACKAGE_TRACKING_ACTION,
@@ -13,13 +15,13 @@ import { packageTypeToTrackCategory } from '~/packages_and_registries/package_re
import Tracking from '~/tracking';
export default {
+ name: 'PackagesList',
components: {
GlAlert,
- GlKeysetPagination,
- GlModal,
- GlSprintf,
+ DeletePackageModal,
PackagesListLoader,
PackagesListRow,
+ RegistryList,
},
mixins: [Tracking.mixin()],
props: {
@@ -46,12 +48,12 @@ export default {
};
},
computed: {
+ listTitle() {
+ return n__('%d package', '%d packages', this.list.length);
+ },
isListEmpty() {
return !this.list || this.list.length === 0;
},
- deletePackageName() {
- return this.itemToBeDeleted?.name ?? '';
- },
tracking() {
const category = this.itemToBeDeleted
? packageTypeToTrackCategory(this.itemToBeDeleted.packageType)
@@ -60,32 +62,6 @@ export default {
category,
};
},
- showPagination() {
- return this.pageInfo.hasPreviousPage || this.pageInfo.hasNextPage;
- },
- showDeleteModal: {
- get() {
- return Boolean(this.itemToBeDeleted);
- },
- set(value) {
- if (!value) {
- this.itemToBeDeleted = null;
- }
- },
- },
- deleteModalActionPrimaryProps() {
- return {
- text: this.$options.i18n.modalAction,
- attributes: {
- variant: 'danger',
- },
- };
- },
- deleteModalActionCancelProps() {
- return {
- text: __('Cancel'),
- };
- },
errorTitleAlert() {
return sprintf(
s__('PackageRegistry|There was an error publishing a %{packageName} package'),
@@ -110,21 +86,28 @@ export default {
this.itemToBeDeleted = { ...item };
this.track(REQUEST_DELETE_PACKAGE_TRACKING_ACTION);
},
+ setItemsToBeDeleted(items) {
+ if (items.length === 1) {
+ const [item] = items;
+ this.setItemToBeDeleted(item);
+ return;
+ }
+ this.$emit('delete', items);
+ },
deleteItemConfirmation() {
this.$emit('package:delete', this.itemToBeDeleted);
this.track(DELETE_PACKAGE_TRACKING_ACTION);
+ this.itemToBeDeleted = null;
},
deleteItemCanceled() {
this.track(CANCEL_DELETE_PACKAGE_TRACKING_ACTION);
+ this.itemToBeDeleted = null;
},
showConfirmationModal() {
this.setItemToBeDeleted(this.errorPackages[0]);
},
},
i18n: {
- deleteModalContent: s__('PackageRegistry|You are about to delete %{name}, are you sure?'),
- modalTitle: s__('PackageRegistry|Delete package'),
- modalAction: s__('PackageRegistry|Permanently delete'),
errorMessageBodyAlert: s__(
'PackageRegistry|There was a timeout and the package was not published. Delete this package and try again.',
),
@@ -150,41 +133,32 @@ export default {
@primaryAction="showConfirmationModal"
>{{ $options.i18n.errorMessageBodyAlert }}</gl-alert
>
- <div data-testid="packages-table">
- <packages-list-row
- v-for="packageEntity in list"
- :key="packageEntity.id"
- :package-entity="packageEntity"
- @packageToDelete="setItemToBeDeleted"
- />
- </div>
-
- <div class="gl-display-flex gl-justify-content-center">
- <gl-keyset-pagination
- v-if="showPagination"
- v-bind="pageInfo"
- class="gl-mt-3"
- @prev="$emit('prev-page')"
- @next="$emit('next-page')"
- />
- </div>
+ <registry-list
+ data-testid="packages-table"
+ :is-loading="isLoading"
+ :items="list"
+ :pagination="pageInfo"
+ :title="listTitle"
+ @delete="setItemsToBeDeleted"
+ @prev-page="$emit('prev-page')"
+ @next-page="$emit('next-page')"
+ >
+ <template #default="{ selectItem, isSelected, item, first }">
+ <packages-list-row
+ :first="first"
+ :package-entity="item"
+ :selected="isSelected(item)"
+ @delete="setItemToBeDeleted(item)"
+ @select="selectItem(item)"
+ />
+ </template>
+ </registry-list>
- <gl-modal
- v-model="showDeleteModal"
- modal-id="confirm-delete-package"
- size="sm"
- :action-primary="deleteModalActionPrimaryProps"
- :action-cancel="deleteModalActionCancelProps"
+ <delete-package-modal
+ :item-to-be-deleted="itemToBeDeleted"
@ok="deleteItemConfirmation"
@cancel="deleteItemCanceled"
- >
- <template #modal-title>{{ $options.i18n.modalTitle }}</template>
- <gl-sprintf :message="$options.i18n.deleteModalContent">
- <template #name>
- <strong>{{ deletePackageName }}</strong>
- </template>
- </gl-sprintf>
- </gl-modal>
+ />
</template>
</div>
</template>
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 4e35176c757..b731cd77e66 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/constants.js
+++ b/app/assets/javascripts/packages_and_registries/package_registry/constants.js
@@ -110,6 +110,13 @@ export const FETCH_PACKAGE_PIPELINES_ERROR_MESSAGE = s__(
export const FETCH_PACKAGE_METADATA_ERROR_MESSAGE = s__(
'PackageRegistry|Something went wrong while fetching the package metadata.',
);
+export const DELETE_PACKAGES_ERROR_MESSAGE = s__(
+ 'PackageRegistry|Something went wrong while deleting packages.',
+);
+export const DELETE_PACKAGES_SUCCESS_MESSAGE = s__('PackageRegistry|Packages deleted successfully');
+
+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_SUCCESS_MESSAGE = s__('PackageRegistry|Package deleted successfully');
export const PACKAGE_REGISTRY_TITLE = __('Package Registry');
@@ -177,6 +184,9 @@ export const PACKAGE_TYPES = [
s__('PackageRegistry|Helm'),
];
+export const HIDE_PACKAGE_MIGRATION_SURVEY_COOKIE = 'hide_package_registry_migration_survey';
+export const SURVEY_LINK = 'https://gitlab.fra1.qualtrics.com/jfe/form/SV_cHomH9FPzOaiDTU';
+
// links
export const EMPTY_LIST_HELP_URL = helpPagePath('user/packages/package_registry/index');
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/graphql/mutations/destroy_packages.mutation.graphql b/app/assets/javascripts/packages_and_registries/package_registry/graphql/mutations/destroy_packages.mutation.graphql
new file mode 100644
index 00000000000..e1ff5518bf8
--- /dev/null
+++ b/app/assets/javascripts/packages_and_registries/package_registry/graphql/mutations/destroy_packages.mutation.graphql
@@ -0,0 +1,5 @@
+mutation destroyPackages($ids: [PackagesPackageID!]!) {
+ destroyPackages(input: { ids: $ids }) {
+ errors
+ }
+}
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 8e50c95b10b..51e0ab5aba8 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
@@ -1,4 +1,10 @@
-query getPackageDetails($id: PackagesPackageID!) {
+query getPackageDetails(
+ $id: PackagesPackageID!
+ $first: Int
+ $last: Int
+ $after: String
+ $before: String
+) {
package(id: $id) {
id
name
@@ -55,7 +61,7 @@ query getPackageDetails($id: PackagesPackageID!) {
downloadPath
}
}
- versions(first: 100) {
+ versions(after: $after, before: $before, first: $first, last: $last) {
nodes {
id
name
@@ -69,6 +75,12 @@ query getPackageDetails($id: PackagesPackageID!) {
}
}
}
+ pageInfo {
+ hasNextPage
+ hasPreviousPage
+ endCursor
+ startCursor
+ }
}
dependencyLinks {
nodes {
diff --git a/app/assets/javascripts/packages_and_registries/package_registry/index.js b/app/assets/javascripts/packages_and_registries/package_registry/index.js
index 6680e612985..336eb0ca079 100644
--- a/app/assets/javascripts/packages_and_registries/package_registry/index.js
+++ b/app/assets/javascripts/packages_and_registries/package_registry/index.js
@@ -36,6 +36,7 @@ export default () => {
const attachMainComponent = () =>
new Vue({
el,
+ name: 'PackageRegistery',
router,
apolloProvider,
provide: {
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 eeed56b77c3..c59dcaee411 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
@@ -22,7 +22,7 @@ import InstallationCommands from '~/packages_and_registries/package_registry/com
import PackageFiles from '~/packages_and_registries/package_registry/components/details/package_files.vue';
import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue';
-import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
+import PackageVersionsList from '~/packages_and_registries/package_registry/components/details/package_versions_list.vue';
import DeletePackage from '~/packages_and_registries/package_registry/components/functional/delete_package.vue';
import {
PACKAGE_TYPE_NUGET,
@@ -48,6 +48,7 @@ import {
DELETE_MODAL_CONTENT,
DELETE_ALL_PACKAGE_FILES_MODAL_CONTENT,
DELETE_LAST_PACKAGE_FILE_MODAL_CONTENT,
+ GRAPHQL_PAGE_SIZE,
} from '~/packages_and_registries/package_registry/constants';
import destroyPackageFilesMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_package_files.mutation.graphql';
@@ -65,13 +66,13 @@ export default {
GlTabs,
GlSprintf,
PackageTitle,
- VersionRow,
DependencyRow,
PackageHistory,
AdditionalMetadata,
InstallationCommands,
PackageFiles,
DeletePackage,
+ PackageVersionsList,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -132,6 +133,7 @@ export default {
queryVariables() {
return {
id: convertToGraphQLId('Packages::Package', this.packageId),
+ first: GRAPHQL_PAGE_SIZE,
};
},
packageFiles() {
@@ -157,6 +159,9 @@ export default {
hasVersions() {
return this.packageEntity.versions?.nodes?.length > 0;
},
+ versionPageInfo() {
+ return this.packageEntity?.versions?.pageInfo ?? {};
+ },
packageDependencies() {
return this.packageEntity.dependencyLinks?.nodes || [];
},
@@ -264,6 +269,34 @@ export default {
resetDeleteModalContent() {
this.deletePackageModalContent = DELETE_MODAL_CONTENT;
},
+ updateQuery(_, { fetchMoreResult }) {
+ return fetchMoreResult;
+ },
+ fetchPreviousVersionsPage() {
+ const variables = {
+ ...this.queryVariables,
+ first: null,
+ last: GRAPHQL_PAGE_SIZE,
+ before: this.versionPageInfo?.startCursor,
+ };
+ this.$apollo.queries.packageEntity.fetchMore({
+ variables,
+ updateQuery: this.updateQuery,
+ });
+ },
+ fetchNextVersionsPage() {
+ const variables = {
+ ...this.queryVariables,
+ first: GRAPHQL_PAGE_SIZE,
+ last: null,
+ after: this.versionPageInfo?.endCursor,
+ };
+
+ this.$apollo.queries.packageEntity.fetchMore({
+ variables,
+ updateQuery: this.updateQuery,
+ });
+ },
},
i18n: {
DELETE_MODAL_TITLE,
@@ -271,6 +304,7 @@ export default {
deleteFileModalContent: s__(
`PackageRegistry|You are about to delete %{filename}. This is a destructive action that may render your package unusable. Are you sure?`,
),
+ otherVersionsTabTitle: __('Other versions'),
},
modal: {
packageDeletePrimaryAction: {
@@ -303,7 +337,7 @@ export default {
:description="s__('PackageRegistry|There was a problem fetching the details for this package.')"
:svg-path="emptyListIllustration"
/>
- <div v-else-if="!isLoading" class="packages-app">
+ <div v-else-if="projectName" class="packages-app">
<package-title :package-entity="packageEntity">
<template #delete-button>
<gl-button
@@ -358,14 +392,20 @@ export default {
</p>
</gl-tab>
- <gl-tab :title="__('Other versions')" title-item-class="js-versions-tab">
- <template v-if="hasVersions">
- <version-row v-for="v in packageEntity.versions.nodes" :key="v.id" :package-entity="v" />
- </template>
-
- <p v-else class="gl-mt-3" data-testid="no-versions-message">
- {{ s__('PackageRegistry|There are no other versions of this package.') }}
- </p>
+ <gl-tab :title="$options.i18n.otherVersionsTabTitle" title-item-class="js-versions-tab" lazy>
+ <package-versions-list
+ :is-loading="isLoading"
+ :page-info="versionPageInfo"
+ :versions="packageEntity.versions.nodes"
+ @prev-page="fetchPreviousVersionsPage"
+ @next-page="fetchNextVersionsPage"
+ >
+ <template #empty-state>
+ <p class="gl-mt-3" data-testid="no-versions-message">
+ {{ s__('PackageRegistry|There are no other versions of this package.') }}
+ </p>
+ </template>
+ </package-versions-list>
</gl-tab>
</gl-tabs>
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 ed9ab0367dd..8b5d51cb856 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,41 +1,52 @@
<script>
-import { GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui';
+import { GlAlert, GlBanner, GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui';
import { createAlert, VARIANT_INFO } from '~/flash';
-import { historyReplaceState } from '~/lib/utils/common_utils';
+import { getCookie, historyReplaceState, parseBoolean, setCookie } 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,
+ HIDE_PACKAGE_MIGRATION_SURVEY_COOKIE,
DELETE_PACKAGE_SUCCESS_MESSAGE,
+ DELETE_PACKAGES_ERROR_MESSAGE,
+ DELETE_PACKAGES_SUCCESS_MESSAGE,
EMPTY_LIST_HELP_URL,
PACKAGE_HELP_URL,
+ SURVEY_LINK,
} from '~/packages_and_registries/package_registry/constants';
import getPackagesQuery from '~/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql';
-
+import destroyPackagesMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_packages.mutation.graphql';
import DeletePackage from '~/packages_and_registries/package_registry/components/functional/delete_package.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 PackageList from '~/packages_and_registries/package_registry/components/list/packages_list.vue';
+import DeleteModal from '~/packages_and_registries/package_registry/components/delete_modal.vue';
export default {
components: {
+ GlAlert,
+ GlBanner,
GlEmptyState,
GlLink,
GlSprintf,
PackageList,
PackageTitle,
PackageSearch,
+ DeleteModal,
DeletePackage,
},
inject: ['emptyListIllustration', 'isGroupPage', 'fullPath'],
data() {
return {
+ alertVariables: null,
+ itemsToBeDeleted: [],
packages: {},
sort: '',
filters: {},
mutationLoading: false,
+ showSurveyBanner: !parseBoolean(getCookie(HIDE_PACKAGE_MIGRATION_SURVEY_COOKIE)),
};
},
apollo: {
@@ -110,10 +121,53 @@ export default {
historyReplaceState(cleanUrl);
}
},
+ async confirmDelete() {
+ const { itemsToBeDeleted } = this;
+ this.itemsToBeDeleted = [];
+ this.mutationLoading = true;
+ try {
+ const { data } = await this.$apollo.mutate({
+ mutation: destroyPackagesMutation,
+ variables: {
+ ids: itemsToBeDeleted.map((i) => i.id),
+ },
+ awaitRefetchQueries: true,
+ refetchQueries: [
+ {
+ query: getPackagesQuery,
+ variables: { ...this.queryVariables, first: GRAPHQL_PAGE_SIZE },
+ },
+ ],
+ });
+
+ if (data?.destroyPackages?.errors[0]) {
+ throw new Error(data.destroyPackages.errors[0]);
+ }
+ this.showAlert({
+ variant: 'success',
+ message: DELETE_PACKAGES_SUCCESS_MESSAGE,
+ });
+ } catch {
+ this.showAlert({
+ variant: 'danger',
+ message: DELETE_PACKAGES_ERROR_MESSAGE,
+ });
+ } finally {
+ this.mutationLoading = false;
+ }
+ },
+ showDeletePackagesModal(toBeDeleted) {
+ this.itemsToBeDeleted = toBeDeleted;
+ this.$refs.deletePackagesModal.show();
+ },
handleSearchUpdate({ sort, filters }) {
this.sort = sort;
this.filters = { ...filters };
},
+ hideSurvey() {
+ this.showSurveyBanner = false;
+ setCookie(HIDE_PACKAGE_MIGRATION_SURVEY_COOKIE, 'true');
+ },
updateQuery(_, { fetchMoreResult }) {
return fetchMoreResult;
},
@@ -143,6 +197,9 @@ export default {
updateQuery: this.updateQuery,
});
},
+ showAlert(obj) {
+ this.alertVariables = { ...obj };
+ },
},
i18n: {
widenFilters: s__('PackageRegistry|To widen your search, change or remove the filters above.'),
@@ -151,18 +208,44 @@ export default {
noResultsText: s__(
'PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab.',
),
+ surveyBannerTitle: s__('PackageRegistry|Help us learn about your registry migration needs'),
+ surveyBannerDescription: s__(
+ 'PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs.',
+ ),
+ surveyBannerPrimaryButtonText: s__('PackageRegistry|Take survey'),
},
links: {
EMPTY_LIST_HELP_URL,
PACKAGE_HELP_URL,
},
+ surveyLink: SURVEY_LINK,
};
</script>
<template>
<div>
+ <gl-alert
+ v-if="alertVariables"
+ :variant="alertVariables.variant"
+ class="gl-mt-5"
+ dismissible
+ @dismiss="alertVariables = null"
+ >
+ {{ alertVariables.message }}
+ </gl-alert>
+ <gl-banner
+ v-if="showSurveyBanner"
+ :title="$options.i18n.surveyBannerTitle"
+ :button-text="$options.i18n.surveyBannerPrimaryButtonText"
+ :button-link="$options.surveyLink"
+ class="gl-mt-3"
+ @primary="hideSurvey"
+ @close="hideSurvey"
+ >
+ <p>{{ $options.i18n.surveyBannerDescription }}</p>
+ </gl-banner>
<package-title :help-url="$options.links.PACKAGE_HELP_URL" :count="packagesCount" />
- <package-search @update="handleSearchUpdate" />
+ <package-search class="gl-mb-5" @update="handleSearchUpdate" />
<delete-package
:refetch-queries="refetchQueriesData"
@@ -178,6 +261,7 @@ export default {
@prev-page="fetchPreviousPage"
@next-page="fetchNextPage"
@package:delete="deletePackage"
+ @delete="showDeletePackagesModal"
>
<template #empty-state>
<gl-empty-state :title="emptyStateTitle" :svg-path="emptyListIllustration">
@@ -196,5 +280,11 @@ export default {
</package-list>
</template>
</delete-package>
+
+ <delete-modal
+ ref="deletePackagesModal"
+ :items-to-be-deleted="itemsToBeDeleted"
+ @confirm="confirmDelete"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/packages_and_registries/settings/group/components/forwarding_settings.vue b/app/assets/javascripts/packages_and_registries/settings/group/components/forwarding_settings.vue
new file mode 100644
index 00000000000..c7fddadab1b
--- /dev/null
+++ b/app/assets/javascripts/packages_and_registries/settings/group/components/forwarding_settings.vue
@@ -0,0 +1,91 @@
+<script>
+import { GlFormCheckbox, GlFormGroup, GlSprintf } from '@gitlab/ui';
+import { isEqual } from 'lodash';
+import {
+ PACKAGE_FORWARDING_CHECKBOX_LABEL,
+ PACKAGE_FORWARDING_ENFORCE_LABEL,
+} from '~/packages_and_registries/settings/group/constants';
+
+export default {
+ name: 'ForwardingSettings',
+ i18n: {
+ PACKAGE_FORWARDING_CHECKBOX_LABEL,
+ PACKAGE_FORWARDING_ENFORCE_LABEL,
+ },
+ components: {
+ GlFormCheckbox,
+ GlFormGroup,
+ GlSprintf,
+ },
+ props: {
+ disabled: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ forwarding: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ label: {
+ type: String,
+ required: true,
+ },
+ lockForwarding: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ modelNames: {
+ type: Object,
+ required: true,
+ validator(value) {
+ return isEqual(Object.keys(value), ['forwarding', 'lockForwarding', 'isLocked']);
+ },
+ },
+ },
+ computed: {
+ fields() {
+ return [
+ {
+ testid: 'forwarding-checkbox',
+ label: PACKAGE_FORWARDING_CHECKBOX_LABEL,
+ updateField: this.modelNames.forwarding,
+ checked: this.forwarding,
+ },
+ {
+ testid: 'lock-forwarding-checkbox',
+ label: PACKAGE_FORWARDING_ENFORCE_LABEL,
+ updateField: this.modelNames.lockForwarding,
+ checked: this.lockForwarding,
+ },
+ ];
+ },
+ },
+ methods: {
+ update(type, value) {
+ this.$emit('update', type, value);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-form-group :label="label">
+ <gl-form-checkbox
+ v-for="field in fields"
+ :key="field.testid"
+ :checked="field.checked"
+ :disabled="disabled"
+ :data-testid="field.testid"
+ @change="update(field.updateField, $event)"
+ >
+ <gl-sprintf :message="field.label">
+ <template #packageType>
+ {{ label }}
+ </template>
+ </gl-sprintf>
+ </gl-form-checkbox>
+ </gl-form-group>
+</template>
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 f285dfc0755..36eb65c623b 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
@@ -2,6 +2,7 @@
import { GlAlert } from '@gitlab/ui';
import { n__ } from '~/locale';
import PackagesSettings from '~/packages_and_registries/settings/group/components/packages_settings.vue';
+import PackagesForwardingSettings from '~/packages_and_registries/settings/group/components/packages_forwarding_settings.vue';
import DependencyProxySettings from '~/packages_and_registries/settings/group/components/dependency_proxy_settings.vue';
import getGroupPackagesSettingsQuery from '~/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql';
@@ -11,6 +12,7 @@ export default {
components: {
GlAlert,
PackagesSettings,
+ PackagesForwardingSettings,
DependencyProxySettings,
},
inject: ['groupPath'],
@@ -82,6 +84,12 @@ export default {
@error="handleError(2)"
/>
+ <packages-forwarding-settings
+ :forward-settings="packageSettings"
+ @success="handleSuccess(2)"
+ @error="handleError(2)"
+ />
+
<dependency-proxy-settings
:dependency-proxy-settings="dependencyProxySettings"
:dependency-proxy-image-ttl-policy="dependencyProxyImageTtlPolicy"
diff --git a/app/assets/javascripts/packages_and_registries/settings/group/components/packages_forwarding_settings.vue b/app/assets/javascripts/packages_and_registries/settings/group/components/packages_forwarding_settings.vue
new file mode 100644
index 00000000000..b7d7f0aaca7
--- /dev/null
+++ b/app/assets/javascripts/packages_and_registries/settings/group/components/packages_forwarding_settings.vue
@@ -0,0 +1,190 @@
+<script>
+import { GlButton } from '@gitlab/ui';
+import { isEqual } from 'lodash';
+import {
+ PACKAGE_FORWARDING_SETTINGS_HEADER,
+ PACKAGE_FORWARDING_SETTINGS_DESCRIPTION,
+ PACKAGE_FORWARDING_FORM_BUTTON,
+ PACKAGE_FORWARDING_FIELDS,
+ MAVEN_FORWARDING_FIELDS,
+} from '~/packages_and_registries/settings/group/constants';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import updateNamespacePackageSettings from '~/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql';
+import { updateGroupPackageSettings } from '~/packages_and_registries/settings/group/graphql/utils/cache_update';
+import { updateGroupPackagesSettingsOptimisticResponse } from '~/packages_and_registries/settings/group/graphql/utils/optimistic_responses';
+
+import SettingsBlock from '~/packages_and_registries/shared/components/settings_block.vue';
+import ForwardingSettings from '~/packages_and_registries/settings/group/components/forwarding_settings.vue';
+
+export default {
+ name: 'PackageForwardingSettings',
+ i18n: {
+ PACKAGE_FORWARDING_FORM_BUTTON,
+ PACKAGE_FORWARDING_SETTINGS_HEADER,
+ PACKAGE_FORWARDING_SETTINGS_DESCRIPTION,
+ },
+ components: {
+ ForwardingSettings,
+ GlButton,
+ SettingsBlock,
+ },
+ mixins: [glFeatureFlagsMixin()],
+ inject: ['groupPath'],
+ props: {
+ forwardSettings: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ mutationLoading: false,
+ workingCopy: { ...this.forwardSettings },
+ };
+ },
+ computed: {
+ packageForwardingFields() {
+ const fields = PACKAGE_FORWARDING_FIELDS;
+
+ if (this.glFeatures.mavenCentralRequestForwarding) {
+ return fields.concat(MAVEN_FORWARDING_FIELDS);
+ }
+
+ return fields;
+ },
+ isEdited() {
+ return !isEqual(this.forwardSettings, this.workingCopy);
+ },
+ isDisabled() {
+ return !this.isEdited || this.mutationLoading;
+ },
+ npmMutation() {
+ if (this.workingCopy.npmPackageRequestsForwardingLocked) {
+ return {};
+ }
+
+ return {
+ npmPackageRequestsForwarding: this.workingCopy.npmPackageRequestsForwarding,
+ lockNpmPackageRequestsForwarding: this.workingCopy.lockNpmPackageRequestsForwarding,
+ };
+ },
+ pypiMutation() {
+ if (this.workingCopy.pypiPackageRequestsForwardingLocked) {
+ return {};
+ }
+
+ return {
+ pypiPackageRequestsForwarding: this.workingCopy.pypiPackageRequestsForwarding,
+ lockPypiPackageRequestsForwarding: this.workingCopy.lockPypiPackageRequestsForwarding,
+ };
+ },
+ mavenMutation() {
+ if (this.workingCopy.mavenPackageRequestsForwardingLocked) {
+ return {};
+ }
+
+ return {
+ mavenPackageRequestsForwarding: this.workingCopy.mavenPackageRequestsForwarding,
+ lockMavenPackageRequestsForwarding: this.workingCopy.lockMavenPackageRequestsForwarding,
+ };
+ },
+ mutationVariables() {
+ return {
+ ...this.npmMutation,
+ ...this.pypiMutation,
+ ...this.mavenMutation,
+ };
+ },
+ },
+ watch: {
+ forwardSettings(newValue) {
+ this.workingCopy = { ...newValue };
+ },
+ },
+ methods: {
+ isForwardingFieldsDisabled(fields) {
+ const isLocked = fields?.modelNames?.isLocked;
+
+ return this.mutationLoading || this.workingCopy[isLocked];
+ },
+ forwardingFieldsForwarding(fields) {
+ const forwarding = fields?.modelNames?.forwarding;
+
+ return this.workingCopy[forwarding];
+ },
+ forwardingFieldsLockForwarding(fields) {
+ const lockForwarding = fields?.modelNames?.lockForwarding;
+
+ return this.workingCopy[lockForwarding];
+ },
+ async submit() {
+ this.mutationLoading = true;
+ try {
+ const { data } = await this.$apollo.mutate({
+ mutation: updateNamespacePackageSettings,
+ variables: {
+ input: {
+ namespacePath: this.groupPath,
+ ...this.mutationVariables,
+ },
+ },
+ update: updateGroupPackageSettings(this.groupPath),
+ optimisticResponse: updateGroupPackagesSettingsOptimisticResponse({
+ ...this.forwardSettings,
+ ...this.mutationVariables,
+ }),
+ });
+
+ if (data.updateNamespacePackageSettings?.errors?.length > 0) {
+ throw new Error();
+ } else {
+ this.$emit('success');
+ }
+ } catch {
+ this.$emit('error');
+ } finally {
+ this.mutationLoading = false;
+ }
+ },
+ updateWorkingCopy(type, value) {
+ this.$set(this.workingCopy, type, value);
+ },
+ },
+};
+</script>
+
+<template>
+ <settings-block>
+ <template #title> {{ $options.i18n.PACKAGE_FORWARDING_SETTINGS_HEADER }}</template>
+ <template #description>
+ <span data-testid="description">
+ {{ $options.i18n.PACKAGE_FORWARDING_SETTINGS_DESCRIPTION }}
+ </span>
+ </template>
+ <template #default>
+ <form @submit.prevent="submit">
+ <forwarding-settings
+ v-for="forwardingFields in packageForwardingFields"
+ :key="forwardingFields.label"
+ :data-testid="forwardingFields.testid"
+ :disabled="isForwardingFieldsDisabled(forwardingFields)"
+ :forwarding="forwardingFieldsForwarding(forwardingFields)"
+ :label="forwardingFields.label"
+ :lock-forwarding="forwardingFieldsLockForwarding(forwardingFields)"
+ :model-names="forwardingFields.modelNames"
+ @update="updateWorkingCopy"
+ />
+ <gl-button
+ type="submit"
+ :disabled="isDisabled"
+ :loading="mutationLoading"
+ category="primary"
+ variant="confirm"
+ class="js-no-auto-disable gl-mr-4"
+ >
+ {{ $options.i18n.PACKAGE_FORWARDING_FORM_BUTTON }}
+ </gl-button>
+ </form>
+ </template>
+ </settings-block>
+</template>
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 2dd6d3f76f6..c93cd7f7d78 100644
--- a/app/assets/javascripts/packages_and_registries/settings/group/constants.js
+++ b/app/assets/javascripts/packages_and_registries/settings/group/constants.js
@@ -7,6 +7,8 @@ export const PACKAGE_SETTINGS_DESCRIPTION = s__(
);
export const PACKAGE_FORMATS_TABLE_HEADER = s__('PackageRegistry|Package formats');
export const MAVEN_PACKAGE_FORMAT = s__('PackageRegistry|Maven');
+export const NPM_PACKAGE_FORMAT = s__('PackageRegistry|npm');
+export const PYPI_PACKAGE_FORMAT = s__('PackageRegistry|PyPI');
export const GENERIC_PACKAGE_FORMAT = s__('PackageRegistry|Generic');
export const DUPLICATES_TOGGLE_LABEL = s__('PackageRegistry|Allow duplicates');
@@ -15,11 +17,65 @@ export const DUPLICATES_SETTINGS_EXCEPTION_LEGEND = s__(
'PackageRegistry|Publish packages if their name or version matches this regex.',
);
+export const PACKAGE_FORWARDING_SETTINGS_HEADER = s__('PackageRegistry|Package forwarding');
+export const PACKAGE_FORWARDING_SETTINGS_DESCRIPTION = s__(
+ 'PackageRegistry|Forward package requests to a public registry if the packages are not found in the GitLab package registry.',
+);
+export const PACKAGE_FORWARDING_CHECKBOX_LABEL = s__(
+ `PackageRegistry|Forward %{packageType} package requests`,
+);
+export const PACKAGE_FORWARDING_ENFORCE_LABEL = s__(
+ `PackageRegistry|Enforce %{packageType} setting for all subgroups`,
+);
+
+const MAVEN_PACKAGE_REQUESTS_FORWARDING = 'mavenPackageRequestsForwarding';
+const LOCK_MAVEN_PACKAGE_REQUESTS_FORWARDING = 'lockMavenPackageRequestsForwarding';
+const MAVEN_PACKAGE_REQUESTS_FORWARDING_LOCKED = 'mavenPackageRequestsForwardingLocked';
+const NPM_PACKAGE_REQUESTS_FORWARDING = 'npmPackageRequestsForwarding';
+const LOCK_NPM_PACKAGE_REQUESTS_FORWARDING = 'lockNpmPackageRequestsForwarding';
+const NPM_PACKAGE_REQUESTS_FORWARDING_LOCKED = 'npmPackageRequestsForwardingLocked';
+const PYPI_PACKAGE_REQUESTS_FORWARDING = 'pypiPackageRequestsForwarding';
+const LOCK_PYPI_PACKAGE_REQUESTS_FORWARDING = 'lockPypiPackageRequestsForwarding';
+const PYPI_PACKAGE_REQUESTS_FORWARDING_LOCKED = 'pypiPackageRequestsForwardingLocked';
+
+export const PACKAGE_FORWARDING_FORM_BUTTON = __('Save changes');
+
export const DEPENDENCY_PROXY_HEADER = s__('DependencyProxy|Dependency Proxy');
export const DEPENDENCY_PROXY_DESCRIPTION = s__(
'DependencyProxy|Enable the Dependency Proxy and settings for clearing the cache.',
);
+export const PACKAGE_FORWARDING_FIELDS = [
+ {
+ label: NPM_PACKAGE_FORMAT,
+ testid: 'npm',
+ modelNames: {
+ forwarding: NPM_PACKAGE_REQUESTS_FORWARDING,
+ lockForwarding: LOCK_NPM_PACKAGE_REQUESTS_FORWARDING,
+ isLocked: NPM_PACKAGE_REQUESTS_FORWARDING_LOCKED,
+ },
+ },
+ {
+ label: PYPI_PACKAGE_FORMAT,
+ testid: 'pypi',
+ modelNames: {
+ forwarding: PYPI_PACKAGE_REQUESTS_FORWARDING,
+ lockForwarding: LOCK_PYPI_PACKAGE_REQUESTS_FORWARDING,
+ isLocked: PYPI_PACKAGE_REQUESTS_FORWARDING_LOCKED,
+ },
+ },
+];
+
+export const MAVEN_FORWARDING_FIELDS = {
+ label: MAVEN_PACKAGE_FORMAT,
+ testid: 'maven',
+ modelNames: {
+ forwarding: MAVEN_PACKAGE_REQUESTS_FORWARDING,
+ lockForwarding: LOCK_MAVEN_PACKAGE_REQUESTS_FORWARDING,
+ isLocked: MAVEN_PACKAGE_REQUESTS_FORWARDING_LOCKED,
+ },
+};
+
// Parameters
export const PACKAGES_DOCS_PATH = helpPagePath('user/packages/index');
diff --git a/app/assets/javascripts/packages_and_registries/settings/group/graphql/fragments/package_settings_fields.fragment.graphql b/app/assets/javascripts/packages_and_registries/settings/group/graphql/fragments/package_settings_fields.fragment.graphql
new file mode 100644
index 00000000000..267e40263f2
--- /dev/null
+++ b/app/assets/javascripts/packages_and_registries/settings/group/graphql/fragments/package_settings_fields.fragment.graphql
@@ -0,0 +1,15 @@
+fragment PackageSettingsFields on PackageSettings {
+ mavenDuplicatesAllowed
+ mavenDuplicateExceptionRegex
+ genericDuplicatesAllowed
+ genericDuplicateExceptionRegex
+ mavenPackageRequestsForwarding
+ lockMavenPackageRequestsForwarding
+ mavenPackageRequestsForwardingLocked
+ npmPackageRequestsForwarding
+ lockNpmPackageRequestsForwarding
+ npmPackageRequestsForwardingLocked
+ pypiPackageRequestsForwarding
+ lockPypiPackageRequestsForwarding
+ pypiPackageRequestsForwardingLocked
+}
diff --git a/app/assets/javascripts/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql b/app/assets/javascripts/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql
index 5c245ff9453..5558cb66f42 100644
--- a/app/assets/javascripts/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql
+++ b/app/assets/javascripts/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql
@@ -1,10 +1,9 @@
+#import "~/packages_and_registries/settings/group/graphql/fragments/package_settings_fields.fragment.graphql"
+
mutation updateNamespacePackageSettings($input: UpdateNamespacePackageSettingsInput!) {
updateNamespacePackageSettings(input: $input) {
packageSettings {
- mavenDuplicatesAllowed
- mavenDuplicateExceptionRegex
- genericDuplicatesAllowed
- genericDuplicateExceptionRegex
+ ...PackageSettingsFields
}
errors
}
diff --git a/app/assets/javascripts/packages_and_registries/settings/group/graphql/mutations/update_package_forwarding_settings.mutation.graphql b/app/assets/javascripts/packages_and_registries/settings/group/graphql/mutations/update_package_forwarding_settings.mutation.graphql
new file mode 100644
index 00000000000..e5e31f03a7d
--- /dev/null
+++ b/app/assets/javascripts/packages_and_registries/settings/group/graphql/mutations/update_package_forwarding_settings.mutation.graphql
@@ -0,0 +1,16 @@
+mutation updatePackageForwardingSettings($input: UpdateNamespacePackageSettingsInput!) {
+ updateNamespacePackageSettings(input: $input) {
+ packageSettings {
+ mavenPackageRequestsForwarding
+ lockMavenPackageRequestsForwarding
+ mavenPackageRequestsForwardingLocked
+ npmPackageRequestsForwarding
+ lockNpmPackageRequestsForwarding
+ npmPackageRequestsForwardingLocked
+ pypiPackageRequestsForwarding
+ lockPypiPackageRequestsForwarding
+ pypiPackageRequestsForwardingLocked
+ }
+ errors
+ }
+}
diff --git a/app/assets/javascripts/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql b/app/assets/javascripts/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql
index 404d9d26d49..82a282d6d81 100644
--- a/app/assets/javascripts/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql
+++ b/app/assets/javascripts/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql
@@ -1,3 +1,5 @@
+#import "~/packages_and_registries/settings/group/graphql/fragments/package_settings_fields.fragment.graphql"
+
query getGroupPackagesSettings($fullPath: ID!) {
group(fullPath: $fullPath) {
id
@@ -9,10 +11,7 @@ query getGroupPackagesSettings($fullPath: ID!) {
enabled
}
packageSettings {
- mavenDuplicatesAllowed
- mavenDuplicateExceptionRegex
- genericDuplicatesAllowed
- genericDuplicateExceptionRegex
+ ...PackageSettingsFields
}
}
}
diff --git a/app/assets/javascripts/packages_and_registries/shared/components/delete_package_modal.vue b/app/assets/javascripts/packages_and_registries/shared/components/delete_package_modal.vue
new file mode 100644
index 00000000000..b66b0b3548d
--- /dev/null
+++ b/app/assets/javascripts/packages_and_registries/shared/components/delete_package_modal.vue
@@ -0,0 +1,83 @@
+<script>
+import { GlModal, GlSprintf } from '@gitlab/ui';
+import { __ } from '~/locale';
+import {
+ DELETE_PACKAGE_MODAL_CONTENT_MESSAGE,
+ DELETE_PACKAGE_MODAL_TITLE,
+ DELETE_PACKAGE_MODAL_ACTION,
+} from '~/packages_and_registries/shared/constants';
+import { TRACK_CATEGORY } from '~/packages_and_registries/infrastructure_registry/shared/constants';
+
+export default {
+ components: {
+ GlModal,
+ GlSprintf,
+ },
+ props: {
+ itemToBeDeleted: {
+ type: Object,
+ required: false,
+ default: null,
+ },
+ },
+ computed: {
+ isModalVisible() {
+ return Boolean(this.itemToBeDeleted);
+ },
+ deletePackageName() {
+ return this.itemToBeDeleted?.name ?? '';
+ },
+ deleteModalActionPrimaryProps() {
+ return {
+ text: this.$options.i18n.modalAction,
+ attributes: {
+ variant: 'danger',
+ },
+ };
+ },
+ deleteModalActionCancelProps() {
+ return {
+ text: __('Cancel'),
+ };
+ },
+ tracking() {
+ return {
+ category: TRACK_CATEGORY,
+ };
+ },
+ },
+ methods: {
+ deleteItemConfirmation() {
+ this.$emit('ok');
+ },
+ onChangeModalVisibility(isVisible) {
+ if (!isVisible) this.$emit('cancel');
+ },
+ },
+ i18n: {
+ modalTitle: DELETE_PACKAGE_MODAL_TITLE,
+ modalDescription: DELETE_PACKAGE_MODAL_CONTENT_MESSAGE,
+ modalAction: DELETE_PACKAGE_MODAL_ACTION,
+ },
+};
+</script>
+
+<template>
+ <gl-modal
+ :visible="isModalVisible"
+ size="sm"
+ modal-id="confirm-delete-package"
+ :title="$options.i18n.modalTitle"
+ :action-primary="deleteModalActionPrimaryProps"
+ :action-cancel="deleteModalActionCancelProps"
+ @ok="deleteItemConfirmation"
+ @change="onChangeModalVisibility"
+ >
+ <template #modal-title>{{ $options.i18n.modalTitle }}</template>
+ <gl-sprintf :message="$options.i18n.modalDescription">
+ <template #name>
+ <strong>{{ deletePackageName }}</strong>
+ </template>
+ </gl-sprintf>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/packages_and_registries/shared/constants/package_registry.js b/app/assets/javascripts/packages_and_registries/shared/constants/package_registry.js
index 7fd440d0b27..f3ce967b756 100644
--- a/app/assets/javascripts/packages_and_registries/shared/constants/package_registry.js
+++ b/app/assets/javascripts/packages_and_registries/shared/constants/package_registry.js
@@ -39,6 +39,12 @@ export const DELETE_PACKAGE_FILE_SUCCESS_MESSAGE = s__(
'PackageRegistry|Package asset deleted successfully',
);
+export const DELETE_PACKAGE_MODAL_CONTENT_MESSAGE = s__(
+ 'PackageRegistry|You are about to delete %{name}, are you sure?',
+);
+export const DELETE_PACKAGE_MODAL_TITLE = s__('PackageRegistry|Delete package');
+export const DELETE_PACKAGE_MODAL_ACTION = s__('PackageRegistry|Permanently delete');
+
export const PACKAGE_ERROR_STATUS = 'error';
export const PACKAGE_DEFAULT_STATUS = 'default';
export const PACKAGE_HIDDEN_STATUS = 'hidden';
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 ccb449f96e1..b68148e5461 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
@@ -44,6 +44,7 @@ export default {
'signupEnabled',
'requireAdminApprovalAfterUserSignup',
'sendUserConfirmationEmail',
+ 'emailConfirmationSetting',
'minimumPasswordLength',
'minimumPasswordLengthMin',
'minimumPasswordLengthMax',
@@ -58,6 +59,8 @@ export default {
'emailRestrictions',
'afterSignUpText',
'pendingUserCount',
+ 'projectSharingHelpLink',
+ 'groupSharingHelpLink',
],
data() {
return {
@@ -66,6 +69,7 @@ export default {
signupEnabled: this.signupEnabled,
requireAdminApproval: this.requireAdminApprovalAfterUserSignup,
sendConfirmationEmail: this.sendUserConfirmationEmail,
+ emailConfirmationSetting: this.emailConfirmationSetting,
minimumPasswordLength: this.minimumPasswordLength,
minimumPasswordLengthMin: this.minimumPasswordLengthMin,
minimumPasswordLengthMax: this.minimumPasswordLengthMax,
@@ -81,6 +85,8 @@ export default {
supportedSyntaxLinkUrl: this.supportedSyntaxLinkUrl,
emailRestrictions: this.emailRestrictions,
afterSignUpText: this.afterSignUpText,
+ projectSharingHelpLink: this.projectSharingHelpLink,
+ groupSharingHelpLink: this.groupSharingHelpLink,
},
};
},
@@ -199,6 +205,15 @@ export default {
signupEnabledLabel: s__('ApplicationSettings|Sign-up enabled'),
requireAdminApprovalLabel: s__('ApplicationSettings|Require admin approval for new sign-ups'),
sendConfirmationEmailLabel: s__('ApplicationSettings|Send confirmation email on sign-up'),
+ emailConfirmationSettingsLabel: s__('ApplicationSettings|Email confirmation settings'),
+ emailConfirmationSettingsOffLabel: s__('ApplicationSettings|Off'),
+ emailConfirmationSettingsOffHelpText: s__(
+ 'ApplicationSettings|New users can sign up without confirming their email address.',
+ ),
+ 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.',
+ ),
minimumPasswordLengthLabel: s__(
'ApplicationSettings|Minimum password length (number of characters)',
),
@@ -208,7 +223,7 @@ export default {
),
userCapLabel: s__('ApplicationSettings|User cap'),
userCapDescription: s__(
- 'ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited.',
+ 'ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}.',
),
domainDenyListGroupLabel: s__('ApplicationSettings|Domain denylist'),
domainDenyListLabel: s__('ApplicationSettings|Enable domain denylist for sign-ups'),
@@ -276,9 +291,28 @@ export default {
:label="$options.i18n.sendConfirmationEmailLabel"
/>
+ <gl-form-group :label="$options.i18n.emailConfirmationSettingsLabel">
+ <gl-form-radio-group
+ 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-group>
+ </gl-form-group>
+
<gl-form-group
:label="$options.i18n.userCapLabel"
:description="$options.i18n.userCapDescription"
+ data-testid="user-cap-form-group"
>
<gl-form-input
v-model="form.userCap"
@@ -286,6 +320,17 @@ export default {
name="application_setting[new_user_signups_cap]"
data-testid="user-cap-input"
/>
+
+ <template #description>
+ <gl-sprintf :message="$options.i18n.userCapDescription">
+ <template #projectSharingLink="{ content }">
+ <gl-link :href="projectSharingHelpLink" target="_blank">{{ content }}</gl-link>
+ </template>
+ <template #groupSharingLink="{ content }">
+ <gl-link :href="groupSharingHelpLink" target="_blank">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </template>
</gl-form-group>
<gl-form-group :label="$options.i18n.minimumPasswordLengthLabel">
diff --git a/app/assets/javascripts/pages/admin/jobs/index/components/constants.js b/app/assets/javascripts/pages/admin/jobs/index/components/constants.js
new file mode 100644
index 00000000000..9e2d464bc4d
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/jobs/index/components/constants.js
@@ -0,0 +1,11 @@
+import { s__, __ } from '~/locale';
+
+export const STOP_JOBS_MODAL_ID = 'stop-jobs-modal';
+export const STOP_JOBS_MODAL_TITLE = s__('AdminArea|Stop all jobs?');
+export const STOP_JOBS_BUTTON_TEXT = s__('AdminArea|Stop all jobs');
+export const CANCEL_TEXT = __('Cancel');
+export const STOP_JOBS_FAILED_TEXT = s__('AdminArea|Stopping jobs failed');
+export const PRIMARY_ACTION_TEXT = s__('AdminArea|Stop jobs');
+export const STOP_JOBS_WARNING = s__(
+ 'AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running.',
+);
diff --git a/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue b/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue
index 4f42ef2892d..b608b3b9492 100644
--- a/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue
+++ b/app/assets/javascripts/pages/admin/jobs/index/components/stop_jobs_modal.vue
@@ -3,7 +3,14 @@ import { GlModal } from '@gitlab/ui';
import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { redirectTo } from '~/lib/utils/url_utility';
-import { __, s__ } from '~/locale';
+import {
+ CANCEL_TEXT,
+ STOP_JOBS_MODAL_ID,
+ STOP_JOBS_FAILED_TEXT,
+ STOP_JOBS_MODAL_TITLE,
+ STOP_JOBS_WARNING,
+ PRIMARY_ACTION_TEXT,
+} from './constants';
export default {
components: {
@@ -15,13 +22,6 @@ export default {
required: true,
},
},
- computed: {
- text() {
- return s__(
- 'AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running.',
- );
- },
- },
methods: {
onSubmit() {
return axios
@@ -32,30 +32,33 @@ export default {
})
.catch((error) => {
createAlert({
- message: s__('AdminArea|Stopping jobs failed'),
+ message: STOP_JOBS_FAILED_TEXT,
});
throw error;
});
},
},
primaryAction: {
- text: s__('AdminArea|Stop jobs'),
+ text: PRIMARY_ACTION_TEXT,
attributes: [{ variant: 'danger' }],
},
cancelAction: {
- text: __('Cancel'),
+ text: CANCEL_TEXT,
},
+ STOP_JOBS_WARNING,
+ STOP_JOBS_MODAL_ID,
+ STOP_JOBS_MODAL_TITLE,
};
</script>
<template>
<gl-modal
- modal-id="stop-jobs-modal"
+ :modal-id="$options.STOP_JOBS_MODAL_ID"
:action-primary="$options.primaryAction"
:action-cancel="$options.cancelAction"
@primary="onSubmit"
>
- <template #modal-title>{{ s__('AdminArea|Stop all jobs?') }}</template>
- {{ text }}
+ <template #modal-title>{{ $options.STOP_JOBS_MODAL_TITLE }}</template>
+ {{ $options.STOP_JOBS_WARNING }}
</gl-modal>
</template>
diff --git a/app/assets/javascripts/pages/admin/jobs/index/index.js b/app/assets/javascripts/pages/admin/jobs/index/index.js
index 4cd312b403c..c82b186f671 100644
--- a/app/assets/javascripts/pages/admin/jobs/index/index.js
+++ b/app/assets/javascripts/pages/admin/jobs/index/index.js
@@ -1,29 +1,29 @@
import Vue from 'vue';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import Translate from '~/vue_shared/translate';
+import { STOP_JOBS_MODAL_ID } from './components/constants';
import StopJobsModal from './components/stop_jobs_modal.vue';
Vue.use(Translate);
function initJobs() {
const buttonId = 'js-stop-jobs-button';
- const modalId = 'stop-jobs-modal';
const stopJobsButton = document.getElementById(buttonId);
if (stopJobsButton) {
// eslint-disable-next-line no-new
new Vue({
- el: `#js-${modalId}`,
+ el: `#js-${STOP_JOBS_MODAL_ID}`,
components: {
StopJobsModal,
},
mounted() {
stopJobsButton.classList.remove('disabled');
stopJobsButton.addEventListener('click', () => {
- this.$root.$emit(BV_SHOW_MODAL, modalId, `#${buttonId}`);
+ this.$root.$emit(BV_SHOW_MODAL, STOP_JOBS_MODAL_ID, `#${buttonId}`);
});
},
render(createElement) {
- return createElement(modalId, {
+ return createElement(STOP_JOBS_MODAL_ID, {
props: {
url: stopJobsButton.dataset.url,
},
diff --git a/app/assets/javascripts/pages/admin/runners/edit/index.js b/app/assets/javascripts/pages/admin/runners/edit/index.js
index 03d31f49a99..dcce2a8dafd 100644
--- a/app/assets/javascripts/pages/admin/runners/edit/index.js
+++ b/app/assets/javascripts/pages/admin/runners/edit/index.js
@@ -1,3 +1,3 @@
-import { initRunnerEdit } from '~/runner/runner_edit';
+import { initRunnerEdit } from '~/ci/runner/runner_edit';
initRunnerEdit('#js-admin-runner-edit');
diff --git a/app/assets/javascripts/pages/admin/runners/index/index.js b/app/assets/javascripts/pages/admin/runners/index/index.js
index f83111b6385..bc7b1421b31 100644
--- a/app/assets/javascripts/pages/admin/runners/index/index.js
+++ b/app/assets/javascripts/pages/admin/runners/index/index.js
@@ -1,3 +1,3 @@
-import { initAdminRunners } from '~/runner/admin_runners';
+import { initAdminRunners } from '~/ci/runner/admin_runners';
initAdminRunners();
diff --git a/app/assets/javascripts/pages/admin/runners/show/index.js b/app/assets/javascripts/pages/admin/runners/show/index.js
index f76f3a2430d..fd38abf221a 100644
--- a/app/assets/javascripts/pages/admin/runners/show/index.js
+++ b/app/assets/javascripts/pages/admin/runners/show/index.js
@@ -1,3 +1,3 @@
-import { initAdminRunnerShow } from '~/runner/admin_runner_show';
+import { initAdminRunnerShow } from '~/ci/runner/admin_runner_show';
initAdminRunnerShow();
diff --git a/app/assets/javascripts/pages/dashboard/issues/index.js b/app/assets/javascripts/pages/dashboard/issues/index.js
index d0903ad53bc..08c247a498b 100644
--- a/app/assets/javascripts/pages/dashboard/issues/index.js
+++ b/app/assets/javascripts/pages/dashboard/issues/index.js
@@ -1,4 +1,5 @@
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
+import { mountIssuesDashboardApp } from '~/issues/dashboard';
import initManualOrdering from '~/issues/manual_ordering';
import { FILTERED_SEARCH } from '~/filtered_search/constants';
import initFilteredSearch from '~/pages/search/init_filtered_search';
@@ -12,3 +13,5 @@ initFilteredSearch({
projectSelect();
initManualOrdering();
+
+mountIssuesDashboardApp();
diff --git a/app/assets/javascripts/pages/groups/observability/dashboards/index.js b/app/assets/javascripts/pages/groups/observability/dashboards/index.js
new file mode 100644
index 00000000000..c3b6ce6f99f
--- /dev/null
+++ b/app/assets/javascripts/pages/groups/observability/dashboards/index.js
@@ -0,0 +1,3 @@
+import ObservabilityApp from '~/observability';
+
+ObservabilityApp();
diff --git a/app/assets/javascripts/pages/groups/observability/explore/index.js b/app/assets/javascripts/pages/groups/observability/explore/index.js
new file mode 100644
index 00000000000..c3b6ce6f99f
--- /dev/null
+++ b/app/assets/javascripts/pages/groups/observability/explore/index.js
@@ -0,0 +1,3 @@
+import ObservabilityApp from '~/observability';
+
+ObservabilityApp();
diff --git a/app/assets/javascripts/pages/groups/observability/manage/index.js b/app/assets/javascripts/pages/groups/observability/manage/index.js
new file mode 100644
index 00000000000..c3b6ce6f99f
--- /dev/null
+++ b/app/assets/javascripts/pages/groups/observability/manage/index.js
@@ -0,0 +1,3 @@
+import ObservabilityApp from '~/observability';
+
+ObservabilityApp();
diff --git a/app/assets/javascripts/pages/groups/runners/edit/index.js b/app/assets/javascripts/pages/groups/runners/edit/index.js
index febb0026b67..08ae57866e2 100644
--- a/app/assets/javascripts/pages/groups/runners/edit/index.js
+++ b/app/assets/javascripts/pages/groups/runners/edit/index.js
@@ -1,3 +1,3 @@
-import { initRunnerEdit } from '~/runner/runner_edit';
+import { initRunnerEdit } from '~/ci/runner/runner_edit';
initRunnerEdit('#js-group-runner-edit');
diff --git a/app/assets/javascripts/pages/groups/runners/index/index.js b/app/assets/javascripts/pages/groups/runners/index/index.js
index ca1a6bdab75..1cc07d1069a 100644
--- a/app/assets/javascripts/pages/groups/runners/index/index.js
+++ b/app/assets/javascripts/pages/groups/runners/index/index.js
@@ -1,3 +1,3 @@
-import { initGroupRunners } from '~/runner/group_runners';
+import { initGroupRunners } from '~/ci/runner/group_runners';
initGroupRunners();
diff --git a/app/assets/javascripts/pages/groups/runners/show/index.js b/app/assets/javascripts/pages/groups/runners/show/index.js
index c59e3b80dc1..755e38004ad 100644
--- a/app/assets/javascripts/pages/groups/runners/show/index.js
+++ b/app/assets/javascripts/pages/groups/runners/show/index.js
@@ -1,3 +1,3 @@
-import { initGroupRunnerShow } from '~/runner/group_runner_show';
+import { initGroupRunnerShow } from '~/ci/runner/group_runner_show';
initGroupRunnerShow();
diff --git a/app/assets/javascripts/pages/groups/shared/group_details.js b/app/assets/javascripts/pages/groups/shared/group_details.js
index 2aec0617b5a..52124865bcc 100644
--- a/app/assets/javascripts/pages/groups/shared/group_details.js
+++ b/app/assets/javascripts/pages/groups/shared/group_details.js
@@ -1,23 +1,12 @@
/* eslint-disable no-new */
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
-import { ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED } from '~/groups/constants';
import initInviteMembersBanner from '~/groups/init_invite_members_banner';
import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
-import { getPagePath, getDashPath } from '~/lib/utils/common_utils';
import initNotificationsDropdown from '~/notifications';
import ProjectsList from '~/projects_list';
-import GroupTabs from './group_tabs';
-export default function initGroupDetails(actionName = 'show') {
- const loadableActions = [ACTIVE_TAB_SHARED, ACTIVE_TAB_ARCHIVED];
- const dashPath = getDashPath();
- let action = loadableActions.includes(dashPath) ? dashPath : getPagePath(1);
- if (actionName && action === actionName) {
- action = 'show'; // 'show' resets GroupTabs to default action through base class
- }
-
- new GroupTabs({ parentEl: '.groups-listing', action });
+export default function initGroupDetails() {
new ShortcutsNavigation();
initNotificationsDropdown();
diff --git a/app/assets/javascripts/pages/groups/shared/group_tabs.js b/app/assets/javascripts/pages/groups/shared/group_tabs.js
deleted file mode 100644
index 73d810007dc..00000000000
--- a/app/assets/javascripts/pages/groups/shared/group_tabs.js
+++ /dev/null
@@ -1,136 +0,0 @@
-import $ from 'jquery';
-import createGroupTree from '~/groups';
-import {
- ACTIVE_TAB_SUBGROUPS_AND_PROJECTS,
- ACTIVE_TAB_SHARED,
- ACTIVE_TAB_ARCHIVED,
- CONTENT_LIST_CLASS,
- GROUPS_LIST_HOLDER_CLASS,
- GROUPS_FILTER_FORM_CLASS,
-} from '~/groups/constants';
-import GroupFilterableList from '~/groups/groups_filterable_list';
-import { removeParams } from '~/lib/utils/url_utility';
-import UserTabs from '~/pages/users/user_tabs';
-
-export default class GroupTabs extends UserTabs {
- constructor({ defaultAction = 'subgroups_and_projects', action, parentEl }) {
- super({ defaultAction, action, parentEl });
- }
-
- bindEvents() {
- this.$parentEl
- .off('shown.bs.tab', '.nav-links a[data-toggle="tab"]')
- .on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', (event) => this.tabShown(event));
- }
-
- tabShown(event) {
- const $target = $(event.target);
- const action = $target.data('action') || $target.data('targetSection');
- const source = $target.attr('href') || $target.data('targetPath');
-
- document.querySelector(GROUPS_FILTER_FORM_CLASS).action = source;
-
- this.setTab(action);
- return this.setCurrentAction(source);
- }
-
- setTab(action) {
- const loadableActions = [
- ACTIVE_TAB_SUBGROUPS_AND_PROJECTS,
- ACTIVE_TAB_SHARED,
- ACTIVE_TAB_ARCHIVED,
- ];
- this.enableSearchBar(action);
- this.action = action;
-
- if (this.loaded[action]) {
- return;
- }
-
- if (loadableActions.includes(action)) {
- this.cleanFilterState();
- this.loadTab(action);
- }
- }
-
- loadTab(action) {
- const elId = `js-groups-${action}-tree`;
- const endpoint = this.getEndpoint(action);
-
- this.toggleLoading(true);
-
- createGroupTree(elId, endpoint, action);
- this.loaded[action] = true;
-
- this.toggleLoading(false);
- }
-
- getEndpoint(action) {
- const { endpointsDefault, endpointsShared } = this.$parentEl.data();
- let endpoint;
-
- switch (action) {
- case ACTIVE_TAB_ARCHIVED:
- endpoint = `${endpointsDefault}?archived=only`;
- break;
- case ACTIVE_TAB_SHARED:
- endpoint = endpointsShared;
- break;
- default:
- // ACTIVE_TAB_SUBGROUPS_AND_PROJECTS
- endpoint = endpointsDefault;
- break;
- }
-
- return endpoint;
- }
-
- enableSearchBar(action) {
- const containerEl = document.getElementById(action);
- const form = document.querySelector(GROUPS_FILTER_FORM_CLASS);
- const filter = form.querySelector('.js-groups-list-filter');
- const holder = containerEl.querySelector(GROUPS_LIST_HOLDER_CLASS);
- const dataEl = containerEl.querySelector(CONTENT_LIST_CLASS);
- const endpoint = this.getEndpoint(action);
-
- if (!dataEl) {
- return;
- }
-
- const { dataset } = dataEl;
- const opts = {
- form,
- filter,
- holder,
- filterEndpoint: endpoint || dataset.endpoint,
- pagePath: null,
- dropdownSel: '.js-group-filter-dropdown-wrap',
- filterInputField: 'filter',
- action,
- };
-
- if (!this.loaded[action]) {
- const filterableList = new GroupFilterableList(opts);
- filterableList.initSearch();
- }
- }
-
- cleanFilterState() {
- const values = Object.values(this.loaded);
- const loadedTabs = values.filter((e) => e === true);
-
- if (!loadedTabs.length) {
- return;
- }
-
- const newState = removeParams(['page'], window.location.search);
-
- window.history.replaceState(
- {
- url: newState,
- },
- document.title,
- newState,
- );
- }
-}
diff --git a/app/assets/javascripts/pages/profiles/init_timezone_dropdown.js b/app/assets/javascripts/pages/profiles/init_timezone_dropdown.js
index 80b911493a8..91d5013c67d 100644
--- a/app/assets/javascripts/pages/profiles/init_timezone_dropdown.js
+++ b/app/assets/javascripts/pages/profiles/init_timezone_dropdown.js
@@ -8,7 +8,7 @@ export const initTimezoneDropdown = () => {
return null;
}
- const { timezoneData, initialValue } = el.dataset;
+ const { timezoneData, initialValue, name } = el.dataset;
const timezones = JSON.parse(timezoneData);
const timezoneDropdown = new Vue({
@@ -23,7 +23,7 @@ export const initTimezoneDropdown = () => {
props: {
value: this.value,
timezoneData: timezones,
- name: 'user[timezone]',
+ name,
},
class: 'gl-md-form-input-lg',
});
diff --git a/app/assets/javascripts/pages/projects/artifacts/index.js b/app/assets/javascripts/pages/projects/artifacts/index.js
new file mode 100644
index 00000000000..4aa9b225790
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/artifacts/index.js
@@ -0,0 +1,3 @@
+import { initArtifactsTable } from '~/artifacts/index';
+
+initArtifactsTable();
diff --git a/app/assets/javascripts/pages/projects/branches/index/index.js b/app/assets/javascripts/pages/projects/branches/index/index.js
index f3530b46845..ac5e0b28dd1 100644
--- a/app/assets/javascripts/pages/projects/branches/index/index.js
+++ b/app/assets/javascripts/pages/projects/branches/index/index.js
@@ -3,6 +3,7 @@ import BranchSortDropdown from '~/branches/branch_sort_dropdown';
import initDiverganceGraph from '~/branches/divergence_graph';
import initDeleteBranchButton from '~/branches/init_delete_branch_button';
import initDeleteBranchModal from '~/branches/init_delete_branch_modal';
+import initDeleteMergedBranches from '~/branches/init_delete_merged_branches';
const { divergingCountsEndpoint, defaultBranch } = document.querySelector(
'.js-branch-list',
@@ -11,6 +12,7 @@ const { divergingCountsEndpoint, defaultBranch } = document.querySelector(
initDiverganceGraph(divergingCountsEndpoint, defaultBranch);
BranchSortDropdown();
initDeprecatedRemoveRowBehavior();
+initDeleteMergedBranches();
document
.querySelectorAll('.js-delete-branch-button')
diff --git a/app/assets/javascripts/pages/projects/hooks/index.js b/app/assets/javascripts/pages/projects/hooks/index.js
index ed476d25f8b..9e559354205 100644
--- a/app/assets/javascripts/pages/projects/hooks/index.js
+++ b/app/assets/javascripts/pages/projects/hooks/index.js
@@ -1,5 +1,7 @@
import initSearchSettings from '~/search_settings';
import initWebhookForm from '~/webhooks';
+import { initPushEventsEditForm } from '~/webhooks/webhook';
initSearchSettings();
initWebhookForm();
+initPushEventsEditForm();
diff --git a/app/assets/javascripts/pages/projects/init_blob.js b/app/assets/javascripts/pages/projects/init_blob.js
index f37a2987685..097b2f33aa9 100644
--- a/app/assets/javascripts/pages/projects/init_blob.js
+++ b/app/assets/javascripts/pages/projects/init_blob.js
@@ -3,7 +3,6 @@ import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import BlobForkSuggestion from '~/blob/blob_fork_suggestion';
import BlobLinePermalinkUpdater from '~/blob/blob_line_permalink_updater';
import LineHighlighter from '~/blob/line_highlighter';
-import initBlobBundle from '~/blob_edit/blob_bundle';
export default () => {
new LineHighlighter(); // eslint-disable-line no-new
@@ -35,6 +34,4 @@ export default () => {
suggestionSections: document.querySelectorAll('.js-file-fork-suggestion-section'),
actionTextPieces: document.querySelectorAll('.js-file-fork-suggestion-section-action'),
}).init();
-
- initBlobBundle();
};
diff --git a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue
index 4eab0cccb06..3717d8027c4 100644
--- a/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue
+++ b/app/assets/javascripts/pages/projects/learn_gitlab/components/learn_gitlab_section_link.vue
@@ -86,6 +86,7 @@ export default {
:target="openInNewTab ? '_blank' : '_self'"
:href="value.url"
data-testid="uncompleted-learn-gitlab-link"
+ data-qa-selector="uncompleted_learn_gitlab_link"
data-track-action="click_link"
:data-track-label="actionLabelValue('trackLabel')"
>{{ actionLabelValue('title') }}</gl-link
diff --git a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js
index ebf7c266482..42fa306d226 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/init_merge_request.js
@@ -6,8 +6,8 @@ import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import Diff from '~/diff';
import GLForm from '~/gl_form';
import LabelsSelect from '~/labels/labels_select';
-import MilestoneSelect from '~/milestones/milestone_select';
import IssuableTemplateSelectors from '~/issuable/issuable_template_selectors';
+import { mountMilestoneDropdown } from '~/sidebar/mount_sidebar';
export default () => {
new Diff();
@@ -15,8 +15,8 @@ export default () => {
new GLForm($('.merge-request-form'));
new IssuableForm($('.merge-request-form'));
new LabelsSelect();
- new MilestoneSelect();
new IssuableTemplateSelectors({
warnTemplateOverride: true,
});
+ mountMilestoneDropdown('[name="merge_request[milestone_id]"]');
};
diff --git a/app/assets/javascripts/pages/projects/ml/experiments/show/index.js b/app/assets/javascripts/pages/projects/ml/experiments/show/index.js
new file mode 100644
index 00000000000..0a9d9f4c987
--- /dev/null
+++ b/app/assets/javascripts/pages/projects/ml/experiments/show/index.js
@@ -0,0 +1,31 @@
+import Vue from 'vue';
+import ShowExperiment from '~/ml/experiment_tracking/components/experiment.vue';
+
+const initShowExperiment = () => {
+ const element = document.querySelector('#js-show-ml-experiment');
+ if (!element) {
+ return;
+ }
+
+ const container = document.createElement('div');
+ element.appendChild(container);
+
+ const candidates = JSON.parse(element.dataset.candidates);
+ const metricNames = JSON.parse(element.dataset.metrics);
+ const paramNames = JSON.parse(element.dataset.params);
+
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: container,
+ provide: {
+ candidates,
+ metricNames,
+ paramNames,
+ },
+ render(h) {
+ return h(ShowExperiment);
+ },
+ });
+};
+
+initShowExperiment();
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js b/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js
index 0edce2db0a3..e2a782bc5d8 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/edit/index.js
@@ -1,4 +1,4 @@
-import initPipelineSchedulesFormApp from '~/pipeline_schedules/mount_pipeline_schedules_form_app';
+import initPipelineSchedulesFormApp from '~/ci/pipeline_schedules/mount_pipeline_schedules_form_app';
import initForm from '../shared/init_form';
if (gon.features?.pipelineSchedulesVue) {
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js b/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js
index 7d0930f6424..27610df482d 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/index/index.js
@@ -1,7 +1,7 @@
import Vue from 'vue';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
-import initPipelineSchedulesApp from '~/pipeline_schedules/mount_pipeline_schedules_app';
-import PipelineSchedulesTakeOwnershipModal from '~/pipeline_schedules/components/take_ownership_modal.vue';
+import initPipelineSchedulesApp from '~/ci/pipeline_schedules/mount_pipeline_schedules_app';
+import PipelineSchedulesTakeOwnershipModalLegacy from '~/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue';
import PipelineSchedulesCallout from '../shared/components/pipeline_schedules_callout.vue';
function initPipelineSchedulesCallout() {
@@ -58,7 +58,7 @@ function initTakeownershipModal() {
});
},
render(createElement) {
- return createElement(PipelineSchedulesTakeOwnershipModal, {
+ return createElement(PipelineSchedulesTakeOwnershipModalLegacy, {
props: {
ownershipUrl: this.url,
},
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js b/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js
index 06084fa729b..d8ba7bbd752 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/new/index.js
@@ -1,4 +1,4 @@
-import initPipelineSchedulesFormApp from '~/pipeline_schedules/mount_pipeline_schedules_form_app';
+import initPipelineSchedulesFormApp from '~/ci/pipeline_schedules/mount_pipeline_schedules_form_app';
import initForm from '../shared/init_form';
if (gon.features?.pipelineSchedulesVue) {
diff --git a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js
index eae721771de..abd17efc498 100644
--- a/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js
+++ b/app/assets/javascripts/pages/projects/pipeline_schedules/shared/init_form.js
@@ -6,8 +6,8 @@ import { REF_TYPE_BRANCHES, REF_TYPE_TAGS } from '~/ref/constants';
import setupNativeFormVariableList from '~/ci_variable_list/native_form_variable_list';
import GlFieldErrors from '~/gl_field_errors';
import Translate from '~/vue_shared/translate';
+import { initTimezoneDropdown } from '../../../profiles/init_timezone_dropdown';
import IntervalPatternInput from './components/interval_pattern_input.vue';
-import TimezoneDropdown from './components/timezone_dropdown';
Vue.use(Translate);
@@ -81,13 +81,6 @@ export default () => {
const formElement = document.getElementById('new-pipeline-schedule-form');
- gl.timezoneDropdown = new TimezoneDropdown({
- $dropdownEl: $('.js-timezone-dropdown'),
- $inputEl: $('#schedule_cron_timezone'),
- onSelectTimezone: () => {
- gl.pipelineScheduleFieldErrors.updateFormValidityState();
- },
- });
gl.pipelineScheduleFieldErrors = new GlFieldErrors(formElement);
initTargetRefDropdown();
@@ -97,3 +90,5 @@ export default () => {
formField: 'schedule',
});
};
+
+initTimezoneDropdown();
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 3e5c02bbf19..c37b4cc643a 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
@@ -41,6 +41,8 @@ export default {
featureFlagsHelpText: s__(
'ProjectSettings|Roll out new features without redeploying with feature flags.',
),
+ infrastructureLabel: s__('ProjectSettings|Infrastructure'),
+ infrastructureHelpText: s__('ProjectSettings|Configure your infrastructure.'),
monitorLabel: s__('ProjectSettings|Monitor'),
packagesHelpText: s__(
'ProjectSettings|Every project can have its own space to store its packages. Note: The Package Registry is always visible when a project is public.',
@@ -157,6 +159,11 @@ export default {
required: false,
default: '',
},
+ infrastructureHelpPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
releasesHelpPath: {
type: String,
required: false,
@@ -245,6 +252,7 @@ export default {
operationsAccessLevel: featureAccessLevel.EVERYONE,
environmentsAccessLevel: featureAccessLevel.EVERYONE,
featureFlagsAccessLevel: featureAccessLevel.PROJECT_MEMBERS,
+ infrastructureAccessLevel: featureAccessLevel.PROJECT_MEMBERS,
releasesAccessLevel: featureAccessLevel.EVERYONE,
monitorAccessLevel: featureAccessLevel.EVERYONE,
containerRegistryAccessLevel: featureAccessLevel.EVERYONE,
@@ -433,6 +441,10 @@ export default {
featureAccessLevel.PROJECT_MEMBERS,
this.featureFlagsAccessLevel,
);
+ this.infrastructureAccessLevel = Math.min(
+ featureAccessLevel.PROJECT_MEMBERS,
+ this.infrastructureAccessLevel,
+ );
this.releasesAccessLevel = Math.min(
featureAccessLevel.PROJECT_MEMBERS,
this.releasesAccessLevel,
@@ -981,6 +993,19 @@ export default {
name="project[project_feature_attributes][feature_flags_access_level]"
/>
</project-setting-row>
+ <project-setting-row
+ ref="infrastructure-settings"
+ :label="$options.i18n.infrastructureLabel"
+ :help-text="$options.i18n.infrastructureHelpText"
+ :help-path="infrastructureHelpPath"
+ >
+ <project-feature-setting
+ v-model="infrastructureAccessLevel"
+ :label="$options.i18n.infrastructureLabel"
+ :options="featureAccessLevelOptions"
+ name="project[project_feature_attributes][infrastructure_access_level]"
+ />
+ </project-setting-row>
</template>
<project-setting-row
ref="releases-settings"
diff --git a/app/assets/javascripts/pages/projects/show/index.js b/app/assets/javascripts/pages/projects/show/index.js
index eff39a744ad..1de36f4a0fb 100644
--- a/app/assets/javascripts/pages/projects/show/index.js
+++ b/app/assets/javascripts/pages/projects/show/index.js
@@ -10,14 +10,6 @@ import { initUploadFileTrigger } from '~/projects/upload_file';
import initReadMore from '~/read_more';
// Project show page loads different overview content based on user preferences
-if (document.querySelector('.js-upload-blob-form')) {
- import(/* webpackChunkName: 'blobBundle' */ '~/blob_edit/blob_bundle')
- .then(({ initUploadForm }) => {
- initUploadForm();
- })
- .catch(() => {});
-}
-
if (document.getElementById('js-tree-list')) {
import(/* webpackChunkName: 'treeList' */ 'ee_else_ce/repository')
.then(({ default: initTree }) => {
diff --git a/app/assets/javascripts/pages/projects/tree/show/index.js b/app/assets/javascripts/pages/projects/tree/show/index.js
index cf7162f477d..17c17014ece 100644
--- a/app/assets/javascripts/pages/projects/tree/show/index.js
+++ b/app/assets/javascripts/pages/projects/tree/show/index.js
@@ -1,10 +1,8 @@
import $ from 'jquery';
import initTree from 'ee_else_ce/repository';
-import initBlob from '~/blob_edit/blob_bundle';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import NewCommitForm from '~/new_commit_form';
new NewCommitForm($('.js-create-dir-form')); // eslint-disable-line no-new
-initBlob();
initTree();
new ShortcutsNavigation(); // eslint-disable-line no-new
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 7b9656de362..8e2f542aec0 100644
--- a/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
+++ b/app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue
@@ -343,7 +343,7 @@ export default {
:uploads-path="pageInfo.uploadsPath"
:enable-content-editor="isMarkdownFormat"
:enable-preview="isMarkdownFormat"
- :init-on-autofocus="pageInfo.persisted"
+ :autofocus="pageInfo.persisted"
:form-field-placeholder="$options.i18n.content.placeholder"
:form-field-aria-label="$options.i18n.content.label"
form-field-id="wiki_content"
diff --git a/app/assets/javascripts/persistent_user_callouts.js b/app/assets/javascripts/persistent_user_callouts.js
index 2580cbcb944..139da5dabbd 100644
--- a/app/assets/javascripts/persistent_user_callouts.js
+++ b/app/assets/javascripts/persistent_user_callouts.js
@@ -23,9 +23,9 @@ const PERSISTENT_USER_CALLOUTS = [
];
const initCallouts = () => {
- PERSISTENT_USER_CALLOUTS.forEach((calloutContainer) =>
- PersistentUserCallout.factory(document.querySelector(calloutContainer)),
- );
+ document
+ .querySelectorAll(PERSISTENT_USER_CALLOUTS)
+ .forEach((calloutContainer) => PersistentUserCallout.factory(calloutContainer));
};
export default initCallouts;
diff --git a/app/assets/javascripts/pipeline_editor/components/pipeline_editor_tabs.vue b/app/assets/javascripts/pipeline_editor/components/pipeline_editor_tabs.vue
index 4941f22230b..ed5466ff99c 100644
--- a/app/assets/javascripts/pipeline_editor/components/pipeline_editor_tabs.vue
+++ b/app/assets/javascripts/pipeline_editor/components/pipeline_editor_tabs.vue
@@ -219,7 +219,6 @@ export default {
:empty-message="$options.i18n.empty.merge"
:keep-component-mounted="false"
:is-empty="isEmpty"
- :is-invalid="isInvalid"
:is-unavailable="isLintUnavailable"
:title="$options.i18n.tabMergedYaml"
lazy
diff --git a/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules.vue b/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules.vue
deleted file mode 100644
index 4a08a82275a..00000000000
--- a/app/assets/javascripts/pipeline_schedules/components/pipeline_schedules.vue
+++ /dev/null
@@ -1,134 +0,0 @@
-<script>
-import { GlAlert, GlLoadingIcon, GlModal } from '@gitlab/ui';
-import { s__, __ } from '~/locale';
-import deletePipelineScheduleMutation from '../graphql/mutations/delete_pipeline_schedule.mutation.graphql';
-import getPipelineSchedulesQuery from '../graphql/queries/get_pipeline_schedules.query.graphql';
-import PipelineSchedulesTable from './table/pipeline_schedules_table.vue';
-
-export default {
- i18n: {
- schedulesFetchError: s__('PipelineSchedules|There was a problem fetching pipeline schedules.'),
- scheduleDeleteError: s__(
- 'PipelineSchedules|There was a problem deleting the pipeline schedule.',
- ),
- },
- modal: {
- id: 'delete-pipeline-schedule-modal',
- deleteConfirmation: s__(
- 'PipelineSchedules|Are you sure you want to delete this pipeline schedule?',
- ),
- actionPrimary: {
- text: s__('PipelineSchedules|Delete pipeline schedule'),
- attributes: [{ variant: 'danger' }],
- },
- actionCancel: {
- text: __('Cancel'),
- attributes: [],
- },
- },
- components: {
- GlAlert,
- GlLoadingIcon,
- GlModal,
- PipelineSchedulesTable,
- },
- inject: {
- fullPath: {
- default: '',
- },
- },
- apollo: {
- schedules: {
- query: getPipelineSchedulesQuery,
- variables() {
- return {
- projectPath: this.fullPath,
- };
- },
- update({ project }) {
- return project?.pipelineSchedules?.nodes || [];
- },
- error() {
- this.reportError(this.$options.i18n.schedulesFetchError);
- },
- },
- },
- data() {
- return {
- schedules: [],
- hasError: false,
- errorMessage: '',
- scheduleToDeleteId: null,
- showModal: false,
- };
- },
- computed: {
- isLoading() {
- return this.$apollo.queries.schedules.loading;
- },
- },
- methods: {
- reportError(error) {
- this.hasError = true;
- this.errorMessage = error;
- },
- showDeleteModal(id) {
- this.showModal = true;
- this.scheduleToDeleteId = id;
- },
- hideModal() {
- this.showModal = false;
- this.scheduleToDeleteId = null;
- },
- async deleteSchedule() {
- try {
- const {
- data: {
- pipelineScheduleDelete: { errors },
- },
- } = await this.$apollo.mutate({
- mutation: deletePipelineScheduleMutation,
- variables: { id: this.scheduleToDeleteId },
- });
-
- if (errors.length > 0) {
- throw new Error();
- } else {
- this.$apollo.queries.schedules.refetch();
- }
- } catch {
- this.reportError(this.$options.i18n.scheduleDeleteError);
- }
- },
- },
-};
-</script>
-
-<template>
- <div>
- <gl-alert v-if="hasError" class="gl-mb-2" variant="danger" @dismiss="hasError = false">
- {{ errorMessage }}
- </gl-alert>
-
- <gl-loading-icon v-if="isLoading" size="lg" />
-
- <!-- Tabs will be addressed in #371989 -->
-
- <template v-else>
- <pipeline-schedules-table :schedules="schedules" @showDeleteModal="showDeleteModal" />
-
- <gl-modal
- :visible="showModal"
- :title="$options.modal.actionPrimary.text"
- :modal-id="$options.modal.id"
- :action-primary="$options.modal.actionPrimary"
- :action-cancel="$options.modal.actionCancel"
- size="sm"
- @primary="deleteSchedule"
- @hide="hideModal"
- >
- {{ $options.modal.deleteConfirmation }}
- </gl-modal>
- </template>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue b/app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue
deleted file mode 100644
index 76d118bf52d..00000000000
--- a/app/assets/javascripts/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue
+++ /dev/null
@@ -1,66 +0,0 @@
-<script>
-import { GlButton, GlButtonGroup, GlTooltipDirective as GlTooltip } from '@gitlab/ui';
-import { s__ } from '~/locale';
-
-export const i18n = {
- playTooltip: s__('PipelineSchedules|Run pipeline schedule'),
- editTooltip: s__('PipelineSchedules|Edit pipeline schedule'),
- deleteTooltip: s__('PipelineSchedules|Delete pipeline schedule'),
- takeOwnershipTooltip: s__('PipelineSchedules|Take ownership of pipeline schedule'),
-};
-
-export default {
- i18n,
- components: {
- GlButton,
- GlButtonGroup,
- },
- directives: {
- GlTooltip,
- },
- props: {
- schedule: {
- type: Object,
- required: true,
- },
- },
- computed: {
- canPlay() {
- return this.schedule.userPermissions.playPipelineSchedule;
- },
- canTakeOwnership() {
- return this.schedule.userPermissions.takeOwnershipPipelineSchedule;
- },
- canUpdate() {
- return this.schedule.userPermissions.updatePipelineSchedule;
- },
- canRemove() {
- return this.schedule.userPermissions.adminPipelineSchedule;
- },
- },
-};
-</script>
-
-<template>
- <div class="gl-display-flex gl-justify-content-end">
- <gl-button-group>
- <gl-button v-if="canPlay" v-gl-tooltip :title="$options.i18n.playTooltip" icon="play" />
- <gl-button
- v-if="canTakeOwnership"
- v-gl-tooltip
- :title="$options.i18n.takeOwnershipTooltip"
- icon="user"
- />
- <gl-button v-if="canUpdate" v-gl-tooltip :title="$options.i18n.editTooltip" icon="pencil" />
- <gl-button
- v-if="canRemove"
- v-gl-tooltip
- :title="$options.i18n.deleteTooltip"
- icon="remove"
- variant="danger"
- data-testid="delete-pipeline-schedule-btn"
- @click="$emit('showDeleteModal', schedule.id)"
- />
- </gl-button-group>
- </div>
-</template>
diff --git a/app/assets/javascripts/pipeline_schedules/components/table/pipeline_schedules_table.vue b/app/assets/javascripts/pipeline_schedules/components/table/pipeline_schedules_table.vue
deleted file mode 100644
index d54008b81b2..00000000000
--- a/app/assets/javascripts/pipeline_schedules/components/table/pipeline_schedules_table.vue
+++ /dev/null
@@ -1,95 +0,0 @@
-<script>
-import { GlTableLite } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import PipelineScheduleActions from './cells/pipeline_schedule_actions.vue';
-import PipelineScheduleLastPipeline from './cells/pipeline_schedule_last_pipeline.vue';
-import PipelineScheduleNextRun from './cells/pipeline_schedule_next_run.vue';
-import PipelineScheduleOwner from './cells/pipeline_schedule_owner.vue';
-import PipelineScheduleTarget from './cells/pipeline_schedule_target.vue';
-
-export default {
- fields: [
- {
- key: 'description',
- label: s__('PipelineSchedules|Description'),
- columnClass: 'gl-w-40p',
- },
- {
- key: 'target',
- label: s__('PipelineSchedules|Target'),
- columnClass: 'gl-w-10p',
- },
- {
- key: 'pipeline',
- label: s__('PipelineSchedules|Last Pipeline'),
- columnClass: 'gl-w-10p',
- },
- {
- key: 'next',
- label: s__('PipelineSchedules|Next Run'),
- columnClass: 'gl-w-15p',
- },
- {
- key: 'owner',
- label: s__('PipelineSchedules|Owner'),
- columnClass: 'gl-w-10p',
- },
- {
- key: 'actions',
- label: '',
- columnClass: 'gl-w-15p',
- },
- ],
- components: {
- GlTableLite,
- PipelineScheduleActions,
- PipelineScheduleLastPipeline,
- PipelineScheduleNextRun,
- PipelineScheduleOwner,
- PipelineScheduleTarget,
- },
- props: {
- schedules: {
- type: Array,
- required: true,
- },
- },
-};
-</script>
-
-<template>
- <gl-table-lite :fields="$options.fields" :items="schedules" stacked="md">
- <template #table-colgroup="{ fields }">
- <col v-for="field in fields" :key="field.key" :class="field.columnClass" />
- </template>
-
- <template #cell(description)="{ item }">
- <span data-testid="pipeline-schedule-description">
- {{ item.description }}
- </span>
- </template>
-
- <template #cell(target)="{ item }">
- <pipeline-schedule-target :schedule="item" />
- </template>
-
- <template #cell(pipeline)="{ item }">
- <pipeline-schedule-last-pipeline :schedule="item" />
- </template>
-
- <template #cell(next)="{ item }">
- <pipeline-schedule-next-run :schedule="item" />
- </template>
-
- <template #cell(owner)="{ item }">
- <pipeline-schedule-owner :schedule="item" />
- </template>
-
- <template #cell(actions)="{ item }">
- <pipeline-schedule-actions
- :schedule="item"
- @showDeleteModal="$emit('showDeleteModal', $event)"
- />
- </template>
- </gl-table-lite>
-</template>
diff --git a/app/assets/javascripts/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql b/app/assets/javascripts/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql
deleted file mode 100644
index 7d9d658b1b6..00000000000
--- a/app/assets/javascripts/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql
+++ /dev/null
@@ -1,40 +0,0 @@
-query getPipelineSchedulesQuery($projectPath: ID!) {
- project(fullPath: $projectPath) {
- id
- pipelineSchedules {
- nodes {
- id
- description
- forTag
- refPath
- refForDisplay
- lastPipeline {
- id
- detailedStatus {
- id
- group
- icon
- label
- text
- detailsPath
- }
- }
- active
- nextRunAt
- realNextRun
- owner {
- id
- avatarUrl
- name
- webPath
- }
- userPermissions {
- playPipelineSchedule
- takeOwnershipPipelineSchedule
- updatePipelineSchedule
- adminPipelineSchedule
- }
- }
- }
- }
-}
diff --git a/app/assets/javascripts/pipeline_schedules/mount_pipeline_schedules_app.js b/app/assets/javascripts/pipeline_schedules/mount_pipeline_schedules_app.js
deleted file mode 100644
index 8f77e06c19a..00000000000
--- a/app/assets/javascripts/pipeline_schedules/mount_pipeline_schedules_app.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import createDefaultClient from '~/lib/graphql';
-import PipelineSchedules from './components/pipeline_schedules.vue';
-
-Vue.use(VueApollo);
-
-const apolloProvider = new VueApollo({
- defaultClient: createDefaultClient(),
-});
-
-export default () => {
- const containerEl = document.querySelector('#pipeline-schedules-app');
-
- if (!containerEl) {
- return false;
- }
-
- const { fullPath } = containerEl.dataset;
-
- return new Vue({
- el: containerEl,
- name: 'PipelineSchedulesRoot',
- apolloProvider,
- provide: {
- fullPath,
- },
- render(createElement) {
- return createElement(PipelineSchedules);
- },
- });
-};
diff --git a/app/assets/javascripts/pipelines/components/dag/dag.vue b/app/assets/javascripts/pipelines/components/dag/dag.vue
index 475dd3bf36e..be12df68f76 100644
--- a/app/assets/javascripts/pipelines/components/dag/dag.vue
+++ b/app/assets/javascripts/pipelines/components/dag/dag.vue
@@ -29,7 +29,7 @@ export default {
dagDocPath: {
default: null,
},
- emptySvgPath: {
+ emptyDagSvgPath: {
default: '',
},
pipelineIid: {
@@ -213,7 +213,7 @@ export default {
/>
<gl-empty-state
v-else-if="hasNoDependentJobs"
- :svg-path="emptySvgPath"
+ :svg-path="emptyDagSvgPath"
:title="$options.emptyStateTexts.title"
>
<template #description>
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 f1c6c6633eb..ba150919e58 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
@@ -27,6 +27,7 @@ export default {
},
dropdownPopperOpts: {
placement: 'bottom',
+ positionFixed: true,
},
components: {
CiIcon,
@@ -136,25 +137,19 @@ export default {
:is-active="isDropdownOpen"
:size="24"
:status="stage.status"
- class="gl-align-items-center gl-border gl-display-inline-flex gl-z-index-1"
+ class="gl-display-inline-flex gl-align-items-center gl-border gl-z-index-1"
/>
</template>
- <div
- v-if="isLoading"
- class="gl-display-flex gl-justify-content-center gl-p-2"
- data-testid="pipeline-stage-loading-state"
- >
+ <div v-if="isLoading" class="gl--flex-center gl-p-2" data-testid="pipeline-stage-loading-state">
<gl-loading-icon size="sm" class="gl-mr-3" />
- <p class="gl-mb-0">{{ $options.i18n.loadingText }}</p>
+ <p class="gl-line-height-normal gl-mb-0">{{ $options.i18n.loadingText }}</p>
</div>
<ul
v-else
class="js-builds-dropdown-list scrollable-menu"
data-testid="mini-pipeline-graph-dropdown-menu-list"
>
- <div
- class="gl-align-items-center gl-border-b gl-display-flex gl-font-weight-bold gl-justify-content-center gl-pb-3"
- >
+ <div class="gl--flex-center gl-border-b gl-font-weight-bold gl-pb-3">
<span class="gl-mr-1">{{ $options.i18n.stage }}</span>
<span data-testid="pipeline-stage-dropdown-menu-title">{{ stageName }}</span>
</div>
diff --git a/app/assets/javascripts/pipelines/components/pipeline_tabs.vue b/app/assets/javascripts/pipelines/components/pipeline_tabs.vue
index 2a78636261b..3798863ae60 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_tabs.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_tabs.vue
@@ -1,12 +1,13 @@
<script>
import { GlBadge, GlTabs, GlTab } from '@gitlab/ui';
import { __ } from '~/locale';
-import { failedJobsTabName, jobsTabName, needsTabName, testReportTabName } from '../constants';
-import PipelineGraphWrapper from './graph/graph_component_wrapper.vue';
-import Dag from './dag/dag.vue';
-import FailedJobsApp from './jobs/failed_jobs_app.vue';
-import JobsApp from './jobs/jobs_app.vue';
-import TestReports from './test_reports/test_reports.vue';
+import {
+ failedJobsTabName,
+ jobsTabName,
+ needsTabName,
+ pipelineTabName,
+ testReportTabName,
+} from '../constants';
export default {
i18n: {
@@ -19,20 +20,16 @@ export default {
},
},
tabNames: {
+ pipeline: pipelineTabName,
needs: needsTabName,
jobs: jobsTabName,
failures: failedJobsTabName,
tests: testReportTabName,
},
components: {
- Dag,
GlBadge,
GlTab,
GlTabs,
- JobsApp,
- FailedJobsApp,
- PipelineGraphWrapper,
- TestReports,
},
inject: [
'defaultTabValue',
@@ -41,14 +38,27 @@ export default {
'totalJobCount',
'testsCount',
],
+ data() {
+ return {
+ activeTab: this.defaultTabValue,
+ };
+ },
computed: {
showFailedJobsTab() {
return this.failedJobsCount > 0;
},
},
+ watch: {
+ $route(to) {
+ this.activeTab = to.name;
+ },
+ },
methods: {
isActive(tabName) {
- return tabName === this.defaultTabValue;
+ return tabName === this.activeTab;
+ },
+ navigateTo(tabName) {
+ this.$router.push({ name: tabName });
},
},
};
@@ -59,10 +69,12 @@ export default {
<gl-tab
ref="pipelineTab"
:title="$options.i18n.tabs.pipelineTitle"
+ :active="isActive($options.tabNames.pipeline)"
data-testid="pipeline-tab"
lazy
+ @click="navigateTo($options.tabNames.pipeline)"
>
- <pipeline-graph-wrapper />
+ <router-view />
</gl-tab>
<gl-tab
ref="dagTab"
@@ -70,15 +82,21 @@ export default {
:active="isActive($options.tabNames.needs)"
data-testid="dag-tab"
lazy
+ @click="navigateTo($options.tabNames.needs)"
>
- <dag />
+ <router-view />
</gl-tab>
- <gl-tab :active="isActive($options.tabNames.jobs)" data-testid="jobs-tab" lazy>
+ <gl-tab
+ :active="isActive($options.tabNames.jobs)"
+ data-testid="jobs-tab"
+ lazy
+ @click="navigateTo($options.tabNames.jobs)"
+ >
<template #title>
<span class="gl-mr-2">{{ $options.i18n.tabs.jobsTitle }}</span>
<gl-badge size="sm" data-testid="builds-counter">{{ totalJobCount }}</gl-badge>
</template>
- <jobs-app />
+ <router-view />
</gl-tab>
<gl-tab
v-if="showFailedJobsTab"
@@ -86,19 +104,25 @@ export default {
:active="isActive($options.tabNames.failures)"
data-testid="failed-jobs-tab"
lazy
+ @click="navigateTo($options.tabNames.failures)"
>
<template #title>
<span class="gl-mr-2">{{ $options.i18n.tabs.failedJobsTitle }}</span>
<gl-badge size="sm" data-testid="failed-builds-counter">{{ failedJobsCount }}</gl-badge>
</template>
- <failed-jobs-app :failed-jobs-summary="failedJobsSummary" />
+ <router-view :failed-jobs-summary="failedJobsSummary" />
</gl-tab>
- <gl-tab :active="isActive($options.tabNames.tests)" data-testid="tests-tab" lazy>
+ <gl-tab
+ :active="isActive($options.tabNames.tests)"
+ data-testid="tests-tab"
+ lazy
+ @click="navigateTo($options.tabNames.tests)"
+ >
<template #title>
<span class="gl-mr-2">{{ $options.i18n.tabs.testsTitle }}</span>
<gl-badge size="sm" data-testid="tests-counter">{{ testsCount }}</gl-badge>
</template>
- <test-reports />
+ <router-view />
</gl-tab>
<slot></slot>
</gl-tabs>
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue
index 39d41415456..fe2ef2c2d71 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_url.vue
@@ -115,6 +115,9 @@ export default {
commitTitle() {
return this.pipeline?.commit?.title;
},
+ pipelineName() {
+ return this.pipeline?.name;
+ },
},
methods: {
trackClick(action) {
@@ -125,7 +128,18 @@ export default {
</script>
<template>
<div class="pipeline-tags" data-testid="pipeline-url-table-cell">
- <div class="commit-title gl-mb-2" data-testid="commit-title-container">
+ <div v-if="pipelineName" class="gl-mb-2" data-testid="pipeline-name-container">
+ <span class="gl-display-flex">
+ <tooltip-on-truncate
+ :title="pipelineName"
+ class="gl-flex-grow-1 gl-text-truncate gl-text-gray-900"
+ >
+ {{ pipelineName }}
+ </tooltip-on-truncate>
+ </span>
+ </div>
+
+ <div v-if="!pipelineName" class="commit-title gl-mb-2" data-testid="commit-title-container">
<span v-if="commitTitle" class="gl-display-flex">
<tooltip-on-truncate :title="commitTitle" class="gl-flex-grow-1 gl-text-truncate">
<gl-link
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue b/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue
index 387438fb726..cd44c998074 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/time_ago.vue
@@ -1,12 +1,14 @@
<script>
import { GlIcon, GlTooltipDirective } from '@gitlab/ui';
-import { formatDate, getTimeago, durationTimeFormatted } from '~/lib/utils/datetime_utility';
+import { durationTimeFormatted } from '~/lib/utils/datetime_utility';
+import timeagoMixin from '~/vue_shared/mixins/timeago';
export default {
directives: {
GlTooltip: GlTooltipDirective,
},
components: { GlIcon },
+ mixins: [timeagoMixin],
props: {
pipeline: {
type: Object,
@@ -35,12 +37,6 @@ export default {
showSkipped() {
return !this.duration && !this.finishedTime && this.skipped;
},
- timeFormatted() {
- return getTimeago().format(this.finishedTime);
- },
- tooltipTitle() {
- return formatDate(this.finishedTime);
- },
},
};
</script>
@@ -73,12 +69,12 @@ export default {
<time
v-gl-tooltip
- :title="tooltipTitle"
+ :title="tooltipTitle(finishedTime)"
:datetime="finishedTime"
data-placement="top"
data-container="body"
>
- {{ timeFormatted }}
+ {{ timeFormatted(finishedTime) }}
</time>
</p>
</div>
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 69509c9088b..2d1f1945e5a 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
@@ -73,6 +73,7 @@ export default {
<template>
<gl-modal
+ data-testid="test-case-details-modal"
:modal-id="modalId"
:title="testCase.classname"
:action-primary="$options.modalCloseButton"
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 7d0f1ba4b5f..1cd28e027f3 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
@@ -112,21 +112,21 @@ export default {
>
<div class="table-section section-20 section-wrap">
<div role="rowheader" class="table-mobile-header">{{ __('Suite') }}</div>
- <div class="table-mobile-content gl-md-pr-2 gl-overflow-wrap-break">
+ <div class="table-mobile-content gl-pr-0 gl-sm-pr-2 gl-overflow-wrap-break">
<gl-friendly-wrap :symbols="$options.wrapSymbols" :text="testCase.classname" />
</div>
</div>
<div class="table-section section-40 section-wrap">
<div role="rowheader" class="table-mobile-header">{{ __('Name') }}</div>
- <div class="table-mobile-content gl-md-pr-2 gl-overflow-wrap-break">
+ <div class="table-mobile-content gl-pr-0 gl-sm-pr-2 gl-overflow-wrap-break">
<gl-friendly-wrap :symbols="$options.wrapSymbols" :text="testCase.name" />
</div>
</div>
<div class="table-section section-10 section-wrap">
<div role="rowheader" class="table-mobile-header">{{ __('Filename') }}</div>
- <div class="table-mobile-content gl-md-pr-2 gl-overflow-wrap-break">
+ <div class="table-mobile-content gl-pr-0 gl-sm-pr-2 gl-overflow-wrap-break">
<gl-link v-if="testCase.file" :href="testCase.filePath" target="_blank">
<gl-friendly-wrap :symbols="$options.wrapSymbols" :text="testCase.file" />
</gl-link>
@@ -156,7 +156,7 @@ export default {
<div role="rowheader" class="table-mobile-header">
{{ __('Duration') }}
</div>
- <div class="table-mobile-content gl-sm-pr-2">
+ <div class="table-mobile-content gl-pr-0 gl-sm-pr-2">
{{ testCase.formattedTime }}
</div>
</div>
diff --git a/app/assets/javascripts/pipelines/constants.js b/app/assets/javascripts/pipelines/constants.js
index 327633dcb1a..ed8ec614304 100644
--- a/app/assets/javascripts/pipelines/constants.js
+++ b/app/assets/javascripts/pipelines/constants.js
@@ -47,8 +47,7 @@ export const CHILD_VIEW = 'child';
// Pipeline tabs
-export const TAB_QUERY_PARAM = 'tab';
-
+export const pipelineTabName = 'graph';
export const needsTabName = 'dag';
export const jobsTabName = 'builds';
export const failedJobsTabName = 'failures';
diff --git a/app/assets/javascripts/pipelines/pipeline_details_bundle.js b/app/assets/javascripts/pipelines/pipeline_details_bundle.js
index 3744649e9d5..1bbdd3625be 100644
--- a/app/assets/javascripts/pipelines/pipeline_details_bundle.js
+++ b/app/assets/javascripts/pipelines/pipeline_details_bundle.js
@@ -1,3 +1,4 @@
+import VueRouter from 'vue-router';
import { createAlert } from '~/flash';
import { __, s__ } from '~/locale';
import createDagApp from './pipeline_details_dag';
@@ -32,9 +33,16 @@ export default async function initPipelineDetailsBundle() {
if (gon.features?.pipelineTabsVue) {
const { createAppOptions } = await import('ee_else_ce/pipelines/pipeline_tabs');
const { createPipelineTabs } = await import('./pipeline_tabs');
+ const { routes } = await import('ee_else_ce/pipelines/routes');
+
+ const router = new VueRouter({
+ mode: 'history',
+ base: dataset.pipelinePath,
+ routes,
+ });
try {
- const appOptions = createAppOptions(SELECTORS.PIPELINE_TABS, apolloProvider);
+ const appOptions = createAppOptions(SELECTORS.PIPELINE_TABS, apolloProvider, router);
createPipelineTabs(appOptions);
} catch {
createAlert({
diff --git a/app/assets/javascripts/pipelines/pipeline_tabs.js b/app/assets/javascripts/pipelines/pipeline_tabs.js
index 508f188c229..d0ee6871a48 100644
--- a/app/assets/javascripts/pipelines/pipeline_tabs.js
+++ b/app/assets/javascripts/pipelines/pipeline_tabs.js
@@ -1,17 +1,17 @@
import Vue from 'vue';
+import VueRouter from 'vue-router';
import Vuex from 'vuex';
import VueApollo from 'vue-apollo';
import PipelineTabs from 'ee_else_ce/pipelines/components/pipeline_tabs.vue';
-import { removeParams, updateHistory } from '~/lib/utils/url_utility';
-import { TAB_QUERY_PARAM } from '~/pipelines/constants';
import { parseBoolean } from '~/lib/utils/common_utils';
import createTestReportsStore from './stores/test_reports';
import { getPipelineDefaultTab, reportToSentry } from './utils';
Vue.use(VueApollo);
+Vue.use(VueRouter);
Vue.use(Vuex);
-export const createAppOptions = (selector, apolloProvider) => {
+export const createAppOptions = (selector, apolloProvider, router) => {
const el = document.querySelector(selector);
if (!el) return null;
@@ -40,6 +40,7 @@ export const createAppOptions = (selector, apolloProvider) => {
suiteEndpoint,
blobPath,
hasTestReport,
+ emptyDagSvgPath,
emptyStateImagePath,
artifactsExpiredImagePath,
isFullCodequalityReportAvailable,
@@ -65,6 +66,7 @@ export const createAppOptions = (selector, apolloProvider) => {
}),
},
}),
+ router,
provide: {
canGenerateCodequalityReports: parseBoolean(canGenerateCodequalityReports),
codequalityReportDownloadPath,
@@ -91,6 +93,7 @@ export const createAppOptions = (selector, apolloProvider) => {
suiteEndpoint,
blobPath,
hasTestReport,
+ emptyDagSvgPath,
emptyStateImagePath,
artifactsExpiredImagePath,
testsCount,
@@ -107,12 +110,6 @@ export const createAppOptions = (selector, apolloProvider) => {
export const createPipelineTabs = (options) => {
if (!options) return;
- updateHistory({
- url: removeParams([TAB_QUERY_PARAM]),
- title: document.title,
- replace: true,
- });
-
// eslint-disable-next-line no-new
new Vue(options);
};
diff --git a/app/assets/javascripts/pipelines/routes.js b/app/assets/javascripts/pipelines/routes.js
new file mode 100644
index 00000000000..0e1414ec390
--- /dev/null
+++ b/app/assets/javascripts/pipelines/routes.js
@@ -0,0 +1,20 @@
+import PipelineGraphWrapper from './components/graph/graph_component_wrapper.vue';
+import Dag from './components/dag/dag.vue';
+import FailedJobsApp from './components/jobs/failed_jobs_app.vue';
+import JobsApp from './components/jobs/jobs_app.vue';
+import TestReports from './components/test_reports/test_reports.vue';
+import {
+ pipelineTabName,
+ needsTabName,
+ jobsTabName,
+ failedJobsTabName,
+ testReportTabName,
+} from './constants';
+
+export const routes = [
+ { name: pipelineTabName, path: '/', component: PipelineGraphWrapper },
+ { name: needsTabName, path: '/dag', component: Dag },
+ { name: jobsTabName, path: '/builds', component: JobsApp },
+ { name: failedJobsTabName, path: '/failures', component: FailedJobsApp },
+ { name: testReportTabName, path: '/test_report', component: TestReports },
+];
diff --git a/app/assets/javascripts/pipelines/utils.js b/app/assets/javascripts/pipelines/utils.js
index 588d15495ab..b8276327843 100644
--- a/app/assets/javascripts/pipelines/utils.js
+++ b/app/assets/javascripts/pipelines/utils.js
@@ -1,12 +1,7 @@
import * as Sentry from '@sentry/browser';
import { pickBy } from 'lodash';
-import { getParameterValues } from '~/lib/utils/url_utility';
-import {
- NEEDS_PROPERTY,
- SUPPORTED_FILTER_PARAMETERS,
- TAB_QUERY_PARAM,
- validPipelineTabNames,
-} from './constants';
+import { parseUrlPathname } from '~/lib/utils/url_utility';
+import { NEEDS_PROPERTY, SUPPORTED_FILTER_PARAMETERS, validPipelineTabNames } from './constants';
/*
The following functions are the main engine in transforming the data as
received from the endpoint into the format the d3 graph expects.
@@ -145,10 +140,12 @@ export const reportMessageToSentry = (component, message, context) => {
};
export const getPipelineDefaultTab = (url) => {
- const [tabQueryValue] = getParameterValues(TAB_QUERY_PARAM, url);
+ const strippedUrl = parseUrlPathname(url);
+ const regexp = /\w*$/;
+ const [tabName] = strippedUrl.match(regexp);
- if (tabQueryValue && validPipelineTabNames.includes(tabQueryValue)) {
- return tabQueryValue;
+ if (tabName && validPipelineTabNames.includes(tabName)) {
+ return tabName;
}
return null;
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 2802e4a90b9..0256eec6d56 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
@@ -124,7 +124,7 @@ export default {
</script>
<template>
- <div class="gl-pt-2">
+ <div>
<gl-loading-icon v-if="$apollo.queries.pipeline.loading" />
<pipeline-mini-graph
v-else
diff --git a/app/assets/javascripts/projects/commits/store/actions.js b/app/assets/javascripts/projects/commits/store/actions.js
index 603fdfdf80a..9365066418b 100644
--- a/app/assets/javascripts/projects/commits/store/actions.js
+++ b/app/assets/javascripts/projects/commits/store/actions.js
@@ -3,6 +3,7 @@ import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { joinPaths } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
+import { ACTIVE_AND_BLOCKED_USER_STATES } from '~/users_select/constants';
import * as types from './mutation_types';
export default {
@@ -23,7 +24,7 @@ export default {
.get(joinPaths(gon.relative_url_root || '', '/-/autocomplete/users.json'), {
params: {
project_id: projectId,
- active: true,
+ states: ACTIVE_AND_BLOCKED_USER_STATES,
search: author,
},
})
diff --git a/app/assets/javascripts/projects/compare/components/app.vue b/app/assets/javascripts/projects/compare/components/app.vue
index 271694863e8..e4d5e5bd233 100644
--- a/app/assets/javascripts/projects/compare/components/app.vue
+++ b/app/assets/javascripts/projects/compare/components/app.vue
@@ -131,7 +131,7 @@ export default {
<revision-card
data-testid="sourceRevisionCard"
:refs-project-path="to.refsProjectPath"
- revision-text="Source"
+ :revision-text="__('Source')"
params-name="to"
:params-branch="to.revision"
:projects="to.projects"
@@ -160,7 +160,7 @@ export default {
<revision-card
data-testid="targetRevisionCard"
:refs-project-path="from.refsProjectPath"
- revision-text="Target"
+ :revision-text="__('Target')"
params-name="from"
:params-branch="from.revision"
:projects="from.projects"
diff --git a/app/assets/javascripts/projects/components/shared/delete_button.vue b/app/assets/javascripts/projects/components/shared/delete_button.vue
index 277af2f281e..64a16b462f5 100644
--- a/app/assets/javascripts/projects/components/shared/delete_button.vue
+++ b/app/assets/javascripts/projects/components/shared/delete_button.vue
@@ -62,7 +62,11 @@ export default {
return {
primary: {
text: __('Yes, delete project'),
- attributes: [{ variant: 'danger' }, { disabled: this.confirmDisabled }],
+ attributes: [
+ { variant: 'danger' },
+ { disabled: this.confirmDisabled },
+ { 'data-qa-selector': 'confirm_delete_button' },
+ ],
},
cancel: {
text: __('Cancel, keep project'),
@@ -97,9 +101,13 @@ export default {
<input type="hidden" name="_method" value="delete" />
<input :value="csrfToken" type="hidden" name="authenticity_token" />
- <gl-button v-gl-modal="modalId" category="primary" variant="danger">{{
- $options.strings.deleteProject
- }}</gl-button>
+ <gl-button
+ v-gl-modal="modalId"
+ category="primary"
+ variant="danger"
+ data-qa-selector="delete_button"
+ >{{ $options.strings.deleteProject }}</gl-button
+ >
<gl-modal
ref="removeModal"
@@ -168,6 +176,7 @@ export default {
v-model="userInput"
name="confirm_name_input"
type="text"
+ data-qa-selector="confirm_name_field"
/>
<slot name="modal-footer"></slot>
</div>
diff --git a/app/assets/javascripts/projects/new/components/new_project_push_tip_popover.vue b/app/assets/javascripts/projects/new/components/new_project_push_tip_popover.vue
index e42d9154866..c23644b40d2 100644
--- a/app/assets/javascripts/projects/new/components/new_project_push_tip_popover.vue
+++ b/app/assets/javascripts/projects/new/components/new_project_push_tip_popover.vue
@@ -56,7 +56,7 @@ export default {
</p>
<p>
<a
- :href="`${workingWithProjectsHelpPath}#push-to-create-a-new-project`"
+ :href="`${workingWithProjectsHelpPath}#create-a-new-project-with-git-push`"
class="gl-font-sm"
target="_blank"
>{{ $options.i18n.helpLinkText }}</a
diff --git a/app/assets/javascripts/projects/pipelines/charts/components/app.vue b/app/assets/javascripts/projects/pipelines/charts/components/app.vue
index 186fcf70838..4643bfe58f6 100644
--- a/app/assets/javascripts/projects/pipelines/charts/components/app.vue
+++ b/app/assets/javascripts/projects/pipelines/charts/components/app.vue
@@ -2,6 +2,8 @@
import { GlTabs, GlTab } from '@gitlab/ui';
import API from '~/api';
import { mergeUrlParams, updateHistory, getParameterValues } from '~/lib/utils/url_utility';
+import Tracking from '~/tracking';
+import { SNOWPLOW_DATA_SOURCE, SNOWPLOW_LABEL, SNOWPLOW_SCHEMA } from '../constants';
import PipelineCharts from './pipeline_charts.vue';
export default {
@@ -23,6 +25,7 @@ export default {
leadTimeTabEvent: 'p_analytics_ci_cd_lead_time',
timeToRestoreServiceTabEvent: 'p_analytics_ci_cd_time_to_restore_service',
changeFailureRateTabEvent: 'p_analytics_ci_cd_change_failure_rate',
+ mixins: [Tracking.mixin()],
inject: {
shouldRenderDoraCharts: {
type: Boolean,
@@ -75,8 +78,21 @@ export default {
updateHistory({ url: path, title: window.title });
}
},
- trackTabClick(tab) {
- API.trackRedisHllUserEvent(tab);
+ trackTabClick(event, snowplow = false) {
+ API.trackRedisHllUserEvent(event);
+
+ if (snowplow) {
+ this.track('click_tab', {
+ label: SNOWPLOW_LABEL,
+ context: {
+ schema: SNOWPLOW_SCHEMA,
+ data: {
+ event_name: event,
+ data_source: SNOWPLOW_DATA_SOURCE,
+ },
+ },
+ });
+ }
},
},
};
@@ -87,7 +103,7 @@ export default {
<gl-tab
:title="__('Pipelines')"
data-testid="pipelines-tab"
- @click="trackTabClick($options.piplelinesTabEvent)"
+ @click="trackTabClick($options.piplelinesTabEvent, true)"
>
<pipeline-charts />
</gl-tab>
@@ -95,14 +111,14 @@ export default {
<gl-tab
:title="__('Deployment frequency')"
data-testid="deployment-frequency-tab"
- @click="trackTabClick($options.deploymentFrequencyTabEvent)"
+ @click="trackTabClick($options.deploymentFrequencyTabEvent, true)"
>
<deployment-frequency-charts />
</gl-tab>
<gl-tab
:title="__('Lead time')"
data-testid="lead-time-tab"
- @click="trackTabClick($options.leadTimeTabEvent)"
+ @click="trackTabClick($options.leadTimeTabEvent, true)"
>
<lead-time-charts />
</gl-tab>
diff --git a/app/assets/javascripts/projects/pipelines/charts/constants.js b/app/assets/javascripts/projects/pipelines/charts/constants.js
index 41fe81f21ea..c13824a9952 100644
--- a/app/assets/javascripts/projects/pipelines/charts/constants.js
+++ b/app/assets/javascripts/projects/pipelines/charts/constants.js
@@ -19,3 +19,7 @@ export const PARSE_FAILURE = 'parse_failure';
export const LOAD_ANALYTICS_FAILURE = 'load_analytics_failure';
export const LOAD_PIPELINES_FAILURE = 'load_analytics_failure';
export const UNSUPPORTED_DATA = 'unsupported_data';
+
+export const SNOWPLOW_LABEL = 'redis_hll_counters.analytics.analytics_total_unique_counts_monthly';
+export const SNOWPLOW_SCHEMA = 'iglu:com.gitlab/gitlab_service_ping/jsonschema/1-0-0';
+export const SNOWPLOW_DATA_SOURCE = 'redis_hll';
diff --git a/app/assets/javascripts/projects/settings/api/access_dropdown_api.js b/app/assets/javascripts/projects/settings/api/access_dropdown_api.js
index 10f6c28a7bf..df99aac6b9e 100644
--- a/app/assets/javascripts/projects/settings/api/access_dropdown_api.js
+++ b/app/assets/javascripts/projects/settings/api/access_dropdown_api.js
@@ -12,7 +12,7 @@ const buildUrl = (urlRoot, url) => {
return newUrl;
};
-export const getUsers = (query) => {
+export const getUsers = (query, states) => {
return axios.get(buildUrl(gon.relative_url_root || '', USERS_PATH), {
params: {
search: query,
@@ -20,6 +20,7 @@ export const getUsers = (query) => {
active: true,
project_id: gon.current_project_id,
push_code: true,
+ states,
},
});
};
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 264c2629433..6da058ebc9c 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
@@ -21,9 +21,14 @@ export const I18N = {
approvalsTitle: s__('BranchRules|Approvals'),
manageApprovalsLinkTitle: s__('BranchRules|Manage in Merge Request Approvals'),
approvalsDescription: s__(
- 'BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Lean more.%{linkEnd}',
+ 'BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}',
),
statusChecksTitle: s__('BranchRules|Status checks'),
+ statusChecksDescription: s__(
+ 'BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}',
+ ),
+ statusChecksLinkTitle: s__('BranchRules|Manage in Status checks'),
+ statusChecksHeader: s__('BranchRules|Status checks (%{total})'),
allowedToPushHeader: s__('BranchRules|Allowed to push (%{total})'),
allowedToMergeHeader: s__('BranchRules|Allowed to merge (%{total})'),
approvalsHeader: s__('BranchRules|Required approvals (%{total})'),
@@ -40,3 +45,5 @@ export const WILDCARDS_HELP_PATH =
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';
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 318940478a8..eb11e17dd1b 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
@@ -12,11 +12,13 @@ import {
WILDCARDS_HELP_PATH,
PROTECTED_BRANCHES_HELP_PATH,
APPROVALS_HELP_PATH,
+ STATUS_CHECKS_HELP_PATH,
} from './constants';
const wildcardsHelpDocLink = helpPagePath(WILDCARDS_HELP_PATH);
const protectedBranchesHelpDocLink = helpPagePath(PROTECTED_BRANCHES_HELP_PATH);
const approvalsHelpDocLink = helpPagePath(APPROVALS_HELP_PATH);
+const statusChecksHelpDocLink = helpPagePath(STATUS_CHECKS_HELP_PATH);
export default {
name: 'RuleView',
@@ -24,6 +26,7 @@ export default {
wildcardsHelpDocLink,
protectedBranchesHelpDocLink,
approvalsHelpDocLink,
+ statusChecksHelpDocLink,
components: { Protection, GlSprintf, GlLink, GlLoadingIcon },
inject: {
projectPath: {
@@ -35,6 +38,9 @@ export default {
approvalRulesPath: {
default: '',
},
+ statusChecksPath: {
+ default: '',
+ },
},
apollo: {
project: {
@@ -45,18 +51,19 @@ export default {
};
},
update({ project: { branchRules } }) {
- this.branchProtection = branchRules.nodes.find(
- (rule) => rule.name === this.branch,
- )?.branchProtection;
+ const branchRule = branchRules.nodes.find((rule) => rule.name === this.branch);
+ this.branchProtection = branchRule?.branchProtection;
+ this.approvalRules = branchRule?.approvalRules;
+ this.statusChecks = branchRule?.externalStatusChecks?.nodes || [];
},
},
},
data() {
return {
branch: getParameterByName(BRANCH_PARAM_NAME),
- branchProtection: {
- approvalRules: {},
- },
+ branchProtection: {},
+ approvalRules: {},
+ statusChecks: [],
};
},
computed: {
@@ -92,6 +99,11 @@ export default {
total,
});
},
+ statusChecksHeader() {
+ return sprintf(this.$options.i18n.statusChecksHeader, {
+ total: this.statusChecks.length,
+ });
+ },
allBranches() {
return this.branch === ALL_BRANCHES_WILDCARD;
},
@@ -104,7 +116,7 @@ export default {
: this.$options.i18n.branchNameOrPattern;
},
approvals() {
- return this.branchProtection?.approvalRules?.nodes || [];
+ return this.approvalRules?.nodes || [];
},
},
methods: {
@@ -202,6 +214,21 @@ export default {
/>
<!-- Status checks -->
- <!-- Follow-up: add status checks section (https://gitlab.com/gitlab-org/gitlab/-/issues/372362) -->
+ <h4 class="gl-mb-1 gl-mt-5">{{ $options.i18n.statusChecksTitle }}</h4>
+ <gl-sprintf :message="$options.i18n.statusChecksDescription">
+ <template #link="{ content }">
+ <gl-link :href="$options.statusChecksHelpDocLink">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+
+ <protection
+ class="gl-mt-3"
+ :header="statusChecksHeader"
+ :header-link-title="$options.i18n.statusChecksLinkTitle"
+ :header-link-href="statusChecksPath"
+ :status-checks="statusChecks"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/projects/settings/branch_rules/components/view/protection.vue b/app/assets/javascripts/projects/settings/branch_rules/components/view/protection.vue
index cfe2df0dbda..813c667dcdd 100644
--- a/app/assets/javascripts/projects/settings/branch_rules/components/view/protection.vue
+++ b/app/assets/javascripts/projects/settings/branch_rules/components/view/protection.vue
@@ -46,6 +46,11 @@ export default {
required: false,
default: () => [],
},
+ statusChecks: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
},
computed: {
showUsersDivider() {
@@ -95,5 +100,14 @@ export default {
:users="approval.eligibleApprovers.nodes"
:approvals-required="approval.approvalsRequired"
/>
+
+ <!-- Status checks -->
+ <protection-row
+ v-for="(statusCheck, index) in statusChecks"
+ :key="statusCheck.id"
+ :show-divider="index !== 0"
+ :title="statusCheck.name"
+ :status-check-url="statusCheck.externalUrl"
+ />
</gl-card>
</template>
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 28a1c09fa82..9bff2f5506c 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
@@ -41,6 +41,11 @@ export default {
required: false,
default: 0,
},
+ statusCheckUrl: {
+ type: String,
+ required: false,
+ default: null,
+ },
},
computed: {
avatarBadgeSrOnlyText() {
@@ -64,10 +69,10 @@ export default {
<template>
<div
- class="gl-display-flex gl-align-items-center gl-border-gray-100 gl-mb-4 gl-pt-4"
+ class="gl-display-flex gl-align-items-center gl-border-gray-100 gl-mb-4 gl-pt-4 gl-border-t-1"
:class="{ 'gl-border-t-solid': showDivider }"
>
- <div class="gl-display-flex gl-w-half gl-justify-content-space-between">
+ <div class="gl-display-flex gl-w-full gl-justify-content-space-between gl-align-items-center">
<div class="gl-mr-7 gl-w-quarter">{{ title }}</div>
<gl-avatars-inline
@@ -94,6 +99,8 @@ export default {
</template>
</gl-avatars-inline>
+ <div v-if="statusCheckUrl" class="gl-ml-7 gl-flex-grow-1">{{ statusCheckUrl }}</div>
+
<div
v-for="(item, index) in accessLevels"
:key="index"
@@ -104,7 +111,7 @@ export default {
{{ item.accessLevelDescription }}
</div>
- <div class="gl-ml-7 gl-w-quarter">{{ approvalsRequiredTitle }}</div>
+ <div class="gl-ml-7 gl-flex-grow-1">{{ approvalsRequiredTitle }}</div>
</div>
</div>
</template>
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 07fd0a7080f..89cfb1e1c8e 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
@@ -14,7 +14,7 @@ export default function mountBranchRules(el) {
defaultClient: createDefaultClient(),
});
- const { projectPath, protectedBranchesPath, approvalRulesPath } = el.dataset;
+ const { projectPath, protectedBranchesPath, approvalRulesPath, statusChecksPath } = el.dataset;
return new Vue({
el,
@@ -23,6 +23,7 @@ export default function mountBranchRules(el) {
projectPath,
protectedBranchesPath,
approvalRulesPath,
+ statusChecksPath,
},
render(h) {
return h(View);
diff --git a/app/assets/javascripts/projects/settings/branch_rules/queries/branch_rules_details.query.graphql b/app/assets/javascripts/projects/settings/branch_rules/queries/branch_rules_details.query.graphql
index 3ac165498a1..aa1e4923aa8 100644
--- a/app/assets/javascripts/projects/settings/branch_rules/queries/branch_rules_details.query.graphql
+++ b/app/assets/javascripts/projects/settings/branch_rules/queries/branch_rules_details.query.graphql
@@ -44,6 +44,30 @@ query getBranchRulesDetails($projectPath: ID!) {
}
}
}
+ approvalRules {
+ nodes {
+ id
+ name
+ type
+ approvalsRequired
+ eligibleApprovers {
+ nodes {
+ id
+ name
+ username
+ webUrl
+ avatarUrl
+ }
+ }
+ }
+ }
+ externalStatusChecks {
+ nodes {
+ id
+ name
+ externalUrl
+ }
+ }
}
}
}
diff --git a/app/assets/javascripts/projects/settings/components/transfer_project_form.vue b/app/assets/javascripts/projects/settings/components/transfer_project_form.vue
index 55420c9c732..fd5fabd7c8a 100644
--- a/app/assets/javascripts/projects/settings/components/transfer_project_form.vue
+++ b/app/assets/javascripts/projects/settings/components/transfer_project_form.vue
@@ -1,30 +1,14 @@
<script>
-import { GlFormGroup, GlAlert } from '@gitlab/ui';
-import { debounce } from 'lodash';
import ConfirmDanger from '~/vue_shared/components/confirm_danger/confirm_danger.vue';
-import NamespaceSelect from '~/vue_shared/components/namespace_select/namespace_select_deprecated.vue';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import TransferLocations from '~/groups_projects/components/transfer_locations.vue';
import { getTransferLocations } from '~/api/projects_api';
-import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
-import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants';
-import { s__, __ } from '~/locale';
-import currentUserNamespace from '../graphql/queries/current_user_namespace.query.graphql';
export default {
name: 'TransferProjectForm',
components: {
- GlFormGroup,
- NamespaceSelect,
+ TransferLocations,
ConfirmDanger,
- GlAlert,
},
- i18n: {
- errorMessage: s__(
- 'ProjectTransfer|An error occurred fetching the transfer locations, please refresh the page and try again.',
- ),
- alertDismissAlert: __('Dismiss'),
- },
- inject: ['projectId'],
props: {
confirmationPhrase: {
type: String,
@@ -37,150 +21,37 @@ export default {
},
data() {
return {
- userNamespaces: [],
- groupNamespaces: [],
- initialNamespacesLoaded: false,
- selectedNamespace: null,
- hasError: false,
- isLoading: false,
- isSearchLoading: false,
- searchTerm: '',
- page: 1,
- totalPages: 1,
+ selectedTransferLocation: null,
};
},
+
computed: {
hasSelectedNamespace() {
- return Boolean(this.selectedNamespace?.id);
+ return Boolean(this.selectedTransferLocation?.id);
},
- hasNextPageOfGroups() {
- return this.page < this.totalPages;
+ },
+ watch: {
+ selectedTransferLocation(selectedTransferLocation) {
+ this.$emit('selectTransferLocation', selectedTransferLocation.id);
},
},
methods: {
- async handleShow() {
- if (this.initialNamespacesLoaded) {
- return;
- }
-
- this.isLoading = true;
-
- [this.groupNamespaces, this.userNamespaces] = await Promise.all([
- this.getGroupNamespaces(),
- this.getUserNamespaces(),
- ]);
-
- this.isLoading = false;
- this.initialNamespacesLoaded = true;
- },
- handleSelect(selectedNamespace) {
- this.selectedNamespace = selectedNamespace;
- this.$emit('selectNamespace', selectedNamespace.id);
- },
- async getGroupNamespaces() {
- try {
- const { data: groupNamespaces, headers } = await getTransferLocations(this.projectId, {
- page: this.page,
- search: this.searchTerm,
- });
-
- const { totalPages } = parseIntPagination(normalizeHeaders(headers));
- this.totalPages = totalPages;
-
- return groupNamespaces.map(({ id, full_name: humanName }) => ({
- id,
- humanName,
- }));
- } catch (error) {
- this.hasError = true;
-
- return [];
- }
- },
- async getUserNamespaces() {
- try {
- const {
- data: {
- currentUser: { namespace },
- },
- } = await this.$apollo.query({
- query: currentUserNamespace,
- });
-
- if (!namespace) {
- return [];
- }
-
- return [
- {
- id: getIdFromGraphQLId(namespace.id),
- humanName: namespace.fullName,
- },
- ];
- } catch (error) {
- this.hasError = true;
-
- return [];
- }
- },
- async handleLoadMoreGroups() {
- this.isLoading = true;
- this.page += 1;
-
- const groupNamespaces = await this.getGroupNamespaces();
- this.groupNamespaces.push(...groupNamespaces);
-
- this.isLoading = false;
- },
- debouncedSearch: debounce(async function debouncedSearch() {
- this.isSearchLoading = true;
-
- this.groupNamespaces = await this.getGroupNamespaces();
-
- this.isSearchLoading = false;
- }, DEBOUNCE_DELAY),
- handleSearch(searchTerm) {
- this.searchTerm = searchTerm;
- this.page = 1;
-
- this.debouncedSearch();
- },
- handleAlertDismiss() {
- this.hasError = false;
- },
+ getTransferLocations,
},
};
</script>
<template>
<div>
- <gl-alert
- v-if="hasError"
- variant="danger"
- :dismiss-label="$options.i18n.alertDismissLabel"
- @dismiss="handleAlertDismiss"
- >{{ $options.i18n.errorMessage }}</gl-alert
- >
- <gl-form-group>
- <namespace-select
- data-testid="transfer-project-namespace"
- :full-width="true"
- :group-namespaces="groupNamespaces"
- :user-namespaces="userNamespaces"
- :selected-namespace="selectedNamespace"
- :has-next-page-of-groups="hasNextPageOfGroups"
- :is-loading="isLoading"
- :is-search-loading="isSearchLoading"
- :should-filter-namespaces="false"
- @select="handleSelect"
- @load-more-groups="handleLoadMoreGroups"
- @search="handleSearch"
- @show="handleShow"
- />
- </gl-form-group>
+ <transfer-locations
+ v-model="selectedTransferLocation"
+ data-testid="transfer-project-namespace"
+ :group-transfer-locations-api-method="getTransferLocations"
+ />
<confirm-danger
:disabled="!hasSelectedNamespace"
:phrase="confirmationPhrase"
:button-text="confirmButtonText"
+ button-qa-selector="transfer_project_button"
@confirm="$emit('confirm')"
/>
</div>
diff --git a/app/assets/javascripts/projects/settings/init_transfer_project_form.js b/app/assets/javascripts/projects/settings/init_transfer_project_form.js
index 89c158a9ba8..7f810e647ae 100644
--- a/app/assets/javascripts/projects/settings/init_transfer_project_form.js
+++ b/app/assets/javascripts/projects/settings/init_transfer_project_form.js
@@ -12,7 +12,7 @@ export default () => {
Vue.use(VueApollo);
const {
- projectId,
+ projectId: resourceId,
targetFormId = null,
targetHiddenInputId = null,
buttonText: confirmButtonText = '',
@@ -27,7 +27,7 @@ export default () => {
}),
provide: {
confirmDangerMessage,
- projectId,
+ resourceId,
},
render(createElement) {
return createElement(TransferProjectForm, {
@@ -36,7 +36,7 @@ export default () => {
confirmationPhrase,
},
on: {
- selectNamespace: (id) => {
+ selectTransferLocation: (id) => {
if (targetHiddenInputId && document.getElementById(targetHiddenInputId)) {
document.getElementById(targetHiddenInputId).value = id;
}
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 94793a535cc..a9eb2a53fbf 100644
--- a/app/assets/javascripts/projects/settings/repository/branch_rules/app.vue
+++ b/app/assets/javascripts/projects/settings/repository/branch_rules/app.vue
@@ -50,7 +50,15 @@ export default {
<template>
<div class="settings-content">
- <branch-rule v-for="rule in branchRules" :key="rule.name" :name="rule.name" />
+ <branch-rule
+ v-for="rule in branchRules"
+ :key="rule.name"
+ :name="rule.name"
+ :is-default="rule.isDefault"
+ :branch-protection="rule.branchProtection"
+ :status-checks-total="rule.externalStatusChecks.nodes.length"
+ :approval-rules-total="rule.approvalRules.nodes.length"
+ />
<span v-if="!branchRules.length" data-testid="empty">{{ $options.i18n.emptyState }}</span>
</div>
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 2b88f8561d7..78c824c66d1 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
@@ -1,11 +1,14 @@
<script>
import { GlBadge, GlButton } from '@gitlab/ui';
-import { s__ } from '~/locale';
+import { s__, sprintf, n__ } from '~/locale';
export const i18n = {
defaultLabel: s__('BranchRules|default'),
- protectedLabel: s__('BranchRules|protected'),
detailsButtonLabel: s__('BranchRules|Details'),
+ allowForcePush: s__('BranchRules|Allowed to force push'),
+ codeOwnerApprovalRequired: s__('BranchRules|Requires CODEOWNERS approval'),
+ statusChecks: s__('BranchRules|%{total} status %{subject}'),
+ approvalRules: s__('BranchRules|%{total} approval %{subject}'),
};
export default {
@@ -30,24 +33,57 @@ export default {
required: false,
default: false,
},
- isProtected: {
- type: Boolean,
+ branchProtection: {
+ type: Object,
required: false,
- default: false,
+ default: () => {},
},
- approvalDetails: {
- type: Array,
+ statusChecksTotal: {
+ type: Number,
required: false,
- default: () => [],
+ default: 0,
+ },
+ approvalRulesTotal: {
+ type: Number,
+ required: false,
+ default: 0,
},
},
computed: {
hasApprovalDetails() {
- return this.approvalDetails && this.approvalDetails.length;
+ return this.approvalDetails.length;
},
detailsPath() {
return `${this.branchRulesPath}?branch=${this.name}`;
},
+ statusChecksText() {
+ return sprintf(this.$options.i18n.statusChecks, {
+ total: this.statusChecksTotal,
+ subject: n__('check', 'checks', this.statusChecksTotal),
+ });
+ },
+ approvalRulesText() {
+ return sprintf(this.$options.i18n.approvalRules, {
+ total: this.approvalRulesTotal,
+ subject: n__('rule', 'rules', this.approvalRulesTotal),
+ });
+ },
+ approvalDetails() {
+ const approvalDetails = [];
+ if (this.branchProtection.allowForcePush) {
+ approvalDetails.push(this.$options.i18n.allowForcePush);
+ }
+ if (this.branchProtection.codeOwnerApprovalRequired) {
+ approvalDetails.push(this.$options.i18n.codeOwnerApprovalRequired);
+ }
+ if (this.statusChecksTotal) {
+ approvalDetails.push(this.statusChecksText);
+ }
+ if (this.approvalRulesTotal) {
+ approvalDetails.push(this.approvalRulesText);
+ }
+ return approvalDetails;
+ },
},
};
</script>
@@ -61,14 +97,12 @@ export default {
$options.i18n.defaultLabel
}}</gl-badge>
- <gl-badge v-if="isProtected" variant="success" size="sm" class="gl-ml-2">{{
- $options.i18n.protectedLabel
- }}</gl-badge>
-
<ul v-if="hasApprovalDetails" class="gl-pl-6 gl-mt-2 gl-mb-0 gl-text-gray-500">
<li v-for="(detail, index) in approvalDetails" :key="index">{{ detail }}</li>
</ul>
</div>
- <gl-button :href="detailsPath"> {{ $options.i18n.detailsButtonLabel }}</gl-button>
+ <gl-button class="gl-align-self-start" :href="detailsPath">
+ {{ $options.i18n.detailsButtonLabel }}</gl-button
+ >
</div>
</template>
diff --git a/app/assets/javascripts/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql b/app/assets/javascripts/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql
index 104a0c25a80..49e089e7805 100644
--- a/app/assets/javascripts/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql
+++ b/app/assets/javascripts/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql
@@ -4,6 +4,21 @@ query getBranchRules($projectPath: ID!) {
branchRules {
nodes {
name
+ isDefault
+ branchProtection {
+ allowForcePush
+ codeOwnerApprovalRequired
+ }
+ externalStatusChecks {
+ nodes {
+ id
+ }
+ }
+ approvalRules {
+ nodes {
+ id
+ }
+ }
}
}
}
diff --git a/app/assets/javascripts/projects/settings_service_desk/components/service_desk_setting.vue b/app/assets/javascripts/projects/settings_service_desk/components/service_desk_setting.vue
index 452e7a4fd21..85550e262e6 100644
--- a/app/assets/javascripts/projects/settings_service_desk/components/service_desk_setting.vue
+++ b/app/assets/javascripts/projects/settings_service_desk/components/service_desk_setting.vue
@@ -265,35 +265,14 @@ export default {
class="mt-3"
>
<gl-form-input
- v-if="hasProjectKeySupport"
id="service-desk-email-from-name"
v-model.trim="outgoingName"
data-testid="email-from-name"
/>
- <template v-if="hasProjectKeySupport" #description>
+ <template #description>
{{ __('Name to be used as the sender for emails from Service Desk.') }}
</template>
- <template v-else #description>
- <span class="gl-text-gray-900">
- <gl-sprintf
- :message="
- __(
- 'To add display name, set up a Service Desk email address. %{linkStart}Learn more.%{linkEnd}',
- )
- "
- >
- <template #link="{ content }">
- <gl-link
- :href="customEmailAddressHelpUrl"
- target="_blank"
- class="gl-text-blue-600 font-size-inherit"
- >{{ content }}
- </gl-link>
- </template>
- </gl-sprintf>
- </span>
- </template>
</gl-form-group>
<gl-button
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 1ab41ee2f0a..4a130ade631 100644
--- a/app/assets/javascripts/related_issues/components/related_issues_block.vue
+++ b/app/assets/javascripts/related_issues/components/related_issues_block.vue
@@ -1,6 +1,6 @@
<script>
import { GlLink, GlIcon, GlButton } from '@gitlab/ui';
-import { __ } from '~/locale';
+import { __, sprintf } from '~/locale';
import {
issuableIconMap,
linkedIssueTypesMap,
@@ -95,6 +95,16 @@ export default {
required: false,
default: true,
},
+ hasError: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ itemAddFailureMessage: {
+ type: String,
+ required: false,
+ default: '',
+ },
},
data() {
return {
@@ -120,9 +130,6 @@ export default {
shouldShowTokenBody() {
return this.hasRelatedIssues || this.isFetching;
},
- hasBody() {
- return this.isFormVisible || this.shouldShowTokenBody;
- },
headerText() {
return issuablesBlockHeaderTextMap[this.issuableType];
},
@@ -147,6 +154,11 @@ export default {
toggleLabel() {
return this.isOpen ? __('Collapse') : __('Expand');
},
+ emptyStateMessage() {
+ return this.showCategorizedIssues
+ ? sprintf(this.$options.i18n.emptyItemsPremium, { issuableType: this.issuableType })
+ : sprintf(this.$options.i18n.emptyItemsFree, { issuableType: this.issuableType });
+ },
},
methods: {
handleToggle() {
@@ -158,6 +170,12 @@ export default {
},
},
linkedIssueTypesTextMap,
+ i18n: {
+ emptyItemsFree: __("Link %{issuableType}s together to show that they're related."),
+ emptyItemsPremium: __(
+ "Link %{issuableType}s together to show that they're related or that one is blocking others.",
+ ),
+ },
};
</script>
@@ -166,7 +184,6 @@ export default {
<div class="card card-slim gl-overflow-hidden gl-mt-5 gl-mb-0">
<div
:class="{
- 'panel-empty-heading border-bottom-0': !hasBody,
'gl-border-b-1': isOpen,
'gl-border-b-0': !isOpen,
}"
@@ -180,16 +197,6 @@ export default {
aria-hidden="true"
/>
<slot name="header-text">{{ headerText }}</slot>
- <gl-link
- v-if="hasHelpPath"
- :href="helpPath"
- target="_blank"
- class="gl-display-flex gl-align-items-center gl-ml-2 gl-text-gray-500"
- data-testid="help-link"
- :aria-label="helpLinkText"
- >
- <gl-icon name="question" :size="12" />
- </gl-link>
<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">
@@ -216,7 +223,6 @@ export default {
size="small"
:icon="toggleIcon"
:aria-label="toggleLabel"
- :disabled="!hasRelatedIssues"
data-testid="toggle-links"
@click="handleToggle"
/>
@@ -233,7 +239,7 @@ export default {
<div
v-if="isFormVisible"
class="js-add-related-issues-form-area card-body bordered-box bg-white"
- :class="{ 'gl-mb-5': shouldShowTokenBody }"
+ :class="{ 'gl-mb-5': shouldShowTokenBody, 'gl-show-field-errors': hasError }"
>
<add-issuable-form
:show-categorized-issues="showCategorizedIssues"
@@ -245,6 +251,8 @@ export default {
:auto-complete-epics="autoCompleteEpics"
:auto-complete-issues="autoCompleteIssues"
:path-id-separator="pathIdSeparator"
+ :has-error="hasError"
+ :item-add-failure-message="itemAddFailureMessage"
@pendingIssuableRemoveRequest="$emit('pendingIssuableRemoveRequest', $event)"
@addIssuableFormInput="$emit('addIssuableFormInput', $event)"
@addIssuableFormBlur="$emit('addIssuableFormBlur', $event)"
@@ -269,6 +277,20 @@ export default {
@saveReorder="$emit('saveReorder', $event)"
/>
</template>
+ <div v-if="!shouldShowTokenBody && !isFormVisible" data-testid="related-items-empty">
+ <p class="gl-my-5 gl-px-5">
+ {{ emptyStateMessage }}
+ <gl-link
+ v-if="hasHelpPath"
+ :href="helpPath"
+ target="_blank"
+ data-testid="help-link"
+ :aria-label="helpLinkText"
+ >
+ {{ __('Learn more.') }}
+ </gl-link>
+ </p>
+ </div>
</div>
</div>
</div>
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 38e1d6e9d4f..795eb3b0083 100644
--- a/app/assets/javascripts/related_issues/components/related_issues_root.vue
+++ b/app/assets/javascripts/related_issues/components/related_issues_root.vue
@@ -107,6 +107,8 @@ export default {
isSubmitting: false,
isFormVisible: false,
inputValue: '',
+ hasError: false,
+ errorMessage: null,
};
},
computed: {
@@ -170,11 +172,11 @@ export default {
this.isFormVisible = false;
})
.catch(({ response }) => {
- let errorMessage = addRelatedIssueErrorMap[this.issuableType];
+ this.hasError = true;
+ this.errorMessage = addRelatedIssueErrorMap[this.issuableType];
if (response && response.data && response.data.message) {
- errorMessage = response.data.message;
+ this.errorMessage = response.data.message;
}
- createAlert({ message: errorMessage });
})
.finally(() => {
this.isSubmitting = false;
@@ -266,6 +268,8 @@ export default {
:issuable-type="issuableType"
:path-id-separator="pathIdSeparator"
:show-categorized-issues="showCategorizedIssues"
+ :has-error="hasError"
+ :item-add-failure-message="errorMessage"
@saveReorder="saveIssueOrder"
@toggleAddRelatedIssuesForm="onToggleAddRelatedIssuesForm"
@addIssuableFormInput="onInput"
diff --git a/app/assets/javascripts/related_issues/constants.js b/app/assets/javascripts/related_issues/constants.js
index 4eb054ccb5c..d1b2d41d7ae 100644
--- a/app/assets/javascripts/related_issues/constants.js
+++ b/app/assets/javascripts/related_issues/constants.js
@@ -111,8 +111,9 @@ export const issuablesBlockHeaderTextMap = {
};
export const issuablesBlockHelpTextMap = {
- [issuableTypesMap.ISSUE]: __('Read more about related issues'),
- [issuableTypesMap.EPIC]: __('Read more about related epics'),
+ [issuableTypesMap.ISSUE]: __('Learn more about linking issues'),
+ [issuableTypesMap.INCIDENT]: __('Learn more about linking issues and incidents'),
+ [issuableTypesMap.EPIC]: __('Learn more about linking epics'),
};
export const issuablesBlockAddButtonTextMap = {
diff --git a/app/assets/javascripts/related_issues/index.js b/app/assets/javascripts/related_issues/index.js
index eb2f5d119b8..c77a67c4287 100644
--- a/app/assets/javascripts/related_issues/index.js
+++ b/app/assets/javascripts/related_issues/index.js
@@ -17,6 +17,7 @@ export function initRelatedIssues(issueType = 'issue') {
provide: {
fullPath: el.dataset.fullPath,
hasIssueWeightsFeature: parseBoolean(el.dataset.hasIssueWeightsFeature),
+ hasIterationsFeature: parseBoolean(el.dataset.hasIterationsFeature),
},
render: (createElement) =>
createElement(RelatedIssuesRoot, {
diff --git a/app/assets/javascripts/releases/components/app_edit_new.vue b/app/assets/javascripts/releases/components/app_edit_new.vue
index dd3f4ed636f..965b9fa09d6 100644
--- a/app/assets/javascripts/releases/components/app_edit_new.vue
+++ b/app/assets/javascripts/releases/components/app_edit_new.vue
@@ -257,9 +257,9 @@ export default {
<asset-links-form />
- <div class="d-flex pt-3">
+ <div class="d-flex gl-gap-x-3 pt-3">
<gl-button
- class="mr-auto js-no-auto-disable"
+ class="js-no-auto-disable"
category="primary"
variant="confirm"
type="submit"
diff --git a/app/assets/javascripts/releases/components/asset_links_form.vue b/app/assets/javascripts/releases/components/asset_links_form.vue
index 7c6d44456d9..dc465851721 100644
--- a/app/assets/javascripts/releases/components/asset_links_form.vue
+++ b/app/assets/javascripts/releases/components/asset_links_form.vue
@@ -131,10 +131,10 @@ export default {
<div
v-for="(link, index) in release.assets.links"
:key="link.id"
- class="row flex-column flex-sm-row align-items-stretch align-items-sm-start no-gutters"
+ class="gl-sm-display-flex flex-column flex-sm-row gl-gap-5 align-items-stretch align-items-sm-start no-gutters"
>
<gl-form-group
- class="url-field form-group col pr-sm-2"
+ class="url-field form-group col"
:label="__('URL')"
:label-for="`asset-url-${index}`"
>
@@ -174,7 +174,7 @@ export default {
</gl-form-group>
<gl-form-group
- class="link-title-field col px-sm-2"
+ class="link-title-field col"
:label="__('Link title')"
:label-for="`asset-link-name-${index}`"
>
@@ -201,7 +201,7 @@ export default {
</gl-form-group>
<gl-form-group
- class="link-type-field col-auto px-sm-2"
+ class="link-type-field col-auto"
:label="__('Type')"
:label-for="`asset-type-${index}`"
>
@@ -216,9 +216,8 @@ export default {
/>
</gl-form-group>
- <div class="mb-5 mb-sm-3 mt-sm-4 col col-sm-auto pl-sm-2">
+ <div v-if="release.assets.links.length !== 1" class="mb-5 mb-sm-3 mt-sm-4 col col-sm-auto">
<gl-button
- v-gl-tooltip
class="remove-button w-100 form-control"
:aria-label="__('Remove asset link')"
:title="__('Remove asset link')"
@@ -233,8 +232,9 @@ export default {
</div>
<gl-button
ref="addAnotherLinkButton"
- variant="link"
- class="align-self-end mb-5 mb-sm-0"
+ category="secondary"
+ variant="confirm"
+ class="gl-align-self-start gl-mb-5"
@click="onAddAnotherClicked"
>
{{ __('Add another link') }}
diff --git a/app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue b/app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue
deleted file mode 100644
index 599e8d35708..00000000000
--- a/app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue
+++ /dev/null
@@ -1,84 +0,0 @@
-<script>
-import { mapState, mapActions, mapGetters } from 'vuex';
-import { s__, sprintf } from '~/locale';
-import { componentNames } from '~/reports/components/issue_body';
-import ReportSection from '~/reports/components/report_section.vue';
-import createStore from './store';
-
-export default {
- name: 'GroupedCodequalityReportsApp',
- store: createStore(),
- components: {
- ReportSection,
- },
- props: {
- headBlobPath: {
- type: String,
- required: true,
- },
- baseBlobPath: {
- type: String,
- required: false,
- default: null,
- },
- codequalityReportsPath: {
- type: String,
- required: false,
- default: '',
- },
- codequalityHelpPath: {
- type: String,
- required: true,
- },
- },
- componentNames,
- computed: {
- ...mapState(['newIssues', 'resolvedIssues', 'hasError', 'statusReason']),
- ...mapGetters([
- 'hasCodequalityIssues',
- 'codequalityStatus',
- 'codequalityText',
- 'codequalityPopover',
- ]),
- },
- created() {
- this.setPaths({
- baseBlobPath: this.baseBlobPath,
- headBlobPath: this.headBlobPath,
- reportsPath: this.codequalityReportsPath,
- helpPath: this.codequalityHelpPath,
- });
-
- this.fetchReports();
- },
- methods: {
- ...mapActions(['fetchReports', 'setPaths']),
- },
- loadingText: sprintf(s__('ciReport|Loading %{reportName} report'), {
- // eslint-disable-next-line @gitlab/require-i18n-strings
- reportName: 'Code quality',
- }),
- errorText: sprintf(s__('ciReport|Failed to load %{reportName} report'), {
- // eslint-disable-next-line @gitlab/require-i18n-strings
- reportName: 'Code quality',
- }),
-};
-</script>
-<template>
- <report-section
- :status="codequalityStatus"
- :loading-text="$options.loadingText"
- :error-text="$options.errorText"
- :success-text="codequalityText"
- :unresolved-issues="newIssues"
- :resolved-issues="resolvedIssues"
- :has-issues="hasCodequalityIssues"
- :component="$options.componentNames.CodequalityIssueBody"
- :popover-options="codequalityPopover"
- :show-report-section-status-icon="false"
- track-action="users_expanding_testing_code_quality_report"
- class="js-codequality-widget mr-widget-border-top mr-report"
- >
- <template v-if="hasError" #sub-heading>{{ statusReason }}</template>
- </report-section>
-</template>
diff --git a/app/assets/javascripts/reports/components/issue_body.js b/app/assets/javascripts/reports/components/issue_body.js
index a76a6f45c07..4f418216024 100644
--- a/app/assets/javascripts/reports/components/issue_body.js
+++ b/app/assets/javascripts/reports/components/issue_body.js
@@ -2,12 +2,10 @@ import IssueStatusIcon from '~/reports/components/issue_status_icon.vue';
export const components = {
CodequalityIssueBody: () => import('../codequality_report/components/codequality_issue_body.vue'),
- TestIssueBody: () => import('../grouped_test_report/components/test_issue_body.vue'),
};
export const componentNames = {
CodequalityIssueBody: 'CodequalityIssueBody',
- TestIssueBody: 'TestIssueBody',
};
export const iconComponents = {
diff --git a/app/assets/javascripts/reports/components/report_section.vue b/app/assets/javascripts/reports/components/report_section.vue
index bb86695b9a3..468c8916b8d 100644
--- a/app/assets/javascripts/reports/components/report_section.vue
+++ b/app/assets/javascripts/reports/components/report_section.vue
@@ -168,11 +168,6 @@ export default {
},
methods: {
toggleCollapsed() {
- // Because the top-level div is always clickable, we need to check if we can collapse.
- if (!this.isCollapsible) {
- return;
- }
-
if (this.trackAction) {
api.trackRedisHllUserEvent(this.trackAction);
}
@@ -187,7 +182,7 @@ export default {
</script>
<template>
<section class="media-section">
- <div class="media" :class="{ 'gl-cursor-pointer': isCollapsible }" @click="toggleCollapsed">
+ <div class="media">
<status-icon :status="statusIconName" :size="24" class="align-self-center" />
<div class="media-body gl-display-flex gl-align-items-flex-start gl-flex-direction-row!">
<div
@@ -218,7 +213,7 @@ export default {
category="tertiary"
size="small"
:icon="isExpanded ? 'chevron-lg-up' : 'chevron-lg-down'"
- @click.stop="toggleCollapsed"
+ @click="toggleCollapsed"
/>
</div>
</div>
diff --git a/app/assets/javascripts/reports/grouped_test_report/components/modal.vue b/app/assets/javascripts/reports/grouped_test_report/components/modal.vue
deleted file mode 100644
index ca518aea743..00000000000
--- a/app/assets/javascripts/reports/grouped_test_report/components/modal.vue
+++ /dev/null
@@ -1,74 +0,0 @@
-<script>
-import { GlModal, GlLink, GlSprintf } from '@gitlab/ui';
-
-import CodeBlock from '~/vue_shared/components/code_block.vue';
-import { fieldTypes } from '../../constants';
-
-export default {
- components: {
- CodeBlock,
- GlModal,
- GlLink,
- GlSprintf,
- },
- props: {
- visible: {
- type: Boolean,
- required: true,
- },
- title: {
- type: String,
- required: true,
- },
- modalData: {
- type: Object,
- required: true,
- },
- },
- computed: {
- filteredModalData() {
- // Filter out the properties that don't have a value
- return Object.fromEntries(
- Object.entries(this.modalData).filter((data) => Boolean(data[1].value)),
- );
- },
- },
- fieldTypes,
-};
-</script>
-<template>
- <gl-modal
- :visible="visible"
- modal-id="modal-mrwidget-reports"
- :title="title"
- :hide-footer="true"
- @hide="$emit('hide')"
- >
- <div v-for="(field, key, index) in filteredModalData" :key="index" class="row gl-mt-3 gl-mb-3">
- <strong class="col-sm-3 text-right"> {{ field.text }}: </strong>
-
- <div class="col-sm-9">
- <code-block v-if="field.type === $options.fieldTypes.codeBlock" :code="field.value" />
-
- <gl-link
- v-else-if="field.type === $options.fieldTypes.link"
- :href="field.value.path"
- target="_blank"
- >
- {{ field.value.text }}
- </gl-link>
-
- <gl-sprintf
- v-else-if="field.type === $options.fieldTypes.seconds"
- :message="__('%{value} s')"
- >
- <template #value>{{ field.value }}</template>
- </gl-sprintf>
-
- <template v-else-if="field.type === $options.fieldTypes.text">
- {{ field.value }}
- </template>
- </div>
- </div>
- </gl-modal>
-</template>
diff --git a/app/assets/javascripts/reports/grouped_test_report/components/test_issue_body.vue b/app/assets/javascripts/reports/grouped_test_report/components/test_issue_body.vue
deleted file mode 100644
index 8913046d62f..00000000000
--- a/app/assets/javascripts/reports/grouped_test_report/components/test_issue_body.vue
+++ /dev/null
@@ -1,64 +0,0 @@
-<script>
-import { GlBadge, GlButton } from '@gitlab/ui';
-import { mapActions } from 'vuex';
-import { sprintf, n__ } from '~/locale';
-import IssueStatusIcon from '~/reports/components/issue_status_icon.vue';
-import { STATUS_NEUTRAL } from '../../constants';
-
-export default {
- name: 'TestIssueBody',
- components: {
- GlBadge,
- GlButton,
- IssueStatusIcon,
- },
- props: {
- issue: {
- type: Object,
- required: true,
- },
- },
- computed: {
- recentFailureMessage() {
- return sprintf(
- n__(
- 'Reports|Failed %{count} time in %{base_branch} in the last 14 days',
- 'Reports|Failed %{count} times in %{base_branch} in the last 14 days',
- this.issue.recent_failures?.count,
- ),
- this.issue.recent_failures,
- );
- },
- showRecentFailures() {
- return this.issue.recent_failures?.count && this.issue.recent_failures?.base_branch;
- },
- status() {
- return this.issue.status || STATUS_NEUTRAL;
- },
- },
- methods: {
- ...mapActions(['openModal']),
- },
-};
-</script>
-<template>
- <div class="gl-display-flex gl-mt-2 gl-mb-2">
- <issue-status-icon :status="status" :status-icon-size="24" class="gl-mr-3" />
- <gl-button
- button-text-classes="gl-white-space-normal! gl-word-break-all gl-text-left"
- variant="link"
- data-testid="test-issue-body-description"
- @click="openModal({ issue })"
- >
- <gl-badge
- v-if="showRecentFailures"
- variant="warning"
- class="gl-mr-2"
- data-testid="test-issue-body-recent-failures"
- >
- {{ recentFailureMessage }}
- </gl-badge>
- {{ issue.name }}
- </gl-button>
- </div>
-</template>
diff --git a/app/assets/javascripts/reports/grouped_test_report/grouped_test_reports_app.vue b/app/assets/javascripts/reports/grouped_test_report/grouped_test_reports_app.vue
deleted file mode 100644
index be49a03a9a5..00000000000
--- a/app/assets/javascripts/reports/grouped_test_report/grouped_test_reports_app.vue
+++ /dev/null
@@ -1,204 +0,0 @@
-<script>
-import { GlButton, GlIcon } from '@gitlab/ui';
-import { mapActions, mapGetters, mapState } from 'vuex';
-import api from '~/api';
-import { sprintf, s__ } from '~/locale';
-import GroupedIssuesList from '../components/grouped_issues_list.vue';
-import { componentNames } from '../components/issue_body';
-import ReportSection from '../components/report_section.vue';
-import SummaryRow from '../components/summary_row.vue';
-import Modal from './components/modal.vue';
-import createStore from './store';
-import {
- summaryTextBuilder,
- reportTextBuilder,
- statusIcon,
- recentFailuresTextBuilder,
-} from './store/utils';
-
-export default {
- name: 'GroupedTestReportsApp',
- store: createStore(),
- components: {
- ReportSection,
- SummaryRow,
- GroupedIssuesList,
- Modal,
- GlButton,
- GlIcon,
- },
- props: {
- endpoint: {
- type: String,
- required: true,
- },
- pipelinePath: {
- type: String,
- required: false,
- default: '',
- },
- headBlobPath: {
- type: String,
- required: true,
- },
- },
- componentNames,
- computed: {
- ...mapState(['reports', 'isLoading', 'hasError', 'summary']),
- ...mapState({
- modalTitle: (state) => state.modal.title || '',
- modalData: (state) => state.modal.data || {},
- modalOpen: (state) => state.modal.open || false,
- }),
- ...mapGetters(['summaryStatus']),
- groupedSummaryText() {
- if (this.isLoading) {
- return s__('Reports|Test summary results are being parsed');
- }
-
- if (this.hasError) {
- return s__('Reports|Test summary failed loading results');
- }
-
- return summaryTextBuilder(s__('Reports|Test summary'), this.summary);
- },
- testTabURL() {
- return `${this.pipelinePath}/test_report`;
- },
- showViewFullReport() {
- return this.pipelinePath.length;
- },
- },
- created() {
- this.setPaths({
- endpoint: this.endpoint,
- headBlobPath: this.headBlobPath,
- });
-
- this.fetchReports();
- },
- methods: {
- ...mapActions(['setPaths', 'fetchReports', 'closeModal']),
- handleToggleEvent() {
- api.trackRedisHllUserEvent(this.$options.expandEvent);
- },
- reportText(report) {
- const { name, summary } = report || {};
-
- if (report.status === 'error') {
- return sprintf(s__('Reports|An error occurred while loading %{name} results'), { name });
- }
-
- if (!report.name) {
- return s__('Reports|An error occurred while loading report');
- }
-
- return reportTextBuilder(name, summary);
- },
- hasRecentFailures(summary) {
- return summary?.recentlyFailed > 0;
- },
- recentFailuresText(summary) {
- return recentFailuresTextBuilder(summary);
- },
- getReportIcon(report) {
- return statusIcon(report.status);
- },
- shouldRenderIssuesList(report) {
- return (
- report.existing_failures.length > 0 ||
- report.new_failures.length > 0 ||
- report.resolved_failures.length > 0 ||
- report.existing_errors.length > 0 ||
- report.new_errors.length > 0 ||
- report.resolved_errors.length > 0
- );
- },
- unresolvedIssues(report) {
- return [
- ...report.new_failures,
- ...report.new_errors,
- ...report.existing_failures,
- ...report.existing_errors,
- ];
- },
- resolvedIssues(report) {
- return report.resolved_failures.concat(report.resolved_errors);
- },
- },
- expandEvent: 'i_testing_summary_widget_total',
-};
-</script>
-<template>
- <report-section
- :status="summaryStatus"
- :success-text="groupedSummaryText"
- :loading-text="groupedSummaryText"
- :error-text="groupedSummaryText"
- :has-issues="reports.length > 0"
- :should-emit-toggle-event="true"
- class="mr-widget-section grouped-security-reports mr-report"
- @toggleEvent.once="handleToggleEvent"
- >
- <template v-if="showViewFullReport" #action-buttons>
- <gl-button
- :href="testTabURL"
- target="_blank"
- icon="external-link"
- data-testid="group-test-reports-full-link"
- class="gl-mr-3"
- >
- {{ s__('ciReport|View full report') }}
- </gl-button>
- </template>
- <template v-if="hasRecentFailures(summary)" #sub-heading>
- {{ recentFailuresText(summary) }}
- </template>
- <template #body>
- <div class="mr-widget-grouped-section report-block">
- <template v-for="(report, i) in reports">
- <summary-row
- :key="`summary-row-${i}`"
- :status-icon="getReportIcon(report)"
- nested-summary
- >
- <template #summary>
- <div class="gl-display-inline-flex gl-flex-direction-column">
- <div>{{ reportText(report) }}</div>
- <div v-if="report.suite_errors">
- <div v-if="report.suite_errors.head">
- <gl-icon name="warning" class="gl-mx-2 gl-text-orange-500" />
- {{ s__('Reports|Head report parsing error:') }}
- {{ report.suite_errors.head }}
- </div>
- <div v-if="report.suite_errors.base">
- <gl-icon name="warning" class="gl-mx-2 gl-text-orange-500" />
- {{ s__('Reports|Base report parsing error:') }}
- {{ report.suite_errors.base }}
- </div>
- </div>
- <div v-if="hasRecentFailures(report.summary)">
- {{ recentFailuresText(report.summary) }}
- </div>
- </div>
- </template>
- </summary-row>
- <grouped-issues-list
- v-if="shouldRenderIssuesList(report)"
- :key="`issues-list-${i}`"
- :unresolved-issues="unresolvedIssues(report)"
- :resolved-issues="resolvedIssues(report)"
- :component="$options.componentNames.TestIssueBody"
- :nested-level="2"
- />
- </template>
- <modal
- :visible="modalOpen"
- :title="modalTitle"
- :modal-data="modalData"
- @hide="closeModal"
- />
- </div>
- </template>
- </report-section>
-</template>
diff --git a/app/assets/javascripts/reports/grouped_test_report/store/actions.js b/app/assets/javascripts/reports/grouped_test_report/store/actions.js
deleted file mode 100644
index 73f8df016b6..00000000000
--- a/app/assets/javascripts/reports/grouped_test_report/store/actions.js
+++ /dev/null
@@ -1,82 +0,0 @@
-import Visibility from 'visibilityjs';
-import axios from '~/lib/utils/axios_utils';
-import httpStatusCodes from '~/lib/utils/http_status';
-import Poll from '~/lib/utils/poll';
-import * as types from './mutation_types';
-
-export const setPaths = ({ commit }, paths) => commit(types.SET_PATHS, paths);
-
-export const requestReports = ({ commit }) => commit(types.REQUEST_REPORTS);
-
-let eTagPoll;
-
-export const clearEtagPoll = () => {
- eTagPoll = null;
-};
-
-export const stopPolling = () => {
- if (eTagPoll) eTagPoll.stop();
-};
-
-export const restartPolling = () => {
- if (eTagPoll) eTagPoll.restart();
-};
-
-/**
- * We need to poll the reports endpoint while they are being parsed in the Backend.
- * This can take up to one minute.
- *
- * Poll.js will handle etag response.
- * While http status code is 204, it means it's parsing, and we'll keep polling
- * When http status code is 200, it means parsing is done, we can show the results & stop polling
- * When http status code is 500, it means parsing went wrong and we stop polling
- */
-export const fetchReports = ({ state, dispatch }) => {
- dispatch('requestReports');
-
- eTagPoll = new Poll({
- resource: {
- getReports(endpoint) {
- return axios.get(endpoint);
- },
- },
- data: state.endpoint,
- method: 'getReports',
- successCallback: ({ data, status }) =>
- dispatch('receiveReportsSuccess', {
- data,
- status,
- }),
- errorCallback: () => dispatch('receiveReportsError'),
- });
-
- if (!Visibility.hidden()) {
- eTagPoll.makeRequest();
- } else {
- axios
- .get(state.endpoint)
- .then(({ data, status }) => dispatch('receiveReportsSuccess', { data, status }))
- .catch(() => dispatch('receiveReportsError'));
- }
-
- Visibility.change(() => {
- if (!Visibility.hidden()) {
- dispatch('restartPolling');
- } else {
- dispatch('stopPolling');
- }
- });
-};
-
-export const receiveReportsSuccess = ({ commit }, response) => {
- // With 204 we keep polling and don't update the state
- if (response.status === httpStatusCodes.OK) {
- commit(types.RECEIVE_REPORTS_SUCCESS, response.data);
- }
-};
-
-export const receiveReportsError = ({ commit }) => commit(types.RECEIVE_REPORTS_ERROR);
-
-export const openModal = ({ commit }, payload) => commit(types.SET_ISSUE_MODAL_DATA, payload);
-
-export const closeModal = ({ commit }, payload) => commit(types.RESET_ISSUE_MODAL_DATA, payload);
diff --git a/app/assets/javascripts/reports/grouped_test_report/store/getters.js b/app/assets/javascripts/reports/grouped_test_report/store/getters.js
deleted file mode 100644
index e7d1675f74a..00000000000
--- a/app/assets/javascripts/reports/grouped_test_report/store/getters.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import { LOADING, ERROR, SUCCESS, STATUS_FAILED } from '../../constants';
-
-export const summaryStatus = (state) => {
- if (state.isLoading) {
- return LOADING;
- }
-
- if (state.hasError || state.status === STATUS_FAILED) {
- return ERROR;
- }
-
- return SUCCESS;
-};
diff --git a/app/assets/javascripts/reports/grouped_test_report/store/index.js b/app/assets/javascripts/reports/grouped_test_report/store/index.js
deleted file mode 100644
index a2edfa94a48..00000000000
--- a/app/assets/javascripts/reports/grouped_test_report/store/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import Vue from 'vue';
-import Vuex from 'vuex';
-import * as actions from './actions';
-import * as getters from './getters';
-import mutations from './mutations';
-import state from './state';
-
-Vue.use(Vuex);
-
-export const getStoreConfig = () => ({
- actions,
- mutations,
- getters,
- state: state(),
-});
-
-export default () => new Vuex.Store(getStoreConfig());
diff --git a/app/assets/javascripts/reports/grouped_test_report/store/mutation_types.js b/app/assets/javascripts/reports/grouped_test_report/store/mutation_types.js
deleted file mode 100644
index ff839c564b6..00000000000
--- a/app/assets/javascripts/reports/grouped_test_report/store/mutation_types.js
+++ /dev/null
@@ -1,7 +0,0 @@
-export const SET_PATHS = 'SET_PATHS';
-
-export const REQUEST_REPORTS = 'REQUEST_REPORTS';
-export const RECEIVE_REPORTS_SUCCESS = 'RECEIVE_REPORTS_SUCCESS';
-export const RECEIVE_REPORTS_ERROR = 'RECEIVE_REPORTS_ERROR';
-export const SET_ISSUE_MODAL_DATA = 'SET_ISSUE_MODAL_DATA';
-export const RESET_ISSUE_MODAL_DATA = 'RESET_ISSUE_MODAL_DATA';
diff --git a/app/assets/javascripts/reports/grouped_test_report/store/mutations.js b/app/assets/javascripts/reports/grouped_test_report/store/mutations.js
deleted file mode 100644
index 2b88776815b..00000000000
--- a/app/assets/javascripts/reports/grouped_test_report/store/mutations.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import * as types from './mutation_types';
-import { countRecentlyFailedTests, formatFilePath } from './utils';
-
-export default {
- [types.SET_PATHS](state, { endpoint, headBlobPath }) {
- state.endpoint = endpoint;
- state.headBlobPath = headBlobPath;
- },
- [types.REQUEST_REPORTS](state) {
- state.isLoading = true;
- },
- [types.RECEIVE_REPORTS_SUCCESS](state, response) {
- state.hasError = response.suites.some((suite) => suite.status === 'error');
-
- state.isLoading = false;
-
- state.summary.total = response.summary.total;
- state.summary.resolved = response.summary.resolved;
- state.summary.failed = response.summary.failed;
- state.summary.errored = response.summary.errored;
- state.summary.recentlyFailed = countRecentlyFailedTests(response.suites);
-
- state.status = response.status;
- state.reports = response.suites;
-
- state.reports.forEach((report, i) => {
- if (!state.reports[i].summary) return;
- state.reports[i].summary.recentlyFailed = countRecentlyFailedTests(report);
- });
- },
- [types.RECEIVE_REPORTS_ERROR](state) {
- state.isLoading = false;
- state.hasError = true;
-
- state.reports = [];
- state.summary = {
- total: 0,
- resolved: 0,
- failed: 0,
- errored: 0,
- recentlyFailed: 0,
- };
- state.status = null;
- },
- [types.SET_ISSUE_MODAL_DATA](state, payload) {
- const { issue } = payload;
- state.modal.title = issue.name;
-
- Object.keys(issue).forEach((key) => {
- if (Object.prototype.hasOwnProperty.call(state.modal.data, key)) {
- state.modal.data[key] = {
- ...state.modal.data[key],
- value: issue[key],
- };
- }
- });
-
- if (issue.file) {
- state.modal.data.filename.value = {
- text: issue.file,
- path: `${state.headBlobPath}/${formatFilePath(issue.file)}`,
- };
- }
-
- state.modal.open = true;
- },
- [types.RESET_ISSUE_MODAL_DATA](state) {
- state.modal.open = false;
-
- // Resetting modal data
- state.modal.title = null;
- Object.keys(state.modal.data).forEach((key) => {
- state.modal.data[key] = {
- ...state.modal.data[key],
- value: null,
- };
- });
- },
-};
diff --git a/app/assets/javascripts/reports/grouped_test_report/store/state.js b/app/assets/javascripts/reports/grouped_test_report/store/state.js
deleted file mode 100644
index 46909bde337..00000000000
--- a/app/assets/javascripts/reports/grouped_test_report/store/state.js
+++ /dev/null
@@ -1,71 +0,0 @@
-import { s__ } from '~/locale';
-import { fieldTypes } from '../../constants';
-
-export default () => ({
- endpoint: null,
-
- isLoading: false,
- hasError: false,
-
- status: null,
-
- summary: {
- total: 0,
- resolved: 0,
- failed: 0,
- errored: 0,
- },
-
- /**
- * Each report will have the following format:
- * {
- * name: {String},
- * summary: {
- * total: {Number},
- * resolved: {Number},
- * failed: {Number},
- * errored: {Number},
- * },
- * new_failures: {Array.<Object>},
- * resolved_failures: {Array.<Object>},
- * existing_failures: {Array.<Object>},
- * new_errors: {Array.<Object>},
- * resolved_errors: {Array.<Object>},
- * existing_errors: {Array.<Object>},
- * }
- */
- reports: [],
-
- modal: {
- title: null,
- open: false,
-
- data: {
- classname: {
- value: null,
- text: s__('Reports|Classname'),
- type: fieldTypes.text,
- },
- filename: {
- value: null,
- text: s__('Reports|Filename'),
- type: fieldTypes.link,
- },
- execution_time: {
- value: null,
- text: s__('Reports|Execution time'),
- type: fieldTypes.seconds,
- },
- failure: {
- value: null,
- text: s__('Reports|Failure'),
- type: fieldTypes.codeBlock,
- },
- system_output: {
- value: null,
- text: s__('Reports|System output'),
- type: fieldTypes.codeBlock,
- },
- },
- },
-});
diff --git a/app/assets/javascripts/reports/grouped_test_report/store/utils.js b/app/assets/javascripts/reports/grouped_test_report/store/utils.js
deleted file mode 100644
index df5dd73b66c..00000000000
--- a/app/assets/javascripts/reports/grouped_test_report/store/utils.js
+++ /dev/null
@@ -1,111 +0,0 @@
-import { sprintf, n__, s__, __ } from '~/locale';
-import {
- STATUS_FAILED,
- STATUS_SUCCESS,
- ICON_WARNING,
- ICON_SUCCESS,
- ICON_NOTFOUND,
-} from '../../constants';
-
-const textBuilder = (results) => {
- const { failed, errored, resolved, total } = results;
-
- const failedOrErrored = (failed || 0) + (errored || 0);
- const failedString = failed ? n__('%d failed', '%d failed', failed) : null;
- const erroredString = errored ? n__('%d error', '%d errors', errored) : null;
- const combinedString =
- failed && errored ? `${failedString}, ${erroredString}` : failedString || erroredString;
- const resolvedString = resolved
- ? n__('%d fixed test result', '%d fixed test results', resolved)
- : null;
- const totalString = total ? n__('out of %d total test', 'out of %d total tests', total) : null;
-
- let resultsString = s__('Reports|no changed test results');
-
- if (failedOrErrored) {
- if (resolved) {
- resultsString = sprintf(s__('Reports|%{combinedString} and %{resolvedString}'), {
- combinedString,
- resolvedString,
- });
- } else {
- resultsString = combinedString;
- }
- } else if (resolved) {
- resultsString = resolvedString;
- }
-
- return `${resultsString} ${totalString}`;
-};
-
-export const summaryTextBuilder = (name = '', results = {}) => {
- const resultsString = textBuilder(results);
- return sprintf(__('%{name} contained %{resultsString}'), { name, resultsString });
-};
-
-export const reportTextBuilder = (name = '', results = {}) => {
- const resultsString = textBuilder(results);
- return sprintf(__('%{name} found %{resultsString}'), { name, resultsString });
-};
-
-export const recentFailuresTextBuilder = (summary = {}) => {
- const { failed, recentlyFailed } = summary;
- if (!failed || !recentlyFailed) return '';
-
- if (failed < 2) {
- return sprintf(
- s__(
- 'Reports|%{recentlyFailed} out of %{failed} failed test has failed more than once in the last 14 days',
- ),
- { recentlyFailed, failed },
- );
- }
- return sprintf(
- n__(
- 'Reports|%{recentlyFailed} out of %{failed} failed tests has failed more than once in the last 14 days',
- 'Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days',
- recentlyFailed,
- ),
- { recentlyFailed, failed },
- );
-};
-
-export const countRecentlyFailedTests = (subject) => {
- // handle either a single report or an array of reports
- const reports = !subject.length ? [subject] : subject;
-
- return reports
- .map((report) => {
- return (
- [report.new_failures, report.existing_failures, report.resolved_failures]
- // only count tests which have failed more than once
- .map(
- (failureArray) =>
- failureArray.filter((failure) => failure.recent_failures?.count > 1).length,
- )
- .reduce((total, count) => total + count, 0)
- );
- })
- .reduce((total, count) => total + count, 0);
-};
-
-export const statusIcon = (status) => {
- if (status === STATUS_FAILED) {
- return ICON_WARNING;
- }
-
- if (status === STATUS_SUCCESS) {
- return ICON_SUCCESS;
- }
-
- return ICON_NOTFOUND;
-};
-
-/**
- * Removes `./` from the beginning of a file path so it can be appended onto a blob path
- * @param {String} file
- * @returns {String} - formatted value
- */
-export const formatFilePath = (file) => {
- return file.replace(/^\.?\/*/, '');
-};
diff --git a/app/assets/javascripts/repository/components/blob_content_viewer.vue b/app/assets/javascripts/repository/components/blob_content_viewer.vue
index bf1667d8734..101625a4b72 100644
--- a/app/assets/javascripts/repository/components/blob_content_viewer.vue
+++ b/app/assets/javascripts/repository/components/blob_content_viewer.vue
@@ -14,7 +14,7 @@ import WebIdeLink from '~/vue_shared/components/web_ide_link.vue';
import CodeIntelligence from '~/code_navigation/components/app.vue';
import LineHighlighter from '~/blob/line_highlighter';
import blobInfoQuery from 'shared_queries/repository/blob_info.query.graphql';
-import addBlameLink from '~/blob/blob_blame_link';
+import { addBlameLink } from '~/blob/blob_blame_link';
import projectInfoQuery from '../queries/project_info.query.graphql';
import getRefMixin from '../mixins/get_ref';
import userInfoQuery from '../queries/user_info.query.graphql';
diff --git a/app/assets/javascripts/repository/constants.js b/app/assets/javascripts/repository/constants.js
index 77d3a517d28..3a6d7d2f779 100644
--- a/app/assets/javascripts/repository/constants.js
+++ b/app/assets/javascripts/repository/constants.js
@@ -93,13 +93,9 @@ export const LFS_STORAGE = 'lfs';
* These are file types that we want the legacy (backend) syntax highlighter to highlight.
*/
export const LEGACY_FILE_TYPES = [
- 'gemfile',
- 'composer_json',
'podfile',
'podspec',
- 'podspec_json',
'cartfile',
- 'godeps_json',
'requirements_txt',
'cargo_toml',
'go_mod',
diff --git a/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue b/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue
deleted file mode 100644
index dbaabb35cde..00000000000
--- a/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue
+++ /dev/null
@@ -1,233 +0,0 @@
-<script>
-import { GlLink } from '@gitlab/ui';
-import { createAlert } from '~/flash';
-import { updateHistory } from '~/lib/utils/url_utility';
-import { fetchPolicies } from '~/lib/graphql';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import { upgradeStatusTokenConfig } from 'ee_else_ce/runner/components/search_tokens/upgrade_status_token_config';
-import {
- fromUrlQueryToSearch,
- fromSearchToUrl,
- fromSearchToVariables,
- isSearchFiltered,
-} from 'ee_else_ce/runner/runner_search_utils';
-import allRunnersQuery from 'ee_else_ce/runner/graphql/list/all_runners.query.graphql';
-import allRunnersCountQuery from 'ee_else_ce/runner/graphql/list/all_runners_count.query.graphql';
-
-import RegistrationDropdown from '../components/registration/registration_dropdown.vue';
-import RunnerStackedLayoutBanner from '../components/runner_stacked_layout_banner.vue';
-import RunnerFilteredSearchBar from '../components/runner_filtered_search_bar.vue';
-import RunnerList from '../components/runner_list.vue';
-import RunnerListEmptyState from '../components/runner_list_empty_state.vue';
-import RunnerName from '../components/runner_name.vue';
-import RunnerStats from '../components/stat/runner_stats.vue';
-import RunnerPagination from '../components/runner_pagination.vue';
-import RunnerTypeTabs from '../components/runner_type_tabs.vue';
-import RunnerActionsCell from '../components/cells/runner_actions_cell.vue';
-
-import { pausedTokenConfig } from '../components/search_tokens/paused_token_config';
-import { statusTokenConfig } from '../components/search_tokens/status_token_config';
-import { tagTokenConfig } from '../components/search_tokens/tag_token_config';
-import {
- ADMIN_FILTERED_SEARCH_NAMESPACE,
- INSTANCE_TYPE,
- I18N_FETCH_ERROR,
- FILTER_CSS_CLASSES,
-} from '../constants';
-import { captureException } from '../sentry_utils';
-
-export default {
- name: 'AdminRunnersApp',
- components: {
- GlLink,
- RegistrationDropdown,
- RunnerStackedLayoutBanner,
- RunnerFilteredSearchBar,
- RunnerList,
- RunnerListEmptyState,
- RunnerName,
- RunnerStats,
- RunnerPagination,
- RunnerTypeTabs,
- RunnerActionsCell,
- },
- mixins: [glFeatureFlagMixin()],
- inject: ['emptyStateSvgPath', 'emptyStateFilteredSvgPath'],
- props: {
- registrationToken: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- search: fromUrlQueryToSearch(),
- runners: {
- items: [],
- pageInfo: {},
- },
- };
- },
- apollo: {
- runners: {
- query: allRunnersQuery,
- fetchPolicy: fetchPolicies.NETWORK_ONLY,
- variables() {
- return this.variables;
- },
- update(data) {
- const { runners } = data;
- return {
- items: runners?.nodes || [],
- pageInfo: runners?.pageInfo || {},
- };
- },
- error(error) {
- createAlert({ message: I18N_FETCH_ERROR });
-
- this.reportToSentry(error);
- },
- },
- },
- computed: {
- variables() {
- return fromSearchToVariables(this.search);
- },
- countVariables() {
- // Exclude pagination variables, leave only filters variables
- const { sort, before, last, after, first, ...countVariables } = this.variables;
- return countVariables;
- },
- runnersLoading() {
- return this.$apollo.queries.runners.loading;
- },
- noRunnersFound() {
- return !this.runnersLoading && !this.runners.items.length;
- },
- searchTokens() {
- return [
- pausedTokenConfig,
- statusTokenConfig,
- {
- ...tagTokenConfig,
- recentSuggestionsStorageKey: `${this.$options.filteredSearchNamespace}-recent-tags`,
- },
- upgradeStatusTokenConfig,
- ];
- },
- isSearchFiltered() {
- return isSearchFiltered(this.search);
- },
- },
- watch: {
- search: {
- deep: true,
- handler() {
- // TODO Implement back button response using onpopstate
- // See: https://gitlab.com/gitlab-org/gitlab/-/issues/333804
- updateHistory({
- url: fromSearchToUrl(this.search),
- title: document.title,
- });
- },
- },
- },
- errorCaptured(error) {
- this.reportToSentry(error);
- },
- methods: {
- onToggledPaused() {
- // When a runner becomes Paused, the tab count can
- // become stale, refetch outdated counts.
- this.refetchCounts();
- },
- onDeleted({ message }) {
- this.refetchCounts();
- this.$root.$toast?.show(message);
- },
- refetchCounts() {
- this.$apollo.getClient().refetchQueries({ include: [allRunnersCountQuery] });
- },
- reportToSentry(error) {
- captureException({ error, component: this.$options.name });
- },
- onPaginationInput(value) {
- this.search.pagination = value;
- },
- },
- filteredSearchNamespace: ADMIN_FILTERED_SEARCH_NAMESPACE,
- INSTANCE_TYPE,
- FILTER_CSS_CLASSES,
-};
-</script>
-<template>
- <div>
- <runner-stacked-layout-banner />
-
- <div
- class="gl-display-flex gl-align-items-center gl-flex-direction-column-reverse gl-md-flex-direction-row gl-mt-3 gl-md-mt-0"
- >
- <runner-type-tabs
- v-model="search"
- :count-scope="$options.INSTANCE_TYPE"
- :count-variables="countVariables"
- class="gl-w-full"
- content-class="gl-display-none"
- nav-class="gl-border-none!"
- />
-
- <registration-dropdown
- class="gl-w-full gl-sm-w-auto gl-mr-auto"
- :registration-token="registrationToken"
- :type="$options.INSTANCE_TYPE"
- right
- />
- </div>
-
- <runner-filtered-search-bar
- v-model="search"
- :class="$options.FILTER_CSS_CLASSES"
- :tokens="searchTokens"
- :namespace="$options.filteredSearchNamespace"
- />
-
- <runner-stats :scope="$options.INSTANCE_TYPE" :variables="countVariables" />
-
- <runner-list-empty-state
- v-if="noRunnersFound"
- :registration-token="registrationToken"
- :is-search-filtered="isSearchFiltered"
- :svg-path="emptyStateSvgPath"
- :filtered-svg-path="emptyStateFilteredSvgPath"
- />
- <template v-else>
- <runner-list
- :runners="runners.items"
- :loading="runnersLoading"
- :checkable="true"
- @deleted="onDeleted"
- >
- <template #runner-name="{ runner }">
- <gl-link :href="runner.adminUrl">
- <runner-name :runner="runner" />
- </gl-link>
- </template>
- <template #runner-actions-cell="{ runner }">
- <runner-actions-cell
- :runner="runner"
- :edit-url="runner.editAdminUrl"
- @toggledPaused="onToggledPaused"
- @deleted="onDeleted"
- />
- </template>
- </runner-list>
- </template>
-
- <runner-pagination
- class="gl-mt-3"
- :disabled="runnersLoading"
- :page-info="runners.pageInfo"
- @input="onPaginationInput"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/runner/admin_runners/index.js b/app/assets/javascripts/runner/admin_runners/index.js
deleted file mode 100644
index 7bb6cd5689e..00000000000
--- a/app/assets/javascripts/runner/admin_runners/index.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import { GlToast } from '@gitlab/ui';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import { visitUrl } from '~/lib/utils/url_utility';
-import { updateOutdatedUrl } from '~/runner/runner_search_utils';
-import createDefaultClient from '~/lib/graphql';
-import { createLocalState } from '../graphql/list/local_state';
-import { showAlertFromLocalStorage } from '../local_storage_alert/show_alert_from_local_storage';
-import AdminRunnersApp from './admin_runners_app.vue';
-
-Vue.use(GlToast);
-Vue.use(VueApollo);
-
-export const initAdminRunners = (selector = '#js-admin-runners') => {
- showAlertFromLocalStorage();
-
- const el = document.querySelector(selector);
-
- if (!el) {
- return null;
- }
-
- // Redirect outdated URLs
- const updatedUrlQuery = updateOutdatedUrl();
- if (updatedUrlQuery) {
- visitUrl(updatedUrlQuery);
-
- // Prevent mounting the rest of the app, redirecting now.
- return null;
- }
-
- const {
- runnerInstallHelpPage,
- registrationToken,
- onlineContactTimeoutSecs,
- staleTimeoutSecs,
- emptyStateSvgPath,
- emptyStateFilteredSvgPath,
- } = el.dataset;
-
- const { cacheConfig, typeDefs, localMutations } = createLocalState();
-
- const apolloProvider = new VueApollo({
- defaultClient: createDefaultClient({}, { cacheConfig, typeDefs }),
- });
-
- return new Vue({
- el,
- apolloProvider,
- provide: {
- runnerInstallHelpPage,
- localMutations,
- onlineContactTimeoutSecs,
- staleTimeoutSecs,
- emptyStateSvgPath,
- emptyStateFilteredSvgPath,
- },
- render(h) {
- return h(AdminRunnersApp, {
- props: {
- registrationToken,
- },
- });
- },
- });
-};
diff --git a/app/assets/javascripts/runner/components/cells/runner_stacked_summary_cell.vue b/app/assets/javascripts/runner/components/cells/runner_stacked_summary_cell.vue
deleted file mode 100644
index e5d49eb7c8e..00000000000
--- a/app/assets/javascripts/runner/components/cells/runner_stacked_summary_cell.vue
+++ /dev/null
@@ -1,112 +0,0 @@
-<script>
-import { GlIcon, GlSprintf, GlTooltipDirective } from '@gitlab/ui';
-
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
-import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
-import RunnerName from '../runner_name.vue';
-import RunnerTags from '../runner_tags.vue';
-import RunnerTypeBadge from '../runner_type_badge.vue';
-
-import { formatJobCount } from '../../utils';
-import {
- I18N_LOCKED_RUNNER_DESCRIPTION,
- I18N_VERSION_LABEL,
- I18N_LAST_CONTACT_LABEL,
- I18N_CREATED_AT_LABEL,
-} from '../../constants';
-import RunnerSummaryField from './runner_summary_field.vue';
-
-export default {
- components: {
- GlIcon,
- GlSprintf,
- TimeAgo,
- RunnerSummaryField,
- RunnerName,
- RunnerTags,
- RunnerTypeBadge,
- RunnerUpgradeStatusIcon: () =>
- import('ee_component/runner/components/runner_upgrade_status_icon.vue'),
- TooltipOnTruncate,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- runner: {
- type: Object,
- required: true,
- },
- },
- computed: {
- jobCount() {
- return formatJobCount(this.runner.jobCount);
- },
- },
- i18n: {
- I18N_LOCKED_RUNNER_DESCRIPTION,
- I18N_VERSION_LABEL,
- I18N_LAST_CONTACT_LABEL,
- I18N_CREATED_AT_LABEL,
- },
-};
-</script>
-
-<template>
- <div>
- <div>
- <slot :runner="runner" name="runner-name">
- <runner-name :runner="runner" />
- </slot>
- <gl-icon
- v-if="runner.locked"
- v-gl-tooltip
- :title="$options.i18n.I18N_LOCKED_RUNNER_DESCRIPTION"
- name="lock"
- />
- <runner-type-badge :type="runner.runnerType" size="sm" class="gl-vertical-align-middle" />
- </div>
-
- <div class="gl-ml-auto gl-display-inline-flex gl-max-w-full gl-py-2">
- <div class="gl-flex-shrink-0">
- <runner-upgrade-status-icon :runner="runner" />
- <gl-sprintf v-if="runner.version" :message="$options.i18n.I18N_VERSION_LABEL">
- <template #version>{{ runner.version }}</template>
- </gl-sprintf>
- </div>
- <div class="gl-text-secondary gl-mx-2" aria-hidden="true">·</div>
- <tooltip-on-truncate class="gl-text-truncate gl-display-block" :title="runner.description">
- {{ runner.description }}
- </tooltip-on-truncate>
- </div>
-
- <div>
- <runner-summary-field icon="clock">
- <gl-sprintf :message="$options.i18n.I18N_LAST_CONTACT_LABEL">
- <template #timeAgo>
- <time-ago v-if="runner.contactedAt" :time="runner.contactedAt" />
- <template v-else>{{ __('Never') }}</template>
- </template>
- </gl-sprintf>
- </runner-summary-field>
-
- <runner-summary-field v-if="runner.ipAddress" icon="disk" :tooltip="__('IP Address')">
- {{ runner.ipAddress }}
- </runner-summary-field>
-
- <runner-summary-field icon="pipeline" data-testid="job-count" :tooltip="__('Jobs')">
- {{ jobCount }}
- </runner-summary-field>
-
- <runner-summary-field icon="calendar">
- <gl-sprintf :message="$options.i18n.I18N_CREATED_AT_LABEL">
- <template #timeAgo>
- <time-ago v-if="runner.createdAt" :time="runner.createdAt" />
- </template>
- </gl-sprintf>
- </runner-summary-field>
- </div>
-
- <runner-tags class="gl-display-block gl-pt-2" :tag-list="runner.tagList" size="sm" />
- </div>
-</template>
diff --git a/app/assets/javascripts/runner/components/cells/runner_status_cell.vue b/app/assets/javascripts/runner/components/cells/runner_status_cell.vue
deleted file mode 100644
index eb98d4ae2fb..00000000000
--- a/app/assets/javascripts/runner/components/cells/runner_status_cell.vue
+++ /dev/null
@@ -1,46 +0,0 @@
-<script>
-import { GlTooltipDirective } from '@gitlab/ui';
-
-import RunnerStatusBadge from '../runner_status_badge.vue';
-import RunnerPausedBadge from '../runner_paused_badge.vue';
-
-export default {
- components: {
- RunnerStatusBadge,
- RunnerUpgradeStatusBadge: () =>
- import('ee_component/runner/components/runner_upgrade_status_badge.vue'),
- RunnerPausedBadge,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- runner: {
- type: Object,
- required: true,
- },
- },
- computed: {
- paused() {
- return !this.runner.active;
- },
- },
-};
-</script>
-
-<template>
- <div>
- <runner-status-badge
- :runner="runner"
- class="gl-display-inline-block gl-max-w-full gl-text-truncate"
- />
- <runner-upgrade-status-badge
- :runner="runner"
- class="gl-display-inline-block gl-max-w-full gl-text-truncate"
- />
- <runner-paused-badge
- v-if="paused"
- class="gl-display-inline-block gl-max-w-full gl-text-truncate"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/runner/components/registration/registration_token_reset_dropdown_item.vue b/app/assets/javascripts/runner/components/registration/registration_token_reset_dropdown_item.vue
deleted file mode 100644
index 667cb0090b3..00000000000
--- a/app/assets/javascripts/runner/components/registration/registration_token_reset_dropdown_item.vue
+++ /dev/null
@@ -1,141 +0,0 @@
-<script>
-import { GlDropdownItem, GlLoadingIcon, GlModal, GlModalDirective } from '@gitlab/ui';
-import { createAlert } from '~/flash';
-import { TYPE_GROUP, TYPE_PROJECT } from '~/graphql_shared/constants';
-import { convertToGraphQLId } from '~/graphql_shared/utils';
-import { __, s__ } from '~/locale';
-import runnersRegistrationTokenResetMutation from '~/runner/graphql/list/runners_registration_token_reset.mutation.graphql';
-import { captureException } from '~/runner/sentry_utils';
-import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '../../constants';
-
-const i18n = {
- modalAction: s__('Runners|Reset token'),
- modalCancel: __('Cancel'),
- modalCopy: __('Are you sure you want to reset the registration token?'),
- modalTitle: __('Reset registration token'),
-};
-
-export default {
- name: 'RunnerRegistrationTokenReset',
- i18n,
- components: {
- GlDropdownItem,
- GlLoadingIcon,
- GlModal,
- },
- directives: {
- GlModal: GlModalDirective,
- },
- inject: {
- groupId: {
- default: null,
- },
- projectId: {
- default: null,
- },
- },
- modalId: 'token-reset-modal',
- props: {
- type: {
- type: String,
- required: true,
- validator(type) {
- return [INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE].includes(type);
- },
- },
- },
- data() {
- return {
- loading: false,
- };
- },
- computed: {
- resetTokenInput() {
- switch (this.type) {
- case INSTANCE_TYPE:
- return {
- type: this.type,
- };
- case GROUP_TYPE:
- return {
- id: convertToGraphQLId(TYPE_GROUP, this.groupId),
- type: this.type,
- };
- case PROJECT_TYPE:
- return {
- id: convertToGraphQLId(TYPE_PROJECT, this.projectId),
- type: this.type,
- };
- default:
- return null;
- }
- },
- actionPrimary() {
- return {
- text: i18n.modalAction,
- attributes: [{ variant: 'danger' }],
- };
- },
- actionSecondary() {
- return {
- text: i18n.modalCancel,
- attributes: [{ variant: 'default' }],
- };
- },
- },
- methods: {
- handleModalPrimary() {
- this.resetToken();
- },
- async resetToken() {
- this.loading = true;
- try {
- const {
- data: {
- runnersRegistrationTokenReset: { token, errors },
- },
- } = await this.$apollo.mutate({
- mutation: runnersRegistrationTokenResetMutation,
- variables: {
- input: this.resetTokenInput,
- },
- });
- if (errors && errors.length) {
- throw new Error(errors.join(' '));
- }
- this.onSuccess(token);
- } catch (e) {
- this.onError(e);
- } finally {
- this.loading = false;
- }
- },
- onError(error) {
- const { message } = error;
-
- createAlert({ message });
- captureException({ error, component: this.$options.name });
- },
- onSuccess(token) {
- this.$toast?.show(s__('Runners|New registration token generated!'));
- this.$emit('tokenReset', token);
- },
- },
-};
-</script>
-<template>
- <gl-dropdown-item v-gl-modal="$options.modalId">
- {{ __('Reset registration token') }}
- <gl-modal
- size="sm"
- :modal-id="$options.modalId"
- :action-primary="actionPrimary"
- :action-secondary="actionSecondary"
- :title="$options.i18n.modalTitle"
- @primary="handleModalPrimary"
- >
- <p>{{ $options.i18n.modalCopy }}</p>
- </gl-modal>
- <gl-loading-icon v-if="loading" inline />
- </gl-dropdown-item>
-</template>
diff --git a/app/assets/javascripts/runner/components/runner_bulk_delete.vue b/app/assets/javascripts/runner/components/runner_bulk_delete.vue
deleted file mode 100644
index 703da01d9c8..00000000000
--- a/app/assets/javascripts/runner/components/runner_bulk_delete.vue
+++ /dev/null
@@ -1,196 +0,0 @@
-<script>
-import { GlButton, GlModalDirective, GlModal, GlSprintf } from '@gitlab/ui';
-import { createAlert } from '~/flash';
-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';
-import { RUNNER_TYPENAME } from '../constants';
-
-export default {
- components: {
- GlButton,
- GlModal,
- GlSprintf,
- },
- directives: {
- GlModal: GlModalDirective,
- },
- inject: ['localMutations'],
- props: {
- runners: {
- type: Array,
- default: () => [],
- required: false,
- },
- },
- data() {
- return {
- isDeleting: false,
- checkedRunnerIds: [],
- };
- },
- apollo: {
- checkedRunnerIds: {
- query: checkedRunnerIdsQuery,
- },
- },
- computed: {
- currentCheckedRunnerIds() {
- return this.runners
- .map(({ id }) => id)
- .filter((id) => this.checkedRunnerIds.indexOf(id) >= 0);
- },
- checkedCount() {
- return this.currentCheckedRunnerIds.length || 0;
- },
- bannerMessage() {
- return sprintf(
- n__(
- 'Runners|%{strongStart}%{count}%{strongEnd} runner selected',
- 'Runners|%{strongStart}%{count}%{strongEnd} runners selected',
- this.checkedCount,
- ),
- {
- count: this.checkedCount,
- },
- );
- },
- modalTitle() {
- return n__('Runners|Delete %d runner', 'Runners|Delete %d runners', this.checkedCount);
- },
- modalActionPrimary() {
- return {
- text: n__(
- 'Runners|Permanently delete %d runner',
- 'Runners|Permanently delete %d runners',
- this.checkedCount,
- ),
- attributes: {
- loading: this.isDeleting,
- variant: 'danger',
- },
- };
- },
- modalActionCancel() {
- return {
- text: __('Cancel'),
- attributes: {
- loading: this.isDeleting,
- },
- };
- },
- modalMessage() {
- return sprintf(
- n__(
- 'Runners|%{strongStart}%{count}%{strongEnd} runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?',
- 'Runners|%{strongStart}%{count}%{strongEnd} runners will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?',
- this.checkedCount,
- ),
- { count: this.checkedCount },
- );
- },
- },
- methods: {
- toastConfirmationMessage(deletedCount) {
- return n__(
- 'Runners|%d selected runner deleted',
- 'Runners|%d selected runners deleted',
- deletedCount,
- );
- },
- onClearChecked() {
- this.localMutations.clearChecked();
- },
- async onConfirmDelete(e) {
- this.isDeleting = true;
- e.preventDefault(); // don't close modal until deletion is complete
-
- try {
- await this.$apollo.mutate({
- mutation: BulkRunnerDelete,
- variables: {
- input: {
- ids: this.currentCheckedRunnerIds,
- },
- },
- update: (cache, { data }) => {
- const { errors, deletedIds } = data.bulkRunnerDelete;
-
- if (errors?.length) {
- this.onError(new Error(errors.join(' ')));
- this.$refs.modal.hide();
- return;
- }
-
- this.$emit('deleted', {
- message: this.toastConfirmationMessage(deletedIds.length),
- });
-
- // Clean up
-
- // Remove deleted runners from the cache
- deletedIds.forEach((id) => {
- const cacheId = cache.identify({ __typename: RUNNER_TYPENAME, id });
- cache.evict({ id: cacheId });
- });
- cache.gc();
-
- this.$refs.modal.hide();
- },
- });
- } catch (error) {
- this.onError(error);
- } finally {
- this.isDeleting = false;
- }
- },
- onError(error) {
- createAlert({
- message: s__(
- 'Runners|Something went wrong while deleting. Please refresh the page to try again.',
- ),
- captureError: true,
- error,
- });
- },
- },
- BULK_DELETE_MODAL_ID: 'bulk-delete-modal',
-};
-</script>
-
-<template>
- <div v-if="checkedCount" 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="bannerMessage">
- <template #strong="{ content }">
- <strong>{{ content }}</strong>
- </template>
- </gl-sprintf>
- </div>
- <div class="gl-ml-auto">
- <gl-button variant="default" @click="onClearChecked">{{
- s__('Runners|Clear selection')
- }}</gl-button>
- <gl-button v-gl-modal="$options.BULK_DELETE_MODAL_ID" variant="danger">{{
- s__('Runners|Delete selected')
- }}</gl-button>
- </div>
- </div>
- <gl-modal
- ref="modal"
- size="sm"
- :modal-id="$options.BULK_DELETE_MODAL_ID"
- :title="modalTitle"
- :action-primary="modalActionPrimary"
- :action-cancel="modalActionCancel"
- @primary="onConfirmDelete"
- >
- <gl-sprintf :message="modalMessage">
- <template #strong="{ content }">
- <strong>{{ content }}</strong>
- </template>
- </gl-sprintf>
- </gl-modal>
- </div>
-</template>
diff --git a/app/assets/javascripts/runner/components/runner_delete_button.vue b/app/assets/javascripts/runner/components/runner_delete_button.vue
deleted file mode 100644
index b4f022a7d14..00000000000
--- a/app/assets/javascripts/runner/components/runner_delete_button.vue
+++ /dev/null
@@ -1,153 +0,0 @@
-<script>
-import { GlButton, GlModalDirective, GlTooltipDirective } from '@gitlab/ui';
-import runnerDeleteMutation from '~/runner/graphql/shared/runner_delete.mutation.graphql';
-import { createAlert } from '~/flash';
-import { sprintf } from '~/locale';
-import { captureException } from '~/runner/sentry_utils';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { I18N_DELETE_RUNNER, I18N_DELETED_TOAST } from '../constants';
-import RunnerDeleteModal from './runner_delete_modal.vue';
-
-export default {
- name: 'RunnerDeleteButton',
- components: {
- GlButton,
- RunnerDeleteModal,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- GlModal: GlModalDirective,
- },
- props: {
- runner: {
- type: Object,
- required: true,
- validator: (runner) => {
- return runner?.id && runner?.shortSha;
- },
- },
- compact: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- emits: ['deleted'],
- data() {
- return {
- deleting: false,
- };
- },
- computed: {
- runnerId() {
- return getIdFromGraphQLId(this.runner.id);
- },
- runnerName() {
- return `#${this.runnerId} (${this.runner.shortSha})`;
- },
- runnerDeleteModalId() {
- return `delete-runner-modal-${this.runnerId}`;
- },
- icon() {
- if (this.compact) {
- return 'close';
- }
- return '';
- },
- buttonContent() {
- if (this.compact) {
- return null;
- }
- return I18N_DELETE_RUNNER;
- },
- buttonClass() {
- // Ensure a square button is shown when compact: true.
- // Without this class we will have distorted/rectangular button.
- if (this.compact) {
- return 'btn-icon';
- }
- return null;
- },
- ariaLabel() {
- if (this.compact) {
- return I18N_DELETE_RUNNER;
- }
- return null;
- },
- tooltip() {
- // Only show basic "delete" tooltip when compact.
- // Also prevent a "sticky" tooltip: If this button is
- // loading, mouseout listeners don't run leaving the tooltip stuck
- if (this.compact && !this.deleting) {
- return I18N_DELETE_RUNNER;
- }
- return '';
- },
- },
- methods: {
- async onDelete() {
- // Deleting stays "true" until this row is removed,
- // should only change back if the operation fails.
- this.deleting = true;
- try {
- await this.$apollo.mutate({
- mutation: runnerDeleteMutation,
- variables: {
- input: {
- id: this.runner.id,
- },
- },
- update: (cache, { data }) => {
- const { errors } = data.runnerDelete;
-
- if (errors?.length) {
- this.onError(new Error(errors.join(' ')));
- return;
- }
-
- this.$emit('deleted', {
- message: sprintf(I18N_DELETED_TOAST, { name: this.runnerName }),
- });
-
- // Remove deleted runner from the cache
- const cacheId = cache.identify(this.runner);
- cache.evict({ id: cacheId });
- cache.gc();
- },
- });
- } catch (e) {
- this.onError(e);
- }
- },
- onError(error) {
- this.deleting = false;
- const { message } = error;
-
- createAlert({ message });
- captureException({ error, component: this.$options.name });
- },
- },
-};
-</script>
-
-<template>
- <div v-gl-tooltip="tooltip" class="btn-group">
- <gl-button
- v-gl-modal="runnerDeleteModalId"
- :aria-label="ariaLabel"
- :icon="icon"
- :class="buttonClass"
- :loading="deleting"
- variant="danger"
- category="secondary"
- v-bind="$attrs"
- >
- {{ buttonContent }}
- </gl-button>
- <runner-delete-modal
- :modal-id="runnerDeleteModalId"
- :runner-name="runnerName"
- @primary="onDelete"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/runner/components/runner_details.vue b/app/assets/javascripts/runner/components/runner_details.vue
deleted file mode 100644
index 3d72abcd393..00000000000
--- a/app/assets/javascripts/runner/components/runner_details.vue
+++ /dev/null
@@ -1,159 +0,0 @@
-<script>
-import { GlIntersperse, GlLink } from '@gitlab/ui';
-import { helpPagePath } from '~/helpers/help_page_helper';
-import { s__ } from '~/locale';
-import HelpPopover from '~/vue_shared/components/help_popover.vue';
-import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
-import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
-import { ACCESS_LEVEL_REF_PROTECTED, GROUP_TYPE, PROJECT_TYPE } from '../constants';
-import RunnerDetail from './runner_detail.vue';
-import RunnerGroups from './runner_groups.vue';
-import RunnerProjects from './runner_projects.vue';
-import RunnerTags from './runner_tags.vue';
-
-export default {
- components: {
- GlIntersperse,
- GlLink,
- HelpPopover,
- RunnerDetail,
- RunnerMaintenanceNoteDetail: () =>
- import('ee_component/runner/components/runner_maintenance_note_detail.vue'),
- RunnerGroups,
- RunnerProjects,
- RunnerUpgradeStatusBadge: () =>
- import('ee_component/runner/components/runner_upgrade_status_badge.vue'),
- RunnerUpgradeStatusAlert: () =>
- import('ee_component/runner/components/runner_upgrade_status_alert.vue'),
- RunnerTags,
- TimeAgo,
- },
- props: {
- runner: {
- type: Object,
- required: false,
- default: null,
- },
- },
- computed: {
- maximumTimeout() {
- const { maximumTimeout } = this.runner;
- if (typeof maximumTimeout !== 'number') {
- return null;
- }
- return timeIntervalInWords(maximumTimeout);
- },
- configTextProtected() {
- if (this.runner.accessLevel === ACCESS_LEVEL_REF_PROTECTED) {
- return s__('Runners|Protected');
- }
- return null;
- },
- configTextUntagged() {
- if (this.runner.runUntagged) {
- return s__('Runners|Runs untagged jobs');
- }
- return null;
- },
- tagList() {
- return this.runner.tagList || [];
- },
- isGroupRunner() {
- return this.runner?.runnerType === GROUP_TYPE;
- },
- isProjectRunner() {
- return this.runner?.runnerType === PROJECT_TYPE;
- },
- tokenExpirationHelpPopoverOptions() {
- return {
- title: s__('Runners|Runner authentication token expiration'),
- };
- },
- tokenExpirationHelpUrl() {
- return helpPagePath('ci/runners/configure_runners', {
- anchor: 'authentication-token-security',
- });
- },
- },
- ACCESS_LEVEL_REF_PROTECTED,
-};
-</script>
-
-<template>
- <div>
- <runner-upgrade-status-alert class="gl-my-4" :runner="runner" />
- <div class="gl-pt-4">
- <dl
- class="gl-mb-0 gl-display-grid runner-details-grid-template"
- data-testid="runner-details-list"
- >
- <runner-detail :label="s__('Runners|Description')" :value="runner.description" />
- <runner-detail
- :label="s__('Runners|Last contact')"
- :empty-value="s__('Runners|Never contacted')"
- >
- <template v-if="runner.contactedAt" #value>
- <time-ago :time="runner.contactedAt" />
- </template>
- </runner-detail>
- <runner-detail :label="s__('Runners|Version')">
- <template v-if="runner.version" #value>
- {{ runner.version }}
- <runner-upgrade-status-badge size="sm" :runner="runner" />
- </template>
- </runner-detail>
- <runner-detail :label="s__('Runners|IP Address')" :value="runner.ipAddress" />
- <runner-detail :label="s__('Runners|Executor')" :value="runner.executorName" />
- <runner-detail :label="s__('Runners|Architecture')" :value="runner.architectureName" />
- <runner-detail :label="s__('Runners|Platform')" :value="runner.platformName" />
- <runner-detail :label="s__('Runners|Configuration')">
- <template v-if="configTextProtected || configTextUntagged" #value>
- <gl-intersperse>
- <span v-if="configTextProtected">{{ configTextProtected }}</span>
- <span v-if="configTextUntagged">{{ configTextUntagged }}</span>
- </gl-intersperse>
- </template>
- </runner-detail>
- <runner-detail :label="s__('Runners|Maximum job timeout')" :value="maximumTimeout" />
- <runner-detail :empty-value="s__('Runners|Never expires')">
- <template #label>
- {{ s__('Runners|Token expiry') }}
- <help-popover :options="tokenExpirationHelpPopoverOptions">
- <p>
- {{
- s__(
- 'Runners|Runner authentication tokens will expire based on a set interval. They will automatically rotate once expired.',
- )
- }}
- </p>
- <p class="gl-mb-0">
- <gl-link
- :href="tokenExpirationHelpUrl"
- target="_blank"
- class="gl-reset-font-size"
- >{{ __('Learn more') }}</gl-link
- >
- </p>
- </help-popover>
- </template>
- <template v-if="runner.tokenExpiresAt" #value>
- <time-ago :time="runner.tokenExpiresAt" />
- </template>
- </runner-detail>
- <runner-detail :label="s__('Runners|Tags')">
- <template v-if="tagList.length" #value>
- <runner-tags class="gl-vertical-align-middle" :tag-list="tagList" size="sm" />
- </template>
- </runner-detail>
-
- <runner-maintenance-note-detail
- class="gl-pt-4 gl-border-t-gray-100 gl-border-t-1 gl-border-t-solid"
- :value="runner.maintenanceNoteHtml"
- />
- </dl>
- </div>
-
- <runner-groups v-if="isGroupRunner" :runner="runner" />
- <runner-projects v-if="isProjectRunner" :runner="runner" />
- </div>
-</template>
diff --git a/app/assets/javascripts/runner/components/runner_filtered_search_bar.vue b/app/assets/javascripts/runner/components/runner_filtered_search_bar.vue
deleted file mode 100644
index da59de9a9eb..00000000000
--- a/app/assets/javascripts/runner/components/runner_filtered_search_bar.vue
+++ /dev/null
@@ -1,100 +0,0 @@
-<script>
-import { cloneDeep } from 'lodash';
-import { __ } from '~/locale';
-import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
-import { searchValidator } from '~/runner/runner_search_utils';
-import { CREATED_DESC, CREATED_ASC, CONTACTED_DESC, CONTACTED_ASC } from '../constants';
-
-const sortOptions = [
- {
- id: 1,
- title: __('Created date'),
- sortDirection: {
- descending: CREATED_DESC,
- ascending: CREATED_ASC,
- },
- },
- {
- id: 2,
- title: __('Last contact'),
- sortDirection: {
- descending: CONTACTED_DESC,
- ascending: CONTACTED_ASC,
- },
- },
-];
-
-export default {
- components: {
- FilteredSearch,
- },
- props: {
- value: {
- type: Object,
- required: true,
- validator: searchValidator,
- },
- tokens: {
- type: Array,
- required: false,
- default: () => [],
- },
- namespace: {
- type: String,
- required: true,
- },
- },
- data() {
- // filtered_search_bar_root.vue may mutate the initial
- // filters. Use `cloneDeep` to prevent those mutations
- // from affecting this component
- const { filters, sort } = cloneDeep(this.value);
- return {
- initialFilterValue: filters,
- initialSortBy: sort,
- };
- },
- computed: {
- validTokens() {
- // Some filters are only available in EE
- // EE-only tokens are represented by `null` or `undefined`
- // values when in CE
- return this.tokens.filter(Boolean);
- },
- },
- methods: {
- onFilter(filters) {
- // Apply new filters, resetting pagination
- this.$emit('input', {
- ...this.value,
- filters,
- pagination: {},
- });
- },
- onSort(sort) {
- // Apply new sort, resetting pagination
- this.$emit('input', {
- ...this.value,
- sort,
- pagination: {},
- });
- },
- },
- sortOptions,
-};
-</script>
-<template>
- <filtered-search
- v-bind="$attrs"
- :namespace="namespace"
- recent-searches-storage-key="runners-search"
- :sort-options="$options.sortOptions"
- :initial-filter-value="initialFilterValue"
- :tokens="validTokens"
- :initial-sort-by="initialSortBy"
- :search-input-placeholder="__('Search or filter results...')"
- data-testid="runners-filtered-search"
- @onFilter="onFilter"
- @onSort="onSort"
- />
-</template>
diff --git a/app/assets/javascripts/runner/components/runner_jobs_table.vue b/app/assets/javascripts/runner/components/runner_jobs_table.vue
deleted file mode 100644
index 7817577bab0..00000000000
--- a/app/assets/javascripts/runner/components/runner_jobs_table.vue
+++ /dev/null
@@ -1,95 +0,0 @@
-<script>
-import { GlTableLite } from '@gitlab/ui';
-import { __, s__ } from '~/locale';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
-import RunnerTags from '~/runner/components/runner_tags.vue';
-import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
-import { tableField } from '../utils';
-import LinkCell from './cells/link_cell.vue';
-
-export default {
- components: {
- CiBadge,
- GlTableLite,
- LinkCell,
- RunnerTags,
- TimeAgo,
- },
- props: {
- jobs: {
- type: Array,
- required: true,
- },
- },
- methods: {
- trAttr(job) {
- if (job?.id) {
- return { 'data-testid': `job-row-${getIdFromGraphQLId(job.id)}` };
- }
- return {};
- },
- jobId(job) {
- return getIdFromGraphQLId(job.id);
- },
- jobPath(job) {
- return job.detailedStatus?.detailsPath;
- },
- projectName(job) {
- return job.pipeline?.project?.name;
- },
- projectWebUrl(job) {
- return job.pipeline?.project?.webUrl;
- },
- commitShortSha(job) {
- return job.shortSha;
- },
- commitPath(job) {
- return job.commitPath;
- },
- },
- fields: [
- tableField({ key: 'status', label: s__('Job|Status') }),
- tableField({ key: 'job', label: __('Job') }),
- tableField({ key: 'project', label: __('Project') }),
- tableField({ key: 'commit', label: __('Commit') }),
- tableField({ key: 'finished_at', label: s__('Job|Finished at') }),
- tableField({ key: 'tags', label: s__('Runners|Tags') }),
- ],
-};
-</script>
-
-<template>
- <gl-table-lite
- :items="jobs"
- :fields="$options.fields"
- :tbody-tr-attr="trAttr"
- primary-key="id"
- stacked="md"
- fixed
- >
- <template #cell(status)="{ item = {} }">
- <ci-badge v-if="item.detailedStatus" :status="item.detailedStatus" />
- </template>
-
- <template #cell(job)="{ item = {} }">
- <link-cell :href="jobPath(item)"> #{{ jobId(item) }} </link-cell>
- </template>
-
- <template #cell(project)="{ item = {} }">
- <link-cell :href="projectWebUrl(item)">{{ projectName(item) }}</link-cell>
- </template>
-
- <template #cell(commit)="{ item = {} }">
- <link-cell :href="commitPath(item)"> {{ commitShortSha(item) }}</link-cell>
- </template>
-
- <template #cell(tags)="{ item = {} }">
- <runner-tags :tag-list="item.tags" />
- </template>
-
- <template #cell(finished_at)="{ item = {} }">
- <time-ago v-if="item.finishedAt" :time="item.finishedAt" />
- </template>
- </gl-table-lite>
-</template>
diff --git a/app/assets/javascripts/runner/components/runner_pause_button.vue b/app/assets/javascripts/runner/components/runner_pause_button.vue
deleted file mode 100644
index 334e5f6023a..00000000000
--- a/app/assets/javascripts/runner/components/runner_pause_button.vue
+++ /dev/null
@@ -1,120 +0,0 @@
-<script>
-import { GlButton, GlTooltipDirective } from '@gitlab/ui';
-import runnerToggleActiveMutation from '~/runner/graphql/shared/runner_toggle_active.mutation.graphql';
-import { createAlert } from '~/flash';
-import { captureException } from '~/runner/sentry_utils';
-import { I18N_PAUSE, I18N_PAUSE_TOOLTIP, I18N_RESUME, I18N_RESUME_TOOLTIP } from '../constants';
-
-export default {
- name: 'RunnerPauseButton',
- components: {
- GlButton,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- runner: {
- type: Object,
- required: true,
- },
- compact: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- emits: ['toggledPaused'],
- data() {
- return {
- updating: false,
- };
- },
- computed: {
- isActive() {
- return this.runner.active;
- },
- icon() {
- return this.isActive ? 'pause' : 'play';
- },
- label() {
- return this.isActive ? I18N_PAUSE : I18N_RESUME;
- },
- buttonContent() {
- if (this.compact) {
- return null;
- }
- return this.label;
- },
- ariaLabel() {
- if (this.compact) {
- return this.label;
- }
- return null;
- },
- tooltip() {
- // Prevent a "sticky" tooltip: If this button is disabled,
- // mouseout listeners don't run leaving the tooltip stuck
- if (!this.updating) {
- return this.isActive ? I18N_PAUSE_TOOLTIP : I18N_RESUME_TOOLTIP;
- }
- return '';
- },
- },
- methods: {
- async onToggle() {
- this.updating = true;
- try {
- const input = {
- id: this.runner.id,
- active: !this.isActive,
- };
-
- const {
- data: {
- runnerUpdate: { errors },
- },
- } = await this.$apollo.mutate({
- mutation: runnerToggleActiveMutation,
- variables: {
- input,
- },
- });
-
- if (errors && errors.length) {
- throw new Error(errors.join(' '));
- }
- this.$emit('toggledPaused');
- } catch (e) {
- this.onError(e);
- } finally {
- this.updating = false;
- }
- },
- onError(error) {
- const { message } = error;
-
- createAlert({ message });
- captureException({ error, component: this.$options.name });
- },
- },
-};
-</script>
-
-<template>
- <gl-button
- v-gl-tooltip="tooltip"
- v-bind="$attrs"
- :aria-label="ariaLabel"
- :icon="icon"
- :loading="updating"
- @click="onToggle"
- v-on="$listeners"
- >
- <!--
- Use <template v-if> to ensure a square button is shown when compact: true.
- Sending empty content will still show a distorted/rectangular button.
- -->
- <template v-if="buttonContent">{{ buttonContent }}</template>
- </gl-button>
-</template>
diff --git a/app/assets/javascripts/runner/components/runner_stacked_layout_banner.vue b/app/assets/javascripts/runner/components/runner_stacked_layout_banner.vue
deleted file mode 100644
index e3a9a9fd8a4..00000000000
--- a/app/assets/javascripts/runner/components/runner_stacked_layout_banner.vue
+++ /dev/null
@@ -1,58 +0,0 @@
-<script>
-import allChangesCommittedSvg from '@gitlab/svgs/dist/illustrations/multi-editor_all_changes_committed_empty.svg';
-import { GlBanner } from '@gitlab/ui';
-
-import { s__ } from '~/locale';
-import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
-
-const I18N_TITLE = s__("Runners|We've made some changes and want your feedback");
-const I18N_DESCRIPTION = s__(
- "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!",
-);
-const I18N_LINK = s__('Runners|Add your feedback in the issue');
-
-// use a data url instead getting it from via HTML data-* attributes to simplify removal of this feature flag
-const ILLUSTRATION_URL = `data:image/svg+xml;utf8,${encodeURIComponent(allChangesCommittedSvg)}`;
-const ISSUE_URL = 'https://gitlab.com/gitlab-org/gitlab/-/issues/371621';
-const STORAGE_KEY = 'runner_list_stacked_layout_feedback_dismissed';
-
-export default {
- components: {
- GlBanner,
- LocalStorageSync,
- },
- data() {
- return {
- isDismissed: false,
- };
- },
- methods: {
- onClose() {
- this.isDismissed = true;
- },
- },
- I18N_TITLE,
- I18N_DESCRIPTION,
- I18N_LINK,
- ILLUSTRATION_URL,
- ISSUE_URL,
- STORAGE_KEY,
-};
-</script>
-
-<template>
- <div>
- <local-storage-sync v-model="isDismissed" :storage-key="$options.STORAGE_KEY" />
- <gl-banner
- v-if="!isDismissed"
- :svg-path="$options.ILLUSTRATION_URL"
- :title="$options.I18N_TITLE"
- :button-text="$options.I18N_LINK"
- :button-link="$options.ISSUE_URL"
- class="gl-my-5"
- @close="onClose"
- >
- <p>{{ $options.I18N_DESCRIPTION }}</p>
- </gl-banner>
- </div>
-</template>
diff --git a/app/assets/javascripts/runner/components/runner_status_popover.vue b/app/assets/javascripts/runner/components/runner_status_popover.vue
deleted file mode 100644
index 5b22f7828a1..00000000000
--- a/app/assets/javascripts/runner/components/runner_status_popover.vue
+++ /dev/null
@@ -1,75 +0,0 @@
-<script>
-import { GlSprintf } from '@gitlab/ui';
-import { duration } from '~/lib/utils/datetime/timeago_utility';
-import HelpPopover from '~/vue_shared/components/help_popover.vue';
-import {
- I18N_STATUS_POPOVER_TITLE,
- I18N_STATUS_POPOVER_NEVER_CONTACTED,
- I18N_STATUS_POPOVER_NEVER_CONTACTED_DESCRIPTION,
- I18N_STATUS_POPOVER_ONLINE,
- I18N_STATUS_POPOVER_ONLINE_DESCRIPTION,
- I18N_STATUS_POPOVER_OFFLINE,
- I18N_STATUS_POPOVER_OFFLINE_DESCRIPTION,
- I18N_STATUS_POPOVER_STALE,
- I18N_STATUS_POPOVER_STALE_DESCRIPTION,
-} from '~/runner/constants';
-
-export default {
- name: 'RunnerStatusPopover',
- components: {
- GlSprintf,
- HelpPopover,
- },
- inject: ['onlineContactTimeoutSecs', 'staleTimeoutSecs'],
- computed: {
- onlineContactTimeoutDuration() {
- return duration(this.onlineContactTimeoutSecs * 1000);
- },
- staleTimeoutDuration() {
- return duration(this.staleTimeoutSecs * 1000);
- },
- },
- I18N_STATUS_POPOVER_TITLE,
- I18N_STATUS_POPOVER_NEVER_CONTACTED,
- I18N_STATUS_POPOVER_NEVER_CONTACTED_DESCRIPTION,
- I18N_STATUS_POPOVER_ONLINE,
- I18N_STATUS_POPOVER_ONLINE_DESCRIPTION,
- I18N_STATUS_POPOVER_OFFLINE,
- I18N_STATUS_POPOVER_OFFLINE_DESCRIPTION,
- I18N_STATUS_POPOVER_STALE,
- I18N_STATUS_POPOVER_STALE_DESCRIPTION,
-};
-</script>
-
-<template>
- <help-popover>
- <template #title>{{ $options.I18N_STATUS_POPOVER_TITLE }}</template>
-
- <p class="gl-mb-0">
- <strong>{{ $options.I18N_STATUS_POPOVER_NEVER_CONTACTED }}</strong>
- <gl-sprintf :message="$options.I18N_STATUS_POPOVER_NEVER_CONTACTED_DESCRIPTION">
- <template #code="{ content }">
- <code>{{ content }}</code>
- </template>
- </gl-sprintf>
- </p>
- <p class="gl-mb-0">
- <strong>{{ $options.I18N_STATUS_POPOVER_ONLINE }}</strong>
- <gl-sprintf :message="$options.I18N_STATUS_POPOVER_ONLINE_DESCRIPTION">
- <template #elapsedTime>{{ onlineContactTimeoutDuration }}</template>
- </gl-sprintf>
- </p>
- <p class="gl-mb-0">
- <strong>{{ $options.I18N_STATUS_POPOVER_OFFLINE }}</strong>
- <gl-sprintf :message="$options.I18N_STATUS_POPOVER_OFFLINE_DESCRIPTION">
- <template #elapsedTime>{{ onlineContactTimeoutDuration }}</template>
- </gl-sprintf>
- </p>
- <p class="gl-mb-0">
- <strong>{{ $options.I18N_STATUS_POPOVER_STALE }}</strong>
- <gl-sprintf :message="$options.I18N_STATUS_POPOVER_STALE_DESCRIPTION">
- <template #elapsedTime>{{ staleTimeoutDuration }}</template>
- </gl-sprintf>
- </p>
- </help-popover>
-</template>
diff --git a/app/assets/javascripts/runner/components/runner_type_tabs.vue b/app/assets/javascripts/runner/components/runner_type_tabs.vue
deleted file mode 100644
index 6b9e3bf91ad..00000000000
--- a/app/assets/javascripts/runner/components/runner_type_tabs.vue
+++ /dev/null
@@ -1,123 +0,0 @@
-<script>
-import { GlBadge, GlTabs, GlTab } from '@gitlab/ui';
-import { searchValidator } from '~/runner/runner_search_utils';
-import { formatNumber } from '~/locale';
-import {
- INSTANCE_TYPE,
- GROUP_TYPE,
- PROJECT_TYPE,
- I18N_ALL_TYPES,
- I18N_INSTANCE_TYPE,
- I18N_GROUP_TYPE,
- I18N_PROJECT_TYPE,
-} from '../constants';
-import RunnerCount from './stat/runner_count.vue';
-
-const I18N_TAB_TITLES = {
- [INSTANCE_TYPE]: I18N_INSTANCE_TYPE,
- [GROUP_TYPE]: I18N_GROUP_TYPE,
- [PROJECT_TYPE]: I18N_PROJECT_TYPE,
-};
-
-const TAB_COUNT_REF = 'tab-count';
-
-export default {
- components: {
- GlBadge,
- GlTabs,
- GlTab,
- RunnerCount,
- },
- props: {
- runnerTypes: {
- type: Array,
- required: false,
- default: () => [INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE],
- },
- value: {
- type: Object,
- required: true,
- validator: searchValidator,
- },
- countScope: {
- type: String,
- required: true,
- },
- countVariables: {
- type: Object,
- required: true,
- },
- },
- computed: {
- tabs() {
- const tabs = this.runnerTypes.map((runnerType) => ({
- title: I18N_TAB_TITLES[runnerType],
- runnerType,
- }));
-
- // Always add a "All" tab that resets filters
- return [
- {
- title: I18N_ALL_TYPES,
- runnerType: null,
- },
- ...tabs,
- ];
- },
- },
- methods: {
- onTabSelected({ runnerType }) {
- this.$emit('input', {
- ...this.value,
- runnerType,
- pagination: { page: 1 },
- });
- },
- isTabActive({ runnerType }) {
- return runnerType === this.value.runnerType;
- },
- tabBadgeCountVariables(runnerType) {
- return { ...this.countVariables, type: runnerType };
- },
- tabCount(count) {
- if (typeof count === 'number') {
- return formatNumber(count);
- }
- return '';
- },
-
- // Component API
- refetch() {
- // Refresh all of the counts here, can be called by parent component
- this.$refs[TAB_COUNT_REF].forEach((countComponent) => {
- countComponent.refetch();
- });
- },
- },
- TAB_COUNT_REF,
-};
-</script>
-<template>
- <gl-tabs v-bind="$attrs" data-testid="runner-type-tabs">
- <gl-tab
- v-for="tab in tabs"
- :key="`${tab.runnerType}`"
- :active="isTabActive(tab)"
- @click="onTabSelected(tab)"
- >
- <template #title>
- {{ tab.title }}
- <runner-count
- #default="{ count }"
- :ref="$options.TAB_COUNT_REF"
- :scope="countScope"
- :variables="tabBadgeCountVariables(tab.runnerType)"
- >
- <gl-badge v-if="tabCount(count)" class="gl-ml-1" size="sm">
- {{ tabCount(count) }}
- </gl-badge>
- </runner-count>
- </template>
- </gl-tab>
- </gl-tabs>
-</template>
diff --git a/app/assets/javascripts/runner/components/runner_update_form.vue b/app/assets/javascripts/runner/components/runner_update_form.vue
deleted file mode 100644
index c613e2d2467..00000000000
--- a/app/assets/javascripts/runner/components/runner_update_form.vue
+++ /dev/null
@@ -1,225 +0,0 @@
-<script>
-import {
- GlButton,
- GlIcon,
- GlForm,
- GlFormCheckbox,
- GlFormGroup,
- GlFormInputGroup,
- GlSkeletonLoader,
- GlTooltipDirective,
-} from '@gitlab/ui';
-import {
- modelToUpdateMutationVariables,
- runnerToModel,
-} from 'ee_else_ce/runner/runner_update_form_utils';
-import { createAlert, VARIANT_SUCCESS } from '~/flash';
-import { redirectTo } from '~/lib/utils/url_utility';
-import { __ } from '~/locale';
-import { captureException } from '~/runner/sentry_utils';
-import { ACCESS_LEVEL_NOT_PROTECTED, ACCESS_LEVEL_REF_PROTECTED, PROJECT_TYPE } from '../constants';
-import runnerUpdateMutation from '../graphql/edit/runner_update.mutation.graphql';
-import { saveAlertToLocalStorage } from '../local_storage_alert/save_alert_to_local_storage';
-
-export default {
- name: 'RunnerUpdateForm',
- components: {
- GlButton,
- GlIcon,
- GlForm,
- GlFormCheckbox,
- GlFormGroup,
- GlFormInputGroup,
- GlSkeletonLoader,
- RunnerMaintenanceNoteField: () =>
- import('ee_component/runner/components/runner_maintenance_note_field.vue'),
- RunnerUpdateCostFactorFields: () =>
- import('ee_component/runner/components/runner_update_cost_factor_fields.vue'),
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- props: {
- runner: {
- type: Object,
- required: false,
- default: null,
- },
- loading: {
- type: Boolean,
- required: false,
- default: false,
- },
- runnerPath: {
- type: String,
- required: false,
- default: null,
- },
- },
- data() {
- return {
- saving: false,
- model: runnerToModel(this.runner),
- };
- },
- computed: {
- canBeLockedToProject() {
- return this.runner?.runnerType === PROJECT_TYPE;
- },
- },
- watch: {
- runner(newVal, oldVal) {
- if (oldVal === null) {
- this.model = runnerToModel(newVal);
- }
- },
- },
- methods: {
- async onSubmit() {
- this.saving = true;
-
- try {
- const {
- data: {
- runnerUpdate: { errors },
- },
- } = await this.$apollo.mutate({
- mutation: runnerUpdateMutation,
- variables: modelToUpdateMutationVariables(this.model),
- });
-
- if (errors?.length) {
- this.onError(errors[0]);
- } else {
- this.onSuccess();
- }
- } catch (error) {
- const { message } = error;
- this.onError(message);
- captureException({ error, component: this.$options.name });
- }
- },
- onSuccess() {
- saveAlertToLocalStorage({ message: __('Changes saved.'), variant: VARIANT_SUCCESS });
- redirectTo(this.runnerPath);
- },
- onError(message) {
- this.saving = false;
- createAlert({ message });
- },
- },
- ACCESS_LEVEL_NOT_PROTECTED,
- ACCESS_LEVEL_REF_PROTECTED,
-};
-</script>
-<template>
- <gl-form @submit.prevent="onSubmit">
- <h4 class="gl-font-lg gl-my-5">{{ s__('Runners|Details') }}</h4>
-
- <gl-skeleton-loader v-if="loading" />
-
- <template v-else>
- <gl-form-group :label="__('Description')" data-testid="runner-field-description">
- <gl-form-input-group v-model="model.description" />
- </gl-form-group>
- <runner-maintenance-note-field v-model="model.maintenanceNote" />
- </template>
-
- <hr />
-
- <h4 class="gl-font-lg gl-my-5">{{ s__('Runners|Configuration') }}</h4>
-
- <template v-if="loading">
- <gl-skeleton-loader v-for="i in 3" :key="i" />
- </template>
- <template v-else>
- <div class="gl-mb-5">
- <gl-form-checkbox
- v-model="model.active"
- data-testid="runner-field-paused"
- :value="false"
- :unchecked-value="true"
- >
- {{ __('Paused') }}
- <template #help>
- {{ s__('Runners|Stop the runner from accepting new jobs.') }}
- </template>
- </gl-form-checkbox>
-
- <gl-form-checkbox
- v-model="model.accessLevel"
- data-testid="runner-field-protected"
- :value="$options.ACCESS_LEVEL_REF_PROTECTED"
- :unchecked-value="$options.ACCESS_LEVEL_NOT_PROTECTED"
- >
- {{ __('Protected') }}
- <template #help>
- {{ s__('Runners|Use the runner on pipelines for protected branches only.') }}
- </template>
- </gl-form-checkbox>
-
- <gl-form-checkbox v-model="model.runUntagged" data-testid="runner-field-run-untagged">
- {{ __('Run untagged jobs') }}
- <template #help>
- {{ s__('Runners|Use the runner for jobs without tags, in addition to tagged jobs.') }}
- </template>
- </gl-form-checkbox>
-
- <gl-form-checkbox
- v-if="canBeLockedToProject"
- v-model="model.locked"
- data-testid="runner-field-locked"
- >
- {{ __('Lock to current projects') }} <gl-icon name="lock" />
- <template #help>
- {{
- s__(
- 'Runners|Use the runner for the currently assigned projects only. Only administrators can change the assigned projects.',
- )
- }}
- </template>
- </gl-form-checkbox>
- </div>
-
- <gl-form-group
- data-testid="runner-field-max-timeout"
- :label="__('Maximum job timeout')"
- :description="
- s__(
- 'Runners|Enter the number of seconds. This timeout takes precedence over lower timeouts set for the project.',
- )
- "
- >
- <gl-form-input-group v-model.number="model.maximumTimeout" type="number" />
- </gl-form-group>
-
- <gl-form-group
- data-testid="runner-field-tags"
- :label="__('Tags')"
- :description="
- __(
- 'You can set up jobs to only use runners with specific tags. Separate tags with commas.',
- )
- "
- >
- <gl-form-input-group v-model="model.tagList" />
- </gl-form-group>
-
- <runner-update-cost-factor-fields v-model="model" />
- </template>
-
- <div class="gl-mt-6">
- <gl-button
- type="submit"
- variant="confirm"
- class="js-no-auto-disable"
- :loading="loading || saving"
- >
- {{ __('Save changes') }}
- </gl-button>
- <gl-button :href="runnerPath">
- {{ __('Cancel') }}
- </gl-button>
- </div>
- </gl-form>
-</template>
diff --git a/app/assets/javascripts/runner/components/search_tokens/status_token_config.js b/app/assets/javascripts/runner/components/search_tokens/status_token_config.js
deleted file mode 100644
index f5c42d120fb..00000000000
--- a/app/assets/javascripts/runner/components/search_tokens/status_token_config.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import { __ } from '~/locale';
-import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants';
-import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
-import {
- I18N_STATUS_ONLINE,
- I18N_STATUS_NEVER_CONTACTED,
- I18N_STATUS_OFFLINE,
- I18N_STATUS_STALE,
- STATUS_ONLINE,
- STATUS_OFFLINE,
- STATUS_NEVER_CONTACTED,
- STATUS_STALE,
- PARAM_KEY_STATUS,
-} from '../../constants';
-
-const options = [
- { value: STATUS_ONLINE, title: I18N_STATUS_ONLINE },
- { value: STATUS_OFFLINE, title: I18N_STATUS_OFFLINE },
- { value: STATUS_NEVER_CONTACTED, title: I18N_STATUS_NEVER_CONTACTED },
- { value: STATUS_STALE, title: I18N_STATUS_STALE },
-];
-
-export const statusTokenConfig = {
- icon: 'status',
- title: __('Status'),
- type: PARAM_KEY_STATUS,
- token: BaseToken,
- unique: true,
- options: options.map(({ value, title }) => ({
- value,
- // Replace whitespace with a special character to avoid
- // splitting this value.
- // Replacing in each option, as translations may also
- // contain spaces!
- // see: https://gitlab.com/gitlab-org/gitlab/-/issues/344142
- // see: https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1438
- title: title.replace(/\s/g, '\u00a0'),
- })),
- operators: OPERATOR_IS_ONLY,
-};
diff --git a/app/assets/javascripts/runner/components/stat/runner_count.vue b/app/assets/javascripts/runner/components/stat/runner_count.vue
deleted file mode 100644
index 37c6f922f9a..00000000000
--- a/app/assets/javascripts/runner/components/stat/runner_count.vue
+++ /dev/null
@@ -1,104 +0,0 @@
-<script>
-import { fetchPolicies } from '~/lib/graphql';
-import allRunnersCountQuery from 'ee_else_ce/runner/graphql/list/all_runners_count.query.graphql';
-import groupRunnersCountQuery from 'ee_else_ce/runner/graphql/list/group_runners_count.query.graphql';
-
-import { captureException } from '../../sentry_utils';
-import { INSTANCE_TYPE, GROUP_TYPE } from '../../constants';
-
-/**
- * Renderless component that wraps a "count" query for the
- * number of runners that follow a filter criteria.
- *
- * Example usage:
- *
- * Render the count of "online" runners in the instance in a
- * <strong/> tag.
- *
- * ```vue
- * <runner-count-stat
- * #default="{ count }"
- * :scope="INSTANCE_TYPE"
- * :variables="{ status: 'ONLINE' }"
- * >
- * <strong>{{ count }}</strong>
- * </runner-count-stat>
- * ```
- *
- * Use `:skip="true"` to prevent data from being fetched and
- * even rendered.
- */
-export default {
- name: 'RunnerCount',
- props: {
- scope: {
- type: String,
- required: true,
- validator: (val) => [INSTANCE_TYPE, GROUP_TYPE].includes(val),
- },
- variables: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- skip: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- data() {
- return { count: null };
- },
- apollo: {
- count: {
- query() {
- if (this.scope === INSTANCE_TYPE) {
- return allRunnersCountQuery;
- } else if (this.scope === GROUP_TYPE) {
- return groupRunnersCountQuery;
- }
- return null;
- },
- fetchPolicy: fetchPolicies.NETWORK_ONLY,
- variables() {
- return this.variables;
- },
- skip() {
- if (this.skip) {
- // Don't show data for skipped stats
- this.count = null;
- }
- return this.skip;
- },
- update(data) {
- if (this.scope === INSTANCE_TYPE) {
- return data?.runners?.count;
- } else if (this.scope === GROUP_TYPE) {
- return data?.group?.runners?.count;
- }
- return null;
- },
- error(error) {
- this.reportToSentry(error);
- },
- },
- },
- methods: {
- reportToSentry(error) {
- captureException({ error, component: this.$options.name });
- },
-
- // Component API
- refetch() {
- // Parent components can use this method to refresh the count
- this.$apollo.queries.count.refetch();
- },
- },
- render() {
- return this.$scopedSlots.default({
- count: this.count,
- });
- },
-};
-</script>
diff --git a/app/assets/javascripts/runner/components/stat/runner_stats.vue b/app/assets/javascripts/runner/components/stat/runner_stats.vue
deleted file mode 100644
index 4df59f5a0c9..00000000000
--- a/app/assets/javascripts/runner/components/stat/runner_stats.vue
+++ /dev/null
@@ -1,89 +0,0 @@
-<script>
-import RunnerSingleStat from '~/runner/components/stat/runner_single_stat.vue';
-import {
- I18N_STATUS_ONLINE,
- I18N_STATUS_OFFLINE,
- I18N_STATUS_STALE,
- STATUS_ONLINE,
- STATUS_OFFLINE,
- STATUS_STALE,
-} from '../../constants';
-
-export default {
- components: {
- RunnerSingleStat,
- RunnerUpgradeStatusStats: () =>
- import('ee_component/runner/components/stat/runner_upgrade_status_stats.vue'),
- },
- props: {
- scope: {
- type: String,
- required: true,
- },
- variables: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- },
- computed: {
- stats() {
- return [
- {
- key: STATUS_ONLINE,
- props: {
- skip: this.statusCountSkip(STATUS_ONLINE),
- variables: { ...this.variables, status: STATUS_ONLINE },
- variant: 'success',
- title: I18N_STATUS_ONLINE,
- metaIcon: 'status-active',
- },
- },
- {
- key: STATUS_OFFLINE,
- props: {
- skip: this.statusCountSkip(STATUS_OFFLINE),
- variables: { ...this.variables, status: STATUS_OFFLINE },
- variant: 'muted',
- title: I18N_STATUS_OFFLINE,
- metaIcon: 'status-waiting',
- },
- },
- {
- key: STATUS_STALE,
- props: {
- skip: this.statusCountSkip(STATUS_STALE),
- variables: { ...this.variables, status: STATUS_STALE },
- variant: 'warning',
- title: I18N_STATUS_STALE,
- metaIcon: 'time-out',
- },
- },
- ];
- },
- },
- methods: {
- statusCountSkip(status) {
- // Show an empty result when we already filter by another status
- return this.variables.status && this.variables.status !== status;
- },
- },
-};
-</script>
-<template>
- <div class="gl-display-flex gl-flex-wrap gl-py-6">
- <runner-single-stat
- v-for="stat in stats"
- :key="stat.key"
- :scope="scope"
- v-bind="stat.props"
- class="gl-px-5"
- />
-
- <runner-upgrade-status-stats
- class="gl-display-contents"
- :scope="scope"
- :variables="variables"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/runner/graphql/edit/runner_form.query.graphql b/app/assets/javascripts/runner/graphql/edit/runner_form.query.graphql
deleted file mode 100644
index 0bf66c223fc..00000000000
--- a/app/assets/javascripts/runner/graphql/edit/runner_form.query.graphql
+++ /dev/null
@@ -1,7 +0,0 @@
-#import "ee_else_ce/runner/graphql/edit/runner_fields.fragment.graphql"
-
-query getRunnerForm($id: CiRunnerID!) {
- runner(id: $id) {
- ...RunnerFields
- }
-}
diff --git a/app/assets/javascripts/runner/graphql/edit/runner_update.mutation.graphql b/app/assets/javascripts/runner/graphql/edit/runner_update.mutation.graphql
deleted file mode 100644
index 8694a51b5a4..00000000000
--- a/app/assets/javascripts/runner/graphql/edit/runner_update.mutation.graphql
+++ /dev/null
@@ -1,13 +0,0 @@
-#import "ee_else_ce/runner/graphql/edit/runner_fields.fragment.graphql"
-
-# Mutation for updates from the runner form, loads
-# attributes shown in the runner details.
-
-mutation runnerUpdate($input: RunnerUpdateInput!) {
- runnerUpdate(input: $input) {
- runner {
- ...RunnerFields
- }
- errors
- }
-}
diff --git a/app/assets/javascripts/runner/graphql/list/all_runners.query.graphql b/app/assets/javascripts/runner/graphql/list/all_runners.query.graphql
deleted file mode 100644
index 1160596aff3..00000000000
--- a/app/assets/javascripts/runner/graphql/list/all_runners.query.graphql
+++ /dev/null
@@ -1,29 +0,0 @@
-#import "~/runner/graphql/list/all_runners_connection.fragment.graphql"
-
-query getAllRunners(
- $before: String
- $after: String
- $first: Int
- $last: Int
- $paused: Boolean
- $status: CiRunnerStatus
- $type: CiRunnerType
- $tagList: [String!]
- $search: String
- $sort: CiRunnerSort
-) {
- runners(
- before: $before
- after: $after
- first: $first
- last: $last
- paused: $paused
- status: $status
- type: $type
- tagList: $tagList
- search: $search
- sort: $sort
- ) {
- ...AllRunnersConnection
- }
-}
diff --git a/app/assets/javascripts/runner/graphql/list/all_runners_connection.fragment.graphql b/app/assets/javascripts/runner/graphql/list/all_runners_connection.fragment.graphql
deleted file mode 100644
index 4440b8e98da..00000000000
--- a/app/assets/javascripts/runner/graphql/list/all_runners_connection.fragment.graphql
+++ /dev/null
@@ -1,13 +0,0 @@
-#import "ee_else_ce/runner/graphql/list/list_item.fragment.graphql"
-#import "~/graphql_shared/fragments/page_info.fragment.graphql"
-
-fragment AllRunnersConnection on CiRunnerConnection {
- nodes {
- ...ListItem
- adminUrl
- editAdminUrl
- }
- pageInfo {
- ...PageInfo
- }
-}
diff --git a/app/assets/javascripts/runner/graphql/list/group_runner_connection.fragment.graphql b/app/assets/javascripts/runner/graphql/list/group_runner_connection.fragment.graphql
deleted file mode 100644
index baef16a4b41..00000000000
--- a/app/assets/javascripts/runner/graphql/list/group_runner_connection.fragment.graphql
+++ /dev/null
@@ -1,16 +0,0 @@
-#import "ee_else_ce/runner/graphql/list/list_item.fragment.graphql"
-#import "~/graphql_shared/fragments/page_info.fragment.graphql"
-
-fragment GroupRunnerConnection on CiRunnerConnection {
- edges {
- webUrl
- editUrl
- node {
- ...ListItem
- projectCount # Used to determine why some project runners can't be deleted
- }
- }
- pageInfo {
- ...PageInfo
- }
-}
diff --git a/app/assets/javascripts/runner/graphql/list/group_runners.query.graphql b/app/assets/javascripts/runner/graphql/list/group_runners.query.graphql
deleted file mode 100644
index 95f9dd1beb9..00000000000
--- a/app/assets/javascripts/runner/graphql/list/group_runners.query.graphql
+++ /dev/null
@@ -1,35 +0,0 @@
-#import "~/runner/graphql/list/group_runner_connection.fragment.graphql"
-
-query getGroupRunners(
- $groupFullPath: ID!
- $membership: CiRunnerMembershipFilter
- $before: String
- $after: String
- $first: Int
- $last: Int
- $paused: Boolean
- $status: CiRunnerStatus
- $type: CiRunnerType
- $tagList: [String!]
- $search: String
- $sort: CiRunnerSort
-) {
- group(fullPath: $groupFullPath) {
- id # Apollo required
- runners(
- membership: $membership
- before: $before
- after: $after
- first: $first
- last: $last
- paused: $paused
- status: $status
- type: $type
- tagList: $tagList
- search: $search
- sort: $sort
- ) {
- ...GroupRunnerConnection
- }
- }
-}
diff --git a/app/assets/javascripts/runner/graphql/list/local_state.js b/app/assets/javascripts/runner/graphql/list/local_state.js
deleted file mode 100644
index e0477c660b4..00000000000
--- a/app/assets/javascripts/runner/graphql/list/local_state.js
+++ /dev/null
@@ -1,75 +0,0 @@
-import { makeVar } from '@apollo/client/core';
-import { RUNNER_TYPENAME } from '../../constants';
-import typeDefs from './typedefs.graphql';
-
-/**
- * Local state for checkable runner items.
- *
- * Usage:
- *
- * ```
- * import { createLocalState } from '~/runner/graphql/list/local_state';
- *
- * // initialize local state
- * const { cacheConfig, typeDefs, localMutations } = createLocalState();
- *
- * // configure the client
- * apolloClient = createApolloClient({}, { cacheConfig, typeDefs });
- *
- * // modify local state
- * localMutations.setRunnerChecked( ... )
- * ```
- *
- * @returns {Object} An object to configure an Apollo client:
- * contains cacheConfig, typeDefs, localMutations.
- */
-export const createLocalState = () => {
- const checkedRunnerIdsVar = makeVar({});
-
- const cacheConfig = {
- typePolicies: {
- Query: {
- fields: {
- checkedRunnerIds(_, { canRead, toReference }) {
- return Object.entries(checkedRunnerIdsVar())
- .filter(([id]) => {
- // Some runners may be deleted by the user separately.
- // Skip dangling references, those not in the cache.
- // See: https://www.apollographql.com/docs/react/caching/garbage-collection/#dangling-references
- return canRead(toReference({ __typename: RUNNER_TYPENAME, id }));
- })
- .filter(([, isChecked]) => isChecked)
- .map(([id]) => id);
- },
- },
- },
- },
- };
-
- const localMutations = {
- setRunnerChecked({ runner, isChecked }) {
- const { id, userPermissions } = runner;
- if (userPermissions?.deleteRunner) {
- checkedRunnerIdsVar({
- ...checkedRunnerIdsVar(),
- [id]: isChecked,
- });
- }
- },
- setRunnersChecked({ runners, isChecked }) {
- const newVal = runners
- .filter(({ userPermissions }) => userPermissions?.deleteRunner)
- .reduce((acc, { id }) => ({ ...acc, [id]: isChecked }), checkedRunnerIdsVar());
- checkedRunnerIdsVar(newVal);
- },
- clearChecked() {
- checkedRunnerIdsVar({});
- },
- };
-
- return {
- cacheConfig,
- typeDefs,
- localMutations,
- };
-};
diff --git a/app/assets/javascripts/runner/graphql/show/runner.query.graphql b/app/assets/javascripts/runner/graphql/show/runner.query.graphql
deleted file mode 100644
index dec434b43a5..00000000000
--- a/app/assets/javascripts/runner/graphql/show/runner.query.graphql
+++ /dev/null
@@ -1,7 +0,0 @@
-#import "ee_else_ce/runner/graphql/show/runner_details.fragment.graphql"
-
-query getRunner($id: CiRunnerID!) {
- runner(id: $id) {
- ...RunnerDetails
- }
-}
diff --git a/app/assets/javascripts/runner/graphql/show/runner_jobs.query.graphql b/app/assets/javascripts/runner/graphql/show/runner_jobs.query.graphql
deleted file mode 100644
index 14585e62bf2..00000000000
--- a/app/assets/javascripts/runner/graphql/show/runner_jobs.query.graphql
+++ /dev/null
@@ -1,36 +0,0 @@
-#import "~/graphql_shared/fragments/page_info.fragment.graphql"
-
-query getRunnerJobs($id: CiRunnerID!, $first: Int, $last: Int, $before: String, $after: String) {
- runner(id: $id) {
- id
- projectCount
- jobs(before: $before, after: $after, first: $first, last: $last) {
- nodes {
- id
- detailedStatus {
- # fields for `<ci-badge>`
- id
- detailsPath
- group
- icon
- text
- }
- pipeline {
- id
- project {
- id
- name
- webUrl
- }
- }
- shortSha
- commitPath
- tags
- finishedAt
- }
- pageInfo {
- ...PageInfo
- }
- }
- }
-}
diff --git a/app/assets/javascripts/runner/group_runners/group_runners_app.vue b/app/assets/javascripts/runner/group_runners/group_runners_app.vue
deleted file mode 100644
index 7f56d895682..00000000000
--- a/app/assets/javascripts/runner/group_runners/group_runners_app.vue
+++ /dev/null
@@ -1,277 +0,0 @@
-<script>
-import { GlLink } from '@gitlab/ui';
-import { createAlert } from '~/flash';
-import { updateHistory } from '~/lib/utils/url_utility';
-import { fetchPolicies } from '~/lib/graphql';
-import { upgradeStatusTokenConfig } from 'ee_else_ce/runner/components/search_tokens/upgrade_status_token_config';
-import {
- fromUrlQueryToSearch,
- fromSearchToUrl,
- fromSearchToVariables,
- isSearchFiltered,
-} from 'ee_else_ce/runner/runner_search_utils';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import groupRunnersQuery from 'ee_else_ce/runner/graphql/list/group_runners.query.graphql';
-import groupRunnersCountQuery from 'ee_else_ce/runner/graphql/list/group_runners_count.query.graphql';
-
-import RegistrationDropdown from '../components/registration/registration_dropdown.vue';
-import RunnerStackedLayoutBanner from '../components/runner_stacked_layout_banner.vue';
-import RunnerFilteredSearchBar from '../components/runner_filtered_search_bar.vue';
-import RunnerList from '../components/runner_list.vue';
-import RunnerListEmptyState from '../components/runner_list_empty_state.vue';
-import RunnerName from '../components/runner_name.vue';
-import RunnerStats from '../components/stat/runner_stats.vue';
-import RunnerPagination from '../components/runner_pagination.vue';
-import RunnerTypeTabs from '../components/runner_type_tabs.vue';
-import RunnerActionsCell from '../components/cells/runner_actions_cell.vue';
-import RunnerMembershipToggle from '../components/runner_membership_toggle.vue';
-
-import { pausedTokenConfig } from '../components/search_tokens/paused_token_config';
-import { statusTokenConfig } from '../components/search_tokens/status_token_config';
-import { tagTokenConfig } from '../components/search_tokens/tag_token_config';
-import {
- GROUP_FILTERED_SEARCH_NAMESPACE,
- GROUP_TYPE,
- PROJECT_TYPE,
- I18N_FETCH_ERROR,
- FILTER_CSS_CLASSES,
-} from '../constants';
-import { captureException } from '../sentry_utils';
-
-export default {
- name: 'GroupRunnersApp',
- components: {
- GlLink,
- RegistrationDropdown,
- RunnerStackedLayoutBanner,
- RunnerFilteredSearchBar,
- RunnerList,
- RunnerListEmptyState,
- RunnerName,
- RunnerMembershipToggle,
- RunnerStats,
- RunnerPagination,
- RunnerTypeTabs,
- RunnerActionsCell,
- },
- mixins: [glFeatureFlagMixin()],
- inject: ['emptyStateSvgPath', 'emptyStateFilteredSvgPath'],
- props: {
- registrationToken: {
- type: String,
- required: false,
- default: null,
- },
- groupFullPath: {
- type: String,
- required: true,
- },
- groupRunnersLimitedCount: {
- type: Number,
- required: true,
- },
- },
- data() {
- return {
- search: fromUrlQueryToSearch(),
- runners: {
- items: [],
- urlsById: {},
- pageInfo: {},
- },
- };
- },
- apollo: {
- runners: {
- query: groupRunnersQuery,
- fetchPolicy: fetchPolicies.NETWORK_ONLY,
- variables() {
- return this.variables;
- },
- update(data) {
- const { edges = [], pageInfo = {} } = data?.group?.runners || {};
-
- const items = [];
- const urlsById = {};
-
- edges.forEach(({ node, webUrl, editUrl }) => {
- items.push(node);
- urlsById[node.id] = {
- web: webUrl,
- edit: editUrl,
- };
- });
-
- return {
- items,
- urlsById,
- pageInfo,
- };
- },
- error(error) {
- createAlert({ message: I18N_FETCH_ERROR });
-
- this.reportToSentry(error);
- },
- },
- },
- computed: {
- variables() {
- return {
- ...fromSearchToVariables(this.search),
- groupFullPath: this.groupFullPath,
- };
- },
- countVariables() {
- // Exclude pagination variables, leave only filters variables
- const { sort, before, last, after, first, ...countVariables } = this.variables;
- return countVariables;
- },
- runnersLoading() {
- return this.$apollo.queries.runners.loading;
- },
- noRunnersFound() {
- return !this.runnersLoading && !this.runners.items.length;
- },
- filteredSearchNamespace() {
- return `${GROUP_FILTERED_SEARCH_NAMESPACE}/${this.groupFullPath}`;
- },
- searchTokens() {
- return [
- pausedTokenConfig,
- statusTokenConfig,
- {
- ...tagTokenConfig,
- suggestionsDisabled: true,
- },
- upgradeStatusTokenConfig,
- ];
- },
- isSearchFiltered() {
- return isSearchFiltered(this.search);
- },
- },
- watch: {
- search: {
- deep: true,
- handler() {
- // TODO Implement back button reponse using onpopstate
- // See https://gitlab.com/gitlab-org/gitlab/-/issues/333804
- updateHistory({
- url: fromSearchToUrl(this.search),
- title: document.title,
- });
- },
- },
- },
- errorCaptured(error) {
- this.reportToSentry(error);
- },
- methods: {
- webUrl(runner) {
- return this.runners.urlsById[runner.id]?.web;
- },
- editUrl(runner) {
- return this.runners.urlsById[runner.id]?.edit;
- },
- refetchCounts() {
- this.$apollo.getClient().refetchQueries({ include: [groupRunnersCountQuery] });
- },
- onToggledPaused() {
- // When a runner becomes Paused, the tab count can
- // become stale, refetch outdated counts.
- this.refetchCounts();
- },
- onDeleted({ message }) {
- this.$root.$toast?.show(message);
- this.refetchCounts();
- },
- reportToSentry(error) {
- captureException({ error, component: this.$options.name });
- },
- onPaginationInput(value) {
- this.search.pagination = value;
- },
- },
- TABS_RUNNER_TYPES: [GROUP_TYPE, PROJECT_TYPE],
- GROUP_TYPE,
- FILTER_CSS_CLASSES,
-};
-</script>
-
-<template>
- <div>
- <runner-stacked-layout-banner />
-
- <div class="gl-display-flex gl-align-items-center">
- <runner-type-tabs
- ref="runner-type-tabs"
- v-model="search"
- :count-scope="$options.GROUP_TYPE"
- :count-variables="countVariables"
- :runner-types="$options.TABS_RUNNER_TYPES"
- class="gl-w-full"
- content-class="gl-display-none"
- nav-class="gl-border-none!"
- />
-
- <registration-dropdown
- v-if="registrationToken"
- class="gl-ml-auto"
- :registration-token="registrationToken"
- :type="$options.GROUP_TYPE"
- right
- />
- </div>
-
- <div
- class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-gap-3"
- :class="$options.FILTER_CSS_CLASSES"
- >
- <runner-filtered-search-bar
- v-model="search"
- :tokens="searchTokens"
- :namespace="filteredSearchNamespace"
- class="gl-flex-grow-1 gl-align-self-stretch"
- />
- <runner-membership-toggle
- v-model="search.membership"
- class="gl-align-self-end gl-md-align-self-center"
- />
- </div>
-
- <runner-stats :scope="$options.GROUP_TYPE" :variables="countVariables" />
-
- <runner-list-empty-state
- v-if="noRunnersFound"
- :registration-token="registrationToken"
- :is-search-filtered="isSearchFiltered"
- :svg-path="emptyStateSvgPath"
- :filtered-svg-path="emptyStateFilteredSvgPath"
- />
- <template v-else>
- <runner-list :runners="runners.items" :loading="runnersLoading" @deleted="onDeleted">
- <template #runner-name="{ runner }">
- <gl-link :href="webUrl(runner)">
- <runner-name :runner="runner" />
- </gl-link>
- </template>
- <template #runner-actions-cell="{ runner }">
- <runner-actions-cell
- :runner="runner"
- :edit-url="editUrl(runner)"
- @toggledPaused="onToggledPaused"
- @deleted="onDeleted"
- />
- </template>
- </runner-list>
- </template>
-
- <runner-pagination
- class="gl-mt-3"
- :disabled="runnersLoading"
- :page-info="runners.pageInfo"
- @input="onPaginationInput"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/search/sidebar/components/app.vue b/app/assets/javascripts/search/sidebar/components/app.vue
index 789efc8f09d..6f29864c0a2 100644
--- a/app/assets/javascripts/search/sidebar/components/app.vue
+++ b/app/assets/javascripts/search/sidebar/components/app.vue
@@ -1,48 +1,29 @@
<script>
-import { GlButton, GlLink } from '@gitlab/ui';
-import { mapActions, mapState } from 'vuex';
-import ConfidentialityFilter from './confidentiality_filter.vue';
-import StatusFilter from './status_filter.vue';
+import { mapState } 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 } from '../constants';
+import ResultsFilters from './results_filters.vue';
export default {
name: 'GlobalSearchSidebar',
components: {
- GlButton,
- GlLink,
- StatusFilter,
- ConfidentialityFilter,
+ ResultsFilters,
+ ScopeNavigation,
},
+ mixins: [glFeatureFlagsMixin()],
computed: {
- ...mapState(['urlQuery', 'sidebarDirty']),
- showReset() {
- return this.urlQuery.state || this.urlQuery.confidential;
+ ...mapState(['urlQuery']),
+ showFilters() {
+ return this.urlQuery.scope === SCOPE_ISSUES || this.urlQuery.scope === SCOPE_MERGE_REQUESTS;
},
- showSidebar() {
- return this.urlQuery.scope === 'issues' || this.urlQuery.scope === 'merge_requests';
- },
- },
- methods: {
- ...mapActions(['applyQuery', 'resetQuery']),
},
};
</script>
<template>
- <form
- class="search-sidebar gl-display-flex gl-flex-direction-column gl-mr-4 gl-mb-6 gl-mt-5"
- @submit.prevent="applyQuery"
- >
- <template v-if="showSidebar">
- <status-filter />
- <confidentiality-filter />
- <div class="gl-display-flex gl-align-items-center gl-mt-3">
- <gl-button category="primary" variant="confirm" type="submit" :disabled="!sidebarDirty">
- {{ __('Apply') }}
- </gl-button>
- <gl-link v-if="showReset" class="gl-ml-auto" @click="resetQuery">{{
- __('Reset filters')
- }}</gl-link>
- </div>
- </template>
- </form>
+ <section class="search-sidebar gl-display-flex gl-flex-direction-column gl-mr-4 gl-mb-6 gl-mt-5">
+ <scope-navigation v-if="glFeatures.searchPageVerticalNav" />
+ <results-filters v-if="showFilters" />
+ </section>
</template>
diff --git a/app/assets/javascripts/search/sidebar/components/results_filters.vue b/app/assets/javascripts/search/sidebar/components/results_filters.vue
new file mode 100644
index 00000000000..5b53f94bb53
--- /dev/null
+++ b/app/assets/javascripts/search/sidebar/components/results_filters.vue
@@ -0,0 +1,49 @@
+<script>
+import { GlButton, GlLink } from '@gitlab/ui';
+import { mapActions, mapState } from 'vuex';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import ConfidentialityFilter from './confidentiality_filter.vue';
+import StatusFilter from './status_filter.vue';
+
+export default {
+ name: 'ResultsFilters',
+ components: {
+ GlButton,
+ GlLink,
+ StatusFilter,
+ ConfidentialityFilter,
+ },
+ mixins: [glFeatureFlagsMixin()],
+ computed: {
+ ...mapState(['urlQuery', 'sidebarDirty']),
+ showReset() {
+ return this.urlQuery.state || this.urlQuery.confidential;
+ },
+ searchPageVerticalNavFeatureFlag() {
+ return this.glFeatures.searchPageVerticalNav;
+ },
+ },
+ methods: {
+ ...mapActions(['applyQuery', 'resetQuery']),
+ },
+};
+</script>
+
+<template>
+ <form
+ :class="searchPageVerticalNavFeatureFlag ? 'gl-px-5' : 'gl-px-0'"
+ @submit.prevent="applyQuery"
+ >
+ <hr v-if="searchPageVerticalNavFeatureFlag" class="gl-my-5 gl-border-gray-100" />
+ <status-filter />
+ <confidentiality-filter />
+ <div class="gl-display-flex gl-align-items-center gl-mt-4">
+ <gl-button category="primary" variant="confirm" type="submit" :disabled="!sidebarDirty">
+ {{ __('Apply') }}
+ </gl-button>
+ <gl-link v-if="showReset" class="gl-ml-auto" @click="resetQuery">{{
+ __('Reset filters')
+ }}</gl-link>
+ </div>
+ </form>
+</template>
diff --git a/app/assets/javascripts/search/sidebar/components/scope_navigation.vue b/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
new file mode 100644
index 00000000000..f5e1525090e
--- /dev/null
+++ b/app/assets/javascripts/search/sidebar/components/scope_navigation.vue
@@ -0,0 +1,66 @@
+<script>
+import { GlNav, GlNavItem } from '@gitlab/ui';
+import { mapActions, mapState } from 'vuex';
+import { formatNumber } from '~/locale';
+import Tracking from '~/tracking';
+import { NAV_LINK_DEFAULT_CLASSES, NUMBER_FORMATING_OPTIONS } from '../constants';
+
+export default {
+ name: 'ScopeNavigation',
+ components: {
+ GlNav,
+ GlNavItem,
+ },
+ mixins: [Tracking.mixin()],
+ computed: {
+ ...mapState(['navigation', 'urlQuery']),
+ },
+ created() {
+ this.fetchSidebarCount();
+ },
+ methods: {
+ ...mapActions(['fetchSidebarCount']),
+ activeClasses(currentScope) {
+ return currentScope === this.urlQuery.scope ? 'gl-font-weight-bold' : '';
+ },
+ showFormatedCount(count) {
+ if (!count) {
+ return '0';
+ }
+ const countNumber = parseInt(count.replace(/,/g, ''), 10);
+ return formatNumber(countNumber, NUMBER_FORMATING_OPTIONS);
+ },
+ handleClick(scope) {
+ this.track('click_menu_item', { label: `vertical_navigation_${scope}` });
+ },
+ linkClasses(scope) {
+ return [
+ { 'gl-font-weight-bold': scope === this.urlQuery.scope },
+ ...this.$options.NAV_LINK_DEFAULT_CLASSES,
+ ];
+ },
+ },
+ NAV_LINK_DEFAULT_CLASSES,
+};
+</script>
+
+<template>
+ <nav data-testid="search-filter">
+ <gl-nav vertical pills>
+ <gl-nav-item
+ v-for="(item, scope, index) in navigation"
+ :key="scope"
+ :link-classes="linkClasses(scope)"
+ class="gl-mb-1"
+ :href="item.link"
+ :active="urlQuery.scope ? urlQuery.scope === scope : index === 0"
+ @click="handleClick(scope)"
+ ><span>{{ item.label }}</span
+ ><span v-if="item.count" class="gl-font-sm gl-font-weight-normal">
+ {{ showFormatedCount(item.count) }}
+ </span>
+ </gl-nav-item>
+ </gl-nav>
+ <hr class="gl-mt-5 gl-mb-0 gl-border-gray-100 gl-md-display-none" />
+ </nav>
+</template>
diff --git a/app/assets/javascripts/search/sidebar/constants/index.js b/app/assets/javascripts/search/sidebar/constants/index.js
new file mode 100644
index 00000000000..3621138afe4
--- /dev/null
+++ b/app/assets/javascripts/search/sidebar/constants/index.js
@@ -0,0 +1,11 @@
+export const SCOPE_ISSUES = 'issues';
+export const SCOPE_MERGE_REQUESTS = 'merge_requests';
+
+export const NUMBER_FORMATING_OPTIONS = { notation: 'compact', compactDisplay: 'short' };
+export const NAV_LINK_DEFAULT_CLASSES = [
+ 'gl-display-flex',
+ 'gl-flex-direction-row',
+ 'gl-flex-wrap-nowrap',
+ 'gl-justify-content-space-between',
+ 'gl-text-gray-900',
+];
diff --git a/app/assets/javascripts/search/store/actions.js b/app/assets/javascripts/search/store/actions.js
index be5742e5949..2a1b744561d 100644
--- a/app/assets/javascripts/search/store/actions.js
+++ b/app/assets/javascripts/search/store/actions.js
@@ -1,6 +1,8 @@
import Api from '~/api';
import { createAlert } from '~/flash';
+import axios from '~/lib/utils/axios_utils';
import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
+import { logError } from '~/lib/logger';
import { __ } from '~/locale';
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY, SIDEBAR_PARAMS } from './constants';
import * as types from './mutation_types';
@@ -99,3 +101,19 @@ export const applyQuery = ({ state }) => {
export const resetQuery = ({ state }) => {
visitUrl(setUrlParams({ ...state.query, page: null, state: null, confidential: null }));
};
+
+export const fetchSidebarCount = ({ commit, state }) => {
+ const promises = Object.keys(state.navigation).map((scope) => {
+ // active nav item has count already so we skip it
+ if (scope !== state.urlQuery.scope) {
+ return axios
+ .get(state.navigation[scope].count_link)
+ .then(({ data: { count } }) => {
+ commit(types.RECEIVE_NAVIGATION_COUNT, { key: scope, count });
+ })
+ .catch((e) => logError(e));
+ }
+ return Promise.resolve();
+ });
+ return Promise.all(promises);
+};
diff --git a/app/assets/javascripts/search/store/index.js b/app/assets/javascripts/search/store/index.js
index 4fa88822722..e20a43808cf 100644
--- a/app/assets/javascripts/search/store/index.js
+++ b/app/assets/javascripts/search/store/index.js
@@ -7,11 +7,11 @@ import createState from './state';
Vue.use(Vuex);
-export const getStoreConfig = ({ query }) => ({
+export const getStoreConfig = ({ query, navigation }) => ({
actions,
getters,
mutations,
- state: createState({ query }),
+ state: createState({ query, navigation }),
});
const createStore = (config) => new Vuex.Store(getStoreConfig(config));
diff --git a/app/assets/javascripts/search/store/mutation_types.js b/app/assets/javascripts/search/store/mutation_types.js
index bf1e3e79cba..511b93cad2b 100644
--- a/app/assets/javascripts/search/store/mutation_types.js
+++ b/app/assets/javascripts/search/store/mutation_types.js
@@ -10,3 +10,4 @@ export const SET_QUERY = 'SET_QUERY';
export const SET_SIDEBAR_DIRTY = 'SET_SIDEBAR_DIRTY';
export const LOAD_FREQUENT_ITEMS = 'LOAD_FREQUENT_ITEMS';
+export const RECEIVE_NAVIGATION_COUNT = 'RECEIVE_NAVIGATION_COUNT';
diff --git a/app/assets/javascripts/search/store/mutations.js b/app/assets/javascripts/search/store/mutations.js
index 5d154fe3aa0..c1339845272 100644
--- a/app/assets/javascripts/search/store/mutations.js
+++ b/app/assets/javascripts/search/store/mutations.js
@@ -32,4 +32,8 @@ export default {
[types.LOAD_FREQUENT_ITEMS](state, { key, data }) {
state.frequentItems[key] = data;
},
+ [types.RECEIVE_NAVIGATION_COUNT](state, { key, count }) {
+ const item = { ...state.navigation[key], count };
+ state.navigation = { ...state.navigation, [key]: item };
+ },
};
diff --git a/app/assets/javascripts/search/store/state.js b/app/assets/javascripts/search/store/state.js
index d4005697f35..b64231a8688 100644
--- a/app/assets/javascripts/search/store/state.js
+++ b/app/assets/javascripts/search/store/state.js
@@ -1,7 +1,7 @@
import { cloneDeep } from 'lodash';
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from './constants';
-const createState = ({ query }) => ({
+const createState = ({ query, navigation }) => ({
urlQuery: cloneDeep(query),
query,
groups: [],
@@ -13,5 +13,6 @@ const createState = ({ query }) => ({
[PROJECTS_LOCAL_STORAGE_KEY]: [],
},
sidebarDirty: false,
+ navigation,
});
export default createState;
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 b14e816a674..ffba3aac681 100644
--- a/app/assets/javascripts/self_monitor/components/self_monitor_form.vue
+++ b/app/assets/javascripts/self_monitor/components/self_monitor_form.vue
@@ -29,7 +29,7 @@ export default {
SafeHtml: GlSafeHtmlDirective,
},
formLabels: {
- createProject: __('Self monitoring'),
+ createProject: __('Self-monitoring'),
},
data() {
return {
@@ -60,7 +60,7 @@ export default {
if (this.projectCreated) {
return sprintf(
s__(
- 'SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance.',
+ 'SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance.',
),
{
projectLinkStart: `<a href="${this.selfMonitorProjectFullUrl}">`,
@@ -71,7 +71,7 @@ export default {
}
return s__(
- 'SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance.',
+ 'SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance.',
);
},
helpDocsPath() {
@@ -139,11 +139,11 @@ export default {
<h4
class="js-section-header settings-title js-settings-toggle js-settings-toggle-trigger-only"
>
- {{ s__('SelfMonitoring|Self monitoring') }}
+ {{ s__('SelfMonitoring|Self-monitoring') }}
</h4>
<gl-button class="js-settings-toggle">{{ __('Expand') }}</gl-button>
<p class="js-section-sub-header">
- {{ s__('SelfMonitoring|Activate or deactivate instance self monitoring.') }}
+ {{ s__('SelfMonitoring|Activate or deactivate instance self-monitoring.') }}
<gl-link :href="helpDocsPath">{{ __('Learn more.') }}</gl-link>
</p>
</div>
@@ -160,9 +160,9 @@ export default {
</form>
</div>
<gl-modal
- :title="s__('SelfMonitoring|Deactivate self monitoring?')"
+ :title="s__('SelfMonitoring|Deactivate self-monitoring?')"
:modal-id="modalId"
- :ok-title="__('Delete self monitoring project')"
+ :ok-title="__('Delete self-monitoring project')"
:cancel-title="__('Cancel')"
ok-variant="danger"
category="primary"
@@ -172,7 +172,7 @@ export default {
<div>
{{
s__(
- 'SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?',
+ 'SelfMonitoring|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?',
)
}}
</div>
diff --git a/app/assets/javascripts/self_monitor/store/actions.js b/app/assets/javascripts/self_monitor/store/actions.js
index f37b654b00a..5b9e994290c 100644
--- a/app/assets/javascripts/self_monitor/store/actions.js
+++ b/app/assets/javascripts/self_monitor/store/actions.js
@@ -56,7 +56,7 @@ export const requestCreateProjectSuccess = ({ commit, dispatch }, selfMonitorDat
commit(types.SET_LOADING, false);
commit(types.SET_PROJECT_URL, selfMonitorData.project_full_path);
commit(types.SET_ALERT_CONTENT, {
- message: s__('SelfMonitoring|Self monitoring project successfully created.'),
+ message: s__('SelfMonitoring|Self-monitoring project successfully created.'),
actionText: __('View project'),
actionName: 'viewSelfMonitorProject',
});
@@ -108,7 +108,7 @@ export const requestDeleteProjectSuccess = ({ commit }) => {
commit(types.SET_PROJECT_URL, '');
commit(types.SET_PROJECT_CREATED, false);
commit(types.SET_ALERT_CONTENT, {
- message: s__('SelfMonitoring|Self monitoring project successfully deleted.'),
+ message: s__('SelfMonitoring|Self-monitoring project successfully deleted.'),
actionText: __('Undo'),
actionName: 'createProject',
});
diff --git a/app/assets/javascripts/sentry/constants.js b/app/assets/javascripts/sentry/constants.js
new file mode 100644
index 00000000000..fd96da5faf6
--- /dev/null
+++ b/app/assets/javascripts/sentry/constants.js
@@ -0,0 +1,43 @@
+import { __ } from '~/locale';
+
+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/sentry_config.js b/app/assets/javascripts/sentry/sentry_config.js
index 8f3c4c644bf..4c5b8dbad5a 100644
--- a/app/assets/javascripts/sentry/sentry_config.js
+++ b/app/assets/javascripts/sentry/sentry_config.js
@@ -1,52 +1,11 @@
import * as Sentry from '@sentry/browser';
import $ from 'jquery';
import { __ } from '~/locale';
-
-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',
-];
-
-const BLACKLIST_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,
-];
-
-const SAMPLE_RATE = 0.95;
+import { IGNORE_ERRORS, DENY_URLS, SAMPLE_RATE } from './constants';
const SentryConfig = {
IGNORE_ERRORS,
- BLACKLIST_URLS,
+ BLACKLIST_URLS: DENY_URLS,
SAMPLE_RATE,
init(options = {}) {
this.options = options;
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue
index 6e18cf36690..2a9100f0cb5 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue
@@ -55,6 +55,7 @@ export default {
class="js-sidebar-dropdown-toggle edit-link btn gl-text-gray-900! gl-ml-auto hide-collapsed btn-default btn-sm gl-button btn-default-tertiary float-right"
href="#"
data-test-id="edit-link"
+ data-qa-selector="edit_link"
data-track-action="click_edit_button"
data-track-label="right_sidebar"
data-track-property="assignee"
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignees.vue b/app/assets/javascripts/sidebar/components/assignees/assignees.vue
index 29ea390a81d..cf07752a0b8 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignees.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignees.vue
@@ -56,6 +56,7 @@ export default {
type="button"
class="gl-button btn-link gl-reset-color!"
data-testid="assign-yourself"
+ data-qa-selector="assign_yourself_button"
@click="assignSelf"
>
{{ __('assign yourself') }}
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 0e4d4c74160..d83ae782e26 100644
--- a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
@@ -91,6 +91,7 @@ export default {
<div
class="gl-ml-3 gl-line-height-normal gl-display-grid gl-align-items-center"
data-testid="username"
+ data-qa-selector="username"
>
<user-name-with-status :name="user.name" :availability="userAvailability(user)" />
</div>
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 98468583992..c262d65f6ce 100644
--- a/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue
+++ b/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue
@@ -170,7 +170,7 @@ export default {
this.$emit('closeForm');
},
openDatePicker() {
- this.$refs.datePicker.calendar.show();
+ this.$refs.datePicker.show();
},
setFixedDate(isFixed) {
const date = this.issuable[dateFields[this.dateType].dateFixed];
diff --git a/app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue b/app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue
new file mode 100644
index 00000000000..1fff089eab4
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue
@@ -0,0 +1,115 @@
+<script>
+import { GlDropdownItem } from '@gitlab/ui';
+import { TYPE_MILESTONE } from '~/graphql_shared/constants';
+import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { IssuableType, WorkspaceType } from '~/issues/constants';
+import { __ } from '~/locale';
+import { IssuableAttributeType } from '../../constants';
+import SidebarDropdown from '../sidebar_dropdown.vue';
+
+const noMilestone = {
+ id: 0,
+ title: __('No milestone'),
+};
+
+const placeholderMilestone = {
+ id: -1,
+ title: __('Select milestone'),
+};
+
+export default {
+ issuableAttribute: IssuableAttributeType.Milestone,
+ components: {
+ GlDropdownItem,
+ SidebarDropdown,
+ },
+ props: {
+ attrWorkspacePath: {
+ required: true,
+ type: String,
+ },
+ canAdminMilestone: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ issuableType: {
+ type: String,
+ required: true,
+ validator(value) {
+ return [IssuableType.Issue, IssuableType.MergeRequest].includes(value);
+ },
+ },
+ inputName: {
+ type: String,
+ required: false,
+ default: 'update[milestone_id]',
+ },
+ milestoneId: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ milestoneTitle: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ projectMilestonesPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ workspaceType: {
+ type: String,
+ required: true,
+ validator(value) {
+ return [WorkspaceType.group, WorkspaceType.project].includes(value);
+ },
+ },
+ },
+ data() {
+ return {
+ milestone: this.milestoneId
+ ? { id: convertToGraphQLId(TYPE_MILESTONE, this.milestoneId), title: this.milestoneTitle }
+ : placeholderMilestone,
+ };
+ },
+ computed: {
+ footerItemText() {
+ return this.canAdminMilestone ? __('Manage milestones') : __('View milestones');
+ },
+ value() {
+ return this.milestone.id === placeholderMilestone.id
+ ? undefined
+ : getIdFromGraphQLId(this.milestone.id);
+ },
+ },
+ methods: {
+ handleChange(milestone) {
+ this.milestone = milestone.id === null ? noMilestone : milestone;
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <input type="hidden" :name="inputName" :value="value" />
+ <sidebar-dropdown
+ :attr-workspace-path="attrWorkspacePath"
+ :current-attribute="milestone"
+ :issuable-attribute="$options.issuableAttribute"
+ :issuable-type="issuableType"
+ :workspace-type="workspaceType"
+ data-qa-selector="issuable_milestone_dropdown"
+ @change="handleChange"
+ >
+ <template #footer>
+ <gl-dropdown-item v-if="projectMilestonesPath" :href="projectMilestonesPath">
+ {{ footerItemText }}
+ </gl-dropdown-item>
+ </template>
+ </sidebar-dropdown>
+ </div>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
index ad061dd2e6b..5f1350690eb 100644
--- a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
+++ b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
@@ -9,6 +9,8 @@ import eventHub from '~/sidebar/event_hub';
import Store from '~/sidebar/stores/sidebar_store';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import getMergeRequestReviewersQuery from '~/vue_shared/components/sidebar/queries/get_merge_request_reviewers.query.graphql';
+import mergeRequestReviewersUpdatedSubscription from '~/vue_shared/components/sidebar/queries/merge_request_reviewers.subscription.graphql';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import ReviewerTitle from './reviewer_title.vue';
import Reviewers from './reviewers.vue';
@@ -66,6 +68,36 @@ export default {
error() {
createAlert({ message: __('An error occurred while fetching reviewers.') });
},
+ subscribeToMore: {
+ document() {
+ return mergeRequestReviewersUpdatedSubscription;
+ },
+ variables() {
+ return {
+ issuableId: this.issuable?.id,
+ };
+ },
+ skip() {
+ return !this.issuable?.id || !this.isRealtimeEnabled;
+ },
+ updateQuery(
+ _,
+ {
+ subscriptionData: {
+ data: { mergeRequestReviewersUpdated },
+ },
+ },
+ ) {
+ if (mergeRequestReviewersUpdated) {
+ this.store.setReviewersFromRealtime(
+ mergeRequestReviewersUpdated.reviewers.nodes.map((r) => ({
+ ...r,
+ id: getIdFromGraphQLId(r.id),
+ })),
+ );
+ }
+ },
+ },
},
},
data() {
@@ -87,6 +119,9 @@ export default {
canUpdate() {
return this.issuable.userPermissions?.adminMergeRequest || false;
},
+ isRealtimeEnabled() {
+ return this.glFeatures.realtimeReviewers;
+ },
},
created() {
this.store = new Store();
diff --git a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers_inputs.vue b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers_inputs.vue
new file mode 100644
index 00000000000..a135dfdca72
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers_inputs.vue
@@ -0,0 +1,34 @@
+<script>
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { state } from './sidebar_reviewers.vue';
+
+export default {
+ data() {
+ return state;
+ },
+ computed: {
+ reviewers() {
+ return this.issuable?.reviewers?.nodes || [];
+ },
+ },
+ methods: {
+ getIdFromGraphQLId,
+ },
+};
+</script>
+
+<template>
+ <div>
+ <input
+ v-for="reviewer in reviewers"
+ :key="reviewer.id"
+ type="hidden"
+ name="merge_request[reviewer_ids][]"
+ :value="getIdFromGraphQLId(reviewer.id)"
+ :data-avatar-url="reviewer.avatarUrl"
+ :data-name="reviewer.name"
+ :data-username="reviewer.username"
+ :data-can-merge="reviewer.mergeRequestInteraction.canMerge"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue
new file mode 100644
index 00000000000..26e2bc96f54
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue
@@ -0,0 +1,252 @@
+<script>
+import {
+ GlDropdown,
+ GlDropdownDivider,
+ GlDropdownItem,
+ GlDropdownText,
+ GlLoadingIcon,
+ GlSearchBoxByType,
+} from '@gitlab/ui';
+import { kebabCase, snakeCase } from 'lodash';
+import { IssuableType, WorkspaceType } from '~/issues/constants';
+import { __ } from '~/locale';
+import {
+ defaultEpicSort,
+ dropdowni18nText,
+ epicIidPattern,
+ issuableAttributesQueries,
+ IssuableAttributeState,
+ IssuableAttributeType,
+ IssuableAttributeTypeKeyMap,
+ LocalizedIssuableAttributeType,
+ noAttributeId,
+} from 'ee_else_ce/sidebar/constants';
+import { createAlert } from '~/flash';
+import { PathIdSeparator } from '~/related_issues/constants';
+
+export default {
+ noAttributeId,
+ i18n: {
+ expired: __('(expired)'),
+ },
+ components: {
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownText,
+ GlDropdownDivider,
+ GlSearchBoxByType,
+ GlLoadingIcon,
+ },
+ inject: {
+ issuableAttributesQueries: {
+ default: issuableAttributesQueries,
+ },
+ issuableAttributesState: {
+ default: IssuableAttributeState,
+ },
+ widgetTitleText: {
+ default: {
+ [IssuableAttributeType.Milestone]: __('Milestone'),
+ expired: __('(expired)'),
+ none: __('None'),
+ },
+ },
+ },
+ props: {
+ attrWorkspacePath: {
+ required: true,
+ type: String,
+ },
+ currentAttribute: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ issuableAttribute: {
+ type: String,
+ required: true,
+ },
+ issuableType: {
+ type: String,
+ required: true,
+ validator(value) {
+ return [IssuableType.Issue, IssuableType.MergeRequest].includes(value);
+ },
+ },
+ workspaceType: {
+ type: String,
+ required: false,
+ default: WorkspaceType.project,
+ validator(value) {
+ return [WorkspaceType.group, WorkspaceType.project].includes(value);
+ },
+ },
+ },
+ data() {
+ return {
+ attributesList: [],
+ searchTerm: '',
+ skipQuery: true,
+ };
+ },
+ apollo: {
+ attributesList: {
+ query() {
+ const { list } = this.issuableAttributeQuery;
+ const { query } = list[this.issuableType];
+ return query[this.workspaceType] || query;
+ },
+ variables() {
+ if (!this.isEpic) {
+ return {
+ fullPath: this.attrWorkspacePath,
+ title: this.searchTerm,
+ state: this.issuableAttributesState[this.issuableAttribute],
+ };
+ }
+
+ const variables = {
+ fullPath: this.attrWorkspacePath,
+ state: this.issuableAttributesState[this.issuableAttribute],
+ sort: defaultEpicSort,
+ };
+
+ if (epicIidPattern.test(this.searchTerm)) {
+ const matches = this.searchTerm.match(epicIidPattern);
+ variables.iidStartsWith = matches.groups.iid;
+ } else if (this.searchTerm !== '') {
+ variables.in = 'TITLE';
+ variables.title = this.searchTerm;
+ }
+
+ return variables;
+ },
+ update: (data) => data?.workspace?.attributes?.nodes ?? [],
+ error(error) {
+ createAlert({ message: this.i18n.listFetchError, captureError: true, error });
+ },
+ skip() {
+ if (
+ this.isEpic &&
+ this.searchTerm.startsWith(PathIdSeparator.Epic) &&
+ this.searchTerm.length < 2
+ ) {
+ return true;
+ }
+ return this.skipQuery;
+ },
+ debounce: 250,
+ },
+ },
+ computed: {
+ attributeTypeTitle() {
+ return this.widgetTitleText[this.issuableAttribute];
+ },
+ dropdownText() {
+ return this.currentAttribute ? this.currentAttribute?.title : this.attributeTypeTitle;
+ },
+ emptyPropsList() {
+ return this.attributesList.length === 0;
+ },
+ i18n() {
+ const localizedAttribute =
+ LocalizedIssuableAttributeType[IssuableAttributeTypeKeyMap[this.issuableAttribute]];
+ return dropdowni18nText(localizedAttribute, this.issuableType);
+ },
+ isEpic() {
+ // MV to EE https://gitlab.com/gitlab-org/gitlab/-/issues/345311
+ return this.issuableAttribute === IssuableType.Epic;
+ },
+ issuableAttributeQuery() {
+ return this.issuableAttributesQueries[this.issuableAttribute];
+ },
+ formatIssuableAttribute() {
+ return {
+ kebab: kebabCase(this.issuableAttribute),
+ snake: snakeCase(this.issuableAttribute),
+ };
+ },
+ },
+ methods: {
+ isAttributeChecked(attributeId) {
+ return (
+ attributeId === this.currentAttribute?.id || (!this.currentAttribute?.id && !attributeId)
+ );
+ },
+ isAttributeOverdue(attribute) {
+ return this.issuableAttribute === IssuableAttributeType.Milestone
+ ? attribute?.expired
+ : false;
+ },
+ handleShow() {
+ this.skipQuery = false;
+ },
+ setFocus() {
+ this.$refs.search.focusInput();
+ },
+ show() {
+ this.$refs.dropdown.show();
+ },
+ updateAttribute(attribute) {
+ this.$emit('change', attribute);
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-dropdown
+ ref="dropdown"
+ block
+ :header-text="i18n.assignAttribute"
+ lazy
+ :text="dropdownText"
+ toggle-class="gl-m-0"
+ @show="handleShow"
+ @shown="setFocus"
+ >
+ <gl-search-box-by-type ref="search" v-model="searchTerm" :placeholder="__('Search')" />
+ <gl-dropdown-item
+ :data-testid="`no-${formatIssuableAttribute.kebab}-item`"
+ is-check-item
+ :is-checked="isAttributeChecked($options.noAttributeId)"
+ @click="$emit('change', { id: $options.noAttributeId })"
+ >
+ {{ i18n.noAttribute }}
+ </gl-dropdown-item>
+ <gl-dropdown-divider />
+ <gl-loading-icon
+ v-if="$apollo.queries.attributesList.loading"
+ size="sm"
+ class="gl-py-4"
+ data-testid="loading-icon-dropdown"
+ />
+ <template v-else>
+ <gl-dropdown-text v-if="emptyPropsList">
+ {{ i18n.noAttributesFound }}
+ </gl-dropdown-text>
+ <slot
+ v-else
+ name="list"
+ :attributes-list="attributesList"
+ :is-attribute-checked="isAttributeChecked"
+ :update-attribute="updateAttribute"
+ >
+ <gl-dropdown-item
+ v-for="attrItem in attributesList"
+ :key="attrItem.id"
+ is-check-item
+ :is-checked="isAttributeChecked(attrItem.id)"
+ :data-testid="`${formatIssuableAttribute.kebab}-items`"
+ @click="updateAttribute(attrItem)"
+ >
+ {{ attrItem.title }}
+ <template v-if="isAttributeOverdue(attrItem)">{{ $options.i18n.expired }}</template>
+ </gl-dropdown-item>
+ </slot>
+ </template>
+ <template #footer>
+ <slot name="footer"></slot>
+ </template>
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue
index c33b1468ca4..a685929cdea 100644
--- a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue
+++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue
@@ -1,17 +1,5 @@
<script>
-import {
- GlLink,
- GlDropdown,
- GlDropdownItem,
- GlDropdownText,
- GlSearchBoxByType,
- GlDropdownDivider,
- GlLoadingIcon,
- GlIcon,
- GlTooltipDirective,
- GlPopover,
- GlButton,
-} from '@gitlab/ui';
+import { GlButton, GlIcon, GlLink, GlPopover, GlTooltipDirective } from '@gitlab/ui';
import { kebabCase, snakeCase } from 'lodash';
import { createAlert } from '~/flash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
@@ -22,19 +10,15 @@ import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue'
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import {
dropdowni18nText,
- Tracking,
- IssuableAttributeState,
- IssuableAttributeType,
LocalizedIssuableAttributeType,
IssuableAttributeTypeKeyMap,
issuableAttributesQueries,
- noAttributeId,
- defaultEpicSort,
- epicIidPattern,
+ IssuableAttributeType,
+ Tracking,
} from 'ee_else_ce/sidebar/constants';
+import SidebarDropdown from './sidebar_dropdown.vue';
export default {
- noAttributeId,
i18n: {
expired: __('(expired)'),
none: __('None'),
@@ -43,17 +27,12 @@ export default {
GlTooltip: GlTooltipDirective,
},
components: {
- SidebarEditableItem,
GlLink,
- GlDropdown,
- GlDropdownItem,
- GlDropdownText,
- GlDropdownDivider,
- GlSearchBoxByType,
GlIcon,
- GlLoadingIcon,
GlPopover,
GlButton,
+ SidebarDropdown,
+ SidebarEditableItem,
},
mixins: [glFeatureFlagMixin()],
inject: {
@@ -63,9 +42,6 @@ export default {
issuableAttributesQueries: {
default: issuableAttributesQueries,
},
- issuableAttributesState: {
- default: IssuableAttributeState,
- },
widgetTitleText: {
default: {
[IssuableAttributeType.Milestone]: __('Milestone'),
@@ -74,7 +50,6 @@ export default {
},
},
},
-
props: {
issuableAttribute: {
type: String,
@@ -134,67 +109,14 @@ export default {
});
},
},
- attributesList: {
- query() {
- const { list } = this.issuableAttributeQuery;
- const { query } = list[this.issuableType];
-
- return query;
- },
- skip() {
- if (this.isEpic && this.searchTerm.startsWith('&') && this.searchTerm.length < 2) {
- return true;
- }
-
- return !this.editing;
- },
- debounce: 250,
- variables() {
- if (!this.isEpic) {
- return {
- fullPath: this.attrWorkspacePath,
- title: this.searchTerm,
- state: this.issuableAttributesState[this.issuableAttribute],
- };
- }
-
- const variables = {
- fullPath: this.attrWorkspacePath,
- state: this.issuableAttributesState[this.issuableAttribute],
- sort: defaultEpicSort,
- };
-
- if (epicIidPattern.test(this.searchTerm)) {
- const matches = this.searchTerm.match(epicIidPattern);
- variables.iidStartsWith = matches.groups.iid;
- } else if (this.searchTerm !== '') {
- variables.in = 'TITLE';
- variables.title = this.searchTerm;
- }
-
- return variables;
- },
- update(data) {
- if (data?.workspace) {
- return data?.workspace?.attributes.nodes;
- }
- return [];
- },
- error(error) {
- createAlert({ message: this.i18n.listFetchError, captureError: true, error });
- },
- },
},
data() {
return {
- searchTerm: '',
- editing: false,
updating: false,
selectedTitle: null,
currentAttribute: null,
hasCurrentAttribute: false,
editConfirmation: false,
- attributesList: [],
tracking: {
event: Tracking.editEvent,
label: Tracking.rightSidebarLabel,
@@ -212,15 +134,9 @@ export default {
attributeUrl() {
return this.currentAttribute?.webUrl;
},
- dropdownText() {
- return this.currentAttribute ? this.currentAttribute?.title : this.attributeTypeTitle;
- },
loading() {
return this.$apollo.queries.currentAttribute.loading;
},
- emptyPropsList() {
- return this.attributesList.length === 0;
- },
attributeTypeTitle() {
return this.widgetTitleText[this.issuableAttribute];
},
@@ -256,16 +172,12 @@ export default {
},
},
methods: {
- updateAttribute(attributeId) {
- if (this.currentAttribute === null && attributeId === null) return;
- if (attributeId === this.currentAttribute?.id) return;
+ updateAttribute({ id }) {
+ if (this.currentAttribute === null && id === null) return;
+ if (id === this.currentAttribute?.id) return;
this.updating = true;
- const selectedAttribute =
- Boolean(attributeId) && this.attributesList.find((p) => p.id === attributeId);
- this.selectedTitle = selectedAttribute ? selectedAttribute.title : this.widgetTitleText.none;
-
const { current } = this.issuableAttributeQuery;
const { mutation } = current[this.issuableType];
@@ -277,8 +189,8 @@ export default {
attributeId:
this.issuableAttribute === IssuableAttributeType.Milestone &&
this.issuableType === IssuableType.Issue
- ? getIdFromGraphQLId(attributeId)
- : attributeId,
+ ? getIdFromGraphQLId(id)
+ : id,
iid: this.iid,
},
})
@@ -298,32 +210,16 @@ export default {
})
.finally(() => {
this.updating = false;
- this.searchTerm = '';
this.selectedTitle = null;
});
},
- isAttributeChecked(attributeId = undefined) {
- return (
- attributeId === this.currentAttribute?.id || (!this.currentAttribute?.id && !attributeId)
- );
- },
isAttributeOverdue(attribute) {
return this.issuableAttribute === IssuableAttributeType.Milestone
? attribute?.expired
: false;
},
showDropdown() {
- this.$refs.newDropdown.show();
- },
- handleOpen() {
- this.editing = true;
- this.showDropdown();
- },
- handleClose() {
- this.editing = false;
- },
- setFocus() {
- this.$refs.search.focusInput();
+ this.$refs.dropdown.show();
},
handlePopoverClose() {
this.$refs.popover.$emit('close');
@@ -349,8 +245,7 @@ export default {
:tracking="tracking"
:should-show-confirmation-popover="shouldShowConfirmationPopover"
:loading="updating || loading"
- @open="handleOpen"
- @close="handleClose"
+ @open="showDropdown"
@edit-confirm="handleEditConfirmation"
>
<template #collapsed>
@@ -432,58 +327,24 @@ export default {
</gl-popover>
</template>
<template v-else #default>
- <gl-dropdown
- ref="newDropdown"
- lazy
- :header-text="i18n.assignAttribute"
- :text="dropdownText"
- :loading="loading"
- class="gl-w-full"
- toggle-class="gl-max-w-100"
- block
- @shown="setFocus"
+ <sidebar-dropdown
+ ref="dropdown"
+ :attr-workspace-path="attrWorkspacePath"
+ :current-attribute="currentAttribute"
+ :issuable-attribute="issuableAttribute"
+ :issuable-type="issuableType"
+ @change="updateAttribute"
>
- <gl-search-box-by-type ref="search" v-model="searchTerm" />
- <gl-dropdown-item
- :data-testid="`no-${formatIssuableAttribute.kebab}-item`"
- is-check-item
- :is-checked="isAttributeChecked($options.noAttributeId)"
- @click="updateAttribute($options.noAttributeId)"
- >
- {{ i18n.noAttribute }}
- </gl-dropdown-item>
- <gl-dropdown-divider />
- <gl-loading-icon
- v-if="$apollo.queries.attributesList.loading"
- size="sm"
- class="gl-py-4"
- data-testid="loading-icon-dropdown"
- />
- <template v-else>
- <gl-dropdown-text v-if="emptyPropsList">
- {{ i18n.noAttributesFound }}
- </gl-dropdown-text>
+ <template #list="{ attributesList, isAttributeChecked, updateAttribute: update }">
<slot
- v-else
name="list"
:attributes-list="attributesList"
:is-attribute-checked="isAttributeChecked"
- :update-attribute="updateAttribute"
+ :update-attribute="update"
>
- <gl-dropdown-item
- v-for="attrItem in attributesList"
- :key="attrItem.id"
- is-check-item
- :is-checked="isAttributeChecked(attrItem.id)"
- :data-testid="`${formatIssuableAttribute.kebab}-items`"
- @click="updateAttribute(attrItem.id)"
- >
- {{ attrItem.title }}
- <span v-if="isAttributeOverdue(attrItem)">{{ $options.i18n.expired }}</span>
- </gl-dropdown-item>
</slot>
</template>
- </gl-dropdown>
+ </sidebar-dropdown>
</template>
</sidebar-editable-item>
</template>
diff --git a/app/assets/javascripts/sidebar/constants.js b/app/assets/javascripts/sidebar/constants.js
index 6248bcb8e2d..67b9b540e91 100644
--- a/app/assets/javascripts/sidebar/constants.js
+++ b/app/assets/javascripts/sidebar/constants.js
@@ -53,6 +53,7 @@ import updateIssueAssigneesMutation from '~/vue_shared/components/sidebar/querie
import updateMergeRequestAssigneesMutation from '~/vue_shared/components/sidebar/queries/update_mr_assignees.mutation.graphql';
import getEscalationStatusQuery from '~/sidebar/queries/escalation_status.query.graphql';
import updateEscalationStatusMutation from '~/sidebar/queries/update_escalation_status.mutation.graphql';
+import groupMilestonesQuery from './queries/group_milestones.query.graphql';
import projectIssueMilestoneMutation from './queries/project_issue_milestone.mutation.graphql';
import projectIssueMilestoneQuery from './queries/project_issue_milestone.query.graphql';
import projectMilestonesQuery from './queries/project_milestones.query.graphql';
@@ -241,10 +242,16 @@ export const issuableMilestoneQueries = {
export const milestonesQueries = {
[IssuableType.Issue]: {
- query: projectMilestonesQuery,
+ query: {
+ [WorkspaceType.group]: groupMilestonesQuery,
+ [WorkspaceType.project]: projectMilestonesQuery,
+ },
},
[IssuableType.MergeRequest]: {
- query: projectMilestonesQuery,
+ query: {
+ [WorkspaceType.group]: groupMilestonesQuery,
+ [WorkspaceType.project]: projectMilestonesQuery,
+ },
},
};
diff --git a/app/assets/javascripts/sidebar/mount_milestone_sidebar.js b/app/assets/javascripts/sidebar/mount_milestone_sidebar.js
index cc5de5e4083..afce59d304f 100644
--- a/app/assets/javascripts/sidebar/mount_milestone_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_milestone_sidebar.js
@@ -5,7 +5,7 @@ import TimeTracker from './components/time_tracking/time_tracker.vue';
export default class SidebarMilestone {
constructor() {
- const el = document.getElementById('issuable-time-tracker');
+ const el = document.querySelector('.js-sidebar-time-tracking-root');
if (!el) return;
diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js
index 9b5bad710dd..b37486283ca 100644
--- a/app/assets/javascripts/sidebar/mount_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_sidebar.js
@@ -18,6 +18,7 @@ import CollapsedAssigneeList from '~/sidebar/components/assignees/collapsed_assi
import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue';
import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue';
import SidebarDueDateWidget from '~/sidebar/components/date/sidebar_date_widget.vue';
+import MilestoneDropdown from '~/sidebar/components/milestone/milestone_dropdown.vue';
import SidebarParticipantsWidget from '~/sidebar/components/participants/sidebar_participants_widget.vue';
import SidebarReferenceWidget from '~/sidebar/components/reference/sidebar_reference_widget.vue';
import SidebarDropdownWidget from '~/sidebar/components/sidebar_dropdown_widget.vue';
@@ -33,6 +34,7 @@ import CopyEmailToClipboard from './components/copy_email_to_clipboard.vue';
import SidebarEscalationStatus from './components/incidents/sidebar_escalation_status.vue';
import IssuableLockForm from './components/lock/issuable_lock_form.vue';
import SidebarReviewers from './components/reviewers/sidebar_reviewers.vue';
+import SidebarReviewersInputs from './components/reviewers/sidebar_reviewers_inputs.vue';
import SidebarSeverity from './components/severity/sidebar_severity.vue';
import SidebarSubscriptionsWidget from './components/subscriptions/sidebar_subscriptions_widget.vue';
import SidebarTimeTracking from './components/time_tracking/sidebar_time_tracking.vue';
@@ -47,27 +49,24 @@ function getSidebarOptions(sidebarOptEl = document.querySelector('.js-sidebar-op
return JSON.parse(sidebarOptEl.innerHTML);
}
-function mountSidebarToDoWidget() {
- const el = document.querySelector('.js-issuable-todo');
+function mountSidebarTodoWidget() {
+ const el = document.querySelector('.js-sidebar-todo-widget-root');
if (!el) {
- return false;
+ return null;
}
const { projectPath, iid, id } = el.dataset;
return new Vue({
el,
- name: 'SidebarTodoRoot',
+ name: 'SidebarTodoWidgetRoot',
apolloProvider,
- components: {
- SidebarTodoWidget,
- },
provide: {
isClassicSidebar: true,
},
render: (createElement) =>
- createElement('sidebar-todo-widget', {
+ createElement(SidebarTodoWidget, {
props: {
fullPath: projectPath,
issuableId:
@@ -97,23 +96,22 @@ function getSidebarAssigneeAvailabilityData() {
);
}
-function mountAssigneesComponentDeprecated(mediator) {
- const el = document.getElementById('js-vue-sidebar-assignees');
+function mountSidebarAssigneesDeprecated(mediator) {
+ const el = document.querySelector('.js-sidebar-assignees-root');
- if (!el) return;
+ if (!el) {
+ return null;
+ }
const { id, iid, fullPath } = getSidebarOptions();
const assigneeAvailabilityStatus = getSidebarAssigneeAvailabilityData();
- // eslint-disable-next-line no-new
- new Vue({
+
+ return new Vue({
el,
name: 'SidebarAssigneesRoot',
apolloProvider,
- components: {
- SidebarAssignees,
- },
render: (createElement) =>
- createElement('sidebar-assignees', {
+ createElement(SidebarAssignees, {
props: {
mediator,
issuableIid: String(iid),
@@ -131,10 +129,12 @@ function mountAssigneesComponentDeprecated(mediator) {
});
}
-function mountAssigneesComponent() {
- const el = document.getElementById('js-vue-sidebar-assignees');
+function mountSidebarAssigneesWidget() {
+ const el = document.querySelector('.js-sidebar-assignees-root');
- if (!el) return;
+ if (!el) {
+ return;
+ }
const { id, iid, fullPath, editable } = getSidebarOptions();
const isIssuablePage = isInIssuePage() || isInIncidentPage() || isInDesignPage();
@@ -144,9 +144,6 @@ function mountAssigneesComponent() {
el,
name: 'SidebarAssigneesRoot',
apolloProvider,
- components: {
- SidebarAssigneesWidget,
- },
provide: {
canUpdate: editable,
directlyInviteMembers: Object.prototype.hasOwnProperty.call(
@@ -155,7 +152,7 @@ function mountAssigneesComponent() {
),
},
render: (createElement) =>
- createElement('sidebar-assignees-widget', {
+ createElement(SidebarAssigneesWidget, {
props: {
iid: String(iid),
fullPath,
@@ -183,10 +180,12 @@ function mountAssigneesComponent() {
}
}
-function mountReviewersComponent(mediator) {
- const el = document.getElementById('js-vue-sidebar-reviewers');
+function mountSidebarReviewers(mediator) {
+ const el = document.querySelector('.js-sidebar-reviewers-root');
- if (!el) return;
+ if (!el) {
+ return;
+ }
const { iid, fullPath } = getSidebarOptions();
// eslint-disable-next-line no-new
@@ -194,11 +193,8 @@ function mountReviewersComponent(mediator) {
el,
name: 'SidebarReviewersRoot',
apolloProvider,
- components: {
- SidebarReviewers,
- },
render: (createElement) =>
- createElement('sidebar-reviewers', {
+ createElement(SidebarReviewers, {
props: {
mediator,
issuableIid: String(iid),
@@ -210,6 +206,18 @@ function mountReviewersComponent(mediator) {
}),
});
+ const reviewersInputEl = document.querySelector('.js-reviewers-inputs');
+
+ if (reviewersInputEl) {
+ // eslint-disable-next-line no-new
+ new Vue({
+ el: reviewersInputEl,
+ render(createElement) {
+ return createElement(SidebarReviewersInputs);
+ },
+ });
+ }
+
const reviewerDropdown = document.querySelector('.js-sidebar-reviewer-dropdown');
if (reviewerDropdown) {
@@ -217,22 +225,21 @@ function mountReviewersComponent(mediator) {
}
}
-function mountCrmContactsComponent() {
- const el = document.getElementById('js-issue-crm-contacts');
+function mountSidebarCrmContacts() {
+ const el = document.querySelector('.js-sidebar-crm-contacts-root');
- if (!el) return;
+ if (!el) {
+ return null;
+ }
const { issueId, groupIssuesPath } = el.dataset;
- // eslint-disable-next-line no-new
- new Vue({
+
+ return new Vue({
el,
name: 'SidebarCrmContactsRoot',
apolloProvider,
- components: {
- CrmContacts,
- },
render: (createElement) =>
- createElement('crm-contacts', {
+ createElement(CrmContacts, {
props: {
issueId,
groupIssuesPath,
@@ -241,28 +248,25 @@ function mountCrmContactsComponent() {
});
}
-function mountMilestoneSelect() {
- const el = document.querySelector('.js-milestone-select');
+function mountSidebarMilestoneWidget() {
+ const el = document.querySelector('.js-sidebar-milestone-widget-root');
if (!el) {
- return false;
+ return null;
}
const { canEdit, projectPath, issueIid } = el.dataset;
return new Vue({
el,
- name: 'SidebarMilestoneRoot',
+ name: 'SidebarMilestoneWidgetRoot',
apolloProvider,
- components: {
- SidebarDropdownWidget,
- },
provide: {
canUpdate: parseBoolean(canEdit),
isClassicSidebar: true,
},
render: (createElement) =>
- createElement('sidebar-dropdown-widget', {
+ createElement(SidebarDropdownWidget, {
props: {
attrWorkspacePath: projectPath,
workspacePath: projectPath,
@@ -276,21 +280,57 @@ function mountMilestoneSelect() {
});
}
-export function mountSidebarLabels() {
- const el = document.querySelector('.js-sidebar-labels');
+export function mountMilestoneDropdown() {
+ const el = document.querySelector('.js-milestone-dropdown-root');
if (!el) {
- return false;
+ return null;
}
+ Vue.use(VueApollo);
+
+ const {
+ canAdminMilestone,
+ fullPath,
+ inputName,
+ milestoneId,
+ milestoneTitle,
+ projectMilestonesPath,
+ workspaceType,
+ } = el.dataset;
+
return new Vue({
el,
- name: 'SidebarLabelsRoot',
+ name: 'MilestoneDropdownRoot',
apolloProvider,
-
- components: {
- LabelsSelectWidget,
+ render(createElement) {
+ return createElement(MilestoneDropdown, {
+ props: {
+ attrWorkspacePath: fullPath,
+ canAdminMilestone,
+ inputName,
+ issuableType: isInIssuePage() ? IssuableType.Issue : IssuableType.MergeRequest,
+ milestoneId,
+ milestoneTitle,
+ projectMilestonesPath,
+ workspaceType,
+ },
+ });
},
+ });
+}
+
+export function mountSidebarLabelsWidget() {
+ const el = document.querySelector('.js-sidebar-labels-widget-root');
+
+ if (!el) {
+ return null;
+ }
+
+ return new Vue({
+ el,
+ name: 'SidebarLabelsWidgetRoot',
+ apolloProvider,
provide: {
...el.dataset,
canUpdate: parseBoolean(el.dataset.canEdit),
@@ -300,7 +340,7 @@ export function mountSidebarLabels() {
isClassicSidebar: true,
},
render: (createElement) =>
- createElement('labels-select-widget', {
+ createElement(LabelsSelectWidget, {
props: {
iid: String(el.dataset.iid),
fullPath: el.dataset.projectPath,
@@ -327,31 +367,27 @@ export function mountSidebarLabels() {
});
}
-function mountConfidentialComponent() {
- const el = document.getElementById('js-confidential-entry-point');
+function mountSidebarConfidentialityWidget() {
+ const el = document.querySelector('.js-sidebar-confidential-widget-root');
+
if (!el) {
- return;
+ return null;
}
const { fullPath, iid } = getSidebarOptions();
const dataNode = document.getElementById('js-confidential-issue-data');
const initialData = JSON.parse(dataNode.innerHTML);
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
- name: 'SidebarConfidentialRoot',
+ name: 'SidebarConfidentialityWidgetRoot',
apolloProvider,
- components: {
- SidebarConfidentialityWidget,
- },
provide: {
canUpdate: initialData.is_editable,
isClassicSidebar: true,
},
-
render: (createElement) =>
- createElement('sidebar-confidentiality-widget', {
+ createElement(SidebarConfidentialityWidget, {
props: {
iid: String(iid),
fullPath,
@@ -364,28 +400,24 @@ function mountConfidentialComponent() {
});
}
-function mountDueDateComponent() {
- const el = document.getElementById('js-due-date-entry-point');
+function mountSidebarDueDateWidget() {
+ const el = document.querySelector('.js-sidebar-due-date-widget-root');
+
if (!el) {
- return;
+ return null;
}
const { fullPath, iid, editable } = getSidebarOptions();
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
- name: 'SidebarDueDateRoot',
+ name: 'SidebarDueDateWidgetRoot',
apolloProvider,
- components: {
- SidebarDueDateWidget,
- },
provide: {
canUpdate: editable,
},
-
render: (createElement) =>
- createElement('sidebar-due-date-widget', {
+ createElement(SidebarDueDateWidget, {
props: {
iid: String(iid),
fullPath,
@@ -395,29 +427,25 @@ function mountDueDateComponent() {
});
}
-function mountReferenceComponent() {
- const el = document.getElementById('js-reference-entry-point');
+function mountSidebarReferenceWidget() {
+ const el = document.querySelector('.js-sidebar-reference-widget-root');
+
if (!el) {
- return;
+ return null;
}
const { fullPath, iid } = getSidebarOptions();
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
- name: 'SidebarReferenceRoot',
+ name: 'SidebarReferenceWidgetRoot',
apolloProvider,
- components: {
- SidebarReferenceWidget,
- },
provide: {
iid: String(iid),
fullPath,
},
-
render: (createElement) =>
- createElement('sidebar-reference-widget', {
+ createElement(SidebarReferenceWidget, {
props: {
issuableType:
isInIssuePage() || isInIncidentPage() || isInDesignPage()
@@ -428,17 +456,16 @@ function mountReferenceComponent() {
});
}
-function mountLockComponent(store) {
- const el = document.getElementById('js-lock-entry-point');
+function mountIssuableLockForm(store) {
+ const el = document.querySelector('.js-sidebar-lock-root');
if (!el || !store) {
- return;
+ return null;
}
const { fullPath, editable } = getSidebarOptions();
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
name: 'SidebarLockRoot',
store,
@@ -454,23 +481,21 @@ function mountLockComponent(store) {
});
}
-function mountParticipantsComponent() {
- const el = document.querySelector('.js-sidebar-participants-entry-point');
+function mountSidebarParticipantsWidget() {
+ const el = document.querySelector('.js-sidebar-participants-widget-root');
- if (!el) return;
+ if (!el) {
+ return null;
+ }
const { fullPath, iid } = getSidebarOptions();
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
- name: 'SidebarParticipantsRoot',
+ name: 'SidebarParticipantsWidgetRoot',
apolloProvider,
- components: {
- SidebarParticipantsWidget,
- },
render: (createElement) =>
- createElement('sidebar-participants-widget', {
+ createElement(SidebarParticipantsWidget, {
props: {
iid: String(iid),
fullPath,
@@ -483,26 +508,24 @@ function mountParticipantsComponent() {
});
}
-function mountSubscriptionsComponent() {
- const el = document.querySelector('.js-sidebar-subscriptions-entry-point');
+function mountSidebarSubscriptionsWidget() {
+ const el = document.querySelector('.js-sidebar-subscriptions-widget-root');
- if (!el) return;
+ if (!el) {
+ return null;
+ }
const { fullPath, iid, editable } = getSidebarOptions();
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
- name: 'SidebarSubscriptionsRoot',
+ name: 'SidebarSubscriptionsWidgetRoot',
apolloProvider,
- components: {
- SidebarSubscriptionsWidget,
- },
provide: {
canUpdate: editable,
},
render: (createElement) =>
- createElement('sidebar-subscriptions-widget', {
+ createElement(SidebarSubscriptionsWidget, {
props: {
iid: String(iid),
fullPath,
@@ -515,14 +538,15 @@ function mountSubscriptionsComponent() {
});
}
-function mountTimeTrackingComponent() {
- const el = document.getElementById('issuable-time-tracker');
+function mountSidebarTimeTracking() {
+ const el = document.querySelector('.js-sidebar-time-tracking-root');
const { id, iid, fullPath, issuableType, timeTrackingLimitToHours } = getSidebarOptions();
- if (!el) return;
+ if (!el) {
+ return null;
+ }
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
name: 'SidebarTimeTrackingRoot',
apolloProvider,
@@ -539,27 +563,24 @@ function mountTimeTrackingComponent() {
});
}
-function mountSeverityComponent() {
- const severityContainerEl = document.querySelector('#js-severity');
+function mountSidebarSeverity() {
+ const el = document.querySelector('.js-sidebar-severity-root');
- if (!severityContainerEl) {
- return false;
+ if (!el) {
+ return null;
}
const { fullPath, iid, severity, editable } = getSidebarOptions();
return new Vue({
- el: severityContainerEl,
+ el,
name: 'SidebarSeverityRoot',
apolloProvider,
- components: {
- SidebarSeverity,
- },
provide: {
canUpdate: editable,
},
render: (createElement) =>
- createElement('sidebar-severity', {
+ createElement(SidebarSeverity, {
props: {
projectPath: fullPath,
iid: String(iid),
@@ -569,27 +590,25 @@ function mountSeverityComponent() {
});
}
-function mountEscalationStatusComponent() {
- const statusContainerEl = document.querySelector('#js-escalation-status');
+function mountSidebarEscalationStatus() {
+ const el = document.querySelector('.js-sidebar-escalation-status-root');
- if (!statusContainerEl) {
- return false;
+ if (!el) {
+ return null;
}
const { issuableType } = getSidebarOptions();
- const { canUpdate, issueIid, projectPath } = statusContainerEl.dataset;
+ const { canUpdate, issueIid, projectPath } = el.dataset;
return new Vue({
- el: statusContainerEl,
+ el,
+ name: 'SidebarEscalationStatusRoot',
apolloProvider,
- components: {
- SidebarEscalationStatus,
- },
provide: {
canUpdate: parseBoolean(canUpdate),
},
render: (createElement) =>
- createElement('sidebar-escalation-status', {
+ createElement(SidebarEscalationStatus, {
props: {
iid: issueIid,
issuableType,
@@ -599,15 +618,16 @@ function mountEscalationStatusComponent() {
});
}
-function mountCopyEmailComponent() {
- const el = document.getElementById('issuable-copy-email');
+function mountCopyEmailToClipboard() {
+ const el = document.querySelector('.js-sidebar-copy-email-root');
- if (!el) return;
+ if (!el) {
+ return null;
+ }
const { createNoteEmail } = getSidebarOptions();
- // eslint-disable-next-line no-new
- new Vue({
+ return new Vue({
el,
name: 'SidebarCopyEmailRoot',
render: (createElement) =>
@@ -621,36 +641,32 @@ const isAssigneesWidgetShown =
export function mountSidebar(mediator, store) {
initInviteMembersModal();
initInviteMembersTrigger();
-
- mountSidebarToDoWidget();
+ mountSidebarTodoWidget();
if (isAssigneesWidgetShown) {
- mountAssigneesComponent();
+ mountSidebarAssigneesWidget();
} else {
- mountAssigneesComponentDeprecated(mediator);
+ mountSidebarAssigneesDeprecated(mediator);
}
- mountReviewersComponent(mediator);
- mountCrmContactsComponent();
- mountSidebarLabels();
- mountMilestoneSelect();
- mountConfidentialComponent(mediator);
- mountDueDateComponent(mediator);
- mountReferenceComponent(mediator);
- mountLockComponent(store);
- mountParticipantsComponent();
- mountSubscriptionsComponent();
- mountCopyEmailComponent();
+ mountSidebarReviewers(mediator);
+ mountSidebarCrmContacts();
+ mountSidebarLabelsWidget();
+ mountSidebarMilestoneWidget();
+ mountSidebarConfidentialityWidget();
+ mountSidebarDueDateWidget();
+ mountSidebarReferenceWidget();
+ mountIssuableLockForm(store);
+ mountSidebarParticipantsWidget();
+ mountSidebarSubscriptionsWidget();
+ mountCopyEmailToClipboard();
+ mountSidebarTimeTracking();
+ mountSidebarSeverity();
+ mountSidebarEscalationStatus();
new SidebarMoveIssue(
mediator,
$('.js-move-issue'),
$('.js-move-issue-confirmation-button'),
).init();
-
- mountTimeTrackingComponent();
-
- mountSeverityComponent();
-
- mountEscalationStatusComponent();
}
export { getSidebarOptions };
diff --git a/app/assets/javascripts/sidebar/stores/sidebar_store.js b/app/assets/javascripts/sidebar/stores/sidebar_store.js
index e2581a8f30e..baf906bb96c 100644
--- a/app/assets/javascripts/sidebar/stores/sidebar_store.js
+++ b/app/assets/javascripts/sidebar/stores/sidebar_store.js
@@ -138,6 +138,10 @@ export default class SidebarStore {
this.assignees = data;
}
+ setReviewersFromRealtime(data) {
+ this.reviewers = data;
+ }
+
setAutocompleteProjects(projects) {
this.autocompleteProjects = projects;
}
diff --git a/app/assets/javascripts/token_access/components/token_access.vue b/app/assets/javascripts/token_access/components/token_access.vue
index 4b91872d80d..fe99f3e1fdd 100644
--- a/app/assets/javascripts/token_access/components/token_access.vue
+++ b/app/assets/javascripts/token_access/components/token_access.vue
@@ -117,7 +117,7 @@ export default {
throw new Error(errors[0]);
}
} catch (error) {
- createAlert({ message: error });
+ createAlert({ message: error.message });
}
},
async addProject() {
@@ -140,7 +140,7 @@ export default {
throw new Error(errors[0]);
}
} catch (error) {
- createAlert({ message: error });
+ createAlert({ message: error.message });
} finally {
this.clearTargetProjectPath();
this.getProjects();
@@ -166,7 +166,7 @@ export default {
throw new Error(errors[0]);
}
} catch (error) {
- createAlert({ message: error });
+ createAlert({ message: error.message });
} finally {
this.getProjects();
}
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 82ef3371d91..ce33478cbee 100644
--- a/app/assets/javascripts/token_access/components/token_projects_table.vue
+++ b/app/assets/javascripts/token_access/components/token_projects_table.vue
@@ -10,14 +10,21 @@ export default {
{
key: 'project',
label: __('Projects that can be accessed'),
- tdClass: 'gl-p-5!',
- columnClass: 'gl-w-85p',
+ thClass: 'gl-border-t-none!',
+ columnClass: 'gl-w-40p',
+ },
+ {
+ key: 'namespace',
+ label: __('Namespace'),
+ thClass: 'gl-border-t-none!',
+ columnClass: 'gl-w-40p',
},
{
key: 'actions',
label: '',
- tdClass: 'gl-p-5! gl-text-right',
- columnClass: 'gl-w-15p',
+ tdClass: 'gl-text-right',
+ thClass: 'gl-border-t-none!',
+ columnClass: 'gl-w-10p',
},
],
components: {
@@ -57,7 +64,11 @@ export default {
</template>
<template #cell(project)="{ item }">
- {{ item.name }}
+ <span data-testid="token-access-project-name">{{ item.name }}</span>
+ </template>
+
+ <template #cell(namespace)="{ item }">
+ <span data-testid="token-access-project-namespace">{{ item.namespace.fullPath }}</span>
</template>
<template #cell(actions)="{ item }">
diff --git a/app/assets/javascripts/token_access/graphql/queries/get_projects_with_ci_job_token_scope.query.graphql b/app/assets/javascripts/token_access/graphql/queries/get_projects_with_ci_job_token_scope.query.graphql
index 664991bc110..a243095f1b4 100644
--- a/app/assets/javascripts/token_access/graphql/queries/get_projects_with_ci_job_token_scope.query.graphql
+++ b/app/assets/javascripts/token_access/graphql/queries/get_projects_with_ci_job_token_scope.query.graphql
@@ -6,6 +6,10 @@ query getProjectsWithCIJobTokenScope($fullPath: ID!) {
nodes {
id
name
+ namespace {
+ id
+ fullPath
+ }
fullPath
}
}
diff --git a/app/assets/javascripts/tracking/tracker.js b/app/assets/javascripts/tracking/tracker.js
index 9ad86e76b6e..85f4979e752 100644
--- a/app/assets/javascripts/tracking/tracker.js
+++ b/app/assets/javascripts/tracking/tracker.js
@@ -39,8 +39,8 @@ export const Tracker = {
},
/**
- * Dispatches a structured event per our taxonomy:
- * https://docs.gitlab.com/ee/development/snowplow/index.html#structured-event-taxonomy.
+ * Dispatches a structured event:
+ * https://docs.gitlab.com/ee/development/snowplow/index.html#event-schema.
*
* If the library is not initialized and events are trying to be
* dispatched (data-attributes, load-events), they will be added
@@ -49,7 +49,7 @@ export const Tracker = {
* If there is an error when using the library, it will return ´false´
* and ´true´ otherwise.
*
- * @param {...any} eventData defined event taxonomy
+ * @param {...any} eventData defined event schema
* @returns {Boolean}
*/
event(...eventData) {
diff --git a/app/assets/javascripts/users_select/constants.js b/app/assets/javascripts/users_select/constants.js
index 64df1e1748c..c100c1f4ca5 100644
--- a/app/assets/javascripts/users_select/constants.js
+++ b/app/assets/javascripts/users_select/constants.js
@@ -1,11 +1,3 @@
-export const AJAX_USERS_SELECT_OPTIONS_MAP = {
- projectId: 'projectId',
- groupId: 'groupId',
- showCurrentUser: 'currentUser',
- authorId: 'authorId',
- skipUsers: 'skipUsers',
-};
-
export const AJAX_USERS_SELECT_PARAMS_MAP = {
project_id: 'projectId',
group_id: 'groupId',
@@ -15,4 +7,7 @@ export const AJAX_USERS_SELECT_PARAMS_MAP = {
current_user: 'showCurrentUser',
author_id: 'authorId',
skip_users: 'skipUsers',
+ states: 'states',
};
+
+export const ACTIVE_AND_BLOCKED_USER_STATES = ['active', 'blocked'];
diff --git a/app/assets/javascripts/users_select/index.js b/app/assets/javascripts/users_select/index.js
index bd425bdc2a8..7c1204c511c 100644
--- a/app/assets/javascripts/users_select/index.js
+++ b/app/assets/javascripts/users_select/index.js
@@ -1,21 +1,17 @@
-/* eslint-disable func-names, prefer-rest-params, consistent-return, no-shadow, no-self-compare, no-unused-expressions, yoda, prefer-spread, camelcase, no-param-reassign */
+/* eslint-disable func-names, consistent-return, no-shadow, no-self-compare, no-unused-expressions, camelcase, no-param-reassign */
/* global Issuable */
/* global emitSidebarEvent */
import $ from 'jquery';
import { escape, template, uniqBy } from 'lodash';
-import {
- AJAX_USERS_SELECT_OPTIONS_MAP,
- AJAX_USERS_SELECT_PARAMS_MAP,
-} from 'ee_else_ce/users_select/constants';
+import { AJAX_USERS_SELECT_PARAMS_MAP } from 'ee_else_ce/users_select/constants';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
import { isUserBusy } from '~/set_status_modal/utils';
import { fixTitle, dispose } from '~/tooltips';
import axios from '~/lib/utils/axios_utils';
import { parseBoolean, spriteIcon } from '~/lib/utils/common_utils';
-import { loadCSSFile } from '~/lib/utils/css_utils';
import { s__, __, sprintf } from '~/locale';
-import { getAjaxUsersSelectOptions, getAjaxUsersSelectParams } from './utils';
+import { getAjaxUsersSelectParams } from './utils';
// TODO: remove eventHub hack after code splitting refactor
window.emitSidebarEvent = window.emitSidebarEvent || $.noop;
@@ -24,9 +20,7 @@ function UsersSelect(currentUser, els, options = {}) {
const elsClassName = els?.toString().match('.(.+$)')[1];
const $els = $(els || '.js-user-search');
this.users = this.users.bind(this);
- this.user = this.user.bind(this);
this.usersPath = '/-/autocomplete/users.json';
- this.userPath = '/-/autocomplete/users/:id.json';
if (currentUser != null) {
if (typeof currentUser === 'object') {
this.currentUser = currentUser;
@@ -35,28 +29,29 @@ function UsersSelect(currentUser, els, options = {}) {
}
}
- const { handleClick } = options;
- const userSelect = this;
+ const { handleClick, states } = options;
$els.each((i, dropdown) => {
const userSelect = this;
- const options = {};
const $dropdown = $(dropdown);
- options.projectId = $dropdown.data('projectId');
- options.groupId = $dropdown.data('groupId');
- options.showCurrentUser = $dropdown.data('currentUser');
- options.todoFilter = $dropdown.data('todoFilter');
- options.todoStateFilter = $dropdown.data('todoStateFilter');
- options.iid = $dropdown.data('iid');
- options.issuableType = $dropdown.data('issuableType');
- options.targetBranch = $dropdown.data('targetBranch');
- options.showSuggested = $dropdown.data('showSuggested');
+ const options = {
+ states,
+ projectId: $dropdown.data('projectId'),
+ groupId: $dropdown.data('groupId'),
+ showCurrentUser: $dropdown.data('currentUser'),
+ todoFilter: $dropdown.data('todoFilter'),
+ todoStateFilter: $dropdown.data('todoStateFilter'),
+ iid: $dropdown.data('iid'),
+ issuableType: $dropdown.data('issuableType'),
+ targetBranch: $dropdown.data('targetBranch'),
+ authorId: $dropdown.data('authorId'),
+ showSuggested: $dropdown.data('showSuggested'),
+ };
const showNullUser = $dropdown.data('nullUser');
const defaultNullUser = $dropdown.data('nullUserDefault');
const showMenuAbove = $dropdown.data('showMenuAbove');
const showAnyUser = $dropdown.data('anyUser');
const firstUser = $dropdown.data('firstUser');
- options.authorId = $dropdown.data('authorId');
const defaultLabel = $dropdown.data('defaultLabel');
const issueURL = $dropdown.data('issueUpdate');
const $selectbox = $dropdown.closest('.selectbox');
@@ -72,6 +67,22 @@ function UsersSelect(currentUser, els, options = {}) {
let assigneeTemplate;
let collapsedAssigneeTemplate;
+ const suggestedReviewersHelpPath = $dropdown.data('suggestedReviewersHelpPath');
+ const suggestedReviewersHeaderTemplate = template(
+ `<div class="gl-display-flex gl-align-items-center">
+ <%- header %>
+ <a
+ title="${s__('SuggestedReviewers|Learn about suggested reviewers')}"
+ href="${suggestedReviewersHelpPath}"
+ rel="noopener"
+ target="_blank"
+ aria-label="${s__('SuggestedReviewers|Suggested reviewers help link')}"
+ class="gl-hover-bg-transparent! gl-p-0! has-tooltip">
+ ${spriteIcon('question-o', 'gl-ml-3 gl-icon s16')}
+ </a>
+ </div>`,
+ );
+
if (selectedId === undefined) {
selectedId = selectedIdDefault;
}
@@ -388,7 +399,12 @@ function UsersSelect(currentUser, els, options = {}) {
if (!suggestedUsers.length) return [];
const items = [
- { type: 'header', content: $dropdown.data('suggestedReviewersHeader') },
+ {
+ type: 'header',
+ content: suggestedReviewersHeaderTemplate({
+ header: $dropdown.data('suggestedReviewersHeader'),
+ }),
+ },
...suggestedUsers,
{ type: 'header', content: $dropdown.data('allMembersHeader') },
];
@@ -431,6 +447,10 @@ function UsersSelect(currentUser, els, options = {}) {
hidden() {
if ($dropdown.hasClass('js-multiselect')) {
if ($dropdown.hasClass(elsClassName)) {
+ if (window.gon?.features?.realtimeReviewers) {
+ $dropdown.data('deprecatedJQueryDropdown').clearMenu();
+ $dropdown.closest('.selectbox').children('input[type="hidden"]').remove();
+ }
emitSidebarEvent('sidebar.saveReviewers');
} else {
emitSidebarEvent('sidebar.saveAssignees');
@@ -615,156 +635,8 @@ function UsersSelect(currentUser, els, options = {}) {
},
});
});
-
- if ($('.ajax-users-select').length) {
- import(/* webpackChunkName: 'select2' */ 'select2/select2')
- .then(() => {
- // eslint-disable-next-line promise/no-nesting
- loadCSSFile(gon.select2_css_path)
- .then(() => {
- $('.ajax-users-select').each((i, select) => {
- const options = getAjaxUsersSelectOptions($(select), AJAX_USERS_SELECT_OPTIONS_MAP);
- options.skipLdap = $(select).hasClass('skip_ldap');
- const showNullUser = $(select).data('nullUser');
- const showAnyUser = $(select).data('anyUser');
- const showEmailUser = $(select).data('emailUser');
- const firstUser = $(select).data('firstUser');
- return $(select).select2({
- placeholder: __('Search for a user'),
- multiple: $(select).hasClass('multiselect'),
- minimumInputLength: 0,
- query(query) {
- return userSelect.users(query.term, options, (users) => {
- let name;
- const data = {
- results: users,
- };
- if (query.term.length === 0) {
- if (firstUser) {
- // Move current user to the front of the list
- const ref = data.results;
-
- for (let index = 0, len = ref.length; index < len; index += 1) {
- const obj = ref[index];
- if (obj.username === firstUser) {
- data.results.splice(index, 1);
- data.results.unshift(obj);
- break;
- }
- }
- }
- if (showNullUser) {
- const nullUser = {
- name: s__('UsersSelect|Unassigned'),
- id: 0,
- };
- data.results.unshift(nullUser);
- }
- if (showAnyUser) {
- name = showAnyUser;
- if (name === true) {
- name = s__('UsersSelect|Any User');
- }
- const anyUser = {
- name,
- id: null,
- };
- data.results.unshift(anyUser);
- }
- }
- if (
- showEmailUser &&
- data.results.length === 0 &&
- query.term.match(/^[^@]+@[^@]+$/)
- ) {
- const trimmed = query.term.trim();
- const emailUser = {
- name: sprintf(__('Invite "%{trimmed}" by email'), { trimmed }),
- username: trimmed,
- id: trimmed,
- invite: true,
- };
- data.results.unshift(emailUser);
- }
- return query.callback(data);
- });
- },
- initSelection() {
- const args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
- return userSelect.initSelection.apply(userSelect, args);
- },
- formatResult() {
- const args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
- return userSelect.formatResult.apply(userSelect, args);
- },
- formatSelection() {
- const args = 1 <= arguments.length ? [].slice.call(arguments, 0) : [];
- return userSelect.formatSelection.apply(userSelect, args);
- },
- dropdownCssClass: 'ajax-users-dropdown',
- // we do not want to escape markup since we are displaying html in results
- escapeMarkup(m) {
- return m;
- },
- });
- });
- })
- .catch(() => {});
- })
- .catch(() => {});
- }
}
-UsersSelect.prototype.initSelection = function (element, callback) {
- const id = $(element).val();
- if (id === '0') {
- const nullUser = {
- name: s__('UsersSelect|Unassigned'),
- };
- return callback(nullUser);
- } else if (id !== '') {
- return this.user(id, callback);
- }
-};
-
-UsersSelect.prototype.formatResult = function (user) {
- let avatar = gon.default_avatar_url;
- if (user.avatar_url) {
- avatar = user.avatar_url;
- }
- return `
- <div class='user-result'>
- <div class='user-image'>
- <img class='avatar avatar-inline s32' src='${avatar}'>
- </div>
- <div class='user-info'>
- <div class='user-name dropdown-menu-user-full-name'>
- ${escape(user.name)}
- </div>
- <div class='user-username dropdown-menu-user-username text-secondary'>
- ${!user.invite ? `@${escape(user.username)}` : ''}
- </div>
- </div>
- </div>
- `;
-};
-
-UsersSelect.prototype.formatSelection = function (user) {
- return escape(user.name);
-};
-
-UsersSelect.prototype.user = function (user_id, callback) {
- if (!/^\d+$/.test(user_id)) {
- return false;
- }
-
- let url = this.buildUrl(this.userPath);
- url = url.replace(':id', user_id);
- return axios.get(url).then(({ data }) => {
- callback(data);
- });
-};
-
// Return users list. Filtered by query
// Only active users retrieved
UsersSelect.prototype.users = function (query, options, callback) {
diff --git a/app/assets/javascripts/users_select/utils.js b/app/assets/javascripts/users_select/utils.js
index b46fd15fb77..8184e646124 100644
--- a/app/assets/javascripts/users_select/utils.js
+++ b/app/assets/javascripts/users_select/utils.js
@@ -1,18 +1,4 @@
/**
- * Get options from data attributes on passed `$select`.
- * @param {jQuery} $select
- * @param {Object} optionsMap e.g. { optionKeyName: 'dataAttributeName' }
- */
-export const getAjaxUsersSelectOptions = ($select, optionsMap) => {
- return Object.keys(optionsMap).reduce((accumulator, optionKey) => {
- const dataKey = optionsMap[optionKey];
- accumulator[optionKey] = $select.data(dataKey);
-
- return accumulator;
- }, {});
-};
-
-/**
* Get query parameters used for users request from passed `options` parameter
* @param {Object} options e.g. { currentUserId: 1, fooBar: 'baz' }
* @param {Object} paramsMap e.g. { user_id: 'currentUserId', foo_bar: 'fooBar' }
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_info.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_info.vue
index 30098f7619a..2132c2953d9 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_info.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_info.vue
@@ -1,7 +1,6 @@
<script>
-import { GlLink, GlTooltipDirective } from '@gitlab/ui';
+import { GlLink, GlTooltipDirective, GlTruncate } from '@gitlab/ui';
import { __ } from '~/locale';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import {
MANUAL_DEPLOY,
@@ -18,7 +17,7 @@ export default {
components: {
GlLink,
MemoryUsage: () => import('./memory_usage.vue'),
- TooltipOnTruncate,
+ GlTruncate,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -74,16 +73,19 @@ export default {
<div class="js-deployment-info deployment-info">
<template v-if="hasDeploymentMeta">
<span>{{ deployedText }}</span>
- <tooltip-on-truncate :title="deployment.name" truncate-target="child" class="label-truncate">
- <gl-link
- :href="deployment.url"
- target="_blank"
- rel="noopener noreferrer nofollow"
- class="js-deploy-meta gl-font-sm gl-pb-1"
- >
- {{ deployment.name }}
- </gl-link>
- </tooltip-on-truncate>
+ <gl-link
+ :href="deployment.url"
+ target="_blank"
+ rel="noopener noreferrer nofollow"
+ class="js-deploy-meta gl-font-sm gl-pb-1"
+ >
+ <gl-truncate
+ class="js-deploy-env-name"
+ :text="deployment.name"
+ position="middle"
+ with-tooltip
+ />
+ </gl-link>
</template>
<span
v-if="hasDeploymentTime"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_list.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_list.vue
index 655acf28253..501f5f1523f 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_list.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_list.vue
@@ -67,7 +67,6 @@ export default {
v-for="deployment in deployments"
:key="deployment.id"
:class="deploymentClass"
- class="gl-bg-gray-50"
:deployment="deployment"
:show-metrics="hasDeploymentMetrics"
/>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_view_button.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_view_button.vue
index 5efa0e2879e..39a6086e0d5 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_view_button.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_view_button.vue
@@ -72,7 +72,7 @@ export default {
:display="appButtonText"
:link="deploymentExternalUrl"
size="small"
- css-class="deploy-link js-deploy-url inline gl-ml-3"
+ css-class="deploy-link js-deploy-url inline"
/>
<modal-copy-button
v-else
@@ -116,7 +116,7 @@ export default {
:display="appButtonText"
:link="deploymentExternalUrl"
size="small"
- css-class="deploy-link js-deploy-url inline gl-ml-3"
+ css-class="deploy-link js-deploy-url inline"
/>
<modal-copy-button
v-else
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/container.js b/app/assets/javascripts/vue_merge_request_widget/components/extensions/container.js
index a58d524b9ed..cc7b9d0ea72 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/extensions/container.js
+++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/container.js
@@ -11,8 +11,6 @@ export default {
render(h) {
const { extensions } = registeredExtensions;
- if (extensions.length === 0) return null;
-
return h(
'section',
{
@@ -22,26 +20,28 @@ export default {
},
},
[
- h(
- 'ul',
- {
- class: 'gl-p-0 gl-m-0 gl-list-style-none',
- },
- [
- ...extensions.map((extension, index) =>
- h('li', { attrs: { class: index > 0 && 'mr-widget-border-top' } }, [
- h(
- { ...extension },
- {
- props: {
- mr: this.mr,
+ h('div', { attrs: { class: 'mr-widget-section' } }, [
+ h(
+ 'ul',
+ {
+ class: 'gl-p-0 gl-m-0 gl-list-style-none',
+ },
+ [
+ ...extensions.map((extension, index) =>
+ h('li', { attrs: { class: index > 0 && 'mr-widget-border-top' } }, [
+ h(
+ { ...extension },
+ {
+ props: {
+ mr: this.mr,
+ },
},
- },
- ),
- ]),
- ),
- ],
- ),
+ ),
+ ]),
+ ),
+ ],
+ ),
+ ]),
],
);
},
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue
index f8d2732b385..6475def461a 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue
@@ -46,8 +46,8 @@ export default {
};
</script>
<template>
- <div>
- <div class="mr-widget-extension d-flex align-items-center pl-3">
+ <div class="mr-widget-extension">
+ <div class="d-flex align-items-center pl-3">
<div v-if="hasError" class="ci-widget media">
<div class="media-body">
<span class="gl-font-sm mr-widget-margin-left gl-line-height-24 js-error-state">
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_container.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_container.vue
index 5967ca026e5..4445448fcd7 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_container.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_container.vue
@@ -1,6 +1,8 @@
<template>
- <div class="mr-widget-heading">
- <div class="mr-widget-content"><slot name="default"></slot></div>
- <slot name="footer"></slot>
+ <div class="mr-section-container mr-widget-workflow">
+ <div class="mr-widget-section">
+ <div class="mr-widget-content"><slot name="default"></slot></div>
+ <slot name="footer"></slot>
+ </div>
</div>
</template>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
index fe69e96bd87..97c6de37054 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue
@@ -200,7 +200,7 @@ export default {
data-testid="pipeline-info-container"
data-qa-selector="merge_request_pipeline_info_content"
>
- {{ pipeline.details.name }}
+ {{ pipeline.details.event_type_name || pipeline.details.name }}
<gl-link
:href="pipeline.path"
class="pipeline-id gl-font-weight-normal pipeline-number"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
index a05e8747a43..010c172c710 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue
@@ -80,13 +80,7 @@ export default {
);
},
preferredAutoMergeStrategy() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return MergeRequestStore.getPreferredAutoMergeStrategy(
- this.mr.availableAutoMergeStrategies,
- );
- }
-
- return this.mr.preferredAutoMergeStrategy;
+ return MergeRequestStore.getPreferredAutoMergeStrategy(this.mr.availableAutoMergeStrategies);
},
ciStatus() {
return this.isPostMerge ? this.mr?.mergePipeline?.details?.status?.text : this.mr.ciStatus;
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/report_widget_container.vue b/app/assets/javascripts/vue_merge_request_widget/components/report_widget_container.vue
new file mode 100644
index 00000000000..2683956e603
--- /dev/null
+++ b/app/assets/javascripts/vue_merge_request_widget/components/report_widget_container.vue
@@ -0,0 +1,18 @@
+<script>
+export default {
+ data() {
+ return {
+ hasChildren: false,
+ };
+ },
+ updated() {
+ this.hasChildren = this.$scopedSlots.default?.()?.some((c) => c.tag);
+ },
+};
+</script>
+
+<template>
+ <div v-show="hasChildren" class="mr-section-container mr-widget-workflow">
+ <slot></slot>
+ </div>
+</template>
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 932659f3c89..66e33a08a12 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
@@ -45,12 +45,19 @@ export default {
if (this.status === 'closed') return 'gl-bg-red-50';
return null;
},
+ hasActionsSlot() {
+ return this.$scopedSlots.actions?.()?.length;
+ },
},
};
</script>
<template>
- <div class="mr-widget-body media" :class="wrapperClasses" v-on="$listeners">
+ <div
+ class="mr-widget-body media mr-widget-body-line-height-1 gl-line-height-normal"
+ :class="wrapperClasses"
+ v-on="$listeners"
+ >
<div v-if="isLoading" class="gl-w-full mr-conflict-loader">
<slot name="loading">
<div class="gl-display-flex">
@@ -67,13 +74,19 @@ export default {
</slot>
<div class="gl-display-flex gl-w-full">
<div
- :class="{ 'gl-display-flex': actions.length, 'gl-md-display-flex': !actions.length }"
+ :class="{
+ 'gl-display-flex gl-align-items-center': actions.length,
+ 'gl-md-display-flex gl-align-items-center': !actions.length,
+ }"
class="media-body"
>
<slot></slot>
<div
- :class="{ 'gl-flex-direction-column-reverse': !actions.length }"
- class="gl-display-flex gl-md-display-block gl-font-size-0 gl-ml-auto"
+ :class="{
+ 'state-container-action-buttons gl-flex-direction-column gl-flex-wrap gl-justify-content-end': !actions.length,
+ 'gl-md-pt-0 gl-pt-3': hasActionsSlot,
+ }"
+ class="gl-display-flex gl-font-size-0 gl-ml-auto gl-gap-3"
>
<slot name="actions">
<actions v-if="actions.length" :tertiary-buttons="actions" />
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/merge_checks_failed.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/merge_checks_failed.vue
index 2b22033514f..38b99dae264 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/merge_checks_failed.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/merge_checks_failed.vue
@@ -9,6 +9,7 @@ export default {
blockingMergeRequests: s__(
'mrWidget|Merge blocked: you can only merge after the above items are resolved.',
),
+ externalStatusChecksFailed: s__('mrWidget|Merge blocked: all status checks must pass.'),
},
components: {
StatusIcon,
@@ -25,6 +26,8 @@ export default {
return this.$options.i18n.approvalNeeded;
} else if (this.mr.detailedMergeStatus === DETAILED_MERGE_STATUS.BLOCKED_STATUS) {
return this.$options.i18n.blockingMergeRequests;
+ } else if (this.mr.detailedMergeStatus === DETAILED_MERGE_STATUS.EXTERNAL_STATUS_CHECKS) {
+ return this.$options.i18n.externalStatusChecksFailed;
}
return null;
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 92a7fa39cdc..38f7d3d2c96 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
@@ -3,8 +3,8 @@ 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 { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { __ } from '~/locale';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { AUTO_MERGE_STRATEGIES } from '../../constants';
import eventHub from '../../event_hub';
import mergeRequestQueryVariablesMixin from '../../mixins/merge_request_query_variables';
@@ -16,9 +16,6 @@ export default {
apollo: {
state: {
query: autoMergeEnabledQuery,
- skip() {
- return !this.glFeatures.mergeRequestWidgetGraphql;
- },
variables() {
return this.mergeRequestQueryVariables;
},
@@ -31,7 +28,7 @@ export default {
GlSprintf,
StateContainer,
},
- mixins: [autoMergeMixin, glFeatureFlagMixin(), mergeRequestQueryVariablesMixin],
+ mixins: [autoMergeMixin, mergeRequestQueryVariablesMixin],
props: {
mr: {
type: Object,
@@ -51,31 +48,21 @@ export default {
},
computed: {
loading() {
- return (
- this.glFeatures.mergeRequestWidgetGraphql &&
- this.$apollo.queries.state.loading &&
- Object.keys(this.state).length === 0
- );
- },
- mergeUser() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return this.state.mergeUser;
- }
-
- return this.mr.setToAutoMergeBy;
+ return this.$apollo.queries.state.loading && Object.keys(this.state).length === 0;
},
- targetBranch() {
- return (this.glFeatures.mergeRequestWidgetGraphql ? this.state : this.mr).targetBranch;
- },
- shouldRemoveSourceBranch() {
- if (!this.glFeatures.mergeRequestWidgetGraphql) return this.mr.shouldRemoveSourceBranch;
-
+ stateRemoveSourceBranch() {
if (!this.state.shouldRemoveSourceBranch) return false;
return this.state.shouldRemoveSourceBranch || this.state.forceRemoveSourceBranch;
},
- autoMergeStrategy() {
- return (this.glFeatures.mergeRequestWidgetGraphql ? this.state : this.mr).autoMergeStrategy;
+ canRemoveSourceBranch() {
+ const { currentUserId } = this.mr;
+ const mergeUserId = getIdFromGraphQLId(this.state.mergeUser?.id);
+ const canRemoveSourceBranch = this.state.userPermissions.removeSourceBranch;
+
+ return (
+ !this.stateRemoveSourceBranch && canRemoveSourceBranch && mergeUserId === currentUserId
+ );
},
actions() {
const actions = [];
@@ -104,12 +91,8 @@ export default {
this.service
.cancelAutomaticMerge()
.then((res) => res.data)
- .then((data) => {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- eventHub.$emit('MRWidgetUpdateRequested');
- } else {
- eventHub.$emit('UpdateWidgetData', data);
- }
+ .then(() => {
+ eventHub.$emit('MRWidgetUpdateRequested');
})
.catch(() => {
this.isCancellingAutoMerge = false;
@@ -121,7 +104,7 @@ export default {
removeSourceBranch() {
const options = {
sha: this.mr.sha,
- auto_merge_strategy: this.autoMergeStrategy,
+ auto_merge_strategy: this.state.autoMergeStrategy,
should_remove_source_branch: true,
};
@@ -135,9 +118,7 @@ export default {
}
})
.then(() => {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- this.$apollo.queries.state.refetch();
- }
+ this.$apollo.queries.state.refetch();
})
.catch(() => {
this.isRemovingSourceBranch = false;
@@ -162,7 +143,7 @@ export default {
<h4 class="gl-mr-3" data-testid="statusText">
<gl-sprintf :message="statusText" data-testid="statusText">
<template #merge_author>
- <mr-widget-author :author="mergeUser" />
+ <mr-widget-author v-if="state.mergeUser" :author="state.mergeUser" />
</template>
</gl-sprintf>
</h4>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue
index 39c56cbb93d..448805cf8b9 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue
@@ -1,6 +1,5 @@
<script>
import { s__ } from '~/locale';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import eventHub from '../../event_hub';
import mergeRequestQueryVariablesMixin from '../../mixins/merge_request_query_variables';
import autoMergeFailedQuery from '../../queries/states/auto_merge_failed.query.graphql';
@@ -11,13 +10,10 @@ export default {
components: {
StateContainer,
},
- mixins: [glFeatureFlagMixin(), mergeRequestQueryVariablesMixin],
+ mixins: [mergeRequestQueryVariablesMixin],
apollo: {
mergeError: {
query: autoMergeFailedQuery,
- skip() {
- return !this.glFeatures.mergeRequestWidgetGraphql;
- },
variables() {
return this.mergeRequestQueryVariables;
},
@@ -32,7 +28,7 @@ export default {
},
data() {
return {
- mergeError: this.glFeatures.mergeRequestWidgetGraphql ? null : this.mr.mergeError,
+ mergeError: null,
isRefreshing: false,
};
},
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
index d60d3cfc9ea..8e1b18c63a4 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_conflicts.vue
@@ -1,6 +1,5 @@
<script>
import { GlButton, GlSkeletonLoader } from '@gitlab/ui';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import mergeRequestQueryVariablesMixin from '../../mixins/merge_request_query_variables';
import userPermissionsQuery from '../../queries/permissions.query.graphql';
import conflictsStateQuery from '../../queries/states/conflicts.query.graphql';
@@ -13,23 +12,17 @@ export default {
GlButton,
StateContainer,
},
- mixins: [glFeatureFlagMixin(), mergeRequestQueryVariablesMixin],
+ mixins: [mergeRequestQueryVariablesMixin],
apollo: {
userPermissions: {
query: userPermissionsQuery,
- skip() {
- return !this.glFeatures.mergeRequestWidgetGraphql;
- },
variables() {
return this.mergeRequestQueryVariables;
},
update: (data) => data.project.mergeRequest.userPermissions,
},
- stateData: {
+ state: {
query: conflictsStateQuery,
- skip() {
- return !this.glFeatures.mergeRequestWidgetGraphql;
- },
variables() {
return this.mergeRequestQueryVariables;
},
@@ -47,40 +40,19 @@ export default {
data() {
return {
userPermissions: {},
- stateData: {},
+ state: {},
};
},
computed: {
isLoading() {
- return (
- this.glFeatures.mergeRequestWidgetGraphql &&
- this.$apollo.queries.userPermissions.loading &&
- this.$apollo.queries.stateData.loading
- );
- },
- canPushToSourceBranch() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return this.userPermissions.pushToSourceBranch;
- }
-
- return this.mr.canPushToSourceBranch;
- },
- canMerge() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return this.userPermissions.canMerge;
- }
-
- return this.mr.canMerge;
- },
- shouldBeRebased() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return this.stateData.shouldBeRebased;
- }
-
- return this.mr.shouldBeRebased;
+ return this.$apollo.queries.userPermissions.loading && this.$apollo.queries.state.loading;
},
showResolveButton() {
- return this.mr.conflictResolutionPath && this.canPushToSourceBranch;
+ return (
+ this.mr.conflictResolutionPath &&
+ this.userPermissions.pushToSourceBranch &&
+ !this.state.sourceBranchProtected
+ );
},
},
};
@@ -95,7 +67,7 @@ export default {
</gl-skeleton-loader>
</template>
<template v-if="!isLoading">
- <span v-if="shouldBeRebased" class="bold gl-ml-0! gl-text-body!">
+ <span v-if="state.shouldBeRebased" class="bold gl-ml-0! gl-text-body!">
{{
s__(`mrWidget|Merge blocked: fast-forward merge is not possible.
To merge this request, first rebase locally.`)
@@ -104,7 +76,7 @@ export default {
<template v-else>
<span class="bold gl-ml-0! gl-text-body! gl-flex-grow-1 gl-w-full gl-md-w-auto gl-mr-2">
{{ s__('mrWidget|Merge blocked: merge conflicts must be resolved.') }}
- <span v-if="!canMerge">
+ <span v-if="!userPermissions.canMerge">
{{
s__(
`mrWidget|Users who can write to the source or target branches can resolve the conflicts.`,
@@ -114,9 +86,9 @@ export default {
</span>
</template>
</template>
- <template v-if="!isLoading && !shouldBeRebased" #actions>
+ <template v-if="!isLoading && !state.shouldBeRebased" #actions>
<gl-button
- v-if="canMerge"
+ v-if="userPermissions.canMerge"
size="small"
variant="confirm"
category="secondary"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue
index 214d1b49732..5e073bf7c04 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue
@@ -1,7 +1,6 @@
<script>
import { GlIcon, GlTooltipDirective, GlSprintf } from '@gitlab/ui';
import { sprintf } from '~/locale';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import mergeRequestQueryVariablesMixin from '../../mixins/merge_request_query_variables';
import missingBranchQuery from '../../queries/states/missing_branch.query.graphql';
import {
@@ -21,13 +20,10 @@ export default {
GlSprintf,
StatusIcon,
},
- mixins: [glFeatureFlagMixin(), mergeRequestQueryVariablesMixin],
+ mixins: [mergeRequestQueryVariablesMixin],
apollo: {
state: {
query: missingBranchQuery,
- skip() {
- return !this.glFeatures.mergeRequestWidgetGraphql;
- },
variables() {
return this.mergeRequestQueryVariables;
},
@@ -44,15 +40,8 @@ export default {
return { state: {} };
},
computed: {
- sourceBranchRemoved() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return !this.state.sourceBranchExists;
- }
-
- return this.mr.sourceBranchRemoved;
- },
type() {
- return this.sourceBranchRemoved ? 'source' : 'target';
+ return this.mr.sourceBranchRemoved ? 'source' : 'target';
},
name() {
return this.type === 'source' ? this.mr.sourceBranch : this.mr.targetBranch;
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 f6843c1f3d3..4ae4edf02c3 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
@@ -2,7 +2,6 @@
import { GlButton, GlSkeletonLoader } from '@gitlab/ui';
import { createAlert } from '~/flash';
import { __ } from '~/locale';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import toast from '~/vue_shared/plugins/global_toast';
import simplePoll from '~/lib/utils/simple_poll';
import eventHub from '../../event_hub';
@@ -15,9 +14,6 @@ export default {
apollo: {
state: {
query: rebaseQuery,
- skip() {
- return !this.glFeatures.mergeRequestWidgetGraphql;
- },
variables() {
return this.mergeRequestQueryVariables;
},
@@ -29,7 +25,7 @@ export default {
GlButton,
StateContainer,
},
- mixins: [glFeatureFlagMixin(), mergeRequestQueryVariablesMixin],
+ mixins: [mergeRequestQueryVariablesMixin],
props: {
mr: {
type: Object,
@@ -49,28 +45,16 @@ export default {
},
computed: {
isLoading() {
- return this.glFeatures.mergeRequestWidgetGraphql && this.$apollo.queries.state.loading;
+ return this.$apollo.queries.state.loading;
},
rebaseInProgress() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return this.state.rebaseInProgress;
- }
-
- return this.mr.rebaseInProgress;
+ return this.state.rebaseInProgress;
},
canPushToSourceBranch() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return this.state.userPermissions.pushToSourceBranch;
- }
-
- return this.mr.canPushToSourceBranch;
+ return this.state.userPermissions.pushToSourceBranch;
},
targetBranch() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return this.state.targetBranch;
- }
-
- return this.mr.targetBranch;
+ return this.state.targetBranch;
},
status() {
if (this.isLoading) {
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/new_ready_to_merge.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/new_ready_to_merge.vue
index 0b6aa104181..2db5c71be82 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/new_ready_to_merge.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/new_ready_to_merge.vue
@@ -8,7 +8,7 @@ export default {
canMerge: {
query: readyToMergeQuery,
skip() {
- return !this.mr || !window.gon?.features?.mergeRequestWidgetGraphql;
+ return !this.mr;
},
variables() {
return this.mergeRequestQueryVariables;
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 1298c1316e2..c54672cd0f8 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
@@ -19,7 +19,6 @@ import { secondsToMilliseconds } from '~/lib/utils/datetime_utility';
import simplePoll from '~/lib/utils/simple_poll';
import { __, s__, n__ } from '~/locale';
import SmartInterval from '~/smart_interval';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { helpPagePath } from '~/helpers/help_page_helper';
import {
AUTO_MERGE_STRATEGIES,
@@ -54,9 +53,6 @@ export default {
apollo: {
state: {
query: readyToMergeQuery,
- skip() {
- return !this.glFeatures.mergeRequestWidgetGraphql;
- },
variables() {
return this.mergeRequestQueryVariables;
},
@@ -123,14 +119,14 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
- mixins: [readyToMergeMixin, glFeatureFlagMixin(), mergeRequestQueryVariablesMixin],
+ mixins: [readyToMergeMixin, mergeRequestQueryVariablesMixin],
props: {
mr: { type: Object, required: true },
service: { type: Object, required: true },
},
data() {
return {
- loading: this.glFeatures.mergeRequestWidgetGraphql,
+ loading: true,
state: {},
removeSourceBranch: this.mr.shouldRemoveSourceBranch,
isMakingRequest: false,
@@ -148,7 +144,7 @@ export default {
},
computed: {
stateData() {
- return this.glFeatures.mergeRequestWidgetGraphql ? this.state : this.mr;
+ return this.state;
},
hasCI() {
return this.stateData.hasCI || this.stateData.hasCi;
@@ -157,35 +153,19 @@ export default {
return !isEmpty(this.stateData.availableAutoMergeStrategies);
},
pipeline() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return this.state.headPipeline;
- }
-
- return this.mr.pipeline;
+ return this.state.headPipeline;
},
isPipelineFailed() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return ['FAILED', 'CANCELED'].indexOf(this.pipeline?.status) !== -1;
- }
-
- return this.mr.isPipelineFailed;
+ return ['FAILED', 'CANCELED'].indexOf(this.pipeline?.status) !== -1;
},
showMergeFailedPipelineConfirmationDialog() {
return this.status === PIPELINE_FAILED_STATE && this.isPipelineFailed;
},
isMergeAllowed() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return this.state.mergeable;
- }
-
- return this.mr.isMergeAllowed;
+ return this.state.mergeable || false;
},
canRemoveSourceBranch() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return this.state.userPermissions.removeSourceBranch;
- }
-
- return this.mr.canRemoveSourceBranch;
+ return this.state.userPermissions.removeSourceBranch;
},
commitTemplateHelpPage() {
return helpPagePath('user/project/merge_requests/commit_templates.md');
@@ -200,46 +180,24 @@ export default {
return this.$options.i18n.mergeCommitTemplateHintText;
},
commits() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return this.state.commitsWithoutMergeCommits.nodes;
- }
-
- return this.mr.commits;
+ return this.state.commitsWithoutMergeCommits?.nodes;
},
commitsCount() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return this.state.commitCount || 0;
- }
-
- return this.mr.commitsCount;
+ return this.state.commitCount || 0;
},
preferredAutoMergeStrategy() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return MergeRequestStore.getPreferredAutoMergeStrategy(
- this.state.availableAutoMergeStrategies,
- );
- }
-
- return this.mr.preferredAutoMergeStrategy;
+ return MergeRequestStore.getPreferredAutoMergeStrategy(
+ this.state.availableAutoMergeStrategies,
+ );
},
squashIsSelected() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return this.isSquashReadOnly ? this.state.squashOnMerge : this.state.squash;
- }
-
- return this.mr.squashIsSelected;
+ return this.isSquashReadOnly ? this.state.squashOnMerge : this.state.squash;
},
isPipelineActive() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return this.pipeline?.active || false;
- }
-
- return this.mr.isPipelineActive;
+ return this.pipeline?.active || false;
},
status() {
- const ciStatus = this.glFeatures.mergeRequestWidgetGraphql
- ? this.pipeline?.status.toLowerCase()
- : this.mr.ciStatus;
+ const ciStatus = this.pipeline?.status?.toLowerCase();
if ((this.hasCI && !ciStatus) || this.hasPipelineMustSucceedConflict) {
return PIPELINE_FAILED_STATE;
@@ -304,11 +262,7 @@ export default {
return this.squashBeforeMerge && this.shouldShowSquashBeforeMerge;
},
shouldShowMergeEdit() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return !this.state.mergeRequestsFfOnlyEnabled;
- }
-
- return !this.mr.ffOnlyEnabled;
+ return !this.state.mergeRequestsFfOnlyEnabled;
},
shaMismatchLink() {
return this.mr.mergeRequestDiffsPath;
@@ -345,18 +299,15 @@ export default {
},
},
mounted() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- eventHub.$on('ApprovalUpdated', this.updateGraphqlState);
- eventHub.$on('MRWidgetUpdateRequested', this.updateGraphqlState);
- eventHub.$on('mr.discussion.updated', this.updateGraphqlState);
- }
+ eventHub.$on('ApprovalUpdated', this.updateGraphqlState);
+ eventHub.$on('MRWidgetUpdateRequested', this.updateGraphqlState);
+ eventHub.$on('mr.discussion.updated', this.updateGraphqlState);
},
beforeDestroy() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- eventHub.$off('ApprovalUpdated', this.updateGraphqlState);
- eventHub.$off('MRWidgetUpdateRequested', this.updateGraphqlState);
- eventHub.$off('mr.discussion.updated', this.updateGraphqlState);
- }
+ eventHub.$off('ApprovalUpdated', this.updateGraphqlState);
+ eventHub.$off('MRWidgetUpdateRequested', this.updateGraphqlState);
+ eventHub.$off('mr.discussion.updated', this.updateGraphqlState);
+ eventHub.$off('ApprovalUpdated', this.updateGraphqlState);
if (this.pollingInterval) {
this.pollingInterval.destroy();
@@ -391,9 +342,7 @@ export default {
if (mergeImmediately) {
this.isMergingImmediately = true;
}
- const latestSha = this.glFeatures.mergeRequestWidgetGraphql
- ? this.state.diffHeadSha
- : this.mr.latestSHA;
+ const latestSha = this.state.diffHeadSha;
const options = {
sha: latestSha || this.mr.sha,
@@ -435,9 +384,7 @@ export default {
this.mr.transitionStateMachine({ transition: MERGE_FAILURE });
}
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- this.updateGraphqlState();
- }
+ this.updateGraphqlState();
this.isMakingRequest = false;
})
@@ -521,7 +468,7 @@ export default {
<template>
<div
data-testid="ready_to_merge_state"
- class="gl-border-t-1 gl-border-t-solid gl-border-gray-100 gl-bg-gray-10 gl-pl-7 gl-rounded-bottom-left-base gl-rounded-bottom-right-base"
+ class="gl-border-t-1 gl-border-t-solid gl-border-gray-100 gl-bg-gray-10 gl-pl-7"
>
<div v-if="loading" class="mr-widget-body">
<div class="gl-w-full mr-ready-to-merge-loader">
@@ -538,13 +485,15 @@ export default {
<div class="media-body">
<div class="mr-widget-body-controls gl-display-flex gl-align-items-center gl-flex-wrap">
<template v-if="shouldShowMergeControls">
- <div class="gl-display-flex gl-align-items-center gl-flex-wrap gl-w-full gl-mb-5">
+ <div
+ class="gl-display-flex gl-sm-flex-direction-column gl-md-align-items-center gl-flex-wrap gl-w-full gl-md-pb-5"
+ >
<gl-form-checkbox
v-if="canRemoveSourceBranch"
id="remove-source-branch-input"
v-model="removeSourceBranch"
:disabled="isRemoveSourceBranchButtonDisabled"
- class="js-remove-source-branch-checkbox gl-display-flex gl-align-items-center gl-mr-5"
+ class="js-remove-source-branch-checkbox gl-display-flex gl-align-items-center gl-mr-5 gl-mb-3 gl-md-mb-0"
>
{{ __('Delete source branch') }}
</gl-form-checkbox>
@@ -555,37 +504,18 @@ export default {
v-model="squashBeforeMerge"
:help-path="mr.squashBeforeMergeHelpPath"
:is-disabled="isSquashReadOnly"
- class="gl-mr-5"
+ class="gl-mr-5 gl-mb-3 gl-md-mb-0"
/>
<gl-form-checkbox
v-if="shouldShowSquashEdit || shouldShowMergeEdit"
v-model="editCommitMessage"
data-testid="widget_edit_commit_message"
- class="gl-display-flex gl-align-items-center"
+ class="gl-display-flex gl-align-items-center gl-mb-3 gl-md-mb-0"
>
{{ __('Edit commit message') }}
</gl-form-checkbox>
</div>
- <div class="gl-w-full gl-text-gray-500 gl-mb-5">
- <added-commit-message
- :is-squash-enabled="squashBeforeMerge"
- :is-fast-forward-enabled="!shouldShowMergeEdit"
- :commits-count="commitsCount"
- :target-branch="stateData.targetBranch"
- />
- <template v-if="mr.relatedLinks">
- &middot;
- <related-links
- :state="mr.state"
- :related-links="mr.relatedLinks"
- :show-assign-to-me="false"
- :diverged-commits-count="mr.divergedCommitsCount"
- :target-branch-path="mr.targetBranchPath"
- class="mr-ready-merge-related-links gl-display-inline"
- />
- </template>
- </div>
<div v-if="editCommitMessage" class="gl-w-full" data-testid="edit_commit_message">
<ul class="border-top commits-list flex-list gl-list-style-none gl-p-0 gl-pt-4">
<commit-edit
@@ -625,6 +555,25 @@ export default {
</li>
</ul>
</div>
+ <div class="gl-w-full gl-text-gray-500 gl-mb-3 gl-md-mb-0 gl-md-pb-5">
+ <added-commit-message
+ :is-squash-enabled="squashBeforeMerge"
+ :is-fast-forward-enabled="!shouldShowMergeEdit"
+ :commits-count="commitsCount"
+ :target-branch="state.targetBranch"
+ />
+ <template v-if="mr.relatedLinks">
+ &middot;
+ <related-links
+ :state="mr.state"
+ :related-links="mr.relatedLinks"
+ :show-assign-to-me="false"
+ :diverged-commits-count="mr.divergedCommitsCount"
+ :target-branch-path="mr.targetBranchPath"
+ class="mr-ready-merge-related-links gl-display-inline"
+ />
+ </template>
+ </div>
<gl-button-group class="gl-align-self-start">
<gl-button
size="medium"
@@ -702,7 +651,7 @@ export default {
:is-squash-enabled="squashBeforeMerge"
:is-fast-forward-enabled="!shouldShowMergeEdit"
:commits-count="commitsCount"
- :target-branch="stateData.targetBranch"
+ :target-branch="state.targetBranch"
:merge-commit-path="mr.mergeCommitPath"
/>
</li>
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue
index 8f2e4eb2131..074758e33b2 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/unresolved_discussions.vue
@@ -26,30 +26,30 @@ export default {
<template>
<state-container :mr="mr" status="failed">
<span
- class="gl-ml-3 gl-font-weight-bold gl-w-100 gl-flex-grow-1 gl-md-mr-3 gl-ml-0! gl-text-body!"
+ class="gl-ml-3 gl-font-weight-bold gl-w-100 gl-flex-grow-1 gl-md-mr-3 gl-ml-0! gl-text-body! gl-align-self-start"
>
{{ s__('mrWidget|Merge blocked: all threads must be resolved.') }}
</span>
<template #actions>
<gl-button
- v-if="mr.createIssueToResolveDiscussionsPath"
- :href="mr.createIssueToResolveDiscussionsPath"
- class="js-create-issue gl-align-self-start gl-vertical-align-top gl-mr-2"
+ data-testid="jump-to-first"
+ class="gl-align-self-start gl-vertical-align-top"
size="small"
variant="confirm"
- category="secondary"
+ category="primary"
+ @click="jumpToFirstUnresolvedDiscussion"
>
- {{ s__('mrWidget|Create issue to resolve all threads') }}
+ {{ s__('mrWidget|Jump to first unresolved thread') }}
</gl-button>
<gl-button
- data-testid="jump-to-first"
- class="gl-mb-2 gl-md-mb-0 gl-align-self-start gl-vertical-align-top"
+ v-if="mr.createIssueToResolveDiscussionsPath"
+ :href="mr.createIssueToResolveDiscussionsPath"
+ class="js-create-issue gl-align-self-start gl-vertical-align-top"
size="small"
variant="confirm"
- category="primary"
- @click="jumpToFirstUnresolvedDiscussion"
+ category="secondary"
>
- {{ s__('mrWidget|Jump to first unresolved thread') }}
+ {{ s__('mrWidget|Create issue to resolve all threads') }}
</gl-button>
</template>
</state-container>
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 dee27a5d5b5..ef5be0fbfcd 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
@@ -5,14 +5,12 @@ import $ from 'jquery';
import { createAlert } from '~/flash';
import toast from '~/vue_shared/plugins/global_toast';
import { __ } from '~/locale';
-import MergeRequest from '~/merge_request';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-import eventHub from '../../event_hub';
import mergeRequestQueryVariablesMixin from '../../mixins/merge_request_query_variables';
import getStateQuery from '../../queries/get_state.query.graphql';
import draftQuery from '../../queries/states/draft.query.graphql';
import removeDraftMutation from '../../queries/toggle_draft.mutation.graphql';
import StateContainer from '../state_container.vue';
+import eventHub from '../../event_hub';
export default {
name: 'WorkInProgress',
@@ -20,13 +18,10 @@ export default {
GlButton,
StateContainer,
},
- mixins: [glFeatureFlagMixin(), mergeRequestQueryVariablesMixin],
+ mixins: [mergeRequestQueryVariablesMixin],
apollo: {
userPermissions: {
query: draftQuery,
- skip() {
- return !this.glFeatures.mergeRequestWidgetGraphql;
- },
variables() {
return this.mergeRequestQueryVariables;
},
@@ -35,7 +30,6 @@ export default {
},
props: {
mr: { type: Object, required: true },
- service: { type: Object, required: true },
},
data() {
return {
@@ -43,17 +37,8 @@ export default {
isMakingRequest: false,
};
},
- computed: {
- canUpdate() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- return this.userPermissions.updateMergeRequest;
- }
-
- return Boolean(this.mr.removeWIPPath);
- },
- },
methods: {
- removeDraftMutation() {
+ handleRemoveDraft() {
const { mergeRequestQueryVariables } = this;
this.isMakingRequest = true;
@@ -138,26 +123,6 @@ export default {
this.isMakingRequest = false;
});
},
- handleRemoveDraft() {
- if (this.glFeatures.mergeRequestWidgetGraphql) {
- this.removeDraftMutation();
- } else {
- this.isMakingRequest = true;
- this.service
- .removeWIP()
- .then((res) => res.data)
- .then((data) => {
- eventHub.$emit('UpdateWidgetData', data);
- MergeRequest.toggleDraftStatus(this.mr.title, true);
- })
- .catch(() => {
- this.isMakingRequest = false;
- createAlert({
- message: __('Something went wrong. Please try again.'),
- });
- });
- }
- },
},
};
</script>
@@ -169,12 +134,13 @@ export default {
</span>
<template #actions>
<gl-button
- v-if="canUpdate"
+ v-if="userPermissions.updateMergeRequest"
size="small"
:disabled="isMakingRequest"
:loading="isMakingRequest"
variant="confirm"
class="js-remove-draft gl-md-ml-3 gl-align-self-start"
+ data-testid="removeWipButton"
@click="handleRemoveDraft"
>
{{ s__('mrWidget|Mark as ready') }}
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/dynamic_content.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/dynamic_content.vue
index d1ade2886f4..4d66c75719b 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/widget/dynamic_content.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/dynamic_content.vue
@@ -58,6 +58,7 @@ export default {
:status-icon-name="statusIcon"
:widget-name="widgetName"
:header="data.header"
+ :help-popover="data.helpPopover"
>
<template #body>
<div class="gl-display-flex gl-flex-direction-column">
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/status_icon.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/status_icon.vue
index ff17de343d6..181b8cfad9a 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/widget/status_icon.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/status_icon.vue
@@ -34,8 +34,8 @@ export default {
iconAriaLabel() {
return `${capitalizeFirstCharacter(this.iconName)} ${this.name}`;
},
- iconSize() {
- return this.level === 1 ? 16 : 12;
+ iconClassNameText() {
+ return this.$options.EXTENSION_ICON_CLASS[this.iconName];
},
},
EXTENSION_ICON_NAMES,
@@ -44,24 +44,22 @@ export default {
</script>
<template>
- <div :class="[$options.EXTENSION_ICON_CLASS[iconName]]" class="gl-mr-3">
+ <div
+ :class="{
+ [iconClassNameText]: !isLoading,
+ [`mr-widget-status-icon-level-${level}`]: !isLoading,
+ 'gl-mr-3': level === 1,
+ }"
+ class="gl-relative gl-w-6 gl-h-6 gl-rounded-full gl--flex-center"
+ >
<gl-loading-icon v-if="isLoading" size="md" inline />
- <div
+ <gl-icon
v-else
- class="gl-display-flex gl-align-items-center gl-justify-content-center gl-rounded-full gl-bg-gray-10"
- :class="{
- 'gl-p-2': level === 1,
- }"
- >
- <div class="gl-rounded-full gl-bg-white">
- <gl-icon
- :name="$options.EXTENSION_ICON_NAMES[iconName]"
- :size="iconSize"
- :aria-label="iconAriaLabel"
- :data-qa-selector="`status_${iconName}_icon`"
- class="gl-display-block"
- />
- </div>
- </div>
+ :name="$options.EXTENSION_ICON_NAMES[iconName]"
+ :size="12"
+ :aria-label="iconAriaLabel"
+ :data-qa-selector="`status_${iconName}_icon`"
+ class="gl-relative gl-z-index-1"
+ />
</div>
</template>
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 94359d7d6ac..cea7fb8260a 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
@@ -1,29 +1,41 @@
<script>
-import { GlButton, GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui';
+import {
+ GlButton,
+ GlLink,
+ GlTooltipDirective,
+ GlLoadingIcon,
+ GlSafeHtmlDirective,
+} from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
import { normalizeHeaders } from '~/lib/utils/common_utils';
import { sprintf, __ } from '~/locale';
import Poll from '~/lib/utils/poll';
+import HelpPopover from '~/vue_shared/components/help_popover.vue';
import ActionButtons from '../action_buttons.vue';
import { EXTENSION_ICONS } from '../../constants';
+import { createTelemetryHub } from '../extensions/telemetry';
import ContentRow from './widget_content_row.vue';
import DynamicContent from './dynamic_content.vue';
import StatusIcon from './status_icon.vue';
const FETCH_TYPE_COLLAPSED = 'collapsed';
const FETCH_TYPE_EXPANDED = 'expanded';
+const WIDGET_PREFIX = 'Widget';
export default {
components: {
ActionButtons,
StatusIcon,
+ GlLink,
GlButton,
GlLoadingIcon,
ContentRow,
DynamicContent,
+ HelpPopover,
},
directives: {
GlTooltip: GlTooltipDirective,
+ SafeHtml: GlSafeHtmlDirective,
},
props: {
/**
@@ -72,8 +84,8 @@ export default {
},
statusIconName: {
type: String,
- default: 'neutral',
required: false,
+ default: 'neutral',
validator: (value) => Object.keys(EXTENSION_ICONS).indexOf(value) > -1,
},
isCollapsible: {
@@ -88,6 +100,26 @@ export default {
widgetName: {
type: String,
required: true,
+ // see https://docs.gitlab.com/ee/development/fe_guide/merge_request_widget_extensions.html#add-new-widgets
+ validator: (val) => val.startsWith(WIDGET_PREFIX),
+ },
+ telemetry: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ /**
+ * @typedef {Object} helpPopover
+ * @property {Object} options
+ * @property {String} options.title
+ * @property {Object} content
+ * @property {String} content.text
+ * @property {String} content.learnMorePath
+ */
+ helpPopover: {
+ type: Object,
+ required: false,
+ default: null,
},
},
data() {
@@ -98,6 +130,7 @@ export default {
isLoadingExpandedContent: false,
summaryError: null,
contentError: null,
+ telemetryHub: null,
};
},
computed: {
@@ -113,8 +146,14 @@ export default {
this.$emit('is-loading', newValue);
},
},
+ created() {
+ if (this.telemetry) {
+ this.telemetryHub = createTelemetryHub(this.widgetName);
+ }
+ },
async mounted() {
this.isLoading = true;
+ this.telemetryHub?.viewed();
try {
await this.fetch(this.fetchCollapsedData, FETCH_TYPE_COLLAPSED);
@@ -125,12 +164,21 @@ export default {
this.isLoading = false;
},
methods: {
+ onActionClick(action) {
+ if (action.fullReport) {
+ this.telemetryHub?.fullReportClicked();
+ }
+ },
toggleCollapsed() {
this.isCollapsed = !this.isCollapsed;
- if (this.isExpandedForTheFirstTime && typeof this.fetchExpandedData === 'function') {
- this.isExpandedForTheFirstTime = false;
- this.fetchExpandedContent();
+ if (this.isExpandedForTheFirstTime) {
+ this.telemetryHub?.expanded({ type: this.summaryStatusIcon });
+
+ if (typeof this.fetchExpandedData === 'function') {
+ this.isExpandedForTheFirstTime = false;
+ this.fetchExpandedContent();
+ }
}
},
async fetchExpandedContent() {
@@ -184,6 +232,9 @@ export default {
},
},
failedStatusIcon: EXTENSION_ICONS.failed,
+ i18n: {
+ learnMore: __('Learn more'),
+ },
};
</script>
@@ -204,11 +255,34 @@ export default {
<span v-if="summaryError">{{ summaryError }}</span>
<slot v-else name="summary">{{ isLoading ? loadingText : summary }}</slot>
</div>
- <action-buttons
- v-if="actionButtons.length > 0"
- :widget="widgetName"
- :tertiary-buttons="actionButtons"
- />
+ <div class="gl-display-flex">
+ <help-popover
+ v-if="helpPopover"
+ :options="helpPopover.options"
+ :class="{ 'gl-mr-3': actionButtons.length > 0 }"
+ >
+ <template v-if="helpPopover.content">
+ <p
+ v-if="helpPopover.content.text"
+ v-safe-html="helpPopover.content.text"
+ class="gl-mb-0"
+ ></p>
+ <gl-link
+ v-if="helpPopover.content.learnMorePath"
+ :href="helpPopover.content.learnMorePath"
+ target="_blank"
+ class="gl-font-sm"
+ >{{ $options.i18n.learnMore }}</gl-link
+ >
+ </template>
+ </help-popover>
+ <action-buttons
+ v-if="actionButtons.length > 0"
+ :widget="widgetName"
+ :tertiary-buttons="actionButtons"
+ @clickedAction="onActionClick"
+ />
+ </div>
<div
v-if="isCollapsible"
class="gl-border-l-1 gl-border-l-solid gl-border-gray-100 gl-ml-3 gl-pl-3 gl-h-6"
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue
index ee81f0950a8..1fd1e325863 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/widget/widget_content_row.vue
@@ -1,5 +1,8 @@
<script>
-import { GlSafeHtmlDirective } from '@gitlab/ui';
+import { GlSafeHtmlDirective, GlLink } from '@gitlab/ui';
+import { __ } from '~/locale';
+import HelpPopover from '~/vue_shared/components/help_popover.vue';
+import ActionButtons from '../action_buttons.vue';
import { EXTENSION_ICONS } from '../../constants';
import { generateText } from '../extensions/utils';
import StatusIcon from './status_icon.vue';
@@ -7,6 +10,9 @@ import StatusIcon from './status_icon.vue';
export default {
components: {
StatusIcon,
+ HelpPopover,
+ GlLink,
+ ActionButtons,
},
directives: {
SafeHtml: GlSafeHtmlDirective,
@@ -19,8 +25,8 @@ export default {
},
statusIconName: {
type: String,
- default: '',
required: false,
+ default: '',
validator: (value) => value === '' || Object.keys(EXTENSION_ICONS).includes(value),
},
widgetName: {
@@ -29,8 +35,26 @@ export default {
},
header: {
type: [String, Array],
+ required: false,
default: '',
+ },
+ /**
+ * @typedef {Object} helpPopover
+ * @property {Object} options
+ * @property {String} options.title
+ * @property {Object} content
+ * @property {String} content.text
+ * @property {String} content.learnMorePath
+ */
+ helpPopover: {
+ type: Object,
required: false,
+ default: null,
+ },
+ actionButtons: {
+ type: Array,
+ required: false,
+ default: () => [],
},
},
computed: {
@@ -40,6 +64,12 @@ export default {
generatedSubheader() {
return Array.isArray(this.header) && this.header[1] ? generateText(this.header[1]) : '';
},
+ shouldShowHeaderActions() {
+ return Boolean(this.helpPopover) || this.actionButtons?.length > 0;
+ },
+ },
+ i18n: {
+ learnMore: __('Learn more'),
},
};
</script>
@@ -49,17 +79,46 @@ export default {
:class="{ 'gl-border-t gl-py-3 gl-pl-7': level === 2 }"
>
<status-icon v-if="statusIconName" :level="2" :name="widgetName" :icon-name="statusIconName" />
- <div>
- <slot name="header">
- <div v-if="header" class="gl-mb-2">
- <strong v-safe-html="generatedHeader" class="gl-display-block"></strong
- ><span
- v-if="generatedSubheader"
- v-safe-html="generatedSubheader"
- class="gl-display-block"
- ></span>
+ <div class="gl-w-full">
+ <div class="gl-display-flex">
+ <slot name="header">
+ <div v-if="header" class="gl-mb-2">
+ <strong v-safe-html="generatedHeader" class="gl-display-block"></strong
+ ><span
+ v-if="generatedSubheader"
+ v-safe-html="generatedSubheader"
+ class="gl-display-block"
+ ></span>
+ </div>
+ </slot>
+ <div
+ v-if="shouldShowHeaderActions"
+ class="gl-ml-auto gl-display-flex gl-align-items-baseline"
+ >
+ <help-popover v-if="helpPopover" :options="helpPopover.options">
+ <template v-if="helpPopover.content">
+ <p
+ v-if="helpPopover.content.text"
+ v-safe-html="helpPopover.content.text"
+ class="gl-mb-0"
+ ></p>
+ <gl-link
+ v-if="helpPopover.content.learnMorePath"
+ :href="helpPopover.content.learnMorePath"
+ target="_blank"
+ class="gl-font-sm"
+ >{{ $options.i18n.learnMore }}</gl-link
+ >
+ </template>
+ </help-popover>
+ <action-buttons
+ v-if="actionButtons.length > 0"
+ :widget="widgetName"
+ :tertiary-buttons="actionButtons"
+ :class="{ 'gl-ml-2': helpPopover }"
+ />
</div>
- </slot>
+ </div>
<div class="gl-display-flex gl-align-items-baseline gl-w-full">
<slot name="body"></slot>
</div>
diff --git a/app/assets/javascripts/vue_merge_request_widget/constants.js b/app/assets/javascripts/vue_merge_request_widget/constants.js
index c6baf3b46ff..7109bed7743 100644
--- a/app/assets/javascripts/vue_merge_request_widget/constants.js
+++ b/app/assets/javascripts/vue_merge_request_widget/constants.js
@@ -192,4 +192,5 @@ export const DETAILED_MERGE_STATUS = {
POLICIES_DENIED: 'POLICIES_DENIED',
CI_MUST_PASS: 'CI_MUST_PASS',
CI_STILL_RUNNING: 'CI_STILL_RUNNING',
+ EXTERNAL_STATUS_CHECKS: 'EXTERNAL_STATUS_CHECKS',
};
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 a3f70b551bf..b96bdcb3833 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,7 +1,10 @@
<script>
import { GlSafeHtmlDirective } from '@gitlab/ui';
import { isEmpty } from 'lodash';
-import { registerExtension } from '~/vue_merge_request_widget/components/extensions';
+import {
+ registerExtension,
+ registeredExtensions,
+} from '~/vue_merge_request_widget/components/extensions';
import MrWidgetApprovals from 'ee_else_ce/vue_merge_request_widget/components/approvals/approvals.vue';
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';
@@ -47,6 +50,7 @@ import terraformExtension from './extensions/terraform';
import accessibilityExtension from './extensions/accessibility';
import codeQualityExtension from './extensions/code_quality';
import testReportExtension from './extensions/test_report';
+import ReportWidgetContainer from './components/report_widget_container.vue';
export default {
// False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/25
@@ -82,21 +86,18 @@ export default {
MrWidgetAutoMergeFailed: AutoMergeFailed,
MrWidgetRebase: RebaseState,
SourceBranchRemovalStatus,
- GroupedCodequalityReportsApp: () =>
- import('../reports/codequality_report/grouped_codequality_reports_app.vue'),
- GroupedTestReportsApp: () =>
- import('../reports/grouped_test_report/grouped_test_reports_app.vue'),
MrWidgetApprovals,
SecurityReportsApp: () => import('~/vue_shared/security_reports/security_reports_app.vue'),
MergeChecksFailed: () => import('./components/states/merge_checks_failed.vue'),
ReadyToMerge: ReadyToMergeState,
+ ReportWidgetContainer,
},
apollo: {
state: {
query: getStateQuery,
manual: true,
skip() {
- return !this.mr || !window.gon?.features?.mergeRequestWidgetGraphql;
+ return !this.mr;
},
variables() {
return this.mergeRequestQueryVariables;
@@ -130,13 +131,6 @@ export default {
};
},
computed: {
- isLoaded() {
- if (window.gon?.features?.mergeRequestWidgetGraphql) {
- return !this.loading;
- }
-
- return this.mr;
- },
shouldRenderApprovals() {
return this.mr.state !== 'nothingToMerge';
},
@@ -185,9 +179,6 @@ export default {
shouldRenderTestReport() {
return Boolean(this.mr?.testResultsPath);
},
- shouldRenderRefactoredTestReport() {
- return window.gon?.features?.refactorMrWidgetTestSummary;
- },
mergeError() {
let { mergeError } = this.mr;
@@ -218,14 +209,14 @@ export default {
shouldShowSecurityExtension() {
return window.gon?.features?.refactorSecurityExtension;
},
- shouldShowCodeQualityExtension() {
- return window.gon?.features?.refactorCodeQualityExtension;
- },
shouldShowMergeDetails() {
if (this.mr.state === 'readyToMerge') return true;
return !this.mr.mergeDetailsCollapsed;
},
+ hasExtensions() {
+ return registeredExtensions.extensions.length;
+ },
},
watch: {
'mr.machineValue': {
@@ -343,9 +334,7 @@ export default {
return new MRWidgetService(this.getServiceEndpoints(store));
},
checkStatus(cb, isRebased) {
- if (window.gon?.features?.mergeRequestWidgetGraphql) {
- this.$apollo.queries.state.refetch();
- }
+ this.$apollo.queries.state.refetch();
return this.service
.checkStatus()
@@ -519,12 +508,12 @@ export default {
}
},
registerCodeQualityExtension() {
- if (this.shouldRenderCodeQuality && this.shouldShowCodeQualityExtension) {
+ if (this.shouldRenderCodeQuality) {
registerExtension(codeQualityExtension);
}
},
registerTestReportExtension() {
- if (this.shouldRenderTestReport && this.shouldRenderRefactoredTestReport) {
+ if (this.shouldRenderTestReport) {
registerExtension(testReportExtension);
}
},
@@ -532,7 +521,7 @@ export default {
};
</script>
<template>
- <div v-if="isLoaded" class="mr-state-widget gl-mt-3">
+ <div v-if="!loading" class="mr-state-widget gl-mt-3">
<header
v-if="shouldRenderCollaborationStatus"
class="gl-rounded-base gl-border-solid gl-border-1 gl-border-gray-100 gl-overflow-hidden mr-widget-workflow gl-mt-0!"
@@ -552,17 +541,19 @@ export default {
:user-callout-feature-id="mr.suggestPipelineFeatureId"
@dismiss="dismissSuggestPipelines"
/>
- <mr-widget-pipeline-container
- v-if="shouldRenderPipelines"
- class="mr-widget-workflow"
- :mr="mr"
- />
- <mr-widget-approvals
- v-if="shouldRenderApprovals"
- class="mr-widget-workflow"
- :mr="mr"
- :service="service"
- />
+ <mr-widget-pipeline-container v-if="shouldRenderPipelines" :mr="mr" />
+ <mr-widget-approvals v-if="shouldRenderApprovals" :mr="mr" :service="service" />
+ <report-widget-container>
+ <extensions-container v-if="hasExtensions" :mr="mr" />
+ <security-reports-app
+ v-if="shouldRenderSecurityReport && !shouldShowSecurityExtension"
+ :pipeline-id="mr.pipeline.id"
+ :project-id="mr.sourceProjectId"
+ :security-reports-docs-path="mr.securityReportsDocsPath"
+ :target-project-full-path="mr.targetProjectFullPath"
+ :mr-iid="mr.iid"
+ />
+ </report-widget-container>
<div class="mr-section-container mr-widget-workflow">
<div v-if="hasAlerts" class="gl-overflow-hidden mr-widget-alert-container">
<mr-widget-alert-message
@@ -589,35 +580,8 @@ export default {
</mr-widget-alert-message>
</div>
- <extensions-container :mr="mr" />
-
<widget-container v-if="mr" :mr="mr" />
- <grouped-codequality-reports-app
- v-if="shouldRenderCodeQuality && !shouldShowCodeQualityExtension"
- :head-blob-path="mr.headBlobPath"
- :base-blob-path="mr.baseBlobPath"
- :codequality-reports-path="mr.codequalityReportsPath"
- :codequality-help-path="mr.codequalityHelpPath"
- />
-
- <security-reports-app
- v-if="shouldRenderSecurityReport && !shouldShowSecurityExtension"
- :pipeline-id="mr.pipeline.id"
- :project-id="mr.sourceProjectId"
- :security-reports-docs-path="mr.securityReportsDocsPath"
- :target-project-full-path="mr.targetProjectFullPath"
- :mr-iid="mr.iid"
- />
-
- <grouped-test-reports-app
- v-if="shouldRenderTestReport && !shouldRenderRefactoredTestReport"
- class="js-reports-container"
- :endpoint="mr.testResultsPath"
- :head-blob-path="mr.headBlobPath"
- :pipeline-path="mr.pipeline.path"
- />
-
<div class="mr-widget-section" data-qa-selector="mr_widget_content">
<component :is="componentName" :mr="mr" :service="service" />
<ready-to-merge
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 731d3886f61..86ce032ea3d 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
@@ -29,6 +29,7 @@ export default class MergeRequestStore {
this.stateMachine = machine(STATE_MACHINE.definition);
this.machineValue = this.stateMachine.value;
this.mergeDetailsCollapsed = window.innerWidth < 768;
+ this.mergeError = data.mergeError;
this.setPaths(data);
@@ -157,25 +158,6 @@ export default class MergeRequestStore {
this.mergeCommitPath = data.merged_commit_path;
this.canPushToSourceBranch = data.can_push_to_source_branch;
- if (!window.gon?.features?.mergeRequestWidgetGraphql) {
- this.autoMergeEnabled = Boolean(data.auto_merge_enabled);
- this.canBeMerged = data.can_be_merged || false;
- this.canMerge = Boolean(data.merge_path);
- this.commitsCount = data.commits_count;
- this.branchMissing = data.branch_missing;
- this.hasConflicts = data.has_conflicts;
- this.hasMergeableDiscussionsState = data.mergeable_discussions_state === false;
- this.isPipelineFailed = this.ciStatus === 'failed' || this.ciStatus === 'canceled';
- this.mergeError = data.merge_error;
- this.mergeStatus = data.merge_status;
- this.onlyAllowMergeIfPipelineSucceeds = data.only_allow_merge_if_pipeline_succeeds || false;
- this.allowMergeOnSkippedPipeline = data.allow_merge_on_skipped_pipeline || false;
- this.projectArchived = data.project_archived;
- this.isSHAMismatch = this.sha !== data.diff_head_sha;
- this.shouldBeRebased = Boolean(data.should_be_rebased);
- this.draft = data.draft;
- }
-
const currentUser = data.current_user;
this.cherryPickInForkPath = currentUser.cherry_pick_in_fork_path;
@@ -299,7 +281,6 @@ export default class MergeRequestStore {
this.headBlobPath = blobPath.head_path || '';
this.baseBlobPath = blobPath.base_path || '';
this.codequalityReportsPath = data.codequality_reports_path;
- this.codequalityHelpPath = data.codequality_help_path;
// Security reports
this.sastComparisonPath = data.sast_comparison_path;
diff --git a/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue b/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue
index f2ea55df63d..96c2ffa929c 100644
--- a/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue
+++ b/app/assets/javascripts/vue_shared/alert_details/components/alert_details.vue
@@ -145,11 +145,14 @@ export default {
},
currentTabIndex: {
get() {
- return this.$options.tabsConfig.findIndex((tab) => tab.id === this.activeTab);
+ const tabIndex = this.$options.tabsConfig.findIndex((tab) => tab.id === this.activeTab);
+ return tabIndex >= 0 ? tabIndex : 0;
},
set(tabIdx) {
const tabId = this.$options.tabsConfig[tabIdx].id;
- this.$router.replace({ name: 'tab', params: { tabId } });
+ if (this.$route.params?.tabId !== tabId) {
+ this.$router.push({ name: 'tab', params: { tabId } });
+ }
},
},
environmentName() {
diff --git a/app/assets/javascripts/vue_shared/alert_details/index.js b/app/assets/javascripts/vue_shared/alert_details/index.js
index 5793069440c..357dfa49901 100644
--- a/app/assets/javascripts/vue_shared/alert_details/index.js
+++ b/app/assets/javascripts/vue_shared/alert_details/index.js
@@ -15,9 +15,17 @@ Vue.use(VueApollo);
export default (selector) => {
const domEl = document.querySelector(selector);
- const { alertId, projectPath, projectIssuesPath, projectId, page, canUpdate } = domEl.dataset;
+ const {
+ alertId,
+ projectPath,
+ projectIssuesPath,
+ projectAlertManagementDetailsPath,
+ projectId,
+ page,
+ canUpdate,
+ } = domEl.dataset;
const iid = alertId;
- const router = createRouter();
+ const router = createRouter(projectAlertManagementDetailsPath);
const resolvers = {
Mutation: {
diff --git a/app/assets/javascripts/vue_shared/alert_details/router.js b/app/assets/javascripts/vue_shared/alert_details/router.js
index 5687fe4e0f5..26477a3a66a 100644
--- a/app/assets/javascripts/vue_shared/alert_details/router.js
+++ b/app/assets/javascripts/vue_shared/alert_details/router.js
@@ -5,9 +5,26 @@ import { joinPaths } from '~/lib/utils/url_utility';
Vue.use(VueRouter);
export default function createRouter(base) {
- return new VueRouter({
- mode: 'hash',
+ const router = new VueRouter({
+ mode: 'history',
base: joinPaths(gon.relative_url_root || '', base),
routes: [{ path: '/:tabId', name: 'tab' }],
});
+
+ /*
+ Backward-compatible behavior. Redirects hash mode URLs to history mode ones.
+ Ex: from #/overview to /overview
+ from #/metrics to /metrics
+ from #/activity to /activity
+ */
+ router.beforeEach((to, _, next) => {
+ if (to.hash.startsWith('#/')) {
+ const path = to.fullPath.substring(2);
+ next(path);
+ } else {
+ next();
+ }
+ });
+
+ return router;
}
diff --git a/app/assets/javascripts/vue_shared/components/blob_viewers/rich_viewer.vue b/app/assets/javascripts/vue_shared/components/blob_viewers/rich_viewer.vue
index dc4d1bd56e9..ed0eb9cc0b8 100644
--- a/app/assets/javascripts/vue_shared/components/blob_viewers/rich_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/blob_viewers/rich_viewer.vue
@@ -15,8 +15,14 @@ export default {
mounted() {
handleBlobRichViewer(this.$refs.content, this.type);
},
+ safeHtmlConfig: {
+ ADD_TAGS: ['copy-code'],
+ },
};
</script>
<template>
- <markdown-field-view ref="content" v-safe-html="richViewer || content" />
+ <markdown-field-view
+ ref="content"
+ v-safe-html:[$options.safeHtmlConfig]="richViewer || content"
+ />
</template>
diff --git a/app/assets/javascripts/vue_shared/components/code_block.stories.js b/app/assets/javascripts/vue_shared/components/code_block.stories.js
index e02a346c1de..994913dc1a8 100644
--- a/app/assets/javascripts/vue_shared/components/code_block.stories.js
+++ b/app/assets/javascripts/vue_shared/components/code_block.stories.js
@@ -13,6 +13,5 @@ const Template = (args, { argTypes }) => ({
export const Default = Template.bind({});
Default.args = {
- // eslint-disable-next-line @gitlab/require-i18n-strings
code: `git commit -a "Message"\ngit push`,
};
diff --git a/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger.vue b/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger.vue
index 5b9efff1c06..2bdc8a174d0 100644
--- a/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger.vue
+++ b/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger.vue
@@ -36,6 +36,11 @@ export default {
required: false,
default: 'confirm-danger-button',
},
+ buttonQaSelector: {
+ type: String,
+ required: false,
+ default: null,
+ },
buttonVariant: {
type: String,
required: false,
@@ -53,7 +58,7 @@ export default {
:variant="buttonVariant"
:disabled="disabled"
:data-testid="buttonTestid"
- data-qa-selector="confirm_danger_button"
+ :data-qa-selector="buttonQaSelector"
>{{ buttonText }}</gl-button
>
<confirm-danger-modal
diff --git a/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.stories.js b/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.stories.js
index 7ecc309db52..b56434f746e 100644
--- a/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.stories.js
+++ b/app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger_modal.stories.js
@@ -1,4 +1,3 @@
-/* eslint-disable @gitlab/require-i18n-strings */
import ConfirmDanger from './confirm_danger.vue';
export default {
diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.stories.js b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.stories.js
index 8256d953466..a48b8bcfa8e 100644
--- a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.stories.js
+++ b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.stories.js
@@ -1,5 +1,3 @@
-/* eslint-disable @gitlab/require-i18n-strings */
-
import { __ } from '~/locale';
import DropdownWidget from './dropdown_widget.vue';
diff --git a/app/assets/javascripts/vue_shared/components/file_row.vue b/app/assets/javascripts/vue_shared/components/file_row.vue
index 2227047a909..8a3a174f414 100644
--- a/app/assets/javascripts/vue_shared/components/file_row.vue
+++ b/app/assets/javascripts/vue_shared/components/file_row.vue
@@ -45,7 +45,7 @@ export default {
},
levelIndentation() {
return {
- marginLeft: this.level ? `${this.level * 16}px` : null,
+ marginLeft: this.level ? `${this.level * 8}px` : null,
};
},
fileClass() {
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js b/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js
index 4873996d357..755ce004aa9 100644
--- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js
+++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js
@@ -13,11 +13,19 @@ export const FILTER_NONE_ANY = [FILTER_NONE, FILTER_ANY];
export const OPERATOR_IS = '=';
export const OPERATOR_IS_TEXT = __('is');
export const OPERATOR_IS_NOT = '!=';
-export const OPERATOR_IS_NOT_TEXT = __('is not');
+export const OPERATOR_IS_NOT_TEXT = __('is not one of');
+export const OPERATOR_OR = '||';
+export const OPERATOR_OR_TEXT = __('is one of');
export const OPERATOR_IS_ONLY = [{ value: OPERATOR_IS, description: OPERATOR_IS_TEXT }];
export const OPERATOR_IS_NOT_ONLY = [{ value: OPERATOR_IS_NOT, description: OPERATOR_IS_NOT_TEXT }];
+export const OPERATOR_OR_ONLY = [{ value: OPERATOR_OR, description: OPERATOR_OR_TEXT }];
export const OPERATOR_IS_AND_IS_NOT = [...OPERATOR_IS_ONLY, ...OPERATOR_IS_NOT_ONLY];
+export const OPERATOR_IS_NOT_OR = [
+ ...OPERATOR_IS_ONLY,
+ ...OPERATOR_IS_NOT_ONLY,
+ ...OPERATOR_OR_ONLY,
+];
export const DEFAULT_LABEL_NONE = { value: FILTER_NONE, text: __('None'), title: __('None') };
export const DEFAULT_LABEL_ANY = { value: FILTER_ANY, text: __('Any'), title: __('Any') };
@@ -55,10 +63,26 @@ export const TOKEN_TITLE_MILESTONE = __('Milestone');
export const TOKEN_TITLE_MY_REACTION = __('My-Reaction');
export const TOKEN_TITLE_ORGANIZATION = s__('Crm|Organization');
export const TOKEN_TITLE_RELEASE = __('Release');
+export const TOKEN_TITLE_SOURCE_BRANCH = __('Source Branch');
+export const TOKEN_TITLE_STATUS = __('Status');
+export const TOKEN_TITLE_TARGET_BRANCH = __('Target Branch');
export const TOKEN_TITLE_TYPE = __('Type');
+export const TOKEN_TYPE_ASSIGNEE = 'assignee';
+export const TOKEN_TYPE_AUTHOR = 'author';
+export const TOKEN_TYPE_CONFIDENTIAL = 'confidential';
+export const TOKEN_TYPE_CONTACT = 'contact';
+export const TOKEN_TYPE_EPIC = 'epic';
// As health status gets reused between issue lists and boards
// this is in the shared constants. Until we have not decoupled the EE filtered search bar
// from the CE component, we need to keep this in the CE code.
// https://gitlab.com/gitlab-org/gitlab/-/issues/377838
-export const TOKEN_TYPE_HEALTH = 'health_status';
+export const TOKEN_TYPE_HEALTH = 'health';
+export const TOKEN_TYPE_ITERATION = 'iteration';
+export const TOKEN_TYPE_LABEL = 'label';
+export const TOKEN_TYPE_MILESTONE = 'milestone';
+export const TOKEN_TYPE_MY_REACTION = 'my-reaction';
+export const TOKEN_TYPE_ORGANIZATION = 'organization';
+export const TOKEN_TYPE_RELEASE = 'release';
+export const TOKEN_TYPE_TYPE = 'type';
+export const TOKEN_TYPE_WEIGHT = 'weight';
diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue
index 8821084ef35..0d0787e7033 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
@@ -89,6 +89,11 @@ export default {
required: false,
default: () => ({}),
},
+ showFriendlyText: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
syncFilterAndSort: {
type: Boolean,
required: false,
@@ -319,7 +324,7 @@ export default {
(sortBy) =>
sortBy.sortDirection.ascending === sort || sortBy.sortDirection.descending === sort,
);
- this.selectedSortDirection = Object.keys(this.selectedSortOption.sortDirection).find(
+ this.selectedSortDirection = Object.keys(this.selectedSortOption?.sortDirection || {}).find(
(key) => this.selectedSortOption.sortDirection[key] === sort,
);
},
@@ -351,6 +356,7 @@ export default {
:close-button-title="__('Close')"
:clear-recent-searches-text="__('Clear recent searches')"
:no-recent-searches-text="__(`You don't have any recent searches`)"
+ :show-friendly-text="showFriendlyText"
class="flex-grow-1"
@history-item-selected="handleHistoryItemSelected"
@clear="onClear"
diff --git a/app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue b/app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue
index 482a2964b4c..2f10e068542 100644
--- a/app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue
+++ b/app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue
@@ -129,6 +129,8 @@ export default {
v-gl-tooltip.hover="toggleVisibilityLabel"
:aria-label="toggleVisibilityLabel"
:icon="toggleVisibilityIcon"
+ data-testid="toggle-visibility-button"
+ data-qa-selector="toggle_visibility_button"
@click.stop="handleToggleVisibilityButtonClick"
/>
<clipboard-button
diff --git a/app/assets/javascripts/vue_shared/components/gitlab_version_check.vue b/app/assets/javascripts/vue_shared/components/gitlab_version_check.vue
deleted file mode 100644
index c2be5e4f7a1..00000000000
--- a/app/assets/javascripts/vue_shared/components/gitlab_version_check.vue
+++ /dev/null
@@ -1,89 +0,0 @@
-<script>
-import { GlBadge } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import Tracking from '~/tracking';
-import axios from '~/lib/utils/axios_utils';
-import { joinPaths } from '~/lib/utils/url_utility';
-import { helpPagePath } from '~/helpers/help_page_helper';
-
-const STATUS_TYPES = {
- SUCCESS: 'success',
- WARNING: 'warning',
- DANGER: 'danger',
-};
-
-const UPGRADE_DOCS_URL = helpPagePath('update/index');
-
-export default {
- name: 'GitlabVersionCheck',
- components: {
- GlBadge,
- },
- mixins: [Tracking.mixin()],
- props: {
- size: {
- type: String,
- required: false,
- default: 'md',
- },
- },
- data() {
- return {
- status: null,
- };
- },
- computed: {
- title() {
- if (this.status === STATUS_TYPES.SUCCESS) {
- return s__('VersionCheck|Up to date');
- } else if (this.status === STATUS_TYPES.WARNING) {
- return s__('VersionCheck|Update available');
- } else if (this.status === STATUS_TYPES.DANGER) {
- return s__('VersionCheck|Update ASAP');
- }
-
- return null;
- },
- },
- created() {
- this.checkGitlabVersion();
- },
- methods: {
- checkGitlabVersion() {
- axios
- .get(joinPaths('/', gon.relative_url_root, '/admin/version_check.json'))
- .then((res) => {
- if (res.data) {
- this.status = res.data.severity;
-
- this.track('rendered_version_badge', {
- label: this.title,
- });
- }
- })
- .catch(() => {
- // Silently fail
- this.status = null;
- });
- },
- onClick() {
- this.track('click_version_badge', { label: this.title });
- },
- },
- UPGRADE_DOCS_URL,
-};
-</script>
-
-<template>
- <!-- TODO: remove the span element once bootstrap-vue is updated to version 2.21.1 -->
- <!-- TODO: https://github.com/bootstrap-vue/bootstrap-vue/issues/6219 -->
- <span v-if="status" data-testid="badge-click-wrapper" @click="onClick">
- <gl-badge
- :href="$options.UPGRADE_DOCS_URL"
- class="version-check-badge"
- :variant="status"
- :size="size"
- >{{ title }}</gl-badge
- >
- </span>
-</template>
diff --git a/app/assets/javascripts/vue_shared/components/group_select/constants.js b/app/assets/javascripts/vue_shared/components/group_select/constants.js
new file mode 100644
index 00000000000..bc70936eb36
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/group_select/constants.js
@@ -0,0 +1,6 @@
+import { __ } from '~/locale';
+
+export const TOGGLE_TEXT = __('Search for a group');
+export const FETCH_GROUPS_ERROR = __('Unable to fetch groups. Reload the page to try again.');
+export const FETCH_GROUP_ERROR = __('Unable to fetch group. Reload the page to try again.');
+export const QUERY_TOO_SHORT_MESSAGE = __('Enter at least three characters to search.');
diff --git a/app/assets/javascripts/vue_shared/components/group_select/group_select.vue b/app/assets/javascripts/vue_shared/components/group_select/group_select.vue
new file mode 100644
index 00000000000..1de6c0121bc
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/group_select/group_select.vue
@@ -0,0 +1,195 @@
+<script>
+import { debounce } from 'lodash';
+import { GlListbox } from '@gitlab/ui';
+import axios from '~/lib/utils/axios_utils';
+import Api from '~/api';
+import { __ } from '~/locale';
+import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
+import { createAlert } from '~/flash';
+import { groupsPath } from './utils';
+import {
+ TOGGLE_TEXT,
+ FETCH_GROUPS_ERROR,
+ FETCH_GROUP_ERROR,
+ QUERY_TOO_SHORT_MESSAGE,
+} from './constants';
+
+const MINIMUM_QUERY_LENGTH = 3;
+
+export default {
+ components: {
+ GlListbox,
+ },
+ props: {
+ inputName: {
+ type: String,
+ required: true,
+ },
+ inputId: {
+ type: String,
+ required: true,
+ },
+ initialSelection: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ clearable: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ parentGroupID: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ groupsFilter: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+ data() {
+ return {
+ pristine: true,
+ searching: false,
+ searchString: '',
+ groups: [],
+ selectedValue: null,
+ selectedText: null,
+ };
+ },
+ computed: {
+ selected: {
+ set(value) {
+ this.selectedValue = value;
+ this.selectedText =
+ value === null ? null : this.groups.find((group) => group.value === value).full_name;
+ },
+ get() {
+ return this.selectedValue;
+ },
+ },
+ toggleText() {
+ return this.selectedText ?? this.$options.i18n.toggleText;
+ },
+ inputValue() {
+ return this.selectedValue ? this.selectedValue : '';
+ },
+ isSearchQueryTooShort() {
+ return this.searchString && this.searchString.length < MINIMUM_QUERY_LENGTH;
+ },
+ noResultsText() {
+ return this.isSearchQueryTooShort
+ ? this.$options.i18n.searchQueryTooShort
+ : this.$options.i18n.noResultsText;
+ },
+ },
+ created() {
+ this.fetchInitialSelection();
+ },
+ methods: {
+ search: debounce(function debouncedSearch(searchString) {
+ this.searchString = searchString;
+ if (this.isSearchQueryTooShort) {
+ this.groups = [];
+ } else {
+ this.fetchGroups(searchString);
+ }
+ }, DEFAULT_DEBOUNCE_AND_THROTTLE_MS),
+ async fetchGroups(searchString = '') {
+ this.searching = true;
+
+ try {
+ const { data } = await axios.get(
+ Api.buildUrl(groupsPath(this.groupsFilter, this.parentGroupID)),
+ {
+ params: {
+ search: searchString,
+ },
+ },
+ );
+ const groups = data.length ? data : data.results || [];
+
+ this.groups = groups.map((group) => ({
+ ...group,
+ value: String(group.id),
+ }));
+
+ this.searching = false;
+ } catch (error) {
+ createAlert({
+ message: FETCH_GROUPS_ERROR,
+ error,
+ parent: this.$el,
+ });
+ }
+ },
+ async fetchInitialSelection() {
+ if (!this.initialSelection) {
+ this.pristine = false;
+ return;
+ }
+ this.searching = true;
+ try {
+ const group = await Api.group(this.initialSelection);
+ this.selectedValue = this.initialSelection;
+ this.selectedText = group.full_name;
+ this.pristine = false;
+ this.searching = false;
+ } catch (error) {
+ createAlert({
+ message: FETCH_GROUP_ERROR,
+ error,
+ parent: this.$el,
+ });
+ }
+ },
+ onShown() {
+ if (!this.searchString && !this.groups.length) {
+ this.fetchGroups();
+ }
+ },
+ onReset() {
+ this.selected = null;
+ },
+ },
+ i18n: {
+ toggleText: TOGGLE_TEXT,
+ selectGroup: __('Select a group'),
+ reset: __('Reset'),
+ noResultsText: __('No results found.'),
+ searchQueryTooShort: QUERY_TOO_SHORT_MESSAGE,
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-listbox
+ ref="listbox"
+ v-model="selected"
+ :header-text="$options.i18n.selectGroup"
+ :reset-button-label="$options.i18n.reset"
+ :toggle-text="toggleText"
+ :loading="searching && pristine"
+ :searching="searching"
+ :items="groups"
+ :no-results-text="noResultsText"
+ searchable
+ @shown="onShown"
+ @search="search"
+ @reset="onReset"
+ >
+ <template #list-item="{ item }">
+ <div class="gl-font-weight-bold">
+ {{ item.full_name }}
+ </div>
+ <div class="gl-text-gray-300">{{ item.full_path }}</div>
+ </template>
+ </gl-listbox>
+ <div class="flash-container"></div>
+ <input :id="inputId" data-testid="input" type="hidden" :name="inputName" :value="inputValue" />
+ </div>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/help_popover.vue b/app/assets/javascripts/vue_shared/components/help_popover.vue
index 1b89bd324c6..f349aa78bac 100644
--- a/app/assets/javascripts/vue_shared/components/help_popover.vue
+++ b/app/assets/javascripts/vue_shared/components/help_popover.vue
@@ -20,6 +20,11 @@ export default {
required: false,
default: () => ({}),
},
+ icon: {
+ type: String,
+ required: false,
+ default: 'question-o',
+ },
},
methods: {
targetFn() {
@@ -30,7 +35,7 @@ export default {
</script>
<template>
<span>
- <gl-button ref="popoverTrigger" variant="link" icon="question-o" :aria-label="__('Help')" />
+ <gl-button ref="popoverTrigger" variant="link" :icon="icon" :aria-label="__('Help')" />
<gl-popover :target="targetFn" v-bind="options">
<template v-if="options.title" #title>
<span v-safe-html="options.title"></span>
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 b38772d5aa5..c0712e46613 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue
@@ -72,7 +72,7 @@ export default {
required: false,
default: '',
},
- initOnAutofocus: {
+ autofocus: {
type: Boolean,
required: false,
default: false,
@@ -87,20 +87,20 @@ export default {
return {
editingMode: EDITING_MODE_MARKDOWN_FIELD,
switchEditingControlEnabled: true,
- autofocus: this.initOnAutofocus,
+ autofocused: false,
};
},
computed: {
isContentEditorActive() {
return this.enableContentEditor && this.editingMode === EDITING_MODE_CONTENT_EDITOR;
},
- contentEditorAutofocus() {
+ contentEditorAutofocused() {
// Match textarea focus behavior
- return this.autofocus ? 'end' : false;
+ return this.autofocus && !this.autofocused ? 'end' : false;
},
},
mounted() {
- this.autofocusTextarea(this.editingMode);
+ this.autofocusTextarea();
},
methods: {
updateMarkdownFromContentEditor({ markdown }) {
@@ -120,7 +120,6 @@ export default {
},
onEditingModeChange(editingMode) {
this.notifyEditingModeChange(editingMode);
- this.enableAutofocus(editingMode);
},
onEditingModeRestored(editingMode) {
this.notifyEditingModeChange(editingMode);
@@ -128,15 +127,15 @@ export default {
notifyEditingModeChange(editingMode) {
this.$emit(editingMode);
},
- enableAutofocus(editingMode) {
- this.autofocus = true;
- this.autofocusTextarea(editingMode);
- },
- autofocusTextarea(editingMode) {
- if (this.autofocus && editingMode === EDITING_MODE_MARKDOWN_FIELD) {
+ autofocusTextarea() {
+ if (this.autofocus && this.editingMode === EDITING_MODE_MARKDOWN_FIELD) {
this.$refs.textarea.focus();
+ this.setEditorAsAutofocused();
}
},
+ setEditorAsAutofocused() {
+ this.autofocused = true;
+ },
},
switchEditingControlOptions: [
{ text: __('Source'), value: EDITING_MODE_MARKDOWN_FIELD },
@@ -197,7 +196,8 @@ export default {
:render-markdown="renderMarkdown"
:uploads-path="uploadsPath"
:markdown="value"
- :autofocus="contentEditorAutofocus"
+ :autofocus="contentEditorAutofocused"
+ @initialized="setEditorAsAutofocused"
@change="updateMarkdownFromContentEditor"
@loading="disableSwitchEditingControl"
@loadingSuccess="enableSwitchEditingControl"
diff --git a/app/assets/javascripts/vue_shared/components/markdown_drawer/makrdown_drawer.stories.js b/app/assets/javascripts/vue_shared/components/markdown_drawer/makrdown_drawer.stories.js
new file mode 100644
index 00000000000..03bd64e2a57
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/markdown_drawer/makrdown_drawer.stories.js
@@ -0,0 +1,54 @@
+import { GlButton } from '@gitlab/ui';
+import { MOCK_HTML } from '../../../../../../spec/frontend/vue_shared/components/markdown_drawer/mock_data';
+import MarkdownDrawer from './markdown_drawer.vue';
+
+export default {
+ component: MarkdownDrawer,
+ title: 'vue_shared/markdown_drawer',
+ parameters: {
+ mirage: {
+ timing: 1000,
+ handlers: {
+ get: {
+ '/help/user/search/global_search/advanced_search_syntax.json': [
+ 200,
+ {},
+ { html: MOCK_HTML },
+ ],
+ },
+ },
+ },
+ },
+};
+
+const createStory = ({ ...options }) => (_, { argTypes }) => ({
+ components: { MarkdownDrawer, GlButton },
+ props: Object.keys(argTypes),
+ data() {
+ return {
+ render: false,
+ };
+ },
+ methods: {
+ toggleDrawer() {
+ this.$refs.drawer.toggleDrawer();
+ },
+ },
+ mounted() {
+ window.requestAnimationFrame(() => {
+ this.render = true;
+ });
+ },
+ template: `
+ <div v-if="render">
+ <gl-button @click="toggleDrawer">Open Drawer</gl-button>
+ <markdown-drawer
+ :documentPath="'user/search/global_search/advanced_search_syntax.json'"
+ ref="drawer"
+ />
+ </div>
+ `,
+ ...options,
+});
+
+export const Default = createStory({});
diff --git a/app/assets/javascripts/vue_shared/components/markdown_drawer/markdown_drawer.vue b/app/assets/javascripts/vue_shared/components/markdown_drawer/markdown_drawer.vue
new file mode 100644
index 00000000000..a4b509f8656
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/markdown_drawer/markdown_drawer.vue
@@ -0,0 +1,117 @@
+<script>
+import { GlSafeHtmlDirective as SafeHtml, GlDrawer, GlAlert, GlSkeletonLoader } from '@gitlab/ui';
+import $ from 'jquery';
+import '~/behaviors/markdown/render_gfm';
+import { s__ } from '~/locale';
+import { contentTop } from '~/lib/utils/common_utils';
+import { getRenderedMarkdown } from './utils/fetch';
+
+export const cache = {};
+
+export default {
+ name: 'MarkdownDrawer',
+ components: {
+ GlDrawer,
+ GlAlert,
+ GlSkeletonLoader,
+ },
+ directives: {
+ SafeHtml,
+ },
+ i18n: {
+ alert: s__('MardownDrawer|Could not fetch help contents.'),
+ },
+ props: {
+ documentPath: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ loading: false,
+ hasFetchError: false,
+ title: '',
+ body: null,
+ open: false,
+ };
+ },
+ computed: {
+ drawerOffsetTop() {
+ return `${contentTop()}px`;
+ },
+ },
+ watch: {
+ documentPath: {
+ immediate: true,
+ handler: 'fetchMarkdown',
+ },
+ open(open) {
+ if (open && this.body) {
+ this.renderGLFM();
+ }
+ },
+ },
+ methods: {
+ async fetchMarkdown() {
+ const cached = cache[this.documentPath];
+ this.hasFetchError = false;
+ this.title = '';
+ if (cached) {
+ this.title = cached.title;
+ this.body = cached.body;
+ if (this.open) {
+ this.renderGLFM();
+ }
+ } else {
+ this.loading = true;
+ const { body, title, hasFetchError } = await getRenderedMarkdown(this.documentPath);
+ this.title = title;
+ this.body = body;
+ this.loading = false;
+ this.hasFetchError = hasFetchError;
+ if (this.open) {
+ this.renderGLFM();
+ }
+ cache[this.documentPath] = { title, body };
+ }
+ },
+ renderGLFM() {
+ this.$nextTick(() => {
+ $(this.$refs['content-element']).renderGFM();
+ });
+ },
+ closeDrawer() {
+ this.open = false;
+ },
+ toggleDrawer() {
+ this.open = !this.open;
+ },
+ openDrawer() {
+ this.open = true;
+ },
+ },
+ safeHtmlConfig: {
+ ADD_TAGS: ['copy-code'],
+ },
+};
+</script>
+<template>
+ <gl-drawer :header-height="drawerOffsetTop" :open="open" header-sticky @close="closeDrawer">
+ <template #title>
+ <h4 data-testid="title-element" class="gl-m-0">{{ title }}</h4>
+ </template>
+ <template #default>
+ <div v-if="hasFetchError">
+ <gl-alert :dismissible="false" variant="danger">{{ $options.i18n.alert }}</gl-alert>
+ </div>
+ <gl-skeleton-loader v-else-if="loading" />
+ <div
+ v-else
+ ref="content-element"
+ v-safe-html:[$options.safeHtmlConfig]="body"
+ class="md"
+ ></div>
+ </template>
+ </gl-drawer>
+</template>
diff --git a/app/assets/javascripts/vue_shared/components/markdown_drawer/utils/fetch.js b/app/assets/javascripts/vue_shared/components/markdown_drawer/utils/fetch.js
new file mode 100644
index 00000000000..7c8e1bc160a
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/markdown_drawer/utils/fetch.js
@@ -0,0 +1,32 @@
+import * as Sentry from '@sentry/browser';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import axios from '~/lib/utils/axios_utils';
+
+export const splitDocument = (htmlString) => {
+ const htmlDocument = new DOMParser().parseFromString(htmlString, 'text/html');
+ const title = htmlDocument.querySelector('h1')?.innerText;
+ htmlDocument.querySelector('h1')?.remove();
+ return {
+ title,
+ body: htmlDocument.querySelector('body').innerHTML.toString(),
+ };
+};
+
+export const getRenderedMarkdown = (documentPath) => {
+ return axios
+ .get(helpPagePath(documentPath))
+ .then(({ data }) => {
+ const { body, title } = splitDocument(data.html);
+ return {
+ body,
+ title,
+ hasFetchError: false,
+ };
+ })
+ .catch((e) => {
+ Sentry.captureException(e);
+ return {
+ hasFetchError: true,
+ };
+ });
+};
diff --git a/app/assets/javascripts/vue_shared/components/namespace_select/namespace_select_deprecated.vue b/app/assets/javascripts/vue_shared/components/namespace_select/namespace_select_deprecated.vue
deleted file mode 100644
index ba9edc7620a..00000000000
--- a/app/assets/javascripts/vue_shared/components/namespace_select/namespace_select_deprecated.vue
+++ /dev/null
@@ -1,212 +0,0 @@
-<script>
-import {
- GlDropdown,
- GlDropdownDivider,
- GlDropdownItem,
- GlDropdownSectionHeader,
- GlSearchBoxByType,
- GlIntersectionObserver,
- GlLoadingIcon,
-} from '@gitlab/ui';
-import { __ } from '~/locale';
-
-export const EMPTY_NAMESPACE_ID = -1;
-export const i18n = {
- DEFAULT_TEXT: __('Select a new namespace'),
- DEFAULT_EMPTY_NAMESPACE_TEXT: __('No namespace'),
- GROUPS: __('Groups'),
- USERS: __('Users'),
-};
-
-const filterByName = (data, searchTerm = '') => {
- if (!searchTerm) {
- return data;
- }
-
- return data.filter((d) => d.humanName.toLowerCase().includes(searchTerm.toLowerCase()));
-};
-
-export default {
- name: 'NamespaceSelectDeprecated',
- components: {
- GlDropdown,
- GlDropdownDivider,
- GlDropdownItem,
- GlDropdownSectionHeader,
- GlSearchBoxByType,
- GlIntersectionObserver,
- GlLoadingIcon,
- },
- props: {
- groupNamespaces: {
- type: Array,
- required: false,
- default: () => [],
- },
- userNamespaces: {
- type: Array,
- required: false,
- default: () => [],
- },
- fullWidth: {
- type: Boolean,
- required: false,
- default: false,
- },
- defaultText: {
- type: String,
- required: false,
- default: i18n.DEFAULT_TEXT,
- },
- includeHeaders: {
- type: Boolean,
- required: false,
- default: true,
- },
- emptyNamespaceTitle: {
- type: String,
- required: false,
- default: i18n.DEFAULT_EMPTY_NAMESPACE_TEXT,
- },
- includeEmptyNamespace: {
- type: Boolean,
- required: false,
- default: false,
- },
- hasNextPageOfGroups: {
- type: Boolean,
- required: false,
- default: false,
- },
- isLoading: {
- type: Boolean,
- required: false,
- default: false,
- },
- isSearchLoading: {
- type: Boolean,
- required: false,
- default: false,
- },
- shouldFilterNamespaces: {
- type: Boolean,
- required: false,
- default: true,
- },
- },
- data() {
- return {
- searchTerm: '',
- selectedNamespace: null,
- };
- },
- computed: {
- hasUserNamespaces() {
- return this.userNamespaces.length;
- },
- hasGroupNamespaces() {
- return this.groupNamespaces.length;
- },
- filteredGroupNamespaces() {
- if (!this.shouldFilterNamespaces) return this.groupNamespaces;
- if (!this.hasGroupNamespaces) return [];
- return filterByName(this.groupNamespaces, this.searchTerm);
- },
- filteredUserNamespaces() {
- if (!this.shouldFilterNamespaces) return this.userNamespaces;
- if (!this.hasUserNamespaces) return [];
- return filterByName(this.userNamespaces, this.searchTerm);
- },
- selectedNamespaceText() {
- return this.selectedNamespace?.humanName || this.defaultText;
- },
- filteredEmptyNamespaceTitle() {
- const { includeEmptyNamespace, emptyNamespaceTitle, searchTerm } = this;
-
- if (!includeEmptyNamespace) {
- return '';
- }
- if (!searchTerm) {
- return emptyNamespaceTitle;
- }
-
- return emptyNamespaceTitle.toLowerCase().includes(searchTerm.toLowerCase());
- },
- },
- watch: {
- searchTerm() {
- this.$emit('search', this.searchTerm);
- },
- },
- methods: {
- handleSelect(item) {
- this.selectedNamespace = item;
- this.searchTerm = '';
- this.$emit('select', item);
- },
- handleSelectEmptyNamespace() {
- this.handleSelect({ id: EMPTY_NAMESPACE_ID, humanName: this.emptyNamespaceTitle });
- },
- },
- i18n,
-};
-</script>
-<template>
- <gl-dropdown
- :text="selectedNamespaceText"
- :block="fullWidth"
- data-qa-selector="namespaces_list"
- @show="$emit('show')"
- >
- <template #header>
- <gl-search-box-by-type
- v-model.trim="searchTerm"
- :is-loading="isSearchLoading"
- data-qa-selector="namespaces_list_search"
- />
- </template>
- <div v-if="filteredEmptyNamespaceTitle">
- <gl-dropdown-item
- data-qa-selector="namespaces_list_item"
- @click="handleSelectEmptyNamespace()"
- >
- {{ emptyNamespaceTitle }}
- </gl-dropdown-item>
- <gl-dropdown-divider />
- </div>
- <div
- v-if="hasUserNamespaces"
- data-qa-selector="namespaces_list_users"
- data-testid="namespace-list-users"
- >
- <gl-dropdown-section-header v-if="includeHeaders">{{
- $options.i18n.USERS
- }}</gl-dropdown-section-header>
- <gl-dropdown-item
- v-for="item in filteredUserNamespaces"
- :key="item.id"
- data-qa-selector="namespaces_list_item"
- @click="handleSelect(item)"
- >{{ item.humanName }}</gl-dropdown-item
- >
- </div>
- <div
- v-if="hasGroupNamespaces"
- data-qa-selector="namespaces_list_groups"
- data-testid="namespace-list-groups"
- >
- <gl-dropdown-section-header v-if="includeHeaders">{{
- $options.i18n.GROUPS
- }}</gl-dropdown-section-header>
- <gl-dropdown-item
- v-for="item in filteredGroupNamespaces"
- :key="item.id"
- data-qa-selector="namespaces_list_item"
- @click="handleSelect(item)"
- >{{ item.humanName }}</gl-dropdown-item
- >
- </div>
- <gl-loading-icon v-if="isLoading" class="gl-mb-3" size="sm" />
- <gl-intersection-observer v-if="hasNextPageOfGroups" @appear="$emit('load-more-groups')" />
- </gl-dropdown>
-</template>
diff --git a/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue
index a5027d2ca5c..867222279b2 100644
--- a/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue
+++ b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue
@@ -9,9 +9,12 @@ import {
} from '@gitlab/ui';
import Api from '~/api';
import { updateHistory, setUrlParams } from '~/lib/utils/url_utility';
-import { __ } from '~/locale';
import Tracking from '~/tracking';
-import { OPERATOR_IS_ONLY } from '~/vue_shared/components/filtered_search_bar/constants';
+import {
+ OPERATOR_IS_ONLY,
+ TOKEN_TITLE_ASSIGNEE,
+ TOKEN_TITLE_AUTHOR,
+} from '~/vue_shared/components/filtered_search_bar/constants';
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
import { initialPaginationState, defaultI18n, defaultPageSize } from './constants';
@@ -112,7 +115,7 @@ export default {
{
type: 'author_username',
icon: 'user',
- title: __('Author'),
+ title: TOKEN_TITLE_AUTHOR,
unique: true,
symbol: '@',
token: AuthorToken,
@@ -123,7 +126,7 @@ export default {
{
type: 'assignee_username',
icon: 'user',
- title: __('Assignee'),
+ title: TOKEN_TITLE_ASSIGNEE,
unique: true,
symbol: '@',
token: AuthorToken,
diff --git a/app/assets/javascripts/vue_shared/components/pagination_bar/pagination_bar.stories.js b/app/assets/javascripts/vue_shared/components/pagination_bar/pagination_bar.stories.js
index f16afc77164..fd9d69bae22 100644
--- a/app/assets/javascripts/vue_shared/components/pagination_bar/pagination_bar.stories.js
+++ b/app/assets/javascripts/vue_shared/components/pagination_bar/pagination_bar.stories.js
@@ -1,4 +1,3 @@
-/* eslint-disable @gitlab/require-i18n-strings */
import PaginationBar from './pagination_bar.vue';
export default {
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/epics_select/epics_select_bundle.js b/app/assets/javascripts/vue_shared/components/sidebar/epics_select/epics_select_bundle.js
deleted file mode 100644
index 1c08433ee78..00000000000
--- a/app/assets/javascripts/vue_shared/components/sidebar/epics_select/epics_select_bundle.js
+++ /dev/null
@@ -1 +0,0 @@
-// This empty file satisfies the import/no-unresolved rule for ee_else_ce imports.
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/health_status_select/health_status_bundle.js b/app/assets/javascripts/vue_shared/components/sidebar/health_status_select/health_status_bundle.js
deleted file mode 100644
index 1c08433ee78..00000000000
--- a/app/assets/javascripts/vue_shared/components/sidebar/health_status_select/health_status_bundle.js
+++ /dev/null
@@ -1 +0,0 @@
-// This empty file satisfies the import/no-unresolved rule for ee_else_ce imports.
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/issuable_move_dropdown.vue b/app/assets/javascripts/vue_shared/components/sidebar/issuable_move_dropdown.vue
index 0f5560ff628..02323e5a0c6 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/issuable_move_dropdown.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/issuable_move_dropdown.vue
@@ -43,6 +43,11 @@ export default {
required: false,
default: false,
},
+ disabled: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -128,7 +133,7 @@ export default {
</script>
<template>
- <div class="block js-issuable-move-block issuable-move-dropdown sidebar-move-issue-dropdown">
+ <div class="js-issuable-move-block issuable-move-dropdown sidebar-move-issue-dropdown">
<div
v-gl-tooltip.left.viewport
data-testid="move-collapsed"
@@ -141,7 +146,7 @@ export default {
<gl-dropdown
ref="dropdown"
:block="true"
- :disabled="moveInProgress"
+ :disabled="moveInProgress || disabled"
class="hide-collapsed"
toggle-class="js-sidebar-dropdown-toggle"
@shown="fetchProjects"
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/iterations_dropdown_bundle.js b/app/assets/javascripts/vue_shared/components/sidebar/iterations_dropdown_bundle.js
deleted file mode 100644
index 1c08433ee78..00000000000
--- a/app/assets/javascripts/vue_shared/components/sidebar/iterations_dropdown_bundle.js
+++ /dev/null
@@ -1 +0,0 @@
-// This empty file satisfies the import/no-unresolved rule for ee_else_ce imports.
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue
index 0127df730b8..27186281c42 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue
@@ -194,6 +194,7 @@ export default {
ref="dropdown"
:text="buttonText"
class="gl-w-full"
+ block
data-testid="labels-select-dropdown-contents"
data-qa-selector="labels_dropdown_content"
@hide="handleDropdownHide"
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/label_item.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/label_item.vue
index caeee2df7e5..314ffbaf84c 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/label_item.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/label_item.vue
@@ -10,7 +10,7 @@ export default {
</script>
<template>
- <div class="gl-display-flex gl-align-items-center">
+ <div class="gl-display-flex gl-align-items-center gl-word-break-word">
<span
class="dropdown-label-box gl-flex-shrink-0 gl-top-0 gl-mr-3"
:style="{ 'background-color': label.color }"
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue
index 0e8da7281d8..2c27a69d587 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue
@@ -129,9 +129,6 @@ export default {
issuableId() {
return this.issuable?.id;
},
- isRealtimeEnabled() {
- return this.glFeatures.realtimeLabels;
- },
},
apollo: {
issuable: {
@@ -163,7 +160,7 @@ export default {
};
},
skip() {
- return !this.issuableId || !this.isDropdownVariantSidebar || !this.isRealtimeEnabled;
+ return !this.issuableId || !this.isDropdownVariantSidebar;
},
updateQuery(
_,
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/queries/merge_request_reviewers.subscription.graphql b/app/assets/javascripts/vue_shared/components/sidebar/queries/merge_request_reviewers.subscription.graphql
new file mode 100644
index 00000000000..a1b16b378b3
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/sidebar/queries/merge_request_reviewers.subscription.graphql
@@ -0,0 +1,22 @@
+#import "~/graphql_shared/fragments/user.fragment.graphql"
+#import "~/graphql_shared/fragments/user_availability.fragment.graphql"
+
+subscription mergeRequestReviewersUpdated($issuableId: IssuableID!) {
+ mergeRequestReviewersUpdated(issuableId: $issuableId) {
+ ... on MergeRequest {
+ id
+ reviewers {
+ nodes {
+ ...User
+ ...UserAvailability
+ mergeRequestInteraction {
+ canMerge
+ canUpdate
+ approved
+ reviewed
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/todo_toggle/todo_button.stories.js b/app/assets/javascripts/vue_shared/components/sidebar/todo_toggle/todo_button.stories.js
index 8a2bab4cb9a..465ee9aa0d4 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/todo_toggle/todo_button.stories.js
+++ b/app/assets/javascripts/vue_shared/components/sidebar/todo_toggle/todo_button.stories.js
@@ -1,5 +1,3 @@
-/* eslint-disable @gitlab/require-i18n-strings */
-
import TodoButton from './todo_button.vue';
export default {
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue
index 9683288f937..a2d8b7cbd15 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue
@@ -1,5 +1,6 @@
<script>
import { GlIntersectionObserver, GlSafeHtmlDirective } from '@gitlab/ui';
+import { scrollToElement } from '~/lib/utils/common_utils';
import ChunkLine from './chunk_line.vue';
/*
@@ -23,6 +24,11 @@ export default {
SafeHtml: GlSafeHtmlDirective,
},
props: {
+ isFirstChunk: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
chunkIndex: {
type: Number,
required: false,
@@ -46,6 +52,11 @@ export default {
required: false,
default: 0,
},
+ totalChunks: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
language: {
type: String,
required: false,
@@ -56,53 +67,68 @@ export default {
required: true,
},
},
+ data() {
+ return {
+ isLoading: true,
+ };
+ },
computed: {
lines() {
return this.content.split('\n');
},
},
+
+ created() {
+ if (this.isFirstChunk) {
+ this.isLoading = false;
+ return;
+ }
+
+ window.requestIdleCallback(() => {
+ this.isLoading = false;
+ const { hash } = this.$route;
+ if (hash && this.totalChunks > 0 && this.totalChunks === this.chunkIndex + 1) {
+ // when the last chunk is loaded scroll to the hash
+ scrollToElement(hash, { behavior: 'auto' });
+ }
+ });
+ },
methods: {
handleChunkAppear() {
if (!this.isHighlighted) {
this.$emit('appear', this.chunkIndex);
}
},
+ calculateLineNumber(index) {
+ return this.startingFrom + index + 1;
+ },
},
};
</script>
<template>
- <div>
- <gl-intersection-observer @appear="handleChunkAppear">
- <div v-if="isHighlighted">
- <chunk-line
- v-for="(line, index) in lines"
+ <gl-intersection-observer @appear="handleChunkAppear">
+ <div v-if="isHighlighted">
+ <chunk-line
+ v-for="(line, index) in lines"
+ :key="index"
+ :number="calculateLineNumber(index)"
+ :content="line"
+ :language="language"
+ :blame-path="blamePath"
+ />
+ </div>
+ <div v-else-if="!isLoading" class="gl-display-flex gl-text-transparent">
+ <div class="gl-display-flex gl-flex-direction-column content-visibility-auto">
+ <span
+ v-for="(n, index) in totalLines"
+ v-once
+ :id="`L${calculateLineNumber(index)}`"
:key="index"
- :number="startingFrom + index + 1"
- :content="line"
- :language="language"
- :blame-path="blamePath"
- />
- </div>
- <div v-else class="gl-display-flex">
- <div class="gl-display-flex gl-flex-direction-column">
- <a
- v-for="(n, index) in totalLines"
- :id="`L${startingFrom + index + 1}`"
- :key="index"
- class="gl-ml-5 gl-text-transparent"
- :href="`#L${startingFrom + index + 1}`"
- :data-line-number="startingFrom + index + 1"
- data-testid="line-number"
- >
- {{ startingFrom + index + 1 }}
- </a>
- </div>
- <div
- class="gl-white-space-pre-wrap! gl-text-transparent"
- data-testid="content"
- v-text="content"
- ></div>
+ data-testid="line-number"
+ v-text="calculateLineNumber(index)"
+ ></span>
</div>
- </gl-intersection-observer>
- </div>
+ <div v-once class="gl-white-space-pre-wrap!" data-testid="content">{{ content }}</div>
+ </div>
+ </gl-intersection-observer>
</template>
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue
index ffd0eea63a1..0bf19f83d86 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/components/chunk_line.vue
@@ -1,6 +1,7 @@
<script>
import { GlSafeHtmlDirective } from '@gitlab/ui';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { getPageParamValue, getPageSearchString } from '~/blob/utils';
export default {
directives: {
@@ -25,6 +26,13 @@ export default {
required: true,
},
},
+ computed: {
+ pageSearchString() {
+ if (!this.glFeatures.fileLineBlame) return '';
+ const page = getPageParamValue(this.number);
+ return getPageSearchString(this.blamePath, page);
+ },
+ },
};
</script>
<template>
@@ -35,7 +43,7 @@ export default {
<a
v-if="glFeatures.fileLineBlame"
class="gl-user-select-none gl-shadow-none! file-line-blame"
- :href="`${blamePath}#L${number}`"
+ :href="`${blamePath}${pageSearchString}#L${number}`"
></a>
<a
:id="`L${number}`"
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/link_dependencies.js b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/link_dependencies.js
index d957990fe7f..fca2616f069 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/link_dependencies.js
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/link_dependencies.js
@@ -1,9 +1,17 @@
import packageJsonLinker from './utils/package_json_linker';
import gemspecLinker from './utils/gemspec_linker';
+import godepsJsonLinker from './utils/godeps_json_linker';
+import gemfileLinker from './utils/gemfile_linker';
+import podspecJsonLinker from './utils/podspec_json_linker';
+import composerJsonLinker from './utils/composer_json_linker';
const DEPENDENCY_LINKERS = {
package_json: packageJsonLinker,
gemspec: gemspecLinker,
+ godeps_json: godepsJsonLinker,
+ gemfile: gemfileLinker,
+ podspec_json: podspecJsonLinker,
+ composer_json: composerJsonLinker,
};
/**
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/composer_json_linker.js b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/composer_json_linker.js
new file mode 100644
index 00000000000..f5c4c886546
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/composer_json_linker.js
@@ -0,0 +1,49 @@
+import { createLink, generateHLJSOpenTag } from './dependency_linker_util';
+
+const PACKAGIST_URL = 'https://packagist.org/packages/';
+const DRUPAL_URL = 'https://www.drupal.org/project/';
+
+const attrOpenTag = generateHLJSOpenTag('attr');
+const stringOpenTag = generateHLJSOpenTag('string');
+const closeTag = '&quot;</span>';
+const DRUPAL_PROJECT_SEPARATOR = 'drupal/';
+const DEPENDENCY_REGEX = new RegExp(
+ /*
+ * Detects dependencies inside of content that is highlighted by Highlight.js
+ * Example: <span class="hljs-attr">&quot;composer/installers&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;^1.2&quot;</span>
+ * Group 1: composer/installers
+ * Group 2: ^1.2
+ */
+ `${attrOpenTag}([^/]+/[^/]+.)${closeTag}.*${stringOpenTag}(.*[0-9].*)(${closeTag})`,
+ 'gm',
+);
+
+const handleReplace = (original, packageName, version, dependenciesToLink) => {
+ const isDrupalDependency = packageName.includes(DRUPAL_PROJECT_SEPARATOR);
+ const href = isDrupalDependency
+ ? `${DRUPAL_URL}${packageName.split(DRUPAL_PROJECT_SEPARATOR)[1]}`
+ : `${PACKAGIST_URL}${packageName}`;
+ const packageLink = createLink(href, packageName);
+ const versionLink = createLink(href, version);
+ const closeAndOpenTag = `${closeTag}: ${attrOpenTag}`;
+ const dependencyToLink = dependenciesToLink[packageName];
+
+ if (dependencyToLink && dependencyToLink === version) {
+ return `${attrOpenTag}${packageLink}${closeAndOpenTag}${versionLink}${closeTag}`;
+ }
+
+ return original;
+};
+
+export default (result, raw) => {
+ const rawParsed = JSON.parse(raw);
+
+ const dependenciesToLink = {
+ ...rawParsed.require,
+ ...rawParsed['require-dev'],
+ };
+
+ return result.value.replace(DEPENDENCY_REGEX, (original, packageName, version) =>
+ handleReplace(original, packageName, version, dependenciesToLink),
+ );
+};
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/dependency_linker_util.js b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/dependency_linker_util.js
index 49704421d6e..c1a1101afad 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/dependency_linker_util.js
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/dependency_linker_util.js
@@ -1,7 +1,27 @@
import { escape } from 'lodash';
export const createLink = (href, innerText) =>
- `<a href="${escape(href)}" rel="nofollow noreferrer noopener">${escape(innerText)}</a>`;
+ `<a href="${escape(href)}" target="_blank" rel="nofollow noreferrer noopener">${escape(
+ innerText,
+ )}</a>`;
export const generateHLJSOpenTag = (type, delimiter = '&quot;') =>
`<span class="hljs-${escape(type)}">${delimiter}`;
+
+export const getObjectKeysByKeyName = (obj, keyName, acc) => {
+ if (obj instanceof Array) {
+ obj.map((subObj) => getObjectKeysByKeyName(subObj, keyName, acc));
+ } else {
+ for (const key in obj) {
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
+ if (key === keyName) {
+ acc.push(...Object.keys(obj[key]));
+ }
+ if (obj[key] instanceof Object || obj[key] instanceof Array) {
+ getObjectKeysByKeyName(obj[key], keyName, acc);
+ }
+ }
+ }
+ }
+ return acc;
+};
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/gemfile_linker.js b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/gemfile_linker.js
new file mode 100644
index 00000000000..81389763f49
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/gemfile_linker.js
@@ -0,0 +1,25 @@
+import { createLink, generateHLJSOpenTag } from './dependency_linker_util';
+
+const GEM_URL = 'https://rubygems.org/gems/';
+const GEM_STRING = 'gem </span>';
+const delimiter = '&#39;';
+const stringOpenTag = generateHLJSOpenTag('string', delimiter);
+
+const DEPENDENCY_REGEX = new RegExp(
+ /*
+ * Detects dependencies inside of content that is highlighted by Highlight.js
+ * Example: 'gem </span><span class="hljs-string">&#39;paranoia&#39;'
+ * Group 1 (packageName) : 'paranoia'
+ */
+ `${GEM_STRING}${stringOpenTag}(.+?(?=${delimiter}))`,
+ 'gm',
+);
+
+const handleReplace = (packageName) => {
+ const href = `${GEM_URL}${packageName}`;
+ const packageLink = createLink(href, packageName);
+ return `${GEM_STRING}${stringOpenTag}${packageLink}`;
+};
+export default (result) => {
+ return result.value.replace(DEPENDENCY_REGEX, (_, packageName) => handleReplace(packageName));
+};
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/godeps_json_linker.js b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/godeps_json_linker.js
new file mode 100644
index 00000000000..bff8e3cf410
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/godeps_json_linker.js
@@ -0,0 +1,64 @@
+import { createLink, generateHLJSOpenTag } from './dependency_linker_util';
+
+const PROTOCOL = 'https://';
+const GODOCS_DOMAIN = 'godoc.org/';
+const REPO_PATH = '/tree/master/';
+const GODOCS_REGEX = /golang.org/;
+const GITLAB_REPO_PATH = `/_${REPO_PATH}`;
+const REPO_REGEX = `[^/'"]+/[^/'"]+`;
+const NESTED_REPO_REGEX = '([^/]+/)+[^/]+?';
+const GITHUB_REPO_REGEX = new RegExp(`(github.com/${REPO_REGEX})/(.+)`);
+const GITLAB_REPO_REGEX = new RegExp(`(gitlab.com/${REPO_REGEX})/(.+)`);
+const GITLAB_NESTED_REPO_REGEX = new RegExp(`(gitlab.com/${NESTED_REPO_REGEX}).git/(.+)`);
+const attrOpenTag = generateHLJSOpenTag('attr');
+const stringOpenTag = generateHLJSOpenTag('string');
+const closeTag = '&quot;</span>';
+const importPathString =
+ 'ImportPath&quot;</span><span class="hljs-punctuation">:</span><span class=""> </span>';
+
+const DEPENDENCY_REGEX = new RegExp(
+ /*
+ * Detects dependencies inside of content that is highlighted by Highlight.js
+ * Example: <span class="hljs-attr">&quot;ImportPath&quot;</span><span class="hljs-punctuation">:</span><span class=""> </span><span class="hljs-string">&quot;github.com/ayufan/golang-kardianos-service&quot;</span>
+ * Group 1: github.com/ayufan/golang-kardianos-service
+ */
+ `${importPathString}${stringOpenTag}(.*)${closeTag}`,
+ 'gm',
+);
+
+const replaceRepoPath = (dependency, regex, repoPath) =>
+ dependency.replace(regex, (_, repo, path) => `${PROTOCOL}${repo}${repoPath}${path}`);
+
+const regexConfigs = [
+ {
+ matcher: GITHUB_REPO_REGEX,
+ resolver: (dep) => replaceRepoPath(dep, GITHUB_REPO_REGEX, REPO_PATH),
+ },
+ {
+ matcher: GITLAB_REPO_REGEX,
+ resolver: (dep) => replaceRepoPath(dep, GITLAB_REPO_REGEX, GITLAB_REPO_PATH),
+ },
+ {
+ matcher: GITLAB_NESTED_REPO_REGEX,
+ resolver: (dep) => replaceRepoPath(dep, GITLAB_NESTED_REPO_REGEX, GITLAB_REPO_PATH),
+ },
+ {
+ matcher: GODOCS_REGEX,
+ resolver: (dep) => `${PROTOCOL}${GODOCS_DOMAIN}${dep}`,
+ },
+];
+
+const getLinkHref = (dependency) => {
+ const regexConfig = regexConfigs.find((config) => dependency.match(config.matcher));
+ return regexConfig ? regexConfig.resolver(dependency) : `${PROTOCOL}${dependency}`;
+};
+
+const handleReplace = (dependency) => {
+ const linkHref = getLinkHref(dependency);
+ const link = createLink(linkHref, dependency);
+ return `${importPathString}${attrOpenTag}${link}${closeTag}`;
+};
+
+export default (result) => {
+ return result.value.replace(DEPENDENCY_REGEX, (_, dependency) => handleReplace(dependency));
+};
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker.js b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker.js
new file mode 100644
index 00000000000..e2007fe408b
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker.js
@@ -0,0 +1,32 @@
+import { createLink, generateHLJSOpenTag, getObjectKeysByKeyName } from './dependency_linker_util';
+
+const COCOAPODS_URL = 'https://cocoapods.org/pods/';
+const beginString = generateHLJSOpenTag('attr');
+const endString =
+ '&quot;</span><span class="hljs-punctuation">:</span><span class=""> </span><span class="hljs-punctuation">\\[';
+
+const DEPENDENCY_REGEX = new RegExp(
+ /*
+ * Detects dependencies inside of content that is highlighted by Highlight.js
+ * Example: <span class="hljs-attr">&quot;AFNetworking/Security&quot;</span><span class="hljs-punctuation">:</span><span class=""> </span><span class="hljs-punctuation"> [
+ * Group 1: AFNetworking/Serialization
+ */
+ `${beginString}([^/]+/?[^/]+.)${endString}`,
+ 'gm',
+);
+
+const handleReplace = (original, dependency, dependenciesToLink) => {
+ if (dependenciesToLink.includes(dependency)) {
+ const href = `${COCOAPODS_URL}${dependency.split('/')[0]}`;
+ const link = createLink(href, dependency);
+ return `${beginString}${link}${endString.replace('\\', '')}`;
+ }
+ return original;
+};
+
+export default (result, raw) => {
+ const dependenciesToLink = getObjectKeysByKeyName(JSON.parse(raw), 'dependencies', []);
+ return result.value.replace(DEPENDENCY_REGEX, (original, dependency) =>
+ handleReplace(original, dependency, dependenciesToLink),
+ );
+};
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/wrap_child_nodes.js b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/wrap_child_nodes.js
index e0ba4b730a7..3540ac6caf1 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/plugins/wrap_child_nodes.js
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/plugins/wrap_child_nodes.js
@@ -22,7 +22,7 @@ const format = (node, kind = '') => {
.split(newlineRegex)
.map((newline) => generateHLJSTag(kind, newline, true))
.join('\n');
- } else if (node.kind) {
+ } else if (node.kind || node.sublanguage) {
const { children } = node;
if (children.length && children.length === 1) {
buffer += format(children[0], node.kind);
diff --git a/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue b/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue
index 536b2c8a281..f621a23734a 100644
--- a/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue
+++ b/app/assets/javascripts/vue_shared/components/source_viewer/source_viewer.vue
@@ -65,6 +65,9 @@ export default {
!supportedLanguages.includes(this.blob.language?.toLowerCase())
);
},
+ totalChunks() {
+ return Object.keys(this.chunks).length;
+ },
},
async created() {
addBlobLinksTracking();
@@ -200,6 +203,7 @@ export default {
:content="firstChunk.content"
:starting-from="firstChunk.startingFrom"
:is-highlighted="firstChunk.isHighlighted"
+ is-first-chunk
:language="firstChunk.language"
:blame-path="blob.blamePath"
/>
@@ -217,6 +221,7 @@ export default {
:chunk-index="index"
:language="chunk.language"
:blame-path="blob.blamePath"
+ :total-chunks="totalChunks"
@appear="highlightChunk"
/>
</div>
diff --git a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.stories.js b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.stories.js
index e621442e601..84615386fe2 100644
--- a/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.stories.js
+++ b/app/assets/javascripts/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.stories.js
@@ -1,4 +1,3 @@
-/* eslint-disable @gitlab/require-i18n-strings */
import TooltipOnTruncate from './tooltip_on_truncate.vue';
const defaultWidth = '250px';
diff --git a/app/assets/javascripts/vue_shared/components/user_deletion_obstacles/user_deletion_obstacles_list.stories.js b/app/assets/javascripts/vue_shared/components/user_deletion_obstacles/user_deletion_obstacles_list.stories.js
index 1f0f4cde234..0815fdd9aac 100644
--- a/app/assets/javascripts/vue_shared/components/user_deletion_obstacles/user_deletion_obstacles_list.stories.js
+++ b/app/assets/javascripts/vue_shared/components/user_deletion_obstacles/user_deletion_obstacles_list.stories.js
@@ -1,5 +1,3 @@
-/* eslint-disable @gitlab/require-i18n-strings */
-
import { OBSTACLE_TYPES } from './constants';
import UserDeletionObstaclesList from './user_deletion_obstacles_list.vue';
diff --git a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue
index 7e735f358eb..30b7b073ac3 100644
--- a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue
+++ b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue
@@ -3,7 +3,7 @@ import { GlLink, GlIcon, GlLabel, GlFormCheckbox, GlSprintf, GlTooltipDirective
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { isScopedLabel } from '~/lib/utils/common_utils';
-import { differenceInSeconds, getTimeago, SECONDS_IN_DAY } from '~/lib/utils/datetime_utility';
+import { getTimeago } from '~/lib/utils/datetime_utility';
import { isExternal, setUrlFragment } from '~/lib/utils/url_utility';
import { __, n__, sprintf } from '~/locale';
import IssuableAssignees from '~/issuable/components/issue_assignees.vue';
@@ -62,9 +62,8 @@ export default {
issuableId() {
return getIdFromGraphQLId(this.issuable.id);
},
- createdInPastDay() {
- const createdSecondsAgo = differenceInSeconds(new Date(this.issuable.createdAt), new Date());
- return createdSecondsAgo < SECONDS_IN_DAY;
+ issuableIid() {
+ return this.issuable.iid;
},
author() {
return this.issuable.author || {};
@@ -184,7 +183,7 @@ export default {
<li
:id="`issuable_${issuableId}`"
class="issue gl-display-flex! gl-px-5!"
- :class="{ closed: issuable.closedAt, today: createdInPastDay }"
+ :class="{ closed: issuable.closedAt }"
:data-labels="labelIdsString"
:data-qa-issue-id="issuableId"
>
@@ -193,6 +192,8 @@ export default {
class="issue-check gl-mr-0"
:checked="checked"
:data-id="issuableId"
+ :data-iid="issuableIid"
+ :data-type="issuable.type"
@input="$emit('checked-input', $event)"
>
<span class="gl-sr-only">{{ issuable.title }}</span>
diff --git a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue
index bc10f84b819..dd3d7c8f4d6 100644
--- a/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue
+++ b/app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue
@@ -7,6 +7,7 @@ import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { updateHistory, setUrlParams } from '~/lib/utils/url_utility';
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
+import issuableEventHub from '~/issues/list/eventhub';
import { DEFAULT_SKELETON_COUNT, PAGE_SIZE_STORAGE_KEY } from '../constants';
import IssuableBulkEditSidebar from './issuable_bulk_edit_sidebar.vue';
import IssuableItem from './issuable_item.vue';
@@ -177,6 +178,11 @@ export default {
required: false,
default: false,
},
+ showFilteredSearchFriendlyText: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
showPageSizeChangeControls: {
type: Boolean,
required: false,
@@ -266,6 +272,7 @@ export default {
handleIssuableCheckedInput(issuable, value) {
this.checkedIssuables[this.issuableId(issuable)].checked = value;
this.$emit('update-legacy-bulk-edit');
+ issuableEventHub.$emit('issuables:issuableChecked', issuable, value);
},
handleAllIssuablesCheckedInput(value) {
Object.keys(this.checkedIssuables).forEach((issuableId) => {
@@ -308,6 +315,7 @@ export default {
:sync-filter-and-sort="syncFilterAndSort"
:show-checkbox="showBulkEditSidebar"
:checkbox-checked="allIssuablesChecked"
+ :show-friendly-text="showFilteredSearchFriendlyText"
class="gl-flex-grow-1 gl-border-t-none row-content-block"
data-qa-selector="issuable_search_container"
@checked-input="handleAllIssuablesCheckedInput"
diff --git a/app/assets/javascripts/vue_shared/security_reports/store/utils.js b/app/assets/javascripts/vue_shared/security_reports/store/utils.js
index 6a4f671abb9..a6628fa0f9f 100644
--- a/app/assets/javascripts/vue_shared/security_reports/store/utils.js
+++ b/app/assets/javascripts/vue_shared/security_reports/store/utils.js
@@ -90,7 +90,7 @@ const createStatusMessage = ({ reportType, status, total }) => {
if (status) {
message = __('%{reportType} %{status}');
} else if (!total) {
- message = __('%{reportType} detected no %{totalStart}new%{totalEnd} vulnerabilities.');
+ message = __('%{reportType} detected no new vulnerabilities.');
} else {
message = __(
'%{reportType} detected %{totalStart}%{total}%{totalEnd} potential %{vulnMessage}',
diff --git a/app/assets/javascripts/webhooks/components/form_url_app.vue b/app/assets/javascripts/webhooks/components/form_url_app.vue
index 5ec16d4ba15..4fafeff8804 100644
--- a/app/assets/javascripts/webhooks/components/form_url_app.vue
+++ b/app/assets/javascripts/webhooks/components/form_url_app.vue
@@ -1,7 +1,8 @@
<script>
-import { isEmpty } from 'lodash';
+import { cloneDeep, isEmpty } from 'lodash';
import { GlFormGroup, GlFormInput, GlFormRadio, GlFormRadioGroup, GlLink } from '@gitlab/ui';
import { __, s__ } from '~/locale';
+import { scrollToElement } from '~/lib/utils/common_utils';
import FormUrlMaskItem from './form_url_mask_item.vue';
@@ -30,10 +31,15 @@ export default {
return {
maskEnabled: !isEmpty(this.initialUrlVariables),
url: this.initialUrl,
- items: isEmpty(this.initialUrlVariables) ? [{}] : this.initialUrlVariables,
+ items: this.getInitialItems(),
+ isValidated: false,
+ formEl: null,
};
},
computed: {
+ urlState() {
+ return !this.isValidated || !isEmpty(this.url);
+ },
maskedUrl() {
if (!this.url) {
return null;
@@ -46,14 +52,83 @@ export default {
return;
}
- const replacementExpression = new RegExp(value, 'g');
- maskedUrl = maskedUrl.replace(replacementExpression, `{${key}}`);
+ maskedUrl = this.maskUrl(maskedUrl, key, value);
});
return maskedUrl;
},
},
+ mounted() {
+ this.formEl = document.querySelector('.js-webhook-form');
+
+ this.formEl?.addEventListener('submit', this.handleSubmit);
+ },
+ destroy() {
+ this.formEl?.removeEventListener('submit', this.handleSubmit);
+ },
methods: {
+ getInitialItems() {
+ return isEmpty(this.initialUrlVariables) ? [{}] : cloneDeep(this.initialUrlVariables);
+ },
+ isEditingItem(index, key) {
+ if (isEmpty(this.initialUrlVariables)) {
+ return false;
+ }
+
+ const item = this.initialUrlVariables[index];
+ return item && item.key === key;
+ },
+ keyInvalidFeedback(key) {
+ if (this.isValidated && isEmpty(key)) {
+ return this.$options.i18n.inputRequired;
+ }
+
+ return null;
+ },
+ valueInvalidFeedback(index, key, value) {
+ if (this.isEditingItem(index, key)) {
+ return null;
+ }
+
+ if (this.isValidated && isEmpty(value)) {
+ return this.$options.i18n.inputRequired;
+ }
+
+ if (!isEmpty(value) && !this.url?.includes(value)) {
+ return this.$options.i18n.valuePartOfUrl;
+ }
+
+ return null;
+ },
+ isValid() {
+ this.isValidated = true;
+
+ if (!this.urlState) {
+ return false;
+ }
+
+ if (
+ this.maskEnabled &&
+ this.items.some(
+ ({ key, value }, index) =>
+ this.keyInvalidFeedback(key) || this.valueInvalidFeedback(index, key, value),
+ )
+ ) {
+ return false;
+ }
+
+ return true;
+ },
+ handleSubmit(e) {
+ if (!this.isValid()) {
+ scrollToElement(this.$refs.formUrl.$el);
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ },
+ maskUrl(url, key, value) {
+ return url.split(value).join(`{${key}}`);
+ },
onItemInput({ index, key, value }) {
this.$set(this.items, index, { key, value });
},
@@ -66,6 +141,7 @@ export default {
},
i18n: {
addItem: s__('Webhooks|+ Mask another portion of URL'),
+ inputRequired: __('This field is required.'),
radioFullUrlText: s__('Webhooks|Show full URL'),
radioMaskUrlText: s__('Webhooks|Mask portions of URL'),
radioMaskUrlHelp: s__('Webhooks|Do not show sensitive data such as tokens in the UI.'),
@@ -75,6 +151,7 @@ export default {
urlLabel: __('URL'),
urlPlaceholder: 'http://example.com/trigger-ci.json',
urlPreview: s__('Webhooks|URL preview'),
+ valuePartOfUrl: s__('Webhooks|Must match part of URL'),
},
};
</script>
@@ -82,14 +159,18 @@ export default {
<template>
<div>
<gl-form-group
+ ref="formUrl"
:label="$options.i18n.urlLabel"
label-for="webhook-url"
:description="$options.i18n.urlDescription"
+ :invalid-feedback="$options.i18n.inputRequired"
+ :state="urlState"
>
<gl-form-input
id="webhook-url"
v-model="url"
name="hook[url]"
+ :state="urlState"
:placeholder="$options.i18n.urlPlaceholder"
data-testid="form-url"
/>
@@ -112,6 +193,9 @@ export default {
:index="index"
:item-key="key"
:item-value="value"
+ :is-editing="isEditingItem(index, key)"
+ :key-invalid-feedback="keyInvalidFeedback(key)"
+ :value-invalid-feedback="valueInvalidFeedback(index, key, value)"
@input="onItemInput"
@remove="removeItem"
/>
diff --git a/app/assets/javascripts/webhooks/components/form_url_mask_item.vue b/app/assets/javascripts/webhooks/components/form_url_mask_item.vue
index 3b75f9b6c0d..f5f81759719 100644
--- a/app/assets/javascripts/webhooks/components/form_url_mask_item.vue
+++ b/app/assets/javascripts/webhooks/components/form_url_mask_item.vue
@@ -1,6 +1,8 @@
<script>
+import { isEmpty } from 'lodash';
import { GlButton, GlFormGroup, GlFormInput } from '@gitlab/ui';
import { s__ } from '~/locale';
+import { MASK_ITEM_VALUE_HIDDEN } from '../constants';
export default {
components: {
@@ -24,6 +26,21 @@ export default {
required: false,
default: null,
},
+ isEditing: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ keyInvalidFeedback: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ valueInvalidFeedback: {
+ type: String,
+ required: false,
+ default: null,
+ },
},
computed: {
keyInputId() {
@@ -32,6 +49,15 @@ export default {
valueInputId() {
return this.inputId('value');
},
+ keyState() {
+ return isEmpty(this.keyInvalidFeedback);
+ },
+ valueState() {
+ return isEmpty(this.valueInvalidFeedback);
+ },
+ displayValue() {
+ return this.isEditing ? MASK_ITEM_VALUE_HIDDEN : this.itemValue;
+ },
},
methods: {
inputId(type) {
@@ -58,23 +84,29 @@ export default {
</script>
<template>
- <div class="gl-display-flex gl-align-items-flex-end gl-gap-3 gl-mb-3">
+ <div class="gl-display-flex gl-align-items-flex-start gl-gap-3 gl-mb-3">
<gl-form-group
:label="$options.i18n.valueLabel"
:label-for="valueInputId"
+ :invalid-feedback="valueInvalidFeedback"
+ :state="valueState"
class="gl-flex-grow-1 gl-mb-0"
data-testid="mask-item-value"
>
<gl-form-input
:id="valueInputId"
:name="inputName('value')"
- :value="itemValue"
+ :value="displayValue"
+ :disabled="isEditing"
+ :state="valueState"
@input="onValueInput"
/>
</gl-form-group>
<gl-form-group
:label="$options.i18n.keyLabel"
:label-for="keyInputId"
+ :invalid-feedback="keyInvalidFeedback"
+ :state="keyState"
class="gl-flex-grow-1 gl-mb-0"
data-testid="mask-item-key"
>
@@ -82,9 +114,17 @@ export default {
:id="keyInputId"
:name="inputName('key')"
:value="itemKey"
+ :disabled="isEditing"
+ :state="keyState"
@input="onKeyInput"
/>
</gl-form-group>
- <gl-button icon="remove" :aria-label="__('Remove')" @click="onRemoveClick" />
+ <gl-button
+ icon="remove"
+ :aria-label="__('Remove')"
+ :disabled="isEditing"
+ class="gl-mt-6"
+ @click="onRemoveClick"
+ />
</div>
</template>
diff --git a/app/assets/javascripts/webhooks/components/push_events.vue b/app/assets/javascripts/webhooks/components/push_events.vue
new file mode 100644
index 00000000000..677f06314e0
--- /dev/null
+++ b/app/assets/javascripts/webhooks/components/push_events.vue
@@ -0,0 +1,112 @@
+<script>
+import { GlFormCheckbox, GlFormRadio, GlFormRadioGroup, GlFormInput, GlSprintf } from '@gitlab/ui';
+import {
+ BRANCH_FILTER_ALL_BRANCHES,
+ WILDCARD_CODE_STABLE,
+ WILDCARD_CODE_PRODUCTION,
+ REGEX_CODE,
+ descriptionText,
+} from '~/webhooks/constants';
+
+export default {
+ components: {
+ GlFormCheckbox,
+ GlFormRadio,
+ GlFormRadioGroup,
+ GlFormInput,
+ GlSprintf,
+ },
+ inject: ['pushEvents', 'strategy', 'isNewHook', 'pushEventsBranchFilter'],
+ data() {
+ return {
+ pushEventsData: !this.isNewHook && this.pushEvents,
+ branchFilterStrategyData: this.isNewHook ? BRANCH_FILTER_ALL_BRANCHES : this.strategy,
+ pushEventsBranchFilterData: this.pushEventsBranchFilter,
+ };
+ },
+ WILDCARD_CODE_STABLE,
+ WILDCARD_CODE_PRODUCTION,
+ REGEX_CODE,
+ descriptionText,
+};
+</script>
+
+<template>
+ <div>
+ <gl-form-checkbox v-model="pushEventsData">{{ s__('Webhooks|Push events') }}</gl-form-checkbox>
+ <input type="hidden" :value="pushEventsData" name="hook[push_events]" />
+
+ <div v-if="pushEventsData" class="gl-pl-6">
+ <gl-form-radio-group v-model="branchFilterStrategyData" name="hook[branch_filter_strategy]">
+ <gl-form-radio
+ class="gl-mt-2 branch-filter-strategy-radio"
+ value="all_branches"
+ data-testid="rule_all_branches"
+ >
+ <div data-qa-selector="strategy_radio_all">{{ __('All branches') }}</div>
+ </gl-form-radio>
+
+ <!-- wildcard -->
+ <gl-form-radio
+ class="gl-mt-2 branch-filter-strategy-radio"
+ value="wildcard"
+ data-testid="rule_wildcard"
+ >
+ <div data-qa-selector="strategy_radio_wildcard">
+ {{ s__('Webhooks|Wildcard pattern') }}
+ </div>
+ </gl-form-radio>
+ <div class="gl-ml-6">
+ <gl-form-input
+ v-if="branchFilterStrategyData === 'wildcard'"
+ v-model="pushEventsBranchFilterData"
+ name="hook[push_events_branch_filter]"
+ data-qa-selector="webhook_branch_filter_field"
+ data-testid="webhook_branch_filter_field"
+ />
+ </div>
+ <p
+ v-if="branchFilterStrategyData === 'wildcard'"
+ class="form-text text-muted custom-control"
+ >
+ <gl-sprintf :message="$options.descriptionText.wildcard">
+ <template #WILDCARD_CODE_STABLE>
+ <code>{{ $options.WILDCARD_CODE_STABLE }}</code>
+ </template>
+ <template #WILDCARD_CODE_PRODUCTION>
+ <code>{{ $options.WILDCARD_CODE_PRODUCTION }}</code>
+ </template>
+ </gl-sprintf>
+ </p>
+
+ <!-- regex -->
+ <gl-form-radio
+ class="gl-mt-2 branch-filter-strategy-radio"
+ value="regex"
+ data-testid="rule_regex"
+ >
+ <div data-qa-selector="strategy_radio_regex">
+ {{ s__('Webhooks|Regular expression') }}
+ </div>
+ </gl-form-radio>
+ <div class="gl-ml-6">
+ <gl-form-input
+ v-if="branchFilterStrategyData === 'regex'"
+ v-model="pushEventsBranchFilterData"
+ name="hook[push_events_branch_filter]"
+ data-qa-selector="webhook_branch_filter_field"
+ data-testid="webhook_branch_filter_field"
+ />
+ </div>
+
+ <p v-if="branchFilterStrategyData === 'regex'" class="form-text text-muted custom-control">
+ <gl-sprintf :message="$options.descriptionText.regex">
+ <template #REGEX_CODE>
+ <code>{{ $options.REGEX_CODE }}</code>
+ </template>
+ </gl-sprintf>
+ </p>
+ </gl-form-radio-group>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/webhooks/constants.js b/app/assets/javascripts/webhooks/constants.js
new file mode 100644
index 00000000000..6710a418117
--- /dev/null
+++ b/app/assets/javascripts/webhooks/constants.js
@@ -0,0 +1,19 @@
+import { s__ } from '~/locale';
+
+export const BRANCH_FILTER_ALL_BRANCHES = 'all_branches';
+export const BRANCH_FILTER_WILDCARD = 'wildcard';
+export const BRANCH_FILTER_REGEX = 'regex';
+
+export const WILDCARD_CODE_STABLE = '*-stable';
+export const WILDCARD_CODE_PRODUCTION = 'production/*';
+
+export const REGEX_CODE = '(feature|hotfix)/*';
+
+export const descriptionText = {
+ [BRANCH_FILTER_WILDCARD]: s__(
+ 'Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported.',
+ ),
+ [BRANCH_FILTER_REGEX]: s__('Webhooks|Regex such as %{REGEX_CODE} is supported.'),
+};
+
+export const MASK_ITEM_VALUE_HIDDEN = '************';
diff --git a/app/assets/javascripts/webhooks/index.js b/app/assets/javascripts/webhooks/index.js
index 1b2b33e44c1..7d04978280b 100644
--- a/app/assets/javascripts/webhooks/index.js
+++ b/app/assets/javascripts/webhooks/index.js
@@ -17,7 +17,7 @@ export default () => {
return createElement(FormUrlApp, {
props: {
initialUrl,
- initialUrlVariables: urlVariables ? JSON.parse(urlVariables) : undefined,
+ initialUrlVariables: JSON.parse(urlVariables),
},
});
},
diff --git a/app/assets/javascripts/webhooks/webhook.js b/app/assets/javascripts/webhooks/webhook.js
new file mode 100644
index 00000000000..ca631502745
--- /dev/null
+++ b/app/assets/javascripts/webhooks/webhook.js
@@ -0,0 +1,23 @@
+import Vue from 'vue';
+import { parseBoolean } from '~/lib/utils/common_utils';
+import pushEvents from './components/push_events.vue';
+
+export function initPushEventsEditForm() {
+ const el = document.querySelector('.js-vue-push-events');
+
+ if (!el) return false;
+
+ const provide = {
+ isNewHook: parseBoolean(el.dataset.isNewHook),
+ pushEvents: parseBoolean(el.dataset.pushEvents),
+ strategy: el.dataset.strategy,
+ pushEventsBranchFilter: el.dataset.pushEventsBranchFilter,
+ };
+ return new Vue({
+ el,
+ provide,
+ render(createElement) {
+ return createElement(pushEvents);
+ },
+ });
+}
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 57babe4569d..57930951856 100644
--- a/app/assets/javascripts/work_items/components/work_item_description.vue
+++ b/app/assets/javascripts/work_items/components/work_item_description.vue
@@ -1,5 +1,5 @@
<script>
-import { GlButton, GlFormGroup, GlSafeHtmlDirective } from '@gitlab/ui';
+import { GlButton, GlFormGroup } from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
import { helpPagePath } from '~/helpers/help_page_helper';
import { getDraft, clearDraft, updateDraft } from '~/lib/utils/autosave';
@@ -7,22 +7,25 @@ import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_m
import { __, s__ } from '~/locale';
import EditedAt from '~/issues/show/components/edited.vue';
import Tracking from '~/tracking';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
-import workItemQuery from '../graphql/work_item.query.graphql';
+import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
+import { getWorkItemQuery } from '../utils';
+import workItemDescriptionSubscription from '../graphql/work_item_description.subscription.graphql';
import updateWorkItemMutation from '../graphql/update_work_item.mutation.graphql';
import { i18n, TRACKING_CATEGORY_SHOW, WIDGET_TYPE_DESCRIPTION } from '../constants';
+import WorkItemDescriptionRendered from './work_item_description_rendered.vue';
export default {
- directives: {
- SafeHtml: GlSafeHtmlDirective,
- },
components: {
EditedAt,
GlButton,
GlFormGroup,
+ MarkdownEditor,
MarkdownField,
+ WorkItemDescriptionRendered,
},
- mixins: [Tracking.mixin()],
+ mixins: [glFeatureFlagMixin(), Tracking.mixin()],
props: {
workItemId: {
type: String,
@@ -32,6 +35,15 @@ export default {
type: String,
required: true,
},
+ fetchByIid: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ queryVariables: {
+ type: Object,
+ required: true,
+ },
},
markdownDocsPath: helpPagePath('user/markdown'),
data() {
@@ -41,21 +53,37 @@ export default {
isSubmitting: false,
isSubmittingWithKeydown: false,
descriptionText: '',
+ descriptionHtml: '',
};
},
apollo: {
workItem: {
- query: workItemQuery,
+ query() {
+ return getWorkItemQuery(this.fetchByIid);
+ },
variables() {
- return {
- id: this.workItemId,
- };
+ return this.queryVariables;
+ },
+ update(data) {
+ return this.fetchByIid ? data.workspace.workItems.nodes[0] : data.workItem;
},
skip() {
return !this.workItemId;
},
+ result() {
+ this.descriptionText = this.workItemDescription?.description;
+ this.descriptionHtml = this.workItemDescription?.descriptionHtml;
+ },
error() {
- this.error = i18n.fetchError;
+ this.$emit('error', i18n.fetchError);
+ },
+ subscribeToMore: {
+ document: workItemDescriptionSubscription,
+ variables() {
+ return {
+ issuableId: this.workItemId,
+ };
+ },
},
},
},
@@ -64,7 +92,7 @@ export default {
return this.workItemId;
},
canEdit() {
- return this.workItem?.userPermissions?.updateWorkItem;
+ return this.workItem?.userPermissions?.updateWorkItem || false;
},
tracking() {
return {
@@ -73,12 +101,6 @@ export default {
property: `type_${this.workItemType}`,
};
},
- descriptionHtml() {
- return this.workItemDescription?.descriptionHtml;
- },
- descriptionEmpty() {
- return this.descriptionHtml?.trim() === '';
- },
workItemDescription() {
const descriptionWidget = this.workItem?.widgets?.find(
(widget) => widget.type === WIDGET_TYPE_DESCRIPTION,
@@ -114,7 +136,7 @@ export default {
await this.$nextTick();
- this.$refs.textarea.focus();
+ this.$refs.textarea?.focus();
},
async cancelEditing() {
const isDirty = this.descriptionText !== this.workItemDescription?.description;
@@ -142,8 +164,10 @@ export default {
updateDraft(this.autosaveKey, this.descriptionText);
},
- async updateWorkItem(event) {
- if (event.key) {
+ async updateWorkItem(event = {}) {
+ const { key } = event;
+
+ if (key) {
this.isSubmittingWithKeydown = true;
}
@@ -179,73 +203,90 @@ export default {
this.isSubmitting = false;
},
+ setDescriptionText(newText) {
+ this.descriptionText = newText;
+ updateDraft(this.autosaveKey, this.descriptionText);
+ },
+ handleDescriptionTextUpdated(newText) {
+ this.descriptionText = newText;
+ this.updateWorkItem();
+ },
},
};
</script>
<template>
- <gl-form-group
- v-if="isEditing"
- class="gl-my-5 gl-border-t gl-pt-6"
- :label="__('Description')"
- label-for="work-item-description"
- >
- <markdown-field
- can-attach-file
- :textarea-value="descriptionText"
- :is-submitting="isSubmitting"
- :markdown-preview-path="markdownPreviewPath"
- :markdown-docs-path="$options.markdownDocsPath"
- class="gl-p-3 bordered-box gl-mt-5"
+ <div>
+ <gl-form-group
+ v-if="isEditing"
+ class="gl-mb-5 gl-border-t gl-pt-6"
+ :label="__('Description')"
+ label-for="work-item-description"
>
- <template #textarea>
- <textarea
- id="work-item-description"
- ref="textarea"
- v-model="descriptionText"
- :disabled="isSubmitting"
- class="note-textarea js-gfm-input js-autosize markdown-area"
- dir="auto"
- data-supports-quick-actions="false"
- :aria-label="__('Description')"
- :placeholder="__('Write a comment or drag your files here…')"
- @keydown.meta.enter="updateWorkItem"
- @keydown.ctrl.enter="updateWorkItem"
- @keydown.exact.esc.stop="cancelEditing"
- @input="onInput"
- ></textarea>
- </template>
- </markdown-field>
-
- <div class="gl-display-flex">
- <gl-button
- category="primary"
- variant="confirm"
- :loading="isSubmitting"
- data-testid="save-description"
- @click="updateWorkItem"
- >{{ __('Save') }}</gl-button
- >
- <gl-button category="tertiary" class="gl-ml-3" data-testid="cancel" @click="cancelEditing">{{
- __('Cancel')
- }}</gl-button>
- </div>
- </gl-form-group>
- <div v-else class="gl-mb-5 gl-border-t">
- <div class="gl-display-inline-flex gl-align-items-center gl-mb-5">
- <label class="d-block col-form-label gl-mr-5">{{ __('Description') }}</label>
- <gl-button
- v-if="canEdit"
- class="gl-ml-auto"
- icon="pencil"
- data-testid="edit-description"
- :aria-label="__('Edit description')"
- @click="startEditing"
+ <markdown-editor
+ v-if="glFeatures.workItemsMvc2"
+ class="gl-my-3 common-note-form"
+ :value="descriptionText"
+ :render-markdown-path="markdownPreviewPath"
+ :markdown-docs-path="$options.markdownDocsPath"
+ :form-field-aria-label="__('Description')"
+ :form-field-placeholder="__('Write a comment or drag your files here…')"
+ form-field-id="work-item-description"
+ form-field-name="work-item-description"
+ enable-autocomplete
+ init-on-autofocus
+ @input="setDescriptionText"
+ @keydown.meta.enter="updateWorkItem"
+ @keydown.ctrl.enter="updateWorkItem"
/>
- </div>
-
- <div v-if="descriptionEmpty" class="gl-text-secondary gl-mb-5">{{ __('None') }}</div>
- <div v-else v-safe-html="descriptionHtml" class="md gl-mb-5 gl-min-h-8"></div>
+ <markdown-field
+ v-else
+ can-attach-file
+ :textarea-value="descriptionText"
+ :is-submitting="isSubmitting"
+ :markdown-preview-path="markdownPreviewPath"
+ :markdown-docs-path="$options.markdownDocsPath"
+ class="gl-p-3 bordered-box gl-mt-5"
+ >
+ <template #textarea>
+ <textarea
+ id="work-item-description"
+ ref="textarea"
+ v-model="descriptionText"
+ :disabled="isSubmitting"
+ class="note-textarea js-gfm-input js-autosize markdown-area"
+ dir="auto"
+ data-supports-quick-actions="false"
+ :aria-label="__('Description')"
+ :placeholder="__('Write a comment or drag your files here…')"
+ @keydown.meta.enter="updateWorkItem"
+ @keydown.ctrl.enter="updateWorkItem"
+ @keydown.exact.esc.stop="cancelEditing"
+ @input="onInput"
+ ></textarea>
+ </template>
+ </markdown-field>
+ <div class="gl-display-flex">
+ <gl-button
+ category="primary"
+ variant="confirm"
+ :loading="isSubmitting"
+ data-testid="save-description"
+ @click="updateWorkItem"
+ >{{ __('Save') }}
+ </gl-button>
+ <gl-button category="tertiary" class="gl-ml-3" data-testid="cancel" @click="cancelEditing"
+ >{{ __('Cancel') }}
+ </gl-button>
+ </div>
+ </gl-form-group>
+ <work-item-description-rendered
+ v-else
+ :work-item-description="workItemDescription"
+ :can-edit="canEdit"
+ @startEditing="startEditing"
+ @descriptionUpdated="handleDescriptionTextUpdated"
+ />
<edited-at
v-if="lastEditedAt"
:updated-at="lastEditedAt"
diff --git a/app/assets/javascripts/work_items/components/work_item_description_rendered.vue b/app/assets/javascripts/work_items/components/work_item_description_rendered.vue
new file mode 100644
index 00000000000..e6f8a301c5e
--- /dev/null
+++ b/app/assets/javascripts/work_items/components/work_item_description_rendered.vue
@@ -0,0 +1,117 @@
+<script>
+import { GlButton, GlSafeHtmlDirective } from '@gitlab/ui';
+import $ from 'jquery';
+import '~/behaviors/markdown/render_gfm';
+
+const isCheckbox = (target) => target?.classList.contains('task-list-item-checkbox');
+
+export default {
+ directives: {
+ SafeHtml: GlSafeHtmlDirective,
+ },
+ components: {
+ GlButton,
+ },
+ props: {
+ workItemDescription: {
+ type: Object,
+ required: true,
+ },
+ canEdit: {
+ type: Boolean,
+ required: true,
+ },
+ },
+ computed: {
+ descriptionText() {
+ return this.workItemDescription?.description;
+ },
+ descriptionHtml() {
+ return this.workItemDescription?.descriptionHtml;
+ },
+ descriptionEmpty() {
+ return this.descriptionHtml?.trim() === '';
+ },
+ },
+ watch: {
+ descriptionHtml: {
+ handler() {
+ this.renderGFM();
+ },
+ immediate: true,
+ },
+ },
+ methods: {
+ async renderGFM() {
+ await this.$nextTick();
+
+ $(this.$refs['gfm-content']).renderGFM();
+
+ if (this.canEdit) {
+ this.checkboxes = this.$el.querySelectorAll('.task-list-item-checkbox');
+
+ // enable boxes, disabled by default in markdown
+ this.checkboxes.forEach((checkbox) => {
+ // eslint-disable-next-line no-param-reassign
+ checkbox.disabled = false;
+ });
+ }
+ },
+ toggleCheckboxes(event) {
+ const { target } = event;
+
+ if (isCheckbox(target)) {
+ target.disabled = true;
+
+ const { sourcepos } = target.parentElement.dataset;
+
+ if (!sourcepos) return;
+
+ const [startRange] = sourcepos.split('-');
+ let [startRow] = startRange.split(':');
+ startRow = Number(startRow) - 1;
+
+ const descriptionTextRows = this.descriptionText.split('\n');
+ const newDescriptionText = descriptionTextRows
+ .map((row, index) => {
+ if (startRow === index) {
+ if (target.checked) {
+ return row.replace(/\[ \]/, '[x]');
+ }
+ return row.replace(/\[[x~]\]/i, '[ ]');
+ }
+ return row;
+ })
+ .join('\n');
+
+ this.$emit('descriptionUpdated', newDescriptionText);
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-mb-5 gl-border-t gl-pt-5">
+ <div class="gl-display-inline-flex gl-align-items-center gl-mb-5">
+ <label class="d-block col-form-label gl-mr-5">{{ __('Description') }}</label>
+ <gl-button
+ v-if="canEdit"
+ class="gl-ml-auto"
+ icon="pencil"
+ data-testid="edit-description"
+ :aria-label="__('Edit description')"
+ @click="$emit('startEditing')"
+ />
+ </div>
+
+ <div v-if="descriptionEmpty" class="gl-text-secondary gl-mb-5">{{ __('None') }}</div>
+ <div
+ v-else
+ ref="gfm-content"
+ v-safe-html="descriptionHtml"
+ class="md gl-mb-5 gl-min-h-8"
+ @change="toggleCheckboxes"
+ ></div>
+ </div>
+</template>
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 af9b8c6101a..7e9fa24e3f5 100644
--- a/app/assets/javascripts/work_items/components/work_item_detail.vue
+++ b/app/assets/javascripts/work_items/components/work_item_detail.vue
@@ -1,4 +1,5 @@
<script>
+import { isEmpty } from 'lodash';
import {
GlAlert,
GlSkeletonLoader,
@@ -11,6 +12,7 @@ import {
} from '@gitlab/ui';
import noAccessSvg from '@gitlab/svgs/dist/illustrations/analytics/no-access.svg';
import { s__ } from '~/locale';
+import { parseBoolean } from '~/lib/utils/common_utils';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue';
@@ -27,12 +29,13 @@ import {
WIDGET_TYPE_ITERATION,
} from '../constants';
-import workItemQuery from '../graphql/work_item.query.graphql';
import workItemDatesSubscription from '../graphql/work_item_dates.subscription.graphql';
import workItemTitleSubscription from '../graphql/work_item_title.subscription.graphql';
import workItemAssigneesSubscription from '../graphql/work_item_assignees.subscription.graphql';
+import workItemMilestoneSubscription from '../graphql/work_item_milestone.subscription.graphql';
import updateWorkItemMutation from '../graphql/update_work_item.mutation.graphql';
import updateWorkItemTaskMutation from '../graphql/update_work_item_task.mutation.graphql';
+import { getWorkItemQuery } from '../utils';
import WorkItemActions from './work_item_actions.vue';
import WorkItemState from './work_item_state.vue';
@@ -72,6 +75,7 @@ export default {
WorkItemMilestone,
},
mixins: [glFeatureFlagMixin()],
+ inject: ['fullPath'],
props: {
isModal: {
type: Boolean,
@@ -83,6 +87,11 @@ export default {
required: false,
default: null,
},
+ iid: {
+ type: String,
+ required: false,
+ default: null,
+ },
workItemParentId: {
type: String,
required: false,
@@ -100,20 +109,26 @@ export default {
},
apollo: {
workItem: {
- query: workItemQuery,
+ query() {
+ return getWorkItemQuery(this.fetchByIid);
+ },
variables() {
- return {
- id: this.workItemId,
- };
+ return this.queryVariables;
},
skip() {
return !this.workItemId;
},
+ update(data) {
+ const workItem = this.fetchByIid ? data.workspace.workItems.nodes[0] : data.workItem;
+ return workItem ?? {};
+ },
error() {
- this.error = this.$options.i18n.fetchError;
- document.title = s__('404|Not found');
+ this.setEmptyState();
},
result() {
+ if (isEmpty(this.workItem)) {
+ this.setEmptyState();
+ }
if (!this.isModal && this.workItem.project) {
const path = this.workItem.project?.fullPath
? ` · ${this.workItem.project.fullPath}`
@@ -127,30 +142,44 @@ export default {
document: workItemTitleSubscription,
variables() {
return {
- issuableId: this.workItemId,
+ issuableId: this.workItem.id,
};
},
+ skip() {
+ return !this.workItem?.id;
+ },
},
{
document: workItemDatesSubscription,
variables() {
return {
- issuableId: this.workItemId,
+ issuableId: this.workItem.id,
};
},
skip() {
- return !this.isWidgetPresent(WIDGET_TYPE_START_AND_DUE_DATE);
+ return !this.isWidgetPresent(WIDGET_TYPE_START_AND_DUE_DATE) || !this.workItem?.id;
},
},
{
document: workItemAssigneesSubscription,
variables() {
return {
- issuableId: this.workItemId,
+ issuableId: this.workItem.id,
+ };
+ },
+ skip() {
+ return !this.isWidgetPresent(WIDGET_TYPE_ASSIGNEES) || !this.workItem?.id;
+ },
+ },
+ {
+ document: workItemMilestoneSubscription,
+ variables() {
+ return {
+ issuableId: this.workItem.id,
};
},
skip() {
- return !this.isWidgetPresent(WIDGET_TYPE_ASSIGNEES);
+ return !this.isWidgetPresent(WIDGET_TYPE_MILESTONE) || !this.workItem?.id;
},
},
],
@@ -212,7 +241,20 @@ export default {
return this.isWidgetPresent(WIDGET_TYPE_ITERATION);
},
workItemMilestone() {
- return this.workItem?.mockWidgets?.find((widget) => widget.type === WIDGET_TYPE_MILESTONE);
+ return this.isWidgetPresent(WIDGET_TYPE_MILESTONE);
+ },
+ fetchByIid() {
+ return this.glFeatures.useIidInWorkItemsPath && parseBoolean(this.$route.query.iid_path);
+ },
+ queryVariables() {
+ return this.fetchByIid
+ ? {
+ fullPath: this.fullPath,
+ iid: this.iid,
+ }
+ : {
+ id: this.workItemId,
+ };
},
},
beforeDestroy() {
@@ -231,7 +273,7 @@ export default {
this.updateInProgress = true;
let updateMutation = updateWorkItemMutation;
let inputVariables = {
- id: this.workItemId,
+ id: this.workItem.id,
confidential: confidentialStatus,
};
@@ -240,7 +282,7 @@ export default {
inputVariables = {
id: this.parentWorkItem.id,
taskData: {
- id: this.workItemId,
+ id: this.workItem.id,
confidential: confidentialStatus,
},
};
@@ -275,6 +317,10 @@ export default {
this.updateInProgress = false;
});
},
+ setEmptyState() {
+ this.error = this.$options.i18n.fetchError;
+ document.title = s__('404|Not found');
+ },
},
WORK_ITEM_VIEWED_STORAGE_KEY,
};
@@ -352,7 +398,7 @@ export default {
:can-update="canUpdate"
:is-confidential="workItem.confidential"
:is-parent-confidential="parentWorkItemConfidentiality"
- @deleteWorkItem="$emit('deleteWorkItem', workItemType)"
+ @deleteWorkItem="$emit('deleteWorkItem', { workItemType, workItemId: workItem.id })"
@toggleWorkItemConfidentiality="toggleConfidentiality"
@error="updateError = $event"
/>
@@ -406,6 +452,8 @@ export default {
: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
@@ -421,8 +469,10 @@ export default {
<work-item-milestone
v-if="workItemMilestone"
:work-item-id="workItem.id"
- :work-item-milestone="workItemMilestone.nodes[0]"
+ :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"
@@ -435,6 +485,8 @@ export default {
:weight="workItemWeight.weight"
:work-item-id="workItem.id"
:work-item-type="workItemType"
+ :fetch-by-iid="fetchByIid"
+ :query-variables="queryVariables"
@error="updateError = $event"
/>
<template v-if="workItemsMvc2Enabled">
@@ -445,6 +497,9 @@ export default {
: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"
/>
</template>
@@ -452,6 +507,8 @@ export default {
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"
/>
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 eae11c2bb2f..9ee302855c7 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
@@ -134,12 +134,12 @@ export default {
async clickShowDueDate() {
this.showDueDateInput = true;
await this.$nextTick();
- this.$refs.dueDatePicker.calendar.show();
+ this.$refs.dueDatePicker.show();
},
async clickShowStartDate() {
this.showStartDateInput = true;
await this.$nextTick();
- this.$refs.startDatePicker.calendar.show();
+ this.$refs.startDatePicker.show();
},
handleStartDateInput() {
if (this.dirtyDueDate && this.dirtyStartDate > this.dirtyDueDate) {
diff --git a/app/assets/javascripts/work_items/components/work_item_labels.vue b/app/assets/javascripts/work_items/components/work_item_labels.vue
index 05077862690..22af3c653e9 100644
--- a/app/assets/javascripts/work_items/components/work_item_labels.vue
+++ b/app/assets/javascripts/work_items/components/work_item_labels.vue
@@ -8,7 +8,7 @@ import LabelItem from '~/vue_shared/components/sidebar/labels_select_widget/labe
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import { isScopedLabel } from '~/lib/utils/common_utils';
import workItemLabelsSubscription from 'ee_else_ce/work_items/graphql/work_item_labels.subscription.graphql';
-import workItemQuery from '../graphql/work_item.query.graphql';
+import { getWorkItemQuery } from '../utils';
import updateWorkItemMutation from '../graphql/update_work_item.mutation.graphql';
import {
@@ -50,6 +50,15 @@ export default {
type: String,
required: true,
},
+ fetchByIid: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ queryVariables: {
+ type: Object,
+ required: true,
+ },
},
data() {
return {
@@ -64,11 +73,14 @@ export default {
},
apollo: {
workItem: {
- query: workItemQuery,
+ query() {
+ return getWorkItemQuery(this.fetchByIid);
+ },
variables() {
- return {
- id: this.workItemId,
- };
+ return this.queryVariables;
+ },
+ update(data) {
+ return this.fetchByIid ? data.workspace.workItems.nodes[0] : data.workItem;
},
skip() {
return !this.workItemId;
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 37aa48be6e5..0251dcc33fa 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
@@ -6,10 +6,6 @@ import WorkItemLinks from './work_item_links.vue';
Vue.use(GlToast);
export default function initWorkItemLinks() {
- if (!window.gon.features.workItemsHierarchy) {
- return;
- }
-
const workItemLinksRoot = document.querySelector('.js-work-item-links-root');
if (!workItemLinksRoot) {
@@ -21,7 +17,6 @@ export default function initWorkItemLinks() {
wiHasIssueWeightsFeature,
iid,
wiHasIterationsFeature,
- projectNamespace,
} = workItemLinksRoot.dataset;
// eslint-disable-next-line no-new
@@ -38,7 +33,6 @@ export default function initWorkItemLinks() {
fullPath: projectPath,
hasIssueWeightsFeature: wiHasIssueWeightsFeature,
hasIterationsFeature: wiHasIterationsFeature,
- projectNamespace,
},
render: (createElement) =>
createElement('work-item-links', {
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 0d3e951de7e..3d469b790a1 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
@@ -1,5 +1,13 @@
<script>
-import { GlButton, GlIcon, GlAlert, GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
+import {
+ GlButton,
+ GlDropdown,
+ GlDropdownItem,
+ GlIcon,
+ GlAlert,
+ GlLoadingIcon,
+ GlTooltipDirective,
+} from '@gitlab/ui';
import { produce } from 'immer';
import { s__ } from '~/locale';
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
@@ -9,7 +17,12 @@ import getIssueDetailsQuery from 'ee_else_ce/work_items/graphql/get_issue_detail
import { isMetaKey } from '~/lib/utils/common_utils';
import { setUrlParams, updateHistory } from '~/lib/utils/url_utility';
-import { WIDGET_ICONS, WORK_ITEM_STATUS_TEXT, WIDGET_TYPE_HIERARCHY } from '../../constants';
+import {
+ FORM_TYPES,
+ WIDGET_ICONS,
+ WORK_ITEM_STATUS_TEXT,
+ WIDGET_TYPE_HIERARCHY,
+} from '../../constants';
import getWorkItemLinksQuery from '../../graphql/work_item_links.query.graphql';
import updateWorkItemMutation from '../../graphql/update_work_item.mutation.graphql';
import workItemQuery from '../../graphql/work_item.query.graphql';
@@ -20,6 +33,8 @@ import WorkItemLinksForm from './work_item_links_form.vue';
export default {
components: {
GlButton,
+ GlDropdown,
+ GlDropdownItem,
GlIcon,
GlAlert,
GlLoadingIcon,
@@ -80,6 +95,7 @@ export default {
prefetchedWorkItem: null,
error: undefined,
parentIssue: null,
+ formType: null,
};
},
computed: {
@@ -89,6 +105,9 @@ export default {
issuableIteration() {
return this.parentIssue?.iteration;
},
+ issuableMilestone() {
+ return this.parentIssue?.milestone;
+ },
children() {
return (
this.workItem?.widgets.find((widget) => widget.type === WIDGET_TYPE_HIERARCHY)?.children
@@ -125,9 +144,10 @@ export default {
toggle() {
this.isOpen = !this.isOpen;
},
- showAddForm() {
+ showAddForm(formType) {
this.isOpen = true;
this.isShownAddForm = true;
+ this.formType = formType;
this.$nextTick(() => {
this.$refs.wiLinksForm.$refs.wiTitleInput?.$el.focus();
});
@@ -239,15 +259,18 @@ export default {
'WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts.',
),
addChildButtonLabel: s__('WorkItem|Add'),
+ addChildOptionLabel: s__('WorkItem|Existing task'),
+ createChildOptionLabel: s__('WorkItem|New task'),
},
WIDGET_TYPE_TASK_ICON: WIDGET_ICONS.TASK,
WORK_ITEM_STATUS_TEXT,
+ FORM_TYPES,
};
</script>
<template>
<div
- class="gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100 gl-bg-gray-10 gl-mt-5"
+ class="gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100 gl-bg-gray-10 gl-mt-4"
data-testid="work-item-links"
>
<div
@@ -264,15 +287,26 @@ export default {
{{ childrenCountLabel }}
</span>
</div>
- <gl-button
+ <gl-dropdown
v-if="canUpdate"
- category="secondary"
+ right
size="small"
- data-testid="toggle-add-form"
- @click="showAddForm"
+ :text="$options.i18n.addChildButtonLabel"
+ data-testid="toggle-form"
>
- {{ $options.i18n.addChildButtonLabel }}
- </gl-button>
+ <gl-dropdown-item
+ data-testid="toggle-create-form"
+ @click="showAddForm($options.FORM_TYPES.create)"
+ >
+ {{ $options.i18n.createChildOptionLabel }}
+ </gl-dropdown-item>
+ <gl-dropdown-item
+ data-testid="toggle-add-form"
+ @click="showAddForm($options.FORM_TYPES.add)"
+ >
+ {{ $options.i18n.addChildOptionLabel }}
+ </gl-dropdown-item>
+ </gl-dropdown>
<div class="gl-border-l-1 gl-border-l-solid gl-border-l-gray-100 gl-pl-3 gl-ml-3">
<gl-button
category="tertiary"
@@ -309,6 +343,8 @@ export default {
:children-ids="childrenIds"
:parent-confidential="confidential"
:parent-iteration="issuableIteration"
+ :parent-milestone="issuableMilestone"
+ :form-type="formType"
@cancel="hideAddForm"
@addWorkItemChild="addChild"
/>
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 a01f4616cab..095ea86e0d8 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
@@ -1,21 +1,26 @@
<script>
-import { GlAlert, GlFormGroup, GlForm, GlFormCombobox, GlButton, GlFormInput } from '@gitlab/ui';
+import { GlAlert, GlFormGroup, GlForm, GlTokenSelector, GlButton, GlFormInput } from '@gitlab/ui';
+import { debounce } from 'lodash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import { __, s__ } from '~/locale';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import projectWorkItemTypesQuery from '~/work_items/graphql/project_work_item_types.query.graphql';
+import projectWorkItemsQuery from '../../graphql/project_work_items.query.graphql';
import updateWorkItemMutation from '../../graphql/update_work_item.mutation.graphql';
import createWorkItemMutation from '../../graphql/create_work_item.mutation.graphql';
-import { TASK_TYPE_NAME } from '../../constants';
+import { FORM_TYPES, TASK_TYPE_NAME } from '../../constants';
export default {
components: {
GlAlert,
GlForm,
- GlFormCombobox,
+ GlTokenSelector,
GlButton,
GlFormGroup,
GlFormInput,
},
+ mixins: [glFeatureFlagMixin()],
inject: ['projectPath', 'hasIterationsFeature'],
props: {
issuableGid: {
@@ -38,6 +43,15 @@ export default {
required: false,
default: () => {},
},
+ parentMilestone: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ formType: {
+ type: String,
+ required: true,
+ },
},
apollo: {
workItemTypes: {
@@ -51,33 +65,73 @@ export default {
return data.workspace?.workItemTypes?.nodes;
},
},
+ availableWorkItems: {
+ query: projectWorkItemsQuery,
+ variables() {
+ return {
+ projectPath: this.projectPath,
+ searchTerm: this.search?.title || this.search,
+ types: ['TASK'],
+ in: this.search ? 'TITLE' : undefined,
+ };
+ },
+ skip() {
+ return !this.searchStarted;
+ },
+ update(data) {
+ return data.workspace.workItems.nodes.filter((wi) => !this.childrenIds.includes(wi.id));
+ },
+ },
},
data() {
return {
+ workItemTypes: [],
availableWorkItems: [],
search: '',
+ searchStarted: false,
error: null,
childToCreateTitle: null,
+ workItemsToAdd: [],
};
},
computed: {
- actionsList() {
- return [
- {
- label: this.$options.i18n.createChildOptionLabel,
- fn: () => {
- this.childToCreateTitle = this.search?.title || this.search;
- },
+ workItemInput() {
+ let workItemInput = {
+ title: this.search?.title || this.search,
+ projectPath: this.projectPath,
+ workItemTypeId: this.taskWorkItemType,
+ hierarchyWidget: {
+ parentId: this.issuableGid,
},
- ];
+ confidential: this.parentConfidential,
+ };
+
+ if (this.associateMilestone) {
+ workItemInput = {
+ ...workItemInput,
+ milestoneWidget: {
+ milestoneId: this.parentMilestoneId,
+ },
+ };
+ }
+ return workItemInput;
+ },
+ workItemsMvc2Enabled() {
+ return this.glFeatures.workItemsMvc2;
+ },
+ isCreateForm() {
+ return this.formType === FORM_TYPES.create;
},
addOrCreateButtonLabel() {
- return this.childToCreateTitle
- ? this.$options.i18n.createChildOptionLabel
- : this.$options.i18n.addTaskButtonLabel;
+ if (this.isCreateForm) {
+ return this.$options.i18n.createChildOptionLabel;
+ } else if (this.workItemsToAdd.length > 1) {
+ return this.$options.i18n.addTasksButtonLabel;
+ }
+ return this.$options.i18n.addTaskButtonLabel;
},
addOrCreateMethod() {
- return this.childToCreateTitle ? this.createChild : this.addChild;
+ return this.isCreateForm ? this.createChild : this.addChild;
},
taskWorkItemType() {
return this.workItemTypes.find((type) => type.name === TASK_TYPE_NAME)?.id;
@@ -85,6 +139,24 @@ export default {
parentIterationId() {
return this.parentIteration?.id;
},
+ associateIteration() {
+ return this.parentIterationId && this.hasIterationsFeature && this.workItemsMvc2Enabled;
+ },
+ parentMilestoneId() {
+ return this.parentMilestone?.id;
+ },
+ associateMilestone() {
+ return this.parentMilestoneId && this.workItemsMvc2Enabled;
+ },
+ isSubmitButtonDisabled() {
+ return this.isCreateForm ? this.search.length === 0 : this.workItemsToAdd.length === 0;
+ },
+ isLoading() {
+ return this.$apollo.queries.availableWorkItems.loading;
+ },
+ },
+ created() {
+ this.debouncedSearchKeyUpdate = debounce(this.setSearchKey, DEFAULT_DEBOUNCE_AND_THROTTLE_MS);
},
methods: {
getIdFromGraphQLId,
@@ -92,6 +164,7 @@ export default {
this.error = null;
},
addChild() {
+ this.searchStarted = false;
this.$apollo
.mutate({
mutation: updateWorkItemMutation,
@@ -99,7 +172,7 @@ export default {
input: {
id: this.issuableGid,
hierarchyWidget: {
- childrenIds: [this.search.id],
+ childrenIds: this.workItemsToAdd.map((wi) => wi.id),
},
},
},
@@ -109,7 +182,7 @@ export default {
[this.error] = data.workItemUpdate.errors;
} else {
this.unsetError();
- this.$emit('addWorkItemChild', this.search);
+ this.workItemsToAdd = [];
}
})
.catch(() => {
@@ -124,15 +197,7 @@ export default {
.mutate({
mutation: createWorkItemMutation,
variables: {
- input: {
- title: this.search?.title || this.search,
- projectPath: this.projectPath,
- workItemTypeId: this.taskWorkItemType,
- hierarchyWidget: {
- parentId: this.issuableGid,
- },
- confidential: this.parentConfidential,
- },
+ input: this.workItemInput,
},
})
.then(({ data }) => {
@@ -145,7 +210,7 @@ export default {
* call update mutation only when there is an iteration associated with the issue
*/
// TODO: setting the iteration should be moved to the creation mutation once the backend is done
- if (this.parentIterationId && this.hasIterationsFeature) {
+ if (this.associateIteration) {
this.addIterationToWorkItem(data.workItemCreate.workItem.id);
}
}
@@ -171,10 +236,25 @@ export default {
},
});
},
+ setSearchKey(value) {
+ this.search = value;
+ },
+ handleFocus() {
+ this.searchStarted = true;
+ },
+ handleMouseOver() {
+ this.timeout = setTimeout(() => {
+ this.searchStarted = true;
+ }, DEFAULT_DEBOUNCE_AND_THROTTLE_MS);
+ },
+ handleMouseOut() {
+ clearTimeout(this.timeout);
+ },
},
i18n: {
inputLabel: __('Title'),
addTaskButtonLabel: s__('WorkItem|Add task'),
+ addTasksButtonLabel: s__('WorkItem|Add tasks'),
addChildErrorMessage: s__(
'WorkItem|Something went wrong when trying to add a child. Please try again.',
),
@@ -182,7 +262,8 @@ export default {
createChildErrorMessage: s__(
'WorkItem|Something went wrong when trying to create a child. Please try again.',
),
- placeholder: s__('WorkItem|Add a title'),
+ createPlaceholder: s__('WorkItem|Add a title'),
+ addPlaceholder: s__('WorkItem|Search existing tasks'),
fieldValidationMessage: __('Maximum of 255 characters'),
},
};
@@ -191,56 +272,59 @@ export default {
<template>
<gl-form
class="gl-bg-white gl-mb-3 gl-p-4 gl-border gl-border-gray-100 gl-rounded-base"
- @submit.prevent="createChild"
+ @submit.prevent="addOrCreateMethod"
>
<gl-alert v-if="error" variant="danger" class="gl-mb-3" @dismiss="unsetError">
{{ error }}
</gl-alert>
- <!-- Follow up issue to turn this functionality back on https://gitlab.com/gitlab-org/gitlab/-/issues/368757 -->
- <gl-form-combobox
- v-if="false"
- v-model="search"
- :token-list="availableWorkItems"
- match-value-to-attr="title"
- class="gl-mb-4"
- :label-text="$options.i18n.inputLabel"
- :action-list="actionsList"
- label-sr-only
- autofocus
- >
- <template #result="{ item }">
- <div class="gl-display-flex">
- <div class="gl-text-secondary gl-mr-4">{{ getIdFromGraphQLId(item.id) }}</div>
- <div>{{ item.title }}</div>
- </div>
- </template>
- <template #action="{ item }">
- <span class="gl-text-blue-500">{{ item.label }}</span>
- </template>
- </gl-form-combobox>
<gl-form-group
+ v-if="isCreateForm"
:label="$options.i18n.inputLabel"
:description="$options.i18n.fieldValidationMessage"
>
<gl-form-input
ref="wiTitleInput"
v-model="search"
- :placeholder="$options.i18n.placeholder"
+ :placeholder="$options.i18n.createPlaceholder"
maxlength="255"
class="gl-mb-3"
autofocus
/>
</gl-form-group>
+ <gl-token-selector
+ v-else
+ v-model="workItemsToAdd"
+ :dropdown-items="availableWorkItems"
+ :loading="isLoading"
+ :placeholder="$options.i18n.addPlaceholder"
+ menu-class="gl-dropdown-menu-wide dropdown-reduced-height gl-min-h-7!"
+ class="gl-mb-4"
+ data-testid="work-item-token-select-input"
+ @text-input="debouncedSearchKeyUpdate"
+ @focus="handleFocus"
+ @mouseover.native="handleMouseOver"
+ @mouseout.native="handleMouseOut"
+ >
+ <template #token-content="{ token }">
+ {{ token.title }}
+ </template>
+ <template #dropdown-item-content="{ dropdownItem }">
+ <div class="gl-display-flex">
+ <div class="gl-text-secondary gl-mr-4">{{ getIdFromGraphQLId(dropdownItem.id) }}</div>
+ <div class="gl-text-truncate">{{ dropdownItem.title }}</div>
+ </div>
+ </template>
+ </gl-token-selector>
<gl-button
category="primary"
variant="confirm"
size="small"
type="submit"
- :disabled="search.length === 0"
+ :disabled="isSubmitButtonDisabled"
data-testid="add-child-button"
class="gl-mr-2"
>
- {{ $options.i18n.createChildOptionLabel }}
+ {{ addOrCreateButtonLabel }}
</gl-button>
<gl-button category="secondary" size="small" @click="$emit('cancel')">
{{ s__('WorkItem|Cancel') }}
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 c4a36e36555..a8d3b57aae0 100644
--- a/app/assets/javascripts/work_items/components/work_item_milestone.vue
+++ b/app/assets/javascripts/work_items/components/work_item_milestone.vue
@@ -11,10 +11,10 @@ import {
import * as Sentry from '@sentry/browser';
import { debounce } from 'lodash';
import Tracking from '~/tracking';
-import { s__ } from '~/locale';
+import { s__, __ } from '~/locale';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import projectMilestonesQuery from '~/sidebar/queries/project_milestones.query.graphql';
-import localUpdateWorkItemMutation from '../graphql/local_update_work_item.mutation.graphql';
+import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
import {
I18N_WORK_ITEM_ERROR_UPDATING,
sprintfWorkItem,
@@ -33,6 +33,7 @@ export default {
MILESTONE_FETCH_ERROR: s__(
'WorkItem|Something went wrong while fetching milestones. Please try again.',
),
+ EXPIRED_TEXT: __('(expired)'),
},
components: {
GlFormGroup,
@@ -68,6 +69,15 @@ export default {
type: String,
required: true,
},
+ fetchByIid: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ queryVariables: {
+ type: Object,
+ required: true,
+ },
},
data() {
return {
@@ -90,8 +100,13 @@ export default {
emptyPlaceholder() {
return this.canUpdate ? this.$options.i18n.MILESTONE_PLACEHOLDER : this.$options.i18n.NONE;
},
+ expired() {
+ return this.localMilestone?.expired ? ` ${this.$options.i18n.EXPIRED_TEXT}` : '';
+ },
dropdownText() {
- return this.localMilestone?.title || this.emptyPlaceholder;
+ return this.localMilestone?.title
+ ? `${this.localMilestone?.title}${this.expired}`
+ : this.emptyPlaceholder;
},
isLoadingMilestones() {
return this.$apollo.queries.milestones.loading;
@@ -106,6 +121,14 @@ export default {
};
},
},
+ watch: {
+ workItemMilestone: {
+ handler(newVal) {
+ this.localMilestone = newVal;
+ },
+ deep: true,
+ },
+ },
created() {
this.debouncedSearchKeyUpdate = debounce(this.setSearchKey, DEFAULT_DEBOUNCE_AND_THROTTLE_MS);
},
@@ -160,12 +183,13 @@ export default {
this.updateInProgress = true;
this.$apollo
.mutate({
- mutation: localUpdateWorkItemMutation,
+ mutation: updateWorkItemMutation,
variables: {
input: {
id: this.workItemId,
- milestone: {
- milestoneId: this.localMilestone?.id,
+ milestoneWidget: {
+ milestoneId:
+ this.localMilestone?.id === 'no-milestone-id' ? null : this.localMilestone?.id,
},
},
},
@@ -240,6 +264,7 @@ export default {
@click="handleMilestoneClick(milestone)"
>
{{ milestone.title }}
+ <template v-if="milestone.expired">{{ $options.i18n.EXPIRED_TEXT }}</template>
</gl-dropdown-item>
</template>
<gl-dropdown-text v-else>{{ $options.i18n.NO_MATCHING_RESULTS }}</gl-dropdown-text>
diff --git a/app/assets/javascripts/work_items/constants.js b/app/assets/javascripts/work_items/constants.js
index 7737c535650..8b47c24de7d 100644
--- a/app/assets/javascripts/work_items/constants.js
+++ b/app/assets/javascripts/work_items/constants.js
@@ -102,4 +102,9 @@ export const WORK_ITEMS_TYPE_MAP = {
},
};
+export const FORM_TYPES = {
+ create: 'create',
+ add: 'add',
+};
+
export const DEFAULT_PAGE_SIZE_ASSIGNEES = 10;
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 6edb6c89f16..daeb58c0947 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
@@ -4,6 +4,9 @@ query issuableDetails($fullPath: ID!, $iid: String) {
issuable: issue(iid: $iid) {
id
confidential
+ milestone {
+ id
+ }
}
}
}
diff --git a/app/assets/javascripts/work_items/graphql/milestone.fragment.graphql b/app/assets/javascripts/work_items/graphql/milestone.fragment.graphql
new file mode 100644
index 00000000000..58140aff89e
--- /dev/null
+++ b/app/assets/javascripts/work_items/graphql/milestone.fragment.graphql
@@ -0,0 +1,5 @@
+fragment MilestoneFragment on Milestone {
+ expired
+ id
+ title
+}
diff --git a/app/assets/javascripts/work_items/graphql/project_work_items.query.graphql b/app/assets/javascripts/work_items/graphql/project_work_items.query.graphql
index 7d38d203b84..3a23db3886a 100644
--- a/app/assets/javascripts/work_items/graphql/project_work_items.query.graphql
+++ b/app/assets/javascripts/work_items/graphql/project_work_items.query.graphql
@@ -1,13 +1,16 @@
-query projectWorkItems($searchTerm: String, $projectPath: ID!, $types: [IssueType!]) {
+query projectWorkItems(
+ $searchTerm: String
+ $projectPath: ID!
+ $types: [IssueType!]
+ $in: [IssuableSearchableField!]
+) {
workspace: project(fullPath: $projectPath) {
id
- workItems(search: $searchTerm, types: $types) {
- edges {
- node {
- id
- title
- state
- }
+ workItems(search: $searchTerm, types: $types, in: $in) {
+ nodes {
+ id
+ title
+ state
}
}
}
diff --git a/app/assets/javascripts/work_items/graphql/typedefs.graphql b/app/assets/javascripts/work_items/graphql/typedefs.graphql
index 36779dfe11e..fda71fabe22 100644
--- a/app/assets/javascripts/work_items/graphql/typedefs.graphql
+++ b/app/assets/javascripts/work_items/graphql/typedefs.graphql
@@ -1,6 +1,5 @@
enum LocalWidgetType {
ASSIGNEES
- MILESTONE
}
interface LocalWorkItemWidget {
@@ -12,11 +11,6 @@ type LocalWorkItemAssignees implements LocalWorkItemWidget {
nodes: [UserCore]
}
-type LocalWorkItemMilestone implements LocalWorkItemWidget {
- type: LocalWidgetType!
- nodes: [Milestone!]
-}
-
extend type WorkItem {
mockWidgets: [LocalWorkItemWidget]
}
@@ -29,14 +23,9 @@ input LocalUserInput {
avatarUrl: String
}
-input LocalMilestoneInput {
- milestoneId: ID!
-}
-
input LocalUpdateWorkItemInput {
id: WorkItemID!
assignees: [LocalUserInput!]
- milestone: LocalMilestoneInput!
}
type LocalWorkItemPayload {
diff --git a/app/assets/javascripts/work_items/graphql/work_item.fragment.graphql b/app/assets/javascripts/work_items/graphql/work_item.fragment.graphql
index bb05c9b2135..6a81cc230b1 100644
--- a/app/assets/javascripts/work_items/graphql/work_item.fragment.graphql
+++ b/app/assets/javascripts/work_items/graphql/work_item.fragment.graphql
@@ -2,6 +2,7 @@
fragment WorkItem on WorkItem {
id
+ iid
title
state
description
diff --git a/app/assets/javascripts/work_items/graphql/work_item.query.graphql b/app/assets/javascripts/work_items/graphql/work_item.query.graphql
index fa0ab56df75..3b46fed97ec 100644
--- a/app/assets/javascripts/work_items/graphql/work_item.query.graphql
+++ b/app/assets/javascripts/work_items/graphql/work_item.query.graphql
@@ -3,16 +3,5 @@
query workItem($id: WorkItemID!) {
workItem(id: $id) {
...WorkItem
- mockWidgets @client {
- ... on LocalWorkItemMilestone {
- type
- nodes {
- id
- title
- expired
- dueDate
- }
- }
- }
}
}
diff --git a/app/assets/javascripts/work_items/graphql/work_item_by_iid.query.graphql b/app/assets/javascripts/work_items/graphql/work_item_by_iid.query.graphql
new file mode 100644
index 00000000000..4c3be007d96
--- /dev/null
+++ b/app/assets/javascripts/work_items/graphql/work_item_by_iid.query.graphql
@@ -0,0 +1,12 @@
+#import "./work_item.fragment.graphql"
+
+query workItemByIid($fullPath: ID!, $iid: String) {
+ workspace: project(fullPath: $fullPath) {
+ id
+ workItems(iid: $iid) {
+ nodes {
+ ...WorkItem
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/work_items/graphql/work_item_description.subscription.graphql b/app/assets/javascripts/work_items/graphql/work_item_description.subscription.graphql
new file mode 100644
index 00000000000..4eb3d8067d9
--- /dev/null
+++ b/app/assets/javascripts/work_items/graphql/work_item_description.subscription.graphql
@@ -0,0 +1,20 @@
+subscription issuableDescription($issuableId: IssuableID!) {
+ issuableDescriptionUpdated(issuableId: $issuableId) {
+ ... on WorkItem {
+ id
+ widgets {
+ ... on WorkItemWidgetDescription {
+ type
+ description
+ descriptionHtml
+ lastEditedAt
+ lastEditedBy {
+ id
+ name
+ webPath
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/work_items/graphql/work_item_milestone.subscription.graphql b/app/assets/javascripts/work_items/graphql/work_item_milestone.subscription.graphql
new file mode 100644
index 00000000000..f5163003fe5
--- /dev/null
+++ b/app/assets/javascripts/work_items/graphql/work_item_milestone.subscription.graphql
@@ -0,0 +1,17 @@
+#import "~/work_items/graphql/milestone.fragment.graphql"
+
+subscription issuableMilestone($issuableId: IssuableID!) {
+ issuableMilestoneUpdated(issuableId: $issuableId) {
+ ... on WorkItem {
+ id
+ widgets {
+ ... on WorkItemWidgetMilestone {
+ type
+ milestone {
+ ...MilestoneFragment
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql b/app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql
index d404cfb10ed..b9715c21c27 100644
--- a/app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql
+++ b/app/assets/javascripts/work_items/graphql/work_item_widgets.fragment.graphql
@@ -1,5 +1,6 @@
#import "~/graphql_shared/fragments/label.fragment.graphql"
#import "~/graphql_shared/fragments/user.fragment.graphql"
+#import "~/work_items/graphql/milestone.fragment.graphql"
fragment WorkItemWidgets on WorkItemWidget {
... on WorkItemWidgetDescription {
@@ -49,4 +50,10 @@ fragment WorkItemWidgets on WorkItemWidget {
}
}
}
+ ... on WorkItemWidgetMilestone {
+ type
+ milestone {
+ ...MilestoneFragment
+ }
+ }
}
diff --git a/app/assets/javascripts/work_items/index.js b/app/assets/javascripts/work_items/index.js
index f872d8c6b12..4fbcdfe2b96 100644
--- a/app/assets/javascripts/work_items/index.js
+++ b/app/assets/javascripts/work_items/index.js
@@ -6,13 +6,7 @@ import { createRouter } from './router';
export const initWorkItemsRoot = () => {
const el = document.querySelector('#js-work-items');
- const {
- fullPath,
- hasIssueWeightsFeature,
- issuesListPath,
- projectNamespace,
- hasIterationsFeature,
- } = el.dataset;
+ const { fullPath, hasIssueWeightsFeature, issuesListPath, hasIterationsFeature } = el.dataset;
return new Vue({
el,
@@ -23,7 +17,6 @@ export const initWorkItemsRoot = () => {
fullPath,
hasIssueWeightsFeature: parseBoolean(hasIssueWeightsFeature),
issuesListPath,
- projectNamespace,
hasIterationsFeature: parseBoolean(hasIterationsFeature),
},
render(createElement) {
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 4908b99e5b0..2245f984174 100644
--- a/app/assets/javascripts/work_items/pages/create_work_item.vue
+++ b/app/assets/javascripts/work_items/pages/create_work_item.vue
@@ -3,10 +3,11 @@ import { GlButton, GlAlert, GlLoadingIcon, GlFormSelect } from '@gitlab/ui';
import { getPreferredLocales, s__ } from '~/locale';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { sprintfWorkItem, I18N_WORK_ITEM_ERROR_CREATING } from '../constants';
-import workItemQuery from '../graphql/work_item.query.graphql';
import createWorkItemMutation from '../graphql/create_work_item.mutation.graphql';
import projectWorkItemTypesQuery from '../graphql/project_work_item_types.query.graphql';
+import { getWorkItemQuery } from '../utils';
import ItemTitle from '../components/item_title.vue';
@@ -21,6 +22,7 @@ export default {
ItemTitle,
GlFormSelect,
},
+ mixins: [glFeatureFlagMixin()],
inject: ['fullPath'],
props: {
initialTitle: {
@@ -71,6 +73,9 @@ export default {
return sprintfWorkItem(I18N_WORK_ITEM_ERROR_CREATING, workItemType);
},
+ fetchByIid() {
+ return this.glFeatures.useIidInWorkItemsPath;
+ },
},
methods: {
async createWorkItem() {
@@ -89,28 +94,47 @@ export default {
workItemTypeId: this.selectedWorkItemType,
},
},
- update(store, { data: { workItemCreate } }) {
+ update: (store, { data: { workItemCreate } }) => {
const { workItem } = workItemCreate;
+ const data = this.fetchByIid
+ ? {
+ workspace: {
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ __typename: 'Project',
+ id: workItem.project.id,
+ workItems: {
+ __typename: 'WorkItemConnection',
+ nodes: [workItem],
+ },
+ },
+ }
+ : { workItem };
store.writeQuery({
- query: workItemQuery,
- variables: {
- id: workItem.id,
- },
- data: {
- workItem,
- },
+ query: getWorkItemQuery(this.fetchByIid),
+ variables: this.fetchByIid
+ ? {
+ fullPath: this.fullPath,
+ iid: workItem.iid,
+ }
+ : {
+ id: workItem.id,
+ },
+ data,
});
},
});
const {
data: {
workItemCreate: {
- workItem: { id },
+ workItem: { id, iid },
},
},
} = response;
- this.$router.push({ name: 'workItem', params: { id: `${getIdFromGraphQLId(id)}` } });
+ const routerParams = this.fetchByIid
+ ? { name: 'workItem', params: { id: iid }, query: { iid_path: 'true' } }
+ : { name: 'workItem', params: { id: `${getIdFromGraphQLId(id)}` } };
+ this.$router.push(routerParams);
} catch {
this.error = this.createErrorText;
}
diff --git a/app/assets/javascripts/work_items/pages/work_item_root.vue b/app/assets/javascripts/work_items/pages/work_item_root.vue
index a2cacd8bd7a..1c00bd16263 100644
--- a/app/assets/javascripts/work_items/pages/work_item_root.vue
+++ b/app/assets/javascripts/work_items/pages/work_item_root.vue
@@ -38,14 +38,12 @@ export default {
this.ZenMode = new ZenMode();
},
methods: {
- deleteWorkItem(workItemType) {
+ deleteWorkItem({ workItemType, workItemId: id }) {
this.$apollo
.mutate({
mutation: deleteWorkItemMutation,
variables: {
- input: {
- id: this.gid,
- },
+ input: { id },
},
})
.then(({ data: { workItemDelete, errors } }) => {
@@ -72,6 +70,6 @@ export default {
<template>
<div>
<gl-alert v-if="error" variant="danger" @dismiss="error = ''">{{ error }}</gl-alert>
- <work-item-detail :work-item-id="gid" @deleteWorkItem="deleteWorkItem($event)" />
+ <work-item-detail :work-item-id="gid" :iid="id" @deleteWorkItem="deleteWorkItem($event)" />
</div>
</template>
diff --git a/app/assets/javascripts/work_items/router/index.js b/app/assets/javascripts/work_items/router/index.js
index 2b39a298720..777badeb5be 100644
--- a/app/assets/javascripts/work_items/router/index.js
+++ b/app/assets/javascripts/work_items/router/index.js
@@ -9,7 +9,7 @@ Vue.use(VueRouter);
export function createRouter(fullPath) {
return new VueRouter({
- routes,
+ routes: routes(),
mode: 'history',
base: joinPaths(fullPath, '-', 'work_items'),
});
diff --git a/app/assets/javascripts/work_items/router/routes.js b/app/assets/javascripts/work_items/router/routes.js
index 95772bbd026..1e3a7e184bb 100644
--- a/app/assets/javascripts/work_items/router/routes.js
+++ b/app/assets/javascripts/work_items/router/routes.js
@@ -1,13 +1,22 @@
-export const routes = [
- {
- path: '/new',
- name: 'createWorkItem',
- component: () => import('../pages/create_work_item.vue'),
- },
- {
- path: '/:id',
- name: 'workItem',
- component: () => import('../pages/work_item_root.vue'),
- props: true,
- },
-];
+function getRoutes() {
+ const routes = [
+ {
+ path: '/:id',
+ name: 'workItem',
+ component: () => import('../pages/work_item_root.vue'),
+ props: true,
+ },
+ ];
+
+ if (gon.features?.workItemsMvc2) {
+ routes.unshift({
+ path: '/new',
+ name: 'createWorkItem',
+ component: () => import('../pages/create_work_item.vue'),
+ });
+ }
+
+ return routes;
+}
+
+export const routes = getRoutes;
diff --git a/app/assets/javascripts/work_items/utils.js b/app/assets/javascripts/work_items/utils.js
new file mode 100644
index 00000000000..17f9c882c2d
--- /dev/null
+++ b/app/assets/javascripts/work_items/utils.js
@@ -0,0 +1,6 @@
+import workItemQuery from './graphql/work_item.query.graphql';
+import workItemByIidQuery from './graphql/work_item_by_iid.query.graphql';
+
+export function getWorkItemQuery(isFetchedByIid) {
+ return isFetchedByIid ? workItemByIidQuery : workItemQuery;
+}
diff --git a/app/assets/javascripts/work_items_hierarchy/components/app.vue b/app/assets/javascripts/work_items_hierarchy/components/app.vue
index 779bd27516a..1eeb3abf4bd 100644
--- a/app/assets/javascripts/work_items_hierarchy/components/app.vue
+++ b/app/assets/javascripts/work_items_hierarchy/components/app.vue
@@ -25,7 +25,7 @@ export default {
workItemTypes() {
return this.workItemHierarchy.reduce(
(itemTypes, item) => {
- const skipItem = workItemTypes[item.type].isWorkItem && !window.gon?.features?.workItems;
+ const skipItem = workItemTypes[item.type].isWorkItem;
if (skipItem) {
return itemTypes;
diff --git a/app/assets/stylesheets/_page_specific_files.scss b/app/assets/stylesheets/_page_specific_files.scss
index 21d9db26382..6878e9a10d7 100644
--- a/app/assets/stylesheets/_page_specific_files.scss
+++ b/app/assets/stylesheets/_page_specific_files.scss
@@ -1,4 +1,3 @@
-@import './pages/branches';
@import './pages/colors';
@import './pages/commits';
@import './pages/detail_page';
@@ -9,11 +8,11 @@
@import './pages/issues';
@import './pages/labels';
@import './pages/login';
+@import './pages/ml_experiment_tracking';
@import './pages/merge_requests';
@import './pages/monitor';
@import './pages/note_form';
@import './pages/notes';
-@import './pages/notifications';
@import './pages/pipelines';
@import './pages/profile';
@import './pages/projects';
diff --git a/app/assets/stylesheets/framework/calendar.scss b/app/assets/stylesheets/framework/calendar.scss
index e69d7b4462d..27e9a041145 100644
--- a/app/assets/stylesheets/framework/calendar.scss
+++ b/app/assets/stylesheets/framework/calendar.scss
@@ -1,6 +1,4 @@
.user-contrib-cell {
- stroke: $t-gray-a-08;
-
&:hover {
cursor: pointer;
stroke: $black;
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index d561a7d9450..c5a34ca4b31 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -46,6 +46,10 @@
}
}
+ &.dropdown-reduced-height {
+ max-height: $dropdown-max-height;
+ }
+
@include media-breakpoint-down(xs) {
width: 100%;
}
diff --git a/app/assets/stylesheets/framework/emojis.scss b/app/assets/stylesheets/framework/emojis.scss
index a31910e3090..68a3493670d 100644
--- a/app/assets/stylesheets/framework/emojis.scss
+++ b/app/assets/stylesheets/framework/emojis.scss
@@ -8,6 +8,7 @@ gl-emoji {
}
.user-status-emoji {
+ margin-left: $gl-padding-4;
margin-right: $gl-padding-4;
gl-emoji {
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index 07516275e58..b28302f29ef 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -290,6 +290,10 @@
padding: $gl-padding;
}
}
+
+ .content-visibility-auto {
+ content-visibility: auto;
+ }
}
}
diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss
index 02b76b89482..7a92adf7b7b 100644
--- a/app/assets/stylesheets/framework/layout.scss
+++ b/app/assets/stylesheets/framework/layout.scss
@@ -207,7 +207,7 @@ body {
}
@include media-breakpoint-up(sm) {
- .logged-out-marketing-header-candidate {
+ .logged-out-marketing-header {
--header-height: 72px;
}
}
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index 900cf9fa4db..ea741af918c 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -1,15 +1,3 @@
-.ajax-users-select {
- width: 400px;
-
- &.input-large {
- width: 210px;
- }
-
- &.input-clamp {
- max-width: 100%;
- }
-}
-
.group-result {
.group-image {
float: left;
@@ -49,7 +37,3 @@
}
}
}
-
-.ajax-users-dropdown {
- min-width: 250px !important;
-}
diff --git a/app/assets/stylesheets/framework/snippets.scss b/app/assets/stylesheets/framework/snippets.scss
index 39786aa0138..14971e3b2ee 100644
--- a/app/assets/stylesheets/framework/snippets.scss
+++ b/app/assets/stylesheets/framework/snippets.scss
@@ -24,6 +24,10 @@
+ .snippet-file-content {
@include gl-mt-5;
}
+
+ &:last-of-type {
+ margin-bottom: 0;
+ }
}
.snippet-header {
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 9cfc5a0201e..99284ea0a64 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -88,14 +88,6 @@ $white-normal: #f0f0f0 !default;
$white-dark: #eaeaea !default;
$white-transparent: rgba($white, 0.8) !default;
-$gray-lightest: #fdfdfd !default;
-$gray-light: #fafafa !default;
-$gray-lighter: #f9f9f9 !default;
-$gray-normal: #f5f5f5 !default;
-$gray-dark: darken($gray-light, $darken-dark-factor) !default;
-$gray-darker: #eee !default;
-$gray-darkest: #c4c4c4 !default;
-
$purple: #6d49cb !default;
$purple-light: #ede8fb !default;
@@ -103,11 +95,6 @@ $black: #000 !default;
$black-transparent: rgba(0, 0, 0, 0.3) !default;
$almost-black: #242424 !default;
-$t-gray-a-02: rgba($black, 0.02) !default;
-$t-gray-a-04: rgba($black, 0.04) !default;
-$t-gray-a-06: rgba($black, 0.06) !default;
-$t-gray-a-08: rgba($black, 0.08) !default;
-
$green-50: #ecf4ee !default;
$green-100: #c3e6cd !default;
$green-200: #91d4a8 !default;
@@ -168,18 +155,33 @@ $purple-800: #453894 !default;
$purple-900: #2f2a6b !default;
$purple-950: #232150 !default;
-$gray-10: #f5f5f5 !default;
-$gray-50: #f0f0f0 !default;
-$gray-100: #dbdbdb !default;
-$gray-200: #bfbfbf !default;
-$gray-300: #999 !default;
-$gray-400: #868686 !default;
-$gray-500: #666 !default;
-$gray-600: #5e5e5e !default;
-$gray-700: #525252 !default;
-$gray-800: #404040 !default;
-$gray-900: #303030 !default;
-$gray-950: #1f1f1f !default;
+$gray-10: #fbfafd !default;
+$gray-50: #ececef !default;
+$gray-100: #dcdcde !default;
+$gray-200: #bfbfc3 !default;
+$gray-300: #a4a3a8 !default;
+$gray-400: #89888d !default;
+$gray-500: #737278 !default;
+$gray-600: #626168 !default;
+$gray-700: #535158 !default;
+$gray-800: #434248 !default;
+$gray-900: #333238 !default;
+$gray-950: #1f1e24 !default;
+
+$gray-lightest: lighten($gray-10, 1) !default;
+$gray-light: $gray-10 !default;
+$gray-lighter: lighten($gray-50, 4) !default;
+$gray-normal: lighten($gray-50, 2) !default;
+$gray-dark: darken($gray-light, $darken-dark-factor) !default;
+$gray-darker: $gray-50 !default;
+$gray-darkest: $gray-200 !default;
+
+$t-gray-a-02: rgba($gray-950, 0.02) !default;
+$t-gray-a-04: rgba($gray-950, 0.04) !default;
+$t-gray-a-06: rgba($gray-950, 0.06) !default;
+$t-gray-a-08: rgba($gray-950, 0.08) !default;
+$t-gray-a-16: rgba($gray-950, 0.16) !default;
+$t-gray-a-24: rgba($gray-950, 0.24) !default;
$greens: (
'50': $green-50,
@@ -346,6 +348,20 @@ $theme-light-red-500: #c24b38;
$theme-light-red-600: #b03927;
$theme-light-red-700: #a62e21;
+// Data visualization color palette
+
+$data-viz-blue-50: #e9ebff;
+$data-viz-blue-100: #d4dcfa;
+$data-viz-blue-200: #b7c6ff;
+$data-viz-blue-300: #97acff;
+$data-viz-blue-400: #748eff;
+$data-viz-blue-500: #5772ff;
+$data-viz-blue-600: #445cf2;
+$data-viz-blue-700: #3547de;
+$data-viz-blue-800: #232fcf;
+$data-viz-blue-900: #1e23a8;
+$data-viz-blue-950: #11118a;
+
$border-white-light: darken($white, $darken-border-factor) !default;
$border-white-normal: darken($white-normal, $darken-border-factor) !default;
@@ -356,7 +372,7 @@ $border-gray-normal-dashed: darken($gray-normal, $darken-border-dashed-factor);
/*
* UI elements
*/
-$contextual-sidebar-bg-color: #f5f5f5;
+$contextual-sidebar-bg-color: $gray-10;
$contextual-sidebar-border-color: #e9e9e9;
$border-color: $gray-100;
$shadow-color: $t-gray-a-08;
@@ -660,18 +676,7 @@ $ci-skipped-color: #888;
*/
$issue-boards-font-size: 14px;
$issue-boards-card-shadow: rgba(0, 0, 0, 0.1);
-/*
- The following heights are used in boards.scss and are used for calculation of the board height.
- They probably should be derived in a smarter way.
-*/
$issue-boards-filter-height: 68px;
-$issue-boards-filter-height-md: 110px;
-$issue-boards-filter-height-sm: 299px;
-$issue-boards-breadcrumbs-height-xs: 63px;
-$issue-board-list-difference-xs: calc(#{$header-height} + #{$issue-boards-breadcrumbs-height-xs});
-$issue-board-list-difference-sm: calc(#{$header-height} + #{$breadcrumb-min-height});
-$issue-board-list-difference-md: calc(#{$issue-board-list-difference-sm} + #{$issue-boards-filter-height-md});
-$issue-board-list-difference-lg: calc(#{$issue-board-list-difference-sm} + #{$issue-boards-filter-height});
/*
The following heights are used in environment_logs.scss and are used for calculation of the log viewer height.
*/
@@ -710,11 +715,11 @@ $job-arrow-margin: 55px;
*/
// See https://gitlab.com/gitlab-org/gitlab/-/issues/332150 to align with Pajamas Design System
$calendar-activity-colors: (
- #f5f5f5,
- #d4dcfa,
- #748eff,
- #3547de,
- #11118a,
+ $gray-50,
+ $data-viz-blue-100,
+ $data-viz-blue-400,
+ $data-viz-blue-700,
+ $data-viz-blue-950,
) !default;
/*
@@ -756,12 +761,6 @@ $document-index-color: #888;
$help-shortcut-header-color: #333;
/*
-* Issues
-*/
-$issues-today-bg: #f3fff2 !default;
-$issues-today-border: #e1e8d5 !default;
-
-/*
* Label
*/
$label-font-size: 12px;
diff --git a/app/assets/stylesheets/highlight/themes/dark.scss b/app/assets/stylesheets/highlight/themes/dark.scss
index 7fb2bf9a875..3438a73eff6 100644
--- a/app/assets/stylesheets/highlight/themes/dark.scss
+++ b/app/assets/stylesheets/highlight/themes/dark.scss
@@ -125,6 +125,14 @@ $dark-il: #de935f;
}
.code.dark {
+ // Highlight.js theme overrides (https://gitlab.com/gitlab-org/gitlab/-/issues/365167)
+ // We should be able to remove the overrides once the upstream issue is fixed (https://github.com/sourcegraph/sourcegraph/issues/23251)
+ @include hljs-override('title\\.class', $dark-nc);
+ @include hljs-override('title\\.class\\.inherited', $dark-no);
+ @include hljs-override('variable\\.constant', $dark-no);
+ @include hljs-override('title\\.function', $dark-nf);
+
+
// Line numbers
.file-line-num {
@include line-link($white, 'link');
diff --git a/app/assets/stylesheets/highlight/themes/monokai.scss b/app/assets/stylesheets/highlight/themes/monokai.scss
index 66cada9181c..75dd342393d 100644
--- a/app/assets/stylesheets/highlight/themes/monokai.scss
+++ b/app/assets/stylesheets/highlight/themes/monokai.scss
@@ -104,7 +104,7 @@ $monokai-gh: #75715e;
@include hljs-override('selector-tag', $monokai-nt);
@include hljs-override('keyword', $monokai-k);
@include hljs-override('variable', $monokai-nv);
- @include hljs-override('variable.language_', $monokai-k);
+ @include hljs-override('variable\\.language_', $monokai-k);
@include hljs-override('title', $monokai-nf);
@include hljs-override('name', $monokai-k);
@include hljs-override('tag', $monokai-nt);
@@ -116,7 +116,13 @@ $monokai-gh: #75715e;
@include hljs-override('bullet', $monokai-n);
@include hljs-override('subst', $monokai-p);
@include hljs-override('symbol', $monokai-ss);
- @include hljs-override('title.class_.inherited__', $monokai-no);
+ @include hljs-override('title\\.class_\\.inherited__', $monokai-no);
+ @include hljs-override('title\\.class\\.inherited', $monokai-no);
+ @include hljs-override('title\\.class', $monokai-nc);
+ @include hljs-override('title\\.function', $monokai-nf);
+ @include hljs-override('variable\\.constant', $monokai-no);
+ @include hljs-override('variable\\.language', $monokai-nb);
+ @include hljs-override('params', $monokai-nb);
// Line numbers
.file-line-num {
diff --git a/app/assets/stylesheets/highlight/themes/solarized-dark.scss b/app/assets/stylesheets/highlight/themes/solarized-dark.scss
index a1bba8720a2..c0b2fb90aa0 100644
--- a/app/assets/stylesheets/highlight/themes/solarized-dark.scss
+++ b/app/assets/stylesheets/highlight/themes/solarized-dark.scss
@@ -107,7 +107,9 @@ $solarized-dark-il: #2aa198;
@include hljs-override('selector-tag', $solarized-dark-nt);
@include hljs-override('keyword', $solarized-dark-k);
@include hljs-override('variable', $solarized-dark-nv);
- @include hljs-override('variable.language_', $solarized-dark-k);
+ @include hljs-override('variable\\.language_', $solarized-dark-k);
+ @include hljs-override('variable\\.language', $solarized-dark-k);
+ @include hljs-override('variable\\.constant', $solarized-dark-no);
@include hljs-override('title', $solarized-dark-nf);
@include hljs-override('name', $solarized-dark-k);
@include hljs-override('tag', $solarized-dark-nt);
@@ -119,7 +121,11 @@ $solarized-dark-il: #2aa198;
@include hljs-override('bullet', $solarized-dark-n);
@include hljs-override('subst', $solarized-dark-p);
@include hljs-override('symbol', $solarized-dark-ni);
- @include hljs-override('title.class_.inherited__', $solarized-dark-no);
+ @include hljs-override('title\\.class_\\.inherited__', $solarized-dark-no);
+ @include hljs-override('title\\.class', $solarized-dark-nc);
+ @include hljs-override('title\\.class\\.inherited', $solarized-dark-no);
+ @include hljs-override('title\\.function', $solarized-dark-nf);
+ @include hljs-override('params', $solarized-dark-nb);
// Line numbers
.file-line-num {
diff --git a/app/assets/stylesheets/highlight/themes/solarized-light.scss b/app/assets/stylesheets/highlight/themes/solarized-light.scss
index 33945f7cda9..921b36dd610 100644
--- a/app/assets/stylesheets/highlight/themes/solarized-light.scss
+++ b/app/assets/stylesheets/highlight/themes/solarized-light.scss
@@ -106,7 +106,17 @@ $solarized-light-il: #2aa198;
}
.code.solarized-light {
- @include hljs-override('title.class_.inherited__', $solarized-light-no);
+ // Highlight.js theme overrides (https://gitlab.com/gitlab-org/gitlab/-/issues/365167)
+ // We should be able to remove the overrides once the upstream issue is fixed (https://github.com/sourcegraph/sourcegraph/issues/23251)
+ @include hljs-override('keyword', $solarized-light-k);
+ @include hljs-override('title\\.class_\\.inherited__', $solarized-light-no);
+ @include hljs-override('title\\.class\\.inherited', $solarized-light-no);
+ @include hljs-override('title\\.class', $solarized-light-nc);
+ @include hljs-override('title\\.function', $solarized-light-nf);
+ @include hljs-override('variable\\.constant', $solarized-light-no);
+ @include hljs-override('variable\\.language', $solarized-light-nb);
+ @include hljs-override('params', $solarized-light-nb);
+
// Line numbers
.file-line-num {
@include line-link($black, 'link');
diff --git a/app/assets/stylesheets/highlight/themes/white.scss b/app/assets/stylesheets/highlight/themes/white.scss
index b0f6595feff..f6cce25671f 100644
--- a/app/assets/stylesheets/highlight/themes/white.scss
+++ b/app/assets/stylesheets/highlight/themes/white.scss
@@ -2,9 +2,18 @@
@import '../white_base';
@include conflict-colors('white');
+
+ // Highlight.js theme overrides (https://gitlab.com/gitlab-org/gitlab/-/issues/365167)
+ // We should be able to remove the overrides once the upstream issue is fixed (https://github.com/sourcegraph/sourcegraph/issues/23251)
@include hljs-override('variable', $white-nv);
@include hljs-override('symbol', $white-ss);
- @include hljs-override('title.class_.inherited__', $white-no);
+ @include hljs-override('title\\.class_\\.inherited__', $white-no);
+ @include hljs-override('title\\.class\\.inherited', $white-no);
+ @include hljs-override('title\\.class', $white-nc);
+ @include hljs-override('variable\\.constant', $white-no);
+ @include hljs-override('variable\\.language', $white-nb);
+ @include hljs-override('title\\.function', $white-nf);
+ @include hljs-override('params', $white-nb);
}
:root {
diff --git a/app/assets/stylesheets/page_bundles/boards.scss b/app/assets/stylesheets/page_bundles/boards.scss
index d45bc865da5..0cc1fb40e4a 100644
--- a/app/assets/stylesheets/page_bundles/boards.scss
+++ b/app/assets/stylesheets/page_bundles/boards.scss
@@ -18,38 +18,9 @@
.boards-list,
.board-swimlanes {
- height: calc(100vh - #{$issue-board-list-difference-xs});
overflow-x: scroll;
min-height: 200px;
border-left: 8px solid var(--gray-10, $white);
-
- @include media-breakpoint-only(sm) {
- height: calc(100vh - #{$issue-board-list-difference-sm});
- }
-
- @include media-breakpoint-up(md) {
- height: calc(100vh - #{$issue-board-list-difference-md});
- }
-
- @include media-breakpoint-up(lg) {
- height: calc(100vh - #{$issue-board-list-difference-lg});
- }
-
- .with-performance-bar & {
- height: calc(100vh - #{$issue-board-list-difference-xs} - #{$performance-bar-height});
-
- @include media-breakpoint-only(sm) {
- height: calc(100vh - #{$issue-board-list-difference-sm} - #{$performance-bar-height});
- }
-
- @include media-breakpoint-up(md) {
- height: calc(100vh - #{$issue-board-list-difference-md} - #{$performance-bar-height});
- }
-
- @include media-breakpoint-up(lg) {
- height: calc(100vh - #{$issue-board-list-difference-lg} - #{$performance-bar-height});
- }
- }
}
.board {
diff --git a/app/assets/stylesheets/page_bundles/branches.scss b/app/assets/stylesheets/page_bundles/branches.scss
new file mode 100644
index 00000000000..2aa90529e22
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/branches.scss
@@ -0,0 +1,41 @@
+@import 'mixins_and_variables_and_functions';
+
+.branch-info {
+ flex: auto;
+ min-width: 0;
+ overflow: hidden;
+}
+
+.divergence-graph {
+ $graph-side-width: 80px;
+ $graph-separator-width: 1px;
+
+ .graph-side {
+ width: $graph-side-width;
+
+ &.full {
+ width: $graph-side-width * 2 + $graph-separator-width;
+ }
+
+ .bar {
+ height: 4px;
+ background-color: $gray-100;
+ }
+
+ .count {
+ font-size: 12px;
+ }
+ }
+
+ .graph-separator {
+ width: $graph-separator-width;
+ height: 18px;
+ background-color: $gray-100;
+ }
+}
+
+.divergence-graph,
+.branch-item .controls {
+ flex: 0 0 auto;
+ white-space: nowrap;
+}
diff --git a/app/assets/stylesheets/page_bundles/clusters.scss b/app/assets/stylesheets/page_bundles/clusters.scss
index a877ae72e31..4f29ff4b1ad 100644
--- a/app/assets/stylesheets/page_bundles/clusters.scss
+++ b/app/assets/stylesheets/page_bundles/clusters.scss
@@ -20,3 +20,7 @@
min-height: 372px;
}
}
+
+.cluster-button-container:focus-within {
+ @include gl-focus;
+}
diff --git a/app/assets/stylesheets/page_bundles/dashboard.scss b/app/assets/stylesheets/page_bundles/dashboard.scss
new file mode 100644
index 00000000000..986a9cc530d
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/dashboard.scss
@@ -0,0 +1,5 @@
+@import 'mixins_and_variables_and_functions';
+
+.empty-state .svg-250 img {
+ max-width: $gl-spacing-scale-20;
+}
diff --git a/app/assets/stylesheets/page_bundles/design_management.scss b/app/assets/stylesheets/page_bundles/design_management.scss
new file mode 100644
index 00000000000..143682e1cd7
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/design_management.scss
@@ -0,0 +1,215 @@
+@import 'mixins_and_variables_and_functions';
+
+$design-pin-diameter: 28px;
+$design-pin-diameter-sm: 24px;
+$t-gray-a-16-design-pin: rgba($black, 0.16);
+
+.design-card-header {
+ background: transparent;
+}
+
+.design-checkbox {
+ position: absolute;
+ top: $gl-padding;
+ left: 30px;
+}
+
+.layout-page.design-detail-layout {
+ max-height: 100vh;
+}
+
+.design-detail {
+ background-color: rgba($modal-backdrop-bg, $modal-backdrop-opacity);
+
+ .with-performance-bar & {
+ top: 35px;
+ }
+
+ .comment-indicator {
+ border-radius: 50%;
+ }
+
+ .comment-indicator,
+ .frame .design-note-pin {
+ &:active {
+ cursor: grabbing;
+ }
+ }
+}
+
+.design-list-item {
+ height: 280px;
+ text-decoration: none;
+
+ .icon-version-status {
+ position: absolute;
+ right: 10px;
+ top: 10px;
+ }
+
+ .card-body {
+ height: 230px;
+ }
+}
+
+// This is temporary class to be removed after feature flag removal: https://gitlab.com/gitlab-org/gitlab/-/issues/223197
+.design-list-item-new {
+ height: 210px;
+}
+
+.design-note-pin {
+ display: flex;
+ height: $design-pin-diameter;
+ width: $design-pin-diameter;
+ box-sizing: content-box;
+ background-color: var(--purple-500, $purple-500);
+ color: var(--white, $white);
+ font-weight: $gl-font-weight-bold;
+ border-radius: 50%;
+ z-index: 1;
+ padding: 0;
+ border: 0;
+
+ &.draft {
+ background-color: var(--orange-500, $orange-500);
+ }
+
+ &.resolved {
+ background-color: var(--gray-500, $gray-500);
+ }
+
+ &.on-image {
+ box-shadow: 0 2px 4px $t-gray-a-08, 0 0 1px $t-gray-a-24;
+ border: var(--white, $white) 2px solid;
+ will-change: transform, box-shadow, opacity;
+ // NOTE: verbose transition property required for Safari
+ transition: transform $general-hover-transition-duration linear, box-shadow $general-hover-transition-duration linear, opacity $general-hover-transition-duration linear;
+ transform-origin: 0 0;
+ transform: translate(-50%, -50%);
+
+ &:hover {
+ transform: scale(1.2) translate(-50%, -50%);
+ }
+
+ &:active {
+ box-shadow: 0 0 4px $t-gray-a-16-design-pin, 0 4px 12px $t-gray-a-16-design-pin;
+ }
+
+ &.inactive {
+ @include gl-opacity-5;
+
+ &:hover {
+ @include gl-opacity-10;
+ }
+ }
+ }
+
+ &.small {
+ position: absolute;
+ border: 1px solid var(--white, $white);
+ height: $design-pin-diameter-sm;
+ width: $design-pin-diameter-sm;
+ }
+
+ &.user-avatar {
+ top: 25px;
+ right: 8px;
+ }
+}
+
+.design-scaler-wrapper {
+ bottom: 0;
+ left: 50%;
+ transform: translateX(-50%);
+}
+
+.image-notes {
+ overflow-y: scroll;
+ padding: $gl-padding;
+ padding-top: 50px;
+ background-color: var(--white, $white);
+ flex-shrink: 0;
+ min-width: 400px;
+ flex-basis: 28%;
+
+ .link-inherit-color {
+ &:hover,
+ &:active,
+ &:focus {
+ color: inherit;
+ text-decoration: none;
+ }
+ }
+
+ .toggle-comments {
+ line-height: 20px;
+ border-top: 1px solid var(--border-color, $border-color);
+
+ &.expanded {
+ border-bottom: 1px solid var(--border-color, $border-color);
+ }
+
+ .toggle-comments-button:focus {
+ text-decoration: none;
+ color: var(--blue-600, $blue-600);
+ }
+ }
+
+ .design-note-pin {
+ margin-left: $gl-padding;
+ }
+
+ .design-discussion {
+ margin: $gl-padding 0;
+
+ &::before {
+ content: '';
+ border-left: 1px solid var(--gray-100, $gray-100);
+ position: absolute;
+ left: 28px;
+ top: -17px;
+ height: 17px;
+ }
+
+ .design-note {
+ padding: $gl-padding;
+ list-style: none;
+ transition: background $gl-transition-duration-medium $general-hover-transition-curve;
+ border-top-left-radius: $border-radius-default; // same border radius used by .bordered-box
+ border-top-right-radius: $border-radius-default;
+
+ a {
+ color: inherit;
+ }
+
+ .note-text a {
+ color: var(--blue-600, $blue-600);
+ }
+ }
+
+ .reply-wrapper {
+ padding: $gl-padding;
+ }
+ }
+
+ .reply-wrapper {
+ border-top: 1px solid var(--border-color, $border-color);
+ }
+
+ .new-discussion-disclaimer {
+ line-height: 20px;
+ }
+}
+
+@media (max-width: map-get($grid-breakpoints, lg)) {
+ .design-detail {
+ overflow-y: scroll;
+ }
+
+ .image-notes {
+ overflow-y: auto;
+ min-width: 100%;
+ flex-grow: 1;
+ flex-basis: auto;
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/ide.scss b/app/assets/stylesheets/page_bundles/ide.scss
index 3951f72112f..ec75c53d026 100644
--- a/app/assets/stylesheets/page_bundles/ide.scss
+++ b/app/assets/stylesheets/page_bundles/ide.scss
@@ -568,6 +568,11 @@ $ide-commit-header-height: 48px;
text-decoration: line-through;
}
}
+
+ .gl-form-radio,
+ .gl-form-checkbox {
+ color: var(--ide-text-color, $gl-text-color);
+ }
}
.ide-sidebar-link {
diff --git a/app/assets/stylesheets/page_bundles/issues_show.scss b/app/assets/stylesheets/page_bundles/issues_show.scss
index bbdcf1ea0c6..26d694f7421 100644
--- a/app/assets/stylesheets/page_bundles/issues_show.scss
+++ b/app/assets/stylesheets/page_bundles/issues_show.scss
@@ -1,9 +1,5 @@
@import 'mixins_and_variables_and_functions';
-$design-pin-diameter: 28px;
-$design-pin-diameter-sm: 24px;
-$t-gray-a-16-design-pin: rgba($black, 0.16);
-
.description {
li {
position: relative;
@@ -27,216 +23,6 @@ $t-gray-a-16-design-pin: rgba($black, 0.16);
}
}
-.design-card-header {
- background: transparent;
-}
-
-.design-checkbox {
- position: absolute;
- top: $gl-padding;
- left: 30px;
-}
-
-.layout-page.design-detail-layout {
- max-height: 100vh;
-}
-
-.design-detail {
- background-color: rgba($modal-backdrop-bg, $modal-backdrop-opacity);
-
- .with-performance-bar & {
- top: 35px;
- }
-
- .comment-indicator {
- border-radius: 50%;
- }
-
- .comment-indicator,
- .frame .design-note-pin {
- &:active {
- cursor: grabbing;
- }
- }
-}
-
-.design-list-item {
- height: 280px;
- text-decoration: none;
-
- .icon-version-status {
- position: absolute;
- right: 10px;
- top: 10px;
- }
-
- .card-body {
- height: 230px;
- }
-}
-
-// This is temporary class to be removed after feature flag removal: https://gitlab.com/gitlab-org/gitlab/-/issues/223197
-.design-list-item-new {
- height: 210px;
-}
-
-.design-note-pin {
- display: flex;
- height: $design-pin-diameter;
- width: $design-pin-diameter;
- box-sizing: content-box;
- background-color: var(--purple-500, $purple-500);
- color: var(--white, $white);
- font-weight: $gl-font-weight-bold;
- border-radius: 50%;
- z-index: 1;
- padding: 0;
- border: 0;
-
- &.draft {
- background-color: var(--orange-500, $orange-500);
- }
-
- &.resolved {
- background-color: var(--gray-500, $gray-500);
- }
-
- &.on-image {
- box-shadow: 0 2px 4px $t-gray-a-08, 0 0 1px $t-gray-a-24;
- border: var(--white, $white) 2px solid;
- will-change: transform, box-shadow, opacity;
- // NOTE: verbose transition property required for Safari
- transition: transform $general-hover-transition-duration linear, box-shadow $general-hover-transition-duration linear, opacity $general-hover-transition-duration linear;
- transform-origin: 0 0;
- transform: translate(-50%, -50%);
-
- &:hover {
- transform: scale(1.2) translate(-50%, -50%);
- }
-
- &:active {
- box-shadow: 0 0 4px $t-gray-a-16-design-pin, 0 4px 12px $t-gray-a-16-design-pin;
- }
-
- &.inactive {
- @include gl-opacity-5;
-
- &:hover {
- @include gl-opacity-10;
- }
- }
- }
-
- &.small {
- position: absolute;
- border: 1px solid var(--white, $white);
- height: $design-pin-diameter-sm;
- width: $design-pin-diameter-sm;
- }
-
- &.user-avatar {
- top: 25px;
- right: 8px;
- }
-}
-
-.design-scaler-wrapper {
- bottom: 0;
- left: 50%;
- transform: translateX(-50%);
-}
-
-.image-notes {
- overflow-y: scroll;
- padding: $gl-padding;
- padding-top: 50px;
- background-color: var(--white, $white);
- flex-shrink: 0;
- min-width: 400px;
- flex-basis: 28%;
-
- .link-inherit-color {
- &:hover,
- &:active,
- &:focus {
- color: inherit;
- text-decoration: none;
- }
- }
-
- .toggle-comments {
- line-height: 20px;
- border-top: 1px solid var(--border-color, $border-color);
-
- &.expanded {
- border-bottom: 1px solid var(--border-color, $border-color);
- }
-
- .toggle-comments-button:focus {
- text-decoration: none;
- color: var(--blue-600, $blue-600);
- }
- }
-
- .design-note-pin {
- margin-left: $gl-padding;
- }
-
- .design-discussion {
- margin: $gl-padding 0;
-
- &::before {
- content: '';
- border-left: 1px solid var(--gray-100, $gray-100);
- position: absolute;
- left: 28px;
- top: -17px;
- height: 17px;
- }
-
- .design-note {
- padding: $gl-padding;
- list-style: none;
- transition: background $gl-transition-duration-medium $general-hover-transition-curve;
- border-top-left-radius: $border-radius-default; // same border radius used by .bordered-box
- border-top-right-radius: $border-radius-default;
-
- a {
- color: inherit;
- }
-
- .note-text a {
- color: var(--blue-600, $blue-600);
- }
- }
-
- .reply-wrapper {
- padding: $gl-padding;
- }
- }
-
- .reply-wrapper {
- border-top: 1px solid var(--border-color, $border-color);
- }
-
- .new-discussion-disclaimer {
- line-height: 20px;
- }
-}
-
-@media (max-width: map-get($grid-breakpoints, lg)) {
- .design-detail {
- overflow-y: scroll;
- }
-
- .image-notes {
- overflow-y: auto;
- min-width: 100%;
- flex-grow: 1;
- flex-basis: auto;
- }
-}
-
.is-ghost {
opacity: 0.3;
pointer-events: none;
diff --git a/app/assets/stylesheets/page_bundles/merge_requests.scss b/app/assets/stylesheets/page_bundles/merge_requests.scss
index b2fbce7cb4b..771428b49e0 100644
--- a/app/assets/stylesheets/page_bundles/merge_requests.scss
+++ b/app/assets/stylesheets/page_bundles/merge_requests.scss
@@ -269,7 +269,7 @@ $tabs-holder-z-index: 250;
position: -webkit-sticky;
position: sticky;
- top: var(--top-pos);
+ 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));
.drag-handle {
@@ -391,6 +391,10 @@ $tabs-holder-z-index: 250;
text-overflow: ellipsis;
min-width: 100px;
+ display: grid;
+ grid-template-columns: max-content minmax(0, max-content) max-content;
+ grid-gap: $gl-spacing-scale-2;
+
@include media-breakpoint-up(xs) {
min-width: 0;
max-width: 100%;
@@ -404,6 +408,7 @@ $tabs-holder-z-index: 250;
.deploy-heading,
.merge-train-position-indicator {
+ padding: $gl-padding-8;
@include media-breakpoint-up(md) {
padding: $gl-padding-8 $gl-padding;
}
@@ -476,6 +481,19 @@ $tabs-holder-z-index: 250;
border-radius: $border-radius-default;
background: var(--white, $white);
+ > .mr-widget-section {
+ > :first-child {
+ border-top-left-radius: $border-radius-default - 1px;
+ border-top-right-radius: $border-radius-default - 1px;
+ }
+
+ > :last-child,
+ .deploy-heading:last-child {
+ border-bottom-left-radius: $border-radius-default - 1px;
+ border-bottom-right-radius: $border-radius-default - 1px;
+ }
+ }
+
> .mr-widget-border-top:first-of-type {
border-top: 0;
}
@@ -637,7 +655,6 @@ $tabs-holder-z-index: 250;
word-break: break-all;
}
- .deploy-link,
.label-branch {
&.label-truncate {
// NOTE: This selector targets its children because some of the HTML comes from
@@ -808,6 +825,13 @@ $tabs-holder-z-index: 250;
.mr-widget-border-top {
border-top: 1px solid var(--border-color, $border-color);
+
+ &:last-child {
+ .report-block-container {
+ border-bottom-left-radius: $border-radius-default - 1px;
+ border-bottom-right-radius: $border-radius-default - 1px;
+ }
+ }
}
.mr-widget-extension {
@@ -875,9 +899,12 @@ $tabs-holder-z-index: 250;
}
.mr-widget-workflow {
- margin-top: $gl-padding;
position: relative;
+ &:not(:first-child) {
+ margin-top: $gl-padding;
+ }
+
&:not(:last-child)::before {
content: '';
border-left: 2px solid var(--gray-10, $gray-10);
@@ -1078,6 +1105,31 @@ $tabs-holder-z-index: 250;
border-top: 0;
}
+.mr-widget-status-icon-level-1::before {
+ @include gl-content-empty;
+ @include gl-absolute;
+ @include gl-left-0;
+ @include gl-top-0;
+ @include gl-bottom-0;
+ @include gl-right-0;
+ @include gl-opacity-3;
+ @include gl-rounded-full;
+ @include gl-border-solid;
+ @include gl-border-4;
+}
+
+.mr-widget-status-icon-level-1::after {
+ @include gl-content-empty;
+ @include gl-absolute;
+ @include gl-rounded-full;
+ @include gl-border-solid;
+ @include gl-border-4;
+ @include gl-left-2;
+ @include gl-right-2;
+ @include gl-top-2;
+ @include gl-bottom-2;
+}
+
.memory-graph-container {
background: var(--white, $white);
border: 1px solid var(--gray-100, $gray-100);
@@ -1154,3 +1206,19 @@ $tabs-holder-z-index: 250;
margin-bottom: 0;
}
}
+
+.commits ol:not(:last-of-type) {
+ margin-bottom: 0;
+}
+
+.mr-section-container {
+ .state-container-action-buttons {
+ @include media-breakpoint-up(md) {
+ flex-direction: row-reverse;
+
+ .btn {
+ margin-left: auto;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/page_bundles/notifications.scss b/app/assets/stylesheets/page_bundles/notifications.scss
new file mode 100644
index 00000000000..88437954f4c
--- /dev/null
+++ b/app/assets/stylesheets/page_bundles/notifications.scss
@@ -0,0 +1,31 @@
+@import 'mixins_and_variables_and_functions';
+
+.notification-list-item {
+ @include media-breakpoint-down(sm) {
+ .notification-dropdown {
+ width: 100%;
+ }
+
+ .btn-group {
+ width: 100%;
+ }
+
+ .table-section {
+ border-top: 0;
+ min-height: unset;
+
+ &:not(:first-child) {
+ padding-top: 0;
+ }
+ }
+
+ .update-notifications {
+ width: 100%;
+ }
+ }
+}
+
+.notification {
+ position: relative;
+ top: 1px;
+}
diff --git a/app/assets/stylesheets/pages/branches.scss b/app/assets/stylesheets/pages/branches.scss
deleted file mode 100644
index 18158fab75f..00000000000
--- a/app/assets/stylesheets/pages/branches.scss
+++ /dev/null
@@ -1,39 +0,0 @@
-.branch-info {
- flex: auto;
- min-width: 0;
- overflow: hidden;
-}
-
-.divergence-graph {
- $graph-side-width: 80px;
- $graph-separator-width: 1px;
-
- .graph-side {
- width: $graph-side-width;
-
- &.full {
- width: $graph-side-width * 2 + $graph-separator-width;
- }
-
- .bar {
- height: 4px;
- background-color: $gray-100;
- }
-
- .count {
- font-size: 12px;
- }
- }
-
- .graph-separator {
- width: $graph-separator-width;
- height: 18px;
- background-color: $gray-100;
- }
-}
-
-.divergence-graph,
-.branch-item .controls {
- flex: 0 0 auto;
- white-space: nowrap;
-}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 6070311dcb6..1b6e7954366 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -76,10 +76,6 @@
.btn-edit {
margin-left: auto;
}
-
- .emoji-block {
- padding: $gl-padding-4 0;
- }
}
.issuable-show-labels {
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index c88834c088f..c2ac4f32480 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -75,11 +75,6 @@ ul.related-merge-requests > li gl-emoji {
.merge-request,
.issue {
- &.today {
- background: $issues-today-bg;
- border-color: $issues-today-border;
- }
-
&.closed,
&.merged {
background: $gray-light;
@@ -123,9 +118,6 @@ ul.related-merge-requests > li gl-emoji {
}
.new-branch-col {
- @include gl-pb-3;
- @include gl-my-2;
-
.discussion-filter-container {
&:not(:last-child) {
margin-right: $gl-spacing-scale-3;
@@ -225,7 +217,7 @@ ul.related-merge-requests > li gl-emoji {
.new-branch-col {
@include gl-pb-0;
- align-self: center;
+ align-self: flex-end;
}
}
diff --git a/app/assets/stylesheets/pages/ml_experiment_tracking.scss b/app/assets/stylesheets/pages/ml_experiment_tracking.scss
new file mode 100644
index 00000000000..2dff51cff92
--- /dev/null
+++ b/app/assets/stylesheets/pages/ml_experiment_tracking.scss
@@ -0,0 +1,16 @@
+@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;
+ }
+}
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 438b7b1afa6..fa3c87490f1 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -6,7 +6,7 @@ $system-note-svg-size: 1rem;
content: '';
border-left: 2px solid var(--gray-10, $gray-10);
position: absolute;
- top: 0;
+ top: $gl-padding-6;
bottom: 0;
left: calc(#{$left} - 1px);
height: calc(100% + 1.5rem);
@@ -421,7 +421,7 @@ $system-note-svg-size: 1rem;
height: $system-note-icon-size;
border: 1px solid $gray-10;
border-radius: $system-note-icon-size;
- margin: -8px 0 0;
+ margin: -6px 0 0;
svg {
width: $system-note-svg-size;
@@ -968,7 +968,7 @@ $system-note-svg-size: 1rem;
height: 12px;
}
- &:hover,
+ &:hover:not([disabled]),
&.inverted {
&::before {
background-color: $white;
diff --git a/app/assets/stylesheets/pages/notifications.scss b/app/assets/stylesheets/pages/notifications.scss
deleted file mode 100644
index 2fd2757cf08..00000000000
--- a/app/assets/stylesheets/pages/notifications.scss
+++ /dev/null
@@ -1,29 +0,0 @@
-.notification-list-item {
- @include media-breakpoint-down(sm) {
- .notification-dropdown {
- width: 100%;
- }
-
- .btn-group {
- width: 100%;
- }
-
- .table-section {
- border-top: 0;
- min-height: unset;
-
- &:not(:first-child) {
- padding-top: 0;
- }
- }
-
- .update-notifications {
- width: 100%;
- }
- }
-}
-
-.notification {
- position: relative;
- top: 1px;
-}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index be8707dcd50..bf20204cfd9 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -277,139 +277,128 @@
.description p {
margin-bottom: 0;
color: $gl-text-color-secondary;
+ @include str-truncated(100%);
}
}
.projects-list {
@include basic-list;
- display: flex;
- flex-direction: column;
+ @include gl-display-table;
.project-row {
- @include basic-list-stats;
- display: flex;
- align-items: center;
- padding: $gl-padding-12 0;
+ @include gl-display-table-row;
}
- h2 {
- font-size: $gl-font-size;
- font-weight: $gl-font-weight-bold;
- margin-bottom: 0;
-
- @include media-breakpoint-up(sm) {
- .namespace-name {
- font-weight: $gl-font-weight-normal;
- }
- }
+ .project-cell {
+ @include gl-display-table-cell;
+ @include gl-border-b;
+ @include gl-vertical-align-top;
+ @include gl-py-4;
}
- .avatar-container {
- flex: 0 0 auto;
- align-self: flex-start;
+ .project-row:last-of-type {
+ .project-cell {
+ @include gl-border-none;
+ }
}
- .project-details {
- min-width: 0;
- line-height: $gl-line-height;
- .flex-wrapper {
- min-width: 0;
- margin-top: -$gl-padding-8; // negative margin required for flex-wrap
- flex: 1 1 100%;
+ &.admin-projects,
+ &.group-settings-projects {
+ .project-row {
+ @include basic-list-stats;
- .project-title {
- line-height: 20px;
+ .description > p {
+ @include gl-mb-0;
}
}
+ .controls {
+ @include gl-line-height-42;
+ }
+ }
+
+ .project-details {
+ max-width: 625px;
+
p,
.commit-row-message {
+ @include gl-mb-0;
@include str-truncated(100%);
- margin-bottom: 0;
- }
-
- .user-access-role {
- margin: 0;
}
.description {
line-height: 1.5;
- color: $gl-text-color-secondary;
- }
-
- @include media-breakpoint-down(md) {
- .user-access-role {
- line-height: $gl-line-height-14;
- }
+ max-height: $gl-spacing-scale-8;
}
}
.ci-status-link {
- display: inline-block;
- line-height: 17px;
- vertical-align: middle;
-
- &:hover {
- text-decoration: none;
- }
+ @include gl-text-decoration-none;
}
- .controls {
- @include media-breakpoint-down(xs) {
- margin-top: $gl-padding-8;
+ &:not(.compact) {
+ .controls {
+ @include media-breakpoint-up(lg) {
+ @include gl-justify-content-start;
+ @include gl-pr-9;
+
+ &:not(.with-pipeline-status) {
+ .icon-wrapper:first-of-type {
+ @include media-breakpoint-up(lg) {
+ @include gl-ml-7;
+ }
+ }
+ }
+ }
}
- @include media-breakpoint-up(sm) {
- margin-top: 0;
+ .project-details {
+ p,
+ .commit-row-message {
+ @include gl-white-space-normal;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ /* stylelint-disable-next-line value-no-vendor-prefix */
+ display: -webkit-box;
+ }
}
+ }
- @include media-breakpoint-up(lg) {
- flex: 1 1 40%;
+ .controls {
+ @include media-breakpoint-up(sm) {
+ @include gl-justify-content-end;
}
.icon-wrapper {
- color: inherit;
- margin-right: $gl-padding;
-
@include media-breakpoint-down(md) {
- margin-right: 0;
- margin-left: $gl-padding-8;
+ @include gl-mr-0;
+ @include gl-ml-3;
}
@include media-breakpoint-down(xs) {
&:first-child {
- margin-left: 0;
- }
- }
- }
-
- &:not(.with-pipeline-status) {
- .icon-wrapper:first-of-type {
- @include media-breakpoint-up(lg) {
- margin-left: $gl-padding-32;
+ @include gl-ml-0;
}
}
}
.ci-status-link {
- display: inline-flex;
+ @include gl-display-inline-flex;
}
}
.icon-container {
- @include media-breakpoint-down(xs) {
- margin-right: $gl-padding-8;
+ @include media-breakpoint-up(lg) {
+ margin-right: $gl-spacing-scale-7;
}
}
&.compact {
- .project-row {
- padding: $gl-padding 0;
- }
-
- h2 {
- font-size: $gl-font-size;
+ .description {
+ @include gl-w-full;
+ @include gl-display-table;
+ @include gl-table-layout-fixed;
}
.avatar-container {
@@ -422,27 +411,15 @@
}
}
- .controls {
- @include media-breakpoint-up(sm) {
- margin-top: 0;
- }
- }
-
.updated-note {
@include media-breakpoint-up(sm) {
- margin-top: $gl-padding-8;
+ @include gl-mt-2;
}
}
.icon-wrapper {
- margin-left: $gl-padding-8;
- margin-right: 0;
-
- @include media-breakpoint-down(xs) {
- &:first-child {
- margin-left: 0;
- }
- }
+ @include gl-ml-3;
+ @include gl-mr-0;
}
.user-access-role {
@@ -451,10 +428,6 @@
}
@include media-breakpoint-down(md) {
- h2 {
- font-size: $gl-font-size;
- }
-
.avatar-container {
@include avatar-size(40px, 10px);
min-height: 40px;
@@ -468,24 +441,18 @@
@include media-breakpoint-down(md) {
.updated-note {
- margin-top: $gl-padding-8;
- text-align: right;
+ @include gl-mt-3;
+ @include gl-text-right;
}
}
.forks,
.pipeline-status,
.updated-note {
- display: flex;
+ @include gl-display-flex;
}
@include media-breakpoint-down(md) {
- &:not(.explore) {
- .forks {
- display: none;
- }
- }
-
&.explore {
.pipeline-status,
.updated-note {
@@ -496,8 +463,8 @@
@include media-breakpoint-down(xs) {
.updated-note {
- margin-top: 0;
- text-align: left;
+ @include gl-mt-0;
+ @include gl-text-left;
}
}
}
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index a8027d2a5f5..1bca04e5eb1 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -52,13 +52,6 @@ input[type='checkbox']:hover {
.global-search-container {
flex-grow: 1;
}
-
- @include media-breakpoint-down(lg) {
- .title-container {
- flex: 0;
- overflow: hidden;
- }
- }
}
}
diff --git a/app/assets/stylesheets/startup/startup-dark.scss b/app/assets/stylesheets/startup/startup-dark.scss
index 32c3ce1ba8c..11131cc1a4b 100644
--- a/app/assets/stylesheets/startup/startup-dark.scss
+++ b/app/assets/stylesheets/startup/startup-dark.scss
@@ -6,15 +6,15 @@
color-scheme: dark;
}
body.gl-dark {
- --gray-10: #1f1f1f;
- --gray-50: #303030;
- --gray-100: #404040;
- --gray-200: #525252;
- --gray-700: #dbdbdb;
- --gray-900: #fafafa;
+ --gray-10: #1f1e24;
+ --gray-50: #333238;
+ --gray-100: #434248;
+ --gray-200: #535158;
+ --gray-700: #bfbfc3;
+ --gray-900: #ececef;
--green-100: #0d532a;
--green-700: #91d4a8;
- --gl-text-color: #fafafa;
+ --gl-text-color: #ececef;
--border-color: #4f4f4f;
--black: #fff;
}
@@ -42,9 +42,9 @@ body {
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
- color: #fafafa;
+ color: #ececef;
text-align: left;
- background-color: #1f1f1f;
+ background-color: #1f1e24;
}
ul {
margin-top: 0;
@@ -118,7 +118,7 @@ kbd {
padding: 0.2rem 0.4rem;
font-size: 90%;
color: #333;
- background-color: #fafafa;
+ background-color: #ececef;
border-radius: 0.2rem;
}
kbd kbd {
@@ -141,24 +141,24 @@ kbd kbd {
font-size: 0.875rem;
font-weight: 400;
line-height: 1.5;
- color: #fafafa;
+ color: #ececef;
background-color: #333;
background-clip: padding-box;
- border: 1px solid #868686;
+ border: 1px solid #737278;
border-radius: 0.25rem;
}
@media (prefers-reduced-motion: reduce) {
}
.form-control:-moz-focusring {
color: transparent;
- text-shadow: 0 0 0 #fafafa;
+ text-shadow: 0 0 0 #ececef;
}
.form-control::placeholder {
- color: #bfbfbf;
+ color: #a4a3a8;
opacity: 1;
}
.form-control:disabled {
- background-color: #303030;
+ background-color: #333238;
opacity: 1;
}
.form-inline {
@@ -176,7 +176,7 @@ kbd kbd {
.btn {
display: inline-block;
font-weight: 400;
- color: #fafafa;
+ color: #ececef;
text-align: center;
vertical-align: middle;
user-select: none;
@@ -212,7 +212,7 @@ kbd kbd {
padding: 0.5rem 0;
margin: 0.125rem 0 0;
font-size: 1rem;
- color: #fafafa;
+ color: #ececef;
text-align: left;
list-style: none;
background-color: #333;
@@ -319,15 +319,15 @@ kbd kbd {
border-radius: 10rem;
}
.badge-success {
- color: #fff;
+ color: #fbfafd;
background-color: #2da160;
}
.badge-info {
- color: #fff;
+ color: #fbfafd;
background-color: #428fdc;
}
.badge-warning {
- color: #fff;
+ color: #fbfafd;
background-color: #c17d10;
}
.rounded-circle {
@@ -371,7 +371,7 @@ kbd kbd {
.gl-avatar {
border-width: 1px;
border-style: solid;
- border-color: rgba(0, 0, 0, 0.08);
+ border-color: rgba(251, 250, 253, 0.08);
overflow: hidden;
flex-shrink: 0;
}
@@ -455,8 +455,8 @@ a.gl-badge.badge-warning:active {
padding-left: 0.75rem;
padding-right: 0.75rem;
height: auto;
- color: #fafafa;
- box-shadow: inset 0 0 0 1px #868686;
+ color: #ececef;
+ box-shadow: inset 0 0 0 1px #737278;
border-style: none;
appearance: none;
-moz-appearance: none;
@@ -465,17 +465,17 @@ a.gl-badge.badge-warning:active {
.gl-form-input:not(.form-control-plaintext):not([type="color"]):read-only,
.gl-form-input.form-control:disabled,
.gl-form-input.form-control:not(.form-control-plaintext):not([type="color"]):read-only {
- background-color: #1f1f1f;
- box-shadow: inset 0 0 0 1px #404040;
+ background-color: #1f1e24;
+ box-shadow: inset 0 0 0 1px #434248;
}
.gl-form-input:disabled,
.gl-form-input.form-control:disabled {
cursor: not-allowed;
- color: #999;
+ color: #89888d;
}
.gl-form-input::placeholder,
.gl-form-input.form-control::placeholder {
- color: #868686;
+ color: #737278;
}
.gl-icon {
fill: currentColor;
@@ -518,9 +518,9 @@ a.gl-badge.badge-warning:active {
padding-right: 0.75rem;
background-color: transparent;
line-height: 1rem;
- color: #fafafa;
+ color: #ececef;
fill: currentColor;
- box-shadow: inset 0 0 0 1px #525252;
+ box-shadow: inset 0 0 0 1px #535158;
justify-content: center;
align-items: center;
font-size: 0.875rem;
@@ -531,20 +531,20 @@ a.gl-badge.badge-warning:active {
}
.gl-button.gl-button.btn-default:active,
.gl-button.gl-button.btn-default.active {
- box-shadow: inset 0 0 0 1px #bfbfbf, 0 0 0 1px #333, 0 0 0 3px #1f75cb;
+ box-shadow: inset 0 0 0 1px #a4a3a8, 0 0 0 1px #333, 0 0 0 3px #1f75cb;
outline: none;
- background-color: #404040;
+ background-color: #434248;
}
.gl-button.gl-button.btn-default:active .gl-icon,
.gl-button.gl-button.btn-default.active .gl-icon {
- color: #fafafa;
+ color: #ececef;
}
.gl-button.gl-button.btn-default .gl-icon {
- color: #999;
+ color: #89888d;
}
.gl-search-box-by-type-search-icon {
margin: 0.5rem;
- color: #999;
+ color: #89888d;
width: 1rem;
position: absolute;
}
@@ -594,35 +594,40 @@ svg {
height: 0;
margin: 4px 0;
overflow: hidden;
- border-top: 1px solid #404040;
+ border-top: 1px solid #434248;
}
.toggle-sidebar-button .collapse-text,
.toggle-sidebar-button .icon-chevron-double-lg-left {
- color: #999;
+ color: #89888d;
}
html {
overflow-y: scroll;
}
+@media (min-width: 576px) {
+ .logged-out-marketing-header {
+ --header-height: 72px;
+ }
+}
.btn {
border-radius: 4px;
font-size: 0.875rem;
font-weight: 400;
padding: 6px 10px;
background-color: #333;
- border-color: #404040;
- color: #fafafa;
- color: #fafafa;
+ border-color: #434248;
+ color: #ececef;
+ color: #ececef;
white-space: nowrap;
}
.btn:active {
- background-color: #303030;
+ background-color: #333238;
box-shadow: none;
}
.btn:active,
.btn.active {
background-color: #444;
border-color: #4f4f4f;
- color: #fafafa;
+ color: #ececef;
}
.btn svg {
height: 15px;
@@ -634,7 +639,7 @@ html {
.badge.badge-pill:not(.gl-badge) {
font-weight: 400;
background-color: rgba(255, 255, 255, 0.07);
- color: #dbdbdb;
+ color: #bfbfc3;
vertical-align: baseline;
}
.gl-font-sm {
@@ -653,10 +658,10 @@ html {
.dropdown-menu-toggle {
padding: 6px 8px 6px 10px;
background-color: #333;
- color: #fafafa;
+ color: #ececef;
font-size: 14px;
text-align: left;
- border: 1px solid #404040;
+ border: 1px solid #434248;
border-radius: 0.25rem;
white-space: nowrap;
}
@@ -685,7 +690,7 @@ html {
font-weight: 400;
padding: 8px 0;
background-color: #333;
- border: 1px solid #404040;
+ border: 1px solid #434248;
border-radius: 0.25rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
@@ -708,7 +713,7 @@ html {
font-weight: 400;
position: relative;
padding: 8px 12px;
- color: #fafafa;
+ color: #ececef;
line-height: 16px;
white-space: normal;
overflow: hidden;
@@ -718,7 +723,7 @@ html {
.dropdown-menu li > a:active,
.dropdown-menu li button:active {
background-color: #4f4f4f;
- color: #fafafa;
+ color: #ececef;
outline: 0;
text-decoration: none;
}
@@ -732,7 +737,7 @@ html {
height: 1px;
margin: 0.25rem 0;
padding: 0;
- background-color: #404040;
+ background-color: #434248;
}
.dropdown-menu .badge.badge-pill + span:not(.badge):not(.badge-pill) {
margin-right: 40px;
@@ -759,7 +764,7 @@ html {
}
input {
border-radius: 0.25rem;
- color: #fafafa;
+ color: #ececef;
background-color: #333;
}
.form-control {
@@ -767,23 +772,23 @@ input {
padding: 6px 10px;
}
.form-control::placeholder {
- color: #868686;
+ color: #737278;
}
kbd {
display: inline-block;
padding: 3px 5px;
font-size: 0.6875rem;
line-height: 10px;
- color: var(--gray-700, #dbdbdb);
+ color: var(--gray-700, #bfbfc3);
vertical-align: middle;
- background-color: var(--gray-10, #1f1f1f);
+ background-color: var(--gray-10, #1f1e24);
border-width: 1px;
border-style: solid;
- border-color: var(--gray-100, #404040) var(--gray-100, #404040)
- var(--gray-200, #525252);
+ border-color: var(--gray-100, #434248) var(--gray-100, #434248)
+ var(--gray-200, #535158);
border-image: none;
border-radius: 3px;
- box-shadow: 0 -1px 0 var(--gray-200, #525252) inset;
+ box-shadow: 0 -1px 0 var(--gray-200, #535158) inset;
}
.navbar-gitlab {
padding: 0 16px;
@@ -1037,7 +1042,7 @@ kbd {
width: 100%;
align-items: center;
padding: 10px 16px 10px 10px;
- color: #fafafa;
+ color: #ececef;
background-color: transparent;
border: 0;
text-align: left;
@@ -1049,7 +1054,7 @@ kbd {
.context-header .sidebar-context-title {
overflow: hidden;
text-overflow: ellipsis;
- color: #fafafa;
+ color: #ececef;
}
@media (min-width: 768px) {
.page-with-contextual-sidebar {
@@ -1073,7 +1078,7 @@ kbd {
z-index: 600;
width: 256px;
top: var(--header-height, 48px);
- background-color: #f5f5f5;
+ background-color: #1f1e24;
border-right: 1px solid #e9e9e9;
transform: translate3d(0, 0, 0);
}
@@ -1110,7 +1115,7 @@ kbd {
}
.nav-sidebar a {
text-decoration: none;
- color: #fafafa;
+ color: #ececef;
}
.nav-sidebar li {
white-space: nowrap;
@@ -1395,7 +1400,7 @@ kbd {
display: block;
}
.sidebar-top-level-items li > a.gl-link {
- color: #fafafa;
+ color: #ececef;
}
.sidebar-top-level-items li > a.gl-link:active {
text-decoration: none;
@@ -1412,12 +1417,12 @@ kbd {
.close-nav-button {
height: 48px;
padding: 0 16px;
- background-color: #303030;
+ background-color: #333238;
border: 0;
- color: #999;
+ color: #89888d;
display: flex;
align-items: center;
- background-color: #f5f5f5;
+ background-color: #1f1e24;
position: fixed;
bottom: 0;
width: 255px;
@@ -1488,14 +1493,14 @@ kbd {
}
}
input::-moz-placeholder {
- color: #868686;
+ color: #737278;
opacity: 1;
}
input::-ms-input-placeholder {
- color: #868686;
+ color: #737278;
}
input:-ms-input-placeholder {
- color: #868686;
+ color: #737278;
}
svg {
fill: currentColor;
@@ -1624,7 +1629,7 @@ svg.s16 {
padding: 0;
background: #222;
overflow: hidden;
- box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
+ box-shadow: inset 0 0 0 1px rgba(251, 250, 253, 0.1);
}
.avatar.avatar-tile {
border-radius: 0;
@@ -1633,8 +1638,8 @@ svg.s16 {
.identicon {
text-align: center;
vertical-align: top;
- color: #fafafa;
- background-color: #303030;
+ color: #ececef;
+ background-color: #333238;
}
.identicon.s16 {
font-size: 10px;
@@ -1663,7 +1668,7 @@ svg.s16 {
background-color: #5c2900;
}
.identicon.bg7 {
- background-color: #303030;
+ background-color: #333238;
}
.avatar-container {
overflow: hidden;
@@ -1702,18 +1707,18 @@ svg.s16 {
color-scheme: dark;
}
body.gl-dark {
- --gray-10: #1f1f1f;
- --gray-50: #303030;
- --gray-100: #404040;
- --gray-200: #525252;
- --gray-300: #5e5e5e;
- --gray-400: #868686;
- --gray-500: #999;
- --gray-600: #bfbfbf;
- --gray-700: #dbdbdb;
- --gray-800: #f0f0f0;
- --gray-900: #fafafa;
- --gray-950: #fff;
+ --gray-10: #1f1e24;
+ --gray-50: #333238;
+ --gray-100: #434248;
+ --gray-200: #535158;
+ --gray-300: #626168;
+ --gray-400: #737278;
+ --gray-500: #89888d;
+ --gray-600: #a4a3a8;
+ --gray-700: #bfbfc3;
+ --gray-800: #dcdcde;
+ --gray-900: #ececef;
+ --gray-950: #fbfafd;
--green-50: #0a4020;
--green-100: #0d532a;
--green-200: #24663b;
@@ -1785,58 +1790,59 @@ body.gl-dark {
--dark-icon-color-purple-3: #9a79f7;
--dark-icon-color-orange-1: #665349;
--dark-icon-color-orange-2: #b37a5d;
- --gl-text-color: #fafafa;
+ --gl-text-color: #ececef;
--border-color: #4f4f4f;
--white: #333;
--black: #fff;
+ --gray-light: #333238;
--svg-status-bg: #333;
}
.nav-sidebar,
.toggle-sidebar-button,
.close-nav-button {
- background-color: #262626;
- border-right: 1px solid #303030;
+ background-color: #29282d;
+ border-right: 1px solid #333238;
}
.gl-avatar:not(.gl-avatar-identicon),
.avatar-container,
.avatar {
- background: rgba(255, 255, 255, 0.04);
+ background: rgba(251, 250, 253, 0.04);
}
.gl-avatar {
border-style: none;
- box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
+ box-shadow: inset 0 0 0 1px rgba(251, 250, 253, 0.1);
}
body.gl-dark {
- --gl-theme-accent: #868686;
+ --gl-theme-accent: #737278;
}
body.gl-dark .navbar-gitlab {
- background-color: #fafafa;
+ background-color: #ececef;
}
body.gl-dark .navbar-gitlab .navbar-collapse {
- color: #fafafa;
+ color: #ececef;
}
body.gl-dark .navbar-gitlab .container-fluid .navbar-toggler {
- border-left: 1px solid #b3b3b3;
- color: #fafafa;
+ border-left: 1px solid #a3a2a6;
+ color: #ececef;
}
body.gl-dark .navbar-gitlab .navbar-sub-nav > li.active > a,
body.gl-dark .navbar-gitlab .navbar-sub-nav > li.active > button,
body.gl-dark .navbar-gitlab .navbar-nav > li.active > a,
body.gl-dark .navbar-gitlab .navbar-nav > li.active > button {
- color: #fafafa;
+ color: #ececef;
background-color: #333;
}
body.gl-dark .navbar-gitlab .navbar-sub-nav {
- color: #fafafa;
+ color: #ececef;
}
body.gl-dark .navbar-gitlab .nav > li {
- color: #fafafa;
+ color: #ececef;
}
body.gl-dark .navbar-gitlab .nav > li.header-search-new {
- color: #fafafa;
+ color: #ececef;
}
body.gl-dark .navbar-gitlab .nav > li > a .notification-dot {
- border: 2px solid #fafafa;
+ border: 2px solid #ececef;
}
body.gl-dark
.navbar-gitlab
@@ -1844,7 +1850,7 @@ body.gl-dark
> li
> a.header-help-dropdown-toggle
.notification-dot {
- background-color: #fafafa;
+ background-color: #ececef;
}
body.gl-dark
.navbar-gitlab
@@ -1852,10 +1858,10 @@ body.gl-dark
> li
> a.header-user-dropdown-toggle
.header-user-avatar {
- border-color: #fafafa;
+ border-color: #ececef;
}
body.gl-dark .navbar-gitlab .nav > li.active > a {
- color: #fafafa;
+ color: #ececef;
background-color: #333;
}
body.gl-dark .navbar-gitlab .nav > li.active > a .notification-dot {
@@ -1867,48 +1873,48 @@ body.gl-dark
> li.active
> a.header-help-dropdown-toggle
.notification-dot {
- background-color: #fafafa;
+ background-color: #ececef;
}
body.gl-dark .header-search {
- background-color: rgba(250, 250, 250, 0.2) !important;
+ background-color: rgba(236, 236, 239, 0.2) !important;
border-radius: 4px;
}
body.gl-dark .header-search svg.gl-search-box-by-type-search-icon {
- color: rgba(250, 250, 250, 0.8);
+ color: rgba(236, 236, 239, 0.8);
}
body.gl-dark .header-search input {
background-color: transparent;
- color: rgba(250, 250, 250, 0.8);
- box-shadow: inset 0 0 0 1px rgba(250, 250, 250, 0.4);
+ color: rgba(236, 236, 239, 0.8);
+ box-shadow: inset 0 0 0 1px rgba(236, 236, 239, 0.4);
}
body.gl-dark .header-search input::placeholder {
- color: rgba(250, 250, 250, 0.8);
+ color: rgba(236, 236, 239, 0.8);
}
body.gl-dark .header-search input:active::placeholder {
- color: #868686;
+ color: #737278;
}
body.gl-dark .header-search .keyboard-shortcut-helper {
- color: #fafafa;
- background-color: rgba(250, 250, 250, 0.2);
+ color: #ececef;
+ background-color: rgba(236, 236, 239, 0.2);
}
body.gl-dark .search form {
- background-color: rgba(250, 250, 250, 0.2);
+ background-color: rgba(236, 236, 239, 0.2);
}
body.gl-dark .search .search-input::placeholder {
- color: rgba(250, 250, 250, 0.8);
+ color: rgba(236, 236, 239, 0.8);
}
body.gl-dark .search .search-input-wrap .search-icon,
body.gl-dark .search .search-input-wrap .clear-icon {
- fill: rgba(250, 250, 250, 0.8);
+ fill: rgba(236, 236, 239, 0.8);
}
body.gl-dark .nav-sidebar li.active > a {
- color: #fafafa;
+ color: #ececef;
}
body.gl-dark .nav-sidebar .fly-out-top-item a,
body.gl-dark .nav-sidebar .fly-out-top-item.active a,
body.gl-dark .nav-sidebar .fly-out-top-item .fly-out-top-item-container {
- background-color: var(--gray-100, #303030);
- color: var(--gray-900, #fafafa);
+ background-color: var(--gray-100, #333238);
+ color: var(--gray-900, #ececef);
}
body.gl-dark .navbar-gitlab {
background-color: var(--gray-50);
@@ -1945,18 +1951,18 @@ body.gl-dark .navbar-gitlab .search form .search-input {
color-scheme: dark;
}
body.gl-dark {
- --gray-10: #1f1f1f;
- --gray-50: #303030;
- --gray-100: #404040;
- --gray-200: #525252;
- --gray-300: #5e5e5e;
- --gray-400: #868686;
- --gray-500: #999;
- --gray-600: #bfbfbf;
- --gray-700: #dbdbdb;
- --gray-800: #f0f0f0;
- --gray-900: #fafafa;
- --gray-950: #fff;
+ --gray-10: #1f1e24;
+ --gray-50: #333238;
+ --gray-100: #434248;
+ --gray-200: #535158;
+ --gray-300: #626168;
+ --gray-400: #737278;
+ --gray-500: #89888d;
+ --gray-600: #a4a3a8;
+ --gray-700: #bfbfc3;
+ --gray-800: #dcdcde;
+ --gray-900: #ececef;
+ --gray-950: #fbfafd;
--green-50: #0a4020;
--green-100: #0d532a;
--green-200: #24663b;
@@ -2028,10 +2034,11 @@ body.gl-dark {
--dark-icon-color-purple-3: #9a79f7;
--dark-icon-color-orange-1: #665349;
--dark-icon-color-orange-2: #b37a5d;
- --gl-text-color: #fafafa;
+ --gl-text-color: #ececef;
--border-color: #4f4f4f;
--white: #333;
--black: #fff;
+ --gray-light: #333238;
--svg-status-bg: #333;
}
.tab-width-8 {
@@ -2054,9 +2061,19 @@ body.gl-dark {
.gl-display-none {
display: none;
}
+@media (min-width: 576px) {
+ .gl-sm-display-none {
+ display: none;
+ }
+}
.gl-display-flex {
display: flex;
}
+@media (min-width: 992px) {
+ .gl-lg-display-flex {
+ display: flex;
+ }
+}
@media (min-width: 576px) {
.gl-sm-display-block {
display: block;
@@ -2067,9 +2084,6 @@ body.gl-dark {
display: block;
}
}
-.gl-display-inline-block\! {
- display: inline-block !important;
-}
.gl-align-items-center {
align-items: center;
}
diff --git a/app/assets/stylesheets/startup/startup-general.scss b/app/assets/stylesheets/startup/startup-general.scss
index 61a2ce8dd62..7fb373bb6f4 100644
--- a/app/assets/stylesheets/startup/startup-general.scss
+++ b/app/assets/stylesheets/startup/startup-general.scss
@@ -23,7 +23,7 @@ body {
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
- color: #303030;
+ color: #333238;
text-align: left;
background-color: #fff;
}
@@ -99,7 +99,7 @@ kbd {
padding: 0.2rem 0.4rem;
font-size: 90%;
color: #fff;
- background-color: #303030;
+ background-color: #333238;
border-radius: 0.2rem;
}
kbd kbd {
@@ -122,24 +122,24 @@ kbd kbd {
font-size: 0.875rem;
font-weight: 400;
line-height: 1.5;
- color: #303030;
+ color: #333238;
background-color: #fff;
background-clip: padding-box;
- border: 1px solid #868686;
+ border: 1px solid #89888d;
border-radius: 0.25rem;
}
@media (prefers-reduced-motion: reduce) {
}
.form-control:-moz-focusring {
color: transparent;
- text-shadow: 0 0 0 #303030;
+ text-shadow: 0 0 0 #333238;
}
.form-control::placeholder {
- color: #5e5e5e;
+ color: #626168;
opacity: 1;
}
.form-control:disabled {
- background-color: #fafafa;
+ background-color: #fbfafd;
opacity: 1;
}
.form-inline {
@@ -157,7 +157,7 @@ kbd kbd {
.btn {
display: inline-block;
font-weight: 400;
- color: #303030;
+ color: #333238;
text-align: center;
vertical-align: middle;
user-select: none;
@@ -193,7 +193,7 @@ kbd kbd {
padding: 0.5rem 0;
margin: 0.125rem 0 0;
font-size: 1rem;
- color: #303030;
+ color: #333238;
text-align: left;
list-style: none;
background-color: #fff;
@@ -352,7 +352,7 @@ kbd kbd {
.gl-avatar {
border-width: 1px;
border-style: solid;
- border-color: rgba(0, 0, 0, 0.08);
+ border-color: rgba(31, 30, 36, 0.08);
overflow: hidden;
flex-shrink: 0;
}
@@ -436,8 +436,8 @@ a.gl-badge.badge-warning:active {
padding-left: 0.75rem;
padding-right: 0.75rem;
height: auto;
- color: #303030;
- box-shadow: inset 0 0 0 1px #868686;
+ color: #333238;
+ box-shadow: inset 0 0 0 1px #89888d;
border-style: none;
appearance: none;
-moz-appearance: none;
@@ -446,17 +446,17 @@ a.gl-badge.badge-warning:active {
.gl-form-input:not(.form-control-plaintext):not([type="color"]):read-only,
.gl-form-input.form-control:disabled,
.gl-form-input.form-control:not(.form-control-plaintext):not([type="color"]):read-only {
- background-color: #f5f5f5;
- box-shadow: inset 0 0 0 1px #dbdbdb;
+ background-color: #fbfafd;
+ box-shadow: inset 0 0 0 1px #dcdcde;
}
.gl-form-input:disabled,
.gl-form-input.form-control:disabled {
cursor: not-allowed;
- color: #666;
+ color: #737278;
}
.gl-form-input::placeholder,
.gl-form-input.form-control::placeholder {
- color: #868686;
+ color: #89888d;
}
.gl-icon {
fill: currentColor;
@@ -499,9 +499,9 @@ a.gl-badge.badge-warning:active {
padding-right: 0.75rem;
background-color: transparent;
line-height: 1rem;
- color: #303030;
+ color: #333238;
fill: currentColor;
- box-shadow: inset 0 0 0 1px #bfbfbf;
+ box-shadow: inset 0 0 0 1px #bfbfc3;
justify-content: center;
align-items: center;
font-size: 0.875rem;
@@ -512,20 +512,20 @@ a.gl-badge.badge-warning:active {
}
.gl-button.gl-button.btn-default:active,
.gl-button.gl-button.btn-default.active {
- box-shadow: inset 0 0 0 1px #5e5e5e, 0 0 0 1px #fff, 0 0 0 3px #428fdc;
+ box-shadow: inset 0 0 0 1px #626168, 0 0 0 1px #fff, 0 0 0 3px #428fdc;
outline: none;
- background-color: #dbdbdb;
+ background-color: #dcdcde;
}
.gl-button.gl-button.btn-default:active .gl-icon,
.gl-button.gl-button.btn-default.active .gl-icon {
- color: #303030;
+ color: #333238;
}
.gl-button.gl-button.btn-default .gl-icon {
- color: #666;
+ color: #737278;
}
.gl-search-box-by-type-search-icon {
margin: 0.5rem;
- color: #666;
+ color: #737278;
width: 1rem;
position: absolute;
}
@@ -575,35 +575,40 @@ svg {
height: 0;
margin: 4px 0;
overflow: hidden;
- border-top: 1px solid #dbdbdb;
+ border-top: 1px solid #dcdcde;
}
.toggle-sidebar-button .collapse-text,
.toggle-sidebar-button .icon-chevron-double-lg-left {
- color: #666;
+ color: #737278;
}
html {
overflow-y: scroll;
}
+@media (min-width: 576px) {
+ .logged-out-marketing-header {
+ --header-height: 72px;
+ }
+}
.btn {
border-radius: 4px;
font-size: 0.875rem;
font-weight: 400;
padding: 6px 10px;
background-color: #fff;
- border-color: #dbdbdb;
- color: #303030;
- color: #303030;
+ border-color: #dcdcde;
+ color: #333238;
+ color: #333238;
white-space: nowrap;
}
.btn:active {
- background-color: #f0f0f0;
+ background-color: #ececef;
box-shadow: none;
}
.btn:active,
.btn.active {
background-color: #eaeaea;
border-color: #e3e3e3;
- color: #303030;
+ color: #333238;
}
.btn svg {
height: 15px;
@@ -615,7 +620,7 @@ html {
.badge.badge-pill:not(.gl-badge) {
font-weight: 400;
background-color: rgba(0, 0, 0, 0.07);
- color: #525252;
+ color: #535158;
vertical-align: baseline;
}
.gl-font-sm {
@@ -634,10 +639,10 @@ html {
.dropdown-menu-toggle {
padding: 6px 8px 6px 10px;
background-color: #fff;
- color: #303030;
+ color: #333238;
font-size: 14px;
text-align: left;
- border: 1px solid #dbdbdb;
+ border: 1px solid #dcdcde;
border-radius: 0.25rem;
white-space: nowrap;
}
@@ -666,7 +671,7 @@ html {
font-weight: 400;
padding: 8px 0;
background-color: #fff;
- border: 1px solid #dbdbdb;
+ border: 1px solid #dcdcde;
border-radius: 0.25rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
@@ -689,7 +694,7 @@ html {
font-weight: 400;
position: relative;
padding: 8px 12px;
- color: #303030;
+ color: #333238;
line-height: 16px;
white-space: normal;
overflow: hidden;
@@ -698,8 +703,8 @@ html {
}
.dropdown-menu li > a:active,
.dropdown-menu li button:active {
- background-color: #eee;
- color: #303030;
+ background-color: #ececef;
+ color: #333238;
outline: 0;
text-decoration: none;
}
@@ -713,7 +718,7 @@ html {
height: 1px;
margin: 0.25rem 0;
padding: 0;
- background-color: #dbdbdb;
+ background-color: #dcdcde;
}
.dropdown-menu .badge.badge-pill + span:not(.badge):not(.badge-pill) {
margin-right: 40px;
@@ -740,7 +745,7 @@ html {
}
input {
border-radius: 0.25rem;
- color: #303030;
+ color: #333238;
background-color: #fff;
}
.form-control {
@@ -748,23 +753,23 @@ input {
padding: 6px 10px;
}
.form-control::placeholder {
- color: #868686;
+ color: #89888d;
}
kbd {
display: inline-block;
padding: 3px 5px;
font-size: 0.6875rem;
line-height: 10px;
- color: var(--gray-700, #525252);
+ color: var(--gray-700, #535158);
vertical-align: middle;
- background-color: var(--gray-10, #f5f5f5);
+ background-color: var(--gray-10, #fbfafd);
border-width: 1px;
border-style: solid;
- border-color: var(--gray-100, #dbdbdb) var(--gray-100, #dbdbdb)
- var(--gray-200, #bfbfbf);
+ border-color: var(--gray-100, #dcdcde) var(--gray-100, #dcdcde)
+ var(--gray-200, #bfbfc3);
border-image: none;
border-radius: 3px;
- box-shadow: 0 -1px 0 var(--gray-200, #bfbfbf) inset;
+ box-shadow: 0 -1px 0 var(--gray-200, #bfbfc3) inset;
}
.navbar-gitlab {
padding: 0 16px;
@@ -986,7 +991,7 @@ kbd {
float: left;
margin-right: 5px;
border-radius: 50%;
- border: 1px solid #f5f5f5;
+ border: 1px solid #f2f2f4;
}
.notification-dot {
background-color: #d99530;
@@ -1018,7 +1023,7 @@ kbd {
width: 100%;
align-items: center;
padding: 10px 16px 10px 10px;
- color: #303030;
+ color: #333238;
background-color: transparent;
border: 0;
text-align: left;
@@ -1030,7 +1035,7 @@ kbd {
.context-header .sidebar-context-title {
overflow: hidden;
text-overflow: ellipsis;
- color: #303030;
+ color: #333238;
}
@media (min-width: 768px) {
.page-with-contextual-sidebar {
@@ -1054,7 +1059,7 @@ kbd {
z-index: 600;
width: 256px;
top: var(--header-height, 48px);
- background-color: #f5f5f5;
+ background-color: #fbfafd;
border-right: 1px solid #e9e9e9;
transform: translate3d(0, 0, 0);
}
@@ -1091,7 +1096,7 @@ kbd {
}
.nav-sidebar a {
text-decoration: none;
- color: #303030;
+ color: #333238;
}
.nav-sidebar li {
white-space: nowrap;
@@ -1376,7 +1381,7 @@ kbd {
display: block;
}
.sidebar-top-level-items li > a.gl-link {
- color: #303030;
+ color: #333238;
}
.sidebar-top-level-items li > a.gl-link:active {
text-decoration: none;
@@ -1393,12 +1398,12 @@ kbd {
.close-nav-button {
height: 48px;
padding: 0 16px;
- background-color: #fafafa;
+ background-color: #fbfafd;
border: 0;
- color: #666;
+ color: #737278;
display: flex;
align-items: center;
- background-color: #f5f5f5;
+ background-color: #fbfafd;
position: fixed;
bottom: 0;
width: 255px;
@@ -1469,14 +1474,14 @@ kbd {
}
}
input::-moz-placeholder {
- color: #868686;
+ color: #89888d;
opacity: 1;
}
input::-ms-input-placeholder {
- color: #868686;
+ color: #89888d;
}
input:-ms-input-placeholder {
- color: #868686;
+ color: #89888d;
}
svg {
fill: currentColor;
@@ -1603,9 +1608,9 @@ svg.s16 {
width: 40px;
height: 40px;
padding: 0;
- background: #fdfdfd;
+ background: #fefefe;
overflow: hidden;
- box-shadow: inset 0 0 0 1px rgba(31, 31, 31, 0.1);
+ box-shadow: inset 0 0 0 1px rgba(31, 30, 36, 0.1);
}
.avatar.avatar-tile {
border-radius: 0;
@@ -1614,8 +1619,8 @@ svg.s16 {
.identicon {
text-align: center;
vertical-align: top;
- color: #303030;
- background-color: #f0f0f0;
+ color: #333238;
+ background-color: #ececef;
}
.identicon.s16 {
font-size: 10px;
@@ -1644,7 +1649,7 @@ svg.s16 {
background-color: #fdf1dd;
}
.identicon.bg7 {
- background-color: #f0f0f0;
+ background-color: #ececef;
}
.avatar-container {
overflow: hidden;
@@ -1700,9 +1705,19 @@ svg.s16 {
.gl-display-none {
display: none;
}
+@media (min-width: 576px) {
+ .gl-sm-display-none {
+ display: none;
+ }
+}
.gl-display-flex {
display: flex;
}
+@media (min-width: 992px) {
+ .gl-lg-display-flex {
+ display: flex;
+ }
+}
@media (min-width: 576px) {
.gl-sm-display-block {
display: block;
@@ -1713,9 +1728,6 @@ svg.s16 {
display: block;
}
}
-.gl-display-inline-block\! {
- display: inline-block !important;
-}
.gl-align-items-center {
align-items: center;
}
diff --git a/app/assets/stylesheets/startup/startup-signin.scss b/app/assets/stylesheets/startup/startup-signin.scss
index 33e10b9bd62..7ae158b3930 100644
--- a/app/assets/stylesheets/startup/startup-signin.scss
+++ b/app/assets/stylesheets/startup/startup-signin.scss
@@ -22,7 +22,7 @@ body {
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
- color: #303030;
+ color: #333238;
text-align: left;
background-color: #fff;
}
@@ -110,7 +110,7 @@ h3 {
margin-bottom: 0.25rem;
font-weight: 600;
line-height: 1.2;
- color: #303030;
+ color: #333238;
}
h1 {
font-size: 2.1875rem;
@@ -196,24 +196,24 @@ hr {
font-size: 0.875rem;
font-weight: 400;
line-height: 1.5;
- color: #303030;
+ color: #333238;
background-color: #fff;
background-clip: padding-box;
- border: 1px solid #868686;
+ border: 1px solid #89888d;
border-radius: 0.25rem;
}
@media (prefers-reduced-motion: reduce) {
}
.form-control:-moz-focusring {
color: transparent;
- text-shadow: 0 0 0 #303030;
+ text-shadow: 0 0 0 #333238;
}
.form-control::placeholder {
- color: #5e5e5e;
+ color: #626168;
opacity: 1;
}
.form-control:disabled {
- background-color: #fafafa;
+ background-color: #fbfafd;
opacity: 1;
}
.form-group {
@@ -222,7 +222,7 @@ hr {
.btn {
display: inline-block;
font-weight: 400;
- color: #303030;
+ color: #333238;
text-align: center;
vertical-align: middle;
user-select: none;
@@ -282,10 +282,10 @@ input.btn-block[type="button"] {
border-color: #b3d7ff;
}
.custom-control-input:disabled ~ .custom-control-label {
- color: #5e5e5e;
+ color: #626168;
}
.custom-control-input:disabled ~ .custom-control-label::before {
- background-color: #fafafa;
+ background-color: #fbfafd;
}
.custom-control-label {
position: relative;
@@ -302,7 +302,7 @@ input.btn-block[type="button"] {
pointer-events: none;
content: "";
background-color: #fff;
- border: #666 solid 1px;
+ border: #737278 solid 1px;
}
.custom-control-label::after {
position: absolute;
@@ -400,8 +400,8 @@ input.btn-block[type="button"] {
padding-left: 0.75rem;
padding-right: 0.75rem;
height: auto;
- color: #303030;
- box-shadow: inset 0 0 0 1px #868686;
+ color: #333238;
+ box-shadow: inset 0 0 0 1px #89888d;
border-style: none;
appearance: none;
-moz-appearance: none;
@@ -410,27 +410,27 @@ input.btn-block[type="button"] {
.gl-form-input:not(.form-control-plaintext):not([type="color"]):read-only,
.gl-form-input.form-control:disabled,
.gl-form-input.form-control:not(.form-control-plaintext):not([type="color"]):read-only {
- background-color: #f5f5f5;
- box-shadow: inset 0 0 0 1px #dbdbdb;
+ background-color: #fbfafd;
+ box-shadow: inset 0 0 0 1px #dcdcde;
}
.gl-form-input:disabled,
.gl-form-input.form-control:disabled {
cursor: not-allowed;
- color: #666;
+ color: #737278;
}
.gl-form-input::placeholder,
.gl-form-input.form-control::placeholder {
- color: #868686;
+ color: #89888d;
}
.gl-form-checkbox {
font-size: 0.875rem;
line-height: 1rem;
- color: #303030;
+ color: #333238;
}
.gl-form-checkbox .custom-control-input:disabled,
.gl-form-checkbox .custom-control-input:disabled ~ .custom-control-label {
cursor: not-allowed;
- color: #868686;
+ color: #89888d;
}
.gl-form-checkbox.custom-control .custom-control-input ~ .custom-control-label {
cursor: pointer;
@@ -447,7 +447,7 @@ input.btn-block[type="button"] {
.custom-control-input
~ .custom-control-label::before {
background-color: #fff;
- border-color: #868686;
+ border-color: #89888d;
}
.gl-form-checkbox.custom-control
.custom-control-input:checked
@@ -490,8 +490,8 @@ input.btn-block[type="button"] {
.gl-form-checkbox.custom-control
.custom-control-input:disabled
~ .custom-control-label::before {
- background-color: #f0f0f0;
- border-color: #dbdbdb;
+ background-color: #ececef;
+ border-color: #dcdcde;
pointer-events: auto;
}
.gl-form-checkbox.custom-control
@@ -500,8 +500,8 @@ input.btn-block[type="button"] {
.gl-form-checkbox.custom-control
.custom-control-input[type="checkbox"]:indeterminate:disabled
~ .custom-control-label::before {
- background-color: #dbdbdb;
- border-color: #dbdbdb;
+ background-color: #dcdcde;
+ border-color: #dcdcde;
}
.gl-form-checkbox.custom-control
.custom-control-input:checked:disabled
@@ -509,7 +509,7 @@ input.btn-block[type="button"] {
.gl-form-checkbox.custom-control
.custom-control-input[type="checkbox"]:indeterminate:disabled
~ .custom-control-label::after {
- background-color: #5e5e5e;
+ background-color: #626168;
}
.gl-button {
display: inline-flex;
@@ -526,9 +526,9 @@ input.btn-block[type="button"] {
padding-right: 0.75rem;
background-color: transparent;
line-height: 1rem;
- color: #303030;
+ color: #333238;
fill: currentColor;
- box-shadow: inset 0 0 0 1px #bfbfbf;
+ box-shadow: inset 0 0 0 1px #bfbfc3;
justify-content: center;
align-items: center;
font-size: 0.875rem;
@@ -560,9 +560,9 @@ input.btn-block[type="button"] {
.gl-button.gl-button.btn-default.active,
.gl-button.gl-button.btn-block.btn-default:active,
.gl-button.gl-button.btn-block.btn-default.active {
- box-shadow: inset 0 0 0 1px #5e5e5e, 0 0 0 1px #fff, 0 0 0 3px #428fdc;
+ box-shadow: inset 0 0 0 1px #626168, 0 0 0 1px #fff, 0 0 0 3px #428fdc;
outline: none;
- background-color: #dbdbdb;
+ background-color: #dcdcde;
}
.gl-button.gl-button.btn-confirm,
.gl-button.gl-button.btn-block.btn-confirm {
@@ -636,20 +636,20 @@ body.navless {
font-weight: 400;
padding: 6px 10px;
background-color: #fff;
- border-color: #dbdbdb;
- color: #303030;
- color: #303030;
+ border-color: #dcdcde;
+ color: #333238;
+ color: #333238;
white-space: nowrap;
}
.btn:active {
- background-color: #f0f0f0;
+ background-color: #ececef;
box-shadow: none;
}
.btn:active,
.btn.active {
background-color: #eaeaea;
border-color: #e3e3e3;
- color: #303030;
+ color: #333238;
}
.btn svg {
height: 15px;
@@ -676,7 +676,7 @@ body.navless {
}
hr {
margin: 1.5rem 0;
- border-top: 1px solid #eee;
+ border-top: 1px solid #ececef;
}
.footer-links {
margin-bottom: 20px;
@@ -704,7 +704,7 @@ hr {
}
input {
border-radius: 0.25rem;
- color: #303030;
+ color: #333238;
background-color: #fff;
}
label {
@@ -721,7 +721,7 @@ label.label-bold {
padding: 6px 10px;
}
.form-control::placeholder {
- color: #868686;
+ color: #89888d;
}
.gl-show-field-errors .form-control:not(textarea) {
height: 34px;
@@ -730,7 +730,7 @@ label.label-bold {
justify-content: center;
height: var(--header-height, 48px);
background: #fff;
- border-bottom: 1px solid #dbdbdb;
+ border-bottom: 1px solid #dcdcde;
}
.navbar-empty .tanuki-logo,
.navbar-empty .brand-header-logo {
@@ -747,14 +747,14 @@ label.label-bold {
fill: #fca326;
}
input::-moz-placeholder {
- color: #868686;
+ color: #89888d;
opacity: 1;
}
input::-ms-input-placeholder {
- color: #868686;
+ color: #89888d;
}
input:-ms-input-placeholder {
- color: #868686;
+ color: #89888d;
}
svg {
fill: currentColor;
@@ -805,7 +805,7 @@ svg {
}
.login-page .login-box,
.login-page .omniauth-container {
- box-shadow: 0 0 0 1px #dbdbdb;
+ box-shadow: 0 0 0 1px #dcdcde;
border-radius: 0.25rem;
}
.login-page .login-box .login-heading h3,
@@ -863,7 +863,7 @@ svg {
}
.login-page .new-session-tabs {
display: flex;
- box-shadow: 0 0 0 1px #dbdbdb;
+ box-shadow: 0 0 0 1px #dcdcde;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
}
@@ -874,7 +874,7 @@ svg {
.login-page .new-session-tabs.nav-links-unboxed .nav-item {
border-left: 0;
border-right: 0;
- border-bottom: 1px solid #dbdbdb;
+ border-bottom: 1px solid #dcdcde;
background-color: transparent;
}
.login-page .new-session-tabs.custom-provider-tabs {
@@ -885,7 +885,7 @@ svg {
flex-basis: auto;
}
.login-page .new-session-tabs.custom-provider-tabs li:nth-child(n + 5) {
- border-top: 1px solid #dbdbdb;
+ border-top: 1px solid #dcdcde;
}
.login-page .new-session-tabs.custom-provider-tabs a {
font-size: 16px;
@@ -893,7 +893,7 @@ svg {
.login-page .new-session-tabs li {
flex: 1;
text-align: center;
- border-left: 1px solid #dbdbdb;
+ border-left: 1px solid #dcdcde;
}
.login-page .new-session-tabs li:first-of-type {
border-left: 0;
@@ -903,7 +903,7 @@ svg {
border-top-right-radius: 4px;
}
.login-page .new-session-tabs li:not(.active) {
- background-color: #fafafa;
+ background-color: #fbfafd;
}
.login-page .new-session-tabs li a {
width: 100%;
diff --git a/app/assets/stylesheets/themes/_dark.scss b/app/assets/stylesheets/themes/_dark.scss
index 8e8cabbe511..a3474d2ed50 100644
--- a/app/assets/stylesheets/themes/_dark.scss
+++ b/app/assets/stylesheets/themes/_dark.scss
@@ -1,15 +1,15 @@
-$gray-10: #1f1f1f;
-$gray-50: #303030;
-$gray-100: #404040;
-$gray-200: #525252;
-$gray-300: #5e5e5e;
-$gray-400: #868686;
-$gray-500: #999;
-$gray-600: #bfbfbf;
-$gray-700: #dbdbdb;
-$gray-800: #f0f0f0;
-$gray-900: #fafafa;
-$gray-950: #fff;
+$gray-10: #1f1e24;
+$gray-50: #333238;
+$gray-100: #434248;
+$gray-200: #535158;
+$gray-300: #626168;
+$gray-400: #737278;
+$gray-500: #89888d;
+$gray-600: #a4a3a8;
+$gray-700: #bfbfc3;
+$gray-800: #dcdcde;
+$gray-900: #ececef;
+$gray-950: #fbfafd;
$green-50: #0a4020;
$green-100: #0d532a;
@@ -203,6 +203,7 @@ body.gl-dark {
--white: #{$white};
--black: #{$black};
+ --gray-light: #{$gray-50};
--svg-status-bg: #{$white};
@@ -255,9 +256,6 @@ $popover-arrow-outer-color: $gray-800;
$secondary: $gray-600;
-$issues-today-bg: #333838;
-$issues-today-border: #333a40;
-
$yiq-text-dark: $gray-50;
$yiq-text-light: $gray-950;
diff --git a/app/assets/stylesheets/themes/theme_helper.scss b/app/assets/stylesheets/themes/theme_helper.scss
index d644d8acc98..f37b426cd91 100644
--- a/app/assets/stylesheets/themes/theme_helper.scss
+++ b/app/assets/stylesheets/themes/theme_helper.scss
@@ -219,6 +219,16 @@
}
}
+ .search-sidebar {
+ .nav-link {
+ &.active,
+ &:hover {
+ background-color: rgba($gray-50, 0.8);
+ color: $gray-900;
+ }
+ }
+ }
+
// Sidebar
.nav-sidebar li.active > a {
color: $gray-900;
diff --git a/app/components/pajamas/avatar_component.rb b/app/components/pajamas/avatar_component.rb
index 073968e0491..423934b6887 100644
--- a/app/components/pajamas/avatar_component.rb
+++ b/app/components/pajamas/avatar_component.rb
@@ -17,10 +17,10 @@ module Pajamas
@avatar_options = avatar_options
end
- private
-
SIZE_OPTIONS = [16, 24, 32, 48, 64, 96].freeze
+ private
+
def avatar_classes
classes = ["gl-avatar", "gl-avatar-s#{@size}", @class]
classes.push("gl-avatar-circle") if @record.is_a?(User)
diff --git a/app/components/pajamas/badge_component.rb b/app/components/pajamas/badge_component.rb
index 244064b0e1e..4955bcd29ed 100644
--- a/app/components/pajamas/badge_component.rb
+++ b/app/components/pajamas/badge_component.rb
@@ -22,11 +22,11 @@ module Pajamas
@html_options = html_options
end
- private
-
SIZE_OPTIONS = [:sm, :md, :lg].freeze
VARIANT_OPTIONS = [:muted, :neutral, :info, :success, :warning, :danger].freeze
+ private
+
delegate :sprite_icon, to: :helpers
def badge_classes
diff --git a/app/components/pajamas/banner_component.rb b/app/components/pajamas/banner_component.rb
index 9b6343b47c9..6082762f22c 100644
--- a/app/components/pajamas/banner_component.rb
+++ b/app/components/pajamas/banner_component.rb
@@ -23,13 +23,15 @@ module Pajamas
@button_text = button_text
@button_link = button_link
@embedded = embedded
- @variant = variant.to_sym
+ @variant = filter_attribute(variant.to_sym, VARIANT_OPTIONS, default: :promotion)
@svg_path = svg_path.to_s
@banner_options = banner_options
@button_options = button_options
@close_options = close_options
end
+ VARIANT_OPTIONS = [:introduction, :promotion].freeze
+
private
def banner_class
diff --git a/app/components/pajamas/spinner_component.html.haml b/app/components/pajamas/spinner_component.html.haml
index aab9c5fdbf7..b319f3b1632 100644
--- a/app/components/pajamas/spinner_component.html.haml
+++ b/app/components/pajamas/spinner_component.html.haml
@@ -1,5 +1,2 @@
-.gl-spinner-container{ class: @class }
- - if @inline
- %span{ class: spinner_class, aria: {label: @label} }
- - else
- %div{ class: spinner_class, aria: {label: @label} }
+= content_tag (@inline ? :span : :div), **html_options do
+ %span{ class: spinner_class, aria: {label: @label} }>
diff --git a/app/components/pajamas/spinner_component.rb b/app/components/pajamas/spinner_component.rb
index c7ffc1ec3da..f2f7236ee3f 100644
--- a/app/components/pajamas/spinner_component.rb
+++ b/app/components/pajamas/spinner_component.rb
@@ -2,26 +2,31 @@
module Pajamas
class SpinnerComponent < Pajamas::Component
- # @param [String] class
# @param [Symbol] color
# @param [Boolean] inline
# @param [String] label
# @param [Symbol] size
- def initialize(class: '', color: :dark, inline: false, label: _("Loading"), size: :sm)
- @class = binding.local_variable_get(:class)
+ def initialize(color: :dark, inline: false, label: _("Loading"), size: :sm, **html_options)
@color = filter_attribute(color.to_sym, COLOR_OPTIONS)
@inline = inline
@label = label.presence
@size = filter_attribute(size.to_sym, SIZE_OPTIONS)
+ @html_options = html_options
end
+ COLOR_OPTIONS = [:light, :dark].freeze
+ SIZE_OPTIONS = [:sm, :md, :lg, :xl].freeze
+
private
def spinner_class
- ["gl-spinner", "gl-spinner-#{@size}", "gl-spinner-#{@color}"]
+ ["gl-spinner", "gl-spinner-#{@size}", "gl-spinner-#{@color} gl-vertical-align-text-bottom!"]
end
- COLOR_OPTIONS = [:light, :dark].freeze
- SIZE_OPTIONS = [:sm, :md, :lg, :xl].freeze
+ def html_options
+ options = format_options(options: @html_options, css_classes: "gl-spinner-container")
+ options[:role] = "status"
+ options
+ end
end
end
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index b75a7c4a2dd..ec9441c2b9b 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -13,10 +13,6 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
before_action :disable_query_limiting, only: [:usage_data]
- before_action do
- push_frontend_feature_flag(:ci_variable_settings_graphql)
- end
-
feature_category :not_owned, [ # rubocop:todo Gitlab/AvoidFeatureCategoryNotOwned
:general, :reporting, :metrics_and_profiling, :network,
:preferences, :update, :reset_health_check_token
@@ -84,7 +80,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
format.json do
Gitlab::UsageDataCounters::ServiceUsageDataCounter.count(:download_payload_click)
- render json: service_ping_data.to_json
+ render json: Gitlab::Json.dump(service_ping_data)
end
end
end
diff --git a/app/controllers/admin/broadcast_messages_controller.rb b/app/controllers/admin/broadcast_messages_controller.rb
index edd85414696..bdf0c6aedb9 100644
--- a/app/controllers/admin/broadcast_messages_controller.rb
+++ b/app/controllers/admin/broadcast_messages_controller.rb
@@ -3,39 +3,60 @@
class Admin::BroadcastMessagesController < Admin::ApplicationController
include BroadcastMessagesHelper
- before_action :finder, only: [:edit, :update, :destroy]
+ before_action :find_broadcast_message, only: [:edit, :update, :destroy]
+ before_action :find_broadcast_messages, only: [:index, :create]
+ before_action :push_features, only: [:index, :edit]
feature_category :onboarding
urgency :low
- # rubocop: disable CodeReuse/ActiveRecord
def index
- push_frontend_feature_flag(:vue_broadcast_messages, current_user)
- push_frontend_feature_flag(:role_targeted_broadcast_messages, current_user)
-
- @broadcast_messages = BroadcastMessage.order(ends_at: :desc).page(params[:page])
- @broadcast_message = BroadcastMessage.new
+ @broadcast_message = BroadcastMessage.new
end
- # rubocop: enable CodeReuse/ActiveRecord
def edit
end
def create
@broadcast_message = BroadcastMessage.new(broadcast_message_params)
+ success = @broadcast_message.save
- if @broadcast_message.save
- redirect_to admin_broadcast_messages_path, notice: _('Broadcast Message was successfully created.')
- else
- render :index
+ respond_to do |format|
+ format.json do
+ if success
+ render json: @broadcast_message, status: :ok
+ else
+ render json: { errors: @broadcast_message.errors.full_messages }, status: :bad_request
+ end
+ end
+ format.html do
+ if success
+ redirect_to admin_broadcast_messages_path, notice: _('Broadcast Message was successfully created.')
+ else
+ render :index
+ end
+ end
end
end
def update
- if @broadcast_message.update(broadcast_message_params)
- redirect_to admin_broadcast_messages_path, notice: _('Broadcast Message was successfully updated.')
- else
- render :edit
+ success = @broadcast_message.update(broadcast_message_params)
+
+ respond_to do |format|
+ format.json do
+ if success
+ render json: @broadcast_message, status: :ok
+ else
+ render json: { errors: @broadcast_message.errors.full_messages }, status: :bad_request
+ end
+ end
+ format.html do
+ if success
+ redirect_to admin_broadcast_messages_path, notice: _('Broadcast Message was successfully updated.')
+ else
+ render :edit
+ end
+ end
end
end
@@ -55,10 +76,14 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
protected
- def finder
+ def find_broadcast_message
@broadcast_message = BroadcastMessage.find(params[:id])
end
+ def find_broadcast_messages
+ @broadcast_messages = BroadcastMessage.order(ends_at: :desc).page(params[:page]) # rubocop: disable CodeReuse/ActiveRecord
+ end
+
def broadcast_message_params
params.require(:broadcast_message)
.permit(%i(
@@ -71,4 +96,9 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
dismissable
), target_access_levels: []).reverse_merge!(target_access_levels: [])
end
+
+ def push_features
+ push_frontend_feature_flag(:vue_broadcast_messages, current_user)
+ push_frontend_feature_flag(:role_targeted_broadcast_messages, current_user)
+ end
end
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index f3c4244269d..1395d4bb3b7 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -38,12 +38,9 @@ class Admin::GroupsController < Admin::ApplicationController
end
def create
- @group = Group.new(group_params)
- @group.name = @group.path.dup unless @group.name
+ @group = ::Groups::CreateService.new(current_user, group_params).execute
- if @group.save
- @group.add_owner(current_user)
- @group.create_namespace_settings
+ if @group.persisted?
redirect_to [:admin, @group], notice: _('Group %{group_name} was successfully created.') % { group_name: @group.name }
else
render "new"
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 1a57d271271..2c8b4888d5d 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -26,6 +26,8 @@ class Admin::UsersController < Admin::ApplicationController
end
def show
+ @can_impersonate = can_impersonate_user
+ @impersonation_error_text = @can_impersonate ? nil : impersonation_error_text
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -47,7 +49,7 @@ class Admin::UsersController < Admin::ApplicationController
end
def impersonate
- if can?(user, :log_in) && !impersonation_in_progress?
+ if can_impersonate_user
session[:impersonator_id] = current_user.id
warden.set_user(user, scope: :user)
@@ -59,16 +61,7 @@ class Admin::UsersController < Admin::ApplicationController
redirect_to root_path
else
- flash[:alert] =
- if impersonation_in_progress?
- _("You are already impersonating another user")
- elsif user.blocked?
- _("You cannot impersonate a blocked user")
- elsif user.internal?
- _("You cannot impersonate an internal user")
- else
- _("You cannot impersonate a user who cannot log in")
- end
+ flash[:alert] = impersonation_error_text
redirect_to admin_user_path(user)
end
@@ -378,6 +371,24 @@ class Admin::UsersController < Admin::ApplicationController
def log_impersonation_event
Gitlab::AppLogger.info(_("User %{current_user_username} has started impersonating %{username}") % { current_user_username: current_user.username, username: user.username })
end
+
+ def can_impersonate_user
+ can?(user, :log_in) && !user.password_expired? && !impersonation_in_progress?
+ end
+
+ def impersonation_error_text
+ if impersonation_in_progress?
+ _("You are already impersonating another user")
+ elsif user.blocked?
+ _("You cannot impersonate a blocked user")
+ elsif user.password_expired?
+ _("You cannot impersonate a user with an expired password")
+ elsif user.internal?
+ _("You cannot impersonate an internal user")
+ else
+ _("You cannot impersonate a user who cannot log in")
+ end
+ end
end
Admin::UsersController.prepend_mod_with('Admin::UsersController')
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 84efb8b0da8..4de6b5de42a 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -13,6 +13,7 @@ class ApplicationController < ActionController::Base
include EnforcesTwoFactorAuthentication
include WithPerformanceBar
include Gitlab::SearchContext::ControllerConcern
+ include PreferredLanguageSwitcher
include SessionlessAuthentication
include SessionsHelper
include ConfirmEmailWarning
@@ -512,7 +513,13 @@ class ApplicationController < ActionController::Base
end
def set_locale(&block)
- Gitlab::I18n.with_user_locale(current_user, &block)
+ return Gitlab::I18n.with_user_locale(current_user, &block) unless Feature.enabled?(:preferred_language_switcher)
+
+ if current_user
+ Gitlab::I18n.with_user_locale(current_user, &block)
+ else
+ Gitlab::I18n.with_locale(preferred_language, &block)
+ end
end
def set_session_storage(&block)
diff --git a/app/controllers/concerns/access_tokens_actions.rb b/app/controllers/concerns/access_tokens_actions.rb
index 6e43be5594d..fdb08c6572f 100644
--- a/app/controllers/concerns/access_tokens_actions.rb
+++ b/app/controllers/concerns/access_tokens_actions.rb
@@ -13,6 +13,13 @@ module AccessTokensActions
def index
@resource_access_token = PersonalAccessToken.new
set_index_vars
+
+ respond_to do |format|
+ format.html
+ format.json do
+ render json: @active_access_tokens
+ end
+ end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
@@ -23,7 +30,7 @@ module AccessTokensActions
if token_response.success?
@resource_access_token = token_response.payload[:access_token]
render json: { new_token: @resource_access_token.token,
- active_access_tokens: active_resource_access_tokens }, status: :ok
+ active_access_tokens: active_access_tokens }, status: :ok
else
render json: { errors: token_response.errors }, status: :unprocessable_entity
end
@@ -62,15 +69,10 @@ module AccessTokensActions
resource.members.load
@scopes = Gitlab::Auth.resource_bot_scopes
- @active_resource_access_tokens = active_resource_access_tokens
+ @active_access_tokens = active_access_tokens
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
- def active_resource_access_tokens
- tokens = finder(state: 'active', sort: 'expires_at_asc_id_desc').execute.preload_users
- represent(tokens)
- end
-
def finder(options = {})
PersonalAccessTokensFinder.new({ user: bot_users, impersonation: false }.merge(options))
end
diff --git a/app/controllers/concerns/authenticates_with_two_factor.rb b/app/controllers/concerns/authenticates_with_two_factor.rb
index fbaa754124c..817f82085e6 100644
--- a/app/controllers/concerns/authenticates_with_two_factor.rb
+++ b/app/controllers/concerns/authenticates_with_two_factor.rb
@@ -137,7 +137,7 @@ module AuthenticatesWithTwoFactor
session[:credentialRequestOptions] = get_options
session[:challenge] = get_options.challenge
- gon.push(webauthn: { options: get_options.to_json })
+ gon.push(webauthn: { options: Gitlab::Json.dump(get_options) })
end
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/controllers/concerns/integrations/params.rb b/app/controllers/concerns/integrations/params.rb
index c3ad9d3dff3..30de4a86bec 100644
--- a/app/controllers/concerns/integrations/params.rb
+++ b/app/controllers/concerns/integrations/params.rb
@@ -88,6 +88,10 @@ module Integrations
param_values = return_value[:integration]
if param_values.is_a?(ActionController::Parameters)
+ if action_name == 'update' && integration.chat? && param_values['webhook'] == BaseChatNotification::SECRET_MASK
+ param_values.delete('webhook')
+ end
+
integration.secret_fields.each do |param|
param_values.delete(param) if param_values[param].blank?
end
diff --git a/app/controllers/concerns/issuable_actions.rb b/app/controllers/concerns/issuable_actions.rb
index 7c3401a7e90..bea184e44b9 100644
--- a/app/controllers/concerns/issuable_actions.rb
+++ b/app/controllers/concerns/issuable_actions.rb
@@ -142,43 +142,21 @@ module IssuableActions
end
end
- # rubocop:disable CodeReuse/ActiveRecord
def discussions
- notes = NotesFinder.new(current_user, finder_params_for_issuable).execute
- .inc_relations_for_view
- .includes(:noteable)
- .fresh
+ finder = Issuable::DiscussionsListService.new(current_user, issuable, finder_params_for_issuable)
+ discussion_notes = finder.execute
- if paginated_discussions
- paginated_discussions_by_type = paginated_discussions.records.group_by(&:table_name)
+ response.headers['X-Next-Page-Cursor'] = finder.paginator.cursor_for_next_page if finder.paginator.present? && finder.paginator.has_next_page?
- notes = if paginated_discussions_by_type['notes'].present?
- notes.with_discussion_ids(paginated_discussions_by_type['notes'].map(&:discussion_id))
- else
- notes.none
- end
-
- response.headers['X-Next-Page-Cursor'] = paginated_discussions.cursor_for_next_page if paginated_discussions.has_next_page?
- end
-
- if notes_filter != UserPreference::NOTES_FILTERS[:only_comments]
- notes = ResourceEvents::MergeIntoNotesService.new(issuable, current_user, paginated_notes: paginated_discussions_by_type).execute(notes)
- end
-
- notes = prepare_notes_for_rendering(notes)
- notes = notes.select { |n| n.readable_by?(current_user) }
-
- discussions = Discussion.build_collection(notes, issuable)
-
- if issuable.is_a?(MergeRequest)
- render_mr_discussions(discussions, discussion_serializer, discussion_cache_context)
- elsif issuable.is_a?(Issue)
- render json: discussion_serializer.represent(discussions, context: self) if stale?(etag: [discussion_cache_context, discussions])
+ case issuable
+ when MergeRequest
+ render_mr_discussions(discussion_notes, discussion_serializer, discussion_cache_context)
+ when Issue
+ render json: discussion_serializer.represent(discussion_notes, context: self) if stale?(etag: [discussion_cache_context, discussion_notes])
else
- render json: discussion_serializer.represent(discussions, context: self)
+ render json: discussion_serializer.represent(discussion_notes, context: self)
end
end
- # rubocop:enable CodeReuse/ActiveRecord
private
@@ -199,17 +177,6 @@ module IssuableActions
context: self)
end
- def paginated_discussions
- return if params[:per_page].blank?
- return if issuable.instance_of?(MergeRequest) && Feature.disabled?(:paginated_mr_discussions, project)
-
- strong_memoize(:paginated_discussions) do
- issuable
- .discussion_root_note_ids(notes_filter: notes_filter)
- .keyset_paginate(cursor: params[:cursor], per_page: params[:per_page].to_i)
- end
- end
-
def notes_filter
strong_memoize(:notes_filter) do
notes_filter_param = params[:notes_filter]&.to_i
@@ -325,9 +292,10 @@ module IssuableActions
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def finder_params_for_issuable
{
- target: @issuable,
- notes_filter: notes_filter
- }.tap { |new_params| new_params[:project] = project if respond_to?(:project, true) }
+ notes_filter: notes_filter,
+ cursor: params[:cursor],
+ per_page: params[:per_page]
+ }
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
end
diff --git a/app/controllers/concerns/issuable_collections_action.rb b/app/controllers/concerns/issuable_collections_action.rb
index e03d1de7bf9..7beb86b51fd 100644
--- a/app/controllers/concerns/issuable_collections_action.rb
+++ b/app/controllers/concerns/issuable_collections_action.rb
@@ -60,7 +60,6 @@ module IssuableCollectionsAction
def finder_options
issue_types = Issue::TYPES_FOR_LIST
- issue_types = issue_types.excluding('task') unless Feature.enabled?(:work_items)
super.merge(
non_archived: true,
diff --git a/app/controllers/concerns/preferred_language_switcher.rb b/app/controllers/concerns/preferred_language_switcher.rb
new file mode 100644
index 00000000000..9711e57cf7a
--- /dev/null
+++ b/app/controllers/concerns/preferred_language_switcher.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module PreferredLanguageSwitcher
+ extend ActiveSupport::Concern
+
+ private
+
+ def init_preferred_language
+ return unless Feature.enabled?(:preferred_language_switcher)
+
+ cookies[:preferred_language] = preferred_language
+ end
+
+ def preferred_language
+ cookies[:preferred_language].presence_in(Gitlab::I18n.available_locales) ||
+ Gitlab::CurrentSettings.default_preferred_language
+ end
+end
diff --git a/app/controllers/concerns/preview_markdown.rb b/app/controllers/concerns/preview_markdown.rb
index 79b3fa28660..7af114313a1 100644
--- a/app/controllers/concerns/preview_markdown.rb
+++ b/app/controllers/concerns/preview_markdown.rb
@@ -41,7 +41,7 @@ module PreviewMarkdown
case controller_name
when 'wikis' then { pipeline: :wiki, wiki: wiki, page_slug: params[:id] }
when 'snippets' then { skip_project_check: true }
- when 'groups' then { group: group }
+ when 'groups' then { group: group, issuable_reference_expansion_enabled: true }
when 'projects' then projects_filter_params
when 'timeline_events' then timeline_events_filter_params
else {}
diff --git a/app/controllers/concerns/product_analytics_tracking.rb b/app/controllers/concerns/product_analytics_tracking.rb
index 4f96cc5c895..dfa159ccfd7 100644
--- a/app/controllers/concerns/product_analytics_tracking.rb
+++ b/app/controllers/concerns/product_analytics_tracking.rb
@@ -6,6 +6,8 @@ module ProductAnalyticsTracking
extend ActiveSupport::Concern
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)
custom_conditions = [:trackable_html_request?, *conditions]
diff --git a/app/controllers/concerns/render_access_tokens.rb b/app/controllers/concerns/render_access_tokens.rb
new file mode 100644
index 00000000000..b0bbad7e37f
--- /dev/null
+++ b/app/controllers/concerns/render_access_tokens.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+module RenderAccessTokens
+ extend ActiveSupport::Concern
+
+ def active_access_tokens
+ tokens = finder(state: 'active', sort: 'expires_at_asc_id_desc').execute.preload_users
+
+ if Feature.enabled?('access_token_pagination')
+ tokens = tokens.page(page)
+ add_pagination_headers(tokens)
+ end
+
+ represent(tokens)
+ end
+
+ def add_pagination_headers(relation)
+ Gitlab::Pagination::OffsetHeaderBuilder.new(
+ request_context: self,
+ per_page: relation.limit_value,
+ page: relation.current_page,
+ next_page: relation.next_page,
+ prev_page: relation.prev_page,
+ total: relation.total_count,
+ params: params.permit(:page, :per_page)
+ ).execute
+ end
+
+ def page
+ (params[:page] || 1).to_i
+ end
+end
diff --git a/app/controllers/concerns/send_file_upload.rb b/app/controllers/concerns/send_file_upload.rb
index c8369c465b8..c91edb74d6b 100644
--- a/app/controllers/concerns/send_file_upload.rb
+++ b/app/controllers/concerns/send_file_upload.rb
@@ -30,7 +30,17 @@ module SendFileUpload
headers.store(*Gitlab::Workhorse.send_url(file_upload.url(**redirect_params)))
head :ok
else
- redirect_to file_upload.url(**redirect_params)
+ redirect_to cdn_fronted_url(file_upload, redirect_params)
+ end
+ end
+
+ def cdn_fronted_url(file, redirect_params)
+ if file.respond_to?(:cdn_enabled_url)
+ result = file.cdn_enabled_url(request.remote_ip, redirect_params[:query])
+ Gitlab::ApplicationContext.push(artifact_used_cdn: result.used_cdn)
+ result.url
+ else
+ file.url(**redirect_params)
end
end
diff --git a/app/controllers/concerns/verifies_with_email.rb b/app/controllers/concerns/verifies_with_email.rb
index 782cae53c3f..ac1475597ff 100644
--- a/app/controllers/concerns/verifies_with_email.rb
+++ b/app/controllers/concerns/verifies_with_email.rb
@@ -8,7 +8,7 @@ module VerifiesWithEmail
include ActionView::Helpers::DateHelper
included do
- prepend_before_action :verify_with_email, only: :create, unless: -> { two_factor_enabled? }
+ prepend_before_action :verify_with_email, only: :create, unless: -> { skip_verify_with_email? }
skip_before_action :required_signup_info, only: :successful_verification
end
@@ -55,6 +55,10 @@ module VerifiesWithEmail
private
+ def skip_verify_with_email?
+ two_factor_enabled? || Gitlab::Qa.request?(request.user_agent)
+ end
+
def find_verification_user
return unless session[:verification_user_id]
@@ -84,10 +88,7 @@ module VerifiesWithEmail
def send_verification_instructions_email(user, token)
return unless user.can?(:receive_notifications)
- Notify.verification_instructions_email(
- user.id,
- token: token,
- expires_in: Users::EmailVerification::ValidateTokenService::TOKEN_VALID_FOR_MINUTES).deliver_later
+ Notify.verification_instructions_email(user.email, token: token).deliver_later
log_verification(user, :instructions_sent)
end
diff --git a/app/controllers/concerns/web_hooks/hook_actions.rb b/app/controllers/concerns/web_hooks/hook_actions.rb
index ea11f13c7ef..75065ef9d24 100644
--- a/app/controllers/concerns/web_hooks/hook_actions.rb
+++ b/app/controllers/concerns/web_hooks/hook_actions.rb
@@ -20,7 +20,7 @@ module WebHooks
unless hook.valid?
self.hooks = relation.select(&:persisted?)
- flash[:alert] = hook.errors.full_messages.join.html_safe
+ flash[:alert] = hook.errors.full_messages.to_sentence.html_safe
end
redirect_to action: :index
@@ -53,6 +53,8 @@ module WebHooks
ps = params.require(:hook).permit(*permitted).to_h
+ ps.delete(:token) if action_name == 'update' && ps[:token] == WebHook::SECRET_MASK
+
ps[:url_variables] = ps[:url_variables].to_h { [_1[:key], _1[:value].presence] } if ps.key?(:url_variables)
if action_name == 'update' && ps.key?(:url_variables)
@@ -64,7 +66,9 @@ module WebHooks
end
def hook_param_names
- %i[enable_ssl_verification token url push_events_branch_filter]
+ param_names = %i[enable_ssl_verification token url push_events_branch_filter]
+ param_names.push(:branch_filter_strategy) if Feature.enabled?(:enhanced_webhook_support_regex)
+ param_names
end
def destroy_hook(hook)
diff --git a/app/controllers/concerns/web_hooks/hook_execution_notice.rb b/app/controllers/concerns/web_hooks/hook_execution_notice.rb
index d651313b30d..69b140723e3 100644
--- a/app/controllers/concerns/web_hooks/hook_execution_notice.rb
+++ b/app/controllers/concerns/web_hooks/hook_execution_notice.rb
@@ -5,7 +5,7 @@ module WebHooks
private
def set_hook_execution_notice(result)
- http_status = result[:http_status]
+ http_status = result.payload[:http_status]
message = result[:message]
if http_status && http_status >= 200 && http_status < 400
diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb
index 713231cbc6f..6dd4d72bbc7 100644
--- a/app/controllers/confirmations_controller.rb
+++ b/app/controllers/confirmations_controller.rb
@@ -6,6 +6,7 @@ class ConfirmationsController < Devise::ConfirmationsController
include OneTrustCSP
include GoogleAnalyticsCSP
+ skip_before_action :required_signup_info
prepend_before_action :check_recaptcha, only: :create
before_action :load_recaptcha, only: :new
diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb
index 0e4592259d8..89d362c88a4 100644
--- a/app/controllers/dashboard/projects_controller.rb
+++ b/app/controllers/dashboard/projects_controller.rb
@@ -66,11 +66,10 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
end
def load_projects(finder_params)
- @total_user_projects_count = ProjectsFinder.new(params: { non_public: true, without_deleted: true, not_aimed_for_deletion: true }, current_user: current_user).execute
- @total_starred_projects_count = ProjectsFinder.new(params: { starred: true, without_deleted: true, not_aimed_for_deletion: true }, current_user: current_user).execute
+ @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
finder_params[:use_cte] = true if use_cte_for_finder?
- finder_params[:without_deleted] = true
projects = ProjectsFinder.new(params: finder_params, current_user: current_user).execute
@@ -93,7 +92,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
def load_events
projects = ProjectsFinder
- .new(params: params.merge(non_public: true, without_deleted: true), current_user: current_user)
+ .new(params: params.merge(non_public: true, not_aimed_for_deletion: true), current_user: current_user)
.execute
@events = EventCollection
diff --git a/app/controllers/explore/groups_controller.rb b/app/controllers/explore/groups_controller.rb
index 97791b43d41..ac355b861b3 100644
--- a/app/controllers/explore/groups_controller.rb
+++ b/app/controllers/explore/groups_controller.rb
@@ -7,6 +7,8 @@ class Explore::GroupsController < Explore::ApplicationController
urgency :low
def index
- render_group_tree GroupsFinder.new(current_user).execute
+ user = Feature.enabled?(:generic_explore_groups, current_user, type: :experiment) ? nil : current_user
+
+ render_group_tree GroupsFinder.new(user).execute
end
end
diff --git a/app/controllers/graphql_controller.rb b/app/controllers/graphql_controller.rb
index 67eeb43d5a2..5ffd525c170 100644
--- a/app/controllers/graphql_controller.rb
+++ b/app/controllers/graphql_controller.rb
@@ -190,7 +190,8 @@ class GraphqlController < ApplicationController
current_user: current_user,
is_sessionless_user: api_user,
request: request,
- scope_validator: ::Gitlab::Auth::ScopeValidator.new(api_user, request_authenticator)
+ scope_validator: ::Gitlab::Auth::ScopeValidator.new(api_user, request_authenticator),
+ remove_deprecated: Gitlab::Utils.to_boolean(params[:remove_deprecated], default: false)
}
end
diff --git a/app/controllers/groups/boards_controller.rb b/app/controllers/groups/boards_controller.rb
index 14b70df0feb..e1ba86220c7 100644
--- a/app/controllers/groups/boards_controller.rb
+++ b/app/controllers/groups/boards_controller.rb
@@ -7,7 +7,7 @@ class Groups::BoardsController < Groups::ApplicationController
before_action do
push_frontend_feature_flag(:board_multi_select, group)
- push_frontend_feature_flag(:realtime_labels, group)
+ push_frontend_feature_flag(:apollo_boards, group)
experiment(:prominent_create_board_btn, subject: current_user) do |e|
e.control {}
e.candidate {}
diff --git a/app/controllers/groups/dependency_proxy/application_controller.rb b/app/controllers/groups/dependency_proxy/application_controller.rb
index f7337a3cdb1..300a82eed78 100644
--- a/app/controllers/groups/dependency_proxy/application_controller.rb
+++ b/app/controllers/groups/dependency_proxy/application_controller.rb
@@ -21,10 +21,11 @@ module Groups
user_or_deploy_token = ::DependencyProxy::AuthTokenService.user_or_deploy_token_from_jwt(token)
- if user_or_deploy_token.is_a?(User)
+ case user_or_deploy_token
+ when User
@authentication_result = Gitlab::Auth::Result.new(user_or_deploy_token, nil, :user, [])
sign_in(user_or_deploy_token)
- elsif user_or_deploy_token.is_a?(DeployToken)
+ when DeployToken
@authentication_result = Gitlab::Auth::Result.new(user_or_deploy_token, nil, :deploy_token, [])
end
end
diff --git a/app/controllers/groups/observability_controller.rb b/app/controllers/groups/observability_controller.rb
index 5b6503494c4..4b1f2b582ce 100644
--- a/app/controllers/groups/observability_controller.rb
+++ b/app/controllers/groups/observability_controller.rb
@@ -9,35 +9,41 @@ module Groups
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 'self'
- frame_src_values = Array.wrap(default_frame_src) | [ObservabilityController.observability_url, "'self'"]
+ frame_src_values = Array.wrap(default_frame_src) | [observability_url, "'self'"]
p.frame_src(*frame_src_values)
end
- before_action :check_observability_allowed, only: :index
+ before_action :check_observability_allowed
- def index
- # Format: https://observe.gitlab.com/-/GROUP_ID
- @observability_iframe_src = "#{ObservabilityController.observability_url}/-/#{@group.id}"
+ def dashboards
+ render_observability
+ end
- # Uncomment below for testing with local GDK
- # @observability_iframe_src = "#{ObservabilityController.observability_url}/9970?groupId=14485840"
+ def manage
+ render_observability
+ end
- render layout: 'group', locals: { base_layout: 'layouts/fullscreen' }
+ def explore
+ render_observability
end
private
+ def render_observability
+ render 'observability', layout: 'group', locals: { base_layout: 'layouts/fullscreen' }
+ end
+
def self.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
- return "https://staging.observe.gitlab.com" if Gitlab.staging?
+ Gitlab::Observability.observability_url
+ end
- "https://observe.gitlab.com"
+ def observability_url
+ self.class.observability_url
end
def check_observability_allowed
- return render_404 unless self.class.observability_url.present?
+ return render_404 unless observability_url.present?
render_404 unless can?(current_user, :read_observability, @group)
end
diff --git a/app/controllers/groups/registry/repositories_controller.rb b/app/controllers/groups/registry/repositories_controller.rb
index bb2d08e487a..cb7bf001918 100644
--- a/app/controllers/groups/registry/repositories_controller.rb
+++ b/app/controllers/groups/registry/repositories_controller.rb
@@ -8,10 +8,6 @@ module Groups
before_action :verify_container_registry_enabled!
before_action :authorize_read_container_image!
- before_action do
- push_frontend_feature_flag(:container_registry_show_shortened_path, group)
- end
-
feature_category :container_registry
urgency :low
diff --git a/app/controllers/groups/settings/access_tokens_controller.rb b/app/controllers/groups/settings/access_tokens_controller.rb
index f01b2b779e3..d86ddcfe2d0 100644
--- a/app/controllers/groups/settings/access_tokens_controller.rb
+++ b/app/controllers/groups/settings/access_tokens_controller.rb
@@ -3,6 +3,7 @@
module Groups
module Settings
class AccessTokensController < Groups::ApplicationController
+ include RenderAccessTokens
include AccessTokensActions
layout 'group_settings'
diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb
index e164a834519..b1afac1f1c7 100644
--- a/app/controllers/groups/settings/ci_cd_controller.rb
+++ b/app/controllers/groups/settings/ci_cd_controller.rb
@@ -10,9 +10,6 @@ module Groups
before_action :define_variables, only: [:show]
before_action :push_licensed_features, only: [:show]
before_action :assign_variables_to_gon, only: [:show]
- before_action do
- push_frontend_feature_flag(:ci_variable_settings_graphql, @group)
- end
feature_category :continuous_integration
urgency :low
diff --git a/app/controllers/groups/settings/packages_and_registries_controller.rb b/app/controllers/groups/settings/packages_and_registries_controller.rb
index 411b8577c3f..ec4a0b312ee 100644
--- a/app/controllers/groups/settings/packages_and_registries_controller.rb
+++ b/app/controllers/groups/settings/packages_and_registries_controller.rb
@@ -7,6 +7,10 @@ module Groups
before_action :authorize_admin_group!
before_action :verify_packages_enabled!
+ before_action do
+ push_frontend_feature_flag(:maven_central_request_forwarding, group)
+ end
+
feature_category :package_registry
urgency :low
diff --git a/app/controllers/groups/settings/repository_controller.rb b/app/controllers/groups/settings/repository_controller.rb
index cb62ea2a543..ecd5d814fb6 100644
--- a/app/controllers/groups/settings/repository_controller.rb
+++ b/app/controllers/groups/settings/repository_controller.rb
@@ -8,9 +8,6 @@ module Groups
before_action :authorize_create_deploy_token!, only: :create_deploy_token
before_action :authorize_access!, only: :show
before_action :define_deploy_token_variables, if: -> { can?(current_user, :create_deploy_token, @group) }
- before_action do
- push_frontend_feature_flag(:ajax_new_deploy_token, @group)
- end
feature_category :continuous_delivery
urgency :low
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 269342a6c22..3f516c24a69 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -35,6 +35,7 @@ class GroupsController < Groups::ApplicationController
before_action :track_experiment_event, only: [:new]
before_action only: :issues do
+ push_frontend_feature_flag(:or_issuable_queries, group)
push_force_frontend_feature_flag(:work_items, group.work_items_feature_flag_enabled?)
end
@@ -111,7 +112,7 @@ class GroupsController < Groups::ApplicationController
def details
respond_to do |format|
format.html do
- render_details_html
+ redirect_to group_path(group)
end
format.atom do
@@ -235,10 +236,6 @@ class GroupsController < Groups::ApplicationController
render 'groups/show', locals: { trial: params[:trial] }
end
- def render_details_html
- render 'groups/show'
- end
-
def render_details_view_atom
load_events
render layout: 'xml', template: 'groups/show'
diff --git a/app/controllers/jira_connect/application_controller.rb b/app/controllers/jira_connect/application_controller.rb
index e26d69314cd..b9f0ea795e1 100644
--- a/app/controllers/jira_connect/application_controller.rb
+++ b/app/controllers/jira_connect/application_controller.rb
@@ -3,6 +3,11 @@
class JiraConnect::ApplicationController < ApplicationController
include Gitlab::Utils::StrongMemoize
+ CORS_ALLOWED_METHODS = {
+ '/-/jira_connect/oauth_application_id' => %i[GET OPTIONS],
+ '/-/jira_connect/subscriptions/*' => %i[DELETE OPTIONS]
+ }.freeze
+
skip_before_action :authenticate_user!
skip_before_action :verify_authenticity_token
before_action :verify_atlassian_jwt!
@@ -60,4 +65,25 @@ class JiraConnect::ApplicationController < ApplicationController
def auth_token
params[:jwt] || request.headers['Authorization']&.split(' ', 2)&.last
end
+
+ def cors_allowed_methods
+ CORS_ALLOWED_METHODS[resource]
+ end
+
+ def resource
+ request.path.gsub(%r{/\d+$}, '/*')
+ end
+
+ def set_cors_headers
+ return unless allow_cors_request?
+
+ response.set_header('Access-Control-Allow-Origin', Gitlab::CurrentSettings.jira_connect_proxy_url)
+ response.set_header('Access-Control-Allow-Methods', cors_allowed_methods.join(', '))
+ end
+
+ def allow_cors_request?
+ return false if cors_allowed_methods.nil?
+
+ !Gitlab.com? && Gitlab::CurrentSettings.jira_connect_proxy_url.present?
+ end
end
diff --git a/app/controllers/jira_connect/cors_preflight_checks_controller.rb b/app/controllers/jira_connect/cors_preflight_checks_controller.rb
new file mode 100644
index 00000000000..3f30c1e04df
--- /dev/null
+++ b/app/controllers/jira_connect/cors_preflight_checks_controller.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module JiraConnect
+ class CorsPreflightChecksController < ApplicationController
+ feature_category :integrations
+
+ skip_before_action :verify_atlassian_jwt!
+ before_action :set_cors_headers
+
+ def index
+ return render_404 unless allow_cors_request?
+
+ render plain: '', content_type: 'text/plain'
+ end
+ end
+end
diff --git a/app/controllers/jira_connect/oauth_application_ids_controller.rb b/app/controllers/jira_connect/oauth_application_ids_controller.rb
index a84b47f4c8b..3e788e2282e 100644
--- a/app/controllers/jira_connect/oauth_application_ids_controller.rb
+++ b/app/controllers/jira_connect/oauth_application_ids_controller.rb
@@ -1,11 +1,11 @@
# frozen_string_literal: true
module JiraConnect
- class OauthApplicationIdsController < ::ApplicationController
+ class OauthApplicationIdsController < ApplicationController
feature_category :integrations
- skip_before_action :authenticate_user!
- skip_before_action :verify_authenticity_token
+ skip_before_action :verify_atlassian_jwt!
+ before_action :set_cors_headers
def show
if show_application_id?
diff --git a/app/controllers/jira_connect/subscriptions_controller.rb b/app/controllers/jira_connect/subscriptions_controller.rb
index 9305f46c39e..9a732cadd94 100644
--- a/app/controllers/jira_connect/subscriptions_controller.rb
+++ b/app/controllers/jira_connect/subscriptions_controller.rb
@@ -27,6 +27,7 @@ class JiraConnect::SubscriptionsController < JiraConnect::ApplicationController
before_action :verify_qsh_claim!, only: :index
before_action :allow_self_managed_content_security_policy, only: :index
before_action :authenticate_user!, only: :create
+ before_action :set_cors_headers
def index
@subscriptions = current_jira_installation.subscriptions.preload_namespace_route
@@ -64,7 +65,7 @@ class JiraConnect::SubscriptionsController < JiraConnect::ApplicationController
private
def allow_self_managed_content_security_policy
- return unless Feature.enabled?(:jira_connect_oauth_self_managed)
+ return unless Feature.enabled?(:jira_connect_oauth_self_managed_setting)
return unless current_jira_installation.instance_url?
@@ -83,7 +84,8 @@ class JiraConnect::SubscriptionsController < JiraConnect::ApplicationController
def allowed_instance_connect_src
[
Gitlab::Utils.append_path(current_jira_installation.instance_url, '/-/jira_connect/'),
- Gitlab::Utils.append_path(current_jira_installation.instance_url, '/api/')
+ Gitlab::Utils.append_path(current_jira_installation.instance_url, '/api/'),
+ Gitlab::Utils.append_path(current_jira_installation.instance_url, '/oauth/token')
]
end
end
diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb
index bf8b61db2e5..43bf895ea76 100644
--- a/app/controllers/oauth/authorizations_controller.rb
+++ b/app/controllers/oauth/authorizations_controller.rb
@@ -4,7 +4,7 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
include InitializesCurrentUserMode
include Gitlab::Utils::StrongMemoize
- before_action :verify_confirmed_email!
+ before_action :verify_confirmed_email!, :verify_admin_allowed!
layout 'profile'
@@ -97,4 +97,19 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
pre_auth.error = :unconfirmed_email
render "doorkeeper/authorizations/error"
end
+
+ def verify_admin_allowed!
+ render "doorkeeper/authorizations/forbidden" if disallow_connect?
+ end
+
+ def disallow_connect?
+ # we're disabling Cop/UserAdmin as OAuth tokens don't seem to respect admin mode
+ current_user&.admin? && Gitlab::CurrentSettings.disable_admin_oauth_scopes && dangerous_scopes? # rubocop:disable Cop/UserAdmin
+ 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?
+ end
end
diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb
index ead5d7c9026..1216353be36 100644
--- a/app/controllers/passwords_controller.rb
+++ b/app/controllers/passwords_controller.rb
@@ -2,6 +2,7 @@
class PasswordsController < Devise::PasswordsController
include GitlabRecaptcha
+ include Gitlab::Tracking::Helpers::WeakPasswordErrorEvent
skip_before_action :require_no_authentication, only: [:edit, :update]
@@ -41,6 +42,8 @@ class PasswordsController < Devise::PasswordsController
resource.password_automatically_set = false
resource.password_expires_at = nil
resource.save(validate: false) if resource.changed?
+ else
+ track_weak_password_error(@user, self.class.name, 'create')
end
end
end
diff --git a/app/controllers/profiles/passwords_controller.rb b/app/controllers/profiles/passwords_controller.rb
index 5eb0f80ddc9..738c41207d5 100644
--- a/app/controllers/profiles/passwords_controller.rb
+++ b/app/controllers/profiles/passwords_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Profiles::PasswordsController < Profiles::ApplicationController
+ include Gitlab::Tracking::Helpers::WeakPasswordErrorEvent
+
skip_before_action :check_password_expiration, only: [:new, :create]
skip_before_action :check_two_factor_requirement, only: [:new, :create]
@@ -27,6 +29,7 @@ class Profiles::PasswordsController < Profiles::ApplicationController
redirect_to root_path, notice: _('Password successfully changed')
else
+ track_weak_password_error(@user, self.class.name, 'create')
render :new
end
end
@@ -48,6 +51,7 @@ class Profiles::PasswordsController < Profiles::ApplicationController
flash[:notice] = _('Password was successfully updated. Please sign in again.')
redirect_to new_user_session_path
else
+ track_weak_password_error(@user, self.class.name, 'update')
@user.reset
render 'edit'
end
@@ -94,3 +98,5 @@ class Profiles::PasswordsController < Profiles::ApplicationController
}
end
end
+
+Profiles::PasswordsController.prepend_mod
diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb
index 4cf26d3e1e2..1663aa61f62 100644
--- a/app/controllers/profiles/personal_access_tokens_controller.rb
+++ b/app/controllers/profiles/personal_access_tokens_controller.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
+ include RenderAccessTokens
+
feature_category :authentication_and_authorization
before_action :check_personal_access_tokens_enabled
@@ -16,7 +18,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
respond_to do |format|
format.html
format.json do
- render json: @active_personal_access_tokens
+ render json: @active_access_tokens
end
end
end
@@ -30,7 +32,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
if result.success?
render json: { new_token: @personal_access_token.token,
- active_access_tokens: active_personal_access_tokens }, status: :ok
+ active_access_tokens: active_access_tokens }, status: :ok
else
render json: { errors: result.errors }, status: :unprocessable_entity
end
@@ -56,36 +58,13 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
def set_index_vars
@scopes = Gitlab::Auth.available_scopes_for(current_user)
- @active_personal_access_tokens = active_personal_access_tokens
+ @active_access_tokens = active_access_tokens
end
- def active_personal_access_tokens
- tokens = finder(state: 'active', sort: 'expires_at_asc_id_desc').execute
-
- if Feature.enabled?('access_token_pagination')
- tokens = tokens.page(page)
- add_pagination_headers(tokens)
- end
-
+ def represent(tokens)
::PersonalAccessTokenSerializer.new.represent(tokens)
end
- def add_pagination_headers(relation)
- Gitlab::Pagination::OffsetHeaderBuilder.new(
- request_context: self,
- per_page: relation.limit_value,
- page: relation.current_page,
- next_page: relation.next_page,
- prev_page: relation.prev_page,
- total: relation.total_count,
- params: params.permit(:page)
- ).execute
- end
-
- def page
- (params[:page] || 1).to_i
- end
-
def check_personal_access_tokens_enabled
render_404 if Gitlab::CurrentSettings.personal_access_tokens_disabled?
end
diff --git a/app/controllers/projects/alerting/notifications_controller.rb b/app/controllers/projects/alerting/notifications_controller.rb
index f3283c88740..89e8a261288 100644
--- a/app/controllers/projects/alerting/notifications_controller.rb
+++ b/app/controllers/projects/alerting/notifications_controller.rb
@@ -18,8 +18,9 @@ module Projects
def create
token = extract_alert_manager_token(request)
result = notify_service.execute(token, integration)
+ has_something_to_return = result.success? && result.http_status != :created
- if result.success?
+ if has_something_to_return
render json: AlertManagement::AlertSerializer.new.represent(result.payload[:alerts]), code: result.http_status
else
head result.http_status
diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb
index 2256471047d..25b83aed78a 100644
--- a/app/controllers/projects/application_controller.rb
+++ b/app/controllers/projects/application_controller.rb
@@ -38,9 +38,9 @@ class Projects::ApplicationController < ApplicationController
if build.debug_mode?
access_denied!(
_('You must have developer or higher permissions in the associated project to view job logs when debug trace ' \
- "is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline " \
- 'configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add ' \
- 'you to the project with developer permissions or higher.')
+ "is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' " \
+ 'in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer ' \
+ 'or owner must add you to the project with developer permissions or higher.')
)
else
access_denied!(_('The current user is not authorized to access the job log.'))
diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb
index 40e89a06b46..c3dcde38d09 100644
--- a/app/controllers/projects/artifacts_controller.rb
+++ b/app/controllers/projects/artifacts_controller.rb
@@ -4,6 +4,7 @@ class Projects::ArtifactsController < Projects::ApplicationController
include ExtractsPath
include RendersBlob
include SendFileUpload
+ include Gitlab::Ci::Artifacts::Logger
urgency :low, [:browse, :file, :latest_succeeded]
@@ -26,12 +27,6 @@ class Projects::ArtifactsController < Projects::ApplicationController
# It should be removed only after resolving the underlying performance
# issues: https://gitlab.com/gitlab-org/gitlab/issues/32281
return head :no_content unless Feature.enabled?(:artifacts_management_page, @project)
-
- finder = Ci::JobArtifactsFinder.new(@project, artifacts_params)
- all_artifacts = finder.execute
-
- @artifacts = all_artifacts.page(params[:page]).per(MAX_PER_PAGE)
- @total_size = all_artifacts.total_size
end
def destroy
@@ -47,6 +42,7 @@ class Projects::ArtifactsController < Projects::ApplicationController
def download
return render_404 unless artifacts_file
+ log_artifacts_filesize(artifacts_file.model)
send_upload(artifacts_file, attachment: artifacts_file.filename, proxy: params[:proxy])
end
diff --git a/app/controllers/projects/boards_controller.rb b/app/controllers/projects/boards_controller.rb
index 6a6701ead15..84872d1e978 100644
--- a/app/controllers/projects/boards_controller.rb
+++ b/app/controllers/projects/boards_controller.rb
@@ -7,7 +7,7 @@ class Projects::BoardsController < Projects::ApplicationController
before_action :check_issues_available!
before_action do
push_frontend_feature_flag(:board_multi_select, project)
- push_frontend_feature_flag(:realtime_labels, project&.group)
+ push_frontend_feature_flag(:apollo_boards, project)
experiment(:prominent_create_board_btn, subject: current_user) do |e|
e.control {}
e.candidate {}
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 2b2764d2e34..870320a79d9 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -86,7 +86,7 @@ class Projects::CommitController < Projects::ApplicationController
respond_to do |format|
format.json do
- render json: @merge_requests.to_json
+ render json: Gitlab::Json.dump(@merge_requests)
end
end
end
diff --git a/app/controllers/projects/environments_controller.rb b/app/controllers/projects/environments_controller.rb
index 4f037cc843e..67f2f85ce65 100644
--- a/app/controllers/projects/environments_controller.rb
+++ b/app/controllers/projects/environments_controller.rb
@@ -183,7 +183,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
def metrics
respond_to do |format|
format.html do
- redirect_to project_metrics_dashboard_path(project, environment: environment )
+ redirect_to project_metrics_dashboard_path(project, environment: environment)
end
format.json do
# Currently, this acts as a hint to load the metrics details into the cache
diff --git a/app/controllers/projects/google_cloud/configuration_controller.rb b/app/controllers/projects/google_cloud/configuration_controller.rb
index 06a6674d578..e109ab95d39 100644
--- a/app/controllers/projects/google_cloud/configuration_controller.rb
+++ b/app/controllers/projects/google_cloud/configuration_controller.rb
@@ -15,7 +15,7 @@ module Projects
gcpRegions: gcp_regions,
revokeOauthUrl: revoke_oauth_url
}
- @js_data = js_data.to_json
+ @js_data = Gitlab::Json.dump(js_data)
track_event(:render_page)
end
diff --git a/app/controllers/projects/google_cloud/databases_controller.rb b/app/controllers/projects/google_cloud/databases_controller.rb
index 77ee830fd24..b511a85b0b8 100644
--- a/app/controllers/projects/google_cloud/databases_controller.rb
+++ b/app/controllers/projects/google_cloud/databases_controller.rb
@@ -17,7 +17,8 @@ module Projects
cloudsqlInstances: ::GoogleCloud::GetCloudsqlInstancesService.new(project).execute,
emptyIllustrationUrl: ActionController::Base.helpers.image_path('illustrations/pipelines_empty.svg')
}
- @js_data = js_data.to_json
+
+ @js_data = Gitlab::Json.dump(js_data)
track_event(:render_page)
end
@@ -27,7 +28,7 @@ module Projects
@title = title(product)
- @js_data = {
+ js_data = {
gcpProjects: gcp_projects,
refs: refs,
cancelPath: project_google_cloud_databases_path(project),
@@ -35,7 +36,9 @@ module Projects
formDescription: description(product),
databaseVersions: Projects::GoogleCloud::CloudsqlHelper::VERSIONS[product],
tiers: Projects::GoogleCloud::CloudsqlHelper::TIERS
- }.to_json
+ }
+
+ @js_data = Gitlab::Json.dump(js_data)
track_event(:render_form)
render template: 'projects/google_cloud/databases/cloudsql_form', formats: :html
diff --git a/app/controllers/projects/google_cloud/deployments_controller.rb b/app/controllers/projects/google_cloud/deployments_controller.rb
index f6cc8d5eafb..041486eb2fb 100644
--- a/app/controllers/projects/google_cloud/deployments_controller.rb
+++ b/app/controllers/projects/google_cloud/deployments_controller.rb
@@ -11,7 +11,7 @@ class Projects::GoogleCloud::DeploymentsController < Projects::GoogleCloud::Base
enableCloudRunUrl: project_google_cloud_deployments_cloud_run_path(project),
enableCloudStorageUrl: project_google_cloud_deployments_cloud_storage_path(project)
}
- @js_data = js_data.to_json
+ @js_data = Gitlab::Json.dump(js_data)
track_event(:render_page)
end
diff --git a/app/controllers/projects/google_cloud/gcp_regions_controller.rb b/app/controllers/projects/google_cloud/gcp_regions_controller.rb
index 2f0bc05030f..c51261721b2 100644
--- a/app/controllers/projects/google_cloud/gcp_regions_controller.rb
+++ b/app/controllers/projects/google_cloud/gcp_regions_controller.rb
@@ -14,7 +14,7 @@ class Projects::GoogleCloud::GcpRegionsController < Projects::GoogleCloud::BaseC
refs: refs,
cancelPath: project_google_cloud_configuration_path(project)
}
- @js_data = js_data.to_json
+ @js_data = Gitlab::Json.dump(js_data)
track_event(:render_form)
end
diff --git a/app/controllers/projects/google_cloud/service_accounts_controller.rb b/app/controllers/projects/google_cloud/service_accounts_controller.rb
index 89d624764df..7b029e25ea2 100644
--- a/app/controllers/projects/google_cloud/service_accounts_controller.rb
+++ b/app/controllers/projects/google_cloud/service_accounts_controller.rb
@@ -14,7 +14,7 @@ class Projects::GoogleCloud::ServiceAccountsController < Projects::GoogleCloud::
refs: refs,
cancelPath: project_google_cloud_configuration_path(project)
}
- @js_data = js_data.to_json
+ @js_data = Gitlab::Json.dump(js_data)
track_event(:render_form)
end
diff --git a/app/controllers/projects/graphs_controller.rb b/app/controllers/projects/graphs_controller.rb
index 47557133ac8..6da70b5e157 100644
--- a/app/controllers/projects/graphs_controller.rb
+++ b/app/controllers/projects/graphs_controller.rb
@@ -104,7 +104,7 @@ class Projects::GraphsController < Projects::ApplicationController
}
end
- render json: @log.to_json
+ render json: Gitlab::Json.dump(@log)
end
def tracking_namespace_source
diff --git a/app/controllers/projects/incidents_controller.rb b/app/controllers/projects/incidents_controller.rb
index 089ee860ea6..599505dcb6d 100644
--- a/app/controllers/projects/incidents_controller.rb
+++ b/app/controllers/projects/incidents_controller.rb
@@ -9,7 +9,6 @@ class Projects::IncidentsController < Projects::ApplicationController
before_action do
push_force_frontend_feature_flag(:work_items, @project&.work_items_feature_flag_enabled?)
push_force_frontend_feature_flag(:work_items_mvc_2, @project&.work_items_mvc_2_feature_flag_enabled?)
- push_frontend_feature_flag(:work_items_hierarchy, @project)
end
feature_category :incident_management
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 5b1117c0224..ee845cd001e 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
class Projects::IssuesController < Projects::ApplicationController
- include RendersNotes
include ToggleSubscriptionAction
include IssuableActions
include ToggleAwardEmoji
@@ -49,11 +48,14 @@ class Projects::IssuesController < Projects::ApplicationController
push_force_frontend_feature_flag(:work_items, project&.work_items_feature_flag_enabled?)
end
+ before_action only: :index do
+ push_frontend_feature_flag(:or_issuable_queries, project)
+ end
+
before_action only: :show do
push_frontend_feature_flag(:issue_assignees_widget, project)
- push_frontend_feature_flag(:realtime_labels, project)
+ push_frontend_feature_flag(:work_items_mvc, project&.group)
push_force_frontend_feature_flag(:work_items_mvc_2, project&.work_items_mvc_2_feature_flag_enabled?)
- push_frontend_feature_flag(:work_items_hierarchy, project)
push_frontend_feature_flag(:epic_widget_edit_confirmation, project)
push_force_frontend_feature_flag(:work_items_create_from_markdown, project&.work_items_create_from_markdown_feature_flag_enabled?)
end
@@ -405,7 +407,6 @@ class Projects::IssuesController < Projects::ApplicationController
options = super
options[:issue_types] = Issue::TYPES_FOR_LIST
- options[:issue_types] = options[:issue_types].excluding('task') unless project.work_items_feature_flag_enabled?
if service_desk?
options.reject! { |key| key == 'author_username' || key == 'author_id' }
@@ -432,10 +433,13 @@ class Projects::IssuesController < Projects::ApplicationController
def create_vulnerability_issue_feedback(issue); end
def redirect_if_task
- return render_404 if issue.task? && !project.work_items_feature_flag_enabled?
return unless issue.task?
- redirect_to project_work_items_path(project, issue.id, params: request.query_parameters)
+ 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
end
end
diff --git a/app/controllers/projects/labels_controller.rb b/app/controllers/projects/labels_controller.rb
index 8ec2cbb41e9..14f2e372bc5 100644
--- a/app/controllers/projects/labels_controller.rb
+++ b/app/controllers/projects/labels_controller.rb
@@ -68,9 +68,10 @@ class Projects::LabelsController < Projects::ApplicationController
def generate
Gitlab::IssuesLabels.generate(@project)
- if params[:redirect] == 'issues'
+ case params[:redirect]
+ when 'issues'
redirect_to project_issues_path(@project)
- elsif params[:redirect] == 'merge_requests'
+ when 'merge_requests'
redirect_to project_merge_requests_path(@project)
else
redirect_to project_labels_path(@project)
diff --git a/app/controllers/projects/learn_gitlab_controller.rb b/app/controllers/projects/learn_gitlab_controller.rb
index 61e4a1812ba..6fe009c8a28 100644
--- a/app/controllers/projects/learn_gitlab_controller.rb
+++ b/app/controllers/projects/learn_gitlab_controller.rb
@@ -23,7 +23,6 @@ class Projects::LearnGitlabController < Projects::ApplicationController
experiment(:invite_for_help_continuous_onboarding, namespace: project.namespace) do |e|
e.candidate {}
- e.publish_to_database
end
end
diff --git a/app/controllers/projects/merge_requests/diffs_controller.rb b/app/controllers/projects/merge_requests/diffs_controller.rb
index 418e7233e21..c88dbc70ed5 100644
--- a/app/controllers/projects/merge_requests/diffs_controller.rb
+++ b/app/controllers/projects/merge_requests/diffs_controller.rb
@@ -38,16 +38,13 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
diffs = @compare.diffs_in_batch(params[:page], params[:per_page], diff_options: diff_options_hash)
unfoldable_positions = @merge_request.note_positions_for_paths(diffs.diff_file_paths, current_user).unfoldable
- diffs.unfold_diff_files(unfoldable_positions)
- diffs.write_cache
-
options = {
merge_request: @merge_request,
commit: commit,
diff_view: diff_view,
merge_ref_head_diff: render_merge_ref_head_diff?,
pagination_data: diffs.pagination_data,
- allow_tree_conflicts: display_merge_conflicts_in_diff?
+ merge_conflicts_in_diff: display_merge_conflicts_in_diff?
}
# NOTE: Any variables that would affect the resulting json needs to be added to the cache_context to avoid stale cache issues.
@@ -60,10 +57,19 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
params[:page],
params[:per_page],
options[:merge_ref_head_diff],
- options[:allow_tree_conflicts]
+ options[:merge_conflicts_in_diff]
]
- return unless stale?(etag: [cache_context + diff_options_hash.fetch(:paths, []), diffs])
+ if Feature.enabled?(:check_etags_diffs_batch_before_write_cache, merge_request.project) && !stale?(etag: [cache_context + diff_options_hash.fetch(:paths, []), diffs])
+ return
+ end
+
+ diffs.unfold_diff_files(unfoldable_positions)
+ diffs.write_cache
+
+ if Feature.disabled?(:check_etags_diffs_batch_before_write_cache, merge_request.project) && !stale?(etag: [cache_context + diff_options_hash.fetch(:paths, []), diffs])
+ return
+ end
render json: PaginatedDiffSerializer.new(current_user: current_user).represent(diffs, options)
end
@@ -75,7 +81,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
options = additional_attributes.merge(
only_context_commits: show_only_context_commits?,
merge_ref_head_diff: render_merge_ref_head_diff?,
- allow_tree_conflicts: display_merge_conflicts_in_diff?
+ merge_conflicts_in_diff: display_merge_conflicts_in_diff?
)
render json: DiffsMetadataSerializer.new(project: @merge_request.project, current_user: current_user)
@@ -104,7 +110,7 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
options = additional_attributes.merge(
diff_view: "inline",
merge_ref_head_diff: render_merge_ref_head_diff?,
- allow_tree_conflicts: display_merge_conflicts_in_diff?
+ merge_conflicts_in_diff: display_merge_conflicts_in_diff?
)
options[:context_commits] = @merge_request.recent_context_commits
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 9c139733248..4ba79d43f27 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -3,7 +3,6 @@
class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationController
include ToggleSubscriptionAction
include IssuableActions
- include RendersNotes
include RendersCommits
include RendersAssignees
include ToggleAwardEmoji
@@ -32,18 +31,15 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
before_action :check_user_can_push_to_source_branch!, only: [:rebase]
before_action only: [:show] do
- push_frontend_feature_flag(:merge_request_widget_graphql, project)
push_frontend_feature_flag(:core_security_mr_widget_counts, project)
- push_frontend_feature_flag(:refactor_code_quality_extension, project)
- push_frontend_feature_flag(:refactor_mr_widget_test_summary, project)
push_frontend_feature_flag(:issue_assignees_widget, @project)
- push_frontend_feature_flag(:realtime_labels, project)
push_frontend_feature_flag(:refactor_security_extension, @project)
push_frontend_feature_flag(:refactor_code_quality_inline_findings, project)
push_frontend_feature_flag(:moved_mr_sidebar, project)
push_frontend_feature_flag(:paginated_mr_discussions, project)
push_frontend_feature_flag(:mr_review_submit_comment, project)
push_frontend_feature_flag(:mr_experience_survey, project)
+ push_frontend_feature_flag(:realtime_reviewers, project)
end
before_action do
@@ -123,12 +119,13 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
@commits_count = @merge_request.commits_count + @merge_request.context_commits_count
@diffs_count = get_diffs_count
@issuable_sidebar = serializer.represent(@merge_request, serializer: 'sidebar')
- @current_user_data = UserSerializer.new(project: @project).represent(current_user, {}, MergeRequestCurrentUserEntity).to_json
+ @current_user_data = Gitlab::Json.dump(UserSerializer.new(project: @project).represent(current_user, {}, MergeRequestCurrentUserEntity))
@show_whitespace_default = current_user.nil? || current_user.show_whitespace_in_diffs
@file_by_file_default = current_user&.view_diffs_file_by_file
@coverage_path = coverage_reports_project_merge_request_path(@project, @merge_request, format: :json) if @merge_request.has_coverage_reports?
@update_current_user_path = expose_path(api_v4_user_preferences_path)
@endpoint_metadata_url = endpoint_metadata_url(@project, @merge_request)
+ @endpoint_diff_batch_url = endpoint_diff_batch_url(@project, @merge_request)
set_pipeline_variables
@@ -179,15 +176,15 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
@merge_request.recent_context_commits
)
- # Get commits from repository
- # or from cache if already merged
- @commits =
- set_commits_for_rendering(
- @merge_request.recent_commits(load_from_gitaly: true).with_latest_pipeline(@merge_request.source_branch).with_markdown_cache,
- commits_count: @merge_request.commits_count
- )
+ per_page = [(params[:per_page] || MergeRequestDiff::COMMITS_SAFE_SIZE).to_i, MergeRequestDiff::COMMITS_SAFE_SIZE].min
+ recent_commits = @merge_request.recent_commits(load_from_gitaly: true, limit: per_page, page: params[:page]).with_latest_pipeline(@merge_request.source_branch).with_markdown_cache
+ @next_page = recent_commits.next_page
+ @commits = set_commits_for_rendering(
+ recent_commits,
+ commits_count: @merge_request.commits_count
+ )
- render json: { html: view_to_html_string('projects/merge_requests/_commits') }
+ render json: { html: view_to_html_string('projects/merge_requests/_commits'), next_page: @next_page }
end
def pipelines
@@ -535,7 +532,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
render json: '', status: :no_content
when :parsed
- render json: report_comparison[:data].to_json, status: :ok
+ render json: Gitlab::Json.dump(report_comparison[:data]), status: :ok
when :error
render json: { status_reason: report_comparison[:status_reason] }, status: :bad_request
else
@@ -553,12 +550,23 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
return render_404 unless can?(current_user, :read_build, merge_request.actual_head_pipeline)
end
+ def show_whitespace
+ current_user&.show_whitespace_in_diffs ? '0' : '1'
+ end
+
def endpoint_metadata_url(project, merge_request)
- params = request.query_parameters.merge(view: 'inline', diff_head: true, w: current_user&.show_whitespace_in_diffs ? '0' : '1')
+ params = request.query_parameters.merge(view: 'inline', diff_head: true, w: show_whitespace)
diffs_metadata_project_json_merge_request_path(project, merge_request, 'json', params)
end
+ def endpoint_diff_batch_url(project, merge_request)
+ per_page = current_user&.view_diffs_file_by_file ? '1' : '5'
+ params = request.query_parameters.merge(view: 'inline', diff_head: true, w: show_whitespace, page: '0', per_page: per_page)
+
+ diffs_batch_project_json_merge_request_path(project, merge_request, 'json', params)
+ end
+
def convert_date_to_epoch(date)
Date.strptime(date, "%Y-%m-%d")&.to_time&.to_i if date
rescue Date::Error, TypeError
diff --git a/app/controllers/projects/ml/experiments_controller.rb b/app/controllers/projects/ml/experiments_controller.rb
new file mode 100644
index 00000000000..749586791ac
--- /dev/null
+++ b/app/controllers/projects/ml/experiments_controller.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module Projects
+ module Ml
+ class ExperimentsController < ::Projects::ApplicationController
+ include Projects::Ml::ExperimentsHelper
+ before_action :check_feature_flag
+
+ feature_category :mlops
+
+ MAX_PER_PAGE = 20
+
+ def index
+ @experiments = ::Ml::Experiment.by_project_id(@project.id).page(params[:page]).per(MAX_PER_PAGE)
+ end
+
+ def show
+ @experiment = ::Ml::Experiment.by_project_id_and_iid(@project.id, params[:id])
+
+ return redirect_to project_ml_experiments_path(@project) unless @experiment.present?
+
+ @candidates = @experiment.candidates&.including_metrics_and_params
+ end
+
+ private
+
+ def check_feature_flag
+ render_404 unless Feature.enabled?(:ml_experiment_tracking, @project)
+ end
+ end
+ end
+end
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index d24b232293b..9d3506d49b0 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -58,7 +58,7 @@ class Projects::NotesController < Projects::ApplicationController
def outdated_line_change
diff_lines = Rails.cache.fetch(['note', note.id, 'oudated_line_change'], expires_in: 7.days) do
- ::MergeRequests::OutdatedDiscussionDiffLinesService.new(project: note.noteable.source_project, note: note).execute.to_json
+ Gitlab::Json.dump(::MergeRequests::OutdatedDiscussionDiffLinesService.new(project: note.noteable.source_project, note: note).execute)
end
render json: diff_lines
diff --git a/app/controllers/projects/packages/infrastructure_registry_controller.rb b/app/controllers/projects/packages/infrastructure_registry_controller.rb
index f1410bf6043..733df9fdb45 100644
--- a/app/controllers/projects/packages/infrastructure_registry_controller.rb
+++ b/app/controllers/projects/packages/infrastructure_registry_controller.rb
@@ -5,7 +5,7 @@ module Projects
class InfrastructureRegistryController < Projects::ApplicationController
include PackagesAccess
- feature_category :infrastructure_as_code
+ feature_category :package_registry
urgency :low
def show
diff --git a/app/controllers/projects/pipeline_schedules_controller.rb b/app/controllers/projects/pipeline_schedules_controller.rb
index ca787785901..31030d958df 100644
--- a/app/controllers/projects/pipeline_schedules_controller.rb
+++ b/app/controllers/projects/pipeline_schedules_controller.rb
@@ -98,7 +98,7 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
def schedule_params
params.require(:schedule)
.permit(:description, :cron, :cron_timezone, :ref, :active,
- variables_attributes: [:id, :variable_type, :key, :secret_value, :_destroy] )
+ variables_attributes: [:id, :variable_type, :key, :secret_value, :_destroy])
end
def authorize_play_pipeline_schedule!
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
index 01f7bb9e2cf..7d1a75ae449 100644
--- a/app/controllers/projects/pipelines_controller.rb
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -140,21 +140,13 @@ class Projects::PipelinesController < Projects::ApplicationController
end
def builds
- if Feature.enabled?(:pipeline_tabs_vue, project)
- redirect_to pipeline_path(@pipeline, tab: 'builds')
- else
- render_show
- end
+ render_show
end
def dag
respond_to do |format|
format.html do
- if Feature.enabled?(:pipeline_tabs_vue, project)
- redirect_to pipeline_path(@pipeline, tab: 'dag')
- else
- render_show
- end
+ render_show
end
format.json do
render json: Ci::DagPipelineSerializer
@@ -165,9 +157,7 @@ class Projects::PipelinesController < Projects::ApplicationController
end
def failures
- if Feature.enabled?(:pipeline_tabs_vue, project)
- redirect_to pipeline_path(@pipeline, tab: 'failures')
- elsif @pipeline.failed_builds.present?
+ if @pipeline.failed_builds.present?
render_show
else
redirect_to pipeline_path(@pipeline)
@@ -222,11 +212,7 @@ class Projects::PipelinesController < Projects::ApplicationController
def test_report
respond_to do |format|
format.html do
- if Feature.enabled?(:pipeline_tabs_vue, project)
- redirect_to pipeline_path(@pipeline, tab: 'test_report')
- else
- render_show
- end
+ render_show
end
format.json do
render json: TestReportSerializer
@@ -352,7 +338,6 @@ class Projects::PipelinesController < Projects::ApplicationController
experiment(:runners_availability_section, namespace: project.root_ancestor) do |e|
e.candidate {}
- e.publish_to_database
end
end
diff --git a/app/controllers/projects/product_analytics_controller.rb b/app/controllers/projects/product_analytics_controller.rb
deleted file mode 100644
index 8085b0a6334..00000000000
--- a/app/controllers/projects/product_analytics_controller.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-# frozen_string_literal: true
-
-class Projects::ProductAnalyticsController < Projects::ApplicationController
- before_action :feature_enabled!, only: [:index, :setup, :test, :graphs]
- before_action :authorize_read_product_analytics!
- before_action :tracker_variables, only: [:setup, :test]
-
- feature_category :product_analytics
-
- def index
- @events = product_analytics_events.order_by_time.page(params[:page])
- end
-
- def setup
- end
-
- def test
- @event = product_analytics_events.try(:first)
- end
-
- def graphs
- @graphs = []
- @timerange = 30
-
- requested_graphs = %w(platform os_timezone br_lang doc_charset)
-
- requested_graphs.each do |graph|
- @graphs << ProductAnalytics::BuildGraphService
- .new(project, { graph: graph, timerange: @timerange })
- .execute
- end
-
- @activity_graph = ProductAnalytics::BuildActivityGraphService
- .new(project, { timerange: @timerange })
- .execute
- end
-
- private
-
- def product_analytics_events
- @project.product_analytics_events
- end
-
- def tracker_variables
- # We use project id as Snowplow appId
- @project_id = @project.id.to_s
-
- # Snowplow remembers values like appId and platform between reloads.
- # That is why we have to rename the tracker with a random integer.
- @random = rand(999999)
-
- # Generate random platform every time a tracker is rendered.
- @platform = %w(web mob app)[(@random % 3)]
- end
-
- def feature_enabled!
- render_404 unless Feature.enabled?(:product_analytics, @project)
- end
-end
-
-Projects::ProductAnalyticsController.prepend_mod_with('Projects::ProductAnalyticsController')
diff --git a/app/controllers/projects/prometheus/alerts_controller.rb b/app/controllers/projects/prometheus/alerts_controller.rb
index c3dc17694d9..27ac64e5758 100644
--- a/app/controllers/projects/prometheus/alerts_controller.rb
+++ b/app/controllers/projects/prometheus/alerts_controller.rb
@@ -23,11 +23,7 @@ module Projects
token = extract_alert_manager_token(request)
result = notify_service.execute(token)
- if result.success?
- render json: AlertManagement::AlertSerializer.new.represent(result.payload[:alerts]), code: result.http_status
- else
- head result.http_status
- end
+ head result.http_status
end
private
@@ -37,19 +33,6 @@ module Projects
.new(project, params.permit!)
end
- def serialize_as_json(alert_obj)
- serializer.represent(alert_obj)
- end
-
- def serializer
- PrometheusAlertSerializer
- .new(project: project, current_user: current_user)
- end
-
- def alerts
- alerts_finder.execute
- end
-
def alert
@alert ||= alerts_finder(metric: params[:id]).execute.first || render_404
end
diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb
index 87cb8e4781f..ffe95bf4fee 100644
--- a/app/controllers/projects/registry/repositories_controller.rb
+++ b/app/controllers/projects/registry/repositories_controller.rb
@@ -8,10 +8,6 @@ module Projects
before_action :authorize_update_container_image!, only: [:destroy]
- before_action do
- push_frontend_feature_flag(:container_registry_show_shortened_path, project)
- end
-
def index
respond_to do |format|
format.html { ensure_root_container_repository! }
@@ -26,7 +22,11 @@ module Projects
def destroy
image.delete_scheduled!
- DeleteContainerRepositoryWorker.perform_async(current_user.id, image.id) # rubocop:disable CodeReuse/Worker
+
+ unless Feature.enabled?(:container_registry_delete_repository_with_cron_worker)
+ DeleteContainerRepositoryWorker.perform_async(current_user.id, image.id) # rubocop:disable CodeReuse/Worker
+ end
+
track_package_event(:delete_repository, :container)
respond_to do |format|
diff --git a/app/controllers/projects/settings/access_tokens_controller.rb b/app/controllers/projects/settings/access_tokens_controller.rb
index bac35583a97..0884816ef62 100644
--- a/app/controllers/projects/settings/access_tokens_controller.rb
+++ b/app/controllers/projects/settings/access_tokens_controller.rb
@@ -3,6 +3,7 @@
module Projects
module Settings
class AccessTokensController < Projects::ApplicationController
+ include RenderAccessTokens
include AccessTokensActions
layout 'project_settings'
diff --git a/app/controllers/projects/settings/ci_cd_controller.rb b/app/controllers/projects/settings/ci_cd_controller.rb
index cda6c8abea7..8aef1c3d24d 100644
--- a/app/controllers/projects/settings/ci_cd_controller.rb
+++ b/app/controllers/projects/settings/ci_cd_controller.rb
@@ -11,10 +11,6 @@ module Projects
before_action :authorize_admin_pipeline!
before_action :check_builds_available!
before_action :define_variables
- before_action do
- push_frontend_feature_flag(:ajax_new_deploy_token, @project)
- push_frontend_feature_flag(:ci_variable_settings_graphql, @project)
- end
helper_method :highlight_badge
@@ -23,9 +19,11 @@ module Projects
def show
if Feature.enabled?(:ci_pipeline_triggers_settings_vue_ui, @project)
- @triggers_json = ::Ci::TriggerSerializer.new.represent(
+ triggers = ::Ci::TriggerSerializer.new.represent(
@project.triggers, current_user: current_user, project: @project
- ).to_json
+ )
+
+ @triggers_json = Gitlab::Json.dump(triggers)
end
render
diff --git a/app/controllers/projects/settings/repository_controller.rb b/app/controllers/projects/settings/repository_controller.rb
index 43c6451577a..90988645d3a 100644
--- a/app/controllers/projects/settings/repository_controller.rb
+++ b/app/controllers/projects/settings/repository_controller.rb
@@ -6,11 +6,8 @@ module Projects
layout 'project_settings'
before_action :authorize_admin_project!
before_action :define_variables, only: [:create_deploy_token]
- before_action do
- push_frontend_feature_flag(:ajax_new_deploy_token, @project)
- end
- feature_category :source_code_management, [:show, :cleanup]
+ feature_category :source_code_management, [:show, :cleanup, :update]
feature_category :continuous_delivery, [:create_deploy_token]
urgency :low, [:show, :create_deploy_token]
@@ -60,6 +57,19 @@ module Projects
end
end
+ def update
+ result = ::Projects::UpdateService.new(@project, current_user, project_params).execute
+
+ if result[:status] == :success
+ flash[:notice] = _("Project settings were successfully updated.")
+ else
+ flash[:alert] = result[:message]
+ @project.reset
+ end
+
+ redirect_to project_settings_repository_path(project)
+ end
+
private
def render_show
@@ -97,6 +107,18 @@ module Projects
params.require(:deploy_token).permit(:name, :expires_at, :read_repository, :read_registry, :write_registry, :read_package_registry, :write_package_registry, :username)
end
+ def project_params
+ params.require(:project).permit(project_params_attributes)
+ end
+
+ def project_params_attributes
+ [
+ :issue_branch_template,
+ :default_branch,
+ :autoclose_referenced_issues
+ ]
+ end
+
def access_levels_options
{
create_access_levels: levels_for_dropdown,
diff --git a/app/controllers/projects/starrers_controller.rb b/app/controllers/projects/starrers_controller.rb
index bc857648a06..06996e8e5fc 100644
--- a/app/controllers/projects/starrers_controller.rb
+++ b/app/controllers/projects/starrers_controller.rb
@@ -11,14 +11,8 @@ class Projects::StarrersController < Projects::ApplicationController
@starrers = UsersStarProjectsFinder.new(@project, params, current_user: @current_user).execute
@sort = params[:sort].presence || sort_value_name
@starrers = @starrers.preload_users.sort_by_attribute(@sort).page(params[:page])
- @public_count = @project.starrers.with_public_profile.size
- @total_count = @project.starrers.size
+ @public_count = @project.starrers.active.with_public_profile.size
+ @total_count = @project.starrers.active.size
@private_count = @total_count - @public_count
end
-
- private
-
- def has_starred_project?(starrers)
- starrers.first { |starrer| starrer.user_id == current_user.id }
- end
end
diff --git a/app/controllers/projects/templates_controller.rb b/app/controllers/projects/templates_controller.rb
index 6d06b05c1e9..ed5fb838670 100644
--- a/app/controllers/projects/templates_controller.rb
+++ b/app/controllers/projects/templates_controller.rb
@@ -12,7 +12,7 @@ class Projects::TemplatesController < Projects::ApplicationController
templates = @template_type.template_subsets(project)
respond_to do |format|
- format.json { render json: templates.to_json }
+ format.json { render json: Gitlab::Json.dump(templates) }
end
end
@@ -20,7 +20,7 @@ class Projects::TemplatesController < Projects::ApplicationController
template = @template_type.find(params[:key], project)
respond_to do |format|
- format.json { render json: template.to_json }
+ format.json { render json: Gitlab::Json.dump(template) }
end
end
diff --git a/app/controllers/projects/usage_quotas_controller.rb b/app/controllers/projects/usage_quotas_controller.rb
index 07a3c010f4f..d3757eaf481 100644
--- a/app/controllers/projects/usage_quotas_controller.rb
+++ b/app/controllers/projects/usage_quotas_controller.rb
@@ -5,7 +5,7 @@ class Projects::UsageQuotasController < Projects::ApplicationController
layout "project_settings"
- feature_category :utilization
+ feature_category :subscription_cost_management
urgency :low
def index
diff --git a/app/controllers/projects/work_items_controller.rb b/app/controllers/projects/work_items_controller.rb
index b794785f285..a7e59a28fb7 100644
--- a/app/controllers/projects/work_items_controller.rb
+++ b/app/controllers/projects/work_items_controller.rb
@@ -4,13 +4,9 @@ class Projects::WorkItemsController < Projects::ApplicationController
before_action do
push_force_frontend_feature_flag(:work_items, project&.work_items_feature_flag_enabled?)
push_force_frontend_feature_flag(:work_items_mvc_2, project&.work_items_mvc_2_feature_flag_enabled?)
- push_frontend_feature_flag(:work_items_hierarchy, project)
+ push_frontend_feature_flag(:use_iid_in_work_items_path, project)
end
feature_category :team_planning
urgency :low
-
- def index
- render_404 unless project&.work_items_feature_flag_enabled?
- end
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index b7b6e6534fb..a5dacbf7f2f 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -46,7 +46,6 @@ class ProjectsController < Projects::ApplicationController
push_force_frontend_feature_flag(:work_items, @project&.work_items_feature_flag_enabled?)
push_force_frontend_feature_flag(:work_items_mvc_2, @project&.work_items_mvc_2_feature_flag_enabled?)
push_frontend_feature_flag(:package_registry_access_level)
- push_frontend_feature_flag(:work_items_hierarchy, @project)
end
before_action only: :edit do
@@ -343,7 +342,7 @@ class ProjectsController < Projects::ApplicationController
options['Commits'] = [ref]
end
- render json: options.to_json
+ render json: Gitlab::Json.dump(options)
rescue Gitlab::Git::CommandError
render json: { error: _('Unable to load refs') }, status: :service_unavailable
end
@@ -440,7 +439,7 @@ class ProjectsController < Projects::ApplicationController
def operations_feature_attributes
if Feature.enabled?(:split_operations_visibility_permissions, project)
%i[
- environments_access_level feature_flags_access_level monitor_access_level
+ environments_access_level feature_flags_access_level monitor_access_level infrastructure_access_level
]
else
%i[operations_access_level]
@@ -465,7 +464,6 @@ class ProjectsController < Projects::ApplicationController
:build_timeout_human_readable,
:resolve_outdated_diff_discussions,
:container_registry_enabled,
- :default_branch,
:description,
:emails_disabled,
:external_authorization_classification_label,
@@ -491,7 +489,6 @@ class ProjectsController < Projects::ApplicationController
:merge_method,
:initialize_with_sast,
:initialize_with_readme,
- :autoclose_referenced_issues,
:ci_separated_caches,
:suggestion_commit_message,
:packages_enabled,
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index 31fe30f3f06..995303a631a 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -8,12 +8,15 @@ class RegistrationsController < Devise::RegistrationsController
include OneTrustCSP
include BizibleCSP
include GoogleAnalyticsCSP
+ include PreferredLanguageSwitcher
include RegistrationsTracking
+ include Gitlab::Tracking::Helpers::WeakPasswordErrorEvent
layout 'devise'
prepend_before_action :check_captcha, only: :create
before_action :ensure_destroy_prerequisites_met, only: [:destroy]
+ before_action :init_preferred_language, only: :new
before_action :load_recaptcha, only: :new
before_action :set_invite_params, only: :new
before_action only: [:create] do
@@ -33,15 +36,15 @@ class RegistrationsController < Devise::RegistrationsController
def create
set_user_state
- token = set_custom_confirmation_token
+ set_custom_confirmation_token
super do |new_user|
accept_pending_invitations if new_user.persisted?
persist_accepted_terms_if_required(new_user)
set_role_required(new_user)
- track_experiment_event(new_user)
- send_custom_confirmation_instructions(new_user, token)
+ send_custom_confirmation_instructions
+ track_weak_password_error(new_user, self.class.name, 'create')
if pending_approval?
NotificationService.new.new_instance_access_request(new_user)
@@ -127,7 +130,7 @@ class RegistrationsController < Devise::RegistrationsController
# after user confirms and comes back, he will be redirected
store_location_for(:redirect, users_sign_up_welcome_path(glm_tracking_params))
- return identity_verification_redirect_path if custom_confirmation_enabled?(resource)
+ return identity_verification_redirect_path if custom_confirmation_enabled?
users_almost_there_path(email: resource.email)
end
@@ -189,7 +192,8 @@ 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: registered_with_invite_email?,
+ preferred_language: preferred_language }))
.execute
end
@@ -239,19 +243,11 @@ class RegistrationsController < Devise::RegistrationsController
current_user
end
- def track_experiment_event(new_user)
- # Track signed up event to relate it with click "Sign up" button events from
- # the experimental logged out header with marketing links. This allows us to
- # have a funnel of visitors clicking on the header and those visitors
- # signing up and becoming users
- experiment(:logged_out_marketing_header, actor: new_user).track(:signed_up) if new_user.persisted?
- end
-
def identity_verification_redirect_path
# overridden by EE module
end
- def custom_confirmation_enabled?(resource)
+ def custom_confirmation_enabled?
# overridden by EE module
end
@@ -259,7 +255,7 @@ class RegistrationsController < Devise::RegistrationsController
# overridden by EE module
end
- def send_custom_confirmation_instructions(user, token)
+ def send_custom_confirmation_instructions
# overridden by EE module
end
end
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 7d4dd04c6d4..5351e3e9e77 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -9,7 +9,11 @@ class SearchController < ApplicationController
RESCUE_FROM_TIMEOUT_ACTIONS = [:count, :show, :autocomplete, :aggregations].freeze
- track_event :show, name: 'i_search_total', destinations: [:redis_hll, :snowplow]
+ track_custom_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]
@@ -108,7 +112,7 @@ class SearchController < ApplicationController
@ref = params[:project_ref] if params[:project_ref].present?
@filter = params[:filter]
- render json: search_autocomplete_opts(term, filter: @filter).to_json
+ render json: Gitlab::Json.dump(search_autocomplete_opts(term, filter: @filter))
end
def opensearch
@@ -140,8 +144,7 @@ class SearchController < ApplicationController
def check_single_commit_result?
return false if params[:force_search_results]
return false unless @project.present?
- # download_code project policy grants user the read_commit ability
- return false unless Ability.allowed?(current_user, :download_code, @project)
+ return false unless Ability.allowed?(current_user, :read_code, @project)
query = params[:search].strip.downcase
return false unless Commit.valid_hash?(query)
@@ -243,6 +246,10 @@ class SearchController < ApplicationController
search_service.project&.namespace || search_service.group
end
+ def tracking_project_source
+ search_service.project
+ end
+
def search_type
'basic'
end
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 5c969c437f4..c20a9aa4485 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -13,6 +13,7 @@ class SessionsController < Devise::SessionsController
include BizibleCSP
include VerifiesWithEmail
include GoogleAnalyticsCSP
+ include PreferredLanguageSwitcher
skip_before_action :check_two_factor_requirement, only: [:destroy]
skip_before_action :check_password_expiration, only: [:destroy]
@@ -30,6 +31,7 @@ class SessionsController < Devise::SessionsController
prepend_before_action :ensure_password_authentication_enabled!, if: -> { action_name == 'create' && password_based_login? }
before_action :auto_sign_in_with_provider, only: [:new]
+ before_action :init_preferred_language, only: :new
before_action :store_unauthenticated_sessions, only: [:new]
before_action :save_failed_login, if: :action_new_and_failed_login?
before_action :load_recaptcha
diff --git a/app/controllers/terraform/services_controller.rb b/app/controllers/terraform/services_controller.rb
index e7b9a94fd8e..7ebe1d9ba98 100644
--- a/app/controllers/terraform/services_controller.rb
+++ b/app/controllers/terraform/services_controller.rb
@@ -3,7 +3,7 @@
class Terraform::ServicesController < ApplicationController
skip_before_action :authenticate_user!
- feature_category :infrastructure_as_code
+ feature_category :package_registry
def index
render json: { 'modules.v1' => "/api/#{::API::API.version}/packages/terraform/modules/v1/" }
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index c35aa8e4346..0f03333d793 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -274,8 +274,6 @@ class UsersController < ApplicationController
def finder_params
{
- # don't display projects pending deletion
- without_deleted: true,
# don't display projects marked for deletion
not_aimed_for_deletion: true
}
diff --git a/app/experiments/application_experiment.rb b/app/experiments/application_experiment.rb
index 863a2c41d4c..60bf47c2f12 100644
--- a/app/experiments/application_experiment.rb
+++ b/app/experiments/application_experiment.rb
@@ -3,25 +3,6 @@
class ApplicationExperiment < Gitlab::Experiment
control { nil } # provide a default control for anonymous experiments
- # Documented in:
- # https://gitlab.com/gitlab-org/gitlab/-/issues/357904
- # https://gitlab.com/gitlab-org/gitlab/-/issues/345932
- #
- # @deprecated
- def publish_to_database
- ActiveSupport::Deprecation.warn('publish_to_database is deprecated and should not be used for reporting anymore')
-
- return unless should_track?
-
- # if the context contains a namespace, group, project, user, or actor
- value = context.value
- subject = value[:namespace] || value[:group] || value[:project] || value[:user] || value[:actor]
- return unless ExperimentSubject.valid_subject?(subject)
-
- variant_name = :experimental if variant&.name != 'control'
- Experiment.add_subject(name, variant: variant_name || :control, subject: subject)
- end
-
def control_behavior
# define a default nil control behavior so we can omit it when not needed
end
diff --git a/app/experiments/require_verification_for_namespace_creation_experiment.rb b/app/experiments/require_verification_for_namespace_creation_experiment.rb
index cb667c6ae60..914c5c4a29e 100644
--- a/app/experiments/require_verification_for_namespace_creation_experiment.rb
+++ b/app/experiments/require_verification_for_namespace_creation_experiment.rb
@@ -12,18 +12,8 @@ class RequireVerificationForNamespaceCreationExperiment < ApplicationExperiment
run
end
- def record_conversion(namespace)
- return unless should_track?
-
- Experiment.by_name(name).record_conversion_event_for_subject(subject, namespace_id: namespace.id)
- end
-
private
- def subject
- context.value[:user]
- end
-
def existing_user
return false unless user_or_actor
diff --git a/app/experiments/security_reports_mr_widget_prompt_experiment.rb b/app/experiments/security_reports_mr_widget_prompt_experiment.rb
index 1bf3e15ba3b..0a5778950fa 100644
--- a/app/experiments/security_reports_mr_widget_prompt_experiment.rb
+++ b/app/experiments/security_reports_mr_widget_prompt_experiment.rb
@@ -3,10 +3,4 @@
class SecurityReportsMrWidgetPromptExperiment < ApplicationExperiment
control {}
candidate {}
-
- def publish(_result = nil)
- super
-
- publish_to_database
- end
end
diff --git a/app/finders/access_requests_finder.rb b/app/finders/access_requests_finder.rb
index 2cc8a978877..9b1407e2971 100644
--- a/app/finders/access_requests_finder.rb
+++ b/app/finders/access_requests_finder.rb
@@ -24,6 +24,6 @@ class AccessRequestsFinder
private
def can_see_access_requests?(current_user)
- source && Ability.allowed?(current_user, :"admin_#{source.class.to_s.underscore}", source)
+ source && Ability.allowed?(current_user, :admin_member_access_request, source)
end
end
diff --git a/app/finders/autocomplete/users_finder.rb b/app/finders/autocomplete/users_finder.rb
index 33d9a8a3dbc..bb91f84de99 100644
--- a/app/finders/autocomplete/users_finder.rb
+++ b/app/finders/autocomplete/users_finder.rb
@@ -12,7 +12,7 @@ module Autocomplete
attr_reader :current_user, :project, :group, :search, :skip_users,
:author_id, :todo_filter, :todo_state_filter,
- :filter_by_current_user
+ :filter_by_current_user, :states
def initialize(params:, current_user:, project:, group:)
@current_user = current_user
@@ -24,6 +24,7 @@ module Autocomplete
@todo_filter = params[:todo_filter]
@todo_state_filter = params[:todo_state_filter]
@filter_by_current_user = params[:current_user]
+ @states = params[:states] || ['active']
end
def execute
@@ -60,7 +61,8 @@ module Autocomplete
# reorder_by_name() is called _before_ optionally_search(), otherwise
# reorder_by_name will break the ORDER BY applied in optionally_search().
find_users
- .active
+ .where(state: states)
+ .non_internal
.reorder_by_name
.optionally_search(search, use_minimum_char_limit: use_minimum_char_limit)
.where_not_in(skip_users)
diff --git a/app/finders/clusters/agent_authorizations_finder.rb b/app/finders/clusters/agent_authorizations_finder.rb
index 8b939f5d646..70c0868cc7f 100644
--- a/app/finders/clusters/agent_authorizations_finder.rb
+++ b/app/finders/clusters/agent_authorizations_finder.rb
@@ -24,15 +24,7 @@ module Clusters
# rubocop: disable CodeReuse/ActiveRecord
def project_authorizations
- namespace_ids = if project.group
- if include_descendants?
- all_namespace_ids
- else
- ancestor_namespace_ids
- end
- else
- project.namespace_id
- end
+ namespace_ids = project.group ? all_namespace_ids : project.namespace_id
Clusters::Agents::ProjectAuthorization
.where(project_id: project.id)
@@ -57,35 +49,21 @@ module Clusters
authorizations[:group_id].eq(ordered_ancestors_cte.table[:id])
).join_sources
- authorized_groups = Clusters::Agents::GroupAuthorization
+ Clusters::Agents::GroupAuthorization
.with(ordered_ancestors_cte.to_arel)
.joins(cte_join_sources)
.joins(agent: :project)
.with_available_ci_access_fields(project)
+ .where(projects: { namespace_id: all_namespace_ids })
.order(Arel.sql('agent_id, array_position(ARRAY(SELECT id FROM ordered_ancestors)::bigint[], agent_group_authorizations.group_id)'))
.select('DISTINCT ON (agent_id) agent_group_authorizations.*')
.preload(agent: :project)
-
- authorized_groups = if include_descendants?
- authorized_groups.where(projects: { namespace_id: all_namespace_ids })
- else
- authorized_groups.where('projects.namespace_id IN (SELECT id FROM ordered_ancestors)')
- end
-
- authorized_groups.to_a
+ .to_a
end
# rubocop: enable CodeReuse/ActiveRecord
- def ancestor_namespace_ids
- project.ancestors.select(:id)
- end
-
def all_namespace_ids
project.root_ancestor.self_and_descendants.select(:id)
end
-
- def include_descendants?
- Feature.enabled?(:agent_authorization_include_descendants, project)
- end
end
end
diff --git a/app/finders/clusters/agent_tokens_finder.rb b/app/finders/clusters/agent_tokens_finder.rb
new file mode 100644
index 00000000000..e241836e1dc
--- /dev/null
+++ b/app/finders/clusters/agent_tokens_finder.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Clusters
+ class AgentTokensFinder
+ def initialize(object, current_user, agent_id)
+ @object = object
+ @current_user = current_user
+ @agent_id = agent_id
+ end
+
+ def execute
+ raise_not_found_unless_can_read_cluster
+
+ object.cluster_agents.find(agent_id).agent_tokens
+ end
+
+ private
+
+ attr_reader :object, :current_user, :agent_id
+
+ def raise_not_found_unless_can_read_cluster
+ raise ActiveRecord::RecordNotFound unless current_user&.can?(:read_cluster, object)
+ end
+ end
+end
diff --git a/app/finders/incident_management/timeline_event_tags_finder.rb b/app/finders/incident_management/timeline_event_tags_finder.rb
new file mode 100644
index 00000000000..71820bf7dcb
--- /dev/null
+++ b/app/finders/incident_management/timeline_event_tags_finder.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module IncidentManagement
+ class TimelineEventTagsFinder
+ def initialize(user, timeline_event, params = {})
+ @user = user
+ @timeline_event = timeline_event
+ @params = params
+ end
+
+ def execute
+ return ::IncidentManagement::TimelineEventTag.none unless allowed?
+
+ timeline_event.timeline_event_tags
+ end
+
+ private
+
+ attr_reader :user, :timeline_event, :params
+
+ def allowed?
+ Ability.allowed?(user, :read_incident_management_timeline_event_tag, timeline_event)
+ end
+ end
+end
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 9f331d381aa..5fcb81949ee 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -46,7 +46,8 @@ class IssuableFinder
requires_cross_project_access unless: -> { params.project? }
- FULL_TEXT_SEARCH_TERM_REGEX = /\A[\p{ASCII}|\p{Latin}]+\z/.freeze
+ FULL_TEXT_SEARCH_TERM_PATTERN = '[\u0000-\u02FF\u1E00-\u1EFF\u2070-\u218F]*'
+ FULL_TEXT_SEARCH_TERM_REGEX = /\A#{FULL_TEXT_SEARCH_TERM_PATTERN}\z/.freeze
NEGATABLE_PARAMS_HELPER_KEYS = %i[project_id scope status include_subgroups].freeze
attr_accessor :current_user, :params
@@ -335,7 +336,7 @@ class IssuableFinder
return items if items.is_a?(ActiveRecord::NullRelation)
return items if Feature.enabled?(:disable_anonymous_search, type: :ops) && current_user.nil?
- return items.pg_full_text_search(search) if use_full_text_search?
+ return filter_by_full_text_search(items) if use_full_text_search?
if use_cte_for_search?
cte = Gitlab::SQL::CTE.new(klass.table_name, items)
@@ -348,12 +349,15 @@ class IssuableFinder
# rubocop: enable CodeReuse/ActiveRecord
def use_full_text_search?
- params[:in].blank? &&
- klass.try(:pg_full_text_searchable_columns).present? &&
+ klass.try(:pg_full_text_searchable_columns).present? &&
params[:search] =~ FULL_TEXT_SEARCH_TERM_REGEX &&
Feature.enabled?(:issues_full_text_search, params.project || params.group)
end
+ def filter_by_full_text_search(items)
+ items.pg_full_text_search(search, matched_columns: params[:in].to_s.split(','))
+ end
+
# rubocop: disable CodeReuse/ActiveRecord
def by_iids(items)
params[:iids].present? ? items.where(iid: params[:iids]) : items
diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb
index 9f96abcd4e5..e12dce744b5 100644
--- a/app/finders/issues_finder.rb
+++ b/app/finders/issues_finder.rb
@@ -29,6 +29,8 @@
# issue_types: array of strings (one of WorkItems::Type.base_types)
#
class IssuesFinder < IssuableFinder
+ extend ::Gitlab::Utils::Override
+
CONFIDENTIAL_ACCESS_LEVEL = Gitlab::Access::REPORTER
def self.scalar_params
@@ -96,6 +98,16 @@ class IssuesFinder < IssuableFinder
by_negated_issue_types(issues)
end
+ override :filter_by_full_text_search
+ def filter_by_full_text_search(items)
+ # This project condition is used as a hint to PG about the partitions that need searching
+ # because the search data is partitioned by project.
+ # In certain cases, like the recent items search, the query plan is much better without this condition.
+ return super if params[:skip_full_text_search_project_condition].present?
+
+ super.with_projects_matching_search_data
+ end
+
def by_confidential(items)
return items if params[:confidential].nil?
diff --git a/app/finders/license_template_finder.rb b/app/finders/license_template_finder.rb
index b4235a77867..51457d443a1 100644
--- a/app/finders/license_template_finder.rb
+++ b/app/finders/license_template_finder.rb
@@ -34,9 +34,13 @@ class LicenseTemplateFinder
private
+ def available_licenses
+ Licensee::License.all(featured: popular_only?)
+ end
+
def vendored_licenses
strong_memoize(:vendored_licenses) do
- Licensee::License.all(featured: popular_only?).map do |license|
+ available_licenses.map do |license|
LicenseTemplate.new(
key: license.key,
name: license.name,
diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb
index 6bfe730ebc9..126687ae41f 100644
--- a/app/finders/projects_finder.rb
+++ b/app/finders/projects_finder.rb
@@ -27,7 +27,6 @@
# last_activity_after: datetime
# last_activity_before: datetime
# repository_storage: string
-# without_deleted: boolean
# not_aimed_for_deletion: boolean
#
class ProjectsFinder < UnionFinder
@@ -76,6 +75,7 @@ class ProjectsFinder < UnionFinder
# EE would override this to add more filters
def filter_projects(collection)
+ collection = collection.without_deleted
collection = by_ids(collection)
collection = by_personal(collection)
collection = by_starred(collection)
@@ -86,7 +86,6 @@ class ProjectsFinder < UnionFinder
collection = by_search(collection)
collection = by_archived(collection)
collection = by_custom_attributes(collection)
- collection = by_deleted_status(collection)
collection = by_not_aimed_for_deletion(collection)
collection = by_last_activity_after(collection)
collection = by_last_activity_before(collection)
@@ -212,10 +211,6 @@ class ProjectsFinder < UnionFinder
items.optionally_search(params[:search], include_namespace: params[:search_namespaces].present?)
end
- def by_deleted_status(items)
- params[:without_deleted].present? ? items.without_deleted : items
- end
-
def by_not_aimed_for_deletion(items)
params[:not_aimed_for_deletion].present? ? items.not_aimed_for_deletion : items
end
diff --git a/app/finders/users_star_projects_finder.rb b/app/finders/users_star_projects_finder.rb
index 7a7587c8631..ed36d0fb274 100644
--- a/app/finders/users_star_projects_finder.rb
+++ b/app/finders/users_star_projects_finder.rb
@@ -12,7 +12,7 @@ class UsersStarProjectsFinder
end
def execute
- stars = UsersStarProject.all
+ stars = UsersStarProject.with_active_user
stars = by_project(stars)
stars = by_search(stars)
filter_visible_profiles(stars)
diff --git a/app/finders/work_items/work_items_finder.rb b/app/finders/work_items/work_items_finder.rb
index 960272fe47e..62cca06bf5e 100644
--- a/app/finders/work_items/work_items_finder.rb
+++ b/app/finders/work_items/work_items_finder.rb
@@ -12,6 +12,30 @@ module WorkItems
private
+ def filter_items(items)
+ items = super(items)
+
+ by_widgets(items)
+ end
+
+ def by_widgets(items)
+ WorkItems::Type.available_widgets.each do |widget_class|
+ widget_filter = widget_filter_for(widget_class)
+
+ next unless widget_filter
+
+ items = widget_filter.filter(items, params)
+ end
+
+ items
+ end
+
+ def widget_filter_for(widget_class)
+ "WorkItems::Widgets::Filters::#{widget_class.name.demodulize.camelize}".constantize
+ rescue NameError
+ nil
+ end
+
def model_class
WorkItem
end
diff --git a/app/graphql/graphql_triggers.rb b/app/graphql/graphql_triggers.rb
index dc4f838ae36..710e7fe110c 100644
--- a/app/graphql/graphql_triggers.rb
+++ b/app/graphql/graphql_triggers.rb
@@ -25,6 +25,10 @@ module GraphqlTriggers
GitlabSchema.subscriptions.trigger('issuableDatesUpdated', { issuable_id: issuable.to_gid }, issuable)
end
+ def self.issuable_milestone_updated(issuable)
+ GitlabSchema.subscriptions.trigger('issuableMilestoneUpdated', { issuable_id: issuable.to_gid }, issuable)
+ end
+
def self.merge_request_reviewers_updated(merge_request)
GitlabSchema.subscriptions.trigger(
'mergeRequestReviewersUpdated',
diff --git a/app/graphql/mutations/ci/job/artifacts_destroy.rb b/app/graphql/mutations/ci/job/artifacts_destroy.rb
index 34c58fc1240..9171299f353 100644
--- a/app/graphql/mutations/ci/job/artifacts_destroy.rb
+++ b/app/graphql/mutations/ci/job/artifacts_destroy.rb
@@ -18,7 +18,7 @@ module Mutations
null: false,
description: 'Number of artifacts deleted.'
- def find_object(id: )
+ def find_object(id:)
GlobalID::Locator.locate(id)
end
diff --git a/app/graphql/mutations/ci/job/base.rb b/app/graphql/mutations/ci/job/base.rb
index 6ea8e25a58d..f68f0507b28 100644
--- a/app/graphql/mutations/ci/job/base.rb
+++ b/app/graphql/mutations/ci/job/base.rb
@@ -10,7 +10,7 @@ module Mutations
required: true,
description: 'ID of the job to mutate.'
- def find_object(id: )
+ def find_object(id:)
GlobalID::Locator.locate(id)
end
end
diff --git a/app/graphql/mutations/ci/job_artifact/destroy.rb b/app/graphql/mutations/ci/job_artifact/destroy.rb
index 47b3535d631..add1b431fbf 100644
--- a/app/graphql/mutations/ci/job_artifact/destroy.rb
+++ b/app/graphql/mutations/ci/job_artifact/destroy.rb
@@ -20,7 +20,7 @@ module Mutations
null: true,
description: 'Deleted artifact.'
- def find_object(id: )
+ def find_object(id:)
GlobalID::Locator.locate(id)
end
diff --git a/app/graphql/mutations/ci/pipeline_schedule/take_ownership.rb b/app/graphql/mutations/ci/pipeline_schedule/take_ownership.rb
new file mode 100644
index 00000000000..2e4312f0045
--- /dev/null
+++ b/app/graphql/mutations/ci/pipeline_schedule/take_ownership.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Mutations
+ module Ci
+ module PipelineSchedule
+ class TakeOwnership < Base
+ graphql_name 'PipelineScheduleTakeOwnership'
+
+ authorize :take_ownership_pipeline_schedule
+
+ field :pipeline_schedule,
+ Types::Ci::PipelineScheduleType,
+ description: 'Updated pipeline schedule ownership.'
+
+ def resolve(id:)
+ schedule = authorized_find!(id: id)
+
+ service_response = ::Ci::PipelineSchedules::TakeOwnershipService.new(schedule, current_user).execute
+ {
+ pipeline_schedule: schedule,
+ errors: service_response.errors
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/ci/runner/bulk_delete.rb b/app/graphql/mutations/ci/runner/bulk_delete.rb
index 4265099d28e..f053eda0f55 100644
--- a/app/graphql/mutations/ci/runner/bulk_delete.rb
+++ b/app/graphql/mutations/ci/runner/bulk_delete.rb
@@ -25,13 +25,12 @@ module Mutations
'Only present if operation was performed synchronously.'
def resolve(**runner_attrs)
- raise_resource_not_available_error! unless Ability.allowed?(current_user, :delete_runners)
-
if ids = runner_attrs[:ids]
- runners = find_all_runners_by_ids(model_ids_of(ids))
+ runner_ids = model_ids_of(ids)
+ runners = find_all_runners_by_ids(runner_ids)
- result = ::Ci::Runners::BulkDeleteRunnersService.new(runners: runners).execute
- result.payload.slice(:deleted_count, :deleted_ids).merge(errors: [])
+ result = ::Ci::Runners::BulkDeleteRunnersService.new(runners: runners, current_user: current_user).execute
+ result.payload.slice(:deleted_count, :deleted_ids, :errors)
else
{ errors: [] }
end
@@ -39,14 +38,15 @@ module Mutations
private
- def model_ids_of(ids)
- ids.filter_map { |gid| gid.model_id.to_i }
+ def model_ids_of(global_ids)
+ global_ids.filter_map { |gid| gid.model_id.to_i }
end
def find_all_runners_by_ids(ids)
return ::Ci::Runner.none if ids.blank?
- ::Ci::Runner.id_in(ids)
+ limit = ::Ci::Runners::BulkDeleteRunnersService::RUNNER_LIMIT
+ ::Ci::Runner.id_in(ids).limit(limit + 1)
end
end
end
diff --git a/app/graphql/mutations/ci/runner/update.rb b/app/graphql/mutations/ci/runner/update.rb
index 2f2c8c4c668..3c99cde60a4 100644
--- a/app/graphql/mutations/ci/runner/update.rb
+++ b/app/graphql/mutations/ci/runner/update.rb
@@ -68,7 +68,7 @@ module Mutations
response = { runner: runner, errors: [] }
::Ci::Runner.transaction do
- associate_runner_projects(response, runner, associated_projects_ids) if associated_projects_ids.present?
+ associate_runner_projects(response, runner, associated_projects_ids) unless associated_projects_ids.nil?
update_runner(response, runner, runner_attrs)
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 e42e59de78f..6738f268e92 100644
--- a/app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb
+++ b/app/graphql/mutations/concerns/mutations/work_items/update_arguments.rb
@@ -33,6 +33,9 @@ module Mutations
argument :labels_widget, ::Types::WorkItems::Widgets::LabelsUpdateInputType,
required: false,
description: 'Input for labels widget.'
+ argument :milestone_widget, ::Types::WorkItems::Widgets::MilestoneInputType,
+ required: false,
+ description: 'Input for milestone widget.'
end
end
end
diff --git a/app/graphql/mutations/container_repositories/destroy.rb b/app/graphql/mutations/container_repositories/destroy.rb
index 2a45291be22..fe1c3fe4e61 100644
--- a/app/graphql/mutations/container_repositories/destroy.rb
+++ b/app/graphql/mutations/container_repositories/destroy.rb
@@ -21,9 +21,11 @@ module Mutations
container_repository = authorized_find!(id: id)
container_repository.delete_scheduled!
- # rubocop:disable CodeReuse/Worker
- DeleteContainerRepositoryWorker.perform_async(current_user.id, container_repository.id)
- # rubocop:enable CodeReuse/Worker
+
+ unless Feature.enabled?(:container_registry_delete_repository_with_cron_worker)
+ DeleteContainerRepositoryWorker.perform_async(current_user.id, container_repository.id) # rubocop:disable CodeReuse/Worker
+ end
+
track_event(:delete_repository, :container)
{
diff --git a/app/graphql/mutations/incident_management/timeline_event/create.rb b/app/graphql/mutations/incident_management/timeline_event/create.rb
index 1907954cada..419b814dc8c 100644
--- a/app/graphql/mutations/incident_management/timeline_event/create.rb
+++ b/app/graphql/mutations/incident_management/timeline_event/create.rb
@@ -18,6 +18,10 @@ module Mutations
required: true,
description: 'Timestamp of when the event occurred.'
+ argument :timeline_event_tag_names, [GraphQL::Types::String],
+ required: false,
+ description: copy_field_description(Types::IncidentManagement::TimelineEventType, :timeline_event_tags)
+
def resolve(incident_id:, **args)
incident = authorized_find!(id: incident_id)
diff --git a/app/graphql/mutations/incident_management/timeline_event_tag/base.rb b/app/graphql/mutations/incident_management/timeline_event_tag/base.rb
new file mode 100644
index 00000000000..b1d07203ca1
--- /dev/null
+++ b/app/graphql/mutations/incident_management/timeline_event_tag/base.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Mutations
+ module IncidentManagement
+ module TimelineEventTag
+ class Base < BaseMutation
+ field :timeline_event_tag,
+ ::Types::IncidentManagement::TimelineEventTagType,
+ null: true,
+ description: 'Timeline event tag.'
+
+ authorize :admin_incident_management_timeline_event_tag
+
+ private
+
+ def response(result)
+ {
+ timeline_event_tag: result.payload[:timeline_event_tag],
+ errors: result.errors
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/incident_management/timeline_event_tag/create.rb b/app/graphql/mutations/incident_management/timeline_event_tag/create.rb
new file mode 100644
index 00000000000..14b1d288365
--- /dev/null
+++ b/app/graphql/mutations/incident_management/timeline_event_tag/create.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Mutations
+ module IncidentManagement
+ module TimelineEventTag
+ class Create < Base
+ graphql_name 'TimelineEventTagCreate'
+
+ include FindsProject
+
+ argument :project_path, GraphQL::Types::ID,
+ required: true,
+ description: 'Project to create the timeline event tag in.'
+
+ argument :name, GraphQL::Types::String,
+ required: true,
+ description: 'Name of the tag.'
+
+ def resolve(project_path:, **args)
+ project = authorized_find!(project_path)
+
+ response ::IncidentManagement::TimelineEventTags::CreateService.new(
+ project, current_user, args
+ ).execute
+ end
+ end
+ end
+ end
+end
diff --git a/app/graphql/mutations/work_items/create.rb b/app/graphql/mutations/work_items/create.rb
index ece00e04ed9..793e5d3caf8 100644
--- a/app/graphql/mutations/work_items/create.rb
+++ b/app/graphql/mutations/work_items/create.rb
@@ -9,7 +9,7 @@ module Mutations
include FindsProject
include Mutations::WorkItems::Widgetable
- description "Creates a work item. Available only when feature flag `work_items` is enabled."
+ description "Creates a work item."
authorize :create_work_item
@@ -22,6 +22,9 @@ module Mutations
argument :hierarchy_widget, ::Types::WorkItems::Widgets::HierarchyCreateInputType,
required: false,
description: 'Input for hierarchy widget.'
+ argument :milestone_widget, ::Types::WorkItems::Widgets::MilestoneInputType,
+ required: false,
+ description: 'Input for milestone widget.'
argument :project_path, GraphQL::Types::ID,
required: true,
description: 'Full path of the project the work item is associated with.'
@@ -39,10 +42,6 @@ module Mutations
def resolve(project_path:, **attributes)
project = authorized_find!(project_path)
- unless project.work_items_feature_flag_enabled?
- return { errors: ['`work_items` feature flag disabled for this project'] }
- end
-
spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
params = global_id_compatibility_params(attributes).merge(author_id: current_user.id)
type = ::WorkItems::Type.find(attributes[:work_item_type_id])
diff --git a/app/graphql/mutations/work_items/create_from_task.rb b/app/graphql/mutations/work_items/create_from_task.rb
index 5ebe8b2c6d7..4ef8269a42f 100644
--- a/app/graphql/mutations/work_items/create_from_task.rb
+++ b/app/graphql/mutations/work_items/create_from_task.rb
@@ -7,8 +7,7 @@ module Mutations
include Mutations::SpamProtection
- description "Creates a work item from a task in another work item's description." \
- " Available only when feature flag `work_items` is enabled."
+ description "Creates a work item from a task in another work item's description."
authorize :update_work_item
@@ -31,10 +30,6 @@ module Mutations
def resolve(id:, work_item_data:)
work_item = authorized_find!(id: id)
- unless work_item.project.work_items_feature_flag_enabled?
- return { errors: ['`work_items` feature flag disabled for this project'] }
- end
-
spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
result = ::WorkItems::CreateFromTaskService.new(
diff --git a/app/graphql/mutations/work_items/delete.rb b/app/graphql/mutations/work_items/delete.rb
index 240a8b4c11e..4b0067d40d4 100644
--- a/app/graphql/mutations/work_items/delete.rb
+++ b/app/graphql/mutations/work_items/delete.rb
@@ -4,8 +4,7 @@ module Mutations
module WorkItems
class Delete < BaseMutation
graphql_name 'WorkItemDelete'
- description "Deletes a work item." \
- " Available only when feature flag `work_items` is enabled."
+ description "Deletes a work item."
authorize :delete_work_item
@@ -20,10 +19,6 @@ module Mutations
def resolve(id:)
work_item = authorized_find!(id: id)
- unless work_item.project.work_items_feature_flag_enabled?
- return { errors: ['`work_items` feature flag disabled for this project'] }
- end
-
result = ::WorkItems::DeleteService.new(
project: work_item.project,
current_user: current_user
diff --git a/app/graphql/mutations/work_items/delete_task.rb b/app/graphql/mutations/work_items/delete_task.rb
index b1bfed0cbf1..47ab3748ab4 100644
--- a/app/graphql/mutations/work_items/delete_task.rb
+++ b/app/graphql/mutations/work_items/delete_task.rb
@@ -5,8 +5,7 @@ module Mutations
class DeleteTask < BaseMutation
graphql_name 'WorkItemDeleteTask'
- description "Deletes a task in a work item's description." \
- ' Available only when feature flag `work_items` is enabled.'
+ description "Deletes a task in a work item's description."
authorize :update_work_item
@@ -29,10 +28,6 @@ module Mutations
work_item = authorized_find!(id: id)
task_data[:task] = authorized_find_task!(task_data[:id])
- unless work_item.project.work_items_feature_flag_enabled?
- return { errors: ['`work_items` feature flag disabled for this project'] }
- end
-
result = ::WorkItems::DeleteTaskService.new(
work_item: work_item,
current_user: current_user,
diff --git a/app/graphql/mutations/work_items/update.rb b/app/graphql/mutations/work_items/update.rb
index b4ed0a1a3ca..04c63d8e876 100644
--- a/app/graphql/mutations/work_items/update.rb
+++ b/app/graphql/mutations/work_items/update.rb
@@ -4,8 +4,7 @@ module Mutations
module WorkItems
class Update < BaseMutation
graphql_name 'WorkItemUpdate'
- description "Updates a work item by Global ID." \
- " Available only when feature flag `work_items` is enabled."
+ description "Updates a work item by Global ID."
include Mutations::SpamProtection
include Mutations::WorkItems::UpdateArguments
@@ -20,10 +19,6 @@ module Mutations
def resolve(id:, **attributes)
work_item = authorized_find!(id: id)
- unless work_item.project.work_items_feature_flag_enabled?
- return { errors: ['`work_items` feature flag disabled for this project'] }
- end
-
spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
widget_params = extract_widget_params!(work_item.work_item_type, attributes)
diff --git a/app/graphql/mutations/work_items/update_task.rb b/app/graphql/mutations/work_items/update_task.rb
index 35fbe672b66..aeb4f1d0f06 100644
--- a/app/graphql/mutations/work_items/update_task.rb
+++ b/app/graphql/mutations/work_items/update_task.rb
@@ -4,8 +4,7 @@ module Mutations
module WorkItems
class UpdateTask < BaseMutation
graphql_name 'WorkItemUpdateTask'
- description "Updates a work item's task by Global ID." \
- " Available only when feature flag `work_items` is enabled."
+ description "Updates a work item's task by Global ID."
include Mutations::SpamProtection
@@ -30,10 +29,6 @@ module Mutations
work_item = authorized_find!(id: id)
task = authorized_find_task!(task_data_hash[:id])
- unless work_item.project.work_items_feature_flag_enabled?
- return { errors: ['`work_items` feature flag disabled for this project'] }
- end
-
spam_params = ::Spam::SpamParams.new_from_request(request: context[:request])
::WorkItems::UpdateService.new(
diff --git a/app/graphql/resolvers/base_issues_resolver.rb b/app/graphql/resolvers/base_issues_resolver.rb
deleted file mode 100644
index 6357132705e..00000000000
--- a/app/graphql/resolvers/base_issues_resolver.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-# frozen_string_literal: true
-
-module Resolvers
- class BaseIssuesResolver < BaseResolver
- prepend IssueResolverArguments
-
- argument :sort, Types::IssueSortEnum,
- description: 'Sort issues by this criteria.',
- required: false,
- default_value: :created_desc
- argument :state, Types::IssuableStateEnum,
- required: false,
- description: 'Current state of this issue.'
-
- # see app/graphql/types/issue_connection.rb
- type 'Types::IssueConnection', null: true
-
- NON_STABLE_CURSOR_SORTS = %i[priority_asc priority_desc
- popularity_asc popularity_desc
- label_priority_asc label_priority_desc
- milestone_due_asc milestone_due_desc
- escalation_status_asc escalation_status_desc].freeze
-
- def continue_issue_resolve(parent, finder, **args)
- issues = Gitlab::Graphql::Loaders::IssuableLoader.new(parent, finder).batching_find_all { |q| apply_lookahead(q) }
-
- if non_stable_cursor_sort?(args[:sort])
- # Certain complex sorts are not supported by the stable cursor pagination yet.
- # In these cases, we use offset pagination, so we return the correct connection.
- offset_pagination(issues)
- else
- issues
- end
- end
-
- private
-
- def unconditional_includes
- [
- {
- project: [:project_feature, :group]
- },
- :author
- ]
- end
-
- def preloads
- {
- alert_management_alert: [:alert_management_alert],
- assignees: [:assignees],
- participants: Issue.participant_includes,
- timelogs: [:timelogs],
- customer_relations_contacts: { customer_relations_contacts: [:group] },
- escalation_status: [:incident_management_issuable_escalation_status]
- }
- end
-
- def non_stable_cursor_sort?(sort)
- NON_STABLE_CURSOR_SORTS.include?(sort)
- end
- end
-end
-
-Resolvers::BaseIssuesResolver.prepend_mod_with('Resolvers::BaseIssuesResolver')
diff --git a/app/graphql/resolvers/blobs_resolver.rb b/app/graphql/resolvers/blobs_resolver.rb
index 0704a845bb0..fb5fa4465f9 100644
--- a/app/graphql/resolvers/blobs_resolver.rb
+++ b/app/graphql/resolvers/blobs_resolver.rb
@@ -5,7 +5,7 @@ module Resolvers
include Gitlab::Graphql::Authorize::AuthorizeResource
type Types::Tree::BlobType.connection_type, null: true
- authorize :download_code
+ authorize :read_code
calls_gitaly!
alias_method :repository, :object
diff --git a/app/graphql/resolvers/bulk_labels_resolver.rb b/app/graphql/resolvers/bulk_labels_resolver.rb
index 7362e257fb6..d7e9564352d 100644
--- a/app/graphql/resolvers/bulk_labels_resolver.rb
+++ b/app/graphql/resolvers/bulk_labels_resolver.rb
@@ -9,7 +9,7 @@ module Resolvers
def resolve
authorize!(object)
- BatchLoader::GraphQL.for(object.id).batch(cache: false) do |ids, loader, args|
+ BatchLoader::GraphQL.for(object.id).batch(key: object.class.name, cache: false) do |ids, loader, args|
labels = Label.for_targets(object.class.id_in(ids)).group_by(&:target_id)
ids.each do |id|
diff --git a/app/graphql/resolvers/concerns/board_item_filterable.rb b/app/graphql/resolvers/concerns/board_item_filterable.rb
index 1457a02e44f..9c0ada4f72c 100644
--- a/app/graphql/resolvers/concerns/board_item_filterable.rb
+++ b/app/graphql/resolvers/concerns/board_item_filterable.rb
@@ -14,6 +14,16 @@ module BoardItemFilterable
set_filter_values(filters[:not])
end
+ if filters[:or]
+ if ::Feature.disabled?(:or_issuable_queries, resource_parent)
+ raise ::Gitlab::Graphql::Errors::ArgumentError,
+ "'or' arguments are only allowed when the `or_issuable_queries` feature flag is enabled."
+ end
+
+ rewrite_param_name(filters[:or], :author_usernames, :author_username)
+ rewrite_param_name(filters[:or], :assignee_usernames, :assignee_username)
+ end
+
filters
end
@@ -30,6 +40,14 @@ module BoardItemFilterable
filters[:assignee_id] = filters.delete(:assignee_wildcard_id)
end
end
+
+ def rewrite_param_name(filters, old_name, new_name)
+ filters[new_name] = filters.delete(old_name) if filters[old_name].present?
+ end
+
+ def resource_parent
+ respond_to?(:board) ? board.resource_parent : list.board.resource_parent
+ end
end
::BoardItemFilterable.prepend_mod_with('Resolvers::BoardItemFilterable')
diff --git a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb b/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
deleted file mode 100644
index 8295bd58388..00000000000
--- a/app/graphql/resolvers/concerns/issue_resolver_arguments.rb
+++ /dev/null
@@ -1,167 +0,0 @@
-# frozen_string_literal: true
-
-module IssueResolverArguments
- extend ActiveSupport::Concern
-
- prepended do
- include SearchArguments
- include LooksAhead
-
- 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 issues. For example, `["1", "2"]`.'
- argument :label_name, [GraphQL::Types::String, null: true],
- required: false,
- description: 'Labels applied to this issue.'
- argument :milestone_title, [GraphQL::Types::String, null: true],
- required: false,
- description: 'Milestone applied to this issue.'
- argument :author_username, GraphQL::Types::String,
- required: false,
- description: 'Username of the author of the issue.'
- argument :assignee_username, GraphQL::Types::String,
- required: false,
- description: 'Username of a user assigned to the issue.',
- deprecated: { reason: 'Use `assigneeUsernames`', milestone: '13.11' }
- argument :assignee_usernames, [GraphQL::Types::String],
- required: false,
- description: 'Usernames of users assigned to the issue.'
- argument :assignee_id, GraphQL::Types::String,
- required: false,
- description: 'ID of a user assigned to the issues. Wildcard values "NONE" and "ANY" are supported.'
- argument :created_before, Types::TimeType,
- required: false,
- description: 'Issues created before this date.'
- argument :created_after, Types::TimeType,
- required: false,
- description: 'Issues created after this date.'
- argument :updated_before, Types::TimeType,
- required: false,
- description: 'Issues updated before this date.'
- argument :updated_after, Types::TimeType,
- required: false,
- description: 'Issues updated after this date.'
- argument :closed_before, Types::TimeType,
- required: false,
- description: 'Issues closed before this date.'
- argument :closed_after, Types::TimeType,
- required: false,
- description: 'Issues closed after this date.'
- argument :types, [Types::IssueTypeEnum],
- as: :issue_types,
- description: 'Filter issues by the given issue types.',
- required: false
- argument :milestone_wildcard_id, ::Types::MilestoneWildcardIdEnum,
- required: false,
- description: 'Filter issues by milestone ID wildcard.'
- argument :my_reaction_emoji, GraphQL::Types::String,
- required: false,
- description: 'Filter by reaction emoji applied by the current user. Wildcard values "NONE" and "ANY" are supported.'
- argument :confidential,
- GraphQL::Types::Boolean,
- required: false,
- description: 'Filter for confidential issues. If "false", excludes confidential issues. If "true", returns only confidential issues.'
- argument :not, Types::Issues::NegatedIssueFilterInputType,
- description: 'Negated arguments.',
- required: false
- argument :crm_contact_id, GraphQL::Types::String,
- required: false,
- description: 'ID of a contact assigned to the issues.'
- argument :crm_organization_id, GraphQL::Types::String,
- required: false,
- description: 'ID of an organization assigned to the issues.'
- end
-
- def resolve_with_lookahead(**args)
- return Issue.none if resource_parent.nil?
-
- finder = IssuesFinder.new(current_user, prepare_finder_params(args))
-
- continue_issue_resolve(resource_parent, finder, **args)
- end
-
- def ready?(**args)
- args[:not] = args[:not].to_h if args[:not].present?
-
- params_not_mutually_exclusive(args, mutually_exclusive_assignee_username_args)
- params_not_mutually_exclusive(args, mutually_exclusive_milestone_args)
- params_not_mutually_exclusive(args.fetch(:not, {}), mutually_exclusive_milestone_args)
- params_not_mutually_exclusive(args, mutually_exclusive_release_tag_args)
-
- super
- end
-
- class_methods do
- def resolver_complexity(args, child_complexity:)
- complexity = super
- complexity += 2 if args[:labelName]
-
- complexity
- end
-
- def accept_release_tag
- argument :release_tag, [GraphQL::Types::String],
- required: false,
- description: "Release tag associated with the issue's milestone."
- argument :release_tag_wildcard_id, Types::ReleaseTagWildcardIdEnum,
- required: false,
- description: 'Filter issues by release tag ID wildcard.'
- end
- end
-
- private
-
- def prepare_finder_params(args)
- params = super(args)
- params[:iids] ||= [params.delete(:iid)].compact if params[:iid]
- params[:attempt_project_search_optimizations] = true if params[:search].present?
-
- prepare_assignee_username_params(params)
- prepare_release_tag_params(params)
-
- params
- end
-
- def prepare_release_tag_params(args)
- release_tag_wildcard = args.delete(:release_tag_wildcard_id)
- return if release_tag_wildcard.blank?
-
- args[:release_tag] ||= release_tag_wildcard
- end
-
- def prepare_assignee_username_params(args)
- args[:assignee_username] = args.delete(:assignee_usernames) if args[:assignee_usernames].present?
- args[:not][:assignee_username] = args[:not].delete(:assignee_usernames) if args.dig(:not, :assignee_usernames).present?
- end
-
- def mutually_exclusive_release_tag_args
- [:release_tag, :release_tag_wildcard_id]
- end
-
- def mutually_exclusive_milestone_args
- [:milestone_title, :milestone_wildcard_id]
- end
-
- def mutually_exclusive_assignee_username_args
- [:assignee_usernames, :assignee_username]
- end
-
- def params_not_mutually_exclusive(args, mutually_exclusive_args)
- if args.slice(*mutually_exclusive_args).compact.size > 1
- arg_str = mutually_exclusive_args.map { |x| x.to_s.camelize(:lower) }.join(', ')
- raise ::Gitlab::Graphql::Errors::ArgumentError, "only one of [#{arg_str}] arguments is allowed at the same time."
- end
- end
-
- def resource_parent
- # The project could have been loaded in batch by `BatchLoader`.
- # At this point we need the `id` of the project to query for issues, so
- # make sure it's loaded and not `nil` before continuing.
- strong_memoize(:resource_parent) do
- object.respond_to?(:sync) ? object.sync : object
- end
- end
-end
diff --git a/app/graphql/resolvers/concerns/issues/look_ahead_preloads.rb b/app/graphql/resolvers/concerns/issues/look_ahead_preloads.rb
new file mode 100644
index 00000000000..c6e32be245d
--- /dev/null
+++ b/app/graphql/resolvers/concerns/issues/look_ahead_preloads.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Issues
+ module LookAheadPreloads
+ extend ActiveSupport::Concern
+
+ prepended do
+ include ::LooksAhead
+ end
+
+ private
+
+ def unconditional_includes
+ [
+ {
+ project: [:project_feature, :group]
+ },
+ :author
+ ]
+ end
+
+ def preloads
+ {
+ alert_management_alert: [:alert_management_alert],
+ assignees: [:assignees],
+ participants: Issue.participant_includes,
+ timelogs: [:timelogs],
+ customer_relations_contacts: { customer_relations_contacts: [:group] },
+ escalation_status: [:incident_management_issuable_escalation_status]
+ }
+ end
+ end
+end
+
+Issues::LookAheadPreloads.prepend_mod
diff --git a/app/graphql/resolvers/concerns/issues/sort_arguments.rb b/app/graphql/resolvers/concerns/issues/sort_arguments.rb
new file mode 100644
index 00000000000..70ae6bd8a5b
--- /dev/null
+++ b/app/graphql/resolvers/concerns/issues/sort_arguments.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Issues
+ module SortArguments
+ extend ActiveSupport::Concern
+
+ NON_STABLE_CURSOR_SORTS = %i[priority_asc priority_desc
+ popularity_asc popularity_desc
+ label_priority_asc label_priority_desc
+ milestone_due_asc milestone_due_desc
+ escalation_status_asc escalation_status_desc].freeze
+
+ included do
+ argument :sort, Types::IssueSortEnum,
+ description: 'Sort issues by this criteria.',
+ required: false,
+ default_value: :created_desc
+ end
+
+ private
+
+ def non_stable_cursor_sort?(sort)
+ NON_STABLE_CURSOR_SORTS.include?(sort)
+ end
+ end
+end
diff --git a/app/graphql/resolvers/concerns/project_search_arguments.rb b/app/graphql/resolvers/concerns/project_search_arguments.rb
index 7e03963f412..faf3b85fc14 100644
--- a/app/graphql/resolvers/concerns/project_search_arguments.rb
+++ b/app/graphql/resolvers/concerns/project_search_arguments.rb
@@ -25,7 +25,6 @@ module ProjectSearchArguments
def project_finder_params(params)
{
- without_deleted: true,
non_public: params[:membership],
search: params[:search],
search_namespaces: params[:search_namespaces],
diff --git a/app/graphql/resolvers/concerns/search_arguments.rb b/app/graphql/resolvers/concerns/search_arguments.rb
index 95c6dbf7497..ccc012f2bf9 100644
--- a/app/graphql/resolvers/concerns/search_arguments.rb
+++ b/app/graphql/resolvers/concerns/search_arguments.rb
@@ -46,9 +46,17 @@ module SearchArguments
def prepare_search_params(args)
return args unless args[:search].present?
+ args[:in] = args[:in].join(',') if args[:in].present?
+ set_search_optimization_param(args)
+
+ args
+ end
+
+ def set_search_optimization_param(args)
+ return args unless respond_to?(:resource_parent, true) && resource_parent.present?
+
parent_type = resource_parent.is_a?(Project) ? :project : :group
args[:"attempt_#{parent_type}_search_optimizations"] = true
- args[:in] = args[:in].join(',') if args[:in].present?
args
end
diff --git a/app/graphql/resolvers/group_issues_resolver.rb b/app/graphql/resolvers/group_issues_resolver.rb
index 05c5e803539..43f01395896 100644
--- a/app/graphql/resolvers/group_issues_resolver.rb
+++ b/app/graphql/resolvers/group_issues_resolver.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
-# rubocop:disable Graphql/ResolverType (inherited from BaseIssuesResolver)
+# rubocop:disable Graphql/ResolverType (inherited from Issues::BaseParentResolver)
module Resolvers
- class GroupIssuesResolver < BaseIssuesResolver
+ class GroupIssuesResolver < Issues::BaseParentResolver
def self.issuable_collection_name
'issues'
end
@@ -18,3 +18,4 @@ module Resolvers
end
end
end
+# rubocop:enable Graphql/ResolverType
diff --git a/app/graphql/resolvers/incident_management/timeline_event_tags_resolver.rb b/app/graphql/resolvers/incident_management/timeline_event_tags_resolver.rb
new file mode 100644
index 00000000000..ac6577d119b
--- /dev/null
+++ b/app/graphql/resolvers/incident_management/timeline_event_tags_resolver.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module IncidentManagement
+ class TimelineEventTagsResolver < BaseResolver
+ include LooksAhead
+
+ type ::Types::IncidentManagement::TimelineEventTagType.connection_type, null: true
+
+ def resolve(**args)
+ apply_lookahead(::IncidentManagement::TimelineEventTagsFinder.new(current_user, object, args).execute)
+ end
+ end
+ end
+end
diff --git a/app/graphql/resolvers/incident_management/timeline_events_resolver.rb b/app/graphql/resolvers/incident_management/timeline_events_resolver.rb
index b9978259e6b..0d46b1387b0 100644
--- a/app/graphql/resolvers/incident_management/timeline_events_resolver.rb
+++ b/app/graphql/resolvers/incident_management/timeline_events_resolver.rb
@@ -22,11 +22,17 @@ module Resolvers
prepare: ->(id, ctx) { id.model_id }
end
- def resolve(**args)
+ def resolve_with_lookahead(**args)
incident = args[:incident_id].find
apply_lookahead(::IncidentManagement::TimelineEventsFinder.new(current_user, incident, args).execute)
end
+
+ def preloads
+ {
+ timeline_event_tags: [:timeline_event_tags]
+ }
+ end
end
end
end
diff --git a/app/graphql/resolvers/issue_status_counts_resolver.rb b/app/graphql/resolvers/issue_status_counts_resolver.rb
index db5c91daac2..92cda77d717 100644
--- a/app/graphql/resolvers/issue_status_counts_resolver.rb
+++ b/app/graphql/resolvers/issue_status_counts_resolver.rb
@@ -1,17 +1,29 @@
# frozen_string_literal: true
module Resolvers
- class IssueStatusCountsResolver < BaseResolver
- prepend IssueResolverArguments
-
+ class IssueStatusCountsResolver < Issues::BaseResolver
type Types::IssueStatusCountsType, null: true
+
accept_release_tag
- extras [:lookahead]
+ def resolve(**args)
+ return Issue.none if resource_parent.nil?
+
+ finder = IssuesFinder.new(current_user, prepare_finder_params(args))
+ finder.parent_param = resource_parent
+
+ Gitlab::IssuablesCountForState.new(finder, resource_parent)
+ end
+
+ private
- def continue_issue_resolve(parent, finder, **args)
- finder.parent_param = parent
- apply_lookahead(Gitlab::IssuablesCountForState.new(finder, parent))
+ def resource_parent
+ # The project could have been loaded in batch by `BatchLoader`.
+ # At this point we need the `id` of the project to query for issues, so
+ # make sure it's loaded and not `nil` before continuing.
+ strong_memoize(:resource_parent) do
+ object.respond_to?(:sync) ? object.sync : object
+ end
end
end
end
diff --git a/app/graphql/resolvers/issues/base_parent_resolver.rb b/app/graphql/resolvers/issues/base_parent_resolver.rb
new file mode 100644
index 00000000000..6308e56f049
--- /dev/null
+++ b/app/graphql/resolvers/issues/base_parent_resolver.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Issues
+ class BaseParentResolver < Issues::BaseResolver
+ prepend ::Issues::LookAheadPreloads
+ include ::Issues::SortArguments
+
+ argument :state, Types::IssuableStateEnum,
+ required: false,
+ description: 'Current state of this issue.'
+
+ # see app/graphql/types/issue_connection.rb
+ type 'Types::IssueConnection', null: true
+
+ def resolve_with_lookahead(**args)
+ return Issue.none if resource_parent.nil?
+
+ finder = IssuesFinder.new(current_user, prepare_finder_params(args))
+
+ issues = Gitlab::Graphql::Loaders::IssuableLoader.new(resource_parent, finder).batching_find_all do |q|
+ apply_lookahead(q)
+ end
+
+ if non_stable_cursor_sort?(args[:sort])
+ # Certain complex sorts are not supported by the stable cursor pagination yet.
+ # In these cases, we use offset pagination, so we return the correct connection.
+ offset_pagination(issues)
+ else
+ issues
+ end
+ end
+
+ private
+
+ def resource_parent
+ # The project could have been loaded in batch by `BatchLoader`.
+ # At this point we need the `id` of the project to query for issues, so
+ # make sure it's loaded and not `nil` before continuing.
+ strong_memoize(:resource_parent) do
+ object.respond_to?(:sync) ? object.sync : object
+ end
+ end
+ end
+ end
+end
+
+Resolvers::Issues::BaseParentResolver.prepend_mod
diff --git a/app/graphql/resolvers/issues/base_resolver.rb b/app/graphql/resolvers/issues/base_resolver.rb
new file mode 100644
index 00000000000..9a2c4572abb
--- /dev/null
+++ b/app/graphql/resolvers/issues/base_resolver.rb
@@ -0,0 +1,186 @@
+# frozen_string_literal: true
+
+module Resolvers
+ module Issues
+ # rubocop:disable Graphql/ResolverType
+ class BaseResolver < Resolvers::BaseResolver
+ include SearchArguments
+
+ argument :assignee_id, GraphQL::Types::String,
+ required: false,
+ description: 'ID of a user assigned to the issues. Wildcard values "NONE" and "ANY" are supported.'
+ argument :assignee_username, GraphQL::Types::String,
+ required: false,
+ description: 'Username of a user assigned to the issue.',
+ deprecated: { reason: 'Use `assigneeUsernames`', milestone: '13.11' }
+ 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 :closed_after, Types::TimeType,
+ required: false,
+ description: 'Issues closed after this date.'
+ argument :closed_before, Types::TimeType,
+ required: false,
+ description: 'Issues closed before this date.'
+ argument :confidential,
+ GraphQL::Types::Boolean,
+ required: false,
+ description: 'Filter for confidential issues. If "false", excludes confidential issues.' \
+ ' If "true", returns only confidential issues.'
+ argument :created_after, Types::TimeType,
+ required: false,
+ description: 'Issues created after this date.'
+ argument :created_before, Types::TimeType,
+ required: false,
+ description: 'Issues created before this date.'
+ argument :crm_contact_id, GraphQL::Types::String,
+ required: false,
+ description: 'ID of a contact assigned to the issues.'
+ argument :crm_organization_id, GraphQL::Types::String,
+ required: false,
+ description: 'ID of an organization assigned to the issues.'
+ 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 issues. For example, `["1", "2"]`.'
+ argument :label_name, [GraphQL::Types::String, { null: true }],
+ required: false,
+ description: 'Labels applied to this issue.'
+ argument :milestone_title, [GraphQL::Types::String, { null: true }],
+ required: false,
+ description: 'Milestone applied to this issue.'
+ argument :milestone_wildcard_id, ::Types::MilestoneWildcardIdEnum,
+ required: false,
+ description: 'Filter issues by milestone ID wildcard.'
+ argument :my_reaction_emoji, GraphQL::Types::String,
+ required: false,
+ description: 'Filter by reaction emoji applied by the current user.' \
+ ' Wildcard values "NONE" and "ANY" are supported.'
+ argument :not, Types::Issues::NegatedIssueFilterInputType,
+ description: 'Negated arguments.',
+ required: false
+ argument :or, Types::Issues::UnionedIssueFilterInputType,
+ description: 'List of arguments with inclusive OR.',
+ required: false
+ argument :types, [Types::IssueTypeEnum],
+ as: :issue_types,
+ description: 'Filter issues by the given issue types.',
+ required: false
+ argument :updated_after, Types::TimeType,
+ required: false,
+ description: 'Issues updated after this date.'
+ argument :updated_before, Types::TimeType,
+ required: false,
+ description: 'Issues updated before this date.'
+
+ class << self
+ def resolver_complexity(args, child_complexity:)
+ complexity = super
+ complexity += 2 if args[:labelName]
+
+ complexity
+ end
+
+ def accept_release_tag
+ argument :release_tag, [GraphQL::Types::String],
+ required: false,
+ description: "Release tag associated with the issue's milestone."
+ argument :release_tag_wildcard_id, Types::ReleaseTagWildcardIdEnum,
+ required: false,
+ description: 'Filter issues by release tag ID wildcard.'
+ end
+ end
+
+ def ready?(**args)
+ if args[:or].present? && or_issuable_queries_disabled?
+ raise ::Gitlab::Graphql::Errors::ArgumentError,
+ "'or' arguments are only allowed when the `or_issuable_queries` feature flag is enabled."
+ end
+
+ args[:not] = args[:not].to_h if args[:not]
+ args[:or] = args[:or].to_h if args[:or]
+
+ params_not_mutually_exclusive(args, mutually_exclusive_assignee_username_args)
+ params_not_mutually_exclusive(args, mutually_exclusive_milestone_args)
+ params_not_mutually_exclusive(args.fetch(:not, {}), mutually_exclusive_milestone_args)
+ params_not_mutually_exclusive(args, mutually_exclusive_release_tag_args)
+
+ super
+ end
+
+ private
+
+ def or_issuable_queries_disabled?
+ if respond_to?(:resource_parent, true)
+ ::Feature.disabled?(:or_issuable_queries, resource_parent)
+ else
+ ::Feature.disabled?(:or_issuable_queries)
+ end
+ end
+
+ def prepare_finder_params(args)
+ params = super(args)
+ params[:not] = params[:not].to_h if params[:not]
+ params[:or] = params[:or].to_h if params[:or]
+ params[:iids] ||= [params.delete(:iid)].compact if params[:iid]
+
+ prepare_author_username_params(params)
+ prepare_assignee_username_params(params)
+ prepare_release_tag_params(params)
+
+ params
+ end
+
+ def prepare_release_tag_params(args)
+ release_tag_wildcard = args.delete(:release_tag_wildcard_id)
+ return if release_tag_wildcard.blank?
+
+ args[:release_tag] ||= release_tag_wildcard
+ end
+
+ def prepare_author_username_params(args)
+ args[:or][:author_username] = args[:or].delete(:author_usernames) if args.dig(:or, :author_usernames).present?
+ end
+
+ def prepare_assignee_username_params(args)
+ args[:assignee_username] = args.delete(:assignee_usernames) if args[:assignee_usernames].present?
+
+ if args.dig(:or, :assignee_usernames).present?
+ args[:or][:assignee_username] = args[:or].delete(:assignee_usernames)
+ end
+
+ return unless args.dig(:not, :assignee_usernames).present?
+
+ args[:not][:assignee_username] = args[:not].delete(:assignee_usernames)
+ end
+
+ def mutually_exclusive_release_tag_args
+ [:release_tag, :release_tag_wildcard_id]
+ end
+
+ def mutually_exclusive_milestone_args
+ [:milestone_title, :milestone_wildcard_id]
+ end
+
+ def mutually_exclusive_assignee_username_args
+ [:assignee_usernames, :assignee_username]
+ end
+
+ def params_not_mutually_exclusive(args, mutually_exclusive_args)
+ return unless args.slice(*mutually_exclusive_args).compact.size > 1
+
+ arg_str = mutually_exclusive_args.map { |x| x.to_s.camelize(:lower) }.join(', ')
+ raise ::Gitlab::Graphql::Errors::ArgumentError,
+ "only one of [#{arg_str}] arguments is allowed at the same time."
+ end
+ end
+ # rubocop:enable Graphql/ResolverType
+ end
+end
+
+Resolvers::Issues::BaseResolver.prepend_mod
diff --git a/app/graphql/resolvers/issues_resolver.rb b/app/graphql/resolvers/issues_resolver.rb
index 4b52ef61d57..e3102a7d32a 100644
--- a/app/graphql/resolvers/issues_resolver.rb
+++ b/app/graphql/resolvers/issues_resolver.rb
@@ -1,8 +1,31 @@
# frozen_string_literal: true
-# rubocop:disable Graphql/ResolverType (inherited from BaseIssuesResolver)
module Resolvers
- class IssuesResolver < BaseIssuesResolver
- accept_release_tag
+ class IssuesResolver < Issues::BaseResolver
+ prepend ::Issues::LookAheadPreloads
+ include ::Issues::SortArguments
+
+ argument :state, Types::IssuableStateEnum,
+ required: false,
+ description: 'Current state of this issue.'
+
+ # see app/graphql/types/issue_connection.rb
+ type 'Types::IssueConnection', null: true
+
+ def resolve_with_lookahead(**args)
+ return unless Feature.enabled?(:root_level_issues_query)
+
+ issues = apply_lookahead(
+ IssuesFinder.new(current_user, prepare_finder_params(args)).execute
+ )
+
+ if non_stable_cursor_sort?(args[:sort])
+ # Certain complex sorts are not supported by the stable cursor pagination yet.
+ # In these cases, we use offset pagination, so we return the correct connection.
+ offset_pagination(issues)
+ else
+ issues
+ end
+ end
end
end
diff --git a/app/graphql/resolvers/project_issues_resolver.rb b/app/graphql/resolvers/project_issues_resolver.rb
new file mode 100644
index 00000000000..f869d8f11c6
--- /dev/null
+++ b/app/graphql/resolvers/project_issues_resolver.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+# rubocop:disable Graphql/ResolverType (inherited from Issues::BaseParentResolver)
+module Resolvers
+ class ProjectIssuesResolver < Issues::BaseParentResolver
+ accept_release_tag
+ end
+end
+# rubocop:enable Graphql/ResolverType
diff --git a/app/graphql/resolvers/work_item_resolver.rb b/app/graphql/resolvers/work_item_resolver.rb
index 9eb7d6bc693..b174a0d2693 100644
--- a/app/graphql/resolvers/work_item_resolver.rb
+++ b/app/graphql/resolvers/work_item_resolver.rb
@@ -11,10 +11,7 @@ module Resolvers
argument :id, ::Types::GlobalIDType[::WorkItem], required: true, description: 'Global ID of the work item.'
def resolve(id:)
- work_item = authorized_find!(id: id)
- return unless work_item.project.work_items_feature_flag_enabled?
-
- work_item
+ authorized_find!(id: id)
end
private
diff --git a/app/graphql/resolvers/work_items/types_resolver.rb b/app/graphql/resolvers/work_items/types_resolver.rb
index 5f9f8ab5572..2508125d392 100644
--- a/app/graphql/resolvers/work_items/types_resolver.rb
+++ b/app/graphql/resolvers/work_items/types_resolver.rb
@@ -11,8 +11,6 @@ module Resolvers
' Argument is experimental and can be removed in the future without notice.'
def resolve(taskable: nil)
- return unless feature_flag_enabled_for_parent?(object)
-
# This will require a finder in the future when groups/projects get their work item types
# All groups/projects use the default types for now
base_scope = ::WorkItems::Type.default
@@ -20,14 +18,6 @@ module Resolvers
base_scope.order_by_name_asc
end
-
- private
-
- def feature_flag_enabled_for_parent?(parent)
- return false unless parent.is_a?(::Project) || parent.is_a?(::Group)
-
- parent.work_items_feature_flag_enabled?
- end
end
end
end
diff --git a/app/graphql/resolvers/work_items_resolver.rb b/app/graphql/resolvers/work_items_resolver.rb
index a4cbcc61ead..42f4f99d4a9 100644
--- a/app/graphql/resolvers/work_items_resolver.rb
+++ b/app/graphql/resolvers/work_items_resolver.rb
@@ -26,7 +26,7 @@ module Resolvers
required: false
def resolve_with_lookahead(**args)
- return WorkItem.none if resource_parent.nil? || !resource_parent.work_items_feature_flag_enabled?
+ return WorkItem.none if resource_parent.nil?
finder = ::WorkItems::WorkItemsFinder.new(current_user, prepare_finder_params(args))
@@ -55,7 +55,8 @@ module Resolvers
last_edited_by: :last_edited_by,
assignees: :assignees,
parent: :work_item_parent,
- labels: :labels
+ labels: :labels,
+ milestone: :milestone
}
end
diff --git a/app/graphql/types/base_argument.rb b/app/graphql/types/base_argument.rb
index 2c899e9edaa..4086015dad6 100644
--- a/app/graphql/types/base_argument.rb
+++ b/app/graphql/types/base_argument.rb
@@ -4,10 +4,10 @@ module Types
class BaseArgument < GraphQL::Schema::Argument
include GitlabStyleDeprecations
- attr_reader :deprecation, :doc_reference
+ attr_reader :doc_reference
def initialize(*args, **kwargs, &block)
- @deprecation = gitlab_deprecation(kwargs)
+ init_gitlab_deprecation(kwargs)
@doc_reference = kwargs.delete(:see)
# our custom addition `nullable` which allows us to declare
diff --git a/app/graphql/types/base_enum.rb b/app/graphql/types/base_enum.rb
index 0224aeddac6..11877b79e59 100644
--- a/app/graphql/types/base_enum.rb
+++ b/app/graphql/types/base_enum.rb
@@ -6,10 +6,8 @@ module Types
class CustomValue < GraphQL::Schema::EnumValue
include ::GitlabStyleDeprecations
- attr_reader :deprecation
-
def initialize(name, desc = nil, **kwargs)
- @deprecation = gitlab_deprecation(kwargs)
+ init_gitlab_deprecation(kwargs)
super(name, desc, **kwargs)
end
diff --git a/app/graphql/types/base_field.rb b/app/graphql/types/base_field.rb
index 6f64e5b5053..36ba3399754 100644
--- a/app/graphql/types/base_field.rb
+++ b/app/graphql/types/base_field.rb
@@ -8,16 +8,16 @@ module Types
DEFAULT_COMPLEXITY = 1
- attr_reader :deprecation, :doc_reference
+ attr_reader :doc_reference
def initialize(**kwargs, &block)
+ init_gitlab_deprecation(kwargs)
@calls_gitaly = !!kwargs.delete(:calls_gitaly)
@doc_reference = kwargs.delete(:see)
@constant_complexity = kwargs[:complexity].is_a?(Integer) && kwargs[:complexity] > 0
@requires_argument = !!kwargs.delete(:requires_argument)
@authorize = Array.wrap(kwargs.delete(:authorize))
kwargs[:complexity] = field_complexity(kwargs[:resolver_class], kwargs[:complexity])
- @deprecation = gitlab_deprecation(kwargs)
after_connection_extensions = kwargs.delete(:late_extensions) || []
super(**kwargs, &block)
diff --git a/app/graphql/types/boards/board_issue_input_type.rb b/app/graphql/types/boards/board_issue_input_type.rb
index 0dd7fbc87da..897e3d05948 100644
--- a/app/graphql/types/boards/board_issue_input_type.rb
+++ b/app/graphql/types/boards/board_issue_input_type.rb
@@ -9,6 +9,10 @@ module Types
required: false,
description: 'List of negated arguments.'
+ argument :or, Types::Issues::UnionedIssueFilterInputType,
+ required: false,
+ description: 'List of arguments with inclusive OR.'
+
argument :search, GraphQL::Types::String,
required: false,
description: 'Search query for issue title or description.'
diff --git a/app/graphql/types/branch_protections/merge_access_level_type.rb b/app/graphql/types/branch_protections/merge_access_level_type.rb
index 85295e1ba25..e8fcd57ba80 100644
--- a/app/graphql/types/branch_protections/merge_access_level_type.rb
+++ b/app/graphql/types/branch_protections/merge_access_level_type.rb
@@ -4,7 +4,7 @@ module Types
module BranchProtections
class MergeAccessLevelType < BaseAccessLevelType # rubocop:disable Graphql/AuthorizeTypes
graphql_name 'MergeAccessLevel'
- description 'Represents the merge access level of a branch protection.'
+ description 'Defines which user roles, users, or groups can merge into a protected branch.'
accepts ::ProtectedBranch::MergeAccessLevel
end
end
diff --git a/app/graphql/types/branch_protections/push_access_level_type.rb b/app/graphql/types/branch_protections/push_access_level_type.rb
index bfbdc4edbea..c5e21fad88d 100644
--- a/app/graphql/types/branch_protections/push_access_level_type.rb
+++ b/app/graphql/types/branch_protections/push_access_level_type.rb
@@ -4,7 +4,7 @@ module Types
module BranchProtections
class PushAccessLevelType < BaseAccessLevelType # rubocop:disable Graphql/AuthorizeTypes
graphql_name 'PushAccessLevel'
- description 'Represents the push access level of a branch protection.'
+ description 'Defines which user roles, users, or groups can push to a protected branch.'
accepts ::ProtectedBranch::PushAccessLevel
end
end
diff --git a/app/graphql/types/ci/job_need_union.rb b/app/graphql/types/ci/job_need_union.rb
index 59608a6a312..61ad5432db8 100644
--- a/app/graphql/types/ci/job_need_union.rb
+++ b/app/graphql/types/ci/job_need_union.rb
@@ -8,9 +8,10 @@ module Types
possible_types Types::Ci::JobType, Types::Ci::BuildNeedType
def self.resolve_type(object, context)
- if object.is_a?(::Ci::BuildNeed)
+ case object
+ when ::Ci::BuildNeed
Types::Ci::BuildNeedType
- elsif object.is_a?(CommitStatus)
+ when CommitStatus
Types::Ci::JobType
else
raise TypeNotSupportedError
diff --git a/app/graphql/types/commit_signature_interface.rb b/app/graphql/types/commit_signature_interface.rb
new file mode 100644
index 00000000000..6b0c16e538a
--- /dev/null
+++ b/app/graphql/types/commit_signature_interface.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Types
+ module CommitSignatureInterface
+ include Types::BaseInterface
+
+ graphql_name 'CommitSignature'
+
+ description 'Represents signing information for a commit'
+
+ field :verification_status, CommitSignatures::VerificationStatusEnum,
+ null: true,
+ description: 'Indicates verification status of the associated key or certificate.'
+
+ field :commit_sha, GraphQL::Types::String,
+ null: true,
+ description: 'SHA of the associated commit.'
+
+ field :project, Types::ProjectType,
+ null: true,
+ description: 'Project of the associated commit.'
+
+ orphan_types Types::CommitSignatures::GpgSignatureType,
+ Types::CommitSignatures::X509SignatureType
+
+ def self.resolve_type(object, context)
+ case object
+ when ::CommitSignatures::GpgSignature
+ Types::CommitSignatures::GpgSignatureType
+ when ::CommitSignatures::X509CommitSignature
+ Types::CommitSignatures::X509SignatureType
+ else
+ raise 'Unsupported commit signature type'
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/commit_signatures/gpg_signature_type.rb b/app/graphql/types/commit_signatures/gpg_signature_type.rb
new file mode 100644
index 00000000000..2a845fff3e2
--- /dev/null
+++ b/app/graphql/types/commit_signatures/gpg_signature_type.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Types
+ module CommitSignatures
+ class GpgSignatureType < Types::BaseObject
+ graphql_name 'GpgSignature'
+ description 'GPG signature for a signed commit'
+
+ implements Types::CommitSignatureInterface
+
+ authorize :download_code
+
+ field :user, Types::UserType, null: true,
+ description: 'User associated with the key.'
+
+ field :gpg_key_user_name, GraphQL::Types::String,
+ null: true,
+ description: 'User name associated with the GPG key.'
+
+ field :gpg_key_user_email, GraphQL::Types::String,
+ null: true,
+ description: 'User email associated with the GPG key.'
+
+ field :gpg_key_primary_keyid, GraphQL::Types::String,
+ null: true,
+ description: 'ID of the GPG key.'
+ end
+ end
+end
diff --git a/app/graphql/types/commit_signatures/verification_status_enum.rb b/app/graphql/types/commit_signatures/verification_status_enum.rb
new file mode 100644
index 00000000000..9df1b7abd82
--- /dev/null
+++ b/app/graphql/types/commit_signatures/verification_status_enum.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+# rubocop:disable Graphql/AuthorizeTypes
+
+module Types
+ module CommitSignatures
+ class VerificationStatusEnum < BaseEnum
+ graphql_name 'VerificationStatus'
+ description 'Verification status of a GPG or X.509 signature for a commit.'
+
+ ::CommitSignatures::GpgSignature.verification_statuses.each do |status, _|
+ value status.upcase, value: status, description: "#{status} verification status."
+ end
+ end
+ end
+end
+
+# rubocop:enable Graphql/AuthorizeTypes
diff --git a/app/graphql/types/commit_signatures/x509_signature_type.rb b/app/graphql/types/commit_signatures/x509_signature_type.rb
new file mode 100644
index 00000000000..9ac96dbc015
--- /dev/null
+++ b/app/graphql/types/commit_signatures/x509_signature_type.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+module Types
+ module CommitSignatures
+ class X509SignatureType < Types::BaseObject
+ graphql_name 'X509Signature'
+ description 'X.509 signature for a signed commit'
+
+ implements Types::CommitSignatureInterface
+
+ authorize :download_code
+
+ field :user, Types::UserType, null: true,
+ calls_gitaly: true,
+ description: 'User associated with the key.'
+
+ field :x509_certificate, Types::X509CertificateType,
+ null: true,
+ description: 'Certificate used for the signature.'
+ end
+ end
+end
diff --git a/app/graphql/types/commit_type.rb b/app/graphql/types/commit_type.rb
index dfb02f29fb7..5dd862c7388 100644
--- a/app/graphql/types/commit_type.rb
+++ b/app/graphql/types/commit_type.rb
@@ -4,7 +4,7 @@ module Types
class CommitType < BaseObject
graphql_name 'Commit'
- authorize :download_code
+ authorize :read_code
present_using CommitPresenter
@@ -40,6 +40,11 @@ module Types
field :web_path, type: GraphQL::Types::String, null: false,
description: 'Web path of the commit.'
+ field :signature, type: Types::CommitSignatureInterface,
+ null: true,
+ calls_gitaly: true,
+ description: 'Signature of the commit.'
+
field :signature_html, type: GraphQL::Types::String, null: true, calls_gitaly: true,
description: 'Rendered HTML of the commit signature.'
diff --git a/app/graphql/types/concerns/gitlab_style_deprecations.rb b/app/graphql/types/concerns/gitlab_style_deprecations.rb
index e404f1fcad9..859a27cac4c 100644
--- a/app/graphql/types/concerns/gitlab_style_deprecations.rb
+++ b/app/graphql/types/concerns/gitlab_style_deprecations.rb
@@ -1,14 +1,22 @@
# frozen_string_literal: true
-# Concern for handling deprecation arguments.
+# Concern for handling GraphQL deprecations.
# https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#deprecating-schema-items
module GitlabStyleDeprecations
extend ActiveSupport::Concern
+ included do
+ attr_accessor :deprecation
+ end
+
+ def visible?(ctx)
+ super && ctx[:remove_deprecated] == true ? deprecation.nil? : true
+ end
+
private
- # Mutate the arguments, returns the deprecation
- def gitlab_deprecation(kwargs)
+ # Set deprecation, mutate the arguments
+ def init_gitlab_deprecation(kwargs)
if kwargs[:deprecation_reason].present?
raise ArgumentError, 'Use `deprecated` property instead of `deprecation_reason`. ' \
'See https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#deprecating-schema-items'
@@ -17,14 +25,12 @@ module GitlabStyleDeprecations
# GitLab allows items to be marked as "alpha", which leverages GraphQL deprecations.
deprecation_args = kwargs.extract!(:alpha, :deprecated)
- deprecation = ::Gitlab::Graphql::Deprecation.parse(**deprecation_args)
+ self.deprecation = ::Gitlab::Graphql::Deprecation.parse(**deprecation_args)
return unless deprecation
raise ArgumentError, "Bad deprecation. #{deprecation.errors.full_messages.to_sentence}" unless deprecation.valid?
kwargs[:deprecation_reason] = deprecation.deprecation_reason
kwargs[:description] = deprecation.edit_description(kwargs[:description])
-
- deprecation
end
end
diff --git a/app/graphql/types/deployment_details_type.rb b/app/graphql/types/deployment_details_type.rb
index f8ba0cb1b24..bbb5cc8e3f1 100644
--- a/app/graphql/types/deployment_details_type.rb
+++ b/app/graphql/types/deployment_details_type.rb
@@ -5,7 +5,7 @@ module Types
graphql_name 'DeploymentDetails'
description 'The details of the deployment'
authorize :read_deployment
- present_using Deployments::DeploymentPresenter
+ present_using ::Deployments::DeploymentPresenter
field :tags,
[Types::DeploymentTagType],
@@ -13,3 +13,5 @@ module Types
calls_gitaly: true
end
end
+
+Types::DeploymentDetailsType.prepend_mod_with('Types::DeploymentDetailsType')
diff --git a/app/graphql/types/deployment_type.rb b/app/graphql/types/deployment_type.rb
index 70a3a4cb574..59b59dc4e1d 100644
--- a/app/graphql/types/deployment_type.rb
+++ b/app/graphql/types/deployment_type.rb
@@ -11,7 +11,7 @@ module Types
graphql_name 'Deployment'
description 'The deployment of an environment'
- present_using Deployments::DeploymentPresenter
+ present_using ::Deployments::DeploymentPresenter
authorize :read_deployment
diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb
index 45357de5502..4e5ddbac8a2 100644
--- a/app/graphql/types/group_type.rb
+++ b/app/graphql/types/group_type.rb
@@ -231,9 +231,7 @@ module Types
field :work_item_types, Types::WorkItems::TypeType.connection_type,
resolver: Resolvers::WorkItems::TypesResolver,
- description: 'Work item types available to the group.' \
- ' Returns `null` if `work_items` feature flag is disabled.' \
- ' This flag is disabled by default, because the feature is experimental and is subject to change without notice.'
+ description: 'Work item types available to the group.'
def label(title:)
BatchLoader::GraphQL.for(title).batch(key: group) do |titles, loader, args|
diff --git a/app/graphql/types/incident_management/timeline_event_tag_type.rb b/app/graphql/types/incident_management/timeline_event_tag_type.rb
new file mode 100644
index 00000000000..452294d4797
--- /dev/null
+++ b/app/graphql/types/incident_management/timeline_event_tag_type.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module Types
+ module IncidentManagement
+ class TimelineEventTagType < BaseObject
+ graphql_name 'TimelineEventTagType'
+
+ description 'Describes a tag on an incident management timeline event.'
+
+ authorize :read_incident_management_timeline_event_tag
+
+ field :id,
+ Types::GlobalIDType[::IncidentManagement::TimelineEventTag],
+ null: false,
+ description: 'ID of the timeline event tag.'
+
+ field :name,
+ GraphQL::Types::String,
+ null: false,
+ description: 'Name of the timeline event tag.'
+ end
+ end
+end
diff --git a/app/graphql/types/incident_management/timeline_event_type.rb b/app/graphql/types/incident_management/timeline_event_type.rb
index 690facc8732..939dd9f09e5 100644
--- a/app/graphql/types/incident_management/timeline_event_type.rb
+++ b/app/graphql/types/incident_management/timeline_event_type.rb
@@ -53,6 +53,13 @@ module Types
null: false,
description: 'Timestamp when the event occurred.'
+ field :timeline_event_tags,
+ ::Types::IncidentManagement::TimelineEventTagType.connection_type,
+ null: true,
+ description: 'Tags for the incident timeline event.',
+ extras: [:lookahead],
+ resolver: Resolvers::IncidentManagement::TimelineEventTagsResolver
+
field :created_at,
Types::TimeType,
null: false,
diff --git a/app/graphql/types/issue_connection.rb b/app/graphql/types/issue_connection.rb
index 8e5c88648ea..2f07888b43e 100644
--- a/app/graphql/types/issue_connection.rb
+++ b/app/graphql/types/issue_connection.rb
@@ -1,15 +1,22 @@
# frozen_string_literal: true
# Normally this wouldn't be needed and we could use
+#
# type Types::IssueType.connection_type, null: true
-# in a resolver. However we can end up with cyclic definitions,
-# which can result in errors like
+#
+# in a resolver. However we can end up with cyclic definitions.
+# Running the spec locally can result in errors like
+#
# NameError: uninitialized constant Resolvers::GroupIssuesResolver
#
-# Now we would use
+# or other errors. To fix this, we created this file and use
+#
# type "Types::IssueConnection", null: true
+#
# which gives a delayed resolution, and the proper connection type.
+#
# See app/graphql/resolvers/base_issues_resolver.rb
# Reference: https://github.com/rmosolgo/graphql-ruby/issues/3974#issuecomment-1084444214
-
+# and https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#testing-tips-and-tricks
+#
Types::IssueConnection = Types::IssueType.connection_type
diff --git a/app/graphql/types/issue_type.rb b/app/graphql/types/issue_type.rb
index 76fac831199..dd2ad26ce49 100644
--- a/app/graphql/types/issue_type.rb
+++ b/app/graphql/types/issue_type.rb
@@ -123,7 +123,15 @@ module Types
field :alert_management_alert,
Types::AlertManagement::AlertType,
null: true,
- description: 'Alert associated to this issue.'
+ description: 'Alert associated to this issue.',
+ deprecated: { reason: 'Use `alert_management_alerts`', milestone: '15.6' }
+
+ field :alert_management_alerts,
+ Types::AlertManagement::AlertType.connection_type,
+ null: true,
+ description: 'Alert Management alerts associated to this issue.',
+ extras: [:lookahead],
+ resolver: Resolvers::AlertManagement::AlertResolver
field :severity, Types::IssuableSeverityEnum, null: true,
description: 'Severity level of the incident.'
diff --git a/app/graphql/types/issue_type_enum.rb b/app/graphql/types/issue_type_enum.rb
index 1044c2ceea4..78cd27f60c3 100644
--- a/app/graphql/types/issue_type_enum.rb
+++ b/app/graphql/types/issue_type_enum.rb
@@ -10,7 +10,11 @@ module Types
end
value 'TASK', value: 'task',
- description: 'Task issue type. Available only when feature flag `work_items` is enabled.',
+ description: 'Task issue type.',
alpha: { milestone: '15.2' }
+
+ value 'OBJECTIVE', value: 'objective',
+ description: 'Objective issue type. Available only when feature flag `okrs_mvc` is enabled.',
+ alpha: { milestone: '15.6' }
end
end
diff --git a/app/graphql/types/issues/unioned_issue_filter_input_type.rb b/app/graphql/types/issues/unioned_issue_filter_input_type.rb
new file mode 100644
index 00000000000..9c7261279c7
--- /dev/null
+++ b/app/graphql/types/issues/unioned_issue_filter_input_type.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Types
+ module Issues
+ class UnionedIssueFilterInputType < BaseInputObject
+ graphql_name 'UnionedIssueFilterInput'
+
+ argument :assignee_usernames, [GraphQL::Types::String],
+ required: false,
+ description: 'Filters issues that are assigned to at least one of the given users.'
+ argument :author_usernames, [GraphQL::Types::String],
+ required: false,
+ description: 'Filters issues that are authored by one of the given users.'
+ end
+ end
+end
diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb
index 8cc600fc68e..49bf7aa638c 100644
--- a/app/graphql/types/merge_request_type.rb
+++ b/app/graphql/types/merge_request_type.rb
@@ -20,7 +20,7 @@ module Types
description: 'Timestamp of when the merge request was created.'
field :description, GraphQL::Types::String, null: true,
description: 'Description of the merge request (Markdown rendered as HTML for caching).'
- field :diff_head_sha, GraphQL::Types::String, null: true,
+ field :diff_head_sha, GraphQL::Types::String, null: true, calls_gitaly: true,
description: 'Diff head SHA of the merge request.'
field :diff_refs, Types::DiffRefsType, null: true,
description: 'References of the base SHA, the head SHA, and the start SHA for this merge request.'
@@ -100,8 +100,7 @@ module Types
field :detailed_merge_status, ::Types::MergeRequests::DetailedMergeStatusEnum, null: true,
calls_gitaly: true,
- description: 'Detailed merge status of the merge request.',
- alpha: { milestone: '15.3' }
+ description: 'Detailed merge status of the merge request.'
field :mergeable_discussions_state, GraphQL::Types::Boolean, null: true,
calls_gitaly: true,
diff --git a/app/graphql/types/metadata_type.rb b/app/graphql/types/metadata_type.rb
index b00fcfd38ad..492cca365f3 100644
--- a/app/graphql/types/metadata_type.rb
+++ b/app/graphql/types/metadata_type.rb
@@ -6,6 +6,8 @@ module Types
authorize :read_instance_metadata
+ field :enterprise, GraphQL::Types::Boolean, null: false,
+ description: 'Enterprise edition.'
field :kas, ::Types::Metadata::KasType, null: false,
description: 'Metadata about KAS.'
field :revision, GraphQL::Types::String, null: false,
diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb
index 5ffc1aeacad..1cbb2ede544 100644
--- a/app/graphql/types/mutation_type.rb
+++ b/app/graphql/types/mutation_type.rb
@@ -47,10 +47,11 @@ module Types
mount_mutation Mutations::DependencyProxy::ImageTtlGroupPolicy::Update
mount_mutation Mutations::DependencyProxy::GroupSettings::Update
mount_mutation Mutations::Environments::CanaryIngress::Update
- mount_mutation Mutations::IncidentManagement::TimelineEvent::Create
+ mount_mutation Mutations::IncidentManagement::TimelineEvent::Create, alpha: { milestone: '15.6' }
mount_mutation Mutations::IncidentManagement::TimelineEvent::PromoteFromNote
mount_mutation Mutations::IncidentManagement::TimelineEvent::Update
mount_mutation Mutations::IncidentManagement::TimelineEvent::Destroy
+ mount_mutation Mutations::IncidentManagement::TimelineEventTag::Create
mount_mutation Mutations::Issues::Create
mount_mutation Mutations::Issues::SetAssignees
mount_mutation Mutations::Issues::SetCrmContacts
@@ -115,6 +116,7 @@ module Types
mount_mutation Mutations::Ci::Pipeline::Destroy
mount_mutation Mutations::Ci::Pipeline::Retry
mount_mutation Mutations::Ci::PipelineSchedule::Delete
+ mount_mutation Mutations::Ci::PipelineSchedule::TakeOwnership
mount_mutation Mutations::Ci::CiCdSettingsUpdate, deprecated: {
reason: :renamed,
replacement: 'ProjectCiCdSettingsUpdate',
diff --git a/app/graphql/types/packages/package_base_type.rb b/app/graphql/types/packages/package_base_type.rb
index 2dc4a2a2bb6..9ec4bb73c47 100644
--- a/app/graphql/types/packages/package_base_type.rb
+++ b/app/graphql/types/packages/package_base_type.rb
@@ -12,6 +12,8 @@ module Types
field :id, ::Types::GlobalIDType[::Packages::Package], null: false, description: 'ID of the package.'
+ field :_links, Types::Packages::PackageLinksType, null: false, method: :itself,
+ description: 'Map of links to perform actions on the package.'
field :can_destroy, GraphQL::Types::Boolean, null: false, description: 'Whether the user can destroy the package.'
field :created_at, Types::TimeType, null: false, description: 'Date of creation.'
field :metadata, Types::Packages::MetadataType,
diff --git a/app/graphql/types/packages/package_links_type.rb b/app/graphql/types/packages/package_links_type.rb
new file mode 100644
index 00000000000..f16937530b9
--- /dev/null
+++ b/app/graphql/types/packages/package_links_type.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Types
+ module Packages
+ class PackageLinksType < BaseObject
+ graphql_name 'PackageLinks'
+ description 'Represents links to perform actions on the package'
+ authorize :read_package
+
+ include ::Routing::PackagesHelper
+
+ field :web_path, GraphQL::Types::String, null: true, description: 'Path to the package details page.'
+
+ def web_path
+ package_path(object)
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/permission_types/ci/runner.rb b/app/graphql/types/permission_types/ci/runner.rb
index 2e92a4011e9..096dcd272cc 100644
--- a/app/graphql/types/permission_types/ci/runner.rb
+++ b/app/graphql/types/permission_types/ci/runner.rb
@@ -6,7 +6,7 @@ module Types
class Runner < BasePermissionType
graphql_name 'RunnerPermissions'
- abilities :read_runner, :update_runner, :delete_runner
+ abilities :read_runner, :update_runner, :delete_runner, :assign_runner
end
end
end
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index a41af34ef4c..771dad00fb3 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -37,6 +37,10 @@ module Types
null: false,
description: 'Path of the project.'
+ field :incident_management_timeline_event_tags, [Types::IncidentManagement::TimelineEventTagType],
+ null: true,
+ description: 'Timeline event tags for the project.'
+
field :sast_ci_configuration, Types::CiConfiguration::Sast::Type,
null: true,
calls_gitaly: true,
@@ -226,8 +230,7 @@ module Types
Types::IssueType.connection_type,
null: true,
description: 'Issues of the project.',
- extras: [:lookahead],
- resolver: Resolvers::IssuesResolver
+ resolver: Resolvers::ProjectIssuesResolver
field :work_items,
Types::WorkItemType.connection_type,
@@ -241,7 +244,6 @@ module Types
Types::IssueStatusCountsType,
null: true,
description: 'Counts of issues by status for the project.',
- extras: [:lookahead],
resolver: Resolvers::IssueStatusCountsResolver
field :milestones, Types::MilestoneType.connection_type,
@@ -275,7 +277,7 @@ module Types
Types::IssueType,
null: true,
description: 'A single issue of the project.',
- resolver: Resolvers::IssuesResolver.single
+ resolver: Resolvers::ProjectIssuesResolver.single
field :packages,
description: 'Packages of the project.',
@@ -513,9 +515,7 @@ module Types
field :work_item_types, Types::WorkItems::TypeType.connection_type,
resolver: Resolvers::WorkItems::TypesResolver,
- description: 'Work item types available to the project.' \
- ' Returns `null` if `work_items` feature flag is disabled.' \
- ' This flag is disabled by default, because the feature is experimental and is subject to change without notice.'
+ description: 'Work item types available to the project.'
field :timelog_categories, Types::TimeTracking::TimelogCategoryType.connection_type,
null: true,
@@ -532,6 +532,11 @@ module Types
description: "Branch rules configured for the project.",
resolver: Resolvers::Projects::BranchRulesResolver
+ field :languages, [Types::Projects::RepositoryLanguageType],
+ null: true,
+ description: "Programming languages used in the project.",
+ calls_gitaly: true
+
def timelog_categories
object.project_namespace.timelog_categories if Feature.enabled?(:timelog_categories)
end
@@ -598,7 +603,7 @@ module Types
end
def sast_ci_configuration
- return unless Ability.allowed?(current_user, :download_code, object)
+ return unless Ability.allowed?(current_user, :read_code, object)
::Security::CiConfiguration::SastParserService.new(object).configuration
end
@@ -609,6 +614,10 @@ module Types
object.service_desk_address
end
+ def languages
+ ::Projects::RepositoryLanguagesService.new(project, current_user).execute
+ end
+
private
def project
diff --git a/app/graphql/types/projects/branch_rule_type.rb b/app/graphql/types/projects/branch_rule_type.rb
index e7632c17cca..1afd2cc3fef 100644
--- a/app/graphql/types/projects/branch_rule_type.rb
+++ b/app/graphql/types/projects/branch_rule_type.rb
@@ -8,6 +8,8 @@ module Types
accepts ::ProtectedBranch
authorize :read_protected_branch
+ alias_method :branch_rule, :object
+
field :name,
type: GraphQL::Types::String,
null: false,
@@ -20,6 +22,12 @@ module Types
calls_gitaly: true,
description: "Check if this branch rule protects the project's default branch."
+ field :matching_branches_count,
+ type: GraphQL::Types::Int,
+ null: false,
+ calls_gitaly: true,
+ description: 'Number of existing branches that match this branch rule.'
+
field :branch_protection,
type: Types::BranchRules::BranchProtectionType,
null: false,
@@ -35,6 +43,10 @@ module Types
Types::TimeType,
null: false,
description: 'Timestamp of when the branch rule was last updated.'
+
+ def matching_branches_count
+ branch_rule.matching(branch_rule.project.repository.branch_names).count
+ end
end
end
end
diff --git a/app/graphql/types/projects/repository_language_type.rb b/app/graphql/types/projects/repository_language_type.rb
new file mode 100644
index 00000000000..76c645c0e85
--- /dev/null
+++ b/app/graphql/types/projects/repository_language_type.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module Types
+ module Projects
+ # rubocop: disable Graphql/AuthorizeTypes
+ class RepositoryLanguageType < BaseObject
+ graphql_name 'RepositoryLanguage'
+
+ field :name, GraphQL::Types::String, null: false,
+ description: 'Name of the repository language.'
+
+ field :share, GraphQL::Types::Float, null: true,
+ description: "Percentage of the repository's languages."
+
+ field :color, Types::ColorType, null: true,
+ description: 'Color to visualize the repository language.'
+ end
+ # rubocop: enable Graphql/AuthorizeTypes
+ end
+end
diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb
index 1b39f43659e..21cb3f9e06c 100644
--- a/app/graphql/types/query_type.rb
+++ b/app/graphql/types/query_type.rb
@@ -82,6 +82,13 @@ module Types
field :echo, resolver: Resolvers::EchoResolver
+ field :issues,
+ null: true,
+ alpha: { milestone: '15.6' },
+ resolver: Resolvers::IssuesResolver,
+ description: 'Issues visible by the current user.' \
+ ' Returns null if the `root_level_issues_query` feature flag is disabled.'
+
field :issue, Types::IssueType,
null: true,
description: 'Find an issue.' do
@@ -92,7 +99,7 @@ module Types
null: true,
resolver: Resolvers::WorkItemResolver,
alpha: { milestone: '15.1' },
- description: 'Find a work item. Returns `null` if `work_items` feature flag is disabled.'
+ description: 'Find a work item.'
field :merge_request, Types::MergeRequestType,
null: true,
diff --git a/app/graphql/types/release_links_type.rb b/app/graphql/types/release_links_type.rb
index 6bc767152e8..2258adc131c 100644
--- a/app/graphql/types/release_links_type.rb
+++ b/app/graphql/types/release_links_type.rb
@@ -14,12 +14,12 @@ module Types
GraphQL::Types::String,
null: true,
description: 'HTTP URL of the issues page, filtered by this release and `state=closed`.',
- authorize: :download_code
+ authorize: :read_code
field :closed_merge_requests_url,
GraphQL::Types::String,
null: true,
description: 'HTTP URL of the merge request page , filtered by this release and `state=closed`.',
- authorize: :download_code
+ authorize: :read_code
field :edit_url, GraphQL::Types::String, null: true,
description: "HTTP URL of the release's edit page.",
authorize: :update_release
@@ -27,17 +27,17 @@ module Types
GraphQL::Types::String,
null: true,
description: 'HTTP URL of the merge request page , filtered by this release and `state=merged`.',
- authorize: :download_code
+ authorize: :read_code
field :opened_issues_url,
GraphQL::Types::String,
null: true,
description: 'HTTP URL of the issues page, filtered by this release and `state=open`.',
- authorize: :download_code
+ authorize: :read_code
field :opened_merge_requests_url,
GraphQL::Types::String,
null: true,
description: 'HTTP URL of the merge request page, filtered by this release and `state=open`.',
- authorize: :download_code
+ authorize: :read_code
field :self_url, GraphQL::Types::String, null: true,
description: 'HTTP URL of the release.'
end
diff --git a/app/graphql/types/release_source_type.rb b/app/graphql/types/release_source_type.rb
index e05a2926ac1..e1959738c4b 100644
--- a/app/graphql/types/release_source_type.rb
+++ b/app/graphql/types/release_source_type.rb
@@ -5,7 +5,7 @@ module Types
graphql_name 'ReleaseSource'
description 'Represents the source code attached to a release in a particular format'
- authorize :download_code
+ authorize :read_code
field :format, GraphQL::Types::String, null: true,
description: 'Format of the source.'
diff --git a/app/graphql/types/release_type.rb b/app/graphql/types/release_type.rb
index d70fe05c906..a20e53ad1bd 100644
--- a/app/graphql/types/release_type.rb
+++ b/app/graphql/types/release_type.rb
@@ -39,7 +39,7 @@ module Types
description: 'Name of the tag associated with the release.'
field :tag_path, GraphQL::Types::String, null: true,
description: 'Relative web path to the tag associated with the release.',
- authorize: :download_code
+ authorize: :read_code
field :upcoming_release, GraphQL::Types::Boolean, null: true, method: :upcoming_release?,
description: 'Indicates the release is an upcoming release.'
field :historical_release, GraphQL::Types::Boolean, null: true, method: :historical_release?,
diff --git a/app/graphql/types/repository_type.rb b/app/graphql/types/repository_type.rb
index ba94f59ab6c..ab5d1bd8c9e 100644
--- a/app/graphql/types/repository_type.rb
+++ b/app/graphql/types/repository_type.rb
@@ -4,7 +4,7 @@ module Types
class RepositoryType < BaseObject
graphql_name 'Repository'
- authorize :download_code
+ authorize :read_code
field :blobs, Types::Repository::BlobType.connection_type, null: true, resolver: Resolvers::BlobsResolver, calls_gitaly: true,
description: 'Blobs contained within the repository'
diff --git a/app/graphql/types/subscription_type.rb b/app/graphql/types/subscription_type.rb
index 3b8f5c64beb..9d5edec82b2 100644
--- a/app/graphql/types/subscription_type.rb
+++ b/app/graphql/types/subscription_type.rb
@@ -22,6 +22,9 @@ module Types
field :issuable_dates_updated, subscription: Subscriptions::IssuableUpdated, null: true,
description: 'Triggered when the due date or start date of an issuable is updated.'
+ field :issuable_milestone_updated, subscription: Subscriptions::IssuableUpdated, null: true,
+ description: 'Triggered when the milestone of an issuable is updated.'
+
field :merge_request_reviewers_updated,
subscription: Subscriptions::IssuableUpdated,
null: true,
diff --git a/app/graphql/types/work_items/widget_interface.rb b/app/graphql/types/work_items/widget_interface.rb
index a3943361114..b85d0a23535 100644
--- a/app/graphql/types/work_items/widget_interface.rb
+++ b/app/graphql/types/work_items/widget_interface.rb
@@ -16,7 +16,8 @@ module Types
::Types::WorkItems::Widgets::HierarchyType,
::Types::WorkItems::Widgets::LabelsType,
::Types::WorkItems::Widgets::AssigneesType,
- ::Types::WorkItems::Widgets::StartAndDueDateType
+ ::Types::WorkItems::Widgets::StartAndDueDateType,
+ ::Types::WorkItems::Widgets::MilestoneType
].freeze
def self.ce_orphan_types
@@ -38,6 +39,8 @@ module Types
::Types::WorkItems::Widgets::LabelsType
when ::WorkItems::Widgets::StartAndDueDate
::Types::WorkItems::Widgets::StartAndDueDateType
+ when ::WorkItems::Widgets::Milestone
+ ::Types::WorkItems::Widgets::MilestoneType
else
raise "Unknown GraphQL type for widget #{object}"
end
diff --git a/app/graphql/types/work_items/widgets/milestone_input_type.rb b/app/graphql/types/work_items/widgets/milestone_input_type.rb
new file mode 100644
index 00000000000..996c782373f
--- /dev/null
+++ b/app/graphql/types/work_items/widgets/milestone_input_type.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Types
+ module WorkItems
+ module Widgets
+ class MilestoneInputType < BaseInputObject
+ graphql_name 'WorkItemWidgetMilestoneInput'
+
+ argument :milestone_id,
+ Types::GlobalIDType[::Milestone],
+ required: :nullable,
+ prepare: ->(id, _) { id.model_id unless id.nil? },
+ description: 'Milestone to assign to the work item.'
+ end
+ end
+ end
+end
diff --git a/app/graphql/types/work_items/widgets/milestone_type.rb b/app/graphql/types/work_items/widgets/milestone_type.rb
new file mode 100644
index 00000000000..73318e58a00
--- /dev/null
+++ b/app/graphql/types/work_items/widgets/milestone_type.rb
@@ -0,0 +1,23 @@
+# 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 MilestoneType < BaseObject
+ graphql_name 'WorkItemWidgetMilestone'
+ description 'Represents a milestone widget'
+
+ implements Types::WorkItems::WidgetInterface
+
+ field :milestone,
+ ::Types::MilestoneType,
+ null: true,
+ description: 'Milestone of the work item.'
+ end
+ # rubocop:enable Graphql/AuthorizeTypes
+ end
+ end
+end
diff --git a/app/graphql/types/x509_certificate_type.rb b/app/graphql/types/x509_certificate_type.rb
new file mode 100644
index 00000000000..806aa441af7
--- /dev/null
+++ b/app/graphql/types/x509_certificate_type.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+# rubocop:disable Graphql/AuthorizeTypes
+
+module Types
+ class X509CertificateType < Types::BaseObject
+ graphql_name 'X509Certificate'
+ description 'Represents an X.509 certificate.'
+
+ field :certificate_status, GraphQL::Types::String,
+ null: false,
+ description: 'Indicates if the certificate is good or revoked.'
+
+ field :created_at, Types::TimeType, null: false,
+ description: 'Timestamp of when the certificate was saved.'
+
+ field :email, GraphQL::Types::String, null: false,
+ description: 'Email associated with the cerificate.'
+
+ field :id, GraphQL::Types::ID, null: false, description: 'ID of the certificate.'
+
+ field :serial_number, GraphQL::Types::String, null: false,
+ description: 'Serial number of the certificate.'
+
+ field :subject, GraphQL::Types::String, null: false, description: 'Subject of the certificate.'
+
+ field :subject_key_identifier, GraphQL::Types::String,
+ null: false,
+ description: 'Subject key identifier of the certificate.'
+
+ field :updated_at, Types::TimeType, null: false,
+ description: 'Timestamp of when the certificate was last updated.'
+
+ field :x509_issuer, Types::X509IssuerType, null: false,
+ description: 'Issuer of the certificate.'
+ end
+end
+
+# rubocop:enable Graphql/AuthorizeTypes
diff --git a/app/graphql/types/x509_issuer_type.rb b/app/graphql/types/x509_issuer_type.rb
new file mode 100644
index 00000000000..a5759e48ee0
--- /dev/null
+++ b/app/graphql/types/x509_issuer_type.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+# rubocop:disable Graphql/AuthorizeTypes
+
+module Types
+ class X509IssuerType < Types::BaseObject
+ graphql_name 'X509Issuer'
+ description 'Issuer of an X.509 certificate.'
+
+ field :created_at, Types::TimeType, null: true,
+ description: 'Timestamp of when the issuer was created.'
+
+ field :crl_url, GraphQL::Types::String, null: true,
+ description: 'Certificate revokation list of the issuer.'
+
+ field :id, GraphQL::Types::ID, null: true, description: 'ID of the issuer.'
+
+ field :subject, GraphQL::Types::String, null: true, description: 'Subject of the issuer.'
+
+ field :subject_key_identifier, GraphQL::Types::String,
+ null: true,
+ description: 'Subject key identifier of the issuer.'
+
+ field :updated_at, Types::TimeType, null: true,
+ description: 'Timestamp of when the issuer was last updated.'
+ end
+end
+
+# rubocop:enable Graphql/AuthorizeTypes
diff --git a/app/helpers/appearances_helper.rb b/app/helpers/appearances_helper.rb
index 957c2afb6d2..9a323852996 100644
--- a/app/helpers/appearances_helper.rb
+++ b/app/helpers/appearances_helper.rb
@@ -10,7 +10,7 @@ module AppearancesHelper
def default_brand_title
# This resides in a separate method so that EE can easily redefine it.
- 'GitLab Community Edition'
+ _('GitLab Community Edition')
end
def brand_image
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 32af1599bd1..ce6900d1779 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -315,7 +315,7 @@ module ApplicationHelper
class_names << 'epic-boards-page gl-overflow-auto' if current_controller?(:epic_boards)
class_names << 'with-performance-bar' if performance_bar_enabled?
class_names << system_message_class
- class_names << marketing_header_experiment_class
+ class_names << 'logged-out-marketing-header' unless current_user
class_names
end
@@ -377,13 +377,13 @@ module ApplicationHelper
end
def client_class_list
- "gl-browser-#{browser.id} gl-platform-#{browser.platform.id}"
+ "gl-browser-#{browser_id} gl-platform-#{platform_id}"
end
def client_js_flags
{
- "is#{browser.id.to_s.titlecase}": true,
- "is#{browser.platform.id.to_s.titlecase}": true
+ "is#{browser_id.titlecase}": true,
+ "is#{platform_id.titlecase}": true
}
end
@@ -453,20 +453,16 @@ module ApplicationHelper
private
- def appearance
- ::Appearance.current
+ def browser_id
+ browser.unknown? ? 'generic' : browser.id.to_s
end
- def marketing_header_experiment_class
- return if current_user
+ def platform_id
+ browser.platform.unknown? ? 'other' : browser.platform.id.to_s
+ end
- experiment(:logged_out_marketing_header, actor: nil) do |e|
- html_class = 'logged-out-marketing-header-candidate'
- e.candidate { html_class }
- e.variant(:trial_focused) { html_class }
- e.control {}
- e.run
- end
+ def appearance
+ ::Appearance.current
end
end
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 21b18203677..7f13f609353 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -221,6 +221,7 @@ module ApplicationSettingsHelper
:default_projects_limit,
:default_snippet_visibility,
:delete_inactive_projects,
+ :disable_admin_oauth_scopes,
:disable_feed_token,
:disabled_oauth_sign_in_sources,
:domain_denylist,
@@ -241,6 +242,7 @@ module ApplicationSettingsHelper
:eks_access_key_id,
:eks_secret_access_key,
:email_author_in_body,
+ :email_confirmation_setting,
:enabled_git_access_protocol,
:enforce_terms,
:error_tracking_enabled,
@@ -278,6 +280,7 @@ module ApplicationSettingsHelper
:inactive_projects_send_warning_email_after_months,
:invisible_captcha_enabled,
:jira_connect_application_key,
+ :jira_connect_proxy_url,
:max_artifacts_size,
:max_attachment_size,
:max_export_size,
@@ -543,6 +546,7 @@ module ApplicationSettingsHelper
signup_enabled: @application_setting[:signup_enabled].to_s,
require_admin_approval_after_user_signup: @application_setting[:require_admin_approval_after_user_signup].to_s,
send_user_confirmation_email: @application_setting[:send_user_confirmation_email].to_s,
+ email_confirmation_setting: @application_setting[:email_confirmation_setting].to_s,
minimum_password_length: @application_setting[:minimum_password_length],
minimum_password_length_min: ApplicationSetting::DEFAULT_MINIMUM_PASSWORD_LENGTH,
minimum_password_length_max: Devise.password_length.max,
@@ -558,7 +562,9 @@ module ApplicationSettingsHelper
supported_syntax_link_url: 'https://github.com/google/re2/wiki/Syntax',
email_restrictions: @application_setting.email_restrictions.to_s,
after_sign_up_text: @application_setting[:after_sign_up_text].to_s,
- pending_user_count: pending_user_count
+ pending_user_count: pending_user_count,
+ project_sharing_help_link: help_page_path('user/group/access_and_permissions', anchor: 'prevent-a-project-from-being-shared-with-groups'),
+ group_sharing_help_link: help_page_path('user/group/access_and_permissions', anchor: 'prevent-group-sharing-outside-the-group-hierarchy')
}
end
end
diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb
index 617bc0e9bee..798bb7b64a4 100644
--- a/app/helpers/avatars_helper.rb
+++ b/app/helpers/avatars_helper.rb
@@ -105,9 +105,10 @@ module AvatarsHelper
end
def avatar_without_link(resource, options = {})
- if resource.is_a?(Namespaces::UserNamespace)
+ case resource
+ when Namespaces::UserNamespace
user_avatar_without_link(options.merge(user: resource.first_owner))
- elsif resource.is_a?(Group)
+ when Group
group_icon(resource, options.merge(class: 'avatar'))
end
end
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 6c09e15f56f..f08c1a2ff0a 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -74,24 +74,6 @@ module BlobHelper
ref)
end
- def modify_file_button(project = @project, ref = @ref, path = @path, blob:, label:, action:, btn_class:, modal_type:)
- return unless current_user
- return unless blob
-
- common_classes = "btn gl-button btn-default btn-#{btn_class}"
- base_button = button_tag(label, class: "#{common_classes} disabled", disabled: true)
-
- if !on_top_of_branch?(project, ref)
- modify_file_button_tooltip(base_button, _("You can only %{action} files when you are on a branch") % { action: action })
- elsif blob.stored_externally?
- modify_file_button_tooltip(base_button, _("It is not possible to %{action} files that are stored in LFS using the web interface") % { action: action })
- elsif can_modify_blob?(blob, project, ref)
- button_tag label, class: "#{common_classes}", 'data-target' => "#modal-#{modal_type}-blob", 'data-toggle' => 'modal'
- elsif can?(current_user, :fork_project, project) && can?(current_user, :create_merge_request_in, project)
- edit_fork_button_tag(common_classes, project, label, edit_modify_file_fork_params(action), action)
- end
- end
-
def can_modify_blob?(blob, project = @project, ref = @ref)
!blob.stored_externally? && can_edit_tree?(project, ref)
end
@@ -346,12 +328,4 @@ module BlobHelper
@path.to_s.end_with?(Ci::Pipeline::CONFIG_EXTENSION) ||
@path.to_s == @project.ci_config_path_or_default
end
-
- private
-
- def modify_file_button_tooltip(button, tooltip_message)
- # Disabled buttons with tooltips should have the tooltip attached
- # to a wrapper element https://bootstrap-vue.org/docs/components/tooltip#disabled-elements
- content_tag(:span, button, class: 'btn-group has-tooltip', title: tooltip_message, data: { container: 'body' })
- end
end
diff --git a/app/helpers/broadcast_messages_helper.rb b/app/helpers/broadcast_messages_helper.rb
index 10cfa97030d..9827f075e54 100644
--- a/app/helpers/broadcast_messages_helper.rb
+++ b/app/helpers/broadcast_messages_helper.rb
@@ -77,11 +77,12 @@ module BroadcastMessagesHelper
return unless current_user.present?
strong_memoize(:current_user_access_level_for_project_or_group) do
- if controller.is_a? Projects::ApplicationController
+ case controller
+ when Projects::ApplicationController
next unless @project
@project.team.max_member_access(current_user.id)
- elsif controller.is_a? Groups::ApplicationController
+ when Groups::ApplicationController
next unless @group
@group.max_member_access_for_user(current_user)
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 5c3b9d4b5ab..e05adc5cd0e 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -24,7 +24,7 @@ module DiffHelper
end
def show_only_context_commits?
- !!params[:only_context_commits] || @merge_request&.commits&.empty?
+ !!params[:only_context_commits] || @merge_request.has_no_commits?
end
def diff_options
@@ -109,11 +109,11 @@ module DiffHelper
end
def inline_diff_btn
- diff_btn('Inline', 'inline', diff_view == :inline)
+ diff_btn(s_('Diffs|Inline'), 'inline', diff_view == :inline)
end
def parallel_diff_btn
- diff_btn('Side-by-side', 'parallel', diff_view == :parallel)
+ diff_btn(s_('Diffs|Side-by-side'), 'parallel', diff_view == :parallel)
end
def submodule_link(blob, ref, repository = @repository)
@@ -227,7 +227,6 @@ module DiffHelper
end
def conflicts(allow_tree_conflicts: false)
- return unless options[:merge_ref_head_diff]
return unless merge_request.cannot_be_merged?
conflicts_service = MergeRequests::Conflicts::ListService.new(merge_request, allow_tree_conflicts: allow_tree_conflicts) # rubocop:disable CodeReuse/ServiceClass
@@ -244,6 +243,10 @@ module DiffHelper
{}
end
+ def params_with_whitespace
+ hide_whitespace? ? safe_params.except(:w) : safe_params.merge(w: 1)
+ end
+
private
def diff_btn(title, name, selected)
@@ -277,13 +280,10 @@ module DiffHelper
params[:w] == '1'
end
- def params_with_whitespace
- hide_whitespace? ? request.query_parameters.except(:w) : request.query_parameters.merge(w: 1)
- end
-
def toggle_whitespace_link(url, options)
options[:class] = [*options[:class], 'btn gl-button btn-default'].join(' ')
- link_to "#{hide_whitespace? ? 'Show' : 'Hide'} whitespace changes", url, class: options[:class]
+ toggle_text = hide_whitespace? ? s_('Diffs|Show whitespace changes') : s_('Diffs|Hide whitespace changes')
+ link_to toggle_text, url, class: options[:class]
end
def code_navigation_path(diffs)
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index b717cbcc312..087e4838ed9 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -68,7 +68,7 @@ module EventsHelper
author = event.author
if author
- name = self_added ? 'You' : author.name
+ name = self_added ? _('You') : author.name
link_to name, user_path(author.username), title: name
else
escape_once(event.author_name)
diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb
index 9e42aeea9ce..963f0b7afc4 100644
--- a/app/helpers/form_helper.rb
+++ b/app/helpers/form_helper.rb
@@ -40,7 +40,7 @@ module FormHelper
end
def dropdown_max_select(data, feature_flag)
- return data[:'max-select'] unless Feature.enabled?(feature_flag)
+ return data[:'max-select'] unless feature_flag.nil? || Feature.enabled?(feature_flag)
if data[:'max-select'] && data[:'max-select'] < ::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
data[:'max-select']
@@ -162,12 +162,7 @@ module FormHelper
new_options[:title] = _('Select assignee(s)')
new_options[:data][:'dropdown-header'] = 'Assignee(s)'
-
- if Feature.enabled?(:limit_assignees_per_issuable)
- new_options[:data][:'max-select'] = ::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
- else
- new_options[:data].delete(:'max-select')
- end
+ new_options[:data][:'max-select'] = ::Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
new_options
end
diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb
index 1be395437ea..178e9d0ab74 100644
--- a/app/helpers/gitlab_routing_helper.rb
+++ b/app/helpers/gitlab_routing_helper.rb
@@ -17,6 +17,7 @@ module GitlabRoutingHelper
include ::Routing::WikiHelper
include ::Routing::GraphqlHelper
include ::Routing::PseudonymizationHelper
+ include ::Routing::PackagesHelper
included do
Gitlab::Routing.includes_helpers(self)
end
diff --git a/app/helpers/graph_helper.rb b/app/helpers/graph_helper.rb
index 45ca820f7b3..788002f126d 100644
--- a/app/helpers/graph_helper.rb
+++ b/app/helpers/graph_helper.rb
@@ -5,8 +5,10 @@ module GraphHelper
refs = [commit.ref_names(repo).join(' ')]
# append note count
- notes_count = @graph.notes[commit.id]
- refs << "[#{pluralize(notes_count, 'note')}]" if notes_count > 0
+ unless Feature.enabled?(:disable_network_graph_notes_count, @project, type: :experiment)
+ notes_count = @graph.notes[commit.id]
+ refs << "[#{pluralize(notes_count, 'note')}]" if notes_count > 0
+ end
refs.join
end
diff --git a/app/helpers/groups/group_members_helper.rb b/app/helpers/groups/group_members_helper.rb
index 6a013a6c864..5034a4cb9b4 100644
--- a/app/helpers/groups/group_members_helper.rb
+++ b/app/helpers/groups/group_members_helper.rb
@@ -5,10 +5,6 @@ module Groups::GroupMembersHelper
AVATAR_SIZE = 40
- def group_member_select_options
- { multiple: true, class: 'input-clamp qa-member-select-field ', scope: :all, email_user: true }
- end
-
def group_members_app_data(group, members:, invited:, access_requests:, banned:, include_relations:, search:)
{
user: group_members_list_data(group, members, { param_name: :page, params: { invited_members_page: nil, search_invited: nil } }),
@@ -16,7 +12,8 @@ module Groups::GroupMembersHelper
invite: group_members_list_data(group, invited.nil? ? [] : invited, { param_name: :invited_members_page, params: { page: nil } }),
access_request: group_members_list_data(group, access_requests.nil? ? [] : access_requests),
source_id: group.id,
- can_manage_members: can?(current_user, :admin_group_member, group)
+ can_manage_members: can?(current_user, :admin_group_member, group),
+ can_manage_access_requests: can?(current_user, :admin_member_access_request, group)
}
end
diff --git a/app/helpers/groups/observability_helper.rb b/app/helpers/groups/observability_helper.rb
new file mode 100644
index 00000000000..6fb6acce386
--- /dev/null
+++ b/app/helpers/groups/observability_helper.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+module Groups
+ module ObservabilityHelper
+ ACTION_TO_PATH = {
+ 'dashboards' => {
+ path: '/',
+ title: -> { s_('Dashboards') }
+ },
+ 'manage' => {
+ path: '/dashboards',
+ title: -> { s_('Manage Dashboards') }
+ },
+ 'explore' => {
+ path: '/explore',
+ title: -> { s_('Explore') }
+ }
+ }.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}"
+ end
+
+ def observability_page_title
+ observability_config_for(params).fetch(:title).call
+ end
+
+ 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
+ end
+end
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 6b00c213875..e8fc6bc292f 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -112,16 +112,6 @@ module GroupsHelper
s_("GroupSettings|Available only on the top-level group. Applies to all subgroups. Groups already shared with a group outside %{group} are still shared unless removed manually.").html_safe % { group: link_to_group(group) }
end
- def parent_group_options(current_group)
- exclude_groups = current_group.self_and_descendants.pluck_primary_key
- exclude_groups << current_group.parent_id if current_group.parent_id
- groups = GroupsFinder.new(current_user, min_access_level: Gitlab::Access::OWNER, exclude_group_ids: exclude_groups).execute.sort_by(&:human_name).map do |group|
- { id: group.id, text: group.human_name }
- end
-
- groups.to_json
- end
-
def render_setting_to_allow_project_access_token_creation?(group)
group.root? && current_user.can?(:admin_setting_to_allow_project_access_token_creation, group)
end
@@ -158,8 +148,13 @@ module GroupsHelper
}
end
- def subgroups_and_projects_list_app_data(group)
+ def group_overview_tabs_app_data(group)
{
+ subgroups_and_projects_endpoint: group_children_path(group, format: :json),
+ shared_projects_endpoint: group_shared_projects_path(group, format: :json),
+ archived_projects_endpoint: group_children_path(group, format: :json, archived: 'only'),
+ current_group_visibility: group.visibility,
+ initial_sort: project_list_sort_by,
show_schema_markup: 'true',
new_subgroup_path: new_group_path(parent_id: group.id, anchor: 'create-group-pane'),
new_project_path: new_project_path(namespace_id: group.id),
@@ -172,16 +167,6 @@ module GroupsHelper
}
end
- def group_overview_tabs_app_data(group)
- {
- subgroups_and_projects_endpoint: group_children_path(group, format: :json),
- shared_projects_endpoint: group_shared_projects_path(group, format: :json),
- archived_projects_endpoint: group_children_path(group, format: :json, archived: 'only'),
- current_group_visibility: group.visibility,
- initial_sort: project_list_sort_by
- }.merge(subgroups_and_projects_list_app_data(group))
- end
-
def enabled_git_access_protocol_options_for_group
case ::Gitlab::CurrentSettings.enabled_git_access_protocol
when nil, ""
diff --git a/app/helpers/hooks_helper.rb b/app/helpers/hooks_helper.rb
index e050ccc0e40..921e30edbaa 100644
--- a/app/helpers/hooks_helper.rb
+++ b/app/helpers/hooks_helper.rb
@@ -4,7 +4,7 @@ module HooksHelper
def webhook_form_data(hook)
{
url: hook.url,
- url_variables: nil
+ url_variables: Gitlab::Json.dump(hook.url_variables.keys.map { { key: _1 } })
}
end
diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb
index 6f7ac069fe4..c81041c2d9c 100644
--- a/app/helpers/icons_helper.rb
+++ b/app/helpers/icons_helper.rb
@@ -42,7 +42,7 @@ module IconsHelper
content_tag(
:svg,
- content_tag(:use, '', { 'href' => "#{sprite_icon_path}##{icon_name}" } ),
+ content_tag(:use, '', { 'href' => "#{sprite_icon_path}##{icon_name}" }),
class: css_classes.empty? ? nil : css_classes.join(' '),
data: { testid: "#{icon_name}-icon" }
)
@@ -70,18 +70,14 @@ module IconsHelper
# gl_loading_icon(css_class: "foo-bar")
#
# See also https://gitlab-org.gitlab.io/gitlab-ui/?path=/story/base-loading-icon--default
- def gl_loading_icon(inline: false, color: 'dark', size: 'sm', css_class: nil)
- spinner = content_tag(:span, "", {
- class: %[gl-spinner gl-spinner-#{color} gl-spinner-#{size} gl-vertical-align-text-bottom!],
- aria: { label: _('Loading') }
- })
-
- container_classes = ['gl-spinner-container']
- container_classes << css_class unless css_class.blank?
- content_tag(inline ? :span : :div, spinner, {
- class: container_classes,
- role: 'status'
- })
+ def gl_loading_icon(inline: false, color: 'dark', size: 'sm', css_class: nil, data: nil)
+ render Pajamas::SpinnerComponent.new(
+ inline: inline,
+ color: color,
+ size: size,
+ class: css_class,
+ data: data
+ )
end
def external_snippet_icon(name)
diff --git a/app/helpers/ide_helper.rb b/app/helpers/ide_helper.rb
index 5b3ca25b5af..34f4749c42a 100644
--- a/app/helpers/ide_helper.rb
+++ b/app/helpers/ide_helper.rb
@@ -5,6 +5,7 @@ module IdeHelper
{
'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
}.merge(use_new_web_ide? ? new_ide_data : legacy_ide_data)
@@ -33,6 +34,7 @@ module IdeHelper
'no-changes-state-svg-path' => image_path('illustrations/multi-editor_no_changes_empty.svg'),
'committed-state-svg-path' => image_path('illustrations/multi-editor_all_changes_committed_empty.svg'),
'pipelines-empty-state-svg-path': image_path('illustrations/pipelines_empty.svg'),
+ 'switch-editor-svg-path': image_path('illustrations/rocket-launch-md.svg'),
'promotion-svg-path': image_path('illustrations/web-ide_promotion.svg'),
'ci-help-page-path' => help_page_path('ci/quick_start/index'),
'web-ide-help-page-path' => help_page_path('user/project/web_ide/index.md'),
diff --git a/app/helpers/integrations_helper.rb b/app/helpers/integrations_helper.rb
index a1512d40235..abfa55cff24 100644
--- a/app/helpers/integrations_helper.rb
+++ b/app/helpers/integrations_helper.rb
@@ -160,6 +160,31 @@ module IntegrationsHelper
!Gitlab.com?
end
+ def integration_issue_type(issue_type)
+ issue_type_i18n_map = {
+ 'issue' => _('Issue'),
+ 'incident' => _('Incident'),
+ 'test_case' => _('Test case'),
+ 'requirement' => _('Requirement'),
+ 'task' => _('Task')
+ }
+
+ issue_type_i18n_map[issue_type] || issue_type
+ end
+
+ def integration_todo_target_type(target_type)
+ target_type_i18n_map = {
+ 'Commit' => _('Commit'),
+ 'Issue' => _('Issue'),
+ 'MergeRequest' => _('Merge Request'),
+ 'Epic' => _('Epic'),
+ DesignManagement::Design.name => _('design'),
+ AlertManagement::Alert.name => _('alert')
+ }
+
+ target_type_i18n_map[target_type] || target_type
+ end
+
extend self
private
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index 2804a58da9e..fd181109a94 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -135,17 +135,6 @@ module IssuablesHelper
end
# rubocop: enable CodeReuse/ActiveRecord
- def milestone_dropdown_label(milestone_title, default_label = _('Milestone'))
- title =
- case milestone_title
- when Milestone::Upcoming.name then Milestone::Upcoming.title
- when Milestone::Started.name then Milestone::Started.title
- else milestone_title.presence
- end
-
- h(title || default_label)
- end
-
def issuable_meta_author_status(author)
return "" unless author&.status&.customized? && status = user_status(author)
@@ -157,9 +146,9 @@ module IssuablesHelper
if issuable.respond_to?(:work_item_type) && WorkItems::Type::WI_TYPES_WITH_CREATED_HEADER.include?(issuable.work_item_type.base_type)
output << content_tag(:span, sprite_icon("#{issuable.work_item_type.icon_name}", css_class: 'gl-icon gl-vertical-align-middle gl-text-gray-500'), class: 'gl-mr-2', aria: { hidden: 'true' })
- output << content_tag(:span, s_('IssuableStatus|%{wi_type} created %{created_at} by ').html_safe % { wi_type: issuable.issue_type.capitalize, created_at: time_ago_with_tooltip(issuable.created_at) }, class: 'gl-mr-2' )
+ output << content_tag(:span, s_('IssuableStatus|%{wi_type} created %{created_at} by ').html_safe % { wi_type: issuable.issue_type.capitalize, created_at: time_ago_with_tooltip(issuable.created_at) }, class: 'gl-mr-2')
else
- output << content_tag(:span, s_('IssuableStatus|Created %{created_at} by').html_safe % { created_at: time_ago_with_tooltip(issuable.created_at) }, class: 'gl-mr-2' )
+ output << content_tag(:span, s_('IssuableStatus|Created %{created_at} by').html_safe % { created_at: time_ago_with_tooltip(issuable.created_at) }, class: 'gl-mr-2')
end
if issuable.is_a?(Issue) && issuable.service_desk_reply_to
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 115cdd432e3..932a50d9451 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -10,7 +10,6 @@ module IssuesHelper
def issue_css_classes(issue)
classes = ["issue"]
classes << "closed" if issue.closed?
- classes << "today" if issue.new?
classes << "gl-cursor-grab" if @sort == 'relative_position'
classes.join(' ')
end
@@ -108,9 +107,10 @@ module IssuesHelper
def awards_sort(awards)
awards.sort_by do |award, award_emojis|
- if award == "thumbsup"
+ case award
+ when "thumbsup"
0
- elsif award == "thumbsdown"
+ when "thumbsdown"
1
else
2
diff --git a/app/helpers/json_helper.rb b/app/helpers/json_helper.rb
new file mode 100644
index 00000000000..e61c789fd08
--- /dev/null
+++ b/app/helpers/json_helper.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module JsonHelper
+ # These two JSON helpers are short-form wrappers for the Gitlab::Json
+ # class, which should be used in place of .to_json calls or calls to
+ # the JSON class.
+ def json_generate(*args)
+ Gitlab::Json.generate(*args)
+ end
+
+ def json_parse(*args)
+ Gitlab::Json.parse(*args)
+ end
+end
diff --git a/app/helpers/markup_helper.rb b/app/helpers/markup_helper.rb
index 866399f3021..9baea43b77d 100644
--- a/app/helpers/markup_helper.rb
+++ b/app/helpers/markup_helper.rb
@@ -6,12 +6,6 @@ module MarkupHelper
include ActionView::Helpers::TextHelper
include ActionView::Context
- # Let's increase the render timeout
- # For a smaller one, a test that renders the blob content statically fails
- # We can consider removing this custom timeout when markup_rendering_timeout FF is removed:
- # https://gitlab.com/gitlab-org/gitlab/-/issues/365358
- RENDER_TIMEOUT = 5.seconds
-
# Use this in places where you would normally use link_to(gfm(...), ...).
def link_to_markdown(body, url, html_options = {})
return '' if body.blank?
@@ -97,8 +91,9 @@ module MarkupHelper
context[:project] ||= @project
context[:group] ||= @group
- html = markdown_unsafe(text, context)
- prepare_for_rendering(html, context)
+ html = Markup::RenderingService.new(text, context: context, postprocess_context: postprocess_context).execute
+
+ Hamlit::RailsHelpers.preserve(html)
end
def markdown_field(object, field, context = {})
@@ -114,8 +109,13 @@ module MarkupHelper
def markup(file_name, text, context = {})
context[:project] ||= @project
context[:text_source] ||= :blob
- html = context.delete(:rendered) || markup_unsafe(file_name, text, context)
- prepare_for_rendering(html, context)
+ prepare_asciidoc_context(file_name, context)
+
+ html = Markup::RenderingService
+ .new(text, file_name: file_name, context: context, postprocess_context: postprocess_context)
+ .execute
+
+ Hamlit::RailsHelpers.preserve(html)
end
def render_wiki_content(wiki_page, context = {})
@@ -123,35 +123,13 @@ module MarkupHelper
return '' unless text.present?
context = render_wiki_content_context(wiki_page.wiki, wiki_page, context)
- html = markup_unsafe(wiki_page.path, text, context)
-
- prepare_for_rendering(html, context)
- end
-
- def markup_unsafe(file_name, text, context = {})
- return '' unless text.present?
+ prepare_asciidoc_context(wiki_page.path, context)
- markup = proc do
- if Gitlab::MarkupHelper.gitlab_markdown?(file_name)
- markdown_unsafe(text, context)
- elsif Gitlab::MarkupHelper.asciidoc?(file_name)
- asciidoc_unsafe(text, context)
- elsif Gitlab::MarkupHelper.plain?(file_name)
- plain_unsafe(text)
- else
- other_markup_unsafe(file_name, text, context)
- end
- end
-
- if Feature.enabled?(:markup_rendering_timeout, @project)
- Gitlab::RenderTimeout.timeout(foreground: RENDER_TIMEOUT, &markup)
- else
- markup.call
- end
- rescue StandardError => e
- Gitlab::ErrorTracking.track_exception(e, project_id: @project&.id, file_name: file_name)
+ html = Markup::RenderingService
+ .new(text, file_name: wiki_page.path, context: context, postprocess_context: postprocess_context)
+ .execute
- simple_format(text)
+ Hamlit::RailsHelpers.preserve(html)
end
# Returns the text necessary to reference `entity` across projects
@@ -214,29 +192,6 @@ module MarkupHelper
end
end
- def markdown_unsafe(text, context = {})
- Banzai.render(text, context)
- end
-
- def asciidoc_unsafe(text, context = {})
- context.reverse_merge!(
- commit: @commit,
- ref: @ref,
- requested_path: @path
- )
- Gitlab::Asciidoc.render(text, context)
- end
-
- def plain_unsafe(text)
- content_tag :pre, class: 'plain-readme' do
- text
- end
- end
-
- def other_markup_unsafe(file_name, text, context = {})
- Gitlab::OtherMarkup.render(file_name, text, context)
- end
-
def render_markdown_field(object, field, context = {})
post_process = context.delete(:post_process)
post_process = true if post_process.nil?
@@ -257,7 +212,15 @@ module MarkupHelper
def prepare_for_rendering(html, context = {})
return '' unless html.present?
- context.reverse_merge!(
+ context.reverse_merge!(postprocess_context)
+
+ html = Banzai.post_process(html, context)
+
+ Hamlit::RailsHelpers.preserve(html)
+ end
+
+ def postprocess_context
+ {
current_user: (current_user if defined?(current_user)),
# RepositoryLinkFilter and UploadLinkFilter
@@ -265,11 +228,13 @@ module MarkupHelper
wiki: @wiki,
ref: @ref,
requested_path: @path
- )
+ }
+ end
- html = Banzai.post_process(html, context)
+ def prepare_asciidoc_context(file_name, context)
+ return unless Gitlab::MarkupHelper.asciidoc?(file_name)
- Hamlit::RailsHelpers.preserve(html)
+ context.reverse_merge!(commit: @commit, ref: @ref, requested_path: @path)
end
extend self
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index 45ded6e35d8..1d7d812dc5d 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -242,13 +242,13 @@ module MergeRequestsHelper
''
end
- link_to branch, branch_path, title: branch, class: 'gl-text-blue-500! gl-font-monospace gl-bg-blue-50 gl-rounded-base gl-font-sm gl-px-2 gl-display-inline-block gl-text-truncate gl-max-w-26 gl-mb-n2'
+ link_to branch, branch_path, title: branch, class: 'gl-text-blue-500! gl-font-monospace gl-bg-blue-50 gl-rounded-base gl-font-sm gl-px-2 gl-display-inline-block gl-text-truncate gl-max-w-26 gl-mx-2'
end
def merge_request_header(project, merge_request)
- link_to_author = link_to_member(project, merge_request.author, size: 24, extra_class: 'gl-font-weight-bold', avatar: false)
+ link_to_author = link_to_member(project, merge_request.author, size: 24, extra_class: 'gl-font-weight-bold gl-mr-2', avatar: false)
copy_button = clipboard_button(text: merge_request.source_branch, title: _('Copy branch name'), class: 'btn btn-default btn-sm gl-button btn-default-tertiary btn-icon gl-display-none! gl-md-display-inline-block! js-source-branch-copy')
- target_branch = link_to merge_request.target_branch, project_tree_path(merge_request.target_project, merge_request.target_branch), title: merge_request.target_branch, class: 'gl-text-blue-500! gl-font-monospace gl-bg-blue-50 gl-rounded-base gl-font-sm gl-px-2 gl-display-inline-block gl-text-truncate gl-max-w-26 gl-mb-n2'
+ target_branch = link_to merge_request.target_branch, project_tree_path(merge_request.target_project, merge_request.target_branch), title: merge_request.target_branch, class: 'gl-text-blue-500! gl-font-monospace gl-bg-blue-50 gl-rounded-base gl-font-sm gl-px-2 gl-display-inline-block gl-text-truncate gl-max-w-26 gl-mx-2'
_('%{author} requested to merge %{source_branch} %{copy_button} into %{target_branch} %{created_at}').html_safe % { author: link_to_author.html_safe, source_branch: merge_request_source_branch(merge_request).html_safe, copy_button: copy_button.html_safe, target_branch: target_branch.html_safe, created_at: time_ago_with_tooltip(merge_request.created_at, html_class: 'gl-display-inline-block').html_safe }
end
diff --git a/app/helpers/nav/top_nav_helper.rb b/app/helpers/nav/top_nav_helper.rb
index 32d3f4aebb4..751900f4593 100644
--- a/app/helpers/nav/top_nav_helper.rb
+++ b/app/helpers/nav/top_nav_helper.rb
@@ -281,76 +281,28 @@ module Nav
end
def projects_submenu_items(builder:)
- if Feature.enabled?(:remove_extra_primary_submenu_options)
- title = _('View all projects')
-
- builder.add_primary_menu_item(
- id: 'your',
- title: title,
- href: dashboard_projects_path,
- data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
- )
- else
- # These project links come from `app/views/layouts/nav/projects_dropdown/_show.html.haml`
- [
- { id: 'your', title: _('Your projects'), href: dashboard_projects_path },
- { id: 'starred', title: _('Starred projects'), href: starred_dashboard_projects_path },
- { id: 'explore', title: _('Explore projects'), href: explore_root_path },
- { id: 'topics', title: _('Explore topics'), href: topics_explore_projects_path }
- ].each do |item|
- builder.add_primary_menu_item(
- **item,
- data: { qa_selector: 'menu_item_link', qa_title: item[:title], **menu_data_tracking_attrs(item[:title]) }
- )
- end
-
- title = _('Create new project')
-
- builder.add_secondary_menu_item(
- id: 'create',
- title: title,
- href: new_project_path,
- data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
- )
- end
+ title = _('View all projects')
+
+ builder.add_primary_menu_item(
+ id: 'your',
+ title: title,
+ href: dashboard_projects_path,
+ data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
+ )
end
def groups_submenu
# These group links come from `app/views/layouts/nav/groups_dropdown/_show.html.haml`
builder = ::Gitlab::Nav::TopNavMenuBuilder.new
- if Feature.enabled?(:remove_extra_primary_submenu_options)
- title = _('View all groups')
-
- builder.add_primary_menu_item(
- id: 'your',
- title: title,
- href: dashboard_groups_path,
- data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
- )
- else
- [
- { id: 'your', title: _('Your groups'), href: dashboard_groups_path },
- { id: 'explore', title: _('Explore groups'), href: explore_groups_path }
- ].each do |item|
- builder.add_primary_menu_item(
- **item,
- data: { qa_selector: 'menu_item_link', qa_title: item[:title], **menu_data_tracking_attrs(item[:title]) }
- )
- end
-
- if current_user.can_create_group?
- title = _('Create group')
-
- builder.add_secondary_menu_item(
- id: 'create',
- title: title,
- href: new_group_path,
- data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
- )
- end
- end
+ title = _('View all groups')
+ builder.add_primary_menu_item(
+ id: 'your',
+ title: title,
+ href: dashboard_groups_path,
+ data: { qa_selector: 'menu_item_link', qa_title: title, **menu_data_tracking_attrs(title) }
+ )
builder.build
end
end
diff --git a/app/helpers/projects/alert_management_helper.rb b/app/helpers/projects/alert_management_helper.rb
index f21538fd3fb..50c7db683c6 100644
--- a/app/helpers/projects/alert_management_helper.rb
+++ b/app/helpers/projects/alert_management_helper.rb
@@ -21,6 +21,7 @@ module Projects::AlertManagementHelper
'project-path' => project.full_path,
'project-id' => project.id,
'project-issues-path' => project_issues_path(project),
+ 'project-alert-management-details-path' => details_project_alert_management_path(project, alert_id),
'page' => 'OPERATIONS',
'can-update' => can?(current_user, :update_alert_management_alert, project).to_s
}
diff --git a/app/helpers/projects/ml/experiments_helper.rb b/app/helpers/projects/ml/experiments_helper.rb
new file mode 100644
index 00000000000..29bd879859e
--- /dev/null
+++ b/app/helpers/projects/ml/experiments_helper.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+module Projects
+ module Ml
+ module ExperimentsHelper
+ require 'json'
+ include ActionView::Helpers::NumberHelper
+
+ def candidates_table_items(candidates)
+ items = candidates.map do |candidate|
+ {
+ **candidate.params.to_h { |p| [p.name, p.value] },
+ **candidate.latest_metrics.to_h { |m| [m.name, number_with_precision(m.value, precision: 4)] }
+ }
+ end
+
+ Gitlab::Json.generate(items)
+ end
+
+ def unique_logged_names(candidates, &selector)
+ Gitlab::Json.generate(candidates.flat_map(&selector).map(&:name).uniq)
+ end
+ end
+ end
+end
diff --git a/app/helpers/projects/pipeline_helper.rb b/app/helpers/projects/pipeline_helper.rb
index c72beb4d722..edbdb9d4adf 100644
--- a/app/helpers/projects/pipeline_helper.rb
+++ b/app/helpers/projects/pipeline_helper.rb
@@ -19,6 +19,7 @@ module Projects
blob_path: project_blob_path(project, pipeline.sha),
has_test_report: pipeline.has_test_reports?,
empty_state_image_path: image_path('illustrations/empty-state/empty-test-cases-lg.svg'),
+ empty_dag_svg_path: image_path('illustrations/empty-state/empty-dag-md.svg'),
artifacts_expired_image_path: image_path('illustrations/pipeline.svg'),
tests_count: pipeline.test_report_summary.total[:count]
}
diff --git a/app/helpers/projects/project_members_helper.rb b/app/helpers/projects/project_members_helper.rb
index 51a7d3e35d0..6026124abb9 100644
--- a/app/helpers/projects/project_members_helper.rb
+++ b/app/helpers/projects/project_members_helper.rb
@@ -8,7 +8,8 @@ module Projects::ProjectMembersHelper
invite: project_members_list_data(project, invited.nil? ? [] : invited),
access_request: project_members_list_data(project, access_requests.nil? ? [] : access_requests),
source_id: project.id,
- can_manage_members: Ability.allowed?(current_user, :admin_project_member, project)
+ can_manage_members: Ability.allowed?(current_user, :admin_project_member, project),
+ can_manage_access_requests: Ability.allowed?(current_user, :admin_member_access_request, project)
}.to_json
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index cddcdf77710..e41a3fa5091 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -69,7 +69,7 @@ module ProjectsHelper
if opts[:name]
inject_classes.concat(["js-user-link", opts[:mobile_classes]])
else
- inject_classes.append( "has-tooltip" )
+ inject_classes.append("has-tooltip")
end
inject_classes = inject_classes.compact.join(" ")
@@ -393,7 +393,8 @@ module ProjectsHelper
membersPagePath: project_project_members_path(project),
environmentsHelpPath: help_page_path('ci/environments/index'),
featureFlagsHelpPath: help_page_path('operations/feature_flags'),
- releasesHelpPath: help_page_path('user/project/releases/index')
+ releasesHelpPath: help_page_path('user/project/releases/index'),
+ infrastructureHelpPath: help_page_path('user/infrastructure/index')
}
end
@@ -475,6 +476,10 @@ module ProjectsHelper
localized_access_names[access] || Gitlab::Access.human_access(access)
end
+ def badge_count(number)
+ format_cached_count(1000, number)
+ end
+
private
def localized_access_names
@@ -662,7 +667,8 @@ module ProjectsHelper
containerRegistryAccessLevel: feature.container_registry_access_level,
environmentsAccessLevel: feature.environments_access_level,
featureFlagsAccessLevel: feature.feature_flags_access_level,
- releasesAccessLevel: feature.releases_access_level
+ releasesAccessLevel: feature.releases_access_level,
+ infrastructureAccessLevel: feature.infrastructure_access_level
}
end
diff --git a/app/helpers/recaptcha_helper.rb b/app/helpers/recaptcha_helper.rb
index 59f0dc8f819..b6b75d03b2e 100644
--- a/app/helpers/recaptcha_helper.rb
+++ b/app/helpers/recaptcha_helper.rb
@@ -2,27 +2,17 @@
module RecaptchaHelper
def recaptcha_enabled?
- return false if gitlab_qa?
+ return false if Gitlab::Qa.request?(request.user_agent)
!!Gitlab::Recaptcha.enabled?
end
alias_method :show_recaptcha_sign_up?, :recaptcha_enabled?
def recaptcha_enabled_on_login?
- return false if gitlab_qa?
+ return false if Gitlab::Qa.request?(request.user_agent)
Gitlab::Recaptcha.enabled_on_login?
end
-
- private
-
- def gitlab_qa?
- return false unless Gitlab.com?
- return false unless request.user_agent.present?
- return false unless Gitlab::Environment.qa_user_agent.present?
-
- ActiveSupport::SecurityUtils.secure_compare(request.user_agent, Gitlab::Environment.qa_user_agent)
- end
end
RecaptchaHelper.prepend_mod
diff --git a/app/helpers/reminder_emails_helper.rb b/app/helpers/reminder_emails_helper.rb
index 132fc3b784c..e46d9273100 100644
--- a/app/helpers/reminder_emails_helper.rb
+++ b/app/helpers/reminder_emails_helper.rb
@@ -41,7 +41,7 @@ module ReminderEmailsHelper
body = invitation_reminder_body_text(reminder_index)
- (format == :html ? html_escape(body) : body ) % options
+ (format == :html ? html_escape(body) : body) % options
end
def invitation_reminder_accept_link(token, format: nil)
diff --git a/app/helpers/routing/packages_helper.rb b/app/helpers/routing/packages_helper.rb
new file mode 100644
index 00000000000..4e76be3b5a3
--- /dev/null
+++ b/app/helpers/routing/packages_helper.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module Routing
+ module PackagesHelper
+ def package_path(package, **options)
+ Gitlab::UrlBuilder.build(package, only_path: true, **options)
+ end
+ end
+end
diff --git a/app/helpers/routing/projects_helper.rb b/app/helpers/routing/projects_helper.rb
index 8c0bd9b1ecc..f4732e398f0 100644
--- a/app/helpers/routing/projects_helper.rb
+++ b/app/helpers/routing/projects_helper.rb
@@ -43,7 +43,14 @@ module Routing
end
def work_item_url(entity, *args)
- project_work_items_url(entity.project, entity.id, *args)
+ unless Feature.enabled?(:use_iid_in_work_items_path, entity.project.group)
+ return project_work_items_url(entity.project, entity.id, *args)
+ end
+
+ options = args.first || {}
+ options[:iid_path] = true
+
+ project_work_items_url(entity.project, entity.iid, **options)
end
def merge_request_url(entity, *args)
@@ -89,7 +96,9 @@ module Routing
private
def use_work_items_path?(issue)
- issue.issue_type == 'task' && issue.project.work_items_feature_flag_enabled?
+ issue.issue_type == 'task'
end
end
end
+
+Routing::ProjectsHelper.prepend_mod
diff --git a/app/helpers/routing/pseudonymization_helper.rb b/app/helpers/routing/pseudonymization_helper.rb
index eb4e5d1c01c..dce0517690d 100644
--- a/app/helpers/routing/pseudonymization_helper.rb
+++ b/app/helpers/routing/pseudonymization_helper.rb
@@ -43,11 +43,12 @@ module Routing
private
def mask_id(value)
- if @request.path_parameters[:controller] == 'projects/blob'
+ case @request.path_parameters[:controller]
+ when 'projects/blob'
':repository_path'
- elsif @request.path_parameters[:controller] == 'projects'
+ when 'projects'
"project#{@project&.id}"
- elsif @request.path_parameters[:controller] == 'groups'
+ when 'groups'
"namespace#{@group&.id}"
else
value
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index f2b88287277..b8ac2afa7d6 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -181,20 +181,51 @@ module SearchHelper
options
end
- # search_context exposes a bit too much data to the frontend, this controls what data we share and when.
+ def search_group
+ # group gets derived from the Project in the project's scope
+ @group || @project&.group
+ end
+
+ def search_has_group?
+ search_group&.present? && search_group&.persisted?
+ end
+
+ def search_has_project?
+ @project&.present? && @project&.persisted?
+ end
+
def header_search_context
{}.tap do |hash|
- hash[:group] = { id: search_context.group.id, name: search_context.group.name, full_name: search_context.group.full_name } if search_context.for_group?
- hash[:group_metadata] = search_context.group_metadata if search_context.for_group?
+ if search_has_group?
+ hash[:group] = { id: search_group.id, name: search_group.name, full_name: search_group.full_name }
+ hash[:group_metadata] = { issues_path: issues_group_path(search_group), mr_path: merge_requests_group_path(search_group) }
+ end
- hash[:project] = { id: search_context.project.id, name: search_context.project.name } if search_context.for_project?
- hash[:project_metadata] = search_context.project_metadata if search_context.for_project?
+ 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[:code_search] = search_scope.nil?
+ hash[:ref] = @ref if @ref && can?(current_user, :read_code, @project)
+ end
- hash[:scope] = search_context.scope if search_context.for_project? || search_context.for_group?
- hash[:code_search] = search_context.code_search? if search_context.for_project? || search_context.for_group?
+ hash[:scope] = search_scope if search_has_project? || search_has_group?
+ hash[:for_snippets] = @snippet&.present? || @snippets&.any?
+ end
+ end
- hash[:ref] = search_context.ref if can?(current_user, :download_code, search_context.project)
- hash[:for_snippets] = search_context.for_snippets?
+ def search_scope
+ if current_controller?(:issues)
+ 'issues'
+ elsif current_controller?(:merge_requests)
+ 'merge_requests'
+ elsif current_controller?(:wikis)
+ 'wiki_blobs'
+ elsif current_controller?(:commits)
+ 'commits'
+ elsif current_controller?(:groups)
+ if %w(issues merge_requests).include?(controller.action_name)
+ controller.action_name
+ end
end
end
@@ -237,7 +268,7 @@ module SearchHelper
result = []
- if can?(current_user, :download_code, @project)
+ if can?(current_user, :read_code, @project)
result.concat([
{ category: "In this project", label: _("Files"), url: project_tree_path(@project, ref) },
{ category: "In this project", label: _("Commits"), url: project_commits_path(@project, ref) }
@@ -386,7 +417,11 @@ module SearchHelper
active_scope = @scope == scope_name
result = { label: label, scope: scope_name, data: data, link: search_path(search_params), active: active_scope }
- result[:count] = @search_results.formatted_count(scope_name) if active_scope && !@timeout
+
+ if active_scope
+ result[:count] = !@timeout ? @search_results.formatted_count(scope_name) : "0"
+ end
+
result[:count_link] = search_count_path(search_params) unless active_scope
result
@@ -395,21 +430,24 @@ module SearchHelper
# search page scope navigation
def search_navigation
{
- projects: { label: _("Projects"), data: { qa_selector: 'projects_tab' }, condition: @project.nil? },
- blobs: { label: _("Code"), data: { qa_selector: 'code_tab' }, condition: project_search_tabs?(:blobs) || search_service.show_elasticsearch_tabs? || feature_flag_tab_enabled?(:global_search_code_tab) },
- issues: { label: _("Issues"), condition: project_search_tabs?(:issues) || feature_flag_tab_enabled?(:global_search_issues_tab) },
- merge_requests: { label: _("Merge requests"), condition: project_search_tabs?(:merge_requests) || feature_flag_tab_enabled?(:global_search_merge_requests_tab) },
- wiki_blobs: { label: _("Wiki"), condition: project_search_tabs?(:wiki) || search_service.show_elasticsearch_tabs? },
- commits: { label: _("Commits"), condition: project_search_tabs?(:commits) || (search_service.show_elasticsearch_tabs? && feature_flag_tab_enabled?(:global_search_commits_tab)) },
- notes: { label: _("Comments"), condition: project_search_tabs?(:notes) || search_service.show_elasticsearch_tabs? },
- milestones: { label: _("Milestones"), condition: project_search_tabs?(:milestones) || @project.nil? },
- users: { label: _("Users"), condition: show_user_search_tab? },
- snippet_titles: { label: _("Titles and Descriptions"), search: { snippets: true, group_id: nil, project_id: nil }, condition: @show_snippets.present? && @project.nil? }
+ projects: { sort: 1, label: _("Projects"), data: { qa_selector: 'projects_tab' }, condition: @project.nil? },
+ blobs: { sort: 2, label: _("Code"), data: { qa_selector: 'code_tab' }, condition: project_search_tabs?(:blobs) || (search_service.show_elasticsearch_tabs? && feature_flag_tab_enabled?(:global_search_code_tab)) },
+ # sort: 3 is reserved for EE items
+ issues: { sort: 4, label: _("Issues"), condition: project_search_tabs?(:issues) || feature_flag_tab_enabled?(:global_search_issues_tab) },
+ merge_requests: { sort: 5, label: _("Merge requests"), condition: project_search_tabs?(:merge_requests) || feature_flag_tab_enabled?(:global_search_merge_requests_tab) },
+ wiki_blobs: { sort: 6, label: _("Wiki"), condition: project_search_tabs?(:wiki) || search_service.show_elasticsearch_tabs? },
+ commits: { sort: 7, label: _("Commits"), condition: project_search_tabs?(:commits) || (search_service.show_elasticsearch_tabs? && feature_flag_tab_enabled?(:global_search_commits_tab)) },
+ notes: { sort: 8, label: _("Comments"), condition: project_search_tabs?(:notes) || search_service.show_elasticsearch_tabs? },
+ milestones: { sort: 9, label: _("Milestones"), condition: project_search_tabs?(:milestones) || @project.nil? },
+ users: { sort: 10, label: _("Users"), condition: show_user_search_tab? },
+ snippet_titles: { sort: 11, label: _("Titles and Descriptions"), search: { snippets: true, group_id: nil, project_id: nil }, condition: @show_snippets.present? && @project.nil? }
}
end
def search_navigation_json
- search_navigation.each_with_object({}) do |(key, value), hash|
+ sorted_navigation = search_navigation.sort_by { |_, h| h[:sort] }
+
+ sorted_navigation.each_with_object({}) do |(key, value), hash|
hash[key] = search_filter_link_json(key, value[:label], value[:data], value[:search]) if value[:condition]
end.to_json
end
diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb
index 14ee6007a43..99da9a7af6c 100644
--- a/app/helpers/selects_helper.rb
+++ b/app/helpers/selects_helper.rb
@@ -1,30 +1,6 @@
# frozen_string_literal: true
module SelectsHelper
- def users_select_tag(id, opts = {})
- css_class = ["ajax-users-select"]
- css_class << "multiselect" if opts[:multiple]
- css_class << "skip_ldap" if opts[:skip_ldap]
- css_class << (opts[:class] || '')
- value = opts[:selected] || ''
- html = {
- class: css_class.join(' '),
- data: users_select_data_attributes(opts)
- }
-
- unless opts[:scope] == :all
- project = opts[:project] || @project
-
- if project
- html['data-project-id'] = project.id
- elsif @group
- html['data-group-id'] = @group.id
- end
- end
-
- hidden_field_tag(id, value, html)
- end
-
def groups_select_tag(id, opts = {})
classes = Array.wrap(opts[:class])
classes << 'ajax-groups-select'
@@ -68,22 +44,6 @@ module SelectsHelper
hidden_field_tag(id, value, opts)
end
-
- private
-
- def users_select_data_attributes(opts)
- {
- placeholder: opts[:placeholder] || 'Search for a user',
- null_user: opts[:null_user] || false,
- any_user: opts[:any_user] || false,
- email_user: opts[:email_user] || false,
- first_user: opts[:first_user] && current_user ? current_user.username : false,
- current_user: opts[:current_user] || false,
- author_id: opts[:author_id] || '',
- skip_users: opts[:skip_users] ? opts[:skip_users].map(&:id) : nil,
- qa_selector: opts[:qa_selector] || ''
- }
- end
end
SelectsHelper.prepend_mod_with('SelectsHelper')
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 520cde9ecee..be63d28600f 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -15,21 +15,25 @@ module TodosHelper
def todo_action_name(todo)
case todo.action
- when Todo::ASSIGNED then todo.self_added? ? 'assigned' : 'assigned you'
- when Todo::REVIEW_REQUESTED then 'requested a review of'
- when Todo::MENTIONED, Todo::DIRECTLY_ADDRESSED then "mentioned #{todo_action_subject(todo)} on"
- when Todo::BUILD_FAILED then 'The pipeline failed in'
- when Todo::MARKED then 'added a todo for'
- when Todo::APPROVAL_REQUIRED then "set #{todo_action_subject(todo)} as an approver for"
- when Todo::UNMERGEABLE then 'Could not merge'
- when Todo::MERGE_TRAIN_REMOVED then "Removed from Merge Train:"
+ when Todo::ASSIGNED then todo.self_added? ? _('assigned') : _('assigned you')
+ when Todo::REVIEW_REQUESTED then s_('Todos|requested a review of')
+ when Todo::MENTIONED, Todo::DIRECTLY_ADDRESSED then format(
+ s_("Todos|mentioned %{who} on"), who: todo_action_subject(todo)
+ )
+ when Todo::BUILD_FAILED then s_('Todos|The pipeline failed in')
+ when Todo::MARKED then s_('Todos|added a todo for')
+ when Todo::APPROVAL_REQUIRED then format(
+ s_("Todos|set %{who} as an approver for"), who: todo_action_subject(todo)
+ )
+ when Todo::UNMERGEABLE then s_('Todos|Could not merge')
+ when Todo::MERGE_TRAIN_REMOVED then s_("Todos|Removed from Merge Train:")
end
end
def todo_self_addressing(todo)
case todo.action
- when Todo::ASSIGNED then 'to yourself'
- when Todo::REVIEW_REQUESTED then 'from yourself'
+ when Todo::ASSIGNED then _('to yourself')
+ when Todo::REVIEW_REQUESTED then _('from yourself')
end
end
@@ -66,9 +70,9 @@ module TodosHelper
return _('alert') if todo.for_alert?
target_type = if todo.for_issue_or_work_item?
- todo.target.issue_type
+ IntegrationsHelper.integration_issue_type(todo.target.issue_type)
else
- todo.target_type
+ IntegrationsHelper.integration_todo_target_type(todo.target_type)
end
target_type.titleize.downcase
@@ -109,12 +113,18 @@ module TodosHelper
return unless show_todo_state?(todo)
state = todo.target.state.to_s
+ raw_state_to_i18n = {
+ "closed" => _('Closed'),
+ "merged" => _('Merged'),
+ "resolved" => _('Resolved')
+ }
case todo.target
when MergeRequest
- if state == 'closed'
+ case state
+ when 'closed'
background_class = 'gl-bg-red-500'
- elsif state == 'merged'
+ when 'merged'
background_class = 'gl-bg-blue-500'
end
when Issue
@@ -124,7 +134,7 @@ module TodosHelper
end
tag.span class: "gl-my-0 gl-px-2 status-box #{background_class}" do
- todo.target.state.to_s.capitalize
+ raw_state_to_i18n[state] || state.capitalize
end
end
@@ -237,7 +247,7 @@ module TodosHelper
end
def todo_action_subject(todo)
- todo.self_added? ? 'yourself' : 'you'
+ todo.self_added? ? s_('Todos|yourself') : _('you')
end
def show_todo_state?(todo)
diff --git a/app/mailers/emails/identity_verification.rb b/app/mailers/emails/identity_verification.rb
index e3089fdef9b..f3fe609e7d1 100644
--- a/app/mailers/emails/identity_verification.rb
+++ b/app/mailers/emails/identity_verification.rb
@@ -2,14 +2,22 @@
module Emails
module IdentityVerification
- def verification_instructions_email(user_id, token:, expires_in:)
+ def verification_instructions_email(email, token:)
@token = token
- @expires_in_minutes = expires_in
+ @expires_in_minutes = Users::EmailVerification::ValidateTokenService::TOKEN_VALID_FOR_MINUTES
@password_link = edit_profile_password_url
@two_fa_link = help_page_url('user/profile/account/two_factor_authentication')
- user = User.find(user_id)
- email_with_layout(to: user.email, subject: s_('IdentityVerification|Verify your identity'))
+ headers = {
+ to: email,
+ subject: s_('IdentityVerification|Verify your identity'),
+ 'X-Mailgun-Suppressions-Bypass' => 'true'
+ }
+
+ mail_with_locale(headers) do |format|
+ format.html { render layout: 'mailer' }
+ format.text
+ end
end
end
end
diff --git a/app/mailers/emails/releases.rb b/app/mailers/emails/releases.rb
index 8fe93f59662..468a8624319 100644
--- a/app/mailers/emails/releases.rb
+++ b/app/mailers/emails/releases.rb
@@ -11,6 +11,8 @@ module Emails
)
@recipient = User.find(user_id)
+ add_project_headers
+
mail_with_locale(
to: @recipient.notification_email_for(@project.group),
subject: subject(release_email_subject)
diff --git a/app/mailers/previews/notify_preview.rb b/app/mailers/previews/notify_preview.rb
index 206518e582b..7d7e01950c8 100644
--- a/app/mailers/previews/notify_preview.rb
+++ b/app/mailers/previews/notify_preview.rb
@@ -210,7 +210,7 @@ class NotifyPreview < ActionMailer::Preview
end
def verification_instructions_email
- Notify.verification_instructions_email(user.id, token: '123456', expires_in: 60).message
+ Notify.verification_instructions_email(user.email, token: '123456').message
end
def project_was_exported_email
diff --git a/app/models/active_session.rb b/app/models/active_session.rb
index 7dbc95c251b..b16c4a2b353 100644
--- a/app/models/active_session.rb
+++ b/app/models/active_session.rb
@@ -83,24 +83,26 @@ class ActiveSession
is_impersonated: request.session[:impersonator_id].present?
)
- redis.pipelined do |pipeline|
- pipeline.setex(
- key_name(user.id, session_private_id),
- expiry,
- active_user_session.dump
- )
-
- # Deprecated legacy format - temporary to support mixed deployments
- pipeline.setex(
- key_name_v1(user.id, session_private_id),
- expiry,
- Marshal.dump(active_user_session)
- )
-
- pipeline.sadd(
- lookup_key_name(user.id),
- session_private_id
- )
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ redis.pipelined do |pipeline|
+ pipeline.setex(
+ key_name(user.id, session_private_id),
+ expiry,
+ active_user_session.dump
+ )
+
+ # Deprecated legacy format - temporary to support mixed deployments
+ pipeline.setex(
+ key_name_v1(user.id, session_private_id),
+ expiry,
+ Marshal.dump(active_user_session)
+ )
+
+ pipeline.sadd?(
+ lookup_key_name(user.id),
+ session_private_id
+ )
+ end
end
end
end
@@ -298,7 +300,7 @@ class ActiveSession
session_ids_and_entries.each do |session_id, entry|
next if entry
- pipeline.srem(lookup_key, session_id)
+ pipeline.srem?(lookup_key, session_id)
removed << session_id
end
end
diff --git a/app/models/alert_management/http_integration.rb b/app/models/alert_management/http_integration.rb
index 0c3b1679dc3..b2686924363 100644
--- a/app/models/alert_management/http_integration.rb
+++ b/app/models/alert_management/http_integration.rb
@@ -13,8 +13,7 @@ module AlertManagement
key: Settings.attr_encrypted_db_key_base_32,
algorithm: 'aes-256-gcm'
- default_value_for(:endpoint_identifier, allows_nil: false) { SecureRandom.hex(8) }
- default_value_for(:token) { generate_token }
+ attribute :endpoint_identifier, default: -> { SecureRandom.hex(8) }
validates :project, presence: true
validates :active, inclusion: { in: [true, false] }
diff --git a/app/models/appearance.rb b/app/models/appearance.rb
index 00a95070691..bd948c2c32a 100644
--- a/app/models/appearance.rb
+++ b/app/models/appearance.rb
@@ -6,6 +6,16 @@ class Appearance < ApplicationRecord
include ObjectStorage::BackgroundMove
include WithUploads
+ attribute :title, default: ''
+ attribute :description, default: ''
+ attribute :new_project_guidelines, default: ''
+ attribute :profile_image_guidelines, default: ''
+ attribute :header_message, default: ''
+ attribute :footer_message, default: ''
+ attribute :message_background_color, default: '#E75E40'
+ attribute :message_font_color, default: '#FFFFFF'
+ attribute :email_header_and_footer_enabled, default: false
+
cache_markdown_field :description
cache_markdown_field :new_project_guidelines
cache_markdown_field :profile_image_guidelines
@@ -20,16 +30,6 @@ class Appearance < ApplicationRecord
validate :single_appearance_row, on: :create
- default_value_for :title, ''
- default_value_for :description, ''
- default_value_for :new_project_guidelines, ''
- default_value_for :profile_image_guidelines, ''
- default_value_for :header_message, ''
- default_value_for :footer_message, ''
- default_value_for :message_background_color, '#E75E40'
- default_value_for :message_font_color, '#FFFFFF'
- default_value_for :email_header_and_footer_enabled, false
-
mount_uploader :logo, AttachmentUploader
mount_uploader :header_logo, AttachmentUploader
mount_uploader :favicon, FaviconUploader
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index 361b1a8dca9..adbbddd635c 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -20,6 +20,7 @@ class ApplicationSetting < ApplicationRecord
'Admin Area > Settings > General > Kroki'
enum whats_new_variant: { all_tiers: 0, current_tier: 1, disabled: 2 }, _prefix: true
+ enum email_confirmation_setting: { off: 0, soft: 1, hard: 2 }
add_authentication_token_field :runners_registration_token, encrypted: -> { Feature.enabled?(:application_settings_tokens_optional_encryption) ? :optional : :required }
add_authentication_token_field :health_check_access_token
@@ -74,9 +75,9 @@ class ApplicationSetting < ApplicationRecord
cache_markdown_field :shared_runners_text, pipeline: :plain_markdown
cache_markdown_field :after_sign_up_text
- default_value_for :id, 1
- default_value_for :repository_storages_weighted, {}
- default_value_for :kroki_formats, {}
+ attribute :id, default: 1
+ attribute :repository_storages_weighted, default: -> { {} }
+ attribute :kroki_formats, default: -> { {} }
chronic_duration_attr_writer :archive_builds_in_human_readable, :archive_builds_in_seconds
@@ -317,6 +318,7 @@ class ApplicationSetting < ApplicationRecord
less_than_or_equal_to: Commit::MAX_DIFF_LINES_SETTING_UPPER_BOUND }
validates :user_default_internal_regex, js_regex: true, allow_nil: true
+ validates :default_preferred_language, presence: true, inclusion: { in: Gitlab::I18n.available_locales }
validates :personal_access_token_prefix,
format: { with: %r{\A[a-zA-Z0-9_+=/@:.-]+\z},
@@ -527,6 +529,11 @@ class ApplicationSetting < ApplicationRecord
length: { maximum: 255, message: N_('is too long (maximum is %{count} characters)') },
allow_blank: true
+ validates :jira_connect_proxy_url,
+ length: { maximum: 255, message: N_('is too long (maximum is %{count} characters)') },
+ allow_blank: true,
+ public_url: true
+
with_options(presence: true, numericality: { only_integer: true, greater_than: 0 }) do
validates :throttle_unauthenticated_api_requests_per_period
validates :throttle_unauthenticated_api_period_in_seconds
@@ -632,10 +639,6 @@ class ApplicationSetting < ApplicationRecord
validates :inactive_projects_send_warning_email_after_months,
numericality: { only_integer: true, greater_than: 0, less_than: :inactive_projects_delete_after_months }
- validates :cube_api_base_url,
- addressable_url: { allow_localhost: true, allow_local_network: false },
- allow_blank: true
-
attr_encrypted :asset_proxy_secret_key,
mode: :per_attribute_iv,
key: Settings.attr_encrypted_db_key_base_truncated,
@@ -675,10 +678,15 @@ class ApplicationSetting < ApplicationRecord
attr_encrypted :arkose_labs_private_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
attr_encrypted :cube_api_key, encryption_options_base_32_aes_256_gcm
attr_encrypted :jitsu_administrator_password, encryption_options_base_32_aes_256_gcm
+ attr_encrypted :telesign_customer_xid, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
+ attr_encrypted :telesign_api_key, encryption_options_base_32_aes_256_gcm.merge(encode: false, encode_iv: false)
validates :disable_feed_token,
inclusion: { in: [true, false], message: N_('must be a boolean value') }
+ validates :disable_admin_oauth_scopes,
+ 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
diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index dee4bd07fd9..308c05d638c 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -62,6 +62,7 @@ module ApplicationSettingImplementation
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,
+ disable_admin_oauth_scopes: false,
disable_feed_token: false,
disabled_oauth_sign_in_sources: [],
dns_rebinding_protection_enabled: true,
@@ -103,6 +104,7 @@ module ApplicationSettingImplementation
invisible_captcha_enabled: false,
issues_create_limit: 300,
jira_connect_application_key: nil,
+ jira_connect_proxy_url: nil,
local_markdown_version: 0,
login_recaptcha_protection_enabled: false,
mailgun_signing_key: nil,
diff --git a/app/models/awareness_session.rb b/app/models/awareness_session.rb
index a84a3454a27..0b652984630 100644
--- a/app/models/awareness_session.rb
+++ b/app/models/awareness_session.rb
@@ -63,16 +63,18 @@ class AwarenessSession # rubocop:disable Gitlab/NamespacedClass
user_key = user_sessions_key(user.id)
with_redis do |redis|
- redis.pipelined do |pipeline|
- pipeline.sadd(user_key, id_i)
- pipeline.expire(user_key, USER_LIFETIME.to_i)
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ redis.pipelined do |pipeline|
+ pipeline.sadd?(user_key, id_i)
+ pipeline.expire(user_key, USER_LIFETIME.to_i)
- pipeline.zadd(users_key, timestamp.to_f, user.id)
+ pipeline.zadd(users_key, timestamp.to_f, user.id)
- # We also mark for expiry when a session key is created (first user joins),
- # because some users might never actively leave a session and the key could
- # therefore become stale, w/o us noticing.
- reset_session_expiry(pipeline)
+ # We also mark for expiry when a session key is created (first user joins),
+ # because some users might never actively leave a session and the key could
+ # therefore become stale, w/o us noticing.
+ reset_session_expiry(pipeline)
+ end
end
end
@@ -83,26 +85,33 @@ class AwarenessSession # rubocop:disable Gitlab/NamespacedClass
user_key = user_sessions_key(user.id)
with_redis do |redis|
- redis.pipelined do |pipeline|
- pipeline.srem(user_key, id_i)
- pipeline.zrem(users_key, user.id)
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ redis.pipelined do |pipeline|
+ pipeline.srem?(user_key, id_i)
+ pipeline.zrem(users_key, user.id)
+ end
end
# cleanup orphan sessions and users
#
# this needs to be a second pipeline due to the delete operations being
# dependent on the result of the cardinality checks
- user_sessions_count, session_users_count = redis.pipelined do |pipeline|
- pipeline.scard(user_key)
- pipeline.zcard(users_key)
- end
+ user_sessions_count, session_users_count =
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ redis.pipelined do |pipeline|
+ pipeline.scard(user_key)
+ pipeline.zcard(users_key)
+ end
+ end
- redis.pipelined do |pipeline|
- pipeline.del(user_key) unless user_sessions_count > 0
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ redis.pipelined do |pipeline|
+ pipeline.del(user_key) unless user_sessions_count > 0
- unless session_users_count > 0
- pipeline.del(users_key)
- @id = nil
+ unless session_users_count > 0
+ pipeline.del(users_key)
+ @id = nil
+ end
end
end
end
diff --git a/app/models/broadcast_message.rb b/app/models/broadcast_message.rb
index 1f921c71984..c5a234ffa69 100644
--- a/app/models/broadcast_message.rb
+++ b/app/models/broadcast_message.rb
@@ -23,8 +23,8 @@ class BroadcastMessage < ApplicationRecord
validates :color, allow_blank: true, color: true
validates :font, allow_blank: true, color: true
- default_value_for :color, '#E75E40'
- default_value_for :font, '#FFFFFF'
+ attribute :color, default: '#E75E40'
+ attribute :font, default: '#FFFFFF'
CACHE_KEY = 'broadcast_message_current_json'
BANNER_CACHE_KEY = 'broadcast_message_current_banner_json'
diff --git a/app/models/ci/bridge.rb b/app/models/ci/bridge.rb
index 323d759510e..d6051d70503 100644
--- a/app/models/ci/bridge.rb
+++ b/app/models/ci/bridge.rb
@@ -21,7 +21,6 @@ module Ci
has_many :sourced_pipelines, class_name: "::Ci::Sources::Pipeline",
foreign_key: :source_job_id
- has_one :sourced_pipeline, class_name: "::Ci::Sources::Pipeline", foreign_key: :source_job_id
has_one :downstream_pipeline, through: :sourced_pipeline, source: :pipeline
validates :ref, presence: true
@@ -58,11 +57,7 @@ module Ci
end
def retryable?
- return false unless Feature.enabled?(:ci_recreate_downstream_pipeline, project)
-
- return false if failed? && (pipeline_loop_detected? || reached_max_descendant_pipelines_depth?)
-
- super
+ false
end
def self.with_preloads
@@ -183,7 +178,7 @@ module Ci
false
end
- def prevent_rollback_deployment?
+ def outdated_deployment?
false
end
@@ -288,7 +283,11 @@ module Ci
return [] unless forward_yaml_variables?
yaml_variables.to_a.map do |hash|
- { key: hash[:key], value: ::ExpandVariables.expand(hash[:value], expand_variables) }
+ if hash[:raw] && ci_raw_variables_in_yaml_config_enabled?
+ { key: hash[:key], value: hash[:value], raw: true }
+ else
+ { key: hash[:key], value: ::ExpandVariables.expand(hash[:value], expand_variables) }
+ end
end
end
@@ -296,7 +295,11 @@ module Ci
return [] unless forward_pipeline_variables?
pipeline.variables.to_a.map do |variable|
- { key: variable.key, value: ::ExpandVariables.expand(variable.value, expand_variables) }
+ if variable.raw? && ci_raw_variables_in_yaml_config_enabled?
+ { key: variable.key, value: variable.value, raw: true }
+ else
+ { key: variable.key, value: ::ExpandVariables.expand(variable.value, expand_variables) }
+ end
end
end
@@ -305,7 +308,11 @@ module Ci
return [] unless pipeline.pipeline_schedule
pipeline.pipeline_schedule.variables.to_a.map do |variable|
- { key: variable.key, value: ::ExpandVariables.expand(variable.value, expand_variables) }
+ if variable.raw? && ci_raw_variables_in_yaml_config_enabled?
+ { key: variable.key, value: variable.value, raw: true }
+ else
+ { key: variable.key, value: ::ExpandVariables.expand(variable.value, expand_variables) }
+ end
end
end
@@ -324,6 +331,12 @@ module Ci
result.nil? ? FORWARD_DEFAULTS[:pipeline_variables] : result
end
end
+
+ def ci_raw_variables_in_yaml_config_enabled?
+ strong_memoize(:ci_raw_variables_in_yaml_config_enabled) do
+ ::Feature.enabled?(:ci_raw_variables_in_yaml_config, project)
+ end
+ end
end
end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index b8511536e32..f44ba124fe2 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -72,33 +72,6 @@ module Ci
delegate :trigger_short_token, to: :trigger_request, allow_nil: true
delegate :ensure_persistent_ref, to: :pipeline
- ##
- # Since Gitlab 11.5, deployments records started being created right after
- # `ci_builds` creation. We can look up a relevant `environment` through
- # `deployment` relation today.
- # (See more https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/22380)
- #
- # Since Gitlab 12.9, we started persisting the expanded environment name to
- # avoid repeated variables expansion in `action: stop` builds as well.
- def persisted_environment
- return unless has_environment?
-
- strong_memoize(:persisted_environment) do
- # This code path has caused N+1s in the past, since environments are only indirectly
- # associated to builds and pipelines; see https://gitlab.com/gitlab-org/gitlab/-/issues/326445
- # We therefore batch-load them to prevent dormant N+1s until we found a proper solution.
- BatchLoader.for(expanded_environment_name).batch(key: project_id) do |names, loader, args|
- Environment.where(name: names, project: args[:key]).find_each do |environment|
- loader.call(environment.name, environment)
- end
- end
- end
- end
-
- def persisted_environment=(environment)
- strong_memoize(:persisted_environment) { environment }
- end
-
serialize :options # rubocop:disable Cop/ActiveRecordSerialize
serialize :yaml_variables, Gitlab::Serializer::Ci::Variables # rubocop:disable Cop/ActiveRecordSerialize
@@ -199,7 +172,7 @@ module Ci
add_authentication_token_field :token, encrypted: :required
- before_save :ensure_token
+ before_save :ensure_token, unless: :assign_token_on_scheduling?
after_save :stick_build_if_status_changed
@@ -218,10 +191,6 @@ module Ci
preload(:job_artifacts_archive, :job_artifacts, :tags, project: [:namespace])
end
- def extra_accessors
- []
- end
-
def clone_accessors
%i[pipeline project ref tag options name
allow_failure stage stage_idx trigger_request
@@ -278,6 +247,14 @@ module Ci
!build.waiting_for_deployment_approval? # If false is returned, it stops the transition
end
+ before_transition any => [:pending] do |build, transition|
+ if build.assign_token_on_scheduling?
+ build.ensure_token
+ end
+
+ true
+ end
+
after_transition created: :scheduled do |build|
build.run_after_commit do
Ci::BuildScheduleWorker.perform_at(build.scheduled_at, build.id)
@@ -445,9 +422,10 @@ module Ci
manual? && starts_environment? && deployment&.blocked?
end
- def prevent_rollback_deployment?
- strong_memoize(:prevent_rollback_deployment) do
+ def outdated_deployment?
+ strong_memoize(:outdated_deployment) do
starts_environment? &&
+ incomplete? &&
project.ci_forward_deployment_enabled? &&
deployment&.older_than_last_successful_deployment?
end
@@ -494,8 +472,34 @@ module Ci
Gitlab::Ci::Build::Prerequisite::Factory.new(self).unmet
end
+ def persisted_environment
+ return unless has_environment_keyword?
+
+ strong_memoize(:persisted_environment) do
+ # This code path has caused N+1s in the past, since environments are only indirectly
+ # associated to builds and pipelines; see https://gitlab.com/gitlab-org/gitlab/-/issues/326445
+ # We therefore batch-load them to prevent dormant N+1s until we found a proper solution.
+ BatchLoader.for(expanded_environment_name).batch(key: project_id) do |names, loader, args|
+ Environment.where(name: names, project: args[:key]).find_each do |environment|
+ loader.call(environment.name, environment)
+ end
+ end
+ end
+ end
+
+ def persisted_environment=(environment)
+ strong_memoize(:persisted_environment) { environment }
+ end
+
+ # If build.persisted_environment is a BatchLoader, we need to remove
+ # the method proxy in order to clone into new item here
+ # https://github.com/exAspArk/batch-loader/issues/31
+ def actual_persisted_environment
+ persisted_environment.respond_to?(:__sync) ? persisted_environment.__sync : persisted_environment
+ end
+
def expanded_environment_name
- return unless has_environment?
+ return unless has_environment_keyword?
strong_memoize(:expanded_environment_name) do
# We're using a persisted expanded environment name in order to avoid
@@ -509,7 +513,7 @@ module Ci
end
def expanded_kubernetes_namespace
- return unless has_environment?
+ return unless has_environment_keyword?
namespace = options.dig(:environment, :kubernetes, :namespace)
@@ -520,16 +524,16 @@ module Ci
end
end
- def has_environment?
+ def has_environment_keyword?
environment.present?
end
def starts_environment?
- has_environment? && self.environment_action == 'start'
+ has_environment_keyword? && self.environment_action == 'start'
end
def stops_environment?
- has_environment? && self.environment_action == 'stop'
+ has_environment_keyword? && self.environment_action == 'stop'
end
def environment_action
@@ -971,7 +975,7 @@ module Ci
def collect_codequality_reports!(codequality_report)
each_report(Ci::JobArtifact.file_types_for_report(:codequality)) do |file_type, blob|
- Gitlab::Ci::Parsers.fabricate!(file_type).parse!(blob, codequality_report)
+ Gitlab::Ci::Parsers.fabricate!(file_type).parse!(blob, codequality_report, { project: project, commit_sha: pipeline.sha })
end
codequality_report
@@ -1043,7 +1047,8 @@ module Ci
# TODO: Have `debug_mode?` check against data on sent back from runner
# to capture all the ways that variables can be set.
# See (https://gitlab.com/gitlab-org/gitlab/-/issues/290955)
- variables['CI_DEBUG_TRACE']&.value&.casecmp('true') == 0
+ variables['CI_DEBUG_TRACE']&.value&.casecmp('true') == 0 ||
+ variables['CI_DEBUG_SERVICES']&.value&.casecmp('true') == 0
end
def drop_with_exit_code!(failure_reason, exit_code)
@@ -1131,6 +1136,10 @@ module Ci
end
end
+ def assign_token_on_scheduling?
+ ::Feature.enabled?(:ci_assign_job_token_on_scheduling, project)
+ end
+
protected
def run_status_commit_hooks!
@@ -1185,7 +1194,7 @@ module Ci
def environment_status
strong_memoize(:environment_status) do
- if has_environment? && merge_request
+ if has_environment_keyword? && merge_request
EnvironmentStatus.new(project, persisted_environment, merge_request, pipeline.sha)
end
end
@@ -1205,8 +1214,6 @@ module Ci
def legacy_jwt_variables
Gitlab::Ci::Variables::Collection.new.tap do |variables|
- break variables unless Feature.enabled?(:ci_job_jwt, project)
-
jwt = Gitlab::Ci::Jwt.for_build(self)
jwt_v2 = Gitlab::Ci::JwtV2.for_build(self)
variables.append(key: 'CI_JOB_JWT', value: jwt, public: false, masked: true)
diff --git a/app/models/ci/build_metadata.rb b/app/models/ci/build_metadata.rb
index 33092e881f0..2f28509f812 100644
--- a/app/models/ci/build_metadata.rb
+++ b/app/models/ci/build_metadata.rb
@@ -5,6 +5,7 @@ module Ci
# Data that should be persisted forever, should be stored with Ci::Build model.
class BuildMetadata < Ci::ApplicationRecord
BuildTimeout = Struct.new(:value, :source)
+ ROUTING_FEATURE_FLAG = :ci_partitioning_use_ci_builds_metadata_routing_table
include Ci::Partitionable
include Presentable
@@ -13,7 +14,12 @@ module Ci
self.table_name = 'ci_builds_metadata'
self.primary_key = 'id'
- partitionable scope: :build
+ self.sequence_name = 'ci_builds_metadata_id_seq'
+
+ partitionable scope: :build, through: {
+ table: :p_ci_builds_metadata,
+ flag: ROUTING_FEATURE_FLAG
+ }
belongs_to :build, class_name: 'CommitStatus'
belongs_to :project
@@ -24,9 +30,9 @@ module Ci
validates :id_tokens, json_schema: { filename: 'build_metadata_id_tokens' }
validates :secrets, json_schema: { filename: 'build_metadata_secrets' }
- serialize :config_options, Serializers::SymbolizedJson # rubocop:disable Cop/ActiveRecordSerialize
- serialize :config_variables, Serializers::SymbolizedJson # rubocop:disable Cop/ActiveRecordSerialize
- serialize :runtime_runner_features, Serializers::SymbolizedJson # rubocop:disable Cop/ActiveRecordSerialize
+ attribute :config_options, :sym_jsonb
+ attribute :config_variables, :sym_jsonb
+ attribute :runtime_runner_features, :sym_jsonb
chronic_duration_attr_reader :timeout_human_readable, :timeout
@@ -50,7 +56,7 @@ module Ci
end
def set_cancel_gracefully
- runtime_runner_features.merge!( { cancel_gracefully: true } )
+ runtime_runner_features.merge!({ cancel_gracefully: true })
end
def cancel_gracefully?
diff --git a/app/models/ci/build_trace_chunk.rb b/app/models/ci/build_trace_chunk.rb
index 221a2284106..7baa98b59f9 100644
--- a/app/models/ci/build_trace_chunk.rb
+++ b/app/models/ci/build_trace_chunk.rb
@@ -10,7 +10,7 @@ module Ci
belongs_to :build, class_name: "Ci::Build", foreign_key: :build_id
- default_value_for :data_store, :redis_trace_chunks
+ attribute :data_store, default: :redis_trace_chunks
after_create { metrics.increment_trace_operation(operation: :chunked) }
diff --git a/app/models/ci/group_variable.rb b/app/models/ci/group_variable.rb
index e11edbda6dc..508aaa5a63c 100644
--- a/app/models/ci/group_variable.rb
+++ b/app/models/ci/group_variable.rb
@@ -5,6 +5,7 @@ module Ci
include Ci::HasVariable
include Presentable
include Ci::Maskable
+ include Ci::RawVariable
prepend HasEnvironmentScope
belongs_to :group, class_name: "::Group"
diff --git a/app/models/ci/instance_variable.rb b/app/models/ci/instance_variable.rb
index da9d4dea537..3e572dbe18f 100644
--- a/app/models/ci/instance_variable.rb
+++ b/app/models/ci/instance_variable.rb
@@ -5,6 +5,7 @@ module Ci
extend Gitlab::ProcessMemoryCache::Helper
include Ci::NewHasVariable
include Ci::Maskable
+ include Ci::RawVariable
include Limitable
self.limit_name = 'ci_instance_level_variables'
diff --git a/app/models/ci/job_variable.rb b/app/models/ci/job_variable.rb
index 44bd3fe8901..332a78b66ae 100644
--- a/app/models/ci/job_variable.rb
+++ b/app/models/ci/job_variable.rb
@@ -3,6 +3,7 @@
module Ci
class JobVariable < Ci::ApplicationRecord
include Ci::NewHasVariable
+ include Ci::RawVariable
include BulkInsertSafe
belongs_to :job, class_name: "Ci::Build", foreign_key: :job_id
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index cc5ba41191b..020f5cf9d8e 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -121,7 +121,7 @@ module Ci
accepts_nested_attributes_for :variables, reject_if: :persisted?
delegate :full_path, to: :project, prefix: true
- delegate :title, to: :pipeline_metadata, allow_nil: true
+ delegate :name, to: :pipeline_metadata, allow_nil: true
validates :sha, presence: { unless: :importing? }
validates :ref, presence: { unless: :importing? }
@@ -183,7 +183,11 @@ module Ci
end
event :succeed do
- transition any - [:success] => :success
+ # A success pipeline can also be retried, for example; a pipeline with a failed manual job.
+ # When retrying the pipeline, the status of the pipeline is not changed because the failed
+ # manual job transitions to the `manual` status.
+ # More info: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98967#note_1144718316
+ transition any => :success
end
event :cancel do
diff --git a/app/models/ci/pipeline_metadata.rb b/app/models/ci/pipeline_metadata.rb
index c96b395b45f..2bd206c5ca5 100644
--- a/app/models/ci/pipeline_metadata.rb
+++ b/app/models/ci/pipeline_metadata.rb
@@ -9,6 +9,6 @@ module Ci
validates :pipeline, presence: true
validates :project, presence: true
- validates :title, presence: true, length: { minimum: 1, maximum: 255 }
+ validates :name, presence: true, length: { minimum: 1, maximum: 255 }
end
end
diff --git a/app/models/ci/pipeline_schedule_variable.rb b/app/models/ci/pipeline_schedule_variable.rb
index 84a24609cc7..718ed14edeb 100644
--- a/app/models/ci/pipeline_schedule_variable.rb
+++ b/app/models/ci/pipeline_schedule_variable.rb
@@ -3,6 +3,7 @@
module Ci
class PipelineScheduleVariable < Ci::ApplicationRecord
include Ci::HasVariable
+ include Ci::RawVariable
belongs_to :pipeline_schedule
diff --git a/app/models/ci/pipeline_variable.rb b/app/models/ci/pipeline_variable.rb
index 6e4418bc360..8e83b41cd0b 100644
--- a/app/models/ci/pipeline_variable.rb
+++ b/app/models/ci/pipeline_variable.rb
@@ -4,6 +4,7 @@ module Ci
class PipelineVariable < Ci::ApplicationRecord
include Ci::Partitionable
include Ci::HasVariable
+ include Ci::RawVariable
belongs_to :pipeline
diff --git a/app/models/ci/processable.rb b/app/models/ci/processable.rb
index 09dc9d4bce1..eb805ffae0a 100644
--- a/app/models/ci/processable.rb
+++ b/app/models/ci/processable.rb
@@ -7,6 +7,7 @@ module Ci
extend ::Gitlab::Utils::Override
has_one :resource, class_name: 'Ci::Resource', foreign_key: 'build_id', inverse_of: :processable
+ has_one :sourced_pipeline, class_name: 'Ci::Sources::Pipeline', foreign_key: :source_job_id, inverse_of: :source_job
belongs_to :resource_group, class_name: 'Ci::ResourceGroup', inverse_of: :processables
diff --git a/app/models/ci/secure_file.rb b/app/models/ci/secure_file.rb
index ffff7eebbee..df38398e5a9 100644
--- a/app/models/ci/secure_file.rb
+++ b/app/models/ci/secure_file.rb
@@ -27,7 +27,7 @@ module Ci
serialize :metadata, Serializers::Json # rubocop:disable Cop/ActiveRecordSerialize
- default_value_for(:file_store) { Ci::SecureFileUploader.default_store }
+ attribute :file_store, default: -> { Ci::SecureFileUploader.default_store }
mount_file_store_uploader Ci::SecureFileUploader
diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb
index c80c2ebe69a..f4e17b5d812 100644
--- a/app/models/ci/variable.rb
+++ b/app/models/ci/variable.rb
@@ -5,6 +5,7 @@ module Ci
include Ci::HasVariable
include Presentable
include Ci::Maskable
+ include Ci::RawVariable
prepend HasEnvironmentScope
belongs_to :project
diff --git a/app/models/clusters/applications/cert_manager.rb b/app/models/clusters/applications/cert_manager.rb
index 2a051233de2..11f84940c38 100644
--- a/app/models/clusters/applications/cert_manager.rb
+++ b/app/models/clusters/applications/cert_manager.rb
@@ -15,11 +15,8 @@ module Clusters
include ::Clusters::Concerns::ApplicationVersion
include ::Clusters::Concerns::ApplicationData
- default_value_for :version, VERSION
-
- default_value_for :email do |cert_manager|
- cert_manager.cluster&.user&.email
- end
+ attribute :version, default: VERSION
+ after_initialize :set_default_email, if: :new_record?
validates :email, presence: true
@@ -55,6 +52,10 @@ module Clusters
private
+ def set_default_email
+ self.email ||= self.cluster&.user&.email
+ end
+
def pre_install_script
[
apply_file("https://raw.githubusercontent.com/jetstack/cert-manager/release-#{CRD_VERSION}/deploy/manifests/00-crds.yaml"),
diff --git a/app/models/clusters/applications/crossplane.rb b/app/models/clusters/applications/crossplane.rb
index 07378b4e8dc..a7b4fb57149 100644
--- a/app/models/clusters/applications/crossplane.rb
+++ b/app/models/clusters/applications/crossplane.rb
@@ -14,11 +14,8 @@ module Clusters
include ::Clusters::Concerns::ApplicationVersion
include ::Clusters::Concerns::ApplicationData
- default_value_for :version, VERSION
-
- default_value_for :stack do |crossplane|
- ''
- end
+ attribute :version, default: VERSION
+ attribute :stack, default: ""
validates :stack, presence: true
diff --git a/app/models/clusters/applications/helm.rb b/app/models/clusters/applications/helm.rb
index e89cb8be1e7..9fac852ed5b 100644
--- a/app/models/clusters/applications/helm.rb
+++ b/app/models/clusters/applications/helm.rb
@@ -18,7 +18,7 @@ module Clusters
include ::Clusters::Concerns::ApplicationStatus
include ::Gitlab::Utils::StrongMemoize
- default_value_for :version, Gitlab::Kubernetes::Helm::V2::BaseCommand::HELM_VERSION
+ attribute :version, default: Gitlab::Kubernetes::Helm::V2::BaseCommand::HELM_VERSION
before_create :create_keys_and_certs
diff --git a/app/models/clusters/applications/ingress.rb b/app/models/clusters/applications/ingress.rb
index 27550616002..034b178d67d 100644
--- a/app/models/clusters/applications/ingress.rb
+++ b/app/models/clusters/applications/ingress.rb
@@ -17,12 +17,11 @@ module Clusters
include AfterCommitQueue
include UsageStatistics
- default_value_for :ingress_type, :nginx
- default_value_for :version, VERSION
+ attribute :version, default: VERSION
enum ingress_type: {
nginx: 1
- }
+ }, _default: :nginx
FETCH_IP_ADDRESS_DELAY = 30.seconds
diff --git a/app/models/clusters/applications/jupyter.rb b/app/models/clusters/applications/jupyter.rb
index 8d7d9c20bfa..9c0e90d59ed 100644
--- a/app/models/clusters/applications/jupyter.rb
+++ b/app/models/clusters/applications/jupyter.rb
@@ -18,7 +18,7 @@ module Clusters
belongs_to :oauth_application, class_name: 'Doorkeeper::Application'
- default_value_for :version, VERSION
+ attribute :version, default: VERSION
def set_initial_status
return unless not_installable?
diff --git a/app/models/clusters/applications/knative.rb b/app/models/clusters/applications/knative.rb
index 0e7cbb35e47..64366594583 100644
--- a/app/models/clusters/applications/knative.rb
+++ b/app/models/clusters/applications/knative.rb
@@ -43,7 +43,7 @@ module Clusters
end
end
- default_value_for :version, VERSION
+ attribute :version, default: VERSION
validates :hostname, presence: true, hostname: true
diff --git a/app/models/clusters/applications/prometheus.rb b/app/models/clusters/applications/prometheus.rb
index d1e169a1f78..a076c871824 100644
--- a/app/models/clusters/applications/prometheus.rb
+++ b/app/models/clusters/applications/prometheus.rb
@@ -15,7 +15,7 @@ module Clusters
include ::Clusters::Concerns::ApplicationData
include AfterCommitQueue
- default_value_for :version, VERSION
+ attribute :version, default: VERSION
scope :preload_cluster_platform, -> { preload(cluster: [:platform_kubernetes]) }
@@ -24,7 +24,7 @@ module Clusters
key: Settings.attr_encrypted_db_key_base_32,
algorithm: 'aes-256-gcm'
- default_value_for(:alert_manager_token) { SecureRandom.hex }
+ after_initialize :set_alert_manager_token, if: :new_record?
after_destroy do
cluster.find_or_build_integration_prometheus.destroy
@@ -101,6 +101,10 @@ module Clusters
private
+ def set_alert_manager_token
+ self.alert_manager_token = SecureRandom.hex
+ end
+
def install_knative_metrics
return [] unless cluster.application_knative_available?
diff --git a/app/models/clusters/applications/runner.rb b/app/models/clusters/applications/runner.rb
index 1ac4cbac1da..b8ed33828bc 100644
--- a/app/models/clusters/applications/runner.rb
+++ b/app/models/clusters/applications/runner.rb
@@ -15,7 +15,7 @@ module Clusters
belongs_to :runner, class_name: 'Ci::Runner', foreign_key: :runner_id
delegate :project, :group, to: :cluster
- default_value_for :version, VERSION
+ attribute :version, default: VERSION
def chart
"#{name}/gitlab-runner"
diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb
index ad1e7dc305f..25d41d68b9e 100644
--- a/app/models/clusters/cluster.rb
+++ b/app/models/clusters/cluster.rb
@@ -79,7 +79,7 @@ module Clusters
validates :namespace_per_environment, inclusion: { in: [true, false] }
validates :helm_major_version, inclusion: { in: [2, 3] }
- default_value_for :helm_major_version, 3
+ attribute :helm_major_version, default: 3
validate :restrict_modification, on: :update
validate :no_groups, unless: :group_type?
diff --git a/app/models/clusters/integrations/prometheus.rb b/app/models/clusters/integrations/prometheus.rb
index 899529ff49f..935d6238dba 100644
--- a/app/models/clusters/integrations/prometheus.rb
+++ b/app/models/clusters/integrations/prometheus.rb
@@ -26,7 +26,7 @@ module Clusters
key: Settings.attr_encrypted_db_key_base_32,
algorithm: 'aes-256-gcm'
- default_value_for(:alert_manager_token) { SecureRandom.hex }
+ after_initialize :set_alert_manager_token, if: :new_record?
scope :enabled, -> { where(enabled: true) }
@@ -54,6 +54,10 @@ module Clusters
private
+ def set_alert_manager_token
+ self.alert_manager_token = SecureRandom.hex
+ end
+
def activate_project_integrations
::Clusters::Applications::ActivateIntegrationWorker
.perform_async(cluster_id, ::Integrations::Prometheus.to_param)
diff --git a/app/models/clusters/platforms/kubernetes.rb b/app/models/clusters/platforms/kubernetes.rb
index 9d4f0a89403..165285b34b2 100644
--- a/app/models/clusters/platforms/kubernetes.rb
+++ b/app/models/clusters/platforms/kubernetes.rb
@@ -10,6 +10,7 @@ module Clusters
include NullifyIfBlank
RESERVED_NAMESPACES = %w(gitlab-managed-apps).freeze
+ REQUIRED_K8S_MIN_VERSION = 23
IGNORED_CONNECTION_EXCEPTIONS = [
Gitlab::UrlBlocker::BlockedUrlError,
@@ -21,6 +22,8 @@ module Clusters
OpenSSL::SSL::SSLError
].freeze
+ FailedVersionCheckError = Class.new(StandardError)
+
self.table_name = 'cluster_platforms_kubernetes'
self.reactive_cache_work_type = :external_dependency
@@ -64,9 +67,7 @@ module Clusters
unknown_authorization: nil,
rbac: 1,
abac: 2
- }
-
- default_value_for :authorization_type, :rbac
+ }, _default: :rbac
nullify_if_blank :namespace
@@ -208,6 +209,29 @@ module Clusters
kubeclient.get_ingresses(namespace: namespace).as_json
rescue Kubeclient::ResourceNotFoundError
[]
+ rescue NoMethodError => e
+ # We get NoMethodError for Kubernetes versions < 1.19. Since we only support >= 1.23
+ # we will ignore this error for previous versions. For more details read:
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/371249#note_1079866043
+ return [] if server_version < REQUIRED_K8S_MIN_VERSION
+
+ raise e
+ end
+
+ def server_version
+ full_url = Gitlab::UrlSanitizer.new("#{api_url}/version").full_url
+
+ # We can't use `kubeclient` to check the cluster version because it does not support it
+ # https://github.com/ManageIQ/kubeclient/issues/309
+ response = Gitlab::HTTP.perform_request(
+ Net::HTTP::Get, full_url,
+ headers: { "Authorization" => "Bearer #{token}" },
+ cert_store: kubeclient_ssl_options[:cert_store])
+
+ Gitlab::ErrorTracking.track_exception(FailedVersionCheckError.new) unless response.success?
+
+ json_response = Gitlab::Json.parse(response.body)
+ json_response["minor"].to_i
end
def build_kube_client!
diff --git a/app/models/clusters/providers/aws.rb b/app/models/clusters/providers/aws.rb
index af2eba42721..f0f56d9ebd9 100644
--- a/app/models/clusters/providers/aws.rb
+++ b/app/models/clusters/providers/aws.rb
@@ -12,9 +12,9 @@ module Clusters
belongs_to :cluster, inverse_of: :provider_aws, class_name: 'Clusters::Cluster'
- default_value_for :region, DEFAULT_REGION
- default_value_for :num_nodes, 3
- default_value_for :instance_type, 'm5.large'
+ attribute :region, default: DEFAULT_REGION
+ attribute :num_nodes, default: 3
+ attribute :instance_type, default: "m5.large"
attr_encrypted :secret_access_key,
mode: :per_attribute_iv,
diff --git a/app/models/clusters/providers/gcp.rb b/app/models/clusters/providers/gcp.rb
index 2ca7d0249dc..fde5ed592cb 100644
--- a/app/models/clusters/providers/gcp.rb
+++ b/app/models/clusters/providers/gcp.rb
@@ -9,10 +9,10 @@ module Clusters
belongs_to :cluster, inverse_of: :provider_gcp, class_name: 'Clusters::Cluster'
- default_value_for :zone, 'us-central1-a'
- default_value_for :num_nodes, 3
- default_value_for :machine_type, 'n1-standard-2'
- default_value_for :cloud_run, false
+ attribute :zone, default: 'us-central1-a'
+ attribute :num_nodes, default: 3
+ attribute :machine_type, default: 'n1-standard-2'
+ attribute :cloud_run, default: false
scope :cloud_run, -> { where(cloud_run: true) }
diff --git a/app/models/commit_collection.rb b/app/models/commit_collection.rb
index a3ee8e4f364..7d89ddde0cb 100644
--- a/app/models/commit_collection.rb
+++ b/app/models/commit_collection.rb
@@ -13,10 +13,11 @@ class CommitCollection
# container - The object the commits belong to.
# commits - The Commit instances to store.
# ref - The name of the ref (e.g. "master").
- def initialize(container, commits, ref = nil)
+ def initialize(container, commits, ref = nil, page: nil, per_page: nil, count: nil)
@container = container
@commits = commits
@ref = ref
+ @pagination = Gitlab::PaginationDelegate.new(page: page, per_page: per_page, count: count)
end
def each(&block)
@@ -113,4 +114,8 @@ class CommitCollection
def method_missing(message, *args, &block)
commits.public_send(message, *args, &block)
end
+
+ def next_page
+ @pagination.next_page
+ end
end
diff --git a/app/models/commit_signatures/gpg_signature.rb b/app/models/commit_signatures/gpg_signature.rb
index 1ce76b53da4..2ae59853520 100644
--- a/app/models/commit_signatures/gpg_signature.rb
+++ b/app/models/commit_signatures/gpg_signature.rb
@@ -49,5 +49,9 @@ module CommitSignatures
Gitlab::Gpg::Commit.new(commit)
end
+
+ def user
+ gpg_key&.user
+ end
end
end
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index 05a258e6e26..2470eada62e 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -9,11 +9,9 @@ class CommitStatus < Ci::ApplicationRecord
include EnumWithNil
include BulkInsertableAssociations
include TaggableQueries
- include IgnorableColumns
self.table_name = 'ci_builds'
partitionable scope: :pipeline
- ignore_column :trace, remove_with: '15.6', remove_after: '2022-10-22'
belongs_to :user
belongs_to :project
@@ -23,7 +21,12 @@ class CommitStatus < Ci::ApplicationRecord
has_many :needs, class_name: 'Ci::BuildNeed', foreign_key: :build_id, inverse_of: :build
+ attribute :retried, default: false
+
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
delegate :commit, to: :pipeline
delegate :sha, :short_sha, :before_sha, to: :pipeline
@@ -98,12 +101,6 @@ class CommitStatus < Ci::ApplicationRecord
merge(or_conditions)
end
- # 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
-
- default_value_for :retried, false
-
##
# We still create some CommitStatuses outside of CreatePipelineService.
#
diff --git a/app/models/concerns/ci/has_status.rb b/app/models/concerns/ci/has_status.rb
index 910885c833f..9a04776f1c6 100644
--- a/app/models/concerns/ci/has_status.rb
+++ b/app/models/concerns/ci/has_status.rb
@@ -110,6 +110,10 @@ module Ci
COMPLETED_STATUSES.include?(status)
end
+ def incomplete?
+ COMPLETED_STATUSES.exclude?(status)
+ end
+
def blocked?
BLOCKED_STATUS.include?(status)
end
diff --git a/app/models/concerns/ci/metadatable.rb b/app/models/concerns/ci/metadatable.rb
index ff884984099..d93f4a150d5 100644
--- a/app/models/concerns/ci/metadatable.rb
+++ b/app/models/concerns/ci/metadatable.rb
@@ -87,6 +87,16 @@ module Ci
ensure_metadata.id_tokens = value
end
+ def enqueue_immediately?
+ !!options[:enqueue_immediately]
+ end
+
+ def set_enqueue_immediately!
+ # ensures that even if `config_options: nil` in the database we set the
+ # new value correctly.
+ self.options = options.merge(enqueue_immediately: true)
+ end
+
private
def read_metadata_attribute(legacy_key, metadata_key, default_value = nil)
diff --git a/app/models/concerns/ci/partitionable.rb b/app/models/concerns/ci/partitionable.rb
index df803180e77..68a6714c892 100644
--- a/app/models/concerns/ci/partitionable.rb
+++ b/app/models/concerns/ci/partitionable.rb
@@ -57,9 +57,14 @@ module Ci
end
class_methods do
- private
+ def partitionable(scope:, through: nil)
+ if through
+ define_singleton_method(:routing_table_name) { through[:table] }
+ define_singleton_method(:routing_table_name_flag) { through[:flag] }
+
+ include Partitionable::Switch
+ end
- def partitionable(scope:)
define_method(:partition_scope_value) do
strong_memoize(:partition_scope_value) do
next Ci::Pipeline.current_partition_value if respond_to?(:importing?) && importing?
diff --git a/app/models/concerns/ci/partitionable/switch.rb b/app/models/concerns/ci/partitionable/switch.rb
new file mode 100644
index 00000000000..c1bbd107e9f
--- /dev/null
+++ b/app/models/concerns/ci/partitionable/switch.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module Ci
+ module Partitionable
+ module Switch
+ extend ActiveSupport::Concern
+
+ # These methods are cached at the class level and depend on the value
+ # of `table_name`, changing that value resets them.
+ # `cached_find_by_statement` is used to cache SQL statements which can
+ # include the table name.
+ #
+ SWAPABLE_METHODS = %i[table_name quoted_table_name arel_table
+ predicate_builder cached_find_by_statement].freeze
+
+ included do |base|
+ partitioned = Class.new(base) do
+ self.table_name = base.routing_table_name
+
+ def self.routing_class?
+ true
+ end
+ end
+
+ base.const_set(:Partitioned, partitioned)
+ end
+
+ class_methods do
+ def routing_class?
+ false
+ end
+
+ def routing_table_enabled?
+ return false if routing_class?
+
+ Gitlab::SafeRequestStore.fetch(routing_table_name_flag) do
+ ::Feature.enabled?(routing_table_name_flag)
+ end
+ end
+
+ # We're delegating them to the `Partitioned` model.
+ # They do not require any check override since they come from AR core
+ # (are always defined) and we're using `super` to get the value.
+ #
+ SWAPABLE_METHODS.each do |name|
+ define_method(name) do |*args, &block|
+ if routing_table_enabled?
+ self::Partitioned.public_send(name, *args, &block) # rubocop: disable GitlabSecurity/PublicSend
+ else
+ super(*args, &block)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/models/concerns/ci/raw_variable.rb b/app/models/concerns/ci/raw_variable.rb
new file mode 100644
index 00000000000..5cfc781c9f1
--- /dev/null
+++ b/app/models/concerns/ci/raw_variable.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Ci
+ module RawVariable
+ extend ActiveSupport::Concern
+
+ included do
+ validates :raw, inclusion: { in: [true, false] }
+ end
+
+ private
+
+ def uncached_runner_variable
+ super.merge(raw: raw?)
+ end
+ end
+end
diff --git a/app/models/concerns/ci/track_environment_usage.rb b/app/models/concerns/ci/track_environment_usage.rb
index 45d9cdeeb59..fe548c77590 100644
--- a/app/models/concerns/ci/track_environment_usage.rb
+++ b/app/models/concerns/ci/track_environment_usage.rb
@@ -17,7 +17,7 @@ module Ci
end
def verifies_environment?
- has_environment? && environment_action == 'verify'
+ has_environment_keyword? && environment_action == 'verify'
end
def count_user_deployment?
diff --git a/app/models/concerns/encrypted_user_password.rb b/app/models/concerns/encrypted_user_password.rb
new file mode 100644
index 00000000000..97e6592f442
--- /dev/null
+++ b/app/models/concerns/encrypted_user_password.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+# Support for both BCrypt and PBKDF2+SHA512 user passwords
+# Meant to be used exclusively with User model but extracted
+# to a concern for isolation and clarity.
+module EncryptedUserPassword
+ extend ActiveSupport::Concern
+
+ BCRYPT_PREFIX = '$2a$'
+ PBKDF2_SHA512_PREFIX = '$pbkdf2-sha512$'
+
+ BCRYPT_STRATEGY = :bcrypt
+ PBKDF2_SHA512_STRATEGY = :pbkdf2_sha512
+
+ # Use Devise DatabaseAuthenticatable#authenticatable_salt
+ # unless encrypted password is PBKDF2+SHA512.
+ def authenticatable_salt
+ return super unless pbkdf2_password?
+
+ Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512.split_digest(encrypted_password)[:salt]
+ end
+
+ # Called by Devise during database authentication.
+ # Also migrates the user password to the configured
+ # encryption type (BCrypt or PBKDF2+SHA512), if needed.
+ def valid_password?(password)
+ return false unless password_matches?(password)
+
+ migrate_password!(password)
+ end
+
+ def password=(new_password)
+ @password = new_password # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ return unless new_password.present?
+
+ self.encrypted_password = if Gitlab::FIPS.enabled?
+ Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512.digest(
+ new_password,
+ Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512::STRETCHES,
+ Devise.friendly_token[0, 16])
+ else
+ Devise::Encryptor.digest(self.class, new_password)
+ end
+ end
+
+ private
+
+ def password_strategy
+ return BCRYPT_STRATEGY if encrypted_password.starts_with?(BCRYPT_PREFIX)
+ return PBKDF2_SHA512_STRATEGY if encrypted_password.starts_with?(PBKDF2_SHA512_PREFIX)
+
+ :unknown
+ end
+
+ def pbkdf2_password?
+ password_strategy == PBKDF2_SHA512_STRATEGY
+ end
+
+ def bcrypt_password?
+ password_strategy == BCRYPT_STRATEGY
+ end
+
+ def password_matches?(password)
+ if bcrypt_password?
+ Devise::Encryptor.compare(self.class, encrypted_password, password)
+ elsif pbkdf2_password?
+ Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512.compare(encrypted_password, password)
+ end
+ end
+
+ def migrate_password!(password)
+ return true if password_strategy == encryptor
+
+ update_attribute(:password, password)
+ end
+
+ def encryptor
+ return BCRYPT_STRATEGY unless Gitlab::FIPS.enabled?
+
+ PBKDF2_SHA512_STRATEGY
+ end
+end
diff --git a/app/models/concerns/enums/sbom.rb b/app/models/concerns/enums/sbom.rb
index 518efa669ad..8848c0c5555 100644
--- a/app/models/concerns/enums/sbom.rb
+++ b/app/models/concerns/enums/sbom.rb
@@ -6,8 +6,23 @@ module Enums
library: 0
}.with_indifferent_access.freeze
+ PURL_TYPES = {
+ composer: 1, # refered to as `packagist` in gemnasium-db
+ conan: 2,
+ gem: 3,
+ golang: 4, # refered to as `go` in gemnasium-db
+ maven: 5,
+ npm: 6,
+ nuget: 7,
+ pypi: 8
+ }.with_indifferent_access.freeze
+
def self.component_types
COMPONENT_TYPES
end
+
+ def self.purl_types
+ PURL_TYPES
+ end
end
end
diff --git a/app/models/concerns/file_store_mounter.rb b/app/models/concerns/file_store_mounter.rb
index f1ac734635d..4d267dc69d0 100644
--- a/app/models/concerns/file_store_mounter.rb
+++ b/app/models/concerns/file_store_mounter.rb
@@ -1,31 +1,35 @@
# frozen_string_literal: true
module FileStoreMounter
+ ALLOWED_FILE_FIELDS = %i[file signed_file].freeze
+
extend ActiveSupport::Concern
class_methods do
- # When `skip_store_file: true` is used, the model MUST explicitly call `store_file_now!`
- def mount_file_store_uploader(uploader, skip_store_file: false)
- mount_uploader(:file, uploader)
+ # When `skip_store_file: true` is used, the model MUST explicitly call `store_#{file_field}_now!`
+ def mount_file_store_uploader(uploader, skip_store_file: false, file_field: :file)
+ raise ArgumentError, "file_field not allowed: #{file_field}" unless ALLOWED_FILE_FIELDS.include?(file_field)
+
+ mount_uploader(file_field, uploader)
+
+ define_method("update_#{file_field}_store") do
+ # The file.object_store is set during `uploader.store!` and `uploader.migrate!`
+ update_column("#{file_field}_store", public_send(file_field).object_store) # rubocop:disable GitlabSecurity/PublicSend
+ end
+
+ define_method("store_#{file_field}_now!") do
+ public_send("store_#{file_field}!") # rubocop:disable GitlabSecurity/PublicSend
+ public_send("update_#{file_field}_store") # rubocop:disable GitlabSecurity/PublicSend
+ end
if skip_store_file
- skip_callback :save, :after, :store_file!
+ skip_callback :save, :after, "store_#{file_field}!".to_sym
return
end
# This hook is a no-op when the file is uploaded after_commit
- after_save :update_file_store, if: :saved_change_to_file?
+ after_save "update_#{file_field}_store".to_sym, if: "saved_change_to_#{file_field}?".to_sym
end
end
-
- def update_file_store
- # The file.object_store is set during `uploader.store!` and `uploader.migrate!`
- update_column(:file_store, file.object_store)
- end
-
- def store_file_now!
- store_file!
- update_file_store
- end
end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index f8389865f91..31b2a8d7cc1 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -217,6 +217,10 @@ module Issuable
false
end
+ def supports_confidentiality?
+ false
+ end
+
def severity
return IssuableSeverity::DEFAULT unless supports_severity?
@@ -236,7 +240,6 @@ module Issuable
end
def validate_assignee_size_length
- return true unless Feature.enabled?(:limit_assignees_per_issuable)
return true unless assignees.size > MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS
errors.add :assignees,
@@ -460,18 +463,6 @@ module Issuable
end
end
- def today?
- Date.today == created_at.to_date
- end
-
- def created_hours_ago
- (Time.now.utc.to_i - created_at.utc.to_i) / 3600
- end
-
- def new?
- created_hours_ago < 24
- end
-
def open?
opened?
end
diff --git a/app/models/concerns/milestoneable.rb b/app/models/concerns/milestoneable.rb
index 14c54d99ef3..a95bed7ad42 100644
--- a/app/models/concerns/milestoneable.rb
+++ b/app/models/concerns/milestoneable.rb
@@ -18,7 +18,7 @@ module Milestoneable
scope :with_milestone, ->(title) { left_joins_milestones.where(milestones: { title: title }) }
scope :without_particular_milestones, ->(titles) { left_outer_joins(:milestone).where("milestones.title NOT IN (?) OR milestone_id IS NULL", titles) }
scope :any_release, -> { joins_milestone_releases }
- scope :with_release, -> (tag, project_id) { joins_milestone_releases.where( milestones: { releases: { tag: tag, project_id: project_id } } ) }
+ scope :with_release, -> (tag, project_id) { joins_milestone_releases.where(milestones: { releases: { tag: tag, project_id: project_id } }) }
scope :without_particular_release, -> (tag, project_id) { joins_milestone_releases.where.not(milestones: { releases: { tag: tag, project_id: project_id } }) }
scope :left_joins_milestones, -> { joins("LEFT OUTER JOIN milestones ON #{table_name}.milestone_id = milestones.id") }
diff --git a/app/models/concerns/mirror_authentication.rb b/app/models/concerns/mirror_authentication.rb
index 14c8be93ce0..e3bfeaf7f95 100644
--- a/app/models/concerns/mirror_authentication.rb
+++ b/app/models/concerns/mirror_authentication.rb
@@ -11,7 +11,7 @@ module MirrorAuthentication
# We should generate a key even if there's no SSH URL present
before_validation :generate_ssh_private_key!, if: -> {
- regenerate_ssh_private_key || ( auth_method == 'ssh_public_key' && ssh_private_key.blank? )
+ regenerate_ssh_private_key || (auth_method == 'ssh_public_key' && ssh_private_key.blank?)
}
credentials_field :auth_method, reader: false
diff --git a/app/models/concerns/noteable.rb b/app/models/concerns/noteable.rb
index c1aac235d33..492d55c74e2 100644
--- a/app/models/concerns/noteable.rb
+++ b/app/models/concerns/noteable.rb
@@ -210,11 +210,23 @@ module Noteable
# Synthetic system notes don't have discussion IDs because these are generated dynamically
# in Ruby. These are always root notes anyway so we don't need to group by discussion ID.
def synthetic_note_ids_relations
- [
- resource_label_events.select("'resource_label_events'", "'NULL'", :id, :created_at),
- resource_milestone_events.select("'resource_milestone_events'", "'NULL'", :id, :created_at),
- resource_state_events.select("'resource_state_events'", "'NULL'", :id, :created_at)
- ]
+ relations = []
+
+ # currently multiple models include Noteable concern, but not all of them support
+ # all resource events, so we check if given model supports given resource event.
+ if respond_to?(:resource_label_events)
+ relations << resource_label_events.select("'resource_label_events'", "'NULL'", :id, :created_at)
+ end
+
+ if respond_to?(:resource_state_events)
+ relations << resource_state_events.select("'resource_state_events'", "'NULL'", :id, :created_at)
+ end
+
+ if respond_to?(:resource_milestone_events)
+ relations << resource_milestone_events.select("'resource_milestone_events'", "'NULL'", :id, :created_at)
+ end
+
+ relations
end
end
diff --git a/app/models/concerns/packages/debian/distribution.rb b/app/models/concerns/packages/debian/distribution.rb
index 1520ec0828e..75fd45d13a9 100644
--- a/app/models/concerns/packages/debian/distribution.rb
+++ b/app/models/concerns/packages/debian/distribution.rb
@@ -85,8 +85,7 @@ module Packages
scope :with_codename_or_suite, ->(codename_or_suite) { with_codename(codename_or_suite).or(with_suite(codename_or_suite)) }
mount_file_store_uploader Packages::Debian::DistributionReleaseFileUploader
- mount_uploader :signed_file, Packages::Debian::DistributionReleaseFileUploader
- after_save :update_signed_file_store, if: :saved_change_to_signed_file?
+ mount_file_store_uploader Packages::Debian::DistributionReleaseFileUploader, file_field: :signed_file
def component_names
components.pluck(:name).sort
@@ -119,12 +118,6 @@ module Packages
self.class.with_container(container).with_codename(suite).exists?
end
-
- def update_signed_file_store
- # The signed_file.object_store is set during `uploader.store!`
- # which happens after object is inserted/updated
- self.update_column(:signed_file_store, signed_file.object_store)
- end
end
end
end
diff --git a/app/models/concerns/pg_full_text_searchable.rb b/app/models/concerns/pg_full_text_searchable.rb
index 335fcec2611..562c8cf23f3 100644
--- a/app/models/concerns/pg_full_text_searchable.rb
+++ b/app/models/concerns/pg_full_text_searchable.rb
@@ -25,6 +25,7 @@ module PgFullTextSearchable
TSVECTOR_MAX_LENGTH = 1.megabyte.freeze
TEXT_SEARCH_DICTIONARY = 'english'
URL_SCHEME_REGEX = %r{(?<=\A|\W)\w+://(?=\w+)}.freeze
+ TSQUERY_DISALLOWED_CHARACTERS_REGEX = %r{[^a-zA-Z0-9 .@/\-_"]}.freeze
def update_search_data!
tsvector_sql_nodes = self.class.pg_full_text_searchable_columns.map do |column, weight|
@@ -102,21 +103,16 @@ module PgFullTextSearchable
end
end
- def pg_full_text_search(search_term)
+ def pg_full_text_search(query, matched_columns: [])
search_data_table = reflect_on_association(:search_data).klass.arel_table
- # This fixes an inconsistency with how to_tsvector and websearch_to_tsquery process URLs
- # See https://gitlab.com/gitlab-org/gitlab/-/issues/354784#note_905431920
- search_term = remove_url_scheme(search_term)
- search_term = ActiveSupport::Inflector.transliterate(search_term)
-
joins(:search_data).where(
Arel::Nodes::InfixOperation.new(
'@@',
search_data_table[:search_vector],
Arel::Nodes::NamedFunction.new(
- 'websearch_to_tsquery',
- [Arel::Nodes.build_quoted(TEXT_SEARCH_DICTIONARY), Arel::Nodes.build_quoted(search_term)]
+ 'to_tsquery',
+ [Arel::Nodes.build_quoted(TEXT_SEARCH_DICTIONARY), build_tsquery(query, matched_columns)]
)
)
)
@@ -124,8 +120,39 @@ module PgFullTextSearchable
private
- def remove_url_scheme(search_term)
- search_term.gsub(URL_SCHEME_REGEX, '')
+ def build_tsquery(query, matched_columns)
+ # URLs get broken up into separate words when : is removed below, so we just remove the whole scheme.
+ query = remove_url_scheme(query)
+ # Remove accents from search term to match indexed data
+ query = ActiveSupport::Inflector.transliterate(query)
+ # Prevent users from using tsquery operators that can cause syntax errors.
+ query = filter_allowed_characters(query)
+
+ weights = matched_columns.map do |column_name|
+ pg_full_text_searchable_columns[column_name]
+ end.compact.join
+ prefix_search_suffix = ":*#{weights}"
+
+ tsquery = Gitlab::SQL::Pattern.split_query_to_search_terms(query).map do |search_term|
+ case search_term
+ when /\A\d+\z/ # Handles https://gitlab.com/gitlab-org/gitlab/-/issues/375337
+ "(#{search_term + prefix_search_suffix} | -#{search_term + prefix_search_suffix})"
+ when /\s/
+ search_term.split.map { |t| "#{t}:#{weights}" }.join(' <-> ')
+ else
+ search_term + prefix_search_suffix
+ end
+ end.join(' & ')
+
+ Arel::Nodes.build_quoted(tsquery)
+ end
+
+ def remove_url_scheme(query)
+ query.gsub(URL_SCHEME_REGEX, '')
+ end
+
+ def filter_allowed_characters(query)
+ query.gsub(TSQUERY_DISALLOWED_CHARACTERS_REGEX, ' ')
end
end
end
diff --git a/app/models/concerns/project_features_compatibility.rb b/app/models/concerns/project_features_compatibility.rb
index 2976b6f02a7..d37f20e2e7c 100644
--- a/app/models/concerns/project_features_compatibility.rb
+++ b/app/models/concerns/project_features_compatibility.rb
@@ -110,6 +110,10 @@ module ProjectFeaturesCompatibility
write_feature_attribute_string(:releases_access_level, value)
end
+ def infrastructure_access_level=(value)
+ write_feature_attribute_string(:infrastructure_access_level, value)
+ end
+
# TODO: Remove this method after we drop support for project create/edit APIs to set the
# container_registry_enabled attribute. They can instead set the container_registry_access_level
# attribute.
diff --git a/app/models/concerns/protected_ref.rb b/app/models/concerns/protected_ref.rb
index ec56f4a32af..7e1ebd1eba3 100644
--- a/app/models/concerns/protected_ref.rb
+++ b/app/models/concerns/protected_ref.rb
@@ -7,7 +7,6 @@ module ProtectedRef
belongs_to :project, touch: true
validates :name, presence: true
- validates :project, presence: true
delegate :matching, :matches?, :wildcard?, to: :ref_matcher
diff --git a/app/models/concerns/protected_ref_access.rb b/app/models/concerns/protected_ref_access.rb
index 618ad96905d..facf0808e7a 100644
--- a/app/models/concerns/protected_ref_access.rb
+++ b/app/models/concerns/protected_ref_access.rb
@@ -21,8 +21,8 @@ module ProtectedRefAccess
included do
scope :maintainer, -> { where(access_level: Gitlab::Access::MAINTAINER) }
scope :developer, -> { where(access_level: Gitlab::Access::DEVELOPER) }
- scope :by_user, -> (user) { where(user_id: user ) }
- scope :by_group, -> (group) { where(group_id: group ) }
+ scope :by_user, -> (user) { where(user_id: user) }
+ scope :by_group, -> (group) { where(group_id: group) }
scope :for_role, -> { where(user_id: nil, group_id: nil) }
scope :for_user, -> { where.not(user_id: nil) }
scope :for_group, -> { where.not(group_id: nil) }
diff --git a/app/models/concerns/redis_cacheable.rb b/app/models/concerns/redis_cacheable.rb
index 2d4ed51ce3b..f1d29ad5a90 100644
--- a/app/models/concerns/redis_cacheable.rb
+++ b/app/models/concerns/redis_cacheable.rb
@@ -26,8 +26,8 @@ module RedisCacheable
end
def cache_attributes(values)
- Gitlab::Redis::Cache.with do |redis|
- redis.set(cache_attribute_key, values.to_json, ex: CACHED_ATTRIBUTES_EXPIRY_TIME)
+ with_redis do |redis|
+ redis.set(cache_attribute_key, Gitlab::Json.dump(values), ex: CACHED_ATTRIBUTES_EXPIRY_TIME)
end
clear_memoization(:cached_attributes)
@@ -41,13 +41,17 @@ module RedisCacheable
def cached_attributes
strong_memoize(:cached_attributes) do
- Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
data = redis.get(cache_attribute_key)
Gitlab::Json.parse(data, symbolize_names: true) if data
end
end
end
+ def with_redis(&block)
+ Gitlab::Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord
+ end
+
def cast_value_from_cache(attribute, value)
self.class.type_for_attribute(attribute.to_s).cast(value)
end
diff --git a/app/models/concerns/repository_storage_movable.rb b/app/models/concerns/repository_storage_movable.rb
index b7fd52ab305..87ff413f2c1 100644
--- a/app/models/concerns/repository_storage_movable.rb
+++ b/app/models/concerns/repository_storage_movable.rb
@@ -19,9 +19,7 @@ module RepositoryStorageMovable
inclusion: { in: ->(_) { Gitlab.config.repositories.storages.keys } }
validate :container_repository_writable, on: :create
- default_value_for(:destination_storage_name, allows_nil: false) do
- Repository.pick_storage_shard
- end
+ attribute :destination_storage_name, default: -> { Repository.pick_storage_shard }
state_machine initial: :initial do
event :schedule do
diff --git a/app/models/concerns/subquery.rb b/app/models/concerns/subquery.rb
new file mode 100644
index 00000000000..ae92d2137c1
--- /dev/null
+++ b/app/models/concerns/subquery.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+# Distinguish between a top level query and a subselect.
+#
+# Retrieve column values when the relation has already been loaded, otherwise reselect the relation.
+# Useful for preload query patterns where the typical Rails #preload does not fit. Such as:
+#
+# projects = Project.where(...)
+# projects.load
+# ...
+# options[members] = ProjectMember.where(...).where(source_id: projects.select(:id))
+module Subquery
+ extend ActiveSupport::Concern
+
+ class_methods do
+ def subquery(*column_names, max_limit: 5_000)
+ if current_scope.loaded? && current_scope.size <= max_limit
+ current_scope.pluck(*column_names)
+ else
+ current_scope.reselect(*column_names)
+ end
+ end
+ end
+end
diff --git a/app/models/concerns/ttl_expirable.rb b/app/models/concerns/ttl_expirable.rb
index 1c2147beedd..d09ce4873b1 100644
--- a/app/models/concerns/ttl_expirable.rb
+++ b/app/models/concerns/ttl_expirable.rb
@@ -4,8 +4,8 @@ module TtlExpirable
extend ActiveSupport::Concern
included do
+ attribute :read_at, default: -> { Time.zone.now }
validates :status, presence: true
- default_value_for :read_at, Time.zone.now
enum status: { default: 0, pending_destruction: 1, processing: 2, error: 3 }
diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb
index 14520b2da26..7da4e31b472 100644
--- a/app/models/container_repository.rb
+++ b/app/models/container_repository.rb
@@ -6,6 +6,7 @@ class ContainerRepository < ApplicationRecord
include EachBatch
include Sortable
include AfterCommitQueue
+ include Packages::Destructible
WAITING_CLEANUP_STATUSES = %i[cleanup_scheduled cleanup_unfinished].freeze
REQUIRING_CLEANUP_STATUSES = %i[cleanup_unscheduled cleanup_scheduled].freeze
@@ -34,7 +35,7 @@ class ContainerRepository < ApplicationRecord
numericality: { greater_than_or_equal_to: 0 },
allow_nil: false
- enum status: { delete_scheduled: 0, delete_failed: 1 }
+ enum status: { delete_scheduled: 0, delete_failed: 1, delete_ongoing: 2 }
enum expiration_policy_cleanup_status: { cleanup_unscheduled: 0, cleanup_scheduled: 1, cleanup_unfinished: 2, cleanup_ongoing: 3 }
enum migration_skipped_reason: {
@@ -69,6 +70,7 @@ class ContainerRepository < ApplicationRecord
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_delete_at, ->(threshold) { where('delete_started_at < ?', threshold) }
scope :import_in_process, -> { where(migration_state: %w[pre_importing pre_import_done importing]) }
scope :recently_done_migration_step, -> do
@@ -224,6 +226,13 @@ class ContainerRepository < ApplicationRecord
end
end
+ # Container Repository model and the code that makes API calls
+ # are tied. Sometimes (mainly in Geo) we need to work with Registry
+ # when Container Repository record doesn't even exist.
+ # The ability to create a not-persisted record with a certain "path" parameter
+ # is very useful
+ attr_writer :path
+
def self.exists_by_path?(path)
where(
project: path.repository_project,
@@ -278,6 +287,10 @@ class ContainerRepository < ApplicationRecord
all
end
+ class << self
+ alias_method :pending_destruction, :delete_scheduled # needed by Packages::Destructible
+ end
+
def skip_import(reason:)
self.migration_skipped_reason = reason
@@ -507,6 +520,14 @@ class ContainerRepository < ApplicationRecord
end
end
+ def set_delete_ongoing_status
+ update_columns(status: :delete_ongoing, delete_started_at: Time.zone.now)
+ end
+
+ def set_delete_scheduled_status
+ update_columns(status: :delete_scheduled, delete_started_at: nil)
+ end
+
def migration_in_active_state?
migration_state.in?(ACTIVE_MIGRATION_STATES)
end
diff --git a/app/models/cycle_analytics/project_level_stage_adapter.rb b/app/models/cycle_analytics/project_level_stage_adapter.rb
index 5538e93a39e..9b9c0822f63 100644
--- a/app/models/cycle_analytics/project_level_stage_adapter.rb
+++ b/app/models/cycle_analytics/project_level_stage_adapter.rb
@@ -4,7 +4,7 @@
# compatible with the old value stream controller actions.
module CycleAnalytics
class ProjectLevelStageAdapter
- ProjectLevelStage = Struct.new(:title, :description, :legend, :name, :project_median, keyword_init: true )
+ ProjectLevelStage = Struct.new(:title, :description, :legend, :name, :project_median, keyword_init: true)
def initialize(stage, options)
@stage = stage
diff --git a/app/models/dependency_proxy/group_setting.rb b/app/models/dependency_proxy/group_setting.rb
index bcf09b27129..3a7ae66a263 100644
--- a/app/models/dependency_proxy/group_setting.rb
+++ b/app/models/dependency_proxy/group_setting.rb
@@ -3,7 +3,7 @@
class DependencyProxy::GroupSetting < ApplicationRecord
belongs_to :group
- validates :group, presence: true
+ attribute :enabled, default: true
- default_value_for :enabled, true
+ validates :group, presence: true
end
diff --git a/app/models/deploy_token.rb b/app/models/deploy_token.rb
index 20d19ec9541..66d1ce01814 100644
--- a/app/models/deploy_token.rb
+++ b/app/models/deploy_token.rb
@@ -13,7 +13,7 @@ class DeployToken < ApplicationRecord
GITLAB_DEPLOY_TOKEN_NAME = 'gitlab-deploy-token'
REQUIRED_DEPENDENCY_PROXY_SCOPES = %i[read_registry write_registry].freeze
- default_value_for(:expires_at) { Forever.date }
+ attribute :expires_at, default: -> { Forever.date }
# Do NOT use this `user` for the authentication/authorization of the deploy tokens.
# It's for the auditing purpose on Credential Inventory, only.
diff --git a/app/models/deployment.rb b/app/models/deployment.rb
index 20841bc14cd..ea92b978d3a 100644
--- a/app/models/deployment.rb
+++ b/app/models/deployment.rb
@@ -306,8 +306,8 @@ class Deployment < ApplicationRecord
last_deployment_id = environment.last_deployment&.id
return false unless last_deployment_id.present?
-
return false if self.id == last_deployment_id
+ return false if self.sha == environment.last_deployment&.sha
self.id < last_deployment_id
end
@@ -439,8 +439,9 @@ class Deployment < ApplicationRecord
end
# default tag limit is 100, 0 means no limit
+ # when refs_by_oid is passed an SHA, returns refs for that commit
def tags(limit: 100)
- project.repository.tag_names_contains(sha, limit: limit)
+ project.repository.refs_by_oid(oid: sha, limit: limit, ref_patterns: [Gitlab::Git::TAG_REF_PREFIX]) || []
end
strong_memoize_attr :tags
diff --git a/app/models/diff_discussion.rb b/app/models/diff_discussion.rb
index f4d665cf279..041ec98ffc9 100644
--- a/app/models/diff_discussion.rb
+++ b/app/models/diff_discussion.rb
@@ -37,18 +37,18 @@ class DiffDiscussion < Discussion
def reply_attributes
super.merge(
- original_position: original_position.to_json,
- position: position.to_json
+ original_position: Gitlab::Json.dump(original_position),
+ position: Gitlab::Json.dump(position)
)
end
def cache_key
- positions_json = diff_note_positions.map { |dnp| dnp.position.to_json }
+ positions_json = diff_note_positions.map { |dnp| Gitlab::Json.dump(dnp.position) }
positions_sha = Digest::SHA1.hexdigest(positions_json.join(':')) if positions_json.any?
[
super,
- Digest::SHA1.hexdigest(position.to_json),
+ Digest::SHA1.hexdigest(Gitlab::Json.dump(position)),
positions_sha
].join(':')
end
diff --git a/app/models/diff_viewer/server_side.rb b/app/models/diff_viewer/server_side.rb
index a1defb2594f..fb127de2bc7 100644
--- a/app/models/diff_viewer/server_side.rb
+++ b/app/models/diff_viewer/server_side.rb
@@ -9,14 +9,6 @@ module DiffViewer
self.size_limit = 5.megabytes
end
- def prepare!
- return if Feature.enabled?(:disable_load_entire_blob_for_diff_viewer, diff_file.repository.project)
-
- # TODO: remove this after resolving #342703
- diff_file.old_blob&.load_all_data!
- diff_file.new_blob&.load_all_data!
- end
-
def render_error
# Files that are not stored in the repository, like LFS files and
# build artifacts, can only be rendered using a client-side viewer,
diff --git a/app/models/error_tracking/project_error_tracking_setting.rb b/app/models/error_tracking/project_error_tracking_setting.rb
index 12d73ef0d72..1c7a8d93e6e 100644
--- a/app/models/error_tracking/project_error_tracking_setting.rb
+++ b/app/models/error_tracking/project_error_tracking_setting.rb
@@ -104,18 +104,9 @@ module ErrorTracking
api_host
end
- def sentry_response_limit_enabled?
- Feature.enabled?(:error_tracking_sentry_limit, project)
- end
-
- def reactive_cache_limit_enabled?
- sentry_response_limit_enabled?
- end
-
def sentry_client
strong_memoize(:sentry_client) do
- ::ErrorTracking::SentryClient
- .new(api_url, token, validate_size_guarded_by_feature_flag: sentry_response_limit_enabled?)
+ ::ErrorTracking::SentryClient.new(api_url, token)
end
end
diff --git a/app/models/event.rb b/app/models/event.rb
index 4c1793d3f13..a1417db3410 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -358,7 +358,7 @@ class Event < ApplicationRecord
# hence we add the extra WHERE clause for last_activity_at.
Project.unscoped.where(id: project_id)
.where('last_activity_at <= ?', RESET_PROJECT_ACTIVITY_INTERVAL.ago)
- .touch_all(:last_activity_at, time: created_at) # rubocop: disable Rails/SkipsModelValidations
+ .touch_all(:last_activity_at, time: created_at)
Gitlab::InactiveProjectsDeletionWarningTracker.new(project.id).reset
end
@@ -441,7 +441,7 @@ class Event < ApplicationRecord
def set_last_repository_updated_at
Project.unscoped.where(id: project_id)
.where("last_repository_updated_at < ? OR last_repository_updated_at IS NULL", REPOSITORY_UPDATED_AT_INTERVAL.ago)
- .touch_all(:last_repository_updated_at, time: created_at) # rubocop: disable Rails/SkipsModelValidations
+ .touch_all(:last_repository_updated_at, time: created_at)
end
def design_action_names
diff --git a/app/models/event_collection.rb b/app/models/event_collection.rb
index 4258027aa56..72e1d28a297 100644
--- a/app/models/event_collection.rb
+++ b/app/models/event_collection.rb
@@ -62,21 +62,12 @@ class EventCollection
end
def in_operator_optimized_relation(parent_column, parents, parent_model)
- query_builder_params = if Feature.enabled?(:optimized_project_and_group_activity_queries)
- array_data = {
- scope_ids: parents.pluck(:id),
- scope_model: parent_model,
- mapping_column: parent_column
- }
- filter.in_operator_query_builder_params(array_data)
- else
- {
- scope: filtered_events,
- array_scope: parents.select(:id),
- array_mapping_scope: -> (parent_id_expression) { Event.where(Event.arel_table[parent_column].eq(parent_id_expression)).reorder(id: :desc) },
- finder_query: -> (id_expression) { Event.where(Event.arel_table[:id].eq(id_expression)) }
- }
- end
+ array_data = {
+ scope_ids: parents.pluck(:id),
+ scope_model: parent_model,
+ mapping_column: parent_column
+ }
+ query_builder_params = filter.in_operator_query_builder_params(array_data)
Gitlab::Pagination::Keyset::InOperatorOptimization::QueryBuilder
.new(**query_builder_params)
@@ -84,10 +75,6 @@ class EventCollection
.limit(@limit + @offset)
end
- def filtered_events
- filter.apply_filter(base_relation)
- end
-
def paginate_events(events)
events.limit(@limit).offset(@offset)
end
diff --git a/app/models/experiment.rb b/app/models/experiment.rb
deleted file mode 100644
index 2300ec2996d..00000000000
--- a/app/models/experiment.rb
+++ /dev/null
@@ -1,77 +0,0 @@
-# frozen_string_literal: true
-
-class Experiment < ApplicationRecord
- has_many :experiment_users
- has_many :experiment_subjects, inverse_of: :experiment
-
- validates :name, presence: true, uniqueness: true, length: { maximum: 255 }
-
- def self.add_user(name, group_type, user, context = {})
- by_name(name).record_user_and_group(user, group_type, context)
- end
-
- def self.add_group(name, variant:, group:)
- add_subject(name, variant: variant, subject: group)
- end
-
- def self.add_subject(name, variant:, subject:)
- by_name(name).record_subject_and_variant!(subject, variant)
- end
-
- def self.record_conversion_event(name, user, context = {})
- by_name(name).record_conversion_event_for_user(user, context)
- end
-
- def self.by_name(name)
- find_or_create_by!(name: name)
- end
-
- # Create or update the recorded experiment_user row for the user in this experiment.
- def record_user_and_group(user, group_type, context = {})
- experiment_user = experiment_users.find_or_initialize_by(user: user)
- experiment_user.assign_attributes(group_type: group_type, context: merged_context(experiment_user, context))
- # We only call save when necessary because this causes the request to stick to the primary DB
- # even when the save is a no-op
- # https://gitlab.com/gitlab-org/gitlab/-/issues/324649
- experiment_user.save! if experiment_user.changed?
-
- experiment_user
- end
-
- def record_conversion_event_for_user(user, context = {})
- experiment_user = experiment_users.find_by(user: user)
- return unless experiment_user
-
- experiment_user.update!(converted_at: Time.current, context: merged_context(experiment_user, context))
- end
-
- def record_conversion_event_for_subject(subject, context = {})
- raise 'Incompatible subject provided!' unless ExperimentSubject.valid_subject?(subject)
-
- attr_name = subject.class.table_name.singularize.to_sym
- experiment_subject = experiment_subjects.find_by(attr_name => subject)
- return unless experiment_subject
-
- experiment_subject.update!(converted_at: Time.current, context: merged_context(experiment_subject, context))
- end
-
- def record_subject_and_variant!(subject, variant)
- raise 'Incompatible subject provided!' unless ExperimentSubject.valid_subject?(subject)
-
- attr_name = subject.class.table_name.singularize.to_sym
- experiment_subject = experiment_subjects.find_or_initialize_by(attr_name => subject)
- experiment_subject.assign_attributes(variant: variant)
- # We only call save when necessary because this causes the request to stick to the primary DB
- # even when the save is a no-op
- # https://gitlab.com/gitlab-org/gitlab/-/issues/324649
- experiment_subject.save! if experiment_subject.changed?
-
- experiment_subject
- end
-
- private
-
- def merged_context(experiment_subject, new_context)
- experiment_subject.context.deep_merge(new_context.deep_stringify_keys)
- end
-end
diff --git a/app/models/experiment_subject.rb b/app/models/experiment_subject.rb
deleted file mode 100644
index 2a7b9017a51..00000000000
--- a/app/models/experiment_subject.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-class ExperimentSubject < ApplicationRecord
- include ::Gitlab::Experimentation::GroupTypes
-
- belongs_to :experiment, inverse_of: :experiment_subjects
- belongs_to :user
- belongs_to :namespace
- belongs_to :project
-
- validates :experiment, presence: true
- validates :variant, presence: true
- validate :must_have_one_subject_present
-
- enum variant: { GROUP_CONTROL => 0, GROUP_EXPERIMENTAL => 1 }
-
- def self.valid_subject?(subject)
- subject.is_a?(Namespace) || subject.is_a?(User) || subject.is_a?(Project)
- end
-
- private
-
- def must_have_one_subject_present
- if non_nil_subjects.length != 1
- errors.add(:base, s_("ExperimentSubject|Must have exactly one of User, Namespace, or Project."))
- end
- end
-
- def non_nil_subjects
- @non_nil_subjects ||= [user, namespace, project].reject(&:blank?)
- end
-end
diff --git a/app/models/experiment_user.rb b/app/models/experiment_user.rb
deleted file mode 100644
index e447becc1bd..00000000000
--- a/app/models/experiment_user.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-class ExperimentUser < ApplicationRecord
- include ::Gitlab::Experimentation::GroupTypes
-
- belongs_to :experiment
- belongs_to :user
-
- enum group_type: { GROUP_CONTROL => 0, GROUP_EXPERIMENTAL => 1 }
-
- validates :experiment_id, presence: true
- validates :user_id, presence: true
- validates :group_type, presence: true
-end
diff --git a/app/models/group.rb b/app/models/group.rb
index 38623d91705..098116ed800 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -119,6 +119,8 @@ class Group < Namespace
has_many :group_callouts, class_name: 'Users::GroupCallout', foreign_key: :group_id
+ has_many :protected_branches, inverse_of: :group
+
has_one :group_feature, inverse_of: :group, class_name: 'Groups::FeatureSetting'
delegate :prevent_sharing_groups_outside_hierarchy, :new_user_signups_cap, :setup_for_company, :jobs_to_be_done, to: :namespace_settings
@@ -465,9 +467,10 @@ class Group < Namespace
end
# Check if user is a last owner of the group.
+ # Excludes non-direct owners for top-level group
# Excludes project_bots
def last_owner?(user)
- has_owner?(user) && all_owners_excluding_project_bots.size == 1
+ has_owner?(user) && member_owners_excluding_project_bots.size == 1
end
def member_last_owner?(member)
@@ -476,8 +479,14 @@ class Group < Namespace
last_owner?(member.user)
end
- def all_owners_excluding_project_bots
- members_with_parents.owners.merge(User.without_project_bot)
+ # Excludes non-direct owners for top-level group
+ # Excludes project_bots
+ def member_owners_excluding_project_bots
+ if root?
+ members
+ else
+ members_with_parents
+ end.owners.merge(User.without_project_bot)
end
def single_blocked_owner?
@@ -487,7 +496,7 @@ class Group < Namespace
def member_last_blocked_owner?(member)
return member.last_blocked_owner unless member.last_blocked_owner.nil?
- return false if members_with_parents.owners.any?
+ return false if member_owners_excluding_project_bots.any?
single_blocked_owner? && blocked_owners.exists?(user_id: member.user)
end
@@ -1010,10 +1019,6 @@ class Group < Namespace
Arel::Nodes::SqlLiteral.new(column_alias))
end
- def self.groups_including_descendants_by(group_ids)
- Group.where(id: group_ids).self_and_descendants
- end
-
def disable_shared_runners!
update!(
shared_runners_enabled: false,
diff --git a/app/models/hooks/active_hook_filter.rb b/app/models/hooks/active_hook_filter.rb
index 283e2d680f4..cdcfd3f3ff5 100644
--- a/app/models/hooks/active_hook_filter.rb
+++ b/app/models/hooks/active_hook_filter.rb
@@ -3,14 +3,36 @@
class ActiveHookFilter
def initialize(hook)
@hook = hook
- @push_events_filter_matcher = RefMatcher.new(@hook.push_events_branch_filter)
end
def matches?(hooks_scope, data)
- return true if hooks_scope != :push_hooks
+ return true unless hooks_scope == :push_hooks
+
+ matches_branch?(data)
+ end
+
+ private
+
+ def matches_branch?(data)
return true if @hook.push_events_branch_filter.blank?
branch_name = Gitlab::Git.branch_name(data[:ref])
- @push_events_filter_matcher.matches?(branch_name)
+
+ if Feature.disabled?(:enhanced_webhook_support_regex)
+ return RefMatcher.new(@hook.push_events_branch_filter).matches?(branch_name)
+ end
+
+ case @hook.branch_filter_strategy
+ when 'all_branches'
+ true
+ when 'wildcard'
+ RefMatcher.new(@hook.push_events_branch_filter).matches?(branch_name)
+ when 'regex'
+ begin
+ Gitlab::UntrustedRegexp.new(@hook.push_events_branch_filter) === branch_name
+ rescue RegexpError
+ false
+ end
+ end
end
end
diff --git a/app/models/hooks/system_hook.rb b/app/models/hooks/system_hook.rb
index c0073f9a9b8..3c7f0ef9ffc 100644
--- a/app/models/hooks/system_hook.rb
+++ b/app/models/hooks/system_hook.rb
@@ -10,9 +10,9 @@ class SystemHook < WebHook
:merge_request_hooks
]
- default_value_for :push_events, false
- default_value_for :repository_update_events, true
- default_value_for :merge_requests_events, false
+ attribute :push_events, default: false
+ attribute :repository_update_events, default: true
+ attribute :merge_requests_events, default: false
validates :url, system_hook_url: true
diff --git a/app/models/hooks/web_hook.rb b/app/models/hooks/web_hook.rb
index 71794964c99..05e50c17988 100644
--- a/app/models/hooks/web_hook.rb
+++ b/app/models/hooks/web_hook.rb
@@ -7,9 +7,11 @@ class WebHook < ApplicationRecord
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,
mode: :per_attribute_iv,
@@ -33,14 +35,26 @@ class WebHook < ApplicationRecord
has_many :web_hook_logs
validates :url, presence: true
- validates :url, public_url: true, unless: ->(hook) { hook.is_a?(SystemHook) }
+ validates :url, public_url: true, unless: ->(hook) { hook.is_a?(SystemHook) || hook.url_variables? }
validates :token, format: { without: /\n/ }
- validates :push_events_branch_filter, branch_filter: true
+ after_initialize :initialize_url_variables
+ before_validation :set_branch_filter_nil, \
+ if: -> { branch_filter_strategy_all_branches? && enhanced_webhook_support_regex? }
+ validates :push_events_branch_filter, \
+ untrusted_regexp: true, if: -> { branch_filter_strategy_regex? && enhanced_webhook_support_regex? }
+ validates :push_events_branch_filter, \
+ "web_hooks/wildcard_branch_filter": true, if: -> { branch_filter_strategy_wildcard? }
+
validates :url_variables, json_schema: { filename: 'web_hooks_url_variables' }
validate :no_missing_url_variables
+ validates :interpolated_url, public_url: true, if: ->(hook) { hook.url_variables? && hook.errors.empty? }
- after_initialize :initialize_url_variables
+ enum branch_filter_strategy: {
+ wildcard: 0,
+ regex: 1,
+ all_branches: 2
+ }, _prefix: true
scope :executable, -> do
next all unless Feature.enabled?(:web_hooks_disable_failed)
@@ -108,7 +122,7 @@ class WebHook < ApplicationRecord
def disable!
return if permanently_disabled?
- update_attribute(:recent_failures, FAILURE_THRESHOLD + 1)
+ update_attribute(:recent_failures, EXCEEDED_FAILURE_THRESHOLD)
end
def enable!
@@ -123,10 +137,10 @@ class WebHook < ApplicationRecord
def backoff!
return if permanently_disabled? || (backoff_count >= MAX_FAILURES && temporarily_disabled?)
- attrs = { recent_failures: recent_failures + 1 }
+ attrs = { recent_failures: next_failure_count }
if recent_failures >= FAILURE_THRESHOLD
- attrs[:backoff_count] = backoff_count.succ.clamp(1, MAX_FAILURES)
+ attrs[:backoff_count] = next_backoff_count
attrs[:disabled_until] = next_backoff.from_now
end
@@ -137,7 +151,7 @@ class WebHook < ApplicationRecord
def failed!
return unless recent_failures < MAX_FAILURES
- assign_attributes(disabled_until: nil, backoff_count: 0, recent_failures: recent_failures + 1)
+ assign_attributes(disabled_until: nil, backoff_count: 0, recent_failures: next_failure_count)
save(validate: false)
end
@@ -198,8 +212,20 @@ class WebHook < ApplicationRecord
# Overridden in child classes.
end
+ def masked_token
+ token.present? ? SECRET_MASK : nil
+ 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
+
def web_hooks_disable_failed?
self.class.web_hooks_disable_failed?(self)
end
@@ -224,4 +250,12 @@ class WebHook < ApplicationRecord
errors.add(:url, "Invalid URL template. Missing keys: #{missing}")
end
+
+ def enhanced_webhook_support_regex?
+ Feature.enabled?(:enhanced_webhook_support_regex)
+ end
+
+ def set_branch_filter_nil
+ self.push_events_branch_filter = nil
+ end
end
diff --git a/app/models/hooks/web_hook_log.rb b/app/models/hooks/web_hook_log.rb
index c32957fbef9..2b26147b494 100644
--- a/app/models/hooks/web_hook_log.rb
+++ b/app/models/hooks/web_hook_log.rb
@@ -56,7 +56,7 @@ class WebHookLog < ApplicationRecord
def redact_user_emails
self.request_data.deep_transform_values! do |value|
- value =~ URI::MailTo::EMAIL_REGEXP ? _('[REDACTED]') : value
+ value.to_s =~ URI::MailTo::EMAIL_REGEXP ? _('[REDACTED]') : value
end
end
end
diff --git a/app/models/incident_management/timeline_event.rb b/app/models/incident_management/timeline_event.rb
index 735d4e4298c..e70209f1538 100644
--- a/app/models/incident_management/timeline_event.rb
+++ b/app/models/incident_management/timeline_event.rb
@@ -18,6 +18,8 @@ module IncidentManagement
validates :project, :incident, :occurred_at, presence: true
validates :action, presence: true, length: { maximum: 128 }
+ # `user_input` is a note filled in by a user via API. Not auto generated by GitLab
+ validates :note, presence: true, length: { maximum: 280 }, on: :user_input
validates :note, presence: true, length: { maximum: 10_000 }
validates :note_html, length: { maximum: 10_000 }
diff --git a/app/models/incident_management/timeline_event_tag.rb b/app/models/incident_management/timeline_event_tag.rb
index cde3afcaa16..d1e3fbc2a6a 100644
--- a/app/models/incident_management/timeline_event_tag.rb
+++ b/app/models/incident_management/timeline_event_tag.rb
@@ -4,6 +4,9 @@ module IncidentManagement
class TimelineEventTag < ApplicationRecord
self.table_name = 'incident_management_timeline_event_tags'
+ START_TIME_TAG_NAME = 'Start time'
+ END_TIME_TAG_NAME = 'End time'
+
belongs_to :project, inverse_of: :incident_management_timeline_event_tags
has_many :timeline_event_tag_links,
@@ -14,7 +17,13 @@ module IncidentManagement
through: :timeline_event_tag_links
validates :name, presence: true, format: { with: /\A[^,]+\z/ }
- validates :name, uniqueness: { scope: :project_id }
+ validates :name, uniqueness: { scope: :project_id, case_sensitive: false }
validates :name, length: { maximum: 255 }
+
+ scope :by_names, -> (tag_names) { where('lower(name) in (?)', tag_names.map(&:downcase)) }
+
+ def self.pluck_names
+ pluck(:name)
+ end
end
end
diff --git a/app/models/instance_metadata.rb b/app/models/instance_metadata.rb
index 6cac78178e0..47460c85671 100644
--- a/app/models/instance_metadata.rb
+++ b/app/models/instance_metadata.rb
@@ -1,11 +1,12 @@
# frozen_string_literal: true
class InstanceMetadata
- attr_reader :version, :revision, :kas
+ attr_reader :version, :revision, :kas, :enterprise
- def initialize(version: Gitlab::VERSION, revision: Gitlab.revision)
+ def initialize(version: Gitlab::VERSION, revision: Gitlab.revision, enterprise: Gitlab.ee?)
@version = version
@revision = revision
@kas = ::InstanceMetadata::Kas.new
+ @enterprise = enterprise
end
end
diff --git a/app/models/integration.rb b/app/models/integration.rb
index 23688a87cbd..41278dce22d 100644
--- a/app/models/integration.rb
+++ b/app/models/integration.rb
@@ -71,20 +71,20 @@ class Integration < ApplicationRecord
alias_attribute :type, :type_new
- default_value_for :active, false
- default_value_for :alert_events, true
- default_value_for :category, 'common'
- default_value_for :commit_events, true
- default_value_for :confidential_issues_events, true
- default_value_for :confidential_note_events, true
- default_value_for :issues_events, true
- default_value_for :job_events, true
- default_value_for :merge_requests_events, true
- default_value_for :note_events, true
- default_value_for :pipeline_events, true
- default_value_for :push_events, true
- default_value_for :tag_push_events, true
- default_value_for :wiki_page_events, true
+ attribute :active, default: false
+ attribute :alert_events, default: true
+ attribute :category, default: 'common'
+ attribute :commit_events, default: true
+ attribute :confidential_issues_events, default: true
+ attribute :confidential_note_events, default: true
+ attribute :issues_events, default: true
+ attribute :job_events, default: true
+ attribute :merge_requests_events, default: true
+ attribute :note_events, default: true
+ attribute :pipeline_events, default: true
+ attribute :push_events, default: true
+ attribute :tag_push_events, default: true
+ attribute :wiki_page_events, default: true
after_initialize :initialize_properties
@@ -589,6 +589,10 @@ class Integration < ApplicationRecord
false
end
+ def chat?
+ category == :chat
+ end
+
private
# Ancestors sorted by hierarchy depth in bottom-top order.
diff --git a/app/models/integrations/assembla.rb b/app/models/integrations/assembla.rb
index 88dbf2915ef..536d5584bf6 100644
--- a/app/models/integrations/assembla.rb
+++ b/app/models/integrations/assembla.rb
@@ -12,6 +12,7 @@ module Integrations
required: true
field :subdomain,
+ exposes_secrets: true,
placeholder: ''
def title
@@ -34,7 +35,9 @@ module Integrations
return unless supported_events.include?(data[:object_kind])
url = "https://atlas.assembla.com/spaces/#{subdomain}/github_tool?secret_key=#{token}"
- Gitlab::HTTP.post(url, body: { payload: data }.to_json, headers: { 'Content-Type' => 'application/json' })
+ body = { payload: data }
+
+ Gitlab::HTTP.post(url, body: Gitlab::Json.dump(body), headers: { 'Content-Type' => 'application/json' })
end
end
end
diff --git a/app/models/integrations/bamboo.rb b/app/models/integrations/bamboo.rb
index c3a4b84bb2d..b4e97f0871e 100644
--- a/app/models/integrations/bamboo.rb
+++ b/app/models/integrations/bamboo.rb
@@ -9,6 +9,7 @@ module Integrations
title: -> { s_('BambooService|Bamboo URL') },
placeholder: -> { s_('https://bamboo.example.com') },
help: -> { s_('BambooService|Bamboo service root URL.') },
+ exposes_secrets: true,
required: true
field :build_key,
@@ -37,14 +38,6 @@ module Integrations
attr_accessor :response
- before_validation :reset_password
-
- def reset_password
- if bamboo_url_changed? && !password_touched?
- self.password = nil
- end
- end
-
def title
s_('BambooService|Atlassian Bamboo')
end
diff --git a/app/models/integrations/base_chat_notification.rb b/app/models/integrations/base_chat_notification.rb
index c7992e4083c..750aa60b185 100644
--- a/app/models/integrations/base_chat_notification.rb
+++ b/app/models/integrations/base_chat_notification.rb
@@ -22,7 +22,9 @@ module Integrations
MATCH_ALL_LABELS = 'match_all'
].freeze
- default_value_for :category, 'chat'
+ SECRET_MASK = '************'
+
+ attribute :category, default: 'chat'
prop_accessor :webhook, :username, :channel, :branches_to_be_notified, :labels_to_be_notified, :labels_to_be_notified_behavior
@@ -71,7 +73,7 @@ module Integrations
def default_fields
[
- { type: 'text', name: 'webhook', placeholder: "#{webhook_placeholder}", required: true }.freeze,
+ { type: 'text', name: 'webhook', help: "#{webhook_help}", required: true }.freeze,
{ type: 'text', name: 'username', placeholder: 'GitLab-integration' }.freeze,
{ type: 'checkbox', name: 'notify_only_broken_pipelines', help: 'Do not send notifications for successful pipelines.' }.freeze,
{
@@ -147,7 +149,7 @@ module Integrations
raise NotImplementedError
end
- def webhook_placeholder
+ def webhook_help
raise NotImplementedError
end
diff --git a/app/models/integrations/base_ci.rb b/app/models/integrations/base_ci.rb
index 4f8732da703..db29f228e60 100644
--- a/app/models/integrations/base_ci.rb
+++ b/app/models/integrations/base_ci.rb
@@ -5,7 +5,7 @@
# working with GitLab merge requests
module Integrations
class BaseCi < Integration
- default_value_for :category, 'ci'
+ attribute :category, default: 'ci'
def valid_token?(token)
self.respond_to?(:token) && self.token.present? && ActiveSupport::SecurityUtils.secure_compare(token, self.token)
diff --git a/app/models/integrations/base_issue_tracker.rb b/app/models/integrations/base_issue_tracker.rb
index a4cec5f927b..e0994305e9d 100644
--- a/app/models/integrations/base_issue_tracker.rb
+++ b/app/models/integrations/base_issue_tracker.rb
@@ -4,7 +4,7 @@ module Integrations
class BaseIssueTracker < Integration
validate :one_issue_tracker, if: :activated?, on: :manual_change
- default_value_for :category, 'issue_tracker'
+ attribute :category, default: 'issue_tracker'
before_validation :handle_properties
before_validation :set_default_data, on: :create
diff --git a/app/models/integrations/base_monitoring.rb b/app/models/integrations/base_monitoring.rb
index 280eeda7c6c..b0bebb5a859 100644
--- a/app/models/integrations/base_monitoring.rb
+++ b/app/models/integrations/base_monitoring.rb
@@ -6,7 +6,7 @@
# to provide additional features for environments.
module Integrations
class BaseMonitoring < Integration
- default_value_for :category, 'monitoring'
+ attribute :category, default: 'monitoring'
def self.supported_events
%w()
diff --git a/app/models/integrations/base_slack_notification.rb b/app/models/integrations/base_slack_notification.rb
new file mode 100644
index 00000000000..cb785afdcfe
--- /dev/null
+++ b/app/models/integrations/base_slack_notification.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+module Integrations
+ class BaseSlackNotification < BaseChatNotification
+ SUPPORTED_EVENTS_FOR_USAGE_LOG = %w[
+ push issue confidential_issue merge_request note confidential_note tag_push wiki_page deployment
+ ].freeze
+
+ prop_accessor EVENT_CHANNEL['alert']
+
+ override :default_channel_placeholder
+ def default_channel_placeholder
+ _('#general, #development')
+ end
+
+ override :get_message
+ def get_message(object_kind, data)
+ return Integrations::ChatMessage::AlertMessage.new(data) if object_kind == 'alert'
+
+ super
+ end
+
+ override :supported_events
+ def supported_events
+ additional = ['alert']
+
+ super + additional
+ end
+
+ override :configurable_channels?
+ def configurable_channels?
+ true
+ end
+
+ override :log_usage
+ def log_usage(event, user_id)
+ return unless user_id
+
+ return unless SUPPORTED_EVENTS_FOR_USAGE_LOG.include?(event)
+
+ key = "i_ecosystem_slack_service_#{event}_notification"
+
+ 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
+ }.compact
+
+ Gitlab::Tracking.event(
+ self.class.name,
+ Integration::SNOWPLOW_EVENT_ACTION,
+ label: Integration::SNOWPLOW_EVENT_LABEL,
+ property: key,
+ user: User.find(user_id),
+ **optional_arguments
+ )
+ end
+ end
+end
diff --git a/app/models/integrations/base_slash_commands.rb b/app/models/integrations/base_slash_commands.rb
index e51d748b562..314f0a6ee5d 100644
--- a/app/models/integrations/base_slash_commands.rb
+++ b/app/models/integrations/base_slash_commands.rb
@@ -4,7 +4,7 @@
# This class is not meant to be used directly, but only to inherrit from.
module Integrations
class BaseSlashCommands < Integration
- default_value_for :category, 'chat'
+ attribute :category, default: 'chat'
prop_accessor :token
diff --git a/app/models/integrations/base_third_party_wiki.rb b/app/models/integrations/base_third_party_wiki.rb
index 24f5bec93cf..8df172e9a53 100644
--- a/app/models/integrations/base_third_party_wiki.rb
+++ b/app/models/integrations/base_third_party_wiki.rb
@@ -2,7 +2,7 @@
module Integrations
class BaseThirdPartyWiki < Integration
- default_value_for :category, 'third_party_wiki'
+ attribute :category, default: 'third_party_wiki'
validate :only_one_third_party_wiki, if: :activated?, on: :manual_change
diff --git a/app/models/integrations/buildkite.rb b/app/models/integrations/buildkite.rb
index f2d2aca3ffe..5c08eac8557 100644
--- a/app/models/integrations/buildkite.rb
+++ b/app/models/integrations/buildkite.rb
@@ -6,13 +6,13 @@ module Integrations
class Buildkite < BaseCi
include HasWebHook
include ReactivelyCached
- extend Gitlab::Utils::Override
ENDPOINT = "https://buildkite.com"
field :project_url,
title: -> { _('Pipeline URL') },
placeholder: "#{ENDPOINT}/example-org/test-pipeline",
+ exposes_secrets: true,
required: true
field :token,
diff --git a/app/models/integrations/chat_message/pipeline_message.rb b/app/models/integrations/chat_message/pipeline_message.rb
index b3502905bf7..88db40bea7f 100644
--- a/app/models/integrations/chat_message/pipeline_message.rb
+++ b/app/models/integrations/chat_message/pipeline_message.rb
@@ -126,6 +126,14 @@ module Integrations
}
end
+ def pipeline_name_field
+ {
+ title: s_("ChatMessage|Pipeline name"),
+ value: pipeline.name,
+ short: false
+ }
+ end
+
def attachments_fields
fields = [
{
@@ -143,6 +151,7 @@ module Integrations
fields << failed_stages_field if failed_stages.any?
fields << failed_jobs_field if failed_jobs.any?
fields << yaml_error_field if pipeline.has_yaml_errors?
+ fields << pipeline_name_field if Feature.enabled?(:pipeline_name, project) && pipeline.name.present?
fields
end
diff --git a/app/models/integrations/datadog.rb b/app/models/integrations/datadog.rb
index ab0fdbd777f..27bed5d3f76 100644
--- a/app/models/integrations/datadog.rb
+++ b/app/models/integrations/datadog.rb
@@ -3,7 +3,6 @@
module Integrations
class Datadog < Integration
include HasWebHook
- extend Gitlab::Utils::Override
DEFAULT_DOMAIN = 'datadoghq.com'
URL_TEMPLATE = 'https://webhook-intake.%{datadog_domain}/api/v2/webhook'
@@ -91,7 +90,7 @@ module Integrations
with_options if: :activated? do
validates :api_key, presence: true, format: { with: /\A\w+\z/ }
- validates :datadog_site, format: { with: /\A[\w\.]+\z/, allow_blank: true }
+ validates :datadog_site, format: { with: %r{\A\w+([-.]\w+)*\.[a-zA-Z]{2,5}(:[0-9]{1,5})?\z}, allow_blank: true }
validates :api_url, public_url: { allow_blank: true }
validates :datadog_site, presence: true, unless: -> (obj) { obj.api_url.present? }
validates :api_url, presence: true, unless: -> (obj) { obj.datadog_site.present? }
@@ -169,8 +168,8 @@ module Integrations
result = execute(data)
{
- success: (200..299).cover?(result[:http_status]),
- result: result[:message]
+ success: (200..299).cover?(result.payload[:http_status]),
+ result: result.message
}
end
diff --git a/app/models/integrations/discord.rb b/app/models/integrations/discord.rb
index d0389b82410..061c491034d 100644
--- a/app/models/integrations/discord.rb
+++ b/app/models/integrations/discord.rb
@@ -10,8 +10,7 @@ module Integrations
field :webhook,
section: SECTION_TYPE_CONNECTION,
- placeholder: 'https://discordapp.com/api/webhooks/…',
- help: 'URL to the webhook for the Discord channel.',
+ help: 'e.g. https://discordapp.com/api/webhooks/…',
required: true
field :notify_only_broken_pipelines,
diff --git a/app/models/integrations/drone_ci.rb b/app/models/integrations/drone_ci.rb
index d1a64aa96d4..781acf65c47 100644
--- a/app/models/integrations/drone_ci.rb
+++ b/app/models/integrations/drone_ci.rb
@@ -6,7 +6,6 @@ module Integrations
include PushDataValidations
include ReactivelyCached
prepend EnableSslVerification
- extend Gitlab::Utils::Override
DRONE_SAAS_HOSTNAME = 'cloud.drone.io'
diff --git a/app/models/integrations/hangouts_chat.rb b/app/models/integrations/hangouts_chat.rb
index 6e7f31aa030..c903e8d9eb8 100644
--- a/app/models/integrations/hangouts_chat.rb
+++ b/app/models/integrations/hangouts_chat.rb
@@ -22,10 +22,6 @@ module Integrations
def default_channel_placeholder
end
- def webhook_placeholder
- 'https://chat.googleapis.com/v1/spaces…'
- end
-
def self.supported_events
%w[push issue confidential_issue merge_request note confidential_note tag_push
pipeline wiki_page]
@@ -33,7 +29,7 @@ module Integrations
def default_fields
[
- { type: 'text', name: 'webhook', placeholder: "#{webhook_placeholder}" },
+ { type: 'text', name: 'webhook', help: 'https://chat.googleapis.com/v1/spaces…' },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' },
{
type: 'select',
diff --git a/app/models/integrations/jenkins.rb b/app/models/integrations/jenkins.rb
index 74a6449f4f9..d2e8393ef95 100644
--- a/app/models/integrations/jenkins.rb
+++ b/app/models/integrations/jenkins.rb
@@ -5,10 +5,10 @@ module Integrations
include HasWebHook
prepend EnableSslVerification
- extend Gitlab::Utils::Override
field :jenkins_url,
title: -> { s_('ProjectService|Jenkins server URL') },
+ exposes_secrets: true,
required: true,
placeholder: 'http://jenkins.example.com',
help: -> { s_('The URL of the Jenkins server.') }
@@ -27,21 +27,13 @@ module Integrations
non_empty_password_title: -> { s_('ProjectService|Enter new password.') },
non_empty_password_help: -> { s_('ProjectService|Leave blank to use your current password.') }
- before_validation :reset_password
-
validates :jenkins_url, presence: true, addressable_url: true, if: :activated?
validates :project_name, presence: true, if: :activated?
validates :username, presence: true, if: ->(service) { service.activated? && service.password_touched? && service.password.present? }
+ validates :password, presence: true, if: ->(service) { service.activated? && service.username.present? }
- default_value_for :merge_requests_events, false
- default_value_for :tag_push_events, false
-
- def reset_password
- # don't reset the password if a new one is provided
- if (jenkins_url_changed? || username.blank?) && !password_touched?
- self.password = nil
- end
- end
+ attribute :merge_requests_events, default: false
+ attribute :tag_push_events, default: false
def execute(data)
return unless supported_events.include?(data[:object_kind])
@@ -52,12 +44,12 @@ module Integrations
def test(data)
begin
result = execute(data)
- return { success: false, result: result[:message] } if result[:http_status] != 200
+ return { success: false, result: result.message } if result.payload[:http_status] != 200
rescue StandardError => e
return { success: false, result: e }
end
- { success: true, result: result[:message] }
+ { success: true, result: result.message }
end
override :hook_url
diff --git a/app/models/integrations/jira.rb b/app/models/integrations/jira.rb
index 3ca514ab1fd..30497c0110e 100644
--- a/app/models/integrations/jira.rb
+++ b/app/models/integrations/jira.rb
@@ -3,7 +3,6 @@
# Accessible as Project#external_issue_tracker
module Integrations
class Jira < BaseIssueTracker
- extend ::Gitlab::Utils::Override
include Gitlab::Routing
include ApplicationHelper
include ActionView::Helpers::AssetUrlHelper
@@ -533,13 +532,14 @@ module Integrations
end
def build_entity_meta(entity)
- if entity.is_a?(Commit)
+ case entity
+ when Commit
{
id: entity.short_id,
description: entity.safe_message,
branch: branch_name(entity)
}
- elsif entity.is_a?(MergeRequest)
+ when MergeRequest
{
id: entity.to_reference,
branch: entity.source_branch
diff --git a/app/models/integrations/mattermost.rb b/app/models/integrations/mattermost.rb
index dae11b99bc5..dd1c98ee06b 100644
--- a/app/models/integrations/mattermost.rb
+++ b/app/models/integrations/mattermost.rb
@@ -3,7 +3,6 @@
module Integrations
class Mattermost < BaseChatNotification
include SlackMattermostNotifier
- extend ::Gitlab::Utils::Override
def title
s_('Mattermost notifications')
@@ -26,7 +25,7 @@ module Integrations
'my-channel'
end
- def webhook_placeholder
+ def webhook_help
'http://mattermost.example.com/hooks/'
end
diff --git a/app/models/integrations/microsoft_teams.rb b/app/models/integrations/microsoft_teams.rb
index 69863f164cd..d6cbe5760e8 100644
--- a/app/models/integrations/microsoft_teams.rb
+++ b/app/models/integrations/microsoft_teams.rb
@@ -18,10 +18,6 @@ module Integrations
'<p>Use this service to send notifications about events in GitLab projects to your Microsoft Teams channels. <a href="https://docs.gitlab.com/ee/user/project/integrations/microsoft_teams.html" target="_blank" rel="noopener noreferrer">How do I configure this integration?</a></p>'
end
- def webhook_placeholder
- 'https://outlook.office.com/webhook/…'
- end
-
def default_channel_placeholder
end
@@ -32,7 +28,7 @@ module Integrations
def default_fields
[
- { type: 'text', section: SECTION_TYPE_CONNECTION, name: 'webhook', required: true, placeholder: "#{webhook_placeholder}" },
+ { type: 'text', section: SECTION_TYPE_CONNECTION, name: 'webhook', help: 'https://outlook.office.com/webhook/…', required: true },
{
type: 'checkbox',
section: SECTION_TYPE_CONFIGURATION,
diff --git a/app/models/integrations/packagist.rb b/app/models/integrations/packagist.rb
index 7177c82a167..7148de66aee 100644
--- a/app/models/integrations/packagist.rb
+++ b/app/models/integrations/packagist.rb
@@ -3,7 +3,6 @@
module Integrations
class Packagist < Integration
include HasWebHook
- extend Gitlab::Utils::Override
field :username,
title: -> { s_('Username') },
@@ -55,12 +54,12 @@ module Integrations
def test(data)
begin
result = execute(data)
- return { success: false, result: result[:message] } if result[:http_status] != 202
+ return { success: false, result: result.message } if result.payload[:http_status] != 202
rescue StandardError => e
- return { success: false, result: e }
+ return { success: false, result: e.message }
end
- { success: true, result: result[:message] }
+ { success: true, result: result.message }
end
override :hook_url
diff --git a/app/models/integrations/pivotaltracker.rb b/app/models/integrations/pivotaltracker.rb
index d32fb974339..1acdbbbf9bc 100644
--- a/app/models/integrations/pivotaltracker.rb
+++ b/app/models/integrations/pivotaltracker.rb
@@ -56,7 +56,7 @@ module Integrations
}
Gitlab::HTTP.post(
API_ENDPOINT,
- body: message.to_json,
+ body: Gitlab::Json.dump(message),
headers: {
'Content-Type' => 'application/json',
'X-TrackerToken' => token
diff --git a/app/models/integrations/pumble.rb b/app/models/integrations/pumble.rb
index 17026410eb1..e08dc6d0f51 100644
--- a/app/models/integrations/pumble.rb
+++ b/app/models/integrations/pumble.rb
@@ -36,7 +36,7 @@ module Integrations
def default_fields
[
- { type: 'text', name: 'webhook', placeholder: "https://api.pumble.com/workspaces/x/...", required: true },
+ { type: 'text', name: 'webhook', help: 'https://api.pumble.com/workspaces/x/...', required: true },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' },
{
type: 'select',
@@ -51,7 +51,7 @@ module Integrations
def notify(message, opts)
header = { 'Content-Type' => 'application/json' }
- response = Gitlab::HTTP.post(webhook, headers: header, body: { text: message.summary }.to_json)
+ response = Gitlab::HTTP.post(webhook, headers: header, body: Gitlab::Json.dump({ text: message.summary }))
response if response.success?
end
diff --git a/app/models/integrations/slack.rb b/app/models/integrations/slack.rb
index c254ea379bb..89326b8174f 100644
--- a/app/models/integrations/slack.rb
+++ b/app/models/integrations/slack.rb
@@ -1,17 +1,8 @@
# frozen_string_literal: true
module Integrations
- class Slack < BaseChatNotification
+ class Slack < BaseSlackNotification
include SlackMattermostNotifier
- extend ::Gitlab::Utils::Override
-
- SUPPORTED_EVENTS_FOR_USAGE_LOG = %w[
- push issue confidential_issue merge_request note confidential_note
- tag_push wiki_page deployment
- ].freeze
- SNOWPLOW_EVENT_CATEGORY = self.name
-
- prop_accessor EVENT_CHANNEL['alert']
def title
'Slack notifications'
@@ -25,57 +16,9 @@ module Integrations
'slack'
end
- def default_channel_placeholder
- _('#general, #development')
- end
-
- def webhook_placeholder
+ override :webhook_help
+ def webhook_help
'https://hooks.slack.com/services/…'
end
-
- def supported_events
- additional = []
- additional << 'alert'
-
- super + additional
- end
-
- def get_message(object_kind, data)
- return Integrations::ChatMessage::AlertMessage.new(data) if object_kind == 'alert'
-
- super
- end
-
- override :log_usage
- def log_usage(event, user_id)
- return unless user_id
-
- return unless SUPPORTED_EVENTS_FOR_USAGE_LOG.include?(event)
-
- key = "i_ecosystem_slack_service_#{event}_notification"
-
- 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
- }.compact
-
- Gitlab::Tracking.event(
- SNOWPLOW_EVENT_CATEGORY,
- Integration::SNOWPLOW_EVENT_ACTION,
- label: Integration::SNOWPLOW_EVENT_LABEL,
- property: key,
- user: User.find(user_id),
- **optional_arguments
- )
- end
-
- override :configurable_channels?
- def configurable_channels?
- true
- end
end
end
diff --git a/app/models/integrations/teamcity.rb b/app/models/integrations/teamcity.rb
index ca7a715f4b3..af629d6ef1e 100644
--- a/app/models/integrations/teamcity.rb
+++ b/app/models/integrations/teamcity.rb
@@ -11,6 +11,7 @@ module Integrations
field :teamcity_url,
title: -> { s_('ProjectService|TeamCity server URL') },
placeholder: 'https://teamcity.example.com',
+ exposes_secrets: true,
required: true
field :build_type,
@@ -36,8 +37,6 @@ module Integrations
attr_accessor :response
- before_validation :reset_password
-
class << self
def to_param
'teamcity'
@@ -48,12 +47,6 @@ module Integrations
end
end
- def reset_password
- if teamcity_url_changed? && !password_touched?
- self.password = nil
- end
- end
-
def title
'JetBrains TeamCity'
end
diff --git a/app/models/integrations/unify_circuit.rb b/app/models/integrations/unify_circuit.rb
index f10a75fac5d..aa19133b8c2 100644
--- a/app/models/integrations/unify_circuit.rb
+++ b/app/models/integrations/unify_circuit.rb
@@ -29,7 +29,7 @@ module Integrations
def default_fields
[
- { type: 'text', name: 'webhook', placeholder: "https://yourcircuit.com/rest/v2/webhooks/incoming/…", required: true },
+ { type: 'text', name: 'webhook', help: 'https://yourcircuit.com/rest/v2/webhooks/incoming/…', required: true },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' },
{
type: 'select',
@@ -43,11 +43,13 @@ module Integrations
private
def notify(message, opts)
- response = Gitlab::HTTP.post(webhook, body: {
+ body = {
subject: message.project_name,
text: message.summary,
markdown: true
- }.to_json)
+ }
+
+ response = Gitlab::HTTP.post(webhook, body: Gitlab::Json.dump(body))
response if response.success?
end
diff --git a/app/models/integrations/webex_teams.rb b/app/models/integrations/webex_teams.rb
index 75be457dcf5..8e6f5ca6d17 100644
--- a/app/models/integrations/webex_teams.rb
+++ b/app/models/integrations/webex_teams.rb
@@ -29,7 +29,7 @@ module Integrations
def default_fields
[
- { type: 'text', name: 'webhook', placeholder: "https://api.ciscospark.com/v1/webhooks/incoming/...", required: true },
+ { type: 'text', name: 'webhook', help: 'https://api.ciscospark.com/v1/webhooks/incoming/...', required: true },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' },
{
type: 'select',
@@ -44,7 +44,7 @@ module Integrations
def notify(message, opts)
header = { 'Content-Type' => 'application/json' }
- response = Gitlab::HTTP.post(webhook, headers: header, body: { markdown: message.summary }.to_json)
+ response = Gitlab::HTTP.post(webhook, headers: header, body: Gitlab::Json.dump({ markdown: message.summary }))
response if response.success?
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index ea7acf9a5d1..fc083002c41 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -39,13 +39,14 @@ class Issue < ApplicationRecord
DueNextMonthAndPreviousTwoWeeks = DueDateStruct.new('Due Next Month And Previous Two Weeks', 'next_month_and_previous_two_weeks').freeze
SORTING_PREFERENCE_FIELD = :issues_sort
+ MAX_BRANCH_TEMPLATE = 255
# Types of issues that should be displayed on issue lists across the app
# for example, project issues list, group issues list, and issues dashboard.
#
# This should be kept consistent with the enums used for the GraphQL issue list query in
# https://gitlab.com/gitlab-org/gitlab/-/blob/1379c2d7bffe2a8d809f23ac5ef9b4114f789c07/app/assets/javascripts/issues/list/constants.js#L154-158
- TYPES_FOR_LIST = %w(issue incident test_case task).freeze
+ TYPES_FOR_LIST = %w(issue incident test_case task objective).freeze
# Types of issues that should be displayed on issue board lists
TYPES_FOR_BOARD_LIST = %w(issue incident).freeze
@@ -90,6 +91,7 @@ class Issue < ApplicationRecord
has_one :incident_management_issuable_escalation_status, class_name: 'IncidentManagement::IssuableEscalationStatus'
has_and_belongs_to_many :self_managed_prometheus_alert_events, join_table: :issues_self_managed_prometheus_alert_events # rubocop: disable Rails/HasAndBelongsToMany
has_and_belongs_to_many :prometheus_alert_events, join_table: :issues_prometheus_alert_events # rubocop: disable Rails/HasAndBelongsToMany
+ has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :issue
has_many :prometheus_alerts, through: :prometheus_alert_events
has_many :issue_customer_relations_contacts, class_name: 'CustomerRelations::IssueContact', inverse_of: :issue
has_many :customer_relations_contacts, through: :issue_customer_relations_contacts, source: :contact, class_name: 'CustomerRelations::Contact', inverse_of: :issues
@@ -210,6 +212,7 @@ class Issue < ApplicationRecord
end
scope :with_null_relative_position, -> { where(relative_position: nil) }
scope :with_non_null_relative_position, -> { where.not(relative_position: nil) }
+ scope :with_projects_matching_search_data, -> { where('issue_search_data.project_id = issues.project_id') }
before_validation :ensure_namespace_id, :ensure_work_item_type
@@ -270,9 +273,14 @@ class Issue < ApplicationRecord
reorder(upvotes_count: :asc)
end
- override :pg_full_text_search
- def pg_full_text_search(search_term)
- super.where('issue_search_data.project_id = issues.project_id')
+ override :full_search
+ def full_search(query, matched_columns: nil, use_minimum_char_limit: true)
+ return super if query.match?(IssuableFinder::FULL_TEXT_SEARCH_TERM_REGEX)
+
+ super.where(
+ 'issues.title NOT SIMILAR TO :pattern OR issues.description NOT SIMILAR TO :pattern',
+ pattern: IssuableFinder::FULL_TEXT_SEARCH_TERM_PATTERN
+ )
end
end
@@ -393,10 +401,21 @@ class Issue < ApplicationRecord
)
end
- def self.to_branch_name(*args)
- branch_name = args.map(&:to_s).each_with_index.map do |arg, i|
- arg.parameterize(preserve_case: i == 0).presence
- end.compact.join('-')
+ def self.to_branch_name(id, title, project: nil)
+ params = {
+ 'id' => id.to_s.parameterize(preserve_case: true),
+ 'title' => title.to_s.parameterize
+ }
+ template = project&.issue_branch_template
+
+ branch_name =
+ if template.present?
+ Gitlab::StringPlaceholderReplacer.replace_string_placeholders(template, /(#{params.keys.join('|')})/) do |arg|
+ params[arg]
+ end
+ else
+ params.values.select(&:present?).join('-')
+ end
if branch_name.length > 100
truncated_string = branch_name[0, 100]
@@ -474,7 +493,7 @@ class Issue < ApplicationRecord
if self.confidential?
"#{iid}-confidential-issue"
else
- self.class.to_branch_name(iid, title)
+ self.class.to_branch_name(iid, title, project: project)
end
end
@@ -653,6 +672,10 @@ class Issue < ApplicationRecord
Gitlab::EtagCaching::Store.new.touch(key)
end
+ def supports_confidentiality?
+ true
+ end
+
private
def due_date_after_start_date
diff --git a/app/models/iteration.rb b/app/models/iteration.rb
index ed73793c78f..c6269313d8b 100644
--- a/app/models/iteration.rb
+++ b/app/models/iteration.rb
@@ -4,9 +4,8 @@
class Iteration < ApplicationRecord
include IgnorableColumns
- # TODO https://gitlab.com/gitlab-org/gitlab/-/issues/372125
# TODO https://gitlab.com/gitlab-org/gitlab/-/issues/372126
- ignore_column :project_id, remove_with: '15.6', remove_after: '2022-09-17'
+ ignore_column :project_id, remove_with: '15.7', remove_after: '2022-11-18'
self.table_name = 'sprints'
diff --git a/app/models/label.rb b/app/models/label.rb
index 483d51099b1..aa53c0e0f3f 100644
--- a/app/models/label.rb
+++ b/app/models/label.rb
@@ -14,8 +14,7 @@ class Label < ApplicationRecord
DEFAULT_COLOR = ::Gitlab::Color.of('#6699cc')
- attribute :color, ::Gitlab::Database::Type::Color.new
- default_value_for :color, DEFAULT_COLOR
+ attribute :color, ::Gitlab::Database::Type::Color.new, default: DEFAULT_COLOR
has_many :lists, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :priorities, class_name: 'LabelPriority'
diff --git a/app/models/member.rb b/app/models/member.rb
index ff1d8f18c25..80c5fd7e468 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -286,7 +286,7 @@ class Member < ApplicationRecord
refresh_member_authorized_projects(blocking: false)
end
- default_value_for :notification_level, NotificationSetting.levels[:global]
+ attribute :notification_level, default: -> { NotificationSetting.levels[:global] }
class << self
def search(query)
diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb
index 2b35f7da7b4..ad1ad1e74fe 100644
--- a/app/models/members/group_member.rb
+++ b/app/models/members/group_member.rb
@@ -13,7 +13,7 @@ class GroupMember < Member
delegate :update_two_factor_requirement, to: :user, allow_nil: true
# Make sure group member points only to group as it source
- default_value_for :source_type, SOURCE_TYPE
+ attribute :source_type, default: SOURCE_TYPE
validates :source_type, format: { with: SOURCE_TYPE_FORMAT }
default_scope { where(source_type: SOURCE_TYPE) } # rubocop:disable Cop/DefaultScope
diff --git a/app/models/members/last_group_owner_assigner.rb b/app/models/members/last_group_owner_assigner.rb
index e411a0ef5eb..48c9bcb9a70 100644
--- a/app/models/members/last_group_owner_assigner.rb
+++ b/app/models/members/last_group_owner_assigner.rb
@@ -40,6 +40,6 @@ class LastGroupOwnerAssigner
end
def owners
- @owners ||= group.all_owners_excluding_project_bots.load
+ @owners ||= group.member_owners_excluding_project_bots.load
end
end
diff --git a/app/models/members/member_task.rb b/app/models/members/member_task.rb
index f093619ff36..6cf6b1adb45 100644
--- a/app/models/members/member_task.rb
+++ b/app/models/members/member_task.rb
@@ -34,9 +34,10 @@ class MemberTask < ApplicationRecord
end
def project_in_member_source
- if member.is_a?(GroupMember)
+ case member
+ when GroupMember
errors.add(:project, _('is not in the member group')) unless project.namespace == member.source
- elsif member.is_a?(ProjectMember)
+ when ProjectMember
errors.add(:project, _('is not the member project')) unless project == member.source
end
end
diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb
index 8fd82fcb34a..1099e0f48c0 100644
--- a/app/models/members/project_member.rb
+++ b/app/models/members/project_member.rb
@@ -10,7 +10,7 @@ class ProjectMember < Member
delegate :namespace_id, to: :project
# Make sure project member points only to project as it source
- default_value_for :source_type, SOURCE_TYPE
+ attribute :source_type, default: SOURCE_TYPE
validates :source_type, format: { with: SOURCE_TYPE_FORMAT }
default_scope { where(source_type: SOURCE_TYPE) } # rubocop:disable Cop/DefaultScope
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index fb20d91fa20..735c0df1529 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -136,7 +136,7 @@ class MergeRequest < ApplicationRecord
before_validation :set_draft_status
- after_create :ensure_merge_request_diff
+ after_create :ensure_merge_request_diff, unless: :skip_ensure_merge_request_diff
after_update :clear_memoized_shas
after_update :reload_diff_if_branch_changed
after_commit :ensure_metrics, on: [:create, :update], unless: :importing?
@@ -146,6 +146,10 @@ class MergeRequest < ApplicationRecord
# It allows us to close or modify broken merge requests
attr_accessor :allow_broken
+ # Temporary flag to skip merge_request_diff creation on create.
+ # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100390
+ attr_accessor :skip_ensure_merge_request_diff
+
# Temporary fields to store compare vars
# when creating new merge request
attr_accessor :can_be_created, :compare_commits, :diff_options, :compare
@@ -242,9 +246,7 @@ 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|
- if Feature.enabled?(:trigger_mr_subscription_on_merge_status_change, merge_request.project)
- GraphqlTriggers.merge_request_merge_status_updated(merge_request)
- end
+ GraphqlTriggers.merge_request_merge_status_updated(merge_request)
end
# rubocop: disable CodeReuse/ServiceClass
@@ -649,8 +651,8 @@ class MergeRequest < ApplicationRecord
context_commits.count
end
- def commits(limit: nil, load_from_gitaly: false)
- return merge_request_diff.commits(limit: limit, load_from_gitaly: load_from_gitaly) if merge_request_diff.persisted?
+ def commits(limit: nil, load_from_gitaly: false, page: nil)
+ return merge_request_diff.commits(limit: limit, load_from_gitaly: load_from_gitaly, page: page) if merge_request_diff.persisted?
commits_arr = if compare_commits
reversed_commits = compare_commits.reverse
@@ -662,8 +664,8 @@ class MergeRequest < ApplicationRecord
CommitCollection.new(source_project, commits_arr, source_branch)
end
- def recent_commits(load_from_gitaly: false)
- commits(limit: MergeRequestDiff::COMMITS_SAFE_SIZE, load_from_gitaly: load_from_gitaly)
+ def recent_commits(limit: MergeRequestDiff::COMMITS_SAFE_SIZE, load_from_gitaly: false, page: nil)
+ commits(limit: limit, load_from_gitaly: load_from_gitaly, page: page)
end
def commits_count
@@ -1130,7 +1132,7 @@ class MergeRequest < ApplicationRecord
# rubocop: enable CodeReuse/ServiceClass
def diffable_merge_ref?
- open? && merge_head_diff.present? && (Feature.enabled?(:display_merge_conflicts_in_diff, project) || can_be_merged?)
+ open? && merge_head_diff.present? && can_be_merged?
end
# Returns boolean indicating the merge_status should be rechecked in order to
@@ -1673,7 +1675,7 @@ class MergeRequest < ApplicationRecord
# TODO: consider renaming this as with exposed artifacts we generate reports,
# not always compare
# issue: https://gitlab.com/gitlab-org/gitlab/issues/34224
- def compare_reports(service_class, current_user = nil, report_type = nil, additional_params = {} )
+ def compare_reports(service_class, current_user = nil, report_type = nil, additional_params = {})
with_reactive_cache(service_class.name, current_user&.id, report_type) do |data|
unless service_class.new(project, current_user, id: id, report_type: report_type, additional_params: additional_params)
.latest?(comparison_base_pipeline(service_class.name), actual_head_pipeline, data)
diff --git a/app/models/merge_request_assignee.rb b/app/models/merge_request_assignee.rb
index be3a1d42eac..3e481e35deb 100644
--- a/app/models/merge_request_assignee.rb
+++ b/app/models/merge_request_assignee.rb
@@ -1,9 +1,6 @@
# frozen_string_literal: true
class MergeRequestAssignee < ApplicationRecord
- include IgnorableColumns
- ignore_column %i[state updated_state_by_user_id], remove_with: '15.6', remove_after: '2022-10-22'
-
belongs_to :merge_request, touch: true
belongs_to :assignee, class_name: "User", foreign_key: :user_id, inverse_of: :merge_request_assignees
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 9f7e98dc04b..98a9ccc2040 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -292,9 +292,9 @@ class MergeRequestDiff < ApplicationRecord
end
end
- def commits(limit: nil, load_from_gitaly: false)
- strong_memoize(:"commits_#{limit || 'all'}_#{load_from_gitaly}") do
- load_commits(limit: limit, load_from_gitaly: load_from_gitaly)
+ def commits(limit: nil, load_from_gitaly: false, page: nil)
+ strong_memoize(:"commits_#{limit || 'all'}_#{load_from_gitaly}_page_#{page}") do
+ load_commits(limit: limit, load_from_gitaly: load_from_gitaly, page: page)
end
end
@@ -725,17 +725,19 @@ class MergeRequestDiff < ApplicationRecord
end
end
- def load_commits(limit: nil, load_from_gitaly: false)
+ def load_commits(limit: nil, load_from_gitaly: false, page: nil)
+ diff_commits = page.present? ? merge_request_diff_commits.page(page).per(limit) : merge_request_diff_commits.limit(limit)
+
if load_from_gitaly
- commits = Gitlab::Git::Commit.batch_by_oid(repository, merge_request_diff_commits.limit(limit).map(&:sha))
+ commits = Gitlab::Git::Commit.batch_by_oid(repository, diff_commits.map(&:sha))
commits = Commit.decorate(commits, project)
else
- commits = merge_request_diff_commits.with_users.limit(limit)
+ commits = diff_commits.with_users
.map { |commit| Commit.from_hash(commit.to_hash, project) }
end
CommitCollection
- .new(merge_request.target_project, commits, merge_request.target_branch)
+ .new(merge_request.target_project, commits, merge_request.target_branch, page: page.to_i, per_page: limit, count: commits_count)
end
def save_diffs
diff --git a/app/models/merge_request_diff_commit.rb b/app/models/merge_request_diff_commit.rb
index 66f1e45fd49..152fb195c97 100644
--- a/app/models/merge_request_diff_commit.rb
+++ b/app/models/merge_request_diff_commit.rb
@@ -70,7 +70,7 @@ class MergeRequestDiffCommit < ApplicationRecord
sha: Gitlab::Database::ShaAttribute.serialize(sha), # rubocop:disable Cop/ActiveRecordSerialize
authored_date: Gitlab::Database.sanitize_timestamp(commit_hash[:authored_date]),
committed_date: Gitlab::Database.sanitize_timestamp(commit_hash[:committed_date]),
- trailers: commit_hash.fetch(:trailers, {}).to_json
+ trailers: Gitlab::Json.dump(commit_hash.fetch(:trailers, {}))
)
end
diff --git a/app/models/merge_request_diff_file.rb b/app/models/merge_request_diff_file.rb
index 04b322ef5a6..5a98131a6fd 100644
--- a/app/models/merge_request_diff_file.rb
+++ b/app/models/merge_request_diff_file.rb
@@ -15,12 +15,7 @@ class MergeRequestDiffFile < ApplicationRecord
end
def utf8_diff
- fetched_diff = if Feature.enabled?(:externally_stored_diffs_caching_export) &&
- merge_request_diff&.stored_externally?
- diff_export
- else
- diff
- end
+ fetched_diff = merge_request_diff&.stored_externally? ? diff_export : diff
return '' if fetched_diff.blank?
diff --git a/app/models/merge_request_reviewer.rb b/app/models/merge_request_reviewer.rb
index 4b5b71481d3..e1e2805cd8f 100644
--- a/app/models/merge_request_reviewer.rb
+++ b/app/models/merge_request_reviewer.rb
@@ -2,8 +2,7 @@
class MergeRequestReviewer < ApplicationRecord
include MergeRequestReviewerState
- include IgnorableColumns
- ignore_column :updated_state_by_user_id, remove_with: '15.6', remove_after: '2022-10-22'
+ include BulkInsertSafe # must be included _last_ i.e. after any other concerns
belongs_to :merge_request
belongs_to :reviewer, class_name: 'User', foreign_key: :user_id, inverse_of: :merge_request_reviewers
diff --git a/app/models/ml/candidate.rb b/app/models/ml/candidate.rb
index 29e1ba88528..f7da4418624 100644
--- a/app/models/ml/candidate.rb
+++ b/app/models/ml/candidate.rb
@@ -11,8 +11,15 @@ module Ml
belongs_to :user
has_many :metrics, class_name: 'Ml::CandidateMetric'
has_many :params, class_name: 'Ml::CandidateParam'
+ has_many :latest_metrics, -> { latest }, class_name: 'Ml::CandidateMetric', inverse_of: :candidate
- default_value_for(:iid) { SecureRandom.uuid }
+ attribute :iid, default: -> { SecureRandom.uuid }
+
+ scope :including_metrics_and_params, -> { includes(:latest_metrics, :params) }
+
+ def artifact_root
+ "/ml_candidate_#{iid}/-/"
+ end
class << self
def with_project_id_and_iid(project_id, iid)
diff --git a/app/models/ml/candidate_metric.rb b/app/models/ml/candidate_metric.rb
index e03a8b83ee6..8e13a46d6b4 100644
--- a/app/models/ml/candidate_metric.rb
+++ b/app/models/ml/candidate_metric.rb
@@ -6,5 +6,7 @@ module Ml
validates :name, length: { maximum: 250 }, presence: true
belongs_to :candidate, class_name: 'Ml::Candidate'
+
+ scope :latest, -> { select('DISTINCT ON (candidate_id, name) *').order('candidate_id, name, id DESC') }
end
end
diff --git a/app/models/ml/experiment.rb b/app/models/ml/experiment.rb
index a32099e8a0c..05b238b960d 100644
--- a/app/models/ml/experiment.rb
+++ b/app/models/ml/experiment.rb
@@ -23,7 +23,7 @@ module Ml
end
def by_project_id(project_id)
- where(project_id: project_id)
+ where(project_id: project_id).order(id: :desc)
end
end
end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 42f362876bb..51c39ad4ec3 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -40,9 +40,9 @@ class Namespace < ApplicationRecord
PATH_TRAILING_VIOLATIONS = %w[.git .atom .].freeze
- # The first date in https://docs.gitlab.com/ee/user/usage_quotas.html#namespace-storage-limit-enforcement-schedule
- # Determines when we start enforcing namespace storage
- MIN_STORAGE_ENFORCEMENT_DATE = Date.new(2022, 10, 19)
+ # This date is just a placeholder until namespace storage enforcement timeline is confirmed at which point
+ # this should be replaced, see https://about.gitlab.com/pricing/faq-efficient-free-tier/#user-limits-on-gitlab-saas-free-tier
+ MIN_STORAGE_ENFORCEMENT_DATE = 3.months.from_now.to_date
# https://gitlab.com/gitlab-org/gitlab/-/issues/367531
MIN_STORAGE_ENFORCEMENT_USAGE = 5.gigabytes
@@ -91,6 +91,7 @@ class Namespace < ApplicationRecord
validates :name,
presence: true,
length: { maximum: 255 }
+ validates :name, uniqueness: { scope: [:type, :parent_id] }, if: -> { parent_id.present? }
validates :description, length: { maximum: 255 }
@@ -550,11 +551,12 @@ class Namespace < ApplicationRecord
end
def shared_runners_setting_higher_than?(other_setting)
- if other_setting == SR_ENABLED
+ case other_setting
+ when SR_ENABLED
false
- elsif other_setting == SR_DISABLED_WITH_OVERRIDE
+ when SR_DISABLED_WITH_OVERRIDE
shared_runners_setting == SR_ENABLED
- elsif other_setting == SR_DISABLED_AND_UNOVERRIDABLE
+ when SR_DISABLED_AND_UNOVERRIDABLE
shared_runners_setting == SR_ENABLED || shared_runners_setting == SR_DISABLED_WITH_OVERRIDE
else
raise ArgumentError
diff --git a/app/models/namespace_setting.rb b/app/models/namespace_setting.rb
index 6a87fba57ac..3e6371b0c4d 100644
--- a/app/models/namespace_setting.rb
+++ b/app/models/namespace_setting.rb
@@ -4,11 +4,6 @@ class NamespaceSetting < ApplicationRecord
include CascadingNamespaceSettingAttribute
include Sanitizable
include ChronicDurationAttribute
- include IgnorableColumns
-
- ignore_columns %i[exclude_from_free_user_cap include_for_free_user_cap_preview],
- remove_with: '15.5',
- remove_after: '2022-09-23'
cascading_attr :delayed_project_removal
diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb
index a034d97a6bb..7ffcb8b9219 100644
--- a/app/models/network/graph.rb
+++ b/app/models/network/graph.rb
@@ -23,6 +23,8 @@ module Network
protected
def collect_notes
+ return {} if Feature.enabled?(:disable_network_graph_notes_count, @project, type: :experiment)
+
h = Hash.new(0)
@project
diff --git a/app/models/note.rb b/app/models/note.rb
index e444111119b..8e1f4979602 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -60,7 +60,7 @@ class Note < ApplicationRecord
# Attribute used to determine whether keep_around_commits will be skipped for diff notes.
attr_accessor :skip_keep_around_commits
- default_value_for :system, false
+ attribute :system, default: false
attr_mentionable :note, pipeline: :note
participant :author
@@ -361,14 +361,6 @@ class Note < ApplicationRecord
super(noteable_type.to_s.classify.constantize.base_class.to_s)
end
- def noteable_assignee_or_author?(user)
- return false unless user
- return false unless noteable.respond_to?(:author_id)
- return noteable.assignee_or_author?(user) if [MergeRequest, Issue].include?(noteable.class)
-
- noteable.author_id == user.id
- end
-
def contributor?
project&.team&.contributor?(self.author_id)
end
@@ -756,7 +748,8 @@ class Note < ApplicationRecord
if user_visible_reference_count.present? && total_reference_count.present?
# if they are not equal, then there are private/confidential references as well
- user_visible_reference_count > 0 && user_visible_reference_count == total_reference_count
+ total_reference_count == 0 ||
+ user_visible_reference_count > 0 && user_visible_reference_count == total_reference_count
else
refs = all_references(user)
refs.all.any? && refs.all_visible?
diff --git a/app/models/notification_setting.rb b/app/models/notification_setting.rb
index 2e45753c182..cde7b92e74a 100644
--- a/app/models/notification_setting.rb
+++ b/app/models/notification_setting.rb
@@ -3,9 +3,7 @@
class NotificationSetting < ApplicationRecord
include FromUnion
- enum level: { global: 3, watch: 2, participating: 1, mention: 4, disabled: 0, custom: 5 }
-
- default_value_for :level, NotificationSetting.levels[:global]
+ enum level: { global: 3, watch: 2, participating: 1, mention: 4, disabled: 0, custom: 5 }, _default: :global
belongs_to :user
belongs_to :source, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
diff --git a/app/models/oauth_access_token.rb b/app/models/oauth_access_token.rb
index eac99e8d441..8e79a750793 100644
--- a/app/models/oauth_access_token.rb
+++ b/app/models/oauth_access_token.rb
@@ -31,8 +31,6 @@ class OauthAccessToken < Doorkeeper::AccessToken
# have `reuse_access_tokens` disabled and we also hash tokens.
# This ensures we don't accidentally return a hashed token value.
def self.matching_token_for(application, resource_owner, scopes)
- return if Feature.enabled?(:hash_oauth_tokens)
-
- super
+ # no-op
end
end
diff --git a/app/models/operations/feature_flag.rb b/app/models/operations/feature_flag.rb
index e36c59366fe..0df8c87f73f 100644
--- a/app/models/operations/feature_flag.rb
+++ b/app/models/operations/feature_flag.rb
@@ -16,8 +16,8 @@ module Operations
has_internal_id :iid, scope: :project
- default_value_for :active, true
- default_value_for :version, :new_version_flag
+ attribute :active, default: true
+ attribute :version, default: :new_version_flag
# strategies exists only for the second version
has_many :strategies, class_name: 'Operations::FeatureFlags::Strategy'
diff --git a/app/models/packages/go/module_version.rb b/app/models/packages/go/module_version.rb
index c442b2416f1..5869a03e081 100644
--- a/app/models/packages/go/module_version.rb
+++ b/app/models/packages/go/module_version.rb
@@ -21,9 +21,10 @@ module Packages
raise ArgumentError, "mod is required" unless mod
raise ArgumentError, "commit is required" unless commit
- if type == :ref
+ case type
+ when :ref
raise ArgumentError, "ref is required" unless ref
- elsif type == :pseudo
+ when :pseudo
raise ArgumentError, "name is required" unless name
raise ArgumentError, "semver is required" unless semver
end
diff --git a/app/models/pages_domain.rb b/app/models/pages_domain.rb
index 16d5492a65e..328c67a0711 100644
--- a/app/models/pages_domain.rb
+++ b/app/models/pages_domain.rb
@@ -10,8 +10,8 @@ class PagesDomain < ApplicationRecord
SSL_RENEWAL_THRESHOLD = 30.days.freeze
enum certificate_source: { user_provided: 0, gitlab_provided: 1 }, _prefix: :certificate
- enum scope: { instance: 0, group: 1, project: 2 }, _prefix: :scope
- enum usage: { pages: 0, serverless: 1 }, _prefix: :usage
+ enum scope: { instance: 0, group: 1, project: 2 }, _prefix: :scope, _default: :project
+ enum usage: { pages: 0, serverless: 1 }, _prefix: :usage, _default: :pages
belongs_to :project
has_many :acme_orders, class_name: "PagesDomainAcmeOrder"
@@ -35,10 +35,8 @@ class PagesDomain < ApplicationRecord
validate :validate_intermediates, if: ->(domain) { domain.certificate.present? && domain.certificate_changed? }
validate :validate_custom_domain_count_per_project, on: :create
- default_value_for(:auto_ssl_enabled, allows_nil: false) { ::Gitlab::LetsEncrypt.enabled? }
- default_value_for :scope, allows_nil: false, value: :project
- default_value_for :wildcard, allows_nil: false, value: false
- default_value_for :usage, allows_nil: false, value: :pages
+ attribute :auto_ssl_enabled, default: -> { ::Gitlab::LetsEncrypt.enabled? }
+ attribute :wildcard, default: false
attr_encrypted :key,
mode: :per_attribute_iv_and_salt,
@@ -50,7 +48,7 @@ class PagesDomain < ApplicationRecord
scope :for_project, ->(project) { where(project: project) }
- scope :enabled, -> { where('enabled_until >= ?', Time.current ) }
+ scope :enabled, -> { where('enabled_until >= ?', Time.current) }
scope :needs_verification, -> do
verified_at = arel_table[:verified_at]
enabled_until = arel_table[:enabled_until]
diff --git a/app/models/personal_access_token.rb b/app/models/personal_access_token.rb
index f0ed1822da6..3126dba9d6d 100644
--- a/app/models/personal_access_token.rb
+++ b/app/models/personal_access_token.rb
@@ -11,8 +11,6 @@ class PersonalAccessToken < ApplicationRecord
add_authentication_token_field :token, digest: true
- REDIS_EXPIRY_TIME = 3.minutes
-
# PATs are 20 characters + optional configurable settings prefix (0..20)
TOKEN_LENGTH_RANGE = (20..40).freeze
@@ -34,8 +32,6 @@ class PersonalAccessToken < ApplicationRecord
scope :for_user, -> (user) { where(user: user) }
scope :for_users, -> (users) { where(user: users) }
scope :preload_users, -> { preload(:user) }
- scope :order_expires_at_asc, -> { reorder(expires_at: :asc) }
- scope :order_expires_at_desc, -> { reorder(expires_at: :desc) }
scope :order_expires_at_asc_id_desc, -> { reorder(expires_at: :asc, id: :desc) }
scope :project_access_token, -> { includes(:user).where(user: { user_type: :project_bot }) }
scope :owner_is_human, -> { includes(:user).where(user: { user_type: :human }) }
@@ -55,35 +51,10 @@ class PersonalAccessToken < ApplicationRecord
!revoked? && !expired?
end
- def self.redis_getdel(user_id)
- Gitlab::Redis::SharedState.with do |redis|
- redis_key = redis_shared_state_key(user_id)
- encrypted_token = redis.get(redis_key)
- redis.del(redis_key)
-
- begin
- Gitlab::CryptoHelper.aes256_gcm_decrypt(encrypted_token)
- rescue StandardError => e
- logger.warn "Failed to decrypt #{self.name} value stored in Redis for key ##{redis_key}: #{e.class}"
- encrypted_token
- end
- end
- end
-
- def self.redis_store!(user_id, token)
- encrypted_token = Gitlab::CryptoHelper.aes256_gcm_encrypt(token)
-
- Gitlab::Redis::SharedState.with do |redis|
- redis.set(redis_shared_state_key(user_id), encrypted_token, ex: REDIS_EXPIRY_TIME)
- end
- end
-
override :simple_sorts
def self.simple_sorts
super.merge(
{
- 'expires_at_asc' => -> { order_expires_at_asc },
- 'expires_at_desc' => -> { order_expires_at_desc },
'expires_at_asc_id_desc' => -> { order_expires_at_asc_id_desc }
}
)
@@ -121,10 +92,6 @@ class PersonalAccessToken < ApplicationRecord
self.scopes = Gitlab::Auth::DEFAULT_SCOPES if self.scopes.empty?
end
-
- def self.redis_shared_state_key(user_id)
- "gitlab:personal_access_token:#{user_id}"
- end
end
PersonalAccessToken.prepend_mod_with('PersonalAccessToken')
diff --git a/app/models/postgresql/detached_partition.rb b/app/models/postgresql/detached_partition.rb
index 12b48895e0c..b0dd52c9657 100644
--- a/app/models/postgresql/detached_partition.rb
+++ b/app/models/postgresql/detached_partition.rb
@@ -3,5 +3,9 @@
module Postgresql
class DetachedPartition < ::Gitlab::Database::SharedModel
scope :ready_to_drop, -> { where('drop_after < ?', Time.current) }
+
+ def fully_qualified_table_name
+ "#{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}.#{table_name}"
+ end
end
end
diff --git a/app/models/preloaders/project_root_ancestor_preloader.rb b/app/models/preloaders/project_root_ancestor_preloader.rb
index 1e935249407..6192f79ce2c 100644
--- a/app/models/preloaders/project_root_ancestor_preloader.rb
+++ b/app/models/preloaders/project_root_ancestor_preloader.rb
@@ -9,7 +9,7 @@ module Preloaders
end
def execute
- return if @projects.is_a?(ActiveRecord::NullRelation)
+ return unless @projects.is_a?(ActiveRecord::Relation)
return unless ::Feature.enabled?(:use_traversal_ids)
root_query = Namespace.joins("INNER JOIN (#{join_sql}) as root_query ON root_query.root_id = namespaces.id")
diff --git a/app/models/preloaders/user_max_access_level_in_projects_preloader.rb b/app/models/preloaders/user_max_access_level_in_projects_preloader.rb
index 2e2272a2ef5..c9fd5e7718a 100644
--- a/app/models/preloaders/user_max_access_level_in_projects_preloader.rb
+++ b/app/models/preloaders/user_max_access_level_in_projects_preloader.rb
@@ -7,9 +7,11 @@ module Preloaders
def initialize(projects, user)
@projects = if projects.is_a?(Array)
Project.where(id: projects)
- else
+ elsif Feature.enabled?(:projects_preloader_fix)
# Push projects base query in to a sub-select to avoid
# table name clashes. Performs better than aliasing.
+ Project.where(id: projects.subquery(:id))
+ else
Project.where(id: projects.reselect(:id))
end
@@ -17,6 +19,8 @@ module Preloaders
end
def execute
+ return unless @user
+
project_authorizations = ProjectAuthorization.arel_table
auths = @projects
diff --git a/app/models/project.rb b/app/models/project.rb
index 7b61010ab01..a07d4147228 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -39,6 +39,7 @@ class Project < ApplicationRecord
include BulkUsersByEmailLoad
include RunnerTokenExpirationInterval
include BlocksUnsafeSerialization
+ include Subquery
extend Gitlab::Cache::RequestCache
extend Gitlab::Utils::Override
@@ -222,6 +223,7 @@ class Project < ApplicationRecord
has_one :youtrack_integration, class_name: 'Integrations::Youtrack'
has_one :zentao_integration, class_name: 'Integrations::Zentao'
+ has_one :wiki_repository, class_name: 'Projects::WikiRepository', inverse_of: :project
has_one :root_of_fork_network,
foreign_key: 'root_project_id',
inverse_of: :root_project,
@@ -451,7 +453,7 @@ class Project < ApplicationRecord
:metrics_dashboard_access_level, :analytics_access_level,
:operations_access_level, :security_and_compliance_access_level,
:container_registry_access_level, :environments_access_level, :feature_flags_access_level,
- :monitor_access_level, :releases_access_level,
+ :monitor_access_level, :releases_access_level, :infrastructure_access_level,
to: :project_feature, allow_nil: true
delegate :show_default_award_emojis, :show_default_award_emojis=,
@@ -491,6 +493,7 @@ class Project < ApplicationRecord
to: :project_setting
delegate :merge_commit_template, :merge_commit_template=, to: :project_setting, allow_nil: true
delegate :squash_commit_template, :squash_commit_template=, to: :project_setting, allow_nil: true
+ delegate :issue_branch_template, :issue_branch_template=, to: :project_setting, allow_nil: true
delegate :log_jira_dvcs_integration_usage, :jira_dvcs_server_last_sync_at, :jira_dvcs_cloud_last_sync_at, to: :feature_usage
@@ -1616,7 +1619,7 @@ class Project < ApplicationRecord
end
def all_clusters
- group_clusters = Clusters::Cluster.joins(:groups).where(cluster_groups: { group_id: ancestors_upto } )
+ group_clusters = Clusters::Cluster.joins(:groups).where(cluster_groups: { group_id: ancestors_upto })
instance_clusters = Clusters::Cluster.instance_type
Clusters::Cluster.from_union([clusters, group_clusters, instance_clusters])
@@ -1705,7 +1708,11 @@ class Project < ApplicationRecord
end
def has_active_integrations?(hooks_scope = :push_hooks)
- integrations.public_send(hooks_scope).any? # rubocop:disable GitlabSecurity/PublicSend
+ @has_active_integrations ||= {} # rubocop: disable Gitlab/PredicateMemoization
+
+ return @has_active_integrations[hooks_scope] if @has_active_integrations.key?(hooks_scope)
+
+ @has_active_integrations[hooks_scope] = integrations.public_send(hooks_scope).any? # rubocop:disable GitlabSecurity/PublicSend
end
def feature_usage
@@ -2729,11 +2736,6 @@ class Project < ApplicationRecord
ci_config_path.blank? || ci_config_path == Gitlab::FileDetector::PATTERNS[:gitlab_ci]
end
- # DO NOT USE. This method will be deprecated soon
- def uses_external_project_ci_config?
- !!(ci_config_path =~ %r{@.+/.+})
- end
-
def limited_protected_branches(limit)
protected_branches.limit(limit)
end
@@ -2784,7 +2786,7 @@ class Project < ApplicationRecord
return unless service_desk_enabled?
config = Gitlab.config.incoming_email
- wildcard = Gitlab::IncomingEmail::WILDCARD_PLACEHOLDER
+ wildcard = Gitlab::Email::Common::WILDCARD_PLACEHOLDER
config.address&.gsub(wildcard, "#{full_path_slug}-#{default_service_desk_suffix}")
end
@@ -2854,11 +2856,6 @@ class Project < ApplicationRecord
repository.gitlab_ci_yml_for(sha, ci_config_path_or_default)
end
- # DO NOT USE. This method will be deprecated soon
- def ci_config_external_project
- Project.find_by_full_path(ci_config_path.split('@', 2).last)
- end
-
def enabled_group_deploy_keys
return GroupDeployKey.none unless group
@@ -2927,10 +2924,6 @@ class Project < ApplicationRecord
ci_cd_settings.keep_latest_artifact?
end
- def runner_token_expiration_interval
- ci_cd_settings&.runner_token_expiration_interval
- end
-
def group_runners_enabled?
return false unless ci_cd_settings
@@ -3006,7 +2999,7 @@ class Project < ApplicationRecord
end
def work_items_create_from_markdown_feature_flag_enabled?
- work_items_feature_flag_enabled? && (group&.work_items_create_from_markdown_feature_flag_enabled? || Feature.enabled?(:work_items_create_from_markdown))
+ group&.work_items_create_from_markdown_feature_flag_enabled? || Feature.enabled?(:work_items_create_from_markdown)
end
def enqueue_record_project_target_platforms
diff --git a/app/models/project_authorization.rb b/app/models/project_authorization.rb
index 8b43e5e5d63..3623b3be20d 100644
--- a/app/models/project_authorization.rb
+++ b/app/models/project_authorization.rb
@@ -31,6 +31,7 @@ class ProjectAuthorization < ApplicationRecord
def self.insert_all_in_batches(attributes, per_batch = BATCH_SIZE)
add_delay = add_delay_between_batches?(entire_size: attributes.size, batch_size: per_batch)
+ log_details(entire_size: attributes.size) if add_delay
attributes.each_slice(per_batch) do |attributes_batch|
insert_all(attributes_batch)
@@ -40,6 +41,7 @@ class ProjectAuthorization < ApplicationRecord
def self.delete_all_in_batches_for_project(project:, user_ids:, per_batch: BATCH_SIZE)
add_delay = add_delay_between_batches?(entire_size: user_ids.size, batch_size: per_batch)
+ log_details(entire_size: user_ids.size) if add_delay
user_ids.each_slice(per_batch) do |user_ids_batch|
project.project_authorizations.where(user_id: user_ids_batch).delete_all
@@ -49,6 +51,7 @@ class ProjectAuthorization < ApplicationRecord
def self.delete_all_in_batches_for_user(user:, project_ids:, per_batch: BATCH_SIZE)
add_delay = add_delay_between_batches?(entire_size: project_ids.size, batch_size: per_batch)
+ log_details(entire_size: project_ids.size) if add_delay
project_ids.each_slice(per_batch) do |project_ids_batch|
user.project_authorizations.where(project_id: project_ids_batch).delete_all
@@ -65,6 +68,13 @@ class ProjectAuthorization < ApplicationRecord
Feature.enabled?(:enable_minor_delay_during_project_authorizations_refresh)
end
+ private_class_method def self.log_details(entire_size:)
+ Gitlab::AppLogger.info(
+ entire_size: entire_size,
+ message: 'Project authorizations refresh performed with delay'
+ )
+ end
+
private_class_method def self.perform_delay
sleep(SLEEP_DELAY)
end
diff --git a/app/models/project_ci_cd_setting.rb b/app/models/project_ci_cd_setting.rb
index d7a5d0d9d84..cc9003423be 100644
--- a/app/models/project_ci_cd_setting.rb
+++ b/app/models/project_ci_cd_setting.rb
@@ -17,8 +17,8 @@ class ProjectCiCdSetting < ApplicationRecord
},
allow_nil: true
- default_value_for :forward_deployment_enabled, true
- default_value_for :separated_caches, true
+ attribute :forward_deployment_enabled, default: true
+ attribute :separated_caches, default: true
chronic_duration_attr :runner_token_expiration_interval_human_readable, :runner_token_expiration_interval
diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb
index dad8aaf0625..11f4a3f3b6f 100644
--- a/app/models/project_feature.rb
+++ b/app/models/project_feature.rb
@@ -25,6 +25,7 @@ class ProjectFeature < ApplicationRecord
environments
feature_flags
releases
+ infrastructure
].freeze
EXPORTABLE_FEATURES = (FEATURES - [:security_and_compliance, :pages]).freeze
diff --git a/app/models/project_setting.rb b/app/models/project_setting.rb
index 6d40544fad4..7116ccd9824 100644
--- a/app/models/project_setting.rb
+++ b/app/models/project_setting.rb
@@ -2,6 +2,7 @@
class ProjectSetting < ApplicationRecord
include ::Gitlab::Utils::StrongMemoize
+ include EachBatch
ALLOWED_TARGET_PLATFORMS = %w(ios osx tvos watchos android).freeze
@@ -20,12 +21,13 @@ class ProjectSetting < ApplicationRecord
validates :merge_commit_template, length: { maximum: Project::MAX_COMMIT_TEMPLATE_LENGTH }
validates :squash_commit_template, length: { maximum: Project::MAX_COMMIT_TEMPLATE_LENGTH }
+ validates :issue_branch_template, length: { maximum: Issue::MAX_BRANCH_TEMPLATE }
validates :target_platforms, inclusion: { in: ALLOWED_TARGET_PLATFORMS }
validates :suggested_reviewers_enabled, inclusion: { in: [true, false] }
validate :validates_mr_default_target_self
- default_value_for(:legacy_open_source_license_available) do
+ attribute :legacy_open_source_license_available, default: -> do
Feature.enabled?(:legacy_open_source_license_available, type: :ops)
end
@@ -57,7 +59,7 @@ class ProjectSetting < ApplicationRecord
!!super
end
end
- strong_memoize_attr :show_diff_preview_in_email
+ strong_memoize_attr :show_diff_preview_in_email?, :show_diff_preview_in_email
private
diff --git a/app/models/project_statistics.rb b/app/models/project_statistics.rb
index f108e43015e..0570be85ad1 100644
--- a/app/models/project_statistics.rb
+++ b/app/models/project_statistics.rb
@@ -7,8 +7,8 @@ class ProjectStatistics < ApplicationRecord
belongs_to :project
belongs_to :namespace
- default_value_for :wiki_size, 0
- default_value_for :snippets_size, 0
+ attribute :wiki_size, default: 0
+ attribute :snippets_size, default: 0
counter_attribute :build_artifacts_size
@@ -95,8 +95,7 @@ class ProjectStatistics < ApplicationRecord
# and the column can be nil.
# This means that, when the columns were added, all rows had nil
# values on them.
- # Therefore, any call to any of those methods will return nil instead
- # of 0, because `default_value_for` works with new records, not existing ones.
+ # Therefore, any call to any of those methods will return nil instead of 0.
#
# These two methods provide consistency and avoid returning nil.
def wiki_size
diff --git a/app/models/projects/import_export/relation_export.rb b/app/models/projects/import_export/relation_export.rb
index 15198049f87..9bdf10d7c0e 100644
--- a/app/models/projects/import_export/relation_export.rb
+++ b/app/models/projects/import_export/relation_export.rb
@@ -34,11 +34,18 @@ module Projects
scope :by_relation, -> (relation) { where(relation: relation) }
+ STATUS = {
+ queued: 0,
+ started: 1,
+ finished: 2,
+ failed: 3
+ }.freeze
+
state_machine :status, initial: :queued do
- state :queued, value: 0
- state :started, value: 1
- state :finished, value: 2
- state :failed, value: 3
+ state :queued, value: STATUS[:queued]
+ state :started, value: STATUS[:started]
+ state :finished, value: STATUS[:finished]
+ state :failed, value: STATUS[:failed]
event :start do
transition queued: :started
diff --git a/app/models/projects/wiki_repository.rb b/app/models/projects/wiki_repository.rb
new file mode 100644
index 00000000000..88382adbcb7
--- /dev/null
+++ b/app/models/projects/wiki_repository.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Projects
+ class WikiRepository < ApplicationRecord
+ self.table_name = :project_wiki_repositories
+
+ belongs_to :project, inverse_of: :wiki_repository
+
+ validates :project, presence: true, uniqueness: true
+ end
+end
+
+Projects::WikiRepository.prepend_mod_with('Projects::WikiRepository')
diff --git a/app/models/protected_branch.rb b/app/models/protected_branch.rb
index dfd5c315f6e..80967c1b072 100644
--- a/app/models/protected_branch.rb
+++ b/app/models/protected_branch.rb
@@ -4,6 +4,10 @@ class ProtectedBranch < ApplicationRecord
include ProtectedRef
include Gitlab::SQL::Pattern
+ belongs_to :group, foreign_key: :namespace_id, touch: true, inverse_of: :protected_branches
+
+ validate :validate_either_project_or_top_group
+
scope :requiring_code_owner_approval,
-> { where(code_owner_approval_required: true) }
@@ -99,6 +103,18 @@ class ProtectedBranch < ApplicationRecord
def default_branch?
name == project.default_branch
end
+
+ private
+
+ def validate_either_project_or_top_group
+ if !project && !group
+ errors.add(:base, _('must be associated with a Group or a Project'))
+ elsif project && group
+ errors.add(:base, _('cannot be associated with both a Group and a Project'))
+ elsif group && group.root_ancestor != group
+ errors.add(:base, _('cannot be associated with a subgroup'))
+ end
+ end
end
ProtectedBranch.prepend_mod_with('ProtectedBranch')
diff --git a/app/models/protected_tag.rb b/app/models/protected_tag.rb
index 5b2467daddc..e89cb3aabc7 100644
--- a/app/models/protected_tag.rb
+++ b/app/models/protected_tag.rb
@@ -4,6 +4,7 @@ class ProtectedTag < ApplicationRecord
include ProtectedRef
validates :name, uniqueness: { scope: :project_id }
+ validates :project, presence: true
protected_ref_access_levels :create
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 3413b3e3424..95d1b815e74 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -98,6 +98,10 @@ class Repository
alias_method :raw, :raw_repository
+ def flipper_id
+ raw_repository.flipper_id
+ end
+
# Don't use this! It's going away. Use Gitaly to read or write from repos.
def path_to_repo
@path_to_repo ||=
@@ -1232,7 +1236,8 @@ class Repository
Gitlab::Git::Repository.new(shard,
disk_path + '.git',
repo_type.identifier_for_container(container),
- container.full_path)
+ container.full_path,
+ container: container)
end
end
diff --git a/app/models/serverless/domain_cluster.rb b/app/models/serverless/domain_cluster.rb
index 1effabf1c22..561bfc65b2b 100644
--- a/app/models/serverless/domain_cluster.rb
+++ b/app/models/serverless/domain_cluster.rb
@@ -19,7 +19,7 @@ module Serverless
validates :uuid, presence: true, uniqueness: true, length: { is: ::Serverless::Domain::UUID_LENGTH },
format: { with: HEX_REGEXP, message: 'only allows hex characters' }
- default_value_for(:uuid, allows_nil: false) { ::Serverless::Domain.generate_uuid }
+ after_initialize :set_uuid, if: :new_record?
delegate :domain, to: :pages_domain
delegate :cluster, to: :knative
@@ -29,5 +29,11 @@ module Serverless
.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/terraform/state.rb b/app/models/terraform/state.rb
index e5c8f4ab32a..8a207c891e2 100644
--- a/app/models/terraform/state.rb
+++ b/app/models/terraform/state.rb
@@ -28,7 +28,7 @@ module Terraform
validates :uuid, presence: true, uniqueness: true, length: { is: UUID_LENGTH },
format: { with: HEX_REGEXP, message: 'only allows hex characters' }
- default_value_for(:uuid, allows_nil: false) { SecureRandom.hex(UUID_LENGTH / 2) }
+ attribute :uuid, default: -> { SecureRandom.hex(UUID_LENGTH / 2) }
def latest_file
latest_version&.file
diff --git a/app/models/terraform/state_version.rb b/app/models/terraform/state_version.rb
index c50eaa66860..d6a16ad5b99 100644
--- a/app/models/terraform/state_version.rb
+++ b/app/models/terraform/state_version.rb
@@ -13,7 +13,7 @@ module Terraform
scope :with_files_stored_locally, -> { where(file_store: Terraform::StateUploader::Store::LOCAL) }
scope :preload_state, -> { includes(:terraform_state) }
- default_value_for(:file_store) { StateUploader.default_store }
+ attribute :file_store, default: -> { StateUploader.default_store }
mount_file_store_uploader StateUploader
diff --git a/app/models/time_tracking/timelog_category.rb b/app/models/time_tracking/timelog_category.rb
index 26614f6fc44..246e78f31cb 100644
--- a/app/models/time_tracking/timelog_category.rb
+++ b/app/models/time_tracking/timelog_category.rb
@@ -24,8 +24,7 @@ module TimeTracking
DEFAULT_COLOR = ::Gitlab::Color.of('#6699cc')
- attribute :color, ::Gitlab::Database::Type::Color.new
- default_value_for :color, DEFAULT_COLOR
+ attribute :color, ::Gitlab::Database::Type::Color.new, default: DEFAULT_COLOR
def self.find_by_name(namespace_id, name)
where(namespace: namespace_id)
diff --git a/app/models/todo.rb b/app/models/todo.rb
index 634fa9e7eda..f2fa0df852a 100644
--- a/app/models/todo.rb
+++ b/app/models/todo.rb
@@ -94,7 +94,7 @@ class Todo < ApplicationRecord
#
# Returns an `ActiveRecord::Relation`.
def for_group_ids_and_descendants(group_ids)
- groups = Group.groups_including_descendants_by(group_ids)
+ groups = Group.where(id: group_ids).self_and_descendants
from_union(
[
diff --git a/app/models/user.rb b/app/models/user.rb
index 6d198fc755b..24f947183a2 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -83,7 +83,10 @@ class User < ApplicationRecord
serialize :otp_backup_codes, JSON # rubocop:disable Cop/ActiveRecordSerialize
devise :lockable, :recoverable, :rememberable, :trackable,
- :validatable, :omniauthable, :confirmable, :registerable, :pbkdf2_encryptable
+ :validatable, :omniauthable, :confirmable, :registerable
+
+ # Must be included after `devise`
+ include EncryptedUserPassword
include AdminChangedPasswordNotifier
@@ -185,7 +188,7 @@ class User < ApplicationRecord
has_many :personal_projects, through: :namespace, source: :projects
has_many :project_members, -> { where(requested_at: nil) }
has_many :projects, through: :project_members
- has_many :created_projects, foreign_key: :creator_id, class_name: 'Project'
+ has_many :created_projects, foreign_key: :creator_id, class_name: 'Project', dependent: :nullify # rubocop:disable Cop/ActiveRecordDependent
has_many :projects_with_active_memberships, -> { where(members: { state: ::Member::STATE_ACTIVE }) }, through: :project_members, source: :project
has_many :users_star_projects, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :starred_projects, through: :users_star_projects, source: :project
@@ -258,6 +261,8 @@ class User < ApplicationRecord
has_many :resource_state_events, dependent: :nullify # rubocop:disable Cop/ActiveRecordDependent
has_many :authored_events, class_name: 'Event', dependent: :destroy, foreign_key: :author_id # rubocop:disable Cop/ActiveRecordDependent
+ has_many :namespace_commit_emails
+
#
# Validations
#
@@ -420,10 +425,6 @@ class User < ApplicationRecord
end
# rubocop: disable CodeReuse/ServiceClass
- # Ideally we should not call a service object here but user.block
- # is also called by Users::MigrateToGhostUserService which references
- # this state transition object in order to do a rollback.
- # For this reason the tradeoff is to disable this cop.
after_transition any => :blocked do |user|
user.run_after_commit do
Ci::DropPipelineService.new.execute_async_for_all(user.pipelines, :user_blocked, user)
@@ -447,6 +448,14 @@ class User < ApplicationRecord
after_transition banned: :active do |user|
user.banned_user&.destroy
end
+
+ after_transition any => :active do |user|
+ user.starred_projects.update_counters(star_count: 1)
+ end
+
+ after_transition active: any do |user|
+ user.starred_projects.update_counters(star_count: -1)
+ end
end
# Scopes
@@ -693,6 +702,8 @@ class User < ApplicationRecord
#
# Returns an ActiveRecord::Relation.
def search(query, **options)
+ return none unless query.is_a?(String)
+
query = query&.delete_prefix('@')
return none if query.blank?
@@ -937,26 +948,14 @@ class User < ApplicationRecord
reset_password_sent_at.present? && reset_password_sent_at >= 1.minute.ago
end
- def authenticatable_salt
- return encrypted_password[0, 29] unless Feature.enabled?(:pbkdf2_password_encryption)
- return super if password_strategy == :pbkdf2_sha512
-
- encrypted_password[0, 29]
- end
-
# Overwrites valid_password? from Devise::Models::DatabaseAuthenticatable
# In constant-time, check both that the password isn't on a denylist AND
# that the password is the user's password
def valid_password?(password)
return false unless password_allowed?(password)
return false if password_automatically_set?
- return super if Feature.enabled?(:pbkdf2_password_encryption)
- Devise::Encryptor.compare(self.class, encrypted_password, password)
- rescue Devise::Pbkdf2Encryptable::Encryptors::InvalidHash
- validate_and_migrate_bcrypt_password(password)
- rescue ::BCrypt::Errors::InvalidHash
- false
+ super
end
def generate_otp_backup_codes!
@@ -975,27 +974,6 @@ class User < ApplicationRecord
end
end
- # This method should be removed once the :pbkdf2_password_encryption feature flag is removed.
- def password=(new_password)
- if Feature.enabled?(:pbkdf2_password_encryption) && Feature.enabled?(:pbkdf2_password_encryption_write, self)
- super
- else
- # Copied from Devise DatabaseAuthenticatable.
- @password = new_password
- self.encrypted_password = Devise::Encryptor.digest(self.class, new_password) if new_password.present?
- end
- end
-
- def password_strategy
- super
- rescue Devise::Pbkdf2Encryptable::Encryptors::InvalidHash
- begin
- return :bcrypt if BCrypt::Password.new(encrypted_password)
- rescue BCrypt::Errors::InvalidHash
- :unknown
- end
- end
-
# See https://gitlab.com/gitlab-org/security/gitlab/-/issues/638
DISALLOWED_PASSWORDS = %w[123qweQWE!@#000000000].freeze
@@ -1224,6 +1202,10 @@ class User < ApplicationRecord
authorized_projects(Gitlab::Access::REPORTER).non_archived.with_issues_enabled
end
+ def preloaded_member_roles_for_projects(projects)
+ # overridden in EE
+ end
+
# rubocop: disable CodeReuse/ServiceClass
def require_ssh_key?
count = Users::KeysCountService.new(self).count
@@ -1786,7 +1768,7 @@ class User < ApplicationRecord
end
def owns_runner?(runner)
- ci_owned_runners.exists?(runner.id)
+ ci_owned_runners.include?(runner)
end
def notification_email_for(notification_group)
@@ -2440,15 +2422,6 @@ class User < ApplicationRecord
Ci::NamespaceMirror.contains_traversal_ids(traversal_ids)
end
-
- def validate_and_migrate_bcrypt_password(password)
- return false unless Devise::Encryptor.compare(self.class, encrypted_password, password)
- return true unless Feature.enabled?(:pbkdf2_password_encryption_write, self)
-
- update_attribute(:password, password)
- rescue ::BCrypt::Errors::InvalidHash
- false
- end
end
User.prepend_mod_with('User')
diff --git a/app/models/users/callout.rb b/app/models/users/callout.rb
index ae6950d800c..b037d07658d 100644
--- a/app/models/users/callout.rb
+++ b/app/models/users/callout.rb
@@ -62,7 +62,8 @@ module Users
namespace_storage_limit_banner_error_threshold: 58, # EE-only
project_quality_summary_feedback: 59, # EE-only
merge_request_settings_moved_callout: 60,
- new_top_level_group_alert: 61
+ new_top_level_group_alert: 61,
+ artifacts_management_page_feedback_banner: 62
}
validates :feature_name,
diff --git a/app/models/users/ghost_user_migration.rb b/app/models/users/ghost_user_migration.rb
index 1d93498e88b..4578e0503c3 100644
--- a/app/models/users/ghost_user_migration.rb
+++ b/app/models/users/ghost_user_migration.rb
@@ -8,5 +8,7 @@ module Users
belongs_to :initiator_user, class_name: 'User'
validates :user_id, presence: true
+
+ scope :consume_order, -> { order(:consume_after, :id) }
end
end
diff --git a/app/models/users/namespace_commit_email.rb b/app/models/users/namespace_commit_email.rb
new file mode 100644
index 00000000000..4ec02f12717
--- /dev/null
+++ b/app/models/users/namespace_commit_email.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+module Users
+ class NamespaceCommitEmail < ApplicationRecord
+ belongs_to :user
+ belongs_to :namespace
+ belongs_to :email
+
+ validates :user, presence: true
+ validates :namespace, presence: true
+ validates :email, presence: true
+ validates :user_id, uniqueness: { scope: [:namespace_id] }
+ end
+end
diff --git a/app/models/users_star_project.rb b/app/models/users_star_project.rb
index 9a514b82506..6cffc97822d 100644
--- a/app/models/users_star_project.rb
+++ b/app/models/users_star_project.rb
@@ -3,7 +3,7 @@
class UsersStarProject < ApplicationRecord
include Sortable
- belongs_to :project, counter_cache: :star_count
+ belongs_to :project
belongs_to :user
validates :user, presence: true
@@ -12,6 +12,10 @@ class UsersStarProject < ApplicationRecord
alias_attribute :starred_since, :created_at
+ after_create :increment_project_star_count
+ after_destroy :decrement_project_star_count
+
+ scope :with_active_user, -> { joins(:user).merge(User.with_state(:active)) }
scope :order_user_name_asc, -> { joins(:user).merge(User.order_name_asc) }
scope :order_user_name_desc, -> { joins(:user).merge(User.order_name_desc) }
scope :by_project, -> (project) { where(project_id: project.id) }
@@ -35,4 +39,14 @@ class UsersStarProject < ApplicationRecord
joins(:user).merge(User.search(query, use_minimum_char_limit: false))
end
end
+
+ private
+
+ def increment_project_star_count
+ Project.update_counters(project, star_count: 1) if user.active?
+ end
+
+ def decrement_project_star_count
+ Project.update_counters(project, star_count: -1) if user.active?
+ end
end
diff --git a/app/models/wiki.rb b/app/models/wiki.rb
index b718c3a096f..57488749b76 100644
--- a/app/models/wiki.rb
+++ b/app/models/wiki.rb
@@ -190,7 +190,7 @@ class Wiki
end
def empty?
- !repository_exists? || list_page_paths.empty?
+ !repository_exists? || list_page_paths(limit: 1).empty?
end
def exists?
@@ -207,9 +207,29 @@ class Wiki
#
# Returns an Array of GitLab WikiPage instances or an
# empty Array if this Wiki has no pages.
- def list_pages(limit: 0, direction: DIRECTION_ASC, load_content: false)
+ def list_pages(direction: DIRECTION_ASC, load_content: false, limit: 0, offset: 0)
create_wiki_repository unless repository_exists?
- list_pages_with_repository_rpcs(limit: limit, direction: direction, load_content: load_content)
+
+ paths = list_page_paths(limit: limit, offset: offset)
+ return [] if paths.empty?
+
+ pages = paths.map do |path|
+ page = Gitlab::Git::WikiPage.new(
+ url_path: sluggified_title(strip_extension(path)),
+ title: canonicalize_filename(path),
+ format: find_page_format(path),
+ path: sluggified_title(path),
+ raw_data: '',
+ name: canonicalize_filename(path),
+ historical: false
+ )
+ WikiPage.new(self, page)
+ end
+ sort_pages!(pages, direction)
+ pages = pages.take(limit) if limit > 0
+ fetch_pages_content!(pages) if load_content
+
+ pages
end
def sidebar_entries(limit: Gitlab::WikiPages::MAX_SIDEBAR_PAGES, **options)
@@ -229,7 +249,27 @@ class Wiki
# Returns an initialized WikiPage instance or nil
def find_page(title, version = nil, load_content: true)
create_wiki_repository unless repository_exists?
- find_page_with_repository_rpcs(title, version, load_content: load_content)
+
+ version = version.presence || default_branch
+ path = find_matched_file(title, version)
+ return if path.blank?
+
+ blob_options = load_content ? {} : { limit: 0 }
+ blob = repository.blob_at(version, path, **blob_options)
+ commit = repository.commit(blob.commit_id)
+ format = find_page_format(path)
+
+ page = Gitlab::Git::WikiPage.new(
+ url_path: sluggified_title(strip_extension(path)),
+ title: canonicalize_filename(path),
+ format: format,
+ path: sluggified_title(path),
+ raw_data: blob.data,
+ name: canonicalize_filename(path),
+ historical: version == default_branch ? false : check_page_historical(path, commit),
+ version: Gitlab::Git::WikiPageVersion.new(commit, format)
+ )
+ WikiPage.new(self, page)
end
def find_sidebar(version = nil)
@@ -315,12 +355,6 @@ class Wiki
[title, title_array.join("/")]
end
- # TODO: This method is redundant. Should be replaced by create_wiki_repository
- def ensure_repository
- create_wiki_repository
- raise CouldNotCreateWikiError unless repository_exists?
- end
-
def hook_attrs
{
web_url: web_url,
@@ -457,7 +491,7 @@ class Wiki
escaped_path = RE2::Regexp.escape(sluggified_title(title))
path_regexp = Gitlab::EncodingHelper.encode_utf8_no_detect("(?i)^#{escaped_path}\\.(#{file_extension_regexp})$")
- matched_files = repository.search_files_by_regexp(path_regexp, version)
+ matched_files = repository.search_files_by_regexp(path_regexp, version, limit: 1)
return if matched_files.blank?
Gitlab::EncodingHelper.encode_utf8_no_detect(matched_files.first)
@@ -472,29 +506,6 @@ class Wiki
repository.last_commit_for_path(default_branch, path)&.id != commit&.id
end
- def find_page_with_repository_rpcs(title, version, load_content: true)
- version = version.presence || default_branch
- path = find_matched_file(title, version)
- return if path.blank?
-
- blob_options = load_content ? {} : { limit: 0 }
- blob = repository.blob_at(version, path, **blob_options)
- commit = repository.commit(blob.commit_id)
- format = find_page_format(path)
-
- page = Gitlab::Git::WikiPage.new(
- url_path: sluggified_title(strip_extension(path)),
- title: canonicalize_filename(path),
- format: format,
- path: sluggified_title(path),
- raw_data: blob.data,
- name: canonicalize_filename(path),
- historical: version == default_branch ? false : check_page_historical(path, commit),
- version: Gitlab::Git::WikiPageVersion.new(commit, format)
- )
- WikiPage.new(self, page)
- end
-
def file_extension_regexp
# We could not use ALLOWED_EXTENSIONS_REGEX constant or similar regexp with
# Regexp.union. The result combination complicated modifiers:
@@ -509,34 +520,11 @@ class Wiki
path.sub(/\.[^.]+\z/, "")
end
- def list_page_paths
+ def list_page_paths(limit: 0, offset: 0)
return [] if repository.empty?
path_regexp = Gitlab::EncodingHelper.encode_utf8_no_detect("(?i)\\.(#{file_extension_regexp})$")
- repository.search_files_by_regexp(path_regexp, default_branch)
- end
-
- def list_pages_with_repository_rpcs(limit:, direction:, load_content:)
- paths = list_page_paths
- return [] if paths.empty?
-
- pages = paths.map do |path|
- page = Gitlab::Git::WikiPage.new(
- url_path: sluggified_title(strip_extension(path)),
- title: canonicalize_filename(path),
- format: find_page_format(path),
- path: sluggified_title(path),
- raw_data: '',
- name: canonicalize_filename(path),
- historical: false
- )
- WikiPage.new(self, page)
- end
- sort_pages!(pages, direction)
- pages = pages.take(limit) if limit > 0
- fetch_pages_content!(pages) if load_content
-
- pages
+ repository.search_files_by_regexp(path_regexp, default_branch, limit: limit, offset: offset)
end
# After migrating to normal repository RPCs, it's very expensive to sort the
@@ -552,7 +540,7 @@ class Wiki
def fetch_pages_content!(pages)
blobs =
repository
- .blobs_at(pages.map { |page| [default_branch, page.path] } )
+ .blobs_at(pages.map { |page| [default_branch, page.path] })
.to_h { |blob| [blob.path, blob.data] }
pages.each do |page|
diff --git a/app/models/work_item.rb b/app/models/work_item.rb
index 05e45fa5b29..ed6f9d161a6 100644
--- a/app/models/work_item.rb
+++ b/app/models/work_item.rb
@@ -16,8 +16,14 @@ class WorkItem < Issue
scope :inc_relations_for_permission_check, -> { includes(:author, project: :project_feature) }
- def self.assignee_association_name
- 'issue'
+ class << self
+ def assignee_association_name
+ 'issue'
+ end
+
+ def test_reports_join_column
+ 'issues.id'
+ end
end
def noteable_target_type_name
diff --git a/app/models/work_items/type.rb b/app/models/work_items/type.rb
index 753fcbcb8f9..dc30899d24f 100644
--- a/app/models/work_items/type.rb
+++ b/app/models/work_items/type.rb
@@ -12,20 +12,27 @@ module WorkItems
# Base types need to exist on the DB on app startup
# This constant is used by the DB seeder
+ # TODO - where to add new icon names created?
BASE_TYPES = {
issue: { name: 'Issue', icon_name: 'issue-type-issue', enum_value: 0 },
incident: { name: 'Incident', icon_name: 'issue-type-incident', enum_value: 1 },
test_case: { name: 'Test Case', icon_name: 'issue-type-test-case', enum_value: 2 }, ## EE-only
requirement: { name: 'Requirement', icon_name: 'issue-type-requirements', enum_value: 3 }, ## EE-only
- task: { name: 'Task', icon_name: 'issue-type-task', enum_value: 4 }
+ task: { name: 'Task', icon_name: 'issue-type-task', enum_value: 4 },
+ objective: { name: 'Objective', icon_name: 'issue-type-objective', enum_value: 5 }, ## EE-only
+ key_result: { name: 'Key Result', icon_name: 'issue-type-keyresult', enum_value: 6 } ## EE-only
}.freeze
WIDGETS_FOR_TYPE = {
- issue: [Widgets::Assignees, Widgets::Labels, Widgets::Description, Widgets::Hierarchy, Widgets::StartAndDueDate],
+ issue: [Widgets::Assignees, Widgets::Labels, Widgets::Description, Widgets::Hierarchy, Widgets::StartAndDueDate,
+ Widgets::Milestone],
incident: [Widgets::Description, Widgets::Hierarchy],
test_case: [Widgets::Description],
requirement: [Widgets::Description],
- task: [Widgets::Assignees, Widgets::Labels, Widgets::Description, Widgets::Hierarchy, Widgets::StartAndDueDate]
+ task: [Widgets::Assignees, Widgets::Labels, Widgets::Description, Widgets::Hierarchy, Widgets::StartAndDueDate,
+ Widgets::Milestone],
+ objective: [Widgets::Assignees, Widgets::Labels, Widgets::Description, Widgets::Hierarchy, Widgets::Milestone],
+ key_result: [Widgets::Assignees, Widgets::Labels, Widgets::Description, Widgets::StartAndDueDate]
}.freeze
WI_TYPES_WITH_CREATED_HEADER = %w[issue incident].freeze
@@ -67,7 +74,7 @@ module WorkItems
end
def self.allowed_types_for_issues
- base_types.keys.excluding('task')
+ base_types.keys.excluding('task', 'objective', 'key_result')
end
def default?
diff --git a/app/models/work_items/widgets/hierarchy.rb b/app/models/work_items/widgets/hierarchy.rb
index 930aced8ace..d0819076efd 100644
--- a/app/models/work_items/widgets/hierarchy.rb
+++ b/app/models/work_items/widgets/hierarchy.rb
@@ -4,14 +4,10 @@ module WorkItems
module Widgets
class Hierarchy < Base
def parent
- return unless work_item.project.work_items_feature_flag_enabled?
-
work_item.work_item_parent
end
def children
- return WorkItem.none unless work_item.project.work_items_feature_flag_enabled?
-
work_item.work_item_children
end
end
diff --git a/app/models/work_items/widgets/milestone.rb b/app/models/work_items/widgets/milestone.rb
new file mode 100644
index 00000000000..a3e610110f1
--- /dev/null
+++ b/app/models/work_items/widgets/milestone.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module WorkItems
+ module Widgets
+ class Milestone < Base
+ delegate :milestone, to: :work_item
+ end
+ end
+end
diff --git a/app/policies/blob_policy.rb b/app/policies/blob_policy.rb
index 639b9dfeea7..8220b035603 100644
--- a/app/policies/blob_policy.rb
+++ b/app/policies/blob_policy.rb
@@ -3,5 +3,5 @@
class BlobPolicy < BasePolicy
delegate { @subject.project }
- rule { can?(:download_code) }.enable :read_blob
+ rule { can?(:read_code) }.enable :read_blob
end
diff --git a/app/policies/ci/build_policy.rb b/app/policies/ci/build_policy.rb
index b657b569e3e..5ef926ef2e3 100644
--- a/app/policies/ci/build_policy.rb
+++ b/app/policies/ci/build_policy.rb
@@ -27,8 +27,8 @@ module Ci
false
end
- condition(:prevent_rollback) do
- @subject.prevent_rollback_deployment?
+ condition(:outdated_deployment) do
+ @subject.outdated_deployment?
end
condition(:owner_of_job) do
@@ -77,12 +77,14 @@ module Ci
# Authorizing the user to access to protected entities.
# There is a "jailbreak" mode to exceptionally bypass the authorization,
# however, you should NEVER allow it, rather suspect it's a wrong feature/product design.
- rule { ~can?(:jailbreak) & (archived | protected_ref | protected_environment | prevent_rollback) }.policy do
+ rule { ~can?(:jailbreak) & (archived | protected_ref | protected_environment) }.policy do
prevent :update_build
prevent :update_commit_status
prevent :erase_build
end
+ rule { outdated_deployment }.prevent :update_build
+
rule { can?(:admin_build) | (can?(:update_build) & owner_of_job & unprotected_ref) }.enable :erase_build
rule { can?(:public_access) & branch_allows_collaboration }.policy do
diff --git a/app/policies/commit_policy.rb b/app/policies/commit_policy.rb
index 4b358c45ec2..66ec2c5ce56 100644
--- a/app/policies/commit_policy.rb
+++ b/app/policies/commit_policy.rb
@@ -3,6 +3,6 @@
class CommitPolicy < BasePolicy
delegate { @subject.project }
- rule { can?(:download_code) }.enable :read_commit
+ rule { can?(:read_code) }.enable :read_commit
rule { ~can?(:read_commit) }.prevent :create_note
end
diff --git a/app/policies/commit_signatures/gpg_signature_policy.rb b/app/policies/commit_signatures/gpg_signature_policy.rb
new file mode 100644
index 00000000000..518a289c1f3
--- /dev/null
+++ b/app/policies/commit_signatures/gpg_signature_policy.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module CommitSignatures
+ class GpgSignaturePolicy < BasePolicy
+ delegate { @subject.project }
+ end
+end
diff --git a/app/policies/commit_signatures/x509_commit_signature_policy.rb b/app/policies/commit_signatures/x509_commit_signature_policy.rb
new file mode 100644
index 00000000000..6b2477797fc
--- /dev/null
+++ b/app/policies/commit_signatures/x509_commit_signature_policy.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module CommitSignatures
+ class X509CommitSignaturePolicy < BasePolicy
+ delegate { @subject.project }
+ end
+end
diff --git a/app/policies/concerns/member_policy_helpers.rb b/app/policies/concerns/member_policy_helpers.rb
new file mode 100644
index 00000000000..6c4a3caf8bf
--- /dev/null
+++ b/app/policies/concerns/member_policy_helpers.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module MemberPolicyHelpers
+ extend ActiveSupport::Concern
+
+ private
+
+ def record_is_access_request_of_self?
+ record_is_access_request? && record_belongs_to_self?
+ end
+
+ def record_is_access_request?
+ @subject.request? # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ end
+
+ def record_belongs_to_self?
+ @user && @subject.user == @user # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ end
+end
diff --git a/app/policies/global_policy.rb b/app/policies/global_policy.rb
index 406144b7a5c..fa7b117f3cd 100644
--- a/app/policies/global_policy.rb
+++ b/app/policies/global_policy.rb
@@ -120,8 +120,6 @@ class GlobalPolicy < BasePolicy
# We can't use `read_statistics` because the user may have different permissions for different projects
rule { admin }.enable :use_project_statistics_filters
- rule { admin }.enable :delete_runners
-
rule { external_user }.prevent :create_snippet
end
diff --git a/app/policies/group_member_policy.rb b/app/policies/group_member_policy.rb
index a394b63fc8e..f61f758a8e8 100644
--- a/app/policies/group_member_policy.rb
+++ b/app/policies/group_member_policy.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class GroupMemberPolicy < BasePolicy
+ include MemberPolicyHelpers
+
delegate :group
with_scope :subject
@@ -9,7 +11,11 @@ class GroupMemberPolicy < BasePolicy
desc "Membership is users' own"
with_score 0
- condition(:is_target_user) { @user && @subject.user_id == @user.id }
+ condition(:target_is_self) { record_belongs_to_self? }
+
+ desc "Membership is users' own access request"
+ with_score 0
+ condition(:access_request_of_self) { record_is_access_request_of_self? }
rule { anonymous }.policy do
prevent :update_group_member
@@ -28,9 +34,13 @@ class GroupMemberPolicy < BasePolicy
rule { project_bot & can?(:admin_group_member) }.enable :destroy_project_bot_member
- rule { is_target_user }.policy do
+ rule { target_is_self }.policy do
enable :destroy_group_member
end
+
+ rule { access_request_of_self }.policy do
+ enable :withdraw_member_access_request
+ end
end
GroupMemberPolicy.prepend_mod_with('GroupMemberPolicy')
diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb
index 7a0fb10928a..806c57bab74 100644
--- a/app/policies/group_policy.rb
+++ b/app/policies/group_policy.rb
@@ -22,7 +22,7 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
condition(:share_with_group_locked, scope: :subject) { @subject.share_with_group_lock? }
condition(:parent_share_with_group_locked, scope: :subject) { @subject.parent&.share_with_group_lock? }
condition(:can_change_parent_share_with_group_lock) { can?(:change_share_with_group_lock, @subject.parent) }
- condition(:migration_bot, scope: :user) { @user.migration_bot? }
+ condition(:migration_bot, scope: :user) { @user&.migration_bot? }
condition(:can_read_group_member) { can_read_group_member? }
desc "User is a project bot"
@@ -283,6 +283,11 @@ class GroupPolicy < Namespaces::GroupProjectNamespaceSharedPolicy
prevent :create_resource_access_tokens
end
+ rule { can?(:admin_group_member) }.policy do
+ # ability to read, approve or reject member access requests of other users
+ enable :admin_member_access_request
+ end
+
rule { support_bot & has_project_with_service_desk_enabled }.policy do
enable :read_label
end
diff --git a/app/policies/incident_management/timeline_event_tag_policy.rb b/app/policies/incident_management/timeline_event_tag_policy.rb
new file mode 100644
index 00000000000..e2268d917b4
--- /dev/null
+++ b/app/policies/incident_management/timeline_event_tag_policy.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+module IncidentManagement
+ class TimelineEventTagPolicy < ::BasePolicy
+ delegate { @subject.project }
+ end
+end
diff --git a/app/policies/issuable_policy.rb b/app/policies/issuable_policy.rb
index df065b24e64..aa07bb7dc5f 100644
--- a/app/policies/issuable_policy.rb
+++ b/app/policies/issuable_policy.rb
@@ -56,7 +56,7 @@ class IssuablePolicy < BasePolicy
end
# This rule replicates permissions in NotePolicy#can_read_confidential
- rule { can?(:reporter_access) | assignee_or_author | admin }.policy do
+ rule { can?(:reporter_access) | admin }.policy do
enable :read_internal_note
end
end
diff --git a/app/policies/note_policy.rb b/app/policies/note_policy.rb
index dbfc63a0069..67b57595beb 100644
--- a/app/policies/note_policy.rb
+++ b/app/policies/note_policy.rb
@@ -23,7 +23,7 @@ class NotePolicy < BasePolicy
# Should be matched with IssuablePolicy#read_internal_note
# and EpicPolicy#read_internal_note
condition(:can_read_confidential) do
- access_level >= Gitlab::Access::REPORTER || @subject.noteable_assignee_or_author?(@user) || admin?
+ access_level >= Gitlab::Access::REPORTER || admin?
end
rule { ~editable }.prevent :admin_note
diff --git a/app/policies/packages/policies/project_policy.rb b/app/policies/packages/policies/project_policy.rb
index c754d24349a..0fb5953f2aa 100644
--- a/app/policies/packages/policies/project_policy.rb
+++ b/app/policies/packages/policies/project_policy.rb
@@ -52,3 +52,5 @@ module Packages
end
end
end
+
+Packages::Policies::ProjectPolicy.prepend_mod_with('Packages::Policies::ProjectPolicy')
diff --git a/app/policies/project_member_policy.rb b/app/policies/project_member_policy.rb
index 40ba30fce5e..bcfc7c87d41 100644
--- a/app/policies/project_member_policy.rb
+++ b/app/policies/project_member_policy.rb
@@ -1,13 +1,18 @@
# frozen_string_literal: true
class ProjectMemberPolicy < BasePolicy
+ include MemberPolicyHelpers
delegate { @subject.project }
condition(:target_is_holder_of_the_personal_namespace, scope: :subject) do
@subject.project.personal_namespace_holder?(@subject.user)
end
- condition(:target_is_self) { @user && @subject.user == @user }
+ desc "Membership is users' own access request"
+ with_score 0
+ condition(:access_request_of_self) { record_is_access_request_of_self? }
+
+ condition(:target_is_self) { record_belongs_to_self? }
condition(:project_bot) { @subject.user&.project_bot? }
rule { anonymous }.prevent_all
@@ -24,5 +29,11 @@ class ProjectMemberPolicy < BasePolicy
rule { project_bot & can?(:admin_project_member) }.enable :destroy_project_bot_member
- rule { target_is_self }.enable :destroy_project_member
+ rule { target_is_self }.policy do
+ enable :destroy_project_member
+ end
+
+ rule { access_request_of_self }.policy do
+ enable :withdraw_member_access_request
+ end
end
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 77bdf9d62fc..bfeb1a602ab 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -195,8 +195,6 @@ class ProjectPolicy < BasePolicy
with_scope :subject
condition(:packages_disabled) { !@subject.packages_enabled }
- condition(:work_items_enabled, scope: :subject) { project&.work_items_feature_flag_enabled? }
-
features = %w[
merge_requests
issues
@@ -213,6 +211,7 @@ class ProjectPolicy < BasePolicy
environments
feature_flags
releases
+ infrastructure
]
features.each do |f|
@@ -255,7 +254,6 @@ class ProjectPolicy < BasePolicy
enable :change_namespace
enable :change_visibility_level
- enable :rename_project
enable :remove_project
enable :archive_project
enable :remove_fork_project
@@ -303,7 +301,7 @@ class ProjectPolicy < BasePolicy
rule { can?(:create_issue) }.enable :create_work_item
- rule { can?(:create_issue) & work_items_enabled }.enable :create_task
+ rule { can?(:create_issue) }.enable :create_task
# These abilities are not allowed to admins that are not members of the project,
# that's why they are defined separately.
@@ -409,6 +407,14 @@ class ProjectPolicy < BasePolicy
prevent(*create_read_update_admin_destroy(:alert_management_alert))
end
+ rule { split_operations_visibility_permissions & 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)
+ end
+
rule { can?(:metrics_dashboard) }.policy do
enable :read_prometheus
enable :read_deployment
@@ -490,6 +496,7 @@ class ProjectPolicy < BasePolicy
enable :push_to_delete_protected_branch
enable :update_snippet
enable :admin_snippet
+ enable :rename_project
enable :admin_project_member
enable :admin_note
enable :admin_wiki
@@ -530,6 +537,7 @@ class ProjectPolicy < BasePolicy
enable :read_web_hooks
enable :read_upload
enable :destroy_upload
+ enable :admin_incident_management_timeline_event_tag
end
rule { public_project & metrics_dashboard_allowed }.policy do
@@ -624,7 +632,6 @@ class ProjectPolicy < BasePolicy
prevent :read_commit_status
prevent :read_pipeline
prevent :read_pipeline_schedule
- prevent(*create_read_update_admin_destroy(:release))
prevent(*create_read_update_admin_destroy(:feature_flag))
prevent(:admin_feature_flags_user_lists)
end
@@ -729,6 +736,10 @@ class ProjectPolicy < BasePolicy
enable :read_work_item
end
+ rule { can?(:read_merge_request) }.policy do
+ enable :read_vulnerability_merge_request_link
+ end
+
rule { can?(:developer_access) }.policy do
enable :read_security_configuration
end
@@ -827,6 +838,8 @@ class ProjectPolicy < BasePolicy
rule { can?(:admin_project_member) }.policy do
enable :import_project_members_from_another_project
+ # ability to read, approve or reject member access requests of other users
+ enable :admin_member_access_request
end
rule { registry_enabled & can?(:admin_container_image) }.policy do
@@ -837,6 +850,14 @@ class ProjectPolicy < BasePolicy
enable :view_package_registry_project_settings
end
+ rule { can?(:read_project) }.policy do
+ enable :read_incident_management_timeline_event_tag
+ end
+
+ rule { can?(:download_code) }.policy do
+ enable :read_code
+ end
+
private
def user_is_user?
diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb
index f62ccef826c..4f3dafbf5c8 100644
--- a/app/policies/user_policy.rb
+++ b/app/policies/user_policy.rb
@@ -36,6 +36,7 @@ class UserPolicy < BasePolicy
rule { (private_profile | blocked_user | unconfirmed_user) & ~(user_is_self | admin) }.prevent :read_user_profile
rule { user_is_self | admin }.enable :disable_two_factor
rule { (user_is_self | admin) & ~blocked }.enable :create_user_personal_access_token
+ rule { (user_is_self | admin) & ~blocked }.enable :get_user_associations_count
end
UserPolicy.prepend_mod_with('UserPolicy')
diff --git a/app/presenters/blob_presenter.rb b/app/presenters/blob_presenter.rb
index 74ac47fa439..92dcfeed104 100644
--- a/app/presenters/blob_presenter.rb
+++ b/app/presenters/blob_presenter.rb
@@ -9,6 +9,19 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
presents ::Blob, as: :blob
+ def highlight_and_trim(ellipsis_svg:, trim_length:, plain: nil)
+ load_all_blob_data
+
+ trimmed_lines, trimmed_idx = trimmed_blob_data(trim_length)
+ Gitlab::Highlight.highlight(
+ blob.path,
+ trimmed_lines,
+ language: blob_language,
+ plain: plain,
+ context: { ellipsis_indexes: trimmed_idx, ellipsis_svg: ellipsis_svg }
+ )
+ end
+
def highlight(to: nil, plain: nil)
load_all_blob_data
@@ -26,6 +39,10 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
highlight(plain: false)
end
+ def trimmed_blob_data(trim_length)
+ @_trimmed_blob_data ||= limited_trimmed_blob_data(trim_length)
+ end
+
def blob_data(to)
@_blob_data ||= limited_blob_data(to: to)
end
@@ -169,6 +186,19 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated
blob.load_all_data! if blob.respond_to?(:load_all_data!)
end
+ def limited_trimmed_blob_data(trim_length)
+ trimmed_idx = []
+
+ trimmed_lines = all_lines.map.with_index do |line, index|
+ next line if line.length <= trim_length
+
+ trimmed_idx << index
+ "#{line[0, trim_length]}\n"
+ end
+
+ [trimmed_lines.join, trimmed_idx]
+ end
+
def limited_blob_data(to: nil)
return blob.data if to.blank?
diff --git a/app/presenters/ci/build_runner_presenter.rb b/app/presenters/ci/build_runner_presenter.rb
index 706608e3029..7242a80b924 100644
--- a/app/presenters/ci/build_runner_presenter.rb
+++ b/app/presenters/ci/build_runner_presenter.rb
@@ -33,9 +33,13 @@ module Ci
end
def runner_variables
- stop_expanding_file_vars = ::Feature.enabled?(:ci_stop_expanding_file_vars_for_runners, project)
+ stop_expanding_raw_refs = ::Feature.enabled?(:ci_raw_variables_in_yaml_config, project)
+
variables
- .sort_and_expand_all(keep_undefined: true, expand_file_vars: !stop_expanding_file_vars, project: project)
+ .sort_and_expand_all(keep_undefined: true,
+ expand_file_refs: false,
+ expand_raw_refs: !stop_expanding_raw_refs,
+ project: project)
.to_runner_variables
end
diff --git a/app/presenters/ci/pipeline_presenter.rb b/app/presenters/ci/pipeline_presenter.rb
index fed4ae7837b..aa0cd476191 100644
--- a/app/presenters/ci/pipeline_presenter.rb
+++ b/app/presenters/ci/pipeline_presenter.rb
@@ -53,7 +53,7 @@ module Ci
}.freeze
end
- def name
+ def event_type_name
# Currently, `merge_request_event_type` is the only source to name pipelines
# but this could be extended with the other types in the future.
localized_names.fetch(pipeline.merge_request_event_type, s_('Pipeline|Pipeline'))
diff --git a/app/presenters/commit_status_presenter.rb b/app/presenters/commit_status_presenter.rb
index 059d6d06be2..f6720546fab 100644
--- a/app/presenters/commit_status_presenter.rb
+++ b/app/presenters/commit_status_presenter.rb
@@ -41,7 +41,7 @@ class CommitStatusPresenter < Gitlab::View::Presenter::Delegated
TROUBLESHOOTING_DOC = {
environment_creation_failure: { path: 'ci/environments/index', anchor: 'a-deployment-job-failed-with-this-job-could-not-be-executed-because-it-would-create-an-environment-with-an-invalid-parameter-error' },
- failed_outdated_deployment_job: { path: 'ci/environments/deployment_safety', anchor: 'skip-outdated-deployment-jobs' }
+ failed_outdated_deployment_job: { path: 'ci/environments/deployment_safety', anchor: 'prevent-outdated-deployment-jobs' }
}.freeze
private_constant :CALLOUT_FAILURE_MESSAGES
diff --git a/app/presenters/deployments/deployment_presenter.rb b/app/presenters/deployments/deployment_presenter.rb
index 5ef6fcff974..478c7a85f90 100644
--- a/app/presenters/deployments/deployment_presenter.rb
+++ b/app/presenters/deployments/deployment_presenter.rb
@@ -5,11 +5,14 @@ module Deployments
presents ::Deployment, as: :deployment
delegator_override :tags
+
+ # Note: this returns the path key as 'tags/tag_name' but it is used as a URL in the UI
+
def tags
super.map do |tag|
{
- name: tag,
- path: "tags/#{tag}"
+ name: tag.delete_prefix(Gitlab::Git::TAG_REF_PREFIX),
+ path: tag.delete_prefix('refs/')
}
end
end
diff --git a/app/presenters/release_presenter.rb b/app/presenters/release_presenter.rb
index fc47ece6199..70fe6324712 100644
--- a/app/presenters/release_presenter.rb
+++ b/app/presenters/release_presenter.rb
@@ -4,13 +4,13 @@ class ReleasePresenter < Gitlab::View::Presenter::Delegated
presents ::Release, as: :release
def commit_path
- return unless release.commit && can_download_code?
+ return unless release.commit && can_read_code?
project_commit_path(project, release.commit.id)
end
def tag_path
- return unless can_download_code?
+ return unless can_read_code?
project_tag_path(project, release.tag)
end
@@ -47,7 +47,7 @@ class ReleasePresenter < Gitlab::View::Presenter::Delegated
delegator_override :assets_count
def assets_count
- if can_download_code?
+ if can_read_code?
release.assets_count
else
release.assets_count(except: [:sources])
@@ -67,8 +67,8 @@ class ReleasePresenter < Gitlab::View::Presenter::Delegated
private
- def can_download_code?
- can?(current_user, :download_code, project)
+ def can_read_code?
+ can?(current_user, :read_code, project)
end
def params_for_issues_and_mrs(state: 'opened')
diff --git a/app/serializers/ci/pipeline_entity.rb b/app/serializers/ci/pipeline_entity.rb
index 20aeb978520..143017c5159 100644
--- a/app/serializers/ci/pipeline_entity.rb
+++ b/app/serializers/ci/pipeline_entity.rb
@@ -4,12 +4,13 @@ class Ci::PipelineEntity < Grape::Entity
include RequestAwareEntity
include Gitlab::Utils::StrongMemoize
- delegate :name, :failure_reason, :coverage, to: :presented_pipeline
+ delegate :event_type_name, :failure_reason, :coverage, to: :presented_pipeline
expose :id
expose :iid
expose :user, using: UserEntity
expose :active?, as: :active
+ expose :name, if: -> (pipeline, _) { Feature.enabled?(:pipeline_name, pipeline.project) }
# Coverage isn't always necessary (e.g. when displaying project pipelines in
# the UI). Instead of creating an entirely different entity we just allow the
@@ -40,7 +41,8 @@ class Ci::PipelineEntity < Grape::Entity
expose :stages, using: StageEntity
expose :duration
expose :finished_at
- expose :name
+ expose :event_type_name
+ expose :event_type_name, as: :name # To be removed in 15.7
end
expose :merge_request, if: -> (*) { has_presentable_merge_request? }, with: MergeRequestForPipelineEntity do |pipeline|
diff --git a/app/serializers/codequality_degradation_entity.rb b/app/serializers/codequality_degradation_entity.rb
index 6289260465b..52945a753dc 100644
--- a/app/serializers/codequality_degradation_entity.rb
+++ b/app/serializers/codequality_degradation_entity.rb
@@ -13,4 +13,6 @@ class CodequalityDegradationEntity < Grape::Entity
expose :line do |degradation|
degradation.dig(:location, :lines, :begin) || degradation.dig(:location, :positions, :begin, :line)
end
+
+ expose :web_url
end
diff --git a/app/serializers/detailed_status_entity.rb b/app/serializers/detailed_status_entity.rb
index 4f23ef0ed82..ed8ac9f40f7 100644
--- a/app/serializers/detailed_status_entity.rb
+++ b/app/serializers/detailed_status_entity.rb
@@ -3,12 +3,25 @@
class DetailedStatusEntity < Grape::Entity
include RequestAwareEntity
- expose :icon, :text, :label, :group
- expose :status_tooltip, as: :tooltip
- expose :has_details?, as: :has_details
- expose :details_path
+ expose :icon, documentation: { type: 'string', example: 'status_success' }
+ expose :text, documentation: { type: 'string', example: 'passed' }
+ expose :label, documentation: { type: 'string', example: 'passed' }
+ expose :group, documentation: { type: 'string', example: 'success' }
+ expose :status_tooltip, as: :tooltip, documentation: { type: 'string', example: 'passed' }
+ expose :has_details?, as: :has_details, documentation: { type: 'boolean', example: true }
+ expose :details_path, documentation: { type: 'string', example: '/test-group/test-project/-/pipelines/287' }
- expose :illustration do |status|
+ expose :illustration, documentation: {
+ type: 'object',
+ example: <<~JSON
+ {
+ "image": "illustrations/job_not_triggered.svg",
+ "size": "svg-306",
+ "title": "This job has not been triggered yet",
+ "content": "This job depends on upstream jobs that need to succeed in order for this job to be triggered"
+ }
+ JSON
+ } do |status|
illustration = {
image: ActionController::Base.helpers.image_path(status.illustration[:image])
}
@@ -19,15 +32,17 @@ class DetailedStatusEntity < Grape::Entity
# ignored
end
- expose :favicon do |status|
+ expose :favicon,
+ documentation: { type: 'string',
+ example: '/assets/ci_favicons/favicon_status_success.png' } do |status|
Gitlab::Favicon.status_overlay(status.favicon)
end
expose :action, if: -> (status, _) { status.has_action? } do
- expose :action_icon, as: :icon
- expose :action_title, as: :title
- expose :action_path, as: :path
- expose :action_method, as: :method
- expose :action_button_title, as: :button_title
+ expose :action_icon, as: :icon, documentation: { type: 'string', example: 'cancel' }
+ expose :action_title, as: :title, documentation: { type: 'string', example: 'Cancel' }
+ expose :action_path, as: :path, documentation: { type: 'string', example: '/namespace1/project1/-/jobs/2/cancel' }
+ expose :action_method, as: :method, documentation: { type: 'string', example: 'post' }
+ expose :action_button_title, as: :button_title, documentation: { type: 'string', example: 'Cancel this job' }
end
end
diff --git a/app/serializers/diff_file_entity.rb b/app/serializers/diff_file_entity.rb
index 9f8628fe849..aa43b9861d3 100644
--- a/app/serializers/diff_file_entity.rb
+++ b/app/serializers/diff_file_entity.rb
@@ -55,17 +55,9 @@ class DiffFileEntity < DiffFileBaseEntity
end
# Used for inline diffs
- expose :highlighted_diff_lines, using: DiffLineEntity, if: -> (diff_file, options) { inline_diff_view?(options) && diff_file.text? } do |diff_file|
- highlighted_diff_lines_for(diff_file, options)
- end
+ expose :diff_lines_for_serializer, as: :highlighted_diff_lines, using: DiffLineEntity, if: -> (diff_file, options) { inline_diff_view?(options) && diff_file.text? }
- expose :is_fully_expanded do |diff_file|
- if conflict_file(options, diff_file)
- false
- else
- diff_file.fully_expanded?
- end
- end
+ expose :fully_expanded?, as: :is_fully_expanded
# Used for parallel diffs
expose :parallel_diff_lines, using: DiffLineParallelEntity, if: -> (diff_file, options) { parallel_diff_view?(options) && diff_file.text? }
@@ -88,15 +80,6 @@ class DiffFileEntity < DiffFileBaseEntity
# If nothing is present, inline will be the default.
options.fetch(:diff_view, :inline).to_sym
end
-
- def highlighted_diff_lines_for(diff_file, options)
- file = conflict_file(options, diff_file) || diff_file
-
- file.diff_lines_for_serializer
- rescue Gitlab::Git::Conflict::Parser::UnmergeableFile
- # Fallback to diff_file as it means that conflict lines can't be parsed due to limit
- diff_file.diff_lines_for_serializer
- end
end
DiffFileEntity.prepend_mod
diff --git a/app/serializers/diffs_entity.rb b/app/serializers/diffs_entity.rb
index c818fcd6215..759d1e0f10a 100644
--- a/app/serializers/diffs_entity.rb
+++ b/app/serializers/diffs_entity.rb
@@ -74,7 +74,7 @@ class DiffsEntity < Grape::Entity
options.merge(
submodule_links: submodule_links,
code_navigation_path: code_navigation_path(diffs),
- conflicts: conflicts(allow_tree_conflicts: options[:allow_tree_conflicts])
+ conflicts: (conflicts(allow_tree_conflicts: true) if options[:merge_conflicts_in_diff])
)
)
end
diff --git a/app/serializers/diffs_metadata_entity.rb b/app/serializers/diffs_metadata_entity.rb
index 8c226130f6e..ace5105dda5 100644
--- a/app/serializers/diffs_metadata_entity.rb
+++ b/app/serializers/diffs_metadata_entity.rb
@@ -6,7 +6,7 @@ class DiffsMetadataEntity < DiffsEntity
DiffFileMetadataEntity.represent(
diffs.raw_diff_files(sorted: true),
options.merge(
- conflicts: conflicts(allow_tree_conflicts: options[:allow_tree_conflicts])
+ conflicts: (conflicts(allow_tree_conflicts: true) if options[:merge_conflicts_in_diff])
)
)
end
diff --git a/app/serializers/environment_serializer.rb b/app/serializers/environment_serializer.rb
index 22839ba3099..46d5a488aea 100644
--- a/app/serializers/environment_serializer.rb
+++ b/app/serializers/environment_serializer.rb
@@ -43,7 +43,7 @@ class EnvironmentSerializer < BaseSerializer
# immediately.
items = @paginator.paginate(items) if paginated?
- environments = batch_load(resource.where(id: items.map(&:last_id)))
+ environments = batch_load(Environment.where(id: items.map(&:last_id)))
environments_by_id = environments.index_by(&:id)
items.map do |item|
@@ -52,15 +52,13 @@ class EnvironmentSerializer < BaseSerializer
end
def batch_load(resource)
- temp_deployment_associations = deployment_associations
-
resource = resource.preload(environment_associations)
Preloaders::Environments::DeploymentPreloader.new(resource)
- .execute_with_union(:last_deployment, temp_deployment_associations)
+ .execute_with_union(:last_deployment, deployment_associations)
Preloaders::Environments::DeploymentPreloader.new(resource)
- .execute_with_union(:upcoming_deployment, temp_deployment_associations)
+ .execute_with_union(:upcoming_deployment, deployment_associations)
resource.to_a.tap do |environments|
environments.each do |environment|
diff --git a/app/serializers/group_child_serializer.rb b/app/serializers/group_child_serializer.rb
index 789707c2c9b..54e65752163 100644
--- a/app/serializers/group_child_serializer.rb
+++ b/app/serializers/group_child_serializer.rb
@@ -39,12 +39,13 @@ class GroupChildSerializer < BaseSerializer
def represent_hierarchy(hierarchy, opts)
serializer = self.class.new(params)
- if hierarchy.is_a?(Hash)
+ case hierarchy
+ when Hash
hierarchy.map do |parent, children|
serializer.represent(parent, opts)
.merge(children: Array.wrap(serializer.represent_hierarchy(children, opts)))
end
- elsif hierarchy.is_a?(Array)
+ when Array
hierarchy.flat_map { |child| serializer.represent_hierarchy(child, opts) }
else
serializer.represent(hierarchy, opts)
diff --git a/app/serializers/integrations/event_entity.rb b/app/serializers/integrations/event_entity.rb
index 91bd91dd941..1cbd6114581 100644
--- a/app/serializers/integrations/event_entity.rb
+++ b/app/serializers/integrations/event_entity.rb
@@ -25,6 +25,9 @@ module Integrations
expose :value do |event|
integration.event_channel_value(event)
end
+ expose :placeholder do |_event|
+ integration.default_channel_placeholder
+ end
end
private
diff --git a/app/serializers/integrations/field_entity.rb b/app/serializers/integrations/field_entity.rb
index 697b53a737e..1c548cfab78 100644
--- a/app/serializers/integrations/field_entity.rb
+++ b/app/serializers/integrations/field_entity.rb
@@ -22,6 +22,8 @@ module Integrations
'true'
elsif field[:type] == 'checkbox'
ActiveRecord::Type::Boolean.new.deserialize(value).to_s
+ elsif field[:name] == 'webhook' && integration.chat?
+ BaseChatNotification::SECRET_MASK if value.present?
else
value
end
diff --git a/app/serializers/merge_request_noteable_entity.rb b/app/serializers/merge_request_noteable_entity.rb
index 07d7d19d1f3..306bac7daae 100644
--- a/app/serializers/merge_request_noteable_entity.rb
+++ b/app/serializers/merge_request_noteable_entity.rb
@@ -66,7 +66,7 @@ class MergeRequestNoteableEntity < IssuableEntity
expose :project_id
expose :archived_project_docs_path, if: -> (merge_request) { merge_request.project.archived? } do |merge_request|
- help_page_path('user/project/settings/index.md', anchor: 'archiving-a-project')
+ help_page_path('user/project/settings/index.md', anchor: 'archive-a-project')
end
private
diff --git a/app/serializers/merge_request_poll_cached_widget_entity.rb b/app/serializers/merge_request_poll_cached_widget_entity.rb
index 0c5af67bcda..33079905ed2 100644
--- a/app/serializers/merge_request_poll_cached_widget_entity.rb
+++ b/app/serializers/merge_request_poll_cached_widget_entity.rb
@@ -3,11 +3,9 @@
class MergeRequestPollCachedWidgetEntity < IssuableEntity
include MergeRequestMetricsHelper
- expose :auto_merge_enabled
expose :state
expose :merged_commit_sha
expose :short_merged_commit_sha
- expose :merge_error
expose :merge_user_id
expose :source_branch
expose :source_project_id
@@ -16,15 +14,10 @@ class MergeRequestPollCachedWidgetEntity < IssuableEntity
expose :target_project_id
expose :squash
expose :rebase_in_progress?, as: :rebase_in_progress
- expose :commits_count
+ expose :default_squash_commit_message
expose :merge_ongoing?, as: :merge_ongoing
- expose :draft?, as: :draft
- expose :draft?, as: :work_in_progress
- expose :cannot_be_merged?, as: :has_conflicts
- expose :can_be_merged?, as: :can_be_merged
expose :remove_source_branch?, as: :remove_source_branch
expose :source_branch_exists?, as: :source_branch_exists
- expose :branch_missing?, as: :branch_missing
expose :merge_status do |merge_request|
merge_request.check_mergeability(async: true)
diff --git a/app/serializers/merge_request_poll_widget_entity.rb b/app/serializers/merge_request_poll_widget_entity.rb
index 40bb905c5c9..ab180b35b29 100644
--- a/app/serializers/merge_request_poll_widget_entity.rb
+++ b/app/serializers/merge_request_poll_widget_entity.rb
@@ -11,7 +11,6 @@ class MergeRequestPollWidgetEntity < Grape::Entity
merge_request.source_project.present? && ProtectedBranch.protected?(merge_request.source_project, merge_request.source_branch)
end
expose :allow_collaboration
- expose :should_be_rebased?, as: :should_be_rebased
expose :ff_only_enabled do |merge_request|
merge_request.project.merge_requests_ff_only_enabled
end
@@ -31,15 +30,6 @@ class MergeRequestPollWidgetEntity < Grape::Entity
merge_request.default_merge_commit_message(include_description: true)
end
- # Booleans
- expose :mergeable_discussions_state?, as: :mergeable_discussions_state do |merge_request|
- merge_request.mergeable_discussions_state?
- end
-
- expose :project_archived do |merge_request|
- merge_request.project.archived?
- end
-
expose :only_allow_merge_if_pipeline_succeeds do |merge_request|
merge_request.project.only_allow_merge_if_pipeline_succeeds?
end
diff --git a/app/serializers/merge_requests/pipeline_entity.rb b/app/serializers/merge_requests/pipeline_entity.rb
index f4fb01604d0..76e75a8ca6d 100644
--- a/app/serializers/merge_requests/pipeline_entity.rb
+++ b/app/serializers/merge_requests/pipeline_entity.rb
@@ -5,6 +5,7 @@ class MergeRequests::PipelineEntity < Grape::Entity
expose :id
expose :active?, as: :active
+ expose :name, if: -> (pipeline, _) { Feature.enabled?(:pipeline_name, pipeline.project) }
expose :path do |pipeline|
project_pipeline_path(pipeline.project, pipeline)
@@ -17,8 +18,12 @@ class MergeRequests::PipelineEntity < Grape::Entity
expose :commit, using: CommitEntity
expose :details do
- expose :name do |pipeline|
- pipeline.present.name
+ expose :event_type_name do |pipeline|
+ pipeline.present.event_type_name
+ end
+
+ expose :name do |pipeline| # To be removed in 15.7
+ pipeline.present.event_type_name
end
expose :artifacts do |pipeline, options|
diff --git a/app/serializers/paginated_diff_entity.rb b/app/serializers/paginated_diff_entity.rb
index c656cff9dd7..b79a0937659 100644
--- a/app/serializers/paginated_diff_entity.rb
+++ b/app/serializers/paginated_diff_entity.rb
@@ -17,7 +17,7 @@ class PaginatedDiffEntity < Grape::Entity
options.merge(
submodule_links: submodule_links,
code_navigation_path: code_navigation_path(diffs),
- conflicts: conflicts(allow_tree_conflicts: options[:allow_tree_conflicts])
+ conflicts: (conflicts(allow_tree_conflicts: true) if options[:merge_conflicts_in_diff])
)
)
end
diff --git a/app/serializers/pipeline_serializer.rb b/app/serializers/pipeline_serializer.rb
index 9cfc81e8705..b738438a78f 100644
--- a/app/serializers/pipeline_serializer.rb
+++ b/app/serializers/pipeline_serializer.rb
@@ -40,6 +40,7 @@ class PipelineSerializer < BaseSerializer
def preloaded_relations
[
+ :pipeline_metadata,
:cancelable_statuses,
:retryable_builds,
:stages,
diff --git a/app/serializers/project_entity.rb b/app/serializers/project_entity.rb
index 60c4ba135d6..77e2115fbe2 100644
--- a/app/serializers/project_entity.rb
+++ b/app/serializers/project_entity.rb
@@ -3,14 +3,14 @@
class ProjectEntity < Grape::Entity
include RequestAwareEntity
- expose :id
- expose :name
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'GitLab' }
- expose :full_path do |project|
+ expose :full_path, documentation: { type: 'string', example: 'gitlab-org/gitlab' } do |project|
project_path(project)
end
- expose :full_name do |project|
+ expose :full_name, documentation: { type: 'string', example: 'GitLab Org / GitLab' } do |project|
project.full_name
end
end
diff --git a/app/serializers/project_import_entity.rb b/app/serializers/project_import_entity.rb
index 9b51af685e7..a3dbff3dc0b 100644
--- a/app/serializers/project_import_entity.rb
+++ b/app/serializers/project_import_entity.rb
@@ -3,11 +3,13 @@
class ProjectImportEntity < ProjectEntity
include ImportHelper
- expose :import_source
- expose :import_status
- expose :human_import_status_name
+ expose :import_source, documentation: { type: 'string', example: 'source/source-repo' }
+ expose :import_status, documentation: {
+ type: 'string', example: 'scheduled', values: %w[scheduled started finished failed canceled]
+ }
+ expose :human_import_status_name, documentation: { type: 'string', example: 'canceled' }
- expose :provider_link do |project, options|
+ expose :provider_link, documentation: { type: 'string', example: '/source/source-repo' } do |project, options|
provider_project_link_url(options[:provider_url], project[:import_source])
end
end
diff --git a/app/serializers/test_case_entity.rb b/app/serializers/test_case_entity.rb
index 8a5fadf53a6..1a872274cbf 100644
--- a/app/serializers/test_case_entity.rb
+++ b/app/serializers/test_case_entity.rb
@@ -3,15 +3,20 @@
class TestCaseEntity < Grape::Entity
include API::Helpers::RelatedResourcesHelpers
- expose :status
- expose :name, default: "(No name)"
- expose :classname
- expose :file
- expose :execution_time
- expose :system_output
- expose :stack_trace
- expose :recent_failures
- expose :attachment_url, if: -> (*) { can_read_screenshots? } do |test_case|
+ expose :status, documentation: { type: 'string', example: 'success' }
+ expose :name, default: "(No name)",
+ documentation: { type: 'string', example: 'Security Reports can create an auto-remediation MR' }
+ expose :classname, documentation: { type: 'string', example: 'vulnerability_management_spec' }
+ expose :file, documentation: { type: 'string', example: './spec/test_spec.rb' }
+ expose :execution_time, documentation: { type: 'integer', example: 180 }
+ expose :system_output, documentation: { type: 'string', example: 'Failure/Error: is_expected.to eq(3)' }
+ expose :stack_trace, documentation: { type: 'string', example: 'Failure/Error: is_expected.to eq(3)' }
+ expose :recent_failures, documentation: { example: { count: 3, base_branch: 'develop' } }
+ expose(
+ :attachment_url,
+ if: -> (*) { can_read_screenshots? },
+ documentation: { type: 'string', example: 'http://localhost/namespace1/project1/-/jobs/1/artifacts/file/some/path.png' }
+ ) do |test_case|
expose_url(test_case.attachment_url)
end
diff --git a/app/serializers/test_report_entity.rb b/app/serializers/test_report_entity.rb
index 9eb487da60a..0ff1c671f53 100644
--- a/app/serializers/test_report_entity.rb
+++ b/app/serializers/test_report_entity.rb
@@ -1,15 +1,15 @@
# frozen_string_literal: true
class TestReportEntity < Grape::Entity
- expose :total_time
- expose :total_count
+ expose :total_time, documentation: { type: 'integer', example: 180 }
+ expose :total_count, documentation: { type: 'integer', example: 1 }
- expose :success_count
- expose :failed_count
- expose :skipped_count
- expose :error_count
+ expose :success_count, documentation: { type: 'integer', example: 1 }
+ expose :failed_count, documentation: { type: 'integer', example: 0 }
+ expose :skipped_count, documentation: { type: 'integer', example: 0 }
+ expose :error_count, documentation: { type: 'integer', example: 0 }
- expose :test_suites, using: TestSuiteEntity do |report|
+ expose :test_suites, using: TestSuiteEntity, documentation: { is_array: true } do |report|
report.test_suites.values
end
end
diff --git a/app/serializers/test_report_summary_entity.rb b/app/serializers/test_report_summary_entity.rb
index bc73c49092f..f712b9f5500 100644
--- a/app/serializers/test_report_summary_entity.rb
+++ b/app/serializers/test_report_summary_entity.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class TestReportSummaryEntity < Grape::Entity
- expose :total
+ expose :total, documentation: { type: 'integer', example: 3363 }
expose :test_suites, using: TestSuiteSummaryEntity do |summary|
summary.test_suites.values
diff --git a/app/serializers/test_suite_entity.rb b/app/serializers/test_suite_entity.rb
index 15eb2891b22..a31b1f3ab9b 100644
--- a/app/serializers/test_suite_entity.rb
+++ b/app/serializers/test_suite_entity.rb
@@ -1,18 +1,19 @@
# frozen_string_literal: true
class TestSuiteEntity < Grape::Entity
- expose :name
- expose :total_time
- expose :total_count
+ expose :name, documentation: { type: 'string', example: 'test' }
+ expose :total_time, documentation: { type: 'integer', example: 1904 }
+ expose :total_count, documentation: { type: 'integer', example: 3363 }
- expose :success_count
- expose :failed_count
- expose :skipped_count
- expose :error_count
+ expose :success_count, documentation: { type: 'integer', example: 3351 }
+ expose :failed_count, documentation: { type: 'integer', example: 0 }
+ expose :skipped_count, documentation: { type: 'integer', example: 12 }
+ expose :error_count, documentation: { type: 'integer', example: 0 }
with_options if: -> (_, opts) { opts[:details] } do |test_suite|
- expose :suite_error
- expose :test_cases, using: TestCaseEntity do |test_suite|
+ expose :suite_error,
+ documentation: { type: 'string', example: 'JUnit XML parsing failed: 1:1: FATAL: Document is empty' }
+ expose :test_cases, using: TestCaseEntity, documentation: { is_array: true } do |test_suite|
test_suite.suite_error ? [] : test_suite.sorted.test_cases.values.flat_map(&:values)
end
end
diff --git a/app/serializers/test_suite_summary_entity.rb b/app/serializers/test_suite_summary_entity.rb
index 228c6e499fe..3a9ccb22713 100644
--- a/app/serializers/test_suite_summary_entity.rb
+++ b/app/serializers/test_suite_summary_entity.rb
@@ -1,9 +1,10 @@
# frozen_string_literal: true
class TestSuiteSummaryEntity < TestSuiteEntity
- expose :build_ids do |summary|
+ expose :build_ids, documentation: { type: 'integer', is_array: true, example: [66004] } do |summary|
summary.build_ids
end
- expose :suite_error
+ expose :suite_error,
+ documentation: { type: 'string', example: 'JUnit XML parsing failed: 1:1: FATAL: Document is empty' }
end
diff --git a/app/services/bulk_imports/create_pipeline_trackers_service.rb b/app/services/bulk_imports/create_pipeline_trackers_service.rb
index f5b944e6df5..7fa62e0ce8a 100644
--- a/app/services/bulk_imports/create_pipeline_trackers_service.rb
+++ b/app/services/bulk_imports/create_pipeline_trackers_service.rb
@@ -55,6 +55,8 @@ module BulkImports
message: 'Pipeline skipped as source instance version not compatible with pipeline',
bulk_import_entity_id: entity.id,
bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
pipeline_name: pipeline[:pipeline],
minimum_source_version: minimum_version,
maximum_source_version: maximum_version,
diff --git a/app/services/bulk_imports/lfs_objects_export_service.rb b/app/services/bulk_imports/lfs_objects_export_service.rb
index 1f745201c8a..b3b7cddf2d9 100644
--- a/app/services/bulk_imports/lfs_objects_export_service.rb
+++ b/app/services/bulk_imports/lfs_objects_export_service.rb
@@ -60,7 +60,7 @@ module BulkImports
def write_lfs_json
filepath = File.join(export_path, "#{BulkImports::FileTransfer::ProjectConfig::LFS_OBJECTS_RELATION}.json")
- File.write(filepath, lfs_json.to_json)
+ File.write(filepath, Gitlab::Json.dump(lfs_json))
end
end
end
diff --git a/app/services/ci/after_requeue_job_service.rb b/app/services/ci/after_requeue_job_service.rb
index 9d54207d75d..4374ccd52e0 100644
--- a/app/services/ci/after_requeue_job_service.rb
+++ b/app/services/ci/after_requeue_job_service.rb
@@ -23,8 +23,6 @@ module Ci
# rubocop: disable CodeReuse/ActiveRecord
def dependent_jobs
- return legacy_dependent_jobs unless ::Feature.enabled?(:ci_requeue_with_dag_object_hierarchy, project)
-
ordered_by_dag(
@processable.pipeline.processables
.from_union(needs_dependent_jobs, stage_dependent_jobs)
@@ -50,24 +48,6 @@ module Ci
).descendants
end
- def legacy_skipped_jobs
- @legacy_skipped_jobs ||= @processable.pipeline.processables.skipped
- end
-
- def legacy_dependent_jobs
- ordered_by_dag(
- legacy_stage_dependent_jobs.or(legacy_needs_dependent_jobs).ordered_by_stage.preload(:needs)
- )
- end
-
- def legacy_stage_dependent_jobs
- legacy_skipped_jobs.after_stage(@processable.stage_idx)
- end
-
- def legacy_needs_dependent_jobs
- legacy_skipped_jobs.scheduling_type_dag.with_needs([@processable.name])
- end
-
def ordered_by_dag(jobs)
sorted_job_names = sort_jobs(jobs).each_with_index.to_h
diff --git a/app/services/ci/archive_trace_service.rb b/app/services/ci/archive_trace_service.rb
index 566346a4b09..3d548c824c8 100644
--- a/app/services/ci/archive_trace_service.rb
+++ b/app/services/ci/archive_trace_service.rb
@@ -68,7 +68,7 @@ module Ci
Gitlab::ErrorTracking
.track_and_raise_for_dev_exception(error,
issue_url: 'https://gitlab.com/gitlab-org/gitlab-foss/issues/51502',
- job_id: job.id )
+ job_id: job.id)
end
end
end
diff --git a/app/services/ci/build_erase_service.rb b/app/services/ci/build_erase_service.rb
index 8a468e094eb..71b4c5481b3 100644
--- a/app/services/ci/build_erase_service.rb
+++ b/app/services/ci/build_erase_service.rb
@@ -33,9 +33,7 @@ module Ci
attr_reader :build, :current_user
def destroy_artifacts
- # fix_expire_at is false because in this case we want to explicitly delete the job artifacts
- # this flag is a workaround that will be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/355833
- Ci::JobArtifacts::DestroyBatchService.new(build.job_artifacts, fix_expire_at: false).execute
+ Ci::JobArtifacts::DestroyBatchService.new(build.job_artifacts).execute
end
def erase_trace!
diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb
index 0b49beffcb5..4106dfe0ecc 100644
--- a/app/services/ci/create_pipeline_service.rb
+++ b/app/services/ci/create_pipeline_service.rb
@@ -30,6 +30,7 @@ module Ci
Gitlab::Ci::Pipeline::Chain::Limit::Deployments,
Gitlab::Ci::Pipeline::Chain::Validate::External,
Gitlab::Ci::Pipeline::Chain::Populate,
+ Gitlab::Ci::Pipeline::Chain::PopulateMetadata,
Gitlab::Ci::Pipeline::Chain::StopDryRun,
Gitlab::Ci::Pipeline::Chain::EnsureEnvironments,
Gitlab::Ci::Pipeline::Chain::EnsureResourceGroups,
@@ -118,17 +119,6 @@ module Ci
end
# rubocop: enable Metrics/ParameterLists
- def execute!(*args, &block)
- source = args[0]
- params = Hash(args[1])
-
- execute(source, **params, &block).tap do |response|
- unless response.payload.persisted?
- raise CreateError, pipeline.full_error_messages
- end
- end
- end
-
private
def commit
diff --git a/app/services/ci/job_artifacts/destroy_associations_service.rb b/app/services/ci/job_artifacts/destroy_associations_service.rb
index 08d7f7f6f02..794d24eadf2 100644
--- a/app/services/ci/job_artifacts/destroy_associations_service.rb
+++ b/app/services/ci/job_artifacts/destroy_associations_service.rb
@@ -12,7 +12,7 @@ module Ci
def destroy_records
@job_artifacts_relation.each_batch(of: BATCH_SIZE) do |relation|
- service = Ci::JobArtifacts::DestroyBatchService.new(relation, pick_up_at: Time.current, fix_expire_at: false)
+ service = Ci::JobArtifacts::DestroyBatchService.new(relation, pick_up_at: Time.current)
result = service.execute(update_stats: false)
updates = result[:statistics_updates]
diff --git a/app/services/ci/job_artifacts/destroy_batch_service.rb b/app/services/ci/job_artifacts/destroy_batch_service.rb
index 54ec2c671c6..e0307d9bd53 100644
--- a/app/services/ci/job_artifacts/destroy_batch_service.rb
+++ b/app/services/ci/job_artifacts/destroy_batch_service.rb
@@ -17,10 +17,9 @@ module Ci
# +pick_up_at+:: When to pick up for deletion of files
# Returns:
# +Hash+:: A hash with status and destroyed_artifacts_count keys
- def initialize(job_artifacts, pick_up_at: nil, fix_expire_at: fix_expire_at?, skip_projects_on_refresh: false)
+ def initialize(job_artifacts, pick_up_at: nil, skip_projects_on_refresh: false)
@job_artifacts = job_artifacts.with_destroy_preloads.to_a
@pick_up_at = pick_up_at
- @fix_expire_at = fix_expire_at
@skip_projects_on_refresh = skip_projects_on_refresh
end
@@ -32,9 +31,7 @@ module Ci
track_artifacts_undergoing_stats_refresh
end
- # Detect and fix artifacts that had `expire_at` wrongly backfilled by migration
- # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47723
- detect_and_fix_wrongly_expired_artifacts
+ exclude_trace_artifacts
return success(destroyed_artifacts_count: 0, statistics_updates: {}) if @job_artifacts.empty?
@@ -113,55 +110,9 @@ module Ci
end
end
- # This detects and fixes job artifacts that have `expire_at` wrongly backfilled by the migration
- # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47723.
- # These job artifacts will not be deleted and will have their `expire_at` removed.
- #
- # The migration would have backfilled `expire_at`
- # to midnight on the 22nd of the month of the local timezone,
- # storing it as UTC time in the database.
- #
- # If the timezone setting has changed since the migration,
- # the `expire_at` stored in the database could have changed to a different local time other than midnight.
- # For example:
- # - changing timezone from UTC+02:00 to UTC+02:30 would change the `expire_at` in local time 00:00:00 to 00:30:00.
- # - changing timezone from UTC+00:00 to UTC-01:00 would change the `expire_at` in local time 00:00:00 to 23:00:00 on the previous day (21st).
- #
- # Therefore job artifacts that have `expire_at` exactly on the 00, 30 or 45 minute mark
- # on the dates 21, 22, 23 of the month will not be deleted.
- # https://en.wikipedia.org/wiki/List_of_UTC_time_offsets
- def detect_and_fix_wrongly_expired_artifacts
- return unless @fix_expire_at
-
- wrongly_expired_artifacts, @job_artifacts = @job_artifacts.partition { |artifact| wrongly_expired?(artifact) }
-
- remove_expire_at(wrongly_expired_artifacts) if wrongly_expired_artifacts.any?
- end
-
- def fix_expire_at?
- Feature.enabled?(:ci_detect_wrongly_expired_artifacts)
- end
-
- def wrongly_expired?(artifact)
- return false unless artifact.expire_at.present?
-
- # Although traces should never have expiration dates that don't match time & date here.
- # we can explicitly exclude them by type since they should never be destroyed.
- artifact.trace? || (match_date?(artifact.expire_at) && match_time?(artifact.expire_at))
- end
-
- def match_date?(expire_at)
- [21, 22, 23].include?(expire_at.day)
- end
-
- def match_time?(expire_at)
- %w[00:00.000 30:00.000 45:00.000].include?(expire_at.strftime('%M:%S.%L'))
- end
-
- def remove_expire_at(artifacts)
- Ci::JobArtifact.id_in(artifacts).update_all(expire_at: nil)
-
- Gitlab::AppLogger.info(message: "Fixed expire_at from artifacts.", fixed_artifacts_expire_at_count: artifacts.count)
+ # Traces should never be destroyed.
+ def exclude_trace_artifacts
+ _trace_artifacts, @job_artifacts = @job_artifacts.partition(&:trace?)
end
def track_artifacts_undergoing_stats_refresh
diff --git a/app/services/ci/job_artifacts/track_artifact_report_service.rb b/app/services/ci/job_artifacts/track_artifact_report_service.rb
index 1be1d98394f..0230a5e19ce 100644
--- a/app/services/ci/job_artifacts/track_artifact_report_service.rb
+++ b/app/services/ci/job_artifacts/track_artifact_report_service.rb
@@ -5,7 +5,7 @@ module Ci
class TrackArtifactReportService
include Gitlab::Utils::UsageData
- REPORT_TRACKED = %i[test].freeze
+ REPORT_TRACKED = %i[test coverage].freeze
def execute(pipeline)
REPORT_TRACKED.each do |report|
diff --git a/app/services/ci/list_config_variables_service.rb b/app/services/ci/list_config_variables_service.rb
index 3890882b3d4..df4963d1b33 100644
--- a/app/services/ci/list_config_variables_service.rb
+++ b/app/services/ci/list_config_variables_service.rb
@@ -30,7 +30,7 @@ module Ci
user: current_user,
sha: sha).execute
- result.valid? ? result.variables_with_data : {}
+ result.valid? ? result.root_variables_with_prefill_data : {}
end
# Required for ReactiveCaching, it is also used in `reactive_cache_worker_finder`
diff --git a/app/services/ci/pipeline_artifacts/coverage_report_service.rb b/app/services/ci/pipeline_artifacts/coverage_report_service.rb
index 9c6fdb7a405..de66a4cb045 100644
--- a/app/services/ci/pipeline_artifacts/coverage_report_service.rb
+++ b/app/services/ci/pipeline_artifacts/coverage_report_service.rb
@@ -39,7 +39,7 @@ module Ci
def carrierwave_file
strong_memoize(:carrier_wave_file) do
CarrierWaveStringFile.new_file(
- file_content: report.to_json,
+ file_content: Gitlab::Json.dump(report),
filename: Ci::PipelineArtifact::DEFAULT_FILE_NAMES.fetch(:code_coverage),
content_type: 'application/json'
)
diff --git a/app/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service.rb b/app/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service.rb
index a0746ef32b2..57b663dc293 100644
--- a/app/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service.rb
+++ b/app/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service.rb
@@ -77,9 +77,9 @@ module Ci
end
def build_quality_mr_diff_report(mr_diff_report)
- mr_diff_report.each_with_object({}) do |diff_report, hash|
+ Gitlab::Json.dump(mr_diff_report.each_with_object({}) do |diff_report, hash|
hash[diff_report.first] = Ci::CodequalityMrDiffReportSerializer.new.represent(diff_report.second) # rubocop: disable CodeReuse/Serializer
- end.to_json
+ end)
end
end
end
diff --git a/app/services/ci/pipeline_schedules/take_ownership_service.rb b/app/services/ci/pipeline_schedules/take_ownership_service.rb
new file mode 100644
index 00000000000..9b4001c74bd
--- /dev/null
+++ b/app/services/ci/pipeline_schedules/take_ownership_service.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Ci
+ module PipelineSchedules
+ class TakeOwnershipService
+ def initialize(schedule, user)
+ @schedule = schedule
+ @user = user
+ end
+
+ def execute
+ return forbidden unless allowed?
+
+ if schedule.update(owner: user)
+ ServiceResponse.success(payload: schedule)
+ else
+ ServiceResponse.error(message: schedule.errors.full_messages)
+ end
+ end
+
+ private
+
+ attr_reader :schedule, :user
+
+ def allowed?
+ user.can?(:take_ownership_pipeline_schedule, schedule)
+ end
+
+ def forbidden
+ ServiceResponse.error(message: _('Failed to change the owner'), reason: :access_denied)
+ end
+ end
+ end
+end
diff --git a/app/services/ci/pipeline_trigger_service.rb b/app/services/ci/pipeline_trigger_service.rb
index 39ac9bf33e9..d7065680053 100644
--- a/app/services/ci/pipeline_trigger_service.rb
+++ b/app/services/ci/pipeline_trigger_service.rb
@@ -93,7 +93,7 @@ module Ci
def payload_variable
{ key: PAYLOAD_VARIABLE_KEY,
- value: params.except(*PAYLOAD_VARIABLE_HIDDEN_PARAMS).to_json,
+ value: Gitlab::Json.dump(params.except(*PAYLOAD_VARIABLE_HIDDEN_PARAMS)),
variable_type: :file }
end
diff --git a/app/services/ci/play_build_service.rb b/app/services/ci/play_build_service.rb
index fbf2aad1991..b7aec57f3e3 100644
--- a/app/services/ci/play_build_service.rb
+++ b/app/services/ci/play_build_service.rb
@@ -5,21 +5,27 @@ module Ci
def execute(build, job_variables_attributes = nil)
check_access!(build, job_variables_attributes)
- # Try to enqueue the build, otherwise create a duplicate.
- #
- if build.enqueue
- build.tap do |build|
- build.update!(user: current_user, job_variables_attributes: job_variables_attributes || [])
-
- AfterRequeueJobService.new(project, current_user).execute(build)
- end
+ if build.can_enqueue?
+ build.user = current_user
+ build.job_variables_attributes = job_variables_attributes || []
+ build.enqueue!
+
+ AfterRequeueJobService.new(project, current_user).execute(build)
+
+ build
else
- Ci::RetryJobService.new(project, current_user).execute(build)[:job]
+ retry_build(build)
end
+ rescue StateMachines::InvalidTransition
+ retry_build(build.reset)
end
private
+ def retry_build(build)
+ Ci::RetryJobService.new(project, current_user).execute(build)[:job]
+ end
+
def check_access!(build, job_variables_attributes)
raise Gitlab::Access::AccessDeniedError unless can?(current_user, :play_job, build)
diff --git a/app/services/ci/process_build_service.rb b/app/services/ci/process_build_service.rb
index 22cd267806d..cb51d918fc2 100644
--- a/app/services/ci/process_build_service.rb
+++ b/app/services/ci/process_build_service.rb
@@ -15,6 +15,8 @@ module Ci
private
def process(build)
+ return enqueue(build) if Feature.enabled?(:ci_retry_job_fix, project) && build.enqueue_immediately?
+
if build.schedulable?
build.schedule
elsif build.action?
@@ -25,7 +27,7 @@ module Ci
end
def enqueue(build)
- return build.drop!(:failed_outdated_deployment_job) if build.prevent_rollback_deployment?
+ return build.drop!(:failed_outdated_deployment_job) if build.outdated_deployment?
build.enqueue
end
diff --git a/app/services/ci/register_job_service.rb b/app/services/ci/register_job_service.rb
index 0bd4bf8cc86..f11577feb88 100644
--- a/app/services/ci/register_job_service.rb
+++ b/app/services/ci/register_job_service.rb
@@ -42,7 +42,7 @@ module Ci
if !db_all_caught_up && !result.build
metrics.increment_queue_operation(:queue_replication_lag)
- ::Ci::RegisterJobService::Result.new(nil, false) # rubocop:disable Cop/AvoidReturnFromBlocks
+ ::Ci::RegisterJobService::Result.new(nil, nil, false) # rubocop:disable Cop/AvoidReturnFromBlocks
else
result
end
@@ -226,7 +226,7 @@ module Ci
log_artifacts_context(build)
log_build_dependencies_size(presented_build)
- build_json = ::API::Entities::Ci::JobRequest::Response.new(presented_build).to_json
+ build_json = Gitlab::Json.dump(::API::Entities::Ci::JobRequest::Response.new(presented_build))
Result.new(build, build_json, true)
end
diff --git a/app/services/ci/retry_job_service.rb b/app/services/ci/retry_job_service.rb
index 25bda8a6380..74ebaef48b1 100644
--- a/app/services/ci/retry_job_service.rb
+++ b/app/services/ci/retry_job_service.rb
@@ -19,7 +19,7 @@ module Ci
end
# rubocop: disable CodeReuse/ActiveRecord
- def clone!(job, variables: [])
+ def clone!(job, variables: [], enqueue_if_actionable: false)
# Cloning a job requires a strict type check to ensure
# the attributes being used for the clone are taken straight
# from the model and not overridden by other abstractions.
@@ -28,6 +28,9 @@ module Ci
check_access!(job)
new_job = job.clone(current_user: current_user, new_job_variables_attributes: variables)
+ if Feature.enabled?(:ci_retry_job_fix, project) && enqueue_if_actionable && new_job.action?
+ new_job.set_enqueue_immediately!
+ end
new_job.run_after_commit do
::Ci::CopyCrossDatabaseAssociationsService.new.execute(job, new_job)
@@ -56,13 +59,20 @@ module Ci
def check_assignable_runners!(job); end
def retry_job(job, variables: [])
- clone!(job, variables: variables).tap do |new_job|
+ clone!(job, variables: variables, enqueue_if_actionable: true).tap do |new_job|
check_assignable_runners!(new_job) if new_job.is_a?(Ci::Build)
next if new_job.failed?
- Gitlab::OptimisticLocking.retry_lock(new_job, name: 'retry_build', &:enqueue)
+ Gitlab::OptimisticLocking.retry_lock(new_job, name: 'retry_build', &:enqueue) if Feature.disabled?(
+ :ci_retry_job_fix, project)
+
AfterRequeueJobService.new(project, current_user).execute(job)
+
+ if Feature.enabled?(:ci_retry_job_fix, project)
+ Ci::PipelineCreation::StartPipelineService.new(job.pipeline).execute
+ new_job.reset
+ end
end
end
diff --git a/app/services/ci/runners/bulk_delete_runners_service.rb b/app/services/ci/runners/bulk_delete_runners_service.rb
index ce07aa541c2..b6b07746e61 100644
--- a/app/services/ci/runners/bulk_delete_runners_service.rb
+++ b/app/services/ci/runners/bulk_delete_runners_service.rb
@@ -7,29 +7,69 @@ module Ci
RUNNER_LIMIT = 50
- # @param runners [Array<Ci::Runner, Integer>] the runners to unregister/destroy
- def initialize(runners:)
+ # @param runners [Array<Ci::Runner>] the runners to unregister/destroy
+ # @param current_user [User] the user performing the operation
+ def initialize(runners:, current_user:)
@runners = runners
+ @current_user = current_user
end
def execute
if @runners
# Delete a few runners immediately
- return ServiceResponse.success(payload: delete_runners)
+ return delete_runners
end
- ServiceResponse.success(payload: { deleted_count: 0, deleted_ids: [] })
+ ServiceResponse.success(payload: { deleted_count: 0, deleted_ids: [], errors: [] })
end
private
def delete_runners
+ runner_count = @runners.limit(RUNNER_LIMIT + 1).count
+ authorized_runners_ids, unauthorized_runners_ids = compute_authorized_runners
# rubocop:disable CodeReuse/ActiveRecord
- runners_to_be_deleted = Ci::Runner.where(id: @runners).limit(RUNNER_LIMIT)
+ runners_to_be_deleted =
+ Ci::Runner
+ .where(id: authorized_runners_ids)
+ .preload([:taggings, :runner_namespaces, :runner_projects])
# rubocop:enable CodeReuse/ActiveRecord
- deleted_ids = runners_to_be_deleted.destroy_all.map(&:id) # rubocop: disable Cop/DestroyAll
+ deleted_ids = runners_to_be_deleted.destroy_all.map(&:id) # rubocop:disable Cop/DestroyAll
- { deleted_count: deleted_ids.count, deleted_ids: deleted_ids }
+ ServiceResponse.success(
+ payload: {
+ deleted_count: deleted_ids.count,
+ deleted_ids: deleted_ids,
+ errors: error_messages(runner_count, authorized_runners_ids, unauthorized_runners_ids)
+ })
+ end
+
+ def compute_authorized_runners
+ # rubocop:disable CodeReuse/ActiveRecord
+ @current_user.ci_owned_runners.load # preload the owned runners to avoid an N+1
+ authorized_runners, unauthorized_runners =
+ @runners.limit(RUNNER_LIMIT)
+ .partition { |runner| Ability.allowed?(@current_user, :delete_runner, runner) }
+ # rubocop:enable CodeReuse/ActiveRecord
+
+ [authorized_runners.map(&:id), unauthorized_runners.map(&:id)]
+ end
+
+ def error_messages(runner_count, authorized_runners_ids, unauthorized_runners_ids)
+ errors = []
+
+ if runner_count > RUNNER_LIMIT
+ errors << "Can only delete up to #{RUNNER_LIMIT} runners per call. Ignored the remaining runner(s)."
+ end
+
+ if authorized_runners_ids.empty?
+ errors << "User does not have permission to delete any of the runners"
+ elsif unauthorized_runners_ids.any?
+ failed_ids = unauthorized_runners_ids.map { |runner_id| "##{runner_id}" }.join(', ')
+ errors << "User does not have permission to delete runner(s) #{failed_ids}"
+ end
+
+ errors
end
end
end
diff --git a/app/services/ci/runners/set_runner_associated_projects_service.rb b/app/services/ci/runners/set_runner_associated_projects_service.rb
index 7930776749d..5e33fdae2f4 100644
--- a/app/services/ci/runners/set_runner_associated_projects_service.rb
+++ b/app/services/ci/runners/set_runner_associated_projects_service.rb
@@ -17,7 +17,7 @@ module Ci
return ServiceResponse.error(message: 'user not allowed to assign runner', http_status: :forbidden)
end
- return ServiceResponse.success if project_ids.blank?
+ return ServiceResponse.success if project_ids.nil?
set_associated_projects
end
diff --git a/app/services/clusters/applications/check_ingress_ip_address_service.rb b/app/services/clusters/applications/check_ingress_ip_address_service.rb
deleted file mode 100644
index e254a0358a0..00000000000
--- a/app/services/clusters/applications/check_ingress_ip_address_service.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Applications
- class CheckIngressIpAddressService < BaseHelmService
- include Gitlab::Utils::StrongMemoize
-
- Error = Class.new(StandardError)
-
- LEASE_TIMEOUT = 15.seconds.to_i
-
- def execute
- return if app.external_ip
- return if app.external_hostname
- return unless try_obtain_lease
-
- app.external_ip = ingress_ip if ingress_ip
- app.external_hostname = ingress_hostname if ingress_hostname
-
- app.save! if app.changed?
- end
-
- private
-
- def try_obtain_lease
- Gitlab::ExclusiveLease
- .new("check_ingress_ip_address_service:#{app.id}", timeout: LEASE_TIMEOUT)
- .try_obtain
- end
-
- def ingress_ip
- ingress_service&.ip
- end
-
- def ingress_hostname
- ingress_service&.hostname
- end
-
- def ingress_service
- strong_memoize(:ingress_service) do
- app.ingress_service.status.loadBalancer.ingress&.first
- end
- end
- end
- end
-end
diff --git a/app/services/clusters/applications/check_installation_progress_service.rb b/app/services/clusters/applications/check_installation_progress_service.rb
deleted file mode 100644
index 10a12f30956..00000000000
--- a/app/services/clusters/applications/check_installation_progress_service.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Applications
- class CheckInstallationProgressService < CheckProgressService
- private
-
- def operation_in_progress?
- app.installing? || app.updating?
- end
-
- def on_success
- app.make_installed!
-
- Gitlab::Tracking.event('cluster:applications', "cluster_application_#{app.name}_installed")
- ensure
- remove_installation_pod
- end
-
- def check_timeout
- if timed_out?
- app.make_errored!("Operation timed out. Check pod logs for #{pod_name} for more details.")
- else
- ClusterWaitForAppInstallationWorker.perform_in(
- ClusterWaitForAppInstallationWorker::INTERVAL, app.name, app.id)
- end
- end
-
- def pod_name
- install_command.pod_name
- end
-
- def timed_out?
- Time.current.utc - app.updated_at.utc > ClusterWaitForAppInstallationWorker::TIMEOUT
- end
-
- def remove_installation_pod
- helm_api.delete_pod!(pod_name)
- end
- end
- end
-end
diff --git a/app/services/clusters/applications/check_uninstall_progress_service.rb b/app/services/clusters/applications/check_uninstall_progress_service.rb
deleted file mode 100644
index cd213c3ebbf..00000000000
--- a/app/services/clusters/applications/check_uninstall_progress_service.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Applications
- class CheckUninstallProgressService < CheckProgressService
- private
-
- def operation_in_progress?
- app.uninstalling?
- end
-
- def on_success
- app.post_uninstall
- app.destroy!
- rescue StandardError => e
- app.make_errored!(_('Application uninstalled but failed to destroy: %{error_message}') % { error_message: e.message })
- ensure
- remove_uninstallation_pod
- end
-
- def check_timeout
- if timed_out?
- app.make_errored!(_('Operation timed out. Check pod logs for %{pod_name} for more details.') % { pod_name: pod_name })
- else
- WaitForUninstallAppWorker.perform_in(WaitForUninstallAppWorker::INTERVAL, app.name, app.id)
- end
- end
-
- def pod_name
- app.uninstall_command.pod_name
- end
-
- def timed_out?
- Time.current.utc - app.updated_at.utc > WaitForUninstallAppWorker::TIMEOUT
- end
-
- def remove_uninstallation_pod
- helm_api.delete_pod!(pod_name)
- end
- end
- end
-end
diff --git a/app/services/clusters/applications/check_upgrade_progress_service.rb b/app/services/clusters/applications/check_upgrade_progress_service.rb
deleted file mode 100644
index c4fd234b302..00000000000
--- a/app/services/clusters/applications/check_upgrade_progress_service.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Applications
- class CheckUpgradeProgressService < BaseHelmService
- def execute
- return unless app.updating?
-
- case phase
- when ::Gitlab::Kubernetes::Pod::SUCCEEDED
- on_success
- when ::Gitlab::Kubernetes::Pod::FAILED
- on_failed
- else
- check_timeout
- end
- rescue ::Kubeclient::HttpError => e
- app.make_update_errored!("Kubernetes error: #{e.message}") unless app.update_errored?
- end
-
- private
-
- def on_success
- app.make_installed!
- ensure
- remove_pod
- end
-
- def on_failed
- app.make_update_errored!(errors || 'Update silently failed')
- ensure
- remove_pod
- end
-
- def check_timeout
- if timed_out?
- begin
- app.make_update_errored!('Update timed out')
- ensure
- remove_pod
- end
- else
- ::ClusterWaitForAppUpdateWorker.perform_in(
- ::ClusterWaitForAppUpdateWorker::INTERVAL, app.name, app.id)
- end
- end
-
- def timed_out?
- Time.current.utc - app.updated_at.to_time.utc > ::ClusterWaitForAppUpdateWorker::TIMEOUT
- end
-
- def remove_pod
- helm_api.delete_pod!(pod_name)
- rescue StandardError
- # no-op
- end
-
- def phase
- helm_api.status(pod_name)
- end
-
- def errors
- helm_api.log(pod_name)
- end
-
- def pod_name
- @pod_name ||= patch_command.pod_name
- end
- end
- end
-end
diff --git a/app/services/clusters/applications/create_service.rb b/app/services/clusters/applications/create_service.rb
deleted file mode 100644
index 2a626a402e4..00000000000
--- a/app/services/clusters/applications/create_service.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Applications
- class CreateService < Clusters::Applications::BaseService
- private
-
- def worker_class(application)
- application.updateable? ? ClusterUpgradeAppWorker : ClusterInstallAppWorker
- end
-
- def builder
- cluster.public_send(application_class.association_name) || # rubocop:disable GitlabSecurity/PublicSend
- cluster.public_send(:"build_application_#{application_name}") # rubocop:disable GitlabSecurity/PublicSend
- end
- end
- end
-end
diff --git a/app/services/clusters/applications/patch_service.rb b/app/services/clusters/applications/patch_service.rb
deleted file mode 100644
index fbea18bae6b..00000000000
--- a/app/services/clusters/applications/patch_service.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Applications
- class PatchService < BaseHelmService
- def execute
- return unless app.scheduled?
-
- app.make_updating!
-
- patch
- end
-
- private
-
- def patch
- log_event(:begin_patch)
- helm_api.update(update_command)
-
- log_event(:schedule_wait_for_patch)
- ClusterWaitForAppInstallationWorker.perform_in(
- ClusterWaitForAppInstallationWorker::INTERVAL, app.name, app.id)
- rescue Kubeclient::HttpError => e
- log_error(e)
- app.make_errored!(_('Kubernetes error: %{error_code}') % { error_code: e.error_code })
- rescue StandardError => e
- log_error(e)
- app.make_errored!(_('Failed to update.'))
- end
- end
- end
-end
diff --git a/app/services/clusters/applications/prometheus_update_service.rb b/app/services/clusters/applications/prometheus_update_service.rb
deleted file mode 100644
index b8b50f06d72..00000000000
--- a/app/services/clusters/applications/prometheus_update_service.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Applications
- # Deprecated, to be removed in %14.0 as part of https://gitlab.com/groups/gitlab-org/-/epics/4280
- class PrometheusUpdateService < BaseHelmService
- attr_accessor :project
-
- def initialize(app, project)
- super(app)
- @project = project
- end
-
- def execute
- raise NotImplementedError, 'Externally installed prometheus should not be modified!' unless app.managed_prometheus?
-
- app.make_updating!
-
- helm_api.update(patch_command(values))
-
- ::ClusterWaitForAppUpdateWorker.perform_in(::ClusterWaitForAppUpdateWorker::INTERVAL, app.name, app.id)
- rescue ::Kubeclient::HttpError => ke
- app.make_update_errored!("Kubernetes error: #{ke.message}")
- rescue StandardError => e
- app.make_update_errored!(e.message)
- end
-
- private
-
- def values
- PrometheusConfigService
- .new(project, cluster, app)
- .execute
- .to_yaml
- end
- end
- end
-end
diff --git a/app/services/clusters/applications/update_service.rb b/app/services/clusters/applications/update_service.rb
deleted file mode 100644
index 7a36401f156..00000000000
--- a/app/services/clusters/applications/update_service.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-module Clusters
- module Applications
- class UpdateService < Clusters::Applications::BaseService
- private
-
- def worker_class(application)
- ClusterPatchAppWorker
- end
-
- def builder
- cluster.public_send(application_class.association_name) # rubocop:disable GitlabSecurity/PublicSend
- end
- end
- end
-end
diff --git a/app/services/clusters/kubernetes/configure_istio_ingress_service.rb b/app/services/clusters/kubernetes/configure_istio_ingress_service.rb
deleted file mode 100644
index 3b7e094bc97..00000000000
--- a/app/services/clusters/kubernetes/configure_istio_ingress_service.rb
+++ /dev/null
@@ -1,112 +0,0 @@
-# frozen_string_literal: true
-
-require 'openssl'
-
-module Clusters
- module Kubernetes
- class ConfigureIstioIngressService
- PASSTHROUGH_RESOURCE = Kubeclient::Resource.new(
- mode: 'PASSTHROUGH'
- ).freeze
-
- MTLS_RESOURCE = Kubeclient::Resource.new(
- mode: 'MUTUAL',
- privateKey: '/etc/istio/ingressgateway-certs/tls.key',
- serverCertificate: '/etc/istio/ingressgateway-certs/tls.crt',
- caCertificates: '/etc/istio/ingressgateway-ca-certs/cert.pem'
- ).freeze
-
- def initialize(cluster:)
- @cluster = cluster
- @platform = cluster.platform
- @kubeclient = platform.kubeclient
- @knative = cluster.application_knative
- end
-
- def execute
- return configure_certificates if serverless_domain_cluster
-
- configure_passthrough
- rescue Kubeclient::HttpError => e
- knative.make_errored!(_('Kubernetes error: %{error_code}') % { error_code: e.error_code })
- rescue StandardError
- knative.make_errored!(_('Failed to update.'))
- end
-
- private
-
- attr_reader :cluster, :platform, :kubeclient, :knative
-
- def serverless_domain_cluster
- knative&.serverless_domain_cluster
- end
-
- def configure_certificates
- create_or_update_istio_cert_and_key
- set_gateway_wildcard_https(MTLS_RESOURCE)
- end
-
- def create_or_update_istio_cert_and_key
- name = OpenSSL::X509::Name.parse("CN=#{knative.hostname}")
-
- key = OpenSSL::PKey::RSA.new(2048)
-
- cert = OpenSSL::X509::Certificate.new
- cert.version = 2
- cert.serial = 0
- cert.not_before = Time.current
- cert.not_after = Time.current + 1000.years
-
- cert.public_key = key.public_key
- cert.subject = name
- cert.issuer = name
- cert.sign(key, OpenSSL::Digest.new('SHA256'))
-
- serverless_domain_cluster.update!(
- key: key.to_pem,
- certificate: cert.to_pem
- )
-
- kubeclient.create_or_update_secret(istio_ca_certs_resource)
- kubeclient.create_or_update_secret(istio_certs_resource)
- end
-
- def istio_ca_certs_resource
- Gitlab::Kubernetes::GenericSecret.new(
- 'istio-ingressgateway-ca-certs',
- {
- 'cert.pem': Base64.strict_encode64(serverless_domain_cluster.certificate)
- },
- Clusters::Kubernetes::ISTIO_SYSTEM_NAMESPACE
- ).generate
- end
-
- def istio_certs_resource
- Gitlab::Kubernetes::TlsSecret.new(
- 'istio-ingressgateway-certs',
- serverless_domain_cluster.certificate,
- serverless_domain_cluster.key,
- Clusters::Kubernetes::ISTIO_SYSTEM_NAMESPACE
- ).generate
- end
-
- def set_gateway_wildcard_https(tls_resource)
- gateway_resource = gateway
- gateway_resource.spec.servers.each do |server|
- next unless server.hosts == ['*'] && server.port.name == 'https'
-
- server.tls = tls_resource
- end
- kubeclient.update_gateway(gateway_resource)
- end
-
- def configure_passthrough
- set_gateway_wildcard_https(PASSTHROUGH_RESOURCE)
- end
-
- def gateway
- kubeclient.get_gateway('knative-ingress-gateway', Clusters::Kubernetes::KNATIVE_SERVING_NAMESPACE)
- end
- end
- end
-end
diff --git a/app/services/concerns/alert_management/responses.rb b/app/services/concerns/alert_management/responses.rb
index 183a831a00a..e48d07d26c0 100644
--- a/app/services/concerns/alert_management/responses.rb
+++ b/app/services/concerns/alert_management/responses.rb
@@ -7,6 +7,10 @@ module AlertManagement
ServiceResponse.success(payload: { alerts: Array(alerts) })
end
+ def created
+ ServiceResponse.success(http_status: :created)
+ end
+
def bad_request
ServiceResponse.error(message: 'Bad Request', http_status: :bad_request)
end
diff --git a/app/services/dependency_proxy/find_cached_manifest_service.rb b/app/services/dependency_proxy/find_cached_manifest_service.rb
index faf0402edaa..ea09445584a 100644
--- a/app/services/dependency_proxy/find_cached_manifest_service.rb
+++ b/app/services/dependency_proxy/find_cached_manifest_service.rb
@@ -19,6 +19,7 @@ module DependencyProxy
head_result = DependencyProxy::HeadManifestService.new(@image, @tag, @token).execute
return respond if cached_manifest_matches?(head_result)
+ return respond if @manifest && head_result[:status] == :error
success(manifest: nil, from_cache: false)
rescue Timeout::Error, *Gitlab::HTTP::HTTP_ERRORS
diff --git a/app/services/deployments/create_for_build_service.rb b/app/services/deployments/create_for_build_service.rb
index 76d871161e3..7bc0ea88910 100644
--- a/app/services/deployments/create_for_build_service.rb
+++ b/app/services/deployments/create_for_build_service.rb
@@ -8,28 +8,62 @@ module Deployments
def execute(build)
return unless build.instance_of?(::Ci::Build) && build.persisted_environment.present?
- # TODO: Move all buisness logic in `Seed::Deployment` to this class after
- # `create_deployment_in_separate_transaction` feature flag has been removed.
- # See https://gitlab.com/gitlab-org/gitlab/-/issues/348778
-
- # If build.persisted_environment is a BatchLoader, we need to remove
- # the method proxy in order to clone into new item here
- # https://github.com/exAspArk/batch-loader/issues/31
- environment = if build.persisted_environment.respond_to?(:__sync)
- build.persisted_environment.__sync
- else
- build.persisted_environment
- end
-
- deployment = ::Gitlab::Ci::Pipeline::Seed::Deployment
- .new(build, environment).to_resource
+ environment = build.actual_persisted_environment
+
+ deployment = to_resource(build, environment)
return unless deployment
- build.create_deployment!(deployment.attributes)
+ deployment.save!
+ build.association(:deployment).target = deployment
+ build.association(:deployment).loaded!
+
+ deployment
rescue ActiveRecord::RecordInvalid => e
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(
DeploymentCreationError.new(e.message), build_id: build.id)
end
+
+ private
+
+ def to_resource(build, environment)
+ return build.deployment if build.deployment
+ return unless build.starts_environment?
+
+ deployment = ::Deployment.new(attributes(build, environment))
+
+ # If there is a validation error on environment creation, such as
+ # the name contains invalid character, the job will fall back to a
+ # non-environment job.
+ return unless deployment.valid? && deployment.environment.persisted?
+
+ if cluster = deployment.environment.deployment_platform&.cluster
+ # double write cluster_id until 12.9: https://gitlab.com/gitlab-org/gitlab/issues/202628
+ deployment.cluster_id = cluster.id
+ deployment.deployment_cluster = ::DeploymentCluster.new(
+ cluster_id: cluster.id,
+ kubernetes_namespace: cluster.kubernetes_namespace_for(deployment.environment, deployable: build)
+ )
+ end
+
+ # Allocate IID for deployments.
+ # This operation must be outside of transactions of pipeline creations.
+ deployment.ensure_project_iid!
+
+ deployment
+ end
+
+ def attributes(build, environment)
+ {
+ project: build.project,
+ environment: environment,
+ deployable: build,
+ user: build.user,
+ ref: build.ref,
+ tag: build.tag,
+ sha: build.sha,
+ on_stop: build.on_stop
+ }
+ end
end
end
diff --git a/app/services/environments/create_for_build_service.rb b/app/services/environments/create_for_build_service.rb
new file mode 100644
index 00000000000..c46b66ac5b3
--- /dev/null
+++ b/app/services/environments/create_for_build_service.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+module Environments
+ # This class creates an environment record for a build (a pipeline job).
+ class CreateForBuildService
+ def execute(build, merge_request: nil)
+ return unless build.instance_of?(::Ci::Build) && build.has_environment_keyword?
+
+ environment = to_resource(build, merge_request)
+
+ if environment.persisted?
+ build.persisted_environment = environment
+ build.assign_attributes(metadata_attributes: { expanded_environment_name: environment.name })
+ else
+ build.assign_attributes(status: :failed, failure_reason: :environment_creation_failure)
+ end
+
+ environment
+ end
+
+ private
+
+ # rubocop: disable Performance/ActiveRecordSubtransactionMethods
+ def to_resource(build, merge_request)
+ build.project.environments.safe_find_or_create_by(name: build.expanded_environment_name) do |environment|
+ # Initialize the attributes at creation
+ environment.auto_stop_in = expanded_auto_stop_in(build)
+ environment.tier = build.environment_tier_from_options
+ environment.merge_request = merge_request
+ end
+ end
+ # rubocop: enable Performance/ActiveRecordSubtransactionMethods
+
+ def expanded_auto_stop_in(build)
+ return unless build.environment_auto_stop_in
+
+ ExpandVariables.expand(build.environment_auto_stop_in, -> { build.simple_variables.sort_and_expand_all })
+ end
+ end
+end
diff --git a/app/services/environments/schedule_to_delete_review_apps_service.rb b/app/services/environments/schedule_to_delete_review_apps_service.rb
index b3b86689748..041b834f11b 100644
--- a/app/services/environments/schedule_to_delete_review_apps_service.rb
+++ b/app/services/environments/schedule_to_delete_review_apps_service.rb
@@ -58,7 +58,7 @@ module Environments
else
result.set_status(
:bad_request,
- error_message: "Failed to authorize deletions for some or all of the environments. Ask someone with more permissions to delete the environments."
+ error_message: "No environments found for scheduled deletion. Either your query did not match any environments (default parameters match environments that are 30 days or older), or you have insufficient permissions to delete matching environments."
)
result.set_unprocessable_entries(failed)
diff --git a/app/services/event_create_service.rb b/app/services/event_create_service.rb
index 019246dfc9f..662980fe506 100644
--- a/app/services/event_create_service.rb
+++ b/app/services/event_create_service.rb
@@ -25,18 +25,22 @@ 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)
- track_snowplow_event(merge_request, current_user,
- Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION,
- :create, 'merge_requests_users')
+ track_snowplow_event(
+ :created,
+ merge_request,
+ current_user
+ )
end
end
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)
- track_snowplow_event(merge_request, current_user,
- Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION,
- :close, 'merge_requests_users')
+ track_snowplow_event(
+ :closed,
+ merge_request,
+ current_user
+ )
end
end
@@ -47,9 +51,11 @@ 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)
- track_snowplow_event(merge_request, current_user,
- Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION,
- :merge, 'merge_requests_users')
+ track_snowplow_event(
+ :merged,
+ merge_request,
+ current_user
+ )
end
end
@@ -73,9 +79,12 @@ class EventCreateService
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)
- track_snowplow_event(note, current_user,
- Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION,
- :comment, 'merge_requests_users')
+ track_snowplow_event(
+ :commented,
+ note,
+ current_user
+ )
+
end
end
end
@@ -109,13 +118,13 @@ class EventCreateService
return [] if records.empty?
if create.any?
- track_snowplow_event(create.first, current_user,
+ old_track_snowplow_event(create.first, current_user,
Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION,
:create, 'design_users')
end
if update.any?
- track_snowplow_event(update.first, current_user,
+ old_track_snowplow_event(update.first, current_user,
Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION,
:update, 'design_users')
end
@@ -126,7 +135,7 @@ class EventCreateService
def destroy_designs(designs, current_user)
return [] unless designs.present?
- track_snowplow_event(designs.first, current_user,
+ old_track_snowplow_event(designs.first, current_user,
Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION,
:destroy, 'design_users')
create_record_events(designs.zip([:destroyed].cycle), current_user)
@@ -213,7 +222,15 @@ class EventCreateService
namespace = project.namespace
if Feature.enabled?(:route_hll_to_snowplow, namespace)
- Gitlab::Tracking.event(self.class.to_s, 'action_active_users_project_repo', namespace: namespace, user: current_user, project: project)
+ Gitlab::Tracking.event(
+ self.class.to_s,
+ :push,
+ label: 'usage_activity_by_stage_monthly.create.action_monthly_active_users_project_repo',
+ namespace: namespace,
+ user: current_user,
+ project: project,
+ context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: 'action_active_users_project_repo').to_context]
+ )
end
Users::LastPushEventService.new(current_user)
@@ -253,7 +270,10 @@ class EventCreateService
Gitlab::UsageDataCounters::TrackUniqueEvents.track_event(**params)
end
- def track_snowplow_event(record, current_user, category, action, label)
+ # This will be deleted as a part of
+ # https://gitlab.com/groups/gitlab-org/-/epics/8641
+ # once all the events are fixed
+ def old_track_snowplow_event(record, current_user, category, action, label)
return unless Feature.enabled?(:route_hll_to_snowplow_phase2)
project = record.project
@@ -266,6 +286,19 @@ class EventCreateService
user: current_user
)
end
+
+ def track_snowplow_event(action, record, user)
+ project = record.project
+ Gitlab::Tracking.event(
+ self.class.to_s,
+ action.to_s,
+ label: 'usage_activity_by_stage_monthly.create.merge_requests_users',
+ namespace: project.namespace,
+ user: user,
+ project: project,
+ context: [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: 'merge_requests_users').to_context]
+ )
+ end
end
EventCreateService.prepend_mod_with('EventCreateService')
diff --git a/app/services/git/base_hooks_service.rb b/app/services/git/base_hooks_service.rb
index 269637805ad..7158116fde1 100644
--- a/app/services/git/base_hooks_service.rb
+++ b/app/services/git/base_hooks_service.rb
@@ -53,11 +53,11 @@ module Git
def create_pipelines
return unless params.fetch(:create_pipelines, true)
- Ci::CreatePipelineService
- .new(project, current_user, pipeline_params)
- .execute!(:push, pipeline_options)
- rescue Ci::CreatePipelineService::CreateError => ex
- log_pipeline_errors(ex)
+ response = Ci::CreatePipelineService
+ .new(project, current_user, pipeline_params)
+ .execute(:push, **pipeline_options)
+
+ log_pipeline_errors(response.message) unless response.payload.persisted?
end
def execute_project_hooks
@@ -148,14 +148,14 @@ module Git
{}
end
- def log_pipeline_errors(exception)
+ def log_pipeline_errors(error_message)
data = {
class: self.class.name,
correlation_id: Labkit::Correlation::CorrelationId.current_id.to_s,
project_id: project.id,
project_path: project.full_path,
message: "Error creating pipeline",
- errors: exception.to_s,
+ errors: error_message,
pipeline_params: sanitized_pipeline_params
}
diff --git a/app/services/google_cloud/create_service_accounts_service.rb b/app/services/google_cloud/create_service_accounts_service.rb
index 9617161b8e9..ca0aa7c91df 100644
--- a/app/services/google_cloud/create_service_accounts_service.rb
+++ b/app/services/google_cloud/create_service_accounts_service.rb
@@ -10,8 +10,8 @@ module GoogleCloud
service_accounts_service.add_for_project(
environment_name,
service_account.project_id,
- service_account.to_json,
- service_account_key.to_json,
+ Gitlab::Json.dump(service_account),
+ Gitlab::Json.dump(service_account_key),
ProtectedBranch.protected?(project, environment_name) || ProtectedTag.protected?(project, environment_name)
)
diff --git a/app/services/google_cloud/generate_pipeline_service.rb b/app/services/google_cloud/generate_pipeline_service.rb
index be0c7a783c9..b6438d6f501 100644
--- a/app/services/google_cloud/generate_pipeline_service.rb
+++ b/app/services/google_cloud/generate_pipeline_service.rb
@@ -34,7 +34,8 @@ module GoogleCloud
end
def generate_commit_attributes
- if action == ACTION_DEPLOY_TO_CLOUD_RUN
+ case action
+ when ACTION_DEPLOY_TO_CLOUD_RUN
branch_name = "deploy-to-cloud-run-#{SecureRandom.hex(8)}"
{
commit_message: 'Enable Cloud Run deployments',
@@ -43,7 +44,7 @@ module GoogleCloud
branch_name: branch_name,
start_branch: branch_name
}
- elsif action == ACTION_DEPLOY_TO_CLOUD_STORAGE
+ when ACTION_DEPLOY_TO_CLOUD_STORAGE
branch_name = "deploy-to-cloud-storage-#{SecureRandom.hex(8)}"
{
commit_message: 'Enable Cloud Storage deployments',
@@ -73,7 +74,7 @@ module GoogleCloud
includes << { 'remote' => include_url }
gitlab_ci_yml['include'] = includes.uniq
- gitlab_ci_yml.to_yaml
+ gitlab_ci_yml.deep_stringify_keys.to_yaml
end
end
end
diff --git a/app/services/google_cloud/setup_cloudsql_instance_service.rb b/app/services/google_cloud/setup_cloudsql_instance_service.rb
index 10237f83b37..40184b927ad 100644
--- a/app/services/google_cloud/setup_cloudsql_instance_service.rb
+++ b/app/services/google_cloud/setup_cloudsql_instance_service.rb
@@ -13,7 +13,7 @@ module GoogleCloud
get_instance_response = google_api_client.get_cloudsql_instance(gcp_project_id, instance_name)
if get_instance_response.state != INSTANCE_STATE_RUNNABLE
- return error("CloudSQL instance not RUNNABLE: #{get_instance_response.to_json}")
+ return error("CloudSQL instance not RUNNABLE: #{Gitlab::Json.dump(get_instance_response)}")
end
save_instance_ci_vars(get_instance_response)
@@ -42,7 +42,7 @@ module GoogleCloud
success
rescue Google::Apis::Error => err
- error(message: err.to_json)
+ error(message: Gitlab::Json.dump(err))
end
private
@@ -97,7 +97,7 @@ module GoogleCloud
database_response = google_api_client.create_cloudsql_database(gcp_project_id, instance_name, database_name)
if database_response.status != OPERATION_STATE_DONE
- return error("Database creation failed: #{database_response.to_json}")
+ return error("Database creation failed: #{Gitlab::Json.dump(database_response)}")
end
success
@@ -109,7 +109,7 @@ module GoogleCloud
user_response = google_api_client.create_cloudsql_user(gcp_project_id, instance_name, username, password)
if user_response.status != OPERATION_STATE_DONE
- return error("User creation failed: #{user_response.to_json}")
+ return error("User creation failed: #{Gitlab::Json.dump(user_response)}")
end
success
diff --git a/app/services/groups/create_service.rb b/app/services/groups/create_service.rb
index d508865ef32..68bb6427350 100644
--- a/app/services/groups/create_service.rb
+++ b/app/services/groups/create_service.rb
@@ -57,7 +57,7 @@ module Groups
end
def after_create_hook
- track_experiment_event
+ # overridden in EE
end
def remove_unallowed_params
@@ -109,15 +109,6 @@ module Groups
@group.shared_runners_enabled = @group.parent.shared_runners_enabled
@group.allow_descendants_override_disabled_shared_runners = @group.parent.allow_descendants_override_disabled_shared_runners
end
-
- def track_experiment_event
- return unless group.persisted?
-
- # Track namespace created events to relate them with signed up events for
- # the same experiment. This will let us associate created namespaces to
- # users that signed up from the experimental logged out header.
- experiment(:logged_out_marketing_header, actor: current_user).track(:namespace_created, namespace: group)
- end
end
end
diff --git a/app/services/groups/update_service.rb b/app/services/groups/update_service.rb
index 2135892a95a..925a2acbb58 100644
--- a/app/services/groups/update_service.rb
+++ b/app/services/groups/update_service.rb
@@ -10,6 +10,8 @@ module Groups
reject_parent_id!
remove_unallowed_params
+ before_assignment_hook(group, params)
+
if renaming_group_with_container_registry_images?
group.errors.add(:base, container_images_error)
return false
@@ -25,8 +27,6 @@ module Groups
handle_changes
- before_assignment_hook(group, params)
-
handle_namespace_settings
group.assign_attributes(params)
diff --git a/app/services/incident_management/timeline_event_tags/base_service.rb b/app/services/incident_management/timeline_event_tags/base_service.rb
new file mode 100644
index 00000000000..7bb596dcd92
--- /dev/null
+++ b/app/services/incident_management/timeline_event_tags/base_service.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module IncidentManagement
+ module TimelineEventTags
+ class BaseService
+ def allowed?
+ user&.can?(:admin_incident_management_timeline_event_tag, project)
+ end
+
+ def success(timeline_event_tag)
+ ServiceResponse.success(payload: { timeline_event_tag: timeline_event_tag })
+ end
+
+ def error(message)
+ ServiceResponse.error(message: message)
+ end
+
+ def error_no_permissions
+ error(_('You have insufficient permissions to manage timeline event tags for this project'))
+ end
+
+ def error_in_save(timeline_event_tag)
+ error(timeline_event_tag.errors.full_messages.to_sentence)
+ end
+ end
+ end
+end
diff --git a/app/services/incident_management/timeline_event_tags/create_service.rb b/app/services/incident_management/timeline_event_tags/create_service.rb
new file mode 100644
index 00000000000..6742bb6ba5c
--- /dev/null
+++ b/app/services/incident_management/timeline_event_tags/create_service.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+module IncidentManagement
+ module TimelineEventTags
+ class CreateService < TimelineEventTags::BaseService
+ attr_reader :project, :user, :params
+
+ def initialize(project, user, params)
+ @project = project
+ @user = user
+ @params = params
+ end
+
+ def execute
+ return error_no_permissions unless allowed?
+
+ timeline_event_tag_params = {
+ project: project,
+ name: params[:name]
+ }
+
+ timeline_event_tag = IncidentManagement::TimelineEventTag.new(timeline_event_tag_params)
+
+ if timeline_event_tag.save
+ success(timeline_event_tag)
+ else
+ error_in_save(timeline_event_tag)
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/incident_management/timeline_events/create_service.rb b/app/services/incident_management/timeline_events/create_service.rb
index 5422b4ad6d2..71ff5b64515 100644
--- a/app/services/incident_management/timeline_events/create_service.rb
+++ b/app/services/incident_management/timeline_events/create_service.rb
@@ -5,6 +5,7 @@ module IncidentManagement
DEFAULT_ACTION = 'comment'
DEFAULT_EDITABLE = false
DEFAULT_AUTO_CREATED = false
+ AUTOCREATE_TAGS = [TimelineEventTag::START_TIME_TAG_NAME, TimelineEventTag::END_TIME_TAG_NAME].freeze
class CreateService < TimelineEvents::BaseService
def initialize(incident, user, params)
@@ -49,6 +50,15 @@ module IncidentManagement
new(incident, user, note: note, occurred_at: occurred_at, action: action, auto_created: true).execute
end
+ def change_severity(incident, user)
+ severity_label = IssuableSeverity::SEVERITY_LABELS[incident.severity.to_sym]
+ note = "@#{user.username} changed the incident severity to **#{severity_label}**"
+ occurred_at = incident.updated_at
+ action = 'severity'
+
+ new(incident, user, note: note, occurred_at: occurred_at, action: action, auto_created: true).execute
+ end
+
def change_labels(incident, user, added_labels: [], removed_labels: [])
return if Feature.disabled?(:incident_timeline_events_from_labels, incident.project)
@@ -85,10 +95,17 @@ module IncidentManagement
editable: params.fetch(:editable, DEFAULT_EDITABLE)
}
+ non_existing_tags = validate_tags(project, params[:timeline_event_tag_names])
+
+ return error("#{_("Following tags don't exist")}: #{non_existing_tags}") unless non_existing_tags.empty?
+
timeline_event = IncidentManagement::TimelineEvent.new(timeline_event_params)
- if timeline_event.save
+ if timeline_event.save(context: validation_context)
add_system_note(timeline_event)
+
+ create_timeline_event_tag_links(timeline_event, params[:timeline_event_tag_names])
+
track_usage_event(:incident_management_timeline_event_created, user.id)
success(timeline_event)
@@ -112,6 +129,53 @@ module IncidentManagement
SystemNoteService.add_timeline_event(timeline_event)
end
+
+ def validation_context
+ :user_input if !auto_created && params[:promoted_from_note].blank?
+ end
+
+ def create_timeline_event_tag_links(timeline_event, tag_names)
+ return unless tag_names&.any?
+
+ auto_create_predefined_tags(tag_names)
+
+ # Refetches the tag objects to consider predefined tags as well
+ tags = project.incident_management_timeline_event_tags.by_names(tag_names)
+
+ tag_links = tags.select(:id).map do |tag|
+ {
+ timeline_event_id: timeline_event.id,
+ timeline_event_tag_id: tag.id,
+ created_at: DateTime.current
+ }
+ end
+
+ IncidentManagement::TimelineEventTagLink.insert_all(tag_links) if tag_links.any?
+ end
+
+ def auto_create_predefined_tags(new_tags)
+ new_tags = new_tags.map(&:downcase)
+
+ tags_to_create = AUTOCREATE_TAGS.select { |tag| tag.downcase.in?(new_tags) }
+
+ tags_to_create.each do |name|
+ project.incident_management_timeline_event_tags.create(name: name)
+ end
+ end
+
+ def validate_tags(project, tag_names)
+ return [] unless tag_names&.any?
+
+ start_time_tag = AUTOCREATE_TAGS[0].downcase
+ end_time_tag = AUTOCREATE_TAGS[1].downcase
+
+ tag_names_downcased = tag_names.map(&:downcase)
+
+ tags = project.incident_management_timeline_event_tags.by_names(tag_names).pluck_names.map(&:downcase)
+
+ # remove tags from given tag_names and also remove predefined tags which can be auto created
+ tag_names_downcased - tags - [start_time_tag, end_time_tag]
+ end
end
end
end
diff --git a/app/services/incident_management/timeline_events/update_service.rb b/app/services/incident_management/timeline_events/update_service.rb
index 012e2f0e260..8d4e29c6857 100644
--- a/app/services/incident_management/timeline_events/update_service.rb
+++ b/app/services/incident_management/timeline_events/update_service.rb
@@ -8,18 +8,23 @@ module IncidentManagement
# @option params [string] note
# @option params [datetime] occurred_at
class UpdateService < TimelineEvents::BaseService
+ VALIDATION_CONTEXT = :user_input
+
def initialize(timeline_event, user, params)
@timeline_event = timeline_event
@incident = timeline_event.incident
@user = user
@note = params[:note]
@occurred_at = params[:occurred_at]
+ @validation_context = VALIDATION_CONTEXT
end
def execute
return error_no_permissions unless allowed?
- if timeline_event.update(update_params)
+ timeline_event.assign_attributes(update_params)
+
+ if timeline_event.save(context: validation_context)
add_system_note(timeline_event)
track_usage_event(:incident_management_timeline_event_edited, user.id)
@@ -31,7 +36,7 @@ module IncidentManagement
private
- attr_reader :timeline_event, :incident, :user, :note, :occurred_at
+ attr_reader :timeline_event, :incident, :user, :note, :occurred_at, :validation_context
def update_params
{ updated_by_user: user, note: note, occurred_at: occurred_at }.compact
diff --git a/app/services/issuable/bulk_update_service.rb b/app/services/issuable/bulk_update_service.rb
index 238f5ebddae..30444fa3938 100644
--- a/app/services/issuable/bulk_update_service.rb
+++ b/app/services/issuable/bulk_update_service.rb
@@ -68,9 +68,10 @@ module Issuable
end
def find_issuables(parent, model_class, ids)
- if parent.is_a?(Project)
+ case parent
+ when Project
projects = parent
- elsif parent.is_a?(Group)
+ when Group
projects = parent.all_projects
else
return
diff --git a/app/services/issuable/discussions_list_service.rb b/app/services/issuable/discussions_list_service.rb
new file mode 100644
index 00000000000..7aa0363af01
--- /dev/null
+++ b/app/services/issuable/discussions_list_service.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+# This service return notes grouped by discussion ID and paginated per discussion.
+# System notes also have a discussion ID assigned including Synthetic system notes.
+module Issuable
+ class DiscussionsListService
+ include RendersNotes
+ include Gitlab::Utils::StrongMemoize
+
+ attr_reader :current_user, :issuable, :params
+
+ def initialize(current_user, issuable, params = {})
+ @current_user = current_user
+ @issuable = issuable
+ @params = params.dup
+ end
+
+ def execute
+ return Note.none unless can_read_issuable?
+
+ notes = NotesFinder.new(current_user, params.merge({ target: issuable, project: issuable.project }))
+ .execute.with_web_entity_associations.inc_relations_for_view.fresh
+
+ if paginator
+ paginated_discussions_by_type = paginator.records.group_by(&:table_name)
+
+ notes = if paginated_discussions_by_type['notes'].present?
+ notes.with_discussion_ids(paginated_discussions_by_type['notes'].map(&:discussion_id))
+ else
+ notes.none
+ end
+ end
+
+ if params[:notes_filter] != UserPreference::NOTES_FILTERS[:only_comments]
+ notes = ResourceEvents::MergeIntoNotesService.new(
+ issuable, current_user, paginated_notes: paginated_discussions_by_type
+ ).execute(notes)
+ end
+
+ notes = prepare_notes_for_rendering(notes)
+
+ # TODO: optimize this permission check.
+ # Given this loads notes on a single issuable and current permission system, we should not have to check
+ # permission on every single note. We should be able to check permission on the given issuable or its container,
+ # which should result in just one permission check. Perhaps that should also either be passed to NotesFinder or
+ # should be done in NotesFinder, which would decide right away if it would need to return no notes
+ # or if it should just filter out internal notes.
+ notes = notes.select { |n| n.readable_by?(current_user) }
+
+ Discussion.build_collection(notes, issuable)
+ end
+
+ def paginator
+ return if params[:per_page].blank?
+ return if issuable.instance_of?(MergeRequest) && Feature.disabled?(:paginated_mr_discussions, issuable.project)
+
+ strong_memoize(:paginator) do
+ issuable
+ .discussion_root_note_ids(notes_filter: params[:notes_filter])
+ .keyset_paginate(cursor: params[:cursor], per_page: params[:per_page].to_i)
+ end
+ end
+
+ def can_read_issuable?
+ return Ability.allowed?(current_user, :read_security_resource, issuable) if issuable.is_a?(Vulnerability)
+
+ Ability.allowed?(current_user, :"read_#{issuable.to_ability_name}", issuable)
+ end
+ end
+end
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index e5feb4422f6..0aed9e3ba40 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -163,6 +163,7 @@ module Issues
invalidate_milestone_issue_counters(issue)
send_milestone_change_notification(issue)
+ GraphqlTriggers.issuable_milestone_updated(issue)
end
def invalidate_milestone_issue_counters(issue)
diff --git a/app/services/jira_import/start_import_service.rb b/app/services/jira_import/start_import_service.rb
index 4d1f2c94ac8..9cd56cf339e 100644
--- a/app/services/jira_import/start_import_service.rb
+++ b/app/services/jira_import/start_import_service.rb
@@ -40,7 +40,7 @@ module JiraImport
project.import_type = 'jira'
project.save! && jira_import.schedule!
- ServiceResponse.success(payload: { import_data: jira_import } )
+ ServiceResponse.success(payload: { import_data: jira_import })
rescue StandardError => ex
# in case project.save! raises an error
Gitlab::ErrorTracking.track_exception(ex, project_id: project.id)
diff --git a/app/services/labels/transfer_service.rb b/app/services/labels/transfer_service.rb
index a79e5b00232..79e807d8010 100644
--- a/app/services/labels/transfer_service.rb
+++ b/app/services/labels/transfer_service.rb
@@ -51,7 +51,7 @@ module Labels
# rubocop: disable CodeReuse/ActiveRecord
def group_labels_applied_to_issues
@labels_applied_to_issues ||= Label.joins(:issues)
- .joins("INNER JOIN namespaces on namespaces.id = labels.group_id AND namespaces.type = 'Group'" )
+ .joins("INNER JOIN namespaces on namespaces.id = labels.group_id AND namespaces.type = 'Group'")
.where(issues: { project_id: project.id }).reorder(nil)
end
# rubocop: enable CodeReuse/ActiveRecord
@@ -59,7 +59,7 @@ module Labels
# rubocop: disable CodeReuse/ActiveRecord
def group_labels_applied_to_merge_requests
@labels_applied_to_mrs ||= Label.joins(:merge_requests)
- .joins("INNER JOIN namespaces on namespaces.id = labels.group_id AND namespaces.type = 'Group'" )
+ .joins("INNER JOIN namespaces on namespaces.id = labels.group_id AND namespaces.type = 'Group'")
.where(merge_requests: { target_project_id: project.id }).reorder(nil)
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/services/loose_foreign_keys/process_deleted_records_service.rb b/app/services/loose_foreign_keys/process_deleted_records_service.rb
index 54f54d99afb..8700276c982 100644
--- a/app/services/loose_foreign_keys/process_deleted_records_service.rb
+++ b/app/services/loose_foreign_keys/process_deleted_records_service.rb
@@ -9,6 +9,7 @@ module LooseForeignKeys
end
def execute
+ raised_error = false
modification_tracker = ModificationTracker.new
tracked_tables.cycle do |table|
records = load_batch_for_table(table)
@@ -35,13 +36,30 @@ module LooseForeignKeys
break if modification_tracker.over_limit?
end
+ ::Gitlab::Metrics::LooseForeignKeysSlis.record_apdex(
+ success: !modification_tracker.over_limit?,
+ db_config_name: db_config_name
+ )
+
modification_tracker.stats
+ rescue StandardError
+ raised_error = true
+ raise
+ ensure
+ ::Gitlab::Metrics::LooseForeignKeysSlis.record_error_rate(
+ error: raised_error,
+ db_config_name: db_config_name
+ )
end
private
attr_reader :connection
+ def db_config_name
+ ::Gitlab::Database.db_config_name(connection)
+ end
+
def load_batch_for_table(table)
fully_qualified_table_name = "#{current_schema}.#{table}"
LooseForeignKeys::DeletedRecord.load_batch_for_table(fully_qualified_table_name, BATCH_SIZE)
diff --git a/app/services/markup/rendering_service.rb b/app/services/markup/rendering_service.rb
new file mode 100644
index 00000000000..0142d600522
--- /dev/null
+++ b/app/services/markup/rendering_service.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+
+module Markup
+ class RenderingService
+ include ActionView::Helpers::TextHelper
+
+ # Let's increase the render timeout
+ # For a smaller one, a test that renders the blob content statically fails
+ # We can consider removing this custom timeout when markup_rendering_timeout FF is removed:
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/365358
+ RENDER_TIMEOUT = 5.seconds
+
+ def initialize(text, file_name: nil, context: {}, postprocess_context: {})
+ @text = text
+ @file_name = file_name
+ @context = context
+ @postprocess_context = postprocess_context
+ end
+
+ def execute
+ return '' unless text.present?
+ return context.delete(:rendered) if context.has_key?(:rendered)
+
+ html = file_name ? markup_unsafe : markdown_unsafe
+
+ return '' unless html.present?
+
+ postprocess_context ? postprocess(html) : html
+ end
+
+ private
+
+ def markup_unsafe
+ markup = proc do
+ if Gitlab::MarkupHelper.gitlab_markdown?(file_name)
+ markdown_unsafe
+ elsif Gitlab::MarkupHelper.asciidoc?(file_name)
+ asciidoc_unsafe
+ elsif Gitlab::MarkupHelper.plain?(file_name)
+ plain_unsafe
+ else
+ other_markup_unsafe
+ end
+ end
+
+ if Feature.enabled?(:markup_rendering_timeout, context[:project])
+ Gitlab::RenderTimeout.timeout(foreground: RENDER_TIMEOUT, &markup)
+ else
+ markup.call
+ end
+ rescue StandardError => e
+ Gitlab::ErrorTracking.track_exception(e, project_id: context[:project]&.id, file_name: file_name)
+
+ simple_format(text)
+ end
+
+ def markdown_unsafe
+ Banzai.render(text, context)
+ end
+
+ def asciidoc_unsafe
+ Gitlab::Asciidoc.render(text, context)
+ end
+
+ def plain_unsafe
+ "<pre class=\"plain-readme\">#{text}</pre>"
+ end
+
+ def other_markup_unsafe
+ Gitlab::OtherMarkup.render(file_name, text, context)
+ end
+
+ def postprocess(html)
+ Banzai.post_process(html, context.reverse_merge(postprocess_context))
+ end
+
+ attr_reader :text, :file_name, :context, :postprocess_context
+ end
+end
diff --git a/app/services/members/approve_access_request_service.rb b/app/services/members/approve_access_request_service.rb
index 5337279f702..51f9492ec91 100644
--- a/app/services/members/approve_access_request_service.rb
+++ b/app/services/members/approve_access_request_service.rb
@@ -16,7 +16,7 @@ module Members
private
def validate_access!(access_requester)
- raise Gitlab::Access::AccessDeniedError unless can_update_access_requester?(access_requester)
+ raise Gitlab::Access::AccessDeniedError unless can_approve_access_requester?(access_requester)
if approving_member_with_owner_access_level?(access_requester) &&
cannot_assign_owner_responsibilities_to_member_in_project?(access_requester)
@@ -24,8 +24,8 @@ module Members
end
end
- def can_update_access_requester?(access_requester)
- can?(current_user, update_member_permission(access_requester), access_requester)
+ def can_approve_access_requester?(access_requester)
+ can?(current_user, :admin_member_access_request, access_requester.source)
end
def approving_member_with_owner_access_level?(access_requester)
diff --git a/app/services/members/destroy_service.rb b/app/services/members/destroy_service.rb
index ce79907e8a8..f18269454e3 100644
--- a/app/services/members/destroy_service.rb
+++ b/app/services/members/destroy_service.rb
@@ -48,6 +48,10 @@ module Members
def authorized?(member, destroy_bot)
return can_destroy_bot_member?(member) if destroy_bot
+ if member.request?
+ return can_destroy_member_access_request?(member) || can_withdraw_member_access_request?(member)
+ end
+
can_destroy_member?(member)
end
@@ -106,6 +110,14 @@ module Members
can?(current_user, destroy_bot_member_permission(member), member)
end
+ def can_destroy_member_access_request?(member)
+ can?(current_user, :admin_member_access_request, member.source)
+ end
+
+ def can_withdraw_member_access_request?(member)
+ can?(current_user, :withdraw_member_access_request, member)
+ end
+
def destroying_member_with_owner_access_level?(member)
member.owner?
end
diff --git a/app/services/members/update_service.rb b/app/services/members/update_service.rb
index 8ef3e307519..0e6b02f7a80 100644
--- a/app/services/members/update_service.rb
+++ b/app/services/members/update_service.rb
@@ -2,37 +2,84 @@
module Members
class UpdateService < Members::BaseService
- # returns the updated member
- def execute(member, permission: :update)
- raise Gitlab::Access::AccessDeniedError unless can?(current_user, action_member_permission(permission, member), member)
- raise Gitlab::Access::AccessDeniedError if prevent_upgrade_to_owner?(member) || prevent_downgrade_from_owner?(member)
+ # @param members [Member, Array<Member>]
+ # returns the updated member(s)
+ def execute(members, permission: :update)
+ members = Array.wrap(members)
- return success(member: member) if update_results_in_no_change?(member)
-
- old_access_level = member.human_access
- old_expiry = member.expires_at
-
- if member.update(params)
- after_execute(action: permission, old_access_level: old_access_level, old_expiry: old_expiry, member: member)
-
- # Deletes only confidential issues todos for guests
- enqueue_delete_todos(member) if downgrading_to_guest?
+ old_access_level_expiry_map = members.to_h do |member|
+ [member.id, { human_access: member.human_access, expires_at: member.expires_at }]
end
- if member.errors.any?
- error(member.errors.full_messages.to_sentence, pass_back: { member: member })
+ if Feature.enabled?(:bulk_update_membership_roles, current_user)
+ multiple_members_update(members, permission, old_access_level_expiry_map)
else
- success(member: member)
+ single_member_update(members.first, permission, old_access_level_expiry_map)
end
+
+ prepare_response(members)
end
private
- def update_results_in_no_change?(member)
- return false if params[:expires_at]&.to_date != member.expires_at
- return false if params[:access_level] != member.access_level
+ def single_member_update(member, permission, old_access_level_expiry_map)
+ raise Gitlab::Access::AccessDeniedError unless has_update_permissions?(member, permission)
+
+ member.attributes = params
+ return success(member: member) unless member.changed?
+
+ post_update(member, permission, old_access_level_expiry_map) if member.save
+ end
+
+ def multiple_members_update(members, permission, old_access_level_expiry_map)
+ begin
+ updated_members =
+ Member.transaction do
+ # Using `next` with `filter_map` avoids the `post_update` call for the member that resulted in no change
+ members.filter_map do |member|
+ raise Gitlab::Access::AccessDeniedError unless has_update_permissions?(member, permission)
+
+ member.attributes = params
+ next unless member.changed?
+
+ member.save!
+ member
+ end
+ end
+ rescue ActiveRecord::RecordInvalid
+ return
+ end
+
+ updated_members.each { |member| post_update(member, permission, old_access_level_expiry_map) }
+ end
+
+ def post_update(member, permission, old_access_level_expiry_map)
+ old_access_level = old_access_level_expiry_map[member.id][:human_access]
+ old_expiry = old_access_level_expiry_map[member.id][:expires_at]
+
+ after_execute(action: permission, old_access_level: old_access_level, old_expiry: old_expiry, member: member)
+ enqueue_delete_todos(member) if downgrading_to_guest? # Deletes only confidential issues todos for guests
+ end
+
+ def prepare_response(members)
+ errored_member = members.detect { |member| member.errors.any? }
+ if errored_member.present?
+ return error(errored_member.errors.full_messages.to_sentence, pass_back: { member: errored_member })
+ end
+
+ # TODO: Remove the :member key when removing the bulk_update_membership_roles FF and update where it's used.
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/373257
+ if members.one?
+ success(member: members.first)
+ else
+ success(members: members)
+ end
+ end
- true
+ def has_update_permissions?(member, permission)
+ can?(current_user, action_member_permission(permission, member), member) &&
+ !prevent_upgrade_to_owner?(member) &&
+ !prevent_downgrade_from_owner?(member)
end
def downgrading_to_guest?
diff --git a/app/services/merge_requests/add_context_service.rb b/app/services/merge_requests/add_context_service.rb
index 7b441ddf5e4..2ce6073050e 100644
--- a/app/services/merge_requests/add_context_service.rb
+++ b/app/services/merge_requests/add_context_service.rb
@@ -65,7 +65,7 @@ module MergeRequests
sha: sha,
authored_date: Gitlab::Database.sanitize_timestamp(commit_hash[:authored_date]),
committed_date: Gitlab::Database.sanitize_timestamp(commit_hash[:committed_date]),
- trailers: commit_hash.fetch(:trailers, {}).to_json
+ trailers: Gitlab::Json.dump(commit_hash.fetch(:trailers, {}))
)
end
end
diff --git a/app/services/merge_requests/after_create_service.rb b/app/services/merge_requests/after_create_service.rb
index 9d12eb80eb6..20b32dbc2a0 100644
--- a/app/services/merge_requests/after_create_service.rb
+++ b/app/services/merge_requests/after_create_service.rb
@@ -5,6 +5,8 @@ module MergeRequests
include Gitlab::Utils::StrongMemoize
def execute(merge_request)
+ merge_request.ensure_merge_request_diff
+
prepare_for_mergeability(merge_request)
prepare_merge_request(merge_request)
end
diff --git a/app/services/merge_requests/approval_service.rb b/app/services/merge_requests/approval_service.rb
index 5761e34caff..72f398ce415 100644
--- a/app/services/merge_requests/approval_service.rb
+++ b/app/services/merge_requests/approval_service.rb
@@ -11,6 +11,8 @@ module MergeRequests
reset_approvals_cache(merge_request)
merge_request_activity_counter.track_approve_mr_action(user: current_user, merge_request: merge_request)
+ trigger_merge_request_merge_status_updated(merge_request)
+ trigger_merge_request_reviewers_updated(merge_request)
# Approval side effects (things not required to be done immediately but
# should happen after a successful approval) should be done asynchronously
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index cfd7c645b7e..e7ab2c062ee 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -20,7 +20,7 @@ module MergeRequests
end
def execute_hooks(merge_request, action = 'open', old_rev: nil, old_associations: {})
- merge_data = hook_data(merge_request, action, old_rev: old_rev, old_associations: old_associations)
+ merge_data = Gitlab::Lazy.new { hook_data(merge_request, action, old_rev: old_rev, old_associations: old_associations) }
merge_request.project.execute_hooks(merge_data, :merge_request_hooks)
merge_request.project.execute_integrations(merge_data, :merge_request_hooks)
@@ -249,6 +249,10 @@ module MergeRequests
def trigger_merge_request_reviewers_updated(merge_request)
GraphqlTriggers.merge_request_reviewers_updated(merge_request)
end
+
+ def trigger_merge_request_merge_status_updated(merge_request)
+ GraphqlTriggers.merge_request_merge_status_updated(merge_request)
+ end
end
end
diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb
index 8e0f72eb380..04d08f257f1 100644
--- a/app/services/merge_requests/create_service.rb
+++ b/app/services/merge_requests/create_service.rb
@@ -14,11 +14,15 @@ module MergeRequests
end
def after_create(issuable)
- issuable.mark_as_preparing
+ current_user_id = current_user.id
+
+ issuable.run_after_commit do
+ # Add new items to MergeRequests::AfterCreateService if they can
+ # be performed in Sidekiq
+ NewMergeRequestWorker.perform_async(issuable.id, current_user_id)
+ end
- # Add new items to MergeRequests::AfterCreateService if they can
- # be performed in Sidekiq
- NewMergeRequestWorker.perform_async(issuable.id, current_user.id)
+ issuable.mark_as_preparing
super
end
@@ -34,7 +38,12 @@ module MergeRequests
# callback (e.g. after_create), a database transaction will be
# open while the Gitaly RPC waits. To avoid an idle in transaction
# timeout, we do this before we attempt to save the merge request.
- merge_request.eager_fetch_ref!
+
+ if Feature.enabled?(:async_merge_request_diff_creation, current_user)
+ merge_request.skip_ensure_merge_request_diff = true
+ else
+ merge_request.eager_fetch_ref!
+ end
end
def set_projects!
@@ -59,4 +68,4 @@ module MergeRequests
end
end
-MergeRequests::CreateService.include_mod_with('MergeRequests::CreateService')
+MergeRequests::CreateService.prepend_mod_with('MergeRequests::CreateService')
diff --git a/app/services/merge_requests/mergeability/run_checks_service.rb b/app/services/merge_requests/mergeability/run_checks_service.rb
index 7f205c8dd6c..740a6feac2c 100644
--- a/app/services/merge_requests/mergeability/run_checks_service.rb
+++ b/app/services/merge_requests/mergeability/run_checks_service.rb
@@ -38,7 +38,7 @@ module MergeRequests
def failure_reason
raise 'Execute needs to be called before' if results.nil?
- results.find(&:failed?)&.payload&.fetch(:reason)
+ results.find(&:failed?)&.payload&.fetch(:reason)&.to_sym
end
private
@@ -46,7 +46,6 @@ module MergeRequests
attr_reader :merge_request, :params, :results
def run_check(check)
- return check.execute unless Feature.enabled?(:mergeability_caching, merge_request.project)
return check.execute unless check.cacheable?
cached_result = cached_results.read(merge_check: check)
diff --git a/app/services/merge_requests/mergeability_check_service.rb b/app/services/merge_requests/mergeability_check_service.rb
index 1ce44f465cd..2a3f417a33b 100644
--- a/app/services/merge_requests/mergeability_check_service.rb
+++ b/app/services/merge_requests/mergeability_check_service.rb
@@ -156,8 +156,7 @@ module MergeRequests
end
def merge_to_ref
- params = { allow_conflicts: Feature.enabled?(:display_merge_conflicts_in_diff, project) }
- result = MergeRequests::MergeToRefService.new(project: project, current_user: merge_request.author, params: params).execute(merge_request)
+ result = MergeRequests::MergeToRefService.new(project: project, current_user: merge_request.author, params: {}).execute(merge_request)
result[:status] == :success
end
diff --git a/app/services/merge_requests/remove_approval_service.rb b/app/services/merge_requests/remove_approval_service.rb
index 52628729519..8387c23fe3f 100644
--- a/app/services/merge_requests/remove_approval_service.rb
+++ b/app/services/merge_requests/remove_approval_service.rb
@@ -17,6 +17,8 @@ module MergeRequests
reset_approvals_cache(merge_request)
create_note(merge_request)
merge_request_activity_counter.track_unapprove_mr_action(user: current_user)
+ trigger_merge_request_merge_status_updated(merge_request)
+ trigger_merge_request_reviewers_updated(merge_request)
end
success
diff --git a/app/services/merge_requests/update_assignees_service.rb b/app/services/merge_requests/update_assignees_service.rb
index 79a3e9f3c22..d45d55cbebc 100644
--- a/app/services/merge_requests/update_assignees_service.rb
+++ b/app/services/merge_requests/update_assignees_service.rb
@@ -19,16 +19,9 @@ module MergeRequests
attrs = update_attrs.merge(assignee_ids: new_ids)
- # We now have assignees validation on merge request
- # If we use an update with bang, it will explode,
- # instead we need to check if its valid then return if its not valid.
- if Feature.enabled?(:limit_assignees_per_issuable)
- merge_request.update(**attrs)
-
- return merge_request unless merge_request.valid?
- else
- merge_request.update!(**attrs)
- end
+ merge_request.update(**attrs)
+
+ return merge_request unless merge_request.valid?
# Defer the more expensive operations (handle_assignee_changes) to the background
MergeRequests::HandleAssigneesChangeService
diff --git a/app/services/metrics/dashboard/self_monitoring_dashboard_service.rb b/app/services/metrics/dashboard/self_monitoring_dashboard_service.rb
index 0651e569d07..62264281a02 100644
--- a/app/services/metrics/dashboard/self_monitoring_dashboard_service.rb
+++ b/app/services/metrics/dashboard/self_monitoring_dashboard_service.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-# Fetches the self monitoring metrics dashboard and formats the output.
+# Fetches the self-monitoring metrics dashboard and formats the output.
# Use Gitlab::Metrics::Dashboard::Finder to retrieve dashboards.
module Metrics
module Dashboard
diff --git a/app/services/milestones/transfer_service.rb b/app/services/milestones/transfer_service.rb
index bbf6920f83b..fa6b461b75d 100644
--- a/app/services/milestones/transfer_service.rb
+++ b/app/services/milestones/transfer_service.rb
@@ -62,7 +62,7 @@ module Milestones
# rubocop: enable CodeReuse/ActiveRecord
def find_or_create_milestone(milestone)
- params = milestone.attributes.slice('title', 'description', 'start_date', 'due_date')
+ params = milestone.attributes.slice('title', 'description', 'start_date', 'due_date', 'state')
FindOrCreateService.new(project, current_user, params).execute
end
diff --git a/app/services/namespaces/statistics_refresher_service.rb b/app/services/namespaces/statistics_refresher_service.rb
index 805060cdee9..2580d2f09fd 100644
--- a/app/services/namespaces/statistics_refresher_service.rb
+++ b/app/services/namespaces/statistics_refresher_service.rb
@@ -5,6 +5,7 @@ module Namespaces
RefresherError = Class.new(StandardError)
def execute(root_namespace)
+ root_namespace = root_namespace.root_ancestor # just in case the true root isn't passed
root_storage_statistics = find_or_create_root_storage_statistics(root_namespace.id)
root_storage_statistics.recalculate!
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index 1aaf7fb769a..555d60dc291 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -137,8 +137,6 @@ module Notes
end
def invalid_assignees?(update_params)
- return false unless Feature.enabled?(:limit_assignees_per_issuable)
-
if update_params.key?(:assignee_ids)
possible_assignees = update_params[:assignee_ids]&.uniq&.size
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb
index 1224cf80b76..660d9891e46 100644
--- a/app/services/notification_service.rb
+++ b/app/services/notification_service.rb
@@ -16,6 +16,16 @@
# NotificationService.new.async.new_issue(issue, current_user)
#
class NotificationService
+ # These should not be called by the MailScheduler::NotificationServiceWorker -
+ # what would it even mean?
+ EXCLUDED_ACTIONS = %i[async].freeze
+
+ def self.permitted_actions
+ @permitted_actions ||= gitlab_extensions.flat_map do |klass|
+ klass.public_instance_methods(false) - EXCLUDED_ACTIONS
+ end.to_set
+ end
+
class Async
attr_reader :parent
diff --git a/app/services/packages/debian/create_distribution_service.rb b/app/services/packages/debian/create_distribution_service.rb
index b4b1ec952ef..218423bb8e3 100644
--- a/app/services/packages/debian/create_distribution_service.rb
+++ b/app/services/packages/debian/create_distribution_service.rb
@@ -61,7 +61,7 @@ module Packages
create_objects(distribution.architectures, architectures, error_label: 'Architecture')
end
- def create_objects(objects, object_names_from_params, error_label: )
+ def create_objects(objects, object_names_from_params, error_label:)
object_names_from_params.each do |name|
new_object = objects.create(name: name)
append_errors(new_object, error_label)
diff --git a/app/services/packages/debian/update_distribution_service.rb b/app/services/packages/debian/update_distribution_service.rb
index 218167ecdc5..5096bd5361f 100644
--- a/app/services/packages/debian/update_distribution_service.rb
+++ b/app/services/packages/debian/update_distribution_service.rb
@@ -58,7 +58,7 @@ module Packages
update_objects(distribution.architectures, architectures, error_label: 'Architecture')
end
- def update_objects(objects, object_names_from_params, error_label: )
+ def update_objects(objects, object_names_from_params, error_label:)
current_object_names = objects.map(&:name)
missing_object_names = object_names_from_params - current_object_names
extra_object_names = current_object_names - object_names_from_params
diff --git a/app/services/packages/maven/metadata/base_create_xml_service.rb b/app/services/packages/maven/metadata/base_create_xml_service.rb
index 4d5cab4978e..3b0d93e1dfb 100644
--- a/app/services/packages/maven/metadata/base_create_xml_service.rb
+++ b/app/services/packages/maven/metadata/base_create_xml_service.rb
@@ -8,13 +8,16 @@ module Packages
INDENT_SPACE = 2
- def initialize(metadata_content:, package:)
+ def initialize(metadata_content:, package:, logger: nil)
@metadata_content = metadata_content
@package = package
+ @logger = logger || Gitlab::AppJsonLogger
end
private
+ attr_reader :logger
+
def xml_doc
strong_memoize(:xml_doc) do
Nokogiri::XML(@metadata_content) do |config|
diff --git a/app/services/packages/maven/metadata/create_versions_xml_service.rb b/app/services/packages/maven/metadata/create_versions_xml_service.rb
index 13b6efa8650..c2ac7fea703 100644
--- a/app/services/packages/maven/metadata/create_versions_xml_service.rb
+++ b/app/services/packages/maven/metadata/create_versions_xml_service.rb
@@ -67,6 +67,12 @@ module Packages
def update_release
return false if release_coherent?
+ unless release_xml_node.present?
+ log_malformed_content('Missing release tag')
+
+ return false
+ end
+
if release_from_database
release_xml_node.content = release_from_database
else
@@ -159,6 +165,15 @@ module Packages
non_snapshot_versions_from_database.last
end
end
+
+ def log_malformed_content(reason)
+ logger.warn(
+ message: 'A malformed metadata file has been encountered',
+ reason: reason,
+ project_id: @package.project_id,
+ package_id: @package.id
+ )
+ end
end
end
end
diff --git a/app/services/packages/npm/create_package_service.rb b/app/services/packages/npm/create_package_service.rb
index a3596314199..dd074f7472b 100644
--- a/app/services/packages/npm/create_package_service.rb
+++ b/app/services/packages/npm/create_package_service.rb
@@ -81,7 +81,7 @@ module Packages
# - https://blog.aaronlenoir.com/2017/11/10/get-original-length-from-base-64-string/
# - https://en.wikipedia.org/wiki/Base64#Decoding_Base64_with_padding
encoded_data = attachment['data']
- ((encoded_data.length * 0.75 ) - encoded_data[-2..].count('=')).to_i
+ ((encoded_data.length * 0.75) - encoded_data[-2..].count('=')).to_i
end
end
diff --git a/app/services/packages/rpm/parse_package_service.rb b/app/services/packages/rpm/parse_package_service.rb
index 689a161a81a..18b916a9d8b 100644
--- a/app/services/packages/rpm/parse_package_service.rb
+++ b/app/services/packages/rpm/parse_package_service.rb
@@ -25,7 +25,8 @@ module Packages
epoch: package_tags[:epoch] || '0',
changelogs: build_changelogs,
requirements: build_requirements,
- provides: build_provides
+ provides: build_provides,
+ directories: package_tags[:dirnames]
}.merge(extract_static_attributes)
end
diff --git a/app/services/packages/rpm/repository_metadata/base_builder.rb b/app/services/packages/rpm/repository_metadata/base_builder.rb
deleted file mode 100644
index 2c0a11457ec..00000000000
--- a/app/services/packages/rpm/repository_metadata/base_builder.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-module Packages
- module Rpm
- module RepositoryMetadata
- class BaseBuilder
- def initialize(xml: nil, data: {})
- @xml = Nokogiri::XML(xml) if xml.present?
- @data = data
- end
-
- def execute
- return build_empty_structure if xml.blank?
-
- update_xml_document
- update_package_count
- xml.to_xml
- end
-
- private
-
- attr_reader :xml, :data
-
- def build_empty_structure
- Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
- xml.method_missing(self.class::ROOT_TAG, self.class::ROOT_ATTRIBUTES)
- end.to_xml
- end
-
- def update_xml_document
- # Add to the root xml element a new package metadata node
- xml.at(self.class::ROOT_TAG).add_child(build_new_node)
- end
-
- def update_package_count
- packages_count = xml.css("//#{self.class::ROOT_TAG}/package").count
-
- xml.at(self.class::ROOT_TAG).attributes["packages"].value = packages_count.to_s
- end
-
- def build_new_node
- raise NotImplementedError, "#{self.class} should implement #{__method__}"
- end
- end
- end
- end
-end
diff --git a/app/services/packages/rpm/repository_metadata/build_filelist_xml.rb b/app/services/packages/rpm/repository_metadata/build_filelist_xml.rb
deleted file mode 100644
index 01fb36f4b91..00000000000
--- a/app/services/packages/rpm/repository_metadata/build_filelist_xml.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-module Packages
- module Rpm
- module RepositoryMetadata
- class BuildFilelistXml < ::Packages::Rpm::RepositoryMetadata::BaseBuilder
- ROOT_TAG = 'filelists'
- ROOT_ATTRIBUTES = {
- xmlns: 'http://linux.duke.edu/metadata/filelists',
- packages: '0'
- }.freeze
- end
- end
- end
-end
diff --git a/app/services/packages/rpm/repository_metadata/build_filelist_xml_service.rb b/app/services/packages/rpm/repository_metadata/build_filelist_xml_service.rb
new file mode 100644
index 00000000000..47cbba76fa4
--- /dev/null
+++ b/app/services/packages/rpm/repository_metadata/build_filelist_xml_service.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+module Packages
+ module Rpm
+ module RepositoryMetadata
+ class BuildFilelistXmlService < BuildXmlBaseService
+ ROOT_TAG = 'filelists'
+ ROOT_ATTRIBUTES = {
+ xmlns: 'http://linux.duke.edu/metadata/filelists',
+ packages: '0'
+ }.freeze
+
+ def execute
+ super do |xml|
+ xml.package(pkgid: data[:pkgid], name: data[:name], arch: data[:arch]) do
+ xml.version epoch: data[:epoch], ver: data[:version], rel: data[:release]
+ build_file_nodes(xml)
+ end
+ end
+ end
+
+ private
+
+ def build_file_nodes(xml)
+ data[:files].each do |path|
+ attributes = dir?(path) ? { type: 'dir' } : {}
+
+ xml.file path, **attributes
+ end
+ end
+
+ def dir?(path)
+ # Add trailing slash to path to check
+ # if it exists in directories list
+ data[:directories].include? File.join(path, '')
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/packages/rpm/repository_metadata/build_other_xml.rb b/app/services/packages/rpm/repository_metadata/build_other_xml.rb
deleted file mode 100644
index 4bf61c901a3..00000000000
--- a/app/services/packages/rpm/repository_metadata/build_other_xml.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-module Packages
- module Rpm
- module RepositoryMetadata
- class BuildOtherXml < ::Packages::Rpm::RepositoryMetadata::BaseBuilder
- ROOT_TAG = 'otherdata'
- ROOT_ATTRIBUTES = {
- xmlns: 'http://linux.duke.edu/metadata/other',
- packages: '0'
- }.freeze
- end
- end
- end
-end
diff --git a/app/services/packages/rpm/repository_metadata/build_other_xml_service.rb b/app/services/packages/rpm/repository_metadata/build_other_xml_service.rb
new file mode 100644
index 00000000000..00e88f4f548
--- /dev/null
+++ b/app/services/packages/rpm/repository_metadata/build_other_xml_service.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+module Packages
+ module Rpm
+ module RepositoryMetadata
+ class BuildOtherXmlService < BuildXmlBaseService
+ ROOT_TAG = 'otherdata'
+ ROOT_ATTRIBUTES = {
+ xmlns: 'http://linux.duke.edu/metadata/other',
+ packages: '0'
+ }.freeze
+
+ def execute
+ super do |xml|
+ xml.package(pkgid: data[:pkgid], name: data[:name], arch: data[:arch]) do
+ xml.version epoch: data[:epoch], ver: data[:version], rel: data[:release]
+ build_changelog_nodes(xml)
+ end
+ end
+ end
+
+ private
+
+ def build_changelog_nodes(xml)
+ data[:changelogs].each do |changelog|
+ xml.changelog changelog[:changelogtext], date: changelog[:changelogtime]
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/packages/rpm/repository_metadata/build_primary_xml.rb b/app/services/packages/rpm/repository_metadata/build_primary_xml.rb
deleted file mode 100644
index 580bf844a0c..00000000000
--- a/app/services/packages/rpm/repository_metadata/build_primary_xml.rb
+++ /dev/null
@@ -1,88 +0,0 @@
-# frozen_string_literal: true
-module Packages
- module Rpm
- module RepositoryMetadata
- class BuildPrimaryXml < ::Packages::Rpm::RepositoryMetadata::BaseBuilder
- ROOT_TAG = 'metadata'
- ROOT_ATTRIBUTES = {
- xmlns: 'http://linux.duke.edu/metadata/common',
- 'xmlns:rpm': 'http://linux.duke.edu/metadata/rpm',
- packages: '0'
- }.freeze
-
- # Nodes that have only text without attributes
- REQUIRED_BASE_ATTRIBUTES = %i[name arch summary description].freeze
- NOT_REQUIRED_BASE_ATTRIBUTES = %i[url packager].freeze
- FORMAT_NODE_BASE_ATTRIBUTES = %i[license vendor group buildhost sourcerpm].freeze
-
- private
-
- def build_new_node
- builder = Nokogiri::XML::Builder.new do |xml|
- xml.package(type: :rpm, 'xmlns:rpm': 'http://linux.duke.edu/metadata/rpm') do
- build_required_base_attributes(xml)
- build_not_required_base_attributes(xml)
- xml.version epoch: data[:epoch], ver: data[:version], rel: data[:release]
- xml.checksum data[:checksum], type: 'sha256', pkgid: 'YES'
- xml.size package: data[:packagesize], installed: data[:installedsize], archive: data[:archivesize]
- xml.time file: data[:filetime], build: data[:buildtime]
- xml.location href: data[:location] if data[:location].present?
- build_format_node(xml)
- end
- end
-
- Nokogiri::XML(builder.to_xml).at('package')
- end
-
- def build_required_base_attributes(xml)
- REQUIRED_BASE_ATTRIBUTES.each do |attribute|
- xml.method_missing(attribute, data[attribute])
- end
- end
-
- def build_not_required_base_attributes(xml)
- NOT_REQUIRED_BASE_ATTRIBUTES.each do |attribute|
- xml.method_missing(attribute, data[attribute]) if data[attribute].present?
- end
- end
-
- def build_format_node(xml)
- xml.format do
- build_base_format_attributes(xml)
- build_provides_node(xml)
- build_requires_node(xml)
- end
- end
-
- def build_base_format_attributes(xml)
- FORMAT_NODE_BASE_ATTRIBUTES.each do |attribute|
- xml[:rpm].method_missing(attribute, data[attribute]) if data[attribute].present?
- end
- end
-
- def build_requires_node(xml)
- xml[:rpm].requires do
- data[:requirements].each do |requires|
- xml[:rpm].entry(
- name: requires[:requirename],
- flags: requires[:requireflags],
- ver: requires[:requireversion]
- )
- end
- end
- end
-
- def build_provides_node(xml)
- xml[:rpm].provides do
- data[:provides].each do |provides|
- xml[:rpm].entry(
- name: provides[:providename],
- flags: provides[:provideflags],
- ver: provides[:provideversion])
- end
- end
- end
- end
- end
- end
-end
diff --git a/app/services/packages/rpm/repository_metadata/build_primary_xml_service.rb b/app/services/packages/rpm/repository_metadata/build_primary_xml_service.rb
new file mode 100644
index 00000000000..1044ab3997a
--- /dev/null
+++ b/app/services/packages/rpm/repository_metadata/build_primary_xml_service.rb
@@ -0,0 +1,78 @@
+# frozen_string_literal: true
+module Packages
+ module Rpm
+ module RepositoryMetadata
+ class BuildPrimaryXmlService < BuildXmlBaseService
+ ROOT_TAG = 'metadata'
+ ROOT_ATTRIBUTES = {
+ xmlns: 'http://linux.duke.edu/metadata/common',
+ 'xmlns:rpm': 'http://linux.duke.edu/metadata/rpm',
+ packages: '0'
+ }.freeze
+
+ # Nodes that have only text without attributes
+ BASE_ATTRIBUTES = %i[name arch summary description url packager].freeze
+ FORMAT_NODE_BASE_ATTRIBUTES = %i[license vendor group buildhost sourcerpm].freeze
+
+ def execute
+ super do |xml|
+ xml.package(type: :rpm, 'xmlns:rpm': 'http://linux.duke.edu/metadata/rpm') do
+ build_base_attributes(xml)
+ xml.version epoch: data[:epoch], ver: data[:version], rel: data[:release]
+ xml.checksum data[:pkgid], type: 'sha256', pkgid: 'YES'
+ xml.size package: data[:packagesize], installed: data[:installedsize], archive: data[:archivesize]
+ xml.time file: data[:filetime], build: data[:buildtime]
+ xml.location href: data[:location] if data[:location].present?
+ build_format_node(xml)
+ end
+ end
+ end
+
+ private
+
+ def build_base_attributes(xml)
+ BASE_ATTRIBUTES.each do |attribute|
+ xml.method_missing(attribute, data[attribute]) if data[attribute].present?
+ end
+ end
+
+ def build_format_node(xml)
+ xml.format do
+ build_base_format_attributes(xml)
+ build_provides_node(xml)
+ build_requires_node(xml)
+ end
+ end
+
+ def build_base_format_attributes(xml)
+ FORMAT_NODE_BASE_ATTRIBUTES.each do |attribute|
+ xml[:rpm].method_missing(attribute, data[attribute]) if data[attribute].present?
+ end
+ end
+
+ def build_requires_node(xml)
+ xml[:rpm].requires do
+ data[:requirements].each do |requires|
+ xml[:rpm].entry(
+ name: requires[:requirename],
+ flags: requires[:requireflags],
+ ver: requires[:requireversion]
+ )
+ end
+ end
+ end
+
+ def build_provides_node(xml)
+ xml[:rpm].provides do
+ data[:provides].each do |provides|
+ xml[:rpm].entry(
+ name: provides[:providename],
+ flags: provides[:provideflags],
+ ver: provides[:provideversion])
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/packages/rpm/repository_metadata/build_repomd_xml.rb b/app/services/packages/rpm/repository_metadata/build_repomd_xml.rb
deleted file mode 100644
index 84614196254..00000000000
--- a/app/services/packages/rpm/repository_metadata/build_repomd_xml.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-# frozen_string_literal: true
-module Packages
- module Rpm
- module RepositoryMetadata
- class BuildRepomdXml
- attr_reader :data
-
- ROOT_ATTRIBUTES = {
- xmlns: 'http://linux.duke.edu/metadata/repo',
- 'xmlns:rpm': 'http://linux.duke.edu/metadata/rpm'
- }.freeze
- ALLOWED_DATA_VALUE_KEYS = %i[checksum open-checksum location timestamp size open-size].freeze
-
- # Expected `data` structure
- #
- # data = {
- # filelists: {
- # checksum: { type: "sha256", value: "123" },
- # location: { href: "repodata/123-filelists.xml.gz" },
- # ...
- # },
- # ...
- # }
- def initialize(data)
- @data = data
- end
-
- def execute
- build_repomd
- end
-
- private
-
- def build_repomd
- Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
- xml.repomd(ROOT_ATTRIBUTES) do
- xml.revision Time.now.to_i
- build_data_info(xml)
- end
- end.to_xml
- end
-
- def build_data_info(xml)
- data.each do |filename, info|
- xml.data(type: filename) do
- build_file_info(info, xml)
- end
- end
- end
-
- def build_file_info(info, xml)
- info.slice(*ALLOWED_DATA_VALUE_KEYS).each do |key, attributes|
- value = attributes.delete(:value)
- xml.method_missing(key, value, attributes)
- end
- end
- end
- end
- end
-end
diff --git a/app/services/packages/rpm/repository_metadata/build_repomd_xml_service.rb b/app/services/packages/rpm/repository_metadata/build_repomd_xml_service.rb
new file mode 100644
index 00000000000..cb80faa12c0
--- /dev/null
+++ b/app/services/packages/rpm/repository_metadata/build_repomd_xml_service.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+module Packages
+ module Rpm
+ module RepositoryMetadata
+ class BuildRepomdXmlService
+ ROOT_ATTRIBUTES = {
+ xmlns: 'http://linux.duke.edu/metadata/repo',
+ 'xmlns:rpm': 'http://linux.duke.edu/metadata/rpm'
+ }.freeze
+ ALLOWED_DATA_VALUE_KEYS = %i[checksum open-checksum location timestamp size open-size].freeze
+
+ # Expected `data` structure
+ #
+ # data = {
+ # filelists: {
+ # checksum: { type: "sha256", value: "123" },
+ # location: { href: "repodata/123-filelists.xml.gz" },
+ # ...
+ # },
+ # ...
+ # }
+ def initialize(data)
+ @data = data
+ end
+
+ def execute
+ Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
+ xml.repomd(ROOT_ATTRIBUTES) do
+ xml.revision Time.now.to_i
+ build_data_info(xml)
+ end
+ end.to_xml
+ end
+
+ private
+
+ attr_reader :data
+
+ def build_data_info(xml)
+ data.each do |filename, info|
+ xml.data(type: filename) do
+ build_file_info(info, xml)
+ end
+ end
+ end
+
+ def build_file_info(info, xml)
+ info.slice(*ALLOWED_DATA_VALUE_KEYS).each do |key, attributes|
+ value = attributes.delete(:value)
+ xml.method_missing(key, value, attributes)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/packages/rpm/repository_metadata/build_xml_base_service.rb b/app/services/packages/rpm/repository_metadata/build_xml_base_service.rb
new file mode 100644
index 00000000000..4dfb4087f1b
--- /dev/null
+++ b/app/services/packages/rpm/repository_metadata/build_xml_base_service.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+module Packages
+ module Rpm
+ module RepositoryMetadata
+ class BuildXmlBaseService
+ def initialize(data)
+ @data = data
+ end
+
+ def execute
+ builder = Nokogiri::XML::Builder.new { |xml| yield xml } # rubocop:disable Style/ExplicitBlockArgument
+
+ Nokogiri::XML(builder.to_xml).at('package')
+ end
+
+ private
+
+ attr_reader :data
+ end
+ end
+ end
+end
diff --git a/app/services/packages/rpm/repository_metadata/update_xml_service.rb b/app/services/packages/rpm/repository_metadata/update_xml_service.rb
new file mode 100644
index 00000000000..8fef425195f
--- /dev/null
+++ b/app/services/packages/rpm/repository_metadata/update_xml_service.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+module Packages
+ module Rpm
+ module RepositoryMetadata
+ class UpdateXmlService
+ BUILDERS = {
+ other: ::Packages::Rpm::RepositoryMetadata::BuildOtherXmlService,
+ primary: ::Packages::Rpm::RepositoryMetadata::BuildPrimaryXmlService,
+ filelist: ::Packages::Rpm::RepositoryMetadata::BuildFilelistXmlService
+ }.freeze
+
+ def initialize(filename:, xml: nil, data: {})
+ @builder_class = BUILDERS[filename]
+ raise ArgumentError, "Filename must be one of: #{BUILDERS.keys.join(', ')}" if @builder_class.nil?
+
+ @xml = Nokogiri::XML(xml) if xml.present?
+ @data = data
+ @filename = filename
+ end
+
+ def execute
+ return build_empty_structure if xml.blank?
+
+ remove_existing_packages
+ update_xml_document
+ update_package_count
+ xml.to_xml
+ end
+
+ private
+
+ attr_reader :xml, :data, :builder_class, :filename
+
+ def build_empty_structure
+ Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
+ xml.method_missing(builder_class::ROOT_TAG, builder_class::ROOT_ATTRIBUTES)
+ end.to_xml
+ end
+
+ def update_xml_document
+ # Add to the root xml element a new package metadata node
+ xml.at(builder_class::ROOT_TAG).add_child(builder_class.new(data).execute)
+ end
+
+ def update_package_count
+ packages_count = xml.css("//#{builder_class::ROOT_TAG}/package").count
+
+ xml.at(builder_class::ROOT_TAG).attributes["packages"].value = packages_count.to_s
+ end
+
+ def remove_existing_packages
+ case filename
+ when :primary
+ xml.search("checksum:contains('#{data[:pkgid]}')").each { _1.parent&.remove }
+ else
+ xml.search("[pkgid='#{data[:pkgid]}']").each(&:remove)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/personal_access_tokens/revoke_service.rb b/app/services/personal_access_tokens/revoke_service.rb
index 732da75da3a..5371b6c91ef 100644
--- a/app/services/personal_access_tokens/revoke_service.rb
+++ b/app/services/personal_access_tokens/revoke_service.rb
@@ -4,7 +4,7 @@ module PersonalAccessTokens
class RevokeService < BaseService
attr_reader :token, :current_user, :group
- def initialize(current_user = nil, token: nil, group: nil )
+ def initialize(current_user = nil, token: nil, group: nil)
@current_user = current_user
@token = token
@group = group
diff --git a/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb b/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb
index c82ed97203f..c91103f897f 100644
--- a/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb
+++ b/app/services/projects/lfs_pointers/lfs_download_link_list_service.rb
@@ -95,10 +95,12 @@ module Projects
end
def request_body(oids)
- {
+ body = {
operation: DOWNLOAD_ACTION,
objects: oids.map { |oid, size| { oid: oid, size: size } }
- }.to_json
+ }
+
+ Gitlab::Json.dump(body)
end
def headers
diff --git a/app/services/projects/move_users_star_projects_service.rb b/app/services/projects/move_users_star_projects_service.rb
index 5490448553f..4f1580c5f53 100644
--- a/app/services/projects/move_users_star_projects_service.rb
+++ b/app/services/projects/move_users_star_projects_service.rb
@@ -12,8 +12,8 @@ module Projects
Project.transaction do
user_stars.update_all(project_id: @project.id)
- Project.reset_counters @project.id, :users_star_projects
- Project.reset_counters source_project.id, :users_star_projects
+ @project.update(star_count: @project.starrers.with_state(:active).size)
+ source_project.update(star_count: source_project.starrers.with_state(:active).size)
success
end
diff --git a/app/services/projects/prometheus/alerts/notify_service.rb b/app/services/projects/prometheus/alerts/notify_service.rb
index 9f260345937..1e084c0e5eb 100644
--- a/app/services/projects/prometheus/alerts/notify_service.rb
+++ b/app/services/projects/prometheus/alerts/notify_service.rb
@@ -36,9 +36,9 @@ module Projects
truncate_alerts! if max_alerts_exceeded?
- alert_responses = process_prometheus_alerts
+ process_prometheus_alerts
- alert_response(alert_responses)
+ created
end
def self.processable?(payload)
@@ -152,12 +152,6 @@ module Projects
.execute
end
end
-
- def alert_response(alert_responses)
- alerts = alert_responses.flat_map { |resp| resp.payload[:alerts] }.compact
-
- success(alerts)
- end
end
end
end
diff --git a/app/services/projects/unlink_fork_service.rb b/app/services/projects/unlink_fork_service.rb
index 9eccc16a8b2..898421364db 100644
--- a/app/services/projects/unlink_fork_service.rb
+++ b/app/services/projects/unlink_fork_service.rb
@@ -60,3 +60,5 @@ module Projects
end
end
end
+
+Projects::UnlinkForkService.prepend_mod_with('Projects::UnlinkForkService')
diff --git a/app/services/protected_branches/api_service.rb b/app/services/protected_branches/api_service.rb
index f604a57bcd1..b8fe9bac13e 100644
--- a/app/services/protected_branches/api_service.rb
+++ b/app/services/protected_branches/api_service.rb
@@ -6,17 +6,32 @@ module ProtectedBranches
::ProtectedBranches::CreateService.new(@project, @current_user, protected_branch_params).execute
end
- def protected_branch_params
- {
- name: params[:name],
- allow_force_push: allow_force_push?,
- push_access_levels_attributes: ::ProtectedRefs::AccessLevelParams.new(:push, params).access_levels,
- merge_access_levels_attributes: ::ProtectedRefs::AccessLevelParams.new(:merge, params).access_levels
- }
+ def update(protected_branch)
+ ::ProtectedBranches::UpdateService.new(@project, @current_user,
+protected_branch_params(with_defaults: false)).execute(protected_branch)
end
- def allow_force_push?
- params[:allow_force_push] || false
+ private
+
+ def protected_branch_params(with_defaults: true)
+ params.slice(*attributes).merge(
+ {
+ push_access_levels_attributes: access_level_attributes(:push, with_defaults),
+ merge_access_levels_attributes: access_level_attributes(:merge, with_defaults)
+ }
+ )
+ end
+
+ def access_level_attributes(type, with_defaults)
+ ::ProtectedRefs::AccessLevelParams.new(
+ type,
+ params,
+ with_defaults: with_defaults
+ ).access_levels
+ end
+
+ def attributes
+ [:name, :allow_force_push]
end
end
end
diff --git a/app/services/protected_branches/cache_service.rb b/app/services/protected_branches/cache_service.rb
index 8c521f4ebcb..66ca549c508 100644
--- a/app/services/protected_branches/cache_service.rb
+++ b/app/services/protected_branches/cache_service.rb
@@ -7,20 +7,26 @@ module ProtectedBranches
CACHE_EXPIRE_IN = 1.day
CACHE_LIMIT = 1000
- def fetch(ref_name, dry_run: false)
+ def fetch(ref_name, dry_run: false, &block)
record = OpenSSL::Digest::SHA256.hexdigest(ref_name)
- Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
cached_result = redis.hget(redis_key, record)
- decoded_result = Gitlab::Redis::Boolean.decode(cached_result) unless cached_result.nil?
+ if cached_result.nil?
+ metrics.increment_cache_miss
+ else
+ metrics.increment_cache_hit
+
+ decoded_result = Gitlab::Redis::Boolean.decode(cached_result)
+ end
# If we're dry-running, don't break because we need to check against
# the real value to ensure the cache is working properly.
# If the result is nil we'll need to run the block, so don't break yet.
break decoded_result unless dry_run || decoded_result.nil?
- calculated_value = yield
+ calculated_value = metrics.observe_cache_generation(&block)
check_and_log_discrepancy(decoded_result, calculated_value, ref_name) if dry_run
@@ -42,11 +48,15 @@ module ProtectedBranches
end
def refresh
- Gitlab::Redis::Cache.with { |redis| redis.unlink(redis_key) }
+ with_redis { |redis| redis.unlink(redis_key) }
end
private
+ def with_redis(&block)
+ Gitlab::Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord
+ end
+
def check_and_log_discrepancy(cached_value, real_value, ref_name)
return if cached_value.nil?
return if cached_value == real_value
@@ -64,5 +74,14 @@ module ProtectedBranches
def redis_key
@redis_key ||= [CACHE_ROOT_KEY, @project.id].join(':')
end
+
+ def metrics
+ @metrics ||= Gitlab::Cache::Metrics.new(
+ caller_id: Gitlab::ApplicationContext.current_context_attribute(:caller_id),
+ cache_identifier: "#{self.class}#fetch",
+ feature_category: :source_code_management,
+ backing_resource: :cpu
+ )
+ end
end
end
diff --git a/app/services/protected_refs/access_level_params.rb b/app/services/protected_refs/access_level_params.rb
index 59fc17868d1..a421964a6ab 100644
--- a/app/services/protected_refs/access_level_params.rb
+++ b/app/services/protected_refs/access_level_params.rb
@@ -4,9 +4,9 @@ module ProtectedRefs
class AccessLevelParams
attr_reader :type, :params
- def initialize(type, params)
+ def initialize(type, params, with_defaults: true)
@type = type
- @params = params_with_default(params)
+ @params = with_defaults ? params_with_default(params) : params
end
def access_levels
diff --git a/app/services/resource_events/base_change_timebox_service.rb b/app/services/resource_events/base_change_timebox_service.rb
index 372f1c9d816..ba7c9d90713 100644
--- a/app/services/resource_events/base_change_timebox_service.rb
+++ b/app/services/resource_events/base_change_timebox_service.rb
@@ -12,11 +12,15 @@ module ResourceEvents
def execute
create_event
+ track_event
+
resource.expire_note_etag_cache
end
private
+ def track_event; end
+
def create_event
raise NotImplementedError
end
diff --git a/app/services/resource_events/change_milestone_service.rb b/app/services/resource_events/change_milestone_service.rb
index 24935a3327a..a092d807d8f 100644
--- a/app/services/resource_events/change_milestone_service.rb
+++ b/app/services/resource_events/change_milestone_service.rb
@@ -13,6 +13,12 @@ module ResourceEvents
private
+ def track_event
+ return unless resource.is_a?(WorkItem)
+
+ Gitlab::UsageDataCounters::WorkItemActivityUniqueCounter.track_work_item_milestone_changed_action(author: user)
+ end
+
def create_event
ResourceMilestoneEvent.create(build_resource_args)
end
diff --git a/app/services/service_ping/submit_service.rb b/app/services/service_ping/submit_service.rb
index 7fd0fb10b4b..da2a51562f8 100644
--- a/app/services/service_ping/submit_service.rb
+++ b/app/services/service_ping/submit_service.rb
@@ -63,7 +63,7 @@ module ServicePing
def submit_payload(payload, path: USAGE_DATA_PATH)
Gitlab::HTTP.post(
URI.join(base_url, path),
- body: payload.to_json,
+ body: Gitlab::Json.dump(payload),
allow_local_requests: true,
headers: { 'Content-type' => 'application/json' }
)
diff --git a/app/services/snippets/create_service.rb b/app/services/snippets/create_service.rb
index e0bab4cd6ad..5cadff42958 100644
--- a/app/services/snippets/create_service.rb
+++ b/app/services/snippets/create_service.rb
@@ -34,7 +34,7 @@ module Snippets
move_temporary_files
- ServiceResponse.success(payload: { snippet: @snippet } )
+ ServiceResponse.success(payload: { snippet: @snippet })
else
snippet_error_response(@snippet, 400)
end
diff --git a/app/services/spam/spam_verdict_service.rb b/app/services/spam/spam_verdict_service.rb
index 08634ec840c..0dcb3546034 100644
--- a/app/services/spam/spam_verdict_service.rb
+++ b/app/services/spam/spam_verdict_service.rb
@@ -24,7 +24,7 @@ module Spam
label = spamcheck_error ? 'ERROR' : spamcheck_result.to_s.upcase
- histogram.observe( { result: label }, external_spam_check_round_trip_time )
+ histogram.observe({ result: label }, external_spam_check_round_trip_time)
# assign result to a var for logging it before reassigning to nil when monitorMode is true
original_spamcheck_result = spamcheck_result
diff --git a/app/services/system_notes/issuables_service.rb b/app/services/system_notes/issuables_service.rb
index 7275a05d2ce..ad9f0dd0368 100644
--- a/app/services/system_notes/issuables_service.rb
+++ b/app/services/system_notes/issuables_service.rb
@@ -16,6 +16,8 @@ module SystemNotes
def self.issuable_events
{
+ assigned: s_('IssuableEvents|assigned to'),
+ unassigned: s_('IssuableEvents|unassigned'),
review_requested: s_('IssuableEvents|requested review from'),
review_request_removed: s_('IssuableEvents|removed review request for')
}.freeze
@@ -83,7 +85,7 @@ module SystemNotes
#
# "assigned to @user1 additionally to @user2"
#
- # "assigned to @user1, @user2 and @user3 and unassigned from @user4 and @user5"
+ # "assigned to @user1, @user2 and @user3 and unassigned @user4 and @user5"
#
# "assigned to @user1 and @user2"
#
@@ -94,8 +96,8 @@ module SystemNotes
text_parts = []
Gitlab::I18n.with_default_locale do
- text_parts << "assigned to #{added_users.map(&:to_reference).to_sentence}" if added_users.any?
- text_parts << "unassigned #{unassigned_users.map(&:to_reference).to_sentence}" if unassigned_users.any?
+ text_parts << "#{self.class.issuable_events[:assigned]} #{added_users.map(&:to_reference).to_sentence}" if added_users.any?
+ text_parts << "#{self.class.issuable_events[:unassigned]} #{unassigned_users.map(&:to_reference).to_sentence}" if unassigned_users.any?
end
body = text_parts.join(' and ')
diff --git a/app/services/tags/create_service.rb b/app/services/tags/create_service.rb
index 8a7b98ab944..e332b51ae94 100644
--- a/app/services/tags/create_service.rb
+++ b/app/services/tags/create_service.rb
@@ -3,6 +3,8 @@
module Tags
class CreateService < BaseService
def execute(tag_name, target, message)
+ return error('Target is empty', 400) if target.blank?
+
valid_tag = Gitlab::GitRefValidator.validate(tag_name)
return error('Tag name invalid', 400) unless valid_tag
diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb
index 6ae394072c6..06352d36215 100644
--- a/app/services/todo_service.rb
+++ b/app/services/todo_service.rb
@@ -329,11 +329,12 @@ class TodoService
commit_id: nil
}
- if target.is_a?(Commit)
+ case target
+ when Commit
attributes.merge!(target_id: nil, commit_id: target.id)
- elsif target.is_a?(Issue)
+ when Issue
attributes[:issue_type] = target.issue_type
- elsif target.is_a?(Discussion)
+ when Discussion
attributes.merge!(target_type: nil, target_id: nil, discussion: target)
end
diff --git a/app/services/two_factor/base_service.rb b/app/services/two_factor/base_service.rb
index 0957d7ebabd..50a3a5c099c 100644
--- a/app/services/two_factor/base_service.rb
+++ b/app/services/two_factor/base_service.rb
@@ -4,12 +4,12 @@ module TwoFactor
class BaseService
include BaseServiceUtility
- attr_reader :current_user, :params, :user
+ attr_reader :current_user, :user, :group
def initialize(current_user, params = {})
@current_user = current_user
- @params = params
@user = params.delete(:user)
+ @group = params.delete(:group)
end
end
end
diff --git a/app/services/two_factor/destroy_service.rb b/app/services/two_factor/destroy_service.rb
index 859012c2153..3db9aefbe70 100644
--- a/app/services/two_factor/destroy_service.rb
+++ b/app/services/two_factor/destroy_service.rb
@@ -3,7 +3,7 @@
module TwoFactor
class DestroyService < ::TwoFactor::BaseService
def execute
- return error(_('You are not authorized to perform this action')) unless can?(current_user, :disable_two_factor, user)
+ return error(_('You are not authorized to perform this action')) unless authorized?
return error(_('Two-factor authentication is not enabled for this user')) unless user.two_factor_enabled?
result = disable_two_factor
@@ -15,6 +15,10 @@ module TwoFactor
private
+ def authorized?
+ can?(current_user, :disable_two_factor, user)
+ end
+
def disable_two_factor
::Users::UpdateService.new(current_user, user: user).execute do |user|
user.disable_two_factor!
diff --git a/app/services/user_project_access_changed_service.rb b/app/services/user_project_access_changed_service.rb
index ceaf21bb926..f7178ee9bb6 100644
--- a/app/services/user_project_access_changed_service.rb
+++ b/app/services/user_project_access_changed_service.rb
@@ -21,9 +21,10 @@ class UserProjectAccessChangedService
if blocking
AuthorizedProjectsWorker.bulk_perform_and_wait(bulk_args)
else
- if priority == HIGH_PRIORITY
+ case priority
+ when HIGH_PRIORITY
AuthorizedProjectsWorker.bulk_perform_async(bulk_args) # rubocop:disable Scalability/BulkPerformWithContext
- elsif priority == MEDIUM_PRIORITY
+ when MEDIUM_PRIORITY
AuthorizedProjectUpdate::UserRefreshWithLowUrgencyWorker.bulk_perform_in(MEDIUM_DELAY, bulk_args, batch_size: 100, batch_delay: 30.seconds) # rubocop:disable Scalability/BulkPerformWithContext
else
with_related_class_context do
diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb
index 0fa1bb96b13..8ef1b3e0613 100644
--- a/app/services/users/build_service.rb
+++ b/app/services/users/build_service.rb
@@ -177,7 +177,7 @@ module Users
# Allowed params for user signup
def signup_params
- [
+ signup_params = [
:email,
:name,
:password,
@@ -187,6 +187,9 @@ module Users
:first_name,
:last_name
]
+ signup_params << :preferred_language if ::Feature.enabled?(:preferred_language_switcher)
+
+ signup_params
end
end
end
diff --git a/app/services/users/destroy_service.rb b/app/services/users/destroy_service.rb
index a378cb09854..d4c00a4dcec 100644
--- a/app/services/users/destroy_service.rb
+++ b/app/services/users/destroy_service.rb
@@ -8,9 +8,20 @@ module Users
def initialize(current_user)
@current_user = current_user
+
+ @scheduled_records_gauge = Gitlab::Metrics.gauge(
+ :gitlab_ghost_user_migration_scheduled_records_total,
+ 'The total number of scheduled ghost user migrations'
+ )
+ @lag_gauge = Gitlab::Metrics.gauge(
+ :gitlab_ghost_user_migration_lag_seconds,
+ 'The waiting time in seconds of the oldest scheduled record for ghost user migration'
+ )
end
- # Synchronously destroys +user+
+ # Asynchronously destroys +user+
+ # Migrating the associated user records, and post-migration cleanup is
+ # handled by the Users::MigrateRecordsToGhostUserWorker cron worker.
#
# The operation will fail if the user is the sole owner of any groups. To
# force the groups to be destroyed, pass `delete_solo_owned_groups: true` in
@@ -24,10 +35,7 @@ module Users
# a hard deletion without destroying solo-owned groups, pass
# `delete_solo_owned_groups: false, hard_delete: true` in +options+.
#
- # To make the service asynchronous, a new behaviour is being introduced
- # behind the user_destroy_with_limited_execution_time_worker feature flag.
- # Migrating the associated user records, and post-migration cleanup is
- # handled by the Users::MigrateRecordsToGhostUserWorker cron worker.
+
def execute(user, options = {})
delete_solo_owned_groups = options.fetch(:delete_solo_owned_groups, options[:hard_delete])
@@ -62,32 +70,43 @@ module Users
yield(user) if block_given?
hard_delete = options.fetch(:hard_delete, false)
+ Users::GhostUserMigration.create!(user: user,
+ initiator_user: current_user,
+ hard_delete: hard_delete)
- if Feature.enabled?(:user_destroy_with_limited_execution_time_worker)
- Users::GhostUserMigration.create!(user: user,
- initiator_user: current_user,
- hard_delete: hard_delete)
+ update_metrics
+ end
- else
- MigrateToGhostUserService.new(user).execute(hard_delete: options[:hard_delete])
+ private
+
+ attr_reader :scheduled_records_gauge, :lag_gauge
- response = Snippets::BulkDestroyService.new(current_user, user.snippets)
- .execute(skip_authorization: hard_delete)
- raise DestroyError, response.message if response.error?
+ def update_metrics
+ update_scheduled_records_gauge
+ update_lag_gauge
+ end
- # Rails attempts to load all related records into memory before
- # destroying: https://github.com/rails/rails/issues/22510
- # This ensures we delete records in batches.
- user.destroy_dependent_associations_in_batches(exclude: [:snippets])
- user.nullify_dependent_associations_in_batches
+ def update_scheduled_records_gauge
+ # We do not want to issue unbounded COUNT() queries, hence we limit the
+ # query to count 1001 records and then approximate the result.
+ count = Users::GhostUserMigration.limit(1001).count
- # Destroy the namespace after destroying the user since certain methods may depend on the namespace existing
- user_data = user.destroy
- namespace.destroy
+ if count == 1001
+ # more than 1000 records, approximate count
+ min = Users::GhostUserMigration.minimum(:id) || 0
+ max = Users::GhostUserMigration.maximum(:id) || 0
- user_data
+ scheduled_records_gauge.set({}, max - min)
+ else
+ # less than 1000 records, count is accurate
+ scheduled_records_gauge.set({}, count)
end
end
+
+ def update_lag_gauge
+ oldest_job = Users::GhostUserMigration.first
+ lag_gauge.set({}, Time.current - oldest_job.created_at)
+ end
end
end
diff --git a/app/services/users/migrate_records_to_ghost_user_in_batches_service.rb b/app/services/users/migrate_records_to_ghost_user_in_batches_service.rb
index 7c4a5698ea9..d294312cc30 100644
--- a/app/services/users/migrate_records_to_ghost_user_in_batches_service.rb
+++ b/app/services/users/migrate_records_to_ghost_user_in_batches_service.rb
@@ -2,25 +2,38 @@
module Users
class MigrateRecordsToGhostUserInBatchesService
+ LIMIT_SIZE = 1000
+
def initialize
@execution_tracker = Gitlab::Utils::ExecutionTracker.new
end
def execute
- Users::GhostUserMigration.find_each do |user_to_migrate|
+ ghost_user_migrations.each do |job|
break if execution_tracker.over_limit?
- service = Users::MigrateRecordsToGhostUserService.new(user_to_migrate.user,
- user_to_migrate.initiator_user,
+ service = Users::MigrateRecordsToGhostUserService.new(job.user,
+ job.initiator_user,
execution_tracker)
- service.execute(hard_delete: user_to_migrate.hard_delete)
+ service.execute(hard_delete: job.hard_delete)
+ rescue Gitlab::Utils::ExecutionTracker::ExecutionTimeOutError
+ # no-op
+ rescue StandardError => e
+ ::Gitlab::ErrorTracking.track_exception(e)
+ reschedule(job)
end
- rescue Gitlab::Utils::ExecutionTracker::ExecutionTimeOutError
- # no-op
end
private
attr_reader :execution_tracker
+
+ def ghost_user_migrations
+ Users::GhostUserMigration.consume_order.limit(LIMIT_SIZE)
+ end
+
+ def reschedule(job)
+ job.update(consume_after: 30.minutes.from_now)
+ end
end
end
diff --git a/app/services/users/migrate_to_ghost_user_service.rb b/app/services/users/migrate_to_ghost_user_service.rb
deleted file mode 100644
index 3eb220c0e40..00000000000
--- a/app/services/users/migrate_to_ghost_user_service.rb
+++ /dev/null
@@ -1,113 +0,0 @@
-# frozen_string_literal: true
-
-# When a user is destroyed, some of their associated records are
-# moved to a "Ghost User", to prevent these associated records from
-# being destroyed.
-#
-# For example, all the issues/MRs a user has created are _not_ destroyed
-# when the user is destroyed.
-module Users
- class MigrateToGhostUserService
- extend ActiveSupport::Concern
-
- attr_reader :ghost_user, :user, :hard_delete
-
- def initialize(user)
- @user = user
- @ghost_user = User.ghost
- end
-
- # If an admin attempts to hard delete a user, in some cases associated
- # records may have a NOT NULL constraint on the user ID that prevent that record
- # from being destroyed. In such situations we must assign the record to the ghost user.
- # Passing in `hard_delete: true` will ensure these records get assigned to
- # the ghost user before the user is destroyed. Other associated records will be destroyed.
- # letting the other associated records be destroyed.
- def execute(hard_delete: false)
- @hard_delete = hard_delete
- transition = user.block_transition
-
- # Block the user before moving records to prevent a data race.
- # For example, if the user creates an issue after `migrate_issues`
- # runs and before the user is destroyed, the destroy will fail with
- # an exception.
- user.block
-
- begin
- user.transaction do
- migrate_records
- end
- rescue Exception # rubocop:disable Lint/RescueException
- # Reverse the user block if record migration fails
- if transition
- transition.rollback
- user.save!
- end
-
- raise
- end
-
- user.reset
- end
-
- private
-
- def migrate_records
- return if hard_delete
-
- migrate_issues
- migrate_merge_requests
- migrate_notes
- migrate_abuse_reports
- migrate_award_emoji
- migrate_snippets
- migrate_reviews
- end
-
- # rubocop: disable CodeReuse/ActiveRecord
- def migrate_issues
- batched_migrate(Issue, :author_id)
- batched_migrate(Issue, :last_edited_by_id)
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- # rubocop: disable CodeReuse/ActiveRecord
- def migrate_merge_requests
- batched_migrate(MergeRequest, :author_id)
- batched_migrate(MergeRequest, :merge_user_id)
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def migrate_notes
- batched_migrate(Note, :author_id)
- end
-
- def migrate_abuse_reports
- user.reported_abuse_reports.update_all(reporter_id: ghost_user.id)
- end
-
- def migrate_award_emoji
- user.award_emoji.update_all(user_id: ghost_user.id)
- end
-
- def migrate_snippets
- snippets = user.snippets.only_project_snippets
- snippets.update_all(author_id: ghost_user.id)
- end
-
- def migrate_reviews
- batched_migrate(Review, :author_id)
- end
-
- # rubocop:disable CodeReuse/ActiveRecord
- def batched_migrate(base_scope, column, batch_size: 50)
- loop do
- update_count = base_scope.where(column => user.id).limit(batch_size).update_all(column => ghost_user.id)
- break if update_count == 0
- end
- end
- # rubocop:enable CodeReuse/ActiveRecord
- end
-end
-
-Users::MigrateToGhostUserService.prepend_mod_with('Users::MigrateToGhostUserService')
diff --git a/app/services/web_hook_service.rb b/app/services/web_hook_service.rb
index e5e5e375198..d32dcd73734 100644
--- a/app/services/web_hook_service.rb
+++ b/app/services/web_hook_service.rb
@@ -57,11 +57,11 @@ class WebHookService
end
def execute
- return { status: :error, message: 'Hook disabled' } if disabled?
+ return ServiceResponse.error(message: 'Hook disabled') if disabled?
if recursion_blocked?
log_recursion_blocked
- return { status: :error, message: 'Recursive webhook blocked' }
+ return ServiceResponse.error(message: 'Recursive webhook blocked')
end
Gitlab::WebHooks::RecursionDetection.register!(hook)
@@ -79,11 +79,7 @@ class WebHookService
execution_duration: Gitlab::Metrics::System.monotonic_time - start_time
)
- {
- status: :success,
- http_status: response.code,
- message: response.body
- }
+ ServiceResponse.success(message: response.body, payload: { http_status: response.code })
rescue *Gitlab::HTTP::HTTP_ERRORS,
Gitlab::Json::LimitedEncoder::LimitExceeded, URI::InvalidURIError => e
execution_duration = Gitlab::Metrics::System.monotonic_time - start_time
@@ -97,10 +93,7 @@ class WebHookService
Gitlab::AppLogger.error("WebHook Error after #{execution_duration.to_i.seconds}s => #{e}")
- {
- status: :error,
- message: error_message
- }
+ ServiceResponse.error(message: error_message)
end
def async_execute
diff --git a/app/services/work_items/create_service.rb b/app/services/work_items/create_service.rb
index ebda043e873..87cc690d666 100644
--- a/app/services/work_items/create_service.rb
+++ b/app/services/work_items/create_service.rb
@@ -30,6 +30,13 @@ module WorkItems
error(e.message, :unprocessable_entity)
end
+ def before_create(work_item)
+ execute_widgets(work_item: work_item, callback: :before_create_callback,
+ widget_params: @widget_params)
+
+ super
+ end
+
def transaction_create(work_item)
super.tap do |save_result|
if save_result
diff --git a/app/services/work_items/widgets/hierarchy_service/base_service.rb b/app/services/work_items/widgets/hierarchy_service/base_service.rb
index bb681ef0083..236762d6937 100644
--- a/app/services/work_items/widgets/hierarchy_service/base_service.rb
+++ b/app/services/work_items/widgets/hierarchy_service/base_service.rb
@@ -7,7 +7,6 @@ module WorkItems
private
def handle_hierarchy_changes(params)
- return feature_flag_error unless feature_flag_enabled?
return incompatible_args_error if incompatible_args?(params)
if params.key?(:parent)
@@ -48,24 +47,16 @@ module WorkItems
.execute
end
- def feature_flag_enabled?
- Feature.enabled?(:work_items_hierarchy, work_item&.project)
- end
-
def incompatible_args?(params)
params[:children] && params[:parent]
end
- def feature_flag_error
- error(_('`work_items_hierarchy` feature flag disabled for this project'))
- end
-
def incompatible_args_error
error(_('A Work Item can be a parent or a child, but not both.'))
end
def invalid_args_error(params)
- error(_("One or more arguments are invalid: %{args}." % { args: params.keys.to_sentence } ))
+ error(_("One or more arguments are invalid: %{args}." % { args: params.keys.to_sentence }))
end
def service_response!(result)
diff --git a/app/services/work_items/widgets/milestone_service/base_service.rb b/app/services/work_items/widgets/milestone_service/base_service.rb
new file mode 100644
index 00000000000..f373e6daea3
--- /dev/null
+++ b/app/services/work_items/widgets/milestone_service/base_service.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module WorkItems
+ module Widgets
+ module MilestoneService
+ class BaseService < WorkItems::Widgets::BaseService
+ private
+
+ def handle_milestone_change(params:)
+ return unless params.present? && params.key?(:milestone_id)
+
+ unless has_permission?(:set_work_item_metadata)
+ params.delete(:milestone_id)
+ return
+ end
+
+ if params[:milestone_id].nil?
+ work_item.milestone = nil
+
+ return
+ end
+
+ project = work_item.project
+ milestone = MilestonesFinder.new({
+ project_ids: [project.id],
+ group_ids: project.group&.self_and_ancestors&.select(:id),
+ ids: [params[:milestone_id]]
+ }).execute.first
+
+ if milestone
+ work_item.milestone = milestone
+ else
+ params.delete(:milestone_id)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/work_items/widgets/milestone_service/create_service.rb b/app/services/work_items/widgets/milestone_service/create_service.rb
new file mode 100644
index 00000000000..e8d6bfe503c
--- /dev/null
+++ b/app/services/work_items/widgets/milestone_service/create_service.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module WorkItems
+ module Widgets
+ module MilestoneService
+ class CreateService < WorkItems::Widgets::MilestoneService::BaseService
+ def before_create_callback(params:)
+ handle_milestone_change(params: params)
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/work_items/widgets/milestone_service/update_service.rb b/app/services/work_items/widgets/milestone_service/update_service.rb
new file mode 100644
index 00000000000..7ff0c2a5367
--- /dev/null
+++ b/app/services/work_items/widgets/milestone_service/update_service.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module WorkItems
+ module Widgets
+ module MilestoneService
+ class UpdateService < WorkItems::Widgets::MilestoneService::BaseService
+ def before_update_callback(params:)
+ handle_milestone_change(params: params)
+ end
+ end
+ end
+ end
+end
diff --git a/app/uploaders/object_storage/cdn.rb b/app/uploaders/object_storage/cdn.rb
index e49e2780147..8c9ee8682f4 100644
--- a/app/uploaders/object_storage/cdn.rb
+++ b/app/uploaders/object_storage/cdn.rb
@@ -12,9 +12,9 @@ module ObjectStorage
UrlResult = Struct.new(:url, :used_cdn)
- def cdn_enabled_url(project, ip_address)
- if Feature.enabled?(:ci_job_artifacts_cdn, project) && use_cdn?(ip_address)
- UrlResult.new(cdn_signed_url, true)
+ def cdn_enabled_url(ip_address, params = {})
+ if use_cdn?(ip_address)
+ UrlResult.new(cdn_signed_url(params), true)
else
UrlResult.new(url, false)
end
@@ -27,8 +27,8 @@ module ObjectStorage
cdn_provider.use_cdn?(request_ip)
end
- def cdn_signed_url
- cdn_provider&.signed_url(path)
+ def cdn_signed_url(params = {})
+ cdn_provider&.signed_url(path, params: params)
end
private
diff --git a/app/uploaders/object_storage/cdn/google_cdn.rb b/app/uploaders/object_storage/cdn/google_cdn.rb
index 91bad1f8d6b..f1fe62e9db3 100644
--- a/app/uploaders/object_storage/cdn/google_cdn.rb
+++ b/app/uploaders/object_storage/cdn/google_cdn.rb
@@ -24,18 +24,24 @@ module ObjectStorage
!GoogleIpCache.google_ip?(request_ip)
end
- def signed_url(path, expiry: 10.minutes)
+ def signed_url(path, expiry: 10.minutes, params: {})
expiration = (Time.current + expiry).utc.to_i
uri = Addressable::URI.parse(cdn_url)
uri.path = path
- uri.query = "Expires=#{expiration}&KeyName=#{key_name}"
-
- signature = OpenSSL::HMAC.digest('SHA1', decoded_key, uri.to_s)
+ # Use an Array to preserve order: Google CDN needs to have
+ # Expires, KeyName, and Signature in that order or it will return a 403 error:
+ # https://cloud.google.com/cdn/docs/troubleshooting-steps#signing
+ query_params = params.to_a
+ query_params << ['Expires', expiration]
+ query_params << ['KeyName', key_name]
+ uri.query_values = query_params
+
+ unsigned_url = uri.to_s
+ signature = OpenSSL::HMAC.digest('SHA1', decoded_key, unsigned_url)
encoded_signature = Base64.urlsafe_encode64(signature)
- uri.query += "&Signature=#{encoded_signature}"
- uri.to_s
+ "#{unsigned_url}&Signature=#{encoded_signature}"
end
private
diff --git a/app/validators/branch_filter_validator.rb b/app/validators/branch_filter_validator.rb
deleted file mode 100644
index 89d6343a9a4..00000000000
--- a/app/validators/branch_filter_validator.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-# frozen_string_literal: true
-
-# BranchFilterValidator
-#
-# Custom validator for branch names. Squishes whitespace and ignores empty
-# string. This only checks that a string is a valid git branch name. It does
-# not check whether a branch already exists.
-#
-# Example:
-#
-# class Webhook < ActiveRecord::Base
-# validates :push_events_branch_filter, branch_name: true
-# end
-#
-class BranchFilterValidator < ActiveModel::EachValidator
- def validate_each(record, attribute, value)
- value.squish! unless value.nil?
-
- if value.present?
- value_without_wildcards = value.tr('*', 'x')
-
- unless Gitlab::GitRefValidator.validate(value_without_wildcards)
- record.errors.add(attribute, "is not a valid branch name")
- end
-
- unless value.length <= 4000
- record.errors.add(attribute, "is longer than the allowed length of 4000 characters.")
- end
- end
- end
-
- private
-
- def contains_wildcard?(value)
- value.include?('*')
- end
-end
diff --git a/app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json b/app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json
index 19258ee7677..fb6b80e0725 100644
--- a/app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json
+++ b/app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json
@@ -1,176 +1,135 @@
{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "global": [
- {
- "field": "SECURE_ANALYZERS_PREFIX",
- "label": "Image prefix",
- "type": "string",
- "default_value": "",
- "value": "",
- "size": "LARGE",
- "description": "Analyzer image's registry prefix (or name of the registry providing the analyzers' image)"
- },
- {
- "field" : "SAST_EXCLUDED_PATHS",
- "label" : "Excluded Paths",
- "type": "string",
- "default_value": "",
- "value": "",
- "size": "MEDIUM",
- "description": "Comma-separated list of paths to be excluded from analyzer output. Patterns can be globs, file paths, or folder paths."
- }
- ],
- "pipeline": [
- {
- "field" : "stage",
- "label" : "Stage",
- "type": "string",
- "default_value": "",
- "value": "",
- "size": "MEDIUM",
- "description": "Pipeline stage in which the scan jobs run"
- },
- {
- "field" : "SEARCH_MAX_DEPTH",
- "label" : "Search maximum depth",
- "type": "string",
- "default_value": "",
- "value": "",
- "size": "SMALL",
- "description": "Maximum depth of language and framework detection"
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "global": [
+ {
+ "field": "SECURE_ANALYZERS_PREFIX",
+ "label": "Image prefix",
+ "type": "string",
+ "default_value": "",
+ "value": "",
+ "size": "LARGE",
+ "description": "Analyzer image's registry prefix (or name of the registry providing the analyzers' image)"
+ },
+ {
+ "field": "SAST_EXCLUDED_PATHS",
+ "label": "Excluded Paths",
+ "type": "string",
+ "default_value": "",
+ "value": "",
+ "size": "MEDIUM",
+ "description": "Comma-separated list of paths to be excluded from analyzer output. Patterns can be globs, file paths, or folder paths."
+ }
+ ],
+ "pipeline": [
+ {
+ "field": "stage",
+ "label": "Stage",
+ "type": "string",
+ "default_value": "",
+ "value": "",
+ "size": "MEDIUM",
+ "description": "Pipeline stage in which the scan jobs run"
+ },
+ {
+ "field": "SEARCH_MAX_DEPTH",
+ "label": "Search maximum depth",
+ "type": "string",
+ "default_value": "",
+ "value": "",
+ "size": "SMALL",
+ "description": "Maximum depth of language and framework detection"
+ }
+ ],
+ "analyzers": [
+ {
+ "name": "brakeman",
+ "label": "Brakeman",
+ "enabled": true,
+ "description": "Ruby on Rails",
+ "variables": [
+ {
+ "field": "SAST_BRAKEMAN_LEVEL",
+ "label": "Brakeman confidence level",
+ "type": "string",
+ "default_value": "1",
+ "value": "",
+ "size": "SMALL",
+ "description": "Ignore Brakeman vulnerabilities under given confidence level. Integer, 1=Low, 2=Medium, 3=High."
}
- ],
- "analyzers": [
- {
- "name": "bandit",
- "label": "Bandit",
- "enabled" : true,
- "description": "Python",
- "variables": [
- {
- "field" : "SAST_BANDIT_EXCLUDED_PATHS",
- "label" : "Paths to exclude from scan",
- "type": "string",
- "default_value": "",
- "value": "",
- "size": "SMALL",
- "description": "Comma-separated list of paths to exclude from scan. Uses Python’s 'fnmatch' syntax; For example: '*/tests/*, */venv/*'"
- }
- ]
- },
- {
- "name": "brakeman",
- "label": "Brakeman",
- "enabled" : true,
- "description": "Ruby on Rails",
- "variables": [
- {
- "field" : "SAST_BRAKEMAN_LEVEL",
- "label" : "Brakeman confidence level",
- "type": "string",
- "default_value": "1",
- "value": "",
- "size": "SMALL",
- "description": "Ignore Brakeman vulnerabilities under given confidence level. Integer, 1=Low, 2=Medium, 3=High."
- }
- ]
- },
- {
- "name": "eslint",
- "label": "ESLint",
- "enabled" : true,
- "description": "JavaScript, TypeScript, React",
- "variables": []
- },
- {
- "name": "flawfinder",
- "label": "Flawfinder",
- "enabled" : true,
- "description": "C, C++",
- "variables": [
- {
- "field" : "SAST_FLAWFINDER_LEVEL",
- "label" : "Flawfinder risk level",
- "type": "string",
- "default_value": "1",
- "value": "",
- "size": "SMALL",
- "description": "Ignore Flawfinder vulnerabilities under given risk level. Integer, 0=No risk, 5=High risk."
- }
- ]
- },
- {
- "name": "gosec",
- "label": "Gosec",
- "enabled" : true,
- "description": "Go",
- "variables": [
- {
- "field" : "SAST_GOSEC_LEVEL",
- "label" : "Gosec confidence level",
- "type": "string",
- "default_value": "0",
- "value": "",
- "size": "SMALL",
- "description": "Ignore Gosec vulnerabilities under given confidence level. Integer, 0=Undefined, 1=Low, 2=Medium, 3=High."
- }
- ]
- },
- {
- "name": "kubesec",
- "label": "Kubesec",
- "enabled" : true,
- "description": "Kubernetes manifests, Helm Charts",
- "variables": []
- },
- {
- "name": "nodejs-scan",
- "label": "Node.js Scan",
- "enabled" : true,
- "description": "Node.js",
- "variables": []
- },
- {
- "name": "phpcs-security-audit",
- "label": "PHP Security Audit",
- "enabled" : true,
- "description": "PHP",
- "variables": []
- },
- {
- "name": "pmd-apex",
- "label": "PMD APEX",
- "enabled" : true,
- "description": "Apex (Salesforce)",
- "variables": []
- },
- {
- "name": "security-code-scan",
- "label": "Security Code Scan",
- "enabled" : true,
- "description": ".NET Core, .NET Framework",
- "variables": []
- },
- {
- "name": "semgrep",
- "label": "Semgrep",
- "enabled": true,
- "description": "Multi-language scanning",
- "variables": []
- },
- {
- "name": "sobelow",
- "label": "Sobelow",
- "enabled" : true,
- "description": "Elixir (Phoenix)",
- "variables": []
- },
- {
- "name": "spotbugs",
- "label": "Spotbugs",
- "enabled" : true,
- "description": "Groovy, Java, Scala",
- "variables": []
+ ]
+ },
+ {
+ "name": "flawfinder",
+ "label": "Flawfinder",
+ "enabled": true,
+ "description": "C, C++",
+ "variables": [
+ {
+ "field": "SAST_FLAWFINDER_LEVEL",
+ "label": "Flawfinder risk level",
+ "type": "string",
+ "default_value": "1",
+ "value": "",
+ "size": "SMALL",
+ "description": "Ignore Flawfinder vulnerabilities under given risk level. Integer, 0=No risk, 5=High risk."
}
- ]
-}
+ ]
+ },
+ {
+ "name": "kubesec",
+ "label": "Kubesec",
+ "enabled": true,
+ "description": "Kubernetes manifests, Helm Charts",
+ "variables": []
+ },
+ {
+ "name": "nodejs-scan",
+ "label": "Node.js Scan",
+ "enabled": true,
+ "description": "Node.js",
+ "variables": []
+ },
+ {
+ "name": "phpcs-security-audit",
+ "label": "PHP Security Audit",
+ "enabled": true,
+ "description": "PHP",
+ "variables": []
+ },
+ {
+ "name": "pmd-apex",
+ "label": "PMD APEX",
+ "enabled": true,
+ "description": "Apex (Salesforce)",
+ "variables": []
+ },
+ {
+ "name": "security-code-scan",
+ "label": "Security Code Scan",
+ "enabled": true,
+ "description": ".NET Core, .NET Framework",
+ "variables": []
+ },
+ {
+ "name": "semgrep",
+ "label": "Semgrep",
+ "enabled": true,
+ "description": "Multi-language scanning",
+ "variables": []
+ },
+ {
+ "name": "sobelow",
+ "label": "Sobelow",
+ "enabled": true,
+ "description": "Elixir (Phoenix)",
+ "variables": []
+ },
+ {
+ "name": "spotbugs",
+ "label": "Spotbugs",
+ "enabled": true,
+ "description": "Groovy, Java, Scala",
+ "variables": []
+ }
+ ]
+} \ No newline at end of file
diff --git a/app/validators/json_schemas/web_hooks_url_variables.json b/app/validators/json_schemas/web_hooks_url_variables.json
index d23a19bf47a..ea504d114e3 100644
--- a/app/validators/json_schemas/web_hooks_url_variables.json
+++ b/app/validators/json_schemas/web_hooks_url_variables.json
@@ -5,7 +5,7 @@
"additionalProperties": false,
"maxProperties": 20,
"patternProperties": {
- "^[A-Za-z_][A-Za-z0-9_]*$": {
+ "^[A-Za-z]+[0-9]*(?:[._-][A-Za-z0-9]+)*$": {
"type": "string",
"minLength": 1,
"maxLength": 100
diff --git a/app/validators/nested_attributes_duplicates_validator.rb b/app/validators/nested_attributes_duplicates_validator.rb
index b60350a6311..de219c300ba 100644
--- a/app/validators/nested_attributes_duplicates_validator.rb
+++ b/app/validators/nested_attributes_duplicates_validator.rb
@@ -25,11 +25,11 @@ class NestedAttributesDuplicatesValidator < ActiveModel::EachValidator
def validate_duplicates(record, attribute, values)
child_attributes.each do |child_attribute|
duplicates = values.reject(&:marked_for_destruction?).group_by(&:"#{child_attribute}").select { |_, v| v.many? }.map(&:first)
- if duplicates.any?
- error_message = +"have duplicate values (#{duplicates.join(", ")})"
- error_message << " for #{values.first.send(options[:scope])} scope" if options[:scope] # rubocop:disable GitlabSecurity/PublicSend
- record.errors.add(attribute, error_message)
- end
+ next unless duplicates.any?
+
+ error_message = +"have duplicate values (#{duplicates.join(", ")})"
+ error_message << " for #{values.first.send(options[:scope])} scope" if options[:scope] # rubocop:disable GitlabSecurity/PublicSend
+ record.errors.add(attribute, error_message)
end
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/app/validators/web_hooks/wildcard_branch_filter_validator.rb b/app/validators/web_hooks/wildcard_branch_filter_validator.rb
new file mode 100644
index 00000000000..12ec78f05de
--- /dev/null
+++ b/app/validators/web_hooks/wildcard_branch_filter_validator.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+# WildcardBranchFilterValidator
+#
+# Custom validator for wildcard branch filter. Squishes whitespace and ignores
+# empty string. This only checks that a string is a valid wildcard git branch
+# like "feature/login" and "feature/*". It doesn't check whether a branch already
+# exists.
+#
+# Example:
+#
+# class Webhook < ActiveRecord::Base
+# validates :push_events_branch_filter, "web_hooks/wildcard_branch_filter": true
+# end
+#
+module WebHooks
+ class WildcardBranchFilterValidator < ActiveModel::EachValidator
+ def validate_each(record, attribute, value)
+ value.squish! unless value.nil?
+
+ return unless value.present?
+
+ value_without_wildcards = value.tr('*', 'x')
+
+ unless Gitlab::GitRefValidator.validate(value_without_wildcards)
+ record.errors.add(attribute, "is not a valid branch name")
+ end
+
+ return if value.length <= 4000
+
+ record.errors.add(attribute, "is longer than the allowed length of 4000 characters.")
+ end
+ end
+end
diff --git a/app/views/admin/application_settings/_account_and_limit.html.haml b/app/views/admin/application_settings/_account_and_limit.html.haml
index c091a2180c5..0f7b10f822d 100644
--- a/app/views/admin/application_settings/_account_and_limit.html.haml
+++ b/app/views/admin/application_settings/_account_and_limit.html.haml
@@ -69,4 +69,6 @@
= render 'admin/application_settings/invitation_flow_enforcement', form: f
= render 'admin/application_settings/user_restrictions', form: f
= render_if_exists 'admin/application_settings/availability_on_namespace_setting', form: f
+ -# This is added for Jihu edition which should not be deleted without notifying Jihu
+ = render_if_exists 'admin/application_settings/password_expiration_setting', form: f
= f.submit _('Save changes'), pajamas_button: true, data: { qa_selector: 'save_changes_button' }
diff --git a/app/views/admin/application_settings/_jira_connect.html.haml b/app/views/admin/application_settings/_jira_connect.html.haml
new file mode 100644
index 00000000000..ad0660797ee
--- /dev/null
+++ b/app/views/admin/application_settings/_jira_connect.html.haml
@@ -0,0 +1,27 @@
+- expanded = integration_expanded?('jira_connect')
+
+%section.settings.no-animate#js-jira_connect-settings{ class: ('expanded' if expanded) }
+ .settings-header
+ %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
+ = s_('JiraConnect|GitLab for Jira App')
+ = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
+ = expanded ? _('Collapse') : _('Expand')
+ %p
+ = s_('JiraConnect|Configure your Jira Connect Application ID.')
+ = link_to sprite_icon('question-o'), 'https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud', target: '_blank', rel: "noopener noreferrer", class: 'has-tooltip', title: _('More information'), aria: { label: _('GitLab for Jira Cloud') }
+
+ .settings-content
+ = gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-jira-connect-application-id-settings'), html: { class: 'fieldset-form', id: 'jira-connect-application-id-settings' } do |f|
+ = form_errors(@application_setting)
+
+ %fieldset
+ .form-group
+ = f.label :jira_connect_application_key, s_('JiraConnect|Jira Connect Application ID'), class: 'label-bold'
+ = f.text_field :jira_connect_application_key, class: 'form-control gl-form-input'
+
+ %fieldset
+ .form-group
+ = f.label :jira_connect_proxy_url, s_('JiraConnect|Jira Connect Proxy URL'), class: 'label-bold'
+ = f.text_field :jira_connect_proxy_url, class: 'form-control gl-form-input'
+
+ = f.submit _('Save changes'), pajamas_button: true
diff --git a/app/views/admin/application_settings/_jira_connect_application_key.html.haml b/app/views/admin/application_settings/_jira_connect_application_key.html.haml
deleted file mode 100644
index b67e7680720..00000000000
--- a/app/views/admin/application_settings/_jira_connect_application_key.html.haml
+++ /dev/null
@@ -1,21 +0,0 @@
-- expanded = integration_expanded?('jira_connect')
-
-%section.settings.no-animate#js-jira_connect-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
- = s_('JiraConnect|GitLab for Jira App')
- = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
- = expanded ? _('Collapse') : _('Expand')
- %p
- = s_('JiraConnect|Configure your Jira Connect Application ID.')
- = link_to sprite_icon('question-o'), 'https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud', target: '_blank', rel: "noopener noreferrer", class: 'has-tooltip', title: _('More information'), aria: { label: _('GitLab for Jira Cloud') }
-
- .settings-content
- = gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-jira-connect-application-id-settings'), html: { class: 'fieldset-form', id: 'jira-connect-application-id-settings' } do |f|
- = form_errors(@application_setting)
-
- %fieldset
- .form-group
- = f.label :jira_connect_application_key, s_('JiraConnect|Jira Connect Application ID'), class: 'label-bold'
- = f.text_field :jira_connect_application_key, class: 'form-control gl-form-input'
- = f.submit _('Save changes'), pajamas_button: true
diff --git a/app/views/admin/application_settings/_package_registry.html.haml b/app/views/admin/application_settings/_package_registry.html.haml
index 3506038ca68..66b04006beb 100644
--- a/app/views/admin/application_settings/_package_registry.html.haml
+++ b/app/views/admin/application_settings/_package_registry.html.haml
@@ -6,7 +6,7 @@
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded_by_default? ? _('Collapse') : _('Expand')
%p
- = _("Control how the GitLab Package Registry functions.")
+ = s_('PackageRegistry|Configure package forwarding and package file size limits.')
= render_if_exists 'admin/application_settings/ee_package_registry'
diff --git a/app/views/admin/application_settings/_repository_check.html.haml b/app/views/admin/application_settings/_repository_check.html.haml
index ef8d3ccc8ab..aaf76c5ff7a 100644
--- a/app/views/admin/application_settings/_repository_check.html.haml
+++ b/app/views/admin/application_settings/_repository_check.html.haml
@@ -18,8 +18,8 @@
.sub-section
%h4= _("Housekeeping")
.form-group
- - help_text = _("Leaving this setting enabled is recommended.")
- - help_link = link_to s_('Learn more.'), help_page_path('administration/housekeeping.md', anchor: 'housekeeping-options'), target: '_blank', rel: 'noopener noreferrer'
+ - help_text = _("Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time.")
+ - help_link = link_to s_('Learn more.'), help_page_path('administration/housekeeping.md', anchor: 'configure-push-based-maintenance'), target: '_blank', rel: 'noopener noreferrer'
= f.gitlab_ui_checkbox_component :housekeeping_enabled,
_("Enable automatic repository housekeeping"),
help_text: '%{help_text} %{help_link}'.html_safe % { help_text: help_text, help_link: help_link }
diff --git a/app/views/admin/application_settings/_user_restrictions.html.haml b/app/views/admin/application_settings/_user_restrictions.html.haml
index de8faa6705f..82f5e6def9f 100644
--- a/app/views/admin/application_settings/_user_restrictions.html.haml
+++ b/app/views/admin/application_settings/_user_restrictions.html.haml
@@ -3,4 +3,4 @@
.form-group
= label_tag _('User restrictions')
= render_if_exists 'admin/application_settings/updating_name_disabled_for_users', form: form
- = form.gitlab_ui_checkbox_component :can_create_group, _("Allow users to create top-level groups")
+ = form.gitlab_ui_checkbox_component :can_create_group, _("Allow new users to create top-level groups")
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 b69b2f74d0d..85bee72e863 100644
--- a/app/views/admin/application_settings/_visibility_and_access.html.haml
+++ b/app/views/admin/application_settings/_visibility_and_access.html.haml
@@ -64,4 +64,7 @@
= render_if_exists 'admin/application_settings/globally_allowed_ips', form: f
+ -# This is added for Jihu edition in https://jihulab.com/gitlab-cn/gitlab/-/merge_requests/1112
+ = render_if_exists 'admin/application_settings/disable_download_button', f: f
+
= f.submit _('Save changes'), class: "gl-button btn btn-confirm"
diff --git a/app/views/admin/application_settings/appearances/_form.html.haml b/app/views/admin/application_settings/appearances/_form.html.haml
index a3bd8b52148..5f51e91436c 100644
--- a/app/views/admin/application_settings/appearances/_form.html.haml
+++ b/app/views/admin/application_settings/appearances/_form.html.haml
@@ -101,7 +101,7 @@
= parsed_with_gfm
.gl-mt-3.gl-mb-3
- = f.submit _('Update appearance settings'), class: 'btn gl-button btn-confirm'
+ = f.submit _('Update appearance settings'), pajamas_button: true
- if @appearance.persisted? || @appearance.updated_at
.mt-4
- if @appearance.persisted?
diff --git a/app/views/admin/application_settings/general.html.haml b/app/views/admin/application_settings/general.html.haml
index ec5d1ef4a34..6d8428d1aa6 100644
--- a/app/views/admin/application_settings/general.html.haml
+++ b/app/views/admin/application_settings/general.html.haml
@@ -119,8 +119,9 @@
= render_if_exists 'admin/application_settings/feishu_integration'
= render 'admin/application_settings/third_party_offers'
= render 'admin/application_settings/snowplow'
+= render_if_exists 'admin/application_settings/product_analytics'
= render 'admin/application_settings/error_tracking' if Feature.enabled?(:gitlab_error_tracking)
= render 'admin/application_settings/eks'
= render 'admin/application_settings/floc'
= render_if_exists 'admin/application_settings/add_license'
-= render 'admin/application_settings/jira_connect_application_key' if Feature.enabled?(:jira_connect_oauth, current_user)
+= render 'admin/application_settings/jira_connect' if Feature.enabled?(:jira_connect_oauth_self_managed_setting, current_user)
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 06bb9df84c4..82b627e1805 100644
--- a/app/views/admin/application_settings/service_usage_data.html.haml
+++ b/app/views/admin/application_settings/service_usage_data.html.haml
@@ -24,7 +24,7 @@
= c.body do
- enable_service_ping_link_url = help_page_path('user/admin_area/settings/usage_statistics', anchor: 'enable-or-disable-usage-statistics')
- enable_service_ping_link = '<a href="%{url}">'.html_safe % { url: enable_service_ping_link_url }
- - generate_manually_link_url = help_page_path('administration/troubleshooting/gitlab_rails_cheat_sheet', anchor: 'generate-service-ping')
+ - generate_manually_link_url = help_page_path('development/service_ping/troubleshooting', anchor: 'generate-service-ping')
- generate_manually_link = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: generate_manually_link_url }
= html_escape(s_('%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload.')) % { enable_service_ping_link_start: enable_service_ping_link, generate_manually_link_start: generate_manually_link, link_end: '</a>'.html_safe }
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index ccea1714973..886402139e9 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -122,7 +122,7 @@
= s_('AdminArea|Components')
- if show_version_check?
.float-right
- .js-gitlab-version-check{ data: { "size": "lg" } }
+ .js-gitlab-version-check-badge{ data: { "size": "lg", "actionable": "true" } }
= link_to(sprite_icon('question'), "https://gitlab.com/gitlab-org/gitlab/-/blob/master/CHANGELOG.md", class: 'gl-ml-2', target: '_blank', rel: 'noopener noreferrer')
%p
= link_to _('GitLab'), general_admin_application_settings_path
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index 6d370919460..c8b0704c35d 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -7,8 +7,9 @@
%h1.page-title.gl-font-size-h-display
= _('Group: %{group_name}') % { group_name: @group.full_name }
- = link_to admin_group_edit_path(@group), class: "btn btn-default gl-button float-right", data: { qa_selector: 'edit_group_link' } do
- = sprite_icon('pencil', css_class: 'gl-icon gl-mr-2')
+ = render Pajamas::ButtonComponent.new(href: admin_group_edit_path(@group),
+ button_options: { class: 'gl-float-right', data: { qa_selector: 'edit_group_link' }},
+ icon: 'pencil') do
= _('Edit')
%hr
.row
diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml
index 47a761e608f..6809f147ef8 100644
--- a/app/views/admin/users/_form.html.haml
+++ b/app/views/admin/users/_form.html.haml
@@ -75,8 +75,8 @@
%div
- if @user.new_record?
- = f.submit _('Create user'), class: "btn gl-button btn-confirm"
+ = f.submit _('Create user'), pajamas_button: true
= link_to _('Cancel'), admin_users_path, class: "gl-button btn btn-default btn-cancel"
- else
- = f.submit _('Save changes'), class: "btn gl-button btn-confirm"
+ = f.submit _('Save changes'), pajamas_button: true
= link_to _('Cancel'), admin_user_path(@user), class: "gl-button btn btn-default btn-cancel"
diff --git a/app/views/admin/users/_head.html.haml b/app/views/admin/users/_head.html.haml
index 0ceff211806..1fa7c9c8651 100644
--- a/app/views/admin/users/_head.html.haml
+++ b/app/views/admin/users/_head.html.haml
@@ -30,9 +30,11 @@
.gl-p-2
#js-admin-user-actions{ data: admin_user_actions_data_attributes(@user) }
- if @user != current_user
- - if impersonation_enabled? && @user.can?(:log_in)
+ - if impersonation_enabled?
.gl-p-2
- = link_to _('Impersonate'), impersonate_admin_user_path(@user), method: :post, class: "btn btn-default gl-button", data: { qa_selector: 'impersonate_user_link' }
+ %span.btn-group{ class: !@can_impersonate ? 'has-tooltip' : nil, title: @impersonation_error_text }
+ = render Pajamas::ButtonComponent.new(disabled: !@can_impersonate, method: :post, href: impersonate_admin_user_path(@user), button_options: { data: { qa_selector: 'impersonate_user_link', testid: 'impersonate_user_link' } }) do
+ = _('Impersonate')
- if can_force_email_confirmation?(@user)
.gl-p-2
= render Pajamas::ButtonComponent.new(variant: :default, button_options: { class: 'js-confirm-modal-button', data: confirm_user_data(@user) }) do
diff --git a/app/views/admin/users/_projects.html.haml b/app/views/admin/users/_projects.html.haml
index 3ccf3ef4f2a..2f77e83ac49 100644
--- a/app/views/admin/users/_projects.html.haml
+++ b/app/views/admin/users/_projects.html.haml
@@ -5,7 +5,7 @@
- c.body do
= render 'shared/projects/list',
projects: contributed_projects.sort_by(&:star_count).reverse,
- projects_limit: 5, stars: true, avatar: false
+ projects_limit: 5, stars: true, avatar: false, compact_mode: true
- if local_assigns.has_key?(:projects) && projects.present?
= render Pajamas::CardComponent.new(card_options: { class: 'gl-mb-5' }, body_options: { class: 'gl-py-0' }) do |c|
@@ -14,4 +14,4 @@
- c.body do
= render 'shared/projects/list',
projects: projects.sort_by(&:star_count).reverse,
- projects_limit: 10, stars: true, avatar: false
+ projects_limit: 10, stars: true, avatar: false, compact_mode: true
diff --git a/app/views/admin/users/_users.html.haml b/app/views/admin/users/_users.html.haml
index 8c77cb394ba..6d85ff50fbe 100644
--- a/app/views/admin/users/_users.html.haml
+++ b/app/views/admin/users/_users.html.haml
@@ -54,7 +54,7 @@
= hidden_field_tag "filter", h(params[:filter])
.search-holder
.search-field-holder.gl-mb-4
- = search_field_tag :search_query, params[:search_query], placeholder: s_('AdminUsers|Search by name, email or username'), class: 'form-control search-text-input js-search-input', spellcheck: false, data: { qa_selector: 'user_search_field' }
+ = search_field_tag :search_query, params[:search_query], placeholder: s_('AdminUsers|Search by name, email, or username'), class: 'form-control search-text-input js-search-input', spellcheck: false, data: { qa_selector: 'user_search_field' }
- if @sort.present?
= hidden_field_tag :sort, @sort
= sprite_icon('search', css_class: 'search-icon')
diff --git a/app/views/award_emoji/_awards_block.html.haml b/app/views/award_emoji/_awards_block.html.haml
index 3952a450c4a..5062599c261 100644
--- a/app/views/award_emoji/_awards_block.html.haml
+++ b/app/views/award_emoji/_awards_block.html.haml
@@ -1,7 +1,7 @@
- api_awards_path = local_assigns.fetch(:api_awards_path, nil)
- if api_awards_path
- .gl-display-flex.gl-flex-wrap.gl-justify-content-space-between.gl-py-3
+ .gl-display-flex.gl-flex-wrap.gl-justify-content-space-between.gl-pt-3
#js-vue-awards-block{ data: { path: api_awards_path, can_award_emoji: can?(current_user, :award_emoji, awardable).to_s } }
= yield
- else
diff --git a/app/views/ci/variables/_index.html.haml b/app/views/ci/variables/_index.html.haml
index 9ca11b35064..08865abbe86 100644
--- a/app/views/ci/variables/_index.html.haml
+++ b/app/views/ci/variables/_index.html.haml
@@ -10,7 +10,7 @@
- is_group = !@group.nil?
- is_project = !@project.nil?
-#js-ci-project-variables{ data: { endpoint: save_endpoint,
+#js-ci-variables{ data: { endpoint: save_endpoint,
is_project: is_project.to_s,
project_id: @project&.id || '',
project_full_path: @project&.full_path || '',
diff --git a/app/views/ci/variables/_url_query_variable_row.html.haml b/app/views/ci/variables/_url_query_variable_row.html.haml
deleted file mode 100644
index 77bcacdb94b..00000000000
--- a/app/views/ci/variables/_url_query_variable_row.html.haml
+++ /dev/null
@@ -1,28 +0,0 @@
-- form_field = local_assigns.fetch(:form_field, nil)
-- variable = local_assigns.fetch(:variable, nil)
-
-- key = variable[0]
-- value = variable[1]
-- variable_type = variable[2] || "env_var"
-
-- destroy_input_name = "#{form_field}[variables_attributes][][_destroy]"
-- variable_type_input_name = "#{form_field}[variables_attributes][][variable_type]"
-- key_input_name = "#{form_field}[variables_attributes][][key]"
-- value_input_name = "#{form_field}[variables_attributes][][secret_value]"
-
-%li.js-row.ci-variable-row
- .ci-variable-row-body.border-bottom
- %input.js-ci-variable-input-destroy{ type: "hidden", name: destroy_input_name }
- %select.js-ci-variable-input-variable-type.ci-variable-body-item.form-control.select-control.custom-select.table-section.section-15{ name: variable_type_input_name }
- = options_for_select(ci_variable_type_options, variable_type)
- %input.js-ci-variable-input-key.ci-variable-body-item.form-control.table-section.section-15{ type: "text",
- name: key_input_name,
- value: key,
- placeholder: s_('CiVariables|Input variable key') }
- .ci-variable-body-item.gl-show-field-errors.table-section.section-15.border-top-0.p-0
- %textarea.js-ci-variable-input-value.js-secret-value.form-control{ rows: 1,
- name: value_input_name,
- placeholder: s_('CiVariables|Input variable value') }
- = value
- %button.gl-button.btn.btn-default.btn-icon.btn-item-remove.js-row-remove-button.ci-variable-row-remove-button.table-section{ type: 'button', 'aria-label': s_('CiVariables|Remove variable row') }
- = sprite_icon('close')
diff --git a/app/views/dashboard/_groups_head.html.haml b/app/views/dashboard/_groups_head.html.haml
index 813c1cdbfe4..1c82b30ed8d 100644
--- a/app/views/dashboard/_groups_head.html.haml
+++ b/app/views/dashboard/_groups_head.html.haml
@@ -8,7 +8,7 @@
.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
+ = gl_tab_link_to _("Explore public groups"), explore_groups_path, data: { qa_selector: "public_groups_tab" }
.nav-controls
= render 'shared/groups/search_form'
= render 'shared/groups/dropdown'
diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml
index 95e772f324b..79f6bfc866a 100644
--- a/app/views/dashboard/issues.html.haml
+++ b/app/views/dashboard/issues.html.haml
@@ -1,6 +1,7 @@
- @hide_top_links = true
- page_title _("Issues")
- @breadcrumb_link = issues_dashboard_path(assignee_username: current_user.username)
+- add_page_specific_style 'page_bundles/dashboard'
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, safe_params.merge(rss_url_options).to_h, title: "#{current_user.name} issues")
@@ -13,14 +14,20 @@
.page-title-controls
= render 'shared/new_project_item_select', path: 'issues/new', label: _("issue"), with_feature_enabled: 'issues', type: :issues
-.top-area
- = render 'shared/issuable/nav', type: :issues, display_count: !@no_filters_set
- .nav-controls
- = render 'shared/issuable/feed_buttons'
+- if ::Feature.enabled?(:vue_issues_dashboard)
+ .js-issues-dashboard{ data: { calendar_path: url_for(safe_params.merge(calendar_url_options)),
+ empty_state_svg_path: image_path('illustrations/issue-dashboard_results-without-filter.svg'),
+ is_signed_in: current_user.present?.to_s,
+ rss_path: url_for(safe_params.merge(rss_url_options)) } }
+- else
+ .top-area
+ = render 'shared/issuable/nav', type: :issues, display_count: !@no_filters_set
+ .nav-controls
+ = render 'shared/issuable/feed_buttons'
-= render 'shared/issuable/search_bar', type: :issues
+ = render 'shared/issuable/search_bar', type: :issues
-- if current_user && @no_filters_set
- = render 'shared/dashboard/no_filter_selected'
-- else
- = render 'shared/issues'
+ - if current_user && @no_filters_set
+ = render 'shared/dashboard/no_filter_selected'
+ - else
+ = render 'shared/issues'
diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml
index b4668b1e52a..47bc8f5c95b 100644
--- a/app/views/dashboard/todos/_todo.html.haml
+++ b/app/views/dashboard/todos/_todo.html.haml
@@ -27,8 +27,7 @@
= todo_target_title(todo)
%span.title-item.todo-project.todo-label
- at
- = todo_parent_path(todo)
+ = s_('Todo|at %{todo_parent_path}').html_safe % { todo_parent_path: todo_parent_path(todo) }
- if todo.self_assigned?
%span.title-item.action-name
diff --git a/app/views/devise/confirmations/almost_there.haml b/app/views/devise/confirmations/almost_there.haml
index ef19ac33a15..01f9595f35c 100644
--- a/app/views/devise/confirmations/almost_there.haml
+++ b/app/views/devise/confirmations/almost_there.haml
@@ -1,4 +1,4 @@
-- user_email = "(#{params[:email]})" if params[:email].present?
+- 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
- content_for :page_specific_javascripts do
diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml
index e0e0b82b596..a4edf165a89 100644
--- a/app/views/devise/sessions/new.html.haml
+++ b/app/views/devise/sessions/new.html.haml
@@ -2,7 +2,6 @@
- content_for :page_specific_javascripts do
= render "layouts/google_tag_manager_head"
= render "layouts/one_trust"
- = render "layouts/bizible"
= render "layouts/google_tag_manager_body"
#signin-container
@@ -17,7 +16,7 @@
%div
= _('No authentication methods configured.')
- - if Feature.enabled?(:restyle_login_page, @project)
+ - if Feature.enabled?(:restyle_login_page, @project) && Gitlab::CurrentSettings.current_application_settings.terms
%p.gl-px-5
= html_escape(s_("SignUp|By signing in you accept the %{link_start}Terms of Use and acknowledge the Privacy Policy and Cookie Policy%{link_end}.")) % { link_start: "<a href='#{terms_path}' target='_blank' rel='noreferrer noopener'>".html_safe,
link_end: '</a>'.html_safe }
diff --git a/app/views/doorkeeper/authorizations/forbidden.html.haml b/app/views/doorkeeper/authorizations/forbidden.html.haml
new file mode 100644
index 00000000000..9cad5ce62d8
--- /dev/null
+++ b/app/views/doorkeeper/authorizations/forbidden.html.haml
@@ -0,0 +1,5 @@
+%h1.page-title.gl-font-size-h-display= _("Forbidden")
+%main{ :role => "main" }
+ %p
+ = sprite_icon('warning-solid')
+ = (_("Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API.") % { code_open: '<code>', code_close: '</code>' }).html_safe
diff --git a/app/views/errors/request_conflict.html.haml b/app/views/errors/request_conflict.html.haml
index 2f5abaca72f..040aa880e1c 100644
--- a/app/views/errors/request_conflict.html.haml
+++ b/app/views/errors/request_conflict.html.haml
@@ -13,6 +13,6 @@
%p
= s_('409|Please contact your GitLab administrator if you think this is a mistake.')
.action-container.js-go-back{ hidden: true }
- %button{ type: 'button', class: 'gl-button btn btn-primary' }
+ = render Pajamas::ButtonComponent.new(variant: :confirm) do
= _('Go Back')
= render "errors/footer"
diff --git a/app/views/groups/_archived_projects.html.haml b/app/views/groups/_archived_projects.html.haml
deleted file mode 100644
index 21107cc22a1..00000000000
--- a/app/views/groups/_archived_projects.html.haml
+++ /dev/null
@@ -1,7 +0,0 @@
-#js-groups-archived-tree
- .empty-state.text-center.hidden
- %p= _("There are no archived projects yet")
-
- %ul.content-list{ data: { hide_projects: 'false', group_id: group.id, path: group_path(group) } }
- .js-groups-list-holder
- = gl_loading_icon(size: 'md', css_class: 'gl-mt-6')
diff --git a/app/views/groups/_shared_projects.html.haml b/app/views/groups/_shared_projects.html.haml
deleted file mode 100644
index 6063d160fab..00000000000
--- a/app/views/groups/_shared_projects.html.haml
+++ /dev/null
@@ -1,7 +0,0 @@
-#js-groups-shared-tree
- .empty-state.text-center.hidden
- %p= _("There are no projects shared with this group yet")
-
- %ul.content-list{ data: { hide_projects: 'false', group_id: group.id, path: group_path(group) } }
- .js-groups-list-holder{ data: { current_group_visibility: group.visibility } }
- = gl_loading_icon
diff --git a/app/views/groups/_subgroups_and_projects.html.haml b/app/views/groups/_subgroups_and_projects.html.haml
deleted file mode 100644
index dc749af3c0c..00000000000
--- a/app/views/groups/_subgroups_and_projects.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-#js-groups-subgroups_and_projects-tree
- %section{ data: { hide_projects: 'false', group_id: group.id, path: group_path(group) } }
- .js-groups-list-holder{ data: subgroups_and_projects_list_app_data(group) }
- = gl_loading_icon(size: 'md', css_class: 'gl-mt-6')
diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml
index d9fef8940eb..4da70c8bf5d 100644
--- a/app/views/groups/group_members/index.html.haml
+++ b/app/views/groups/group_members/index.html.haml
@@ -1,8 +1,6 @@
- add_page_specific_style 'page_bundles/members'
- page_title _('Group members')
-= render_if_exists 'shared/free_user_cap_alert', source: @group
-
.row.gl-mt-3
.col-lg-12
.gl-display-flex.gl-flex-wrap
diff --git a/app/views/groups/observability/index.html.haml b/app/views/groups/observability/index.html.haml
deleted file mode 100644
index 582651c329b..00000000000
--- a/app/views/groups/observability/index.html.haml
+++ /dev/null
@@ -1,2 +0,0 @@
-- page_title _("Observability")
-%iframe{ id: 'observability-ui-iframe', src: @observability_iframe_src, frameborder: 0, width: "100%", height: "100%" }
diff --git a/app/views/groups/observability/observability.html.haml b/app/views/groups/observability/observability.html.haml
new file mode 100644
index 00000000000..834fa0e027c
--- /dev/null
+++ b/app/views/groups/observability/observability.html.haml
@@ -0,0 +1,3 @@
+- page_title observability_page_title
+
+#js-observability-app{ data: { observability_iframe_src: observability_iframe_src(@group) } }
diff --git a/app/views/groups/settings/_remove.html.haml b/app/views/groups/settings/_remove.html.haml
index 8571b93364b..a37a0f8053b 100644
--- a/app/views/groups/settings/_remove.html.haml
+++ b/app/views/groups/settings/_remove.html.haml
@@ -1,6 +1,6 @@
- remove_form_id = local_assigns.fetch(:remove_form_id, nil)
- if group.adjourned_deletion?
- = render_if_exists 'groups/settings/adjourned_deletion', group: group, remove_form_id: remove_form_id
+ = render_if_exists 'groups/settings/delayed_deletion', group: group, remove_form_id: remove_form_id
- else
= render 'groups/settings/permanent_deletion', group: group, remove_form_id: remove_form_id
diff --git a/app/views/groups/settings/_transfer.html.haml b/app/views/groups/settings/_transfer.html.haml
index 7fe5a7a665b..e01d703206c 100644
--- a/app/views/groups/settings/_transfer.html.haml
+++ b/app/views/groups/settings/_transfer.html.haml
@@ -1,5 +1,5 @@
- form_id = "transfer-group-form"
-- initial_data = { button_text: s_('GroupSettings|Transfer group'), group_name: @group.name, target_form_id: form_id, parent_groups: parent_group_options(group), is_paid_group: group.paid?.to_s }
+- initial_data = { button_text: s_('GroupSettings|Transfer group'), group_name: @group.name, group_id: @group.id, target_form_id: form_id, is_paid_group: group.paid?.to_s }
.sub-section
%h4.warning-title= s_('GroupSettings|Transfer group')
diff --git a/app/views/groups/settings/access_tokens/index.html.haml b/app/views/groups/settings/access_tokens/index.html.haml
index 5e3d814687e..309633471a5 100644
--- a/app/views/groups/settings/access_tokens/index.html.haml
+++ b/app/views/groups/settings/access_tokens/index.html.haml
@@ -39,6 +39,5 @@
prefix: :resource_access_token,
help_path: help_page_path('user/group/settings/group_access_tokens', anchor: 'scopes-for-a-group-access-token')
- #js-access-token-table-app{ data: { access_token_type: type, access_token_type_plural: type_plural, initial_active_access_tokens: @active_resource_access_tokens.to_json, no_active_tokens_message: _('This group has no active access tokens.'), show_role: true
+ #js-access-token-table-app{ data: { access_token_type: type, access_token_type_plural: type_plural, initial_active_access_tokens: @active_access_tokens.to_json, no_active_tokens_message: _('This group has no active access tokens.'), show_role: true
} }
-
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index 012a31c1ecf..72b7bec1b92 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -4,7 +4,6 @@
- add_page_specific_style 'page_bundles/group'
= render_if_exists 'shared/qrtly_reconciliation_alert', group: @group
-= render_if_exists 'shared/free_user_cap_alert', source: @group
- if show_invite_banner?(@group)
= content_for :group_invite_members_banner do
@@ -30,36 +29,4 @@
= render_if_exists 'groups/group_activity_analytics', group: @group
-- if Feature.enabled?(:group_overview_tabs_vue, @group)
- #js-group-overview-tabs{ data: group_overview_tabs_app_data(@group) }
-- else
- .groups-listing{ data: { endpoints: { default: group_children_path(@group, format: :json), shared: group_shared_projects_path(@group, format: :json) } } }
- .top-area.group-nav-container.justify-content-between
- .scrolling-tabs-container.inner-page-scroll-tabs
- .fade-left= sprite_icon('chevron-lg-left', size: 12)
- .fade-right= sprite_icon('chevron-lg-right', size: 12)
- -# `item_active` is set to `false` as the active state is set by `app/assets/javascripts/pages/groups/shared/group_details.js`
- -# TODO: Replace this approach in https://gitlab.com/gitlab-org/gitlab/-/issues/23466
- = gl_tabs_nav({ class: 'nav-links scrolling-tabs gl-display-flex gl-flex-grow-1 gl-flex-nowrap gl-border-0' }) do
- = gl_tab_link_to group_path, item_active: false, tab_class: 'js-subgroups_and_projects-tab', data: { target: 'div#subgroups_and_projects', action: 'subgroups_and_projects', toggle: 'tab' } do
- = _("Subgroups and projects")
- = gl_tab_link_to group_shared_path, item_active: false, tab_class: 'js-shared-tab', data: { target: 'div#shared', action: 'shared', toggle: 'tab' } do
- = _("Shared projects")
- = gl_tab_link_to group_archived_path, item_active: false, tab_class: 'js-archived-tab', data: { target: 'div#archived', action: 'archived', toggle: 'tab' } do
- = _("Archived projects")
-
- .nav-controls.d-block.d-md-flex
- .group-search
- = render "shared/groups/search_form"
-
- = render "shared/groups/dropdown", options_hash: subgroups_sort_options_hash
-
- .tab-content
- #subgroups_and_projects.tab-pane
- = render "subgroups_and_projects", group: @group
-
- #shared.tab-pane
- = render "shared_projects", group: @group
-
- #archived.tab-pane
- = render "archived_projects", group: @group
+#js-group-overview-tabs{ data: group_overview_tabs_app_data(@group) }
diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml
index eaa58580454..8c74aac5ef5 100644
--- a/app/views/help/index.html.haml
+++ b/app/views/help/index.html.haml
@@ -11,7 +11,7 @@
%span= link_to_version
- if show_version_check?
%span.gl-mt-5.gl-mb-3.gl-ml-3
- .js-gitlab-version-check{ data: { "size": "lg" } }
+ .js-gitlab-version-check-badge{ data: { "size": "lg", "actionable": "true" } }
%hr
- unless Gitlab::CurrentSettings.help_page_hide_commercial_content?
diff --git a/app/views/import/_githubish_status.html.haml b/app/views/import/_githubish_status.html.haml
index 9ea52a8f82f..e92db09aaf1 100644
--- a/app/views/import/_githubish_status.html.haml
+++ b/app/views/import/_githubish_status.html.haml
@@ -4,7 +4,7 @@
- filterable = local_assigns.fetch(:filterable, true)
- paginatable = local_assigns.fetch(:paginatable, false)
- default_namespace_path = (local_assigns[:default_namespace] || current_user.namespace).full_path
-- provider_title = Gitlab::ImportSources.title(provider)
+- provider_title = Gitlab::ImportSources.title(local_assigns.fetch(:provider))
- optional_stages = local_assigns.fetch(:optional_stages, [])
- header_title _("New project"), new_project_path
diff --git a/app/views/layouts/_img_loader.html.haml b/app/views/layouts/_img_loader.html.haml
index f6d7d163e6f..979ebeb0a02 100644
--- a/app/views/layouts/_img_loader.html.haml
+++ b/app/views/layouts/_img_loader.html.haml
@@ -12,6 +12,7 @@
img.src = imgUrl;
img.removeAttribute('data-src');
img.classList.remove('lazy');
- img.classList.add('js-lazy-loaded', 'qa-js-lazy-loaded');
+ img.classList.add('js-lazy-loaded');
+ img.dataset.qa_selector = 'js_lazy_loaded_content';
});
}
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index 014e26c7613..d668399b408 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -24,7 +24,7 @@
= yield :group_invite_members_banner
- unless @hide_breadcrumbs
= render "layouts/nav/breadcrumbs"
- %div{ class: "#{(container_class unless @no_container)} #{@content_class}" }
+ %div{ class: "#{container_class unless @no_container} #{@content_class}" }
%main.content{ id: "content-body", **page_itemtype }
= render "layouts/flash", extra_flash_class: 'limit-container-width'
= yield :after_flash_content
diff --git a/app/views/layouts/component_preview.html.haml b/app/views/layouts/component_preview.html.haml
index ec12395a5d4..a1b1304f994 100644
--- a/app/views/layouts/component_preview.html.haml
+++ b/app/views/layouts/component_preview.html.haml
@@ -1,5 +1,14 @@
%head
- = stylesheet_link_tag "application"
- = stylesheet_link_tag "application_utilities"
-%body{ style: "background-color: #{params.dig(:lookbook, :display, :bg_color) || 'white'}" }
- .container.gl-mt-6= yield
+ - 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
+ - if params[:lookbook][:display][:bg_dark]
+ .bg-dark.rounded.shadow.p-4
+ = yield
+ - else
+ = yield
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index 97c2b8bb7e3..95934f43a51 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -16,4 +16,6 @@
:plain
window.uploads_path = "#{group_uploads_path(@group)}";
+= dispensable_render_if_exists "shared/free_user_cap_alert", source: @group
+
= render template: base_layout || "layouts/application"
diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml
index b74dfd4d3a1..42ffd155647 100644
--- a/app/views/layouts/header/_default.html.haml
+++ b/app/views/layouts/header/_default.html.haml
@@ -19,16 +19,9 @@
.gl-display-none.gl-sm-display-block
= render "layouts/nav/top_nav"
- else
- - experiment(:logged_out_marketing_header, actor: nil) do |e|
- - e.candidate do
- = render 'layouts/header/marketing_links'
- - e.try(:trial_focused) do
- = render 'layouts/header/marketing_links'
- - e.control do
- .gl-display-none.gl-sm-display-block
- = render "layouts/nav/top_nav"
+ = render 'layouts/header/marketing_links'
- - if top_nav_show_search && Feature.enabled?(:new_navbar_layout)
+ - if top_nav_show_search
.navbar-collapse.gl-transition-medium.collapse.gl-mr-auto.global-search-container.hide-when-top-nav-responsive-open
- search_menu_item = top_nav_search_menu_item_attrs
%ul.nav.navbar-nav.gl-w-full.gl-align-items-center
@@ -42,21 +35,10 @@
= link_to search_menu_item.fetch(:href), title: search_menu_item.fetch(:title), aria: { label: search_menu_item.fetch(:title) }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= sprite_icon(search_menu_item.fetch(:icon))
- .navbar-collapse.gl-transition-medium.collapse{ class: ('global-search-container' unless Feature.enabled?(:new_navbar_layout)) }
+ .navbar-collapse.gl-transition-medium.collapse
%ul.nav.navbar-nav.gl-w-full.gl-align-items-center.gl-justify-content-end
- if current_user
= render 'layouts/header/new_dropdown', class: 'gl-display-none gl-sm-display-block gl-white-space-nowrap gl-text-right'
- - if top_nav_show_search && Feature.disabled?(:new_navbar_layout)
- - search_menu_item = top_nav_search_menu_item_attrs
- %li.nav-item.header-search-new.gl-display-none.gl-lg-display-block.gl-w-full
- - unless current_controller?(:search)
- - if Feature.enabled?(:new_header_search)
- = render 'layouts/header_search'
- - else
- = render 'layouts/search'
- %li.nav-item{ class: 'd-none d-sm-inline-block d-lg-none' }
- = link_to search_menu_item.fetch(:href), title: search_menu_item.fetch(:title), aria: { label: search_menu_item.fetch(:title) }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
- = sprite_icon(search_menu_item.fetch(:icon))
- if header_link?(:issues)
= nav_link(path: 'dashboard#issues', html_options: { class: "user-counter" }) do
= link_to assigned_issues_dashboard_path, title: _('Issues'), class: 'dashboard-shortcuts-issues js-prefetch-document', aria: { label: _('Issues') },
@@ -67,7 +49,7 @@
container: 'body' } do
= sprite_icon('issues')
- issues_count = assigned_issuables_count(:issues)
- = gl_badge_tag({ size: :sm, variant: :success }, { class: "gl-ml-n2 #{(' gl-display-none' if issues_count == 0)}", "aria-label": n_("%d assigned issue", "%d assigned issues", issues_count) % issues_count }) do
+ = gl_badge_tag({ size: :sm, variant: :success }, { class: "gl-ml-n2 #{'gl-display-none' if issues_count == 0}", "aria-label": n_("%d assigned issue", "%d assigned issues", issues_count) % issues_count }) do
= number_with_delimiter(issues_count)
- if header_link?(:merge_requests)
= nav_link(path: 'dashboard#merge_requests', html_options: { class: "user-counter dropdown" }) do
@@ -81,7 +63,7 @@
track_property: 'navigation',
container: 'body' } do
= sprite_icon('git-merge')
- = gl_badge_tag({ size: :sm, variant: :warning }, { class: "js-merge-requests-count gl-ml-n2#{(' gl-display-none' if user_merge_requests_counts[:total] == 0)}", "aria-label": n_("%d merge request", "%d merge requests", user_merge_requests_counts[:total]) % user_merge_requests_counts[:total] }) do
+ = gl_badge_tag({ size: :sm, variant: :warning }, { class: "js-merge-requests-count gl-ml-n2 #{'gl-display-none' if user_merge_requests_counts[:total] == 0}", "aria-label": n_("%d merge request", "%d merge requests", user_merge_requests_counts[:total]) % user_merge_requests_counts[:total] }) do
= number_with_delimiter(user_merge_requests_counts[:total])
= sprite_icon('chevron-down', css_class: 'caret-down gl-mx-0!')
.dropdown-menu.dropdown-menu-right
@@ -94,7 +76,7 @@
= gl_badge_tag({ variant: :neutral, size: :sm }, { class: "js-assigned-mr-count gl-ml-auto" }) do
= user_merge_requests_counts[:assigned]
%li
- = link_to reviewer_mrs_dashboard_path, class: 'gl-display-flex! gl-align-items-center js-prefetch-document' do
+ = link_to reviewer_mrs_dashboard_path, class: 'dashboard-shortcuts-review_requests gl-display-flex! gl-align-items-center js-prefetch-document' do
= _('Review requests for you')
= gl_badge_tag({ variant: :neutral, size: :sm }, { class: "js-reviewer-mr-count gl-ml-auto" }) do
= user_merge_requests_counts[:review_requested]
@@ -109,7 +91,7 @@
= sprite_icon('todo-done')
-# The todos' counter badge's visibility is being toggled by adding or removing the .hidden class in Js.
-# We'll eventually migrate to .gl-display-none: https://gitlab.com/gitlab-org/gitlab/-/issues/351792.
- = gl_badge_tag({ size: :sm, variant: :info }, { class: "js-todos-count gl-ml-n2#{(' hidden' if todos_pending_count == 0)}", "aria-label": _("Todos count") }) do
+ = gl_badge_tag({ size: :sm, variant: :info }, { class: "js-todos-count gl-ml-n2 #{'hidden' if todos_pending_count == 0}", "aria-label": _("Todos count") }) do
= todos_count_format(todos_pending_count)
%li.nav-item.header-help.dropdown.d-none.d-md-block{ data: { track_action: 'click_question_mark_link', track_label: 'main_navigation', track_property: 'navigation', track_experiment: 'cross_stage_fdm' } }
= link_to help_path, class: 'header-help-dropdown-toggle gl-relative', data: { toggle: "dropdown" } do
@@ -121,14 +103,8 @@
.dropdown-menu.dropdown-menu-right
= render 'layouts/header/help_dropdown'
- unless current_user
- - experiment(:logged_out_marketing_header, actor: nil) do |e|
- - e.candidate do
- %li.nav-item.gl-display-none.gl-sm-display-block
- = render "layouts/nav/top_nav"
- - e.try(:trial_focused) do
- %li.nav-item.gl-display-none.gl-sm-display-block
- = render "layouts/nav/top_nav"
- - e.control {}
+ %li.nav-item.gl-display-none.gl-sm-display-block
+ = render "layouts/nav/top_nav"
- if header_link?(:user_dropdown)
%li.nav-item.header-user.js-nav-user-dropdown.dropdown{ data: { track_label: "profile_dropdown", track_action: "click_dropdown", track_value: "", qa_selector: 'user_menu', testid: 'user-menu' }, class: ('mr-0' if has_impersonation_link) }
= link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown" } do
@@ -142,23 +118,11 @@
= link_to admin_impersonation_path, class: 'nav-link impersonation-btn', method: :delete, title: _('Stop impersonation'), aria: { label: _('Stop impersonation') }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body', qa_selector: 'stop_impersonation_link' } do
= sprite_icon('incognito', size: 18)
- if header_link?(:sign_in)
- - experiment(:logged_out_marketing_header, actor: nil) do |e|
- - e.candidate do
- %li.nav-item.gl-display-none.gl-sm-display-block
- = link_to _('Sign up now'), new_user_registration_path, class: 'gl-button btn btn-default btn-sign-in', data: { track_action: 'click_button', track_experiment: e.name, track_label: 'sign_up_now' }
- %li.nav-item.gl-display-none.gl-sm-display-block
- = link_to _('Login'), new_session_path(:user, redirect_to_referer: 'yes')
- = render 'layouts/header/sign_in_register_button', class: 'gl-sm-display-none'
- - e.try(:trial_focused) do
- %li.nav-item.gl-display-none.gl-sm-display-block
- = link_to _('Get a free trial'), 'https://about.gitlab.com/free-trial/', class: 'gl-button btn btn-default btn-sign-in', data: { track_action: 'click_button', track_experiment: e.name, track_label: 'get_a_free_trial' }
- %li.nav-item.gl-display-none.gl-sm-display-block
- = link_to _('Sign up'), new_user_registration_path, data: { track_action: 'click_button', track_experiment: e.name, track_label: 'sign_up' }
- %li.nav-item.gl-display-none.gl-sm-display-block
- = link_to _('Login'), new_session_path(:user, redirect_to_referer: 'yes')
- = render 'layouts/header/sign_in_register_button', class: 'gl-sm-display-none'
- - e.control do
- = render 'layouts/header/sign_in_register_button'
+ %li.nav-item.gl-display-none.gl-sm-display-block
+ = link_to _('Sign up now'), new_user_registration_path, class: 'gl-button btn btn-default btn-sign-in'
+ %li.nav-item.gl-display-none.gl-sm-display-block
+ = link_to _('Login'), new_session_path(:user, redirect_to_referer: 'yes')
+ = render 'layouts/header/sign_in_register_button', class: 'gl-sm-display-none'
%button.navbar-toggler.d-block.d-sm-none{ type: 'button', class: 'gl-border-none!', data: { testid: 'top-nav-responsive-toggle', qa_selector: 'mobile_navbar_button' } }
%span.sr-only= _('Toggle navigation')
diff --git a/app/views/layouts/header/_gitlab_version.html.haml b/app/views/layouts/header/_gitlab_version.html.haml
index fae6926a687..2315caa5fe8 100644
--- a/app/views/layouts/header/_gitlab_version.html.haml
+++ b/app/views/layouts/header/_gitlab_version.html.haml
@@ -1,6 +1,15 @@
- return unless show_version_check?
-%a{ class: 'gl-display-flex! gl-flex-direction-column gl-px-4! gl-py-3! gl-line-height-24!', href: help_page_path('update/index'), 'data-testid': 'gitlab-version-container' }
+%a{
+ class: 'gl-display-flex! gl-flex-direction-column gl-px-4! gl-py-3! gl-line-height-24!',
+ href: help_page_path('update/index'),
+ data: {
+ testid: 'gitlab-version-container',
+ track_action: 'click_link',
+ track_label: 'version_help_dropdown',
+ track_property: "#{Gitlab.version_info.major}.#{Gitlab.version_info.minor}"
+ }
+ }
%span
= s_("VersionCheck|Your GitLab Version")
= emoji_icon('rocket')
@@ -8,4 +17,4 @@
%span.gl-font-sm.gl-text-gray-500
#{Gitlab.version_info.major}.#{Gitlab.version_info.minor}
%span.gl-ml-2
- .js-gitlab-version-check{ data: { "size": "sm" } }
+ .js-gitlab-version-check-badge{ data: { "size": "sm" } }
diff --git a/app/views/layouts/header/_new_dropdown.html.haml b/app/views/layouts/header/_new_dropdown.html.haml
index 9801b0cc055..f39fb53032d 100644
--- a/app/views/layouts/header/_new_dropdown.html.haml
+++ b/app/views/layouts/header/_new_dropdown.html.haml
@@ -7,7 +7,7 @@
- return if menu_sections.empty?
%li.header-new.gl-flex-grow-1.gl-flex-shrink-1.dropdown{ class: top_class, data: { track_label: "new_dropdown", track_action: "click_dropdown" } }
- = link_to new_project_path, class: "header-new-dropdown-toggle has-tooltip gl-display-inline-block!", id: "js-onboarding-new-project-link", title: title, ref: 'tooltip', aria: { label: title }, data: { toggle: 'dropdown', placement: 'bottom', container: 'body', display: 'static', qa_selector: 'new_menu_toggle' } do
+ = link_to new_project_path, class: "header-new-dropdown-toggle has-tooltip gl-display-flex", id: "js-onboarding-new-project-link", title: title, ref: 'tooltip', aria: { label: title }, data: { toggle: 'dropdown', placement: 'bottom', container: 'body', display: 'static', qa_selector: 'new_menu_toggle' } do
= sprite_icon('plus-square')
= sprite_icon('chevron-down', css_class: 'caret-down')
.dropdown-menu.dropdown-menu-right.dropdown-extended-height
diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml
index 75d5e40011c..6ad6696b313 100644
--- a/app/views/layouts/project.html.haml
+++ b/app/views/layouts/project.html.haml
@@ -19,5 +19,6 @@
window.uploads_path = "#{project_uploads_path(project)}";
= dispensable_render_if_exists "shared/web_hooks/web_hook_disabled_alert"
+= dispensable_render_if_exists "projects/free_user_cap_alert", project: @project
= render template: "layouts/application"
diff --git a/app/views/notify/pipeline_failed_email.html.haml b/app/views/notify/pipeline_failed_email.html.haml
index 4e8d8a20ef1..5d4d2c0fcd8 100644
--- a/app/views/notify/pipeline_failed_email.html.haml
+++ b/app/views/notify/pipeline_failed_email.html.haml
@@ -6,7 +6,7 @@
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;vertical-align:middle;color:#ffffff;text-align:center;padding-right:5px;line-height:1;" }
%img{ alt: "✖", height: "13", src: image_url('mailers/ci_pipeline_notif_v1/icon-x-red-inverted.gif'), style: "display:block;", width: "13" }/
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;vertical-align:middle;color:#ffffff;text-align:center;" }
- Pipeline ##{@pipeline.id} has failed!
+ = s_('Notify|Pipeline #%{pipeline_id} has failed!') % { pipeline_id: @pipeline.id }
%tr.spacer
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;height:18px;font-size:18px;line-height:18px;" }
&nbsp;
@@ -15,7 +15,8 @@
%table.table-info{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;" }
%tbody
%tr
- %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;" } Project
+ %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;" }
+ = _('Project')
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:500;padding:14px 0;margin:0;color:#333333;width:75%;padding-left:5px;" }
- namespace_name = @project.group ? @project.group.name : @project.namespace.owner.name
- namespace_url = @project.group ? group_url(@project.group) : user_url(@project.namespace.owner)
@@ -25,7 +26,8 @@
%a.muted{ href: project_url(@project), style: "color:#333333;text-decoration:none;" }
= @project.name
%tr
- %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" } Branch
+ %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" }
+ = _('Branch')
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:500;padding:14px 0;margin:0;color:#333333;width:75%;padding-left:5px;border-top:1px solid #ededed;" }
%table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" }
%tbody
@@ -36,7 +38,8 @@
%a.muted{ href: commits_url(@pipeline), style: "color:#333333;text-decoration:none;" }
= @pipeline.source_ref
%tr
- %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" } Commit
+ %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" }
+ = _('Commit')
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:400;padding:14px 0;margin:0;color:#333333;width:75%;padding-left:5px;border-top:1px solid #ededed;" }
%table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" }
%tbody
@@ -54,7 +57,8 @@
= @pipeline.git_commit_message.truncate(50)
- commit = @pipeline.commit
%tr
- %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" } Commit Author
+ %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" }
+ = s_('Notify|Commit Author')
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:500;padding:14px 0;margin:0;color:#333333;width:75%;padding-left:5px;border-top:1px solid #ededed;" }
%table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" }
%tbody
@@ -93,11 +97,10 @@
%table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;margin:0 auto;" }
%tbody
%tr
- %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;font-weight:500;line-height:1.4;vertical-align:baseline;" }
- Pipeline
- %a{ href: pipeline_url(@pipeline), style: "color:#3777b0;text-decoration:none;" }
- = "\##{@pipeline.id}"
- triggered by
+ - common_style = "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;font-weight:500;line-height:1.4;vertical-align:baseline;"
+ - pipeline_link = link_to "##{@pipeline.id}", pipeline_url(@pipeline), style: "color:#3777b0;text-decoration:none;"
+ %td{ style: "#{common_style}" }
+ = s_('Notify|Pipeline %{pipeline_link} triggered by').html_safe % { pipeline_link: pipeline_link }
- if @pipeline.user
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;padding-right:5px;padding-left:5px", width: "24" }
%img.avatar{ height: "24", src: avatar_icon_for_user(@pipeline.user, 24, only_path: false), style: "display:block;border-radius:12px;margin:-2px 0;", width: "24", alt: "" }/
diff --git a/app/views/notify/unknown_sign_in_email.html.haml b/app/views/notify/unknown_sign_in_email.html.haml
index b1c79274e26..64bf4e7b4e8 100644
--- a/app/views/notify/unknown_sign_in_email.html.haml
+++ b/app/views/notify/unknown_sign_in_email.html.haml
@@ -9,7 +9,7 @@
%tr
%td{ style: "#{default_font}vertical-align:middle;color:#ffffff;text-align:center;" }
%span
- = _("Your %{host} account was signed in to from a new location") % { host: Gitlab.config.gitlab.host }
+ = _("Someone signed in to your %{host} account from a new location") % { host: Gitlab.config.gitlab.host }
%tr.spacer
%td{ style: spacer_style }
&nbsp;
diff --git a/app/views/profiles/keys/_form.html.haml b/app/views/profiles/keys/_form.html.haml
index b37a0d9cc1a..e6d91543585 100644
--- a/app/views/profiles/keys/_form.html.haml
+++ b/app/views/profiles/keys/_form.html.haml
@@ -5,12 +5,12 @@
.form-group
= f.label :key, s_('Profiles|Key'), class: 'label-bold'
- = f.text_area :key, class: "form-control gl-form-input js-add-ssh-key-validation-input qa-key-public-key-field", rows: 8, required: true, data: { supported_algorithms: Gitlab::SSHPublicKey.supported_algorithms }
+ = f.text_area :key, class: "form-control gl-form-input js-add-ssh-key-validation-input", rows: 8, required: true, data: { supported_algorithms: Gitlab::SSHPublicKey.supported_algorithms, qa_selector: 'key_public_key_field' }
%p.form-text.text-muted= s_('Profiles|Begins with %{ssh_key_algorithms}.') % { ssh_key_algorithms: ssh_key_allowed_algorithms }
.form-row
.col.form-group
= f.label :title, s_('Profiles|Title'), class: 'label-bold'
- = f.text_field :title, class: "form-control gl-form-input input-lg qa-key-title-field", required: true, placeholder: s_('Profiles|Example: MacBook key')
+ = f.text_field :title, class: "form-control gl-form-input input-lg", required: true, placeholder: s_('Profiles|Example: MacBook key'), data: { qa_selector: 'key_title_field' }
%p.form-text.text-muted= s_('Profiles|Key titles are publicly visible.')
.form-row
@@ -29,4 +29,4 @@
button_options: { class: 'js-add-ssh-key-validation-confirm-submit' }) do
= _("Yes, add it")
.gl-mt-3
- = f.submit s_('Profiles|Add key'), class: "js-add-ssh-key-validation-original-submit qa-add-key-button", pajamas_button: true
+ = f.submit s_('Profiles|Add key'), class: "js-add-ssh-key-validation-original-submit", pajamas_button: true, data: { qa_selector: 'add_key_button' }
diff --git a/app/views/profiles/notifications/show.html.haml b/app/views/profiles/notifications/show.html.haml
index 23a0d824bfe..efc1e23d9b4 100644
--- a/app/views/profiles/notifications/show.html.haml
+++ b/app/views/profiles/notifications/show.html.haml
@@ -1,3 +1,4 @@
+- add_page_specific_style 'page_bundles/notifications'
- page_title _('Notifications')
- @content_class = "limit-container-width" unless fluid_layout
diff --git a/app/views/profiles/personal_access_tokens/index.html.haml b/app/views/profiles/personal_access_tokens/index.html.haml
index 636defb3f10..82df6b1b2c7 100644
--- a/app/views/profiles/personal_access_tokens/index.html.haml
+++ b/app/views/profiles/personal_access_tokens/index.html.haml
@@ -25,6 +25,6 @@
scopes: @scopes,
help_path: help_page_path('user/profile/personal_access_tokens.md', anchor: 'personal-access-token-scopes')
- #js-access-token-table-app{ data: { access_token_type: type, access_token_type_plural: type_plural, initial_active_access_tokens: @active_personal_access_tokens.to_json } }
+ #js-access-token-table-app{ data: { access_token_type: type, access_token_type_plural: type_plural, initial_active_access_tokens: @active_access_tokens.to_json } }
#js-tokens-app{ data: { tokens_data: tokens_app_data } }
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index dfaa4c31cdf..a140d780180 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -62,7 +62,7 @@
%p= s_("Profiles|Set your local time zone.")
.col-lg-8
= f.label :user_timezone, _("Time zone")
- .js-timezone-dropdown{ data: { timezone_data: timezone_data.to_json, initial_value: @user.timezone } }
+ .js-timezone-dropdown{ data: { timezone_data: timezone_data.to_json, initial_value: @user.timezone, name: 'user[timezone]' } }
.col-lg-12
%hr
.row.js-search-settings-section
diff --git a/app/views/projects/_files.html.haml b/app/views/projects/_files.html.haml
index 319c6333e77..51222784847 100644
--- a/app/views/projects/_files.html.haml
+++ b/app/views/projects/_files.html.haml
@@ -6,7 +6,7 @@
- if readme_path = @project.repository.readme_path
- add_page_startup_api_call project_blob_path(@project, tree_join(@ref, readme_path), viewer: "rich", format: "json")
-#tree-holder.tree-holder.clearfix
+#tree-holder.tree-holder.clearfix.js-per-page{ data: { blame_per_page: Projects::BlameService::PER_PAGE } }
.nav-block.gl-display-flex.gl-xs-flex-direction-column.gl-align-items-stretch
= render 'projects/tree/tree_header', tree: @tree, is_project_overview: is_project_overview
diff --git a/app/views/projects/_import_project_pane.html.haml b/app/views/projects/_import_project_pane.html.haml
index 42cdc1d6989..cc5271a1cd2 100644
--- a/app/views/projects/_import_project_pane.html.haml
+++ b/app/views/projects/_import_project_pane.html.haml
@@ -10,45 +10,32 @@
.import-buttons
- if gitlab_project_import_enabled?
.import_gitlab_project.has-tooltip{ data: { container: 'body', qa_selector: 'gitlab_import_button' } }
- = link_to '#', class: 'gl-button btn-default btn btn_import_gitlab_project js-import-project-btn', data: { href: new_import_gitlab_project_path, platform: 'gitlab_export', **tracking_attrs_data(track_label, 'click_button', 'gitlab_export') } do
- .gl-button-icon
- = sprite_icon('tanuki')
- = _("GitLab export")
+ = render Pajamas::ButtonComponent.new(href: '#', icon: 'tanuki', button_options: { class: 'btn_import_gitlab_project js-import-project-btn', data: { href: new_import_gitlab_project_path, platform: 'gitlab_export', **tracking_attrs_data(track_label, 'click_button', 'gitlab_export') } }) do
+ = _('GitLab export')
+
+ - if gitlab_import_enabled?
+ %div
+ = render Pajamas::ButtonComponent.new(href: status_import_gitlab_path(namespace_id: namespace_id), icon: 'tanuki', button_options: { class: "import_gitlab js-import-project-btn #{'js-how-to-import-link' unless gitlab_import_configured?}", data: { modal_title: _("Import projects from GitLab.com"), modal_message: import_from_gitlab_message, platform: 'gitlab_com', **tracking_attrs_data(track_label, 'click_button', 'gitlab_com') } }) do
+ GitLab.com
- if github_import_enabled?
%div
- = link_to new_import_github_path(namespace_id: namespace_id), class: 'gl-button btn-default btn js-import-github js-import-project-btn', data: { platform: 'github', **tracking_attrs_data(track_label, 'click_button', 'github') } do
- .gl-button-icon
- = sprite_icon('github')
+ = render Pajamas::ButtonComponent.new(href: new_import_github_path(namespace_id: namespace_id), icon: 'github', button_options: { class: 'js-import-github js-import-project-btn', data: { platform: 'github', **tracking_attrs_data(track_label, 'click_button', 'github') } }) do
GitHub
- if bitbucket_import_enabled?
%div
- = link_to status_import_bitbucket_path(namespace_id: namespace_id), class: "gl-button btn-default btn import_bitbucket js-import-project-btn #{'js-how-to-import-link' unless bitbucket_import_configured?}",
- data: { modal_title: _("Import projects from Bitbucket"), modal_message: import_from_bitbucket_message, platform: 'bitbucket_cloud', **tracking_attrs_data(track_label, 'click_button', 'bitbucket_cloud') } do
- .gl-button-icon
- = sprite_icon('bitbucket')
+ = render Pajamas::ButtonComponent.new(href: status_import_bitbucket_path(namespace_id: namespace_id), icon: 'bitbucket', button_options: { class: "import_bitbucket js-import-project-btn #{'js-how-to-import-link' unless bitbucket_import_configured?}", data: { modal_title: _("Import projects from Bitbucket"), modal_message: import_from_bitbucket_message, platform: 'bitbucket_cloud', **tracking_attrs_data(track_label, 'click_button', 'bitbucket_cloud') } }) do
Bitbucket Cloud
+
- if bitbucket_server_import_enabled?
%div
- = link_to status_import_bitbucket_server_path(namespace_id: namespace_id), class: "gl-button btn-default btn import_bitbucket js-import-project-btn", data: { platform: 'bitbucket_server', **tracking_attrs_data(track_label, 'click_button', 'bitbucket_server') } do
- .gl-button-icon
- = sprite_icon('bitbucket')
+ = render Pajamas::ButtonComponent.new(href: status_import_bitbucket_server_path(namespace_id: namespace_id), icon: 'bitbucket', button_options: { class: 'import_bitbucket js-import-project-btn', data: { platform: 'bitbucket_server', **tracking_attrs_data(track_label, 'click_button', 'bitbucket_server') } }) do
Bitbucket Server
- %div
- - if gitlab_import_enabled?
- %div
- = link_to status_import_gitlab_path(namespace_id: namespace_id), class: "gl-button btn-default btn import_gitlab js-import-project-btn #{'js-how-to-import-link' unless gitlab_import_configured?}",
- data: { modal_title: _("Import projects from GitLab.com"), modal_message: import_from_gitlab_message, platform: 'gitlab_com', **tracking_attrs_data(track_label, 'click_button', 'gitlab_com') } do
- .gl-button-icon
- = sprite_icon('tanuki')
- = _("GitLab.com")
- if fogbugz_import_enabled?
%div
- = link_to new_import_fogbugz_path(namespace_id: namespace_id), class: 'gl-button btn-default btn import_fogbugz js-import-project-btn', data: { platform: 'fogbugz', **tracking_attrs_data(track_label, 'click_button', 'fogbugz') } do
- .gl-button-icon
- = sprite_icon('bug')
+ = render Pajamas::ButtonComponent.new(href: new_import_fogbugz_path(namespace_id: namespace_id), icon: 'bug', button_options: { class: 'import_fogbugz js-import-project-btn', data: { platform: 'fogbugz', **tracking_attrs_data(track_label, 'click_button', 'fogbugz') } }) do
FogBugz
- if gitea_import_enabled?
@@ -60,24 +47,20 @@
- if git_import_enabled?
%div
- %button.gl-button.btn-default.btn.btn-svg.js-toggle-button.js-import-git-toggle-button.js-import-project-btn{ type: "button", data: { platform: 'repo_url', toggle_open_class: 'active', **tracking_attrs_data(track_label, 'click_button', 'repo_url') } }
- .gl-button-icon
- = sprite_icon('link', css_class: 'gl-icon')
+ = render Pajamas::ButtonComponent.new(icon: 'link', button_options: { class: 'js-toggle-button js-import-git-toggle-button js-import-project-btn', data: { platform: 'repo_url', toggle_open_class: 'active', **tracking_attrs_data(track_label, 'click_button', 'repo_url') } }) do
= _('Repository by URL')
- if manifest_import_enabled?
%div
- = link_to new_import_manifest_path(namespace_id: namespace_id), class: 'gl-button btn-default btn import_manifest js-import-project-btn', data: { platform: 'manifest_file', **tracking_attrs_data(track_label, 'click_button', 'manifest_file') } do
- .gl-button-icon
- = sprite_icon('doc-text')
- Manifest file
+ = render Pajamas::ButtonComponent.new(href: new_import_manifest_path(namespace_id: namespace_id), icon: 'doc-text', button_options: { class: 'import_manifest js-import-project-btn', data: { platform: 'manifest_file', **tracking_attrs_data(track_label, 'click_button', 'manifest_file') } }) do
+ = _('Manifest file')
- if phabricator_import_enabled?
%div
- = link_to new_import_phabricator_path(namespace_id: namespace_id), class: 'gl-button btn-default btn import_phabricator js-import-project-btn', data: { platform: 'phabricator', track_label: "#{track_label}", track_action: "click_button", track_property: "phabricator" } do
- .gl-button-icon
- = custom_icon('issues')
- = _("Phabricator Tasks")
+ = render Pajamas::ButtonComponent.new(href: new_import_phabricator_path(namespace_id: namespace_id), icon: 'issues', button_options: { class: 'import_phabricator js-import-project-btn', data: { platform: 'phabricator', track_label: "#{track_label}", track_action: "click_button", track_property: "phabricator" } }) do
+ = _('Phabricator tasks')
+
+ = render_if_exists "projects/gitee_import_button", namespace_id: namespace_id, track_label: track_label
.js-toggle-content.toggle-import-form{ class: ('hide' if active_tab != 'import') }
diff --git a/app/views/projects/_last_push.html.haml b/app/views/projects/_last_push.html.haml
index 859f065377d..5b493772f0a 100644
--- a/app/views/projects/_last_push.html.haml
+++ b/app/views/projects/_last_push.html.haml
@@ -16,5 +16,5 @@
- if create_mr_button_from_event?(event)
= c.actions do
- = render Pajamas::ButtonComponent.new(variant: :confirm, href: create_mr_path_from_push_event(event), button_options: { class: 'qa-create-merge-request' }) do
+ = render Pajamas::ButtonComponent.new(variant: :confirm, href: create_mr_path_from_push_event(event), button_options: { data: { qa_selector: 'create_merge_request_button' }}) do
= _('Create merge request')
diff --git a/app/views/projects/_merge_request_merge_checks_settings.html.haml b/app/views/projects/_merge_request_merge_checks_settings.html.haml
index 3345b3043b8..8c12399fdbb 100644
--- a/app/views/projects/_merge_request_merge_checks_settings.html.haml
+++ b/app/views/projects/_merge_request_merge_checks_settings.html.haml
@@ -12,6 +12,7 @@
s_('ProjectSettings|Skipped pipelines are considered successful'),
help_text: s_('ProjectSettings|Introduces the risk of merging changes that do not pass the pipeline.'),
checkbox_options: { class: 'gl-pl-6' }
+ = render_if_exists 'projects/merge_request_merge_checks_status_checks', form: form, project: @project
= form.gitlab_ui_checkbox_component :only_allow_merge_if_all_discussions_are_resolved,
s_('ProjectSettings|All threads must be resolved'),
checkbox_options: { data: { qa_selector: 'allow_merge_if_all_discussions_are_resolved_checkbox' } }
diff --git a/app/views/projects/_transfer.html.haml b/app/views/projects/_transfer.html.haml
index e3aa2d8afc9..93fc8d12960 100644
--- a/app/views/projects/_transfer.html.haml
+++ b/app/views/projects/_transfer.html.haml
@@ -3,7 +3,7 @@
- hidden_input_id = "new_namespace_id"
- initial_data = { button_text: s_('ProjectSettings|Transfer project'), confirm_danger_message: transfer_project_message(@project), phrase: @project.name, target_form_id: form_id, target_hidden_input_id: hidden_input_id, project_id: @project.id }
-.sub-section
+.sub-section{ data: { qa_selector: 'transfer_project_content' } }
%h4.danger-title= _('Transfer project')
= form_for @project, url: transfer_project_path(@project), method: :put, html: { class: 'js-project-transfer-form', id: form_id } do |f|
.form-group
@@ -20,5 +20,4 @@
%li= _('You will need to update your local repositories to point to the new location.')
%li= _('Project visibility level will be changed to match namespace rules when transferring to a group.')
= hidden_field_tag(hidden_input_id)
- = label_tag :new_namespace_id, _('Select a new namespace'), class: 'gl-font-weight-bold'
.js-transfer-project-form{ data: initial_data }
diff --git a/app/views/projects/_visibility_modal.html.haml b/app/views/projects/_visibility_modal.html.haml
deleted file mode 100644
index e8a4e091dcf..00000000000
--- a/app/views/projects/_visibility_modal.html.haml
+++ /dev/null
@@ -1,29 +0,0 @@
-- strong_start = "<strong>".html_safe
-- strong_end = "</strong>".html_safe
-
-.modal.js-confirm-project-visiblity{ tabindex: -1 }
- .modal-dialog
- .modal-content
- .modal-header
- %h1.page-title.gl-font-size-h-display= _('Reduce this project’s visibility?')
- %button.close{ type: "button", "data-dismiss": "modal", "aria-label" => _('Close') }
- %span{ "aria-hidden": "true" }= sprite_icon("close")
- .modal-body
- %p
- - if @project.group
- = _("You're about to reduce the visibility of the project %{strong_start}%{project_name}%{strong_end} in %{strong_start}%{group_name}%{strong_end}.").html_safe % { project_name: @project.name, group_name: @project.group.name, strong_start: strong_start, strong_end: strong_end }
- - else
- = _("You're about to reduce the visibility of the project %{strong_start}%{project_name}%{strong_end}.").html_safe % { project_name: @project.name, strong_start: strong_start, strong_end: strong_end }
- %p
- = _('Once you confirm and press "Reduce project visibility":')
- %ul
- %li
- = _("Current forks will keep their visibility level.").html_safe
- %label{ for: "confirm_path_input" }
- = _("To confirm, type %{phrase_code}").html_safe % { phrase_code: '<code class="js-legacy-confirm-danger-match">%{phrase_name}</code>'.html_safe % { phrase_name: @project.full_path } }
- .form-group
- = text_field_tag 'confirm_path_input', '', class: 'form-control js-legacy-confirm-danger-input'
- .form-actions
- %button.btn.gl-button.btn-default.gl-mr-4{ type: "button", "data-dismiss": "modal" }
- = _('Cancel')
- = submit_tag _('Reduce project visibility'), class: "btn gl-button btn-danger js-legacy-confirm-danger-submit", disabled: true
diff --git a/app/views/projects/artifacts/_artifact.html.haml b/app/views/projects/artifacts/_artifact.html.haml
deleted file mode 100644
index 9e548582396..00000000000
--- a/app/views/projects/artifacts/_artifact.html.haml
+++ /dev/null
@@ -1,61 +0,0 @@
-.gl-responsive-table-row.px-md-3
- .table-section.section-25.section-wrap.commit
- .table-mobile-header{ role: 'rowheader' }= _('Job')
- .table-mobile-content
- .branch-commit.cgray
- - if can?(current_user, :read_build, @project)
- = link_to project_job_path(@project, artifact.job) do
- %span.build-link ##{artifact.job_id}
- - else
- %span.build-link ##{artifact.job_id}
-
- - if artifact.job.ref
- .icon-container.gl-display-inline-block{ "aria-label" => artifact.job.tag? ? _('Tag') : _('Branch') }
- = artifact.job.tag? ? sprite_icon('tag', css_class: 'sprite') : sprite_icon('branch', css_class: 'sprite')
- = link_to artifact.job.ref, project_ref_path(@project, artifact.job.ref), class: 'ref-name'
- - else
- .light= _('none')
- .icon-container.commit-icon{ "aria-label" => _('Commit') }
- = sprite_icon('commit')
-
- - if artifact.job.sha
- = link_to artifact.job.short_sha, project_commit_path(@project, artifact.job.sha), class: 'commit-sha mr-0'
-
- .table-section.section-15.section-wrap
- .table-mobile-header{ role: 'rowheader' }= _('Name')
- .table-mobile-content
- = artifact.job.name
-
- .table-section.section-20
- .table-mobile-header{ role: 'rowheader' }= _('Creation date')
- .table-mobile-content
- %p.finished-at
- = sprite_icon("calendar")
- %span= time_ago_with_tooltip(artifact.created_at)
-
- .table-section.section-20
- .table-mobile-header{ role: 'rowheader' }= _('Expiration date')
- .table-mobile-content
- - if artifact.expire_at
- %p.finished-at
- = sprite_icon("calendar")
- %span= time_ago_with_tooltip(artifact.expire_at)
-
- .table-section.section-10
- .table-mobile-header{ role: 'rowheader' }= _('Size')
- .table-mobile-content
- = number_to_human_size(artifact.size, precision: 2)
-
- .table-section.table-button-footer.section-10
- .table-action-buttons
- .btn-group
- - if can?(current_user, :read_build, @project)
- = link_to download_project_job_artifacts_path(@project, artifact.job), rel: 'nofollow', download: '', title: _('Download artifacts'), data: { placement: 'top', container: 'body' }, ref: 'tooltip', aria: { label: _('Download artifacts') }, class: 'gl-button btn btn-default btn-icon has-tooltip' do
- = sprite_icon('download', css_class: 'gl-icon')
-
- = link_to browse_project_job_artifacts_path(@project, artifact.job), rel: 'nofollow', title: _('Browse artifacts'), data: { placement: 'top', container: 'body' }, ref: 'tooltip', aria: { label: _('Browse artifacts') }, class: 'gl-button btn btn-default btn-icon has-tooltip' do
- = sprite_icon('folder-open', css_class: 'gl-icon')
-
- - if can?(current_user, :destroy_artifacts, @project)
- = link_to project_artifact_path(@project, artifact), data: { placement: 'top', container: 'body', confirm: _('Are you sure you want to delete these artifacts?'), confirm_btn_variant: "danger" }, method: :delete, title: _('Delete artifacts'), ref: 'tooltip', aria: { label: _('Delete artifacts') }, class: 'gl-button btn btn-danger btn-icon has-tooltip' do
- = sprite_icon('remove', css_class: 'gl-icon')
diff --git a/app/views/projects/artifacts/_table.html.haml b/app/views/projects/artifacts/_table.html.haml
deleted file mode 100644
index 1963449d704..00000000000
--- a/app/views/projects/artifacts/_table.html.haml
+++ /dev/null
@@ -1,16 +0,0 @@
-- if artifacts.blank?
- .nothing-here-block= _('No jobs to show')
-- else
- .table-holder
- .ci-table
- .gl-responsive-table-row.table-row-header.px-md-3{ role: 'row' }
- .table-section.section-25{ role: 'rowheader' }= _('Job')
- .table-section.section-15{ role: 'rowheader' }= _('Name')
- .table-section.section-20{ role: 'rowheader' }= _('Creation date')
- .table-section.section-20{ role: 'rowheader' }= _('Expiration date')
- .table-section.section-10{ role: 'rowheader' }= _('Size')
- .table-section.section-10{ role: 'rowheader' }
-
- = render partial: 'artifact', collection: artifacts, as: :artifact
-
- = paginate artifacts, theme: "gitlab", total_pages: @total_pages
diff --git a/app/views/projects/artifacts/index.html.haml b/app/views/projects/artifacts/index.html.haml
index 1ab3e8e67d8..9cbc149177c 100644
--- a/app/views/projects/artifacts/index.html.haml
+++ b/app/views/projects/artifacts/index.html.haml
@@ -1,10 +1,9 @@
-- @no_container = true
- page_title _('Artifacts')
%div{ class: container_class }
- .top-area.py-3
- .align-self-center
- = _('Total artifacts size: %{total_size}') % { total_size: number_to_human_size(@total_size, precicion: 2) }
-
- .content-list.builds-content-list
- = render "table", artifacts: @artifacts, project: @project
+ %h1.page-title.gl-font-size-h-display.gl-mb-0
+ = s_('Artifacts|Artifacts')
+ .gl-mb-6
+ %strong= s_('Artifacts|Total artifacts size')
+ = number_to_human_size(@total_size, precicion: 2)
+ #js-artifact-management{ data: { "project-path" => @project.full_path } }
diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml
index 9fd542e0cfb..17d5ef69b76 100644
--- a/app/views/projects/blob/_blob.html.haml
+++ b/app/views/projects/blob/_blob.html.haml
@@ -13,7 +13,7 @@
#js-code-owners{ data: { blob_path: blob.path, project_path: @project.full_path, branch: @ref } }
= render "projects/blob/auxiliary_viewer", blob: blob
-#blob-content-holder.blob-content-holder
+#blob-content-holder.blob-content-holder.js-per-page{ data: { blame_per_page: Projects::BlameService::PER_PAGE } }
- if @code_navigation_path
#js-code-navigation{ data: { code_navigation_path: @code_navigation_path, blob_path: blob.path, definition_path_prefix: project_blob_path(@project, @ref) } }
- if !expanded
diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml
index bd08ab67cd3..a907e175443 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",
+ = text_field_tag 'file_name', params[:file_name], placeholder: "File name", 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?
@@ -38,7 +38,7 @@
.file-editor.code
- if Feature.enabled?(:source_editor_toolbar, current_user)
#editor-toolbar
- .js-edit-mode-pane.qa-editor#editor{ data: { 'editor-loading': true, qa_selector: 'source_editor_preview_container' } }<
+ .js-edit-mode-pane#editor{ data: { 'editor-loading': true, qa_selector: 'source_editor_preview_container' } }<
%pre.editor-loading-content= params[:content] || local_assigns[:blob_data]
- if local_assigns[:path]
.js-edit-mode-pane#preview.hide
diff --git a/app/views/projects/blob/viewers/_loading.html.haml b/app/views/projects/blob/viewers/_loading.html.haml
index 9cb934da7c0..d8efaf9ad95 100644
--- a/app/views/projects/blob/viewers/_loading.html.haml
+++ b/app/views/projects/blob/viewers/_loading.html.haml
@@ -1 +1 @@
-= gl_loading_icon(size: "md", css_class: "qa-spinner gl-my-4")
+= gl_loading_icon(size: "md", css_class: "gl-my-4", data: { qa_selector: 'spinner_placeholder' })
diff --git a/app/views/projects/branch_defaults/_branch_names_fields.html.haml b/app/views/projects/branch_defaults/_branch_names_fields.html.haml
new file mode 100644
index 00000000000..65f975fbd9e
--- /dev/null
+++ b/app/views/projects/branch_defaults/_branch_names_fields.html.haml
@@ -0,0 +1,14 @@
+- if @project.project_feature.issues_access_level > 0
+ %fieldset#branch-names-settings
+ .form-group
+ = f.label :issue_branch_template, _('Branch name template'), class: 'label-bold'
+ %p= s_('ProjectSettings|Branches created from issues follow this pattern.')
+
+ .form-group
+ .gl-mb-2
+ = f.text_field :issue_branch_template, class: 'form-control gl-mb-2', placeholder: "%{id}-%{title}"
+ %p.form-text.text-muted
+ = s_('ProjectSettings|Leave empty to use default template.')
+ = sprintf(s_('ProjectSettings|Maximum %{maxLength} characters.'), { maxLength: Issue::MAX_BRANCH_TEMPLATE })
+ - branch_name_help_link = help_page_path('user/project/repository/web_editor.md', anchor: 'create-a-new-branch-from-an-issue')
+ = link_to _('What variables can I use?'), branch_name_help_link, target: "_blank"
diff --git a/app/views/projects/branch_defaults/_default_branch_fields.html.haml b/app/views/projects/branch_defaults/_default_branch_fields.html.haml
new file mode 100644
index 00000000000..e4f51725f1a
--- /dev/null
+++ b/app/views/projects/branch_defaults/_default_branch_fields.html.haml
@@ -0,0 +1,16 @@
+%fieldset#default-branch-settings
+ - if @project.empty_repo?
+ .text-secondary
+ = s_('ProjectSettings|A default branch cannot be chosen for an empty project.')
+ - else
+ .form-group
+ = f.label :default_branch, _("Default branch"), class: 'label-bold'
+ %p= s_('ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one.')
+ .js-select-default-branch{ data: { default_branch: @project.default_branch, project_id: @project.id } }
+
+ .form-group
+ - help_text = _("When merge requests and commits in the default branch close, any issues they reference also close.")
+ - help_icon = link_to sprite_icon('question-o'), help_page_path('user/project/issues/managing_issues.md', anchor: 'closing-issues-automatically'), target: '_blank', rel: 'noopener noreferrer'
+ = f.gitlab_ui_checkbox_component :autoclose_referenced_issues,
+ s_('ProjectSettings|Auto-close referenced issues on default branch'),
+ help_text: (help_text + "&nbsp;" + help_icon).html_safe
diff --git a/app/views/projects/branch_defaults/_show.html.haml b/app/views/projects/branch_defaults/_show.html.haml
new file mode 100644
index 00000000000..4ecbc3b7fc8
--- /dev/null
+++ b/app/views/projects/branch_defaults/_show.html.haml
@@ -0,0 +1,17 @@
+- expanded = expanded_by_default?
+
+%section.settings.no-animate#branch-defaults-settings{ class: ('expanded' if expanded) }
+ .settings-header
+ %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Branch defaults')
+ = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
+ = expanded ? _('Collapse') : _('Expand')
+ %p
+ = s_('ProjectSettings|Select the default branch for this project, and configure the template for branch names.')
+
+ .settings-content
+ - url = namespace_project_settings_repository_path(@project.namespace, @project)
+ = gitlab_ui_form_for @project, url: url, method: :put, html: { multipart: true, class: "issue-settings-form js-issue-settings-form" }, authenticity_token: true do |f|
+ %input{ name: 'update_section', type: 'hidden', value: 'js-issue-settings' }
+ = render 'projects/branch_defaults/default_branch_fields', f: f
+ = render 'projects/branch_defaults/branch_names_fields', f: f
+ = f.submit _('Save changes'), pajamas_button: true, data: { qa_selector: 'save_changes_button' }
diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml
index 52b8d6bc66f..51c218f40b9 100644
--- a/app/views/projects/branches/_branch.html.haml
+++ b/app/views/projects/branches/_branch.html.haml
@@ -1,19 +1,19 @@
- merged = local_assigns.fetch(:merged, false)
- commit = @repository.commit(branch.dereferenced_target)
- merge_project = merge_request_source_project_for_project(@project)
-%li{ class: "branch-item gl-display-flex! gl-align-items-center! js-branch-item js-branch-#{branch.name}", data: { name: branch.name } }
+%li{ class: "branch-item gl-display-flex! gl-align-items-center! js-branch-item js-branch-#{branch.name}", data: { name: branch.name, qa_selector: 'branch_container', qa_name: branch.name } }
.branch-info
.gl-display-flex.gl-align-items-center
= sprite_icon('branch', size: 12, css_class: 'gl-flex-shrink-0')
- = link_to project_tree_path(@project, branch.name), class: 'item-title str-truncated-100 ref-name gl-ml-3 qa-branch-name' do
+ = link_to project_tree_path(@project, branch.name), class: 'item-title str-truncated-100 ref-name gl-ml-3', data: { qa_selector: 'branch_link' } do
= branch.name
= clipboard_button(text: branch.name, title: _("Copy branch name"))
- if branch.name == @repository.root_ref
- = gl_badge_tag s_('DefaultBranchLabel|default'), { variant: :info, size: :sm }, { class: 'gl-ml-2' }
+ = gl_badge_tag s_('DefaultBranchLabel|default'), { variant: :info, size: :sm }, { class: 'gl-ml-2', data: { qa_selector: 'badge_content' } }
- elsif merged
- = gl_badge_tag s_('Branches|merged'), { variant: :info, size: :sm }, { class: 'gl-ml-2', title: s_('Branches|Merged into %{default_branch}') % { default_branch: @repository.root_ref }, data: { toggle: 'tooltip', container: 'body' } }
+ = gl_badge_tag s_('Branches|merged'), { variant: :info, size: :sm }, { class: 'gl-ml-2', title: s_('Branches|Merged into %{default_branch}') % { default_branch: @repository.root_ref }, data: { toggle: 'tooltip', container: 'body', qa_selector: 'badge_content' } }
- if protected_branch?(@project, branch)
- = gl_badge_tag s_('Branches|protected'), { variant: :success, size: :sm }, { class: 'gl-ml-2' }
+ = gl_badge_tag s_('Branches|protected'), { variant: :success, size: :sm }, { class: 'gl-ml-2', data: { qa_selector: 'badge_content' } }
= render_if_exists 'projects/branches/diverged_from_upstream', branch: branch
@@ -46,4 +46,5 @@
= render 'projects/buttons/download', project: @project, ref: branch.name, pipeline: @refs_pipelines[branch.name], class: 'gl-vertical-align-top'
- = render 'projects/branches/delete_branch_modal_button', project: @project, branch: branch, merged: merged
+ - if can?(current_user, :push_code, @project)
+ = render 'projects/branches/delete_branch_modal_button', project: @project, branch: branch, merged: merged
diff --git a/app/views/projects/branches/_panel.html.haml b/app/views/projects/branches/_panel.html.haml
index 6ca5aaf061e..a1f93d21647 100644
--- a/app/views/projects/branches/_panel.html.haml
+++ b/app/views/projects/branches/_panel.html.haml
@@ -11,7 +11,7 @@
- c.header do
= panel_title
- c.body do
- %ul.content-list.all-branches.qa-all-branches
+ %ul.content-list.all-branches{ data: { qa_selector: 'all_branches_container' } }
- branches.first(overview_max_branches).each do |branch|
= render "projects/branches/branch", branch: branch, merged: project.repository.merged_to_root_ref?(branch), commit_status: @branch_pipeline_statuses[branch.name], show_commit_status: @branch_pipeline_statuses.any?
- if branches.size > overview_max_branches
diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml
index 295b2de9bd2..475bc9e1c20 100644
--- a/app/views/projects/branches/index.html.haml
+++ b/app/views/projects/branches/index.html.haml
@@ -1,3 +1,4 @@
+- add_page_specific_style 'page_bundles/branches'
- page_title _('Branches')
- add_to_breadcrumbs(_('Repository'), project_tree_path(@project))
@@ -6,21 +7,16 @@
= gl_tab_link_to s_('Branches|Overview'), project_branches_path(@project), { item_active: @mode == 'overview', title: s_('Branches|Show overview of the branches') }
= gl_tab_link_to s_('Branches|Active'), project_branches_filtered_path(@project, state: 'active'), { title: s_('Branches|Show active branches') }
= gl_tab_link_to s_('Branches|Stale'), project_branches_filtered_path(@project, state: 'stale'), { title: s_('Branches|Show stale branches') }
- = gl_tab_link_to s_('Branches|All'), project_branches_filtered_path(@project, state: 'all'), { item_active: !%w[overview active stale].include?(@mode), title: s_('Branches|Show all branches') }
+ = gl_tab_link_to s_('Branches|All'), project_branches_filtered_path(@project, state: 'all'), { item_active: %w[overview active stale].exclude?(@mode), title: s_('Branches|Show all branches') }
.nav-controls
#js-branches-sort-dropdown{ data: { project_branches_filtered_path: project_branches_path(@project, state: 'all'), sort_options: branches_sort_options_hash.to_json, mode: @mode } }
- if can? current_user, :push_code, @project
- = link_to project_merged_branches_path(@project),
- class: 'gl-button btn btn-danger btn-danger-secondary has-tooltip qa-delete-merged-branches',
- title: s_("Branches|Delete all branches that are merged into '%{default_branch}'") % { default_branch: @project.repository.root_ref },
- method: :delete,
- aria: { label: s_('Branches|Delete merged branches') },
- data: { confirm: s_('Branches|Deleting the merged branches cannot be undone. Are you sure?'),
- confirm_btn_variant: 'danger',
- container: 'body' } do
- = s_('Branches|Delete merged branches')
+ .js-delete-merged-branches{ data: {
+ default_branch: @project.repository.root_ref,
+ form_path: project_merged_branches_path(@project) }
+ }
= link_to new_project_branch_path(@project), class: 'gl-button btn btn-confirm' do
= s_('Branches|New branch')
diff --git a/app/views/projects/buttons/_download.html.haml b/app/views/projects/buttons/_download.html.haml
index 2d32e07d379..23dcb7f41e1 100644
--- a/app/views/projects/buttons/_download.html.haml
+++ b/app/views/projects/buttons/_download.html.haml
@@ -1,3 +1,5 @@
+- project = local_assigns.fetch(:project)
+- ref = local_assigns.fetch(:ref)
- pipeline = local_assigns.fetch(:pipeline) { project.latest_successful_pipeline_for(ref) }
- if !project.empty_repo? && can?(current_user, :download_code, project)
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index 23572d1d6ac..6e202063900 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -30,7 +30,7 @@
= preserve(markdown_field(@commit, :description))
.info-well.js-commit-box-info{ 'data-commit-path' => branches_project_commit_path(@project, @commit.id) }
- .well-segment.branch-info
+ .well-segment
.icon-container.commit-icon
= custom_icon("icon_commit")
%span.cgray= n_('parent', 'parents', @commit.parents.count)
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index bf6b628dd36..b5481f19352 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -34,8 +34,8 @@
&middot;
= commit.short_id
- if commit.description? && collapsible
- %button.gl-button.btn.btn-default.button-ellipsis-horizontal.btn-sm.gl-ml-2.text-expander.js-toggle-button{ data: { toggle: 'tooltip', container: 'body' }, :title => _("Toggle commit description"), aria: { label: _("Toggle commit description") } }
- = sprite_icon('ellipsis_h', size: 12)
+ = render Pajamas::ButtonComponent.new(icon: 'ellipsis_h',
+ button_options: { class: 'button-ellipsis-horizontal text-expander js-toggle-button', data: { toggle: 'tooltip', container: 'body' }, :title => _("Toggle commit description"), aria: { label: _("Toggle commit description") }})
.committer
- commit_author_link = commit_author_link(commit, avatar: false, size: 24)
diff --git a/app/views/projects/commits/_commits.html.haml b/app/views/projects/commits/_commits.html.haml
index bb3a38d6ac8..b5ecc9b0193 100644
--- a/app/views/projects/commits/_commits.html.haml
+++ b/app/views/projects/commits/_commits.html.haml
@@ -33,16 +33,15 @@
- else
= render partial: 'projects/commits/commit', collection: context_commits, locals: { project: project, ref: ref, merge_request: merge_request }
-- if hidden > 0
+- if hidden > 0 && !@merge_request
%li
= render Pajamas::AlertComponent.new(variant: :warning,
dismissible: false) do |c|
= c.body do
= n_('%s additional commit has been omitted to prevent performance issues.', '%s additional commits have been omitted to prevent performance issues.', hidden) % number_with_delimiter(hidden)
-- if can_update_merge_request && context_commits&.empty?
- = render Pajamas::ButtonComponent.new(button_options: { class: 'gl-mt-5 add-review-item-modal-trigger', data: { context_commits_empty: 'true' } }) do
- = _('Add previously merged commits')
+- if can_update_merge_request && context_commits&.empty? && !(defined?(@next_page) && @next_page)
+ .add-review-item-modal-trigger{ data: { context_commits_empty: 'true' } }
- if commits.size == 0 && context_commits.nil?
.commits-empty.gl-mt-6
diff --git a/app/views/projects/default_branch/_show.html.haml b/app/views/projects/default_branch/_show.html.haml
deleted file mode 100644
index 04712cd59f7..00000000000
--- a/app/views/projects/default_branch/_show.html.haml
+++ /dev/null
@@ -1,29 +0,0 @@
-- expanded = expanded_by_default?
-
-%section.settings.no-animate#default-branch-settings{ class: ('expanded' if expanded) }
- .settings-header
- %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Default branch')
- = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
- = expanded ? _('Collapse') : _('Expand')
- %p
- = _('Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one.')
-
- .settings-content
- = gitlab_ui_form_for @project, remote: true, html: { multipart: true, anchor: 'default-branch-settings' }, authenticity_token: true do |f|
- %fieldset
- - if @project.empty_repo?
- .text-secondary
- = _('A default branch cannot be chosen for an empty project.')
- - else
- .form-group
- = f.label :default_branch, _("Default branch"), class: 'label-bold'
- .js-select-default-branch{ data: { default_branch: @project.default_branch, project_id: @project.id } }
-
- .form-group
- - help_text = _("When merge requests and commits in the default branch close, any issues they reference also close.")
- - help_icon = link_to sprite_icon('question-o'), help_page_path('user/project/issues/managing_issues.md', anchor: 'closing-issues-automatically'), target: '_blank', rel: 'noopener noreferrer'
- = f.gitlab_ui_checkbox_component :autoclose_referenced_issues,
- _("Auto-close referenced issues on default branch"),
- help_text: (help_text + "&nbsp;" + help_icon).html_safe
-
- = f.submit _('Save changes'), data: { qa_selector: 'save_changes_button' }, pajamas_button: true
diff --git a/app/views/projects/deployments/_actions.haml b/app/views/projects/deployments/_actions.haml
index c0fe143020a..e1c8992a28c 100644
--- a/app/views/projects/deployments/_actions.haml
+++ b/app/views/projects/deployments/_actions.haml
@@ -1,4 +1,4 @@
-- if can?(current_user, :create_deployment, deployment)
+- if can?(current_user, :read_deployment, deployment)
- actions = deployment.manual_actions
- if actions.present?
.btn-group
@@ -8,7 +8,7 @@
= sprite_icon('chevron-down')
%ul.dropdown-menu.dropdown-menu-right
- actions.each do |action|
- - next unless can?(current_user, :update_build, action)
+ - next unless can?(current_user, :play_job, action)
%li
= link_to [:play, @project, action], method: :post, rel: 'nofollow' do
%span= action.name
diff --git a/app/views/projects/deployments/_rollback.haml b/app/views/projects/deployments/_rollback.haml
index 223f7520b47..e50fa1fa0f7 100644
--- a/app/views/projects/deployments/_rollback.haml
+++ b/app/views/projects/deployments/_rollback.haml
@@ -1,4 +1,4 @@
-- if deployment.deployable && can?(current_user, :create_deployment, deployment)
+- if deployment.deployable && can?(current_user, :play_job, deployment.deployable)
- tooltip = deployment.last? ? s_('Environments|Re-deploy to environment') : s_('Environments|Rollback environment')
- icon = deployment.last? ? 'repeat' : 'redo'
= render Pajamas::ButtonComponent.new(icon: icon, button_options: { title: tooltip, class: 'js-confirm-rollback-modal-button has-tooltip', data: { environment_name: @environment.name, commit_short_sha: deployment.short_sha, commit_url: project_commit_path(@project, deployment.sha), is_last_deployment: deployment.last?.to_s, retry_path: retry_project_job_path(@environment.project, deployment.deployable) } })
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index 6f2e135f9d3..43159a759f4 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -3,8 +3,6 @@
- escaped_default_branch_name = default_branch_name.shellescape
- @skip_current_level_breadcrumb = true
-= render_if_exists 'projects/free_user_cap_alert', project: @project
-
= render partial: 'flash_messages', locals: { project: @project }
= render 'clusters_deprecation_alert'
@@ -20,7 +18,7 @@
%p
= _('You can get started by cloning the repository or start adding files to it with one of the following options.')
-.project-buttons.qa-quick-actions
+.project-buttons{ data: { qa_selector: 'quick_actions_container' } }
.project-clone-holder.d-block.d-md-none.gl-mt-3.gl-mr-3
= render "shared/mobile_clone_panel"
diff --git a/app/views/projects/hooks/edit.html.haml b/app/views/projects/hooks/edit.html.haml
index ca71990f5e3..3e63faaf448 100644
--- a/app/views/projects/hooks/edit.html.haml
+++ b/app/views/projects/hooks/edit.html.haml
@@ -9,7 +9,7 @@
= render 'shared/web_hooks/title_and_docs', hook: @hook
.col-lg-9.gl-mb-3
- = gitlab_ui_form_for [@project, @hook], as: :hook, url: project_hook_path(@project, @hook) do |f|
+ = gitlab_ui_form_for [@project, @hook], as: :hook, url: project_hook_path(@project, @hook), html: { class: 'js-webhook-form' } do |f|
= render partial: 'shared/web_hooks/form', locals: { form: f, hook: @hook }
= f.submit _('Save changes'), pajamas_button: true
diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml
index 0476193c2cb..15cb7869dc5 100644
--- a/app/views/projects/hooks/index.html.haml
+++ b/app/views/projects/hooks/index.html.haml
@@ -7,8 +7,8 @@
= render 'shared/web_hooks/title_and_docs', hook: @hook
.col-lg-8.gl-mb-3
- = gitlab_ui_form_for @hook, as: :hook, url: polymorphic_path([@project, :hooks]) do |f|
+ = gitlab_ui_form_for @hook, as: :hook, url: polymorphic_path([@project, :hooks]), html: { class: 'js-webhook-form' } do |f|
= render partial: 'shared/web_hooks/form', locals: { form: f, hook: @hook }
- = f.submit 'Add webhook', pajamas_button: true
+ = f.submit _('Add webhook'), pajamas_button: true, data: { qa_selector: "create_webhook_button" }
= render 'shared/web_hooks/index', hooks: @hooks, hook_class: @hook.class
diff --git a/app/views/projects/incidents/show.html.haml b/app/views/projects/incidents/show.html.haml
index 7a1e7f503f8..6d733dc46df 100644
--- a/app/views/projects/incidents/show.html.haml
+++ b/app/views/projects/incidents/show.html.haml
@@ -2,6 +2,7 @@
- add_to_breadcrumbs _("Incidents"), project_incidents_path(@project)
- breadcrumb_title @issue.to_reference
- page_title "#{@issue.title} (#{@issue.to_reference})", _("Incidents")
+- add_page_specific_style 'page_bundles/design_management'
- add_page_specific_style 'page_bundles/incidents'
- add_page_specific_style 'page_bundles/issues_show'
diff --git a/app/views/projects/issues/_related_issues.html.haml b/app/views/projects/issues/_related_issues.html.haml
index 1c252958525..80f2b8b189c 100644
--- a/app/views/projects/issues/_related_issues.html.haml
+++ b/app/views/projects/issues/_related_issues.html.haml
@@ -4,4 +4,5 @@
full_path: @project.full_path,
has_issue_weights_feature: @project.licensed_feature_available?(:issue_weights).to_s,
help_path: help_page_path('user/project/issues/related_issues'),
- show_categorized_issues: @project.licensed_feature_available?(:blocked_issues).to_s } }
+ show_categorized_issues: @project.licensed_feature_available?(:blocked_issues).to_s,
+ has_iterations_feature: @project.licensed_feature_available?(:iterations).to_s } }
diff --git a/app/views/projects/issues/_work_item_links.html.haml b/app/views/projects/issues/_work_item_links.html.haml
index c0de711136a..72f9ec2ff16 100644
--- a/app/views/projects/issues/_work_item_links.html.haml
+++ b/app/views/projects/issues/_work_item_links.html.haml
@@ -1,2 +1 @@
-- if Feature.enabled?(:work_items_hierarchy, @project)
- .js-work-item-links-root{ data: { issuable_id: @issue.id, iid: @issue.iid, project_namespace: @project.namespace.path, project_path: @project.full_path, wi: work_items_index_data(@project) } }
+.js-work-item-links-root{ data: { issuable_id: @issue.id, iid: @issue.iid, project_path: @project.full_path, wi: work_items_index_data(@project) } }
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 76b725d140c..a8edf87b696 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -2,6 +2,7 @@
- add_to_breadcrumbs _("Issues"), project_issues_path(@project)
- breadcrumb_title @issue.to_reference
- page_title "#{@issue.title} (#{@issue.to_reference})", _("Issues")
+- add_page_specific_style 'page_bundles/design_management'
- add_page_specific_style 'page_bundles/incidents'
- add_page_specific_style 'page_bundles/issues_show'
- add_page_specific_style 'page_bundles/work_items'
diff --git a/app/views/projects/merge_requests/_awards_block.html.haml b/app/views/projects/merge_requests/_awards_block.html.haml
index 820927fdd1a..c1952793e72 100644
--- a/app/views/projects/merge_requests/_awards_block.html.haml
+++ b/app/views/projects/merge_requests/_awards_block.html.haml
@@ -1,2 +1,2 @@
-.content-block.emoji-block.emoji-list-container.js-noteable-awards
+.emoji-block.emoji-list-container.js-noteable-awards
= render 'award_emoji/awards_block', awardable: @merge_request, inline: true, api_awards_path: award_emoji_merge_request_api_path(@merge_request)
diff --git a/app/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml b/app/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml
index 478db70877d..78fce3f7087 100644
--- a/app/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml
+++ b/app/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml
@@ -1,7 +1,7 @@
- display_issuable_type = issuable_display_type(@merge_request)
-.float-left.btn-group.gl-md-ml-3.gl-display-flex.dropdown.gl-new-dropdown.gl-md-w-auto.gl-w-full
- = button_tag type: 'button', class: "btn dropdown-toggle btn-default btn-md gl-button gl-dropdown-toggle btn-default-tertiary dropdown-icon-only dropdown-toggle-no-caret has-tooltip gl-display-none! gl-md-display-inline-flex!", data: { toggle: 'dropdown', title: _('Merge request actions'), testid: 'merge-request-actions' } do
+.btn-group.gl-md-ml-3.gl-display-flex.dropdown.gl-new-dropdown.gl-md-w-auto.gl-w-full
+ = button_tag type: 'button', class: "btn dropdown-toggle btn-default btn-md gl-button gl-dropdown-toggle btn-default-tertiary dropdown-icon-only dropdown-toggle-no-caret has-tooltip gl-display-none! gl-md-display-inline-flex!", data: { toggle: 'dropdown', title: _('Merge request actions'), testid: 'merge-request-actions', 'aria-label': _('Merge request actions') } do
= sprite_icon "ellipsis_v", size: 16, css_class: "dropdown-icon gl-icon"
= button_tag type: 'button', class: "btn dropdown-toggle btn-default btn-md btn-block gl-button gl-dropdown-toggle gl-md-display-none!", data: { 'toggle' => 'dropdown' } do
%span.gl-new-dropdown-button-text= _('Merge request actions')
@@ -11,7 +11,7 @@
.gl-new-dropdown-contents
%ul
- if current_user && moved_mr_sidebar_enabled?
- %li.gl-new-dropdown-item.js-sidebar-subscriptions-entry-point
+ %li.gl-new-dropdown-item.js-sidebar-subscriptions-widget-root
%li.gl-new-dropdown-divider
%hr.dropdown-divider
- if can?(current_user, :update_merge_request, @merge_request)
@@ -36,7 +36,7 @@
= _('Reopen')
= display_issuable_type
- if moved_mr_sidebar_enabled?
- %li.gl-new-dropdown-item#js-lock-entry-point
+ %li.gl-new-dropdown-item.js-sidebar-lock-root
%li.gl-new-dropdown-item
%button.dropdown-item.js-copy-reference{ type: "button", data: { 'clipboard-text': @merge_request.to_reference(full: true) } }
.gl-new-dropdown-item-text-wrapper
diff --git a/app/views/projects/merge_requests/_code_dropdown.html.haml b/app/views/projects/merge_requests/_code_dropdown.html.haml
index bb42c3067d9..5c7fe56095c 100644
--- a/app/views/projects/merge_requests/_code_dropdown.html.haml
+++ b/app/views/projects/merge_requests/_code_dropdown.html.haml
@@ -1,4 +1,4 @@
-.float-left.gl-md-ml-3.dropdown.gl-new-dropdown{ class: "gl-display-none! gl-md-display-flex!" }
+.gl-md-ml-3.dropdown.gl-new-dropdown{ class: "gl-display-none! gl-md-display-flex!" }
#js-check-out-modal{ data: how_merge_modal_data(@merge_request) }
= button_tag type: 'button', class: "btn dropdown-toggle btn-confirm gl-button gl-dropdown-toggle", data: { toggle: 'dropdown', qa_selector: 'mr_code_dropdown' } do
%span.gl-new-dropdown-button-text= _('Code')
@@ -16,12 +16,12 @@
= _('Check out branch')
- if current_user
%li.gl-new-dropdown-item
- = link_to ide_merge_request_path(@merge_request), class: 'dropdown-item', data: { qa_selector: 'open_in_web_ide_button' } do
+ = link_to ide_merge_request_path(@merge_request), class: 'dropdown-item', target: '_blank', data: { qa_selector: 'open_in_web_ide_button' } do
.gl-new-dropdown-item-text-wrapper
= _('Open in Web IDE')
- if Gitlab::CurrentSettings.gitpod_enabled && current_user&.gitpod_enabled
%li.gl-new-dropdown-item
- = link_to "#{Gitlab::CurrentSettings.gitpod_url}##{merge_request_url(@merge_request)}", class: 'dropdown-item' do
+ = link_to "#{Gitlab::CurrentSettings.gitpod_url}##{merge_request_url(@merge_request)}", target: '_blank', class: 'dropdown-item' do
.gl-new-dropdown-item-text-wrapper
= _('Open in Gitpod')
%li.gl-new-dropdown-divider
diff --git a/app/views/projects/merge_requests/_commits.html.haml b/app/views/projects/merge_requests/_commits.html.haml
index 7cadc37b0fd..ee0ab984d6f 100644
--- a/app/views/projects/merge_requests/_commits.html.haml
+++ b/app/views/projects/merge_requests/_commits.html.haml
@@ -13,6 +13,9 @@
- else
%ol#commits-list.list-unstyled
= render "projects/commits/commits", merge_request: @merge_request
+ - if @next_page && @merge_request
+ = render Pajamas::ButtonComponent.new(button_options: { class: 'js-load-more-commits', data: { next_page: @next_page } }) do
+ = _('Load more')
-- if can_update_merge_request && @merge_request.iid
+- if can_update_merge_request && @merge_request.iid && !@next_page
.add-review-item-modal-wrapper{ data: { context_commits_path: context_commits_project_json_merge_request_url(@merge_request&.project, @merge_request, :json), target_branch: @merge_request.target_branch, merge_request_iid: @merge_request.iid, project_id: @merge_request.project.id } }
diff --git a/app/views/projects/merge_requests/_mr_box.html.haml b/app/views/projects/merge_requests/_mr_box.html.haml
index 4fc405c63ff..901a2ebfd1e 100644
--- a/app/views/projects/merge_requests/_mr_box.html.haml
+++ b/app/views/projects/merge_requests/_mr_box.html.haml
@@ -1,3 +1,3 @@
-.detail-page-description.py-2{ class: "#{'is-merge-request' if moved_mr_sidebar_enabled? && !fluid_layout}" }
+.detail-page-description.py-2.gl-display-flex.gl-align-items-center.gl-flex-wrap{ class: "#{'is-merge-request' if moved_mr_sidebar_enabled? && !fluid_layout}" }
= render 'shared/issuable/status_box', issuable: @merge_request
= merge_request_header(@project, @merge_request)
diff --git a/app/views/projects/merge_requests/_mr_title.html.haml b/app/views/projects/merge_requests/_mr_title.html.haml
index 893f03157db..a73d2aa5cc4 100644
--- a/app/views/projects/merge_requests/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/_mr_title.html.haml
@@ -25,9 +25,9 @@
- display_class = moved_mr_sidebar_enabled? ? 'gl-md-display-none!' : 'gl-sm-display-none!'
= render Pajamas::ButtonComponent.new(icon: "chevron-double-lg-left", button_options: { class: "btn-icon float-right gl-display-block gutter-toggle issuable-gutter-toggle js-sidebar-toggle #{display_class}" })
- .detail-page-header-actions.gl-align-self-start.is-merge-request.js-issuable-actions
+ .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 btn-grouped js-issuable-edit", data: { qa_selector: "edit_button" }
+ = 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" }
- if @merge_request.source_project
= render 'projects/merge_requests/code_dropdown'
diff --git a/app/views/projects/merge_requests/creations/_new_submit.html.haml b/app/views/projects/merge_requests/creations/_new_submit.html.haml
index ef3174efcc7..1246c45a529 100644
--- a/app/views/projects/merge_requests/creations/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/creations/_new_submit.html.haml
@@ -14,7 +14,7 @@
- if @commits.empty?
.commits-empty
%h4
- There are no commits yet.
+ = _("There are no commits yet.")
= custom_icon ('illustration_no_commits')
- else
.merge-request-tabs-holder{ class: ("js-tabs-affix" unless ENV['RAILS_ENV'] == 'test') }
@@ -25,16 +25,16 @@
%ul.merge-request-tabs.nav.nav-tabs.nav-links.no-top.no-bottom.gl-display-flex.gl-flex-nowrap.gl-m-0.gl-p-0.js-tabs-affix
%li.commits-tab.new-tab
= link_to url_for(safe_params), data: {target: 'div#commits', action: 'new', toggle: 'tabvue'} do
- Commits
+ = _("Commits")
= gl_badge_tag @total_commit_count, { size: :sm }, { class: 'gl-tab-counter-badge' }
- if @pipelines.any?
%li.builds-tab
= link_to url_for(safe_params.merge(action: 'pipelines')), data: {target: 'div#pipelines', action: 'pipelines', toggle: 'tabvue'} do
- Pipelines
+ = _("Pipelines")
= gl_badge_tag @pipelines.size, { size: :sm }, { class: 'gl-tab-counter-badge' }
%li.diffs-tab
= link_to url_for(safe_params.merge(action: 'diffs')), data: {target: 'div#diffs', action: 'diffs', toggle: 'tabvue', qa_selector: 'diffs_tab'} do
- Changes
+ = _("Changes")
= gl_badge_tag @merge_request.diff_size, { size: :sm }, { class: 'gl-tab-counter-badge' }
#diff-notes-app.tab-content
diff --git a/app/views/projects/merge_requests/dropdowns/_branch.html.haml b/app/views/projects/merge_requests/dropdowns/_branch.html.haml
index a60c445aa51..d6af8b2f5a5 100644
--- a/app/views/projects/merge_requests/dropdowns/_branch.html.haml
+++ b/app/views/projects/merge_requests/dropdowns/_branch.html.haml
@@ -1,5 +1,5 @@
%ul
- branches.each do |branch|
%li
- %a{ href: '#', class: "#{('is-active' if selected == branch)}", title: branch, data: { id: branch } }
+ %a{ href: '#', class: "#{'is-active' if selected == branch}", title: branch, data: { id: branch } }
= branch
diff --git a/app/views/projects/merge_requests/dropdowns/_project.html.haml b/app/views/projects/merge_requests/dropdowns/_project.html.haml
index b3cf3c1d369..41c0b0ab55b 100644
--- a/app/views/projects/merge_requests/dropdowns/_project.html.haml
+++ b/app/views/projects/merge_requests/dropdowns/_project.html.haml
@@ -1,5 +1,5 @@
%ul
- projects.each do |project|
%li
- %a{ href: "#", class: "#{('is-active' if selected == project.id)}", data: { id: project.id, 'refs-url': refs_project_path(project) } }
+ %a{ href: "#", class: "#{'is-active' if selected == project.id}", data: { id: project.id, 'refs-url': refs_project_path(project) } }
= project.full_path
diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml
index d77d5231a7d..203724fc1f1 100644
--- a/app/views/projects/merge_requests/show.html.haml
+++ b/app/views/projects/merge_requests/show.html.haml
@@ -8,12 +8,15 @@
- page_card_attributes @merge_request.card_attributes
- suggest_changes_help_path = help_page_path('user/project/merge_requests/reviews/suggestions.md')
- mr_action = j(params[:tab].presence || 'show')
+- add_page_specific_style 'page_bundles/design_management'
- add_page_specific_style 'page_bundles/merge_requests'
- add_page_specific_style 'page_bundles/pipelines'
- add_page_specific_style 'page_bundles/reports'
- add_page_specific_style 'page_bundles/ci_status'
- add_page_startup_api_call @endpoint_metadata_url
+- if mr_action == 'diffs'
+ - add_page_startup_api_call @endpoint_diff_batch_url
.merge-request{ data: { mr_action: mr_action, url: merge_request_path(@merge_request, format: :json), project_path: project_path(@merge_request.project), lock_version: @merge_request.lock_version } }
- if moved_mr_sidebar_enabled?
@@ -47,7 +50,7 @@
#js-vue-discussion-counter{ data: { blocks_merge: @project.only_allow_merge_if_all_discussions_are_resolved?.to_s } }
- if moved_mr_sidebar_enabled?
- if !!@issuable_sidebar.dig(:current_user, :id)
- .js-issuable-todo{ data: { project_path: @issuable_sidebar[:project_full_path], iid: @issuable_sidebar[:iid], id: @issuable_sidebar[:id] } }
+ .js-sidebar-todo-widget-root{ data: { project_path: @issuable_sidebar[:project_full_path], iid: @issuable_sidebar[:iid], id: @issuable_sidebar[:id] } }
.gl-ml-auto.gl-align-items-center.gl-display-none.gl-md-display-flex.gl-ml-3.js-expand-sidebar{ class: "gl-lg-display-none!" }
= render Pajamas::ButtonComponent.new(icon: 'chevron-double-lg-left',
button_options: { class: 'js-sidebar-toggle' }) do
diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml
index fb7c1130f5c..cdb8a63bca9 100644
--- a/app/views/projects/milestones/_form.html.haml
+++ b/app/views/projects/milestones/_form.html.haml
@@ -25,8 +25,8 @@
.form-actions
- if @milestone.new_record?
- = f.submit _('Create milestone'), class: 'gl-button btn-confirm btn', data: { qa_selector: 'create_milestone_button' }
+ = 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'), class: 'gl-button btn-confirm btn'
+ = f.submit _('Save changes'), 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/_authentication_method.html.haml b/app/views/projects/mirrors/_authentication_method.html.haml
index 4b549aaf1cd..54e1f1a8b20 100644
--- a/app/views/projects/mirrors/_authentication_method.html.haml
+++ b/app/views/projects/mirrors/_authentication_method.html.haml
@@ -5,10 +5,10 @@
= f.label :auth_method, _('Authentication method'), class: 'label-bold'
= f.select :auth_method,
options_for_select(auth_options, mirror.auth_method),
- {}, { class: "custom-select gl-form-select js-mirror-auth-type qa-authentication-method" }
+ {}, { class: "custom-select gl-form-select js-mirror-auth-type", data: { qa_selector: 'authentication_method_field' } }
= f.hidden_field :auth_method, value: "password", class: "js-hidden-mirror-auth-type"
.form-group
.well-password-auth.collapse.js-well-password-auth
= f.label :password, _("Password"), class: "label-bold"
- = f.password_field :password, class: 'form-control gl-form-input qa-password js-mirror-password-field', autocomplete: 'off'
+ = f.password_field :password, class: 'form-control gl-form-input js-mirror-password-field', autocomplete: 'off', data: { qa_selector: 'password_field' }
diff --git a/app/views/projects/mirrors/_disabled_mirror_badge.html.haml b/app/views/projects/mirrors/_disabled_mirror_badge.html.haml
index 86e54acecc4..1834627c705 100644
--- a/app/views/projects/mirrors/_disabled_mirror_badge.html.haml
+++ b/app/views/projects/mirrors/_disabled_mirror_badge.html.haml
@@ -1,2 +1,2 @@
-%span.qa-disabled-mirror-badge.rspec-disabled-mirror-badge{ data: { toggle: 'tooltip', html: 'true' }, title: _('Disabled mirrors can only be enabled by instance owners. It is recommended that you delete them.') }
+%span.rspec-disabled-mirror-badge{ data: { toggle: 'tooltip', html: 'true' }, title: _('Disabled mirrors can only be enabled by instance owners. It is recommended that you delete them.') }
= gl_badge_tag _('Disabled'), variant: :warning
diff --git a/app/views/projects/mirrors/_mirror_repos.html.haml b/app/views/projects/mirrors/_mirror_repos.html.haml
index c98f88fa31e..f4e57450aa1 100644
--- a/app/views/projects/mirrors/_mirror_repos.html.haml
+++ b/app/views/projects/mirrors/_mirror_repos.html.haml
@@ -21,7 +21,7 @@
.form-group.has-feedback
= label_tag :url, _('Git repository URL'), class: 'label-light'
- = text_field_tag :url, nil, class: 'form-control gl-form-input js-mirror-url js-repo-url qa-mirror-repository-url-input', placeholder: _('Input the remote repository URL'), required: true, pattern: "(#{protocols}):\/\/.+", autocomplete: 'new-password'
+ = text_field_tag :url, nil, class: 'form-control gl-form-input js-mirror-url js-repo-url', placeholder: _('Input the remote repository URL'), required: true, pattern: "(#{protocols}):\/\/.+", autocomplete: 'new-password', data: { qa_selector: 'mirror_repository_url_field' }
= render 'projects/mirrors/instructions'
@@ -35,7 +35,7 @@
= link_to _('Learn more.'), help_page_path('user/project/repository/mirror/index.md', anchor: 'mirror-only-protected-branches'), target: '_blank', rel: 'noopener noreferrer'
.panel-footer
- = f.submit _('Mirror repository'), class: 'js-mirror-submit qa-mirror-repository-button', name: :update_remote_mirror, pajamas_button: true
+ = f.submit _('Mirror repository'), class: 'js-mirror-submit', name: :update_remote_mirror, pajamas_button: true, data: { qa_selector: 'mirror_repository_button' }
- else
= render Pajamas::AlertComponent.new(dismissible: false) do |c|
= c.body do
diff --git a/app/views/projects/mirrors/_mirror_repos_form.html.haml b/app/views/projects/mirrors/_mirror_repos_form.html.haml
index 34b7c75debf..1322e677d5a 100644
--- a/app/views/projects/mirrors/_mirror_repos_form.html.haml
+++ b/app/views/projects/mirrors/_mirror_repos_form.html.haml
@@ -1,7 +1,7 @@
.form-group
= label_tag :mirror_direction, _('Mirror direction'), class: 'label-light'
.select-wrapper
- = select_tag :mirror_direction, options_for_select([[_('Push'), 'push']]), class: 'form-control gl-form-select select-control js-mirror-direction qa-mirror-direction', disabled: true
+ = select_tag :mirror_direction, options_for_select([[_('Push'), 'push']]), class: 'form-control gl-form-select select-control js-mirror-direction', disabled: true, data: { qa_selector: 'mirror_direction_field' }
= sprite_icon('chevron-down', css_class: "gl-icon gl-absolute gl-top-3 gl-right-3 gl-text-gray-200")
= render partial: "projects/mirrors/mirror_repos_push", locals: { f: f }
diff --git a/app/views/projects/mirrors/_mirror_repos_list.html.haml b/app/views/projects/mirrors/_mirror_repos_list.html.haml
index 2dbcbd659c8..fb8133e6de8 100644
--- a/app/views/projects/mirrors/_mirror_repos_list.html.haml
+++ b/app/views/projects/mirrors/_mirror_repos_list.html.haml
@@ -25,17 +25,17 @@
= render_if_exists 'projects/mirrors/table_pull_row'
- @project.remote_mirrors.each_with_index do |mirror, index|
- next if mirror.new_record?
- %tr.rspec-mirrored-repository-row{ class: ('bg-secondary' if mirror.disabled?), data: { qa_selector: 'mirrored_repository_row' } }
- %td{ data: { qa_selector: 'mirror_repository_url_cell' } }= mirror.safe_url || _('Invalid URL')
+ %tr.rspec-mirrored-repository-row{ class: ('bg-secondary' if mirror.disabled?), data: { qa_selector: 'mirrored_repository_row_container' } }
+ %td{ data: { qa_selector: 'mirror_repository_url_content' } }= mirror.safe_url || _('Invalid URL')
%td= _('Push')
%td
= mirror.last_update_started_at.present? ? time_ago_with_tooltip(mirror.last_update_started_at) : _('Never')
- %td{ data: { qa_selector: 'mirror_last_update_at_cell' } }= mirror.last_update_at.present? ? time_ago_with_tooltip(mirror.last_update_at) : _('Never')
+ %td{ data: { qa_selector: 'mirror_last_update_at_content' } }= mirror.last_update_at.present? ? time_ago_with_tooltip(mirror.last_update_at) : _('Never')
%td
- if mirror.disabled?
= render 'projects/mirrors/disabled_mirror_badge'
- if mirror.last_error.present?
- = gl_badge_tag _('Error'), { variant: :danger }, { data: { toggle: 'tooltip', html: 'true', qa_selector: 'mirror_error_badge' }, title: html_escape(mirror.last_error.try(:strip)) }
+ = gl_badge_tag _('Error'), { variant: :danger }, { data: { toggle: 'tooltip', html: 'true', qa_selector: 'mirror_error_badge_content' }, title: html_escape(mirror.last_error.try(:strip)) }
%td.gl-display-flex
- if mirror_settings_enabled
.btn-group.mirror-actions-group{ role: 'group' }
@@ -44,4 +44,4 @@
= render 'shared/remote_mirror_update_button', remote_mirror: mirror
= render Pajamas::ButtonComponent.new(variant: :danger,
icon: 'remove',
- button_options: { class: 'js-delete-mirror qa-delete-mirror rspec-delete-mirror', title: _('Remove'), data: { mirror_id: mirror.id, toggle: 'tooltip', container: 'body' } })
+ button_options: { class: 'js-delete-mirror rspec-delete-mirror', title: _('Remove'), data: { mirror_id: mirror.id, toggle: 'tooltip', container: 'body' } })
diff --git a/app/views/projects/ml/experiments/_experiment.html.haml b/app/views/projects/ml/experiments/_experiment.html.haml
new file mode 100644
index 00000000000..42823f47469
--- /dev/null
+++ b/app/views/projects/ml/experiments/_experiment.html.haml
@@ -0,0 +1,3 @@
+%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
new file mode 100644
index 00000000000..a25e814b2b5
--- /dev/null
+++ b/app/views/projects/ml/experiments/_experiment_list.html.haml
@@ -0,0 +1,7 @@
+- 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
new file mode 100644
index 00000000000..e34f3fd2d2f
--- /dev/null
+++ b/app/views/projects/ml/experiments/_incubation_banner.html.haml
@@ -0,0 +1,8 @@
+= 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/index.html.haml b/app/views/projects/ml/experiments/index.html.haml
new file mode 100644
index 00000000000..a84cb15d940
--- /dev/null
+++ b/app/views/projects/ml/experiments/index.html.haml
@@ -0,0 +1,11 @@
+- breadcrumb_title _('ML Experiments')
+- page_title _('ML Experiments')
+
+.page-title-holder.d-flex.align-items-center
+ %h1.page-title.gl-font-size-h-display= _('Machine Learning Experiments')
+
+= render "incubation_banner"
+
+%div{ class: container_class }
+ .content-list.builds-content-list
+ = render "experiment_list", experiments: @experiments, project: @project
diff --git a/app/views/projects/ml/experiments/show.html.haml b/app/views/projects/ml/experiments/show.html.haml
new file mode 100644
index 00000000000..2c350439762
--- /dev/null
+++ b/app/views/projects/ml/experiments/show.html.haml
@@ -0,0 +1,14 @@
+- add_to_breadcrumbs _("Experiments"), project_ml_experiments_path(@project)
+- breadcrumb_title @experiment.name
+- page_title @experiment.name
+- items = candidates_table_items(@candidates)
+- metrics = unique_logged_names(@candidates, &:latest_metrics)
+- params = unique_logged_names(@candidates, &:params)
+
+.page-title-holder.d-flex.align-items-center
+ %h1.page-title.gl-font-size-h-display= @experiment.name
+
+#js-show-ml-experiment{ data: {
+ candidates: items,
+ metrics: metrics,
+ params: params } }
diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml
index b6700c9ed1e..2a3171e9fd8 100644
--- a/app/views/projects/network/show.html.haml
+++ b/app/views/projects/network/show.html.haml
@@ -6,8 +6,7 @@
.controls.gl-bg-gray-50.gl-p-2.gl-font-base.gl-text-gray-400.gl-border-b-1.gl-border-b-solid.gl-border-b-gray-300
= form_tag project_network_path(@project, @id), method: :get, class: 'form-inline network-form' do |f|
= text_field_tag :extended_sha1, @options[:extended_sha1], placeholder: _("Git revision"), class: 'search-input form-control gl-form-input input-mx-250 search-sha gl-mr-2'
- = button_tag class: 'btn gl-button btn-confirm btn-icon' do
- = sprite_icon('search')
+ = render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, icon: 'search')
.inline.gl-ml-5
.form-check.light
= check_box_tag :filter_ref, 1, @options[:filter_ref], class: 'form-check-input'
diff --git a/app/views/projects/no_repo.html.haml b/app/views/projects/no_repo.html.haml
index a8a30d73000..e3f46d601a3 100644
--- a/app/views/projects/no_repo.html.haml
+++ b/app/views/projects/no_repo.html.haml
@@ -1,8 +1,6 @@
- page_title _('No repository')
- @skip_current_level_breadcrumb = true
-= render_if_exists 'projects/free_user_cap_alert', project: @project
-
%h2.gl-display-flex
.gl-display-flex.gl-align-items-center.gl-justify-content-center
= sprite_icon('warning-solid', size: 24, css_class: 'gl-mr-2')
diff --git a/app/views/projects/notes/_actions.html.haml b/app/views/projects/notes/_actions.html.haml
index 9a8b83649de..6b875ff904c 100644
--- a/app/views/projects/notes/_actions.html.haml
+++ b/app/views/projects/notes/_actions.html.haml
@@ -9,14 +9,16 @@
- if can?(current_user, :award_emoji, note)
- if note.emoji_awardable?
.note-actions-item
- = button_tag title: 'Add reaction', class: "note-action-button note-emoji-button js-add-award js-note-emoji has-tooltip btn gl-button btn-icon btn-default-tertiary", data: { position: 'right', container: 'body' } do
+ = render Pajamas::ButtonComponent.new(category: :tertiary,
+ button_options: { title: _('Add reaction'), class: 'btn-icon note-action-button note-emoji-button js-add-award js-note-emoji has-tooltip', data: { position: 'right', container: 'body' }, 'aria-label': _('Add reaction') }) do
= sprite_icon('slight-smile', css_class: 'award-control-icon-neutral gl-button-icon gl-icon')
= sprite_icon('smiley', css_class: 'award-control-icon-positive gl-button-icon gl-icon gl-left-3!')
= sprite_icon('smile', css_class: 'award-control-icon-super-positive gl-button-icon gl-icon gl-left-3! ')
- if note_editable
.note-actions-item.gl-ml-0
- = button_tag title: 'Edit comment', class: 'note-action-button js-note-edit has-tooltip btn gl-button btn-default-tertiary btn-icon', data: { container: 'body', qa_selector: 'edit_comment_button' } do
- = sprite_icon('pencil', css_class: 'gl-button-icon gl-icon')
+ = render Pajamas::ButtonComponent.new(category: :tertiary,
+ icon: 'pencil',
+ button_options: { class: 'note-action-button js-note-edit has-tooltip', data: { container: 'body', qa_selector: 'edit_comment_button' }, title: _('Edit comment'), 'aria-label': _('Edit comment') })
= render 'projects/notes/more_actions_dropdown', note: note, note_editable: note_editable
diff --git a/app/views/projects/pipeline_schedules/_form.html.haml b/app/views/projects/pipeline_schedules/_form.html.haml
index ab692d1830a..235b89b8c5b 100644
--- a/app/views/projects/pipeline_schedules/_form.html.haml
+++ b/app/views/projects/pipeline_schedules/_form.html.haml
@@ -9,10 +9,10 @@
= f.label :cron, _('Interval Pattern'), class: 'label-bold'
#interval-pattern-input{ data: { initial_interval: @schedule.cron, daily_limit: @schedule.daily_limit } }
.form-group.row
- .col-md-9
- = f.label :cron_timezone, _('Cron Timezone'), class: 'label-bold'
- = dropdown_tag(_("Select a timezone"), options: { toggle_class: 'gl-button btn btn-default js-timezone-dropdown w-100', dropdown_class: 'w-100', title: _("Select a timezone"), filter: true, placeholder: s_("OfSearchInADropdown|Filter"), data: { data: timezone_data } } )
- = f.text_field :cron_timezone, value: @schedule.cron_timezone, id: 'schedule_cron_timezone', class: 'hidden', name: 'schedule[cron_timezone]', required: true
+ .col-md-9{ data: { testid: 'schedule-timezone' } }
+ = f.label :cron_timezone, _("Cron Timezone")
+ .js-timezone-dropdown{ data: { timezone_data: timezone_data.to_json, initial_value: @schedule.cron_timezone, name: 'schedule[cron_timezone]' } }
+
.form-group.row
.col-md-9
= f.label :ref, _('Target branch or tag'), class: 'label-bold'
diff --git a/app/views/projects/pipelines/_info.html.haml b/app/views/projects/pipelines/_info.html.haml
index 2e403358e2e..30cc7f94311 100644
--- a/app/views/projects/pipelines/_info.html.haml
+++ b/app/views/projects/pipelines/_info.html.haml
@@ -1,9 +1,13 @@
-.commit-box
- %h3.commit-title
- = markdown(commit.title, pipeline: :single_line)
- - if commit.description.present?
- %pre.commit-description<
- = preserve(markdown(commit.description, pipeline: :single_line))
+- if Feature.enabled?(:pipeline_name, @pipeline.project) && @pipeline.name
+ %h3
+ = @pipeline.name
+- else
+ .commit-box
+ %h3.commit-title
+ = markdown(commit.title, pipeline: :single_line)
+ - if commit.description.present?
+ %pre.commit-description<
+ = preserve(markdown(commit.description, pipeline: :single_line))
.info-well
.well-segment.pipeline-info{ class: "gl-align-items-baseline!" }
@@ -19,7 +23,7 @@
= s_("Pipelines|(queued for %{queued_duration})") % { queued_duration: time_interval_in_words(@pipeline.queued_duration)}
- if has_pipeline_badges?(@pipeline)
- .well-segment.qa-pipeline-badges
+ .well-segment
.icon-container
= sprite_icon('flag', css_class: 'gl-top-0!')
- if @pipeline.schedule?
@@ -45,11 +49,16 @@
- if @pipeline.stuck?
= gl_badge_tag s_('Pipelines|stuck'), { variant: :warning, size: :sm }, { class: 'js-pipeline-url-stuck has-tooltip' }
- .well-segment.branch-info
+ .well-segment{ 'data-testid': 'commit-row' }
.icon-container.commit-icon
= sprite_icon('commit', css_class: 'gl-top-0!')
- = link_to commit.short_id, project_commit_path(@project, @pipeline.sha), class: "commit-sha"
- = clipboard_button(text: @pipeline.sha, title: _("Copy commit SHA"))
+ - if Feature.enabled?(:pipeline_name, @pipeline.project) && @pipeline.name
+ = markdown(commit.title, pipeline: :single_line)
+ = clipboard_button(text: @pipeline.sha, title: _("Copy commit SHA"))
+ = link_to commit.short_id, project_commit_path(@project, @pipeline.sha), class: "commit-sha"
+ - else
+ = link_to commit.short_id, project_commit_path(@project, @pipeline.sha), class: "commit-sha"
+ = clipboard_button(text: @pipeline.sha, title: _("Copy commit SHA"))
.well-segment.related-merge-request-info
.icon-container
diff --git a/app/views/projects/pipelines/show.html.haml b/app/views/projects/pipelines/show.html.haml
index c9eb2e92193..4531bb2d0a9 100644
--- a/app/views/projects/pipelines/show.html.haml
+++ b/app/views/projects/pipelines/show.html.haml
@@ -30,4 +30,4 @@
#js-pipeline-tabs{ data: js_pipeline_tabs_data(@project, @pipeline, @current_user) }
- else
= render "projects/pipelines/with_tabs", pipeline: @pipeline, stages: @stages, pipeline_has_errors: pipeline_has_errors
-.js-pipeline-details-vue{ data: { metrics_path: namespace_project_ci_prometheus_metrics_histograms_path(namespace_id: @project.namespace, project_id: @project, format: :json), pipeline_project_path: @project.full_path, pipeline_iid: @pipeline.iid, graphql_resource_etag: graphql_etag_pipeline_path(@pipeline) } }
+.js-pipeline-details-vue{ data: { metrics_path: namespace_project_ci_prometheus_metrics_histograms_path(namespace_id: @project.namespace, project_id: @project, format: :json), pipeline_project_path: @project.full_path, pipeline_iid: @pipeline.iid, graphql_resource_etag: graphql_etag_pipeline_path(@pipeline), pipeline_path: pipeline_path(@pipeline) } }
diff --git a/app/views/projects/product_analytics/_graph.html.haml b/app/views/projects/product_analytics/_graph.html.haml
deleted file mode 100644
index fd81a248005..00000000000
--- a/app/views/projects/product_analytics/_graph.html.haml
+++ /dev/null
@@ -1,6 +0,0 @@
-- graph = local_assigns.fetch(:graph)
-
-%h3
- = graph[:id]
-
-.js-project-analytics-chart{ "data-chart-data": graph.to_json, "data-chart-id": graph[:id] }
diff --git a/app/views/projects/product_analytics/_links.html.haml b/app/views/projects/product_analytics/_links.html.haml
deleted file mode 100644
index 6e5667e2644..00000000000
--- a/app/views/projects/product_analytics/_links.html.haml
+++ /dev/null
@@ -1,5 +0,0 @@
-= gl_tabs_nav({ class: 'mb-3'}) do
- = gl_tab_link_to _('Events'), project_product_analytics_path(@project)
- = gl_tab_link_to _('Graphs'), graphs_project_product_analytics_path(@project)
- = gl_tab_link_to _('Test'), test_project_product_analytics_path(@project)
- = gl_tab_link_to _('Setup'), setup_project_product_analytics_path(@project)
diff --git a/app/views/projects/product_analytics/_tracker.html.erb b/app/views/projects/product_analytics/_tracker.html.erb
deleted file mode 100644
index dbb96f19e22..00000000000
--- a/app/views/projects/product_analytics/_tracker.html.erb
+++ /dev/null
@@ -1,10 +0,0 @@
-;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
-p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
-};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
-n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","<%= product_analytics_tracker_url -%>","snowplow<%= @random -%>"));
-snowplow<%= @random -%>("newTracker", "sp", "<%= product_analytics_tracker_collector_url -%>", {
- appId: "<%= @project_id -%>",
- platform: "<%= @platform -%>",
- eventMethod: "get"
-});
-snowplow<%= @random -%>('trackPageView');
diff --git a/app/views/projects/product_analytics/graphs.html.haml b/app/views/projects/product_analytics/graphs.html.haml
deleted file mode 100644
index c345561e6ce..00000000000
--- a/app/views/projects/product_analytics/graphs.html.haml
+++ /dev/null
@@ -1,16 +0,0 @@
-- page_title _('Product Analytics')
-
-= render 'links'
-
-%p
- = _('Showing graphs based on events of the last %{timerange} days.') % { timerange: @timerange }
-
-
-.gl-mb-3
- = render 'graph', graph: @activity_graph
-
-- @graphs.each_slice(2) do |pair|
- .row.append-bottom-10
- - pair.each do |graph|
- .col-md-6{ id: graph[:id] }
- = render 'graph', graph: graph
diff --git a/app/views/projects/product_analytics/index.html.haml b/app/views/projects/product_analytics/index.html.haml
deleted file mode 100644
index 386f9265179..00000000000
--- a/app/views/projects/product_analytics/index.html.haml
+++ /dev/null
@@ -1,16 +0,0 @@
-- page_title _('Product Analytics')
-
-= render 'links'
-
-- if @events.any?
- %p
- - if @events.total_count > @events.size
- = _('Number of events for this project: %{total_count}.') % { total_count: number_with_delimiter(@events.total_count) }
- %ol
- - @events.each do |event|
- %li
- %code= event.as_json_wo_empty
-- else
- .empty-state
- .text-content
- = _('There are currently no events.')
diff --git a/app/views/projects/product_analytics/setup.html.haml b/app/views/projects/product_analytics/setup.html.haml
deleted file mode 100644
index e1819c7d74b..00000000000
--- a/app/views/projects/product_analytics/setup.html.haml
+++ /dev/null
@@ -1,12 +0,0 @@
-- page_title _('Product Analytics')
-
-= render 'links'
-
-%p
- = _('Copy the code below to implement tracking in your application:')
-
-%pre
- = render "tracker"
-
-%p.hint
- = _('A platform value can be web, mob or app.')
diff --git a/app/views/projects/product_analytics/test.html.haml b/app/views/projects/product_analytics/test.html.haml
deleted file mode 100644
index 3204cd5fbbe..00000000000
--- a/app/views/projects/product_analytics/test.html.haml
+++ /dev/null
@@ -1,17 +0,0 @@
-- page_title _('Product Analytics')
-
-= render 'links'
-
-%p
- = _('This page sends a payload. Go back to the events page to see a newly created event.')
-
-- if @event
- %p
- = _('Last item before this page loaded in your browser:')
-
- %code
- = @event.as_json_wo_empty
-
--# haml-lint:disable InlineJavaScript
-:javascript
- #{render 'tracker'}
diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml
index 34305d15eff..c7818602f52 100644
--- a/app/views/projects/project_members/index.html.haml
+++ b/app/views/projects/project_members/index.html.haml
@@ -1,7 +1,6 @@
- add_page_specific_style 'page_bundles/members'
- page_title _("Members")
-= render_if_exists 'projects/free_user_cap_alert', project: @project
= render_if_exists 'shared/ultimate_feature_removal_banner', project: @project
.row.gl-mt-3
diff --git a/app/views/projects/protected_branches/shared/_dropdown.html.haml b/app/views/projects/protected_branches/shared/_dropdown.html.haml
index d5111bd8be5..c5dbf8991cd 100644
--- a/app/views/projects/protected_branches/shared/_dropdown.html.haml
+++ b/app/views/projects/protected_branches/shared/_dropdown.html.haml
@@ -3,14 +3,16 @@
= f.hidden_field(:name)
= dropdown_tag(_('Select branch or create wildcard'),
- options: { toggle_class: "js-protected-branch-select js-filter-submit wide monospace qa-protected-branch-select #{toggle_classes}",
+ options: { toggle_class: "js-protected-branch-select js-filter-submit wide monospace #{toggle_classes}",
filter: true,
- dropdown_class: "dropdown-menu-selectable git-revision-dropdown qa-protected-branch-dropdown",
+ dropdown_class: "dropdown-menu-selectable git-revision-dropdown",
+ dropdown_qa_selector: "protected_branch_dropdown_content",
placeholder: _("Search protected branches"),
footer_content: true,
data: { show_no: true, show_any: true, show_upcoming: true,
selected: params[:protected_branch_name],
- project_id: @project.try(:id) } }) do
+ project_id: @project.try(:id),
+ qa_selector: "protected_branch_dropdown" } }) do
%ul.dropdown-footer-list
%li
diff --git a/app/views/projects/protected_branches/shared/_index.html.haml b/app/views/projects/protected_branches/shared/_index.html.haml
index 1d60791eae2..c204508d355 100644
--- a/app/views/projects/protected_branches/shared/_index.html.haml
+++ b/app/views/projects/protected_branches/shared/_index.html.haml
@@ -4,7 +4,7 @@
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= s_("ProtectedBranch|Protected branches")
- = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle qa-expand-protected-branches' }) do
+ = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
= expanded ? _('Collapse') : _('Expand')
%p
= s_("ProtectedBranch|Keep stable branches secure and force developers to use merge requests.")
diff --git a/app/views/projects/protected_tags/shared/_dropdown.html.haml b/app/views/projects/protected_tags/shared/_dropdown.html.haml
index 9c7f532fa29..9d5d649bc40 100644
--- a/app/views/projects/protected_tags/shared/_dropdown.html.haml
+++ b/app/views/projects/protected_tags/shared/_dropdown.html.haml
@@ -1,8 +1,8 @@
= f.hidden_field(:name)
-= dropdown_tag('Select tag or create wildcard',
+= dropdown_tag(s_('ProtectedBranch|Select tag or create wildcard'),
options: { toggle_class: 'js-protected-tag-select js-filter-submit wide monospace',
- filter: true, dropdown_class: "dropdown-menu-selectable capitalize-header git-revision-dropdown", placeholder: "Search protected tags",
+ filter: true, dropdown_class: "dropdown-menu-selectable capitalize-header git-revision-dropdown", placeholder: s_("ProtectedBranch|Search protected tags"),
footer_content: true,
data: { show_no: true, show_any: true, show_upcoming: true,
selected: params[:protected_tag_name],
@@ -10,6 +10,6 @@
%ul.dropdown-footer-list
%li
- %button{ class: "dropdown-create-new-item-button js-dropdown-create-new-item", title: "New Protected Tag" }
- Create wildcard
+ %button{ class: "dropdown-create-new-item-button js-dropdown-create-new-item", title: s_("ProtectedBranch|New Protected Tag") }
+ = s_('ProtectedBranch|Create wildcard')
%code
diff --git a/app/views/projects/protected_tags/shared/_tags_list.html.haml b/app/views/projects/protected_tags/shared/_tags_list.html.haml
index 5f3ea281278..0a85a353e27 100644
--- a/app/views/projects/protected_tags/shared/_tags_list.html.haml
+++ b/app/views/projects/protected_tags/shared/_tags_list.html.haml
@@ -1,9 +1,9 @@
.protected-tags-list.js-protected-tags-list
- if @protected_tags.empty?
.card-header
- Protected tags (0)
+ = s_('ProtectedBranch|Protected tags (%{tags_count})') % { tags_count: 0 }
%p.settings-message.text-center
- No tags are protected.
+ = s_('ProtectedBranch|No tags are protected.')
- else
- can_admin_project = can?(current_user, :admin_project, @project)
@@ -16,9 +16,12 @@
%col
%thead
%tr
- %th Protected tags (#{@protected_tags_count})
- %th Last commit
- %th Allowed to create
+ %th
+ = s_('ProtectedBranch|Protected tags (%{tags_count})') % { tags_count: @protected_tags_count }
+ %th
+ = s_('ProtectedBranch|Last commit')
+ %th
+ = s_('ProtectedBranch|Allowed to create')
- if can_admin_project
%th
%tbody
diff --git a/app/views/projects/settings/_archive.html.haml b/app/views/projects/settings/_archive.html.haml
index 2f97a068b49..70e14eadaf9 100644
--- a/app/views/projects/settings/_archive.html.haml
+++ b/app/views/projects/settings/_archive.html.haml
@@ -1,6 +1,6 @@
- return unless can?(current_user, :archive_project, @project)
-.sub-section{ data: { qa_selector: 'archive_project_content' } }
+.sub-section
%h4.warning-title
- if @project.archived?
= _('Unarchive project')
diff --git a/app/views/projects/settings/access_tokens/index.html.haml b/app/views/projects/settings/access_tokens/index.html.haml
index 9f598ffb2d1..f6c5c4e2950 100644
--- a/app/views/projects/settings/access_tokens/index.html.haml
+++ b/app/views/projects/settings/access_tokens/index.html.haml
@@ -40,5 +40,5 @@
description_prefix: :project_access_token,
help_path: help_page_path('user/project/settings/project_access_tokens', anchor: 'scopes-for-a-project-access-token')
- #js-access-token-table-app{ data: { access_token_type: type, access_token_type_plural: type_plural, initial_active_access_tokens: @active_resource_access_tokens.to_json, no_active_tokens_message: _('This project has no active access tokens.'), show_role: true
+ #js-access-token-table-app{ data: { access_token_type: type, access_token_type_plural: type_plural, initial_active_access_tokens: @active_access_tokens.to_json, no_active_tokens_message: _('This project has no active access tokens.'), show_role: true
} }
diff --git a/app/views/projects/settings/branch_rules/index.html.haml b/app/views/projects/settings/branch_rules/index.html.haml
index a7e80101a88..571a992a552 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') } }
+#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') } }
diff --git a/app/views/projects/settings/ci_cd/_form.html.haml b/app/views/projects/settings/ci_cd/_form.html.haml
index 51d28411b30..68dc7f2be8d 100644
--- a/app/views/projects/settings/ci_cd/_form.html.haml
+++ b/app/views/projects/settings/ci_cd/_form.html.haml
@@ -1,6 +1,6 @@
- help_link_public_pipelines = link_to sprite_icon('question-o'), help_page_path('ci/pipelines/settings', anchor: 'change-which-users-can-view-your-pipelines'), target: '_blank', rel: 'noopener noreferrer'
- help_link_auto_canceling = link_to sprite_icon('question-o'), help_page_path('ci/pipelines/settings', anchor: 'auto-cancel-redundant-pipelines'), target: '_blank', rel: 'noopener noreferrer'
-- help_link_skip_outdated = link_to sprite_icon('question-o'), help_page_path('ci/pipelines/settings', anchor: 'skip-outdated-deployment-jobs'), target: '_blank', rel: 'noopener noreferrer'
+- help_link_skip_outdated = link_to sprite_icon('question-o'), help_page_path('ci/pipelines/settings', anchor: 'prevent-outdated-deployment-jobs'), target: '_blank', rel: 'noopener noreferrer'
- help_link_separated_caches = link_to sprite_icon('question-o'), help_page_path('ci/caching/index', anchor: 'cache-key-names'), target: '_blank', rel: 'noopener noreferrer'
.row.gl-mt-3
@@ -22,8 +22,8 @@
.form-group
= f.fields_for :ci_cd_settings_attributes, @project.ci_cd_settings do |form|
- = form.gitlab_ui_checkbox_component :forward_deployment_enabled, _("Skip outdated deployment jobs"),
- help_text: (_('When a deployment job is successful, skip older deployment jobs that are still pending.') + ' ' + help_link_skip_outdated).html_safe
+ = form.gitlab_ui_checkbox_component :forward_deployment_enabled, _("Prevent outdated deployment jobs"),
+ help_text: (_('When a deployment job is successful, prevent older deployment jobs that are still pending.') + ' ' + help_link_skip_outdated).html_safe
.form-group
= f.gitlab_ui_checkbox_component :ci_separated_caches,
diff --git a/app/views/projects/settings/ci_cd/show.html.haml b/app/views/projects/settings/ci_cd/show.html.haml
index c4f589f3f91..1b35de85145 100644
--- a/app/views/projects/settings/ci_cd/show.html.haml
+++ b/app/views/projects/settings/ci_cd/show.html.haml
@@ -57,7 +57,7 @@
.settings-content
#js-artifacts-settings-app{ data: { full_path: @project.full_path, help_page_path: help_page_path('ci/pipelines/job_artifacts', anchor: 'keep-artifacts-from-most-recent-successful-jobs') } }
-%section.qa-variables-settings.settings.no-animate#js-cicd-variables-settings{ class: ('expanded' if expanded), data: { qa_selector: 'variables_settings_content' } }
+%section.settings.no-animate#js-cicd-variables-settings{ class: ('expanded' if expanded), data: { qa_selector: 'variables_settings_content' } }
.settings-header
= render 'ci/variables/header', expanded: expanded
.settings-content
diff --git a/app/views/projects/settings/repository/show.html.haml b/app/views/projects/settings/repository/show.html.haml
index 500cfdcb62b..306ce47cee7 100644
--- a/app/views/projects/settings/repository/show.html.haml
+++ b/app/views/projects/settings/repository/show.html.haml
@@ -3,7 +3,7 @@
- @content_class = "limit-container-width" unless fluid_layout
- deploy_token_description = s_('DeployTokens|Deploy tokens allow access to packages, your repository, and registry images.')
-= render "projects/default_branch/show"
+= render "projects/branch_defaults/show"
- if Feature.enabled?(:branch_rules, @project)
= render "projects/branch_rules/show"
= render_if_exists "projects/push_rules/index"
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index c7ac28fa194..77c44b792ab 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -7,7 +7,6 @@
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, project_path(@project, rss_url_options), title: "#{@project.name} activity")
-= render_if_exists 'projects/free_user_cap_alert', project: @project
= render_if_exists 'shared/ultimate_feature_removal_banner', project: @project
= render partial: 'flash_messages', locals: { project: @project }
= render 'clusters_deprecation_alert'
diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml
index ddebc19be15..58e86ebffa0 100644
--- a/app/views/projects/snippets/show.html.haml
+++ b/app/views/projects/snippets/show.html.haml
@@ -3,9 +3,9 @@
- breadcrumb_title @snippet.to_reference
- page_title "#{@snippet.title} (#{@snippet.to_reference})", _("Snippets")
-#js-snippet-view{ data: {'qa-selector': 'snippet_view', 'snippet-gid': @snippet.to_global_id, 'report-abuse-path': snippet_report_abuse_path(@snippet), 'can-report-spam': @snippet.submittable_as_spam_by?(current_user).to_s } }
+#js-snippet-view{ data: { 'snippet-gid': @snippet.to_global_id, 'report-abuse-path': snippet_report_abuse_path(@snippet), 'can-report-spam': @snippet.submittable_as_spam_by?(current_user).to_s } }
-.row-content-block.top-block.content-component-block.gl-px-0.gl-py-2
+.gl-px-0.gl-py-2
= render 'award_emoji/awards_block', awardable: @snippet, inline: true, api_awards_path: project_snippets_award_api_path(@snippet)
#notes.limited-width-notes= render "shared/notes/notes_with_form", :autocomplete => true
diff --git a/app/views/projects/triggers/_form.html.haml b/app/views/projects/triggers/_form.html.haml
index 9043b8e60fc..b6b24a0c26a 100644
--- a/app/views/projects/triggers/_form.html.haml
+++ b/app/views/projects/triggers/_form.html.haml
@@ -1,4 +1,4 @@
-= form_for [@project, @trigger], html: { class: 'gl-show-field-errors' } do |f|
+= gitlab_ui_form_for [@project, @trigger], html: { class: 'gl-show-field-errors' } do |f|
= form_errors(@trigger)
- if @trigger.token
@@ -8,4 +8,4 @@
.form-group
= f.label :key, "Description", class: "label-bold"
= f.text_field :description, class: 'form-control gl-form-input', required: true, title: 'Trigger description is required.', placeholder: "Trigger description"
- = f.submit btn_text, class: "gl-button btn btn-confirm"
+ = f.submit btn_text, pajamas_button: true
diff --git a/app/views/registrations/welcome/show.html.haml b/app/views/registrations/welcome/show.html.haml
index fe455f4a0bc..283659875ef 100644
--- a/app/views/registrations/welcome/show.html.haml
+++ b/app/views/registrations/welcome/show.html.haml
@@ -7,7 +7,6 @@
= render "layouts/one_trust"
= render "layouts/bizible"
= render "layouts/google_tag_manager_body"
-
.row.gl-flex-grow-1
.d-flex.gl-flex-direction-column.gl-align-items-center.gl-w-full.gl-px-5.gl-pb-5
.edit-profile.login-page.d-flex.flex-column.gl-align-items-center
diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml
index 54aa9aad8a5..c15afd7bd5b 100644
--- a/app/views/search/_category.html.haml
+++ b/app/views/search/_category.html.haml
@@ -5,7 +5,7 @@
.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller
.fade-left= sprite_icon('chevron-lg-left', size: 12)
.fade-right= sprite_icon('chevron-lg-right', size: 12)
- = gl_tabs_nav({ class: 'search-filter scrolling-tabs nav-links'}) do
+ = gl_tabs_nav({ class: 'scrolling-tabs nav-links', data: { testid: 'search-filter' } }) do
- if @project
- if project_search_tabs?(:blobs)
= search_filter_link 'blobs', _("Code"), data: { qa_selector: 'code_tab' }
diff --git a/app/views/search/_results.html.haml b/app/views/search/_results.html.haml
index 8262c3c90e1..027ae6bf77c 100644
--- a/app/views/search/_results.html.haml
+++ b/app/views/search/_results.html.haml
@@ -1,13 +1,12 @@
- search_bar_classes = 'search-sidebar gl-display-flex gl-flex-direction-column gl-mr-4'
= render_if_exists 'shared/promotions/promote_advanced_search'
-- if Feature.enabled?(:search_page_vertical_nav, current_user) && %w[issues merge_requests].include?(@scope)
+- if Feature.enabled?(:search_page_vertical_nav, current_user)
.results.gl-md-display-flex.gl-mt-0
#js-search-sidebar{ class: search_bar_classes, data: { navigation: search_navigation_json } }
.gl-w-full.gl-flex-grow-1.gl-overflow-x-hidden
= render partial: 'search/results_status', locals: { search_service: @search_service } unless @search_objects.to_a.empty?
= render partial: 'search/results_list'
-
- else
= render partial: 'search/results_status', locals: { search_service: @search_service } unless @search_objects.to_a.empty?
diff --git a/app/views/search/_results_status.html.haml b/app/views/search/_results_status.html.haml
index e6bb0c18b90..adea6b598f7 100644
--- a/app/views/search/_results_status.html.haml
+++ b/app/views/search/_results_status.html.haml
@@ -3,7 +3,6 @@
- return unless search_service.show_results_status?
- if Feature.enabled?(:search_page_vertical_nav, current_user)
- = render partial: 'search/results_status_vert_nav', locals: { search_service: @search_service }
-
+ = render partial: 'search/results_status_vert_nav', locals: { search_service: search_service }
- else
- = render partial: 'search/results_status_horiz_nav', locals: { search_service: @search_service }
+ = render partial: 'search/results_status_horiz_nav', locals: { search_service: search_service }
diff --git a/app/views/search/results/_blob_highlight.html.haml b/app/views/search/results/_blob_highlight.html.haml
index 7ba114496af..37ffabad717 100644
--- a/app/views/search/results/_blob_highlight.html.haml
+++ b/app/views/search/results/_blob_highlight.html.haml
@@ -4,7 +4,8 @@
#search-blob-content.file-content.code.js-syntax-highlight{ class: 'gl-py-3!' }
- if blob.present?
.blob-content{ data: { blob_id: blob.id, path: blob.path, highlight_line: highlight, qa_selector: 'file_content' } }
- - blob.present.highlight.lines.each_with_index do |line, index|
+ - blob_highlight = blob.present.highlight_and_trim(trim_length: 1024, ellipsis_svg: sprite_icon('ellipsis_h', size: 12, css_class: "gl-text-gray-700"))
+ - blob_highlight.lines.each_with_index do |line, index|
- i = index + offset
.line_holder.code-search-line.gl-display-flex
.line-numbers
diff --git a/app/views/shared/_file_picker_button.html.haml b/app/views/shared/_file_picker_button.html.haml
index 1d688e7f4b0..8d76e9c1b7d 100644
--- a/app/views/shared/_file_picker_button.html.haml
+++ b/app/views/shared/_file_picker_button.html.haml
@@ -1,7 +1,8 @@
- classes = local_assigns.fetch(:classes, '')
%span.js-filepicker
- %button.gl-button.btn.btn-default.js-filepicker-button{ type: 'button', class: classes }= _("Choose file…")
+ = render Pajamas::ButtonComponent.new(button_options: { class: "js-filepicker-button #{classes}" }) do
+ = _("Choose file…")
%span.file_name.js-filepicker-filename= _("No file chosen.")
= f.file_field field, class: "js-filepicker-input hidden"
- if help_text.present?
diff --git a/app/views/shared/_flash_user_callout.html.haml b/app/views/shared/_flash_user_callout.html.haml
index 7b2d59407b4..c549c4e6e4d 100644
--- a/app/views/shared/_flash_user_callout.html.haml
+++ b/app/views/shared/_flash_user_callout.html.haml
@@ -4,7 +4,7 @@
.flash-container.flash-container-page.user-callout{ data: callout_data }
-# We currently only support `alert`, `warning`, `notice`, `success`
%div{ class: "flash-#{flash_type}" }
- %div{ class: "#{(container_class unless fluid_layout)} #{(extra_flash_class unless @no_container)} #{@content_class}" }
+ %div{ class: "#{container_class unless fluid_layout} #{extra_flash_class unless @no_container} #{@content_class}" }
%span= message
%button.btn.gl-button.btn-default.close.js-close{ type: 'button',
'aria-label' => _('Dismiss') }
diff --git a/app/views/shared/_label.html.haml b/app/views/shared/_label.html.haml
index c0bc50fef5b..1645c2695b5 100644
--- a/app/views/shared/_label.html.haml
+++ b/app/views/shared/_label.html.haml
@@ -42,7 +42,7 @@
- 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?
- = render Pajamas::ButtonComponent.new(button_options: { class: "js-unsubscribe-button #{('hidden' if status.unsubscribed?)}", data: { url: toggle_subscription_path, toggle: 'tooltip', container: 'body' }, title: tooltip_title } ) do
+ = render Pajamas::ButtonComponent.new(button_options: { class: "js-unsubscribe-button #{'hidden' if status.unsubscribed?}", data: { url: toggle_subscription_path, toggle: 'tooltip', container: 'body' }, title: tooltip_title } ) do
= _('Unsubscribe')
.dropdown.dropdown-group-label{ class: ('hidden' unless status.unsubscribed?) }
= render Pajamas::ButtonComponent.new(button_options: { class: 'gl-w-full', data: { toggle: 'dropdown' } }) do
@@ -51,10 +51,10 @@
.dropdown-menu.dropdown-open-left
%ul
%li
- = render Pajamas::ButtonComponent.new(category: :tertiary, button_options: { class: "js-subscribe-button #{('hidden' unless status.unsubscribed?)}", data: { status: status, url: toggle_subscription_project_label_path(@project, label) } } ) do
+ = render Pajamas::ButtonComponent.new(category: :tertiary, button_options: { class: "js-subscribe-button #{'hidden' unless status.unsubscribed?}", data: { status: status, url: toggle_subscription_project_label_path(@project, label) } } ) do
= _('Subscribe at project level')
%li
- = render Pajamas::ButtonComponent.new(category: :tertiary, button_options: { class: "js-subscribe-button js-group-level #{('hidden' unless status.unsubscribed?)}", data: { status: status, url: toggle_subscription_group_label_path(label.group, label) } } ) do
+ = render Pajamas::ButtonComponent.new(category: :tertiary, button_options: { class: "js-subscribe-button js-group-level #{'hidden' unless status.unsubscribed?}", data: { status: status, url: toggle_subscription_group_label_path(label.group, label) } } ) do
= _('Subscribe at group level')
- else
= render Pajamas::ButtonComponent.new(button_options: { class: 'js-subscribe-button gl-w-full', data: { status: status, url: toggle_subscription_path, toggle: 'tooltip', container: 'body' }, title: tooltip_title } ) do
diff --git a/app/views/shared/_md_preview.html.haml b/app/views/shared/_md_preview.html.haml
index 7314a7ddadc..2fff70cdc74 100644
--- a/app/views/shared/_md_preview.html.haml
+++ b/app/views/shared/_md_preview.html.haml
@@ -1,6 +1,6 @@
- referenced_users = local_assigns.fetch(:referenced_users, nil)
-- if defined?(@merge_request) && @merge_request.discussion_locked?
+- if @merge_request&.discussion_locked?
.issuable-note-warning
= sprite_icon('lock', css_class: 'icon')
%span
diff --git a/app/views/shared/access_tokens/_created_container.html.haml b/app/views/shared/access_tokens/_created_container.html.haml
deleted file mode 100644
index c0aaa46e761..00000000000
--- a/app/views/shared/access_tokens/_created_container.html.haml
+++ /dev/null
@@ -1,12 +0,0 @@
-.created-personal-access-token-container
- %h5.gl-mt-0
- = _('Your new %{type}') % { type: type }
- .form-group
- .input-group
- = text_field_tag 'created-personal-access-token', new_token_value, readonly: true, class: 'form-control js-select-on-focus', data: { qa_selector: 'created_access_token_field' }, 'aria-describedby' => 'created-token-help-block'
- %span.input-group-append
- = clipboard_button(text: new_token_value, title: _('Copy %{type}') % { type: type }, placement: 'left', class: 'input-group-text btn-default btn-clipboard')
- %span#created-token-help-block.form-text.text-muted.text-danger
- = _("Make sure you save it - you won't be able to access it again.")
-
-%hr
diff --git a/app/views/shared/access_tokens/_table.html.haml b/app/views/shared/access_tokens/_table.html.haml
deleted file mode 100644
index 53c6800f93d..00000000000
--- a/app/views/shared/access_tokens/_table.html.haml
+++ /dev/null
@@ -1,51 +0,0 @@
-- no_active_tokens_message = local_assigns.fetch(:no_active_tokens_message, _('This user has no active %{type}.') % { type: type_plural })
-- impersonation = local_assigns.fetch(:impersonation, false)
-- resource = local_assigns.fetch(:resource, false)
-
-%hr
-
-%h5
- = _('Active %{type} (%{token_length})') % { type: type_plural, token_length: active_tokens.length }
-
-- if impersonation
- %p.profile-settings-content
- = _("To see all the user's personal access tokens you must impersonate them first.")
-
-- if active_tokens.present?
- .table-responsive
- %table.table.active-tokens
- %thead
- %tr
- %th= _('Token name')
- %th= _('Scopes')
- %th= s_('AccessTokens|Created')
- %th
- = _('Last Used')
- = link_to sprite_icon('question-o'), help_page_path('user/profile/personal_access_tokens.md', anchor: 'view-the-last-time-a-token-was-used'), target: '_blank', rel: 'noopener noreferrer'
- %th= _('Expires')
- - if resource
- %th= _('Role')
- %th
- %tbody
- - active_tokens.each do |token|
- %tr
- %td= token.name
- %td= token.scopes.present? ? token.scopes.join(', ') : _('no scopes selected')
- %td= token.created_at.to_date.to_s(:medium)
- %td
- - if token.last_used_at?
- %span.token-last-used-label= _(time_ago_with_tooltip(token.last_used_at))
- - else
- %span.token-never-used-label= _('Never')
- %td
- - if token.expires?
- %span{ class: ('text-warning' if token.expires_soon?) }
- = time_ago_with_tooltip(token.expires_at)
- - else
- %span.token-never-expires-label= _('Never')
- - if resource
- %td= resource.member(token.user).human_access
- %td= link_to _('Revoke'), revoke_route_helper.call(token), method: :put, class: "gl-button btn btn-danger btn-sm float-right #{'btn-danger-secondary' unless token.expires?}", aria: { label: _('Revoke') }, data: { confirm: _('Are you sure you want to revoke this %{type}? This action cannot be undone.') % { type: type }, 'confirm-btn-variant': 'danger', qa_selector: 'revoke_button' }
-- else
- .settings-message.text-center
- = no_active_tokens_message
diff --git a/app/views/shared/deploy_tokens/_form.html.haml b/app/views/shared/deploy_tokens/_form.html.haml
index 1b48843eb10..0f290f34a95 100644
--- a/app/views/shared/deploy_tokens/_form.html.haml
+++ b/app/views/shared/deploy_tokens/_form.html.haml
@@ -3,7 +3,7 @@
- group_deploy_tokens_help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: group_deploy_tokens_help_link_url }
= s_('DeployTokens|Create a new deploy token for all projects in this group. %{link_start}What are deploy tokens?%{link_end}').html_safe % { link_start: group_deploy_tokens_help_link_start, link_end: '</a>'.html_safe }
-= gitlab_ui_form_for token, url: create_deploy_token_path(group_or_project, anchor: 'js-deploy-tokens'), method: :post, remote: Feature.enabled?(:ajax_new_deploy_token, group_or_project) do |f|
+= gitlab_ui_form_for token, url: create_deploy_token_path(group_or_project, anchor: 'js-deploy-tokens'), method: :post, remote: true do |f|
.form-group
= f.label :name, class: 'label-bold'
diff --git a/app/views/shared/deploy_tokens/_index.html.haml b/app/views/shared/deploy_tokens/_index.html.haml
index faec379e42b..e5f1fd99125 100644
--- a/app/views/shared/deploy_tokens/_index.html.haml
+++ b/app/views/shared/deploy_tokens/_index.html.haml
@@ -8,20 +8,13 @@
%p
= description
.settings-content
- - if Feature.enabled?(:ajax_new_deploy_token, group_or_project)
- #js-new-deploy-token{ data: {
- container_registry_enabled: container_registry_enabled?(group_or_project),
- packages_registry_enabled: packages_registry_enabled?(group_or_project),
- create_new_token_path: create_deploy_token_path(group_or_project),
- token_type: group_or_project.is_a?(Group) ? 'group' : 'project',
- deploy_tokens_help_url: help_page_path('user/project/deploy_tokens/index.md')
- }
+ #js-new-deploy-token{ data: {
+ container_registry_enabled: container_registry_enabled?(group_or_project),
+ packages_registry_enabled: packages_registry_enabled?(group_or_project),
+ create_new_token_path: create_deploy_token_path(group_or_project),
+ token_type: group_or_project.is_a?(Group) ? 'group' : 'project',
+ deploy_tokens_help_url: help_page_path('user/project/deploy_tokens/index.md')
}
- - else
- - if @created_deploy_token
- = render 'shared/deploy_tokens/new_deploy_token', deploy_token: @created_deploy_token
- %h5.gl-mt-0
- = s_('DeployTokens|New deploy token')
- = render 'shared/deploy_tokens/form', group_or_project: group_or_project, token: @new_deploy_token, presenter: @deploy_tokens
+ }
%hr
= render 'shared/deploy_tokens/table', group_or_project: group_or_project, active_tokens: @deploy_tokens
diff --git a/app/views/shared/empty_states/_snippets.html.haml b/app/views/shared/empty_states/_snippets.html.haml
index a006a3bc0a4..e34166bac6c 100644
--- a/app/views/shared/empty_states/_snippets.html.haml
+++ b/app/views/shared/empty_states/_snippets.html.haml
@@ -2,8 +2,8 @@
.row.empty-state
.col-12
- .svg-content
- = image_tag 'illustrations/snippets_empty.svg', data: { qa_selector: 'svg_content' }
+ .svg-content{ data: { qa_selector: 'svg_content' } }
+ = image_tag 'illustrations/snippets_empty.svg'
.text-content.gl-text-center.gl-pt-0
- if current_user
%h4
diff --git a/app/views/shared/issuable/_bulk_update_sidebar.html.haml b/app/views/shared/issuable/_bulk_update_sidebar.html.haml
index e6bdefc64d2..da8477f4b2e 100644
--- a/app/views/shared/issuable/_bulk_update_sidebar.html.haml
+++ b/app/views/shared/issuable/_bulk_update_sidebar.html.haml
@@ -1,5 +1,6 @@
- type = local_assigns.fetch(:type)
- is_issue = type == :issues
+- move_data = { projects_fetch_path: autocomplete_projects_path(project_id: @project.id), project_full_path: @project.full_path }
%aside.issues-bulk-update.js-right-sidebar.right-sidebar{ "aria-live" => "polite", data: { 'signed-in': current_user.present? }, 'aria-label': _('Bulk update') }
.issuable-sidebar.hidden
@@ -33,7 +34,7 @@
.title
= _('Milestone')
.filter-item
- = dropdown_tag(_("Select milestone"), options: { title: _("Assign milestone"), toggle_class: "js-milestone-select js-extra-options js-filter-submit js-filter-bulk-update", filter: true, dropdown_class: "dropdown-menu-selectable dropdown-menu-milestone", placeholder: _("Search milestones"), data: { show_no: true, field_name: "update[milestone_id]", project_id: @project.id, use_id: true, default_label: _("Milestone") } })
+ .js-milestone-dropdown-root{ data: { full_path: @project.full_path, workspace_type: Namespaces::ProjectNamespace.sti_name.downcase } }
- if is_issue
= render_if_exists 'shared/issuable/iterations_dropdown', parent: @project.group
- if is_issue
@@ -42,6 +43,9 @@
.title
= _('Subscriptions')
.js-subscriptions-dropdown
+ - if is_issue
+ .block
+ .js-move-issues{ data: move_data }
= hidden_field_tag "update[issuable_ids]", []
= hidden_field_tag :state_event, params[:state_event]
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 5b7f9c4226c..a325ad5f447 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -71,7 +71,10 @@
- else
= link_to _('Cancel'), polymorphic_path([@project, issuable]), class: 'gl-button btn btn-default js-reset-autosave'
- if can?(current_user, :"destroy_#{issuable.to_ability_name}", @project)
- = link_to 'Delete', polymorphic_path([@project, issuable], params: { destroy_confirm: true }), data: { confirm: _('%{issuableType} will be removed! Are you sure?') % { issuableType: issuable.human_class_name } }, method: :delete, class: 'btn gl-button btn-danger btn-danger-secondary gl-float-right js-reset-autosave'
+ - confirm_title = _('Delete %{issuableType}?') % { issuableType: issuable.human_class_name }
+ - confirm_body = _('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.') % { issuableType: issuable.human_class_name, issuableTitle: issuable.title, strongOpen: '<strong>', strongClose: '</strong>' }
+ - confirm_primary_btn_text = _('Delete %{issuableType}') % { issuableType: issuable.human_class_name }
+ = link_to _('Delete'), polymorphic_path([@project, issuable], params: { destroy_confirm: true }), data: { title: confirm_title, confirm: confirm_body, is_html_message: true, confirm_btn_variant: 'danger'}, method: :delete, class: 'btn gl-button btn-danger btn-danger-secondary gl-float-right js-reset-autosave', "aria-label": confirm_primary_btn_text
- if issuable.respond_to?(:issue_type)
= form.hidden_field :issue_type
diff --git a/app/views/shared/issuable/_milestone_dropdown.html.haml b/app/views/shared/issuable/_milestone_dropdown.html.haml
index 58108ceeb76..a02d2851c4c 100644
--- a/app/views/shared/issuable/_milestone_dropdown.html.haml
+++ b/app/views/shared/issuable/_milestone_dropdown.html.haml
@@ -1,19 +1,11 @@
+- name = local_assigns.fetch(:name, nil)
- project = @target_project || @project
-- extra_class = extra_class || ''
-- show_menu_above = show_menu_above || false
- selected = local_assigns.fetch(:selected, nil)
-- selected_text = selected.try(:title) || params[:milestone_title]
-- dropdown_title = local_assigns.fetch(:dropdown_title, _('Filter by milestone'))
-- if selected.present? || params[:milestone_title].present?
- = hidden_field_tag(name, name == :milestone_title ? selected_text : selected.id)
-= dropdown_tag(milestone_dropdown_label(selected_text), options: { title: dropdown_title, toggle_class: "js-milestone-select js-filter-submit #{extra_class}", filter: true, dropdown_class: "dropdown-menu-selectable dropdown-menu-milestone", dropdown_qa_selector: "issuable_milestone_dropdown_content",
- placeholder: _('Search milestones'), footer_content: project.present?, data: { show_no: true, show_menu_above: show_menu_above, show_any: show_any, show_upcoming: show_upcoming, show_started: show_started, field_name: name, selected: selected_text, project_id: project.try(:id), default_label: _('Milestone'), qa_selector: "issuable_milestone_dropdown", testid: "issuable-milestone-dropdown" } }) do
- - if project
- %ul.dropdown-footer-list
- %li
- = link_to project_milestones_path(project) do
- - if can? current_user, :admin_milestone, project
- = _('Manage milestones')
- - else
- = _('View milestones')
+.js-milestone-dropdown-root{ data: { can_admin_milestone: can?(current_user, :admin_milestone, project),
+ full_path: project.full_path,
+ input_name: name,
+ milestone_id: selected.try(:id),
+ milestone_title: selected.try(:title),
+ project_milestones_path: project_milestones_path(project),
+ workspace_type: Namespaces::ProjectNamespace.sti_name.downcase } }
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index 4199b7e870b..0fd128df997 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -17,14 +17,14 @@
%a.gutter-toggle.float-right.js-sidebar-toggle.has-tooltip{ role: "button", class: "#{'gl-display-block' if moved_sidebar_enabled}", href: "#", "aria-label" => _('Toggle sidebar'), title: sidebar_gutter_tooltip_text, data: { container: 'body', placement: 'left', boundary: 'viewport' } }
= sidebar_gutter_toggle_icon
- if signed_in && !moved_sidebar_enabled
- .js-issuable-todo{ data: { project_path: issuable_sidebar[:project_full_path], iid: issuable_sidebar[:iid], id: issuable_sidebar[:id] } }
+ .js-sidebar-todo-widget-root{ data: { project_path: issuable_sidebar[:project_full_path], iid: issuable_sidebar[:iid], id: issuable_sidebar[:id] } }
= form_for issuable_type, url: issuable_sidebar[:issuable_json_path], remote: true, html: { class: 'issuable-context-form inline-update js-issuable-update' } do |f|
- .block.assignee.qa-assignee-block{ class: "#{'gl-mt-3' if !signed_in && moved_sidebar_enabled}", data: { qa_selector: 'assignee_block_container' } }
+ .block.assignee{ class: "#{'gl-mt-3' if !signed_in && moved_sidebar_enabled}", data: { qa_selector: 'assignee_block_container' } }
= render "shared/issuable/sidebar_assignees", issuable_sidebar: issuable_sidebar, assignees: assignees, signed_in: signed_in
- if issuable_sidebar[:supports_severity]
- #js-severity
+ .js-sidebar-severity-root
- if reviewers
.block.reviewer{ data: { qa_selector: 'reviewers_block_container' } }
@@ -32,17 +32,17 @@
- if issuable_sidebar[:supports_escalation]
.block.escalation-status{ data: { testid: 'escalation_status_container' } }
- #js-escalation-status{ data: { can_update: issuable_sidebar.dig(:current_user, :can_update_escalation_status).to_s, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid] } }
+ .js-sidebar-escalation-status-root{ data: { can_update: issuable_sidebar.dig(:current_user, :can_update_escalation_status).to_s, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid] } }
= render_if_exists 'shared/issuable/sidebar_escalation_policy', issuable_sidebar: issuable_sidebar
- if @project.group.present?
= render_if_exists 'shared/issuable/sidebar_item_epic', issuable_sidebar: issuable_sidebar, group_path: @project.group.full_path, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid], issuable_type: issuable_type
- .js-sidebar-labels{ data: sidebar_labels_data(issuable_sidebar, @project) }
+ .js-sidebar-labels-widget-root{ data: sidebar_labels_data(issuable_sidebar, @project) }
- if issuable_sidebar[:supports_milestone]
.block.milestone{ :class => ("gl-border-b-0!" if in_group_context_with_iterations), data: { qa_selector: 'milestone_block', testid: 'sidebar-milestones' } }
- .js-milestone-select{ data: { can_edit: can_edit_issuable.to_s, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid] } }
+ .js-sidebar-milestone-widget-root{ data: { can_edit: can_edit_issuable.to_s, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid] } }
- if in_group_context_with_iterations
.block.gl-collapse-empty{ data: { qa_selector: 'iteration_container', testid: 'iteration_container' } }<
@@ -50,40 +50,40 @@
- if issuable_sidebar[:show_crm_contacts]
.block.contact
- #js-issue-crm-contacts{ data: { issue_id: issuable_sidebar[:id], group_issues_path: issues_group_path(@project.group) } }
+ .js-sidebar-crm-contacts-root{ data: { issue_id: issuable_sidebar[:id], group_issues_path: issues_group_path(@project.group) } }
= render_if_exists 'shared/issuable/sidebar_weight', issuable_sidebar: issuable_sidebar, can_edit: can_edit_issuable.to_s, project_path: issuable_sidebar[:project_full_path], issue_iid: issuable_sidebar[:iid]
- if issuable_sidebar.has_key?(:due_date)
- #js-due-date-entry-point
+ .js-sidebar-due-date-widget-root
- if issuable_sidebar[:supports_time_tracking]
- #issuable-time-tracker.block
+ .js-sidebar-time-tracking-root.block
// Fallback while content is loading
.title.hide-collapsed
= _('Time tracking')
= gl_loading_icon(inline: true)
- if issuable_sidebar.dig(:features_available, :health_status)
- .js-sidebar-health-status-entry-point{ data: sidebar_status_data(issuable_sidebar, @project) }
+ .js-sidebar-health-status-widget-root{ data: sidebar_status_data(issuable_sidebar, @project) }
- if issuable_sidebar.has_key?(:confidential)
-# haml-lint:disable InlineJavaScript
%script#js-confidential-issue-data{ type: "application/json" }= { is_confidential: issuable_sidebar[:confidential], is_editable: can_edit_issuable }.to_json.html_safe
- #js-confidential-entry-point
+ .js-sidebar-confidential-widget-root
= render_if_exists 'shared/issuable/sidebar_cve_id_request', issuable_sidebar: issuable_sidebar
- if !moved_sidebar_enabled
- #js-lock-entry-point
+ .js-sidebar-lock-root
- if signed_in
- .js-sidebar-subscriptions-entry-point
+ .js-sidebar-subscriptions-widget-root
- .js-sidebar-participants-entry-point
+ .js-sidebar-participants-widget-root
.block.with-sub-blocks
- if !moved_sidebar_enabled
- #js-reference-entry-point
+ .js-sidebar-reference-widget-root
- if issuable_type == 'merge_request' && !moved_sidebar_enabled
.sub-block.js-sidebar-source-branch
.sidebar-collapsed-icon.js-dont-change-state
@@ -95,7 +95,7 @@
- if show_forwarding_email
.block
- #issuable-copy-email
+ .js-sidebar-copy-email-root
- if issuable_sidebar.dig(:current_user, :can_move)
.block.js-sidebar-move-issue-block
.sidebar-collapsed-icon{ data: { toggle: 'tooltip', placement: 'left', container: 'body', boundary: 'viewport' }, title: _('Move issue') }
diff --git a/app/views/shared/issuable/_sidebar_assignees.html.haml b/app/views/shared/issuable/_sidebar_assignees.html.haml
index 62221fb8218..8ca30d7ca97 100644
--- a/app/views/shared/issuable/_sidebar_assignees.html.haml
+++ b/app/views/shared/issuable/_sidebar_assignees.html.haml
@@ -1,7 +1,7 @@
- issuable_type = issuable_sidebar[:type]
- dropdown_options = assignees_dropdown_options(issuable_type)
-#js-vue-sidebar-assignees{ data: { field: issuable_type,
+.js-sidebar-assignees-root{ data: { field: issuable_type,
signed_in: signed_in,
max_assignees: dropdown_options[:data][:"max-select"],
directly_invite_members: can_admin_project_member?(@project) } }
@@ -39,7 +39,7 @@
- data[:multi_select] = true
- data['dropdown-title'] = title
- data['dropdown-header'] = dropdown_options[:data][:'dropdown-header']
- - data['max-select'] = dropdown_max_select(dropdown_options[:data], :limit_assignees_per_issuable)
+ - data['max-select'] = dropdown_max_select(dropdown_options[:data], nil)
- options[:data].merge!(data)
= render 'shared/issuable/sidebar_user_dropdown',
diff --git a/app/views/shared/issuable/_sidebar_reviewers.html.haml b/app/views/shared/issuable/_sidebar_reviewers.html.haml
index 771db8af6a8..4df393eeb67 100644
--- a/app/views/shared/issuable/_sidebar_reviewers.html.haml
+++ b/app/views/shared/issuable/_sidebar_reviewers.html.haml
@@ -1,16 +1,12 @@
- issuable_type = issuable_sidebar[:type]
-#js-vue-sidebar-reviewers{ data: { field: issuable_type, signed_in: signed_in } }
+.js-sidebar-reviewers-root{ data: { field: issuable_type, signed_in: signed_in } }
.title.hide-collapsed
= _('Reviewers')
= gl_loading_icon(inline: true)
.selectbox.hide-collapsed
- - if reviewers.none?
- = hidden_field_tag "#{issuable_type}[reviewer_ids][]", 0, id: nil
- - else
- - reviewers.each do |reviewer|
- = hidden_field_tag "#{issuable_type}[reviewer_ids][]", reviewer.id, id: nil, data: reviewer_sidebar_data(reviewer, merge_request: @merge_request)
+ .js-reviewers-inputs
- options = { toggle_class: 'js-reviewer-search js-author-search',
title: _('Request review from'),
@@ -32,10 +28,10 @@
- dropdown_options = reviewers_dropdown_options(issuable_type)
- title = dropdown_options[:title]
- options[:toggle_class] += ' js-multiselect js-save-user-data'
- - data = { field_name: "#{issuable_type}[reviewer_ids][]" }
- - data[:multi_select] = true
+ - data = { multi_select: true }
- data['dropdown-title'] = title
- data['dropdown-header'] = dropdown_options[:data][:'dropdown-header']
+ - data[:suggested_reviewers_help_path] = dropdown_options[:data][:suggested_reviewers_help_path]
- data[:suggested_reviewers_header] = dropdown_options[:data][:suggested_reviewers_header]
- data[:all_members_header] = dropdown_options[:data][:all_members_header]
- data[:show_suggested] = dropdown_options[:data][:show_suggested]
diff --git a/app/views/shared/issuable/form/_metadata.html.haml b/app/views/shared/issuable/form/_metadata.html.haml
index 76469b34832..9603178f7de 100644
--- a/app/views/shared/issuable/form/_metadata.html.haml
+++ b/app/views/shared/issuable/form/_metadata.html.haml
@@ -35,7 +35,7 @@
= form.label :milestone_id, _('Milestone'), class: "col-12"
.col-12
.issuable-form-select-holder
- = render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false, show_started: false, extra_class: "js-issuable-form-dropdown js-dropdown-keep-input", dropdown_title: _('Select milestone')
+ = render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]"
.form-group.row
= form.label :label_ids, _('Labels'), class: "col-12"
@@ -54,3 +54,4 @@
.col-12
.issuable-form-select-holder
= form.gitlab_ui_datepicker :due_date, placeholder: _('Select due date'), autocomplete: 'off', id: "issuable-due-date"
+ = render_if_exists "shared/issuable/form/iteration", form: form, group: project.group
diff --git a/app/views/shared/issue_type/_emoji_block.html.haml b/app/views/shared/issue_type/_emoji_block.html.haml
index a5c71fb1d24..7eb3c0f5c9f 100644
--- a/app/views/shared/issue_type/_emoji_block.html.haml
+++ b/app/views/shared/issue_type/_emoji_block.html.haml
@@ -1,8 +1,8 @@
- api_awards_path = local_assigns.fetch(:api_awards_path, nil)
-.content-block.emoji-block.emoji-block-sticky
+.emoji-block.emoji-block-sticky
.row.gl-m-0.gl-justify-content-space-between
.js-noteable-awards
= render 'award_emoji/awards_block', awardable: issuable, inline: true, api_awards_path: api_awards_path
- .new-branch-col.gl-font-size-0
+ .new-branch-col.gl-font-size-0.gl-my-2
= render 'new_branch' if show_new_branch_button?
diff --git a/app/views/shared/labels/_form.html.haml b/app/views/shared/labels/_form.html.haml
index c6932d49d33..9ef4b9e084d 100644
--- a/app/views/shared/labels/_form.html.haml
+++ b/app/views/shared/labels/_form.html.haml
@@ -29,8 +29,10 @@
= f.submit _('Save changes'), class: 'js-save-button gl-mr-2', pajamas_button: true
- else
= f.submit _('Create label'), class: 'js-save-button gl-mr-2', data: { qa_selector: 'label_create_button' }, pajamas_button: true
- = link_to _('Cancel'), back_path, class: 'btn gl-button btn-default btn-cancel gl-mr-2'
+ = render Pajamas::ButtonComponent.new(href: back_path) do
+ = _('Cancel')
+
- if @label.persisted?
- presented_label = @label.present
- %button.btn.btn-danger.gl-button.btn-danger-secondary.js-delete-label-modal-button{ type: 'button', data: { label_name: presented_label.name, subject_name: presented_label.subject_name, destroy_path: presented_label.destroy_path } }
- %span.gl-button-text= _('Delete')
+ = render Pajamas::ButtonComponent.new(variant: :danger, category: :secondary, button_options: { class: 'js-delete-label-modal-button', data: { label_name: presented_label.name, subject_name: presented_label.subject_name, destroy_path: presented_label.destroy_path } }) do
+ = _('Delete')
diff --git a/app/views/shared/members/_access_request_links.html.haml b/app/views/shared/members/_access_request_links.html.haml
index 7af946377be..0b38b9d7945 100644
--- a/app/views/shared/members/_access_request_links.html.haml
+++ b/app/views/shared/members/_access_request_links.html.haml
@@ -8,9 +8,10 @@
data: { confirm: leave_confirmation_message(source), confirm_btn_variant: 'danger', qa_selector: 'leave_group_link' },
class: 'js-leave-link'
- elsif requester = source.requesters.find_by(user_id: current_user.id) # rubocop: disable CodeReuse/ActiveRecord
- = link_to _('Withdraw Access Request'), polymorphic_path([:leave, source, :members]),
- method: :delete,
- data: { confirm: remove_member_message(requester) }
+ - if can?(current_user, :withdraw_member_access_request, requester)
+ = link_to _('Withdraw Access Request'), polymorphic_path([:leave, source, :members]),
+ method: :delete,
+ data: { confirm: remove_member_message(requester) }
- elsif source.request_access_enabled && can?(current_user, :request_access, source)
= link_to _('Request Access'), polymorphic_path([:request_access, source, :members]),
method: :post
diff --git a/app/views/shared/milestones/_delete_button.html.haml b/app/views/shared/milestones/_delete_button.html.haml
index 8a709a36835..432d2efc36e 100644
--- a/app/views/shared/milestones/_delete_button.html.haml
+++ b/app/views/shared/milestones/_delete_button.html.haml
@@ -1,11 +1,7 @@
- milestone_url = @milestone.project_milestone? ? project_milestone_path(@project, @milestone) : group_milestone_path(@group, @milestone)
-%button.js-delete-milestone-button.btn.gl-button.btn-grouped.btn-danger{ data: { milestone_id: @milestone.id,
- milestone_title: markdown_field(@milestone, :title),
- milestone_url: milestone_url,
- milestone_issue_count: @milestone.issues.count,
- milestone_merge_request_count: @milestone.merge_requests.count },
- disabled: true }
+= render Pajamas::ButtonComponent.new(variant: :danger,
+ button_options: { class: 'js-delete-milestone-button btn-grouped', data: { milestone_id: @milestone.id, milestone_title: markdown_field(@milestone, :title), milestone_url: milestone_url, milestone_issue_count: @milestone.issues.count, milestone_merge_request_count: @milestone.merge_requests.count }, disabled: true }) do
= gl_loading_icon(inline: true, css_class: "gl-mr-2 js-loading-icon hidden")
= _('Delete')
diff --git a/app/views/shared/milestones/_sidebar.html.haml b/app/views/shared/milestones/_sidebar.html.haml
index 6a65909b1c2..cc1965945ac 100644
--- a/app/views/shared/milestones/_sidebar.html.haml
+++ b/app/views/shared/milestones/_sidebar.html.haml
@@ -94,7 +94,7 @@
= milestone.issues_visible_to_user(current_user).closed.count
.block
- #issuable-time-tracker{ data: { time_estimate: @milestone.total_time_estimate,
+ .js-sidebar-time-tracking-root{ data: { time_estimate: @milestone.total_time_estimate,
time_spent: @milestone.total_time_spent,
human_time_estimate: @milestone.human_total_time_estimate,
human_time_spent: @milestone.human_total_time_spent,
diff --git a/app/views/shared/projects/_list.html.haml b/app/views/shared/projects/_list.html.haml
index c39dc561801..43cd2ee4c5b 100644
--- a/app/views/shared/projects/_list.html.haml
+++ b/app/views/shared/projects/_list.html.haml
@@ -32,7 +32,7 @@
- if any_projects?(projects)
- load_pipeline_status(projects) if pipeline_status
- load_max_project_member_accesses(projects) # Prime cache used in shared/projects/project view rendered below
- %ul.projects-list{ class: css_classes }
+ %ul.projects-list.gl-text-secondary.gl-w-full.gl-my-2{ class: css_classes }
- projects.each_with_index do |project, i|
- css_class = (i >= projects_limit) || project.pending_delete? ? 'hide' : nil
= render "shared/projects/project", project: project, skip_namespace: skip_namespace,
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
index 81e2e066bd3..908eb2428e8 100644
--- a/app/views/shared/projects/_project.html.haml
+++ b/app/views/shared/projects/_project.html.haml
@@ -8,102 +8,108 @@
- access = max_project_member_access(project)
- compact_mode = false unless local_assigns[:compact_mode] == true
- show_last_commit_as_description = false unless local_assigns[:show_last_commit_as_description] == true && can_show_last_commit_in_list?(project)
-- css_class = '' unless local_assigns[:css_class]
-- css_class += " gl-display-flex!"
+- css_class = "gl-sm-display-flex gl-align-items-center gl-vertical-align-middle!" if project.description.blank? && !show_last_commit_as_description
- cache_key = project_list_cache_key(project, pipeline_status: pipeline_status)
- updated_tooltip = time_ago_with_tooltip(project.last_activity_date)
- show_pipeline_status_icon = pipeline_status && can?(current_user, :read_cross_project) && project.pipeline_status.has_status? && can?(current_user, :read_build, project)
- last_pipeline = project.last_pipeline if show_pipeline_status_icon
-- css_controls_class = compact_mode ? [] : ["flex-lg-row", "justify-content-lg-between"]
-- css_controls_class << "with-pipeline-status" if show_pipeline_status_icon && last_pipeline.present?
-- avatar_container_class = project.creator && use_creator_avatar ? '' : 'rect-avatar'
+- css_controls_class = "with-pipeline-status" if show_pipeline_status_icon && last_pipeline.present?
+- css_controls_container_class = compact_mode ? "" : "gl-lg-flex-direction-row gl-justify-content-space-between"
+- css_metadata_classes = "gl-display-flex gl-align-items-center gl-mr-5 gl-reset-color! icon-wrapper has-tooltip"
-%li.project-row.gl-align-items-center{ class: css_class }
+%li.project-row
= cache(cache_key) do
- if avatar
- .flex-grow-0.flex-shrink-0{ class: avatar_container_class }
+ .project-cell.gl-w-11
= link_to project_path(project), class: dom_class(project) do
- if project.creator && use_creator_avatar
= render Pajamas::AvatarComponent.new(project.creator, size: 48, alt: '', class: 'gl-mr-5')
- else
= render Pajamas::AvatarComponent.new(project, size: 48, alt: '', class: 'gl-mr-5')
- .project-details.d-sm-flex.flex-sm-fill.align-items-center{ data: { qa_selector: 'project_content', qa_project_name: project.name } }
- .flex-wrapper
- .d-flex.align-items-center.flex-wrap.project-title
- %h2.d-flex.gl-mt-3
- = link_to project_path(project), class: 'text-plain js-prefetch-document' do
- %span.project-full-name.gl-mr-3><
- %span.namespace-name
- - if project.namespace && !skip_namespace
- = project.namespace.human_name
- \/
- %span.project-name<
- = project.name
+ .project-cell{ class: css_class }
+ .project-details.gl-pr-9.gl-sm-pr-0.gl-w-full.gl-display-flex.gl-flex-direction-column{ data: { qa_selector: 'project_content', qa_project_name: project.name } }
+ .gl-display-flex.gl-align-items-center.gl-flex-wrap-wrap
+ %h2.gl-font-base.gl-line-height-20.gl-my-0
+ = link_to project_path(project), class: 'text-plain gl-mr-3 js-prefetch-document' do
+ %span.namespace-name.gl-font-weight-normal
+ - if project.namespace && !skip_namespace
+ = project.namespace.human_name
+ \/
+ %span.project-name<
+ = project.name
- %span.metadata-info.visibility-icon.gl-mr-3.gl-mt-3.text-secondary.has-tooltip{ data: { container: 'body', placement: 'top' }, title: visibility_icon_description(project) }
- = visibility_level_icon(project.visibility_level)
+ %span.gl-mr-3.has-tooltip{ data: { container: 'body', placement: 'top' }, title: visibility_icon_description(project) }
+ = visibility_level_icon(project.visibility_level)
- - if explore_projects_tab? && project_license_name(project)
- %span.metadata-info.d-inline-flex.align-items-center.gl-mr-3.gl-mt-3
- = sprite_icon('scale', size: 14, css_class: 'gl-mr-2')
- = project_license_name(project)
+ - if explore_projects_tab? && project_license_name(project)
+ %span.gl-display-inline-flex.gl-align-items-center.gl-mr-3
+ = sprite_icon('scale', size: 14, css_class: 'gl-mr-2')
+ = project_license_name(project)
- - if !explore_projects_tab? && access&.nonzero?
- -# haml-lint:disable UnnecessaryStringOutput
- = ' ' # prevent haml from eating the space between elements
- .metadata-info.gl-mt-3
- %span.user-access-role.gl-display-block{ data: { qa_selector: 'user_role_content' } }= localized_project_human_access(access)
+ - if !explore_projects_tab? && access&.nonzero?
+ -# haml-lint:disable UnnecessaryStringOutput
+ = ' ' # prevent haml from eating the space between elements
+ %span.user-access-role.gl-display-block.gl-m-0{ data: { qa_selector: 'user_role_content' } }= Gitlab::Access.human_access(access)
- - if !explore_projects_tab?
- .metadata-info.gl-mt-3
- = render_if_exists 'compliance_management/compliance_framework/compliance_framework_badge', project: project
+ - if !explore_projects_tab?
+ = render_if_exists 'compliance_management/compliance_framework/compliance_framework_badge', project: project
- - if show_last_commit_as_description
- .description.d-none.d-sm-block.gl-mr-3
- = link_to_markdown(project.commit.title, project_commit_path(project, project.commit), class: "commit-row-message")
- - elsif project.description.present?
- .description.d-none.d-sm-block.gl-mr-3
- = markdown_field(project, :description)
+ - if show_last_commit_as_description
+ .description.gl-display-none.gl-sm-display-block.gl-overflow-hidden.gl-mr-3.gl-mt-2
+ = link_to_markdown(project.commit.title, project_commit_path(project, project.commit), class: "commit-row-message")
+ - elsif project.description.present?
+ .description.gl-display-none.gl-sm-display-block.gl-overflow-hidden.gl-mr-3.gl-mt-2
+ = markdown_field(project, :description)
- - if project.topics.any?
- .gl-mt-2
- = render "shared/projects/topics", project: project.present(current_user: current_user)
+ - if project.topics.any?
+ .gl-mt-2
+ = render "shared/projects/topics", project: project.present(current_user: current_user)
- = render_if_exists 'shared/projects/removed', project: project
+ = render_if_exists 'shared/projects/removed', project: project
- .controls.d-flex.flex-sm-column.align-items-center.align-items-sm-end.flex-wrap.flex-shrink-0.text-secondary{ class: css_controls_class.join(" ") }
- .icon-container.d-flex.align-items-center
+ .gl-display-flex.gl-mt-3{ class: "#{css_class} gl-sm-display-none!" }
+ .controls.gl-display-flex.gl-align-items-center
- if show_pipeline_status_icon && last_pipeline.present?
- pipeline_path = pipelines_project_commit_path(project.pipeline_status.project, project.pipeline_status.sha, ref: project.pipeline_status.ref)
- %span.icon-wrapper.pipeline-status
+ %span.icon-wrapper.pipeline-status.gl-mr-5
= render 'ci/status/icon', status: last_pipeline.detailed_status(current_user), tooltip_placement: 'top', path: pipeline_path
= render_if_exists 'shared/projects/archived', project: project
- if stars
- = link_to project_starrers_path(project),
- class: "d-flex align-items-center icon-wrapper stars has-tooltip",
- title: _('Stars'), data: { container: 'body', placement: 'top' } do
- = sprite_icon('star', size: 14, css_class: 'gl-mr-2')
- = number_with_delimiter(project.star_count)
- - if forks
- = link_to project_forks_path(project),
- class: "align-items-center icon-wrapper forks has-tooltip",
- title: _('Forks'), data: { container: 'body', placement: 'top' } do
- = sprite_icon('fork', size: 14, css_class: 'gl-mr-2')
- = number_with_delimiter(project.forks_count)
- - if show_merge_request_count?(disabled: !merge_requests, compact_mode: compact_mode)
- = link_to project_merge_requests_path(project),
- class: "d-none d-xl-flex align-items-center icon-wrapper merge-requests has-tooltip",
- title: _('Merge requests'), data: { container: 'body', placement: 'top' } do
- = sprite_icon('git-merge', size: 14, css_class: 'gl-mr-2')
- = number_with_delimiter(project.open_merge_requests_count)
- - if show_issue_count?(disabled: !issues, compact_mode: compact_mode)
- = link_to project_issues_path(project),
- class: "d-none d-xl-flex align-items-center icon-wrapper issues has-tooltip",
- title: _('Issues'), data: { container: 'body', placement: 'top' } do
- = sprite_icon('issues', size: 14, css_class: 'gl-mr-2')
- = number_with_delimiter(project.open_issues_count)
- .updated-note
+ = link_to project_starrers_path(project), class: "#{css_metadata_classes} stars", title: _('Stars'), data: { container: 'body', placement: 'top' } do
+ = sprite_icon('star-o', size: 14, css_class: 'gl-mr-2')
+ = badge_count(project.star_count)
+ .updated-note.gl-ml-3.gl-sm-ml-0
%span
= _('Updated')
= updated_tooltip
+
+ .project-cell{ class: "#{css_class} gl-xs-display-none!" }
+ .project-controls.gl-display-flex.gl-flex-direction-column.gl-w-full{ class: css_controls_container_class, data: { testid: 'project_controls'} }
+ .controls.gl-display-flex.gl-align-items-center{ class: css_controls_class }
+ - if show_pipeline_status_icon && last_pipeline.present?
+ - pipeline_path = pipelines_project_commit_path(project.pipeline_status.project, project.pipeline_status.sha, ref: project.pipeline_status.ref)
+ %span.icon-wrapper.pipeline-status.gl-mr-5
+ = render 'ci/status/icon', status: last_pipeline.detailed_status(current_user), tooltip_placement: 'top', path: pipeline_path
+
+ = render_if_exists 'shared/projects/archived', project: project
+ - if stars
+ = link_to project_starrers_path(project), class: "#{css_metadata_classes} stars", title: _('Stars'), data: { container: 'body', placement: 'top' } do
+ = sprite_icon('star-o', size: 14, css_class: 'gl-mr-2')
+ = badge_count(project.star_count)
+ - if forks
+ = link_to project_forks_path(project), class: "#{css_metadata_classes} forks", title: _('Forks'), data: { container: 'body', placement: 'top' } do
+ = sprite_icon('fork', size: 14, css_class: 'gl-mr-2')
+ = badge_count(project.forks_count)
+ - if show_merge_request_count?(disabled: !merge_requests, compact_mode: compact_mode)
+ = link_to project_merge_requests_path(project), class: "#{css_metadata_classes} merge-requests", title: _('Merge requests'), data: { container: 'body', placement: 'top' } do
+ = sprite_icon('git-merge', size: 14, css_class: 'gl-mr-2')
+ = badge_count(project.open_merge_requests_count)
+ - if show_issue_count?(disabled: !issues, compact_mode: compact_mode)
+ = link_to project_issues_path(project), class: "#{css_metadata_classes} issues", title: _('Issues'), data: { container: 'body', placement: 'top' } do
+ = sprite_icon('issues', size: 14, css_class: 'gl-mr-2')
+ = badge_count(project.open_issues_count)
+ .updated-note.gl-white-space-nowrap.gl-justify-content-end
+ %span
+ = _('Updated')
+ = updated_tooltip
diff --git a/app/views/shared/web_hooks/_form.html.haml b/app/views/shared/web_hooks/_form.html.haml
index c95e63bdc83..ecb736dac4f 100644
--- a/app/views/shared/web_hooks/_form.html.haml
+++ b/app/views/shared/web_hooks/_form.html.haml
@@ -10,21 +10,25 @@
= s_('Webhooks|URL must be percent-encoded if it contains one or more special characters.')
.form-group
= form.label :token, s_('Webhooks|Secret token'), class: 'label-bold'
- = form.text_field :token, class: 'form-control gl-form-input', placeholder: ''
+ = form.password_field :token, value: hook.masked_token, autocomplete: 'new-password', class: 'form-control gl-form-input'
%p.form-text.text-muted
- code_start = '<code>'.html_safe
- code_end = '</code>'.html_safe
- = s_('Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header.').html_safe % { code_start: code_start, code_end: code_end }
+ = s_('Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header.').html_safe % { code_start: code_start, code_end: code_end }
.form-group
= form.label :url, s_('Webhooks|Trigger'), class: 'label-bold'
%ul.list-unstyled
%li.gl-pb-5
- = form.gitlab_ui_checkbox_component :push_events, s_('Webhooks|Push events')
- .gl-pl-6
- = form.text_field :push_events_branch_filter, class: 'form-control gl-form-input',
- placeholder: 'Branch name or wildcard pattern to trigger on (leave blank for all)'
- %p.form-text.text-muted.custom-control
- = s_('Webhooks|Push to the repository.')
+ - if Feature.enabled?(:enhanced_webhook_support_regex)
+ - is_new_hook = hook.id.nil?
+ .js-vue-push-events{ data: { push_events: hook.push_events.to_s, strategy: hook.branch_filter_strategy, is_new_hook: is_new_hook.to_s, push_events_branch_filter: hook.push_events_branch_filter } }
+ - else
+ = form.gitlab_ui_checkbox_component :push_events, s_('Webhooks|Push events')
+ .gl-pl-6
+ = form.text_field :push_events_branch_filter, class: 'form-control gl-form-input',
+ placeholder: 'Branch name or wildcard pattern to trigger on (leave blank for all)'
+ %p.form-text.text-muted.custom-control
+ = s_('Webhooks|Push to the repository.')
%li.gl-pb-5
= form.gitlab_ui_checkbox_component :tag_push_events,
s_('Webhooks|Tag push events'),
diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml
index 47ccc449e1b..bb43c3c6274 100644
--- a/app/views/snippets/show.html.haml
+++ b/app/views/snippets/show.html.haml
@@ -12,7 +12,7 @@
- content_for :prefetch_asset_tags do
- webpack_preload_asset_tag('monaco', prefetch: true)
-#js-snippet-view{ data: {'qa-selector': 'snippet_view', 'snippet-gid': @snippet.to_global_id, 'report-abuse-path': snippet_report_abuse_path(@snippet), 'can-report-spam': @snippet.submittable_as_spam_by?(current_user).to_s } }
+#js-snippet-view{ data: { 'snippet-gid': @snippet.to_global_id, 'report-abuse-path': snippet_report_abuse_path(@snippet), 'can-report-spam': @snippet.submittable_as_spam_by?(current_user).to_s } }
.row-content-block.top-block.content-component-block.gl-px-0.gl-py-2
= render 'award_emoji/awards_block', awardable: @snippet, inline: true
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 952023b3745..7cef87ba19f 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -14,33 +14,31 @@
.cover-block.user-cover-block{ class: [('border-bottom' if profile_tabs.empty?)] }
= render layout: 'users/cover_controls' do
- if @user == current_user
- = link_to profile_path, class: link_classes + 'btn gl-button btn-default btn-icon has-tooltip',
- title: s_('UserProfile|Edit profile'), 'aria-label': 'Edit profile', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
- = sprite_icon('pencil')
+ = render Pajamas::ButtonComponent.new(href: profile_path,
+ icon: 'pencil',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Edit profile'), 'aria-label': 'Edit profile', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
- elsif current_user
- if @user.abuse_report
- %button{ class: link_classes + 'btn gl-button btn-danger btn-icon', title: s_('UserProfile|Already reported for abuse'),
- data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } }>
- = sprite_icon('error')
+ = render Pajamas::ButtonComponent.new(variant: :danger,
+ icon: 'error',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Already reported for abuse'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
- else
- = link_to new_abuse_report_path(user_id: @user.id, ref_url: request.referer), class: link_classes + 'btn gl-button btn-default btn-icon',
- title: s_('UserProfile|Report abuse'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
- = sprite_icon('error')
+ = render Pajamas::ButtonComponent.new(href: new_abuse_report_path(user_id: @user.id, ref_url: request.referer),
+ icon: 'error',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Report abuse'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
- verified_gpg_keys = @user.gpg_keys.select(&:verified?)
- if verified_gpg_keys.any?
- = link_to user_gpg_keys_path,
- class: link_classes + 'btn btn-default btn-md gl-button btn-icon has-tooltip',
- title: n_('View public GPG key', 'View public GPG keys', verified_gpg_keys.length),
- data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
- = sprite_icon('key', css_class: 'gl-button-icon gl-icon')
+ = render Pajamas::ButtonComponent.new(href: user_gpg_keys_path,
+ icon: 'key',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: n_('View public GPG key', 'View public GPG keys', verified_gpg_keys.length), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
- if can?(current_user, :read_user_profile, @user)
- = link_to user_path(@user, rss_url_options), class: link_classes + 'btn gl-button btn-default btn-icon has-tooltip',
- title: s_('UserProfile|Subscribe'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
- = sprite_icon('rss')
+ = render Pajamas::ButtonComponent.new(href: user_path(@user, rss_url_options),
+ icon: 'rss',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|Subscribe'), data: { toggle: 'tooltip', placement: 'bottom', container: 'body' }})
- if current_user && current_user.admin?
- = link_to [:admin, @user], class: link_classes + 'btn gl-button btn-default btn-icon', title: s_('UserProfile|View user in admin area'),
- data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
- = sprite_icon('user')
+ = render Pajamas::ButtonComponent.new(href: [:admin, @user],
+ icon: 'user',
+ button_options: { class: 'gl-flex-grow-1 gl-mx-1 has-tooltip', title: s_('UserProfile|View user in admin area'), data: {toggle: 'tooltip', placement: 'bottom', container: 'body'}})
- if current_user && current_user.id != @user.id
- if current_user.following?(@user)
= form_tag user_unfollow_path(@user, :json), class: link_classes + 'gl-display-inline-block' do
@@ -58,12 +56,12 @@
- if @user.blocked? || !@user.confirmed?
.user-info
- .cover-title
+ %h1.cover-title
= user_display_name(@user)
= render "users/profile_basic_info"
- else
.user-info
- .cover-title{ itemprop: 'name' }
+ %h1.cover-title{ itemprop: 'name' }
= @user.name
- if @user.pronouns.present?
%span.gl-font-base.gl-text-gray-500.gl-vertical-align-middle
@@ -133,7 +131,6 @@
.profile-user-bio
= @user.bio
-
- unless profile_tabs.empty?
.scrolling-tabs-container
.fade-left= sprite_icon('chevron-lg-left', size: 12)
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index a0f6da57f9e..b9168a65764 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -147,6 +147,15 @@
:weight: 1
:idempotent: false
:tags: []
+- :name: container_repository_delete:container_registry_delete_container_repository
+ :worker_name: ContainerRegistry::DeleteContainerRepositoryWorker
+ :feature_category: :container_registry
+ :has_external_dependencies: false
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: cronjob:admin_email
:worker_name: AdminEmailWorker
:feature_category: :source_code_management
@@ -282,6 +291,15 @@
:weight: 1
:idempotent: false
:tags: []
+- :name: cronjob:container_registry_cleanup
+ :worker_name: ContainerRegistry::CleanupWorker
+ :feature_category: :container_registry
+ :has_external_dependencies: false
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: cronjob:container_registry_migration_enqueuer
:worker_name: ContainerRegistry::Migration::EnqueuerWorker
:feature_category: :container_registry
@@ -779,7 +797,7 @@
:tags: []
- :name: cronjob:users_deactivate_dormant_users
:worker_name: Users::DeactivateDormantUsersWorker
- :feature_category: :utilization
+ :feature_category: :subscription_cost_management
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
@@ -1146,6 +1164,15 @@
:weight: 1
:idempotent: false
:tags: []
+- :name: github_importer:github_import_pull_requests_import_review_request
+ :worker_name: Gitlab::GithubImport::PullRequests::ImportReviewRequestWorker
+ :feature_category: :importers
+ :has_external_dependencies: true
+ :urgency: :low
+ :resource_boundary: :cpu
+ :weight: 1
+ :idempotent: false
+ :tags: []
- :name: github_importer:github_import_refresh_import_jid
:worker_name: Gitlab::GithubImport::RefreshImportJidWorker
:feature_category: :importers
@@ -1245,6 +1272,15 @@
:weight: 1
:idempotent: false
:tags: []
+- :name: github_importer:github_import_stage_import_pull_requests_review_requests
+ :worker_name: Gitlab::GithubImport::Stage::ImportPullRequestsReviewRequestsWorker
+ :feature_category: :importers
+ :has_external_dependencies: false
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: false
+ :tags: []
- :name: github_importer:github_import_stage_import_pull_requests_reviews
:worker_name: Gitlab::GithubImport::Stage::ImportPullRequestsReviewsWorker
:feature_category: :importers
@@ -2694,6 +2730,15 @@
:weight: 1
:idempotent: true
:tags: []
+- :name: merge_requests_delete_branch
+ :worker_name: MergeRequests::DeleteBranchWorker
+ :feature_category: :source_code_management
+ :has_external_dependencies: false
+ :urgency: :high
+ :resource_boundary: :unknown
+ :weight: 1
+ :idempotent: true
+ :tags: []
- :name: merge_requests_delete_source_branch
:worker_name: MergeRequests::DeleteSourceBranchWorker
:feature_category: :source_code_management
@@ -3236,7 +3281,7 @@
:tags: []
- :name: update_highest_role
:worker_name: UpdateHighestRoleWorker
- :feature_category: :utilization
+ :feature_category: :subscription_usage_reports
:has_external_dependencies: false
:urgency: :high
:resource_boundary: :unknown
diff --git a/app/workers/authorized_keys_worker.rb b/app/workers/authorized_keys_worker.rb
index 039fe629a61..77f2ed5f495 100644
--- a/app/workers/authorized_keys_worker.rb
+++ b/app/workers/authorized_keys_worker.rb
@@ -7,8 +7,6 @@ class AuthorizedKeysWorker
sidekiq_options retry: 3
- PERMITTED_ACTIONS = %w[add_key remove_key].freeze
-
feature_category :source_code_management
urgency :high
weight 2
diff --git a/app/workers/bulk_imports/entity_worker.rb b/app/workers/bulk_imports/entity_worker.rb
index ada3210624c..d23d57c33ab 100644
--- a/app/workers/bulk_imports/entity_worker.rb
+++ b/app/workers/bulk_imports/entity_worker.rb
@@ -12,13 +12,18 @@ module BulkImports
worker_has_external_dependencies!
def perform(entity_id, current_stage = nil)
+ @entity = ::BulkImports::Entity.find(entity_id)
+
if stage_running?(entity_id, current_stage)
logger.info(
structured_payload(
bulk_import_entity_id: entity_id,
- bulk_import_id: bulk_import_id(entity_id),
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
current_stage: current_stage,
message: 'Stage running',
+ source_version: source_version,
importer: 'gitlab_migration'
)
)
@@ -29,9 +34,12 @@ module BulkImports
logger.info(
structured_payload(
bulk_import_entity_id: entity_id,
- bulk_import_id: bulk_import_id(entity_id),
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
current_stage: current_stage,
message: 'Stage starting',
+ source_version: source_version,
importer: 'gitlab_migration'
)
)
@@ -44,23 +52,34 @@ module BulkImports
)
end
rescue StandardError => e
- logger.error(
- structured_payload(
+ log_exception(e,
+ {
bulk_import_entity_id: entity_id,
- bulk_import_id: bulk_import_id(entity_id),
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
current_stage: current_stage,
- message: e.message,
+ message: 'Entity failed',
+ source_version: source_version,
importer: 'gitlab_migration'
- )
+ }
)
Gitlab::ErrorTracking.track_exception(
- e, bulk_import_entity_id: entity_id, bulk_import_id: bulk_import_id(entity_id), importer: 'gitlab_migration'
+ e,
+ bulk_import_entity_id: entity_id,
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
+ source_version: source_version,
+ importer: 'gitlab_migration'
)
end
private
+ attr_reader :entity
+
def stage_running?(entity_id, stage)
return unless stage
@@ -71,12 +90,18 @@ module BulkImports
BulkImports::Tracker.next_pipeline_trackers_for(entity_id).update(status_event: 'enqueue')
end
- def bulk_import_id(entity_id)
- @bulk_import_id ||= Entity.find(entity_id).bulk_import_id
+ def source_version
+ entity.bulk_import.source_version_info.to_s
end
def logger
@logger ||= Gitlab::Import::Logger.build
end
+
+ def log_exception(exception, payload)
+ Gitlab::ExceptionLogFormatter.format!(exception, payload)
+
+ logger.error(structured_payload(payload))
+ end
end
end
diff --git a/app/workers/bulk_imports/export_request_worker.rb b/app/workers/bulk_imports/export_request_worker.rb
index a57071ddcf1..1a5f6250429 100644
--- a/app/workers/bulk_imports/export_request_worker.rb
+++ b/app/workers/bulk_imports/export_request_worker.rb
@@ -22,7 +22,19 @@ module BulkImports
if e.retriable?(entity)
retry_request(e, entity)
else
- log_export_failure(e, entity)
+ log_exception(e,
+ {
+ bulk_import_entity_id: entity.id,
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
+ message: "Request to export #{entity.source_type} failed",
+ source_version: entity.bulk_import.source_version_info.to_s,
+ importer: 'gitlab_migration'
+ }
+ )
+
+ BulkImports::Failure.create(failure_attributes(e, entity))
entity.fail_op!
end
@@ -41,22 +53,7 @@ module BulkImports
)
end
- def log_export_failure(exception, entity)
- Gitlab::Import::Logger.error(
- structured_payload(
- log_attributes(exception, entity).merge(
- bulk_import_id: entity.bulk_import_id,
- bulk_import_entity_type: entity.source_type,
- message: "Request to export #{entity.source_type} failed",
- importer: 'gitlab_migration'
- )
- )
- )
-
- BulkImports::Failure.create(log_attributes(exception, entity))
- end
-
- def log_attributes(exception, entity)
+ def failure_attributes(exception, entity)
{
bulk_import_entity_id: entity.id,
pipeline_class: 'ExportRequestWorker',
@@ -84,15 +81,16 @@ module BulkImports
::GlobalID.parse(response.dig(*query.data_path, 'id')).model_id
rescue StandardError => e
- Gitlab::Import::Logger.error(
- structured_payload(
- log_attributes(e, entity).merge(
- message: 'Failed to fetch source entity id',
- bulk_import_id: entity.bulk_import_id,
- bulk_import_entity_type: entity.source_type,
- importer: 'gitlab_migration'
- )
- )
+ log_exception(e,
+ {
+ message: 'Failed to fetch source entity id',
+ bulk_import_entity_id: entity.id,
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
+ source_version: entity.bulk_import.source_version_info.to_s,
+ importer: 'gitlab_migration'
+ }
)
nil
@@ -107,18 +105,29 @@ module BulkImports
end
def retry_request(exception, entity)
- Gitlab::Import::Logger.error(
- structured_payload(
- log_attributes(exception, entity).merge(
- message: 'Retrying export request',
- bulk_import_id: entity.bulk_import_id,
- bulk_import_entity_type: entity.source_type,
- importer: 'gitlab_migration'
- )
- )
+ log_exception(exception,
+ {
+ message: 'Retrying export request',
+ bulk_import_entity_id: entity.id,
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
+ source_version: entity.bulk_import.source_version_info.to_s,
+ importer: 'gitlab_migration'
+ }
)
self.class.perform_in(2.seconds, entity.id)
end
+
+ def logger
+ @logger ||= Gitlab::Import::Logger.build
+ end
+
+ def log_exception(exception, payload)
+ Gitlab::ExceptionLogFormatter.format!(exception, payload)
+
+ logger.error(structured_payload(payload))
+ end
end
end
diff --git a/app/workers/bulk_imports/pipeline_worker.rb b/app/workers/bulk_imports/pipeline_worker.rb
index 6d314774cff..5716f6e3f31 100644
--- a/app/workers/bulk_imports/pipeline_worker.rb
+++ b/app/workers/bulk_imports/pipeline_worker.rb
@@ -17,24 +17,34 @@ module BulkImports
.find_by_id(pipeline_tracker_id)
if pipeline_tracker.present?
+ @entity = @pipeline_tracker.entity
+
logger.info(
structured_payload(
- bulk_import_entity_id: pipeline_tracker.entity.id,
- bulk_import_id: pipeline_tracker.entity.bulk_import_id,
+ bulk_import_entity_id: entity.id,
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
pipeline_name: pipeline_tracker.pipeline_name,
message: 'Pipeline starting',
+ source_version: source_version,
importer: 'gitlab_migration'
)
)
run
else
+ @entity = ::BulkImports::Entity.find(entity_id)
+
logger.error(
structured_payload(
bulk_import_entity_id: entity_id,
- bulk_import_id: bulk_import_id(entity_id),
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
pipeline_tracker_id: pipeline_tracker_id,
message: 'Unstarted pipeline not found',
+ source_version: source_version,
importer: 'gitlab_migration'
)
)
@@ -46,10 +56,10 @@ module BulkImports
private
- attr_reader :pipeline_tracker
+ attr_reader :pipeline_tracker, :entity
def run
- return skip_tracker if pipeline_tracker.entity.failed?
+ return skip_tracker if entity.failed?
raise(Pipeline::ExpiredError, 'Pipeline timeout') if job_timeout?
raise(Pipeline::FailedError, "Export from source instance failed: #{export_status.error}") if export_failed?
@@ -65,33 +75,39 @@ module BulkImports
fail_tracker(e)
end
- def bulk_import_id(entity_id)
- @bulk_import_id ||= Entity.find(entity_id).bulk_import_id
+ def source_version
+ entity.bulk_import.source_version_info.to_s
end
def fail_tracker(exception)
pipeline_tracker.update!(status_event: 'fail_op', jid: jid)
- logger.error(
- structured_payload(
- bulk_import_entity_id: pipeline_tracker.entity.id,
- bulk_import_id: pipeline_tracker.entity.bulk_import_id,
+ log_exception(exception,
+ {
+ bulk_import_entity_id: entity.id,
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
pipeline_name: pipeline_tracker.pipeline_name,
- message: exception.message,
+ message: 'Pipeline failed',
+ source_version: source_version,
importer: 'gitlab_migration'
- )
+ }
)
Gitlab::ErrorTracking.track_exception(
exception,
- bulk_import_entity_id: pipeline_tracker.entity.id,
- bulk_import_id: pipeline_tracker.entity.bulk_import_id,
+ bulk_import_entity_id: entity.id,
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
pipeline_name: pipeline_tracker.pipeline_name,
+ source_version: source_version,
importer: 'gitlab_migration'
)
BulkImports::Failure.create(
- bulk_import_entity_id: context.entity.id,
+ bulk_import_entity_id: entity.id,
pipeline_class: pipeline_tracker.pipeline_name,
pipeline_step: 'pipeline_worker_run',
exception_class: exception.class.to_s,
@@ -109,7 +125,7 @@ module BulkImports
delay,
pipeline_tracker.id,
pipeline_tracker.stage,
- pipeline_tracker.entity.id
+ entity.id
)
end
@@ -128,7 +144,7 @@ module BulkImports
def job_timeout?
return false unless file_extraction_pipeline?
- (Time.zone.now - pipeline_tracker.entity.created_at) > Pipeline::NDJSON_EXPORT_TIMEOUT
+ (Time.zone.now - entity.created_at) > Pipeline::NDJSON_EXPORT_TIMEOUT
end
def export_failed?
@@ -150,14 +166,17 @@ module BulkImports
end
def retry_tracker(exception)
- logger.error(
- structured_payload(
- bulk_import_entity_id: pipeline_tracker.entity.id,
- bulk_import_id: pipeline_tracker.entity.bulk_import_id,
+ log_exception(exception,
+ {
+ bulk_import_entity_id: entity.id,
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
pipeline_name: pipeline_tracker.pipeline_name,
- message: "Retrying error: #{exception.message}",
+ message: "Retrying pipeline",
+ source_version: source_version,
importer: 'gitlab_migration'
- )
+ }
)
pipeline_tracker.update!(status_event: 'retry', jid: jid)
@@ -168,15 +187,23 @@ module BulkImports
def skip_tracker
logger.info(
structured_payload(
- bulk_import_entity_id: pipeline_tracker.entity.id,
- bulk_import_id: pipeline_tracker.entity.bulk_import_id,
+ bulk_import_entity_id: entity.id,
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
pipeline_name: pipeline_tracker.pipeline_name,
message: 'Skipping pipeline due to failed entity',
+ source_version: source_version,
importer: 'gitlab_migration'
)
)
pipeline_tracker.update!(status_event: 'skip', jid: jid)
end
+
+ def log_exception(exception, payload)
+ Gitlab::ExceptionLogFormatter.format!(exception, payload)
+ logger.error(structured_payload(payload))
+ end
end
end
diff --git a/app/workers/cluster_configure_istio_worker.rb b/app/workers/cluster_configure_istio_worker.rb
index 0def66b7381..8bf723d89f7 100644
--- a/app/workers/cluster_configure_istio_worker.rb
+++ b/app/workers/cluster_configure_istio_worker.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+# DEPRECATED
+#
+# To be removed by https://gitlab.com/gitlab-org/gitlab/-/issues/366573
class ClusterConfigureIstioWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
@@ -10,9 +13,5 @@ class ClusterConfigureIstioWorker # rubocop:disable Scalability/IdempotentWorker
worker_has_external_dependencies!
- def perform(cluster_id)
- Clusters::Cluster.find_by_id(cluster_id).try do |cluster|
- Clusters::Kubernetes::ConfigureIstioIngressService.new(cluster: cluster).execute
- end
- end
+ def perform(cluster_id); end
end
diff --git a/app/workers/cluster_install_app_worker.rb b/app/workers/cluster_install_app_worker.rb
index e16e6e9ca71..0c94f8cad6a 100644
--- a/app/workers/cluster_install_app_worker.rb
+++ b/app/workers/cluster_install_app_worker.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+# DEPRECATED
+#
+# To be removed by https://gitlab.com/gitlab-org/gitlab/-/issues/366573
class ClusterInstallAppWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
@@ -12,9 +15,5 @@ class ClusterInstallAppWorker # rubocop:disable Scalability/IdempotentWorker
worker_has_external_dependencies!
loggable_arguments 0
- def perform(app_name, app_id)
- find_application(app_name, app_id) do |app|
- Clusters::Applications::InstallService.new(app).execute
- end
- end
+ def perform(app_name, app_id); end
end
diff --git a/app/workers/cluster_patch_app_worker.rb b/app/workers/cluster_patch_app_worker.rb
index bb16cf7a5e6..1ef9dc7f6fe 100644
--- a/app/workers/cluster_patch_app_worker.rb
+++ b/app/workers/cluster_patch_app_worker.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+# DEPRECATED
+#
+# To be removed by https://gitlab.com/gitlab-org/gitlab/-/issues/366573
class ClusterPatchAppWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
@@ -12,9 +15,5 @@ class ClusterPatchAppWorker # rubocop:disable Scalability/IdempotentWorker
worker_has_external_dependencies!
loggable_arguments 0
- def perform(app_name, app_id)
- find_application(app_name, app_id) do |app|
- Clusters::Applications::PatchService.new(app).execute
- end
- end
+ def perform(app_name, app_id); end
end
diff --git a/app/workers/cluster_update_app_worker.rb b/app/workers/cluster_update_app_worker.rb
index 97fdec02ba4..7d997c0a293 100644
--- a/app/workers/cluster_update_app_worker.rb
+++ b/app/workers/cluster_update_app_worker.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
# Deprecated, to be removed in %14.0 as part of https://gitlab.com/groups/gitlab-org/-/epics/4280
+# Also see https://gitlab.com/gitlab-org/gitlab/-/issues/366573
class ClusterUpdateAppWorker # rubocop:disable Scalability/IdempotentWorker
UpdateAlreadyInProgressError = Class.new(StandardError)
@@ -16,38 +17,5 @@ class ClusterUpdateAppWorker # rubocop:disable Scalability/IdempotentWorker
LEASE_TIMEOUT = 10.minutes.to_i
- def perform(app_name, app_id, project_id, scheduled_time)
- @app_id = app_id
-
- try_obtain_lease do
- execute(app_name, app_id, project_id, scheduled_time)
- end
- end
-
- private
-
- def execute(app_name, app_id, project_id, scheduled_time)
- project = Project.find_by_id(project_id)
- return unless project
-
- find_application(app_name, app_id) do |app|
- update_prometheus(app, scheduled_time, project)
- end
- end
-
- def update_prometheus(app, scheduled_time, project)
- return unless app.managed_prometheus?
- return if app.updated_since?(scheduled_time)
- return if app.update_in_progress?
-
- Clusters::Applications::PrometheusUpdateService.new(app, project).execute
- end
-
- def lease_key
- @lease_key ||= "#{self.class.name.underscore}-#{@app_id}"
- end
-
- def lease_timeout
- LEASE_TIMEOUT
- end
+ def perform(app_name, app_id, project_id, scheduled_time); end
end
diff --git a/app/workers/cluster_upgrade_app_worker.rb b/app/workers/cluster_upgrade_app_worker.rb
index bbe0cb7f0c2..40feee9374d 100644
--- a/app/workers/cluster_upgrade_app_worker.rb
+++ b/app/workers/cluster_upgrade_app_worker.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+# DEPRECATED
+#
+# To be removed by https://gitlab.com/gitlab-org/gitlab/-/issues/366573
class ClusterUpgradeAppWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
@@ -12,9 +15,5 @@ class ClusterUpgradeAppWorker # rubocop:disable Scalability/IdempotentWorker
worker_has_external_dependencies!
loggable_arguments 0
- def perform(app_name, app_id)
- find_application(app_name, app_id) do |app|
- Clusters::Applications::UpgradeService.new(app).execute
- end
- end
+ def perform(app_name, app_id); end
end
diff --git a/app/workers/cluster_wait_for_app_installation_worker.rb b/app/workers/cluster_wait_for_app_installation_worker.rb
index 846e4442233..ec291ddeb10 100644
--- a/app/workers/cluster_wait_for_app_installation_worker.rb
+++ b/app/workers/cluster_wait_for_app_installation_worker.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+# DEPRECATED
+#
+# To be removed by https://gitlab.com/gitlab-org/gitlab/-/issues/366573
class ClusterWaitForAppInstallationWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
@@ -16,9 +19,5 @@ class ClusterWaitForAppInstallationWorker # rubocop:disable Scalability/Idempote
worker_resource_boundary :cpu
loggable_arguments 0
- def perform(app_name, app_id)
- find_application(app_name, app_id) do |app|
- Clusters::Applications::CheckInstallationProgressService.new(app).execute
- end
- end
+ def perform(app_name, app_id); end
end
diff --git a/app/workers/cluster_wait_for_app_update_worker.rb b/app/workers/cluster_wait_for_app_update_worker.rb
index e96e03ae249..084e8b41a49 100644
--- a/app/workers/cluster_wait_for_app_update_worker.rb
+++ b/app/workers/cluster_wait_for_app_update_worker.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+# DEPRECATED
+#
+# To be removed by https://gitlab.com/gitlab-org/gitlab/-/issues/366573
class ClusterWaitForAppUpdateWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
@@ -14,9 +17,5 @@ class ClusterWaitForAppUpdateWorker # rubocop:disable Scalability/IdempotentWork
loggable_arguments 0
- def perform(app_name, app_id)
- find_application(app_name, app_id) do |app|
- ::Clusters::Applications::CheckUpgradeProgressService.new(app).execute
- end
- end
+ def perform(app_name, app_id); end
end
diff --git a/app/workers/cluster_wait_for_ingress_ip_address_worker.rb b/app/workers/cluster_wait_for_ingress_ip_address_worker.rb
index 561e72562e9..8983942c0fb 100644
--- a/app/workers/cluster_wait_for_ingress_ip_address_worker.rb
+++ b/app/workers/cluster_wait_for_ingress_ip_address_worker.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+# DEPRECATED
+#
+# To be removed by https://gitlab.com/gitlab-org/gitlab/-/issues/366573
class ClusterWaitForIngressIpAddressWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
@@ -12,9 +15,5 @@ class ClusterWaitForIngressIpAddressWorker # rubocop:disable Scalability/Idempot
worker_has_external_dependencies!
loggable_arguments 0
- def perform(app_name, app_id)
- find_application(app_name, app_id) do |app|
- Clusters::Applications::CheckIngressIpAddressService.new(app).execute
- end
- end
+ def perform(app_name, app_id); end
end
diff --git a/app/workers/clusters/applications/deactivate_integration_worker.rb b/app/workers/clusters/applications/deactivate_integration_worker.rb
index d1db99d21af..fca05e8ad2e 100644
--- a/app/workers/clusters/applications/deactivate_integration_worker.rb
+++ b/app/workers/clusters/applications/deactivate_integration_worker.rb
@@ -24,6 +24,8 @@ module Clusters
.include_integration(integration_association_name)
projects.find_each do |project|
+ # This use of public_send is safe because we constructed the
+ # integration_association_name ourselves above.
project.public_send(integration_association_name).update!(active: false) # rubocop:disable GitlabSecurity/PublicSend
end
end
diff --git a/app/workers/clusters/applications/wait_for_uninstall_app_worker.rb b/app/workers/clusters/applications/wait_for_uninstall_app_worker.rb
index 510ea8e7b17..974d99139a1 100644
--- a/app/workers/clusters/applications/wait_for_uninstall_app_worker.rb
+++ b/app/workers/clusters/applications/wait_for_uninstall_app_worker.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+# DEPRECATED
+#
+# To be removed by https://gitlab.com/gitlab-org/gitlab/-/issues/366573
module Clusters
module Applications
class WaitForUninstallAppWorker # rubocop:disable Scalability/IdempotentWorker
@@ -18,11 +21,7 @@ module Clusters
worker_resource_boundary :cpu
loggable_arguments 0
- def perform(app_name, app_id)
- find_application(app_name, app_id) do |app|
- Clusters::Applications::CheckUninstallProgressService.new(app).execute
- end
- end
+ def perform(app_name, app_id); end
end
end
end
diff --git a/app/workers/concerns/limited_capacity/job_tracker.rb b/app/workers/concerns/limited_capacity/job_tracker.rb
index a1eb4e45027..4b5ce8a01f6 100644
--- a/app/workers/concerns/limited_capacity/job_tracker.rb
+++ b/app/workers/concerns/limited_capacity/job_tracker.rb
@@ -58,7 +58,7 @@ module LimitedCapacity
end
def remove_job_keys(redis, keys)
- redis.srem(counter_key, keys)
+ redis.srem?(counter_key, keys)
end
def with_redis(&block)
diff --git a/app/workers/container_registry/cleanup_worker.rb b/app/workers/container_registry/cleanup_worker.rb
new file mode 100644
index 00000000000..8350ae3431b
--- /dev/null
+++ b/app/workers/container_registry/cleanup_worker.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+module ContainerRegistry
+ class CleanupWorker
+ include ApplicationWorker
+ # we don't have any project, user or group context here
+ include CronjobQueue # rubocop:disable Scalability/CronWorkerContext
+
+ data_consistency :always
+ idempotent!
+
+ feature_category :container_registry
+
+ STALE_DELETE_THRESHOLD = 30.minutes.freeze
+ BATCH_SIZE = 200
+
+ def perform
+ return unless Feature.enabled?(:container_registry_delete_repository_with_cron_worker)
+
+ log_counts
+
+ reset_stale_deletes
+
+ enqueue_delete_container_repository_jobs if ContainerRepository.delete_scheduled.exists?
+ end
+
+ private
+
+ def reset_stale_deletes
+ ContainerRepository.delete_ongoing.each_batch(of: BATCH_SIZE) do |batch|
+ batch.with_stale_delete_at(STALE_DELETE_THRESHOLD.ago).update_all(
+ status: :delete_scheduled,
+ delete_started_at: nil
+ )
+ end
+ end
+
+ def enqueue_delete_container_repository_jobs
+ ContainerRegistry::DeleteContainerRepositoryWorker.perform_with_capacity
+ end
+
+ def log_counts
+ ::Gitlab::Database::LoadBalancing::Session.current.use_replicas_for_read_queries do
+ log_extra_metadata_on_done(
+ :delete_scheduled_container_repositories_count,
+ ContainerRepository.delete_scheduled.count
+ )
+ log_extra_metadata_on_done(
+ :stale_delete_container_repositories_count,
+ stale_delete_container_repositories.count
+ )
+ end
+ end
+
+ def stale_delete_container_repositories
+ ContainerRepository.delete_ongoing.with_stale_delete_at(STALE_DELETE_THRESHOLD.ago)
+ end
+ end
+end
diff --git a/app/workers/container_registry/delete_container_repository_worker.rb b/app/workers/container_registry/delete_container_repository_worker.rb
new file mode 100644
index 00000000000..1f94b1b9e71
--- /dev/null
+++ b/app/workers/container_registry/delete_container_repository_worker.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+module ContainerRegistry
+ class DeleteContainerRepositoryWorker
+ include ApplicationWorker
+ include LimitedCapacity::Worker
+ include Gitlab::Utils::StrongMemoize
+ extend ::Gitlab::Utils::Override
+
+ data_consistency :always
+ queue_namespace :container_repository_delete
+ feature_category :container_registry
+ urgency :low
+ worker_resource_boundary :unknown
+ idempotent!
+
+ MAX_CAPACITY = 2
+ CLEANUP_TAGS_SERVICE_PARAMS = {
+ 'name_regex_delete' => '.*',
+ 'container_expiration_policy' => true # to avoid permissions checks
+ }.freeze
+
+ def perform_work
+ return unless next_container_repository
+
+ result = delete_tags
+ log_delete_tags_service_result(next_container_repository, result)
+
+ if result[:status] == :error || next_container_repository.tags_count != 0
+ return next_container_repository.set_delete_scheduled_status
+ end
+
+ next_container_repository.destroy!
+ rescue StandardError => exception
+ next_container_repository&.set_delete_scheduled_status
+
+ Gitlab::ErrorTracking.log_exception(exception, class: self.class.name)
+ end
+
+ def remaining_work_count
+ ::ContainerRepository.delete_scheduled.limit(max_running_jobs + 1).count
+ end
+
+ def max_running_jobs
+ MAX_CAPACITY
+ end
+
+ private
+
+ def delete_tags
+ service = Projects::ContainerRepository::CleanupTagsService.new(
+ container_repository: next_container_repository,
+ params: CLEANUP_TAGS_SERVICE_PARAMS
+ )
+ service.execute
+ end
+
+ def next_container_repository
+ strong_memoize(:next_container_repository) do
+ ContainerRepository.transaction do
+ # we don't care about the order
+ repository = ContainerRepository.next_pending_destruction(order_by: nil)
+
+ repository&.tap(&:set_delete_ongoing_status)
+ end
+ end
+ end
+
+ def log_delete_tags_service_result(container_repository, delete_tags_service_result)
+ logger.info(
+ structured_payload(
+ project_id: container_repository.project_id,
+ container_repository_id: container_repository.id,
+ container_repository_path: container_repository.path,
+ tags_size_before_delete: delete_tags_service_result[:original_size],
+ deleted_tags_size: delete_tags_service_result[:deleted_size]
+ )
+ )
+ end
+ end
+end
diff --git a/app/workers/database/batched_background_migration/execution_worker.rb b/app/workers/database/batched_background_migration/execution_worker.rb
new file mode 100644
index 00000000000..098153c742f
--- /dev/null
+++ b/app/workers/database/batched_background_migration/execution_worker.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+module Database
+ module BatchedBackgroundMigration
+ class ExecutionWorker # rubocop:disable Scalability/IdempotentWorker
+ include ExclusiveLeaseGuard
+ include Gitlab::Utils::StrongMemoize
+
+ INTERVAL_VARIANCE = 5.seconds.freeze
+ LEASE_TIMEOUT_MULTIPLIER = 3
+
+ def perform(database_name, migration_id)
+ self.database_name = database_name
+
+ return unless enabled?
+ return if shares_db_config?
+
+ Gitlab::Database::SharedModel.using_connection(base_model.connection) do
+ self.migration = find_migration(migration_id)
+
+ break unless migration
+
+ try_obtain_lease do
+ run_migration_job if executable_migration?
+ end
+ end
+ end
+
+ private
+
+ attr_accessor :database_name, :migration
+
+ def enabled?
+ Feature.enabled?(:execute_batched_migrations_on_schedule, type: :ops)
+ end
+
+ def shares_db_config?
+ Gitlab::Database.db_config_share_with(base_model.connection_db_config).present?
+ end
+
+ def base_model
+ strong_memoize(:base_model) do
+ Gitlab::Database.database_base_models[database_name]
+ end
+ end
+
+ def find_migration(id)
+ Gitlab::Database::BackgroundMigration::BatchedMigration.find_executable(id, connection: base_model.connection)
+ end
+
+ def lease_key
+ @lease_key ||= [
+ self.class.name.underscore,
+ 'database_name',
+ database_name,
+ 'table_name',
+ migration.table_name
+ ].join(':')
+ end
+
+ def lease_timeout
+ migration.interval * LEASE_TIMEOUT_MULTIPLIER
+ end
+
+ def executable_migration?
+ migration.active? && migration.interval_elapsed?(variance: INTERVAL_VARIANCE)
+ end
+
+ def run_migration_job
+ Gitlab::Database::BackgroundMigration::BatchedMigrationRunner.new(connection: base_model.connection)
+ .run_migration_job(migration)
+ end
+ end
+ end
+end
diff --git a/app/workers/database/batched_background_migration/single_database_worker.rb b/app/workers/database/batched_background_migration/single_database_worker.rb
index cfbd44ba397..0c7c51d5c0a 100644
--- a/app/workers/database/batched_background_migration/single_database_worker.rb
+++ b/app/workers/database/batched_background_migration/single_database_worker.rb
@@ -58,14 +58,7 @@ module Database
break unless self.class.enabled? && active_migration
with_exclusive_lease(active_migration.interval) do
- # Now that we have the exclusive lease, reload migration in case another process has changed it.
- # This is a temporary solution until we have better concurrency handling around job execution
- #
- # We also have to disable this cop, because ApplicationRecord aliases reset to reload, but our database
- # models don't inherit from ApplicationRecord
- active_migration.reload # rubocop:disable Cop/ActiveRecordAssociationReload
-
- run_active_migration if active_migration.active? && active_migration.interval_elapsed?(variance: INTERVAL_VARIANCE)
+ run_active_migration
end
end
end
@@ -77,7 +70,7 @@ module Database
end
def run_active_migration
- Gitlab::Database::BackgroundMigration::BatchedMigrationRunner.new(connection: base_model.connection).run_migration_job(active_migration)
+ Database::BatchedBackgroundMigration::ExecutionWorker.new.perform(self.class.tracking_database, active_migration.id)
end
def base_model
diff --git a/app/workers/gitlab/github_import/advance_stage_worker.rb b/app/workers/gitlab/github_import/advance_stage_worker.rb
index fdf4ec6f396..a9f645bd634 100644
--- a/app/workers/gitlab/github_import/advance_stage_worker.rb
+++ b/app/workers/gitlab/github_import/advance_stage_worker.rb
@@ -21,6 +21,7 @@ module Gitlab
# The known importer stages and their corresponding Sidekiq workers.
STAGES = {
pull_requests_merged_by: Stage::ImportPullRequestsMergedByWorker,
+ pull_request_review_requests: Stage::ImportPullRequestsReviewRequestsWorker,
pull_request_reviews: Stage::ImportPullRequestsReviewsWorker,
issues_and_diff_notes: Stage::ImportIssuesAndDiffNotesWorker,
issue_events: Stage::ImportIssueEventsWorker,
diff --git a/app/workers/gitlab/github_import/pull_requests/import_review_request_worker.rb b/app/workers/gitlab/github_import/pull_requests/import_review_request_worker.rb
new file mode 100644
index 00000000000..e475a39810d
--- /dev/null
+++ b/app/workers/gitlab/github_import/pull_requests/import_review_request_worker.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module GithubImport
+ module PullRequests
+ class ImportReviewRequestWorker # rubocop:disable Scalability/IdempotentWorker
+ include ObjectImporter
+
+ worker_resource_boundary :cpu
+
+ def representation_class
+ Gitlab::GithubImport::Representation::PullRequests::ReviewRequests
+ end
+
+ def importer_class
+ Importer::PullRequests::ReviewRequestImporter
+ end
+
+ def object_type
+ :pull_request_review_request
+ end
+ end
+ end
+ end
+end
diff --git a/app/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker.rb b/app/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker.rb
index 8c2d652a689..9b123b5776a 100644
--- a/app/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker.rb
+++ b/app/workers/gitlab/github_import/stage/import_pull_requests_merged_by_worker.rb
@@ -24,7 +24,7 @@ module Gitlab
AdvanceStageWorker.perform_async(
project.id,
{ waiter.key => waiter.jobs_remaining },
- :pull_request_reviews
+ :pull_request_review_requests
)
end
end
diff --git a/app/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker.rb b/app/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker.rb
new file mode 100644
index 00000000000..bcbf5dd471a
--- /dev/null
+++ b/app/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module GithubImport
+ module Stage
+ class ImportPullRequestsReviewRequestsWorker # 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)
+ waiter = Importer::PullRequests::ReviewRequestsImporter
+ .new(project, client)
+ .execute
+
+ project.import_state.refresh_jid_expiration
+
+ AdvanceStageWorker.perform_async(
+ project.id,
+ { waiter.key => waiter.jobs_remaining },
+ :pull_request_reviews
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/app/workers/gitlab_performance_bar_stats_worker.rb b/app/workers/gitlab_performance_bar_stats_worker.rb
index 6d637ad1586..0b31c159726 100644
--- a/app/workers/gitlab_performance_bar_stats_worker.rb
+++ b/app/workers/gitlab_performance_bar_stats_worker.rb
@@ -18,7 +18,7 @@ class GitlabPerformanceBarStatsWorker
idempotent!
def perform(lease_uuid)
- Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
request_ids = fetch_request_ids(redis, lease_uuid)
stats = Gitlab::PerformanceBar::Stats.new(redis)
@@ -30,6 +30,10 @@ class GitlabPerformanceBarStatsWorker
private
+ def with_redis(&block)
+ Gitlab::Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord
+ end
+
def fetch_request_ids(redis, lease_uuid)
ids = redis.smembers(STATS_KEY)
redis.del(STATS_KEY)
diff --git a/app/workers/gitlab_shell_worker.rb b/app/workers/gitlab_shell_worker.rb
index 1bcaf5a42be..2f396dcdb86 100644
--- a/app/workers/gitlab_shell_worker.rb
+++ b/app/workers/gitlab_shell_worker.rb
@@ -14,18 +14,12 @@ class GitlabShellWorker # rubocop:disable Scalability/IdempotentWorker
loggable_arguments 0
def perform(action, *arg)
- # Gitlab::Shell is being removed but we need to continue to process jobs
- # enqueued in the previous release, so handle them here.
- #
- # See https://gitlab.com/gitlab-org/gitlab/-/issues/25095 for more details
- if AuthorizedKeysWorker::PERMITTED_ACTIONS.include?(action.to_s)
- AuthorizedKeysWorker.new.perform(action, *arg)
-
- return
+ if ::Feature.enabled?(:verify_gitlab_shell_worker_method_names) && Gitlab::Shell::PERMITTED_ACTIONS.exclude?(action)
+ raise(ArgumentError, "#{action} not allowed for #{self.class.name}")
end
Gitlab::GitalyClient::NamespaceService.allow do
- gitlab_shell.__send__(action, *arg) # rubocop:disable GitlabSecurity/PublicSend
+ gitlab_shell.public_send(action, *arg) # rubocop:disable GitlabSecurity/PublicSend
end
end
end
diff --git a/app/workers/incident_management/add_severity_system_note_worker.rb b/app/workers/incident_management/add_severity_system_note_worker.rb
index 3a4667bea0a..b2d2d6748ee 100644
--- a/app/workers/incident_management/add_severity_system_note_worker.rb
+++ b/app/workers/incident_management/add_severity_system_note_worker.rb
@@ -21,7 +21,10 @@ module IncidentManagement
user = User.find_by_id(user_id)
return unless user
- SystemNoteService.change_incident_severity(incident, user)
+ incident.transaction do
+ SystemNoteService.change_incident_severity(incident, user)
+ TimelineEvents::CreateService.change_severity(incident, user)
+ end
end
end
end
diff --git a/app/workers/loose_foreign_keys/cleanup_worker.rb b/app/workers/loose_foreign_keys/cleanup_worker.rb
index 0a3a834578a..9a0909598bb 100644
--- a/app/workers/loose_foreign_keys/cleanup_worker.rb
+++ b/app/workers/loose_foreign_keys/cleanup_worker.rb
@@ -12,7 +12,11 @@ module LooseForeignKeys
idempotent!
def perform
- in_lock(self.class.name.underscore, ttl: ModificationTracker::MAX_RUNTIME, retries: 0) do
+ # Add small buffer on MAX_RUNTIME to account for single long running
+ # query or extra worker time after the cleanup.
+ lock_ttl = ModificationTracker::MAX_RUNTIME + 20.seconds
+
+ in_lock(self.class.name.underscore, ttl: lock_ttl, retries: 0) do
stats = {}
connection_name, base_model = current_connection_name_and_base_model
diff --git a/app/workers/mail_scheduler/notification_service_worker.rb b/app/workers/mail_scheduler/notification_service_worker.rb
index 25c9ac5547b..12e8de4491e 100644
--- a/app/workers/mail_scheduler/notification_service_worker.rb
+++ b/app/workers/mail_scheduler/notification_service_worker.rb
@@ -18,6 +18,12 @@ module MailScheduler
def perform(meth, *args)
check_arguments!(args)
+ if ::Feature.enabled?(:verify_mail_scheduler_notification_service_worker_method_names) &&
+ NotificationService.permitted_actions.exclude?(meth.to_sym)
+
+ raise(ArgumentError, "#{meth} not allowed for #{self.class.name}")
+ end
+
deserialized_args = ActiveJob::Arguments.deserialize(args)
notification_service.public_send(meth, *deserialized_args) # rubocop:disable GitlabSecurity/PublicSend
rescue ActiveJob::DeserializationError
diff --git a/app/workers/merge_requests/delete_branch_worker.rb b/app/workers/merge_requests/delete_branch_worker.rb
new file mode 100644
index 00000000000..6816f9a4b77
--- /dev/null
+++ b/app/workers/merge_requests/delete_branch_worker.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module MergeRequests
+ class DeleteBranchWorker
+ include ApplicationWorker
+
+ data_consistency :always
+
+ feature_category :source_code_management
+ urgency :high
+ idempotent!
+
+ def perform(merge_request_id, user_id, branch_name, retarget_branch)
+ merge_request = MergeRequest.find_by_id(merge_request_id)
+ user = User.find_by_id(user_id)
+
+ return unless merge_request.present? && user.present?
+
+ ::Branches::DeleteService.new(merge_request.source_project, user).execute(branch_name)
+
+ return unless retarget_branch
+
+ ::MergeRequests::RetargetChainService.new(project: merge_request.source_project, current_user: user)
+ .execute(merge_request)
+ end
+ end
+end
diff --git a/app/workers/merge_requests/delete_source_branch_worker.rb b/app/workers/merge_requests/delete_source_branch_worker.rb
index 66392c670b5..96dde413d5b 100644
--- a/app/workers/merge_requests/delete_source_branch_worker.rb
+++ b/app/workers/merge_requests/delete_source_branch_worker.rb
@@ -18,15 +18,14 @@ class MergeRequests::DeleteSourceBranchWorker
# Source branch changed while it's being removed
return if merge_request.source_branch_sha != source_branch_sha
- delete_service_result = ::Branches::DeleteService.new(merge_request.source_project, user)
- .execute(merge_request.source_branch)
+ if Feature.enabled?(:add_delete_branch_worker, merge_request.source_project)
+ ::MergeRequests::DeleteBranchWorker.perform_async(merge_request_id, user_id, merge_request.source_branch, true)
+ else
+ ::Branches::DeleteService.new(merge_request.source_project, user).execute(merge_request.source_branch)
- if Feature.enabled?(:track_delete_source_errors, merge_request.source_project)
- delete_service_result.track_exception if delete_service_result&.error?
+ ::MergeRequests::RetargetChainService.new(project: merge_request.source_project, current_user: user)
+ .execute(merge_request)
end
-
- ::MergeRequests::RetargetChainService.new(project: merge_request.source_project, current_user: user)
- .execute(merge_request)
rescue ActiveRecord::RecordNotFound
end
end
diff --git a/app/workers/namespaces/root_statistics_worker.rb b/app/workers/namespaces/root_statistics_worker.rb
index e1271dae335..e3aa8a1f779 100644
--- a/app/workers/namespaces/root_statistics_worker.rb
+++ b/app/workers/namespaces/root_statistics_worker.rb
@@ -4,13 +4,14 @@ module Namespaces
class RootStatisticsWorker
include ApplicationWorker
- data_consistency :always
+ data_consistency :sticky, feature_flag: :root_statistics_worker_read_replica
sidekiq_options retry: 3
queue_namespace :update_namespace_statistics
feature_category :source_code_management
idempotent!
+ deduplicate :until_executed, if_deduplicated: :reschedule_once
def perform(namespace_id)
namespace = Namespace.find(namespace_id)
diff --git a/app/workers/onboarding/issue_created_worker.rb b/app/workers/onboarding/issue_created_worker.rb
index ff39fefad81..73e96850786 100644
--- a/app/workers/onboarding/issue_created_worker.rb
+++ b/app/workers/onboarding/issue_created_worker.rb
@@ -22,6 +22,3 @@ module Onboarding
end
end
end
-
-# remove in %15.6 as per https://gitlab.com/gitlab-org/gitlab/-/issues/372432
-Namespaces::OnboardingIssueCreatedWorker = Onboarding::IssueCreatedWorker
diff --git a/app/workers/onboarding/pipeline_created_worker.rb b/app/workers/onboarding/pipeline_created_worker.rb
index 6bd5863b0e0..c6e84882d6f 100644
--- a/app/workers/onboarding/pipeline_created_worker.rb
+++ b/app/workers/onboarding/pipeline_created_worker.rb
@@ -22,6 +22,3 @@ module Onboarding
end
end
end
-
-# remove in %15.6 as per https://gitlab.com/gitlab-org/gitlab/-/issues/372432
-Namespaces::OnboardingPipelineCreatedWorker = Onboarding::PipelineCreatedWorker
diff --git a/app/workers/onboarding/progress_worker.rb b/app/workers/onboarding/progress_worker.rb
index 525934c4a7c..34503bfa451 100644
--- a/app/workers/onboarding/progress_worker.rb
+++ b/app/workers/onboarding/progress_worker.rb
@@ -23,6 +23,3 @@ module Onboarding
end
end
end
-
-# remove in %15.6 as per https://gitlab.com/gitlab-org/gitlab/-/issues/372432
-Namespaces::OnboardingProgressWorker = Onboarding::ProgressWorker
diff --git a/app/workers/onboarding/user_added_worker.rb b/app/workers/onboarding/user_added_worker.rb
index 38e9cd063ea..b096bf752dc 100644
--- a/app/workers/onboarding/user_added_worker.rb
+++ b/app/workers/onboarding/user_added_worker.rb
@@ -19,6 +19,3 @@ module Onboarding
end
end
end
-
-# remove in %15.6 as per https://gitlab.com/gitlab-org/gitlab/-/issues/372432
-Namespaces::OnboardingUserAddedWorker = Onboarding::UserAddedWorker
diff --git a/app/workers/pages_worker.rb b/app/workers/pages_worker.rb
index 3aff4b42629..adb6d38fd12 100644
--- a/app/workers/pages_worker.rb
+++ b/app/workers/pages_worker.rb
@@ -11,7 +11,7 @@ class PagesWorker # rubocop:disable Scalability/IdempotentWorker
worker_resource_boundary :cpu
def perform(action, *arg)
- send(action, *arg) # rubocop:disable GitlabSecurity/PublicSend
+ deploy(*arg) if action == 'deploy'
end
def deploy(build_id)
diff --git a/app/workers/projects/inactive_projects_deletion_cron_worker.rb b/app/workers/projects/inactive_projects_deletion_cron_worker.rb
index ba6d44ec4a5..af62efeb089 100644
--- a/app/workers/projects/inactive_projects_deletion_cron_worker.rb
+++ b/app/workers/projects/inactive_projects_deletion_cron_worker.rb
@@ -90,22 +90,26 @@ module Projects
end
def save_last_processed_project_id(project_id)
- Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.set(LAST_PROCESSED_INACTIVE_PROJECT_REDIS_KEY, project_id)
end
end
def last_processed_project_id
- Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.get(LAST_PROCESSED_INACTIVE_PROJECT_REDIS_KEY).to_i
end
end
def reset_last_processed_project_id
- Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.del(LAST_PROCESSED_INACTIVE_PROJECT_REDIS_KEY)
end
end
+
+ def with_redis(&block)
+ Gitlab::Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord
+ end
end
end
diff --git a/app/workers/projects/post_creation_worker.rb b/app/workers/projects/post_creation_worker.rb
index 3a39bd17ce3..886919ecace 100644
--- a/app/workers/projects/post_creation_worker.rb
+++ b/app/workers/projects/post_creation_worker.rb
@@ -17,6 +17,7 @@ module Projects
return unless project
create_prometheus_integration(project)
+ create_incident_management_timeline_event_tags(project)
end
private
@@ -34,5 +35,19 @@ module Projects
rescue ActiveRecord::RecordInvalid => e
Gitlab::ErrorTracking.track_exception(e, extra: { project_id: project.id })
end
+
+ def create_incident_management_timeline_event_tags(project)
+ tags = project.incident_management_timeline_event_tags.pluck_names
+ start_time_name = ::IncidentManagement::TimelineEventTag::START_TIME_TAG_NAME
+ end_time_name = ::IncidentManagement::TimelineEventTag::END_TIME_TAG_NAME
+
+ project.incident_management_timeline_event_tags.new(name: start_time_name) unless tags.include?(start_time_name)
+
+ project.incident_management_timeline_event_tags.new(name: end_time_name) unless tags.include?(end_time_name)
+
+ project.save!
+ rescue StandardError => e
+ Gitlab::ErrorTracking.track_exception(e, extra: { project_id: project.id })
+ end
end
end
diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb
index 413bb135943..5e89b9f3362 100644
--- a/app/workers/repository_import_worker.rb
+++ b/app/workers/repository_import_worker.rb
@@ -33,11 +33,9 @@ class RepositoryImportWorker # rubocop:disable Scalability/IdempotentWorker
if result[:status] == :error
fail_import(result[:message])
-
- raise result[:message]
+ else
+ project.after_import
end
-
- project.after_import
end
private
diff --git a/app/workers/run_pipeline_schedule_worker.rb b/app/workers/run_pipeline_schedule_worker.rb
index 35e3e633c70..8974ddce47b 100644
--- a/app/workers/run_pipeline_schedule_worker.rb
+++ b/app/workers/run_pipeline_schedule_worker.rb
@@ -21,13 +21,14 @@ class RunPipelineScheduleWorker # rubocop:disable Scalability/IdempotentWorker
end
def run_pipeline_schedule(schedule, user)
- Ci::CreatePipelineService.new(schedule.project,
- user,
- ref: schedule.ref)
- .execute!(:schedule, ignore_skip_ci: true, save_on_errors: false, schedule: schedule)
- rescue Ci::CreatePipelineService::CreateError => e
+ response = Ci::CreatePipelineService
+ .new(schedule.project, user, ref: schedule.ref)
+ .execute(:schedule, ignore_skip_ci: true, save_on_errors: false, schedule: schedule)
+
+ return response if response.payload.persisted?
+
# This is a user operation error such as corrupted .gitlab-ci.yml. Log the error for debugging purpose.
- log_extra_metadata_on_done(:pipeline_creation_error, e)
+ log_extra_metadata_on_done(:pipeline_creation_error, response.message)
rescue StandardError => e
error(schedule, e)
end
diff --git a/app/workers/update_highest_role_worker.rb b/app/workers/update_highest_role_worker.rb
index 064b8203d4d..a05c9c7a1e7 100644
--- a/app/workers/update_highest_role_worker.rb
+++ b/app/workers/update_highest_role_worker.rb
@@ -7,7 +7,7 @@ class UpdateHighestRoleWorker
sidekiq_options retry: 3
- feature_category :utilization
+ feature_category :subscription_usage_reports
urgency :high
weight 2
diff --git a/app/workers/users/deactivate_dormant_users_worker.rb b/app/workers/users/deactivate_dormant_users_worker.rb
index b14b7e67450..c3799480b12 100644
--- a/app/workers/users/deactivate_dormant_users_worker.rb
+++ b/app/workers/users/deactivate_dormant_users_worker.rb
@@ -8,7 +8,7 @@ module Users
include CronjobQueue
- feature_category :utilization
+ feature_category :subscription_cost_management
def perform
return if Gitlab.com?
diff --git a/app/workers/users/migrate_records_to_ghost_user_in_batches_worker.rb b/app/workers/users/migrate_records_to_ghost_user_in_batches_worker.rb
index ddddfc106ae..d9a80b6e899 100644
--- a/app/workers/users/migrate_records_to_ghost_user_in_batches_worker.rb
+++ b/app/workers/users/migrate_records_to_ghost_user_in_batches_worker.rb
@@ -12,8 +12,6 @@ module Users
idempotent!
def perform
- return unless Feature.enabled?(:user_destroy_with_limited_execution_time_worker)
-
in_lock(self.class.name.underscore, ttl: Gitlab::Utils::ExecutionTracker::MAX_RUNTIME, retries: 0) do
Users::MigrateRecordsToGhostUserInBatchesService.new.execute
end
diff --git a/bin/audit-event-type b/bin/audit-event-type
new file mode 100755
index 00000000000..8704dcfc0b0
--- /dev/null
+++ b/bin/audit-event-type
@@ -0,0 +1,354 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+#
+# Generate an audit event type file in the correct location.
+#
+# Automatically stages the file and amends the previous commit if the `--amend`
+# argument is used.
+
+require 'optparse'
+require 'yaml'
+require 'fileutils'
+require 'uri'
+require 'readline'
+
+require_relative '../lib/gitlab/audit/type/shared' unless defined?(::Gitlab::Audit::Type::Shared)
+require_relative '../lib/gitlab/utils' unless defined?(::Gitlab::Utils)
+
+module AuditEventTypeHelpers
+ Abort = Class.new(StandardError)
+ Done = Class.new(StandardError)
+
+ def capture_stdout(cmd)
+ output = IO.popen(cmd, &:read)
+ fail_with "command failed: #{cmd.join(' ')}" unless $?.success?
+ output
+ end
+
+ def fail_with(message)
+ raise Abort, "\e[31merror\e[0m #{message}"
+ end
+end
+
+class AuditEventTypeOptionParser
+ extend AuditEventTypeHelpers
+
+ Options = Struct.new(
+ :name,
+ :description,
+ :group,
+ :milestone,
+ :saved_to_database,
+ :streamed,
+ :ee,
+ :jh,
+ :amend,
+ :dry_run,
+ :force,
+ :introduced_by_issue,
+ :introduced_by_mr
+ )
+
+ class << self
+ def parse(argv)
+ options = Options.new
+
+ parser = OptionParser.new do |opts|
+ opts.banner = "Usage: #{__FILE__} [options] <audit-event-type>\n\n"
+
+ # Note: We do not provide a shorthand for this in order to match the `git
+ # commit` interface
+ opts.on('--amend', 'Amend the previous commit') do |value|
+ options.amend = value
+ end
+
+ opts.on('-f', '--force', 'Overwrite an existing entry') do |value|
+ options.force = value
+ end
+
+ opts.on('-d', '--description [string]', String,
+'A human-readable description of how this event is triggered') do |value|
+ options.description = value
+ end
+
+ opts.on('-g', '--group [string]', String,
+"Name of the group that introduced this audit event. For example, govern::compliance") do |value|
+ options.group = value
+ end
+
+ opts.on('-M', '--milestone [string]', String,
+'Milestone that introduced this audit event type. For example, 15.8') do |value|
+ options.milestone = value
+ end
+
+ opts.on('-s', '--[no-]saved-to-database',
+"Indicate whether to persist events to database and JSON logs") do |value|
+ options.saved_to_database = value
+ end
+
+ opts.on('-t', '--[no-]streamed',
+"Indicate that events should be streamed to external services (if configured)") do |value|
+ options.streamed = value
+ end
+
+ opts.on('-n', '--dry-run', "Don't actually write anything, just print") do |value|
+ options.dry_run = value
+ end
+
+ opts.on('-e', '--ee', 'Generate an audit event type entry for GitLab EE') do |value|
+ options.ee = value
+ end
+
+ opts.on('-j', '--jh', 'Generate an audit event type entry for GitLab JH') do |value|
+ options.jh = value
+ end
+
+ opts.on('-m', '--introduced-by-mr [string]', String,
+'URL to GitLab merge request that added this type of audit event') do |value|
+ options.introduced_by_mr = value
+ end
+
+ opts.on('-i', '--introduced-by-issue [string]', String,
+'URL to GitLab issue that added this type of audit event') do |value|
+ options.introduced_by_issue = value
+ end
+
+ opts.on('-h', '--help', 'Print help message') do
+ $stdout.puts opts
+ raise Done
+ end
+ end
+
+ parser.parse!(argv)
+
+ unless argv.one?
+ $stdout.puts parser.help
+ $stdout.puts
+ raise Abort, 'Name for the type of audit event is required'
+ end
+
+ options.name = argv.first.downcase.tr('-', '_')
+
+ options
+ end
+
+ def read_description
+ $stdout.puts
+ $stdout.puts ">> Specify a human-readable description of how this event is triggered:"
+
+ loop do
+ description = Readline.readline('?> ', false)&.strip
+ description = nil if description.empty?
+ return description unless description.nil?
+
+ warn "description is a required field."
+ end
+ end
+
+ def read_group
+ $stdout.puts
+ $stdout.puts ">> Specify the group introducing the audit event type, like `govern::compliance`:"
+
+ loop do
+ group = Readline.readline('?> ', false)&.strip
+ group = nil if group.empty?
+ return group unless group.nil?
+
+ warn "group is a required field."
+ end
+ end
+
+ def read_saved_to_database
+ $stdout.puts
+ $stdout.puts ">> Specify whether to persist events to database and JSON logs [yes, no]:"
+
+ loop do
+ saved_to_database = Readline.readline('?> ', false)&.strip
+ saved_to_database = Gitlab::Utils.to_boolean(saved_to_database)
+ return saved_to_database unless saved_to_database.nil?
+
+ warn "saved_to_database is a required boolean field."
+ end
+ end
+
+ def read_streamed
+ $stdout.puts
+ $stdout.puts ">> Specify if events should be streamed to external services (if configured) [yes, no]:"
+
+ loop do
+ streamed = Readline.readline('?> ', false)&.strip
+ streamed = Gitlab::Utils.to_boolean(streamed)
+ return streamed unless streamed.nil?
+
+ warn "streamed is a required boolean field."
+ end
+ end
+
+ def read_introduced_by_mr
+ $stdout.puts
+ $stdout.puts ">> URL to GitLab merge request that added this type of audit event:"
+
+ loop do
+ introduced_by_mr = Readline.readline('?> ', false)&.strip
+ introduced_by_mr = nil if introduced_by_mr.empty?
+ return introduced_by_mr if introduced_by_mr.nil? || introduced_by_mr.start_with?('https://')
+
+ warn "URL needs to start with https://"
+ end
+ end
+
+ def read_introduced_by_issue
+ $stdout.puts ">> URL to GitLab issue that added this type of audit event:"
+
+ loop do
+ created_url = Readline.readline('?> ', false)&.strip
+ created_url = nil if created_url.empty?
+ return created_url if !created_url.nil? && created_url.start_with?('https://')
+
+ warn "URL needs to start with https://"
+ end
+ end
+
+ def read_milestone
+ milestone = File.read('VERSION')
+ milestone.gsub(/^(\d+\.\d+).*$/, '\1').chomp
+ end
+ end
+end
+
+class AuditEventTypeCreator
+ include AuditEventTypeHelpers
+
+ attr_reader :options
+
+ def initialize(options)
+ @options = options
+ end
+
+ def execute
+ assert_feature_branch!
+ assert_name!
+ assert_existing_audit_event_type!
+
+ options.description ||= AuditEventTypeOptionParser.read_description
+ options.group ||= AuditEventTypeOptionParser.read_group
+ options.milestone ||= AuditEventTypeOptionParser.read_milestone
+ options.saved_to_database = AuditEventTypeOptionParser.read_saved_to_database if options.saved_to_database.nil?
+ options.streamed = AuditEventTypeOptionParser.read_streamed if options.streamed.nil?
+ options.introduced_by_mr ||= AuditEventTypeOptionParser.read_introduced_by_mr
+ options.introduced_by_issue ||= AuditEventTypeOptionParser.read_introduced_by_issue
+
+ $stdout.puts "\e[32mcreate\e[0m #{file_path}"
+ $stdout.puts contents
+
+ unless options.dry_run
+ write
+ amend_commit if options.amend
+ end
+
+ system("#{editor} '#{file_path}'") if editor
+ end
+
+ private
+
+ def contents
+ # Slice is used to ensure that YAML keys
+ # are always ordered in a predictable way
+ config_hash.slice(
+ *::Gitlab::Audit::Type::Shared::PARAMS.map(&:to_s)
+ ).to_yaml
+ end
+
+ def config_hash
+ {
+ 'name' => options.name,
+ 'description' => options.description,
+ 'group' => options.group,
+ 'milestone' => options.milestone,
+ 'saved_to_database' => options.saved_to_database,
+ 'streamed' => options.streamed,
+ 'introduced_by_mr' => options.introduced_by_mr,
+ 'introduced_by_issue' => options.introduced_by_issue
+ }
+ end
+
+ def write
+ FileUtils.mkdir_p(File.dirname(file_path))
+ File.write(file_path, contents)
+ end
+
+ def editor
+ ENV['EDITOR']
+ end
+
+ def amend_commit
+ fail_with "git add failed" unless system(*%W[git add #{file_path}])
+
+ Kernel.exec(*%w[git commit --amend])
+ end
+
+ def assert_feature_branch!
+ return unless branch_name == 'master'
+
+ fail_with "Create a branch first!"
+ end
+
+ def assert_existing_audit_event_type!
+ existing_path = all_audit_event_type_names[options.name]
+ return unless existing_path
+ return if options.force
+
+ fail_with "#{existing_path} already exists! Use `--force` to overwrite."
+ end
+
+ def assert_name!
+ return if options.name =~ /\A[a-z0-9_-]+\Z/
+
+ fail_with "Provide a name for the audit event type that is [a-z0-9_-]"
+ end
+
+ def file_path
+ audit_event_types_paths.last.sub('*.yml', "#{options.name}.yml")
+ end
+
+ def all_audit_event_type_names
+ @all_audit_event_type_names ||=
+ audit_event_types_paths.flat_map do |glob_path|
+ Dir.glob(glob_path).map do |path|
+ [File.basename(path, '.yml'), path]
+ end
+ end.to_h
+ end
+
+ def audit_event_types_paths
+ paths = []
+ paths << File.join('config', 'audit_events', 'types', '*.yml')
+ paths << File.join('ee', 'config', 'audit_events', 'types', '*.yml') if ee?
+ paths << File.join('jh', 'config', 'audit_events', 'types', '*.yml') if jh?
+ paths
+ end
+
+ def ee?
+ options.ee
+ end
+
+ def jh?
+ options.jh
+ end
+
+ def branch_name
+ @branch_name ||= capture_stdout(%w[git symbolic-ref --short HEAD]).strip
+ end
+end
+
+if $PROGRAM_NAME == __FILE__
+ begin
+ options = AuditEventTypeOptionParser.parse(ARGV)
+ AuditEventTypeCreator.new(options).execute
+ rescue AuditEventTypeHelpers::Abort => ex
+ warn ex.message
+ exit 1
+ rescue AuditEventTypeHelpers::Done
+ exit
+ end
+end
diff --git a/config/application.rb b/config/application.rb
index d7e16117d53..249db9c6a67 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -262,12 +262,15 @@ module Gitlab
config.assets.precompile << "page_bundles/alert_management_settings.css"
config.assets.precompile << "page_bundles/billings.css"
config.assets.precompile << "page_bundles/boards.css"
+ 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/cluster_agents.css"
config.assets.precompile << "page_bundles/clusters.css"
config.assets.precompile << "page_bundles/cycle_analytics.css"
+ config.assets.precompile << "page_bundles/dashboard.css"
config.assets.precompile << "page_bundles/dashboard_projects.css"
+ config.assets.precompile << "page_bundles/design_management.css"
config.assets.precompile << "page_bundles/dev_ops_reports.css"
config.assets.precompile << "page_bundles/editor.css"
config.assets.precompile << "page_bundles/environments.css"
@@ -293,6 +296,7 @@ module Gitlab
config.assets.precompile << "page_bundles/merge_requests.css"
config.assets.precompile << "page_bundles/milestone.css"
config.assets.precompile << "page_bundles/new_namespace.css"
+ config.assets.precompile << "page_bundles/notifications.css"
config.assets.precompile << "page_bundles/oncall_schedules.css"
config.assets.precompile << "page_bundles/operations.css"
config.assets.precompile << "page_bundles/escalation_policies.css"
@@ -418,22 +422,15 @@ module Gitlab
allow do
origins '*'
resource oauth_path,
- headers: %w(Authorization),
+ # These headers are added as defaults to axios.
+ # See: https://gitlab.com/gitlab-org/gitlab/-/blob/dd1e70d3676891025534dc4a1e89ca9383178fe7/app/assets/javascripts/lib/utils/axios_utils.js#L8)
+ # It's added to declare that this is a XHR request and add the CSRF token without which Rails may reject the request from the frontend.
+ headers: %w(Authorization X-CSRF-Token X-Requested-With),
credentials: false,
methods: %i(post options)
end
end
- # Cross-origin requests must be enabled to fetch the self-managed application oauth application ID
- # for the GitLab for Jira app.
- allow do
- origins '*'
- resource '/-/jira_connect/oauth_application_id',
- headers: :any,
- methods: %i(get options),
- credentials: false
- end
-
# These are routes from doorkeeper-openid_connect:
# https://github.com/doorkeeper-gem/doorkeeper-openid_connect#routes
allow do
@@ -472,6 +469,11 @@ module Gitlab
g.factory_bot false
end
+ if defined?(FactoryBotRails)
+ config.factory_bot.definition_file_paths << 'ee/spec/factories' if Gitlab.ee?
+ config.factory_bot.definition_file_paths << 'jh/spec/factories' if Gitlab.jh?
+ end
+
# sprocket-rails adds some precompile assets we actually do not need.
#
# It copies all _non_ js and CSS files from the app/assets/ older.
diff --git a/config/audit_events/types/policy_project_updated.yml b/config/audit_events/types/policy_project_updated.yml
new file mode 100644
index 00000000000..6fffc7f6b10
--- /dev/null
+++ b/config/audit_events/types/policy_project_updated.yml
@@ -0,0 +1,8 @@
+name: policy_project_updated
+description: "This event is triggered whenever the security policy project is updated for a project."
+introduced_by_issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/377877"
+introduced_by_mr: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102154"
+milestone: "15.6"
+group: "govern::security policies"
+saved_to_database: true
+streamed: false
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 5e67ed71954..8f266f2660c 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -51,6 +51,10 @@ Rails.application.configure do
config.autoload_paths.push("#{config.root}/spec/components/previews")
config.lookbook.page_paths = ["#{config.root}/spec/components/docs"]
+ config.lookbook.preview_params_options_eval = true
+ config.lookbook.preview_display_options = {
+ theme: ["light", "dark (alpha)"]
+ }
# Adds additional error checking when serving assets at runtime.
# Checks for improperly declared sprockets dependencies.
diff --git a/config/events/1658833247_integrations_class_perform_integrations_action.yml b/config/events/1658833247_integrations_class_perform_integrations_action.yml
index 62da809fe14..d8f7cb4d38f 100644
--- a/config/events/1658833247_integrations_class_perform_integrations_action.yml
+++ b/config/events/1658833247_integrations_class_perform_integrations_action.yml
@@ -8,7 +8,7 @@ identifiers:
- user
- namespace
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
milestone: "15.3"
@@ -20,4 +20,3 @@ 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
new file mode 100644
index 00000000000..d19db52074b
--- /dev/null
+++ b/config/events/1666038724_Gitlab__Tracking__Helpers__WeakPasswordErrorEvent_track_weak_password_error.yml
@@ -0,0 +1,29 @@
+---
+description: User record is invalid due to weak password
+category: Gitlab::Tracking::Helpers::WeakPasswordErrorEvent
+action: track_weak_password_error
+label_description:
+property_description:
+value_description:
+extra_properties:
+ controller:
+ type: string
+ description: The controller which triggered the weak password check
+ method:
+ type: string
+ description: The method or controller action which triggered the weak password check
+identifiers:
+product_section: dev
+product_stage: manage
+product_group: group::authentication and authorization
+product_category: authentication_and_authorization
+milestone: "15.6"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100237
+distributions:
+- ce
+- ee
+tiers:
+- free
+- premium
+- ultimate
+
diff --git a/config/events/202109151015_cluster_services_prometheus_disabled_manual_prometheus.yml b/config/events/202109151015_cluster_services_prometheus_disabled_manual_prometheus.yml
index c98ac8323d4..4181ce723a7 100644
--- a/config/events/202109151015_cluster_services_prometheus_disabled_manual_prometheus.yml
+++ b/config/events/202109151015_cluster_services_prometheus_disabled_manual_prometheus.yml
@@ -7,7 +7,7 @@ value_description:
extra_properties:
identifiers:
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: group::integrations
product_category:
milestone: "14.0"
diff --git a/config/events/202109151015_cluster_services_prometheus_enabled_manual_prometheus.yml b/config/events/202109151015_cluster_services_prometheus_enabled_manual_prometheus.yml
index c453b2f035c..94e54d59de4 100644
--- a/config/events/202109151015_cluster_services_prometheus_enabled_manual_prometheus.yml
+++ b/config/events/202109151015_cluster_services_prometheus_enabled_manual_prometheus.yml
@@ -7,7 +7,7 @@ value_description:
extra_properties:
identifiers:
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: group::integrations
product_category:
milestone: "14.0"
diff --git a/config/events/20210915205112_packages_delete_package.yml b/config/events/20210915205112_packages_delete_package.yml
index 568a800a8e6..ebbebd553bf 100644
--- a/config/events/20210915205112_packages_delete_package.yml
+++ b/config/events/20210915205112_packages_delete_package.yml
@@ -7,8 +7,8 @@ value_description: ""
extra_properties:
identifiers:
product_section: dev
-product_stage: create
-product_group: group::ecosystem
+product_stage: manage
+product_group: group::foundations
product_category:
milestone: "13.4"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/41668
diff --git a/config/feature_categories.yml b/config/feature_categories.yml
index 66aa6071502..94a50dc416e 100644
--- a/config/feature_categories.yml
+++ b/config/feature_categories.yml
@@ -17,7 +17,7 @@
- authentication_and_authorization
- auto_devops
- backup_restore
-- billing_and_subscription_management
+- billing_and_payments
- build
- build_artifacts
- chatops
@@ -35,6 +35,7 @@
- continuous_integration_scaling
- continuous_verification
- credential_management
+- customersdot_application
- database
- dataops
- dedicated
@@ -59,7 +60,9 @@
- experimentation_expansion
- feature_flags
- five_minute_production_app
-- fulfillment_platform
+- fulfillment_admin_tooling
+- fulfillment_developer_productivity
+- fulfillment_infrastructure
- fuzz_testing
- geo_replication
- git_lfs
@@ -97,10 +100,8 @@
- planning_analytics
- pods
- portfolio_management
-- privacy_control_center
- product_analytics
- projects
-- provision
- pubsec_services
- purchase
- quality_management
@@ -114,6 +115,7 @@
- runner
- runner_fleet
- runner_saas
+- saas_provisioning
- scalability
- secret_detection
- secrets_management
@@ -121,16 +123,19 @@
- security_policy_management
- service_desk
- service_ping
+- sm_provisioning
- snippets
- source_code_management
- static_application_security_testing
- subgroups
+- subscription_cost_management
+- subscription_management
+- subscription_usage_reports
- system_access
- team_planning
- tracing
- user_management
- users
-- utilization
- value_stream_management
- vulnerability_management
- web_ide
diff --git a/config/feature_flags/development/actors_aware_gitaly_calls.yml b/config/feature_flags/development/actors_aware_gitaly_calls.yml
new file mode 100644
index 00000000000..0ae6140c579
--- /dev/null
+++ b/config/feature_flags/development/actors_aware_gitaly_calls.yml
@@ -0,0 +1,8 @@
+---
+name: actors_aware_gitaly_calls
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101218
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381516
+milestone: '15.6'
+type: development
+group: group::gitaly
+default_enabled: false
diff --git a/config/feature_flags/development/add_delete_branch_worker.yml b/config/feature_flags/development/add_delete_branch_worker.yml
new file mode 100644
index 00000000000..b0470a7f901
--- /dev/null
+++ b/config/feature_flags/development/add_delete_branch_worker.yml
@@ -0,0 +1,8 @@
+---
+name: add_delete_branch_worker
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102208
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381640
+milestone: '15.6'
+type: development
+group: group::code review
+default_enabled: false
diff --git a/config/feature_flags/development/agent_authorization_include_descendants.yml b/config/feature_flags/development/agent_authorization_include_descendants.yml
deleted file mode 100644
index 17d3a484395..00000000000
--- a/config/feature_flags/development/agent_authorization_include_descendants.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: agent_authorization_include_descendants
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95774
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/371310
-milestone: '15.5'
-type: development
-group: group::configure
-default_enabled: false
diff --git a/config/feature_flags/development/ai_assist_api.yml b/config/feature_flags/development/ai_assist_api.yml
new file mode 100644
index 00000000000..9b7da480f62
--- /dev/null
+++ b/config/feature_flags/development/ai_assist_api.yml
@@ -0,0 +1,8 @@
+---
+name: ai_assist_api
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100500
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/378470
+milestone: '15.6'
+type: development
+group: group::incubation
+default_enabled: false
diff --git a/config/feature_flags/development/ai_assist_flag.yml b/config/feature_flags/development/ai_assist_flag.yml
new file mode 100644
index 00000000000..ce8bff8267c
--- /dev/null
+++ b/config/feature_flags/development/ai_assist_flag.yml
@@ -0,0 +1,8 @@
+---
+name: ai_assist_flag
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100500
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/378470
+milestone: '15.6'
+type: development
+group: group::incubation
+default_enabled: false
diff --git a/config/feature_flags/development/ajax_new_deploy_token.yml b/config/feature_flags/development/ajax_new_deploy_token.yml
deleted file mode 100644
index 6b0d9697006..00000000000
--- a/config/feature_flags/development/ajax_new_deploy_token.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ajax_new_deploy_token
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27141
-rollout_issue_url:
-milestone: '12.10'
-type: development
-group: group::release
-default_enabled: false
diff --git a/config/feature_flags/development/allow_audit_event_type_filtering.yml b/config/feature_flags/development/allow_audit_event_type_filtering.yml
new file mode 100644
index 00000000000..e5cbd2fddcf
--- /dev/null
+++ b/config/feature_flags/development/allow_audit_event_type_filtering.yml
@@ -0,0 +1,8 @@
+---
+name: allow_audit_event_type_filtering
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102502
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/373833
+milestone: '15.6'
+type: development
+group: group::compliance
+default_enabled: false
diff --git a/config/feature_flags/development/apollo_boards.yml b/config/feature_flags/development/apollo_boards.yml
new file mode 100644
index 00000000000..d95e60bf4ea
--- /dev/null
+++ b/config/feature_flags/development/apollo_boards.yml
@@ -0,0 +1,8 @@
+---
+name: apollo_boards
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102719
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381210
+milestone: '15.6'
+type: development
+group: group::product planning
+default_enabled: false
diff --git a/config/feature_flags/development/approval_rules_eligible_filter.yml b/config/feature_flags/development/approval_rules_eligible_filter.yml
deleted file mode 100644
index e8d925d08a7..00000000000
--- a/config/feature_flags/development/approval_rules_eligible_filter.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: approval_rules_eligible_filter
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100192
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/376331
-milestone: '15.5'
-type: development
-group: group::source code
-default_enabled: false
diff --git a/config/feature_flags/development/async_merge_request_diff_creation.yml b/config/feature_flags/development/async_merge_request_diff_creation.yml
new file mode 100644
index 00000000000..8e4bdd13b2b
--- /dev/null
+++ b/config/feature_flags/development/async_merge_request_diff_creation.yml
@@ -0,0 +1,8 @@
+---
+name: async_merge_request_diff_creation
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100390"
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/376759
+milestone: '15.6'
+type: development
+group: group::code review
+default_enabled: false
diff --git a/config/feature_flags/development/audit_invalid_approver_rules.yml b/config/feature_flags/development/audit_invalid_approver_rules.yml
deleted file mode 100644
index eca5ffc25bb..00000000000
--- a/config/feature_flags/development/audit_invalid_approver_rules.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: audit_invalid_approver_rules
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98636
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/375060
-milestone: '15.5'
-type: development
-group: group::code review
-default_enabled: false
diff --git a/config/feature_flags/development/board_grouped_by_epic_performance.yml b/config/feature_flags/development/board_grouped_by_epic_performance.yml
new file mode 100644
index 00000000000..08519f3c328
--- /dev/null
+++ b/config/feature_flags/development/board_grouped_by_epic_performance.yml
@@ -0,0 +1,8 @@
+---
+name: board_grouped_by_epic_performance
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101640'
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381664
+milestone: '15.6'
+type: development
+group: group::product planning
+default_enabled: false
diff --git a/config/feature_flags/development/bulk_update_membership_roles.yml b/config/feature_flags/development/bulk_update_membership_roles.yml
new file mode 100644
index 00000000000..701f72db3e1
--- /dev/null
+++ b/config/feature_flags/development/bulk_update_membership_roles.yml
@@ -0,0 +1,8 @@
+---
+name: bulk_update_membership_roles
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96745
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/373257
+milestone: '15.6'
+type: development
+group: group::workspace
+default_enabled: false
diff --git a/config/feature_flags/development/cache_unleash_client_api.yml b/config/feature_flags/development/cache_unleash_client_api.yml
deleted file mode 100644
index dcaa9c323c4..00000000000
--- a/config/feature_flags/development/cache_unleash_client_api.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: cache_unleash_client_api
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90490
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/365575
-milestone: '15.2'
-type: development
-group: group::release
-default_enabled: false
diff --git a/config/feature_flags/development/cascade_package_forwarding_settings.yml b/config/feature_flags/development/cascade_package_forwarding_settings.yml
deleted file mode 100644
index 2b09c25d6f9..00000000000
--- a/config/feature_flags/development/cascade_package_forwarding_settings.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: cascade_package_forwarding_settings
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/99285
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/375761
-milestone: '15.5'
-type: development
-group: group::package
-default_enabled: false
diff --git a/config/feature_flags/development/check_etags_diffs_batch_before_write_cache.yml b/config/feature_flags/development/check_etags_diffs_batch_before_write_cache.yml
new file mode 100644
index 00000000000..fb03ff91d0a
--- /dev/null
+++ b/config/feature_flags/development/check_etags_diffs_batch_before_write_cache.yml
@@ -0,0 +1,8 @@
+---
+name: check_etags_diffs_batch_before_write_cache
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101421
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/378333
+milestone: '15.6'
+type: development
+group: group::code review
+default_enabled: false
diff --git a/config/feature_flags/development/ci_assign_job_token_on_scheduling.yml b/config/feature_flags/development/ci_assign_job_token_on_scheduling.yml
new file mode 100644
index 00000000000..179fef03d5e
--- /dev/null
+++ b/config/feature_flags/development/ci_assign_job_token_on_scheduling.yml
@@ -0,0 +1,8 @@
+---
+name: ci_assign_job_token_on_scheduling
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103377
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382042
+milestone: '15.6'
+type: development
+group: group::pipeline execution
+default_enabled: false
diff --git a/config/feature_flags/development/ci_detect_wrongly_expired_artifacts.yml b/config/feature_flags/development/ci_detect_wrongly_expired_artifacts.yml
deleted file mode 100644
index d48747c3bf5..00000000000
--- a/config/feature_flags/development/ci_detect_wrongly_expired_artifacts.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_detect_wrongly_expired_artifacts
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82084
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/354955
-milestone: '14.9'
-type: development
-group: group::pipeline insights
-default_enabled: true
diff --git a/config/feature_flags/development/ci_job_artifacts_cdn.yml b/config/feature_flags/development/ci_job_artifacts_cdn.yml
deleted file mode 100644
index 4a019312ee7..00000000000
--- a/config/feature_flags/development/ci_job_artifacts_cdn.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_job_artifacts_cdn
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98010
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/373860
-milestone: '15.5'
-type: development
-group: group::pipeline execution
-default_enabled: false
diff --git a/config/feature_flags/development/ci_job_jwt.yml b/config/feature_flags/development/ci_job_jwt.yml
deleted file mode 100644
index 3ce97c6334c..00000000000
--- a/config/feature_flags/development/ci_job_jwt.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_job_jwt
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28063
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/207125
-milestone: '12.10'
-type: development
-group: group::configure
-default_enabled: true
diff --git a/config/feature_flags/development/ci_partitioning_use_ci_builds_metadata_routing_table.yml b/config/feature_flags/development/ci_partitioning_use_ci_builds_metadata_routing_table.yml
new file mode 100644
index 00000000000..71c2aa735a2
--- /dev/null
+++ b/config/feature_flags/development/ci_partitioning_use_ci_builds_metadata_routing_table.yml
@@ -0,0 +1,8 @@
+---
+name: ci_partitioning_use_ci_builds_metadata_routing_table
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100935"
+rollout_issue_url: "https://gitlab.com/gitlab-org/gitlab/-/issues/378601"
+milestone: '15.6'
+type: development
+group: "group::pipeline execution"
+default_enabled: false
diff --git a/config/feature_flags/development/ci_raw_variables_in_yaml_config.yml b/config/feature_flags/development/ci_raw_variables_in_yaml_config.yml
new file mode 100644
index 00000000000..ab135526c0b
--- /dev/null
+++ b/config/feature_flags/development/ci_raw_variables_in_yaml_config.yml
@@ -0,0 +1,8 @@
+---
+name: ci_raw_variables_in_yaml_config
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98420
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/375034
+milestone: '15.6'
+type: development
+group: group::pipeline authoring
+default_enabled: false
diff --git a/config/feature_flags/development/ci_recreate_downstream_pipeline.yml b/config/feature_flags/development/ci_recreate_downstream_pipeline.yml
deleted file mode 100644
index 17b8a0965fc..00000000000
--- a/config/feature_flags/development/ci_recreate_downstream_pipeline.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_recreate_downstream_pipeline
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83613
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/358409
-milestone: '14.10'
-type: development
-group: group::pipeline authoring
-default_enabled: false
diff --git a/config/feature_flags/development/ci_requeue_with_dag_object_hierarchy.yml b/config/feature_flags/development/ci_requeue_with_dag_object_hierarchy.yml
deleted file mode 100644
index b6f4974915b..00000000000
--- a/config/feature_flags/development/ci_requeue_with_dag_object_hierarchy.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_requeue_with_dag_object_hierarchy
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97156
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/373148
-milestone: '15.4'
-type: development
-group: group::pipeline authoring
-default_enabled: true
diff --git a/config/feature_flags/development/ci_retry_job_fix.yml b/config/feature_flags/development/ci_retry_job_fix.yml
new file mode 100644
index 00000000000..30782e57dea
--- /dev/null
+++ b/config/feature_flags/development/ci_retry_job_fix.yml
@@ -0,0 +1,8 @@
+---
+name: ci_retry_job_fix
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100712
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/207988
+milestone: '15.6'
+type: development
+group: group::pipeline execution
+default_enabled: false
diff --git a/config/feature_flags/development/ci_stop_expanding_file_vars_for_runners.yml b/config/feature_flags/development/ci_stop_expanding_file_vars_for_runners.yml
deleted file mode 100644
index a78290b65d6..00000000000
--- a/config/feature_flags/development/ci_stop_expanding_file_vars_for_runners.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_stop_expanding_file_vars_for_runners
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/94198
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/369907
-milestone: '15.3'
-type: development
-group: group::pipeline authoring
-default_enabled: true
diff --git a/config/feature_flags/development/ci_variable_settings_graphql.yml b/config/feature_flags/development/ci_variable_settings_graphql.yml
deleted file mode 100644
index 0af109968ab..00000000000
--- a/config/feature_flags/development/ci_variable_settings_graphql.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_variable_settings_graphql
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/89332
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/364423
-milestone: '15.1'
-type: development
-group: group::pipeline authoring
-default_enabled: false
diff --git a/config/feature_flags/development/container_registry_delete_repository_with_cron_worker.yml b/config/feature_flags/development/container_registry_delete_repository_with_cron_worker.yml
new file mode 100644
index 00000000000..ef531228398
--- /dev/null
+++ b/config/feature_flags/development/container_registry_delete_repository_with_cron_worker.yml
@@ -0,0 +1,8 @@
+---
+name: container_registry_delete_repository_with_cron_worker
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101918
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/378818
+milestone: '15.6'
+type: development
+group: group::container registry
+default_enabled: false
diff --git a/config/feature_flags/development/container_registry_show_shortened_path.yml b/config/feature_flags/development/container_registry_show_shortened_path.yml
deleted file mode 100644
index 33781386e8a..00000000000
--- a/config/feature_flags/development/container_registry_show_shortened_path.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: container_registry_show_shortened_path
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91548
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/366808
-milestone: '15.2'
-type: development
-group: group::package
-default_enabled: false
diff --git a/config/feature_flags/development/cube_api_proxy.yml b/config/feature_flags/development/cube_api_proxy.yml
deleted file mode 100644
index 06dcefb1303..00000000000
--- a/config/feature_flags/development/cube_api_proxy.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: cube_api_proxy
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96250
-rollout_issue_url:
-milestone: '15.4'
-type: development
-group: group::product_analytics
-default_enabled: false
diff --git a/config/feature_flags/development/dast_api_scanner.yml b/config/feature_flags/development/dast_api_scanner.yml
index 8299004fecb..5cc268ee9b9 100644
--- a/config/feature_flags/development/dast_api_scanner.yml
+++ b/config/feature_flags/development/dast_api_scanner.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345837
milestone: '14.7'
type: development
group: group::dynamic analysis
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/disable_load_entire_blob_for_diff_viewer.yml b/config/feature_flags/development/disable_load_entire_blob_for_diff_viewer.yml
deleted file mode 100644
index 5e767e3540b..00000000000
--- a/config/feature_flags/development/disable_load_entire_blob_for_diff_viewer.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: disable_load_entire_blob_for_diff_viewer
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/99029
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/376330
-milestone: '15.5'
-type: development
-group: group::source code
-default_enabled: false
diff --git a/config/feature_flags/development/enable_new_sentry_clientside_integration.yml b/config/feature_flags/development/enable_new_sentry_clientside_integration.yml
new file mode 100644
index 00000000000..338fd2b1e25
--- /dev/null
+++ b/config/feature_flags/development/enable_new_sentry_clientside_integration.yml
@@ -0,0 +1,8 @@
+---
+name: enable_new_sentry_clientside_integration
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102650
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/344832
+milestone: '15.6'
+type: development
+group: group::runner
+default_enabled: false
diff --git a/config/feature_flags/development/enhanced_webhook_support_regex.yml b/config/feature_flags/development/enhanced_webhook_support_regex.yml
new file mode 100644
index 00000000000..2c0d2c82dbf
--- /dev/null
+++ b/config/feature_flags/development/enhanced_webhook_support_regex.yml
@@ -0,0 +1,8 @@
+---
+name: enhanced_webhook_support_regex
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97235
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/375728
+milestone: '15.6'
+type: development
+group: group::integrations
+default_enabled: false
diff --git a/config/feature_flags/development/error_tracking_sentry_limit.yml b/config/feature_flags/development/error_tracking_sentry_limit.yml
deleted file mode 100644
index 75a32fa2114..00000000000
--- a/config/feature_flags/development/error_tracking_sentry_limit.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: error_tracking_sentry_limit
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/84209
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/372427
-milestone: '15.4'
-type: development
-group: group::observability
-default_enabled: false
diff --git a/config/feature_flags/development/externally_stored_diffs_caching_export.yml b/config/feature_flags/development/externally_stored_diffs_caching_export.yml
deleted file mode 100644
index 395ce5c7cb9..00000000000
--- a/config/feature_flags/development/externally_stored_diffs_caching_export.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: externally_stored_diffs_caching_export
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90159
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/366255
-milestone: '15.2'
-type: development
-group: group::import
-default_enabled: false
diff --git a/config/feature_flags/development/group_overview_tabs_vue.yml b/config/feature_flags/development/group_overview_tabs_vue.yml
deleted file mode 100644
index 4c54ab31b53..00000000000
--- a/config/feature_flags/development/group_overview_tabs_vue.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: group_overview_tabs_vue
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95850
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/370872
-milestone: '15.4'
-type: development
-group: group::workspace
-default_enabled: false
diff --git a/config/feature_flags/development/hash_oauth_tokens.yml b/config/feature_flags/development/hash_oauth_tokens.yml
deleted file mode 100644
index 96bd4a3702e..00000000000
--- a/config/feature_flags/development/hash_oauth_tokens.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: hash_oauth_tokens
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91501
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/367570
-milestone: '15.3'
-type: development
-group: group::authentication and authorization
-default_enabled: true
diff --git a/config/feature_flags/development/incident_declare_slash_command.yml b/config/feature_flags/development/incident_declare_slash_command.yml
new file mode 100644
index 00000000000..9a35dd3274c
--- /dev/null
+++ b/config/feature_flags/development/incident_declare_slash_command.yml
@@ -0,0 +1,8 @@
+---
+name: incident_declare_slash_command
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101177
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/378072
+milestone: '15.6'
+type: development
+group: group::respond
+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
index d233194c6d4..4b9903b25c9 100644
--- a/config/feature_flags/development/integration_slack_app_notifications.yml
+++ b/config/feature_flags/development/integration_slack_app_notifications.yml
@@ -1,7 +1,7 @@
---
name: integration_slack_app_notifications
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98663
-rollout_issue_url:
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381012
milestone: '15.5'
type: development
group: group::integrations
diff --git a/config/feature_flags/development/ipynb_semantic_diff.yml b/config/feature_flags/development/ipynb_semantic_diff.yml
deleted file mode 100644
index ef16cacaa37..00000000000
--- a/config/feature_flags/development/ipynb_semantic_diff.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ipynb_semantic_diff
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85079
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/358917
-milestone: '15.0'
-type: development
-group: group::code review
-default_enabled: true
diff --git a/config/feature_flags/development/jira_connect_oauth_self_managed_setting.yml b/config/feature_flags/development/jira_connect_oauth_self_managed_setting.yml
new file mode 100644
index 00000000000..05232d0f80a
--- /dev/null
+++ b/config/feature_flags/development/jira_connect_oauth_self_managed_setting.yml
@@ -0,0 +1,8 @@
+---
+name: jira_connect_oauth_self_managed_setting
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100725
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/377679
+milestone: '15.6'
+type: development
+group: group::integrations
+default_enabled: false
diff --git a/config/feature_flags/development/job_webhook_retries_count.yml b/config/feature_flags/development/job_webhook_retries_count.yml
new file mode 100644
index 00000000000..96b33695440
--- /dev/null
+++ b/config/feature_flags/development/job_webhook_retries_count.yml
@@ -0,0 +1,8 @@
+---
+name: job_webhook_retries_count
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101618
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382046
+milestone: '15.6'
+type: development
+group: group::delivery
+default_enabled: false
diff --git a/config/feature_flags/development/lazy_load_commits.yml b/config/feature_flags/development/lazy_load_commits.yml
index d4764907211..6140b88c3c2 100644
--- a/config/feature_flags/development/lazy_load_commits.yml
+++ b/config/feature_flags/development/lazy_load_commits.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/342497
milestone: '14.4'
type: development
group: group::source code
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/limit_assignees_per_issuable.yml b/config/feature_flags/development/limit_assignees_per_issuable.yml
deleted file mode 100644
index d950b8c2f09..00000000000
--- a/config/feature_flags/development/limit_assignees_per_issuable.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: limit_assignees_per_issuable
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95673
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/373237
-milestone: '15.5'
-type: development
-group: group::code review
-default_enabled: false
diff --git a/config/feature_flags/development/merge_request_widget_graphql.yml b/config/feature_flags/development/merge_request_widget_graphql.yml
deleted file mode 100644
index 8d13c6b1c62..00000000000
--- a/config/feature_flags/development/merge_request_widget_graphql.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: merge_request_widget_graphql
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38311
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/267560
-milestone: '13.3'
-type: development
-group: group::code review
-default_enabled: true
diff --git a/config/feature_flags/development/mergeability_caching.yml b/config/feature_flags/development/mergeability_caching.yml
deleted file mode 100644
index b9063299926..00000000000
--- a/config/feature_flags/development/mergeability_caching.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: mergeability_caching
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68312
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340810
-milestone: '14.4'
-type: development
-group: group::code review
-default_enabled: false
diff --git a/config/feature_flags/development/ml_experiment_tracking.yml b/config/feature_flags/development/ml_experiment_tracking.yml
index 2749cbc3fc1..19f14196591 100644
--- a/config/feature_flags/development/ml_experiment_tracking.yml
+++ b/config/feature_flags/development/ml_experiment_tracking.yml
@@ -2,7 +2,8 @@
name: ml_experiment_tracking
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95689
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/371669
-milestone: '15.4'
+milestone: '15.6'
type: development
group: group::incubation
default_enabled: false
+log_state_changes: true
diff --git a/config/feature_flags/development/new_navbar_layout.yml b/config/feature_flags/development/new_navbar_layout.yml
deleted file mode 100644
index 2d212922fcc..00000000000
--- a/config/feature_flags/development/new_navbar_layout.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: new_navbar_layout
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96853
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/373078
-milestone: '15.4'
-type: development
-group: group::foundations
-default_enabled: true
diff --git a/config/feature_flags/development/observability_group_tab.yml b/config/feature_flags/development/observability_group_tab.yml
index b588a74e7d0..168299c15af 100644
--- a/config/feature_flags/development/observability_group_tab.yml
+++ b/config/feature_flags/development/observability_group_tab.yml
@@ -1,7 +1,7 @@
---
name: observability_group_tab
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96374
-rollout_issue_url:
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381740
milestone: '15.3'
type: development
group: group::observability
diff --git a/config/feature_flags/development/optimized_project_and_group_activity_queries.yml b/config/feature_flags/development/optimized_project_and_group_activity_queries.yml
deleted file mode 100644
index 6efb0a3818a..00000000000
--- a/config/feature_flags/development/optimized_project_and_group_activity_queries.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: optimized_project_and_group_activity_queries
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85810
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/360458
-milestone: '15.0'
-type: development
-group: group::workspace
-default_enabled: false
diff --git a/config/feature_flags/development/pbkdf2_password_encryption.yml b/config/feature_flags/development/pbkdf2_password_encryption.yml
deleted file mode 100644
index 995173a6a38..00000000000
--- a/config/feature_flags/development/pbkdf2_password_encryption.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: pbkdf2_password_encryption
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91622
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/367147
-milestone: '15.2'
-type: development
-group: group::authentication and authorization
-default_enabled: false
diff --git a/config/feature_flags/development/pbkdf2_password_encryption_write.yml b/config/feature_flags/development/pbkdf2_password_encryption_write.yml
deleted file mode 100644
index 29c7baedaf2..00000000000
--- a/config/feature_flags/development/pbkdf2_password_encryption_write.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: pbkdf2_password_encryption_write
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91622
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/367147
-milestone: '15.2'
-type: development
-group: group::authentication and authorization
-default_enabled: false
diff --git a/config/feature_flags/development/preferred_language_switcher.yml b/config/feature_flags/development/preferred_language_switcher.yml
new file mode 100644
index 00000000000..9dedb1421aa
--- /dev/null
+++ b/config/feature_flags/development/preferred_language_switcher.yml
@@ -0,0 +1,7 @@
+---
+name: preferred_language_switcher
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101621
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381181
+milestone: '15.6'
+type: development
+default_enabled: false
diff --git a/config/feature_flags/development/product_analytics.yml b/config/feature_flags/development/product_analytics.yml
deleted file mode 100644
index 4dfe0ce57d8..00000000000
--- a/config/feature_flags/development/product_analytics.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: product_analytics
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36443
-rollout_issue_url:
-milestone: '13.2'
-type: development
-group: group::product intelligence
-default_enabled: false
diff --git a/config/feature_flags/development/projects_preloader_fix.yml b/config/feature_flags/development/projects_preloader_fix.yml
new file mode 100644
index 00000000000..1ad578f11a4
--- /dev/null
+++ b/config/feature_flags/development/projects_preloader_fix.yml
@@ -0,0 +1,8 @@
+---
+name: projects_preloader_fix
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96108
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/378858
+milestone: '15.6'
+type: development
+group: group::workspace
+default_enabled: false
diff --git a/config/feature_flags/development/realtime_labels.yml b/config/feature_flags/development/realtime_labels.yml
deleted file mode 100644
index 0c047a09a6d..00000000000
--- a/config/feature_flags/development/realtime_labels.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: realtime_labels
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83743
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/357370
-milestone: '14.10'
-type: development
-group: group::project management
-default_enabled: true
diff --git a/config/feature_flags/development/realtime_reviewers.yml b/config/feature_flags/development/realtime_reviewers.yml
new file mode 100644
index 00000000000..a7da47a3c29
--- /dev/null
+++ b/config/feature_flags/development/realtime_reviewers.yml
@@ -0,0 +1,8 @@
+---
+name: realtime_reviewers
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/99137'
+rollout_issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/378299'
+milestone: '15.5'
+type: development
+group: group::code review
+default_enabled: true
diff --git a/config/feature_flags/development/refactor_code_quality_extension.yml b/config/feature_flags/development/refactor_code_quality_extension.yml
deleted file mode 100644
index c6eb7c19a6e..00000000000
--- a/config/feature_flags/development/refactor_code_quality_extension.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: refactor_code_quality_extension
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/88865
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/363845
-milestone: '15.1'
-type: development
-group: group::secure
-default_enabled: false
diff --git a/config/feature_flags/development/refactor_mr_widget_test_summary.yml b/config/feature_flags/development/refactor_mr_widget_test_summary.yml
deleted file mode 100644
index 902248f1d85..00000000000
--- a/config/feature_flags/development/refactor_mr_widget_test_summary.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: refactor_mr_widget_test_summary
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83631
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/358208
-milestone: '15.0'
-type: development
-group: group::pipeline insights
-default_enabled: false
diff --git a/config/feature_flags/development/remove_extra_primary_submenu_options.yml b/config/feature_flags/development/remove_extra_primary_submenu_options.yml
deleted file mode 100644
index dda22c5d57e..00000000000
--- a/config/feature_flags/development/remove_extra_primary_submenu_options.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: remove_extra_primary_submenu_options
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96931
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/373078
-milestone: '15.4'
-type: development
-group: group::foundations
-default_enabled: true
diff --git a/config/feature_flags/development/require_approval_on_scan_removal.yml b/config/feature_flags/development/require_approval_on_scan_removal.yml
new file mode 100644
index 00000000000..2cbbe8e49f8
--- /dev/null
+++ b/config/feature_flags/development/require_approval_on_scan_removal.yml
@@ -0,0 +1,8 @@
+---
+name: require_approval_on_scan_removal
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102631
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382079
+milestone: '15.6'
+type: development
+group: group::security policies
+default_enabled: false
diff --git a/config/feature_flags/development/root_level_issues_query.yml b/config/feature_flags/development/root_level_issues_query.yml
new file mode 100644
index 00000000000..308f9168167
--- /dev/null
+++ b/config/feature_flags/development/root_level_issues_query.yml
@@ -0,0 +1,8 @@
+---
+name: root_level_issues_query
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102348
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382250
+milestone: '15.6'
+type: development
+group: group::project management
+default_enabled: false
diff --git a/config/feature_flags/development/root_statistics_worker_read_replica.yml b/config/feature_flags/development/root_statistics_worker_read_replica.yml
new file mode 100644
index 00000000000..516bead1ee7
--- /dev/null
+++ b/config/feature_flags/development/root_statistics_worker_read_replica.yml
@@ -0,0 +1,8 @@
+---
+name: root_statistics_worker_read_replica
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102516
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/379678
+milestone: '15.6'
+type: development
+group: group::utilization
+default_enabled: false
diff --git a/config/feature_flags/development/saml_group_sync_retain_default_membership.yml b/config/feature_flags/development/saml_group_sync_retain_default_membership.yml
deleted file mode 100644
index dbaaf681fb9..00000000000
--- a/config/feature_flags/development/saml_group_sync_retain_default_membership.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: saml_group_sync_retain_default_membership
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/88064
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/364144
-milestone: '15.1'
-type: development
-group: group::authentication and authorization
-default_enabled: false
diff --git a/config/feature_flags/development/scan_result_role_action.yml b/config/feature_flags/development/scan_result_role_action.yml
new file mode 100644
index 00000000000..e6a4a552350
--- /dev/null
+++ b/config/feature_flags/development/scan_result_role_action.yml
@@ -0,0 +1,8 @@
+---
+name: scan_result_role_action
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101464
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/377866
+milestone: '15.6'
+type: development
+group: group::security policies
+default_enabled: false
diff --git a/config/feature_flags/development/search_index_curation.yml b/config/feature_flags/development/search_index_curation.yml
new file mode 100644
index 00000000000..ddcc243c60f
--- /dev/null
+++ b/config/feature_flags/development/search_index_curation.yml
@@ -0,0 +1,8 @@
+---
+name: search_index_curation
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98809
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/375274
+milestone: '15.6'
+type: development
+group: group::global search
+default_enabled: false
diff --git a/config/feature_flags/development/split_operations_visibility_permissions.yml b/config/feature_flags/development/split_operations_visibility_permissions.yml
index 612876a2dcd..56955733217 100644
--- a/config/feature_flags/development/split_operations_visibility_permissions.yml
+++ b/config/feature_flags/development/split_operations_visibility_permissions.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/364240
milestone: '15.1'
type: development
group: group::respond
-default_enabled: false
+default_enabled: true
diff --git a/config/feature_flags/development/track_delete_source_errors.yml b/config/feature_flags/development/track_delete_source_errors.yml
deleted file mode 100644
index 57152ed86cd..00000000000
--- a/config/feature_flags/development/track_delete_source_errors.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: track_delete_source_errors
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/99028
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/377258
-milestone: '15.5'
-type: development
-group: group::code review
-default_enabled: false
diff --git a/config/feature_flags/development/trigger_mr_subscription_on_merge_status_change.yml b/config/feature_flags/development/trigger_mr_subscription_on_merge_status_change.yml
deleted file mode 100644
index 058fde35110..00000000000
--- a/config/feature_flags/development/trigger_mr_subscription_on_merge_status_change.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: trigger_mr_subscription_on_merge_status_change
-introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/99213"
-rollout_issue_url: "https://gitlab.com/gitlab-org/gitlab/-/issues/375704"
-milestone: '15.5'
-type: development
-group: group::code review
-default_enabled: false
diff --git a/config/feature_flags/development/usage_data_ci_i_testing_coverage_report_uploaded.yml b/config/feature_flags/development/usage_data_ci_i_testing_coverage_report_uploaded.yml
new file mode 100644
index 00000000000..f3a3772972e
--- /dev/null
+++ b/config/feature_flags/development/usage_data_ci_i_testing_coverage_report_uploaded.yml
@@ -0,0 +1,8 @@
+---
+name: usage_data_ci_i_testing_coverage_report_uploaded
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102371
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/339721
+milestone: '15.6'
+type: development
+group: group::pipeline insights
+default_enabled: false
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
new file mode 100644
index 00000000000..d2d328bbbc1
--- /dev/null
+++ b/config/feature_flags/development/use_iid_in_work_items_path.yml
@@ -0,0 +1,8 @@
+---
+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/user_destroy_with_limited_execution_time_worker.yml b/config/feature_flags/development/user_destroy_with_limited_execution_time_worker.yml
deleted file mode 100644
index 9eacfc019ac..00000000000
--- a/config/feature_flags/development/user_destroy_with_limited_execution_time_worker.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: user_destroy_with_limited_execution_time_worker
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97141
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/373138
-milestone: '15.4'
-type: development
-group: group::authentication and authorization
-default_enabled: false
diff --git a/config/feature_flags/development/verify_gitlab_shell_worker_method_names.yml b/config/feature_flags/development/verify_gitlab_shell_worker_method_names.yml
new file mode 100644
index 00000000000..d6b28c28600
--- /dev/null
+++ b/config/feature_flags/development/verify_gitlab_shell_worker_method_names.yml
@@ -0,0 +1,8 @@
+---
+name: verify_gitlab_shell_worker_method_names
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103783
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/371470
+milestone: '15.6'
+type: development
+group: group::scalability
+default_enabled: false
diff --git a/config/feature_flags/development/verify_mail_scheduler_notification_service_worker_method_names.yml b/config/feature_flags/development/verify_mail_scheduler_notification_service_worker_method_names.yml
new file mode 100644
index 00000000000..0fc30f63047
--- /dev/null
+++ b/config/feature_flags/development/verify_mail_scheduler_notification_service_worker_method_names.yml
@@ -0,0 +1,8 @@
+---
+name: verify_mail_scheduler_notification_service_worker_method_names
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103785
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/371470
+milestone: '15.6'
+type: development
+group: group::scalability
+default_enabled: false
diff --git a/config/feature_flags/development/vue_group_select.yml b/config/feature_flags/development/vue_group_select.yml
new file mode 100644
index 00000000000..d31f57a3eb9
--- /dev/null
+++ b/config/feature_flags/development/vue_group_select.yml
@@ -0,0 +1,8 @@
+---
+name: vue_group_select
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98597
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/381042
+milestone: '15.6'
+type: development
+group: group::foundations
+default_enabled: false
diff --git a/config/feature_flags/development/vue_issues_dashboard.yml b/config/feature_flags/development/vue_issues_dashboard.yml
new file mode 100644
index 00000000000..133343b3a3c
--- /dev/null
+++ b/config/feature_flags/development/vue_issues_dashboard.yml
@@ -0,0 +1,8 @@
+---
+name: vue_issues_dashboard
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102197
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/379025
+milestone: '15.6'
+type: development
+group: group::project management
+default_enabled: false
diff --git a/config/feature_flags/development/work_items_hierarchy.yml b/config/feature_flags/development/work_items_hierarchy.yml
deleted file mode 100644
index ce27c58df96..00000000000
--- a/config/feature_flags/development/work_items_hierarchy.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: work_items_hierarchy
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/88504
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/363447
-milestone: '15.1'
-type: development
-group: group::product planning
-default_enabled: true
diff --git a/config/feature_flags/development/work_items_mvc.yml b/config/feature_flags/development/work_items_mvc.yml
new file mode 100644
index 00000000000..928175c70ba
--- /dev/null
+++ b/config/feature_flags/development/work_items_mvc.yml
@@ -0,0 +1,8 @@
+---
+name: work_items_mvc
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101062"
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/377912
+milestone: '15.5'
+type: development
+group: group::project management
+default_enabled: false
diff --git a/config/feature_flags/development/workhorse_google_client.yml b/config/feature_flags/development/workhorse_google_client.yml
new file mode 100644
index 00000000000..e3417ac4afd
--- /dev/null
+++ b/config/feature_flags/development/workhorse_google_client.yml
@@ -0,0 +1,8 @@
+---
+name: workhorse_google_client
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96891
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/372596
+milestone: '15.6'
+type: development
+group: 'group::package registry'
+default_enabled: false
diff --git a/config/feature_flags/experiment/disable_network_graph_notes_count.yml b/config/feature_flags/experiment/disable_network_graph_notes_count.yml
new file mode 100644
index 00000000000..fa4e5b4e104
--- /dev/null
+++ b/config/feature_flags/experiment/disable_network_graph_notes_count.yml
@@ -0,0 +1,8 @@
+---
+name: disable_network_graph_notes_count
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103636"
+rollout_issue_url:
+milestone: '15.6'
+type: experiment
+group: group::source code
+default_enabled: false
diff --git a/config/feature_flags/experiment/generic_explore_groups.yml b/config/feature_flags/experiment/generic_explore_groups.yml
new file mode 100644
index 00000000000..635af65f000
--- /dev/null
+++ b/config/feature_flags/experiment/generic_explore_groups.yml
@@ -0,0 +1,8 @@
+---
+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: false
diff --git a/config/feature_flags/experiment/logged_out_marketing_header.yml b/config/feature_flags/experiment/logged_out_marketing_header.yml
deleted file mode 100644
index 8bc09d59b16..00000000000
--- a/config/feature_flags/experiment/logged_out_marketing_header.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: logged_out_marketing_header
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76076
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/348525
-milestone: '14.7'
-type: experiment
-group: group::activation
-default_enabled: false
diff --git a/config/feature_flags/ops/ci_partitioning_analyze_queries_partition_id_check.yml b/config/feature_flags/ops/ci_partitioning_analyze_queries_partition_id_check.yml
new file mode 100644
index 00000000000..1d3efcea70a
--- /dev/null
+++ b/config/feature_flags/ops/ci_partitioning_analyze_queries_partition_id_check.yml
@@ -0,0 +1,8 @@
+---
+name: ci_partitioning_analyze_queries_partition_id_check
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100804
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/378282
+milestone: '15.6'
+type: ops
+group: group::pipeline execution
+default_enabled: false
diff --git a/config/feature_flags/ops/purge_stale_security_findings.yml b/config/feature_flags/ops/purge_stale_security_findings.yml
index 0c011a1ddae..b540c8a1d60 100644
--- a/config/feature_flags/ops/purge_stale_security_findings.yml
+++ b/config/feature_flags/ops/purge_stale_security_findings.yml
@@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/356464
milestone: '14.9'
type: ops
group: group::threat insights
-default_enabled: false
+default_enabled: true
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 050d112843f..732d46d284b 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -505,11 +505,11 @@ production: &base
# Periodically executed jobs, to self-heal GitLab, do external synchronizations, etc.
# Please read here for more information: https://github.com/ondrejbartas/sidekiq-cron#adding-cron-job
cron_jobs:
- # Interval, in seconds, for each Sidekiq process to check for scheduled cron jobs that need to be enqueued. If set
- # to 0, disable polling for cron jobs entirely. This is useful in setups with multiple Sidekiq processes if you want
- # to limit which ones perform this task. Note that at least one process in your instance needs to have polling
- # enabled for cron jobs to be executed.
- poll_interval: 30
+ # Interval, in seconds, for each Sidekiq process to check for scheduled cron jobs that need to be enqueued. If not
+ # set, the interval scales dynamically with the number of Sidekiq processes. If set to 0, disable polling for cron
+ # jobs entirely.
+ # poll_interval: 30
+
# Flag stuck CI jobs as failed
stuck_ci_jobs_worker:
cron: "0 * * * *"
diff --git a/config/gitlab_loose_foreign_keys.yml b/config/gitlab_loose_foreign_keys.yml
index 1530c681eb0..efb14cdea36 100644
--- a/config/gitlab_loose_foreign_keys.yml
+++ b/config/gitlab_loose_foreign_keys.yml
@@ -14,10 +14,6 @@ ci_builds:
- table: ci_runners
column: runner_id
on_delete: async_nullify
-ci_builds_metadata:
- - table: projects
- column: project_id
- on_delete: async_delete
ci_daily_build_group_report_results:
- table: namespaces
column: group_id
@@ -210,6 +206,10 @@ merge_trains:
- table: ci_pipelines
column: pipeline_id
on_delete: async_nullify
+p_ci_builds_metadata:
+ - table: projects
+ column: project_id
+ on_delete: async_delete
packages_build_infos:
- table: ci_pipelines
column: pipeline_id
diff --git a/config/initializers/0_inject_enterprise_edition_module.rb b/config/initializers/0_inject_enterprise_edition_module.rb
index 1951940a2a1..cc67e384d83 100644
--- a/config/initializers/0_inject_enterprise_edition_module.rb
+++ b/config/initializers/0_inject_enterprise_edition_module.rb
@@ -35,6 +35,12 @@ module InjectEnterpriseEditionModule
include_mod_with(name) # rubocop: disable Cop/InjectEnterpriseEditionModule
end
+ def gitlab_extensions
+ extensions = [self]
+ each_extension_for(name, Object) { |c| extensions << c }
+ extensions
+ end
+
private
def prepend_module(mod, with_descendants)
diff --git a/config/initializers/0_marginalia.rb b/config/initializers/0_marginalia.rb
index e88599fd93c..c776747939f 100644
--- a/config/initializers/0_marginalia.rb
+++ b/config/initializers/0_marginalia.rb
@@ -13,7 +13,8 @@ require 'marginalia'
# matching against the raw SQL, and prepending the comment prevents color
# coding from working in the development log.
Marginalia::Comment.prepend_comment = true if Rails.env.production?
-Marginalia::Comment.components = [:application, :correlation_id, :jid, :endpoint_id, :db_config_name]
+Marginalia::Comment.components = [:application, :correlation_id, :jid, :endpoint_id, :db_config_name,
+ :console_hostname, :console_username]
# As mentioned in https://github.com/basecamp/marginalia/pull/93/files,
# adding :line has some overhead because a regexp on the backtrace has
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 2244e415c3d..da4277c8146 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -457,7 +457,7 @@ if Gitlab.ee? && Settings['ee_cron_jobs']
Settings.cron_jobs.merge!(Settings.ee_cron_jobs)
end
-Settings.cron_jobs['poll_interval'] ||= 30
+Settings.cron_jobs['poll_interval'] ||= nil
Settings.cron_jobs['stuck_ci_jobs_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['stuck_ci_jobs_worker']['cron'] ||= '0 * * * *'
Settings.cron_jobs['stuck_ci_jobs_worker']['job_class'] = 'StuckCiJobsWorker'
@@ -572,6 +572,9 @@ Settings.cron_jobs['container_registry_migration_observer_worker']['job_class']
Settings.cron_jobs['container_registry_migration_enqueuer_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['container_registry_migration_enqueuer_worker']['cron'] ||= '15,45 */1 * * *'
Settings.cron_jobs['container_registry_migration_enqueuer_worker']['job_class'] = 'ContainerRegistry::Migration::EnqueuerWorker'
+Settings.cron_jobs['cleanup_container_registry_worker'] ||= Settingslogic.new({})
+Settings.cron_jobs['cleanup_container_registry_worker']['cron'] ||= '*/5 * * * *'
+Settings.cron_jobs['cleanup_container_registry_worker']['job_class'] = 'ContainerRegistry::CleanupWorker'
Settings.cron_jobs['image_ttl_group_policy_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['image_ttl_group_policy_worker']['cron'] ||= '40 0 * * *'
Settings.cron_jobs['image_ttl_group_policy_worker']['job_class'] = 'DependencyProxy::ImageTtlGroupPolicyWorker'
@@ -579,7 +582,7 @@ Settings.cron_jobs['cleanup_dependency_proxy_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['cleanup_dependency_proxy_worker']['cron'] ||= '20 3,15 * * *'
Settings.cron_jobs['cleanup_dependency_proxy_worker']['job_class'] = 'DependencyProxy::CleanupDependencyProxyWorker'
Settings.cron_jobs['cleanup_package_registry_worker'] ||= Settingslogic.new({})
-Settings.cron_jobs['cleanup_package_registry_worker']['cron'] ||= '20 0,12 * * *'
+Settings.cron_jobs['cleanup_package_registry_worker']['cron'] ||= '20 * * * *'
Settings.cron_jobs['cleanup_package_registry_worker']['job_class'] = 'Packages::CleanupPackageRegistryWorker'
Settings.cron_jobs['x509_issuer_crl_check_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['x509_issuer_crl_check_worker']['cron'] ||= '30 1 * * *'
@@ -770,7 +773,7 @@ Gitlab.ee do
Settings.cron_jobs['iterations_generator_worker']['cron'] ||= '5 0 * * *'
Settings.cron_jobs['iterations_generator_worker']['job_class'] = 'Iterations::Cadences::ScheduleCreateIterationsWorker'
Settings.cron_jobs['vulnerability_statistics_schedule_worker'] ||= Settingslogic.new({})
- Settings.cron_jobs['vulnerability_statistics_schedule_worker']['cron'] ||= '15 1 * * *'
+ Settings.cron_jobs['vulnerability_statistics_schedule_worker']['cron'] ||= '15 1,20 * * *'
Settings.cron_jobs['vulnerability_statistics_schedule_worker']['job_class'] = 'Vulnerabilities::Statistics::ScheduleWorker'
Settings.cron_jobs['vulnerability_historical_statistics_deletion_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['vulnerability_historical_statistics_deletion_worker']['cron'] ||= '15 3 * * *'
@@ -1023,6 +1026,7 @@ Settings.monitoring.sidekiq_health_checks['port'] ||= 8092
Settings.monitoring['web_exporter'] ||= Settingslogic.new({})
Settings.monitoring.web_exporter['enabled'] ||= false
+Settings.monitoring.web_exporter['log_enabled'] ||= true
Settings.monitoring.web_exporter['address'] ||= 'localhost'
Settings.monitoring.web_exporter['port'] ||= 8083
Settings.monitoring.web_exporter['tls_enabled'] ||= false
diff --git a/config/initializers/8_devise.rb b/config/initializers/8_devise.rb
index 65314c4472f..237231f544f 100644
--- a/config/initializers/8_devise.rb
+++ b/config/initializers/8_devise.rb
@@ -178,14 +178,6 @@ Devise.setup do |config|
# reset. Defaults to true, so a user is signed in automatically after a reset.
config.sign_in_after_reset_password = false
- # ==> Configuration for :encryptable
- # Allow you to use another encryption algorithm besides bcrypt (default). You can use
- # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1,
- # :authlogic_sha512 (then you should set stretches above to 20 for default behavior)
- # and :restful_authentication_sha1 (then you should set stretches to 10, and copy
- # REST_AUTH_SITE_KEY to pepper)
- config.encryptor = :pbkdf2_sha512
-
# Authentication through token does not store user in session and needs
# to be supplied on each request. Useful if you are using the token as API token.
config.skip_session_storage << :token_auth
diff --git a/config/initializers/active_support_json.rb b/config/initializers/active_support_json.rb
new file mode 100644
index 00000000000..5e38ebd7c89
--- /dev/null
+++ b/config/initializers/active_support_json.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module ActiveSupport
+ module JSON
+ module Encoding
+ self.json_encoder = Gitlab::Json::RailsEncoder
+
+ # This method is used only to test that our
+ # encoder maintains compatibility with the default
+ # ActiveSupport encoder. See spec/lib/gitlab/json_spec.rb
+ def self.use_encoder(encoder)
+ previous_encoder = json_encoder
+ self.json_encoder = encoder
+
+ result = yield
+
+ self.json_encoder = previous_encoder
+
+ result
+ end
+ end
+ end
+end
diff --git a/config/initializers/database_query_analyzers.rb b/config/initializers/database_query_analyzers.rb
index 2e73fbb79a2..ad6ed20b94d 100644
--- a/config/initializers/database_query_analyzers.rb
+++ b/config/initializers/database_query_analyzers.rb
@@ -1,15 +1,19 @@
# frozen_string_literal: true
# Currently we register validator only for `dev` or `test` environment
-Gitlab::Database::QueryAnalyzer.instance.hook!
-Gitlab::Database::QueryAnalyzer.instance.all_analyzers.append(::Gitlab::Database::QueryAnalyzers::GitlabSchemasMetrics)
-Gitlab::Database::QueryAnalyzer.instance.all_analyzers.append(
- ::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification
-)
+Gitlab::Database::QueryAnalyzer.instance.tap do |query_analyzer|
+ query_analyzer.hook!
-if Gitlab.dev_or_test_env?
- query_analyzer = ::Gitlab::Database::QueryAnalyzers::GitlabSchemasValidateConnection
- Gitlab::Database::QueryAnalyzer.instance.all_analyzers.append(query_analyzer)
+ query_analyzer.all_analyzers.tap do |analyzers|
+ analyzers.append(::Gitlab::Database::QueryAnalyzers::GitlabSchemasMetrics)
+ analyzers.append(::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification)
+ analyzers.append(::Gitlab::Database::QueryAnalyzers::Ci::PartitioningRoutingAnalyzer)
+
+ if Gitlab.dev_or_test_env?
+ analyzers.append(::Gitlab::Database::QueryAnalyzers::GitlabSchemasValidateConnection)
+ analyzers.append(::Gitlab::Database::QueryAnalyzers::QueryRecorder)
+ end
+ end
end
Gitlab::Application.configure do |config|
diff --git a/config/initializers/google_api_client_patch.rb b/config/initializers/google_api_client_patch.rb
index 1408dcb0501..2a832790f97 100644
--- a/config/initializers/google_api_client_patch.rb
+++ b/config/initializers/google_api_client_patch.rb
@@ -1,8 +1,9 @@
# frozen_string_literal: true
require 'google/apis/core/http_command'
+require 'google/apis/version'
-raise 'This patch is only tested with google-api-client-ruby v0.50.0' unless Google::Apis::VERSION == "0.50.0"
+raise 'This patch is only tested with google-api-client-ruby v0.53.0' unless Google::Apis::VERSION == "0.53.0"
# The google-api-ruby-client does not have a way to increase or disable
# the maximum allowed time for a request to be retried. By default, it
diff --git a/config/initializers/hashie_mash_permitted_patch.rb b/config/initializers/hashie_mash_permitted_patch.rb
new file mode 100644
index 00000000000..b793a408c91
--- /dev/null
+++ b/config/initializers/hashie_mash_permitted_patch.rb
@@ -0,0 +1,53 @@
+# frozen_string_literal: true
+
+# Pulls logic from https://github.com/Maxim-Filimonov/hashie-forbidden_attributes so we could drop the dependency.
+# This gem is simply `Hashie::Mash` monkey patch to allow mass assignment bypassing `:permitted?` check.
+#
+# Reasons:
+# 1. The gem was last updated 5 years ago and does not have CI setup to test under the latest Ruby/Rails.
+# 2. There is a significant chance this logic is not used at all.
+# We didn't find any explicit places in the code where we mass-assign to `Hashie::Mash`.
+# Experimental MR where we dropped the gem showed that no tests from the full suite failed:
+# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101535
+# 3. The logic is very simple. Even if we need it, keeping it in our codebase is better than pulling a dependency.
+# This logic will be visible and it will be one less gem to install.
+#
+# Next steps:
+# 1. Keep the patch for at least one milestone in our codebase. Log its usage.
+# 2. After that, check if there were any related log events.
+# 3. If no usages were tracked, we could drop the patch (delete this file).
+# 4. Otherwise, audit where and why we need it, and add a comment to that place.
+#
+# See discussion https://gitlab.com/gitlab-org/gitlab/-/issues/378398#note_1143133426
+
+require 'hashie/mash'
+
+module Hashie
+ class Mash
+ module MonkeyPatch
+ def respond_to_missing?(method_name, *args)
+ if method_name == :permitted?
+ Gitlab::AppLogger.info(message: 'Hashie::Mash#respond_to?(:permitted?)',
+ caller: Gitlab::BacktraceCleaner.clean_backtrace(caller))
+
+ return false
+ end
+
+ super
+ end
+
+ def method_missing(method_name, *args)
+ if method_name == :permitted?
+ Gitlab::AppLogger.info(message: 'Hashie::Mash#permitted?',
+ caller: Gitlab::BacktraceCleaner.clean_backtrace(caller))
+
+ raise ArgumentError
+ end
+
+ super
+ end
+ end
+
+ prepend MonkeyPatch
+ end
+end
diff --git a/config/initializers/memory_watchdog.rb b/config/initializers/memory_watchdog.rb
index ce8e5029e7a..99c5d61293f 100644
--- a/config/initializers/memory_watchdog.rb
+++ b/config/initializers/memory_watchdog.rb
@@ -1,35 +1,14 @@
# frozen_string_literal: true
return unless Gitlab::Runtime.application?
-return unless Gitlab::Utils.to_boolean(ENV['GITLAB_MEMORY_WATCHDOG_ENABLED'])
+return unless Gitlab::Utils.to_boolean(ENV['GITLAB_MEMORY_WATCHDOG_ENABLED'], default: Gitlab::Runtime.puma?)
Gitlab::Cluster::LifecycleEvents.on_worker_start do
watchdog = Gitlab::Memory::Watchdog.new
- max_strikes = ENV.fetch('GITLAB_MEMWD_MAX_STRIKES', 5).to_i
- sleep_time_seconds = ENV.fetch('GITLAB_MEMWD_SLEEP_TIME_SEC', 60).to_i
- max_mem_growth = ENV.fetch('GITLAB_MEMWD_MAX_MEM_GROWTH', 3.0).to_f
- max_heap_frag = ENV.fetch('GITLAB_MEMWD_MAX_HEAP_FRAG', 0.5).to_f
-
- watchdog.configure do |config|
- config.handler =
- if Gitlab::Runtime.puma?
- Gitlab::Memory::Watchdog::PumaHandler.new
- elsif Gitlab::Runtime.sidekiq?
- Gitlab::Memory::Watchdog::TermProcessHandler.new
- else
- Gitlab::Memory::Watchdog::NullHandler.instance
- end
-
- config.logger = Gitlab::AppLogger
- config.sleep_time_seconds = sleep_time_seconds
- # config.monitor.use MonitorClass, args*, max_strikes:, kwargs**, &block
- config.monitors.use Gitlab::Memory::Watchdog::Monitor::HeapFragmentation,
- max_heap_fragmentation: max_heap_frag,
- max_strikes: max_strikes
-
- config.monitors.use Gitlab::Memory::Watchdog::Monitor::UniqueMemoryGrowth,
- max_mem_growth: max_mem_growth,
- max_strikes: max_strikes
+ if Gitlab::Runtime.puma?
+ watchdog.configure(&Gitlab::Memory::Watchdog::Configurator.configure_for_puma)
+ elsif Gitlab::Runtime.sidekiq?
+ watchdog.configure(&Gitlab::Memory::Watchdog::Configurator.configure_for_sidekiq)
end
Gitlab::BackgroundTask.new(watchdog).start
diff --git a/config/initializers/sawyer_patch.rb b/config/initializers/sawyer_patch.rb
index 34d2843d165..2a946cf0f7d 100644
--- a/config/initializers/sawyer_patch.rb
+++ b/config/initializers/sawyer_patch.rb
@@ -6,47 +6,21 @@ module SawyerClassPatch
def attr_accessor(*attrs)
attrs.each do |attribute|
class_eval do
- # rubocop:disable Gitlab/ModuleWithInstanceVariables
- if method_defined?(attribute) || method_defined?("#{attribute}=") || method_defined?("#{attribute}?")
- define_method attribute do
- raise Sawyer::Error,
- "Sawyer method \"#{attribute}\" overlaps Ruby method. Convert to a hash to access the attribute."
- end
-
- define_method "#{attribute}=" do |value|
- raise Sawyer::Error,
- "Sawyer method \"#{attribute}\" overlaps Ruby method. Convert to a hash to access the attribute."
- end
-
- define_method "#{attribute}?" do
- raise Sawyer::Error,
- "Sawyer method \"#{attribute}\" overlaps Ruby method. Convert to a hash to access the attribute."
- end
- else
- define_method attribute do
- Gitlab::Import::Logger.warn(
- Gitlab::ApplicationContext.current.merge(
- {
- message: 'Sawyer attribute called',
- attribute: attribute,
- caller: Gitlab::BacktraceCleaner.clean_backtrace(caller)
- }
- )
- )
-
- @attrs[attribute.to_sym]
- end
+ define_method attribute do
+ raise Sawyer::Error,
+ "Sawyer method \"#{attribute}\" access is forbidden. Convert to a hash to access the attribute."
+ end
- define_method "#{attribute}=" do |value|
- @attrs[attribute.to_sym] = value
- end
+ define_method "#{attribute}=" do |value|
+ raise Sawyer::Error,
+ "Sawyer method \"#{attribute}=\" access is forbidden. Convert to a hash to access the attribute."
+ end
- define_method "#{attribute}?" do
- !!@attrs[attribute.to_sym]
- end
+ define_method "#{attribute}?" do
+ raise Sawyer::Error,
+ "Sawyer method \"#{attribute}?\" overlaps Ruby method. Convert to a hash to access the attribute."
end
end
- # rubocop:enable Gitlab/ModuleWithInstanceVariables
end
end
end
diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb
index cef34425bf4..363438849ed 100644
--- a/config/initializers/sidekiq.rb
+++ b/config/initializers/sidekiq.rb
@@ -35,19 +35,19 @@ enable_json_logs = Gitlab.config.sidekiq.log_format == 'json'
enable_sidekiq_memory_killer = ENV['SIDEKIQ_MEMORY_KILLER_MAX_RSS'].to_i.nonzero?
Sidekiq.configure_server do |config|
- config.options[:strict] = false
- config.options[:queues] = Gitlab::SidekiqConfig.expand_queues(config.options[:queues])
+ config[:strict] = false
+ config[:queues] = Gitlab::SidekiqConfig.expand_queues(config[:queues])
if enable_json_logs
config.log_formatter = Gitlab::SidekiqLogging::JSONFormatter.new
- config.options[:job_logger] = Gitlab::SidekiqLogging::StructuredLogger
+ config[:job_logger] = Gitlab::SidekiqLogging::StructuredLogger
# Remove the default-provided handler. The exception is logged inside
# Gitlab::SidekiqLogging::StructuredLogger
- config.error_handlers.reject! { |handler| handler.is_a?(Sidekiq::ExceptionHandler::Logger) }
+ config.error_handlers.delete(Sidekiq::DEFAULT_ERROR_HANDLER)
end
- Sidekiq.logger.info "Listening on queues #{config.options[:queues].uniq.sort}"
+ Sidekiq.logger.info "Listening on queues #{config[:queues].uniq.sort}"
config.redis = queues_config_hash
@@ -83,14 +83,18 @@ Sidekiq.configure_server do |config|
end
end
+ config.on(:shutdown) do
+ Gitlab::Cluster::LifecycleEvents.do_worker_stop
+ end
+
if enable_reliable_fetch?
- config.options[:semi_reliable_fetch] = enable_semi_reliable_fetch_mode?
+ config[:semi_reliable_fetch] = enable_semi_reliable_fetch_mode?
Sidekiq::ReliableFetch.setup_reliable_fetch!(config)
end
Gitlab::SidekiqVersioning.install!
- config.options[:cron_poll_interval] = Gitlab.config.cron_jobs.poll_interval
+ config[:cron_poll_interval] = Gitlab.config.cron_jobs.poll_interval
load_cron_jobs!
# Avoid autoload issue such as 'Mail::Parsers::AddressStruct'
@@ -114,3 +118,4 @@ end
Sidekiq::Scheduled::Poller.prepend Gitlab::Patch::SidekiqPoller
Sidekiq::Cron::Poller.prepend Gitlab::Patch::SidekiqPoller
+Sidekiq::Cron::Poller.prepend Gitlab::Patch::SidekiqCronPoller
diff --git a/config/initializers/sidekiq_cluster.rb b/config/initializers/sidekiq_cluster.rb
index 6fd598b3e25..5851e3bd838 100644
--- a/config/initializers/sidekiq_cluster.rb
+++ b/config/initializers/sidekiq_cluster.rb
@@ -19,7 +19,7 @@ if ENV['ENABLE_SIDEKIQ_CLUSTER']
# Allow sidekiq to cleanly terminate and push any running jobs back
# into the queue. We use the configured timeout and add a small
# grace period
- sleep(Sidekiq.options[:timeout] + 5)
+ sleep(Sidekiq[:timeout] + 5)
# Signaling the Sidekiq Pgroup as KILL is not forwarded to
# a possible child process. In Sidekiq Cluster, all child Sidekiq
diff --git a/config/initializers/types.rb b/config/initializers/types.rb
new file mode 100644
index 00000000000..4a20e257469
--- /dev/null
+++ b/config/initializers/types.rb
@@ -0,0 +1,3 @@
+# frozen_string_literal: true
+
+ActiveRecord::Type.register(:sym_jsonb, Gitlab::Database::Type::SymbolizedJsonb)
diff --git a/config/initializers/zz_metrics.rb b/config/initializers/zz_metrics.rb
index 940d8eed61f..ff3ae9a2467 100644
--- a/config/initializers/zz_metrics.rb
+++ b/config/initializers/zz_metrics.rb
@@ -40,8 +40,9 @@ if Gitlab::Metrics.enabled? && !Rails.env.test? && !(Rails.env.development? && d
if Gitlab::Runtime.puma?
Gitlab::Metrics::RequestsRackMiddleware.initialize_metrics
Gitlab::Metrics::GlobalSearchSlis.initialize_slis!
- elsif Gitlab.ee? && Gitlab::Runtime.sidekiq?
- Gitlab::Metrics::GlobalSearchIndexingSlis.initialize_slis!
+ elsif Gitlab::Runtime.sidekiq?
+ Gitlab::Metrics::GlobalSearchIndexingSlis.initialize_slis! if Gitlab.ee?
+ Gitlab::Metrics::LooseForeignKeysSlis.initialize_slis!
end
GC::Profiler.enable
diff --git a/config/initializers_before_autoloader/000_inflections.rb b/config/initializers_before_autoloader/000_inflections.rb
index dfd33938611..795b0f20128 100644
--- a/config/initializers_before_autoloader/000_inflections.rb
+++ b/config/initializers_before_autoloader/000_inflections.rb
@@ -17,6 +17,7 @@ ActiveSupport::Inflector.inflections do |inflect|
award_emoji
ci_secure_file_registry
container_repository_registry
+ dependency_proxy_blob_registry
design_registry
event_log
file_registry
@@ -30,6 +31,7 @@ ActiveSupport::Inflector.inflections do |inflect|
pipeline_artifact_registry
project_auto_devops
project_registry
+ project_wiki_repository_registry
project_statistics
snippet_repository_registry
system_note_metadata
diff --git a/config/locales/doorkeeper.zh-cn.yml b/config/locales/doorkeeper.zh-cn.yml
new file mode 100644
index 00000000000..f9b37c43866
--- /dev/null
+++ b/config/locales/doorkeeper.zh-cn.yml
@@ -0,0 +1,122 @@
+zh-CN:
+ activerecord:
+ errors:
+ models:
+ application:
+ attributes:
+ redirect_uri:
+ fragment_present: 'ä¸èƒ½åŒ…å«ç‰‡æ®µã€‚'
+ invalid_uri: '必须是一个有效的 URI。'
+ relative_uri: '必须是一个ç»å¯¹ URI。'
+ mongoid:
+ errors:
+ models:
+ application:
+ attributes:
+ redirect_uri:
+ fragment_present: 'ä¸èƒ½åŒ…å«ç‰‡æ®µã€‚'
+ invalid_uri: '必须是一个有效的 URI。'
+ relative_uri: '必须是一个ç»å¯¹ URI。'
+ mongo_mapper:
+ errors:
+ models:
+ application:
+ attributes:
+ redirect_uri:
+ fragment_present: 'ä¸èƒ½åŒ…å«ç‰‡æ®µã€‚'
+ invalid_uri: '必须是一个有效的 URI。'
+ relative_uri: '必须是一个ç»å¯¹ URI。'
+ doorkeeper:
+ errors:
+ messages:
+ # Common error messages
+ invalid_redirect_uri: '包å«çš„é‡å®šå‘ URI 无效。'
+ unauthorized_client: '客户端无æƒä½¿ç”¨æ­¤æ–¹æ³•æ‰§è¡Œæ­¤è¯·æ±‚。'
+ access_denied: '资æºæ‰€æœ‰è€…或授æƒæœåŠ¡å™¨æ‹’ç»äº†è¯¥è¯·æ±‚。'
+ invalid_scope: '请求的范围无效ã€æœªçŸ¥æˆ–æ ¼å¼ä¸æ­£ç¡®ã€‚'
+ server_error: '授æƒæœåŠ¡å™¨é‡åˆ°äº†æ„外情况,导致无法完æˆè¯·æ±‚。'
+ unconfirmed_email: '在您登录之å‰ï¼ŒéªŒè¯æ‚¨çš„å¸æˆ·é…置文件中的电å­é‚®ä»¶åœ°å€ã€‚'
+ temporarily_unavailable: '由于æœåŠ¡å™¨ä¸´æ—¶è¶…载或维护,授æƒæœåŠ¡å™¨ç›®å‰æ— æ³•å¤„ç†è¯·æ±‚。'
+
+ #configuration error messages
+ credential_flow_not_configured: '由于 Doorkeeper.configure.resource_owner_from_credentials 未é…置,资æºæ‰€æœ‰è€…密ç å‡­è¯æŽˆäºˆå·¥ä½œæµå¤±è´¥ã€‚'
+ resource_owner_authenticator_not_configured: '由于 Doorkeeper.configure.resource_owner_authenticator 未é…置,资æºæ‰€æœ‰è€…查找失败。'
+
+ # Access grant errors
+ unsupported_response_type: '授æƒæœåŠ¡å™¨ä¸æ”¯æŒæ­¤å“应类型。'
+
+ # Access token errors
+ invalid_client: '由于未知客户端ã€ä¸åŒ…括客户端身份验è¯æˆ–ä¸æ”¯æŒçš„身份验è¯æ–¹æ³•ï¼Œå®¢æˆ·ç«¯èº«ä»½éªŒè¯å¤±è´¥ã€‚'
+ invalid_grant: '所æ供的授æƒæ— æ•ˆã€è¿‡æœŸã€è¢«æ’¤é”€ã€ä¸ŽæŽˆæƒè¯·æ±‚中使用的é‡å®šå‘ URI ä¸åŒ¹é…,或者已å‘å¦ä¸€ä¸ªå®¢æˆ·ç«¯å‘出。'
+ unsupported_grant_type: '授æƒæœåŠ¡å™¨ä¸æ”¯æŒæŽˆæƒæŽˆäºˆç±»åž‹ã€‚'
+
+ # Password Access token errors
+ invalid_resource_owner: '所æ供的资æºæ‰€æœ‰è€…凭è¯æ— æ•ˆï¼Œæˆ–找ä¸åˆ°èµ„æºæ‰€æœ‰è€…。'
+
+ invalid_request:
+ unknown: '该请求缺少一个必需的å‚数,包括一个ä¸æ”¯æŒçš„å‚数值,或在其他方é¢æ˜¯é”™è¯¯çš„。'
+ missing_param: '缺少所需的å‚数:%{value}。'
+ not_support_pkce: '无效的 code_verifier å‚数。æœåŠ¡å™¨ä¸æ”¯æŒ pkce。'
+ request_not_authorized: '请求需è¦æŽˆæƒã€‚授æƒè¯·æ±‚所需的å‚数缺失或无效。'
+
+ invalid_token:
+ revoked: "访问令牌被撤销"
+ expired: "访问令牌过期"
+ unknown: "访问令牌无效"
+ scopes:
+ api: 访问ç»è¿‡éªŒè¯çš„用户的 API
+ read_user: 读å–已验è¯ç”¨æˆ·çš„个人信æ¯
+ read_repository: å…许对仓库进行åªè¯»è®¿é—®
+ write_repository: å…许对仓库进行读写访问
+ read_registry: 授予读å–容器镜åƒåº“é•œåƒçš„æƒé™
+ openid: 使用 OpenID Connect 进行身份验è¯
+ sudo: 作为系统中的任何用户执行 API æ“作
+ profile: å…许使用 OpenID Connect åªè¯»è®¿é—®ç”¨æˆ·çš„个人信æ¯
+ email: å…许使用 OpenID Connect åªè¯»è®¿é—®ç”¨æˆ·çš„主è¦ç”µå­é‚®ä»¶åœ°å€
+ scope_desc:
+ api:
+ 授予对 API 的完全读/写访问æƒï¼ŒåŒ…括所有群组和项目ã€å®¹å™¨é•œåƒåº“和软件包库。
+ read_api:
+ 授予对 API 的读访问æƒï¼ŒåŒ…括所有群组和项目ã€å®¹å™¨é•œåƒåº“和软件包库。
+ read_user:
+ 通过 /user API端点授予对通过身份验è¯çš„用户概è¦çš„åªè¯»è®¿é—®æƒï¼Œè¯¥ç«¯ç‚¹åŒ…括用户åã€å…¬å…±ç”µå­é‚®ä»¶å’Œå…¨å。还授予对 /users 下的åªè¯» API 端点的访问æƒã€‚
+ read_repository:
+ 使用 Git-over-HTTP 或 Repository Files API 授予对ç§æœ‰é¡¹ç›®ä»“库的åªè¯»è®¿é—®æƒã€‚
+ write_repository:
+ 使用 Git-over-HTTP (ä¸ä½¿ç”¨ API)授予对ç§æœ‰é¡¹ç›®ä¸Šçš„仓库的读写访问æƒã€‚
+ read_registry:
+ 授予对ç§æœ‰é¡¹ç›®ä¸Šçš„容器镜åƒåº“é•œåƒçš„åªè¯»è®¿é—®æƒã€‚
+ write_registry:
+ 授予对ç§æœ‰é¡¹ç›®ä¸Šçš„容器镜åƒåº“é•œåƒçš„写访问æƒã€‚
+ openid:
+ 授予使用 OpenID Connect 与 GitLab 进行身份验è¯çš„æƒé™ã€‚还æ供对用户é…置文件和组æˆå‘˜å…³ç³»çš„åªè¯»è®¿é—®æƒé™ã€‚
+ sudo:
+ 当以管ç†å‘˜ç”¨æˆ·èº«ä»½è¿›è¡Œèº«ä»½éªŒè¯æ—¶ï¼ŒæŽˆäºˆä½œä¸ºç³»ç»Ÿä¸­ä»»ä½•ç”¨æˆ·æ‰§è¡Œ API æ“作的æƒé™ã€‚
+ profile:
+ 使用 OpenID Connect 授予对用户é…置文件数æ®çš„åªè¯»è®¿é—®æƒã€‚
+ email:
+ 使用 OpenID Connect 授予对用户主电å­é‚®ä»¶åœ°å€çš„åªè¯»è®¿é—®æƒã€‚
+ project_access_token_scope_desc:
+ api:
+ 授予对é™å®šèŒƒå›´çš„项目 API 的完全读写访问æƒã€‚
+ read_api:
+ 授予对é™å®šèŒƒå›´çš„项目 API 的读访问æƒã€‚
+ read_repository:
+ å…许åªè¯»è®¿é—®ï¼ˆæ‹‰å–)到仓库。
+ write_repository:
+ å…许对仓库的读写访问(拉å–ã€æŽ¨é€ï¼‰ã€‚
+ read_registry:
+ 如果项目是ç§æœ‰çš„且需è¦æŽˆæƒï¼Œåˆ™å…许读å–(拉å–)容器镜åƒåº“é•œåƒã€‚
+ write_registry:
+ å…许写访问(推é€ï¼‰åˆ°å®¹å™¨é•œåƒåº“。
+ flash:
+ applications:
+ create:
+ notice: '创建应用æˆåŠŸã€‚'
+ destroy:
+ notice: '删除应用æˆåŠŸã€‚'
+ update:
+ notice: '更新应用æˆåŠŸã€‚'
+ authorized_applications:
+ destroy:
+ notice: '应用被撤销访问æƒé™ã€‚'
diff --git a/config/metrics/counts_28d/20210216180745_action_monthly_active_users_design_management.yml b/config/metrics/counts_28d/20210216180745_action_monthly_active_users_design_management.yml
index 28b876507a7..ca47e918461 100644
--- a/config/metrics/counts_28d/20210216180745_action_monthly_active_users_design_management.yml
+++ b/config/metrics/counts_28d/20210216180745_action_monthly_active_users_design_management.yml
@@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: 28d
data_source: redis_hll
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - design_action
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216180747_action_monthly_active_users_wiki_repo.yml b/config/metrics/counts_28d/20210216180747_action_monthly_active_users_wiki_repo.yml
index 9e1c5477bab..2a9353caf6a 100644
--- a/config/metrics/counts_28d/20210216180747_action_monthly_active_users_wiki_repo.yml
+++ b/config/metrics/counts_28d/20210216180747_action_monthly_active_users_wiki_repo.yml
@@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: 28d
data_source: redis_hll
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - wiki_action
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216181150_projects_jira_active.yml b/config/metrics/counts_28d/20210216181150_projects_jira_active.yml
index dcfe0bb5638..6f687b89560 100644
--- a/config/metrics/counts_28d/20210216181150_projects_jira_active.yml
+++ b/config/metrics/counts_28d/20210216181150_projects_jira_active.yml
@@ -3,7 +3,7 @@ data_category: operational
key_path: usage_activity_by_stage_monthly.plan.projects_jira_active
description: Distinct count of creator_id from projects with an active Jira integration.
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_28d/20210216181152_projects_jira_dvcs_cloud_active.yml b/config/metrics/counts_28d/20210216181152_projects_jira_dvcs_cloud_active.yml
index 9c2a821ea1d..ba6994ac23a 100644
--- a/config/metrics/counts_28d/20210216181152_projects_jira_dvcs_cloud_active.yml
+++ b/config/metrics/counts_28d/20210216181152_projects_jira_dvcs_cloud_active.yml
@@ -4,7 +4,7 @@ key_path: usage_activity_by_stage_monthly.plan.projects_jira_dvcs_cloud_active
description: Distinct count of creator_id from projects with an active Jira Cloud
DVCS integration.
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integration
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_28d/20210216181154_projects_jira_dvcs_server_active.yml b/config/metrics/counts_28d/20210216181154_projects_jira_dvcs_server_active.yml
index 214dd882f1f..3d327b17de0 100644
--- a/config/metrics/counts_28d/20210216181154_projects_jira_dvcs_server_active.yml
+++ b/config/metrics/counts_28d/20210216181154_projects_jira_dvcs_server_active.yml
@@ -4,7 +4,7 @@ key_path: usage_activity_by_stage_monthly.plan.projects_jira_dvcs_server_active
description: Distinct count of creator_id from projects with an active Jira Server
DVCS integration.
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integration
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_28d/20210216182040_action_monthly_active_users_project_repo.yml b/config/metrics/counts_28d/20210216182040_action_monthly_active_users_project_repo.yml
index 3db7aec4eab..4744976f4d1 100644
--- a/config/metrics/counts_28d/20210216182040_action_monthly_active_users_project_repo.yml
+++ b/config/metrics/counts_28d/20210216182040_action_monthly_active_users_project_repo.yml
@@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: 28d
data_source: redis_hll
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - project_action
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216182041_action_monthly_active_users_git_write.yml b/config/metrics/counts_28d/20210216182041_action_monthly_active_users_git_write.yml
index eaad616dbb5..153596352e7 100644
--- a/config/metrics/counts_28d/20210216182041_action_monthly_active_users_git_write.yml
+++ b/config/metrics/counts_28d/20210216182041_action_monthly_active_users_git_write.yml
@@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: 28d
data_source: redis_hll
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - git_write_action
distribution:
- ce
- ee
diff --git a/config/metrics/counts_28d/20210216184941_i_ecosystem_jira_service_close_issue_monthly.yml b/config/metrics/counts_28d/20210216184941_i_ecosystem_jira_service_close_issue_monthly.yml
index bb919257a57..d1b7a63db8e 100644
--- a/config/metrics/counts_28d/20210216184941_i_ecosystem_jira_service_close_issue_monthly.yml
+++ b/config/metrics/counts_28d/20210216184941_i_ecosystem_jira_service_close_issue_monthly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_jira_service_close_issue_monthly
description: Number of users closing Jira issues by month
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_28d/20210216184945_i_ecosystem_jira_service_cross_reference_monthly.yml b/config/metrics/counts_28d/20210216184945_i_ecosystem_jira_service_cross_reference_monthly.yml
index efd75c178b3..cea761bd778 100644
--- a/config/metrics/counts_28d/20210216184945_i_ecosystem_jira_service_cross_reference_monthly.yml
+++ b/config/metrics/counts_28d/20210216184945_i_ecosystem_jira_service_cross_reference_monthly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_jira_service_cross_reference_monthly
description: Number of users that cross-referenced Jira issues by month
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_28d/20210216184957_ecosystem_total_unique_counts_monthly.yml b/config/metrics/counts_28d/20210216184957_ecosystem_total_unique_counts_monthly.yml
index 9f62f61a967..7b18f83973a 100644
--- a/config/metrics/counts_28d/20210216184957_ecosystem_total_unique_counts_monthly.yml
+++ b/config/metrics/counts_28d/20210216184957_ecosystem_total_unique_counts_monthly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.ecosystem_total_unique_counts_monthly
description: Number of users for Jira and Slack by month
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_28d/20210303150507_i_ecosystem_slack_service_issue_notification_monthly.yml b/config/metrics/counts_28d/20210303150507_i_ecosystem_slack_service_issue_notification_monthly.yml
index d668067c0ff..01e2b9d0059 100644
--- a/config/metrics/counts_28d/20210303150507_i_ecosystem_slack_service_issue_notification_monthly.yml
+++ b/config/metrics/counts_28d/20210303150507_i_ecosystem_slack_service_issue_notification_monthly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_issue_notification_monthly
description: Calculated unique users to trigger a Slack message by performing an action on an issue by month
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_28d/20210303150654_i_ecosystem_slack_service_push_notification_monthly.yml b/config/metrics/counts_28d/20210303150654_i_ecosystem_slack_service_push_notification_monthly.yml
index f342e358301..d028a10c1a3 100644
--- a/config/metrics/counts_28d/20210303150654_i_ecosystem_slack_service_push_notification_monthly.yml
+++ b/config/metrics/counts_28d/20210303150654_i_ecosystem_slack_service_push_notification_monthly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_push_notification_monthly
description: Calculated unique users to trigger a Slack message by performing a Git push by month
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_28d/20210303150912_i_ecosystem_slack_service_deployment_notification_monthly.yml b/config/metrics/counts_28d/20210303150912_i_ecosystem_slack_service_deployment_notification_monthly.yml
index daa96258a11..2b8f4166e6b 100644
--- a/config/metrics/counts_28d/20210303150912_i_ecosystem_slack_service_deployment_notification_monthly.yml
+++ b/config/metrics/counts_28d/20210303150912_i_ecosystem_slack_service_deployment_notification_monthly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_deployment_notification_monthly
description: Calculated unique users to trigger a Slack message by performing a deployment by month
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_28d/20210303151609_i_ecosystem_slack_service_wiki_page_notification_monthly.yml b/config/metrics/counts_28d/20210303151609_i_ecosystem_slack_service_wiki_page_notification_monthly.yml
index d8852ab90bd..7b5515f99a5 100644
--- a/config/metrics/counts_28d/20210303151609_i_ecosystem_slack_service_wiki_page_notification_monthly.yml
+++ b/config/metrics/counts_28d/20210303151609_i_ecosystem_slack_service_wiki_page_notification_monthly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_wiki_page_notification_monthly
description: Calculated unique users to trigger a Slack message by performing an action on a wiki page by month
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_28d/20210303151831_i_ecosystem_slack_service_merge_request_notification_monthly.yml b/config/metrics/counts_28d/20210303151831_i_ecosystem_slack_service_merge_request_notification_monthly.yml
index 9b485c7c39d..7229d9b0803 100644
--- a/config/metrics/counts_28d/20210303151831_i_ecosystem_slack_service_merge_request_notification_monthly.yml
+++ b/config/metrics/counts_28d/20210303151831_i_ecosystem_slack_service_merge_request_notification_monthly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_merge_request_notification_monthly
description: Calculated unique users to trigger a Slack message by performing an action on a merge request by month
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_28d/20210303151946_i_ecosystem_slack_service_note_notification_monthly.yml b/config/metrics/counts_28d/20210303151946_i_ecosystem_slack_service_note_notification_monthly.yml
index f407a19aab3..bd2269d1680 100644
--- a/config/metrics/counts_28d/20210303151946_i_ecosystem_slack_service_note_notification_monthly.yml
+++ b/config/metrics/counts_28d/20210303151946_i_ecosystem_slack_service_note_notification_monthly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_note_notification_monthly
description: Calculated unique users to trigger a Slack message by creating a note by month
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_28d/20210303152049_i_ecosystem_slack_service_tag_push_notification_monthly.yml b/config/metrics/counts_28d/20210303152049_i_ecosystem_slack_service_tag_push_notification_monthly.yml
index f815f161859..73fa05ac498 100644
--- a/config/metrics/counts_28d/20210303152049_i_ecosystem_slack_service_tag_push_notification_monthly.yml
+++ b/config/metrics/counts_28d/20210303152049_i_ecosystem_slack_service_tag_push_notification_monthly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_tag_push_notification_monthly
description: Calculated unique users to trigger a Slack message by performing a tag push by month
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_28d/20210303152144_i_ecosystem_slack_service_confidential_note_notification_monthly.yml b/config/metrics/counts_28d/20210303152144_i_ecosystem_slack_service_confidential_note_notification_monthly.yml
index b8485c38da2..5cb154ad6e4 100644
--- a/config/metrics/counts_28d/20210303152144_i_ecosystem_slack_service_confidential_note_notification_monthly.yml
+++ b/config/metrics/counts_28d/20210303152144_i_ecosystem_slack_service_confidential_note_notification_monthly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_confidential_note_notification_monthly
description: Calculated unique users to trigger a Slack message by creating a confidential note by month
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_28d/20210303152233_i_ecosystem_slack_service_confidential_issue_notification_monthly.yml b/config/metrics/counts_28d/20210303152233_i_ecosystem_slack_service_confidential_issue_notification_monthly.yml
index 023bf9955b9..bcd3147e9ea 100644
--- a/config/metrics/counts_28d/20210303152233_i_ecosystem_slack_service_confidential_issue_notification_monthly.yml
+++ b/config/metrics/counts_28d/20210303152233_i_ecosystem_slack_service_confidential_issue_notification_monthly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_confidential_issue_notification_monthly
description: Calculated unique users to trigger a Slack message by performing an action on a confidential issue by month
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_28d/20220222215951_xmau_plan.yml b/config/metrics/counts_28d/20220222215951_xmau_plan.yml
index c254ad942c2..70cc27b801c 100644
--- a/config/metrics/counts_28d/20220222215951_xmau_plan.yml
+++ b/config/metrics/counts_28d/20220222215951_xmau_plan.yml
@@ -22,6 +22,8 @@ options:
- users_updating_work_item_dates
- users_updating_work_item_labels
- users_updating_work_item_iteration
+ - users_updating_weight_estimate
+ - users_updating_work_item_milestone
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_28d/20220222215952_xmau_project_management.yml b/config/metrics/counts_28d/20220222215952_xmau_project_management.yml
index 0dad4fd0979..13a943c972c 100644
--- a/config/metrics/counts_28d/20220222215952_xmau_project_management.yml
+++ b/config/metrics/counts_28d/20220222215952_xmau_project_management.yml
@@ -22,6 +22,8 @@ options:
- users_updating_work_item_dates
- users_updating_work_item_labels
- users_updating_work_item_iteration
+ - users_updating_weight_estimate
+ - users_updating_work_item_milestone
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_28d/20220222215955_users_work_items.yml b/config/metrics/counts_28d/20220222215955_users_work_items.yml
index ec07fb25f11..cb3dc63035f 100644
--- a/config/metrics/counts_28d/20220222215955_users_work_items.yml
+++ b/config/metrics/counts_28d/20220222215955_users_work_items.yml
@@ -22,6 +22,8 @@ options:
- users_updating_work_item_dates
- users_updating_work_item_labels
- users_updating_work_item_iteration
+ - users_updating_weight_estimate
+ - users_updating_work_item_milestone
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_28d/20220621085114_unique_active_users_monthly.yml b/config/metrics/counts_28d/20220621085114_unique_active_users_monthly.yml
index 3282a4db173..06b1cbcc3cc 100644
--- a/config/metrics/counts_28d/20220621085114_unique_active_users_monthly.yml
+++ b/config/metrics/counts_28d/20220621085114_unique_active_users_monthly.yml
@@ -10,7 +10,7 @@ milestone: "15.2"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90468/
time_frame: 28d
data_source: redis_hll
-data_category: optional
+data_category: operational
instrumentation_class: RedisHLLMetric
options:
events:
diff --git a/config/metrics/counts_28d/20220707022802_users_updating_weight_estimate_monthly.yml b/config/metrics/counts_28d/20220707022802_users_updating_weight_estimate_monthly.yml
new file mode 100644
index 00000000000..88fc09b6cc2
--- /dev/null
+++ b/config/metrics/counts_28d/20220707022802_users_updating_weight_estimate_monthly.yml
@@ -0,0 +1,26 @@
+---
+key_path: redis_hll_counters.work_items.users_updating_weight_estimate_monthly
+name: users_updating_weight_estimate_monthly
+description: Unique users updating a work item's weight estimate
+product_category: team_planning
+product_section: dev
+product_stage: plan
+product_group: project_management
+value_type: number
+status: active
+milestone: "15.2"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91957
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+performance_indicator_type: []
+options:
+ events:
+ - users_updating_weight_estimate
+distribution:
+- ce
+- ee
+tier:
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20221031070329_users_updating_work_item_milestone_monthly.yml b/config/metrics/counts_28d/20221031070329_users_updating_work_item_milestone_monthly.yml
new file mode 100644
index 00000000000..02edb32765e
--- /dev/null
+++ b/config/metrics/counts_28d/20221031070329_users_updating_work_item_milestone_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.work_items.users_updating_work_item_milestone_monthly
+description: Unique users updating a work item's milestone
+product_section: dev
+product_stage: plan
+product_group: project_management
+product_category: team_planning
+value_type: number
+status: active
+milestone: "15.6"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102495
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - users_updating_work_item_milestone
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
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
new file mode 100644
index 00000000000..ef51a24bc1e
--- /dev/null
+++ b/config/metrics/counts_28d/20221101190915_i_testing_coverage_report_uploaded_monthly.yml
@@ -0,0 +1,26 @@
+---
+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_category: testing
+value_type: number
+status: active
+milestone: "15.6"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102371
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_testing_coverage_report_uploaded
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20221108101211_merge_request_authors_monthly.yml b/config/metrics/counts_28d/20221108101211_merge_request_authors_monthly.yml
new file mode 100644
index 00000000000..5987bde2d14
--- /dev/null
+++ b/config/metrics/counts_28d/20221108101211_merge_request_authors_monthly.yml
@@ -0,0 +1,22 @@
+---
+key_path: usage_activity_by_stage_monthly.create.merge_request_authors_monthly
+description: Number of unique merge request authors
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.6"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103334
+time_frame: 28d
+data_source: database
+data_category: optional
+instrumentation_class: CountMergeRequestAuthorsMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20210216180620_incident_management_total_unique_counts_weekly.yml b/config/metrics/counts_7d/20210216180620_incident_management_total_unique_counts_weekly.yml
index 7bc0d698f3a..03ea343b1da 100644
--- a/config/metrics/counts_7d/20210216180620_incident_management_total_unique_counts_weekly.yml
+++ b/config/metrics/counts_7d/20210216180620_incident_management_total_unique_counts_weekly.yml
@@ -10,8 +10,11 @@ value_type: number
status: active
time_frame: 7d
data_source: redis_hll
-instrumentation_class: RedisHLLMetric
+instrumentation_class: AggregatedMetric
options:
+ aggregate:
+ operator: OR
+ attribute: user_id
events:
- incident_management_incident_created
- incident_management_incident_reopened
diff --git a/config/metrics/counts_7d/20210216184848_deploy_token_packages_total_unique_counts_weekly.yml b/config/metrics/counts_7d/20210216184848_deploy_token_packages_total_unique_counts_weekly.yml
index 19bb7f0ba3c..967e8e5888e 100644
--- a/config/metrics/counts_7d/20210216184848_deploy_token_packages_total_unique_counts_weekly.yml
+++ b/config/metrics/counts_7d/20210216184848_deploy_token_packages_total_unique_counts_weekly.yml
@@ -27,6 +27,7 @@ options:
- i_package_pypi_deploy_token
- i_package_rubygems_deploy_token
- i_package_terraform_module_deploy_token
+ - i_package_rpm_deploy_token
distribution:
- ee
- ce
diff --git a/config/metrics/counts_7d/20210216184939_i_ecosystem_jira_service_close_issue_weekly.yml b/config/metrics/counts_7d/20210216184939_i_ecosystem_jira_service_close_issue_weekly.yml
index 2b433855670..b650f2ff5fa 100644
--- a/config/metrics/counts_7d/20210216184939_i_ecosystem_jira_service_close_issue_weekly.yml
+++ b/config/metrics/counts_7d/20210216184939_i_ecosystem_jira_service_close_issue_weekly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_jira_service_close_issue_weekly
description: Number of users closing Jira issues by week
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_7d/20210216184943_i_ecosystem_jira_service_cross_reference_weekly.yml b/config/metrics/counts_7d/20210216184943_i_ecosystem_jira_service_cross_reference_weekly.yml
index aa3c99eab67..4058804272b 100644
--- a/config/metrics/counts_7d/20210216184943_i_ecosystem_jira_service_cross_reference_weekly.yml
+++ b/config/metrics/counts_7d/20210216184943_i_ecosystem_jira_service_cross_reference_weekly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_jira_service_cross_reference_weekly
description: Number of users that cross-referenced Jira issues by week
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_7d/20210216184955_ecosystem_total_unique_counts_weekly.yml b/config/metrics/counts_7d/20210216184955_ecosystem_total_unique_counts_weekly.yml
index 350a7032493..968525a9005 100644
--- a/config/metrics/counts_7d/20210216184955_ecosystem_total_unique_counts_weekly.yml
+++ b/config/metrics/counts_7d/20210216184955_ecosystem_total_unique_counts_weekly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.ecosystem_total_unique_counts_weekly
description: Number of users performing actions on Jira issues by week
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_7d/20210302103002_i_ecosystem_slack_service_issue_notification_weekly.yml b/config/metrics/counts_7d/20210302103002_i_ecosystem_slack_service_issue_notification_weekly.yml
index fac4c52904a..3a7cee3cc4f 100644
--- a/config/metrics/counts_7d/20210302103002_i_ecosystem_slack_service_issue_notification_weekly.yml
+++ b/config/metrics/counts_7d/20210302103002_i_ecosystem_slack_service_issue_notification_weekly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_issue_notification_weekly
description: Calculated unique users to trigger a Slack message by performing an action on an issue by week
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_7d/20210302103629_i_ecosystem_slack_service_push_notification_weekly.yml b/config/metrics/counts_7d/20210302103629_i_ecosystem_slack_service_push_notification_weekly.yml
index bac63e461c9..6c10ec49dfe 100644
--- a/config/metrics/counts_7d/20210302103629_i_ecosystem_slack_service_push_notification_weekly.yml
+++ b/config/metrics/counts_7d/20210302103629_i_ecosystem_slack_service_push_notification_weekly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_push_notification_weekly
description: Calculated unique users to trigger a Slack message by performing a Git push by week
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_7d/20210302103755_i_ecosystem_slack_service_deployment_notification_weekly.yml b/config/metrics/counts_7d/20210302103755_i_ecosystem_slack_service_deployment_notification_weekly.yml
index 30ee2e05a18..f26b088c356 100644
--- a/config/metrics/counts_7d/20210302103755_i_ecosystem_slack_service_deployment_notification_weekly.yml
+++ b/config/metrics/counts_7d/20210302103755_i_ecosystem_slack_service_deployment_notification_weekly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_deployment_notification_weekly
description: Calculated unique users to trigger a Slack message by performing a deployment by week
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_7d/20210302103907_i_ecosystem_slack_service_wiki_page_notification_weekly.yml b/config/metrics/counts_7d/20210302103907_i_ecosystem_slack_service_wiki_page_notification_weekly.yml
index 54ff97eeb13..dc0bf804080 100644
--- a/config/metrics/counts_7d/20210302103907_i_ecosystem_slack_service_wiki_page_notification_weekly.yml
+++ b/config/metrics/counts_7d/20210302103907_i_ecosystem_slack_service_wiki_page_notification_weekly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_wiki_page_notification_weekly
description: Calculated unique users to trigger a Slack message by performing an action on a wiki page by week
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_7d/20210302104007_i_ecosystem_slack_service_merge_request_notification_weekly.yml b/config/metrics/counts_7d/20210302104007_i_ecosystem_slack_service_merge_request_notification_weekly.yml
index 4a2a99f8282..b27cec15caa 100644
--- a/config/metrics/counts_7d/20210302104007_i_ecosystem_slack_service_merge_request_notification_weekly.yml
+++ b/config/metrics/counts_7d/20210302104007_i_ecosystem_slack_service_merge_request_notification_weekly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_merge_request_notification_weekly
description: Calculated unique users to trigger a Slack message by performing an action on a merge request by week
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_7d/20210302104047_i_ecosystem_slack_service_note_notification_weekly.yml b/config/metrics/counts_7d/20210302104047_i_ecosystem_slack_service_note_notification_weekly.yml
index 559940a3be9..d56eec656ae 100644
--- a/config/metrics/counts_7d/20210302104047_i_ecosystem_slack_service_note_notification_weekly.yml
+++ b/config/metrics/counts_7d/20210302104047_i_ecosystem_slack_service_note_notification_weekly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_note_notification_weekly
description: Calculated unique users to trigger a Slack message by creating a note by week
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_7d/20210302104144_i_ecosystem_slack_service_tag_push_notification_weekly.yml b/config/metrics/counts_7d/20210302104144_i_ecosystem_slack_service_tag_push_notification_weekly.yml
index a029e1b30c4..671a2f4ac58 100644
--- a/config/metrics/counts_7d/20210302104144_i_ecosystem_slack_service_tag_push_notification_weekly.yml
+++ b/config/metrics/counts_7d/20210302104144_i_ecosystem_slack_service_tag_push_notification_weekly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_tag_push_notification_weekly
description: Calculated unique users to trigger a Slack message by performing a tag push by week
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_7d/20210302104556_i_ecosystem_slack_service_confidential_note_notification_weekly.yml b/config/metrics/counts_7d/20210302104556_i_ecosystem_slack_service_confidential_note_notification_weekly.yml
index b278b731c7d..3a80c12cdd1 100644
--- a/config/metrics/counts_7d/20210302104556_i_ecosystem_slack_service_confidential_note_notification_weekly.yml
+++ b/config/metrics/counts_7d/20210302104556_i_ecosystem_slack_service_confidential_note_notification_weekly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_confidential_note_notification_weekly
description: Calculated unique users to trigger a Slack message by creating a confidential note by week
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_7d/20210302104814_i_ecosystem_slack_service_confidential_issue_notification_weekly.yml b/config/metrics/counts_7d/20210302104814_i_ecosystem_slack_service_confidential_issue_notification_weekly.yml
index fe0a2011392..addaed1b2c1 100644
--- a/config/metrics/counts_7d/20210302104814_i_ecosystem_slack_service_confidential_issue_notification_weekly.yml
+++ b/config/metrics/counts_7d/20210302104814_i_ecosystem_slack_service_confidential_issue_notification_weekly.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: redis_hll_counters.ecosystem.i_ecosystem_slack_service_confidential_issue_notification_weekly
description: Calculated unique users to trigger a Slack message by performing an action on a confidential issue by week
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_7d/20210916102312_templates_gitlab_slack_application_active.yml b/config/metrics/counts_7d/20210916102312_templates_gitlab_slack_application_active.yml
index d1021ed4c0b..06952dd2050 100644
--- a/config/metrics/counts_7d/20210916102312_templates_gitlab_slack_application_active.yml
+++ b/config/metrics/counts_7d/20210916102312_templates_gitlab_slack_application_active.yml
@@ -3,7 +3,7 @@ key_path: counts.templates_gitlab_slack_application_active
name: count_templates_gitlab_slack_application_active
description: Count templates with active slack application
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_7d/20220222215851_xmau_plan.yml b/config/metrics/counts_7d/20220222215851_xmau_plan.yml
index 77325a205ee..4520652ddf1 100644
--- a/config/metrics/counts_7d/20220222215851_xmau_plan.yml
+++ b/config/metrics/counts_7d/20220222215851_xmau_plan.yml
@@ -22,6 +22,8 @@ options:
- users_updating_work_item_dates
- users_updating_work_item_labels
- users_updating_work_item_iteration
+ - users_updating_weight_estimate
+ - users_updating_work_item_milestone
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_7d/20220222215852_xmau_project_management.yml b/config/metrics/counts_7d/20220222215852_xmau_project_management.yml
index c7e712cf92a..59543e71dcb 100644
--- a/config/metrics/counts_7d/20220222215852_xmau_project_management.yml
+++ b/config/metrics/counts_7d/20220222215852_xmau_project_management.yml
@@ -22,6 +22,8 @@ options:
- users_updating_work_item_dates
- users_updating_work_item_labels
- users_updating_work_item_iteration
+ - users_updating_weight_estimate
+ - users_updating_work_item_milestone
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_7d/20220222215855_users_work_items.yml b/config/metrics/counts_7d/20220222215855_users_work_items.yml
index 0985f38c83b..6dc426231e9 100644
--- a/config/metrics/counts_7d/20220222215855_users_work_items.yml
+++ b/config/metrics/counts_7d/20220222215855_users_work_items.yml
@@ -22,6 +22,8 @@ options:
- users_updating_work_item_dates
- users_updating_work_item_labels
- users_updating_work_item_iteration
+ - users_updating_weight_estimate
+ - users_updating_work_item_milestone
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_7d/20220707022758_users_updating_weight_estimate_weekly.yml b/config/metrics/counts_7d/20220707022758_users_updating_weight_estimate_weekly.yml
new file mode 100644
index 00000000000..17486482ad1
--- /dev/null
+++ b/config/metrics/counts_7d/20220707022758_users_updating_weight_estimate_weekly.yml
@@ -0,0 +1,26 @@
+---
+key_path: redis_hll_counters.work_items.users_updating_weight_estimate_weekly
+name: users_updating_weight_estimate_weekly
+description: Unique users updating a work item's weight estimate
+product_category: team_planning
+product_section: dev
+product_stage: plan
+product_group: project_management
+value_type: number
+status: active
+milestone: "15.2"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91957
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+performance_indicator_type: []
+options:
+ events:
+ - users_updating_weight_estimate
+distribution:
+- ce
+- ee
+tier:
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20220909143617_i_package_rpm_user_weekly.yml b/config/metrics/counts_7d/20220909143617_i_package_rpm_user_weekly.yml
new file mode 100644
index 00000000000..895e6c3cf91
--- /dev/null
+++ b/config/metrics/counts_7d/20220909143617_i_package_rpm_user_weekly.yml
@@ -0,0 +1,25 @@
+---
+data_category: optional
+key_path: redis_hll_counters.user_packages.i_package_rpm_user_weekly
+description: A weekly count of users that have published an rpm package to the registry
+product_section: ops
+product_stage: package
+product_group: package
+product_category: package_registry
+value_type: number
+status: active
+milestone: '15.6'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97133
+time_frame: 7d
+data_source: redis_hll
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_package_rpm_user
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20220913104805_i_package_rpm_deploy_token_weekly.yml b/config/metrics/counts_7d/20220913104805_i_package_rpm_deploy_token_weekly.yml
new file mode 100644
index 00000000000..37f539d1ec4
--- /dev/null
+++ b/config/metrics/counts_7d/20220913104805_i_package_rpm_deploy_token_weekly.yml
@@ -0,0 +1,25 @@
+---
+data_category: optional
+key_path: redis_hll_counters.deploy_token_packages.i_package_rpm_deploy_token_weekly
+description: A weekly count of RPM packages published to the registry using a deploy token
+product_section: ops
+product_stage: package
+product_group: package
+product_category: package_registry
+value_type: number
+status: active
+milestone: '15.6'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97133
+time_frame: 7d
+data_source: redis_hll
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_package_rpm_deploy_token
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20221031065930_users_updating_work_item_milestone_weekly.yml b/config/metrics/counts_7d/20221031065930_users_updating_work_item_milestone_weekly.yml
new file mode 100644
index 00000000000..a06f0a5bdbe
--- /dev/null
+++ b/config/metrics/counts_7d/20221031065930_users_updating_work_item_milestone_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.work_items.users_updating_work_item_milestone_weekly
+description: Unique users updating a work item's milestone
+product_section: dev
+product_stage: plan
+product_group: project_management
+product_category: team_planning
+value_type: number
+status: active
+milestone: "15.6"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102495
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - users_updating_work_item_milestone
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
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
new file mode 100644
index 00000000000..be6ba98c10c
--- /dev/null
+++ b/config/metrics/counts_7d/20221101190913_i_testing_coverage_report_uploaded_weekly.yml
@@ -0,0 +1,26 @@
+---
+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_category: testing
+value_type: number
+status: active
+milestone: "15.6"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102371
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_testing_coverage_report_uploaded
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20210216175621_web_hooks.yml b/config/metrics/counts_all/20210216175621_web_hooks.yml
index 8614e7d4be6..416c4f739e9 100644
--- a/config/metrics/counts_all/20210216175621_web_hooks.yml
+++ b/config/metrics/counts_all/20210216175621_web_hooks.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.web_hooks
description: Count of web hooks
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category:
value_type: number
diff --git a/config/metrics/counts_all/20210216175623_projects_asana_active.yml b/config/metrics/counts_all/20210216175623_projects_asana_active.yml
index 5b6e4ece343..f5d77814ff9 100644
--- a/config/metrics/counts_all/20210216175623_projects_asana_active.yml
+++ b/config/metrics/counts_all/20210216175623_projects_asana_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_asana_active
description: Count of projects with active integrations for Asana
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175625_groups_asana_active.yml b/config/metrics/counts_all/20210216175625_groups_asana_active.yml
index 87269b04570..e2ee8440616 100644
--- a/config/metrics/counts_all/20210216175625_groups_asana_active.yml
+++ b/config/metrics/counts_all/20210216175625_groups_asana_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_asana_active
description: Count of groups with active integrations for Asana
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175627_templates_asana_active.yml b/config/metrics/counts_all/20210216175627_templates_asana_active.yml
index 121409c5b7f..0fc5c5321ef 100644
--- a/config/metrics/counts_all/20210216175627_templates_asana_active.yml
+++ b/config/metrics/counts_all/20210216175627_templates_asana_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_asana_active
description: Count of active service templates for Asana
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175628_instances_asana_active.yml b/config/metrics/counts_all/20210216175628_instances_asana_active.yml
index 0a5c5fa1242..70047243025 100644
--- a/config/metrics/counts_all/20210216175628_instances_asana_active.yml
+++ b/config/metrics/counts_all/20210216175628_instances_asana_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_asana_active
description: Count of active instance-level integrations for Asana
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175630_projects_inheriting_asana_active.yml b/config/metrics/counts_all/20210216175630_projects_inheriting_asana_active.yml
index be27b267acd..e5bd8119cef 100644
--- a/config/metrics/counts_all/20210216175630_projects_inheriting_asana_active.yml
+++ b/config/metrics/counts_all/20210216175630_projects_inheriting_asana_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_asana_active
description: Count of active projects inheriting integrations for Asana
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175632_groups_inheriting_asana_active.yml b/config/metrics/counts_all/20210216175632_groups_inheriting_asana_active.yml
index 06bb348d677..df2237ce08d 100644
--- a/config/metrics/counts_all/20210216175632_groups_inheriting_asana_active.yml
+++ b/config/metrics/counts_all/20210216175632_groups_inheriting_asana_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_asana_active
description: Count of active groups inheriting integrations for Asana
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175634_projects_assembla_active.yml b/config/metrics/counts_all/20210216175634_projects_assembla_active.yml
index ad6ae1afc72..d5e61e86f48 100644
--- a/config/metrics/counts_all/20210216175634_projects_assembla_active.yml
+++ b/config/metrics/counts_all/20210216175634_projects_assembla_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_assembla_active
description: Count of projects with active integrations for Assembla
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175636_groups_assembla_active.yml b/config/metrics/counts_all/20210216175636_groups_assembla_active.yml
index a9a1ba26633..d3b8252b5bf 100644
--- a/config/metrics/counts_all/20210216175636_groups_assembla_active.yml
+++ b/config/metrics/counts_all/20210216175636_groups_assembla_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_assembla_active
description: Count of groups with active integrations for Assembla
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175638_templates_assembla_active.yml b/config/metrics/counts_all/20210216175638_templates_assembla_active.yml
index 88d0c631218..0faa5a7f435 100644
--- a/config/metrics/counts_all/20210216175638_templates_assembla_active.yml
+++ b/config/metrics/counts_all/20210216175638_templates_assembla_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_assembla_active
description: Count of active service templates for Assembla
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175640_instances_assembla_active.yml b/config/metrics/counts_all/20210216175640_instances_assembla_active.yml
index c76d508d58c..1fcf673aba2 100644
--- a/config/metrics/counts_all/20210216175640_instances_assembla_active.yml
+++ b/config/metrics/counts_all/20210216175640_instances_assembla_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_assembla_active
description: Count of active instance-level integrations for Assembla
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175642_projects_inheriting_assembla_active.yml b/config/metrics/counts_all/20210216175642_projects_inheriting_assembla_active.yml
index 72143e165cc..f1d8dd731dd 100644
--- a/config/metrics/counts_all/20210216175642_projects_inheriting_assembla_active.yml
+++ b/config/metrics/counts_all/20210216175642_projects_inheriting_assembla_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_assembla_active
description: Count of active projects inheriting integrations for Assembla
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175644_groups_inheriting_assembla_active.yml b/config/metrics/counts_all/20210216175644_groups_inheriting_assembla_active.yml
index d22ac41c550..ebbdba6c097 100644
--- a/config/metrics/counts_all/20210216175644_groups_inheriting_assembla_active.yml
+++ b/config/metrics/counts_all/20210216175644_groups_inheriting_assembla_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_assembla_active
description: Count of active groups inheriting integrations for Assembla
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175645_projects_bamboo_active.yml b/config/metrics/counts_all/20210216175645_projects_bamboo_active.yml
index 3ad3dfb25a9..7e1530aa6e6 100644
--- a/config/metrics/counts_all/20210216175645_projects_bamboo_active.yml
+++ b/config/metrics/counts_all/20210216175645_projects_bamboo_active.yml
@@ -3,7 +3,7 @@ data_category: operational
key_path: counts.projects_bamboo_active
description: Count of projects with active integrations for Bamboo CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175647_groups_bamboo_active.yml b/config/metrics/counts_all/20210216175647_groups_bamboo_active.yml
index e5543ca5766..cfc1d7d7f39 100644
--- a/config/metrics/counts_all/20210216175647_groups_bamboo_active.yml
+++ b/config/metrics/counts_all/20210216175647_groups_bamboo_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_bamboo_active
description: Count of groups with active integrations for Bamboo CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175649_templates_bamboo_active.yml b/config/metrics/counts_all/20210216175649_templates_bamboo_active.yml
index 96947738ac7..8965c65ed6f 100644
--- a/config/metrics/counts_all/20210216175649_templates_bamboo_active.yml
+++ b/config/metrics/counts_all/20210216175649_templates_bamboo_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_bamboo_active
description: Count of active service templates for Bamboo CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175651_instances_bamboo_active.yml b/config/metrics/counts_all/20210216175651_instances_bamboo_active.yml
index db0824288cd..b07649a858c 100644
--- a/config/metrics/counts_all/20210216175651_instances_bamboo_active.yml
+++ b/config/metrics/counts_all/20210216175651_instances_bamboo_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_bamboo_active
description: Count of active instance-level integrations for Bamboo CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175653_projects_inheriting_bamboo_active.yml b/config/metrics/counts_all/20210216175653_projects_inheriting_bamboo_active.yml
index 429540bdbd4..1fcd94588bf 100644
--- a/config/metrics/counts_all/20210216175653_projects_inheriting_bamboo_active.yml
+++ b/config/metrics/counts_all/20210216175653_projects_inheriting_bamboo_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_bamboo_active
description: Count of active projects inheriting integrations for Bamboo CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175655_groups_inheriting_bamboo_active.yml b/config/metrics/counts_all/20210216175655_groups_inheriting_bamboo_active.yml
index 19bc979b41e..b2216f34b48 100644
--- a/config/metrics/counts_all/20210216175655_groups_inheriting_bamboo_active.yml
+++ b/config/metrics/counts_all/20210216175655_groups_inheriting_bamboo_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_bamboo_active
description: Count of active groups inheriting integrations for Bamboo CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175657_projects_bugzilla_active.yml b/config/metrics/counts_all/20210216175657_projects_bugzilla_active.yml
index 39caf54919d..c6a0e9c4654 100644
--- a/config/metrics/counts_all/20210216175657_projects_bugzilla_active.yml
+++ b/config/metrics/counts_all/20210216175657_projects_bugzilla_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_bugzilla_active
description: Count of projects with active integrations for Bugzilla
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175659_groups_bugzilla_active.yml b/config/metrics/counts_all/20210216175659_groups_bugzilla_active.yml
index 2e3c1b5527f..1c4be08b4da 100644
--- a/config/metrics/counts_all/20210216175659_groups_bugzilla_active.yml
+++ b/config/metrics/counts_all/20210216175659_groups_bugzilla_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_bugzilla_active
description: Count of groups with active integrations for Bugzilla
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175701_templates_bugzilla_active.yml b/config/metrics/counts_all/20210216175701_templates_bugzilla_active.yml
index 12866071b53..41a36dfede4 100644
--- a/config/metrics/counts_all/20210216175701_templates_bugzilla_active.yml
+++ b/config/metrics/counts_all/20210216175701_templates_bugzilla_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_bugzilla_active
description: Count of active service templates for Bugzilla
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175702_instances_bugzilla_active.yml b/config/metrics/counts_all/20210216175702_instances_bugzilla_active.yml
index 55f5f38555a..bc9cc8c78c2 100644
--- a/config/metrics/counts_all/20210216175702_instances_bugzilla_active.yml
+++ b/config/metrics/counts_all/20210216175702_instances_bugzilla_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_bugzilla_active
description: Count of active instance-level integrations for Bugzilla
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175704_projects_inheriting_bugzilla_active.yml b/config/metrics/counts_all/20210216175704_projects_inheriting_bugzilla_active.yml
index be9231fcece..d034b007408 100644
--- a/config/metrics/counts_all/20210216175704_projects_inheriting_bugzilla_active.yml
+++ b/config/metrics/counts_all/20210216175704_projects_inheriting_bugzilla_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_bugzilla_active
description: Count of active projects inheriting integrations for Bugzilla
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175706_groups_inheriting_bugzilla_active.yml b/config/metrics/counts_all/20210216175706_groups_inheriting_bugzilla_active.yml
index 699b9019dfc..b9b92f72f02 100644
--- a/config/metrics/counts_all/20210216175706_groups_inheriting_bugzilla_active.yml
+++ b/config/metrics/counts_all/20210216175706_groups_inheriting_bugzilla_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_bugzilla_active
description: Count of active groups inheriting integrations for Bugzilla
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175708_projects_buildkite_active.yml b/config/metrics/counts_all/20210216175708_projects_buildkite_active.yml
index 741b7220458..0c359862309 100644
--- a/config/metrics/counts_all/20210216175708_projects_buildkite_active.yml
+++ b/config/metrics/counts_all/20210216175708_projects_buildkite_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_buildkite_active
description: Count of projects with active integrations for Buildkite
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175710_groups_buildkite_active.yml b/config/metrics/counts_all/20210216175710_groups_buildkite_active.yml
index 1b334022e44..363671ad07e 100644
--- a/config/metrics/counts_all/20210216175710_groups_buildkite_active.yml
+++ b/config/metrics/counts_all/20210216175710_groups_buildkite_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_buildkite_active
description: Count of groups with active integrations for Buildkite
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175712_templates_buildkite_active.yml b/config/metrics/counts_all/20210216175712_templates_buildkite_active.yml
index d5a46ed861c..14ffea5ffb4 100644
--- a/config/metrics/counts_all/20210216175712_templates_buildkite_active.yml
+++ b/config/metrics/counts_all/20210216175712_templates_buildkite_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_buildkite_active
description: Count of active service templates for Buildkite
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175714_instances_buildkite_active.yml b/config/metrics/counts_all/20210216175714_instances_buildkite_active.yml
index 8d99d2c1f05..39451d3ae53 100644
--- a/config/metrics/counts_all/20210216175714_instances_buildkite_active.yml
+++ b/config/metrics/counts_all/20210216175714_instances_buildkite_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_buildkite_active
description: Count of active instance-level integrations for Buildkite
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175716_projects_inheriting_buildkite_active.yml b/config/metrics/counts_all/20210216175716_projects_inheriting_buildkite_active.yml
index fd54ff78891..a789fc50df4 100644
--- a/config/metrics/counts_all/20210216175716_projects_inheriting_buildkite_active.yml
+++ b/config/metrics/counts_all/20210216175716_projects_inheriting_buildkite_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_buildkite_active
description: Count of active projects inheriting integrations for Buildkite
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175717_groups_inheriting_buildkite_active.yml b/config/metrics/counts_all/20210216175717_groups_inheriting_buildkite_active.yml
index 350f74c97b7..f846e126f3e 100644
--- a/config/metrics/counts_all/20210216175717_groups_inheriting_buildkite_active.yml
+++ b/config/metrics/counts_all/20210216175717_groups_inheriting_buildkite_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_buildkite_active
description: Count of active groups inheriting integrations for Buildkite
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175719_projects_campfire_active.yml b/config/metrics/counts_all/20210216175719_projects_campfire_active.yml
index 73d8a063f0b..816f153d252 100644
--- a/config/metrics/counts_all/20210216175719_projects_campfire_active.yml
+++ b/config/metrics/counts_all/20210216175719_projects_campfire_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_campfire_active
description: Count of projects with active integrations for Campfire
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175721_groups_campfire_active.yml b/config/metrics/counts_all/20210216175721_groups_campfire_active.yml
index c4879e4fd91..e87e0748062 100644
--- a/config/metrics/counts_all/20210216175721_groups_campfire_active.yml
+++ b/config/metrics/counts_all/20210216175721_groups_campfire_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_campfire_active
description: Count of groups with active integrations for Campfire
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175723_templates_campfire_active.yml b/config/metrics/counts_all/20210216175723_templates_campfire_active.yml
index b5b8b9905ca..00f32987f4e 100644
--- a/config/metrics/counts_all/20210216175723_templates_campfire_active.yml
+++ b/config/metrics/counts_all/20210216175723_templates_campfire_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_campfire_active
description: Count of active service templates for Campfire
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175725_instances_campfire_active.yml b/config/metrics/counts_all/20210216175725_instances_campfire_active.yml
index 88a013fff2f..a2c18935954 100644
--- a/config/metrics/counts_all/20210216175725_instances_campfire_active.yml
+++ b/config/metrics/counts_all/20210216175725_instances_campfire_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_campfire_active
description: Count of active instance-level integrations for Campfire
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175727_projects_inheriting_campfire_active.yml b/config/metrics/counts_all/20210216175727_projects_inheriting_campfire_active.yml
index 51150db3bdd..a09a7f7cb4e 100644
--- a/config/metrics/counts_all/20210216175727_projects_inheriting_campfire_active.yml
+++ b/config/metrics/counts_all/20210216175727_projects_inheriting_campfire_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_campfire_active
description: Count of active projects inheriting integrations for Campfire
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175729_groups_inheriting_campfire_active.yml b/config/metrics/counts_all/20210216175729_groups_inheriting_campfire_active.yml
index f081a57eff4..55780ebfef1 100644
--- a/config/metrics/counts_all/20210216175729_groups_inheriting_campfire_active.yml
+++ b/config/metrics/counts_all/20210216175729_groups_inheriting_campfire_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_campfire_active
description: Count of active groups inheriting integrations for Campfire
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175731_projects_confluence_active.yml b/config/metrics/counts_all/20210216175731_projects_confluence_active.yml
index c361af80c75..ec23eae4aad 100644
--- a/config/metrics/counts_all/20210216175731_projects_confluence_active.yml
+++ b/config/metrics/counts_all/20210216175731_projects_confluence_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_confluence_active
description: Count of projects with active integrations for Confluence
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175733_groups_confluence_active.yml b/config/metrics/counts_all/20210216175733_groups_confluence_active.yml
index 8a9d3e4aa2b..ae6caba5551 100644
--- a/config/metrics/counts_all/20210216175733_groups_confluence_active.yml
+++ b/config/metrics/counts_all/20210216175733_groups_confluence_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_confluence_active
description: Count of groups with active integrations for Confluence
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175734_templates_confluence_active.yml b/config/metrics/counts_all/20210216175734_templates_confluence_active.yml
index 5b09f81d9f7..720325f1ee9 100644
--- a/config/metrics/counts_all/20210216175734_templates_confluence_active.yml
+++ b/config/metrics/counts_all/20210216175734_templates_confluence_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_confluence_active
description: Count of active service templates for Confluence
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175736_instances_confluence_active.yml b/config/metrics/counts_all/20210216175736_instances_confluence_active.yml
index f8df0b86ffd..521f29949c1 100644
--- a/config/metrics/counts_all/20210216175736_instances_confluence_active.yml
+++ b/config/metrics/counts_all/20210216175736_instances_confluence_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_confluence_active
description: Count of active instance-level integrations for Confluence
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175738_projects_inheriting_confluence_active.yml b/config/metrics/counts_all/20210216175738_projects_inheriting_confluence_active.yml
index c59ba1dd8f8..1fc45db4903 100644
--- a/config/metrics/counts_all/20210216175738_projects_inheriting_confluence_active.yml
+++ b/config/metrics/counts_all/20210216175738_projects_inheriting_confluence_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_confluence_active
description: Count of active projects inheriting integrations for Confluence
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175740_groups_inheriting_confluence_active.yml b/config/metrics/counts_all/20210216175740_groups_inheriting_confluence_active.yml
index 2242a04f332..e9c0d456ab0 100644
--- a/config/metrics/counts_all/20210216175740_groups_inheriting_confluence_active.yml
+++ b/config/metrics/counts_all/20210216175740_groups_inheriting_confluence_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_confluence_active
description: Count of active groups inheriting integrations for Confluence
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175742_projects_custom_issue_tracker_active.yml b/config/metrics/counts_all/20210216175742_projects_custom_issue_tracker_active.yml
index a727e6fedb6..f3ee6b40bce 100644
--- a/config/metrics/counts_all/20210216175742_projects_custom_issue_tracker_active.yml
+++ b/config/metrics/counts_all/20210216175742_projects_custom_issue_tracker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_custom_issue_tracker_active
description: Count of projects with active integrations for a Custom Issue Tracker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175744_groups_custom_issue_tracker_active.yml b/config/metrics/counts_all/20210216175744_groups_custom_issue_tracker_active.yml
index 4c63579d92e..c9b11d6c5e9 100644
--- a/config/metrics/counts_all/20210216175744_groups_custom_issue_tracker_active.yml
+++ b/config/metrics/counts_all/20210216175744_groups_custom_issue_tracker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_custom_issue_tracker_active
description: Count of groups with active integrations for a Custom Issue Tracker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175745_templates_custom_issue_tracker_active.yml b/config/metrics/counts_all/20210216175745_templates_custom_issue_tracker_active.yml
index b1f0c7955ff..110f6cc9606 100644
--- a/config/metrics/counts_all/20210216175745_templates_custom_issue_tracker_active.yml
+++ b/config/metrics/counts_all/20210216175745_templates_custom_issue_tracker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_custom_issue_tracker_active
description: Count of active service templates for a Custom Issue Tracker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175747_instances_custom_issue_tracker_active.yml b/config/metrics/counts_all/20210216175747_instances_custom_issue_tracker_active.yml
index a87c20b1e8b..ae72b015264 100644
--- a/config/metrics/counts_all/20210216175747_instances_custom_issue_tracker_active.yml
+++ b/config/metrics/counts_all/20210216175747_instances_custom_issue_tracker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_custom_issue_tracker_active
description: Count of active instance-level integrations for a Custom Issue Tracker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175749_projects_inheriting_custom_issue_tracker_active.yml b/config/metrics/counts_all/20210216175749_projects_inheriting_custom_issue_tracker_active.yml
index 1ef220f5e4f..22b6fbfe846 100644
--- a/config/metrics/counts_all/20210216175749_projects_inheriting_custom_issue_tracker_active.yml
+++ b/config/metrics/counts_all/20210216175749_projects_inheriting_custom_issue_tracker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_custom_issue_tracker_active
description: Count of active projects inheriting integrations for a Custom Issue Tracker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175751_groups_inheriting_custom_issue_tracker_active.yml b/config/metrics/counts_all/20210216175751_groups_inheriting_custom_issue_tracker_active.yml
index 0ff7a037288..a047b76b5cb 100644
--- a/config/metrics/counts_all/20210216175751_groups_inheriting_custom_issue_tracker_active.yml
+++ b/config/metrics/counts_all/20210216175751_groups_inheriting_custom_issue_tracker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_custom_issue_tracker_active
description: Count of active groups inheriting integrations for a Custom Issue Tracker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175753_projects_discord_active.yml b/config/metrics/counts_all/20210216175753_projects_discord_active.yml
index 9b4eecbd372..a228c98c52f 100644
--- a/config/metrics/counts_all/20210216175753_projects_discord_active.yml
+++ b/config/metrics/counts_all/20210216175753_projects_discord_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_discord_active
description: Count of projects with active integrations for Discord
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175755_groups_discord_active.yml b/config/metrics/counts_all/20210216175755_groups_discord_active.yml
index 7ac463d87e3..86ffb00edc4 100644
--- a/config/metrics/counts_all/20210216175755_groups_discord_active.yml
+++ b/config/metrics/counts_all/20210216175755_groups_discord_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_discord_active
description: Count of groups with active integrations for Discord
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175756_templates_discord_active.yml b/config/metrics/counts_all/20210216175756_templates_discord_active.yml
index 4b913f35acd..47d111dc895 100644
--- a/config/metrics/counts_all/20210216175756_templates_discord_active.yml
+++ b/config/metrics/counts_all/20210216175756_templates_discord_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_discord_active
description: Count of active service templates for Discord
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175758_instances_discord_active.yml b/config/metrics/counts_all/20210216175758_instances_discord_active.yml
index 5d790f5d6df..d508e171a7a 100644
--- a/config/metrics/counts_all/20210216175758_instances_discord_active.yml
+++ b/config/metrics/counts_all/20210216175758_instances_discord_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_discord_active
description: Count of active instance-level integrations for Discord
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175800_projects_inheriting_discord_active.yml b/config/metrics/counts_all/20210216175800_projects_inheriting_discord_active.yml
index 85634cb58b2..478151f1889 100644
--- a/config/metrics/counts_all/20210216175800_projects_inheriting_discord_active.yml
+++ b/config/metrics/counts_all/20210216175800_projects_inheriting_discord_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_discord_active
description: Count of active projects inheriting integrations for Discord
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175802_groups_inheriting_discord_active.yml b/config/metrics/counts_all/20210216175802_groups_inheriting_discord_active.yml
index 74f1c4a32f5..1016a71b1c8 100644
--- a/config/metrics/counts_all/20210216175802_groups_inheriting_discord_active.yml
+++ b/config/metrics/counts_all/20210216175802_groups_inheriting_discord_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_discord_active
description: Count of active groups inheriting integrations for Discord
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175804_projects_drone_ci_active.yml b/config/metrics/counts_all/20210216175804_projects_drone_ci_active.yml
index 005d9f65a33..e8511564bdd 100644
--- a/config/metrics/counts_all/20210216175804_projects_drone_ci_active.yml
+++ b/config/metrics/counts_all/20210216175804_projects_drone_ci_active.yml
@@ -3,7 +3,7 @@ data_category: operational
key_path: counts.projects_drone_ci_active
description: Count of projects with active integrations for Drone CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175806_groups_drone_ci_active.yml b/config/metrics/counts_all/20210216175806_groups_drone_ci_active.yml
index 23b4fab18b3..3a5ce0f3882 100644
--- a/config/metrics/counts_all/20210216175806_groups_drone_ci_active.yml
+++ b/config/metrics/counts_all/20210216175806_groups_drone_ci_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_drone_ci_active
description: Count of groups with active integrations for Drone CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175807_templates_drone_ci_active.yml b/config/metrics/counts_all/20210216175807_templates_drone_ci_active.yml
index e3422fb6193..80e017c5a2c 100644
--- a/config/metrics/counts_all/20210216175807_templates_drone_ci_active.yml
+++ b/config/metrics/counts_all/20210216175807_templates_drone_ci_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_drone_ci_active
description: Count of active service templates for Drone CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175809_instances_drone_ci_active.yml b/config/metrics/counts_all/20210216175809_instances_drone_ci_active.yml
index a47163d7540..b071268f48c 100644
--- a/config/metrics/counts_all/20210216175809_instances_drone_ci_active.yml
+++ b/config/metrics/counts_all/20210216175809_instances_drone_ci_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_drone_ci_active
description: Count of active instance-level integrations for Drone CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175811_projects_inheriting_drone_ci_active.yml b/config/metrics/counts_all/20210216175811_projects_inheriting_drone_ci_active.yml
index ee862f15d30..b9fafd7d3c8 100644
--- a/config/metrics/counts_all/20210216175811_projects_inheriting_drone_ci_active.yml
+++ b/config/metrics/counts_all/20210216175811_projects_inheriting_drone_ci_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_drone_ci_active
description: Count of active projects inheriting integrations for Drone CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175813_groups_inheriting_drone_ci_active.yml b/config/metrics/counts_all/20210216175813_groups_inheriting_drone_ci_active.yml
index aafc802b87c..60b5c5bf7c8 100644
--- a/config/metrics/counts_all/20210216175813_groups_inheriting_drone_ci_active.yml
+++ b/config/metrics/counts_all/20210216175813_groups_inheriting_drone_ci_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_drone_ci_active
description: Count of active groups inheriting integrations for Drone CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175815_projects_emails_on_push_active.yml b/config/metrics/counts_all/20210216175815_projects_emails_on_push_active.yml
index 1ba9979c98a..47f094738d0 100644
--- a/config/metrics/counts_all/20210216175815_projects_emails_on_push_active.yml
+++ b/config/metrics/counts_all/20210216175815_projects_emails_on_push_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_emails_on_push_active
description: Count of projects with active integrations for Emails on Push
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175817_groups_emails_on_push_active.yml b/config/metrics/counts_all/20210216175817_groups_emails_on_push_active.yml
index 6049a9126a7..7c67463eba3 100644
--- a/config/metrics/counts_all/20210216175817_groups_emails_on_push_active.yml
+++ b/config/metrics/counts_all/20210216175817_groups_emails_on_push_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_emails_on_push_active
description: Count of groups with active integrations for Emails on Push
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175818_templates_emails_on_push_active.yml b/config/metrics/counts_all/20210216175818_templates_emails_on_push_active.yml
index 33e588ce60e..387874eb108 100644
--- a/config/metrics/counts_all/20210216175818_templates_emails_on_push_active.yml
+++ b/config/metrics/counts_all/20210216175818_templates_emails_on_push_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_emails_on_push_active
description: Count of active service templates for Emails on Push
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175820_instances_emails_on_push_active.yml b/config/metrics/counts_all/20210216175820_instances_emails_on_push_active.yml
index 40ab3459baf..a1588510b2b 100644
--- a/config/metrics/counts_all/20210216175820_instances_emails_on_push_active.yml
+++ b/config/metrics/counts_all/20210216175820_instances_emails_on_push_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_emails_on_push_active
description: Count of active instance-level integrations for Emails on Push
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175822_projects_inheriting_emails_on_push_active.yml b/config/metrics/counts_all/20210216175822_projects_inheriting_emails_on_push_active.yml
index 5df16d4bcaf..892249b795d 100644
--- a/config/metrics/counts_all/20210216175822_projects_inheriting_emails_on_push_active.yml
+++ b/config/metrics/counts_all/20210216175822_projects_inheriting_emails_on_push_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_emails_on_push_active
description: Count of active projects inheriting integrations for Emails on Push
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175824_groups_inheriting_emails_on_push_active.yml b/config/metrics/counts_all/20210216175824_groups_inheriting_emails_on_push_active.yml
index c478fc02745..a02c183202d 100644
--- a/config/metrics/counts_all/20210216175824_groups_inheriting_emails_on_push_active.yml
+++ b/config/metrics/counts_all/20210216175824_groups_inheriting_emails_on_push_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_emails_on_push_active
description: Count of active groups inheriting integrations for Emails on Push
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175826_projects_external_wiki_active.yml b/config/metrics/counts_all/20210216175826_projects_external_wiki_active.yml
index fc99b7a20cc..f2d71a1a775 100644
--- a/config/metrics/counts_all/20210216175826_projects_external_wiki_active.yml
+++ b/config/metrics/counts_all/20210216175826_projects_external_wiki_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_external_wiki_active
description: Count of projects with active integrations for External Wiki
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175828_groups_external_wiki_active.yml b/config/metrics/counts_all/20210216175828_groups_external_wiki_active.yml
index d154a4ec723..e7cb654e8e5 100644
--- a/config/metrics/counts_all/20210216175828_groups_external_wiki_active.yml
+++ b/config/metrics/counts_all/20210216175828_groups_external_wiki_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_external_wiki_active
description: Count of groups with active integrations for External Wiki
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175829_templates_external_wiki_active.yml b/config/metrics/counts_all/20210216175829_templates_external_wiki_active.yml
index 522315e40f6..b80bb0e6902 100644
--- a/config/metrics/counts_all/20210216175829_templates_external_wiki_active.yml
+++ b/config/metrics/counts_all/20210216175829_templates_external_wiki_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_external_wiki_active
description: Count of active service templates for External Wiki
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175831_instances_external_wiki_active.yml b/config/metrics/counts_all/20210216175831_instances_external_wiki_active.yml
index 9d5e41f4302..fbc863ee474 100644
--- a/config/metrics/counts_all/20210216175831_instances_external_wiki_active.yml
+++ b/config/metrics/counts_all/20210216175831_instances_external_wiki_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_external_wiki_active
description: Count of active instance-level integrations for External Wiki
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175833_projects_inheriting_external_wiki_active.yml b/config/metrics/counts_all/20210216175833_projects_inheriting_external_wiki_active.yml
index 166d7f1734b..f27b94f9b54 100644
--- a/config/metrics/counts_all/20210216175833_projects_inheriting_external_wiki_active.yml
+++ b/config/metrics/counts_all/20210216175833_projects_inheriting_external_wiki_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_external_wiki_active
description: Count of active projects inheriting integrations for External Wiki
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175835_groups_inheriting_external_wiki_active.yml b/config/metrics/counts_all/20210216175835_groups_inheriting_external_wiki_active.yml
index c233df8e8ff..7f6ca0a013b 100644
--- a/config/metrics/counts_all/20210216175835_groups_inheriting_external_wiki_active.yml
+++ b/config/metrics/counts_all/20210216175835_groups_inheriting_external_wiki_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_external_wiki_active
description: Count of active groups inheriting integrations for External Wiki
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175837_projects_flowdock_active.yml b/config/metrics/counts_all/20210216175837_projects_flowdock_active.yml
index 0ca23369618..46db9f97e85 100644
--- a/config/metrics/counts_all/20210216175837_projects_flowdock_active.yml
+++ b/config/metrics/counts_all/20210216175837_projects_flowdock_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_flowdock_active
description: Count of projects with active integrations for Flowdock
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175839_groups_flowdock_active.yml b/config/metrics/counts_all/20210216175839_groups_flowdock_active.yml
index 878a6b1615a..d5da36978b6 100644
--- a/config/metrics/counts_all/20210216175839_groups_flowdock_active.yml
+++ b/config/metrics/counts_all/20210216175839_groups_flowdock_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_flowdock_active
description: Count of groups with active integrations for Flowdock
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175840_templates_flowdock_active.yml b/config/metrics/counts_all/20210216175840_templates_flowdock_active.yml
index 19bd891b300..d3ed9f36425 100644
--- a/config/metrics/counts_all/20210216175840_templates_flowdock_active.yml
+++ b/config/metrics/counts_all/20210216175840_templates_flowdock_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_flowdock_active
description: Count of active service templates for Flowdock
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175842_instances_flowdock_active.yml b/config/metrics/counts_all/20210216175842_instances_flowdock_active.yml
index 2b58b35d466..198af43a99d 100644
--- a/config/metrics/counts_all/20210216175842_instances_flowdock_active.yml
+++ b/config/metrics/counts_all/20210216175842_instances_flowdock_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_flowdock_active
description: Count of active instance-level integrations for Flowdock
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175844_projects_inheriting_flowdock_active.yml b/config/metrics/counts_all/20210216175844_projects_inheriting_flowdock_active.yml
index 88425a3aaff..f094f894ded 100644
--- a/config/metrics/counts_all/20210216175844_projects_inheriting_flowdock_active.yml
+++ b/config/metrics/counts_all/20210216175844_projects_inheriting_flowdock_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_flowdock_active
description: Count of active projects inheriting integrations for Flowdock
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175846_groups_inheriting_flowdock_active.yml b/config/metrics/counts_all/20210216175846_groups_inheriting_flowdock_active.yml
index 8c8150ec316..fb7931ddf09 100644
--- a/config/metrics/counts_all/20210216175846_groups_inheriting_flowdock_active.yml
+++ b/config/metrics/counts_all/20210216175846_groups_inheriting_flowdock_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_flowdock_active
description: Count of active groups inheriting integrations for Flowdock
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175859_projects_hangouts_chat_active.yml b/config/metrics/counts_all/20210216175859_projects_hangouts_chat_active.yml
index bdb36ce40a4..14865b2dffc 100644
--- a/config/metrics/counts_all/20210216175859_projects_hangouts_chat_active.yml
+++ b/config/metrics/counts_all/20210216175859_projects_hangouts_chat_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_hangouts_chat_active
description: Count of projects with active integrations for Hangouts Chat
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175901_groups_hangouts_chat_active.yml b/config/metrics/counts_all/20210216175901_groups_hangouts_chat_active.yml
index ce776453c04..0dcb3881909 100644
--- a/config/metrics/counts_all/20210216175901_groups_hangouts_chat_active.yml
+++ b/config/metrics/counts_all/20210216175901_groups_hangouts_chat_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_hangouts_chat_active
description: Count of groups with active integrations for Hangouts Chat
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175902_templates_hangouts_chat_active.yml b/config/metrics/counts_all/20210216175902_templates_hangouts_chat_active.yml
index c41f72918d9..0d60c70c6e2 100644
--- a/config/metrics/counts_all/20210216175902_templates_hangouts_chat_active.yml
+++ b/config/metrics/counts_all/20210216175902_templates_hangouts_chat_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_hangouts_chat_active
description: Count of active service templates for Hangouts Chat
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175904_instances_hangouts_chat_active.yml b/config/metrics/counts_all/20210216175904_instances_hangouts_chat_active.yml
index 023893954f3..4208f647cf3 100644
--- a/config/metrics/counts_all/20210216175904_instances_hangouts_chat_active.yml
+++ b/config/metrics/counts_all/20210216175904_instances_hangouts_chat_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_hangouts_chat_active
description: Count of active instance-level integrations for Hangouts Chat
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175906_projects_inheriting_hangouts_chat_active.yml b/config/metrics/counts_all/20210216175906_projects_inheriting_hangouts_chat_active.yml
index 2a706665d8f..7168c788670 100644
--- a/config/metrics/counts_all/20210216175906_projects_inheriting_hangouts_chat_active.yml
+++ b/config/metrics/counts_all/20210216175906_projects_inheriting_hangouts_chat_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_hangouts_chat_active
description: Count of active projects inheriting integrations for Hangouts Chat
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175908_groups_inheriting_hangouts_chat_active.yml b/config/metrics/counts_all/20210216175908_groups_inheriting_hangouts_chat_active.yml
index 8586fb00ab4..45465412b80 100644
--- a/config/metrics/counts_all/20210216175908_groups_inheriting_hangouts_chat_active.yml
+++ b/config/metrics/counts_all/20210216175908_groups_inheriting_hangouts_chat_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_hangouts_chat_active
description: Count of active groups inheriting integrations for Hangouts Chat
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175910_projects_hipchat_active.yml b/config/metrics/counts_all/20210216175910_projects_hipchat_active.yml
index 779f0579f49..915c634cdb3 100644
--- a/config/metrics/counts_all/20210216175910_projects_hipchat_active.yml
+++ b/config/metrics/counts_all/20210216175910_projects_hipchat_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_hipchat_active
description: Count of projects with active integrations for HipChat
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175912_groups_hipchat_active.yml b/config/metrics/counts_all/20210216175912_groups_hipchat_active.yml
index 16419a7005b..5391dda3b7c 100644
--- a/config/metrics/counts_all/20210216175912_groups_hipchat_active.yml
+++ b/config/metrics/counts_all/20210216175912_groups_hipchat_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_hipchat_active
description: Count of groups with active integrations for HipChat
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175913_templates_hipchat_active.yml b/config/metrics/counts_all/20210216175913_templates_hipchat_active.yml
index 65516f0a17b..7bcb8206beb 100644
--- a/config/metrics/counts_all/20210216175913_templates_hipchat_active.yml
+++ b/config/metrics/counts_all/20210216175913_templates_hipchat_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_hipchat_active
description: Count of active service templates for HipChat
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175915_instances_hipchat_active.yml b/config/metrics/counts_all/20210216175915_instances_hipchat_active.yml
index 0c7c6c5ee99..f30e667b316 100644
--- a/config/metrics/counts_all/20210216175915_instances_hipchat_active.yml
+++ b/config/metrics/counts_all/20210216175915_instances_hipchat_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_hipchat_active
description: Count of active instance-level integrations for HipChat
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175917_projects_inheriting_hipchat_active.yml b/config/metrics/counts_all/20210216175917_projects_inheriting_hipchat_active.yml
index febbbf234aa..aef3e97590f 100644
--- a/config/metrics/counts_all/20210216175917_projects_inheriting_hipchat_active.yml
+++ b/config/metrics/counts_all/20210216175917_projects_inheriting_hipchat_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_hipchat_active
description: Count of active projects inheriting integrations for HipChat
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175919_groups_inheriting_hipchat_active.yml b/config/metrics/counts_all/20210216175919_groups_inheriting_hipchat_active.yml
index df5bc192dfd..ff4e3d9d0b3 100644
--- a/config/metrics/counts_all/20210216175919_groups_inheriting_hipchat_active.yml
+++ b/config/metrics/counts_all/20210216175919_groups_inheriting_hipchat_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_hipchat_active
description: Count of active groups inheriting integrations for HipChat
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175921_projects_irker_active.yml b/config/metrics/counts_all/20210216175921_projects_irker_active.yml
index c23511b99b0..0a01091482f 100644
--- a/config/metrics/counts_all/20210216175921_projects_irker_active.yml
+++ b/config/metrics/counts_all/20210216175921_projects_irker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_irker_active
description: Count of projects with active integrations for Irker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175923_groups_irker_active.yml b/config/metrics/counts_all/20210216175923_groups_irker_active.yml
index efb8317fd4a..12faf9b8871 100644
--- a/config/metrics/counts_all/20210216175923_groups_irker_active.yml
+++ b/config/metrics/counts_all/20210216175923_groups_irker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_irker_active
description: Count of groups with active integrations for Irker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175924_templates_irker_active.yml b/config/metrics/counts_all/20210216175924_templates_irker_active.yml
index 6075daa321b..1717439aad6 100644
--- a/config/metrics/counts_all/20210216175924_templates_irker_active.yml
+++ b/config/metrics/counts_all/20210216175924_templates_irker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_irker_active
description: Count of active service templates for Irker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175926_instances_irker_active.yml b/config/metrics/counts_all/20210216175926_instances_irker_active.yml
index e2821326503..edb31b01c5e 100644
--- a/config/metrics/counts_all/20210216175926_instances_irker_active.yml
+++ b/config/metrics/counts_all/20210216175926_instances_irker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_irker_active
description: Count of active instance-level integrations for Irker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175928_projects_inheriting_irker_active.yml b/config/metrics/counts_all/20210216175928_projects_inheriting_irker_active.yml
index bce07c5c584..5aab65d8491 100644
--- a/config/metrics/counts_all/20210216175928_projects_inheriting_irker_active.yml
+++ b/config/metrics/counts_all/20210216175928_projects_inheriting_irker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_irker_active
description: Count of active projects inheriting integrations for Irker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175930_groups_inheriting_irker_active.yml b/config/metrics/counts_all/20210216175930_groups_inheriting_irker_active.yml
index c99e8ed3d01..d724dccbd82 100644
--- a/config/metrics/counts_all/20210216175930_groups_inheriting_irker_active.yml
+++ b/config/metrics/counts_all/20210216175930_groups_inheriting_irker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_irker_active
description: Count of active groups inheriting integrations for Irker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175932_projects_jenkins_active.yml b/config/metrics/counts_all/20210216175932_projects_jenkins_active.yml
index 7e71a319c67..85eb568a586 100644
--- a/config/metrics/counts_all/20210216175932_projects_jenkins_active.yml
+++ b/config/metrics/counts_all/20210216175932_projects_jenkins_active.yml
@@ -3,7 +3,7 @@ data_category: operational
key_path: counts.projects_jenkins_active
description: Count of projects with active integrations for Jenkins
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175934_groups_jenkins_active.yml b/config/metrics/counts_all/20210216175934_groups_jenkins_active.yml
index 5db9b4b46a9..336eea6884a 100644
--- a/config/metrics/counts_all/20210216175934_groups_jenkins_active.yml
+++ b/config/metrics/counts_all/20210216175934_groups_jenkins_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_jenkins_active
description: Count of groups with active integrations for Jenkins
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175935_templates_jenkins_active.yml b/config/metrics/counts_all/20210216175935_templates_jenkins_active.yml
index 0205e0497bf..3475c1d4046 100644
--- a/config/metrics/counts_all/20210216175935_templates_jenkins_active.yml
+++ b/config/metrics/counts_all/20210216175935_templates_jenkins_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_jenkins_active
description: Count of active service templates for Jenkins
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175937_instances_jenkins_active.yml b/config/metrics/counts_all/20210216175937_instances_jenkins_active.yml
index 4135f36bd0a..a587373aa24 100644
--- a/config/metrics/counts_all/20210216175937_instances_jenkins_active.yml
+++ b/config/metrics/counts_all/20210216175937_instances_jenkins_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_jenkins_active
description: Count of active instance-level integrations for Jenkins
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175939_projects_inheriting_jenkins_active.yml b/config/metrics/counts_all/20210216175939_projects_inheriting_jenkins_active.yml
index 82f93fa3bcd..8670bf8ccc2 100644
--- a/config/metrics/counts_all/20210216175939_projects_inheriting_jenkins_active.yml
+++ b/config/metrics/counts_all/20210216175939_projects_inheriting_jenkins_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_jenkins_active
description: Count of active projects inheriting integrations for Jenkins
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175941_groups_inheriting_jenkins_active.yml b/config/metrics/counts_all/20210216175941_groups_inheriting_jenkins_active.yml
index 7b01ab9e25a..1cb7931cf48 100644
--- a/config/metrics/counts_all/20210216175941_groups_inheriting_jenkins_active.yml
+++ b/config/metrics/counts_all/20210216175941_groups_inheriting_jenkins_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_jenkins_active
description: Count of active groups inheriting integrations for Jenkins
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175943_projects_jira_active.yml b/config/metrics/counts_all/20210216175943_projects_jira_active.yml
index ac627472066..adfaacfae0a 100644
--- a/config/metrics/counts_all/20210216175943_projects_jira_active.yml
+++ b/config/metrics/counts_all/20210216175943_projects_jira_active.yml
@@ -3,7 +3,7 @@ data_category: operational
key_path: counts.projects_jira_active
description: Count of projects with active integrations for Jira
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175945_groups_jira_active.yml b/config/metrics/counts_all/20210216175945_groups_jira_active.yml
index d99920be62a..3464df2ef60 100644
--- a/config/metrics/counts_all/20210216175945_groups_jira_active.yml
+++ b/config/metrics/counts_all/20210216175945_groups_jira_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_jira_active
description: Count of groups with active integrations for Jira
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175946_templates_jira_active.yml b/config/metrics/counts_all/20210216175946_templates_jira_active.yml
index 63c1929b00e..a77057f5a53 100644
--- a/config/metrics/counts_all/20210216175946_templates_jira_active.yml
+++ b/config/metrics/counts_all/20210216175946_templates_jira_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_jira_active
description: Count of active service templates for Jira
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175948_instances_jira_active.yml b/config/metrics/counts_all/20210216175948_instances_jira_active.yml
index 98d1d27bed7..444f1c79ca9 100644
--- a/config/metrics/counts_all/20210216175948_instances_jira_active.yml
+++ b/config/metrics/counts_all/20210216175948_instances_jira_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_jira_active
description: Count of active instance-level integrations for Jira
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175950_projects_inheriting_jira_active.yml b/config/metrics/counts_all/20210216175950_projects_inheriting_jira_active.yml
index af8e8414beb..4a0097e21ba 100644
--- a/config/metrics/counts_all/20210216175950_projects_inheriting_jira_active.yml
+++ b/config/metrics/counts_all/20210216175950_projects_inheriting_jira_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_jira_active
description: Count of active projects inheriting integrations for Jira
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175952_groups_inheriting_jira_active.yml b/config/metrics/counts_all/20210216175952_groups_inheriting_jira_active.yml
index 3e9531cba26..6ff87cde23f 100644
--- a/config/metrics/counts_all/20210216175952_groups_inheriting_jira_active.yml
+++ b/config/metrics/counts_all/20210216175952_groups_inheriting_jira_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_jira_active
description: Count of active groups inheriting integrations for Jira
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175954_projects_mattermost_active.yml b/config/metrics/counts_all/20210216175954_projects_mattermost_active.yml
index b02c9e4919f..4d351b42abb 100644
--- a/config/metrics/counts_all/20210216175954_projects_mattermost_active.yml
+++ b/config/metrics/counts_all/20210216175954_projects_mattermost_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_mattermost_active
description: Count of projects with active integrations for Mattermost
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175956_groups_mattermost_active.yml b/config/metrics/counts_all/20210216175956_groups_mattermost_active.yml
index cdf2962548c..8036eff1e67 100644
--- a/config/metrics/counts_all/20210216175956_groups_mattermost_active.yml
+++ b/config/metrics/counts_all/20210216175956_groups_mattermost_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_mattermost_active
description: Count of groups with active integrations for Mattermost
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175957_templates_mattermost_active.yml b/config/metrics/counts_all/20210216175957_templates_mattermost_active.yml
index ced52649fd3..c4cc0f0d9c7 100644
--- a/config/metrics/counts_all/20210216175957_templates_mattermost_active.yml
+++ b/config/metrics/counts_all/20210216175957_templates_mattermost_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_mattermost_active
description: Count of active service templates for Mattermost
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216175959_instances_mattermost_active.yml b/config/metrics/counts_all/20210216175959_instances_mattermost_active.yml
index 519039cb6c2..cdde4ac4027 100644
--- a/config/metrics/counts_all/20210216175959_instances_mattermost_active.yml
+++ b/config/metrics/counts_all/20210216175959_instances_mattermost_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_mattermost_active
description: Count of active instance-level integrations for Mattermost
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180001_projects_inheriting_mattermost_active.yml b/config/metrics/counts_all/20210216180001_projects_inheriting_mattermost_active.yml
index 40a9e3f3eac..240a59a8b1e 100644
--- a/config/metrics/counts_all/20210216180001_projects_inheriting_mattermost_active.yml
+++ b/config/metrics/counts_all/20210216180001_projects_inheriting_mattermost_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_mattermost_active
description: Count of active projects inheriting integrations for Mattermost
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180003_groups_inheriting_mattermost_active.yml b/config/metrics/counts_all/20210216180003_groups_inheriting_mattermost_active.yml
index eea105726c1..f7bb7cb1a3e 100644
--- a/config/metrics/counts_all/20210216180003_groups_inheriting_mattermost_active.yml
+++ b/config/metrics/counts_all/20210216180003_groups_inheriting_mattermost_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_mattermost_active
description: Count of active groups inheriting integrations for Mattermost
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180005_projects_mattermost_slash_commands_active.yml b/config/metrics/counts_all/20210216180005_projects_mattermost_slash_commands_active.yml
index 36cdffa264b..d2a787ffa32 100644
--- a/config/metrics/counts_all/20210216180005_projects_mattermost_slash_commands_active.yml
+++ b/config/metrics/counts_all/20210216180005_projects_mattermost_slash_commands_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_mattermost_slash_commands_active
description: Count of projects with active integrations for Mattermost (slash commands)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180006_groups_mattermost_slash_commands_active.yml b/config/metrics/counts_all/20210216180006_groups_mattermost_slash_commands_active.yml
index 5356bbad505..6b8c43319c6 100644
--- a/config/metrics/counts_all/20210216180006_groups_mattermost_slash_commands_active.yml
+++ b/config/metrics/counts_all/20210216180006_groups_mattermost_slash_commands_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_mattermost_slash_commands_active
description: Count of groups with active integrations for Mattermost (slash commands)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180008_templates_mattermost_slash_commands_active.yml b/config/metrics/counts_all/20210216180008_templates_mattermost_slash_commands_active.yml
index 9851fc82dcd..a9703666f63 100644
--- a/config/metrics/counts_all/20210216180008_templates_mattermost_slash_commands_active.yml
+++ b/config/metrics/counts_all/20210216180008_templates_mattermost_slash_commands_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_mattermost_slash_commands_active
description: Count of active service templates for Mattermost (slash commands)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180010_instances_mattermost_slash_commands_active.yml b/config/metrics/counts_all/20210216180010_instances_mattermost_slash_commands_active.yml
index 08026f0a267..0e498eaf251 100644
--- a/config/metrics/counts_all/20210216180010_instances_mattermost_slash_commands_active.yml
+++ b/config/metrics/counts_all/20210216180010_instances_mattermost_slash_commands_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_mattermost_slash_commands_active
description: Count of active instance-level integrations for Mattermost (slash commands)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180012_projects_inheriting_mattermost_slash_commands_active.yml b/config/metrics/counts_all/20210216180012_projects_inheriting_mattermost_slash_commands_active.yml
index 08ea0768dcd..5f498994eb6 100644
--- a/config/metrics/counts_all/20210216180012_projects_inheriting_mattermost_slash_commands_active.yml
+++ b/config/metrics/counts_all/20210216180012_projects_inheriting_mattermost_slash_commands_active.yml
@@ -4,7 +4,7 @@ key_path: counts.projects_inheriting_mattermost_slash_commands_active
description: Count of active projects inheriting integrations for Mattermost (slash
commands)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180014_groups_inheriting_mattermost_slash_commands_active.yml b/config/metrics/counts_all/20210216180014_groups_inheriting_mattermost_slash_commands_active.yml
index 0458c912d4f..804100472b8 100644
--- a/config/metrics/counts_all/20210216180014_groups_inheriting_mattermost_slash_commands_active.yml
+++ b/config/metrics/counts_all/20210216180014_groups_inheriting_mattermost_slash_commands_active.yml
@@ -4,7 +4,7 @@ key_path: counts.groups_inheriting_mattermost_slash_commands_active
description: Count of active groups inheriting integrations for Mattermost (slash
commands)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180016_projects_microsoft_teams_active.yml b/config/metrics/counts_all/20210216180016_projects_microsoft_teams_active.yml
index 60dece28890..6b517b8ea65 100644
--- a/config/metrics/counts_all/20210216180016_projects_microsoft_teams_active.yml
+++ b/config/metrics/counts_all/20210216180016_projects_microsoft_teams_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_microsoft_teams_active
description: Count of projects with active integrations for Microsoft Teams
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180018_groups_microsoft_teams_active.yml b/config/metrics/counts_all/20210216180018_groups_microsoft_teams_active.yml
index b6ff5d7e4a3..75bc1c38b85 100644
--- a/config/metrics/counts_all/20210216180018_groups_microsoft_teams_active.yml
+++ b/config/metrics/counts_all/20210216180018_groups_microsoft_teams_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_microsoft_teams_active
description: Count of groups with active integrations for Microsoft Teams
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180019_templates_microsoft_teams_active.yml b/config/metrics/counts_all/20210216180019_templates_microsoft_teams_active.yml
index f3b96753b7b..0bd44801ce0 100644
--- a/config/metrics/counts_all/20210216180019_templates_microsoft_teams_active.yml
+++ b/config/metrics/counts_all/20210216180019_templates_microsoft_teams_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_microsoft_teams_active
description: Count of active service templates for Microsoft Teams
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180021_instances_microsoft_teams_active.yml b/config/metrics/counts_all/20210216180021_instances_microsoft_teams_active.yml
index 04c89b9544c..e5fbd0dd3b6 100644
--- a/config/metrics/counts_all/20210216180021_instances_microsoft_teams_active.yml
+++ b/config/metrics/counts_all/20210216180021_instances_microsoft_teams_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_microsoft_teams_active
description: Count of active instance-level integrations for Microsoft Teams
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180023_projects_inheriting_microsoft_teams_active.yml b/config/metrics/counts_all/20210216180023_projects_inheriting_microsoft_teams_active.yml
index 0a9c6e8f2d5..de36020f9e5 100644
--- a/config/metrics/counts_all/20210216180023_projects_inheriting_microsoft_teams_active.yml
+++ b/config/metrics/counts_all/20210216180023_projects_inheriting_microsoft_teams_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_microsoft_teams_active
description: Count of active projects inheriting integrations for Microsoft Teams
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180025_groups_inheriting_microsoft_teams_active.yml b/config/metrics/counts_all/20210216180025_groups_inheriting_microsoft_teams_active.yml
index 430438fa682..0f17bfc7fb4 100644
--- a/config/metrics/counts_all/20210216180025_groups_inheriting_microsoft_teams_active.yml
+++ b/config/metrics/counts_all/20210216180025_groups_inheriting_microsoft_teams_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_microsoft_teams_active
description: Count of active groups inheriting integrations for Microsoft Teams
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180027_projects_packagist_active.yml b/config/metrics/counts_all/20210216180027_projects_packagist_active.yml
index 2d6da6dd87c..f598ea26661 100644
--- a/config/metrics/counts_all/20210216180027_projects_packagist_active.yml
+++ b/config/metrics/counts_all/20210216180027_projects_packagist_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_packagist_active
description: Count of projects with active integrations for Packagist
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180029_groups_packagist_active.yml b/config/metrics/counts_all/20210216180029_groups_packagist_active.yml
index 72d22778e35..25feaa36b23 100644
--- a/config/metrics/counts_all/20210216180029_groups_packagist_active.yml
+++ b/config/metrics/counts_all/20210216180029_groups_packagist_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_packagist_active
description: Count of groups with active integrations for Packagist
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180030_templates_packagist_active.yml b/config/metrics/counts_all/20210216180030_templates_packagist_active.yml
index 83e0d46c6b8..61d0d5e1341 100644
--- a/config/metrics/counts_all/20210216180030_templates_packagist_active.yml
+++ b/config/metrics/counts_all/20210216180030_templates_packagist_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_packagist_active
description: Count of active service templates for Packagist
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180032_instances_packagist_active.yml b/config/metrics/counts_all/20210216180032_instances_packagist_active.yml
index f79210d6870..7cf1c495a94 100644
--- a/config/metrics/counts_all/20210216180032_instances_packagist_active.yml
+++ b/config/metrics/counts_all/20210216180032_instances_packagist_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_packagist_active
description: Count of active instance-level integrations for Packagist
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180034_projects_inheriting_packagist_active.yml b/config/metrics/counts_all/20210216180034_projects_inheriting_packagist_active.yml
index 0dfdbd5b610..cc61aeab951 100644
--- a/config/metrics/counts_all/20210216180034_projects_inheriting_packagist_active.yml
+++ b/config/metrics/counts_all/20210216180034_projects_inheriting_packagist_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_packagist_active
description: Count of active projects inheriting integrations for Packagist
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180036_groups_inheriting_packagist_active.yml b/config/metrics/counts_all/20210216180036_groups_inheriting_packagist_active.yml
index 21b7b80ec17..87e89a24f0b 100644
--- a/config/metrics/counts_all/20210216180036_groups_inheriting_packagist_active.yml
+++ b/config/metrics/counts_all/20210216180036_groups_inheriting_packagist_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_packagist_active
description: Count of active groups inheriting integrations for Packagist
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180038_projects_pipelines_email_active.yml b/config/metrics/counts_all/20210216180038_projects_pipelines_email_active.yml
index b1f315903a6..e23ac62c864 100644
--- a/config/metrics/counts_all/20210216180038_projects_pipelines_email_active.yml
+++ b/config/metrics/counts_all/20210216180038_projects_pipelines_email_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_pipelines_email_active
description: Count of projects with active integrations for Pipeline Emails
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180040_groups_pipelines_email_active.yml b/config/metrics/counts_all/20210216180040_groups_pipelines_email_active.yml
index b3e5ff8ea4c..8e969cd2254 100644
--- a/config/metrics/counts_all/20210216180040_groups_pipelines_email_active.yml
+++ b/config/metrics/counts_all/20210216180040_groups_pipelines_email_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_pipelines_email_active
description: Count of groups with active integrations for Pipeline Emails
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180041_templates_pipelines_email_active.yml b/config/metrics/counts_all/20210216180041_templates_pipelines_email_active.yml
index ad3ed4311ff..9fccfbfb67e 100644
--- a/config/metrics/counts_all/20210216180041_templates_pipelines_email_active.yml
+++ b/config/metrics/counts_all/20210216180041_templates_pipelines_email_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_pipelines_email_active
description: Count of active service templates for Pipeline Emails
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180043_instances_pipelines_email_active.yml b/config/metrics/counts_all/20210216180043_instances_pipelines_email_active.yml
index c815050bec2..253d76935dd 100644
--- a/config/metrics/counts_all/20210216180043_instances_pipelines_email_active.yml
+++ b/config/metrics/counts_all/20210216180043_instances_pipelines_email_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_pipelines_email_active
description: Count of active instance-level integrations for Pipeline Emails
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180045_projects_inheriting_pipelines_email_active.yml b/config/metrics/counts_all/20210216180045_projects_inheriting_pipelines_email_active.yml
index 04cff98babb..c43f3484f35 100644
--- a/config/metrics/counts_all/20210216180045_projects_inheriting_pipelines_email_active.yml
+++ b/config/metrics/counts_all/20210216180045_projects_inheriting_pipelines_email_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_pipelines_email_active
description: Count of active projects inheriting integrations for Pipeline Emails
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180047_groups_inheriting_pipelines_email_active.yml b/config/metrics/counts_all/20210216180047_groups_inheriting_pipelines_email_active.yml
index 1408f2084b8..4e03c0cf990 100644
--- a/config/metrics/counts_all/20210216180047_groups_inheriting_pipelines_email_active.yml
+++ b/config/metrics/counts_all/20210216180047_groups_inheriting_pipelines_email_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_pipelines_email_active
description: Count of active groups inheriting integrations for Pipeline Emails
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180049_projects_pivotaltracker_active.yml b/config/metrics/counts_all/20210216180049_projects_pivotaltracker_active.yml
index 312e0c0dd93..39be8cbf49c 100644
--- a/config/metrics/counts_all/20210216180049_projects_pivotaltracker_active.yml
+++ b/config/metrics/counts_all/20210216180049_projects_pivotaltracker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_pivotaltracker_active
description: Count of projects with active integrations for Pivotal Tracker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180051_groups_pivotaltracker_active.yml b/config/metrics/counts_all/20210216180051_groups_pivotaltracker_active.yml
index 2d1d3110957..ef3d5627379 100644
--- a/config/metrics/counts_all/20210216180051_groups_pivotaltracker_active.yml
+++ b/config/metrics/counts_all/20210216180051_groups_pivotaltracker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_pivotaltracker_active
description: Count of groups with active integrations for Pivotal Tracker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180052_templates_pivotaltracker_active.yml b/config/metrics/counts_all/20210216180052_templates_pivotaltracker_active.yml
index 338fa4f6adc..b54e62f535c 100644
--- a/config/metrics/counts_all/20210216180052_templates_pivotaltracker_active.yml
+++ b/config/metrics/counts_all/20210216180052_templates_pivotaltracker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_pivotaltracker_active
description: Count of active service templates for Pivotal Tracker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180054_instances_pivotaltracker_active.yml b/config/metrics/counts_all/20210216180054_instances_pivotaltracker_active.yml
index 8e6590c031c..931c9b981f6 100644
--- a/config/metrics/counts_all/20210216180054_instances_pivotaltracker_active.yml
+++ b/config/metrics/counts_all/20210216180054_instances_pivotaltracker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_pivotaltracker_active
description: Count of active instance-level integrations for Pivotal Tracker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180056_projects_inheriting_pivotaltracker_active.yml b/config/metrics/counts_all/20210216180056_projects_inheriting_pivotaltracker_active.yml
index 14f61d6c3e2..beaf20266af 100644
--- a/config/metrics/counts_all/20210216180056_projects_inheriting_pivotaltracker_active.yml
+++ b/config/metrics/counts_all/20210216180056_projects_inheriting_pivotaltracker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_pivotaltracker_active
description: Count of active projects inheriting integrations for Pivotal Tracker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180058_groups_inheriting_pivotaltracker_active.yml b/config/metrics/counts_all/20210216180058_groups_inheriting_pivotaltracker_active.yml
index 9dfa4d23021..55f9346ac0f 100644
--- a/config/metrics/counts_all/20210216180058_groups_inheriting_pivotaltracker_active.yml
+++ b/config/metrics/counts_all/20210216180058_groups_inheriting_pivotaltracker_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_pivotaltracker_active
description: Count of active groups inheriting integrations for Pivotal Tracker
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180100_projects_pushover_active.yml b/config/metrics/counts_all/20210216180100_projects_pushover_active.yml
index 85f9bfdf6c6..7f6a57168d9 100644
--- a/config/metrics/counts_all/20210216180100_projects_pushover_active.yml
+++ b/config/metrics/counts_all/20210216180100_projects_pushover_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_pushover_active
description: Count of projects with active integrations for Pushover
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180102_groups_pushover_active.yml b/config/metrics/counts_all/20210216180102_groups_pushover_active.yml
index ab43af5212f..897c531a6f7 100644
--- a/config/metrics/counts_all/20210216180102_groups_pushover_active.yml
+++ b/config/metrics/counts_all/20210216180102_groups_pushover_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_pushover_active
description: Count of groups with active integrations for Pushover
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180104_templates_pushover_active.yml b/config/metrics/counts_all/20210216180104_templates_pushover_active.yml
index 7ba07c02ded..1f0cca6305d 100644
--- a/config/metrics/counts_all/20210216180104_templates_pushover_active.yml
+++ b/config/metrics/counts_all/20210216180104_templates_pushover_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_pushover_active
description: Count of active service templates for Pushover
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180105_instances_pushover_active.yml b/config/metrics/counts_all/20210216180105_instances_pushover_active.yml
index 362873d1d7b..bfaf2726283 100644
--- a/config/metrics/counts_all/20210216180105_instances_pushover_active.yml
+++ b/config/metrics/counts_all/20210216180105_instances_pushover_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_pushover_active
description: Count of active instance-level integrations for Pushover
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180107_projects_inheriting_pushover_active.yml b/config/metrics/counts_all/20210216180107_projects_inheriting_pushover_active.yml
index b8c567b02bf..a71e5f50fb1 100644
--- a/config/metrics/counts_all/20210216180107_projects_inheriting_pushover_active.yml
+++ b/config/metrics/counts_all/20210216180107_projects_inheriting_pushover_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_pushover_active
description: Count of active projects inheriting integrations for Pushover
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180109_groups_inheriting_pushover_active.yml b/config/metrics/counts_all/20210216180109_groups_inheriting_pushover_active.yml
index a587a6ab81c..c08a8f4cc90 100644
--- a/config/metrics/counts_all/20210216180109_groups_inheriting_pushover_active.yml
+++ b/config/metrics/counts_all/20210216180109_groups_inheriting_pushover_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_pushover_active
description: Count of active groups inheriting integrations for Pushover
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180111_projects_redmine_active.yml b/config/metrics/counts_all/20210216180111_projects_redmine_active.yml
index bcb72acdf48..c058489c438 100644
--- a/config/metrics/counts_all/20210216180111_projects_redmine_active.yml
+++ b/config/metrics/counts_all/20210216180111_projects_redmine_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_redmine_active
description: Count of projects with active integrations for Redmine
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180113_groups_redmine_active.yml b/config/metrics/counts_all/20210216180113_groups_redmine_active.yml
index ab31eb0ec82..95c566730bb 100644
--- a/config/metrics/counts_all/20210216180113_groups_redmine_active.yml
+++ b/config/metrics/counts_all/20210216180113_groups_redmine_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_redmine_active
description: Count of groups with active integrations for Redmine
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180115_templates_redmine_active.yml b/config/metrics/counts_all/20210216180115_templates_redmine_active.yml
index 7bddca755ec..c3806d83cf9 100644
--- a/config/metrics/counts_all/20210216180115_templates_redmine_active.yml
+++ b/config/metrics/counts_all/20210216180115_templates_redmine_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_redmine_active
description: Count of active service templates for Redmine
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180116_instances_redmine_active.yml b/config/metrics/counts_all/20210216180116_instances_redmine_active.yml
index 2e1cd17c20f..c6990f3a55d 100644
--- a/config/metrics/counts_all/20210216180116_instances_redmine_active.yml
+++ b/config/metrics/counts_all/20210216180116_instances_redmine_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_redmine_active
description: Count of active instance-level integrations for Redmine
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180118_projects_inheriting_redmine_active.yml b/config/metrics/counts_all/20210216180118_projects_inheriting_redmine_active.yml
index ba6aacb1d0a..968b5a2c71d 100644
--- a/config/metrics/counts_all/20210216180118_projects_inheriting_redmine_active.yml
+++ b/config/metrics/counts_all/20210216180118_projects_inheriting_redmine_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_redmine_active
description: Count of active projects inheriting integrations for Redmine
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180120_groups_inheriting_redmine_active.yml b/config/metrics/counts_all/20210216180120_groups_inheriting_redmine_active.yml
index c219ea9aa92..521ddf7e182 100644
--- a/config/metrics/counts_all/20210216180120_groups_inheriting_redmine_active.yml
+++ b/config/metrics/counts_all/20210216180120_groups_inheriting_redmine_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_redmine_active
description: Count of active groups inheriting integrations for Redmine
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180122_projects_slack_active.yml b/config/metrics/counts_all/20210216180122_projects_slack_active.yml
index 206d36548ad..a885f965100 100644
--- a/config/metrics/counts_all/20210216180122_projects_slack_active.yml
+++ b/config/metrics/counts_all/20210216180122_projects_slack_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_slack_active
description: Count of projects with active integrations for Slack
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180124_groups_slack_active.yml b/config/metrics/counts_all/20210216180124_groups_slack_active.yml
index 91bf70daa37..f7c35542615 100644
--- a/config/metrics/counts_all/20210216180124_groups_slack_active.yml
+++ b/config/metrics/counts_all/20210216180124_groups_slack_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_slack_active
description: Count of groups with active integrations for Slack
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180126_templates_slack_active.yml b/config/metrics/counts_all/20210216180126_templates_slack_active.yml
index aa90f12ab18..5253bed85ca 100644
--- a/config/metrics/counts_all/20210216180126_templates_slack_active.yml
+++ b/config/metrics/counts_all/20210216180126_templates_slack_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_slack_active
description: Count of active service templates for Slack
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180127_instances_slack_active.yml b/config/metrics/counts_all/20210216180127_instances_slack_active.yml
index 931404189d1..707d61aed19 100644
--- a/config/metrics/counts_all/20210216180127_instances_slack_active.yml
+++ b/config/metrics/counts_all/20210216180127_instances_slack_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_slack_active
description: Count of active instance-level integrations for Slack
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180129_projects_inheriting_slack_active.yml b/config/metrics/counts_all/20210216180129_projects_inheriting_slack_active.yml
index 84552e83be8..f402f2b39d3 100644
--- a/config/metrics/counts_all/20210216180129_projects_inheriting_slack_active.yml
+++ b/config/metrics/counts_all/20210216180129_projects_inheriting_slack_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_slack_active
description: Count of active projects inheriting integrations for Slack
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180131_groups_inheriting_slack_active.yml b/config/metrics/counts_all/20210216180131_groups_inheriting_slack_active.yml
index ec48bd47db0..d83501b3273 100644
--- a/config/metrics/counts_all/20210216180131_groups_inheriting_slack_active.yml
+++ b/config/metrics/counts_all/20210216180131_groups_inheriting_slack_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_slack_active
description: Count of active groups inheriting integrations for Slack
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180133_projects_slack_slash_commands_active.yml b/config/metrics/counts_all/20210216180133_projects_slack_slash_commands_active.yml
index 790872db206..e0a75a66df5 100644
--- a/config/metrics/counts_all/20210216180133_projects_slack_slash_commands_active.yml
+++ b/config/metrics/counts_all/20210216180133_projects_slack_slash_commands_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_slack_slash_commands_active
description: Count of projects with active integrations for Slack (slash commands)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180135_groups_slack_slash_commands_active.yml b/config/metrics/counts_all/20210216180135_groups_slack_slash_commands_active.yml
index 5a820ea6ae7..d53b0333205 100644
--- a/config/metrics/counts_all/20210216180135_groups_slack_slash_commands_active.yml
+++ b/config/metrics/counts_all/20210216180135_groups_slack_slash_commands_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_slack_slash_commands_active
description: Count of groups with active integrations for Slack (slash commands)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180137_templates_slack_slash_commands_active.yml b/config/metrics/counts_all/20210216180137_templates_slack_slash_commands_active.yml
index 1718564975d..ce6a1ae807d 100644
--- a/config/metrics/counts_all/20210216180137_templates_slack_slash_commands_active.yml
+++ b/config/metrics/counts_all/20210216180137_templates_slack_slash_commands_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_slack_slash_commands_active
description: Count of active service templates for Slack (slash commands)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180138_instances_slack_slash_commands_active.yml b/config/metrics/counts_all/20210216180138_instances_slack_slash_commands_active.yml
index 9f6da9f0e7f..de0bd69b1d9 100644
--- a/config/metrics/counts_all/20210216180138_instances_slack_slash_commands_active.yml
+++ b/config/metrics/counts_all/20210216180138_instances_slack_slash_commands_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_slack_slash_commands_active
description: Count of active instance-level integrations for Slack (slash commands)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180140_projects_inheriting_slack_slash_commands_active.yml b/config/metrics/counts_all/20210216180140_projects_inheriting_slack_slash_commands_active.yml
index 7e8f209f625..cb3ae4b9b14 100644
--- a/config/metrics/counts_all/20210216180140_projects_inheriting_slack_slash_commands_active.yml
+++ b/config/metrics/counts_all/20210216180140_projects_inheriting_slack_slash_commands_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_slack_slash_commands_active
description: Count of active projects inheriting integrations for Slack (slash commands)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180142_groups_inheriting_slack_slash_commands_active.yml b/config/metrics/counts_all/20210216180142_groups_inheriting_slack_slash_commands_active.yml
index 4dfed91dc58..d075715daae 100644
--- a/config/metrics/counts_all/20210216180142_groups_inheriting_slack_slash_commands_active.yml
+++ b/config/metrics/counts_all/20210216180142_groups_inheriting_slack_slash_commands_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_slack_slash_commands_active
description: Count of active groups inheriting integrations for Slack (slash commands)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180144_projects_teamcity_active.yml b/config/metrics/counts_all/20210216180144_projects_teamcity_active.yml
index ad8d1afcc8e..10c1f56070a 100644
--- a/config/metrics/counts_all/20210216180144_projects_teamcity_active.yml
+++ b/config/metrics/counts_all/20210216180144_projects_teamcity_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_teamcity_active
description: Count of projects with active integrations for Teamcity CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180146_groups_teamcity_active.yml b/config/metrics/counts_all/20210216180146_groups_teamcity_active.yml
index 20deac7fe75..5171ab2c2d1 100644
--- a/config/metrics/counts_all/20210216180146_groups_teamcity_active.yml
+++ b/config/metrics/counts_all/20210216180146_groups_teamcity_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_teamcity_active
description: Count of groups with active integrations for Teamcity CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180148_templates_teamcity_active.yml b/config/metrics/counts_all/20210216180148_templates_teamcity_active.yml
index e1f01e57a31..b6845efeb28 100644
--- a/config/metrics/counts_all/20210216180148_templates_teamcity_active.yml
+++ b/config/metrics/counts_all/20210216180148_templates_teamcity_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_teamcity_active
description: Count of active service templates for Teamcity CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180149_instances_teamcity_active.yml b/config/metrics/counts_all/20210216180149_instances_teamcity_active.yml
index 32404539b74..00f423a9169 100644
--- a/config/metrics/counts_all/20210216180149_instances_teamcity_active.yml
+++ b/config/metrics/counts_all/20210216180149_instances_teamcity_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_teamcity_active
description: Count of active instance-level integrations for Teamcity CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180151_projects_inheriting_teamcity_active.yml b/config/metrics/counts_all/20210216180151_projects_inheriting_teamcity_active.yml
index daddf5ca1db..917579478b5 100644
--- a/config/metrics/counts_all/20210216180151_projects_inheriting_teamcity_active.yml
+++ b/config/metrics/counts_all/20210216180151_projects_inheriting_teamcity_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_teamcity_active
description: Count of active projects inheriting integrations for Teamcity CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180153_groups_inheriting_teamcity_active.yml b/config/metrics/counts_all/20210216180153_groups_inheriting_teamcity_active.yml
index 53879bc7462..5a82830dea5 100644
--- a/config/metrics/counts_all/20210216180153_groups_inheriting_teamcity_active.yml
+++ b/config/metrics/counts_all/20210216180153_groups_inheriting_teamcity_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_teamcity_active
description: Count of active groups inheriting integrations for Teamcity CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180155_projects_unify_circuit_active.yml b/config/metrics/counts_all/20210216180155_projects_unify_circuit_active.yml
index 3b678d43017..6aa78eaabfd 100644
--- a/config/metrics/counts_all/20210216180155_projects_unify_circuit_active.yml
+++ b/config/metrics/counts_all/20210216180155_projects_unify_circuit_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_unify_circuit_active
description: Count of projects with active integrations for Unifiy Circuit
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180157_groups_unify_circuit_active.yml b/config/metrics/counts_all/20210216180157_groups_unify_circuit_active.yml
index 4d40f5a473d..623c2389073 100644
--- a/config/metrics/counts_all/20210216180157_groups_unify_circuit_active.yml
+++ b/config/metrics/counts_all/20210216180157_groups_unify_circuit_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_unify_circuit_active
description: Count of groups with active integrations for Unifiy Circuit
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180159_templates_unify_circuit_active.yml b/config/metrics/counts_all/20210216180159_templates_unify_circuit_active.yml
index 6e7c83ed6fc..47731d1b5b9 100644
--- a/config/metrics/counts_all/20210216180159_templates_unify_circuit_active.yml
+++ b/config/metrics/counts_all/20210216180159_templates_unify_circuit_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_unify_circuit_active
description: Count of active service templates for Unifiy Circuit
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180201_instances_unify_circuit_active.yml b/config/metrics/counts_all/20210216180201_instances_unify_circuit_active.yml
index 74f90bf006c..20deb22c0cb 100644
--- a/config/metrics/counts_all/20210216180201_instances_unify_circuit_active.yml
+++ b/config/metrics/counts_all/20210216180201_instances_unify_circuit_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_unify_circuit_active
description: Count of active instance-level integrations for Unifiy Circuit
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180203_projects_inheriting_unify_circuit_active.yml b/config/metrics/counts_all/20210216180203_projects_inheriting_unify_circuit_active.yml
index 0f3c151d505..d75f316c69c 100644
--- a/config/metrics/counts_all/20210216180203_projects_inheriting_unify_circuit_active.yml
+++ b/config/metrics/counts_all/20210216180203_projects_inheriting_unify_circuit_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_unify_circuit_active
description: Count of active projects inheriting integrations for Unifiy Circuit
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180204_groups_inheriting_unify_circuit_active.yml b/config/metrics/counts_all/20210216180204_groups_inheriting_unify_circuit_active.yml
index af114532491..a4e9de64cc7 100644
--- a/config/metrics/counts_all/20210216180204_groups_inheriting_unify_circuit_active.yml
+++ b/config/metrics/counts_all/20210216180204_groups_inheriting_unify_circuit_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_unify_circuit_active
description: Count of active groups inheriting integrations for Unifiy Circuit
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180206_projects_webex_teams_active.yml b/config/metrics/counts_all/20210216180206_projects_webex_teams_active.yml
index 07f5c5d5ce1..92d93cecdb5 100644
--- a/config/metrics/counts_all/20210216180206_projects_webex_teams_active.yml
+++ b/config/metrics/counts_all/20210216180206_projects_webex_teams_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_webex_teams_active
description: Count of projects with active integrations for Webex Teams
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180208_groups_webex_teams_active.yml b/config/metrics/counts_all/20210216180208_groups_webex_teams_active.yml
index 682e719a37c..4a40e435994 100644
--- a/config/metrics/counts_all/20210216180208_groups_webex_teams_active.yml
+++ b/config/metrics/counts_all/20210216180208_groups_webex_teams_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_webex_teams_active
description: Count of groups with active integrations for Webex Teams
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180210_templates_webex_teams_active.yml b/config/metrics/counts_all/20210216180210_templates_webex_teams_active.yml
index ace629d4322..3360b45093e 100644
--- a/config/metrics/counts_all/20210216180210_templates_webex_teams_active.yml
+++ b/config/metrics/counts_all/20210216180210_templates_webex_teams_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_webex_teams_active
description: Count of active service templates for Webex Teams
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180212_instances_webex_teams_active.yml b/config/metrics/counts_all/20210216180212_instances_webex_teams_active.yml
index 2d75cb7bebe..a5e4dc2cfa6 100644
--- a/config/metrics/counts_all/20210216180212_instances_webex_teams_active.yml
+++ b/config/metrics/counts_all/20210216180212_instances_webex_teams_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_webex_teams_active
description: Count of active instance-level integrations for Webex Teams
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180214_projects_inheriting_webex_teams_active.yml b/config/metrics/counts_all/20210216180214_projects_inheriting_webex_teams_active.yml
index b2527e738ca..2fe2a61187e 100644
--- a/config/metrics/counts_all/20210216180214_projects_inheriting_webex_teams_active.yml
+++ b/config/metrics/counts_all/20210216180214_projects_inheriting_webex_teams_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_webex_teams_active
description: Count of active projects inheriting integrations for Webex Teams
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180215_groups_inheriting_webex_teams_active.yml b/config/metrics/counts_all/20210216180215_groups_inheriting_webex_teams_active.yml
index 5a59e20a5af..8a87a1cdc02 100644
--- a/config/metrics/counts_all/20210216180215_groups_inheriting_webex_teams_active.yml
+++ b/config/metrics/counts_all/20210216180215_groups_inheriting_webex_teams_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_webex_teams_active
description: Count of active groups inheriting integrations for Webex Teams
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180217_projects_youtrack_active.yml b/config/metrics/counts_all/20210216180217_projects_youtrack_active.yml
index 3e65b2b28dd..a8625a464cb 100644
--- a/config/metrics/counts_all/20210216180217_projects_youtrack_active.yml
+++ b/config/metrics/counts_all/20210216180217_projects_youtrack_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_youtrack_active
description: Count of projects with active integrations for YouTrack
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180219_groups_youtrack_active.yml b/config/metrics/counts_all/20210216180219_groups_youtrack_active.yml
index 6c57b9e5c86..0ee62f379e8 100644
--- a/config/metrics/counts_all/20210216180219_groups_youtrack_active.yml
+++ b/config/metrics/counts_all/20210216180219_groups_youtrack_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_youtrack_active
description: Count of groups with active integrations for YouTrack
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180221_templates_youtrack_active.yml b/config/metrics/counts_all/20210216180221_templates_youtrack_active.yml
index 252c1724c48..9334ef68345 100644
--- a/config/metrics/counts_all/20210216180221_templates_youtrack_active.yml
+++ b/config/metrics/counts_all/20210216180221_templates_youtrack_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_youtrack_active
description: Count of active service templates for YouTrack
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180223_instances_youtrack_active.yml b/config/metrics/counts_all/20210216180223_instances_youtrack_active.yml
index e678f693ef4..24d6440afb6 100644
--- a/config/metrics/counts_all/20210216180223_instances_youtrack_active.yml
+++ b/config/metrics/counts_all/20210216180223_instances_youtrack_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_youtrack_active
description: Count of active instance-level integrations for YouTrack
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180225_projects_inheriting_youtrack_active.yml b/config/metrics/counts_all/20210216180225_projects_inheriting_youtrack_active.yml
index ffeecb454d2..cacc694f002 100644
--- a/config/metrics/counts_all/20210216180225_projects_inheriting_youtrack_active.yml
+++ b/config/metrics/counts_all/20210216180225_projects_inheriting_youtrack_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_youtrack_active
description: Count of active projects inheriting integrations for YouTrack
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180226_groups_inheriting_youtrack_active.yml b/config/metrics/counts_all/20210216180226_groups_inheriting_youtrack_active.yml
index c8874399e76..1286a306aef 100644
--- a/config/metrics/counts_all/20210216180226_groups_inheriting_youtrack_active.yml
+++ b/config/metrics/counts_all/20210216180226_groups_inheriting_youtrack_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_youtrack_active
description: Count of active groups inheriting integrations for YouTrack
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
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 752f280dab3..cc000031e83 100644
--- a/config/metrics/counts_all/20210216180228_projects_jira_server_active.yml
+++ b/config/metrics/counts_all/20210216180228_projects_jira_server_active.yml
@@ -3,7 +3,7 @@ data_category: operational
key_path: counts.projects_jira_server_active
description: Count of active integrations with Jira Software (server)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
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 ceea89b7035..d607f3d6aea 100644
--- a/config/metrics/counts_all/20210216180230_projects_jira_cloud_active.yml
+++ b/config/metrics/counts_all/20210216180230_projects_jira_cloud_active.yml
@@ -3,7 +3,7 @@ data_category: operational
key_path: counts.projects_jira_cloud_active
description: Count of active integrations with Jira Cloud (Saas)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180232_projects_jira_dvcs_cloud_active.yml b/config/metrics/counts_all/20210216180232_projects_jira_dvcs_cloud_active.yml
index c98c7526f16..158e18a738e 100644
--- a/config/metrics/counts_all/20210216180232_projects_jira_dvcs_cloud_active.yml
+++ b/config/metrics/counts_all/20210216180232_projects_jira_dvcs_cloud_active.yml
@@ -3,7 +3,7 @@ data_category: operational
key_path: counts.projects_jira_dvcs_cloud_active
description: Count of active integrations with Jira Cloud (DVCS Connector)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216180234_projects_jira_dvcs_server_active.yml b/config/metrics/counts_all/20210216180234_projects_jira_dvcs_server_active.yml
index 9179ec898f3..a436d0dddae 100644
--- a/config/metrics/counts_all/20210216180234_projects_jira_dvcs_server_active.yml
+++ b/config/metrics/counts_all/20210216180234_projects_jira_dvcs_server_active.yml
@@ -3,7 +3,7 @@ data_category: operational
key_path: counts.projects_jira_dvcs_server_active
description: Count of active integrations with Jira Software (DVCS connector)
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216181014_projects_with_expiration_policy_disabled.yml b/config/metrics/counts_all/20210216181014_projects_with_expiration_policy_disabled.yml
index c2294650494..6b6f0e978ae 100644
--- a/config/metrics/counts_all/20210216181014_projects_with_expiration_policy_disabled.yml
+++ b/config/metrics/counts_all/20210216181014_projects_with_expiration_policy_disabled.yml
@@ -10,7 +10,9 @@ value_type: number
status: active
time_frame: all
data_source: database
-instrumentation_class: DistinctCountProjectsWithExpirationPolicyDisabledMetric
+instrumentation_class: DistinctCountProjectsWithExpirationPolicyMetric
+options:
+ enabled: false
distribution:
- ee
- ce
diff --git a/config/metrics/counts_all/20210216181016_projects_with_expiration_policy_enabled.yml b/config/metrics/counts_all/20210216181016_projects_with_expiration_policy_enabled.yml
index c5e5e7fffd1..3c49f82fa6b 100644
--- a/config/metrics/counts_all/20210216181016_projects_with_expiration_policy_enabled.yml
+++ b/config/metrics/counts_all/20210216181016_projects_with_expiration_policy_enabled.yml
@@ -10,6 +10,9 @@ value_type: number
status: active
time_frame: all
data_source: database
+instrumentation_class: DistinctCountProjectsWithExpirationPolicyMetric
+options:
+ enabled: true
distribution:
- ee
- ce
diff --git a/config/metrics/counts_all/20210216181018_projects_with_expiration_policy_enabled_with_keep_n_set_to_1.yml b/config/metrics/counts_all/20210216181018_projects_with_expiration_policy_enabled_with_keep_n_set_to_1.yml
index 2a531707621..e9eaec20453 100644
--- a/config/metrics/counts_all/20210216181018_projects_with_expiration_policy_enabled_with_keep_n_set_to_1.yml
+++ b/config/metrics/counts_all/20210216181018_projects_with_expiration_policy_enabled_with_keep_n_set_to_1.yml
@@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: all
data_source: database
+instrumentation_class: DistinctCountProjectsWithExpirationPolicyMetric
+options:
+ enabled: true
+ keep_n: 1
distribution:
- ee
- ce
diff --git a/config/metrics/counts_all/20210216181020_projects_with_expiration_policy_enabled_with_keep_n_set_to_5.yml b/config/metrics/counts_all/20210216181020_projects_with_expiration_policy_enabled_with_keep_n_set_to_5.yml
index 4e9df93f171..b6bc610b97a 100644
--- a/config/metrics/counts_all/20210216181020_projects_with_expiration_policy_enabled_with_keep_n_set_to_5.yml
+++ b/config/metrics/counts_all/20210216181020_projects_with_expiration_policy_enabled_with_keep_n_set_to_5.yml
@@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: all
data_source: database
+instrumentation_class: DistinctCountProjectsWithExpirationPolicyMetric
+options:
+ enabled: true
+ keep_n: 5
distribution:
- ee
- ce
diff --git a/config/metrics/counts_all/20210216181022_projects_with_expiration_policy_enabled_with_keep_n_set_to_10.yml b/config/metrics/counts_all/20210216181022_projects_with_expiration_policy_enabled_with_keep_n_set_to_10.yml
index da0e5006521..906382f2e52 100644
--- a/config/metrics/counts_all/20210216181022_projects_with_expiration_policy_enabled_with_keep_n_set_to_10.yml
+++ b/config/metrics/counts_all/20210216181022_projects_with_expiration_policy_enabled_with_keep_n_set_to_10.yml
@@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: all
data_source: database
+instrumentation_class: DistinctCountProjectsWithExpirationPolicyMetric
+options:
+ enabled: true
+ keep_n: 10
distribution:
- ee
- ce
diff --git a/config/metrics/counts_all/20210216181024_projects_with_expiration_policy_enabled_with_keep_n_set_to_25.yml b/config/metrics/counts_all/20210216181024_projects_with_expiration_policy_enabled_with_keep_n_set_to_25.yml
index 84bce062d63..2ba5e503c81 100644
--- a/config/metrics/counts_all/20210216181024_projects_with_expiration_policy_enabled_with_keep_n_set_to_25.yml
+++ b/config/metrics/counts_all/20210216181024_projects_with_expiration_policy_enabled_with_keep_n_set_to_25.yml
@@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: all
data_source: database
+instrumentation_class: DistinctCountProjectsWithExpirationPolicyMetric
+options:
+ enabled: true
+ keep_n: 25
distribution:
- ee
- ce
diff --git a/config/metrics/counts_all/20210216181025_projects_with_expiration_policy_enabled_with_keep_n_set_to_50.yml b/config/metrics/counts_all/20210216181025_projects_with_expiration_policy_enabled_with_keep_n_set_to_50.yml
index 38579a1bdc2..faa4bb4ba8f 100644
--- a/config/metrics/counts_all/20210216181025_projects_with_expiration_policy_enabled_with_keep_n_set_to_50.yml
+++ b/config/metrics/counts_all/20210216181025_projects_with_expiration_policy_enabled_with_keep_n_set_to_50.yml
@@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: all
data_source: database
+instrumentation_class: DistinctCountProjectsWithExpirationPolicyMetric
+options:
+ enabled: true
+ keep_n: 50
distribution:
- ee
- ce
diff --git a/config/metrics/counts_all/20210216181027_projects_with_expiration_policy_enabled_with_keep_n_set_to_100.yml b/config/metrics/counts_all/20210216181027_projects_with_expiration_policy_enabled_with_keep_n_set_to_100.yml
index 69c59dd2262..bc2963db71f 100644
--- a/config/metrics/counts_all/20210216181027_projects_with_expiration_policy_enabled_with_keep_n_set_to_100.yml
+++ b/config/metrics/counts_all/20210216181027_projects_with_expiration_policy_enabled_with_keep_n_set_to_100.yml
@@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: all
data_source: database
+instrumentation_class: DistinctCountProjectsWithExpirationPolicyMetric
+options:
+ enabled: true
+ keep_n: 100
distribution:
- ee
- ce
diff --git a/config/metrics/counts_all/20210216181029_projects_with_expiration_policy_enabled_with_cadence_set_to_1d.yml b/config/metrics/counts_all/20210216181029_projects_with_expiration_policy_enabled_with_cadence_set_to_1d.yml
index 1694127fd2c..2c6e2745560 100644
--- a/config/metrics/counts_all/20210216181029_projects_with_expiration_policy_enabled_with_cadence_set_to_1d.yml
+++ b/config/metrics/counts_all/20210216181029_projects_with_expiration_policy_enabled_with_cadence_set_to_1d.yml
@@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: all
data_source: database
+instrumentation_class: DistinctCountProjectsWithExpirationPolicyMetric
+options:
+ enabled: true
+ cadence: 1d
distribution:
- ee
- ce
diff --git a/config/metrics/counts_all/20210216181031_projects_with_expiration_policy_enabled_with_cadence_set_to_7d.yml b/config/metrics/counts_all/20210216181031_projects_with_expiration_policy_enabled_with_cadence_set_to_7d.yml
index a9f8ed70c94..15be6b54bfd 100644
--- a/config/metrics/counts_all/20210216181031_projects_with_expiration_policy_enabled_with_cadence_set_to_7d.yml
+++ b/config/metrics/counts_all/20210216181031_projects_with_expiration_policy_enabled_with_cadence_set_to_7d.yml
@@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: all
data_source: database
+instrumentation_class: DistinctCountProjectsWithExpirationPolicyMetric
+options:
+ enabled: true
+ cadence: 7d
distribution:
- ee
- ce
diff --git a/config/metrics/counts_all/20210216181033_projects_with_expiration_policy_enabled_with_cadence_set_to_14d.yml b/config/metrics/counts_all/20210216181033_projects_with_expiration_policy_enabled_with_cadence_set_to_14d.yml
index 7afc773b713..68d54c4ebe0 100644
--- a/config/metrics/counts_all/20210216181033_projects_with_expiration_policy_enabled_with_cadence_set_to_14d.yml
+++ b/config/metrics/counts_all/20210216181033_projects_with_expiration_policy_enabled_with_cadence_set_to_14d.yml
@@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: all
data_source: database
+instrumentation_class: DistinctCountProjectsWithExpirationPolicyMetric
+options:
+ enabled: true
+ cadence: 14d
distribution:
- ee
- ce
diff --git a/config/metrics/counts_all/20210216181035_projects_with_expiration_policy_enabled_with_cadence_set_to_1month.yml b/config/metrics/counts_all/20210216181035_projects_with_expiration_policy_enabled_with_cadence_set_to_1month.yml
index b083411ab7f..fe620f1997c 100644
--- a/config/metrics/counts_all/20210216181035_projects_with_expiration_policy_enabled_with_cadence_set_to_1month.yml
+++ b/config/metrics/counts_all/20210216181035_projects_with_expiration_policy_enabled_with_cadence_set_to_1month.yml
@@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: all
data_source: database
+instrumentation_class: DistinctCountProjectsWithExpirationPolicyMetric
+options:
+ enabled: true
+ cadence: 1month
distribution:
- ee
- ce
diff --git a/config/metrics/counts_all/20210216181037_projects_with_expiration_policy_enabled_with_cadence_set_to_3month.yml b/config/metrics/counts_all/20210216181037_projects_with_expiration_policy_enabled_with_cadence_set_to_3month.yml
index 0df858b127d..8b06790d4ac 100644
--- a/config/metrics/counts_all/20210216181037_projects_with_expiration_policy_enabled_with_cadence_set_to_3month.yml
+++ b/config/metrics/counts_all/20210216181037_projects_with_expiration_policy_enabled_with_cadence_set_to_3month.yml
@@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: all
data_source: database
+instrumentation_class: DistinctCountProjectsWithExpirationPolicyMetric
+options:
+ enabled: true
+ cadence: 3month
distribution:
- ee
- ce
diff --git a/config/metrics/counts_all/20210216181046_projects_with_expiration_policy_enabled_with_keep_n_unset.yml b/config/metrics/counts_all/20210216181046_projects_with_expiration_policy_enabled_with_keep_n_unset.yml
index 6a98e4ecfd8..912e349a206 100644
--- a/config/metrics/counts_all/20210216181046_projects_with_expiration_policy_enabled_with_keep_n_unset.yml
+++ b/config/metrics/counts_all/20210216181046_projects_with_expiration_policy_enabled_with_keep_n_unset.yml
@@ -11,6 +11,10 @@ value_type: number
status: active
time_frame: all
data_source: database
+instrumentation_class: DistinctCountProjectsWithExpirationPolicyMetric
+options:
+ enabled: true
+ keep_n: null
distribution:
- ee
- ce
diff --git a/config/metrics/counts_all/20210216181126_projects_jira_active.yml b/config/metrics/counts_all/20210216181126_projects_jira_active.yml
index 2bd0cdf62c3..54426bd92bf 100644
--- a/config/metrics/counts_all/20210216181126_projects_jira_active.yml
+++ b/config/metrics/counts_all/20210216181126_projects_jira_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: usage_activity_by_stage.plan.projects_jira_active
description: Distinct count of creator_id from projects with an active Jira integration.
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216181128_projects_jira_dvcs_cloud_active.yml b/config/metrics/counts_all/20210216181128_projects_jira_dvcs_cloud_active.yml
index 9d17fd23fde..7ed8f79a5a7 100644
--- a/config/metrics/counts_all/20210216181128_projects_jira_dvcs_cloud_active.yml
+++ b/config/metrics/counts_all/20210216181128_projects_jira_dvcs_cloud_active.yml
@@ -4,7 +4,7 @@ key_path: usage_activity_by_stage.plan.projects_jira_dvcs_cloud_active
description: Distinct count of creator_id from projects with an active Jira Cloud
DVCS integration.
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integration
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216181130_projects_jira_dvcs_server_active.yml b/config/metrics/counts_all/20210216181130_projects_jira_dvcs_server_active.yml
index 49747d3239c..4d34d7917d5 100644
--- a/config/metrics/counts_all/20210216181130_projects_jira_dvcs_server_active.yml
+++ b/config/metrics/counts_all/20210216181130_projects_jira_dvcs_server_active.yml
@@ -4,7 +4,7 @@ key_path: usage_activity_by_stage.plan.projects_jira_dvcs_server_active
description: Distinct count of creator_id from projects with an active Jira Server
DVCS integration.
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integration
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216181258_jira_imports_total_imported_count.yml b/config/metrics/counts_all/20210216181258_jira_imports_total_imported_count.yml
index c38fc0bd081..4facf658e6a 100644
--- a/config/metrics/counts_all/20210216181258_jira_imports_total_imported_count.yml
+++ b/config/metrics/counts_all/20210216181258_jira_imports_total_imported_count.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.jira_imports_total_imported_count
description: Count of Jira imports completed
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: jira_importer
value_type: number
diff --git a/config/metrics/counts_all/20210216181259_jira_imports_projects_count.yml b/config/metrics/counts_all/20210216181259_jira_imports_projects_count.yml
index 0188ba1510b..fb5a674aff9 100644
--- a/config/metrics/counts_all/20210216181259_jira_imports_projects_count.yml
+++ b/config/metrics/counts_all/20210216181259_jira_imports_projects_count.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.jira_imports_projects_count
description: Count of Projects that imported Issues from Jira
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: jira_importer
value_type: number
diff --git a/config/metrics/counts_all/20210216181301_jira_imports_total_imported_issues_count.yml b/config/metrics/counts_all/20210216181301_jira_imports_total_imported_issues_count.yml
index c67c7daa770..6d4265d9ac7 100644
--- a/config/metrics/counts_all/20210216181301_jira_imports_total_imported_issues_count.yml
+++ b/config/metrics/counts_all/20210216181301_jira_imports_total_imported_issues_count.yml
@@ -4,7 +4,7 @@ key_path: counts.jira_imports_total_imported_issues_count
instrumentation_class: JiraImportsTotalImportedIssuesCountMetric
description: Count of total issues imported via the Jira Importer
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: jira_importer
value_type: number
diff --git a/config/metrics/counts_all/20210216182547_projects_datadog_active.yml b/config/metrics/counts_all/20210216182547_projects_datadog_active.yml
index 90be5ffdc55..3d057ff95bc 100644
--- a/config/metrics/counts_all/20210216182547_projects_datadog_active.yml
+++ b/config/metrics/counts_all/20210216182547_projects_datadog_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_datadog_active
description: Count of projects with active integrations for Datadog
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182549_groups_datadog_active.yml b/config/metrics/counts_all/20210216182549_groups_datadog_active.yml
index a3a52c46c32..be03cd7e5e2 100644
--- a/config/metrics/counts_all/20210216182549_groups_datadog_active.yml
+++ b/config/metrics/counts_all/20210216182549_groups_datadog_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_datadog_active
description: Count of groups with active integrations for Datadog
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182551_templates_datadog_active.yml b/config/metrics/counts_all/20210216182551_templates_datadog_active.yml
index 9046087dbdc..4fba91477b6 100644
--- a/config/metrics/counts_all/20210216182551_templates_datadog_active.yml
+++ b/config/metrics/counts_all/20210216182551_templates_datadog_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_datadog_active
description: Count of active service templates for Datadog
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182553_instances_datadog_active.yml b/config/metrics/counts_all/20210216182553_instances_datadog_active.yml
index 396e3f19253..f5d70fb8260 100644
--- a/config/metrics/counts_all/20210216182553_instances_datadog_active.yml
+++ b/config/metrics/counts_all/20210216182553_instances_datadog_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_datadog_active
description: Count of active instance-level integrations for Datadog
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182555_projects_inheriting_datadog_active.yml b/config/metrics/counts_all/20210216182555_projects_inheriting_datadog_active.yml
index 50b1f471188..0bd995daf6f 100644
--- a/config/metrics/counts_all/20210216182555_projects_inheriting_datadog_active.yml
+++ b/config/metrics/counts_all/20210216182555_projects_inheriting_datadog_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_datadog_active
description: Count of active projects inheriting integrations for Datadog
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182557_groups_inheriting_datadog_active.yml b/config/metrics/counts_all/20210216182557_groups_inheriting_datadog_active.yml
index 039c71f6b32..09bcd9912f6 100644
--- a/config/metrics/counts_all/20210216182557_groups_inheriting_datadog_active.yml
+++ b/config/metrics/counts_all/20210216182557_groups_inheriting_datadog_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_datadog_active
description: Count of active groups inheriting integrations for Datadog
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182614_projects_ewm_active.yml b/config/metrics/counts_all/20210216182614_projects_ewm_active.yml
index 2a906265e76..772ef421072 100644
--- a/config/metrics/counts_all/20210216182614_projects_ewm_active.yml
+++ b/config/metrics/counts_all/20210216182614_projects_ewm_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_ewm_active
description: Count of projects with active integrations for EWM
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182616_groups_ewm_active.yml b/config/metrics/counts_all/20210216182616_groups_ewm_active.yml
index f2de8af7f77..07366301514 100644
--- a/config/metrics/counts_all/20210216182616_groups_ewm_active.yml
+++ b/config/metrics/counts_all/20210216182616_groups_ewm_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_ewm_active
description: Count of groups with active integrations for EWM
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182618_templates_ewm_active.yml b/config/metrics/counts_all/20210216182618_templates_ewm_active.yml
index de408750880..0e11cba9c6e 100644
--- a/config/metrics/counts_all/20210216182618_templates_ewm_active.yml
+++ b/config/metrics/counts_all/20210216182618_templates_ewm_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_ewm_active
description: Count of active service templates for EWM
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182620_instances_ewm_active.yml b/config/metrics/counts_all/20210216182620_instances_ewm_active.yml
index 3cf2648b6ba..5e07ff74113 100644
--- a/config/metrics/counts_all/20210216182620_instances_ewm_active.yml
+++ b/config/metrics/counts_all/20210216182620_instances_ewm_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_ewm_active
description: Count of active instance-level integrations for EWM
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182622_projects_inheriting_ewm_active.yml b/config/metrics/counts_all/20210216182622_projects_inheriting_ewm_active.yml
index 5c7b7c23d20..4704daf9813 100644
--- a/config/metrics/counts_all/20210216182622_projects_inheriting_ewm_active.yml
+++ b/config/metrics/counts_all/20210216182622_projects_inheriting_ewm_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_ewm_active
description: Count of active projects inheriting integrations for EWM
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182623_groups_inheriting_ewm_active.yml b/config/metrics/counts_all/20210216182623_groups_inheriting_ewm_active.yml
index c385ba3eccc..e5c80d2c1d1 100644
--- a/config/metrics/counts_all/20210216182623_groups_inheriting_ewm_active.yml
+++ b/config/metrics/counts_all/20210216182623_groups_inheriting_ewm_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_ewm_active
description: Count of active groups inheriting integrations for EWM
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182722_projects_mock_ci_active.yml b/config/metrics/counts_all/20210216182722_projects_mock_ci_active.yml
index a3d554185c3..cd958106cbc 100644
--- a/config/metrics/counts_all/20210216182722_projects_mock_ci_active.yml
+++ b/config/metrics/counts_all/20210216182722_projects_mock_ci_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_mock_ci_active
description: Count of projects with active integrations for Mock CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182724_groups_mock_ci_active.yml b/config/metrics/counts_all/20210216182724_groups_mock_ci_active.yml
index 0f00e04dbf9..0db2c32ba7a 100644
--- a/config/metrics/counts_all/20210216182724_groups_mock_ci_active.yml
+++ b/config/metrics/counts_all/20210216182724_groups_mock_ci_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_mock_ci_active
description: Count of groups with active integrations for Mock CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182726_templates_mock_ci_active.yml b/config/metrics/counts_all/20210216182726_templates_mock_ci_active.yml
index 4cff208fc0e..279fd3cc10d 100644
--- a/config/metrics/counts_all/20210216182726_templates_mock_ci_active.yml
+++ b/config/metrics/counts_all/20210216182726_templates_mock_ci_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_mock_ci_active
description: Count of active service templates for Mock CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182728_instances_mock_ci_active.yml b/config/metrics/counts_all/20210216182728_instances_mock_ci_active.yml
index 90878f664ca..15347e16178 100644
--- a/config/metrics/counts_all/20210216182728_instances_mock_ci_active.yml
+++ b/config/metrics/counts_all/20210216182728_instances_mock_ci_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_mock_ci_active
description: Count of active instance-level integrations for Mock CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182730_projects_inheriting_mock_ci_active.yml b/config/metrics/counts_all/20210216182730_projects_inheriting_mock_ci_active.yml
index 0e7cee64e47..6b1a9ed0089 100644
--- a/config/metrics/counts_all/20210216182730_projects_inheriting_mock_ci_active.yml
+++ b/config/metrics/counts_all/20210216182730_projects_inheriting_mock_ci_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_mock_ci_active
description: Count of active projects inheriting integrations for Mock CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182732_groups_inheriting_mock_ci_active.yml b/config/metrics/counts_all/20210216182732_groups_inheriting_mock_ci_active.yml
index 4bd419796cd..314e0e23397 100644
--- a/config/metrics/counts_all/20210216182732_groups_inheriting_mock_ci_active.yml
+++ b/config/metrics/counts_all/20210216182732_groups_inheriting_mock_ci_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_mock_ci_active
description: Count of active groups inheriting integrations for Mock CI
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182734_projects_mock_monitoring_active.yml b/config/metrics/counts_all/20210216182734_projects_mock_monitoring_active.yml
index b44a007dd38..df1a5def60d 100644
--- a/config/metrics/counts_all/20210216182734_projects_mock_monitoring_active.yml
+++ b/config/metrics/counts_all/20210216182734_projects_mock_monitoring_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_mock_monitoring_active
description: Count of projects with active integrations for Mock Monitoring
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182736_groups_mock_monitoring_active.yml b/config/metrics/counts_all/20210216182736_groups_mock_monitoring_active.yml
index c7d70b6fb98..1e891cd7307 100644
--- a/config/metrics/counts_all/20210216182736_groups_mock_monitoring_active.yml
+++ b/config/metrics/counts_all/20210216182736_groups_mock_monitoring_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_mock_monitoring_active
description: Count of groups with active integrations for Mock Monitoring
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182738_templates_mock_monitoring_active.yml b/config/metrics/counts_all/20210216182738_templates_mock_monitoring_active.yml
index 7971b785633..4254f5ffd44 100644
--- a/config/metrics/counts_all/20210216182738_templates_mock_monitoring_active.yml
+++ b/config/metrics/counts_all/20210216182738_templates_mock_monitoring_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.templates_mock_monitoring_active
description: Count of active service templates for Mock Monitoring
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182739_instances_mock_monitoring_active.yml b/config/metrics/counts_all/20210216182739_instances_mock_monitoring_active.yml
index b5949125a90..e2504a98c71 100644
--- a/config/metrics/counts_all/20210216182739_instances_mock_monitoring_active.yml
+++ b/config/metrics/counts_all/20210216182739_instances_mock_monitoring_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_mock_monitoring_active
description: Count of active instance-level integrations for Mock Monitoring
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182741_projects_inheriting_mock_monitoring_active.yml b/config/metrics/counts_all/20210216182741_projects_inheriting_mock_monitoring_active.yml
index 9cd2d8c098a..6a39fcb9fa1 100644
--- a/config/metrics/counts_all/20210216182741_projects_inheriting_mock_monitoring_active.yml
+++ b/config/metrics/counts_all/20210216182741_projects_inheriting_mock_monitoring_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_mock_monitoring_active
description: Count of active projects inheriting integrations for Mock Monitoring
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216182743_groups_inheriting_mock_monitoring_active.yml b/config/metrics/counts_all/20210216182743_groups_inheriting_mock_monitoring_active.yml
index 681ee727cd6..7a3fe6993d8 100644
--- a/config/metrics/counts_all/20210216182743_groups_inheriting_mock_monitoring_active.yml
+++ b/config/metrics/counts_all/20210216182743_groups_inheriting_mock_monitoring_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_mock_monitoring_active
description: Count of active groups inheriting integrations for Mock Monitoring
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210216183000_package_events_i_package_pull_package_by_guest.yml b/config/metrics/counts_all/20210216183000_package_events_i_package_pull_package_by_guest.yml
index 45dcd531484..1ad33d0d479 100644
--- a/config/metrics/counts_all/20210216183000_package_events_i_package_pull_package_by_guest.yml
+++ b/config/metrics/counts_all/20210216183000_package_events_i_package_pull_package_by_guest.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: counts.package_events_i_package_pull_package_by_guest
description: A count of packages that have been downloaded from the package registry
by a guest
diff --git a/config/metrics/counts_all/20210216183005_package_events_i_package_push_package_by_deploy_token.yml b/config/metrics/counts_all/20210216183005_package_events_i_package_push_package_by_deploy_token.yml
index 252474155c1..051e99a67e4 100644
--- a/config/metrics/counts_all/20210216183005_package_events_i_package_push_package_by_deploy_token.yml
+++ b/config/metrics/counts_all/20210216183005_package_events_i_package_push_package_by_deploy_token.yml
@@ -1,5 +1,5 @@
---
-data_category: optional
+data_category: operational
key_path: counts.package_events_i_package_push_package_by_deploy_token
description: A count of packages that have been published to the package registry
using a deploy token
diff --git a/config/metrics/counts_all/20210510201537_in_product_marketing_email_create_0_sent.yml b/config/metrics/counts_all/20210510201537_in_product_marketing_email_create_0_sent.yml
index 1ce9be56198..b8362fb9d71 100644
--- a/config/metrics/counts_all/20210510201537_in_product_marketing_email_create_0_sent.yml
+++ b/config/metrics/counts_all/20210510201537_in_product_marketing_email_create_0_sent.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailSentMetric
+options:
+ track: create
+ series: 0
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510201919_in_product_marketing_email_create_0_cta_clicked.yml b/config/metrics/counts_all/20210510201919_in_product_marketing_email_create_0_cta_clicked.yml
index 98ed67d0910..b93fe4f735e 100644
--- a/config/metrics/counts_all/20210510201919_in_product_marketing_email_create_0_cta_clicked.yml
+++ b/config/metrics/counts_all/20210510201919_in_product_marketing_email_create_0_cta_clicked.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailCtaClickedMetric
+options:
+ track: create
+ series: 0
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510202148_in_product_marketing_email_create_1_sent.yml b/config/metrics/counts_all/20210510202148_in_product_marketing_email_create_1_sent.yml
index 67177bce5dd..b6b3fbb3c49 100644
--- a/config/metrics/counts_all/20210510202148_in_product_marketing_email_create_1_sent.yml
+++ b/config/metrics/counts_all/20210510202148_in_product_marketing_email_create_1_sent.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailSentMetric
+options:
+ track: create
+ series: 1
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510202356_in_product_marketing_email_create_1_cta_clicked.yml b/config/metrics/counts_all/20210510202356_in_product_marketing_email_create_1_cta_clicked.yml
index c5c057fce25..4c457b33db3 100644
--- a/config/metrics/counts_all/20210510202356_in_product_marketing_email_create_1_cta_clicked.yml
+++ b/config/metrics/counts_all/20210510202356_in_product_marketing_email_create_1_cta_clicked.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailCtaClickedMetric
+options:
+ track: create
+ series: 1
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510202604_in_product_marketing_email_create_2_sent.yml b/config/metrics/counts_all/20210510202604_in_product_marketing_email_create_2_sent.yml
index c25864475c4..b0611253f8f 100644
--- a/config/metrics/counts_all/20210510202604_in_product_marketing_email_create_2_sent.yml
+++ b/config/metrics/counts_all/20210510202604_in_product_marketing_email_create_2_sent.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailSentMetric
+options:
+ track: create
+ series: 2
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510202724_in_product_marketing_email_create_2_cta_clicked.yml b/config/metrics/counts_all/20210510202724_in_product_marketing_email_create_2_cta_clicked.yml
index 37ec35d95ba..150e8ba7f3a 100644
--- a/config/metrics/counts_all/20210510202724_in_product_marketing_email_create_2_cta_clicked.yml
+++ b/config/metrics/counts_all/20210510202724_in_product_marketing_email_create_2_cta_clicked.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailCtaClickedMetric
+options:
+ track: create
+ series: 2
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510202807_in_product_marketing_email_verify_0_sent.yml b/config/metrics/counts_all/20210510202807_in_product_marketing_email_verify_0_sent.yml
index 59e3aff567d..d52c4b0066c 100644
--- a/config/metrics/counts_all/20210510202807_in_product_marketing_email_verify_0_sent.yml
+++ b/config/metrics/counts_all/20210510202807_in_product_marketing_email_verify_0_sent.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailSentMetric
+options:
+ track: verify
+ series: 0
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510202943_in_product_marketing_email_verify_0_cta_clicked.yml b/config/metrics/counts_all/20210510202943_in_product_marketing_email_verify_0_cta_clicked.yml
index 17ca0252a0c..6deabd1edda 100644
--- a/config/metrics/counts_all/20210510202943_in_product_marketing_email_verify_0_cta_clicked.yml
+++ b/config/metrics/counts_all/20210510202943_in_product_marketing_email_verify_0_cta_clicked.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailCtaClickedMetric
+options:
+ track: verify
+ series: 0
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510202955_in_product_marketing_email_verify_1_sent.yml b/config/metrics/counts_all/20210510202955_in_product_marketing_email_verify_1_sent.yml
index dfd8bb11919..6d0d53c94d4 100644
--- a/config/metrics/counts_all/20210510202955_in_product_marketing_email_verify_1_sent.yml
+++ b/config/metrics/counts_all/20210510202955_in_product_marketing_email_verify_1_sent.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailSentMetric
+options:
+ track: verify
+ series: 1
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510203005_in_product_marketing_email_verify_1_cta_clicked.yml b/config/metrics/counts_all/20210510203005_in_product_marketing_email_verify_1_cta_clicked.yml
index 6c76386456a..dd412d2cb96 100644
--- a/config/metrics/counts_all/20210510203005_in_product_marketing_email_verify_1_cta_clicked.yml
+++ b/config/metrics/counts_all/20210510203005_in_product_marketing_email_verify_1_cta_clicked.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailCtaClickedMetric
+options:
+ track: verify
+ series: 1
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510203015_in_product_marketing_email_verify_2_sent.yml b/config/metrics/counts_all/20210510203015_in_product_marketing_email_verify_2_sent.yml
index 8cc755cc5bf..f076b40f403 100644
--- a/config/metrics/counts_all/20210510203015_in_product_marketing_email_verify_2_sent.yml
+++ b/config/metrics/counts_all/20210510203015_in_product_marketing_email_verify_2_sent.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailSentMetric
+options:
+ track: verify
+ series: 2
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510203025_in_product_marketing_email_verify_2_cta_clicked.yml b/config/metrics/counts_all/20210510203025_in_product_marketing_email_verify_2_cta_clicked.yml
index 61940a9e0cb..1eea75bb65f 100644
--- a/config/metrics/counts_all/20210510203025_in_product_marketing_email_verify_2_cta_clicked.yml
+++ b/config/metrics/counts_all/20210510203025_in_product_marketing_email_verify_2_cta_clicked.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailCtaClickedMetric
+options:
+ track: verify
+ series: 2
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510203035_in_product_marketing_email_trial_0_sent.yml b/config/metrics/counts_all/20210510203035_in_product_marketing_email_trial_0_sent.yml
index cc2a9c29f1f..216997d9710 100644
--- a/config/metrics/counts_all/20210510203035_in_product_marketing_email_trial_0_sent.yml
+++ b/config/metrics/counts_all/20210510203035_in_product_marketing_email_trial_0_sent.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailSentMetric
+options:
+ track: trial
+ series: 0
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510203044_in_product_marketing_email_trial_0_cta_clicked.yml b/config/metrics/counts_all/20210510203044_in_product_marketing_email_trial_0_cta_clicked.yml
index 3b4a1f7a88e..4a8cbd28827 100644
--- a/config/metrics/counts_all/20210510203044_in_product_marketing_email_trial_0_cta_clicked.yml
+++ b/config/metrics/counts_all/20210510203044_in_product_marketing_email_trial_0_cta_clicked.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailCtaClickedMetric
+options:
+ track: trial
+ series: 0
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510203054_in_product_marketing_email_trial_1_sent.yml b/config/metrics/counts_all/20210510203054_in_product_marketing_email_trial_1_sent.yml
index dd7487b6609..faaf52e4edd 100644
--- a/config/metrics/counts_all/20210510203054_in_product_marketing_email_trial_1_sent.yml
+++ b/config/metrics/counts_all/20210510203054_in_product_marketing_email_trial_1_sent.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailSentMetric
+options:
+ track: trial
+ series: 1
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510203104_in_product_marketing_email_trial_1_cta_clicked.yml b/config/metrics/counts_all/20210510203104_in_product_marketing_email_trial_1_cta_clicked.yml
index 0dd150778fe..87b8a1322d5 100644
--- a/config/metrics/counts_all/20210510203104_in_product_marketing_email_trial_1_cta_clicked.yml
+++ b/config/metrics/counts_all/20210510203104_in_product_marketing_email_trial_1_cta_clicked.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailCtaClickedMetric
+options:
+ track: trial
+ series: 1
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510203114_in_product_marketing_email_trial_2_sent.yml b/config/metrics/counts_all/20210510203114_in_product_marketing_email_trial_2_sent.yml
index 66610ba34f5..0a1c9d7018e 100644
--- a/config/metrics/counts_all/20210510203114_in_product_marketing_email_trial_2_sent.yml
+++ b/config/metrics/counts_all/20210510203114_in_product_marketing_email_trial_2_sent.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailSentMetric
+options:
+ track: trial
+ series: 2
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510203124_in_product_marketing_email_trial_2_cta_clicked.yml b/config/metrics/counts_all/20210510203124_in_product_marketing_email_trial_2_cta_clicked.yml
index e630c81f53c..10d03b730d0 100644
--- a/config/metrics/counts_all/20210510203124_in_product_marketing_email_trial_2_cta_clicked.yml
+++ b/config/metrics/counts_all/20210510203124_in_product_marketing_email_trial_2_cta_clicked.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailCtaClickedMetric
+options:
+ track: trial
+ series: 2
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510203134_in_product_marketing_email_team_0_sent.yml b/config/metrics/counts_all/20210510203134_in_product_marketing_email_team_0_sent.yml
index b8febff5fcd..572547424c7 100644
--- a/config/metrics/counts_all/20210510203134_in_product_marketing_email_team_0_sent.yml
+++ b/config/metrics/counts_all/20210510203134_in_product_marketing_email_team_0_sent.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailSentMetric
+options:
+ track: team
+ series: 0
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510203143_in_product_marketing_email_team_0_cta_clicked.yml b/config/metrics/counts_all/20210510203143_in_product_marketing_email_team_0_cta_clicked.yml
index d90a0f9dbde..aeaced8c4f2 100644
--- a/config/metrics/counts_all/20210510203143_in_product_marketing_email_team_0_cta_clicked.yml
+++ b/config/metrics/counts_all/20210510203143_in_product_marketing_email_team_0_cta_clicked.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailCtaClickedMetric
+options:
+ track: team
+ series: 0
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510203153_in_product_marketing_email_team_1_sent.yml b/config/metrics/counts_all/20210510203153_in_product_marketing_email_team_1_sent.yml
index 84f7d7d28af..3e8fead4c32 100644
--- a/config/metrics/counts_all/20210510203153_in_product_marketing_email_team_1_sent.yml
+++ b/config/metrics/counts_all/20210510203153_in_product_marketing_email_team_1_sent.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailSentMetric
+options:
+ track: team
+ series: 1
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510203203_in_product_marketing_email_team_1_cta_clicked.yml b/config/metrics/counts_all/20210510203203_in_product_marketing_email_team_1_cta_clicked.yml
index 1abe86f5a89..8445229f781 100644
--- a/config/metrics/counts_all/20210510203203_in_product_marketing_email_team_1_cta_clicked.yml
+++ b/config/metrics/counts_all/20210510203203_in_product_marketing_email_team_1_cta_clicked.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailCtaClickedMetric
+options:
+ track: team
+ series: 1
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510203213_in_product_marketing_email_team_2_sent.yml b/config/metrics/counts_all/20210510203213_in_product_marketing_email_team_2_sent.yml
index ba1530445e8..d8f4beb30c1 100644
--- a/config/metrics/counts_all/20210510203213_in_product_marketing_email_team_2_sent.yml
+++ b/config/metrics/counts_all/20210510203213_in_product_marketing_email_team_2_sent.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailSentMetric
+options:
+ track: team
+ series: 2
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210510203223_in_product_marketing_email_team_2_cta_clicked.yml b/config/metrics/counts_all/20210510203223_in_product_marketing_email_team_2_cta_clicked.yml
index f9b473aec6c..b6ff4c4ad85 100644
--- a/config/metrics/counts_all/20210510203223_in_product_marketing_email_team_2_cta_clicked.yml
+++ b/config/metrics/counts_all/20210510203223_in_product_marketing_email_team_2_cta_clicked.yml
@@ -13,6 +13,10 @@ milestone: "13.12"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56752
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailCtaClickedMetric
+options:
+ track: team
+ series: 2
distribution:
- ce
- ee
diff --git a/config/metrics/counts_all/20210727095918_in_product_marketing_email_team_short_0_cta_clicked.yml b/config/metrics/counts_all/20210727095918_in_product_marketing_email_team_short_0_cta_clicked.yml
index 94b3340d1ca..4c8659e9f95 100644
--- a/config/metrics/counts_all/20210727095918_in_product_marketing_email_team_short_0_cta_clicked.yml
+++ b/config/metrics/counts_all/20210727095918_in_product_marketing_email_team_short_0_cta_clicked.yml
@@ -12,6 +12,10 @@ milestone: "14.2"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66854
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailCtaClickedMetric
+options:
+ track: team_short
+ series: 0
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_all/20210727095923_in_product_marketing_email_team_short_0_sent.yml b/config/metrics/counts_all/20210727095923_in_product_marketing_email_team_short_0_sent.yml
index dbcd4faf26f..9f18e78c443 100644
--- a/config/metrics/counts_all/20210727095923_in_product_marketing_email_team_short_0_sent.yml
+++ b/config/metrics/counts_all/20210727095923_in_product_marketing_email_team_short_0_sent.yml
@@ -12,6 +12,10 @@ milestone: "14.2"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66854
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailSentMetric
+options:
+ track: team_short
+ series: 0
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_all/20210727170553_in_product_marketing_email_trial_short_0_cta_clicked.yml b/config/metrics/counts_all/20210727170553_in_product_marketing_email_trial_short_0_cta_clicked.yml
index a23c977240a..57f1fcc6694 100644
--- a/config/metrics/counts_all/20210727170553_in_product_marketing_email_trial_short_0_cta_clicked.yml
+++ b/config/metrics/counts_all/20210727170553_in_product_marketing_email_trial_short_0_cta_clicked.yml
@@ -12,6 +12,10 @@ milestone: "14.2"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66943
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailCtaClickedMetric
+options:
+ track: trial_short
+ series: 0
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_all/20210727170558_in_product_marketing_email_trial_short_0_sent.yml b/config/metrics/counts_all/20210727170558_in_product_marketing_email_trial_short_0_sent.yml
index c24e2f4b6b5..dc18b08081f 100644
--- a/config/metrics/counts_all/20210727170558_in_product_marketing_email_trial_short_0_sent.yml
+++ b/config/metrics/counts_all/20210727170558_in_product_marketing_email_trial_short_0_sent.yml
@@ -12,6 +12,10 @@ milestone: "14.2"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66943
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailSentMetric
+options:
+ track: trial_short
+ series: 0
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_all/20210729140021_in_product_marketing_email_admin_verify_0_cta_clicked.yml b/config/metrics/counts_all/20210729140021_in_product_marketing_email_admin_verify_0_cta_clicked.yml
index 2a62f9a572f..a991d9362d1 100644
--- a/config/metrics/counts_all/20210729140021_in_product_marketing_email_admin_verify_0_cta_clicked.yml
+++ b/config/metrics/counts_all/20210729140021_in_product_marketing_email_admin_verify_0_cta_clicked.yml
@@ -12,6 +12,10 @@ milestone: "14.2"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67147
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailCtaClickedMetric
+options:
+ track: admin_verify
+ series: 0
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_all/20210729140423_in_product_marketing_email_admin_verify_0_sent.yml b/config/metrics/counts_all/20210729140423_in_product_marketing_email_admin_verify_0_sent.yml
index b04c9502a12..0ecf55cc5fc 100644
--- a/config/metrics/counts_all/20210729140423_in_product_marketing_email_admin_verify_0_sent.yml
+++ b/config/metrics/counts_all/20210729140423_in_product_marketing_email_admin_verify_0_sent.yml
@@ -12,6 +12,10 @@ milestone: "14.2"
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/67147
time_frame: all
data_source: database
+instrumentation_class: InProductMarketingEmailSentMetric
+options:
+ track: admin_verify
+ series: 0
data_category: optional
distribution:
- ce
diff --git a/config/metrics/counts_all/20210730011801_projects_zentao_active.yml b/config/metrics/counts_all/20210730011801_projects_zentao_active.yml
index 857e96901a1..2071f97b37e 100644
--- a/config/metrics/counts_all/20210730011801_projects_zentao_active.yml
+++ b/config/metrics/counts_all/20210730011801_projects_zentao_active.yml
@@ -3,7 +3,7 @@ key_path: counts.projects_zentao_active
name: count_all_projects_zentao_active
description: Count of projects with active Zentao integrations
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210730011802_groups_zentao_active.yml b/config/metrics/counts_all/20210730011802_groups_zentao_active.yml
index d0b023c241e..5708b9f678e 100644
--- a/config/metrics/counts_all/20210730011802_groups_zentao_active.yml
+++ b/config/metrics/counts_all/20210730011802_groups_zentao_active.yml
@@ -3,7 +3,7 @@ key_path: counts.groups_zentao_active
name: count_all_groups_zentao_active
description: Count of groups with active Zentao integrations
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210730011804_instances_zentao_active.yml b/config/metrics/counts_all/20210730011804_instances_zentao_active.yml
index 89532a91d52..1fed38ede89 100644
--- a/config/metrics/counts_all/20210730011804_instances_zentao_active.yml
+++ b/config/metrics/counts_all/20210730011804_instances_zentao_active.yml
@@ -3,7 +3,7 @@ key_path: counts.instances_zentao_active
name: count_all_instances_zentao_active
description: Count of instances with active Zentao integrations
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210730011805_projects_inheriting_zentao_active.yml b/config/metrics/counts_all/20210730011805_projects_inheriting_zentao_active.yml
index 054714f5c42..81408dc5e1c 100644
--- a/config/metrics/counts_all/20210730011805_projects_inheriting_zentao_active.yml
+++ b/config/metrics/counts_all/20210730011805_projects_inheriting_zentao_active.yml
@@ -3,7 +3,7 @@ key_path: counts.projects_inheriting_zentao_active
name: count_all_projects_inheriting_zentao_active
description: Count of projects that inherit active Zentao integrations
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210730011806_groups_inheriting_zentao_active.yml b/config/metrics/counts_all/20210730011806_groups_inheriting_zentao_active.yml
index ce6797e5114..55fcd877e8c 100644
--- a/config/metrics/counts_all/20210730011806_groups_inheriting_zentao_active.yml
+++ b/config/metrics/counts_all/20210730011806_groups_inheriting_zentao_active.yml
@@ -3,7 +3,7 @@ key_path: counts.groups_inheriting_zentao_active
name: count_all_groups_inheriting_zentao_active
description: Count of groups that inherit active Zentao integrations
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210916100524_groups_gitlab_slack_application_active.yml b/config/metrics/counts_all/20210916100524_groups_gitlab_slack_application_active.yml
index 5c3fc71f564..b8b238e28fe 100644
--- a/config/metrics/counts_all/20210916100524_groups_gitlab_slack_application_active.yml
+++ b/config/metrics/counts_all/20210916100524_groups_gitlab_slack_application_active.yml
@@ -3,7 +3,7 @@ key_path: counts.groups_gitlab_slack_application_active
name: count_groups_gitlab_slack_application_active
description: Count groups with active slack application
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210916101641_projects_gitlab_slack_application_active.yml b/config/metrics/counts_all/20210916101641_projects_gitlab_slack_application_active.yml
index a3fac680dbf..7e696485c9b 100644
--- a/config/metrics/counts_all/20210916101641_projects_gitlab_slack_application_active.yml
+++ b/config/metrics/counts_all/20210916101641_projects_gitlab_slack_application_active.yml
@@ -3,7 +3,7 @@ key_path: counts.projects_gitlab_slack_application_active
name: count_project_gitlab_slack_application_active
description: Count projects with active slack application
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210916101837_instances_gitlab_slack_application_active.yml b/config/metrics/counts_all/20210916101837_instances_gitlab_slack_application_active.yml
index a4908a2a8e1..3730c21bd59 100644
--- a/config/metrics/counts_all/20210916101837_instances_gitlab_slack_application_active.yml
+++ b/config/metrics/counts_all/20210916101837_instances_gitlab_slack_application_active.yml
@@ -3,7 +3,7 @@ key_path: counts.instances_gitlab_slack_application_active
name: count_instances_gitlab_slack_application_active
description: Count instances with active slack application
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210917040700_groups_inheriting_gitlab_slack_application_active.yml b/config/metrics/counts_all/20210917040700_groups_inheriting_gitlab_slack_application_active.yml
index f5d10688fec..904cf384072 100644
--- a/config/metrics/counts_all/20210917040700_groups_inheriting_gitlab_slack_application_active.yml
+++ b/config/metrics/counts_all/20210917040700_groups_inheriting_gitlab_slack_application_active.yml
@@ -3,7 +3,7 @@ key_path: counts.groups_inheriting_gitlab_slack_application_active
name: count_groups_inheriting_gitlab_slack_application_active
description: Count groups inheriting active slack application
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20210917040956_projects_inheriting_gitlab_slack_application_active.yml b/config/metrics/counts_all/20210917040956_projects_inheriting_gitlab_slack_application_active.yml
index 17bb5b34247..5b4843c2fd0 100644
--- a/config/metrics/counts_all/20210917040956_projects_inheriting_gitlab_slack_application_active.yml
+++ b/config/metrics/counts_all/20210917040956_projects_inheriting_gitlab_slack_application_active.yml
@@ -3,7 +3,7 @@ key_path: counts.projects_inheriting_gitlab_slack_application_active
name: count_project_inheriting_gitlab_slack_application_active
description: Count projects inheriting active slack application
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20211028210001_projects_shimo_active.yml b/config/metrics/counts_all/20211028210001_projects_shimo_active.yml
index 3d7f04a9f82..9256e3114e7 100644
--- a/config/metrics/counts_all/20211028210001_projects_shimo_active.yml
+++ b/config/metrics/counts_all/20211028210001_projects_shimo_active.yml
@@ -3,7 +3,7 @@ key_path: counts.projects_shimo_active
name: count_all_projects_shimo_active
description: Count of projects with active Shimo integrations
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20211028210002_groups_shimo_active.yml b/config/metrics/counts_all/20211028210002_groups_shimo_active.yml
index 641d40aa1fd..215c300a418 100644
--- a/config/metrics/counts_all/20211028210002_groups_shimo_active.yml
+++ b/config/metrics/counts_all/20211028210002_groups_shimo_active.yml
@@ -3,7 +3,7 @@ key_path: counts.groups_shimo_active
name: count_all_groups_shimo_active
description: Count of groups with active Shimo integrations
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20211028210003_instances_shimo_active.yml b/config/metrics/counts_all/20211028210003_instances_shimo_active.yml
index e9b77835ca4..f2d18212671 100644
--- a/config/metrics/counts_all/20211028210003_instances_shimo_active.yml
+++ b/config/metrics/counts_all/20211028210003_instances_shimo_active.yml
@@ -3,7 +3,7 @@ key_path: counts.instances_shimo_active
name: count_all_instances_shimo_active
description: Count of instances with active Shimo integrations
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20211028210004_projects_inheriting_shimo_active.yml b/config/metrics/counts_all/20211028210004_projects_inheriting_shimo_active.yml
index 7693de6b2f2..cb433b10c0e 100644
--- a/config/metrics/counts_all/20211028210004_projects_inheriting_shimo_active.yml
+++ b/config/metrics/counts_all/20211028210004_projects_inheriting_shimo_active.yml
@@ -3,7 +3,7 @@ key_path: counts.projects_inheriting_shimo_active
name: count_all_projects_inheriting_shimo_active
description: Count of projects that inherit active Shimo integrations
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20211028210005_groups_inheriting_shimo_active.yml b/config/metrics/counts_all/20211028210005_groups_inheriting_shimo_active.yml
index b81747fee78..0dc13607603 100644
--- a/config/metrics/counts_all/20211028210005_groups_inheriting_shimo_active.yml
+++ b/config/metrics/counts_all/20211028210005_groups_inheriting_shimo_active.yml
@@ -3,7 +3,7 @@ key_path: counts.groups_inheriting_shimo_active
name: count_all_groups_inheriting_shimo_active
description: Count of groups that inherit active Shimo integrations
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20220315180122_projects_harbor_active.yml b/config/metrics/counts_all/20220315180122_projects_harbor_active.yml
index ff28b7df17f..7e84ebefc86 100644
--- a/config/metrics/counts_all/20220315180122_projects_harbor_active.yml
+++ b/config/metrics/counts_all/20220315180122_projects_harbor_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_harbor_active
description: Count of projects with active integrations for Harbor
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20220315180124_groups_harbor_active.yml b/config/metrics/counts_all/20220315180124_groups_harbor_active.yml
index 79614c925d1..344a07e006d 100644
--- a/config/metrics/counts_all/20220315180124_groups_harbor_active.yml
+++ b/config/metrics/counts_all/20220315180124_groups_harbor_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_harbor_active
description: Count of groups with active integrations for Harbor
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20220315180127_instances_harbor_active.yml b/config/metrics/counts_all/20220315180127_instances_harbor_active.yml
index b865a905c0b..d6f76a1c31a 100644
--- a/config/metrics/counts_all/20220315180127_instances_harbor_active.yml
+++ b/config/metrics/counts_all/20220315180127_instances_harbor_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_harbor_active
description: Count of active instance-level integrations for Harbor
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20220315180129_projects_inheriting_harbor_active.yml b/config/metrics/counts_all/20220315180129_projects_inheriting_harbor_active.yml
index 375f3b9a0b3..d3c6e214eb8 100644
--- a/config/metrics/counts_all/20220315180129_projects_inheriting_harbor_active.yml
+++ b/config/metrics/counts_all/20220315180129_projects_inheriting_harbor_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_harbor_active
description: Count of active projects inheriting integrations for Harbor
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20220315180131_groups_inheriting_harbor_active.yml b/config/metrics/counts_all/20220315180131_groups_inheriting_harbor_active.yml
index 6e216121414..c61c58da4c9 100644
--- a/config/metrics/counts_all/20220315180131_groups_inheriting_harbor_active.yml
+++ b/config/metrics/counts_all/20220315180131_groups_inheriting_harbor_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_harbor_active
description: Count of active groups inheriting integrations for Harbor
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20220802141715_groups_inheriting_pumble_active.yml b/config/metrics/counts_all/20220802141715_groups_inheriting_pumble_active.yml
index 960f859b07f..07a630424df 100644
--- a/config/metrics/counts_all/20220802141715_groups_inheriting_pumble_active.yml
+++ b/config/metrics/counts_all/20220802141715_groups_inheriting_pumble_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_inheriting_pumble_active
description: Count of active groups inheriting integrations for Pumble
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20220802141715_groups_pumble_active.yml b/config/metrics/counts_all/20220802141715_groups_pumble_active.yml
index 3a62a002f10..2d79df7b275 100644
--- a/config/metrics/counts_all/20220802141715_groups_pumble_active.yml
+++ b/config/metrics/counts_all/20220802141715_groups_pumble_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.groups_pumble_active
description: Count of groups with active integrations for Pumble
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20220802141715_instances_pumble_active.yml b/config/metrics/counts_all/20220802141715_instances_pumble_active.yml
index d313ee39b31..457e6d7e861 100644
--- a/config/metrics/counts_all/20220802141715_instances_pumble_active.yml
+++ b/config/metrics/counts_all/20220802141715_instances_pumble_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.instances_pumble_active
description: Count of active instance-level integrations for Pumble
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20220802141715_projects_inheriting_pumble_active.yml b/config/metrics/counts_all/20220802141715_projects_inheriting_pumble_active.yml
index ae928de6140..560593744d1 100644
--- a/config/metrics/counts_all/20220802141715_projects_inheriting_pumble_active.yml
+++ b/config/metrics/counts_all/20220802141715_projects_inheriting_pumble_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_inheriting_pumble_active
description: Count of active projects inheriting integrations for Pumble
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20220802141715_projects_pumble_active.yml b/config/metrics/counts_all/20220802141715_projects_pumble_active.yml
index 5f352a1cae4..182a76e98f8 100644
--- a/config/metrics/counts_all/20220802141715_projects_pumble_active.yml
+++ b/config/metrics/counts_all/20220802141715_projects_pumble_active.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: counts.projects_pumble_active
description: Count of projects with active integrations for Pumble
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20220906074055_package_events_i_package_rpm_pull_package.yml b/config/metrics/counts_all/20220906074055_package_events_i_package_rpm_pull_package.yml
new file mode 100644
index 00000000000..e45b9092147
--- /dev/null
+++ b/config/metrics/counts_all/20220906074055_package_events_i_package_rpm_pull_package.yml
@@ -0,0 +1,25 @@
+---
+data_category: optional
+key_path: counts.package_events_i_package_rpm_pull_package
+description: A count of RPM packages that have been downloaded
+product_section: ops
+product_stage: package
+product_group: package
+product_category: package_registry
+value_type: number
+status: active
+milestone: '15.6'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97133
+time_frame: all
+data_source: redis
+instrumentation_class: RedisMetric
+options:
+ prefix: package_events
+ event: i_package_rpm_pull_package
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20220906074525_package_events_i_package_rpm_push_package.yml b/config/metrics/counts_all/20220906074525_package_events_i_package_rpm_push_package.yml
new file mode 100644
index 00000000000..f41f98d5052
--- /dev/null
+++ b/config/metrics/counts_all/20220906074525_package_events_i_package_rpm_push_package.yml
@@ -0,0 +1,25 @@
+---
+data_category: optional
+key_path: counts.package_events_i_package_rpm_push_package
+description: A count of RPM packages that have been published
+product_section: ops
+product_stage: package
+product_group: package
+product_category: package_registry
+value_type: number
+status: active
+milestone: '15.6'
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97133
+time_frame: all
+data_source: redis
+instrumentation_class: RedisMetric
+options:
+ prefix: package_events
+ event: i_package_rpm_push_package
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20220912145754_gitlab_for_jira_app_direct_installations.yml b/config/metrics/counts_all/20220912145754_gitlab_for_jira_app_direct_installations.yml
index a538e097254..a89ceecbe0e 100644
--- a/config/metrics/counts_all/20220912145754_gitlab_for_jira_app_direct_installations.yml
+++ b/config/metrics/counts_all/20220912145754_gitlab_for_jira_app_direct_installations.yml
@@ -2,7 +2,7 @@
key_path: counts.gitlab_for_jira_app_direct_installations
description: Count active Jira Cloud direct installations
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/counts_all/20220913083454_gitlab_for_jira_app_proxy_installations.yml b/config/metrics/counts_all/20220913083454_gitlab_for_jira_app_proxy_installations.yml
index fcab9fd1794..6b05ad8c250 100644
--- a/config/metrics/counts_all/20220913083454_gitlab_for_jira_app_proxy_installations.yml
+++ b/config/metrics/counts_all/20220913083454_gitlab_for_jira_app_proxy_installations.yml
@@ -2,7 +2,7 @@
key_path: counts.gitlab_for_jira_app_proxy_installations
description: Count active Jira Cloud installations that are using GitLab as a proxy
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: number
diff --git a/config/metrics/settings/20210204124908_mattermost_enabled.yml b/config/metrics/settings/20210204124908_mattermost_enabled.yml
index c269fe6edd4..fb4608c12c5 100644
--- a/config/metrics/settings/20210204124908_mattermost_enabled.yml
+++ b/config/metrics/settings/20210204124908_mattermost_enabled.yml
@@ -3,7 +3,7 @@ data_category: optional
key_path: mattermost_enabled
description: Whether Mattermost is enabled
product_section: dev
-product_stage: ecosystem
+product_stage: manage
product_group: integrations
product_category: integrations
value_type: boolean
diff --git a/config/metrics/settings/20221015152126_deactivate_dormant_users_enabled.yml b/config/metrics/settings/20221015152126_deactivate_dormant_users_enabled.yml
new file mode 100644
index 00000000000..0f77cde4014
--- /dev/null
+++ b/config/metrics/settings/20221015152126_deactivate_dormant_users_enabled.yml
@@ -0,0 +1,23 @@
+---
+key_path: deactivate_dormant_users_enabled
+description: Whether Dormant User Deactivation is enabled
+product_section: fulfillment
+product_stage: fulfillment
+product_group: utilization
+product_category: subscription_cost_management
+value_type: boolean
+status: active
+milestone: "15.6"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101125
+time_frame: none
+data_source: database
+data_category: optional
+instrumentation_class: DormantUserSettingEnabledMetric
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/settings/20221015161233_deactivate_dormant_users_period.yml b/config/metrics/settings/20221015161233_deactivate_dormant_users_period.yml
new file mode 100644
index 00000000000..6cd7e0f0da7
--- /dev/null
+++ b/config/metrics/settings/20221015161233_deactivate_dormant_users_period.yml
@@ -0,0 +1,23 @@
+---
+key_path: deactivate_dormant_users_period
+description: The value of the dormant users period being used
+product_section: fulfillment
+product_stage: fulfillment
+product_group: utilization
+product_category: subscription_cost_management
+value_type: boolean
+status: active
+milestone: "15.6"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101125
+time_frame: none
+data_source: database
+data_category: optional
+instrumentation_class: DormantUserPeriodSettingMetric
+performance_indicator_type: []
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/open_api.yml b/config/open_api.yml
index 8415a6bff3d..6e767f51ef8 100644
--- a/config/open_api.yml
+++ b/config/open_api.yml
@@ -14,5 +14,98 @@ metadata:
name: private_token
in: query
tags:
+ # Keep in alphabetical order
+ - name: access_requests
+ description: Operations related to access requests
+ - name: ci_lint
+ description: Operations related to linting a CI config file
+ - name: ci_resource_groups
+ description: Operations to manage job concurrency with resource groups
+ - name: ci_variables
+ description: Operations related to CI/CD variables
+ - name: cluster_agents
+ description: Operations related to the GitLab agent for Kubernetes
+ - name: clusters
+ description: Operations related to clusters
+ - name: container_registry
+ description: Operations related to container registry
+ - name: dashboard_annotations
+ description: Operations related to dashboard annotations
+ - name: dependency_proxy
+ description: Operations to manage dependency proxy for a groups
+ - name: deploy_keys
+ description: Operations related to deploy keys
+ - name: deploy_tokens
+ description: Operations related to deploy tokens
+ - name: deployments
+ description: Operations related to deployments
+ - name: dora_metrics
+ description: Operations related to DevOps Research and Assessment (DORA) key metrics
+ - name: environments
+ description: Operations related to environments
+ - name: error_tracking_client_keys
+ description: Operations related to error tracking client keys
+ - name: error_tracking_project_settings
+ description: Operations related to error tracking project settings
+ - name: feature_flags_user_lists
+ description: Operations related to accessing GitLab feature flag user lists
+ - name: feature_flags
+ description: Operations related to feature flags
+ - name: features
+ description: Operations related to managing Flipper-based feature flags
+ - name: freeze_periods
+ description: Operations related to deploy freeze periods
+ - name: geo
+ description: Operations related to Geo
+ - name: geo_nodes
+ description: Operations related Geo Nodes
+ - name: go_proxy
+ description: Operations related to Go Proxy
+ - name: group_export
+ description: Operations related to exporting groups
+ - name: group_import
+ description: Operations related to importing groups
+ - name: group_packages
+ description: Operations related to group packages
+ - name: integrations
+ description: Operations related to integrations
+ - name: issue_links
+ description: Operations related to issue links
+ - name: merge_requests
+ description: Operations related to merge requests
- name: metadata
description: Operations related to metadata of the GitLab instance
+ - name: metrics_user_starred_dashboards
+ description: Operations related to User-starred metrics dashboards
+ - name: package_files
+ description: Operations about package files
+ - name: plan_limits
+ description: Operations related to plan limits
+ - name: project_export
+ description: Operations related to exporting projects
+ - name: project_hooks
+ description: Operations related to project hooks
+ - name: project_import
+ description: Operations related to importing projects
+ - name: project_import_bitbucket
+ description: Operations related to importing BitBucket projects
+ - name: project_import_github
+ description: Operations related to importing GitHub projects
+ - name: protected environments
+ description: Operations related to protected environments
+ - name: release_links
+ description: Operations related to release assets (links)
+ - name: releases
+ description: Operations related to releases
+ - name: resource_milestone_events
+ description: Operations about resource milestone events
+ - name: suggestions
+ description: Operations related to suggestions
+ - name: system_hooks
+ description: Operations related to system hooks
+ - name: terraform_state
+ description: Operations related to Terraform state files
+ - name: terraform_registry
+ description: Operations related to the Terraform module registry
+ - name: unleash_api
+ description: Operations related to Unleash API
diff --git a/config/puma.example.development.rb b/config/puma.example.development.rb
index 3164ffe3ef4..71a4e9b36f1 100644
--- a/config/puma.example.development.rb
+++ b/config/puma.example.development.rb
@@ -67,6 +67,11 @@ on_worker_boot do
Gitlab::Cluster::LifecycleEvents.do_worker_start
end
+on_worker_shutdown do
+ # Signal application hooks that a worker is shutting down
+ Gitlab::Cluster::LifecycleEvents.do_worker_stop
+end
+
# Preload the application before starting the workers; this conflicts with
# phased restart feature. (off by default)
diff --git a/config/puma.rb.example b/config/puma.rb.example
index c70baf6570e..59844b4aecf 100644
--- a/config/puma.rb.example
+++ b/config/puma.rb.example
@@ -57,6 +57,11 @@ on_worker_boot do
Gitlab::Cluster::LifecycleEvents.do_worker_start
end
+on_worker_shutdown do
+ # Signal application hooks that a worker is shutting down
+ Gitlab::Cluster::LifecycleEvents.do_worker_stop
+end
+
# Preload the application before starting the workers; this conflicts with
# phased restart feature. (off by default)
preload_app!
diff --git a/config/routes.rb b/config/routes.rb
index 6cfbb969acb..27313854233 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -2,7 +2,6 @@
require 'sidekiq/web'
require 'sidekiq/cron/web'
-require 'product_analytics/collector_app'
InitializerConnections.with_disabled_database_connections do
Rails.application.routes.draw do
@@ -56,7 +55,9 @@ InitializerConnections.with_disabled_database_connections do
match '/oauth/token' => 'oauth/tokens#create', via: :options
match '/oauth/revoke' => 'oauth/tokens#revoke', via: :options
- match '/-/jira_connect/oauth_application_id' => 'jira_connect/oauth_application_ids#show', via: :options
+ match '/-/jira_connect/oauth_application_id' => 'jira_connect/cors_preflight_checks#index', via: :options
+ match '/-/jira_connect/subscriptions/:id' => 'jira_connect/cors_preflight_checks#index', via: :options
+ match '/-/jira_connect/installations' => 'jira_connect/cors_preflight_checks#index', via: :options
# Sign up
scope path: '/users/sign_up', module: :registrations, as: :users_sign_up do
@@ -217,9 +218,6 @@ InitializerConnections.with_disabled_database_connections do
# Deprecated route for permanent failures
# https://gitlab.com/gitlab-org/gitlab/-/issues/362606
post '/members/mailgun/permanent_failures' => 'mailgun/webhooks#process_webhook'
-
- # Product analytics collector
- match '/collector/i', to: ProductAnalytics::CollectorApp.new, via: :all
end
# End of the /-/ scope.
diff --git a/config/routes/group.rb b/config/routes/group.rb
index 4a47b349665..a715596580d 100644
--- a/config/routes/group.rb
+++ b/config/routes/group.rb
@@ -121,7 +121,11 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
resource :dependency_proxy, only: [:show, :update]
resources :email_campaigns, only: :index
- resources :observability, only: :index
+ namespace :observability do
+ get 'dashboards'
+ get 'explore'
+ get 'manage'
+ end
namespace :harbor do
resources :repositories, only: [:index, :show], constraints: { id: %r{[a-zA-Z./:0-9_\-]+} } do
diff --git a/config/routes/project.rb b/config/routes/project.rb
index 0b0d370223c..5a85a029607 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -142,7 +142,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
- resource :repository, only: [:show], controller: :repository do
+ resource :repository, only: [:show, :update], controller: :repository do
# TODO: Removed this "create_deploy_token" route after change was made in app/helpers/ci_variables_helper.rb:14
# See MR comment for more detail: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/27059#note_311585356
post :create_deploy_token, path: 'deploy_token/create'
@@ -353,7 +353,9 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
resources :alert_management, only: [:index] do
- get 'details', on: :member
+ member do
+ get 'details(/*page)', to: 'alert_management#details', as: 'details'
+ end
end
get 'alert_management/:id', to: 'alert_management#details', as: 'alert_management_alert'
@@ -379,14 +381,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
resources :projects, only: :index
end
- resources :product_analytics, only: [:index] do
- collection do
- get :setup
- get :test
- get :graphs
- end
- end
-
resources :error_tracking, only: [:index], controller: :error_tracking do
collection do
get ':issue_id/details',
@@ -478,6 +472,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
end
+
+ namespace :ml do
+ resources :experiments, only: [:index, :show], controller: 'experiments'
+ end
end
# End of the /-/ scope.
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index eff83e3f3c4..4ed4dca8912 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -109,6 +109,8 @@
- 1
- - container_repository
- 1
+- - container_repository_delete
+ - 1
- - create_commit_signature
- 2
- - create_github_webhook
@@ -257,6 +259,8 @@
- 1
- - integrations_slack_event
- 1
+- - integrations_slack_interactivity
+ - 1
- - invalid_gpg_signature_update
- 2
- - issuable_export_csv
@@ -297,6 +301,8 @@
- 1
- - merge_requests_create_approval_note
- 1
+- - merge_requests_delete_branch
+ - 1
- - merge_requests_delete_source_branch
- 1
- - merge_requests_execute_approval_hooks
diff --git a/danger/architecture/Dangerfile b/danger/architecture/Dangerfile
new file mode 100644
index 00000000000..148180247fe
--- /dev/null
+++ b/danger/architecture/Dangerfile
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+BLUEPRINT_LABEL = 'Architecture Evolution Blueprint'
+
+return unless helper.ci?
+
+blueprint_changes = helper.changed_files(%r{^doc/architecture/blueprints/.*})
+
+BLUEPRINT_SHORT_MESSAGE = <<~MSG
+This merge request requires a review from an [Architecture Evolution Coach](https://about.gitlab.com/handbook/engineering/architecture/workflow/).
+MSG
+
+BLUEPRINT_LONG_MESSAGE = <<~MSG
+## Architecture Evolution Review
+
+#{BLUEPRINT_SHORT_MESSAGE}
+
+Following files, that may require the additional review, have been changed:
+#{helper.markdown_list(blueprint_changes.to_set)}
+MSG
+
+if blueprint_changes.any?
+ message(BLUEPRINT_SHORT_MESSAGE)
+ markdown(BLUEPRINT_LONG_MESSAGE)
+
+ helper.labels_to_add.push(BLUEPRINT_LABEL) unless helper.mr_has_labels?(BLUEPRINT_LABEL)
+end
diff --git a/danger/documentation/Dangerfile b/danger/documentation/Dangerfile
index eaa1839c8e5..1e94af391c8 100644
--- a/danger/documentation/Dangerfile
+++ b/danger/documentation/Dangerfile
@@ -4,6 +4,10 @@ def feature_mr?
(helper.mr_labels & %w[feature::addition feature::enhancement]).any?
end
+def doc_path_to_url(path)
+ path.sub("doc/", "https://docs.gitlab.com/ee/").sub("index.md", "").sub(".md", "/")
+end
+
DOCUMENTATION_UPDATE_MISSING = <<~MSG
~"feature::addition" and ~"feature::enhancement" merge requests normally have a documentation change. Consider adding a documentation update or confirming the documentation plan with the [Technical Writer counterpart](https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments).
@@ -31,7 +35,7 @@ markdown(<<~MARKDOWN)
The following files require a review from a technical writer:
- * #{docs_paths_to_review.map { |path| "`#{path}`" }.join("\n* ")}
+ * #{docs_paths_to_review.map { |path| "`#{path}` ([Link to current live version](#{doc_path_to_url(path)}))" }.join("\n* ")}
The review does not need to block merging this merge request. See the:
diff --git a/danger/pajamas/Dangerfile b/danger/pajamas/Dangerfile
index fde12c08b35..5fe9e9e8b19 100644
--- a/danger/pajamas/Dangerfile
+++ b/danger/pajamas/Dangerfile
@@ -20,8 +20,6 @@ PATTERNS = %w[
<tabs
bs-callout
deprecated-modal
- has-tooltip
- has_tooltip
initDeprecatedJQueryDropdown
loading-button
v-popover
diff --git a/danger/pipeline/Dangerfile b/danger/pipeline/Dangerfile
index 861d031915e..2fffd94be2e 100644
--- a/danger/pipeline/Dangerfile
+++ b/danger/pipeline/Dangerfile
@@ -6,7 +6,7 @@ MESSAGE = <<~MESSAGE
This merge request contains changes to the pipeline configuration for the GitLab project.
Please consider the effect of the changes in this merge request on the following:
-- Effects on different [pipeline types](https://docs.gitlab.com/ee/development/pipelines.html#pipelines-for-merge-requests)
+- Effects on different [pipeline types](https://docs.gitlab.com/ee/development/pipelines/index.html#pipelines-types-for-merge-requests)
- Effects on non-canonical projects:
- `gitlab-foss`
- `security`
diff --git a/danger/rubygems/Dangerfile b/danger/rubygems/Dangerfile
new file mode 100644
index 00000000000..8e404d88fc1
--- /dev/null
+++ b/danger/rubygems/Dangerfile
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+all_changed_files = helper.all_changed_files
+
+if all_changed_files.detect { |file| file == 'Gemfile' || file == 'Gemfile.lock' }
+ markdown <<~MSG
+ ## Rubygems
+
+ This merge request adds, or changes a Rubygems dependency. Please review the [Gemfile guidelines](https://docs.gitlab.com/ee/development/gemfile.html).
+ MSG
+end
diff --git a/data/deprecations/14-3-serverless.yml b/data/deprecations/14-3-serverless.yml
index aac3cc9cd6a..08a54046f4a 100644
--- a/data/deprecations/14-3-serverless.yml
+++ b/data/deprecations/14-3-serverless.yml
@@ -5,10 +5,10 @@
removal_date: "2022-05-22"
breaking_change: true
body: |
- [GitLab Serverless](https://docs.gitlab.com/ee/user/project/clusters/serverless/) is a feature set to support Knative-based serverless development with automatic deployments and monitoring.
+ GitLab Serverless is a feature set to support Knative-based serverless development with automatic deployments and monitoring.
We decided to remove the GitLab Serverless features as they never really resonated with our users. Besides, given the continuous development of Kubernetes and Knative, our current implementations do not even work with recent versions.
stage: Configure
tiers: [Core, Premium, Ultimate]
issue_url: "https://gitlab.com/groups/gitlab-org/configure/-/epics/6"
- documentation_url: "https://docs.gitlab.com/ee/user/project/clusters/serverless/"
+ documentation_url: "https://gitlab.com/groups/gitlab-org/configure/-/epics/6"
diff --git a/data/deprecations/14-7-deprecate-merged_by-api-field.yml b/data/deprecations/14-7-deprecate-merged_by-api-field.yml
index 0a84b118981..561f3d5360e 100644
--- a/data/deprecations/14-7-deprecate-merged_by-api-field.yml
+++ b/data/deprecations/14-7-deprecate-merged_by-api-field.yml
@@ -13,11 +13,11 @@
- name: "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.
announcement_date: "2022-01-22" # 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.0" # The milestone when this feature is planned to be removed
- removal_date: "2022-05-22" # the date of the milestone release when this feature is planned to be removed
+ removal_milestone: "16.0" # The milestone when this feature is planned to be removed
+ removal_date: "2023-05-22" # the date of the milestone release 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) is being deprecated and will be removed in GitLab 15.0. This field is being replaced with the `merge_user` field (already present in GraphQL) 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.
+ 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]
diff --git a/data/deprecations/14-7-deprecate-static-site-editor.yml b/data/deprecations/14-7-deprecate-static-site-editor.yml
index 0960bffe4cf..7d1d324c0ca 100644
--- a/data/deprecations/14-7-deprecate-static-site-editor.yml
+++ b/data/deprecations/14-7-deprecate-static-site-editor.yml
@@ -6,11 +6,11 @@
body: | # Do not modify this line, instead modify the lines below.
The Static Site Editor will no longer be available starting in GitLab 15.0. Improvements to the Markdown editing experience across GitLab will deliver smiliar benefit but with a wider reach. Incoming requests to the Static Site Editor will be redirected to the [Web IDE](https://docs.gitlab.com/ee/user/project/web_ide/index.html).
- Current users of the Static Site Editor can view the [documentation](https://docs.gitlab.com/ee/user/project/static_site_editor/) for more information, including how to remove the configuration files from existing projects.
+ Current users of the Static Site Editor can view the [documentation](https://docs.gitlab.com/ee/user/project/web_ide/index.html) for more information, including how to remove the configuration files from existing projects.
# 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: [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]
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/347137 # (optional) This is a link to the deprecation issue in GitLab
- documentation_url: https://docs.gitlab.com/ee/user/project/static_site_editor/ # (optional) This is a link to the current documentation page
+ documentation_url: https://docs.gitlab.com/ee/user/project/web_ide/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/14-8-Elasticsearch-6-8.yml b/data/deprecations/14-8-Elasticsearch-6-8.yml
index 28a25803d41..e52e237ffbc 100644
--- a/data/deprecations/14-8-Elasticsearch-6-8.yml
+++ b/data/deprecations/14-8-Elasticsearch-6-8.yml
@@ -14,4 +14,4 @@
stage: Enablement
tiers: [Premium, Ultimate]
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/350275
- documentation_url: https://docs.gitlab.com/ee/integration/elasticsearch.html#version-requirements
+ documentation_url: https://docs.gitlab.com/ee/integration/advanced_search/elasticsearch.html#version-requirements
diff --git a/data/deprecations/14-8-graphql-ids.yml b/data/deprecations/14-8-graphql-ids.yml
index cd830a313b1..899ff323792 100644
--- a/data/deprecations/14-8-graphql-ids.yml
+++ b/data/deprecations/14-8-graphql-ids.yml
@@ -58,7 +58,7 @@
to one of the other two forms (using the correct appropriate type in the signature, or using
an inline argument expression).
# The following items are not published on the docs page, but may be used in the future.
- stage: ecosystem
+ stage: Manage
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/257883'
documentation_url: # (optional) This is a link to the current documentation page
diff --git a/data/deprecations/14-8-request-profiling.yml b/data/deprecations/14-8-request-profiling.yml
index ea3833d98ef..e6c20abf2b1 100644
--- a/data/deprecations/14-8-request-profiling.yml
+++ b/data/deprecations/14-8-request-profiling.yml
@@ -6,7 +6,7 @@
breaking_change: true
reporter: iroussos
body: | # Do not modify this line, instead modify the lines below.
- [Request profiling](https://docs.gitlab.com/ee/administration/monitoring/performance/request_profiling.html) is deprecated in GitLab 14.8 and scheduled for removal in GitLab 15.0.
+ [Request profiling](https://docs.gitlab.com/ee/administration/monitoring/performance/index.html) is deprecated in GitLab 14.8 and scheduled for removal in GitLab 15.0.
We're working on [consolidating our profiling tools](https://gitlab.com/groups/gitlab-org/-/epics/7327) and making them more easily accessible.
We [evaluated](https://gitlab.com/gitlab-org/gitlab/-/issues/350152) the use of this feature and we found that it is not widely used.
@@ -16,4 +16,4 @@
stage: Monitor
tiers: [Free, Premium, Ultimate]
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/352488
- documentation_url: https://docs.gitlab.com/ee/administration/monitoring/performance/request_profiling.html
+ documentation_url: https://docs.gitlab.com/ee/administration/monitoring/performance/index.html
diff --git a/data/deprecations/14-8-sast-analyzer-removals.yml b/data/deprecations/14-8-sast-analyzer-removals.yml
index 85d1533b762..4c4675be808 100644
--- a/data/deprecations/14-8-sast-analyzer-removals.yml
+++ b/data/deprecations/14-8-sast-analyzer-removals.yml
@@ -18,10 +18,12 @@
- [Bandit](https://gitlab.com/gitlab-org/security-products/analyzers/bandit) (Python)
NOTE:
- This change was originally planned for GitLab 15.0 and has been postponed.
+ This change was originally planned for GitLab 15.0 and was postponed to GitLab 15.4.
+ See [the removal notice](./removals.md#sast-analyzer-consolidation-and-cicd-template-changes) for further details.
These analyzers will be removed from the [GitLab-managed SAST CI/CD template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml) and replaced with the [Semgrep-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep).
- They will no longer receive routine updates, except for security issues.
+ Effective immediately, they will receive only security updates; other routine improvements or updates are not guaranteed.
+ After these analyzers reach End of Support, no further updates will be provided.
We will not delete container images previously published for these analyzers; any such change would be announced as a [deprecation, removal, or breaking change announcement](https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations-removals-and-breaking-changes).
We will also remove Java from the scope of the [SpotBugs](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) analyzer and replace it with the [Semgrep-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep).
diff --git a/data/deprecations/15-1-jira-github-enterprise-dvcs.yml b/data/deprecations/15-1-jira-github-enterprise-dvcs.yml
index ac8b630c1ff..d35d06e006c 100644
--- a/data/deprecations/15-1-jira-github-enterprise-dvcs.yml
+++ b/data/deprecations/15-1-jira-github-enterprise-dvcs.yml
@@ -8,7 +8,7 @@
The [Jira DVCS Connector](https://docs.gitlab.com/ee/integration/jira/dvcs.html) (which enables the [Jira Development Panel](https://support.atlassian.com/jira-software-cloud/docs/view-development-information-for-an-issue/)), will no longer support Jira Cloud users starting with GitLab 16.0. The [GitLab for Jira App](https://docs.gitlab.com/ee/integration/jira/connect-app.html) has always been recommended for Jira Cloud users, and it will be required instead of the DVCS connector. If you are a Jira Cloud user, we recommended you begin migrating to the GitLab for Jira App.
Any Jira Server and Jira Data Center users will need to confirm they are not using the GitHub Enterprise Connector to enable the GitLab DVCS integration, but they may continue to use the [native GitLab DVCS integration](https://docs.gitlab.com/ee/integration/jira/dvcs.html) (supported in Jira 8.14 and later).
# The following items are not published on the docs page, but may be used in the future.
- stage: Ecosystem # (optional - may be required in the future) String value of the stage that the feature was created in. e.g., Growth
+ stage: Manage # (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/groups/gitlab-org/-/epics/7508 # (optional) This is a link to the deprecation issue in GitLab
documentation_url: https://docs.gitlab.com/ee/integration/jira/dvcs.html # (optional) This is a link to the current documentation page
diff --git a/data/deprecations/15-2-job_age-deprecation.yml b/data/deprecations/15-2-job_age-deprecation.yml
index 889c8651bbe..b395c97447c 100644
--- a/data/deprecations/15-2-job_age-deprecation.yml
+++ b/data/deprecations/15-2-job_age-deprecation.yml
@@ -24,7 +24,7 @@
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) If this deprecation is a breaking change, set this value to true
reporter: jheimbuck_gl # (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
+ 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/334253 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
The `job_age` parameter, returned from the `POST /jobs/request` API endpoint used in communication with GitLab Runner, was never used by any GitLab or Runner feature. This parameter will be removed in GitLab 16.0.
diff --git a/data/deprecations/15-3-deprecate-redis-5.yml b/data/deprecations/15-3-deprecate-redis-5.yml
index f0e350cc62b..d61b1a1c475 100644
--- a/data/deprecations/15-3-deprecate-redis-5.yml
+++ b/data/deprecations/15-3-deprecate-redis-5.yml
@@ -2,7 +2,7 @@
announcement_milestone: "15.3" # (required) The milestone when this feature was first announced as deprecated.
announcement_date: "2022-08-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) If this deprecation is a breaking change, set this value to true
reporter: tnir
stage: Enablement
diff --git a/data/deprecations/15-4-create-deprecation-draft-quick-action-toggle.yml b/data/deprecations/15-4-create-deprecation-draft-quick-action-toggle.yml
index 2265354c4c7..5d4fb1b5b66 100644
--- a/data/deprecations/15-4-create-deprecation-draft-quick-action-toggle.yml
+++ b/data/deprecations/15-4-create-deprecation-draft-quick-action-toggle.yml
@@ -2,11 +2,11 @@
announcement_milestone: "15.4" # (required) The milestone when this feature was first announced as deprecated.
announcement_date: "2022-09-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: "2022-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: "2022-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) If this deprecation is a breaking change, set this value to true
reporter: phikai # (required) GitLab username of the person reporting the deprecation
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/365365 # (required) Link to the deprecation issue in GitLab
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/365365 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
In order to make the behavior of toggling the draft status of a merge request more clear via a quick action, we're deprecating and removing the toggle behavior of the `/draft` quick action. Beginning with the 16.0 release of GitLab, `/draft` will only set a merge request to Draft and a new `/ready` quick action will be used to remove the draft status.
- documentation_url: # (optional) This is a link to the current documentation page
+ documentation_url: # (optional) This is a link to the current documentation page
diff --git a/data/deprecations/15-5-disable-file-type-var-expansion-ci-pipeline.yml b/data/deprecations/15-5-disable-file-type-var-expansion-ci-pipeline.yml
new file mode 100644
index 00000000000..31b0d9c2dbc
--- /dev/null
+++ b/data/deprecations/15-5-disable-file-type-var-expansion-ci-pipeline.yml
@@ -0,0 +1,13 @@
+- name: "File Type variable expansion in `.gitlab-ci.yml`" # (required) The name of the feature to be deprecated
+ announcement_milestone: "15.5" # (required) The milestone when this feature was first announced as deprecated.
+ announcement_date: "2022-10-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.7" # (required) The milestone when this feature is planned to be removed
+ removal_date: # (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) 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/29407 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ Previously, variables that referenced or applied alias file variables expanded the value of the `File` type variable. For example, the file contents. This behavior was incorrect because it did not comply with typical shell variable expansion rules. To leak secrets or sensitive information stored in `File` type variables, a user could run an $echo command with the variable as an input parameter.
+
+ This breaking change fixes this issue but could disrupt user workflows that work around the behavior. With this change, job variable expansions that reference or apply alias file variables, expand to the file name or path of the `File` type variable, instead of its value, such as the file contents.
diff --git a/data/deprecations/15-6-deprecate-config-fields-runner-helm-chart.yml b/data/deprecations/15-6-deprecate-config-fields-runner-helm-chart.yml
new file mode 100644
index 00000000000..3d8d946027f
--- /dev/null
+++ b/data/deprecations/15-6-deprecate-config-fields-runner-helm-chart.yml
@@ -0,0 +1,13 @@
+- name: "Configuration fields in 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.
+ announcement_date: "2022-11-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.
+ 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/379064 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ From GitLab 13.6, users can [specify any runner configuration in the GitLab Runner Helm chart](https://docs.gitlab.com/runner/install/kubernetes.html). When we implemented this feature, we deprecated values in the GitLab Helm Chart configuration that were specific to GitLab Runner. These fields are deprecated and we plan to remove them in v1.0 of the GitLab Runner Helm chart.
+ end_of_support_milestone: "16.0" # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
+ end_of_support_date: "2023-05-22" # (optional) The date of the milestone release when support for this feature will end.
diff --git a/data/deprecations/15-6-deprecate-merge_status-api-field.yml b/data/deprecations/15-6-deprecate-merge_status-api-field.yml
new file mode 100644
index 00000000000..55a7cce0b6c
--- /dev/null
+++ b/data/deprecations/15-6-deprecate-merge_status-api-field.yml
@@ -0,0 +1,15 @@
+- name: "merge_status API field" # The name of the feature to be deprecated
+ announcement_milestone: "15.6" # The milestone when this feature was first announced as deprecated.
+ announcement_date: "2022-11-22" # 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" # The milestone when this feature is planned to be removed
+ removal_date: "2023-05-22" # the date of the milestone release 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 `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.
+# 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/382032 # (optional) This is a link to the deprecation issue in GitLab
+ documentation_url: https://docs.gitlab.com/ee/api/merge_requests.html#merge-status # (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-post-api-v4-runner.yml b/data/deprecations/15-6-deprecate-post-api-v4-runner.yml
new file mode 100644
index 00000000000..9e308fbecce
--- /dev/null
+++ b/data/deprecations/15-6-deprecate-post-api-v4-runner.yml
@@ -0,0 +1,24 @@
+- name: "`POST /api/v4/runners` method to register runners" # (required) The name of the feature to be deprecated
+ announcement_milestone: "15.6" # (required) The milestone when this feature was first announced as deprecated.
+ announcement_date: "2022-11-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.
+ 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/379743 # (required) Link to the deprecation issue in GitLab
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ The `POST` method operation on the `/api/v4/runners` endpoint is deprecated.
+ This endpoint and method [registers](https://docs.gitlab.com/ee/api/runners.html#register-a-new-runner) a runner
+ with a GitLab instance at the instance, group, or project level through the API. We plan to remove this endpoint
+ and method in GitLab 16.0.
+
+ In GitLab 15.8, 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/).
+ 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 16.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.0" # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
+ end_of_support_date: "2023-05-22" # (optional) The date of the milestone release 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
new file mode 100644
index 00000000000..330f1b1f39e
--- /dev/null
+++ b/data/deprecations/15-6-deprecate-runner-reg-token-helm.yml
@@ -0,0 +1,19 @@
+- name: "`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.
+ announcement_date: "2022-11-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.
+ 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/381111 # (required) Link to the deprecation issue in GitLab
+ 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.
+ - A unique system ID saved to the `config.toml`, which will ensure traceability between jobs and runners.
+ From GitLab 16.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.0" # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
+ end_of_support_date: "2023-05-22" # (optional) The date of the milestone release 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
new file mode 100644
index 00000000000..b20bc4bbeec
--- /dev/null
+++ b/data/deprecations/15-6-deprecate-runner-register-command.yml
@@ -0,0 +1,18 @@
+- name: "`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.
+ announcement_date: "2022-11-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.
+ 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 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.8,
+ 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).
+ The new method will involve passing a [runner authentication token](https://docs.gitlab.com/ee/security/token_overview.html#runner-authentication-tokens-also-called-runner-tokens)
+ to a new `gitlab-runner deploy` command.
+ end_of_support_milestone: "16.0" # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
+ end_of_support_date: "2023-05-22" # (optional) The date of the milestone release 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
new file mode 100644
index 00000000000..20f6ba758bb
--- /dev/null
+++ b/data/deprecations/15-6-deprecate-runner-register-token-k8s-operator.yml
@@ -0,0 +1,21 @@
+- name: "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.
+ announcement_date: "2022-11-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.
+ 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.0" # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
+ end_of_support_date: "2023-05-22" # (optional) The date of the milestone release when support for this feature will end.
+
+
+# OTHER OPTIONAL FIELDS
+#
+ tiers: # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
+ documentation_url: https://docs.gitlab.com/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
+ 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/templates/example.yml b/data/deprecations/templates/example.yml
index e5e04e5d216..cc512f70b3e 100644
--- a/data/deprecations/templates/example.yml
+++ b/data/deprecations/templates/example.yml
@@ -41,9 +41,9 @@
#
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: # (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/removals/14_0/release_remove_redundant_keyvalue_pair_from_the_payload_of_dora.yml b/data/removals/14_0/release_remove_redundant_keyvalue_pair_from_the_payload_of_dora.yml
index 47c58bcb143..98aef74fd03 100644
--- a/data/removals/14_0/release_remove_redundant_keyvalue_pair_from_the_payload_of_dora.yml
+++ b/data/removals/14_0/release_remove_redundant_keyvalue_pair_from_the_payload_of_dora.yml
@@ -5,4 +5,4 @@
issue_url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/325931'
breaking_change: true
body: |
- The [deployment frequency project-level API](https://docs.gitlab.com/ee/api/dora4_project_analytics.html#list-project-deployment-frequencies) endpoint has been deprecated in favor of the [DORA 4 API](https://docs.gitlab.com/ee/api/dora/metrics.html), which consolidates all the metrics under one API with the specific metric as a required field. As a result, the timestamp field, which doesn't allow adding future extensions and causes performance issues, will be removed. With the old API, an example response would be `{ "2021-03-01": 3, "date": "2021-03-01", "value": 3 }`. The first key/value (`"2021-03-01": 3`) will be removed and replaced by the last two (`"date": "2021-03-01", "value": 3`).
+ The [deployment frequency project-level API](https://docs.gitlab.com/ee/api/dora/metrics.html#list-project-deployment-frequencies) endpoint has been deprecated in favor of the [DORA 4 API](https://docs.gitlab.com/ee/api/dora/metrics.html), which consolidates all the metrics under one API with the specific metric as a required field. As a result, the timestamp field, which doesn't allow adding future extensions and causes performance issues, will be removed. With the old API, an example response would be `{ "2021-03-01": 3, "date": "2021-03-01", "value": 3 }`. The first key/value (`"2021-03-01": 3`) will be removed and replaced by the last two (`"date": "2021-03-01", "value": 3`).
diff --git a/data/removals/14_0/removals-14-testing-team.yml b/data/removals/14_0/removals-14-testing-team.yml
index 2012f8738b8..8b877ece6cc 100644
--- a/data/removals/14_0/removals-14-testing-team.yml
+++ b/data/removals/14_0/removals-14-testing-team.yml
@@ -4,7 +4,7 @@
reporter: jheimbuck_gl
breaking_change: true
body: |
- Browser Performance Testing has run in a job named `performance` by default. With the introduction of [Load Performance Testing](https://docs.gitlab.com/ee/user/project/merge_requests/load_performance_testing.html) in GitLab 13.2, this naming could be confusing. To make it clear which job is running [Browser Performance Testing](https://docs.gitlab.com/ee/user/project/merge_requests/browser_performance_testing.html), the default job name is changed from `performance` to `browser_performance` in the template in GitLab 14.0.
+ Browser Performance Testing has run in a job named `performance` by default. With the introduction of [Load Performance Testing](https://docs.gitlab.com/ee/ci/testing/code_quality.html) in GitLab 13.2, this naming could be confusing. To make it clear which job is running [Browser Performance Testing](https://docs.gitlab.com/ee/ci/testing/browser_performance_testing.html), the default job name is changed from `performance` to `browser_performance` in the template in GitLab 14.0.
Relevant Issue: [Rename default Browser Performance Testing job](https://gitlab.com/gitlab-org/gitlab/-/issues/225914)
- name: "Code Quality RuboCop support changed"
@@ -13,7 +13,7 @@
reporter: jheimbuck_gl
breaking_change: true
body: |
- By default, the Code Quality feature has not provided support for Ruby 2.6+ if you're using the Code Quality template. To better support the latest versions of Ruby, the default RuboCop version is updated to add support for Ruby 2.4 through 3.0. As a result, support for Ruby 2.1, 2.2, and 2.3 is removed. You can re-enable support for older versions by [customizing your configuration](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html#rubocop-errors).
+ By default, the Code Quality feature has not provided support for Ruby 2.6+ if you're using the Code Quality template. To better support the latest versions of Ruby, the default RuboCop version is updated to add support for Ruby 2.4 through 3.0. As a result, support for Ruby 2.1, 2.2, and 2.3 is removed. You can re-enable support for older versions by [customizing your configuration](https://docs.gitlab.com/ee/ci/testing/code_quality.html#rubocop-errors).
Relevant Issue: [Default `codeclimate-rubocop` engine does not support Ruby 2.6+](https://gitlab.com/gitlab-org/ci-cd/codequality/-/issues/28)
- name: "Ruby version changed in `Ruby.gitlab-ci.yml`"
diff --git a/data/removals/15_0/15-0-advanced-search-elasticsearch-6-8.yml b/data/removals/15_0/15-0-advanced-search-elasticsearch-6-8.yml
index 5877b9cf0af..e40e48ba9e9 100644
--- a/data/removals/15_0/15-0-advanced-search-elasticsearch-6-8.yml
+++ b/data/removals/15_0/15-0-advanced-search-elasticsearch-6-8.yml
@@ -10,7 +10,7 @@
If you use Elasticsearch 6.8, **you must upgrade your Elasticsearch version to 7.x** prior to upgrading to GitLab 15.0.
You should not upgrade to Elasticsearch 8 until you have completed the GitLab 15.0 upgrade.
- View the [version requirements](https://docs.gitlab.com/ee/integration/elasticsearch.html#version-requirements) for details.
+ View the [version requirements](https://docs.gitlab.com/ee/integration/advanced_search/elasticsearch.html#version-requirements) for details.
# The following items are not published on the docs page, but may be used in the future.
stage: "Enablement"
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/350275
diff --git a/data/removals/15_0/15-0-request-profiling.yml b/data/removals/15_0/15-0-request-profiling.yml
index 0ca6919130c..f5cea4e0d11 100644
--- a/data/removals/15_0/15-0-request-profiling.yml
+++ b/data/removals/15_0/15-0-request-profiling.yml
@@ -6,7 +6,7 @@
breaking_change: true
reporter: iroussos
body: | # Do not modify this line, instead modify the lines below.
- [Request profiling](https://docs.gitlab.com/ee/administration/monitoring/performance/request_profiling.html) has been removed in GitLab 15.0.
+ [Request profiling](https://docs.gitlab.com/ee/administration/monitoring/performance/index.html) has been removed in GitLab 15.0.
We're working on [consolidating our profiling tools](https://gitlab.com/groups/gitlab-org/-/epics/7327) and making them more easily accessible.
We [evaluated](https://gitlab.com/gitlab-org/gitlab/-/issues/350152) the use of this feature and we found that it is not widely used.
diff --git a/data/removals/15_0/15-0-static-site-editor.yml b/data/removals/15_0/15-0-static-site-editor.yml
index 492c3b5e3d2..bea1b14232a 100644
--- a/data/removals/15_0/15-0-static-site-editor.yml
+++ b/data/removals/15_0/15-0-static-site-editor.yml
@@ -8,10 +8,10 @@
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/347137 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
- The Static Site Editor was deprecated in GitLab 14.7 and the feature is being removed in GitLab 15.0. Incoming requests to the Static Site Editor will be redirected and open the target file to edit in the Web IDE. Current users of the Static Site Editor can view the [documentation](https://docs.gitlab.com/ee/user/project/static_site_editor/) for more information, including how to remove the configuration files from existing projects. We will continue investing in improvements to the Markdown editing experience by [maturing the Content Editor](https://gitlab.com/groups/gitlab-org/-/epics/5401) and making it available as a way to edit content across GitLab.
+ The Static Site Editor was deprecated in GitLab 14.7 and the feature is being removed in GitLab 15.0. Incoming requests to the Static Site Editor will be redirected and open the target file to edit in the Web IDE. Current users of the Static Site Editor can view the [documentation](https://docs.gitlab.com/ee/user/project/web_ide/index.html) for more information, including how to remove the configuration files from existing projects. We will continue investing in improvements to the Markdown editing experience by [maturing the Content Editor](https://gitlab.com/groups/gitlab-org/-/epics/5401) and making it available as a way to edit content across GitLab.
# 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/user/project/static_site_editor/
+ documentation_url: https://docs.gitlab.com/ee/user/project/web_ide/index.html
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/16_0/source_code-approvals-endpoint.yml b/data/removals/16_0/source_code-approvals-endpoint.yml
new file mode 100644
index 00000000000..e754c1cfebf
--- /dev/null
+++ b/data/removals/16_0/source_code-approvals-endpoint.yml
@@ -0,0 +1,20 @@
+- name: "Changing merge request approvals with the `/approvals` API endpoint"
+ announcement_milestone: "12.3"
+ announcement_date: "2019-09-22"
+ removal_milestone: "16.0"
+ removal_date: "2023-03-22"
+ breaking_change: true
+ reporter: tlinz
+ stage: Create
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/353097
+ body: | # (required) Do not modify this line, instead modify the lines below.
+ To change the approvals required for a merge request, you should no longer use the `/approvals` API endpoint, which was deprecated in GitLab 12.3.
+
+ Instead, use the [`/approval_rules` endpoint](https://docs.gitlab.com/ee/api/merge_request_approvals.html#merge-request-level-mr-approvals) to [create](https://docs.gitlab.com/ee/api/merge_request_approvals.html#create-merge-request-level-rule) or [update](https://docs.gitlab.com/ee/api/merge_request_approvals.html#update-merge-request-level-rule) the approval rules for a merge request.
+#
+# OPTIONAL FIELDS
+#
+ tiers: Premium
+ documentation_url: https://docs.gitlab.com/ee/api/merge_request_approvals.html
+ image_url: # (optional) This is a link to a thumbnail image depicting the feature
+ video_url: # (optional) Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
diff --git a/data/whats_new/202011230001_13_06.yml b/data/whats_new/202011230001_13_06.yml
index effaa243812..8701a050d4c 100644
--- a/data/whats_new/202011230001_13_06.yml
+++ b/data/whats_new/202011230001_13_06.yml
@@ -23,7 +23,7 @@
self-managed: true
gitlab-com: true
available_in: [Free, Premium, Ultimate]
- documentation_link: https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html#code-quality-widget
+ documentation_link: https://docs.gitlab.com/ee/ci/testing/code_quality.html#code-quality-widget
image_url: https://about.gitlab.com/images/13_6/code_quality_severity.png
published_at: 2020-11-22
release: 13.6
diff --git a/data/whats_new/202103220001_13_10.yml b/data/whats_new/202103220001_13_10.yml
index bba60a60ca2..077f97afe81 100644
--- a/data/whats_new/202103220001_13_10.yml
+++ b/data/whats_new/202103220001_13_10.yml
@@ -41,12 +41,12 @@
release: 13.10
- name: "DORA4-based lead time for changes"
description: |
- Measuring the efficiency of your software development lifecycle is an important step to grow DevOps adoption for any organization. In the previous milestone, we added support for [DORA4-based Deployment Frequency](https://docs.gitlab.com/ee/api/dora4_project_analytics.html). In this release, we are excited to announce the support of a new API for lead time for changes (via merge requests) on the project level. The lead time for changes gives you an indication of how long it takes for code to be committed and deployed to your production environment. Understanding and tracking this data is a great starting point in your journey to continuous improvement in your DevOps process.
+ Measuring the efficiency of your software development lifecycle is an important step to grow DevOps adoption for any organization. In the previous milestone, we added support for [DORA4-based Deployment Frequency](https://docs.gitlab.com/ee/api/dora/metrics.html). In this release, we are excited to announce the support of a new API for lead time for changes (via merge requests) on the project level. The lead time for changes gives you an indication of how long it takes for code to be committed and deployed to your production environment. Understanding and tracking this data is a great starting point in your journey to continuous improvement in your DevOps process.
stage: Release
self-managed: true
gitlab-com: true
available_in: [Ultimate]
- documentation_link: https://docs.gitlab.com/ee/api/dora4_project_analytics.html#list-project-merge-request-lead-times
+ documentation_link: https://docs.gitlab.com/ee/api/dora/metrics.html#list-project-merge-request-lead-times
image_url: https://about.gitlab.com/images/13_10/api.png
published_at: 2021-03-22
release: 13.10
diff --git a/data/whats_new/202105220001_13_12.yml b/data/whats_new/202105220001_13_12.yml
index 893ea694988..bcb2da40f63 100644
--- a/data/whats_new/202105220001_13_12.yml
+++ b/data/whats_new/202105220001_13_12.yml
@@ -74,7 +74,7 @@
self-managed: true
gitlab-com: true
available_in: [Ultimate]
- documentation_link: https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html#code-quality-in-diff-view
+ documentation_link: https://docs.gitlab.com/ee/ci/testing/code_quality.html#code-quality-in-diff-view
image_url: https://about.gitlab.com/images/13_12/code-quality-mr-diff-mvc.png
published_at: 2021-05-22
release: 13.12
diff --git a/data/whats_new/202205220001_15_0.yml b/data/whats_new/202205220001_15_0.yml
index e1449f13c0a..112154d9352 100644
--- a/data/whats_new/202205220001_15_0.yml
+++ b/data/whats_new/202205220001_15_0.yml
@@ -22,7 +22,7 @@
self-managed: true # Boolean value (true or false)
gitlab-com: true # Boolean value (true or false)
available_in: [Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Starter, Premium, Ultimate]
- documentation_link: https://docs.gitlab.com/ee/integration/elasticsearch.html # This is the documentation URL, but can be a URL to a video if there is one
+ documentation_link: https://docs.gitlab.com/ee/integration/advanced_search/elasticsearch.html # This is the documentation URL, but can be a URL to a video if there is one
image_url: https://about.gitlab.com/images/15_0/gitlab_advanced_search_is_now_compatible_with_opensearch.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
published_at: 2022-05-22 # YYYY-MM-DD
release: 15.0 # XX.Y
diff --git a/data/whats_new/202206220001_15_1.yml b/data/whats_new/202206220001_15_1.yml
index ab91ffeecb6..4a57db233b9 100644
--- a/data/whats_new/202206220001_15_1.yml
+++ b/data/whats_new/202206220001_15_1.yml
@@ -17,7 +17,7 @@
gitlab-com: true
available_in: [Premium, Ultimate]
documentation_link: https://docs.gitlab.com/ee/user/group/saml_sso/group_sync.html
- image_url: https://about.gitlab.com/images/15_1/SAML_Group_Sync.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ image_url: https://about.gitlab.com/images/15_1/SAML_Group_Sync.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
published_at: 2022-06-22
release: 15.1
- name: Enhancing visibility into Value Stream with DORA metrics
@@ -28,7 +28,7 @@
gitlab-com: true
available_in: [Free, Premium, Ultimate]
documentation_link: https://docs.gitlab.com/ee/user/analytics/ci_cd_analytics.html
- image_url: https://about.gitlab.com/images/15_1/vsa_dora_n_ttrs.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ image_url: https://about.gitlab.com/images/15_1/vsa_dora_n_ttrs.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
published_at: 2022-06-22
release: 15.1
- name: "SLSA-2 attestation included for build artifacts"
diff --git a/data/whats_new/202207220001_15_2.yml b/data/whats_new/202207220001_15_2.yml
index 4f6f65c9f18..7563a9ffbe9 100644
--- a/data/whats_new/202207220001_15_2.yml
+++ b/data/whats_new/202207220001_15_2.yml
@@ -1,4 +1,4 @@
-- name: "Live preview diagrams in the wiki WYSIWYG editor" # Match the release post entry
+- name: "Live preview diagrams in the wiki WYSIWYG editor" # Match the release post entry
description: | # Do not modify this line, instead modify the lines below.
GitLab Flavored Markdown includes extensions to support [Mermaid, PlantUML, and Kroki diagrams](https://docs.gitlab.com/ee/user/markdown.html#diagrams-and-flowcharts) but writing anything other than the most basic diagrams can be cumbersome without a live preview. You can toggle between the raw source and static preview and there are external tools you can use to write these diagrams, but the shift away from your content can be distracting.
@@ -11,8 +11,8 @@
image_url: https://about.gitlab.com/images/15_2/create-preview-diagrams-in-wysiwyg.png
published_at: 2022-07-22
release: 15.2
-- name: Incident timeline # Match the release post entry
- description: | # Do not modify this line, instead modify the lines below.
+- name: Incident timeline # Match the release post entry
+ description: | # Do not modify this line, instead modify the lines below.
Capturing what happened during an incident is an important practice that facilitates learning and the opportunity for improvement. Yet, asking incident responders to take on additional administrative tasks when they're busy fire-fighting, or trying to reconstruct the timeline of events post incident lead to incomplete or less than accurate information.
GitLab incident timeline is designed to make information capture during an incident, or post incident, easy and efficient. In the Incident timeline MVC, we make it possible to add new timeline events manually, delete a timeline event, and view the incident timeline in a dedicated tab within an incident issue.
@@ -24,8 +24,8 @@
image_url: https://img.youtube.com/vi/a0brUwOajvQ/hqdefault.jpg
published_at: 2022-07-22
release: 15.2
-- name: "Merge request reports redesign" # Match the release post entry
- description: | # Do not modify this line, instead modify the lines below.
+- name: "Merge request reports redesign" # Match the release post entry
+ description: | # Do not modify this line, instead modify the lines below.
Merge request reports are an important part of code review, providing insights into the impact of changes and improvements to meet project standards.
Report widgets now all follow design guidelines for layout, hierarchy, and content sections, making them consistent, scannable, and utilitarian. These improvements make it easier for you to find actionable information in each report.
@@ -37,8 +37,8 @@
image_url: https://about.gitlab.com/images/15_2/create-merge-request-widget-redesign.png
published_at: 2022-07-22
release: 15.2
-- name: "Change failure rate chart for visualizing software stability" # Match the release post entry
- description: | # Do not modify this line, instead modify the lines below.
+- name: "Change failure rate chart for visualizing software stability" # Match the release post entry
+ description: | # Do not modify this line, instead modify the lines below.
In this release, we added a new trend chart for the DORA [Change failure rate](https://docs.gitlab.com/ee/user/analytics/ci_cd_analytics.html) metric. This chart shows the percentage of deployments that cause an incident in a production environment. GitLab measures the change failure rate as the number of [incidents](https://docs.gitlab.com/ee/operations/incident_management/incidents.html) divided by the number of deployments to a production environment during a given time period.
This is the fourth DORA chart available in GitLab that provides insights into [value stream velocity and reliability trends](https://about.gitlab.com/blog/2022/06/20/gitlab-value-stream-management-and-dora/).
@@ -50,8 +50,8 @@
image_url: https://about.gitlab.com/images/15_2/dora4_chart_cfr.png
published_at: 2022-07-22
release: 15.2
-- name: "Enforce IP address restrictions for Git over SSH" # Match the release post entry
- description: | # Do not modify this line, instead modify the lines below.
+- name: "Enforce IP address restrictions for Git over SSH" # Match the release post entry
+ description: | # Do not modify this line, instead modify the lines below.
Limiting access to requests from a trusted set of IP addresses may improve security. Until now, only the API and UI supported such access restrictions; SSH access was blocked entirely. SSH now also adheres to this restriction, and grants access only to requests coming from IP addresses in your list.
stage: create
self-managed: false
@@ -61,8 +61,8 @@
image_url: https://img.youtube.com/vi/f60EgVK3mWc/hqdefault.jpg
published_at: 2022-07-22
release: 15.2
-- name: "Group and subgroup scan execution policies" # Match the release post entry
- description: | # Do not modify this line, instead modify the lines below.
+- name: "Group and subgroup scan execution policies" # Match the release post entry
+ description: | # Do not modify this line, instead modify the lines below.
Your security and compliance teams can now apply policies uniformly to all projects by scanning execution policies at the group and subgroup levels. This functionality is especially helpful for large organizations who have a large number of projects. Policies defined for the group or subgroup will flow down and apply to all child projects. To get started, ask your group owner to link a security policy project to your group on the **Security & Compliance > Policies** page.
Currently scan execution policies are the only policy type that is supported at the group and subgroup levels. You can track the efforts to add group and subgroup level support for scan result policies in [this epic](https://gitlab.com/groups/gitlab-org/-/epics/7622).
@@ -74,8 +74,8 @@
image_url: https://about.gitlab.com/images/15_2/protect_group_policies.png
published_at: 2022-07-22
release: 15.2
-- name: "Set the image pull policy in pipeline configuration" # Match the release post entry
- description: | # Do not modify this line, instead modify the lines below.
+- name: "Set the image pull policy in pipeline configuration" # Match the release post entry
+ description: | # Do not modify this line, instead modify the lines below.
You can select different [pull policies](https://docs.gitlab.com/runner/executors/docker.html#how-pull-policies-work) for how a GitLab Runner downloads Docker images in CI/CD jobs. `always` (the default behavior) ensures the image is always downloaded, `if-not-present` downloads an image only when a local version does not exist, and `never` only uses the local version (never download an image).
Previously, you could define the pull policy only at the runner level. In this release we've added the ability to define the pull policy at the pipeline level. Use `pull_policy` in your `.gitlab-ci.yml` to define different pull policies at the job or pipeline level. This feature is not supported by shared runners.
diff --git a/data/whats_new/202209220001_15_04.yml b/data/whats_new/202209220001_15_04.yml
index 056826c6457..3ee7c65ce23 100644
--- a/data/whats_new/202209220001_15_04.yml
+++ b/data/whats_new/202209220001_15_04.yml
@@ -1,19 +1,19 @@
-- name: "Suggested Reviewers open beta" # Match the release post entry
+- name: "Suggested Reviewers open beta" # Match the release post entry
description: | # Do not modify this line, instead modify the lines below.
Deciding the right person to [review your merge request](https://docs.gitlab.com/ee/user/project/merge_requests/reviews/) isn't always straightforward or obvious. Choosing the wrong reviewer can cause delays, low quality reviews, back and forth reassigning reviewers, or even no review at all.
Now, GitLab can recommend a reviewer with [Suggested Reviewers](https://docs.gitlab.com/ee/user/project/merge_requests/reviews/#suggested-reviewers). Using the changes in a merge request and a project's contribution graph, machine learning powered suggestions appear in the [reviewer dropdown](https://docs.gitlab.com/ee/user/project/merge_requests/getting_started.html#reviewer) in the merge request sidebar.
This feature is currently in [beta](https://about.gitlab.com/handbook/product/gitlab-the-product/#open-beta) behind a [feature flag](https://gitlab.com/gitlab-org/gitlab/-/issues/368356). It will be rolling out to all Ultimate GitLab.com customers over the next week.
- stage: create # String value of the stage that the feature was created in. e.g., Growth
- self-managed: false # Boolean value (true or false)
- gitlab-com: true # Boolean value (true or false)
- available_in: [Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Premium, Ultimate]
- documentation_link: 'https://docs.gitlab.com/ee/user/project/merge_requests/reviews/#suggested-reviewers' # This is the documentation URL, but can be a URL to a video if there is one
- image_url: https://about.gitlab.com/images/15_4/create-code-review-suggested-reviewers.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
- published_at: 2022-09-22 # YYYY-MM-DD
- release: 15.4 # XX.Y
-- name: "Improved CI/CD integration in VS Code" # Match the release post entry
+ stage: create # String value of the stage that the feature was created in. e.g., Growth
+ self-managed: false # Boolean value (true or false)
+ gitlab-com: true # Boolean value (true or false)
+ available_in: [Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Premium, Ultimate]
+ documentation_link: 'https://docs.gitlab.com/ee/user/project/merge_requests/reviews/#suggested-reviewers' # This is the documentation URL, but can be a URL to a video if there is one
+ image_url: https://about.gitlab.com/images/15_4/create-code-review-suggested-reviewers.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ published_at: 2022-09-22 # YYYY-MM-DD
+ release: 15.4 # XX.Y
+- name: "Improved CI/CD integration in VS Code" # Match the release post entry
description: | # Do not modify this line, instead modify the lines below.
When you're constructing complicated GitLab CI configurations that may contain `include:` or `extends:` keywords, it's challenging to ensure the configuration is valid and the resulting file has your expected configuration. Use [GitLab Workflow](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow) for Visual Studio Code to preview your merged GitLab CI/CD configuration file directly in VS Code. You can view your changes locally, and ensure your configuration is as you expect, before you commit and push.
@@ -21,28 +21,28 @@
* Download artifacts: [commit `f4d027c`](https://gitlab.com/gitlab-org/gitlab-vscode-extension/commit/f4d027c616c884bef9fc42e5f20dfac43b811134), [merge request `!635`](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/merge_requests/635)
* Retry or cancel an existing pipeline: [commit `c2caee4`](https://gitlab.com/gitlab-org/gitlab-vscode-extension/commit/c2caee40cfcbfb5d13cc790f9a2d1cfcf6c6a7ab), [merge request `!637`](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/merge_requests/637)
- stage: create # String value of the stage that the feature was created in. e.g., Growth
- self-managed: true # Boolean value (true or false)
- gitlab-com: false # Boolean value (true or false)
- available_in: [Free, Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Premium, Ultimate]
- documentation_link: 'https://gitlab.com/gitlab-org/gitlab-vscode-extension#show-merged-gitlab-cicd-configuration' # This is the documentation URL, but can be a URL to a video if there is one
- image_url: https://about.gitlab.com/images/15_4/create-vs-code-cicd-improvements.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
- published_at: 2022-09-22 # YYYY-MM-DD
- release: 15.4 # XX.Y
-- name: "Users on verified domains can bypass email validation" # Match the release post entry
+ stage: create # String value of the stage that the feature was created in. e.g., Growth
+ self-managed: true # Boolean value (true or false)
+ gitlab-com: false # Boolean value (true or false)
+ available_in: [Free, Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Premium, Ultimate]
+ documentation_link: 'https://gitlab.com/gitlab-org/gitlab-vscode-extension#show-merged-gitlab-cicd-configuration' # This is the documentation URL, but can be a URL to a video if there is one
+ image_url: https://about.gitlab.com/images/15_4/create-vs-code-cicd-improvements.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ published_at: 2022-09-22 # YYYY-MM-DD
+ release: 15.4 # XX.Y
+- name: "Users on verified domains can bypass email validation" # Match the release post entry
description: | # Do not modify this line, instead modify the lines below.
New GitLab users created using SAML or SCIM that belong to a [verified domain](https://docs.gitlab.com/ee/user/project/pages/custom_domains_ssl_tls_certification/#1-add-a-custom-domain) no longer receive the GitLab account verification e-mail.
This reduces account activation friction. Accounts generated through a provisioning process are already verified, so users should not have to individually verify them manually.
- stage: manage # String value of the stage that the feature was created in. e.g., Growth
- self-managed: false # Boolean value (true or false)
- gitlab-com: true # Boolean value (true or false)
- available_in: [Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Premium, Ultimate]
- documentation_link: 'https://docs.gitlab.com/ee/user/group/saml_sso/index.html#bypass-user-verification-with-verified-domains' # This is the documentation URL, but can be a URL to a video if there is one
- image_url: https://about.gitlab.com/images/15_4/domain-verification.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
- published_at: 2022-09-22 # YYYY-MM-DD
- release: 15.4 # XX.Y
-- name: "Sortable, filterable data-driven tables in Markdown" # Match the release post entry
+ stage: manage # String value of the stage that the feature was created in. e.g., Growth
+ self-managed: false # Boolean value (true or false)
+ gitlab-com: true # Boolean value (true or false)
+ available_in: [Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Premium, Ultimate]
+ documentation_link: 'https://docs.gitlab.com/ee/user/group/saml_sso/index.html#bypass-user-verification-with-verified-domains' # This is the documentation URL, but can be a URL to a video if there is one
+ image_url: https://about.gitlab.com/images/15_4/domain-verification.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ published_at: 2022-09-22 # YYYY-MM-DD
+ release: 15.4 # XX.Y
+- name: "Sortable, filterable data-driven tables in Markdown" # Match the release post entry
description: | # Do not modify this line, instead modify the lines below.
Working with tables in Markdown can be a bit cumbersome. Not only is it difficult to figure out the correct number of pipes and empty cells, but the table output is static when you save your document. If you have to sort the table by the third column in an ascending order, you end up rewriting the whole thing.
@@ -58,46 +58,46 @@
- Dynamic filtering of data using `"filter" : true`
Now it's as simple as a click when you have to re-sort that 100-row table and as easy as a web search when you have to find that one issue reference lost in a sea of nearly identical URLs.
- stage: create # String value of the stage that the feature was created in. e.g., Growth
- self-managed: true # Boolean value (true or false)
- gitlab-com: true # Boolean value (true or false)
- available_in: [Free, Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Premium, Ultimate]
- documentation_link: 'https://docs.gitlab.com/ee/user/markdown.html#json' # This is the documentation URL, but can be a URL to a video if there is one
- image_url: https://img.youtube.com/vi/12yWKw1AdKY/hqdefault.jpg # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
- published_at: 2022-09-22 # YYYY-MM-DD
- release: 15.4 # XX.Y
-- name: "Getting started with GitLab Pages just got easier" # Match the release post entry
+ stage: create # String value of the stage that the feature was created in. e.g., Growth
+ self-managed: true # Boolean value (true or false)
+ gitlab-com: true # Boolean value (true or false)
+ available_in: [Free, Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Premium, Ultimate]
+ documentation_link: 'https://docs.gitlab.com/ee/user/markdown.html#json' # This is the documentation URL, but can be a URL to a video if there is one
+ image_url: https://img.youtube.com/vi/12yWKw1AdKY/hqdefault.jpg # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ published_at: 2022-09-22 # YYYY-MM-DD
+ release: 15.4 # XX.Y
+- name: "Getting started with GitLab Pages just got easier" # Match the release post entry
description: | # Do not modify this line, instead modify the lines below.
We've made it much easier to get started with GitLab Pages. Instead of creating configuration files by hand, build them interactively using the GitLab UI. Just answer a few basic questions on how your app is built, and we'll build the `.gitlab-ci.yml` file to get you started.
This is the first time we're using our new [Pipeline Wizard](https://docs.gitlab.com/ee/development/cicd/pipeline_wizard.html), a tool that makes it easy to create `.gitlab-ci.yml` files by building them in the GitLab UI. You can look forward to more simplified onboarding helpers like this one.
- stage: create # String value of the stage that the feature was created in. e.g., Growth
- self-managed: true # Boolean value (true or false)
- gitlab-com: true # Boolean value (true or false)
- available_in: [Free, Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Premium, Ultimate]
- documentation_link: 'https://docs.gitlab.com/ee/user/project/pages/getting_started/pages_ui.html' # This is the documentation URL, but can be a URL to a video if there is one
- image_url: https://about.gitlab.com/images/15_4/create-pages-onboarding.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
- published_at: 2022-09-22 # YYYY-MM-DD
- release: 15.4 # XX.Y
-- name: "More powerful Linux machine types for GitLab SaaS runners" # Match the release post entry
+ stage: create # String value of the stage that the feature was created in. e.g., Growth
+ self-managed: true # Boolean value (true or false)
+ gitlab-com: true # Boolean value (true or false)
+ available_in: [Free, Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Premium, Ultimate]
+ documentation_link: 'https://docs.gitlab.com/ee/user/project/pages/getting_started/pages_ui.html' # This is the documentation URL, but can be a URL to a video if there is one
+ image_url: https://about.gitlab.com/images/15_4/create-pages-onboarding.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ published_at: 2022-09-22 # YYYY-MM-DD
+ release: 15.4 # XX.Y
+- name: "More powerful Linux machine types for GitLab SaaS runners" # Match the release post entry
description: | # Do not modify this line, instead modify the lines below.
When you run jobs on GitLab SaaS Linux runners, you now have access to more powerful machine types: medium and large. With these two machine types, you have more choices for your GitLab SaaS CI/CD jobs. And with 100% job isolation on an ephemeral virtual machine, and security and autoscaling fully managed by GitLab, you can confidently run your critical CI/CD jobs on GitLab SaaS.
- stage: create # String value of the stage that the feature was created in. e.g., Growth
- self-managed: false # Boolean value (true or false)
- gitlab-com: true # Boolean value (true or false)
- available_in: [Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Premium, Ultimate]
- documentation_link: 'https://docs.gitlab.com/ee/ci/runners/saas/linux_saas_runner.html' # This is the documentation URL, but can be a URL to a video if there is one
- image_url: https://about.gitlab.com/images/15_4/select-multiple-gitlab-saas-linux-runners.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
- published_at: 2022-09-22 # YYYY-MM-DD
- release: 15.4 # XX.Y
-- name: "Limit the maximum number of custom domains per project" # Match the release post entry
+ stage: create # String value of the stage that the feature was created in. e.g., Growth
+ self-managed: false # Boolean value (true or false)
+ gitlab-com: true # Boolean value (true or false)
+ available_in: [Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Premium, Ultimate]
+ documentation_link: 'https://docs.gitlab.com/ee/ci/runners/saas/linux_saas_runner.html' # This is the documentation URL, but can be a URL to a video if there is one
+ image_url: https://about.gitlab.com/images/15_4/select-multiple-gitlab-saas-linux-runners.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ published_at: 2022-09-22 # YYYY-MM-DD
+ release: 15.4 # XX.Y
+- name: "Limit the maximum number of custom domains per project" # Match the release post entry
description: | # Do not modify this line, instead modify the lines below.
You can use GitLab Pages to define custom domains for your website. Too many custom domains, however, can result in slow response times from the Pages API and impact the overall reliability of the service. Now you can limit the maximum number of custom domains per project at the instance level and strike the right balance for your needs. The default value is `0` (unlimited).
- stage: create # String value of the stage that the feature was created in. e.g., Growth
- self-managed: true # Boolean value (true or false)
- gitlab-com: false # Boolean value (true or false)
- available_in: [Free, Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Premium, Ultimate]
- documentation_link: 'https://docs.gitlab.com/ee/administration/pages/#set-maximum-number-of-gitlab-pages-custom-domains-for-a-project' # This is the documentation URL, but can be a URL to a video if there is one
- image_url: https://about.gitlab.com/images/15_4/create-pages-domain-limits.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
- published_at: 2022-09-22 # YYYY-MM-DD
- release: 15.4 # XX.Y
+ stage: create # String value of the stage that the feature was created in. e.g., Growth
+ self-managed: true # Boolean value (true or false)
+ gitlab-com: false # Boolean value (true or false)
+ available_in: [Free, Premium, Ultimate] # Array of strings. The Array brackets are required here. e.g., [Free, Premium, Ultimate]
+ documentation_link: 'https://docs.gitlab.com/ee/administration/pages/#set-maximum-number-of-gitlab-pages-custom-domains-for-a-project' # This is the documentation URL, but can be a URL to a video if there is one
+ image_url: https://about.gitlab.com/images/15_4/create-pages-domain-limits.png # This should be a full URL, generally taken from the release post content. If a video, use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
+ published_at: 2022-09-22 # YYYY-MM-DD
+ release: 15.4 # XX.Y
diff --git a/db/docs/approval_merge_request_rule_sources.yml b/db/docs/approval_merge_request_rule_sources.yml
index c1b4da16a1e..868d694d190 100644
--- a/db/docs/approval_merge_request_rule_sources.yml
+++ b/db/docs/approval_merge_request_rule_sources.yml
@@ -4,6 +4,6 @@ classes:
- ApprovalMergeRequestRuleSource
feature_categories:
- source_code_management
-description: TODO
+description: Keeps connection between merge request and project approval rule
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/8497
milestone: '11.7'
diff --git a/db/docs/approval_merge_request_rules.yml b/db/docs/approval_merge_request_rules.yml
index 2db3de519db..ad8b3411706 100644
--- a/db/docs/approval_merge_request_rules.yml
+++ b/db/docs/approval_merge_request_rules.yml
@@ -4,6 +4,6 @@ classes:
- ApprovalMergeRequestRule
feature_categories:
- source_code_management
-description: TODO
+description: Keeps approval merge request rules
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/8497
milestone: '11.7'
diff --git a/db/docs/approval_merge_request_rules_groups.yml b/db/docs/approval_merge_request_rules_groups.yml
index 86aa93fa179..1acf9882d57 100644
--- a/db/docs/approval_merge_request_rules_groups.yml
+++ b/db/docs/approval_merge_request_rules_groups.yml
@@ -3,6 +3,6 @@ table_name: approval_merge_request_rules_groups
classes: []
feature_categories:
- source_code_management
-description: TODO
+description: Keeps connection between group and a merge request approval rule
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/8497
milestone: '11.7'
diff --git a/db/docs/approval_merge_request_rules_users.yml b/db/docs/approval_merge_request_rules_users.yml
index 710de6cc0c4..750e7ae1f48 100644
--- a/db/docs/approval_merge_request_rules_users.yml
+++ b/db/docs/approval_merge_request_rules_users.yml
@@ -3,6 +3,6 @@ table_name: approval_merge_request_rules_users
classes: []
feature_categories:
- source_code_management
-description: TODO
+description: Keeps connection between user and a merge request approval rule
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/8497
milestone: '11.7'
diff --git a/db/docs/approval_project_rules.yml b/db/docs/approval_project_rules.yml
index a2a9eeb823f..c2aff9d358f 100644
--- a/db/docs/approval_project_rules.yml
+++ b/db/docs/approval_project_rules.yml
@@ -4,6 +4,6 @@ classes:
- ApprovalProjectRule
feature_categories:
- source_code_management
-description: TODO
+description: Keeps approval project rules
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/8497
milestone: '11.7'
diff --git a/db/docs/approval_project_rules_groups.yml b/db/docs/approval_project_rules_groups.yml
index 11ed75a398b..83eeb52099c 100644
--- a/db/docs/approval_project_rules_groups.yml
+++ b/db/docs/approval_project_rules_groups.yml
@@ -3,6 +3,6 @@ table_name: approval_project_rules_groups
classes: []
feature_categories:
- source_code_management
-description: TODO
+description: Keeps connection between group and a project approval rule
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/8497
milestone: '11.7'
diff --git a/db/docs/approval_project_rules_protected_branches.yml b/db/docs/approval_project_rules_protected_branches.yml
index 197644b75db..a41fd741af8 100644
--- a/db/docs/approval_project_rules_protected_branches.yml
+++ b/db/docs/approval_project_rules_protected_branches.yml
@@ -4,6 +4,6 @@ classes:
- ApprovalProjectRulesProtectedBranch
feature_categories:
- source_code_management
-description: TODO
+description: Keeps relation between approval project rules and protected branches.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22673
milestone: '12.7'
diff --git a/db/docs/approval_project_rules_users.yml b/db/docs/approval_project_rules_users.yml
index 8fe1c5c7f71..a1ff8bf7bff 100644
--- a/db/docs/approval_project_rules_users.yml
+++ b/db/docs/approval_project_rules_users.yml
@@ -3,6 +3,6 @@ table_name: approval_project_rules_users
classes: []
feature_categories:
- source_code_management
-description: TODO
+description: Keeps connection between user and a project approval rule
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/8497
milestone: '11.7'
diff --git a/db/docs/approvals.yml b/db/docs/approvals.yml
index e26a2ca4aa4..82d833b9ba6 100644
--- a/db/docs/approvals.yml
+++ b/db/docs/approvals.yml
@@ -4,6 +4,6 @@ classes:
- Approval
feature_categories:
- source_code_management
-description: TODO
+description: Stores merge request approvals made by users
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/73faf3c7289c4fa4535b752a12247ee74b173976
milestone: '7.12'
diff --git a/db/docs/approver_groups.yml b/db/docs/approver_groups.yml
index 6f0be968f07..e078e20814c 100644
--- a/db/docs/approver_groups.yml
+++ b/db/docs/approver_groups.yml
@@ -3,7 +3,8 @@ table_name: approver_groups
classes:
- ApproverGroup
feature_categories:
+- code_review
- source_code_management
-description: TODO
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/21d27185191e6204a6645d776c77ae3855cce3e8
+description: Group approvers of given merge request
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/743
milestone: '8.13'
diff --git a/db/docs/approvers.yml b/db/docs/approvers.yml
index 86fc663be93..f0bfa47761a 100644
--- a/db/docs/approvers.yml
+++ b/db/docs/approvers.yml
@@ -4,6 +4,7 @@ classes:
- Approver
feature_categories:
- code_review
+- source_code_management
description: Approvers of given merge request
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/3cc78d89984d9c9df8372c52b7bba38e6226f9f2
milestone: '7.13'
diff --git a/db/docs/audit_events_streaming_event_type_filters.yml b/db/docs/audit_events_streaming_event_type_filters.yml
new file mode 100644
index 00000000000..7119c84589e
--- /dev/null
+++ b/db/docs/audit_events_streaming_event_type_filters.yml
@@ -0,0 +1,9 @@
+---
+table_name: audit_events_streaming_event_type_filters
+classes:
+ - AuditEvents::Streaming::EventTypeFilter
+feature_categories:
+ - audit_events
+description: Represents a event type filter for audit event streaming
+introduced_by_url:
+milestone: '15.6'
diff --git a/db/docs/ci_build_report_results.yml b/db/docs/ci_build_report_results.yml
index 42d152221f3..b1f112aea3c 100644
--- a/db/docs/ci_build_report_results.yml
+++ b/db/docs/ci_build_report_results.yml
@@ -4,6 +4,6 @@ classes:
- Ci::BuildReportResult
feature_categories:
- code_testing
-description: TODO
+description: Stores data related to the build that finished, including junit test data.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32991
milestone: '13.1'
diff --git a/db/docs/ci_daily_build_group_report_results.yml b/db/docs/ci_daily_build_group_report_results.yml
index 8f23ac42bd0..3e75950f462 100644
--- a/db/docs/ci_daily_build_group_report_results.yml
+++ b/db/docs/ci_daily_build_group_report_results.yml
@@ -4,6 +4,6 @@ classes:
- Ci::DailyBuildGroupReportResult
feature_categories:
- code_testing
-description: TODO
+description: Stores daily aggregated data related to the build group, including code coverage data.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/30387
milestone: '13.0'
diff --git a/db/docs/ci_deleted_objects.yml b/db/docs/ci_deleted_objects.yml
index 24d19069913..a2e108e6c0a 100644
--- a/db/docs/ci_deleted_objects.yml
+++ b/db/docs/ci_deleted_objects.yml
@@ -4,6 +4,6 @@ classes:
- Ci::DeletedObject
feature_categories:
- build_artifacts
-description: TODO
+description: Allows efficient batch deletion of data in object storage.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/9bf76fe03f8edf4f67023448161af27abb8fb521
milestone: '13.5'
diff --git a/db/docs/ci_job_artifacts.yml b/db/docs/ci_job_artifacts.yml
index 781ba3babf1..492132315b6 100644
--- a/db/docs/ci_job_artifacts.yml
+++ b/db/docs/ci_job_artifacts.yml
@@ -5,6 +5,6 @@ classes:
- Gitlab::Ci::JobArtifact
feature_categories:
- build_artifacts
-description: TODO
+description: Stores artifacts produced by a build.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/61864a5a5bb523953589c9398a431c4369fbfc76
milestone: '10.3'
diff --git a/db/docs/ci_pipeline_artifacts.yml b/db/docs/ci_pipeline_artifacts.yml
index 753a57c74e2..124fe4de90b 100644
--- a/db/docs/ci_pipeline_artifacts.yml
+++ b/db/docs/ci_pipeline_artifacts.yml
@@ -4,6 +4,6 @@ classes:
- Ci::PipelineArtifact
feature_categories:
- build_artifacts
-description: TODO
+description: Stores aggregated artifacts produced by a pipeline.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37969
milestone: '13.3'
diff --git a/db/docs/ci_unit_test_failures.yml b/db/docs/ci_unit_test_failures.yml
index 14f66f5c586..9a1b27e8062 100644
--- a/db/docs/ci_unit_test_failures.yml
+++ b/db/docs/ci_unit_test_failures.yml
@@ -4,6 +4,6 @@ classes:
- Ci::UnitTestFailure
feature_categories:
- code_testing
-description: TODO
+description: Stores unit test failure data produced from builds.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56137
milestone: '13.11'
diff --git a/db/docs/ci_unit_tests.yml b/db/docs/ci_unit_tests.yml
index c22ad567c12..46b405678f0 100644
--- a/db/docs/ci_unit_tests.yml
+++ b/db/docs/ci_unit_tests.yml
@@ -4,6 +4,6 @@ classes:
- Ci::UnitTest
feature_categories:
- code_testing
-description: TODO
+description: Stores unit test data produced from builds.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56137
milestone: '13.11'
diff --git a/db/docs/content_blocked_states.yml b/db/docs/content_blocked_states.yml
index c2c4118b534..0abf239a98b 100644
--- a/db/docs/content_blocked_states.yml
+++ b/db/docs/content_blocked_states.yml
@@ -3,6 +3,6 @@ table_name: content_blocked_states
classes: []
feature_categories:
- source_code_management
-description: TODO
+description: JiHu only. Keeps list of restricted blobs.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72124
milestone: '14.5'
diff --git a/db/docs/dependency_proxy_blob_states.yml b/db/docs/dependency_proxy_blob_states.yml
new file mode 100644
index 00000000000..ddb9414b5f8
--- /dev/null
+++ b/db/docs/dependency_proxy_blob_states.yml
@@ -0,0 +1,9 @@
+---
+table_name: dependency_proxy_blob_states
+classes:
+ - Geo::DependencyProxyBlobState
+feature_categories:
+ - geo_replication
+description: Separate table for dependency proxy blob verification states
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101429
+milestone: '15.6'
diff --git a/db/docs/diff_note_positions.yml b/db/docs/diff_note_positions.yml
index 8e8a64861ab..0c4f688b4d4 100644
--- a/db/docs/diff_note_positions.yml
+++ b/db/docs/diff_note_positions.yml
@@ -4,6 +4,6 @@ classes:
- DiffNotePosition
feature_categories:
- source_code_management
-description: TODO
+description: Stores diff notes positions
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28113
milestone: '13.0'
diff --git a/db/docs/experiment_users.yml b/db/docs/experiment_users.yml
deleted file mode 100644
index 38e6c57a283..00000000000
--- a/db/docs/experiment_users.yml
+++ /dev/null
@@ -1,9 +0,0 @@
----
-table_name: experiment_users
-classes:
-- ExperimentUser
-feature_categories:
-- experimentation_conversion
-description: TODO
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38397
-milestone: '13.3'
diff --git a/db/docs/external_approval_rules_protected_branches.yml b/db/docs/external_approval_rules_protected_branches.yml
index ca498fe82ca..de4e1af7214 100644
--- a/db/docs/external_approval_rules_protected_branches.yml
+++ b/db/docs/external_approval_rules_protected_branches.yml
@@ -2,7 +2,7 @@
table_name: external_approval_rules_protected_branches
classes: []
feature_categories:
-- source_code_management
-description: TODO
+- compliance_management
+description: Keeps relation between protected branches and external approval rules
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/54002
milestone: '13.10'
diff --git a/db/docs/external_status_checks.yml b/db/docs/external_status_checks.yml
index fd9fe357173..1bb1bc03224 100644
--- a/db/docs/external_status_checks.yml
+++ b/db/docs/external_status_checks.yml
@@ -3,7 +3,7 @@ table_name: external_status_checks
classes:
- MergeRequests::ExternalStatusCheck
feature_categories:
-- source_code_management
-description: TODO
+- compliance_management
+description: Stores project's external status checks
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62186
milestone: '14.0'
diff --git a/db/docs/external_status_checks_protected_branches.yml b/db/docs/external_status_checks_protected_branches.yml
index 34f4edabb5d..bf26689bd0b 100644
--- a/db/docs/external_status_checks_protected_branches.yml
+++ b/db/docs/external_status_checks_protected_branches.yml
@@ -2,7 +2,7 @@
table_name: external_status_checks_protected_branches
classes: []
feature_categories:
-- source_code_management
-description: TODO
+- compliance_management
+description: Keeps relation between protected branches and external status checks
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62186
milestone: '14.0'
diff --git a/db/docs/fork_network_members.yml b/db/docs/fork_network_members.yml
index 47f6150a147..2077977f1b7 100644
--- a/db/docs/fork_network_members.yml
+++ b/db/docs/fork_network_members.yml
@@ -4,6 +4,6 @@ classes:
- ForkNetworkMember
feature_categories:
- source_code_management
-description: TODO
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/3098
+description: Keeps track of fork relations between projects.
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62186
milestone: '10.1'
diff --git a/db/docs/gpg_key_subkeys.yml b/db/docs/gpg_key_subkeys.yml
index 828ee6dac70..b3824c36e81 100644
--- a/db/docs/gpg_key_subkeys.yml
+++ b/db/docs/gpg_key_subkeys.yml
@@ -4,6 +4,6 @@ classes:
- GpgKeySubkey
feature_categories:
- source_code_management
-description: TODO
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/3098
+description: Stores GPG subkeys
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/14517
milestone: '10.1'
diff --git a/db/docs/gpg_keys.yml b/db/docs/gpg_keys.yml
index d4524e777ee..00b76959fe4 100644
--- a/db/docs/gpg_keys.yml
+++ b/db/docs/gpg_keys.yml
@@ -4,6 +4,6 @@ classes:
- GpgKey
feature_categories:
- source_code_management
-description: TODO
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/fbf1fd1a204a24aef2b80473ec64a520ed2a2dfc
+description: Stores GPG keys
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9546
milestone: '9.5'
diff --git a/db/docs/gpg_signatures.yml b/db/docs/gpg_signatures.yml
index a0f79655270..f49a0c03844 100644
--- a/db/docs/gpg_signatures.yml
+++ b/db/docs/gpg_signatures.yml
@@ -4,6 +4,6 @@ classes:
- CommitSignatures::GpgSignature
feature_categories:
- source_code_management
-description: TODO
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/8236b12dff3df6d223888664c820ae54b4e0eaf7
+description: Stores GPG signatures
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9546
milestone: '9.5'
diff --git a/db/docs/group_merge_request_approval_settings.yml b/db/docs/group_merge_request_approval_settings.yml
index 70a2ef9311b..33bb2370a86 100644
--- a/db/docs/group_merge_request_approval_settings.yml
+++ b/db/docs/group_merge_request_approval_settings.yml
@@ -4,6 +4,6 @@ classes:
- GroupMergeRequestApprovalSetting
feature_categories:
- source_code_management
-description: TODO
+description: Keeps merge request approval settings per group
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50256
milestone: '13.8'
diff --git a/db/docs/merge_request_blocks.yml b/db/docs/merge_request_blocks.yml
index 992fd88c1e5..1a3452fc66c 100644
--- a/db/docs/merge_request_blocks.yml
+++ b/db/docs/merge_request_blocks.yml
@@ -4,6 +4,6 @@ classes:
- MergeRequestBlock
feature_categories:
- source_code_management
-description: TODO
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/df778038981ae49cb7c0fec0a60f89abf801c5f0
-milestone: '12.0'
+description: Keeps relation between blocked and blocking merge requests
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/27323
+milestone: '11.11'
diff --git a/db/docs/merge_request_context_commit_diff_files.yml b/db/docs/merge_request_context_commit_diff_files.yml
index 08311e244a1..08af5c387c4 100644
--- a/db/docs/merge_request_context_commit_diff_files.yml
+++ b/db/docs/merge_request_context_commit_diff_files.yml
@@ -3,7 +3,7 @@ table_name: merge_request_context_commit_diff_files
classes:
- MergeRequestContextCommitDiffFile
feature_categories:
-- source_code_management
-description: TODO
+- code_review
+description: Stores diffs data for merge request context commits
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23701
milestone: '12.8'
diff --git a/db/docs/namespace_aggregation_schedules.yml b/db/docs/namespace_aggregation_schedules.yml
index 517a65000eb..07c80396302 100644
--- a/db/docs/namespace_aggregation_schedules.yml
+++ b/db/docs/namespace_aggregation_schedules.yml
@@ -3,7 +3,7 @@ table_name: namespace_aggregation_schedules
classes:
- Namespace::AggregationSchedule
feature_categories:
-- source_code_management
-description: TODO
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/bde41ee866d0fe0b1bb5ece1130fb6e24d95ad17
+- utilization
+description: Keeps update schedules for namespace_root_storage_statistics
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/29570
milestone: '12.1'
diff --git a/db/docs/namespace_commit_emails.yml b/db/docs/namespace_commit_emails.yml
new file mode 100644
index 00000000000..d7e192f97f4
--- /dev/null
+++ b/db/docs/namespace_commit_emails.yml
@@ -0,0 +1,9 @@
+---
+table_name: namespace_commit_emails
+classes:
+- Users::NamespaceCommitEmail
+feature_categories:
+- source_code_management
+description: User default email for commits from the GitLab UI
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101832
+milestone: '15.6'
diff --git a/db/docs/p_ci_builds_metadata.yml b/db/docs/p_ci_builds_metadata.yml
new file mode 100644
index 00000000000..676cb3bfb1c
--- /dev/null
+++ b/db/docs/p_ci_builds_metadata.yml
@@ -0,0 +1,9 @@
+---
+table_name: p_ci_builds_metadata
+classes:
+- Ci::BuildMetadata
+feature_categories:
+- continuous_integration
+description: Routing table that holds information for job execution
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/100115
+milestone: '15.5'
diff --git a/db/docs/path_locks.yml b/db/docs/path_locks.yml
index 0a6e3390035..27548f44c39 100644
--- a/db/docs/path_locks.yml
+++ b/db/docs/path_locks.yml
@@ -4,6 +4,6 @@ classes:
- PathLock
feature_categories:
- source_code_management
-description: TODO
+description: Stores paths to repository blobs locked by users
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/684e9d1b5979e11d2edae11a3028a696bfcdedf8
milestone: '8.9'
diff --git a/db/docs/project_aliases.yml b/db/docs/project_aliases.yml
index 66dead7706a..f79c81d2afe 100644
--- a/db/docs/project_aliases.yml
+++ b/db/docs/project_aliases.yml
@@ -4,6 +4,6 @@ classes:
- ProjectAlias
feature_categories:
- source_code_management
-description: TODO
+description: Stores aliases of projects
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/14108
milestone: '12.1'
diff --git a/db/docs/project_build_artifacts_size_refreshes.yml b/db/docs/project_build_artifacts_size_refreshes.yml
index 8f07ab9b3e1..56bad0e4df6 100644
--- a/db/docs/project_build_artifacts_size_refreshes.yml
+++ b/db/docs/project_build_artifacts_size_refreshes.yml
@@ -4,6 +4,6 @@ classes:
- Projects::BuildArtifactsSizeRefresh
feature_categories:
- build_artifacts
-description: TODO
+description: Temporary table to accurately recompute artifacts size.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81306
milestone: '14.9'
diff --git a/db/docs/project_ci_feature_usages.yml b/db/docs/project_ci_feature_usages.yml
index af9404570df..e7e354c6cc7 100644
--- a/db/docs/project_ci_feature_usages.yml
+++ b/db/docs/project_ci_feature_usages.yml
@@ -4,6 +4,6 @@ classes:
- Projects::CiFeatureUsage
feature_categories:
- code_testing
-description: Project CI feature usage information
+description: Project CI feature usage information used to access CI data from the main database.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68186
milestone: '14.2'
diff --git a/db/docs/project_daily_statistics.yml b/db/docs/project_daily_statistics.yml
index cddde444296..5de94c2845b 100644
--- a/db/docs/project_daily_statistics.yml
+++ b/db/docs/project_daily_statistics.yml
@@ -4,6 +4,6 @@ classes:
- ProjectDailyStatistic
feature_categories:
- source_code_management
-description: TODO
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/5ae9a44aa17c8929627cc450f936cd960c143e25
+description: Stores repository fetch statistics per day
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/23596
milestone: '11.9'
diff --git a/db/docs/project_repositories.yml b/db/docs/project_repositories.yml
index cd0d7a6c1d7..ed90a0d1595 100644
--- a/db/docs/project_repositories.yml
+++ b/db/docs/project_repositories.yml
@@ -4,6 +4,6 @@ classes:
- ProjectRepository
feature_categories:
- source_code_management
-description: TODO
+description: Keeps disk path to repositories and link to the shard
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/8614
milestone: '11.6'
diff --git a/db/docs/project_repository_states.yml b/db/docs/project_repository_states.yml
index 343ae980a88..fa762a646f4 100644
--- a/db/docs/project_repository_states.yml
+++ b/db/docs/project_repository_states.yml
@@ -3,7 +3,7 @@ table_name: project_repository_states
classes:
- ProjectRepositoryState
feature_categories:
-- source_code_management
-description: TODO
+- geo_replication
+description: Keeps checksums of repositories
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/4428
milestone: '10.6'
diff --git a/db/docs/project_repository_storage_moves.yml b/db/docs/project_repository_storage_moves.yml
index 12fa9d33f07..4255a0d4a8a 100644
--- a/db/docs/project_repository_storage_moves.yml
+++ b/db/docs/project_repository_storage_moves.yml
@@ -3,7 +3,7 @@ table_name: project_repository_storage_moves
classes:
- Projects::RepositoryStorageMove
feature_categories:
-- source_code_management
-description: TODO
+- gitaly
+description: Stores status of project repository moves
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29095
milestone: '13.0'
diff --git a/db/docs/project_wiki_repositories.yml b/db/docs/project_wiki_repositories.yml
new file mode 100644
index 00000000000..9f01fd2db3f
--- /dev/null
+++ b/db/docs/project_wiki_repositories.yml
@@ -0,0 +1,9 @@
+---
+table_name: project_wiki_repositories
+classes:
+- Projects::WikiRepository
+feature_categories:
+- wiki
+description: Stores information about project wiki repositories.
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103399
+milestone: '15.6'
diff --git a/db/docs/protected_branch_merge_access_levels.yml b/db/docs/protected_branch_merge_access_levels.yml
index 953d05f8eec..a07303975ad 100644
--- a/db/docs/protected_branch_merge_access_levels.yml
+++ b/db/docs/protected_branch_merge_access_levels.yml
@@ -4,6 +4,6 @@ classes:
- ProtectedBranch::MergeAccessLevel
feature_categories:
- source_code_management
-description: TODO
+description: Stores merge access settings for protected branches
introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/5081
milestone: '8.11'
diff --git a/db/docs/protected_branch_push_access_levels.yml b/db/docs/protected_branch_push_access_levels.yml
index 58010735b0f..fff94bceace 100644
--- a/db/docs/protected_branch_push_access_levels.yml
+++ b/db/docs/protected_branch_push_access_levels.yml
@@ -4,6 +4,6 @@ classes:
- ProtectedBranch::PushAccessLevel
feature_categories:
- source_code_management
-description: TODO
+description: Stores push access settings for protected branches
introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/5081
milestone: '8.11'
diff --git a/db/docs/protected_branch_unprotect_access_levels.yml b/db/docs/protected_branch_unprotect_access_levels.yml
index 635cf646df2..8727d77e8ec 100644
--- a/db/docs/protected_branch_unprotect_access_levels.yml
+++ b/db/docs/protected_branch_unprotect_access_levels.yml
@@ -4,6 +4,6 @@ classes:
- ProtectedBranch::UnprotectAccessLevel
feature_categories:
- source_code_management
-description: TODO
+description: Stores access settings for protected branch unprotection
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/5103
milestone: '10.7'
diff --git a/db/docs/protected_branches.yml b/db/docs/protected_branches.yml
index d1851c7cde6..a94c7d7681c 100644
--- a/db/docs/protected_branches.yml
+++ b/db/docs/protected_branches.yml
@@ -5,6 +5,6 @@ classes:
- ProtectedBranch
feature_categories:
- source_code_management
-description: TODO
+description: Keeps a list of protected branches by project
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/37224dc9c1ee80ba9030b616e2bc87bd96919e09
milestone: "<6.0"
diff --git a/db/docs/protected_tag_create_access_levels.yml b/db/docs/protected_tag_create_access_levels.yml
index 9856b1a0f25..0c1ae808e67 100644
--- a/db/docs/protected_tag_create_access_levels.yml
+++ b/db/docs/protected_tag_create_access_levels.yml
@@ -4,6 +4,6 @@ classes:
- ProtectedTag::CreateAccessLevel
feature_categories:
- source_code_management
-description: TODO
+description: Stores create access settings for protected tags
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/07d7d8e65905a39164b63f55eccdcea8f10f5d14
milestone: '9.1'
diff --git a/db/docs/protected_tags.yml b/db/docs/protected_tags.yml
index 0a18451d592..79b0b51de5f 100644
--- a/db/docs/protected_tags.yml
+++ b/db/docs/protected_tags.yml
@@ -4,6 +4,6 @@ classes:
- ProtectedTag
feature_categories:
- source_code_management
-description: TODO
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/1a416a42f1c1b876ecd96687e41696bc915cc2c2
+description: Keeps a list of protected tags by project
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10356
milestone: '9.1'
diff --git a/db/docs/push_event_payloads.yml b/db/docs/push_event_payloads.yml
index ea40e5270f4..68cd4ae4bb8 100644
--- a/db/docs/push_event_payloads.yml
+++ b/db/docs/push_event_payloads.yml
@@ -3,7 +3,7 @@ table_name: push_event_payloads
classes:
- PushEventPayload
feature_categories:
-- source_code_management
-description: TODO
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/0395c47193b3bbf6b4f060f28c9f632580313a35
+- users
+description: Stores log of push events
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/12463
milestone: '9.5'
diff --git a/db/docs/remote_mirrors.yml b/db/docs/remote_mirrors.yml
index 6926e0d2633..5d38c9cc3ec 100644
--- a/db/docs/remote_mirrors.yml
+++ b/db/docs/remote_mirrors.yml
@@ -4,6 +4,6 @@ classes:
- RemoteMirror
feature_categories:
- source_code_management
-description: TODO
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/ab83917c25c5d1f7dd29c82c91c699008292bc1d
+description: Stores push mirrors and their update statuses
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/249
milestone: '8.7'
diff --git a/db/docs/repository_languages.yml b/db/docs/repository_languages.yml
index b38afde69a0..ceee8670a68 100644
--- a/db/docs/repository_languages.yml
+++ b/db/docs/repository_languages.yml
@@ -4,6 +4,6 @@ classes:
- RepositoryLanguage
feature_categories:
- source_code_management
-description: TODO
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/79a5d76801a45696db629e1f543f2e1d6fa4784f
+description: Keeps relation between projects and repository languages
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/19480
milestone: '11.2'
diff --git a/db/docs/required_code_owners_sections.yml b/db/docs/required_code_owners_sections.yml
index a8018193d30..059078cce27 100644
--- a/db/docs/required_code_owners_sections.yml
+++ b/db/docs/required_code_owners_sections.yml
@@ -4,6 +4,6 @@ classes:
- ProtectedBranch::RequiredCodeOwnersSection
feature_categories:
- source_code_management
-description: TODO
+description: Keeps required code owners sections
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/43573
milestone: '13.5'
diff --git a/db/docs/software_license_policies.yml b/db/docs/software_license_policies.yml
index 478c68d8c59..615ae644985 100644
--- a/db/docs/software_license_policies.yml
+++ b/db/docs/software_license_policies.yml
@@ -3,7 +3,7 @@ table_name: software_license_policies
classes:
- SoftwareLicensePolicy
feature_categories:
-- license_compliance
+- security_policy_management
description: Allows user to approve or deny the use certain software licenses in their project.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6246
milestone: '11.2'
diff --git a/db/docs/software_licenses.yml b/db/docs/software_licenses.yml
index 48e78c8ca02..67ebd697fa8 100644
--- a/db/docs/software_licenses.yml
+++ b/db/docs/software_licenses.yml
@@ -3,7 +3,7 @@ table_name: software_licenses
classes:
- SoftwareLicense
feature_categories:
-- license_compliance
+- security_policy_management
description: Normalized software licenses to use in conjunction with License Compliance features (like software license policies)
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/6246
milestone: '11.2'
diff --git a/db/docs/trending_projects.yml b/db/docs/trending_projects.yml
index 9dd23857da0..1ee72f2d244 100644
--- a/db/docs/trending_projects.yml
+++ b/db/docs/trending_projects.yml
@@ -4,6 +4,6 @@ classes:
- TrendingProject
feature_categories:
- source_code_management
-description: TODO
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/237c8f66e6608420629503280aaea555ee980022
+description: Stores the list of trending projects
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/6749
milestone: '8.13'
diff --git a/db/docs/x509_certificates.yml b/db/docs/x509_certificates.yml
index 26fc03c743d..bcf976155f4 100644
--- a/db/docs/x509_certificates.yml
+++ b/db/docs/x509_certificates.yml
@@ -4,6 +4,6 @@ classes:
- X509Certificate
feature_categories:
- source_code_management
-description: TODO
+description: Stores data about X.509 certificate
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17773
milestone: '12.8'
diff --git a/db/docs/x509_commit_signatures.yml b/db/docs/x509_commit_signatures.yml
index 5791f6439d6..170294c8d56 100644
--- a/db/docs/x509_commit_signatures.yml
+++ b/db/docs/x509_commit_signatures.yml
@@ -4,6 +4,6 @@ classes:
- CommitSignatures::X509CommitSignature
feature_categories:
- source_code_management
-description: TODO
+description: Stores X.509 verification status of the commit
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17773
milestone: '12.8'
diff --git a/db/docs/x509_issuers.yml b/db/docs/x509_issuers.yml
index 0165189f044..30bbe8e4b12 100644
--- a/db/docs/x509_issuers.yml
+++ b/db/docs/x509_issuers.yml
@@ -4,6 +4,6 @@ classes:
- X509Issuer
feature_categories:
- source_code_management
-description: TODO
+description: Stores data about issuer of X.509 certificate
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/17773
milestone: '12.8'
diff --git a/db/fixtures/development/17_cycle_analytics.rb b/db/fixtures/development/17_cycle_analytics.rb
index 8e9952e9ba1..4f6bfc5c82a 100644
--- a/db/fixtures/development/17_cycle_analytics.rb
+++ b/db/fixtures/development/17_cycle_analytics.rb
@@ -2,6 +2,7 @@
require './spec/support/sidekiq_middleware'
require './spec/support/helpers/test_env'
+require 'active_support/testing/time_helpers'
# Usage:
#
@@ -18,6 +19,8 @@ require './spec/support/helpers/test_env'
# VSA_SEED_PROJECT_ID=10 FILTER=cycle_analytics SEED_VSA=1 bundle exec rake db:seed_fu
class Gitlab::Seeder::CycleAnalytics
+ include ActiveSupport::Testing::TimeHelpers
+
attr_reader :project, :issues, :merge_requests, :developers
FLAG = 'SEED_VSA'
@@ -104,7 +107,7 @@ class Gitlab::Seeder::CycleAnalytics
def seed_test_stage!
merge_requests.each do |merge_request|
- pipeline = FactoryBot.create(:ci_pipeline, :success, project: project)
+ 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
@@ -133,7 +136,7 @@ class Gitlab::Seeder::CycleAnalytics
def create_issues!
@issue_count.times do
- Timecop.travel start_time + rand(5).days do
+ travel_to(start_time + rand(5).days) do
title = "#{FFaker::Product.brand}-#{suffix}"
@issues << Issue.create!(project: project, title: title, author: developers.sample)
end
diff --git a/db/fixtures/development/98_gitlab_instance_administration_project.rb b/db/fixtures/development/98_gitlab_instance_administration_project.rb
index 3338f2bd2fc..35bc3edbd70 100644
--- a/db/fixtures/development/98_gitlab_instance_administration_project.rb
+++ b/db/fixtures/development/98_gitlab_instance_administration_project.rb
@@ -2,14 +2,17 @@
response = Sidekiq::Worker.skipping_transaction_check do
result = ::Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService.new.execute
+
+ next result unless result[:status] == :success
+
AuthorizedProjectUpdate::ProjectRecalculateService.new(result[:project]).execute
result
end
if response[:status] == :success
- puts "Successfully created self monitoring project."
+ puts "Successfully created self-monitoring project."
else
- puts "Could not create self monitoring project due to error: '#{response[:message]}'"
+ puts "Could not create self-monitoring project due to error: '#{response[:message]}'"
puts "Check logs for more details."
end
diff --git a/db/fixtures/production/998_gitlab_instance_administration_project.rb b/db/fixtures/production/998_gitlab_instance_administration_project.rb
index 8be707ffb08..d935832aea6 100644
--- a/db/fixtures/production/998_gitlab_instance_administration_project.rb
+++ b/db/fixtures/production/998_gitlab_instance_administration_project.rb
@@ -3,8 +3,8 @@
response = ::Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService.new.execute
if response[:status] == :success
- puts "Successfully created self monitoring project."
+ puts "Successfully created self-monitoring project."
else
- puts "Could not create self monitoring project due to error: '#{response[:message]}'"
+ puts "Could not create self-monitoring project due to error: '#{response[:message]}'"
puts "Check logs for more details."
end
diff --git a/db/migrate/20210305031822_create_dast_site_profile_variables.rb b/db/migrate/20210305031822_create_dast_site_profile_variables.rb
index f55755aa731..4b8fc982d86 100644
--- a/db/migrate/20210305031822_create_dast_site_profile_variables.rb
+++ b/db/migrate/20210305031822_create_dast_site_profile_variables.rb
@@ -13,7 +13,7 @@ class CreateDastSiteProfileVariables < ActiveRecord::Migration[6.0]
encrypted_value_constraint_name = check_constraint_name(:dast_site_profile_secret_variables, 'encrypted_value', 'max_length')
encrypted_value_iv_constraint_name = check_constraint_name(:dast_site_profile_secret_variables, 'encrypted_value_iv', 'max_length')
- create_table_with_constraints :dast_site_profile_secret_variables, comment: table_comment.to_json do |t|
+ create_table_with_constraints :dast_site_profile_secret_variables, comment: Gitlab::Json.dump(table_comment) do |t|
t.references :dast_site_profile, null: false, foreign_key: { on_delete: :cascade }, index: false
t.timestamps_with_timezone
diff --git a/db/migrate/20210317035357_create_dast_profiles_pipelines.rb b/db/migrate/20210317035357_create_dast_profiles_pipelines.rb
index f7a29958f12..f84e1237643 100644
--- a/db/migrate/20210317035357_create_dast_profiles_pipelines.rb
+++ b/db/migrate/20210317035357_create_dast_profiles_pipelines.rb
@@ -6,7 +6,7 @@ class CreateDastProfilesPipelines < ActiveRecord::Migration[6.0]
def up
table_comment = { owner: 'group::dynamic analysis', description: 'Join table between DAST Profiles and CI Pipelines' }
- create_table :dast_profiles_pipelines, primary_key: [:dast_profile_id, :ci_pipeline_id], comment: table_comment.to_json do |t|
+ create_table :dast_profiles_pipelines, primary_key: [:dast_profile_id, :ci_pipeline_id], comment: Gitlab::Json.dump(table_comment) do |t|
t.bigint :dast_profile_id, null: false
t.bigint :ci_pipeline_id, null: false
diff --git a/db/migrate/20210412111213_create_security_orchestration_policy_rule_schedule.rb b/db/migrate/20210412111213_create_security_orchestration_policy_rule_schedule.rb
index c7035400cba..365fa36f11b 100644
--- a/db/migrate/20210412111213_create_security_orchestration_policy_rule_schedule.rb
+++ b/db/migrate/20210412111213_create_security_orchestration_policy_rule_schedule.rb
@@ -11,7 +11,7 @@ class CreateSecurityOrchestrationPolicyRuleSchedule < ActiveRecord::Migration[6.
def up
table_comment = { owner: 'group::container security', description: 'Schedules used to store relationship between project and security policy repository' }
- create_table_with_constraints :security_orchestration_policy_rule_schedules, comment: table_comment.to_json do |t|
+ create_table_with_constraints :security_orchestration_policy_rule_schedules, comment: Gitlab::Json.dump(table_comment) do |t|
t.timestamps_with_timezone
t.datetime_with_timezone :next_run_at, null: true
diff --git a/db/migrate/20210423054022_create_dast_site_profiles_pipelines.rb b/db/migrate/20210423054022_create_dast_site_profiles_pipelines.rb
index bbdb4f02ab4..80b97ff5afe 100644
--- a/db/migrate/20210423054022_create_dast_site_profiles_pipelines.rb
+++ b/db/migrate/20210423054022_create_dast_site_profiles_pipelines.rb
@@ -4,7 +4,7 @@ class CreateDastSiteProfilesPipelines < ActiveRecord::Migration[6.0]
def up
table_comment = { owner: 'group::dynamic analysis', description: 'Join table between DAST Site Profiles and CI Pipelines' }
- create_table :dast_site_profiles_pipelines, primary_key: [:dast_site_profile_id, :ci_pipeline_id], comment: table_comment.to_json do |t|
+ create_table :dast_site_profiles_pipelines, primary_key: [:dast_site_profile_id, :ci_pipeline_id], comment: Gitlab::Json.dump(table_comment) do |t|
t.bigint :dast_site_profile_id, null: false
t.bigint :ci_pipeline_id, null: false
diff --git a/db/migrate/20210604032738_create_dast_site_profiles_builds.rb b/db/migrate/20210604032738_create_dast_site_profiles_builds.rb
index 2e9eb2c7cb7..6e653b36787 100644
--- a/db/migrate/20210604032738_create_dast_site_profiles_builds.rb
+++ b/db/migrate/20210604032738_create_dast_site_profiles_builds.rb
@@ -4,7 +4,7 @@ class CreateDastSiteProfilesBuilds < ActiveRecord::Migration[6.1]
def up
table_comment = { owner: 'group::dynamic analysis', description: 'Join table between DAST Site Profiles and CI Builds' }
- create_table :dast_site_profiles_builds, primary_key: [:dast_site_profile_id, :ci_build_id], comment: table_comment.to_json do |t|
+ create_table :dast_site_profiles_builds, primary_key: [:dast_site_profile_id, :ci_build_id], comment: Gitlab::Json.dump(table_comment) do |t|
t.bigint :dast_site_profile_id, null: false
t.bigint :ci_build_id, null: false
diff --git a/db/migrate/20210604051330_create_dast_scanner_profiles_builds.rb b/db/migrate/20210604051330_create_dast_scanner_profiles_builds.rb
index f8a5f735f0d..0fe3ada4c0d 100644
--- a/db/migrate/20210604051330_create_dast_scanner_profiles_builds.rb
+++ b/db/migrate/20210604051330_create_dast_scanner_profiles_builds.rb
@@ -4,7 +4,7 @@ class CreateDastScannerProfilesBuilds < ActiveRecord::Migration[6.1]
def up
table_comment = { owner: 'group::dynamic analysis', description: 'Join table between DAST Scanner Profiles and CI Builds' }
- create_table :dast_scanner_profiles_builds, primary_key: [:dast_scanner_profile_id, :ci_build_id], comment: table_comment.to_json do |t|
+ create_table :dast_scanner_profiles_builds, primary_key: [:dast_scanner_profile_id, :ci_build_id], comment: Gitlab::Json.dump(table_comment) do |t|
t.bigint :dast_scanner_profile_id, null: false
t.bigint :ci_build_id, null: false
diff --git a/db/migrate/20210713123345_create_dast_profile_schedule.rb b/db/migrate/20210713123345_create_dast_profile_schedule.rb
index 951aab63579..ea660de572a 100644
--- a/db/migrate/20210713123345_create_dast_profile_schedule.rb
+++ b/db/migrate/20210713123345_create_dast_profile_schedule.rb
@@ -10,7 +10,7 @@ class CreateDastProfileSchedule < ActiveRecord::Migration[6.1]
owner: 'group::dynamic analysis', description: 'Scheduling for scans using DAST Profiles'
}
- create_table_with_constraints :dast_profile_schedules, comment: table_comment.to_json do |t|
+ create_table_with_constraints :dast_profile_schedules, comment: Gitlab::Json.dump(table_comment) do |t|
t.bigint :project_id, null: false
t.bigint :dast_profile_id, null: false
t.bigint :user_id
diff --git a/db/migrate/20220613112029_add_namespace_id_to_protected_branches.rb b/db/migrate/20220613112029_add_namespace_id_to_protected_branches.rb
new file mode 100644
index 00000000000..1620a23d564
--- /dev/null
+++ b/db/migrate/20220613112029_add_namespace_id_to_protected_branches.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class AddNamespaceIdToProtectedBranches < Gitlab::Database::Migration[2.0]
+ enable_lock_retries!
+
+ def change
+ add_column :protected_branches, :namespace_id, :bigint
+ end
+end
diff --git a/db/migrate/20220613112030_add_namespace_id_indexes_foreign_key_to_protected_branches.rb b/db/migrate/20220613112030_add_namespace_id_indexes_foreign_key_to_protected_branches.rb
new file mode 100644
index 00000000000..18a91743746
--- /dev/null
+++ b/db/migrate/20220613112030_add_namespace_id_indexes_foreign_key_to_protected_branches.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddNamespaceIdIndexesForeignKeyToProtectedBranches < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_protected_branches_namespace_id'
+
+ def up
+ add_concurrent_index :protected_branches, :namespace_id, name: INDEX_NAME, where: 'namespace_id IS NOT NULL'
+ add_concurrent_foreign_key :protected_branches, :namespaces, column: :namespace_id, on_delete: :cascade
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key :protected_branches, column: :namespace_id
+ end
+ remove_concurrent_index :protected_branches, :namespace_id, name: INDEX_NAME
+ end
+end
diff --git a/db/migrate/20220613112031_add_group_or_project_constraint_in_protected_branches.rb b/db/migrate/20220613112031_add_group_or_project_constraint_in_protected_branches.rb
new file mode 100644
index 00000000000..b7f20450480
--- /dev/null
+++ b/db/migrate/20220613112031_add_group_or_project_constraint_in_protected_branches.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddGroupOrProjectConstraintInProtectedBranches < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ CONSTRAINT_NAME = 'protected_branches_project_id_namespace_id_any_not_null'
+
+ def up
+ constraint = <<~CONSTRAINT
+ (project_id IS NULL) <> (namespace_id IS NULL)
+ CONSTRAINT
+ add_check_constraint :protected_branches, constraint, CONSTRAINT_NAME
+ end
+
+ def down
+ remove_check_constraint :protected_branches, CONSTRAINT_NAME
+ end
+end
diff --git a/db/migrate/20220613112032_change_project_id_null_in_protected_branches.rb b/db/migrate/20220613112032_change_project_id_null_in_protected_branches.rb
new file mode 100644
index 00000000000..4bf8437d4fb
--- /dev/null
+++ b/db/migrate/20220613112032_change_project_id_null_in_protected_branches.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class ChangeProjectIdNullInProtectedBranches < Gitlab::Database::Migration[2.0]
+ enable_lock_retries!
+
+ def up
+ change_column_null :protected_branches, :project_id, true
+ end
+
+ def down
+ change_column_null :protected_branches, :project_id, false
+ end
+end
diff --git a/db/migrate/20220721065723_add_issue_branch_template_to_project_settings.rb b/db/migrate/20220721065723_add_issue_branch_template_to_project_settings.rb
new file mode 100644
index 00000000000..d65bd2c21e7
--- /dev/null
+++ b/db/migrate/20220721065723_add_issue_branch_template_to_project_settings.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddIssueBranchTemplateToProjectSettings < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ add_column :project_settings, :issue_branch_template, :text, if_not_exists: true
+ end
+
+ add_text_limit :project_settings, :issue_branch_template, 255
+ end
+
+ def down
+ remove_column :project_settings, :issue_branch_template, if_exists: true
+ end
+end
diff --git a/db/migrate/20220919062640_add_mirror_branch_regex_to_remote_mirrors.rb b/db/migrate/20220919062640_add_mirror_branch_regex_to_remote_mirrors.rb
new file mode 100644
index 00000000000..0f27ba9488b
--- /dev/null
+++ b/db/migrate/20220919062640_add_mirror_branch_regex_to_remote_mirrors.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddMirrorBranchRegexToRemoteMirrors < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ def up
+ add_column :remote_mirrors, :mirror_branch_regex, :text
+ add_text_limit :remote_mirrors, :mirror_branch_regex, 255
+ end
+
+ def down
+ remove_text_limit :remote_mirrors, :mirror_branch_regex
+ remove_column :remote_mirrors, :mirror_branch_regex
+ end
+end
diff --git a/db/migrate/20220920135632_add_jira_connect_proxy_url_setting.rb b/db/migrate/20220920135632_add_jira_connect_proxy_url_setting.rb
new file mode 100644
index 00000000000..c5842b6c787
--- /dev/null
+++ b/db/migrate/20220920135632_add_jira_connect_proxy_url_setting.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class AddJiraConnectProxyUrlSetting < Gitlab::Database::Migration[2.0]
+ # rubocop:disable Migration/AddLimitToTextColumns
+ # limit is added in 20220920135717_add_textlimit_to_jira_connect_proxy_url_setting.rb
+ def change
+ add_column :application_settings, :jira_connect_proxy_url, :text
+ end
+ # rubocop:enable Migration/AddLimitToTextColumns
+end
diff --git a/db/migrate/20220920135717_add_textlimit_to_jira_connect_proxy_url_setting.rb b/db/migrate/20220920135717_add_textlimit_to_jira_connect_proxy_url_setting.rb
new file mode 100644
index 00000000000..3a571580e79
--- /dev/null
+++ b/db/migrate/20220920135717_add_textlimit_to_jira_connect_proxy_url_setting.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddTextlimitToJiraConnectProxyUrlSetting < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ def up
+ add_text_limit :application_settings, :jira_connect_proxy_url, 255
+ end
+
+ def down
+ remove_text_limit :application_settings, :jira_connect_proxy_url
+ end
+end
diff --git a/db/migrate/20220926023734_add_mirror_branch_regex_to_project_settings.rb b/db/migrate/20220926023734_add_mirror_branch_regex_to_project_settings.rb
new file mode 100644
index 00000000000..5032a9ff964
--- /dev/null
+++ b/db/migrate/20220926023734_add_mirror_branch_regex_to_project_settings.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+class AddMirrorBranchRegexToProjectSettings < Gitlab::Database::Migration[2.0]
+ enable_lock_retries!
+
+ # rubocop:disable Migration/AddLimitToTextColumns
+ # limit is added in 20221027124848_add_text_limit_to_project_settings_mirror_branch_regex.rb
+ def change
+ add_column :project_settings, :mirror_branch_regex, :text
+ end
+ # rubocop:enable Migration/AddLimitToTextColumns
+end
diff --git a/db/migrate/20221003151747_create_audit_events_streaming_event_type_filters.rb b/db/migrate/20221003151747_create_audit_events_streaming_event_type_filters.rb
new file mode 100644
index 00000000000..c0acbe75d78
--- /dev/null
+++ b/db/migrate/20221003151747_create_audit_events_streaming_event_type_filters.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class CreateAuditEventsStreamingEventTypeFilters < Gitlab::Database::Migration[2.0]
+ UNIQ_INDEX_NAME = 'unique_streaming_event_type_filters_destination_id'
+
+ def change
+ create_table :audit_events_streaming_event_type_filters do |t|
+ t.timestamps_with_timezone null: false
+ t.references :external_audit_event_destination,
+ null: false,
+ index: false,
+ foreign_key: { to_table: 'audit_events_external_audit_event_destinations', on_delete: :cascade }
+ t.text :audit_event_type, null: false, limit: 255
+
+ t.index [:external_audit_event_destination_id, :audit_event_type], unique: true, name: UNIQ_INDEX_NAME
+ end
+ end
+end
diff --git a/db/migrate/20221010103207_add_product_analytics_enabled_to_application_settings.rb b/db/migrate/20221010103207_add_product_analytics_enabled_to_application_settings.rb
new file mode 100644
index 00000000000..24887e7b9fb
--- /dev/null
+++ b/db/migrate/20221010103207_add_product_analytics_enabled_to_application_settings.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddProductAnalyticsEnabledToApplicationSettings < Gitlab::Database::Migration[2.0]
+ def change
+ add_column :application_settings, :product_analytics_enabled, :boolean, default: false, null: false
+ end
+end
diff --git a/db/migrate/20221010184839_add_new_amount_used_to_ci_project_monthly_usages.rb b/db/migrate/20221010184839_add_new_amount_used_to_ci_project_monthly_usages.rb
new file mode 100644
index 00000000000..5c77dfe9334
--- /dev/null
+++ b/db/migrate/20221010184839_add_new_amount_used_to_ci_project_monthly_usages.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class AddNewAmountUsedToCiProjectMonthlyUsages < Gitlab::Database::Migration[2.0]
+ TABLE = :ci_project_monthly_usages
+ OLD_COLUMN = :amount_used
+ NEW_COLUMN = :new_amount_used
+ TRIGGER_NAME = 'sync_projects_amount_used_columns'
+
+ disable_ddl_transaction!
+
+ def up
+ check_trigger_permissions!(TABLE)
+
+ add_column(TABLE, NEW_COLUMN, :decimal, default: 0.0, precision: 18, scale: 4, null: false, if_not_exists: true)
+
+ install_rename_triggers(TABLE, OLD_COLUMN, NEW_COLUMN, trigger_name: TRIGGER_NAME)
+ end
+
+ def down
+ remove_rename_triggers(TABLE, TRIGGER_NAME)
+
+ remove_column(TABLE, NEW_COLUMN)
+ end
+end
diff --git a/db/migrate/20221010201815_add_purl_type_to_sbom_components.rb b/db/migrate/20221010201815_add_purl_type_to_sbom_components.rb
new file mode 100644
index 00000000000..3ab2aa262b1
--- /dev/null
+++ b/db/migrate/20221010201815_add_purl_type_to_sbom_components.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddPurlTypeToSbomComponents < Gitlab::Database::Migration[2.0]
+ def change
+ add_column :sbom_components, :purl_type, :smallint
+ end
+end
diff --git a/db/migrate/20221010202339_remove_unique_index_on_sbom_components_type_and_name.rb b/db/migrate/20221010202339_remove_unique_index_on_sbom_components_type_and_name.rb
new file mode 100644
index 00000000000..fe092232ca6
--- /dev/null
+++ b/db/migrate/20221010202339_remove_unique_index_on_sbom_components_type_and_name.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class RemoveUniqueIndexOnSbomComponentsTypeAndName < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'index_sbom_components_on_component_type_and_name'
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index_by_name :sbom_components, name: INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :sbom_components, [:component_type, :name], unique: true, name: INDEX_NAME
+ end
+end
diff --git a/db/migrate/20221010202408_add_unique_index_on_sbom_components_type_name_and_purl_type.rb b/db/migrate/20221010202408_add_unique_index_on_sbom_components_type_name_and_purl_type.rb
new file mode 100644
index 00000000000..5935db7c2c1
--- /dev/null
+++ b/db/migrate/20221010202408_add_unique_index_on_sbom_components_type_name_and_purl_type.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddUniqueIndexOnSbomComponentsTypeNameAndPurlType < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'index_sbom_components_on_component_type_name_and_purl_type'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :sbom_components, [:name, :purl_type, :component_type], unique: true, name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :sbom_components, name: INDEX_NAME
+ end
+end
diff --git a/db/migrate/20221013103738_add_disable_admin_oauth_scopes.rb b/db/migrate/20221013103738_add_disable_admin_oauth_scopes.rb
new file mode 100644
index 00000000000..3406252790d
--- /dev/null
+++ b/db/migrate/20221013103738_add_disable_admin_oauth_scopes.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddDisableAdminOauthScopes < Gitlab::Database::Migration[2.0]
+ def change
+ add_column :application_settings, :disable_admin_oauth_scopes, :boolean, null: false, default: false
+ end
+end
diff --git a/db/migrate/20221015000511_add_email_confirmation_setting_to_application_settings.rb b/db/migrate/20221015000511_add_email_confirmation_setting_to_application_settings.rb
new file mode 100644
index 00000000000..42fa4c1baf5
--- /dev/null
+++ b/db/migrate/20221015000511_add_email_confirmation_setting_to_application_settings.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddEmailConfirmationSettingToApplicationSettings < Gitlab::Database::Migration[2.0]
+ def change
+ add_column :application_settings, :email_confirmation_setting, :integer, limit: 2, default: 2
+ end
+end
diff --git a/db/migrate/20221017084208_rename_ci_pipeline_metadata_title.rb b/db/migrate/20221017084208_rename_ci_pipeline_metadata_title.rb
new file mode 100644
index 00000000000..3c1a3bbd40a
--- /dev/null
+++ b/db/migrate/20221017084208_rename_ci_pipeline_metadata_title.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class RenameCiPipelineMetadataTitle < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ def up
+ rename_column_concurrently :ci_pipeline_metadata, :title, :name, batch_column_name: :pipeline_id
+ end
+
+ def down
+ undo_rename_column_concurrently :ci_pipeline_metadata, :title, :name
+ end
+end
diff --git a/db/migrate/20221018050323_add_objective_and_keyresult_to_work_item_types.rb b/db/migrate/20221018050323_add_objective_and_keyresult_to_work_item_types.rb
new file mode 100644
index 00000000000..51834a3b19b
--- /dev/null
+++ b/db/migrate/20221018050323_add_objective_and_keyresult_to_work_item_types.rb
@@ -0,0 +1,56 @@
+# 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 AddObjectiveAndKeyresultToWorkItemTypes < Gitlab::Database::Migration[2.0]
+ # Added the following statements as per https://docs.gitlab.com/ee/development/database/migrations_for_multiple_databases.html
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ OBJECTIVE_ENUM_VALUE = 5
+ KEY_RESULT_ENUM_VALUE = 6
+
+ class WorkItemType < MigrationRecord
+ self.inheritance_column = :_type_disabled
+ self.table_name = 'work_item_types'
+ end
+
+ def up
+ # New instances will not run this migration and add this type via fixtures
+ # checking if record exists mostly because migration specs will run all migrations
+ # and that will conflict with the preloaded base work item types
+ objective_work_item = WorkItemType.find_by(base_type: OBJECTIVE_ENUM_VALUE, name: 'Objective', namespace_id: nil)
+ key_result_work_item = WorkItemType.find_by(base_type: KEY_RESULT_ENUM_VALUE, name: 'Key Result', namespace_id: nil)
+
+ if objective_work_item
+ say('Objective item record exist, skipping creation')
+ else
+ execute(
+ <<~SQL
+ INSERT INTO work_item_types (base_type, icon_name, name, created_at, updated_at) VALUES(
+ #{OBJECTIVE_ENUM_VALUE}, 'issue-type-objective', 'Objective', NOW(), NOW()
+ ) ON CONFLICT DO NOTHING;
+ SQL
+ )
+ end
+
+ if key_result_work_item
+ say('Keyresult item record exist, skipping creation')
+ else
+ execute(
+ <<~SQL
+ INSERT INTO work_item_types (base_type, icon_name, name, created_at, updated_at) VALUES(
+ #{KEY_RESULT_ENUM_VALUE}, 'issue-type-keyresult', 'Key Result', NOW(), NOW()
+ ) ON CONFLICT DO NOTHING;
+ SQL
+ )
+ end
+ end
+
+ def down
+ # There's the remote possibility that issues could already be
+ # using this issue type, with a tight foreign constraint.
+ # Therefore we will not attempt to remove any data.
+ end
+end
diff --git a/db/migrate/20221018092552_add_file_name_index_to_packages_rpm_repository_files.rb b/db/migrate/20221018092552_add_file_name_index_to_packages_rpm_repository_files.rb
new file mode 100644
index 00000000000..fcec3a6800d
--- /dev/null
+++ b/db/migrate/20221018092552_add_file_name_index_to_packages_rpm_repository_files.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddFileNameIndexToPackagesRpmRepositoryFiles < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ NEW_INDEX_NAME = 'index_packages_rpm_repository_files_on_project_id_and_file_name'
+ OLD_INDEX_NAME = 'index_packages_rpm_repository_files_on_project_id'
+
+ def up
+ add_concurrent_index :packages_rpm_repository_files, %i[project_id file_name], name: NEW_INDEX_NAME
+ remove_concurrent_index :packages_rpm_repository_files, :project_id, name: OLD_INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :packages_rpm_repository_files, :project_id, name: OLD_INDEX_NAME
+ remove_concurrent_index :packages_rpm_repository_files, %i[project_id file_name], name: NEW_INDEX_NAME
+ end
+end
diff --git a/db/migrate/20221018124029_add_consume_after_to_ghost_user_migrations.rb b/db/migrate/20221018124029_add_consume_after_to_ghost_user_migrations.rb
new file mode 100644
index 00000000000..148c6516dc9
--- /dev/null
+++ b/db/migrate/20221018124029_add_consume_after_to_ghost_user_migrations.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddConsumeAfterToGhostUserMigrations < Gitlab::Database::Migration[2.0]
+ def change
+ add_column :ghost_user_migrations, :consume_after, :datetime_with_timezone, null: false, default: -> { 'NOW()' }
+ end
+end
diff --git a/db/migrate/20221018124035_add_consume_after_index_to_ghost_user_migrations.rb b/db/migrate/20221018124035_add_consume_after_index_to_ghost_user_migrations.rb
new file mode 100644
index 00000000000..543d91b3f33
--- /dev/null
+++ b/db/migrate/20221018124035_add_consume_after_index_to_ghost_user_migrations.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddConsumeAfterIndexToGhostUserMigrations < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'index_ghost_user_migrations_on_consume_after_id'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :ghost_user_migrations, [:consume_after, :id], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :ghost_user_migrations, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20221018202524_create_dependency_proxy_blob_states.rb b/db/migrate/20221018202524_create_dependency_proxy_blob_states.rb
new file mode 100644
index 00000000000..b042df43f04
--- /dev/null
+++ b/db/migrate/20221018202524_create_dependency_proxy_blob_states.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+class CreateDependencyProxyBlobStates < Gitlab::Database::Migration[2.0]
+ VERIFICATION_STATE_INDEX_NAME = "index_dependency_proxy_blob_states_on_verification_state"
+ PENDING_VERIFICATION_INDEX_NAME = "index_dependency_proxy_blob_states_pending_verification"
+ FAILED_VERIFICATION_INDEX_NAME = "index_dependency_proxy_blob_states_failed_verification"
+ NEEDS_VERIFICATION_INDEX_NAME = "index_dependency_proxy_blob_states_needs_verification"
+
+ enable_lock_retries!
+
+ def up
+ table_comment = {
+ owner: 'group::geo',
+ description: 'Geo-specific table to store the verification state of DependencyProxy::Blob objects'
+ }
+
+ create_table :dependency_proxy_blob_states, id: false, comment: Gitlab::Json.dump(table_comment) do |t|
+ t.datetime_with_timezone :verification_started_at
+ t.datetime_with_timezone :verification_retry_at
+ t.datetime_with_timezone :verified_at
+ t.references :dependency_proxy_blob,
+ primary_key: true,
+ default: nil,
+ index: true,
+ 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 :dependency_proxy_blob_states
+ end
+end
diff --git a/db/migrate/20221020124018_add_delete_started_at_to_container_repositories.rb b/db/migrate/20221020124018_add_delete_started_at_to_container_repositories.rb
new file mode 100644
index 00000000000..c225d9cc343
--- /dev/null
+++ b/db/migrate/20221020124018_add_delete_started_at_to_container_repositories.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AddDeleteStartedAtToContainerRepositories < Gitlab::Database::Migration[2.0]
+ def change
+ add_column :container_repositories,
+ :delete_started_at,
+ :datetime_with_timezone,
+ null: true,
+ default: nil
+ end
+end
diff --git a/db/migrate/20221021213216_create_namespace_commit_emails.rb b/db/migrate/20221021213216_create_namespace_commit_emails.rb
new file mode 100644
index 00000000000..07811bf7b75
--- /dev/null
+++ b/db/migrate/20221021213216_create_namespace_commit_emails.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+class CreateNamespaceCommitEmails < Gitlab::Database::Migration[2.0]
+ def change
+ create_table :namespace_commit_emails do |t|
+ t.references :user, index: false, null: false, foreign_key: { on_delete: :cascade }
+ t.references :namespace, null: false
+ t.references :email, null: false
+ t.timestamps_with_timezone null: false
+
+ t.index [:user_id, :namespace_id], unique: true
+ end
+ end
+end
diff --git a/db/migrate/20221022213505_add_namespace_commit_emails_namespace_fk.rb b/db/migrate/20221022213505_add_namespace_commit_emails_namespace_fk.rb
new file mode 100644
index 00000000000..0c543b03397
--- /dev/null
+++ b/db/migrate/20221022213505_add_namespace_commit_emails_namespace_fk.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddNamespaceCommitEmailsNamespaceFk < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :namespace_commit_emails, :namespaces, column: :namespace_id, on_delete: :cascade
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key :namespace_commit_emails, column: :namespace_id
+ end
+ end
+end
diff --git a/db/migrate/20221022213521_add_namespace_commit_emails_email_fk.rb b/db/migrate/20221022213521_add_namespace_commit_emails_email_fk.rb
new file mode 100644
index 00000000000..9dbde26475c
--- /dev/null
+++ b/db/migrate/20221022213521_add_namespace_commit_emails_email_fk.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddNamespaceCommitEmailsEmailFk < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_foreign_key :namespace_commit_emails, :emails, column: :email_id, on_delete: :cascade
+ end
+
+ def down
+ with_lock_retries do
+ remove_foreign_key :namespace_commit_emails, column: :email_id
+ end
+ end
+end
diff --git a/db/migrate/20221025043930_change_default_value_on_password_last_changed_at_to_user_details.rb b/db/migrate/20221025043930_change_default_value_on_password_last_changed_at_to_user_details.rb
new file mode 100644
index 00000000000..49436043a66
--- /dev/null
+++ b/db/migrate/20221025043930_change_default_value_on_password_last_changed_at_to_user_details.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class ChangeDefaultValueOnPasswordLastChangedAtToUserDetails < Gitlab::Database::Migration[2.0]
+ enable_lock_retries!
+
+ # rubocop:disable Migration/RemoveColumn
+ def change
+ remove_column :user_details, :password_last_changed_at, :datetime_with_timezone
+ add_column :user_details, :password_last_changed_at, :datetime_with_timezone,
+ null: false, default: -> { 'NOW()' }, comment: 'JiHu-specific column'
+ end
+ # rubocop:enable Migration/RemoveColumn
+end
diff --git a/db/migrate/20221025105205_add_status_and_id_index_to_container_repositories.rb b/db/migrate/20221025105205_add_status_and_id_index_to_container_repositories.rb
new file mode 100644
index 00000000000..380ffd2e484
--- /dev/null
+++ b/db/migrate/20221025105205_add_status_and_id_index_to_container_repositories.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddStatusAndIdIndexToContainerRepositories < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_container_repositories_on_status_and_id'
+
+ def up
+ add_concurrent_index :container_repositories, [:status, :id], name: INDEX_NAME, where: 'status IS NOT NULL'
+ end
+
+ def down
+ remove_concurrent_index :container_repositories, [:status, :id], name: INDEX_NAME
+ end
+end
diff --git a/db/migrate/20221025145452_change_vulnerability_feedback_unique_idx.rb b/db/migrate/20221025145452_change_vulnerability_feedback_unique_idx.rb
new file mode 100644
index 00000000000..677245e1f50
--- /dev/null
+++ b/db/migrate/20221025145452_change_vulnerability_feedback_unique_idx.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class ChangeVulnerabilityFeedbackUniqueIdx < Gitlab::Database::Migration[2.0]
+ NEW_INDEX_NAME = :index_vulnerability_feedback_on_common_attributes
+ OLD_INDEX_NAME = :vulnerability_feedback_unique_idx
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :vulnerability_feedback,
+ %i[project_id category feedback_type project_fingerprint],
+ name: NEW_INDEX_NAME
+
+ remove_concurrent_index_by_name :vulnerability_feedback, OLD_INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :vulnerability_feedback,
+ %i[project_id category feedback_type project_fingerprint],
+ name: OLD_INDEX_NAME,
+ unique: true
+
+ remove_concurrent_index_by_name :vulnerability_feedback, NEW_INDEX_NAME
+ end
+end
diff --git a/db/migrate/20221025150202_add_index_for_finding_uuid_and_feedback_type_on_feedback.rb b/db/migrate/20221025150202_add_index_for_finding_uuid_and_feedback_type_on_feedback.rb
new file mode 100644
index 00000000000..f909573937b
--- /dev/null
+++ b/db/migrate/20221025150202_add_index_for_finding_uuid_and_feedback_type_on_feedback.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddIndexForFindingUuidAndFeedbackTypeOnFeedback < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = :index_vulnerability_feedback_on_feedback_type_and_finding_uuid
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :vulnerability_feedback, %i[feedback_type finding_uuid], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :vulnerability_feedback, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20221027124848_add_text_limit_to_project_settings_mirror_branch_regex.rb b/db/migrate/20221027124848_add_text_limit_to_project_settings_mirror_branch_regex.rb
new file mode 100644
index 00000000000..e87eb207204
--- /dev/null
+++ b/db/migrate/20221027124848_add_text_limit_to_project_settings_mirror_branch_regex.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddTextLimitToProjectSettingsMirrorBranchRegex < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ def up
+ add_text_limit :project_settings, :mirror_branch_regex, 255
+ end
+
+ def down
+ remove_text_limit :project_settings, :mirror_branch_regex
+ end
+end
diff --git a/db/migrate/20221028015347_add_commit_committer_name_check_to_push_rules.rb b/db/migrate/20221028015347_add_commit_committer_name_check_to_push_rules.rb
new file mode 100644
index 00000000000..e9a0887f353
--- /dev/null
+++ b/db/migrate/20221028015347_add_commit_committer_name_check_to_push_rules.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class AddCommitCommitterNameCheckToPushRules < Gitlab::Database::Migration[2.0]
+ def change
+ add_column :push_rules, :commit_committer_name_check, :boolean, default: false, null: false
+ end
+end
diff --git a/db/migrate/20221028152422_add_finding_data_column_to_security_findings.rb b/db/migrate/20221028152422_add_finding_data_column_to_security_findings.rb
new file mode 100644
index 00000000000..a5d3929579b
--- /dev/null
+++ b/db/migrate/20221028152422_add_finding_data_column_to_security_findings.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class AddFindingDataColumnToSecurityFindings < Gitlab::Database::Migration[2.0]
+ enable_lock_retries!
+
+ def up
+ add_column :security_findings, :finding_data, :jsonb, default: {}, null: false
+ end
+
+ def down
+ remove_column :security_findings, :finding_data
+ end
+end
diff --git a/db/migrate/20221031102916_add_users_foreign_key_to_projects.rb b/db/migrate/20221031102916_add_users_foreign_key_to_projects.rb
new file mode 100644
index 00000000000..fb37b3b37c2
--- /dev/null
+++ b/db/migrate/20221031102916_add_users_foreign_key_to_projects.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddUsersForeignKeyToProjects < Gitlab::Database::Migration[2.0]
+ 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/migrate/20221101032521_add_default_preferred_language_to_application_settings.rb b/db/migrate/20221101032521_add_default_preferred_language_to_application_settings.rb
new file mode 100644
index 00000000000..d6941f95465
--- /dev/null
+++ b/db/migrate/20221101032521_add_default_preferred_language_to_application_settings.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+class AddDefaultPreferredLanguageToApplicationSettings < Gitlab::Database::Migration[2.0]
+ def change
+ # rubocop:disable Migration/AddLimitToTextColumns
+ # limit is added in 20221101032600_add_text_limit_to_default_preferred_language_on_application_settings.rb
+ add_column :application_settings, :default_preferred_language, :text, default: 'en', null: false
+ # rubocop:enable Migration/AddLimitToTextColumns
+ end
+end
diff --git a/db/migrate/20221101032600_add_text_limit_to_default_preferred_language_on_application_settings.rb b/db/migrate/20221101032600_add_text_limit_to_default_preferred_language_on_application_settings.rb
new file mode 100644
index 00000000000..1f6b9815b93
--- /dev/null
+++ b/db/migrate/20221101032600_add_text_limit_to_default_preferred_language_on_application_settings.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddTextLimitToDefaultPreferredLanguageOnApplicationSettings < Gitlab::Database::Migration[2.0]
+ MAXIMUM_LIMIT = 32
+
+ disable_ddl_transaction!
+
+ def up
+ add_text_limit :application_settings, :default_preferred_language, MAXIMUM_LIMIT
+ end
+
+ def down
+ remove_text_limit :application_settings, :default_preferred_language
+ end
+end
diff --git a/db/migrate/20221101195903_change_email_confirmation_setting_default.rb b/db/migrate/20221101195903_change_email_confirmation_setting_default.rb
new file mode 100644
index 00000000000..86c1896f184
--- /dev/null
+++ b/db/migrate/20221101195903_change_email_confirmation_setting_default.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class ChangeEmailConfirmationSettingDefault < Gitlab::Database::Migration[2.0]
+ def change
+ change_column_default(:application_settings, :email_confirmation_setting, from: 2, to: 0)
+ end
+end
diff --git a/db/migrate/20221101201031_set_email_confirmation_setting_from_send_user_confirmation_email_setting.rb b/db/migrate/20221101201031_set_email_confirmation_setting_from_send_user_confirmation_email_setting.rb
new file mode 100644
index 00000000000..0c0a0dc1a58
--- /dev/null
+++ b/db/migrate/20221101201031_set_email_confirmation_setting_from_send_user_confirmation_email_setting.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class SetEmailConfirmationSettingFromSendUserConfirmationEmailSetting < Gitlab::Database::Migration[2.0]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ class ApplicationSetting < MigrationRecord
+ self.table_name = 'application_settings'
+ end
+
+ def up
+ return unless ApplicationSetting.exists?
+ return unless ApplicationSetting.last.send_user_confirmation_email
+
+ ApplicationSetting.last.update(email_confirmation_setting: 2)
+ end
+
+ def down
+ return unless ApplicationSetting.exists?
+
+ ApplicationSetting.last.update(email_confirmation_setting: 0)
+ end
+end
diff --git a/db/migrate/20221102202130_extend_x509_subject_limit.rb b/db/migrate/20221102202130_extend_x509_subject_limit.rb
new file mode 100644
index 00000000000..3e6bfc7691c
--- /dev/null
+++ b/db/migrate/20221102202130_extend_x509_subject_limit.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class ExtendX509SubjectLimit < Gitlab::Database::Migration[2.0]
+ def up
+ change_column :x509_certificates, :subject, :string, limit: 512
+ end
+
+ def down
+ change_column :x509_certificates, :subject, :string, limit: 255
+ end
+end
diff --git a/db/migrate/20221102225800_add_max_seats_used_changed_at_index_to_gitlab_subscriptions.rb b/db/migrate/20221102225800_add_max_seats_used_changed_at_index_to_gitlab_subscriptions.rb
new file mode 100644
index 00000000000..b5cf8289673
--- /dev/null
+++ b/db/migrate/20221102225800_add_max_seats_used_changed_at_index_to_gitlab_subscriptions.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddMaxSeatsUsedChangedAtIndexToGitlabSubscriptions < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'index_gitlab_subscriptions_on_max_seats_used_changed_at'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :gitlab_subscriptions, [:max_seats_used_changed_at, :namespace_id], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :gitlab_subscriptions, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20221103131409_add_partial_index_on_primary_key_of_security_scans.rb b/db/migrate/20221103131409_add_partial_index_on_primary_key_of_security_scans.rb
new file mode 100644
index 00000000000..f3defcd38c6
--- /dev/null
+++ b/db/migrate/20221103131409_add_partial_index_on_primary_key_of_security_scans.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddPartialIndexOnPrimaryKeyOfSecurityScans < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = :index_security_scans_on_id_for_non_purged_records
+ PURGED_STATE = 6
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :security_scans, :id, where: "status != #{PURGED_STATE}", name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :security_scans, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20221104061320_add_disable_download_button_into_application_settings.rb b/db/migrate/20221104061320_add_disable_download_button_into_application_settings.rb
new file mode 100644
index 00000000000..b93085b8617
--- /dev/null
+++ b/db/migrate/20221104061320_add_disable_download_button_into_application_settings.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+class AddDisableDownloadButtonIntoApplicationSettings < Gitlab::Database::Migration[2.0]
+ def change
+ add_column :application_settings, :disable_download_button, :boolean,
+ null: false, default: false, comment: 'JiHu-specific column'
+ end
+end
diff --git a/db/migrate/20221104094042_remove_users_foreign_key_to_projects.rb b/db/migrate/20221104094042_remove_users_foreign_key_to_projects.rb
new file mode 100644
index 00000000000..19497c80b8e
--- /dev/null
+++ b/db/migrate/20221104094042_remove_users_foreign_key_to_projects.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class RemoveUsersForeignKeyToProjects < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ remove_foreign_key_if_exists :projects, column: :creator_id
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key :projects, :users, column: :creator_id, on_delete: :nullify, validate: false
+ end
+end
diff --git a/db/migrate/20221107115247_change_scim_identity_group_id_remove_null.rb b/db/migrate/20221107115247_change_scim_identity_group_id_remove_null.rb
new file mode 100644
index 00000000000..f68cab68261
--- /dev/null
+++ b/db/migrate/20221107115247_change_scim_identity_group_id_remove_null.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+class ChangeScimIdentityGroupIdRemoveNull < Gitlab::Database::Migration[2.0]
+ def up
+ change_column_null :scim_identities, :group_id, true
+ end
+
+ def down
+ # There may now be nulls in the table, so we cannot re-add the constraint here.
+ end
+end
diff --git a/db/migrate/20221107115413_change_scim_oauth_access_token_group_id_remove_null.rb b/db/migrate/20221107115413_change_scim_oauth_access_token_group_id_remove_null.rb
new file mode 100644
index 00000000000..c33e67291a4
--- /dev/null
+++ b/db/migrate/20221107115413_change_scim_oauth_access_token_group_id_remove_null.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+class ChangeScimOauthAccessTokenGroupIdRemoveNull < Gitlab::Database::Migration[2.0]
+ def up
+ change_column_null :scim_oauth_access_tokens, :group_id, true
+ end
+
+ def down
+ # There may now be nulls in the table, so we cannot re-add the constraint here.
+ end
+end
diff --git a/db/migrate/20221107183222_create_project_wiki_repositories.rb b/db/migrate/20221107183222_create_project_wiki_repositories.rb
new file mode 100644
index 00000000000..770c62604ff
--- /dev/null
+++ b/db/migrate/20221107183222_create_project_wiki_repositories.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class CreateProjectWikiRepositories < Gitlab::Database::Migration[2.0]
+ def change
+ create_table :project_wiki_repositories do |t|
+ t.references :project, index: { unique: true }, foreign_key: { on_delete: :cascade }, null: false
+
+ t.timestamps_with_timezone null: false
+ end
+ end
+end
diff --git a/db/migrate/20221107184542_add_new_amount_used_to_ci_namespace_monthly_usages.rb b/db/migrate/20221107184542_add_new_amount_used_to_ci_namespace_monthly_usages.rb
new file mode 100644
index 00000000000..23a5a716164
--- /dev/null
+++ b/db/migrate/20221107184542_add_new_amount_used_to_ci_namespace_monthly_usages.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class AddNewAmountUsedToCiNamespaceMonthlyUsages < Gitlab::Database::Migration[2.0]
+ TABLE = :ci_namespace_monthly_usages
+ OLD_COLUMN = :amount_used
+ NEW_COLUMN = :new_amount_used
+ TRIGGER_NAME = 'sync_namespaces_amount_used_columns'
+
+ disable_ddl_transaction!
+
+ def up
+ check_trigger_permissions!(TABLE)
+
+ add_column(TABLE, NEW_COLUMN, :decimal, default: 0.0, precision: 18, scale: 4, null: false, if_not_exists: true)
+
+ install_rename_triggers(TABLE, OLD_COLUMN, NEW_COLUMN, trigger_name: TRIGGER_NAME)
+ end
+
+ def down
+ remove_rename_triggers(TABLE, TRIGGER_NAME)
+
+ remove_column(TABLE, NEW_COLUMN)
+ end
+end
diff --git a/db/migrate/20221108015813_add_telesign_to_application_settings.rb b/db/migrate/20221108015813_add_telesign_to_application_settings.rb
new file mode 100644
index 00000000000..f8e4fb5340b
--- /dev/null
+++ b/db/migrate/20221108015813_add_telesign_to_application_settings.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class AddTelesignToApplicationSettings < Gitlab::Database::Migration[2.0]
+ def change
+ add_column :application_settings, :encrypted_telesign_customer_xid, :binary
+ add_column :application_settings, :encrypted_telesign_customer_xid_iv, :binary
+
+ add_column :application_settings, :encrypted_telesign_api_key, :binary
+ add_column :application_settings, :encrypted_telesign_api_key_iv, :binary
+ end
+end
diff --git a/db/migrate/20221108185442_add_project_wiki_repository_id_to_project_wiki_repository_states.rb b/db/migrate/20221108185442_add_project_wiki_repository_id_to_project_wiki_repository_states.rb
new file mode 100644
index 00000000000..317f58dac27
--- /dev/null
+++ b/db/migrate/20221108185442_add_project_wiki_repository_id_to_project_wiki_repository_states.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+class AddProjectWikiRepositoryIdToProjectWikiRepositoryStates < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'idx_project_wiki_repository_states_project_wiki_repository_id'
+
+ def up
+ with_lock_retries do
+ unless column_exists?(:project_wiki_repository_states, :project_wiki_repository_id)
+ add_column :project_wiki_repository_states, :project_wiki_repository_id, :bigint
+ end
+ end
+
+ add_concurrent_index :project_wiki_repository_states,
+ :project_wiki_repository_id,
+ name: INDEX_NAME
+
+ add_concurrent_foreign_key :project_wiki_repository_states,
+ :project_wiki_repositories,
+ column: :project_wiki_repository_id,
+ on_delete: :cascade
+ end
+
+ def down
+ with_lock_retries do
+ if column_exists?(:project_wiki_repository_states, :project_wiki_repository_id)
+ remove_column :project_wiki_repository_states, :project_wiki_repository_id
+ end
+ end
+
+ remove_foreign_key_if_exists :project_wiki_repository_states, column: :project_wiki_repository_id
+ remove_concurrent_index_by_name :project_wiki_repository_states, name: INDEX_NAME
+ end
+end
diff --git a/db/migrate/20221110105857_add_index_for_in_product_marketing_email_metrics.rb b/db/migrate/20221110105857_add_index_for_in_product_marketing_email_metrics.rb
new file mode 100644
index 00000000000..f1bc07e4197
--- /dev/null
+++ b/db/migrate/20221110105857_add_index_for_in_product_marketing_email_metrics.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddIndexForInProductMarketingEmailMetrics < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_in_product_marketing_emails_on_track_series_id_clicked'
+
+ def up
+ add_concurrent_index :in_product_marketing_emails, %i[track series id cta_clicked_at], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :in_product_marketing_emails, INDEX_NAME
+ end
+end
diff --git a/db/migrate/20221110150942_add_project_id_lower_name_index_remove_old_index.rb b/db/migrate/20221110150942_add_project_id_lower_name_index_remove_old_index.rb
new file mode 100644
index 00000000000..dfff2f89610
--- /dev/null
+++ b/db/migrate/20221110150942_add_project_id_lower_name_index_remove_old_index.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class AddProjectIdLowerNameIndexRemoveOldIndex < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'index_im_timeline_event_tags_name_project_id'
+ NEW_INDEX_NAME = 'index_im_timeline_event_tags_on_lower_name_and_project_id'
+
+ disable_ddl_transaction!
+
+ def up
+ # Add new index
+ add_concurrent_index :incident_management_timeline_event_tags, 'project_id, LOWER(name)',
+ unique: true, name: NEW_INDEX_NAME
+
+ # Remove old index
+ remove_concurrent_index_by_name :incident_management_timeline_event_tags, INDEX_NAME
+ end
+
+ def down
+ # Add old index
+ add_concurrent_index :incident_management_timeline_event_tags, [:project_id, :name],
+ unique: true, name: INDEX_NAME
+
+ # Remove new index
+ remove_concurrent_index_by_name :incident_management_timeline_event_tags, NEW_INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20210311120155_backfill_events_id_for_bigint_conversion.rb b/db/post_migrate/20210311120155_backfill_events_id_for_bigint_conversion.rb
index b9427f7cc93..5d31cdb05e6 100644
--- a/db/post_migrate/20210311120155_backfill_events_id_for_bigint_conversion.rb
+++ b/db/post_migrate/20210311120155_backfill_events_id_for_bigint_conversion.rb
@@ -19,7 +19,7 @@ class BackfillEventsIdForBigintConversion < ActiveRecord::Migration[6.0]
Gitlab::Database::BackgroundMigration::BatchedMigration
.where(job_class_name: 'CopyColumnUsingBackgroundMigrationJob')
.where(table_name: 'events', column_name: 'id')
- .where(job_arguments: %w[id id_convert_to_bigint].to_json)
+ .where(job_arguments: Gitlab::Json.dump(%w[id id_convert_to_bigint]))
.delete_all
end
diff --git a/db/post_migrate/20210311120156_backfill_push_event_payload_event_id_for_bigint_conversion.rb b/db/post_migrate/20210311120156_backfill_push_event_payload_event_id_for_bigint_conversion.rb
index 0d610f1dde1..b64282fe0d3 100644
--- a/db/post_migrate/20210311120156_backfill_push_event_payload_event_id_for_bigint_conversion.rb
+++ b/db/post_migrate/20210311120156_backfill_push_event_payload_event_id_for_bigint_conversion.rb
@@ -20,7 +20,7 @@ class BackfillPushEventPayloadEventIdForBigintConversion < ActiveRecord::Migrati
Gitlab::Database::BackgroundMigration::BatchedMigration
.where(job_class_name: 'CopyColumnUsingBackgroundMigrationJob')
.where(table_name: 'push_event_payloads', column_name: 'event_id')
- .where(job_arguments: %w[event_id event_id_convert_to_bigint].to_json)
+ .where(job_arguments: Gitlab::Json.dump(%w[event_id event_id_convert_to_bigint]))
.delete_all
end
diff --git a/db/post_migrate/20210415101228_backfill_ci_build_needs_for_bigint_conversion.rb b/db/post_migrate/20210415101228_backfill_ci_build_needs_for_bigint_conversion.rb
index 1ee67cd9dda..8fcaeb3fb04 100644
--- a/db/post_migrate/20210415101228_backfill_ci_build_needs_for_bigint_conversion.rb
+++ b/db/post_migrate/20210415101228_backfill_ci_build_needs_for_bigint_conversion.rb
@@ -20,7 +20,7 @@ class BackfillCiBuildNeedsForBigintConversion < ActiveRecord::Migration[6.0]
Gitlab::Database::BackgroundMigration::BatchedMigration
.where(job_class_name: 'CopyColumnUsingBackgroundMigrationJob')
.where(table_name: 'ci_build_needs', column_name: 'build_id')
- .where(job_arguments: %w[build_id build_id_convert_to_bigint].to_json)
+ .where(job_arguments: Gitlab::Json.dump(%w[build_id build_id_convert_to_bigint]))
.delete_all
end
diff --git a/db/post_migrate/20210420121149_backfill_conversion_of_ci_job_artifacts.rb b/db/post_migrate/20210420121149_backfill_conversion_of_ci_job_artifacts.rb
index 67076cc647a..0c68834f723 100644
--- a/db/post_migrate/20210420121149_backfill_conversion_of_ci_job_artifacts.rb
+++ b/db/post_migrate/20210420121149_backfill_conversion_of_ci_job_artifacts.rb
@@ -19,7 +19,7 @@ class BackfillConversionOfCiJobArtifacts < ActiveRecord::Migration[6.0]
Gitlab::Database::BackgroundMigration::BatchedMigration
.where(job_class_name: 'CopyColumnUsingBackgroundMigrationJob')
.where(table_name: 'ci_job_artifacts', column_name: 'id')
- .where(job_arguments: [%w[id job_id], %w[id_convert_to_bigint job_id_convert_to_bigint]].to_json)
+ .where(job_arguments: Gitlab::Json.dump([%w[id job_id], %w[id_convert_to_bigint job_id_convert_to_bigint]]))
.delete_all
end
diff --git a/db/post_migrate/20210422023046_backfill_ci_sources_pipelines_source_job_id_for_bigint_conversion.rb b/db/post_migrate/20210422023046_backfill_ci_sources_pipelines_source_job_id_for_bigint_conversion.rb
index bde91473ee3..3c6f2385f1d 100644
--- a/db/post_migrate/20210422023046_backfill_ci_sources_pipelines_source_job_id_for_bigint_conversion.rb
+++ b/db/post_migrate/20210422023046_backfill_ci_sources_pipelines_source_job_id_for_bigint_conversion.rb
@@ -18,7 +18,7 @@ class BackfillCiSourcesPipelinesSourceJobIdForBigintConversion < ActiveRecord::M
Gitlab::Database::BackgroundMigration::BatchedMigration
.where(job_class_name: 'CopyColumnUsingBackgroundMigrationJob')
.where(table_name: 'ci_sources_pipelines', column_name: 'id')
- .where(job_arguments: [%w[source_job_id], %w[source_job_id_convert_to_bigint]].to_json)
+ .where(job_arguments: Gitlab::Json.dump([%w[source_job_id], %w[source_job_id_convert_to_bigint]]))
.delete_all
end
diff --git a/db/post_migrate/20210615234935_fix_batched_migrations_old_format_job_arguments.rb b/db/post_migrate/20210615234935_fix_batched_migrations_old_format_job_arguments.rb
index 535f7426938..818aea39762 100644
--- a/db/post_migrate/20210615234935_fix_batched_migrations_old_format_job_arguments.rb
+++ b/db/post_migrate/20210615234935_fix_batched_migrations_old_format_job_arguments.rb
@@ -17,8 +17,8 @@ class FixBatchedMigrationsOldFormatJobArguments < ActiveRecord::Migration[6.1]
# rubocop:disable Rails/WhereEquals
base_scope
- .where('job_arguments = ?', legacy_job_arguments.to_json)
- .where('NOT EXISTS (?)', base_scope.select('1').where('job_arguments = ?', current_job_arguments.to_json))
+ .where('job_arguments = ?', Gitlab::Json.dump(legacy_job_arguments))
+ .where('NOT EXISTS (?)', base_scope.select('1').where('job_arguments = ?', Gitlab::Json.dump(current_job_arguments)))
.update_all(job_arguments: current_job_arguments)
# rubocop:enable Rails/WhereEquals
end
diff --git a/db/post_migrate/20210818185845_backfill_projects_with_coverage.rb b/db/post_migrate/20210818185845_backfill_projects_with_coverage.rb
index 003b7536767..d86d49f4393 100644
--- a/db/post_migrate/20210818185845_backfill_projects_with_coverage.rb
+++ b/db/post_migrate/20210818185845_backfill_projects_with_coverage.rb
@@ -1,29 +1,8 @@
# frozen_string_literal: true
class BackfillProjectsWithCoverage < ActiveRecord::Migration[6.1]
- include Gitlab::Database::MigrationHelpers
-
- MIGRATION = 'BackfillProjectsWithCoverage'
- DELAY_INTERVAL = 2.minutes
- BATCH_SIZE = 10_000
- SUB_BATCH_SIZE = 1_000
-
- disable_ddl_transaction!
-
- class CiDailyBuildGroupReportResult < ActiveRecord::Base
- include EachBatch
-
- self.table_name = 'ci_daily_build_group_report_results'
- end
-
def up
- queue_background_migration_jobs_by_range_at_intervals(
- CiDailyBuildGroupReportResult,
- MIGRATION,
- DELAY_INTERVAL,
- batch_size: BATCH_SIZE,
- other_job_arguments: [SUB_BATCH_SIZE]
- )
+ # noop
end
def down
diff --git a/db/post_migrate/20220802112102_schedule_migrate_shared_vulnerability_scanners.rb b/db/post_migrate/20220802112102_schedule_migrate_shared_vulnerability_scanners.rb
index 92ca0998bae..724bd323169 100644
--- a/db/post_migrate/20220802112102_schedule_migrate_shared_vulnerability_scanners.rb
+++ b/db/post_migrate/20220802112102_schedule_migrate_shared_vulnerability_scanners.rb
@@ -1,34 +1,14 @@
# frozen_string_literal: true
class ScheduleMigrateSharedVulnerabilityScanners < Gitlab::Database::Migration[2.0]
- MIGRATION = "MigrateSharedVulnerabilityScanners"
- TABLE_NAME = :vulnerability_occurrences
- BATCH_COLUMN = :id
- DELAY_INTERVAL = 5.minutes
- BATCH_SIZE = 1000
- SUB_BATCH_SIZE = 100
-
- BATCH_MIN_VALUE = 23658505
- BATCH_MAX_VALUE = 204428752
-
disable_ddl_transaction!
restrict_gitlab_migration gitlab_schema: :gitlab_main
def up
- queue_batched_background_migration(
- MIGRATION,
- TABLE_NAME,
- BATCH_COLUMN,
- job_interval: DELAY_INTERVAL,
- batch_size: BATCH_SIZE,
- max_batch_size: BATCH_SIZE,
- sub_batch_size: SUB_BATCH_SIZE,
- batch_min_value: BATCH_MIN_VALUE,
- batch_max_value: BATCH_MAX_VALUE
- )
+ # no-op
end
def down
- delete_batched_background_migration(MIGRATION, TABLE_NAME, BATCH_COLUMN, [])
+ # no-op
end
end
diff --git a/db/post_migrate/20220919080303_delete_migrate_shared_vulnerability_scanners.rb b/db/post_migrate/20220919080303_delete_migrate_shared_vulnerability_scanners.rb
new file mode 100644
index 00000000000..4aedfcf1699
--- /dev/null
+++ b/db/post_migrate/20220919080303_delete_migrate_shared_vulnerability_scanners.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+class DeleteMigrateSharedVulnerabilityScanners < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ MIGRATION = "MigrateSharedVulnerabilityScanners"
+ TABLE_NAME = :vulnerability_occurrences
+ BATCH_COLUMN = :id
+ BATCH_SIZE = 250
+
+ class BatchedBackgroundMigration < MigrationRecord
+ self.table_name = "batched_background_migrations"
+ end
+
+ class BatchedBackgroundMigrationJob < MigrationRecord
+ include ::EachBatch
+
+ self.table_name = "batched_background_migration_jobs"
+
+ belongs_to :batched_background_migration
+ end
+
+ def up
+ return unless migration_id = BatchedBackgroundMigration.find_by(job_class_name: MIGRATION)&.id
+
+ # rubocop:disable Style/SymbolProc
+ BatchedBackgroundMigrationJob
+ .where(batched_background_migration_id: migration_id)
+ .each_batch(of: BATCH_SIZE) do |relation|
+ relation.delete_all
+ end
+ # rubocop:enable Style/SymbolProc
+
+ delete_batched_background_migration(MIGRATION,
+ TABLE_NAME,
+ BATCH_COLUMN,
+ [])
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20220919080304_reschedule_migrate_shared_vulnerability_scanners.rb b/db/post_migrate/20220919080304_reschedule_migrate_shared_vulnerability_scanners.rb
new file mode 100644
index 00000000000..69757085587
--- /dev/null
+++ b/db/post_migrate/20220919080304_reschedule_migrate_shared_vulnerability_scanners.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class RescheduleMigrateSharedVulnerabilityScanners < Gitlab::Database::Migration[2.0]
+ MIGRATION = "MigrateSharedVulnerabilityScanners"
+ TABLE_NAME = :vulnerability_occurrences
+ BATCH_COLUMN = :id
+ DELAY_INTERVAL = 5.minutes
+ BATCH_SIZE = 1000
+ SUB_BATCH_SIZE = 100
+
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ TABLE_NAME,
+ BATCH_COLUMN,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ max_batch_size: BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, TABLE_NAME, BATCH_COLUMN, [])
+ end
+end
diff --git a/db/post_migrate/20220927171740_prepare_for_vulnerability_occurrences_uuid_type_transition.rb b/db/post_migrate/20220927171740_prepare_for_vulnerability_occurrences_uuid_type_transition.rb
new file mode 100644
index 00000000000..e6f3384514d
--- /dev/null
+++ b/db/post_migrate/20220927171740_prepare_for_vulnerability_occurrences_uuid_type_transition.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+class PrepareForVulnerabilityOccurrencesUuidTypeTransition < Gitlab::Database::Migration[2.0]
+ enable_lock_retries!
+
+ TABLE = :vulnerability_occurrences
+ MAPPINGS = {
+ uuid: {
+ from_type: :string,
+ to_type: :uuid,
+ default_value: '00000000-0000-0000-0000-000000000000'
+ }
+ }
+
+ def up
+ create_temporary_columns_and_triggers(TABLE, MAPPINGS)
+ end
+
+ def down
+ columns = MAPPINGS.keys
+ temporary_columns = columns.map { |column| convert_to_type_column(column, :string, :uuid) }
+ trigger_name = rename_trigger_name(TABLE, columns, temporary_columns)
+ remove_rename_triggers(TABLE, trigger_name)
+ temporary_columns.each { |column| remove_column(TABLE, column) }
+ end
+end
diff --git a/db/post_migrate/20221004074910_routing_table_prepare_constraint_for_builds_metadata.rb b/db/post_migrate/20221004074910_routing_table_prepare_constraint_for_builds_metadata.rb
new file mode 100644
index 00000000000..013984154ae
--- /dev/null
+++ b/db/post_migrate/20221004074910_routing_table_prepare_constraint_for_builds_metadata.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+class RoutingTablePrepareConstraintForBuildsMetadata < Gitlab::Database::Migration[2.0]
+ include Gitlab::Database::PartitioningMigrationHelpers::TableManagementHelpers
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = :ci_builds_metadata
+ PARENT_TABLE_NAME = :p_ci_builds_metadata
+ FIRST_PARTITION = 100
+ PARTITION_COLUMN = :partition_id
+
+ def up
+ prepare_constraint_for_list_partitioning(
+ table_name: TABLE_NAME,
+ partitioning_column: PARTITION_COLUMN,
+ parent_table_name: PARENT_TABLE_NAME,
+ initial_partitioning_value: FIRST_PARTITION
+ )
+ end
+
+ def down
+ revert_preparing_constraint_for_list_partitioning(
+ table_name: TABLE_NAME,
+ partitioning_column: PARTITION_COLUMN,
+ parent_table_name: PARENT_TABLE_NAME,
+ initial_partitioning_value: FIRST_PARTITION
+ )
+ end
+end
diff --git a/db/post_migrate/20221004074914_create_routing_table_for_builds_metadata.rb b/db/post_migrate/20221004074914_create_routing_table_for_builds_metadata.rb
new file mode 100644
index 00000000000..a792fc91d3d
--- /dev/null
+++ b/db/post_migrate/20221004074914_create_routing_table_for_builds_metadata.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+class CreateRoutingTableForBuildsMetadata < Gitlab::Database::Migration[2.0]
+ def up; end
+
+ def down; end
+end
diff --git a/db/post_migrate/20221006070927_finalize_invalid_member_cleanup.rb b/db/post_migrate/20221006070927_finalize_invalid_member_cleanup.rb
new file mode 100644
index 00000000000..78786e46f5c
--- /dev/null
+++ b/db/post_migrate/20221006070927_finalize_invalid_member_cleanup.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class FinalizeInvalidMemberCleanup < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ MIGRATION = 'DestroyInvalidMembers'
+
+ def up
+ ensure_batched_background_migration_is_finished(
+ job_class_name: MIGRATION,
+ table_name: :members,
+ column_name: :id,
+ job_arguments: []
+ )
+ end
+
+ def down
+ # noop
+ end
+end
diff --git a/db/post_migrate/20221006172302_adjust_task_note_rename_background_migration_values.rb b/db/post_migrate/20221006172302_adjust_task_note_rename_background_migration_values.rb
index 2af16fb6d3c..b582b163e2d 100644
--- a/db/post_migrate/20221006172302_adjust_task_note_rename_background_migration_values.rb
+++ b/db/post_migrate/20221006172302_adjust_task_note_rename_background_migration_values.rb
@@ -20,7 +20,7 @@ class AdjustTaskNoteRenameBackgroundMigrationValues < Gitlab::Database::Migratio
scope :for_configuration, ->(job_class_name, table_name, column_name, job_arguments) do
where(job_class_name: job_class_name, table_name: table_name, column_name: column_name)
- .where("job_arguments = ?", job_arguments.to_json) # rubocop:disable Rails/WhereEquals
+ .where("job_arguments = ?", Gitlab::Json.dump(job_arguments)) # rubocop:disable Rails/WhereEquals
end
end
diff --git a/db/post_migrate/20221010141500_add_index_author_id_target_project_id_on_merge_requests.rb b/db/post_migrate/20221010141500_add_index_author_id_target_project_id_on_merge_requests.rb
new file mode 100644
index 00000000000..5b9d5be2b3f
--- /dev/null
+++ b/db/post_migrate/20221010141500_add_index_author_id_target_project_id_on_merge_requests.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddIndexAuthorIdTargetProjectIdOnMergeRequests < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'index_merge_requests_on_author_id_and_target_project_id'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :merge_requests, %i[author_id target_project_id], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :merge_requests, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221010162137_add_index_author_id_and_id_on_merge_requests.rb b/db/post_migrate/20221010162137_add_index_author_id_and_id_on_merge_requests.rb
new file mode 100644
index 00000000000..36184b5f573
--- /dev/null
+++ b/db/post_migrate/20221010162137_add_index_author_id_and_id_on_merge_requests.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddIndexAuthorIdAndIdOnMergeRequests < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'index_merge_requests_on_author_id_and_id'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :merge_requests, %i[author_id id], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :merge_requests, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221011062254_sync_new_amount_used_for_ci_project_monthly_usages.rb b/db/post_migrate/20221011062254_sync_new_amount_used_for_ci_project_monthly_usages.rb
new file mode 100644
index 00000000000..32943f10fcf
--- /dev/null
+++ b/db/post_migrate/20221011062254_sync_new_amount_used_for_ci_project_monthly_usages.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class SyncNewAmountUsedForCiProjectMonthlyUsages < Gitlab::Database::Migration[2.0]
+ restrict_gitlab_migration gitlab_schema: :gitlab_ci
+
+ def up
+ project_usages = define_batchable_model('ci_project_monthly_usages')
+
+ project_usages.each_batch(of: 500) do |batch|
+ batch.where('amount_used > 0').update_all('new_amount_used = amount_used')
+ end
+ end
+
+ def down
+ # Non reversible migration.
+ # This data migration keeps `new_amount_used` in sync with the old `amount_used`.
+ # In case of failure or interruption the migration can be retried.
+ end
+end
diff --git a/db/post_migrate/20221013215832_cleanup_vulnerability_state_transitions_with_same_from_state_to_state.rb b/db/post_migrate/20221013215832_cleanup_vulnerability_state_transitions_with_same_from_state_to_state.rb
new file mode 100644
index 00000000000..a81a80deb25
--- /dev/null
+++ b/db/post_migrate/20221013215832_cleanup_vulnerability_state_transitions_with_same_from_state_to_state.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class CleanupVulnerabilityStateTransitionsWithSameFromStateToState < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ class VulnerabilityStateTransition < MigrationRecord
+ self.table_name = 'vulnerability_state_transitions'
+ end
+
+ def up
+ VulnerabilityStateTransition.where('from_state = to_state').delete_all
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20221017084227_cleanup_rename_ci_pipeline_metadata_title.rb b/db/post_migrate/20221017084227_cleanup_rename_ci_pipeline_metadata_title.rb
new file mode 100644
index 00000000000..0829f3d8734
--- /dev/null
+++ b/db/post_migrate/20221017084227_cleanup_rename_ci_pipeline_metadata_title.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class CleanupRenameCiPipelineMetadataTitle < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ def up
+ cleanup_concurrent_column_rename :ci_pipeline_metadata, :title, :name
+ end
+
+ def down
+ undo_cleanup_concurrent_column_rename :ci_pipeline_metadata, :title, :name, batch_column_name: :pipeline_id
+ end
+end
diff --git a/db/post_migrate/20221018062308_schedule_backfill_project_namespace_details.rb b/db/post_migrate/20221018062308_schedule_backfill_project_namespace_details.rb
new file mode 100644
index 00000000000..74c8ef37ac2
--- /dev/null
+++ b/db/post_migrate/20221018062308_schedule_backfill_project_namespace_details.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class ScheduleBackfillProjectNamespaceDetails < Gitlab::Database::Migration[2.0]
+ MIGRATION = 'BackfillProjectNamespaceDetails'
+ INTERVAL = 2.minutes
+ BATCH_SIZE = 1_000
+ 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,
+ :projects,
+ :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, :projects, :id, [])
+ end
+end
diff --git a/db/post_migrate/20221018193635_ensure_task_note_renaming_background_migration_finished.rb b/db/post_migrate/20221018193635_ensure_task_note_renaming_background_migration_finished.rb
new file mode 100644
index 00000000000..c6ae0f185d8
--- /dev/null
+++ b/db/post_migrate/20221018193635_ensure_task_note_renaming_background_migration_finished.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class EnsureTaskNoteRenamingBackgroundMigrationFinished < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ MIGRATION = 'RenameTaskSystemNoteToChecklistItem'
+
+ def up
+ ensure_batched_background_migration_is_finished(
+ job_class_name: MIGRATION,
+ table_name: :system_note_metadata,
+ column_name: :id,
+ job_arguments: []
+ )
+ end
+
+ def down
+ # noop
+ end
+end
diff --git a/db/post_migrate/20221018193827_drop_tmp_index_system_note_metadata_on_id_where_task.rb b/db/post_migrate/20221018193827_drop_tmp_index_system_note_metadata_on_id_where_task.rb
new file mode 100644
index 00000000000..5cc70c530c6
--- /dev/null
+++ b/db/post_migrate/20221018193827_drop_tmp_index_system_note_metadata_on_id_where_task.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class DropTmpIndexSystemNoteMetadataOnIdWhereTask < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'tmp_index_system_note_metadata_on_id_where_task'
+
+ def up
+ remove_concurrent_index_by_name :system_note_metadata, INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :system_note_metadata, [:id, :action], where: "action = 'task'", name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221018232820_add_temp_index_for_user_details_fields.rb b/db/post_migrate/20221018232820_add_temp_index_for_user_details_fields.rb
new file mode 100644
index 00000000000..b46b316981d
--- /dev/null
+++ b/db/post_migrate/20221018232820_add_temp_index_for_user_details_fields.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class AddTempIndexForUserDetailsFields < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'tmp_idx_where_user_details_fields_filled'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :users, :id, name: INDEX_NAME, where: <<~QUERY
+ (COALESCE(linkedin, '') IS DISTINCT FROM '')
+ OR (COALESCE(twitter, '') IS DISTINCT FROM '')
+ OR (COALESCE(skype, '') IS DISTINCT FROM '')
+ OR (COALESCE(website_url, '') IS DISTINCT FROM '')
+ OR (COALESCE(location, '') IS DISTINCT FROM '')
+ OR (COALESCE(organization, '') IS DISTINCT FROM '')
+ QUERY
+ end
+
+ def down
+ remove_concurrent_index_by_name :users, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221019002459_queue_backfill_user_details_fields.rb b/db/post_migrate/20221019002459_queue_backfill_user_details_fields.rb
new file mode 100644
index 00000000000..8ed4416a98d
--- /dev/null
+++ b/db/post_migrate/20221019002459_queue_backfill_user_details_fields.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class QueueBackfillUserDetailsFields < Gitlab::Database::Migration[2.0]
+ MIGRATION = 'BackfillUserDetailsFields'
+ INTERVAL = 2.minutes
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(MIGRATION, :users, :id, job_interval: INTERVAL)
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :users, :id, [])
+ end
+end
diff --git a/db/post_migrate/20221019102426_remove_tmp_index_approval_merge_request_rules_on_report_type.rb b/db/post_migrate/20221019102426_remove_tmp_index_approval_merge_request_rules_on_report_type.rb
new file mode 100644
index 00000000000..7203d35de92
--- /dev/null
+++ b/db/post_migrate/20221019102426_remove_tmp_index_approval_merge_request_rules_on_report_type.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class RemoveTmpIndexApprovalMergeRequestRulesOnReportType < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'tmp_index_approval_merge_request_rules_on_report_type_equal_one'
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index_by_name :approval_merge_request_rules, INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :approval_merge_request_rules,
+ [:id, :report_type],
+ name: INDEX_NAME,
+ where: "report_type = 1"
+ end
+end
diff --git a/db/post_migrate/20221019105041_queue_populate_projects_star_count.rb b/db/post_migrate/20221019105041_queue_populate_projects_star_count.rb
new file mode 100644
index 00000000000..768e0c7826f
--- /dev/null
+++ b/db/post_migrate/20221019105041_queue_populate_projects_star_count.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class QueuePopulateProjectsStarCount < Gitlab::Database::Migration[2.0]
+ MIGRATION = 'PopulateProjectsStarCount'
+ DELAY_INTERVAL = 2.minutes
+
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :projects,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ sub_batch_size: 50
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :projects, :id, [])
+ end
+end
diff --git a/db/post_migrate/20221019141508_add_index_to_test_reports_issue_id_created_at_and_id.rb b/db/post_migrate/20221019141508_add_index_to_test_reports_issue_id_created_at_and_id.rb
new file mode 100644
index 00000000000..054512adf2e
--- /dev/null
+++ b/db/post_migrate/20221019141508_add_index_to_test_reports_issue_id_created_at_and_id.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class AddIndexToTestReportsIssueIdCreatedAtAndId < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ TABLE_NAME = 'requirements_management_test_reports'
+ INDEX_NAME = 'idx_test_reports_on_issue_id_created_at_and_id'
+
+ def up
+ add_concurrent_index TABLE_NAME, [:issue_id, :created_at, :id], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name TABLE_NAME, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221019194751_disable_fastupdate_on_issues_title_gin_index.rb b/db/post_migrate/20221019194751_disable_fastupdate_on_issues_title_gin_index.rb
new file mode 100644
index 00000000000..6ad846dda1c
--- /dev/null
+++ b/db/post_migrate/20221019194751_disable_fastupdate_on_issues_title_gin_index.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class DisableFastupdateOnIssuesTitleGinIndex < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_issues_on_title_trigram'
+
+ def up
+ with_lock_retries do
+ execute <<~SQL
+ ALTER INDEX #{INDEX_NAME} SET ( fastupdate = false ) ;
+ SQL
+ end
+ end
+
+ def down
+ with_lock_retries do
+ execute <<~SQL
+ ALTER INDEX #{INDEX_NAME} RESET ( fastupdate ) ;
+ SQL
+ end
+ end
+end
diff --git a/db/post_migrate/20221019195754_disable_fastupdate_on_issues_description_gin_index.rb b/db/post_migrate/20221019195754_disable_fastupdate_on_issues_description_gin_index.rb
new file mode 100644
index 00000000000..ce09a48833f
--- /dev/null
+++ b/db/post_migrate/20221019195754_disable_fastupdate_on_issues_description_gin_index.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class DisableFastupdateOnIssuesDescriptionGinIndex < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_issues_on_description_trigram'
+
+ def up
+ with_lock_retries do
+ execute <<~SQL
+ ALTER INDEX #{INDEX_NAME} SET ( fastupdate = false ) ;
+ SQL
+ end
+ end
+
+ def down
+ with_lock_retries do
+ execute <<~SQL
+ ALTER INDEX #{INDEX_NAME} RESET ( fastupdate ) ;
+ SQL
+ end
+ end
+end
diff --git a/db/post_migrate/20221019200033_disable_fastupdate_on_merge_requests_title_gin_index.rb b/db/post_migrate/20221019200033_disable_fastupdate_on_merge_requests_title_gin_index.rb
new file mode 100644
index 00000000000..eb4c413a5a9
--- /dev/null
+++ b/db/post_migrate/20221019200033_disable_fastupdate_on_merge_requests_title_gin_index.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class DisableFastupdateOnMergeRequestsTitleGinIndex < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_merge_requests_on_title_trigram'
+
+ def up
+ with_lock_retries do
+ execute <<~SQL
+ ALTER INDEX #{INDEX_NAME} SET ( fastupdate = false ) ;
+ SQL
+ end
+ end
+
+ def down
+ with_lock_retries do
+ execute <<~SQL
+ ALTER INDEX #{INDEX_NAME} RESET ( fastupdate ) ;
+ SQL
+ end
+ end
+end
diff --git a/db/post_migrate/20221019200206_disable_fastupdate_on_merge_requests_description_gin_index.rb b/db/post_migrate/20221019200206_disable_fastupdate_on_merge_requests_description_gin_index.rb
new file mode 100644
index 00000000000..2e55937db36
--- /dev/null
+++ b/db/post_migrate/20221019200206_disable_fastupdate_on_merge_requests_description_gin_index.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class DisableFastupdateOnMergeRequestsDescriptionGinIndex < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_merge_requests_on_description_trigram'
+
+ def up
+ with_lock_retries do
+ execute <<~SQL
+ ALTER INDEX #{INDEX_NAME} SET ( fastupdate = false ) ;
+ SQL
+ end
+ end
+
+ def down
+ with_lock_retries do
+ execute <<~SQL
+ ALTER INDEX #{INDEX_NAME} RESET ( fastupdate ) ;
+ SQL
+ end
+ end
+end
diff --git a/db/post_migrate/20221021082255_add_unique_index_on_ci_runners_token.rb b/db/post_migrate/20221021082255_add_unique_index_on_ci_runners_token.rb
new file mode 100644
index 00000000000..3dfa44f9615
--- /dev/null
+++ b/db/post_migrate/20221021082255_add_unique_index_on_ci_runners_token.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class AddUniqueIndexOnCiRunnersToken < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_uniq_ci_runners_on_token'
+
+ def up
+ finalize_background_migration 'ResetDuplicateCiRunnersTokenValues'
+
+ add_concurrent_index :ci_runners,
+ :token,
+ name: INDEX_NAME,
+ unique: true
+ end
+
+ def down
+ remove_concurrent_index_by_name :ci_runners, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221021082312_add_unique_index_on_ci_runners_token_encrypted.rb b/db/post_migrate/20221021082312_add_unique_index_on_ci_runners_token_encrypted.rb
new file mode 100644
index 00000000000..8728c0ff20e
--- /dev/null
+++ b/db/post_migrate/20221021082312_add_unique_index_on_ci_runners_token_encrypted.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class AddUniqueIndexOnCiRunnersTokenEncrypted < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_uniq_ci_runners_on_token_encrypted'
+
+ def up
+ finalize_background_migration 'ResetDuplicateCiRunnersTokenEncryptedValues'
+
+ add_concurrent_index :ci_runners,
+ :token_encrypted,
+ name: INDEX_NAME,
+ unique: true
+ end
+
+ def down
+ remove_concurrent_index_by_name :ci_runners, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221021082720_drop_index_on_ci_runners_token.rb b/db/post_migrate/20221021082720_drop_index_on_ci_runners_token.rb
new file mode 100644
index 00000000000..9125831fbf3
--- /dev/null
+++ b/db/post_migrate/20221021082720_drop_index_on_ci_runners_token.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class DropIndexOnCiRunnersToken < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_ci_runners_on_token'
+
+ def up
+ remove_concurrent_index_by_name :ci_runners, INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :ci_runners,
+ :token,
+ name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221021082734_drop_index_on_ci_runners_token_encrypted.rb b/db/post_migrate/20221021082734_drop_index_on_ci_runners_token_encrypted.rb
new file mode 100644
index 00000000000..39771fb5f85
--- /dev/null
+++ b/db/post_migrate/20221021082734_drop_index_on_ci_runners_token_encrypted.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class DropIndexOnCiRunnersTokenEncrypted < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_ci_runners_on_token_encrypted'
+
+ def up
+ remove_concurrent_index_by_name :ci_runners, INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :ci_runners,
+ :token_encrypted,
+ name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221021145820_create_routing_table_for_builds_metadata_v2.rb b/db/post_migrate/20221021145820_create_routing_table_for_builds_metadata_v2.rb
new file mode 100644
index 00000000000..e5f1ba5cb87
--- /dev/null
+++ b/db/post_migrate/20221021145820_create_routing_table_for_builds_metadata_v2.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+class CreateRoutingTableForBuildsMetadataV2 < Gitlab::Database::Migration[2.0]
+ include Gitlab::Database::PartitioningMigrationHelpers::TableManagementHelpers
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = :ci_builds_metadata
+ PARENT_TABLE_NAME = :p_ci_builds_metadata
+ FIRST_PARTITION = 100
+ PARTITION_COLUMN = :partition_id
+
+ def up
+ return if connection.table_exists?(PARENT_TABLE_NAME) && partition_attached?
+
+ convert_table_to_first_list_partition(
+ table_name: TABLE_NAME,
+ partitioning_column: PARTITION_COLUMN,
+ parent_table_name: PARENT_TABLE_NAME,
+ initial_partitioning_value: FIRST_PARTITION,
+ lock_tables: [:ci_builds, :ci_builds_metadata]
+ )
+ end
+
+ def down
+ revert_converting_table_to_first_list_partition(
+ table_name: TABLE_NAME,
+ partitioning_column: PARTITION_COLUMN,
+ parent_table_name: PARENT_TABLE_NAME,
+ initial_partitioning_value: FIRST_PARTITION
+ )
+ end
+
+ private
+
+ def partition_attached?
+ connection.select_value(<<~SQL)
+ SELECT true FROM postgres_partitions WHERE name = '#{TABLE_NAME}';
+ SQL
+ end
+end
diff --git a/db/post_migrate/20221021160735_add_index_for_common_finder_query_desc_with_namespace_id.rb b/db/post_migrate/20221021160735_add_index_for_common_finder_query_desc_with_namespace_id.rb
new file mode 100644
index 00000000000..d7c50010b72
--- /dev/null
+++ b/db/post_migrate/20221021160735_add_index_for_common_finder_query_desc_with_namespace_id.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddIndexForCommonFinderQueryDescWithNamespaceId < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'index_group_vulnerability_reads_common_finder_query_desc'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :vulnerability_reads,
+ [:namespace_id, :state, :report_type, :severity, :vulnerability_id],
+ name: INDEX_NAME,
+ order: { severity: :desc, vulnerability_id: :desc }
+ end
+
+ def down
+ remove_concurrent_index_by_name :vulnerability_reads, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221024034228_remove_sprints_project_id_column.rb b/db/post_migrate/20221024034228_remove_sprints_project_id_column.rb
new file mode 100644
index 00000000000..e30d6dce497
--- /dev/null
+++ b/db/post_migrate/20221024034228_remove_sprints_project_id_column.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+class RemoveSprintsProjectIdColumn < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ DATERANGE_CONSTRAINT_NAME = 'iteration_start_and_due_daterange_project_id_constraint'
+
+ def up
+ with_lock_retries do
+ remove_column :sprints, :project_id, :bigint if column_exists?(:sprints, :project_id)
+ end
+ end
+
+ def down
+ with_lock_retries do
+ add_column :sprints, :project_id, :bigint unless column_exists?(:sprints, :project_id)
+ end
+
+ with_lock_retries do
+ next if check_constraint_exists?(:sprints, DATERANGE_CONSTRAINT_NAME)
+
+ execute(<<~SQL)
+ ALTER TABLE sprints
+ ADD CONSTRAINT #{DATERANGE_CONSTRAINT_NAME}
+ EXCLUDE USING gist (project_id WITH =, daterange(start_date, due_date, '[]'::text) WITH &&)
+ WHERE (project_id IS NOT NULL)
+ SQL
+ end
+
+ add_check_constraint(:sprints,
+ 'project_id <> NULL::bigint AND group_id IS NULL OR group_id <> NULL::bigint AND project_id IS NULL',
+ 'sprints_must_belong_to_project_or_group')
+
+ add_concurrent_index :sprints, [:project_id, :iid], unique: true, name: 'index_sprints_on_project_id_and_iid'
+
+ add_concurrent_foreign_key :sprints, :projects, column: :project_id, on_delete: :cascade
+ end
+end
diff --git a/db/post_migrate/20221024121500_drop_fingerprint_from_sbom_sources.rb b/db/post_migrate/20221024121500_drop_fingerprint_from_sbom_sources.rb
new file mode 100644
index 00000000000..83856cbe5dd
--- /dev/null
+++ b/db/post_migrate/20221024121500_drop_fingerprint_from_sbom_sources.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+class DropFingerprintFromSbomSources < Gitlab::Database::Migration[2.0]
+ enable_lock_retries!
+
+ def change
+ remove_column :sbom_sources, :fingerprint, :bytea
+ end
+end
diff --git a/db/post_migrate/20221025115006_check_vulnerabilities_state_transition_from_state_not_equal_to_state.rb b/db/post_migrate/20221025115006_check_vulnerabilities_state_transition_from_state_not_equal_to_state.rb
new file mode 100644
index 00000000000..2ab7f8a9c04
--- /dev/null
+++ b/db/post_migrate/20221025115006_check_vulnerabilities_state_transition_from_state_not_equal_to_state.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class CheckVulnerabilitiesStateTransitionFromStateNotEqualToState < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ def up
+ add_check_constraint(:vulnerability_state_transitions, '(from_state != to_state)', constraint_name)
+ end
+
+ def down
+ remove_check_constraint(:vulnerability_state_transitions, constraint_name)
+ end
+
+ private
+
+ def constraint_name
+ check_constraint_name('vulnerability_state_transitions', 'fully_qualified_table_name', 'state_not_equal')
+ end
+end
diff --git a/db/post_migrate/20221025220607_add_index_id_on_scan_finding_approval_merge_request_rules.rb b/db/post_migrate/20221025220607_add_index_id_on_scan_finding_approval_merge_request_rules.rb
new file mode 100644
index 00000000000..4e72e7f95ec
--- /dev/null
+++ b/db/post_migrate/20221025220607_add_index_id_on_scan_finding_approval_merge_request_rules.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class AddIndexIdOnScanFindingApprovalMergeRequestRules < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'scan_finding_approval_mr_rule_index_id'
+ SCAN_FINDING_REPORT_TYPE = 4
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :approval_merge_request_rules, :id,
+ where: "report_type = #{SCAN_FINDING_REPORT_TYPE}", name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :approval_merge_request_rules, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221027203556_delete_experiment_user_foreign_keys.rb b/db/post_migrate/20221027203556_delete_experiment_user_foreign_keys.rb
new file mode 100644
index 00000000000..564dc3d4899
--- /dev/null
+++ b/db/post_migrate/20221027203556_delete_experiment_user_foreign_keys.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class DeleteExperimentUserForeignKeys < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ def up
+ with_lock_retries do
+ remove_foreign_key_if_exists :experiment_users, :experiments, name: 'fk_rails_56d4708b4a'
+ end
+
+ with_lock_retries do
+ remove_foreign_key_if_exists :experiment_users, :users, name: 'fk_rails_fd805f771a'
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key :experiment_users, :experiments, column: :experiment_id, name: 'fk_rails_56d4708b4a'
+ add_concurrent_foreign_key :experiment_users, :users, column: :user_id, name: 'fk_rails_fd805f771a'
+ end
+end
diff --git a/db/post_migrate/20221027203951_drop_experiment_users_table.rb b/db/post_migrate/20221027203951_drop_experiment_users_table.rb
new file mode 100644
index 00000000000..95455db98e5
--- /dev/null
+++ b/db/post_migrate/20221027203951_drop_experiment_users_table.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class DropExperimentUsersTable < Gitlab::Database::Migration[2.0]
+ def up
+ drop_table :experiment_users
+ end
+
+ def down
+ create_table :experiment_users do |t| # rubocop:disable Migration/SchemaAdditionMethodsNoPost
+ t.bigint :experiment_id, null: false
+ t.bigint :user_id, null: false
+ t.integer :group_type, limit: 2, null: false, default: 0
+ t.timestamps_with_timezone null: false
+ t.datetime_with_timezone :converted_at
+ t.jsonb :context, null: false, default: {}
+ end
+
+ add_index :experiment_users, :experiment_id
+ add_index :experiment_users, :user_id
+ end
+end
diff --git a/db/post_migrate/20221028000041_remove_invalid_partial_trigram_indexes_for_issues.rb b/db/post_migrate/20221028000041_remove_invalid_partial_trigram_indexes_for_issues.rb
new file mode 100644
index 00000000000..9b46647047a
--- /dev/null
+++ b/db/post_migrate/20221028000041_remove_invalid_partial_trigram_indexes_for_issues.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class RemoveInvalidPartialTrigramIndexesForIssues < Gitlab::Database::Migration[2.0]
+ TITLE_INDEX_NAME = 'index_issues_on_title_trigram_non_latin'
+ DESCRIPTION_INDEX_NAME = 'index_issues_on_description_trigram_non_latin'
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index_by_name :issues, TITLE_INDEX_NAME
+ remove_concurrent_index_by_name :issues, DESCRIPTION_INDEX_NAME
+ end
+
+ def down; end
+end
diff --git a/db/post_migrate/20221028000603_prepare_partial_trigram_indexes_for_issues_attempt_3.rb b/db/post_migrate/20221028000603_prepare_partial_trigram_indexes_for_issues_attempt_3.rb
new file mode 100644
index 00000000000..199a7a22d5b
--- /dev/null
+++ b/db/post_migrate/20221028000603_prepare_partial_trigram_indexes_for_issues_attempt_3.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+class PreparePartialTrigramIndexesForIssuesAttempt3 < Gitlab::Database::Migration[2.0]
+ TITLE_INDEX_NAME = 'index_issues_on_title_trigram_non_latin'
+ DESCRIPTION_INDEX_NAME = 'index_issues_on_description_trigram_non_latin'
+
+ def up
+ prepare_async_index :issues, :title,
+ name: TITLE_INDEX_NAME,
+ using: :gin, opclass: { description: :gin_trgm_ops },
+ where: "title NOT SIMILAR TO '[\\u0000-\\u02FF\\u1E00-\\u1EFF\\u2070-\\u218F]*' " \
+ "OR description NOT SIMILAR TO '[\\u0000-\\u02FF\\u1E00-\\u1EFF\\u2070-\\u218F]*'"
+
+ prepare_async_index :issues, :description,
+ name: DESCRIPTION_INDEX_NAME,
+ using: :gin, opclass: { description: :gin_trgm_ops },
+ where: "title NOT SIMILAR TO '[\\u0000-\\u02FF\\u1E00-\\u1EFF\\u2070-\\u218F]*' " \
+ "OR description NOT SIMILAR TO '[\\u0000-\\u02FF\\u1E00-\\u1EFF\\u2070-\\u218F]*'"
+ end
+
+ def down
+ unprepare_async_index_by_name :issues, DESCRIPTION_INDEX_NAME
+ unprepare_async_index_by_name :issues, TITLE_INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221028022627_add_index_on_password_last_changed_at_to_user_details.rb b/db/post_migrate/20221028022627_add_index_on_password_last_changed_at_to_user_details.rb
new file mode 100644
index 00000000000..8314767ade1
--- /dev/null
+++ b/db/post_migrate/20221028022627_add_index_on_password_last_changed_at_to_user_details.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddIndexOnPasswordLastChangedAtToUserDetails < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'index_user_details_on_password_last_changed_at'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :user_details, :password_last_changed_at, name: INDEX_NAME, comment: 'JiHu-specific index'
+ end
+
+ def down
+ remove_concurrent_index_by_name :user_details, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221102090940_create_next_ci_partitions_record.rb b/db/post_migrate/20221102090940_create_next_ci_partitions_record.rb
new file mode 100644
index 00000000000..4bd89a70daa
--- /dev/null
+++ b/db/post_migrate/20221102090940_create_next_ci_partitions_record.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class CreateNextCiPartitionsRecord < Gitlab::Database::Migration[2.0]
+ NEXT_PARTITION_ID = 101
+
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_ci
+
+ def up
+ return unless Gitlab.com?
+
+ execute(<<~SQL)
+ INSERT INTO "ci_partitions" ("id", "created_at", "updated_at")
+ VALUES (#{NEXT_PARTITION_ID}, now(), now())
+ ON CONFLICT DO NOTHING;
+ SQL
+
+ reset_pk_sequence!('ci_partitions')
+ end
+
+ def down
+ return unless Gitlab.com?
+
+ execute(<<~SQL)
+ DELETE FROM "ci_partitions"
+ WHERE "ci_partitions"."id" = #{NEXT_PARTITION_ID};
+ SQL
+ end
+end
diff --git a/db/post_migrate/20221102090943_create_second_partition_for_builds_metadata.rb b/db/post_migrate/20221102090943_create_second_partition_for_builds_metadata.rb
new file mode 100644
index 00000000000..6923e6f6cba
--- /dev/null
+++ b/db/post_migrate/20221102090943_create_second_partition_for_builds_metadata.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+class CreateSecondPartitionForBuildsMetadata < Gitlab::Database::Migration[2.0]
+ TABLE_NAME = 'p_ci_builds_metadata'
+ BUILDS_TABLE = 'ci_builds'
+ NEXT_PARTITION_ID = 101
+ PARTITION_NAME = 'gitlab_partitions_dynamic.ci_builds_metadata_101'
+
+ disable_ddl_transaction!
+
+ def up
+ return unless Gitlab.com?
+
+ 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 (#{NEXT_PARTITION_ID});
+ SQL
+ end
+ end
+
+ def down
+ return unless Gitlab.com?
+ return unless table_exists?(PARTITION_NAME)
+
+ with_lock_retries(**lock_args) do
+ connection.execute(<<~SQL)
+ LOCK TABLE #{BUILDS_TABLE}, #{TABLE_NAME}, #{PARTITION_NAME} IN ACCESS EXCLUSIVE MODE;
+ SQL
+
+ connection.execute(<<~SQL)
+ ALTER TABLE #{TABLE_NAME} DETACH PARTITION #{PARTITION_NAME};
+ SQL
+
+ connection.execute(<<~SQL)
+ DROP TABLE IF EXISTS #{PARTITION_NAME} CASCADE;
+ SQL
+ end
+ 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/post_migrate/20221103073328_change_member_namespace_id_not_null.rb b/db/post_migrate/20221103073328_change_member_namespace_id_not_null.rb
new file mode 100644
index 00000000000..19f6732d297
--- /dev/null
+++ b/db/post_migrate/20221103073328_change_member_namespace_id_not_null.rb
@@ -0,0 +1,16 @@
+# 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 ChangeMemberNamespaceIdNotNull < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ def up
+ add_not_null_constraint :members, :member_namespace_id, validate: false
+ end
+
+ def down
+ remove_not_null_constraint :members, :member_namespace_id
+ end
+end
diff --git a/db/post_migrate/20221103084213_remove_tmp_index_members_on_id_where_namespace_id_null.rb b/db/post_migrate/20221103084213_remove_tmp_index_members_on_id_where_namespace_id_null.rb
new file mode 100644
index 00000000000..07908e697f5
--- /dev/null
+++ b/db/post_migrate/20221103084213_remove_tmp_index_members_on_id_where_namespace_id_null.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class RemoveTmpIndexMembersOnIdWhereNamespaceIdNull < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'tmp_index_members_on_id_where_namespace_id_null'
+
+ disable_ddl_transaction!
+
+ def up
+ remove_concurrent_index_by_name :members, INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :members, :id, name: INDEX_NAME, where: 'member_namespace_id IS NULL'
+ end
+end
diff --git a/db/post_migrate/20221103150250_migrate_sidekiq_queued_jobs.rb b/db/post_migrate/20221103150250_migrate_sidekiq_queued_jobs.rb
new file mode 100644
index 00000000000..1934711f9ef
--- /dev/null
+++ b/db/post_migrate/20221103150250_migrate_sidekiq_queued_jobs.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class MigrateSidekiqQueuedJobs < Gitlab::Database::Migration[2.0]
+ def up
+ # no-op because of https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20221104042137_add_partial_trigram_index_for_issue_title_attempt_2.rb b/db/post_migrate/20221104042137_add_partial_trigram_index_for_issue_title_attempt_2.rb
new file mode 100644
index 00000000000..24204577959
--- /dev/null
+++ b/db/post_migrate/20221104042137_add_partial_trigram_index_for_issue_title_attempt_2.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddPartialTrigramIndexForIssueTitleAttempt2 < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_issues_on_title_trigram_non_latin'
+
+ def up
+ add_concurrent_index :issues, :title,
+ name: INDEX_NAME,
+ using: :gin, opclass: { description: :gin_trgm_ops },
+ where: "title NOT SIMILAR TO '[\\u0000-\\u02FF\\u1E00-\\u1EFF\\u2070-\\u218F]*' " \
+ "OR description NOT SIMILAR TO '[\\u0000-\\u02FF\\u1E00-\\u1EFF\\u2070-\\u218F]*'"
+ end
+
+ def down
+ remove_concurrent_index_by_name :issues, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221104042159_add_partial_trigram_index_for_issue_description_attempt_2.rb b/db/post_migrate/20221104042159_add_partial_trigram_index_for_issue_description_attempt_2.rb
new file mode 100644
index 00000000000..36b595d1067
--- /dev/null
+++ b/db/post_migrate/20221104042159_add_partial_trigram_index_for_issue_description_attempt_2.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddPartialTrigramIndexForIssueDescriptionAttempt2 < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_issues_on_description_trigram_non_latin'
+
+ def up
+ add_concurrent_index :issues, :description,
+ name: INDEX_NAME,
+ using: :gin, opclass: { description: :gin_trgm_ops },
+ where: "title NOT SIMILAR TO '[\\u0000-\\u02FF\\u1E00-\\u1EFF\\u2070-\\u218F]*' " \
+ "OR description NOT SIMILAR TO '[\\u0000-\\u02FF\\u1E00-\\u1EFF\\u2070-\\u218F]*'"
+ end
+
+ def down
+ remove_concurrent_index_by_name :issues, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221104074652_add_temp_index_for_project_statistics_upload_size_migration.rb b/db/post_migrate/20221104074652_add_temp_index_for_project_statistics_upload_size_migration.rb
new file mode 100644
index 00000000000..b6ee636fa9b
--- /dev/null
+++ b/db/post_migrate/20221104074652_add_temp_index_for_project_statistics_upload_size_migration.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddTempIndexForProjectStatisticsUploadSizeMigration < Gitlab::Database::Migration[2.0]
+ INDEX_PROJECT_STATSISTICS_UPLOADS_SIZE = 'tmp_index_project_statistics_uploads_size'
+
+ disable_ddl_transaction!
+
+ def up
+ # Temporary index is to be used to trigger refresh for all project_statistics with
+ # upload_size <> 0
+ add_concurrent_index :project_statistics, [:project_id],
+ name: INDEX_PROJECT_STATSISTICS_UPLOADS_SIZE,
+ where: "uploads_size <> 0"
+ end
+
+ def down
+ remove_concurrent_index_by_name :project_statistics, INDEX_PROJECT_STATSISTICS_UPLOADS_SIZE
+ end
+end
diff --git a/db/post_migrate/20221104100203_recreate_async_trigram_index_for_vulnerability_reads_container_images.rb b/db/post_migrate/20221104100203_recreate_async_trigram_index_for_vulnerability_reads_container_images.rb
new file mode 100644
index 00000000000..ea2914f4dc4
--- /dev/null
+++ b/db/post_migrate/20221104100203_recreate_async_trigram_index_for_vulnerability_reads_container_images.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class RecreateAsyncTrigramIndexForVulnerabilityReadsContainerImages < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'index_vulnerability_reads_on_location_image_trigram'
+ REPORT_TYPES = { container_scanning: 2, cluster_image_scanning: 7 }.freeze
+
+ def up
+ remove_concurrent_index_by_name :vulnerability_reads, INDEX_NAME
+
+ prepare_async_index :vulnerability_reads, :location_image,
+ name: INDEX_NAME,
+ using: :gin, opclass: { location_image: :gin_trgm_ops },
+ where: "report_type = ANY (ARRAY[#{REPORT_TYPES.values.join(', ')}]) AND location_image IS NOT NULL"
+ end
+
+ def down
+ unprepare_async_index :vulnerability_reads, :location_image, name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221104170500_add_vulnerability_reads_all_status_index.rb b/db/post_migrate/20221104170500_add_vulnerability_reads_all_status_index.rb
new file mode 100644
index 00000000000..1dc1921ebaa
--- /dev/null
+++ b/db/post_migrate/20221104170500_add_vulnerability_reads_all_status_index.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+class AddVulnerabilityReadsAllStatusIndex < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = 'index_vulnerability_reads_on_namespace_type_severity_id'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :vulnerability_reads, %i[namespace_id report_type severity vulnerability_id], name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :vulnerability_reads, INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20221104190203_validate_environment_id_on_deployments.rb b/db/post_migrate/20221104190203_validate_environment_id_on_deployments.rb
new file mode 100644
index 00000000000..9546daa3975
--- /dev/null
+++ b/db/post_migrate/20221104190203_validate_environment_id_on_deployments.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+class ValidateEnvironmentIdOnDeployments < Gitlab::Database::Migration[2.0]
+ def up
+ validate_foreign_key :deployments, :environment_id
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20221107094359_recount_epic_cache_counts.rb b/db/post_migrate/20221107094359_recount_epic_cache_counts.rb
new file mode 100644
index 00000000000..37ab952edba
--- /dev/null
+++ b/db/post_migrate/20221107094359_recount_epic_cache_counts.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class RecountEpicCacheCounts < Gitlab::Database::Migration[2.0]
+ MIGRATION = 'RecountEpicCacheCounts'
+ DELAY_INTERVAL = 2.minutes.to_i
+ BATCH_SIZE = 200
+ MAX_BATCH_SIZE = 1000
+ SUB_BATCH_SIZE = 20
+
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :epics,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ max_batch_size: MAX_BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE,
+ gitlab_schema: :gitlab_main
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :epics, :id, [])
+ end
+end
diff --git a/db/post_migrate/20221107184758_sync_new_amount_used_for_ci_namespace_monthly_usages.rb b/db/post_migrate/20221107184758_sync_new_amount_used_for_ci_namespace_monthly_usages.rb
new file mode 100644
index 00000000000..9a6014b5c94
--- /dev/null
+++ b/db/post_migrate/20221107184758_sync_new_amount_used_for_ci_namespace_monthly_usages.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class SyncNewAmountUsedForCiNamespaceMonthlyUsages < Gitlab::Database::Migration[2.0]
+ restrict_gitlab_migration gitlab_schema: :gitlab_ci
+
+ def up
+ namespace_usages = define_batchable_model('ci_namespace_monthly_usages')
+
+ namespace_usages.each_batch(of: 500) do |batch|
+ batch.where('amount_used > 0').update_all('new_amount_used = amount_used')
+ end
+ end
+
+ def down
+ # Non reversible migration.
+ # This data migration keeps `new_amount_used` in sync with the old `amount_used`.
+ # In case of failure or interruption the migration can be retried.
+ end
+end
diff --git a/db/post_migrate/20221107220420_validate_not_null_constraint_on_member_namespace_id.rb b/db/post_migrate/20221107220420_validate_not_null_constraint_on_member_namespace_id.rb
new file mode 100644
index 00000000000..48da0c1fd09
--- /dev/null
+++ b/db/post_migrate/20221107220420_validate_not_null_constraint_on_member_namespace_id.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class ValidateNotNullConstraintOnMemberNamespaceId < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ CONSTRAINT_NAME = 'check_508774aac0'
+
+ def up
+ validate_not_null_constraint :members, :member_namespace_id, constraint_name: CONSTRAINT_NAME
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20221107220526_validate_fk_member_namespace_id.rb b/db/post_migrate/20221107220526_validate_fk_member_namespace_id.rb
new file mode 100644
index 00000000000..f78dc5a36fd
--- /dev/null
+++ b/db/post_migrate/20221107220526_validate_fk_member_namespace_id.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class ValidateFkMemberNamespaceId < Gitlab::Database::Migration[2.0]
+ CONSTRAINT_NAME = 'fk_2f85abf8f1'
+
+ def up
+ validate_foreign_key :members, :member_namespace_id, name: CONSTRAINT_NAME
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20221107222213_remove_old_member_namespace_id_fk.rb b/db/post_migrate/20221107222213_remove_old_member_namespace_id_fk.rb
new file mode 100644
index 00000000000..d46fa80336e
--- /dev/null
+++ b/db/post_migrate/20221107222213_remove_old_member_namespace_id_fk.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+class RemoveOldMemberNamespaceIdFk < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ TARGET_COLUMN = :member_namespace_id
+
+ def up
+ with_lock_retries do
+ remove_foreign_key_if_exists(:members, column: TARGET_COLUMN, name: fk_name(TARGET_COLUMN))
+ end
+ end
+
+ def down
+ add_concurrent_foreign_key(
+ :members,
+ :namespaces,
+ column: TARGET_COLUMN,
+ name: fk_name(TARGET_COLUMN),
+ on_delete: :nullify
+ )
+ end
+
+ def fk_name(column_name)
+ # generate a FK name
+ concurrent_foreign_key_name(:members, column_name)
+ end
+end
diff --git a/db/post_migrate/20221108045019_truncate_timeline_event_tags_table.rb b/db/post_migrate/20221108045019_truncate_timeline_event_tags_table.rb
new file mode 100644
index 00000000000..37e6a21abed
--- /dev/null
+++ b/db/post_migrate/20221108045019_truncate_timeline_event_tags_table.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class TruncateTimelineEventTagsTable < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ def up
+ execute('TRUNCATE TABLE incident_management_timeline_event_tags, incident_management_timeline_event_tag_links')
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/post_migrate/20221108121322_add_supporting_index_for_vulnerabilities_feedback_migration.rb b/db/post_migrate/20221108121322_add_supporting_index_for_vulnerabilities_feedback_migration.rb
new file mode 100644
index 00000000000..c77930512d2
--- /dev/null
+++ b/db/post_migrate/20221108121322_add_supporting_index_for_vulnerabilities_feedback_migration.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+class AddSupportingIndexForVulnerabilitiesFeedbackMigration < Gitlab::Database::Migration[2.0]
+ INDEX_NAME = "tmp_idx_for_vulnerability_feedback_migration"
+ WHERE_CLAUSE = "migrated_to_state_transition = false AND feedback_type = 0"
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index(
+ :vulnerability_feedback,
+ %i[migrated_to_state_transition feedback_type],
+ where: WHERE_CLAUSE,
+ name: INDEX_NAME
+ )
+ end
+
+ def down
+ remove_concurrent_index_by_name(
+ :vulnerability_feedback,
+ INDEX_NAME
+ )
+ end
+end
diff --git a/db/post_migrate/20221108222015_remove_temp_index_on_project_features_where_releases_access_level_gt_repository.rb b/db/post_migrate/20221108222015_remove_temp_index_on_project_features_where_releases_access_level_gt_repository.rb
new file mode 100644
index 00000000000..e7cc6786b4b
--- /dev/null
+++ b/db/post_migrate/20221108222015_remove_temp_index_on_project_features_where_releases_access_level_gt_repository.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class RemoveTempIndexOnProjectFeaturesWhereReleasesAccessLevelGtRepository < Gitlab::Database::Migration[2.0]
+ disable_ddl_transaction!
+
+ INDEX_NAME = 'tmp_idx_project_features_on_releases_al_and_repo_al_partial'
+
+ def up
+ remove_concurrent_index_by_name :project_features, INDEX_NAME
+ end
+
+ def down
+ add_concurrent_index :project_features,
+ [:releases_access_level, :repository_access_level],
+ name: INDEX_NAME,
+ where: 'releases_access_level > repository_access_level'
+ end
+end
diff --git a/db/post_migrate/20221110045406_sanitize_confidential_note_todos.rb b/db/post_migrate/20221110045406_sanitize_confidential_note_todos.rb
new file mode 100644
index 00000000000..f98be3f036f
--- /dev/null
+++ b/db/post_migrate/20221110045406_sanitize_confidential_note_todos.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+class SanitizeConfidentialNoteTodos < Gitlab::Database::Migration[2.0]
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ MIGRATION = 'SanitizeConfidentialTodos'
+ DELAY_INTERVAL = 2.minutes.to_i
+ BATCH_SIZE = 200
+ MAX_BATCH_SIZE = 1000
+ SUB_BATCH_SIZE = 20
+
+ disable_ddl_transaction!
+ restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+ def up
+ queue_batched_background_migration(
+ MIGRATION,
+ :notes,
+ :id,
+ job_interval: DELAY_INTERVAL,
+ batch_size: BATCH_SIZE,
+ max_batch_size: MAX_BATCH_SIZE,
+ sub_batch_size: SUB_BATCH_SIZE,
+ gitlab_schema: :gitlab_main
+ )
+ end
+
+ def down
+ delete_batched_background_migration(MIGRATION, :notes, :id, [])
+ end
+end
diff --git a/db/post_migrate/20221111070314_prepare_removal_of_issue_trigram_indexes.rb b/db/post_migrate/20221111070314_prepare_removal_of_issue_trigram_indexes.rb
new file mode 100644
index 00000000000..c4cae19497e
--- /dev/null
+++ b/db/post_migrate/20221111070314_prepare_removal_of_issue_trigram_indexes.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+class PrepareRemovalOfIssueTrigramIndexes < Gitlab::Database::Migration[2.0]
+ TITLE_INDEX_NAME = 'index_issues_on_title_trigram'
+ DESCRIPTION_INDEX_NAME = 'index_issues_on_description_trigram'
+
+ def up
+ prepare_async_index_removal :issues, :title, name: TITLE_INDEX_NAME
+ prepare_async_index_removal :issues, :description, name: DESCRIPTION_INDEX_NAME
+ end
+
+ def down
+ unprepare_async_index_by_name :issues, DESCRIPTION_INDEX_NAME
+ unprepare_async_index_by_name :issues, TITLE_INDEX_NAME
+ end
+end
diff --git a/db/schema_migrations/20220613112029 b/db/schema_migrations/20220613112029
new file mode 100644
index 00000000000..d0bb2de83b5
--- /dev/null
+++ b/db/schema_migrations/20220613112029
@@ -0,0 +1 @@
+04a04a34de63b17f02a6b1333854638ae3b44d284e5ce2fcbee6fb3ec06b7757 \ No newline at end of file
diff --git a/db/schema_migrations/20220613112030 b/db/schema_migrations/20220613112030
new file mode 100644
index 00000000000..3dda586034d
--- /dev/null
+++ b/db/schema_migrations/20220613112030
@@ -0,0 +1 @@
+3d1b1394aa1b5db83867b284f119ec711255d2a01b78720d42c0a1acfe93c94f \ No newline at end of file
diff --git a/db/schema_migrations/20220613112031 b/db/schema_migrations/20220613112031
new file mode 100644
index 00000000000..dc0d913e1eb
--- /dev/null
+++ b/db/schema_migrations/20220613112031
@@ -0,0 +1 @@
+30d48cf8219cb4bcfeac454d7baf70d05f0285bdac519e4a1fb9f1c412267a9d \ No newline at end of file
diff --git a/db/schema_migrations/20220613112032 b/db/schema_migrations/20220613112032
new file mode 100644
index 00000000000..f1c0d9c80e6
--- /dev/null
+++ b/db/schema_migrations/20220613112032
@@ -0,0 +1 @@
+c8c26dad8d11b3715fce07ee9bedc9c4f66d2454646d58994e1568758f240299 \ No newline at end of file
diff --git a/db/schema_migrations/20220721065723 b/db/schema_migrations/20220721065723
new file mode 100644
index 00000000000..78b1fedaff1
--- /dev/null
+++ b/db/schema_migrations/20220721065723
@@ -0,0 +1 @@
+5e3fbb2c033f8512e5fd14b8ce8c6088866c596a2b769e115dcc1feb9ce9d041 \ No newline at end of file
diff --git a/db/schema_migrations/20220919062640 b/db/schema_migrations/20220919062640
new file mode 100644
index 00000000000..0284cadd6d6
--- /dev/null
+++ b/db/schema_migrations/20220919062640
@@ -0,0 +1 @@
+6b4e0ed9d29ace12f6ae1d4b8177ef998f9a5a3915cca80fa546a9f90ccde887 \ No newline at end of file
diff --git a/db/schema_migrations/20220919080303 b/db/schema_migrations/20220919080303
new file mode 100644
index 00000000000..081e25c4ed5
--- /dev/null
+++ b/db/schema_migrations/20220919080303
@@ -0,0 +1 @@
+9a5ba202075e0022defd834184aa59c60980cdccf7f4111834af6a119713b4c2 \ No newline at end of file
diff --git a/db/schema_migrations/20220919080304 b/db/schema_migrations/20220919080304
new file mode 100644
index 00000000000..263128018ca
--- /dev/null
+++ b/db/schema_migrations/20220919080304
@@ -0,0 +1 @@
+d5883d3edad5d8cc130f26feb4cc6fdb63e3b46c513ce463bdf7e45a8d7ffcdf \ No newline at end of file
diff --git a/db/schema_migrations/20220920135632 b/db/schema_migrations/20220920135632
new file mode 100644
index 00000000000..b20c7886bf9
--- /dev/null
+++ b/db/schema_migrations/20220920135632
@@ -0,0 +1 @@
+ec4d492f229e78a8f0efd8691a0a3f04d5f8125d8e1c7d0f93b45faa034108f7 \ No newline at end of file
diff --git a/db/schema_migrations/20220920135717 b/db/schema_migrations/20220920135717
new file mode 100644
index 00000000000..7e64f02956c
--- /dev/null
+++ b/db/schema_migrations/20220920135717
@@ -0,0 +1 @@
+06c73930dcc4ce0edfe5fa57ff721b6799f6458ff68f3c37c0eaf1745c8db1f1 \ No newline at end of file
diff --git a/db/schema_migrations/20220926023734 b/db/schema_migrations/20220926023734
new file mode 100644
index 00000000000..2fd1175b02d
--- /dev/null
+++ b/db/schema_migrations/20220926023734
@@ -0,0 +1 @@
+efa3d1c94b5de9c68ae3d007e95bbbae9582f4354e922b00a02ff5753dbe4d05 \ No newline at end of file
diff --git a/db/schema_migrations/20220927171740 b/db/schema_migrations/20220927171740
new file mode 100644
index 00000000000..e775b211200
--- /dev/null
+++ b/db/schema_migrations/20220927171740
@@ -0,0 +1 @@
+5ba49d525d6238975f990c94972ee4f3587a2446a4873e6e8a7f4791cf015b7e \ No newline at end of file
diff --git a/db/schema_migrations/20221003151747 b/db/schema_migrations/20221003151747
new file mode 100644
index 00000000000..70a8babf308
--- /dev/null
+++ b/db/schema_migrations/20221003151747
@@ -0,0 +1 @@
+84b89419404d26f7d2783a3adf1fa7b7d89417d6533b393ae6e0de40a31e299a \ No newline at end of file
diff --git a/db/schema_migrations/20221004074910 b/db/schema_migrations/20221004074910
new file mode 100644
index 00000000000..e316408ef0f
--- /dev/null
+++ b/db/schema_migrations/20221004074910
@@ -0,0 +1 @@
+df8b2f83f93fecd3450cb7fc2619e7ddbfde014a885d0a414076908bbcbbdf9f \ No newline at end of file
diff --git a/db/schema_migrations/20221004074914 b/db/schema_migrations/20221004074914
new file mode 100644
index 00000000000..a197fe1b9ea
--- /dev/null
+++ b/db/schema_migrations/20221004074914
@@ -0,0 +1 @@
+d6459263b828e6807f473adb7ba534d78055ab1b5137478a8e96cd500297ff54 \ No newline at end of file
diff --git a/db/schema_migrations/20221006070927 b/db/schema_migrations/20221006070927
new file mode 100644
index 00000000000..804f77384e0
--- /dev/null
+++ b/db/schema_migrations/20221006070927
@@ -0,0 +1 @@
+933cb5a869696f2343b0b8dfc32f94a64ed7a5119c3f6b2b64ce30e3ae4e555c \ No newline at end of file
diff --git a/db/schema_migrations/20221010103207 b/db/schema_migrations/20221010103207
new file mode 100644
index 00000000000..24fcfc34c41
--- /dev/null
+++ b/db/schema_migrations/20221010103207
@@ -0,0 +1 @@
+04997da3ff51b8be05fd765c6534f92a15eea0a4ee4a535f1cb84c6da4e1bdd5 \ No newline at end of file
diff --git a/db/schema_migrations/20221010141500 b/db/schema_migrations/20221010141500
new file mode 100644
index 00000000000..8479fb0519c
--- /dev/null
+++ b/db/schema_migrations/20221010141500
@@ -0,0 +1 @@
+250ec3ff701dacd333d669f128762e9f035a626f2f7720c6e7e1dc61499d431d \ No newline at end of file
diff --git a/db/schema_migrations/20221010162137 b/db/schema_migrations/20221010162137
new file mode 100644
index 00000000000..567b788a5c6
--- /dev/null
+++ b/db/schema_migrations/20221010162137
@@ -0,0 +1 @@
+c9f5827072920fdc52efeaf1ab39c67c48896a6288c5720e4be96070340ce6d8 \ No newline at end of file
diff --git a/db/schema_migrations/20221010184839 b/db/schema_migrations/20221010184839
new file mode 100644
index 00000000000..de24fc0a4f0
--- /dev/null
+++ b/db/schema_migrations/20221010184839
@@ -0,0 +1 @@
+062f807c0bf823b00e19cc55323faedd506b19d6492d1f23f09aaa662eaddcfb \ No newline at end of file
diff --git a/db/schema_migrations/20221010201815 b/db/schema_migrations/20221010201815
new file mode 100644
index 00000000000..8c4c06ba4f6
--- /dev/null
+++ b/db/schema_migrations/20221010201815
@@ -0,0 +1 @@
+f1f30c3581e35a92f3ede694e1eb70c6fc4dccfdb9e377b5f9046e18eaca2c54 \ No newline at end of file
diff --git a/db/schema_migrations/20221010202339 b/db/schema_migrations/20221010202339
new file mode 100644
index 00000000000..c536fc8a3dc
--- /dev/null
+++ b/db/schema_migrations/20221010202339
@@ -0,0 +1 @@
+33bbeaa1d94cfa936de422fcc2f0456d235dde13072f6907cd514a12956ef9aa \ No newline at end of file
diff --git a/db/schema_migrations/20221010202408 b/db/schema_migrations/20221010202408
new file mode 100644
index 00000000000..2007c27f7fd
--- /dev/null
+++ b/db/schema_migrations/20221010202408
@@ -0,0 +1 @@
+0e985bac7558768e0b97316c1362cb411fed5605c0a313c3872e86f7242f8d36 \ No newline at end of file
diff --git a/db/schema_migrations/20221011062254 b/db/schema_migrations/20221011062254
new file mode 100644
index 00000000000..a64a2dd4bfe
--- /dev/null
+++ b/db/schema_migrations/20221011062254
@@ -0,0 +1 @@
+ae4f3c26acd69aa0c701651a246a1359c91a0daad0daad64ba8dc186268880a4 \ No newline at end of file
diff --git a/db/schema_migrations/20221013103738 b/db/schema_migrations/20221013103738
new file mode 100644
index 00000000000..8643304c5b1
--- /dev/null
+++ b/db/schema_migrations/20221013103738
@@ -0,0 +1 @@
+704d0973ce5fec01228a28d5551ecc88ccf057e246ee75f8f5b0cc0a08815095 \ No newline at end of file
diff --git a/db/schema_migrations/20221013215832 b/db/schema_migrations/20221013215832
new file mode 100644
index 00000000000..106cb540d6e
--- /dev/null
+++ b/db/schema_migrations/20221013215832
@@ -0,0 +1 @@
+2ab913b0b479fc29d939d03b5df95dc2a8c5a155f1b35a606e300802cb3aa9d3 \ No newline at end of file
diff --git a/db/schema_migrations/20221015000511 b/db/schema_migrations/20221015000511
new file mode 100644
index 00000000000..16845f8859c
--- /dev/null
+++ b/db/schema_migrations/20221015000511
@@ -0,0 +1 @@
+001b43cc0006b8f936310171ff2d12993eece1378f64945e6835728f540815ba \ No newline at end of file
diff --git a/db/schema_migrations/20221017084208 b/db/schema_migrations/20221017084208
new file mode 100644
index 00000000000..3fb09558549
--- /dev/null
+++ b/db/schema_migrations/20221017084208
@@ -0,0 +1 @@
+d28932a3d52279446e3ef84806a6bb6b53dc10c5b9ae81e2c626203da4238a9a \ No newline at end of file
diff --git a/db/schema_migrations/20221017084227 b/db/schema_migrations/20221017084227
new file mode 100644
index 00000000000..9f57ca08267
--- /dev/null
+++ b/db/schema_migrations/20221017084227
@@ -0,0 +1 @@
+dc03ff5c63ada744d41e5e37e276306b1fe3bb2d8f925ebb0087be3a4b51791e \ No newline at end of file
diff --git a/db/schema_migrations/20221018050323 b/db/schema_migrations/20221018050323
new file mode 100644
index 00000000000..3e1d102da64
--- /dev/null
+++ b/db/schema_migrations/20221018050323
@@ -0,0 +1 @@
+05754025966b87f6998a0801e76c811b0cd42b2a77f35e8129a0c47f935e9bc4 \ No newline at end of file
diff --git a/db/schema_migrations/20221018062308 b/db/schema_migrations/20221018062308
new file mode 100644
index 00000000000..1b408ed101a
--- /dev/null
+++ b/db/schema_migrations/20221018062308
@@ -0,0 +1 @@
+58aec3260f2b26d5a49159b95de7c6486b16c8af354f716190d4c48f83324910 \ No newline at end of file
diff --git a/db/schema_migrations/20221018092552 b/db/schema_migrations/20221018092552
new file mode 100644
index 00000000000..8416f7d72a3
--- /dev/null
+++ b/db/schema_migrations/20221018092552
@@ -0,0 +1 @@
+d7ec9ab32c5f58805bec64bea9bd32aedbd80f678d6b8e8c6914aa26523dcc95 \ No newline at end of file
diff --git a/db/schema_migrations/20221018124029 b/db/schema_migrations/20221018124029
new file mode 100644
index 00000000000..6c050ebf248
--- /dev/null
+++ b/db/schema_migrations/20221018124029
@@ -0,0 +1 @@
+c3a38f280c8835e77953b69ba41ef5d58b76fd5f2f39e758a523c493306b0ab2 \ No newline at end of file
diff --git a/db/schema_migrations/20221018124035 b/db/schema_migrations/20221018124035
new file mode 100644
index 00000000000..1d0721c4bfb
--- /dev/null
+++ b/db/schema_migrations/20221018124035
@@ -0,0 +1 @@
+77aca033a7c58af4e981136b96629acf5b82a42701072928532681dd91b05280 \ No newline at end of file
diff --git a/db/schema_migrations/20221018193635 b/db/schema_migrations/20221018193635
new file mode 100644
index 00000000000..e29e4605d5b
--- /dev/null
+++ b/db/schema_migrations/20221018193635
@@ -0,0 +1 @@
+de28d291a4a49dcb1743466ce61d95e47c28bdf293731e446b7b43d370d76e36 \ No newline at end of file
diff --git a/db/schema_migrations/20221018193827 b/db/schema_migrations/20221018193827
new file mode 100644
index 00000000000..26753827185
--- /dev/null
+++ b/db/schema_migrations/20221018193827
@@ -0,0 +1 @@
+fb64884e988fb0f3589fd189780f3ac5358d06b7599243935f1d4c3dd7e794fc \ No newline at end of file
diff --git a/db/schema_migrations/20221018202524 b/db/schema_migrations/20221018202524
new file mode 100644
index 00000000000..ee738f3608c
--- /dev/null
+++ b/db/schema_migrations/20221018202524
@@ -0,0 +1 @@
+a3266078f4760f0f5a4c7a43669cea1170924f29d6867e712620c2234dbf13c6 \ No newline at end of file
diff --git a/db/schema_migrations/20221018232820 b/db/schema_migrations/20221018232820
new file mode 100644
index 00000000000..870de8adb4a
--- /dev/null
+++ b/db/schema_migrations/20221018232820
@@ -0,0 +1 @@
+cdf3e65f07f700617f47435b79743b4b35307f47cf46a9696350e55af1774d42 \ No newline at end of file
diff --git a/db/schema_migrations/20221019002459 b/db/schema_migrations/20221019002459
new file mode 100644
index 00000000000..cab21003736
--- /dev/null
+++ b/db/schema_migrations/20221019002459
@@ -0,0 +1 @@
+6c3fe5bf01ac9e74f142ddb3e093867b62cf430f24ba885f8475ccf7f73899cb \ No newline at end of file
diff --git a/db/schema_migrations/20221019102426 b/db/schema_migrations/20221019102426
new file mode 100644
index 00000000000..482f7ab0980
--- /dev/null
+++ b/db/schema_migrations/20221019102426
@@ -0,0 +1 @@
+6990eb33313f6c0a82409fde69c74a88d0a9db2cd144322bcff4428261bbf1e4 \ No newline at end of file
diff --git a/db/schema_migrations/20221019105041 b/db/schema_migrations/20221019105041
new file mode 100644
index 00000000000..0dff355b300
--- /dev/null
+++ b/db/schema_migrations/20221019105041
@@ -0,0 +1 @@
+186e7df4e7e81913981595a069c5c8b5fbb600ee5dcebf333bfff728c5019ab2 \ No newline at end of file
diff --git a/db/schema_migrations/20221019141508 b/db/schema_migrations/20221019141508
new file mode 100644
index 00000000000..2b4ecc805e4
--- /dev/null
+++ b/db/schema_migrations/20221019141508
@@ -0,0 +1 @@
+527b18e3bd89316c33b099d4e3cd622617b6e8dbb482a0f0ce983386b0210f7e \ No newline at end of file
diff --git a/db/schema_migrations/20221019194751 b/db/schema_migrations/20221019194751
new file mode 100644
index 00000000000..e917d4ac1f6
--- /dev/null
+++ b/db/schema_migrations/20221019194751
@@ -0,0 +1 @@
+785ed2a3c711edf54f1b23bdbd4b333b7a4ee02b86f8581c1f4cc20003e5f832 \ No newline at end of file
diff --git a/db/schema_migrations/20221019195754 b/db/schema_migrations/20221019195754
new file mode 100644
index 00000000000..2be5ca3ce1a
--- /dev/null
+++ b/db/schema_migrations/20221019195754
@@ -0,0 +1 @@
+b09530d7b72d70774624ef44683be6665bd1141be49db551a0dfe303ce67eefa \ No newline at end of file
diff --git a/db/schema_migrations/20221019200033 b/db/schema_migrations/20221019200033
new file mode 100644
index 00000000000..2826a18d7df
--- /dev/null
+++ b/db/schema_migrations/20221019200033
@@ -0,0 +1 @@
+a72855a95f243d2a404d840fde900a99b9f568144dfde47e813c4e9bc81ef8cf \ No newline at end of file
diff --git a/db/schema_migrations/20221019200206 b/db/schema_migrations/20221019200206
new file mode 100644
index 00000000000..73eb8571a5a
--- /dev/null
+++ b/db/schema_migrations/20221019200206
@@ -0,0 +1 @@
+1bd5d356d0a15737178eee70bce65c9883bd5daa2a672a9049ccecb4e73f431b \ No newline at end of file
diff --git a/db/schema_migrations/20221020124018 b/db/schema_migrations/20221020124018
new file mode 100644
index 00000000000..6f6c76eb531
--- /dev/null
+++ b/db/schema_migrations/20221020124018
@@ -0,0 +1 @@
+c4b296345f45b6184e04181708eb2f55a1b3a621f331b75173b33b0036c3176f \ No newline at end of file
diff --git a/db/schema_migrations/20221021082255 b/db/schema_migrations/20221021082255
new file mode 100644
index 00000000000..afb266271d4
--- /dev/null
+++ b/db/schema_migrations/20221021082255
@@ -0,0 +1 @@
+10caa548bccc134775ed14f85eae2b2063e83afe4a932982c353ecf1549a557d \ No newline at end of file
diff --git a/db/schema_migrations/20221021082312 b/db/schema_migrations/20221021082312
new file mode 100644
index 00000000000..26007002f54
--- /dev/null
+++ b/db/schema_migrations/20221021082312
@@ -0,0 +1 @@
+86d979a179c504508fd2e9c1a62e935884297054b13b78a4c1460679d75f5b96 \ No newline at end of file
diff --git a/db/schema_migrations/20221021082720 b/db/schema_migrations/20221021082720
new file mode 100644
index 00000000000..b3591da1021
--- /dev/null
+++ b/db/schema_migrations/20221021082720
@@ -0,0 +1 @@
+a9122e3772587b85a889740ccc54d48b6ead91a3b472d712e1e8bf5946655cf4 \ No newline at end of file
diff --git a/db/schema_migrations/20221021082734 b/db/schema_migrations/20221021082734
new file mode 100644
index 00000000000..6fc0aaa3fca
--- /dev/null
+++ b/db/schema_migrations/20221021082734
@@ -0,0 +1 @@
+d7c109cba935e1f355789dffa1d64b29b787f44ced7b0d3090e19a2dd0b8e266 \ No newline at end of file
diff --git a/db/schema_migrations/20221021145820 b/db/schema_migrations/20221021145820
new file mode 100644
index 00000000000..e3d50c654ba
--- /dev/null
+++ b/db/schema_migrations/20221021145820
@@ -0,0 +1 @@
+e9fd4d60833624e20fcf9b01b883dca15e6c135aa99f1afd1c7a365eebac17fb \ No newline at end of file
diff --git a/db/schema_migrations/20221021160735 b/db/schema_migrations/20221021160735
new file mode 100644
index 00000000000..73c10f7e23d
--- /dev/null
+++ b/db/schema_migrations/20221021160735
@@ -0,0 +1 @@
+0b7727e942f6e3fa2e1b0ed9e22c504a64aceac19adf25f126baba587db4b764 \ No newline at end of file
diff --git a/db/schema_migrations/20221021213216 b/db/schema_migrations/20221021213216
new file mode 100644
index 00000000000..900a4f6701e
--- /dev/null
+++ b/db/schema_migrations/20221021213216
@@ -0,0 +1 @@
+defe6e66c98648ea7fb77d8001392bc707ec022f639d346c42d23fad10958856 \ No newline at end of file
diff --git a/db/schema_migrations/20221022213505 b/db/schema_migrations/20221022213505
new file mode 100644
index 00000000000..4cf0b87eedf
--- /dev/null
+++ b/db/schema_migrations/20221022213505
@@ -0,0 +1 @@
+c48015b2ff6ad4b58bffaf5342247d890f6bd2388c467751654bc705f5eb53ed \ No newline at end of file
diff --git a/db/schema_migrations/20221022213521 b/db/schema_migrations/20221022213521
new file mode 100644
index 00000000000..c3bb483debf
--- /dev/null
+++ b/db/schema_migrations/20221022213521
@@ -0,0 +1 @@
+739952c72f82b804b84d73107264804202ad102b425008d4dcb029c1f02e2118 \ No newline at end of file
diff --git a/db/schema_migrations/20221024034228 b/db/schema_migrations/20221024034228
new file mode 100644
index 00000000000..3df637a8198
--- /dev/null
+++ b/db/schema_migrations/20221024034228
@@ -0,0 +1 @@
+7f83a1d04357f4f2e1e4ed92e0d9b0041f79d1850b28f41cee45d243e25741f0 \ No newline at end of file
diff --git a/db/schema_migrations/20221024121500 b/db/schema_migrations/20221024121500
new file mode 100644
index 00000000000..6db609001ad
--- /dev/null
+++ b/db/schema_migrations/20221024121500
@@ -0,0 +1 @@
+8449de1e73e2fb46698e0e160641c4132b99918792b0b3379d6009bab9eab0b7 \ No newline at end of file
diff --git a/db/schema_migrations/20221025043930 b/db/schema_migrations/20221025043930
new file mode 100644
index 00000000000..37365baea27
--- /dev/null
+++ b/db/schema_migrations/20221025043930
@@ -0,0 +1 @@
+6762034e2dff9d6e6d146f1ce3b281f8886895b056c5ed54767ceb0d6c18bd59 \ No newline at end of file
diff --git a/db/schema_migrations/20221025105205 b/db/schema_migrations/20221025105205
new file mode 100644
index 00000000000..4003f74aa11
--- /dev/null
+++ b/db/schema_migrations/20221025105205
@@ -0,0 +1 @@
+80daa2f50ae9f8c0dee206ed9d45eb04884e14a0331475cb8c9a2d57f4c86ef5 \ No newline at end of file
diff --git a/db/schema_migrations/20221025115006 b/db/schema_migrations/20221025115006
new file mode 100644
index 00000000000..d831d6aeec9
--- /dev/null
+++ b/db/schema_migrations/20221025115006
@@ -0,0 +1 @@
+1529e1b436b65ff7b787f43fc5b8de7515aebe427719d2e4e62e9a7f923e877b \ No newline at end of file
diff --git a/db/schema_migrations/20221025145452 b/db/schema_migrations/20221025145452
new file mode 100644
index 00000000000..df551b8bae6
--- /dev/null
+++ b/db/schema_migrations/20221025145452
@@ -0,0 +1 @@
+951ad9faf483d58778cd831a0ac949473d6eeb753322754eff3f02756d757583 \ No newline at end of file
diff --git a/db/schema_migrations/20221025150202 b/db/schema_migrations/20221025150202
new file mode 100644
index 00000000000..aa6db23de6c
--- /dev/null
+++ b/db/schema_migrations/20221025150202
@@ -0,0 +1 @@
+2185444f733eec25a2741764619516eecb1d2c6e3e4ec3b3ed5b72bfd9c4db46 \ No newline at end of file
diff --git a/db/schema_migrations/20221025220607 b/db/schema_migrations/20221025220607
new file mode 100644
index 00000000000..30322b1ab3f
--- /dev/null
+++ b/db/schema_migrations/20221025220607
@@ -0,0 +1 @@
+d6eb5bb918f12c08f23c228916b7e21432e1e2958832c10be4e46dfa2079103d \ No newline at end of file
diff --git a/db/schema_migrations/20221027124848 b/db/schema_migrations/20221027124848
new file mode 100644
index 00000000000..249e4e4b83f
--- /dev/null
+++ b/db/schema_migrations/20221027124848
@@ -0,0 +1 @@
+108dec45cbed3651aec46636a3009cb18296d0fa0ca720774dc2105123955dfd \ No newline at end of file
diff --git a/db/schema_migrations/20221027203556 b/db/schema_migrations/20221027203556
new file mode 100644
index 00000000000..e386f0e6bbb
--- /dev/null
+++ b/db/schema_migrations/20221027203556
@@ -0,0 +1 @@
+9ea13068b90797013677ec390de4222e00e80076080cf4e5335e9f90e2e59f2d \ No newline at end of file
diff --git a/db/schema_migrations/20221027203951 b/db/schema_migrations/20221027203951
new file mode 100644
index 00000000000..866ccf8c208
--- /dev/null
+++ b/db/schema_migrations/20221027203951
@@ -0,0 +1 @@
+5f4fd4e64d398208e2d32573273a70106c9a4fd5ab350d75fcf7a6f4c824e00a \ No newline at end of file
diff --git a/db/schema_migrations/20221028000041 b/db/schema_migrations/20221028000041
new file mode 100644
index 00000000000..4160c4d26ed
--- /dev/null
+++ b/db/schema_migrations/20221028000041
@@ -0,0 +1 @@
+b2e38680afc264fadd5fbaa7d07c95c7ba6e1fb7a32bdff267e35a7d9bde72c8 \ No newline at end of file
diff --git a/db/schema_migrations/20221028000603 b/db/schema_migrations/20221028000603
new file mode 100644
index 00000000000..0dc60ae68eb
--- /dev/null
+++ b/db/schema_migrations/20221028000603
@@ -0,0 +1 @@
+aee0c708436ae365e2469b2bb5b508dcbf6975326faa90bd1571dd400312eded \ No newline at end of file
diff --git a/db/schema_migrations/20221028015347 b/db/schema_migrations/20221028015347
new file mode 100644
index 00000000000..ab633b763df
--- /dev/null
+++ b/db/schema_migrations/20221028015347
@@ -0,0 +1 @@
+7b86ae0739c4c381b050539261c67dbf3d4716edf0f0bde9b281cbdc5143a4d2 \ No newline at end of file
diff --git a/db/schema_migrations/20221028022627 b/db/schema_migrations/20221028022627
new file mode 100644
index 00000000000..34c365800a6
--- /dev/null
+++ b/db/schema_migrations/20221028022627
@@ -0,0 +1 @@
+0305d0fa4d95b0a1553c9ba7984af2cb74099988dbc9983e1048b54ead39a76e \ No newline at end of file
diff --git a/db/schema_migrations/20221028152422 b/db/schema_migrations/20221028152422
new file mode 100644
index 00000000000..bfe9807b1c6
--- /dev/null
+++ b/db/schema_migrations/20221028152422
@@ -0,0 +1 @@
+c9322bdc7e862bd20ec548fbcd3ec6a9ef4da6abc0a688d503e1792acc262472 \ No newline at end of file
diff --git a/db/schema_migrations/20221031102916 b/db/schema_migrations/20221031102916
new file mode 100644
index 00000000000..53f927cfc32
--- /dev/null
+++ b/db/schema_migrations/20221031102916
@@ -0,0 +1 @@
+e0065beaf2e1dc5e5850353244ba2c76477e855733f3683a1901a340a5826ae1 \ No newline at end of file
diff --git a/db/schema_migrations/20221101032521 b/db/schema_migrations/20221101032521
new file mode 100644
index 00000000000..995b034fa89
--- /dev/null
+++ b/db/schema_migrations/20221101032521
@@ -0,0 +1 @@
+db7e477626aa34154db2d6ff30bcafc7c70a2a9c3a719bfb7e7ac0a8e0d7e579 \ No newline at end of file
diff --git a/db/schema_migrations/20221101032600 b/db/schema_migrations/20221101032600
new file mode 100644
index 00000000000..2b060661657
--- /dev/null
+++ b/db/schema_migrations/20221101032600
@@ -0,0 +1 @@
+49449f2bb02e8dbe0cff73b6ac8dc291c00c7ce9c0d54bf7bb2b5cd9c599d713 \ No newline at end of file
diff --git a/db/schema_migrations/20221101195903 b/db/schema_migrations/20221101195903
new file mode 100644
index 00000000000..9b19cb05b66
--- /dev/null
+++ b/db/schema_migrations/20221101195903
@@ -0,0 +1 @@
+984a2bcc65364293cd110d3a917aecd37253f621150220000f99e8ea215e30ab \ No newline at end of file
diff --git a/db/schema_migrations/20221101201031 b/db/schema_migrations/20221101201031
new file mode 100644
index 00000000000..82544cf461d
--- /dev/null
+++ b/db/schema_migrations/20221101201031
@@ -0,0 +1 @@
+6ed6a3fdd144b118c7f85960d08500f21a7f666abfdaafc9d681e03723ed22e8 \ No newline at end of file
diff --git a/db/schema_migrations/20221102090940 b/db/schema_migrations/20221102090940
new file mode 100644
index 00000000000..c0ef7881688
--- /dev/null
+++ b/db/schema_migrations/20221102090940
@@ -0,0 +1 @@
+3be66e9f4239eb75f14118d1fd795f1a1bcd2d6bc4e34fe58a0c8422e33c893a \ No newline at end of file
diff --git a/db/schema_migrations/20221102090943 b/db/schema_migrations/20221102090943
new file mode 100644
index 00000000000..bc7ff679c6e
--- /dev/null
+++ b/db/schema_migrations/20221102090943
@@ -0,0 +1 @@
+8e907e086c4b23dd08163c4d946ec4a0202288f7da08eff565a159bccdd445f2 \ No newline at end of file
diff --git a/db/schema_migrations/20221102202130 b/db/schema_migrations/20221102202130
new file mode 100644
index 00000000000..82ee1088544
--- /dev/null
+++ b/db/schema_migrations/20221102202130
@@ -0,0 +1 @@
+76c2fe9422491d0bd457584580b383924b895574cec7e90cdfa5de9ed56a3639 \ No newline at end of file
diff --git a/db/schema_migrations/20221102225800 b/db/schema_migrations/20221102225800
new file mode 100644
index 00000000000..fca933ed91b
--- /dev/null
+++ b/db/schema_migrations/20221102225800
@@ -0,0 +1 @@
+2e7e55a23574d45e877712fb67b2c2b50d85905c95fe4ec3990cfd8fe5160122 \ No newline at end of file
diff --git a/db/schema_migrations/20221103073328 b/db/schema_migrations/20221103073328
new file mode 100644
index 00000000000..8a90e224a2f
--- /dev/null
+++ b/db/schema_migrations/20221103073328
@@ -0,0 +1 @@
+6f0ce1b68310b3194aa7b6219d79570e8179d449f49d828800f90f70d9242f38 \ No newline at end of file
diff --git a/db/schema_migrations/20221103084213 b/db/schema_migrations/20221103084213
new file mode 100644
index 00000000000..f9790952cf0
--- /dev/null
+++ b/db/schema_migrations/20221103084213
@@ -0,0 +1 @@
+90794c6a9b8b9e08e8b0898e55bc581b8411fd0e85a17fefa916213d82e98099 \ No newline at end of file
diff --git a/db/schema_migrations/20221103131409 b/db/schema_migrations/20221103131409
new file mode 100644
index 00000000000..88be59197a3
--- /dev/null
+++ b/db/schema_migrations/20221103131409
@@ -0,0 +1 @@
+cb301b88dc9b0f5bffd9d1a4419c5923e8145cb8770e576d88dc7881c1c9e39c \ No newline at end of file
diff --git a/db/schema_migrations/20221103150250 b/db/schema_migrations/20221103150250
new file mode 100644
index 00000000000..cc6b55ba5ea
--- /dev/null
+++ b/db/schema_migrations/20221103150250
@@ -0,0 +1 @@
+662c4df2d65a9259e2eafc11e828ffc15765b92fe3a5291ff869129aaf7bb1c0 \ No newline at end of file
diff --git a/db/schema_migrations/20221104042137 b/db/schema_migrations/20221104042137
new file mode 100644
index 00000000000..4e3a1d27d53
--- /dev/null
+++ b/db/schema_migrations/20221104042137
@@ -0,0 +1 @@
+3192407f3034683ba226d651e247385de200a06e26142e87978fa080eecda110 \ No newline at end of file
diff --git a/db/schema_migrations/20221104042159 b/db/schema_migrations/20221104042159
new file mode 100644
index 00000000000..3454e08597d
--- /dev/null
+++ b/db/schema_migrations/20221104042159
@@ -0,0 +1 @@
+462fd09ac4c59b9fc3f865e984da4c83c4a75d60e557d634631d5eafd67741cc \ No newline at end of file
diff --git a/db/schema_migrations/20221104061320 b/db/schema_migrations/20221104061320
new file mode 100644
index 00000000000..f1cc9a7e277
--- /dev/null
+++ b/db/schema_migrations/20221104061320
@@ -0,0 +1 @@
+c181db849e3542570b4cc55337be8fbda87556773c989ce4e8259cefa1c74922 \ No newline at end of file
diff --git a/db/schema_migrations/20221104074652 b/db/schema_migrations/20221104074652
new file mode 100644
index 00000000000..460f21a3f6e
--- /dev/null
+++ b/db/schema_migrations/20221104074652
@@ -0,0 +1 @@
+167032d562467c3d6be9e6c6c8c072f117e23798db35301f95386130ae115a00 \ No newline at end of file
diff --git a/db/schema_migrations/20221104094042 b/db/schema_migrations/20221104094042
new file mode 100644
index 00000000000..08694063f07
--- /dev/null
+++ b/db/schema_migrations/20221104094042
@@ -0,0 +1 @@
+7ddb85c1acfd3fbeddbe96857d329ad09cd21210e6765ff36d4b9f516a7c10be \ No newline at end of file
diff --git a/db/schema_migrations/20221104100203 b/db/schema_migrations/20221104100203
new file mode 100644
index 00000000000..df7b06eef5d
--- /dev/null
+++ b/db/schema_migrations/20221104100203
@@ -0,0 +1 @@
+1d7912409bb5afc7de82b7507fb2aeb164253c70a58eaf88d502513577bad979 \ No newline at end of file
diff --git a/db/schema_migrations/20221104170500 b/db/schema_migrations/20221104170500
new file mode 100644
index 00000000000..58fd45b5223
--- /dev/null
+++ b/db/schema_migrations/20221104170500
@@ -0,0 +1 @@
+1826209494234355dd2014b3ae7f8ef5c2138a3d22ce143f744ab911e3ebb985 \ No newline at end of file
diff --git a/db/schema_migrations/20221104190203 b/db/schema_migrations/20221104190203
new file mode 100644
index 00000000000..cf604255bc1
--- /dev/null
+++ b/db/schema_migrations/20221104190203
@@ -0,0 +1 @@
+248aecf9fa53146f2c1f7771fd60adf720fa8c0d2bd33d71c6177b185e4248d1 \ No newline at end of file
diff --git a/db/schema_migrations/20221107094359 b/db/schema_migrations/20221107094359
new file mode 100644
index 00000000000..f5cb6814e61
--- /dev/null
+++ b/db/schema_migrations/20221107094359
@@ -0,0 +1 @@
+47d2ac5130583e1a5d0b89d73f32d4af208f8800fc62726bce8ca86e3ce0ed40 \ No newline at end of file
diff --git a/db/schema_migrations/20221107115247 b/db/schema_migrations/20221107115247
new file mode 100644
index 00000000000..e5426ef7be1
--- /dev/null
+++ b/db/schema_migrations/20221107115247
@@ -0,0 +1 @@
+c3616b3184b29fb2dbe83ec18391b8c52a2ab23591803bb949226a7202e49c2b \ No newline at end of file
diff --git a/db/schema_migrations/20221107115413 b/db/schema_migrations/20221107115413
new file mode 100644
index 00000000000..f8889bebe98
--- /dev/null
+++ b/db/schema_migrations/20221107115413
@@ -0,0 +1 @@
+71bacdb2d4c1c3c21fe39d4092cad803a4ebf44b6d621b8425baaa77b15b3891 \ No newline at end of file
diff --git a/db/schema_migrations/20221107183222 b/db/schema_migrations/20221107183222
new file mode 100644
index 00000000000..e7049b0d3a1
--- /dev/null
+++ b/db/schema_migrations/20221107183222
@@ -0,0 +1 @@
+593bf8c98becf8300ccdd38403d805c9f185827a9a131b83d3b0aa571aa6f172 \ No newline at end of file
diff --git a/db/schema_migrations/20221107184542 b/db/schema_migrations/20221107184542
new file mode 100644
index 00000000000..ac7a4c78f66
--- /dev/null
+++ b/db/schema_migrations/20221107184542
@@ -0,0 +1 @@
+876dce84bbc5ee00cd7ee837be6c549c677ec7eb7ec8db39d7711877d57dd7be \ No newline at end of file
diff --git a/db/schema_migrations/20221107184758 b/db/schema_migrations/20221107184758
new file mode 100644
index 00000000000..f327e45183b
--- /dev/null
+++ b/db/schema_migrations/20221107184758
@@ -0,0 +1 @@
+1aa75f334b1b56e46e8e0985febba567b0eb55af0f1ced0e198bfc979e5e262c \ No newline at end of file
diff --git a/db/schema_migrations/20221107220420 b/db/schema_migrations/20221107220420
new file mode 100644
index 00000000000..f56ca1204b1
--- /dev/null
+++ b/db/schema_migrations/20221107220420
@@ -0,0 +1 @@
+499f7b3951c9792d2a8f204b72c474a42e8301b487fa9f68080dd5bb5db0c64c \ No newline at end of file
diff --git a/db/schema_migrations/20221107220526 b/db/schema_migrations/20221107220526
new file mode 100644
index 00000000000..93be68808d7
--- /dev/null
+++ b/db/schema_migrations/20221107220526
@@ -0,0 +1 @@
+b633df04851493d7d4b5d7da79ba3057f6f2c302e507b4f963596edf9cbfcb88 \ No newline at end of file
diff --git a/db/schema_migrations/20221107222213 b/db/schema_migrations/20221107222213
new file mode 100644
index 00000000000..5950f0d5c5a
--- /dev/null
+++ b/db/schema_migrations/20221107222213
@@ -0,0 +1 @@
+f5295b135cd395a59c7afc6a9d999201f9ea1174aab893d31ead398aa8c0f8bb \ No newline at end of file
diff --git a/db/schema_migrations/20221108015813 b/db/schema_migrations/20221108015813
new file mode 100644
index 00000000000..39263419da6
--- /dev/null
+++ b/db/schema_migrations/20221108015813
@@ -0,0 +1 @@
+d6b24d6346bd9b32dd726d61048e7eea791d02016b9b4c3a8cb561b2430e1fdb \ No newline at end of file
diff --git a/db/schema_migrations/20221108045019 b/db/schema_migrations/20221108045019
new file mode 100644
index 00000000000..518b5118173
--- /dev/null
+++ b/db/schema_migrations/20221108045019
@@ -0,0 +1 @@
+b8438bebe77ae835b754431d8d67c306714205bef11826a15d4c84d7b67a3581 \ No newline at end of file
diff --git a/db/schema_migrations/20221108121322 b/db/schema_migrations/20221108121322
new file mode 100644
index 00000000000..d1880c9319a
--- /dev/null
+++ b/db/schema_migrations/20221108121322
@@ -0,0 +1 @@
+4e5deb2f5be081eef7b3dab726b2877bc21a7afad1b6a12aca240f510cada0b3 \ No newline at end of file
diff --git a/db/schema_migrations/20221108185442 b/db/schema_migrations/20221108185442
new file mode 100644
index 00000000000..ec32f966df9
--- /dev/null
+++ b/db/schema_migrations/20221108185442
@@ -0,0 +1 @@
+fc1f31a717e8c5e8539138e612dcba4acafb5b7324534b6ca23220142c43de80 \ No newline at end of file
diff --git a/db/schema_migrations/20221108222015 b/db/schema_migrations/20221108222015
new file mode 100644
index 00000000000..2b9ce458ce9
--- /dev/null
+++ b/db/schema_migrations/20221108222015
@@ -0,0 +1 @@
+555c69896e457b0b41c00926007b422ef34869e45fc0bde89b87ecc2df51de00 \ No newline at end of file
diff --git a/db/schema_migrations/20221110045406 b/db/schema_migrations/20221110045406
new file mode 100644
index 00000000000..264e4f5003b
--- /dev/null
+++ b/db/schema_migrations/20221110045406
@@ -0,0 +1 @@
+d0a14750dfcf3bd7641c9f37fbf5f992d4d7be7be33565ed9dd14eb12a983005 \ No newline at end of file
diff --git a/db/schema_migrations/20221110105857 b/db/schema_migrations/20221110105857
new file mode 100644
index 00000000000..f515180dcdf
--- /dev/null
+++ b/db/schema_migrations/20221110105857
@@ -0,0 +1 @@
+5ef00449d9c5b4a44b99410839d3ba4c4d6d8cb152460822b882c6ac60f771e3 \ No newline at end of file
diff --git a/db/schema_migrations/20221110150942 b/db/schema_migrations/20221110150942
new file mode 100644
index 00000000000..1c627232e78
--- /dev/null
+++ b/db/schema_migrations/20221110150942
@@ -0,0 +1 @@
+fa663262d6d73637e7ffefecd0f06705456bc226024d5023377a527cf3498ac7 \ No newline at end of file
diff --git a/db/schema_migrations/20221111070314 b/db/schema_migrations/20221111070314
new file mode 100644
index 00000000000..754d584f0f2
--- /dev/null
+++ b/db/schema_migrations/20221111070314
@@ -0,0 +1 @@
+4a85ceb76874c618fa21030838900ed1a7219e4ee40b2d88645f4025743034f9 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 2dab5e7abc9..350ac2ad454 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -225,6 +225,33 @@ RETURN NULL;
END
$$;
+CREATE FUNCTION sync_namespaces_amount_used_columns() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ NEW."new_amount_used" := NEW."amount_used";
+ RETURN NEW;
+END;
+$$;
+
+CREATE FUNCTION sync_projects_amount_used_columns() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ NEW."new_amount_used" := NEW."amount_used";
+ RETURN NEW;
+END;
+$$;
+
+CREATE FUNCTION trigger_1a857e8db6cd() RETURNS trigger
+ LANGUAGE plpgsql
+ AS $$
+BEGIN
+ NEW."uuid_convert_string_to_uuid" := NEW."uuid";
+ RETURN NEW;
+END;
+$$;
+
CREATE FUNCTION unset_has_issues_on_vulnerability_reads() RETURNS trigger
LANGUAGE plpgsql
AS $$
@@ -434,6 +461,7 @@ CREATE TABLE security_findings (
uuid uuid,
overridden_uuid uuid,
partition_number integer DEFAULT 1 NOT NULL,
+ finding_data jsonb DEFAULT '{}'::jsonb NOT NULL,
CONSTRAINT check_6c2851a8c9 CHECK ((uuid IS NOT NULL)),
CONSTRAINT check_b9508c6df8 CHECK ((char_length(project_fingerprint) <= 40))
)
@@ -11488,9 +11516,19 @@ CREATE TABLE application_settings (
lock_maven_package_requests_forwarding boolean DEFAULT false NOT NULL,
lock_pypi_package_requests_forwarding boolean DEFAULT false NOT NULL,
lock_npm_package_requests_forwarding boolean DEFAULT false NOT NULL,
+ jira_connect_proxy_url text,
password_expiration_enabled boolean DEFAULT false NOT NULL,
password_expires_in_days integer DEFAULT 90 NOT NULL,
password_expires_notice_before_days integer DEFAULT 7 NOT NULL,
+ product_analytics_enabled boolean DEFAULT false NOT NULL,
+ email_confirmation_setting smallint DEFAULT 0,
+ disable_admin_oauth_scopes boolean DEFAULT false NOT NULL,
+ default_preferred_language text DEFAULT 'en'::text NOT NULL,
+ disable_download_button boolean DEFAULT false NOT NULL,
+ encrypted_telesign_customer_xid bytea,
+ encrypted_telesign_customer_xid_iv bytea,
+ encrypted_telesign_api_key bytea,
+ encrypted_telesign_api_key_iv bytea,
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)),
@@ -11509,6 +11547,7 @@ CREATE TABLE application_settings (
CONSTRAINT check_3455368420 CHECK ((char_length(database_grafana_api_url) <= 255)),
CONSTRAINT check_3559645ae5 CHECK ((char_length(container_registry_import_target_plan) <= 255)),
CONSTRAINT check_3def0f1829 CHECK ((char_length(sentry_clientside_dsn) <= 255)),
+ CONSTRAINT check_4847426287 CHECK ((char_length(jira_connect_proxy_url) <= 255)),
CONSTRAINT check_492cc1354d CHECK ((char_length(error_tracking_api_url) <= 255)),
CONSTRAINT check_4f8b811780 CHECK ((char_length(sentry_dsn) <= 255)),
CONSTRAINT check_51700b31b5 CHECK ((char_length(default_branch_name) <= 255)),
@@ -11530,6 +11569,7 @@ CREATE TABLE application_settings (
CONSTRAINT check_d4865d70f3 CHECK ((char_length(clickhouse_connection_string) <= 1024)),
CONSTRAINT check_d820146492 CHECK ((char_length(spam_check_endpoint_url) <= 255)),
CONSTRAINT check_dea8792229 CHECK ((char_length(jitsu_host) <= 255)),
+ CONSTRAINT check_e2692d7523 CHECK ((char_length(default_preferred_language) <= 32)),
CONSTRAINT check_e2dd6e290a CHECK ((char_length(jira_connect_application_key) <= 255)),
CONSTRAINT check_e5024c8801 CHECK ((char_length(elasticsearch_username) <= 255)),
CONSTRAINT check_e5aba18f02 CHECK ((char_length(container_registry_version) <= 255)),
@@ -11579,6 +11619,8 @@ COMMENT ON COLUMN application_settings.password_expires_in_days IS 'JiHu-specifi
COMMENT ON COLUMN application_settings.password_expires_notice_before_days IS 'JiHu-specific column';
+COMMENT ON COLUMN application_settings.disable_download_button IS 'JiHu-specific column';
+
CREATE SEQUENCE application_settings_id_seq
START WITH 1
INCREMENT BY 1
@@ -11854,6 +11896,24 @@ CREATE SEQUENCE audit_events_id_seq
ALTER SEQUENCE audit_events_id_seq OWNED BY audit_events.id;
+CREATE TABLE audit_events_streaming_event_type_filters (
+ id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL,
+ external_audit_event_destination_id bigint NOT NULL,
+ audit_event_type text NOT NULL,
+ CONSTRAINT check_d20c8e5a51 CHECK ((char_length(audit_event_type) <= 255))
+);
+
+CREATE SEQUENCE audit_events_streaming_event_type_filters_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE audit_events_streaming_event_type_filters_id_seq OWNED BY audit_events_streaming_event_type_filters.id;
+
CREATE TABLE audit_events_streaming_headers (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
@@ -12646,7 +12706,7 @@ CREATE SEQUENCE ci_builds_id_seq
ALTER SEQUENCE ci_builds_id_seq OWNED BY ci_builds.id;
-CREATE TABLE ci_builds_metadata (
+CREATE TABLE p_ci_builds_metadata (
project_id integer NOT NULL,
timeout integer,
timeout_source integer DEFAULT 1 NOT NULL,
@@ -12662,7 +12722,8 @@ CREATE TABLE ci_builds_metadata (
runtime_runner_features jsonb DEFAULT '{}'::jsonb NOT NULL,
id_tokens jsonb DEFAULT '{}'::jsonb NOT NULL,
partition_id bigint DEFAULT 100 NOT NULL
-);
+)
+PARTITION BY LIST (partition_id);
CREATE SEQUENCE ci_builds_metadata_id_seq
START WITH 1
@@ -12671,7 +12732,26 @@ CREATE SEQUENCE ci_builds_metadata_id_seq
NO MAXVALUE
CACHE 1;
-ALTER SEQUENCE ci_builds_metadata_id_seq OWNED BY ci_builds_metadata.id;
+ALTER SEQUENCE ci_builds_metadata_id_seq OWNED BY p_ci_builds_metadata.id;
+
+CREATE TABLE ci_builds_metadata (
+ project_id integer NOT NULL,
+ timeout integer,
+ timeout_source integer DEFAULT 1 NOT NULL,
+ interruptible boolean,
+ config_options jsonb,
+ config_variables jsonb,
+ has_exposed_artifacts boolean,
+ environment_auto_stop_in character varying(255),
+ expanded_environment_name character varying(255),
+ secrets jsonb DEFAULT '{}'::jsonb NOT NULL,
+ build_id bigint NOT NULL,
+ id bigint DEFAULT nextval('ci_builds_metadata_id_seq'::regclass) NOT NULL,
+ runtime_runner_features jsonb DEFAULT '{}'::jsonb NOT NULL,
+ id_tokens jsonb DEFAULT '{}'::jsonb NOT NULL,
+ partition_id bigint DEFAULT 100 NOT NULL
+);
+ALTER TABLE ONLY p_ci_builds_metadata ATTACH PARTITION ci_builds_metadata FOR VALUES IN ('100');
CREATE TABLE ci_builds_runner_session (
id bigint NOT NULL,
@@ -12921,6 +13001,7 @@ CREATE TABLE ci_namespace_monthly_usages (
notification_level smallint DEFAULT 100 NOT NULL,
shared_runners_duration integer DEFAULT 0 NOT NULL,
created_at timestamp with time zone,
+ new_amount_used numeric(18,4) DEFAULT 0.0 NOT NULL,
CONSTRAINT ci_namespace_monthly_usages_year_month_constraint CHECK ((date = date_trunc('month'::text, (date)::timestamp with time zone)))
);
@@ -13040,8 +13121,9 @@ ALTER SEQUENCE ci_pipeline_messages_id_seq OWNED BY ci_pipeline_messages.id;
CREATE TABLE ci_pipeline_metadata (
project_id bigint NOT NULL,
pipeline_id bigint NOT NULL,
- title text NOT NULL,
- CONSTRAINT check_e6a636a3f3 CHECK ((char_length(title) <= 255))
+ name text,
+ CONSTRAINT check_25d23931f1 CHECK ((name IS NOT NULL)),
+ CONSTRAINT check_9d3665463c CHECK ((char_length(name) <= 255))
);
CREATE TABLE ci_pipeline_schedule_variables (
@@ -13200,6 +13282,7 @@ CREATE TABLE ci_project_monthly_usages (
amount_used numeric(18,2) DEFAULT 0.0 NOT NULL,
shared_runners_duration integer DEFAULT 0 NOT NULL,
created_at timestamp with time zone,
+ new_amount_used numeric(18,4) DEFAULT 0.0 NOT NULL,
CONSTRAINT ci_project_monthly_usages_year_month_constraint CHECK ((date = date_trunc('month'::text, (date)::timestamp with time zone)))
);
@@ -14084,6 +14167,7 @@ CREATE TABLE container_repositories (
migration_aborted_in_state text,
migration_plan text,
last_cleanup_deleted_tags_count integer,
+ delete_started_at timestamp with time zone,
CONSTRAINT check_05e9012f36 CHECK ((char_length(migration_plan) <= 255)),
CONSTRAINT check_13c58fe73a CHECK ((char_length(migration_state) <= 255)),
CONSTRAINT check_97f0249439 CHECK ((char_length(migration_aborted_in_state) <= 255))
@@ -14506,6 +14590,20 @@ CREATE SEQUENCE dast_sites_id_seq
ALTER SEQUENCE dast_sites_id_seq OWNED BY dast_sites.id;
+CREATE TABLE dependency_proxy_blob_states (
+ verification_started_at timestamp with time zone,
+ verification_retry_at timestamp with time zone,
+ verified_at timestamp with time zone,
+ dependency_proxy_blob_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_8e4f76fffe CHECK ((char_length(verification_failure) <= 255))
+);
+
+COMMENT ON TABLE dependency_proxy_blob_states IS '{"owner":"group::geo","description":"Geo-specific table to store the verification state of DependencyProxy::Blob objects"}';
+
CREATE TABLE dependency_proxy_blobs (
id integer NOT NULL,
group_id integer NOT NULL,
@@ -15288,26 +15386,6 @@ CREATE SEQUENCE experiment_subjects_id_seq
ALTER SEQUENCE experiment_subjects_id_seq OWNED BY experiment_subjects.id;
-CREATE TABLE experiment_users (
- id bigint NOT NULL,
- experiment_id bigint NOT NULL,
- user_id bigint NOT NULL,
- group_type smallint DEFAULT 0 NOT NULL,
- created_at timestamp with time zone NOT NULL,
- updated_at timestamp with time zone NOT NULL,
- converted_at timestamp with time zone,
- context jsonb DEFAULT '{}'::jsonb NOT NULL
-);
-
-CREATE SEQUENCE experiment_users_id_seq
- START WITH 1
- INCREMENT BY 1
- NO MINVALUE
- NO MAXVALUE
- CACHE 1;
-
-ALTER SEQUENCE experiment_users_id_seq OWNED BY experiment_users.id;
-
CREATE TABLE experiments (
id bigint NOT NULL,
name text NOT NULL,
@@ -15815,7 +15893,8 @@ CREATE TABLE ghost_user_migrations (
initiator_user_id bigint,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
- hard_delete boolean DEFAULT false NOT NULL
+ hard_delete boolean DEFAULT false NOT NULL,
+ consume_after timestamp with time zone DEFAULT now() NOT NULL
);
CREATE SEQUENCE ghost_user_migrations_id_seq
@@ -17296,7 +17375,8 @@ CREATE TABLE members (
state smallint DEFAULT 0,
invite_email_success boolean DEFAULT true NOT NULL,
member_namespace_id bigint,
- member_role_id bigint
+ member_role_id bigint,
+ CONSTRAINT check_508774aac0 CHECK ((member_namespace_id IS NOT NULL))
);
CREATE SEQUENCE members_id_seq
@@ -17894,6 +17974,24 @@ CREATE TABLE namespace_ci_cd_settings (
allow_stale_runner_pruning boolean DEFAULT false NOT NULL
);
+CREATE TABLE namespace_commit_emails (
+ id bigint NOT NULL,
+ user_id bigint NOT NULL,
+ namespace_id bigint NOT NULL,
+ email_id bigint NOT NULL,
+ created_at timestamp with time zone NOT NULL,
+ updated_at timestamp with time zone NOT NULL
+);
+
+CREATE SEQUENCE namespace_commit_emails_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE namespace_commit_emails_id_seq OWNED BY namespace_commit_emails.id;
+
CREATE TABLE namespace_details (
namespace_id bigint NOT NULL,
created_at timestamp with time zone,
@@ -20147,12 +20245,16 @@ CREATE TABLE project_settings (
target_platforms character varying[] DEFAULT '{}'::character varying[] NOT NULL,
enforce_auth_checks_on_uploads boolean DEFAULT true NOT NULL,
selective_code_owner_removals boolean DEFAULT false NOT NULL,
+ issue_branch_template text,
show_diff_preview_in_email boolean DEFAULT true NOT NULL,
jitsu_key text,
suggested_reviewers_enabled boolean DEFAULT false NOT NULL,
only_allow_merge_if_all_status_checks_passed boolean DEFAULT false NOT NULL,
+ mirror_branch_regex text,
CONSTRAINT check_2981f15877 CHECK ((char_length(jitsu_key) <= 100)),
CONSTRAINT check_3a03e7557a CHECK ((char_length(previous_default_branch) <= 4096)),
+ CONSTRAINT check_3ca5cbffe6 CHECK ((char_length(issue_branch_template) <= 255)),
+ CONSTRAINT check_67292e4b99 CHECK ((char_length(mirror_branch_regex) <= 255)),
CONSTRAINT check_b09644994b CHECK ((char_length(squash_commit_template) <= 500)),
CONSTRAINT check_bde223416c CHECK ((show_default_award_emojis IS NOT NULL)),
CONSTRAINT check_eaf7cfb6a7 CHECK ((char_length(merge_commit_template) <= 500))
@@ -20205,6 +20307,22 @@ CREATE SEQUENCE project_topics_id_seq
ALTER SEQUENCE project_topics_id_seq OWNED BY project_topics.id;
+CREATE TABLE project_wiki_repositories (
+ 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
+);
+
+CREATE SEQUENCE project_wiki_repositories_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE project_wiki_repositories_id_seq OWNED BY project_wiki_repositories.id;
+
CREATE TABLE project_wiki_repository_states (
verification_started_at timestamp with time zone,
verification_retry_at timestamp with time zone,
@@ -20214,6 +20332,7 @@ CREATE TABLE project_wiki_repository_states (
verification_retry_count smallint,
verification_checksum bytea,
verification_failure text,
+ project_wiki_repository_id bigint,
CONSTRAINT check_119f134b68 CHECK ((char_length(verification_failure) <= 255))
);
@@ -20450,12 +20569,14 @@ ALTER SEQUENCE protected_branch_unprotect_access_levels_id_seq OWNED BY protecte
CREATE TABLE protected_branches (
id integer NOT NULL,
- project_id integer NOT NULL,
+ project_id integer,
name character varying NOT NULL,
created_at timestamp without time zone,
updated_at timestamp without time zone,
code_owner_approval_required boolean DEFAULT false NOT NULL,
- allow_force_push boolean DEFAULT false NOT NULL
+ allow_force_push boolean DEFAULT false NOT NULL,
+ namespace_id bigint,
+ CONSTRAINT protected_branches_project_id_namespace_id_any_not_null CHECK (((project_id IS NULL) <> (namespace_id IS NULL)))
);
CREATE SEQUENCE protected_branches_id_seq
@@ -20599,7 +20720,8 @@ CREATE TABLE push_rules (
commit_committer_check boolean,
regexp_uses_re2 boolean DEFAULT true,
commit_message_negative_regex character varying,
- reject_non_dco_commits boolean
+ reject_non_dco_commits boolean,
+ commit_committer_name_check boolean DEFAULT false NOT NULL
);
CREATE SEQUENCE push_rules_id_seq
@@ -20728,7 +20850,9 @@ CREATE TABLE remote_mirrors (
only_protected_branches boolean DEFAULT false NOT NULL,
remote_name character varying,
error_notification_sent boolean,
- keep_divergent_refs boolean
+ keep_divergent_refs boolean,
+ mirror_branch_regex text,
+ CONSTRAINT check_aa6b497785 CHECK ((char_length(mirror_branch_regex) <= 255))
);
CREATE SEQUENCE remote_mirrors_id_seq
@@ -21034,6 +21158,7 @@ CREATE TABLE sbom_components (
updated_at timestamp with time zone NOT NULL,
component_type smallint NOT NULL,
name text NOT NULL,
+ purl_type smallint,
CONSTRAINT check_91a8f6ad53 CHECK ((char_length(name) <= 255))
);
@@ -21072,8 +21197,7 @@ CREATE TABLE sbom_sources (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
source_type smallint NOT NULL,
- source jsonb DEFAULT '{}'::jsonb NOT NULL,
- fingerprint bytea
+ source jsonb DEFAULT '{}'::jsonb NOT NULL
);
CREATE SEQUENCE sbom_sources_id_seq
@@ -21109,7 +21233,7 @@ CREATE TABLE schema_migrations (
CREATE TABLE scim_identities (
id bigint NOT NULL,
- group_id bigint NOT NULL,
+ group_id bigint,
user_id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
@@ -21130,7 +21254,7 @@ CREATE TABLE scim_oauth_access_tokens (
id integer NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
- group_id integer NOT NULL,
+ group_id integer,
token_encrypted character varying NOT NULL
);
@@ -21550,7 +21674,6 @@ CREATE TABLE sprints (
updated_at timestamp with time zone NOT NULL,
start_date date,
due_date date,
- project_id bigint,
group_id bigint,
iid integer NOT NULL,
cached_markdown_version integer,
@@ -21561,7 +21684,6 @@ CREATE TABLE sprints (
state_enum smallint DEFAULT 1 NOT NULL,
iterations_cadence_id integer,
sequence integer,
- CONSTRAINT sprints_must_belong_to_project_or_group CHECK ((((project_id <> NULL::bigint) AND (group_id IS NULL)) OR ((group_id <> NULL::bigint) AND (project_id IS NULL)))),
CONSTRAINT sprints_title CHECK ((char_length(title) <= 255))
);
@@ -22126,13 +22248,13 @@ CREATE TABLE user_details (
registration_objective smallint,
phone text,
requires_credit_card_verification boolean DEFAULT false NOT NULL,
- password_last_changed_at timestamp with time zone,
linkedin text DEFAULT ''::text NOT NULL,
twitter text DEFAULT ''::text NOT NULL,
skype text DEFAULT ''::text NOT NULL,
website_url text DEFAULT ''::text NOT NULL,
location text DEFAULT ''::text NOT NULL,
organization text DEFAULT ''::text NOT NULL,
+ password_last_changed_at timestamp with time zone DEFAULT now() NOT NULL,
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)),
@@ -22893,6 +23015,7 @@ CREATE TABLE vulnerability_occurrences (
cve text,
location jsonb,
detection_method smallint DEFAULT 0 NOT NULL,
+ uuid_convert_string_to_uuid uuid DEFAULT '00000000-0000-0000-0000-000000000000'::uuid NOT NULL,
CONSTRAINT check_4a3a60f2ba CHECK ((char_length(solution) <= 7000)),
CONSTRAINT check_ade261da6b CHECK ((char_length(description) <= 15000)),
CONSTRAINT check_df6dd20219 CHECK ((char_length(message) <= 3000)),
@@ -22989,6 +23112,7 @@ CREATE TABLE vulnerability_state_transitions (
author_id bigint,
comment text,
dismissal_reason smallint,
+ CONSTRAINT check_d1ca8ec043 CHECK ((from_state <> to_state)),
CONSTRAINT check_fca4a7ca39 CHECK ((char_length(comment) <= 255))
);
@@ -23205,7 +23329,7 @@ CREATE TABLE x509_certificates (
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
subject_key_identifier character varying(255) NOT NULL,
- subject character varying(255) NOT NULL,
+ subject character varying(512) NOT NULL,
email character varying(255) NOT NULL,
serial_number bytea NOT NULL,
certificate_status smallint DEFAULT 0 NOT NULL,
@@ -23371,6 +23495,8 @@ ALTER TABLE ONLY audit_events ALTER COLUMN id SET DEFAULT nextval('audit_events_
ALTER TABLE ONLY audit_events_external_audit_event_destinations ALTER COLUMN id SET DEFAULT nextval('audit_events_external_audit_event_destinations_id_seq'::regclass);
+ALTER TABLE ONLY audit_events_streaming_event_type_filters ALTER COLUMN id SET DEFAULT nextval('audit_events_streaming_event_type_filters_id_seq'::regclass);
+
ALTER TABLE ONLY audit_events_streaming_headers ALTER COLUMN id SET DEFAULT nextval('audit_events_streaming_headers_id_seq'::regclass);
ALTER TABLE ONLY authentication_events ALTER COLUMN id SET DEFAULT nextval('authentication_events_id_seq'::regclass);
@@ -23441,8 +23567,6 @@ ALTER TABLE ONLY ci_build_trace_chunks ALTER COLUMN id SET DEFAULT nextval('ci_b
ALTER TABLE ONLY ci_builds ALTER COLUMN id SET DEFAULT nextval('ci_builds_id_seq'::regclass);
-ALTER TABLE ONLY ci_builds_metadata ALTER COLUMN id SET DEFAULT nextval('ci_builds_metadata_id_seq'::regclass);
-
ALTER TABLE ONLY ci_builds_runner_session ALTER COLUMN id SET DEFAULT nextval('ci_builds_runner_session_id_seq'::regclass);
ALTER TABLE ONLY ci_daily_build_group_report_results ALTER COLUMN id SET DEFAULT nextval('ci_daily_build_group_report_results_id_seq'::regclass);
@@ -23669,8 +23793,6 @@ ALTER TABLE ONLY evidences ALTER COLUMN id SET DEFAULT nextval('evidences_id_seq
ALTER TABLE ONLY experiment_subjects ALTER COLUMN id SET DEFAULT nextval('experiment_subjects_id_seq'::regclass);
-ALTER TABLE ONLY experiment_users ALTER COLUMN id SET DEFAULT nextval('experiment_users_id_seq'::regclass);
-
ALTER TABLE ONLY experiments ALTER COLUMN id SET DEFAULT nextval('experiments_id_seq'::regclass);
ALTER TABLE ONLY external_approval_rules ALTER COLUMN id SET DEFAULT nextval('external_approval_rules_id_seq'::regclass);
@@ -23909,6 +24031,8 @@ ALTER TABLE ONLY namespace_admin_notes ALTER COLUMN id SET DEFAULT nextval('name
ALTER TABLE ONLY namespace_bans ALTER COLUMN id SET DEFAULT nextval('namespace_bans_id_seq'::regclass);
+ALTER TABLE ONLY namespace_commit_emails ALTER COLUMN id SET DEFAULT nextval('namespace_commit_emails_id_seq'::regclass);
+
ALTER TABLE ONLY namespace_statistics ALTER COLUMN id SET DEFAULT nextval('namespace_statistics_id_seq'::regclass);
ALTER TABLE ONLY namespaces ALTER COLUMN id SET DEFAULT nextval('namespaces_id_seq'::regclass);
@@ -23947,6 +24071,8 @@ ALTER TABLE ONLY operations_strategies_user_lists ALTER COLUMN id SET DEFAULT ne
ALTER TABLE ONLY operations_user_lists ALTER COLUMN id SET DEFAULT nextval('operations_user_lists_id_seq'::regclass);
+ALTER TABLE ONLY p_ci_builds_metadata ALTER COLUMN id SET DEFAULT nextval('ci_builds_metadata_id_seq'::regclass);
+
ALTER TABLE ONLY packages_build_infos ALTER COLUMN id SET DEFAULT nextval('packages_build_infos_id_seq'::regclass);
ALTER TABLE ONLY packages_composer_cache_files ALTER COLUMN id SET DEFAULT nextval('packages_composer_cache_files_id_seq'::regclass);
@@ -24069,6 +24195,8 @@ ALTER TABLE ONLY project_statistics ALTER COLUMN id SET DEFAULT nextval('project
ALTER TABLE ONLY project_topics ALTER COLUMN id SET DEFAULT nextval('project_topics_id_seq'::regclass);
+ALTER TABLE ONLY project_wiki_repositories ALTER COLUMN id SET DEFAULT nextval('project_wiki_repositories_id_seq'::regclass);
+
ALTER TABLE ONLY projects ALTER COLUMN id SET DEFAULT nextval('projects_id_seq'::regclass);
ALTER TABLE ONLY projects_sync_events ALTER COLUMN id SET DEFAULT nextval('projects_sync_events_id_seq'::regclass);
@@ -25040,6 +25168,9 @@ ALTER TABLE ONLY audit_events_external_audit_event_destinations
ALTER TABLE ONLY audit_events
ADD CONSTRAINT audit_events_pkey PRIMARY KEY (id, created_at);
+ALTER TABLE ONLY audit_events_streaming_event_type_filters
+ ADD CONSTRAINT audit_events_streaming_event_type_filters_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY audit_events_streaming_headers
ADD CONSTRAINT audit_events_streaming_headers_pkey PRIMARY KEY (id);
@@ -25169,6 +25300,9 @@ ALTER TABLE ONLY ci_build_trace_chunks
ALTER TABLE ONLY ci_build_trace_metadata
ADD CONSTRAINT ci_build_trace_metadata_pkey PRIMARY KEY (build_id);
+ALTER TABLE ONLY p_ci_builds_metadata
+ ADD CONSTRAINT p_ci_builds_metadata_pkey PRIMARY KEY (id, partition_id);
+
ALTER TABLE ONLY ci_builds_metadata
ADD CONSTRAINT ci_builds_metadata_pkey PRIMARY KEY (id, partition_id);
@@ -25442,6 +25576,9 @@ ALTER TABLE ONLY dast_site_validations
ALTER TABLE ONLY dast_sites
ADD CONSTRAINT dast_sites_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY dependency_proxy_blob_states
+ ADD CONSTRAINT dependency_proxy_blob_states_pkey PRIMARY KEY (dependency_proxy_blob_id);
+
ALTER TABLE ONLY dependency_proxy_blobs
ADD CONSTRAINT dependency_proxy_blobs_pkey PRIMARY KEY (id);
@@ -25559,9 +25696,6 @@ ALTER TABLE ONLY evidences
ALTER TABLE ONLY experiment_subjects
ADD CONSTRAINT experiment_subjects_pkey PRIMARY KEY (id);
-ALTER TABLE ONLY experiment_users
- ADD CONSTRAINT experiment_users_pkey PRIMARY KEY (id);
-
ALTER TABLE ONLY experiments
ADD CONSTRAINT experiments_pkey PRIMARY KEY (id);
@@ -25811,9 +25945,6 @@ ALTER TABLE ONLY issues_self_managed_prometheus_alert_events
ALTER TABLE ONLY sprints
ADD CONSTRAINT iteration_start_and_due_date_iterations_cadence_id_constraint EXCLUDE USING gist (iterations_cadence_id WITH =, daterange(start_date, due_date, '[]'::text) WITH &&) WHERE ((group_id IS NOT NULL)) DEFERRABLE INITIALLY DEFERRED;
-ALTER TABLE ONLY sprints
- ADD CONSTRAINT iteration_start_and_due_daterange_project_id_constraint EXCLUDE USING gist (project_id WITH =, daterange(start_date, due_date, '[]'::text) WITH &&) WHERE ((project_id IS NOT NULL));
-
ALTER TABLE ONLY iterations_cadences
ADD CONSTRAINT iterations_cadences_pkey PRIMARY KEY (id);
@@ -25967,6 +26098,9 @@ ALTER TABLE ONLY namespace_bans
ALTER TABLE ONLY namespace_ci_cd_settings
ADD CONSTRAINT namespace_ci_cd_settings_pkey PRIMARY KEY (namespace_id);
+ALTER TABLE ONLY namespace_commit_emails
+ ADD CONSTRAINT namespace_commit_emails_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY namespace_details
ADD CONSTRAINT namespace_details_pkey PRIMARY KEY (namespace_id);
@@ -26273,6 +26407,9 @@ ALTER TABLE ONLY project_statistics
ALTER TABLE ONLY project_topics
ADD CONSTRAINT project_topics_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY project_wiki_repositories
+ ADD CONSTRAINT project_wiki_repositories_pkey PRIMARY KEY (id);
+
ALTER TABLE ONLY project_wiki_repository_states
ADD CONSTRAINT project_wiki_repository_states_pkey PRIMARY KEY (project_id);
@@ -27835,6 +27972,8 @@ CREATE UNIQUE INDEX idx_project_id_payload_key_self_managed_prometheus_alert_eve
CREATE INDEX idx_project_repository_check_partial ON projects USING btree (repository_storage, created_at) WHERE (last_repository_check_at IS NULL);
+CREATE INDEX idx_project_wiki_repository_states_project_wiki_repository_id ON project_wiki_repository_states USING btree (project_wiki_repository_id);
+
CREATE INDEX idx_projects_api_created_at_id_for_archived ON projects USING btree (created_at, id) WHERE ((archived = true) AND (pending_delete = false) AND (hidden = false));
CREATE INDEX idx_projects_api_created_at_id_for_archived_vis20 ON projects USING btree (created_at, id) WHERE ((archived = true) AND (visibility_level = 20) AND (pending_delete = false) AND (hidden = false));
@@ -27867,6 +28006,8 @@ CREATE UNIQUE INDEX idx_serverless_domain_cluster_on_clusters_applications_knati
CREATE INDEX idx_streaming_headers_on_external_audit_event_destination_id ON audit_events_streaming_headers USING btree (external_audit_event_destination_id);
+CREATE INDEX idx_test_reports_on_issue_id_created_at_and_id ON requirements_management_test_reports USING btree (issue_id, created_at, id);
+
CREATE INDEX idx_user_details_on_provisioned_by_group_id_user_id ON user_details USING btree (provisioned_by_group_id, user_id);
CREATE UNIQUE INDEX idx_vuln_signatures_on_occurrences_id_and_signature_sha ON vulnerability_finding_signatures USING btree (finding_id, signature_sha);
@@ -28181,14 +28322,24 @@ CREATE UNIQUE INDEX index_ci_build_trace_chunks_on_build_id_and_chunk_index ON c
CREATE INDEX index_ci_build_trace_metadata_on_trace_artifact_id ON ci_build_trace_metadata USING btree (trace_artifact_id);
+CREATE INDEX p_ci_builds_metadata_build_id_idx ON ONLY p_ci_builds_metadata USING btree (build_id) WHERE (has_exposed_artifacts IS TRUE);
+
CREATE INDEX index_ci_builds_metadata_on_build_id_and_has_exposed_artifacts ON ci_builds_metadata USING btree (build_id) WHERE (has_exposed_artifacts IS TRUE);
+CREATE INDEX p_ci_builds_metadata_build_id_id_idx ON ONLY p_ci_builds_metadata USING btree (build_id) INCLUDE (id) WHERE (interruptible = true);
+
CREATE INDEX index_ci_builds_metadata_on_build_id_and_id_and_interruptible ON ci_builds_metadata USING btree (build_id) INCLUDE (id) WHERE (interruptible = true);
+CREATE UNIQUE INDEX p_ci_builds_metadata_build_id_partition_id_idx ON ONLY p_ci_builds_metadata USING btree (build_id, partition_id);
+
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);
CREATE INDEX index_ci_builds_on_auto_canceled_by_id ON ci_builds USING btree (auto_canceled_by_id);
@@ -28319,7 +28470,7 @@ CREATE UNIQUE INDEX index_ci_pipeline_chat_data_on_pipeline_id ON ci_pipeline_ch
CREATE INDEX index_ci_pipeline_messages_on_pipeline_id ON ci_pipeline_messages USING btree (pipeline_id);
-CREATE INDEX index_ci_pipeline_metadata_on_pipeline_id_title ON ci_pipeline_metadata USING btree (pipeline_id, title);
+CREATE INDEX index_ci_pipeline_metadata_on_pipeline_id_name ON ci_pipeline_metadata USING btree (pipeline_id, name);
CREATE INDEX index_ci_pipeline_metadata_on_project_id ON ci_pipeline_metadata USING btree (project_id);
@@ -28421,10 +28572,6 @@ CREATE INDEX index_ci_runners_on_locked ON ci_runners USING btree (locked);
CREATE INDEX index_ci_runners_on_runner_type ON ci_runners USING btree (runner_type);
-CREATE INDEX index_ci_runners_on_token ON ci_runners USING btree (token);
-
-CREATE INDEX index_ci_runners_on_token_encrypted ON ci_runners USING btree (token_encrypted);
-
CREATE INDEX index_ci_runners_on_token_expires_at_and_id_desc ON ci_runners USING btree (token_expires_at, id DESC);
CREATE INDEX index_ci_runners_on_token_expires_at_desc_and_id_desc ON ci_runners USING btree (token_expires_at DESC, id DESC);
@@ -28587,6 +28734,8 @@ CREATE INDEX index_container_repositories_on_project_id_and_id ON container_repo
CREATE UNIQUE INDEX index_container_repositories_on_project_id_and_name ON container_repositories USING btree (project_id, name);
+CREATE INDEX index_container_repositories_on_status_and_id ON container_repositories USING btree (status, id) WHERE (status IS NOT NULL);
+
CREATE INDEX index_container_repository_on_name_trigram ON container_repositories USING gin (name gin_trgm_ops);
CREATE UNIQUE INDEX index_content_blocked_states_on_container_id_commit_sha_path ON content_blocked_states USING btree (container_identifier, commit_sha, path);
@@ -28657,6 +28806,16 @@ CREATE UNIQUE INDEX index_dast_sites_on_project_id_and_url ON dast_sites USING b
CREATE UNIQUE INDEX index_dep_prox_manifests_on_group_id_file_name_and_status ON dependency_proxy_manifests USING btree (group_id, file_name, status);
+CREATE INDEX index_dependency_proxy_blob_states_failed_verification ON dependency_proxy_blob_states USING btree (verification_retry_at NULLS FIRST) WHERE (verification_state = 3);
+
+CREATE INDEX index_dependency_proxy_blob_states_needs_verification ON dependency_proxy_blob_states USING btree (verification_state) WHERE ((verification_state = 0) OR (verification_state = 3));
+
+CREATE INDEX index_dependency_proxy_blob_states_on_dependency_proxy_blob_id ON dependency_proxy_blob_states USING btree (dependency_proxy_blob_id);
+
+CREATE INDEX index_dependency_proxy_blob_states_on_verification_state ON dependency_proxy_blob_states USING btree (verification_state);
+
+CREATE INDEX index_dependency_proxy_blob_states_pending_verification ON dependency_proxy_blob_states USING btree (verified_at NULLS FIRST) WHERE (verification_state = 0);
+
CREATE INDEX index_dependency_proxy_blobs_on_group_id_and_file_name ON dependency_proxy_blobs USING btree (group_id, file_name);
CREATE INDEX index_dependency_proxy_blobs_on_group_id_status_read_at_id ON dependency_proxy_blobs USING btree (group_id, status, read_at, id);
@@ -28915,10 +29074,6 @@ CREATE INDEX index_experiment_subjects_on_project_id ON experiment_subjects USIN
CREATE INDEX index_experiment_subjects_on_user_id ON experiment_subjects USING btree (user_id);
-CREATE INDEX index_experiment_users_on_experiment_id ON experiment_users USING btree (experiment_id);
-
-CREATE INDEX index_experiment_users_on_user_id ON experiment_users USING btree (user_id);
-
CREATE UNIQUE INDEX index_experiments_on_name ON experiments USING btree (name);
CREATE INDEX index_expired_and_not_notified_personal_access_tokens ON personal_access_tokens USING btree (id, expires_at) WHERE ((impersonation = false) AND (revoked = false) AND (expire_notification_delivered = false));
@@ -28999,6 +29154,8 @@ CREATE INDEX index_geo_repository_updated_events_on_source ON geo_repository_upd
CREATE INDEX index_geo_reset_checksum_events_on_project_id ON geo_reset_checksum_events USING btree (project_id);
+CREATE INDEX index_ghost_user_migrations_on_consume_after_id ON ghost_user_migrations USING btree (consume_after, id);
+
CREATE UNIQUE INDEX index_ghost_user_migrations_on_user_id ON ghost_user_migrations USING btree (user_id);
CREATE INDEX index_gin_ci_namespace_mirrors_on_traversal_ids ON ci_namespace_mirrors USING gin (traversal_ids);
@@ -29011,6 +29168,8 @@ CREATE INDEX index_gitlab_subscriptions_on_end_date_and_namespace_id ON gitlab_s
CREATE INDEX index_gitlab_subscriptions_on_hosted_plan_id ON gitlab_subscriptions USING btree (hosted_plan_id);
+CREATE INDEX index_gitlab_subscriptions_on_max_seats_used_changed_at ON gitlab_subscriptions USING btree (max_seats_used_changed_at, namespace_id);
+
CREATE UNIQUE INDEX index_gitlab_subscriptions_on_namespace_id ON gitlab_subscriptions USING btree (namespace_id);
CREATE UNIQUE INDEX index_gpg_key_subkeys_on_fingerprint ON gpg_key_subkeys USING btree (fingerprint);
@@ -29079,6 +29238,8 @@ CREATE INDEX index_group_stages_on_stage_event_hash_id ON analytics_cycle_analyt
CREATE UNIQUE INDEX index_group_user_callouts_feature ON user_group_callouts USING btree (user_id, feature_name, group_id);
+CREATE INDEX index_group_vulnerability_reads_common_finder_query_desc ON vulnerability_reads USING btree (namespace_id, state, report_type, severity DESC, vulnerability_id DESC);
+
CREATE UNIQUE INDEX index_group_wiki_repositories_on_disk_path ON group_wiki_repositories USING btree (disk_path);
CREATE INDEX index_group_wiki_repositories_on_shard_id ON group_wiki_repositories USING btree (shard_id);
@@ -29099,7 +29260,7 @@ CREATE UNIQUE INDEX index_im_oncall_schedules_on_project_id_and_iid ON incident_
CREATE INDEX index_im_timeline_event_id ON incident_management_timeline_event_tag_links USING btree (timeline_event_id);
-CREATE UNIQUE INDEX index_im_timeline_event_tags_name_project_id ON incident_management_timeline_event_tags USING btree (project_id, name);
+CREATE UNIQUE INDEX index_im_timeline_event_tags_on_lower_name_and_project_id ON incident_management_timeline_event_tags USING btree (project_id, lower(name));
CREATE UNIQUE INDEX index_im_timeline_event_tags_on_tag_id_and_event_id ON incident_management_timeline_event_tag_links USING btree (timeline_event_tag_id, timeline_event_id);
@@ -29131,6 +29292,8 @@ CREATE INDEX index_imported_projects_on_import_type_creator_id_created_at ON pro
CREATE INDEX index_imported_projects_on_import_type_id ON projects USING btree (import_type, id) WHERE (import_type IS NOT NULL);
+CREATE INDEX index_in_product_marketing_emails_on_track_series_id_clicked ON in_product_marketing_emails USING btree (track, series, id, cta_clicked_at);
+
CREATE UNIQUE INDEX index_in_product_marketing_emails_on_user_campaign ON in_product_marketing_emails USING btree (user_id, campaign);
CREATE INDEX index_in_product_marketing_emails_on_user_id ON in_product_marketing_emails USING btree (user_id);
@@ -29235,7 +29398,9 @@ CREATE INDEX index_issues_on_closed_by_id ON issues USING btree (closed_by_id);
CREATE INDEX index_issues_on_confidential ON issues USING btree (confidential);
-CREATE INDEX index_issues_on_description_trigram ON issues USING gin (description gin_trgm_ops);
+CREATE INDEX index_issues_on_description_trigram ON issues USING gin (description gin_trgm_ops) WITH (fastupdate='false');
+
+CREATE INDEX index_issues_on_description_trigram_non_latin ON issues USING gin (description gin_trgm_ops) WHERE (((title)::text !~ similar_escape('[\u0000-\u02FF\u1E00-\u1EFF\u2070-\u218F]*'::text, NULL::text)) OR (description !~ similar_escape('[\u0000-\u02FF\u1E00-\u1EFF\u2070-\u218F]*'::text, NULL::text)));
CREATE INDEX index_issues_on_duplicated_to_id ON issues USING btree (duplicated_to_id) WHERE (duplicated_to_id IS NOT NULL);
@@ -29271,7 +29436,9 @@ CREATE INDEX index_issues_on_promoted_to_epic_id ON issues USING btree (promoted
CREATE INDEX index_issues_on_sprint_id ON issues USING btree (sprint_id);
-CREATE INDEX index_issues_on_title_trigram ON issues USING gin (title gin_trgm_ops);
+CREATE INDEX index_issues_on_title_trigram ON issues USING gin (title gin_trgm_ops) WITH (fastupdate='false');
+
+CREATE INDEX index_issues_on_title_trigram_non_latin ON issues USING gin (title gin_trgm_ops) WHERE (((title)::text !~ similar_escape('[\u0000-\u02FF\u1E00-\u1EFF\u2070-\u218F]*'::text, NULL::text)) OR (description !~ similar_escape('[\u0000-\u02FF\u1E00-\u1EFF\u2070-\u218F]*'::text, NULL::text)));
CREATE INDEX index_issues_on_updated_at ON issues USING btree (updated_at);
@@ -29481,9 +29648,13 @@ CREATE INDEX index_merge_requests_on_assignee_id ON merge_requests USING btree (
CREATE INDEX index_merge_requests_on_author_id ON merge_requests USING btree (author_id);
+CREATE INDEX index_merge_requests_on_author_id_and_id ON merge_requests USING btree (author_id, id);
+
+CREATE INDEX index_merge_requests_on_author_id_and_target_project_id ON merge_requests USING btree (author_id, target_project_id);
+
CREATE INDEX index_merge_requests_on_created_at ON merge_requests USING btree (created_at);
-CREATE INDEX index_merge_requests_on_description_trigram ON merge_requests USING gin (description gin_trgm_ops);
+CREATE INDEX index_merge_requests_on_description_trigram ON merge_requests USING gin (description gin_trgm_ops) WITH (fastupdate='false');
CREATE INDEX index_merge_requests_on_head_pipeline_id ON merge_requests USING btree (head_pipeline_id);
@@ -29519,7 +29690,7 @@ CREATE INDEX index_merge_requests_on_target_project_id_and_updated_at_and_id ON
CREATE INDEX index_merge_requests_on_target_project_id_iid_jira_description ON merge_requests USING btree (target_project_id, iid) WHERE (description ~ '[A-Z][A-Z_0-9]+-\d+'::text);
-CREATE INDEX index_merge_requests_on_title_trigram ON merge_requests USING gin (title gin_trgm_ops);
+CREATE INDEX index_merge_requests_on_title_trigram ON merge_requests USING gin (title gin_trgm_ops) WITH (fastupdate='false');
CREATE INDEX index_merge_requests_on_tp_id_and_merge_commit_sha_and_id ON merge_requests USING btree (target_project_id, merge_commit_sha, id);
@@ -29593,6 +29764,12 @@ CREATE UNIQUE INDEX index_namespace_bans_on_namespace_id_and_user_id ON namespac
CREATE INDEX index_namespace_bans_on_user_id ON namespace_bans USING btree (user_id);
+CREATE INDEX index_namespace_commit_emails_on_email_id ON namespace_commit_emails USING btree (email_id);
+
+CREATE INDEX index_namespace_commit_emails_on_namespace_id ON namespace_commit_emails USING btree (namespace_id);
+
+CREATE UNIQUE INDEX index_namespace_commit_emails_on_user_id_and_namespace_id ON namespace_commit_emails USING btree (user_id, namespace_id);
+
CREATE UNIQUE INDEX index_namespace_root_storage_statistics_on_namespace_id ON namespace_root_storage_statistics USING btree (namespace_id);
CREATE UNIQUE INDEX index_namespace_statistics_on_namespace_id ON namespace_statistics USING btree (namespace_id);
@@ -29857,7 +30034,7 @@ CREATE INDEX index_packages_project_id_name_partial_for_nuget ON packages_packag
CREATE INDEX index_packages_rpm_metadata_on_package_id ON packages_rpm_metadata USING btree (package_id);
-CREATE INDEX index_packages_rpm_repository_files_on_project_id ON packages_rpm_repository_files USING btree (project_id);
+CREATE INDEX index_packages_rpm_repository_files_on_project_id_and_file_name ON packages_rpm_repository_files USING btree (project_id, file_name);
CREATE INDEX index_packages_tags_on_package_id ON packages_tags USING btree (package_id);
@@ -30059,6 +30236,8 @@ CREATE INDEX index_project_topics_on_topic_id ON project_topics USING btree (top
CREATE UNIQUE INDEX index_project_user_callouts_feature ON user_project_callouts USING btree (user_id, feature_name, project_id);
+CREATE UNIQUE INDEX index_project_wiki_repositories_on_project_id ON project_wiki_repositories USING btree (project_id);
+
CREATE INDEX index_project_wiki_repository_states_failed_verification ON project_wiki_repository_states USING btree (verification_retry_at NULLS FIRST) WHERE (verification_state = 3);
CREATE INDEX index_project_wiki_repository_states_needs_verification ON project_wiki_repository_states USING btree (verification_state) WHERE ((verification_state = 0) OR (verification_state = 3));
@@ -30189,6 +30368,8 @@ CREATE INDEX index_protected_branch_unprotect_access_levels_on_group_id ON prote
CREATE INDEX index_protected_branch_unprotect_access_levels_on_user_id ON protected_branch_unprotect_access_levels USING btree (user_id);
+CREATE INDEX index_protected_branches_namespace_id ON protected_branches USING btree (namespace_id) WHERE (namespace_id IS NOT NULL);
+
CREATE INDEX index_protected_branches_on_project_id ON protected_branches USING btree (project_id);
CREATE INDEX index_protected_environment_approval_rules_on_group_id ON protected_environment_approval_rules USING btree (group_id);
@@ -30359,7 +30540,7 @@ CREATE INDEX index_sbom_component_versions_on_component_id ON sbom_component_ver
CREATE UNIQUE INDEX index_sbom_component_versions_on_component_id_and_version ON sbom_component_versions USING btree (component_id, version);
-CREATE UNIQUE INDEX index_sbom_components_on_component_type_and_name ON sbom_components USING btree (component_type, name);
+CREATE UNIQUE INDEX index_sbom_components_on_component_type_name_and_purl_type ON sbom_components USING btree (name, purl_type, component_type);
CREATE INDEX index_sbom_occurrences_on_component_id ON sbom_occurrences USING btree (component_id);
@@ -30391,6 +30572,8 @@ CREATE INDEX index_security_scans_on_created_at ON security_scans USING btree (c
CREATE INDEX index_security_scans_on_date_created_at_and_id ON security_scans USING btree (date(timezone('UTC'::text, created_at)), id);
+CREATE INDEX index_security_scans_on_id_for_non_purged_records ON security_scans USING btree (id) WHERE (status <> 6);
+
CREATE INDEX index_security_scans_on_length_of_errors ON security_scans USING btree (pipeline_id, jsonb_array_length(COALESCE((info -> 'errors'::text), '[]'::jsonb)));
CREATE INDEX index_security_scans_on_length_of_warnings ON security_scans USING btree (pipeline_id, jsonb_array_length(COALESCE((info -> 'warnings'::text), '[]'::jsonb)));
@@ -30503,8 +30686,6 @@ CREATE INDEX index_sprints_on_due_date ON sprints USING btree (due_date);
CREATE INDEX index_sprints_on_group_id ON sprints USING btree (group_id);
-CREATE UNIQUE INDEX index_sprints_on_project_id_and_iid ON sprints USING btree (project_id, iid);
-
CREATE INDEX index_sprints_on_title ON sprints USING btree (title);
CREATE INDEX index_sprints_on_title_trigram ON sprints USING gin (title gin_trgm_ops);
@@ -30623,6 +30804,10 @@ CREATE INDEX index_u2f_registrations_on_key_handle ON u2f_registrations USING bt
CREATE INDEX index_u2f_registrations_on_user_id ON u2f_registrations USING btree (user_id);
+CREATE UNIQUE INDEX index_uniq_ci_runners_on_token ON ci_runners USING btree (token);
+
+CREATE UNIQUE INDEX index_uniq_ci_runners_on_token_encrypted ON ci_runners USING btree (token_encrypted);
+
CREATE UNIQUE INDEX index_uniq_im_issuable_escalation_statuses_on_issue_id ON incident_management_issuable_escalation_statuses USING btree (issue_id);
CREATE UNIQUE INDEX index_uniq_projects_on_runners_token ON projects USING btree (runners_token);
@@ -30681,6 +30866,10 @@ CREATE INDEX index_user_custom_attributes_on_key_and_value ON user_custom_attrib
CREATE UNIQUE INDEX index_user_custom_attributes_on_user_id_and_key ON user_custom_attributes USING btree (user_id, key);
+CREATE INDEX index_user_details_on_password_last_changed_at ON user_details USING btree (password_last_changed_at);
+
+COMMENT ON INDEX index_user_details_on_password_last_changed_at IS 'JiHu-specific index';
+
CREATE UNIQUE INDEX index_user_details_on_phone ON user_details USING btree (phone) WHERE (phone IS NOT NULL);
COMMENT ON INDEX index_user_details_on_phone IS 'JiHu-specific index';
@@ -30837,6 +31026,10 @@ CREATE INDEX index_vulnerability_feedback_on_author_id ON vulnerability_feedback
CREATE INDEX index_vulnerability_feedback_on_comment_author_id ON vulnerability_feedback USING btree (comment_author_id);
+CREATE INDEX index_vulnerability_feedback_on_common_attributes ON vulnerability_feedback USING btree (project_id, category, feedback_type, project_fingerprint);
+
+CREATE INDEX index_vulnerability_feedback_on_feedback_type_and_finding_uuid ON vulnerability_feedback USING btree (feedback_type, finding_uuid);
+
CREATE INDEX index_vulnerability_feedback_on_issue_id ON vulnerability_feedback USING btree (issue_id);
CREATE INDEX index_vulnerability_feedback_on_issue_id_not_null ON vulnerability_feedback USING btree (id) WHERE (issue_id IS NOT NULL);
@@ -30901,6 +31094,8 @@ CREATE INDEX index_vulnerability_reads_on_location_image ON vulnerability_reads
CREATE INDEX index_vulnerability_reads_on_location_image_partial ON vulnerability_reads USING btree (project_id, location_image) WHERE ((report_type = ANY (ARRAY[2, 7])) AND (location_image IS NOT NULL));
+CREATE INDEX index_vulnerability_reads_on_namespace_type_severity_id ON vulnerability_reads USING btree (namespace_id, report_type, severity, vulnerability_id);
+
CREATE INDEX index_vulnerability_reads_on_scanner_id ON vulnerability_reads USING btree (scanner_id);
CREATE UNIQUE INDEX index_vulnerability_reads_on_uuid ON vulnerability_reads USING btree (uuid);
@@ -31031,6 +31226,8 @@ CREATE UNIQUE INDEX partial_index_sop_configs_on_project_id ON security_orchestr
CREATE INDEX partial_index_user_id_app_id_created_at_token_not_revoked ON oauth_access_tokens USING btree (resource_owner_id, application_id, created_at) WHERE (revoked_at IS NULL);
+CREATE INDEX scan_finding_approval_mr_rule_index_id ON approval_merge_request_rules USING btree (id) WHERE (report_type = 4);
+
CREATE INDEX scan_finding_approval_mr_rule_index_merge_request_id ON approval_merge_request_rules USING btree (merge_request_id) WHERE (report_type = 4);
CREATE INDEX scan_finding_approval_project_rule_index_created_at_project_id ON approval_project_rules USING btree (created_at, project_id) WHERE (report_type = 4);
@@ -31059,11 +31256,11 @@ CREATE UNIQUE INDEX taggings_idx ON taggings USING btree (tag_id, taggable_id, t
CREATE UNIQUE INDEX term_agreements_unique_index ON term_agreements USING btree (user_id, term_id);
-CREATE INDEX tmp_idx_project_features_on_releases_al_and_repo_al_partial ON project_features USING btree (releases_access_level, repository_access_level) WHERE (releases_access_level > repository_access_level);
+CREATE INDEX tmp_idx_for_vulnerability_feedback_migration ON vulnerability_feedback USING btree (migrated_to_state_transition, feedback_type) WHERE ((migrated_to_state_transition = false) AND (feedback_type = 0));
CREATE INDEX tmp_idx_vulnerabilities_on_id_where_report_type_7_99 ON vulnerabilities USING btree (id) WHERE (report_type = ANY (ARRAY[7, 99]));
-CREATE INDEX tmp_index_approval_merge_request_rules_on_report_type_equal_one ON approval_merge_request_rules USING btree (id, report_type) WHERE (report_type = 1);
+CREATE INDEX tmp_idx_where_user_details_fields_filled ON users USING btree (id) WHERE (((COALESCE(linkedin, ''::character varying))::text IS DISTINCT FROM ''::text) OR ((COALESCE(twitter, ''::character varying))::text IS DISTINCT FROM ''::text) OR ((COALESCE(skype, ''::character varying))::text IS DISTINCT FROM ''::text) OR ((COALESCE(website_url, ''::character varying))::text IS DISTINCT FROM ''::text) OR ((COALESCE(location, ''::character varying))::text IS DISTINCT FROM ''::text) OR ((COALESCE(organization, ''::character varying))::text IS DISTINCT FROM ''::text));
CREATE INDEX tmp_index_ci_job_artifacts_on_expire_at_where_locked_unknown ON ci_job_artifacts USING btree (expire_at, job_id) WHERE ((locked = 2) AND (expire_at IS NOT NULL));
@@ -31081,8 +31278,6 @@ CREATE INDEX tmp_index_for_project_namespace_id_migration_on_routes ON routes US
CREATE INDEX tmp_index_issues_on_issue_type_and_id ON issues USING btree (issue_type, id);
-CREATE INDEX tmp_index_members_on_id_where_namespace_id_null ON members USING btree (id) WHERE (member_namespace_id 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));
@@ -31093,7 +31288,7 @@ CREATE INDEX tmp_index_on_vulnerabilities_non_dismissed ON vulnerabilities USING
CREATE INDEX tmp_index_project_statistics_cont_registry_size ON project_statistics USING btree (project_id) WHERE (container_registry_size = 0);
-CREATE INDEX tmp_index_system_note_metadata_on_id_where_task ON system_note_metadata USING btree (id, action) WHERE ((action)::text = 'task'::text);
+CREATE INDEX tmp_index_project_statistics_uploads_size ON project_statistics USING btree (project_id) WHERE (uploads_size <> 0);
CREATE INDEX tmp_index_vulnerability_occurrences_on_id_and_scanner_id ON vulnerability_occurrences USING btree (id, scanner_id) WHERE (report_type = ANY (ARRAY[7, 99]));
@@ -31117,14 +31312,14 @@ CREATE UNIQUE INDEX unique_merge_request_metrics_by_merge_request_id ON merge_re
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);
+
CREATE UNIQUE INDEX unique_vuln_merge_request_link_vuln_id_and_mr_id ON vulnerability_merge_request_links USING btree (vulnerability_id, merge_request_id);
CREATE INDEX user_follow_users_followee_id_idx ON user_follow_users USING btree (followee_id);
CREATE INDEX users_forbidden_state_idx ON users USING btree (id) WHERE ((confirmed_at IS NOT NULL) AND ((state)::text <> ALL (ARRAY['blocked'::text, 'banned'::text, 'ldap_blocked'::text])));
-CREATE UNIQUE INDEX vulnerability_feedback_unique_idx ON vulnerability_feedback USING btree (project_id, category, feedback_type, project_fingerprint);
-
CREATE UNIQUE INDEX vulnerability_occurrence_pipelines_on_unique_keys ON vulnerability_occurrence_pipelines USING btree (occurrence_id, pipeline_id);
CREATE UNIQUE INDEX work_item_types_namespace_id_and_name_unique ON work_item_types USING btree (namespace_id, btrim(lower(name)));
@@ -32409,6 +32604,18 @@ ALTER INDEX product_analytics_events_experimental_pkey ATTACH PARTITION gitlab_p
ALTER INDEX product_analytics_events_experimental_pkey ATTACH PARTITION gitlab_partitions_static.product_analytics_events_experimental_63_pkey;
+ALTER INDEX p_ci_builds_metadata_pkey ATTACH PARTITION ci_builds_metadata_pkey;
+
+ALTER INDEX p_ci_builds_metadata_build_id_idx ATTACH PARTITION index_ci_builds_metadata_on_build_id_and_has_exposed_artifacts;
+
+ALTER INDEX p_ci_builds_metadata_build_id_id_idx ATTACH PARTITION index_ci_builds_metadata_on_build_id_and_id_and_interruptible;
+
+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();
CREATE TRIGGER ci_builds_loose_fk_trigger AFTER DELETE ON ci_builds REFERENCING OLD TABLE AS old_table FOR EACH STATEMENT EXECUTE FUNCTION insert_into_loose_foreign_keys_deleted_records();
@@ -32427,6 +32634,12 @@ CREATE TRIGGER nullify_merge_request_metrics_build_data_on_update BEFORE UPDATE
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();
+CREATE TRIGGER sync_namespaces_amount_used_columns BEFORE INSERT OR UPDATE ON ci_namespace_monthly_usages FOR EACH ROW EXECUTE FUNCTION sync_namespaces_amount_used_columns();
+
+CREATE TRIGGER sync_projects_amount_used_columns BEFORE INSERT OR UPDATE ON ci_project_monthly_usages FOR EACH ROW EXECUTE FUNCTION sync_projects_amount_used_columns();
+
+CREATE TRIGGER trigger_1a857e8db6cd BEFORE INSERT OR UPDATE ON vulnerability_occurrences FOR EACH ROW EXECUTE FUNCTION trigger_1a857e8db6cd();
+
CREATE TRIGGER trigger_delete_project_namespace_on_project_delete AFTER DELETE ON projects FOR EACH ROW WHEN ((old.project_namespace_id IS NOT NULL)) EXECUTE FUNCTION delete_associated_project_namespace();
CREATE TRIGGER trigger_has_external_issue_tracker_on_delete AFTER DELETE ON integrations FOR EACH ROW WHEN ((((old.category)::text = 'issue_tracker'::text) AND (old.active = true) AND (old.project_id IS NOT NULL))) EXECUTE FUNCTION set_has_external_issue_tracker();
@@ -32472,7 +32685,7 @@ CREATE TRIGGER trigger_update_vulnerability_reads_on_vulnerability_update AFTER
CREATE TRIGGER users_loose_fk_trigger AFTER DELETE ON users REFERENCING OLD TABLE AS old_table FOR EACH STATEMENT EXECUTE FUNCTION insert_into_loose_foreign_keys_deleted_records();
ALTER TABLE ONLY deployments
- ADD CONSTRAINT fk_009fd21147 FOREIGN KEY (environment_id) REFERENCES environments(id) ON DELETE CASCADE NOT VALID;
+ ADD CONSTRAINT fk_009fd21147 FOREIGN KEY (environment_id) REFERENCES environments(id) ON DELETE CASCADE;
ALTER TABLE ONLY epics
ADD CONSTRAINT fk_013c9f36ca FOREIGN KEY (due_date_sourcing_epic_id) REFERENCES epics(id) ON DELETE SET NULL;
@@ -32646,7 +32859,7 @@ ALTER TABLE ONLY vulnerability_merge_request_links
ADD CONSTRAINT fk_2ef3954596 FOREIGN KEY (vulnerability_id) REFERENCES vulnerabilities(id) ON DELETE CASCADE;
ALTER TABLE ONLY members
- ADD CONSTRAINT fk_2f85abf8f1 FOREIGN KEY (member_namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE NOT VALID;
+ ADD CONSTRAINT fk_2f85abf8f1 FOREIGN KEY (member_namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY analytics_cycle_analytics_group_stages
ADD CONSTRAINT fk_3078345d6d FOREIGN KEY (stage_event_hash_id) REFERENCES analytics_cycle_analytics_stage_event_hashes(id) ON DELETE CASCADE;
@@ -32738,6 +32951,9 @@ ALTER TABLE ONLY user_namespace_callouts
ALTER TABLE ONLY sbom_occurrences
ADD CONSTRAINT fk_4b88e5b255 FOREIGN KEY (component_version_id) REFERENCES sbom_component_versions(id) ON DELETE CASCADE;
+ALTER TABLE ONLY namespace_commit_emails
+ ADD CONSTRAINT fk_4d6ba63ba5 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY vulnerability_reads
ADD CONSTRAINT fk_4f593f6c62 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@@ -32813,6 +33029,9 @@ ALTER TABLE ONLY ci_builds
ALTER TABLE ONLY application_settings
ADD CONSTRAINT fk_693b8795e4 FOREIGN KEY (push_rule_id) REFERENCES push_rules(id) ON DELETE SET NULL;
+ALTER TABLE ONLY project_wiki_repository_states
+ ADD CONSTRAINT fk_6951681c70 FOREIGN KEY (project_wiki_repository_id) REFERENCES project_wiki_repositories(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY merge_requests
ADD CONSTRAINT fk_6a5165a692 FOREIGN KEY (milestone_id) REFERENCES milestones(id) ON DELETE SET NULL;
@@ -33056,9 +33275,6 @@ ALTER TABLE ONLY epics
ALTER TABLE ONLY dast_profiles
ADD CONSTRAINT fk_aa76ef30e9 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
-ALTER TABLE ONLY members
- ADD CONSTRAINT fk_aa82dcc1c6 FOREIGN KEY (member_namespace_id) REFERENCES namespaces(id) ON DELETE SET NULL;
-
ALTER TABLE ONLY alert_management_alerts
ADD CONSTRAINT fk_aad61aedca FOREIGN KEY (environment_id) REFERENCES environments(id) ON DELETE SET NULL;
@@ -33122,6 +33338,9 @@ ALTER TABLE ONLY issue_assignees
ALTER TABLE ONLY agent_project_authorizations
ADD CONSTRAINT fk_b7fe9b4777 FOREIGN KEY (agent_id) REFERENCES cluster_agents(id) ON DELETE CASCADE;
+ALTER TABLE ONLY namespace_commit_emails
+ ADD CONSTRAINT fk_b8d89d555e FOREIGN KEY (email_id) REFERENCES emails(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY ci_trigger_requests
ADD CONSTRAINT fk_b8ec8b7245 FOREIGN KEY (trigger_id) REFERENCES ci_triggers(id) ON DELETE CASCADE;
@@ -33284,6 +33503,9 @@ ALTER TABLE ONLY security_scans
ALTER TABLE ONLY epics
ADD CONSTRAINT fk_dccd3f98fc FOREIGN KEY (assignee_id) REFERENCES users(id) ON DELETE SET NULL;
+ALTER TABLE ONLY protected_branches
+ ADD CONSTRAINT fk_de9216e774 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY issues
ADD CONSTRAINT fk_df75a7c8b8 FOREIGN KEY (promoted_to_epic_id) REFERENCES epics(id) ON DELETE SET NULL;
@@ -33296,7 +33518,7 @@ ALTER TABLE ONLY ci_resources
ALTER TABLE ONLY ci_sources_pipelines
ADD CONSTRAINT fk_e1bad85861 FOREIGN KEY (pipeline_id) REFERENCES ci_pipelines(id) ON DELETE CASCADE;
-ALTER TABLE ONLY ci_builds_metadata
+ALTER TABLE p_ci_builds_metadata
ADD CONSTRAINT fk_e20479742e FOREIGN KEY (build_id) REFERENCES ci_builds(id) ON DELETE CASCADE;
ALTER TABLE ONLY gitlab_subscriptions
@@ -33320,9 +33542,6 @@ ALTER TABLE ONLY namespaces
ALTER TABLE ONLY fork_networks
ADD CONSTRAINT fk_e7b436b2b5 FOREIGN KEY (root_project_id) REFERENCES projects(id) ON DELETE SET NULL;
-ALTER TABLE ONLY sprints
- ADD CONSTRAINT fk_e8206c9686 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
-
ALTER TABLE ONLY application_settings
ADD CONSTRAINT fk_e8a145f3a7 FOREIGN KEY (instance_administrators_group_id) REFERENCES namespaces(id) ON DELETE SET NULL;
@@ -33911,6 +34130,9 @@ ALTER TABLE ONLY project_metrics_settings
ALTER TABLE ONLY prometheus_metrics
ADD CONSTRAINT fk_rails_4c8957a707 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+ALTER TABLE ONLY dependency_proxy_blob_states
+ ADD CONSTRAINT fk_rails_4cdbb92cbd FOREIGN KEY (dependency_proxy_blob_id) REFERENCES dependency_proxy_blobs(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY scim_identities
ADD CONSTRAINT fk_rails_4d2056ebd9 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
@@ -33965,9 +34187,6 @@ ALTER TABLE ONLY issuable_metric_images
ALTER TABLE ONLY group_deploy_keys
ADD CONSTRAINT fk_rails_5682fc07f8 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT;
-ALTER TABLE ONLY experiment_users
- ADD CONSTRAINT fk_rails_56d4708b4a FOREIGN KEY (experiment_id) REFERENCES experiments(id) ON DELETE CASCADE;
-
ALTER TABLE ONLY issue_user_mentions
ADD CONSTRAINT fk_rails_57581fda73 FOREIGN KEY (issue_id) REFERENCES issues(id) ON DELETE CASCADE;
@@ -34670,6 +34889,9 @@ ALTER TABLE ONLY packages_nuget_dependency_link_metadata
ALTER TABLE ONLY group_deploy_keys_groups
ADD CONSTRAINT fk_rails_c3854f19f5 FOREIGN KEY (group_deploy_key_id) REFERENCES group_deploy_keys(id) ON DELETE CASCADE;
+ALTER TABLE ONLY project_wiki_repositories
+ ADD CONSTRAINT fk_rails_c3dd796199 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY merge_request_user_mentions
ADD CONSTRAINT fk_rails_c440b9ea31 FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE;
@@ -34826,6 +35048,9 @@ ALTER TABLE ONLY packages_debian_project_distributions
ALTER TABLE ONLY incident_management_oncall_shifts
ADD CONSTRAINT fk_rails_df4feb286a FOREIGN KEY (rotation_id) REFERENCES incident_management_oncall_rotations(id) ON DELETE CASCADE;
+ALTER TABLE ONLY namespace_commit_emails
+ ADD CONSTRAINT fk_rails_dfa4c104f5 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY analytics_cycle_analytics_group_stages
ADD CONSTRAINT fk_rails_dfb37c880d FOREIGN KEY (end_event_label_id) REFERENCES labels(id) ON DELETE CASCADE;
@@ -34889,6 +35114,9 @@ ALTER TABLE ONLY dast_site_tokens
ALTER TABLE ONLY group_deploy_keys_groups
ADD CONSTRAINT fk_rails_e87145115d FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
+ALTER TABLE ONLY audit_events_streaming_event_type_filters
+ ADD CONSTRAINT fk_rails_e8bd011129 FOREIGN KEY (external_audit_event_destination_id) REFERENCES audit_events_external_audit_event_destinations(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY description_versions
ADD CONSTRAINT fk_rails_e8f4caf9c7 FOREIGN KEY (epic_id) REFERENCES epics(id) ON DELETE CASCADE;
@@ -35024,9 +35252,6 @@ ALTER TABLE ONLY customer_relations_contacts
ALTER TABLE ONLY external_approval_rules
ADD CONSTRAINT fk_rails_fd4f9ac573 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
-ALTER TABLE ONLY experiment_users
- ADD CONSTRAINT fk_rails_fd805f771a FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
-
ALTER TABLE ONLY cluster_groups
ADD CONSTRAINT fk_rails_fdb8648a96 FOREIGN KEY (cluster_id) REFERENCES clusters(id) ON DELETE CASCADE;
diff --git a/doc/.markdownlint/require_helper.js b/doc/.markdownlint/require_helper.js
new file mode 100644
index 00000000000..7d06cf67419
--- /dev/null
+++ b/doc/.markdownlint/require_helper.js
@@ -0,0 +1,14 @@
+/**
+ * Look up the global node modules directory.
+ *
+ * Because we install markdownlint packages globally
+ * in the Docker image where this runs, we need to
+ * provide the path to the global install location
+ * when referencing global functions from our own node
+ * modules.
+ *
+ * Image:
+ * https://gitlab.com/gitlab-org/gitlab-docs/-/blob/main/dockerfiles/gitlab-docs-lint-markdown.Dockerfile
+ */
+const { execSync } = require('child_process');
+module.exports.globalPath = execSync('yarn global dir').toString().trim() + '/node_modules/';
diff --git a/doc/.markdownlint/rules/tabs_blank_lines.js b/doc/.markdownlint/rules/tabs_blank_lines.js
new file mode 100644
index 00000000000..e0e2c1a0a9b
--- /dev/null
+++ b/doc/.markdownlint/rules/tabs_blank_lines.js
@@ -0,0 +1,26 @@
+const { globalPath } = require('../require_helper');
+const {
+ forEachLine,
+ getLineMetadata,
+ isBlankLine,
+} = require(`${globalPath}/markdownlint-rule-helpers`);
+
+module.exports = {
+ names: ['tabs-blank-lines'],
+ description: 'Tab elements must be surrounded by blank lines',
+ tags: ['gitlab-docs', 'tabs'],
+ function: (params, onError) => {
+ const tabElements = ['::Tabs', '::EndTabs', ':::TabTitle'];
+ forEachLine(getLineMetadata(params), (line, lineIndex) => {
+ const lineHasTab = tabElements.includes(line.split(' ')[0]);
+ const prevLine = params.lines[lineIndex - 1];
+ const nextLine = params.lines[lineIndex + 1];
+
+ if (lineHasTab && (!isBlankLine(prevLine) || !isBlankLine(nextLine))) {
+ onError({
+ lineNumber: lineIndex + 1,
+ });
+ }
+ });
+ },
+};
diff --git a/doc/.markdownlint/rules/tabs_title_markup.js b/doc/.markdownlint/rules/tabs_title_markup.js
new file mode 100644
index 00000000000..9c1de1e630d
--- /dev/null
+++ b/doc/.markdownlint/rules/tabs_title_markup.js
@@ -0,0 +1,31 @@
+const { globalPath } = require('../require_helper');
+const { forEachLine, getLineMetadata } = require(`${globalPath}/markdownlint-rule-helpers`);
+
+module.exports = {
+ names: ['tabs-title-markup'],
+ description: 'Incorrect number of colon characters for tag',
+ information: new URL('https://docs.gitlab.com/ee/development/documentation/styleguide/#tabs'),
+ tags: ['gitlab-docs', 'tabs'],
+ function: (params, onError) => {
+ // Note the correct number of colons in each tab tag type.
+ const wrapperColons = 2;
+ const titleColons = 3;
+
+ forEachLine(getLineMetadata(params), (line, lineIndex) => {
+ // Get the number of colons in this line.
+ const colonCount = [...line].filter((x) => x === ':').length;
+
+ // Throw an error in the case of a mismatch.
+ if (
+ ((line.includes(':Tabs') || line.includes(':EndTabs')) && colonCount !== wrapperColons) ||
+ (line.includes(':TabTitle') && colonCount !== titleColons)
+ ) {
+ const correctColonCount = line.includes(':TabTitle') ? wrapperColons : titleColons;
+ onError({
+ lineNumber: lineIndex + 1,
+ detail: `Actual: ${colonCount}; Expected: ${correctColonCount}`,
+ });
+ }
+ });
+ },
+};
diff --git a/doc/.markdownlint/rules/tabs_title_text.js b/doc/.markdownlint/rules/tabs_title_text.js
new file mode 100644
index 00000000000..672aa70f562
--- /dev/null
+++ b/doc/.markdownlint/rules/tabs_title_text.js
@@ -0,0 +1,23 @@
+const { globalPath } = require('../require_helper');
+const {
+ forEachLine,
+ getLineMetadata,
+ isBlankLine,
+} = require(`${globalPath}/markdownlint-rule-helpers`);
+
+module.exports = {
+ names: ['tabs-title-text'],
+ description: 'Tab without title text',
+ information: new URL('https://docs.gitlab.com/ee/development/documentation/styleguide/#tabs'),
+ tags: ['gitlab-docs', 'tabs'],
+ function: (params, onError) => {
+ forEachLine(getLineMetadata(params), (line, lineIndex) => {
+ if (!isBlankLine(line) && line.replace(':::TabTitle', '').trim() === '') {
+ onError({
+ lineNumber: lineIndex + 1,
+ detail: 'Expected: :::TabTitle <your title here>; Actual: :::TabTitle',
+ });
+ }
+ });
+ },
+};
diff --git a/doc/.markdownlint/rules/tabs_wrapper_tags.js b/doc/.markdownlint/rules/tabs_wrapper_tags.js
new file mode 100644
index 00000000000..beacec0b737
--- /dev/null
+++ b/doc/.markdownlint/rules/tabs_wrapper_tags.js
@@ -0,0 +1,21 @@
+module.exports = {
+ names: ['tabs-wrapper-tags'],
+ description: 'Unequal number of tab start and end tags',
+ information: new URL('https://docs.gitlab.com/ee/development/documentation/styleguide/#tabs'),
+ tags: ['gitlab-docs', 'tabs'],
+ function: function rule(params, onError) {
+ const tabStarts = params.lines.filter((line) => line === '::Tabs');
+ const tabEnds = params.lines.filter((line) => line === '::EndTabs');
+
+ if (tabStarts.length !== tabEnds.length) {
+ const errorIndex =
+ params.lines.indexOf('::Tabs') > 0
+ ? params.lines.indexOf('::Tabs')
+ : params.lines.indexOf('::EndTabs');
+ onError({
+ lineNumber: errorIndex + 1,
+ detail: `Opening tags: ${tabStarts.length}; Closing tags: ${tabEnds.length}`,
+ });
+ }
+ },
+};
diff --git a/doc/.vale/gitlab/Admin.yml b/doc/.vale/gitlab/Admin.yml
deleted file mode 100644
index 78a86e27456..00000000000
--- a/doc/.vale/gitlab/Admin.yml
+++ /dev/null
@@ -1,13 +0,0 @@
----
-# Suggestion: gitlab.Admin
-#
-# Checks for "admin" and recommends using the full word instead. "Admin Area" is OK.
-#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
-extends: substitution
-message: 'Verify this use of the word "admin". Can it be updated to "administration", "administrator", "administer", or "Admin Area"?'
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html
-level: suggestion
-ignorecase: false
-swap:
- '[Aa]dmin ?\w*': '(?:Admin( Area| Mode)?|[Aa]dminist(ration|rator|rators|er|rative|ering|ered))'
diff --git a/doc/.vale/gitlab/AlertBoxStyle.yml b/doc/.vale/gitlab/AlertBoxStyle.yml
index 5912c4707fd..0a4514fa3c8 100644
--- a/doc/.vale/gitlab/AlertBoxStyle.yml
+++ b/doc/.vale/gitlab/AlertBoxStyle.yml
@@ -3,13 +3,13 @@
#
# Makes sure alert boxes are used with block quotes. Checks for 3 formatting issues:
#
-# - Alert boxes inside a block quote (">")
+# - Alert boxes inside a block quote ('>')
# - Alert boxes with the note text on the same line
-# - Alert boxes using words other than "NOTE" or "WARNING"
+# - Alert boxes using words other than 'NOTE' or 'WARNING'
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Alert box "%s" must use the formatting in the style guide.'
+message: "Update the format of the '%s' alert box. View the style guide for details."
link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#alert-boxes
level: error
nonword: true
diff --git a/doc/.vale/gitlab/BadPlurals.yml b/doc/.vale/gitlab/BadPlurals.yml
index 533805c67b0..9cdb8661708 100644
--- a/doc/.vale/gitlab/BadPlurals.yml
+++ b/doc/.vale/gitlab/BadPlurals.yml
@@ -1,11 +1,11 @@
---
# Warning: gitlab.BadPlurals
#
-# Don't write plural words with the '(s)' construction. "HTTP(S)" is acceptable.
+# Don't write plural words with the '(s)' construction. 'HTTP(S)' is acceptable.
#
-# For a list of all options, see https://docs.errata.ai/vale/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Rewrite "%s" to be plural, without parentheses.'
+message: "Rewrite '%s' to be plural without parentheses."
link: https://docs.gitlab.com/ee/development/documentation/styleguide/word_list.html#s
level: warning
ignorecase: true
diff --git a/doc/.vale/gitlab/BadgeCapitalization.yml b/doc/.vale/gitlab/BadgeCapitalization.yml
index 33425693d53..6e77c3fe822 100644
--- a/doc/.vale/gitlab/BadgeCapitalization.yml
+++ b/doc/.vale/gitlab/BadgeCapitalization.yml
@@ -3,9 +3,9 @@
#
# Verifies that badges are not mixed case, which won't render properly.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Badge "%s" must be capitalized.'
+message: "Capitalize the '%s' badge."
link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#product-tier-badges
level: error
scope: raw
diff --git a/doc/.vale/gitlab/British.yml b/doc/.vale/gitlab/British.yml
index c63cbd917c7..432ed302e11 100644
--- a/doc/.vale/gitlab/British.yml
+++ b/doc/.vale/gitlab/British.yml
@@ -3,9 +3,9 @@
#
# Checks that US spelling is used instead of British spelling.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: substitution
-message: 'Use the US spelling "%s" instead of the British "%s".'
+message: "Use the US spelling '%s' instead of the British '%s'."
link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#language
level: error
ignorecase: true
diff --git a/doc/.vale/gitlab/CIConfigFile.yml b/doc/.vale/gitlab/CIConfigFile.yml
index 5a65e51ea16..4d2ba454410 100644
--- a/doc/.vale/gitlab/CIConfigFile.yml
+++ b/doc/.vale/gitlab/CIConfigFile.yml
@@ -3,9 +3,9 @@
#
# Checks that the `.gitlab-ci.yml` file is referenced properly.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'The CI/CD configuration file should be exactly: `.gitlab-ci.yml`'
+message: "Change the file name to be exactly '.gitlab-ci.yml'."
link: https://docs.gitlab.com/ee/development/documentation/versions.html
level: error
scope: raw
diff --git a/doc/.vale/gitlab/CodeblockFences.yml b/doc/.vale/gitlab/CodeblockFences.yml
index 6c2d94e7b8d..9d5efe7f60a 100644
--- a/doc/.vale/gitlab/CodeblockFences.yml
+++ b/doc/.vale/gitlab/CodeblockFences.yml
@@ -3,9 +3,9 @@
#
# Ensures all codeblock language tags use the full name, not aliases.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Syntax highlighting hint "%s" must be one of: 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, golang, python, dockerfile, or typescript."
link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#code-blocks
level: error
scope: raw
diff --git a/doc/.vale/gitlab/CurlStringsQuoted.yml b/doc/.vale/gitlab/CurlStringsQuoted.yml
index a59fe64d990..efe7aa23832 100644
--- a/doc/.vale/gitlab/CurlStringsQuoted.yml
+++ b/doc/.vale/gitlab/CurlStringsQuoted.yml
@@ -3,9 +3,9 @@
#
# Ensures all code blocks using `curl` wrap URL strings in quotation marks.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'For consistency across all cURL examples, always wrap the URL in double quotes ("): %s'
+message: "For the cURL example, use double quotes around the URL: %s"
link: https://docs.gitlab.com/ee/development/documentation/restful_api_styleguide.html#curl-commands
level: error
scope: code
diff --git a/doc/.vale/gitlab/CurrentStatus.yml b/doc/.vale/gitlab/CurrentStatus.yml
index 040fd3d8a8f..57b95dcf4ac 100644
--- a/doc/.vale/gitlab/CurrentStatus.yml
+++ b/doc/.vale/gitlab/CurrentStatus.yml
@@ -3,12 +3,12 @@
#
# Checks for words that indicate a product or feature may change in the future.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Avoid words like "%s" when you write about future features. Our documentation is about the current state of the product.'
+message: "Remove '%s'. The documentation reflects the current state of the product."
level: suggestion
ignorecase: true
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/#promising-features-in-future-versions
+link: https://docs.gitlab.com/ee/development/documentation/versions.html#promising-features-in-future-versions
tokens:
- currently
- yet
diff --git a/doc/.vale/gitlab/DefaultBranch.yml b/doc/.vale/gitlab/DefaultBranch.yml
index 4bc68433c6d..86c627bcfe3 100644
--- a/doc/.vale/gitlab/DefaultBranch.yml
+++ b/doc/.vale/gitlab/DefaultBranch.yml
@@ -1,14 +1,14 @@
---
# Warning: gitlab.DefaultBranch
#
-# Do not refer to the default branch as the "master" branch, if possible.
+# Do not refer to the default branch as the 'master' branch, if possible.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Use "default branch" or `main` instead of `master`, when possible.'
+message: "Use 'default branch' or `main` instead of `master`, when possible."
level: warning
ignorecase: true
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/word_list.html#default-branch
scope: raw
raw:
- '\`master\`'
diff --git a/doc/.vale/gitlab/Dropdown.yml b/doc/.vale/gitlab/Dropdown.yml
index 691d44d1a48..c656d1209f5 100644
--- a/doc/.vale/gitlab/Dropdown.yml
+++ b/doc/.vale/gitlab/Dropdown.yml
@@ -3,11 +3,11 @@
#
# Catches many ways the phrase 'dropdown list' can be fumbled.
#
-# For a list of all options, see https://errata-ai.github.io/vale/styles/
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Use "dropdown list".'
+message: "Use 'dropdown list'."
link: https://docs.gitlab.com/ee/development/documentation/styleguide/word_list.html#dropdown-list
-level: suggestion
+level: warning
ignorecase: true
tokens:
- drop-down( [\w]*)?
diff --git a/doc/.vale/gitlab/EOLWhitespace.yml b/doc/.vale/gitlab/EOLWhitespace.yml
index e160b706014..153786443cc 100644
--- a/doc/.vale/gitlab/EOLWhitespace.yml
+++ b/doc/.vale/gitlab/EOLWhitespace.yml
@@ -3,9 +3,9 @@
#
# Checks that there is no useless whitespace at the end of lines.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Lines should not end with whitespace characters.'
+message: "Remove whitespace characters from the end of the line."
link: https://docs.gitlab.com/ee/development/documentation/versions.html
level: warning
scope: raw
diff --git a/doc/.vale/gitlab/ElementDescriptors.yml b/doc/.vale/gitlab/ElementDescriptors.yml
index 36f1202aef1..f3573f5ce65 100644
--- a/doc/.vale/gitlab/ElementDescriptors.yml
+++ b/doc/.vale/gitlab/ElementDescriptors.yml
@@ -3,9 +3,9 @@
#
# Suggests the correct way to describe elements in a form.
#
-# For a list of all options, see https://errata-ai.github.io/vale/styles/
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: substitution
-message: 'When describing elements, %s "%s".'
+message: "When describing elements, %s '%s'."
link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#language
level: suggestion
ignorecase: true
diff --git a/doc/.vale/gitlab/FirstPerson.yml b/doc/.vale/gitlab/FirstPerson.yml
index 6fc93d9515c..e97b886b5ed 100644
--- a/doc/.vale/gitlab/FirstPerson.yml
+++ b/doc/.vale/gitlab/FirstPerson.yml
@@ -3,12 +3,12 @@
#
# Checks for use of first person pronouns.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: '"%s" is a first-person pronoun. Use second- or third-person pronouns (like we, you, us, one) instead.'
+message: "Instead of '%s', speak directly to the reader. Use 'you' or re-write to remove."
level: warning
ignorecase: true
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#usage-list
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html
tokens:
- '\bI[ ,;:?!"]|\bI\x27.{1,2}'
- me
diff --git a/doc/.vale/gitlab/FutureTense.yml b/doc/.vale/gitlab/FutureTense.yml
index 64e79612fff..d1484b20008 100644
--- a/doc/.vale/gitlab/FutureTense.yml
+++ b/doc/.vale/gitlab/FutureTense.yml
@@ -3,12 +3,12 @@
#
# Checks for use of future tense in sentences. Present tense is strongly preferred.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Avoid using future tense: "%s". Use present tense instead.'
+message: "Instead of future tense '%s', use present tense."
ignorecase: true
level: warning
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#usage-list
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/word_list.html#future-tense
raw:
- "(going to( |\n|[[:punct:]])[a-zA-Z]*|"
- "will( |\n|[[:punct:]])[a-zA-Z]*|"
diff --git a/doc/.vale/gitlab/HeadingContent.yml b/doc/.vale/gitlab/HeadingContent.yml
index c2dd2a5c6c2..31ac3022934 100644
--- a/doc/.vale/gitlab/HeadingContent.yml
+++ b/doc/.vale/gitlab/HeadingContent.yml
@@ -3,12 +3,12 @@
#
# Checks for generic, unhelpful subheadings.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Rename the subheading "%s", or re-purpose the content elsewhere.'
+message: "Rename the heading '%s', or re-purpose the content elsewhere."
level: warning
scope: heading
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/#headings-1
+link: https://docs.gitlab.com/ee/development/documentation/topic_types/concept.html#concept-headings
ignorecase: false
tokens:
- How it works
diff --git a/doc/.vale/gitlab/HeadingDepth.yml b/doc/.vale/gitlab/HeadingDepth.yml
index 466ab317226..7a3e5b4b552 100644
--- a/doc/.vale/gitlab/HeadingDepth.yml
+++ b/doc/.vale/gitlab/HeadingDepth.yml
@@ -5,7 +5,7 @@
#
# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'The subheading "%s" is nested too deeply. Headings deeper than H5 suggest the section or page should be refactored.'
+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
level: warning
scope: raw
diff --git a/doc/.vale/gitlab/InclusionAbleism.yml b/doc/.vale/gitlab/InclusionAbleism.yml
index 1ebb6a97cf8..7419430c8a2 100644
--- a/doc/.vale/gitlab/InclusionAbleism.yml
+++ b/doc/.vale/gitlab/InclusionAbleism.yml
@@ -3,10 +3,10 @@
#
# Suggests alternatives for words that foster ableism.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: substitution
-message: 'Use inclusive language. Consider "%s" instead of "%s".'
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#inclusive-language
+message: "Use inclusive language. Consider '%s' instead of '%s'."
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/word_list.html
level: suggestion
ignorecase: true
swap:
diff --git a/doc/.vale/gitlab/InclusionCultural.yml b/doc/.vale/gitlab/InclusionCultural.yml
index 6f63d1725fc..6de838e7f25 100644
--- a/doc/.vale/gitlab/InclusionCultural.yml
+++ b/doc/.vale/gitlab/InclusionCultural.yml
@@ -3,10 +3,10 @@
#
# Suggests alternatives for words that are culturally inappropriate.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: substitution
-message: 'Use inclusive language. Consider "%s" instead of "%s".'
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#inclusive-language
+message: "Use inclusive language. Consider '%s' instead of '%s'."
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/word_list.html
level: warning
ignorecase: true
swap:
diff --git a/doc/.vale/gitlab/InclusionGender.yml b/doc/.vale/gitlab/InclusionGender.yml
index 313a1cc42dc..ce8861b6a09 100644
--- a/doc/.vale/gitlab/InclusionGender.yml
+++ b/doc/.vale/gitlab/InclusionGender.yml
@@ -3,10 +3,10 @@
#
# Suggests alternatives for words that are gender-specific.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: substitution
-message: 'Use inclusive language. Consider "%s" instead of "%s".'
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#inclusive-language
+message: "Use inclusive language. Consider '%s' instead of '%s'."
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/word_list.html
level: suggestion
ignorecase: true
swap:
diff --git a/doc/.vale/gitlab/InternalLinkCase.yml b/doc/.vale/gitlab/InternalLinkCase.yml
index c00e633426b..fded735812a 100644
--- a/doc/.vale/gitlab/InternalLinkCase.yml
+++ b/doc/.vale/gitlab/InternalLinkCase.yml
@@ -3,10 +3,10 @@
#
# Checks that anchor fragments on internal links are in lower-case.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Links to subheadings in GitLab docs must be in lower-case: "%s"'
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#links-to-internal-documentation
+message: "Use lowercase for the anchor link."
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#anchor-links
level: error
scope: raw
raw:
diff --git a/doc/.vale/gitlab/InternalLinkExtension.yml b/doc/.vale/gitlab/InternalLinkExtension.yml
index 52142b50dfc..364263f90c8 100644
--- a/doc/.vale/gitlab/InternalLinkExtension.yml
+++ b/doc/.vale/gitlab/InternalLinkExtension.yml
@@ -3,10 +3,10 @@
#
# Checks that internal links have .md extenstion and not .html extension.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Link "%s" must link directly to a file and use the .md file extension.'
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#links-to-internal-documentation
+message: "Link to a file and use the .md file extension instead of .html."
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#links
level: error
scope: raw
raw:
diff --git a/doc/.vale/gitlab/InternalLinkFormat.yml b/doc/.vale/gitlab/InternalLinkFormat.yml
index b9ee83b7f5c..be09a020846 100644
--- a/doc/.vale/gitlab/InternalLinkFormat.yml
+++ b/doc/.vale/gitlab/InternalLinkFormat.yml
@@ -1,13 +1,13 @@
---
# Error: gitlab.InternalLinkFormat
#
-# Checks that internal link paths don't start with "./", which is not needed.
+# Checks that internal link paths don't start with './', which is not needed.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Link "%s" must not start with "./".'
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#links-to-internal-documentation
+message: "Edit the link so it does not start with './'."
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#links
level: error
scope: raw
raw:
- - '\[.+\]\(\.\/.*?\)'
+ - '\[[^\]]+\]\(\.\/.*?\)'
diff --git a/doc/.vale/gitlab/LatinTerms.yml b/doc/.vale/gitlab/LatinTerms.yml
index 12553a801a1..0bac0448bb1 100644
--- a/doc/.vale/gitlab/LatinTerms.yml
+++ b/doc/.vale/gitlab/LatinTerms.yml
@@ -3,10 +3,10 @@
#
# Checks for use of Latin terms.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: substitution
-message: 'Use "%s" instead of "%s", but consider rewriting the sentence.'
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#usage-list
+message: "Use '%s' instead of '%s', but consider rewriting the sentence."
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/word_list.html
level: warning
nonword: true
ignorecase: true
diff --git a/doc/.vale/gitlab/Markdown_emoji.yml b/doc/.vale/gitlab/Markdown_emoji.yml
index ac0dab2d69d..9873fb8becd 100644
--- a/doc/.vale/gitlab/Markdown_emoji.yml
+++ b/doc/.vale/gitlab/Markdown_emoji.yml
@@ -3,9 +3,9 @@
#
# Check for use of GLFM emoji syntax (https://docs.gitlab.com/ee/user/markdown.html#emojis), which doesn't render correctly in documentation.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'This appears to be GLFM emoji syntax. Replace "%s" with GitLab SVGs or Unicode emojis.'
+message: "Replace '%s' with GitLab SVGs or Unicode emojis."
link: https://docs.gitlab.com/ee/development/documentation/styleguide/#gitlab-svg-icons
level: warning
scope: text
diff --git a/doc/.vale/gitlab/MeaningfulLinkWords.yml b/doc/.vale/gitlab/MeaningfulLinkWords.yml
index 4a255e5aae4..6fb41c7ce95 100644
--- a/doc/.vale/gitlab/MeaningfulLinkWords.yml
+++ b/doc/.vale/gitlab/MeaningfulLinkWords.yml
@@ -3,13 +3,13 @@
#
# Checks for the presence of semantically unhelpful words in link text.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Improve SEO and accessibility by rewriting "%s" in the link text.'
+message: "Improve SEO and accessibility by rewriting '%s' in the link text."
level: warning
scope: link
ignorecase: true
-link: https://about.gitlab.com/handbook/communication/#writing-style-guidelines
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#text-for-links
tokens:
- here
- this page
diff --git a/doc/.vale/gitlab/MergeConflictMarkers.yml b/doc/.vale/gitlab/MergeConflictMarkers.yml
index 4f216ac34c5..54e044f195d 100644
--- a/doc/.vale/gitlab/MergeConflictMarkers.yml
+++ b/doc/.vale/gitlab/MergeConflictMarkers.yml
@@ -3,9 +3,9 @@
#
# Checks for the presence of merge conflict markers.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Merge conflict marker "%s" found.'
+message: "Remove the merge conflict marker '%s'."
link: https://docs.gitlab.com/ee/development/code_review.html#merging-a-merge-request
level: error
scope: raw
diff --git a/doc/.vale/gitlab/MultiLineLinks.yml b/doc/.vale/gitlab/MultiLineLinks.yml
index 64ad017f16c..32fe38277dc 100644
--- a/doc/.vale/gitlab/MultiLineLinks.yml
+++ b/doc/.vale/gitlab/MultiLineLinks.yml
@@ -3,10 +3,10 @@
#
# Checks that links are all on a single line.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Link "%s" must be on a single line, even if very long.'
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#basic-link-criteria
+message: "Put the full link on one line, even if the link is very long."
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#links
level: error
scope: raw
raw:
diff --git a/doc/.vale/gitlab/NonStandardQuotes.yml b/doc/.vale/gitlab/NonStandardQuotes.yml
index f31d615eb19..6161a4cc000 100644
--- a/doc/.vale/gitlab/NonStandardQuotes.yml
+++ b/doc/.vale/gitlab/NonStandardQuotes.yml
@@ -3,12 +3,12 @@
#
# Use only standard single and double quotes, not left or right quotes.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Use standard single quotes or double quotes only. Do not use left or right quotes.'
+message: "Use standard single quotes or double quotes only. Do not use left or right quotes."
level: warning
ignorecase: true
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#punctuation
scope: raw
raw:
- '[‘’“â€]'
diff --git a/doc/.vale/gitlab/OutdatedVersions.yml b/doc/.vale/gitlab/OutdatedVersions.yml
index f25de44ad17..10fbaa0a676 100644
--- a/doc/.vale/gitlab/OutdatedVersions.yml
+++ b/doc/.vale/gitlab/OutdatedVersions.yml
@@ -3,10 +3,10 @@
#
# Checks for references to versions of GitLab that are no longer supported.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Can this reference to "%s" be refactored?'
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#gitlab-versions
+message: "If possible, remove the reference to '%s'."
+link: https://docs.gitlab.com/ee/development/documentation/versions.html
level: suggestion
nonword: true
ignorecase: true
diff --git a/doc/.vale/gitlab/OxfordComma.yml b/doc/.vale/gitlab/OxfordComma.yml
index 1716145b26a..81a9ae5c1fc 100644
--- a/doc/.vale/gitlab/OxfordComma.yml
+++ b/doc/.vale/gitlab/OxfordComma.yml
@@ -3,9 +3,9 @@
#
# Checks for the lack of an Oxford comma. In some cases, will catch overly complex sentence structures with lots of commas.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Use a comma before the last "and" or "or" in a list of four or more items.'
+message: "Use a comma before the last 'and' or 'or' in a list of four or more items."
link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#punctuation
level: warning
raw:
diff --git a/doc/.vale/gitlab/Possessive.yml b/doc/.vale/gitlab/Possessive.yml
index 92ae66543a2..64c9481ac28 100644
--- a/doc/.vale/gitlab/Possessive.yml
+++ b/doc/.vale/gitlab/Possessive.yml
@@ -3,11 +3,11 @@
#
# The word GitLab should not be used in the possessive form.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: "Rewrite '%s' to not use 's."
+message: "Remove 's from %s."
level: error
ignorecase: true
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#trademark
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/word_list.html#gitlab
tokens:
- GitLab's
diff --git a/doc/.vale/gitlab/ReadingLevel.yml b/doc/.vale/gitlab/ReadingLevel.yml
index cd7597ee8dc..a1ddebec1ea 100644
--- a/doc/.vale/gitlab/ReadingLevel.yml
+++ b/doc/.vale/gitlab/ReadingLevel.yml
@@ -4,8 +4,10 @@
# Checks the Flesch-Kincaid reading level.
#
# https://docs.errata.ai/vale/styles#metric
+#
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: metric
-message: "The grade level - %s - refers to how hard the content is to understand. Aim for 8th grade or lower by using shorter sentences and words."
+message: "The grade level is %s. Aim for 8th grade or lower by using shorter sentences and words."
link: https://docs.gitlab.com/ee/development/documentation/testing.html#vale-readability-score
level: suggestion
formula: |
diff --git a/doc/.vale/gitlab/ReferenceLinks.yml b/doc/.vale/gitlab/ReferenceLinks.yml
index ca9948844f8..d9f20fa1bd6 100644
--- a/doc/.vale/gitlab/ReferenceLinks.yml
+++ b/doc/.vale/gitlab/ReferenceLinks.yml
@@ -3,10 +3,10 @@
#
# Checks for reference-style links that should be converted to inline links.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Link "%s" must be inline.'
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#basic-link-criteria
+message: "Put this link inline with the rest of the text."
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#links
level: error
scope: raw
raw:
diff --git a/doc/.vale/gitlab/RelativeLinks.yml b/doc/.vale/gitlab/RelativeLinks.yml
index 14ffc4bd0b8..6d46e432e08 100644
--- a/doc/.vale/gitlab/RelativeLinks.yml
+++ b/doc/.vale/gitlab/RelativeLinks.yml
@@ -3,11 +3,11 @@
#
# Checks for the presence of absolute hyperlinks that should be relative.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Link "%s" must be a relative link with a .md extension.'
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#links-to-internal-documentation
+message: "Use a relative link instead of a URL, and ensure the file name ends in .md and not .html."
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#links
level: error
scope: raw
raw:
- - '\[.+\]\(https?:\/\/docs\.gitlab\.com\/[ce]e.*\)'
+ - '\[[^\]]+\]\(https?:\/\/docs\.gitlab\.com\/[ce]e.*?\)'
diff --git a/doc/.vale/gitlab/RelativeLinksDoubleSlashes.yml b/doc/.vale/gitlab/RelativeLinksDoubleSlashes.yml
index ce6ce8b5691..6a94c7f927a 100644
--- a/doc/.vale/gitlab/RelativeLinksDoubleSlashes.yml
+++ b/doc/.vale/gitlab/RelativeLinksDoubleSlashes.yml
@@ -3,10 +3,10 @@
#
# Checks for the presence of double slashes in relative URLs.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Relative links must not include a double slash.'
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#links-to-internal-documentation
+message: "Remove the double slash from this relative link."
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#links
level: error
scope: raw
raw:
diff --git a/doc/.vale/gitlab/Repetition.yml b/doc/.vale/gitlab/Repetition.yml
index c4b0cc14192..cdeb29e7d45 100644
--- a/doc/.vale/gitlab/Repetition.yml
+++ b/doc/.vale/gitlab/Repetition.yml
@@ -3,9 +3,9 @@
#
# Checks for duplicate words, like `the the` or `and and`.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: repetition
-message: '"%s" is repeated.'
+message: "Remove this duplicate word: '%s'."
level: error
alpha: true
tokens:
diff --git a/doc/.vale/gitlab/SentenceLength.yml b/doc/.vale/gitlab/SentenceLength.yml
index c60df1803e2..69b0d27072e 100644
--- a/doc/.vale/gitlab/SentenceLength.yml
+++ b/doc/.vale/gitlab/SentenceLength.yml
@@ -3,9 +3,9 @@
#
# Counts words in a sentence and alerts if a sentence exceeds 25 words.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: occurrence
-message: 'Shorter sentences improve readability (max 25 words).'
+message: "Improve readability by using fewer than 25 words in this sentence."
scope: sentence
link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#language
level: warning
diff --git a/doc/.vale/gitlab/SentenceSpacing.yml b/doc/.vale/gitlab/SentenceSpacing.yml
index 0288abe834f..9ca685b00b8 100644
--- a/doc/.vale/gitlab/SentenceSpacing.yml
+++ b/doc/.vale/gitlab/SentenceSpacing.yml
@@ -3,9 +3,9 @@
#
# Checks for incorrect spacing (no spaces, or more than one space) around punctuation.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: '"%s" must contain one and only one space.'
+message: "Remove the extra space: '%s'"
link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#punctuation
level: error
nonword: true
diff --git a/doc/.vale/gitlab/Simplicity.yml b/doc/.vale/gitlab/Simplicity.yml
index 44e78f89c20..89169c1aa46 100644
--- a/doc/.vale/gitlab/Simplicity.yml
+++ b/doc/.vale/gitlab/Simplicity.yml
@@ -3,12 +3,12 @@
#
# Checks for words implying ease of use, to avoid cognitive dissonance for frustrated users.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Avoid words like "%s" that imply ease of use, because the user may find this action hard.'
+message: "Remove '%s'. Be precise instead of subjective."
level: suggestion
ignorecase: true
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#usage-list
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/word_list.html
tokens:
- easy
- easily
diff --git a/doc/.vale/gitlab/Spelling.yml b/doc/.vale/gitlab/Spelling.yml
index 4ebaf7bfb70..92c5cb13b29 100644
--- a/doc/.vale/gitlab/Spelling.yml
+++ b/doc/.vale/gitlab/Spelling.yml
@@ -8,9 +8,9 @@
# Commands, like `git clone` must use backticks, and must not be added to the
# exceptions.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: spelling
-message: 'Spelling check: "%s"?'
+message: "Check the spelling of '%s'. If the spelling is correct, add this word to the spelling exception list."
level: warning
ignore:
- gitlab/spelling-exceptions.txt
diff --git a/doc/.vale/gitlab/SubstitutionSuggestions.yml b/doc/.vale/gitlab/SubstitutionSuggestions.yml
index 4b77def065d..21cabf1e0a7 100644
--- a/doc/.vale/gitlab/SubstitutionSuggestions.yml
+++ b/doc/.vale/gitlab/SubstitutionSuggestions.yml
@@ -4,25 +4,26 @@
# Suggests better options for frequently misused terms that are often - but not always - incorrect.
# SubstitutionWarning.yml and Substitutions.yml also exist.
#
-# For a list of all options, see https://errata-ai.github.io/vale/styles/
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: substitution
-message: 'Consider %s instead of "%s".'
+message: "Consider '%s' instead of '%s'."
link: https://docs.gitlab.com/ee/development/documentation/styleguide/word_list.html
level: suggestion
ignorecase: true
swap:
- active user: '"billable user"'
- active users: '"billable users"'
- docs: '"documentation"'
- e-mail: '"email"'
- GLFM: '"GitLab Flavored Markdown"'
- it is recommended: '"we recommend"'
+ active user: "billable user"
+ active users: "billable users"
+ docs: "documentation"
+ e-mail: "email"
+ GLFM: "GitLab Flavored Markdown"
+ it is recommended: "you should"
+ we recommend: "you should"
navigate: go
- OAuth2: '"OAuth 2.0"'
- once that: '"after that"'
- once the: '"after the"'
- once you: '"after you"'
- since: '"because" or "after"'
- sub-group: '"subgroup"'
- sub-groups: '"subgroups"'
- within: '"in"'
+ OAuth2: "OAuth 2.0"
+ once that: "after that"
+ once the: "after the"
+ once you: "after you"
+ since: "because' or 'after"
+ sub-group: "subgroup"
+ sub-groups: "subgroups"
+ within: "in"
diff --git a/doc/.vale/gitlab/SubstitutionWarning.yml b/doc/.vale/gitlab/SubstitutionWarning.yml
index d17015b97fd..8d6c18c1520 100644
--- a/doc/.vale/gitlab/SubstitutionWarning.yml
+++ b/doc/.vale/gitlab/SubstitutionWarning.yml
@@ -4,26 +4,26 @@
# Checks for misused terms or common shorthand that should never be used at GitLab, but can't be flagged as errors.
# Substitutions.yml and SubstitionSuggestions.yml also exist.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: substitution
-message: 'If possible, use "%s" instead of "%s".'
+message: "If possible, use %s instead of '%s'."
link: https://about.gitlab.com/handbook/communication/#top-misused-terms
level: warning
ignorecase: true
swap:
- air(?:-| )?gapped: offline environment
- bullet: list item
- click: select
- code base: codebase
- config: configuration
- deselect: clear
- deselected: cleared
- distro: distribution
- file name: filename
- filesystem: file system
- GFM: GLFM
- info: information
- n/a: not applicable
- repo: repository
- timezone: time zone
- utilize: use
+ air(?:-| )?gapped: "offline environment"
+ bullet: "list item"
+ click: "select"
+ code base: "codebase"
+ config: "configuration"
+ deselect: "clear"
+ deselected: "cleared"
+ distro: "distribution"
+ file name: "filename"
+ filesystem: "file system"
+ GFM: "'GitLab Flavored Markdown' or 'GitHub Flavored Markdown'"
+ info: "information"
+ n/a: "not applicable"
+ repo: "repository"
+ timezone: "time zone"
+ utilize: "use"
diff --git a/doc/.vale/gitlab/Substitutions.yml b/doc/.vale/gitlab/Substitutions.yml
index af426fa7e06..92791486491 100644
--- a/doc/.vale/gitlab/Substitutions.yml
+++ b/doc/.vale/gitlab/Substitutions.yml
@@ -4,9 +4,9 @@
# Checks for misused terms that should never be used at GitLab.
# SubstitutionWarning.yml and SubstitionSuggestions.yml also exist.
#
-# For a list of all options, see https://docs.errata.ai/vale/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: substitution
-message: 'Use "%s" instead of "%s".'
+message: "Use '%s' instead of '%s'."
link: https://about.gitlab.com/handbook/communication/#top-misused-terms
level: error
ignorecase: true
diff --git a/doc/.vale/gitlab/ToDo.yml b/doc/.vale/gitlab/ToDo.yml
index a3725cb7f6b..079f13baa28 100644
--- a/doc/.vale/gitlab/ToDo.yml
+++ b/doc/.vale/gitlab/ToDo.yml
@@ -3,10 +3,10 @@
#
# You should not use "To Do", unless it refers to the UI element.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: substitution
-message: 'Use "to-do item" in most cases, or "Add a to do" if referring to the UI button.'
-link: https://docs.gitlab.com/ee/development/documentation/styleguide/index.html#feature-names
+message: "Use 'to-do item' in most cases, or 'Add a to do' if referring to the UI button."
+link: https://docs.gitlab.com/ee/development/documentation/styleguide/word_list.html#to-do-item
level: warning
ignorecase: false
swap:
diff --git a/doc/.vale/gitlab/UnclearAntecedent.yml b/doc/.vale/gitlab/UnclearAntecedent.yml
index 5f238598d9f..e5d43b6ab7d 100644
--- a/doc/.vale/gitlab/UnclearAntecedent.yml
+++ b/doc/.vale/gitlab/UnclearAntecedent.yml
@@ -3,9 +3,9 @@
#
# Checks for words that need a noun for clarity.
#
-# For a list of all options, see https://docs.errata.ai/vale/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: "'%s' is not precise. Try rewriting with a specific subject and verb."
+message: "Instead of '%s', try starting this sentence with a specific subject and verb."
link: https://docs.gitlab.com/ee/development/documentation/styleguide/word_list.html#this-these-that-those
level: warning
ignorecase: false
diff --git a/doc/.vale/gitlab/Units.yml b/doc/.vale/gitlab/Units.yml
new file mode 100644
index 00000000000..4211fdee38b
--- /dev/null
+++ b/doc/.vale/gitlab/Units.yml
@@ -0,0 +1,15 @@
+---
+# Suggestion: gitlab.Units
+#
+# Recommends a space between a number and a unit of measure.
+#
+# For a list of all options, see https://vale.sh/docs/topics/styles/
+extends: existence
+message: "Add a space between the number and the unit in '%s'."
+link: 'https://docs.gitlab.com/ee/development/documentation/styleguide/'
+nonword: true
+level: suggestion
+ignorecase: true
+tokens:
+ - \d+(?:B|kB|KiB|MB|MiB|GB|GiB|TB|TiB)
+ - \d+(?:ns|ms|μs|s|min|h|d)
diff --git a/doc/.vale/gitlab/Uppercase.yml b/doc/.vale/gitlab/Uppercase.yml
index dc05aa05730..f53e1c72dcb 100644
--- a/doc/.vale/gitlab/Uppercase.yml
+++ b/doc/.vale/gitlab/Uppercase.yml
@@ -3,9 +3,9 @@
#
# Checks for use of all uppercase letters with unknown reason.
#
-# For a list of all options, see https://docs.errata.ai/vale/styles.
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: conditional
-message: "'%s' is uppercase. Use lowercase or `backticks` if possible. Otherwise add this word to the rule's exception list."
+message: "Instead of uppercase for '%s', use lowercase or backticks (`) if possible. Otherwise, add this word or acronym to the rule's exception list."
link: https://docs.gitlab.com/ee/development/documentation/testing.html#vale-uppercase-acronym-test
level: warning
ignorecase: false
@@ -25,6 +25,7 @@ exceptions:
- ARN
- ASCII
- ASG
+ - AST
- AWS
- BMP
- BSD
@@ -144,6 +145,7 @@ exceptions:
- NOTE
- NPM
- NTP
+ - OCI
- OKD
- ONLY
- OSS
diff --git a/doc/.vale/gitlab/VersionText.yml b/doc/.vale/gitlab/VersionText.yml
index 571fba52ab7..4fd80bc3f4e 100644
--- a/doc/.vale/gitlab/VersionText.yml
+++ b/doc/.vale/gitlab/VersionText.yml
@@ -9,9 +9,9 @@
# - `> Introduced in GitLab 14.0.
# - `> Removed in GitLab 15.0.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'This introduced-in section is not formatted correctly. Each entry must start with `> -` and long entries must be on one line.'
+message: "Start each entry with `> -`. Keep long entries on one line."
link: https://docs.gitlab.com/ee/development/documentation/versions.html
level: error
scope: raw
diff --git a/doc/.vale/gitlab/VersionTextSingleLine.yml b/doc/.vale/gitlab/VersionTextSingleLine.yml
index f76574bcf8a..552ccb9951e 100644
--- a/doc/.vale/gitlab/VersionTextSingleLine.yml
+++ b/doc/.vale/gitlab/VersionTextSingleLine.yml
@@ -3,9 +3,9 @@
#
# Verifies that single-item version notes don't have a hyphen.
#
-# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: existence
-message: 'Version text with only a single item must not start with a hyphen.'
+message: "Do not use a hyphen '-' in version text if there is only a single item."
link: https://docs.gitlab.com/ee/development/documentation/versions.html#add-a-version-history-item
level: error
scope: raw
diff --git a/doc/.vale/gitlab/Wordy.yml b/doc/.vale/gitlab/Wordy.yml
index 7888d16dadb..45546435ee9 100644
--- a/doc/.vale/gitlab/Wordy.yml
+++ b/doc/.vale/gitlab/Wordy.yml
@@ -3,15 +3,15 @@
#
# Suggests shorter versions of wordy phrases.
#
-# For a list of all options, see https://docs.errata.ai/vale/styles
+# For a list of all options, see https://vale.sh/docs/topics/styles/
extends: substitution
-message: '%s "%s".'
+message: "%s"
link: https://docs.gitlab.com/ee/development/documentation/styleguide/word_list.html
level: suggestion
ignorecase: true
swap:
- in order to: "Be concise: use 'to' rather than"
- needs? to: "Rewrite the sentence, or use 'must', instead of"
- note that: "Be concise: rewrite the sentence to not use"
- please: "Remove this word from the sentence: "
- respectively: "Rewrite the sentence to be more precise, instead of using "
+ note that: "Remove the phrase 'note that'."
+ please: "Use 'please' only if we've inconvenienced the user."
+ respectively: "Remove 'respectively' and list each option instead."
+ and so on: "Remove 'and so on'. Try to use 'like' and provide examples instead."
+ in order to: "Remove 'in order' and leave 'to'."
diff --git a/doc/.vale/gitlab/spelling-exceptions.txt b/doc/.vale/gitlab/spelling-exceptions.txt
index 5d268fdb241..0fc7c9703ac 100644
--- a/doc/.vale/gitlab/spelling-exceptions.txt
+++ b/doc/.vale/gitlab/spelling-exceptions.txt
@@ -546,6 +546,7 @@ relicensing
remediations
renderers
replicables
+rpcs
repmgr
repmgrd
repurposing
@@ -570,6 +571,7 @@ roadmap
roadmaps
rollout
rollouts
+RSpec
rsync
rsynced
rsyncing
@@ -613,6 +615,7 @@ Silverlight
Sisense
Sitespeed
skippable
+skopeo
Slack
Slackbot
Slony
diff --git a/doc/.vale/vale-json.tmpl b/doc/.vale/vale-json.tmpl
index ed3c3259df3..7969cb704a0 100644
--- a/doc/.vale/vale-json.tmpl
+++ b/doc/.vale/vale-json.tmpl
@@ -1,47 +1,28 @@
{{- /* Modify Vale's output https://docs.errata.ai/vale/cli#--output */ -}}
-{{- /* Keep track of our various counts */ -}}
+{{- $fileIndexes := len .Files -}}
+{{- $fileIndexes = sub $fileIndexes 1 -}}
-{{- $e := 0 -}}
-{{- $w := 0 -}}
-{{- $s := 0 -}}
-{{- $f := 0 -}}
-
-{{- /* Range over the linted files */ -}}
-
-{{- range .Files}}
-
-{{- $f = add1 $f -}}
-{{- $path := .Path -}}
-
-{{- /* Range over the file's alerts */ -}}
[
-
-{{- range $idx, $a := .Alerts -}}
-
-{{- $error := "" -}}
-{{- if eq .Severity "error" -}}
- {{- $error = .Severity -}}
- {{- $e = add1 $e -}}
-{{- else if eq .Severity "warning" -}}
- {{- $error = .Severity -}}
- {{- $w = add1 $w -}}
-{{- else -}}
- {{- $error = .Severity -}}
- {{- $s = add1 $s -}}
-{{- end}}
-
-{{- /* Variables setup */ -}}
-
-{{- $path = $path -}}
-{{- $loc := printf "%d" .Line -}}
-{{- $check := printf "%s" .Check -}}
-{{- $message := printf "%s" .Message -}}
-{{- $link := printf "%s" .Link -}}
-{{- if $idx -}},{{- end -}}
-
-{{- /* Output */ -}}
-
+ {{- /* Range over the linted files */ -}}
+ {{- range $idx1, $a := .Files -}}
+ {{- $path := .Path -}}
+
+ {{/* Range over the file's alerts */}}
+ {{- range $idx2, $b := .Alerts -}}
+ {{- $error := "info" -}}
+ {{- if eq .Severity "error" -}}
+ {{- $error = "blocker" -}}
+ {{- else if eq .Severity "warning" -}}
+ {{- $error = "major" -}}
+ {{- end}}
+
+ {{- /* Variables setup */ -}}
+ {{- $loc := printf "%d" .Line -}}
+ {{- $message := printf "%s" .Message -}}
+ {{- if $idx2 -}},{{- end -}}
+
+ {{/* Output */}}
{
"description": "{{ $message }}",
"fingerprint": "{{ $path }}-{{ $loc }}",
@@ -53,6 +34,6 @@
}
}
}
-{{end -}}
-{{end -}}
+ {{- end}}{{- if (lt $idx1 $fileIndexes) -}},{{- end -}}
+ {{- end}}
]
diff --git a/doc/administration/audit_event_streaming.md b/doc/administration/audit_event_streaming.md
index ca60b6142fe..0af1af12a60 100644
--- a/doc/administration/audit_event_streaming.md
+++ b/doc/administration/audit_event_streaming.md
@@ -312,10 +312,7 @@ Streamed audit events have a predictable schema in the body of the response.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/357211) in GitLab 15.0.
> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/357211) in GitLab 15.1 by default.
> - [Added `details.author_class` field](https://gitlab.com/gitlab-org/gitlab/-/issues/363876) in GitLab 15.3.
-
-FLAG:
-On self-managed GitLab, by default this feature is available. To hide the
-feature, ask an administrator to [disable the feature flag](feature_flags.md) named `audit_event_streaming_git_operations`.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101583) in GitLab 15.6. Feature flag `audit_event_streaming_git_operations` removed.
Streaming audit events can be sent when signed-in users push, pull, or clone a project's remote Git repositories:
diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md
index 11600bc2da6..0aa0d163972 100644
--- a/doc/administration/audit_events.md
+++ b/doc/administration/audit_events.md
@@ -4,37 +4,22 @@ 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 Events **(PREMIUM)**
+# Audit events **(PREMIUM)**
-GitLab offers a way to view the changes made within the GitLab server for owners and administrators
-on a [paid plan](https://about.gitlab.com/pricing/).
+Use audit events to track important events, including who performed the related action and when.
+You can use audit events to track, for example:
-GitLab system administrators can also view all audit events by accessing the [`audit_json.log` file](logs/index.md#audit_jsonlog).
-The JSON audit log does not include events that are [only streamed](../development/audit_event_guide/index.md#event-streaming).
+- Who changed the permission level of a particular user for a GitLab project, and when.
+- Who added a new user or removed a user, and when.
-You can:
+The GitLab API, database, and `audit_json.log` record many audit events. Some audit events are only available through
+[streaming audit events](audit_event_streaming.md).
-- Generate an [audit report](audit_reports.md) of audit events.
-- [Stream audit events](audit_event_streaming.md) to an external endpoint.
+You can also generate an [audit report](audit_reports.md) of audit events.
-## Overview
-
-**Audit Events** is a tool for GitLab owners and administrators
-to track important events such as who performed certain actions and the
-time they happened. For example, these actions could be a change to a user
-permission level, who added a new user, or who removed a user.
-
-## Use cases
-
-- Check who changed the permission level of a particular
- user for a GitLab project.
-- Track which users have access to a certain group of projects
- in GitLab, and who gave them that permission level.
-
-## Retention policy
-
-There is no retention policy in place for audit events.
-See the [Specify a retention period for audit events](https://gitlab.com/groups/gitlab-org/-/epics/7917) for more information.
+NOTE:
+You can't configure a retention policy for audit events, but epic
+[7917](https://gitlab.com/groups/gitlab-org/-/epics/7917) proposes to change this.
## List of events
@@ -115,7 +100,7 @@ From there, you can see the following actions:
- Instance administrator started or stopped impersonation of a group member. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/300961) in GitLab 14.8.
- Group deploy token was successfully created, revoked, or deleted. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/353452) in GitLab 14.9.
- Failed attempt to create a group deploy token. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/353452) in GitLab 14.9.
-- [IP restrictions](../user/group/access_and_permissions.md#restrict-group-access-by-ip-address) changed. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/358986) in GitLab 15.0.
+- [IP restrictions](../user/group/access_and_permissions.md#restrict-access-to-groups-by-ip-address) changed. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/358986) in GitLab 15.0.
- Changes to push rules. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/227629) in GitLab 15.0.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/356152) in GitLab 15.1, changes to the following merge request approvals settings:
- Prevent approval by author.
@@ -124,6 +109,7 @@ From there, you can see the following actions:
- Require user password to approve.
- Remove all approvals when commits are added to the source branch.
- Changes to streaming audit destination custom HTTP headers. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/366350) in GitLab 15.3.
+- Group had a security policy project linked, changed, or unlinked. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/377877) in GitLab 15.6)
Group events can also be accessed via the [Group Audit Events API](../api/audit_events.md#group-audit-events)
@@ -194,6 +180,7 @@ From there, you can see the following actions:
- Squash commit message template is updated ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/355805) in GitLab 15.0)
- Default description template for merge requests is updated ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/355805) in GitLab 15.0)
- Project was scheduled for deletion due to inactivity ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85689) in GitLab 15.0)
+- Project had a security policy project linked, changed, or unlinked ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/377877) in GitLab 15.6)
Project events can also be accessed via the [Project Audit Events API](../api/audit_events.md#project-audit-events).
diff --git a/doc/administration/auth/authentiq.md b/doc/administration/auth/authentiq.md
index 1ac62b06fe7..d51601439f9 100644
--- a/doc/administration/auth/authentiq.md
+++ b/doc/administration/auth/authentiq.md
@@ -95,6 +95,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/administration/auth/jwt.md b/doc/administration/auth/jwt.md
index c7e7253ef72..c1e76d1c2ed 100644
--- a/doc/administration/auth/jwt.md
+++ b/doc/administration/auth/jwt.md
@@ -87,6 +87,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/administration/auth/ldap/google_secure_ldap.md b/doc/administration/auth/ldap/google_secure_ldap.md
index 2077c6f7baf..01197fdacdf 100644
--- a/doc/administration/auth/ldap/google_secure_ldap.md
+++ b/doc/administration/auth/ldap/google_secure_ldap.md
@@ -225,6 +225,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/administration/auth/ldap/index.md b/doc/administration/auth/ldap/index.md
index 3bb9350e960..6243f3da2d2 100644
--- a/doc/administration/auth/ldap/index.md
+++ b/doc/administration/auth/ldap/index.md
@@ -179,7 +179,7 @@ These configuration settings are available:
| `allow_username_or_email_login` | If enabled, GitLab ignores everything after the first `@` in the LDAP username submitted by the user on sign-in. If you are using `uid: 'userPrincipalName'` on ActiveDirectory you must disable this setting, because the userPrincipalName contains an `@`. | **{dotted-circle}** No | boolean |
| `block_auto_created_users` | To maintain tight control over the number of billable users on your GitLab installation, enable this setting to keep new users blocked until they have been cleared by an administrator (default: false). | **{dotted-circle}** No | boolean |
| `base` | Base where we can search for users. | **{check-circle}** Yes | `'ou=people,dc=gitlab,dc=example'` or `'DC=mydomain,DC=com'` |
-| `user_filter` | Filter LDAP users. Format: [RFC 4515](https://tools.ietf.org/search/rfc4515) Note: GitLab does not support `omniauth-ldap`'s custom filter syntax. | **{dotted-circle}** No | For examples, read [Examples of user filters](#examples-of-user-filters). |
+| `user_filter` | Filter LDAP users. Format: [RFC 4515](https://www.rfc-editor.org/rfc/rfc4515.html) Note: GitLab does not support `omniauth-ldap`'s custom filter syntax. | **{dotted-circle}** No | For examples, read [Examples of user filters](#examples-of-user-filters). |
| `lowercase_usernames` | If enabled, GitLab converts the name to lower case. | **{dotted-circle}** No | boolean |
| `retry_empty_result_with_codes` | An array of LDAP query response code that attempt to retry the operation if the result/content is empty. For Google Secure LDAP, set this value to `[80]`. | **{dotted-circle}** No | `[80]` |
@@ -281,7 +281,7 @@ This example results in a sign-in page with the following tabs:
To limit all GitLab access to a subset of the LDAP users on your LDAP server, first narrow the
configured `base`. However, to further filter users if
-necessary, you can set up an LDAP user filter. The filter must comply with [RFC 4515](https://tools.ietf.org/search/rfc4515).
+necessary, you can set up an LDAP user filter. The filter must comply with [RFC 4515](https://www.rfc-editor.org/rfc/rfc4515.html).
- Example user filter for Omnibus GitLab instances:
@@ -336,7 +336,7 @@ The `user_filter` DN can contain special characters. For example:
```
These characters must be escaped as documented in
- [RFC 4515](https://tools.ietf.org/search/rfc4515).
+ [RFC 4515](https://www.rfc-editor.org/rfc/rfc4515.html).
- Escape commas with `\2C`. For example:
diff --git a/doc/administration/auth/ldap/ldap-troubleshooting.md b/doc/administration/auth/ldap/ldap-troubleshooting.md
index 0ec482648a9..499c3c64af7 100644
--- a/doc/administration/auth/ldap/ldap-troubleshooting.md
+++ b/doc/administration/auth/ldap/ldap-troubleshooting.md
@@ -196,7 +196,7 @@ same user) has the email `email@example.com` set as a secondary email, which
is throwing this error.
We can check where this conflicting email address is coming from using the
-[rails console](#rails-console). Once in the console, run the following:
+[rails console](#rails-console). In the console, run the following:
```ruby
# This searches for an email among the primary AND secondary emails
@@ -546,7 +546,7 @@ this entry, it could be due to a mismatched DN stored in GitLab. See
```shell
User with DN `uid=john0,ou=people,dc=example,dc=com` should have access
to 'my_group' group but there is no user in GitLab with that
-identity. Membership will be updated once the user signs in for
+identity. Membership will be updated when the user signs in for
the first time.
```
@@ -556,7 +556,7 @@ Finally, the following entry says syncing has finished for this group:
Finished syncing all providers for 'my_group' group
```
-Once all the configured group links have been synchronized, GitLab looks
+When all the configured group links have been synchronized, GitLab looks
for any Administrators or External users to sync:
```shell
@@ -614,6 +614,16 @@ ldap_group.member_dns
ldap_group.member_uids
```
+#### LDAP synchronization does not remove group creator from group
+
+[LDAP synchronization](ldap_synchronization.md) should remove an LDAP group's creator
+from that group, if that user does not exist in the group. If running LDAP synchronization
+does not do this:
+
+1. Add the user to the LDAP group.
+1. Wait until LDAP group synchronization has finished running.
+1. Remove the user from the LDAP group.
+
### User DN or/and email have changed
When an LDAP user is created in GitLab, their LDAP DN is stored for later reference.
@@ -735,7 +745,7 @@ To resolve this error, you must apply a new license to the GitLab instance witho
1. Remove or comment out the GitLab configuration lines for all non-primary LDAP servers.
1. [Reconfigure GitLab](../../restart_gitlab.md#omnibus-gitlab-reconfigure) so that it temporarily uses only one LDAP server.
-1. Enter the [Rails console and add the license key](../../troubleshooting/gitlab_rails_cheat_sheet.md#add-a-license-through-the-console).
+1. Enter the [Rails console and add the license key](../../../user/admin_area/license_file.md#add-a-license-through-the-console).
1. Re-enable the additional LDAP servers in the GitLab configuration and reconfigure GitLab again.
## Debugging Tools
diff --git a/doc/administration/auth/ldap/ldap_synchronization.md b/doc/administration/auth/ldap/ldap_synchronization.md
index af2b1400670..02b04861844 100644
--- a/doc/administration/auth/ldap/ldap_synchronization.md
+++ b/doc/administration/auth/ldap/ldap_synchronization.md
@@ -182,16 +182,18 @@ group, GitLab revokes their `admin` role when syncing.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1793) in GitLab 12.0.
-"Lock memberships to LDAP synchronization" setting allows instance administrators
-to lock down user abilities to invite new members to a group.
+GitLab administrators can prevent group members from inviting new members to subgroups that have their membership synchronized with LDAP.
-When enabled, the following applies:
+Global group membership lock only applies to subgroups of the top-level group where LDAP synchronization is configured. No user can modify the
+membership of a top-level group configured for LDAP synchronization.
+
+When global group memberships lock is enabled:
- Only an administrator can manage memberships of any group including access levels.
- Users are not allowed to share a project with other groups or invite members to
a project created in a group.
-To enable it, you must:
+To enable global group memberships lock:
1. [Configure LDAP](index.md#configure-ldap).
1. On the top bar, select **Main menu > Admin**.
diff --git a/doc/administration/auth/oidc.md b/doc/administration/auth/oidc.md
index bb263512e06..1f73d8bff38 100644
--- a/doc/administration/auth/oidc.md
+++ b/doc/administration/auth/oidc.md
@@ -154,7 +154,7 @@ different providers with Omnibus GitLab.
### Configure Google
-See the [Google documentation](https://developers.google.com/identity/protocols/oauth2/openid-connect)
+See the [Google documentation](https://developers.google.com/identity/openid-connect/openid-connect)
for more details:
```ruby
@@ -502,7 +502,7 @@ For your app, complete the following steps on Casdoor:
ensure the Casdoor app has the following
`Redirect URI`: `https://gitlab.example.com/users/auth/openid_connect/callback`.
-See the [Casdoor documentation](https://casdoor.org/docs/integration/gitlab) for more details.
+See the [Casdoor documentation](https://casdoor.org/docs/integration/ruby/gitlab) for more details.
Example Omnibus GitLab configuration (file path: `/etc/gitlab/gitlab.rb`):
diff --git a/doc/administration/auth/smartcard.md b/doc/administration/auth/smartcard.md
index 11117e8a74c..5b6d299f171 100644
--- a/doc/administration/auth/smartcard.md
+++ b/doc/administration/auth/smartcard.md
@@ -342,6 +342,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/administration/cicd.md b/doc/administration/cicd.md
index 6899b572e8f..ad0671d4c13 100644
--- a/doc/administration/cicd.md
+++ b/doc/administration/cicd.md
@@ -101,6 +101,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/administration/compliance.md b/doc/administration/compliance.md
index ad345461776..ee7476ed6d4 100644
--- a/doc/administration/compliance.md
+++ b/doc/administration/compliance.md
@@ -48,9 +48,9 @@ settings and automation to ensure that whatever a compliance team has configured
stays configured and working correctly. These features can help you automate
compliance:
-- [**Compliance frameworks**](../user/group/manage.md#compliance-frameworks) (for groups): Create a custom
+- [**Compliance frameworks**](../user/group/compliance_frameworks.md) (for groups): Create a custom
compliance framework at the group level to describe the type of compliance requirements any child project needs to follow.
-- [**Compliance pipelines**](../user/group/manage.md#configure-a-compliance-pipeline) (for groups): Define a
+- [**Compliance pipelines**](../user/group/compliance_frameworks.md#configure-a-compliance-pipeline) (for groups): Define a
pipeline configuration to run for any projects with a given compliance framework.
## Audit management
diff --git a/doc/administration/configure.md b/doc/administration/configure.md
index 40f03d25e8d..91fec753f7e 100644
--- a/doc/administration/configure.md
+++ b/doc/administration/configure.md
@@ -30,7 +30,7 @@ The tables lists features on the left and provides their capabilities to the rig
## Geo Capabilities
-If your availability needs to span multiple zones or multiple locations, please read about [Geo](geo/index.md).
+If your availability needs to span multiple zones or multiple locations, read about [Geo](geo/index.md).
| | Availability | Recoverability | Data Resiliency | Performance | Risks/Trade-offs|
|-|--------------|----------------|-----------------|-------------|-----------------|
@@ -46,5 +46,5 @@ The following table outlines failure modes and mitigation paths for the product
| Single Gitaly Node + Geo Secondary | Downtime - Must restore from backup, can perform a manual failover to secondary | Downtime - Must restore from Backup, errors could have propagated to secondary | Manual intervention - failover to Geo secondary | |
| Sharded Gitaly Install | Partial Downtime - Only repositories on impacted node affected, must restore from backup | Partial Downtime - Only repositories on impacted node affected, must restore from backup | Downtime - Must wait for outage to end | |
| Sharded Gitaly Install + Geo Secondary | Partial Downtime - Only repositories on impacted node affected, must restore from backup, could perform manual failover to secondary for impacted repositories | Partial Downtime - Only repositories on impacted node affected, must restore from backup, errors could have propagated to secondary | Manual intervention - failover to Geo secondary | |
-| Gitaly Cluster Install* | No Downtime - will swap repository primary to another node after 10 seconds | Not applicable; All writes are voted on by multiple Gitaly Cluster nodes | Downtime - Must wait for outage to end | Snapshot backups for Gitaly Cluster nodes not supported at this time |
-| Gitaly Cluster Install* + Geo Secondary | No Downtime - will swap repository primary to another node after 10 seconds | Not applicable; All writes are voted on by multiple Gitaly Cluster nodes | Manual intervention - failover to Geo secondary | Snapshot backups for Gitaly Cluster nodes not supported at this time |
+| Gitaly Cluster Install* | No Downtime - swaps repository primary to another node after 10 seconds | Not applicable; All writes are voted on by multiple Gitaly Cluster nodes | Downtime - Must wait for outage to end | Snapshot backups for Gitaly Cluster nodes not supported at this time |
+| Gitaly Cluster Install* + Geo Secondary | No Downtime - swaps repository primary to another node after 10 seconds | Not applicable; All writes are voted on by multiple Gitaly Cluster nodes | Manual intervention - failover to Geo secondary | Snapshot backups for Gitaly Cluster nodes not supported at this time |
diff --git a/doc/administration/consul.md b/doc/administration/consul.md
index a6f76882c4d..965231db440 100644
--- a/doc/administration/consul.md
+++ b/doc/administration/consul.md
@@ -8,7 +8,7 @@ type: reference
# How to set up Consul **(PREMIUM SELF)**
A Consul cluster consists of both
-[server and client agents](https://www.consul.io/docs/agent).
+[server and client agents](https://developer.hashicorp.com/consul/docs/agent).
The servers run on their own nodes and the clients run on other nodes that in
turn communicate with the servers.
@@ -99,7 +99,7 @@ Consul nodes communicate using the raft protocol. If the current leader goes
offline, there must be a leader election. A leader node must exist to facilitate
synchronization across the cluster. If too many nodes go offline at the same time,
the cluster loses quorum and doesn't elect a leader due to
-[broken consensus](https://www.consul.io/docs/architecture/consensus).
+[broken consensus](https://developer.hashicorp.com/consul/docs/architecture/consensus).
Consult the [troubleshooting section](#troubleshooting-consul) if the cluster is not
able to recover after the upgrade. The [outage recovery](#outage-recovery) may
@@ -148,7 +148,7 @@ you follow the Consul [outage recovery](#outage-recovery) process.
To be safe, it's recommended that you only restart Consul in one node at a time to
ensure the cluster remains intact. For larger clusters, it is possible to restart
multiple nodes at a time. See the
-[Consul consensus document](https://www.consul.io/docs/architecture/consensus#deployment-table)
+[Consul consensus document](https://developer.hashicorp.com/consul/docs/architecture/consensus#deployment-table)
for the number of failures it can tolerate. This is the number of simultaneous
restarts it can sustain.
@@ -161,7 +161,7 @@ sudo gitlab-ctl restart consul
### Consul nodes unable to communicate
By default, Consul attempts to
-[bind](https://www.consul.io/docs/agent/config/config-files#bind_addr) to `0.0.0.0`, but
+[bind](https://developer.hashicorp.com/consul/docs/agent/config/config-files#bind_addr) to `0.0.0.0`, but
it advertises the first private IP address on the node for other Consul nodes
to communicate with it. If the other nodes cannot communicate with a node on
this address, then the cluster has a failed status.
@@ -249,5 +249,5 @@ Shortly after that, the client agents should rejoin as well.
If you have taken advantage of Consul to store other data and want to restore
the failed node, follow the
-[Consul guide](https://learn.hashicorp.com/tutorials/consul/recovery-outage)
+[Consul guide](https://developer.hashicorp.com/consul/tutorials/datacenter-operations/recovery-outage)
to recover a failed cluster.
diff --git a/doc/administration/environment_variables.md b/doc/administration/environment_variables.md
index beaef7afe57..d2edc3085f1 100644
--- a/doc/administration/environment_variables.md
+++ b/doc/administration/environment_variables.md
@@ -50,5 +50,5 @@ To set environment variables, follow [these instructions](https://docs.gitlab.co
It's possible to preconfigure the GitLab Docker image by adding the environment
variable `GITLAB_OMNIBUS_CONFIG` to the `docker run` command.
-For more information, see the [Pre-configure Docker container](https://docs.gitlab.com/omnibus/docker/#pre-configure-docker-container)
+For more information, see the [Pre-configure Docker container](../install/docker.md#pre-configure-docker-container)
section of the Omnibus GitLab documentation.
diff --git a/doc/administration/feature_flags.md b/doc/administration/feature_flags.md
index 4f8f7c22a55..f2a40b60536 100644
--- a/doc/administration/feature_flags.md
+++ b/doc/administration/feature_flags.md
@@ -118,10 +118,10 @@ Some feature flags can be enabled or disabled on a per project basis:
Feature.enable(:<feature flag>, Project.find(<project id>))
```
-For example, to enable the [`:product_analytics`](../operations/product_analytics.md) feature flag for project `1234`:
+For example, to enable the `:my_awesome_feature` feature flag for project `1234`:
```ruby
-Feature.enable(:product_analytics, Project.find(1234))
+Feature.enable(:my_awesome_feature, Project.find(1234))
```
`Feature.enable` and `Feature.disable` always return `true`, even if the application doesn't use the flag:
diff --git a/doc/administration/file_hooks.md b/doc/administration/file_hooks.md
index 8fafb258593..f8b55a7c680 100644
--- a/doc/administration/file_hooks.md
+++ b/doc/administration/file_hooks.md
@@ -7,10 +7,8 @@ type: reference
# File hooks **(FREE SELF)**
-> Renamed feature from Plugins to File hooks in GitLab 12.8.
-
-With custom file hooks, GitLab administrators can introduce custom integrations
-without modifying the GitLab source code.
+Use custom file hooks (not to be confused with [server hooks](server_hooks.md) or [system hooks](system_hooks.md)),
+to introduce custom integrations without modifying the GitLab source code.
A file hook runs on each event. You can filter events or projects
in a file hook's code, and create many file hooks as you need. Each file hook is
diff --git a/doc/administration/geo/disaster_recovery/background_verification.md b/doc/administration/geo/disaster_recovery/background_verification.md
index 699fe6851eb..99ac95cd536 100644
--- a/doc/administration/geo/disaster_recovery/background_verification.md
+++ b/doc/administration/geo/disaster_recovery/background_verification.md
@@ -122,7 +122,7 @@ be resynced with a back-off period. If you want to reset them manually, this
Rake task marks projects where verification has failed or the checksum mismatch
to be resynced without the back-off period:
-Run the appropriate commands on a **Rails node on the primary** site.
+Run the appropriate commands on a **Rails node on the secondary** site.
For repositories:
diff --git a/doc/administration/geo/disaster_recovery/index.md b/doc/administration/geo/disaster_recovery/index.md
index 156a87614e6..dfa8d09e6ef 100644
--- a/doc/administration/geo/disaster_recovery/index.md
+++ b/doc/administration/geo/disaster_recovery/index.md
@@ -758,7 +758,7 @@ If you are running GitLab 14.4 and earlier:
To promote the **secondary** cluster to a **primary** cluster, update `role: secondary` to `role: primary`.
- If the cluster remains as a primary site, you can remove the entire `psql` section; it refers to the tracking database and is ignored whilst the cluster is acting as a primary site.
+ If the cluster remains as a primary site, you can remove the entire `psql` section; it refers to the tracking database and is ignored while the cluster is acting as a primary site.
Update the cluster with the new configuration:
diff --git a/doc/administration/geo/disaster_recovery/planned_failover.md b/doc/administration/geo/disaster_recovery/planned_failover.md
index 60101f5af8e..80707afacca 100644
--- a/doc/administration/geo/disaster_recovery/planned_failover.md
+++ b/doc/administration/geo/disaster_recovery/planned_failover.md
@@ -14,12 +14,12 @@ downtime.
As replication between Geo sites is asynchronous, a planned failover requires
a maintenance window in which updates to the **primary** site are blocked. The
-length of this window is determined by your replication capacity - once the
+length of this window is determined by your replication capacity - when the
**secondary** site is completely synchronized with the **primary** site, the failover can occur without
data loss.
This document assumes you already have a fully configured, working Geo setup.
-Please read it and the [Disaster Recovery](index.md) failover
+Read this document and the [Disaster Recovery](index.md) failover
documentation in full before proceeding. Planned failover is a major operation,
and if performed incorrectly, there is a high risk of data loss. Consider
rehearsing the procedure until you are comfortable with the necessary steps and
diff --git a/doc/administration/geo/index.md b/doc/administration/geo/index.md
index a336f5ff8bc..68fd0c63e37 100644
--- a/doc/administration/geo/index.md
+++ b/doc/administration/geo/index.md
@@ -120,18 +120,18 @@ The following are required to run Geo:
- [CentOS](https://www.centos.org) 7.4 or later
- [Ubuntu](https://ubuntu.com) 16.04 or later
- PostgreSQL 12 or 13 with [Streaming Replication](https://wiki.postgresql.org/wiki/Streaming_Replication)
- - Note,[PostgreSQL 12 is deprecated](../../update/deprecations.md#postgresql-12-deprecated) and will be removed in GitLab 16.0.
+ - 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).
-- 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.
+- 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.
Additionally, check the GitLab [minimum requirements](../../install/requirements.md),
-and we recommend you use the latest version of GitLab for a better experience.
+and use the latest version of GitLab for a better experience.
### Firewall rules
-The following table lists basic ports that must be open between the **primary** and **secondary** sites for Geo. To simplify failovers, we recommend opening ports in both directions.
+The following table lists basic ports that must be open between the **primary** and **secondary** sites for Geo. To simplify failovers, you should open ports in both directions.
| Source site | Source port | Destination site | Destination port | Protocol |
|-------------|-------------|------------------|------------------|-------------|
@@ -306,7 +306,7 @@ For an example of how to set up a location-aware Git remote URL with AWS Route53
### Backfill
-Once a **secondary** site is set up, it starts replicating missing data from
+When a **secondary** site is set up, it starts replicating missing data from
the **primary** site in a process known as **backfill**. You can monitor the
synchronization process on each Geo site from the **primary** site's **Geo Nodes**
dashboard in your browser.
diff --git a/doc/administration/geo/replication/configuration.md b/doc/administration/geo/replication/configuration.md
index fa74f16cdc8..55c5d3784c2 100644
--- a/doc/administration/geo/replication/configuration.md
+++ b/doc/administration/geo/replication/configuration.md
@@ -12,7 +12,7 @@ type: howto
NOTE:
This is the final step in setting up a **secondary** Geo site. Stages of the
setup process must be completed in the documented order.
-If not, [complete all prior stages](../setup/index.md#using-omnibus-gitlab) before procceed.
+If not, [complete all prior stages](../setup/index.md#using-omnibus-gitlab) before proceeding.
Make sure you [set up the database replication](../setup/database.md), and [configured fast lookup of authorized SSH keys](../../operations/fast_ssh_key_lookup.md) in **both primary and secondary sites**.
@@ -239,8 +239,9 @@ keys must be manually replicated to the **secondary** site.
If any of the checks fail, check the [troubleshooting documentation](troubleshooting.md).
-Once added to the Geo administration page and restarted, the **secondary** site automatically starts
-replicating missing data from the **primary** site in a process known as **backfill**.
+After the **secondary** site is added to the Geo administration page and restarted,
+the site automatically starts replicating missing data from the **primary** site
+in a process known as **backfill**.
Meanwhile, the **primary** site starts to notify each **secondary** site of any changes, so
that the **secondary** site can act on those notifications immediately.
diff --git a/doc/administration/geo/replication/datatypes.md b/doc/administration/geo/replication/datatypes.md
index 566df2ee509..0198d2a63e8 100644
--- a/doc/administration/geo/replication/datatypes.md
+++ b/doc/administration/geo/replication/datatypes.md
@@ -201,8 +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 | Replication is behind feature flag `geo_container_repository_replication`, enabled by default.
-Requires additional configuration. See [instructions](container_registry.md) to set up the Container Registry replication. |
+|[Container Registry](../../packages/container_registry.md) | **Yes** (12.3)* | No | No | No | Replication is behind feature flag `geo_container_repository_replication`, enabled by default. Requires additional configuration. 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/disable_geo.md b/doc/administration/geo/replication/disable_geo.md
index 3230a92136f..c42130a62a7 100644
--- a/doc/administration/geo/replication/disable_geo.md
+++ b/doc/administration/geo/replication/disable_geo.md
@@ -24,8 +24,8 @@ To disable Geo, follow these steps:
## Remove all secondary Geo sites
-To disable Geo, you need to first remove all your secondary Geo sites, which means replication will not happen
-anymore on these sites. You can follow our docs to [remove your secondary Geo sites](remove_geo_site.md).
+To disable Geo, you need to first remove all your secondary Geo sites, which means replication does not happen
+anymore on these sites. You can follow our documentation to [remove your secondary Geo sites](remove_geo_site.md).
If the current site that you want to keep using is a secondary site, you need to first promote it to primary.
You can use our steps on [how to promote a secondary site](../disaster_recovery/index.md#step-3-promoting-a-secondary-site)
diff --git a/doc/administration/geo/replication/docker_registry.md b/doc/administration/geo/replication/docker_registry.md
deleted file mode 100644
index d0af6f2a66f..00000000000
--- a/doc/administration/geo/replication/docker_registry.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: 'container_registry.md'
-remove_date: '2022-10-29'
----
-
-This document was moved to [another location](container_registry.md).
-
-<!-- This redirect file can be deleted after <2022-10-29>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html --> \ No newline at end of file
diff --git a/doc/administration/geo/replication/faq.md b/doc/administration/geo/replication/faq.md
index 81afcc19bb1..311cdeee5b9 100644
--- a/doc/administration/geo/replication/faq.md
+++ b/doc/administration/geo/replication/faq.md
@@ -22,7 +22,7 @@ For each project to sync:
1. Geo issues a `git fetch geo --mirror` to get the latest information from the **primary** site.
If there are no changes, the sync is fast. Otherwise, it has to pull the latest commits.
-1. The **secondary** site updates the tracking database to store the fact that it has synced projects A, B, C, and so on.
+1. The **secondary** site updates the tracking database to store the fact that it has synced projects by name.
1. Repeat until all projects are synced.
When someone pushes a commit to the **primary** site, it generates an event in the GitLab database that the repository has changed.
@@ -45,8 +45,8 @@ Read the documentation for [Disaster Recovery](../disaster_recovery/index.md).
## What data is replicated to a **secondary** site?
We currently replicate project repositories, LFS objects, generated
-attachments and avatars, and the whole database. This means user accounts,
-issues, merge requests, groups, project data, and so on, are available for
+attachments and avatars, and the whole database. This means information such as user accounts,
+issues, merge requests, groups, and project data are available for
query.
For more details, see the [supported Geo data types](datatypes.md).
@@ -58,8 +58,8 @@ Pushing directly to a **secondary** site (for both HTTP and SSH, including Git L
## How long does it take to have a commit replicated to a **secondary** site?
All replication operations are asynchronous and are queued to be dispatched. Therefore, it depends on a lot of
-factors including the amount of traffic, how big your commit is, the
-connectivity between your sites, your hardware, and so on.
+factors such as the amount of traffic, how big your commit is, the
+connectivity between your sites, and your hardware.
## What if the SSH server runs at a different port?
diff --git a/doc/administration/geo/replication/geo_validation_tests.md b/doc/administration/geo/replication/geo_validation_tests.md
index 8fa5a45b579..f09422d1e26 100644
--- a/doc/administration/geo/replication/geo_validation_tests.md
+++ b/doc/administration/geo/replication/geo_validation_tests.md
@@ -29,7 +29,7 @@ The following are GitLab upgrade validation tests we performed.
[Switch from repmgr to Patroni on a Geo primary site](https://gitlab.com/gitlab-org/gitlab/-/issues/224652):
- Description: Tested switching from repmgr to Patroni on a multi-node Geo primary site. Used [the orchestrator tool](https://gitlab.com/gitlab-org/gitlab-orchestrator) to deploy a Geo installation with 3 database nodes managed by repmgr. With this approach, we were also able to address a related issue for [verifying a Geo installation with Patroni and PostgreSQL 11](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5113).
-- Outcome: Partial success. We enabled Patroni on the primary site and set up database replication on the secondary site. However, we found that Patroni would delete the secondary site's replication slot whenever Patroni was restarted. Another issue is that when Patroni elects a new leader in the cluster, the secondary site will fail to automatically follow the new leader. Until these issues are resolved, we cannot officially support and recommend Patroni for Geo installations.
+- Outcome: Partial success. We enabled Patroni on the primary site and set up database replication on the secondary site. However, we found that Patroni would delete the secondary site's replication slot whenever Patroni was restarted. Another issue is that when Patroni elects a new leader in the cluster, the secondary site fails to automatically follow the new leader. Until these issues are resolved, we cannot officially support and recommend Patroni for Geo installations.
- Follow up issues/actions:
- [Investigate permanent replication slot for Patroni with Geo single node secondary](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/5528)
@@ -213,7 +213,7 @@ The following are additional validation tests we performed.
[Validate Object storage replication using GCP based object storage](https://gitlab.com/gitlab-org/gitlab/-/issues/351464):
- Description: Tested the average time it takes for a single image to replicate from the primary object storage location to the secondary when using GCP based object storage replication and [GitLab based object storage replication](object_storage.md#enabling-gitlab-managed-object-storage-replication). This was tested by uploading a 1mb image to a project on the primary site every second for 60 seconds. The time was then measured until a image was available on the secondary site. This was achieved using a [Ruby Script](https://gitlab.com/gitlab-org/quality/geo-replication-tester).
-- Outcome: GCP handles replication differently than other Cloud Providers. In GCP, the process is to a create single bucket that is either multi, dual or single region based. This means that the bucket will automatically store replicas in a region based on the option chosen. Even when using multi region, this will still only replicate within a single continent, the options being America, Europe, or Asia. At current there doesn't seem to be any way to replicate objects between continents using GCP based replication. For Geo managed replication the average time when replicating within the same region was 6 seconds, and when replicating cross region this rose to just 9 seconds.
+- Outcome: GCP handles replication differently than other Cloud Providers. In GCP, the process is to a create single bucket that is either multi, dual, or single region based. This means that the bucket automatically stores replicas in a region based on the option chosen. Even when using multi region, this only replicates in a single continent, the options being America, Europe, or Asia. At current there doesn't seem to be any way to replicate objects between continents using GCP based replication. For Geo managed replication the average time when replicating in the same region was 6 seconds, and when replicating cross region this rose to just 9 seconds.
## Other tests
diff --git a/doc/administration/geo/replication/location_aware_git_url.md b/doc/administration/geo/replication/location_aware_git_url.md
index e0e113eebbd..dbe543f5a62 100644
--- a/doc/administration/geo/replication/location_aware_git_url.md
+++ b/doc/administration/geo/replication/location_aware_git_url.md
@@ -31,7 +31,7 @@ In this example, we have already set up:
- `primary.example.com` as a Geo **primary** site.
- `secondary.example.com` as a Geo **secondary** site.
-We will create a `git.example.com` subdomain that will automatically direct
+We create a `git.example.com` subdomain that automatically directs
requests:
- From Europe to the **secondary** site.
diff --git a/doc/administration/geo/replication/remove_geo_site.md b/doc/administration/geo/replication/remove_geo_site.md
index 62b1d9fdf7b..4b9f31dc08c 100644
--- a/doc/administration/geo/replication/remove_geo_site.md
+++ b/doc/administration/geo/replication/remove_geo_site.md
@@ -14,7 +14,8 @@ type: howto
1. Select the **Remove** button for the **secondary** site you want to remove.
1. Confirm by selecting **Remove** when the prompt appears.
-Once removed from the Geo administration page, you must stop and uninstall the **secondary** site. For each node on your secondary Geo site:
+After the **secondary** site is removed from the Geo administration page, you must
+stop and uninstall this site. For each node on your secondary Geo site:
1. Stop GitLab:
@@ -35,7 +36,7 @@ Once removed from the Geo administration page, you must stop and uninstall the *
sudo rpm --erase gitlab-ee
```
-Once GitLab has been uninstalled from each node on the **secondary** site, the replication slot must be dropped from the **primary** site's database as follows:
+When GitLab has been uninstalled from each node on the **secondary** site, the replication slot must be dropped from the **primary** site's database as follows:
1. On the **primary** site's database node, start a PostgreSQL console session:
diff --git a/doc/administration/geo/replication/security_review.md b/doc/administration/geo/replication/security_review.md
index 0231da53b9c..afe831dcb9c 100644
--- a/doc/administration/geo/replication/security_review.md
+++ b/doc/administration/geo/replication/security_review.md
@@ -25,8 +25,8 @@ from [owasp.org](https://owasp.org/).
### What data does the application receive, produce, and process?
- Geo streams almost all data held by a GitLab instance between sites. This
- includes full database replication, most files (user-uploaded attachments,
- and so on) and repository + wiki data. In a typical configuration, this will
+ includes full database replication, most files such as user-uploaded attachments,
+ and repository + wiki data. In a typical configuration, this will
happen across the public Internet, and be TLS-encrypted.
- PostgreSQL replication is TLS-encrypted.
- See also: [only TLSv1.2 should be supported](https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/2948)
@@ -37,7 +37,7 @@ from [owasp.org](https://owasp.org/).
private projects. Geo replicates them all indiscriminately. "Selective sync"
exists for files and repositories (but not database content), which would permit
only less-sensitive projects to be replicated to a **secondary** site if desired.
-- See also: [GitLab data classification policy](https://about.gitlab.com/handbook/engineering/security/data-classification-standard.html).
+- See also: [GitLab data classification policy](https://about.gitlab.com/handbook/security/data-classification-standard.html).
### What data backup and retention requirements have been defined for the application?
@@ -59,8 +59,8 @@ from [owasp.org](https://owasp.org/).
(notably a HTTP/HTTPS web application, and HTTP/HTTPS or SSH Git repository
access), but is constrained to read-only activities. The principal use case is
envisioned to be cloning Git repositories from the **secondary** site in favor of the
- **primary** site, but end-users may use the GitLab web interface to view projects,
- issues, merge requests, snippets, and so on.
+ **primary** site, but end-users may use the GitLab web interface to view information like projects,
+ issues, merge requests, and snippets.
### What security expectations do the endâ€users have?
diff --git a/doc/administration/geo/replication/troubleshooting.md b/doc/administration/geo/replication/troubleshooting.md
index 3f16c1552ad..fa668091c90 100644
--- a/doc/administration/geo/replication/troubleshooting.md
+++ b/doc/administration/geo/replication/troubleshooting.md
@@ -12,8 +12,9 @@ miss a step.
Here is a list of steps you should take to attempt to fix problem:
1. Perform [basic troubleshooting](#basic-troubleshooting).
-1. Fix any [replication errors](#fixing-replication-errors).
+1. Fix any [PostgreSQL database replication errors](#fixing-postgresql-database-replication-errors).
1. Fix any [common](#fixing-common-errors) errors.
+1. Fix any [non-PostgreSQL replication failures](#fixing-non-postgresql-replication-failures).
## Basic troubleshooting
@@ -131,6 +132,8 @@ http://secondary.example.com/
To find more details about failed items, check
[the `gitlab-rails/geo.log` file](../../logs/log_parsing.md#find-most-common-geo-sync-errors)
+If you notice replication or verification failures, you can try to [resolve them](#fixing-non-postgresql-replication-failures).
+
### Check if PostgreSQL replication is working
To check if PostgreSQL replication is working, check if:
@@ -185,6 +188,41 @@ This machine's Geo node name matches a database record ... no
Learn more about recommended site names in the description of the Name field in
[Geo Admin Area Common Settings](../../../user/admin_area/geo_sites.md#common-settings).
+### Reverify all uploads (or any SSF data type which is verified)
+
+1. SSH into a GitLab Rails node in the primary Geo site.
+1. Open [Rails console](../../operations/rails_console.md).
+1. Mark all uploads as "pending verification":
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
+ ```ruby
+ Upload.verification_state_table_class.each_batch do |relation|
+ relation.update_all(verification_state: 0)
+ end
+ ```
+
+1. This will cause the primary to start checksumming all Uploads.
+1. When a primary successfully checksums a record, then all secondaries rechecksum as well, and they compare the values.
+
+A similar thing can be done for all Models handled by the [Geo Self-Service Framework](../../../development/geo/framework.md) which have implemented verification:
+
+- `LfsObject`
+- `MergeRequestDiff`
+- `Packages::PackageFile`
+- `Terraform::StateVersion`
+- `SnippetRepository`
+- `Ci::PipelineArtifact`
+- `PagesDeployment`
+- `Upload`
+- `Ci::JobArtifact`
+- `Ci::SecureFile`
+
+NOTE:
+`GroupWikiRepository` is not in the previous list since verification is not implemented.
+There is an [issue to implement this functionality in the Admin Area UI](https://gitlab.com/gitlab-org/gitlab/-/issues/364729).
+
### Message: `WARNING: oldest xmin is far in the past` and `pg_wal` size growing
If a replication slot is inactive,
@@ -311,52 +349,41 @@ sudo gitlab-rake gitlab:geo:check
When performing a PostgreSQL major version (9 > 10) update this is expected. Follow
the [initiate-the-replication-process](../setup/database.md#step-3-initiate-the-replication-process).
-### Repository verification failures
+### Message: Machine clock is synchronized ... Exception
-[Start a Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
-to gather the following, basic troubleshooting information.
+The Rake task attempts to verify that the server clock is synchronized with NTP. Synchronized clocks
+are required for Geo to function correctly. As an example, for security, when the server time on the
+primary site and secondary site differ by about a minute or more, requests between Geo sites
+will fail. If this check task fails to complete due to a reason other than mismatching times, it
+does not necessarily mean that Geo will not work.
-WARNING:
-Any command that changes data directly could be damaging if not run correctly, or under the right conditions. We highly recommend running them in a test environment with a backup of the instance ready to be restored, just in case.
+The Ruby gem which performs the check is hard coded with `pool.ntp.org` as its reference time source.
-#### Get the number of verification failed repositories
+- Exception message `Machine clock is synchronized ... Exception: Timeout::Error`
-```ruby
-Geo::ProjectRegistry.verification_failed('repository').count
-```
+ This issue occurs when your server cannot access the host `pool.ntp.org`.
-#### Find the verification failed repositories
+- Exception message `Machine clock is synchronized ... Exception: No route to host - recvfrom(2)`
-```ruby
-Geo::ProjectRegistry.verification_failed('repository')
-```
+ This issue occurs when the hostname `pool.ntp.org` resolves to a server which does not provide a time service.
-#### Find repositories that failed to sync
+There is [an issue open](https://gitlab.com/gitlab-org/gitlab/-/issues/381422) for this dependency on `pool.ntp.org`.
-```ruby
-Geo::ProjectRegistry.sync_failed('repository')
-```
-
-### Resync repositories
-
-[Start a Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
-to enact the following, basic troubleshooting steps.
-
-#### Queue up all repositories for resync. Sidekiq handles each sync
+To workaround this, do one of the following:
-```ruby
-Geo::ProjectRegistry.update_all(resync_repository: true, resync_wiki: true)
-```
+- Add entries in `/etc/hosts` for `pool.ntp.org` to direct the request to valid local time servers.
+ This fixes the long timeout and the timeout error.
+- Direct the check to any valid IP address. This resolves the timeout issue, but the check will fail
+ with the `No route to host` error, as noted above.
-#### Sync individual repository now
+[Cloud native GitLab deployments](https://docs.gitlab.com/charts/advanced/geo/#set-the-geo-primary-site)
+generate an error because containers in Kubernetes do not have access to the host clock:
-```ruby
-project = Project.find_by_full_path('<group/project>')
-
-Geo::RepositorySyncService.new(project).execute
+```plaintext
+Machine clock is synchronized ... Exception: getaddrinfo: Servname not supported for ai_socktype
```
-## Fixing replication errors
+## Fixing PostgreSQL database replication errors
The following sections outline troubleshooting steps for fixing replication
error messages (indicated by `Database replication working? ... no` in the
@@ -469,7 +496,7 @@ This happens because the PostgreSQL certificate that the Omnibus GitLab package
the Common Name `PostgreSQL`, but the replication is connecting to a different host and GitLab attempts to use
the `verify-full` SSL mode by default.
-In order to fix this, you can either:
+To fix this issue, you can either:
- Use the `--sslmode=verify-ca` argument with the `replicate-geo-database` command.
- For an already replicated database, change `sslmode=verify-full` to `sslmode=verify-ca`
@@ -837,120 +864,6 @@ This behavior affects only the following data types through GitLab 14.6:
to make Geo visibly surface data loss risks. The sync/verification loop is
therefore short-circuited. `last_sync_failure` is now set to `The file is missing on the Geo primary site`.
-### Blob types
-
-- `Ci::JobArtifact`
-- `Ci::PipelineArtifact`
-- `Ci::SecureFile`
-- `LfsObject`
-- `MergeRequestDiff`
-- `Packages::PackageFile`
-- `PagesDeployment`
-- `Terraform::StateVersion`
-- `Upload`
-
-`Packages::PackageFile` is used in the following
-[Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
-examples, but things generally work the same for the other types.
-
-WARNING:
-Any command that changes data directly could be damaging if not run correctly, or under the right conditions. We highly recommend running them in a test environment with a backup of the instance ready to be restored, just in case.
-
-#### The Replicator
-
-The main kinds of classes are Registry, Model, and Replicator. If you have an instance of one of these classes, you can get the others. The Registry and Model mostly manage PostgreSQL DB state. The Replicator knows how to replicate/verify (or it can call a service to do it):
-
-```ruby
-model_record = Packages::PackageFile.last
-model_record.replicator.registry.replicator.model_record # just showing that these methods exist
-```
-
-#### Replicate a package file, synchronously, given an ID
-
-```ruby
-model_record = Packages::PackageFile.find(id)
-model_record.replicator.send(:download)
-```
-
-#### Replicate a package file, synchronously, given a registry ID
-
-```ruby
-registry = Geo::PackageFileRegistry.find(registry_id)
-registry.replicator.send(:download)
-```
-
-#### Verify package files on the secondary manually
-
-This iterates over all package files on the secondary, looking at the
-`verification_checksum` stored in the database (which came from the primary)
-and then calculate this value on the secondary to check if they match. This
-does not change anything in the UI:
-
-```ruby
-# Run on secondary
-status = {}
-
-Packages::PackageFile.find_each do |package_file|
- primary_checksum = package_file.verification_checksum
- secondary_checksum = Packages::PackageFile.hexdigest(package_file.file.path)
- verification_status = (primary_checksum == secondary_checksum)
-
- status[verification_status.to_s] ||= []
- status[verification_status.to_s] << package_file.id
-end
-
-# Count how many of each value we get
-status.keys.each {|key| puts "#{key} count: #{status[key].count}"}
-
-# See the output in its entirety
-status
-```
-
-### Repository types newer than project/wiki repositories
-
-- `SnippetRepository`
-- `GroupWikiRepository`
-
-`SnippetRepository` is used in the examples below, but things generally work the same for the other Repository types.
-
-#### The Replicator
-
-The main kinds of classes are Registry, Model, and Replicator. If you have an instance of one of these classes, you can get the others. The Registry and Model mostly manage PostgreSQL DB state. The Replicator knows how to replicate/verify (or it can call a service to do it).
-
-```ruby
-model_record = SnippetRepository.last
-model_record.replicator.registry.replicator.model_record # just showing that these methods exist
-```
-
-#### Replicate a snippet repository, synchronously, given an ID
-
-```ruby
-model_record = SnippetRepository.find(id)
-model_record.replicator.send(:sync_repository)
-```
-
-#### Replicate a snippet repository, synchronously, given a registry ID
-
-```ruby
-registry = Geo::SnippetRepositoryRegistry.find(registry_id)
-registry.replicator.send(:sync_repository)
-```
-
-### Find failed artifacts
-
-[Start a Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
-to run the following commands:
-
-```ruby
-Geo::JobArtifactRegistry.failed
-```
-
-#### Find `ID` of synced artifacts that are missing on primary
-
-```ruby
-Geo::JobArtifactRegistry.synced.missing_on_primary.pluck(:artifact_id)
-```
-
#### Failed syncs with GitLab-managed object storage replication
There is [an issue in GitLab 14.2 through 14.7](https://gitlab.com/gitlab-org/gitlab/-/issues/299819#note_822629467)
@@ -1218,7 +1131,8 @@ If you set up a new secondary from scratch, you must also [remove the old site f
The most common problems that prevent the database from replicating correctly are:
-- **Secondary** sites cannot reach the **primary** site. Check credentials, [firewall rules](../index.md#firewall-rules), and so on.
+- **Secondary** sites cannot reach the **primary** site. Check credentials and
+ [firewall rules](../index.md#firewall-rules).
- SSL certificate problems. Make sure you copied `/etc/gitlab/gitlab-secrets.json` from the **primary** site.
- Database storage disk is full.
- Database replication slot is misconfigured.
@@ -1320,6 +1234,217 @@ To fix this issue, set the primary site's internal URL to a URL that is:
GeoNode.where(primary: true).first.update!(internal_url: "https://unique.url.for.primary.site")
```
+## Fixing non-PostgreSQL replication failures
+
+If you notice replication failures in `Admin > Geo > Sites` or the [Sync status Rake task](#sync-status-rake-task), you can try to resolve the failures with the following general steps:
+
+1. Geo will automatically retry failures. If the failures are new and few in number, or if you suspect the root cause is already resolved, then you can wait to see if the failures go away.
+1. If failures were present for a long time, then many retries have already occurred, and the interval between automatic retries has increased to up to 4 hours depending on the type of failure. If you suspect the root cause is already resolved, you can [manually retry replication or verification](#manually-retry-replication-or-verification).
+1. If the failures persist, use the following sections to try to resolve them.
+
+### Manually retry replication or verification
+
+Project Git repositories and Project Wiki Git repositories have the ability in `Admin > Geo > Replication` to `Resync all`, `Reverify all`, or for a single resource, `Resync` or `Reverify`.
+
+Adding this ability to other data types is proposed in issue [364725](https://gitlab.com/gitlab-org/gitlab/-/issues/364725).
+
+The following sections describe how to use internal application commands in the [Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session) to cause replication or verification immediately.
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
+### Blob types
+
+- `Ci::JobArtifact`
+- `Ci::PipelineArtifact`
+- `Ci::SecureFile`
+- `LfsObject`
+- `MergeRequestDiff`
+- `Packages::PackageFile`
+- `PagesDeployment`
+- `Terraform::StateVersion`
+- `Upload`
+
+`Packages::PackageFile` is used in the following
+[Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
+examples, but things generally work the same for the other types.
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
+#### The Replicator
+
+The main kinds of classes are Registry, Model, and Replicator. If you have an instance of one of these classes, you can get the others. The Registry and Model mostly manage PostgreSQL DB state. The Replicator knows how to replicate/verify (or it can call a service to do it):
+
+```ruby
+model_record = Packages::PackageFile.last
+model_record.replicator.registry.replicator.model_record # just showing that these methods exist
+```
+
+#### Replicate a package file, synchronously, given an ID
+
+```ruby
+model_record = Packages::PackageFile.find(id)
+model_record.replicator.send(:download)
+```
+
+#### Replicate a package file, synchronously, given a registry ID
+
+```ruby
+registry = Geo::PackageFileRegistry.find(registry_id)
+registry.replicator.send(:download)
+```
+
+#### Verify package files on the secondary manually
+
+This iterates over all package files on the secondary, looking at the
+`verification_checksum` stored in the database (which came from the primary)
+and then calculate this value on the secondary to check if they match. This
+does not change anything in the UI:
+
+```ruby
+# Run on secondary
+status = {}
+
+Packages::PackageFile.find_each do |package_file|
+ primary_checksum = package_file.verification_checksum
+ secondary_checksum = Packages::PackageFile.hexdigest(package_file.file.path)
+ verification_status = (primary_checksum == secondary_checksum)
+
+ status[verification_status.to_s] ||= []
+ status[verification_status.to_s] << package_file.id
+end
+
+# Count how many of each value we get
+status.keys.each {|key| puts "#{key} count: #{status[key].count}"}
+
+# See the output in its entirety
+status
+```
+
+### Reverify all uploads (or any SSF data type which is verified)
+
+1. SSH into a GitLab Rails node in the primary Geo site.
+1. Open [Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session).
+1. Mark all uploads as "pending verification":
+
+ ```ruby
+ Upload.verification_state_table_class.each_batch do |relation|
+ relation.update_all(verification_state: 0)
+ end
+ ```
+
+1. This will cause the primary to start checksumming all Uploads.
+1. When a primary successfully checksums a record, then all secondaries rechecksum as well, and they compare the values.
+
+For other SSF data types replace `Upload` in the command above with the desired model class.
+
+NOTE:
+There is an [issue to implement this functionality in the Admin Area UI](https://gitlab.com/gitlab-org/gitlab/-/issues/364729).
+
+### Repository types, except for project or project wiki repositories
+
+- `SnippetRepository`
+- `GroupWikiRepository`
+
+`SnippetRepository` is used in the examples below, but things generally work the same for the other Repository types.
+
+[Start a Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
+to enact the following, basic troubleshooting steps.
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
+#### The Replicator
+
+The main kinds of classes are Registry, Model, and Replicator. If you have an instance of one of these classes, you can get the others. The Registry and Model mostly manage PostgreSQL DB state. The Replicator knows how to replicate/verify (or it can call a service to do it).
+
+```ruby
+model_record = SnippetRepository.last
+model_record.replicator.registry.replicator.model_record # just showing that these methods exist
+```
+
+#### Replicate a snippet repository, synchronously, given an ID
+
+```ruby
+model_record = SnippetRepository.find(id)
+model_record.replicator.send(:sync_repository)
+```
+
+#### Replicate a snippet repository, synchronously, given a registry ID
+
+```ruby
+registry = Geo::SnippetRepositoryRegistry.find(registry_id)
+registry.replicator.send(:sync_repository)
+```
+
+### Find failed artifacts
+
+[Start a Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
+to run the following commands:
+
+```ruby
+Geo::JobArtifactRegistry.failed
+```
+
+#### Find `ID` of synced artifacts that are missing on primary
+
+```ruby
+Geo::JobArtifactRegistry.synced.missing_on_primary.pluck(:artifact_id)
+```
+
+### Project or project wiki repositories
+
+#### Find repository verification failures
+
+[Start a Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
+to gather the following, basic troubleshooting information.
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
+##### Get the number of verification failed repositories
+
+```ruby
+Geo::ProjectRegistry.verification_failed('repository').count
+```
+
+##### Find the verification failed repositories
+
+```ruby
+Geo::ProjectRegistry.verification_failed('repository')
+```
+
+##### Find repositories that failed to sync
+
+```ruby
+Geo::ProjectRegistry.sync_failed('repository')
+```
+
+#### Resync project and project wiki repositories
+
+[Start a Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
+to enact the following, basic troubleshooting steps.
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
+##### Queue up all repositories for resync
+
+When you run this, Sidekiq handles each sync.
+
+```ruby
+Geo::ProjectRegistry.update_all(resync_repository: true, resync_wiki: true)
+```
+
+##### Sync individual repository now
+
+```ruby
+project = Project.find_by_full_path('<group/project>')
+
+Geo::RepositorySyncService.new(project).execute
+```
+
## Fixing client errors
### Authorization errors from LFS HTTP(S) client requests
@@ -1390,10 +1515,6 @@ If the above steps are **not successful**, proceed through the next steps:
1. Verify you can connect to the newly-promoted **primary** site using the URL used previously for the **secondary** site.
1. If successful, the **secondary** site is now promoted to the **primary** site.
-## Additional tools
-
-There are useful snippets for manipulating Geo internals in the [GitLab Rails Cheat Sheet](../../troubleshooting/gitlab_rails_cheat_sheet.md#geo). For example, you can find how to manually sync or verify a replicable in Rails console.
-
## Check OS locale data compatibility
If different operating systems or different operating system versions are deployed across Geo sites, we recommend that you perform a locale data compatibility check setting up Geo.
diff --git a/doc/administration/geo/secondary_proxy/location_aware_external_url.md b/doc/administration/geo/secondary_proxy/location_aware_external_url.md
index b983230a314..b71b813ee9f 100644
--- a/doc/administration/geo/secondary_proxy/location_aware_external_url.md
+++ b/doc/administration/geo/secondary_proxy/location_aware_external_url.md
@@ -15,10 +15,6 @@ advantage of closer Geo sites as they move.
With [Geo proxying for secondary sites](index.md) web and Git requests are proxied
from **secondary** sites to the **primary**.
-Though these instructions use [AWS Route53](https://aws.amazon.com/route53/),
-other services such as [Cloudflare](https://www.cloudflare.com/) can be used
-as well.
-
## Prerequisites
This example creates a `gitlab.example.com` subdomain that automatically directs
@@ -36,17 +32,20 @@ For this example, you need:
- A working GitLab **primary** site that is accessible at `gitlab.example.com` _and_ `primary.example.com`.
- A working GitLab **secondary** site.
-- A Route53 Hosted Zone managing your domain for the Route53 setup.
+- A DNS zone managing your domain. Although the following instructions use
+ [AWS Route53](https://aws.amazon.com/route53/)
+ and [GCP cloud DNS](https://cloud.google.com/dns/), other services such as
+ [Cloudflare](https://www.cloudflare.com/) can be used as well.
If you haven't yet set up a Geo _primary_ site and _secondary_ site, see the
[Geo setup instructions](../index.md#setup-instructions).
## AWS Route53
-### Create a traffic policy
+In this example, you use a Route53 Hosted Zone managing your domain for the Route53 setup.
In a Route53 Hosted Zone, traffic policies can be used to set up a variety of
-routing configurations.
+routing configurations. To create a traffic policy:
1. Go to the
[Route53 dashboard](https://console.aws.amazon.com/route53/home) and select
@@ -78,6 +77,30 @@ routing configurations.
You have successfully set up a single host, like `gitlab.example.com`, which
distributes traffic to your Geo sites by geolocation.
+## GCP
+
+In this example, you create a GCP Cloud DNS zone managing your domain.
+
+When creating Geo-Based record sets, GCP applies a nearest match for the source region when the source of the traffic doesn't match any policy items exactly. To create a Geo-Based record set:
+
+1. Select **Network Services** > **Cloud DNS**.
+1. Select the Zone configured for your domain.
+1. Select **Add Record Set**.
+1. Enter the DNS Name for your Location-aware public URL e.g. `gitlab.example.com`.
+1. Select the **Routing Policy**: **Geo-Based**.
+1. Select **Add Managed RRData**.
+ 1. Select **Source Region**: **us-central1**.
+ 1. Enter your `<**primary** IP address>`.
+ 1. Select **Done**.
+1. Select **Add Managed RRData**.
+ 1. Select **Source Region**: **europe-west1**.
+ 1. Enter your `<**secondary** IP address>`.
+ 1. Select **Done**.
+1. Select **Create**.
+
+You have successfully set up a single host, like `gitlab.example.com`, which
+distributes traffic to your Geo sites using a location-aware URL.
+
## Enable Geo proxying for secondary sites
After setting up a single URL to use for all Geo sites, continue with the [steps to enable Geo proxying for secondary sites](index.md).
diff --git a/doc/administration/geo/setup/database.md b/doc/administration/geo/setup/database.md
index 8ea8d6c4d8e..86caf5306b5 100644
--- a/doc/administration/geo/setup/database.md
+++ b/doc/administration/geo/setup/database.md
@@ -478,6 +478,12 @@ data before running `pg_basebackup`.
Each Geo **secondary** site must have its own unique replication slot name.
Using the same slot name between two secondaries breaks PostgreSQL replication.
+ NOTE:
+ Replication slot names must only contain lowercase letters, numbers, and the underscore character.
+
+ When prompted, enter the _plaintext_ password you set up for the `gitlab_replicator`
+ user in the first step.
+
```shell
gitlab-ctl replicate-geo-database \
--slot-name=<secondary_site_name> \
@@ -486,12 +492,6 @@ data before running `pg_basebackup`.
```
NOTE:
- Replication slot names must only contain lowercase letters, numbers, and the underscore character.
-
- When prompted, enter the _plaintext_ password you set up for the `gitlab_replicator`
- user in the first step.
-
- NOTE:
If you have generated custom PostgreSQL certificates, you will want to use
`--sslmode=verify-full` (or omit the `sslmode` line entirely), to benefit from the extra
validation of the full host name in the certificate CN / SAN for additional security.
@@ -619,7 +619,7 @@ If you still haven't [migrated from repmgr to Patroni](#migrating-from-repmgr-to
1. Before migrating, we recommend that there is no replication lag between the **primary** and **secondary** sites and that replication is paused. In GitLab 13.2 and later, you can pause and resume replication with `gitlab-ctl geo-replication-pause` and `gitlab-ctl geo-replication-resume` on a Geo secondary database node.
1. Follow the [instructions to migrate repmgr to Patroni](../../postgresql/replication_and_failover.md#switching-from-repmgr-to-patroni). When configuring Patroni on each **primary** site database node, add `patroni['replication_slots'] = { '<slot_name>' => 'physical' }`
to `gitlab.rb` where `<slot_name>` is the name of the replication slot for your **secondary** site. This ensures that Patroni recognizes the replication slot as permanent and not drop it upon restarting.
-1. If database replication to the **secondary** site was paused before migration, resume replication once Patroni is confirmed working on the **primary** site.
+1. If database replication to the **secondary** site was paused before migration, resume replication after Patroni is confirmed working on the **primary** site.
### Migrating a single PostgreSQL node to Patroni
diff --git a/doc/administration/geo/setup/external_database.md b/doc/administration/geo/setup/external_database.md
index eabed7c10f3..0fefc11f078 100644
--- a/doc/administration/geo/setup/external_database.md
+++ b/doc/administration/geo/setup/external_database.md
@@ -62,7 +62,7 @@ developed and tested. We aim to be compatible with most external
To set up an external database, you can either:
-- Set up [streaming replication](https://www.postgresql.org/docs/12/warm-standby.html#STREAMING-REPLICATION-SLOTS) yourself (for example Amazon RDS, bare metal not managed by Omnibus, and so on).
+- Set up [streaming replication](https://www.postgresql.org/docs/12/warm-standby.html#STREAMING-REPLICATION-SLOTS) yourself (for example Amazon RDS, or bare metal not managed by Omnibus).
- Perform the Omnibus configuration manually as follows.
#### Leverage your cloud provider's tools to replicate the primary database
@@ -78,7 +78,7 @@ cloud providers:
- Azure Database for PostgreSQL - [Create and manage read replicas in Azure Database for PostgreSQL](https://learn.microsoft.com/en-us/azure/postgresql/single-server/how-to-read-replicas-portal)
- Google Cloud SQL - [Creating read replicas](https://cloud.google.com/sql/docs/postgres/replication/create-replica)
-Once your read-only replica is set up, you can skip to [configure your secondary site](#configure-secondary-site-to-use-the-external-read-replica)
+When your read-only replica is set up, you can skip to [configure your secondary site](#configure-secondary-site-to-use-the-external-read-replica)
#### Manually configure the primary database for replication
diff --git a/doc/administration/git_protocol.md b/doc/administration/git_protocol.md
index f900c5a6867..349a92de51e 100644
--- a/doc/administration/git_protocol.md
+++ b/doc/administration/git_protocol.md
@@ -25,7 +25,7 @@ From the server side, if we want to configure SSH we need to set the `sshd`
server to accept the `GIT_PROTOCOL` environment.
In installations using [GitLab Helm Charts](https://docs.gitlab.com/charts/)
-and [All-in-one Docker image](https://docs.gitlab.com/omnibus/docker/), the SSH
+and [All-in-one Docker image](../install/docker.md), the SSH
service is already configured to accept the `GIT_PROTOCOL` environment. Users
need not do anything more.
@@ -36,7 +36,7 @@ the SSH configuration of your server manually by adding this line to the `/etc/s
AcceptEnv GIT_PROTOCOL
```
-Once configured, restart the SSH daemon for the change to take effect:
+When you have configured the SSH daemon, restart it for the change to take effect:
```shell
# CentOS 6 / RHEL 6
diff --git a/doc/administration/gitaly/configure_gitaly.md b/doc/administration/gitaly/configure_gitaly.md
index e4aef2db9a8..e7a6fc35ced 100644
--- a/doc/administration/gitaly/configure_gitaly.md
+++ b/doc/administration/gitaly/configure_gitaly.md
@@ -57,21 +57,6 @@ The process for setting up Gitaly on its own server is:
1. [Configure Gitaly clients](#configure-gitaly-clients).
1. [Disable Gitaly where not required](#disable-gitaly-where-not-required-optional) (optional).
-When running Gitaly on its own server, note the following regarding GitLab versions:
-
-- From GitLab 11.4, Gitaly was able to serve all Git requests without requiring a shared NFS mount
- for Git repository data, except for the
- [Elasticsearch indexer](https://gitlab.com/gitlab-org/gitlab-elasticsearch-indexer).
-- From GitLab 11.8, the Elasticsearch indexer also uses Gitaly for data access. NFS can still be
- leveraged for redundancy on block-level Git data, but should be mounted only on the Gitaly
- servers.
-- From GitLab 11.8 to 12.2, it is possible to use Elasticsearch in a Gitaly setup that doesn't use
- NFS. To use Elasticsearch in these versions, the
- [repository indexer](../../integration/advanced_search/elasticsearch.md#elasticsearch-repository-indexer)
- must be enabled in your GitLab configuration.
-- [In GitLab 12.3 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/6481), the new indexer is
- the default and no configuration is required.
-
### Network architecture
The following list depicts the network architecture of Gitaly:
@@ -1100,8 +1085,8 @@ benefit from it. It is orthogonal to:
- The transport (HTTP or SSH).
- Git protocol version (v0 or v2).
-- The type of fetch (full clones, incremental fetches, shallow clones,
- partial clones, and so on).
+- The type of fetch, such as full clones, incremental fetches, shallow clones,
+ or partial clones.
The strength of this cache is its ability to deduplicate concurrent
identical fetches. It:
@@ -1309,18 +1294,38 @@ 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:
```ruby
+ ignored_blobs = "/etc/gitlab/instance_wide_ignored_git_blobs.txt"
+
gitaly['gitconfig'] = [
+
+ # 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: "receive.fsck.hasDotgit", value: "ignore" },
+ { key: "fsck.missingSpaceBeforeEmail", value: "ignore" },
]
```
- In GitLab 15.2 and earlier (legacy method):
```ruby
- ignored_git_errors = ["hasDotgit = ignore"]
+ ignored_git_errors = [
+ "hasDotgit = ignore",
+ "missingSpaceBeforeEmail = ignore",
+ ]
omnibus_gitconfig['system'] = {
+
+ # Populate a file with one unabbreviated SHA-1 per line.
+ # See https://git-scm.com/docs/git-config#Documentation/git-config.txt-fsckskipList
+ "fsck.skipList" => ignored_blobs
+ "fetch.fsck.skipList" => ignored_blobs,
+ "receive.fsck.skipList" => ignored_blobs,
+
"fsck" => ignored_git_errors,
"fetch.fsck" => ignored_git_errors,
"receive.fsck" => ignored_git_errors,
@@ -1342,6 +1347,30 @@ value = "ignore"
[[git.config]]
key = "receive.fsck.hasDotgit"
value = "ignore"
+
+[[git.config]]
+key = "fsck.missingSpaceBeforeEmail"
+value = "ignore"
+
+[[git.config]]
+key = "fetch.fsck.missingSpaceBeforeEmail"
+value = "ignore"
+
+[[git.config]]
+key = "receive.fsck.missingSpaceBeforeEmail"
+value = "ignore"
+
+[[git.config]]
+key = "fsck.skipList"
+value = "/etc/gitlab/instance_wide_ignored_git_blobs.txt"
+
+[[git.config]]
+key = "fetch.fsck.skipList"
+value = "/etc/gitlab/instance_wide_ignored_git_blobs.txt"
+
+[[git.config]]
+key = "receive.fsck.skipList"
+value = "/etc/gitlab/instance_wide_ignored_git_blobs.txt"
```
## Configure commit signing for GitLab UI commits
diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md
index 96447239116..1b7e1f0f7c6 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -45,7 +45,7 @@ repository storage is either:
## Before deploying Gitaly Cluster
Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management.
-Before deploying Gitaly Cluster, please review:
+Before deploying Gitaly Cluster, review:
- Existing [known issues](#known-issues).
- [Snapshot limitations](#snapshot-backup-and-recovery-limitations).
@@ -66,13 +66,14 @@ Contact your Technical Account Manager or customer support if you have any quest
### Known issues
The following table outlines current known issues impacting the use of Gitaly Cluster. For
-the current status of these issues, please refer to the referenced issues and epics.
+the current status of these issues, refer to the referenced issues and epics.
| Issue | Summary | How to avoid |
|:--------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------|
| Gitaly Cluster + Geo - Issues retrying failed syncs | If Gitaly Cluster is used on a Geo secondary site, repositories that have failed to sync could continue to fail when Geo tries to resync them. Recovering from this state requires assistance from support to run manual steps. | No known solution prior to GitLab 15.0. In GitLab 15.0 to 15.2, enable the [`gitaly_praefect_generated_replica_paths` feature flag](#praefect-generated-replica-paths-gitlab-150-and-later). In GitLab 15.3, the feature flag is enabled by default. |
| Praefect unable to insert data into the database due to migrations not being applied after an upgrade | If the database is not kept up to date with completed migrations, then the Praefect node is unable to perform normal operation. | Make sure the Praefect database is up and running with all migrations completed (For example: `/opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-migrate-status` should show a list of all applied migrations). Consider [requesting upgrade assistance](https://about.gitlab.com/support/scheduling-upgrade-assistance/) so your upgrade plan can be reviewed by support. |
-| Restoring a Gitaly Cluster node from a snapshot in a running cluster | Because the Gitaly Cluster runs with consistent state, introducing a single node that is behind will result in the cluster not being able to reconcile the nodes data and other nodes data | Don't restore a single Gitaly Cluster node from a backup snapshot. If you must restore from backup, it's best to [shut down GitLab](../read_only_gitlab.md#shut-down-the-gitlab-ui), snapshot all Gitaly Cluster nodes at the same time and take a database dump of the Praefect database. |
+| Restoring a Gitaly Cluster node from a snapshot in a running cluster | Because the Gitaly Cluster runs with consistent state, introducing a single node that is behind results in the cluster not being able to reconcile the nodes data and other nodes data | Don't restore a single Gitaly Cluster node from a backup snapshot. If you must restore from backup:<br/><br/>1. [Shut down GitLab](../read_only_gitlab.md#shut-down-the-gitlab-ui).<br/>2. Snapshot all Gitaly Cluster nodes at the same time.<br/>3. Take a database dump of the Praefect database. |
+| Rebuilding or replacing an existing Gitaly Cluster node | There is no way to replace existing nodes in place because the Praefect database is relied on to determine the current state of each Gitaly node. Changing how Gitaly Cluster stores repositories is proposed in issue [4218](https://gitlab.com/gitlab-org/gitaly/-/issues/4218). Turning on [repository verification](praefect.md#repository-verification) is proposed in issue [4429](https://gitlab.com/gitlab-org/gitaly/-/issues/4429) so Praefect can detect that data is missing and needs to replicated to a new Gitaly node. | No known solution at this time. |
### Snapshot backup and recovery limitations
@@ -83,11 +84,11 @@ during a restore, we recommend using the [official backup and restore Rake tasks
The [incremental backup method](../../raketasks/backup_gitlab.md#incremental-repository-backups)
can be used to speed up Gitaly Cluster backups.
-If you are unable to use either method, please contact customer support for restoration help.
+If you are unable to use either method, contact customer support for restoration help.
### What to do if you are on Gitaly Cluster experiencing an issue or limitation
-Please contact customer support for immediate help in restoration or recovery.
+Contact customer support for immediate help in restoration or recovery.
## Directly accessing repositories
@@ -219,8 +220,7 @@ The availability objectives for Gitaly clusters assuming a single node failure a
second. Failover requires ten consecutive failed health checks on each
Praefect node.
- Faster outage detection, to improve this speed to less than 1 second,
- is tracked [in this issue](https://gitlab.com/gitlab-org/gitaly/-/issues/2608).
+Improvements to RPO and RTO are proposed in epic [8903](https://gitlab.com/groups/gitlab-org/-/epics/8903).
WARNING:
If complete cluster failure occurs, disaster recovery plans should be executed. These can affect the
@@ -320,9 +320,7 @@ follow the [hashed storage](../repository_storage_types.md#hashed-storage) schem
> - [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/4218) in GitLab 15.0 [with a flag](../feature_flags.md) named `gitaly_praefect_generated_replica_paths`. Disabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitaly/-/issues/4218) in GitLab 15.2.
> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/4809) in GitLab 15.3.
-
-FLAG:
-On self-managed GitLab, by default this feature is available. To hide the feature, ask an administrator to [disable the feature flag](../feature_flags.md) named `gitaly_praefect_generated_replica_paths`. On GitLab.com, this feature is available but can be configured by GitLab.com administrators only.
+> - [Generally available](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/4941) in GitLab 15.6. Feature flag `gitaly_praefect_generated_replica_paths` removed.
When Gitaly Cluster creates a repository, it assigns the repository a unique and permanent ID called the _repository ID_. The repository ID is
internal to Gitaly Cluster and doesn't relate to any IDs elsewhere in GitLab. If a repository is removed from Gitaly Cluster and later moved
@@ -410,7 +408,7 @@ relative path of the repository in the metadata store.
### Moving beyond NFS
Engineering support for NFS for Git repositories is deprecated. Technical support is planned to be unavailable starting
-November 22, 2022. Please see our [statement of support](https://about.gitlab.com/support/statement-of-support/#gitaly-and-nfs)
+November 22, 2022. See our [statement of support](https://about.gitlab.com/support/statement-of-support/#gitaly-and-nfs)
for more details.
[Network File System (NFS)](https://en.wikipedia.org/wiki/Network_File_System)
@@ -470,12 +468,6 @@ including [horizontally distributing reads](https://gitlab.com/groups/gitlab-org
#### Distributed reads
-> - Introduced in GitLab 13.1 in [beta](../../policy/alpha-beta-support.md#beta-features) with feature flag `gitaly_distributed_reads` set to disabled.
-> - [Made generally available and enabled by default](https://gitlab.com/gitlab-org/gitaly/-/issues/2951) in GitLab 13.3.
-> - [Disabled by default](https://gitlab.com/gitlab-org/gitaly/-/issues/3178) in GitLab 13.5.
-> - [Enabled by default](https://gitlab.com/gitlab-org/gitaly/-/issues/3334) in GitLab 13.8.
-> - [Feature flag removed](https://gitlab.com/gitlab-org/gitaly/-/issues/3383) in GitLab 13.11.
-
Gitaly Cluster supports distribution of read operations across Gitaly nodes that are configured for
the [virtual storage](#virtual-storage).
@@ -496,31 +488,21 @@ You can [monitor distribution of reads](monitoring.md#monitor-gitaly-cluster) us
#### Strong consistency
-> - Introduced in GitLab 13.1 in [alpha](../../policy/alpha-beta-support.md#alpha-features), disabled by default.
-> - Entered [beta](../../policy/alpha-beta-support.md#beta-features) in GitLab 13.2, disabled by default.
-> - In GitLab 13.3, disabled unless primary-wins voting strategy is disabled.
-> - From GitLab 13.4, enabled by default.
-> - From GitLab 13.5, you must use Git v2.28.0 or higher on Gitaly nodes to enable strong consistency.
-> - From GitLab 13.6, primary-wins voting strategy and the `gitaly_reference_transactions_primary_wins` feature flag was removed.
-> - From GitLab 14.0, [Gitaly Cluster only supports strong consistency](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/3575), and the `gitaly_reference_transactions` feature flag was removed.
+> - In GitLab 13.6 to 13.12, strong consistency must be manually configured. Refer to [the 13.12 documentation](https://docs.gitlab.com/13.12/ee/administration/gitaly/praefect.html#strong-consistency).
+> - In GitLab 14.0, strong consistency is the primary replication method.
Gitaly Cluster provides strong consistency by writing changes synchronously to all healthy, up-to-date replicas. If a
replica is outdated or unhealthy at the time of the transaction, the write is asynchronously replicated to it.
+Strong consistency is the primary replication method. A subset of operations still use replication jobs
+(eventual consistency) instead of strong consistency. Refer to the
+[strong consistency epic](https://gitlab.com/groups/gitlab-org/-/epics/1189) for more information.
+
If strong consistency is unavailable, Gitaly Cluster guarantees eventual consistency. In this case. Gitaly Cluster
replicates all writes to secondary Gitaly nodes after the write to the primary Gitaly node has occurred.
-Strong consistency:
-
-- Is the primary replication method in GitLab 14.0 and later. A subset of operations still use replication jobs
- (eventual consistency) instead of strong consistency. Refer to the
- [strong consistency epic](https://gitlab.com/groups/gitlab-org/-/epics/1189) for more information.
-- Must be configured in GitLab versions 13.1 to 13.12. For configuration information, refer to either:
- - Documentation on your GitLab instance at `/help`.
- - The [13.12 documentation](https://docs.gitlab.com/13.12/ee/administration/gitaly/praefect.html#strong-consistency).
-- Is unavailable in GitLab 13.0 and earlier.
-
-For more information on monitoring strong consistency, see the Gitaly Cluster [Prometheus metrics documentation](monitoring.md#monitor-gitaly-cluster).
+For more information on monitoring strong consistency, see the Gitaly Cluster
+[Prometheus metrics documentation](monitoring.md#monitor-gitaly-cluster).
#### Replication factor
@@ -598,7 +580,7 @@ To migrate to Gitaly Cluster:
1. Create the required storage. Refer to
[repository storage recommendations](praefect.md#repository-storage-recommendations).
1. Create and configure [Gitaly Cluster](praefect.md).
-1. Configure the existing Gitaly instance [to use TPC](praefect.md#use-tcp-for-existing-gitlab-instances), if not already configured that way.
+1. Configure the existing Gitaly instance [to use TCP](praefect.md#use-tcp-for-existing-gitlab-instances), if not already configured that way.
1. [Move the repositories](../operations/moving_repositories.md#move-repositories). To migrate to
Gitaly Cluster, existing repositories stored outside Gitaly Cluster must be moved. There is no
automatic migration but the moves can be scheduled with the GitLab API.
@@ -718,4 +700,4 @@ The second facet presents the only real solution. For this, we developed
## NFS deprecation notice
Engineering support for NFS for Git repositories is deprecated. Technical support is planned to be
-unavailable beginning November 22, 2022. For further information, please see our [NFS Deprecation](../nfs.md#gitaly-and-nfs-deprecation) documentation.
+unavailable beginning November 22, 2022. For further information, see our [NFS Deprecation](../nfs.md#gitaly-and-nfs-deprecation) documentation.
diff --git a/doc/administration/gitaly/monitoring.md b/doc/administration/gitaly/monitoring.md
index 9b7acd536b3..8d4f30c7c20 100644
--- a/doc/administration/gitaly/monitoring.md
+++ b/doc/administration/gitaly/monitoring.md
@@ -152,9 +152,6 @@ The following metrics are available from the `/metrics` endpoint:
for replication to complete after the replication job starts. Available in GitLab 12.10 and later.
- `gitaly_praefect_replication_delay_bucket`, a histogram measuring how much time passes between
when the replication job is created and when it starts. Available in GitLab 12.10 and later.
-- `gitaly_praefect_node_latency_bucket`, a histogram measuring the latency in Gitaly returning
- health check information to Praefect. This indicates Praefect connection saturation. Available in
- GitLab 12.10 and later.
- `gitaly_praefect_connections_total`, the total number of connections to Praefect. [Introduced](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/4220) in GitLab 14.7.
To monitor [strong consistency](index.md#strong-consistency), you can use the following Prometheus metrics:
diff --git a/doc/administration/gitaly/praefect.md b/doc/administration/gitaly/praefect.md
index e3b198d1012..8cf32a6aaa3 100644
--- a/doc/administration/gitaly/praefect.md
+++ b/doc/administration/gitaly/praefect.md
@@ -28,6 +28,9 @@ The minimum recommended configuration for a Gitaly Cluster requires:
- 3 Praefect nodes
- 3 Gitaly nodes (1 primary, 2 secondary)
+You should configure an odd number of Gitaly nodes so that transactions have a tie-breaker in case one of the
+Gitaly nodes fails in a mutating RPC call.
+
See the [design document](https://gitlab.com/gitlab-org/gitaly/-/blob/master/doc/design_ha.md)
for implementation details.
@@ -155,6 +158,14 @@ We note in the instructions below where these secrets are required.
NOTE:
Omnibus GitLab installations can use `gitlab-secrets.json` for `GITLAB_SHELL_SECRET_TOKEN`.
+### Customize time server setting
+
+By default, Gitaly and Praefect nodes use the time server at `pool.ntp.org` for time synchronization checks. You can customize this setting by adding the
+following to `gitlab.rb` on each node:
+
+- `gitaly['env'] = { "NTP_HOST" => "ntp.example.com" }`, for Gitaly nodes.
+- `praefect['env'] = { "NTP_HOST" => "ntp.example.com" }`, for Praefect nodes.
+
### PostgreSQL
NOTE:
@@ -285,7 +296,7 @@ praefect['database_direct_dbname'] = 'praefect_production'
#praefect['database_direct_sslrootcert'] = '...'
```
-Once configured, this connection is automatically used for the
+When configured, this connection is automatically used for the
[SQL LISTEN](https://www.postgresql.org/docs/11/sql-listen.html) feature and
allows Praefect to receive notifications from PostgreSQL for cache invalidation.
@@ -584,11 +595,7 @@ Updates to example must be made at:
}
```
- NOTE:
- In [GitLab 13.8 and earlier](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/4988),
- Gitaly nodes were configured directly under the virtual storage, and not under the `nodes` key.
-
-1. [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2013) in GitLab 13.1 and later, enable [distribution of reads](index.md#distributed-reads).
+1. Enable [distribution of reads](index.md#distributed-reads).
1. Save the changes to `/etc/gitlab/gitlab.rb` and
[reconfigure Praefect](../restart_gitlab.md#omnibus-gitlab-reconfigure):
@@ -641,8 +648,6 @@ Updates to example must be made at:
#### Enable TLS support
-> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/1698) in GitLab 13.2.
-
Praefect supports TLS encryption. To communicate with a Praefect instance that listens
for secure connections, you must:
@@ -1369,7 +1374,8 @@ We recommend using [repository-specific primary nodes](#repository-specific-prim
### Repository-specific primary nodes
-> [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/3492) in GitLab 13.12.
+> - [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/3492) in GitLab 13.12, with primary elections run when Praefect starts or the cluster's consensus of a Gitaly node's health changes.
+> - [Changed](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/3543) in GitLab 14.1, primary elections are run lazily.
Gitaly Cluster supports electing repository-specific primary Gitaly nodes. Repository-specific
Gitaly primary nodes are enabled in `/etc/gitlab/gitlab.rb` by setting
@@ -1386,14 +1392,8 @@ The `per_repository` election strategy solves this problem by electing a primary
repository. Combined with [configurable replication factors](#configure-replication-factor), you can
horizontally scale storage capacity and distribute write load across Gitaly nodes.
-Primary elections are run:
-
-- In GitLab 14.1 and later, lazily. This means that Praefect doesn't immediately elect
- a new primary node if the current one is unhealthy. A new primary is elected if it is
- necessary to serve a request while the current primary is unavailable.
-- In GitLab 13.12 to GitLab 14.0 when:
- - Praefect starts up.
- - The cluster's consensus of a Gitaly node's health changes.
+Primary elections are run lazily. Praefect doesn't immediately elect a new primary node if the current
+one is unhealthy. A new primary is elected if a request must be served while the current primary is unavailable.
A valid primary node candidate is a Gitaly node that:
@@ -1422,9 +1422,9 @@ To migrate existing clusters:
1. Praefect nodes didn't historically keep database records of every repository stored on the cluster. When
the `per_repository` election strategy is configured, Praefect expects to have database records of
- each repository. A [background database migration](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/2749) is
- included in GitLab 13.6 and later to create any missing database records for repositories. Before migrating,
- check Praefect's logs to verify that the database migration ran.
+ each repository. A [background database migration](https://gitlab.com/gitlab-org/gitaly/-/merge_requests/2749)
+ creates any missing database records for repositories. Before migrating, check Praefect's logs to verify
+ that the database migration ran.
Check Praefect's logs for `repository importer finished` message. The `virtual_storages` field contains
the names of virtual storages and whether they've had any missing database records created.
diff --git a/doc/administration/gitaly/recovery.md b/doc/administration/gitaly/recovery.md
index b51454aa44e..56894f3e963 100644
--- a/doc/administration/gitaly/recovery.md
+++ b/doc/administration/gitaly/recovery.md
@@ -11,40 +11,15 @@ recovery and has Praefect tracking database tools.
## Primary node failure
-Gitaly Cluster recovers from a failing primary Gitaly node by promoting a healthy secondary as the
-new primary.
+> - Introduced in GitLab 13.0, Gitaly Cluster, elects the secondary with the least unreplicated writes from the primary to be the new primary. There can still be some unreplicated writes, so [data loss can occur](#check-for-data-loss).
+> - Primary node failure recovery support added in GitLab 14.1.
-In GitLab 14.1 and later, Gitaly Cluster:
+Gitaly Cluster recovers from a failing primary Gitaly node by promoting a healthy secondary as the new primary. Gitaly
+Cluster:
- Elects a healthy secondary with a fully up to date copy of the repository as the new primary.
- Repository becomes unavailable if there are no fully up to date copies of it on healthy secondaries.
-To minimize data loss in GitLab 13.0 to 14.0, Gitaly Cluster:
-
-- Switches repositories that are outdated on the new primary to [read-only mode](#read-only-mode).
-- Elects the secondary with the least unreplicated writes from the primary to be the new
- primary. Because there can still be some unreplicated writes,
- [data loss can occur](#check-for-data-loss).
-
-### Read-only mode
-
-> - Introduced in GitLab 13.0 as [generally available](../../policy/alpha-beta-support.md#generally-available-ga).
-> - Between GitLab 13.0 and GitLab 13.2, read-only mode applied to the whole virtual storage and occurred whenever failover occurred.
-> - [In GitLab 13.3 and later](https://gitlab.com/gitlab-org/gitaly/-/issues/2862), read-only mode applies on a per-repository basis and only occurs if a new primary is out of date. If the failed primary contained unreplicated writes, [data loss can occur](#check-for-data-loss).
-> - Removed in GitLab 14.1. Instead, repositories [become unavailable](#unavailable-repositories).
-
-When Gitaly Cluster switches to a new primary in GitLab 13.0 to 14.0, repositories enter read-only mode if they are
-out-of-date. This can happen after failing over to an outdated secondary. Read-only mode eases data recovery efforts by
-preventing writes that may conflict with the unreplicated writes on other nodes.
-
-To enable writes again in GitLab 13.0 to 14.0, an administrator can:
-
-1. [Check](#check-for-data-loss) for data loss.
-1. Attempt to [recover](#data-recovery) missing data.
-1. Either [enable writes](#enable-writes-or-accept-data-loss) in the virtual storage or
- [accept data loss](#enable-writes-or-accept-data-loss) if necessary, depending on the version of
- GitLab.
-
### 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.
@@ -144,9 +119,7 @@ Virtual storage: default
#### Unavailable replicas of available repositories
-NOTE:
-In GitLab 14.0 and earlier, the flag is `-partially-replicated` and the output shows any repositories with assigned nodes with outdated
-copies.
+> Introduced in GitLab 14.0, flag renamed from `-partially-replicated` and behavior changed.
To also list information of repositories which are available but are unavailable from some of the assigned nodes,
use the `-partially-unavailable` flag.
@@ -209,26 +182,17 @@ WARNING:
`accept-dataloss` causes permanent data loss by overwriting other versions of the repository.
Data [recovery efforts](#data-recovery) must be performed before using it.
-Praefect provides the following subcommands to re-enable writes or accept data loss:
-
-- In GitLab 13.2 and earlier, `enable-writes` to re-enable virtual storage for writes after
- data recovery attempts:
+Praefect provides the following subcommands to re-enable writes or accept data loss. If it is not possible to bring one
+of the up-to-date nodes back online, you might have to accept data loss:
- ```shell
- sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml enable-writes -virtual-storage <virtual-storage>
- ```
-
-- In GitLab 13.3 and later, if it is not possible to bring one of the up to date nodes back
- online, you may have to accept data loss:
-
- ```shell
- sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml accept-dataloss -virtual-storage <virtual-storage> -repository <relative-path> -authoritative-storage <storage-name>
- ```
+```shell
+sudo /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml accept-dataloss -virtual-storage <virtual-storage> -repository <relative-path> -authoritative-storage <storage-name>
+```
- When accepting data loss, Praefect:
+When accepting data loss, Praefect:
- 1. Marks the chosen copy of the repository as the latest version.
- 1. Replicates the copy to the other assigned Gitaly nodes.
+1. Marks the chosen copy of the repository as the latest version.
+1. Replicates the copy to the other assigned Gitaly nodes.
This process overwrites any other copy of the repository so care must be taken.
diff --git a/doc/administration/gitaly/reference.md b/doc/administration/gitaly/reference.md
index 3bf1e3136c0..8f7dc688e56 100644
--- a/doc/administration/gitaly/reference.md
+++ b/doc/administration/gitaly/reference.md
@@ -192,8 +192,7 @@ For historical reasons
[GitLab Shell](https://gitlab.com/gitlab-org/gitlab-shell) contains
the Git hooks that allow GitLab to validate and react to Git pushes.
Because Gitaly "owns" Git pushes, GitLab Shell must therefore be
-installed alongside Gitaly. We plan to
-[simplify this](https://gitlab.com/gitlab-org/gitaly/-/issues/1226).
+installed alongside Gitaly.
| Name | Type | Required | Description |
| ---- | ---- | -------- | ----------- |
diff --git a/doc/administration/gitaly/troubleshooting.md b/doc/administration/gitaly/troubleshooting.md
index 1c5f0d43864..7edce840396 100644
--- a/doc/administration/gitaly/troubleshooting.md
+++ b/doc/administration/gitaly/troubleshooting.md
@@ -41,17 +41,6 @@ The `gitaly-debug` command provides "production debugging" tools for Gitaly and
performance. It is intended to help production engineers and support
engineers investigate Gitaly performance problems.
-If you're using GitLab 11.6 or newer, this tool should be installed on
-your GitLab or Gitaly server already at `/opt/gitlab/embedded/bin/gitaly-debug`.
-If you're investigating an older GitLab version you can compile this
-tool offline and copy the executable to your server:
-
-```shell
-git clone https://gitlab.com/gitlab-org/gitaly.git
-cd cmd/gitaly-debug
-GOOS=linux GOARCH=amd64 go build -o gitaly-debug
-```
-
To see the help page of `gitaly-debug` for a list of supported sub-commands, run:
```shell
@@ -144,9 +133,8 @@ If you have Prometheus set up to scrape your Gitaly process, you can see
request rates and error codes for individual RPCs in `gitaly-ruby` by
querying `grpc_client_handled_total`.
-- In theory, this metric does not differentiate between `gitaly-ruby` and other RPCs.
-- In practice from GitLab 11.9, all gRPC calls made by Gitaly itself are internal calls from the
- main Gitaly process to one of its `gitaly-ruby` sidecars.
+All gRPC calls made by `gitaly-ruby` itself are internal calls from the main Gitaly process to one of its `gitaly-ruby`
+sidecars.
Assuming your `grpc_client_handled_total` counter only observes Gitaly,
the following query shows you RPCs are (most likely) internally
@@ -335,7 +323,7 @@ You might see the following in Gitaly and Praefect logs:
}
```
-This is a GRPC call
+This is a gRPC call
[error response code](https://grpc.github.io/grpc/core/md_doc_statuscodes.html).
If this error occurs, even though
@@ -359,7 +347,7 @@ necessary because [this issue](https://gitlab.com/gitlab-org/gitaly/-/issues/252
If this error occurs even though file permissions are correct, it's likely that the Gitaly node is
experiencing [clock drift](https://en.wikipedia.org/wiki/Clock_drift).
-Please ensure that the GitLab and Gitaly nodes are synchronized and use an NTP time
+Ensure that the GitLab and Gitaly nodes are synchronized and use an NTP time
server to keep them synchronized if possible.
### Health check warnings
@@ -604,6 +592,16 @@ For each replica, the following metadata is available:
| `Valid Primary` | Indicates whether the replica is fit to serve as the primary node. If the repository's primary is not a valid primary, a failover occurs on the next write to the repository if there is another replica that is a valid primary. A replica is a valid primary if:<br><br>- It is stored on a healthy Gitaly node.<br>- It is fully up to date.<br>- It is not targeted by a pending deletion job from decreasing replication factor.<br>- It is assigned. |
| `Verified At` | Indicates last successful verification of the replica by the [verification worker](praefect.md#repository-verification). If the replica has not yet been verified, `unverified` is displayed in place of the last successful verification time. Introduced in GitLab 15.0. |
+#### Command fails with 'repository not found'
+
+If the supplied value for `-virtual-storage` is incorrect, the command returns the following error:
+
+```plaintext
+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`.
+
### Check that repositories are in sync
Is [some cases](index.md#known-issues) the Praefect database can get out of sync with the underlying Gitaly nodes. To check that
diff --git a/doc/administration/housekeeping.md b/doc/administration/housekeeping.md
index 15287b917e7..2d3e937e047 100644
--- a/doc/administration/housekeeping.md
+++ b/doc/administration/housekeeping.md
@@ -1,43 +1,144 @@
---
stage: Systems
-group: Distribution
+group: Gitaly
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Housekeeping **(FREE SELF)**
-GitLab supports and automates housekeeping tasks in your current repository such as:
+GitLab supports and automates housekeeping tasks in Git repositories to ensure
+that they can be served as efficiently as possible. Housekeeping tasks include:
-- Compressing Git objects.
+- Compressing Git objects and revisions.
- Removing unreachable objects.
+- Removing stale data like lock files.
+- Maintaining data structures that improve performance.
+- Updating object pools to improve object deduplication across forks.
-## Configure housekeeping
+WARNING:
+Do not manually execute Git commands to perform housekeeping in Git
+repositories that are controlled by GitLab. Doing so may lead to corrupt
+repositories and data loss.
+
+## Housekeeping strategy
+
+Gitaly can perform housekeeping tasks in a Git repository in two ways:
+
+- [Eager housekeeping](#eager-housekeeping) executes specific housekeeping tasks
+ independent of the state a repository is in.
+- [Heuristical housekeeping](#heuristical-housekeeping) executes housekeeping
+ tasks based on a set of heuristics that determine what housekeeping tasks need
+ to be executed based on the repository state.
+
+### Eager housekeeping
+
+The "eager" housekeeping strategy executes housekeeping tasks in a repository
+independent of the repository state. This is the default strategy as used by the
+[manual trigger](#manual-trigger) and the [push-based trigger](#push-based-trigger).
+
+The eager housekeeping strategy is controlled by the GitLab application.
+Depending on the trigger that caused the housekeeping job to run, GitLab asks
+Gitaly to perform specific housekeeping tasks. Gitaly performs these tasks even
+if the repository is in an optimized state. As a result, this strategy can be
+inefficient in large repositories where performing the housekeeping tasks may
+be slow.
+
+### Heuristical housekeeping
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitaly/-/issues/2634) in GitLab 14.9 for the [manual trigger](#manual-trigger) and the [push-based trigger](#push-based-trigger) [with a flag](feature_flags.md) named `optimized_housekeeping`. Disabled by default.
+> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/353607) in GitLab 14.10.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available for the [manual trigger](#manual-trigger) and the [push-based trigger](#push-based-trigger).
+To make it available, ask an administrator to [enable the feature flag](feature_flags.md) named `optimized_housekeeping`.
+
+The heuristical (or "opportunistic") housekeeping strategy analyzes the
+repository's state and executes housekeeping tasks only when it finds one or
+more data structures are insufficiently optimized. This is the strategy used by
+[scheduled housekeeping](#scheduled-housekeeping). It can optionally be enabled
+for the [manual trigger](#manual-trigger) and the [push-based trigger](#push-based-trigger)
+by enabling the `optimized_housekeeping` feature flag.
+
+Heuristical housekeeping uses the following information to decide on the tasks
+it needs to run:
+
+- The number of loose and stale objects.
+- The number of packfiles that contain already-compressed objects.
+- The number of loose references.
+- The presence of a commit-graph.
+
+The decision whether any of the analyzed data structures need to be optimized is
+based on the size of the repository:
+
+- Objects are repacked frequently the bigger the total size of all objects.
+- References are repacked less frequently the more references there are in
+ total.
+
+Gitaly does this to offset the fact that optimizing those data structures takes
+more time the bigger they get. It is especially important in large
+monorepositories (which receive a lot of traffic) to avoid optimizing them too
+frequently.
+
+## Running housekeeping tasks
+
+There are different ways in which GitLab runs housekeeping tasks:
-GitLab automatically runs `git gc` and `git repack` on repositories after Git pushes:
+- A project's administrator can [manually trigger](#manual-trigger) repository
+ housekeeping tasks.
+- GitLab can automatically schedule housekeeping tasks [after a number of Git pushes](#push-based-trigger).
+- GitLab can [schedule a job](#scheduled-housekeeping) that runs housekeeping
+ tasks for all repositories in a configurable time frame.
+
+### Manual trigger
+
+Administrators of repositories can manually trigger housekeeping tasks in a
+repository. In general this is not required as GitLab knows to automatically run
+housekeeping tasks. The manual trigger can be useful when either:
+
+- A repository is known to require housekeeping.
+- Automated push-based scheduling of housekeeping tasks has been disabled.
+
+To trigger housekeeping tasks manually:
+
+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. Select **Run housekeeping**.
+
+This starts an asynchronous background worker for the project's repository. The
+background worker executes `git gc`, which performs a number of optimizations.
+
+### Push-based trigger
+
+GitLab automatically runs repository housekeeping tasks after a configured
+number of pushes:
- [`git gc`](https://git-scm.com/docs/git-gc) runs a number of housekeeping tasks such as:
- Compressing Git objects to reduce disk space and increase performance.
- Removing unreachable objects that may have been created from changes to the repository, like force-overwriting branches.
- [`git repack`](https://git-scm.com/docs/git-repack) either:
- - Runs an incremental repack, according to a [configured period](#housekeeping-options). This
+ - Runs an incremental repack, according to a [configured period](#configure-push-based-maintenance). This
packs all loose objects into a new packfile and prunes the now-redundant loose objects.
- - Runs a full repack, according to a [configured period](#housekeeping-options). This repacks all
+ - Runs a full repack, according to a [configured period](#configure-push-based-maintenance). This repacks all
packfiles and loose objects into a single new packfile, and deletes the old now-redundant loose
objects and packfiles. It also optionally creates bitmaps for the new packfile.
+- [`git pack-refs`](https://git-scm.com/docs/git-pack-refs) compresses references
+ stored as loose files into a single file.
+
+#### Configure push-based maintenance
-You can change how often this happens or turn it off:
+You can change how often these tasks run when pushes occur, or you can turn
+them off entirely:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > Repository**.
1. Expand **Repository maintenance**.
-1. In the **Housekeeping** section, configure the [housekeeping options](#housekeeping-options).
+1. In the **Housekeeping** section, configure the housekeeping options.
1. Select **Save changes**.
-### Housekeeping options
-
The following housekeeping options are available:
-- **Enable automatic repository housekeeping**: Regularly run `git repack` and `git gc`. If you
+- **Enable automatic repository housekeeping**: Regularly run housekeeping tasks. If you
keep this setting disabled for a long time, Git repository access on your GitLab server becomes
slower and your repositories use more disk space.
- **Incremental repack period**: Number of Git pushes after which an incremental `git repack` is
@@ -60,30 +161,80 @@ Housekeeping also [removes unreferenced LFS files](../raketasks/cleanup.md#remov
from your project on the same schedule as the `git gc` operation, freeing up storage space for your
project.
-WARNING:
-Running `git gc` or `git repack` commands manually in the
-[repository folder](repository_storage_types.md#from-project-name-to-hashed-path)
-is discouraged. If the created pack files get incorrect access rights (that is, owned by the wrong user)
-browsing to the project page might result in `404` and `503` errors.
-
-## How housekeeping handles pool repositories
-
-Housekeeping for pool repositories is handled differently from standard repositories. It is
-ultimately performed by the Gitaly RPC `FetchIntoObjectPool`.
-
-This is the current call stack by which it is invoked:
-
-1. `Repositories::HousekeepingService#execute_gitlab_shell_gc`
-1. `Projects::GitGarbageCollectWorker#perform`
-1. `Projects::GitDeduplicationService#fetch_from_source`
-1. `ObjectPool#fetch`
-1. `ObjectPoolService#fetch`
-1. `Gitaly::FetchIntoObjectPoolRequest`
-
-To manually invoke it from a [Rails console](operations/rails_console.md) if needed, you can call
-`project.pool_repository.object_pool.fetch`. This is a potentially long-running task, though Gitaly
-times out in about 8 hours.
-
-WARNING:
-Do not run `git prune` or `git gc` in pool repositories! This can cause data loss in "real"
-repositories that depend on the pool in question.
+### Scheduled housekeeping
+
+While GitLab automatically performs housekeeping tasks based on the number of
+pushes, it does not maintain repositories that don't receive any pushes at all.
+As a result, inactive repositories or repositories that are only getting read
+requests may not benefit from improvements in the repository housekeeping
+strategy.
+
+Administrators can enable a background job that performs housekeeping in all
+repositories at a customizable interval to remedy this situation. This
+background job processes all repositories hosted by a Gitaly node in a random
+order and eagerly performs housekeeping tasks on them. The Gitaly node will stop
+processing repositories if it takes longer than the configured interval.
+
+#### Configure scheduled housekeeping
+
+Background maintenance of Git repositories is configured in Gitaly. By default,
+Gitaly performs background repository maintenance every day at 12:00 noon for a
+duration of 10 minutes.
+
+You can change this default in Gitaly configuration. The following snippet
+enables daily background repository maintenance starting at 23:00 for 1 hour
+for the `default` storage:
+
+```toml
+[daily_maintenance]
+start_hour = 23
+start_minute = 00
+duration = 1h
+storages = ["default"]
+```
+
+Use the following snippet to completely disable background repository
+maintenance:
+
+```toml
+[daily_maintenance]
+disabled = true
+```
+
+## Object pool repositories
+
+Object pool repositories are used by GitLab to deduplicate objects across forks
+of a repository. When creating the first fork, we:
+
+1. Create an object pool repository that contains all objects of the repository
+ that is about to be forked.
+1. Link the repository to this new object pool via Git's altenates mechanism.
+1. Repack the repository so that it uses objects from the object pool. It thus
+ can drop its own copy of the objects.
+
+Any forks of this repository can now link against the object pool and thus only
+have to keep objects that diverge from the primary repository.
+
+GitLab needs to perform special housekeeping operations in object pools:
+
+- Gitaly cannot ever delete unreachable objects from object pools because they
+ might be used by any of the forks that are connected to it.
+- Gitaly must keep all objects reachable due to the same reason. Object pools
+ thus maintain references to unreachable "dangling" objects so that they don't
+ ever get deleted.
+- GitLab must update object pools regularly to pull in new objects that have
+ been added in the primary repository. Otherwise, an object pool will become
+ increasingly inefficient at deduplicating objects.
+
+These housekeeping operations are performed by the specialized
+`FetchIntoObjectPool` RPC that handles all of these special tasks while also
+executing the regular housekeeping tasks we execute for normal Git
+repositories.
+
+Object pools are getting optimized automatically whenever the primary member is
+getting garbage collected. Therefore, the cadence can be configured using the
+same Git GC period in that project.
+
+If you need to manually invoke the RPC from a [Rails console](operations/rails_console.md),
+you can call `project.pool_repository.object_pool.fetch`. This is a potentially
+long-running task, though Gitaly times out after about 8 hours.
diff --git a/doc/administration/incoming_email.md b/doc/administration/incoming_email.md
index 4959bacaaa4..433956bb066 100644
--- a/doc/administration/incoming_email.md
+++ b/doc/administration/incoming_email.md
@@ -41,7 +41,7 @@ in the mailbox for `user@example.com` . It is supported by providers such as
Gmail, Google Apps, Yahoo! Mail, Outlook.com, and iCloud, as well as the
[Postfix mail server](reply_by_email_postfix_setup.md), which you can run on-premises.
Microsoft Exchange Server [does not support sub-addressing](#microsoft-exchange-server),
-and Microsoft Office 365 [does not support sub-addressing by default](#microsoft-office-365)
+and Microsoft Office 365 [does not support sub-addressing by default](#microsoft-office-365).
NOTE:
If your provider or server supports email sub-addressing, we recommend using it.
diff --git a/doc/administration/index.md b/doc/administration/index.md
index 7d684daf5a6..95db2b7a2e0 100644
--- a/doc/administration/index.md
+++ b/doc/administration/index.md
@@ -185,7 +185,7 @@ Learn how to install, configure, update, and maintain your GitLab instance.
## Git configuration options
-- [Server hooks](server_hooks.md): Server hooks (on the file system) for when webhooks aren't enough.
+- [Git server hooks](server_hooks.md): Git server hooks (on the file system) for when webhooks aren't enough. Previously called server hooks.
- [Git LFS configuration](lfs/index.md): Learn how to configure LFS for GitLab.
- [Housekeeping](housekeeping.md): Keep your Git repositories tidy and fast.
- [Configuring Git Protocol v2](git_protocol.md): Git protocol version 2 support.
@@ -232,12 +232,9 @@ who are aware of the risks.
- [Troubleshooting Kubernetes](https://docs.gitlab.com/charts/troubleshooting/kubernetes_cheat_sheet.html)
- [Troubleshooting PostgreSQL](troubleshooting/postgresql.md)
- [Guide to test environments](troubleshooting/test_environments.md) (for Support Engineers)
-- [GitLab Rails console commands](troubleshooting/gitlab_rails_cheat_sheet.md) (for Support Engineers)
- [Troubleshooting SSL](troubleshooting/ssl.md)
- Related links:
- [GitLab Developer Documentation](../development/index.md)
- [Repairing and recovering broken Git repositories](https://git.seveas.net/repairing-and-recovering-broken-git-repositories.html)
- [Testing with OpenSSL](https://www.feistyduck.com/library/openssl-cookbook/online/testing-with-openssl/index.html)
- [`strace` zine](https://wizardzines.com/zines/strace/)
-- GitLab.com-specific resources:
- - [Example group SAML and SCIM configurations](../user/group/saml_sso/example_saml_config.md)
diff --git a/doc/administration/instance_limits.md b/doc/administration/instance_limits.md
index 3f44b53a6d5..546c4667220 100644
--- a/doc/administration/instance_limits.md
+++ b/doc/administration/instance_limits.md
@@ -212,12 +212,20 @@ It's possible that this limit changes to a lower number in the future.
## Size of commit titles and descriptions
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/292039) in GitLab 13.9
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/292039) in GitLab 13.9.
-Commits with arbitrarily large messages may be pushed to GitLab, but when
-displaying commits, titles (the first line of the commit message)
-limits to 1KiB, and descriptions (the rest of the message) limits to
-1MiB.
+Commits with arbitrarily large messages may be pushed to GitLab, but the following
+display limits apply:
+
+- **Title** - The first line of the commit message. Limited to 1 KiB.
+- **Description** - The rest of the commit message. Limited to 1 MiB.
+
+When a commit is pushed, GitLab processes the title and description to replace
+references to issues (`#123`) and merge requests (`!123`) with links to the
+issues and merge requests.
+
+When a branch with a large number of commits is pushed, only the last 100 commits
+are processed.
## Number of issues in the milestone overview
@@ -359,7 +367,7 @@ header. Such emails don't create comments on issues or merge requests.
## Amount of data sent from Sentry through Error Tracking
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/14926) in GitLab 12.6.
+> [Limiting all Sentry responses](https://gitlab.com/gitlab-org/gitlab/-/issues/356448) introduced in GitLab 15.6.
Sentry payloads sent to GitLab have a 1 MB maximum limit, both for security reasons
and to limit memory consumption.
diff --git a/doc/administration/integration/kroki.md b/doc/administration/integration/kroki.md
index aa029be90e7..491eeb002e4 100644
--- a/doc/administration/integration/kroki.md
+++ b/doc/administration/integration/kroki.md
@@ -34,7 +34,7 @@ The [`yuzutech/kroki`](https://hub.docker.com/r/yuzutech/kroki) image contains t
<!-- vale gitlab.Spelling = NO -->
- [Bytefield](https://bytefield-svg.deepsymmetry.org/)
-- [Ditaa](http://ditaa.sourceforge.net)
+- [Ditaa](https://ditaa.sourceforge.net)
- [Erd](https://github.com/BurntSushi/erd)
- [GraphViz](https://www.graphviz.org/)
- [Nomnoml](https://github.com/skanaar/nomnoml)
diff --git a/doc/administration/integration/mailgun.md b/doc/administration/integration/mailgun.md
index baf9e8c8a3b..d78cd9e1796 100644
--- a/doc/administration/integration/mailgun.md
+++ b/doc/administration/integration/mailgun.md
@@ -48,5 +48,5 @@ you're ready to enable the Mailgun integration:
1. Select the **Enable Mailgun** checkbox.
1. Enter the Mailgun HTTP webhook signing key as described in
[the Mailgun documentation](https://documentation.mailgun.com/en/latest/user_manual.html#webhooks-1) and
- shown in the [API security](https://app.mailgun.com/app/account/security/api_keys) section for your Mailgun account.
+ shown in the API security (`https://app.mailgun.com/app/account/security/api_keys`) section for your Mailgun account.
1. Select **Save changes**.
diff --git a/doc/administration/issue_closing_pattern.md b/doc/administration/issue_closing_pattern.md
index d10f5320109..e9150ae0650 100644
--- a/doc/administration/issue_closing_pattern.md
+++ b/doc/administration/issue_closing_pattern.md
@@ -17,7 +17,7 @@ in the project's default branch.
## Change the issue closing pattern
-In order to change the pattern you need to have access to the server that GitLab
+To change the pattern, you must have access to the server that GitLab
is installed on.
The default pattern can be located in [`gitlab.yml.example`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/gitlab.yml.example)
diff --git a/doc/administration/job_artifacts.md b/doc/administration/job_artifacts.md
index 1e9f20ded55..d79f322c3f5 100644
--- a/doc/administration/job_artifacts.md
+++ b/doc/administration/job_artifacts.md
@@ -200,7 +200,8 @@ sudo -u git -H bundle exec rake gitlab:artifacts:migrate RAILS_ENV=production
You can optionally track progress and verify that all job artifacts migrated successfully using the
[PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database):
-- `sudo gitlab-rails dbconsole` for Omnibus GitLab instances.
+- `sudo gitlab-rails dbconsole` for Omnibus GitLab 14.1 and earlier.
+- `sudo gitlab-rails dbconsole --database main` for Omnibus GitLab 14.2 and later.
- `sudo -u git -H psql -d gitlabhq_production` for source-installed instances.
Verify `objectstg` below (where `store=2`) has count of all job artifacts:
@@ -301,7 +302,7 @@ I/O. It instead inspects the metadata file which contains all the relevant
information. This is especially important when there is a lot of artifacts, or
an archive is a very large file.
-When clicking on a specific file, [GitLab Workhorse](https://gitlab.com/gitlab-org/gitlab-workhorse) extracts it
+When selecting a specific file, [GitLab Workhorse](https://gitlab.com/gitlab-org/gitlab-workhorse) extracts it
from the archive and the download begins. This implementation saves space,
memory and disk I/O.
@@ -315,12 +316,132 @@ reasons are:
- Users have configured job artifacts expiration to be longer than necessary.
- The number of jobs run, and hence artifacts generated, is higher than expected.
- Job logs are larger than expected, and have accumulated over time.
+- The file system might run out of inodes because
+ [empty directories are left behind by artifact housekeeping](https://gitlab.com/gitlab-org/gitlab/-/issues/17465).
+ [The Rake task for _orphaned_ artifact files](../raketasks/cleanup.md#remove-orphan-artifact-files)
+ removes these.
+- Artifact files might be left on disk and not deleted by housekeeping. Run the
+ [Rake task for _orphaned_ artifact files](../raketasks/cleanup.md#remove-orphan-artifact-files)
+ to remove these. This script should always find work to do, as it also removes empty directories (see above).
+- [Artifact housekeeping was changed significantly](#artifacts-housekeeping-disabled-in-gitlab-146-to-152),
+ and you might need to enable a feature flag to used the updated system.
In these and other cases, identify the projects most responsible
for disk space usage, figure out what types of artifacts are using the most
space, and in some cases, manually delete job artifacts to reclaim disk space.
-One possible first step is to [clean up _orphaned_ artifact files](../raketasks/cleanup.md#remove-orphan-artifact-files).
+#### Artifacts housekeeping disabled in GitLab 14.6 to 15.2
+
+Artifact housekeeping was significantly changed in GitLab 14.10, and the changes
+were back ported to GitLab 14.6 and later. The updated housekeeping must be
+enabled with feature flags [until GitLab 15.3](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92931).
+
+To check if the feature flags are enabled:
+
+1. Start a [Rails console](operations/rails_console.md#starting-a-rails-console-session).
+
+1. Check if the feature flags are enabled.
+
+ - GitLab 14.10 and earlier:
+
+ ```ruby
+ Feature.enabled?(:ci_detect_wrongly_expired_artifacts, default_enabled: :yaml)
+ Feature.enabled?(:ci_update_unlocked_job_artifacts, default_enabled: :yaml)
+ Feature.enabled?(:ci_destroy_unlocked_job_artifacts, default_enabled: :yaml)
+ ```
+
+ - GitLab 15.00 and later:
+
+ ```ruby
+ Feature.enabled?(:ci_detect_wrongly_expired_artifacts)
+ Feature.enabled?(:ci_update_unlocked_job_artifacts)
+ Feature.enabled?(:ci_destroy_unlocked_job_artifacts)
+ ```
+
+1. If any of the feature flags are disabled, enable them:
+
+ ```ruby
+ Feature.enable(:ci_detect_wrongly_expired_artifacts)
+ Feature.enable(:ci_update_unlocked_job_artifacts)
+ Feature.enable(:ci_destroy_unlocked_job_artifacts)
+ ```
+
+These changes include switching artifacts from `unlocked` to `locked` if
+they [should be retained](../ci/pipelines/job_artifacts.md#keep-artifacts-from-most-recent-successful-jobs).
+
+Artifacts created before this feature was introduced have a status of `unknown`. After they expire,
+these artifacts are not processed by the new housekeeping jobs.
+
+You can check the database to confirm if your instance has artifacts with the `unknown` status:
+
+1. Start a database console, on Omnibus:
+
+ ```shell
+ sudo gitlab-psql
+ ```
+
+1. Run this query:
+
+ ```sql
+ select expire_at, file_type, locked, count(*) from ci_job_artifacts
+ where expire_at is not null and
+ file_type != 3
+ group by expire_at, file_type, locked having count(*) > 1;
+ ```
+
+If records are returned, then there are artifacts which the housekeeping job
+is unable to process. For example:
+
+```plaintext
+ expire_at | file_type | locked | count
+-------------------------------+-----------+--------+--------
+ 2021-06-21 22:00:00+00 | 1 | 2 | 73614
+ 2021-06-21 22:00:00+00 | 2 | 2 | 73614
+ 2021-06-21 22:00:00+00 | 4 | 2 | 3522
+ 2021-06-21 22:00:00+00 | 9 | 2 | 32
+ 2021-06-21 22:00:00+00 | 12 | 2 | 163
+```
+
+Artifacts with locked status `2` are `unknown`. Check
+[issue #346261](https://gitlab.com/gitlab-org/gitlab/-/issues/346261#note_1028871458)
+for more details.
+
+The Sidekiq worker that processes all `unknown` artifacts is enabled by default in
+GitLab 15.3 and later. It analyzes the artifacts returned by the above database query and
+determines which should be `locked` or `unlocked`. Artifacts are then deleted
+by that worker if needed.
+
+The worker can be enabled on self-managed instances running GitLab 14.10 and later:
+
+1. Start a [Rails console](operations/rails_console.md#starting-a-rails-console-session).
+
+1. Check if the feature is enabled.
+
+ - GitLab 14.10:
+
+ ```ruby
+ Feature.enabled?(:ci_job_artifacts_backlog_work, default_enabled: :yaml)
+ ```
+
+ - GitLab 15.0 and later:
+
+ ```ruby
+ Feature.enabled?(:ci_job_artifacts_backlog_work)
+ ```
+
+1. Enable the feature, if needed:
+
+ ```ruby
+ Feature.enable(:ci_job_artifacts_backlog_work)
+ ```
+
+The worker processes 10,000 `unknown` artifacts every seven minutes, or roughly two million
+in 24 hours.
+
+There is a related `ci_job_artifacts_backlog_large_loop_limit` feature flag
+which causes the worker to process `unknown` artifacts
+[in batches that are five times larger](https://gitlab.com/gitlab-org/gitlab/-/issues/356319).
+This flag is not recommended for use on self-managed instances.
#### List projects and builds with artifacts with a specific expiration (or no expiration)
diff --git a/doc/administration/lfs/index.md b/doc/administration/lfs/index.md
index 1b01c665ab8..8fdc98bd12a 100644
--- a/doc/administration/lfs/index.md
+++ b/doc/administration/lfs/index.md
@@ -174,10 +174,11 @@ For installations from source:
RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:lfs:migrate
```
-You can optionally track progress and verify that all packages migrated successfully using the
+You can optionally track progress and verify that all LFS objects migrated successfully using the
[PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database):
-- `sudo gitlab-rails dbconsole` for Omnibus GitLab instances.
+- `sudo gitlab-rails dbconsole` for Omnibus GitLab 14.1 and earlier.
+- `sudo gitlab-rails dbconsole --database main` for Omnibus GitLab 14.2 and later.
- `sudo -u git -H psql -d gitlabhq_production` for source-installed instances.
Verify `objectstg` below (where `store=2`) has count of all LFS objects:
diff --git a/doc/administration/libravatar.md b/doc/administration/libravatar.md
index 5b2334bff8a..802a3be46fa 100644
--- a/doc/administration/libravatar.md
+++ b/doc/administration/libravatar.md
@@ -134,6 +134,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/administration/logs.md b/doc/administration/logs.md
deleted file mode 100644
index 7264cf6db98..00000000000
--- a/doc/administration/logs.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: 'logs/index.md'
-remove_date: '2022-10-23'
----
-
-This document was moved to [another location](logs/index.md).
-
-<!-- This redirect file can be deleted after <2022-10-23>. -->
-<!-- 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/logs/index.md b/doc/administration/logs/index.md
index 2bcda759442..b0631c52a47 100644
--- a/doc/administration/logs/index.md
+++ b/doc/administration/logs/index.md
@@ -340,6 +340,12 @@ associated SSH key can download the project in question by using a `git fetch` o
- `params`: Key-value pairs passed in a query string or HTTP body (sensitive parameters, such as passwords and tokens, are filtered out)
- `ua`: The User-Agent of the requester
+NOTE:
+As of [`Grape Logging`](https://github.com/aserafin/grape_logging) v1.8.4,
+the `view_duration_s` is calculated by [`duration_s - db_duration_s`](https://github.com/aserafin/grape_logging/blob/v1.8.4/lib/grape_logging/middleware/request_logger.rb#L117-L119).
+Therefore, `view_duration_s` can be affected by multiple different factors, like read-write
+process on Redis or external HTTP, not only the serialization process.
+
## `application.log`
Depending on your installation method, this file is located at:
@@ -417,44 +423,16 @@ like this example:
}
```
-## `kubernetes.log`
+## `kubernetes.log` (DEPRECATED)
+
+> [Deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5.
Depending on your installation method, this file is located at:
- Omnibus GitLab: `/var/log/gitlab/gitlab-rails/kubernetes.log`
- Installations from source: `/home/git/gitlab/log/kubernetes.log`
-It logs information related to the Kubernetes Integration, including errors
-during installing cluster applications on your managed Kubernetes
-clusters.
-
-Each line contains JSON that can be ingested by services like Elasticsearch and Splunk.
-Line breaks have been added to the following example for clarity:
-
-```json
-{
- "severity":"ERROR",
- "time":"2018-11-23T15:14:54.652Z",
- "exception":"Kubeclient::HttpError",
- "error_code":401,
- "service":"Clusters::Applications::CheckInstallationProgressService",
- "app_id":14,
- "project_ids":[1],
- "group_ids":[],
- "message":"Unauthorized"
-}
-{
- "severity":"ERROR",
- "time":"2018-11-23T15:42:11.647Z",
- "exception":"Kubeclient::HttpError",
- "error_code":null,
- "service":"Clusters::Applications::InstallService",
- "app_id":2,
- "project_ids":[19],
- "group_ids":[],
- "message":"SSL_connect returned=1 errno=0 state=error: certificate verify failed (unable to get local issuer certificate)"
-}
-```
+It logs information related to [certificate-based clusters](../../user/project/clusters/index.md), such as connectivity errors. Each line contains JSON that can be ingested by services like Elasticsearch and Splunk.
## `git_json.log`
diff --git a/doc/administration/logs/tracing_correlation_id.md b/doc/administration/logs/tracing_correlation_id.md
index f651455a088..906dcd3cea9 100644
--- a/doc/administration/logs/tracing_correlation_id.md
+++ b/doc/administration/logs/tracing_correlation_id.md
@@ -103,7 +103,7 @@ sudo gitlab-ctl tail gitlab-rails/production_json.log | grep '"username":"bob"'
## Searching your logs for the correlation ID
-Once you have the correlation ID you can start searching for relevant log
+When you have the correlation ID you can start searching for relevant log
entries. You can filter the lines by the correlation ID itself.
Combining a `find` and `grep` should be sufficient to find the entries you are looking for.
diff --git a/doc/administration/maintenance_mode/index.md b/doc/administration/maintenance_mode/index.md
index 12f3c4c1cc3..9adb8ce2cd9 100644
--- a/doc/administration/maintenance_mode/index.md
+++ b/doc/administration/maintenance_mode/index.md
@@ -8,9 +8,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2149) in GitLab 13.9.
-Maintenance Mode allows administrators to reduce write operations to a minimum while maintenance tasks are performed. The main goal is to block all external actions that change the internal state, including the PostgreSQL database, but especially files, Git repositories, Container repositories, and so on.
+Maintenance Mode allows administrators to reduce write operations to a minimum while maintenance tasks are performed. The main goal is to block all external actions that change the internal state, including the PostgreSQL database, but especially files, Git repositories, and Container repositories.
-Once Maintenance Mode is enabled, in-progress actions finish relatively quickly since no new actions are coming in, and internal state changes are minimal.
+When Maintenance Mode is enabled, in-progress actions finish relatively quickly since no new actions are coming in, and internal state changes are minimal.
In that state, various maintenance tasks are easier, and services can be stopped completely or be
further degraded for a much shorter period of time than might otherwise be needed. For example, stopping cron jobs and draining queues should be fairly quick.
@@ -150,7 +150,7 @@ is turned off.
Deployments don't go through because pipelines are unfinished.
-It is recommended to disable auto deploys during Maintenance Mode, and enable them once it is disabled.
+It is recommended to disable auto deploys during Maintenance Mode, and enable them when it is disabled.
#### Terraform integration
diff --git a/doc/administration/monitoring/gitlab_self_monitoring_project/index.md b/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
index ad864255f02..35dc64a0594 100644
--- a/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
+++ b/doc/administration/monitoring/gitlab_self_monitoring_project/index.md
@@ -30,31 +30,31 @@ As an administrator, you can add new members to the group to give them the Maint
This project can be used to:
-- Self monitor your GitLab instance. The metrics dashboard of the project shows some basic resource
+- Self-monitor your GitLab instance. The metrics dashboard of the project shows some basic resource
usage charts, such as CPU and memory usage of each server in
[Omnibus GitLab](https://docs.gitlab.com/omnibus/) installations.
- Also configure your own [custom metrics](../../../operations/metrics/index.md#adding-custom-metrics)
using metrics exposed by the [GitLab exporter](../prometheus/gitlab_metrics.md#metrics-available).
-## Create the self monitoring project
+## Create the self-monitoring project
1. On the top bar, select **Main menu > Admin**.
-1. On the left sidebar, select **Settings > Metrics and profiling** and expand **Self monitoring**.
-1. Toggle **Self monitoring** on.
+1. On the left sidebar, select **Settings > Metrics and profiling** and expand **Self-monitoring**.
+1. Toggle **Self-monitoring** on.
1. After your GitLab instance creates the project, GitLab displays a link to the
- project in the text above the **Self monitoring** toggle. You can also find it
+ project in the text above the **Self-monitoring** toggle. You can also find it
from the top bar by selecting **Main menu > Projects**.
-## Delete the self monitoring project
+## Delete the self-monitoring project
WARNING:
-Deleting the self monitoring project removes any changes made to the project. If
+Deleting the self-monitoring project removes any changes made to the project. If
you create the project again, it's created in its default state.
1. On the top bar, select **Main menu > Admin**.
-1. On the left sidebar, go to **Settings > Metrics and profiling** and expand **Self monitoring**.
-1. Toggle **Self monitoring** off.
-1. In the confirmation dialog that opens, select **Delete self monitoring project**.
+1. On the left sidebar, go to **Settings > Metrics and profiling** and expand **Self-monitoring**.
+1. Toggle **Self-monitoring** off.
+1. In the confirmation dialog that opens, select **Delete self-monitoring project**.
It can take a few seconds for it to be deleted.
1. After the project is deleted, GitLab displays a message confirming your action.
@@ -66,7 +66,7 @@ panels, provide a regular expression in the **Instance label regex** field.
The dashboard uses metrics available in
[Omnibus GitLab](https://docs.gitlab.com/omnibus/) installations.
-![GitLab self monitoring overview dashboard](img/self_monitoring_overview_dashboard.png)
+![GitLab self-monitoring overview dashboard](img/self_monitoring_overview_dashboard.png)
You can also
[create your own dashboards](../../../operations/metrics/dashboards/index.md).
@@ -85,12 +85,12 @@ you [configure it manually](../../../user/project/integrations/prometheus.md#man
You can [add a Prometheus integration](../../../operations/incident_management/integrations.md)
to GitLab to receive notifications of any alerts.
-Once the integration is setup, you can
+When the integration is set up, you can
[take action on incoming alerts](../../../operations/metrics/alerts.md#trigger-actions-from-alerts).
-## Add custom metrics to the self monitoring project
+## Add custom metrics to the self-monitoring project
-You can add custom metrics in the self monitoring project by:
+You can add custom metrics in the self-monitoring project by:
1. [Duplicating](../../../operations/metrics/dashboards/index.md#duplicate-a-gitlab-defined-dashboard) the overview dashboard.
1. [Editing](../../../operations/metrics/index.md) the newly created dashboard file and configuring it with [dashboard YAML properties](../../../operations/metrics/dashboards/yaml.md).
@@ -118,4 +118,4 @@ If this returns true, the first administrator user is an external user.
If you face this issue, you can temporarily
[make the administrator user a non-external user](../../../user/permissions.md#external-users)
and then try to create the project.
-Once the project is created, the administrator user can be changed back to an external user.
+After the project is created, the administrator user can be changed back to an external user.
diff --git a/doc/administration/monitoring/ip_allowlist.md b/doc/administration/monitoring/ip_allowlist.md
index 400c70d0fde..94d6876b16f 100644
--- a/doc/administration/monitoring/ip_allowlist.md
+++ b/doc/administration/monitoring/ip_allowlist.md
@@ -6,9 +6,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# IP whitelist **(FREE SELF)**
-NOTE:
-We intend to [rename IP whitelist as `IP allowlist`](https://gitlab.com/groups/gitlab-org/-/epics/3478).
-
GitLab provides some [monitoring endpoints](../../user/admin_area/monitoring/health_check.md)
that provide health check information when probed.
diff --git a/doc/administration/monitoring/performance/grafana_configuration.md b/doc/administration/monitoring/performance/grafana_configuration.md
index a003a3f25bc..92e9672cdb6 100644
--- a/doc/administration/monitoring/performance/grafana_configuration.md
+++ b/doc/administration/monitoring/performance/grafana_configuration.md
@@ -133,15 +133,15 @@ However, you should **not** reinstate your old data _except_ under one of the fo
If you require access to your old Grafana data but don't meet one of these criteria, you may consider:
1. Reinstating it temporarily.
-1. [Exporting the dashboards](https://grafana.com/docs/grafana/latest/dashboards/export-import/#exporting-a-dashboard) you need.
-1. Refreshing the data and [re-importing your dashboards](https://grafana.com/docs/grafana/latest/dashboards/export-import/#import-dashboard).
+1. [Exporting the dashboards](https://grafana.com/docs/grafana/latest/dashboards/manage-dashboards/#export-and-import-dashboards) you need.
+1. Refreshing the data and [re-importing your dashboards](https://grafana.com/docs/grafana/latest/dashboards/manage-dashboards/#export-and-import-dashboards).
WARNING:
These actions pose a temporary vulnerability while your old Grafana data is in use.
Deciding to take any of these actions should be weighed carefully with your need to access
existing data and dashboards.
-For more information and further mitigation details, please refer to our
+For more information and further mitigation details, refer to our
[blog post on the security release](https://about.gitlab.com/releases/2019/08/12/critical-security-release-gitlab-12-dot-1-dot-6-released/).
Read more on:
diff --git a/doc/administration/monitoring/performance/index.md b/doc/administration/monitoring/performance/index.md
index 0bea0836191..89f1270532a 100644
--- a/doc/administration/monitoring/performance/index.md
+++ b/doc/administration/monitoring/performance/index.md
@@ -41,7 +41,7 @@ Two types of metrics are collected:
Transaction metrics are metrics that can be associated with a single
transaction. This includes statistics such as the transaction duration, timings
-of any executed SQL queries, time spent rendering HAML views, and so on. These metrics
+of any executed SQL queries, and time spent rendering HAML views. These metrics
are collected for every Rack request and Sidekiq job processed.
### Sampled Metrics
diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md
index e8bdacb0e14..d3b28fd15bc 100644
--- a/doc/administration/monitoring/prometheus/gitlab_metrics.md
+++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md
@@ -44,6 +44,8 @@ The following metrics are available:
| `gitlab_ci_pipeline_size_builds` | Histogram | 13.1 | Total number of builds within a pipeline grouped by a pipeline source | `source` |
| `gitlab_ci_runner_authentication_success_total` | Counter | 15.2 | Total number of times that runner authentication has succeeded | `type` |
| `gitlab_ci_runner_authentication_failure_total` | Counter | 15.2 | Total number of times that runner authentication has failed
+| `gitlab_ghost_user_migration_lag_seconds` | Gauge | 15.6 | The waiting time in seconds of the oldest scheduled record for ghost user migration | |
+| `gitlab_ghost_user_migration_scheduled_records_total` | Gauge | 15.6 | The total number of scheduled ghost user migrations | |
| `job_waiter_started_total` | Counter | 12.9 | Number of batches of jobs started where a web request is waiting for the jobs to complete | `worker` |
| `job_waiter_timeouts_total` | Counter | 12.9 | Number of batches of jobs that timed out where a web request is waiting for the jobs to complete | `worker` |
| `gitlab_ci_active_jobs` | Histogram | 14.2 | Count of active jobs when pipeline is created | |
@@ -148,6 +150,8 @@ The following metrics are available:
| `gitlab_ci_build_trace_errors_total` | Counter | 14.4 | Total amount of different error types on a build trace | `error_reason` |
| `gitlab_presentable_object_cacheless_render_real_duration_seconds` | Histogram | 15.3 | Duration of real time spent caching and representing specific web request objects | `controller`, `action` |
| `cached_object_operations_total` | Counter | 15.3 | Total number of objects cached for specific web requests | `controller`, `action` |
+| `redis_hit_miss_operations_total` | Counter | 15.6 | Total number of Redis cache hits and misses | `cache_hit`, `caller_id`, `cache_identifier`, `feature_category`, `backing_resource` |
+| `redis_cache_generation_duration_seconds` | Histogram | 15.6 | Time to generate Redis cache | `cache_hit`, `caller_id`, `cache_identifier`, `feature_category`, `backing_resource` |
## Metrics controlled by a feature flag
@@ -155,7 +159,6 @@ The following metrics can be controlled by feature flags:
| Metric | Feature Flag |
|:---------------------------------------------------------------|:-------------------------------------------------------------------|
-| `gitlab_method_call_duration_seconds` | `prometheus_metrics_method_instrumentation` |
| `gitlab_view_rendering_duration_seconds` | `prometheus_metrics_view_instrumentation` |
## Praefect metrics
@@ -318,6 +321,16 @@ configuration option in `gitlab.yml`. These metrics are served from the
| `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_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_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 | |
## Database load balancing metrics **(PREMIUM SELF)**
@@ -374,6 +387,8 @@ Some basic Ruby runtime metrics are available:
| `ruby_process_cpu_seconds_total` | Gauge | 12.0 | Total amount of CPU time per process |
| `ruby_process_max_fds` | Gauge | 12.0 | Maximum number of open file descriptors per process |
| `ruby_process_resident_memory_bytes` | Gauge | 12.0 | Memory usage by process (RSS/Resident Set Size) |
+| `ruby_process_resident_anon_memory_bytes`| Gauge | 15.6 | Anonymous memory usage by process (RSS/Resident Set Size) |
+| `ruby_process_resident_file_memory_bytes`| Gauge | 15.6 | File-backed memory usage by process (RSS/Resident Set Size) |
| `ruby_process_unique_memory_bytes` | Gauge | 13.0 | Memory usage by process (USS/Unique Set Size) |
| `ruby_process_proportional_memory_bytes` | Gauge | 13.0 | Memory usage by process (PSS/Proportional Set Size) |
| `ruby_process_start_time_seconds` | Gauge | 12.0 | UNIX timestamp of process start time |
@@ -399,7 +414,7 @@ These client metrics are meant to complement Redis server metrics.
These metrics are broken down per
[Redis instance](https://docs.gitlab.com/omnibus/settings/redis.html#running-with-multiple-redis-instances).
These metrics all have a `storage` label which indicates the Redis
-instance (`cache`, `shared_state`, and so on).
+instance. For example, `cache` or `shared_state`.
| Metric | Type | Since | Description |
|:--------------------------------- |:------- |:----- |:----------- |
diff --git a/doc/administration/nfs.md b/doc/administration/nfs.md
index 9072bd1f344..85f35a1b188 100644
--- a/doc/administration/nfs.md
+++ b/doc/administration/nfs.md
@@ -10,7 +10,7 @@ type: reference
NFS can be used as an alternative for object storage but this isn't typically
recommended for performance reasons.
-For data objects such as LFS, Uploads, Artifacts, and so on, an [Object Storage service](object_storage.md)
+For data objects such as LFS, Uploads, and Artifacts, an [Object Storage service](object_storage.md)
is recommended over NFS where possible, due to better performance.
When eliminating the usage of NFS, there are [additional steps you need to take](object_storage.md#other-alternatives-to-file-system-storage)
in addition to moving to Object Storage.
@@ -44,7 +44,7 @@ GitLab support is unable to continue with the investigation if both:
- The date of the request is on or after the release of GitLab version 15.6.
- Support Engineers and Management determine that all reasonable non-NFS root causes have been exhausted.
-If the issue is reproducible, or if it happens intermittently but regularly, GitLab Support can investigate providing the issue reproduces without the use of NFS. In order to reproduce without NFS, the affected repositories should be migrated to a different Gitaly shard, such as Gitaly cluster or a standalone Gitaly VM, backed with block storage.
+If the issue is reproducible, or if it happens intermittently but regularly, GitLab Support can investigate providing the issue reproduces without the use of NFS. To reproduce without NFS, the affected repositories should be migrated to a different Gitaly shard, such as Gitaly cluster or a standalone Gitaly VM, backed with block storage.
### Why remove NFS for Git repository data
@@ -52,7 +52,7 @@ If the issue is reproducible, or if it happens intermittently but regularly, Git
NFS is not well-suited to a workload consisting of many small files, like Git repositories. NFS does provide a number of configuration options designed to improve performance. However, over time, a number of these mount options have proven to result in inconsistencies across multiple nodes mounting the NFS volume, up to and including data loss. Addressing these inconsistencies consume extraordinary development and support engineer time that hamper our ability to develop [Gitaly Cluster](gitaly/praefect.md), our purpose-built solution to addressing the deficiencies of NFS in this environment.
-Please note that Gitaly Cluster provides highly-available Git repository storage. If this is not a requirement, single-node Gitaly backed by block storage is a suitable substitute.
+Gitaly Cluster provides highly-available Git repository storage. If this is not a requirement, single-node Gitaly backed by block storage is a suitable substitute.
Engineering support for NFS for Git repositories is deprecated. Technical support is planned to be
unavailable from GitLab 15.0. No further enhancements are planned for this feature.
@@ -338,7 +338,7 @@ following are the 4 locations need to be shared:
| -------- | ----------- | --------------------- |
| `/var/opt/gitlab/git-data` | Git repository data. This accounts for a large portion of your data | `git_data_dirs({"default" => { "path" => "/var/opt/gitlab/git-data"} })`
| `/var/opt/gitlab/gitlab-rails/uploads` | User uploaded attachments | `gitlab_rails['uploads_directory'] = '/var/opt/gitlab/gitlab-rails/uploads'`
-| `/var/opt/gitlab/gitlab-rails/shared` | Build artifacts, GitLab Pages, LFS objects, temp files, and so on. If you're using LFS this may also account for a large portion of your data | `gitlab_rails['shared_path'] = '/var/opt/gitlab/gitlab-rails/shared'`
+| `/var/opt/gitlab/gitlab-rails/shared` | Objects such as build artifacts, GitLab Pages, LFS objects, and temp files. If you're using LFS this may also account for a large portion of your data | `gitlab_rails['shared_path'] = '/var/opt/gitlab/gitlab-rails/shared'`
| `/var/opt/gitlab/gitlab-ci/builds` | GitLab CI/CD build traces | `gitlab_ci['builds_directory'] = '/var/opt/gitlab/gitlab-ci/builds'`
Other GitLab directories should not be shared between nodes. They contain
@@ -352,7 +352,7 @@ are empty before attempting a restore. Read more about the
## Testing NFS
-Once you've set up the NFS server and client, you can verify NFS is configured correctly
+When you've set up the NFS server and client, you can verify NFS is configured correctly
by testing the following commands:
```shell
diff --git a/doc/administration/object_storage.md b/doc/administration/object_storage.md
index 0e85635b3d2..d2c9c35148c 100644
--- a/doc/administration/object_storage.md
+++ b/doc/administration/object_storage.md
@@ -18,7 +18,7 @@ GitLab has been tested by vendors and customers on a number of object storage pr
- [Amazon S3](https://aws.amazon.com/s3/)
- [Google Cloud Storage](https://cloud.google.com/storage)
- [Digital Ocean Spaces](https://www.digitalocean.com/products/spaces)
-- [Oracle Cloud Infrastructure](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)
+- [Oracle Cloud Infrastructure](https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)
- [OpenStack Swift (S3 compatible mode)](https://docs.openstack.org/swift/latest/s3_compat.html)
- [Azure Blob storage](https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction)
- On-premises hardware and appliances from various storage vendors, whose list is not officially established.
@@ -88,8 +88,8 @@ 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).
-Most types of objects, such as CI artifacts, LFS files, upload
-attachments, and so on can be saved in object storage by specifying a single
+Most types of objects, such as CI artifacts, LFS files, and upload
+attachments can be saved in object storage by specifying a single
credential for object storage with multiple buckets.
When the consolidated form is:
@@ -279,7 +279,7 @@ Here are the valid connection parameters for GCS:
| `google_project` | GCP project name. | `gcp-project-12345` |
| `google_json_key_location` | JSON key path. | `/path/to/gcp-project-12345-abcde.json` |
| `google_json_key_string` | JSON key string. | `{ "type": "service_account", "project_id": "example-project-382839", ... }` |
-| `google_application_default` | Set to `true` to use [Google Cloud Application Default Credentials](https://cloud.google.com/docs/authentication/production#automatically) to locate service account credentials. | |
+| `google_application_default` | Set to `true` to use [Google Cloud Application Default Credentials](https://cloud.google.com/docs/authentication#adc) to locate service account credentials. | |
GitLab reads the value of `google_json_key_location`, then `google_json_key_string`, and finally, `google_application_default`.
It uses the first of these settings that has a value.
@@ -492,7 +492,7 @@ To migrate existing local data to object storage see the following guides:
Prior to GitLab 13.2:
- Object storage configuration for all types of objects such as CI/CD artifacts, LFS
- files, upload attachments, and so on had to be configured independently.
+ files, and upload attachments had to be configured independently.
- Object store connection parameters such as passwords and endpoint URLs had to be
duplicated for each type.
diff --git a/doc/administration/operations/moving_repositories.md b/doc/administration/operations/moving_repositories.md
index 75078568c44..96c1fcc422d 100644
--- a/doc/administration/operations/moving_repositories.md
+++ b/doc/administration/operations/moving_repositories.md
@@ -376,14 +376,3 @@ sudo -u git -H bundle exec rake gitlab:list_repos SINCE='2015-10-1 12:00 UTC' |\
/home/git/repositories \
/mnt/gitlab/repositories
```
-
-## Troubleshooting
-
-See the following for information on troubleshooting repository moves.
-
-### Repository move fails for archived projects
-
-Because of a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/363670),
-[archived projects](../../user/project/settings/index.md#advanced-project-settings) fail to move even though the data is cloned
-by Gitaly. Make sure archived projects are
-[unarchived](../../user/project/settings/index.md#unarchive-a-project) before initiating a move.
diff --git a/doc/administration/operations/rails_console.md b/doc/administration/operations/rails_console.md
index 1ef985b8938..efaf480c6df 100644
--- a/doc/administration/operations/rails_console.md
+++ b/doc/administration/operations/rails_console.md
@@ -59,6 +59,40 @@ you may run in the console. To turn off logging again, run:
ActiveRecord::Base.logger = nil
```
+## Attributes
+
+View available attributes, formatted using pretty print (`pp`).
+
+For example, determine what attributes contain users' names and email addresses:
+
+```ruby
+u = User.find_by_username('someuser')
+pp u.attributes
+```
+
+Partial output:
+
+```plaintext
+{"id"=>1234,
+ "email"=>"someuser@example.com",
+ "sign_in_count"=>99,
+ "name"=>"S User",
+ "username"=>"someuser",
+ "first_name"=>nil,
+ "last_name"=>nil,
+ "bot_type"=>nil}
+```
+
+Then make use of the attributes, [testing SMTP, for example](https://docs.gitlab.com/omnibus/settings/smtp.html#testing-the-smtp-configuration):
+
+```ruby
+e = u.email
+n = u.name
+Notify.test_email(e, "Test email for #{n}", 'Test email').deliver_now
+#
+Notify.test_email(u.email, "Test email for #{u.name}", 'Test email').deliver_now
+```
+
## Disable database statement timeout
You can disable the PostgreSQL statement timeout for the current Rails console
@@ -702,7 +736,7 @@ ApplicationSetting.current
### Open object in `irb`
WARNING:
-Any command that changes data directly could be damaging if not run correctly, or under the right conditions. We highly recommend running them in a test environment with a backup of the instance ready to be restored, just in case.
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
Sometimes it is easier to go through a method if you are in the context of the object. You can shim into the namespace of `Object` to let you open `irb` in the context of any object:
diff --git a/doc/administration/package_information/defaults.md b/doc/administration/package_information/defaults.md
index c6a33ed7ba9..717e5ca31c9 100644
--- a/doc/administration/package_information/defaults.md
+++ b/doc/administration/package_information/defaults.md
@@ -68,8 +68,8 @@ over a network which will require, based on implementation, ports `111` and
`2049` to be open.
NOTE:
-In some cases, the GitLab Registry will be automatically enabled by default. Please see [our documentation](../packages/container_registry.md) for more details
+In some cases, the GitLab Registry will be automatically enabled by default. See [our documentation](../packages/container_registry.md) for more details.
- [^Consul-notes]: If using additional Consul functionality, more ports may need to be opened. See the [official documentation](https://www.consul.io/docs/install/ports#ports-table) for the list.
+ [^Consul-notes]: If using additional Consul functionality, more ports may need to be opened. See the [official documentation](https://developer.hashicorp.com/consul/docs/install/ports#ports-table) for the list.
[^Sidekiq-health]: If Sidekiq health check settings are not set, they will default to the Sidekiq metrics exporter settings. This default is deprecated and is set to be removed in [GitLab 15.0](https://gitlab.com/gitlab-org/gitlab/-/issues/347509).
diff --git a/doc/administration/package_information/omnibus_packages.md b/doc/administration/package_information/omnibus_packages.md
index ec406f8b458..7b3892ace70 100644
--- a/doc/administration/package_information/omnibus_packages.md
+++ b/doc/administration/package_information/omnibus_packages.md
@@ -72,7 +72,7 @@ Some drawbacks of a package with bundled dependencies:
1. Duplication with possibly existing software.
1. Less flexibility in configuration.
-## Why would I install an omnibus package when I can use a system package?
+## Why would you install an omnibus package when you can use a system package?
The answer can be simplified to: less maintenance required. Instead of handling
multiple packages that *can* break existing functionality if the versions are
diff --git a/doc/administration/package_information/postgresql_versions.md b/doc/administration/package_information/postgresql_versions.md
index 6409c5fdbc9..c1e9f7320ea 100644
--- a/doc/administration/package_information/postgresql_versions.md
+++ b/doc/administration/package_information/postgresql_versions.md
@@ -30,6 +30,7 @@ Read more about update policies and warnings in the PostgreSQL
| GitLab version | PostgreSQL versions | Default version for fresh installs | Default version for upgrades | Notes |
| -------------- | --------------------- | ---------------------------------- | ---------------------------- | ----- |
+| 15.6 | 12.12, 13.8 | 13.8 | 12.12 | For upgrades, users can manually upgrade to 13.8 following the [upgrade documentation](https://docs.gitlab.com/omnibus/settings/database.html#gitlab-150-and-later). |
| 15.0 | 12.10, 13.6 | 13.6 | 12.10 | For upgrades, users can manually upgrade to 13.6 following the [upgrade documentation](https://docs.gitlab.com/omnibus/settings/database.html#gitlab-150-and-later). |
| 14.1 | 12.7, 13.3 | 12.7 | 12.7 | PostgreSQL 13 available for fresh installations if not using [Geo](../geo/index.md#requirements-for-running-geo) or [Patroni](../postgresql/index.md#postgresql-replication-and-failover-with-omnibus-gitlab).
| 14.0 | 12.7 | 12.7 | 12.7 | HA installations with repmgr are no longer supported and are prevented from upgrading to Omnibus GitLab 14.0 |
diff --git a/doc/administration/package_information/signed_packages.md b/doc/administration/package_information/signed_packages.md
index 34c8148e807..e4566be7534 100644
--- a/doc/administration/package_information/signed_packages.md
+++ b/doc/administration/package_information/signed_packages.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Package Signatures **(FREE SELF)**
-As of the release of GitLab 9.5 on August 22, 2017, GitLab provides signed Omnibus GitLab packages for RPM and DEB based distributions. This means that all packages provided on <https://packages.gitlab.com> are signed, starting with `9.5.0`, and all future versions of supported branches (for example `9.3.x` and `9.4.x` after August 22, 2017). Any package version prior to August 22, 2017, will not be signed. Please pass the appropriate argument to your package manager. (Example: `yum --nogpgcheck`)
+As of the release of GitLab 9.5 on August 22, 2017, GitLab provides signed Omnibus GitLab packages for RPM and DEB based distributions. This means that all packages provided on <https://packages.gitlab.com> are signed, starting with `9.5.0`, and all future versions of supported branches (for example `9.3.x` and `9.4.x` after August 22, 2017). Any package version prior to August 22, 2017, will not be signed. Pass the appropriate argument to your package manager. (Example: `yum --nogpgcheck`)
Omnibus GitLab packages produced by GitLab are created via the [Omnibus](https://github.com/chef/omnibus) tool, for which GitLab has added DEB signing via `debsigs` in [our own fork](https://gitlab.com/gitlab-org/omnibus). This addition, combined with the existing functionality of RPM signing, allows GitLab to provide signed packages for all supported distributions using DEB or RPM.
diff --git a/doc/administration/packages/container_registry.md b/doc/administration/packages/container_registry.md
index d04e3217f57..2623f2afd8d 100644
--- a/doc/administration/packages/container_registry.md
+++ b/doc/administration/packages/container_registry.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+group: Container 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
---
@@ -198,7 +198,8 @@ docker login gitlab.example.com:5050
When the Registry is configured to use its own domain, you need a TLS
certificate for that specific domain (for example, `registry.example.com`). You might need
a wildcard certificate if hosted under a subdomain of your existing GitLab
-domain, for example, `registry.gitlab.example.com`.
+domain. For example, `*.gitlab.example.com`, is a wildcard that matches `registry.gitlab.example.com`,
+and is distinct from `*.example.com`.
As well as manually generated SSL certificates (explained here), certificates automatically
generated by Let's Encrypt are also [supported in Omnibus installs](https://docs.gitlab.com/omnibus/settings/ssl.html).
@@ -1156,7 +1157,7 @@ blobs start being deleted is anything permanent done.
## Configuring GitLab and Registry to run on separate nodes (Omnibus GitLab)
By default, package assumes that both services are running on the same node.
-In order to get GitLab and Registry to run on a separate nodes, separate configuration
+To get GitLab and Registry to run on a separate nodes, separate configuration
is necessary for Registry and GitLab.
### Configuring Registry
diff --git a/doc/administration/packages/dependency_proxy.md b/doc/administration/packages/dependency_proxy.md
index 789863e8ed0..f6eb6f85274 100644
--- a/doc/administration/packages/dependency_proxy.md
+++ b/doc/administration/packages/dependency_proxy.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+group: Container 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
---
@@ -215,11 +215,12 @@ For installations from source:
RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:dependency_proxy:migrate
```
-You can optionally track progress and verify that all packages migrated successfully using the
+You can optionally track progress and verify that all Dependency Proxy blobs and manifests migrated successfully using the
[PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database):
-- For Omnibus GitLab instances: `sudo gitlab-rails dbconsole`
-- For installations from source: `sudo -u git -H psql -d gitlabhq_production`
+- `sudo gitlab-rails dbconsole` for Omnibus GitLab 14.1 and earlier.
+- `sudo gitlab-rails dbconsole --database main` for Omnibus GitLab 14.2 and later.
+- `sudo -u git -H psql -d gitlabhq_production` for source-installed instances.
Verify that `objectstg` (where `file_store = '2'`) has the count of all Dependency Proxy blobs and
manifests for each respective query:
diff --git a/doc/administration/packages/index.md b/doc/administration/packages/index.md
index a7ab0fb3246..74d835eb744 100644
--- a/doc/administration/packages/index.md
+++ b/doc/administration/packages/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
@@ -231,7 +231,8 @@ RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:packages:migrate
You can optionally track progress and verify that all packages migrated successfully using the
[PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database):
-- `sudo gitlab-rails dbconsole` for Omnibus GitLab instances.
+- `sudo gitlab-rails dbconsole` for Omnibus GitLab 14.1 and earlier.
+- `sudo gitlab-rails dbconsole --database main` for Omnibus GitLab 14.2 and later.
- `sudo -u git -H psql -d gitlabhq_production` for source-installed instances.
Verify `objectstg` below (where `file_store = '2'`) has count of all packages:
diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md
index 922f9a27aad..3d31491a9d2 100644
--- a/doc/administration/pages/index.md
+++ b/doc/administration/pages/index.md
@@ -260,6 +260,7 @@ control over how the Pages daemon runs and serves content in your environment.
| `gitlab_id` | The OAuth application public ID. Leave blank to automatically fill when Pages authenticates with GitLab. |
| `gitlab_secret` | The OAuth application secret. Leave blank to automatically fill when Pages authenticates with GitLab. |
| `auth_scope` | The OAuth application scope to use for authentication. Must match GitLab Pages OAuth application settings. Leave blank to use `api` scope by default. |
+| `auth_cookie_session_timeout` | Authentication cookie session timeout in seconds (default: 600s). A value of `0` means the cookie is deleted after the browser session ends. |
| `gitlab_server` | Server to use for authentication when access control is enabled; defaults to GitLab `external_url`. |
| `headers` | Specify any additional http headers that should be sent to the client with each response. Multiple headers can be given as an array, header and value as one string, for example `['my-header: myvalue', 'my-other-header: my-other-value']` |
| `enable_disk` | Allows the GitLab Pages daemon to serve content from disk. Shall be disabled if shared disk storage isn't available. |
@@ -512,7 +513,7 @@ internet connectivity is gated by a proxy. To use a proxy for GitLab Pages:
### Using a custom Certificate Authority (CA)
-When using certificates issued by a custom CA, [Access Control](../../user/project/pages/pages_access_control.md#gitlab-pages-access-control) and
+When using certificates issued by a custom CA, [Access Control](../../user/project/pages/pages_access_control.md) and
the [online view of HTML job artifacts](../../ci/pipelines/job_artifacts.md#download-job-artifacts)
fails to work if the custom CA is not recognized.
@@ -820,8 +821,8 @@ database encryption. Proceed with caution.
It's possible to run GitLab Pages on multiple servers if you wish to distribute
the load. You can do this through standard load balancing practices such as
-configuring your DNS server to return multiple IPs for your Pages server,
-configuring a load balancer to work at the IP level, and so on. If you wish to
+configuring your DNS server to return multiple IPs for your Pages server, or
+configuring a load balancer to work at the IP level. If you wish to
set up GitLab Pages on multiple servers, perform the above procedure for each
Pages server.
@@ -1073,7 +1074,8 @@ sudo gitlab-rake gitlab:pages:deployments:migrate_to_object_storage
You can track progress and verify that all Pages deployments migrated successfully using the
[PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database):
-- `sudo gitlab-rails dbconsole` for Omnibus GitLab instances.
+- `sudo gitlab-rails dbconsole` for Omnibus GitLab 14.1 and earlier.
+- `sudo gitlab-rails dbconsole --database main` for Omnibus GitLab 14.2 and later.
- `sudo -u git -H psql -d gitlabhq_production` for source-installed instances.
Verify `objectstg` below (where `store=2`) has count of all Pages deployments:
@@ -1213,7 +1215,7 @@ the section below.
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/administration/pages/source.md b/doc/administration/pages/source.md
index 52556809845..e122d49a963 100644
--- a/doc/administration/pages/source.md
+++ b/doc/administration/pages/source.md
@@ -459,7 +459,7 @@ Pages access control is disabled by default. To enable it:
auth-server=<URL of the GitLab instance>
```
-1. Users can now configure it in their [projects' settings](../../user/project/pages/introduction.md#gitlab-pages-access-control).
+1. Users can now configure it in their [projects' settings](../../user/project/pages/pages_access_control.md).
## Change storage path
diff --git a/doc/administration/polling.md b/doc/administration/polling.md
index 11f26f081cb..deb6e89183d 100644
--- a/doc/administration/polling.md
+++ b/doc/administration/polling.md
@@ -6,8 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Polling interval multiplier **(FREE SELF)**
-The GitLab UI polls for updates for different resources (issue notes, issue titles, pipeline
-statuses, and so on) on a schedule appropriate to the resource.
+The GitLab UI polls for updates for different resources (such as issue notes, issue titles, and pipeline
+statuses) on a schedule appropriate to the resource.
Adjust the multiplier on these schedules to adjust how frequently the GitLab UI polls for updates. If
you set the multiplier to:
diff --git a/doc/administration/postgresql/database_load_balancing.md b/doc/administration/postgresql/database_load_balancing.md
index 6bf36ef4794..805c4b2023f 100644
--- a/doc/administration/postgresql/database_load_balancing.md
+++ b/doc/administration/postgresql/database_load_balancing.md
@@ -130,6 +130,7 @@ record. For example:
| `interval` | The minimum time in seconds between checking the DNS record. | 60 |
| `disconnect_timeout` | The time in seconds after which an old connection is closed, after the list of hosts was updated. | 120 |
| `use_tcp` | Lookup DNS resources using TCP instead of UDP | false |
+| `max_replica_pools` | The maximum number of replicas each Rails process connects to. This is useful if you run a lot of Postgres replicas and a lot of Rails processes because without this limit every Rails process connects to every replica by default. The default behavior is unlimited if not set. | nil |
If `record_type` is set to `SRV`, then GitLab continues to use round-robin algorithm
and ignores the `weight` and `priority` in the record. Since `SRV` records usually
diff --git a/doc/administration/postgresql/replication_and_failover.md b/doc/administration/postgresql/replication_and_failover.md
index 0ee48047944..ee90b120d05 100644
--- a/doc/administration/postgresql/replication_and_failover.md
+++ b/doc/administration/postgresql/replication_and_failover.md
@@ -606,7 +606,7 @@ Here is a list and description of each machine and the assigned IP:
- `10.6.0.33`: PostgreSQL 3
- `10.6.0.41`: GitLab application
-All passwords are set to `toomanysecrets`. Please do not use this password or derived hashes and the `external_url` for GitLab is `http://gitlab.example.com`.
+All passwords are set to `toomanysecrets`. Do not use this password or derived hashes and the `external_url` for GitLab is `http://gitlab.example.com`.
After the initial configuration, if a failover occurs, the PostgresSQL leader node changes to one of the available secondaries until it is failed back.
@@ -957,7 +957,7 @@ For further details, see [Patroni documentation on this subject](https://patroni
### Switching from repmgr to Patroni
WARNING:
-Switching from repmgr to Patroni is straightforward, the other way around is *not*. Rolling back from Patroni to repmgr can be complicated and may involve deletion of data directory. If you need to do that, please contact GitLab support.
+Switching from repmgr to Patroni is straightforward, the other way around is *not*. Rolling back from Patroni to repmgr can be complicated and may involve deletion of data directory. If you need to do that, contact GitLab support.
You can switch an exiting database cluster to use Patroni instead of repmgr with the following steps:
diff --git a/doc/administration/raketasks/uploads/migrate.md b/doc/administration/raketasks/uploads/migrate.md
index b6f14bc6fa4..1f6e7fda082 100644
--- a/doc/administration/raketasks/uploads/migrate.md
+++ b/doc/administration/raketasks/uploads/migrate.md
@@ -42,10 +42,11 @@ gitlab-rake "gitlab:uploads:migrate:all"
sudo RAILS_ENV=production -u git -H bundle exec rake gitlab:uploads:migrate:all
```
-You can optionally track progress and verify that all packages migrated successfully using the
+You can optionally track progress and verify that all uploads migrated successfully using the
[PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database):
-- `sudo gitlab-rails dbconsole` for Omnibus GitLab instances.
+- `sudo gitlab-rails dbconsole` for Omnibus GitLab 14.1 and earlier.
+- `sudo gitlab-rails dbconsole --database main` for Omnibus GitLab 14.2 and later.
- `sudo -u git -H psql -d gitlabhq_production` for source-installed instances.
Verify `objectstg` below (where `store=2`) has count of all artifacts:
diff --git a/doc/administration/redis/replication_and_failover.md b/doc/administration/redis/replication_and_failover.md
index 1c2515099fe..2ba19aa6f0a 100644
--- a/doc/administration/redis/replication_and_failover.md
+++ b/doc/administration/redis/replication_and_failover.md
@@ -66,7 +66,7 @@ When a **Primary** fails to respond, it's the application's responsibility
(in our case GitLab) to handle timeout and reconnect (querying a **Sentinel**
for a new **Primary**).
-To get a better understanding on how to correctly set up Sentinel, please read
+To get a better understanding on how to correctly set up Sentinel, read
the [Redis Sentinel](https://redis.io/docs/manual/sentinel/) documentation first, as
failing to configure it correctly can lead to data loss or can bring your
whole cluster down, invalidating the failover effort.
@@ -350,7 +350,7 @@ Now that the Redis servers are all set up, let's configure the Sentinel
servers.
If you are not sure if your Redis servers are working and replicating
-correctly, please read the [Troubleshooting Replication](troubleshooting.md#troubleshooting-redis-replication)
+correctly, read the [Troubleshooting Replication](troubleshooting.md#troubleshooting-redis-replication)
and fix it before proceeding with Sentinel setup.
You must have at least `3` Redis Sentinel servers, and they need to
diff --git a/doc/administration/redis/replication_and_failover_external.md b/doc/administration/redis/replication_and_failover_external.md
index 7904fb1ded8..23c9ce33c2d 100644
--- a/doc/administration/redis/replication_and_failover_external.md
+++ b/doc/administration/redis/replication_and_failover_external.md
@@ -64,7 +64,7 @@ settings outlined in
We cannot stress enough the importance of reading the
[replication and failover](replication_and_failover.md) documentation of the
Omnibus Redis HA as it provides some invaluable information to the configuration
-of Redis. Please proceed to read it before going forward with this guide.
+of Redis. Read it before going forward with this guide.
Before proceeding on setting up the new Redis instances, here are some
requirements:
diff --git a/doc/administration/redis/troubleshooting.md b/doc/administration/redis/troubleshooting.md
index e568daed961..29407f65efd 100644
--- a/doc/administration/redis/troubleshooting.md
+++ b/doc/administration/redis/troubleshooting.md
@@ -26,8 +26,8 @@ Start Redis troubleshooting with a basic Redis activity check:
1. Open a terminal on your GitLab server.
1. Run `gitlab-redis-cli --stat` and observe the output while it runs.
-1. Go to your GitLab UI and browse to a handful of pages. Any page works, like
- group or project overviews, issues, files in repositories, and so on.
+1. Go to your GitLab UI and browse to a handful of pages. Any page works, such as
+ group or project overviews, issues, or files in repositories.
1. Check the `stat` output again and verify that the values for `keys`, `clients`,
`requests`, and `connections` increases as you browse. If the numbers go up,
basic Redis functionality is working and GitLab can connect to it.
diff --git a/doc/administration/reference_architectures/10k_users.md b/doc/administration/reference_architectures/10k_users.md
index 45939b48f78..a2463c6ff88 100644
--- a/doc/administration/reference_architectures/10k_users.md
+++ b/doc/administration/reference_architectures/10k_users.md
@@ -28,7 +28,7 @@ full list of reference architectures, see
| Internal load balancing node<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Redis/Sentinel - Cache<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
| Redis/Sentinel - Persistent<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
-| Gitaly<sup>5</sup> | 3 | 16 vCPU, 60 GB memory | `n1-standard-16` | `m5.4xlarge` |
+| Gitaly<sup>5 6</sup> | 3 | 16 vCPU, 60 GB memory | `n1-standard-16` | `m5.4xlarge` |
| Praefect<sup>5</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Sidekiq | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
@@ -50,6 +50,7 @@ full list of reference architectures, see
- [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work.
4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section.
5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`.
+6. Gitaly has been designed and tested with repositories of varying sizes that follow best practices. However, large repositories or monorepos that don't follow these practices can significantly impact Gitaly requirements. Refer to the [Large Repositories](#large-repositories) for more info.
<!-- markdownlint-enable MD029 -->
NOTE:
@@ -158,10 +159,45 @@ Any "burstable" instance types are not recommended due to inconsistent performan
### Supported infrastructure
-As a general guidance, GitLab should run on most infrastructure such as reputable Cloud Providers (AWS, GCP) and their services, or self managed (ESXi) that meet both the specs detailed above, as well as any requirements in this section. However, this does not constitute a guarantee for every potential permutation.
+As a general guidance, GitLab should run on most infrastructure such as reputable Cloud Providers (AWS, GCP) and their services,
+or self managed (ESXi) that meet both the specs detailed above, as well as any requirements in this section.
+However, this does not constitute a guarantee for every potential permutation.
See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+### Additional workloads
+
+The Reference Architectures have been [designed and tested](index.md#validation-and-test-results) for standard GitLab setups with
+good headroom in mind to cover most scenarios. However, if any additional workloads are being added on the nodes,
+such as security software, you may still need to adjust the specs accordingly to compensate.
+
+This also applies for some GitLab features where it's possible to run custom scripts, for example [server hooks](../server_hooks.md).
+
+As a general rule, it's recommended to have robust monitoring in place to measure the impact of
+any additional workloads to inform any changes needed to be made.
+
+### Large repositories
+
+The Reference Architectures were tested with repositories of varying sizes that follow best practices.
+
+However, large repositories or monorepos (several gigabytes or more) can **significantly** impact the performance
+of Git and in turn the environment itself if best practices aren't being followed such as not storing
+binary or blob files in LFS. Repositories are at the core of any environment the consequences can be wide-ranging
+when they are not optimized. Some examples of this impact include [Git packing operations](https://git-scm.com/book/en/v2/Git-Internals-Packfiles)
+taking longer and consuming high CPU / Memory resources or Git checkouts taking longer that affect both users and
+CI pipelines alike.
+
+As such, large repositories come with notable cost and typically will require more resources to handle,
+significantly so in some cases. It's therefore **strongly** recommended then to review large repositories
+to ensure they maintain good repo health and reduce their size wherever possible.
+
+NOTE:
+If best practices aren't followed and large repositories are present on the environment,
+increased Gitaly specs may be required to ensure stable performance.
+
+Refer to the [Managing large repositories documentation](../../user/project/repository/managing_large_repositories.md)
+for more information and guidance.
+
### Praefect PostgreSQL
It's worth noting that at this time [Praefect requires its own database server](../gitaly/praefect.md#postgresql) and
@@ -241,8 +277,7 @@ In a multi-node GitLab configuration, you'll need a load balancer to route
traffic to the application servers. The specifics on which load balancer to use
or its exact configuration is beyond the scope of GitLab documentation. We assume
that if you're managing multi-node systems like GitLab, you already have a load
-balancer of choice and that the routing methods used are distributing calls evenly
-between all nodes. Some load balancer examples include HAProxy (open-source),
+balancer of choice. Some load balancer examples include HAProxy (open-source),
F5 Big-IP LTM, and Citrix Net Scaler. This documentation outline the ports and
protocols needed for use with GitLab.
@@ -250,47 +285,13 @@ This architecture has been tested and validated with [HAProxy](https://www.hapro
as the load balancer. Although other load balancers with similar feature sets
could also be used, those load balancers have not been validated.
-The next question is how you will handle SSL in your environment.
-There are several different options:
+### Balancing algorithm
-- [The application node terminates SSL](#application-node-terminates-ssl).
-- [The load balancer terminates SSL without backend SSL](#load-balancer-terminates-ssl-without-backend-ssl)
- and communication is not secure between the load balancer and the application node.
-- [The load balancer terminates SSL with backend SSL](#load-balancer-terminates-ssl-with-backend-ssl)
- and communication is *secure* between the load balancer and the application node.
-
-### Application node terminates SSL
+We recommend that a least-connection load balancing algorithm or equivalent
+is used wherever possible to ensure equal spread of calls to the nodes and good performance.
-Configure your load balancer to pass connections on port 443 as `TCP` rather
-than `HTTP(S)` protocol. This will pass the connection to the application node's
-NGINX service untouched. NGINX will have the SSL certificate and listen on port 443.
-
-See the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
-for details on managing SSL certificates and configuring NGINX.
-
-### Load balancer terminates SSL without backend SSL
-
-Configure your load balancer to use the `HTTP(S)` protocol rather than `TCP`.
-The load balancer will then be responsible for managing SSL certificates and
-terminating SSL.
-
-Since communication between the load balancer and GitLab will not be secure,
-there is some additional configuration needed. See the
-[proxied SSL documentation](https://docs.gitlab.com/omnibus/settings/ssl.html#configure-a-reverse-proxy-or-load-balancer-ssl-termination)
-for details.
-
-### Load balancer terminates SSL with backend SSL
-
-Configure your load balancers to use the 'HTTP(S)' protocol rather than 'TCP'.
-The load balancers will be responsible for managing SSL certificates that
-end users will see.
-
-Traffic will also be secure between the load balancers and NGINX in this
-scenario. There is no need to add configuration for proxied SSL since the
-connection will be secure all the way. However, configuration will need to be
-added to GitLab to configure SSL certificates. See
-the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
-for details on managing SSL certificates and configuring NGINX.
+We don't recommend the use of round-robin algorithms as they are known to not
+spread connections equally in practice.
### Readiness checks
@@ -351,6 +352,50 @@ Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
| ------- | ------------ | -------- |
| 443 | 22 | TCP |
+### SSL
+
+The next question is how you will handle SSL in your environment.
+There are several different options:
+
+- [The application node terminates SSL](#application-node-terminates-ssl).
+- [The load balancer terminates SSL without backend SSL](#load-balancer-terminates-ssl-without-backend-ssl)
+ and communication is not secure between the load balancer and the application node.
+- [The load balancer terminates SSL with backend SSL](#load-balancer-terminates-ssl-with-backend-ssl)
+ and communication is *secure* between the load balancer and the application node.
+
+#### Application node terminates SSL
+
+Configure your load balancer to pass connections on port 443 as `TCP` rather
+than `HTTP(S)` protocol. This will pass the connection to the application node's
+NGINX service untouched. NGINX will have the SSL certificate and listen on port 443.
+
+See the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
+for details on managing SSL certificates and configuring NGINX.
+
+#### Load balancer terminates SSL without backend SSL
+
+Configure your load balancer to use the `HTTP(S)` protocol rather than `TCP`.
+The load balancer will then be responsible for managing SSL certificates and
+terminating SSL.
+
+Since communication between the load balancer and GitLab will not be secure,
+there is some additional configuration needed. See the
+[proxied SSL documentation](https://docs.gitlab.com/omnibus/settings/ssl.html#configure-a-reverse-proxy-or-load-balancer-ssl-termination)
+for details.
+
+#### Load balancer terminates SSL with backend SSL
+
+Configure your load balancers to use the 'HTTP(S)' protocol rather than 'TCP'.
+The load balancers will be responsible for managing SSL certificates that
+end users will see.
+
+Traffic will also be secure between the load balancers and NGINX in this
+scenario. There is no need to add configuration for proxied SSL since the
+connection will be secure all the way. However, configuration will need to be
+added to GitLab to configure SSL certificates. See
+the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
+for details on managing SSL certificates and configuring NGINX.
+
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
Back to setup components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
@@ -415,8 +460,14 @@ backend praefect
```
Refer to your preferred Load Balancer's documentation for further guidance.
-Also ensure that the routing methods used are distributing calls evenly across
-all nodes.
+
+### Balancing algorithm
+
+We recommend that a least-connection-based load balancing algorithm or equivalent
+is used wherever possible to ensure equal spread of calls to the nodes and good performance.
+
+We don't recommend the use of round-robin algorithms as they are known to not
+spread connections equally in practice.
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
@@ -1168,6 +1219,12 @@ NOTE:
Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster).
For implementations with sharded Gitaly, use the same Gitaly specs. Follow the [separate Gitaly documentation](../gitaly/configure_gitaly.md) instead of this section.
+NOTE:
+Gitaly has been designed and tested with repositories of varying sizes that follow best practices.
+However, large repositories or monorepos not following these practices can significantly
+impact Gitaly performance and requirements.
+Refer to the [Large Repositories](#large-repositories) for more info.
+
The recommended cluster setup includes the following components:
- 3 Gitaly nodes: Replicated storage of Git repositories.
@@ -1475,9 +1532,15 @@ The [Gitaly](../gitaly/index.md) server nodes that make up the cluster have
requirements that are dependent on data and load.
NOTE:
-The Reference Architecture specs have been designed with good headroom in mind
-but for Gitaly, increased specs or additional
-Gitaly Cluster arrays may be required for notably large data sets or load.
+Increased specs for Gitaly nodes may be required in some circumstances such as
+significantly large repositories or if any [additional workloads](#additional-workloads),
+such as [server hooks](../server_hooks.md), have been added.
+
+NOTE:
+Gitaly has been designed and tested with repositories of varying sizes that follow best practices.
+However, large repositories or monorepos not following these practices can significantly
+impact Gitaly performance and requirements.
+Refer to the [Large Repositories](#large-repositories) for more info.
Due to Gitaly having notable input and output requirements, we strongly
recommend that all Gitaly nodes use solid-state drives (SSDs). These SSDs
@@ -1790,7 +1853,7 @@ Updates to example must be made at:
gitlab_rails['auto_migrate'] = false
# Sidekiq
- sidekiqp['enable'] = true
+ sidekiq['enable'] = true
sidekiq['listen_address'] = "0.0.0.0"
# Set number of Sidekiq queue processes to the same number as available CPUs
@@ -2155,7 +2218,7 @@ GitLab has been tested on a number of object storage providers:
- [Amazon S3](https://aws.amazon.com/s3/)
- [Google Cloud Storage](https://cloud.google.com/storage)
- [Digital Ocean Spaces](https://www.digitalocean.com/products/spaces)
-- [Oracle Cloud Infrastructure](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)
+- [Oracle Cloud Infrastructure](https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)
- [OpenStack Swift (S3 compatibility mode)](https://docs.openstack.org/swift/latest/s3_compat.html)
- MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
@@ -2237,6 +2300,10 @@ compute deployments. With this, _stateless_ components can benefit from cloud na
workload management benefits while _stateful_ components are deployed in compute VMs
with Omnibus to benefit from increased permanence.
+Refer to the Helm charts [Advanced configuration](https://docs.gitlab.com/charts/advanced/)
+documentation for setup instructions including guidance on what GitLab secrets to sync
+between Kubernetes and the backend components.
+
NOTE:
This is an **advanced** setup. Running services in Kubernetes is well known
to be complex. **This setup is only recommended** if you have strong working
@@ -2279,7 +2346,7 @@ services where applicable):
| Internal load balancing node<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Redis/Sentinel - Cache<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
| Redis/Sentinel - Persistent<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
-| Gitaly<sup>5</sup> | 3 | 16 vCPU, 60 GB memory | `n1-standard-16` | `m5.4xlarge` |
+| Gitaly<sup>5 6</sup> | 3 | 16 vCPU, 60 GB memory | `n1-standard-16` | `m5.4xlarge` |
| Praefect<sup>5</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Object storage<sup>4</sup> | - | - | - | - |
@@ -2297,6 +2364,7 @@ services where applicable):
- [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work.
4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section.
5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`.
+6. Gitaly has been designed and tested with repositories of varying sizes that follow best practices. However, large repositories or monorepos that don't follow these practices can significantly impact Gitaly requirements. Refer to the [Large Repositories](#large-repositories) for more info.
<!-- markdownlint-enable MD029 -->
NOTE:
@@ -2403,7 +2471,7 @@ ratio for each additional pod.
For further information on resource usage, see the [Sidekiq resources](https://docs.gitlab.com/charts/charts/gitlab/sidekiq/#resources).
-### Supporting
+#### Supporting
The Supporting Node Pool is designed to house all supporting deployments that don't need to be
on the Webservice and Sidekiq pools.
@@ -2416,6 +2484,12 @@ to deploy these in this pool where possible and not in the Webservice or Sidekiq
specifically to accommodate several additional deployments. However, if your deployments don't fit into the
pool as given, you can increase the node pool accordingly.
+## Secrets
+
+When setting up a Cloud Native Hybrid environment, it's worth noting that several secrets should be synced from backend VMs from the `/etc/gitlab/gitlab-secrets.json` file into Kubernetes.
+
+For this setup specifically, the [GitLab Rails](https://docs.gitlab.com/charts/installation/secrets.html#gitlab-rails-secret) and [GitLab Shell](https://docs.gitlab.com/charts/installation/secrets.html#gitlab-rails-secret) secrets should be synced.
+
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
Back to setup components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
diff --git a/doc/administration/reference_architectures/1k_users.md b/doc/administration/reference_architectures/1k_users.md
index a8e0e23512f..2a9636b6e05 100644
--- a/doc/administration/reference_architectures/1k_users.md
+++ b/doc/administration/reference_architectures/1k_users.md
@@ -82,10 +82,23 @@ Any "burstable" instance types are not recommended due to inconsistent performan
### Supported infrastructure
-As a general guidance, GitLab should run on most infrastructure such as reputable Cloud Providers (AWS, GCP, Azure) and their services, or self managed (ESXi) that meet both the specs detailed above, as well as any requirements in this section. However, this does not constitute a guarantee for every potential permutation.
+As a general guidance, GitLab should run on most infrastructure such as reputable Cloud Providers (AWS, GCP) and their services,
+or self managed (ESXi) that meet both the specs detailed above, as well as any requirements in this section.
+However, this does not constitute a guarantee for every potential permutation.
See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+### Additional workloads
+
+The Reference Architectures have been [designed and tested](index.md#validation-and-test-results) for standard GitLab setups with
+good headroom in mind to cover most scenarios. However, if any additional workloads are being added on the nodes,
+such as security software, you may still need to adjust the specs accordingly to compensate.
+
+This also applies for some GitLab features where it's possible to run custom scripts, for example [server hooks](../server_hooks.md).
+
+As a general rule, it's recommended to have robust monitoring in place to measure the impact of
+any additional workloads to inform any changes needed to be made.
+
### Swap
In addition to the stated configurations, we recommend having at least 2 GB of
diff --git a/doc/administration/reference_architectures/25k_users.md b/doc/administration/reference_architectures/25k_users.md
index 7d67ac48b73..84eba01fe11 100644
--- a/doc/administration/reference_architectures/25k_users.md
+++ b/doc/administration/reference_architectures/25k_users.md
@@ -28,7 +28,7 @@ full list of reference architectures, see
| Internal load balancing node<sup>3</sup> | 1 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` |
| Redis/Sentinel - Cache<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
| Redis/Sentinel - Persistent<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
-| Gitaly<sup>5</sup> | 3 | 32 vCPU, 120 GB memory | `n1-standard-32` | `m5.8xlarge` |
+| Gitaly<sup>5 6</sup> | 3 | 32 vCPU, 120 GB memory | `n1-standard-32` | `m5.8xlarge` |
| Praefect<sup>5</sup> | 3 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` |
| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Sidekiq | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
@@ -50,6 +50,7 @@ full list of reference architectures, see
- [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work.
4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section.
5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`.
+6. Gitaly has been designed and tested with repositories of varying sizes that follow best practices. However, large repositories or monorepos that don't follow these practices can significantly impact Gitaly requirements. Refer to the [Large Repositories](#large-repositories) for more info.
<!-- markdownlint-enable MD029 -->
NOTE:
@@ -158,10 +159,45 @@ Any "burstable" instance types are not recommended due to inconsistent performan
### Supported infrastructure
-As a general guidance, GitLab should run on most infrastructure such as reputable Cloud Providers (AWS, GCP) and their services, or self managed (ESXi) that meet both the specs detailed above, as well as any requirements in this section. However, this does not constitute a guarantee for every potential permutation.
+As a general guidance, GitLab should run on most infrastructure such as reputable Cloud Providers (AWS, GCP, Azure) and their services,
+or self managed (ESXi) that meet both the specs detailed above, as well as any requirements in this section.
+However, this does not constitute a guarantee for every potential permutation.
See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+### Additional workloads
+
+The Reference Architectures have been [designed and tested](index.md#validation-and-test-results) for standard GitLab setups with
+good headroom in mind to cover most scenarios. However, if any additional workloads are being added on the nodes,
+such as security software, you may still need to adjust the specs accordingly to compensate.
+
+This also applies for some GitLab features where it's possible to run custom scripts, for example [server hooks](../server_hooks.md).
+
+As a general rule, it's recommended to have robust monitoring in place to measure the impact of
+any additional workloads to inform any changes needed to be made.
+
+### Large repositories
+
+The Reference Architectures were tested with repositories of varying sizes that follow best practices.
+
+However, large repositories or monorepos (several gigabytes or more) can **significantly** impact the performance
+of Git and in turn the environment itself if best practices aren't being followed such as not storing
+binary or blob files in LFS. Repositories are at the core of any environment the consequences can be wide-ranging
+when they are not optimized. Some examples of this impact include [Git packing operations](https://git-scm.com/book/en/v2/Git-Internals-Packfiles)
+taking longer and consuming high CPU / Memory resources or Git checkouts taking longer that affect both users and
+CI pipelines alike.
+
+As such, large repositories come with notable cost and typically will require more resources to handle,
+significantly so in some cases. It's therefore **strongly** recommended then to review large repositories
+to ensure they maintain good repo health and reduce their size wherever possible.
+
+NOTE:
+If best practices aren't followed and large repositories are present on the environment,
+increased Gitaly specs may be required to ensure stable performance.
+
+Refer to the [Managing large repositories documentation](../../user/project/repository/managing_large_repositories.md)
+for more information and guidance.
+
### Praefect PostgreSQL
It's worth noting that at this time [Praefect requires its own database server](../gitaly/praefect.md#postgresql) and
@@ -243,8 +279,7 @@ In a multi-node GitLab configuration, you'll need a load balancer to route
traffic to the application servers. The specifics on which load balancer to use
or its exact configuration is beyond the scope of GitLab documentation. We assume
that if you're managing multi-node systems like GitLab, you already have a load
-balancer of choice and that the routing methods used are distributing calls evenly
-between all nodes. Some load balancer examples include HAProxy (open-source),
+balancer of choice. Some load balancer examples include HAProxy (open-source),
F5 Big-IP LTM, and Citrix Net Scaler. This documentation outline the ports and
protocols needed for use with GitLab.
@@ -261,38 +296,13 @@ There are several different options:
- [The load balancer terminates SSL with backend SSL](#load-balancer-terminates-ssl-with-backend-ssl)
and communication is *secure* between the load balancer and the application node.
-### Application node terminates SSL
-
-Configure your load balancer to pass connections on port 443 as `TCP` rather
-than `HTTP(S)` protocol. This will pass the connection to the application node's
-NGINX service untouched. NGINX will have the SSL certificate and listen on port 443.
-
-See the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
-for details on managing SSL certificates and configuring NGINX.
-
-### Load balancer terminates SSL without backend SSL
-
-Configure your load balancer to use the `HTTP(S)` protocol rather than `TCP`.
-The load balancer will then be responsible for managing SSL certificates and
-terminating SSL.
-
-Since communication between the load balancer and GitLab will not be secure,
-there is some additional configuration needed. See the
-[proxied SSL documentation](https://docs.gitlab.com/omnibus/settings/ssl.html#configure-a-reverse-proxy-or-load-balancer-ssl-termination)
-for details.
+### Balancing algorithm
-### Load balancer terminates SSL with backend SSL
+We recommend that a least-connection load balancing algorithm or equivalent
+is used wherever possible to ensure equal spread of calls to the nodes and good performance.
-Configure your load balancers to use the 'HTTP(S)' protocol rather than 'TCP'.
-The load balancers will be responsible for managing SSL certificates that
-end users will see.
-
-Traffic will also be secure between the load balancers and NGINX in this
-scenario. There is no need to add configuration for proxied SSL since the
-connection will be secure all the way. However, configuration will need to be
-added to GitLab to configure SSL certificates. See the
-[HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
-for details on managing SSL certificates and configuring NGINX.
+We don't recommend the use of round-robin algorithms as they are known to not
+spread connections equally in practice.
### Readiness checks
@@ -353,6 +363,50 @@ Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
| ------- | ------------ | -------- |
| 443 | 22 | TCP |
+### SSL
+
+The next question is how you will handle SSL in your environment.
+There are several different options:
+
+- [The application node terminates SSL](#application-node-terminates-ssl).
+- [The load balancer terminates SSL without backend SSL](#load-balancer-terminates-ssl-without-backend-ssl)
+ and communication is not secure between the load balancer and the application node.
+- [The load balancer terminates SSL with backend SSL](#load-balancer-terminates-ssl-with-backend-ssl)
+ and communication is *secure* between the load balancer and the application node.
+
+#### Application node terminates SSL
+
+Configure your load balancer to pass connections on port 443 as `TCP` rather
+than `HTTP(S)` protocol. This will pass the connection to the application node's
+NGINX service untouched. NGINX will have the SSL certificate and listen on port 443.
+
+See the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
+for details on managing SSL certificates and configuring NGINX.
+
+#### Load balancer terminates SSL without backend SSL
+
+Configure your load balancer to use the `HTTP(S)` protocol rather than `TCP`.
+The load balancer will then be responsible for managing SSL certificates and
+terminating SSL.
+
+Since communication between the load balancer and GitLab will not be secure,
+there is some additional configuration needed. See the
+[proxied SSL documentation](https://docs.gitlab.com/omnibus/settings/ssl.html#configure-a-reverse-proxy-or-load-balancer-ssl-termination)
+for details.
+
+#### Load balancer terminates SSL with backend SSL
+
+Configure your load balancers to use the 'HTTP(S)' protocol rather than 'TCP'.
+The load balancers will be responsible for managing SSL certificates that
+end users will see.
+
+Traffic will also be secure between the load balancers and NGINX in this
+scenario. There is no need to add configuration for proxied SSL since the
+connection will be secure all the way. However, configuration will need to be
+added to GitLab to configure SSL certificates. See
+the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
+for details on managing SSL certificates and configuring NGINX.
+
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
Back to setup components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
@@ -417,8 +471,20 @@ backend praefect
```
Refer to your preferred Load Balancer's documentation for further guidance.
-Also ensure that the routing methods used are distributing calls evenly across
-all nodes.
+
+### Balancing algorithm
+
+We recommend that a least-connection load balancing algorithm or equivalent
+is used wherever possible to ensure equal spread of calls to the nodes and good performance.
+
+We don't recommend the use of round-robin algorithms as they are known to not
+spread connections equally in practice.
+
+<div align="right">
+ <a type="button" class="btn btn-default" href="#setup-components">
+ Back to setup components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
+ </a>
+</div>
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
@@ -1173,6 +1239,12 @@ NOTE:
Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster).
For implementations with sharded Gitaly, use the same Gitaly specs. Follow the [separate Gitaly documentation](../gitaly/configure_gitaly.md) instead of this section.
+NOTE:
+Gitaly has been designed and tested with repositories of varying sizes that follow best practices.
+However, large repositories or monorepos not following these practices can significantly
+impact Gitaly performance and requirements.
+Refer to the [Large Repositories](#large-repositories) for more info.
+
The recommended cluster setup includes the following components:
- 3 Gitaly nodes: Replicated storage of Git repositories.
@@ -1478,9 +1550,15 @@ The [Gitaly](../gitaly/index.md) server nodes that make up the cluster have
requirements that are dependent on data and load.
NOTE:
-The Reference Architecture specs have been designed with good headroom in mind
-but for Gitaly, increased specs or additional
-Gitaly Cluster arrays may be required for notably large data sets or load.
+Increased specs for Gitaly nodes may be required in some circumstances such as
+significantly large repositories or if any [additional workloads](#additional-workloads),
+such as [server hooks](../server_hooks.md), have been added.
+
+NOTE:
+Gitaly has been designed and tested with repositories of varying sizes that follow best practices.
+However, large repositories or monorepos not following these practices can significantly
+impact Gitaly performance and requirements.
+Refer to the [Large Repositories](#large-repositories) for more info.
Due to Gitaly having notable input and output requirements, we strongly
recommend that all Gitaly nodes use solid-state drives (SSDs). These SSDs
@@ -2159,7 +2237,7 @@ GitLab has been tested on a number of object storage providers:
- [Amazon S3](https://aws.amazon.com/s3/)
- [Google Cloud Storage](https://cloud.google.com/storage)
- [Digital Ocean Spaces](https://www.digitalocean.com/products/spaces)
-- [Oracle Cloud Infrastructure](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)
+- [Oracle Cloud Infrastructure](https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)
- [OpenStack Swift (S3 compatibility mode)](https://docs.openstack.org/swift/latest/s3_compat.html)
- MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
@@ -2241,6 +2319,10 @@ compute deployments. With this, _stateless_ components can benefit from cloud na
workload management benefits while _stateful_ components are deployed in compute VMs
with Omnibus to benefit from increased permanence.
+Refer to the Helm charts [Advanced configuration](https://docs.gitlab.com/charts/advanced/)
+documentation for setup instructions including guidance on what GitLab secrets to sync
+between Kubernetes and the backend components.
+
NOTE:
This is an **advanced** setup. Running services in Kubernetes is well known
to be complex. **This setup is only recommended** if you have strong working
@@ -2283,7 +2365,7 @@ services where applicable):
| Internal load balancing node<sup>3</sup> | 1 | 4 vCPU, 3.6GB memory | `n1-highcpu-4` | `c5.xlarge` |
| Redis/Sentinel - Cache<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
| Redis/Sentinel - Persistent<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
-| Gitaly<sup>5</sup> | 3 | 32 vCPU, 120 GB memory | `n1-standard-32` | `m5.8xlarge` |
+| Gitaly<sup>5 6</sup> | 3 | 32 vCPU, 120 GB memory | `n1-standard-32` | `m5.8xlarge` |
| Praefect<sup>5</sup> | 3 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` |
| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Object storage<sup>4</sup> | - | - | - | - |
@@ -2301,6 +2383,7 @@ services where applicable):
- [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work.
4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section.
5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`.
+6. Gitaly has been designed and tested with repositories of varying sizes that follow best practices. However, large repositories or monorepos that don't follow these practices can significantly impact Gitaly requirements. Refer to the [Large Repositories](#large-repositories) for more info.
<!-- markdownlint-enable MD029 -->
NOTE:
diff --git a/doc/administration/reference_architectures/2k_users.md b/doc/administration/reference_architectures/2k_users.md
index 61ea435f63f..1acae93f764 100644
--- a/doc/administration/reference_architectures/2k_users.md
+++ b/doc/administration/reference_architectures/2k_users.md
@@ -25,7 +25,7 @@ For a full list of reference architectures, see
| Load balancer<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` |
| PostgreSQL<sup>1</sup> | 1 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | `m5.large` | `D2s v3` |
| Redis<sup>2</sup> | 1 | 1 vCPU, 3.75 GB memory | `n1-standard-1` | `m5.large` | `D2s v3` |
-| Gitaly | 1 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` |
+| Gitaly<sup>5</sup> | 1 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` | `D4s v3` |
| GitLab Rails | 2 | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | `c5.2xlarge` | `F8s v2` |
| Monitoring node | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` | `F2s v2` |
| Object storage<sup>4</sup> | - | - | - | - | - |
@@ -35,13 +35,14 @@ For a full list of reference architectures, see
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
- [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work.
- [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo.
- - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/services/postgresql/) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61).
+ - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/products/postgresql/#overview) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61).
- Consul is primarily used for Omnibus PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery.
2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
- [Google Memorystore](https://cloud.google.com/memorystore) and [Amazon ElastiCache](https://aws.amazon.com/elasticache/) are known to work.
3. Can be optionally run on reputable third-party load balancing services (LB PaaS). See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
- [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work.
4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section.
+5. Gitaly has been designed and tested with repositories of varying sizes that follow best practices. However, large repositories or monorepos that don't follow these practices can significantly impact Gitaly requirements. Refer to the [Large Repositories](#large-repositories) for more info.
<!-- markdownlint-enable MD029 -->
NOTE:
@@ -94,10 +95,45 @@ Any "burstable" instance types are not recommended due to inconsistent performan
### Supported infrastructure
-As a general guidance, GitLab should run on most infrastructure such as reputable Cloud Providers (AWS, GCP, Azure) and their services, or self managed (ESXi) that meet both the specs detailed above, as well as any requirements in this section. However, this does not constitute a guarantee for every potential permutation.
+As a general guidance, GitLab should run on most infrastructure such as reputable Cloud Providers (AWS, GCP) and their services,
+or self managed (ESXi) that meet both the specs detailed above, as well as any requirements in this section.
+However, this does not constitute a guarantee for every potential permutation.
See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+### Additional workloads
+
+The Reference Architectures have been [designed and tested](index.md#validation-and-test-results) for standard GitLab setups with
+good headroom in mind to cover most scenarios. However, if any additional workloads are being added on the nodes,
+such as security software, you may still need to adjust the specs accordingly to compensate.
+
+This also applies for some GitLab features where it's possible to run custom scripts, for example [server hooks](../server_hooks.md).
+
+As a general rule, it's recommended to have robust monitoring in place to measure the impact of
+any additional workloads to inform any changes needed to be made.
+
+### Large repositories
+
+The Reference Architectures were tested with repositories of varying sizes that follow best practices.
+
+However, large repositories or monorepos (several gigabytes or more) can **significantly** impact the performance
+of Git and in turn the environment itself if best practices aren't being followed such as not storing
+binary or blob files in LFS. Repositories are at the core of any environment the consequences can be wide-ranging
+when they are not optimized. Some examples of this impact include [Git packing operations](https://git-scm.com/book/en/v2/Git-Internals-Packfiles)
+taking longer and consuming high CPU / Memory resources or Git checkouts taking longer that affect both users and
+CI pipelines alike.
+
+As such, large repositories come with notable cost and typically will require more resources to handle,
+significantly so in some cases. It's therefore **strongly** recommended then to review large repositories
+to ensure they maintain good repo health and reduce their size wherever possible.
+
+NOTE:
+If best practices aren't followed and large repositories are present on the environment,
+increased Gitaly specs may be required to ensure stable performance.
+
+Refer to the [Managing large repositories documentation](../../user/project/repository/managing_large_repositories.md)
+for more information and guidance.
+
## Setup components
To set up GitLab and its components to accommodate up to 2,000 users:
@@ -127,8 +163,7 @@ In a multi-node GitLab configuration, you'll need a load balancer to route
traffic to the application servers. The specifics on which load balancer to use
or its exact configuration is beyond the scope of GitLab documentation. We assume
that if you're managing multi-node systems like GitLab, you already have a load
-balancer of choice and that the routing methods used are distributing calls evenly
-between all nodes. Some load balancer examples include HAProxy (open-source),
+balancer of choice. Some load balancer examples include HAProxy (open-source),
F5 Big-IP LTM, and Citrix Net Scaler. This documentation outline the ports and
protocols needed for use with GitLab.
@@ -145,36 +180,13 @@ several different options:
- [The load balancer terminates SSL with backend SSL](#load-balancer-terminates-ssl-with-backend-ssl)
and communication is *secure* between the load balancer and the application node.
-### Application node terminates SSL
-
-Configure your load balancer to pass connections on port 443 as `TCP` instead
-of `HTTP(S)`. This will pass the connection unaltered to the application node's
-NGINX service, which has the SSL certificate and listens to port 443.
-
-For details about managing SSL certificates and configuring NGINX, see the
-[HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
-
-### Load balancer terminates SSL without backend SSL
-
-Configure your load balancer to use the `HTTP(S)` protocol instead of `TCP`.
-The load balancer will be responsible for both managing SSL certificates and
-terminating SSL.
-
-Due to communication between the load balancer and GitLab not being secure,
-you'll need to complete some additional configuration. For details, see the
-[proxied SSL documentation](https://docs.gitlab.com/omnibus/settings/ssl.html#configure-a-reverse-proxy-or-load-balancer-ssl-termination).
-
-### Load balancer terminates SSL with backend SSL
+### Balancing algorithm
-Configure your load balancers (or single balancer, if you have only one) to use
-the `HTTP(S)` protocol rather than `TCP`. The load balancers will be
-responsible for the managing SSL certificates for end users.
+We recommend that a least-connection load balancing algorithm or equivalent
+is used wherever possible to ensure equal spread of calls to the nodes and good performance.
-Traffic will be secure between the load balancers and NGINX in this scenario,
-and there's no need to add a configuration for proxied SSL. However, you'll
-need to add a configuration to GitLab to configure SSL certificates. For
-details about managing SSL certificates and configuring NGINX, see the
-[HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html).
+We don't recommend the use of round-robin algorithms as they are known to not
+spread connections equally in practice.
### Readiness checks
@@ -186,56 +198,99 @@ connect.
### Ports
-The basic load balancer ports you should use are described in the following
-table:
+The basic ports to be used are shown in the table below.
-| Port | Backend Port | Protocol |
+| LB Port | Backend Port | Protocol |
| ------- | ------------ | ------------------------ |
| 80 | 80 | HTTP (*1*) |
| 443 | 443 | TCP or HTTPS (*1*) (*2*) |
| 22 | 22 | TCP |
-- (*1*): [Web terminal](../../ci/environments/index.md#web-terminals-deprecated) support
- requires your load balancer to correctly handle WebSocket connections.
- When using HTTP or HTTPS proxying, your load balancer must be configured
- to pass through the `Connection` and `Upgrade` hop-by-hop headers. For
- details, see the [web terminal](../integration/terminal.md) integration guide.
-- (*2*): When using the HTTPS protocol for port 443, you'll need to add an SSL
- certificate to the load balancers. If you need to terminate SSL at the
- GitLab application server, use the TCP protocol.
+- (*1*): [Web terminal](../../ci/environments/index.md#web-terminals-deprecated) support requires
+ your load balancer to correctly handle WebSocket connections. When using
+ HTTP or HTTPS proxying, this means your load balancer must be configured
+ to pass through the `Connection` and `Upgrade` hop-by-hop headers. See the
+ [web terminal](../integration/terminal.md) integration guide for
+ more details.
+- (*2*): When using HTTPS protocol for port 443, you will need to add an SSL
+ certificate to the load balancers. If you wish to terminate SSL at the
+ GitLab application server instead, use TCP protocol.
If you're using GitLab Pages with custom domain support you will need some
-additional port configurations. GitLab Pages requires a separate virtual IP
-address. Configure DNS to point the `pages_external_url` from
-`/etc/gitlab/gitlab.rb` to the new virtual IP address. For more information,
-see the [GitLab Pages documentation](../pages/index.md).
+additional port configurations.
+GitLab Pages requires a separate virtual IP address. Configure DNS to point the
+`pages_external_url` from `/etc/gitlab/gitlab.rb` at the new virtual IP address. See the
+[GitLab Pages documentation](../pages/index.md) for more information.
-| Port | Backend Port | Protocol |
+| LB Port | Backend Port | Protocol |
| ------- | ------------- | --------- |
| 80 | Varies (*1*) | HTTP |
| 443 | Varies (*1*) | TCP (*2*) |
- (*1*): The backend port for GitLab Pages depends on the
`gitlab_pages['external_http']` and `gitlab_pages['external_https']`
- settings. For details, see the [GitLab Pages documentation](../pages/index.md).
-- (*2*): Port 443 for GitLab Pages must use the TCP protocol. Users can
- configure custom domains with custom SSL, which wouldn't be possible if SSL
- was terminated at the load balancer.
+ setting. See [GitLab Pages documentation](../pages/index.md) for more details.
+- (*2*): Port 443 for GitLab Pages should always use the TCP protocol. Users can
+ configure custom domains with custom SSL, which would not be possible
+ if SSL was terminated at the load balancer.
#### Alternate SSH Port
Some organizations have policies against opening SSH port 22. In this case,
-it may be helpful to configure an alternate SSH hostname that instead allows
-users to use SSH over port 443. An alternate SSH hostname requires a new
-virtual IP address compared to the previously described GitLab HTTP
-configuration.
+it may be helpful to configure an alternate SSH hostname that allows users
+to use SSH on port 443. An alternate SSH hostname will require a new virtual IP address
+compared to the other GitLab HTTP configuration above.
-Configure DNS for an alternate SSH hostname, such as `altssh.gitlab.example.com`:
+Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
| LB Port | Backend Port | Protocol |
| ------- | ------------ | -------- |
| 443 | 22 | TCP |
+### SSL
+
+The next question is how you will handle SSL in your environment.
+There are several different options:
+
+- [The application node terminates SSL](#application-node-terminates-ssl).
+- [The load balancer terminates SSL without backend SSL](#load-balancer-terminates-ssl-without-backend-ssl)
+ and communication is not secure between the load balancer and the application node.
+- [The load balancer terminates SSL with backend SSL](#load-balancer-terminates-ssl-with-backend-ssl)
+ and communication is *secure* between the load balancer and the application node.
+
+#### Application node terminates SSL
+
+Configure your load balancer to pass connections on port 443 as `TCP` rather
+than `HTTP(S)` protocol. This will pass the connection to the application node's
+NGINX service untouched. NGINX will have the SSL certificate and listen on port 443.
+
+See the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
+for details on managing SSL certificates and configuring NGINX.
+
+#### Load balancer terminates SSL without backend SSL
+
+Configure your load balancer to use the `HTTP(S)` protocol rather than `TCP`.
+The load balancer will then be responsible for managing SSL certificates and
+terminating SSL.
+
+Since communication between the load balancer and GitLab will not be secure,
+there is some additional configuration needed. See the
+[proxied SSL documentation](https://docs.gitlab.com/omnibus/settings/ssl.html#configure-a-reverse-proxy-or-load-balancer-ssl-termination)
+for details.
+
+#### Load balancer terminates SSL with backend SSL
+
+Configure your load balancers to use the 'HTTP(S)' protocol rather than 'TCP'.
+The load balancers will be responsible for managing SSL certificates that
+end users will see.
+
+Traffic will also be secure between the load balancers and NGINX in this
+scenario. There is no need to add configuration for proxied SSL since the
+connection will be secure all the way. However, configuration will need to be
+added to GitLab to configure SSL certificates. See
+the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
+for details on managing SSL certificates and configuring NGINX.
+
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
Back to setup components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
@@ -407,9 +462,15 @@ are supported and can be added if needed.
specifically the number of projects and those projects' sizes.
NOTE:
-The Reference Architecture specs have been designed with good headroom in mind
-but for Gitaly, increased specs or switching to Gitaly Cluster
-may be required for notably large data sets or load.
+Increased specs for Gitaly nodes may be required in some circumstances such as
+significantly large repositories or if any [additional workloads](#additional-workloads),
+such as [server hooks](../server_hooks.md), have been added.
+
+NOTE:
+Gitaly has been designed and tested with repositories of varying sizes that follow best practices.
+However, large repositories or monorepos not following these practices can significantly
+impact Gitaly performance and requirements.
+Refer to the [Large Repositories](#large-repositories) for more info.
Due to Gitaly having notable input and output requirements, we strongly
recommend that all Gitaly nodes use solid-state drives (SSDs). These SSDs
@@ -878,7 +939,7 @@ GitLab has been tested on a number of object storage providers:
- [Amazon S3](https://aws.amazon.com/s3/)
- [Google Cloud Storage](https://cloud.google.com/storage)
- [Digital Ocean Spaces](https://www.digitalocean.com/products/spaces)
-- [Oracle Cloud Infrastructure](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)
+- [Oracle Cloud Infrastructure](https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)
- [OpenStack Swift (S3 compatibility mode)](https://docs.openstack.org/swift/latest/s3_compat.html)
- [Azure Blob storage](https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction)
- MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
@@ -962,7 +1023,9 @@ compute deployments. With this, _stateless_ components can benefit from cloud na
workload management benefits while _stateful_ components are deployed in compute VMs
with Omnibus to benefit from increased permanence.
-The 2,000 reference architecture is not a highly-available setup. To achieve HA, you can follow a modified [3K reference architecture](3k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative).
+Refer to the Helm charts [Advanced configuration](https://docs.gitlab.com/charts/advanced/)
+documentation for setup instructions including guidance on what GitLab secrets to sync
+between Kubernetes and the backend components.
NOTE:
This is an **advanced** setup. Running services in Kubernetes is well known
@@ -971,6 +1034,10 @@ knowledge and experience in Kubernetes. The rest of this
section assumes this.
NOTE:
+The 2,000 reference architecture is not a highly-available setup. To achieve HA,
+you can follow a modified [3K reference architecture](3k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative).
+
+NOTE:
**Gitaly Cluster is not supported to be run in Kubernetes**.
Refer to [epic 6127](https://gitlab.com/groups/gitlab-org/-/epics/6127) for more details.
@@ -1010,7 +1077,7 @@ services where applicable):
1. Can be optionally run on reputable third-party external PaaS PostgreSQL solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
- [Google Cloud SQL](https://cloud.google.com/sql/docs/postgres/high-availability#normal) and [Amazon RDS](https://aws.amazon.com/rds/) are known to work.
- [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo.
- - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/services/postgresql/) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61).
+ - [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is **incompatible** with load balancing enabled by default in [14.4.0](../../update/index.md#1440), and [Azure Database for PostgreSQL](https://azure.microsoft.com/en-gb/products/postgresql/#overview) is **not recommended** due to [performance issues](https://gitlab.com/gitlab-org/quality/reference-architectures/-/issues/61).
- Consul is primarily used for Omnibus PostgreSQL high availability so can be ignored when using a PostgreSQL PaaS setup. However, Consul is also used optionally by Prometheus for Omnibus auto host discovery.
2. Can be optionally run on reputable third-party external PaaS Redis solutions. See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
- [Google Memorystore](https://cloud.google.com/memorystore) and [Amazon ElastiCache](https://aws.amazon.com/elasticache/) are known to work.
diff --git a/doc/administration/reference_architectures/3k_users.md b/doc/administration/reference_architectures/3k_users.md
index 7484fafe1b0..4fc6af3f72e 100644
--- a/doc/administration/reference_architectures/3k_users.md
+++ b/doc/administration/reference_architectures/3k_users.md
@@ -37,7 +37,7 @@ For a full list of reference architectures, see
| PostgreSQL<sup>1</sup> | 3 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | `m5.large` |
| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Internal load balancing node<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
-| Gitaly<sup>5</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
+| Gitaly<sup>5 6</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
| Praefect<sup>5</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Sidekiq | 4 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | `m5.large` |
@@ -59,6 +59,7 @@ For a full list of reference architectures, see
- [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work.
4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section.
5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`.
+6. Gitaly has been designed and tested with repositories of varying sizes that follow best practices. However, large repositories or monorepos that don't follow these practices can significantly impact Gitaly requirements. Refer to the [Large Repositories](#large-repositories) for more info.
<!-- markdownlint-enable MD029 -->
NOTE:
@@ -164,10 +165,45 @@ Any "burstable" instance types are not recommended due to inconsistent performan
### Supported infrastructure
-As a general guidance, GitLab should run on most infrastructure such as reputable Cloud Providers (AWS, GCP) and their services, or self managed (ESXi) that meet both the specs detailed above, as well as any requirements in this section. However, this does not constitute a guarantee for every potential permutation.
+As a general guidance, GitLab should run on most infrastructure such as reputable Cloud Providers (AWS, GCP) and their services,
+or self managed (ESXi) that meet both the specs detailed above, as well as any requirements in this section.
+However, this does not constitute a guarantee for every potential permutation.
See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+### Additional workloads
+
+The Reference Architectures have been [designed and tested](index.md#validation-and-test-results) for standard GitLab setups with
+good headroom in mind to cover most scenarios. However, if any additional workloads are being added on the nodes,
+such as security software, you may still need to adjust the specs accordingly to compensate.
+
+This also applies for some GitLab features where it's possible to run custom scripts, for example [server hooks](../server_hooks.md).
+
+As a general rule, it's recommended to have robust monitoring in place to measure the impact of
+any additional workloads to inform any changes needed to be made.
+
+### Large repositories
+
+The Reference Architectures were tested with repositories of varying sizes that follow best practices.
+
+However, large repositories or monorepos (several gigabytes or more) can **significantly** impact the performance
+of Git and in turn the environment itself if best practices aren't being followed such as not storing
+binary or blob files in LFS. Repositories are at the core of any environment the consequences can be wide-ranging
+when they are not optimized. Some examples of this impact include [Git packing operations](https://git-scm.com/book/en/v2/Git-Internals-Packfiles)
+taking longer and consuming high CPU / Memory resources or Git checkouts taking longer that affect both users and
+CI pipelines alike.
+
+As such, large repositories come with notable cost and typically will require more resources to handle,
+significantly so in some cases. It's therefore **strongly** recommended then to review large repositories
+to ensure they maintain good repo health and reduce their size wherever possible.
+
+NOTE:
+If best practices aren't followed and large repositories are present on the environment,
+increased Gitaly specs may be required to ensure stable performance.
+
+Refer to the [Managing large repositories documentation](../../user/project/repository/managing_large_repositories.md)
+for more information and guidance.
+
### Praefect PostgreSQL
It's worth noting that at this time [Praefect requires its own database server](../gitaly/praefect.md#postgresql) and
@@ -244,8 +280,7 @@ In a multi-node GitLab configuration, you'll need a load balancer to route
traffic to the application servers. The specifics on which load balancer to use
or its exact configuration is beyond the scope of GitLab documentation. We assume
that if you're managing multi-node systems like GitLab, you already have a load
-balancer of choice and that the routing methods used are distributing calls evenly
-between all nodes. Some load balancer examples include HAProxy (open-source),
+balancer of choice. Some load balancer examples include HAProxy (open-source),
F5 Big-IP LTM, and Citrix Net Scaler. This documentation outline the ports and
protocols needed for use with GitLab.
@@ -262,38 +297,13 @@ There are several different options:
- [The load balancer terminates SSL with backend SSL](#load-balancer-terminates-ssl-with-backend-ssl)
and communication is *secure* between the load balancer and the application node.
-### Application node terminates SSL
+### Balancing algorithm
-Configure your load balancer to pass connections on port 443 as `TCP` rather
-than `HTTP(S)` protocol. This will pass the connection to the application node's
-NGINX service untouched. NGINX will have the SSL certificate and listen on port 443.
-
-See the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
-for details on managing SSL certificates and configuring NGINX.
-
-### Load balancer terminates SSL without backend SSL
+We recommend that a least-connection load balancing algorithm or equivalent
+is used wherever possible to ensure equal spread of calls to the nodes and good performance.
-Configure your load balancer to use the `HTTP(S)` protocol rather than `TCP`.
-The load balancer will then be responsible for managing SSL certificates and
-terminating SSL.
-
-Since communication between the load balancer and GitLab will not be secure,
-there is some additional configuration needed. See the
-[proxied SSL documentation](https://docs.gitlab.com/omnibus/settings/ssl.html#configure-a-reverse-proxy-or-load-balancer-ssl-termination)
-for details.
-
-### Load balancer terminates SSL with backend SSL
-
-Configure your load balancers to use the 'HTTP(S)' protocol rather than 'TCP'.
-The load balancers will be responsible for managing SSL certificates that
-end users will see.
-
-Traffic will also be secure between the load balancers and NGINX in this
-scenario. There is no need to add configuration for proxied SSL since the
-connection will be secure all the way. However, configuration will need to be
-added to GitLab to configure SSL certificates. See the
-[HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
-for details on managing SSL certificates and configuring NGINX.
+We don't recommend the use of round-robin algorithms as they are known to not
+spread connections equally in practice.
### Readiness checks
@@ -354,6 +364,50 @@ Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
| ------- | ------------ | -------- |
| 443 | 22 | TCP |
+### SSL
+
+The next question is how you will handle SSL in your environment.
+There are several different options:
+
+- [The application node terminates SSL](#application-node-terminates-ssl).
+- [The load balancer terminates SSL without backend SSL](#load-balancer-terminates-ssl-without-backend-ssl)
+ and communication is not secure between the load balancer and the application node.
+- [The load balancer terminates SSL with backend SSL](#load-balancer-terminates-ssl-with-backend-ssl)
+ and communication is *secure* between the load balancer and the application node.
+
+#### Application node terminates SSL
+
+Configure your load balancer to pass connections on port 443 as `TCP` rather
+than `HTTP(S)` protocol. This will pass the connection to the application node's
+NGINX service untouched. NGINX will have the SSL certificate and listen on port 443.
+
+See the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
+for details on managing SSL certificates and configuring NGINX.
+
+#### Load balancer terminates SSL without backend SSL
+
+Configure your load balancer to use the `HTTP(S)` protocol rather than `TCP`.
+The load balancer will then be responsible for managing SSL certificates and
+terminating SSL.
+
+Since communication between the load balancer and GitLab will not be secure,
+there is some additional configuration needed. See the
+[proxied SSL documentation](https://docs.gitlab.com/omnibus/settings/ssl.html#configure-a-reverse-proxy-or-load-balancer-ssl-termination)
+for details.
+
+#### Load balancer terminates SSL with backend SSL
+
+Configure your load balancers to use the 'HTTP(S)' protocol rather than 'TCP'.
+The load balancers will be responsible for managing SSL certificates that
+end users will see.
+
+Traffic will also be secure between the load balancers and NGINX in this
+scenario. There is no need to add configuration for proxied SSL since the
+connection will be secure all the way. However, configuration will need to be
+added to GitLab to configure SSL certificates. See
+the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
+for details on managing SSL certificates and configuring NGINX.
+
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
Back to setup components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
@@ -418,8 +472,14 @@ backend praefect
```
Refer to your preferred Load Balancer's documentation for further guidance.
-Also ensure that the routing methods used are distributing calls evenly across
-all nodes.
+
+### Balancing algorithm
+
+We recommend that a least-connection load balancing algorithm or equivalent
+is used wherever possible to ensure equal spread of calls to the nodes and good performance.
+
+We don't recommend the use of round-robin algorithms as they are known to not
+spread connections equally in practice.
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
@@ -1114,6 +1174,12 @@ NOTE:
Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster).
For implementations with sharded Gitaly, use the same Gitaly specs. Follow the [separate Gitaly documentation](../gitaly/configure_gitaly.md) instead of this section.
+NOTE:
+Gitaly has been designed and tested with repositories of varying sizes that follow best practices.
+However, large repositories or monorepos not following these practices can significantly
+impact Gitaly performance and requirements.
+Refer to the [Large Repositories](#large-repositories) for more info.
+
The recommended cluster setup includes the following components:
- 3 Gitaly nodes: Replicated storage of Git repositories.
@@ -1418,9 +1484,15 @@ The [Gitaly](../gitaly/index.md) server nodes that make up the cluster have
requirements that are dependent on data and load.
NOTE:
-The Reference Architecture specs have been designed with good headroom in mind
-but for Gitaly, increased specs or additional
-Gitaly Cluster arrays may be required for notably large data sets or load.
+Increased specs for Gitaly nodes may be required in some circumstances such as
+significantly large repositories or if any [additional workloads](#additional-workloads),
+such as [server hooks](../server_hooks.md), have been added.
+
+NOTE:
+Gitaly has been designed and tested with repositories of varying sizes that follow best practices.
+However, large repositories or monorepos not following these practices can significantly
+impact Gitaly performance and requirements.
+Refer to the [Large Repositories](#large-repositories) for more info.
Due to Gitaly having notable input and output requirements, we strongly
recommend that all Gitaly nodes use solid-state drives (SSDs). These SSDs
@@ -2112,7 +2184,7 @@ GitLab has been tested on a number of object storage providers:
- [Amazon S3](https://aws.amazon.com/s3/)
- [Google Cloud Storage](https://cloud.google.com/storage)
- [Digital Ocean Spaces](https://www.digitalocean.com/products/spaces)
-- [Oracle Cloud Infrastructure](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)
+- [Oracle Cloud Infrastructure](https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)
- [OpenStack Swift (S3 compatibility mode)](https://docs.openstack.org/swift/latest/s3_compat.html)
- MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
@@ -2197,7 +2269,6 @@ but with smaller performance requirements, several modifications can be consider
- PostgreSQL and PgBouncer: PgBouncer nodes could be removed and instead be enabled on PostgreSQL nodes with the Internal Load Balancer pointing to them. However, to enable [Database Load Balancing](../postgresql/database_load_balancing.md), a separate PgBouncer array is still required.
- Reducing the node counts: Some node types do not need consensus and can run with fewer nodes (but more than one for redundancy). This will also lead to reduced performance.
- GitLab Rails and Sidekiq: Stateless services don't have a minimum node count. Two are enough for redundancy.
- - Gitaly and Praefect: A quorum is not strictly necessary. Two Gitaly nodes and two Praefect nodes are enough for redundancy.
- PostgreSQL and PgBouncer: A quorum is not strictly necessary. Two PostgreSQL nodes and two PgBouncer nodes are enough for redundancy.
- Running select components in reputable Cloud PaaS solutions: Select components of the GitLab setup can instead be run on Cloud Provider PaaS solutions. By doing this, additional dependent components can also be removed:
- PostgreSQL: Can be run on reputable Cloud PaaS solutions such as Google Cloud SQL or Amazon RDS. In this setup, the PgBouncer and Consul nodes are no longer required:
@@ -2219,6 +2290,10 @@ compute deployments. With this, _stateless_ components can benefit from cloud na
workload management benefits while _stateful_ components are deployed in compute VMs
with Omnibus to benefit from increased permanence.
+Refer to the Helm charts [Advanced configuration](https://docs.gitlab.com/charts/advanced/)
+documentation for setup instructions including guidance on what GitLab secrets to sync
+between Kubernetes and the backend components.
+
NOTE:
This is an **advanced** setup. Running services in Kubernetes is well known
to be complex. **This setup is only recommended** if you have strong working
@@ -2260,7 +2335,7 @@ services where applicable):
| PostgreSQL<sup>1</sup> | 3 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | `m5.large` |
| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Internal load balancing node<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
-| Gitaly<sup>5</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
+| Gitaly<sup>5 6</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
| Praefect<sup>5</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Object storage<sup>4</sup> | - | - | - | - |
@@ -2278,6 +2353,7 @@ services where applicable):
- [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work.
4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section.
5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`.
+6. Gitaly has been designed and tested with repositories of varying sizes that follow best practices. However, large repositories or monorepos that don't follow these practices can significantly impact Gitaly requirements. Refer to the [Large Repositories](#large-repositories) for more info.
<!-- markdownlint-enable MD029 -->
NOTE:
diff --git a/doc/administration/reference_architectures/50k_users.md b/doc/administration/reference_architectures/50k_users.md
index 88fc3649b3f..ca159d62f1f 100644
--- a/doc/administration/reference_architectures/50k_users.md
+++ b/doc/administration/reference_architectures/50k_users.md
@@ -28,7 +28,7 @@ full list of reference architectures, see
| Internal load balancing node<sup>3</sup> | 1 | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | `c5.2xlarge` |
| Redis/Sentinel - Cache<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
| Redis/Sentinel - Persistent<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
-| Gitaly<sup>5</sup> | 3 | 64 vCPU, 240 GB memory | `n1-standard-64` | `m5.16xlarge` |
+| Gitaly<sup>5 6</sup> | 3 | 64 vCPU, 240 GB memory | `n1-standard-64` | `m5.16xlarge` |
| Praefect<sup>5</sup> | 3 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` |
| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Sidekiq | 4 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
@@ -50,6 +50,7 @@ full list of reference architectures, see
- [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work.
4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section.
5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`.
+6. Gitaly has been designed and tested with repositories of varying sizes that follow best practices. However, large repositories or monorepos that don't follow these practices can significantly impact Gitaly requirements. Refer to the [Large Repositories](#large-repositories) for more info.
<!-- markdownlint-enable MD029 -->
NOTE:
@@ -158,10 +159,45 @@ Any "burstable" instance types are not recommended due to inconsistent performan
### Supported infrastructure
-As a general guidance, GitLab should run on most infrastructure such as reputable Cloud Providers (AWS, GCP) and their services, or self managed (ESXi) that meet both the specs detailed above, as well as any requirements in this section. However, this does not constitute a guarantee for every potential permutation.
+As a general guidance, GitLab should run on most infrastructure such as reputable Cloud Providers (AWS, GCP, Azure) and their services,
+or self managed (ESXi) that meet both the specs detailed above, as well as any requirements in this section.
+However, this does not constitute a guarantee for every potential permutation.
See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+### Additional workloads
+
+The Reference Architectures have been [designed and tested](index.md#validation-and-test-results) for standard GitLab setups with
+good headroom in mind to cover most scenarios. However, if any additional workloads are being added on the nodes,
+such as security software, you may still need to adjust the specs accordingly to compensate.
+
+This also applies for some GitLab features where it's possible to run custom scripts, for example [server hooks](../server_hooks.md).
+
+As a general rule, it's recommended to have robust monitoring in place to measure the impact of
+any additional workloads to inform any changes needed to be made.
+
+### Large repositories
+
+The Reference Architectures were tested with repositories of varying sizes that follow best practices.
+
+However, large repositories or monorepos (Several gigabytes or more) can **significantly** impact the performance
+of Git and in turn the environment itself if best practices aren't being followed such as not storing
+binary or blob files in LFS. Repositories are at the core of any environment the consequences can be wide-ranging
+when they are not optimized. Some examples of this impact include [Git packing operations](https://git-scm.com/book/en/v2/Git-Internals-Packfiles)
+taking longer and consuming high CPU / Memory resources or Git checkouts taking longer that affect both users and
+CI pipelines alike.
+
+As such, large repositories come with notable cost and typically will require more resources to handle,
+significantly so in some cases. It's therefore **strongly** recommended then to review large repositories
+to ensure they maintain good repo health and reduce their size wherever possible.
+
+NOTE:
+If best practices aren't followed and large repositories are present on the environment,
+increased Gitaly specs may be required to ensure stable performance.
+
+Refer to the [Managing large repositories documentation](../../user/project/repository/managing_large_repositories.md)
+for more information and guidance.
+
### Praefect PostgreSQL
It's worth noting that at this time [Praefect requires its own database server](../gitaly/praefect.md#postgresql) and
@@ -250,8 +286,7 @@ In a multi-node GitLab configuration, you'll need a load balancer to route
traffic to the application servers. The specifics on which load balancer to use
or its exact configuration is beyond the scope of GitLab documentation. We assume
that if you're managing multi-node systems like GitLab, you already have a load
-balancer of choice and that the routing methods used are distributing calls evenly
-between all nodes. Some load balancer examples include HAProxy (open-source),
+balancer of choice. Some load balancer examples include HAProxy (open-source),
F5 Big-IP LTM, and Citrix Net Scaler. This documentation outline the ports and
protocols needed for use with GitLab.
@@ -259,47 +294,13 @@ This architecture has been tested and validated with [HAProxy](https://www.hapro
as the load balancer. Although other load balancers with similar feature sets
could also be used, those load balancers have not been validated.
-The next question is how you will handle SSL in your environment.
-There are several different options:
-
-- [The application node terminates SSL](#application-node-terminates-ssl).
-- [The load balancer terminates SSL without backend SSL](#load-balancer-terminates-ssl-without-backend-ssl)
- and communication is not secure between the load balancer and the application node.
-- [The load balancer terminates SSL with backend SSL](#load-balancer-terminates-ssl-with-backend-ssl)
- and communication is *secure* between the load balancer and the application node.
-
-### Application node terminates SSL
-
-Configure your load balancer to pass connections on port 443 as `TCP` rather
-than `HTTP(S)` protocol. This will pass the connection to the application node's
-NGINX service untouched. NGINX will have the SSL certificate and listen on port 443.
-
-See the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
-for details on managing SSL certificates and configuring NGINX.
-
-### Load balancer terminates SSL without backend SSL
+### Balancing algorithm
-Configure your load balancer to use the `HTTP(S)` protocol rather than `TCP`.
-The load balancer will then be responsible for managing SSL certificates and
-terminating SSL.
+We recommend that a least-connection load balancing algorithm or equivalent
+is used wherever possible to ensure equal spread of calls to the nodes and good performance.
-Since communication between the load balancer and GitLab will not be secure,
-there is some additional configuration needed. See the
-[proxied SSL documentation](https://docs.gitlab.com/omnibus/settings/ssl.html#configure-a-reverse-proxy-or-load-balancer-ssl-termination)
-for details.
-
-### Load balancer terminates SSL with backend SSL
-
-Configure your load balancers to use the 'HTTP(S)' protocol rather than 'TCP'.
-The load balancers will be responsible for managing SSL certificates that
-end users will see.
-
-Traffic will also be secure between the load balancers and NGINX in this
-scenario. There is no need to add configuration for proxied SSL since the
-connection will be secure all the way. However, configuration will need to be
-added to GitLab to configure SSL certificates. See the
-[HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
-for details on managing SSL certificates and configuring NGINX.
+We don't recommend the use of round-robin algorithms as they are known to not
+spread connections equally in practice.
### Readiness checks
@@ -360,6 +361,50 @@ Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
| ------- | ------------ | -------- |
| 443 | 22 | TCP |
+### SSL
+
+The next question is how you will handle SSL in your environment.
+There are several different options:
+
+- [The application node terminates SSL](#application-node-terminates-ssl).
+- [The load balancer terminates SSL without backend SSL](#load-balancer-terminates-ssl-without-backend-ssl)
+ and communication is not secure between the load balancer and the application node.
+- [The load balancer terminates SSL with backend SSL](#load-balancer-terminates-ssl-with-backend-ssl)
+ and communication is *secure* between the load balancer and the application node.
+
+#### Application node terminates SSL
+
+Configure your load balancer to pass connections on port 443 as `TCP` rather
+than `HTTP(S)` protocol. This will pass the connection to the application node's
+NGINX service untouched. NGINX will have the SSL certificate and listen on port 443.
+
+See the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
+for details on managing SSL certificates and configuring NGINX.
+
+#### Load balancer terminates SSL without backend SSL
+
+Configure your load balancer to use the `HTTP(S)` protocol rather than `TCP`.
+The load balancer will then be responsible for managing SSL certificates and
+terminating SSL.
+
+Since communication between the load balancer and GitLab will not be secure,
+there is some additional configuration needed. See the
+[proxied SSL documentation](https://docs.gitlab.com/omnibus/settings/ssl.html#configure-a-reverse-proxy-or-load-balancer-ssl-termination)
+for details.
+
+#### Load balancer terminates SSL with backend SSL
+
+Configure your load balancers to use the 'HTTP(S)' protocol rather than 'TCP'.
+The load balancers will be responsible for managing SSL certificates that
+end users will see.
+
+Traffic will also be secure between the load balancers and NGINX in this
+scenario. There is no need to add configuration for proxied SSL since the
+connection will be secure all the way. However, configuration will need to be
+added to GitLab to configure SSL certificates. See
+the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
+for details on managing SSL certificates and configuring NGINX.
+
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
Back to setup components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
@@ -424,8 +469,14 @@ backend praefect
```
Refer to your preferred Load Balancer's documentation for further guidance.
-Also ensure that the routing methods used are distributing calls evenly across
-all nodes.
+
+### Balancing algorithm
+
+We recommend that a least-connection load balancing algorithm or equivalent
+is used wherever possible to ensure equal spread of calls to the nodes and good performance.
+
+We don't recommend the use of round-robin algorithms as they are known to not
+spread connections equally in practice.
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
@@ -1181,6 +1232,12 @@ NOTE:
Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster).
For implementations with sharded Gitaly, use the same Gitaly specs. Follow the [separate Gitaly documentation](../gitaly/configure_gitaly.md) instead of this section.
+NOTE:
+Gitaly has been designed and tested with repositories of varying sizes that follow best practices.
+However, large repositories or monorepos not following these practices can significantly
+impact Gitaly performance and requirements.
+Refer to the [Large Repositories](#large-repositories) for more info.
+
The recommended cluster setup includes the following components:
- 3 Gitaly nodes: Replicated storage of Git repositories.
@@ -1488,9 +1545,15 @@ The [Gitaly](../gitaly/index.md) server nodes that make up the cluster have
requirements that are dependent on data and load.
NOTE:
-The Reference Architecture specs have been designed with good headroom in mind
-but for Gitaly, increased specs or additional
-Gitaly Cluster arrays may be required for notably large data sets or load.
+Increased specs for Gitaly nodes may be required in some circumstances such as
+significantly large repositories or if any [additional workloads](#additional-workloads),
+such as [server hooks](../server_hooks.md), have been added.
+
+NOTE:
+Gitaly has been designed and tested with repositories of varying sizes that follow best practices.
+However, large repositories or monorepos not following these practices can significantly
+impact Gitaly performance and requirements.
+Refer to the [Large Repositories](#large-repositories) for more info.
Due to Gitaly having notable input and output requirements, we strongly
recommend that all Gitaly nodes use solid-state drives (SSDs). These SSDs
@@ -2176,7 +2239,7 @@ GitLab has been tested on a number of object storage providers:
- [Amazon S3](https://aws.amazon.com/s3/)
- [Google Cloud Storage](https://cloud.google.com/storage)
- [Digital Ocean Spaces](https://www.digitalocean.com/products/spaces)
-- [Oracle Cloud Infrastructure](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)
+- [Oracle Cloud Infrastructure](https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)
- [OpenStack Swift (S3 compatibility mode)](https://docs.openstack.org/swift/latest/s3_compat.html)
- MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
@@ -2258,6 +2321,10 @@ compute deployments. With this, _stateless_ components can benefit from cloud na
workload management benefits while _stateful_ components are deployed in compute VMs
with Omnibus to benefit from increased permanence.
+Refer to the Helm charts [Advanced configuration](https://docs.gitlab.com/charts/advanced/)
+documentation for setup instructions including guidance on what GitLab secrets to sync
+between Kubernetes and the backend components.
+
NOTE:
This is an **advanced** setup. Running services in Kubernetes is well known
to be complex. **This setup is only recommended** if you have strong working
@@ -2300,7 +2367,7 @@ services where applicable):
| Internal load balancing node<sup>3</sup> | 1 | 8 vCPU, 7.2 GB memory | `n1-highcpu-8` | `c5.2xlarge` |
| Redis/Sentinel - Cache<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
| Redis/Sentinel - Persistent<sup>2</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
-| Gitaly<sup>5</sup> | 3 | 64 vCPU, 240 GB memory | `n1-standard-64` | `m5.16xlarge` |
+| Gitaly<sup>5 6</sup> | 3 | 64 vCPU, 240 GB memory | `n1-standard-64` | `m5.16xlarge` |
| Praefect<sup>5</sup> | 3 | 4 vCPU, 3.6 GB memory | `n1-highcpu-4` | `c5.xlarge` |
| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Object storage<sup>4</sup> | - | - | - | - |
@@ -2318,6 +2385,7 @@ services where applicable):
- [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work.
4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section.
5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`.
+6. Gitaly has been designed and tested with repositories of varying sizes that follow best practices. However, large repositories or monorepos that don't follow these practices can significantly impact Gitaly requirements. Refer to the [Large Repositories](#large-repositories) for more info.
<!-- markdownlint-enable MD029 -->
NOTE:
diff --git a/doc/administration/reference_architectures/5k_users.md b/doc/administration/reference_architectures/5k_users.md
index c8cf35a2e59..a2b92f9c300 100644
--- a/doc/administration/reference_architectures/5k_users.md
+++ b/doc/administration/reference_architectures/5k_users.md
@@ -34,7 +34,7 @@ costly-to-operate environment by using the
| PostgreSQL<sup>1</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Internal load balancing node<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
-| Gitaly<sup>5</sup> | 3 | 8 vCPU, 30 GB memory | `n1-standard-8` | `m5.2xlarge` |
+| Gitaly<sup>5 6</sup> | 3 | 8 vCPU, 30 GB memory | `n1-standard-8` | `m5.2xlarge` |
| Praefect<sup>5</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Sidekiq | 4 | 2 vCPU, 7.5 GB memory | `n1-standard-2` | `m5.large` |
@@ -56,6 +56,7 @@ costly-to-operate environment by using the
- [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work.
4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section.
5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`.
+6. Gitaly has been designed and tested with repositories of varying sizes that follow best practices. However, large repositories or monorepos that don't follow these practices can significantly impact Gitaly requirements. Refer to the [Large Repositories](#large-repositories) for more info.
<!-- markdownlint-enable MD029 -->
NOTE:
@@ -161,10 +162,45 @@ Any "burstable" instance types are not recommended due to inconsistent performan
### Supported infrastructure
-As a general guidance, GitLab should run on most infrastructure such as reputable Cloud Providers (AWS, GCP) and their services, or self managed (ESXi) that meet both the specs detailed above, as well as any requirements in this section. However, this does not constitute a guarantee for every potential permutation.
+As a general guidance, GitLab should run on most infrastructure such as reputable Cloud Providers (AWS, GCP) and their services,
+or self managed (ESXi) that meet both the specs detailed above, as well as any requirements in this section.
+However, this does not constitute a guarantee for every potential permutation.
See [Recommended cloud providers and services](index.md#recommended-cloud-providers-and-services) for more information.
+### Additional workloads
+
+The Reference Architectures have been [designed and tested](index.md#validation-and-test-results) for standard GitLab setups with
+good headroom in mind to cover most scenarios. However, if any additional workloads are being added on the nodes,
+such as security software, you may still need to adjust the specs accordingly to compensate.
+
+This also applies for some GitLab features where it's possible to run custom scripts, for example [server hooks](../server_hooks.md).
+
+As a general rule, it's recommended to have robust monitoring in place to measure the impact of
+any additional workloads to inform any changes needed to be made.
+
+### Large repositories
+
+The Reference Architectures were tested with repositories of varying sizes that follow best practices.
+
+However, large repositories or monorepos (Several gigabytes or more) can **significantly** impact the performance
+of Git and in turn the environment itself if best practices aren't being followed such as not storing
+binary or blob files in LFS. Repositories are at the core of any environment the consequences can be wide-ranging
+when they are not optimized. Some examples of this impact include [Git packing operations](https://git-scm.com/book/en/v2/Git-Internals-Packfiles)
+taking longer and consuming high CPU / Memory resources or Git checkouts taking longer that affect both users and
+CI pipelines alike.
+
+As such, large repositories come with notable cost and typically will require more resources to handle,
+significantly so in some cases. It's therefore **strongly** recommended then to review large repositories
+to ensure they maintain good repo health and reduce their size wherever possible.
+
+NOTE:
+If best practices aren't followed and large repositories are present on the environment,
+increased Gitaly specs may be required to ensure stable performance.
+
+Refer the [Managing large repositories documentation](../../user/project/repository/managing_large_repositories.md)
+for more information and guidance.
+
### Praefect PostgreSQL
It's worth noting that at this time [Praefect requires its own database server](../gitaly/praefect.md#postgresql) and
@@ -237,12 +273,11 @@ The following list includes descriptions of each server and its assigned IP:
## Configure the external load balancer
-In a multi-node GitLab configuration, you need a load balancer to route
+In a multi-node GitLab configuration, you'll need a load balancer to route
traffic to the application servers. The specifics on which load balancer to use
or its exact configuration is beyond the scope of GitLab documentation. We assume
that if you're managing multi-node systems like GitLab, you already have a load
-balancer of choice and that the routing methods used are distributing calls evenly
-between all nodes. Some load balancer examples include HAProxy (open-source),
+balancer of choice. Some load balancer examples include HAProxy (open-source),
F5 Big-IP LTM, and Citrix Net Scaler. This documentation outline the ports and
protocols needed for use with GitLab.
@@ -259,45 +294,20 @@ There are several different options:
- [The load balancer terminates SSL with backend SSL](#load-balancer-terminates-ssl-with-backend-ssl)
and communication is *secure* between the load balancer and the application node.
-### Application node terminates SSL
-
-Configure your load balancer to pass connections on port 443 as `TCP` rather
-than `HTTP(S)` protocol. This passes the connection to the application node's
-NGINX service untouched. NGINX has the SSL certificate and listen on port 443.
+### Balancing algorithm
-See the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
-for details on managing SSL certificates and configuring NGINX.
+We recommend that a least-connection load balancing algorithm or equivalent
+is used wherever possible to ensure equal spread of calls to the nodes and good performance.
-### Load balancer terminates SSL without backend SSL
-
-Configure your load balancer to use the `HTTP(S)` protocol rather than `TCP`.
-The load balancer is then responsible for managing SSL certificates and
-terminating SSL.
-
-Since communication between the load balancer and GitLab is not secure,
-there is some additional configuration needed. See the
-[proxied SSL documentation](https://docs.gitlab.com/omnibus/settings/ssl.html#configure-a-reverse-proxy-or-load-balancer-ssl-termination)
-for details.
-
-### Load balancer terminates SSL with backend SSL
-
-Configure your load balancers to use the 'HTTP(S)' protocol rather than 'TCP'.
-The load balancers are responsible for managing SSL certificates that
-end users see.
-
-Traffic is also secure between the load balancers and NGINX in this
-scenario. There is no need to add configuration for proxied SSL since the
-connection is secure all the way. However, configuration needs to be
-added to GitLab to configure SSL certificates. See the
-[HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
-for details on managing SSL certificates and configuring NGINX.
+We don't recommend the use of round-robin algorithms as they are known to not
+spread connections equally in practice.
### Readiness checks
Ensure the external load balancer only routes to working services with built
in monitoring endpoints. The [readiness checks](../../user/admin_area/monitoring/health_check.md)
all require [additional configuration](../monitoring/ip_allowlist.md)
-on the nodes being checked, otherwise, the external load balancer is not able to
+on the nodes being checked, otherwise, the external load balancer will not be able to
connect.
### Ports
@@ -316,11 +326,11 @@ The basic ports to be used are shown in the table below.
to pass through the `Connection` and `Upgrade` hop-by-hop headers. See the
[web terminal](../integration/terminal.md) integration guide for
more details.
-- (*2*): When using HTTPS protocol for port 443, you need to add an SSL
+- (*2*): When using HTTPS protocol for port 443, you will need to add an SSL
certificate to the load balancers. If you wish to terminate SSL at the
GitLab application server instead, use TCP protocol.
-If you're using GitLab Pages with custom domain support you need some
+If you're using GitLab Pages with custom domain support you will need some
additional port configurations.
GitLab Pages requires a separate virtual IP address. Configure DNS to point the
`pages_external_url` from `/etc/gitlab/gitlab.rb` at the new virtual IP address. See the
@@ -342,7 +352,7 @@ GitLab Pages requires a separate virtual IP address. Configure DNS to point the
Some organizations have policies against opening SSH port 22. In this case,
it may be helpful to configure an alternate SSH hostname that allows users
-to use SSH on port 443. An alternate SSH hostname requires a new virtual IP address
+to use SSH on port 443. An alternate SSH hostname will require a new virtual IP address
compared to the other GitLab HTTP configuration above.
Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
@@ -351,6 +361,50 @@ Configure DNS for an alternate SSH hostname such as `altssh.gitlab.example.com`.
| ------- | ------------ | -------- |
| 443 | 22 | TCP |
+### SSL
+
+The next question is how you will handle SSL in your environment.
+There are several different options:
+
+- [The application node terminates SSL](#application-node-terminates-ssl).
+- [The load balancer terminates SSL without backend SSL](#load-balancer-terminates-ssl-without-backend-ssl)
+ and communication is not secure between the load balancer and the application node.
+- [The load balancer terminates SSL with backend SSL](#load-balancer-terminates-ssl-with-backend-ssl)
+ and communication is *secure* between the load balancer and the application node.
+
+#### Application node terminates SSL
+
+Configure your load balancer to pass connections on port 443 as `TCP` rather
+than `HTTP(S)` protocol. This will pass the connection to the application node's
+NGINX service untouched. NGINX will have the SSL certificate and listen on port 443.
+
+See the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
+for details on managing SSL certificates and configuring NGINX.
+
+#### Load balancer terminates SSL without backend SSL
+
+Configure your load balancer to use the `HTTP(S)` protocol rather than `TCP`.
+The load balancer will then be responsible for managing SSL certificates and
+terminating SSL.
+
+Since communication between the load balancer and GitLab will not be secure,
+there is some additional configuration needed. See the
+[proxied SSL documentation](https://docs.gitlab.com/omnibus/settings/ssl.html#configure-a-reverse-proxy-or-load-balancer-ssl-termination)
+for details.
+
+#### Load balancer terminates SSL with backend SSL
+
+Configure your load balancers to use the 'HTTP(S)' protocol rather than 'TCP'.
+The load balancers will be responsible for managing SSL certificates that
+end users will see.
+
+Traffic will also be secure between the load balancers and NGINX in this
+scenario. There is no need to add configuration for proxied SSL since the
+connection will be secure all the way. However, configuration will need to be
+added to GitLab to configure SSL certificates. See
+the [HTTPS documentation](https://docs.gitlab.com/omnibus/settings/ssl.html)
+for details on managing SSL certificates and configuring NGINX.
+
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
Back to setup components <i class="fa fa-angle-double-up" aria-hidden="true"></i>
@@ -415,8 +469,14 @@ backend praefect
```
Refer to your preferred Load Balancer's documentation for further guidance.
-Also ensure that the routing methods used are distributing calls evenly across
-all nodes.
+
+### Balancing algorithm
+
+We recommend that a least-connection load balancing algorithm or equivalent
+is used wherever possible to ensure equal spread of calls to the nodes and good performance.
+
+We don't recommend the use of round-robin algorithms as they are known to not
+spread connections equally in practice.
<div align="right">
<a type="button" class="btn btn-default" href="#setup-components">
@@ -1110,6 +1170,12 @@ NOTE:
Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster).
For implementations with sharded Gitaly, use the same Gitaly specs. Follow the [separate Gitaly documentation](../gitaly/configure_gitaly.md) instead of this section.
+NOTE:
+Gitaly has been designed and tested with repositories of varying sizes that follow best practices.
+However, large repositories or monorepos not following these practices can significantly
+impact Gitaly performance and requirements.
+Refer to the [Large Repositories](#large-repositories) for more info.
+
The recommended cluster setup includes the following components:
- 3 Gitaly nodes: Replicated storage of Git repositories.
@@ -1415,9 +1481,15 @@ The [Gitaly](../gitaly/index.md) server nodes that make up the cluster have
requirements that are dependent on data and load.
NOTE:
-The Reference Architecture specs have been designed with good headroom in mind
-but for Gitaly, increased specs or additional
-Gitaly Cluster arrays may be required for notably large data sets or load.
+Increased specs for Gitaly nodes may be required in some circumstances such as
+significantly large repositories or if any [additional workloads](#additional-workloads),
+such as [server hooks](../server_hooks.md), have been added.
+
+NOTE:
+Gitaly has been designed and tested with repositories of varying sizes that follow best practices.
+However, large repositories or monorepos not following these practices can significantly
+impact Gitaly performance and requirements.
+Refer to the [Large Repositories](#large-repositories) for more info.
Due to Gitaly having notable input and output requirements, we strongly
recommend that all Gitaly nodes use solid-state drives (SSDs). These SSDs
@@ -2111,7 +2183,7 @@ GitLab has been tested on a number of object storage providers:
- [Amazon S3](https://aws.amazon.com/s3/)
- [Google Cloud Storage](https://cloud.google.com/storage)
- [Digital Ocean Spaces](https://www.digitalocean.com/products/spaces)
-- [Oracle Cloud Infrastructure](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)
+- [Oracle Cloud Infrastructure](https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm)
- [OpenStack Swift (S3 compatibility mode)](https://docs.openstack.org/swift/latest/s3_compat.html)
- MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation.
@@ -2193,6 +2265,10 @@ compute deployments. With this, _stateless_ components can benefit from cloud na
workload management benefits while _stateful_ components are deployed in compute VMs
with Omnibus to benefit from increased permanence.
+Refer to the Helm charts [Advanced configuration](https://docs.gitlab.com/charts/advanced/)
+documentation for setup instructions including guidance on what GitLab secrets to sync
+between Kubernetes and the backend components.
+
NOTE:
This is an **advanced** setup. Running services in Kubernetes is well known
to be complex. **This setup is only recommended** if you have strong working
@@ -2234,7 +2310,7 @@ services where applicable):
| PostgreSQL<sup>1</sup> | 3 | 4 vCPU, 15 GB memory | `n1-standard-4` | `m5.xlarge` |
| PgBouncer<sup>1</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Internal load balancing node<sup>3</sup> | 1 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
-| Gitaly<sup>5</sup> | 3 | 8 vCPU, 30 GB memory | `n1-standard-8` | `m5.2xlarge` |
+| Gitaly<sup>5 6</sup> | 3 | 8 vCPU, 30 GB memory | `n1-standard-8` | `m5.2xlarge` |
| Praefect<sup>5</sup> | 3 | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Praefect PostgreSQL<sup>1</sup> | 1+ | 2 vCPU, 1.8 GB memory | `n1-highcpu-2` | `c5.large` |
| Object storage<sup>4</sup> | - | - | - | - |
@@ -2252,6 +2328,7 @@ services where applicable):
- [Google Cloud Load Balancing](https://cloud.google.com/load-balancing) and [Amazon Elastic Load Balancing](https://aws.amazon.com/elasticloadbalancing/) are known to work.
4. Should be run on reputable Cloud Provider or Self Managed solutions. More information can be found in the [Configure the object storage](#configure-the-object-storage) section.
5. Gitaly Cluster provides the benefits of fault tolerance, but comes with additional complexity of setup and management. Review the existing [technical limitations and considerations before deploying Gitaly Cluster](../gitaly/index.md#before-deploying-gitaly-cluster). If you want sharded Gitaly, use the same specs listed above for `Gitaly`.
+6. Gitaly has been designed and tested with repositories of varying sizes that follow best practices. However, large repositories or monorepos that don't follow these practices can significantly impact Gitaly requirements. Refer to the [Large Repositories](#large-repositories) for more info.
<!-- markdownlint-enable MD029 -->
NOTE:
diff --git a/doc/administration/reference_architectures/index.md b/doc/administration/reference_architectures/index.md
index 2cf9f2a1e83..467cc332e25 100644
--- a/doc/administration/reference_architectures/index.md
+++ b/doc/administration/reference_architectures/index.md
@@ -43,11 +43,6 @@ The following Cloud Native Hybrid reference architectures, where select recommen
- [Up to 25,000 users](25k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative)
- [Up to 50,000 users](50k_users.md#cloud-native-hybrid-reference-architecture-with-helm-charts-alternative)
-A GitLab [Premium or Ultimate](https://about.gitlab.com/pricing/#self-managed) license is required
-to get assistance from Support with troubleshooting the [2,000 users](2k_users.md)
-and higher reference architectures.
-[Read more about our definition of scaled architectures](https://about.gitlab.com/support/definitions/#definition-of-scaled-architecture).
-
## Deciding which architecture to use
The Reference Architectures are designed to strike a balance between two important factors--performance and resilience.
@@ -109,18 +104,18 @@ Below you can find the above guidance in the form of a decision tree. It's recom
```mermaid
%%{init: { 'theme': 'base' } }%%
-graph TD
+graph TD
L1A(<b>What Reference Architecture should I use?</b>) --> L2A(More than 3000 users?)
L2A -->|No| L3A("<a href=#do-you-need-high-availability-ha>Do you need HA?</a><br>(or Zero-Downtime Upgrades)") --> |Yes| L4A><b>Recommendation</b><br><br>3K architecture with HA<br>including supported modifications]
L3A -->|No| L4B><b>Recommendation</b><br><br>Architecture closest to user<br>count with Backups]
L2A -->|Yes| L3B[Do you have experience with<br/>and want additional resilience<br/>with select components in Kubernetes?]
L3B -->|No| L4C><b>Recommendation</b><br><br>Architecture closest to user<br>count with HA]
L3B -->|Yes| L4D><b>Recommendation</b><br><br>Cloud Native Hybrid architecture<br>closest to user count]
-
+
L5A("<a href=#gitlab-geo-cross-regional-distribution-disaster-recovery>Do you need cross regional distribution or disaster recovery?"</a>) --> |Yes| L6A><b>Additional Recommendation</b><br><br> GitLab Geo]
L4A -.- L5A
- L4B -.- L5A
- L4C -.- L5A
+ L4B -.- L5A
+ L4C -.- L5A
L4D -.- L5A
classDef default fill:#FCA326
@@ -211,7 +206,7 @@ When selecting a database service, it should run a standard, performant, and [su
Several cloud provider services are known not to support the above or have been found to have other issues and aren't recommended:
- [Amazon Aurora](https://aws.amazon.com/rds/aurora/) is incompatible and not supported. See [14.4.0](../../update/index.md#1440) for more details.
-- [Azure Database for PostgreSQL Single Server](https://azure.microsoft.com/en-gb/services/postgresql/#overview) (Single / Flexible) is **strongly not recommended** for use due to notable performance / stability issues or missing functionality. See [Recommendation Notes for Azure](#recommendation-notes-for-azure) for more details.
+- [Azure Database for PostgreSQL Single Server](https://azure.microsoft.com/en-gb/products/postgresql/#overview) (Single / Flexible) is **strongly not recommended** for use due to notable performance / stability issues or missing functionality. See [Recommendation Notes for Azure](#recommendation-notes-for-azure) for more details.
- [Google AlloyDB](https://cloud.google.com/alloydb) and [Amazon RDS Multi-AZ DB clusters](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/multi-az-db-clusters-concepts.html) have not been tested and are not recommended. Both solutions are specifically not expected to work with GitLab Geo.
### Recommendation notes for Azure
@@ -222,7 +217,7 @@ In addition to the above, you should be aware of the additional specific guidanc
- **We outright strongly do not recommend [Azure Database for PostgreSQL Single Server](https://learn.microsoft.com/en-us/azure/postgresql/single-server/overview-single-server)** specifically due to significant performance and stability issues found. **For GitLab 14.0 and higher the service is not supported** due to it only supporting up to PostgreSQL 11.
- A new service, [Azure Database for Postgres Flexible Server](https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/) has been released but due to it missing some functionality we don't recommend it at this time.
-- [Azure Blob Storage](https://azure.microsoft.com/en-gb/services/storage/blobs/) has been found to have performance limits that can impact production use at certain times. However, this has only been seen in larger architectures.
+- [Azure Blob Storage](https://azure.microsoft.com/en-gb/products/storage/blobs/) has been found to have performance limits that can impact production use at certain times. However, this has only been seen in larger architectures.
## Validation and test results
diff --git a/doc/administration/reference_architectures/troubleshooting.md b/doc/administration/reference_architectures/troubleshooting.md
deleted file mode 100644
index a9bf035a528..00000000000
--- a/doc/administration/reference_architectures/troubleshooting.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../configure.md'
-remove_date: '2022-10-24'
----
-
-This document was moved to [another location](../configure.md).
-
-<!-- This redirect file can be deleted after <2022-10-24>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html --> \ No newline at end of file
diff --git a/doc/administration/repository_storage_paths.md b/doc/administration/repository_storage_paths.md
index 492c5306b26..808659132f9 100644
--- a/doc/administration/repository_storage_paths.md
+++ b/doc/administration/repository_storage_paths.md
@@ -45,8 +45,8 @@ For more information on:
WARNING:
The following information is for configuring GitLab to directly access repositories. This
-configuration option is deprecated in favor of using [Gitaly](gitaly/index.md) and is scheduled to
-[be removed in GitLab 14.0](https://gitlab.com/gitlab-org/gitaly/-/issues/1690).
+configuration option is deprecated in favor of using [Gitaly](gitaly/index.md). Gitaly issue
+[1690](https://gitlab.com/gitlab-org/gitaly/-/issues/1690) proposes to remove this configuration option.
To configure repository storage paths:
diff --git a/doc/administration/server_hooks.md b/doc/administration/server_hooks.md
index 6ab4f476e5e..448becb32dc 100644
--- a/doc/administration/server_hooks.md
+++ b/doc/administration/server_hooks.md
@@ -5,16 +5,18 @@ info: To determine the technical writer assigned to the Stage/Group associated w
disqus_identifier: 'https://docs.gitlab.com/ee/administration/custom_hooks.html'
---
-# Server hooks **(FREE SELF)**
+# Git server hooks **(FREE SELF)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196051) in GitLab 12.8 replacing Custom Hooks.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196051) in GitLab 12.8 replacing Custom Hooks.
+> - [Renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/372991) from server hooks to Git server hooks in GitLab 15.6.
-Server hooks run custom logic on the GitLab server. Users can use them to run Git-related tasks such as:
+Git server hooks (not to be confused with [system hooks](system_hooks.md) or [file hooks](file_hooks.md)) run custom logic
+on the GitLab server. You can use them to run Git-related tasks such as:
- Enforcing specific commit policies.
- Performing tasks based on the state of the repository.
-Server hooks use `pre-receive`, `post-receive`, and `update`
+Git server hooks use `pre-receive`, `post-receive`, and `update`
[Git server-side hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#_server_side_hooks).
GitLab administrators configure server hooks on the file system of the GitLab server. If you don't have file system access,
@@ -46,7 +48,7 @@ To create server hooks for a repository:
- To create many server hooks, create a directory for the hooks that matches the hook type. For example, for a
`pre-receive` server hook, the directory name should be `pre-receive.d`. Put the files for the hook in that directory.
1. Make the server hook files executable and ensure that they are owned by the Git user.
-1. Write the code to make the server hook function as expected. Server hooks can be in any programming language. Ensure
+1. Write the code to make the server hook function as expected. Git server hooks can be in any programming language. Ensure
the [shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) at the top reflects the language type. For
example, if the script is in Ruby the shebang is probably `#!/usr/bin/env ruby`.
1. Make the hook file executable, ensure that it's owned by the Git user, and ensure it does not match the backup file
@@ -87,7 +89,7 @@ To create a global server hook for all repositories:
1. On the GitLab server, go to the configured global server hook directory.
1. In the configured global server hook directory, create a directory for the hooks that matches the hook type. For example, for a `pre-receive` server hook, the directory name should be `pre-receive.d`.
-1. Inside this new directory, add your server hooks. Server hooks can be in any programming language. Ensure the
+1. Inside this new directory, add your server hooks. Git server hooks can be in any programming language. Ensure the
[shebang](https://en.wikipedia.org/wiki/Shebang_(Unix)) at the top reflects the language type. For example, if the
script is in Ruby the shebang is probably `#!/usr/bin/env ruby`.
1. Make the hook file executable, ensure that it's owned by the Git user, and ensure it does not match the backup file
diff --git a/doc/administration/sidekiq/sidekiq_memory_killer.md b/doc/administration/sidekiq/sidekiq_memory_killer.md
index bbf95bc45ce..0876f98621d 100644
--- a/doc/administration/sidekiq/sidekiq_memory_killer.md
+++ b/doc/administration/sidekiq/sidekiq_memory_killer.md
@@ -64,5 +64,5 @@ The MemoryKiller is controlled using environment variables.
If the process hard shutdown/restart is not performed by Sidekiq,
the Sidekiq process is forcefully terminated after
- `Sidekiq.options[:timeout] + 2` seconds. An external supervision mechanism
+ `Sidekiq[:timeout] + 2` seconds. An external supervision mechanism
(for example, runit) must restart Sidekiq afterwards.
diff --git a/doc/administration/snippets/index.md b/doc/administration/snippets/index.md
index 89a571946af..7bf828afedd 100644
--- a/doc/administration/snippets/index.md
+++ b/doc/administration/snippets/index.md
@@ -26,7 +26,7 @@ content changes.
### Snippets size limit configuration
This setting is not available through the [Admin Area settings](../../user/admin_area/settings/index.md).
-In order to configure this setting, use either the Rails console
+To configure this setting, use either the Rails console
or the [Application settings API](../../api/settings.md).
NOTE:
diff --git a/doc/administration/system_hooks.md b/doc/administration/system_hooks.md
index 56e73150616..038c26a9c2e 100644
--- a/doc/administration/system_hooks.md
+++ b/doc/administration/system_hooks.md
@@ -7,7 +7,8 @@ type: reference
# System hooks **(FREE SELF)**
-Your GitLab instance can perform HTTP POST requests on the following events:
+System hooks (not to be confused with [server hooks](server_hooks.md) or [file hooks](file_hooks.md)) perform HTTP POST
+requests and are triggered on the following events:
- `group_create`
- `group_destroy`
@@ -31,21 +32,18 @@ Your GitLab instance can perform HTTP POST requests on the following events:
- `user_update_for_group`
- `user_update_for_team`
-The triggers for most of these are self-explanatory, but `project_update` and
-`project_rename` deserve some clarification: `project_update` is fired any time
-an attribute of a project is changed (including name, description, and tags)
-_unless_ the `path` attribute is also changed. In that case, a `project_rename`
-is triggered instead (so that, for instance, if all you care about is the
-repository URL, you can just listen for `project_rename`).
+The triggers for most of these are self-explanatory, but `project_update` and `project_rename` require clarification:
-`user_failed_login` is sent whenever a _blocked_ user attempts to sign in and is
-denied access.
+- `project_update` triggers when an attribute of a project is changed (including name, description, and tags)
+ **except** when the `path` attribute is also changed.
+- `project_rename` triggers when an attribute of a project (including `path`) is changed. If you only care about the
+ repository URL, just listen for `project_rename`.
-System hooks can be used, for example, for logging or changing information in an
-LDAP server.
+`user_failed_login` is sent whenever a **blocked** user attempts to sign in and is denied access.
-In addition to these default events, you can enable triggers for other events,
-such as push events, and disable the `repository_update` event
+As an example, use system hooks for logging or changing information in an LDAP server.
+
+You can also enable triggers for other events, such as push events, and disable the `repository_update` event
when you create a system hook.
NOTE:
@@ -136,7 +134,7 @@ X-Gitlab-Event: System Hook
```
Note that `project_rename` is not triggered if the namespace changes.
-Please refer to `group_rename` and `user_rename` for that case.
+Refer to `group_rename` and `user_rename` for that case.
**Project transferred:**
@@ -766,6 +764,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/administration/terraform_state.md b/doc/administration/terraform_state.md
index 61fda91ba71..02a95e28747 100644
--- a/doc/administration/terraform_state.md
+++ b/doc/administration/terraform_state.md
@@ -135,10 +135,11 @@ For GitLab 13.8 and earlier versions, you can use a workaround for the Rake task
end
```
-You can optionally track progress and verify that all packages migrated successfully using the
+You can optionally track progress and verify that all Terraform state files migrated successfully using the
[PostgreSQL console](https://docs.gitlab.com/omnibus/settings/database.html#connecting-to-the-bundled-postgresql-database):
-- `sudo gitlab-rails dbconsole` for Omnibus GitLab instances.
+- `sudo gitlab-rails dbconsole` for Omnibus GitLab 14.1 and earlier.
+- `sudo gitlab-rails dbconsole --database main` for Omnibus GitLab 14.2 and later.
- `sudo -u git -H psql -d gitlabhq_production` for source-installed instances.
Verify `objectstg` below (where `file_store=2`) has count of all states:
diff --git a/doc/administration/troubleshooting/debug.md b/doc/administration/troubleshooting/debug.md
deleted file mode 100644
index d5019f1aa4a..00000000000
--- a/doc/administration/troubleshooting/debug.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../reference_architectures/troubleshooting.md'
-remove_date: '2022-10-19'
----
-
-This document was moved to [another location](../reference_architectures/troubleshooting.md).
-
-<!-- This redirect file can be deleted after 2022-10-19. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/administration/troubleshooting/defcon.md b/doc/administration/troubleshooting/defcon.md
deleted file mode 100644
index f2554f523f0..00000000000
--- a/doc/administration/troubleshooting/defcon.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../../ci/troubleshooting.md#disaster-recovery'
-remove_date: '2022-10-04'
----
-
-This document was moved to [another location](../../ci/troubleshooting.md#disaster-recovery).
-
-<!-- This redirect file can be deleted after <2022-10-04>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
index 20ce52a9094..6993d48b450 100644
--- a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
+++ b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md
@@ -1,660 +1,11 @@
---
-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
+redirect_to: 'index.md'
+remove_date: '2023-02-01'
---
-# GitLab Rails Console Cheat Sheet **(FREE SELF)**
+This document was moved to [another location](index.md).
-This is the GitLab Support Team's collection of information regarding the GitLab Rails
-console, for use while troubleshooting. It is listed here for transparency,
-and for users with experience with these tools. If you are currently
-having an issue with GitLab, it is highly recommended that you first check
-our guide on [our Rails console](../operations/rails_console.md),
-and your [support options](https://about.gitlab.com/support/), before attempting to use
-this information.
-
-WARNING:
-Some of these scripts could be damaging if not run correctly,
-or under the right conditions. We highly recommend running them under the
-guidance of a Support Engineer, or running them in a test environment with a
-backup of the instance ready to be restored, just in case.
-
-WARNING:
-As GitLab changes, changes to the code are inevitable,
-and so some scripts may not work as they once used to. These are not kept
-up-to-date as these scripts/commands were added as they were found/needed. As
-mentioned above, we recommend running these scripts under the supervision of a
-Support Engineer, who can also verify that they continue to work as they
-should and, if needed, update the script for the latest version of GitLab.
-
-## Attributes
-
-View available attributes, formatted using pretty print (`pp`).
-
-For example, determine what attributes contain users' names and email addresses:
-
-```ruby
-u = User.find_by_username('someuser')
-pp u.attributes
-```
-
-Partial output:
-
-```plaintext
-{"id"=>1234,
- "email"=>"someuser@example.com",
- "sign_in_count"=>99,
- "name"=>"S User",
- "username"=>"someuser",
- "first_name"=>nil,
- "last_name"=>nil,
- "bot_type"=>nil}
-```
-
-Then make use of the attributes, [testing SMTP, for example](https://docs.gitlab.com/omnibus/settings/smtp.html#testing-the-smtp-configuration):
-
-```ruby
-e = u.email
-n = u.name
-Notify.test_email(e, "Test email for #{n}", 'Test email').deliver_now
-#
-Notify.test_email(u.email, "Test email for #{u.name}", 'Test email').deliver_now
-```
-
-## Imports and exports
-
-### Import a project
-
-```ruby
-# Find the project and get the error
-p = Project.find_by_full_path('<username-or-group>/<project-name>')
-
-p.import_error
-
-# To finish the import on GitLab running version before 11.6
-p.import_finish
-
-# To finish the import on GitLab running version 11.6 or after
-p.import_state.mark_as_failed("Failed manually through console.")
-```
-
-### Rename imported repository
-
-In a specific situation, an imported repository needed to be renamed. The Support
-Team was informed of a backup restore that failed on a single repository, which created
-the project with an empty repository. The project was successfully restored to a development
-instance, then exported, and imported into a new project under a different name.
-
-The Support Team was able to transfer the incorrectly named imported project into the
-correctly named empty project using the steps below.
-
-Move the new repository to the empty repository:
-
-```shell
-mv /var/opt/gitlab/git-data/repositories/<group>/<new-project> /var/opt/gitlab/git-data/repositories/<group>/<empty-project>
-```
-
-Make sure the permissions are correct:
-
-```shell
-chown -R git:git <path-to-directory>.git
-```
-
-Clear the cache:
-
-```shell
-sudo gitlab-rake cache:clear
-```
-
-### Export a project
-
-It's typically recommended to export a project through [the web interface](../../user/project/settings/import_export.md#export-a-project-and-its-data) or through [the API](../../api/project_import_export.md). In situations where this is not working as expected, it may be preferable to export a project directly via the Rails console:
-
-```ruby
-user = User.find_by_username('<username>')
-# Sufficient permissions needed
-# Read https://docs.gitlab.com/ee/user/permissions.html#project-members-permissions
-
-project = Project.find_by_full_path('<username-or-group>/<project-name')
-Projects::ImportExport::ExportService.new(project, user).execute
-```
-
-If this all runs successfully, you see an output like the following before being returned to the Rails console prompt:
-
-```ruby
-=> nil
-```
-
-The exported project is located in a `.tar.gz` file in `/var/opt/gitlab/gitlab-rails/uploads/-/system/import_export_upload/export_file/`.
-
-If this fails, [enable verbose logging](../operations/rails_console.md#looking-up-database-persisted-objects),
-repeat the above procedure after,
-and report the output to
-[GitLab Support](https://about.gitlab.com/support/).
-
-## Mirrors
-
-### Find mirrors with "bad decrypt" errors
-
-This content has been converted to a Rake task, see [verify database values can be decrypted using the current secrets](../raketasks/check.md#verify-database-values-can-be-decrypted-using-the-current-secrets).
-
-### Transfer mirror users and tokens to a single service account
-
-This content has been moved to [Troubleshooting Repository mirroring](../../user/project/repository/mirror/index.md#transfer-mirror-users-and-tokens-to-a-single-service-account-in-rails-console).
-
-## Users
-
-### Create new user
-
-```ruby
-u = User.new(username: 'test_user', email: 'test@example.com', name: 'Test User', password: 'password', password_confirmation: 'password')
-u.skip_confirmation! # Use it only if you wish user to be automatically confirmed. If skipped, user receives confirmation e-mail
-u.save!
-```
-
-### Skip reconfirmation
-
-```ruby
-user = User.find_by_username('<username>')
-user.skip_reconfirmation!
-```
-
-### Disable 2fa for single user
-
-**In GitLab 13.5 and later:**
-
-Use the code under [Disable 2FA | For a single user](../../security/two_factor_authentication.md#for-a-single-user) so that the target user
-is notified that 2FA has been disabled.
-
-**In GitLab 13.4 and earlier:**
-
-```ruby
-user = User.find_by_username('<username>')
-user.disable_two_factor!
-```
-
-### Active users & Historical users
-
-```ruby
-# Active users on the instance, now
-User.active.count
-
-# Users taking a seat on the instance
-User.billable.count
-
-# The historical max on the instance as of the past year
-::HistoricalData.max_historical_user_count(from: 1.year.ago.beginning_of_day, to: Time.current.end_of_day)
-```
-
-Using cURL and jq (up to a max 100, see [Pagination](../../api/index.md#pagination)):
-
-```shell
-curl --silent --header "Private-Token: ********************" \
- "https://gitlab.example.com/api/v4/users?per_page=100&active" | jq --compact-output '.[] | [.id,.name,.username]'
-```
-
-### Update Daily Billable & Historical users
-
-```ruby
-# Forces recount of historical (max) users
-::HistoricalDataWorker.new.perform
-
-# Forces recount of daily billable users
-identifier = Analytics::UsageTrends::Measurement.identifiers[:billable_users]
-::Analytics::UsageTrends::CounterJobWorker.new.perform(identifier, User.minimum(:id), User.maximum(:id), Time.zone.now)
-```
-
-### Block or Delete Users that have no projects or groups
-
-```ruby
-users = User.where('id NOT IN (select distinct(user_id) from project_authorizations)')
-
-# How many users are removed?
-users.count
-
-# If that count looks sane:
-
-# You can either block the users:
-users.each { |user| user.blocked? ? nil : user.block! }
-
-# Or you can delete them:
- # need 'current user' (your user) for auditing purposes
-current_user = User.find_by(username: '<your username>')
-
-users.each do |user|
- DeleteUserWorker.perform_async(current_user.id, user.id)
-end
-```
-
-### Deactivate Users that have no recent activity
-
-```ruby
-days_inactive = 90
-inactive_users = User.active.where("last_activity_on <= ?", days_inactive.days.ago)
-
-inactive_users.each do |user|
- puts "user '#{user.username}': #{user.last_activity_on}"
- user.deactivate!
-end
-```
-
-### Block Users that have no recent activity
-
-```ruby
-days_inactive = 90
-inactive_users = User.active.where("last_activity_on <= ?", days_inactive.days.ago)
-
-inactive_users.each do |user|
- puts "user '#{user.username}': #{user.last_activity_on}"
- user.block!
-end
-```
-
-### Find a user's max permissions for project/group
-
-```ruby
-user = User.find_by_username 'username'
-project = Project.find_by_full_path 'group/project'
-user.max_member_access_for_project project.id
-```
-
-```ruby
-user = User.find_by_username 'username'
-group = Group.find_by_full_path 'group'
-user.max_member_access_for_group group.id
-```
-
-## Merge requests
-
-### Close a merge request
-
-```ruby
-u = User.find_by_username('<username>')
-p = Project.find_by_full_path('<namespace/project>')
-m = p.merge_requests.find_by(iid: <iid>)
-MergeRequests::CloseService.new(project: p, current_user: u).execute(m)
-```
-
-### Delete a merge request
-
-```ruby
-u = User.find_by_username('<username>')
-p = Project.find_by_full_path('<namespace/project>')
-m = p.merge_requests.find_by(iid: <iid>)
-Issuable::DestroyService.new(project: m.project, current_user: u).execute(m)
-```
-
-### Rebase manually
-
-```ruby
-u = User.find_by_username('<username>')
-p = Project.find_by_full_path('<namespace/project>')
-m = p.merge_requests.find_by(iid: <iid>)
-MergeRequests::RebaseService.new(project: m.target_project, current_user: u).execute(m)
-```
-
-### Set a merge request as merged
-
-Use when a merge request was accepted and the changes merged into the Git repository,
-but the merge request still shows as open.
-
-If the changes are not merged yet, this action causes the merge request to
-incorrectly show `merged into <branch-name>`.
-
-```ruby
-u = User.find_by_username('<username>')
-p = Project.find_by_full_path('<namespace/project>')
-m = p.merge_requests.find_by(iid: <iid>)
-MergeRequests::PostMergeService.new(project: p, current_user: u).execute(m)
-```
-
-## CI
-
-### Cancel stuck pending pipelines
-
-For more information, see the [confidential issue](../../user/project/issues/confidential_issues.md)
-`https://gitlab.com/gitlab-com/support-forum/issues/2449#note_41929707`.
-
-```ruby
-Ci::Pipeline.where(project_id: p.id).where(status: 'pending').count
-Ci::Pipeline.where(project_id: p.id).where(status: 'pending').each {|p| p.cancel if p.stuck?}
-Ci::Pipeline.where(project_id: p.id).where(status: 'pending').count
-```
-
-### Remove artifacts more than a week old
-
-This section has been moved to the [job artifacts troubleshooting documentation](../job_artifacts.md#delete-job-artifacts-from-jobs-completed-before-a-specific-date).
-
-### Find reason failure (for when build trace is empty) (Introduced in 10.3.0)
-
-See <https://gitlab.com/gitlab-org/gitlab-foss/-/issues/41111>.
-
-```ruby
-build = Ci::Build.find(78420)
-
-build.failure_reason
-
-build.dependencies.each do |d| { puts "status: #{d.status}, finished at: #{d.finished_at},
- completed: #{d.complete?}, artifacts_expired: #{d.artifacts_expired?}, erased: #{d.erased?}" }
-```
-
-### Try CI integration
-
-```ruby
-p = Project.find_by_full_path('<project_path>')
-m = project.merge_requests.find_by(iid: )
-m.project.try(:ci_integration)
-```
-
-### Validate the `.gitlab-ci.yml`
-
-```ruby
-project = Project.find_by_full_path 'group/project'
-content = project.repository.gitlab_ci_yml_for(project.repository.root_ref_sha)
-Gitlab::Ci::Lint.new(project: project, current_user: User.first).validate(content)
-```
-
-### Disable AutoDevOps on Existing Projects
-
-```ruby
-Project.all.each do |p|
- p.auto_devops_attributes={"enabled"=>"0"}
- p.save
-end
-```
-
-### Obtain runners registration token
-
-```ruby
-Gitlab::CurrentSettings.current_application_settings.runners_registration_token
-```
-
-### Seed runners registration token
-
-```ruby
-appSetting = Gitlab::CurrentSettings.current_application_settings
-appSetting.set_runners_registration_token('<new-runners-registration-token>')
-appSetting.save!
-```
-
-### Run pipeline schedules manually
-
-You can run pipeline schedules manually through the Rails console to reveal any errors that are usually not visible.
-
-```ruby
-# schedule_id can be obtained from Edit Pipeline Schedule page
-schedule = Ci::PipelineSchedule.find_by(id: <schedule_id>)
-
-# Select the user that you want to run the schedule for
-user = User.find_by_username('<username>')
-
-# Run the schedule
-ps = Ci::CreatePipelineService.new(schedule.project, user, ref: schedule.ref).execute!(:schedule, ignore_skip_ci: true, save_on_errors: false, schedule: schedule)
-```
-
-## License
-
-### See current license information
-
-```ruby
-# License information (name, company, email address)
-License.current.licensee
-
-# Plan:
-License.current.plan
-
-# Uploaded:
-License.current.created_at
-
-# Started:
-License.current.starts_at
-
-# Expires at:
-License.current.expires_at
-
-# Is this a trial license?
-License.current.trial?
-
-# License ID for lookup on CustomersDot
-License.current.license_id
-
-# License data in Base64-encoded ASCII format
-License.current.data
-```
-
-### Check if a project feature is available on the instance
-
-Features listed in <https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/models/license.rb>.
-
-```ruby
-License.current.feature_available?(:jira_dev_panel_integration)
-```
-
-### Check if a project feature is available in a project
-
-Features listed in [`license.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/models/license.rb).
-
-```ruby
-p = Project.find_by_full_path('<group>/<project>')
-p.feature_available?(:jira_dev_panel_integration)
-```
-
-### Add a license through the console
-
-```ruby
-key = "<key>"
-license = License.new(data: key)
-license.save
-License.current # check to make sure it applied
-```
-
-This is needed for example in a known edge-case with
-[expired license and multiple LDAP servers](../auth/ldap/ldap-troubleshooting.md#expired-license-causes-errors-with-multiple-ldap-servers).
-
-### Remove licenses
-
-To clean up the [License History table](../../user/admin_area/license_file.md#view-license-details-and-history):
-
-```ruby
-TYPE = :trial?
-# or :expired?
-
-License.select(&TYPE).each(&:destroy!)
-
-# or even License.all.each(&:destroy!)
-```
-
-## Registry
-
-### Registry Disk Space Usage by Project
-
-Find this content in the [Container Registry troubleshooting documentation](../packages/container_registry.md#registry-disk-space-usage-by-project).
-
-### Run the Cleanup policy now
-
-Find this content in the [Container Registry troubleshooting documentation](../packages/container_registry.md#run-the-cleanup-policy-now).
-
-## Sidekiq
-
-This content has been moved to [Troubleshooting Sidekiq](sidekiq.md).
-
-## LFS
-
-### Get information about LFS objects and associated project
-
-```ruby
-o = LfsObject.find_by(oid: "<oid>")
-p = Project.find(LfsObjectsProject.find_by_lfs_object_id(o.id).project_id)
-```
-
-You can then delete these records from the database with:
-
-```ruby
-LfsObjectsProject.find_by_lfs_object_id(o.id).destroy
-o.destroy
-```
-
-You would also want to combine this with deleting the LFS file in the LFS storage
-area on disk. It remains to be seen exactly how or whether the deletion is useful, however.
-
-## Decryption Problems
-
-### Bad Decrypt Script (for encrypted variables)
-
-This content has been converted to a Rake task, see [verify database values can be decrypted using the current secrets](../raketasks/check.md#verify-database-values-can-be-decrypted-using-the-current-secrets).
-
-As an example of repairing, if `ProjectImportData Bad count:` is detected and the decision is made to delete the
-encrypted credentials to allow manual reentry:
-
-```ruby
- # Find the ids of the corrupt ProjectImportData objects
- total = 0
- bad = []
- ProjectImportData.find_each do |data|
- begin
- total += 1
- data.credentials
- rescue => e
- bad << data.id
- end
- end
-
- puts "Bad count: #{bad.count} / #{total}"
-
- # See the bad ProjectImportData ids
- bad
-
- # Remove the corrupted credentials
- import_data = ProjectImportData.where(id: bad)
- import_data.each do |data|
- data.update_columns({ encrypted_credentials: nil, encrypted_credentials_iv: nil, encrypted_credentials_salt: nil})
- end
-```
-
-If `User OTP Secret Bad count:` is detected. For each user listed disable/enable
-two-factor authentication.
-
-The following script searches in some of the tables for encrypted tokens that are
-causing decryption errors, and update or reset as needed:
-
-```shell
-wget -O /tmp/encrypted-tokens.rb https://gitlab.com/snippets/1876342/raw
-gitlab-rails runner /tmp/encrypted-tokens.rb
-```
-
-### Decrypt Script for encrypted tokens
-
-This content has been converted to a Rake task, see [verify database values can be decrypted using the current secrets](../raketasks/check.md#verify-database-values-can-be-decrypted-using-the-current-secrets).
-
-## Geo
-
-### Reverify all uploads (or any SSF data type which is verified)
-
-1. SSH into a GitLab Rails node in the primary Geo site.
-1. Open [Rails console](../operations/rails_console.md).
-1. Mark all uploads as "pending verification":
-
- ```ruby
- Upload.verification_state_table_class.each_batch do |relation|
- relation.update_all(verification_state: 0)
- end
- ```
-
-1. This will cause the primary to start checksumming all Uploads.
-1. When a primary successfully checksums a record, then all secondaries rechecksum as well, and they compare the values.
-
-A similar thing can be done for all Models handled by the [Geo Self-Service Framework](../../development/geo/framework.md) which have implemented verification:
-
-- `LfsObject`
-- `MergeRequestDiff`
-- `Packages::PackageFile`
-- `Terraform::StateVersion`
-- `SnippetRepository`
-- `Ci::PipelineArtifact`
-- `PagesDeployment`
-- `Upload`
-- `Ci::JobArtifact`
-- `Ci::SecureFile`
-
-NOTE:
-`GroupWikiRepository` is not in the previous list since verification is not implemented.
-There is an [issue to implement this functionality in the Admin UI](https://gitlab.com/gitlab-org/gitlab/-/issues/364729).
-
-### Artifacts
-
-Moved to [Geo replication troubleshooting](../geo/replication/troubleshooting.md#find-failed-artifacts).
-
-### Repository verification failures
-
-Moved to [Geo replication troubleshooting](../geo/replication/troubleshooting.md#repository-verification-failures).
-
-### Resync repositories
-
-Moved to [Geo replication troubleshooting](../geo/replication/troubleshooting.md#resync-repositories).
-
-### Blob types
-
-Moved to [Geo replication troubleshooting](../geo/replication/troubleshooting.md#blob-types).
-
-## Generate Service Ping
-
-The [Service Ping Guide](../../development/service_ping/index.md) in our developer documentation
-has more information about Service Ping.
-
-### Generate or get the cached Service Ping
-
-```ruby
-Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values, cached: true)
-```
-
-### Generate a fresh new Service Ping
-
-This also refreshes the cached Service Ping displayed in the Admin Area
-
-```ruby
-Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values)
-```
-
-### Generate and print
-
-Generates Service Ping data in JSON format.
-
-```shell
-rake gitlab:usage_data:generate
-```
-
-Generates Service Ping data in YAML format:
-
-```shell
-rake gitlab:usage_data:dump_sql_in_yaml
-```
-
-### Generate and send Service Ping
-
-Prints the metrics saved in `conversational_development_index_metrics`.
-
-```shell
-rake gitlab:usage_data:generate_and_send
-```
-
-## GraphQL
-
-Call a [GraphQL](../../api/graphql/getting_started.md) endpoint through the Rails console:
-
-```ruby
-query = <<~EOQ
-query securityGetProjects($search: String!) {
- projects(search: $search) {
- nodes {
- path
- }
- }
-}
-EOQ
-
-variables = { "search": "gitlab" }
-
-result = GitlabSchema.execute(query, variables: variables, context: { current_user: current_user })
-result.to_h
-```
+<!-- 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/administration/troubleshooting/group_saml_scim.md b/doc/administration/troubleshooting/group_saml_scim.md
deleted file mode 100644
index b5187504231..00000000000
--- a/doc/administration/troubleshooting/group_saml_scim.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../../user/group/saml_sso/example_saml_config.md'
-remove_date: '2022-10-29'
----
-
-This document was moved to [another location](../../user/group/saml_sso/example_saml_config.md).
-
-<!-- This redirect file can be deleted after <2022-10-29>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (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/troubleshooting/index.md b/doc/administration/troubleshooting/index.md
index ce548f9e100..db572f202ea 100644
--- a/doc/administration/troubleshooting/index.md
+++ b/doc/administration/troubleshooting/index.md
@@ -9,19 +9,21 @@ info: To determine the technical writer assigned to the Stage/Group associated w
This page documents a collection of resources to help you troubleshoot a GitLab
installation.
+This list is not necessarily comprehensive. If you don't find what you're looking
+for in this list, you should search the documentation.
+
## Troubleshooting guides
- [SSL](ssl.md)
- [Geo](../geo/replication/troubleshooting.md)
-- [GitLab Rails console cheat sheet](gitlab_rails_cheat_sheet.md)
-- [Example group SAML and SCIM configurations](../../user/group/saml_sso/example_saml_config.md)
+- [SAML](../../user/group/saml_sso/troubleshooting.md)
- [Kubernetes cheat sheet](https://docs.gitlab.com/charts/troubleshooting/kubernetes_cheat_sheet.html)
- [Linux cheat sheet](linux_cheat_sheet.md)
- [Parsing GitLab logs with `jq`](../logs/log_parsing.md)
- [Diagnostics tools](diagnostics_tools.md)
Some feature documentation pages also have a troubleshooting section at the end
-that you can check for feature-specific help.
+that you can check for feature-specific help, including helpful Rails commands.
If you need a testing environment to troubleshoot, see the
[apps for a testing environment](test_environments.md).
diff --git a/doc/administration/troubleshooting/kubernetes_cheat_sheet.md b/doc/administration/troubleshooting/kubernetes_cheat_sheet.md
deleted file mode 100644
index 15ec8d5940b..00000000000
--- a/doc/administration/troubleshooting/kubernetes_cheat_sheet.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: 'https://docs.gitlab.com/charts/troubleshooting/kubernetes_cheat_sheet.html'
-remove_date: '2022-10-05'
----
-
-This document was moved to [another location](https://docs.gitlab.com/charts/troubleshooting/kubernetes_cheat_sheet.html).
-
-<!-- This redirect file can be deleted after 2022-10-05. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/administration/troubleshooting/linux_cheat_sheet.md b/doc/administration/troubleshooting/linux_cheat_sheet.md
index 0c6fcd31d1d..90cd1e24c79 100644
--- a/doc/administration/troubleshooting/linux_cheat_sheet.md
+++ b/doc/administration/troubleshooting/linux_cheat_sheet.md
@@ -210,7 +210,7 @@ using the `-s` or `--sort` flag. The number of results defaults to 25 processes,
can be changed using the `-c`/`--count` option. See `--help` for full details.
```shell
-$ ./strace-parser sidekiq_trace.txt summary -c15 -s=pid
+$ ./strace-parser sidekiq_trace.txt summary -c15 -s=pid
Top 15 PIDs by PID #
-----------
@@ -244,7 +244,7 @@ processes using the `-p`/`--pid` for a specific process, or `-s`/`--stats` flags
a sorted list. `--stats` takes the same sorting and count options as summary.
```shell
-./strace-parser sidekiq_trace.txt p 16815
+./strace-parser sidekiq_trace.txt p 16815
PID 16815
diff --git a/doc/administration/troubleshooting/log_parsing.md b/doc/administration/troubleshooting/log_parsing.md
deleted file mode 100644
index 929a49494be..00000000000
--- a/doc/administration/troubleshooting/log_parsing.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../logs/log_parsing.md'
-remove_date: '2022-10-24'
----
-
-This document was moved to [another location](../logs/log_parsing.md).
-
-<!-- This redirect file can be deleted after <2022-10-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/administration/troubleshooting/navigating_gitlab_via_rails_console.md b/doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md
deleted file mode 100644
index 09a5cb8d185..00000000000
--- a/doc/administration/troubleshooting/navigating_gitlab_via_rails_console.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../operations/rails_console.md'
-remove_date: '2022-10-05'
----
-
-This document was moved to [another location](../operations/rails_console.md).
-
-<!-- This redirect file can be deleted after <2022-10-05>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (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/troubleshooting/postgresql.md b/doc/administration/troubleshooting/postgresql.md
index 8a76d4f88ab..829fed38060 100644
--- a/doc/administration/troubleshooting/postgresql.md
+++ b/doc/administration/troubleshooting/postgresql.md
@@ -58,59 +58,6 @@ This section is for links to information elsewhere in the GitLab documentation.
some of which is absolutely not for production use. Including:
- Understanding EXPLAIN plans.
-### Troubleshooting/Fixes
-
-- [GitLab database requirements](../../install/requirements.md#database),
- including
- - Support for MySQL was removed in GitLab 12.1; [migrate to PostgreSQL](../../update/mysql_to_postgresql.md).
- - Required extension: `pg_trgm`
- - Required extension: `btree_gist`
-
-- Errors like this in the `production/sidekiq` log; see:
- [Set `default_transaction_isolation` into read committed](https://docs.gitlab.com/omnibus/settings/database.html#set-default_transaction_isolation-into-read-committed):
-
- ```plaintext
- ActiveRecord::StatementInvalid PG::TRSerializationFailure: ERROR: could not serialize access due to concurrent update
- ```
-
-- PostgreSQL HA [replication slot errors](https://docs.gitlab.com/omnibus/settings/database.html#troubleshooting-upgrades-in-an-ha-cluster):
-
- ```plaintext
- pg_basebackup: could not create temporary replication slot "pg_basebackup_12345": ERROR: all replication slots are in use
- HINT: Free one or increase max_replication_slots.
- ```
-
-- Geo [replication errors](../geo/replication/troubleshooting.md#fixing-replication-errors) including:
-
- ```plaintext
- ERROR: replication slots can only be used if max_replication_slots > 0
-
- FATAL: could not start WAL streaming: ERROR: replication slot "geo_secondary_my_domain_com" does not exist
-
- Command exceeded allowed execution time
-
- PANIC: could not write to file 'pg_xlog/xlogtemp.123': No space left on device
- ```
-
-- [Checking Geo configuration](../geo/replication/troubleshooting.md), including:
- - Reconfiguring hosts/ports.
- - Checking and fixing user/password mappings.
-
-- [Common Geo errors](../geo/replication/troubleshooting.md#fixing-common-errors).
-
-- Mismatch in `pg_dump` and `psql` versions:
-
- ```plaintext
- Dumping PostgreSQL database gitlabhq_production ... pg_dump: error: server version: 13.3; pg_dump version: 14.2
- pg_dump: error: aborting because of server version mismatch
- ```
-
- To fix this, see [Backup and restore a non-packaged PostgreSQL database](https://docs.gitlab.com/omnibus/settings/database.html#backup-and-restore-a-non-packaged-postgresql-database).
-
-- Deploying PostgreSQL on Azure Database for PostgreSQL - Flexible Server may result in an error stating `extension "btree_gist" is not allow-listed for "azure_pg_admin" users in Azure Database for PostgreSQL`
-
- To resolve the above error, [allow-list the extension](https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/concepts-extensions#how-to-use-postgresql-extensions) prior to install.
-
## Support topics
### Database deadlocks
@@ -236,3 +183,96 @@ To temporarily change the statement timeout:
1. Perform the action for which you need a different timeout
(for example the backup or the Rails command).
1. Revert the edit in `/var/opt/gitlab/gitlab-rails/etc/database.yml`.
+
+## Troubleshooting
+
+### Database is not accepting commands to avoid wraparound data loss
+
+This error likely means that AUTOVACUUM is failing to complete its run:
+
+```plaintext
+ERROR: database is not accepting commands to avoid wraparound data loss in database "gitlabhq_production"
+```
+
+To resolve the error, run `VACUUM` manually:
+
+1. Stop GitLab with the command `gitlab-ctl stop`.
+1. Place the database in single-user mode with the command:
+
+ ```shell
+ /opt/gitlab/embedded/bin/postgres --single -D /var/opt/gitlab/postgresql/data gitlabhq_production
+ ```
+
+1. In the `backend>` prompt, run `VACUUM;`. This command can take several minutes to complete.
+1. Wait for the command to complete, then press <kbd>Control</kbd> + <kbd>D</kbd> to exit.
+1. Start GitLab with the command `gitlab-ctl start`.
+
+### GitLab database requirements
+
+The [database requirements](../../install/requirements.md#database) for GitLab include:
+
+- Support for MySQL was removed in GitLab 12.1; [migrate to PostgreSQL](../../update/mysql_to_postgresql.md).
+- Review and install the [required extension list](../../install/postgresql_extensions.md).
+
+### Serialization errors in the `production/sidekiq` log
+
+If you receive errors like this example in your `production/sidekiq` log, read
+about [setting `default_transaction_isolation` into read committed](https://docs.gitlab.com/omnibus/settings/database.html#set-default_transaction_isolation-into-read-committed) to fix the problem:
+
+```plaintext
+ActiveRecord::StatementInvalid PG::TRSerializationFailure: ERROR: could not serialize access due to concurrent update
+```
+
+### PostgreSQL replication slot errors
+
+If you receive errors like this example, read about how to resolve PostgreSQL HA
+[replication slot errors](https://docs.gitlab.com/omnibus/settings/database.html#troubleshooting-upgrades-in-an-ha-cluster):
+
+```plaintext
+pg_basebackup: could not create temporary replication slot "pg_basebackup_12345": ERROR: all replication slots are in use
+HINT: Free one or increase max_replication_slots.
+```
+
+### Geo replication errors
+
+If you receive errors like this example, read about how to resolve
+[Geo replication errors](../geo/replication/troubleshooting.md#fixing-postgresql-database-replication-errors):
+
+```plaintext
+ERROR: replication slots can only be used if max_replication_slots > 0
+
+FATAL: could not start WAL streaming: ERROR: replication slot "geo_secondary_my_domain_com" does not exist
+
+Command exceeded allowed execution time
+
+PANIC: could not write to file 'pg_xlog/xlogtemp.123': No space left on device
+```
+
+### Review Geo configuration and common errors
+
+When troubleshooting problems with Geo, you should:
+
+- Review [common Geo errors](../geo/replication/troubleshooting.md#fixing-common-errors).
+- [Review your Geo configuration](../geo/replication/troubleshooting.md), including:
+ - Reconfiguring hosts and ports.
+ - Reviewing and fixing the user and password mappings.
+
+### Mismatch in `pg_dump` and `psql` versions
+
+If you receive errors like this example, read about how to
+[back up and restore a non-packaged PostgreSQL database](https://docs.gitlab.com/omnibus/settings/database.html#backup-and-restore-a-non-packaged-postgresql-database):
+
+```plaintext
+Dumping PostgreSQL database gitlabhq_production ... pg_dump: error: server version: 13.3; pg_dump version: 14.2
+pg_dump: error: aborting because of server version mismatch
+```
+
+### Extension `btree_gist` is not allow-listed
+
+Deploying PostgreSQL on an Azure Database for PostgreSQL - Flexible Server may result in this error:
+
+```plaintext
+extension "btree_gist" is not allow-listed for "azure_pg_admin" users in Azure Database for PostgreSQL
+```
+
+To resolve this error, [allow-list the extension](https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/concepts-extensions#how-to-use-postgresql-extensions) prior to install.
diff --git a/doc/administration/troubleshooting/ssl.md b/doc/administration/troubleshooting/ssl.md
index 245ff9f4982..bf8e6b45fde 100644
--- a/doc/administration/troubleshooting/ssl.md
+++ b/doc/administration/troubleshooting/ssl.md
@@ -1,263 +1,11 @@
---
-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
-type: reference
+redirect_to: 'https://docs.gitlab.com/omnibus/settings/ssl/ssl_troubleshooting.html'
+remove_date: '2023-10-27'
---
-# Troubleshooting SSL **(FREE SELF)**
+This document was moved to [another location](https://docs.gitlab.com/omnibus/settings/ssl/ssl_troubleshooting.html).
-This page contains a list of common SSL-related errors and scenarios that you
-may encounter while working with GitLab. It should serve as an addition to the
-main SSL documentation:
-
-- [Omnibus SSL Configuration](https://docs.gitlab.com/omnibus/settings/ssl.html).
-- [Self-signed certificates or custom Certification Authorities for GitLab Runner](https://docs.gitlab.com/runner/configuration/tls-self-signed.html).
-- [Configure HTTPS manually](https://docs.gitlab.com/omnibus/settings/ssl.html#configure-https-manually).
-
-## Using an internal CA certificate with GitLab
-
-After configuring a GitLab instance with an internal CA certificate, you might
-not be able to access it by using various CLI tools. You may experience the
-following issues:
-
-- `curl` fails:
-
- ```shell
- curl "https://gitlab.domain.tld"
- curl: (60) SSL certificate problem: unable to get local issuer certificate
- More details here: https://curl.haxx.se/docs/sslcerts.html
- ```
-
-- Testing by using the [rails console](../operations/rails_console.md#starting-a-rails-console-session)
- also fails:
-
- ```ruby
- uri = URI.parse("https://gitlab.domain.tld")
- http = Net::HTTP.new(uri.host, uri.port)
- http.use_ssl = true
- http.verify_mode = 1
- response = http.request(Net::HTTP::Get.new(uri.request_uri))
- ...
- Traceback (most recent call last):
- 1: from (irb):5
- OpenSSL::SSL::SSLError (SSL_connect returned=1 errno=0 state=error: certificate verify failed (unable to get local issuer certificate))
- ```
-
-- The error `SSL certificate problem: unable to get local issuer certificate`
- is displayed when setting up a [mirror](../../user/project/repository/mirror/index.md)
- from this GitLab instance.
-- `openssl` works when specifying the path to the certificate:
-
- ```shell
- /opt/gitlab/embedded/bin/openssl s_client -CAfile /root/my-cert.crt -connect gitlab.domain.tld:443 -servername gitlab.domain.tld
- ```
-
-If you have the previously described issues, add your certificate to
-`/etc/gitlab/trusted-certs`, and then run `sudo gitlab-ctl reconfigure`.
-
-## X.509 key values mismatch error
-
-After configuring your instance with a certificate bundle, NGINX may display
-the following error message:
-
-`SSL: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch`
-
-This error message means that the server certificate and key you have provided
-don't match. You can confirm this by running the following command and then
-comparing the output:
-
-```shell
-openssl rsa -noout -modulus -in path/to/your/.key | openssl md5
-openssl x509 -noout -modulus -in path/to/your/.crt | openssl md5
-```
-
-The following is an example of an md5 output between a matching key and
-certificate. Note the matching md5 hashes:
-
-```shell
-$ openssl rsa -noout -modulus -in private.key | openssl md5
-4f49b61b25225abeb7542b29ae20e98c
-$ openssl x509 -noout -modulus -in public.crt | openssl md5
-4f49b61b25225abeb7542b29ae20e98c
-```
-
-This is an opposing output with a non-matching key and certificate which shows
-different md5 hashes:
-
-```shell
-$ openssl rsa -noout -modulus -in private.key | openssl md5
-d418865077299af27707b1d1fa83cd99
-$ openssl x509 -noout -modulus -in public.crt | openssl md5
-4f49b61b25225abeb7542b29ae20e98c
-```
-
-If the two outputs differ like the previous example, there's a mismatch between
-the certificate and key. Contact the provider of the SSL certificate for
-further support.
-
-## Using GitLab Runner with a GitLab instance configured with internal CA certificate or self-signed certificate
-
-Besides getting the errors mentioned in
-[Using an internal CA certificate with GitLab](ssl.md#using-an-internal-ca-certificate-with-gitlab),
-your CI pipelines may get stuck in `Pending` status. In the runner logs you may
-see the following error message:
-
-```shell
-Dec 6 02:43:17 runner-host01 gitlab-runner[15131]: #033[0;33mWARNING: Checking for jobs... failed
-#033[0;m #033[0;33mrunner#033[0;m=Bfkz1fyb #033[0;33mstatus#033[0;m=couldn't execute POST against
-https://gitlab.domain.tld/api/v4/jobs/request: Post https://gitlab.domain.tld/api/v4/jobs/request:
-x509: certificate signed by unknown authority
-```
-
-Follow the details in [Self-signed certificates or custom Certification Authorities for GitLab Runner](https://docs.gitlab.com/runner/configuration/tls-self-signed.html).
-
-## Mirroring a remote GitLab repository that uses a self-signed SSL certificate
-
-When configuring a local GitLab instance to [mirror a repository](../../user/project/repository/mirror/index.md)
-from a remote GitLab instance that uses a self-signed certificate, you may see
-the `SSL certificate problem: self signed certificate` error message in the
-user interface.
-
-The cause of the issue can be confirmed by checking if:
-
-- `curl` fails:
-
- ```shell
- $ curl "https://gitlab.domain.tld"
- curl: (60) SSL certificate problem: self signed certificate
- More details here: https://curl.haxx.se/docs/sslcerts.html
- ```
-
-- Testing by using the Rails console also fails:
-
- ```ruby
- uri = URI.parse("https://gitlab.domain.tld")
- http = Net::HTTP.new(uri.host, uri.port)
- http.use_ssl = true
- http.verify_mode = 1
- response = http.request(Net::HTTP::Get.new(uri.request_uri))
- ...
- Traceback (most recent call last):
- 1: from (irb):5
- OpenSSL::SSL::SSLError (SSL_connect returned=1 errno=0 state=error: certificate verify failed (unable to get local issuer certificate))
- ```
-
-To fix this problem:
-
-- Add the self-signed certificate from the remote GitLab instance to the
- `/etc/gitlab/trusted-certs` directory on the local GitLab instance, and then
- run `sudo gitlab-ctl reconfigure` as per the instructions for
- [installing custom public certificates](https://docs.gitlab.com/omnibus/settings/ssl.html#install-custom-public-certificates).
-- If your local GitLab instance was installed using the Helm Charts, you can
- [add your self-signed certificate to your GitLab instance](https://docs.gitlab.com/runner/install/kubernetes.html#providing-a-custom-certificate-for-accessing-gitlab).
-
-You may also get another error message when trying to mirror a repository from
-a remote GitLab instance that uses a self-signed certificate:
-
-```shell
-2:Fetching remote upstream failed: fatal: unable to access &amp;#39;https://gitlab.domain.tld/root/test-repo/&amp;#39;:
-SSL: unable to obtain common name from peer certificate
-```
-
-In this case, the problem can be related to the certificate itself:
-
-1. Validate that your self-signed certificate isn't missing a common name. If it
- is, regenerate a valid certificate
-1. Add the certificate to `/etc/gitlab/trusted-certs`.
-1. Run `sudo gitlab-ctl reconfigure`.
-
-## Unable to perform Git operations due to an internal or self-signed certificate
-
-If your GitLab instance is using a self-signed certificate, or if the
-certificate is signed by an internal certificate authority (CA), you might
-experience the following errors when attempting to perform Git operations:
-
-```shell
-$ git clone https://gitlab.domain.tld/group/project.git
-Cloning into 'project'...
-fatal: unable to access 'https://gitlab.domain.tld/group/project.git/': SSL certificate problem: self signed certificate
-```
-
-```shell
-$ git clone https://gitlab.domain.tld/group/project.git
-Cloning into 'project'...
-fatal: unable to access 'https://gitlab.domain.tld/group/project.git/': server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt CRLfile: none
-```
-
-To fix this problem:
-
-- If possible, use SSH remotes for all Git operations. This is considered more
- secure and convenient to use.
-- If you must use HTTPS remotes, you can try the following:
- - Copy the self-signed certificate or the internal root CA certificate to a
- local directory (for example, `~/.ssl`) and configure Git to trust your
- certificate:
-
- ```shell
- git config --global http.sslCAInfo ~/.ssl/gitlab.domain.tld.crt
- ```
-
- - Disable SSL verification in your Git client. This is intended as a
- temporary measure, as it could be considered a security risk.
-
- ```shell
- git config --global http.sslVerify false
- ```
-
-## SSL_connect wrong version number
-
-A misconfiguration may result in:
-
-- `gitlab-rails/exceptions_json.log` entries containing:
-
- ```plaintext
- "exception.class":"Excon::Error::Socket","exception.message":"SSL_connect returned=1 errno=0 state=error: wrong version number (OpenSSL::SSL::SSLError)",
- "exception.class":"Excon::Error::Socket","exception.message":"SSL_connect returned=1 errno=0 state=error: wrong version number (OpenSSL::SSL::SSLError)",
- ```
-
-- `gitlab-workhorse/current` containing:
-
- ```plaintext
- http: server gave HTTP response to HTTPS client
- http: server gave HTTP response to HTTPS client
- ```
-
-- `gitlab-rails/sidekiq.log` or `sidekiq/current` containing:
-
- ```plaintext
- message: SSL_connect returned=1 errno=0 state=error: wrong version number (OpenSSL::SSL::SSLError)
- message: SSL_connect returned=1 errno=0 state=error: wrong version number (OpenSSL::SSL::SSLError)
- ```
-
-Some of these errors come from the Excon Ruby gem, and could be generated in
-circumstances where GitLab is configured to initiate an HTTPS session to a
-remote server that is serving only HTTP.
-
-One scenario is that you're using [object storage](../object_storage.md), which
-isn't served under HTTPS. GitLab is misconfigured and attempts a TLS handshake,
-but the object storage responds with plain HTTP.
-
-## `schannel: SEC_E_UNTRUSTED_ROOT`
-
-If you're on Windows and get the following error:
-
-```plaintext
-Fatal: unable to access 'https://gitlab.domain.tld/group/project.git': schannel: SEC_E_UNTRUSTED_ROOT (0x80090325) - The certificate chain was issued by an authority that is not trusted."
-```
-
-You must specify that Git should use OpenSSL:
-
-```shell
-git config --system http.sslbackend openssl
-```
-
-Alternatively, you can ignore SSL verification by running:
-
-WARNING:
-Proceed with caution when [ignoring SSL](https://git-scm.com/docs/git-config#Documentation/git-config.txt-httpsslVerify)
-due to the potential security issues associated with disabling this option at global level. Use this option _only_ when troubleshooting, and reinstate SSL verification immediately after.
-
-```shell
-git config --global http.sslVerify false
-```
+<!-- This redirect file can be deleted after <2023-01-25>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
+<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/administration/troubleshooting/test_environments.md b/doc/administration/troubleshooting/test_environments.md
index a249d5bd133..c4d191f8c0f 100644
--- a/doc/administration/troubleshooting/test_environments.md
+++ b/doc/administration/troubleshooting/test_environments.md
@@ -20,13 +20,13 @@ are only available internally at GitLab.
## Docker
The following were tested on Docker containers running in the cloud. Support Engineers,
-please see [these docs](https://gitlab.com/gitlab-com/dev-resources/tree/master/dev-resources#running-docker-containers)
+see [these docs](https://gitlab.com/gitlab-com/dev-resources/tree/master/dev-resources#running-docker-containers)
on how to run Docker containers on `dev-resources`. Other setups haven't been tested,
but contributions are welcome.
### GitLab
-Please see [our official Docker installation method](../../install/docker.md)
+See [our official Docker installation method](../../install/docker.md)
for how to run GitLab on Docker.
### SAML
diff --git a/doc/administration/user_settings.md b/doc/administration/user_settings.md
index a767132db0f..c96a6311208 100644
--- a/doc/administration/user_settings.md
+++ b/doc/administration/user_settings.md
@@ -14,7 +14,7 @@ By default, new users can create top-level groups. To disable new users'
ability to create top-level groups (does not affect existing users' setting), GitLab administrators can modify this setting:
- In GitLab 15.5 and later, using either:
- - The [GitLab UI](../user/admin_area/settings/account_and_limit_settings.md#prevent-users-from-creating-top-level-groups).
+ - The [GitLab UI](../user/admin_area/settings/account_and_limit_settings.md#prevent-new-users-from-creating-top-level-groups).
- The [application setting API](../api/settings.md#change-application-settings).
- In GitLab 15.4 and earlier, in a configuration file by following the steps in this section.
diff --git a/doc/api/award_emoji.md b/doc/api/award_emoji.md
index ca6761ed6be..9d0b8945c53 100644
--- a/doc/api/award_emoji.md
+++ b/doc/api/award_emoji.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
---
-# Award emoji API **(FREE)**
+# Award emojis API **(FREE)**
An [awarded emoji](../user/award_emojis.md) tells a thousand words.
@@ -15,11 +15,11 @@ We call GitLab objects on which you can award an emoji "awardables". You can awa
- [Merge requests](../user/project/merge_requests/index.md) ([API](merge_requests.md)).
- [Snippets](../user/snippets.md) ([API](snippets.md)).
-Emojis can also [be awarded](../user/award_emojis.md#award-emoji-for-comments) on comments (also known as notes). See also [Notes API](notes.md).
+Emojis can also [be awarded](../user/award_emojis.md#award-emojis-for-comments) on comments (also known as notes). See also [Notes API](notes.md).
## Issues, merge requests, and snippets
-See [Award Emoji on Comments](#award-emoji-on-comments) for information on using these endpoints with comments.
+See [Award emojis on comments](#award-emojis-on-comments) for information on using these endpoints with comments.
### List an awardable's award emojis
@@ -201,7 +201,7 @@ Parameters:
curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/issues/80/award_emoji/344"
```
-## Award Emoji on Comments
+## Award emojis on comments
Comments (also known as notes) are a sub-resource of issues, merge requests, and snippets.
@@ -366,7 +366,7 @@ Parameters:
| `id` | integer/string | yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
| `issue_iid` | integer | yes | Internal ID of an issue. |
| `note_id` | integer | yes | ID of a comment (note). |
-| `award_id` | integer | yes | ID of an award_emoji. |
+| `award_id` | integer | yes | ID of an award emoji. |
Example request:
diff --git a/doc/api/broadcast_messages.md b/doc/api/broadcast_messages.md
index cc777a8bf53..d91557523a9 100644
--- a/doc/api/broadcast_messages.md
+++ b/doc/api/broadcast_messages.md
@@ -6,7 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Broadcast Messages API **(FREE SELF)**
-> `target_access_levels` [introduced](https://gitlab.com/gitlab-org/growth/team-tasks/-/issues/461) in GitLab 14.8 [with a flag](../administration/feature_flags.md) named `role_targeted_broadcast_messages`. Disabled by default.
+- > `target_access_levels` [introduced](https://gitlab.com/gitlab-org/growth/team-tasks/-/issues/461) in GitLab 14.8 [with a flag](../administration/feature_flags.md) named `role_targeted_broadcast_messages`. Disabled by default.
+- > `color` parameter [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95829) in GitLab 15.6.
Broadcast messages API operates on [broadcast messages](../user/admin_area/broadcast_messages.md).
@@ -37,7 +38,6 @@ Example response:
"message":"Example broadcast message",
"starts_at":"2016-08-24T23:21:16.078Z",
"ends_at":"2016-08-26T23:21:16.080Z",
- "color":"#E75E40",
"font":"#FFFFFF",
"id":1,
"active": false,
@@ -76,7 +76,6 @@ Example response:
"message":"Deploy in progress",
"starts_at":"2016-08-24T23:21:16.078Z",
"ends_at":"2016-08-26T23:21:16.080Z",
- "color":"#cecece",
"font":"#FFFFFF",
"id":1,
"active":false,
@@ -102,7 +101,6 @@ Parameters:
| `message` | string | yes | Message to display. |
| `starts_at` | datetime | no | Starting time (defaults to current time in UTC). Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `ends_at` | datetime | no | Ending time (defaults to one hour from current time in UTC). Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
-| `color` | string | no | Background color hex code. |
| `font` | string | no | Foreground color hex code. |
| `target_access_levels` | array of integers | no | Target access levels (roles) of the broadcast message.|
| `target_path` | string | no | Target path of the broadcast message. |
@@ -121,7 +119,7 @@ following levels are valid:
Example request:
```shell
-curl --data "message=Deploy in progress&color=#cecece&target_access_levels[]=10&target_access_levels[]=30" \
+curl --data "message=Deploy in progress&target_access_levels[]=10&target_access_levels[]=30" \
--header "PRIVATE-TOKEN: <your_access_token>" \
"https://gitlab.example.com/api/v4/broadcast_messages"
```
@@ -133,7 +131,6 @@ Example response:
"message":"Deploy in progress",
"starts_at":"2016-08-26T00:41:35.060Z",
"ends_at":"2016-08-26T01:41:35.060Z",
- "color":"#cecece",
"font":"#FFFFFF",
"id":1,
"active": true,
@@ -160,7 +157,6 @@ Parameters:
| `message` | string | no | Message to display. |
| `starts_at` | datetime | no | Starting time (UTC). Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
| `ends_at` | datetime | no | Ending time (UTC). Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) |
-| `color` | string | no | Background color hex code. |
| `font` | string | no | Foreground color hex code. |
| `target_access_levels` | array of integers | no | Target access levels (roles) of the broadcast message.|
| `target_path` | string | no | Target path of the broadcast message. |
@@ -179,7 +175,7 @@ following levels are valid:
Example request:
```shell
-curl --request PUT --data "message=Update message&color=#000" \
+curl --request PUT --data "message=Update message" \
--header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/broadcast_messages/1"
```
@@ -190,7 +186,6 @@ Example response:
"message":"Update message",
"starts_at":"2016-08-26T00:41:35.060Z",
"ends_at":"2016-08-26T01:41:35.060Z",
- "color":"#000",
"font":"#FFFFFF",
"id":1,
"active": true,
diff --git a/doc/api/commits.md b/doc/api/commits.md
index f08fe5ba881..3fe77dd5f43 100644
--- a/doc/api/commits.md
+++ b/doc/api/commits.md
@@ -58,7 +58,7 @@ Example response:
"parent_ids": [
"6104942438c14ec7bd21c6cd5bd995272b3faff6"
],
- "web_url": "https://gitlab.example.com/thedude/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746"
+ "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746"
},
{
"id": "6104942438c14ec7bd21c6cd5bd995272b3faff6",
@@ -73,7 +73,7 @@ Example response:
"parent_ids": [
"ae1d9fb46aa2b07ee9836d49862ec4e2c46fbbba"
],
- "web_url": "https://gitlab.example.com/thedude/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746"
+ "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746"
}
]
```
@@ -173,7 +173,7 @@ Example response:
"total": 4
},
"status": null,
- "web_url": "https://gitlab.example.com/thedude/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746"
+ "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746"
}
```
@@ -253,7 +253,7 @@ Example response:
"total": 25
},
"status": "running",
- "web_url": "https://gitlab.example.com/thedude/gitlab-foss/-/commit/6104942438c14ec7bd21c6cd5bd995272b3faff6"
+ "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/6104942438c14ec7bd21c6cd5bd995272b3faff6"
}
```
@@ -331,7 +331,7 @@ Example response:
"parent_ids": [
"a738f717824ff53aebad8b090c1b79a14f2bd9e8"
],
- "web_url": "https://gitlab.example.com/thedude/gitlab-foss/-/commit/8b090c1b79a14f2bd9e8a738f717824ff53aebad"
+ "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/8b090c1b79a14f2bd9e8a738f717824ff53aebad"
}
```
@@ -401,7 +401,7 @@ Example response:
"committer_name":"Administrator",
"committer_email":"admin@example.com",
"committed_date":"2018-11-08T15:55:26.000Z",
- "web_url": "https://gitlab.example.com/thedude/gitlab-foss/-/commit/8b090c1b79a14f2bd9e8a738f717824ff53aebad"
+ "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/commit/8b090c1b79a14f2bd9e8a738f717824ff53aebad"
}
```
@@ -536,7 +536,7 @@ POST /projects/:id/repository/commits/:sha/comments
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
- --form "note=Nice picture man\!" --form "path=dudeism.md" --form "line=11" --form "line_type=new" \
+ --form "note=Nice picture\!" --form "path=README.md" --form "line=11" --form "line_type=new" \
"https://gitlab.example.com/api/v4/projects/17/repository/commits/18f3e63d05582537db6d183d9d557be09e1f90c8/comments"
```
@@ -545,18 +545,18 @@ Example response:
```json
{
"author" : {
- "web_url" : "https://gitlab.example.com/thedude",
- "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/The-Big-Lebowski-400-400.png",
- "username" : "thedude",
+ "web_url" : "https://gitlab.example.com/janedoe",
+ "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/jane-doe-400-400.png",
+ "username" : "janedoe",
"state" : "active",
- "name" : "Jeff Lebowski",
+ "name" : "Jane Doe",
"id" : 28
},
"created_at" : "2016-01-19T09:44:55.600Z",
"line_type" : "new",
- "path" : "dudeism.md",
+ "path" : "README.md",
"line" : 11,
- "note" : "Nice picture man!"
+ "note" : "Nice picture!"
}
```
@@ -590,15 +590,15 @@ Example response:
{
"id": 334686748,
"type": null,
- "body": "I'm the Dude, so that's what you call me.",
+ "body": "Nice piece of code!",
"attachment": null,
"author" : {
"id" : 28,
- "name" : "Jeff Lebowski",
- "username" : "thedude",
- "web_url" : "https://gitlab.example.com/thedude",
+ "name" : "Jane Doe",
+ "username" : "janedoe",
+ "web_url" : "https://gitlab.example.com/janedoe",
"state" : "active",
- "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/The-Big-Lebowski-400-400.png"
+ "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/jane-doe-400-400.png"
},
"created_at": "2020-04-30T18:48:11.432Z",
"updated_at": "2020-04-30T18:48:11.432Z",
@@ -655,16 +655,16 @@ Example response:
"name" : "bundler:audit",
"allow_failure" : true,
"author" : {
- "username" : "thedude",
+ "username" : "janedoe",
"state" : "active",
- "web_url" : "https://gitlab.example.com/thedude",
- "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/The-Big-Lebowski-400-400.png",
+ "web_url" : "https://gitlab.example.com/janedoe",
+ "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/jane-doe-400-400.png",
"id" : 28,
- "name" : "Jeff Lebowski"
+ "name" : "Jane Doe"
},
"description" : null,
"sha" : "18f3e63d05582537db6d183d9d557be09e1f90c8",
- "target_url" : "https://gitlab.example.com/thedude/gitlab-foss/builds/91",
+ "target_url" : "https://gitlab.example.com/janedoe/gitlab-foss/builds/91",
"finished_at" : null,
"id" : 91,
"ref" : "master"
@@ -675,18 +675,18 @@ Example response:
"allow_failure" : false,
"status" : "pending",
"created_at" : "2016-01-19T08:40:25.832Z",
- "target_url" : "https://gitlab.example.com/thedude/gitlab-foss/builds/90",
+ "target_url" : "https://gitlab.example.com/janedoe/gitlab-foss/builds/90",
"id" : 90,
"finished_at" : null,
"ref" : "master",
"sha" : "18f3e63d05582537db6d183d9d557be09e1f90c8",
"author" : {
"id" : 28,
- "name" : "Jeff Lebowski",
- "username" : "thedude",
- "web_url" : "https://gitlab.example.com/thedude",
+ "name" : "Jane Doe",
+ "username" : "janedoe",
+ "web_url" : "https://gitlab.example.com/janedoe",
"state" : "active",
- "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/The-Big-Lebowski-400-400.png"
+ "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/jane-doe-400-400.png"
},
"description" : null
},
@@ -724,10 +724,10 @@ Example response:
```json
{
"author" : {
- "web_url" : "https://gitlab.example.com/thedude",
- "name" : "Jeff Lebowski",
- "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/The-Big-Lebowski-400-400.png",
- "username" : "thedude",
+ "web_url" : "https://gitlab.example.com/janedoe",
+ "name" : "Jane Doe",
+ "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/jane-doe-400-400.png",
+ "username" : "janedoe",
"state" : "active",
"id" : 28
},
@@ -781,10 +781,10 @@ Example response:
"upvotes":0,
"downvotes":0,
"author" : {
- "web_url" : "https://gitlab.example.com/thedude",
- "name" : "Jeff Lebowski",
- "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/The-Big-Lebowski-400-400.png",
- "username" : "thedude",
+ "web_url" : "https://gitlab.example.com/janedoe",
+ "name" : "Jane Doe",
+ "avatar_url" : "https://gitlab.example.com/uploads/user/avatar/28/jane-doe-400-400.png",
+ "username" : "janedoe",
"state" : "active",
"id" : 28
},
diff --git a/doc/api/container_registry.md b/doc/api/container_registry.md
index 6e8911df098..5b11c324802 100644
--- a/doc/api/container_registry.md
+++ b/doc/api/container_registry.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+group: Container 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
---
diff --git a/doc/api/dependency_proxy.md b/doc/api/dependency_proxy.md
index 05e144f5810..b7eade83bb8 100644
--- a/doc/api/dependency_proxy.md
+++ b/doc/api/dependency_proxy.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+group: Container 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
---
diff --git a/doc/api/deploy_tokens.md b/doc/api/deploy_tokens.md
index 5c4c99f3ba3..dff3ef05bb0 100644
--- a/doc/api/deploy_tokens.md
+++ b/doc/api/deploy_tokens.md
@@ -222,7 +222,7 @@ Parameters:
| Attribute | Type | Required | Description |
|:---------------|:---------------|:-----------------------|:------------|
-| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
+| `id` | integer/string | **{check-circle}** Yes | ID or [URL-encoded path of the group](index.md#namespaced-path-encoding). |
| `active` | boolean | **{dotted-circle}** No | Limit by active status. |
Example request:
diff --git a/doc/api/deployments.md b/doc/api/deployments.md
index 9618d57013f..daf2b635855 100644
--- a/doc/api/deployments.md
+++ b/doc/api/deployments.md
@@ -23,7 +23,7 @@ GET /projects/:id/deployments
| `updated_after` | datetime | no | Return deployments updated after the specified date. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). |
| `updated_before` | datetime | no | Return deployments updated before the specified date. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). |
| `environment` | string | no | The [name of the environment](../ci/environments/index.md) to filter deployments by. |
-| `status` | string | no | The status to filter deployments by. One of `created`, `running`, `success`, `failed`, `canceled`, `blocked`.
+| `status` | string | no | The status to filter deployments by. One of `created`, `running`, `success`, `failed`, `canceled`, or `blocked`.
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/deployments"
@@ -133,7 +133,7 @@ Example response:
"tag": false,
"project": {
"ci_job_token_scope_enabled": false
- },
+ },
"user": {
"id": 1,
"name": "Administrator",
@@ -487,7 +487,11 @@ curl --request "DELETE" --header "PRIVATE-TOKEN: <your_access_token>" "https://g
Example responses:
```json
-{ "message": "202 Accepted" }
+{ "message": "204 Deployment destroyed" }
+```
+
+```json
+{ "message": "403 Forbidden" }
```
```json
@@ -503,8 +507,7 @@ Example responses:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35739) in GitLab 12.7.
NOTE:
-Not all deployments can be associated with merge requests.
-Please see
+Not all deployments can be associated with merge requests. See
[Track what merge requests were deployed to an environment](../ci/environments/index.md#track-newly-included-merge-requests-per-deployment)
for more information.
diff --git a/doc/api/environments.md b/doc/api/environments.md
index 0f969ea4fd3..89b4bb6a1de 100644
--- a/doc/api/environments.md
+++ b/doc/api/environments.md
@@ -20,7 +20,7 @@ GET /projects/:id/environments
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
| `name` | string | no | Return the environment with this name. Mutually exclusive with `search` |
| `search` | string | no | Return list of environments matching the search criteria. Mutually exclusive with `name` |
-| `states` | string | no | List all environments that match a specific state. Accepted values: `available`, `stopping` or `stopped`. If no state value given, returns all environments. |
+| `states` | string | no | List all environments that match a specific state. Accepted values: `available`, `stopping`, or `stopped`. If no state value given, returns all environments. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/environments?name=review%2Ffix-foo"
@@ -279,7 +279,7 @@ Example response:
}
```
-## Edit an existing environment
+## Update an existing environment
Updates an existing environment's name and/or `external_url`.
diff --git a/doc/api/error_tracking.md b/doc/api/error_tracking.md
index c8f795ed88c..4d6d5e50245 100644
--- a/doc/api/error_tracking.md
+++ b/doc/api/error_tracking.md
@@ -1,6 +1,6 @@
---
stage: Monitor
-group: Respond
+group: Observability
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
diff --git a/doc/api/events.md b/doc/api/events.md
index 632f573be47..320c7a531e8 100644
--- a/doc/api/events.md
+++ b/doc/api/events.md
@@ -10,7 +10,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
### Actions
-See [User contribution events](../user/profile/index.md#user-contribution-events) for available types for the `action` parameter.
+See [User contribution events](../user/profile/contributions_calendar.md#user-contribution-events) for available types for the `action` parameter.
These options are in lowercase.
### Target Types
diff --git a/doc/api/feature_flag_specs.md b/doc/api/feature_flag_specs.md
index b549c790aaa..960d00278d6 100644
--- a/doc/api/feature_flag_specs.md
+++ b/doc/api/feature_flag_specs.md
@@ -2,11 +2,13 @@
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 **(PREMIUM)**
+# 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).
-Please use [the new API](feature_flags.md) instead.
+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 ef65da64668..ca4ca755d08 100644
--- a/doc/api/feature_flag_user_lists.md
+++ b/doc/api/feature_flag_user_lists.md
@@ -70,8 +70,8 @@ POST /projects/:id/feature_flags_user_lists
| Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
-| `name` | string | yes | The name of the feature flag. |
-| `user_xids` | string | yes | A comma-separated list of user IDs. |
+| `name` | string | yes | The name of the list. |
+| `user_xids` | string | yes | A comma-separated list of external user IDs. |
```shell
curl "https://gitlab.example.com/api/v4/projects/1/feature_flags_user_lists" \
@@ -142,8 +142,8 @@ PUT /projects/:id/feature_flags_user_lists/:iid
| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
| `iid` | integer/string | yes | The internal ID of the project's feature flag user list. |
-| `name` | string | no | The name of the feature flag. |
-| `user_xids` | string | no | A comma-separated list of user IDs. |
+| `name` | string | no | The name of the list. |
+| `user_xids` | string | no | A comma-separated list of external user IDs. |
```shell
curl "https://gitlab.example.com/api/v4/projects/1/feature_flags_user_lists/1" \
diff --git a/doc/api/feature_flags.md b/doc/api/feature_flags.md
index c4d766a6319..1aec1006610 100644
--- a/doc/api/feature_flags.md
+++ b/doc/api/feature_flags.md
@@ -144,14 +144,14 @@ POST /projects/:id/feature_flags
| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
| `name` | string | yes | The name of the feature flag. |
-| `version` | string | yes | The version of the feature flag. Must be `new_version_flag`. Omit or set to `legacy_flag` to create a Legacy feature flag. |
+| `version` | string | yes | The version of the feature flag. Must be `new_version_flag`. Omit to create a Legacy feature flag. |
| `description` | string | no | The description of the feature flag. |
| `active` | boolean | no | The active state of the flag. Defaults to true. [Supported](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38350) in GitLab 13.3 and later. |
| `strategies` | JSON | no | The feature flag [strategies](../operations/feature_flags.md#feature-flag-strategies). |
| `strategies:name` | JSON | no | The strategy name. Can be `default`, `gradualRolloutUserId`, `userWithId`, or `gitlabUserList`. In [GitLab 13.5](https://gitlab.com/gitlab-org/gitlab/-/issues/36380) and later, can be [`flexibleRollout`](https://docs.getunleash.io/user_guide/activation_strategy#gradual-rollout). |
| `strategies:parameters` | JSON | no | The strategy parameters. |
| `strategies:scopes` | JSON | no | The scopes for the strategy. |
-| `strategies:scopes:environment_scope` | string | no | The environment spec for the scope. |
+| `strategies:scopes:environment_scope` | string | no | The environment scope of the scope. |
```shell
curl "https://gitlab.example.com/api/v4/projects/1/feature_flags" \
@@ -213,8 +213,8 @@ PUT /projects/:id/feature_flags/:feature_flag_name
| `strategies:name` | JSON | no | The strategy name. |
| `strategies:parameters` | JSON | no | The strategy parameters. |
| `strategies:scopes` | JSON | no | The scopes for the strategy. |
-| `strategies:scopes:id` | JSON | no | The scopes ID. |
-| `strategies:scopes:environment_scope` | string | no | The environment spec for the scope. |
+| `strategies:scopes:id` | JSON | no | The environment scope ID. |
+| `strategies:scopes:environment_scope` | string | no | The environment scope of the scope. |
```shell
curl "https://gitlab.example.com/api/v4/projects/1/feature_flags/awesome_feature" \
diff --git a/doc/api/features.md b/doc/api/features.md
index 6f3af683020..819405bea77 100644
--- a/doc/api/features.md
+++ b/doc/api/features.md
@@ -111,20 +111,21 @@ percentage of time.
POST /features/:name
```
-| Attribute | Type | Required | Description |
-| --------- | ---- | -------- | ----------- |
-| `name` | string | yes | Name of the feature to create or update |
-| `value` | integer/string | yes | `true` or `false` to enable/disable, or an integer for percentage of time |
-| `key` | string | no | `percentage_of_actors` or `percentage_of_time` (default) |
-| `feature_group` | string | no | A Feature group name |
-| `user` | string | no | A GitLab username or comma-separated multiple usernames |
-| `group` | string | no | A GitLab group's path, for example `gitlab-org`, or comma-separated multiple group paths |
-| `namespace` | string | no | A GitLab group or user namespace's path, for example `john-doe`, or comma-separated multiple namespace paths. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/353117) in GitLab 15.0. |
-| `project` | string | no | A projects path, for example `gitlab-org/gitlab-foss`, or comma-separated multiple project paths |
-| `force` | boolean | no | Skip feature flag validation checks, such as a YAML definition |
+| Attribute | Type | Required | Description |
+|-----------------|----------------|----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `name` | string | yes | Name of the feature to create or update |
+| `value` | integer/string | yes | `true` or `false` to enable/disable, or an integer for percentage of time |
+| `key` | string | no | `percentage_of_actors` or `percentage_of_time` (default) |
+| `feature_group` | string | no | A Feature group name |
+| `user` | string | no | A GitLab username or comma-separated multiple usernames |
+| `group` | string | no | A GitLab group's path, for example `gitlab-org`, or comma-separated multiple group paths |
+| `namespace` | string | no | A GitLab group or user namespace's path, for example `john-doe`, or comma-separated multiple namespace paths. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/353117) in GitLab 15.0. |
+| `project` | string | no | A projects path, for example `gitlab-org/gitlab-foss`, or comma-separated multiple project paths |
+| `repository` | string | no | A repository path, for example `gitlab-org/gitlab-test.git`, `gitlab-org/gitlab-test.wiki.git`, , `snippets/21.git`, to name a few. Use comma to separate multiple repository paths |
+| `force` | boolean | no | Skip feature flag validation checks, such as a YAML definition |
You can enable or disable a feature for a `feature_group`, a `user`,
-a `group`, a `namespace` and a `project` in a single API call.
+a `group`, a `namespace`, a `project`, and a `repository` in a single API call.
```shell
curl --data "value=30" --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/features/new_library"
diff --git a/doc/api/freeze_periods.md b/doc/api/freeze_periods.md
index 36d069df607..9d2989229ae 100644
--- a/doc/api/freeze_periods.md
+++ b/doc/api/freeze_periods.md
@@ -16,9 +16,9 @@ You can use the Freeze Periods API to manipulate GitLab [Freeze Period](../user/
Only users with Maintainer [permissions](../user/permissions.md) can
interact with the Freeze Period API endpoints.
-## List Freeze Periods
+## List freeze periods
-Paginated list of Freeze Periods, sorted by `created_at` in ascending order.
+Paginated list of freeze periods, sorted by `created_at` in ascending order.
```plaintext
GET /projects/:id/freeze_periods
@@ -49,9 +49,9 @@ Example response:
]
```
-## Get a Freeze Period by a `freeze_period_id`
+## Get a freeze period by a `freeze_period_id`
-Get a Freeze Period for the given `freeze_period_id`.
+Get a freeze period for the given `freeze_period_id`.
```plaintext
GET /projects/:id/freeze_periods/:freeze_period_id
@@ -60,7 +60,7 @@ GET /projects/:id/freeze_periods/:freeze_period_id
| Attribute | Type | Required | Description |
| ------------- | -------------- | -------- | ----------------------------------------------------------------------------------- |
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
-| `freeze_period_id` | string | yes | The database ID of the Freeze Period. |
+| `freeze_period_id` | integer | yes | The ID of the freeze period. |
Example request:
@@ -81,9 +81,9 @@ Example response:
}
```
-## Create a Freeze Period
+## Create a freeze period
-Create a Freeze Period.
+Create a freeze period.
```plaintext
POST /projects/:id/freeze_periods
@@ -92,8 +92,8 @@ POST /projects/:id/freeze_periods
| Attribute | Type | Required | Description |
| -------------------| --------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
-| `freeze_start` | string | yes | Start of the Freeze Period in [cron](https://crontab.guru/) format. |
-| `freeze_end` | string | yes | End of the Freeze Period in [cron](https://crontab.guru/) format. |
+| `freeze_start` | string | yes | Start of the freeze period in [cron](https://crontab.guru/) format. |
+| `freeze_end` | string | yes | End of the freeze period in [cron](https://crontab.guru/) format. |
| `cron_timezone` | string | no | The time zone for the cron fields, defaults to UTC if not provided. |
Example request:
@@ -117,9 +117,9 @@ Example response:
}
```
-## Update a Freeze Period
+## Update a freeze period
-Update a Freeze Period for the given `freeze_period_id`.
+Update a freeze period for the given `freeze_period_id`.
```plaintext
PUT /projects/:id/freeze_periods/:freeze_period_id
@@ -128,9 +128,9 @@ PUT /projects/:id/freeze_periods/:freeze_period_id
| Attribute | Type | Required | Description |
| ------------- | --------------- | -------- | ----------------------------------------------------------------------------------------------------------- |
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
-| `freeze_period_id` | integer or string | yes | The database ID of the Freeze Period. |
-| `freeze_start` | string | no | Start of the Freeze Period in [cron](https://crontab.guru/) format. |
-| `freeze_end` | string | no | End of the Freeze Period in [cron](https://crontab.guru/) format. |
+| `freeze_period_id` | integer | yes | The ID of the freeze period. |
+| `freeze_start` | string | no | Start of the freeze period in [cron](https://crontab.guru/) format. |
+| `freeze_end` | string | no | End of the freeze period in [cron](https://crontab.guru/) format. |
| `cron_timezone` | string | no | The time zone for the cron fields. |
Example request:
@@ -154,9 +154,9 @@ Example response:
}
```
-## Delete a Freeze Period
+## Delete a freeze period
-Delete a Freeze Period for the given `freeze_period_id`.
+Delete a freeze period for the given `freeze_period_id`.
```plaintext
DELETE /projects/:id/freeze_periods/:freeze_period_id
@@ -165,7 +165,7 @@ DELETE /projects/:id/freeze_periods/:freeze_period_id
| Attribute | Type | Required | Description |
| ------------- | -------------- | -------- | ----------------------------------------------------------------------------------- |
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
-| `freeze_period_id` | string | yes | The database ID of the Freeze Period. |
+| `freeze_period_id` | integer | yes | The ID of the freeze period. |
Example request:
diff --git a/doc/api/geo_nodes.md b/doc/api/geo_nodes.md
index fe25b6661a0..00380e1624b 100644
--- a/doc/api/geo_nodes.md
+++ b/doc/api/geo_nodes.md
@@ -504,6 +504,19 @@ Example response:
"ci_secure_files_synced_in_percentage": "100.00%",
"ci_secure_files_verified_in_percentage": "100.00%",
"ci_secure_files_synced_missing_on_primary_count": 0,
+ "dependency_proxy_blobs_count": 5,
+ "dependency_proxy_blobs_checksum_total_count": 5,
+ "dependency_proxy_blobs_checksummed_count": 5,
+ "dependency_proxy_blobs_checksum_failed_count": 0,
+ "dependency_proxy_blobs_synced_count": 5,
+ "dependency_proxy_blobs_failed_count": 0,
+ "dependency_proxy_blobs_registry_count": 5,
+ "dependency_proxy_blobs_verification_total_count": 5,
+ "dependency_proxy_blobs_verified_count": 5,
+ "dependency_proxy_blobs_verification_failed_count": 0,
+ "dependency_proxy_blobs_synced_in_percentage": "100.00%",
+ "dependency_proxy_blobs_verified_in_percentage": "100.00%",
+ "dependency_proxy_blobs_synced_missing_on_primary_count": 0,
"container_repositories_count": 5,
"container_repositories_synced_count": 5,
"container_repositories_failed_count": 0,
@@ -675,6 +688,19 @@ Example response:
"job_artifacts_synced_in_percentage": "100.00%",
"job_artifacts_verified_in_percentage": "100.00%",
"job_artifacts_synced_missing_on_primary_count": 0,
+ "dependency_proxy_blobs_count": 5,
+ "dependency_proxy_blobs_checksum_total_count": 5,
+ "dependency_proxy_blobs_checksummed_count": 5,
+ "dependency_proxy_blobs_checksum_failed_count": 0,
+ "dependency_proxy_blobs_synced_count": 5,
+ "dependency_proxy_blobs_failed_count": 0,
+ "dependency_proxy_blobs_registry_count": 5,
+ "dependency_proxy_blobs_verification_total_count": 5,
+ "dependency_proxy_blobs_verified_count": 5,
+ "dependency_proxy_blobs_verification_failed_count": 0,
+ "dependency_proxy_blobs_synced_in_percentage": "100.00%",
+ "dependency_proxy_blobs_verified_in_percentage": "100.00%",
+ "dependency_proxy_blobs_synced_missing_on_primary_count": 0,
"container_repositories_count": 5,
"container_repositories_synced_count": 5,
"container_repositories_failed_count": 0,
@@ -856,6 +882,19 @@ Example response:
"ci_secure_files_synced_in_percentage": "100.00%",
"ci_secure_files_verified_in_percentage": "100.00%",
"ci_secure_files_synced_missing_on_primary_count": 0,
+ "dependency_proxy_blobs_count": 5,
+ "dependency_proxy_blobs_checksum_total_count": 5,
+ "dependency_proxy_blobs_checksummed_count": 5,
+ "dependency_proxy_blobs_checksum_failed_count": 0,
+ "dependency_proxy_blobs_synced_count": 5,
+ "dependency_proxy_blobs_failed_count": 0,
+ "dependency_proxy_blobs_registry_count": 5,
+ "dependency_proxy_blobs_verification_total_count": 5,
+ "dependency_proxy_blobs_verified_count": 5,
+ "dependency_proxy_blobs_verification_failed_count": 0,
+ "dependency_proxy_blobs_synced_in_percentage": "100.00%",
+ "dependency_proxy_blobs_verified_in_percentage": "100.00%",
+ "dependency_proxy_blobs_synced_missing_on_primary_count": 0,
"container_repositories_count": 5,
"container_repositories_synced_count": 5,
"container_repositories_failed_count": 0,
diff --git a/doc/api/graphql/custom_emoji.md b/doc/api/graphql/custom_emoji.md
index ea90b02a069..e2e8bce4290 100644
--- a/doc/api/graphql/custom_emoji.md
+++ b/doc/api/graphql/custom_emoji.md
@@ -6,17 +6,15 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Use custom emojis with GraphQL **(FREE)**
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37911) in GitLab 13.6
-> - [Deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
-> - Enabled on GitLab.com.
-> - Recommended for production use.
-> - To use in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-custom-emoji-api). **(FREE SELF)**
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37911) in GitLab 13.6 [with a flag](../../administration/feature_flags.md) named `custom_emoji`. Disabled by default.
+> - Enabled on GitLab.com in GitLab 14.0.
-This in-development feature might not be available for your use. There can be
-[risks when enabling features still in development](../../administration/feature_flags.md#risks-when-enabling-features-still-in-development).
-Refer to this feature's version history for more details.
+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 `custom_emoji`.
+On GitLab.com, this feature is available.
+This feature is ready for production use.
-To use custom emoji in comments and descriptions, you can add them to a group using the GraphQL API.
+To use custom emojis in comments and descriptions, you can add them to a group using the GraphQL API.
Parameters:
@@ -30,15 +28,17 @@ Parameters:
```graphql
mutation CreateCustomEmoji($groupPath: ID!) {
- createCustomEmoji(input: {groupPath: $groupPath, name: "party-parrot", file: "https://cultofthepartyparrot.com/parrots/hd/parrot.gif", external: true}) {
+ createCustomEmoji(input: {groupPath: $groupPath, name: "party-parrot", url: "https://cultofthepartyparrot.com/parrots/hd/parrot.gif"}) {
clientMutationId
- name
+ customEmoji {
+ name
+ }
errors
}
}
```
-After adding custom emoji to the group, members can use it in the same way as other emoji in the comments.
+After adding a custom emoji to the group, members can use it in the same way as other emojis in the comments.
## Get custom emoji for a group
@@ -90,22 +90,3 @@ For more information on:
- GraphQL specific entities, such as Fragments and Interfaces, see the official
[GraphQL documentation](https://graphql.org/learn/).
- Individual attributes, see the [GraphQL API Resources](reference/index.md).
-
-## Enable or disable custom emoji API **(FREE SELF)**
-
-Custom emoji 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 enable it.
-
-To enable it:
-
-```ruby
-Feature.enable(:custom_emoji)
-```
-
-To disable it:
-
-```ruby
-Feature.disable(:custom_emoji)
-```
diff --git a/doc/api/graphql/getting_started.md b/doc/api/graphql/getting_started.md
index 20fb2f030f2..1945f528d67 100644
--- a/doc/api/graphql/getting_started.md
+++ b/doc/api/graphql/getting_started.md
@@ -18,6 +18,7 @@ The examples documented here can be run using:
- The command line.
- GraphiQL.
+- Rails console.
### Command line
@@ -73,6 +74,27 @@ NOTE:
If you are running GitLab 12.0, enable the `graphql`
[feature flag](../features.md#set-or-create-a-feature).
+### Rails console **(FREE SELF)**
+
+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
+query = <<~EOQ
+query securityGetProjects($search: String!) {
+ projects(search: $search) {
+ nodes {
+ path
+ }
+ }
+}
+EOQ
+
+variables = { "search": "gitlab" }
+
+result = GitlabSchema.execute(query, variables: variables, context: { current_user: current_user })
+result.to_h
+```
+
## Queries and mutations
The GitLab GraphQL API can be used to perform:
diff --git a/doc/api/graphql/index.md b/doc/api/graphql/index.md
index 40e1ed115a3..4cf296ac1f3 100644
--- a/doc/api/graphql/index.md
+++ b/doc/api/graphql/index.md
@@ -69,12 +69,13 @@ However, GitLab sometimes changes the GraphQL API in a way that is not backward-
can include removing or renaming fields, arguments, or other parts of the schema.
When creating a breaking change, GitLab follows a [deprecation and removal process](#deprecation-and-removal-process).
-Learn more about [breaking changes](../../development/deprecation_guidelines/index.md).
+To avoid having a breaking change affect your integrations, you should
+familiarize yourself with the [deprecation and removal process](#deprecation-and-removal-process) and
+frequently [verify your API calls against the future breaking-change schema](#verify-against-the-future-breaking-change-schema).
Fields behind a feature flag and disabled by default do not follow the deprecation and removal process, and can be removed at any time without notice.
-To avoid having a breaking change affect your integrations, you should
-familiarize yourself with the deprecation and removal process.
+Learn more about [breaking changes](../../development/deprecation_guidelines/index.md).
WARNING:
GitLab makes all attempts to follow the [deprecation and removal process](#deprecation-and-removal-process).
@@ -82,10 +83,22 @@ On rare occasions, GitLab might make immediate breaking changes to the GraphQL
API to patch critical security or performance concerns if the deprecation
process would pose significant risk.
+### Verify against the future breaking-change schema
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/353642) in GitLab 15.6.
+
+You can make calls against the GraphQL API as if all deprecated items were already removed.
+This way, you can verify API calls ahead of a [breaking-change release](#deprecation-and-removal-process)
+before the items are actually removed from the schema.
+
+To make these calls, add a
+`remove_deprecated=true` query parameter to the GitLab GraphQL API endpoint (for example,
+`https://gitlab.com/api/graphql?remove_deprecated=true` for GitLab SaaS GraphQL).
+
### Deprecation and removal process
The deprecation and removal process for the GitLab GraphQL API aligns with the wider GitLab
-[deprecation process](https://about.gitlab.com/handbook/product/gitlab-the-product/#breaking-changes-deprecations-and-removing-features).
+[deprecation process](https://about.gitlab.com/handbook/product/gitlab-the-product/#deprecations-removals-and-breaking-changes).
Parts of the schema marked for removal from the GitLab GraphQL API are first
[deprecated](https://about.gitlab.com/handbook/product/gitlab-the-product/#deprecation)
@@ -99,12 +112,13 @@ Items are marked as deprecated in:
- The [deprecation feature removal schedule](../../update/deprecations.md), which is linked from release posts.
- Introspection queries of the GraphQL API.
+The deprecation message provides an alternative for the deprecated schema item,
+if applicable.
+
NOTE:
If you use the GraphQL API, we recommend you remove the deprecated schema from your GraphQL
API calls as soon as possible to avoid experiencing breaking changes.
-
-The deprecation message provides an alternative for the deprecated schema item,
-if applicable.
+You should [verify your API calls against the schema without the deprecated schema items](#verify-against-the-future-breaking-change-schema).
#### Deprecation example
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 11a60671008..b1f9d6ceae1 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -214,6 +214,57 @@ Returns [`Issue`](#issue).
| ---- | ---- | ----------- |
| <a id="queryissueid"></a>`id` | [`IssueID!`](#issueid) | Global ID of the issue. |
+### `Query.issues`
+
+Issues visible by the current user. Returns null if the `root_level_issues_query` feature flag is disabled.
+
+WARNING:
+**Introduced** in 15.6.
+This feature is in Alpha. It can be changed or removed at any time.
+
+Returns [`IssueConnection`](#issueconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="queryissuesassigneeid"></a>`assigneeId` | [`String`](#string) | ID of a user assigned to the issues. Wildcard values "NONE" and "ANY" are supported. |
+| <a id="queryissuesassigneeusername"></a>`assigneeUsername` **{warning-solid}** | [`String`](#string) | **Deprecated** in 13.11. Use `assigneeUsernames`. |
+| <a id="queryissuesassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Usernames of users assigned to the issue. |
+| <a id="queryissuesauthorusername"></a>`authorUsername` | [`String`](#string) | Username of the author of the issue. |
+| <a id="queryissuesclosedafter"></a>`closedAfter` | [`Time`](#time) | Issues closed after this date. |
+| <a id="queryissuesclosedbefore"></a>`closedBefore` | [`Time`](#time) | Issues closed before this date. |
+| <a id="queryissuesconfidential"></a>`confidential` | [`Boolean`](#boolean) | Filter for confidential issues. If "false", excludes confidential issues. If "true", returns only confidential issues. |
+| <a id="queryissuescreatedafter"></a>`createdAfter` | [`Time`](#time) | Issues created after this date. |
+| <a id="queryissuescreatedbefore"></a>`createdBefore` | [`Time`](#time) | Issues created before this date. |
+| <a id="queryissuescrmcontactid"></a>`crmContactId` | [`String`](#string) | ID of a contact assigned to the issues. |
+| <a id="queryissuescrmorganizationid"></a>`crmOrganizationId` | [`String`](#string) | ID of an organization assigned to the issues. |
+| <a id="queryissuesepicid"></a>`epicId` | [`String`](#string) | ID of an epic associated with the issues, "none" and "any" values are supported. |
+| <a id="queryissueshealthstatusfilter"></a>`healthStatusFilter` | [`HealthStatusFilter`](#healthstatusfilter) | Health status of the issue, "none" and "any" values are supported. |
+| <a id="queryissuesiid"></a>`iid` | [`String`](#string) | IID of the issue. For example, "1". |
+| <a id="queryissuesiids"></a>`iids` | [`[String!]`](#string) | List of IIDs of issues. For example, `["1", "2"]`. |
+| <a id="queryissuesin"></a>`in` | [`[IssuableSearchableField!]`](#issuablesearchablefield) | Specify the fields to perform the search in. Defaults to `[TITLE, DESCRIPTION]`. Requires the `search` argument.'. |
+| <a id="queryissuesincludesubepics"></a>`includeSubepics` | [`Boolean`](#boolean) | Whether to include subepics when filtering issues by epicId. |
+| <a id="queryissuesiterationid"></a>`iterationId` | [`[ID]`](#id) | List of iteration Global IDs applied to the issue. |
+| <a id="queryissuesiterationwildcardid"></a>`iterationWildcardId` | [`IterationWildcardId`](#iterationwildcardid) | Filter by iteration ID wildcard. |
+| <a id="queryissueslabelname"></a>`labelName` | [`[String]`](#string) | Labels applied to this issue. |
+| <a id="queryissuesmilestonetitle"></a>`milestoneTitle` | [`[String]`](#string) | Milestone applied to this issue. |
+| <a id="queryissuesmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. |
+| <a id="queryissuesmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by reaction emoji applied by the current user. Wildcard values "NONE" and "ANY" are supported. |
+| <a id="queryissuesnot"></a>`not` | [`NegatedIssueFilterInput`](#negatedissuefilterinput) | Negated arguments. |
+| <a id="queryissuesor"></a>`or` | [`UnionedIssueFilterInput`](#unionedissuefilterinput) | List of arguments with inclusive OR. |
+| <a id="queryissuessearch"></a>`search` | [`String`](#string) | Search query for title or description. |
+| <a id="queryissuessort"></a>`sort` | [`IssueSort`](#issuesort) | Sort issues by this criteria. |
+| <a id="queryissuesstate"></a>`state` | [`IssuableState`](#issuablestate) | Current state of this issue. |
+| <a id="queryissuestypes"></a>`types` | [`[IssueType!]`](#issuetype) | Filter issues by the given issue types. |
+| <a id="queryissuesupdatedafter"></a>`updatedAfter` | [`Time`](#time) | Issues updated after this date. |
+| <a id="queryissuesupdatedbefore"></a>`updatedBefore` | [`Time`](#time) | Issues updated before this date. |
+| <a id="queryissuesweight"></a>`weight` | [`String`](#string) | Weight applied to the issue, "none" and "any" values are supported. |
+
### `Query.iteration`
Find an iteration.
@@ -595,7 +646,7 @@ Returns [`Vulnerability`](#vulnerability).
### `Query.workItem`
-Find a work item. Returns `null` if `work_items` feature flag is disabled.
+Find a work item.
WARNING:
**Introduced** in 15.1.
@@ -673,6 +724,7 @@ Input type: `AdminSidekiqQueuesDeleteJobsInput`
| <a id="mutationadminsidekiqqueuesdeletejobsrootnamespace"></a>`rootNamespace` | [`String`](#string) | Delete jobs matching root_namespace in the context metadata. |
| <a id="mutationadminsidekiqqueuesdeletejobssubscriptionplan"></a>`subscriptionPlan` | [`String`](#string) | Delete jobs matching subscription_plan in the context metadata. |
| <a id="mutationadminsidekiqqueuesdeletejobsuser"></a>`user` | [`String`](#string) | Delete jobs matching user in the context metadata. |
+| <a id="mutationadminsidekiqqueuesdeletejobsuserid"></a>`userId` | [`String`](#string) | Delete jobs matching user_id in the context metadata. |
| <a id="mutationadminsidekiqqueuesdeletejobsworkerclass"></a>`workerClass` | [`String`](#string) | Delete jobs with the given worker class. |
#### Fields
@@ -778,6 +830,26 @@ Input type: `ArtifactDestroyInput`
| <a id="mutationartifactdestroyclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationartifactdestroyerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+### `Mutation.auditEventsStreamingDestinationEventsAdd`
+
+Input type: `AuditEventsStreamingDestinationEventsAddInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationauditeventsstreamingdestinationeventsaddclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationauditeventsstreamingdestinationeventsadddestinationid"></a>`destinationId` | [`AuditEventsExternalAuditEventDestinationID!`](#auditeventsexternalauditeventdestinationid) | Destination id. |
+| <a id="mutationauditeventsstreamingdestinationeventsaddeventtypefilters"></a>`eventTypeFilters` | [`[String!]!`](#string) | List of event type filters to add for streaming. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationauditeventsstreamingdestinationeventsaddclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationauditeventsstreamingdestinationeventsadderrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationauditeventsstreamingdestinationeventsaddeventtypefilters"></a>`eventTypeFilters` | [`[String!]`](#string) | Event type filters present. |
+
### `Mutation.auditEventsStreamingHeadersCreate`
Input type: `AuditEventsStreamingHeadersCreateInput`
@@ -4198,6 +4270,25 @@ Input type: `PipelineScheduleDeleteInput`
| <a id="mutationpipelinescheduledeleteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationpipelinescheduledeleteerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+### `Mutation.pipelineScheduleTakeOwnership`
+
+Input type: `PipelineScheduleTakeOwnershipInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationpipelinescheduletakeownershipclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationpipelinescheduletakeownershipid"></a>`id` | [`CiPipelineScheduleID!`](#cipipelinescheduleid) | ID of the pipeline schedule to mutate. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationpipelinescheduletakeownershipclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationpipelinescheduletakeownershiperrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationpipelinescheduletakeownershippipelineschedule"></a>`pipelineSchedule` | [`PipelineSchedule`](#pipelineschedule) | Updated pipeline schedule ownership. |
+
### `Mutation.projectCiCdSettingsUpdate`
Input type: `ProjectCiCdSettingsUpdateInput`
@@ -4863,6 +4954,10 @@ Input type: `TerraformStateUnlockInput`
### `Mutation.timelineEventCreate`
+WARNING:
+**Introduced** in 15.6.
+This feature is in Alpha. It can be changed or removed at any time.
+
Input type: `TimelineEventCreateInput`
#### Arguments
@@ -4873,6 +4968,7 @@ Input type: `TimelineEventCreateInput`
| <a id="mutationtimelineeventcreateincidentid"></a>`incidentId` | [`IssueID!`](#issueid) | Incident ID of the timeline event. |
| <a id="mutationtimelineeventcreatenote"></a>`note` | [`String!`](#string) | Text note of the timeline event. |
| <a id="mutationtimelineeventcreateoccurredat"></a>`occurredAt` | [`Time!`](#time) | Timestamp of when the event occurred. |
+| <a id="mutationtimelineeventcreatetimelineeventtagnames"></a>`timelineEventTagNames` | [`[String!]`](#string) | Tags for the incident timeline event. |
#### Fields
@@ -4920,6 +5016,26 @@ Input type: `TimelineEventPromoteFromNoteInput`
| <a id="mutationtimelineeventpromotefromnoteerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationtimelineeventpromotefromnotetimelineevent"></a>`timelineEvent` | [`TimelineEventType`](#timelineeventtype) | Timeline event. |
+### `Mutation.timelineEventTagCreate`
+
+Input type: `TimelineEventTagCreateInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationtimelineeventtagcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationtimelineeventtagcreatename"></a>`name` | [`String!`](#string) | Name of the tag. |
+| <a id="mutationtimelineeventtagcreateprojectpath"></a>`projectPath` | [`ID!`](#id) | Project to create the timeline event tag in. |
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="mutationtimelineeventtagcreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
+| <a id="mutationtimelineeventtagcreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
+| <a id="mutationtimelineeventtagcreatetimelineeventtag"></a>`timelineEventTag` | [`TimelineEventTagType`](#timelineeventtagtype) | Timeline event tag. |
+
### `Mutation.timelineEventUpdate`
Input type: `TimelineEventUpdateInput`
@@ -5758,7 +5874,7 @@ Input type: `VulnerabilityRevertToDetectedInput`
### `Mutation.workItemCreate`
-Creates a work item. Available only when feature flag `work_items` is enabled.
+Creates a work item.
WARNING:
**Introduced** in 15.1.
@@ -5774,6 +5890,7 @@ Input type: `WorkItemCreateInput`
| <a id="mutationworkitemcreateconfidential"></a>`confidential` | [`Boolean`](#boolean) | Sets the work item confidentiality. |
| <a id="mutationworkitemcreatedescription"></a>`description` | [`String`](#string) | Description of the work item. |
| <a id="mutationworkitemcreatehierarchywidget"></a>`hierarchyWidget` | [`WorkItemWidgetHierarchyCreateInput`](#workitemwidgethierarchycreateinput) | Input for hierarchy widget. |
+| <a id="mutationworkitemcreatemilestonewidget"></a>`milestoneWidget` | [`WorkItemWidgetMilestoneInput`](#workitemwidgetmilestoneinput) | Input for milestone widget. |
| <a id="mutationworkitemcreateprojectpath"></a>`projectPath` | [`ID!`](#id) | Full path of the project the work item is associated with. |
| <a id="mutationworkitemcreatetitle"></a>`title` | [`String!`](#string) | Title of the work item. |
| <a id="mutationworkitemcreateworkitemtypeid"></a>`workItemTypeId` | [`WorkItemsTypeID!`](#workitemstypeid) | Global ID of a work item type. |
@@ -5788,7 +5905,7 @@ Input type: `WorkItemCreateInput`
### `Mutation.workItemCreateFromTask`
-Creates a work item from a task in another work item's description. Available only when feature flag `work_items` is enabled.
+Creates a work item from a task in another work item's description.
WARNING:
**Introduced** in 15.1.
@@ -5815,7 +5932,7 @@ Input type: `WorkItemCreateFromTaskInput`
### `Mutation.workItemDelete`
-Deletes a work item. Available only when feature flag `work_items` is enabled.
+Deletes a work item.
WARNING:
**Introduced** in 15.1.
@@ -5840,7 +5957,7 @@ Input type: `WorkItemDeleteInput`
### `Mutation.workItemDeleteTask`
-Deletes a task in a work item's description. Available only when feature flag `work_items` is enabled.
+Deletes a task in a work item's description.
WARNING:
**Introduced** in 15.1.
@@ -5867,7 +5984,7 @@ Input type: `WorkItemDeleteTaskInput`
### `Mutation.workItemUpdate`
-Updates a work item by Global ID. Available only when feature flag `work_items` is enabled.
+Updates a work item by Global ID.
WARNING:
**Introduced** in 15.1.
@@ -5887,6 +6004,7 @@ Input type: `WorkItemUpdateInput`
| <a id="mutationworkitemupdateid"></a>`id` | [`WorkItemID!`](#workitemid) | Global ID of the work item. |
| <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="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. |
| <a id="mutationworkitemupdatestatuswidget"></a>`statusWidget` | [`StatusInput`](#statusinput) | Input for status widget. |
@@ -5903,7 +6021,7 @@ Input type: `WorkItemUpdateInput`
### `Mutation.workItemUpdateTask`
-Updates a work item's task by Global ID. Available only when feature flag `work_items` is enabled.
+Updates a work item's task by Global ID.
WARNING:
**Introduced** in 15.1.
@@ -6934,6 +7052,29 @@ The edge type for [`ContainerRepositoryTag`](#containerrepositorytag).
| <a id="containerrepositorytagedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="containerrepositorytagedgenode"></a>`node` | [`ContainerRepositoryTag`](#containerrepositorytag) | The item at the end of the edge. |
+#### `ContributionAnalyticsContributionConnection`
+
+The connection type for [`ContributionAnalyticsContribution`](#contributionanalyticscontribution).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="contributionanalyticscontributionconnectionedges"></a>`edges` | [`[ContributionAnalyticsContributionEdge]`](#contributionanalyticscontributionedge) | A list of edges. |
+| <a id="contributionanalyticscontributionconnectionnodes"></a>`nodes` | [`[ContributionAnalyticsContribution]`](#contributionanalyticscontribution) | A list of nodes. |
+| <a id="contributionanalyticscontributionconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `ContributionAnalyticsContributionEdge`
+
+The edge type for [`ContributionAnalyticsContribution`](#contributionanalyticscontribution).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="contributionanalyticscontributionedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="contributionanalyticscontributionedgenode"></a>`node` | [`ContributionAnalyticsContribution`](#contributionanalyticscontribution) | The item at the end of the edge. |
+
#### `CoverageFuzzingCorpusConnection`
The connection type for [`CoverageFuzzingCorpus`](#coveragefuzzingcorpus).
@@ -7142,6 +7283,29 @@ The edge type for [`DependencyProxyBlob`](#dependencyproxyblob).
| <a id="dependencyproxyblobedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="dependencyproxyblobedgenode"></a>`node` | [`DependencyProxyBlob`](#dependencyproxyblob) | The item at the end of the edge. |
+#### `DependencyProxyBlobRegistryConnection`
+
+The connection type for [`DependencyProxyBlobRegistry`](#dependencyproxyblobregistry).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="dependencyproxyblobregistryconnectionedges"></a>`edges` | [`[DependencyProxyBlobRegistryEdge]`](#dependencyproxyblobregistryedge) | A list of edges. |
+| <a id="dependencyproxyblobregistryconnectionnodes"></a>`nodes` | [`[DependencyProxyBlobRegistry]`](#dependencyproxyblobregistry) | A list of nodes. |
+| <a id="dependencyproxyblobregistryconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `DependencyProxyBlobRegistryEdge`
+
+The edge type for [`DependencyProxyBlobRegistry`](#dependencyproxyblobregistry).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="dependencyproxyblobregistryedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="dependencyproxyblobregistryedgenode"></a>`node` | [`DependencyProxyBlobRegistry`](#dependencyproxyblobregistry) | The item at the end of the edge. |
+
#### `DependencyProxyManifestConnection`
The connection type for [`DependencyProxyManifest`](#dependencyproxymanifest).
@@ -7513,6 +7677,29 @@ The edge type for [`ExternalAuditEventDestination`](#externalauditeventdestinati
| <a id="externalauditeventdestinationedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="externalauditeventdestinationedgenode"></a>`node` | [`ExternalAuditEventDestination`](#externalauditeventdestination) | The item at the end of the edge. |
+#### `ExternalStatusCheckConnection`
+
+The connection type for [`ExternalStatusCheck`](#externalstatuscheck).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="externalstatuscheckconnectionedges"></a>`edges` | [`[ExternalStatusCheckEdge]`](#externalstatuscheckedge) | A list of edges. |
+| <a id="externalstatuscheckconnectionnodes"></a>`nodes` | [`[ExternalStatusCheck]`](#externalstatuscheck) | A list of nodes. |
+| <a id="externalstatuscheckconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `ExternalStatusCheckEdge`
+
+The edge type for [`ExternalStatusCheck`](#externalstatuscheck).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="externalstatuscheckedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="externalstatuscheckedgenode"></a>`node` | [`ExternalStatusCheck`](#externalstatuscheck) | The item at the end of the edge. |
+
#### `GroupConnection`
The connection type for [`Group`](#group).
@@ -8488,6 +8675,52 @@ The edge type for [`PipelineSecurityReportFinding`](#pipelinesecurityreportfindi
| <a id="pipelinesecurityreportfindingedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="pipelinesecurityreportfindingedgenode"></a>`node` | [`PipelineSecurityReportFinding`](#pipelinesecurityreportfinding) | The item at the end of the edge. |
+#### `ProductAnalyticsDashboardConnection`
+
+The connection type for [`ProductAnalyticsDashboard`](#productanalyticsdashboard).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="productanalyticsdashboardconnectionedges"></a>`edges` | [`[ProductAnalyticsDashboardEdge]`](#productanalyticsdashboardedge) | A list of edges. |
+| <a id="productanalyticsdashboardconnectionnodes"></a>`nodes` | [`[ProductAnalyticsDashboard]`](#productanalyticsdashboard) | A list of nodes. |
+| <a id="productanalyticsdashboardconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `ProductAnalyticsDashboardEdge`
+
+The edge type for [`ProductAnalyticsDashboard`](#productanalyticsdashboard).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="productanalyticsdashboardedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="productanalyticsdashboardedgenode"></a>`node` | [`ProductAnalyticsDashboard`](#productanalyticsdashboard) | The item at the end of the edge. |
+
+#### `ProductAnalyticsDashboardWidgetConnection`
+
+The connection type for [`ProductAnalyticsDashboardWidget`](#productanalyticsdashboardwidget).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="productanalyticsdashboardwidgetconnectionedges"></a>`edges` | [`[ProductAnalyticsDashboardWidgetEdge]`](#productanalyticsdashboardwidgetedge) | A list of edges. |
+| <a id="productanalyticsdashboardwidgetconnectionnodes"></a>`nodes` | [`[ProductAnalyticsDashboardWidget]`](#productanalyticsdashboardwidget) | A list of nodes. |
+| <a id="productanalyticsdashboardwidgetconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `ProductAnalyticsDashboardWidgetEdge`
+
+The edge type for [`ProductAnalyticsDashboardWidget`](#productanalyticsdashboardwidget).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="productanalyticsdashboardwidgetedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="productanalyticsdashboardwidgetedgenode"></a>`node` | [`ProductAnalyticsDashboardWidget`](#productanalyticsdashboardwidget) | The item at the end of the edge. |
+
#### `ProjectConnection`
The connection type for [`Project`](#project).
@@ -9299,6 +9532,29 @@ The edge type for [`TimeTrackingTimelogCategory`](#timetrackingtimelogcategory).
| <a id="timetrackingtimelogcategoryedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="timetrackingtimelogcategoryedgenode"></a>`node` | [`TimeTrackingTimelogCategory`](#timetrackingtimelogcategory) | The item at the end of the edge. |
+#### `TimelineEventTagTypeConnection`
+
+The connection type for [`TimelineEventTagType`](#timelineeventtagtype).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="timelineeventtagtypeconnectionedges"></a>`edges` | [`[TimelineEventTagTypeEdge]`](#timelineeventtagtypeedge) | A list of edges. |
+| <a id="timelineeventtagtypeconnectionnodes"></a>`nodes` | [`[TimelineEventTagType]`](#timelineeventtagtype) | A list of nodes. |
+| <a id="timelineeventtagtypeconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `TimelineEventTagTypeEdge`
+
+The edge type for [`TimelineEventTagType`](#timelineeventtagtype).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="timelineeventtagtypeedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="timelineeventtagtypeedgenode"></a>`node` | [`TimelineEventTagType`](#timelineeventtagtype) | The item at the end of the edge. |
+
#### `TimelineEventTypeConnection`
The connection type for [`TimelineEventType`](#timelineeventtype).
@@ -9437,6 +9693,29 @@ The edge type for [`TreeEntry`](#treeentry).
| <a id="treeentryedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
| <a id="treeentryedgenode"></a>`node` | [`TreeEntry`](#treeentry) | The item at the end of the edge. |
+#### `UnprotectAccessLevelConnection`
+
+The connection type for [`UnprotectAccessLevel`](#unprotectaccesslevel).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="unprotectaccesslevelconnectionedges"></a>`edges` | [`[UnprotectAccessLevelEdge]`](#unprotectaccessleveledge) | A list of edges. |
+| <a id="unprotectaccesslevelconnectionnodes"></a>`nodes` | [`[UnprotectAccessLevel]`](#unprotectaccesslevel) | A list of nodes. |
+| <a id="unprotectaccesslevelconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
+
+#### `UnprotectAccessLevelEdge`
+
+The edge type for [`UnprotectAccessLevel`](#unprotectaccesslevel).
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="unprotectaccessleveledgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
+| <a id="unprotectaccessleveledgenode"></a>`node` | [`UnprotectAccessLevel`](#unprotectaccesslevel) | The item at the end of the edge. |
+
#### `UploadRegistryConnection`
The connection type for [`UploadRegistry`](#uploadregistry).
@@ -9737,6 +10016,36 @@ Represents the access level of a relationship between a User and object that it
| <a id="accesslevelintegervalue"></a>`integerValue` | [`Int`](#int) | Integer representation of access level. |
| <a id="accesslevelstringvalue"></a>`stringValue` | [`AccessLevelEnum`](#accesslevelenum) | String representation of access level. |
+### `AccessLevelGroup`
+
+Representation of a GitLab group.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="accesslevelgroupavatarurl"></a>`avatarUrl` | [`String`](#string) | Avatar URL of the group. |
+| <a id="accesslevelgroupid"></a>`id` | [`ID!`](#id) | ID of the group. |
+| <a id="accesslevelgroupname"></a>`name` | [`String!`](#string) | Name of the group. |
+| <a id="accesslevelgroupparent"></a>`parent` | [`AccessLevelGroup`](#accesslevelgroup) | Parent group. |
+| <a id="accesslevelgroupweburl"></a>`webUrl` | [`String!`](#string) | Web URL of the group. |
+
+### `AccessLevelUser`
+
+Representation of a GitLab user.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="accessleveluseravatarurl"></a>`avatarUrl` | [`String`](#string) | URL of the user's avatar. |
+| <a id="accessleveluserid"></a>`id` | [`ID!`](#id) | ID of the user. |
+| <a id="accesslevelusername"></a>`name` | [`String!`](#string) | Human-readable name of the user. Returns `****` if the user is a project bot and the requester does not have permission to view the project. |
+| <a id="accessleveluserpublicemail"></a>`publicEmail` | [`String`](#string) | User's public email. |
+| <a id="accessleveluserusername"></a>`username` | [`String!`](#string) | Username of the user. Unique within this instance of GitLab. |
+| <a id="accessleveluserwebpath"></a>`webPath` | [`String!`](#string) | Web path of the user. |
+| <a id="accessleveluserweburl"></a>`webUrl` | [`String!`](#string) | Web URL of the user. |
+
### `AgentConfiguration`
Configuration details for an Agent.
@@ -10218,7 +10527,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="boardepicchildreniidstartswith"></a>`iidStartsWith` | [`String`](#string) | Filter epics by IID for autocomplete. |
| <a id="boardepicchildreniids"></a>`iids` | [`[ID!]`](#id) | List of IIDs of epics, e.g., `[1, 2]`. |
| <a id="boardepicchildrenin"></a>`in` | [`[IssuableSearchableField!]`](#issuablesearchablefield) | Specify the fields to perform the search in. Defaults to `[TITLE, DESCRIPTION]`. Requires the `search` argument.'. |
-| <a id="boardepicchildrenincludeancestorgroups"></a>`includeAncestorGroups` | [`Boolean`](#boolean) | Include epics from ancestor groups. |
+| <a id="boardepicchildrenincludeancestorgroups"></a>`includeAncestorGroups` | [`Boolean`](#boolean) | Include child epics from ancestor groups. |
| <a id="boardepicchildrenincludedescendantgroups"></a>`includeDescendantGroups` | [`Boolean`](#boolean) | Include epics from descendant groups. |
| <a id="boardepicchildrenlabelname"></a>`labelName` | [`[String!]`](#string) | Filter epics by labels. |
| <a id="boardepicchildrenmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Filter epics by milestone title, computed from epic's issues. |
@@ -10333,6 +10642,7 @@ Branch protection details for a branch rule.
| <a id="branchprotectioncodeownerapprovalrequired"></a>`codeOwnerApprovalRequired` | [`Boolean!`](#boolean) | Enforce code owner approvals before allowing a merge. |
| <a id="branchprotectionmergeaccesslevels"></a>`mergeAccessLevels` | [`MergeAccessLevelConnection`](#mergeaccesslevelconnection) | Details about who can merge when this branch is the source branch. (see [Connections](#connections)) |
| <a id="branchprotectionpushaccesslevels"></a>`pushAccessLevels` | [`PushAccessLevelConnection`](#pushaccesslevelconnection) | Details about who can push when this branch is the source branch. (see [Connections](#connections)) |
+| <a id="branchprotectionunprotectaccesslevels"></a>`unprotectAccessLevels` | [`UnprotectAccessLevelConnection`](#unprotectaccesslevelconnection) | Details about who can unprotect this branch. (see [Connections](#connections)) |
### `BranchRule`
@@ -10345,7 +10655,9 @@ List of branch rules for a project, grouped by branch name.
| <a id="branchruleapprovalrules"></a>`approvalRules` | [`ApprovalProjectRuleConnection`](#approvalprojectruleconnection) | Merge request approval rules configured for this branch rule. (see [Connections](#connections)) |
| <a id="branchrulebranchprotection"></a>`branchProtection` | [`BranchProtection!`](#branchprotection) | Branch protections configured for this branch rule. |
| <a id="branchrulecreatedat"></a>`createdAt` | [`Time!`](#time) | Timestamp of when the branch rule was created. |
+| <a id="branchruleexternalstatuschecks"></a>`externalStatusChecks` | [`ExternalStatusCheckConnection`](#externalstatuscheckconnection) | External status checks configured for this branch rule. (see [Connections](#connections)) |
| <a id="branchruleisdefault"></a>`isDefault` | [`Boolean!`](#boolean) | Check if this branch rule protects the project's default branch. |
+| <a id="branchrulematchingbranchescount"></a>`matchingBranchesCount` | [`Int!`](#int) | Number of existing branches that match this branch rule. |
| <a id="branchrulename"></a>`name` | [`String!`](#string) | Branch name, with wildcards, for the branch rules. |
| <a id="branchruleupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the branch rule was last updated. |
@@ -10622,7 +10934,8 @@ CI/CD variables given to a manual job.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="ciminutesprojectmonthlyusageminutes"></a>`minutes` | [`Int`](#int) | Number of CI/CD minutes used by the project in the month. |
-| <a id="ciminutesprojectmonthlyusagename"></a>`name` | [`String`](#string) | Name of the project. |
+| <a id="ciminutesprojectmonthlyusagename"></a>`name` **{warning-solid}** | [`String`](#string) | **Deprecated** in 15.6. Use `project.name`. |
+| <a id="ciminutesprojectmonthlyusageproject"></a>`project` | [`Project`](#project) | Project having the recorded usage. |
| <a id="ciminutesprojectmonthlyusagesharedrunnersduration"></a>`sharedRunnersDuration` | [`Int`](#int) | Total duration (in seconds) of shared runners use by the project for the month. |
### `CiProjectVariable`
@@ -10874,6 +11187,7 @@ Represents a code quality degradation on the pipeline.
| <a id="codequalitydegradationline"></a>`line` | [`Int!`](#int) | Line on which the code quality degradation occurred. |
| <a id="codequalitydegradationpath"></a>`path` | [`String!`](#string) | Relative path to the file containing the code quality degradation. |
| <a id="codequalitydegradationseverity"></a>`severity` | [`CodeQualityDegradationSeverity!`](#codequalitydegradationseverity) | Status of the degradation (BLOCKER, CRITICAL, MAJOR, MINOR, INFO, UNKNOWN). |
+| <a id="codequalitydegradationweburl"></a>`webUrl` | [`String`](#string) | URL to the file along with line number. |
### `Commit`
@@ -10894,6 +11208,7 @@ Represents a code quality degradation on the pipeline.
| <a id="commitmessage"></a>`message` | [`String`](#string) | Raw commit message. |
| <a id="commitsha"></a>`sha` | [`String!`](#string) | SHA1 ID of the commit. |
| <a id="commitshortid"></a>`shortId` | [`String!`](#string) | Short SHA1 ID of the commit. |
+| <a id="commitsignature"></a>`signature` | [`CommitSignature`](#commitsignature) | Signature of the commit. |
| <a id="commitsignaturehtml"></a>`signatureHtml` | [`String`](#string) | Rendered HTML of the commit signature. |
| <a id="committitle"></a>`title` | [`String`](#string) | Title of the commit message. |
| <a id="committitlehtml"></a>`titleHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `title`. |
@@ -10934,6 +11249,7 @@ Represents a ComplianceFramework associated with a Project.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="complianceframeworkcolor"></a>`color` | [`String!`](#string) | Hexadecimal representation of compliance framework's label color. |
+| <a id="complianceframeworkdefault"></a>`default` | [`Boolean`](#boolean) | Default compliance framework for the group. |
| <a id="complianceframeworkdescription"></a>`description` | [`String!`](#string) | Description of the compliance framework. |
| <a id="complianceframeworkid"></a>`id` | [`ID!`](#id) | Compliance framework ID. |
| <a id="complianceframeworkname"></a>`name` | [`String!`](#string) | Name of the compliance framework. |
@@ -11141,6 +11457,24 @@ A tag from a container repository.
| <a id="containerrepositorytagshortrevision"></a>`shortRevision` | [`String`](#string) | Short revision of the tag. |
| <a id="containerrepositorytagtotalsize"></a>`totalSize` | [`BigInt`](#bigint) | Size of the tag. |
+### `ContributionAnalyticsContribution`
+
+Represents the contributions of a user.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="contributionanalyticscontributionissuesclosed"></a>`issuesClosed` | [`Int`](#int) | Number of issues closed by the user. |
+| <a id="contributionanalyticscontributionissuescreated"></a>`issuesCreated` | [`Int`](#int) | Number of issues created by the user. |
+| <a id="contributionanalyticscontributionmergerequestsapproved"></a>`mergeRequestsApproved` | [`Int`](#int) | Number of merge requests approved by the user. |
+| <a id="contributionanalyticscontributionmergerequestsclosed"></a>`mergeRequestsClosed` | [`Int`](#int) | Number of merge requests closed by the user. |
+| <a id="contributionanalyticscontributionmergerequestscreated"></a>`mergeRequestsCreated` | [`Int`](#int) | Number of merge requests created by the user. |
+| <a id="contributionanalyticscontributionmergerequestsmerged"></a>`mergeRequestsMerged` | [`Int`](#int) | Number of merge requests merged by the user. |
+| <a id="contributionanalyticscontributionrepopushed"></a>`repoPushed` | [`Int`](#int) | Number of repository pushes the user made. |
+| <a id="contributionanalyticscontributiontotalevents"></a>`totalEvents` | [`Int`](#int) | Total number of events contributed by the user. |
+| <a id="contributionanalyticscontributionuser"></a>`user` | [`UserCore`](#usercore) | Contributor User object. |
+
### `CoverageFuzzingCorpus`
Corpus for a coverage fuzzing job.
@@ -11315,6 +11649,7 @@ Represents a DAST Site Profile.
| <a id="dastsiteprofiletargettype"></a>`targetType` | [`DastTargetTypeEnum`](#dasttargettypeenum) | Type of target to be scanned. |
| <a id="dastsiteprofiletargeturl"></a>`targetUrl` | [`String`](#string) | URL of the target to be scanned. |
| <a id="dastsiteprofileuserpermissions"></a>`userPermissions` | [`DastSiteProfilePermissions!`](#dastsiteprofilepermissions) | Permissions for the current user on the resource. |
+| <a id="dastsiteprofilevalidationstartedat"></a>`validationStartedAt` | [`Time`](#time) | Site profile validation start time. |
| <a id="dastsiteprofilevalidationstatus"></a>`validationStatus` | [`DastSiteProfileValidationStatusEnum`](#dastsiteprofilevalidationstatusenum) | Current validation status of the site profile. |
### `DastSiteProfileAuth`
@@ -11381,6 +11716,25 @@ Dependency proxy blob.
| <a id="dependencyproxyblobsize"></a>`size` | [`String!`](#string) | Size of the blob file. |
| <a id="dependencyproxyblobupdatedat"></a>`updatedAt` | [`Time!`](#time) | Date of most recent update. |
+### `DependencyProxyBlobRegistry`
+
+Represents the Geo replication and verification state of a dependency_proxy_blob.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="dependencyproxyblobregistrycreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp when the DependencyProxyBlobRegistry was created. |
+| <a id="dependencyproxyblobregistrydependencyproxyblobid"></a>`dependencyProxyBlobId` | [`ID!`](#id) | ID of the Dependency Proxy Blob. |
+| <a id="dependencyproxyblobregistryid"></a>`id` | [`ID!`](#id) | ID of the DependencyProxyBlobRegistry. |
+| <a id="dependencyproxyblobregistrylastsyncfailure"></a>`lastSyncFailure` | [`String`](#string) | Error message during sync of the DependencyProxyBlobRegistry. |
+| <a id="dependencyproxyblobregistrylastsyncedat"></a>`lastSyncedAt` | [`Time`](#time) | Timestamp of the most recent successful sync of the DependencyProxyBlobRegistry. |
+| <a id="dependencyproxyblobregistryretryat"></a>`retryAt` | [`Time`](#time) | Timestamp after which the DependencyProxyBlobRegistry is resynced. |
+| <a id="dependencyproxyblobregistryretrycount"></a>`retryCount` | [`Int`](#int) | Number of consecutive failed sync attempts of the DependencyProxyBlobRegistry. |
+| <a id="dependencyproxyblobregistrystate"></a>`state` | [`RegistryState`](#registrystate) | Sync state of the DependencyProxyBlobRegistry. |
+| <a id="dependencyproxyblobregistryverificationretryat"></a>`verificationRetryAt` | [`Time`](#time) | Timestamp after which the DependencyProxyBlobRegistry is reverified. |
+| <a id="dependencyproxyblobregistryverifiedat"></a>`verifiedAt` | [`Time`](#time) | Timestamp of the most recent successful verification of the DependencyProxyBlobRegistry. |
+
### `DependencyProxyImageTtlGroupPolicy`
Group-level Dependency Proxy TTL policy settings.
@@ -11442,6 +11796,33 @@ The deployment of an environment.
| <a id="deploymenttriggerer"></a>`triggerer` | [`UserCore`](#usercore) | User who executed the deployment. |
| <a id="deploymentupdatedat"></a>`updatedAt` | [`Time`](#time) | When the deployment record was updated. |
+### `DeploymentApproval`
+
+Approval of the deployment.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="deploymentapprovalcomment"></a>`comment` | [`String`](#string) | Additional comment. |
+| <a id="deploymentapprovalcreatedat"></a>`createdAt` | [`Time`](#time) | When the user approved/rejected first time. |
+| <a id="deploymentapprovalstatus"></a>`status` | [`DeploymentsApprovalStatus`](#deploymentsapprovalstatus) | Whether the deployment was approved/rejected. |
+| <a id="deploymentapprovalupdatedat"></a>`updatedAt` | [`Time`](#time) | When the user updated the approval. |
+| <a id="deploymentapprovaluser"></a>`user` | [`UserCore`](#usercore) | User who approved or rejected the deployment. |
+
+### `DeploymentApprovalSummary`
+
+Approval summary of the deployment.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="deploymentapprovalsummaryrules"></a>`rules` | [`[ProtectedEnvironmentApprovalRuleForSummary!]`](#protectedenvironmentapprovalruleforsummary) | Approval Rules for the deployment. |
+| <a id="deploymentapprovalsummarystatus"></a>`status` | [`DeploymentApprovalSummaryStatus`](#deploymentapprovalsummarystatus) | Status of the approvals. |
+| <a id="deploymentapprovalsummarytotalpendingapprovalcount"></a>`totalPendingApprovalCount` | [`Int`](#int) | Total pending approval count. |
+| <a id="deploymentapprovalsummarytotalrequiredapprovals"></a>`totalRequiredApprovals` | [`Int`](#int) | Total number of required approvals. |
+
### `DeploymentDetails`
The details of the deployment.
@@ -11450,6 +11831,7 @@ The details of the deployment.
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="deploymentdetailsapprovalsummary"></a>`approvalSummary` | [`DeploymentApprovalSummary`](#deploymentapprovalsummary) | Approval summary of the deployment. |
| <a id="deploymentdetailscommit"></a>`commit` | [`Commit`](#commit) | Commit details of the deployment. |
| <a id="deploymentdetailscreatedat"></a>`createdAt` | [`Time`](#time) | When the deployment record was created. |
| <a id="deploymentdetailsfinishedat"></a>`finishedAt` | [`Time`](#time) | When the deployment finished. |
@@ -12082,7 +12464,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="epicchildreniidstartswith"></a>`iidStartsWith` | [`String`](#string) | Filter epics by IID for autocomplete. |
| <a id="epicchildreniids"></a>`iids` | [`[ID!]`](#id) | List of IIDs of epics, e.g., `[1, 2]`. |
| <a id="epicchildrenin"></a>`in` | [`[IssuableSearchableField!]`](#issuablesearchablefield) | Specify the fields to perform the search in. Defaults to `[TITLE, DESCRIPTION]`. Requires the `search` argument.'. |
-| <a id="epicchildrenincludeancestorgroups"></a>`includeAncestorGroups` | [`Boolean`](#boolean) | Include epics from ancestor groups. |
+| <a id="epicchildrenincludeancestorgroups"></a>`includeAncestorGroups` | [`Boolean`](#boolean) | Include child epics from ancestor groups. |
| <a id="epicchildrenincludedescendantgroups"></a>`includeDescendantGroups` | [`Boolean`](#boolean) | Include epics from descendant groups. |
| <a id="epicchildrenlabelname"></a>`labelName` | [`[String!]`](#string) | Filter epics by labels. |
| <a id="epicchildrenmilestonetitle"></a>`milestoneTitle` | [`String`](#string) | Filter epics by milestone title, computed from epic's issues. |
@@ -12204,7 +12586,7 @@ Relationship between an epic and an issue.
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="epicissuealertmanagementalert"></a>`alertManagementAlert` | [`AlertManagementAlert`](#alertmanagementalert) | Alert associated to this issue. |
+| <a id="epicissuealertmanagementalert"></a>`alertManagementAlert` **{warning-solid}** | [`AlertManagementAlert`](#alertmanagementalert) | **Deprecated** in 15.6. Use `alert_management_alerts`. |
| <a id="epicissueassignees"></a>`assignees` | [`UserCoreConnection`](#usercoreconnection) | Assignees of the issue. (see [Connections](#connections)) |
| <a id="epicissueauthor"></a>`author` | [`UserCore!`](#usercore) | User that created the issue. |
| <a id="epicissueblocked"></a>`blocked` | [`Boolean!`](#boolean) | Indicates the issue is blocked. |
@@ -12272,6 +12654,27 @@ Relationship between an epic and an issue.
#### Fields with arguments
+##### `EpicIssue.alertManagementAlerts`
+
+Alert Management alerts associated to this issue.
+
+Returns [`AlertManagementAlertConnection`](#alertmanagementalertconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="epicissuealertmanagementalertsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of a user assigned to the issue. |
+| <a id="epicissuealertmanagementalertsdomain"></a>`domain` | [`AlertManagementDomainFilter!`](#alertmanagementdomainfilter) | Filter query for given domain. |
+| <a id="epicissuealertmanagementalertsiid"></a>`iid` | [`String`](#string) | IID of the alert. For example, "1". |
+| <a id="epicissuealertmanagementalertssearch"></a>`search` | [`String`](#string) | Search query for title, description, service, or monitoring_tool. |
+| <a id="epicissuealertmanagementalertssort"></a>`sort` | [`AlertManagementAlertSort`](#alertmanagementalertsort) | Sort alerts by this criteria. |
+| <a id="epicissuealertmanagementalertsstatuses"></a>`statuses` | [`[AlertManagementStatus!]`](#alertmanagementstatus) | Alerts with the specified statues. For example, `[TRIGGERED]`. |
+
##### `EpicIssue.currentUserTodos`
To-do items for the current user.
@@ -12429,6 +12832,7 @@ Represents an external resource to send audit events to.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="externalauditeventdestinationdestinationurl"></a>`destinationUrl` | [`String!`](#string) | External destination to send audit events to. |
+| <a id="externalauditeventdestinationeventtypefilters"></a>`eventTypeFilters` | [`[String!]!`](#string) | List of event type filters added for streaming. |
| <a id="externalauditeventdestinationgroup"></a>`group` | [`Group!`](#group) | Group the destination belongs to. |
| <a id="externalauditeventdestinationheaders"></a>`headers` | [`AuditEventStreamingHeaderConnection!`](#auditeventstreamingheaderconnection) | List of additional HTTP headers sent with each event. (see [Connections](#connections)) |
| <a id="externalauditeventdestinationid"></a>`id` | [`ID!`](#id) | ID of the destination. |
@@ -12450,6 +12854,18 @@ Represents an external issue.
| <a id="externalissueupdatedat"></a>`updatedAt` | [`Time`](#time) | Timestamp of when the issue was updated. |
| <a id="externalissueweburl"></a>`webUrl` | [`String`](#string) | URL to the issue in the external tracker. |
+### `ExternalStatusCheck`
+
+Describes an external status check.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="externalstatuscheckexternalurl"></a>`externalUrl` | [`String!`](#string) | External URL for the status check. |
+| <a id="externalstatuscheckid"></a>`id` | [`GlobalID!`](#globalid) | ID of the rule. |
+| <a id="externalstatuscheckname"></a>`name` | [`String!`](#string) | Name of the rule. |
+
### `FileUpload`
#### Fields
@@ -12524,6 +12940,28 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="geonodecontainerrepositoryregistriesreplicationstate"></a>`replicationState` | [`ReplicationStateEnum`](#replicationstateenum) | Filters registries by their replication state. |
| <a id="geonodecontainerrepositoryregistriesverificationstate"></a>`verificationState` | [`VerificationStateEnum`](#verificationstateenum) | Filters registries by their verification state. |
+##### `GeoNode.dependencyProxyBlobRegistries`
+
+Find Dependency Proxy Blob registries on this Geo node. Ignored if `geo_dependency_proxy_blob_replication` feature flag is disabled.
+
+WARNING:
+**Introduced** in 15.6.
+This feature is in Alpha. It can be changed or removed at any time.
+
+Returns [`DependencyProxyBlobRegistryConnection`](#dependencyproxyblobregistryconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="geonodedependencyproxyblobregistriesids"></a>`ids` | [`[ID!]`](#id) | Filters registries by their ID. |
+| <a id="geonodedependencyproxyblobregistriesreplicationstate"></a>`replicationState` | [`ReplicationStateEnum`](#replicationstateenum) | Filters registries by their replication state. |
+| <a id="geonodedependencyproxyblobregistriesverificationstate"></a>`verificationState` | [`VerificationStateEnum`](#verificationstateenum) | Filters registries by their verification state. |
+
##### `GeoNode.groupWikiRepositoryRegistries`
Find group wiki repository registries on this Geo node.
@@ -12704,6 +13142,22 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="geonodeuploadregistriesreplicationstate"></a>`replicationState` | [`ReplicationStateEnum`](#replicationstateenum) | Filters registries by their replication state. |
| <a id="geonodeuploadregistriesverificationstate"></a>`verificationState` | [`VerificationStateEnum`](#verificationstateenum) | Filters registries by their verification state. |
+### `GpgSignature`
+
+GPG signature for a signed commit.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="gpgsignaturecommitsha"></a>`commitSha` | [`String`](#string) | SHA of the associated commit. |
+| <a id="gpgsignaturegpgkeyprimarykeyid"></a>`gpgKeyPrimaryKeyid` | [`String`](#string) | ID of the GPG key. |
+| <a id="gpgsignaturegpgkeyuseremail"></a>`gpgKeyUserEmail` | [`String`](#string) | User email associated with the GPG key. |
+| <a id="gpgsignaturegpgkeyusername"></a>`gpgKeyUserName` | [`String`](#string) | User name associated with the GPG key. |
+| <a id="gpgsignatureproject"></a>`project` | [`Project`](#project) | Project of the associated commit. |
+| <a id="gpgsignatureuser"></a>`user` | [`UserCore`](#usercore) | User associated with the key. |
+| <a id="gpgsignatureverificationstatus"></a>`verificationStatus` | [`VerificationStatus`](#verificationstatus) | Indicates verification status of the associated key or certificate. |
+
### `GrafanaIntegration`
#### Fields
@@ -12918,6 +13372,23 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="groupcontainerrepositoriesname"></a>`name` | [`String`](#string) | Filter the container repositories by their name. |
| <a id="groupcontainerrepositoriessort"></a>`sort` | [`ContainerRepositorySort`](#containerrepositorysort) | Sort container repositories by this criteria. |
+##### `Group.contributions`
+
+Provides the aggregated contributions by users within the group and its subgroups.
+
+Returns [`ContributionAnalyticsContributionConnection`](#contributionanalyticscontributionconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="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. |
+
##### `Group.descendantGroups`
List of descendant groups of this group.
@@ -13095,6 +13566,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="groupissuesmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. |
| <a id="groupissuesmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by reaction emoji applied by the current user. Wildcard values "NONE" and "ANY" are supported. |
| <a id="groupissuesnot"></a>`not` | [`NegatedIssueFilterInput`](#negatedissuefilterinput) | Negated arguments. |
+| <a id="groupissuesor"></a>`or` | [`UnionedIssueFilterInput`](#unionedissuefilterinput) | List of arguments with inclusive OR. |
| <a id="groupissuessearch"></a>`search` | [`String`](#string) | Search query for title or description. |
| <a id="groupissuessort"></a>`sort` | [`IssueSort`](#issuesort) | Sort issues by this criteria. |
| <a id="groupissuesstate"></a>`state` | [`IssuableState`](#issuablestate) | Current state of this issue. |
@@ -13370,9 +13842,25 @@ 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`. |
+| <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="groupscanexecutionpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
+##### `Group.scanResultPolicies`
+
+Scan Result Policies of the project.
+
+Returns [`ScanResultPolicyConnection`](#scanresultpolicyconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="groupscanresultpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
+
##### `Group.timelogs`
Time logged on issues and merge requests in the group and its subgroups.
@@ -13474,7 +13962,7 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
##### `Group.workItemTypes`
-Work item types available to the group. Returns `null` if `work_items` feature flag is disabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice.
+Work item types available to the group.
Returns [`WorkItemTypeConnection`](#workitemtypeconnection).
@@ -13755,7 +14243,7 @@ Describes an issuable resource link for incident issues.
| Name | Type | Description |
| ---- | ---- | ----------- |
-| <a id="issuealertmanagementalert"></a>`alertManagementAlert` | [`AlertManagementAlert`](#alertmanagementalert) | Alert associated to this issue. |
+| <a id="issuealertmanagementalert"></a>`alertManagementAlert` **{warning-solid}** | [`AlertManagementAlert`](#alertmanagementalert) | **Deprecated** in 15.6. Use `alert_management_alerts`. |
| <a id="issueassignees"></a>`assignees` | [`UserCoreConnection`](#usercoreconnection) | Assignees of the issue. (see [Connections](#connections)) |
| <a id="issueauthor"></a>`author` | [`UserCore!`](#usercore) | User that created the issue. |
| <a id="issueblocked"></a>`blocked` | [`Boolean!`](#boolean) | Indicates the issue is blocked. |
@@ -13821,6 +14309,27 @@ Describes an issuable resource link for incident issues.
#### Fields with arguments
+##### `Issue.alertManagementAlerts`
+
+Alert Management alerts associated to this issue.
+
+Returns [`AlertManagementAlertConnection`](#alertmanagementalertconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="issuealertmanagementalertsassigneeusername"></a>`assigneeUsername` | [`String`](#string) | Username of a user assigned to the issue. |
+| <a id="issuealertmanagementalertsdomain"></a>`domain` | [`AlertManagementDomainFilter!`](#alertmanagementdomainfilter) | Filter query for given domain. |
+| <a id="issuealertmanagementalertsiid"></a>`iid` | [`String`](#string) | IID of the alert. For example, "1". |
+| <a id="issuealertmanagementalertssearch"></a>`search` | [`String`](#string) | Search query for title, description, service, or monitoring_tool. |
+| <a id="issuealertmanagementalertssort"></a>`sort` | [`AlertManagementAlertSort`](#alertmanagementalertsort) | Sort alerts by this criteria. |
+| <a id="issuealertmanagementalertsstatuses"></a>`statuses` | [`[AlertManagementStatus!]`](#alertmanagementstatus) | Alerts with the specified statues. For example, `[TRIGGERED]`. |
+
##### `Issue.currentUserTodos`
To-do items for the current user.
@@ -14128,7 +14637,7 @@ Maven metadata.
### `MergeAccessLevel`
-Represents the merge access level of a branch protection.
+Defines which user roles, users, or groups can merge into a protected branch.
#### Fields
@@ -14136,8 +14645,8 @@ Represents the merge access level of a branch protection.
| ---- | ---- | ----------- |
| <a id="mergeaccesslevelaccesslevel"></a>`accessLevel` | [`Int!`](#int) | GitLab::Access level. |
| <a id="mergeaccesslevelaccessleveldescription"></a>`accessLevelDescription` | [`String!`](#string) | Human readable representation for this access level. |
-| <a id="mergeaccesslevelgroup"></a>`group` | [`Group`](#group) | Group associated with this access level. |
-| <a id="mergeaccessleveluser"></a>`user` | [`UserCore`](#usercore) | User associated with this access level. |
+| <a id="mergeaccesslevelgroup"></a>`group` | [`AccessLevelGroup`](#accesslevelgroup) | Group associated with this access level. |
+| <a id="mergeaccessleveluser"></a>`user` | [`AccessLevelUser`](#accessleveluser) | User associated with this access level. |
### `MergeRequest`
@@ -14166,7 +14675,7 @@ Represents the merge access level of a branch protection.
| <a id="mergerequestdefaultsquashcommitmessage"></a>`defaultSquashCommitMessage` | [`String`](#string) | Default squash commit message of the merge request. |
| <a id="mergerequestdescription"></a>`description` | [`String`](#string) | Description of the merge request (Markdown rendered as HTML for caching). |
| <a id="mergerequestdescriptionhtml"></a>`descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. |
-| <a id="mergerequestdetailedmergestatus"></a>`detailedMergeStatus` **{warning-solid}** | [`DetailedMergeStatus`](#detailedmergestatus) | **Introduced** in 15.3. This feature is in Alpha. It can be changed or removed at any time. Detailed merge status of the merge request. |
+| <a id="mergerequestdetailedmergestatus"></a>`detailedMergeStatus` | [`DetailedMergeStatus`](#detailedmergestatus) | Detailed merge status of the merge request. |
| <a id="mergerequestdiffheadsha"></a>`diffHeadSha` | [`String`](#string) | Diff head SHA of the merge request. |
| <a id="mergerequestdiffrefs"></a>`diffRefs` | [`DiffRefs`](#diffrefs) | References of the base SHA, the head SHA, and the start SHA for this merge request. |
| <a id="mergerequestdiffstatssummary"></a>`diffStatsSummary` | [`DiffStatsSummary`](#diffstatssummary) | Summary of which files were changed in this merge request. |
@@ -15274,6 +15783,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="metadataenterprise"></a>`enterprise` | [`Boolean!`](#boolean) | Enterprise edition. |
| <a id="metadatakas"></a>`kas` | [`Kas!`](#kas) | Metadata about KAS. |
| <a id="metadatarevision"></a>`revision` | [`String!`](#string) | Revision. |
| <a id="metadataversion"></a>`version` | [`String!`](#string) | Version. |
@@ -15466,9 +15976,25 @@ 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`. |
+| <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="namespacescanexecutionpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
+##### `Namespace.scanResultPolicies`
+
+Scan Result Policies of the project.
+
+Returns [`ScanResultPolicyConnection`](#scanresultpolicyconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="namespacescanresultpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
+
### `NamespaceBan`
#### Fields
@@ -15612,6 +16138,7 @@ Represents a package with pipelines in the Package Registry.
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="package_links"></a>`_links` | [`PackageLinks!`](#packagelinks) | Map of links to perform actions on the package. |
| <a id="packagecandestroy"></a>`canDestroy` | [`Boolean!`](#boolean) | Whether the user can destroy the package. |
| <a id="packagecreatedat"></a>`createdAt` | [`Time!`](#time) | Date of creation. |
| <a id="packageid"></a>`id` | [`PackagesPackageID!`](#packagespackageid) | ID of the package. |
@@ -15633,6 +16160,7 @@ Represents a package in the Package Registry.
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="packagebase_links"></a>`_links` | [`PackageLinks!`](#packagelinks) | Map of links to perform actions on the package. |
| <a id="packagebasecandestroy"></a>`canDestroy` | [`Boolean!`](#boolean) | Whether the user can destroy the package. |
| <a id="packagebasecreatedat"></a>`createdAt` | [`Time!`](#time) | Date of creation. |
| <a id="packagebaseid"></a>`id` | [`PackagesPackageID!`](#packagespackageid) | ID of the package. |
@@ -15691,6 +16219,7 @@ Represents a package details in the Package Registry.
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="packagedetailstype_links"></a>`_links` | [`PackageLinks!`](#packagelinks) | Map of links to perform actions on the package. |
| <a id="packagedetailstypecandestroy"></a>`canDestroy` | [`Boolean!`](#boolean) | Whether the user can destroy the package. |
| <a id="packagedetailstypecomposerconfigrepositoryurl"></a>`composerConfigRepositoryUrl` | [`String`](#string) | Url of the Composer setup endpoint. |
| <a id="packagedetailstypecomposerurl"></a>`composerUrl` | [`String`](#string) | Url of the Composer endpoint. |
@@ -15809,6 +16338,16 @@ Represents the contents of a Helm Chart.yml file.
| <a id="packagehelmmetadatatypetype"></a>`type` | [`String`](#string) | Type of the chart. |
| <a id="packagehelmmetadatatypeversion"></a>`version` | [`String!`](#string) | Version of the chart. |
+### `PackageLinks`
+
+Represents links to perform actions on the package.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="packagelinkswebpath"></a>`webPath` | [`String`](#string) | Path to the package details page. |
+
### `PackageSettings`
Namespace-level Package Registry settings.
@@ -15978,6 +16517,18 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="pipelinejobssecurityreporttypes"></a>`securityReportTypes` | [`[SecurityReportTypeEnum!]`](#securityreporttypeenum) | Filter jobs by the type of security report they produce. |
| <a id="pipelinejobsstatuses"></a>`statuses` | [`[CiJobStatus!]`](#cijobstatus) | Filter jobs by status. |
+##### `Pipeline.securityReportFinding`
+
+Vulnerability finding reported on the pipeline.
+
+Returns [`PipelineSecurityReportFinding`](#pipelinesecurityreportfinding).
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="pipelinesecurityreportfindinguuid"></a>`uuid` | [`String!`](#string) | UUID of the security report finding. |
+
##### `Pipeline.securityReportFindings`
Vulnerability findings reported on the pipeline.
@@ -16133,6 +16684,7 @@ Represents vulnerability finding of a security report on the pipeline.
| <a id="pipelinesecurityreportfindingconfidence"></a>`confidence` **{warning-solid}** | [`String`](#string) | **Deprecated** in 15.4. This field will be removed from the Finding domain model. |
| <a id="pipelinesecurityreportfindingdescription"></a>`description` | [`String`](#string) | Description of the vulnerability finding. |
| <a id="pipelinesecurityreportfindingdescriptionhtml"></a>`descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. |
+| <a id="pipelinesecurityreportfindingdetails"></a>`details` | [`[VulnerabilityDetail!]!`](#vulnerabilitydetail) | Details of the security finding. |
| <a id="pipelinesecurityreportfindingevidence"></a>`evidence` | [`VulnerabilityEvidence`](#vulnerabilityevidence) | Evidence for the vulnerability. |
| <a id="pipelinesecurityreportfindingfalsepositive"></a>`falsePositive` | [`Boolean`](#boolean) | Indicates whether the vulnerability is a false positive. |
| <a id="pipelinesecurityreportfindingidentifiers"></a>`identifiers` | [`[VulnerabilityIdentifier!]!`](#vulnerabilityidentifier) | Identifiers of the vulnerability finding. |
@@ -16159,6 +16711,29 @@ Represents vulnerability finding of a security report on the pipeline.
| <a id="previewbillableuserchangenewbillableusercount"></a>`newBillableUserCount` | [`Int`](#int) | Total number of billable users after change. |
| <a id="previewbillableuserchangeseatsinsubscription"></a>`seatsInSubscription` | [`Int`](#int) | Number of seats in subscription. |
+### `ProductAnalyticsDashboard`
+
+Represents a product analytics dashboard.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="productanalyticsdashboarddescription"></a>`description` | [`String`](#string) | Description of the dashboard. |
+| <a id="productanalyticsdashboardtitle"></a>`title` | [`String!`](#string) | Title of the dashboard. |
+| <a id="productanalyticsdashboardwidgets"></a>`widgets` | [`ProductAnalyticsDashboardWidgetConnection!`](#productanalyticsdashboardwidgetconnection) | Widgets shown on the dashboard. (see [Connections](#connections)) |
+
+### `ProductAnalyticsDashboardWidget`
+
+Represents a product analytics dashboard widget.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="productanalyticsdashboardwidgetgridattributes"></a>`gridAttributes` | [`JSON`](#json) | Description of the position and size of the widget. |
+| <a id="productanalyticsdashboardwidgettitle"></a>`title` | [`String!`](#string) | Title of the widget. |
+
### `Project`
#### Fields
@@ -16196,10 +16771,12 @@ Represents vulnerability finding of a security report on the pipeline.
| <a id="projecthttpurltorepo"></a>`httpUrlToRepo` | [`String`](#string) | URL to connect to the project via HTTPS. |
| <a id="projectid"></a>`id` | [`ID!`](#id) | ID of the project. |
| <a id="projectimportstatus"></a>`importStatus` | [`String`](#string) | Status of import background job of the project. |
+| <a id="projectincidentmanagementtimelineeventtags"></a>`incidentManagementTimelineEventTags` | [`[TimelineEventTagType!]`](#timelineeventtagtype) | Timeline event tags for the project. |
| <a id="projectissuesenabled"></a>`issuesEnabled` | [`Boolean`](#boolean) | Indicates if Issues are enabled for the current user. |
| <a id="projectjiraimportstatus"></a>`jiraImportStatus` | [`String`](#string) | Status of Jira import background job of the project. |
| <a id="projectjiraimports"></a>`jiraImports` | [`JiraImportConnection`](#jiraimportconnection) | Jira imports into the project. (see [Connections](#connections)) |
| <a id="projectjobsenabled"></a>`jobsEnabled` | [`Boolean`](#boolean) | Indicates if CI/CD pipeline jobs are enabled for the current user. |
+| <a id="projectlanguages"></a>`languages` | [`[RepositoryLanguage!]`](#repositorylanguage) | Programming languages used in the project. |
| <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. |
@@ -16226,7 +16803,6 @@ Represents vulnerability finding of a security report on the pipeline.
| <a id="projectrequestaccessenabled"></a>`requestAccessEnabled` | [`Boolean`](#boolean) | Indicates if users can request member access to the project. |
| <a id="projectrequirementstatescount"></a>`requirementStatesCount` | [`RequirementStatesCount`](#requirementstatescount) | Number of requirements for the project by their state. |
| <a id="projectsastciconfiguration"></a>`sastCiConfiguration` | [`SastCiConfiguration`](#sastciconfiguration) | SAST CI configuration for the project. |
-| <a id="projectscanresultpolicies"></a>`scanResultPolicies` | [`ScanResultPolicyConnection`](#scanresultpolicyconnection) | Scan Result Policies of the project. (see [Connections](#connections)) |
| <a id="projectsecuritydashboardpath"></a>`securityDashboardPath` | [`String`](#string) | Path to project's security dashboard. |
| <a id="projectsecurityscanners"></a>`securityScanners` | [`SecurityScanners`](#securityscanners) | Information about security analyzers used in the project. |
| <a id="projectsentryerrors"></a>`sentryErrors` | [`SentryErrorCollection`](#sentryerrorcollection) | Paginated collection of Sentry errors on the project. |
@@ -16692,6 +17268,7 @@ Returns [`Issue`](#issue).
| <a id="projectissuemilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. |
| <a id="projectissuemyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by reaction emoji applied by the current user. Wildcard values "NONE" and "ANY" are supported. |
| <a id="projectissuenot"></a>`not` | [`NegatedIssueFilterInput`](#negatedissuefilterinput) | Negated arguments. |
+| <a id="projectissueor"></a>`or` | [`UnionedIssueFilterInput`](#unionedissuefilterinput) | List of arguments with inclusive OR. |
| <a id="projectissuereleasetag"></a>`releaseTag` | [`[String!]`](#string) | Release tag associated with the issue's milestone. |
| <a id="projectissuereleasetagwildcardid"></a>`releaseTagWildcardId` | [`ReleaseTagWildcardId`](#releasetagwildcardid) | Filter issues by release tag ID wildcard. |
| <a id="projectissuesearch"></a>`search` | [`String`](#string) | Search query for title or description. |
@@ -16723,20 +17300,27 @@ Returns [`IssueStatusCountsType`](#issuestatuscountstype).
| <a id="projectissuestatuscountscreatedbefore"></a>`createdBefore` | [`Time`](#time) | Issues created before this date. |
| <a id="projectissuestatuscountscrmcontactid"></a>`crmContactId` | [`String`](#string) | ID of a contact assigned to the issues. |
| <a id="projectissuestatuscountscrmorganizationid"></a>`crmOrganizationId` | [`String`](#string) | ID of an organization assigned to the issues. |
+| <a id="projectissuestatuscountsepicid"></a>`epicId` | [`String`](#string) | ID of an epic associated with the issues, "none" and "any" values are supported. |
+| <a id="projectissuestatuscountshealthstatusfilter"></a>`healthStatusFilter` | [`HealthStatusFilter`](#healthstatusfilter) | Health status of the issue, "none" and "any" values are supported. |
| <a id="projectissuestatuscountsiid"></a>`iid` | [`String`](#string) | IID of the issue. For example, "1". |
| <a id="projectissuestatuscountsiids"></a>`iids` | [`[String!]`](#string) | List of IIDs of issues. For example, `["1", "2"]`. |
| <a id="projectissuestatuscountsin"></a>`in` | [`[IssuableSearchableField!]`](#issuablesearchablefield) | Specify the fields to perform the search in. Defaults to `[TITLE, DESCRIPTION]`. Requires the `search` argument.'. |
+| <a id="projectissuestatuscountsincludesubepics"></a>`includeSubepics` | [`Boolean`](#boolean) | Whether to include subepics when filtering issues by epicId. |
+| <a id="projectissuestatuscountsiterationid"></a>`iterationId` | [`[ID]`](#id) | List of iteration Global IDs applied to the issue. |
+| <a id="projectissuestatuscountsiterationwildcardid"></a>`iterationWildcardId` | [`IterationWildcardId`](#iterationwildcardid) | Filter by iteration ID wildcard. |
| <a id="projectissuestatuscountslabelname"></a>`labelName` | [`[String]`](#string) | Labels applied to this issue. |
| <a id="projectissuestatuscountsmilestonetitle"></a>`milestoneTitle` | [`[String]`](#string) | Milestone applied to this issue. |
| <a id="projectissuestatuscountsmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. |
| <a id="projectissuestatuscountsmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by reaction emoji applied by the current user. Wildcard values "NONE" and "ANY" are supported. |
| <a id="projectissuestatuscountsnot"></a>`not` | [`NegatedIssueFilterInput`](#negatedissuefilterinput) | Negated arguments. |
+| <a id="projectissuestatuscountsor"></a>`or` | [`UnionedIssueFilterInput`](#unionedissuefilterinput) | List of arguments with inclusive OR. |
| <a id="projectissuestatuscountsreleasetag"></a>`releaseTag` | [`[String!]`](#string) | Release tag associated with the issue's milestone. |
| <a id="projectissuestatuscountsreleasetagwildcardid"></a>`releaseTagWildcardId` | [`ReleaseTagWildcardId`](#releasetagwildcardid) | Filter issues by release tag ID wildcard. |
| <a id="projectissuestatuscountssearch"></a>`search` | [`String`](#string) | Search query for title or description. |
| <a id="projectissuestatuscountstypes"></a>`types` | [`[IssueType!]`](#issuetype) | Filter issues by the given issue types. |
| <a id="projectissuestatuscountsupdatedafter"></a>`updatedAfter` | [`Time`](#time) | Issues updated after this date. |
| <a id="projectissuestatuscountsupdatedbefore"></a>`updatedBefore` | [`Time`](#time) | Issues updated before this date. |
+| <a id="projectissuestatuscountsweight"></a>`weight` | [`String`](#string) | Weight applied to the issue, "none" and "any" values are supported. |
##### `Project.issues`
@@ -16777,6 +17361,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="projectissuesmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter issues by milestone ID wildcard. |
| <a id="projectissuesmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by reaction emoji applied by the current user. Wildcard values "NONE" and "ANY" are supported. |
| <a id="projectissuesnot"></a>`not` | [`NegatedIssueFilterInput`](#negatedissuefilterinput) | Negated arguments. |
+| <a id="projectissuesor"></a>`or` | [`UnionedIssueFilterInput`](#unionedissuefilterinput) | List of arguments with inclusive OR. |
| <a id="projectissuesreleasetag"></a>`releaseTag` | [`[String!]`](#string) | Release tag associated with the issue's milestone. |
| <a id="projectissuesreleasetagwildcardid"></a>`releaseTagWildcardId` | [`ReleaseTagWildcardId`](#releasetagwildcardid) | Filter issues by release tag ID wildcard. |
| <a id="projectissuessearch"></a>`search` | [`String`](#string) | Search query for title or description. |
@@ -17068,6 +17653,26 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="projectpipelinesupdatedbefore"></a>`updatedBefore` | [`Time`](#time) | Pipelines updated before this date. |
| <a id="projectpipelinesusername"></a>`username` | [`String`](#string) | Filter pipelines by the user that triggered the pipeline. |
+##### `Project.productAnalyticsDashboards`
+
+Product Analytics dashboards of the project.
+
+WARNING:
+**Introduced** in 15.6.
+This feature is in Alpha. It can be changed or removed at any time.
+
+Returns [`ProductAnalyticsDashboardConnection`](#productanalyticsdashboardconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="projectproductanalyticsdashboardsslug"></a>`slug` | [`String`](#string) | Find by dashboard slug. |
+
##### `Project.projectMembers`
Members of the project.
@@ -17168,9 +17773,25 @@ 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`. |
+| <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="projectscanexecutionpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
+##### `Project.scanResultPolicies`
+
+Scan Result Policies of the project.
+
+Returns [`ScanResultPolicyConnection`](#scanresultpolicyconnection).
+
+This field returns a [connection](#connections). It accepts the
+four standard [pagination arguments](#connection-pagination-arguments):
+`before: String`, `after: String`, `first: Int`, `last: Int`.
+
+###### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="projectscanresultpoliciesrelationship"></a>`relationship` | [`SecurityPolicyRelationType`](#securitypolicyrelationtype) | Filter policies by the given policy relationship. |
+
##### `Project.securityTrainingProviders`
List of security training providers for the project.
@@ -17343,7 +17964,7 @@ Returns [`VulnerabilitySeveritiesCount`](#vulnerabilityseveritiescount).
##### `Project.workItemTypes`
-Work item types available to the project. Returns `null` if `work_items` feature flag is disabled. This flag is disabled by default, because the feature is experimental and is subject to change without notice.
+Work item types available to the project.
Returns [`WorkItemTypeConnection`](#workitemtypeconnection).
@@ -17381,6 +18002,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <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="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. |
### `ProjectCiCdSetting`
@@ -17558,6 +18180,23 @@ Which group, user or role is allowed to approve deployments to the environment.
| <a id="protectedenvironmentapprovalrulerequiredapprovals"></a>`requiredApprovals` | [`Int`](#int) | Number of required approvals. |
| <a id="protectedenvironmentapprovalruleuser"></a>`user` | [`UserCore`](#usercore) | User details. Present if it's user specific access control. |
+### `ProtectedEnvironmentApprovalRuleForSummary`
+
+Which group, user or role is allowed to approve deployments to the environment.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="protectedenvironmentapprovalruleforsummaryaccesslevel"></a>`accessLevel` | [`AccessLevel`](#accesslevel) | Role details. Present if it's role specific access control. |
+| <a id="protectedenvironmentapprovalruleforsummaryapprovals"></a>`approvals` | [`[DeploymentApproval!]`](#deploymentapproval) | Current approvals of the deployment. |
+| <a id="protectedenvironmentapprovalruleforsummaryapprovedcount"></a>`approvedCount` | [`Int`](#int) | Approved count. |
+| <a id="protectedenvironmentapprovalruleforsummarygroup"></a>`group` | [`Group`](#group) | Group details. Present if it's group specific access control. |
+| <a id="protectedenvironmentapprovalruleforsummarypendingapprovalcount"></a>`pendingApprovalCount` | [`Int`](#int) | Pending approval count. |
+| <a id="protectedenvironmentapprovalruleforsummaryrequiredapprovals"></a>`requiredApprovals` | [`Int`](#int) | Number of required approvals. |
+| <a id="protectedenvironmentapprovalruleforsummarystatus"></a>`status` | [`DeploymentApprovalSummaryStatus`](#deploymentapprovalsummarystatus) | Status of the approval summary. |
+| <a id="protectedenvironmentapprovalruleforsummaryuser"></a>`user` | [`UserCore`](#usercore) | User details. Present if it's user specific access control. |
+
### `ProtectedEnvironmentDeployAccessLevel`
Which group, user or role is allowed to execute deployments to the environment.
@@ -17572,7 +18211,7 @@ Which group, user or role is allowed to execute deployments to the environment.
### `PushAccessLevel`
-Represents the push access level of a branch protection.
+Defines which user roles, users, or groups can push to a protected branch.
#### Fields
@@ -17580,8 +18219,8 @@ Represents the push access level of a branch protection.
| ---- | ---- | ----------- |
| <a id="pushaccesslevelaccesslevel"></a>`accessLevel` | [`Int!`](#int) | GitLab::Access level. |
| <a id="pushaccesslevelaccessleveldescription"></a>`accessLevelDescription` | [`String!`](#string) | Human readable representation for this access level. |
-| <a id="pushaccesslevelgroup"></a>`group` | [`Group`](#group) | Group associated with this access level. |
-| <a id="pushaccessleveluser"></a>`user` | [`UserCore`](#usercore) | User associated with this access level. |
+| <a id="pushaccesslevelgroup"></a>`group` | [`AccessLevelGroup`](#accesslevelgroup) | Group associated with this access level. |
+| <a id="pushaccessleveluser"></a>`user` | [`AccessLevelUser`](#accessleveluser) | User associated with this access level. |
### `PushRules`
@@ -17838,6 +18477,16 @@ Returns [`Tree`](#tree).
| <a id="repositoryblobstoredexternally"></a>`storedExternally` | [`Boolean`](#boolean) | Whether the blob's content is stored externally (for instance, in LFS). |
| <a id="repositoryblobwebpath"></a>`webPath` | [`String`](#string) | Web path of the blob. |
+### `RepositoryLanguage`
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="repositorylanguagecolor"></a>`color` | [`Color`](#color) | Color to visualize the repository language. |
+| <a id="repositorylanguagename"></a>`name` | [`String!`](#string) | Name of the repository language. |
+| <a id="repositorylanguageshare"></a>`share` | [`Float`](#float) | Percentage of the repository's languages. |
+
### `Requirement`
Represents a requirement.
@@ -17937,6 +18586,7 @@ Counts of requirements by their state.
| Name | Type | Description |
| ---- | ---- | ----------- |
+| <a id="runnerpermissionsassignrunner"></a>`assignRunner` | [`Boolean!`](#boolean) | Indicates the user can perform `assign_runner` on this resource. |
| <a id="runnerpermissionsdeleterunner"></a>`deleteRunner` | [`Boolean!`](#boolean) | Indicates the user can perform `delete_runner` on this resource. |
| <a id="runnerpermissionsreadrunner"></a>`readRunner` | [`Boolean!`](#boolean) | Indicates the user can perform `read_runner` on this resource. |
| <a id="runnerpermissionsupdaterunner"></a>`updateRunner` | [`Boolean!`](#boolean) | Indicates the user can perform `update_runner` on this resource. |
@@ -18064,6 +18714,7 @@ Represents the scan result policy.
| <a id="scanresultpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
| <a id="scanresultpolicygroupapprovers"></a>`groupApprovers` | [`[Group!]`](#group) | Approvers of the group type. |
| <a id="scanresultpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
+| <a id="scanresultpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
| <a id="scanresultpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
| <a id="scanresultpolicyuserapprovers"></a>`userApprovers` | [`[UserCore!]`](#usercore) | Approvers of the user type. |
| <a id="scanresultpolicyyaml"></a>`yaml` | [`String!`](#string) | YAML definition of the policy. |
@@ -18695,6 +19346,17 @@ Explains why we could not generate a timebox report.
| <a id="timeboxreporterrorcode"></a>`code` | [`TimeboxReportErrorReason`](#timeboxreporterrorreason) | Machine readable code, categorizing the error. |
| <a id="timeboxreporterrormessage"></a>`message` | [`String`](#string) | Human readable message explaining what happened. |
+### `TimelineEventTagType`
+
+Describes a tag on an incident management timeline event.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="timelineeventtagtypeid"></a>`id` | [`IncidentManagementTimelineEventTagID!`](#incidentmanagementtimelineeventtagid) | ID of the timeline event tag. |
+| <a id="timelineeventtagtypename"></a>`name` | [`String!`](#string) | Name of the timeline event tag. |
+
### `TimelineEventType`
Describes an incident management timeline event.
@@ -18713,6 +19375,7 @@ Describes an incident management timeline event.
| <a id="timelineeventtypenotehtml"></a>`noteHtml` | [`String`](#string) | HTML note of the timeline event. |
| <a id="timelineeventtypeoccurredat"></a>`occurredAt` | [`Time!`](#time) | Timestamp when the event occurred. |
| <a id="timelineeventtypepromotedfromnote"></a>`promotedFromNote` | [`Note`](#note) | Note from which the timeline event was created. |
+| <a id="timelineeventtypetimelineeventtags"></a>`timelineEventTags` | [`TimelineEventTagTypeConnection`](#timelineeventtagtypeconnection) | Tags for the incident timeline event. (see [Connections](#connections)) |
| <a id="timelineeventtypeupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp when the event updated. |
| <a id="timelineeventtypeupdatedbyuser"></a>`updatedByUser` | [`UserCore`](#usercore) | User that updated the timeline event. |
@@ -18801,6 +19464,19 @@ Represents a directory.
| <a id="treeentrywebpath"></a>`webPath` | [`String`](#string) | Web path for the tree entry (directory). |
| <a id="treeentryweburl"></a>`webUrl` | [`String`](#string) | Web URL for the tree entry (directory). |
+### `UnprotectAccessLevel`
+
+Defines which user roles, users, or groups can unprotect a protected branch.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="unprotectaccesslevelaccesslevel"></a>`accessLevel` | [`Int!`](#int) | GitLab::Access level. |
+| <a id="unprotectaccesslevelaccessleveldescription"></a>`accessLevelDescription` | [`String!`](#string) | Human readable representation for this access level. |
+| <a id="unprotectaccesslevelgroup"></a>`group` | [`AccessLevelGroup`](#accesslevelgroup) | Group associated with this access level. |
+| <a id="unprotectaccessleveluser"></a>`user` | [`AccessLevelUser`](#accessleveluser) | User associated with this access level. |
+
### `UploadRegistry`
Represents the Geo replication and verification state of an upload.
@@ -19171,7 +19847,8 @@ Represents a vulnerability.
| <a id="vulnerabilitytitle"></a>`title` | [`String`](#string) | Title of the vulnerability. |
| <a id="vulnerabilityusernotescount"></a>`userNotesCount` | [`Int!`](#int) | Number of user notes attached to the vulnerability. |
| <a id="vulnerabilityuserpermissions"></a>`userPermissions` | [`VulnerabilityPermissions!`](#vulnerabilitypermissions) | Permissions for the current user on the resource. |
-| <a id="vulnerabilityvulnerabilitypath"></a>`vulnerabilityPath` | [`String`](#string) | URL to the vulnerability's details page. |
+| <a id="vulnerabilityvulnerabilitypath"></a>`vulnerabilityPath` | [`String`](#string) | Path to the vulnerability's details page. |
+| <a id="vulnerabilityweburl"></a>`webUrl` | [`String`](#string) | URL to the vulnerability's details page. |
#### Fields with arguments
@@ -19812,6 +20489,17 @@ Represents the labels widget.
| <a id="workitemwidgetlabelslabels"></a>`labels` | [`LabelConnection`](#labelconnection) | Labels assigned to the work item. (see [Connections](#connections)) |
| <a id="workitemwidgetlabelstype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
+### `WorkItemWidgetMilestone`
+
+Represents a milestone widget.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="workitemwidgetmilestonemilestone"></a>`milestone` | [`Milestone`](#milestone) | Milestone of the work item. |
+| <a id="workitemwidgetmilestonetype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
+
### `WorkItemWidgetStartAndDueDate`
Represents a start and due date widget.
@@ -19846,6 +20534,53 @@ Represents a weight widget.
| <a id="workitemwidgetweighttype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. |
| <a id="workitemwidgetweightweight"></a>`weight` | [`Int`](#int) | Weight of the work item. |
+### `X509Certificate`
+
+Represents an X.509 certificate.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="x509certificatecertificatestatus"></a>`certificateStatus` | [`String!`](#string) | Indicates if the certificate is good or revoked. |
+| <a id="x509certificatecreatedat"></a>`createdAt` | [`Time!`](#time) | Timestamp of when the certificate was saved. |
+| <a id="x509certificateemail"></a>`email` | [`String!`](#string) | Email associated with the cerificate. |
+| <a id="x509certificateid"></a>`id` | [`ID!`](#id) | ID of the certificate. |
+| <a id="x509certificateserialnumber"></a>`serialNumber` | [`String!`](#string) | Serial number of the certificate. |
+| <a id="x509certificatesubject"></a>`subject` | [`String!`](#string) | Subject of the certificate. |
+| <a id="x509certificatesubjectkeyidentifier"></a>`subjectKeyIdentifier` | [`String!`](#string) | Subject key identifier of the certificate. |
+| <a id="x509certificateupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the certificate was last updated. |
+| <a id="x509certificatex509issuer"></a>`x509Issuer` | [`X509Issuer!`](#x509issuer) | Issuer of the certificate. |
+
+### `X509Issuer`
+
+Issuer of an X.509 certificate.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="x509issuercreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp of when the issuer was created. |
+| <a id="x509issuercrlurl"></a>`crlUrl` | [`String`](#string) | Certificate revokation list of the issuer. |
+| <a id="x509issuerid"></a>`id` | [`ID`](#id) | ID of the issuer. |
+| <a id="x509issuersubject"></a>`subject` | [`String`](#string) | Subject of the issuer. |
+| <a id="x509issuersubjectkeyidentifier"></a>`subjectKeyIdentifier` | [`String`](#string) | Subject key identifier of the issuer. |
+| <a id="x509issuerupdatedat"></a>`updatedAt` | [`Time`](#time) | Timestamp of when the issuer was last updated. |
+
+### `X509Signature`
+
+X.509 signature for a signed commit.
+
+#### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="x509signaturecommitsha"></a>`commitSha` | [`String`](#string) | SHA of the associated commit. |
+| <a id="x509signatureproject"></a>`project` | [`Project`](#project) | Project of the associated commit. |
+| <a id="x509signatureuser"></a>`user` | [`UserCore`](#usercore) | User associated with the key. |
+| <a id="x509signatureverificationstatus"></a>`verificationStatus` | [`VerificationStatus`](#verificationstatus) | Indicates verification status of the associated key or certificate. |
+| <a id="x509signaturex509certificate"></a>`x509Certificate` | [`X509Certificate`](#x509certificate) | Certificate used for the signature. |
+
## Enumeration types
Also called _Enums_, enumeration types are a special kind of scalar that
@@ -20302,6 +21037,7 @@ Status of a container repository.
| Value | Description |
| ----- | ----------- |
| <a id="containerrepositorystatusdelete_failed"></a>`DELETE_FAILED` | Delete Failed status. |
+| <a id="containerrepositorystatusdelete_ongoing"></a>`DELETE_ONGOING` | Delete Ongoing status. |
| <a id="containerrepositorystatusdelete_scheduled"></a>`DELETE_SCHEDULED` | Delete Scheduled status. |
### `ContainerRepositoryTagSort`
@@ -20431,6 +21167,16 @@ Weight of the data visualization palette.
| <a id="dependencyproxymanifeststatuspending_destruction"></a>`PENDING_DESTRUCTION` | Dependency proxy manifest has a status of pending_destruction. |
| <a id="dependencyproxymanifeststatusprocessing"></a>`PROCESSING` | Dependency proxy manifest has a status of processing. |
+### `DeploymentApprovalSummaryStatus`
+
+Status of the deployment approval summary.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="deploymentapprovalsummarystatusapproved"></a>`APPROVED` | Summarized deployment approval status that is approved. |
+| <a id="deploymentapprovalsummarystatuspending_approval"></a>`PENDING_APPROVAL` | Summarized deployment approval status that is pending approval. |
+| <a id="deploymentapprovalsummarystatusrejected"></a>`REJECTED` | Summarized deployment approval status that is rejected. |
+
### `DeploymentStatus`
All deployment statuses.
@@ -20457,6 +21203,15 @@ All environment deployment tiers.
| <a id="deploymenttierstaging"></a>`STAGING` | Staging. |
| <a id="deploymenttiertesting"></a>`TESTING` | Testing. |
+### `DeploymentsApprovalStatus`
+
+Status of the deployment approval.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="deploymentsapprovalstatusapproved"></a>`APPROVED` | A deployment approval that is approved. |
+| <a id="deploymentsapprovalstatusrejected"></a>`REJECTED` | A deployment approval that is rejected. |
+
### `DesignCollectionCopyState`
Copy state of a DesignCollection.
@@ -20746,6 +21501,8 @@ Values for sorting issues.
| <a id="issuesortdue_date_desc"></a>`DUE_DATE_DESC` | Due date by descending order. |
| <a id="issuesortescalation_status_asc"></a>`ESCALATION_STATUS_ASC` | Status from triggered to resolved. |
| <a id="issuesortescalation_status_desc"></a>`ESCALATION_STATUS_DESC` | Status from resolved to triggered. |
+| <a id="issuesorthealth_status_asc"></a>`HEALTH_STATUS_ASC` | Issues with healthy issues first. |
+| <a id="issuesorthealth_status_desc"></a>`HEALTH_STATUS_DESC` | Issues with unhealthy issues first. |
| <a id="issuesortlabel_priority_asc"></a>`LABEL_PRIORITY_ASC` | Label priority by ascending order. |
| <a id="issuesortlabel_priority_desc"></a>`LABEL_PRIORITY_DESC` | Label priority by descending order. |
| <a id="issuesortmilestone_due_asc"></a>`MILESTONE_DUE_ASC` | Milestone due date by ascending order. |
@@ -20800,8 +21557,9 @@ Issue type.
| ----- | ----------- |
| <a id="issuetypeincident"></a>`INCIDENT` | Incident issue type. |
| <a id="issuetypeissue"></a>`ISSUE` | Issue issue type. |
+| <a id="issuetypeobjective"></a>`OBJECTIVE` **{warning-solid}** | **Introduced** in 15.6. This feature is in Alpha. It can be changed or removed at any time. Objective issue type. Available only when feature flag `okrs_mvc` is enabled. |
| <a id="issuetyperequirement"></a>`REQUIREMENT` | Requirement issue type. |
-| <a id="issuetypetask"></a>`TASK` **{warning-solid}** | **Introduced** in 15.2. This feature is in Alpha. It can be changed or removed at any time. Task issue type. Available only when feature flag `work_items` is enabled. |
+| <a id="issuetypetask"></a>`TASK` **{warning-solid}** | **Introduced** in 15.2. This feature is in Alpha. It can be changed or removed at any time. Task issue type. |
| <a id="issuetypetest_case"></a>`TEST_CASE` | Test Case issue type. |
### `IterationSearchableField`
@@ -21612,6 +22370,7 @@ Name of the feature that the callout is for.
| Value | Description |
| ----- | ----------- |
| <a id="usercalloutfeaturenameenumactive_user_count_threshold"></a>`ACTIVE_USER_COUNT_THRESHOLD` | Callout feature name for active_user_count_threshold. |
+| <a id="usercalloutfeaturenameenumartifacts_management_page_feedback_banner"></a>`ARTIFACTS_MANAGEMENT_PAGE_FEEDBACK_BANNER` | Callout feature name for artifacts_management_page_feedback_banner. |
| <a id="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. |
@@ -21684,6 +22443,20 @@ Possible states of a user.
| <a id="verificationstateenumstarted"></a>`STARTED` | Verification process is in progress. |
| <a id="verificationstateenumsucceeded"></a>`SUCCEEDED` | Verification process finished successfully. |
+### `VerificationStatus`
+
+Verification status of a GPG or X.509 signature for a commit.
+
+| Value | Description |
+| ----- | ----------- |
+| <a id="verificationstatusmultiple_signatures"></a>`MULTIPLE_SIGNATURES` | multiple_signatures verification status. |
+| <a id="verificationstatusother_user"></a>`OTHER_USER` | other_user verification status. |
+| <a id="verificationstatussame_user_different_email"></a>`SAME_USER_DIFFERENT_EMAIL` | same_user_different_email verification status. |
+| <a id="verificationstatusunknown_key"></a>`UNKNOWN_KEY` | unknown_key verification status. |
+| <a id="verificationstatusunverified"></a>`UNVERIFIED` | unverified verification status. |
+| <a id="verificationstatusunverified_key"></a>`UNVERIFIED_KEY` | unverified_key verification status. |
+| <a id="verificationstatusverified"></a>`VERIFIED` | verified verification status. |
+
### `VisibilityLevelsEnum`
| Value | Description |
@@ -21869,6 +22642,7 @@ Type of a work item widget.
| <a id="workitemwidgettypehierarchy"></a>`HIERARCHY` | Hierarchy widget. |
| <a id="workitemwidgettypeiteration"></a>`ITERATION` | Iteration widget. |
| <a id="workitemwidgettypelabels"></a>`LABELS` | Labels widget. |
+| <a id="workitemwidgettypemilestone"></a>`MILESTONE` | Milestone widget. |
| <a id="workitemwidgettypestart_and_due_date"></a>`START_AND_DUE_DATE` | Start And Due Date widget. |
| <a id="workitemwidgettypestatus"></a>`STATUS` | Status widget. |
| <a id="workitemwidgettypeweight"></a>`WEIGHT` | Weight widget. |
@@ -22199,6 +22973,12 @@ A `IncidentManagementTimelineEventID` is a global ID. It is encoded as a string.
An example `IncidentManagementTimelineEventID` is: `"gid://gitlab/IncidentManagement::TimelineEvent/1"`.
+### `IncidentManagementTimelineEventTagID`
+
+A `IncidentManagementTimelineEventTagID` is a global ID. It is encoded as a string.
+
+An example `IncidentManagementTimelineEventTagID` is: `"gid://gitlab/IncidentManagement::TimelineEventTag/1"`.
+
### `Int`
Represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.
@@ -22651,6 +23431,23 @@ Implementations:
| <a id="civariablevalue"></a>`value` | [`String`](#string) | Value of the variable. |
| <a id="civariablevariabletype"></a>`variableType` | [`CiVariableType`](#civariabletype) | Type of the variable. |
+#### `CommitSignature`
+
+Represents signing information for a commit.
+
+Implementations:
+
+- [`GpgSignature`](#gpgsignature)
+- [`X509Signature`](#x509signature)
+
+##### Fields
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="commitsignaturecommitsha"></a>`commitSha` | [`String`](#string) | SHA of the associated commit. |
+| <a id="commitsignatureproject"></a>`project` | [`Project`](#project) | Project of the associated commit. |
+| <a id="commitsignatureverificationstatus"></a>`verificationStatus` | [`VerificationStatus`](#verificationstatus) | Indicates verification status of the associated key or certificate. |
+
#### `CurrentUserTodos`
Implementations:
@@ -23139,6 +23936,7 @@ Implementations:
- [`WorkItemWidgetHierarchy`](#workitemwidgethierarchy)
- [`WorkItemWidgetIteration`](#workitemwidgetiteration)
- [`WorkItemWidgetLabels`](#workitemwidgetlabels)
+- [`WorkItemWidgetMilestone`](#workitemwidgetmilestone)
- [`WorkItemWidgetStartAndDueDate`](#workitemwidgetstartandduedate)
- [`WorkItemWidgetStatus`](#workitemwidgetstatus)
- [`WorkItemWidgetWeight`](#workitemwidgetweight)
@@ -23193,6 +23991,7 @@ Field that are available while modifying the custom mapping attributes for an HT
| <a id="boardissueinputmilestonewildcardid"></a>`milestoneWildcardId` | [`MilestoneWildcardId`](#milestonewildcardid) | Filter by milestone ID wildcard. |
| <a id="boardissueinputmyreactionemoji"></a>`myReactionEmoji` | [`String`](#string) | Filter by reaction emoji applied by the current user. Wildcard values "NONE" and "ANY" are supported. |
| <a id="boardissueinputnot"></a>`not` | [`NegatedBoardIssueInput`](#negatedboardissueinput) | List of negated arguments. |
+| <a id="boardissueinputor"></a>`or` | [`UnionedIssueFilterInput`](#unionedissuefilterinput) | List of arguments with inclusive OR. |
| <a id="boardissueinputreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
| <a id="boardissueinputsearch"></a>`search` | [`String`](#string) | Search query for issue title or description. |
| <a id="boardissueinputtypes"></a>`types` | [`[IssueType!]`](#issuetype) | Filter by the given issue types. |
@@ -23231,6 +24030,7 @@ Attributes for defining a CI/CD variable.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="complianceframeworkinputcolor"></a>`color` | [`String`](#string) | New color representation of the compliance framework in hex format. e.g. #FCA121. |
+| <a id="complianceframeworkinputdefault"></a>`default` | [`Boolean`](#boolean) | Set this compliance framework as the default framework for the group. |
| <a id="complianceframeworkinputdescription"></a>`description` | [`String`](#string) | New description for the compliance framework. |
| <a id="complianceframeworkinputname"></a>`name` | [`String`](#string) | New name for the compliance framework. |
| <a id="complianceframeworkinputpipelineconfigurationfullpath"></a>`pipelineConfigurationFullPath` | [`String`](#string) | Full path of the compliance pipeline configuration stored in a project repository, such as `.gitlab/.compliance-gitlab-ci.yml@compliance/hipaa` **(ULTIMATE)**. |
@@ -23569,6 +24369,14 @@ Represents an action to perform over a snippet file.
| <a id="snippetblobactioninputtypefilepath"></a>`filePath` | [`String!`](#string) | Path of the snippet file. |
| <a id="snippetblobactioninputtypepreviouspath"></a>`previousPath` | [`String`](#string) | Previous path of the snippet file. |
+### `StatusFilterInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="statusfilterinputstatus"></a>`status` | [`RequirementStatusFilter!`](#requirementstatusfilter) | Status of the work item. |
+
### `StatusInput`
#### Arguments
@@ -23588,6 +24396,15 @@ A time-frame defined as a closed inclusive range of two dates.
| <a id="timeframeend"></a>`end` | [`Date!`](#date) | End of the range. |
| <a id="timeframestart"></a>`start` | [`Date!`](#date) | Start of the range. |
+### `UnionedIssueFilterInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="unionedissuefilterinputassigneeusernames"></a>`assigneeUsernames` | [`[String!]`](#string) | Filters issues that are assigned to at least one of the given users. |
+| <a id="unionedissuefilterinputauthorusernames"></a>`authorUsernames` | [`[String!]`](#string) | Filters issues that are authored by one of the given users. |
+
### `UpdateDiffImagePositionInput`
#### Arguments
@@ -23664,6 +24481,7 @@ A time-frame defined as a closed inclusive range of two dates.
| <a id="workitemupdatedtaskinputhierarchywidget"></a>`hierarchyWidget` | [`WorkItemWidgetHierarchyUpdateInput`](#workitemwidgethierarchyupdateinput) | Input for hierarchy widget. |
| <a id="workitemupdatedtaskinputid"></a>`id` | [`WorkItemID!`](#workitemid) | Global ID of the work item. |
| <a id="workitemupdatedtaskinputlabelswidget"></a>`labelsWidget` | [`WorkItemWidgetLabelsUpdateInput`](#workitemwidgetlabelsupdateinput) | Input for labels widget. |
+| <a id="workitemupdatedtaskinputmilestonewidget"></a>`milestoneWidget` | [`WorkItemWidgetMilestoneInput`](#workitemwidgetmilestoneinput) | Input for milestone widget. |
| <a id="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. |
@@ -23718,6 +24536,14 @@ A time-frame defined as a closed inclusive range of two dates.
| <a id="workitemwidgetlabelsupdateinputaddlabelids"></a>`addLabelIds` | [`[LabelID!]`](#labelid) | Global IDs of labels to be added to the work item. |
| <a id="workitemwidgetlabelsupdateinputremovelabelids"></a>`removeLabelIds` | [`[LabelID!]`](#labelid) | Global IDs of labels to be removed from the work item. |
+### `WorkItemWidgetMilestoneInput`
+
+#### Arguments
+
+| Name | Type | Description |
+| ---- | ---- | ----------- |
+| <a id="workitemwidgetmilestoneinputmilestoneid"></a>`milestoneId` | [`MilestoneID`](#milestoneid) | Milestone to assign to the work item. |
+
### `WorkItemWidgetStartAndDueDateUpdateInput`
#### Arguments
diff --git a/doc/api/group_iterations.md b/doc/api/group_iterations.md
index 92333de701c..988986d8965 100644
--- a/doc/api/group_iterations.md
+++ b/doc/api/group_iterations.md
@@ -20,8 +20,8 @@ Returns a list of group iterations.
GET /groups/:id/iterations
GET /groups/:id/iterations?state=opened
GET /groups/:id/iterations?state=closed
-GET /groups/:id/iterations?title=1.0
GET /groups/:id/iterations?search=version
+GET /groups/:id/iterations?include_ancestors=false
```
| Attribute | Type | Required | Description |
diff --git a/doc/api/group_level_variables.md b/doc/api/group_level_variables.md
index cdda15d9610..6ca4cc1d080 100644
--- a/doc/api/group_level_variables.md
+++ b/doc/api/group_level_variables.md
@@ -32,6 +32,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
"value": "TEST_1",
"protected": false,
"masked": false,
+ "raw": false,
"environment_scope": "*"
},
{
@@ -40,6 +41,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
"value": "TEST_2",
"protected": false,
"masked": false,
+ "raw": false,
"environment_scope": "*"
}
]
@@ -69,6 +71,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
"value": "TEST_1",
"protected": false,
"masked": false,
+ "raw": false,
"environment_scope": "*"
}
```
@@ -89,6 +92,7 @@ POST /groups/:id/variables
| `variable_type` | string | no | The type of a variable. Available types are: `env_var` (default) and `file` |
| `protected` | boolean | no | Whether the variable is protected |
| `masked` | boolean | no | Whether the variable is masked |
+| `raw` | boolean | no | Whether the variable is expandable |
| `environment_scope` **(PREMIUM)** | string | no | The [environment scope](../ci/variables/index.md#limit-the-environment-scope-of-a-cicd-variable) of a variable |
```shell
@@ -103,6 +107,7 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
"variable_type": "env_var",
"protected": false,
"masked": false,
+ "raw": false,
"environment_scope": "*"
}
```
@@ -123,6 +128,7 @@ PUT /groups/:id/variables/:key
| `variable_type` | string | no | The type of a variable. Available types are: `env_var` (default) and `file` |
| `protected` | boolean | no | Whether the variable is protected |
| `masked` | boolean | no | Whether the variable is masked |
+| `raw` | boolean | no | Whether the variable is expandable |
| `environment_scope` **(PREMIUM)** | string | no | The [environment scope](../ci/variables/index.md#limit-the-environment-scope-of-a-cicd-variable) of a variable |
```shell
@@ -137,6 +143,7 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
"variable_type": "env_var",
"protected": true,
"masked": true,
+ "raw": true,
"environment_scope": "*"
}
```
diff --git a/doc/api/group_protected_environments.md b/doc/api/group_protected_environments.md
index 4cf87cb4305..ecd433bf321 100644
--- a/doc/api/group_protected_environments.md
+++ b/doc/api/group_protected_environments.md
@@ -95,7 +95,7 @@ Example response:
}
```
-## Protect an environment
+## Protect a single environment
Protects a single environment.
@@ -136,7 +136,7 @@ Example response:
}
```
-## Update an environment
+## Update a protected environment
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/351854) in GitLab 15.4.
@@ -304,7 +304,7 @@ Example response:
}
```
-## Unprotect environment
+## Unprotect a single environment
Unprotects the given protected environment.
diff --git a/doc/api/groups.md b/doc/api/groups.md
index c1effc78a4d..cba54648705 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -1413,7 +1413,7 @@ Parameters:
## Group members
-Please consult the [Group Members](members.md) documentation.
+See the [Group Members](members.md) documentation.
## LDAP Group Links
@@ -1605,7 +1605,7 @@ If successful, returns [`201`](index.md#status-codes) and the following response
Example request:
```shell
-curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/1/saml_group_links"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" --header "Content-Type: application/json" --data '{ "saml_group_name": "<your_saml_group_name`>", "access_level": <chosen_access_level> }' --url "https://gitlab.example.com/api/v4/groups/1/saml_group_links"
```
Example response:
diff --git a/doc/api/index.md b/doc/api/index.md
index 7e14137b0fe..cc54731de81 100644
--- a/doc/api/index.md
+++ b/doc/api/index.md
@@ -593,7 +593,7 @@ GET /api/v4/projects/1/repository/tags/my%2Ftag
## Request Payload
API Requests can use parameters sent as [query strings](https://en.wikipedia.org/wiki/Query_string)
-or as a [payload body](https://tools.ietf.org/html/draft-ietf-httpbis-p3-payload-14#section-3.2).
+or as a [payload body](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-p3-payload-14#section-3.2).
GET requests usually send a query string, while PUT or POST requests usually
send the payload body:
diff --git a/doc/api/instance_level_ci_variables.md b/doc/api/instance_level_ci_variables.md
index 776b1000651..e71cf777b2c 100644
--- a/doc/api/instance_level_ci_variables.md
+++ b/doc/api/instance_level_ci_variables.md
@@ -28,14 +28,16 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
"variable_type": "env_var",
"value": "TEST_1",
"protected": false,
- "masked": false
+ "masked": false,
+ "raw": false
},
{
"key": "TEST_VARIABLE_2",
"variable_type": "env_var",
"value": "TEST_2",
"protected": false,
- "masked": false
+ "masked": false,
+ "raw": false
}
]
```
@@ -62,7 +64,8 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
"variable_type": "env_var",
"value": "TEST_1",
"protected": false,
- "masked": false
+ "masked": false,
+ "raw": false
}
```
@@ -83,6 +86,7 @@ POST /admin/ci/variables
| `variable_type` | string | no | The type of a variable. Available types are: `env_var` (default) and `file`. |
| `protected` | boolean | no | Whether the variable is protected. |
| `masked` | boolean | no | Whether the variable is masked. |
+| `raw` | boolean | no | Whether the variable is expandable. |
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
@@ -95,7 +99,8 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
"value": "new value",
"variable_type": "env_var",
"protected": false,
- "masked": false
+ "masked": false,
+ "raw": false
}
```
@@ -114,6 +119,7 @@ PUT /admin/ci/variables/:key
| `variable_type` | string | no | The type of a variable. Available types are: `env_var` (default) and `file`. |
| `protected` | boolean | no | Whether the variable is protected. |
| `masked` | boolean | no | Whether the variable is masked. |
+| `raw` | boolean | no | Whether the variable is expandable. |
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
@@ -126,7 +132,8 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
"value": "updated value",
"variable_type": "env_var",
"protected": true,
- "masked": true
+ "masked": true,
+ "raw": true
}
```
diff --git a/doc/api/integrations.md b/doc/api/integrations.md
index 176ed931d38..d64c67e1402 100644
--- a/doc/api/integrations.md
+++ b/doc/api/integrations.md
@@ -262,7 +262,7 @@ GET /projects/:id/integrations/buildkite
## Campfire
Send notifications about push events to Campfire chat rooms.
-[New users can no longer sign up for Campfire](https://basecamp.com/retired/campfire).
+[New users can no longer sign up for Campfire](https://basecamp.com/handbook/05-product-histories#campfire).
### Create/Edit Campfire integration
diff --git a/doc/api/issues.md b/doc/api/issues.md
index a0eb518f23e..dd5a1354a3a 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -1506,8 +1506,8 @@ Please use `iid` of the `epic` attribute instead.
Clone the issue to given project. If the user has insufficient permissions,
an error message with status code `400` is returned.
-Copies as much data as possible as long as the target project contains equivalent labels, milestones,
-and so on.
+Copies as much data as possible as long as the target project contains equivalent
+criteria such as labels or milestones.
```plaintext
POST /projects/:id/issues/:issue_iid/clone
diff --git a/doc/api/iterations.md b/doc/api/iterations.md
index 5704bcd3418..4997a917a5a 100644
--- a/doc/api/iterations.md
+++ b/doc/api/iterations.md
@@ -22,8 +22,8 @@ Returns a list of project iterations.
GET /projects/:id/iterations
GET /projects/:id/iterations?state=opened
GET /projects/:id/iterations?state=closed
-GET /projects/:id/iterations?title=1.0
GET /projects/:id/iterations?search=version
+GET /projects/:id/iterations?include_ancestors=false
```
| Attribute | Type | Required | Description |
diff --git a/doc/api/job_artifacts.md b/doc/api/job_artifacts.md
index 2a40f7c15ef..3e5f49377cb 100644
--- a/doc/api/job_artifacts.md
+++ b/doc/api/job_artifacts.md
@@ -25,7 +25,7 @@ GET /projects/:id/jobs/:job_id/artifacts
Example request using the `PRIVATE-TOKEN` header:
```shell
-curl --output artifacts.zip --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/42/artifacts"
+curl --location --output artifacts.zip --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/42/artifacts"
```
To use this in a [`script` definition](../ci/yaml/index.md#script) inside
@@ -90,7 +90,7 @@ Parameters
Example request using the `PRIVATE-TOKEN` header:
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/artifacts/main/download?job=test"
+curl --location --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/jobs/artifacts/main/download?job=test"
```
To use this in a [`script` definition](../ci/yaml/index.md#script) inside
diff --git a/doc/api/lint.md b/doc/api/lint.md
index c1d95f65a86..e50832a9528 100644
--- a/doc/api/lint.md
+++ b/doc/api/lint.md
@@ -210,7 +210,7 @@ Example responses:
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, local includes, and so on.
+specific data available, including variables and local includes.
```plaintext
GET /projects/:id/ci/lint
diff --git a/doc/api/members.md b/doc/api/members.md
index 52bc3f6f468..66729abcad8 100644
--- a/doc/api/members.md
+++ b/doc/api/members.md
@@ -313,9 +313,6 @@ Gets a list of group members that count as billable. The list includes members i
This API endpoint works on top-level groups only. It does not work on subgroups.
-NOTE:
-Unlike other API endpoints, billable members is updated once per day at 12:00 UTC.
-
This function takes [pagination](index.md#pagination) parameters `page` and `per_page` to restrict the list of users.
[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/262875) in GitLab 13.7, the `search` and
diff --git a/doc/api/merge_request_approvals.md b/doc/api/merge_request_approvals.md
index e65263030b1..0476035784a 100644
--- a/doc/api/merge_request_approvals.md
+++ b/doc/api/merge_request_approvals.md
@@ -6,6 +6,8 @@ info: "To determine the technical writer assigned to the Stage/Group associated
# Merge request approvals API **(PREMIUM)**
+> Changing approval configuration with the `/approvals` endpoint was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/11132) in GitLab 12.3.
+
Configuration for
[approvals on all merge requests](../user/project/merge_requests/approvals/index.md)
in the project. Must be authenticated for all endpoints.
@@ -57,7 +59,7 @@ Supported attributes:
| Attribute | Type | Required | Description |
| ------------------------------------------------ | ------- | -------- | -- |
| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of a project](index.md#namespaced-path-encoding). |
-| `approvals_before_merge` | integer | **{dotted-circle}** No | How many approvals are required before a merge request can be merged. Deprecated in GitLab 12.0 in favor of Approval Rules API. |
+| `approvals_before_merge` (deprecated) | integer | **{dotted-circle}** No | How many approvals are required before a merge request can be merged. [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/11132) in GitLab 12.3. |
| `disable_overriding_approvers_per_merge_request` | boolean | **{dotted-circle}** No | Allow or prevent overriding approvers per merge request. |
| `merge_requests_author_approval` | boolean | **{dotted-circle}** No | Allow or prevent authors from self approving merge requests; `true` means authors can self approve. |
| `merge_requests_disable_committers_approval` | boolean | **{dotted-circle}** No | Allow or prevent committers from self approving merge requests. |
@@ -582,9 +584,16 @@ Supported attributes:
}
```
-### Change approval configuration
+### Change approval configuration (deprecated)
-> Moved to GitLab Premium in 13.9.
+> - Moved to GitLab Premium in GitLab 13.9.
+> - Endpoint `/approvals` [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/11132) in GitLab 12.3.
+
+WARNING:
+The `/approvals` endpoint was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/11132) in GitLab 12.3
+and is planned for removal in 16.0. To change the approvals required for a merge request,
+use the `/approval_rules` endpoint described in [Create merge request level rule](#create-merge-request-level-rule).
+on this page. This change is a breaking change.
If you are allowed to, you can change `approvals_required` using the following
endpoint:
@@ -598,7 +607,7 @@ Supported attributes:
| Attribute | Type | Required | Description |
|----------------------|-------------------|----------|-------------|
| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of a project](index.md#namespaced-path-encoding). |
-| `approvals_required` | integer | **{check-circle}** Yes | Approvals required before MR can be merged. Deprecated in GitLab 12.0 in favor of Approval Rules API. |
+| `approvals_required` | integer | **{check-circle}** Yes | Approvals required before MR can be merged. |
| `merge_request_iid` | integer | **{check-circle}** Yes | The IID of the merge request. |
```json
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 4667e48f233..4b4d36ec23e 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -160,6 +160,7 @@ Supported attributes:
},
"merge_when_pipeline_succeeds": true,
"merge_status": "can_be_merged",
+ "detailed_merge_status": "not_open",
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
"squash_commit_sha": null,
@@ -360,6 +361,7 @@ Supported attributes:
},
"merge_when_pipeline_succeeds": true,
"merge_status": "can_be_merged",
+ "detailed_merge_status": "not_open",
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
"squash_commit_sha": null,
@@ -547,6 +549,7 @@ Supported attributes:
},
"merge_when_pipeline_succeeds": true,
"merge_status": "can_be_merged",
+ "detailed_merge_status": "not_open",
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
"squash_commit_sha": null,
@@ -616,6 +619,67 @@ Supported attributes:
| `include_rebase_in_progress` | boolean | **{dotted-circle}** No | If `true`, response includes whether a rebase operation is in progress. |
| `render_html` | boolean | **{dotted-circle}** No | If `true`, response includes rendered HTML for title and description. |
+### Response
+
+| Attribute | Type | Description |
+|----------------------------------|------|-------------|
+| `approvals_before_merge` | integer | **(PREMIUM)** Number of approvals required before this merge request can merge. |
+| `assignee` | object | First assignee of the merge request. |
+| `assignees` | array | Assignees of the merge request. |
+| `author` | object | User who created this merge request. |
+| `blocking_discussions_resolved` | boolean | Indicates if all discussions are resolved only if all are required before merge request can be merged. |
+| `changes_count` | string | Number of changes made on the merge request. |
+| `closed_at` | datetime | Timestamp of when the merge request was closed. |
+| `closed_by` | object | User who closed this merge request. |
+| `created_at` | datetime | Timestamp of when the merge request was created. |
+| `description` | string | Description of the merge request. Contains Markdown rendered as HTML for caching. |
+| `detailed_merge_status` | string | Detailed merge status of the merge request. |
+| `diff_refs` | object | References of the base SHA, the head SHA, and the start SHA for this merge request. Corresponds to the latest diff version of the merge request. |
+| `discussion_locked` | boolean | Indicates if comments on the merge request are locked to members only. |
+| `downvotes` | integer | Number of downvotes for the merge request. |
+| `draft` | boolean | Indicates if the merge request is a draft. |
+| `first_contribution` | boolean | Indicates if the merge request is the first contribution of the author. |
+| `first_deployed_to_production_at` | datetime | Timestamp of when the first deployment finished. |
+| `force_remove_source_branch` | boolean | Indicates if the project settings will lead to source branch deletion after merge. |
+| `has_conflicts` | boolean | Indicates if merge request has conflicts and cannot be merged. Dependent on the `merge_status` property. Returns `false` unless `merge_status` is `cannot_be_merged`. |
+| `head_pipeline` | object | Pipeline running on the branch HEAD of the merge request. Contains more complete information than `pipeline` and should be used instead of it. |
+| `id` | integer | ID of the merge request. |
+| `iid` | integer | Internal ID of the merge request. |
+| `labels` | array | Labels of the merge request. |
+| `latest_build_finished_at` | datetime | Timestamp of when the latest build for the merge request finished. |
+| `latest_build_started_at` | datetime | Timestamp of when the latest build for the merge request started. |
+| `merge_commit_sha` | string | SHA of the merge request commit. Returns `null` until merged. |
+| `merge_error` | string | Error message due to a merge error. |
+| `merge_user` | object | The user who merged this merge request, the user who set it to merge when pipeline succeeds, or `null`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/349031) in GitLab 14.7. |
+| `merge_status` | string | Status of the merge request. Can be `unchecked`, `checking`, `can_be_merged`, `cannot_be_merged`, or `cannot_be_merged_recheck`. Affects the `has_conflicts` property. [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/3169#note_1162532204) in GitLab 15.6. Use `detailed_merge_status` instead. |
+| `merge_when_pipeline_succeeds` | boolean | Indicates if the merge has been set to be merged when its pipeline succeeds. |
+| `merged_at` | datetime | Timestamp of when the merge request was merged. |
+| `merged_by` | object | User who merged this merge request or set it to merge when pipeline succeeds. [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/350534) in GitLab 14.7, and scheduled for removal in [API version 5](https://gitlab.com/groups/gitlab-org/-/epics/8115). Use `merge_user` instead. |
+| `milestone` | object | Milestone of the merge request. |
+| `pipeline` | object | Pipeline running on the branch HEAD of the merge request. Consider using `head_pipeline` instead, as it contains more information. |
+| `project_id` | integer | ID of the merge request project. |
+| `reference` | string | Internal reference of the merge request. Returned in shortened format by default. [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20354) in GitLab 12.7, and scheduled for removal in [API version 5](https://gitlab.com/groups/gitlab-org/-/epics/8115). Use `references` instead. |
+| `references` | object | Internal references of the merge request. Includes `short`, `relative`, and `full` references. `references.relative` is relative to the merge request's group or project. When fetched from the merge request's project, `relative` and `short` formats are identical. When requested across groups or projects, `relative` and `full` formats are identical.|
+| `reviewers` | array | Reviewers of the merge request. |
+| `sha` | string | Diff head SHA of the merge request. |
+| `should_remove_source_branch` | boolean | Indicates if the source branch of the merge request will be deleted after merge. |
+| `source_branch` | string | Source branch of the merge request. |
+| `source_project_id` | integer | ID of the merge request source project. |
+| `squash` | boolean | Indicates if squash on merge is enabled. |
+| `squash_commit_sha` | string | SHA of the squash commit. Empty until merged. |
+| `state` | string | State of the merge request. Can be `opened`, `closed`, `merged` or `locked`. |
+| `subscribed` | boolean | Indicates if the currently logged in user is subscribed to this merge request. |
+| `target_branch` | string | Target branch of the merge request. |
+| `target_project_id` | integer | ID of the merge request target project. |
+| `task_completion_status` | object | Completion status of tasks. |
+| `title` | string | Title of the merge request. |
+| `updated_at` | datetime | Timestamp of when the merge request was updated. |
+| `upvotes` | integer | Number of upvotes for the merge request. |
+| `user` | object | Permissions of the user requested for the merge request. |
+| `user_notes_count` | integer | User notes count of the merge request. |
+| `web_url` | string | Web URL of the merge request. |
+| `work_in_progress` | boolean | Deprecated: Use `draft` instead. Indicates if the merge request is a draft. |
+
```json
{
"id": 155016530,
@@ -626,7 +690,7 @@ Supported attributes:
"state": "opened",
"created_at": "2022-05-13T07:26:38.402Z",
"updated_at": "2022-05-14T03:38:31.354Z",
- "merged_by": null, // Deprecated and will be removed in API v5, use `merge_user` instead
+ "merged_by": null, // Deprecated and will be removed in API v5. Use `merge_user` instead.
"merge_user": null,
"merged_at": null,
"closed_by": null,
@@ -655,13 +719,14 @@ Supported attributes:
"milestone": null,
"merge_when_pipeline_succeeds": false,
"merge_status": "can_be_merged",
+ "detailed_merge_status": "can_be_merged",
"sha": "e82eb4a098e32c796079ca3915e07487fc4db24c",
"merge_commit_sha": null,
"squash_commit_sha": null,
"discussion_locked": null,
"should_remove_source_branch": null,
"force_remove_source_branch": true,
- "reference": "!133",
+ "reference": "!133", // Deprecated. Use `references` instead.
"references": {
"short": "!133",
"relative": "!133",
@@ -687,7 +752,7 @@ Supported attributes:
"latest_build_started_at": "2022-05-13T09:46:50.032Z",
"latest_build_finished_at": null,
"first_deployed_to_production_at": null,
- "pipeline": { // Old parameter, use `head_pipeline` instead.
+ "pipeline": { // Use `head_pipeline` instead.
"id": 538317940,
"iid": 1877,
"project_id": 15513260,
@@ -748,44 +813,43 @@ Supported attributes:
"first_contribution": false,
"user": {
"can_merge": true
- }
-}
-```
-
-Users on [GitLab Premium or higher](https://about.gitlab.com/pricing/) also see
-the `approvals_before_merge` parameter:
-
-```json
-{
- "id": 1,
- "title": "test1",
- "approvals_before_merge": null
- ...
+ },
+ "approvals_before_merge": { // Available for GitLab Premium and higher tiers only
+ "id": 1,
+ "title": "test1",
+ "approvals_before_merge": null
+ },
}
```
### Single merge request response notes
-- The `merge_status` field may hold one of the following values:
- - `unchecked`: This merge request has not yet been checked.
- - `checking`: This merge request is currently being checked to see if it can be merged.
- - `can_be_merged`: This merge request can be merged without conflict.
- - `cannot_be_merged`: There are merge conflicts between the source and target branches.
- - `cannot_be_merged_recheck`: Currently unchecked. Before the current changes, there were conflicts.
-- The `diff_refs` in the response correspond to the latest diff version of the merge request.
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/29984) in GitLab 12.8, the mergeability (`merge_status`)
of each merge request is checked asynchronously when a request is made to this endpoint. Poll this API endpoint
to get updated status. This affects the `has_conflicts` property as it is dependent on the `merge_status`. It returns
`false` unless `merge_status` is `cannot_be_merged`.
-- `references.relative` is relative to the group or project that the merge request is being requested. When the merge
- request is fetched from its project, `relative` format would be the same as `short` format, and when requested across
- groups or projects, it is expected to be the same as `full` format.
-- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/349031) in GitLab 14.7,
- field `merge_user` can be either user who merged this merge request,
- user who set it to merge when pipeline succeeds or `null`.
- Field `merged_by` (user who merged this merge request or `null`) has been deprecated.
-- `pipeline` is an old parameter and should not be used. Use `head_pipeline` instead,
- as it is faster and returns more information.
+
+### Merge status
+
+> - The `detailed_merge_status` field was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101724) in GitLab 15.6.
+> - The `merge_status` field was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/3169#note_1162532204) in GitLab 15.6.
+
+Use `detailed_merge_status` instead of `merge_status` to account for all potential statuses.
+
+- The `detailed_merge_status` field may hold one of the following values:
+ - `blocked_status`: Merge request is blocked by another merge request.
+ - `broken_status`: Can not merge the source into the target branch, potential conflict.
+ - `checking`: currently checking for mergeability.
+ - `ci_must_pass`: Pipeline must succeed before merging.
+ - `ci_still_running`: Pipeline is still running.
+ - `discussions_not_resolved`: Discussions must be resolved before merging.
+ - `draft_status`: Merge request must not be draft before merging.
+ - `external_status_checks`: Status checks must pass.
+ - `mergeable`: branch can be merged.
+ - `not_approved`: Merge request must be approved before merging.
+ - `not_open`: merge request must be open before merging.
+ - `policies_denied`: There are denied policies for the merge request.
+ - `unchecked`: merge status has not been checked.
## Get single MR participants
@@ -994,6 +1058,7 @@ Supported attributes:
},
"merge_when_pipeline_succeeds": true,
"merge_status": "can_be_merged",
+ "detailed_merge_status": "can_be_merged",
"subscribed" : true,
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
@@ -1211,6 +1276,7 @@ If `approvals_before_merge` is not provided, it inherits the value from the targ
},
"merge_when_pipeline_succeeds": true,
"merge_status": "can_be_merged",
+ "detailed_merge_status": "not_open",
"merge_error": null,
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
@@ -1392,6 +1458,7 @@ Must include at least one non-required attribute from above.
},
"merge_when_pipeline_succeeds": true,
"merge_status": "can_be_merged",
+ "detailed_merge_status": "not_open",
"merge_error": null,
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
@@ -1580,6 +1647,7 @@ Supported attributes:
},
"merge_when_pipeline_succeeds": true,
"merge_status": "can_be_merged",
+ "detailed_merge_status": "not_open",
"merge_error": null,
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
@@ -1792,6 +1860,7 @@ Supported attributes:
},
"merge_when_pipeline_succeeds": false,
"merge_status": "can_be_merged",
+ "detailed_merge_status": "not_open",
"merge_error": null,
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
@@ -2124,6 +2193,7 @@ Example response:
},
"merge_when_pipeline_succeeds": true,
"merge_status": "can_be_merged",
+ "detailed_merge_status": "not_open",
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
"squash_commit_sha": null,
@@ -2294,6 +2364,7 @@ Example response:
},
"merge_when_pipeline_succeeds": true,
"merge_status": "can_be_merged",
+ "detailed_merge_status": "not_open",
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
"squash_commit_sha": null,
@@ -2479,6 +2550,7 @@ Example response:
},
"merge_when_pipeline_succeeds": false,
"merge_status": "unchecked",
+ "detailed_merge_status": "not_open",
"subscribed": true,
"sha": "8888888888888888888888888888888888888888",
"merge_commit_sha": null,
diff --git a/doc/api/merge_trains.md b/doc/api/merge_trains.md
index 64ca2bf9b97..111cf5255d6 100644
--- a/doc/api/merge_trains.md
+++ b/doc/api/merge_trains.md
@@ -84,3 +84,73 @@ Example response:
}
]
```
+
+## List merge requests in a merge train
+
+Get all merge requests added to a merge train for the requested target branch.
+
+```plaintext
+GET /projects/:id/merge_trains/:target_branch
+```
+
+Supported attributes:
+
+| Attribute | Type | Required | Description |
+| --------------- | ---------------| -------- | ------------ |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
+| `target_branch` | string | yes | The target branch of the merge train. |
+| `scope` | string | no | Return Merge Trains filtered by the given scope. Available scopes are `active` (to be merged) and `complete` (have been merged). |
+| `sort` | string | no | Return Merge Trains sorted in `asc` or `desc` order. Default is `desc`. |
+
+Example request:
+
+```shell
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/597/merge_trains/main"
+```
+
+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/metadata.md b/doc/api/metadata.md
index 3803173b0b8..c3cbae70a54 100644
--- a/doc/api/metadata.md
+++ b/doc/api/metadata.md
@@ -24,6 +24,7 @@ Response body attributes:
| `kas.enabled` | boolean | Indicates whether KAS is enabled. |
| `kas.externalUrl` | string or null | URL used by the agents to communicate with KAS. It's `null` if `kas.enabled` is `false`. |
| `kas.version` | string or null | Version of KAS. It's `null` if `kas.enabled` is `false`. |
+| `enterprise` | boolean | Indicates whether GitLab instance is Enterprise Edition. |
Example request:
@@ -41,6 +42,7 @@ Example response:
"enabled": true,
"externalUrl": "grpc://gitlab.example.com:8150",
"version": "15.0.0"
- }
+ },
+ "enterprise": true
}
```
diff --git a/doc/api/milestones.md b/doc/api/milestones.md
index df09e374395..22746d4ceed 100644
--- a/doc/api/milestones.md
+++ b/doc/api/milestones.md
@@ -88,8 +88,8 @@ Parameters:
| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
| `title` | string | yes | The title of a milestone |
| `description` | string | no | The description of the milestone |
-| `due_date` | string | no | The due date of the milestone |
-| `start_date` | string | no | The start date of the milestone |
+| `due_date` | string | no | The due date of the milestone (`YYYYMMDD`) |
+| `start_date` | string | no | The start date of the milestone (`YYYYMMDD`) |
## Edit milestone
@@ -107,8 +107,8 @@ Parameters:
| `milestone_id` | integer | yes | The ID of the project's milestone |
| `title` | string | no | The title of a milestone |
| `description` | string | no | The description of the milestone |
-| `due_date` | string | no | The due date of the milestone |
-| `start_date` | string | no | The start date of the milestone |
+| `due_date` | string | no | The due date of the milestone (`YYYYMMDD`) |
+| `start_date` | string | no | The start date of the milestone (`YYYYMMDD`) |
| `state_event` | string | no | The state event of the milestone (close or activate) |
## Delete project milestone
diff --git a/doc/api/oauth2.md b/doc/api/oauth2.md
index aca6ee74b15..371e3f9ae47 100644
--- a/doc/api/oauth2.md
+++ b/doc/api/oauth2.md
@@ -63,7 +63,7 @@ For a list of scopes in GitLab, see [the provider documentation](../integration/
### Prevent CSRF attacks
-To [protect redirect-based flows](https://tools.ietf.org/id/draft-ietf-oauth-security-topics-13.html#rec_redirect),
+To [protect redirect-based flows](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics-13#section-3.1),
the OAuth specification recommends the use of "One-time use CSRF tokens carried in the state
parameter, which are securely bound to the user agent", with each request to the
`/oauth/authorize` endpoint. This can prevent
diff --git a/doc/api/openapi/openapi.yaml b/doc/api/openapi/openapi.yaml
index a3a0485428d..9ee2b8119be 100644
--- a/doc/api/openapi/openapi.yaml
+++ b/doc/api/openapi/openapi.yaml
@@ -43,35 +43,657 @@ components:
paths:
# METADATA
/v4/metadata:
- $ref: 'v4/metadata.yaml'
+ $ref: '#/metadata'
# VERSION
/v4/version:
- $ref: 'v4/version.yaml'
+ $ref: '#/version'
# ACCESS REQUESTS (PROJECTS)
/v4/projects/{id}/access_requests:
- $ref: 'v4/access_requests.yaml#/accessRequestsProjects'
+ $ref: '#/accessRequestsProjects'
/v4/projects/{id}/access_requests/{user_id}/approve:
- $ref: 'v4/access_requests.yaml#/accessRequestsProjectsApprove'
+ $ref: '#/accessRequestsProjectsApprove'
/v4/projects/{id}/access_requests/{user_id}:
- $ref: 'v4/access_requests.yaml#/accessRequestsProjectsDeny'
+ $ref: '#/accessRequestsProjectsDeny'
# ACCESS REQUESTS (GROUPS)
/v4/groups/{id}/access_requests:
- $ref: 'v4/access_requests.yaml#/accessRequestsGroups'
+ $ref: '#/accessRequestsGroups'
/v4/groups/{id}/access_requests/{user_id}/approve:
- $ref: 'v4/access_requests.yaml#/accessRequestsGroupsApprove'
+ $ref: '#/accessRequestsGroupsApprove'
/v4/groups/{id}/access_requests/{user_id}:
- $ref: 'v4/access_requests.yaml#/accessRequestsGroupsDeny'
+ $ref: '#/accessRequestsGroupsDeny'
# ACCESS REQUESTS (PROJECTS)
/v4/projects/{id}/access_tokens:
- $ref: 'v4/access_tokens.yaml#/accessTokens'
+ $ref: '#/accessTokens'
/v4/projects/{id}/access_tokens/{token_id}:
- $ref: 'v4/access_tokens.yaml#/accessTokensRevoke'
+ $ref: '#/accessTokensRevoke'
+
+metadata:
+ get:
+ tags:
+ - metadata
+ summary: 'Retrieve metadata information for this GitLab instance.'
+ operationId: 'getMetadata'
+ responses:
+ '401':
+ description: 'unauthorized operation'
+ '200':
+ description: 'successful operation'
+ content:
+ 'application/json':
+ schema:
+ title: 'MetadataResponse'
+ type: 'object'
+ properties:
+ version:
+ type: 'string'
+ revision:
+ type: 'string'
+ kas:
+ type: 'object'
+ properties:
+ enabled:
+ type: 'boolean'
+ externalUrl:
+ type: 'string'
+ nullable: true
+ version:
+ type: 'string'
+ nullable: true
+ examples:
+ Example:
+ value:
+ version: '15.0-pre'
+ revision: 'c401a659d0c'
+ kas:
+ enabled: true
+ externalUrl: 'grpc://gitlab.example.com:8150'
+ version: '15.0.0'
+
+version:
+ get:
+ tags:
+ - version
+ summary: 'Retrieve version information for this GitLab instance.'
+ operationId: 'getVersion'
+ responses:
+ '401':
+ description: 'unauthorized operation'
+ '200':
+ description: 'successful operation'
+ content:
+ 'application/json':
+ schema:
+ title: 'VersionResponse'
+ type: 'object'
+ properties:
+ version:
+ type: 'string'
+ revision:
+ type: 'string'
+ examples:
+ Example:
+ value:
+ version: '13.3.0-pre'
+ revision: 'f2b05afebb0'
+
+#/v4/projects/{id}/access_requests
+accessRequestsProjects:
+ get:
+ description: Lists access requests for a project
+ summary: List access requests for a project
+ operationId: accessRequestsProjects_get
+ tags:
+ - access_requests
+ parameters:
+ - name: id
+ in: path
+ description: The ID or URL-encoded path of the project owned by the authenticated user.
+ required: true
+ schema:
+ oneOf:
+ - type: integer
+ - type: string
+ responses:
+ '401':
+ description: Unauthorized operation
+ '200':
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ title: ProjectAccessResponse
+ type: object
+ properties:
+ id:
+ type: integer
+ usename:
+ type: string
+ name:
+ type: string
+ state:
+ type: string
+ created_at:
+ type: string
+ requested_at:
+ type: string
+ example:
+ - 'id': 1
+ 'username': 'raymond_smith'
+ 'name': 'Raymond Smith'
+ 'state': 'active'
+ 'created_at': '2012-10-22T14:13:35Z'
+ 'requested_at': '2012-10-22T14:13:35Z'
+ - 'id': 2
+ 'username': 'john_doe'
+ 'name': 'John Doe'
+ 'state': 'active'
+ 'created_at': '2012-10-22T14:13:35Z'
+ 'requested_at': '2012-10-22T14:13:35Z'
+ post:
+ description: Requests access for the authenticated user to a project
+ summary: Requests access for the authenticated user to a project
+ operationId: accessRequestsProjects_post
+ tags:
+ - access_requests
+ parameters:
+ - name: id
+ in: path
+ description: The ID or URL-encoded path of the project owned by the authenticated user.
+ required: true
+ schema:
+ oneOf:
+ - type: integer
+ - type: string
+ responses:
+ '401':
+ description: Unauthorized operation
+ '200':
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ title: ProjectAccessRequest
+ type: object
+ properties:
+ id:
+ type: integer
+ usename:
+ type: string
+ name:
+ type: string
+ state:
+ type: string
+ created_at:
+ type: string
+ requested_at:
+ type: string
+ example:
+ 'id': 1
+ 'username': 'raymond_smith'
+ 'name': 'Raymond Smith'
+ 'state': 'active'
+ 'created_at': '2012-10-22T14:13:35Z'
+ 'requested_at': '2012-10-22T14:13:35Z'
+
+#/v4/projects/{id}/access_requests/{user_id}/approve
+accessRequestsProjectsApprove:
+ put:
+ description: Approves access for the authenticated user to a project
+ summary: Approves access for the authenticated user to a project
+ operationId: accessRequestsProjectsApprove_put
+ tags:
+ - access_requests
+ parameters:
+ - name: id
+ in: path
+ description: The ID or URL-encoded path of the project owned by the authenticated user.
+ required: true
+ schema:
+ oneOf:
+ - type: integer
+ - type: string
+ - name: user_id
+ in: path
+ description: The userID of the access requester
+ required: true
+ schema:
+ type: integer
+ - name: access_level
+ in: query
+ description: A valid project access level. 0 = no access , 10 = guest, 20 = reporter, 30 = developer, 40 = Maintainer. Default is 30.'
+ required: false
+ schema:
+ enum: [0, 10, 20, 30, 40]
+ default: 30
+ type: integer
+ responses:
+ '401':
+ description: Unauthorized operation
+ '200':
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ title: ProjectAccessApprove
+ type: object
+ properties:
+ id:
+ type: integer
+ usename:
+ type: string
+ name:
+ type: string
+ state:
+ type: string
+ created_at:
+ type: string
+ access_level:
+ type: integer
+ example:
+ 'id': 1
+ 'username': 'raymond_smith'
+ 'name': 'Raymond Smith'
+ 'state': 'active'
+ 'created_at': '2012-10-22T14:13:35Z'
+ 'access_level': 20
+
+#/v4/projects/{id}/access_requests/{user_id}
+accessRequestsProjectsDeny:
+ delete:
+ description: Denies a project access request for the given user
+ summary: Denies a project access request for the given user
+ operationId: accessRequestProjectsDeny_delete
+ tags:
+ - access_requests
+ parameters:
+ - name: id
+ in: path
+ description: The ID or URL-encoded path of the project owned by the authenticated user.
+ required: true
+ schema:
+ oneOf:
+ - type: integer
+ - type: string
+ - name: user_id
+ in: path
+ description: The user ID of the access requester
+ required: true
+ schema:
+ type: integer
+ responses: # Does anything go here? Markdown doc does not list a response.
+ '401':
+ description: Unauthorized operation
+ '200':
+ description: Successful operation
+
+#/v4/groups/{id}/access_requests
+accessRequestsGroups:
+ get:
+ description: List access requests for a group
+ summary: List access requests for a group
+ operationId: accessRequestsGroups_get
+ tags:
+ - access_requests
+ parameters:
+ - name: id
+ in: path
+ description: The ID or URL-encoded path of the group owned by the authenticated user.
+ required: true
+ schema:
+ oneOf:
+ - type: integer
+ - type: string
+ responses:
+ '401':
+ description: Unauthorized operation
+ '200':
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ title: GroupAccessResponse
+ type: object
+ properties:
+ id:
+ type: integer
+ usename:
+ type: string
+ name:
+ type: string
+ state:
+ type: string
+ created_at:
+ type: string
+ requested_at:
+ type: string
+ example:
+ - 'id': 1
+ 'username': 'raymond_smith'
+ 'name': 'Raymond Smith'
+ 'state': 'active'
+ 'created_at': '2012-10-22T14:13:35Z'
+ 'requested_at': '2012-10-22T14:13:35Z'
+ - 'id': 2
+ 'username': 'john_doe'
+ 'name': 'John Doe'
+ 'state': 'active'
+ 'created_at': '2012-10-22T14:13:35Z'
+ 'requested_at': '2012-10-22T14:13:35Z'
+ post:
+ description: Requests access for the authenticated user to a group
+ summary: Requests access for the authenticated user to a group
+ operationId: accessRequestsGroups_post
+ tags:
+ - access_requests
+ parameters:
+ - name: id
+ in: path
+ description: The ID or URL-encoded path of the group owned by the authenticated user.
+ required: true
+ schema:
+ oneOf:
+ - type: integer
+ - type: string
+ responses:
+ '401':
+ description: Unauthorized operation
+ '200':
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ title: GroupAccessRequest
+ type: object
+ properties:
+ id:
+ type: integer
+ usename:
+ type: string
+ name:
+ type: string
+ state:
+ type: string
+ created_at:
+ type: string
+ requested_at:
+ type: string
+ example:
+ 'id': 1
+ 'username': 'raymond_smith'
+ 'name': 'Raymond Smith'
+ 'state': 'active'
+ 'created_at': '2012-10-22T14:13:35Z'
+ 'requested_at': '2012-10-22T14:13:35Z'
+
+#/v4/groups/{id}/access_requests/{user_id}/approve
+accessRequestsGroupsApprove:
+ put:
+ description: Approves access for the authenticated user to a group
+ summary: Approves access for the authenticated user to a group
+ operationId: accessRequestsGroupsApprove_put
+ tags:
+ - access_requests
+ parameters:
+ - name: id
+ in: path
+ description: The ID or URL-encoded path of the group owned by the authenticated user.
+ required: true
+ schema:
+ oneOf:
+ - type: integer
+ - type: string
+ - name: user_id
+ in: path
+ description: The userID of the access requester
+ required: true
+ schema:
+ type: integer
+ - name: access_level
+ in: query
+ description: A valid group access level. 0 = no access , 10 = Guest, 20 = Reporter, 30 = Developer, 40 = Maintainer, 50 = Owner. Default is 30.
+ required: false
+ schema:
+ enum: [0, 10, 20, 30, 40, 50]
+ default: 30
+ type: integer
+ responses:
+ '401':
+ description: Unauthorized operation
+ '200':
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ title: GroupAccessApprove
+ type: object
+ properties:
+ id:
+ type: integer
+ usename:
+ type: string
+ name:
+ type: string
+ state:
+ type: string
+ created_at:
+ type: string
+ access_level:
+ type: integer
+ example:
+ 'id': 1
+ 'username': 'raymond_smith'
+ 'name': 'Raymond Smith'
+ 'state': 'active'
+ 'created_at': '2012-10-22T14:13:35Z'
+ 'access_level': 20
+
+#/v4/groups/{id}/access_requests/{user_id}
+accessRequestsGroupsDeny:
+ delete:
+ description: Denies a group access request for the given user
+ summary: Denies a group access request for the given user
+ operationId: accessRequestsGroupsDeny_delete
+ tags:
+ - access_requests
+ parameters:
+ - name: id
+ in: path
+ description: The ID or URL-encoded path of the group owned by the authenticated user.
+ required: true
+ schema:
+ oneOf:
+ - type: integer
+ - type: string
+ - name: user_id
+ in: path
+ description: The userID of the access requester
+ required: true
+ schema:
+ type: integer
+ responses: # Does anything go here? Markdown doc does not list a response.
+ '401':
+ description: Unauthorized operation
+ '200':
+ description: Successful operation
+#/v4/projects/{id}/access_tokens
+accessTokens:
+ get:
+ description: Lists access tokens for a project
+ summary: List access tokens for a project
+ operationId: accessTokens_get
+ tags:
+ - access_tokens
+ parameters:
+ - name: id
+ in: path
+ description: The ID or URL-encoded path of the project
+ required: true
+ schema:
+ oneOf:
+ - type: integer
+ - type: string
+ responses:
+ '404':
+ description: Not Found
+ '401':
+ description: Unauthorized operation
+ '200':
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ title: AccessTokenList
+ type: object
+ properties:
+ user_id:
+ type: integer
+ scopes:
+ type: array
+ name:
+ type: string
+ expires_at:
+ type: date
+ id:
+ type: integer
+ active:
+ type: boolean
+ created_at:
+ type: date
+ revoked:
+ type: boolean
+ example:
+ 'user_id': 141
+ 'scopes': ['api']
+ 'name': 'token'
+ 'expires_at': '2022-01-31'
+ 'id': 42
+ 'active': true
+ 'created_at': '2021-01-20T14:13:35Z'
+ 'revoked': false
+ post:
+ description: Creates an access token for a project
+ summary: Creates an access token for a project
+ operationId: accessTokens_post
+ tags:
+ - access_tokens
+ parameters:
+ - name: id
+ in: path
+ description: The ID or URL-encoded path of the project
+ required: true
+ schema:
+ oneOf:
+ - type: integer
+ - type: string
+ - name: name
+ in: query
+ description: The name of the project access token
+ required: true
+ schema:
+ type: string
+ - name: scopes
+ in: query
+ description: Defines read and write permissions for the token
+ required: true
+ schema:
+ type: array
+ items:
+ type: string
+ enum:
+ [
+ 'api',
+ 'read_api',
+ 'read_registry',
+ 'write_registry',
+ 'read_repository',
+ 'write_repository',
+ ]
+ - name: expires_at
+ in: query
+ description: Date when the token expires. Time of day is Midnight UTC of that date.
+ required: false
+ schema:
+ type: date
+ responses:
+ '404':
+ description: Not Found
+ '401':
+ description: Unauthorized operation
+ '200':
+ description: Successful operation
+ content:
+ application/json:
+ schema:
+ title: AccessTokenList
+ type: object
+ properties:
+ user_id:
+ type: integer
+ scopes:
+ type: array
+ name:
+ type: string
+ expires_at:
+ type: date
+ id:
+ type: integer
+ active:
+ type: boolean
+ created_at:
+ type: date
+ revoked:
+ type: boolean
+ token:
+ type: string
+ example:
+ 'user_id': 166
+ 'scopes': ['api', 'read_repository']
+ 'name': 'test'
+ 'expires_at': '2022-01-31'
+ 'id': 58
+ 'active': true
+ 'created_at': '2021-01-20T14:13:35Z'
+ 'revoked': false
+ 'token': 'D4y...Wzr'
+
+#/v4/projects/{id}/access_tokens/{token_id}
+accessTokensRevoke:
+ delete:
+ description: Revokes an access token
+ summary: Revokes an access token
+ operationId: accessTokens_delete
+ tags:
+ - access_tokens
+ parameters:
+ - name: id
+ in: path
+ description: The ID or URL-encoded path of the project
+ required: true
+ schema:
+ oneOf:
+ - type: integer
+ - type: string
+ - name: token_id
+ in: path
+ description: The ID of the project access token
+ required: true
+ schema:
+ oneOf:
+ - type: integer
+ - type: string
+ responses:
+ '400':
+ description: Bad Request
+ '404':
+ description: Not Found
+ '204':
+ description: No content if successfully revoked
diff --git a/doc/api/openapi/openapi_v2.yaml b/doc/api/openapi/openapi_v2.yaml
index 59b21ecd048..5a99f6c8793 100644
--- a/doc/api/openapi/openapi_v2.yaml
+++ b/doc/api/openapi/openapi_v2.yaml
@@ -16,9 +16,295 @@ securityDefinitions:
in: query
host: gitlab.com
tags:
+- name: user_counts
+ description: Operations about user_counts
- name: metadata
description: Operations related to metadata of the GitLab instance
+- name: access_requests
+ description: Operations related to access requests
paths:
+ "/api/v4/groups/{id}/access_requests/{user_id}":
+ delete:
+ summary: Denies an access request for the given user.
+ description: This feature was introduced in GitLab 8.11.
+ produces:
+ - application/json
+ parameters:
+ - in: path
+ name: id
+ description: The ID or URL-encoded path of the group owned by the authenticated
+ user
+ type: string
+ required: true
+ - in: path
+ name: user_id
+ description: The user ID of the access requester
+ type: integer
+ format: int32
+ required: true
+ responses:
+ '204':
+ description: Denies an access request for the given user.
+ tags:
+ - access_requests
+ operationId: deleteApiV4GroupsIdAccessRequestsUserId
+ "/api/v4/groups/{id}/access_requests/{user_id}/approve":
+ put:
+ summary: Approves an access request for the given user.
+ description: This feature was introduced in GitLab 8.11.
+ produces:
+ - application/json
+ consumes:
+ - application/json
+ parameters:
+ - in: path
+ name: id
+ description: The ID or URL-encoded path of the group owned by the authenticated
+ user
+ type: string
+ required: true
+ - in: path
+ name: user_id
+ description: The user ID of the access requester
+ type: integer
+ format: int32
+ required: true
+ - in: formData
+ name: access_level
+ description: 'A valid access level (defaults: `30`, the Developer role)'
+ type: integer
+ format: int32
+ default: 30
+ required: false
+ responses:
+ '200':
+ description: successful operation
+ schema:
+ "$ref": "#/definitions/API_Entities_AccessRequester"
+ examples:
+ successfull_response:
+ id: 1
+ username: raymond_smith
+ name: Raymond Smith
+ state: active
+ created_at: '2012-10-22T14:13:35Z'
+ access_level: 20
+ tags:
+ - access_requests
+ operationId: putApiV4GroupsIdAccessRequestsUserIdApprove
+ "/api/v4/groups/{id}/access_requests":
+ post:
+ summary: Requests access for the authenticated user to a group.
+ description: This feature was introduced in GitLab 8.11.
+ produces:
+ - application/json
+ consumes:
+ - application/json
+ parameters:
+ - in: path
+ name: id
+ description: The ID or URL-encoded path of the group owned by the authenticated
+ user
+ type: string
+ required: true
+ responses:
+ '200':
+ description: successful operation
+ schema:
+ "$ref": "#/definitions/API_Entities_AccessRequester"
+ examples:
+ successfull_response:
+ id: 1
+ username: raymond_smith
+ name: Raymond Smith
+ state: active
+ created_at: '2012-10-22T14:13:35Z'
+ access_level: 20
+ tags:
+ - access_requests
+ operationId: postApiV4GroupsIdAccessRequests
+ get:
+ summary: Gets a list of access requests for a group.
+ description: This feature was introduced in GitLab 8.11.
+ produces:
+ - application/json
+ parameters:
+ - in: path
+ name: id
+ description: The ID or URL-encoded path of the group owned by the authenticated
+ user
+ type: string
+ required: true
+ - in: query
+ name: page
+ description: Current page number
+ type: integer
+ format: int32
+ default: 1
+ required: false
+ - in: query
+ name: per_page
+ description: Number of items per page
+ type: integer
+ format: int32
+ default: 20
+ required: false
+ responses:
+ '200':
+ description: Gets a list of access requests for a group.
+ schema:
+ "$ref": "#/definitions/API_Entities_AccessRequester"
+ tags:
+ - access_requests
+ operationId: getApiV4GroupsIdAccessRequests
+ "/api/v4/projects/{id}/access_requests/{user_id}":
+ delete:
+ summary: Denies an access request for the given user.
+ description: This feature was introduced in GitLab 8.11.
+ produces:
+ - application/json
+ parameters:
+ - in: path
+ name: id
+ description: The ID or URL-encoded path of the project owned by the authenticated
+ user
+ type: string
+ required: true
+ - in: path
+ name: user_id
+ description: The user ID of the access requester
+ type: integer
+ format: int32
+ required: true
+ responses:
+ '204':
+ description: Denies an access request for the given user.
+ tags:
+ - access_requests
+ operationId: deleteApiV4ProjectsIdAccessRequestsUserId
+ "/api/v4/projects/{id}/access_requests/{user_id}/approve":
+ put:
+ summary: Approves an access request for the given user.
+ description: This feature was introduced in GitLab 8.11.
+ produces:
+ - application/json
+ consumes:
+ - application/json
+ parameters:
+ - in: path
+ name: id
+ description: The ID or URL-encoded path of the project owned by the authenticated
+ user
+ type: string
+ required: true
+ - in: path
+ name: user_id
+ description: The user ID of the access requester
+ type: integer
+ format: int32
+ required: true
+ - in: formData
+ name: access_level
+ description: 'A valid access level (defaults: `30`, the Developer role)'
+ type: integer
+ format: int32
+ default: 30
+ required: false
+ responses:
+ '200':
+ description: successful operation
+ schema:
+ "$ref": "#/definitions/API_Entities_AccessRequester"
+ examples:
+ successfull_response:
+ id: 1
+ username: raymond_smith
+ name: Raymond Smith
+ state: active
+ created_at: '2012-10-22T14:13:35Z'
+ access_level: 20
+ tags:
+ - access_requests
+ operationId: putApiV4ProjectsIdAccessRequestsUserIdApprove
+ "/api/v4/projects/{id}/access_requests":
+ post:
+ summary: Requests access for the authenticated user to a project.
+ description: This feature was introduced in GitLab 8.11.
+ produces:
+ - application/json
+ consumes:
+ - application/json
+ parameters:
+ - in: path
+ name: id
+ description: The ID or URL-encoded path of the project owned by the authenticated
+ user
+ type: string
+ required: true
+ responses:
+ '200':
+ description: successful operation
+ schema:
+ "$ref": "#/definitions/API_Entities_AccessRequester"
+ examples:
+ successfull_response:
+ id: 1
+ username: raymond_smith
+ name: Raymond Smith
+ state: active
+ created_at: '2012-10-22T14:13:35Z'
+ access_level: 20
+ tags:
+ - access_requests
+ operationId: postApiV4ProjectsIdAccessRequests
+ get:
+ summary: Gets a list of access requests for a project.
+ description: This feature was introduced in GitLab 8.11.
+ produces:
+ - application/json
+ parameters:
+ - in: path
+ name: id
+ description: The ID or URL-encoded path of the project owned by the authenticated
+ user
+ type: string
+ required: true
+ - in: query
+ name: page
+ description: Current page number
+ type: integer
+ format: int32
+ default: 1
+ required: false
+ - in: query
+ name: per_page
+ description: Number of items per page
+ type: integer
+ format: int32
+ default: 20
+ required: false
+ responses:
+ '200':
+ description: Gets a list of access requests for a project.
+ schema:
+ "$ref": "#/definitions/API_Entities_AccessRequester"
+ tags:
+ - access_requests
+ operationId: getApiV4ProjectsIdAccessRequests
+ "/api/v4/user_counts":
+ get:
+ summary: Return the user specific counts
+ description: Assigned open issues, assigned MRs and pending todos count
+ produces:
+ - application/json
+ responses:
+ '200':
+ description: Return the user specific counts
+ schema:
+ "$ref": "#/definitions/API_Entities_UserCounts"
+ tags:
+ - user_counts
+ operationId: getApiV4UserCounts
"/api/v4/metadata":
get:
summary: Retrieve metadata information for this GitLab instance.
@@ -71,6 +357,63 @@ paths:
- metadata
operationId: getApiV4Version
definitions:
+ API_Entities_AccessRequester:
+ type: object
+ properties:
+ id:
+ type: string
+ username:
+ type: string
+ name:
+ type: string
+ state:
+ type: string
+ avatar_url:
+ type: string
+ avatar_path:
+ type: string
+ custom_attributes:
+ "$ref": "#/definitions/API_Entities_CustomAttribute"
+ web_url:
+ type: string
+ is_gitlab_employee:
+ type: string
+ email:
+ type: string
+ requested_at:
+ type: string
+ description: API_Entities_AccessRequester model
+ API_Entities_CustomAttribute:
+ type: object
+ properties:
+ key:
+ type: string
+ value:
+ type: string
+ API_Entities_UserCounts:
+ type: object
+ properties:
+ merge_requests:
+ type: integer
+ format: int32
+ example: 10
+ assigned_issues:
+ type: integer
+ format: int32
+ example: 10
+ assigned_merge_requests:
+ type: integer
+ format: int32
+ example: 10
+ review_requested_merge_requests:
+ type: integer
+ format: int32
+ example: 10
+ todos:
+ type: integer
+ format: int32
+ example: 10
+ description: API_Entities_UserCounts model
API_Entities_Metadata:
type: object
properties:
diff --git a/doc/api/openapi/v4/access_requests.yaml b/doc/api/openapi/v4/access_requests.yaml
deleted file mode 100644
index 157a0973e1e..00000000000
--- a/doc/api/openapi/v4/access_requests.yaml
+++ /dev/null
@@ -1,381 +0,0 @@
-# Markdown documentation: https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/api/access_requests.md
-
-#/v4/projects/{id}/access_requests
-accessRequestsProjects:
- get:
- description: Lists access requests for a project
- summary: List access requests for a project
- operationId: accessRequestsProjects_get
- tags:
- - access_requests
- parameters:
- - name: id
- in: path
- description: The ID or URL-encoded path of the project owned by the authenticated user.
- required: true
- schema:
- oneOf:
- - type: integer
- - type: string
- responses:
- '401':
- description: Unauthorized operation
- '200':
- description: Successful operation
- content:
- application/json:
- schema:
- title: ProjectAccessResponse
- type: object
- properties:
- id:
- type: integer
- usename:
- type: string
- name:
- type: string
- state:
- type: string
- created_at:
- type: string
- requested_at:
- type: string
- example:
- - "id": 1
- "username": "raymond_smith"
- "name": "Raymond Smith"
- "state": "active"
- "created_at": "2012-10-22T14:13:35Z"
- "requested_at": "2012-10-22T14:13:35Z"
- - "id": 2
- "username": "john_doe"
- "name": "John Doe"
- "state": "active"
- "created_at": "2012-10-22T14:13:35Z"
- "requested_at": "2012-10-22T14:13:35Z"
- post:
- description: Requests access for the authenticated user to a project
- summary: Requests access for the authenticated user to a project
- operationId: accessRequestsProjects_post
- tags:
- - access_requests
- parameters:
- - name: id
- in: path
- description: The ID or URL-encoded path of the project owned by the authenticated user.
- required: true
- schema:
- oneOf:
- - type: integer
- - type: string
- responses:
- '401':
- description: Unauthorized operation
- '200':
- description: Successful operation
- content:
- application/json:
- schema:
- title: ProjectAccessRequest
- type: object
- properties:
- id:
- type: integer
- usename:
- type: string
- name:
- type: string
- state:
- type: string
- created_at:
- type: string
- requested_at:
- type: string
- example:
- "id": 1
- "username": "raymond_smith"
- "name": "Raymond Smith"
- "state": "active"
- "created_at": "2012-10-22T14:13:35Z"
- "requested_at": "2012-10-22T14:13:35Z"
-
-#/v4/projects/{id}/access_requests/{user_id}/approve
-accessRequestsProjectsApprove:
- put:
- description: Approves access for the authenticated user to a project
- summary: Approves access for the authenticated user to a project
- operationId: accessRequestsProjectsApprove_put
- tags:
- - access_requests
- parameters:
- - name: id
- in: path
- description: The ID or URL-encoded path of the project owned by the authenticated user.
- required: true
- schema:
- oneOf:
- - type: integer
- - type: string
- - name: user_id
- in: path
- description: The userID of the access requester
- required: true
- schema:
- type: integer
- - name: access_level
- in: query
- description: A valid project access level. 0 = no access , 10 = guest, 20 = reporter, 30 = developer, 40 = Maintainer. Default is 30.'
- required: false
- schema:
- enum: [0, 10, 20, 30, 40]
- default: 30
- type: integer
- responses:
- '401':
- description: Unauthorized operation
- '200':
- description: Successful operation
- content:
- application/json:
- schema:
- title: ProjectAccessApprove
- type: object
- properties:
- id:
- type: integer
- usename:
- type: string
- name:
- type: string
- state:
- type: string
- created_at:
- type: string
- access_level:
- type: integer
- example:
- "id": 1
- "username": "raymond_smith"
- "name": "Raymond Smith"
- "state": "active"
- "created_at": "2012-10-22T14:13:35Z"
- "access_level": 20
-
-#/v4/projects/{id}/access_requests/{user_id}
-accessRequestsProjectsDeny:
- delete:
- description: Denies a project access request for the given user
- summary: Denies a project access request for the given user
- operationId: accessRequestProjectsDeny_delete
- tags:
- - access_requests
- parameters:
- - name: id
- in: path
- description: The ID or URL-encoded path of the project owned by the authenticated user.
- required: true
- schema:
- oneOf:
- - type: integer
- - type: string
- - name: user_id
- in: path
- description: The user ID of the access requester
- required: true
- schema:
- type: integer
- responses: # Does anything go here? Markdown doc does not list a response.
- '401':
- description: Unauthorized operation
- '200':
- description: Successful operation
-
-#/v4/groups/{id}/access_requests
-accessRequestsGroups:
- get:
- description: List access requests for a group
- summary: List access requests for a group
- operationId: accessRequestsGroups_get
- tags:
- - access_requests
- parameters:
- - name: id
- in: path
- description: The ID or URL-encoded path of the group owned by the authenticated user.
- required: true
- schema:
- oneOf:
- - type: integer
- - type: string
- responses:
- '401':
- description: Unauthorized operation
- '200':
- description: Successful operation
- content:
- application/json:
- schema:
- title: GroupAccessResponse
- type: object
- properties:
- id:
- type: integer
- usename:
- type: string
- name:
- type: string
- state:
- type: string
- created_at:
- type: string
- requested_at:
- type: string
- example:
- - "id": 1
- "username": "raymond_smith"
- "name": "Raymond Smith"
- "state": "active"
- "created_at": "2012-10-22T14:13:35Z"
- "requested_at": "2012-10-22T14:13:35Z"
- - "id": 2
- "username": "john_doe"
- "name": "John Doe"
- "state": "active"
- "created_at": "2012-10-22T14:13:35Z"
- "requested_at": "2012-10-22T14:13:35Z"
- post:
- description: Requests access for the authenticated user to a group
- summary: Requests access for the authenticated user to a group
- operationId: accessRequestsGroups_post
- tags:
- - access_requests
- parameters:
- - name: id
- in: path
- description: The ID or URL-encoded path of the group owned by the authenticated user.
- required: true
- schema:
- oneOf:
- - type: integer
- - type: string
- responses:
- '401':
- description: Unauthorized operation
- '200':
- description: Successful operation
- content:
- application/json:
- schema:
- title: GroupAccessRequest
- type: object
- properties:
- id:
- type: integer
- usename:
- type: string
- name:
- type: string
- state:
- type: string
- created_at:
- type: string
- requested_at:
- type: string
- example:
- "id": 1
- "username": "raymond_smith"
- "name": "Raymond Smith"
- "state": "active"
- "created_at": "2012-10-22T14:13:35Z"
- "requested_at": "2012-10-22T14:13:35Z"
-
-#/v4/groups/{id}/access_requests/{user_id}/approve
-accessRequestsGroupsApprove:
- put:
- description: Approves access for the authenticated user to a group
- summary: Approves access for the authenticated user to a group
- operationId: accessRequestsGroupsApprove_put
- tags:
- - access_requests
- parameters:
- - name: id
- in: path
- description: The ID or URL-encoded path of the group owned by the authenticated user.
- required: true
- schema:
- oneOf:
- - type: integer
- - type: string
- - name: user_id
- in: path
- description: The userID of the access requester
- required: true
- schema:
- type: integer
- - name: access_level
- in: query
- description: A valid group access level. 0 = no access , 10 = Guest, 20 = Reporter, 30 = Developer, 40 = Maintainer, 50 = Owner. Default is 30.
- required: false
- schema:
- enum: [0, 10, 20, 30, 40, 50]
- default: 30
- type: integer
- responses:
- '401':
- description: Unauthorized operation
- '200':
- description: Successful operation
- content:
- application/json:
- schema:
- title: GroupAccessApprove
- type: object
- properties:
- id:
- type: integer
- usename:
- type: string
- name:
- type: string
- state:
- type: string
- created_at:
- type: string
- access_level:
- type: integer
- example:
- "id": 1
- "username": "raymond_smith"
- "name": "Raymond Smith"
- "state": "active"
- "created_at": "2012-10-22T14:13:35Z"
- "access_level": 20
-
-#/v4/groups/{id}/access_requests/{user_id}
-accessRequestsGroupsDeny:
- delete:
- description: Denies a group access request for the given user
- summary: Denies a group access request for the given user
- operationId: accessRequestsGroupsDeny_delete
- tags:
- - access_requests
- parameters:
- - name: id
- in: path
- description: The ID or URL-encoded path of the group owned by the authenticated user.
- required: true
- schema:
- oneOf:
- - type: integer
- - type: string
- - name: user_id
- in: path
- description: The userID of the access requester
- required: true
- schema:
- type: integer
- responses: # Does anything go here? Markdown doc does not list a response.
- '401':
- description: Unauthorized operation
- '200':
- description: Successful operation
diff --git a/doc/api/openapi/v4/access_tokens.yaml b/doc/api/openapi/v4/access_tokens.yaml
deleted file mode 100644
index 9a1a6960eea..00000000000
--- a/doc/api/openapi/v4/access_tokens.yaml
+++ /dev/null
@@ -1,170 +0,0 @@
-# Markdown documentation: https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/api/resource_access_tokens.md
-
-#/v4/projects/{id}/access_tokens
-accessTokens:
- get:
- description: Lists access tokens for a project
- summary: List access tokens for a project
- operationId: accessTokens_get
- tags:
- - access_tokens
- parameters:
- - name: id
- in: path
- description: The ID or URL-encoded path of the project
- required: true
- schema:
- oneOf:
- - type: integer
- - type: string
- responses:
- '404':
- description: Not Found
- '401':
- description: Unauthorized operation
- '200':
- description: Successful operation
- content:
- application/json:
- schema:
- title: AccessTokenList
- type: object
- properties:
- user_id:
- type: integer
- scopes:
- type: array
- name:
- type: string
- expires_at:
- type: date
- id:
- type: integer
- active:
- type: boolean
- created_at:
- type: date
- revoked:
- type: boolean
- example:
- "user_id": 141
- "scopes" : ["api"]
- "name": "token"
- "expires_at": "2022-01-31"
- "id": 42
- "active": true
- "created_at": "2021-01-20T14:13:35Z"
- "revoked" : false
- post:
- description: Creates an access token for a project
- summary: Creates an access token for a project
- operationId: accessTokens_post
- tags:
- - access_tokens
- parameters:
- - name: id
- in: path
- description: The ID or URL-encoded path of the project
- required: true
- schema:
- oneOf:
- - type: integer
- - type: string
- - name: name
- in: query
- description: The name of the project access token
- required: true
- schema:
- type: string
- - name: scopes
- in: query
- description: Defines read and write permissions for the token
- required: true
- schema:
- type: array
- items:
- type: string
- enum: ["api", "read_api", "read_registry", "write_registry", "read_repository", "write_repository"]
- - name: expires_at
- in: query
- description: Date when the token expires. Time of day is Midnight UTC of that date.
- required: false
- schema:
- type: date
- responses:
- '404':
- description: Not Found
- '401':
- description: Unauthorized operation
- '200':
- description: Successful operation
- content:
- application/json:
- schema:
- title: AccessTokenList
- type: object
- properties:
- user_id:
- type: integer
- scopes:
- type: array
- name:
- type: string
- expires_at:
- type: date
- id:
- type: integer
- active:
- type: boolean
- created_at:
- type: date
- revoked:
- type: boolean
- token:
- type: string
- example:
- "user_id": 166
- "scopes" : [
- "api",
- "read_repository"
- ]
- "name": "test"
- "expires_at": "2022-01-31"
- "id": 58
- "active": true
- "created_at": "2021-01-20T14:13:35Z"
- "revoked" : false
- "token" : "D4y...Wzr"
-
-#/v4/projects/{id}/access_tokens/{token_id}
-accessTokensRevoke:
- delete:
- description: Revokes an access token
- summary: Revokes an access token
- operationId: accessTokens_delete
- tags:
- - access_tokens
- parameters:
- - name: id
- in: path
- description: The ID or URL-encoded path of the project
- required: true
- schema:
- oneOf:
- - type: integer
- - type: string
- - name: token_id
- in: path
- description: The ID of the project access token
- required: true
- schema:
- oneOf:
- - type: integer
- - type: string
- responses:
- '400':
- description: Bad Request
- '404':
- description: Not Found
- '204':
- description: No content if successfully revoked
diff --git a/doc/api/openapi/v4/metadata.yaml b/doc/api/openapi/v4/metadata.yaml
deleted file mode 100644
index 6a5ef9f3355..00000000000
--- a/doc/api/openapi/v4/metadata.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-# Markdown documentation: https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/api/metadata.md
-
-get:
- tags:
- - metadata
- summary: "Retrieve metadata information for this GitLab instance."
- operationId: "getMetadata"
- responses:
- "401":
- description: "unauthorized operation"
- "200":
- description: "successful operation"
- content:
- "application/json":
- schema:
- title: "MetadataResponse"
- type: "object"
- properties:
- version:
- type: "string"
- revision:
- type: "string"
- kas:
- type: "object"
- properties:
- enabled:
- type: "boolean"
- externalUrl:
- type: "string"
- nullable: true
- version:
- type: "string"
- nullable: true
- examples:
- Example:
- value:
- version: "15.0-pre"
- revision: "c401a659d0c"
- kas:
- enabled: true
- externalUrl: "grpc://gitlab.example.com:8150"
- version: "15.0.0"
-
diff --git a/doc/api/openapi/v4/version.yaml b/doc/api/openapi/v4/version.yaml
deleted file mode 100644
index 3a689840f4c..00000000000
--- a/doc/api/openapi/v4/version.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-# Markdown documentation: https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/api/version.md
-
-get:
- tags:
- - version
- summary: "Retrieve version information for this GitLab instance."
- operationId: "getVersion"
- responses:
- "401":
- description: "unauthorized operation"
- "200":
- description: "successful operation"
- content:
- "application/json":
- schema:
- title: "VersionResponse"
- type: "object"
- properties:
- version:
- type: "string"
- revision:
- type: "string"
- examples:
- Example:
- value:
- version: "13.3.0-pre"
- revision: "f2b05afebb0"
-
diff --git a/doc/api/packages.md b/doc/api/packages.md
index 4fd21a43a92..ffdd9fe7d11 100644
--- a/doc/api/packages.md
+++ b/doc/api/packages.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/api/packages/composer.md b/doc/api/packages/composer.md
index 913831776d9..e75dbfeb92f 100644
--- a/doc/api/packages/composer.md
+++ b/doc/api/packages/composer.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/api/packages/conan.md b/doc/api/packages/conan.md
index d0077d18c11..c37296ad664 100644
--- a/doc/api/packages/conan.md
+++ b/doc/api/packages/conan.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
@@ -494,7 +494,7 @@ Upload a recipe file to the package registry. You must use an upload URL that th
returned.
```plaintext
-GET packages/conan/v1/files/:package_name/:package_version/:package_username/:package_channel/:recipe_revision/export/:file_name
+PUT packages/conan/v1/files/:package_name/:package_version/:package_username/:package_channel/:recipe_revision/export/:file_name
```
| Attribute | Type | Required | Description |
@@ -509,7 +509,8 @@ GET packages/conan/v1/files/:package_name/:package_version/:package_username/:pa
Provide the file context in the request body:
```shell
-curl --header "Authorization: Bearer <authenticate_token>" \
+curl --request PUT \
+ --user <username>:<personal_access_token> \
--upload-file path/to/conanfile.py \
"https://gitlab.example.com/api/v4/packages/conan/v1/files/my-package/1.0/my-group+my-project/stable/0/export/conanfile.py"
```
@@ -558,7 +559,7 @@ Upload a package file to the package registry. You must use an upload URL that t
returned.
```plaintext
-GET packages/conan/v1/files/:package_name/:package_version/:package_username/:package_channel/:recipe_revision/package/:conan_package_reference/:package_revision/:file_name
+PUT packages/conan/v1/files/:package_name/:package_version/:package_username/:package_channel/:recipe_revision/package/:conan_package_reference/:package_revision/:file_name
```
| Attribute | Type | Required | Description |
@@ -575,9 +576,10 @@ GET packages/conan/v1/files/:package_name/:package_version/:package_username/:pa
Provide the file context in the request body:
```shell
-curl --header "Authorization: Bearer <authenticate_token>" \
+curl --request PUT \
+ --user <username>:<personal_access_token> \
--upload-file path/to/conaninfo.txt \
- "https://gitlab.example.com/api/v4/packages/conan/v1/files/my-package/1.0/my-group+my-project/stable/packages/103f6067a947f366ef91fc1b7da351c588d1827f/0/conaninfo.txt"
+ "https://gitlab.example.com/api/v4/packages/conan/v1/files/my-package/1.0/my-group+my-project/stable/0/package/103f6067a947f366ef91fc1b7da351c588d1827f/0/conaninfo.txt"
```
## Delete a Package (delete a Conan recipe)
diff --git a/doc/api/packages/debian.md b/doc/api/packages/debian.md
index 0e85e554f01..88baf760973 100644
--- a/doc/api/packages/debian.md
+++ b/doc/api/packages/debian.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
@@ -61,8 +61,8 @@ PUT projects/:id/packages/debian/:file_name
```shell
curl --request PUT \
+ --user <username>:<personal_access_token> \
--upload-file path/to/mypkg.deb \
- --header "Private-Token: <personal_access_token>" \
"https://gitlab.example.com/api/v4/projects/1/packages/debian/mypkg.deb"
```
diff --git a/doc/api/packages/debian_group_distributions.md b/doc/api/packages/debian_group_distributions.md
index e3fabd92c51..95f3bae2c1d 100644
--- a/doc/api/packages/debian_group_distributions.md
+++ b/doc/api/packages/debian_group_distributions.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/api/packages/debian_project_distributions.md b/doc/api/packages/debian_project_distributions.md
index f8ad7259866..573f1bffd1a 100644
--- a/doc/api/packages/debian_project_distributions.md
+++ b/doc/api/packages/debian_project_distributions.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/api/packages/go_proxy.md b/doc/api/packages/go_proxy.md
index 3a98c5acd2f..08a7138a82a 100644
--- a/doc/api/packages/go_proxy.md
+++ b/doc/api/packages/go_proxy.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/api/packages/helm.md b/doc/api/packages/helm.md
index b9888f2eed7..0e9a72c2389 100644
--- a/doc/api/packages/helm.md
+++ b/doc/api/packages/helm.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/api/packages/maven.md b/doc/api/packages/maven.md
index 6eb343dc7ab..4086b68b750 100644
--- a/doc/api/packages/maven.md
+++ b/doc/api/packages/maven.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/api/packages/npm.md b/doc/api/packages/npm.md
index a35fe630075..7e8732d9553 100644
--- a/doc/api/packages/npm.md
+++ b/doc/api/packages/npm.md
@@ -1,7 +1,7 @@
---
stage: Package
-group: Package
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.example/handbook/product/ux/technical-writing/#assignments
+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
---
# npm API **(FREE)**
@@ -65,7 +65,7 @@ curl --request PUT
--header "Content-Type: application/json"
--data @./path/to/metadata/file.json
--header "Authorization: Bearer <personal_access_token>" \
- "https://gitlab.example.com/api/v4/projects/1/packages/npm/@myscope/my-pkg"
+ "https://gitlab.example.com/api/v4/projects/1/packages/npm/@myscope%2fmy-pkg"
```
The metadata file content is generated by npm, but looks something like this:
diff --git a/doc/api/packages/nuget.md b/doc/api/packages/nuget.md
index 4c63524291b..ebcb51be447 100644
--- a/doc/api/packages/nuget.md
+++ b/doc/api/packages/nuget.md
@@ -1,7 +1,7 @@
---
stage: Package
-group: Package
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about..example/handbook/product/ux/technical-writing/#assignments
+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
---
# NuGet API **(FREE)**
@@ -97,9 +97,9 @@ PUT projects/:id/packages/nuget
```shell
curl --request PUT \
- --upload-file path/to/mynugetpkg.1.3.0.17.nupkg \
+ --form 'package=@path/to/mynugetpkg.1.3.0.17.nupkg' \
--user <username>:<personal_access_token> \
- "https://gitlab.example.com/api/v4/projects/1/packages/nuget"
+ "https://gitlab.example.com/api/v4/projects/1/packages/nuget/"
```
## Upload a symbol package file
@@ -121,7 +121,7 @@ PUT projects/:id/packages/nuget/symbolpackage
```shell
curl --request PUT \
- --upload-file path/to/mynugetpkg.1.3.0.17.snupkg \
+ --form 'package=@path/to/mynugetpkg.1.3.0.17.snupkg' \
--user <username>:<personal_access_token> \
"https://gitlab.example.com/api/v4/projects/1/packages/nuget/symbolpackage"
```
diff --git a/doc/api/packages/pypi.md b/doc/api/packages/pypi.md
index 061de5bb9dd..4e4c060d99b 100644
--- a/doc/api/packages/pypi.md
+++ b/doc/api/packages/pypi.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
@@ -264,8 +264,10 @@ PUT projects/:id/packages/pypi
| `requires_python` | string | no | The PyPI required version. |
```shell
-curl --request PUT \
- --upload-file path/to/my.pypi.package-0.0.1.tar.gz \
+curl --request POST \
+ --form 'content=@path/to/my.pypi.package-0.0.1.tar.gz' \
+ --form 'name=my.pypi.package'
+ --form 'version=1.3.7'
--user <username>:<personal_access_token> \
"https://gitlab.example.com/api/v4/projects/1/packages/pypi"
```
diff --git a/doc/api/packages/rubygems.md b/doc/api/packages/rubygems.md
index a87df17ab43..c2d05f24085 100644
--- a/doc/api/packages/rubygems.md
+++ b/doc/api/packages/rubygems.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/api/packages/terraform-modules.md b/doc/api/packages/terraform-modules.md
index 4c32e3f7cb4..bb5b39b5161 100644
--- a/doc/api/packages/terraform-modules.md
+++ b/doc/api/packages/terraform-modules.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/api/pipeline_triggers.md b/doc/api/pipeline_triggers.md
index 1fc29d2a654..999b223a934 100644
--- a/doc/api/pipeline_triggers.md
+++ b/doc/api/pipeline_triggers.md
@@ -170,7 +170,7 @@ Supported attributes:
| `id` | integer/string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `ref` | string | **{check-circle}** Yes | The branch or tag to run the pipeline on. |
| `token` | string | **{check-circle}** Yes | The trigger token or CI/CD job token. |
-| `variables` | array | **{dotted-circle}** No | An [array of hashes](index.md#array-of-hashes) containing the variables available in the pipeline, matching the structure `[{ 'key': 'UPLOAD_TO_S3', 'variable_type': 'file', 'value': 'true' }, {'key': 'TEST', 'value': 'test variable'}]`. If `variable_type` is excluded, it defaults to `env_var`. |
+| `variables` | hash | **{dotted-circle}** No | A map of key-valued strings containing the pipeline variables. For example: `{ VAR1: "value1", VAR2: "value2" }`. |
Example request:
diff --git a/doc/api/pipelines.md b/doc/api/pipelines.md
index a44d02982c0..8242f8cff00 100644
--- a/doc/api/pipelines.md
+++ b/doc/api/pipelines.md
@@ -269,6 +269,67 @@ Sample response:
}
```
+## Get the latest pipeline
+
+Get the latest pipeline for a specific ref in a project.
+
+```plaintext
+POST /projects/:id/pipeline/latest
+```
+
+| Attribute | Type | Required | Description |
+|-------------|---------|----------|---------------------|
+| `ref` | string | no | The branch or tag to check for the latest pipeline. Defaults to the default branch when not specified. |
+
+```shell
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/1/pipelines/latest"
+```
+
+Example of response
+
+```json
+{
+ "id": 287,
+ "iid": 144,
+ "project_id": 21,
+ "sha": "50f0acb76a40e34a4ff304f7347dcc6587da8a14",
+ "ref": "main",
+ "status": "success",
+ "source": "push",
+ "created_at": "2022-09-21T01:05:07.200Z",
+ "updated_at": "2022-09-21T01:05:50.185Z",
+ "web_url": "http://127.0.0.1:3000/test-group/test-project/-/pipelines/287",
+ "before_sha": "8a24fb3c5877a6d0b611ca41fc86edc174593e2b",
+ "tag": false,
+ "yaml_errors": null,
+ "user": {
+ "id": 1,
+ "username": "root",
+ "name": "Administrator",
+ "state": "active",
+ "avatar_url": "https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
+ "web_url": "http://127.0.0.1:3000/root"
+ },
+ "started_at": "2022-09-21T01:05:14.197Z",
+ "finished_at": "2022-09-21T01:05:50.175Z",
+ "committed_at": null,
+ "duration": 34,
+ "queued_duration": 6,
+ "coverage": null,
+ "detailed_status": {
+ "icon": "status_success",
+ "text": "passed",
+ "label": "passed",
+ "group": "success",
+ "tooltip": "passed",
+ "has_details": false,
+ "details_path": "/test-group/test-project/-/pipelines/287",
+ "illustration": null,
+ "favicon": "/assets/ci_favicons/favicon_status_success-8451333011eee8ce9f2ab25dc487fe24a8758c694827a582f17f42b0a90446a2.png"
+ }
+}
+```
+
## Create a new pipeline
> `iid` in response [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/342223) in GitLab 14.6.
diff --git a/doc/api/product_analytics.md b/doc/api/product_analytics.md
index 4653a52732a..e10327bc59b 100644
--- a/doc/api/product_analytics.md
+++ b/doc/api/product_analytics.md
@@ -4,7 +4,7 @@ group: Product Analytics
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Product analytics API
+# Product analytics API **(ULTIMATE)**
> Introduced in GitLab 15.4 [with a flag](../administration/feature_flags.md) named `cube_api_proxy`. Disabled by default.
diff --git a/doc/api/project_level_variables.md b/doc/api/project_level_variables.md
index d900e1da78c..c6b56c53413 100644
--- a/doc/api/project_level_variables.md
+++ b/doc/api/project_level_variables.md
@@ -31,6 +31,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
"value": "TEST_1",
"protected": false,
"masked": true,
+ "raw": false,
"environment_scope": "*"
},
{
@@ -39,6 +40,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
"value": "TEST_2",
"protected": false,
"masked": false,
+ "raw": false,
"environment_scope": "*"
}
]
@@ -70,6 +72,7 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
"value": "TEST_1",
"protected": false,
"masked": true,
+ "raw": false,
"environment_scope": "*"
}
```
@@ -92,6 +95,7 @@ POST /projects/:id/variables
| `variable_type` | string | no | The type of a variable. Available types are: `env_var` (default) and `file` |
| `protected` | boolean | no | Whether the variable is protected. Default: `false` |
| `masked` | boolean | no | Whether the variable is masked. Default: `false` |
+| `raw` | boolean | no | Whether the variable is expandable. Default: `false` |
| `environment_scope` | string | no | The `environment_scope` of the variable. Default: `*` |
```shell
@@ -106,6 +110,7 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
"value": "new value",
"protected": false,
"masked": false,
+ "raw": false,
"environment_scope": "*"
}
```
@@ -127,6 +132,7 @@ PUT /projects/:id/variables/:key
| `variable_type` | string | no | The type of a variable. Available types are: `env_var` (default) and `file` |
| `protected` | boolean | no | Whether the variable is protected |
| `masked` | boolean | no | Whether the variable is masked |
+| `raw` | boolean | no | Whether the variable is expandable. Default: `false` |
| `environment_scope` | string | no | The `environment_scope` of the variable |
| `filter` | hash | no | Available filters: `[environment_scope]`. See the [`filter` parameter details](#the-filter-parameter). |
@@ -142,6 +148,7 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" \
"value": "updated value",
"protected": true,
"masked": false,
+ "raw": false,
"environment_scope": "*"
}
```
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 470b3721b23..638af168f22 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -243,6 +243,7 @@ When the user is authenticated and `simple` is not set this returns something li
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
+ "issue_branch_template": "gitlab/%{id}-%{title}",
"auto_devops_enabled": false,
"auto_devops_deploy_strategy": "continuous",
"autoclose_referenced_issues": true,
@@ -421,6 +422,7 @@ GET /users/:user_id/projects
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
+ "issue_branch_template": "gitlab/%{id}-%{title}",
"marked_for_deletion_at": "2020-04-03", // Deprecated and will be removed in API v5 in favor of marked_for_deletion_on
"marked_for_deletion_on": "2020-04-03",
"statistics": {
@@ -544,6 +546,7 @@ GET /users/:user_id/projects
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
+ "issue_branch_template": "gitlab/%{id}-%{title}",
"statistics": {
"commit_count": 12,
"storage_size": 2066080,
@@ -677,6 +680,7 @@ Example response:
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
+ "issue_branch_template": "gitlab/%{id}-%{title}",
"statistics": {
"commit_count": 37,
"storage_size": 1038090,
@@ -793,6 +797,7 @@ Example response:
"suggestion_commit_message": null,
"merge_commit_template": null,
"squash_commit_template": null,
+ "issue_branch_template": "gitlab/%{id}-%{title}",
"statistics": {
"commit_count": 12,
"storage_size": 2066080,
@@ -969,6 +974,7 @@ GET /projects/:id
"enforce_auth_checks_on_uploads": true,
"merge_commit_template": null,
"squash_commit_template": null,
+ "issue_branch_template": "gitlab/%{id}-%{title}",
"marked_for_deletion_at": "2020-04-03", // Deprecated and will be removed in API v5 in favor of marked_for_deletion_on
"marked_for_deletion_on": "2020-04-03",
"compliance_frameworks": [ "sox" ],
@@ -1334,6 +1340,7 @@ POST /projects/user/:user_id
| `shared_runners_enabled` | boolean | **{dotted-circle}** No | Enable shared runners for this project. |
| `snippets_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
| `snippets_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable snippets for this project. Use `snippets_access_level` instead. |
+| `issue_branch_template` | string | **{dotted-circle}** No | Template used to suggest names for [branches created from issues](../user/project/repository/web_editor.md#create-a-new-branch-from-an-issue). _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21243) in GitLab 15.6.)_ |
| `squash_commit_template` | string | **{dotted-circle}** No | [Template](../user/project/merge_requests/commit_templates.md) used to create squash commit message in merge requests. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345275) in GitLab 14.6.)_ |
| `squash_option` | string | **{dotted-circle}** No | One of `never`, `always`, `default_on`, or `default_off`. |
| `suggestion_commit_message` | string | **{dotted-circle}** No | The commit message used to apply merge request [suggestions](../user/project/merge_requests/reviews/suggestions.md). |
@@ -1385,7 +1392,7 @@ Supported attributes:
| `builds_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
| `ci_config_path` | string | **{dotted-circle}** No | The path to CI configuration file. |
| `ci_default_git_depth` | integer | **{dotted-circle}** No | Default number of revisions for [shallow cloning](../ci/pipelines/settings.md#limit-the-number-of-changes-fetched-during-clone). |
-| `ci_forward_deployment_enabled` | boolean | **{dotted-circle}** No | When a new deployment job starts, [skip older deployment jobs](../ci/pipelines/settings.md#skip-outdated-deployment-jobs) that are still pending |
+| `ci_forward_deployment_enabled` | boolean | **{dotted-circle}** No | Enable or disable [prevent outdated deployment jobs](../ci/pipelines/settings.md#prevent-outdated-deployment-jobs). |
| `ci_allow_fork_pipelines_to_run_in_parent_project` | boolean | **{dotted-circle}** No | Enable or disable [running pipelines in the parent project for merge requests from forks](../ci/pipelines/merge_request_pipelines.md#run-pipelines-in-the-parent-project). _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325189) in GitLab 15.3.)_ |
| `ci_separated_caches` | boolean | **{dotted-circle}** No | Set whether or not caches should be [separated](../ci/caching/index.md#cache-key-names) by branch protection status. |
| `container_expiration_policy_attributes` | hash | **{dotted-circle}** No | Update the image cleanup policy for this project. Accepts: `cadence` (string), `keep_n` (integer), `older_than` (string), `name_regex` (string), `name_regex_delete` (string), `name_regex_keep` (string), `enabled` (boolean). |
@@ -1439,6 +1446,7 @@ Supported attributes:
| `shared_runners_enabled` | boolean | **{dotted-circle}** No | Enable shared runners for this project. |
| `snippets_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
| `snippets_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable snippets for this project. Use `snippets_access_level` instead. |
+| `issue_branch_template` | string | **{dotted-circle}** No | Template used to suggest names for [branches created from issues](../user/project/repository/web_editor.md#create-a-new-branch-from-an-issue). _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21243) in GitLab 15.6.)_ |
| `squash_commit_template` | string | **{dotted-circle}** No | [Template](../user/project/merge_requests/commit_templates.md) used to create squash commit message in merge requests. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345275) in GitLab 14.6.)_ |
| `squash_option` | string | **{dotted-circle}** No | One of `never`, `always`, `default_on`, or `default_off`. |
| `suggestion_commit_message` | string | **{dotted-circle}** No | The commit message used to apply merge request suggestions. |
@@ -2830,6 +2838,42 @@ Read more in the [Project members](members.md) documentation.
Read more in the [Project vulnerabilities](project_vulnerabilities.md) documentation.
+## Get a project's pull mirror details **(PREMIUM)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/354506) in GitLab 15.5.
+
+Returns the details of the project's pull mirror.
+
+```plaintext
+GET /projects/:id/mirror/pull
+```
+
+Supported attributes:
+
+| Attribute | Type | Required | Description |
+|:----------|:------|:------------|:------------|
+| `id` | integer or string | **{check-circle}** Yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). |
+
+Example request:
+
+```shell
+curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/:id/mirror/pull"
+```
+
+Example response:
+
+```json
+{
+ "id": 101486,
+ "last_error": null,
+ "last_successful_update_at": "2020-01-06T17:32:02.823Z",
+ "last_update_at": "2020-01-06T17:32:02.823Z",
+ "last_update_started_at": "2020-01-06T17:31:55.864Z",
+ "update_status": "finished",
+ "url": "https://*****:*****@gitlab.com/gitlab-org/security/gitlab.git"
+}
+```
+
## Configure pull mirroring for a project **(PREMIUM)**
> Moved to GitLab Premium in 13.9.
diff --git a/doc/api/protected_branches.md b/doc/api/protected_branches.md
index 620cb0e0bae..96bd5c15f13 100644
--- a/doc/api/protected_branches.md
+++ b/doc/api/protected_branches.md
@@ -43,12 +43,14 @@ Example response:
"name": "master",
"push_access_levels": [
{
+ "id": 1,
"access_level": 40,
"access_level_description": "Maintainers"
}
],
"merge_access_levels": [
{
+ "id": 1,
"access_level": 40,
"access_level_description": "Maintainers"
}
@@ -61,12 +63,14 @@ Example response:
"name": "release/*",
"push_access_levels": [
{
+ "id": 1,
"access_level": 40,
"access_level_description": "Maintainers"
}
],
"merge_access_levels": [
{
+ "id": 1,
"access_level": 40,
"access_level_description": "Maintainers"
}
@@ -90,6 +94,7 @@ Example response:
"name": "master",
"push_access_levels": [
{
+ "id": 1,
"access_level": 40,
"user_id": null,
"group_id": null,
@@ -98,6 +103,7 @@ Example response:
],
"merge_access_levels": [
{
+ "id": 1,
"access_level": null,
"user_id": null,
"group_id": 1234,
@@ -136,12 +142,14 @@ Example response:
"name": "master",
"push_access_levels": [
{
+ "id": 1,
"access_level": 40,
"access_level_description": "Maintainers"
}
],
"merge_access_levels": [
{
+ "id": 1,
"access_level": 40,
"access_level_description": "Maintainers"
}
@@ -162,6 +170,7 @@ Example response:
"name": "master",
"push_access_levels": [
{
+ "id": 1,
"access_level": 40,
"user_id": null,
"group_id": null,
@@ -170,6 +179,7 @@ Example response:
],
"merge_access_levels": [
{
+ "id": 1,
"access_level": null,
"user_id": null,
"group_id": 1234,
@@ -215,18 +225,21 @@ Example response:
"name": "*-stable",
"push_access_levels": [
{
+ "id": 1,
"access_level": 30,
"access_level_description": "Developers + Maintainers"
}
],
"merge_access_levels": [
{
+ "id": 1,
"access_level": 30,
"access_level_description": "Developers + Maintainers"
}
],
"unprotect_access_levels": [
{
+ "id": 1,
"access_level": 40,
"access_level_description": "Maintainers"
}
@@ -247,6 +260,7 @@ Example response:
"name": "*-stable",
"push_access_levels": [
{
+ "id": 1,
"access_level": 30,
"user_id": null,
"group_id": null,
@@ -255,6 +269,7 @@ Example response:
],
"merge_access_levels": [
{
+ "id": 1,
"access_level": 30,
"user_id": null,
"group_id": null,
@@ -263,6 +278,7 @@ Example response:
],
"unprotect_access_levels": [
{
+ "id": 1,
"access_level": 40,
"user_id": null,
"group_id": null,
@@ -291,6 +307,7 @@ Example response:
"name": "*-stable",
"push_access_levels": [
{
+ "id": 1,
"access_level": null,
"user_id": 1,
"group_id": null,
@@ -299,6 +316,7 @@ Example response:
],
"merge_access_levels": [
{
+ "id": 1,
"access_level": 40,
"user_id": null,
"group_id": null,
@@ -307,6 +325,7 @@ Example response:
],
"unprotect_access_levels": [
{
+ "id": 1,
"access_level": 40,
"user_id": null,
"group_id": null,
@@ -348,6 +367,7 @@ Example response:
"name": "master",
"push_access_levels": [
{
+ "id": 1,
"access_level": 30,
"access_level_description": "Developers + Maintainers",
"user_id": null,
@@ -356,12 +376,14 @@ Example response:
],
"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,
@@ -370,6 +392,7 @@ Example response:
],
"unprotect_access_levels": [
{
+ "id": 1,
"access_level": 40,
"access_level_description": "Maintainers",
"user_id": null,
@@ -398,20 +421,107 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
| `name` | string | yes | The name of the branch |
-## Require code owner approvals for a single branch **(PREMIUM)**
+## Update a protected branch
-Update the "code owner approval required" option for the given protected branch.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101903) in GitLab 15.6.
+
+Updates a protected branch.
```plaintext
PATCH /projects/:id/protected_branches/:name
```
```shell
-curl --request PATCH --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/protected_branches/feature-branch?code_owner_approval_required=true"
+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](index.md#namespaced-path-encoding) owned by the authenticated user |
-| `name` | string | yes | The name of the branch |
-| `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). (defaults: false)|
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](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. |
+| `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
+`{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 '{"push_access_levels": [{"group_id": 9899829, access_level: 40}]}' \
+ --header "PRIVATE-TOKEN: <your_access_token>" \
+ "https://gitlab.example.com/api/v4/projects/22034114/protected_branches/master"
+```
+
+Example response:
+
+```json
+{
+ "name": "master",
+ "allowed_to_push": [
+ {
+ "id": 12,
+ "access_level": 40,
+ "access_level_description": "Administrator",
+ "user_id": null,
+ "group_id": 9899829
+ }
+ ]
+}
+```
+
+### Example: update a `push_access_level` record
+
+```shell
+curl --header 'Content-Type: application/json' --request PUT \
+ --data '{"push_access_levels": [{"id": 12, "group_id": 22034120}]' \
+ --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/22034114/protected_branches/master"
+```
+
+```json
+{
+ "name": "master",
+ "deploy_access_levels": [
+ {
+ "id": 12,
+ "access_level": 40,
+ "access_level_description": "Administrator",
+ "user_id": null,
+ "group_id": 22034120
+ }
+ ]
+}
+```
+
+### Example: delete a `push_access_level` record
+
+```shell
+curl --header 'Content-Type: application/json' --request PUT \
+ --data '{"push_access_levels": [{"id": 12, "_destroy": true}]' \
+ --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/22034114/protected_branches/master"
+```
+
+Example response:
+
+```json
+{
+ "name": "master",
+ "push_access_levels": []
+}
+```
diff --git a/doc/api/protected_environments.md b/doc/api/protected_environments.md
index 9ff3c34d2d7..ec0657148da 100644
--- a/doc/api/protected_environments.md
+++ b/doc/api/protected_environments.md
@@ -103,7 +103,7 @@ Example response:
}
```
-## Protect repository environments
+## Protect a single environment
Protects a single environment:
@@ -343,7 +343,7 @@ Example response:
}
```
-## Unprotect environment
+## Unprotect a single environment
Unprotects the given protected environment:
diff --git a/doc/api/protected_tags.md b/doc/api/protected_tags.md
index c8e7117e5a9..88b868a3965 100644
--- a/doc/api/protected_tags.md
+++ b/doc/api/protected_tags.md
@@ -41,6 +41,7 @@ Example response:
"name": "release-1-0",
"create_access_levels": [
{
+ "id":1,
"access_level": 40,
"access_level_description": "Maintainers"
}
@@ -75,6 +76,7 @@ Example response:
"name": "release-1-0",
"create_access_levels": [
{
+ "id": 1,
"access_level": 40,
"access_level_description": "Maintainers"
}
@@ -109,6 +111,7 @@ Example response:
"name": "*-stable",
"create_access_levels": [
{
+ "id": 1,
"access_level": 30,
"access_level_description": "Developers + Maintainers"
}
diff --git a/doc/api/releases/index.md b/doc/api/releases/index.md
index e3b1d9230f6..66d5775f499 100644
--- a/doc/api/releases/index.md
+++ b/doc/api/releases/index.md
@@ -28,7 +28,7 @@ For authentication, the Releases API accepts either:
> [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72448) to allow for `JOB-TOKEN` in GitLab 14.5.
-Paginated list of Releases, sorted by `released_at`.
+Returns a paginated list of releases, sorted by `released_at`.
```plaintext
GET /projects/:id/releases
@@ -235,7 +235,7 @@ Example response:
> [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72448) to allow for `JOB-TOKEN` in GitLab 14.5.
-Get a Release for the given tag.
+Gets a release for the given tag.
```plaintext
GET /projects/:id/releases/:tag_name
@@ -364,9 +364,62 @@ Example response:
}
```
+## Download a release asset
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/358188) in GitLab 15.4.
+
+Download a release asset file by making a request with the following format:
+
+```plaintext
+GET /projects/:id/releases/:tag_name/downloads/:filepath
+```
+
+| Attribute | Type | Required | Description |
+|----------------------------| -------------- | -------- | ----------------------------------------------------------------------------------- |
+| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../index.md#namespaced-path-encoding). |
+| `tag_name` | string | yes | The Git tag the release is associated with. |
+| `filepath` | string | yes | Path to the release asset file as specified when [creating](links.md#create-a-release-link) or [updating](links.md#update-a-release-link) its link. |
+
+Example request:
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/24/releases/v0.1/downloads/bin/asset.exe"
+```
+
+### Get the latest release
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/358188) in GitLab 15.4.
+
+Latest release information is accessible through a permanent API URL.
+
+The format of the URL is:
+
+```plaintext
+GET /projects/:id/releases/permalink/latest
+```
+
+To call any other GET API that requires a release tag, append a suffix to the `permalink/latest` API path.
+
+For example, to get latest [release evidence](#collect-release-evidence) you can use:
+
+```plaintext
+GET /projects/:id/releases/permalink/latest/evidence
+```
+
+Another example is [downloading an asset](#download-a-release-asset) of the latest release, for which you can use:
+
+```plaintext
+GET /projects/:id/releases/permalink/latest/downloads/bin/asset.exe
+```
+
+#### Sorting preferences
+
+By default, GitLab fetches the release using `released_at` time. The use of the query parameter
+`?order_by=released_at` is optional, and support for `?order_by=semver` is tracked [in issue 352945](https://gitlab.com/gitlab-org/gitlab/-/issues/352945).
+
## Create a release
-Create a release. Developer level access to the project is required to create a release.
+Creates a release. Developer level access to the project is required to create a release.
```plaintext
POST /projects/:id/releases
@@ -516,7 +569,7 @@ adding milestones for ancestor groups raises an error.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/199065) in GitLab 12.10.
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72448) to allow for `JOB-TOKEN` in GitLab 14.5.
-Create Evidence for an existing Release.
+Creates an evidence for an existing release.
```plaintext
POST /projects/:id/releases/:tag_name/evidence
@@ -543,7 +596,7 @@ Example response:
> [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72448) to allow for `JOB-TOKEN` in GitLab 14.5.
-Update a release. Developer level access to the project is required to update a release.
+Updates a release. Developer level access to the project is required to update a release.
```plaintext
PUT /projects/:id/releases/:tag_name
@@ -652,7 +705,7 @@ Example response:
> [Changed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72448) to allow for `JOB-TOKEN` in GitLab 14.5.
-Delete a release. Deleting a release doesn't delete the associated tag. Maintainer level access to the project is required to delete a release.
+Deletes a release. Deleting a release doesn't delete the associated tag. Maintainer level access to the project is required to delete a release.
```plaintext
DELETE /projects/:id/releases/:tag_name
diff --git a/doc/api/releases/links.md b/doc/api/releases/links.md
index 050d7cabdf9..732f5ea57ef 100644
--- a/doc/api/releases/links.md
+++ b/doc/api/releases/links.md
@@ -13,9 +13,9 @@ links. For manipulating other Release assets, see [Release API](index.md).
GitLab supports links to `http`, `https`, and `ftp` assets.
-## Get links
+## List links of a release
-Get assets as links from a Release.
+Get assets as links from a release.
```plaintext
GET /projects/:id/releases/:tag_name/assets/links
@@ -53,9 +53,9 @@ Example response:
]
```
-## Get a link
+## Get a release link
-Get an asset as a link from a Release.
+Get an asset as a link from a release.
```plaintext
GET /projects/:id/releases/:tag_name/assets/links/:link_id
@@ -85,9 +85,9 @@ Example response:
}
```
-## Create a link
+## Create a release link
-Create an asset as a link from a Release.
+Creates an asset as a link from a release.
```plaintext
POST /projects/:id/releases/:tag_name/assets/links
@@ -126,9 +126,9 @@ Example response:
}
```
-## Update a link
+## Update a release link
-Update an asset as a link from a Release.
+Updates an asset as a link from a release.
```plaintext
PUT /projects/:id/releases/:tag_name/assets/links/:link_id
@@ -167,9 +167,9 @@ Example response:
}
```
-## Delete a link
+## Delete a release link
-Delete an asset as a link from a Release.
+Deletes an asset as a link from a release.
```plaintext
DELETE /projects/:id/releases/:tag_name/assets/links/:link_id
diff --git a/doc/api/remote_mirrors.md b/doc/api/remote_mirrors.md
index 1013ffb49fb..bd59aa64e45 100644
--- a/doc/api/remote_mirrors.md
+++ b/doc/api/remote_mirrors.md
@@ -8,15 +8,15 @@ type: reference, api
# Project remote mirrors API **(FREE)**
[Push mirrors](../user/project/repository/mirror/push.md)
-defined on a project's repository settings are called "remote mirrors", and the
-state of these mirrors can be queried and modified via the remote mirror API
-outlined below.
+defined on a project's repository settings are called "remote mirrors". You
+can query and modify the state of these mirrors with the remote mirror API.
-## List a project's remote mirrors
+For security reasons, the `url` attribute in the API response is always scrubbed of username
+and password information.
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/38121) in GitLab 12.9.
+## List a project's remote mirrors
-Returns an Array of remote mirrors and their statuses:
+Returns an array of remote mirrors and their statuses:
```plaintext
GET /projects/:id/remote_mirrors
@@ -47,10 +47,6 @@ Example response:
]
```
-NOTE:
-For security reasons, the `url` attribute is always scrubbed of username
-and password information.
-
## Get a single project's remote mirror
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82770) in GitLab 14.10.
@@ -84,19 +80,14 @@ Example response:
}
```
-NOTE:
-For security reasons, the `url` attribute is always scrubbed of username
-and password information.
-
## Create a pull mirror
Learn how to [configure a pull mirror](projects.md#configure-pull-mirroring-for-a-project) using the Projects API.
## Create a push mirror
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24189) in GitLab 12.9.
-
-Push mirroring is disabled by default. You can enable it by including the optional parameter `enabled` when creating it:
+Push mirroring is disabled by default. To enable it, include the optional parameter
+`enabled` when you create the mirror:
```plaintext
POST /projects/:id/remote_mirrors
@@ -106,8 +97,8 @@ POST /projects/:id/remote_mirrors
| :---------- | :----- | :--------- | :------------ |
| `url` | String | yes | The target URL to which the repository is mirrored. |
| `enabled` | Boolean | no | Determines if the mirror is enabled. |
-| `only_protected_branches` | Boolean | no | Determines if only protected branches are mirrored. |
| `keep_divergent_refs` | Boolean | no | Determines if divergent refs are skipped. |
+| `only_protected_branches` | Boolean | no | Determines if only protected branches are mirrored. |
Example request:
@@ -135,8 +126,6 @@ Example response:
## Update a remote mirror's attributes
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/38121) in GitLab 12.9.
-
Toggle a remote mirror on or off, or change which types of branches are
mirrored:
@@ -148,8 +137,8 @@ PUT /projects/:id/remote_mirrors/:mirror_id
| :---------- | :----- | :--------- | :------------ |
| `mirror_id` | Integer | yes | The remote mirror ID. |
| `enabled` | Boolean | no | Determines if the mirror is enabled. |
-| `only_protected_branches` | Boolean | no | Determines if only protected branches are mirrored. |
| `keep_divergent_refs` | Boolean | no | Determines if divergent refs are skipped. |
+| `only_protected_branches` | Boolean | no | Determines if only protected branches are mirrored. |
Example request:
diff --git a/doc/api/repositories.md b/doc/api/repositories.md
index 751bbd75c7a..428a09f1bbe 100644
--- a/doc/api/repositories.md
+++ b/doc/api/repositories.md
@@ -223,7 +223,7 @@ Example response:
}],
"compare_timeout": false,
"compare_same_ref": false,
- "web_url": "https://gitlab.example.com/thedude/gitlab-foss/-/compare/ae73cb07c9eeaf35924a10f713b364d32b2dd34f...0b4bc9a49b562e85de7cc9e834518ea6828729b9"
+ "web_url": "https://gitlab.example.com/janedoe/gitlab-foss/-/compare/ae73cb07c9eeaf35924a10f713b364d32b2dd34f...0b4bc9a49b562e85de7cc9e834518ea6828729b9"
}
```
diff --git a/doc/api/repository_files.md b/doc/api/repository_files.md
index 9f06467964b..1db614fce36 100644
--- a/doc/api/repository_files.md
+++ b/doc/api/repository_files.md
@@ -18,14 +18,14 @@ in the following table.
| Scope | Description |
| ----- | ----------- |
-| `read_repository` | Allows read-access to the repository files. |
| `api` | Allows read-write access to the repository files. |
+| `read_repository` | Allows read-access to the repository files. |
## Get file from repository
> The `execute_filemode` field in the response was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83499) in GitLab 14.10.
-Allows you to receive information about file in repository like name, size,
+Allows you to receive information about file in repository like name, size, and
content. File content is Base64 encoded. This endpoint can be accessed
without authentication if the repository is publicly accessible.
@@ -37,11 +37,11 @@ GET /projects/:id/repository/files/:file_path
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb?ref=master"
```
-| Attribute | Type | Required | Description |
-|-------------|----------------|----------|-----------------------------------------------------------------------------------------------------------------|
-| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
-| `file_path` | string | yes | URL encoded full path to new file. Ex. `lib%2Fclass%2Erb`. |
-| `ref` | string | yes | The name of branch, tag or commit |
+| Attribute | Type | Required | Description |
+|-------------|----------------|----------|-------------|
+| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
+| `file_path` | string | yes | URL encoded full path to new file, such as `lib%2Fclass%2Erb`. |
+| `ref` | string | yes | The name of branch, tag or commit. |
Example response:
@@ -62,7 +62,8 @@ Example response:
```
NOTE:
-`blob_id` is the blob SHA, see [repositories - Get a blob from repository](repositories.md#get-a-blob-from-repository)
+`blob_id` is the blob SHA. Refer to [Get a blob from repository](repositories.md#get-a-blob-from-repository)
+in the Repositories API.
In addition to the `GET` method, you can also use `HEAD` to get just file metadata.
@@ -100,14 +101,14 @@ Allows you to receive blame information. Each blame range contains lines and cor
GET /projects/:id/repository/files/:file_path/blame
```
-| Attribute | Type | Required | Description |
-|-----------------|-------------------|----------|--------------------------------------------------------------------------------------------------------------|
-| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
-| `file_path` | string | yes | URL encoded full path to new file. Ex. `lib%2Fclass%2Erb`. |
-| `ref` | string | yes | The name of branch, tag or commit |
-| `range` | hash | no | Blame range |
-| `range[start]` | integer | yes | The first line of the range to blame |
-| `range[end]` | integer | yes | The last line of the range to blame |
+| Attribute | Type | Required | Description |
+|-----------------|-------------------|----------|-------------|
+| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
+| `file_path` | string | yes | URL-encoded full path to new file, such as`lib%2Fclass%2Erb`. |
+| `ref` | string | yes | The name of branch, tag or commit. |
+| `range[end]` | integer | yes | The last line of the range to blame. |
+| `range[start]` | integer | yes | The first line of the range to blame. |
+| `range` | hash | no | Blame range. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/path%2Fto%2Ffile.rb/blame?ref=master"
@@ -142,7 +143,7 @@ Example response:
```
NOTE:
-`HEAD` method return just file metadata as in [Get file from repository](repository_files.md#get-file-from-repository).
+`HEAD` method returns just file metadata, as in [Get file from repository](repository_files.md#get-file-from-repository).
```shell
curl --head --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/path%2Fto%2Ffile.rb/blame?ref=master"
@@ -168,7 +169,8 @@ X-Gitlab-Execute-Filemode: false
### Examples
-To request a blame range, specify `range[start]` and `range[end]` parameters with the start and end line numbers of the file.
+To request a blame range, specify `range[start]` and `range[end]` parameters with
+the starting and ending line numbers of the file.
```shell
curl --head --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/path%2Fto%2Ffile.rb/blame?ref=master&range[start]=1&range[end]=2"
@@ -207,24 +209,25 @@ Example response:
GET /projects/:id/repository/files/:file_path/raw
```
-| Attribute | Type | Required | Description |
-|-------------|----------------|----------|-----------------------------------------------------------------------------------------------------------------|
-| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
-| `file_path` | string | yes | URL encoded full path to new file. Ex. `lib%2Fclass%2Erb`. |
-| `ref` | string | yes | The name of branch, tag or commit. Default is the `HEAD` of the project. |
+| Attribute | Type | Required | Description |
+|-------------|----------------|----------|------------|
+| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
+| `file_path` | string | yes | URL-encoded full path to new file, such as `lib%2Fclass%2Erb`. |
+| `ref` | string | yes | The name of branch, tag or commit. Default is the `HEAD` of the project. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/13083/repository/files/app%2Fmodels%2Fkey%2Erb/raw?ref=master"
```
NOTE:
-Like [Get file from repository](repository_files.md#get-file-from-repository) you can use `HEAD` to get just file metadata.
+Like [Get file from repository](repository_files.md#get-file-from-repository), you can use `HEAD` to get just file metadata.
## Create new file in repository
> The `execute_filemode` parameter was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83499) in GitLab 14.10.
-This allows you to create a single file. For creating multiple files with a single request see the [commits API](commits.md#create-a-commit-with-multiple-files-and-actions).
+Allows you to create a single file. For creating multiple files with a single request,
+refer to the [commits API](commits.md#create-a-commit-with-multiple-files-and-actions).
```plaintext
POST /projects/:id/repository/files/:file_path
@@ -232,16 +235,16 @@ POST /projects/:id/repository/files/:file_path
| Attribute | Type | Required | Description |
| ---------------- | -------------- | -------- | ----------- |
-| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `file_path` | string | yes | URL-encoded full path to new file. For example: `lib%2Fclass%2Erb`. |
| `branch` | string | yes | Name of the new branch to create. The commit is added to this branch. |
-| `start_branch` | string | no | Name of the base branch to create the new branch from. |
-| `encoding` | string | no | Change encoding to `base64`. Default is `text`. |
+| `commit_message` | string | yes | The commit message. |
+| `content` | string | yes | The file's content. |
+| `file_path` | string | yes | URL-encoded full path to new file. For example: `lib%2Fclass%2Erb`. |
+| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `author_email` | string | no | The commit author's email address. |
| `author_name` | string | no | The commit author's name. |
-| `content` | string | yes | The file's content. |
-| `commit_message` | string | yes | The commit message. |
+| `encoding` | string | no | Change encoding to `base64`. Default is `text`. |
| `execute_filemode` | boolean | no | Enables or disables the `execute` flag on the file. Can be `true` or `false`. |
+| `start_branch` | string | no | Name of the base branch to create the new branch from. |
```shell
curl --request POST --header 'PRIVATE-TOKEN: <your_access_token>' \
@@ -264,7 +267,8 @@ Example response:
> The `execute_filemode` parameter was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83499) in GitLab 14.10.
-This allows you to update a single file. For updating multiple files with a single request see the [commits API](commits.md#create-a-commit-with-multiple-files-and-actions).
+Allows you to update a single file. For updating multiple files with a single request,
+refer to the [commits API](commits.md#create-a-commit-with-multiple-files-and-actions).
```plaintext
PUT /projects/:id/repository/files/:file_path
@@ -272,17 +276,17 @@ PUT /projects/:id/repository/files/:file_path
| Attribute | Type | Required | Description |
| ---------------- | -------------- | -------- | ----------- |
-| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
-| `file_path` | string | yes | URL-encoded full path to new file. For example: `lib%2Fclass%2Erb`. |
| `branch` | string | yes | Name of the new branch to create. The commit is added to this branch. |
-| `start_branch` | string | no | Name of the base branch to create the new branch from. |
-| `encoding` | string | no | Change encoding to `base64`. Default is `text`. |
+| `commit_message` | string | yes | The commit message. |
+| `content` | string | yes | The file's content. |
+| `file_path` | string | yes | URL-encoded full path to new file. For example: `lib%2Fclass%2Erb`. |
+| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
| `author_email` | string | no | The commit author's email address. |
| `author_name` | string | no | The commit author's name. |
-| `content` | string | yes | The file's content. |
-| `commit_message` | string | yes | The commit message. |
-| `last_commit_id` | string | no | Last known file commit ID. |
+| `encoding` | string | no | Change encoding to `base64`. Default is `text`. |
| `execute_filemode` | boolean | no | Enables or disables the `execute` flag on the file. Can be `true` or `false`. |
+| `last_commit_id` | string | no | Last known file commit ID. |
+| `start_branch` | string | no | Name of the base branch to create the new branch from. |
```shell
curl --request PUT --header 'PRIVATE-TOKEN: <your_access_token>' \
@@ -301,19 +305,19 @@ Example response:
}
```
-If the commit fails for any reason we return a 400 error with a non-specific
+If the commit fails for any reason we return a `400 Bad Request` error with a non-specific
error message. Possible causes for a failed commit include:
-- the `file_path` contained `/../` (attempted directory traversal);
-- the new file contents were identical to the current file contents. That is, the
- user tried to make an empty commit;
-- the branch was updated by a Git push while the file edit was in progress.
+- The `file_path` contained `/../` (attempted directory traversal).
+- The commit was empty: new file contents were identical to the current file contents.
+- The branch was updated by `git push` while the file edit was in progress.
-GitLab Shell has a boolean return code, preventing GitLab from specifying the error.
+[GitLab Shell](https://gitlab.com/gitlab-org/gitlab-shell/) has a boolean return code, preventing GitLab from specifying the error.
## Delete existing file in repository
-This allows you to delete a single file. For deleting multiple files with a single request, see the [commits API](commits.md#create-a-commit-with-multiple-files-and-actions).
+This allows you to delete a single file. For deleting multiple files with a single request,
+refer to the [commits API](commits.md#create-a-commit-with-multiple-files-and-actions).
```plaintext
DELETE /projects/:id/repository/files/:file_path
@@ -321,14 +325,14 @@ DELETE /projects/:id/repository/files/:file_path
| Attribute | Type | Required | Description |
| ---------------- | -------------- | -------- | ----------- |
-| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
-| `file_path` | string | yes | URL-encoded full path to new file. For example: `lib%2Fclass%2Erb`. |
| `branch` | string | yes | Name of the new branch to create. The commit is added to this branch. |
-| `start_branch` | string | no | Name of the base branch to create the new branch from. |
+| `commit_message` | string | yes | The commit message. |
+| `file_path` | string | yes | URL-encoded full path to new file. For example: `lib%2Fclass%2Erb`. |
+| `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user. |
| `author_email` | string | no | The commit author's email address. |
| `author_name` | string | no | The commit author's name. |
-| `commit_message` | string | yes | The commit message. |
| `last_commit_id` | string | no | Last known file commit ID. |
+| `start_branch` | string | no | Name of the base branch to create the new branch from. |
```shell
curl --request DELETE --header 'PRIVATE-TOKEN: <your_access_token>' \
diff --git a/doc/api/runners.md b/doc/api/runners.md
index 657eb4d470c..f690e0cb9c1 100644
--- a/doc/api/runners.md
+++ b/doc/api/runners.md
@@ -15,7 +15,7 @@ There are two tokens to take into account when connecting a runner with GitLab.
| Token | Description |
| ----- | ----------- |
| Registration token | Token used to [register the runner](https://docs.gitlab.com/runner/register/). It can be [obtained through GitLab](../ci/runners/index.md). |
-| Authentication token | Token used to authenticate the runner with the GitLab instance. It is obtained automatically when you [register a runner](https://docs.gitlab.com/runner/register/) or by the Runner API when you manually [register a runner](#register-a-new-runner) or [reset the authentication token](#reset-runners-authentication-token-by-using-the-runner-id). |
+| Authentication token | Token used to authenticate the runner with the GitLab instance. It is obtained automatically when you [register a runner](https://docs.gitlab.com/runner/register/) or by the Runner API when you manually [register a runner](#register-a-new-runner-deprecated) or [reset the authentication token](#reset-runners-authentication-token-by-using-the-runner-id). |
Here's an example of how the two tokens are used in runner registration:
@@ -46,11 +46,11 @@ GET /runners?tag_list=tag1,tag2
| Attribute | Type | Required | Description |
|------------|--------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of specific runners to show, one of: `active`, `paused`, `online` and `offline`; showing all runners if none provided |
-| `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` |
-| `status` | string | no | The status of runners to show, one of: `online`, `offline`, `stale`, and `never_contacted`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 |
+| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of specific runners to return, one of: `active`, `paused`, `online` and `offline`; showing all runners if none provided |
+| `type` | string | no | The type of runners to return, one of: `instance_type`, `group_type`, `project_type` |
+| `status` | string | no | The status of runners to return, one of: `online`, `offline`, `stale`, and `never_contacted`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 |
| `paused` | boolean | no | Whether to include only runners that are accepting or ignoring new jobs |
-| `tag_list` | string array | no | List of the runner's tags |
+| `tag_list` | string array | no | A list of runner tags |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners"
@@ -111,11 +111,11 @@ GET /runners/all?tag_list=tag1,tag2
| Attribute | Type | Required | Description |
|------------|--------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of runners to show, one of: `specific`, `shared`, `active`, `paused`, `online` and `offline`; showing all runners if none provided |
-| `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` |
-| `status` | string | no | The status of runners to show, one of: `online`, `offline`, `stale`, and `never_contacted`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 |
+| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of runners to return, one of: `specific`, `shared`, `active`, `paused`, `online` and `offline`; showing all runners if none provided |
+| `type` | string | no | The type of runners to return, one of: `instance_type`, `group_type`, `project_type` |
+| `status` | string | no | The status of runners to return, one of: `online`, `offline`, `stale`, and `never_contacted`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 |
| `paused` | boolean | no | Whether to include only runners that are accepting or ignoring new jobs |
-| `tag_list` | string array | no | List of the runner's tags |
+| `tag_list` | string array | no | A list of runner tags |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners/all"
@@ -260,17 +260,17 @@ Update details of a runner.
PUT /runners/:id
```
-| Attribute | Type | Required | Description |
-|-------------------|---------|----------|--------------------------------------------------------------------------------------------------|
-| `id` | integer | yes | The ID of a runner |
-| `description` | string | no | The description of a runner |
-| `active` | boolean | no | Deprecated: Use `:paused` instead. Flag indicating whether the runner is allowed to receive jobs |
-| `paused` | boolean | no | Flag indicating whether the runner should ignore new jobs |
-| `tag_list` | array | no | The list of tags for a runner; put array of tags, that should be finally assigned to a runner |
-| `run_untagged` | boolean | no | Flag indicating the runner can execute untagged jobs |
-| `locked` | boolean | no | Flag indicating the runner is locked |
-| `access_level` | string | no | The access_level of the runner; `not_protected` or `ref_protected` |
-| `maximum_timeout` | integer | no | Maximum timeout set when this runner handles the job |
+| Attribute | Type | Required | Description |
+|-------------------|---------|----------|-------------------------------------------------------------------------------------------------|
+| `id` | integer | yes | The ID of a runner |
+| `description` | string | no | The description of the runner |
+| `active` | boolean | no | Deprecated: Use `paused` instead. Flag indicating whether the runner is allowed to receive jobs |
+| `paused` | boolean | no | Specifies whether the runner should ignore new jobs |
+| `tag_list` | array | no | The list of tags for the runner |
+| `run_untagged` | boolean | no | Specifies whether the runner can execute untagged jobs |
+| `locked` | boolean | no | Specifies whether the runner is locked |
+| `access_level` | string | no | The access level of the runner; `not_protected` or `ref_protected` |
+| `maximum_timeout` | integer | no | Maximum timeout that limits the amount of time (in seconds) that runners can run jobs |
```shell
curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/runners/6" \
@@ -370,7 +370,7 @@ GET /runners/:id/jobs
|-----------|---------|----------|---------------------|
| `id` | integer | yes | The ID of a runner |
| `status` | string | no | Status of the job; one of: `running`, `success`, `failed`, `canceled` |
-| `order_by`| string | no | Order jobs by `id`. |
+| `order_by`| string | no | Order jobs by `id` |
| `sort` | string | no | Sort jobs in `asc` or `desc` order (default: `desc`). Specify `order_by` as well, including for `id`. |
```shell
@@ -463,11 +463,11 @@ GET /projects/:id/runners?tag_list=tag1,tag2
| Attribute | Type | Required | Description |
|------------|----------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding) owned by the authenticated user |
-| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of specific runners to show, one of: `active`, `paused`, `online` and `offline`; showing all runners if none provided |
-| `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type` |
-| `status` | string | no | The status of runners to show, one of: `online`, `offline`, `stale`, and `never_contacted`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 |
+| `scope` | string | no | Deprecated: Use `type` or `status` instead. The scope of specific runners to return, one of: `active`, `paused`, `online` and `offline`; showing all runners if none provided |
+| `type` | string | no | The type of runners to return, one of: `instance_type`, `group_type`, `project_type` |
+| `status` | string | no | The status of runners to return, one of: `online`, `offline`, `stale`, and `never_contacted`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 |
| `paused` | boolean | no | Whether to include only runners that are accepting or ignoring new jobs |
-| `tag_list` | string array | no | List of the runner's tags |
+| `tag_list` | string array | no | A list of runner tags |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/9/runners"
@@ -580,10 +580,10 @@ GET /groups/:id/runners?tag_list=tag1,tag2
| Attribute | Type | Required | Description |
|------------|----------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id` | integer | yes | The ID of the group owned by the authenticated user |
-| `type` | string | no | The type of runners to show, one of: `instance_type`, `group_type`, `project_type`. The `project_type` value is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/351466) and will be removed in GitLab 15.0 |
-| `status` | string | no | The status of runners to show, one of: `online`, `offline`, `stale`, and `never_contacted`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 |
+| `type` | string | no | The type of runners to return, one of: `instance_type`, `group_type`, `project_type`. The `project_type` value is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/351466) and will be removed in GitLab 15.0 |
+| `status` | string | no | The status of runners to return, one of: `online`, `offline`, `stale`, and `never_contacted`. `active` and `paused` are also possible values which were deprecated in GitLab 14.8 and will be removed in GitLab 16.0 |
| `paused` | boolean | no | Whether to include only runners that are accepting or ignoring new jobs |
-| `tag_list` | string array | no | List of the runner's tags |
+| `tag_list` | string array | no | A list of runner tags |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/9/runners"
@@ -640,7 +640,12 @@ Example response:
]
```
-## Register a new runner
+## Register a new runner (deprecated)
+
+> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102579) in GitLab 15.6.
+
+WARNING:
+This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102579) in GitLab 15.6 and is planned for removal in 16.0. This change is a breaking change.
Register a new runner for the instance.
@@ -652,14 +657,14 @@ POST /runners
|--------------------|--------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `token` | string | yes | [Registration token](#registration-and-authentication-tokens) |
| `description` | string | no | Runner's description |
-| `info` | hash | no | Runner's metadata. You can include `name`, `version`, `revision`, `platform`, and `architecture`, but only `version` is displayed in the Admin Area of the UI |
-| `active` | boolean | no | Deprecated: Use `:paused` instead. Whether the runner is allowed to receive jobs |
-| `paused` | boolean | no | Whether the runner should ignore new jobs |
-| `locked` | boolean | no | Whether the runner should be locked for current project |
-| `run_untagged` | boolean | no | Whether the runner should handle untagged jobs |
-| `tag_list` | string array | no | List of runner's tags |
-| `access_level` | string | no | The access_level of the runner; `not_protected` or `ref_protected` |
-| `maximum_timeout` | integer | no | Maximum timeout set when this runner handles the job |
+| `info` | hash | no | Runner's metadata. You can include `name`, `version`, `revision`, `platform`, and `architecture`, but only `version`, `platform`, and `architecture` are displayed in the Admin Area of the UI |
+| `active` | boolean | no | Deprecated: Use `paused` instead. Specifies whether the runner is allowed to receive new jobs |
+| `paused` | boolean | no | Specifies whether the runner should ignore new jobs |
+| `locked` | boolean | no | Specifies whether the runner should be locked for the current project |
+| `run_untagged` | boolean | no | Specifies whether the runner should handle untagged jobs |
+| `tag_list` | string array | no | A list of runner tags |
+| `access_level` | string | no | The access level of the runner; `not_protected` or `ref_protected` |
+| `maximum_timeout` | integer | no | Maximum timeout that limits the amount of time (in seconds) that runners can run jobs |
| `maintainer_note` | string | no | [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/350730), see `maintenance_note` |
| `maintenance_note` | string | no | Free-form maintenance notes for the runner (1024 characters) |
@@ -739,9 +744,9 @@ Validates authentication credentials for a registered runner.
POST /runners/verify
```
-| Attribute | Type | Required | Description |
-|-------------|---------|----------|---------------------|
-| `token` | string | yes | Runner's [authentication token](#registration-and-authentication-tokens). |
+| Attribute | Type | Required | Description |
+|-------------|---------|----------|-------------------------------------------------------------------------------|
+| `token` | string | yes | The runner's [authentication token](#registration-and-authentication-tokens). |
```shell
curl --request POST "https://gitlab.example.com/api/v4/runners/verify" \
@@ -759,7 +764,7 @@ Response:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30942) in GitLab 14.3.
-Resets the runner registration token for the GitLab instance.
+Reset the runner registration token for the GitLab instance.
```plaintext
POST /runners/reset_registration_token
@@ -774,7 +779,7 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30942) in GitLab 14.3.
-Resets the runner registration token for a project.
+Reset the runner registration token for a project.
```plaintext
POST /projects/:id/runners/reset_registration_token
@@ -789,7 +794,7 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30942) in GitLab 14.3.
-Resets the runner registration token for a group.
+Reset the runner registration token for a group.
```plaintext
POST /groups/:id/runners/reset_registration_token
@@ -802,7 +807,7 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
## Reset runner's authentication token by using the runner ID
-Resets the runner's authentication token by using its runner ID.
+Reset the runner's authentication token by using its runner ID.
```plaintext
POST /runners/:id/reset_authentication_token
@@ -828,15 +833,15 @@ Example response:
## Reset runner's authentication token by using the current token
-Resets the runner's authentication token by using the current token's value as an input.
+Reset the runner's authentication token by using the current token's value as an input.
```plaintext
POST /runners/reset_authentication_token
```
-| Attribute | Type | Required | Description |
-|-----------|---------|----------|---------------------------------|
-| `token` | string | yes | The current token of the runner |
+| Attribute | Type | Required | Description |
+|-----------|---------|----------|----------------------------------------|
+| `token` | string | yes | The authentication token of the runner |
```shell
curl --request POST --form "token=<current token>" \
diff --git a/doc/api/scim.md b/doc/api/scim.md
index b1763a44fc4..53897cadf90 100644
--- a/doc/api/scim.md
+++ b/doc/api/scim.md
@@ -25,7 +25,7 @@ Supported attributes:
| Attribute | Type | Required | Description |
|:------------------|:--------|:---------|:----------------------|
-| `id` | integer | Yes | Return SAML identities for the given group ID. |
+| `id` | integer | Yes | Return SCIM identities for the given group ID. |
If successful, returns [`200`](index.md#status-codes) and the following
response attributes:
@@ -49,8 +49,8 @@ Example response:
Example request:
```shell
-curl --location --request GET "https://gdk.test:3443/api/v4/groups/33/scim/identities" \
---header "<PRIVATE-TOKEN>" \
+curl --location --request GET "https://gitlab.example.com/api/v4/groups/33/scim/identities" \
+--header "PRIVATE-TOKEN: <PRIVATE-TOKEN>" \
--form "extern_uid=<ID_TO_BE_UPDATED>" \
```
@@ -77,7 +77,7 @@ Parameters:
Example request:
```shell
-curl --location --request PATCH "https://gdk.test:3443/api/v4/groups/33/scim/sydney_jones" \
---header "<PRIVATE TOKEN>" \
+curl --location --request PATCH "https://gitlab.example.com/api/v4/groups/33/scim/sydney_jones" \
+--header "PRIVATE-TOKEN: <PRIVATE TOKEN>" \
--form "extern_uid=sydney_jones_new" \
```
diff --git a/doc/api/secure_files.md b/doc/api/secure_files.md
index 0c34dd30cdf..c2c21134d6f 100644
--- a/doc/api/secure_files.md
+++ b/doc/api/secure_files.md
@@ -42,14 +42,34 @@ Example response:
"name": "myfile.jks",
"checksum": "16630b189ab34b2e3504f4758e1054d2e478deda510b2b08cc0ef38d12e80aac",
"checksum_algorithm": "sha256",
- "created_at": "2022-02-22T22:22:22.222Z"
+ "created_at": "2022-02-22T22:22:22.222Z",
+ "expires_at": null,
+ "metadata": null
},
{
"id": 2,
- "name": "myotherfile.jks",
+ "name": "myfile.cer",
"checksum": "16630b189ab34b2e3504f4758e1054d2e478deda510b2b08cc0ef38d12e80aa2",
"checksum_algorithm": "sha256",
- "created_at": "2022-02-22T22:22:22.222Z"
+ "created_at": "2022-02-22T22:22:22.222Z",
+ "expires_at": "2022-09-21T14:56:00.000Z",
+ "metadata": {
+ "id":"75949910542696343243264405377658443914",
+ "issuer": {
+ "C":"US",
+ "O":"Apple Inc.",
+ "CN":"Apple Worldwide Developer Relations Certification Authority",
+ "OU":"G3"
+ },
+ "subject": {
+ "C":"US",
+ "O":"Organization Name",
+ "CN":"Apple Distribution: Organization Name (ABC123XYZ)",
+ "OU":"ABC123XYZ",
+ "UID":"ABC123XYZ"
+ },
+ "expires_at":"2022-09-21T14:56:00.000Z"
+ }
}
]
```
@@ -83,7 +103,9 @@ Example response:
"name": "myfile.jks",
"checksum": "16630b189ab34b2e3504f4758e1054d2e478deda510b2b08cc0ef38d12e80aac",
"checksum_algorithm": "sha256",
- "created_at": "2022-02-22T22:22:22.222Z"
+ "created_at": "2022-02-22T22:22:22.222Z",
+ "expires_at": null,
+ "metadata": null
}
```
@@ -118,7 +140,9 @@ Example response:
"name": "myfile.jks",
"checksum": "16630b189ab34b2e3504f4758e1054d2e478deda510b2b08cc0ef38d12e80aac",
"checksum_algorithm": "sha256",
- "created_at": "2022-02-22T22:22:22.222Z"
+ "created_at": "2022-02-22T22:22:22.222Z",
+ "expires_at": null,
+ "metadata": null
}
```
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 3d8d02b8429..78dc81c4f84 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -109,12 +109,13 @@ Example response:
```
Users on [GitLab Premium or Ultimate](https://about.gitlab.com/pricing/) may also see
-the `file_template_project_id`, `delayed_project_deletion`, `delayed_group_deletion`, `deletion_adjourned_period`, or the `geo_node_allowed_ips` parameters:
+the `group_owners_can_manage_default_branch_protection`, `file_template_project_id`, `delayed_project_deletion`, `delayed_group_deletion`, `deletion_adjourned_period`, or the `geo_node_allowed_ips` parameters:
```json
{
"id" : 1,
"signup_enabled" : true,
+ "group_owners_can_manage_default_branch_protection" : true,
"file_template_project_id": 1,
"geo_node_allowed_ips": "0.0.0.0/0, ::/0",
"delayed_project_deletion": false,
@@ -224,6 +225,7 @@ Example response:
Users on [GitLab Premium or Ultimate](https://about.gitlab.com/pricing/) may also see
these parameters:
+- `group_owners_can_manage_default_branch_protection`
- `file_template_project_id`
- `geo_node_allowed_ips`
- `geo_status_timeout`
@@ -295,6 +297,7 @@ listed in the descriptions of the relevant settings.
| `diff_max_patch_bytes` | integer | no | Maximum [diff patch size](../user/admin_area/diff_limits.md), in bytes. |
| `diff_max_files` | integer | no | Maximum [files in a diff](../user/admin_area/diff_limits.md). |
| `diff_max_lines` | integer | no | Maximum [lines in a diff](../user/admin_area/diff_limits.md). |
+| `disable_admin_oauth_scopes` | boolean | no | Stops administrators from connecting their GitLab accounts to non-trusted OAuth 2.0 applications that have the `api`, `read_api`, `read_repository`, `write_repository`, `read_registry`, `write_registry`, or `sudo` scopes. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375043) in GitLab 15.6. |
| `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. |
| `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. |
@@ -352,6 +355,7 @@ listed in the descriptions of the relevant settings.
| `grafana_enabled` | boolean | no | Enable Grafana. |
| `grafana_url` | string | no | Grafana URL. |
| `gravatar_enabled` | boolean | no | Enable Gravatar. |
+| `group_owners_can_manage_default_branch_protection` **(PREMIUM SELF)** | boolean | no | Prevent overrides of default branch protection. |
| `hashed_storage_enabled` | boolean | no | Create new projects using hashed storage paths: Enable immutable, hash-based paths and repository names to store repositories on disk. This prevents repositories from having to be moved or renamed when the Project URL changes and may improve disk I/O performance. (Always enabled in GitLab versions 13.0 and later, configuration is scheduled for removal in 14.0) |
| `help_page_hide_commercial_content` | boolean | no | Hide marketing-related entries from help. |
| `help_page_support_url` | string | no | Alternate support URL for help page and help dropdown list. |
diff --git a/doc/api/status_checks.md b/doc/api/status_checks.md
index a30bfbd4dfb..e6a9c633418 100644
--- a/doc/api/status_checks.md
+++ b/doc/api/status_checks.md
@@ -121,8 +121,8 @@ defined external service. This includes confidential merge requests.
| Attribute | Type | Required | Description |
|------------------------|------------------|----------|------------------------------------------------|
| `id` | integer | yes | ID of a project |
-| `name` | string | yes | Display name of status check |
-| `external_url` | string | yes | URL of status check resource |
+| `name` | string | yes | Display name of external status check |
+| `external_url` | string | yes | URL of external status check resource |
| `protected_branch_ids` | `array<Integer>` | no | IDs of protected branches to scope the rule by |
## Delete external status check
@@ -135,7 +135,7 @@ DELETE /projects/:id/external_status_checks/:check_id
| Attribute | Type | Required | Description |
|------------------------|----------------|----------|-----------------------|
-| `rule_id` | integer | yes | ID of an status check |
+| `check_id` | integer | yes | ID of an external status check |
| `id` | integer | yes | ID of a project |
## Update external status check
@@ -149,8 +149,8 @@ PUT /projects/:id/external_status_checks/:check_id
| Attribute | Type | Required | Description |
|------------------------|------------------|----------|------------------------------------------------|
| `id` | integer | yes | ID of a project |
-| `rule_id` | integer | yes | ID of an external status check |
-| `name` | string | no | Display name of status check |
+| `check_id` | integer | yes | ID of an external status check |
+| `name` | string | no | Display name of external status check |
| `external_url` | string | no | URL of external status check resource |
| `protected_branch_ids` | `array<Integer>` | no | IDs of protected branches to scope the rule by |
diff --git a/doc/api/suggestions.md b/doc/api/suggestions.md
index 9771225ad31..1e1f226481c 100644
--- a/doc/api/suggestions.md
+++ b/doc/api/suggestions.md
@@ -11,7 +11,7 @@ This page describes the API for [suggesting changes](../user/project/merge_reque
Every API call to suggestions must be authenticated.
-## Applying suggestions
+## Applying a suggestion
Applies a suggested patch in a merge request. Users must have
at least the Developer role to perform such action.
@@ -22,7 +22,7 @@ PUT /suggestions/:id/apply
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `id` | integer/string | yes | The ID of a suggestion |
+| `id` | integer | yes | The ID of a suggestion |
| `commit_message` | string | no | A custom commit message to use instead of the default generated message or the project's default message |
```shell
@@ -32,13 +32,53 @@ curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab
Example response:
```json
+{
+ "id": 5,
+ "from_line": 10,
+ "to_line": 10,
+ "applicable": true,
+ "applied": false,
+ "from_content": "This is an eaxmple\n",
+ "to_content": "This is an example\n"
+}
+```
+
+## Applying multiple suggestions
+
+```plaintext
+PUT /suggestions/batch_apply
+```
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `ids` | integer | yes | The IDs of suggestions |
+| `commit_message` | string | no | A custom commit message to use instead of the default generated message or the project's default message |
+
+```shell
+curl --request PUT --header "PRIVATE-TOKEN: <your_access_token>" --header 'Content-Type: application/json' --data '{"ids": [5, 6]}' "https://gitlab.example.com/api/v4/suggestions/batch_apply"
+```
+
+Example response:
+
+```json
+[
{
- "id": 36,
+ "id": 5,
"from_line": 10,
"to_line": 10,
- "applicable": false,
- "applied": true,
- "from_content": " \"--talk-name=org.freedesktop.\",\n",
- "to_content": " \"--talk-name=org.free.\",\n \"--talk-name=org.desktop.\",\n"
+ "applicable": true,
+ "applied": false,
+ "from_content": "This is an eaxmple\n",
+ "to_content": "This is an example\n"
+ }
+ {
+ "id": 6,
+ "from_line": 19
+ "to_line": 19,
+ "applicable": true,
+ "applied": false,
+ "from_content": "This is another eaxmple\n",
+ "to_content": "This is another example\n"
}
+ ]
```
diff --git a/doc/api/templates/dockerfiles.md b/doc/api/templates/dockerfiles.md
index 9636393dfe9..31b676558db 100644
--- a/doc/api/templates/dockerfiles.md
+++ b/doc/api/templates/dockerfiles.md
@@ -142,6 +142,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/api/templates/gitignores.md b/doc/api/templates/gitignores.md
index 7c68daa5c48..1569a2bc89d 100644
--- a/doc/api/templates/gitignores.md
+++ b/doc/api/templates/gitignores.md
@@ -146,6 +146,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/api/templates/gitlab_ci_ymls.md b/doc/api/templates/gitlab_ci_ymls.md
index 152f3373ad6..b7048795313 100644
--- a/doc/api/templates/gitlab_ci_ymls.md
+++ b/doc/api/templates/gitlab_ci_ymls.md
@@ -147,6 +147,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/api/templates/licenses.md b/doc/api/templates/licenses.md
index e676da2e999..6abdb3ca3b0 100644
--- a/doc/api/templates/licenses.md
+++ b/doc/api/templates/licenses.md
@@ -166,6 +166,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/api/users.md b/doc/api/users.md
index 4a924f3b5f3..19c25236f55 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -431,7 +431,7 @@ see the `group_saml` option and `provisioned_by_group_id` parameter:
}
```
-Administrators can use the `created_by` parameter to see if a user account was created:
+Administrators can use the `created_by` parameter to see if a user account was created:
- [Manually by an administrator](../user/profile/account/create_accounts.md#create-users-in-admin-area).
- As a [project bot user](../user/project/settings/project_access_tokens.md#bot-users-for-projects).
@@ -510,6 +510,8 @@ Parameters:
Modifies an existing user. Only administrators can change attributes of a user.
+The `email` field is the user's primary email address. You can only change this field to an already-added secondary email address for that user. To add more email addresses to the same user, use the [add email function](#add-email).
+
```plaintext
PUT /users/:id
```
@@ -966,6 +968,33 @@ Example response:
Please refer to the [List of user projects](projects.md#list-user-projects).
+## List associations count for user
+
+Get a list of a specified user's count of projects, groups, issues and merge requests.
+
+Administrators can query any user, but non-administrators can only query themselves.
+
+```plaintext
+GET /users/:id/associations_count
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+|-----------|---------|----------|------------------|
+| `id` | integer | yes | ID of a user |
+
+Example response:
+
+```json
+{
+ "groups_count": 2,
+ "projects_count": 3,
+ "issues_count": 8,
+ "merge_requests_count": 5
+}
+```
+
## List SSH keys
Get a list of currently authenticated user's SSH keys.
@@ -1486,6 +1515,7 @@ Parameters:
Deletes email owned by currently authenticated user.
This returns a `204 No Content` status code if the operation was successfully or `404` if the resource was not found.
+This cannot delete a primary email address.
```plaintext
DELETE /user/emails/:email_id
@@ -1499,7 +1529,11 @@ Parameters:
## Delete email for given user **(FREE SELF)**
-Deletes email owned by a specified user. Available only for administrator.
+Prerequisite:
+
+- You must be an administrator of a self-managed GitLab instance.
+
+Deletes an email address owned by a specified user. This cannot delete a primary email address.
```plaintext
DELETE /users/:id/emails/:email_id
@@ -1573,7 +1607,7 @@ Returns:
- `404 User Not Found` if user cannot be found.
- `403 Forbidden` when trying to deactivate a user:
- Blocked by administrator or by LDAP synchronization.
- - That has any activity in past 90 days. These users cannot be deactivated.
+ - That is not [dormant](../user/admin_area/moderate_users.md#automatically-deactivate-dormant-users).
- That is internal.
## Activate user **(FREE SELF)**
diff --git a/doc/api/vulnerability_exports.md b/doc/api/vulnerability_exports.md
index 14966d2e925..8c166c2ba2a 100644
--- a/doc/api/vulnerability_exports.md
+++ b/doc/api/vulnerability_exports.md
@@ -198,18 +198,11 @@ The response is `404 Not Found` if the vulnerability export is not finished yet
Example response:
```csv
-Group Name,Project Name,Tool,Scanner Name,Status,Vulnerability,Details,Additional Info,Severity,CVE,CWE,Other Identifiers
-Gitlab.org,Defend,container_scanning,Trivy,detected,CVE-2017-16997 in glibc,,CVE-2017-16997 in glibc,critical,CVE-2017-16997
-Gitlab.org,Defend,container_scanning,Trivy,detected,CVE-2017-18269 in glibc,,CVE-2017-18269 in glibc,critical,CVE-2017-18269
-Gitlab.org,Defend,container_scanning,Trivy,detected,CVE-2018-1000001 in glibc,,CVE-2018-1000001 in glibc,high,CVE-2018-1000001
-Gitlab.org,Defend,container_scanning,Trivy,detected,CVE-2016-10228 in glibc,,CVE-2016-10228 in glibc,medium,CVE-2016-10228
-Gitlab.org,Defend,container_scanning,Trivy,detected,CVE-2010-4052 in glibc,,CVE-2010-4052 in glibc,low,CVE-2010-4052
-Gitlab.org,Defend,container_scanning,Trivy,detected,CVE-2018-18520 in elfutils,,CVE-2018-18520 in elfutils,low,CVE-2018-18520
-Gitlab.org,Defend,container_scanning,Trivy,detected,CVE-2018-16869 in nettle,,CVE-2018-16869 in nettle,unknown,CVE-2018-16869,CWE-1
-Gitlab.org,Defend,dependency_scanning,Gemnasium,detected,Regular Expression Denial of Service in debug,,Regular Expression Denial of Service in debug,unknown,CVE-2021-1234,CWE-2,"""yarn.lock:debug:gemnasium:37283ed4-0380-40d7-ada7-2d994afcc62a"""
-Gitlab.org,Defend,dependency_scanning,Gemnasium,detected,Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js,,Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js,unknown,,,"""yarn.lock:saml2-js:gemnasium:9952e574-7b5b-46fa-a270-aeb694198a98"""
-Gitlab.org,Defend,sast,Find Security Bugs,detected,Predictable pseudorandom number generator,,Predictable pseudorandom number generator,medium,,,"""818bf5dacb291e15d9e6dc3c5ac32178:PREDICTABLE_RANDOM:src/main/java/com/gitlab/security_products/tests/App.java:47"""
-Gitlab.org,Defend,sast,Find Security Bugs,detected,Cipher with no integrity,,Cipher with no integrity,medium,,,"""e6449b89335daf53c0db4c0219bc1634:CIPHER_INTEGRITY:src/main/java/com/gitlab/security_products/tests/App.java:29"""
-Gitlab.org,Defend,sast,Find Security Bugs,detected,Predictable pseudorandom number generator,,Predictable pseudorandom number generator,medium,,,"""e8ff1d01f74cd372f78da8f5247d3e73:PREDICTABLE_RANDOM:src/main/java/com/gitlab/security_products/tests/App.java:41"""
-Gitlab.org,Defend,sast,Find Security Bugs,detected,ECB mode is insecure,,ECB mode is insecure,medium,,,"""ea0f905fc76f2739d5f10a1fd1e37a10:ECB_MODE:src/main/java/com/gitlab/security_products/tests/App.java:29"""
+Group Name,Project Name,Tool,Scanner Name,Status,Vulnerability,Details,Additional Info,Severity,CVE,CWE,Other Identifiers,Detected At,Location,Activity,Comments,
+Gitlab.org,Defend,container_scanning,Trivy,resolved,CVE-2019-14697 in musl-utils-1.1.20-r4,"musl libc through 1.1.23 has an x87 floating-point stack adjustment imbalance, related to the math/i386/ directory. In some cases, use of this library could introduce out-of-bounds writes that are not present in an application's source code.",CVE-2019-14697 in musl-utils-1.1.20-r4,critical,CVE-2019-14697,,"",2022-10-07 13:34:41 UTC,"{""image""=>""python:3.4-alpine"", ""dependency""=>{""package""=>{""name""=>""musl-utils""}, ""version""=>""1.1.20-r4""}, ""operating_system""=>""alpine 3.9.2""}",true,"2022-10-07 13:41:08 UTC|root|resolved|changed vulnerability status to resolved",
+Gitlab.org,Defend,container_scanning,Trivy,detected,CVE-2019-19242 in sqlite-libs-3.26.0-r3,"SQLite 3.30.1 mishandles pExpr->y.pTab, as demonstrated by the TK_COLUMN case in sqlite3ExprCodeTarget in expr.c.",CVE-2019-19242 in sqlite-libs-3.26.0-r3,medium,CVE-2019-19242,,"",2022-10-07 13:34:41 UTC,"{""image""=>""python:3.4-alpine"", ""dependency""=>{""package""=>{""name""=>""sqlite-libs""}, ""version""=>""3.26.0-r3""}, ""operating_system""=>""alpine 3.9.2""}",true,"",
+Gitlab.org,Defend,container_scanning,Trivy,detected,CVE-2020-28928 in musl-1.1.20-r4,"In musl libc through 1.2.1, wcsnrtombs mishandles particular combinations of destination buffer size and source character limit, as demonstrated by an invalid write access (buffer overflow).",CVE-2020-28928 in musl-1.1.20-r4,medium,CVE-2020-28928,,"",2022-10-07 13:34:41 UTC,"{""image""=>""python:3.4-alpine"", ""dependency""=>{""package""=>{""name""=>""musl""}, ""version""=>""1.1.20-r4""}, ""operating_system""=>""alpine 3.9.2""}",true,"",
+Gitlab.org,Defend,dependency_scanning,Gemnasium,detected,Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') in rack,Carefully crafted requests can cause shell escape sequences to be written to the terminal via Rack's Lint middleware and CommonLogger middleware. These escape sequences can be leveraged to possibly execute commands in the victim's terminal.,Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') in rack,unknown,Gemfile.lock:rack:gemnasium:60b5a27f-4e4d-4ab4-8ae7-74b4b212e177,,Gemnasium-60b5a27f-4e4d-4ab4-8ae7-74b4b212e177; GHSA-wq4h-7r42-5hrr,2022-10-14 13:16:00 UTC,"{""file""=>""Gemfile.lock"", ""dependency""=>{""package""=>{""name""=>""rack""}, ""version""=>""2.2.3""}}",false,"",
+Gitlab.org,Defend,dependency_scanning,Gemnasium,detected,Denial of Service Vulnerability in Rack Multipart Parsing in rack,"Carefully crafted multipart POST requests can cause Rack's multipart parser to take much longer than expected, leading to a possible denial of service vulnerability. Impacted code will use Rack's multipart parser to parse multipart posts.",Denial of Service Vulnerability in Rack Multipart Parsing in rack,unknown,Gemfile.lock:rack:gemnasium:20daa17a-47b5-4f79-80c2-cd8f2db9805c,,Gemnasium-20daa17a-47b5-4f79-80c2-cd8f2db9805c; GHSA-hxqx-xwvh-44m2,2022-10-14 13:16:00 UTC,"{""file""=>""Gemfile.lock"", ""dependency""=>{""package""=>{""name""=>""rack""}, ""version""=>""2.2.3""}}",false,"",
+Gitlab.org,Defend,sast,Brakeman,detected,Possible SQL injection,,Possible SQL injection,medium,e52f23a259cd489168b4313317ac94a3f13bffde57b9635171c1a44a9f329e9a,,"""Brakeman Warning Code 0""",2022-10-13 15:16:36 UTC,"{""file""=>""main.rb"", ""class""=>""User"", ""method""=>""index"", ""start_line""=>3}",false,""
```
diff --git a/doc/architecture/blueprints/_template.md b/doc/architecture/blueprints/_template.md
index 7637c3bf5fa..798d51a97ad 100644
--- a/doc/architecture/blueprints/_template.md
+++ b/doc/architecture/blueprints/_template.md
@@ -1,14 +1,11 @@
---
-stage: none
-group: unassigned
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
status: proposed
creation-date: yyyy-mm-dd
authors: [ "@username" ]
coach: "@username"
-owning-section: "~section::<section>"
-participating-sections: []
approvers: [ "@product-manager", "@engineering-manager" ]
+owning-stage: "~devops::<stage>"
+participating-stages: []
---
<!--
diff --git a/doc/architecture/blueprints/ci_data_decay/index.md b/doc/architecture/blueprints/ci_data_decay/index.md
index 221c2364f79..b7c3bdde2f8 100644
--- a/doc/architecture/blueprints/ci_data_decay/index.md
+++ b/doc/architecture/blueprints/ci_data_decay/index.md
@@ -1,8 +1,11 @@
---
-stage: none
-group: unassigned
-comments: false
-description: 'CI/CD data time decay'
+status: ready
+creation-date: "2021-09-10"
+authors: [ "@grzesiek" ]
+coach: "@kamil"
+approvers: [ "@jporter", "@cheryl.li" ]
+owning-stage: "~devops::verify"
+participating-stages: []
---
# CI/CD data time decay
@@ -23,18 +26,6 @@ the data storage for pipeline builds remains almost the same since 2012. In
ia separate database. Now we want to improve the architecture of GitLab CI/CD
product to enable further scaling.
-_Disclaimer: The following 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 in this document and linked pages 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._
-
## Goals
**Implement a new architecture of CI/CD data storage to enable scaling.**
@@ -67,7 +58,7 @@ When a build gets archived it will not be possible to retry it, but we still do
keep all the processing metadata in the database, and it consumes resources
that are scarce in the primary database.
-In order to improve performance and make it easier to scale CI/CD data storage
+To improve performance and make it easier to scale CI/CD data storage
we might want to follow these three tracks described below.
![pipeline data time decay](pipeline_data_time_decay.png)
@@ -210,7 +201,7 @@ We accept the possible necessity of building a separate API endpoint /
endpoints needed to access pipeline data through the API.
In the new API users might need to provide a time range in which the data has
-been created to search through their pipelines / builds. In order to make it
+been created to search through their pipelines / builds. To make it
efficient it might be necessary to restrict access to querying data residing in
more than two partitions at once. We can do that by supporting time ranges
spanning the duration that equals to the builds archival policy.
@@ -246,35 +237,4 @@ In progress.
- 2022-04-30: Additional [benchmarking started](https://gitlab.com/gitlab-org/gitlab/-/issues/361019) to evaluate impact.
- 2022-06-31: [Pipeline partitioning design](pipeline_partitioning.md) document [merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87683) merged.
- 2022-09-01: Engineering effort started to implement partitioning.
-
-## Who
-
-Proposal:
-
-<!-- vale gitlab.Spelling = NO -->
-
-| Role | Who
-|------------------------------|-------------------------|
-| Author | Grzegorz Bizon |
-| Engineering Leader | Cheryl Li |
-| Product Manager | Jackie Porter |
-| Architecture Evolution Coach | Kamil Trzciński |
-
-DRIs:
-
-| Role | Who
-|------------------------------|------------------------|
-| Leadership | Cheryl Li |
-| Product | Jackie Porter |
-| Engineering | Grzegorz Bizon |
-
-Domain experts:
-
-| Area | Who
-|------------------------------|------------------------|
-| Verify / Pipeline execution | Fabio Pitino |
-| Verify / Pipeline execution | Marius Bobin |
-| Verify / Pipeline insights | Maxime Orefice |
-| PostgreSQL Database | Andreas Brandl |
-
-<!-- vale gitlab.Spelling = YES -->
+- 2022-11-01: The fastest growing CI table partitioned: `ci_builds_metadata`.
diff --git a/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md b/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md
index 5f907ecdaa4..d61412ae1ed 100644
--- a/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md
+++ b/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md
@@ -7,18 +7,6 @@ description: 'Pipeline data partitioning design'
# Pipeline data partitioning design
-_Disclaimer: The following 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 in this document and linked pages
-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._
-
## What problem are we trying to solve?
We want to partition the CI/CD dataset, because some of the database tables are
@@ -267,9 +255,27 @@ new routing tables. Depending on the chosen
[partitioning strategy](#how-do-we-want-to-partition-cicd-data) for a given
table, it is possible to have many logical partitions per one physical partition.
+### Attaching first partition and acquiring locks
+
+We learned when [partitioning](https://gitlab.com/gitlab-org/gitlab/-/issues/378644)
+the first table that `PostgreSQL` requires an `AccessExclusiveLock` on the table and
+all of the other tables that it references through foreign keys. This can cause a deadlock
+if the migration tries to acquire the locks in a different order from the application
+business logic.
+
+To solve this problem, we introduced a **priority locking strategy** to avoid
+further deadlock errors. This allows us to define the locking order and
+then try keep retrying aggressively until we acquire the locks or run out of retries.
+This process can take up to 40 minutes.
+
+With this strategy, we successfully acquired a lock on `ci_builds` table after 15 retries
+during a low traffic period([after `00:00 UTC`](https://dashboards.gitlab.net/d/web-main/web-overview?orgId=1&viewPanel=537181794&from=now-2d&to=now)).
+
+See an example of this strategy in our [partition tooling](../../../development/database/table_partitioning.md#step-6---create-parent-table-and-attach-existing-table-as-the-initial-partition)).
+
## Storing partitions metadata in the database
-In order to build an efficient mechanism that will be responsible for creating
+To build an efficient mechanism that will be responsible for creating
new partitions, and to implement time decay we want to introduce a partitioning
metadata table, called `ci_partitions`. In that table we would store metadata
about all the logical partitions, with many pipelines per partition. We may
@@ -366,6 +372,20 @@ scope block takes an argument). Preloading instance dependent scopes is not
supported.
```
+### Query analyzers
+
+We implemented 2 query analyzers to detect queries that need to be fixed so that everything
+keeps working with partitioned tables:
+
+- One analyzer to detect queries not going through a routing table.
+- One analyzer to detect queries that use routing tables without specifying the `partition_id` in the `WHERE` clauses.
+
+We started by enabling our first analyzer in `test` environment to detect existing broken
+queries. It is also enabled on `production` environment, but for a small subset of the traffic (`0.1%`)
+because of scalability concerns.
+
+The second analyzer will be enabled in a future iteration.
+
### Primary key
Primary key must include the partitioning key column to partition the table.
@@ -652,7 +672,7 @@ application-wide outage.
1. Make it possible to create partitions in an automatic way.
1. Deliver the new architecture to self-managed instances.
-The diagram below visualizes this plan on Gantt chart. Please note that dates
+The diagram below visualizes this plan on Gantt chart. The dates
on the chart below are just estimates to visualize the plan better, these are
not deadlines and can change at any time.
diff --git a/doc/architecture/blueprints/ci_pipeline_components/index.md b/doc/architecture/blueprints/ci_pipeline_components/index.md
index 115f6909d2d..a3c72227f3e 100644
--- a/doc/architecture/blueprints/ci_pipeline_components/index.md
+++ b/doc/architecture/blueprints/ci_pipeline_components/index.md
@@ -1,12 +1,13 @@
---
-stage: Stage
-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
-comments: false
-description: 'Create a catalog of shareable pipeline constructs'
+status: proposed
+creation-date: "2022-09-14"
+authors: [ "@fabio", "@grzesiek" ]
+coach: "@kamil"
+approvers: [ "@dov" ]
+owning-stage: "~devops::verify"
+participating-stages: []
---
-
# CI/CD pipeline components catalog
## Summary
@@ -115,21 +116,22 @@ while encapsulating and isolating implementation details.
Components allow a pipeline to be assembled by using abstractions instead of having all the details defined in one place.
When using a component in a pipeline, a user shouldn't need to know the implementation details of the component and should
-only rely on the provided interface. The interface will have a version / revision, so that users understand which revision they are interfacing with.
+only rely on the provided interface.
A pipeline component defines its type which indicates in which context of the pipeline configuration the component can be used.
For example, a component of type X can only be used according to the type X use-case.
-For best experience with any systems made of components it's fundamental that components are single purpose,
-isolated, reusable and resolvable.
+For best experience with any systems made of components it's fundamental that components:
- **Single purpose**: a component must focus on a single goal and the scope be as small as possible.
-- **Isolation**: when a component is used in a pipeline, its implementation details should not leak outside the
+- **Isolated**: when a component is used in a pipeline, its implementation details should not leak outside the
component itself and into the main pipeline.
-- **Reusability:** a component is designed to be used in different pipelines.
+- **Reusable**: a component is designed to be used in different pipelines.
Depending on the assumptions it's built on a component can be more or less generic.
Generic components are more reusable but may require more customization.
-- **Resolvable:** When a component depends on another component, this dependency must be explicit and trackable.
+- **Versioned**: when using a component we must specify the version we are interested in.
+ The version identifies the exact interface and behavior of the component.
+- **Resolvable**: when a component depends on another component, this dependency must be explicit and trackable.
## Proposal
@@ -186,35 +188,3 @@ Some limits we could consider adding:
- Allow self-managed administrators to populate their self-managed catalog by importing/updating
components from GitLab.com or from repository exports.
- Iterate on feedback.
-
-## Who
-
-Proposal:
-
-<!-- vale gitlab.Spelling = NO -->
-
-| Role | Who
-|------------------------------|-------------------------|
-| Author | Fabio Pitino |
-| Engineering Leader | ? |
-| Product Manager | Dov Hershkovitch |
-| Architecture Evolution Coach | Kamil Trzciński |
-
-DRIs:
-
-| Role | Who
-|------------------------------|------------------------|
-| Leadership | ? |
-| Product | Dov Hershkovitch |
-| Engineering | ? |
-| UX | Nadia Sotnikova |
-
-Domain experts:
-
-| Area | Who
-|------------------------------|------------------------|
-| Verify / Pipeline authoring | Avielle Wolfe |
-| Verify / Pipeline authoring | Furkan Ayhan |
-| Verify / Pipeline execution | Fabio Pitino |
-
-<!-- vale gitlab.Spelling = YES -->
diff --git a/doc/architecture/blueprints/cloud_native_build_logs/index.md b/doc/architecture/blueprints/cloud_native_build_logs/index.md
index b77d7998fc8..20cfb46abc4 100644
--- a/doc/architecture/blueprints/cloud_native_build_logs/index.md
+++ b/doc/architecture/blueprints/cloud_native_build_logs/index.md
@@ -1,9 +1,11 @@
---
-stage: none
-group: unassigned
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-comments: false
-description: 'Next iteration of build logs architecture at GitLab'
+status: implemented
+creation-date: "2020-08-26"
+authors: [ "@grzesiek" ]
+coach: "@kamil"
+approvers: [ "@thaoyeager", "@darbyfrey" ]
+owning-stage: "~devops::release"
+participating-stages: []
---
# Cloud Native Build Logs
@@ -31,7 +33,7 @@ a job is complete, the trace file contents are sent to the object store.
New architecture writes data to Redis instead of writing build logs into a
file.
-In order to make this performant and resilient enough, we implemented a chunked
+To make this performant and resilient enough, we implemented a chunked
I/O mechanism - we store data in Redis in chunks, and migrate them to an object
store once we reach a desired chunk size.
@@ -121,27 +123,3 @@ Enabling this feature on GitLab.com is a subtask of
This change has been implemented and enabled on GitLab.com.
We are working on [an epic to make this feature more resilient and observable](https://gitlab.com/groups/gitlab-org/-/epics/4860).
-
-## Who
-
-Proposal:
-
-<!-- vale gitlab.Spelling = NO -->
-
-| Role | Who
-|------------------------------|-------------------------|
-| Author | Grzegorz Bizon |
-| Architecture Evolution Coach | Gerardo Lopez-Fernandez |
-| Engineering Leader | Darby Frey |
-| Domain Expert | Kamil Trzciński |
-| Domain Expert | Sean McGivern |
-
-DRIs:
-
-| Role | Who
-|------------------------------|------------------------|
-| Product | Thao Yeager |
-| Leadership | Darby Frey |
-| Engineering | Grzegorz Bizon |
-
-<!-- vale gitlab.Spelling = YES -->
diff --git a/doc/architecture/blueprints/cloud_native_gitlab_pages/index.md b/doc/architecture/blueprints/cloud_native_gitlab_pages/index.md
index 127badabb71..b6f3a59dc0b 100644
--- a/doc/architecture/blueprints/cloud_native_gitlab_pages/index.md
+++ b/doc/architecture/blueprints/cloud_native_gitlab_pages/index.md
@@ -1,9 +1,11 @@
---
-stage: none
-group: unassigned
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-comments: false
-description: 'Making GitLab Pages a Cloud Native application - architecture blueprint.'
+status: implemented
+creation-date: "2019-05-16"
+authors: [ "@grzesiek" ]
+coach: "@kamil"
+approvers: [ "@ogolowinski", "@dcroft", "@vshushlin" ]
+owning-stage: "~devops::release"
+participating-stages: []
---
# GitLab Pages New Architecture
@@ -100,38 +102,3 @@ too.
[GitLab Pages Architecture](https://gitlab.com/groups/gitlab-org/-/epics/1316)
epic with detailed roadmap is also available.
-
-## Who
-
-Proposal:
-
-<!-- vale gitlab.Spelling = NO -->
-
-| Role | Who
-|------------------------------|-------------------------|
-| Author | Grzegorz Bizon |
-| Architecture Evolution Coach | Kamil Trzciński |
-| Engineering Leader | Daniel Croft |
-| Domain Expert | Grzegorz Bizon |
-| Domain Expert | Vladimir Shushlin |
-| Domain Expert | Jaime Martinez |
-
-DRIs:
-
-| Role | Who
-|------------------------------|------------------------|
-| Product | Orit Golowinski |
-| Leadership | Daniel Croft |
-| Engineering | Vladimir Shushlin |
-
-Domain Experts:
-
-| Role | Who
-|------------------------------|------------------------|
-| Domain Expert | Kamil Trzciński |
-| Domain Expert | Grzegorz Bizon |
-| Domain Expert | Vladimir Shushlin |
-| Domain Expert | Jaime Martinez |
-| Domain Expert | Krasimir Angelov |
-
-<!-- vale gitlab.Spelling = YES -->
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 4111e2ef056..53f38fa85fd 100644
--- a/doc/architecture/blueprints/composable_codebase_using_rails_engines/index.md
+++ b/doc/architecture/blueprints/composable_codebase_using_rails_engines/index.md
@@ -1,16 +1,18 @@
---
-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
-comments: false
-description: 'Making a GitLab codebase composable - allowing to run parts of the application'
+status: proposed
+creation-date: "2021-05-19"
+authors: [ "@kamil", "@mkaeppler" ]
+coach: "@glopezfernandez"
+approvers: []
+owning-stage: "~devops::non_devops"
+participating-stages: []
---
+# Composable GitLab codebase - using Rails Engines
+
NOTE:
Due to our focus on improving the overall availability of GitLab.com and reducing tech debt, we do not have capacity to act on this blueprint. We will re-evaluate in Q1-FY23.
-# Composable GitLab codebase - using Rails Engines
-
The one of the major risks of a single codebase is an infinite growth of the whole
application. The more code being added results in not only ever increasing resource requirements
for running the application, but increased application coupling and explosion of the complexity.
@@ -585,33 +587,3 @@ to be created to ensure that we do not have explosion of engines.
- [Use nested structure to organize CI classes](https://gitlab.com/gitlab-org/gitlab/-/issues/209745)
- [WIP: Make it simple to build and use "Decoupled Services"](https://gitlab.com/gitlab-org/gitlab/-/issues/31121)
- [Rails takes awhile to boot, let's see if we can improve this](https://gitlab.com/gitlab-org/gitlab/-/issues/213992)
-
-## Who
-
-Proposal:
-
-<!-- vale gitlab.Spelling = NO -->
-
-| Role | Who
-|------------------------------|-------------------------|
-| Author | Kamil Trzciński |
-| Architecture Evolution Coach | ? |
-| Engineering Leader | ? |
-
-DRIs:
-
-| Role | Who
-|------------------------------|------------------------|
-| Product | ? |
-| Leadership | Craig Gomes |
-| Engineering | ? |
-
-Domain Experts:
-
-| Role | Who
-|------------------------------|------------------------|
-| Domain Expert | Nikola Milojevic |
-| Domain Expert | ? |
-| Domain Expert | ? |
-
-<!-- vale gitlab.Spelling = YES -->
diff --git a/doc/architecture/blueprints/consolidating_groups_and_projects/index.md b/doc/architecture/blueprints/consolidating_groups_and_projects/index.md
index 433c23bf188..0818d9b973d 100644
--- a/doc/architecture/blueprints/consolidating_groups_and_projects/index.md
+++ b/doc/architecture/blueprints/consolidating_groups_and_projects/index.md
@@ -1,9 +1,11 @@
---
-stage: none
-group: unassigned
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-comments: false
-description: Consolidating groups and projects
+status: proposed
+creation-date: "2021-02-07"
+authors: [ "@alexpooley", "@ifarkas" ]
+coach: "@grzesiek"
+approvers: [ "@m_gill", "@mushakov" ]
+owning-stage: "~devops::plan"
+participating-stages: []
---
# Consolidating Groups and Projects
@@ -143,34 +145,6 @@ The initial iteration will provide a framework to house features under `Namespac
- Start small: What are the product changes that need to be made to assist with the migration?
- Move fast: Prioritise these solution ideas, document in issues, and create a roadmap for implementation.
-## Who
-
-Proposal:
-
-<!-- vale gitlab.Spelling = NO -->
-
-| Role | Who
-|------------------------------|-------------------------------------|
-| Author | Alex Pooley, Imre Farkas |
-| Architecture Evolution Coach | Dmitriy Zaporozhets, Grzegorz Bizon |
-| Engineering Leader | Michelle Gill |
-| Domain Expert | Jan Provaznik |
-
-<!-- vale gitlab.Spelling = YES -->
-
-DRIs:
-
-<!-- vale gitlab.Spelling = NO -->
-
-| Role | Who
-|------------------------------|------------------------|
-| Product | Melissa Ushakov |
-| Leadership | Michelle Gill |
-| Engineering | Imre Farkas |
-| Design | Nick Post |
-
-<!-- vale gitlab.Spelling = YES -->
-
## Related topics
- [Workspace developer documentation](../../../development/workspace/index.md)
diff --git a/doc/architecture/blueprints/container_registry_metadata_database/index.md b/doc/architecture/blueprints/container_registry_metadata_database/index.md
index 58d59fe5737..63e27286756 100644
--- a/doc/architecture/blueprints/container_registry_metadata_database/index.md
+++ b/doc/architecture/blueprints/container_registry_metadata_database/index.md
@@ -1,9 +1,11 @@
---
-stage: Package
-group: Package
-info: To 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
-description: 'Container Registry metadata database'
+status: implemented
+creation-date: "2020-09-29"
+authors: [ "@jdrpereira" ]
+coach: "@glopezfernandez"
+approvers: [ "@trizzi", "@hswimelar" ]
+owning-stage: "~devops::package"
+participating-stages: []
---
# Container Registry Metadata Database
@@ -344,24 +346,3 @@ A more detailed list of all tasks, as well as periodic progress updates can be f
- [Gradual migration proposal for the GitLab.com container registry](https://gitlab.com/gitlab-org/container-registry/-/issues/191)
- [Create a self-serve registry deployment](https://gitlab.com/groups/gitlab-com/gl-infra/-/epics/316)
- [Database cluster for container registry](https://gitlab.com/gitlab-com/gl-infra/reliability/-/issues/11154)
-
-## Who
-
-Proposal:
-
-<!-- vale gitlab.Spelling = NO -->
-
-| Role | Who
-|------------------------------|-------------------------|
-| Author | João Pereira |
-| Architecture Evolution Coach | Gerardo Lopez-Fernandez |
-| Engineering Leader | |
-| Domain Expert | Hayley Swimelar |
-
-DRIs:
-
-| Role | Who
-|------------------------------|------------------------|
-| Product | Tim Rizzi |
-| Leadership | |
-| Engineering | João Pereira |
diff --git a/doc/architecture/blueprints/database/scalability/patterns/read_mostly.md b/doc/architecture/blueprints/database/scalability/patterns/read_mostly.md
index 6cf8e17edeb..ec236c9bfe3 100644
--- a/doc/architecture/blueprints/database/scalability/patterns/read_mostly.md
+++ b/doc/architecture/blueprints/database/scalability/patterns/read_mostly.md
@@ -8,7 +8,7 @@ description: 'Learn how to scale operating on read-mostly data at scale'
# Read-mostly data
-[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/326037) in GitLab 14.0.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/326037) in GitLab 14.0.
This document describes the *read-mostly* pattern introduced in the
[Database Scalability Working Group](https://about.gitlab.com/company/team/structure/working-groups/database-scalability/#read-mostly-data).
diff --git a/doc/architecture/blueprints/database/scalability/patterns/time_decay.md b/doc/architecture/blueprints/database/scalability/patterns/time_decay.md
index ff5f7c25ea1..93f5dffd3f5 100644
--- a/doc/architecture/blueprints/database/scalability/patterns/time_decay.md
+++ b/doc/architecture/blueprints/database/scalability/patterns/time_decay.md
@@ -8,7 +8,7 @@ description: 'Learn how to operate on large time-decay data'
# Time-decay data
-[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/326035) in GitLab 14.0.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/326035) in GitLab 14.0.
This document describes the *time-decay pattern* introduced in the
[Database Scalability Working Group](https://about.gitlab.com/company/team/structure/working-groups/database-scalability/#time-decay-data).
diff --git a/doc/architecture/blueprints/database_scaling/size-limits.md b/doc/architecture/blueprints/database_scaling/size-limits.md
index 0bb1ae9efb4..e530bd6eff0 100644
--- a/doc/architecture/blueprints/database_scaling/size-limits.md
+++ b/doc/architecture/blueprints/database_scaling/size-limits.md
@@ -117,7 +117,7 @@ limit 30;
NOTE:
In PostgreSQL context, a **physical table** is either a regular table or a partition of a partitioned table.
-In order to maintain and improve operational stability and lessen development burden, we target a **table size less than 100 GB for a physical table on GitLab.com** (including its indexes). This has numerous benefits:
+To maintain and improve operational stability and lessen development burden, we target a **table size less than 100 GB for a physical table on GitLab.com** (including its indexes). This has numerous benefits:
1. Improved query performance and more stable query plans
1. Significantly reduce vacuum run times and increase frequency of vacuum runs to maintain a healthy state - reducing overhead on the database primary
diff --git a/doc/architecture/blueprints/database_testing/index.md b/doc/architecture/blueprints/database_testing/index.md
index 3f8041ea416..fe6dcf1723d 100644
--- a/doc/architecture/blueprints/database_testing/index.md
+++ b/doc/architecture/blueprints/database_testing/index.md
@@ -1,9 +1,11 @@
---
-stage: none
-group: unassigned
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-comments: false
-description: 'Database Testing'
+status: accepted
+creation-date: "2021-02-08"
+authors: [ "@abrandl" ]
+coach: "@glopezfernandez"
+approvers: [ "@fabian", "@craig-gomes" ]
+owning-stage: "~devops::data_stores"
+participating-stages: []
---
# Database Testing
@@ -122,26 +124,3 @@ An alternative approach we have discussed and abandoned is to "scrub" and anonym
- Annotating data as "sensitive" is error prone, with the wrong anonymization approach used for a data type or one sensitive attribute accidentally not marked as such possibly leading to a data breach.
- Scrubbing not only removes sensitive data, but it also changes data distribution, which greatly affects performance of migrations and queries.
- Scrubbing heavily changes the database contents, potentially updating a lot of data, which leads to different data storage details (think MVC bloat), affecting performance of migrations and queries.
-
-## Who
-
-<!-- vale gitlab.Spelling = NO -->
-
-This effort is owned and driven by the [GitLab Database Team](https://about.gitlab.com/handbook/engineering/development/enablement/data_stores/database/) with support from the [GitLab.com Reliability Datastores](https://about.gitlab.com/handbook/engineering/infrastructure/team/reliability/) team.
-
-| Role | Who
-|------------------------------|-------------------------|
-| Author | Andreas Brandl |
-| Architecture Evolution Coach | Gerardo Lopez-Fernandez |
-| Engineering Leader | Craig Gomes |
-| Domain Expert | Yannis Roussos |
-| Domain Expert | Pat Bair |
-
-DRIs:
-
-| Role | Who
-|------------------------------|------------------------|
-| Product | Fabian Zimmer |
-| Engineering | Andreas Brandl |
-
-<!-- vale gitlab.Spelling = YES -->
diff --git a/doc/architecture/blueprints/feature_flags_development/index.md b/doc/architecture/blueprints/feature_flags_development/index.md
index 866be9d8a70..730daf56f0d 100644
--- a/doc/architecture/blueprints/feature_flags_development/index.md
+++ b/doc/architecture/blueprints/feature_flags_development/index.md
@@ -1,9 +1,11 @@
---
-stage: none
-group: unassigned
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-comments: false
-description: 'Internal usage of Feature Flags for GitLab development'
+status: accepted
+creation-date: "2020-06-10"
+authors: [ "@kamil" ]
+coach: "@glopezfernandez"
+approvers: [ "@kencjohnston", "@craig-gomes" ]
+owning-stage: "~devops::non_devops"
+participating-stages: []
---
# Architectural discussion of feature flags
@@ -118,26 +120,3 @@ These are reason why these changes are needed:
This work is being done as part of dedicated epic:
[Improve internal usage of Feature Flags](https://gitlab.com/groups/gitlab-org/-/epics/3551).
This epic describes a meta reasons for making these changes.
-
-## Who
-
-Proposal:
-
-<!-- vale gitlab.Spelling = NO -->
-
-| Role | Who
-|------------------------------|-------------------------|
-| Author | Kamil Trzciński |
-| Architecture Evolution Coach | Gerardo Lopez-Fernandez |
-| Engineering Leader | Kamil Trzciński |
-| Domain Expert | Shinya Maeda |
-
-DRIs:
-
-| Role | Who
-|------------------------------|------------------------|
-| Product | Kenny Johnston |
-| Leadership | Craig Gomes |
-| Engineering | Kamil Trzciński |
-
-<!-- vale gitlab.Spelling = YES -->
diff --git a/doc/architecture/blueprints/gitlab_to_kubernetes_communication/index.md b/doc/architecture/blueprints/gitlab_to_kubernetes_communication/index.md
index 19fd995bead..6ac67dd0f18 100644
--- a/doc/architecture/blueprints/gitlab_to_kubernetes_communication/index.md
+++ b/doc/architecture/blueprints/gitlab_to_kubernetes_communication/index.md
@@ -1,9 +1,11 @@
---
-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
-comments: false
-description: 'GitLab to Kubernetes communication'
+status: implemented
+creation-date: "2020-12-03"
+authors: [ "@ash2k" ]
+coach: "@andrewn"
+approvers: [ "@nicholasklick", "@nagyv-gitlab" ]
+owning-stage: "~devops::configure"
+participating-stages: []
---
# GitLab to Kubernetes communication **(FREE)**
@@ -137,28 +139,3 @@ flowchart LR
### Iterations
Iterations are tracked in [the dedicated epic](https://gitlab.com/groups/gitlab-org/-/epics/4591).
-
-## Who
-
-Proposal:
-
-<!-- vale gitlab.Spelling = NO -->
-
-| Role | Who
-|------------------------------|-------------------------|
-| Author | Mikhail Mazurskiy |
-| Architecture Evolution Coach | Andrew Newdigate |
-| Engineering Leader | Nicholas Klick |
-| Domain Expert | Thong Kuah |
-| Domain Expert | Graeme Gillies |
-| Security Expert | Vitor Meireles De Sousa |
-
-DRIs:
-
-| Role | Who
-|------------------------------|------------------------|
-| Product Lead | Viktor Nagy |
-| Engineering Leader | Nicholas Klick |
-| Domain Expert | Mikhail Mazurskiy |
-
-<!-- vale gitlab.Spelling = YES -->
diff --git a/doc/architecture/blueprints/graphql_api/index.md b/doc/architecture/blueprints/graphql_api/index.md
index 1ee322c412b..4b446a78541 100644
--- a/doc/architecture/blueprints/graphql_api/index.md
+++ b/doc/architecture/blueprints/graphql_api/index.md
@@ -1,8 +1,11 @@
---
-stage: none
-group: unassigned
-comments: false
-description: 'GraphQL API architecture foundation'
+status: accepted
+creation-date: "2021-01-07"
+authors: [ "@grzesiek" ]
+coach: "@kamil"
+approvers: [ "@dsatcher", "@deuley" ]
+owning-stage: "~devops::manage"
+participating-stages: []
---
# GraphQL API
@@ -155,43 +158,3 @@ state synchronization mechanisms and hooking into existing ones.
1. [Build a scalable state synchronization for GraphQL](https://gitlab.com/groups/gitlab-org/-/epics/5319)
1. [Add support for direct uploads for GraphQL](https://gitlab.com/gitlab-org/gitlab/-/issues/280819)
1. [Review GraphQL design choices related to security](https://gitlab.com/gitlab-org/security/gitlab/-/issues/339)
-
-## Status
-
-Current status: in progress.
-
-## Who
-
-Proposal:
-
-<!-- vale gitlab.Spelling = NO -->
-
-| Role | Who
-|------------------------------|-------------------------|
-| Author | Grzegorz Bizon |
-| Architecture Evolution Coach | Kamil Trzciński |
-| Engineering Leader | Darva Satcher |
-| Product Manager | Patrick Deuley |
-| Domain Expert / GraphQL | Charlie Ablett |
-| Domain Expert / GraphQL | Alex Kalderimis |
-| Domain Expert / GraphQL | Natalia Tepluhina |
-| Domain Expert / Scalability | Bob Van Landuyt |
-
-DRIs:
-
-| Role | Who
-|------------------------------|------------------------|
-| Leadership | Darva Satcher |
-| Product | Patrick Deuley |
-| Engineering | Paul Slaughter |
-
-Domain Experts:
-
-| Area | Who
-|------------------------------|------------------------|
-| Domain Expert / GraphQL | Charlie Ablett |
-| Domain Expert / GraphQL | Alex Kalderimis |
-| Domain Expert / GraphQL | Natalia Tepluhina |
-| Domain Expert / Scalability | Bob Van Landuyt |
-
-<!-- vale gitlab.Spelling = YES -->
diff --git a/doc/architecture/blueprints/image_resizing/index.md b/doc/architecture/blueprints/image_resizing/index.md
index dd7ce27f459..948378d8834 100644
--- a/doc/architecture/blueprints/image_resizing/index.md
+++ b/doc/architecture/blueprints/image_resizing/index.md
@@ -1,9 +1,11 @@
---
-stage: none
-group: unassigned
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-comments: false
-description: 'Image Resizing'
+status: implemented
+creation-date: "2020-10-21"
+authors: [ "@craig-gomes" ]
+coach: "@kamil"
+approvers: [ "@timzallmann", "@joshlambert" ]
+owning-stage: "~devops::non_devops"
+participating-stages: []
---
# Image resizing for avatars and content images
diff --git a/doc/architecture/blueprints/object_storage/index.md b/doc/architecture/blueprints/object_storage/index.md
index 7a4ecd0e5a8..61dc37d7706 100644
--- a/doc/architecture/blueprints/object_storage/index.md
+++ b/doc/architecture/blueprints/object_storage/index.md
@@ -1,8 +1,11 @@
---
-stage: none
-group: unassigned
-comments: false
-description: 'Object storage: direct_upload consolidation - architecture blueprint.'
+status: ready
+creation-date: "2021-11-18"
+authors: [ "@nolith" ]
+coach: "@glopezfernandez"
+approvers: [ "@marin" ]
+owning-stage: "~devops::data_stores"
+participating-stages: []
---
# Object storage: `direct_upload` consolidation
@@ -197,24 +200,3 @@ require one bucket.
- [Speed up the monolith, building a smart reverse proxy in Go](https://archive.fosdem.org/2020/schedule/event/speedupmonolith/): a presentation explaining a bit of workhorse history and the challenge we faced in releasing the first cloud-native installation.
- [Object Storage improvements epic](https://gitlab.com/groups/gitlab-org/-/epics/483).
- We are moving to GraphQL API, but [we do not support direct upload](https://gitlab.com/gitlab-org/gitlab/-/issues/280819).
-
-## Who
-
-Proposal:
-
-<!-- vale gitlab.Spelling = NO -->
-
-| Role | Who |
-|--------------------------------|-------------------------|
-| Author | Alessio Caiazza |
-| Architecture Evolution Coach | Gerardo Lopez-Fernandez |
-| Engineering Leader | Marin Jankovski |
-| Domain Expert / Object storage | Stan Hu |
-| Domain Expert / Security | Joern Schneeweisz |
-
-DRIs:
-
-The DRI for this blueprint is the
-[Object Storage Working Group](https://about.gitlab.com/company/team/structure/working-groups/object-storage/).
-
-<!-- vale gitlab.Spelling = YES -->
diff --git a/doc/architecture/blueprints/pods/images/iteration0-organizations-introduction.png b/doc/architecture/blueprints/pods/images/iteration0-organizations-introduction.png
new file mode 100644
index 00000000000..5725b0fa71f
--- /dev/null
+++ b/doc/architecture/blueprints/pods/images/iteration0-organizations-introduction.png
Binary files differ
diff --git a/doc/architecture/blueprints/pods/images/pods-and-fulfillment.png b/doc/architecture/blueprints/pods/images/pods-and-fulfillment.png
new file mode 100644
index 00000000000..aab8556a5d3
--- /dev/null
+++ b/doc/architecture/blueprints/pods/images/pods-and-fulfillment.png
Binary files differ
diff --git a/doc/architecture/blueprints/pods/images/term-cluster.png b/doc/architecture/blueprints/pods/images/term-cluster.png
new file mode 100644
index 00000000000..87e4d631551
--- /dev/null
+++ b/doc/architecture/blueprints/pods/images/term-cluster.png
Binary files differ
diff --git a/doc/architecture/blueprints/pods/images/term-organization.png b/doc/architecture/blueprints/pods/images/term-organization.png
new file mode 100644
index 00000000000..4c82c62b8f4
--- /dev/null
+++ b/doc/architecture/blueprints/pods/images/term-organization.png
Binary files differ
diff --git a/doc/architecture/blueprints/pods/term-pod.png b/doc/architecture/blueprints/pods/images/term-pod.png
index d8f79df2f29..d8f79df2f29 100644
--- a/doc/architecture/blueprints/pods/term-pod.png
+++ b/doc/architecture/blueprints/pods/images/term-pod.png
Binary files differ
diff --git a/doc/architecture/blueprints/pods/term-top-level-namespace.png b/doc/architecture/blueprints/pods/images/term-top-level-namespace.png
index c1cd317d878..c1cd317d878 100644
--- a/doc/architecture/blueprints/pods/term-top-level-namespace.png
+++ b/doc/architecture/blueprints/pods/images/term-top-level-namespace.png
Binary files differ
diff --git a/doc/architecture/blueprints/pods/index.md b/doc/architecture/blueprints/pods/index.md
index 01d56c483ea..3ba319d169b 100644
--- a/doc/architecture/blueprints/pods/index.md
+++ b/doc/architecture/blueprints/pods/index.md
@@ -1,15 +1,15 @@
---
-stage: enablement
-group: pods
-comments: false
-description: 'Pods'
+status: accepted
+creation-date: "2022-09-07"
+authors: [ "@fzimmer", "@DylanGriffith" ]
+coach: "@kamil"
+approvers: [ "@fzimmer" ]
+owning-stage: "~devops::enablement"
+participating-stages: []
---
# Pods
-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 Pods design. Significant aspects are not documented, though we expect to add them in the future.
## Summary
@@ -24,7 +24,7 @@ We use the following terms to describe components and properties of the Pods arc
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](term-pod.png)
+![Term Pod](images/term-pod.png)
#### Pod properties
@@ -42,7 +42,7 @@ Discouraged synonyms: GitLab instance, cluster, shard
A cluster is a collection of Pods.
-![Term Cluster](term-cluster.png)
+![Term Cluster](images/term-cluster.png)
#### Cluster properties
@@ -66,7 +66,7 @@ Organizations work under the following assumptions:
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](term-organization.png)
+![Term Organization](images/term-organization.png)
#### Organization properties
@@ -94,7 +94,7 @@ Top-level namespaces may [be replaced by workspaces](https://gitlab.com/gitlab-o
Discouraged synonyms: Root-level namespace
-![Term Top-level Namespace](term-top-level-namespace.png)
+![Term Top-level Namespace](images/term-top-level-namespace.png)
#### Top-level namespace properties
@@ -111,8 +111,8 @@ Users are available globally and not restricted to a single Pod. Users can be me
- 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 administrate organizations
-- User activity is aggregated within an organization
+- Users can administer organizations
+- User activity is aggregated in an organization
- Every user has one personal namespace
## Goals
@@ -160,6 +160,59 @@ A number of technical issues need to be resolved to implement Pods (in no partic
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.
@@ -189,7 +242,7 @@ Organizations solve the following problems:
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](iteration0-organizations-introduction.png)
+![Move to Organizations](images/iteration0-organizations-introduction.png)
#### Why would customers opt-in to Organizations?
@@ -251,28 +304,31 @@ Based on user research, we may want to change certain features to work across or
- Specific features allow for cross-organization interactions, for example forking, search.
-### Links
+## 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)
+
+## 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)
-
-### Who
-
-| Role | Who
-|------------------------------|-------------------------|
-| Author | Fabian Zimmer |
-| Architecture Evolution Coach | Kamil Trzciński |
-| Engineering Leader | TBD |
-| Product Manager | Fabian Zimmer |
-| Domain Expert / Database | TBD |
-
-DRIs:
-
-| Role | Who
-|------------------------------|------------------------|
-| Leadership | TBD |
-| Product | Fabian Zimmer |
-| Engineering | Thong Kuah |
diff --git a/doc/architecture/blueprints/pods/iteration0-organizations-introduction.png b/doc/architecture/blueprints/pods/iteration0-organizations-introduction.png
deleted file mode 100644
index 5f5cad7b169..00000000000
--- a/doc/architecture/blueprints/pods/iteration0-organizations-introduction.png
+++ /dev/null
Binary files differ
diff --git a/doc/architecture/blueprints/pods/pods-feature-data-migration.md b/doc/architecture/blueprints/pods/pods-feature-data-migration.md
new file mode 100644
index 00000000000..fad6bca45fa
--- /dev/null
+++ b/doc/architecture/blueprints/pods/pods-feature-data-migration.md
@@ -0,0 +1,82 @@
+---
+stage: enablement
+group: pods
+comments: false
+description: 'Pods: 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
+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.
+
+## 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 authorative
+ 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.
+
+### 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.
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
diff --git a/doc/architecture/blueprints/pods/pods-feature-database-sequences.md b/doc/architecture/blueprints/pods/pods-feature-database-sequences.md
new file mode 100644
index 00000000000..0a8bb4d250e
--- /dev/null
+++ b/doc/architecture/blueprints/pods/pods-feature-database-sequences.md
@@ -0,0 +1,94 @@
+---
+stage: enablement
+group: pods
+comments: false
+description: 'Pods: 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
+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
diff --git a/doc/architecture/blueprints/pods/pods-feature-git-access.md b/doc/architecture/blueprints/pods/pods-feature-git-access.md
new file mode 100644
index 00000000000..ae996281d46
--- /dev/null
+++ b/doc/architecture/blueprints/pods/pods-feature-git-access.md
@@ -0,0 +1,163 @@
+---
+stage: enablement
+group: pods
+comments: false
+description: 'Pods: Git Access'
+---
+
+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: Git Access
+
+This document describes impact of Pods architecture on all Git access (over HTTPS and SSH)
+patterns providing explanantion 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 ambigious 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).
diff --git a/doc/architecture/blueprints/pods/pods-feature-graphql.md b/doc/architecture/blueprints/pods/pods-feature-graphql.md
new file mode 100644
index 00000000000..5f8a39c0b3f
--- /dev/null
+++ b/doc/architecture/blueprints/pods/pods-feature-graphql.md
@@ -0,0 +1,94 @@
+---
+stage: enablement
+group: pods
+comments: false
+description: 'Pods: 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
+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 exensively 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
diff --git a/doc/architecture/blueprints/pods/pods-feature-organizations.md b/doc/architecture/blueprints/pods/pods-feature-organizations.md
new file mode 100644
index 00000000000..a0a87458767
--- /dev/null
+++ b/doc/architecture/blueprints/pods/pods-feature-organizations.md
@@ -0,0 +1,58 @@
+---
+stage: enablement
+group: pods
+comments: false
+description: 'Pods: 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
+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
diff --git a/doc/architecture/blueprints/pods/pods-feature-router-endpoints-classification.md b/doc/architecture/blueprints/pods/pods-feature-router-endpoints-classification.md
new file mode 100644
index 00000000000..c672342fff9
--- /dev/null
+++ b/doc/architecture/blueprints/pods/pods-feature-router-endpoints-classification.md
@@ -0,0 +1,46 @@
+---
+stage: enablement
+group: pods
+comments: false
+description: 'Pods: 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
+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 houndreds 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/pods/pods-feature-template.md b/doc/architecture/blueprints/pods/pods-feature-template.md
new file mode 100644
index 00000000000..dfae21b5406
--- /dev/null
+++ b/doc/architecture/blueprints/pods/pods-feature-template.md
@@ -0,0 +1,29 @@
+---
+stage: enablement
+group: pods
+comments: false
+description: 'Pods: Problem A'
+---
+
+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: A
+
+> TL;DR
+
+## 1. Definition
+
+## 2. Data flow
+
+## 3. Proposal
+
+## 4. Evaluation
+
+## 4.1. Pros
+
+## 4.2. Cons
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
new file mode 100644
index 00000000000..21aa72273fe
--- /dev/null
+++ b/doc/architecture/blueprints/pods/proposal-stateless-router-with-buffering-requests.md
@@ -0,0 +1,648 @@
+---
+stage: enablement
+group: pods
+comments: false
+description: 'Pods 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 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 currently 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` (ie. 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` (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.
+ 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. Stil 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 (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... 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-logged in 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. 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 10ms). Now, if your
+request is bounced back and redirected to US which has different latency
+(lets assume that roundtrip will be around 60ms) 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.
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
new file mode 100644
index 00000000000..e7520f3d6a8
--- /dev/null
+++ b/doc/architecture/blueprints/pods/proposal-stateless-router-with-routes-learning.md
@@ -0,0 +1,672 @@
+---
+stage: enablement
+group: pods
+comments: false
+description: 'Pods 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 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 currently 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-logged in 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 10ms). Now, if your
+request is bounced back and redirected to US which has different latency
+(lets assume that roundtrip will be around 60ms) 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.
diff --git a/doc/architecture/blueprints/pods/term-cluster.png b/doc/architecture/blueprints/pods/term-cluster.png
deleted file mode 100644
index f52e31b52ad..00000000000
--- a/doc/architecture/blueprints/pods/term-cluster.png
+++ /dev/null
Binary files differ
diff --git a/doc/architecture/blueprints/pods/term-organization.png b/doc/architecture/blueprints/pods/term-organization.png
deleted file mode 100644
index f605adb124d..00000000000
--- a/doc/architecture/blueprints/pods/term-organization.png
+++ /dev/null
Binary files differ
diff --git a/doc/architecture/blueprints/rate_limiting/index.md b/doc/architecture/blueprints/rate_limiting/index.md
index 2ed66f22b53..ffe0712d69b 100644
--- a/doc/architecture/blueprints/rate_limiting/index.md
+++ b/doc/architecture/blueprints/rate_limiting/index.md
@@ -1,8 +1,11 @@
---
-stage: none
-group: unassigned
-comments: false
-description: 'Next Rate Limiting Architecture'
+status: ready
+creation-date: "2022-09-08"
+authors: [ "@grzesiek", "@marshall007", "@fabiopitino", "@hswimelar" ]
+coach: "@andrewn"
+approvers: [ "@sgoldstein" ]
+owning-stage:
+participating-stages: []
---
# Next Rate Limiting Architecture
@@ -35,18 +38,6 @@ stack.
This blueprint has been written to consolidate our limits and to describe the
vision of our next rate limiting and policies enforcement architecture.
-_Disclaimer: The following 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 in this document and linked pages 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._
-
## Goals
**Implement a next architecture for rate limiting and policies definition.**
@@ -361,6 +352,31 @@ hierarchy. Choosing a proper solution will require a thoughtful research.
1. Maintain consistent features and behavior across SaaS and self-managed codebase.
1. Be mindful about a cognitive load added by the hierarchical limits, aim to reduce it.
+## Phases and iterations
+
+**Phase 1**: Compile examples of current most important application limits — Owning Team
+ a. Owning Team (in collaboration with Stage Groups) compiles a list of the
+ most important application limits used in Rails today.
+**Phase 2**: Implement Rate Limiting Framework in Rails - Owning Team
+ a. Triangulate rate limiting abstractions based on the data gathered in Phase 1
+ b. Develop YAML model for limits.
+ c. Build Rails SDK.
+ d. Create examples showcasing usage of the new rate limits SDK.
+**Phase 3**: Team Fanout of Rails SDK - Stage Groups
+ a. Individual stage groups begin using the SDK built in Phase 2 for new limit and policies.
+ b. Stage groups begin replacing historical adhoc limit implementations with the SDK.
+ c. Provides means to monitor and observe the progress of the replacement effort. Ideally this is broken down to the `feature_category` level to drive group-level buy-in -- Owning Team.
+**Phase 4**: Enable Satellite Services to Use the Rate Limiting Framework - Owning Team
+ a. Determine if the goals of Phase 4 are best met by either
+ 1. Extracting the Rails rate limiting service into a decoupled service OR
+ 2. Implementing a separate Go library which uses the same backend (eg, Redis) for rate limiting.
+**Phase 5**: SDK for Satellite Services - Owning Team
+ a. Build Golang SDK.
+ c. Create examples showcasing usage of the new rate limits SDK.
+**Phase 6**: Team Fanout for Satellite Services - Stage Groups
+ a. Individual stage groups being using the SDK built in Phase 5 for new limit and policies.
+ b. Stage groups begin replacing historical adhoc limit implementations with the SDK.
+
## Status
Request For Comments.
@@ -373,39 +389,3 @@ Request For Comments.
- 2022-07-06: A fourth, [consolidated proposal](https://gitlab.com/gitlab-org/gitlab/-/issues/364524#note_1017640650), has been submitted.
- 2022-07-12: Started working on the design document following [Architecture Evolution Workflow](https://about.gitlab.com/handbook/engineering/architecture/workflow/).
- 2022-09-08: The initial version of the blueprint has been merged.
-
-## Who
-
-Proposal:
-
-<!-- vale gitlab.Spelling = NO -->
-
-| Role | Who
-|------------------------------|-------------------------|
-| Author | Grzegorz Bizon |
-| Author | Fabio Pitino |
-| Author | Marshall Cottrell |
-| Author | Hayley Swimelar |
-| Engineering Leader | Sam Goldstein |
-| Product Manager | |
-| Architecture Evolution Coach | Andrew Newdigate |
-| Recommender | |
-| Recommender | |
-| Recommender | |
-| Recommender | |
-
-DRIs:
-
-| Role | Who
-|------------------------------|------------------------|
-| Leadership | |
-| Product | |
-| Engineering | |
-
-Domain experts:
-
-| Area | Who
-|------------------------------|------------------------|
-| | |
-
-<!-- vale gitlab.Spelling = YES -->
diff --git a/doc/architecture/blueprints/runner_scaling/index.md b/doc/architecture/blueprints/runner_scaling/index.md
index 415884449ed..24c6820f94a 100644
--- a/doc/architecture/blueprints/runner_scaling/index.md
+++ b/doc/architecture/blueprints/runner_scaling/index.md
@@ -1,8 +1,11 @@
---
-stage: none
-group: unassigned
-comments: false
-description: 'Next Runner Auto-scaling Architecture'
+status: accepted
+creation-date: "2022-01-19"
+authors: [ "@grzesiek", "@tmaczukin", "@josephburnett" ]
+coach: "@kamil"
+approvers: [ "@DarrenEastman" ]
+owning-stage: "~devops::verify"
+participating-stages: []
---
# Next Runner Auto-scaling Architecture
@@ -50,18 +53,6 @@ build on top of it to improve efficiency, reliability and availability.
We call this new mechanism the "next GitLab Runner Scaling architecture".
-_Disclaimer The following contain 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 in this document and linked pages 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._
-
## Continuing building on Docker Machine
At this moment one of our core products - GitLab Runner - and one of its most
@@ -210,7 +201,7 @@ easier to understand how it performs.
## Details
-How the abstraction for the custom provider will look exactly is something that
+How the abstraction will look exactly is something that
we will need to prototype, PoC and decide in a data-informed way. There are a
few proposals that we should describe in detail, develop requirements for, PoC
and score. We will choose the solution that seems to support our goals the
@@ -257,6 +248,10 @@ them each separately.
to the Runner system. These details are highly dependent on the VM
architecture and operating system as well as Executor type.
+See also Glossary below.
+
+#### Current state
+
The current architecture has several points of coupling between concerns.
Coupling reduces opportunities for abstraction (e.g. community supported
plugins) and increases complexity, making the code harder to understand,
@@ -391,7 +386,7 @@ for by the plugin.
Rationale: [Description of the Custom Executor Provider proposal](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/28848#note_823321515)
-### Fleeting VM provider
+### Taskscaler provider
We can introduce a more simple version of the `Machine` abstraction in the
form of a "Fleeting" interface. Fleeting provides a low-level interface to
@@ -412,6 +407,22 @@ component so it can be used by multiple Runner Executors (not just `docker+autos
Rationale: [Description of the InstanceGroup / Fleeting proposal](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/28848#note_823430883)
POC: [Merge request](https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests/3315)
+## Glossary
+
+- **[GitLab Runner](../../../development/documentation/styleguide/word_list.md#gitlab-runner)** - the software application that you can choose to install and manage, whose source code is hosted at `gitlab.com/gitlab-org/gitlab-runner`.
+- **[runners](../../../development/documentation/styleguide/word_list.md#runner-runners)** - the runner is the agent that's responsible for running GitLab CI/CD jobs in an environment and reporting the results to a GitLab instance. It /1/ retrieves jobs from GitLab, /2/ configures a local or remote build environment, and /3/ executes jobs within the provisioned environment, passing along log data and status updates to GitLab.
+- **runner manager** - the runner process is often referred to as the `Runner Manager` as it manages multiple runners, which are the `[[runners]]` workers defined in the runners `config.toml` file.
+- **executor** - a concrete environment which can be prepared and used to run a job. A new executor is created for each job.
+- **executor provider** - an implementation capable of providing executors on demand. Executor providers are registered on import and initialized once when a runner starts up.
+- **custom executor** - works as an interface between GitLab Runner and a set of binaries or shell scripts with environment variable inputs that enable executing CI jobs in any host computing environment. New custom executors can be added to the system without making any changes to the GitLab Runner codebase.
+- **custom executor provider** - a new abstraction, proposed under the custom provider heading in the plugin boundary proposal section above, which allows new executor providers to be created without modifying the GitLab Runner codebase. The protocol could be similar to custom executors or done over gRPC. This abstraction places all the mechanics of producing executors within the plugin, delegating autoscaling and lifecycle management concerns to each implementation.
+- **taskscaler** - a new library, proposed under the taskscaler provider heading in the plugin boundary proposal section above, which is parameterized with a concrete executor provider and a fleeting provider. Taskscaler is responsible for the autoscaling concern and can be used to autoscale any executor provider using any VM shape. Taskscaler is also responsible for the runner-specific aspect of VM lifecycle and keeps track of how many jobs are using a give VM and how many times a VM has been used.
+- **fleeting** - a new library proposed along with taskscaler which provides abstractions for cloud provider VMs.
+- **fleeting instance group** - the abstraction that fleeting uses to represent a pool of like VMs. This would represent a GCP IGM or an AWS ASG (without the autoscaling). Instance groups can be increased, decreased or can provide connection details for a specific VM.
+- **fleeting plugin** - a concrete implementation of a fleeting instance group representing a specific IGM or ASG (when initialized). There will be N of these, one for each provider, each in its own project. We will own and maintain the core ones but some will be community supported. A new fleeting plugin can be created without making any changes to the runner, taskscaler or fleeting code bases. This makes it analogous to the custom executor provider in terms of self-service and decoupling, but along a different line of concerns.
+- **fleeting plugin Google Compute** - the fleeting plugin which creates GCP instances. This lives in a separate project from the fleeting and taskscaler.
+- **fleeting plugin AWS** - the fleeting plugin which creates AWS instances. This lives in a separate project from the fleeting and taskscaler.
+
## Status
Status: RFC.
diff --git a/doc/architecture/blueprints/runner_tokens/index.md b/doc/architecture/blueprints/runner_tokens/index.md
new file mode 100644
index 00000000000..3f8a27e503d
--- /dev/null
+++ b/doc/architecture/blueprints/runner_tokens/index.md
@@ -0,0 +1,227 @@
+---
+stage: Verify
+group: Runner
+comments: false
+description: 'Next Runner Token Architecture'
+---
+
+# Next GitLab Runner Token Architecture
+
+## Summary
+
+GitLab Runner is a core component of GitLab CI/CD that runs
+CI/CD jobs in a reliable and concurrent environment. Ever since the beginnings
+of the service as a Ruby program, runners are registered in a GitLab instance with
+a registration token - a randomly generated string of text. The registration token is unique for its given scope
+(instance, group, or project). The registration token proves that the party that registers the runner has
+administrator access to the instance, group, or project to which the runner is registered.
+
+This approach has worked well in the initial years, but some major known issues started to
+become apparent as the target audience grew:
+
+| Problem | Symptoms |
+|---------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Single token per scope | - The registration token is shared by multiple runners: <br/>- Single tokens lower the value of auditing and make traceability almost impossible; <br/>- Copied in many places for [self-registration of runners](https://docs.gitlab.com/runner/install/kubernetes.html#required-configuration); <br/>- Reports of users storing tokens in unsecured locations; <br/>- Makes rotation of tokens costly. <br/>- In the case of a security event affecting the whole instance, rotating tokens requires users to update a table of projects/namespaces, which takes a significant amount of time. |
+| No provision for automatic expiration | Requires manual intervention to change token. Addressed in [#30942](https://gitlab.com/gitlab-org/gitlab/-/issues/30942). |
+| No permissions model | Used to register a runner for protected branches, and for any tags. In this case, the registration token has permission to do everything. Effectively, someone taking a possession of registration token could steal secrets or source code. |
+| No traceability | Given that the token is not created by a user, and is accessible to all administrators, there is no possibility to know the source of a leaked token. |
+| No historical records | When reset, the previous value of the registration token is not stored so there is no historical data to enable deeper auditing and inspection. |
+| Token stored in project/namespace model | Inadvertent disclosure of token is possible. |
+| Too many registered runners | It is too straightforward to register a new runner using a well-known registration token. |
+
+In light of these issues, it is important that we redesign the way in which we connect runners to the GitLab instance so that we can guarantee traceability, security, and performance.
+
+We call this new mechanism the "next GitLab Runner Token architecture".
+
+## Proposal
+
+The proposal addresses the issues of a _single token per scope_ and _token storage_
+by eliminating the need for a registration token. Runner creation happens
+in the GitLab Runners settings page for the given scope, in the context of the logged-in user
+, which provides traceability. The page provides instructions to configure the newly-created
+runner in supported environments.
+
+The runner configuration will be generated through a new `deploy` command, which will leverage
+the `/runners/verify` REST endpoint to ensure the validity of the authentication token.
+The remaining concerns become non-issues due to the elimination of the registration token.
+
+The configuration can be applied across many machines by reusing the same instructions.
+A unique system identifier will be generated automatically if a value is missing from
+the runner entry in the `config.toml` file. This allows differentiating systems sharing the same
+runner token (for example, in auto-scaling scenarios), and is crucial for the proper functioning of our
+long-polling mechanism when the same authentication token is shared across two or more runner managers.
+
+Given that the creation of runners involves user interaction, it should be possible
+to eventually lower the per-plan limit of CI runners that can be registered per scope.
+
+### Auto-scaling scenarios (for example Helm chart)
+
+In the existing model, a new runner is created whenever a new worker is required. This
+has led to many situations where runners are left behind and become stale.
+
+In the proposed model, a `ci_runners` table entry describes a configuration,
+which the runner could reuse across multiple machines. This allows differentiating the context in
+which the runner is being used. In situations where we must differentiate between runners
+that reuse the same configuration, we can use the unique system identifier to track all
+unique "runners" that are executed in context of a single `ci_runners` model. This unique
+system identifier would be present in the Runner's `config.toml` configuration file and
+initially set when generating the new `[[runners]]` configuration by means of the `deploy` command.
+Legacy files that miss values for unique system identifiers will get rewritten automatically with new values.
+
+### Runner identification in CI jobs
+
+For users to identify the machine where the job was executed, the unique identifier will need to be visible in CI job contexts.
+As a first iteration, GitLab Runner will include the unique system identifier in the build logs,
+wherever it publishes the short token SHA.
+
+Given that the runner will potentially be reused with different unique system identifiers,
+we can store the unique system ID. This ensures the unique system ID maps to a GitLab Runner's `config.toml` entry with
+the runner token. The `ci_runner_machines` would hold information about each unique runner machine,
+with information when runner last connected, and what type of runner it was. The relevant fields
+will be moved from the `ci_runners`.
+The `ci_builds_runner_session` (or `ci_builds` or `ci_builds_metadata`) will reference
+`ci_runner_machines`.
+We might consider a more efficient way to store `contacted_at` than updating the existing record.
+
+```sql
+CREATE TABLE ci_builds_runner_session (
+ ...
+ runner_machine_id bigint NOT NULL
+);
+
+CREATE TABLE ci_runner_machines (
+ id integer NOT NULL,
+ machine_id character varying UNIQUE NOT NULL,
+ contacted_at timestamp without time zone,
+ version character varying,
+ revision character varying,
+ platform character varying,
+ architecture character varying,
+ ip_address character varying,
+ executor_type smallint,
+);
+```
+
+## Advantages
+
+- Easier for users to wrap their minds around the concept: instead of two types of tokens,
+ there is a single type of token - the per-runner authentication token. Having two types of tokens
+ frequently results in misunderstandings when discussing issues;
+- Runners can always be traced back to the user who created it, using the audit log;
+- The claims of a CI runner are known at creation time, and cannot be changed from the runner
+ (for example, changing the `access_level`/`protected` flag). Authenticated users
+ may however still edit these settings through the GitLab UI.
+
+## Details
+
+In the proposed approach, we create a distinct way to configure runners that is usable
+alongside the current registration token method during a transition period. The idea is
+to avoid having the Runner make API calls that allow it to leverage a single "god-like"
+token to register new runners.
+
+The new workflow looks as follows:
+
+ 1. The user opens the Runners settings page;
+ 1. The user fills in the details regarding the new desired runner, namely description,
+ tags, protected, locked, etc.;
+ 1. The user clicks `Create`. That results in the following:
+
+ 1. Creates a new runner in the `ci_runners` table (and corresponding authentication token);
+ 1. Presents the user with instructions on how to configure this new runner on a machine,
+ with possibilities for different supported deployment scenarios (e.g. shell, `docker-compose`, Helm chart, etc.)
+ This information contains a token which will only be available to the user once, and the UI
+ will make it clear to the user that the value will not be shown again, as registering the same runner multiple times
+ is discouraged (though not impossible).
+
+ 1. The user copies and pastes the instructions for the intended deployment scenario (a `deploy` command), leading to the following actions:
+
+ 1. Upon executing the new `gitlab-runner deploy` command in the instructions, `gitlab-runner` will perform
+ a call to the `POST /runners/verify` with the given runner token;
+ 1. If the `POST /runners/verify` GitLab endpoint validates the token, the `config.toml` file will be populated with the configuration.
+
+ The `gitlab-runner deploy` will also accept executor-specific arguments
+ currently present in the `register` command.
+
+As part of the transition period, we will provide admins and top-level group owners with a instance/group-level setting to disable
+the legacy registration token functionality and enforce using only the new workflow.
+Any attempt by a `gitlab-runner register` command to hit the `POST /runners` endpoint to register a new runner
+will result in a `HTTP 410 - Gone` status code. The instance setting is inherited by the groups
+, which means that if the legacy registration method is disabled at the instance method, the descendant groups/projects will also mandatorily
+prevent the legacy registration method.
+
+The registration token workflow is to be deprecated (with a deprecation notice printed by the `gitlab-runner register` command)
+and removed at a future major release after the concept is proven stable and customers have migrated to the new workflow.
+
+### Handling of legacy runners
+
+Legacy versions of GitLab Runner will not send the unique system identifier in its requests, and we
+will not change logic in Workhorse to handle unique system IDs. This can be improved upon in the
+future once the legacy registration system is removed, and runners have been upgraded to newer
+versions.
+
+Not using the unique system ID means that all connected runners with the same token will be
+notified, instead of just the runner matching the exact system identifier. While not ideal, this is
+not an issue per-se.
+
+### Helm chart
+
+The `runnerRegistrationToken` entry in the [`values.yaml` file](https://gitlab.com/gitlab-org/charts/gitlab-runner/-/blob/a70bc29a903b79d5675bb0c45d981adf8b7a8659/values.yaml#L52)
+will be retired. The `runnerRegistrationToken` entry will be replaced by the existing `runnerToken` value, which will be passed
+to the new `gitlab-runner deploy` command in [`configmap.yaml`](https://gitlab.com/gitlab-org/charts/gitlab-runner/-/blob/a70bc29a903b79d5675bb0c45d981adf8b7a8659/templates/configmap.yaml#L116).
+
+### Runner creation through API
+
+Automated runner creation may be allowed, although always through authenticated API calls -
+using PAT tokens for example - such that every runner is associated with an owner.
+
+## Implementation plan
+
+| Component | Milestone | Changes |
+|------------------|-----------|---------|
+| GitLab Rails app | `15.x` (latest at `15.6`) | Deprecate `POST /api/v4/runners` endpoint for `16.0`. This hinges on a [proposal](https://gitlab.com/gitlab-org/gitlab/-/issues/373774) to allow deprecating REST API endpoints for security reasons. |
+| GitLab Runner | `15.x` (latest at `15.8`) | Add deprecation notice for `register` command for `16.0`. |
+| GitLab Runner | `15.x` | Ensure all runner entries in `config.toml` have unique system identifier values assigned. Log new system ID values with `INFO` level as they get created. |
+| GitLab Runner | `15.x` | Start additionally logging unique system ID anywhere we log the runner short SHA. |
+| GitLab Rails app | `15.x` | Create database migrations to add settings from `application_settings` and `namaspace_settings` tables. |
+| GitLab Runner | `15.x` | Start sending `unique_id` value in `POST /jobs/request` request and other follow-up requests that require identifying the unique system. |
+| GitLab Runner | `15.x` | Implement new user-authenticated API (REST and GraphQL) to create a new runner. |
+| GitLab Rails app | `15.x` | Implement UI to create new runner. |
+| GitLab Runner | `16.0` | Remove `register` command and support for `POST /runners` endpoint. |
+| GitLab Rails app | `16.0` | Remove legacy UI showing registration with a registration token. |
+| GitLab Rails app | `16.0` | Create database migrations to remove settings from `application_settings` and `namaspace_settings` tables. |
+| GitLab Rails app | `16.0` | Make [`POST /api/v4/runners` endpoint](../../../api/runners.md#register-a-new-runner-deprecated) permanently return `410 Gone`. A future v5 version of the API would return `404 Not Found`. |
+| GitLab Rails app | `16.0` | Start refusing job requests that don't include a unique ID. |
+
+## Status
+
+Status: RFC.
+
+## Who
+
+Proposal:
+
+<!-- vale gitlab.Spelling = NO -->
+
+| Role | Who
+|------------------------------|--------------------------------------------------|
+| Authors | Kamil Trzciński, Tomasz Maczukin, Pedro Pombeiro |
+| Architecture Evolution Coach | Kamil Trzciński |
+| Engineering Leader | Elliot Rushton, Cheryl Li |
+| Product Manager | Darren Eastman, Jackie Porter |
+| Domain Expert / Runner | Tomasz Maczukin |
+
+DRIs:
+
+| Role | Who |
+|------------------------------|---------------------------------|
+| Leadership | Elliot Rushton |
+| Product | Darren Eastman |
+| Engineering | Tomasz Maczukin, Pedro Pombeiro |
+
+Domain experts:
+
+| Area | Who |
+|------------------------------|-----------------|
+| Domain Expert / Runner | Tomasz Maczukin |
+
+<!-- vale gitlab.Spelling = YES -->
diff --git a/doc/architecture/blueprints/work_items/index.md b/doc/architecture/blueprints/work_items/index.md
index 42864e7112e..75a9d8d76ad 100644
--- a/doc/architecture/blueprints/work_items/index.md
+++ b/doc/architecture/blueprints/work_items/index.md
@@ -1,15 +1,15 @@
---
-stage: Plan
-group: Project Management
-comments: false
-description: 'Work Items'
+status: accepted
+creation-date: "2022-09-28"
+authors: [ "@ntepluhina" ]
+coach: "@kamil"
+approvers: [ "@gweaver" ]
+owning-stage: "~devops::plan"
+participating-stages: []
---
# Work Items
-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. Some aspects are not documented, though we expect to add them in the future.
## Summary
@@ -55,14 +55,19 @@ All Work Item types share the same pool of predefined widgets and are customized
### Work Item widget types (updating)
-- assignees
-- description
-- hierarchy
-- iteration
-- labels
-- start and due date
-- verification status
-- weight
+| widget type | feature flag |
+|---|---|---|
+| assignees | |
+| description | |
+| hierarchy | |
+| [iteration](https://gitlab.com/gitlab-org/gitlab/-/issues/367456) | work_items_mvc_2 |
+| [milestone](https://gitlab.com/gitlab-org/gitlab/-/issues/367463) | work_items_mvc_2 |
+| labels | |
+| start and due date | |
+| status\* | |
+| weight | |
+
+\* status is not currently a widget, but a part of the root work item, similar to title
### Work Item view
@@ -72,6 +77,16 @@ The new frontend view that renders Work Items of any type using global Work Item
Task is a special Work Item type. Tasks can be added to issues as child items and can be displayed in the modal on the issue view.
+### Feature flags
+
+Since this is a large project with numerous moving parts, feature flags are being used to track promotions of available widgets. The table below shows the different feature flags that are being used, and the audience that they are available to.
+
+| feature flag name | audience |
+|---|---|
+| `work_items` | defaulted to on |
+| `work_items_mvc` | `gitlab-org`, `gitlab-com` |
+| `work_items_mvc_2` | `gitlab-org/plan-stage` |
+
## Motivation
Work Items main goal is to enhance the planning toolset to become the most popular collaboration tool for knowledge workers in any industry.
@@ -107,24 +122,3 @@ Work Item architecture is designed with making all the features for all the type
- [Tasks roadmap](https://gitlab.com/groups/gitlab-org/-/epics/7103?_gl=1*zqatx*_ga*NzUyOTc3NTc1LjE2NjEzNDcwMDQ.*_ga_ENFH3X7M5Y*MTY2MjU0MDQ0MC43LjEuMTY2MjU0MDc2MC4wLjAuMA..)
- [Work Item "Vision" Prototype](https://gitlab.com/gitlab-org/gitlab/-/issues/368607)
- [Work Item Discussions](https://gitlab.com/groups/gitlab-org/-/epics/7060)
-
-### Who
-
-| Role | Who
-|------------------------------|-----------------------------|
-| Author | Natalia Tepluhina |
-| Architecture Evolution Coach | Kamil Trzciński |
-| Engineering Leader | TBD |
-| Product Manager | Gabe Weaver |
-| Domain Expert / Frontend | Natalia Tepluhina |
-| Domain Expert / Backend | Heinrich Lee Yu |
-| Domain Expert / Backend | Jan Provaznik |
-| Domain Expert / Backend | Mario Celi |
-
-DRIs:
-
-| Role | Who
-|------------------------------|------------------------|
-| Leadership | TBD |
-| Product | Gabe Weaver |
-| Engineering | TBD |
diff --git a/doc/architecture/index.md b/doc/architecture/index.md
index 643f5766b0a..689ff2afaa0 100644
--- a/doc/architecture/index.md
+++ b/doc/architecture/index.md
@@ -1,9 +1,7 @@
---
-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
+feedback: false
comments: false
-description: 'Architecture Practice at GitLab'
+toc: false
---
# Architecture at GitLab
diff --git a/doc/ci/chatops/index.md b/doc/ci/chatops/index.md
index 3354c94aff2..f0efb5fc884 100644
--- a/doc/ci/chatops/index.md
+++ b/doc/ci/chatops/index.md
@@ -121,6 +121,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md b/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md
index 6256f11f1ea..a0665e1c054 100644
--- a/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md
+++ b/doc/ci/ci_cd_for_external_repos/bitbucket_integration.md
@@ -25,11 +25,11 @@ To use GitLab CI/CD with a Bitbucket Cloud repository:
- You can generate and use a [Bitbucket App Password](https://support.atlassian.com/bitbucket-cloud/docs/app-passwords/) for the password field.
GitLab imports the repository and enables [Pull Mirroring](../../user/project/repository/mirror/pull.md).
- You can check that mirroring is working in the project by going to **Settings > Repository > Mirroring repositories**.
+ You can check that mirroring is working in the project in **Settings > Repository > Mirroring repositories**.
1. In GitLab, create a
[Personal Access Token](../../user/profile/personal_access_tokens.md)
- with `api` scope. This is used to authenticate requests from the web
+ with `api` scope. The token is used to authenticate requests from the web
hook that is created in Bitbucket to notify GitLab of new commits.
1. In Bitbucket, from **Settings > Webhooks**, create a new web hook to notify
@@ -58,18 +58,14 @@ To use GitLab CI/CD with a Bitbucket Cloud repository:
1. In GitLab, from **Settings > CI/CD > Variables**, add variables to allow
communication with Bitbucket via the Bitbucket API:
- `BITBUCKET_ACCESS_TOKEN`: the Bitbucket app password created above.
+ - `BITBUCKET_ACCESS_TOKEN`: The Bitbucket app password created above. This variable should be [masked](../variables/index.md#mask-a-cicd-variable).
+ - `BITBUCKET_USERNAME`: The username of the Bitbucket account.
+ - `BITBUCKET_NAMESPACE`: Set this variable if your GitLab and Bitbucket namespaces differ.
+ - `BITBUCKET_REPOSITORY`: Set this variable if your GitLab and Bitbucket project names differ.
- `BITBUCKET_USERNAME`: the username of the Bitbucket account.
-
- `BITBUCKET_NAMESPACE`: set this if your GitLab and Bitbucket namespaces differ.
-
- `BITBUCKET_REPOSITORY`: set this if your GitLab and Bitbucket project names differ.
-
-1. In Bitbucket, add a script to push the pipeline status to Bitbucket.
-
- NOTE:
- The changes must be made in Bitbucket as any changes in the GitLab repository are overwritten by Bitbucket when GitLab next mirrors the repository.
+1. In Bitbucket, add a script that pushes the pipeline status to Bitbucket. The script
+ is created in Bitbucket, but the mirroring process copies it to the GitLab mirror. The GitLab
+ CI/CD pipeline runs the script, and pushes the status back to Bitbucket.
Create a file `build_status` and insert the script below and run
`chmod +x build_status` in your terminal to make the script executable.
@@ -125,7 +121,8 @@ To use GitLab CI/CD with a Bitbucket Cloud repository:
```
1. In Bitbucket, create a `.gitlab-ci.yml` file to use the script to push
- pipeline success and failures to Bitbucket.
+ pipeline success and failures to Bitbucket. Similar to the script added above,
+ this file is copied to the GitLab repo as part of the mirroring process.
```yaml
stages:
@@ -168,6 +165,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/ci/ci_cd_for_external_repos/github_integration.md b/doc/ci/ci_cd_for_external_repos/github_integration.md
index 18cc430c225..9933fafcb69 100644
--- a/doc/ci/ci_cd_for_external_repos/github_integration.md
+++ b/doc/ci/ci_cd_for_external_repos/github_integration.md
@@ -98,6 +98,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/ci/cloud_deployment/index.md b/doc/ci/cloud_deployment/index.md
index 83774f63566..bd9276275a7 100644
--- a/doc/ci/cloud_deployment/index.md
+++ b/doc/ci/cloud_deployment/index.md
@@ -76,7 +76,7 @@ Prerequisites:
- [Authenticate AWS with GitLab](#authenticate-gitlab-with-aws).
- Create a cluster on Amazon ECS.
-- Create related components, like an ECS service, a database on Amazon RDS, and so on.
+- Create related components, like an ECS service or a database on Amazon RDS.
- Create an ECS task definition, where the value for the `containerDefinitions[].name` attribute is
the same as the `Container name` defined in your targeted ECS service. The task definition can be:
- An existing task definition in ECS.
diff --git a/doc/ci/cloud_services/azure/index.md b/doc/ci/cloud_services/azure/index.md
index 944f95c03e2..b2f78648be9 100644
--- a/doc/ci/cloud_services/azure/index.md
+++ b/doc/ci/cloud_services/azure/index.md
@@ -16,7 +16,7 @@ Prerequisites:
- Access to an existing Azure Subscription with `Owner` access level.
- Access to the corresponding Azure Active Directory Tenant with at least the `Application Developer` access level.
-- A local installation of the [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli).
+- A local installation of the [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli).
Alternatively, you can follow all the steps below with the [Azure Cloud Shell](https://shell.azure.com/).
- A GitLab project.
@@ -27,11 +27,11 @@ To complete this tutorial:
1. [Grant permissions for the service principal](#grant-permissions-for-the-service-principal).
1. [Retrieve a temporary credential](#retrieve-a-temporary-credential).
-For more information, review Azure's documentation on [Workload identity federation](https://learn.microsoft.com/azure/active-directory/develop/workload-identity-federation).
+For more information, review Azure's documentation on [Workload identity federation](https://learn.microsoft.com/en-us/azure/active-directory/develop/workload-identity-federation).
## Create Azure AD application and service principal
-To create an [Azure AD application](https://learn.microsoft.com/cli/azure/ad/app?view=azure-cli-latest#az-ad-app-create)
+To create an [Azure AD application](https://learn.microsoft.com/en-us/cli/azure/ad/app?view=azure-cli-latest#az-ad-app-create)
and service principal:
1. In the Azure CLI, create the AD application:
@@ -43,13 +43,13 @@ and service principal:
Save the `appId` (Application client ID) output, as you need it later
to configure your GitLab CI/CD pipeline.
-1. Create a corresponding [Service Principal](https://learn.microsoft.com/cli/azure/ad/sp?view=azure-cli-latest#az-ad-sp-create):
+1. Create a corresponding [Service Principal](https://learn.microsoft.com/en-us/cli/azure/ad/sp?view=azure-cli-latest#az-ad-sp-create):
```shell
az ad sp create --id $appId --query appId -otsv
```
-Instead of the Azure CLI, you can [use the Azure Portal to create these resources](https://learn.microsoft.com/azure/active-directory/develop/howto-create-service-principal-portal).
+Instead of the Azure CLI, you can [use the Azure Portal to create these resources](https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal).
## Create Azure AD federated identity credentials
@@ -88,7 +88,7 @@ identity credentials from the Azure Portal:
## Grant permissions for the service principal
-After you create the credentials, use [`role assignment`](https://learn.microsoft.com/cli/azure/role/assignment?view=azure-cli-latest#az-role-assignment-create)
+After you create the credentials, use [`role assignment`](https://learn.microsoft.com/en-us/cli/azure/role/assignment?view=azure-cli-latest#az-role-assignment-create)
to grant permissions to the above service principal to access to Azure resources:
```shell
@@ -97,13 +97,13 @@ az role assignment create --assignee $appId --role Reader --scope /subscriptions
You can find your subscription ID in:
-- The [Azure Portal](https://learn.microsoft.com/azure/azure-portal/get-subscription-tenant-id#find-your-azure-subscription).
-- The [Azure CLI](https://learn.microsoft.com/cli/azure/manage-azure-subscriptions-azure-cli#get-the-active-subscription).
+- The [Azure Portal](https://learn.microsoft.com/en-us/azure/azure-portal/get-subscription-tenant-id#find-your-azure-subscription).
+- The [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/manage-azure-subscriptions-azure-cli#get-the-active-subscription).
## Retrieve a temporary credential
After you configure the Azure AD application and federated identity credentials,
-the CI/CD job can retrieve a temporary credential by using the [Azure CLI](https://learn.microsoft.com/cli/azure/reference-index?view=azure-cli-latest#az-login):
+the CI/CD job can retrieve a temporary credential by using the [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/reference-index?view=azure-cli-latest#az-login):
```yaml
default:
@@ -123,7 +123,7 @@ The CI/CD variables are:
- `AZURE_CLIENT_ID`: The [application client ID you saved earlier](#create-azure-ad-application-and-service-principal).
- `AZURE_TENANT_ID`: Your Azure Active Directory. You can
- [find it by using the Azure CLI or Azure Portal](https://learn.microsoft.com/azure/active-directory/fundamentals/active-directory-how-to-find-tenant).
+ [find it by using the Azure CLI or Azure Portal](https://learn.microsoft.com/en-us/azure/active-directory/fundamentals/active-directory-how-to-find-tenant).
- `CI_JOB_JWT_V2`: The JSON web token is a [predefined CI/CD variable](../../variables/predefined_variables.md).
## Troubleshooting
diff --git a/doc/ci/directed_acyclic_graph/index.md b/doc/ci/directed_acyclic_graph/index.md
index ded91edeff5..39f45471021 100644
--- a/doc/ci/directed_acyclic_graph/index.md
+++ b/doc/ci/directed_acyclic_graph/index.md
@@ -91,7 +91,7 @@ To see the needs visualization, select **Needs** when viewing a pipeline that us
![Needs visualization example](img/dag_graph_example_v13_1.png)
-Clicking a node highlights all the job paths it depends on.
+Selecting a node highlights all the job paths it depends on.
![Needs visualization with path highlight](img/dag_graph_example_clicked_v13_1.png)
diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md
index 06197d71690..ea62133cb7f 100644
--- a/doc/ci/docker/using_docker_build.md
+++ b/doc/ci/docker/using_docker_build.md
@@ -47,7 +47,7 @@ the Docker commands, but needs permission to do so.
```
1. On the server where GitLab Runner is installed, install Docker Engine.
- View a list of [supported platforms](https://docs.docker.com/engine/installation/).
+ View a list of [supported platforms](https://docs.docker.com/engine/install/).
1. Add the `gitlab-runner` user to the `docker` group:
@@ -829,7 +829,7 @@ environment = ["DOCKER_DRIVER=overlay2"]
If you're running multiple runners, you have to 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/engine/userguide/storagedriver/overlayfs-driver/).
+and [using the OverlayFS storage driver](https://docs.docker.com/storage/storagedriver/overlayfs-driver/).
## Docker alternatives
diff --git a/doc/ci/docker/using_docker_images.md b/doc/ci/docker/using_docker_images.md
index 70680a44ed2..0ba510acdbc 100644
--- a/doc/ci/docker/using_docker_images.md
+++ b/doc/ci/docker/using_docker_images.md
@@ -64,7 +64,7 @@ For example, you can set the [Docker pull policy](https://docs.gitlab.com/runner
to use local images.
For more information about images and Docker Hub, see
-the [Docker Fundamentals](https://docs.docker.com/engine/understanding-docker/) documentation.
+the [Docker overview](https://docs.docker.com/get-started/overview/).
## Define `image` in the `.gitlab-ci.yml` file
diff --git a/doc/ci/enable_or_disable_ci.md b/doc/ci/enable_or_disable_ci.md
index adb9b5a87d5..e75f902c153 100644
--- a/doc/ci/enable_or_disable_ci.md
+++ b/doc/ci/enable_or_disable_ci.md
@@ -54,6 +54,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/ci/environments/deployment_approvals.md b/doc/ci/environments/deployment_approvals.md
index 5f5ec027827..d7fa31b583b 100644
--- a/doc/ci/environments/deployment_approvals.md
+++ b/doc/ci/environments/deployment_approvals.md
@@ -64,10 +64,9 @@ co-exist and multiple approval rules takes the precedence over the unified appro
There are two ways to configure approvals for a protected environment:
-1. Using the [UI](protected_environments.md#protecting-environments)
- 1. Set the **Required approvals** field to 1 or more.
-1. Using the [REST API](../../api/protected_environments.md#protect-repository-environments)
- 2. Set the `required_approval_count` field to 1 or more.
+- Using the [UI](protected_environments.md#protecting-environments), set the **Required approvals** field to 1 or more.
+- Using the [REST API](../../api/protected_environments.md#protect-a-single-environment),
+ set the `required_approval_count` field to 1 or more.
After this is configured, all jobs deploying to this environment automatically go into a blocked state and wait for approvals before running. Ensure that the number of required approvals is less than the number of users allowed to deploy.
@@ -89,9 +88,9 @@ Maintainer role.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345678) in GitLab 14.10 with a flag named `deployment_approval_rules`. Disabled by default.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/345678) in GitLab 15.0. [Feature flag `deployment_approval_rules`](https://gitlab.com/gitlab-org/gitlab/-/issues/345678) removed.
-1. Using the [REST API](../../api/group_protected_environments.md#protect-an-environment).
- 1. `deploy_access_levels` represents which entity can execute the deployment job.
- 1. `approval_rules` represents which entity can approve the deployment job.
+- Using the [REST API](../../api/group_protected_environments.md#protect-a-single-environment).
+ - `deploy_access_levels` represents which entity can execute the deployment job.
+ - `approval_rules` represents which entity can approve the deployment job.
After this is configured, all jobs deploying to this environment automatically go into a blocked state and wait for approvals before running. Ensure that the number of required approvals is less than the number of users allowed to deploy.
@@ -138,10 +137,6 @@ To approve or reject a deployment to a protected environment using the UI:
1. Optional. Add a comment which describes your reason for approving or rejecting the deployment.
1. Select **Approve** or **Reject**.
-NOTE:
-This feature might not work as expected when [Multiple approval rules](#multiple-approval-rules) is configured.
-See the [issue](https://gitlab.com/gitlab-org/gitlab/-/issues/355708) for planned improvement.
-
### Approve or reject a deployment using the API
Prerequisites:
@@ -191,6 +186,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/ci/environments/deployment_safety.md b/doc/ci/environments/deployment_safety.md
index 665aeb23d28..1e4eb54c559 100644
--- a/doc/ci/environments/deployment_safety.md
+++ b/doc/ci/environments/deployment_safety.md
@@ -13,16 +13,20 @@ that help maintain deployment security and stability.
You can:
+- Set appropriate roles to your project. See [Project members permissions](../../user/permissions.md#project-members-permissions)
+ for the different user roles GitLab supports and the permissions of each.
- [Restrict write-access to a critical environment](#restrict-write-access-to-a-critical-environment)
- [Prevent deployments during deploy freeze windows](#prevent-deployments-during-deploy-freeze-windows)
-- [Set appropriate roles to your project](#setting-appropriate-roles-to-your-project)
- [Protect production secrets](#protect-production-secrets)
- [Separate project for deployments](#separate-project-for-deployments)
If you are using a continuous deployment workflow and want to ensure that concurrent deployments to the same environment do not happen, you should enable the following options:
- [Ensure only one deployment job runs at a time](#ensure-only-one-deployment-job-runs-at-a-time)
-- [Skip outdated deployment jobs](#skip-outdated-deployment-jobs)
+- [Prevent outdated deployment jobs](#prevent-outdated-deployment-jobs)
+
+<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
+For an overview, see [How to secure your CD pipelines/workflow](https://www.youtube.com/watch?v=Mq3C1KveDc0).
## Restrict write access to a critical environment
@@ -63,7 +67,10 @@ The improved pipeline flow **after** using the resource group:
For more information, see [Resource Group documentation](../resource_groups/index.md).
-## Skip outdated deployment jobs
+## Prevent outdated deployment jobs
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25276) in GitLab 12.9.
+> - In GitLab 15.5, the behavior was [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/363328) to prevent outdated job runs.
The effective execution order of pipeline jobs can vary from run to run, which
could cause undesired behavior. For example, a [deployment job](../jobs/index.md#deployment-jobs)
@@ -71,22 +78,46 @@ in a newer pipeline could finish before a deployment job in an older pipeline.
This creates a race condition where the older deployment finishes later,
overwriting the "newer" deployment.
-You can ensure that older deployment jobs are cancelled automatically when a newer deployment
-job is started by enabling the [Skip outdated deployment jobs](../pipelines/settings.md#skip-outdated-deployment-jobs) feature.
+You can prevent older deployment jobs from running when a newer deployment
+job is started by enabling the [Prevent outdated deployment jobs](../pipelines/settings.md#prevent-outdated-deployment-jobs) feature.
+
+When an older deployment job starts, it fails and is labeled:
+
+- `failed outdated deployment job` in the pipeline view.
+- `The deployment job is older than the latest deployment, and therefore failed.`
+ when viewing the completed job.
+
+When an older deployment job is manual, the play button is disabled with a message
+`This deployment job does not run automatically and must be started manually, but it's older than the latest deployment, and therefore can't run.`.
+
+Job age is determined by the job start time, not the commit time, so a newer commit
+can be prevented in some circumstances.
+
+### How to rollback to an outdated deployment
-Example of a problematic pipeline flow **before** enabling Skip outdated deployment jobs:
+> In GitLab 15.6, [rollback via job retry was introduced back](https://gitlab.com/gitlab-org/gitlab/-/issues/378359).
+
+In some cases, you need to rollback to an outdated deployment.
+This feature explicitly allows rollback via [Environment Rollback](index.md#environment-rollback),
+so that you can quickly rollback in an urgent case.
+
+Alternatively, you can run a new pipeline with a previous commit. It contains newer deployment jobs than the latest deployment.
+
+### Example
+
+Example of a problematic pipeline flow **before** enabling Prevent outdated deployment jobs:
1. Pipeline-A is created on the default branch.
1. Later, Pipeline-B is created on the default branch (with a newer commit SHA).
1. The `deploy` job in Pipeline-B finishes first, and deploys the newer code.
1. The `deploy` job in Pipeline-A finished later, and deploys the older code, **overwriting** the newer (latest) deployment.
-The improved pipeline flow **after** enabling Skip outdated deployment jobs:
+The improved pipeline flow **after** enabling Prevent outdated deployment jobs:
1. Pipeline-A is created on the default branch.
1. Later, Pipeline-B is created on the default branch (with a newer SHA).
1. The `deploy` job in Pipeline-B finishes first, and deploys the newer code.
-1. The `deploy` job in Pipeline-A was automatically cancelled, so that it doesn't overwrite the deployment from the newer pipeline.
+1. The `deploy` job in Pipeline-A fails, so that it doesn't overwrite the deployment from the newer pipeline.
## Prevent deployments during deploy freeze windows
@@ -95,19 +126,6 @@ vacation period when most employees are out, you can set up a [Deploy Freeze](..
During a deploy freeze period, no deployment can be executed. This is helpful to
ensure that deployments do not happen unexpectedly.
-## Setting appropriate roles to your project
-
-GitLab supports several different roles that can be assigned to your project members. See
-[Project members permissions](../../user/permissions.md#project-members-permissions)
-for an explanation of these roles and the permissions of each.
-
-<div class="video-fallback">
- See the video: <a href="https://www.youtube.com/watch?v=Mq3C1KveDc0">How to secure your CD pipelines</a>.
-</div>
-<figure class="video-container">
- <iframe src="https://www.youtube.com/embed/Mq3C1KveDc0" frameborder="0" allowfullscreen="true"> </iframe>
-</figure>
-
## Protect production secrets
Production secrets are needed to deploy successfully. For example, when deploying to the cloud,
@@ -153,7 +171,7 @@ Before promoting a deployment to a production environment, cross-verifying it wi
### Pipelines jobs fail with `The deployment job is older than the previously succeeded deployment job...`
-This is caused by the [Skip outdated deployment jobs](../pipelines/settings.md#skip-outdated-deployment-jobs) feature.
+This is caused by the [Prevent outdated deployment jobs](../pipelines/settings.md#prevent-outdated-deployment-jobs) feature.
If you have multiple jobs for the same environment (including non-deployment jobs), you might encounter this problem, for example:
```yaml
@@ -166,5 +184,5 @@ build:service-b:
name: production
```
-The [Skip outdated deployment jobs](../pipelines/settings.md#skip-outdated-deployment-jobs) might
+The [Prevent outdated deployment jobs](../pipelines/settings.md#prevent-outdated-deployment-jobs) might
not work well with this configuration, and must be disabled.
diff --git a/doc/ci/environments/environments_dashboard.md b/doc/ci/environments/environments_dashboard.md
index f662c156f55..479b783202d 100644
--- a/doc/ci/environments/environments_dashboard.md
+++ b/doc/ci/environments/environments_dashboard.md
@@ -29,7 +29,7 @@ The Environments dashboard displays a paginated list of projects that includes
up to three environments per project.
The listed environments for each project are unique, such as
-"production", "staging", and so on. Review apps and other grouped
+"production" and "staging". Review apps and other grouped
environments are not displayed.
## Adding a project to the dashboard
diff --git a/doc/ci/environments/incremental_rollouts.md b/doc/ci/environments/incremental_rollouts.md
index af431a9812e..10cda68c4b5 100644
--- a/doc/ci/environments/incremental_rollouts.md
+++ b/doc/ci/environments/incremental_rollouts.md
@@ -76,7 +76,7 @@ available, demonstrating manually triggered incremental rollouts.
## Timed Rollouts
Timed rollouts behave in the same way as manual rollouts, except that each job is defined with a
-delay in minutes before it deploys. Clicking the job reveals the countdown.
+delay in minutes before it deploys. Selecting the job reveals the countdown.
![Timed rollout](img/timed_rollout_v12_7.png)
diff --git a/doc/ci/environments/index.md b/doc/ci/environments/index.md
index 63641a9b7c3..c4672b9dc7e 100644
--- a/doc/ci/environments/index.md
+++ b/doc/ci/environments/index.md
@@ -178,7 +178,7 @@ deploy_prod:
The `when: manual` action:
- Exposes a play button for the job in the GitLab UI, with the text **Can be manually deployed to &lt;environment&gt;**.
-- Means the `deploy_prod` job is only triggered when the play button is clicked.
+- Means the `deploy_prod` job is only triggered when the play button is selected.
You can find the play button in the pipelines, environments, deployments, and jobs views.
@@ -383,6 +383,11 @@ To retry or rollback a deployment:
- To retry a deployment, select **Re-deploy to environment**.
- To roll back to a deployment, next to a previously successful deployment, select **Rollback environment**.
+NOTE:
+If you have [prevented outdated deployment jobs](deployment_safety.md#prevent-outdated-deployment-jobs) in your project,
+the rollback buttons might be hidden or disabled.
+In this case, see [how to rollback to an outdated deployment](deployment_safety.md#how-to-rollback-to-an-outdated-deployment).
+
### Environment URL
> - [Fixed](https://gitlab.com/gitlab-org/gitlab/-/issues/337417) to persist arbitrary URLs in GitLab 15.2 [with a flag](../../administration/feature_flags.md) named `soft_validation_on_external_url`. Disabled by default.
@@ -721,7 +726,7 @@ build:
```
This gives you access to environment-scoped variables, and can be used to protect builds from unauthorized access. Also,
-it's effective to avoid the [skip outdated deployment jobs](deployment_safety.md#skip-outdated-deployment-jobs) feature.
+it's effective to avoid the [prevent outdated deployment jobs](deployment_safety.md#prevent-outdated-deployment-jobs) feature.
### Group similar environments
@@ -1063,8 +1068,8 @@ To fix this, use one of the following solutions:
- Remove `environment` keyword from the deployment job. GitLab has already been
ignoring the invalid keyword, therefore your deployment pipelines stay intact
even after the keyword removal.
-- Ensure the variable exists in the pipeline. Please note that there is
- [a limitation on supported variables](../variables/where_variables_can_be_used.md#gitlab-ciyml-file).
+- Ensure the variable exists in the pipeline. Review the
+ [limitation on supported variables](../variables/where_variables_can_be_used.md#gitlab-ciyml-file).
#### If you get this error on Review Apps
@@ -1107,6 +1112,6 @@ to execute the following command on Rails console:
Project.find_by_full_path(<your-project-full-path>).deployments.where(archived: true).each(&:create_ref)
```
-Please note that GitLab could drop this support in the future for the performance concern.
+GitLab might drop this support in the future for the performance concern.
You can open an issue in [GitLab Issue Tracker](https://gitlab.com/gitlab-org/gitlab/-/issues/new)
to discuss the behavior of this feature.
diff --git a/doc/ci/environments/protected_environments.md b/doc/ci/environments/protected_environments.md
index 0f943679c07..5c120da32a0 100644
--- a/doc/ci/environments/protected_environments.md
+++ b/doc/ci/environments/protected_environments.md
@@ -26,7 +26,7 @@ Maintainer role.
Prerequisites:
-- When granting the **Allowed to deploy** permission to a group or subgroup, the user configuring the protected environment must be a **direct member** of the group or subgroup to be added. Otherwise, the group or subgroup will not show up in the dropdown. For more information see [issue #345140](https://gitlab.com/gitlab-org/gitlab/-/issues/345140).
+- When granting the **Allowed to deploy** permission to a group or subgroup, the user configuring the protected environment must be a **direct member** of the group or subgroup to be added. Otherwise, the group or subgroup will not show up in the dropdown list. For more information see [issue #345140](https://gitlab.com/gitlab-org/gitlab/-/issues/345140).
To protect an environment:
@@ -147,7 +147,7 @@ Maintainers can:
- Update existing protected environments at any time by changing the access in the
**Allowed to Deploy** dropdown list.
-- Unprotect a protected environment by clicking the **Unprotect** button for that environment.
+- Unprotect a protected environment by selecting the **Unprotect** button for that environment.
After an environment is unprotected, all access entries are deleted and must
be re-entered if the environment is re-protected.
diff --git a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
index 59e377dbb09..7208caaccae 100644
--- a/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
+++ b/doc/ci/examples/authenticating-with-hashicorp-vault/index.md
@@ -29,7 +29,7 @@ You must replace the `vault.example.com` URL below with the URL of your Vault se
## How it works
-Each job has JSON Web Token (JWT) provided as CI/CD variable named `CI_JOB_JWT`. This JWT can be used to authenticate with Vault using the [JWT Auth](https://www.vaultproject.io/docs/auth/jwt#jwt-authentication) method.
+Each job has JSON Web Token (JWT) provided as CI/CD variable named `CI_JOB_JWT`. This JWT can be used to authenticate with Vault using the [JWT Auth](https://developer.hashicorp.com/vault/docs/auth/jwt#jwt-authentication) method.
The following fields are included in the JWT:
@@ -90,7 +90,7 @@ The JWT is encoded by using RS256 and signed with a dedicated private key. The e
You can use this JWT and your instance's JWKS endpoint (`https://gitlab.example.com/-/jwks`) to authenticate with a Vault server that is configured to allow the JWT Authentication method for authentication.
-When configuring roles in Vault, you can use [bound_claims](https://www.vaultproject.io/docs/auth/jwt#bound-claims) to match against the JWT's claims and restrict which secrets each CI job has access to.
+When configuring roles in Vault, you can use [bound_claims](https://developer.hashicorp.com/vault/docs/auth/jwt#bound-claims) to match against the JWT's claims and restrict which secrets each CI job has access to.
To communicate with Vault, you can use either its CLI client or perform API requests (using `curl` or another client).
@@ -109,7 +109,7 @@ $ vault kv get -field=password secret/myproject/production/db
real-pa$$w0rd
```
-To configure your Vault server, start by enabling the [JWT Auth](https://www.vaultproject.io/docs/auth/jwt) method:
+To configure your Vault server, start by enabling the [JWT Auth](https://developer.hashicorp.com/vault/docs/auth/jwt) method:
```shell
$ vault auth enable jwt
@@ -180,17 +180,17 @@ $ vault write auth/jwt/role/myproject-production - <<EOF
EOF
```
-This example uses [bound_claims](https://www.vaultproject.io/api-docs/auth/jwt#bound_claims) to specify that only a JWT with matching values for the specified claims is allowed to authenticate.
+This example uses [bound_claims](https://developer.hashicorp.com/vault/api-docs/auth/jwt#bound_claims) to specify that only a JWT with matching values for the specified claims is allowed to authenticate.
Combined with [protected branches](../../../user/project/protected_branches.md), you can restrict who is able to authenticate and read the secrets.
-[`token_explicit_max_ttl`](https://www.vaultproject.io/api-docs/auth/jwt#token_explicit_max_ttl) specifies that the token issued by Vault, upon successful authentication, has a hard lifetime limit of 60 seconds.
+[`token_explicit_max_ttl`](https://developer.hashicorp.com/vault/api-docs/auth/jwt#token_explicit_max_ttl) specifies that the token issued by Vault, upon successful authentication, has a hard lifetime limit of 60 seconds.
-[`user_claim`](https://www.vaultproject.io/api-docs/auth/jwt#user_claim) specifies the name for the Identity alias created by Vault upon a successful login.
+[`user_claim`](https://developer.hashicorp.com/vault/api-docs/auth/jwt#user_claim) specifies the name for the Identity alias created by Vault upon a successful login.
-[`bound_claims_type`](https://www.vaultproject.io/api-docs/auth/jwt#bound_claims_type) configures the interpretation of the `bound_claims` values. If set to `glob`, the values are interpreted as globs, with `*` matching any number of characters.
+[`bound_claims_type`](https://developer.hashicorp.com/vault/api-docs/auth/jwt#bound_claims_type) configures the interpretation of the `bound_claims` values. If set to `glob`, the values are interpreted as globs, with `*` matching any number of characters.
-The claim fields listed in [the table above](#how-it-works) can also be accessed for [Vault's policy path templating](https://learn.hashicorp.com/tutorials/vault/policy-templating?in=vault/policies) purposes by using the accessor name of the JWT auth within Vault. The [mount accessor name](https://learn.hashicorp.com/tutorials/vault/identity#step-1-create-an-entity-with-alias) (`ACCESSOR_NAME` in the example below) can be retrieved by running `vault auth list`.
+The claim fields listed in [the table above](#how-it-works) can also be accessed for [Vault's policy path templating](https://developer.hashicorp.com/vault/tutorials/policies/policy-templating?in=vault%2Fpolicies) purposes by using the accessor name of the JWT auth within Vault. The [mount accessor name](https://developer.hashicorp.com/vault/tutorials/auth-methods/identity#step-1-create-an-entity-with-alias) (`ACCESSOR_NAME` in the example below) can be retrieved by running `vault auth list`.
Policy template example making use of a named metadata field named `project_path`:
@@ -200,7 +200,7 @@ path "secret/data/{{identity.entity.aliases.ACCESSOR_NAME.metadata.project_path}
}
```
-Role example to support the templated policy above, mapping the claim field `project_path` as a metadata field through use of [`claim_mappings`](https://www.vaultproject.io/api-docs/auth/jwt#claim_mappings) configuration:
+Role example to support the templated policy above, mapping the claim field `project_path` as a metadata field through use of [`claim_mappings`](https://developer.hashicorp.com/vault/api-docs/auth/jwt#claim_mappings) configuration:
```plaintext
{
@@ -212,7 +212,7 @@ Role example to support the templated policy above, mapping the claim field `pro
}
```
-For the full list of options, see Vault's [Create Role documentation](https://www.vaultproject.io/api-docs/auth/jwt#create-role).
+For the full list of options, see Vault's [Create Role documentation](https://developer.hashicorp.com/vault/api-docs/auth/jwt#create-role).
WARNING:
Always restrict your roles to project or namespace by using one of the provided claims (for example, `project_id` or `namespace_id`). Otherwise any JWT generated by this instance may be allowed to authenticate using this role.
@@ -225,9 +225,9 @@ $ vault write auth/jwt/config \
bound_issuer="gitlab.example.com"
```
-[bound_issuer](https://www.vaultproject.io/api-docs/auth/jwt#bound_issuer) specifies that only a JWT with the issuer (that is, the `iss` claim) set to `gitlab.example.com` can use this method to authenticate, and that the JWKS endpoint (`https://gitlab.example.com/-/jwks`) should be used to validate the token.
+[bound_issuer](https://developer.hashicorp.com/vault/api-docs/auth/jwt#bound_issuer) specifies that only a JWT with the issuer (that is, the `iss` claim) set to `gitlab.example.com` can use this method to authenticate, and that the JWKS endpoint (`https://gitlab.example.com/-/jwks`) should be used to validate the token.
-For the full list of available configuration options, see Vault's [API documentation](https://www.vaultproject.io/api-docs/auth/jwt#configure).
+For the full list of available configuration options, see Vault's [API documentation](https://developer.hashicorp.com/vault/api-docs/auth/jwt#configure).
The following job, when run for the default branch, is able to read secrets under `secret/myproject/staging/`, but not the secrets under `secret/myproject/production/`:
@@ -242,7 +242,7 @@ read_secrets:
# Vault's address can be provided here or as CI/CD variable
- export VAULT_ADDR=http://vault.example.com:8200
# Authenticate and get token. Token expiry time and other properties can be configured
- # when configuring JWT Auth - https://www.vaultproject.io/api-docs/auth/jwt#parameters-1
+ # when configuring JWT Auth - https://developer.hashicorp.com/vault/api-docs/auth/jwt#parameters-1
- export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=myproject-staging jwt=$CI_JOB_JWT)"
# Now use the VAULT_TOKEN to read the secret and store it in an environment variable
- export PASSWORD="$(vault kv get -field=password secret/myproject/staging/db)"
@@ -271,7 +271,7 @@ read_secrets:
# Vault's address can be provided here or as CI/CD variable
- export VAULT_ADDR=http://vault.example.com:8200
# Authenticate and get token. Token expiry time and other properties can be configured
- # when configuring JWT Auth - https://www.vaultproject.io/api-docs/auth/jwt#parameters-1
+ # when configuring JWT Auth - https://developer.hashicorp.com/vault/api-docs/auth/jwt#parameters-1
- export VAULT_TOKEN="$(vault write -field=token auth/jwt/login role=myproject-production jwt=$CI_JOB_JWT)"
# Now use the VAULT_TOKEN to read the secret and store it in environment variable
- export PASSWORD="$(vault kv get -field=password secret/myproject/production/db)"
@@ -286,11 +286,11 @@ read_secrets:
You can control `CI_JOB_JWT` access to Vault secrets by using Vault protections
and GitLab features. For example, restrict the token by:
-- Using Vault [bound_claims](https://www.vaultproject.io/docs/auth/jwt#bound-claims)
+- Using Vault [bound_claims](https://developer.hashicorp.com/vault/docs/auth/jwt#bound-claims)
for specific groups using `group_claim`.
- Hard coding values for Vault bound claims based on the `user_login` and `user_email`
of specific users.
-- Setting Vault time limits for TTL of the token as specified in [`token_explicit_max_ttl`](https://www.vaultproject.io/api-docs/auth/jwt#token_explicit_max_ttl),
+- Setting Vault time limits for TTL of the token as specified in [`token_explicit_max_ttl`](https://developer.hashicorp.com/vault/api-docs/auth/jwt#token_explicit_max_ttl),
where the token expires after authentication.
- Scoping the JWT to [GitLab protected branches](../../../user/project/protected_branches.md)
that are restricted to a subset of project users.
diff --git a/doc/ci/examples/deployment/composer-npm-deploy.md b/doc/ci/examples/deployment/composer-npm-deploy.md
index f14372757a9..a603207aef7 100644
--- a/doc/ci/examples/deployment/composer-npm-deploy.md
+++ b/doc/ci/examples/deployment/composer-npm-deploy.md
@@ -47,7 +47,7 @@ All these operations put all files into a `build` folder, which is ready to be d
## How to transfer files to a live server
-You have multiple options: rsync, SCP, SFTP, and so on. For now, use SCP.
+You have multiple options such as rsync, SCP, or SFTP. For now, use SCP.
To make this work, you must add a GitLab CI/CD Variable (accessible on `gitlab.example/your-project-name/variables`). Name this variable `STAGING_PRIVATE_KEY` and set it to the **private** SSH key of your server.
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 e9f126b0409..7b5690e2d3d 100644
--- a/doc/ci/examples/end_to_end_testing_webdriverio/index.md
+++ b/doc/ci/examples/end_to_end_testing_webdriverio/index.md
@@ -88,7 +88,7 @@ hit our 404 page. We can then use [`browser.getUrl`](http://v4.webdriver.io/api/
to verify that the current page is indeed at the location we specified. To interact with the page,
we can pass CSS selectors to
[`browser.element`](http://v4.webdriver.io/api/protocol/element.html) to get access to elements on the
-page and to interact with them - for example, to click on the link back to the home page.
+page and to interact with them - for example, to select the link back to the home page.
The simple test shown above
can already give us a lot of confidence if it passes: we know our deployment has succeeded, that the
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 80e476f2a87..28016216dbb 100644
--- a/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
+++ b/doc/ci/examples/laravel_with_gitlab_and_envoy/index.md
@@ -444,7 +444,7 @@ On your GitLab project repository navigate to the **Registry** tab.
You may need to enable the Container Registry for your project to see this tab. You'll find it under your project's **Settings > General > Visibility, project features, permissions**.
To start using Container Registry on our machine, we first need to sign in to the GitLab registry using our GitLab username and password.
-Make sure you have [Docker](https://docs.docker.com/engine/installation/) installed on our machine,
+Make sure you have [Docker](https://docs.docker.com/engine/install/) installed on our machine,
then run the following commands:
```shell
@@ -628,11 +628,11 @@ To do that, commit and push `.gitlab-ci.yml` to the `main` branch. It will trigg
Here we see our **Test** and **Deploy** stages.
The **Test** stage has the `unit_test` build running.
-click on it to see the runner's output.
+Select it to see the runner's output.
![pipeline page](img/pipeline_page.png)
-After our code passed through the pipeline successfully, we can deploy to our production server by clicking the **play** button on the right side.
+After our code passed through the pipeline successfully, we can deploy to our production server by selecting the **play** button on the right side.
![pipelines page deploy button](img/pipelines_page_deploy_button.png)
@@ -644,7 +644,7 @@ If something doesn't work as expected, you can roll back to the latest working v
![environment page](img/environment_page.png)
-By clicking on the external link icon specified on the right side, GitLab opens the production website.
+By selecting the external link icon specified on the right side, GitLab opens the production website.
Our deployment successfully was done and we can see the application is live.
![Laravel welcome page](img/laravel_welcome_page.png)
diff --git a/doc/ci/examples/semantic-release.md b/doc/ci/examples/semantic-release.md
index 88e63a7f36f..8f0321517ab 100644
--- a/doc/ci/examples/semantic-release.md
+++ b/doc/ci/examples/semantic-release.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/ci/git_submodules.md b/doc/ci/git_submodules.md
index ee9d15894fe..68cbff21fae 100644
--- a/doc/ci/git_submodules.md
+++ b/doc/ci/git_submodules.md
@@ -60,6 +60,13 @@ To make submodules work correctly in CI/CD jobs:
GIT_SUBMODULE_STRATEGY: recursive
```
+1. Use `GIT_SUBMODULE_DEPTH` to configure the cloning depth of submodules independently of the [`GIT_DEPTH`](runners/configure_runners.md#shallow-cloning) variable:
+
+ ```yaml
+ variables:
+ GIT_SUBMODULE_DEPTH: 1
+ ```
+
1. You can filter or exclude specific submodules to control which submodules will be synced using
[`GIT_SUBMODULE_PATHS`](runners/configure_runners.md#git-submodule-paths).
@@ -76,6 +83,14 @@ To make submodules work correctly in CI/CD jobs:
GIT_SUBMODULE_STRATEGY: recursive
GIT_SUBMODULE_UPDATE_FLAGS: --jobs 4
```
+
+1. You can set the [GIT_SUBMODULE_PATHS](runners/configure_runners.md#sync-or-exclude-specific-submodules-from-ci-jobs) to explicitly ignore submodules during cloning:
+
+ ```yaml
+ variables:
+ GIT_SUBMODULE_STRATEGY: recursive
+ GIT_SUBMODULE_PATHS: ':(exclude)submodule'
+ ```
If you use the [`CI_JOB_TOKEN`](jobs/ci_job_token.md) to clone a submodule in a
pipeline job, the user executing the job must be assigned to a role that has
diff --git a/doc/ci/interactive_web_terminal/index.md b/doc/ci/interactive_web_terminal/index.md
index a1df55cfc38..44c081b9d7f 100644
--- a/doc/ci/interactive_web_terminal/index.md
+++ b/doc/ci/interactive_web_terminal/index.md
@@ -65,7 +65,7 @@ for the current job.
![Example of job running with terminal available](img/interactive_web_terminal_running_job.png)
-When clicked, a new tab opens to the terminal page where you can access
+When selected, a new tab opens to the terminal page where you can access
the terminal and type commands like a normal shell.
![terminal of the job](img/interactive_web_terminal_page.png)
diff --git a/doc/ci/jobs/ci_job_token.md b/doc/ci/jobs/ci_job_token.md
index 7282ebb0909..1e7b389c84a 100644
--- a/doc/ci/jobs/ci_job_token.md
+++ b/doc/ci/jobs/ci_job_token.md
@@ -26,8 +26,8 @@ You can use a GitLab CI/CD job token to authenticate with specific API endpoints
- [Terraform plan](../../user/infrastructure/index.md).
The token has the same permissions to access the API as the user that caused the
-job to run. A user can cause a job to run by pushing a commit, triggering a manual job,
-being the owner of a scheduled pipeline, and so on. Therefore, this user must be assigned to
+job to run. A user can cause a job to run by taking action like pushing a commit,
+triggering a manual job, or being the owner of a scheduled pipeline. Therefore, this user must be assigned to
[a role that has the required privileges](../../user/permissions.md#gitlab-cicd-permissions).
The token is valid only while the pipeline job runs. After the job finishes, you can't
diff --git a/doc/ci/jobs/index.md b/doc/ci/jobs/index.md
index d1a4f1e35bf..4eb8952dd73 100644
--- a/doc/ci/jobs/index.md
+++ b/doc/ci/jobs/index.md
@@ -37,7 +37,7 @@ independently from each other.
When you access a pipeline, you can see the related jobs for that pipeline.
-Clicking an individual job shows you its job log, and allows you to:
+Selecting an individual job shows you its job log, and allows you to:
- Cancel the job.
- Retry the job.
@@ -389,5 +389,5 @@ deploy me:
The behavior of deployment jobs can be controlled with
[deployment safety](../environments/deployment_safety.md) settings like
-[skipping outdated deployment jobs](../environments/deployment_safety.md#skip-outdated-deployment-jobs)
+[preventing outdated deployment jobs](../environments/deployment_safety.md#prevent-outdated-deployment-jobs)
and [ensuring only one deployment job runs at a time](../environments/deployment_safety.md#ensure-only-one-deployment-job-runs-at-a-time).
diff --git a/doc/ci/jobs/job_control.md b/doc/ci/jobs/job_control.md
index 39ab0998291..d26c698af89 100644
--- a/doc/ci/jobs/job_control.md
+++ b/doc/ci/jobs/job_control.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
When a new pipeline starts, GitLab checks the pipeline configuration to determine
which jobs should run in that pipeline. You can configure jobs to run depending on
-the status of variables, the pipeline type, and so on.
+factors like the status of variables, or the pipeline type.
To configure a job to be included or excluded from certain pipelines, you can use:
@@ -107,6 +107,33 @@ job:
- make build
```
+#### Skip job if the branch is empty
+
+Use [`rules:changes:compare_to`](../yaml/index.md#ruleschangescompare_to) to avoid
+running a job when the branch is empty, which saves CI/CD resources. Compare the
+branch to the default branch, and if the branch:
+
+- Doesn't have changed files, the job doesn't run.
+- Has changed files, the job runs.
+
+For example, in a project with `main` as the default branch:
+
+```yaml
+job:
+ script:
+ - echo "This job only runs for branches that are not empty"
+ rules:
+ - if: $CI_COMMIT_BRANCH
+ changes:
+ compare_to: refs/heads/main
+ paths:
+ - '*'
+```
+
+The rule for this job compares all files and paths (`*`) in the current branch against
+the default branch `main`. The rule matches and the job runs only when there are
+changes to the files in the branch.
+
### Complex rules
You can use all `rules` keywords, like `if`, `changes`, and `exists`, in the same
@@ -1061,7 +1088,7 @@ docker_build:
When the `DOCKERFILES_DIR` variable is expanded in the `changes:` section, the full
path becomes `path/to/files//*`. The double slashes might cause unexpected behavior
-depending on the keyword used, shell and OS of the runner, and so on.
+depending on factors like the keyword used, or the shell and OS of the runner.
### `You are not allowed to download code from this project.` error message
diff --git a/doc/ci/migration/circleci.md b/doc/ci/migration/circleci.md
index 5354e406e34..034c8ba5ad6 100644
--- a/doc/ci/migration/circleci.md
+++ b/doc/ci/migration/circleci.md
@@ -268,7 +268,7 @@ test_async:
## Contexts and variables
-CircleCI provides [Contexts](https://circleci.com/docs/contexts) to securely pass environment variables across project pipelines. In GitLab, a [Group](../../user/group/index.md) can be created to assemble related projects together. At the group level, [CI/CD variables](../variables/index.md#add-a-cicd-variable-to-a-group) can be stored outside the individual projects, and securely passed into pipelines across multiple projects.
+CircleCI provides [Contexts](https://circleci.com/docs/contexts/) to securely pass environment variables across project pipelines. In GitLab, a [Group](../../user/group/index.md) can be created to assemble related projects together. At the group level, [CI/CD variables](../variables/index.md#add-a-cicd-variable-to-a-group) can be stored outside the individual projects, and securely passed into pipelines across multiple projects.
## Orbs
diff --git a/doc/ci/migration/jenkins.md b/doc/ci/migration/jenkins.md
index 300de610aa7..4ba59e14811 100644
--- a/doc/ci/migration/jenkins.md
+++ b/doc/ci/migration/jenkins.md
@@ -49,8 +49,8 @@ things we have found that help this:
your users understand why the effort is worth it. The value is clear when
the work is done, but people need to be aware while it's in progress too.
- Sponsorship and alignment from the relevant leadership team helps with the point above.
-- Spending time educating your users on what's different, sharing this document with them,
- and so on helps ensure you are successful.
+- Spending time educating your users on what's different and sharing this document
+ with them helps ensure you are successful.
- Finding ways to sequence or delay parts of the migration can help a lot, but you
don't want to leave things in a non-migrated (or partially-migrated) state for too
long. To gain all the benefits of GitLab, moving your existing Jenkins setup over
@@ -67,7 +67,7 @@ of transition, by letting you delay the migration of less urgent pipelines for a
If you are interested in helping GitLab test the wrapper, join our [public testing issue](https://gitlab.com/gitlab-org/gitlab/-/issues/215675) for instructions and to provide your feedback.
NOTE:
-If you have a paid GitLab subscription, note that the JenkinsFile Wrapper is not packaged as part of GitLab, and falls outside of the scope of support. For more information, see the [Statement of Support](https://about.gitlab.com/support/statement-of-support.html).
+If you have a paid GitLab subscription, note that the JenkinsFile Wrapper is not packaged as part of GitLab, and falls outside of the scope of support. For more information, see the [Statement of Support](https://about.gitlab.com/support/statement-of-support/).
## Important product differences
@@ -197,7 +197,7 @@ can leverage. You can see the complete list of packaging features in the
## Integrated features
-Where you may have used plugins to get things like code quality, unit tests, security scanning, and so on working in Jenkins,
+Where you may have used plugins to get things like code quality, unit tests, and security scanning working in Jenkins,
GitLab takes advantage of our connected ecosystem to automatically pull these kinds of results into
your merge requests, pipeline details pages, and other locations. You may find that you actually don't
need to configure anything to have these appear.
diff --git a/doc/ci/pipelines/cicd_minutes.md b/doc/ci/pipelines/cicd_minutes.md
index a5484fcdf5a..772a06980af 100644
--- a/doc/ci/pipelines/cicd_minutes.md
+++ b/doc/ci/pipelines/cicd_minutes.md
@@ -128,9 +128,7 @@ These additional CI/CD minutes:
- Are carried over to the next month, if any remain at the end of the month.
- Are valid for 12 months from date of purchase or until all minutes are consumed, whichever comes first. Expiry of minutes is not currently enforced.
-If you use more CI/CD minutes than your monthly quota, when you purchase more,
-those CI/CD minutes are deducted from your quota. For example, with a GitLab SaaS
-Premium license:
+For example, with a GitLab SaaS Premium license:
- You have `10,000` monthly minutes.
- You purchase an additional `5,000` minutes.
@@ -232,7 +230,7 @@ For this reduced cost factor:
- The merge request source project must be a fork of a GitLab-maintained project,
such as [`gitlab-com/www-gitlab-com`](https://gitlab.com/gitlab-com/www-gitlab-com),
- [`gitlab-org/gitlab`](https://gitlab.com/gitlab-org/gitlab), and so on.
+ or [`gitlab-org/gitlab`](https://gitlab.com/gitlab-org/gitlab).
- The merge request target project must be the fork's parent project.
- The pipeline must be a merge request, merged results, or merge train pipeline.
@@ -271,9 +269,9 @@ the next month.
For example:
-- On **1st April**, you purchase `5,000` CI/CD minutes.
-- During April, you use only `3,000` of the `5,000` minutes.
-- On **1st May**, the remaining `2,000` minutes roll over and are added to your monthly quota.
+- On **1st April**, you purchase `5,000` additional CI/CD minutes.
+- During April, you use only `3,000` of the `5,000` additional minutes.
+- On **1st May**, the unused minute roll over, so you have `2,000` additional minutes available for May.
Additional CI/CD minutes are a one-time purchase and do not renew or refresh each month.
diff --git a/doc/ci/pipelines/downstream_pipelines.md b/doc/ci/pipelines/downstream_pipelines.md
index 0b1963e1874..c8fcd06da07 100644
--- a/doc/ci/pipelines/downstream_pipelines.md
+++ b/doc/ci/pipelines/downstream_pipelines.md
@@ -20,8 +20,10 @@ but there are [key differences](pipeline_architectures.md).
## Parent-child pipelines
-A parent pipeline is one that triggers a downstream pipeline in the same project.
-The downstream pipeline is called a child pipeline. Child pipelines:
+A parent pipeline is a pipeline that triggers a downstream pipeline in the same project.
+The downstream pipeline is called a child pipeline.
+
+Child pipelines:
- Run under the same project, ref, and commit SHA as the parent pipeline.
- Do not directly affect the overall status of the ref the pipeline runs against. For example,
@@ -30,18 +32,18 @@ The downstream pipeline is called a child pipeline. Child pipelines:
pipeline is triggered with [`strategy:depend`](../yaml/index.md#triggerstrategy).
- Are automatically canceled if the pipeline is configured with [`interruptible`](../yaml/index.md#interruptible)
when a new pipeline is created for the same ref.
-- Are not displayed in the pipeline index page. You can only view child pipelines on
- their parent pipeline's page.
+- Are not displayed in the project's pipeline list. You can only view child pipelines on
+ their parent pipeline's details page.
### Nested child pipelines
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/29651) in GitLab 13.4.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/243747) in GitLab 13.5.
-Parent and child pipelines were introduced with a maximum depth of one level of child
-pipelines, which was later increased to two. A parent pipeline can trigger many child
-pipelines, and these child pipelines can trigger their own child pipelines. It's not
-possible to trigger another level of child pipelines.
+Parent and child pipelines have a maximum depth of two levels of child pipelines.
+
+A parent pipeline can trigger many child pipelines, and these child pipelines can trigger
+their own child pipelines. You cannot trigger another level of child pipelines.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see [Nested Dynamic Pipelines](https://youtu.be/C5j3ju9je2M).
@@ -52,11 +54,6 @@ A pipeline in one project can trigger downstream pipelines in another project,
called multi-project pipelines. The user triggering the upstream pipeline must be able to
start pipelines in the downstream project, otherwise [the downstream pipeline fails to start](#trigger-job-fails-and-does-not-create-multi-project-pipeline).
-For example, you might deploy your web application from three different GitLab projects.
-With multi-project pipelines you can trigger a pipeline in each project, where each
-has its own build, test, and deploy process. You can visualize the connected pipelines
-in one place, including all cross-project interdependencies.
-
Multi-project pipelines:
- Are triggered from another project's pipeline, but the upstream (triggering) pipeline does
@@ -68,8 +65,7 @@ Multi-project pipelines:
- Are not automatically canceled in the downstream project when using [`interruptible`](../yaml/index.md#interruptible)
if a new pipeline runs for the same ref in the upstream pipeline. They can be
automatically canceled if a new pipeline is triggered for the same ref on the downstream project.
-- Multi-project pipelines are standalone pipelines because they are normal pipelines
- that happened to be triggered by an external project. They are all visible on the pipeline index page.
+- Are visible in the downstream project's pipeline list.
- Are independent, so there are no nesting limits.
Learn more in the "Cross-project Pipeline Triggering and Visualization" demo at
@@ -87,48 +83,49 @@ always displays:
Use the [`trigger`](../yaml/index.md#trigger) keyword in your `.gitlab-ci.yml` file
to create a job that triggers a downstream pipeline. This job is called a trigger job.
-After the trigger job starts, the initial status of the job is `pending` while GitLab
-attempts to create the downstream pipeline. If the downstream pipeline is created,
-GitLab marks the job as passed, otherwise the job failed. Alternatively,
-you can [set the trigger job to show the downstream pipeline's status](#mirror-the-status-of-a-downstream-pipeline-in-the-trigger-job)
-instead.
-
For example:
::Tabs
-:::TabTitle Multi-project pipeline
+:::TabTitle Parent-child pipeline
```yaml
trigger_job:
trigger:
- project: project-group/my-downstream-project
+ include:
+ - local: path/to/child-pipeline.yml
```
-:::TabTitle Parent-child pipeline
+:::TabTitle Multi-project pipeline
```yaml
trigger_job:
trigger:
- include:
- - local: path/to/child-pipeline.yml
+ project: project-group/my-downstream-project
```
::EndTabs
+After the trigger job starts, the initial status of the job is `pending` while GitLab
+attempts to create the downstream pipeline. The trigger job shows `passed` if the
+downstream pipeline is created successfully, otherwise it shows `failed`. Alternatively,
+you can [set the trigger job to show the downstream pipeline's status](#mirror-the-status-of-a-downstream-pipeline-in-the-trigger-job)
+instead.
+
### Use `rules` to control downstream pipeline jobs
-You can use CI/CD variables or the [`rules`](../yaml/index.md#rulesif) keyword to
-[control job behavior](../jobs/job_control.md) for downstream pipelines.
+Use CI/CD variables or the [`rules`](../yaml/index.md#rulesif) keyword to
+[control job behavior](../jobs/job_control.md) in downstream pipelines.
-When a downstream pipeline is triggered with the [`trigger`](../yaml/index.md#trigger) keyword,
+When you trigger a downstream pipeline with the [`trigger`](../yaml/index.md#trigger) keyword,
the value of the [`$CI_PIPELINE_SOURCE` predefined variable](../variables/predefined_variables.md)
for all jobs is:
- `pipeline` for multi-project pipelines.
-- `parent` for parent-child pipelines.
+- `parent_pipeline` for parent-child pipelines.
-For example, with a multi-project pipeline:
+For example, to control jobs in multi-project pipelines in a project that also runs
+merge request pipelines:
```yaml
job1:
@@ -148,38 +145,12 @@ job3:
script: echo "This job runs in both multi-project and merge request pipelines"
```
-### Specify a branch for multi-project pipelines
-
-You can specify a branch name for a multi-project pipeline to use. GitLab uses
-the commit on the head of the branch to create the downstream pipeline:
-
-```yaml
-rspec:
- stage: test
- script: bundle exec rspec
-
-staging:
- stage: deploy
- trigger:
- project: my/deployment
- branch: stable-11-2
-```
-
-Use:
-
-- The `project` keyword to specify the full path to a downstream project.
- In [GitLab 15.3 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/367660), variable expansion is
- supported.
-- The `branch` keyword to specify the name of a branch in the project specified by `project`.
- In [GitLab 12.4 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/10126), variable expansion is
- supported.
-
### Use a child pipeline configuration file in a different project
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/205157) in GitLab 13.5.
-You can use [`include:file`](../yaml/index.md#includefile) to trigger child pipelines
-with a configuration file in a different project:
+You can use [`include:project`](../yaml/index.md#includeproject) in a trigger job
+to trigger child pipelines with a configuration file in a different project:
```yaml
microservice_a:
@@ -208,8 +179,6 @@ microservice_a:
### Dynamic child pipelines
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35632) in GitLab 12.9.
-
You can trigger a child pipeline from a YAML file generated in a job, instead of a
static file saved in your project. This technique can be very powerful for generating pipelines
targeting content that changed or to build a matrix of targets and architectures.
@@ -231,43 +200,42 @@ To trigger a child pipeline from a dynamically generated configuration file:
1. Generate the configuration file in a job and save it as an [artifact](../yaml/index.md#artifactspaths):
- ```yaml
- generate-config:
- stage: build
- script: generate-ci-config > generated-config.yml
- artifacts:
- paths:
- - generated-config.yml
- ```
+ ```yaml
+ generate-config:
+ stage: build
+ script: generate-ci-config > generated-config.yml
+ artifacts:
+ paths:
+ - generated-config.yml
+ ```
1. Configure the trigger job to run after the job that generated the configuration file,
and set `include: artifact` to the generated artifact:
- ```yaml
- child-pipeline:
- stage: test
- trigger:
- include:
- - artifact: generated-config.yml
- job: generate-config
- ```
+ ```yaml
+ child-pipeline:
+ stage: test
+ trigger:
+ include:
+ - artifact: generated-config.yml
+ job: generate-config
+ ```
-In this example, `generated-config.yml` is extracted from the artifacts and used as the configuration
-for triggering the child pipeline.
+In this example, GitLab retrieves `generated-config.yml` and triggers a child pipeline
+with the CI/CD configuration in that file.
The artifact path is parsed by GitLab, not the runner, so the path must match the
syntax for the OS running GitLab. If GitLab is running on Linux but using a Windows
runner for testing, the path separator for the trigger job is `/`. Other CI/CD
-configuration for jobs that use the Windows runner, like scripts, use `\`.
+configuration for jobs that use the Windows runner, like scripts, use <code>&#92;</code>.
### Run child pipelines with merge request pipelines
To trigger a child pipeline as a [merge request pipeline](merge_request_pipelines.md):
-1. Set the trigger job to run on merge requests:
+1. Set the trigger job to run on merge requests in the parent pipeline's configuration file:
```yaml
- # parent .gitlab-ci.yml
microservice_a:
trigger:
include: path/to/microservice_a.yml
@@ -275,45 +243,50 @@ To trigger a child pipeline as a [merge request pipeline](merge_request_pipeline
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
```
-1. Configure the child pipeline jobs to run in merge request pipelines:
+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:
- - With [`workflow:rules`](../yaml/index.md#workflowrules):
+ ```yaml
+ job1:
+ script: ...
+ rules:
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
- ```yaml
- # child path/to/microservice_a.yml
- workflow:
- rules:
- - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+ job2:
+ script: ...
+ rules:
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+ ```
- job1:
- script: ...
+### Specify a branch for multi-project pipelines
- job2:
- script: ...
- ```
+You can specify the branch to use when triggering a multi-project pipeline. GitLab uses
+the commit on the head of the branch to create the downstream pipeline. For example:
- - By configuring [rules](../yaml/index.md#rules) for each job:
+```yaml
+staging:
+ stage: deploy
+ trigger:
+ project: my/deployment
+ branch: stable-11-2
+```
- ```yaml
- # child path/to/microservice_a.yml
- job1:
- script: ...
- rules:
- - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+Use:
- job2:
- script: ...
- rules:
- - if: $CI_PIPELINE_SOURCE == "merge_request_event"
- ```
+- 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)
+ in the project specified by `project`. You can use variable expansion.
## Trigger a multi-project pipeline by using the API
You can use the [CI/CD job token (`CI_JOB_TOKEN`)](../jobs/ci_job_token.md) with the
[pipeline trigger API endpoint](../../api/pipeline_triggers.md#trigger-a-pipeline-with-a-token)
-to trigger multi-project pipelines from a CI/CD job. GitLab recognizes the source of the job token
-and marks the pipelines as related. In the pipeline graph, the relationships are displayed
-as inbound and outbound connections for upstream and downstream pipeline dependencies.
+to trigger multi-project pipelines from inside a CI/CD job. GitLab sets pipelines triggered
+with a job token as downstream pipelines of the pipeline that contains the job that
+made the API call.
For example:
@@ -357,27 +330,27 @@ To cancel a downstream pipeline that is still running, select **Cancel** (**{can
### Mirror the status of a downstream pipeline in the trigger job
-You can mirror the pipeline status from the triggered pipeline to the source trigger job
+You can mirror the status of the downstream pipeline in the trigger job
by using [`strategy: depend`](../yaml/index.md#triggerstrategy):
::Tabs
-:::TabTitle Multi-project pipeline
+:::TabTitle Parent-child pipeline
```yaml
trigger_job:
trigger:
- project: my/project
+ include:
+ - local: path/to/child-pipeline.yml
strategy: depend
```
-:::TabTitle Parent-child pipeline
+:::TabTitle Multi-project pipeline
```yaml
trigger_job:
trigger:
- include:
- - local: path/to/child-pipeline.yml
+ project: my/project
strategy: depend
```
@@ -385,7 +358,7 @@ trigger_job:
### View multi-project pipelines in pipeline graphs **(PREMIUM)**
-When you trigger a multi-project pipeline, the downstream pipeline displays
+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)
@@ -395,12 +368,13 @@ displays to the right of the mini graph.
![Multi-project pipeline mini graph](img/pipeline_mini_graph_v15_0.png)
-## Pass artifacts to a downstream pipeline
+## Fetch artifacts from an upstream pipeline
-You can pass artifacts to a downstream pipeline by using [`needs:project`](../yaml/index.md#needsproject).
+Use [`needs:project`](../yaml/index.md#needsproject) to fetch artifacts from an
+upstream pipeline:
-1. In a job in the upstream pipeline, save the artifacts using the [`artifacts`](../yaml/index.md#artifacts) keyword.
-1. Trigger the downstream pipeline with a trigger job:
+1. In the upstream pipeline, save the artifacts in a job with the [`artifacts`](../yaml/index.md#artifacts)
+ keyword, then trigger the downstream pipeline with a trigger job:
```yaml
build_artifacts:
@@ -416,9 +390,7 @@ You can pass artifacts to a downstream pipeline by using [`needs:project`](../ya
trigger: my/downstream_project
```
-1. In a job in the downstream pipeline, fetch the artifacts from the upstream pipeline
- by using `needs:project`. Set `job` to the job in the upstream pipeline to fetch artifacts from,
- `ref` to the branch, and `artifacts: true`.
+1. Use `needs:project` in a job in the downstream pipeline to fetch the artifacts.
```yaml
test:
@@ -432,22 +404,27 @@ You can pass artifacts to a downstream pipeline by using [`needs:project`](../ya
artifacts: true
```
-### Pass artifacts from a Merge Request pipeline
+ Set:
-When you use `needs:project` to [pass artifacts to a downstream pipeline](#pass-artifacts-to-a-downstream-pipeline),
+ - `job` to the job in the upstream pipeline that created the artifacts.
+ - `ref` to the branch.
+ - `artifacts` to `true`.
+
+### Fetch artifacts from an upstream merge request pipeline
+
+When you use `needs:project` to [pass artifacts to a downstream pipeline](#fetch-artifacts-from-an-upstream-pipeline),
the `ref` value is usually a branch name, like `main` or `development`.
-For merge request pipelines, the `ref` value is in the form of `refs/merge-requests/<id>/head`,
+For [merge request pipelines](merge_request_pipelines.md), the `ref` value is in the form of `refs/merge-requests/<id>/head`,
where `id` is the merge request ID. You can retrieve this ref with the [`CI_MERGE_REQUEST_REF_PATH`](../variables/predefined_variables.md#predefined-variables-for-merge-request-pipelines)
CI/CD variable. Do not use a branch name as the `ref` with merge request pipelines,
because the downstream pipeline attempts to fetch artifacts from the latest branch pipeline.
To fetch the artifacts from the upstream `merge request` pipeline instead of the `branch` pipeline,
-pass this variable to the downstream pipeline using variable inheritance:
+pass `CI_MERGE_REQUEST_REF_PATH` to the downstream pipeline using [variable inheritance](#pass-yaml-defined-cicd-variables):
1. In a job in the upstream pipeline, save the artifacts using the [`artifacts`](../yaml/index.md#artifacts) keyword.
-1. In the job that triggers the downstream pipeline, pass the `$CI_MERGE_REQUEST_REF_PATH` variable by using
- [variable inheritance](#pass-yaml-defined-cicd-variables):
+1. In the job that triggers the downstream pipeline, pass the `$CI_MERGE_REQUEST_REF_PATH` variable:
```yaml
build_artifacts:
@@ -467,8 +444,7 @@ pass this variable to the downstream pipeline using variable inheritance:
```
1. In a job in the downstream pipeline, fetch the artifacts from the upstream pipeline
- by using `needs:project`. Set the `ref` to the `UPSTREAM_REF` variable, and `job`
- to the job in the upstream pipeline to fetch artifacts from:
+ by using `needs:project` and the passed variable as the `ref`:
```yaml
test:
@@ -482,86 +458,137 @@ pass this variable to the downstream pipeline using variable inheritance:
artifacts: true
```
-This method works for fetching artifacts from a regular merge request parent pipeline,
-but fetching artifacts from [merge results](merged_results_pipelines.md) pipelines is not supported.
+You can use this method to fetch artifacts from upstream merge request pipeline,
+but not from [merge results pipelines](merged_results_pipelines.md).
## Pass CI/CD variables to a downstream pipeline
-You can pass CI/CD variables to a downstream pipeline with a few different methods,
-based on where the variable is created or defined.
+You can pass [CI/CD variables](../variables/index.md) to a downstream pipeline with
+a few different methods, based on where the variable is created or defined.
### Pass YAML-defined CI/CD variables
-You can use the `variables` keyword to pass CI/CD variables to a downstream pipeline,
-just like you would for any other job.
+You can use the `variables` keyword to pass CI/CD variables to a downstream pipeline.
-For example, in a [multi-project pipeline](#multi-project-pipelines):
+For example:
+
+::Tabs
+
+:::TabTitle Parent-child pipeline
```yaml
-rspec:
- stage: test
- script: bundle exec rspec
+variables:
+ VERSION: "1.0.0"
staging:
variables:
ENVIRONMENT: staging
stage: deploy
- trigger: my/deployment
+ trigger:
+ include:
+ - local: path/to/child-pipeline.yml
```
-The `ENVIRONMENT` variable is passed to every job defined in a downstream
-pipeline. It is available as a variable when GitLab Runner picks a job.
-
-In the following configuration, the `MY_VARIABLE` variable is passed to the downstream pipeline
-that is created when the `trigger-downstream` job is queued. This behavior is because `trigger-downstream`
-job inherits variables declared in [global `variables`](../yaml/index.md#variables) blocks,
-and then GitLab passes these variables to the downstream pipeline.
+:::TabTitle Multi-project pipeline
```yaml
variables:
- MY_VARIABLE: my-value
+ VERSION: "1.0.0"
-trigger-downstream:
+staging:
variables:
- ENVIRONMENT: something
- trigger: my/project
+ ENVIRONMENT: staging
+ stage: deploy
+ trigger: my-group/my-deployment-project
```
+::EndTabs
+
+The `ENVIRONMENT` variable is available in every job defined in the downstream pipeline.
+
+The `VERSION` global variable is also available in the downstream pipeline, because
+all jobs in a pipeline, including trigger jobs, inherit [global `variables`](../yaml/index.md#variables).
+
#### Prevent global variables from being passed
-You can stop global variables from reaching the downstream pipeline by using the [`inherit:variables` keyword](../yaml/index.md#inheritvariables).
-For example, in a [multi-project pipeline](#multi-project-pipelines):
+You can stop global CI/CD variables from reaching the downstream pipeline with
+[`inherit:variables:false`](../yaml/index.md#inheritvariables).
+
+For example:
+
+::Tabs
+
+:::TabTitle Parent-child pipeline
```yaml
variables:
- MY_GLOBAL_VAR: value
+ GLOBAL_VAR: value
-trigger-downstream:
+trigger-job:
inherit:
variables: false
variables:
- MY_LOCAL_VAR: value
- trigger: my/project
+ JOB_VAR: value
+ trigger:
+ include:
+ - local: path/to/child-pipeline.yml
```
-In this example, the `MY_GLOBAL_VAR` variable is not available in the triggered pipeline.
+:::TabTitle Multi-project pipeline
+
+```yaml
+variables:
+ GLOBAL_VAR: value
+
+trigger-job:
+ inherit:
+ variables: false
+ variables:
+ JOB_VAR: value
+ trigger: my-group/my-project
+```
+
+::EndTabs
+
+The `GLOBAL_VAR` variable is not available in the triggered pipeline, but `JOB_VAR`
+is available.
### Pass a predefined variable
-You might want to pass some information about the upstream pipeline using predefined variables.
-To do that, you can use interpolation to pass any variable. For example,
-in a [multi-project pipeline](#multi-project-pipelines):
+To pass information about the upstream pipeline using [predefined CI/CD variables](../variables/predefined_variables.md).
+use interpolation. Save the predefined variable as a new job variable in the trigger
+job, which is passed to the downstream pipeline. For example:
+
+::Tabs
+
+:::TabTitle Parent-child pipeline
+
+```yaml
+trigger-job:
+ variables:
+ PARENT_BRANCH: $CI_COMMIT_REF_NAME
+ trigger:
+ include:
+ - local: path/to/child-pipeline.yml
+```
+
+:::TabTitle Multi-project pipeline
```yaml
-downstream-job:
+trigger-job:
variables:
UPSTREAM_BRANCH: $CI_COMMIT_REF_NAME
- trigger: my/project
+ trigger: my-group/my-project
```
-In this scenario, the `UPSTREAM_BRANCH` variable with the value of the upstream pipeline's
-`$CI_COMMIT_REF_NAME` is passed to `downstream-job`. It is available in the
-context of all downstream builds.
+::EndTabs
+
+The `UPSTREAM_BRANCH` variable, which contains the value of the upstream pipeline's `$CI_COMMIT_REF_NAME`
+predefined CI/CD variable, is available in the downstream pipeline.
+
+Do not use this method to pass [masked variables](../variables/index.md#mask-a-cicd-variable)
+to a multi-project pipeline. The CI/CD masking configuration is not passed to the
+downstream pipeline and the variable could be unmasked in job logs in the downstream project.
You cannot use this method to forward [job-level persisted variables](../variables/where_variables_can_be_used.md#persisted-variables)
to a downstream pipeline, as they are not available in trigger jobs.
@@ -623,3 +650,10 @@ With multi-project pipelines, the trigger job fails and does not create the down
- The downstream pipeline targets a protected branch and the user does not have permission
to run pipelines against the protected branch. See [pipeline security for protected branches](index.md#pipeline-security-on-protected-branches)
for more information.
+
+### `Ref is ambiguous`
+
+You cannot trigger a multi-project pipeline with a tag when a branch exists with the same
+name. The downstream pipeline fails to create with the error: `downstream pipeline can not be created, Ref is ambiguous`.
+
+Only trigger multi-project pipelines with tag names that do not match branch names.
diff --git a/doc/ci/pipelines/img/merge_train_cancel_v12_0.png b/doc/ci/pipelines/img/merge_train_cancel_v12_0.png
deleted file mode 100644
index d7720ac1143..00000000000
--- a/doc/ci/pipelines/img/merge_train_cancel_v12_0.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/pipelines/img/merge_train_failure.png b/doc/ci/pipelines/img/merge_train_failure.png
deleted file mode 100644
index 8a795fff432..00000000000
--- a/doc/ci/pipelines/img/merge_train_failure.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/pipelines/img/merge_train_immediate_merge_v12_6.png b/doc/ci/pipelines/img/merge_train_immediate_merge_v12_6.png
deleted file mode 100644
index 7b903716a3d..00000000000
--- a/doc/ci/pipelines/img/merge_train_immediate_merge_v12_6.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/pipelines/img/merge_train_position_v12_0.png b/doc/ci/pipelines/img/merge_train_position_v12_0.png
deleted file mode 100644
index ec4b157d428..00000000000
--- a/doc/ci/pipelines/img/merge_train_position_v12_0.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/pipelines/img/merge_train_start_v12_0.png b/doc/ci/pipelines/img/merge_train_start_v12_0.png
deleted file mode 100644
index a4d0c8cf0e6..00000000000
--- a/doc/ci/pipelines/img/merge_train_start_v12_0.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/pipelines/img/merge_train_start_when_pipeline_succeeds_v12_0.png b/doc/ci/pipelines/img/merge_train_start_when_pipeline_succeeds_v12_0.png
deleted file mode 100644
index 45762b8e85e..00000000000
--- a/doc/ci/pipelines/img/merge_train_start_when_pipeline_succeeds_v12_0.png
+++ /dev/null
Binary files differ
diff --git a/doc/ci/pipelines/index.md b/doc/ci/pipelines/index.md
index ed0583e0872..f1ca8afa62c 100644
--- a/doc/ci/pipelines/index.md
+++ b/doc/ci/pipelines/index.md
@@ -80,7 +80,7 @@ You can also configure specific aspects of your pipelines through the GitLab UI.
### Ref specs for runners
When a runner picks a pipeline job, GitLab provides that job's metadata. This includes the [Git refspecs](https://git-scm.com/book/en/v2/Git-Internals-The-Refspec),
-which indicate which ref (branch, tag, and so on) and commit (SHA1) are checked out from your
+which indicate which ref (such as branch or tag) and commit (SHA1) are checked out from your
project repository.
This table lists the refspecs injected for each pipeline type:
@@ -158,7 +158,7 @@ The pipeline now executes the jobs as configured.
You can use the [`description` and `value`](../yaml/index.md#variablesdescription)
keywords to define [pipeline-level (global) variables](../variables/index.md#create-a-custom-cicd-variable-in-the-gitlab-ciyml-file)
that are prefilled when running a pipeline manually. Use the description to explain
-what the variable is used for, what the acceptable values are, and so on.
+information such as what the variable is used for, and what the acceptable values are.
Job-level variables cannot be pre-filled.
@@ -260,7 +260,7 @@ pipelines.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24851) in GitLab 12.7.
Users with the Owner role for a project can delete a pipeline
-by clicking on the pipeline in the **CI/CD > Pipelines** to get to the **Pipeline Details**
+by selecting the pipeline in the **CI/CD > Pipelines** to get to the **Pipeline Details**
page, then selecting **Delete**.
![Pipeline Delete](img/pipeline-delete.png)
@@ -301,6 +301,9 @@ preserving deployment keys and other credentials from being unintentionally
accessed. To ensure that jobs intended to be executed on protected
runners do not use regular runners, they must be tagged accordingly.
+Review the [deployment safety](../environments/deployment_safety.md)
+page for additional security recommendations for securing your pipelines.
+
## Trigger a pipeline when an upstream project is rebuilt **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9045) in GitLab 12.8.
diff --git a/doc/ci/pipelines/job_artifacts.md b/doc/ci/pipelines/job_artifacts.md
index 33a9069240b..cc26ede5f6e 100644
--- a/doc/ci/pipelines/job_artifacts.md
+++ b/doc/ci/pipelines/job_artifacts.md
@@ -309,61 +309,50 @@ for [parent and child pipelines](downstream_pipelines.md#parent-child-pipelines)
order from parent to child. For example, if both parent and child pipelines have a
job with the same name, the job artifact from the parent pipeline is returned.
-## Access the latest job artifacts by URL
+## Access the latest job artifacts
-You can download job artifacts from the latest successful pipeline by using a URL.
+You can download job artifacts from the latest successful pipeline by using [the job artifacts API](../../api/job_artifacts.md).
+You cannot download [artifact reports](../yaml/artifacts_reports.md) with the job artifacts API,
+unless the report is added as a regular artifact with `artifacts:paths`.
-To download the whole artifacts archive:
+### Download the whole artifacts archive for a specific job
-```plaintext
-https://example.com/<namespace>/<project>/-/jobs/artifacts/<ref>/download?job=<job_name>
-```
+You can download the artifacts archive for a specific job with [the job artifacts API](../../api/job_artifacts.md#download-the-artifacts-archive).
-To download a single file from the artifacts:
+For example, to download the latest artifacts of a job named `build` in the `main` branch of a project on GitLab.com:
```plaintext
-https://example.com/<namespace>/<project>/-/jobs/artifacts/<ref>/raw/<path_to_file>?job=<job_name>
+https://gitlab.com/api/v4/projects/<project-id>/jobs/artifacts/main/download?job=build
```
-For example, to download the latest artifacts of the job named `coverage` in
-the `main` branch of the `gitlab` project in the `gitlab-org`
-namespace:
-
-```plaintext
-https://gitlab.com/gitlab-org/gitlab/-/jobs/artifacts/main/download?job=coverage
-```
+Replace `<project-id>` with a valid project ID, found at the top of the project details page.
-To download the file `review/index.html` from the same artifacts:
+### Download a single file from the artifacts
-```plaintext
-https://gitlab.com/gitlab-org/gitlab/-/jobs/artifacts/main/raw/review/index.html?job=coverage
-```
+You can download a specific file from the artifacts archive for a specific job with [the job artifacts API](../../api/job_artifacts.md#download-a-single-artifact-file-by-job-id).
-To browse the latest job artifacts:
+For example, to download the file `review/index.html` from the latest job named `build` in the `main` branch of the `gitlab` project in the `gitlab-org` namespace:
```plaintext
-https://example.com/<namespace>/<project>/-/jobs/artifacts/<ref>/browse?job=<job_name>
+https://gitlab.com/api/v4/projects/27456355/jobs/artifacts/main/raw/review/index.html?job=build
```
-For example:
+### Browse job artifacts
-```plaintext
-https://gitlab.com/gitlab-org/gitlab/-/jobs/artifacts/main/browse?job=coverage
-```
-
-To download specific files, including HTML files that
-are shown in [GitLab Pages](../../administration/pages/index.md):
+To browse the job artifacts of the latest successful pipeline for a specific job you can use the following URL:
```plaintext
-https://example.com/<namespace>/<project>/-/jobs/artifacts/<ref>/file/<path>?job=<job_name>
+https://example.com/<namespace>/<project>/-/jobs/artifacts/<ref>/browse?job=<job_name>
```
-For example, when a job `coverage` creates the artifact `htmlcov/index.html`:
+For example, to browse the latest artifacts of a job named `build` in the `main` branch of a project on GitLab.com:
```plaintext
-https://gitlab.com/gitlab-org/gitlab/-/jobs/artifacts/main/file/htmlcov/index.html?job=coverage
+https://gitlab.com/<full-project-path>/-/jobs/artifacts/main/browse?job=build
```
+Replace `<full-project-path>` with a valid project path, you can find it in the URL for your project.
+
## When job artifacts are deleted
See the [`expire_in`](../yaml/index.md#artifactsexpire_in) documentation for information on when
@@ -396,7 +385,24 @@ a project, you can disable this behavior to save space:
You can disable this behavior for all projects on a self-managed instance in the
[instance's CI/CD settings](../../user/admin_area/settings/continuous_integration.md#keep-the-latest-artifacts-for-all-jobs-in-the-latest-successful-pipelines).
-## Troubleshooting job artifacts
+## Troubleshooting
+
+### Job does not retrieve certain artifacts
+
+By default, jobs fetch all artifacts from previous stages, but jobs using `dependencies`
+or `needs` do not fetch artifacts from all jobs by default.
+
+If you use these keywords, artifacts are fetched from only a subset of jobs. Review
+the keyword reference for information on how to fetch artifacts with these keywords:
+
+- [`dependencies`](../yaml/index.md#dependencies)
+- [`needs`](../yaml/index.md#needs)
+- [`needs:artifacts`](../yaml/index.md#needsartifacts)
+
+### Job artifacts using too much disk space
+
+There are a number of potential causes for this.
+[Read more in the job artifacts administration documentation](../../administration/job_artifacts.md#job-artifacts-using-too-much-disk-space).
### Error message `No files to upload`
diff --git a/doc/ci/pipelines/merge_trains.md b/doc/ci/pipelines/merge_trains.md
index c501d2a7904..370d81dacc4 100644
--- a/doc/ci/pipelines/merge_trains.md
+++ b/doc/ci/pipelines/merge_trains.md
@@ -6,253 +6,245 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Merge trains **(PREMIUM)**
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9186) in GitLab 12.0.
-> - [Squash and merge](../../user/project/merge_requests/squash_and_merge.md) support [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13001) in GitLab 12.6.
+Use merge trains to queue merge requests and verify their changes work together before
+they are merged to the target branch.
-For more information about why you might want to use merge trains, read [How starting merge trains improve efficiency for DevOps](https://about.gitlab.com/blog/2020/01/30/all-aboard-merge-trains/).
+In projects with frequent merges to the default branch, changes in different merge requests
+might conflict with each other. [Merged results pipelines](merged_results_pipelines.md)
+ensure the changes work with the content in the default branch, but not content
+that others are merging at the same time.
-When [merged results pipelines](merged_results_pipelines.md) are
-enabled, the pipeline jobs run as if the changes from your source branch have already
-been merged into the target branch.
+Merge trains do not work with [Semi-linear history merge requests](../../user/project/merge_requests/methods/index.md#merge-commit-with-semi-linear-history)
+or [fast-forward merge requests](../../user/project/merge_requests/methods/index.md#fast-forward-merge).
-However, the target branch may be changing rapidly. When you're ready to merge,
-if you haven't run the pipeline in a while, the target branch may have already changed.
-Merging now could introduce breaking changes.
+For more information about:
-*Merge trains* can prevent this from happening. A merge train is a queued list of merge
-requests, each waiting to be merged into the target branch.
+- How merge trains work, review the [merge train workflow](#merge-train-workflow).
+- Why you might want to use merge trains, read [How starting merge trains improve efficiency for DevOps](https://about.gitlab.com/blog/2020/01/30/all-aboard-merge-trains/).
-Many merge requests can be added to the train. Each merge request runs its own merged results pipeline,
-which includes the changes from all of the other merge requests in *front* of it on the train.
-All the pipelines run in parallel, to save time. The author of the internal merged result commit is always the user that initiated the merge.
+## Merge train workflow
-If the pipeline for a merge request fails, the breaking changes are not merged, and the target
-branch is unaffected. The merge request is removed from the train, and all pipelines behind it restart.
+A merge train starts when there are no merge requests waiting to merge and you
+select [**Start merge train**](#start-a-merge-train). GitLab starts a merge train pipeline
+that verifies that the changes can merge into the default branch. This first pipeline
+is the same as a [merged results pipeline](merged_results_pipelines.md), which runs on
+the changes of the source and target branches combined together. The author of the
+internal merged result commit is the user that initiated the merge.
-If the pipeline for the merge request at the front of the train completes successfully,
-the changes are merged into the target branch, and the other pipelines continue to
-run.
+To queue a second merge request to merge immediately after the first pipeline completes, select
+[**Add to merge train**](#add-a-merge-request-to-a-merge-train) and add it to the train.
+This second merge train pipeline runs on the changes of _both_ merge requests combined with the
+target branch. Similarly, if you add a third merge request, that pipeline runs on the changes
+of all three merge requests merged with the target branch. The pipelines all run in parallel.
-To add a merge request to a merge train, you need [permissions](../../user/permissions.md) to merge or push to the
-target branch.
+Each merge request merges into the target branch only after:
-Each merge train can run a maximum of **twenty** pipelines in parallel.
-If more than twenty merge requests are added to the merge train, the merge requests
-are queued until a slot in the merge train is free. There is no limit to the
-number of merge requests that can be queued.
+- The merge request's pipeline completes successfully.
+- All other merge requests queued before it are merged.
-## Merge train example
+If a merge train pipeline fails, the merge request is not merged. GitLab
+removes that merge request from the merge train, and starts new pipelines for all
+the merge requests that were queued after it.
-Three merge requests (`A`, `B` and `C`) are added to a merge train in order, which
+For example:
+
+Three merge requests (`A`, `B`, and `C`) are added to a merge train in order, which
creates three merged results pipelines that run in parallel:
1. The first pipeline runs on the changes from `A` combined with the target branch.
1. The second pipeline runs on the changes from `A` and `B` combined with the target branch.
1. The third pipeline runs on the changes from `A`, `B`, and `C` combined with the target branch.
-If the pipeline for `B` fails, it is removed from the train. The pipeline for
-`C` restarts with the `A` and `C` changes, but without the `B` changes.
+If the pipeline for `B` fails:
+
+- The first pipeline (`A`) continues to run.
+- `B` is removed from the train.
+- The pipeline for `C` [is cancelled](#automatic-pipeline-cancellation), and a new pipeline
+ starts for the changes from `A` and `C` combined with the target branch (without the `B` changes).
If `A` then completes successfully, it merges into the target branch, and `C` continues
-to run. If more merge requests are added to the train, they now include the `A`
-changes that are included in the target branch, and the `C` changes that are from
-the merge request already in the train.
+to run. Any new merge requests added to the train include the `A` changes now in
+the target branch, and the `C` changes from the merge train.
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
-Watch this video for a demonstration on
-[how parallel execution of merge trains can prevent commits from breaking the default branch](https://www.youtube.com/watch?v=D4qCqXgZkHQ).
+Watch this video for a demonstration on [how parallel execution of merge trains can prevent commits from breaking the default branch](https://www.youtube.com/watch?v=D4qCqXgZkHQ).
-## Prerequisites
+### Automatic pipeline cancellation
-To enable merge trains:
+GitLab CI/CD detects redundant pipelines, and cancels them to conserve resources.
-- You must have the Maintainer role.
-- You must be using [GitLab Runner](https://gitlab.com/gitlab-org/gitlab-runner) 11.9 or later.
-- Your repository must be a GitLab repository, not an
- [external repository](../ci_cd_for_external_repos/index.md).
+Redundant merge train pipelines happen when:
-Merge trains do not work with [Semi-linear history merge requests](../../user/project/merge_requests/methods/index.md#merge-commit-with-semi-linear-history)
-or [fast-forward merge requests](../../user/project/merge_requests/methods/index.md#fast-forward-merge).
+- The pipeline fails for one of the merge requests in the merge train.
+- You [skip the merge train and merge immediately](#skip-the-merge-train-and-merge-immediately).
+- You [remove a merge request from a merge train](#remove-a-merge-request-from-a-merge-train).
+
+In these cases, GitLab must create new merge train pipelines for some or all of the
+merge requests on the train. The old pipelines were comparing against the previous
+combined changes in the merge train, which are no longer valid, so these old pipelines
+are cancelled.
## Enable merge trains
-To enable merge trains for your project:
+Prerequisites:
+
+- You must have the Maintainer role.
+- Your repository must be a GitLab repository, not an [external repository](../ci_cd_for_external_repos/index.md).
+- Your pipeline must be [configured to use merge request pipelines](merge_request_pipelines.md#prerequisites).
+ Otherwise your merge requests may become stuck in an unresolved state or your pipelines
+ might be dropped.
+
+To enable merge trains:
-1. If you are on a self-managed GitLab instance, ensure the [feature flag](#merge-trains-feature-flag) is set correctly.
-1. [Configure your CI/CD configuration file](merge_request_pipelines.md#prerequisites)
- so that the pipeline or individual jobs run for merge requests.
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Settings > Merge requests**.
1. In the **Merge method** section, verify that **Merge commit** is selected.
-1. In the **Merge options** section, select **Enable merged results pipelines** (if not already selected) and **Enable merge trains**.
+1. In the **Merge options** section:
+ - In GitLab 13.6 and later, select **Enable merged results pipelines** and **Enable merge trains**.
+ - In GitLab 13.5 and earlier, select **Enable merge trains and pipelines for merged results**.
+ Additionally, [a feature flag](#disable-merge-trains-in-gitlab-135-and-earlier)
+ must be set correctly.
1. Select **Save changes**.
-In GitLab 13.5 and earlier, there is only one checkbox, named
-**Enable merge trains and pipelines for merged results**.
+## Start a merge train
-WARNING:
-If you select the checkbox but don't configure your CI/CD to use
-merge request pipelines, your merge requests may become stuck in an
-unresolved state or your pipelines may be dropped.
+Prerequisites:
-## Start a merge train
+- You must have [permissions](../../user/permissions.md) to merge or push to the target branch.
To start a merge train:
1. Visit a merge request.
-1. Select **Start merge train**.
+1. Select:
+ - When no pipeline is running, **Start merge train**.
+ - When a pipeline is running, **Start merge train when pipeline succeeds**.
-![Start merge train](img/merge_train_start_v12_0.png)
+The merge request's merge train status displays under the pipeline widget with a
+message similar to `A new merge train has started and this merge request is the first of the queue.`
Other merge requests can now be added to the train.
## Add a merge request to a merge train
+Prerequisites:
+
+- You must have [permissions](../../user/permissions.md) to merge or push to the target branch.
+
To add a merge request to a merge train:
1. Visit a merge request.
-1. Select **Add to merge train**.
+1. Select:
+ - When no pipeline is running, **Add to merge train**.
+ - When a pipeline is running, **Add to merge train when pipeline succeeds**.
-If pipelines are already running for the merge request, you cannot add the merge request
-to the train. Instead, you can schedule to add the merge request to a merge train **when the latest
-pipeline succeeds**.
+The merge request's merge train status displays under the pipeline widget with a
+message similar to `Added to the merge train. There are 2 merge requests waiting to be merged.`
-![Add to merge train when pipeline succeeds](img/merge_train_start_when_pipeline_succeeds_v12_0.png)
+Each merge train can run a maximum of twenty pipelines in parallel. If you add more than
+twenty merge requests to the merge train, the extra merge requests are queued, waiting
+for pipelines to complete. There is no limit to the number of queued merge requests
+waiting to join the merge train.
## Remove a merge request from a merge train
-1. Visit a merge request.
-1. Select **Remove from merge train**.
-
-![Cancel merge train](img/merge_train_cancel_v12_0.png)
+To remove a merge request from a merge train, select **Remove from merge train**.
+You can add the merge request to a merge train again later.
-If you want to add the merge request to a merge train again later, you can.
+When you remove a merge request from a merge train:
-## View a merge request's current position on the merge train
+- All pipelines for merge requests queued after the removed merge request restart.
+- Redundant pipelines [are cancelled](#automatic-pipeline-cancellation).
-After a merge request has been added to the merge train, the merge request's
-current position is displayed under the pipeline widget:
+## Skip the merge train and merge immediately
-![Merge train position indicator](img/merge_train_position_v12_0.png)
+If you have a high-priority merge request, like a critical patch that must
+be merged urgently, select **Merge Immediately**.
-## Immediately merge a merge request with a merge train
+When you merge a merge request immediately:
-If you have a high-priority merge request (for example, a critical patch) that must
-be merged urgently, you can bypass the merge train by using the **Merge Immediately** option.
-This is the fastest option to get the change merged into the target branch.
-
-![Merge Immediately](img/merge_train_immediate_merge_v12_6.png)
+- The current merge train is recreated.
+- All pipelines restart.
+- Redundant pipelines [are cancelled](#automatic-pipeline-cancellation).
WARNING:
-Each time you merge a merge request immediately, the current merge train is recreated,
-all pipelines restart, and [redundant pipelines are cancelled](#automatic-pipeline-cancellation).
+Merging immediately can use a lot of CI/CD resources. Use this option
+only in critical situations.
-### Automatic pipeline cancellation
+## Disable merge trains in GitLab 13.5 and earlier **(PREMIUM SELF)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12996) in GitLab 12.3.
+In [GitLab 13.6 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/244831),
+you can [enable or disable merge trains in the project settings](#enable-merge-trains).
-GitLab CI/CD can detect the presence of redundant pipelines, and cancels them
-to conserve CI resources.
+In GitLab 13.5 and earlier, merge trains are automatically enabled when
+[merged results pipelines](merged_results_pipelines.md) are enabled.
+To use merged results pipelines but not merge trains, enable the `disable_merge_trains`
+[feature flag](../../user/feature_flags.md).
-When a user merges a merge request immediately in an ongoing merge
-train, the train is reconstructed, because it recreates the expected
-post-merge commit and pipeline. In this case, the merge train may already
-have pipelines running against the previous expected post-merge commit.
-These pipelines are considered redundant and are automatically
-canceled.
+[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
+can enable the feature flag to disable merge trains:
-## Troubleshooting
+```ruby
+Feature.enable(:disable_merge_trains)
+```
-### Merge request dropped from the merge train immediately
+After you enable this feature flag, GitLab cancels existing merge trains and removes
+the **Start/Add to merge train** option from merge requests.
-If a merge request is not mergeable (for example, it's a draft merge request or it has a merge
-conflict), the merge train drops your merge request automatically.
+To disable the feature flag, which enables merge trains again:
-In these cases, the reason for dropping the merge request is in the **system notes**.
+```ruby
+Feature.disable(:disable_merge_trains)
+```
-To check the reason:
+## Troubleshooting
-1. Open the merge request that was dropped from the merge train.
-1. Select the **Discussion** tab.
-1. Find a system note that includes either:
- - **... removed this merge request from the merge train because ...**
- - **... aborted this merge request from the merge train because ...**
+### Merge request dropped from the merge train
-The reason is given in the text after the **because ...** phrase.
+If a merge request becomes unmergeable while a merge train pipeline is running,
+the merge train drops your merge request automatically. For example, this could be caused by:
-![Merge train failure](img/merge_train_failure.png)
+- Changing the merge request to a [draft](../../user/project/merge_requests/drafts.md).
+- A merge conflict.
+- A new conversation thread that is unresolved, when [all threads must be resolved](../../user/discussions/index.md#prevent-merge-unless-all-threads-are-resolved)
+ is enabled.
-### Merge When Pipeline Succeeds cannot be chosen
+You can find reason the merge request was dropped from the merge train in the system
+notes. Check the **Activity** section in the **Overview** tab for a message similar to:
+`User removed this merge request from the merge train because ...`
-[Merge When Pipeline Succeeds](../../user/project/merge_requests/merge_when_pipeline_succeeds.md)
-is currently unavailable when merge trains are enabled.
+### Cannot use merge when pipeline succeeds
-See [the related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/12267)
+You cannot use [merge when pipeline succeeds](../../user/project/merge_requests/merge_when_pipeline_succeeds.md)
+when merge trains are enabled. See [the related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/12267)
for more information.
-### Merge train pipeline cannot be retried
+### Cannot retry merge train pipeline cannot
When a merge train pipeline fails, the merge request is dropped from the train and the pipeline can't be retried.
Merge train pipelines run on the merged result of the changes in the merge request and
-the changes from other merge requests already on the train. If the merge request is dropped from the train,
+changes from other merge requests already on the train. If the merge request is dropped from the train,
the merged result is out of date and the pipeline can't be retried.
-Instead, you should [add the merge request to the train](#add-a-merge-request-to-a-merge-train)
-again, which triggers a new pipeline.
-
-If a job only fails intermittently, you can try using the [`retry`](../yaml/index.md#retry)
-keyword in the `.gitlab-ci.yml` file to have the job retried before the pipeline completes.
-If it succeeds after a retry, the merge request is not removed from the merge train.
+You can:
-### Unable to add to merge train with message "The pipeline for this merge request failed."
+- [Add the merge request to the train](#add-a-merge-request-to-a-merge-train) again,
+ which triggers a new pipeline.
+- Add the [`retry`](../yaml/index.md#retry) keyword to the job if it fails intermittently.
+ If it succeeds after a retry, the merge request is not removed from the merge train.
-Sometimes the **Start/Add to merge train** button is not available and the merge request says,
-"The pipeline for this merge request failed. Please retry the job or push a new commit to fix the failure."
+### Unable to add to the merge train
-This issue occurs when [**Pipelines must succeed**](../../user/project/merge_requests/merge_when_pipeline_succeeds.md#require-a-successful-pipeline-for-merge)
-is enabled in **Settings > General > Merge requests**. This option requires that you
-run a new successful pipeline before you can re-add a merge request to a merge train.
+When [**Pipelines must succeed**](../../user/project/merge_requests/merge_when_pipeline_succeeds.md#require-a-successful-pipeline-for-merge)
+is enabled, but the latest pipeline failed:
-Merge trains ensure that each pipeline has succeeded before a merge happens, so
-you can:
+- The **Start/Add to merge train** option is not available.
+- The merge request displays `The pipeline for this merge request failed. Please retry the job or push a new commit to fix the failure.`
-- Clear the **Pipelines must succeed** checkbox.
-- Select the **Enable merged results pipelines** and **Enable merge trains** checkboxes.
+Before you can re-add a merge request to a merge train, you can try to:
- In GitLab 13.5 and earlier, there is only one checkbox, named
- **Enable merge trains and pipelines for merged results**.
-
-If you want to keep the **Pipelines must succeed** option selected along with merge
-trains, create a new merged results pipeline when this error occurs:
-
-1. On the **Pipelines** tab, select **Run pipeline**.
-1. Select **Start/Add to merge train when pipeline succeeds**.
+- Retry the failed job. If it passes, and no other jobs failed, the pipeline is marked as successful.
+- Rerun the whole pipeline. On the **Pipelines** tab, select **Run pipeline**.
+- Push a new commit that fixes the issue, which also triggers a new pipeline.
See [the related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/35135)
for more information.
-
-### Merge trains feature flag **(PREMIUM SELF)**
-
-In [GitLab 13.6 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/244831),
-you can [enable or disable merge trains in the project settings](#enable-merge-trains).
-
-In GitLab 13.5 and earlier, merge trains are automatically enabled when
-[merged results pipelines](merged_results_pipelines.md) are enabled.
-To use merged results pipelines without using merge trains, you can enable a
-[feature flag](../../user/feature_flags.md) that blocks the merge trains feature.
-
-[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
-can enable the feature flag to disable merge trains:
-
-```ruby
-Feature.enable(:disable_merge_trains)
-```
-
-After you enable this feature flag, all existing merge trains are cancelled and
-the **Start/Add to merge train** button no longer appears in merge requests.
-
-To disable the feature flag, and enable merge trains again:
-
-```ruby
-Feature.disable(:disable_merge_trains)
-```
diff --git a/doc/ci/pipelines/pipeline_architectures.md b/doc/ci/pipelines/pipeline_architectures.md
index e36eb24055f..1e4d32fc331 100644
--- a/doc/ci/pipelines/pipeline_architectures.md
+++ b/doc/ci/pipelines/pipeline_architectures.md
@@ -23,13 +23,18 @@ own advantages. These methods can be mixed and matched if needed:
- [Multi-project pipelines](downstream_pipelines.md#multi-project-pipelines): Good for larger products that require cross-project interdependencies,
like those with a [microservices architecture](https://about.gitlab.com/blog/2016/08/16/trends-in-version-control-land-microservices/).
+ For example, you might deploy your web application from three different GitLab projects.
+ With multi-project pipelines you can trigger a pipeline in each project, where each
+ has its own build, test, and deploy process. You can visualize the connected pipelines
+ in one place, including all cross-project interdependencies.
+
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
For an overview, see the [Multi-project pipelines demo](https://www.youtube.com/watch?v=g_PIwBM1J84).
## Basic Pipelines
This is the simplest pipeline in GitLab. It runs everything in the build stage concurrently,
-and once all of those finish, it runs everything in the test stage the same way, and so on.
+and once all of those finish, it runs everything in the test and subsequent stages the same way.
It's not the most efficient, and if you have lots of steps it can grow quite complex, but it's
easier to maintain:
diff --git a/doc/ci/pipelines/pipeline_efficiency.md b/doc/ci/pipelines/pipeline_efficiency.md
index aa2f074693a..276a03cb480 100644
--- a/doc/ci/pipelines/pipeline_efficiency.md
+++ b/doc/ci/pipelines/pipeline_efficiency.md
@@ -225,7 +225,7 @@ has more information about building efficient Docker images.
Methods to reduce Docker image size:
- Use a small base image, for example `debian-slim`.
-- Do not install convenience tools like vim, curl, and so on, if they aren't strictly needed.
+- Do not install convenience tools such as vim or curl if they aren't strictly needed.
- Create a dedicated development image.
- Disable man pages and docs installed by packages to save space.
- Reduce the `RUN` layers and combine software installation steps.
diff --git a/doc/ci/pipelines/schedules.md b/doc/ci/pipelines/schedules.md
index 0eeb0eada87..02728d5e1e0 100644
--- a/doc/ci/pipelines/schedules.md
+++ b/doc/ci/pipelines/schedules.md
@@ -95,6 +95,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/ci/pipelines/settings.md b/doc/ci/pipelines/settings.md
index d7155004359..a7f3cfb59d3 100644
--- a/doc/ci/pipelines/settings.md
+++ b/doc/ci/pipelines/settings.md
@@ -82,9 +82,10 @@ You can set pending or running pipelines to cancel automatically when a new pipe
Use the [`interruptible`](../yaml/index.md#interruptible) keyword to indicate if a
running job can be cancelled before it completes.
-## Skip outdated deployment jobs
+## Prevent outdated deployment jobs
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25276) in GitLab 12.9.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/25276) in GitLab 12.9.
+> - In GitLab 15.5, the behavior was [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/363328) to prevent outdated job runs.
Your project may have multiple concurrent deployment jobs that are
scheduled to run in the same time frame.
@@ -97,29 +98,10 @@ To avoid this scenario:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Settings > CI/CD**.
1. Expand **General pipelines**.
-1. Select the **Skip outdated deployment jobs** checkbox.
+1. Select the **Prevent outdated deployment jobs** checkbox.
1. Select **Save changes**.
-When a new deployment starts, older deployment jobs are skipped. Skipped jobs are labeled:
-
-- `forward deployment failure` in the pipeline view.
-- `The deployment job is older than the previously succeeded deployment job, and therefore cannot be run`
- when viewing the completed job.
-
-Job age is determined by the job start time, not the commit time, so a newer commit
-can be skipped in some circumstances.
-
-For more information, see [Deployment safety](../environments/deployment_safety.md).
-
-## Retry outdated jobs
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/211339) in GitLab 13.6.
-
-A deployment job can fail because a newer one has run. If you retry the failed deployment job, the
-environment could be overwritten with older source code. If you select **Retry**, a modal warns you
-about this and asks for confirmation.
-
-For more information, see [Deployment safety](../environments/deployment_safety.md).
+For more information, see [Deployment safety](../environments/deployment_safety.md#prevent-outdated-deployment-jobs).
## Specify a custom CI/CD configuration file
@@ -246,53 +228,6 @@ averaged.
To add test coverage results to a merge request using the project's `.gitlab-ci.yml` file, provide a regular expression
using the [`coverage`](../yaml/index.md#coverage) keyword.
-<!-- start_remove The following content will be removed on remove_date: '2023-08-22' -->
-
-### Add test coverage results using project settings (removed)
-
-> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/17633) in GitLab 14.8. Replaced by [`coverage` keyword](../yaml/index.md#coverage).
-> - [Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/17633) in GitLab 15.0.
-
-This feature is in its end-of-life process. It was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/17633)
-in GitLab 14.8. The feature is [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/17633) in GitLab 15.0.
-
-To migrate from a project setting to the `coverage` keyword, add the [former project setting](#locate-former-project-setting)
-to a CI/CD job. For example:
-
-- A Go test coverage project setting: `coverage: \d+.\d+% of statements`.
-- A CI/CD job with `coverage` keyword setting:
-
- ```yaml
- unit-test:
- stage: test
- coverage: '/coverage: \d+.\d+% of statements/'
- script:
- - go test -cover
- ```
-
-The `.gitlab-ci.yml` job [`coverage`](../yaml/index.md#coverage) keyword must be:
-
-- A regular expression starts and ends with the `/` character.
-- Defined as single-quoted string.
-
-You can verify correct syntax using the [pipeline editor](../pipeline_editor/index.md).
-
-#### Locate former project setting
-
-To migrate from the project coverage setting to the `coverage` keyword, use the
-regular expression displayed in the settings. Available in GitLab 14.10 and earlier:
-
-1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Settings > CI/CD**.
-1. Expand **General pipelines**.
-
-The regular expression you need is in the **Test coverage parsing** field.
-
-If you need to retrieve the project coverage setting from many projects, you can
-[use the API to programmatically retrieve the setting](https://gitlab.com/gitlab-org/gitlab/-/issues/17633#note_945941397).
-
-<!-- end_remove -->
-
### Test coverage examples
Use this regex for commonly used test tools.
@@ -302,6 +237,7 @@ Use this regex for commonly used test tools.
- Simplecov (Ruby). Example: `/\(\d+.\d+\%\) covered/`.
- pytest-cov (Python). Example: `/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/`.
- Scoverage (Scala). Example: `/Statement coverage[A-Za-z\.*]\s*:\s*([^%]+)/`.
+- `pest --coverage --colors=never` (PHP). Example: `/^\s*Cov:\s*\d+\.\d+?%$/`.
- `phpunit --coverage-text --colors=never` (PHP). Example: `/^\s*Lines:\s*\d+.\d+\%/`.
- gcovr (C/C++). Example: `/^TOTAL.*\s+(\d+\%)$/`.
- `tap --coverage-report=text-summary` (NodeJS). Example: `/^Statements\s*:\s*([^%]+)/`.
@@ -437,12 +373,12 @@ https://gitlab.example.com/<namespace>/<project>/badges/<branch>/coverage.svg
```
To get the coverage report from a specific job, add
-the `job=coverage_job_name` parameter to the URL. For example, the following
-Markdown code embeds the test coverage report badge of the `coverage` job
-in your `README.md`:
+the `job=coverage_job_name` parameter to the URL. For example, you can use code
+similar to the following to add the test coverage report badge of the `coverage` job
+to a Markdown file:
```markdown
-![coverage](https://gitlab.com/gitlab-org/gitlab/badges/main/coverage.svg?job=coverage)
+![coverage](https://gitlab.example.com/<namespace>/<project>/badges/<branch>/coverage.svg?job=coverage)
```
#### Test coverage report badge colors and limits
@@ -527,6 +463,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/ci/quick_start/index.md b/doc/ci/quick_start/index.md
index ad41e4fa88a..8d71f4569e5 100644
--- a/doc/ci/quick_start/index.md
+++ b/doc/ci/quick_start/index.md
@@ -1,50 +1,41 @@
---
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
---
-# Get started with GitLab CI/CD **(FREE)**
+# Tutorial: Create and run your first GitLab CI/CD pipeline **(FREE)**
-Use this document to get started with [GitLab CI/CD](../index.md).
+This tutorial shows you how to configure and run your first CI/CD pipeline in GitLab.
+
+## Prerequisites
Before you start, make sure you have:
- A project in GitLab that you would like to use CI/CD for.
- The Maintainer or Owner role for the project.
-If you are migrating from another CI/CD tool, view this documentation:
-
-- [Migrate from CircleCI](../migration/circleci.md).
-- [Migrate from Jenkins](../migration/jenkins.md).
+If you don't have a project, you can create a public project for free on <https://gitlab.com>.
-> - <i class="fa fa-youtube-play youtube" aria-hidden="true"></i>&nbsp;Watch [First time GitLab & CI/CD](https://www.youtube.com/watch?v=kTNfi5z6Uvk&t=553s). This includes a quick introduction to GitLab, the first steps with CI/CD, building a Go project, running tests, using the CI/CD pipeline editor, detecting secrets and security vulnerabilities and offers more exercises for asynchronous practice.
-> - <i class="fa fa-youtube-play youtube" aria-hidden="true"></i>&nbsp;Watch [Intro to GitLab CI](https://www.youtube.com/watch?v=l5705U8s_nQ&t=358s). This workshop uses the Web IDE to quickly get going with building source code using CI/CD, and run unit tests.
+## Steps
-## CI/CD process overview
-
-To use GitLab CI/CD:
+To create and run your first pipeline:
1. [Ensure you have runners available](#ensure-you-have-runners-available) to run your jobs.
- GitLab SaaS provides runners, so if you're using GitLab.com, you can skip this step.
- If you don't have a runner, [install GitLab Runner](https://docs.gitlab.com/runner/install/)
- and [register a runner](https://docs.gitlab.com/runner/register/) for your instance, project, or group.
+ If you're using GitLab.com, you can skip this step. GitLab.com provides shared runners for you.
+
1. [Create a `.gitlab-ci.yml` file](#create-a-gitlab-ciyml-file)
- at the root of your repository. This file is where you define your CI/CD jobs.
+ at the root of your repository. This file is where you define the CI/CD jobs.
When you commit the file to your repository, the runner runs your jobs.
The job results [are displayed in a pipeline](#view-the-status-of-your-pipeline-and-jobs).
-### Ensure you have runners available
+## Ensure you have runners available
In GitLab, runners are agents that run your CI/CD jobs.
-You might already have runners available for your project, including
-[shared runners](../runners/runners_scope.md), which are
-available to all projects in your GitLab instance.
-
To view available runners:
- Go to **Settings > CI/CD** and expand **Runners**.
@@ -52,34 +43,32 @@ To view available runners:
As long as you have at least one runner that's active, with a green circle next to it,
you have a runner available to process your jobs.
-If no runners are listed on the **Runners** page in the UI, you or an administrator
-must [install GitLab Runner](https://docs.gitlab.com/runner/install/) and
-[register](https://docs.gitlab.com/runner/register/) at least one runner.
+### If you don't have a runner
+
+If you don't have a runner:
+
+1. [Install GitLab Runner](https://docs.gitlab.com/runner/install/) on your local machine.
+1. [Register the runner](https://docs.gitlab.com/runner/register/) for your project.
+ Choose the `shell` executor.
-If you are testing CI/CD, you can install GitLab Runner and register runners on your local machine.
-When your CI/CD jobs run, they run on your local machine.
+When your CI/CD jobs run, in a later step, they will run on your local machine.
-### Create a `.gitlab-ci.yml` file
+## Create a `.gitlab-ci.yml` file
-The `.gitlab-ci.yml` file is a [YAML](https://en.wikipedia.org/wiki/YAML) file where
-you configure specific instructions for GitLab CI/CD.
+Now create a `.gitlab-ci.yml` file. It is a [YAML](https://en.wikipedia.org/wiki/YAML) file where
+you specify instructions for GitLab CI/CD.
In this file, you define:
- The structure and order of jobs that the runner should execute.
- The decisions the runner should make when specific conditions are encountered.
-For example, you might want to run a suite of tests when you commit to
-any branch except the default branch. When you commit to the default branch, you want
-to run the same suite, but also publish your application.
-
-All of this is defined in the `.gitlab-ci.yml` file.
-
To create a `.gitlab-ci.yml` file:
-1. On the left sidebar, select **Project information > Details**.
-1. Above the file list, select the branch you want to commit to,
- select the plus icon, then select **New file**:
+1. On the left sidebar, select **Repository > Files**.
+1. Above the file list, select the branch you want to commit to.
+ If you're not sure, leave `master` or `main`.
+ Then select the plus icon (**{plus}**) and **New file**:
![New file](img/new_file_v13_6.png)
@@ -112,46 +101,50 @@ To create a `.gitlab-ci.yml` file:
environment: production
```
- `$GITLAB_USER_LOGIN` and `$CI_COMMIT_BRANCH` are
- [predefined variables](../variables/predefined_variables.md)
- that populate when the job runs.
+ This example shows four jobs: `build-job`, `test-job1`, `test-job2`, and `deploy-prod`.
+ The comments listed in the `echo` commands are displayed in the UI when you view the jobs.
+ The values for the [predefined variables](../variables/predefined_variables.md)
+ `$GITLAB_USER_LOGIN` and `$CI_COMMIT_BRANCH` are populated when the jobs run.
1. Select **Commit changes**.
-The pipeline starts when the commit is committed.
+The pipeline starts and runs the jobs you defined in the `.gitlab-ci.yml` file.
+
+## View the status of your pipeline and jobs
+
+Now take a look at your pipeline and the jobs within.
+
+1. Go to **CI/CD > Pipelines**. A pipeline with three stages should be displayed:
+
+ ![Three stages](img/three_stages_v13_6.png)
-#### `.gitlab-ci.yml` tips
+1. View a visual representation of your pipeline by selecting the pipeline ID:
-- After you create your first `.gitlab-ci.yml` file, use the [pipeline editor](../pipeline_editor/index.md)
- for all future edits to the file. With the pipeline editor, you can:
- - Edit the pipeline configuration with automatic syntax highlighting and validation.
- - View the [CI/CD configuration visualization](../pipeline_editor/index.md#visualize-ci-configuration),
- a graphical representation of your `.gitlab-ci.yml` file.
-- If you want the runner to [use a Docker container to run the jobs](../docker/using_docker_images.md),
- edit the `.gitlab-ci.yml` file
- to include an image name:
+ ![Pipeline graph](img/pipeline_graph_v13_6.png)
- ```yaml
- default:
- image: ruby:2.7.5
- ```
+1. View details of a job by selecting the job name. For example, `deploy-prod`:
- This command tells the runner to use a Ruby image from Docker Hub
- and to run the jobs in a container that's generated from the image.
+ ![Job details](img/job_details_v13_6.png)
- This process is different than
- [building an application as a Docker container](../docker/using_docker_build.md).
- Your application does not need to be built as a Docker container to
- run CI/CD jobs in Docker containers.
+You have successfully created your first CI/CD pipeline in GitLab. Congratulations!
-- Each job contains scripts and stages:
+Now you can get started customizing your `.gitlab-ci.yml` and defining more advanced jobs.
+
+## `.gitlab-ci.yml` tips
+
+Here are some tips to get started working with the `.gitlab-ci.yml` file.
+
+For the complete `.gitlab-ci.yml` syntax, see [the full `.gitlab-ci.yml` keyword reference](../yaml/index.md).
+
+- Use the [pipeline editor](../pipeline_editor/index.md) to edit your `.gitlab-ci.yml` file.
+- Each job contains a script section and belongs to a stage:
- The [`default`](../yaml/index.md#default) keyword is for
custom defaults, for example with [`before_script`](../yaml/index.md#before_script)
and [`after_script`](../yaml/index.md#after_script).
- [`stage`](../yaml/index.md#stage) describes the sequential execution of jobs.
Jobs in a single stage run in parallel as long as there are available runners.
- - Use [Directed Acyclic Graphs (DAG)](../directed_acyclic_graph/index.md) keywords
- to run jobs out of stage order.
+ - Use the [`needs` keyword](../yaml/index.md#needs) to run jobs out of stage order.
+ This creates a [Directed Acyclic Graph (DAG)](../directed_acyclic_graph/index.md).
- You can set additional configuration to customize how your jobs and stages perform:
- Use the [`rules`](../yaml/index.md#rules) keyword to specify when to run or skip jobs.
The `only` and `except` legacy keywords are still supported, but can't be used
@@ -159,26 +152,10 @@ The pipeline starts when the commit is committed.
- Keep information across jobs and stages persistent in a pipeline with [`cache`](../yaml/index.md#cache)
and [`artifacts`](../yaml/index.md#artifacts). These keywords are ways to store
dependencies and job output, even when using ephemeral runners for each job.
-- For the complete `.gitlab-ci.yml` syntax, see [the full `.gitlab-ci.yml` reference topic](../yaml/index.md).
-
-### View the status of your pipeline and jobs
-
-When you committed your changes, a pipeline started.
-
-To view your pipeline:
-
-- Go to **CI/CD > Pipelines**.
-
- A pipeline with three stages should be displayed:
-
- ![Three stages](img/three_stages_v13_6.png)
-
-- To view a visual representation of your pipeline, select the pipeline ID.
-
- ![Pipeline graph](img/pipeline_graph_v13_6.png)
-
-- To view details of a job, select the job name, for example, `deploy-prod`.
- ![Job details](img/job_details_v13_6.png)
+## Related topics
-If the job status is `stuck`, check to ensure a runner is properly configured for the project.
+- [Follow this guide to migrate from CircleCI](../migration/circleci.md).
+- [Follow this guide to migrate from Jenkins](../migration/jenkins.md).
+- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i>&nbsp;Watch [First time GitLab & CI/CD](https://www.youtube.com/watch?v=kTNfi5z6Uvk&t=553s). This includes a quick introduction to GitLab, the first steps with CI/CD, building a Go project, running tests, using the CI/CD pipeline editor, detecting secrets and security vulnerabilities and offers more exercises for asynchronous practice.
+- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i>&nbsp;Watch [Intro to GitLab CI](https://www.youtube.com/watch?v=l5705U8s_nQ&t=358s). This workshop uses the Web IDE to quickly get going with building source code using CI/CD, and run unit tests.
diff --git a/doc/ci/resource_groups/index.md b/doc/ci/resource_groups/index.md
index 2803ddba828..b46008abb07 100644
--- a/doc/ci/resource_groups/index.md
+++ b/doc/ci/resource_groups/index.md
@@ -89,7 +89,7 @@ The following modes are supported:
that are sorted by pipeline ID in descending order.
This mode is efficient when you want to ensure that the jobs are executed from the newest pipeline and
- cancel all of the old deploy jobs with the [skip outdated deployment jobs](../environments/deployment_safety.md#skip-outdated-deployment-jobs) feature.
+ prevent all of the old deploy jobs with the [prevent outdated deployment jobs](../environments/deployment_safety.md#prevent-outdated-deployment-jobs) feature.
This is the most efficient option in terms of the pipeline efficiency, but you must ensure that each deployment job is idempotent.
### Change the process mode
@@ -171,7 +171,6 @@ deploy:
include: deploy.gitlab-ci.yml
strategy: depend
resource_group: AWS-production
- environment: production
```
```yaml
diff --git a/doc/ci/review_apps/index.md b/doc/ci/review_apps/index.md
index 2f23ebbfd9f..7a0f43f9ec5 100644
--- a/doc/ci/review_apps/index.md
+++ b/doc/ci/review_apps/index.md
@@ -4,96 +4,96 @@ group: Pipeline 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
---
-# Review Apps **(FREE)**
+# Review apps **(FREE)**
-Review Apps is a collaboration tool that assists with providing an environment to showcase product changes.
+Review apps are a collaboration tool that provide an environment to showcase product changes.
NOTE:
If you have a Kubernetes cluster, you can automate this feature in your applications
by using [Auto DevOps](../../topics/autodevops/index.md).
-Review Apps:
+Review apps:
- Provide an automatic live preview of changes made in a feature branch by spinning up a dynamic environment for your merge requests.
- Allow designers and product managers to see your changes without needing to check out your branch and run your changes in a sandbox environment.
- Are fully integrated with the [GitLab DevOps LifeCycle](../../index.md#the-entire-devops-lifecycle).
- Allow you to deploy your changes wherever you want.
-![Review Apps Workflow](img/continuous-delivery-review-apps.svg)
+![review apps workflow](img/continuous-delivery-review-apps.svg)
In the previous example:
-- A Review App is built every time a commit is pushed to `topic branch`.
+- A review app is built every time a commit is pushed to `topic branch`.
- The reviewer fails two reviews before passing the third review.
- After the review passes, `topic branch` is merged into the default branch, where it's deployed to staging.
- After its approval in staging, the changes that were merged into the default branch are deployed to production.
-## How Review Apps work
+## How review apps work
-A Review App is a mapping of a branch with an [environment](../environments/index.md).
-Access to the Review App is made available as a link on the [merge request](../../user/project/merge_requests/index.md) relevant to the branch.
+A review app is a mapping of a branch with an [environment](../environments/index.md).
+Access to the review app is made available as a link on the [merge request](../../user/project/merge_requests/index.md) relevant to the branch.
The following is an example of a merge request with an environment set dynamically.
-![Review App in merge request](img/review_apps_preview_in_mr.png)
+![review app in merge request](img/review_apps_preview_in_mr.png)
In this example, a branch was:
- Successfully built.
- Deployed under a dynamic environment that can be reached by selecting **View app**.
-After adding Review Apps to your workflow, you follow the branched Git flow. That is:
+After adding review apps to your workflow, you follow the branched Git flow. That is:
-1. Push a branch and let the runner deploy the Review App based on the `script` definition of the dynamic environment job.
+1. Push a branch and let the runner deploy the review app based on the `script` definition of the dynamic environment job.
1. Wait for the runner to build and deploy your web application.
1. To view the changes live, select the link in the merge request related to the branch.
-## Configuring Review Apps
+## Configuring review apps
-Review Apps are built on [dynamic environments](../environments/index.md#create-a-dynamic-environment), which allow you to dynamically create a new environment for each branch.
+Review apps are built on [dynamic environments](../environments/index.md#create-a-dynamic-environment), which allow you to dynamically create a new environment for each branch.
-The process of configuring Review Apps is as follows:
+The process of configuring review apps is as follows:
-1. Set up the infrastructure to host and deploy the Review Apps (check the [examples](#review-apps-examples) below).
+1. Set up the infrastructure to host and deploy the review apps (check the [examples](#review-apps-examples) below).
1. [Install](https://docs.gitlab.com/runner/install/) and [configure](https://docs.gitlab.com/runner/commands/) a runner to do deployment.
1. Set up a job in `.gitlab-ci.yml` that uses the [predefined CI/CD variable](../variables/index.md) `${CI_COMMIT_REF_SLUG}`
to create dynamic environments and restrict it to run only on branches.
- Alternatively, you can get a YAML template for this job by [enabling review apps](#enable-review-apps-button) for your project.
-1. Optionally, set a job that [manually stops](../environments/index.md#stop-an-environment) the Review Apps.
+ Alternatively, you can get a YAML template for this job by [enabling review apps](#enable-review-app-button) for your project.
+1. Optionally, set a job that [manually stops](../environments/index.md#stop-an-environment) the review apps.
-### Enable Review Apps button
+### Enable review app button
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118844) in GitLab 12.8.
-When configuring Review Apps for a project, you add a new job to the `.gitlab-ci.yml` file,
+When configuring review apps for a project, you add a new job to the `.gitlab-ci.yml` file,
as mentioned above. To facilitate this, and if you are using Kubernetes, you can select
-**Enable Review Apps** and GitLab prompts you with a template code block that
+**Enable review app** and GitLab prompts you with a template code block that
you can copy and paste into `.gitlab-ci.yml` as a starting point.
Prerequisite:
- You need at least the Developer role for the project.
-To use the Review Apps template:
+To use the review apps template:
-1. On the top bar, select **Main menu > Projects** and find the project you want to create a Review App job for.
+1. On the top bar, select **Main menu > Projects** and find the project you want to create a review app job for.
1. On the left sidebar, select **Deployments > Environments**.
-1. Select **Enable Review Apps**.
+1. Select **Enable review app**.
1. Copy the provided code snippet and paste it into your
`.gitlab-ci.yml` file:
- ![Enable Review Apps modal](img/enable_review_app_v12_8.png)
+ ![enable review apps modal](img/enable_review_app_v12_8.png)
You can edit this template as needed.
-## Review Apps auto-stop
+## Review apps auto-stop
-See how to [configure Review Apps environments to expire and auto-stop](../environments/index.md#stop-an-environment-after-a-certain-time-period)
+See how to [configure review apps environments to expire and auto-stop](../environments/index.md#stop-an-environment-after-a-certain-time-period)
after a given period of time.
-## Review Apps examples
+## Review apps examples
-The following are example projects that demonstrate Review App configuration:
+The following are example projects that demonstrate review app configuration:
| Project | Configuration file |
|-------------------------------------------------------------------------|--------------------|
@@ -104,17 +104,17 @@ The following are example projects that demonstrate Review App configuration:
| [`https://about.gitlab.com/`](https://gitlab.com/gitlab-com/www-gitlab-com/) | [`.gitlab-ci.yml`](https://gitlab.com/gitlab-com/www-gitlab-com/-/blob/6ffcdc3cb9af2abed490cbe5b7417df3e83cd76c/.gitlab-ci.yml#L332) |
| [GitLab Insights](https://gitlab.com/gitlab-org/gitlab-insights/) | [`.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab-insights/-/blob/9e63f44ac2a5a4defc965d0d61d411a768e20546/.gitlab-ci.yml#L234) |
-Other examples of Review Apps:
+Other examples of review apps:
- <i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
[Cloud Native Development with GitLab](https://www.youtube.com/watch?v=jfIyQEwrocw).
-- [Review Apps for Android](https://about.gitlab.com/blog/2020/05/06/how-to-create-review-apps-for-android-with-gitlab-fastlane-and-appetize-dot-io/).
+- [Review apps for Android](https://about.gitlab.com/blog/2020/05/06/how-to-create-review-apps-for-android-with-gitlab-fastlane-and-appetize-dot-io/).
## Route Maps
Route Maps allows you to go directly from source files
to public pages on the [environment](../environments/index.md) defined for
-Review Apps.
+review apps.
Once set up, the review app link in the merge request
widget can take you directly to the pages changed, making it easier
@@ -198,7 +198,7 @@ After you have the route mapping set up, it takes effect in the following locati
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10761) in GitLab 12.0.
> - [Moved](https://about.gitlab.com/blog/2021/01/26/new-gitlab-product-subscription-model/) to GitLab Premium in 13.9.
> - It's [deployed behind a feature flag](../../user/feature_flags.md), `anonymous_visual_review_feedback`, disabled by default.
-> - It's enabled on GitLab.com.
+> - It's disabled on GitLab.com.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available,
@@ -209,7 +209,7 @@ With Visual Reviews, members of any team (Product, Design, Quality, and so on) c
### Using Visual Reviews
After Visual Reviews has been [configured](#configure-review-apps-for-visual-reviews) for the
-Review App, the Visual Reviews feedback form is overlaid on the right side of every page.
+review app, the Visual Reviews feedback form is overlaid on the right side of every page.
![Visual review feedback form](img/toolbar_feedback_form_v13_5.png)
@@ -227,9 +227,9 @@ To use the feedback form to make a comment in the merge request:
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
To see Visual reviews in action, see the [Visual Reviews Walk through](https://youtu.be/1_tvWTlPfM4).
-### Configure Review Apps for Visual Reviews
+### Configure review apps for Visual Reviews
-The feedback form is served through a script you add to pages in your Review App.
+The feedback form is served through a script you add to pages in your review app.
It should be added to the `<head>` of your application and
consists of some project and merge request specific values. Here's how it
looks for a project with code hosted in a project on GitLab.com:
diff --git a/doc/ci/runners/configure_runners.md b/doc/ci/runners/configure_runners.md
index 19e0c1e3c81..c675f7204ec 100644
--- a/doc/ci/runners/configure_runners.md
+++ b/doc/ci/runners/configure_runners.md
@@ -97,6 +97,13 @@ Whenever a project is forked, it copies the settings of the jobs that relate
to it. This means that if you have shared runners set up for a project and
someone forks that project, the shared runners serve jobs of this project.
+Because of a [known issue](https://gitlab.com/gitlab-org/gitlab/-/issues/364303), you might encounter the message `An error occurred while forking the project. Please try again.` if the runner settings of the project you are forking does not match the new project namespace.
+
+To work around this issue, you should make sure that the shared runner settings are consistent in the forked project and the new namespace.
+
+- If shared runners are **enabled** on the forked project, then this should also be **enabled** on the new namespace.
+- If shared runners are **disabled** on the forked project, then this should also be **disabled** on the new namespace.
+
### Attack vectors in runners
Mentioned briefly earlier, but the following things of runners can be exploited.
@@ -299,12 +306,14 @@ globally or for individual jobs:
- [`GIT_STRATEGY`](#git-strategy)
- [`GIT_SUBMODULE_STRATEGY`](#git-submodule-strategy)
+- [`GIT_SUBMODULE_PATHS`](#sync-or-exclude-specific-submodules-from-ci-jobs)
- [`GIT_CHECKOUT`](#git-checkout)
- [`GIT_CLEAN_FLAGS`](#git-clean-flags)
- [`GIT_FETCH_EXTRA_FLAGS`](#git-fetch-extra-flags)
- [`GIT_SUBMODULE_PATHS`](#git-submodule-paths)
- [`GIT_SUBMODULE_UPDATE_FLAGS`](#git-submodule-update-flags)
- [`GIT_DEPTH`](#shallow-cloning) (shallow cloning)
+- [`GIT_SUBMODULE_DEPTH`](#git-submodule-depth)
- [`GIT_CLONE_PATH`](#custom-build-directories) (custom build directories)
- [`TRANSFER_METER_FREQUENCY`](#artifact-and-cache-settings) (artifact/cache meter update frequency)
- [`ARTIFACT_COMPRESSION_LEVEL`](#artifact-and-cache-settings) (artifact archiver compression level)
@@ -556,6 +565,34 @@ You should be aware of the implications for the security, stability, and reprodu
your builds when using the `--remote` flag. In most cases, it is better to explicitly track
submodule commits as designed, and update them using an auto-remediation/dependency bot.
+### Sync or exclude specific submodules from CI jobs
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/26495) in GitLab Runner 14.0.
+
+Some projects have a large number of submodules, and not all of them need to be
+synced or updated in all CI jobs. Use the `GIT_SUBMODULE_PATHS` variable to control this behavior.
+The path syntax is the same as [`git submodule`](https://git-scm.com/docs/git-submodule#Documentation/git-submodule.txt-ltpathgt82308203):
+
+- To sync and update specific paths:
+
+ ```yaml
+ variables:
+ GIT_SUBMODULE_PATHS: 'submoduleA'
+ ```
+
+- To exclude specific paths:
+
+ ```yaml
+ variables:
+ GIT_SUBMODULE_PATHS: ':(exclude)submoduleA'
+ ```
+
+WARNING:
+Git ignores nested and multiple submodule paths. To ignore a nested submodule, exclude
+the parent submodule and then manually clone it in the job's scripts. For example,
+ `git clone <repo> --recurse-submodules=':(exclude)nested-submodule'`. Make sure
+to wrap the string in single quotes so the YAML can be parsed successfully.
+
### Shallow cloning
> Introduced in GitLab 8.9 as an experimental feature.
@@ -590,6 +627,24 @@ variables:
You can set it globally or per-job in the [`variables`](../yaml/index.md#variables) section.
+### Git submodule depth
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/merge_requests/3651) in GitLab Runner 15.5.
+
+Use the `GIT_SUBMODULE_DEPTH` variable to specify the depth of fetching and cloning submodules
+when [`GIT_SUBMODULE_STRATEGY`](#git-submodule-strategy) is set to either `normal` or `recursive`.
+You can set it globally or for a specific job in the [`variables`](../yaml/index.md#variables) section.
+
+When you set the `GIT_SUBMODULE_DEPTH` variable, it overwrites the [`GIT_DEPTH`](#shallow-cloning) setting
+for the submodules only.
+
+To fetch or clone only the last 3 commits:
+
+```yaml
+variables:
+ GIT_SUBMODULE_DEPTH: 3
+```
+
### Custom build directories
> [Introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/2211) in GitLab Runner 11.10.
@@ -752,7 +807,7 @@ variables:
NOTE:
Zip archives are the only supported artifact type. Follow [the issue for details](https://gitlab.com/gitlab-org/gitlab/-/issues/367203).
-GitLab Runner can generate and produce attestation metadata for all build artifacts. To enable this feature, you must set the `RUNNER_GENERATE_ARTIFACTS_METADATA` environment variable to `true`. This variable can either be set globally or it can be set for individual jobs. The metadata is in rendered in a plain text `.json` file that's stored with the artifact. The file name is as follows: `{JOB_ID}-artifacts-metadata.json`.
+GitLab Runner can generate and produce attestation metadata for all build artifacts. To enable this feature, you must set the `RUNNER_GENERATE_ARTIFACTS_METADATA` environment variable to `true`. This variable can either be set globally or it can be set for individual jobs. The metadata is in rendered in a plain text `.json` file that's stored with the artifact. The file name is as follows: `{ARTIFACT_NAME}-metadata.json` where `ARTIFACT_NAME` is what was defined as the [name for the artifact](../pipelines/job_artifacts.md#use-cicd-variables-to-define-the-artifacts-name) in the CI file. The file name, however, defaults to `artifacts-metadata.json` if no name was given to the build artifacts.
### Attestation format
diff --git a/doc/ci/runners/index.md b/doc/ci/runners/index.md
index 405310fb8ba..41cde709143 100644
--- a/doc/ci/runners/index.md
+++ b/doc/ci/runners/index.md
@@ -1,6 +1,6 @@
---
stage: Verify
-group: Runner
+group: Runner SaaS
info: To 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/runners/runners_scope.md b/doc/ci/runners/runners_scope.md
index 4be4ed33feb..6354a519810 100644
--- a/doc/ci/runners/runners_scope.md
+++ b/doc/ci/runners/runners_scope.md
@@ -192,6 +192,25 @@ You must have the Owner role for the group.
From this page, you can edit, pause, and remove runners from the group, its subgroups, and projects.
+#### Delete multiple group runners
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/361721/) in GitLab 15.6
+
+Prerequisites:
+
+- You must have either:
+ - Owner role for the group.
+ - Access to delete any runners in the group.
+
+To delete multiple runners in a single action in the group list:
+
+1. On the top bar, select **Main menu > Groups** and find your group.
+1. On the left sidebar, select **CI/CD > Runners**.
+1. To delete multiple runners, you can either:
+ - Select the checkbox next to the runner.
+ - Select the checkbox at the top of the runner list to select all runners in the list.
+1. To delete the runners, select **Delete selected**.
+
#### Filter group runners to show only inherited
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/337838/) in GitLab 15.5.
diff --git a/doc/ci/runners/saas/linux_saas_runner.md b/doc/ci/runners/saas/linux_saas_runner.md
index d1c63ab7291..df7d5570953 100644
--- a/doc/ci/runners/saas/linux_saas_runner.md
+++ b/doc/ci/runners/saas/linux_saas_runner.md
@@ -116,7 +116,7 @@ The `CI_PRE_CLONE_SCRIPT` variable does not work on GitLab SaaS Windows or macOS
This example was used in the `gitlab-org/gitlab` project until November 2021.
The project no longer uses this optimization because the
[pack-objects cache](../../../administration/gitaly/configure_gitaly.md#pack-objects-cache)
-lets Gitaly serve the full CI/CD fetch traffic. See [Git fetch caching](../../../development/pipelines.md#git-fetch-caching).
+lets Gitaly serve the full CI/CD fetch traffic. See [Git fetch caching](../../../development/pipelines/performance.md#git-fetch-caching).
The `CI_PRE_CLONE_SCRIPT` was defined as a project CI/CD variable:
diff --git a/doc/ci/runners/saas/macos_saas_runner.md b/doc/ci/runners/saas/macos_saas_runner.md
index 50c24349712..cd40aac25bc 100644
--- a/doc/ci/runners/saas/macos_saas_runner.md
+++ b/doc/ci/runners/saas/macos_saas_runner.md
@@ -14,7 +14,7 @@ Use these runners to build, test, and deploy apps for the Apple ecosystem (macOS
of all the capabilities of the GitLab single DevOps platform and not have to manage or operate a
build environment.
-Jobs handled by macOS shared runners on GitLab.com **time out after 2 hours**, regardless of the timeout configured in a project.
+Jobs handled by macOS shared runners on GitLab.com **time out after 3 hours**, regardless of the timeout configured in a project.
## Access request process
diff --git a/doc/ci/secrets/index.md b/doc/ci/secrets/index.md
index 62350905bd4..a5082af89bc 100644
--- a/doc/ci/secrets/index.md
+++ b/doc/ci/secrets/index.md
@@ -20,11 +20,11 @@ required by a job. Read [GitLab CI/CD pipeline configuration reference](../yaml/
for more information about the syntax.
GitLab has selected [Vault by HashiCorp](https://www.vaultproject.io) as the
-first supported provider, and [KV-V2](https://www.vaultproject.io/docs/secrets/kv/kv-v2)
+first supported provider, and [KV-V2](https://developer.hashicorp.com/vault/docs/secrets/kv/kv-v2)
as the first supported secrets engine.
GitLab authenticates using Vault's
-[JSON Web Token (JWT) authentication method](https://www.vaultproject.io/docs/auth/jwt#jwt-authentication), using
+[JSON Web Token (JWT) authentication method](https://developer.hashicorp.com/vault/docs/auth/jwt#jwt-authentication), using
the [JSON Web Token](https://gitlab.com/gitlab-org/gitlab/-/issues/207125) (`CI_JOB_JWT`)
introduced in GitLab 12.10.
@@ -88,10 +88,10 @@ To configure your Vault server:
- `VAULT_SERVER_URL` - The URL of your Vault server, such as `https://vault.example.com:8200`.
Required.
- `VAULT_AUTH_ROLE` - Optional. The role to use when attempting to authenticate.
- If no role is specified, Vault uses the [default role](https://www.vaultproject.io/api-docs/auth/jwt#default_role)
+ If no role is specified, Vault uses the [default role](https://developer.hashicorp.com/vault/api-docs/auth/jwt#default_role)
specified when the authentication method was configured.
- `VAULT_AUTH_PATH` - Optional. The path where the authentication method is mounted, default is `jwt`.
- - `VAULT_NAMESPACE` - Optional. The [Vault Enterprise namespace](https://www.vaultproject.io/docs/enterprise/namespaces) to use for reading secrets and authentication.
+ - `VAULT_NAMESPACE` - Optional. The [Vault Enterprise namespace](https://developer.hashicorp.com/vault/docs/enterprise/namespaces) to use for reading secrets and authentication.
If no namespace is specified, Vault uses the `root` ("`/`") namespace.
The setting is ignored by Vault Open Source.
@@ -142,7 +142,7 @@ When a CI job attempts to authenticate, it specifies a role. You can use roles t
different policies together. If authentication is successful, these policies are
attached to the resulting Vault token.
-[Bound claims](https://www.vaultproject.io/docs/auth/jwt#bound-claims) are predefined
+[Bound claims](https://developer.hashicorp.com/vault/docs/auth/jwt#bound-claims) are predefined
values that are matched to the JWT's claims. With bounded claims, you can restrict access
to specific GitLab users, specific projects, or even jobs running for specific Git
references. You can have as many bounded claims you need, but they must *all* match
@@ -183,7 +183,7 @@ For a full list of `CI_JOB_JWT` claims, read the
You can also specify some attributes for the resulting Vault tokens, such as time-to-live,
IP address range, and number of uses. The full list of options is available in
-[Vault's documentation on creating roles](https://www.vaultproject.io/api-docs/auth/jwt#create-role)
+[Vault's documentation on creating roles](https://developer.hashicorp.com/vault/api-docs/auth/jwt#create-role)
for the JSON web token method.
## Using a self-signed Vault server
diff --git a/doc/ci/services/index.md b/doc/ci/services/index.md
index 0f82f2301c7..830b9406c6e 100644
--- a/doc/ci/services/index.md
+++ b/doc/ci/services/index.md
@@ -37,7 +37,7 @@ the CI container itself.
## How services are linked to the job
To better understand how container linking works, read
-[Linking containers together](https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/).
+[Linking containers together](https://docs.docker.com/network/links/).
If you add `mysql` as service to your application, the image is
used to create a container that's linked to the job container.
@@ -392,6 +392,46 @@ time.
1. Check the exit status of build script.
1. Remove the build container and all created service containers.
+## Capturing service container logs
+
+Logs generated by applications running in service containers can be captured for subsequent examination and debugging.
+You might want to look at service container's logs when the service container has started successfully, but is not
+behaving es expected, leading to job failures. The logs can indicate missing or incorrect configuration of the service
+within the container.
+
+`CI_DEBUG_SERVICES` should only by enabled when service containers are being actively debugged as there are both storage
+and performance consequences to capturing service container logs.
+
+To enable service logging, add the `CI_DEBUG_SERVICES` variable to the project's
+`.gitlab-ci.yml` file:
+
+```yaml
+variables:
+ CI_DEBUG_SERVICES: "true"
+```
+
+Accepted values are:
+
+- Enabled: `TRUE`, `true`, `True`
+- Disabled: `FALSE`, `false`, `False`
+
+Any other values will result in an error message and effectively disable the feature.
+
+When enabled, logs for _all_ service containers will be captured and streamed into the jobs trace log concurrently with
+other logs. Logs from each container will be prefixed with the container's aliases, and displayed in a different color.
+
+NOTE:
+You may want to adjust the logging level in the service container for which you want to capture logs since the default
+logging level may not provide sufficient details to diagnose job failures.
+
+WARNING:
+Enabling `CI_DEBUG_SERVICES` _may_ result in masked variables being revealed. When `CI_DEBUG_SERVICES` is enabled,
+service container logs and the CI job's logs are streamed to the job's trace log _concurrently_, which makes it possible
+for a service container log to be inserted _inside_ a job's masked log. This would thwart the variable masking mechanism
+and result in the masked variable being revealed.
+
+See [Mask a CI/CD Variable](../variables/index.md#mask-a-cicd-variable)
+
## Debug a job locally
The following commands are run without root privileges. You should be
diff --git a/doc/ci/testing/code_quality.md b/doc/ci/testing/code_quality.md
index 7345c7ca5eb..d1ed28b79c0 100644
--- a/doc/ci/testing/code_quality.md
+++ b/doc/ci/testing/code_quality.md
@@ -339,6 +339,20 @@ This example is specific to GitLab Code Quality. For more general
instructions on how to configure DinD with a registry mirror, see the
relevant [documentation](../docker/using_docker_build.md#enable-registry-mirror-for-dockerdind-service).
+#### List of images to be stored in the private container registry
+
+The following images are needed for the [default `.codeclimate.yml`](https://gitlab.com/gitlab-org/ci-cd/codequality/-/blob/master/codeclimate_defaults/.codeclimate.yml.template):
+
+- `codeclimate/codeclimate-structure:latest`
+- `codeclimate/codeclimate-csslint:latest`
+- `codeclimate/codeclimate-coffeelint:latest`
+- `codeclimate/codeclimate-duplication:latest`
+- `codeclimate/codeclimate-eslint:latest`
+- `codeclimate/codeclimate-fixme:latest`
+- `codeclimate/codeclimate-rubocop:rubocop-0-92`
+
+If you are using a custom `.codeclimate.yml` configuration file, you must add the specified plugins in your private container registry.
+
#### Configure Code Quality to use the Dependency Proxy
Prerequisite:
diff --git a/doc/ci/testing/load_performance_testing.md b/doc/ci/testing/load_performance_testing.md
index 6e1b440f252..ba7bf14fb59 100644
--- a/doc/ci/testing/load_performance_testing.md
+++ b/doc/ci/testing/load_performance_testing.md
@@ -138,7 +138,7 @@ For example, you can override the duration of the test with a CLI option:
```
GitLab only displays the key performance metrics in the MR widget if k6's results are saved
-via [summary export](https://k6.io/docs/results-visualization/json#summary-export)
+via [summary export](https://k6.io/docs/results-output/real-time/json/#summary-export)
as a [Load Performance report artifact](../yaml/artifacts_reports.md#artifactsreportsload_performance).
The latest Load Performance artifact available is always used, using the
summary values from the test.
diff --git a/doc/ci/testing/test_coverage_visualization.md b/doc/ci/testing/test_coverage_visualization.md
index ee6b47e69a5..9bff8dbf780 100644
--- a/doc/ci/testing/test_coverage_visualization.md
+++ b/doc/ci/testing/test_coverage_visualization.md
@@ -360,7 +360,7 @@ The following [`.gitlab-ci.yml`](../yaml/index.md) example for Go uses:
- [`gocover-cobertura`](https://github.com/boumenot/gocover-cobertura) to convert Go's coverage profile into the Cobertura XML format.
This example assumes that [Go modules](https://go.dev/ref/mod)
-are being used. Please note that the `-covermode count` option does not work with the `-race` flag.
+are being used. The `-covermode count` option does not work with the `-race` flag.
If you want to generate code coverage while also using the `-race` flag, you must switch to
`-covermode atomic` which is slower than `-covermode count`. See [this blog post](https://go.dev/blog/cover)
for more details.
diff --git a/doc/ci/testing/unit_test_report_examples.md b/doc/ci/testing/unit_test_report_examples.md
index c14e4eedd7c..5d4cfa88d88 100644
--- a/doc/ci/testing/unit_test_report_examples.md
+++ b/doc/ci/testing/unit_test_report_examples.md
@@ -18,7 +18,10 @@ Use the following job in `.gitlab-ci.yml`. This includes the `artifacts:paths` k
```yaml
## Use https://github.com/sj26/rspec_junit_formatter to generate a JUnit report format XML file with rspec
ruby:
+ image: ruby:3.0.4
stage: test
+ before_script:
+ - apt-get update -y && apt-get install -y bundler
script:
- bundle install
- bundle exec rspec --format progress --format RspecJunitFormatter --out rspec.xml
diff --git a/doc/ci/triggers/index.md b/doc/ci/triggers/index.md
index cafa64c4832..a667836fee4 100644
--- a/doc/ci/triggers/index.md
+++ b/doc/ci/triggers/index.md
@@ -193,3 +193,11 @@ A response of `{"message":"404 Not Found"}` when triggering a pipeline might be
by using a [personal access token](../../user/profile/personal_access_tokens.md)
instead of a trigger token. [Create a new trigger token](#create-a-trigger-token)
and use it instead of the personal access token.
+
+### `The requested URL returned error: 400` when triggering a pipeline
+
+If you attempt to trigger a pipeline by using a `ref` that is a branch name that
+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.
diff --git a/doc/ci/troubleshooting.md b/doc/ci/troubleshooting.md
index 8f78469af18..87ebff74600 100644
--- a/doc/ci/troubleshooting.md
+++ b/doc/ci/troubleshooting.md
@@ -182,6 +182,14 @@ a branch pipeline instead.
It's also possible that your [`workflow: rules`](yaml/index.md#workflow) configuration
blocked the pipeline, or allowed the wrong pipeline type.
+### Pipeline with many jobs fails to start
+
+A Pipeline that has more jobs than the instance's defined [CI/CD limits](../user/admin_area/settings/continuous_integration.md#set-cicd-limits)
+fails to start.
+
+To reduce the number of jobs in your pipeline, you can split your `.gitlab-ci.yml`
+configuration using [parent-child pipelines](../ci/pipelines/pipeline_architectures.md#parent-child-pipelines).
+
### A job runs unexpectedly
A common reason a job is added to a pipeline unexpectedly is because the `changes`
@@ -285,14 +293,14 @@ has failed or been canceled.
If a merge request pipeline or merged result pipeline was canceled or failed, you can:
-- Re-run the entire pipeline by clicking **Run pipeline** in the pipeline tab in the merge request.
+- Re-run the entire pipeline by selecting **Run pipeline** in the pipeline tab in the merge request.
- [Retry only the jobs that failed](pipelines/index.md#view-pipelines). If you re-run the entire pipeline, this is not necessary.
- Push a new commit to fix the failure.
If the merge train pipeline has failed, you can:
- Check the failure and determine if you can use the [`/merge` quick action](../user/project/quick_actions.md) to immediately add the merge request to the train again.
-- Re-run the entire pipeline by clicking **Run pipeline** in the pipeline tab in the merge request, then add the merge request to the train again.
+- Re-run the entire pipeline by selecting **Run pipeline** in the pipeline tab in the merge request, then add the merge request to the train again.
- Push a commit to fix the failure, then add the merge request to the train again.
If the merge train pipeline was canceled before the merge request was merged, without a failure, you can:
@@ -400,6 +408,77 @@ This flag reduces system resource usage on the `jobs/request` endpoint.
When enabled, jobs created in the last hour can run in projects which are out of quota.
Earlier jobs are already canceled by a periodic background worker (`StuckCiJobsWorker`).
+## CI/CD troubleshooting rails console commands
+
+The following commands are run in the [rails console](../administration/operations/rails_console.md#starting-a-rails-console-session).
+
+WARNING:
+Any command that changes data directly could be damaging if not run correctly, or under the right conditions.
+We highly recommend running them in a test environment with a backup of the instance ready to be restored, just in case.
+
+### Cancel stuck pending pipelines
+
+```ruby
+project = Project.find_by_full_path('<project_path>')
+Ci::Pipeline.where(project_id: project.id).where(status: 'pending').count
+Ci::Pipeline.where(project_id: project.id).where(status: 'pending').each {|p| p.cancel if p.stuck?}
+Ci::Pipeline.where(project_id: project.id).where(status: 'pending').count
+```
+
+### Try merge request integration
+
+```ruby
+project = Project.find_by_full_path('<project_path>')
+mr = project.merge_requests.find_by(iid: <merge_request_iid>)
+mr.project.try(:ci_integration)
+```
+
+### Validate the `.gitlab-ci.yml` file
+
+```ruby
+project = Project.find_by_full_path('<project_path>')
+content = p.repository.gitlab_ci_yml_for(project.repository.root_ref_sha)
+Gitlab::Ci::Lint.new(project: project, current_user: User.first).validate(content)
+```
+
+### Disable AutoDevOps on Existing Projects
+
+```ruby
+Project.all.each do |p|
+ p.auto_devops_attributes={"enabled"=>"0"}
+ p.save
+end
+```
+
+### Obtain runners registration token
+
+```ruby
+Gitlab::CurrentSettings.current_application_settings.runners_registration_token
+```
+
+### Seed runners registration token
+
+```ruby
+appSetting = Gitlab::CurrentSettings.current_application_settings
+appSetting.set_runners_registration_token('<new-runners-registration-token>')
+appSetting.save!
+```
+
+### Run pipeline schedules manually
+
+You can run pipeline schedules manually through the Rails console to reveal any errors that are usually not visible.
+
+```ruby
+# schedule_id can be obtained from Edit Pipeline Schedule page
+schedule = Ci::PipelineSchedule.find_by(id: <schedule_id>)
+
+# Select the user that you want to run the schedule for
+user = User.find_by_username('<username>')
+
+# Run the schedule
+ps = Ci::CreatePipelineService.new(schedule.project, user, ref: schedule.ref).execute!(:schedule, ignore_skip_ci: true, save_on_errors: false, schedule: schedule)
+```
+
## How to get help
If you are unable to resolve pipeline issues, you can get help from:
diff --git a/doc/ci/variables/index.md b/doc/ci/variables/index.md
index 7ad42aaf96b..97707c603bd 100644
--- a/doc/ci/variables/index.md
+++ b/doc/ci/variables/index.md
@@ -106,7 +106,7 @@ job1:
Variables saved in the `.gitlab-ci.yml` file should store only non-sensitive project
configuration, like a `RAILS_ENV` or `DATABASE_URL` variable. These variables are
-visible in the repository. Store sensitive variables containing secrets, keys, and so on
+visible in the repository. Store sensitive variables containing values like secrets or keys
in project settings.
Variables saved in the `.gitlab-ci.yml` file are also available in [service containers](../docker/using_docker_images.md).
@@ -161,7 +161,7 @@ in the project settings, not in the `.gitlab-ci.yml` file.
To add or update variables in the project settings:
1. Go to your project's **Settings > CI/CD** and expand the **Variables** section.
-1. Select the **Add Variable** button and fill in the details:
+1. Select **Add variable** and fill in the details:
- **Key**: Must be one line, with no spaces, using only letters, numbers, or `_`.
- **Value**: No limitations.
@@ -203,7 +203,7 @@ Use group variables to store secrets like passwords, SSH keys, and credentials,
To add a group variable:
1. In the group, go to **Settings > CI/CD**.
-1. Select the **Add Variable** button and fill in the details:
+1. Select **Add variable** and fill in the details:
- **Key**: Must be one line, with no spaces, using only letters, numbers, or `_`.
- **Value**: No limitations.
@@ -241,7 +241,7 @@ To add an instance variable:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > CI/CD** and expand the **Variables** section.
-1. Select the **Add variable** button, and fill in the details:
+1. Select **Add variable** and fill in the details:
- **Key**: Must be one line, with no spaces, using only letters, numbers, or `_`.
- **Value**: In [GitLab 13.3 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/220028),
@@ -255,8 +255,6 @@ To add an instance variable:
### CI/CD variable types
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/46806) in GitLab 11.11.
-
All predefined CI/CD variables and variables defined in the `.gitlab-ci.yml` file
are `Variable` type. Project, group and instance CI/CD variables can be `Variable`
or `File` type.
@@ -333,7 +331,7 @@ job1:
### Mask a CI/CD variable
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/13784) in GitLab 11.10
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/330650) in GitLab 13.12, the `~` character can be used in masked variables.
You can mask a project, group, or instance CI/CD variable so the value of the variable
does not display in job logs.
@@ -352,20 +350,24 @@ The value of the variable must:
- Be a single line.
- Be 8 characters or longer, consisting only of:
- Characters from the Base64 alphabet (RFC4648).
- - The `@` and `:` characters (In [GitLab 12.2 and later](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/63043)).
- - The `.` character (In [GitLab 12.10 and later](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29022)).
- - The `~` character (In [GitLab 13.12 and later](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61517)).
+ - The `@`, `:`, `.`, or `~` characters.
- Not match the name of an existing predefined or custom CI/CD variable.
-NOTE:
-Masking a CI/CD variable is not a guaranteed way to prevent malicious users from accessing
-variable values. To make variables more secure, you can [use external secrets](../secrets/index.md).
-
WARNING:
-Due to a technical limitation, masked variables that are more than 4 KiB in length are not recommended. Printing such
-a large value to the trace log has the potential to be [revealed](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/28128).
-When using GitLab Runner 14.2, only the tail of the variable, characters beyond 4KiB in length, have the potential to
-be revealed.
+Masking a CI/CD variable is not a guaranteed way to prevent malicious users from
+accessing variable values. The masking feature is "best-effort" and there to
+help when a variable is accidentally revealed. To make variables more secure,
+consider using [external secrets](../secrets/index.md) and [file type variables](#cicd-variable-types)
+to prevent commands such as `env`/`printenv` from printing secret variables.
+
+Runner versions implement masking in different ways, some with technical
+limitations. Below is a table of such limitations.
+
+| Version from | Version to | Limitations |
+| ------------ | ---------- | ------ |
+| v11.9.0 | v14.1.0 | Masking of large secrets (greater than 4 KiB) could potentially be [revealed](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/28128). No sensitive URL parameter masking. |
+| v14.2.0 | v15.3.0 | The tail of a large secret (greater than 4 KiB) could potentially be [revealed](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/28128). No sensitive URL parameter masking. |
+| v15.7.0 | | Potential for secrets to be revealed when `CI_DEBUG_SERVICES` is enabled. For details, read about [service container logging](../services/index.md#capturing-service-container-logs). |
### Protected CI/CD variables
@@ -506,7 +508,7 @@ job_name:
# - 'dir env:' # Use this for PowerShell
```
-Example job log output:
+Example job log output (truncated):
```shell
export CI_JOB_ID="50"
@@ -528,31 +530,6 @@ export CI_PROJECT_ID="34"
export CI_PROJECT_DIR="/builds/gitlab-org/gitlab-foss"
export CI_PROJECT_NAME="gitlab-foss"
export CI_PROJECT_TITLE="GitLab FOSS"
-export CI_PROJECT_DESCRIPTION="GitLab FOSS is a read-only mirror of GitLab, with all proprietary code removed."
-export CI_PROJECT_NAMESPACE="gitlab-org"
-export CI_PROJECT_ROOT_NAMESPACE="gitlab-org"
-export CI_PROJECT_PATH="gitlab-org/gitlab-foss"
-export CI_PROJECT_URL="https://example.com/gitlab-org/gitlab-foss"
-export CI_REGISTRY="registry.example.com"
-export CI_REGISTRY_IMAGE="registry.example.com/gitlab-org/gitlab-foss"
-export CI_REGISTRY_USER="gitlab-ci-token"
-export CI_REGISTRY_PASSWORD="[masked]"
-export CI_RUNNER_ID="10"
-export CI_RUNNER_DESCRIPTION="my runner"
-export CI_RUNNER_TAGS="docker, linux"
-export CI_SERVER="yes"
-export CI_SERVER_URL="https://example.com"
-export CI_SERVER_HOST="example.com"
-export CI_SERVER_PORT="443"
-export CI_SERVER_PROTOCOL="https"
-export CI_SERVER_NAME="GitLab"
-export CI_SERVER_REVISION="70606bf"
-export CI_SERVER_VERSION="8.9.0"
-export CI_SERVER_VERSION_MAJOR="8"
-export CI_SERVER_VERSION_MINOR="9"
-export CI_SERVER_VERSION_PATCH="0"
-export GITLAB_USER_EMAIL="user@example.com"
-export GITLAB_USER_ID="42"
...
```
@@ -776,8 +753,6 @@ explains if the integration has any deployment variables available.
## Auto DevOps environment variables
-> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/49056) in GitLab 11.7.
-
You can configure [Auto DevOps](../../topics/autodevops/index.md) to pass CI/CD variables
to a running application.
@@ -817,7 +792,7 @@ job_name:
Example output (truncated):
-```shell
+```plaintext
...
export CI_SERVER_TLS_CA_FILE="/builds/gitlab-examples/ci-debug-trace.tmp/CI_SERVER_TLS_CA_FILE"
if [[ -d "/builds/gitlab-examples/ci-debug-trace/.git" ]]; then
@@ -885,48 +860,6 @@ if [[ -d "/builds/gitlab-examples/ci-debug-trace/.git" ]]; then
++ CI_PROJECT_ID=17893
++ export CI_PROJECT_NAME=ci-debug-trace
++ CI_PROJECT_NAME=ci-debug-trace
-++ export CI_PROJECT_TITLE='GitLab FOSS'
-++ CI_PROJECT_TITLE='GitLab FOSS'
-++ export CI_PROJECT_DESCRIPTION='GitLab FOSS is a read-only mirror of GitLab, with all proprietary code removed.'
-++ CI_PROJECT_DESCRIPTION='GitLab FOSS is a read-only mirror of GitLab, with all proprietary code removed.'
-++ export CI_PROJECT_PATH=gitlab-examples/ci-debug-trace
-++ CI_PROJECT_PATH=gitlab-examples/ci-debug-trace
-++ export CI_PROJECT_PATH_SLUG=gitlab-examples-ci-debug-trace
-++ CI_PROJECT_PATH_SLUG=gitlab-examples-ci-debug-trace
-++ export CI_PROJECT_NAMESPACE=gitlab-examples
-++ CI_PROJECT_NAMESPACE=gitlab-examples
-++ export CI_PROJECT_ROOT_NAMESPACE=gitlab-examples
-++ CI_PROJECT_ROOT_NAMESPACE=gitlab-examples
-++ export CI_PROJECT_URL=https://gitlab.com/gitlab-examples/ci-debug-trace
-++ CI_PROJECT_URL=https://gitlab.com/gitlab-examples/ci-debug-trace
-++ export CI_PROJECT_VISIBILITY=public
-++ CI_PROJECT_VISIBILITY=public
-++ export CI_PROJECT_REPOSITORY_LANGUAGES=
-++ CI_PROJECT_REPOSITORY_LANGUAGES=
-++ export CI_PROJECT_CLASSIFICATION_LABEL=
-++ CI_PROJECT_CLASSIFICATION_LABEL=
-++ export CI_DEFAULT_BRANCH=main
-++ CI_DEFAULT_BRANCH=main
-++ export CI_REGISTRY=registry.gitlab.com
-++ CI_REGISTRY=registry.gitlab.com
-++ export CI_API_V4_URL=https://gitlab.com/api/v4
-++ CI_API_V4_URL=https://gitlab.com/api/v4
-++ export CI_PIPELINE_IID=123
-++ CI_PIPELINE_IID=123
-++ export CI_PIPELINE_SOURCE=web
-++ CI_PIPELINE_SOURCE=web
-++ export CI_CONFIG_PATH=.gitlab-ci.yml
-++ CI_CONFIG_PATH=.gitlab-ci.yml
-++ export CI_COMMIT_SHA=dd648b2e48ce6518303b0bb580b2ee32fadaf045
-++ CI_COMMIT_SHA=dd648b2e48ce6518303b0bb580b2ee32fadaf045
-++ export CI_COMMIT_SHORT_SHA=dd648b2e
-++ CI_COMMIT_SHORT_SHA=dd648b2e
-++ export CI_COMMIT_BEFORE_SHA=0000000000000000000000000000000000000000
-++ CI_COMMIT_BEFORE_SHA=0000000000000000000000000000000000000000
-++ export CI_COMMIT_REF_NAME=main
-++ CI_COMMIT_REF_NAME=main
-++ export CI_COMMIT_REF_SLUG=main
-++ CI_COMMIT_REF_SLUG=main
...
```
diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md
index 606847ee756..852110a1415 100644
--- a/doc/ci/variables/predefined_variables.md
+++ b/doc/ci/variables/predefined_variables.md
@@ -46,6 +46,7 @@ as it can cause the pipeline to behave unexpectedly.
| `CI_CONCURRENT_PROJECT_ID` | all | 11.10 | The unique ID of build execution in a single executor and project. |
| `CI_CONFIG_PATH` | 9.4 | 0.5 | The path to the CI/CD configuration file. Defaults to `.gitlab-ci.yml`. Read-only inside a running pipeline. |
| `CI_DEBUG_TRACE` | all | 1.7 | `true` if [debug logging (tracing)](index.md#debug-logging) is enabled. |
+| `CI_DEBUG_SERVICES` | 15.7 | 15.7 | `true` if [service container logging](../services/index.md#capturing-service-container-logs) is enabled. |
| `CI_DEFAULT_BRANCH` | 12.4 | all | The name of the project's default branch. |
| `CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX` | 13.7 | all | The top-level group image prefix for pulling images through the Dependency Proxy. |
| `CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX` | 14.3 | all | The direct group image prefix for pulling images through the Dependency Proxy. |
@@ -89,7 +90,6 @@ as it can cause the pipeline to behave unexpectedly.
| `CI_PIPELINE_TRIGGERED` | all | all | `true` if the job was [triggered](../triggers/index.md). |
| `CI_PIPELINE_URL` | 11.1 | 0.5 | The URL for the pipeline details. |
| `CI_PIPELINE_CREATED_AT` | 13.10 | all | The UTC datetime when the pipeline was created, in [ISO 8601](https://www.rfc-editor.org/rfc/rfc3339#appendix-A) format. |
-| `CI_PROJECT_CONFIG_PATH` | 13.8 to 13.12 | all | [Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/322807) in GitLab 14.0. Use `CI_CONFIG_PATH`. |
| `CI_PROJECT_DIR` | all | all | The full path the repository is cloned to, and where the job runs from. If the GitLab Runner `builds_dir` parameter is set, this variable is set relative to the value of `builds_dir`. For more information, see the [Advanced GitLab Runner configuration](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section). |
| `CI_PROJECT_ID` | all | all | The ID of the current project. This ID is unique across all projects on the GitLab instance. |
| `CI_PROJECT_NAME` | 8.10 | 0.5 | The name of the directory for the project. For example if the project URL is `gitlab.example.com/group-name/project-1`, `CI_PROJECT_NAME` is `project-1`. |
diff --git a/doc/ci/variables/where_variables_can_be_used.md b/doc/ci/variables/where_variables_can_be_used.md
index 7e5451658f2..c8436fc044d 100644
--- a/doc/ci/variables/where_variables_can_be_used.md
+++ b/doc/ci/variables/where_variables_can_be_used.md
@@ -36,13 +36,15 @@ There are two places defined variables can be used. On the:
| [`include`](../yaml/index.md#include) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. <br/><br/>See [Use variables with include](../yaml/includes.md#use-variables-with-include) for more information on supported variables. |
| [`only:variables`](../yaml/index.md#onlyvariables--exceptvariables) | no | Not applicable | The variable must be in the form of `$variable`. Not supported are the following:<br/><br/>- Variables that are based on the environment's name (`CI_ENVIRONMENT_NAME`, `CI_ENVIRONMENT_SLUG`).<br/>- Any other variables related to environment (currently only `CI_ENVIRONMENT_URL`).<br/>- [Persisted variables](#persisted-variables). |
| [`resource_group`](../yaml/index.md#resource_group) | yes | GitLab | Similar to `environment:url`, but the variables expansion doesn't support the following:<br/>- `CI_ENVIRONMENT_URL`<br/>- [Persisted variables](#persisted-variables). |
+| [`rules:exists`](../yaml/index.md#rulesexists) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. |
| [`rules:if`](../yaml/index.md#rulesif) | no | Not applicable | The variable must be in the form of `$variable`. Not supported are the following:<br/><br/>- Variables that are based on the environment's name (`CI_ENVIRONMENT_NAME`, `CI_ENVIRONMENT_SLUG`).<br/>- Any other variables related to environment (currently only `CI_ENVIRONMENT_URL`).<br/>- [Persisted variables](#persisted-variables). |
| [`script`](../yaml/index.md#script) | yes | Script execution shell | The variable expansion is made by the [execution shell environment](#execution-shell-environment). |
| [`services:name`](../yaml/index.md#services) | yes | Runner | The variable expansion is made by GitLab Runner's [internal variable expansion mechanism](#gitlab-runner-internal-variable-expansion-mechanism). |
| [`services`](../yaml/index.md#services) | yes | Runner | The variable expansion is made by GitLab Runner's [internal variable expansion mechanism](#gitlab-runner-internal-variable-expansion-mechanism). |
| [`tags`](../yaml/index.md#tags) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/35742) in GitLab 14.1. |
-| [`trigger` and `trigger:project`](../yaml/index.md#trigger) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/367660) in GitLab 15.3. |
+| [`trigger` and `trigger:project`](../yaml/index.md#trigger) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab. Variable expansion for `trigger:project` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/367660) in GitLab 15.3. |
| [`variables`](../yaml/index.md#variables) | yes | GitLab/Runner | The variable expansion is first made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab, and then any unrecognized or unavailable variables are expanded by GitLab Runner's [internal variable expansion mechanism](#gitlab-runner-internal-variable-expansion-mechanism). |
+| [`workflow:name`](../yaml/index.md#workflowname) | yes | GitLab | The variable expansion is made by the [internal variable expansion mechanism](#gitlab-internal-variable-expansion-mechanism) in GitLab.<br/><br/>Supported are all variables available in `workflow`:<br/>- Project/Group variables.<br/>- Global `variables` and `workflow:rules:variables` (when matching the rule).<br/>- Variables inherited from parent pipelines.<br/>- Variables from triggers.<br/>- Variables from pipeline schedules.<br/><br/>Not supported are variables defined in the GitLab Runner `config.toml`, variables defined in jobs, or [Persisted variables](#persisted-variables). |
### `config.toml` file
diff --git a/doc/ci/yaml/artifacts_reports.md b/doc/ci/yaml/artifacts_reports.md
index 67cbe989f74..9f5e4e919b0 100644
--- a/doc/ci/yaml/artifacts_reports.md
+++ b/doc/ci/yaml/artifacts_reports.md
@@ -178,7 +178,7 @@ report uploads to GitLab as an artifact.
GitLab can display the results of one or more reports in:
-- The merge request [security widget](../../user/application_security/dast/index.md#view-details-of-a-vulnerability-detected-by-dast).
+- The merge request security widget.
- The pipeline [**Security** tab](../../user/application_security/vulnerability_report/pipeline.md#view-vulnerabilities-in-a-pipeline).
- The [Project Vulnerability report](../../user/application_security/vulnerability_report/index.md).
- The [security dashboard](../../user/application_security/security_dashboard/index.md).
diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md
index e06abe1dc69..3392304775a 100644
--- a/doc/ci/yaml/index.md
+++ b/doc/ci/yaml/index.md
@@ -146,7 +146,7 @@ the time limit to resolve all files is 30 seconds.
**Possible inputs**: The `include` subkeys:
- [`include:local`](#includelocal)
-- [`include:file`](#includefile)
+- [`include:project`](#includeproject)
- [`include:remote`](#includeremote)
- [`include:template`](#includetemplate)
@@ -203,58 +203,52 @@ include: '.gitlab-ci-production.yml'
- 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.
-#### `include:file`
+#### `include:project`
> Including multiple files from the same project [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/26793) in GitLab 13.6. [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/271560) in GitLab 13.8.
To include files from another private project on the same GitLab instance,
-use `include:file`. You can use `include:file` in combination with `include:project` only.
+use `include:project` and `include:file`.
**Keyword type**: Global keyword.
**Possible inputs**:
-A full path, relative to the root directory (`/`):
+- `include:project`: The full GitLab project path.
+- `include:file` A full file path, or array of file paths, relative to the root directory (`/`).
+ 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.
-- The YAML file must have the extension `.yml` or `.yaml`.
-- 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:file`**:
+**Example of `include:project`**:
```yaml
include:
- project: 'my-group/my-project'
file: '/templates/.gitlab-ci-template.yml'
+ - project: 'my-group/my-subgroup/my-project-2'
+ file:
+ - '/templates/.builds.yml'
+ - '/templates/.tests.yml'
```
-You can also specify a `ref`. If you do not specify a value, the ref defaults to the `HEAD` of the project:
+You can also specify a `ref`:
```yaml
include:
- project: 'my-group/my-project'
- ref: main
+ ref: main # Git branch
file: '/templates/.gitlab-ci-template.yml'
-
- project: 'my-group/my-project'
- ref: v1.0.0 # Git Tag
+ ref: v1.0.0 # Git Tag
file: '/templates/.gitlab-ci-template.yml'
-
- project: 'my-group/my-project'
ref: 787123b47f14b552955ca2786bc9542ae66fee5b # Git SHA
file: '/templates/.gitlab-ci-template.yml'
```
-You can include multiple files from the same project:
-
-```yaml
-include:
- - project: 'my-group/my-project'
- ref: main
- file:
- - '/templates/.builds.yml'
- - '/templates/.tests.yml'
-```
-
**Additional details**:
- All [nested includes](includes.md#use-nested-includes) are executed in the scope of the target project.
@@ -379,7 +373,7 @@ start. Jobs in the current stage are not stopped and continue to run.
- If a job does not specify a [`stage`](#stage), the job is assigned the `test` stage.
- If a stage is defined but no jobs use it, the stage is not visible in the pipeline,
- which can help [compliance pipeline configurations](../../user/group/manage.md#configure-a-compliance-pipeline):
+ which can help [compliance pipeline configurations](../../user/group/compliance_frameworks.md#configure-a-compliance-pipeline):
- Stages can be defined in the compliance configuration but remain hidden if not used.
- The defined stages become visible when developers use them in job definitions.
@@ -414,12 +408,33 @@ All pipelines are assigned the defined name. Any leading or trailing spaces in t
**Possible inputs**:
- A string.
+- [CI/CD variables](../variables/where_variables_can_be_used.md#gitlab-ciyml-file).
+- A combination of both.
-**Example of `workflow:name`**:
+**Examples of `workflow:name`**:
+
+A simple pipeline name with a predefined variable:
```yaml
workflow:
- name: 'Pipeline name'
+ name: 'Pipeline for branch: $CI_COMMIT_BRANCH'
+```
+
+A configuration with different pipeline names depending on the pipeline conditions:
+
+```yaml
+variables:
+ PIPELINE_NAME: 'Default pipeline name'
+
+workflow:
+ name: '$PIPELINE_NAME'
+ rules:
+ - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
+ variables:
+ PIPELINE_NAME: 'MR pipeline: $CI_COMMIT_BRANCH'
+ - if: '$CI_MERGE_REQUEST_LABELS =~ /pipeline:run-in-ruby3/'
+ variables:
+ PIPELINE_NAME: 'Ruby 3 pipeline'
```
#### `workflow:rules`
@@ -982,7 +997,7 @@ rspec:
- Combining reports in parent pipelines using [artifacts from child pipelines](#needspipelinejob) is
not supported. Track progress on adding support in [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/215725).
-- To be able to browse the report output files, include the [`artifacts:paths`](#artifactspaths) keyword. Please note that this will upload and store the artifact twice.
+- To be able to browse the report output files, include the [`artifacts:paths`](#artifactspaths) keyword. This will upload and store the artifact twice.
- The test reports are collected regardless of the job results (success or failure).
You can use [`artifacts:expire_in`](#artifactsexpire_in) to set up an expiration
date for artifacts reports.
@@ -1134,7 +1149,7 @@ that use the same cache key use the same cache, including in different pipelines
If not set, the default key is `default`. All jobs with the `cache` keyword but
no `cache:key` share the `default` cache.
-Must be used with `cache: path`, or nothing is cached.
+Must be used with `cache: paths`, or nothing is cached.
**Keyword type**: Job keyword. You can use it only as part of a job or in the
[`default` section](#default).
@@ -1304,7 +1319,7 @@ rspec:
Use `cache:when` to define when to save the cache, based on the status of the job.
-Must be used with `cache: path`, or nothing is cached.
+Must be used with `cache: paths`, or nothing is cached.
**Keyword type**: Job keyword. You can use it only as part of a job or in the
[`default` section](#default).
@@ -1344,7 +1359,7 @@ Use the `pull` policy when you have many jobs executing in parallel that use the
This policy speeds up job execution and reduces load on the cache server. You can
use a job with the `push` policy to build the cache.
-Must be used with `cache: path`, or nothing is cached.
+Must be used with `cache: paths`, or nothing is cached.
**Keyword type**: Job keyword. You can use it only as part of a job or in the
[`default` section](#default).
@@ -1464,8 +1479,8 @@ to select a specific site profile and scanner profile.
**Related topics**:
-- [Site profile](../../user/application_security/dast/index.md#site-profile).
-- [Scanner profile](../../user/application_security/dast/index.md#scanner-profile).
+- [Site profile](../../user/application_security/dast/proxy-based.md#site-profile).
+- [Scanner profile](../../user/application_security/dast/proxy-based.md#scanner-profile).
### `dependencies`
@@ -1749,6 +1764,11 @@ deploy:
deployment_tier: production
```
+**Additional details**:
+
+- Enviroments created from this job definition are assigned a [tier](../environments/index.md#deployment-tier-of-environments) based on this value.
+- Existing environments don't have their tier updated if this value is added later. Existing enviroments must have their tier updated via the [Environments API](../../api/environments.md#update-an-existing-environment).
+
**Related topics**:
- [Deployment tier of environments](../environments/index.md#deployment-tier-of-environments).
@@ -2809,6 +2829,13 @@ deploystacks: [vultr, data]
deploystacks: [vultr, processing]
```
+**Additional details**:
+
+- `parallel:matrix` jobs add the variable values to the job names to differentiate
+ the jobs from each other, but [large values can cause names to exceed limits](https://gitlab.com/gitlab-org/gitlab/-/issues/362262):
+ - Job names must be [255 characters or fewer](../jobs/index.md#job-name-limitations).
+ - When using [`needs`](#needs), job names must be 128 characters or fewer.
+
**Related topics**:
- [Run a one-dimensional matrix of parallel jobs](../jobs/job_control.md#run-a-one-dimensional-matrix-of-parallel-jobs).
@@ -3229,7 +3256,8 @@ Use `rules:if` clauses to specify when to add a job to a pipeline:
- If no `if` statements are true, do not add the job to the pipeline.
`if` clauses are evaluated based on the values of [predefined CI/CD variables](../variables/predefined_variables.md)
-or [custom CI/CD variables](../variables/index.md#custom-cicd-variables).
+or [custom CI/CD variables](../variables/index.md#custom-cicd-variables), with
+[some exceptions](../variables/where_variables_can_be_used.md#gitlab-ciyml-file).
**Keyword type**: Job-specific and pipeline-specific. You can use it as part of a job
to configure the job behavior, or with [`workflow`](#workflow) to configure the pipeline behavior.
@@ -3403,7 +3431,8 @@ relative to `refs/heads/branch1` and the pipeline source is a merge request even
#### `rules:exists`
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24021) in GitLab 12.4.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24021) in GitLab 12.4.
+> - CI/CD variable support [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/283881) in GitLab 15.6.
Use `exists` to run a job when certain files exist in the repository.
@@ -3411,8 +3440,7 @@ Use `exists` to run a job when certain files exist in the repository.
**Possible inputs**:
-- An array of file paths. Paths are relative to the project directory (`$CI_PROJECT_DIR`)
- and can't directly link outside it. File paths can use glob patterns.
+- An array of file paths. Paths are relative to the project directory (`$CI_PROJECT_DIR`) and can't directly link outside it. File paths can use glob patterns and [CI/CD variables](../variables/where_variables_can_be_used.md#gitlab-ciyml-file).
**Example of `rules:exists`**:
@@ -3573,7 +3601,7 @@ Use `secrets:vault` to specify secrets provided by a [HashiCorp Vault](https://w
**Example of `secrets:vault`**:
-To specify all details explicitly and use the [KV-V2](https://www.vaultproject.io/docs/secrets/kv/kv-v2) secrets engine:
+To specify all details explicitly and use the [KV-V2](https://developer.hashicorp.com/vault/docs/secrets/kv/kv-v2) secrets engine:
```yaml
job:
@@ -3938,14 +3966,15 @@ Use `trigger` to declare that a job is a "trigger job" which starts a
Trigger jobs can use only a limited set of GitLab CI/CD configuration keywords.
The keywords available for use in trigger jobs are:
-- [`trigger`](#trigger).
-- [`stage`](#stage).
- [`allow_failure`](#allow_failure).
-- [`rules`](#rules).
-- [`only` and `except`](#only--except).
-- [`when`](#when) (only with a value of `on_success`, `on_failure`, or `always`).
- [`extends`](#extends).
- [`needs`](#needs), but not [`needs:project`](#needsproject).
+- [`only` and `except`](#only--except).
+- [`rules`](#rules).
+- [`stage`](#stage).
+- [`trigger`](#trigger).
+- [`variables`](#variables).
+- [`when`](#when) (only with a value of `on_success`, `on_failure`, or `always`).
**Keyword type**: Job keyword. You can use it only as part of a job.
@@ -3969,6 +3998,8 @@ trigger-multi-project-pipeline:
- In [GitLab 13.5 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/201938), you
can use [`when:manual`](#when) in the same job as `trigger`. In GitLab 13.4 and
earlier, using them together causes the error `jobs:#{job-name} when should be on_success, on_failure or always`.
+- You cannot [manually specify CI/CD variables](../jobs/index.md#specifying-variables-when-running-manual-jobs)
+ before running a manual trigger job.
- [Manual pipeline variables](../variables/index.md#override-a-defined-cicd-variable)
and [scheduled pipeline variables](../pipelines/schedules.md#add-a-pipeline-schedule)
are not passed to downstream pipelines by default. Use [trigger:forward](#triggerforward)
@@ -4079,6 +4110,8 @@ successfully complete before starting.
shows **pending** (**{status_pending}**) if the downstream pipeline status is
**waiting for manual action** (**{status_manual}**) due to manual jobs. By default,
jobs in later stages do not start until the trigger job completes.
+- If the downstream pipeline has a failed job, but the job uses [`allow_failure: true`](#allow_failure),
+ the downstream pipeline is considered successful and the trigger job shows **success**.
#### `trigger:forward`
@@ -4222,6 +4255,38 @@ variables:
- A global variable defined with `value` but no `description` behaves the same as
[`variables`](#variables).
+#### `variables:expand`
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/353991) in GitLab 15.6 [with a flag](../../administration/feature_flags.md) named `ci_raw_variables_in_yaml_config`. Disabled by default.
+
+Use the `expand` keyword to configure a variable to be expandable or not.
+
+**Keyword type**: Global and job keyword. You can use it at the global level, and also at the job level.
+
+**Possible inputs**:
+
+- `true` (default): The variable is expandable.
+- `false`: The variable is not expandable.
+
+**Example of `variables:expand`**:
+
+```yaml
+variables:
+ VAR1: value1
+ VAR2: value2 $VAR1
+ VAR3:
+ value: value3 $VAR1
+ expand: false
+```
+
+- The result of `VAR2` is `value2 value1`.
+- The result of `VAR3` is `value3 $VAR1`.
+
+**Additional details**:
+
+- The `expand` keyword can only be used with the global and job-level `variables` keywords.
+ You can't use it with [`rules:variables`](#rulesvariables) or [`workflow:rules:variables`](#workflowrulesvariables).
+
### `when`
Use `when` to configure the conditions for when jobs run. If not defined in a job,
diff --git a/doc/cloud_seed/index.md b/doc/cloud_seed/index.md
index bf51da88cb4..04b560f7f87 100644
--- a/doc/cloud_seed/index.md
+++ b/doc/cloud_seed/index.md
@@ -13,6 +13,9 @@ Cloud Seed is an open-source program led
by [GitLab Incubation Engineering](https://about.gitlab.com/handbook/engineering/incubation/) in collaboration with
[Google Cloud](https://cloud.google.com/).
+Cloud Seed combines Heroku-like ease-of-use with hyper-cloud flexibility. We do this by using OAuth 2 to provision
+services on a hyper-cloud based on a foundation of Terraform and infrastructure-as-code to enable day 2 operations.
+
## Purpose
We believe that it should be **trivial** to deploy web applications (and other workloads) from GitLab to major cloud
diff --git a/doc/development/api_graphql_styleguide.md b/doc/development/api_graphql_styleguide.md
index d3053a1ca5f..c19341a1404 100644
--- a/doc/development/api_graphql_styleguide.md
+++ b/doc/development/api_graphql_styleguide.md
@@ -1294,15 +1294,25 @@ class MyThingResolver < BaseResolver
end
```
-The final thing that is needed is that every field that uses this resolver needs
-to advertise the need for lookahead:
+The `LooksAhead` concern also provides basic support for preloading associations based on nested GraphQL field
+definitions. The [WorkItemsResolver](https://gitlab.com/gitlab-org/gitlab/-/blob/e824a7e39e08a83fb162db6851de147cf0bfe14a/app/graphql/resolvers/work_items_resolver.rb#L46)
+is a good example for this. `nested_preloads` is another method you can define to return a hash, but unlike the
+`preloads` method, the value for each hash key is another hash and not the list of associations to preload. So in
+the previous example, you could override `nested_preloads` like this:
```ruby
- # in ParentType
- field :my_things, MyThingType.connection_type, null: true,
- extras: [:lookahead], # Necessary
- resolver: MyThingResolver,
- description: 'My things.'
+class MyThingResolver < BaseResolver
+ # ...
+
+ def nested_preloads
+ {
+ root_field: {
+ nested_field1: :association_to_preload,
+ nested_field2: [:association1, :association2]
+ }
+ }
+ end
+end
```
For an example of real world use, please
@@ -1733,15 +1743,18 @@ there are no problems we need to inform the user of.
#### Failure (relevant to the user)
-An error that affects the **user** occurred. We refer to these as _mutation errors_. In
-this case there is typically no `thing` to return:
+An error that affects the **user** occurred. We refer to these as _mutation errors_.
+
+In a _create_ mutation there is typically no `thing` to return.
+
+In an _update_ mutation we return the current true state of `thing`. Developers may need to call `#reset` on the `thing` instance to ensure this happens.
```javascript
{
data: {
doTheThing: {
errors: ["you cannot touch the thing"],
- thing: null
+ thing: { .. }
}
}
}
@@ -2165,32 +2178,44 @@ end
```ruby
NameError: uninitialized constant Resolvers::GroupIssuesResolver
+
+ or
+
+ GraphQL::Pagination::Connections::ImplementationMissingError
```
+ though you might see something different.
+
To fix this, we must create a new file that encapsulates the connection type,
and then reference it using double quotes. This gives a delayed resolution,
and the proper connection type. For example:
+ [app/graphql/resolvers/base_issues_resolver.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/resolvers/base_issues_resolver.rb)
+ originally contained the line
+
```ruby
- module Types
- # rubocop: disable Graphql/AuthorizeTypes
- class IssueConnectionType < CountableConnectionType
- end
- end
+ type Types::IssueType.connection_type, null: true
+ ```
+
+ Running the specs locally for this file caused the
+ `NameError: uninitialized constant Resolvers::GroupIssuesResolver` error.
+
+ The fix was to create a new file, [app/graphql/types/issue_connection.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/types/issue_connection.rb) with the
+ line:
- Types::IssueConnectionType.prepend_mod_with('Types::IssueConnectionType')
+ ```ruby
+ Types::IssueConnection = Types::IssueType.connection_type
```
- in [types/issue_connection_type.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/types/issue_connection_type.rb)
- defines a new `Types::IssueConnectionType`, and is then referenced in
- [app/graphql/resolvers/base_issues_resolver.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/resolvers/base_issues_resolver.rb)
+ and in [app/graphql/resolvers/base_issues_resolver.rb](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/resolvers/base_issues_resolver.rb)
+ we use the line
```ruby
type "Types::IssueConnection", null: true
```
Only use this style if you are having spec failures. This is not intended to be a new
- pattern that we use. This issue may disappear after we've upgraded to `2.x`.
+ pattern that we use. This issue should disappear after we've upgraded to `2.x`.
- There can be instances where a spec fails because the class is not loaded correctly.
It relates to the
diff --git a/doc/development/application_limits.md b/doc/development/application_limits.md
index edf159a116a..b64d25ccf64 100644
--- a/doc/development/application_limits.md
+++ b/doc/development/application_limits.md
@@ -38,7 +38,7 @@ It's recommended to create two separate migration script files.
desired limit using `create_or_update_plan_limit` migration helper, such as:
```ruby
- class InsertProjectHooksPlanLimits < Gitlab::Database::Migration[1.0]
+ class InsertProjectHooksPlanLimits < Gitlab::Database::Migration[2.0]
def up
create_or_update_plan_limit('project_hooks', 'default', 0)
create_or_update_plan_limit('project_hooks', 'free', 10)
diff --git a/doc/development/audit_event_guide/index.md b/doc/development/audit_event_guide/index.md
index 5c8938aa46a..dfa6d56b3b5 100644
--- a/doc/development/audit_event_guide/index.md
+++ b/doc/development/audit_event_guide/index.md
@@ -21,9 +21,9 @@ While any events could trigger an Audit Event, not all events should. In general
- Not attributable to one specific user.
- Not of specific interest to an administrator or owner persona.
- Are tracking information for product feature adoption.
-- Are covered in the direction page's discussion on [what is not planned](https://about.gitlab.com/direction/manage/compliance/audit-events/#what-is-not-planned-right-now).
+- Are covered in the direction page's discussion on [what is not planned](https://about.gitlab.com/direction/govern/compliance/audit-events/#what-is-not-planned-right-now).
-If you have any questions, please reach out to `@gitlab-org/manage/compliance` to see if an Audit Event, or some other approach, may be best for your event.
+If you have any questions, please reach out to `@gitlab-org/govern/compliance` to see if an Audit Event, or some other approach, may be best for your event.
## Audit Event Schemas
@@ -120,7 +120,7 @@ end
Because every audit event is persisted to the database, consider the amount of data we expect to generate, and the rate of generation, for new
audit events. For new audit events that will produce a lot of data in the database, consider adding a
[streaming-only audit event](#event-streaming) instead. If you have questions about this, feel free to ping
-`@gitlab-org/manage/compliance/backend` in an issue or merge request.
+`@gitlab-org/govern/compliance/backend` in an issue or merge request.
## Audit Event instrumentation flows
@@ -205,8 +205,10 @@ All new audit events must have a type definition stored in `config/audit_events/
To add a new audit event type:
-1. Create a new file in `config/audit_events/types/` with the filename matching the name of the event type. For example, a definition for the event type triggered when a
- user is added to a project might be stored in `config/audit_events/types/project_add_user.yml`.
+1. Create the YAML definition. You can either:
+ - Use the `bin/audit-event-type` CLI to create the YAML definition automatically.
+ - Perform manual steps to create a new file in `config/audit_events/types/` with the filename matching the name of the event type. For example,
+ a definition for the event type triggered when a user is added to a project might be stored in `config/audit_events/types/project_add_user.yml`.
1. Add contents to the file that conform to the [schema](#schema) defined in `config/audit_events/types/type_schema.json`.
1. Ensure that all calls to `Gitlab::Audit::Auditor` use the `name` defined in your file.
diff --git a/doc/development/backend/ruby_style_guide.md b/doc/development/backend/ruby_style_guide.md
index 9b5a68e4292..1a1c0db49f7 100644
--- a/doc/development/backend/ruby_style_guide.md
+++ b/doc/development/backend/ruby_style_guide.md
@@ -7,31 +7,32 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Ruby style guide
-This is a GitLab-specific style guide for Ruby code.
+This is a GitLab-specific style guide for Ruby code. Everything documented in this page can be [reopened for discussion](https://about.gitlab.com/handbook/values/#disagree-commit-and-disagree).
-Generally, if a style is not covered by [existing RuboCop rules or style guides](../contributing/style_guides.md#ruby-rails-rspec), it shouldn't be a blocker.
-Before adding a new cop to enforce a given style, make sure to discuss it with your team.
-When the style is approved by a backend EM or by a BE staff eng, add a new section to this page to
-document the new rule. For every new guideline, add it in a new section and link the discussion from the section's
-[version history note](../documentation/versions.md#add-a-version-history-item)
-to provide context and serve as a reference.
+We use [RuboCop](../rubocop_development_guide.md) to enforce Ruby style guide rules.
-See also [guidelines for reusing abstractions](../reusing_abstractions.md).
+Where a RuboCop rule is absent, refer to the following style guides as general guidelines to write idiomatic Ruby:
-Everything listed here can be [reopened for discussion](https://about.gitlab.com/handbook/values/#disagree-commit-and-disagree).
+- [Ruby Style Guide](https://github.com/rubocop/ruby-style-guide).
+- [Rails Style Guide](https://github.com/rubocop/rails-style-guide).
+- [RSpec Style Guide](https://github.com/rubocop/rspec-style-guide).
-## String literals quoting
+Generally, if a style is not covered by existing RuboCop rules or the above style guides, it shouldn't be a blocker.
-Due to the sheer amount of work to rectify, we do not care whether string
-literals are single, or double quoted.
+Some styles we have decided [no one should not have a strong opinion on](#styles-we-have-no-opinion-on).
-Previous discussions include:
+See also:
-- <https://gitlab.com/gitlab-org/gitlab-foss/-/issues/44234>
-- <https://gitlab.com/gitlab-org/gitlab-foss/-/issues/36076>
-- <https://gitlab.com/gitlab-org/gitlab/-/issues/198046>
+- [Guidelines for reusing abstractions](../reusing_abstractions.md).
+- [Test-specific style guides and best practices](../testing_guide/index.md).
+
+## Styles we have no rule for
-## Instance variable access using `attr_reader`
+These styles are not backed by a RuboCop rule.
+
+For every style added to this section, link the discussion from the section's [version history note](../documentation/versions.md#add-a-version-history-item) to provide context and serve as a reference.
+
+### Instance variable access using `attr_reader`
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52351) in GitLab 14.1.
@@ -84,11 +85,11 @@ Public attributes should only be used if they are accessed outside of the class.
There is not a strong opinion on what strategy is used when attributes are only
accessed internally, as long as there is consistency in related code.
-## Newlines style guide
+### Newlines style guide
-This style guide recommends best practices for newlines in Ruby code.
+In addition to the RuboCops `Layout/EmptyLinesAroundMethodBody` and `Cop/LineBreakAroundConditionalBlock` that enforce some newline styles, we have the following guidelines that are not backed by RuboCop.
-### Rule: separate code with newlines only to group together related logic
+#### Rule: separate code with newlines only to group together related logic
```ruby
# bad
@@ -111,9 +112,7 @@ def method
end
```
-### Rule: separate code and block with newlines
-
-#### Newline before block
+#### Rule: newline before block
```ruby
# bad
@@ -136,35 +135,11 @@ def method
end
```
-### Rule: Newline after block
-
-```ruby
-# bad
-def method
- if issue.save
- issue.send_email
- end
- render json: issue
-end
-```
-
-```ruby
-# good
-def method
- if issue.save
- issue.send_email
- end
-
- render json: issue
-end
-```
-
-#### Exception: no need for newline when code block starts or ends right inside another code block
+##### Exception: no need for a newline when code block starts or ends right inside another code block
```ruby
# bad
def method
-
if issue
if issue.valid?
@@ -172,7 +147,6 @@ def method
end
end
-
end
```
@@ -186,3 +160,18 @@ def method
end
end
```
+
+## Styles we have no opinion on
+
+If a RuboCop rule is proposed and we choose not to add it, we should document that decision in this guide so it is more discoverable and link the relevant discussion as a reference.
+
+### Quoting string literals
+
+Due to the sheer amount of work to rectify, we do not care whether string
+literals are single or double-quoted.
+
+Previous discussions include:
+
+- <https://gitlab.com/gitlab-org/gitlab-foss/-/issues/44234>
+- <https://gitlab.com/gitlab-org/gitlab-foss/-/issues/36076>
+- <https://gitlab.com/gitlab-org/gitlab/-/issues/198046>
diff --git a/doc/development/cached_queries.md b/doc/development/cached_queries.md
index fbb857106be..e4625a50d79 100644
--- a/doc/development/cached_queries.md
+++ b/doc/development/cached_queries.md
@@ -87,7 +87,7 @@ and the number of executed cached queries:
![Performance Bar Database Queries](img/performance_bar_members_page.png)
-The page included 55 cached queries. Clicking the number displays a modal window
+The page included 55 cached queries. Selecting the number displays a modal window
with more details about queries. Cached queries are marked with the `cached` label
below the query. You can see multiple duplicate cached queries in this modal window:
diff --git a/doc/development/cascading_settings.md b/doc/development/cascading_settings.md
index 22f146c3f5a..1a0f0ec5b5f 100644
--- a/doc/development/cascading_settings.md
+++ b/doc/development/cascading_settings.md
@@ -38,7 +38,7 @@ Settings are not cascading by default. To define a cascading setting, take the f
`application_settings`.
```ruby
- class AddDelayedProjectRemovalCascadingSetting < Gitlab::Database::Migration[1.0]
+ class AddDelayedProjectRemovalCascadingSetting < Gitlab::Database::Migration[2.0]
include Gitlab::Database::MigrationHelpers::CascadingNamespaceSettings
enable_lock_retries!
diff --git a/doc/development/changelog.md b/doc/development/changelog.md
index 7dc3ae0a80b..27bcffe7560 100644
--- a/doc/development/changelog.md
+++ b/doc/development/changelog.md
@@ -41,6 +41,10 @@ vendor field to be `gitlab` to avoid cve matching old versions.
Changelog: changed
```
+If your merge request has multiple commits,
+[make sure to add the `Changelog` entry to the first commit](changelog.md#how-to-generate-a-changelog-entry).
+This ensures that the correct entry is generated when commits are squashed.
+
### Overriding the associated merge request
GitLab automatically links the merge request to the commit when generating the
diff --git a/doc/development/chatops_on_gitlabcom.md b/doc/development/chatops_on_gitlabcom.md
index 16dc17dd229..c9cb2591e4e 100644
--- a/doc/development/chatops_on_gitlabcom.md
+++ b/doc/development/chatops_on_gitlabcom.md
@@ -23,7 +23,7 @@ To request access to ChatOps on GitLab.com:
with one of the following methods (Okta is not supported):
- The same username you use on GitLab.com. You may have to choose a different username later.
- - Clicking the **Sign in with Google** button to sign in with your GitLab.com email address.
+ - Selecting the **Sign in with Google** button to sign in with your GitLab.com email address.
1. Confirm that your username in [Internal GitLab for Operations](https://ops.gitlab.net/)
is the same as your username in [GitLab.com](https://gitlab.com/). If the usernames
@@ -31,7 +31,7 @@ To request access to ChatOps on GitLab.com:
1. Comment in your onboarding issue, and tag your onboarding buddy and your manager.
Request they add you to the `ops` ChatOps project by running this command
- in the `#chat-ops-test` Slack channel, replacing `<username>` with your username:
+ in the `#chat-ops-test` Slack channel, replacing `<username>` with your GitLab.com username:
`/chatops run member add <username> gitlab-com/chatops --ops`
```plaintext
diff --git a/doc/development/cicd/index.md b/doc/development/cicd/index.md
index cd31038ddd1..73ece709b8d 100644
--- a/doc/development/cicd/index.md
+++ b/doc/development/cicd/index.md
@@ -33,7 +33,7 @@ On the left side we have the events that can trigger a pipeline based on various
- A `git push` is the most common event that triggers a pipeline.
- The [Web API](../../api/pipelines.md#create-a-new-pipeline).
-- A user clicking the "Run pipeline" button in the UI.
+- A user selecting the "Run pipeline" button in the UI.
- When a [merge request is created or updated](../../ci/pipelines/merge_request_pipelines.md).
- When an MR is added to a [Merge Train](../../ci/pipelines/merge_trains.md#merge-trains).
- A [scheduled pipeline](../../ci/pipelines/schedules.md).
diff --git a/doc/development/cicd/templates.md b/doc/development/cicd/templates.md
index 85ac58e749d..6bc6c57e809 100644
--- a/doc/development/cicd/templates.md
+++ b/doc/development/cicd/templates.md
@@ -418,7 +418,7 @@ is updated in a major version GitLab release.
Every CI/CD template must also have metrics defined to track their use. The CI/CD template monthly usage report
can be found in [Sisense (GitLab team members only)](https://app.periscopedata.com/app/gitlab/785953/Pipeline-Authoring-Dashboard?widget=13440051&udv=0).
-Double click a template to see the graph for that single template.
+Select a template to see the graph for that single template.
To add a metric definition for a new template:
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index 5b745f06d22..90f33319365 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -28,6 +28,13 @@ The reviewer can:
- Give you a second opinion on the chosen solution and implementation.
- Help look for bugs, logic problems, or uncovered edge cases.
+If the merge request is trivial (for example, fixing a typo or a tiny refactor that doesn't change the behavior or any data),
+you can skip the reviewer step and directly ask a [maintainer](https://about.gitlab.com/handbook/engineering/workflow/code-review/#maintainer).
+Otherwise, a merge request should always be first reviewed by a reviewer in each
+[category (e.g. backend, database)](#approval-guidelines)
+the MR touches, as maintainers may not have the relevant domain knowledge, and
+also to spread the workload.
+
For assistance with security scans or comments, include the Application Security Team (`@gitlab-com/gl-security/appsec`).
The reviewers use the [reviewer functionality](../user/project/merge_requests/getting_started.md#reviewer) in the sidebar.
@@ -56,8 +63,8 @@ We make the following assumption with regards to automatically being considered
- Team members working in a specific stage/group (for example, create: source code) are considered domain experts for that area of the app they work on.
- Team members working on a specific feature (for example, search) are considered domain experts for that feature.
-We default to assigning reviews to team members with domain expertise.
-When a suitable [domain expert](#domain-experts) isn't available, you can choose any team member to review the MR, or follow the [Reviewer roulette](#reviewer-roulette) recommendation.
+We default to assigning reviews to team members with domain expertise for code reviews. For UX reviews we default to the recommended designer from the Reviewer roulette.
+When a suitable [domain expert](#domain-experts) isn't available, you can choose any team member to review the MR, or follow the [Reviewer roulette](#reviewer-roulette) recommendation (see above for UX reviews).
To find a domain expert:
@@ -77,7 +84,7 @@ Reviewer roulette is an internal tool for use on GitLab.com, and not available f
The [Danger bot](dangerbot.md) randomly picks a reviewer and a maintainer for
each area of the codebase that your merge request seems to touch. It makes
**recommendations** for developer reviewers and you should override it if you think someone else is a better
-fit. User-facing changes are required to have a UX review, too. Default to the recommended UX reviewer suggested.
+fit. User-facing changes are also required to have a UX review, even if it's behind a feature flag. Default to the recommended UX reviewer suggested.
It picks reviewers and maintainers from the list at the
[engineering projects](https://about.gitlab.com/handbook/engineering/projects/)
@@ -147,7 +154,7 @@ with [domain expertise](#domain-experts).
| `~workhorse` changes | [Workhorse maintainer](https://about.gitlab.com/handbook/engineering/projects/#gitlab_maintainers_workhorse). |
| `~frontend` changes (*1*) | [Frontend maintainer](https://about.gitlab.com/handbook/engineering/projects/#gitlab_maintainers_frontend). |
| `~UX` user-facing changes (*3*) | [Product Designer](https://about.gitlab.com/handbook/engineering/projects/#gitlab_reviewers_UX). Refer to the [design and user interface guidelines](contributing/design.md) for details. |
-| Adding a new JavaScript library (*1*) | - [Frontend foundations member](https://about.gitlab.com/direction/ecosystem/foundations/) if the library significantly increases the [bundle size](https://gitlab.com/gitlab-org/frontend/playground/webpack-memory-metrics/-/blob/master/doc/report.md).<br/>- A [legal department member](https://about.gitlab.com/handbook/legal/) if the license used by the new library hasn't been approved for use in GitLab.<br/><br/>More information about license compatibility can be found in our [GitLab Licensing and Compatibility documentation](licensing.md). |
+| Adding a new JavaScript library (*1*) | - [Frontend foundations member](https://about.gitlab.com/direction/manage/foundations/) if the library significantly increases the [bundle size](https://gitlab.com/gitlab-org/frontend/playground/webpack-memory-metrics/-/blob/master/doc/report.md).<br/>- A [legal department member](https://about.gitlab.com/handbook/legal/) if the license used by the new library hasn't been approved for use in GitLab.<br/><br/>More information about license compatibility can be found in our [GitLab Licensing and Compatibility documentation](licensing.md). |
| A new dependency or a file system change | - [Distribution team member](https://about.gitlab.com/company/team/). See how to work with the [Distribution team](https://about.gitlab.com/handbook/engineering/development/enablement/systems/distribution/#how-to-work-with-distribution) for more details.<br/>- For Rubygems, request an [AppSec review](gemfile.md#request-an-appsec-review). |
| `~documentation` or `~UI text` changes | [Technical writer](https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments) based on assignments in the appropriate [DevOps stage group](https://about.gitlab.com/handbook/product/categories/#devops-stages). |
| Changes to development guidelines | Follow the [review process](development_processes.md#development-guidelines-review) and get the approvals accordingly. |
@@ -212,8 +219,8 @@ See the [test engineering process](https://about.gitlab.com/handbook/engineering
##### Security
-1. I have confirmed that if this MR contains changes to processing or storing of credentials or tokens, authorization, and authentication methods, or other items described in [the security review guidelines](https://about.gitlab.com/handbook/engineering/security/#when-to-request-a-security-review), I have added the `~security` label and I have `@`-mentioned `@gitlab-com/gl-security/appsec`.
-1. I have reviewed the documentation regarding [internal application security reviews](https://about.gitlab.com/handbook/engineering/security/#internal-application-security-reviews) for **when** and **how** to request a security review and requested a security review if this is warranted for this change.
+1. I have confirmed that if this MR contains changes to processing or storing of credentials or tokens, authorization, and authentication methods, or other items described in [the security review guidelines](https://about.gitlab.com/handbook/security/#when-to-request-a-security-review), I have added the `~security` label and I have `@`-mentioned `@gitlab-com/gl-security/appsec`.
+1. I have reviewed the documentation regarding [internal application security reviews](https://about.gitlab.com/handbook/security/#internal-application-security-reviews) for **when** and **how** to request a security review and requested a security review if this is warranted for this change.
##### Deployment
@@ -508,7 +515,7 @@ people who add commits to an MR are not authorized to approve the merge request,
so they must seek a maintainer who has not contributed to the MR to approve the MR before it can be merged.
This policy is in place to satisfy the CHG-04 control of the GitLab
-[Change Management Controls](https://about.gitlab.com/handbook/engineering/security/security-assurance/security-compliance/guidance/change-management.html).
+[Change Management Controls](https://about.gitlab.com/handbook/security/security-assurance/security-compliance/guidance/change-management.html).
To implement this policy in `gitlab-org/gitlab`, we have enabled the following
settings to ensure MRs get an approval from a top-level CODEOWNERS maintainer:
@@ -518,6 +525,9 @@ settings to ensure MRs get an approval from a top-level CODEOWNERS maintainer:
- [Prevent editing approval rules in merge requests](../user/project/merge_requests/approvals/settings.md#prevent-editing-approval-rules-in-merge-requests).
- [Remove all approvals when commits are added to the source branch](../user/project/merge_requests/approvals/settings.md#remove-all-approvals-when-commits-are-added-to-the-source-branch)
+To update the code owners in the `CODEOWNERS` file for `gitlab-org/gitlab`, follow
+the process explained in the [code owners approvals handbook section](https://about.gitlab.com/handbook/engineering/workflow/code-review/#code-owner-approvals).
+
There are scenarios such as rebasing locally or applying suggestions that are considered
the same as adding a commit and could reset existing approvals. Approvals are not removed
when rebasing from the UI or with the [`/rebase` quick action](../user/project/quick_actions.md).
diff --git a/doc/development/contributing/design.md b/doc/development/contributing/design.md
index 9e54b92337a..e6b6b56cf73 100644
--- a/doc/development/contributing/design.md
+++ b/doc/development/contributing/design.md
@@ -24,7 +24,7 @@ screenshots (or videos) of your changes in the description, as explained in our
[MR workflow](merge_request_workflow.md). These screenshots/videos are very helpful
for all reviewers and can speed up the review process, especially if the changes
are small.
-- Attach the ~UX label to any merge request that impacts the user experience. This will enable Product Designers to [review](https://about.gitlab.com/handbook/engineering/ux/product-designer/mr-reviews/#stage-group-mrs/) any user facing changes.
+- Attach the ~UX label to any merge request that impacts the user experience. This will enable Product Designers to [review](https://about.gitlab.com/handbook/product/ux/product-designer/mr-reviews/#stage-group-mrs/) any user facing changes.
- Assign the Product Designer suggested by Reviewer Roulette as the reviewer of your merge request. The reviewer does not have to be the domain expert unless this is a community contribution.
## Checklist
@@ -64,7 +64,7 @@ Check visual design properties using your browser's _elements inspector_ ([Chrom
guidelines.
- _Optionally_ consider [dark mode](../../user/profile/preferences.md#dark-mode). [^1]
- [^1]: You're not required to design for [dark mode](../../user/profile/preferences.md#dark-mode) while the feature is in [alpha](../../policy/alpha-beta-support.md#alpha-features). The [UX Foundations team](https://about.gitlab.com/direction/ecosystem/foundations/) plans to improve the dark mode in the future. Until we integrate [Pajamas](https://design.gitlab.com/) components into the product and the underlying design strategy is in place to support dark mode, we cannot guarantee that we won't introduce bugs and debt to this mode. At your discretion, evaluate the need to create dark mode patches.
+ [^1]: You're not required to design for [dark mode](../../user/profile/preferences.md#dark-mode) while the feature is in [alpha](../../policy/alpha-beta-support.md#alpha-features). The [UX Foundations team](https://about.gitlab.com/direction/manage/foundations/) plans to improve the dark mode in the future. Until we integrate [Pajamas](https://design.gitlab.com/) components into the product and the underlying design strategy is in place to support dark mode, we cannot guarantee that we won't introduce bugs and debt to this mode. At your discretion, evaluate the need to create dark mode patches.
### States
diff --git a/doc/development/contributing/index.md b/doc/development/contributing/index.md
index cbccd832d78..8c0d18f877b 100644
--- a/doc/development/contributing/index.md
+++ b/doc/development/contributing/index.md
@@ -100,7 +100,7 @@ If you have any questions or need help, visit [Getting Help](https://about.gitla
communicate with the GitLab community. GitLab prefers [asynchronous communication](https://about.gitlab.com/handbook/communication/#internal-communication) over real-time communication.
We do encourage you to connect and hang out with us. GitLab has a Gitter room dedicated for [contributors](https://gitter.im/gitlab/contributors), which is bridged with our
-internal Slack. We actively monitor this channel. There is also a community-run [Discord server](https://discord.gg/S4cwz9sR8u) where you can
+internal Slack. We actively monitor this channel. There is also a community-run [Discord server](http://discord.gg/gitlab) where you can
find other contributors in the `#contributors` channel.
Thanks for your contribution!
diff --git a/doc/development/contributing/merge_request_workflow.md b/doc/development/contributing/merge_request_workflow.md
index b40df01cbe9..f2c06e289c9 100644
--- a/doc/development/contributing/merge_request_workflow.md
+++ b/doc/development/contributing/merge_request_workflow.md
@@ -38,6 +38,10 @@ and see the [Development section](../../index.md) for the required guidelines.
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).
+
If the change is non-trivial, we encourage you to
start a discussion with [a product manager or a member of the team](https://about.gitlab.com/handbook/product/categories/).
You can do
diff --git a/doc/development/contributing/style_guides.md b/doc/development/contributing/style_guides.md
index 9d04e1590d0..fe1aa8449c2 100644
--- a/doc/development/contributing/style_guides.md
+++ b/doc/development/contributing/style_guides.md
@@ -108,117 +108,6 @@ pre-push:
For more information, check out [Lefthook documentation Skipping commands section](https://github.com/evilmartians/lefthook/blob/master/docs/full_guide.md#skipping-commands).
-## Ruby, Rails, RSpec
-
-Our codebase style is defined and enforced by [RuboCop](https://github.com/rubocop-hq/rubocop).
-
-You can check for any offenses locally with `bundle exec rubocop --parallel`.
-On the CI, this is automatically checked by the `static-analysis` jobs.
-
-In addition, you can [integrate RuboCop](../developing_with_solargraph.md) into
-supported IDEs using the [Solargraph](https://github.com/castwide/solargraph) gem.
-
-For RuboCop rules that we have not taken a decision on yet, we follow the
-[Ruby Style Guide](https://github.com/rubocop-hq/ruby-style-guide),
-[Rails Style Guide](https://github.com/rubocop-hq/rails-style-guide), and
-[RSpec Style Guide](https://github.com/rubocop-hq/rspec-style-guide) as general
-guidelines to write idiomatic Ruby/Rails/RSpec, but reviewers/maintainers should
-be tolerant and not too pedantic about style.
-
-Similarly, some RuboCop rules are currently disabled, and for those,
-reviewers/maintainers must not ask authors to use one style or the other, as both
-are accepted. This isn't an ideal situation since this leaves space for
-[bike-shedding](https://en.wiktionary.org/wiki/bikeshedding), and ideally we
-should enable all RuboCop rules to avoid style-related
-discussions/nitpicking/back-and-forth in reviews. There are some styles that
-commonly come up in reviews that are not enforced, the
-[GitLab Ruby style guide](../backend/ruby_style_guide.md) includes a non-exhaustive
-list of these topics.
-
-Additionally, we have a dedicated
-[newlines style guide](../newlines_styleguide.md), as well as dedicated
-[test-specific style guides and best practices](../testing_guide/index.md).
-
-### Creating new RuboCop cops
-
-Typically it is better for the linting rules to be enforced programmatically as it
-reduces the aforementioned [bike-shedding](https://en.wiktionary.org/wiki/bikeshedding).
-
-To that end, we encourage creation of new RuboCop rules in the codebase.
-
-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.
-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.
-
-### Cop grace period
-
-A cop is in a "grace period" if it is enabled and has `Details: grace period` defined in its TODO YAML configuration.
-
-On the default branch, all of the offenses from cops in the ["grace period"](../rake_tasks.md#run-rubocop-in-graceful-mode) will not fail the RuboCop CI job. The job will notify Slack in the `#f_rubocop` channel when offenses have been silenced in the scheduled pipeline. However, on merge request pipelines, the RuboCop job will fail.
-
-A grace period can safely be lifted as soon as there are no warnings for 2 weeks in the `#f_rubocop` channel on Slack.
-
-### Enabling a new cop
-
-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 remove "grace period" after 2 weeks silence in `#f_rubocop` Slack channel. ([See an example](https://gitlab.com/gitlab-org/gitlab/-/issues/374903).)
-
-### Silenced offenses
-
-When offenses are silenced for cops in ["grace period"](#cop-grace-period),
-the `#f_rubocop` Slack channel receives a notification message every two hours.
-
-To fix this issue:
-
-1. Find cops with silenced offenses in the linked CI job.
-1. [Generate TODOs](../rake_tasks.md#generate-initial-rubocop-todo-list) for these cops.
-
-#### RuboCop node pattern
-
-When creating [node patterns](https://docs.rubocop.org/rubocop-ast/node_pattern.html) to match
-Ruby's AST, you can use [`scripts/rubocop-parse`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/scripts/rubocop-parse)
-to display the AST of a Ruby expression, to help you create the matcher.
-See also [!97024](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97024).
-
-### Resolving RuboCop exceptions
-
-When the number of RuboCop exceptions exceed the default [`exclude-limit` of 15](https://docs.rubocop.org/rubocop/1.2/usage/basic_usage.html#command-line-flags),
-we may want to resolve exceptions over multiple commits. To minimize confusion,
-we should track our progress through the exception list.
-
-The preferred way to [generate the initial list or a list for specific RuboCop rules](../rake_tasks.md#generate-initial-rubocop-todo-list)
-is to run the Rake task `rubocop:todo:generate`:
-
-```shell
-# Initial list
-bundle exec rake rubocop:todo:generate
-
-# List for specific RuboCop rules
-bundle exec rake 'rubocop:todo:generate[Gitlab/NamespacedClass,Lint/Syntax]'
-```
-
-This Rake task creates or updates the exception list in `.rubocop_todo/`. For
-example, the configuration for the RuboCop rule `Gitlab/NamespacedClass` is
-located in `.rubocop_todo/gitlab/namespaced_class.yml`.
-
-Make sure to commit any changes in `.rubocop_todo/` after running the Rake task.
-
-### Reveal existing RuboCop exceptions
-
-To reveal existing RuboCop exceptions in the code that have been excluded via `.rubocop_todo.yml` and
-`.rubocop_todo/**/*.yml`, set the environment variable `REVEAL_RUBOCOP_TODO` to `1`.
-
-This allows you to reveal existing RuboCop exceptions during your daily work cycle and fix them along the way.
-
-NOTE:
-Define permanent `Exclude`s in `.rubocop.yml` instead of `.rubocop_todo/**/*.yml`.
-
## Database migrations
See the dedicated [Database Migrations Style Guide](../migration_style_guide.md).
@@ -231,6 +120,10 @@ See the dedicated [JS Style Guide](../fe_guide/style/javascript.md).
See the dedicated [SCSS Style Guide](../fe_guide/style/scss.md).
+## Ruby
+
+See the dedicated [Ruby Style Guide](../backend/ruby_style_guide.md).
+
## Go
See the dedicated [Go standards and style guidelines](../go_guide/index.md).
diff --git a/doc/development/database/adding_database_indexes.md b/doc/development/database/adding_database_indexes.md
index 040c6780316..d4cd807ef22 100644
--- a/doc/development/database/adding_database_indexes.md
+++ b/doc/development/database/adding_database_indexes.md
@@ -215,6 +215,42 @@ def down
end
```
+## Indexes for partitioned tables
+
+Indexes [cannot be created](https://www.postgresql.org/docs/15/ddl-partitioning.html#DDL-PARTITIONING-DECLARATIVE-MAINTENANCE)
+**concurrently** on a partitioned table. You must use `CONCURRENTLY` to avoid service disruption in a hot system.
+
+To create an index on a partitioned table, use `add_concurrent_partitioned_index`, provided by the database team.
+
+Under the hood, `add_concurrent_partitioned_index`:
+
+1. Creates indexes on each partition using `CONCURRENTLY`.
+1. Creates an index on the parent table.
+
+A Rails migration example:
+
+```ruby
+# in db/post_migrate/
+
+class AddIndexToPartitionedTable < Gitlab::Database::Migration[2.0]
+ include Gitlab::Database::PartitioningMigrationHelpers
+
+ disable_ddl_transaction!
+
+ TABLE_NAME = :table_name
+ COLUMN_NAMES = [:partition_id, :id]
+ INDEX_NAME = :index_name
+
+ def up
+ add_concurrent_partitioned_index(TABLE_NAME, COLUMN_NAMES, name: INDEX_NAME)
+ end
+
+ def down
+ remove_concurrent_partitioned_index_by_name(TABLE_NAME, INDEX_NAME)
+ end
+end
+```
+
## Create indexes asynchronously
For very large tables, index creation can be a challenge to manage.
diff --git a/doc/development/database/background_migrations.md b/doc/development/database/background_migrations.md
index 8e6f29b9eb8..fe62bbc6b14 100644
--- a/doc/development/database/background_migrations.md
+++ b/doc/development/database/background_migrations.md
@@ -236,7 +236,7 @@ Next we need a post-deployment migration that schedules the migration for
existing data.
```ruby
-class ScheduleExtractIntegrationsUrl < Gitlab::Database::Migration[1.0]
+class ScheduleExtractIntegrationsUrl < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
MIGRATION = 'ExtractIntegrationsUrl'
@@ -263,7 +263,7 @@ jobs and manually run on any un-migrated rows. Such a migration would look like
this:
```ruby
-class ConsumeRemainingExtractIntegrationsUrlJobs < Gitlab::Database::Migration[1.0]
+class ConsumeRemainingExtractIntegrationsUrlJobs < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
def up
diff --git a/doc/development/database/batched_background_migrations.md b/doc/development/database/batched_background_migrations.md
index a48a9c42e27..ca11e9c8dd3 100644
--- a/doc/development/database/batched_background_migrations.md
+++ b/doc/development/database/batched_background_migrations.md
@@ -219,6 +219,7 @@ In this example, `copy_from` returns `name`, and `copy_to` returns `name_convert
```ruby
class CopyColumnUsingBackgroundMigrationJob < BatchedMigrationJob
job_arguments :copy_from, :copy_to
+ operation_name :update_all
def perform
from_column = connection.quote_column_name(copy_from)
@@ -226,7 +227,7 @@ class CopyColumnUsingBackgroundMigrationJob < BatchedMigrationJob
assignment_clause = "#{to_column} = #{from_column}"
- each_sub_batch(operation_name: :update_all) do |relation|
+ each_sub_batch do |relation|
relation.update_all(assignment_clause)
end
end
@@ -267,9 +268,10 @@ In the second (filtered) example, we know exactly 100 will be updated with each
```ruby
class BackfillNamespaceType < BatchedMigrationJob
scope_to ->(relation) { relation.where(type: nil) }
+ operation_name :update_all
def perform
- each_sub_batch(operation_name: :update_all) do |sub_batch|
+ each_sub_batch do |sub_batch|
sub_batch.update_all(type: 'User')
end
end
@@ -327,9 +329,10 @@ background migration.
# self.table_name = 'routes'
# end
+ operation_name :update_all
+
def perform
each_sub_batch(
- operation_name: :update_all,
batching_scope: -> (relation) { relation.where("source_type <> 'UnusedType'") }
) do |sub_batch|
sub_batch.update_all('namespace_id = source_id')
@@ -483,8 +486,10 @@ module Gitlab
class BatchProjectsWithIssues < Gitlab::BackgroundMigration::BatchedMigrationJob
include Gitlab::Database::DynamicModelHelpers
+ operation_name :backfill_issues
+
def perform
- distinct_each_batch(operation_name: :backfill_issues) do |batch|
+ distinct_each_batch do |batch|
project_ids = batch.pluck(batch_column)
# do something with the distinct project_ids
end
diff --git a/doc/development/database/database_debugging.md b/doc/development/database/database_debugging.md
index 4dc6a3bdcfa..0d6e9955a19 100644
--- a/doc/development/database/database_debugging.md
+++ b/doc/development/database/database_debugging.md
@@ -49,9 +49,11 @@ bundle exec rake db:reset RAILS_ENV=test
- `bundle exec rake db:migrate RAILS_ENV=development`: Execute any pending migrations that you may have picked up from a MR
- `bundle exec rake db:migrate:status RAILS_ENV=development`: Check if all migrations are `up` or `down`
-- `bundle exec rake db:migrate:down VERSION=20170926203418 RAILS_ENV=development`: Tear down a migration
-- `bundle exec rake db:migrate:up VERSION=20170926203418 RAILS_ENV=development`: Set up a migration
-- `bundle exec rake db:migrate:redo VERSION=20170926203418 RAILS_ENV=development`: Re-run a specific migration
+- `bundle exec rake db:migrate:down:main VERSION=20170926203418 RAILS_ENV=development`: Tear down a migration
+- `bundle exec rake db:migrate:up:main VERSION=20170926203418 RAILS_ENV=development`: Set up a migration
+- `bundle exec rake db:migrate:redo:main VERSION=20170926203418 RAILS_ENV=development`: Re-run a specific migration
+
+Replace `main` in the above commands to execute agains the `ci` database instead of `main`.
## Manually access the database
diff --git a/doc/development/database/database_migration_pipeline.md b/doc/development/database/database_migration_pipeline.md
index 148dc1e94a0..06e16b4c7f1 100644
--- a/doc/development/database/database_migration_pipeline.md
+++ b/doc/development/database/database_migration_pipeline.md
@@ -22,34 +22,54 @@ For security reasons, access to the pipeline is restricted to database maintaine
When the pipeline starts, a bot notifies you with a comment in the merge request.
When it finishes, the comment gets updated with the test results.
-There are three sections which are described below.
+
+The comment contains testing information for both the `main` and `ci` databases.
+Each database tested has four sections which are described below.
## Summary
The first section of the comment contains a summary of the test results, including:
-| Result | Description |
-|-------------------|---------------------------------------------------------------------------------------------------------------------|
-| Warnings | Highlights critical issues such as exceptions or long-running queries. |
-| Migrations | The time each migration took to complete, whether it was successful, and the increment in the size of the database. |
-| Runtime histogram | Expand this section to see a histogram of query runtimes across all migrations. |
+- **Warnings** - Highlights critical issues such as exceptions or long-running queries.
+- **Migrations** - The time each migration took to complete, whether it was successful,
+ and the increment in the size of the database.
+- **Runtime histogram** - Expand this section to see a histogram of query runtimes across all migrations.
## Migration details
The next section of the comment contains detailed information for each migration, including:
-| Result | Description |
-|-------------------|-------------------------------------------------------------------------------------------------------------------------|
-| Details | The type of migration, total duration, and database size change. |
-| Queries | Every query executed during the migration, along with the number of calls, timings, and the number of the changed rows. |
-| Runtime histogram | Indicates the distribution of query times for the migration. |
+- **Details** - The type of migration, total duration, and database size change.
+- **Queries** - Every query executed during the migration, along with the number of
+ calls, timings, and the number of the changed rows.
+- **Runtime histogram** - Indicates the distribution of query times for the migration.
+
+## Background migration details
+
+The next section of the comment contains detailed information about each batched background migration, including:
+
+- **Sampling information** - The number of batches sampled during this test run.
+ Sampled batches are chosen uniformly across the table's ID range. Sampling runs
+ for 30 minutes, split evenly across each background migration to test.
+- **Aggregated query information** - Aggregate data about each query executed across
+ all the sampled batches, along with the number of calls, timings, and the number of changed rows.
+- **Batch runtime histogram** - A histogram of timings for each sampled batch
+ from the background migration.
+- **Query runtime histogram** - A histogram of timings for all queries executed
+ in any batch of this background migration.
## Clone details and artifacts
Some additional information is included at the bottom of the comment:
-| Result | Description |
-|----------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| Migrations pending on GitLab.com | A summary of migrations not deployed yet to GitLab.com. This information is useful when testing a migration that was merged but not deployed yet. |
-| Clone details | A link to the `Postgres.ai` thin clone created for this testing pipeline, along with information about its expiry. This can be used to further explore the results of running the migration. Only accessible by database maintainers or with an access request. |
-| Artifacts | A link to the pipeline's artifacts. Full query logs for each migration (ending in `.log`) are available there and only accessible by database maintainers or with an access request. |
+- **Migrations pending on GitLab.com** - A summary of migrations not deployed yet
+ to GitLab.com. This information is useful when testing a migration that was merged
+ but not deployed yet.
+- **Clone details** - A link to the `Postgres.ai` thin clone created for this
+ testing pipeline, along with information about its expiry. This can be used to
+ further explore the results of running the migration. Only accessible by
+ database maintainers or with an access request.
+- **Artifacts** - A link to the pipeline's artifacts. Full query logs for each
+ migration (ending in `.log`) are available there, and only accessible by
+ database maintainers or with an access request. Details of the specific
+ batched background migration batches sampled are also available.
diff --git a/doc/development/database/loose_foreign_keys.md b/doc/development/database/loose_foreign_keys.md
index abf66368548..962cd2602bc 100644
--- a/doc/development/database/loose_foreign_keys.md
+++ b/doc/development/database/loose_foreign_keys.md
@@ -192,7 +192,7 @@ trigger needs to be configured only once. If the model already has at least one
`loose_foreign_key` definition, then this step can be skipped:
```ruby
-class TrackProjectRecordChanges < Gitlab::Database::Migration[1.0]
+class TrackProjectRecordChanges < Gitlab::Database::Migration[2.0]
include Gitlab::Database::MigrationHelpers::LooseForeignKeyHelpers
enable_lock_retries!
@@ -227,7 +227,7 @@ trigger. If the foreign key is deleted earlier, there is a good chance of
introducing data inconsistency which needs manual cleanup:
```ruby
-class RemoveProjectsCiPipelineFk < Gitlab::Database::Migration[1.0]
+class RemoveProjectsCiPipelineFk < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
def up
@@ -258,7 +258,7 @@ records in the database.
Migration for removing the trigger:
```ruby
-class UnTrackProjectRecordChanges < Gitlab::Database::Migration[1.0]
+class UnTrackProjectRecordChanges < Gitlab::Database::Migration[2.0]
include Gitlab::Database::MigrationHelpers::LooseForeignKeyHelpers
enable_lock_retries!
@@ -278,7 +278,7 @@ table however, there is still a chance for having leftover pending records in th
must be removed with an inline data migration.
```ruby
-class RemoveLeftoverProjectDeletions < Gitlab::Database::Migration[1.0]
+class RemoveLeftoverProjectDeletions < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
def up
diff --git a/doc/development/database/not_null_constraints.md b/doc/development/database/not_null_constraints.md
index dccaff2df00..53ab9a83d60 100644
--- a/doc/development/database/not_null_constraints.md
+++ b/doc/development/database/not_null_constraints.md
@@ -25,7 +25,7 @@ For example, consider a migration that creates a table with two `NOT NULL` colum
`db/migrate/20200401000001_create_db_guides.rb`:
```ruby
-class CreateDbGuides < Gitlab::Database::Migration[1.0]
+class CreateDbGuides < Gitlab::Database::Migration[2.0]
def change
create_table :db_guides do |t|
t.bigint :stars, default: 0, null: false
@@ -44,7 +44,7 @@ For example, consider a migration that adds a new `NOT NULL` column `active` to
`db/migrate/20200501000001_add_active_to_db_guides.rb`:
```ruby
-class AddExtendedTitleToSprints < Gitlab::Database::Migration[1.0]
+class AddExtendedTitleToSprints < Gitlab::Database::Migration[2.0]
def change
add_column :db_guides, :active, :boolean, default: true, null: false
end
@@ -116,7 +116,7 @@ with `validate: false` in a post-deployment migration,
`db/post_migrate/20200501000001_add_not_null_constraint_to_epics_description.rb`:
```ruby
-class AddNotNullConstraintToEpicsDescription < Gitlab::Database::Migration[1.0]
+class AddNotNullConstraintToEpicsDescription < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
def up
@@ -147,7 +147,7 @@ so we add a post-deployment migration for the 13.0 milestone (current),
`db/post_migrate/20200501000002_cleanup_epics_with_null_description.rb`:
```ruby
-class CleanupEpicsWithNullDescription < Gitlab::Database::Migration[1.0]
+class CleanupEpicsWithNullDescription < Gitlab::Database::Migration[2.0]
# With BATCH_SIZE=1000 and epics.count=29500 on GitLab.com
# - 30 iterations will be run
# - each requires on average ~150ms
@@ -185,7 +185,7 @@ migration helper in a final post-deployment migration,
`db/post_migrate/20200601000001_validate_not_null_constraint_on_epics_description.rb`:
```ruby
-class ValidateNotNullConstraintOnEpicsDescription < Gitlab::Database::Migration[1.0]
+class ValidateNotNullConstraintOnEpicsDescription < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
def up
diff --git a/doc/development/database/query_recorder.md b/doc/development/database/query_recorder.md
index 3fc38c10d68..f1540e7e2ae 100644
--- a/doc/development/database/query_recorder.md
+++ b/doc/development/database/query_recorder.md
@@ -39,12 +39,17 @@ end
As an example you might create 5 issues in between counts, which would cause the query count to increase by 5 if an N+1 problem exists.
-In some cases the query count might change slightly between runs for unrelated reasons. In this case you might need to test `exceed_query_limit(control_count + acceptable_change)`, but this should be avoided if possible.
+In some cases, the query count might change slightly between runs for unrelated reasons. In this case you might need to test `exceed_query_limit(control_count + acceptable_change)`, but this should be avoided if possible.
If this test fails, and the control was passed as a `QueryRecorder`, then the
failure message indicates where the extra queries are by matching queries on
the longest common prefix, grouping similar queries together.
+In some cases, N+1 specs have been written to include three requests: first one to
+warm the cache, second one to establish a control, third one to validate that
+ther are no N+1 queries. Rather than make an extra request to warm the cache, prefer two requests
+(control and test) and configure your test to ignore [cached queries](#cached-queries) in N+1 specs.
+
## Cached queries
By default, QueryRecorder ignores [cached queries](../merge_request_performance_guidelines.md#cached-queries) in the count. However, it may be better to count
@@ -62,7 +67,7 @@ end
## Use request specs instead of controller specs
-Use a [request spec](https://gitlab.com/gitlab-org/gitlab-foss/tree/master/spec/requests) when writing a N+1 test on the controller level.
+Use a [request spec](https://gitlab.com/gitlab-org/gitlab/-/tree/master/spec/requests) when writing a N+1 test on the controller level.
Controller specs should not be used to write N+1 tests as the controller is only initialized once per example.
This could lead to false successes where subsequent "requests" could have queries reduced (for example, because of memoization).
diff --git a/doc/development/database/single_table_inheritance.md b/doc/development/database/single_table_inheritance.md
index ad0101e1594..32de1fdea35 100644
--- a/doc/development/database/single_table_inheritance.md
+++ b/doc/development/database/single_table_inheritance.md
@@ -47,7 +47,7 @@ This ensures that the migration loads the columns for the migration in isolation
and the helper disables STI by default.
```ruby
-class EnqueueSomeBackgroundMigration < Gitlab::Database::Migration[1.0]
+class EnqueueSomeBackgroundMigration < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
def up
diff --git a/doc/development/database/table_partitioning.md b/doc/development/database/table_partitioning.md
index bf12329473d..ac715b871da 100644
--- a/doc/development/database/table_partitioning.md
+++ b/doc/development/database/table_partitioning.md
@@ -173,7 +173,7 @@ An example migration of partitioning the `audit_events` table by its
`created_at` column would look like:
```ruby
-class PartitionAuditEvents < Gitlab::Database::Migration[1.0]
+class PartitionAuditEvents < Gitlab::Database::Migration[2.0]
include Gitlab::Database::PartitioningMigrationHelpers
def up
@@ -200,7 +200,7 @@ into the partitioned copy.
Continuing the above example, the migration would look like:
```ruby
-class BackfillPartitionAuditEvents < Gitlab::Database::Migration[1.0]
+class BackfillPartitionAuditEvents < Gitlab::Database::Migration[2.0]
include Gitlab::Database::PartitioningMigrationHelpers
def up
@@ -233,7 +233,7 @@ failed jobs.
Once again, continuing the example, this migration would look like:
```ruby
-class CleanupPartitionedAuditEventsBackfill < Gitlab::Database::Migration[1.0]
+class CleanupPartitionedAuditEventsBackfill < Gitlab::Database::Migration[2.0]
include Gitlab::Database::PartitioningMigrationHelpers
def up
@@ -447,6 +447,7 @@ class ConvertTableToListPartitioning < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
TABLE_NAME = :table_name
+ TABLE_FK = :table_references_by_fk
PARENT_TABLE_NAME = :p_table_name
FIRST_PARTITION = 100
PARTITION_COLUMN = :partition_id
@@ -457,6 +458,7 @@ class ConvertTableToListPartitioning < Gitlab::Database::Migration[2.0]
partitioning_column: PARTITION_COLUMN,
parent_table_name: PARENT_TABLE_NAME,
initial_partitioning_value: FIRST_PARTITION
+ lock_tables: [TABLE_FK, TABLE_NAME]
)
end
@@ -470,3 +472,14 @@ class ConvertTableToListPartitioning < Gitlab::Database::Migration[2.0]
end
end
```
+
+NOTE:
+Do not forget to set the sequence name explicitly in your model because it will
+be owned by the routing table and `ActiveRecord` can't determine it. This can
+be cleaned up after the `table_name` is changed to the routing table.
+
+```ruby
+class Model < ApplicationRecord
+ self.sequence_name = 'model_id_seq'
+end
+```
diff --git a/doc/development/database_review.md b/doc/development/database_review.md
index 58776c5330c..7fbc48af91c 100644
--- a/doc/development/database_review.md
+++ b/doc/development/database_review.md
@@ -43,15 +43,14 @@ If your merge request description does not include these items, the review is re
#### Migrations
-If new migrations are introduced, in the MR **you are required to provide**:
-
-- The output of both migrating (`db:migrate`) and rolling back (`db:rollback`) for all migrations.
+If new migrations are introduced, database reviewers must review the output of both migrating (`db:migrate`)
+and rolling back (`db:rollback`) for all migrations.
We have automated tooling for
[GitLab](https://gitlab.com/gitlab-org/gitlab) (provided by the
-[`db:check-migrations`](database/dbcheck-migrations-job.md) pipeline job) that provides this output for migrations on
-~database merge requests. You do not need to provide this information manually
-if the bot can do it for you. The bot also checks that migrations are correctly
+[`db:check-migrations`](database/dbcheck-migrations-job.md) pipeline job) that provides this output in the CI job logs.
+It is not required for the author to provide this output in the merge request description,
+but doing so may be helpful for reviewers. The bot also checks that migrations are correctly
reversible.
#### Queries
@@ -176,7 +175,7 @@ Include in the MR description:
- 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 clicking **Share** in the upper right corner.
+ 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.
- 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,
diff --git a/doc/development/deprecation_guidelines/index.md b/doc/development/deprecation_guidelines/index.md
index a940cd9404c..be4a3369dcb 100644
--- a/doc/development/deprecation_guidelines/index.md
+++ b/doc/development/deprecation_guidelines/index.md
@@ -83,7 +83,7 @@ For configuration removals, see the [Omnibus deprecation policy](../../administr
For versioning and upgrade details, see our [Release and Maintenance policy](../../policy/maintenance.md).
-## Update the deprecations and removals documentation
+## Update the deprecations and removals documentation pages
The [deprecations](../../update/deprecations.md) and [removals](../../update/removals.md)
documentation is generated from the YAML files located in
@@ -131,3 +131,7 @@ Related Handbook pages:
- <https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations-removals-and-breaking-changes>
- <https://about.gitlab.com/handbook/marketing/blog/release-posts/#update-the-deprecations-and-removals-docs>
+
+## Update the related documentation
+
+When features are deprecated and removed, [update the related documentation](../documentation/versions.md#deprecations-and-removals).
diff --git a/doc/development/development_processes.md b/doc/development/development_processes.md
index 10818b749ab..e1df3b55d06 100644
--- a/doc/development/development_processes.md
+++ b/doc/development/development_processes.md
@@ -80,7 +80,7 @@ In these cases, use the following workflow:
- [Backend](https://about.gitlab.com/handbook/engineering/)
- [Database](https://about.gitlab.com/handbook/engineering/development/database/)
- [User Experience (UX)](https://about.gitlab.com/handbook/product/ux/)
- - [Security](https://about.gitlab.com/handbook/engineering/security/)
+ - [Security](https://about.gitlab.com/handbook/security/)
- [Quality](https://about.gitlab.com/handbook/engineering/quality/)
- [Engineering Productivity](https://about.gitlab.com/handbook/engineering/quality/engineering-productivity/)
- [Infrastructure](https://about.gitlab.com/handbook/engineering/infrastructure/)
diff --git a/doc/development/distributed_tracing.md b/doc/development/distributed_tracing.md
index 0ca10bc93dd..9e62f019fbf 100644
--- a/doc/development/distributed_tracing.md
+++ b/doc/development/distributed_tracing.md
@@ -91,7 +91,7 @@ Once the performance bar is enabled, select **Trace** in the performance bar to
the Jaeger UI.
The Jaeger search UI returns a query for the `Correlation-ID` of the current request. Normally,
-this search should return a single trace result. Clicking this result shows the detail of the
+this search should return a single trace result. Selecting this result shows the detail of the
trace in a hierarchical time-line.
![Jaeger Search UI](img/distributed_tracing_jaeger_ui.png)
diff --git a/doc/development/documentation/drawers.md b/doc/development/documentation/drawers.md
new file mode 100644
index 00000000000..7ede1a0b652
--- /dev/null
+++ b/doc/development/documentation/drawers.md
@@ -0,0 +1,59 @@
+---
+stage: none
+group: Documentation Guidelines
+info: To 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 content for drawers
+
+In the GitLab UI, you can display help content in
+[a drawer component](https://design.gitlab.com/components/drawer/).
+The component for Markdown is
+[in the storybook](https://gitlab-org.gitlab.io/gitlab/storybook/?path=/story/vue-shared-markdown-drawer--default).
+
+The component points to a Markdown file. Any time you update the Markdown
+file, the contents of the drawer are updated.
+
+Drawer content is displayed in drawers only, and not on `docs.gitlab.com`.
+The content is rendered in GitLab Flavored Markdown.
+
+To create this content:
+
+1. In the [GitLab](https://gitlab.com/gitlab-org/gitlab) repository,
+ go to the `/doc/drawers` folder.
+1. Create a Markdown file. Use a descriptive filename.
+ Do not create subfolders.
+1. Add the standard page metadata. Also, include:
+
+ ```markdown
+ type: drawer
+ ```
+
+1. Author the content.
+1. If the page includes content that is also on a page on `docs.gitlab.com`,
+ on the page's metadata, include a path to the other file. For example:
+
+ ```markdown
+ source: /doc/user/search/global_search/advanced_search_syntax.md
+ ```
+
+1. Work with the developer to view the content in the drawer and
+ verify that the content appears correctly.
+
+## Drawer content guidelines
+
+- The headings in the file are used as headings in the drawer.
+ The `H1` heading is the drawer title.
+- Do not include any characters other than plain text in the `H1`.
+- The drawer component is narrow and not resizable.
+ - If you include tables, the content within should be brief.
+ - While no technical limitation exists on the number of characters
+ you can use, you should preview the drawer content to
+ ensure it renders well.
+- To link from the drawer to other content, use absolute URLs.
+- Do not include:
+ - Tier badges
+ - Version history text
+ - Alert boxes
+ - Images
+ - SVG icons
diff --git a/doc/development/documentation/feature_flags.md b/doc/development/documentation/feature_flags.md
index dae62fea603..0fab693fdee 100644
--- a/doc/development/documentation/feature_flags.md
+++ b/doc/development/documentation/feature_flags.md
@@ -57,6 +57,13 @@ FLAG:
<This feature is not ready for production use.>
```
+A `FLAG` note renders on the GitLab documentation site as:
+
+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 `example_flag`.
+On GitLab.com, this feature is not available.
+This feature is not ready for production use.
+
### Self-managed GitLab availability information
| If the feature is... | Use this text |
diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md
index c52b3b5adae..d52db71b633 100644
--- a/doc/development/documentation/index.md
+++ b/doc/development/documentation/index.md
@@ -145,68 +145,41 @@ pages. You can safely remove the `type` metadata parameter and its values.
### Batch updates for TW metadata
-NOTE:
-This task is an MVC, and requires significant manual preparation of the output.
-While the task can be time consuming, it is still faster than doing the work
-entirely manually.
+The [`CODEOWNERS`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/CODEOWNERS)
+file contains a list of files and the associated technical writers.
-It's important to keep the [`CODEOWNERS`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/CODEOWNERS)
-file in the `gitlab` project up to date with the current Technical Writing team assignments.
-This information is used in merge requests that contain documentation:
+When a merge request contains documentation, the information in the `CODEOWNERS` file determines:
-- To populate the eligible approvers section.
-- By GitLab Bot to ping reviewers for community contributions.
+- The list of users in the **Approvers** section.
+- The technical writer that the GitLab Bot pings for community contributions.
-GitLab cannot automatically associate the stage and group metadata in our documentation
-pages with the technical writer assigned to that group, so we use a Rake task to
-generate entries for the `CODEOWNERS` file. Declaring code owners for pages reduces
-the number of times GitLab Bot pings the entire Technical Writing team.
+You can use a Rake task to update the `CODEOWNERS` file.
-The `tw:codeowners` Rake task, located in [`lib/tasks/gitlab/tw/codeowners.rake`](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/tasks/gitlab/tw/codeowners.rake),
-contains an array of groups and their assigned technical writer. This task:
+#### Update the `CODEOWNERS` file
-- Outputs a line for each doc with metadata that matches a group in `lib/tasks/gitlab/tw/codeowners.rake`.
- Files not matching a group are skipped.
-- Adds the full path to the page, and the assigned technical writer.
+To update the `CODEOWNERS` file:
-To prepare an update to the `CODEOWNERS` file:
+1. Open a merge request to update
+ [the Rake task](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/tasks/gitlab/tw/codeowners.rake)
+ with the latest [TW team assignments](https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments).
+1. Assign the merge request to a backend maintainer for review and merge.
+1. After the MR is merged, go to the root of the `gitlab` repository.
+1. Run the Rake task and save the output in a file:
-1. Update `lib/tasks/gitlab/tw/codeowners.rake` with the latest [TW team assignments](https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments).
- Make this update in a standalone merge request, as it runs a long pipeline and
- requires backend maintainer review. Make sure this is merged before you update
- `CODEOWNERS` in another merge request.
-1. Run the task from the root directory of the `gitlab` repository, and save the output in a file:
-
- ```ruby
+ ```shell
bundle exec rake tw:codeowners > ~/Desktop/updates.md
```
-1. Open the file you just created (`~/Desktop/updates.md` in this example), and prepare the output:
- - Find and replace `./` with `/`.
- - Sort the lines in alphabetical (ascending) order. If you use VS Code, you can
- select everything, press <kbd>F1</kbd>, type `sort`, and select **Sort lines (ascending, case insensitive**.
-1. Create a new branch for your `CODEOWNERS` updates.
-1. Replace the documentation-related lines in the `^[Documentation Pages]` section
- with the output you prepared.
+1. Open the file (for example, `~/Desktop/updates.md`) and copy everything
+ except the errors at the bottom of the file.
+1. Open the [`CODEOWNERS`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/CODEOWNERS)
+ file and paste the lines into the `^[Documentation Pages]` section.
WARNING:
The documentation section is not the last section of the `CODEOWNERS` file. Don't
delete data that isn't ours!
-1. Create a commit with the raw changes.
-1. From the command line, run `git diff master`.
-1. In the diff, look for directory-level assignments to manually restore to the
- `CODEOWNERS` file. If all files in a single directory are assigned to the same
- technical writer, we simplify these entries. Remove all the lines for the individual
- files, and leave a single entry for the directory, for example: `/doc/directory/ @tech.writer`.
-1. In the diff, look for changes that don't match your expectations:
- - New pages, or newly moved pages, show up as added lines.
- - Deleted pages, and pages that are now redirects, show up as deleted lines.
- - If you see an unusual number of changes to pages that all seem related,
- check the metadata for the pages. A group might have been renamed and the Rake task
- must be updated to match.
-1. Create another commit with your manual changes, and create a second merge request
- with your changes to the `CODEOWNERS` file. Assign it to a technical writing manager for review.
+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 dc84f3a08dd..21c8c8543ab 100644
--- a/doc/development/documentation/restful_api_styleguide.md
+++ b/doc/development/documentation/restful_api_styleguide.md
@@ -129,7 +129,7 @@ To deprecate an attribute:
```
To widely announce a deprecation, or if it's a breaking change,
-[update the deprecations and removals documentation](../deprecation_guidelines/index.md#update-the-deprecations-and-removals-documentation).
+[update the deprecations and removals documentation pages](../deprecation_guidelines/index.md#update-the-deprecations-and-removals-documentation-pages).
## Method description
@@ -289,7 +289,7 @@ contains spaces in its title. Observe how spaces are escaped using the `%20`
ASCII code.
```shell
-curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/42/issues?title=Hello%20Dude"
+curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/42/issues?title=Hello%20GitLab"
```
Use `%2F` for slashes (`/`).
diff --git a/doc/development/documentation/review_apps.md b/doc/development/documentation/review_apps.md
index cb04f0909c1..3cf77fda22b 100644
--- a/doc/development/documentation/review_apps.md
+++ b/doc/development/documentation/review_apps.md
@@ -47,12 +47,11 @@ If you want to know the in-depth details, here's what's really happening:
1. The preview URL is shown both at the job output and in the merge request
widget. You also get the link to the remote pipeline.
1. In the `gitlab-org/gitlab-docs` project, the pipeline is created and it
- [skips the test jobs](https://gitlab.com/gitlab-org/gitlab-docs/blob/8d5d5c750c602a835614b02f9db42ead1c4b2f5e/.gitlab-ci.yml#L50-55)
+ [skips most test jobs](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/d41ca9323f762132780d2d072f845d28817a5383/.gitlab/ci/rules.gitlab-ci.yml#L101-103)
to lower the build time.
-1. Once the docs site is built, the HTML files are uploaded as artifacts.
-1. A specific runner tied only to the docs project, runs the Review App job
- that downloads the artifacts and uses `rsync` to transfer the files over
- to a location where NGINX serves them.
+1. After the docs site is built, the HTML files are uploaded as artifacts to
+ a GCP bucket (see [issue `gitlab-com/gl-infra/reliability#11021`](https://gitlab.com/gitlab-com/gl-infra/reliability/-/issues/11021)
+ for the implementation details).
The following GitLab features are used among others:
@@ -60,42 +59,26 @@ The following GitLab features are used among others:
- [Multi project pipelines](../../ci/pipelines/downstream_pipelines.md#multi-project-pipelines)
- [Review Apps](../../ci/review_apps/index.md)
- [Artifacts](../../ci/yaml/index.md#artifacts)
-- [Specific runner](../../ci/runners/runners_scope.md#prevent-a-specific-runner-from-being-enabled-for-other-projects)
- [Merge request pipelines](../../ci/pipelines/merge_request_pipelines.md)
## Troubleshooting review apps
-### Review app returns a 404 error
+### `NoSuchKey The specified key does not exist`
-If the review app URL returns a 404 error, either the site is not
-yet deployed, or something went wrong with the remote pipeline. You can:
+If you see the following message in a review app, either the site is not
+yet deployed, or something went wrong with the downstream pipeline in `gitlab-docs`.
-- Wait a few minutes and it should appear online.
-- Check the manual job's log and verify the URL. If the URL is different, try the
- one from the job log.
-- Check the status of the remote pipeline from the link in the merge request's job output.
- If the pipeline failed or got stuck, GitLab team members can ask for help in the `#docs`
- chat channel. Contributors can ping a technical writer in the merge request.
-
-### Not enough disk space
-
-Sometimes the review app server is full and there is no more disk space. Each review
-app takes about 570MB of disk space.
+```plaintext
+NoSuchKeyThe specified key does not exist.No such object: <URL>
+```
-A cron job to remove review apps older than 20 days runs hourly,
-but the disk space still occasionally fills up. To manually free up more space,
-a GitLab technical writing team member can:
+In that case, you can:
-1. Navigate to the [`gitlab-docs` schedules page](https://gitlab.com/gitlab-org/gitlab-docs/-/pipeline_schedules).
-1. Select the play button for the `Remove old review apps from review app server`
- schedule. By default, this cleans up review apps older than 14 days.
-1. Navigate to the [pipelines page](https://gitlab.com/gitlab-org/gitlab-docs/-/pipelines)
- and start the manual job called `clean-pages`.
-
-If the job says no review apps were found in that period, edit the `CLEAN_REVIEW_APPS_DAYS`
-variable in the schedule, and repeat the process above. Gradually decrease the variable
-until the free disk space reaches an acceptable amount (for example, 3GB).
-Remember to set it to 14 again when you're done.
-
-There's an issue to [migrate from the DigitalOcean server to GCP buckets](https://gitlab.com/gitlab-org/gitlab-docs/-/issues/735)),
-which should solve the disk space problem.
+- Wait a few minutes and the review app should appear online.
+- Check the `review-docs-deploy` job's log and verify the URL. If the URL shown in the merge
+ request UI is different than the job log, try the one from the job log.
+- Check the status of the remote pipeline from the link in the merge request's job output.
+ If the pipeline failed or got stuck, GitLab team members can ask for help in the `#docs`
+ internal Slack channel. Contributors can ping a
+ [technical writer](https://about.gitlab.com/handbook/product/ux/technical-writing/#designated-technical-writers)
+ in the merge request.
diff --git a/doc/development/documentation/site_architecture/deployment_process.md b/doc/development/documentation/site_architecture/deployment_process.md
index b5c3a59b0eb..18cc27adaaa 100644
--- a/doc/development/documentation/site_architecture/deployment_process.md
+++ b/doc/development/documentation/site_architecture/deployment_process.md
@@ -6,6 +6,14 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Documentation deployments
+## Deployment environments
+
+The [GitLab documentation site](https://docs.gitlab.com/) is a static site hosted by [GitLab Pages](../../../user/project/pages/index.md). The deployment is done by the [Pages deploy job](#pages-deploy-job).
+
+The website hosts documentation only for the [currently supported](../../../policy/maintenance.md) GitLab versions. Documentation for older versions is built and uploaded as Docker images to be downloaded from [GitLab Docs archives](https://docs.gitlab.com/archives/).
+
+## Parts of release process
+
The documentation [release process](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/main/doc/releases.md)
involves:
@@ -24,10 +32,8 @@ For general information on using Docker with CI/CD pipelines, see [Docker integr
## Stable branches
-Stable branches for documentation include the relevant stable branches of all the projects required to publish the entire
-documentation suite. For example, the stable version of documentation for version `14.4` includes:
+Pipelines for stable branches in the documentation project pull the relevant stable branches of included projects. For example, the documentation for stable version `14.4` is built from the [`14.4`](https://gitlab.com/gitlab-org/gitlab-docs/-/tree/14.4) branch of the `gitlab-docs` project, which then includes:
-- The [`14.4`](https://gitlab.com/gitlab-org/gitlab-docs/-/tree/14.4) branch of the `gitlab-docs` project.
- The [`14-4-stable-ee`](https://gitlab.com/gitlab-org/gitlab/-/tree/14-4-stable-ee) branch of the `gitlab` project.
- The [`14-4-stable`](https://gitlab.com/gitlab-org/gitlab-runner/-/tree/14-4-stable) branch of the `gitlab-runner` project.
- The [`14-4-stable`](https://gitlab.com/gitlab-org/omnibus-gitlab/-/tree/14-4-stable) branch of the `omnibus-gitlab` project.
@@ -117,7 +123,7 @@ graph TD
G--"Latest `gitlab-docs:latest` image<br>pushed up"-->H
```
-## Documentation Pages deployment
+## Pages deploy job
[GitLab Docs](https://docs.gitlab.com) is a [Pages site](../../../user/project/pages/index.md) and documentation updates
for it must be deployed to become available.
@@ -176,7 +182,7 @@ Dockerfiles to build and deploy <https://docs.gitlab.com>. It is heavily inspire
Although build images are built automatically via GitLab CI/CD, you can build and tag all tooling images locally:
-1. Make sure you have [Docker installed](https://docs.docker.com/install/).
+1. Make sure you have [Docker installed](https://docs.docker.com/get-docker/).
1. Make sure you're in the `dockerfiles/` directory of the `gitlab-docs` repository.
1. Build the images:
diff --git a/doc/development/documentation/site_architecture/global_nav.md b/doc/development/documentation/site_architecture/global_nav.md
index 37d10b16fcd..d95ca720119 100644
--- a/doc/development/documentation/site_architecture/global_nav.md
+++ b/doc/development/documentation/site_architecture/global_nav.md
@@ -234,7 +234,7 @@ below the doc link:
external_url: true
```
-All nav links are clickable. If the higher-level link does not have a link
+All nav links are selectable. If the higher-level link does not have a link
of its own, it must link to its first sub-item link, mimicking the navigation in GitLab.
This must be avoided so that we don't have duplicated links nor two `.active` links
at the same time.
diff --git a/doc/development/documentation/styleguide/index.md b/doc/development/documentation/styleguide/index.md
index d629bc0b87e..ef934186981 100644
--- a/doc/development/documentation/styleguide/index.md
+++ b/doc/development/documentation/styleguide/index.md
@@ -18,11 +18,22 @@ In addition to this page, the following resources can help you craft and contrib
- [Recommended word list](word_list.md)
- [Doc style and consistency testing](../testing.md)
- [Guidelines for UI error messages](https://design.gitlab.com/content/error-messages/)
+- [Documentation global navigation](../site_architecture/global_nav.md)
- [GitLab Handbook style guidelines](https://about.gitlab.com/handbook/communication/#writing-style-guidelines)
- [Microsoft Style Guide](https://learn.microsoft.com/en-us/style-guide/welcome/)
- [Google Developer Documentation Style Guide](https://developers.google.com/style)
- [Recent updates to this guide](https://gitlab.com/dashboard/merge_requests?scope=all&state=merged&label_name[]=tw-style&not[label_name][]=docs%3A%3Afix)
+## The GitLab voice
+
+The GitLab brand guidelines define the
+[voice used by the larger organization](https://design.gitlab.com/brand/overview/#tone-of-voice).
+
+Building on that guidance, the voice in the GitLab documentation strives to be concise,
+direct, and precise. The goal is to provide information that's easy to search and scan.
+
+The voice in the documentation should be conversational but brief, friendly but succinct.
+
## Documentation is the single source of truth (SSOT)
The GitLab documentation is the SSOT for all
@@ -125,6 +136,23 @@ Maintaining a knowledge base separate from the documentation would
be against the documentation-first methodology, because the content would overlap with
the documentation.
+## Writing for localization
+
+The GitLab documentation is not localized, but we follow guidelines that
+help benefit translation. For example, we:
+
+- Write in [active voice](word_list.md#active-voice).
+- Write in [present tense](word_list.md#future-tense).
+- Avoid words that can be translated incorrectly, like:
+ - [since and because](word_list.md#since)
+ - [once and after](word_list.md#once)
+ - [it](word_list.md#it)
+- Avoid [ing](word_list.md#-ing-words) words.
+
+[The GitLab voice](#the-gitlab-voice) dictates that we write clearly and directly,
+and with translation in mind. [The word list](word_list.md) and our Vale rules
+also aid in consistency, which is important for localization.
+
## Markdown
All GitLab documentation is written using [Markdown](https://en.wikipedia.org/wiki/Markdown).
@@ -143,26 +171,17 @@ Hard-coded HTML is valid, although it's discouraged from being used. HTML is per
- Special styling is required.
- Reviewed and approved by a technical writer.
-### Headings in Markdown
+### Heading levels in Markdown
Each documentation page begins with a level 1 heading (`#`). This becomes the `h1` element when
the page is rendered to HTML. There can be only **one** level 1 heading per page.
- For each subsection, increment the heading level. In other words, increment the number of `#` characters
- in front of the heading.
-- Avoid headings greater than `H5` (`#####`). If you need more than five heading levels, move the topics to a new page instead.
- Headings greater than `H5` do not display in the right sidebar navigation.
+ in front of the topic title.
+- Avoid heading levels greater than `H5` (`#####`). If you need more than five heading levels, move the topics to a new page instead.
+ Heading levels greater than `H5` do not display in the right sidebar navigation.
- Do not skip a level. For example: `##` > `####`.
-- Leave one blank line before and after the heading.
-
-When you change heading text, the anchor link changes. To avoid broken links:
-
-- Do not use step numbers in headings.
-- When possible, do not use words that might change in the future.
-
-Also, do not use links as part of heading text.
-
-See also [heading guidelines for specific topic types](../structure.md).
+- Leave one blank line before and after the topic title.
### Backticks in Markdown
@@ -221,9 +240,9 @@ GitLab documentation should be clear and easy to understand.
As a company, we tend toward lowercase.
-#### Headings
+#### Topic titles
-Use sentence case. For example:
+Use sentence case for topic titles. For example:
- `# Use variables to configure pipelines`
- `## Use the To-Do List`
@@ -329,7 +348,7 @@ Some contractions, however, should be avoided:
### Acronyms
If you use an acronym, spell it out on first use on a page. You do not need to spell it out more than once on a page.
-When possible, try to avoid acronyms in headings.
+When possible, try to avoid acronyms in topic titles.
### Numbers
@@ -374,22 +393,31 @@ You can use italics when you are introducing a term for the first time. Otherwis
### Punctuation
-Follow these guidelines for punctuation:
+Follow these guidelines for punctuation.
<!-- vale gitlab.Repetition = NO -->
- End full sentences with a period.
-- Use one space between sentences.
-- Do not use semicolons. Use two sentences instead.
-- Do not use double spaces. (Tested in [`SentenceSpacing.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/SentenceSpacing.yml).)
-- Do not use non-breaking spaces. Use standard spaces instead. (Tested in [`lint-doc.sh`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/scripts/lint-doc.sh).)
-- Do not use tabs for indentation. Use spaces instead. You can configure your code editor to output spaces instead of tabs when pressing the tab key.
- Use serial (Oxford) commas before the final **and** or **or** in a list of three or more items. (Tested in [`OxfordComma.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/OxfordComma.yml).)
-- Avoid dashes. Use separate sentences, or commas, instead.
-- Do not use typographer's ("curly") quotes. Use straight quotes instead. (Tested in [`NonStandardQuotes.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/NonStandardQuotes.yml).)
<!-- vale gitlab.Repetition = YES -->
+When spacing content:
+
+- Use one space between sentences. (Use of more than one space is tested in [`SentenceSpacing.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/SentenceSpacing.yml).)
+- Do not use non-breaking spaces. Use standard spaces instead. (Tested in [`lint-doc.sh`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/scripts/lint-doc.sh).)
+- Do not use tabs for indentation. Use spaces instead. You can configure your code editor to output spaces instead of tabs when pressing the <kbd>Tab</kbd> key.
+
+<!-- vale gitlab.NonStandardQuotes = NO -->
+
+Do not use these punctuation characters:
+
+- `;` (semicolon): Use two sentences instead.
+- `–` (en dash) or `—` (em dash): Use separate sentences, or commas, instead.
+- `“` `â€` `‘` `’`: Double or single typographer's ("curly") quotation marks. Use straight quotes instead. (Tested in [`NonStandardQuotes.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/NonStandardQuotes.yml).)
+
+<!-- vale gitlab.NonStandardQuotes = YES -->
+
### Placeholder text
You might want to provide a command or configuration that
@@ -677,22 +705,27 @@ use a URL like `https://docs.gitlab.com/charts/`.
### Anchor links
-Each heading has an anchor link. For example, a topic with the title
+Each topic title has an anchor link. For example, a topic with the title
`## This is an example` has the anchor `#this-is-an-example`.
-The first topic on a page (the `h1`) has an anchor link,
+The first topic title on a page (the `h1`) has an anchor link,
but do not use it. Link to the page instead.
-If a heading has a [product tier badge](#product-tier-badges),
-do not include it in the anchor link. For example, for the heading
+If a topic title has a [product tier badge](#product-tier-badges),
+do not include it in the anchor link. For example, for the topic
`## This is an example **(FREE)**`, use the anchor `#this-is-an-example`.
With Kramdown, you can add a custom ID to an HTML element, but these IDs
don't work in `/help`, so you should not use them.
+When you change topic title text, the anchor link changes. To avoid broken links:
+
+- Do not use step numbers in topic titles.
+- When possible, do not use words that might change in the future.
+
#### Changing links and titles
-When you change a heading, the anchor link changes. To ensure you update
+When you change a topic title, the anchor link changes. To ensure you update
any related links, search these directories:
- `doc/*`
@@ -823,7 +856,7 @@ To open either project or group settings:
```markdown
1. On the top bar, select **Main menu**, and:
- - For a project, select ***Projects** and find your project.
+ - 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 > CI/CD**.
1. Expand **General pipelines**.
@@ -1195,7 +1228,7 @@ Instead of adding a note:
- Re-write the sentence as part of a paragraph.
- Put the information into its own paragraph.
-- Put the content under a new subheading.
+- Put the content under a new topic title.
If you must use a note, use this format:
@@ -1311,6 +1344,7 @@ It renders on the GitLab documentation site as:
> - Second item in the list
## Tabs
+<!-- markdownlint-disable tabs-blank-lines -->
On the docs site, you can format text so it's displayed as tabs.
@@ -1329,6 +1363,7 @@ Here's some other content in tab two.
::EndTabs
```
+<!-- markdownlint-enable tabs-blank-lines -->
This code renders on the GitLab documentation site as:
@@ -1378,25 +1413,25 @@ When names change, it is more complicated to search or grep text that has line b
### Product tier badges
-Tier badges are displayed as orange text next to a heading. These badges link to the GitLab
+Tier badges are displayed as orange text next to a topic title. These badges link to the GitLab
pricing page. For example:
![Tier badge](img/tier_badge.png)
You must assign a tier badge:
-- To all H1 topic headings, except the pages under `doc/development/*`.
-- To topic headings that don't apply to the same tier as the H1.
+- To all H1 topic titles, except the pages under `doc/development/*`.
+- To topic titles that don't apply to the same tier as the H1.
-To add a tier badge to a heading, add the relevant tier badge
-after the heading text. For example:
+To add a tier badge to a topic title, add the relevant tier badge
+after the title text. For example:
```markdown
-# Heading title **(FREE)**
+# Topic title **(FREE)**
```
Do not add tier badges inline with other text, except for [API attributes](../restful_api_styleguide.md).
-The single source of truth for a feature should be the heading where the
+The single source of truth for a feature should be the topic where the
functionality is described.
#### Available product tier badges
diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md
index 65ad8dea688..d28972a644b 100644
--- a/doc/development/documentation/styleguide/word_list.md
+++ b/doc/development/documentation/styleguide/word_list.md
@@ -35,7 +35,7 @@ Don't use backticks.
## 2FA, two-factor authentication
-Spell out **two-factor authentication** in sentence case for the first use and in section headings, and **2FA**
+Spell out **two-factor authentication** in sentence case for the first use and in topic titles, and **2FA**
thereafter. If the first word in a sentence, do not capitalize `factor` or `authentication`. For example:
- Two-factor authentication (2FA) helps secure your account. Set up 2FA when you first log in.
@@ -64,6 +64,23 @@ When you create a user, you choose an access level: **Regular**, **Auditor**, or
Capitalize these words when you refer to the UI. Otherwise use lowercase.
+## active voice
+
+Use active voice instead of passive.
+
+Use:
+
+- The contributor writes the documentation.
+
+Instead of:
+
+- The documentation is written by contributors.
+
+NOTE:
+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.
+
## administrator
Use **administrator access** instead of **admin** when talking about a user's access level.
@@ -460,6 +477,10 @@ Do not use **foo** in product documentation. You can use it in our API and contr
When possible, use present tense instead of future tense. For example, use **after you execute this command, GitLab displays the result** instead of **after you execute this command, GitLab will display the result**. ([Vale](../testing.md#vale) rule: [`FutureTense.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/FutureTense.yml))
+## GB, gigabytes
+
+For **GB** and **MB**, follow the [Microsoft guidance](https://learn.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/term-collections/bits-bytes-terms).
+
## Geo
Use title case for **Geo**.
@@ -570,6 +591,15 @@ Do not use Latin abbreviations. Use **that is** instead. ([Vale](../testing.md#v
Do not use **in order to**. Use **to** instead. ([Vale](../testing.md#vale) rule: [`Wordy.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/Wordy.yml))
+## -ing words
+
+Remove **-ing** words whenever possible. They can be difficult to translate,
+and more precise terms are usually available. For example:
+
+- Instead of **The files using storage are deleted**, use **The files that use storage are deleted**.
+- Instead of **Delete files using the Edit button**, use **Delete files by using the Edit button**.
+- Instead of **Replicating your server is required**, use **You must replicate your server**.
+
## issue
Use lowercase for **issue**.
@@ -582,6 +612,21 @@ Use lowercase for **issue board**.
Use lowercase for **issue weights**.
+## it
+
+When you use the word **it**, ensure the word it refers to is obvious.
+If it's not obvious, repeat the word rather than using **it**.
+
+Use:
+
+- The field returns a connection. The field accepts four arguments.
+
+Instead of:
+
+- The field returns a connection. It accepts four arguments.
+
+See also [this, these, that, those](#this-these-that-those).
+
## job
Do not use **build** to be synonymous with **job**. A job is defined in the `.gitlab-ci.yml` file and runs as part of a pipeline.
@@ -692,6 +737,10 @@ Do not use `master`. Use `main` when you need a sample [default branch name](#de
**Might** means something has the probability of occurring. **May** gives permission to do something. Consider **can** instead of **may**.
+## MB, megabytes
+
+For **MB** and **GB**, follow the [Microsoft guidance](https://learn.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/term-collections/bits-bytes-terms).
+
## me, myself, mine
Do not use first-person singular. Use **you**, **we**, or **us** instead. ([Vale](../testing.md#vale) rule: [`FirstPerson.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/FirstPerson.yml))
@@ -720,24 +769,18 @@ Do not use **navigate**. Use **go** instead. For example:
## need to, should
-Try to avoid **needs to**, because it's wordy. Avoid **should** when you can be more specific. If something is required, use **must**.
+Try to avoid **needs to**, because it's wordy. If something is recommended, use **should** instead. If something is required, use **must**.
Use:
-- You must set the variable.
-- Set the variable.
+- You should set the variable. (recommended)
+- You must set the variable. (required)
+- Set the variable. (required)
Instead of:
- You need to set the variable.
-
-**Should** is acceptable for recommended actions or items, or in cases where an event may not
-happen. For example:
-
-- Although you can configure the installation manually, you should use the express configuration to
- avoid complications.
-- You should see a success message in the console. Contact support if an error message appears
- instead.
+- We recommend that you set the variable.
## note that
@@ -811,7 +854,7 @@ When writing about the Owner role:
- Instead of: if you are an owner
Do not use bold.
-
+
Do not use **Owner permissions**. A user who is assigned the Owner role has a set of associated permissions.
An Owner is the highest role a user can have.
@@ -893,6 +936,10 @@ Instead of:
- Select **Create user** or **Save changes** if you created a new user or
edited an existing one respectively.
+## review app
+
+Use lowercase for **review app**.
+
## roles
Do not use **roles** and [**permissions**](#permissions) interchangeably. Each user is assigned a role. Each role includes a set of permissions.
@@ -981,7 +1028,11 @@ Use **setup** as a noun, and **set up** as a verb. For example:
## sign in
-Use **sign in** instead of **sign on** or **log on** or **log in**. If the user interface has different words, use those.
+Use **sign in** or **sign in to**.
+
+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 **single sign-on**.
@@ -1108,6 +1159,14 @@ For example:
See also [**enter**](#enter).
+## units of measurement
+
+Use a space between the number and the unit of measurement. For example, **128 GB**.
+([Vale](../testing.md#vale) rule: [`Units.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/Units.yml))
+
+For other guidance, follow
+[the Microsoft style guidelines](https://learn.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/term-collections/bits-bytes-terms).
+
## update
Use **update** for installing a newer **patch** version of the software only. For example:
@@ -1173,7 +1232,26 @@ Instead of:
- We created a feature for you to add widgets.
-One exception: You can use **we recommend** instead of **it is recommended** or **GitLab recommends**. ([Vale](../testing.md#vale) rule: [`SubstitutionSuggestions.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/SubstitutionSuggestions.yml))
+([Vale](../testing.md#vale) rule: [`SubstitutionSuggestions.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/SubstitutionSuggestions.yml))
+
+## while
+
+Use **while** to refer only to something occurring in time. For example,
+**Leave the window open while the process runs.**
+
+Do not use **while** for comparison. For example, use:
+
+- Job 1 can run quickly. However, job 2 is more precise.
+
+Instead of:
+
+- While job 1 can run quickly, job 2 is more precise.
+
+For details, see the [Microsoft style guide](https://learn.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/w/while).
+
+## whilst
+
+Do not use **whilst**. Use [while](#while) instead. **While** is more succinct and easier for non-native English speakers to understand.
## whitelist
@@ -1203,5 +1281,19 @@ Instead of:
- Users can configure a pipeline.
+## you can
+
+When possible, start sentences with an active verb instead of **you can**.
+For example:
+
+- Use code review analytics to view merge request data.
+- Create a board to organize your team tasks.
+- Configure variables to restrict pushes to a repository.
+
+Use **you can** for optional actions. For example:
+
+- Use code review analytics to view metrics per merge request. You can also use the API.
+- Enter the name and value pairs. You can add up to 20 pairs per streaming destination.
+
<!-- vale on -->
<!-- markdownlint-enable -->
diff --git a/doc/development/documentation/testing.md b/doc/development/documentation/testing.md
index c801bb9f877..8b8f281d7c1 100644
--- a/doc/development/documentation/testing.md
+++ b/doc/development/documentation/testing.md
@@ -86,7 +86,7 @@ job, which runs two types of link checks. In both cases, links with destinations
that begin with `http` or `https` are considered external links, and skipped:
- `bundle exec nanoc check internal_links`: Tests links to internal pages.
-- `bundle exec nanoc check internal_anchors`: Tests links to subheadings (anchors) on internal pages.
+- `bundle exec nanoc check internal_anchors`: Tests links to topic title anchors on internal pages.
Failures from these tests are displayed at the end of the test results in the **Issues found!** area.
For example, failures in the `internal_anchors` test follow this format:
@@ -104,7 +104,7 @@ For example, failures in the `internal_anchors` test follow this format:
- **Destination**: The full path to the file not found by the test. To find the
file in the `gitlab` repository, replace `/tmp/gitlab-docs/public/ee` with `doc`, and `.html` with `.md`.
- **Link**: The actual link the script attempted to find.
-- **Anchor**: If present, the subheading (anchor) the script attempted to find.
+- **Anchor**: If present, the topic title anchor the script attempted to find.
Check for multiple instances of the same broken link on each page reporting an error.
Even if a specific broken link appears multiple times on a page, the test reports it only once.
diff --git a/doc/development/documentation/topic_types/concept.md b/doc/development/documentation/topic_types/concept.md
index dfd003b642d..7be6bef4fad 100644
--- a/doc/development/documentation/topic_types/concept.md
+++ b/doc/development/documentation/topic_types/concept.md
@@ -32,13 +32,13 @@ Remember, if you start to describe about another concept, stop yourself.
Each concept should be about one concept only.
```
-## Concept headings
+## Concept topic titles
-For the heading text, use a noun. For example, `Widgets` or `GDK dependency management`.
+For the title text, use a noun. For example, `Widgets` or `GDK dependency management`.
If a noun is ambiguous, you can add a gerund. For example, `Documenting versions` instead of `Versions`.
-Avoid these heading titles:
+Avoid these topic titles:
- `Overview` or `Introduction`. Instead, use a more specific
noun or phrase that someone would search for.
diff --git a/doc/development/documentation/topic_types/index.md b/doc/development/documentation/topic_types/index.md
index 8403fd26517..8e8c474ce3c 100644
--- a/doc/development/documentation/topic_types/index.md
+++ b/doc/development/documentation/topic_types/index.md
@@ -20,11 +20,10 @@ The acronym refers to the first letter of each topic type.
In general, each page in the GitLab documentation contains multiple topics.
Each topic on a page should be recognizable as a specific topic type.
-## Other topic types
+In addition to the four primary topic types, we also have a page type for
+[Tutorials](tutorial.md) and [Get started](#get-started).
-In addition to the four primary topic types, we have a few other types.
-
-### Related topics
+## Related topics
If inline links are not sufficient, you can create a topic called **Related topics**
and include an unordered list of related topics. This topic should be above the Troubleshooting section.
@@ -36,57 +35,7 @@ and include an unordered list of related topics. This topic should be above the
- [Trigger a pipeline manually](link-to-topic).
```
-### Tutorials
-
-A tutorial is page that contains an end-to-end walkthrough of a complex workflow or scenario.
-In general, you might consider using a tutorial when:
-
-- The workflow requires a number of sequential steps where each step consists
- of sub-steps.
-- The steps cover a variety of GitLab features or third-party tools.
-
-Tutorials are learning aids that complement our core documentation.
-They do not introduce new features.
-Always use the primary [topic types](#documentation-topic-types-ctrt) to document new features.
-
-Tutorials should be in this format:
-
-```markdown
-# Title (starts with "Tutorial:" followed by an active verb, like "Tutorial: Create a website")
-
-A paragraph that explains what the tutorial does, and the expected outcome.
-
-To create a website:
-
-1. [Do the first task](#do-the-first-task)
-1. [Do the second task](#do-the-second-task)
-
-Prerequisites (optional):
-
-- Thing 1
-- Thing 2
-- Thing 3
-
-## Do the first task
-
-To do step 1:
-
-1. First step.
-1. Another step.
-1. Another step.
-
-## Do the second task
-
-Before you begin, make sure you have [done the first task](#do-the-first-task).
-
-To do step 2:
-
-1. First step.
-1. Another step.
-1. Another step.
-```
-
-### Get started
+## Get started
A get started page is a set of steps to help a user get set up
quickly to use a single GitLab feature or tool.
@@ -110,21 +59,21 @@ consider using subsections for each distinct task.
In the left nav, use `Get started` as the text. On the page itself, spell out
the full name. For example, `Get started with application security`.
-### Topics and resources
+## Topics and resources
Some pages are solely a list of links to other documentation.
We do not encourage this page type. Lists of links can get out-of-date quickly
and offer little value to users, who prefer to search to find information.
-## Heading text guidelines
+## Topic text guidelines
-In general, for heading text:
+In general, for topic text:
- Be clear and direct. Make every word count.
- Use articles and prepositions.
- Follow [capitalization](../styleguide/index.md#capitalization) guidelines.
-- Do not repeat text from earlier headings. For example, if the page is about merge requests,
+- Do not repeat text from earlier topic titles. For example, if the page is about merge requests,
instead of `Troubleshooting merge requests`, use only `Troubleshooting`.
-See also [guidelines for headings in Markdown](../styleguide/index.md#headings-in-markdown).
+See also [guidelines for heading levels in Markdown](../styleguide/index.md#heading-levels-in-markdown).
diff --git a/doc/development/documentation/topic_types/reference.md b/doc/development/documentation/topic_types/reference.md
index e7ee8b20925..8bb89f4c210 100644
--- a/doc/development/documentation/topic_types/reference.md
+++ b/doc/development/documentation/topic_types/reference.md
@@ -19,11 +19,11 @@ Introductory sentence.
| **Name** | Descriptive sentence about the setting. |
```
-## Reference headings
+## Reference topic titles
-Reference headings are usually nouns.
+Reference topic titles are usually nouns.
-Avoid these heading titles:
+Avoid these topic titles:
- `Important notes`. Instead, incorporate this information
closer to where it belongs. For example, this information might be a prerequisite
diff --git a/doc/development/documentation/topic_types/task.md b/doc/development/documentation/topic_types/task.md
index 60508fbf6ee..78d670a16d6 100644
--- a/doc/development/documentation/topic_types/task.md
+++ b/doc/development/documentation/topic_types/task.md
@@ -52,14 +52,23 @@ To create an issue:
The issue is created. You can view it by going to **Issues > List**.
```
-## Task headings
+## Task topic titles
-For the heading text, use the structure `active verb` + `noun`.
+For the title text, use the structure `active verb` + `noun`.
For example, `Create an issue`.
If you have several tasks on a page that share prerequisites, you can use the title
`Prerequisites` and link to it.
+## Task introductions
+
+To start the task topic, use the structure `active verb` + `noun`, and
+provide context about the action.
+For example, `Create an issue when you want to track bugs or future work`.
+
+To start the task steps, use a succinct action followed by a colon.
+For example, `To create an issue:`
+
## Related topics
- [View the format for writing task steps](../styleguide/index.md#navigation).
diff --git a/doc/development/documentation/topic_types/troubleshooting.md b/doc/development/documentation/topic_types/troubleshooting.md
index e2136de2e06..70475eb0ccf 100644
--- a/doc/development/documentation/topic_types/troubleshooting.md
+++ b/doc/development/documentation/topic_types/troubleshooting.md
@@ -6,10 +6,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Troubleshooting topic type
-Troubleshooting topics should be the last topics on a page.
+Troubleshooting topics should be the final topics on a page.
If a page has more than five troubleshooting topics, put the content on a separate page that has troubleshooting information exclusively. Name the page `Troubleshooting <feature>`
-and in the left nav, use the word `Troubleshoot` only.
+and in the left nav, use the word `Troubleshooting` only.
Troubleshooting can be one of three types.
@@ -46,11 +46,22 @@ The workaround is...
If multiple causes or workarounds exist, consider putting them into a table format.
If you use the exact error message, surround it in backticks so it's styled as code.
-## Troubleshooting headings
+## Troubleshooting topic titles
-For the heading of a **Troubleshooting reference** topic:
+For the title of a **Troubleshooting reference** topic:
- Consider including at least a partial error message.
- Use fewer than 70 characters.
+- Do not use links in the title.
If you do not put the full error in the title, include it in the body text.
+
+## Rails console write functions
+
+If the troubleshooting suggestion includes a function that changes data on the GitLab instance,
+add the following warning:
+
+```markdown
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+```
diff --git a/doc/development/documentation/topic_types/tutorial.md b/doc/development/documentation/topic_types/tutorial.md
new file mode 100644
index 00000000000..1b1426a0465
--- /dev/null
+++ b/doc/development/documentation/topic_types/tutorial.md
@@ -0,0 +1,102 @@
+---
+stage: none
+group: Style Guide
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Tutorial page type
+
+A tutorial is page that contains an end-to-end walkthrough of a complex workflow or scenario.
+In general, you might consider using a tutorial when:
+
+- The workflow requires a number of sequential steps where each step consists
+ of sub-steps.
+- The steps cover a variety of GitLab features or third-party tools.
+
+Tutorials are learning aids that complement our core documentation.
+They do not introduce new features.
+Always use the primary [topic types](index.md) to document new features.
+
+## Tutorial format
+
+Tutorials should be in this format:
+
+```markdown
+# Title (starts with "Tutorial:" followed by an active verb, like "Tutorial: Create a website")
+
+A paragraph that explains what the tutorial does, and the expected outcome.
+
+To create a website:
+
+1. [Do the first task](#do-the-first-task)
+1. [Do the second task](#do-the-second-task)
+
+Prerequisites (optional):
+
+- Thing 1
+- Thing 2
+- Thing 3
+
+## Do the first task
+
+To do step 1:
+
+1. First step.
+1. Another step.
+1. Another step.
+
+## Do the second task
+
+Before you begin, make sure you have [done the first task](#do-the-first-task).
+
+To do step 2:
+
+1. First step.
+1. Another step.
+1. Another step.
+```
+
+An example of a tutorial that follows this format is
+[Tutorial: Make your first Git commit](../../../tutorials/make_your_first_git_commit.md).
+
+## Tutorial page title
+
+Start the page title with `Tutorial:` followed by an active verb, like `Tutorial: Create a website`.
+
+In the left nav, use the full page title. Do not abbreviate it.
+Put the text in quotes so the pipeline will pass. For example,
+`"Tutorial: Make your first Git commit"`.
+
+On [the **Learn GitLab with tutorials** page](../../../tutorials/index.md),
+do not use `Tutorial` in the title.
+
+## Screenshots
+
+You can include screenshots in a tutorial to illustrate important steps in the process.
+In the core product documentation, you should [use screenshots sparingly](../styleguide/index.md#images).
+However, in tutorials, screenshots can help users understand where they are in a complex process.
+
+Try to balance the number of screenshots in the tutorial so they don't disrupt
+the narrative flow. For example, do not put one large screenshot in the middle of the tutorial.
+Instead, put multiple, smaller screenshots throughout.
+
+## Tutorial voice
+
+Use a friendlier tone than you would for other topic types. For example,
+you can:
+
+- Add encouraging or congratulatory phrases after tasks.
+- Use future tense from time to time, especially when you're introducing
+ steps. For example, `Next, you will associate your issues with your epics`.
+- Be more conversational. For example, `This task might take a while to complete`.
+
+## Metadata
+
+On pages that are tutorials, add the most appropriate `stage:` and `group:` metadata at the top of the file.
+If the majority of the content does not align with a single group, specify `none` for the stage
+and `Tutorials` for the group:
+
+```plaintext
+stage: none
+group: Tutorials
+```
diff --git a/doc/development/documentation/versions.md b/doc/development/documentation/versions.md
index 12381b84c2c..030bdec0361 100644
--- a/doc/development/documentation/versions.md
+++ b/doc/development/documentation/versions.md
@@ -31,7 +31,7 @@ You do not need to add version information on the pages in the `/development` di
### Add a **Version history** item
-If all content in a topic is related, add a version history item after the topic heading.
+If all content in a topic is related, add a version history item after the topic title.
For example:
```markdown
diff --git a/doc/development/documentation/workflow.md b/doc/development/documentation/workflow.md
index 85d3d5e9cfc..9d8d25607c8 100644
--- a/doc/development/documentation/workflow.md
+++ b/doc/development/documentation/workflow.md
@@ -153,7 +153,7 @@ 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 headings don't affect in-app hyperlinks.
+- 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:
diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md
index 2516196d2e0..14df73b8779 100644
--- a/doc/development/ee_features.md
+++ b/doc/development/ee_features.md
@@ -120,24 +120,32 @@ To do so:
### Simulate a SaaS instance
-If you're developing locally and need your instance to act like the SaaS version of the product,
-you can simulate SaaS by exporting an environment variable:
+If you're developing locally and need your instance to simulate the SaaS (GitLab.com)
+version of the product:
-```shell
-export GITLAB_SIMULATE_SAAS=1
-```
+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 a `env.runit` file in the root of your GDK with the above snippet.
+ 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.
-#### Allow use of licensed EE feature
+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.
-To enable plans per namespace turn on the `Allow use of licensed EE features` option from the settings page.
-This will make licensed EE features available to projects only if the project namespace's plan includes the feature
-or if the project is public. To enable it:
+ 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. If you are developing locally, follow the steps in [Simulate a SaaS instance](#simulate-a-saas-instance) to make the option available.
-1. Visit Admin > Settings > General > "Account and limit" and enable "Allow use of licensed EE features".
+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
@@ -147,7 +155,7 @@ FOSS context as well.
To run pipelines in both contexts, add the `~"pipeline:run-as-if-foss"` label to the merge request.
-See the [As-if-FOSS jobs](pipelines.md#as-if-foss-jobs) pipelines documentation for more information.
+See the [As-if-FOSS jobs](pipelines/index.md#as-if-foss-jobs) pipelines documentation for more information.
## Separation of EE code in the backend
@@ -692,7 +700,7 @@ module EE
prepended do
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: ::API::API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
# ...
diff --git a/doc/development/event_store.md b/doc/development/event_store.md
index b9200d3be25..10dc0b1a7a9 100644
--- a/doc/development/event_store.md
+++ b/doc/development/event_store.md
@@ -351,6 +351,12 @@ RSpec.describe MergeRequests::UpdateHeadPipelineWorker do
let(:event) { pipeline_created_event }
end
+ # This shared example ensures that an published event is ignored. This might be useful for
+ # conditional dispatch testing.
+ it_behaves_like 'ignores the published event' do
+ let(:event) { pipeline_created_event }
+ end
+
it 'does something' do
# This helper directly executes `perform` ensuring that `handle_event` is called correctly.
consume_event(subscriber: described_class, event: pipeline_created_event)
diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md
index 9ed3e551ff2..28ea84301a6 100644
--- a/doc/development/fe_guide/graphql.md
+++ b/doc/development/fe_guide/graphql.md
@@ -907,7 +907,7 @@ For example, we have a query like this:
query searchGroupsWhereUserCanTransfer {
currentUser {
id
- groups {
+ groups(after: 'somecursor') {
nodes {
id
fullName
@@ -920,9 +920,7 @@ query searchGroupsWhereUserCanTransfer {
}
```
-Here, the `groups` field doesn't have a good candidate for `keyArgs`: both
-`nodes` and `pageInfo` will be updated when we're fetching a second page.
-Setting `keyArgs` to `false` makes the update work as intended:
+Here, the `groups` field doesn't have a good candidate for `keyArgs`: we don't want to account for `after` argument because it will change on requesting subsequent pages. Setting `keyArgs` to `false` makes the update work as intended:
```javascript
typePolicies: {
diff --git a/doc/development/fe_guide/merge_request_widget_extensions.md b/doc/development/fe_guide/merge_request_widget_extensions.md
index e5e813bf921..61d3e79a080 100644
--- a/doc/development/fe_guide/merge_request_widget_extensions.md
+++ b/doc/development/fe_guide/merge_request_widget_extensions.md
@@ -85,7 +85,7 @@ special formatting is required. When the extension receives this data,
it is set to `collapsedData`. You can access `collapsedData` in any computed property or
method.
-When the user clicks **Expand**, the `fetchFullData` method is called. This method
+When the user selects **Expand**, the `fetchFullData` method is called. This method
also gets called with the props as an argument. This method **must** also return
the full data. However, this data must be correctly formatted to match the format
mentioned in the data structure section.
diff --git a/doc/development/fe_guide/registry_architecture.md b/doc/development/fe_guide/registry_architecture.md
index a87d38634d5..d86f8416db6 100644
--- a/doc/development/fe_guide/registry_architecture.md
+++ b/doc/development/fe_guide/registry_architecture.md
@@ -71,7 +71,7 @@ main pieces of the desired UI and UX of a registry page. The most important comp
secondary content, right primary and secondary content, right action, and details slots.
- `metadata-item`: represents one piece of metadata, with an icon or a link. Used primarily in the
title area.
-- `persisted-dropdown-selection`: represents a dropdown menu that stores the user selection in the
+- `persisted-dropdown-selection`: represents a menu that stores the user selection in the
`localStorage`.
- `registry-search`: implements `gl-filtered-search` with a sorting section on the right.
- `title-area`: implements the top title area of the registry. Includes: a main title, an avatar, a
diff --git a/doc/development/fe_guide/style/scss.md b/doc/development/fe_guide/style/scss.md
index aacf07fda92..98f74813231 100644
--- a/doc/development/fe_guide/style/scss.md
+++ b/doc/development/fe_guide/style/scss.md
@@ -176,7 +176,7 @@ To check if any warnings are produced by your changes, run `yarn lint:stylelint`
catch any warnings.
If the Rake task is throwing warnings you don't understand, SCSS Lint's
-documentation includes [a full list of their rules](https://stylelint.io/user-guide/rules/list/).
+documentation includes [a full list of their rules](https://stylelint.io/user-guide/rules/).
### Fixing issues
diff --git a/doc/development/fe_guide/view_component.md b/doc/development/fe_guide/view_component.md
index 662d1ad32fc..b61c23cadef 100644
--- a/doc/development/fe_guide/view_component.md
+++ b/doc/development/fe_guide/view_component.md
@@ -15,7 +15,7 @@ watch this [introduction video](https://youtu.be/akRhUbvtnmo).
## Browse components with Lookbook
-We have a [Lookbook](https://github.com/allmarkedup/lookbook) in [http://gdk.test:3000/rails/lookbook](http://gdk.test:3000/rails/lookbook) (only available in development mode) to browse and interact with ViewComponent previews.
+We have a [Lookbook](https://github.com/allmarkedup/lookbook) in `http://gdk.test:3000/rails/lookbook` (only available in development mode) to browse and interact with ViewComponent previews.
## Pajamas components
@@ -24,12 +24,12 @@ available as a ViewComponent in `app/components/pajamas`.
NOTE:
We are still in the process of creating these components, so not every Pajamas component is available as ViewComponent.
-Reach out to the [Foundations team](https://about.gitlab.com/handbook/engineering/development/dev/ecosystem/foundations/)
+Reach out to the [Foundations team](https://about.gitlab.com/handbook/engineering/development/dev/manage/foundations/)
if the component you are looking for is not yet available.
### Available components
-Consider this list a best effort. The full list can be found in [`app/components/pajamas`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/app/components/pajamas). Also see [our Lookbook](http://gdk.test:3000/rails/lookbook) for a more interactive way to browse our components.
+Consider this list a best effort. The full list can be found in [`app/components/pajamas`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/app/components/pajamas). Also see our Lookbook (`http://gdk.test:3000/rails/lookbook`) for a more interactive way to browse our components.
#### Alert
@@ -155,7 +155,7 @@ For the full list of options, see its
#### Checkbox tag
-The `Pajamas::CheckboxTagComponent` follows the [Pajamas Checkbox](https://design.gitlab.com/components/checkbox) specification.
+The `Pajamas::CheckboxTagComponent` follows the [Pajamas Checkbox](https://design.gitlab.com/components/checkbox/) specification.
The `name` argument and `label` slot are required.
@@ -176,7 +176,7 @@ For the full list of options, see its
#### Checkbox
-The `Pajamas::CheckboxComponent` follows the [Pajamas Checkbox](https://design.gitlab.com/components/checkbox) specification.
+The `Pajamas::CheckboxComponent` follows the [Pajamas Checkbox](https://design.gitlab.com/components/checkbox/) specification.
NOTE:
`Pajamas::CheckboxComponent` is used internally by the [GitLab UI form builder](haml.md#use-the-gitlab-ui-form-builder) and requires an instance of [ActionView::Helpers::FormBuilder](https://api.rubyonrails.org/v6.1.0/classes/ActionView/Helpers/FormBuilder.html) to be passed as the `form` argument.
diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md
index 00d9588d087..779010b8aa1 100644
--- a/doc/development/fe_guide/vue.md
+++ b/doc/development/fe_guide/vue.md
@@ -65,6 +65,9 @@ To do that, you can use the `data` attributes in the HTML element and query them
You should only do this while initializing the application, because the mounted element is replaced
with a Vue-generated DOM.
+The `data` attributes are [only able to accept String values](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes#javascript_access),
+so you will need to cast or convert other variable types to String.
+
The advantage of providing data from the DOM to the Vue instance through `props` or
`provide` in the `render` function, instead of querying the DOM inside the main Vue
component, is that you avoid creating a fixture or an HTML element in the unit test.
diff --git a/doc/development/fe_guide/vue3_migration.md b/doc/development/fe_guide/vue3_migration.md
index c3ce42a80a5..aae7674d190 100644
--- a/doc/development/fe_guide/vue3_migration.md
+++ b/doc/development/fe_guide/vue3_migration.md
@@ -159,3 +159,232 @@ export default {
[In Vue 3](https://v3-migration.vuejs.org/breaking-changes/props-default-this.html),
the props default value factory is passed the raw props as an argument, and can
also access injections.
+
+## Handling libraries that do not work with `@vue/compat`
+
+**Problem**
+
+Some libraries rely on Vue.js 2 internals. They might not work with `@vue/compat`, so we need a strategy to use an updated version with Vue.js 3 while maintaining compatibility with the current codebase.
+
+**Goals**
+
+- We should add as few changes as possible to existing code to support new libraries. Instead, we should **add*- new code, which will act as **facade**, making the new version compatible with the old one
+- Switching between new and old versions should be hidden inside tooling (webpack / jest) and should not be exposed to the code
+- All facades specific to migration should live in the same directory to simplify future migration steps
+
+### Step-by-step migration
+
+In the step-by-step guide, we will be migrating [VueApollo Demo](https://gitlab.com/gitlab-org/frontend/vue3-migration-vue-apollo/-/tree/main/src/vue3compat) project. It will allow us to focus on migration specifics while avoiding nuances of complex tooling setup in the GitLab project. The project intentionally uses the same tooling as GitLab:
+
+- webpack
+- yarn
+- Vue.js + VueApollo
+
+#### Initial state
+
+Right after cloning, you could run [VueApollo Demo](https://gitlab.com/gitlab-org/frontend/vue3-migration-vue-apollo/-/tree/main/src/vue3compat) with Vue.js 2 using `yarn serve` or with Vue.js 3 (compat build) using `yarn serve:vue3`. However latter immediately crashes:
+
+```javascript
+Uncaught TypeError: Cannot read properties of undefined (reading 'loading')
+```
+
+VueApollo v3 (used for Vue.js 2) fails to initialize in Vue.js compat
+
+NOTE:
+While stubbing `Vue.version` will solve VueApollo-related issues in the demo project, it will still lose reactivity on specific scenarios, so an upgrade is still needed
+
+#### Step 1. Perform upgrade according to library docs
+
+According to [VueApollo v4 installation guide](https://v4.apollo.vuejs.org/guide/installation.html), we need to install `@vue/apollo-option` (this package provides VueApollo support for Options API) and make changes to our application:
+
+```diff
+--- a/src/index.js
++++ b/src/index.js
+@@ -1,19 +1,17 @@
+-import Vue from "vue";
+-import VueApollo from "vue-apollo";
++import { createApp, h } from "vue";
++import { createApolloProvider } from "@vue/apollo-option";
+
+ import Demo from "./components/Demo.vue";
+ import createDefaultClient from "./lib/graphql";
+
+-Vue.use(VueApollo);
+-
+-const apolloProvider = new VueApollo({
++const apolloProvider = createApolloProvider({
+ defaultClient: createDefaultClient(),
+ });
+
+-new Vue({
+- el: "#app",
+- apolloProvider,
+- render(h) {
++const app = createApp({
++ render() {
+ return h(Demo);
+ },
+ });
++app.use(apolloProvider);
++app.mount("#app");
+```
+
+You can view these changes in [01-upgrade-vue-apollo](https://gitlab.com/gitlab-org/frontend/vue3-migration-vue-apollo/-/compare/main...01-upgrade-vue-apollo) branch of demo project
+
+#### Step 2. Addressing differences in augmenting applications in Vue.js 2 and 3
+
+In Vue.js 2 tooling like `VueApollo` is initialized in a "lazy" fashion:
+
+```javascript
+// We are registering VueApollo "handler" to handle some data LATER
+Vue.use(VueApollo)
+// ...
+// apolloProvider is provided at app instantiation,
+// previously registered VueApollo will handle that
+new Vue({ /- ... */, apolloProvider })
+```
+
+In Vue.js 3 both steps were merged in one - we are immediately registering the handler and passing configuration:
+
+```javascript
+app.use(apolloProvider)
+```
+
+In order to backport this behavior, we need the following knowledge:
+
+- We can access extra options provided to Vue instance via `$options`, so extra `apolloProvider` will be visible as `this.$options.apolloProvider`
+- We can access the current `app` (in Vue.js 3 meaning) on the Vue instance via `this.$.appContext.app`
+
+NOTE:
+We're relying on non-public Vue.js 3 API in this case. However, since `@vue/compat` builds are expected to be available only for 3.2.x branch, we have reduced risks that this API will be changed
+
+With this knowledge, we can move the initialization of our tooling as early as possible in Vue2 - in the `beforeCreate()` lifecycle hook:
+
+```diff
+--- a/src/index.js
++++ b/src/index.js
+@@ -1,4 +1,4 @@
+-import { createApp, h } from "vue";
++import Vue from "vue";
+ import { createApolloProvider } from "@vue/apollo-option";
+
+ import Demo from "./components/Demo.vue";
+@@ -8,10 +8,13 @@ const apolloProvider = createApolloProvider({
+ defaultClient: createDefaultClient(),
+ });
+
+-const app = createApp({
+- render() {
++new Vue({
++ el: "#app",
++ apolloProvider,
++ render(h) {
+ return h(Demo);
+ },
++ beforeCreate() {
++ this.$.appContext.app.use(this.$options.apolloProvider);
++ },
+ });
+-app.use(apolloProvider);
+-app.mount("#app");
+```
+
+You can view these changes in [02-bring-back-new-vue](https://gitlab.com/gitlab-org/frontend/vue3-migration-vue-apollo/-/compare/01-upgrade-vue-apollo...02-bring-back-new-vue) branch of demo project
+
+#### Step 3. Recreating `VueApollo` class
+
+Vue.js 3 libraries (and Vue.js itself) have a preference for using factories like `createApp` instead of classes (previously `new Vue`)
+
+`VueApollo` class served two purposes:
+
+- constructor for creating `apolloProvider`
+- installation of apollo-related logic in components
+
+We can utilize `Vue.use(VueApollo)` code, which existed in our codebase, to hide there our mixin and avoid modification of our app code:
+
+```diff
+--- a/src/index.js
++++ b/src/index.js
+@@ -4,7 +4,26 @@ import { createApolloProvider } from "@vue/apollo-option";
+ import Demo from "./components/Demo.vue";
+ import createDefaultClient from "./lib/graphql";
+
+-const apolloProvider = createApolloProvider({
++class VueApollo {
++ constructor(...args) {
++ return createApolloProvider(...args);
++ }
++
++ // called by Vue.use
++ static install() {
++ Vue.mixin({
++ beforeCreate() {
++ if (this.$options.apolloProvider) {
++ this.$.appContext.app.use(this.$options.apolloProvider);
++ }
++ },
++ });
++ }
++}
++
++Vue.use(VueApollo);
++
++const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+ });
+
+@@ -14,7 +33,4 @@ new Vue({
+ render(h) {
+ return h(Demo);
+ },
+- beforeCreate() {
+- this.$.appContext.app.use(this.$options.apolloProvider);
+- },
+ });
+```
+
+You can view these changes in [03-recreate-vue-apollo](https://gitlab.com/gitlab-org/frontend/vue3-migration-vue-apollo/-/compare/02-bring-back-new-vue...03-recreate-vue-apollo) branch of demo project
+
+#### Step 4. Moving `VueApollo` class to a separate file and setting up an alias
+
+Now, we have almost the same code (excluding import) as in Vue.js 2 version.
+We will move our facade to the separate file and set up `webpack` conditionally execute it if `vue-apollo` is imported when using Vue.js 3:
+
+```diff
+--- a/src/index.js
++++ b/src/index.js
+@@ -1,5 +1,5 @@
+ import Vue from "vue";
+-import { createApolloProvider } from "@vue/apollo-option";
++import VueApollo from "vue-apollo";
+
+ import Demo from "./components/Demo.vue";
+ import createDefaultClient from "./lib/graphql";
+diff --git a/webpack.config.js b/webpack.config.js
+index 6160d3f..b8b955f 100644
+--- a/webpack.config.js
++++ b/webpack.config.js
+@@ -12,6 +12,7 @@ if (USE_VUE3) {
+
+ VUE3_ALIASES = {
+ vue: "@vue/compat",
++ "vue-apollo": path.resolve("src/vue3compat/vue-apollo"),
+ };
+ }
+```
+
+(moving `VueApollo` class from `index.js` to `vue3compat/vue-apollo.js` as default export is omitted for clarity)
+
+You can view these changes in [04-add-webpack-alias](https://gitlab.com/gitlab-org/frontend/vue3-migration-vue-apollo/-/compare/03-recreate-vue-apollo...04-add-webpack-alias) branch of demo project
+
+#### Step 5. Observe the results
+
+At this point, you should be able again to run **both*- Vue.js 2 version with `yarn serve` and Vue.js 3 one with `yarn serve:vue3`
+[Final MR](https://gitlab.com/gitlab-org/frontend/vue3-migration-vue-apollo/-/merge_requests/1/diffs) with all changes from previous steps displays no changes to `index.js` (application code), which was our goal
+
+### Applying this approach in the GitLab project
+
+In [commit adding VueApollo v4 support](https://gitlab.com/gitlab-org/gitlab/-/commit/e0af7e6479695a28a4fe85a88f90815aa3ce2814) we can see additional nuances not covered by step-by-step guide:
+
+- We might need to add additional imports to our facades (our code in GitLab uses `ApolloMutation` component)
+- We need to update aliases not only for webpack but also for jest so our tests could also consume our facade
diff --git a/doc/development/fe_guide/vuex.md b/doc/development/fe_guide/vuex.md
index 5047f1b7f89..19bbfa314ea 100644
--- a/doc/development/fe_guide/vuex.md
+++ b/doc/development/fe_guide/vuex.md
@@ -22,7 +22,7 @@ official [Vuex documentation](https://vuex.vuejs.org).
Vuex is composed of State, Getters, Mutations, Actions, and Modules.
-When a user clicks on an action, we need to `dispatch` it. This action `commits` a mutation that changes the state. The action itself does not update the state; only a mutation should update the state.
+When a user selects an action, we need to `dispatch` it. This action `commits` a mutation that changes the state. The action itself does not update the state; only a mutation should update the state.
## File structure
diff --git a/doc/development/feature_development.md b/doc/development/feature_development.md
index 760ba033633..76447124177 100644
--- a/doc/development/feature_development.md
+++ b/doc/development/feature_development.md
@@ -197,6 +197,7 @@ The following integration guides are internal. Some integrations require access
- [Preventing transient bugs](transient/prevention-patterns.md)
- [GitLab Application SLIs](application_slis/index.md)
- [Spam protection and CAPTCHA development guide](spam_protection_and_captcha/index.md)
+- [RuboCop development guide](rubocop_development_guide.md)
## Other GitLab Development Kit (GDK) guides
diff --git a/doc/development/feature_flags/controls.md b/doc/development/feature_flags/controls.md
index e6c3c20d50b..e804a888e98 100644
--- a/doc/development/feature_flags/controls.md
+++ b/doc/development/feature_flags/controls.md
@@ -16,7 +16,7 @@ To turn on/off features behind feature flags in any of the
GitLab-provided environments, like staging and production, you need to
have access to the [ChatOps](../chatops_on_gitlabcom.md) bot. The ChatOps bot
is currently running on the ops instance, which is different from
-[GitLab.com](https://gitlab.com) or [`dev.gitlab.org`](https://dev.gitlab.org).
+[GitLab.com](https://gitlab.com) or `dev.gitlab.org`.
Follow the ChatOps document to [request access](../chatops_on_gitlabcom.md#requesting-access).
@@ -55,8 +55,8 @@ change feature flags or you do not have access.
### Enabling a feature for pre-production testing
As a first step in a feature rollout, you should enable the feature on
-[`staging.gitlab.com`](https://staging.gitlab.com)
-and [`dev.gitlab.org`](https://dev.gitlab.org).
+`staging.gitlab.com`
+and `dev.gitlab.org`.
These two environments have different scopes.
`dev.gitlab.org` is a production CE environment that has internal GitLab Inc.
diff --git a/doc/development/feature_flags/index.md b/doc/development/feature_flags/index.md
index f1cde4ae1ea..500afa8ba1d 100644
--- a/doc/development/feature_flags/index.md
+++ b/doc/development/feature_flags/index.md
@@ -435,7 +435,7 @@ For example, the following feature flags are enabled for a certain percentage of
If a project A has `:feature-set-1` enabled, there is no guarantee that project A also has `:feature-set-2` enabled.
-For more detail, see [This is how percentages work in Flipper](https://www.hackwithpassion.com/this-is-how-percentages-work-in-flipper).
+For more detail, see [This is how percentages work in Flipper](https://www.hackwithpassion.com/this-is-how-percentages-work-in-flipper/).
#### Use actors for verifying in production
diff --git a/doc/development/fips_compliance.md b/doc/development/fips_compliance.md
index 475c1a49000..c6208d45c77 100644
--- a/doc/development/fips_compliance.md
+++ b/doc/development/fips_compliance.md
@@ -67,7 +67,7 @@ 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.
Additionally, these package repositories are disabled in FIPS mode:
@@ -203,7 +203,7 @@ This [GitHub pull request](https://github.com/awslabs/amazon-eks-ami/pull/898) m
it possible to create an Amazon Linux 2 EKS AMI with FIPS enabled for Kubernetes v1.21.
To build an image:
-1. [Install Packer](https://learn.hashicorp.com/tutorials/packer/get-started-install-cli).
+1. [Install Packer](https://developer.hashicorp.com/packer/tutorials/docker-get-started/get-started-install-cli).
1. Run the following:
```shell
diff --git a/doc/development/gemfile.md b/doc/development/gemfile.md
index 7d3531afb49..3c7dc19da8e 100644
--- a/doc/development/gemfile.md
+++ b/doc/development/gemfile.md
@@ -66,7 +66,7 @@ This means that new dependencies should, at a minimum, meet the following criter
When adding a new gem to our `Gemfile` or even changing versions in
`Gemfile.lock` it is strongly recommended that you
-[request a Security review](https://about.gitlab.com/handbook/engineering/security/#how-to-request-a-security-review).
+[request a Security review](https://about.gitlab.com/handbook/security/#how-to-request-a-security-review).
New gems add an extra security risk for GitLab, and it is important to
evaluate this risk before we ship this to production. Technically, just adding
a new gem and pushing to a branch in our main `gitlab` project is a security
diff --git a/doc/development/github_importer.md b/doc/development/github_importer.md
index 9ba375439f4..edf78d5f83d 100644
--- a/doc/development/github_importer.md
+++ b/doc/development/github_importer.md
@@ -78,14 +78,21 @@ individually to import this information. A
`Gitlab::GithubImport::ImportPullRequestMergedByWorker` job is scheduled for each fetched pull
request.
-### 6. Stage::ImportPullRequestsReviewsWorker
+### 6. Stage::ImportPullRequestsReviewRequestsWorker
-This worker imports the pull requests' reviews. For each pull request, this worker:
+This worker imports assigned reviewers of pull requests. For each pull request, this worker:
+
+- Fetches all assigned review requests.
+- Schedules a `Gitlab::GithubImport::PullRequests::ImportReviewRequestWorker` job for each fetched review request.
+
+### 7. Stage::ImportPullRequestsReviewsWorker
+
+This worker imports reviews of pull requests. For each pull request, this worker:
- Fetches all the pages of reviews.
- Schedules a `Gitlab::GithubImport::ImportPullRequestReviewWorker` job for each fetched review.
-### 7. Stage::ImportIssuesAndDiffNotesWorker
+### 8. Stage::ImportIssuesAndDiffNotesWorker
This worker imports all issues and pull request comments. For every issue, we
schedule a job for the `Gitlab::GithubImport::ImportIssueWorker` worker. For
@@ -101,7 +108,7 @@ label links in the same worker removes the need for performing a separate crawl
through the API data, reducing the number of API calls necessary to import a
project.
-### 8. Stage::ImportIssueEventsWorker
+### 9. Stage::ImportIssueEventsWorker
This worker imports all issues and pull request events. For every event, we
schedule a job for the `Gitlab::GithubImport::ImportIssueEventWorker` worker.
@@ -117,7 +124,7 @@ Therefore, both issues and pull requests have a common API for most related thin
NOTE:
This stage is optional and can consume significant extra import time (controlled by `Gitlab::GithubImport::Settings`).
-### 9. Stage::ImportNotesWorker
+### 10. Stage::ImportNotesWorker
This worker imports regular comments for both issues and pull requests. For
every comment, we schedule a job for the
@@ -128,7 +135,7 @@ returns comments for both issues and pull requests. This means we have to wait
for all issues and pull requests to be imported before we can import regular
comments.
-### 10. Stage::ImportAttachmentsWorker
+### 11. Stage::ImportAttachmentsWorker
This worker imports note attachments that are linked inside Markdown.
For each entity with Markdown text in the project, we schedule a job of:
@@ -147,7 +154,7 @@ Each job:
NOTE:
It's an optional stage that could consume significant extra import time (controlled by `Gitlab::GithubImport::Settings`).
-### 11. Stage::ImportProtectedBranchesWorker
+### 12. Stage::ImportProtectedBranchesWorker
This worker imports protected branch rules.
For every rule that exists on GitHub, we schedule a job of
@@ -156,7 +163,7 @@ For every rule that exists on GitHub, we schedule a job of
Each job compares the branch protection rules from GitHub and GitLab and applies
the strictest of the rules to the branches in GitLab.
-### 12. Stage::FinishImportWorker
+### 13. Stage::FinishImportWorker
This worker completes the import process by performing some housekeeping
(such as flushing any caches) and by marking the import as completed.
diff --git a/doc/development/gitlab_flavored_markdown/specification_guide/index.md b/doc/development/gitlab_flavored_markdown/specification_guide/index.md
index 95d06907aa6..17afebcf6ee 100644
--- a/doc/development/gitlab_flavored_markdown/specification_guide/index.md
+++ b/doc/development/gitlab_flavored_markdown/specification_guide/index.md
@@ -34,7 +34,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
against the official specification.
- They support [snapshot testing](#markdown-snapshot-testing) of GitLab
internal GLFM processing logic. This is accomplished by automatically
- generating YAML ["example snapshot files"](#example-snapshot-files)
+ generating YAML ["example snapshot files"](#output-example-snapshot-files)
which are used as fixtures to drive automated testing within the GitLab app.
- There are [various scripts and logic](#scripts)
which are used to accomplish the above goals.
@@ -104,13 +104,13 @@ serve as input to automated conformance tests. It is
Here are the HTML-rendered versions of the specifications:
-- [GitLab Flavored Markdown (GLFM) specification](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/output/spec.html), which extends the:
+- [GitLab Flavored Markdown (GLFM) specification](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/output_spec/spec.html), which extends the:
- [GitHub Flavored Markdown (GFM) specification](https://github.github.com/gfm/) (rendered from the [source `spec.txt` for GFM specification](https://github.com/github/cmark-gfm/blob/master/test/spec.txt)), which extends the:
- [CommonMark specification](https://spec.commonmark.org/0.30/) (rendered from the [source `spec.txt` for CommonMark specification](https://github.com/commonmark/commonmark-spec/blob/master/spec.txt))
NOTE:
The creation of the
-[HTML-rendered version of the GitLab Flavored Markdown (GLFM) specification](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/output/spec.html)
+[HTML-rendered version of the GitLab Flavored Markdown (GLFM) specification](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/output_spec/spec.html)
file is still pending.
However, GLFM has more complex parsing, rendering, and testing requirements than
@@ -177,7 +177,7 @@ In this context, it should not be confused with other similar or related meaning
_example_, such as
[RSpec examples](https://relishapp.com/rspec/rspec-core/docs/example-groups/basic-structure-describe-it).
-See the section on the [`glfm_official_specification_examples.md`](#glfm_official_specification_examplesmd) file
+See the section on the [`glfm_official_specification.md`](#glfm_official_specificationmd) file
for more details on the backtick-delimited Markdown+HTML example syntax.
### Parsers and renderers
@@ -341,7 +341,7 @@ The GitLab [Markdown API](../../../api/markdown.md) generates HTML
for a given Markdown string using this method.
The Markdown specified in the [Markdown examples](#markdown-examples) is used to automatically generate HTML in
-[`glfm_specification/example_snapshots/html.yml`](#glfm_specificationexample_snapshotshtmlyml) via
+[`glfm_specification/output_example_snapshots/html.yml`](#htmlyml) via
[`update-example-snapshots.rb`](#update-example-snapshotsrb-script). These examples are
used when running [Markdown snapshot testing](#markdown-snapshot-testing).
@@ -353,7 +353,7 @@ in the ProseMirror WYSIWYG editor.
Just like static HTML,
the Markdown specified in the [Markdown examples](#markdown-examples) is used to automatically generate HTML in
-[`glfm_specification/example_snapshots/html.yml`](#glfm_specificationexample_snapshotshtmlyml) via
+[`glfm_specification/output_example_snapshots/html.yml`](#htmlyml) via
[`update-example-snapshots.rb`](#update-example-snapshotsrb-script). These examples are
used when running [Markdown snapshot testing](#markdown-snapshot-testing).
@@ -387,10 +387,10 @@ Here are more details on the sources of canonical HTML examples:
version of [`spec.txt`](#spectxt).
1. For the examples which are part of the GLFM [_official specification_](#official-specifications),
the canonical HTML is manually maintained and curated via the examples contained in the
- [`glfm_official_specification_examples.md`](#glfm_official_specification_examplesmd) [input specification file](#input-specification-files).
+ [`glfm_official_specification.md`](#glfm_official_specificationmd) [input specification file](#input-specification-files).
1. For the examples which are part of the GLFM [_internal extensions_](#internal-extensions),
the canonical HTML **is never specified**, and **must be left empty in all examples** contained in
- the [`glfm_internal_extension_examples.md`](#glfm_internal_extension_examplesmd) [input specification file](#input-specification-files).
+ the [`glfm_internal_extensions.md`](#glfm_internal_extensionsmd) [input specification file](#input-specification-files).
### Canonicalization of HTML
@@ -401,7 +401,7 @@ or HTML elements, to support specific appearance and behavioral requirements.
Neither the backend nor the frontend rendering logic can directly render the clean, basic HTML
which is necessary to perform comparison to the [canonical HTML](#canonical-html)
when running [Markdown conformance testing](#markdown-conformance-testing)
-for the [GLFM official specification examples](#glfm_official_specification_examplesmd).
+for the [GLFM official specification examples](#glfm_official_specificationmd).
Nor should they be able to, because:
@@ -443,7 +443,7 @@ Fixture-based normalization should be used whenever possible, because it is simp
understand than regex-based normalization.
The [Markdown snapshot testing](#markdown-snapshot-testing) uses RSpec to generate the
-[example snapshot files](#example-snapshot-files). RSpec enables you to:
+[example snapshot files](#output-example-snapshot-files). RSpec enables you to:
- Use the same powerful fixture support and helpers as all the rest of the GitLab RSpec suite.
- Use fixtures to control the state of the database when the example snapshots are generated.
@@ -575,10 +575,10 @@ The documentation on the implementation is split into three sections:
1. [Scripts](#scripts).
1. [Specification files](#specification-files).
-1. [Example snapshot files](#example-snapshot-files):
+1. [Example snapshot files](#output-example-snapshot-files):
These YAML files are used as input data
or fixtures to drive the various tests, and are located under
- `glfm_specification/example_snapshots`. All example snapshot files are automatically
+ `glfm_specification/output_example_snapshots`. All example snapshot files are automatically
generated based on the specification files and the implementation of the parsers and renderers.
However, they can also be directly edited if necessary, such as to
test-drive an incomplete implementation.
@@ -620,8 +620,8 @@ end
subgraph input:<br/>input specification files
C[ghfm_spec_v_0.29.md] --> A
D[glfm_intro.md] --> A
- E[glfm_official_specification_examples.md] --> A
- F[glfm_internal_extension_examples.md] --> A
+ E[glfm_official_specification.md] --> A
+ F[glfm_internal_extensions.md] --> A
end
subgraph output:<br/>GLFM specification files
A --> G[spec.txt]
@@ -646,7 +646,7 @@ script, which expects canonical HTML, against the GitLab renderer implementation
`scripts/glfm/run-spec-tests.sh` is a convenience shell script which runs
conformance specs via the CommonMark standard `spec_tests.py` script,
-which uses the `glfm_specification/output/spec.txt` file and `scripts/glfm/canonicalize-html.rb`
+which uses the `glfm_specification/output_spec/spec.txt` file and `scripts/glfm/canonicalize-html.rb`
helper script to test the GLFM renderer implementations' support for rendering Markdown
specification examples to canonical HTML.
@@ -672,9 +672,9 @@ end
#### `update-example-snapshots.rb` script
The `scripts/glfm/update-example-snapshots.rb` script uses the GLFM
-`glfm_specification/output/spec.txt` specification file and the
+`glfm_specification/output_spec/spec.txt` specification file and the
`glfm_specification/input/gitlab_flavored_markdown/glfm_example_status.yml`
-file to create and update the [example snapshot](#example-snapshot-files)
+file to create and update the [example snapshot](#output-example-snapshot-files)
YAML files:
```mermaid
@@ -746,7 +746,7 @@ runs the [`update-specification.rb`](#update-specificationrb-script).
It fails with an exception and non-zero return code if running these scripts
results in any diffs to the generated and committed
[output specification files](#output-specification-files) or
-[example snapshot files](#example-snapshot-files).
+[example snapshot files](#output-example-snapshot-files).
This script is run via the `glfm-verify` CI job to ensure that all changes to the
[input specification files](#input-specification-files)
@@ -766,12 +766,16 @@ subcategories based on their usage and purpose:
[`ghfm_spec_v_0.29.md`](#github-flavored-markdown-specification) specification.
- `gitlab_flavored_markdown`: Contains all `glfm_*` files.
- `*.md` [input specification files](#input-specification-files),
- which represent the GLFM specification itself.
+ which represent the source of truth for the GLFM specification and all associated examples.
- `*.yml` [input specification configuration files](#input-specification-configuration-files),
which control various aspects of the automated GLFM scripts and processes.
- - `output`: Contains [output specification files](#output-specification-files),
- which are automatically generated from the
+ - `output_spec`: Contains the `spec.txt` and `spec.html` [output specification files](#output-specification-files),
+ which represent the [GLFM official specification](#official-specifications), and are automatically generated from the
input files by running the [`update-specification.rb`](#update-specificationrb-script) script.
+ - `output_example_snapshots`: Contains [output example snapshot files](#output-example-snapshot-files).
+ which are used to drive [snapshot testing](#markdown-snapshot-testing), and are automatically generated from the
+ input files by running the [`update-specification.rb`](#update-specificationrb-script)
+ and [`scripts/glfm/update-example-snapshots.rb`](#update-example-snapshotsrb-script) scripts.
#### Input specification files
@@ -790,31 +794,22 @@ is a copy of the official latest [GFM `spec.txt`](https://github.com/github/cmar
- When it is downloaded, the version number is added to the filename.
- The extension is changed from `*.txt` to `*.md` so that it can be handled better by Markdown editors.
-NOTE:
-For extra clarity, this file uses the `ghfm` acronym in its name instead of `gfm`, as
-explained in the [Acronyms section](#acronyms-glfm-ghfm-gfm-commonmark).
-
-##### `glfm_intro.md`
-
-[`glfm_specification/input/gitlab_flavored_markdown/glfm_intro.md`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/input/gitlab_flavored_markdown/glfm_intro.md)
-is the GitLab-specific version of the prose in the introduction section of the GLFM specification.
+It currently contains additional **Introduction** and **Appendix** prose-only header sections which do not
+contain any examples.
-- It is manually updated.
-- The `update-specification.rb` script inserts it into the generated GLFM `spec.txt` to replace
- the GitHub-specific GFM version of the introductory section.
-
-##### `glfm_canonical_examples.txt`
+All header sections which contain examples are expected to be contained within a contiguous file section
+which is delimited by:
-The `glfm_canonical_examples.txt` file is deprecated and no longer exists. It has been replaced by two files:
+1. The beginning of the second H1 header (the first one after the **Introduction** section)
+1. An `<!-- END TESTS -->` HTML comment line.
-- [`glfm_official_specification_examples.md`](#glfm_official_specification_examplesmd)
- which contains the [GLFM official specification](#official-specifications) examples.
-- [`glfm_internal_extension_examples.md`](#glfm_internal_extension_examplesmd)
- which contains the [GLFM internal extension](#internal-extensions) examples.
+NOTE:
+For extra clarity, this file uses the `ghfm` acronym in its name instead of `gfm`, as
+explained in the [Acronyms section](#acronyms-glfm-ghfm-gfm-commonmark).
-##### `glfm_official_specification_examples.md`
+##### `glfm_official_specification.md`
-[`glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification_examples.md`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification_examples.md)
+[`glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification.md`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification.md)
consists of the manually updated Markdown+HTML examples for the
[GLFM official specification](#official-specifications), and their associated documentation and descriptions.
@@ -832,7 +827,12 @@ consists of the manually updated Markdown+HTML examples for the
- `H3` header sections must be nested within `H2` header sections. They cannot be
nested directly within `H1` header sections.
-`glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification_examples.md` sample entries:
+It _may_ contain additional prose-only header sections which do not contain any examples.
+
+All header sections which contain examples _must_ be contained within a contiguous file section which
+is delimited by `<!-- BEGIN TESTS -->` and `<!-- END TESTS -->` HTML comment lines.
+
+`glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification.md` sample entries:
<!-- markdownlint-disable MD048 -->
@@ -864,13 +864,13 @@ bold
<!-- markdownlint-enable MD048 -->
-##### `glfm_internal_extension_examples.md`
+##### `glfm_internal_extensions.md`
-[`glfm_specification/input/gitlab_flavored_markdown/glfm_internal_extension_examples.md`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/input/gitlab_flavored_markdown/glfm_internal_extension_examples.md)
+[`glfm_specification/input/gitlab_flavored_markdown/glfm_internal_extensions.md`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/input/gitlab_flavored_markdown/glfm_internal_extensions.md)
consists of the manually updated Markdown examples for the
[GLFM internal extensions](#internal-extensions), and their associated documentation and descriptions.
-Its general format is identical to [`glfm_official_specification_examples.md`](#glfm_official_specification_examplesmd),
+Its general format is identical to [`glfm_official_specification.md`](#glfm_official_specificationmd),
consisting of `H1`, `H2`, or `H3` sections containing [Markdown examples](#markdown-examples) in the
[standard backtick-delimited `spec.txt` format](#various-markdown-specifications).
@@ -878,7 +878,12 @@ However, as described in the [canonical HTML section](#canonical-html), only the
example is specified, and the HTML portion is left empty, because internal extension examples are
never used for [Markdown conformance testing](#markdown-conformance-testing).
-`glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification_examples.md` sample entries:
+It _may_ contain additional prose-only header sections which do not contain any examples.
+
+All header sections which contain examples _must_ be contained within a contiguous file section which
+is delimited by `<!-- BEGIN TESTS -->` and `<!-- END TESTS -->` HTML comment lines.
+
+`glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification.md` sample entries:
NOTE:
All lines in this example are prefixed with a `|` character. This prefix helps avoid false
@@ -908,7 +913,7 @@ See the main [specification files](#specification-files) section for more contex
All of the manually curated example names in the configuration files must correspond to
an existing [Markdown example](#markdown-examples) name found in
-[`example_snapshots/examples_index.yml`](#glfm_specificationexample_snapshotsexamples_indexyml),
+[`output_example_snapshots/examples_index.yml`](#examples_indexyml),
which is automatically generated based on the [input specification files](#input-specification-files).
If there is an invalid reference to an example name that does not exist, the
@@ -943,16 +948,16 @@ controls the behavior of the [scripts](#scripts) and [tests](#types-of-markdown-
The following optional entries are supported for each example. They all default to `false`:
- `skip_update_example_snapshots`: When true, skips any addition or update of any this example's entries
- in the [`glfm_specification/example_snapshots/html.yml`](#glfm_specificationexample_snapshotshtmlyml) file
- or the [`glfm_specification/example_snapshots/prosemirror_json.yml`](#glfm_specificationexample_snapshotsprosemirror_jsonyml) file.
+ in the [`glfm_specification/output_example_snapshots/html.yml`](#htmlyml) file
+ or the [`glfm_specification/output_example_snapshots/prosemirror_json.yml`](#prosemirror_jsonyml) file.
If this value is truthy, then no other `skip_update_example_snapshot_*` entries can be truthy,
and an error is raised if any of them are.
- `skip_update_example_snapshot_html_static`: When true, skips addition or update of this example's [static HTML](#static-html)
- entry in the [`glfm_specification/example_snapshots/html.yml`](#glfm_specificationexample_snapshotshtmlyml) file.
+ entry in the [`glfm_specification/output_example_snapshots/html.yml`](#htmlyml) file.
- `skip_update_example_snapshot_html_wysiwyg`: When true, skips addition or update of this example's [WYSIWYG HTML](#wysiwyg-html)
- entry in the [`glfm_specification/example_snapshots/html.yml`](#glfm_specificationexample_snapshotshtmlyml) file.
+ entry in the [`glfm_specification/output_example_snapshots/html.yml`](#htmlyml) file.
- `skip_update_example_snapshot_prosemirror_json`: When true, skips addition or update of this example's
- entry in the [`glfm_specification/example_snapshots/prosemirror_json.yml`](#glfm_specificationexample_snapshotsprosemirror_jsonyml) file.
+ entry in the [`glfm_specification/output_example_snapshots/prosemirror_json.yml`](#prosemirror_jsonyml) file.
- `skip_running_conformance_static_tests`: When true, skips running the [Markdown conformance tests](#markdown-conformance-testing)
of the [static HTML](#static-html) for this example.
- `skip_running_conformance_wysiwyg_tests`: When true, skips running the [Markdown conformance tests](#markdown-conformance-testing)
@@ -962,7 +967,7 @@ The following optional entries are supported for each example. They all default
- `skip_running_snapshot_wysiwyg_html_tests`: When true, skips running the [Markdown snapshot tests](#markdown-snapshot-testing)
of the [WYSIWYG HTML](#wysiwyg-html) for this example.
- `skip_running_snapshot_prosemirror_json_tests`: When true, skips running the [Markdown snapshot tests](#markdown-snapshot-testing)
- of the [ProseMirror JSON](#glfm_specificationexample_snapshotsprosemirror_jsonyml) for this example.
+ of the [ProseMirror JSON](#prosemirror_jsonyml) for this example.
`glfm_specification/input/gitlab_flavored_markdown/glfm_example_status.yml` sample entry:
@@ -1033,9 +1038,9 @@ or [environment-variable-based normalization](#environment-variable-based-normal
snapshot:
07_01_00_href: *07_01_00_href
07_01_00_id: *07_01_00_id
- wysiwyg:
- 07_01_00_href: *07_01_00_href
- 07_01_00_id: *07_01_00_id
+ wysiwyg:
+ 07_01_00_href: *07_01_00_href
+ 07_01_00_id: *07_01_00_id
prosemirror_json:
07_01_00_href: *07_01_00_href
07_01_00_id: *07_01_00_id
@@ -1093,36 +1098,66 @@ move or copy a hosted version of the rendered HTML `spec.html` version to anothe
##### spec.txt
-[`glfm_specification/output/spec.txt`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/output/spec.txt)
+[`glfm_specification/output_spec/spec.txt`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/output_spec/spec.txt)
is a Markdown specification file, in the standard format
with prose and Markdown + canonical HTML examples.
-It also serves as input for other scripts such as `update-example-snapshots.rb`
-and `run-spec-tests.sh`.
+It also serves as input for other scripts such as
+`run-spec-tests.sh`.
It is generated or updated by the `update-specification.rb` script, using the
[input specification files](#input-specification-files) as input.
See the [`update-specification.rb` script section](#update-specificationrb-script)
for a diagram and more description on this process.
+NOTE:
+Even though `spec.txt` is a Markdown file, it is named with a `*.txt` extension
+for consistency with the GFM and CommonMark specifications. All other GLFM
+Markdown files are named with a `*.md` extension for compatibility with
+various editors to enable Markdown formatting and syntax highlighting.
+
##### spec.html
-[`glfm_specification/output/spec.html`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/output/spec.html)
+[`glfm_specification/output_spec/spec.html`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/output_spec/spec.html)
is an HTML file, rendered based on `spec.txt`. It is
-also generated (or updated) by the `update-specification.rb` script at the same time as
+generated (or updated) by the `update-specification.rb` script at the same time as
`spec.txt`.
It corresponds to the HTML-rendered versions of the
"GitHub Flavored Markdown" (<abbr title="GitHub Flavored Markdown">GFM</abbr>)
[specification](https://github.github.com/gfm/)
-and the [CommonMark specification](https://spec.commonmark.org/0.30/).
+and the [CommonMark specification](https://spec.commonmark.org/0.30/), but only
+contains GitLab Flavored Markdown (GLFM) examples.
-### Example snapshot files
+NOTE:
+
+The formatting of this HTML is currently not identical to the GFM and CommonMark
+HTML-rendered specification. It is only the raw output of running `spec.txt` through
+the GitLab Markdown renderer. Properly formatting the HTML will require
+duplicating or reusing the Lua script and template from the CommonMark project:
+[CommonMark Makefile](https://github.com/commonmark/commonmark-spec/blob/master/Makefile#L11)
+
+#### Output example snapshot files
+
+The `output_example_snapshots` directory contains files which are generated by the
+`update-specification.rb` and `update-example-snapshots.rb` scripts based off of the files in the
+`glfm_specification/input` directory.
+
+The `output-specification.rb` script generates
+`output_snapshot_examples/snapshot_spec.md` and `output_snapshot_examples/snapshot_spec.html`.
+These files are Markdown specification files containing examples generated based on input files,
+similar to the `output_spec/spec.txt` and `output_spec/spec.html`, with the following differences:
-The `example_snapshots` directory contains files which are generated by the
-`update-example-snapshots.rb` script based off of the files in the
-`glfm_specification/input` directory. They are used as fixtures to drive the
-various Markdown snapshot tests.
+1. They contain a superset of _all_ examples from
+ the Commonmark, GitHub Flavored Markdown, and GitLab Flavored Markdown specifications, whereas
+ `spec.*` only contains the GLFM specification. This is to provide a single place to refer to
+ all examples when working with [snapshot testing](#markdown-snapshot-testing).
+1. They contain _only_ header sections which contain examples. They do not contain any prose-only
+ sections which do not contain examples.
+
+The `update-example-snapshots.rb` script generates the various
+`output_snapshot_examples/*.yml` files, which
+are used as fixtures to drive the [snapshot testing](#markdown-snapshot-testing).
After the entire GLFM implementation is complete for both backend (Ruby) and
frontend (JavaScript), all of these YAML files can be automatically generated.
@@ -1131,9 +1166,47 @@ key in `glfm_specification/input/gitlab_flavored_markdown/glfm_example_status.ym
can be used to disable automatic generation of some examples. They can instead
be manually edited as necessary to help drive the implementations.
-#### `glfm_specification/example_snapshots/examples_index.yml`
+##### `snapshot_spec.md`
+
+[`glfm_specification/output_example_snapshots/snapshot_spec.md`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/output_example_snapshots/snapshot_spec.md)
+is a Markdown file, containing standard Markdown + canonical HTML examples like [`spec.txt`](#spectxt).
+
+It is generated or updated by the `update-specification.rb` script, using the
+[input specification files](#input-specification-files) as input.
+See the [`update-specification.rb` script section](#update-specificationrb-script)
+for a diagram and more description on this process. It also serves as input for other
+scripts such as `update-example-snapshots.rb`.
+
+It is similar to [`spec.txt`](#spectxt), with the following differences:
+
+1. [`spec.txt`](#spectxt) contains only examples for GitLab Flavored Markdown, but
+ `snapshot_spec.md` also contains the full superset of examples from the
+ "GitHub Flavored Markdown" (<abbr title="GitHub Flavored Markdown">GFM</abbr>)[specification](https://github.github.com/gfm/)
+ and the [CommonMark specification](https://spec.commonmark.org/0.30/) specifications.
+1. [`spec.txt`](#spectxt) represents the full GLFM specification, including additional header sections
+ containing only explanatory prose and no examples, but `snapshot_spec.md` consists of only
+ header sections which contain examples. This is because its purpose is to serve as input for
+ the other [`output example snapshot files`](#output-example-snapshot-files) - it is not intended
+ to serve as an actual [specification file](#output-specification-files)
+ like [`spec.txt`](#spectxt) or [`spec.html`](#spechtml).
+
+##### `snapshot_spec.html`
+
+[`glfm_specification/output_snapshot_examples/snapshot_spec.html`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/output_snapshot_examples/snapshot_spec.html)
+is an HTML file, rendered based on `snapshot_spec.md`. It is
+generated (or updated) by the `update-specification.rb` script at the same time as
+`snapshot_spec.md`.
+
+NOTE:
+The formatting of this HTML is currently not identical to the GFM and CommonMark
+HTML-rendered specification. It is only the raw output of running `snapshot_spec.md` through
+the GitLab Markdown renderer. Properly formatting the HTML will require
+duplicating or reusing the Lua script and template from the CommonMark project:
+[CommonMark Makefile](https://github.com/commonmark/commonmark-spec/blob/master/Makefile#L11)
+
+##### `examples_index.yml`
-[`glfm_specification/example_snapshots/examples_index.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/example_snapshots/examples_index.yml)
+[`glfm_specification/output_example_snapshots/examples_index.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/output_example_snapshots/examples_index.yml)
is the main list of all
CommonMark, GFM, and GLFM example names, each with a uniquely identifying name.
@@ -1142,9 +1215,9 @@ CommonMark, GFM, and GLFM example names, each with a uniquely identifying name.
- For CommonMark and GFM examples,
these sections originally came from the GFM `spec.txt`.
- For GLFM examples, it is generated from
- [`glfm_official_specification_examples.md`](#glfm_official_specification_examplesmd) and [`glfm_internal_extension_examples.md`](#glfm_internal_extension_examplesmd).
+ [`glfm_official_specification.md`](#glfm_official_specificationmd) and [`glfm_internal_extensions.md`](#glfm_internal_extensionsmd).
- It also contains extra metadata about each example, such as:
- 1. `spec_txt_example_position` - The position of the example in the generated GLFM `spec.txt` file.
+ 1. `spec_example_position` - The position of the example in the generated GLFM `spec.txt` file.
- This value is the index order of each individual Markdown + HTML5 example in the file. It is _not_
the line number in the file.
- This value can be used to locate the example in the rendered `spec.html` file, because the standard
@@ -1159,49 +1232,49 @@ CommonMark, GFM, and GLFM example names, each with a uniquely identifying name.
examples where multiple examples exist for the same Section 7 subsection are
added to the end of the sub-section.
-`glfm_specification/example_snapshots/examples_index.yml` sample entries:
+`examples_index.yml` sample entries:
```yaml
02_01_00_preliminaries_characters_and_lines_1:
- spec_txt_example_position: 1
+ spec_example_position: 1
source_specification: commonmark
03_01_00_blocks_and_inlines_precedence_1:
- spec_txt_example_position: 12
+ spec_example_position: 12
source_specification: commonmark
05_03_00_container_blocks_task_list_items_1:
- spec_txt_example_position: 279
+ spec_example_position: 279
source_specification: github
06_04_00_inlines_emphasis_and_strong_emphasis_1:
- spec_txt_example_position: 360
+ spec_example_position: 360
source_specification: github
07_01_00_audio_link_1:
- spec_txt_example_position: 301
+ spec_example_position: 301
source_specification: gitlab
```
-#### `glfm_specification/example_snapshots/markdown.yml`
+##### `markdown.yml`
-[`glfm_specification/example_snapshots/markdown.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/example_snapshots/markdown.yml) contains the original Markdown
-for each entry in `glfm_specification/example_snapshots/examples_index.yml`
+[`glfm_specification/output_example_snapshots/markdown.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/output_example_snapshots/markdown.yml) contains the original Markdown
+for each entry in `glfm_specification/output_example_snapshots/examples_index.yml`:
- For CommonMark and GFM Markdown,
it is generated (or updated) from the standard GFM
`spec.txt` using the `update-example-snapshots.rb` script.
- For GLFM, it is generated (or updated) from the
- [`glfm_official_specification_examples.md`](#glfm_official_specification_examplesmd) and [`glfm_internal_extension_examples.md`](#glfm_internal_extension_examplesmd)
+ [`glfm_official_specification.md`](#glfm_official_specificationmd) and [`glfm_internal_extensions.md`](#glfm_internal_extensionsmd)
input specification files.
-`glfm_specification/example_snapshots/markdown.yml` sample entry:
+`glfm_specification/output_example_snapshots/markdown.yml` sample entry:
```yaml
06_04_00_inlines_emphasis_and_strong_emphasis_1: |
*foo bar*
```
-#### `glfm_specification/example_snapshots/html.yml`
+##### `html.yml`
-[`glfm_specification/example_snapshots/html.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/example_snapshots/html.yml)
-contains the HTML for each entry in `glfm_specification/example_snapshots/examples_index.yml`
+[`glfm_specification/output_example_snapshots/html.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/output_example_snapshots/html.yml)
+contains the HTML for each entry in `glfm_specification/output_example_snapshots/examples_index.yml`:
Three types of entries exist, with different HTML for each:
@@ -1209,16 +1282,16 @@ Three types of entries exist, with different HTML for each:
- The ["Canonical"](#canonicalization-of-html) HTML.
- For CommonMark and GFM examples, the HTML comes from the examples in `spec.txt`.
- For [GLFM official specification](#official-specifications) examples, it is generated/updated from
- [`glfm_official_specification_examples.md`](#glfm_official_specification_examplesmd).
+ [`glfm_official_specification.md`](#glfm_official_specificationmd).
- **Static**
- This is the static (backend (Ruby)-generated) HTML for each entry in
- `glfm_specification/example_snapshots/examples_index.yml`.
+ `glfm_specification/output_example_snapshots/examples_index.yml`.
- It is generated/updated from backend [Markdown API](../../../api/markdown.md)
(or the underlying internal classes) via the `update-example-snapshots.rb` script,
but can be manually updated for static examples with incomplete implementations.
- **WYSIWYG**
- The WYSIWYG (frontend, JavaScript-generated) HTML for each entry in
- `glfm_specification/example_snapshots/examples_index.yml`.
+ `glfm_specification/output_example_snapshots/examples_index.yml`.
- It is generated (or updated) from the frontend Content Editor implementation via the
`update-example-snapshots.rb` script. It can be manually updated for WYSIWYG
examples with incomplete implementations.
@@ -1226,7 +1299,7 @@ Three types of entries exist, with different HTML for each:
Any exceptions or failures which occur when generating HTML are replaced with an
`Error - check implementation` value.
-`glfm_specification/example_snapshots/html.yml` sample entry:
+`glfm_specification/output_example_snapshots/html.yml` sample entry:
```yaml
06_04_00_inlines_emphasis_and_strong_emphasis_1:
@@ -1242,16 +1315,16 @@ NOTE:
The actual `static` or `WYSIWYG` entries may differ from the example `html.yml`,
depending on how the implementations evolve.
-#### `glfm_specification/example_snapshots/prosemirror_json.yml`
+##### `prosemirror_json.yml`
-[`glfm_specification/example_snapshots/prosemirror_json.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/example_snapshots/prosemirror_json.yml)
-contains the ProseMirror JSON for each entry in `glfm_specification/example_snapshots/examples_index.yml`
+[`glfm_specification/output_example_snapshots/prosemirror_json.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/glfm_specification/output_example_snapshots/prosemirror_json.yml)
+contains the ProseMirror JSON for each entry in `glfm_specification/output_example_snapshots/examples_index.yml`
- It is generated (or updated) from the frontend code via the `update-example-snapshots.rb`
script, but can be manually updated for examples with incomplete implementations.
- Any exceptions or failures when generating are replaced with a `Error - check implementation` value.
-`glfm_specification/example_snapshots/prosemirror_json.yml` sample entry:
+`glfm_specification/output_example_snapshots/prosemirror_json.yml` sample entry:
```yaml
06_04_00_inlines_emphasis_and_strong_emphasis_1: |-
@@ -1291,13 +1364,13 @@ This section describes how the scripts can be used to manage the GLFM specificat
1. If you are working on an in-progress feature or bug, make any necessary manual updates to the [input specification files](#input-specification-files). This may include:
1. Updating the canonical Markdown or HTML examples in
- [`glfm_official_specification_examples.md`](#glfm_official_specification_examplesmd) or [`glfm_internal_extension_examples.md`](#glfm_internal_extension_examplesmd).
+ [`glfm_official_specification.md`](#glfm_official_specificationmd) or [`glfm_internal_extensions.md`](#glfm_internal_extensionsmd).
1. Updating `glfm_specification/input/gitlab_flavored_markdown/glfm_example_status.yml` to reflect the current status of the examples or tests.
1. Run [`update-specification.rb`](#update-specificationrb-script) to update the `spec.txt` to reflect any changes which were made to the [input specification files](#input-specification-files).
1. Visually inspect and confirm any resulting changes to the [output specification files](#output-specification-files).
-1. Run [`update-example-snapshots.rb`](#update-example-snapshotsrb-script) to update the [example snapshot files](#example-snapshot-files).
-1. Visually inspect and confirm any resulting changes to the [example snapshot files](#example-snapshot-files).
+1. Run [`update-example-snapshots.rb`](#update-example-snapshotsrb-script) to update the [example snapshot files](#output-example-snapshot-files).
+1. Visually inspect and confirm any resulting changes to the [example snapshot files](#output-example-snapshot-files).
1. Run [`run-snapshot-tests.sh`](#run-snapshot-testssh-script) as a convenience script to run all relevant frontend (RSpec) and backend (Jest) tests which use the example snapshots.
1. Any frontend or backend snapshot test may also be run individually.
1. All frontend and backend tests are also run as part of the continuous integration suite, as they normally are.
-1. Commit any changes to the [input specification files](#input-specification-files), [output specification files](#output-specification-files), or [example snapshot files](#example-snapshot-files).
+1. Commit any changes to the [input specification files](#input-specification-files), [output specification files](#output-specification-files), or [example snapshot files](#output-example-snapshot-files).
diff --git a/doc/development/go_guide/index.md b/doc/development/go_guide/index.md
index 197c7616d82..b561ebc4285 100644
--- a/doc/development/go_guide/index.md
+++ b/doc/development/go_guide/index.md
@@ -408,7 +408,7 @@ should be used in functions that can block and passed as the first parameter.
Every project should have a `Dockerfile` at the root of their repository, to
build and run the project. Since Go program are static binaries, they should
not require any external dependency, and shells in the final image are useless.
-We encourage [Multistage builds](https://docs.docker.com/develop/develop-images/multistage-build/):
+We encourage [Multistage builds](https://docs.docker.com/build/building/multi-stage/):
- They let the user build the project with the right Go version and
dependencies.
diff --git a/doc/development/graphql_guide/pagination.md b/doc/development/graphql_guide/pagination.md
index 7b9d2158c60..daa39875119 100644
--- a/doc/development/graphql_guide/pagination.md
+++ b/doc/development/graphql_guide/pagination.md
@@ -20,7 +20,7 @@ See the [general pagination guidelines section](../database/pagination_guideline
This is the traditional, page-by-page pagination, that is most common,
and used across much of GitLab. You can recognize it by
-a list of page numbers near the bottom of a page, which, when clicked,
+a list of page numbers near the bottom of a page, which, when selected,
take you to that page of results.
For example, when you select **Page 100**, we send `100` to the
@@ -248,7 +248,7 @@ incorrect sort order.
There are times when the [complexity of sorting](#limitations-of-query-complexity)
is more than our keyset pagination can handle.
-For example, in [`IssuesResolver`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/resolvers/issues_resolver.rb),
+For example, in [`ProjectIssuesResolver`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/resolvers/project_issues_resolver.rb),
when sorting by `priority_asc`, we can't use keyset pagination as the ordering is much
too complex. For more information, read [`issuable.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/models/concerns/issuable.rb).
diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md
index 158eb19764b..91e2efcb2a3 100644
--- a/doc/development/i18n/externalization.md
+++ b/doc/development/i18n/externalization.md
@@ -463,12 +463,17 @@ use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make sure to
The `n_` and `n__` methods should only be used to fetch pluralized translations of the same
string, not to control the logic of showing different strings for different
-quantities. Some languages have different quantities of target plural forms.
+quantities. For similar strings, pluralize the entire sentence to provide the most context
+when translating. Some languages have different quantities of target plural forms.
For example, Chinese (simplified) has only one target plural form in our
translation tool. This means the translator has to choose to translate only one
of the strings, and the translation doesn't behave as intended in the other case.
-For example, use this:
+Below are some examples:
+
+Example 1: For different strings
+
+Use this:
```ruby
if selected_projects.one?
@@ -485,6 +490,27 @@ Instead of this:
format(n_("%{project_name}", "%d projects selected", count), project_name: 'GitLab')
```
+Example 2: For similar strings
+
+Use this:
+
+```ruby
+n__('Last day', 'Last %d days', days.length)
+```
+
+Instead of this:
+
+```ruby
+# incorrect usage example
+const pluralize = n__('day', 'days', days.length)
+
+if (days.length === 1 ) {
+ return sprintf(s__('Last %{pluralize}', pluralize)
+}
+
+return sprintf(s__('Last %{dayNumber} %{pluralize}'), { dayNumber: days.length, pluralize })
+```
+
### Namespaces
A namespace is a way to group translations that belong together. They provide context to our
diff --git a/doc/development/i18n/merging_translations.md b/doc/development/i18n/merging_translations.md
index 2a086c796c9..f98e5119916 100644
--- a/doc/development/i18n/merging_translations.md
+++ b/doc/development/i18n/merging_translations.md
@@ -36,7 +36,7 @@ it should be disapproved in Crowdin. Our strings must use [variables](externaliz
for HTML instead.
It might be useful to pause the integration on the Crowdin side for a
-moment so translations don't keep coming. You can do this by clicking
+moment so translations don't keep coming. You can do this by selecting
**Pause sync** on the [Crowdin integration settings page](https://translate.gitlab.com/project/gitlab-ee/settings#integration).
## Merging translations
diff --git a/doc/development/i18n/proofreader.md b/doc/development/i18n/proofreader.md
index b5d57f9912b..8a4ad73efe3 100644
--- a/doc/development/i18n/proofreader.md
+++ b/doc/development/i18n/proofreader.md
@@ -58,6 +58,7 @@ are very appreciative of the work done by translators and proofreaders!
- French
- Davy Defaud - [GitLab](https://gitlab.com/DevDef), [Crowdin](https://crowdin.com/profile/DevDef)
- Germain Gorisse - [GitLab](https://gitlab.com/ggorisse), [Crowdin](https://crowdin.com/profile/germaingorisse)
+ - Xavier Delatour - [GitLab](https://gitlab.com/xdelatour), [Crowdin](https://crowdin.com/profile/xdelatour)
- Galician
- Antón Méixome - [Crowdin](https://crowdin.com/profile/meixome)
- Pedro Garcia - [GitLab](https://gitlab.com/pedgarrod), [Crowdin](https://crowdin.com/profile/breaking_pitt)
diff --git a/doc/development/import_export.md b/doc/development/import_export.md
index f864dd3b678..9aab7f38dbb 100644
--- a/doc/development/import_export.md
+++ b/doc/development/import_export.md
@@ -6,116 +6,10 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Import/Export development documentation
-Troubleshooting and general development guidelines and tips for the [Import/Export feature](../user/project/settings/import_export.md).
+General development guidelines and tips for the [Import/Export feature](../user/project/settings/import_export.md).
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i> This document is originally based on the [Import/Export 201 presentation available on YouTube](https://www.youtube.com/watch?v=V3i1OfExotE).
-## Troubleshooting commands
-
-Finds information about the status of the import and further logs using the JID:
-
-```ruby
-# Rails console
-Project.find_by_full_path('group/project').import_state.slice(:jid, :status, :last_error)
-> {"jid"=>"414dec93f941a593ea1a6894", "status"=>"finished", "last_error"=>nil}
-```
-
-```shell
-# Logs
-grep JID /var/log/gitlab/sidekiq/current
-grep "Import/Export error" /var/log/gitlab/sidekiq/current
-grep "Import/Export backtrace" /var/log/gitlab/sidekiq/current
-tail /var/log/gitlab/gitlab-rails/importer.log
-```
-
-## Troubleshooting performance issues
-
-Read through the current performance problems using the Import/Export below.
-
-### OOM errors
-
-Out of memory (OOM) errors are normally caused by the [Sidekiq Memory Killer](../administration/operations/sidekiq_memory_killer.md):
-
-```shell
-SIDEKIQ_MEMORY_KILLER_MAX_RSS = 2000000
-SIDEKIQ_MEMORY_KILLER_HARD_LIMIT_RSS = 3000000
-SIDEKIQ_MEMORY_KILLER_GRACE_TIME = 900
-```
-
-An import status `started`, and the following Sidekiq logs signal a memory issue:
-
-```shell
-WARN: Work still in progress <struct with JID>
-```
-
-### Timeouts
-
-Timeout errors occur due to the `Gitlab::Import::StuckProjectImportJobsWorker` marking the process as failed:
-
-```ruby
-module Gitlab
- module Import
- class StuckProjectImportJobsWorker
- include Gitlab::Import::StuckImportJob
- # ...
- end
- end
-end
-
-module Gitlab
- module Import
- module StuckImportJob
- # ...
- IMPORT_JOBS_EXPIRATION = 15.hours.to_i
- # ...
- def perform
- stuck_imports_without_jid_count = mark_imports_without_jid_as_failed!
- stuck_imports_with_jid_count = mark_imports_with_jid_as_failed!
-
- track_metrics(stuck_imports_with_jid_count, stuck_imports_without_jid_count)
- end
- # ...
- end
- end
-end
-```
-
-```shell
-Marked stuck import jobs as failed. JIDs: xyz
-```
-
-```plaintext
- +-----------+ +-----------------------------------+
- |Export Job |--->| Calls ActiveRecord `as_json` and |
- +-----------+ | `to_json` on all project models |
- +-----------------------------------+
-
- +-----------+ +-----------------------------------+
- |Import Job |--->| Loads all JSON in memory, then |
- +-----------+ | inserts into the DB in batches |
- +-----------------------------------+
-```
-
-### Problems and solutions
-
-| 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 |
-| | [Netflix Fast JSON API](https://github.com/Netflix/fast_jsonapi) may help |
-| | Batch reading/writing to disk and any SQL
-
-### Temporary solutions
-
-While the performance problems are not tackled, there is a process to workaround
-importing big projects, using a foreground import:
-
-[Foreground import](https://gitlab.com/gitlab-com/gl-infra/reliability/-/issues/5384) of big projects for customers.
-(Using the import template in the [infrastructure tracker](https://gitlab.com/gitlab-com/gl-infra/reliability/-/issues))
-
## Security
The Import/Export feature is constantly updated (adding new things to export), however
diff --git a/doc/development/integrations/index.md b/doc/development/integrations/index.md
index a0a81775391..2639da818c6 100644
--- a/doc/development/integrations/index.md
+++ b/doc/development/integrations/index.md
@@ -10,9 +10,9 @@ description: "GitLab's development guidelines for Integrations"
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).
-Also see our [direction page](https://about.gitlab.com/direction/ecosystem/integrations/) for an overview of our strategy around integrations.
+Also see our [direction page](https://about.gitlab.com/direction/manage/integrations/) for an overview of our strategy around integrations.
-This guide is a work in progress. You're welcome to ping `@gitlab-org/ecosystem-stage/integrations`
+This guide is a work in progress. You're welcome to ping `@gitlab-org/manage/integrations`
if you need clarification or spot any outdated information.
## Add a new integration
diff --git a/doc/development/integrations/jira_connect.md b/doc/development/integrations/jira_connect.md
index fb0d239db46..d4215662db4 100644
--- a/doc/development/integrations/jira_connect.md
+++ b/doc/development/integrations/jira_connect.md
@@ -109,4 +109,4 @@ The following steps describe setting up an environment to test the GitLab OAuth
1. Go to **Admin > Settings > General**.
1. Scroll down and expand the GitLab for Jira App section.
1. Go to [gitpod.io/variables](https://gitpod.io/variables).
-1. Paste the Application ID into the **Jira Connect Application ID** field and click **Save changes**
+1. Paste the Application ID into the **Jira Connect Application ID** field and select **Save changes**.
diff --git a/doc/development/integrations/secure.md b/doc/development/integrations/secure.md
index f40caf29cfa..787b46133ad 100644
--- a/doc/development/integrations/secure.md
+++ b/doc/development/integrations/secure.md
@@ -157,7 +157,7 @@ If the scanner requires a fully functional Linux environment,
it is recommended to use a [Debian](https://www.debian.org/intro/about) "slim" distribution or [Alpine Linux](https://www.alpinelinux.org/).
If possible, it is recommended to build the image from scratch, using the `FROM scratch` instruction,
and to compile the scanner with all the libraries it needs.
-[Multi-stage builds](https://docs.docker.com/develop/develop-images/multistage-build/)
+[Multi-stage builds](https://docs.docker.com/build/building/multi-stage/)
might also help with keeping the image small.
To keep an image size small, consider using [dive](https://github.com/wagoodman/dive#dive) to analyze layers in a Docker image to
@@ -314,7 +314,7 @@ This documentation gives an overview of the report JSON format,
as well as recommendations and examples to help integrators set its fields.
The format is extensively described in the documentation of
[SAST](../../user/application_security/sast/index.md#reports-json-format),
-[DAST](../../user/application_security/dast/index.md#reports),
+[DAST](../../user/application_security/dast/proxy-based.md#reports),
[Dependency Scanning](../../user/application_security/dependency_scanning/index.md#reports-json-format),
and [Container Scanning](../../user/application_security/container_scanning/index.md#reports-json-format)
diff --git a/doc/development/integrations/secure_partner_integration.md b/doc/development/integrations/secure_partner_integration.md
index ba0654971d3..bcbc02d4827 100644
--- a/doc/development/integrations/secure_partner_integration.md
+++ b/doc/development/integrations/secure_partner_integration.md
@@ -77,7 +77,7 @@ and complete an integration with the Secure stage.
1. Get a test account to begin developing your integration. You can
request a [GitLab.com Subscription Sandbox](https://about.gitlab.com/partners/technology-partners/integrate/#gitlabcom-subscription-sandbox-request)
or an [EE Developer License](https://about.gitlab.com/partners/technology-partners/integrate/#requesting-ultimate-dev-license-for-rd).
-1. Provide a [pipeline job](../../development/pipelines.md)
+1. Provide a [pipeline job](../../development/pipelines)
template that users could integrate into their own GitLab pipelines.
1. Create a report artifact with your pipeline jobs.
1. Ensure your pipeline jobs create a report artifact that GitLab can process
diff --git a/doc/development/internal_api/index.md b/doc/development/internal_api/index.md
index 9b77a20a0d6..68d9b88bc05 100644
--- a/doc/development/internal_api/index.md
+++ b/doc/development/internal_api/index.md
@@ -496,8 +496,6 @@ metric counters.
| Attribute | Type | Required | Description |
|:---------------------------------------------------------------------------|:--------------|:---------|:-----------------------------------------------------------------------------------------------------------------|
-| `gitops_sync_count` (DEPRECATED) | integer | no | The number to increase the `gitops_sync` counter by |
-| `k8s_api_proxy_request_count` (DEPRECATED) | integer | no | The number to increase the `k8s_api_proxy_request` counter by |
| `counters` | hash | no | The number to increase the `k8s_api_proxy_request` counter by |
| `counters["k8s_api_proxy_request"]` | integer | no | The number to increase the `k8s_api_proxy_request` counter by |
| `counters["gitops_sync"]` | integer | no | The number to increase the `gitops_sync` counter by |
@@ -512,7 +510,7 @@ Example Request:
```shell
curl --request POST --header "Gitlab-Kas-Api-Request: <JWT token>" --header "Content-Type: application/json" \
- --data '{"gitops_sync_count":1}' "http://localhost:3000/api/v4/internal/kubernetes/usage_metrics"
+ --data '{"counters": {"gitops_sync":1}}' "http://localhost:3000/api/v4/internal/kubernetes/usage_metrics"
```
### Create Starboard vulnerability
diff --git a/doc/development/kubernetes.md b/doc/development/kubernetes.md
index e7764326db3..332a3c4ab09 100644
--- a/doc/development/kubernetes.md
+++ b/doc/development/kubernetes.md
@@ -155,15 +155,9 @@ Mitigation strategies include:
## Debugging Kubernetes integrations
Logs related to the Kubernetes integration can be found in
-[`kubernetes.log`](../administration/logs/index.md#kuberneteslog). On a local
+[`kubernetes.log`](../administration/logs/index.md#kuberneteslog-deprecated). On a local
GDK install, these logs are present in `log/kubernetes.log`.
-Some services such as
-[`Clusters::Applications::InstallService`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/clusters/applications/install_service.rb#L18)
-rescues `StandardError` which can make it harder to debug issues in an
-development environment. The current workaround is to temporarily
-comment out the `rescue` in your local development source.
-
You can also follow the installation logs to debug issues related to
installation. Once the installation/upgrade is underway, wait for the
pod to be created. Then run the following to obtain the pods logs as
diff --git a/doc/development/licensed_feature_availability.md b/doc/development/licensed_feature_availability.md
deleted file mode 100644
index b007df8f1da..00000000000
--- a/doc/development/licensed_feature_availability.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: 'ee_features.md'
-remove_date: '2022-10-08'
----
-
-This document was moved to [another location](ee_features.md).
-
-<!-- This redirect file can be deleted after <2022-10-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 (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/merge_request_concepts/widget_extensions.md b/doc/development/merge_request_concepts/widget_extensions.md
deleted file mode 100644
index 097e9155f2b..00000000000
--- a/doc/development/merge_request_concepts/widget_extensions.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: '../fe_guide/merge_request_widget_extensions.md'
-remove_date: '2022-10-27'
----
-
-This document was moved to [another location](../fe_guide/merge_request_widget_extensions.md).
-
-<!-- This redirect file can be deleted after <2022-10-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/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index f59c1fd8368..5764c876e4d 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -52,9 +52,18 @@ work it needs to perform and how long it takes to complete:
of release manager through the [post-deploy migration pipeline](https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/post_deploy_migration/readme.md#how-to-determine-if-a-post-deploy-migration-has-been-executed-on-gitlabcom).
These migrations can be used for schema changes that aren't critical for the application to operate, or data migrations that take at most a few minutes.
Common examples for schema changes that should run post-deploy include:
+
- Clean-ups, like removing unused columns.
- Adding non-critical indices on high-traffic tables.
- Adding non-critical indices that take a long time to create.
+
+ These migrations should not be used for schema changes that are critical for the application to operate. Making such
+ schema changes in a post-deployment migration have caused issues in the past, for example [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/378582).
+ Changes that should always be a regular schema migration and not be executed in a post-deployment migration include:
+
+ - Creating a new table, example: `create_table`.
+ - Adding a new column to an existing table, example: `add_column`.
+
1. [**Batched background migrations.**](database/batched_background_migrations.md) These aren't regular Rails migrations, but application code that is
executed via Sidekiq jobs, although a post-deployment migration is used to schedule them. Use them only for data migrations that
exceed the timing guidelines for post-deploy migrations. Batched background migrations should _not_ change the schema.
@@ -897,9 +906,14 @@ end
Table **has records** but **no foreign keys**:
-- First release: Remove the application code related to the table, such as models,
-controllers and services.
-- Second release: Use the `drop_table` method in your migration.
+- Remove the application code related to the table, such as models,
+ controllers and services.
+- In a post-deployment migration, use `drop_table`.
+
+This can all be in a single migration if you're sure the code is not used.
+If you want to reduce risk slightly, consider putting the migrations into a
+second merge request after the application changes are merged. This approach
+provides an opportunity to roll back.
```ruby
def up
@@ -913,12 +927,16 @@ end
Table **has foreign keys**:
-- First release: Remove the application code related to the table, such as models,
-controllers, and services.
-- Second release: Remove the foreign keys using the `with_lock_retries`
-helper method. Use `drop_table` in another migration file.
+- Remove the application code related to the table, such as models,
+ controllers, and services.
+- In a post-deployment migration, remove the foreign keys using the
+ `with_lock_retries` helper method. In another subsequent post-deployment
+ migration, use `drop_table`.
-**Migrations for the second release:**
+This can all be in a single migration if you're sure the code is not used.
+If you want to reduce risk slightly, consider putting the migrations into a
+second merge request after the application changes are merged. This approach
+provides an opportunity to roll back.
Removing the foreign key on the `projects` table:
diff --git a/doc/development/multi_version_compatibility.md b/doc/development/multi_version_compatibility.md
index 808554d6027..8e2103b2f3e 100644
--- a/doc/development/multi_version_compatibility.md
+++ b/doc/development/multi_version_compatibility.md
@@ -258,7 +258,7 @@ For more information, see [the relevant issue](https://gitlab.com/gitlab-org/git
We bumped the Markdown cache version and found a bug when a user edited a description or comment which was generated from a different Markdown
cache version. The cached HTML wasn't generated properly after saving. In most cases, this wouldn't have happened because users would have
-viewed the Markdown before clicking **Edit** and that would mean the Markdown cache is refreshed. But because we run mixed versions, this is
+viewed the Markdown before selecting **Edit** and that would mean the Markdown cache is refreshed. But because we run mixed versions, this is
more likely to happen. Another user on a different version could view the same page and refresh the cache to the other version behind the scenes.
For more information, see [the relevant issue](https://gitlab.com/gitlab-org/gitlab/-/issues/208255).
diff --git a/doc/development/packages/cleanup_policies.md b/doc/development/packages/cleanup_policies.md
new file mode 100644
index 00000000000..aa60cde450b
--- /dev/null
+++ b/doc/development/packages/cleanup_policies.md
@@ -0,0 +1,122 @@
+---
+stage: Package
+group: Container 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
+---
+
+# Cleanup policies
+
+Cleanup policies are recurrent background processes that automatically remove
+objects according to some parameters set by users.
+
+## Container Registry
+
+Cleanup policies for the container registry work on all the container repositories
+hosted in a single project. All tags that match the cleanup parameters are removed.
+
+### Parameters
+
+The [ContainerExpirationPolicy](https://gitlab.com/gitlab-org/gitlab/-/blob/37a76cbfb54a9a3f0dba3c3748eaaac82fb8bf4b/app/models/container_expiration_policy.rb)
+holds all parameters for the container registry cleanup policies.
+
+The parameters are split into two groups:
+
+- The parameters that define tags to keep:
+ - `keep_n`. Keep the `n` most recent tags.
+ - `name_regex_keep`. Keep tags matching this regular expression.
+- The parameters that define tags to destroy:
+ - `older_than`. Destroy tags older than this timestamp.
+ - `name_regex`. Destroy tags matching this regular expression.
+
+The remaining parameters impact when the policy is executed:
+
+- `enabled`. Defines if the policy is enabled or not.
+- `cadence`. Defines the execution cadence of the policy.
+- `next_run_at`. Defines when the next execution should happen.
+
+### Execution
+
+Due to the large number of policies we need to process on GitLab.com, the execution
+follows this design.
+
+- Policy executions are limited in time.
+- Policy executions are either complete or partial.
+- The background jobs will consider the next job to be executed based on two
+priorities:
+ - Policy with a `next_run_at` in the past.
+ - Partially executed policies.
+
+To track the cleanup policy status on a container repository,
+we have an `expiration_policy_cleanup_status` on the `ContainerRepository`
+model.
+
+Background jobs for this execution are organized on:
+
+- A cron background job that runs every hour.
+- A set of background jobs that will loop on container repositories that need
+a policy execution.
+
+#### The cron background job
+
+The [cron background job](https://gitlab.com/gitlab-org/gitlab/-/blob/36454d77a8de76a25896efd7c051d6796985f579/app/workers/container_expiration_policy_worker.rb)
+is quite simple.
+Its main tasks are:
+
+1. Check if there are any container repositories in need of a cleanup. If any,
+enqueue as many limited capacity jobs as necessary, up to a limit.
+1. Compute metrics for cleanup policies and log them.
+
+#### The limited capacity job
+
+This [job](https://gitlab.com/gitlab-org/gitlab/-/blob/36454d77a8de76a25896efd7c051d6796985f579/app/workers/container_expiration_policies/cleanup_container_repository_worker.rb)
+is based on the [limited capacity concern](../sidekiq/limited_capacity_worker.md).
+
+This job will run in parallel up to [a specific capacity](settings.md#container-registry).
+
+The primary responsibility of this job is to select the next container
+repository that requires cleaning and call the related service on it.
+
+This is where the two priorities are evaluated in order. If a container repository
+is found, the cleanup service is called on it.
+
+To ensure that only one cleaning is executed on a given container repository
+at any time, we use a database lock along with the
+`expiration_policy_cleanup_status` column.
+
+This job will re-enqueue itself until no more container repositories require cleanup.
+
+#### Services
+
+Here is the services call that will happen from the limited capacity job:
+
+```mermaid
+flowchart TD
+ job[Limited capacity job] --> cleanup([ContainerExpirationPolicies::CleanupService])
+ cleanup --> cleanup_tags([Projects::ContainerRepository::CleanupTagsService])
+ cleanup_tags --> delete_tags([Projects::ContainerRepository::DeleteTagsService])
+```
+
+- [`ContainerExpirationPolicies::CleanupService`](https://gitlab.com/gitlab-org/gitlab/-/blob/6546ffc6fe4e9b447a1b7f050edddb8926fe4a3d/app/services/container_expiration_policies/cleanup_service.rb).
+This service mainly deals with container repository `expiration_policy_cleanup_status`
+updates and will call the cleanup tags service.
+- [`Projects::ContainerRepository::CleanupTagsService`](https://gitlab.com/gitlab-org/gitlab/-/blob/f23d70b7d638c38d71af102cfd32a3f6751596f9/app/services/projects/container_repository/cleanup_tags_service.rb).
+This service receives the policy parameters and builds the list of tags to
+destroy on the container registry.
+- [`Projects::ContainerRepository::DeleteTagsService`](https://gitlab.com/gitlab-org/gitlab/-/blob/f23d70b7d638c38d71af102cfd32a3f6751596f9/app/services/projects/container_repository/delete_tags_service.rb).
+This service receives a list of tags and loops on that list. For each tag,
+the service will call the container registry API endpoint to destroy the target tag.
+
+The cleanup tags service uses a very specific [execution order](../../user/packages/container_registry/reduce_container_registry_storage.md#how-the-cleanup-policy-works)
+to build the list of tags to destroy.
+
+Lastly, the cleanup tags service and delete tags service work using facades.
+The actual implementation depends on the type of container registry connected.
+If the GitLab container registry is connected, several improvements are available
+and used during cleanup policies execution, such as [better use of the container registry API](https://gitlab.com/groups/gitlab-org/-/epics/8379).
+
+### Historic reference links
+
+- [First iteration](https://gitlab.com/gitlab-org/gitlab/-/issues/15398)
+- [Throttling policy executions](https://gitlab.com/gitlab-org/gitlab/-/issues/208193)
+- [Adding caching](https://gitlab.com/gitlab-org/gitlab/-/issues/339129)
+- [Further improvements](https://gitlab.com/groups/gitlab-org/-/epics/8379)
diff --git a/doc/development/packages/debian_repository.md b/doc/development/packages/debian_repository.md
index 71f6c916652..26a33c548d8 100644
--- a/doc/development/packages/debian_repository.md
+++ b/doc/development/packages/debian_repository.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/development/packages/dependency_proxy.md b/doc/development/packages/dependency_proxy.md
index f3e323fb9fa..d5cc219cba0 100644
--- a/doc/development/packages/dependency_proxy.md
+++ b/doc/development/packages/dependency_proxy.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+group: Container 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
---
@@ -130,7 +130,7 @@ graph TD
A[Receive manifest request] --> | We have the manifest cached.| B{Docker manifest HEAD request}
A --> | We do not have manifest cached.| C{Docker manifest GET request}
B --> | Digest matches the one in the DB | D[Fetch manifest from cache]
- B --> | Network failure, cannot reach DockerHub | D[Fetch manifest from cache]
+ B --> | HEAD request error, network failure, cannot reach DockerHub | D[Fetch manifest from cache]
B --> | Digest does not match the one in DB | C
C --> E[Save manifest to cache, save digest to database]
D --> F
diff --git a/doc/development/packages/index.md b/doc/development/packages/index.md
index 41d6e1b84fd..e6ec7e9654a 100644
--- a/doc/development/packages/index.md
+++ b/doc/development/packages/index.md
@@ -1,15 +1,18 @@
---
stage: Package
-group: Package
+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 Registry Development
+# Package and container registry documentation
-Development and Architectural documentation for the package registry
+The documentation for package and container registry development is split into two groups.
+
+## Package registry development
+
+Development and architectural documentation for the package registry:
- [Debian repository structure](debian_repository.md)
-- [Dependency proxy structure](dependency_proxy.md)
- [Developing a new format](new_format_development.md)
- [Settings](settings.md)
- [Structure / Schema](structure.md)
@@ -25,3 +28,12 @@ Development and Architectural documentation for the package registry
- [NuGet](../../api/packages/nuget.md)
- [PyPI](../../api/packages/pypi.md)
- [Ruby Gems](../../api/packages/rubygems.md)
+
+## Container registry development
+
+Development and architectural documentation for the container registry
+
+- [Dependency proxy structure](dependency_proxy.md)
+- [Settings](settings.md)
+- [Structure / Schema](structure.md)
+- [Cleanup policies](cleanup_policies.md)
diff --git a/doc/development/packages/new_format_development.md b/doc/development/packages/new_format_development.md
index e9decea3094..f730d4f9476 100644
--- a/doc/development/packages/new_format_development.md
+++ b/doc/development/packages/new_format_development.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/development/packages/settings.md b/doc/development/packages/settings.md
index d591f708954..33caa064ab3 100644
--- a/doc/development/packages/settings.md
+++ b/doc/development/packages/settings.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/development/packages/structure.md b/doc/development/packages/structure.md
index e5426f8e2b8..281ec2e6c39 100644
--- a/doc/development/packages/structure.md
+++ b/doc/development/packages/structure.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/development/performance.md b/doc/development/performance.md
index 4f22d9ceb03..3881fad0528 100644
--- a/doc/development/performance.md
+++ b/doc/development/performance.md
@@ -21,8 +21,8 @@ consistent performance of GitLab. Refer to the [Index](#performance-documentatio
- [Query performance guidelines](database/query_performance.md)
- [Pagination performance guidelines](../development/database/pagination_performance_guidelines.md)
- [Keyset pagination performance](../development/database/keyset_pagination.md#performance)
- - [Troubleshooting import/export performance issues](../development/import_export.md#troubleshooting-performance-issues)
- - [Pipelines performance in the `gitlab` project](../development/pipelines.md#performance)
+ - [Troubleshooting import/export performance issues](../user/project/settings/import_export_troubleshooting.md#troubleshooting-performance-issues)
+ - [Pipelines performance in the `gitlab` project](pipelines/performance.md)
- Frontend:
- [Performance guidelines and monitoring](../development/fe_guide/performance.md)
- [Browser performance testing guidelines](../ci/testing/browser_performance_testing.md)
diff --git a/doc/development/pipelines.md b/doc/development/pipelines.md
index 01e42fda2c9..a4e06e98d14 100644
--- a/doc/development/pipelines.md
+++ b/doc/development/pipelines.md
@@ -1,871 +1,11 @@
---
-stage: none
-group: Engineering Productivity
-info: To 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: 'pipelines/index.md'
+remove_date: '2023-01-20'
---
-# Pipelines for the GitLab project
+This document was moved to [another location](pipelines/index.md).
-Pipelines for [`gitlab-org/gitlab`](https://gitlab.com/gitlab-org/gitlab) (as well as the `dev` instance's) is configured in the usual
-[`.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab-ci.yml)
-which itself includes files under
-[`.gitlab/ci/`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/.gitlab/ci)
-for easier maintenance.
-
-We're striving to [dogfood](https://about.gitlab.com/handbook/engineering/development/principles/#dogfooding)
-GitLab [CI/CD features and best-practices](../ci/yaml/index.md)
-as much as possible.
-
-## Minimal test jobs before a merge request is approved
-
-**To reduce the pipeline cost and shorten the job duration, before a merge request is approved, the pipeline will run a minimal set of RSpec & Jest tests that are related to the merge request changes.**
-
-After a merge request has been approved, the pipeline would contain the full RSpec & Jest tests. This will ensure that all tests
-have been run before a merge request is merged.
-
-### Overview of the GitLab project test dependency
-
-To understand how the minimal test jobs are executed, we need to understand the dependency between
-GitLab code (frontend and backend) and the respective tests (Jest and RSpec).
-This dependency can be visualized in the following diagram:
-
-```mermaid
-flowchart LR
- subgraph frontend
- fe["Frontend code"]--tested with-->jest
- end
- subgraph backend
- be["Backend code"]--tested with-->rspec
- end
-
- be--generates-->fixtures["frontend fixtures"]
- fixtures--used in-->jest
-```
-
-In summary:
-
-- RSpec tests are dependent on the backend code.
-- Jest tests are dependent on both frontend and backend code, the latter through the frontend fixtures.
-
-### RSpec minimal jobs
-
-#### Determining related RSpec test files in a merge request
-
-To identify the minimal set of tests needed, we use the [`test_file_finder` gem](https://gitlab.com/gitlab-org/ci-cd/test_file_finder), with two strategies:
-
-- dynamic mapping from test coverage tracing (generated via the [`Crystalball` gem](https://github.com/toptal/crystalball))
- ([see where it's used](https://gitlab.com/gitlab-org/gitlab/-/blob/47d507c93779675d73a05002e2ec9c3c467cd698/tooling/bin/find_tests#L15))
-- static mapping maintained in the [`tests.yml` file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/tests.yml) for special cases that cannot
- be mapped via coverage tracing ([see where it's used](https://gitlab.com/gitlab-org/gitlab/-/blob/47d507c93779675d73a05002e2ec9c3c467cd698/tooling/bin/find_tests#L12))
-
-The test mappings contain a map of each source files to a list of test files which is dependent of the source file.
-
-In the `detect-tests` job, we use this mapping to identify the minimal tests needed for the current merge request.
-
-Later on in [the `rspec fail-fast` job](#fail-fast-job-in-merge-request-pipelines), we run the minimal tests needed for the current merge request.
-
-#### Exceptional cases
-
-In addition, there are a few circumstances where we would always run the full RSpec tests:
-
-- when the `pipeline:run-all-rspec` label is set on the merge request
-- when the `pipeline:run-full-rspec` label is set on the merge request, this label is assigned by triage automation when the merge request is approved by any reviewer
-- when the merge request is created by an automation (for example, Gitaly update or MR targeting a stable branch)
-- when the merge request is created in a security mirror
-- when any CI configuration file is changed (for example, `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
-
-### Jest minimal jobs
-
-#### Determining related Jest test files in a merge request
-
-To identify the minimal set of tests needed, we pass a list of all the changed files into `jest` using the [`--findRelatedTests`](https://jestjs.io/docs/cli#--findrelatedtests-spaceseparatedlistofsourcefiles) option.
-In this mode, `jest` would resolve all the dependencies of related to the changed files, which include test files that have these files in the dependency chain.
-
-#### Exceptional cases
-
-In addition, there are a few circumstances where we would always run the full Jest tests:
-
-- when the `pipeline:run-all-jest` label is set on the merge request
-- when the merge request is created by an automation (for example, Gitaly update or MR targeting a stable branch)
-- when the merge request is created in a security mirror
-- when any CI configuration file is changed (for example, `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
-- when any frontend "core" file is changed (for example, `package.json`, `yarn.lock`, `babel.config.js`, `jest.config.*.js`, `config/helpers/**/*.js`)
-- when any vendored JavaScript file is changed (for example, `vendor/assets/javascripts/**/*`)
-- when any backend file is changed ([see the patterns list for details](https://gitlab.com/gitlab-org/gitlab/-/blob/3616946936c1adbd9e754c1bd06f86ba670796d8/.gitlab/ci/rules.gitlab-ci.yml#L205-216))
-
-### Fork pipelines
-
-We run only the minimal 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).
-
-## Fail-fast job in merge request pipelines
-
-To provide faster feedback when a merge request breaks existing tests, we are experimenting with a
-fail-fast mechanism.
-
-An `rspec fail-fast` job is added in parallel to all other `rspec` jobs in a merge
-request pipeline. This job runs the tests that are directly related to the changes
-in the merge request.
-
-If any of these tests fail, the `rspec fail-fast` job fails, triggering a
-`fail-pipeline-early` job to run. The `fail-pipeline-early` job:
-
-- Cancels the currently running pipeline and all in-progress jobs.
-- Sets pipeline to have status `failed`.
-
-For example:
-
-```mermaid
-graph LR
- subgraph "prepare stage";
- A["detect-tests"]
- end
-
- subgraph "test stage";
- B["jest"];
- C["rspec migration"];
- D["rspec unit"];
- E["rspec integration"];
- F["rspec system"];
- G["rspec fail-fast"];
- end
-
- subgraph "post-test stage";
- Z["fail-pipeline-early"];
- end
-
- A --"artifact: list of test files"--> G
- G --"on failure"--> Z
-```
-
-The `rspec fail-fast` is a no-op if there are more than 10 test files related to the
-merge request. This prevents `rspec fail-fast` duration from exceeding the average
-`rspec` job duration and defeating its purpose.
-
-This number can be overridden by setting a CI/CD variable named `RSPEC_FAIL_FAST_TEST_FILE_COUNT_THRESHOLD`.
-
-## Faster feedback when reverting merge requests
-
-When you need to revert a merge request, to get accelerated feedback, you can add the `~pipeline:revert` label to your merge request.
-
-When this label is assigned, the following steps of the CI/CD pipeline are skipped:
-
-- The `e2e:package-and-test` job.
-- The `rspec:undercoverage` job.
-- The entire [Review Apps process](testing_guide/review_apps.md).
-
-Apply the label to the merge request, and run a new pipeline for the MR.
-
-## Test jobs
-
-We have dedicated jobs for each [testing level](testing_guide/testing_levels.md) and each job runs depending on the
-changes made in your merge request.
-If you want to force all the RSpec jobs to run regardless of your changes, you can add the `pipeline:run-all-rspec` label to the merge request.
-
-WARNING:
-Forcing all jobs on docs only related MRs would not have the prerequisite jobs and would lead to errors
-
-### Test suite parallelization
-
-Our current RSpec tests parallelization setup is as follows:
-
-1. The `retrieve-tests-metadata` job in the `prepare` stage ensures we have a
- `knapsack/report-master.json` file:
- - The `knapsack/report-master.json` file is fetched from the latest `main` pipeline which runs `update-tests-metadata`
- (for now it's the 2-hourly `maintenance` scheduled master pipeline), if it's not here we initialize the file with `{}`.
-1. Each `[rspec|rspec-ee] [migration|unit|integration|system|geo] n m` job are run with
- `knapsack rspec` and should have an evenly distributed share of tests:
- - It works because the jobs have access to the `knapsack/report-master.json`
- since the "artifacts from all previous stages are passed by default".
- - the jobs set their own report path to
- `"knapsack/${TEST_TOOL}_${TEST_LEVEL}_${DATABASE}_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json"`.
- - if knapsack is doing its job, test files that are run should be listed under
- `Report specs`, not under `Leftover specs`.
-1. The `update-tests-metadata` job (which only runs on scheduled pipelines for
- [the canonical project](https://gitlab.com/gitlab-org/gitlab) takes all the
- `knapsack/rspec*.json` files and merge them all together into a single
- `knapsack/report-master.json` file that is saved as artifact.
-
-After that, the next pipeline uses the up-to-date `knapsack/report-master.json` file.
-
-### Flaky tests
-
-#### Automatic skipping of flaky tests
-
-Tests that are [known to be flaky](testing_guide/flaky_tests.md#automatic-retries-and-flaky-tests-detection) are
-skipped unless the `$SKIP_FLAKY_TESTS_AUTOMATICALLY` variable is set to `false` or if the `~"pipeline:run-flaky-tests"`
-label is set on the MR.
-
-See the [experiment issue](https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/1069).
-
-#### Automatic retry of failing tests in a separate process
-
-Unless `$RETRY_FAILED_TESTS_IN_NEW_PROCESS` variable is set to `false` (`true` by default), RSpec tests that failed are automatically retried once in a separate
-RSpec process. The goal is to get rid of most side-effects from previous tests that may lead to a subsequent test failure.
-
-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).
-
-### Single database testing
-
-By default, all tests run with [multiple databases](database/multiple_databases.md).
-
-We also run tests with a single database in nightly scheduled pipelines, and in merge requests that touch database-related files.
-
-If you want to force tests to run with a single database, you can add the `pipeline:run-single-db` label to the merge request.
-
-### Monitoring
-
-The GitLab test suite is [monitored](performance.md#rspec-profiling) for the `main` branch, and any branch
-that includes `rspec-profile` in their name.
-
-### Logging
-
-- Rails logging to `log/test.log` is disabled by default in CI
- [for performance reasons](https://jtway.co/speed-up-your-rails-test-suite-by-6-in-1-line-13fedb869ec4).
- To override this setting, provide the
- `RAILS_ENABLE_TEST_LOG` environment variable.
-
-## Review app jobs
-
-Consult the [Review Apps](testing_guide/review_apps.md) dedicated page for more information.
-
-If you want to force a Review App to be deployed regardless of your changes, you can add the `pipeline:run-review-app` label to the merge request.
-
-## As-if-FOSS jobs
-
-The `* as-if-foss` jobs run the GitLab test suite "as if FOSS", meaning as if the jobs would run in the context
-of `gitlab-org/gitlab-foss`. These jobs are only created in the following cases:
-
-- when the `pipeline:run-as-if-foss` label is set on the merge request
-- when the merge request is created in the `gitlab-org/security/gitlab` project
-- when any CI configuration file is changed (for example, `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
-
-The `* as-if-foss` jobs are run in addition to the regular EE-context jobs. They have the `FOSS_ONLY='1'` variable
-set and get the `ee/` folder removed before the tests start running.
-
-The intent is to ensure that a change doesn't introduce a failure after `gitlab-org/gitlab` is synced to `gitlab-org/gitlab-foss`.
-
-## As-if-JH jobs
-
-NOTE:
-This is disabled for now.
-
-The `* as-if-jh` jobs run the GitLab test suite "as if JiHu", meaning as if the jobs would run in the context
-of [GitLab JH](jh_features_review.md). These jobs are only created in the following cases:
-
-- when the `pipeline:run-as-if-jh` label is set on the merge request
-- when the `pipeline:run-all-rspec` label is set on the merge request
-- when any code or backstage file is changed
-- when any startup CSS file is changed
-
-The `* as-if-jh` jobs are run in addition to the regular EE-context jobs. The `jh/` folder is added before the tests start running.
-
-The intent is to ensure that a change doesn't introduce a failure after `gitlab-org/gitlab` is synced to [GitLab JH](https://jihulab.com/gitlab-cn/gitlab).
-
-### When to consider applying `pipeline:run-as-if-jh` label
-
-NOTE:
-This is disabled for now.
-
-If a Ruby file is renamed and there's a corresponding [`prepend_mod` line](jh_features_review.md#jh-features-based-on-ce-or-ee-features),
-it's likely that GitLab JH is relying on it and requires a corresponding
-change to rename the module or class it's prepending.
-
-### Corresponding JH branch
-
-NOTE:
-This is disabled for now.
-
-You can create a corresponding JH branch on [GitLab JH](https://jihulab.com/gitlab-cn/gitlab) by
-appending `-jh` to the branch name. If a corresponding JH branch is found,
-`* as-if-jh` jobs grab the `jh` folder from the respective branch,
-rather than from the default branch `main-jh`.
-
-NOTE:
-For now, CI will try to fetch the branch on the [GitLab JH mirror](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab), so it might take some time for the new JH branch to propagate to the mirror.
-
-## Ruby 3.0 jobs
-
-You can add the `pipeline:run-in-ruby3` label to the merge request to switch
-the Ruby version used for running the whole test suite to 3.0. When you do
-this, the test suite will no longer run in Ruby 2.7 (default), and an
-additional job `verify-ruby-2.7` will also run and always fail to remind us to
-remove the label and run in Ruby 2.7 before merging the merge request.
-
-This should let us:
-
-- Test changes for Ruby 3.0
-- Make sure it will not break anything when it's merged into the default branch
-
-## `undercover` RSpec test
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74859) in GitLab 14.6.
-
-The `rspec:undercoverage` job runs [`undercover`](https://rubygems.org/gems/undercover)
-to detect, and fail if any changes introduced in the merge request has zero coverage.
-
-The `rspec:undercoverage` job obtains coverage data from the `rspec:coverage`
-job.
-
-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.
-
-### Troubleshooting `rspec:undercoverage` failures
-
-The `rspec:undercoverage` job has [known bugs](https://gitlab.com/groups/gitlab-org/-/epics/8254)
-that can cause false positive failures. You can test coverage locally to determine if it's
-safe to apply `~"pipeline:skip-undercoverage"`. For example, using `<spec>` as the name of the
-test causing the failure:
-
-1. Run `SIMPLECOV=1 bundle exec rspec <spec>`.
-1. Run `scripts/undercoverage`.
-
-If these commands return `undercover: ✅ No coverage is missing in latest changes` then you can apply `~"pipeline:skip-undercoverage"` to bypass pipeline failures.
-
-## Ruby versions testing
-
-Our test suite runs against Ruby 2 in merge requests and default branch pipelines.
-
-We also run our test suite against Ruby 3 on another 2-hourly scheduled pipelines, as GitLab.com will soon run on Ruby 3.
-
-## PostgreSQL versions testing
-
-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).
-
-### Current versions testing
-
-| Where? | PostgreSQL version | Ruby version |
-|------------------------------------------------------------------------------------------------|-------------------------------------------------|--------------|
-| Merge requests | 12 (default version), 11 for DB library changes | 2.7 (default version) |
-| `master` branch commits | 12 (default version), 11 for DB library changes | 2.7 (default version) |
-| `maintenance` scheduled pipelines for the `master` branch (every even-numbered hour) | 12 (default version), 11 for DB library changes | 2.7 (default version) |
-| `maintenance` scheduled pipelines for the `ruby3` branch (every odd-numbered hour), see below. | 12 (default version), 11 for DB library changes | 3.0 (coded in the branch) |
-| `nightly` scheduled pipelines for the `master` branch | 12 (default version), 11, 13 | 2.7 (default version) |
-
-The pipeline configuration for the scheduled pipeline testing Ruby 3 is
-stored in the `ruby3-sync` branch. The pipeline updates the `ruby3` branch
-with latest `master`, and then it triggers a regular branch pipeline for
-`ruby3`. Any changes in `ruby3` are only for running the pipeline. It should
-never be merged back to `master`. Any other Ruby 3 changes should go into
-`master` directly, which should be compatible with Ruby 2.7.
-
-Previously, `ruby3-sync` was using a project token stored in `RUBY3_SYNC_TOKEN`
-(now backed up in `RUBY3_SYNC_TOKEN_NOT_USED`), however due to various
-permissions issues, we ended up using an access token from `gitlab-bot` so now
-`RUBY3_SYNC_TOKEN` is actually an access token from `gitlab-bot`.
-
-### Long-term plan
-
-We follow the [PostgreSQL versions shipped with Omnibus GitLab](../administration/package_information/postgresql_versions.md):
-
-| 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
-
-Our test suite runs against Redis 6 as GitLab.com runs on Redis 6 and
-[Omnibus defaults to Redis 6 for new installs and upgrades](https://gitlab.com/gitlab-org/omnibus-gitlab/-/blob/master/config/software/redis.rb).
-
-We do run our test suite against Redis 5 on `nightly` scheduled pipelines, specifically when running backward-compatible and forward-compatible PostgreSQL jobs.
-
-### Current versions testing
-
-| Where? | Redis version |
-| ------ | ------------------ |
-| MRs | 6 |
-| `default branch` (non-scheduled pipelines) | 6 |
-| `nightly` scheduled pipelines | 5 |
-
-## Pipelines types for merge requests
-
-In general, pipelines for an MR fall into one of the following types (from shorter to longer), depending on the changes made in the MR:
-
-- [Documentation pipeline](#documentation-pipeline): For MRs that touch documentation.
-- [Backend pipeline](#backend-pipeline): For MRs that touch backend code.
-- [Frontend pipeline](#frontend-pipeline): For MRs that touch frontend code.
-- [End-to-end pipeline](#end-to-end-pipeline): For MRs that touch code in the `qa/` folder.
-
-A "pipeline type" is an abstract term that mostly describes the "critical path" (for example, the chain of jobs for which the sum
-of individual duration equals the pipeline's duration).
-We use these "pipeline types" in [metrics dashboards](https://app.periscopedata.com/app/gitlab/858266/GitLab-Pipeline-Durations) to detect what types and jobs need to be optimized first.
-
-An MR that touches multiple areas would be associated with the longest type applicable. For instance, an MR that touches backend
-and frontend would fall into the "Frontend" pipeline type since this type takes longer to finish than the "Backend" pipeline type.
-
-We use the [`rules:`](../ci/yaml/index.md#rules) and [`needs:`](../ci/yaml/index.md#needs) keywords extensively
-to determine the jobs that need to be run in a pipeline. Note that an MR that includes multiple types of changes would
-have a pipelines that include jobs from multiple types (for example, a combination of docs-only and code-only pipelines).
-
-Following are graphs of the critical paths for each pipeline type. Jobs that aren't part of the critical path are omitted.
-
-### Documentation pipeline
-
-[Reference pipeline](https://gitlab.com/gitlab-org/gitlab/-/pipelines/432049110).
-
-```mermaid
-graph LR
- classDef criticalPath fill:#f66;
-
- 1-3["docs-lint links (5 minutes)"];
- class 1-3 criticalPath;
- click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356757&udv=0"
-```
-
-### Backend pipeline
-
-[Reference pipeline](https://gitlab.com/gitlab-org/gitlab/-/pipelines/433316063).
-
-```mermaid
-graph RL;
- classDef criticalPath fill:#f66;
-
- 1-3["compile-test-assets (6 minutes)"];
- class 1-3 criticalPath;
- click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914317&udv=0"
- 1-6["setup-test-env (4 minutes)"];
- click 1-6 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914315&udv=0"
- 1-14["retrieve-tests-metadata"];
- click 1-14 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356697&udv=0"
- 1-15["detect-tests"];
- click 1-15 "https://app.periscopedata.com/app/gitlab/652085/EP---Jobs-Durations?widget=10113603&udv=1005715"
-
- 2_5-1["rspec & db jobs (24 minutes)"];
- class 2_5-1 criticalPath;
- click 2_5-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations"
- 2_5-1 --> 1-3 & 1-6 & 1-14 & 1-15;
-
- 3_2-1["rspec:coverage (5.35 minutes)"];
- class 3_2-1 criticalPath;
- click 3_2-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7248745&udv=0"
- 3_2-1 -.->|"(don't use needs<br/>because of limitations)"| 2_5-1;
-
- 4_3-1["rspec:undercoverage (3.5 minutes)"];
- class 4_3-1 criticalPath;
- click 4_3-1 "https://app.periscopedata.com/app/gitlab/652085/EP---Jobs-Durations?widget=13446492&udv=1005715"
- 4_3-1 --> 3_2-1;
-
-```
-
-### Frontend pipeline
-
-[Reference pipeline](https://gitlab.com/gitlab-org/gitlab/-/pipelines/431913287).
-
-```mermaid
-graph RL;
- classDef criticalPath fill:#f66;
-
- 1-2["build-qa-image (2 minutes)"];
- click 1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914325&udv=0"
- 1-5["compile-production-assets (16 minutes)"];
- class 1-5 criticalPath;
- click 1-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914312&udv=0"
-
- 2_3-1["build-assets-image (1.3 minutes)"];
- class 2_3-1 criticalPath;
- 2_3-1 --> 1-5
-
- 2_6-1["start-review-app-pipeline (49 minutes)"];
- class 2_6-1 criticalPath;
- click 2_6-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations"
- 2_6-1 --> 2_3-1 & 1-2;
-```
-
-### End-to-end pipeline
-
-[Reference pipeline](https://gitlab.com/gitlab-org/gitlab/-/pipelines/431918463).
-
-```mermaid
-graph RL;
- classDef criticalPath fill:#f66;
-
- 1-2["build-qa-image (2 minutes)"];
- click 1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914325&udv=0"
- 1-5["compile-production-assets (16 minutes)"];
- class 1-5 criticalPath;
- click 1-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914312&udv=0"
- 1-15["detect-tests"];
- click 1-15 "https://app.periscopedata.com/app/gitlab/652085/EP---Jobs-Durations?widget=10113603&udv=1005715"
-
- 2_3-1["build-assets-image (1.3 minutes)"];
- class 2_3-1 criticalPath;
- 2_3-1 --> 1-5
-
- 2_4-1["e2e:package-and-test (102 minutes)"];
- class 2_4-1 criticalPath;
- click 2_4-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914305&udv=0"
- 2_4-1 --> 1-2 & 2_3-1 & 1-15;
-```
-
-## CI configuration internals
-
-### Workflow rules
-
-Pipelines for the GitLab project are created using the [`workflow:rules` keyword](../ci/yaml/index.md#workflow)
-feature of the GitLab CI/CD.
-
-Pipelines are always created for the following scenarios:
-
-- `main` branch, including on schedules, pushes, merges, and so on.
-- Merge requests.
-- Tags.
-- Stable, `auto-deploy`, and security branches.
-
-Pipeline creation is also affected by the following CI/CD variables:
-
-- If `$FORCE_GITLAB_CI` is set, pipelines are created.
-- If `$GITLAB_INTERNAL` is not set, pipelines are not created.
-
-No pipeline is created in any other cases (for example, when pushing a branch with no
-MR for it).
-
-The source of truth for these workflow rules is defined in [`.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab-ci.yml).
-
-### Default image
-
-The default image is defined in [`.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab-ci.yml).
-
-<!-- vale gitlab.Spelling = NO -->
-
-It includes Ruby, Go, Git, Git LFS, Chrome, Node, Yarn, PostgreSQL, and Graphics Magick.
-
-<!-- vale gitlab.Spelling = YES -->
-
-The images used in our pipelines are configured in the
-[`gitlab-org/gitlab-build-images`](https://gitlab.com/gitlab-org/gitlab-build-images)
-project, which is push-mirrored to [`gitlab/gitlab-build-images`](https://dev.gitlab.org/gitlab/gitlab-build-images)
-for redundancy.
-
-The current version of the build images can be found in the
-["Used by GitLab section"](https://gitlab.com/gitlab-org/gitlab-build-images/blob/master/.gitlab-ci.yml).
-
-### Default variables
-
-In addition to the [predefined CI/CD variables](../ci/variables/predefined_variables.md),
-each pipeline includes default variables defined in
-[`.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab-ci.yml).
-
-### Stages
-
-The current stages are:
-
-- `sync`: This stage is used to synchronize changes from [`gitlab-org/gitlab`](https://gitlab.com/gitlab-org/gitlab) to
- [`gitlab-org/gitlab-foss`](https://gitlab.com/gitlab-org/gitlab-foss).
-- `prepare`: This stage includes jobs that prepare artifacts that are needed by
- jobs in subsequent stages.
-- `build-images`: This stage includes jobs that prepare Docker images
- that are needed by jobs in subsequent stages or downstream pipelines.
-- `fixtures`: This stage includes jobs that prepare fixtures needed by frontend tests.
-- `lint`: This stage includes linting and static analysis jobs.
-- `test`: This stage includes most of the tests, and DB/migration jobs.
-- `post-test`: This stage includes jobs that build reports or gather data from
- the `test` stage's jobs (for example, coverage, Knapsack metadata, and so on).
-- `review`: This stage includes jobs that build the CNG images, deploy them, and
- run end-to-end tests against Review Apps (see [Review Apps](testing_guide/review_apps.md) for details).
- It also includes Docs Review App jobs.
-- `qa`: This stage includes jobs that perform QA tasks against the Review App
- that is deployed in stage `review`.
-- `post-qa`: This stage includes jobs that build reports or gather data from
- the `qa` stage's jobs (for example, Review App performance report).
-- `pages`: This stage includes a job that deploys the various reports as
- GitLab Pages (for example, [`coverage-ruby`](https://gitlab-org.gitlab.io/gitlab/coverage-ruby/),
- and `webpack-report` (found at `https://gitlab-org.gitlab.io/gitlab/webpack-report/`, but there is
- [an issue with the deployment](https://gitlab.com/gitlab-org/gitlab/-/issues/233458)).
-- `notify`: This stage includes jobs that notify various failures to Slack.
-
-### Dependency Proxy
-
-Some of the jobs are using images from Docker Hub, where we also use
-`${GITLAB_DEPENDENCY_PROXY_ADDRESS}` as a prefix to the image path, so that we pull
-images from our [Dependency Proxy](../user/packages/dependency_proxy/index.md).
-By default, this variable is set from the value of `${GITLAB_DEPENDENCY_PROXY}`.
-
-`${GITLAB_DEPENDENCY_PROXY}` is a group CI/CD variable defined in
-[`gitlab-org`](https://gitlab.com/gitlab-org) as
-`${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/`. This means when we use an image
-defined as:
-
-```yaml
-image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}alpine:edge
-```
-
-Projects in the `gitlab-org` group pull from the Dependency Proxy, while
-forks that reside on any other personal namespaces or groups fall back to
-Docker Hub unless `${GITLAB_DEPENDENCY_PROXY}` is also defined there.
-
-#### Work around for when a pipeline is started by a Project access token user
-
-When a pipeline is started by a Project access token user (e.g. the `release-tools approver bot` user which
-automatically updates the Gitaly version used in the main project),
-[the Dependency proxy isn't accessible](https://gitlab.com/gitlab-org/gitlab/-/issues/332411#note_1130388163)
-and the job fails at the `Preparing the "docker+machine" executor` step.
-To work around that, we have a special workflow rule, that overrides the
-`${GITLAB_DEPENDENCY_PROXY_ADDRESS}` variable so that Depdendency proxy isn't used in that case:
-
-```yaml
-- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $GITLAB_USER_LOGIN =~ /project_\d+_bot\d*/'
- variables:
- GITLAB_DEPENDENCY_PROXY_ADDRESS: ""
-```
-
-NOTE:
-We don't directly override the `${GITLAB_DEPENDENCY_PROXY}` variable because group-level
-variables have higher precedence over `.gitlab-ci.yml` variables.
-
-### Common job definitions
-
-Most of the jobs [extend from a few CI definitions](../ci/yaml/index.md#extends)
-defined in [`.gitlab/ci/global.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/global.gitlab-ci.yml)
-that are scoped to a single [configuration keyword](../ci/yaml/index.md#job-keywords).
-
-| Job definitions | Description |
-|------------------|-------------|
-| `.default-retry` | Allows a job to [retry](../ci/yaml/index.md#retry) upon `unknown_failure`, `api_failure`, `runner_system_failure`, `job_execution_timeout`, or `stuck_or_timeout_failure`. |
-| `.default-before_script` | Allows a job to use a default `before_script` definition suitable for Ruby/Rails tasks that may need a database running (for example, tests). |
-| `.setup-test-env-cache` | Allows a job to use a default `cache` definition suitable for setting up test environment for subsequent Ruby/Rails tasks. |
-| `.rails-cache` | Allows a job to use a default `cache` definition suitable for Ruby/Rails tasks. |
-| `.static-analysis-cache` | Allows a job to use a default `cache` definition suitable for static analysis tasks. |
-| `.coverage-cache` | Allows a job to use a default `cache` definition suitable for coverage tasks. |
-| `.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). |
-| `.use-pg13-ee` | Same as `.use-pg13` but also use an `elasticsearch` service (see [`.gitlab/ci/global.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/global.gitlab-ci.yml) for the specific version of the service). |
-| `.use-kaniko` | Allows a job to use the `kaniko` tool to build Docker images. |
-| `.as-if-foss` | Simulate the FOSS project by setting the `FOSS_ONLY='1'` CI/CD variable. |
-| `.use-docker-in-docker` | Allows a job to use Docker in Docker. |
-
-### `rules`, `if:` conditions and `changes:` patterns
-
-We're using the [`rules` keyword](../ci/yaml/index.md#rules) extensively.
-
-All `rules` definitions are defined in
-[`rules.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/rules.gitlab-ci.yml),
-then included in individual jobs via [`extends`](../ci/yaml/index.md#extends).
-
-The `rules` definitions are composed of `if:` conditions and `changes:` patterns,
-which are also defined in
-[`rules.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/rules.gitlab-ci.yml)
-and included in `rules` definitions via [YAML anchors](../ci/yaml/yaml_optimization.md#anchors)
-
-#### `if:` conditions
-
-<!-- vale gitlab.Substitutions = NO -->
-
-| `if:` conditions | Description | Notes |
-|------------------|-------------|-------|
-| `if-not-canonical-namespace` | Matches if the project isn't in the canonical (`gitlab-org/`) or security (`gitlab-org/security`) namespace. | Use to create a job for forks (by using `when: on_success|manual`), or **not** create a job for forks (by using `when: never`). |
-| `if-not-ee` | Matches if the project isn't EE (that is, project name isn't `gitlab` or `gitlab-ee`). | Use to create a job only in the FOSS project (by using `when: on_success|manual`), or **not** create a job if the project is EE (by using `when: never`). |
-| `if-not-foss` | Matches if the project isn't FOSS (that is, project name isn't `gitlab-foss`, `gitlab-ce`, or `gitlabhq`). | Use to create a job only in the EE project (by using `when: on_success|manual`), or **not** create a job if the project is FOSS (by using `when: never`). |
-| `if-default-refs` | Matches if the pipeline is for `master`, `main`, `/^[\d-]+-stable(-ee)?$/` (stable branches), `/^\d+-\d+-auto-deploy-\d+$/` (auto-deploy branches), `/^security\//` (security branches), merge requests, and tags. | Note that jobs aren't created for branches with this default configuration. |
-| `if-master-refs` | Matches if the current branch is `master` or `main`. | |
-| `if-master-push` | Matches if the current branch is `master` or `main` and pipeline source is `push`. | |
-| `if-master-schedule-maintenance` | Matches if the current branch is `master` or `main` and pipeline runs on a 2-hourly schedule. | |
-| `if-master-schedule-nightly` | Matches if the current branch is `master` or `main` and pipeline runs on a nightly schedule. | |
-| `if-auto-deploy-branches` | Matches if the current branch is an auto-deploy one. | |
-| `if-master-or-tag` | Matches if the pipeline is for the `master` or `main` branch or for a tag. | |
-| `if-merge-request` | Matches if the pipeline is for a merge request. | |
-| `if-merge-request-title-as-if-foss` | Matches if the pipeline is for a merge request and the MR has label ~"pipeline:run-as-if-foss" | |
-| `if-merge-request-title-update-caches` | Matches if the pipeline is for a merge request and the MR has label ~"pipeline:update-cache". | |
-| `if-merge-request-title-run-all-rspec` | Matches if the pipeline is for a merge request and the MR has label ~"pipeline:run-all-rspec". | |
-| `if-security-merge-request` | Matches if the pipeline is for a security merge request. | |
-| `if-security-schedule` | Matches if the pipeline is for a security scheduled pipeline. | |
-| `if-nightly-master-schedule` | Matches if the pipeline is for a `master` scheduled pipeline with `$NIGHTLY` set. | |
-| `if-dot-com-gitlab-org-schedule` | Limits jobs creation to scheduled pipelines for the `gitlab-org` group on GitLab.com. | |
-| `if-dot-com-gitlab-org-master` | Limits jobs creation to the `master` or `main` branch for the `gitlab-org` group on GitLab.com. | |
-| `if-dot-com-gitlab-org-merge-request` | Limits jobs creation to merge requests for the `gitlab-org` group on GitLab.com. | |
-| `if-dot-com-gitlab-org-and-security-tag` | Limits job creation to tags for the `gitlab-org` and `gitlab-org/security` groups on GitLab.com. | |
-| `if-dot-com-gitlab-org-and-security-merge-request` | Limit jobs creation to merge requests for the `gitlab-org` and `gitlab-org/security` groups on GitLab.com. | |
-| `if-dot-com-gitlab-org-and-security-tag` | Limit jobs creation to tags for the `gitlab-org` and `gitlab-org/security` groups on GitLab.com. | |
-| `if-dot-com-ee-schedule` | Limits jobs to scheduled pipelines for the `gitlab-org/gitlab` project on GitLab.com. | |
-| `if-security-pipeline-merge-result` | Matches if the pipeline is for a security merge request triggered by `@gitlab-release-tools-bot`. | |
-
-<!-- vale gitlab.Substitutions = YES -->
-
-#### `changes:` patterns
-
-| `changes:` patterns | Description |
-|------------------------------|--------------------------------------------------------------------------|
-| `ci-patterns` | Only create job for CI configuration-related changes. |
-| `ci-build-images-patterns` | Only create job for CI configuration-related changes related to the `build-images` stage. |
-| `ci-review-patterns` | Only create job for CI configuration-related changes related to the `review` stage. |
-| `ci-qa-patterns` | Only create job for CI configuration-related changes related to the `qa` stage. |
-| `yaml-lint-patterns` | Only create job for YAML-related changes. |
-| `docs-patterns` | Only create job for docs-related changes. |
-| `frontend-dependency-patterns` | Only create job when frontend dependencies are updated (that is, `package.json`, and `yarn.lock`). changes. |
-| `frontend-patterns` | Only create job for frontend-related changes. |
-| `backend-patterns` | Only create job for backend-related changes. |
-| `db-patterns` | Only create job for DB-related changes. |
-| `backstage-patterns` | Only create job for backstage-related changes (that is, Danger, fixtures, RuboCop, specs). |
-| `code-patterns` | Only create job for code-related changes. |
-| `qa-patterns` | Only create job for QA-related changes. |
-| `code-backstage-patterns` | Combination of `code-patterns` and `backstage-patterns`. |
-| `code-qa-patterns` | Combination of `code-patterns` and `qa-patterns`. |
-| `code-backstage-qa-patterns` | Combination of `code-patterns`, `backstage-patterns`, and `qa-patterns`. |
-| `static-analysis-patterns` | Only create jobs for Static Analytics configuration-related changes. |
-
-## Performance
-
-### Interruptible pipelines
-
-By default, all jobs are [interruptible](../ci/yaml/index.md#interruptible), except the
-`dont-interrupt-me` job which runs automatically on `main`, and is `manual`
-otherwise.
-
-If you want a running pipeline to finish even if you push new commits to a merge
-request, be sure to start the `dont-interrupt-me` job before pushing.
-
-### Git fetch caching
-
-Because GitLab.com uses the [pack-objects cache](../administration/gitaly/configure_gitaly.md#pack-objects-cache),
-concurrent Git fetches of the same pipeline ref are deduplicated on
-the Gitaly server (always) and served from cache (when available).
-
-This works well for the following reasons:
-
-- The pack-objects cache is enabled on all Gitaly servers on GitLab.com.
-- The CI/CD [Git strategy setting](../ci/pipelines/settings.md#choose-the-default-git-strategy) for `gitlab-org/gitlab` is **Git clone**,
- causing all jobs to fetch the same data, which maximizes the cache hit ratio.
-- We use [shallow clone](../ci/pipelines/settings.md#limit-the-number-of-changes-fetched-during-clone) to avoid downloading the full Git
- history for every job.
-
-### Caching strategy
-
-1. All jobs must only pull caches by default.
-1. All jobs must be able to pass with an empty cache. In other words, caches are only there to speed up jobs.
-1. We currently have several different cache definitions defined in
- [`.gitlab/ci/global.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/global.gitlab-ci.yml),
- with fixed keys:
- - `.setup-test-env-cache`
- - `.ruby-cache`
- - `.rails-cache`
- - `.static-analysis-cache`
- - `.rubocop-cache`
- - `.coverage-cache`
- - `.ruby-node-cache`
- - `.qa-cache`
- - `.yarn-cache`
- - `.assets-compile-cache` (the key includes `${NODE_ENV}` so it's actually two different caches).
-1. These cache definitions are composed of [multiple atomic caches](../ci/caching/index.md#use-multiple-caches).
-1. Only the following jobs, running in 2-hourly `maintenance` scheduled pipelines, are pushing (that is, updating) to the caches:
- - `update-setup-test-env-cache`, defined in [`.gitlab/ci/rails.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/rails.gitlab-ci.yml).
- - `update-gitaly-binaries-cache`, defined in [`.gitlab/ci/rails.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/rails.gitlab-ci.yml).
- - `update-rubocop-cache`, defined in [`.gitlab/ci/rails.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/rails.gitlab-ci.yml).
- - `update-qa-cache`, defined in [`.gitlab/ci/qa.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/qa.gitlab-ci.yml).
- - `update-assets-compile-production-cache`, defined in [`.gitlab/ci/frontend.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/frontend.gitlab-ci.yml).
- - `update-assets-compile-test-cache`, defined in [`.gitlab/ci/frontend.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/frontend.gitlab-ci.yml).
- - `update-yarn-cache`, defined in [`.gitlab/ci/frontend.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/frontend.gitlab-ci.yml).
- - `update-storybook-yarn-cache`, defined in [`.gitlab/ci/frontend.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/frontend.gitlab-ci.yml).
-1. These jobs can also be forced to run in merge requests with the `pipeline:update-cache` label (this can be useful to warm the caches in a MR that updates the cache keys).
-
-### Artifacts strategy
-
-We limit the artifacts that are saved and retrieved by jobs to the minimum to reduce the upload/download time and costs, as well as the artifacts storage.
-
-### Components caching
-
-Some external components (GitLab Workhorse and frontend assets) of GitLab need to be built from source as a preliminary step for running tests.
-
-#### `cache-workhorse`
-
-In [this MR](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79766), and then
-[this MR](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96297),
-we introduced a new `cache-workhorse` job that:
-
-- runs automatically for all GitLab.com `gitlab-org/gitlab` scheduled pipelines
-- runs automatically for any `master` commit that touches the `workhorse/` folder
-- is manual for GitLab.com's `gitlab-org`'s MRs that touches caching-related files
-
-This job tries to download a generic package that contains GitLab Workhorse binaries needed in the GitLab test suite (under `tmp/tests/gitlab-workhorse`).
-
-- If the package URL returns a 404:
- 1. It runs `scripts/setup-test-env`, so that the GitLab Workhorse binaries are built.
- 1. It then creates an archive which contains the binaries and upload it [as a generic package](https://gitlab.com/gitlab-org/gitlab/-/packages/).
-- Otherwise, if the package already exists, it exits the job successfully.
-
-We also changed the `setup-test-env` job to:
-
-1. First download the GitLab Workhorse generic package build and uploaded by `cache-workhorse`.
-1. If the package is retrieved successfully, its content is placed in the right folder (for example, `tmp/tests/gitlab-workhorse`), preventing the building of the binaries when `scripts/setup-test-env` is run later on.
-1. If the package URL returns a 404, the behavior doesn't change compared to the current one: the GitLab Workhorse binaries are built as part of `scripts/setup-test-env`.
-
-NOTE:
-The version of the package is the workhorse tree SHA (for example, `git rev-parse HEAD:workhorse`).
-
-#### `cache-assets`
-
-In [this MR](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96297),
-we introduced three new `cache-assets:test`, `cache-assets:test as-if-foss`,
-and `cache-assets:production` jobs that:
-
-- never run unless `$CACHE_ASSETS_AS_PACKAGE == "true"`
-- runs automatically for all GitLab.com `gitlab-org/gitlab` scheduled pipelines
-- runs automatically for any `master` commit that touches the assets-related folders
-- is manual for GitLab.com's `gitlab-org`'s MRs that touches caching-related files
-
-This job tries to download a generic package that contains GitLab compiled assets
-needed in the GitLab test suite (under `app/assets/javascripts/locale/**/app.js`,
-and `public/assets`).
-
-- If the package URL returns a 404:
- 1. It runs `bin/rake gitlab:assets:compile`, so that the GitLab assets are compiled.
- 1. It then creates an archive which contains the assets and uploads it [as a generic package](https://gitlab.com/gitlab-org/gitlab/-/packages/).
- The package version is set to the assets folders' hash sum.
-- Otherwise, if the package already exists, it exits the job successfully.
-
-#### `compile-*-assets`
-
-We also changed the `compile-test-assets`, `compile-test-assets as-if-foss`,
-and `compile-production-assets` jobs to:
-
-1. First download the "native" cache assets, which contain:
- - The [compiled assets](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/global.gitlab-ci.yml#L86-87).
- - A [`cached-assets-hash.txt` file](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/global.gitlab-ci.yml#L85)
- containing the `SHA256` hexdigest of all the source files on which the assets depend on.
- This list of files is a pessimistic list and the assets might not depend on
- some of these files. At worst we compile the assets more often, which is better than
- using outdated assets.
-
- The file is [created after assets are compiled](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/frontend.gitlab-ci.yml#L83).
-1. We then we compute the `SHA256` hexdigest of all the source files the assets depend on, **for the current checked out branch**. We [store the hexdigest in the `GITLAB_ASSETS_HASH` variable](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/frontend.gitlab-ci.yml#L27).
-1. If `$CACHE_ASSETS_AS_PACKAGE == "true"`, we download the generic package built and uploaded by [`cache-assets:*`](#cache-assets).
- - If the cache is up-to-date for the checked out branch, we download the native cache
- **and** the cache package. We could optimize that by not downloading
- the genetic package but the native cache is actually very often outdated because it's
- rebuilt only every 2 hours.
-1. We [run the `assets_compile_script` function](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/frontend.gitlab-ci.yml#L35),
- which [itself runs](https://gitlab.com/gitlab-org/gitlab/-/blob/c023191ef412e868ae957f3341208a41ca678403/scripts/utils.sh#L76)
- the [`assets:compile` Rake task](https://gitlab.com/gitlab-org/gitlab/-/blob/c023191ef412e868ae957f3341208a41ca678403/lib/tasks/gitlab/assets.rake#L80-109).
-
- This task is responsible for deciding if assets need to be compiled or not.
- It [compares the `HEAD` `SHA256` hexdigest from `$GITLAB_ASSETS_HASH` with the `master` hexdigest from `cached-assets-hash.txt`](https://gitlab.com/gitlab-org/gitlab/-/blob/c023191ef412e868ae957f3341208a41ca678403/lib/tasks/gitlab/assets.rake#L86).
-1. If the hashes are the same, we don't compile anything. If they're different, we compile the assets.
-
-### Pre-clone step
-
-NOTE:
-We no longer use this optimization for `gitlab-org/gitlab` because the [pack-objects cache](../administration/gitaly/configure_gitaly.md#pack-objects-cache)
-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).
-
----
-
-[Return to Development documentation](index.md)
+<!-- This redirect file can be deleted after <2023-01-20>. -->
+<!-- Redirects that point to other docs in the same project expire in three months. -->
+<!-- Redirects that point to docs in a different project or site (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/pipelines/index.md b/doc/development/pipelines/index.md
new file mode 100644
index 00000000000..01bb813e794
--- /dev/null
+++ b/doc/development/pipelines/index.md
@@ -0,0 +1,631 @@
+---
+stage: none
+group: Engineering Productivity
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Pipelines for the GitLab project
+
+Pipelines for [`gitlab-org/gitlab`](https://gitlab.com/gitlab-org/gitlab) (as well as the `dev` instance's) is configured in the usual
+[`.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab-ci.yml)
+which itself includes files under
+[`.gitlab/ci/`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/.gitlab/ci)
+for easier maintenance.
+
+We're striving to [dogfood](https://about.gitlab.com/handbook/engineering/development/principles/#dogfooding)
+GitLab [CI/CD features and best-practices](../../ci/yaml/index.md)
+as much as possible.
+
+## Minimal test jobs before a merge request is approved
+
+**To reduce the pipeline cost and shorten the job duration, before a merge request is approved, the pipeline will run a minimal set of RSpec & Jest tests that are related to the merge request changes.**
+
+After a merge request has been approved, the pipeline would contain the full RSpec & Jest tests. This will ensure that all tests
+have been run before a merge request is merged.
+
+### Overview of the GitLab project test dependency
+
+To understand how the minimal test jobs are executed, we need to understand the dependency between
+GitLab code (frontend and backend) and the respective tests (Jest and RSpec).
+This dependency can be visualized in the following diagram:
+
+```mermaid
+flowchart LR
+ subgraph frontend
+ fe["Frontend code"]--tested with-->jest
+ end
+ subgraph backend
+ be["Backend code"]--tested with-->rspec
+ end
+
+ be--generates-->fixtures["frontend fixtures"]
+ fixtures--used in-->jest
+```
+
+In summary:
+
+- RSpec tests are dependent on the backend code.
+- Jest tests are dependent on both frontend and backend code, the latter through the frontend fixtures.
+
+### RSpec minimal jobs
+
+#### Determining related RSpec test files in a merge request
+
+To identify the minimal set of tests needed, we use the [`test_file_finder` gem](https://gitlab.com/gitlab-org/ci-cd/test_file_finder), with two strategies:
+
+- dynamic mapping from test coverage tracing (generated via the [`Crystalball` gem](https://github.com/toptal/crystalball))
+ ([see where it's used](https://gitlab.com/gitlab-org/gitlab/-/blob/47d507c93779675d73a05002e2ec9c3c467cd698/tooling/bin/find_tests#L15))
+- static mapping maintained in the [`tests.yml` file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/tests.yml) for special cases that cannot
+ be mapped via coverage tracing ([see where it's used](https://gitlab.com/gitlab-org/gitlab/-/blob/47d507c93779675d73a05002e2ec9c3c467cd698/tooling/bin/find_tests#L12))
+
+The test mappings contain a map of each source files to a list of test files which is dependent of the source file.
+
+In the `detect-tests` job, we use this mapping to identify the minimal tests needed for the current merge request.
+
+Later on in [the `rspec fail-fast` job](#fail-fast-job-in-merge-request-pipelines), we run the minimal tests needed for the current merge request.
+
+#### Exceptional cases
+
+In addition, there are a few circumstances where we would always run the full RSpec tests:
+
+- when the `pipeline:run-all-rspec` label is set on the merge request
+- when the `pipeline:run-full-rspec` label is set on the merge request, this label is assigned by triage automation when the merge request is approved by any reviewer
+- when the merge request is created by an automation (for example, Gitaly update or MR targeting a stable branch)
+- when the merge request is created in a security mirror
+- when any CI configuration file is changed (for example, `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
+
+### Jest minimal jobs
+
+#### Determining related Jest test files in a merge request
+
+To identify the minimal set of tests needed, we pass a list of all the changed files into `jest` using the [`--findRelatedTests`](https://jestjs.io/docs/cli#--findrelatedtests-spaceseparatedlistofsourcefiles) option.
+In this mode, `jest` would resolve all the dependencies of related to the changed files, which include test files that have these files in the dependency chain.
+
+#### Exceptional cases
+
+In addition, there are a few circumstances where we would always run the full Jest tests:
+
+- when the `pipeline:run-all-jest` label is set on the merge request
+- when the merge request is created by an automation (for example, Gitaly update or MR targeting a stable branch)
+- when the merge request is created in a security mirror
+- when any CI configuration file is changed (for example, `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
+- when any frontend "core" file is changed (for example, `package.json`, `yarn.lock`, `babel.config.js`, `jest.config.*.js`, `config/helpers/**/*.js`)
+- when any vendored JavaScript file is changed (for example, `vendor/assets/javascripts/**/*`)
+- when any backend file is changed ([see the patterns list for details](https://gitlab.com/gitlab-org/gitlab/-/blob/3616946936c1adbd9e754c1bd06f86ba670796d8/.gitlab/ci/rules.gitlab-ci.yml#L205-216))
+
+### Fork pipelines
+
+We run only the minimal 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).
+
+## Fail-fast job in merge request pipelines
+
+To provide faster feedback when a merge request breaks existing tests, we are experimenting with a
+fail-fast mechanism.
+
+An `rspec fail-fast` job is added in parallel to all other `rspec` jobs in a merge
+request pipeline. This job runs the tests that are directly related to the changes
+in the merge request.
+
+If any of these tests fail, the `rspec fail-fast` job fails, triggering a
+`fail-pipeline-early` job to run. The `fail-pipeline-early` job:
+
+- Cancels the currently running pipeline and all in-progress jobs.
+- Sets pipeline to have status `failed`.
+
+For example:
+
+```mermaid
+graph LR
+ subgraph "prepare stage";
+ A["detect-tests"]
+ end
+
+ subgraph "test stage";
+ B["jest"];
+ C["rspec migration"];
+ D["rspec unit"];
+ E["rspec integration"];
+ F["rspec system"];
+ G["rspec fail-fast"];
+ end
+
+ subgraph "post-test stage";
+ Z["fail-pipeline-early"];
+ end
+
+ A --"artifact: list of test files"--> G
+ G --"on failure"--> Z
+```
+
+The `rspec fail-fast` is a no-op if there are more than 10 test files related to the
+merge request. This prevents `rspec fail-fast` duration from exceeding the average
+`rspec` job duration and defeating its purpose.
+
+This number can be overridden by setting a CI/CD variable named `RSPEC_FAIL_FAST_TEST_FILE_COUNT_THRESHOLD`.
+
+## Faster feedback for merge requests that fix a broken `master`
+
+When you need to [fix a broken `master`](https://about.gitlab.com/handbook/engineering/workflow/#resolution-of-broken-master), you can add the `pipeline:expedite-master-fixing` label to expedite the pipelines that run on the merge request.
+
+When this label is assigned, the following steps of the CI/CD pipeline are skipped:
+
+- The `e2e:package-and-test` job.
+- The `rspec:undercoverage` job.
+- The entire [Review Apps process](../testing_guide/review_apps.md).
+
+Apply the label to the merge request, and run a new pipeline for the MR.
+
+Note that the merge request also needs to have the `master:broken` or `master:foss-broken` label set.
+
+## Test jobs
+
+We have dedicated jobs for each [testing level](../testing_guide/testing_levels.md) and each job runs depending on the
+changes made in your merge request.
+If you want to force all the RSpec jobs to run regardless of your changes, you can add the `pipeline:run-all-rspec` label to the merge request.
+
+WARNING:
+Forcing all jobs on docs only related MRs would not have the prerequisite jobs and would lead to errors
+
+### Test suite parallelization
+
+Our current RSpec tests parallelization setup is as follows:
+
+1. The `retrieve-tests-metadata` job in the `prepare` stage ensures we have a
+ `knapsack/report-master.json` file:
+ - The `knapsack/report-master.json` file is fetched from the latest `main` pipeline which runs `update-tests-metadata`
+ (for now it's the 2-hourly `maintenance` scheduled master pipeline), if it's not here we initialize the file with `{}`.
+1. Each `[rspec|rspec-ee] [migration|unit|integration|system|geo] n m` job are run with
+ `knapsack rspec` and should have an evenly distributed share of tests:
+ - It works because the jobs have access to the `knapsack/report-master.json`
+ since the "artifacts from all previous stages are passed by default".
+ - the jobs set their own report path to
+ `"knapsack/${TEST_TOOL}_${TEST_LEVEL}_${DATABASE}_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json"`.
+ - if knapsack is doing its job, test files that are run should be listed under
+ `Report specs`, not under `Leftover specs`.
+1. The `update-tests-metadata` job (which only runs on scheduled pipelines for
+ [the canonical project](https://gitlab.com/gitlab-org/gitlab) takes all the
+ `knapsack/rspec*.json` files and merge them all together into a single
+ `knapsack/report-master.json` file that is saved as artifact.
+
+After that, the next pipeline uses the up-to-date `knapsack/report-master.json` file.
+
+### Flaky tests
+
+#### Automatic skipping of flaky tests
+
+Tests that are [known to be flaky](../testing_guide/flaky_tests.md#automatic-retries-and-flaky-tests-detection) are
+skipped unless the `$SKIP_FLAKY_TESTS_AUTOMATICALLY` variable is set to `false` or if the `~"pipeline:run-flaky-tests"`
+label is set on the MR.
+
+See the [experiment issue](https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/1069).
+
+#### Automatic retry of failing tests in a separate process
+
+Unless `$RETRY_FAILED_TESTS_IN_NEW_PROCESS` variable is set to `false` (`true` by default), RSpec tests that failed are automatically retried once in a separate
+RSpec process. The goal is to get rid of most side-effects from previous tests that may lead to a subsequent test failure.
+
+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).
+
+### Compatibility testing
+
+By default, we run all tests with the versions that runs on GitLab.com.
+
+Other versions (usually one back-compatible version, and one forward-compatible version) should be running in nightly scheduled pipelines.
+
+Exceptions to this general guideline should be motivated and documented.
+
+#### Single database testing
+
+By default, all tests run with [multiple databases](../database/multiple_databases.md).
+
+We also run tests with a single database in nightly scheduled pipelines, and in merge requests that touch database-related files.
+
+If you want to force tests to run with a single database, you can add the `pipeline:run-single-db` label to the merge request.
+
+### Monitoring
+
+The GitLab test suite is [monitored](../performance.md#rspec-profiling) for the `main` branch, and any branch
+that includes `rspec-profile` in their name.
+
+### Logging
+
+- Rails logging to `log/test.log` is disabled by default in CI
+ [for performance reasons](https://jtway.co/speed-up-your-rails-test-suite-by-6-in-1-line-13fedb869ec4).
+ To override this setting, provide the
+ `RAILS_ENABLE_TEST_LOG` environment variable.
+
+## Review app jobs
+
+Consult the [Review Apps](../testing_guide/review_apps.md) dedicated page for more information.
+
+If you want to force a Review App to be deployed regardless of your changes, you can add the `pipeline:run-review-app` label to the merge request.
+
+## As-if-FOSS jobs
+
+The `* as-if-foss` jobs run the GitLab test suite "as if FOSS", meaning as if the jobs would run in the context
+of `gitlab-org/gitlab-foss`. These jobs are only created in the following cases:
+
+- when the `pipeline:run-as-if-foss` label is set on the merge request
+- when the merge request is created in the `gitlab-org/security/gitlab` project
+- when any CI configuration file is changed (for example, `.gitlab-ci.yml` or `.gitlab/ci/**/*`)
+
+The `* as-if-foss` jobs are run in addition to the regular EE-context jobs. They have the `FOSS_ONLY='1'` variable
+set and get the `ee/` folder removed before the tests start running.
+
+The intent is to ensure that a change doesn't introduce a failure after `gitlab-org/gitlab` is synced to `gitlab-org/gitlab-foss`.
+
+## As-if-JH cross project downstream pipeline
+
+The `start-as-if-jh` job triggers a cross project downstream pipeline which
+runs the GitLab test suite "as if JiHu", meaning as if the pipeline would run
+in the context of [GitLab JH](../jh_features_review.md). These jobs are only
+created in the following cases:
+
+- when the `pipeline:run-as-if-jh` label is set on the merge request
+
+This pipeline runs under the context of a generated branch in the
+[GitLab JH validation](https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation)
+project, which is a mirror of the
+[GitLab JH mirror](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab).
+
+The generated branch name is prefixed with `as-if-jh/` along with the branch
+name in the merge request. This generated branch is based on the merge request
+branch, additionally adding changes downloaded from the
+[corresponding JH branch](#corresponding-jh-branch) on top to turn the whole
+pipeline as if JiHu.
+
+The intent is to ensure that a change doesn't introduce a failure after
+[GitLab](https://gitlab.com/gitlab-org/gitlab) is synchronized to
+[GitLab JH](https://jihulab.com/gitlab-cn/gitlab).
+
+### When to consider applying `pipeline:run-as-if-jh` label
+
+If a Ruby file is renamed and there's a corresponding [`prepend_mod` line](../jh_features_review.md#jh-features-based-on-ce-or-ee-features),
+it's likely that GitLab JH is relying on it and requires a corresponding
+change to rename the module or class it's prepending.
+
+### Corresponding JH branch
+
+You can create a corresponding JH branch on [GitLab JH](https://jihulab.com/gitlab-cn/gitlab) by
+appending `-jh` to the branch name. If a corresponding JH branch is found,
+as-if-jh pipeline grabs files from the respective branch, rather than from the
+default branch `main-jh`.
+
+NOTE:
+For now, CI will try to fetch the branch on the [GitLab JH mirror](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab), so it might take some time for the new JH branch to propagate to the mirror.
+
+NOTE:
+While [GitLab JH validation](https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation) is a mirror of
+[GitLab JH mirror](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab),
+it does not include any corresponding JH branch beside the default `main-jh`.
+This is why when we want to fetch corresponding JH branch we should fetch it
+from the main mirror, rather than the validation project.
+
+### How as-if-JH pipeline was configured
+
+The whole process looks like this:
+
+```mermaid
+flowchart TD
+ subgraph "JiHuLab.com"
+ JH["gitlab-cn/gitlab"]
+ end
+
+ subgraph "GitLab.com"
+ Mirror["gitlab-org/gitlab-jh-mirrors/gitlab"]
+ Validation["gitlab-org-sandbox/gitlab-jh-validation"]
+
+ subgraph MR["gitlab-org/gitlab merge request"]
+ Add["add-jh-files job"]
+ Prepare["prepare-as-if-jh-branch job"]
+ Add --"download artifacts"--> Prepare
+ end
+
+ Mirror --"pull mirror with master and main-jh"--> Validation
+ Mirror --"download JiHu files with ADD_JH_FILES_TOKEN"--> Add
+ Prepare --"push as-if-jh branches with AS_IF_JH_TOKEN"--> Validation
+ Validation --> Pipeline["as-if-jh pipeline"]
+ end
+
+ JH --"pull mirror with corresponding JH branches"--> Mirror
+```
+
+#### Tokens set in the project variables
+
+- `ADD_JH_FILES_TOKEN`: This is a [GitLab JH mirror](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab)
+ project token with `read_api` permission, to be able to download JiHu files.
+- `AS_IF_JH_TOKEN`: This is a [GitLab JH validation](https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation)
+ project token with `write_repository` permission, to push generated `as-if-jh/*` branch.
+
+#### How we generate the as-if-JH branch
+
+First `add-jh-files` job will download the required JiHu files from the
+corresponding JH branch, saving in artifacts. Next `prepare-as-if-jh-branch`
+job will create a new branch from the merge request branch, commit the
+changes, and finally push the branch to the
+[validation project](https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation).
+
+#### How we trigger and run the as-if-JH pipeline
+
+After having the `as-if-jh/*` branch, `start-as-if-jh` job will trigger a pipeline
+in the [validation project](https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation)
+to run the cross-project downstream pipeline.
+
+#### How the GitLab JH mirror project is set up
+
+The [GitLab JH mirror](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab) project is private and CI is disabled.
+
+It's a pull mirror pulling from [GitLab JH](https://jihulab.com/gitlab-cn/gitlab),
+mirroring all branches, overriding divergent refs, triggering no pipelines
+when mirror is updated.
+
+The pulling user is [`@gitlab-jh-bot`](https://gitlab.com/gitlab-jh-bot), who
+is a maintainer in the project. The credentials can be found in the 1password
+engineering vault.
+
+No password is used from mirroring because GitLab JH is a public project.
+
+#### How the GitLab JH validation project is set up
+
+This [GitLab JH validation](https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation) project is public and CI is enabled, without any project variables.
+
+It's a pull mirror pulling from [GitLab JH mirror](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab),
+mirroring only protected branches, `master` and `main-jh`, overriding
+divergent refs, triggering no pipelines when mirror is updated.
+
+The pulling user is [`@gitlab-jh-validation-bot`](https://gitlab.com/gitlab-jh-validation-bot), who is a maintainer in the project, and also a
+reporter in the
+[GitLab JH mirror](https://gitlab.com/gitlab-org/gitlab-jh-mirrors/gitlab).
+The credentials can be found in the 1password engineering vault.
+
+A personal access token from `@gitlab-jh-validation-bot` with
+`write_repository` permission is used as the password to pull changes from
+the GitLab JH mirror. Username is set with `gitlab-jh-validation-bot`.
+
+There is also a [pipeline schedule](https://gitlab.com/gitlab-org-sandbox/gitlab-jh-validation/-/pipeline_schedules)
+to run maintenance pipelines with variable `SCHEDULE_TYPE` set to `maintenance`
+running every day, updating cache.
+
+The default CI/CD configuration file is also set at `jh/.gitlab-ci.yml` so it
+runs exactly like [GitLab JH](https://jihulab.com/gitlab-cn/gitlab/-/blob/main-jh/jh/.gitlab-ci.yml).
+
+## Ruby 3.0 jobs
+
+You can add the `pipeline:run-in-ruby3` label to the merge request to switch
+the Ruby version used for running the whole test suite to 3.0. When you do
+this, the test suite will no longer run in Ruby 2.7 (default), and an
+additional job `verify-ruby-2.7` will also run and always fail to remind us to
+remove the label and run in Ruby 2.7 before merging the merge request.
+
+This should let us:
+
+- Test changes for Ruby 3.0
+- Make sure it will not break anything when it's merged into the default branch
+
+## `undercover` RSpec test
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74859) in GitLab 14.6.
+
+The `rspec:undercoverage` job runs [`undercover`](https://rubygems.org/gems/undercover)
+to detect, and fail if any changes introduced in the merge request has zero coverage.
+
+The `rspec:undercoverage` job obtains coverage data from the `rspec:coverage`
+job.
+
+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.
+
+### Troubleshooting `rspec:undercoverage` failures
+
+The `rspec:undercoverage` job has [known bugs](https://gitlab.com/groups/gitlab-org/-/epics/8254)
+that can cause false positive failures. You can test coverage locally to determine if it's
+safe to apply `~"pipeline:skip-undercoverage"`. For example, using `<spec>` as the name of the
+test causing the failure:
+
+1. Run `SIMPLECOV=1 bundle exec rspec <spec>`.
+1. Run `scripts/undercoverage`.
+
+If these commands return `undercover: ✅ No coverage is missing in latest changes` then you can apply `~"pipeline:skip-undercoverage"` to bypass pipeline failures.
+
+## Ruby versions testing
+
+Our test suite runs against Ruby 2 in merge requests and default branch pipelines.
+
+We also run our test suite against Ruby 3 on another 2-hourly scheduled pipelines, as GitLab.com will soon run on Ruby 3.
+
+## PostgreSQL versions testing
+
+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).
+
+### Current versions testing
+
+| Where? | PostgreSQL version | Ruby version |
+|------------------------------------------------------------------------------------------------|-------------------------------------------------|--------------|
+| Merge requests | 12 (default version), 11 for DB library changes | 2.7 (default version) |
+| `master` branch commits | 12 (default version), 11 for DB library changes | 2.7 (default version) |
+| `maintenance` scheduled pipelines for the `master` branch (every even-numbered hour) | 12 (default version), 11 for DB library changes | 2.7 (default version) |
+| `maintenance` scheduled pipelines for the `ruby3` branch (every odd-numbered hour), see below. | 12 (default version), 11 for DB library changes | 3.0 (coded in the branch) |
+| `nightly` scheduled pipelines for the `master` branch | 12 (default version), 11, 13 | 2.7 (default version) |
+
+There are 2 pipeline schedules used for testing Ruby 3. One is triggering a
+pipeline in `ruby3-sync` branch, which updates the `ruby3` branch with latest
+`master`, and no pipelines will be triggered by this push. The other schedule
+is triggering a pipeline in `ruby3` 5 minutes after it, which is considered
+the maintenance schedule to run test suites and update cache.
+
+Any changes in `ruby3` are only for running the pipeline. It should
+never be merged back to `master`. Any other Ruby 3 changes should go into
+`master` directly, which should be compatible with Ruby 2.7.
+
+Previously, `ruby3-sync` was using a project token stored in `RUBY3_SYNC_TOKEN`
+(now backed up in `RUBY3_SYNC_TOKEN_NOT_USED`), however due to various
+permissions issues, we ended up using an access token from `gitlab-bot` so now
+`RUBY3_SYNC_TOKEN` is actually an access token from `gitlab-bot`.
+
+### Long-term plan
+
+We follow the [PostgreSQL versions shipped with Omnibus GitLab](../../administration/package_information/postgresql_versions.md):
+
+| 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
+
+Our test suite runs against Redis 6 as GitLab.com runs on Redis 6 and
+[Omnibus defaults to Redis 6 for new installs and upgrades](https://gitlab.com/gitlab-org/omnibus-gitlab/-/blob/master/config/software/redis.rb).
+
+We do run our test suite against Redis 5 on `nightly` scheduled pipelines, specifically when running backward-compatible and forward-compatible PostgreSQL jobs.
+
+### Current versions testing
+
+| Where? | Redis version |
+| ------ | ------------------ |
+| MRs | 6 |
+| `default branch` (non-scheduled pipelines) | 6 |
+| `nightly` scheduled pipelines | 5 |
+
+## Pipelines types for merge requests
+
+In general, pipelines for an MR fall into one of the following types (from shorter to longer), depending on the changes made in the MR:
+
+- [Documentation pipeline](#documentation-pipeline): For MRs that touch documentation.
+- [Backend pipeline](#backend-pipeline): For MRs that touch backend code.
+- [Frontend pipeline](#frontend-pipeline): For MRs that touch frontend code.
+- [End-to-end pipeline](#end-to-end-pipeline): For MRs that touch code in the `qa/` folder.
+
+A "pipeline type" is an abstract term that mostly describes the "critical path" (for example, the chain of jobs for which the sum
+of individual duration equals the pipeline's duration).
+We use these "pipeline types" in [metrics dashboards](https://app.periscopedata.com/app/gitlab/858266/GitLab-Pipeline-Durations) to detect what types and jobs need to be optimized first.
+
+An MR that touches multiple areas would be associated with the longest type applicable. For instance, an MR that touches backend
+and frontend would fall into the "Frontend" pipeline type since this type takes longer to finish than the "Backend" pipeline type.
+
+We use the [`rules:`](../../ci/yaml/index.md#rules) and [`needs:`](../../ci/yaml/index.md#needs) keywords extensively
+to determine the jobs that need to be run in a pipeline. Note that an MR that includes multiple types of changes would
+have a pipelines that include jobs from multiple types (for example, a combination of docs-only and code-only pipelines).
+
+Following are graphs of the critical paths for each pipeline type. Jobs that aren't part of the critical path are omitted.
+
+### Documentation pipeline
+
+[Reference pipeline](https://gitlab.com/gitlab-org/gitlab/-/pipelines/432049110).
+
+```mermaid
+graph LR
+ classDef criticalPath fill:#f66;
+
+ 1-3["docs-lint links (5 minutes)"];
+ class 1-3 criticalPath;
+ click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356757&udv=0"
+```
+
+### Backend pipeline
+
+[Reference pipeline](https://gitlab.com/gitlab-org/gitlab/-/pipelines/433316063).
+
+```mermaid
+graph RL;
+ classDef criticalPath fill:#f66;
+
+ 1-3["compile-test-assets (6 minutes)"];
+ class 1-3 criticalPath;
+ click 1-3 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914317&udv=0"
+ 1-6["setup-test-env (4 minutes)"];
+ click 1-6 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914315&udv=0"
+ 1-14["retrieve-tests-metadata"];
+ click 1-14 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=8356697&udv=0"
+ 1-15["detect-tests"];
+ click 1-15 "https://app.periscopedata.com/app/gitlab/652085/EP---Jobs-Durations?widget=10113603&udv=1005715"
+
+ 2_5-1["rspec & db jobs (24 minutes)"];
+ class 2_5-1 criticalPath;
+ click 2_5-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations"
+ 2_5-1 --> 1-3 & 1-6 & 1-14 & 1-15;
+
+ 3_2-1["rspec:coverage (5.35 minutes)"];
+ class 3_2-1 criticalPath;
+ click 3_2-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=7248745&udv=0"
+ 3_2-1 -.->|"(don't use needs<br/>because of limitations)"| 2_5-1;
+
+ 4_3-1["rspec:undercoverage (3.5 minutes)"];
+ class 4_3-1 criticalPath;
+ click 4_3-1 "https://app.periscopedata.com/app/gitlab/652085/EP---Jobs-Durations?widget=13446492&udv=1005715"
+ 4_3-1 --> 3_2-1;
+
+```
+
+### Frontend pipeline
+
+[Reference pipeline](https://gitlab.com/gitlab-org/gitlab/-/pipelines/431913287).
+
+```mermaid
+graph RL;
+ classDef criticalPath fill:#f66;
+
+ 1-2["build-qa-image (2 minutes)"];
+ click 1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914325&udv=0"
+ 1-5["compile-production-assets (16 minutes)"];
+ class 1-5 criticalPath;
+ click 1-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914312&udv=0"
+
+ 2_3-1["build-assets-image (1.3 minutes)"];
+ class 2_3-1 criticalPath;
+ 2_3-1 --> 1-5
+
+ 2_6-1["start-review-app-pipeline (49 minutes)"];
+ class 2_6-1 criticalPath;
+ click 2_6-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations"
+ 2_6-1 --> 2_3-1 & 1-2;
+```
+
+### End-to-end pipeline
+
+[Reference pipeline](https://gitlab.com/gitlab-org/gitlab/-/pipelines/431918463).
+
+```mermaid
+graph RL;
+ classDef criticalPath fill:#f66;
+
+ 1-2["build-qa-image (2 minutes)"];
+ click 1-2 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914325&udv=0"
+ 1-5["compile-production-assets (16 minutes)"];
+ class 1-5 criticalPath;
+ click 1-5 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914312&udv=0"
+ 1-15["detect-tests"];
+ click 1-15 "https://app.periscopedata.com/app/gitlab/652085/EP---Jobs-Durations?widget=10113603&udv=1005715"
+
+ 2_3-1["build-assets-image (1.3 minutes)"];
+ class 2_3-1 criticalPath;
+ 2_3-1 --> 1-5
+
+ 2_4-1["e2e:package-and-test (102 minutes)"];
+ class 2_4-1 criticalPath;
+ click 2_4-1 "https://app.periscopedata.com/app/gitlab/652085/Engineering-Productivity---Pipeline-Build-Durations?widget=6914305&udv=0"
+ 2_4-1 --> 1-2 & 2_3-1 & 1-15;
+```
+
+## CI configuration internals
+
+See the dedicated [CI configuration internals page](internals.md).
+
+## Performance
+
+See the dedicated [CI configuration performance page](performance.md).
+
+---
+
+[Return to Development documentation](../index.md)
diff --git a/doc/development/pipelines/internals.md b/doc/development/pipelines/internals.md
new file mode 100644
index 00000000000..2861e2f266b
--- /dev/null
+++ b/doc/development/pipelines/internals.md
@@ -0,0 +1,216 @@
+---
+stage: none
+group: Engineering Productivity
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# CI configuration internals
+
+## Workflow rules
+
+Pipelines for the GitLab project are created using the [`workflow:rules` keyword](../../ci/yaml/index.md#workflow)
+feature of the GitLab CI/CD.
+
+Pipelines are always created for the following scenarios:
+
+- `main` branch, including on schedules, pushes, merges, and so on.
+- Merge requests.
+- Tags.
+- Stable, `auto-deploy`, and security branches.
+
+Pipeline creation is also affected by the following CI/CD variables:
+
+- If `$FORCE_GITLAB_CI` is set, pipelines are created.
+- If `$GITLAB_INTERNAL` is not set, pipelines are not created.
+
+No pipeline is created in any other cases (for example, when pushing a branch with no
+MR for it).
+
+The source of truth for these workflow rules is defined in [`.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab-ci.yml).
+
+## Default image
+
+The default image is defined in [`.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab-ci.yml).
+
+<!-- vale gitlab.Spelling = NO -->
+
+It includes Ruby, Go, Git, Git LFS, Chrome, Node, Yarn, PostgreSQL, and Graphics Magick.
+
+<!-- vale gitlab.Spelling = YES -->
+
+The images used in our pipelines are configured in the
+[`gitlab-org/gitlab-build-images`](https://gitlab.com/gitlab-org/gitlab-build-images)
+project, which is push-mirrored to [`gitlab/gitlab-build-images`](https://dev.gitlab.org/gitlab/gitlab-build-images)
+for redundancy.
+
+The current version of the build images can be found in the
+["Used by GitLab section"](https://gitlab.com/gitlab-org/gitlab-build-images/blob/master/.gitlab-ci.yml).
+
+## Default variables
+
+In addition to the [predefined CI/CD variables](../../ci/variables/predefined_variables.md),
+each pipeline includes default variables defined in
+[`.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab-ci.yml).
+
+## Stages
+
+The current stages are:
+
+- `sync`: This stage is used to synchronize changes from [`gitlab-org/gitlab`](https://gitlab.com/gitlab-org/gitlab) to
+ [`gitlab-org/gitlab-foss`](https://gitlab.com/gitlab-org/gitlab-foss).
+- `prepare`: This stage includes jobs that prepare artifacts that are needed by
+ jobs in subsequent stages.
+- `build-images`: This stage includes jobs that prepare Docker images
+ that are needed by jobs in subsequent stages or downstream pipelines.
+- `fixtures`: This stage includes jobs that prepare fixtures needed by frontend tests.
+- `lint`: This stage includes linting and static analysis jobs.
+- `test`: This stage includes most of the tests, and DB/migration jobs.
+- `post-test`: This stage includes jobs that build reports or gather data from
+ the `test` stage's jobs (for example, coverage, Knapsack metadata, and so on).
+- `review`: This stage includes jobs that build the CNG images, deploy them, and
+ run end-to-end tests against Review Apps (see [Review Apps](../testing_guide/review_apps.md) for details).
+ It also includes Docs Review App jobs.
+- `qa`: This stage includes jobs that perform QA tasks against the Review App
+ that is deployed in stage `review`.
+- `post-qa`: This stage includes jobs that build reports or gather data from
+ the `qa` stage's jobs (for example, Review App performance report).
+- `pages`: This stage includes a job that deploys the various reports as
+ GitLab Pages (for example, [`coverage-ruby`](https://gitlab-org.gitlab.io/gitlab/coverage-ruby/),
+ and `webpack-report` (found at `https://gitlab-org.gitlab.io/gitlab/webpack-report/`, but there is
+ [an issue with the deployment](https://gitlab.com/gitlab-org/gitlab/-/issues/233458)).
+- `notify`: This stage includes jobs that notify various failures to Slack.
+
+## Dependency Proxy
+
+Some of the jobs are using images from Docker Hub, where we also use
+`${GITLAB_DEPENDENCY_PROXY_ADDRESS}` as a prefix to the image path, so that we pull
+images from our [Dependency Proxy](../../user/packages/dependency_proxy/index.md).
+By default, this variable is set from the value of `${GITLAB_DEPENDENCY_PROXY}`.
+
+`${GITLAB_DEPENDENCY_PROXY}` is a group CI/CD variable defined in
+[`gitlab-org`](https://gitlab.com/gitlab-org) as
+`${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/`. This means when we use an image
+defined as:
+
+```yaml
+image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}alpine:edge
+```
+
+Projects in the `gitlab-org` group pull from the Dependency Proxy, while
+forks that reside on any other personal namespaces or groups fall back to
+Docker Hub unless `${GITLAB_DEPENDENCY_PROXY}` is also defined there.
+
+### Work around for when a pipeline is started by a Project access token user
+
+When a pipeline is started by a Project access token user (e.g. the `release-tools approver bot` user which
+automatically updates the Gitaly version used in the main project),
+[the Dependency proxy isn't accessible](https://gitlab.com/gitlab-org/gitlab/-/issues/332411#note_1130388163)
+and the job fails at the `Preparing the "docker+machine" executor` step.
+To work around that, we have a special workflow rule, that overrides the
+`${GITLAB_DEPENDENCY_PROXY_ADDRESS}` variable so that Depdendency proxy isn't used in that case:
+
+```yaml
+- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $GITLAB_USER_LOGIN =~ /project_\d+_bot\d*/'
+ variables:
+ GITLAB_DEPENDENCY_PROXY_ADDRESS: ""
+```
+
+NOTE:
+We don't directly override the `${GITLAB_DEPENDENCY_PROXY}` variable because group-level
+variables have higher precedence over `.gitlab-ci.yml` variables.
+
+## Common job definitions
+
+Most of the jobs [extend from a few CI definitions](../../ci/yaml/index.md#extends)
+defined in [`.gitlab/ci/global.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/global.gitlab-ci.yml)
+that are scoped to a single [configuration keyword](../../ci/yaml/index.md#job-keywords).
+
+| Job definitions | Description |
+|------------------|-------------|
+| `.default-retry` | Allows a job to [retry](../../ci/yaml/index.md#retry) upon `unknown_failure`, `api_failure`, `runner_system_failure`, `job_execution_timeout`, or `stuck_or_timeout_failure`. |
+| `.default-before_script` | Allows a job to use a default `before_script` definition suitable for Ruby/Rails tasks that may need a database running (for example, tests). |
+| `.setup-test-env-cache` | Allows a job to use a default `cache` definition suitable for setting up test environment for subsequent Ruby/Rails tasks. |
+| `.rails-cache` | Allows a job to use a default `cache` definition suitable for Ruby/Rails tasks. |
+| `.static-analysis-cache` | Allows a job to use a default `cache` definition suitable for static analysis tasks. |
+| `.coverage-cache` | Allows a job to use a default `cache` definition suitable for coverage tasks. |
+| `.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). |
+| `.use-pg13-ee` | Same as `.use-pg13` but also use an `elasticsearch` service (see [`.gitlab/ci/global.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/global.gitlab-ci.yml) for the specific version of the service). |
+| `.use-kaniko` | Allows a job to use the `kaniko` tool to build Docker images. |
+| `.as-if-foss` | Simulate the FOSS project by setting the `FOSS_ONLY='1'` CI/CD variable. |
+| `.use-docker-in-docker` | Allows a job to use Docker in Docker. |
+
+## `rules`, `if:` conditions and `changes:` patterns
+
+We're using the [`rules` keyword](../../ci/yaml/index.md#rules) extensively.
+
+All `rules` definitions are defined in
+[`rules.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/rules.gitlab-ci.yml),
+then included in individual jobs via [`extends`](../../ci/yaml/index.md#extends).
+
+The `rules` definitions are composed of `if:` conditions and `changes:` patterns,
+which are also defined in
+[`rules.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/rules.gitlab-ci.yml)
+and included in `rules` definitions via [YAML anchors](../../ci/yaml/yaml_optimization.md#anchors)
+
+### `if:` conditions
+
+<!-- vale gitlab.Substitutions = NO -->
+
+| `if:` conditions | Description | Notes |
+|------------------|-------------|-------|
+| `if-not-canonical-namespace` | Matches if the project isn't in the canonical (`gitlab-org/`) or security (`gitlab-org/security`) namespace. | Use to create a job for forks (by using `when: on_success|manual`), or **not** create a job for forks (by using `when: never`). |
+| `if-not-ee` | Matches if the project isn't EE (that is, project name isn't `gitlab` or `gitlab-ee`). | Use to create a job only in the FOSS project (by using `when: on_success|manual`), or **not** create a job if the project is EE (by using `when: never`). |
+| `if-not-foss` | Matches if the project isn't FOSS (that is, project name isn't `gitlab-foss`, `gitlab-ce`, or `gitlabhq`). | Use to create a job only in the EE project (by using `when: on_success|manual`), or **not** create a job if the project is FOSS (by using `when: never`). |
+| `if-default-refs` | Matches if the pipeline is for `master`, `main`, `/^[\d-]+-stable(-ee)?$/` (stable branches), `/^\d+-\d+-auto-deploy-\d+$/` (auto-deploy branches), `/^security\//` (security branches), merge requests, and tags. | Note that jobs aren't created for branches with this default configuration. |
+| `if-master-refs` | Matches if the current branch is `master` or `main`. | |
+| `if-master-push` | Matches if the current branch is `master` or `main` and pipeline source is `push`. | |
+| `if-master-schedule-maintenance` | Matches if the current branch is `master` or `main` and pipeline runs on a 2-hourly schedule. | |
+| `if-master-schedule-nightly` | Matches if the current branch is `master` or `main` and pipeline runs on a nightly schedule. | |
+| `if-auto-deploy-branches` | Matches if the current branch is an auto-deploy one. | |
+| `if-master-or-tag` | Matches if the pipeline is for the `master` or `main` branch or for a tag. | |
+| `if-merge-request` | Matches if the pipeline is for a merge request. | |
+| `if-merge-request-title-as-if-foss` | Matches if the pipeline is for a merge request and the MR has label ~"pipeline:run-as-if-foss" | |
+| `if-merge-request-title-update-caches` | Matches if the pipeline is for a merge request and the MR has label ~"pipeline:update-cache". | |
+| `if-merge-request-title-run-all-rspec` | Matches if the pipeline is for a merge request and the MR has label ~"pipeline:run-all-rspec". | |
+| `if-security-merge-request` | Matches if the pipeline is for a security merge request. | |
+| `if-security-schedule` | Matches if the pipeline is for a security scheduled pipeline. | |
+| `if-nightly-master-schedule` | Matches if the pipeline is for a `master` scheduled pipeline with `$NIGHTLY` set. | |
+| `if-dot-com-gitlab-org-schedule` | Limits jobs creation to scheduled pipelines for the `gitlab-org` group on GitLab.com. | |
+| `if-dot-com-gitlab-org-master` | Limits jobs creation to the `master` or `main` branch for the `gitlab-org` group on GitLab.com. | |
+| `if-dot-com-gitlab-org-merge-request` | Limits jobs creation to merge requests for the `gitlab-org` group on GitLab.com. | |
+| `if-dot-com-gitlab-org-and-security-tag` | Limits job creation to tags for the `gitlab-org` and `gitlab-org/security` groups on GitLab.com. | |
+| `if-dot-com-gitlab-org-and-security-merge-request` | Limit jobs creation to merge requests for the `gitlab-org` and `gitlab-org/security` groups on GitLab.com. | |
+| `if-dot-com-gitlab-org-and-security-tag` | Limit jobs creation to tags for the `gitlab-org` and `gitlab-org/security` groups on GitLab.com. | |
+| `if-dot-com-ee-schedule` | Limits jobs to scheduled pipelines for the `gitlab-org/gitlab` project on GitLab.com. | |
+| `if-security-pipeline-merge-result` | Matches if the pipeline is for a security merge request triggered by `@gitlab-release-tools-bot`. | |
+
+<!-- vale gitlab.Substitutions = YES -->
+
+### `changes:` patterns
+
+| `changes:` patterns | Description |
+|------------------------------|--------------------------------------------------------------------------|
+| `ci-patterns` | Only create job for CI configuration-related changes. |
+| `ci-build-images-patterns` | Only create job for CI configuration-related changes related to the `build-images` stage. |
+| `ci-review-patterns` | Only create job for CI configuration-related changes related to the `review` stage. |
+| `ci-qa-patterns` | Only create job for CI configuration-related changes related to the `qa` stage. |
+| `yaml-lint-patterns` | Only create job for YAML-related changes. |
+| `docs-patterns` | Only create job for docs-related changes. |
+| `frontend-dependency-patterns` | Only create job when frontend dependencies are updated (that is, `package.json`, and `yarn.lock`). changes. |
+| `frontend-patterns-for-as-if-foss` | Only create job for frontend-related changes that have impact on FOSS. |
+| `backend-patterns` | Only create job for backend-related changes. |
+| `db-patterns` | Only create job for DB-related changes. |
+| `backstage-patterns` | Only create job for backstage-related changes (that is, Danger, fixtures, RuboCop, specs). |
+| `code-patterns` | Only create job for code-related changes. |
+| `qa-patterns` | Only create job for QA-related changes. |
+| `code-backstage-patterns` | Combination of `code-patterns` and `backstage-patterns`. |
+| `code-qa-patterns` | Combination of `code-patterns` and `qa-patterns`. |
+| `code-backstage-qa-patterns` | Combination of `code-patterns`, `backstage-patterns`, and `qa-patterns`. |
+| `static-analysis-patterns` | Only create jobs for Static Analytics configuration-related changes. |
diff --git a/doc/development/pipelines/performance.md b/doc/development/pipelines/performance.md
new file mode 100644
index 00000000000..1c6f9d78879
--- /dev/null
+++ b/doc/development/pipelines/performance.md
@@ -0,0 +1,151 @@
+---
+stage: none
+group: Engineering Productivity
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# CI configuration performance
+
+## Interruptible pipelines
+
+By default, all jobs are [interruptible](../../ci/yaml/index.md#interruptible), except the
+`dont-interrupt-me` job which runs automatically on `main`, and is `manual`
+otherwise.
+
+If you want a running pipeline to finish even if you push new commits to a merge
+request, be sure to start the `dont-interrupt-me` job before pushing.
+
+## Git fetch caching
+
+Because GitLab.com uses the [pack-objects cache](../../administration/gitaly/configure_gitaly.md#pack-objects-cache),
+concurrent Git fetches of the same pipeline ref are deduplicated on
+the Gitaly server (always) and served from cache (when available).
+
+This works well for the following reasons:
+
+- The pack-objects cache is enabled on all Gitaly servers on GitLab.com.
+- The CI/CD [Git strategy setting](../../ci/pipelines/settings.md#choose-the-default-git-strategy) for `gitlab-org/gitlab` is **Git clone**,
+ causing all jobs to fetch the same data, which maximizes the cache hit ratio.
+- We use [shallow clone](../../ci/pipelines/settings.md#limit-the-number-of-changes-fetched-during-clone) to avoid downloading the full Git
+ history for every job.
+
+## Caching strategy
+
+1. All jobs must only pull caches by default.
+1. All jobs must be able to pass with an empty cache. In other words, caches are only there to speed up jobs.
+1. We currently have several different cache definitions defined in
+ [`.gitlab/ci/global.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/global.gitlab-ci.yml),
+ with fixed keys:
+ - `.setup-test-env-cache`
+ - `.ruby-cache`
+ - `.rails-cache`
+ - `.static-analysis-cache`
+ - `.rubocop-cache`
+ - `.coverage-cache`
+ - `.ruby-node-cache`
+ - `.qa-cache`
+ - `.yarn-cache`
+ - `.assets-compile-cache` (the key includes `${NODE_ENV}` so it's actually two different caches).
+1. These cache definitions are composed of [multiple atomic caches](../../ci/caching/index.md#use-multiple-caches).
+1. Only the following jobs, running in 2-hourly `maintenance` scheduled pipelines, are pushing (that is, updating) to the caches:
+ - `update-setup-test-env-cache`, defined in [`.gitlab/ci/rails.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/rails.gitlab-ci.yml).
+ - `update-gitaly-binaries-cache`, defined in [`.gitlab/ci/rails.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/rails.gitlab-ci.yml).
+ - `update-rubocop-cache`, defined in [`.gitlab/ci/rails.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/rails.gitlab-ci.yml).
+ - `update-qa-cache`, defined in [`.gitlab/ci/qa.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/qa.gitlab-ci.yml).
+ - `update-assets-compile-production-cache`, defined in [`.gitlab/ci/frontend.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/frontend.gitlab-ci.yml).
+ - `update-assets-compile-test-cache`, defined in [`.gitlab/ci/frontend.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/frontend.gitlab-ci.yml).
+ - `update-yarn-cache`, defined in [`.gitlab/ci/frontend.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/frontend.gitlab-ci.yml).
+ - `update-storybook-yarn-cache`, defined in [`.gitlab/ci/frontend.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/.gitlab/ci/frontend.gitlab-ci.yml).
+1. These jobs can also be forced to run in merge requests with the `pipeline:update-cache` label (this can be useful to warm the caches in a MR that updates the cache keys).
+
+## Artifacts strategy
+
+We limit the artifacts that are saved and retrieved by jobs to the minimum to reduce the upload/download time and costs, as well as the artifacts storage.
+
+## Components caching
+
+Some external components (GitLab Workhorse and frontend assets) of GitLab need to be built from source as a preliminary step for running tests.
+
+## `cache-workhorse`
+
+In [this MR](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/79766), and then
+[this MR](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96297),
+we introduced a new `cache-workhorse` job that:
+
+- runs automatically for all GitLab.com `gitlab-org/gitlab` scheduled pipelines
+- runs automatically for any `master` commit that touches the `workhorse/` folder
+- is manual for GitLab.com's `gitlab-org`'s MRs that touches caching-related files
+
+This job tries to download a generic package that contains GitLab Workhorse binaries needed in the GitLab test suite (under `tmp/tests/gitlab-workhorse`).
+
+- If the package URL returns a 404:
+ 1. It runs `scripts/setup-test-env`, so that the GitLab Workhorse binaries are built.
+ 1. It then creates an archive which contains the binaries and upload it [as a generic package](https://gitlab.com/gitlab-org/gitlab/-/packages/).
+- Otherwise, if the package already exists, it exits the job successfully.
+
+We also changed the `setup-test-env` job to:
+
+1. First download the GitLab Workhorse generic package build and uploaded by `cache-workhorse`.
+1. If the package is retrieved successfully, its content is placed in the right folder (for example, `tmp/tests/gitlab-workhorse`), preventing the building of the binaries when `scripts/setup-test-env` is run later on.
+1. If the package URL returns a 404, the behavior doesn't change compared to the current one: the GitLab Workhorse binaries are built as part of `scripts/setup-test-env`.
+
+NOTE:
+The version of the package is the workhorse tree SHA (for example, `git rev-parse HEAD:workhorse`).
+
+## `cache-assets`
+
+In [this MR](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96297),
+we introduced three new `cache-assets:test`, `cache-assets:test as-if-foss`,
+and `cache-assets:production` jobs that:
+
+- never run unless `$CACHE_ASSETS_AS_PACKAGE == "true"`
+- runs automatically for all GitLab.com `gitlab-org/gitlab` scheduled pipelines
+- runs automatically for any `master` commit that touches the assets-related folders
+- is manual for GitLab.com's `gitlab-org`'s MRs that touches caching-related files
+
+This job tries to download a generic package that contains GitLab compiled assets
+needed in the GitLab test suite (under `app/assets/javascripts/locale/**/app.js`,
+and `public/assets`).
+
+- If the package URL returns a 404:
+ 1. It runs `bin/rake gitlab:assets:compile`, so that the GitLab assets are compiled.
+ 1. It then creates an archive which contains the assets and uploads it [as a generic package](https://gitlab.com/gitlab-org/gitlab/-/packages/).
+ The package version is set to the assets folders' hash sum.
+- Otherwise, if the package already exists, it exits the job successfully.
+
+## `compile-*-assets`
+
+We also changed the `compile-test-assets`, `compile-test-assets as-if-foss`,
+and `compile-production-assets` jobs to:
+
+1. First download the "native" cache assets, which contain:
+ - The [compiled assets](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/global.gitlab-ci.yml#L86-87).
+ - A [`cached-assets-hash.txt` file](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/global.gitlab-ci.yml#L85)
+ containing the `SHA256` hexdigest of all the source files on which the assets depend on.
+ This list of files is a pessimistic list and the assets might not depend on
+ some of these files. At worst we compile the assets more often, which is better than
+ using outdated assets.
+
+ The file is [created after assets are compiled](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/frontend.gitlab-ci.yml#L83).
+1. We then we compute the `SHA256` hexdigest of all the source files the assets depend on, **for the current checked out branch**. We [store the hexdigest in the `GITLAB_ASSETS_HASH` variable](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/frontend.gitlab-ci.yml#L27).
+1. If `$CACHE_ASSETS_AS_PACKAGE == "true"`, we download the generic package built and uploaded by [`cache-assets:*`](#cache-assets).
+ - If the cache is up-to-date for the checked out branch, we download the native cache
+ **and** the cache package. We could optimize that by not downloading
+ the genetic package but the native cache is actually very often outdated because it's
+ rebuilt only every 2 hours.
+1. We [run the `assets_compile_script` function](https://gitlab.com/gitlab-org/gitlab/-/blob/a6910c9086bb28e553f5e747ec2dd50af6da3c6b/.gitlab/ci/frontend.gitlab-ci.yml#L35),
+ which [itself runs](https://gitlab.com/gitlab-org/gitlab/-/blob/c023191ef412e868ae957f3341208a41ca678403/scripts/utils.sh#L76)
+ the [`assets:compile` Rake task](https://gitlab.com/gitlab-org/gitlab/-/blob/c023191ef412e868ae957f3341208a41ca678403/lib/tasks/gitlab/assets.rake#L80-109).
+
+ This task is responsible for deciding if assets need to be compiled or not.
+ It [compares the `HEAD` `SHA256` hexdigest from `$GITLAB_ASSETS_HASH` with the `master` hexdigest from `cached-assets-hash.txt`](https://gitlab.com/gitlab-org/gitlab/-/blob/c023191ef412e868ae957f3341208a41ca678403/lib/tasks/gitlab/assets.rake#L86).
+1. If the hashes are the same, we don't compile anything. If they're different, we compile the assets.
+
+## Pre-clone step
+
+NOTE:
+We no longer use this optimization for `gitlab-org/gitlab` because the [pack-objects cache](../../administration/gitaly/configure_gitaly.md#pack-objects-cache)
+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).
diff --git a/doc/development/prometheus_metrics.md b/doc/development/prometheus_metrics.md
index c2caa354567..d3d809c5386 100644
--- a/doc/development/prometheus_metrics.md
+++ b/doc/development/prometheus_metrics.md
@@ -36,7 +36,7 @@ After you add or change an existing common metric, you must [re-run the import s
Or, you can create a database migration:
```ruby
-class ImportCommonMetrics < Gitlab::Database::Migration[1.0]
+class ImportCommonMetrics < Gitlab::Database::Migration[2.0]
def up
::Gitlab::DatabaseImporters::CommonMetrics::Importer.new.execute
end
diff --git a/doc/development/rake_tasks.md b/doc/development/rake_tasks.md
index 505f480c410..14fbe0e875b 100644
--- a/doc/development/rake_tasks.md
+++ b/doc/development/rake_tasks.md
@@ -85,6 +85,18 @@ To import these metrics, you can run:
bundle exec rake 'gitlab:seed:development_metrics[your_project_id]'
```
+#### Seed a project with vulnerabilities
+
+You can seed a project with [security vulnerabilities](../user/application_security/vulnerabilities/index.md).
+
+```shell
+# Seed all projects
+bin/rake 'gitlab:seed:vulnerabilities'
+
+# Seed a specific project
+bin/rake 'gitlab:seed:vulnerabilities[group-path/project-path]'
+```
+
### Automation
If you're very sure that you want to **wipe the current database** and refill
@@ -208,7 +220,7 @@ bundle exec rake rubocop:todo:generate\[Gitlab/NamespacedClass,Lint/Syntax\]
Some shells require brackets to be escaped or quoted.
-See [Resolving RuboCop exceptions](contributing/style_guides.md#resolving-rubocop-exceptions)
+See [Resolving RuboCop exceptions](../development/rubocop_development_guide.md#resolving-rubocop-exceptions)
on how to proceed from here.
### Run RuboCop in graceful mode
diff --git a/doc/development/reusing_abstractions.md b/doc/development/reusing_abstractions.md
index 2701192137c..58d1e20394c 100644
--- a/doc/development/reusing_abstractions.md
+++ b/doc/development/reusing_abstractions.md
@@ -151,7 +151,8 @@ When implementing a service class, consider:
developer's discretion, such as: `issue`, `project`, `merge_request`.
1. When service represents an action initiated by a user or executed in the
context of a user, the initializer must have the `current_user:` keyword argument.
- Services with `current_user:` argument run high-level business logic.
+ Services with the `current_user:` argument run high-level business logic
+ and must validate user authorization to perform their operations.
1. When service does not have a user context and it's not directly initiated
by a user (like background service or side-effects), the `current_user:`
argument is not needed. This describes low-level domain logic or instance-wide logic.
diff --git a/doc/development/routing.md b/doc/development/routing.md
index 16ed15fdcc6..8f475674c39 100644
--- a/doc/development/routing.md
+++ b/doc/development/routing.md
@@ -39,7 +39,7 @@ You can view and find routes from the console by running:
rails routes | grep crm
```
-You can also view routes in your browser by going to [http://gdk.test:3000/rails/info/routes](http://gdk.test:3000/rails/info/routes).
+You can also view routes in your browser by going to `http://gdk.test:3000/rails/info/routes`.
## Global routes
diff --git a/doc/development/rubocop_development_guide.md b/doc/development/rubocop_development_guide.md
new file mode 100644
index 00000000000..2ff94f65232
--- /dev/null
+++ b/doc/development/rubocop_development_guide.md
@@ -0,0 +1,114 @@
+---
+type: reference, dev
+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
+---
+
+# RuboCop rule development guide
+
+Our codebase style is defined and enforced by [RuboCop](https://github.com/rubocop-hq/rubocop).
+
+You can check for any offenses locally with `bundle exec rubocop --parallel`.
+On the CI, this is automatically checked by the `static-analysis` jobs.
+
+In addition, you can [integrate RuboCop](developing_with_solargraph.md) into
+supported IDEs using the [Solargraph](https://github.com/castwide/solargraph) gem.
+
+For RuboCop rules that we have not taken a decision on, follow the [Ruby style guide](backend/ruby_style_guide.md) to write idiomatic Ruby.
+
+Reviewers/maintainers should be tolerant and not too pedantic about style.
+
+Some RuboCop rules are disabled, and for those,
+reviewers/maintainers must not ask authors to use one style or the other, as both
+are accepted. This isn't an ideal situation because this leaves space for
+[bike-shedding](https://en.wiktionary.org/wiki/bikeshedding). Ideally we
+should enable all RuboCop rules to avoid style-related
+discussions, nitpicking, or back-and-forth in reviews. The
+[GitLab Ruby style guide](backend/ruby_style_guide.md) includes a non-exhaustive
+list of styles that commonly come up in reviews and are not enforced.
+
+Additionally, we have dedicated
+[test-specific style guides and best practices](testing_guide/index.md).
+
+## Creating new RuboCop cops
+
+Typically it is better for the linting rules to be enforced programmatically as it
+reduces the aforementioned [bike-shedding](https://en.wiktionary.org/wiki/bikeshedding).
+
+To that end, we encourage creation of new RuboCop rules in the codebase.
+
+Before adding a new cop to enforce a given style, make sure to discuss it with your team.
+
+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.
+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.
+
+## Cop grace period
+
+A cop is in a _grace period_ if it is enabled and has `Details: grace period` defined in its TODO YAML configuration.
+
+On the default branch, offenses from cops in the [grace period](rake_tasks.md#run-rubocop-in-graceful-mode) do not fail the RuboCop CI job. Instead, the job notifies the `#f_rubocop` Slack channel. However, on other branches, the RuboCop job fails.
+
+A grace period can safely be lifted as soon as there are no warnings for 2 weeks in the `#f_rubocop` channel on Slack.
+
+## Enabling a new cop
+
+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 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
+
+When offenses are silenced for cops in the [grace period](#cop-grace-period),
+the `#f_rubocop` Slack channel receives a notification message every 2 hours.
+
+To fix this issue:
+
+1. Find cops with silenced offenses in the linked CI job.
+1. [Generate TODOs](rake_tasks.md#generate-initial-rubocop-todo-list) for these cops.
+
+### RuboCop node pattern
+
+When creating [node patterns](https://docs.rubocop.org/rubocop-ast/node_pattern.html) to match
+Ruby's AST, you can use [`scripts/rubocop-parse`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/scripts/rubocop-parse).
+This displays the AST of a Ruby expression to help you create the matcher.
+See also [!97024](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97024).
+
+## Resolving RuboCop exceptions
+
+When the number of RuboCop exceptions exceeds the default [`exclude-limit` of 15](https://docs.rubocop.org/rubocop/1.2/usage/basic_usage.html#command-line-flags),
+we may want to resolve exceptions over multiple commits. To minimize confusion,
+we should track our progress through the exception list.
+
+The preferred way to [generate the initial list or a list for specific RuboCop rules](rake_tasks.md#generate-initial-rubocop-todo-list)
+is to run the Rake task `rubocop:todo:generate`:
+
+```shell
+# Initial list
+bundle exec rake rubocop:todo:generate
+
+# List for specific RuboCop rules
+bundle exec rake 'rubocop:todo:generate[Gitlab/NamespacedClass,Lint/Syntax]'
+```
+
+This Rake task creates or updates the exception list in `.rubocop_todo/`. For
+example, the configuration for the RuboCop rule `Gitlab/NamespacedClass` is
+located in `.rubocop_todo/gitlab/namespaced_class.yml`.
+
+Make sure to commit any changes in `.rubocop_todo/` after running the Rake task.
+
+## Reveal existing RuboCop exceptions
+
+To reveal existing RuboCop exceptions in the code that have been excluded via `.rubocop_todo.yml` and
+`.rubocop_todo/**/*.yml`, set the environment variable `REVEAL_RUBOCOP_TODO` to `1`.
+
+This allows you to reveal existing RuboCop exceptions during your daily work cycle and fix them along the way.
+
+NOTE:
+Define permanent `Exclude`s in `.rubocop.yml` instead of `.rubocop_todo/**/*.yml`.
diff --git a/doc/development/sec/analyzer_development_guide.md b/doc/development/sec/analyzer_development_guide.md
index a35bc2b7237..af3a6f2b7d7 100644
--- a/doc/development/sec/analyzer_development_guide.md
+++ b/doc/development/sec/analyzer_development_guide.md
@@ -78,11 +78,23 @@ go build -o analyzer
./analyzer convert test/fixtures/app/spotbugsXml.Xml > ./gl-sast-report.json
```
+### Execution criteria
+
+[Enabling SAST](../../user/application_security/sast/index.md#configure-sast-manually) requires including a pre-defined [template](https://gitlab.com/gitlab-org/gitlab/-/blob/ee4d473eb9a39f2f84b719aa0ca13d2b8e11dc7e/lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml) to your GitLab CI/CD configuration.
+
+The following independent criteria determine which analyzer needs to be run on a project:
+
+1. The SAST template uses [`rules:exists`](../../ci/yaml/index.md#rulesexists) to determine which analyzer will be run based on the presence of certain files. For example, the Brakeman analyzer [runs when there are](https://gitlab.com/gitlab-org/gitlab/-/blob/ee4d473eb9a39f2f84b719aa0ca13d2b8e11dc7e/lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml#L60) `.rb` files and a `Gemfile`.
+1. Each analyzer runs a customizable [match interface](https://gitlab.com/gitlab-org/security-products/analyzers/common/-/blob/master/search/search.go) before it performs the actual analysis. For example: [Flawfinder checks for C/C++ files](https://gitlab.com/gitlab-org/security-products/analyzers/flawfinder/-/blob/f972ac786268fb649553056a94cda05cdc1248b2/plugin/plugin.go#L14).
+1. For some analyzers that run on generic file extensions, there is a check based on a CI/CD variable. For example: Kubernetes manifests are written in YAML, so [Kubesec](https://gitlab.com/gitlab-org/security-products/analyzers/kubesec) runs only when [`SCAN_KUBERNETES_MANIFESTS` is set to true](../../user/application_security/sast/index.md#enabling-kubesec-analyzer).
+
+Step 1 helps prevent wastage of CI/CD minutes that would be spent running analyzers not suitable for the project. However, due to [technical limitations](https://gitlab.com/gitlab-org/gitlab/-/issues/227632), it cannot be used for large projects. Therefore, step 2 acts as final check to ensure a mismatched analyzer is able to exit early.
+
## How to test the analyzers
Video walkthrough of how Dependency Scanning analyzers are using [downstream pipeline](../../ci/pipelines/downstream_pipelines.md) feature to test analyzers using test projects:
-[![How Sec leverages the downstream pipeline feature of GitLab to test analyzers end to end](http://img.youtube.com/vi/KauRBlfUbDE/0.jpg)](http://www.youtube.com/watch?v=KauRBlfUbDE)
+[![How Sec leverages the downstream pipeline feature of GitLab to test analyzers end to end](https://img.youtube.com/vi/KauRBlfUbDE/0.jpg)](https://www.youtube.com/watch?v=KauRBlfUbDE)
### Testing local changes
@@ -118,6 +130,12 @@ To use Docker with `replace` in the `go.mod` file:
1. Update the `replace` statement to make sure it matches the destination of the `COPY` statement in the step above:
`replace gitlab.com/gitlab-org/security-products/analyzers/command/v3 => /command`
+## Analyzer scripts
+
+The [analyzer-scripts](https://gitlab.com/gitlab-org/secure/tools/analyzer-scripts) repository contains scripts that can be used to interact with most analyzers. They enable you to build, run, and debug analyzers in a GitLab CI-like environment, and are particularly useful for locally validating changes to an analyzer.
+
+For more information, refer to the [project README](https://gitlab.com/gitlab-org/secure/tools/analyzer-scripts/-/blob/master/README.md).
+
## Versioning and release process
Analyzers are independent projects that follow their own versioning. `Patch` version bumps tend to correspond to a `Minor` version bump of the underlying tools (i.e. [`bandit`](https://wiki.openstack.org/wiki/Security/Projects/Bandit)), allowing us greater flexibility in reserving `Minor` bumps for more significant changes to our scanners. In case of breaking changes imposed by the wrapped scanner, creating a new analyzer on a separate repository must be considered.
diff --git a/doc/development/sec/img/primary_identifier_changed_v15_6.png b/doc/development/sec/img/primary_identifier_changed_v15_6.png
new file mode 100644
index 00000000000..aa1a116c801
--- /dev/null
+++ b/doc/development/sec/img/primary_identifier_changed_v15_6.png
Binary files differ
diff --git a/doc/development/sec/index.md b/doc/development/sec/index.md
index c9805044e58..fc13c960451 100644
--- a/doc/development/sec/index.md
+++ b/doc/development/sec/index.md
@@ -64,7 +64,97 @@ After the data is available as a Report Artifact it can be processed by the GitL
Depending on the context, the security reports may be stored either in the database or stay as Report Artifacts for on-demand access.
+#### Security report ingestion overview
+
+For details on how GitLab processes the reports generated by the scanners, see
+[Security report ingestion overview](security_report_ingestion_overview.md).
+
## CI/CD template development
While CI/CD templates are the responsibility of the Verify section, many are critical to the Sec Section's feature usage.
If you are working with CI/CD templates, please read the [development guide for GitLab CI/CD templates](../cicd/templates.md).
+
+## Importance of the primary identifier
+
+Within analyzer JSON reports, the [`identifiers` field](../integrations/secure.md#identifiers) contains a collection of types and categories by which
+a vulnerability can be described (that is, a CWE family).
+
+The first item in the `identifiers` collection is known as the [primary identifier](../../user/application_security/terminology#primary-identifier),
+a critical component to both describing and tracking vulnerabilities.
+
+In most other cases, the `identifiers` collection is unordered, where the remaining secondary identifiers act as metadata for grouping vulnerabilities
+(see [Analyzer vulnerability translation](#analyzer-vulnerability-translation) below for the exception).
+
+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)
+
+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).
+
+### Guiding principles for ensuring primary identifier stability
+
+- A primary identifier should never change unless we have a compelling reason.
+- Analyzer supporting vulnerability translation must include the legacy primary identifiers in a secondary position to prevent “orphaning†of results.
+- Beyond the primary identifier, the order of secondary identifiers does not matter.
+- The identifier is unique based on a combination of the `Type` and `Value` fields (see [identifier fingerprint](https://gitlab.com/gitlab-org/gitlab/-/blob/v15.5.1-ee/lib/gitlab/ci/reports/security/identifier.rb#L63)).
+- If we change the primary identifier, rolling back analyzers to previous versions will not fix the orphaned results. The data previously ingested into our database is an artifact of previous jobs with few ways of automating data migrations.
+
+### Analyzer vulnerability translation
+
+In the case of SAST's semgrep analyzer, there is a secondary identifier of particular importance: the identifier linking the report’s vulnerability
+to the legacy analyzer (that is, bandit or eslint).
+
+To [enable vulnerability translation](../../user/application_security/sast/analyzers.md#vulnerability-translation)
+the semgrep analyzer relies on a secondary identifier exactly matching the primary identifier of the legacy analyzer.
+
+For example, when [`eslint`](https://gitlab.com/gitlab-org/security-products/analyzers/eslint) was previously used to generate vulnerability records,
+the [`semgrep`](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) analyzer must produce an identifier collection containing the
+original eslint primary identifier.
+
+Given the original `eslint` report:
+
+```json
+{
+ "version": "14.0.4",
+ "vulnerabilities": [
+ {
+ "identifiers": [
+ {
+ "type": "eslint_rule_id",
+ "name": "ESLint rule ID security/detect-eval-with-expression",
+ "value": "security/detect-eval-with-expression"
+ }
+ ]
+ }
+ ]
+}
+```
+
+The corresponding semgrep report must contain the `eslint_rule_id`:
+
+```json
+{
+ "version": "14.0.4",
+ "vulnerabilities": [
+ {
+ "identifiers": [
+ {
+ "type": "semgrep_id",
+ "name": "eslint.detect-eval-with-expression",
+ "value": "eslint.detect-eval-with-expression",
+ "url": "https://semgrep.dev/r/gitlab.eslint.detect-eval-with-expression"
+ },
+ {
+ "type": "eslint_rule_id",
+ "name": "ESLint rule ID security/detect-eval-with-expression",
+ "value": "security/detect-eval-with-expression"
+ }
+ ]
+ }
+ ]
+}
+```
+
+[Tracking of vulnerabilities](../integrations/secure.md#tracking-and-merging-vulnerabilities) relies on a combination of the two identifiers
+to remap DB records previously generated with the legacy analyzers to those generated with the new `semgrep` ones.
diff --git a/doc/development/sec/security_report_ingestion_overview.md b/doc/development/sec/security_report_ingestion_overview.md
new file mode 100644
index 00000000000..c1d977c2a17
--- /dev/null
+++ b/doc/development/sec/security_report_ingestion_overview.md
@@ -0,0 +1,74 @@
+---
+stage: Secure
+group: Threat Insights
+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
+type: concepts
+---
+
+# Security report ingestion overview
+
+## Definitions
+
+- **Vulnerability Finding** – an instance of `Vulnerabilities::Finding` class. This class was previously called `Vulnerabilities::Occurrence`; after renaming the class, we kept the associated table name `vulnerability_occurrences` due to the effort involved in renaming large tables.
+- **Vulnerability** – an instance of `Vulnerability` class. They are created based on information available in `Vulnerabilities::Finding` class. Every `Vulnerability` **must have** a corresponding `Vulnerabilities::Finding` object to be valid, however this is not enforced at the database level.
+- **Security Finding** – an instance of `Security::Finding` class. They store **partial** finding data to improve performance of the pipeline security report. We are working on extending this class to store almost all required information so we can stop relying on job artifacts.
+- **Feedback** – an instance of `Vulnerabilities::Feedback` class. They are created to keep track of users' interactions with Vulnerability Findings before they are promoted to a Vulnerability. We are in the process of removing this model via [Deprecate and remove Vulnerabilities::Feedback epic](https://gitlab.com/groups/gitlab-org/-/epics/5629).
+- **Issue Link** – an instance of `Vulnerabilities::IssueLink` class. They are used to link `Vulnerability` objects to `Issue` objects.
+
+## Vulnerability creation from security reports
+
+Assumptions:
+
+- Project uses GitLab CI
+- Project uses [security scanning tools](../../user/application_security)
+- No Vulnerabilities are present in the database
+- All pipelines perform security scans
+
+1. Code is pushed to a branch that's **not** the default branch.
+1. GitLab CI runs a new pipeline for that branch.
+1. Pipeline status transitions to any of [`::Ci::Pipeline.completed_statuses`](https://gitlab.com/gitlab-org/gitlab/-/blob/354261b2fe4fc5b86d1408467beadd90e466ce0a/app/models/concerns/ci/has_status.rb#L12).
+1. `Security::StoreScansWorker` is called and it schedules `Security::StoreScansService`.
+1. `Security::StoreScansService` calls `Security::StoreGroupedScansService`.
+1. `Security::StoreGroupedScansService` calls `Security::StoreScanService`.
+1. `Security::StoreScanService` calls `Security::StoreFindingsService`.
+1. At this point we have `Security::Finding` objects **only**.
+
+At this point, the following things can happen to the `Security::Finding`:
+
+- Dismissal
+- Issue creation
+- Promotion to a Vulnerability
+
+If the pipeline ran on the default branch then the following, additional steps are done:
+
+1. `Security::StoreScansService` gets called and schedules `Security::StoreSecurityReportsWorker`.
+1. `Security::StoreSecurityReportsWorker` executes `Security::Ingestion::IngestReportsService`.
+1. `Security::Ingestion::IngestReportsService` takes all reports from a given Pipeline and calls `Security::Ingestion::IngestReportService` and then calls `Security::Ingestion::MarkAsResolvedService`.
+1. `Security::Ingestion::IngestReportService` calls `Security::Ingestion::IngestReportSliceService` which executes a number of tasks for a report slice.
+
+### Dismissal
+
+If you select `Dismiss vulnerability`, a Feedback is created. You can also dismiss it with a comment.
+
+#### After Feedback removal
+
+If there is only a Security Finding, a Vulnerability Finding and a Vulnerability get created. At the same time we create a `Vulnerabilities::StateTransition` record to indicate the Vulnerability was dismissed.
+
+### Issue creation
+
+If you select `Create issue`, a Vulnerabilities::Feedback record is created as well. The Feedback has a different `feedback_type` and an `issue_id` that’s not `NULL`.
+
+NOTE:
+Vulnerabilities::Feedback are in the process of being [deprecated](https://gitlab.com/groups/gitlab-org/-/epics/5629). This will later create a `Vulnerabilities::IssueLink` record.
+
+#### After Feedback removal
+
+If there's only a Security Finding, a Vulnerability Finding and a Vulnerability gets created. At the same time, we create an Issue and a Issue Link.
+
+## Promotion to a Vulnerability
+
+If the branch with a Security Finding gets merged into the default branch, all Security Findings get promoted into Vulnerabilities. Promotion is the process of creating Vulnerability Findings and Vulnerability records from those Security Findings.
+
+If there's a dismissal Feedback present for that Security Finding, the created Vulnerability is marked as dismissed.
+
+If there's an issue Feedback present for that Security Finding, we also create an Issue Link for that Vulnerability.
diff --git a/doc/development/secure_coding_guidelines.md b/doc/development/secure_coding_guidelines.md
index 67f7c556055..c102e99720f 100644
--- a/doc/development/secure_coding_guidelines.md
+++ b/doc/development/secure_coding_guidelines.md
@@ -856,7 +856,7 @@ Working with archive files like `zip`, `tar`, `jar`, `war`, `cpio`, `apk`, `rar`
### Zip Slip
-In 2018, the security company Snyk [released a blog post](https://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.
+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.
A Zip Slip vulnerability happens when an application extracts an archive without validating and sanitizing the filenames inside the archive for directory traversal sequences that change the file location when the file is extracted.
@@ -1218,7 +1218,7 @@ GitLab-specific example can be found in [this issue](https://gitlab.com/gitlab-o
**Example 3:** you need to fetch a remote file, and perform a `HEAD` request to get and validate the content length and content type. When you subsequently make a `GET` request, though, the file delivered is a different size or different file type. (This is stretching the definition of TOCTOU, but things _have_ changed between time of check and time of use).
-**Example 4:** you allow users to upvote a comment if they haven't already. The server is multi-threaded, and you aren't using transactions or an applicable database index. By repeatedly clicking upvote in quick succession a malicious user is able to add multiple upvotes: the requests arrive at the same time, the checks run in parallel and confirm that no upvote exists yet, and so each upvote is written to the database.
+**Example 4:** you allow users to upvote a comment if they haven't already. The server is multi-threaded, and you aren't using transactions or an applicable database index. By repeatedly selecting upvote in quick succession a malicious user is able to add multiple upvotes: the requests arrive at the same time, the checks run in parallel and confirm that no upvote exists yet, and so each upvote is written to the database.
Here's some pseudocode showing an example of a potential TOCTOU bug:
@@ -1271,7 +1271,7 @@ This sensitive data must be handled carefully to avoid leaks which could lead to
- The [Gitleaks Git hook](https://gitlab.com/gitlab-com/gl-security/security-research/gitleaks-endpoint-installer) is recommended for preventing credentials from being committed.
- Never log credentials under any circumstance. Issue [#353857](https://gitlab.com/gitlab-org/gitlab/-/issues/353857) is an example of credential leaks through log file.
- When credentials are required in a CI/CD job, use [masked variables](../ci/variables/index.md#mask-a-cicd-variable) to help prevent accidental exposure in the job logs. Be aware that when [debug logging](../ci/variables/index.md#debug-logging) is enabled, all masked CI/CD variables are visible in job logs. Also consider using [protected variables](../ci/variables/index.md#protected-cicd-variables) when possible so that sensitive CI/CD variables are only available to pipelines running on protected branches or protected tags.
-- Proper scanners must be enabled depending on what data those credentials are protecting. See the [Application Security Inventory Policy](https://about.gitlab.com/handbook/engineering/security/security-engineering-and-research/application-security/inventory.html#policies) and our [Data Classification Standards](https://about.gitlab.com/handbook/engineering/security/data-classification-standard.html#data-classification-standards).
+- Proper scanners must be enabled depending on what data those credentials are protecting. See the [Application Security Inventory Policy](https://about.gitlab.com/handbook/security/security-engineering-and-research/application-security/inventory.html#policies) and our [Data Classification Standards](https://about.gitlab.com/handbook/security/data-classification-standard.html#data-classification-standards).
- To store and/or share credentials between teams, refer to [1Password for Teams](https://about.gitlab.com/handbook/security/#1password-for-teams) and follow [the 1Password Guidelines](https://about.gitlab.com/handbook/security/#1password-guidelines).
- If you need to share a secret with a team member, use 1Password. Do not share a secret over email, Slack, or other service on the Internet.
@@ -1281,7 +1281,7 @@ This sensitive data must be handled carefully to avoid leaks which could lead to
- Avoid including credentials as part of an HTTP response unless it is absolutely necessary as part of the workflow. For example, generating a PAT for users.
- Avoid sending credentials in URL parameters, as these can be more easily logged inadvertently during transit.
-In the event of credential leak through an MR, issue, or any other medium, [reach out to SIRT team](https://about.gitlab.com/handbook/engineering/security/security-operations/sirt/#-engaging-sirt).
+In the event of credential leak through an MR, issue, or any other medium, [reach out to SIRT team](https://about.gitlab.com/handbook/security/security-operations/sirt/#-engaging-sirt).
## Serialization
diff --git a/doc/development/service_ping/implement.md b/doc/development/service_ping/implement.md
index 88a1454393f..5a564b2d83e 100644
--- a/doc/development/service_ping/implement.md
+++ b/doc/development/service_ping/implement.md
@@ -231,13 +231,6 @@ Examples:
estimate_batch_distinct_count(::Note.with_suggestions.where(time_period), :author_id, start: ::Note.minimum(:id), finish: ::Note.maximum(:id))
```
-1. Execution of estimated batch counter with joined relation (`joins(:cluster)`),
- for a custom column (`'clusters.user_id'`):
-
- ```ruby
- estimate_batch_distinct_count(::Clusters::Applications::CertManager.where(time_period).available.joins(:cluster), 'clusters.user_id')
- ```
-
When instrumenting metric with usage of estimated batch counter please add
`_estimated` suffix to its name, for example:
@@ -266,7 +259,7 @@ Arguments:
#### Ordinary Redis counters
-Example of implementation: [`Gitlab::UsageDataCounters::WikiPageCounter`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/wiki_page_counter.rb), using Redis methods [`INCR`](https://redis.io/commands/incr) and [`GET`](https://redis.io/commands/get).
+Example of implementation: [`Gitlab::UsageDataCounters::WikiPageCounter`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data_counters/wiki_page_counter.rb), using Redis methods [`INCR`](https://redis.io/commands/incr/) and [`GET`](https://redis.io/commands/get/).
Events are handled by counter classes in the `Gitlab::UsageDataCounters` namespace, inheriting from `BaseCounter`, that are either:
@@ -813,7 +806,7 @@ and run a local container instance:
1. On your local machine, make sure you are signed in to the GitLab Docker registry. You can find the instructions for this in
[Authenticate to the GitLab Container Registry](../../user/packages/container_registry/index.md#authenticate-with-the-container-registry).
1. Once signed in, download the new image by using `docker pull registry.gitlab.com/gitlab-org/build/omnibus-gitlab-mirror/gitlab-ee:<VERSION>`
-1. For more information about working with and running Omnibus GitLab containers in Docker, refer to [GitLab Docker images](https://docs.gitlab.com/omnibus/docker/README.html) in the Omnibus documentation.
+1. For more information about working with and running Omnibus GitLab containers in Docker, refer to [GitLab Docker images](../../install/docker.md) documentation.
### Test with GitLab development toolkits
@@ -849,105 +842,6 @@ You can then count each user that performed any combination of these actions.
To add data for aggregated metrics to the Service Ping payload,
create metric YAML definition file following [Aggregated metric instrumentation guide](metrics_instrumentation.md#aggregated-metrics).
-### (DEPRECATED) Defining aggregated metric via aggregated metric YAML config file
-
-WARNING:
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98206) in GitLab 15.5
-and is planned for removal in 15.5. Use [metrics definition YAMLs](https://gitlab.com/gitlab-org/gitlab/-/issues/370963) instead.
-
-To add data for aggregated metrics to the Service Ping payload, add a corresponding definition to:
-
-- [`config/metrics/aggregates/*.yaml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/aggregates/) for metrics available in the Community Edition.
-- [`ee/config/metrics/aggregates/*.yaml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/aggregates/) for metrics available in the Enterprise Edition.
-
-Each aggregate definition includes following parts:
-
-- `name`: Unique name under which the aggregate metric is added to the Service Ping payload.
-- `operator`: Operator that defines how the aggregated metric data is counted. Available operators are:
- - `OR`: Removes duplicates and counts all entries that triggered any of listed events.
- - `AND`: Removes duplicates and counts all elements that were observed triggering all of following events.
-- `time_frame`: One or more valid time frames. Use these to limit the data included in aggregated metric to events within a specific date-range. Valid time frames are:
- - `7d`: Last seven days of data.
- - `28d`: Last twenty eight days of data.
- - `all`: All historical data, only available for `database` sourced aggregated metrics.
-- `source`: Data source used to collect all events data included in aggregated metric. Valid data sources are:
- - [`database`](#database-sourced-aggregated-metrics)
- - [`redis`](#redis-sourced-aggregated-metrics)
-- `events`: list of events names to aggregate into metric. All events in this list must
- relay on the same data source. Additional data source requirements are described in the
- [Database sourced aggregated metrics](#database-sourced-aggregated-metrics) and
- [Redis sourced aggregated metrics](#redis-sourced-aggregated-metrics) sections.
-- `feature_flag`: Name of [development feature flag](../feature_flags/index.md#development-type)
- that is checked before metrics aggregation is performed. Corresponding feature flag
- should have `default_enabled` attribute set to `false`. The `feature_flag` attribute
- is optional and can be omitted. When `feature_flag` is missing, no feature flag is checked.
-
-Example aggregated metric entries:
-
-```yaml
-- name: example_metrics_union
- operator: OR
- events:
- - 'users_expanding_secure_security_report'
- - 'users_expanding_testing_code_quality_report'
- - 'users_expanding_testing_accessibility_report'
- source: redis
- time_frame:
- - 7d
- - 28d
-- name: example_metrics_intersection
- operator: AND
- source: database
- time_frame:
- - 28d
- - all
- events:
- - 'dependency_scanning_pipeline_all_time'
- - 'container_scanning_pipeline_all_time'
- feature_flag: example_aggregated_metric
-```
-
-Aggregated metrics collected in `7d` and `28d` time frames are added into Service Ping payload under the `aggregated_metrics` sub-key in the `counts_weekly` and `counts_monthly` top level keys.
-
-```ruby
-{
- :counts_monthly => {
- :deployments => 1003,
- :successful_deployments => 78,
- :failed_deployments => 275,
- :packages => 155,
- :personal_snippets => 2106,
- :project_snippets => 407,
- :aggregated_metrics => {
- :example_metrics_union => 7,
- :example_metrics_intersection => 2
- },
- :snippets => 2513
- }
-}
-```
-
-Aggregated metrics for `all` time frame are present in the `count` top level key, with the `aggregate_` prefix added to their name.
-
-For example:
-
-`example_metrics_intersection`
-
-Becomes:
-
-`counts.aggregate_example_metrics_intersection`
-
-```ruby
-{
- :counts => {
- :deployments => 11003,
- :successful_deployments => 178,
- :failed_deployments => 1275,
- :aggregate_example_metrics_intersection => 12
- }
-}
-```
-
### Redis sourced aggregated metrics
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45979) in GitLab 13.6.
@@ -963,9 +857,7 @@ you must fulfill the following requirements:
### Database sourced aggregated metrics
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52784) in GitLab 13.9.
-> - It's [deployed behind a feature flag](../../user/feature_flags.md), disabled by default.
-> - It's enabled on GitLab.com.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52784) in GitLab 13.9.
To declare an aggregate of metrics based on events collected from database, follow
these steps:
@@ -1018,25 +910,9 @@ end
#### Add new aggregated metric definition
-After all metrics are persisted, you can add an aggregated metric definition at
-[`aggregated_metrics/`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/aggregates/).
-
+After all metrics are persisted, you can add an aggregated metric definition following [Aggregated metric instrumentation guide](metrics_instrumentation.md#aggregated-metrics).
To declare the aggregate of metrics collected with [Estimated Batch Counters](#estimated-batch-counters),
you must fulfill the following requirements:
- Metrics names listed in the `events:` attribute, have to use the same names you passed in the `metric_name` argument while persisting metrics in previous step.
- Every metric listed in the `events:` attribute, has to be persisted for **every** selected `time_frame:` value.
-
-Example definition:
-
-```yaml
-- name: example_metrics_intersection_database_sourced
- operator: AND
- source: database
- events:
- - 'dependency_scanning_pipeline'
- - 'container_scanning_pipeline'
- time_frame:
- - 28d
- - all
-```
diff --git a/doc/development/service_ping/index.md b/doc/development/service_ping/index.md
index 0a4e5998345..37e0b753448 100644
--- a/doc/development/service_ping/index.md
+++ b/doc/development/service_ping/index.md
@@ -115,7 +115,7 @@ sequenceDiagram
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/295289) in GitLab 15.2. [Feature flag `measure_service_ping_metric_collection`](https://gitlab.com/gitlab-org/gitlab/-/issues/358128) removed.
```ruby
- {
+ {
"metadata"=>
{
"uuid"=>"0000000-0000-0000-0000-000000000000",
@@ -504,7 +504,7 @@ Service Ping reporting process state is monitored with [internal SiSense dashboa
- [Product Intelligence Guide](https://about.gitlab.com/handbook/product/product-intelligence-guide/)
- [Snowplow Guide](../snowplow/index.md)
-- [Product Intelligence Direction](https://about.gitlab.com/direction/product-intelligence/)
+- [Product Intelligence Direction](https://about.gitlab.com/direction/analytics/product-intelligence/)
- [Data Analysis Process](https://about.gitlab.com/handbook/business-technology/data-team/#data-analysis-process/)
- [Data for Product Managers](https://about.gitlab.com/handbook/business-technology/data-team/programs/data-for-product-managers/)
- [Data Infrastructure](https://about.gitlab.com/handbook/business-technology/data-team/platform/infrastructure/)
diff --git a/doc/development/service_ping/metrics_instrumentation.md b/doc/development/service_ping/metrics_instrumentation.md
index 7a3f291460c..a9f236819fe 100644
--- a/doc/development/service_ping/metrics_instrumentation.md
+++ b/doc/development/service_ping/metrics_instrumentation.md
@@ -41,7 +41,7 @@ We have built a domain-specific language (DSL) to define the metrics instrumenta
You can use database metrics to track data kept in the database, for example, a count of issues that exist on a given instance.
- `operation`: Operations for the given `relation`, one of `count`, `distinct_count`, `sum`, and `average`.
-- `relation`: `ActiveRecord::Relation` for the objects we want to perform the `operation`.
+- `relation`: Assigns lambda that returns the `ActiveRecord::Relation` for the objects we want to perform the `operation`. The assigned lambda can accept up to one parameter. The parameter is hashed and stored under the `options` key in the metric definition.
- `start`: Specifies the start value of the batch counting, by default is `relation.minimum(:id)`.
- `finish`: Specifies the end value of the batch counting, by default is `relation.maximum(:id)`.
- `cache_start_and_finish_as`: Specifies the cache key for `start` and `finish` values and sets up caching them. Use this call when `start` and `finish` are expensive queries that should be reused between different metric calculations.
@@ -55,10 +55,10 @@ module Gitlab
module Usage
module Metrics
module Instrumentations
- class CountBoardsMetric < DatabaseMetric
+ class CountIssuesMetric < DatabaseMetric
operation :count
- relation { Board }
+ relation ->(options) { Issue.where(confidential: options[:confidential]) }
end
end
end
@@ -156,7 +156,7 @@ You can use Redis metrics to track events not kept in the database, for example,
[Example of a merge request that adds a `Redis` metric](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97009).
-Please note that `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.
+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.
@@ -256,6 +256,13 @@ options:
## Aggregated metrics
+<div class="video-fallback">
+ See the video from: <a href="https://www.youtube.com/embed/22LbYqHwtUQ">Product Intelligence Office Hours Oct 6th</a> for an aggregated metrics walk-through.
+</div>
+<figure class="video-container">
+ <iframe src="https://www.youtube.com/embed/22LbYqHwtUQ" frameborder="0" allowfullscreen="true"> </iframe>
+</figure>
+
The aggregated metrics feature provides insight into the number of data attributes, for example `pseudonymized_user_ids`, that occurred in a collection of events. For example, you can aggregate the number of users who perform multiple actions such as creating a new issue and opening
a new merge request.
diff --git a/doc/development/service_ping/metrics_lifecycle.md b/doc/development/service_ping/metrics_lifecycle.md
index f13aebeb16e..92c5d2d317d 100644
--- a/doc/development/service_ping/metrics_lifecycle.md
+++ b/doc/development/service_ping/metrics_lifecycle.md
@@ -25,6 +25,10 @@ Any such changes lead to inconsistent reports from multiple GitLab instances.
If there is a problem with an existing metric, it's best to deprecate the existing metric,
and use it, side by side, with the desired new metric.
+If you do need to change a metric, please notify the Customer Success Ops team (`@csops-team`), Analytics Engineers (`@gitlab-data/analytics-engineers`), and Product Analysts (`@gitlab-data/product-analysts`) teams by `@` mentioning those groups in a comment on the MR.
+Many Service Ping metrics are relied upon for health score and XMAU reporting and
+unexpected changes to those metrics could break reporting.
+
Example:
Consider following change. Before GitLab 12.6, the `example_metric` was implemented as:
@@ -135,3 +139,6 @@ To remove a metric:
1. Remove any other records related to the metric:
- The feature flag YAML file at [`config/feature_flags/*/*.yaml`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/config/feature_flags).
- The entry in the known events YAML file at [`lib/gitlab/usage_data_counters/known_events/*.yaml`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/usage_data_counters/known_events).
+
+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 on the MR.
+ Many Service Ping metrics are relied upon for health score and XMAU reporting and unexpected changes to those metrics could break reporting.
diff --git a/doc/development/service_ping/review_guidelines.md b/doc/development/service_ping/review_guidelines.md
index a1806551303..70f7f3dca54 100644
--- a/doc/development/service_ping/review_guidelines.md
+++ b/doc/development/service_ping/review_guidelines.md
@@ -68,6 +68,7 @@ are regular backend changes.
Read the [stages file](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml).
- Check the file location. Consider the time frame, and if the file should be under `ee`.
- Check the tiers.
+- If a metric was changed or removed: Make sure the MR author notified 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 on the MR.
- Metrics instrumentations
- Recommend using metrics instrumentation for new metrics, [if possible](metrics_instrumentation.md#support-for-instrumentation-classes).
- Approve the MR, and relabel the MR with `~"product intelligence::approved"`.
diff --git a/doc/development/service_ping/troubleshooting.md b/doc/development/service_ping/troubleshooting.md
index 201d6a385eb..f8fd45e6062 100644
--- a/doc/development/service_ping/troubleshooting.md
+++ b/doc/development/service_ping/troubleshooting.md
@@ -120,3 +120,45 @@ To work around this bug, you have two options:
1. Expand **Usage Statistics**.
1. Clear the **Enable Service Ping** checkbox.
1. Select **Save Changes**.
+
+## Generate Service Ping
+
+### Generate or get the cached Service Ping in rails console
+
+Use the following method in the [rails console](../../administration/operations/rails_console.md#starting-a-rails-console-session).
+
+```ruby
+Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values, cached: true)
+```
+
+### Generate a fresh new Service Ping
+
+Use the following method in the [rails console](../../administration/operations/rails_console.md#starting-a-rails-console-session).
+
+This also refreshes the cached Service Ping displayed in the Admin Area.
+
+```ruby
+Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values)
+```
+
+### Generate and print
+
+Generates Service Ping data in JSON format.
+
+```shell
+gitlab-rake gitlab:usage_data:generate
+```
+
+Generates Service Ping data in YAML format:
+
+```shell
+gitlab-rake gitlab:usage_data:dump_sql_in_yaml
+```
+
+### Generate and send Service Ping
+
+Prints the metrics saved in `conversational_development_index_metrics`.
+
+```shell
+gitlab-rake gitlab:usage_data:generate_and_send
+```
diff --git a/doc/development/service_ping/usage_data.md b/doc/development/service_ping/usage_data.md
index 2f2df14f56d..1c7a212ed64 100644
--- a/doc/development/service_ping/usage_data.md
+++ b/doc/development/service_ping/usage_data.md
@@ -66,5 +66,4 @@ Examples:
```ruby
distinct_count(::Project, :creator_id)
distinct_count(::Note.with_suggestions.where(time_period), :author_id, start: ::User.minimum(:id), finish: ::User.maximum(:id))
-distinct_count(::Clusters::Applications::CertManager.where(time_period).available.joins(:cluster), 'clusters.user_id')
```
diff --git a/doc/development/shell_commands.md b/doc/development/shell_commands.md
index 3935e98199a..d78a005d76b 100644
--- a/doc/development/shell_commands.md
+++ b/doc/development/shell_commands.md
@@ -71,6 +71,8 @@ FileUtils.touch myfile
This coding style could have prevented CVE-2013-4546.
+See also <https://gitlab.com/gitlab-org/gitlab/-/merge_requests/93030>, and <https://starlabs.sg/blog/2022/07-gitlab-project-import-rce-analysis-cve-2022-2185/> for another example.
+
## Separate options from arguments with --
Make the difference between options and arguments clear to the argument parsers of system commands with `--`. This is supported by many but not all Unix commands.
diff --git a/doc/development/sidekiq/index.md b/doc/development/sidekiq/index.md
index e8c939571cf..a95e94cdd34 100644
--- a/doc/development/sidekiq/index.md
+++ b/doc/development/sidekiq/index.md
@@ -36,6 +36,31 @@ with back-off between each retry. 25 retries means that the last retry
would happen around three weeks after the first attempt (assuming all 24
prior retries failed).
+This means that a lot can happen in between the job being scheduled
+and its execution. Therefore, we must guard workers so they don't
+fail 25 times when the state changes after they are scheduled. For
+example, a job should not fail when the project it was scheduled for
+is deleted.
+
+Instead of:
+
+```ruby
+def perform(project_id)
+ project = Project.find(project_id)
+ # ...
+end
+```
+
+Do this:
+
+```ruby
+def perform(project_id)
+ project = Project.find_by_id(project_id)
+ return unless project
+ # ...
+end
+```
+
For most workers - especially [idempotent workers](idempotent_jobs.md) -
the default of 25 retries is more than sufficient. Many of our older
workers declare 3 retries, which used to be the default within the
diff --git a/doc/development/sidekiq/worker_attributes.md b/doc/development/sidekiq/worker_attributes.md
index 48a222d65a0..4fcd8e33d5c 100644
--- a/doc/development/sidekiq/worker_attributes.md
+++ b/doc/development/sidekiq/worker_attributes.md
@@ -277,7 +277,7 @@ they prefer read replicas and will wait for replicas to catch up:
| **Data Consistency** | **Description** |
|--------------|-----------------------------|
-| `:always` | The job is required to use the primary database (default). It should be used for workers that primarily perform writes or that have strict requirements around data consistency when reading their own writes. |
+| `:always` | The job is required to use the primary database (default). It should be used for workers that primarily perform writes, have strict requirements around data consistency when reading their own writes, or are cron jobs. |
| `:sticky` | The job prefers replicas, but switches to the primary for writes or when encountering replication lag. It should be used for jobs that require to be executed as fast as possible but can sustain a small initial queuing delay. |
| `:delayed` | The job prefers replicas, but switches to the primary for writes. When encountering replication lag before the job starts, the job is retried once. If the replica is still not up to date on the next retry, it switches to the primary. It should be used for jobs where delaying execution further typically does not matter, such as cache expiration or web hooks execution. |
diff --git a/doc/development/snowplow/event_dictionary_guide.md b/doc/development/snowplow/event_dictionary_guide.md
index c5a21f5a081..794a9a0160c 100644
--- a/doc/development/snowplow/event_dictionary_guide.md
+++ b/doc/development/snowplow/event_dictionary_guide.md
@@ -22,24 +22,24 @@ All event definitions are stored in the following directories:
Each event is defined in a separate YAML file consisting of the following fields:
-| Field | Required | Additional information |
-|------------------------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `description` | yes | A description of the event. |
-| `category` | yes | The event category (see [Structured event taxonomy](index.md#structured-event-taxonomy)). |
-| `action` | yes | The event action (see [Structured event taxonomy](index.md#structured-event-taxonomy)). |
-| `label_description` | no | A description of the event label (see [Structured event taxonomy](index.md#structured-event-taxonomy)). |
-| `property_description` | no | A description of the event property (see [Structured event taxonomy](index.md#structured-event-taxonomy)). |
-| `value_description` | no | A description of the event value (see [Structured event taxonomy](index.md#structured-event-taxonomy)). |
-| `extra_properties` | no | The type and description of each extra property sent with the event. |
-| `identifiers` | no | A list of identifiers sent with the event. Can be set to one or more of `project`, `user`, or `namespace`. |
-| `iglu_schema_url` | no | The URL to the custom schema sent with the event, for example, `iglu:com.gitlab/gitlab_experiment/jsonschema/1-0-0`. |
-| `product_section` | yes | The [section](https://gitlab.com/gitlab-com/www-gitlab-com/-/blob/master/data/sections.yml). |
-| `product_stage` | no | The [stage](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml) for the event. |
-| `product_group` | yes | The [group](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml) that owns the event. |
-| `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`. |
+| Field | Required | Additional information |
+|------------------------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `description` | yes | A description of the event. |
+| `category` | yes | The event category (see [Event schema](index.md#event-schema)). |
+| `action` | yes | The event action (see [Event schema](index.md#event-schema)). |
+| `label_description` | no | A description of the event label (see [Event schema](index.md#event-schema)). |
+| `property_description` | no | A description of the event property (see [Event schema](index.md#event-schema)). |
+| `value_description` | no | A description of the event value (see [Event schema](index.md#event-schema)). |
+| `extra_properties` | no | The type and description of each extra property sent with the event. |
+| `identifiers` | no | A list of identifiers sent with the event. Can be set to one or more of `project`, `user`, or `namespace`. |
+| `iglu_schema_url` | no | The URL to the custom schema sent with the event, for example, `iglu:com.gitlab/gitlab_experiment/jsonschema/1-0-0`. |
+| `product_section` | yes | The [section](https://gitlab.com/gitlab-com/www-gitlab-com/-/blob/master/data/sections.yml). |
+| `product_stage` | no | The [stage](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml) for the event. |
+| `product_group` | yes | The [group](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml) that owns the event. |
+| `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`. |
### Example event definition
diff --git a/doc/development/snowplow/implementation.md b/doc/development/snowplow/implementation.md
index 26016eeba84..a80d6fe70ff 100644
--- a/doc/development/snowplow/implementation.md
+++ b/doc/development/snowplow/implementation.md
@@ -13,7 +13,7 @@ This page describes how to:
## Snowplow JavaScript frontend tracking
-GitLab provides a `Tracking` interface that wraps the [Snowplow JavaScript tracker](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/)
+GitLab provides a `Tracking` interface that wraps the [Snowplow JavaScript tracker](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/javascript-trackers/)
to track custom events.
For the recommended frontend tracking implementation, see [Usage recommendations](#usage-recommendations).
@@ -42,14 +42,14 @@ and the custom `extra` object. You can modify this object for any subsequent
structured event that fires, although this is not recommended.
Tracking implementations must have an `action` and a `category`. You can provide additional
-properties from the [structured event taxonomy](index.md#structured-event-taxonomy), in
+properties from the [event schema](index.md#event-schema), in
addition to an `extra` object that accepts key-value pairs.
-| Property | Type | Default value | Description |
-|:-----------|:-------|:---------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `category` | string | `document.body.dataset.page` | Page or subsection of a page in which events are captured. |
+| Property | Type | Default value | Description |
+|:-----------|:-------|:---------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `category` | string | `document.body.dataset.page` | Page or subsection of a page in which events are captured. |
| `action` | string | `'generic'` | Action the user is taking. Clicks must be `click` and activations must be `activate`. For example, focusing a form field is `activate_form_input`, and clicking a button is `click_button`. |
-| `data` | object | `{}` | Additional data such as `label`, `property`, `value` as described in [Structured event taxonomy](index.md#structured-event-taxonomy), `context` for custom contexts, and `extra` (key-value pairs object). |
+| `data` | object | `{}` | Additional data such as `label`, `property`, `value` as described in [Event schema](index.md#event-schema), `context` for custom contexts, and `extra` (key-value pairs object). |
### Usage recommendations
@@ -81,7 +81,7 @@ The following example shows `data-track-*` attributes assigned to a button:
| Attribute | Required | Description |
|:----------------------|:---------|:------------|
| `data-track-action` | true | Action the user is taking. Clicks must be prepended with `click` and activations must be prepended with `activate`. For example, focusing a form field is `activate_form_input` and clicking a button is `click_button`. Replaces `data-track-event`, which was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/290962) in GitLab 13.11. |
-| `data-track-label` | false | The specific element or object to act on. This can be: the label of the element, for example, a tab labeled 'Create from template' for `create_from_template`; a unique identifier if no text is available, for example, `groups_dropdown_close` for closing the Groups dropdown in the top bar; or the name or title attribute of a record being created. |
+| `data-track-label` | false | The specific element or object to act on. This can be: the label of the element, for example, a tab labeled 'Create from template' for `create_from_template`; a unique identifier if no text is available, for example, `groups_dropdown_close` for closing the Groups dropdown list in the top bar; or the name or title attribute of a record being created. |
| `data-track-property` | false | Any additional property of the element, or object being acted on. |
| `data-track-value` | false | Describes a numeric value (decimal) directly related to the event. This could be the value of an input. For example, `10` when clicking `internal` visibility. If omitted, this is the element's `value` property or `undefined`. For checkboxes, the default value is the element's checked attribute or `0` when unchecked. The value is parsed as numeric before sending the event. |
| `data-track-extra` | false | A key-value pair object passed as a valid JSON string. This attribute is added to the `extra` property in our [`gitlab_standard`](schemas.md#gitlab_standard) schema. |
@@ -349,7 +349,7 @@ describe('MyTracking', () => {
### Form tracking
-To enable Snowplow automatic [form tracking](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v2/tracking-specific-events/#form-tracking):
+To enable Snowplow automatic [form tracking](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v2/tracking-specific-events/#form-tracking):
1. Call `Tracking.enableFormTracking` when the DOM is ready.
1. Provide a `config` object that includes at least one of the following elements:
@@ -389,7 +389,7 @@ describe('MyFormTracking', () => {
## Implement Ruby backend tracking
-`Gitlab::Tracking` is an interface that wraps the [Snowplow Ruby Tracker](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/ruby-tracker/) for tracking custom events.
+`Gitlab::Tracking` is an interface that wraps the [Snowplow Ruby Tracker](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/ruby-tracker/) for tracking custom events.
Backend tracking provides:
- User behavior tracking
@@ -415,7 +415,7 @@ Use the following arguments:
|------------|---------------------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------|
| `category` | String | | Area or aspect of the application. For example, `HealthCheckController` or `Lfs::FileTransformer`. |
| `action` | String | | The action being taken. For example, a controller action such as `create`, or an Active Record callback. |
-| `label` | String | `nil` | The specific element or object to act on. This can be one of the following: the label of the element, for example, a tab labeled 'Create from template' for `create_from_template`; a unique identifier if no text is available, for example, `groups_dropdown_close` for closing the Groups dropdown in the top bar; or the name or title attribute of a record being created. |
+| `label` | String | `nil` | The specific element or object to act on. This can be one of the following: the label of the element, for example, a tab labeled 'Create from template' for `create_from_template`; a unique identifier if no text is available, for example, `groups_dropdown_close` for closing the Groups dropdown list in the top bar; or the name or title attribute of a record being created. |
| `property` | String | `nil` | Any additional property of the element, or object being acted on. |
| `value` | Numeric | `nil` | Describes a numeric value (decimal) directly related to the event. This could be the value of an input. For example, `10` when clicking `internal` visibility. |
| `context` | Array\[SelfDescribingJSON\] | `nil` | An array of custom contexts to send with this event. Most events should not have any custom contexts. |
@@ -451,7 +451,7 @@ Before you test frontend events in development, you must:
1. Turn off ad blockers that could prevent Snowplow JavaScript from loading in your environment.
1. Turn off "Do Not Track" (DNT) in your browser.
-All URLs are pseudonymized. The entity identifier [replaces](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v2/tracker-setup/other-parameters-2/#Setting_a_custom_page_URL_and_referrer_URL) personally identifiable
+All URLs are pseudonymized. The entity identifier [replaces](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v2/tracker-setup/other-parameters-2/#setting-a-custom-page-url-and-referrer-url) personally identifiable
information (PII). PII includes usernames, group, and project names.
Page titles are hardcoded as `GitLab` for the same reason.
@@ -477,7 +477,7 @@ For a video tutorial, see the [Snowplow plugin walk through](https://www.youtube
#### Snowplow Micro
-[Snowplow Micro](https://snowplowanalytics.com/blog/2019/07/17/introducing-snowplow-micro/) is a
+[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
records the same events as the full Snowplow pipeline. To query events, use the Snowplow Micro API.
diff --git a/doc/development/snowplow/index.md b/doc/development/snowplow/index.md
index 7327f18fcaf..8d05e05e592 100644
--- a/doc/development/snowplow/index.md
+++ b/doc/development/snowplow/index.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Snowplow is an enterprise-grade marketing and Product Intelligence platform that tracks how users engage with our website and application.
-[Snowplow](https://snowplowanalytics.com) consists of several loosely-coupled sub-systems:
+[Snowplow](https://snowplow.io/) consists of several loosely-coupled sub-systems:
- **Trackers** fire Snowplow events. Snowplow has twelve trackers that cover web, mobile, desktop, server, and IoT.
- **Collectors** receive Snowplow events from trackers. We use different event collectors that synchronize events to Amazon S3, Apache Kafka, or Amazon Kinesis.
@@ -80,20 +80,21 @@ sequenceDiagram
For more details about the architecture, see [Snowplow infrastructure](infrastructure.md).
-## Structured event taxonomy
+## Event schema
-Click events must be consistent. If each feature captures events differently, it can be difficult
+All the events must be consistent. If each feature captures events differently, it can be difficult
to perform analysis.
-Each click event provides attributes that describe the event.
+Each event provides attributes that describe the event.
| Attribute | Type | Required | Description |
| --------- | ------- | -------- | ----------- |
| category | text | true | The page or backend section of the application. Unless infeasible, use the Rails page attribute by default in the frontend, and namespace + class name on the backend, for example, `Notes::CreateService`. |
| action | text | true | The action the user takes, or aspect that's being instrumented. The first word must describe the action or aspect. For example, clicks must be `click`, activations must be `activate`, creations must be `create`. Use underscores to describe what was acted on. For example, activating a form field is `activate_form_input`, an interface action like clicking on a dropdown list is `click_dropdown`, a behavior like creating a project record from the backend is `create_project`. |
-| label | text | false | The specific element or object to act on. This can be one of the following: the label of the element, for example, a tab labeled 'Create from template' for `create_from_template`; a unique identifier if no text is available, for example, `groups_dropdown_close` for closing the Groups dropdown in the top bar; or the name or title attribute of a record being created. For Service Ping metrics adapted to Snowplow events, this should be the full metric [key path](../service_ping/metrics_dictionary.md#metric-key_path) taken from its definition file. |
+| label | text | false | The specific element or object to act on. This can be one of the following: the label of the element, for example, a tab labeled 'Create from template' for `create_from_template`; a unique identifier if no text is available, for example, `groups_dropdown_close` for closing the Groups dropdown list in the top bar; or the name or title attribute of a record being created. For Service Ping metrics adapted to Snowplow events, this should be the full metric [key path](../service_ping/metrics_dictionary.md#metric-key_path) taken from its definition file. |
| property | text | false | Any additional property of the element, or object being acted on. For Service Ping metrics adapted to Snowplow events, this should be additional information or context that can help analyze the event. For example, in the case of `usage_activity_by_stage_monthly.create.merge_requests_users`, there are four different possible merge request actions: "create", "merge", "comment", and "close". Each of these would be a possible property value. |
| value | decimal | false | Describes a numeric value (decimal) directly related to the event. This could be the value of an input. For example, `10` when clicking `internal` visibility. |
+| context | vector | false | Additional data in the form of a [self-describing JSON](https://docs.snowplow.io/docs/pipeline-components-and-applications/iglu/common-architecture/self-describing-json-schemas/) to describe the event if the attributes are not sufficient. Each context must have its schema defined to assure data integrity. Refer to the list of GitLab-defined contexts for more details. |
### Examples
@@ -185,16 +186,16 @@ LIMIT 100
### Web-specific parameters
-Snowplow JavaScript adds [web-specific parameters](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/snowplow-tracker-protocol/#Web-specific_parameters) to all web events by default.
+Snowplow JavaScript adds [web-specific parameters](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/snowplow-tracker-protocol/#Web-specific_parameters) to all web events by default.
## Related topics
-- [Snowplow data structure](https://docs.snowplowanalytics.com/docs/understanding-your-pipeline/canonical-event/)
+- [Snowplow data structure](https://docs.snowplow.io/docs/understanding-your-pipeline/canonical-event/)
- [Our Iglu schema registry](https://gitlab.com/gitlab-org/iglu)
- [List of events used in our codebase (Event Dictionary)](https://metrics.gitlab.com/snowplow/)
- [Product Intelligence Guide](https://about.gitlab.com/handbook/product/product-intelligence-guide/)
- [Service Ping Guide](../service_ping/index.md)
-- [Product Intelligence Direction](https://about.gitlab.com/direction/product-intelligence/)
+- [Product Intelligence Direction](https://about.gitlab.com/direction/analytics/product-intelligence/)
- [Data Analysis Process](https://about.gitlab.com/handbook/business-technology/data-team/#data-analysis-process/)
- [Data for Product Managers](https://about.gitlab.com/handbook/business-technology/data-team/programs/data-for-product-managers/)
- [Data Infrastructure](https://about.gitlab.com/handbook/business-technology/data-team/platform/infrastructure/)
diff --git a/doc/development/snowplow/review_guidelines.md b/doc/development/snowplow/review_guidelines.md
index 756dbd0ca92..ee2c1eb95df 100644
--- a/doc/development/snowplow/review_guidelines.md
+++ b/doc/development/snowplow/review_guidelines.md
@@ -35,7 +35,7 @@ events or touches Snowplow related files.
#### The Product Intelligence **reviewer** should
-- Check that the [event taxonomy](index.md#structured-event-taxonomy) is correct.
+- Check that the [event schema](index.md#event-schema) is correct.
- Check the [usage recommendations](implementation.md#usage-recommendations).
- Check that the [Event Dictionary](event_dictionary_guide.md) is up-to-date.
- If needed, check that the events are firing locally using one of the
diff --git a/doc/development/snowplow/schemas.md b/doc/development/snowplow/schemas.md
index 482c0e0105b..5a6cdea9fee 100644
--- a/doc/development/snowplow/schemas.md
+++ b/doc/development/snowplow/schemas.md
@@ -33,8 +33,8 @@ _\* Default value present for frontend events only_
## Default Schema
-Frontend events include a [web-specific schema](https://docs.snowplowanalytics.com/docs/understanding-your-pipeline/canonical-event/#Web-specific_fields) provided by Snowplow.
-All URLs are pseudonymized. The entity identifier [replaces](https://docs.snowplowanalytics.com/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v2/tracker-setup/other-parameters-2/#Setting_a_custom_page_URL_and_referrer_URL) personally identifiable
+Frontend events include a [web-specific schema](https://docs.snowplow.io/docs/understanding-your-pipeline/canonical-event/#web-specific-fields) provided by Snowplow.
+All URLs are pseudonymized. The entity identifier [replaces](https://docs.snowplow.io/docs/collecting-data/collecting-from-own-applications/javascript-trackers/javascript-tracker/javascript-tracker-v2/tracker-setup/other-parameters-2/#setting-a-custom-page-url-and-referrer-url) personally identifiable
information (PII). PII includes usernames, group, and project names.
Page titles are hardcoded as `GitLab` for the same reason.
@@ -172,3 +172,18 @@ Page titles are hardcoded as `GitLab` for the same reason.
| `v_collector` | **{dotted-circle}** | string | Collector version |
| `v_etl` | **{dotted-circle}** | string | ETL version |
| `v_tracker` | **{dotted-circle}** | string | Identifier for Snowplow tracker |
+
+## `gitlab_service_ping`
+
+Backend events converted from ServicePing (`redis` and `redis_hll`) must include [ServicePing context](https://gitlab.com/gitlab-org/iglu/-/tree/master/public/schemas/com.gitlab/gitlab_service_ping/jsonschema)
+using the [helper class](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/tracking/service_ping_context.rb).
+
+An example of converted `redis_hll` [event with context](https://gitlab.com/gitlab-org/gitlab/-/edit/master/app/controllers/concerns/product_analytics_tracking.rb#L58).
+
+| Field Name | Required | Type | Description |
+|---------------|:-------------------:|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `data_source` | **{check-circle}** | string (max 64 chars) | The `data_source` attribute from the metrics YAML definition. |
+| `event_name`* | **{dotted-circle}** | string (max 128 chars) | When there is a many-to-many relationship between events and metrics, this field contains the name of a Redis event that can be used for aggregations in downstream systems |
+| `key_path`* | **{dotted-circle}** | string (max 256 chars) | The `key_path` attribute from the metrics YAML definition |
+
+_\* Either `event_name` or `key_path` is required_
diff --git a/doc/development/spam_protection_and_captcha/exploratory_testing.md b/doc/development/spam_protection_and_captcha/exploratory_testing.md
index e17d25acb9d..f6e3e6814a8 100644
--- a/doc/development/spam_protection_and_captcha/exploratory_testing.md
+++ b/doc/development/spam_protection_and_captcha/exploratory_testing.md
@@ -91,7 +91,7 @@ CAPTCHA response string does not matter. It can be any string. If you use a
real, valid key pair, you must solve the CAPTCHA to obtain a
valid CAPTCHA response to use. You can do this once only, and only before it expires.
-To directly test the GraphQL API via [GraphQL Explorer](http://gdk.test:3000/-/graphql-explorer),
+To directly test the GraphQL API via GraphQL Explorer (`http://gdk.test:3000/-/graphql-explorer`),
get a reCAPTCHA response string via this form: `public/recaptcha.html` (`http://gdk.test:3000/recaptcha.html`):
```html
diff --git a/doc/development/sql.md b/doc/development/sql.md
index 5829d27b8ee..cdc952eb08b 100644
--- a/doc/development/sql.md
+++ b/doc/development/sql.md
@@ -103,7 +103,7 @@ transaction. Transactions for migrations can be disabled using the following
pattern:
```ruby
-class MigrationName < Gitlab::Database::Migration[1.0]
+class MigrationName < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
end
```
@@ -111,7 +111,7 @@ end
For example:
```ruby
-class AddUsersLowerUsernameEmailIndexes < Gitlab::Database::Migration[1.0]
+class AddUsersLowerUsernameEmailIndexes < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
def up
diff --git a/doc/development/stage_group_observability/dashboards/index.md b/doc/development/stage_group_observability/dashboards/index.md
index 9f9ba609271..c2da46bde7d 100644
--- a/doc/development/stage_group_observability/dashboards/index.md
+++ b/doc/development/stage_group_observability/dashboards/index.md
@@ -43,7 +43,7 @@ All metrics recorded in the GitLab production system have
[one-year retention](https://gitlab.com/gitlab-cookbooks/gitlab-prometheus/-/blob/31526b03fef823e2f9b3cda7c75dcd28a12418a3/attributes/prometheus.rb#L40).
You can also zoom in and filter the time range directly on a graph. For more information, see the
-[Grafana Time Range Controls](https://grafana.com/docs/grafana/latest/dashboards/time-range-controls/)
+[Grafana Time Range Controls](https://grafana.com/docs/grafana/latest/dashboards/use-dashboards/#set-dashboard-time-range)
documentation.
## Filters and annotations
@@ -51,7 +51,7 @@ documentation.
On each dashboard, there are two filters and some annotation switches on the top of the page.
Some special events are meaningful to development and operational activities.
-[Grafana annotations](https://grafana.com/docs/grafana/latest/dashboards/annotations/) mark them
+[Grafana annotations](https://grafana.com/docs/grafana/latest/dashboards/build-dashboards/annotate-visualizations/) mark them
directly on the graphs.
![Filters and annotations](img/stage_group_dashboards_filters.png)
diff --git a/doc/development/stage_group_observability/dashboards/stage_group_dashboard.md b/doc/development/stage_group_observability/dashboards/stage_group_dashboard.md
index fb5d5bbe379..abc46c52407 100644
--- a/doc/development/stage_group_observability/dashboards/stage_group_dashboard.md
+++ b/doc/development/stage_group_observability/dashboards/stage_group_dashboard.md
@@ -56,7 +56,7 @@ description, note the following:
To inspect the raw data of the panel for further calculation, select **Inspect** from the dropdown list of a panel.
Queries, raw data, and panel JSON structure are available.
-Read more at [Grafana panel inspection](http://grafana.com/docs/grafana/next/panels/query-a-data-source/).
+Read more at [Grafana panel inspection](https://grafana.com/docs/grafana/latest/panels-visualizations/query-transform-data/).
All the dashboards are powered by [Grafana](https://grafana.com/), a frontend for displaying metrics.
Grafana consumes the data returned from queries to backend Prometheus data source, then presents it
diff --git a/doc/development/testing_guide/best_practices.md b/doc/development/testing_guide/best_practices.md
index f1a23f06699..b6bf3c7805a 100644
--- a/doc/development/testing_guide/best_practices.md
+++ b/doc/development/testing_guide/best_practices.md
@@ -110,7 +110,7 @@ If the specs fail the check they must be fixed before than can run in random ord
### Test speed
-GitLab has a massive test suite that, without [parallelization](../pipelines.md#test-suite-parallelization), can take hours
+GitLab has a massive test suite that, without [parallelization](../pipelines/index.md#test-suite-parallelization), can take hours
to run. It's important that we make an effort to write tests that are accurate
and effective _as well as_ fast.
@@ -282,7 +282,7 @@ end
#### Stubbing methods within factories
-You should avoid using `allow(object).to receive(:method)` in factories, as this makes the factory unable to be used with `let_it_be`.
+You should avoid using `allow(object).to receive(:method)` in factories, as this makes the factory unable to be used with `let_it_be`, as described in [common test setup](#common-test-setup).
Instead, you can use `stub_method` to stub the method:
@@ -425,6 +425,11 @@ results are available, and not just the first failure.
when you need an ID/IID/access level that doesn't actually exists. Using 123, 1234,
or even 999 is brittle as these IDs could actually exist in the database in the
context of a CI run.
+- All top-level `RSpec.describe` blocks should have [`feature_category`](https://about.gitlab.com/categories.json) metadata set.
+ Consider splitting the file in the case there are identified multiple feature categories in same file.
+ If no `feature_category` is identified then use `not_owned`. This information is used in flaky test
+ issues created in order to identify the group owning the feature.
+ Eg: `RSpec.describe Admin::Geo::SettingsController, :geo, feature_category: :geo_replication do`.
### Coverage
@@ -921,7 +926,8 @@ them unspecified, and look up the value after the row is created.
#### Redis
GitLab stores two main categories of data in Redis: cached items, and Sidekiq
-jobs.
+jobs. [View the full list of `Gitlab::Redis::Wrapper` descendants](https://gitlab.com/gitlab-org/gitlab/-/tree/master/lib/gitlab/redis.rb) that are backed by
+a separate Redis instance.
In most specs, the Rails cache is actually an in-memory store. This is replaced
between specs, so calls to `Rails.cache.read` and `Rails.cache.write` are safe.
@@ -961,6 +967,14 @@ it "really connects to Prometheus", :permit_dns do
And if you need more specific control, the DNS blocking is implemented in
`spec/support/helpers/dns_helpers.rb` and these methods can be called elsewhere.
+#### Rate Limiting
+
+[Rate limiting](../../security/rate_limits.md) is enabled in the test suite. Rate limits
+may be triggered in feature specs that use the `:js` trait. In most cases, triggering rate
+limiting can be avoided by marking the spec with the `:clean_gitlab_redis_rate_limiting`
+trait. This trait clears the rate limiting data stored in Redis cache between specs. If
+a single test triggers the rate limit, the `:disable_rate_limit` can be used instead.
+
#### Stubbing File methods
In the situations where you need to
@@ -1437,9 +1451,10 @@ GitLab uses [factory_bot](https://github.com/thoughtbot/factory_bot) as a test f
resulting record to pass validation.
- When instantiating from a factory, don't supply attributes that aren't
required by the test.
-- Prefer [implicit](https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#implicit-definition)
- or [explicit](https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#explicit-definition)
- association definitions instead of using `create` / `build` for association setup.
+- Prefer [implicit](https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#implicit-definition),
+ [explicit](https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#explicit-definition), or
+ [inline](https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#inline-definition) associations
+ over `create` / `build` for association setup in callbacks.
See [issue #262624](https://gitlab.com/gitlab-org/gitlab/-/issues/262624) for further context.
- Factories don't have to be limited to `ActiveRecord` objects.
[See example](https://gitlab.com/gitlab-org/gitlab-foss/commit/0b8cefd3b2385a21cfed779bd659978c0402766d).
diff --git a/doc/development/testing_guide/contract/consumer_tests.md b/doc/development/testing_guide/contract/consumer_tests.md
index 67bb7160749..9c72e6835bd 100644
--- a/doc/development/testing_guide/contract/consumer_tests.md
+++ b/doc/development/testing_guide/contract/consumer_tests.md
@@ -213,7 +213,7 @@ pactWith(
const discussions = await getDiscussions({
url: provider.mockService.baseUrl,
});
-
+
expect(discussions).toEqual(Matchers.eachLike({
id: 'fd73763cbcbf7b29eb8765d969a38f7d735e222a',
project_id: 6954442,
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 37eda7f76f5..777a9f47339 100644
--- a/doc/development/testing_guide/end_to_end/best_practices.md
+++ b/doc/development/testing_guide/end_to_end/best_practices.md
@@ -17,8 +17,8 @@ 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).
-If a test case issue does not yet exist you can create one yourself. To do so, create a new
-issue in the [Test Cases](https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases) GitLab project
+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
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/feature_flags.md b/doc/development/testing_guide/end_to_end/feature_flags.md
index 8e25c817938..6d826e170f6 100644
--- a/doc/development/testing_guide/end_to_end/feature_flags.md
+++ b/doc/development/testing_guide/end_to_end/feature_flags.md
@@ -160,7 +160,7 @@ For example:
```ruby
def initialize
- name_of_the_future_flag_activated = false
+ name_of_the_feature_flag_activated = false
...
end
```
diff --git a/doc/development/testing_guide/end_to_end/index.md b/doc/development/testing_guide/end_to_end/index.md
index 1853ad47779..8ffe044c4d8 100644
--- a/doc/development/testing_guide/end_to_end/index.md
+++ b/doc/development/testing_guide/end_to_end/index.md
@@ -123,9 +123,8 @@ test or a group of tests that are different than the groups in any of the existi
For example, when we [dequarantine](https://about.gitlab.com/handbook/engineering/quality/quality-engineering/debugging-qa-test-failures/#dequarantining-tests)
a flaky test we first want to make sure that it's no longer flaky.
-We can do that using the `ce:custom-parallel` and `ee:custom-parallel` jobs.
-Both are manual jobs that you can configure using custom variables.
-When selecting the name (not the play icon) of one of the parallel jobs,
+We can do that by running `_ee:quarantine` manual job.
+When selecting the name (not the play icon) of manual job,
you are prompted to enter variables. You can use any of
[the variables that can be used with `gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/what_tests_can_be_run.md#supported-gitlab-environment-variables)
as well as these:
@@ -134,7 +133,7 @@ as well as these:
|-|-|
| `QA_SCENARIO` | The scenario to run (default `Test::Instance::Image`) |
| `QA_TESTS` | The tests to run (no default, which means run all the tests in the scenario). Use file paths as you would when running tests via RSpec, for example, `qa/specs/features/ee/browser_ui` would include all the `EE` UI tests. |
-| `QA_RSPEC_TAGS` | The RSpec tags to add (no default) |
+| `QA_RSPEC_TAGS` | The RSpec tags to add (default `--tag quarantine`) |
For now,
[manual jobs with custom variables don't use the same variable when retried](https://gitlab.com/gitlab-org/gitlab/-/issues/31367),
@@ -157,6 +156,19 @@ against the [Review App](../review_apps.md).
See [Review Apps](../review_apps.md) for more details about Review Apps.
+#### Selective test execution
+
+In order to limit amount of tests executed in a merge request, dynamic selection of which tests to execute is present. Algorithm of which tests to run is based
+on changed files and merge request labels. Following criteria determine which tests will run:
+
+1. Changes in `qa` framework code would execute the full suite
+1. Changes in particular `_spec.rb` file in `qa` folder would execute only that particular test
+1. Merge request with backend changes and label `devops::manage` would execute all e2e tests related to `manage` stage
+
+#### Overriding selective test execution
+
+To override selective test execution and trigger the full suite, label `pipeline:run-all-e2e` should be added to particular merge request.
+
### Run tests in parallel
To run tests in parallel on CI, the [Knapsack](https://github.com/KnapsackPro/knapsack)
@@ -184,7 +196,8 @@ Use these environment variables to configure metrics export:
| `QA_INFLUXDB_URL` | `true` | Should be set to `https://influxdb.quality.gitlab.net`. No default value. |
| `QA_INFLUXDB_TOKEN` | `true` | InfluxDB write token that can be found under `Influxdb auth tokens` document in `Gitlab-QA` `1Password` vault. No default value. |
| `QA_RUN_TYPE` | `false` | Arbitrary name for test execution, like `package-and-test`. Automatically inferred from the project name for live environment test executions. No default value. |
-| `QA_EXPORT_TEST_METRICS` | `false` | Flag to enable or disable metrics export. Defaults to `true`. |
+| `QA_EXPORT_TEST_METRICS` | `false` | Flag to enable or disable metrics export to InfluxDB. Defaults to `false`. |
+| `QA_SAVE_TEST_METRICS` | `false` | Flag to enable or disable saving metrics as JSON file. Defaults to `false`. |
## Test reports
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 b12c6bd443a..a7d1ece77b2 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
@@ -36,7 +36,7 @@ This is a partial list of the [RSpec metadata](https://relishapp.com/rspec/rspec
| `:only` | The test is only to be run in specific execution contexts. See [test execution context selection](execution_context_selection.md) for more information. |
| `:orchestrated` | The GitLab instance under test may be [configured by `gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa/-/blob/master/docs/what_tests_can_be_run.md#orchestrated-tests) to be different to the default GitLab configuration, or `gitlab-qa` may launch additional services in separate Docker containers, or both. Tests tagged with `:orchestrated` are excluded when testing environments where we can't dynamically modify the GitLab configuration (for example, Staging). |
| `:packages` | The test requires a GitLab instance that has the [Package Registry](../../../administration/packages/index.md#gitlab-package-registry-administration) enabled. |
-| `:product_group` | Specifies what product group the test belongs to. See [Product sections, stages, groups, and categories](https://about.gitlab.com/handbook/product/categories) for the comprehensive groups list. |
+| `:product_group` | Specifies what product group the test belongs to. See [Product sections, stages, groups, and categories](https://about.gitlab.com/handbook/product/categories/) for the comprehensive groups list. |
| `:quarantine` | The test has been [quarantined](https://about.gitlab.com/handbook/engineering/quality/quality-engineering/debugging-qa-test-failures/#quarantining-tests), runs in a separate job that only includes quarantined tests, and is allowed to fail. The test is skipped in its regular job so that if it fails it doesn't hold up the pipeline. Note that you can also [quarantine a test only when it runs in a specific context](execution_context_selection.md#quarantine-a-test-for-a-specific-environment). |
| `:relative_url` | The test requires a GitLab instance to be installed under a [relative URL](../../../install/relative_url.md). |
| `:reliable` | The test has been [promoted to a reliable test](https://about.gitlab.com/handbook/engineering/quality/quality-engineering/reliable-tests/#promoting-an-existing-test-to-reliable) meaning it passes consistently in all pipelines, including merge requests. |
diff --git a/doc/development/testing_guide/end_to_end/style_guide.md b/doc/development/testing_guide/end_to_end/style_guide.md
index f380b24d7a5..419942d6b8f 100644
--- a/doc/development/testing_guide/end_to_end/style_guide.md
+++ b/doc/development/testing_guide/end_to_end/style_guide.md
@@ -12,7 +12,7 @@ This document describes the conventions used at GitLab for writing End-to-end (E
### When to use `click_`?
-When clicking in a single link to navigate, use `click_`.
+When selecting a single link to navigate, use `click_`.
For example:
@@ -24,9 +24,9 @@ def click_ci_cd_pipelines
end
```
-From a testing perspective, if we want to check that clicking a link, or a button (a single interaction) is working as intended, we would want the test to read as:
+From a testing perspective, if we want to check that selecting a link, or a button (a single interaction) is working as intended, we would want the test to read as:
-- Click a certain element
+- Select a certain element
- Verify the action took place
### When to use `go_to_`?
@@ -47,7 +47,7 @@ end
`go_to_` fits the definition of interacting with multiple elements very well given it's more of a meta-navigation action that includes multiple interactions.
-Notice that in the above example, before clicking the `:operations_environments_link`, another element is hovered over.
+Notice that in the above example, before selecting the `:operations_environments_link`, another element is hovered over.
> We can create these methods as helpers to abstract multi-step navigation.
diff --git a/doc/development/testing_guide/flaky_tests.md b/doc/development/testing_guide/flaky_tests.md
index 45f1d0ddf7e..cc62a0ebf03 100644
--- a/doc/development/testing_guide/flaky_tests.md
+++ b/doc/development/testing_guide/flaky_tests.md
@@ -11,9 +11,144 @@ info: To determine the technical writer assigned to the Stage/Group associated w
It's a test that sometimes fails, but if you retry it enough times, it passes,
eventually.
+## What are the potential cause for a test to be flaky?
+
+### Unclean environment
+
+**Label:** `flaky-test::unclean environment`
+
+**Description:** The environment got dirtied by a previous test. The actual cause is probably not the flaky test here.
+
+**Difficulty to reproduce:** Moderate. Usually, running the same spec files until the one that's failing reproduces the problem.
+
+**Resolution:** Fix the previous tests and/or places where the environment is modified, so that
+it's reset to a pristine test after each test.
+
+**Examples:**
+
+- [Example 1](https://gitlab.com/gitlab-org/gitlab/-/issues/378414#note_1142026988): A migration
+ test might roll-back the database, perform its testing, and then roll-up the database in an
+ inconsistent state, so that following tests might not know about certain columns.
+- [Example 2](https://gitlab.com/gitlab-org/gitlab/-/issues/368500): A test modifies data that is
+ used by a following test.
+- [Example 3](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103434#note_1172316521): A test for a database query passes in a fresh database, but in a
+ CI/CD pipeline where the database is used to process previous test sequences, the test fails. This likely
+ means that the query itself needs to be updated to work in a non-clean database.
+
+### Ordering assertion
+
+**Label:** `flaky-test::ordering assertion`
+
+**Description:** The test is expecting a specific order in the data under test yet the data is in
+a non-deterministic order.
+
+**Difficulty to reproduce:** Easy. Usually, running the test locally several times would reproduce
+the problem.
+
+**Resolution:** Depending on the problem, you might want to:
+
+- loosen the assertion if the test shouldn't care about ordering but only on the elements
+- fix the test by specifying a deterministic ordering
+- fix the app code by specifying a deterministic ordering
+
+**Examples:**
+
+- [Example 1](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/10148/diffs): Without
+ specifying `ORDER BY`, database will not give deterministic ordering, or data race happening
+ in the tests.
+
+### Dataset-specific
+
+**Label:** `flaky-test::dataset-specific`
+
+**Description:** The test assumes the dataset is in a particular (usually limited) state, which
+might not be true depending on when the test run during the test suite.
+
+**Difficulty to reproduce:** Moderate, as the amount of data needed to reproduce the issue might be
+difficult to achieve locally.
+
+**Resolution:** Fix the test to not assume that the dataset is in a particular state, don't hardcode IDs.
+
+**Examples:**
+
+- [Example 1](https://gitlab.com/gitlab-org/gitlab/-/issues/378381): The database is recreated when
+ any table has more than 500 columns. It could pass in the merge request, but fail later in
+ `master` if the order of tests changes.
+- [Example 2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91016/diffs): A test asserts
+ that trying to find a record with an unexisting ID retuns an error message. The test uses an
+ hardcoded ID that's supposed to not exist (e.g. `42`). If the test is run early in the test
+ suite, it might pass as not enough records were created before it, but as soon as it would run
+ later in the suite, there could be a record that actually has the ID `42`, hence the test would
+ start to fail.
+
+### Random input
+
+**Label:** `flaky-test::random input`
+
+**Description:** The test use random values, that sometimes match the expectations, and sometimes not.
+
+**Difficulty to reproduce:** Easy, as the test can be modified locally to use the "random value"
+used at the time the test failed
+
+**Resolution:** Once the problem is reproduced, it should be easy to debug and fix either the test
+or the app.
+
+**Examples:**
+
+- [Example 1](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/20121): The test isn't robust enough to handle a specific data, that only appears sporadically since the data input is random.
+
+### Unreliable DOM Selector
+
+**Label:** `flaky-test::unreliable dom selector`
+
+**Description:** The DOM selector used in the test is unreliable.
+
+**Difficulty to reproduce:** Moderate to difficult. Depending on whether the DOM selector is duplicated, or appears after a delay etc.
+
+**Resolution:** It really depends on the problem here. It could be to wait for requests to finish, to scroll down the page etc.
+
+**Examples:**
+
+- [Example 1](https://gitlab.com/gitlab-org/gitlab/-/issues/338341): A non-unique CSS selector
+ matching more than one element, or a non-waiting selector method that does not allow rendering
+ time before throwing an `element not found` error.
+- [Example 2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101728/diffs): A CSS selector
+ only appears after a GraphQL requests has finished, and the UI has updated.
+
+### Datetime-sensitive
+
+**Label:** `flaky-test::datetime-sensitive`
+
+**Description:** The test is assuming a specific date or time.
+
+**Difficulty to reproduce:** Easy to moderate, depending on whether the test consistently fails after a certain date, or only fails at a given time or date.
+
+**Resolution:** Freezing the time is usually a good solution.
+
+**Examples:**
+
+- [Example 1](https://gitlab.com/gitlab-org/gitlab/-/issues/118612): A test that breaks after some time passed.
+
+### Unstable infrastructure
+
+**Label:** `flaky-test::unstable infrastructure`
+
+**Description:** The test fails from time to time due to infrastructure issues.
+
+**Difficulty to reproduce:** Hard. It's really hard to reproduce CI infrastructure issues. It might
+be possible by using containers locally.
+
+**Resolution:** Starting a conversation with the Infrastructure department in a dedicated issue is
+usually a good idea.
+
+**Examples:**
+
+- [Example 1](https://gitlab.com/gitlab-org/gitlab/-/issues/363214): The runner is under heavy load at this time.
+- [Example 2](https://gitlab.com/gitlab-org/gitlab/-/issues/360559): The runner is having networking issues, making a job failing early
+
## Quarantined tests
-When a test frequently fails in `main`,
+When a test frequently fails in `master`,
create [a ~"failure::flaky-test" issue](https://about.gitlab.com/handbook/engineering/workflow/#broken-master).
If the test cannot be fixed in a timely fashion, there is an impact on the
@@ -62,7 +197,7 @@ For example, `FLAKY_RSPEC_GENERATE_REPORT=1 bin/rspec ...`.
The `rspec/flaky/report-suite.json` report is:
-- Used for [automatically skipping known flaky tests](../pipelines.md#automatic-skipping-of-flaky-tests).
+- Used for [automatically skipping known flaky tests](../pipelines/index.md#automatic-skipping-of-flaky-tests).
- [Imported into Snowflake](https://gitlab.com/gitlab-data/analytics/-/blob/master/extract/gitlab_flaky_tests/upload.py)
once per day, for monitoring with the [internal dashboard](https://app.periscopedata.com/app/gitlab/888968/EP---Flaky-tests).
diff --git a/doc/development/testing_guide/frontend_testing.md b/doc/development/testing_guide/frontend_testing.md
index d7627e2064f..041b0f0a4f4 100644
--- a/doc/development/testing_guide/frontend_testing.md
+++ b/doc/development/testing_guide/frontend_testing.md
@@ -11,7 +11,7 @@ at GitLab. We use Jest for JavaScript unit and integration testing,
and RSpec feature tests with Capybara for e2e (end-to-end) integration testing.
Unit and feature tests need to be written for all new features.
-Most of the time, you should use [RSpec](https://github.com/rspec/rspec-rails#feature-specs) for your feature tests.
+Most of the time, you should use [RSpec](https://github.com/rspec/rspec-rails#feature-specs) for your feature tests. For more information on how to get started with feature tests, see [get started with feature tests](#get-started-with-feature-tests)
Regression tests should be written for bug fixes to prevent them from recurring
in the future.
@@ -458,7 +458,7 @@ If you cannot register handlers to the `Promise`, for example because it is exec
```javascript
it('waits for an Ajax call', async () => {
synchronousFunction();
-
+
await waitForPromises();
expect(something).toBe('done');
@@ -962,7 +962,7 @@ If an integration test depends on JavaScript to run correctly, you need to make
sure the spec is configured to enable JavaScript when the tests are run. If you
don't do this, the spec runner displays vague error messages.
-To enable a JavaScript driver in an `rspec` test, add `:js` to the
+To enable a JavaScript driver in an `RSpec` test, add `:js` to the
individual spec or the context block containing multiple specs that need
JavaScript enabled:
@@ -1242,6 +1242,332 @@ A good guideline to follow: the more complex the component you may want to steer
- To just have some kind of test written
- To capture highly volatile UI elements without stubbing them (Think of GitLab UI version updates)
+## Get started with feature tests
+
+### What is a feature test
+
+A [feature test](testing_levels.md#white-box-tests-at-the-system-level-formerly-known-as-system--feature-tests), also known as `white-box testing`, is a test that spawns a browser and has Capybara helpers. This means the test can:
+
+- Locate an element in the browser.
+- Click that element.
+- Call the API.
+
+Feature tests are expensive to run. You should make sure that you **really want** this type of test before running one.
+
+All of our feature tests are written in `Ruby` but often end up being written by `JavaScript` engineers, as they implement the user-facing feature. So, the following section assumes no prior knowledge of `Ruby` or `Capybara`, and provide a clear guideline on when and how to use these tests.
+
+### When to use feature tests
+
+You should use a feature test when the test:
+
+- Is across multiple components.
+- Requires that a user navigate across pages.
+- Is submitting a form and observing results elsewhere.
+- Would result in a huge number of mocking and stubbing with fake data and components if done as a unit test.
+
+Feature tests are especially useful when you want to test:
+
+- That multiple components are working together successfully.
+- Complex API interactions. Feature tests interact with the API, so they are slower but do not need any level of mocking or fixtures.
+
+### When not to use feature tests
+
+You should use `jest` and `vue-test-utils` unit tests instead of a feature test if you can get the same test results from these methods. Feature tests are quite expensive to run.
+
+You should use a unit test if:
+
+- The behavior you are implementing is all in one component.
+- You can simulate other components' behavior to trigger the desired effect.
+- You can already select UI elements in the virtual DOM to trigger the desired effects.
+
+Also, if a behavior in your new code needs multiple components to work together, you should consider testing your behavior higher in the component tree. For example, let's say that we have a component called `ParentComponent` with the code:
+
+```vue
+ <script>
+ export default{
+ name: ParentComponent,
+ data(){
+ return {
+ internalData: 'oldValue'
+ }
+ },
+ methods:{
+ changeSomeInternalData(newVal){
+ this.internalData = newVal
+ }
+ }
+ }
+ </script>
+ <template>
+ <div>
+ <child-component-1 @child-event="changeSomeInternalData" />
+ <child-component-2 :parent-data="internalData" />
+ </div>
+ </template>
+```
+
+In this example:
+
+- `ChildComponent1` emits an event.
+- `ParentComponent` changes its `internalData` value.
+- `ParentComponent` passes the props down to `ChildComponent2`.
+
+You can use a unit test instead by:
+
+- From inside the `ParentComponent` unit test file, emitting the expected event from `childComponent1`
+- Making sure the prop is passed down to `childComponent2`.
+
+Then each child component unit tests what happens when the event is emitted and when the prop changes.
+
+This example also applies at larger scale and with deeper component trees. It is definitely worth using unit tests and avoiding the extra cost of feature tests if you can:
+
+- Confidently mount child components.
+- Emit events or select elements in the virtual DOM.
+- Get the test behavior that you want.
+
+### Where to create your test
+
+Feature tests live in `spec/features` folder. You should look for existing files that can test the page you are adding a feature to. Within that folder, you can locate your section. For example, if you wanted to add a new feature test for the pipeline page, you would look in `spec/features/projects/pipelines` and see if the test you want to write exists here.
+
+### How to run a feature test
+
+1. Make sure that you have a working GDK environment.
+1. Start your `gdk` environment with `gdk start` command.
+1. In your terminal, run:
+
+ ```shell
+ bundle exec rspec path/to/file:line_of_my_test
+ ```
+
+You can also prefix this command with `WEBDRIVER_HEADLESS=0` which will run the test by opening an actual browser on your computer that you can see, which is very useful for debugging.
+
+### How to write a test
+
+#### Basic file structure
+
+1. Make all string literals unchangeable
+
+ In all feature tests, the very first line should be:
+
+ ```ruby
+ # frozen_string_literal: true
+ ```
+
+ This is in every `Ruby` file and makes all string literals unchangeable. There are also some performance benefits, but this is beyond the scope of this section.
+
+1. Import dependencies.
+
+ You should import the modules you need. You will most likely always need to require `spec_helper`:
+
+ ```ruby
+ require 'spec_helper'
+ ```
+
+ Import any other relevant module.
+
+1. Create a global scope for RSpec to define our tests, just like what we do in jest with the initial describe block.
+
+Then, you need to create the very first `RSpec` scope.
+
+```ruby
+RSpec.describe 'Pipeline', :js do
+ ...
+end
+```
+
+What is different though, is that just like everything in Ruby, this is actually a `class`. Which means that right at the top, you can `include` modules that you'd need for your test. For example, you could include the `RoutesHelpers` to navigate more easily.
+
+```ruby
+RSpec.describe 'Pipeline', :js do
+ include RoutesHelpers
+ ...
+end
+```
+
+After all of this implementation, we have a file that looks something like this:
+
+```ruby
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Pipeline', :js do
+ include RoutesHelpers
+end
+```
+
+#### Seeding data
+
+Each test is in its own environment and so you must use a factory to seed the required data. To continue on with the pipeline example, let's say that you want a test that takes you to the main pipeline page, which is at the route `/namespace/project/-/pipelines/:id/`.
+
+Most feature tests at least require you to create a user, because you want to be signed in. You can skip this step if you don't have to be signed in, but as a general rule, you should **always create a user unless you are specifically testing a feature looked at by an anonymous user**. This makes sure that you explicitly set a level of permission that you can edit in the test as needed to change or test a new level of permission as the section changes. To create a user:
+
+```ruby
+ let(:user) { create(:user) }
+```
+
+This creates a variable that holds the newly created user and we can use `create` because we imported the `spec_helper`.
+
+However, we have not done anything with this user yet because it's just a variable. So, in the `before do` block of the spec, we could sign in with the user so that every spec starts with a signed in user.
+
+```ruby
+ let(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ end
+```
+
+Now that we have a user, we should look at what else we'd need before asserting anything on a pipeline page. If you look at the route `/namespace/project/-/pipelines/:id/` we can determine we need a project and a pipeline.
+
+So we'd create a project and pipeline, and link them together. Usually in factories, the child element requires its parent as an argument. In this case, a pipeline is a child of a project. So we can create the project first, and then when we create the pipeline, we are pass the project as an argument which "binds" the pipeline to the project. A pipeline is also owned by a user, so we need the user as well. For example, this creates a project and a pipeline:
+
+```ruby
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :repository) }
+ let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id, user: user) }
+```
+
+In the same spirit, you could then create a job (build) by using the build factory and passing the parent pipeline:
+
+```ruby
+ create(:ci_build, pipeline: pipeline, stage_idx: 10, stage: 'publish', name: 'CentOS')
+```
+
+There are many factories that already exists, so make sure to look at other existing files to see if what you need is available.
+
+#### Navigation
+
+You can navigate to a page by using the `visit` method and passing the path as an argument. Rails automatically generates helper paths, so make sure to use these instead of a hardcoded string. They are generated using the route model, so if we want to go to a pipeline, we'd use:
+
+```ruby
+ visit project_pipeline_path(project, pipeline)
+```
+
+Before executing any page interaction when navigating or making asynchronous call through the UI, make sure to use `wait_for_requests` before proceeding with further instructions.
+
+#### Elements interaction
+
+There are a lot of different ways to find and interact with elements. For example, you could use the basic `find` method with the `selector` and `text` parameter and then use the `.click` method
+
+```ruby
+ find('.gl-tab-nav-item', text: 'Tests').click
+```
+
+Alternatively, you could use `click_button` with a string of text that is found within the button, which is a more semantically meaningful way of clicking the element.
+
+```ruby
+ click_button 'Text inside the button element'
+```
+
+If you want to follow a link, then there is `click_link`:
+
+```ruby
+ click_link 'Text inside the link tag'
+```
+
+You can use `fill_in` to fill input / form elements. The first argument is the selector, the second is `with:` which is the value to pass in.
+
+```ruby
+ fill_in 'current_password', with: '123devops'
+```
+
+Alternatively, you can use the `find` selector paired with `send_keys` to add keys in a field without removing previous text, or `set` which completely replaces the value of the input element.
+
+All of these are valid selectors and methods. Pick whichever suits your needs and look around as there are many more useful ones!
+
+#### Assertions
+
+To assert anything in a page, you can always access `page` variable, which is automatically defines and actually means the page document. This means you can expect the `page` to have certain components like selectors or content. Here are a few examples:
+
+```ruby
+ # Finding an element by ID
+ expect(page).to have_selector('#js-pipeline-graph')
+```
+
+```ruby
+ # Finding by text
+ expect(page).to have_content('build')
+```
+
+```ruby
+ # Finding by `href` value
+ expect(page).to have_link(pipeline.ref)
+```
+
+```ruby
+ # Finding by CSS selector. This is a last resort.
+ # For example, when you cannot add attributes on the desired element.
+ expect(page).to have_css('.js-icon-retry')
+```
+
+```ruby
+ # Find by data-testid
+ # Like CSS selector, this is acceptable when there isn't a specific matcher available.
+ expect(page).to have_selector('[data-testid="pipeline-multi-actions-dropdown"]')
+```
+
+```ruby
+ # You can combine any of these selectors with `not_to` instead
+ expect(page).not_to have_selector('#js-pipeline-graph')
+```
+
+```ruby
+ # When a test case has back to back expectations,
+ # it is recommended to group them using `:aggregate_failures`
+ it 'shows the issue description and design references', :aggregate_failures do
+ expect(page).to have_text('The designs I mentioned')
+ expect(page).to have_link(design_tab_ref)
+ expect(page).to have_link(design_ref_a)
+ expect(page).to have_link(design_ref_b)
+ end
+```
+
+You can also create a sub-block to look into, to:
+
+- Scope down where you are making your assertions and reduce the risk of finding another element that was not intended.
+- Make sure an element is found within the right boundaries.
+
+```ruby
+ page.within('#js-pipeline-graph') do
+ ...
+ end
+```
+
+#### Feature flags
+
+By default, every feature flag is enabled **regardless of the YAML definition or the flags you've set manually in your GDK**. To test when a feature flag is disabled, you must manually stub the flag, ideally in a `before do` block.
+
+```ruby
+ stub_feature_flags(my_feature_flag: false)
+```
+
+If you are stubbing an `ee` feature flag, then use:
+
+```ruby
+ stub_licensed_features(my_feature_flag: false)
+```
+
+### Debugging
+
+You can run your spec with the prefix `WEBDRIVER_HEADLESS=0` to open an actual browser. However, the specs goes though the commands quickly and leaves you no time to look around.
+
+To avoid this problem, you can write `binding.pry` on the line where you want Capybara to stop execution. You are then inside the browser with normal usage. To understand why you cannot find certain elements, you can:
+
+- Select elements.
+- Use the console and network tab.
+- Execute selectors inside the browser console.
+
+Inside the terminal, where capybara is running, you can also execute `next` which goes line by line through the test. This way you can check every single interaction one by one to see what might be causing an issue.
+
+### Updating ChromeDriver
+
+On MacOS, if you get a ChromeDriver error, make sure to update it by running
+
+```shell
+ brew upgrade chromedriver
+```
+
---
[Return to Testing documentation](index.md)
diff --git a/doc/development/testing_guide/index.md b/doc/development/testing_guide/index.md
index 753089fa673..5008564de01 100644
--- a/doc/development/testing_guide/index.md
+++ b/doc/development/testing_guide/index.md
@@ -43,12 +43,17 @@ system tests, parameterized tests etc.
Everything you should know about how to write good Frontend tests: Jest,
testing promises, stubbing etc.
+## [Getting started with Feature tests](frontend_testing.md#get-started-with-feature-tests)
+
+Need to get started with feature tests? Here are some general guidelines,
+tips and tricks to get the most out of white-box testing.
+
## [Flaky tests](flaky_tests.md)
What are flaky tests, the different kind of flaky tests we encountered, and what
we do about them.
-## [GitLab pipelines](../pipelines.md)
+## [GitLab pipelines](../pipelines/index.md)
How GitLab test suite is run in the CI context: setup, caches, artifacts,
parallelization, monitoring.
diff --git a/doc/development/testing_guide/review_apps.md b/doc/development/testing_guide/review_apps.md
index d86d1c3c7b4..5edf18725c0 100644
--- a/doc/development/testing_guide/review_apps.md
+++ b/doc/development/testing_guide/review_apps.md
@@ -4,9 +4,9 @@ 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
---
-# Review Apps
+# Using review apps in the development of GitLab
-Review Apps are deployed using the `start-review-app-pipeline` job which triggers a child pipeline containing a series of jobs to perform the various tasks needed to deploy a Review App.
+Review apps are deployed using the `start-review-app-pipeline` job which triggers a child pipeline containing a series of jobs to perform the various tasks needed to deploy a review app.
![start-review-app-pipeline job](img/review-app-parent-pipeline.png)
@@ -21,7 +21,7 @@ For any of the following scenarios, the `start-review-app-pipeline` job would be
- for scheduled pipelines
- the MR has the `pipeline:run-review-app` label set
-## QA runs on Review Apps
+## QA runs on review apps
On every [pipeline](https://gitlab.com/gitlab-org/gitlab/pipelines/125315730) in the `qa` stage (which comes after the
`review` stage), the `review-qa-smoke` and `review-qa-reliable` jobs are automatically started. The `review-qa-smoke` runs
@@ -34,7 +34,7 @@ You can also manually start the `review-qa-all`: it runs the full QA suite.
After the end-to-end test runs have finished, [Allure reports](https://github.com/allure-framework/allure2) are generated and published by
the `allure-report-qa-smoke`, `allure-report-qa-reliable`, and `allure-report-qa-all` jobs. A comment with links to the reports are added to the merge request.
-Errors can be found in the `gitlab-review-apps` Sentry project and [filterable by Review App URL](https://sentry.gitlab.net/gitlab/gitlab-review-apps/?query=url%3A%22https%3A%2F%2Fgitlab-review-require-ve-u92nn2.gitlab-review.app%2F%22) or [commit SHA](https://sentry.gitlab.net/gitlab/gitlab-review-apps/releases/6095b501da7/all-events/).
+Errors can be found in the `gitlab-review-apps` Sentry project and [filterable by review app URL](https://sentry.gitlab.net/gitlab/gitlab-review-apps/?query=url%3A%22https%3A%2F%2Fgitlab-review-require-ve-u92nn2.gitlab-review.app%2F%22) or [commit SHA](https://sentry.gitlab.net/gitlab/gitlab-review-apps/releases/6095b501da7/all-events/).
### Bypass failed review app deployment to merge a broken `master` fix
@@ -47,7 +47,7 @@ On every [pipeline](https://gitlab.com/gitlab-org/gitlab/pipelines/125315730) in
browser performance testing using a
[Sitespeed.io Container](../../ci/testing/browser_performance_testing.md).
-## Sample Data for Review Apps
+## Sample Data for review apps
Upon deployment of a review app, project data is created from the [`sample-gitlab-project`](https://gitlab.com/gitlab-org/sample-data-templates/sample-gitlab-project) template project. This aims to provide projects with prepopulated resources to facilitate manual and exploratory testing.
@@ -55,16 +55,16 @@ The sample projects will be created in the `root` user namespace and can be acce
## How to
-### Redeploy Review App from a clean slate
+### Redeploy review app from a clean slate
-To reset Review App and redeploy from a clean slate, do the following:
+To reset review app and redeploy from a clean slate, do the following:
1. Run `review-stop` job.
1. Re-deploy by running or retrying `review-deploy` job.
-Doing this will remove all existing data from a previously deployed Review App.
+Doing this will remove all existing data from a previously deployed review app.
-### Get access to the GCP Review Apps cluster
+### Get access to the GCP review apps cluster
You need to [open an access request (internal link)](https://gitlab.com/gitlab-com/access-requests/-/issues/new)
for the `gcp-review-apps-dev` GCP group and role.
@@ -74,7 +74,7 @@ This grants you the following permissions for:
- [Retrieving pod logs](#dig-into-a-pods-logs). Granted by [Viewer (`roles/viewer`)](https://cloud.google.com/iam/docs/understanding-roles#kubernetes-engine-roles).
- [Running a Rails console](#run-a-rails-console). Granted by [Kubernetes Engine Developer (`roles/container.pods.exec`)](https://cloud.google.com/iam/docs/understanding-roles#kubernetes-engine-roles).
-### Log into my Review App
+### Log into my review app
For GitLab Team Members only. If you want to sign in to the review app, review
the GitLab handbook information for the [shared 1Password account](https://about.gitlab.com/handbook/security/#1password-for-teams).
@@ -82,23 +82,23 @@ the GitLab handbook information for the [shared 1Password account](https://about
- The default username is `root`.
- The password can be found in the 1Password login item named `GitLab EE Review App`.
-### Enable a feature flag for my Review App
+### Enable a feature flag for my review app
-1. Open your Review App and sign in as documented above.
+1. Open your review app and sign in as documented above.
1. Create a personal access token.
1. Enable the feature flag using the [Feature flag API](../../api/features.md).
-### Find my Review App slug
+### Find my review app slug
1. Open the `review-deploy` job.
1. Look for `** Deploying review-*`.
1. For instance for `** Deploying review-1234-abc-defg... **`,
- your Review App slug would be `review-1234-abc-defg` in this case.
+ your review app slug would be `review-1234-abc-defg` in this case.
### Run a Rails console
1. Make sure you [have access to the cluster](#get-access-to-the-gcp-review-apps-cluster) and the `container.pods.exec` permission first.
-1. [Filter Workloads by your Review App slug](https://console.cloud.google.com/kubernetes/workload?project=gitlab-review-apps). For example, `review-qa-raise-e-12chm0`.
+1. [Filter Workloads by your review app slug](https://console.cloud.google.com/kubernetes/workload?project=gitlab-review-apps). For example, `review-qa-raise-e-12chm0`.
1. Find and open the `toolbox` Deployment. For example, `review-qa-raise-e-12chm0-toolbox`.
1. Select the Pod in the "Managed pods" section. For example, `review-qa-raise-e-12chm0-toolbox-d5455cc8-2lsvz`.
1. Select the `KUBECTL` dropdown list, then `Exec` -> `toolbox`.
@@ -111,7 +111,7 @@ the GitLab handbook information for the [shared 1Password account](https://about
### Dig into a Pod's logs
1. Make sure you [have access to the cluster](#get-access-to-the-gcp-review-apps-cluster) and the `container.pods.getLogs` permission first.
-1. [Filter Workloads by your Review App slug](https://console.cloud.google.com/kubernetes/workload?project=gitlab-review-apps). For example, `review-qa-raise-e-12chm0`.
+1. [Filter Workloads by your review app slug](https://console.cloud.google.com/kubernetes/workload?project=gitlab-review-apps). For example, `review-qa-raise-e-12chm0`.
1. Find and open the `migrations` Deployment. For example, `review-qa-raise-e-12chm0-migrations.1`.
1. Select the Pod in the "Managed pods" section. For example, `review-qa-raise-e-12chm0-migrations.1-nqwtx`.
1. Select `Container logs`.
@@ -149,11 +149,11 @@ subgraph "2. gitlab `review-prepare` stage"
end
subgraph "3. gitlab `review` stage"
- C["review-deploy<br><br>Helm deploys the Review App using the Cloud<br/>Native images built by the CNG-mirror pipeline.<br><br>Cloud Native images are deployed to the `review-apps`<br>Kubernetes (GKE) cluster, in the GCP `gitlab-review-apps` project."]
+ C["review-deploy<br><br>Helm deploys the review app using the Cloud<br/>Native images built by the CNG-mirror pipeline.<br><br>Cloud Native images are deployed to the `review-apps`<br>Kubernetes (GKE) cluster, in the GCP `gitlab-review-apps` project."]
end
subgraph "4. gitlab `qa` stage"
- E[review-qa-smoke, review-qa-reliable<br><br>gitlab-qa runs the smoke and reliable suites against the Review App.]
+ E[review-qa-smoke, review-qa-reliable<br><br>gitlab-qa runs the smoke and reliable suites against the review app.]
end
subgraph "CNG-mirror pipeline"
@@ -172,7 +172,7 @@ subgraph "CNG-mirror pipeline"
job [triggers a pipeline](https://gitlab.com/gitlab-org/build/CNG-mirror/pipelines/44364657)
in the [`CNG-mirror`](https://gitlab.com/gitlab-org/build/CNG-mirror) project.
- The `review-build-cng` job automatically starts only if your MR includes
- [CI or frontend changes](../pipelines.md#changes-patterns). In other cases, the job is manual.
+ [CI or frontend changes](../pipelines/internals.md#changes-patterns). In other cases, the job is manual.
- The [`CNG-mirror`](https://gitlab.com/gitlab-org/build/CNG-mirror/pipelines/44364657) pipeline creates the Docker images of
each component (for example, `gitlab-rails-ee`, `gitlab-shell`, `gitaly` etc.)
based on the commit from the [GitLab pipeline](https://gitlab.com/gitlab-org/gitlab/pipelines/125315730) and stores
@@ -180,10 +180,10 @@ subgraph "CNG-mirror pipeline"
- We use the [`CNG-mirror`](https://gitlab.com/gitlab-org/build/CNG-mirror) project so that the `CNG`, (Cloud
Native GitLab), project's registry is not overloaded with a lot of transient Docker images.
1. Once `review-build-cng` is done, the [`review-deploy`](https://gitlab.com/gitlab-org/gitlab/-/jobs/467724810) job
- deploys the Review App using [the official GitLab Helm chart](https://gitlab.com/gitlab-org/charts/gitlab/) to
+ deploys the review app using [the official GitLab Helm chart](https://gitlab.com/gitlab-org/charts/gitlab/) to
the [`review-apps`](https://console.cloud.google.com/kubernetes/clusters/details/us-central1-b/review-apps?project=gitlab-review-apps)
Kubernetes cluster on GCP.
- - The actual scripts used to deploy the Review App can be found at
+ - The actual scripts used to deploy the review app can be found at
[`scripts/review_apps/review-apps.sh`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/scripts/review_apps/review-apps.sh).
- These scripts are basically
[our official Auto DevOps scripts](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml) where the
@@ -192,11 +192,11 @@ subgraph "CNG-mirror pipeline"
- Since we're using [the official GitLab Helm chart](https://gitlab.com/gitlab-org/charts/gitlab/), this means
you get a dedicated environment for your branch that's very close to what
it would look in production.
- - Each review app is deployed to its own Kubernetes namespace. The namespace is based on the Review App slug that is
+ - Each review app is deployed to its own Kubernetes namespace. The namespace is based on the review app slug that is
unique to each branch.
1. Once the [`review-deploy`](https://gitlab.com/gitlab-org/gitlab/-/jobs/467724810) job succeeds, you should be able to
- use your Review App thanks to the direct link to it from the MR widget. To log
- into the Review App, see "Log into my Review App?" below.
+ use your review app thanks to the direct link to it from the MR widget. To log
+ into the review app, see "Log into my review app?" below.
**Additional notes:**
@@ -213,23 +213,23 @@ subgraph "CNG-mirror pipeline"
`#quality` channel and/or create a ~Quality ~"type::bug" issue with a link to your
merge request.
- The manual `review-stop` can be used to
- stop a Review App manually, and is also started by GitLab once a merge
+ stop a review app manually, and is also started by GitLab once a merge
request's branch is deleted after being merged.
- The Kubernetes cluster is connected to the `gitlab` projects using the
[GitLab Kubernetes integration](../../user/infrastructure/clusters/index.md). This basically
- allows to have a link to the Review App directly from the merge request widget.
+ allows to have a link to the review app directly from the merge request widget.
-### Auto-stopping of Review Apps
+### Auto-stopping of review apps
-Review Apps are automatically stopped 2 days after the last deployment thanks to
+Review apps are automatically stopped 2 days after the last deployment thanks to
the [Environment auto-stop](../../ci/environments/index.md#stop-an-environment-after-a-certain-time-period) feature.
-If you need your Review App to stay up for a longer time, you can
+If you need your review app to stay up for a longer time, you can
[pin its environment](../../ci/environments/index.md#override-a-deployments-scheduled-stop-time) or retry the
`review-deploy` job to update the "latest deployed at" time.
The `review-cleanup` job that automatically runs in scheduled
-pipelines stops stale Review Apps after 5 days,
+pipelines stops stale review apps after 5 days,
deletes their environment after 6 days, and cleans up any dangling Helm releases
and Kubernetes resources after 7 days.
@@ -246,13 +246,13 @@ The Helm version used is defined in the
[`registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-helm3.5-kubectl1.17` image](https://gitlab.com/gitlab-org/gitlab-build-images/-/blob/master/Dockerfile.gitlab-helm3.5-kubectl1.17#L6)
used by the `review-deploy` and `review-stop` jobs.
-## Diagnosing unhealthy Review App releases
+## Diagnosing unhealthy review app releases
-If [Review App Stability](https://app.periscopedata.com/app/gitlab/496118/Engineering-Productivity-Sandbox?widget=6690556&udv=785399)
+If [review app stability](https://app.periscopedata.com/app/gitlab/496118/Engineering-Productivity-Sandbox?widget=6690556&udv=785399)
dips this may be a signal that the `review-apps` cluster is unhealthy.
-Leading indicators may be health check failures leading to restarts or majority failure for Review App deployments.
+Leading indicators may be health check failures leading to restarts or majority failure for review app deployments.
-The [Review Apps Overview dashboard](https://console.cloud.google.com/monitoring/classic/dashboards/6798952013815386466?project=gitlab-review-apps&timeDomain=1d)
+The [review apps Overview dashboard](https://console.cloud.google.com/monitoring/classic/dashboards/6798952013815386466?project=gitlab-review-apps&timeDomain=1d)
aids in identifying load spikes on the cluster, and if nodes are problematic or the entire cluster is trending towards unhealthy.
See the [review apps page of the Engineering Productivity Runbook](https://gitlab.com/gitlab-org/quality/engineering-productivity/team/-/blob/main/runbook/review-apps.md) for troubleshooting review app releases.
@@ -273,7 +273,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)
+- [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)
### Helpful command line tools
diff --git a/doc/development/utilities.md b/doc/development/utilities.md
index 45a6b74f33a..551834670b3 100644
--- a/doc/development/utilities.md
+++ b/doc/development/utilities.md
@@ -199,10 +199,26 @@ Refer to [`strong_memoize.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/maste
end
strong_memoize_attr :result
- strong_memoize_attr :enabled?, :enabled
def enabled?
Feature.enabled?(:some_feature)
end
+ strong_memoize_attr :enabled?, :enabled
+ end
+ ```
+
+ There's also `strong_memoize_with` to help memoize methods that take arguments.
+ This should be used for methods that have a low number of possible values
+ as arguments or with consistent repeating arguments in a loop.
+
+ ```ruby
+ class Find
+ include Gitlab::Utils::StrongMemoize
+
+ def result(basic: true)
+ strong_memoize_with(:result, basic) do
+ search(basic)
+ end
+ end
end
```
diff --git a/doc/development/windows.md b/doc/development/windows.md
index 5f32848da79..bf56e16344a 100644
--- a/doc/development/windows.md
+++ b/doc/development/windows.md
@@ -132,7 +132,7 @@ PowerShell has aliases for all of the following commands so you don't have to le
- `ls` ---> `dir`
- `rm` ---> `del`
- `rm -rf nonemptydir` ---> `rmdir /S nonemptydir`
-- `/` ---> `\` (path separator)
+- `/` ---> <code>&#92;</code> (path separator)
- `cat` ---> `type`
- `mv` ---> `move`
- Redirection works the same (for example, `>` and `2>&1`)
diff --git a/doc/development/work_items.md b/doc/development/work_items.md
index eabad175bf7..a417e1d1349 100644
--- a/doc/development/work_items.md
+++ b/doc/development/work_items.md
@@ -55,6 +55,7 @@ To avoid confusion and ensure communication is efficient, we will use the follow
| legacy issue view | The existing view used to render issues and incidents | | |
| issue | The existing issue model | | |
| issuable | Any model currently using the issueable module (issues, epics and MRs) | _Incidents are an **issuable**_ | _Incidents are a **work item type**_ |
+| widget | A UI element to present or allow interaction with specific work item data | | |
Some terms have been used in the past but have since become confusing and are now discouraged.
@@ -138,6 +139,20 @@ To introduce a new WIT there are two options:
### Work item type widgets
+A widget is a single component that can exist on a work item. This component can be used on one or
+many work item types and can be lightly customized at the point of implementation.
+
+A widget contains both the frontend UI (if present) and the associated logic for presenting and
+managing any data used by the widget. There can be a one-to-many connection between the data model
+and widgets. It means there can be multiple widgets that use or manage the same data, and they could
+be present at the same time (for example, a read-only summary widget and an editable detail widget,
+or two widgets showing two different filtered views of the same model).
+
+Widgets should be differentiated by their **purpose**. When possible, this purpose should be
+abstracted to the highest reasonable level to maximize reusability. For example, the widget for
+managing "tasks" was built as "child items". Rather than managing one type of child, it's abstracted
+up to managing any children.
+
All WITs will share the same pool of predefined widgets and will be customized by
which widgets are active on a specific WIT. Every attribute (column or association)
will become a widget with self-encapsulated functionality regardless of the WIT it belongs to.
@@ -164,13 +179,17 @@ define these various types in a very flexible manner. Having GitLab use
this system first (without introducing customer customization) allows us to
better build out the initial system.
-NOTE:
-Currently work item's `base_type` is used to define static mapping of what
+Work item's `base_type` is used to define static mapping of what
widgets are available for each type (current status), this definition should be
-rather stored in database table. The exact structure of the WIT widgets
-metadata is still to be defined. `base_type` was added to help converting other
-types of resources (requirements and incidents) into work items. Eventually (when
-these resources become regular work items), `base_type` will be removed.
+rather stored in a database table. The exact structure of the WIT widgets metadata
+is [still to be defined](https://gitlab.com/gitlab-org/gitlab/-/issues/370599).
+`base_type` was added to help convert other types of resources (requirements
+and incidents) into work items. Eventually (when these resources become regular
+work items), `base_type` will be removed.
+
+Until the architecture of WIT widgets is finalized, we are holding off on the creation of new work item
+types. If a new work item type is absolutely necessary, please reach out to a
+member of the [Project Management Engineering Team](https://gitlab.com/gitlab-org/gitlab/-/issues/370599).
### Custom work item types
diff --git a/doc/development/workhorse/index.md b/doc/development/workhorse/index.md
index 0f4e55a002a..91795336f78 100644
--- a/doc/development/workhorse/index.md
+++ b/doc/development/workhorse/index.md
@@ -21,7 +21,7 @@ but that repository is no longer used for development.
## Install Workhorse
-To install GitLab Workhorse you need [Go 1.15 or newer](https://go.dev/dl) and
+To install GitLab Workhorse you need [Go 1.18 or newer](https://go.dev/dl) and
[GNU Make](https://www.gnu.org/software/make/).
To install into `/usr/local/bin` run `make install`.
diff --git a/doc/drawers/advanced_search_syntax.md b/doc/drawers/advanced_search_syntax.md
index 3c2ce212b99..7556c8bdfaf 100644
--- a/doc/drawers/advanced_search_syntax.md
+++ b/doc/drawers/advanced_search_syntax.md
@@ -3,39 +3,42 @@ 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"
type: drawer
-source: /doc/user/search/global_search/advanced_search_syntax.md
+source: /doc/user/search/advanced_search.md
---
# Search tips
<!-- markdownlint-disable -->
-| Use | Description | Example |
-|------|-------------|---------|
-| `"` | Exact search | [`"gem sidekiq"`](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=%22gem+sidekiq%22) |
-| <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) |
-| `*` | Partial | [`bug error 50*`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=bug+error+50%2A&snippets=) |
-| `\` | Escape | [`\*md`](https://gitlab.com/search?snippets=&scope=blobs&repository_ref=&search=%5C*md&group_id=9970&project_id=278964) |
+| Syntax | Description | Example |
+|--------------|---------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `"` | Exact search | [`"gem sidekiq"`](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=%22gem+sidekiq%22) |
+| <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) |
+| `*` | Partial | [`bug error 50*`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=bug+error+50%2A&snippets=) |
+| `\` | Escape | [`\*md`](https://gitlab.com/search?snippets=&scope=blobs&repository_ref=&search=%5C*md&group_id=9970&project_id=278964) |
+| `#` | 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) |
## Code search
-| Use | 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 the `.` | [`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) |
+| 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) |
-`extension` and `blob` return exact matches only.
+`extension:` and `blob:` return exact matches only.
## Examples
-| Use | Description |
-|------|-------------|
-| [`rails -filename:gemfile.lock`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=rails+-filename%3Agemfile.lock&snippets=) | Show _rails_ in all files except the _`gemfile.lock`_ file. |
-| [`RSpec.describe Resolvers -*builder`](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=RSpec.describe+Resolvers+-*builder) | Show all _RSpec.describe Resolvers_ that don't 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) | Show _bug_ **or** _display_ **and** _banner_. |
+| Query | Description |
+|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------|
+| [`rails -filename:gemfile.lock`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=rails+-filename%3Agemfile.lock&snippets=) | Returns `rails` in all files except the `gemfile.lock` file. |
+| [`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. |
<!-- markdownlint-enable -->
diff --git a/doc/gitlab-basics/add-file.md b/doc/gitlab-basics/add-file.md
index 64384372a44..95b8b59a48d 100644
--- a/doc/gitlab-basics/add-file.md
+++ b/doc/gitlab-basics/add-file.md
@@ -90,6 +90,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/gitlab-basics/command-line-commands.md b/doc/gitlab-basics/command-line-commands.md
index 4b53535a711..07ab9365693 100644
--- a/doc/gitlab-basics/command-line-commands.md
+++ b/doc/gitlab-basics/command-line-commands.md
@@ -118,6 +118,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/gitlab-basics/start-using-git.md b/doc/gitlab-basics/start-using-git.md
index 056fad4061b..25ef094b2a7 100644
--- a/doc/gitlab-basics/start-using-git.md
+++ b/doc/gitlab-basics/start-using-git.md
@@ -443,6 +443,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/install/aws/gitlab_hybrid_on_aws.md b/doc/install/aws/gitlab_hybrid_on_aws.md
index ad3d28d15e3..7ae4391dde0 100644
--- a/doc/install/aws/gitlab_hybrid_on_aws.md
+++ b/doc/install/aws/gitlab_hybrid_on_aws.md
@@ -46,7 +46,7 @@ The Beta version deploys Aurora PostgreSQL, but the release version will deploy
| | [AWS Quick Start for GitLab Cloud Native Hybrid on EKS](https://aws-quickstart.github.io/quickstart-eks-gitlab/) | [GitLab Environment Toolkit (GET)](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) |
| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
-| Overview and Vision | [AWS Quick Start](https://aws.amazon.com/quickstart/) | [GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/README.md) |
+| Overview and Vision | [AWS Quick Start](https://aws.amazon.com/quickstart/architecture/amazon-eks/) | [GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/README.md) |
| Licensing | [Open Source (Apache 2.0)](https://github.com/aws-quickstart/quickstart-eks-gitlab/blob/main/LICENSE.txt) | [GitLab Enterprise Edition license](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/LICENSE) ([GitLab Premium tier](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/README.md)) |
| GitLab Support | [GitLab Beta Support](../../policy/alpha-beta-support.md#beta-features) | [GitLab GA Support](../../policy/alpha-beta-support.md#generally-available-ga) |
| GitLab Reference Architecture Compliant | Yes | Yes |
diff --git a/doc/install/aws/manual_install_aws.md b/doc/install/aws/manual_install_aws.md
index 7dbb245dd99..5d8138e4705 100644
--- a/doc/install/aws/manual_install_aws.md
+++ b/doc/install/aws/manual_install_aws.md
@@ -147,7 +147,7 @@ We now create a VPC, a virtual networking environment that you control:
![Create VPC](img/create_vpc.png)
-1. Select the VPC, select **Actions**, select **Edit DNS resolution**, and enable DNS resolution. Hit **Save** when done.
+1. Select the VPC, select **Actions**, select **Edit DNS resolution**, and enable DNS resolution. Select **Save** when done.
### Subnets
@@ -226,7 +226,7 @@ it receive traffic from any destination.
route to show the options at the bottom.
1. Select the **Routes** tab, select **Edit routes > Add route** and set `0.0.0.0/0`
as the destination. In the target column, select the `gitlab-gateway` we created previously.
- Hit **Save routes** once done.
+ Select **Save routes** when done.
Next, we must associate the **public** subnets to the route table:
diff --git a/doc/install/docker.md b/doc/install/docker.md
index 93988454a27..11525842c6e 100644
--- a/doc/install/docker.md
+++ b/doc/install/docker.md
@@ -31,7 +31,7 @@ to community resources (such as IRC or forums) to seek help from other users.
## Prerequisites
-Docker is required. See the [official installation documentation](https://docs.docker.com/install/).
+Docker is required. See the [official installation documentation](https://docs.docker.com/get-docker/).
## Set up the volumes location
@@ -138,7 +138,7 @@ With [Docker Compose](https://docs.docker.com/compose/) you can easily configure
install, and upgrade your Docker-based GitLab installation:
1. [Install Docker Compose](https://docs.docker.com/compose/install/).
-1. Create a `docker-compose.yml` file (or [download an example](https://gitlab.com/gitlab-org/omnibus-gitlab/raw/master/docker/docker-compose.yml)):
+1. Create a `docker-compose.yml` file:
```yaml
version: '3.6'
@@ -211,7 +211,7 @@ and [Docker configurations](https://docs.docker.com/engine/swarm/configs/) to ef
Secrets can be used to securely pass your initial root password without exposing it as an environment variable.
Configurations can help you to keep your GitLab image as generic as possible.
-Here's an example that deploys GitLab with four runners as a [stack](https://docs.docker.com/get-started/part5/), using secrets and configurations:
+Here's an example that deploys GitLab with four runners as a [stack](https://docs.docker.com/get-started/swarm-deploy/#describe-apps-using-stack-files), using secrets and configurations:
1. [Set up a Docker swarm](https://docs.docker.com/engine/swarm/swarm-tutorial/).
1. Create a `docker-compose.yml` file:
diff --git a/doc/install/google_cloud_platform/index.md b/doc/install/google_cloud_platform/index.md
index 7ba1fbad5ea..d16ac3e2174 100644
--- a/doc/install/google_cloud_platform/index.md
+++ b/doc/install/google_cloud_platform/index.md
@@ -143,6 +143,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 6108ec8d0e0..c00a959e037 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -46,12 +46,12 @@ 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.17` | From GitLab 15.2, Go 1.17 or later is required. |
-| [Git](#git) | `2.33.x` | From GitLab 14.4, Git 2.33.x and later is required. It's highly recommended that you use the [Git version provided by Gitaly](#git). |
-| [Node.js](#4-node) | `14.15.0` | GitLab uses [webpack](https://webpack.js.org/) to compile frontend assets. Node.js 16.x is recommended, as it's faster. You can check which version you're running with `node -v`. You must update it to a newer version if needed. |
+| 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.37.x` | From GitLab 15.6, Git 2.37.x and later is required. It's highly recommended that you use the [Git version provided by Gitaly](#git). |
+| [Node.js](#4-node) | `14.15.0` | GitLab uses [webpack](https://webpack.js.org/) to compile frontend assets. Node.js 16.x is recommended, as it's faster. You can check which version you're running with `node -v`. You must update it to a newer version if needed. |
## GitLab directory structure
@@ -250,11 +250,11 @@ Linux. You can find downloads for other platforms at the
# Remove former Go installation folder
sudo rm -rf /usr/local/go
-curl --remote-name --location --progress-bar "https://go.dev/dl/go1.17.10.linux-amd64.tar.gz"
-echo '87fc728c9c731e2f74e4a999ef53cf07302d7ed3504b0839027bd9c10edaa3fd go1.17.10.linux-amd64.tar.gz' | shasum -a256 -c - && \
- sudo tar -C /usr/local -xzf go1.17.10.linux-amd64.tar.gz
+curl --remote-name --location --progress-bar "https://go.dev/dl/go1.18.8.linux-amd64.tar.gz"
+echo '4d854c7bad52d53470cf32f1b287a5c0c441dc6b98306dea27358e099698142a go1.18.8.linux-amd64.tar.gz' | shasum -a256 -c - && \
+ sudo tar -C /usr/local -xzf go1.18.8.linux-amd64.tar.gz
sudo ln -sf /usr/local/go/bin/{go,gofmt} /usr/local/bin/
-rm go1.17.10.linux-amd64.tar.gz
+rm go1.18.8.linux-amd64.tar.gz
```
## 4. Node
@@ -864,12 +864,6 @@ Check if GitLab and its environment are configured correctly:
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production
```
-### Compile GetText PO files
-
-```shell
-sudo -u git -H bundle exec rake gettext:compile RAILS_ENV=production
-```
-
### Compile Assets
```shell
diff --git a/doc/install/migrate/compare_sm_to_saas.md b/doc/install/migrate/compare_sm_to_saas.md
index e12861632b8..db5bb54386f 100644
--- a/doc/install/migrate/compare_sm_to_saas.md
+++ b/doc/install/migrate/compare_sm_to_saas.md
@@ -83,7 +83,7 @@ In a self-managed instance:
On GitLab SaaS:
-- You cannot use internal encryption key for the data store ([bring-your-own-key](https://about.gitlab.com/handbook/engineering/security/vulnerability_management/encryption-policy.html#rolling-your-own-crypto)).
+- You cannot use internal encryption key for the data store ([bring-your-own-key](https://about.gitlab.com/handbook/security/threat-management/vulnerability-management/encryption-policy.html#rolling-your-own-crypto)).
- You cannot view console logs.
- You cannot enforce jobs on every pipeline across the group or organization.
- You cannot configure or control data backups. You must use [group](../../api/group_import_export.md) and [project](../../api/project_import_export.md) export.
@@ -106,7 +106,7 @@ In a self-managed instance, you control the encryption type and configuration.
On GitLab SaaS:
-- An [Access Management Process](https://about.gitlab.com/handbook/engineering/security/#access-management-process) is in place.
+- An [Access Management Process](https://about.gitlab.com/handbook/security/#access-management-process) is in place.
- All data on GitLab.com is encrypted at rest by default. Access to encryption keys is strictly managed by GitLab.
- GitLab does not access your tenant data except as part of a verified service request from you.
diff --git a/doc/install/relative_url.md b/doc/install/relative_url.md
index 3fe34f6a9b0..6f4221f9e2e 100644
--- a/doc/install/relative_url.md
+++ b/doc/install/relative_url.md
@@ -134,6 +134,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index 8a1533dc268..f581a1c50f9 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -55,7 +55,7 @@ Memory requirements are dependent on the number of users and expected workload.
The following is the recommended minimum Memory hardware guidance for a handful of example GitLab user base sizes.
- **4GB RAM** is the **required** minimum memory size and supports up to 500 users
- - Our [Memory Team](https://about.gitlab.com/handbook/engineering/development/enablement/data_stores/memory/) is working to reduce the memory requirement.
+ - Our [Memory Team](https://about.gitlab.com/handbook/engineering/development/enablement/data_stores/application_performance/) is working to reduce the memory requirement.
- 8GB RAM supports up to 1000 users
- More users? Consult the [reference architectures page](../administration/reference_architectures/index.md)
@@ -299,7 +299,7 @@ GitLab supports the following web browsers:
- [Google Chrome](https://www.google.com/chrome/)
- [Chromium](https://www.chromium.org/getting-involved/dev-channel/)
- [Apple Safari](https://www.apple.com/safari/)
-- [Microsoft Edge](https://www.microsoft.com/en-us/edge)
+- [Microsoft Edge](https://www.microsoft.com/en-us/edge?form=MA13FJ)
For the listed web browsers, GitLab supports:
@@ -322,6 +322,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/integration/advanced_search/elasticsearch.md b/doc/integration/advanced_search/elasticsearch.md
index 87b812f3f9b..94493aa6958 100644
--- a/doc/integration/advanced_search/elasticsearch.md
+++ b/doc/integration/advanced_search/elasticsearch.md
@@ -251,7 +251,7 @@ 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.
-You can filter the selection dropdown by writing part of the namespace or project name you're interested in.
+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)
diff --git a/doc/integration/advanced_search/elasticsearch_troubleshooting.md b/doc/integration/advanced_search/elasticsearch_troubleshooting.md
index 7136c273a2a..aa6613d6f1a 100644
--- a/doc/integration/advanced_search/elasticsearch_troubleshooting.md
+++ b/doc/integration/advanced_search/elasticsearch_troubleshooting.md
@@ -212,8 +212,8 @@ More [complex Elasticsearch API calls](https://www.elastic.co/guide/en/elasticse
If the results:
-- Sync up, please check that you are using [supported syntax](../../user/search/global_search/advanced_search_syntax.md). Note that 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)
+- 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:
The above instructions are not to be used for scenarios that only index a [subset of namespaces](elasticsearch.md#limit-the-number-of-namespaces-and-projects-that-can-be-indexed).
diff --git a/doc/integration/bitbucket.md b/doc/integration/bitbucket.md
index 38d8f0049db..8019eccc421 100644
--- a/doc/integration/bitbucket.md
+++ b/doc/integration/bitbucket.md
@@ -38,7 +38,7 @@ you to use.
The URL to your GitLab installation, such as
`https://gitlab.example.com/users/auth`.
Leaving this field empty
- [results in an `Invalid redirect_uri` message](https://confluence.atlassian.com/bitbucket/oauth-faq-338365710.html).
+ results in an `Invalid redirect_uri` message.
WARNING:
To help prevent an [OAuth 2 covert redirect](https://oauth.net/advisories/2014-1-covert-redirect/)
diff --git a/doc/integration/gitlab.md b/doc/integration/gitlab.md
index 0658c921610..1b0a1e50445 100644
--- a/doc/integration/gitlab.md
+++ b/doc/integration/gitlab.md
@@ -19,10 +19,11 @@ GitLab.com generates an application ID and secret key for you to use.
- Name: This can be anything. Consider something like `<Organization>'s GitLab` or `<Your Name>'s GitLab` or something else descriptive.
- Redirect URI:
- ```plaintext
- http://your-gitlab.example.com/import/gitlab/callback
- http://your-gitlab.example.com/users/auth/gitlab/callback
- ```
+ ```plaintext
+ # You can also use a non-SSL URL, but you should use SSL URLs.
+ https://your-gitlab.example.com/import/gitlab/callback
+ https://your-gitlab.example.com/users/auth/gitlab/callback
+ ```
The first link is required for the importer and second for authentication.
diff --git a/doc/integration/gitpod.md b/doc/integration/gitpod.md
index 26d0da4b49d..0088d4b886d 100644
--- a/doc/integration/gitpod.md
+++ b/doc/integration/gitpod.md
@@ -44,7 +44,7 @@ With the Gitpod integration enabled for your GitLab instance, to enable it for y
For GitLab self-managed instances, a GitLab administrator needs to:
-1. Set up a Gitpod instance to integrate with GitLab. Refer to the [Gitpod documentation](https://www.gitpod.io/docs/self-hosted/latest)
+1. Set up a Gitpod instance to integrate with GitLab. Refer to the [Gitpod documentation](https://www.gitpod.io/docs/configure/self-hosted/latest)
to get your instance up and running.
1. Enable it in GitLab:
1. On the top bar, select **Main menu > Admin**.
diff --git a/doc/integration/index.md b/doc/integration/index.md
index 147edcc9e0f..b2a4201e88c 100644
--- a/doc/integration/index.md
+++ b/doc/integration/index.md
@@ -7,56 +7,67 @@ comments: false
# GitLab integrations **(FREE)**
-GitLab can be integrated with external services for enhanced functionality.
+You can integrate GitLab with external services for enhanced functionality.
## Services
-Services such as Campfire, Flowdock, Jira, Pivotal Tracker, and Slack are available as [integrations](../user/project/integrations/index.md).
+Services such as Campfire, Flowdock, Jira, Pivotal Tracker, and Slack
+are available as [integrations](../user/project/integrations/index.md).
## Issue trackers
-You can use an [external issue tracker](external-issue-tracker.md) at the same time as the GitLab
-issue tracker, or use only the external issue tracker.
+You can use an [external issue tracker](external-issue-tracker.md) with the GitLab
+issue tracker or use an external issue tracker only.
## Authentication sources
-GitLab can be configured to authenticate access requests with the following authentication sources:
+You can integrate GitLab with the following authentication sources:
- Enable the [Auth0 OmniAuth](auth0.md) provider.
-- Enable sign in with [Bitbucket](bitbucket.md) accounts.
-- Integrate with [Kerberos](kerberos.md).
-- Enable sign in via [LDAP](../administration/auth/ldap/index.md).
-- Enable [OAuth2 provider](oauth_provider.md) application creation.
-- Use [OmniAuth](omniauth.md) to enable sign in through Twitter, GitHub, GitLab.com, Google,
- Bitbucket, Facebook, SAML, Crowd, Azure, or Authentiq ID.
+- Enable sign-in with [Bitbucket](bitbucket.md) accounts.
+- Authenticate with [Kerberos](kerberos.md).
+- Enable sign-in with [LDAP](../administration/auth/ldap/index.md).
+- Enable creating [OAuth 2.0](oauth_provider.md) applications.
+- Use [OmniAuth](omniauth.md) to enable sign-in through:
+ - Authentiq ID
+ - Azure
+ - Bitbucket
+ - Crowd
+ - Facebook
+ - GitHub
+ - GitLab.com
+ - Google
+ - SAML
+ - Twitter
- Use GitLab as an [OpenID Connect](openid_connect_provider.md) identity provider.
-- Authenticate to [Vault](vault.md) through GitLab OpenID Connect.
-- Configure GitLab as a [SAML](saml.md) 2.0 Service Provider.
+- Authenticate with [Vault](vault.md) through GitLab OpenID Connect.
+- Configure GitLab as a [SAML 2.0](saml.md) Service Provider.
## Security enhancements
-GitLab can be integrated with the following external services to enhance security:
+You can integrate GitLab with the following security enhancements:
-- [Akismet](akismet.md) helps reduce spam.
-- Google [reCAPTCHA](recaptcha.md) helps verify new users.
+- [Akismet](akismet.md) to reduce spam.
+- Google [reCAPTCHA](recaptcha.md) to verify new users.
-GitLab also provides features to improve the security of your own application. For more details see [GitLab Secure](../user/application_security/index.md).
+GitLab also provides features to improve the security of your own application.
+For more details, see [Secure your application](../user/application_security/index.md).
## Security partners
-GitLab has integrated with several security partners. For more information, see
-[Security partners integration](security_partners/index.md).
+You can integrate GitLab with several security partners. For more information, see
+[Security partner integrations](security_partners/index.md).
## Continuous integration
-GitLab can be integrated with the following external services for continuous integration:
+You can integrate GitLab with the following external services for continuous integration:
- [Jenkins](jenkins.md) CI.
-- [Datadog](datadog.md), to monitor for CI/CD job failures and performance issues.
+- [Datadog](datadog.md) to monitor for CI/CD job failures and performance issues.
## Feature enhancements
-GitLab can be integrated with the following enhancements:
+You can integrate GitLab with the following feature enhancements:
- Add GitLab actions to [Gmail actions buttons](gmail_action_buttons_for_gitlab.md).
- Configure [PlantUML](../administration/integration/plantuml.md)
@@ -69,40 +80,28 @@ or [Kroki](../administration/integration/kroki.md) to use diagrams in AsciiDoc a
### SSL certificate errors
-When trying to integrate GitLab with services using self-signed certificates,
-SSL certificate errors can occur in different parts of the application. Sidekiq
-is a common culprit.
+When integrating GitLab with services using a self-signed certificate, you might
+encounter SSL certificate errors in different parts of the application.
-There are two approaches you can take to solve this:
+As a workaround, you can do one of the following:
-1. Add the root certificate to the trusted chain of the OS.
-1. If using Omnibus, you can add the certificate to the GitLab trusted certificates.
+- Add the certificate to the OS trusted chain. See:
+ - [Adding trusted root certificates to the server](https://manuals.gfi.com/en/kerio/connect/content/server-configuration/ssl-certificates/adding-trusted-root-certificates-to-the-server-1605.html)
+ - [How do you add a certificate authority (CA) to Ubuntu?](https://superuser.com/questions/437330/how-do-you-add-a-certificate-authority-ca-to-ubuntu)
+- In Omnibus GitLab, add the certificate to the Omnibus trusted chain:
+ 1. [Install the self-signed certificate](https://docs.gitlab.com/omnibus/settings/ssl.html#install-custom-public-certificates).
+ 1. Concatenate the self-signed certificate with the GitLab trusted certificate.
+ The self-signed certificate might be overwritten during upgrades.
-**OS main trusted chain**
+ ```shell
+ cat jira.pem >> /opt/gitlab/embedded/ssl/certs/cacert.pem
+ ```
-This [resource](https://manuals.gfi.com/en/kerio/connect/content/server-configuration/ssl-certificates/adding-trusted-root-certificates-to-the-server-1605.html)
-has all the information you need to add a certificate to the main trusted chain.
+ 1. Restart GitLab.
-This [answer](https://superuser.com/questions/437330/how-do-you-add-a-certificate-authority-ca-to-ubuntu)
-at Super User also has relevant information.
-
-**Omnibus Trusted Chain**
-
-[Install the self signed certificate or custom certificate authorities](https://docs.gitlab.com/omnibus/troubleshooting.html#using-self-signed-certificate-or-custom-certificate-authorities)
-in to Omnibus GitLab.
-
-It is enough to concatenate the certificate to the main trusted certificate
-however it may be overwritten during upgrades:
-
-```shell
-cat jira.pem >> /opt/gitlab/embedded/ssl/certs/cacert.pem
-```
-
-After that restart GitLab with:
-
-```shell
-sudo gitlab-ctl restart
-```
+ ```shell
+ sudo gitlab-ctl restart
+ ```
### Search Sidekiq logs in Kibana
@@ -112,4 +111,9 @@ To locate a specific integration in Kibana, use the following KQL search string:
`json.integration_class.keyword : "Integrations::Jira" and json.project_path : "path/to/project"`
```
-You can find information in `json.exception.backtrace`, `json.exception.class`, `json.exception.message`, and `json.message`.
+You can find information in:
+
+- `json.exception.backtrace`
+- `json.exception.class`
+- `json.exception.message`
+- `json.message`
diff --git a/doc/integration/jenkins_deprecated.md b/doc/integration/jenkins_deprecated.md
deleted file mode 100644
index 53f7162402b..00000000000
--- a/doc/integration/jenkins_deprecated.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-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
-remove_date: '2022-10-29'
-redirect_to: 'jenkins.md'
----
-
-# Jenkins CI service (removed) **(FREE)**
-
-This feature was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/1600)
-in GitLab 13.0.
-Use the [Jenkins integration](jenkins.md) instead.
diff --git a/doc/integration/jira/configure.md b/doc/integration/jira/configure.md
index 66339d5ec27..98d296db170 100644
--- a/doc/integration/jira/configure.md
+++ b/doc/integration/jira/configure.md
@@ -52,7 +52,7 @@ To configure your project:
can view all issues from the specified Jira project.
1. To enable [issue creation for vulnerabilities](../../user/application_security/vulnerabilities/index.md#create-a-jira-issue-for-a-vulnerability), select **Enable Jira issue creation from vulnerabilities**.
-1. Select the **Jira issue type**. If the dropdown is empty, select refresh (**{retry}**) and try again.
+1. Select the **Jira issue type**. If the dropdown list is empty, select refresh (**{retry}**) and try again.
1. To verify the Jira connection is working, select **Test settings**.
1. Select **Save changes**.
diff --git a/doc/integration/jira/index.md b/doc/integration/jira/index.md
index 5daad4094f4..63cd472b0b9 100644
--- a/doc/integration/jira/index.md
+++ b/doc/integration/jira/index.md
@@ -79,102 +79,3 @@ This method provides more fine-grained access control because access can be rest
Developers have built several third-party Jira integrations for GitLab that are
listed on the [Atlassian Marketplace](https://marketplace.atlassian.com/search?product=jira&query=gitlab).
-
-## Troubleshooting
-
-If these features do not work as expected, it is likely due to a problem with the way the integration settings were configured.
-
-### GitLab cannot comment on a Jira issue
-
-If GitLab cannot comment on Jira issues, make sure the Jira user you
-set up for the integration has permission to:
-
-- Post comments on a Jira issue.
-- Transition the Jira issue.
-
-Jira issue references and update comments do not work if the GitLab issue tracker is disabled.
-
-If you [restrict IP addresses for Jira access](https://support.atlassian.com/security-and-access-policies/docs/specify-ip-addresses-for-product-access/), make sure you add your self-managed IP addresses or [GitLab.com IP range](../../user/gitlab_com/index.md#ip-range) to the allowlist in Jira.
-
-### GitLab cannot close a Jira issue
-
-If GitLab cannot close a Jira issue:
-
-- Make sure the `Transition ID` you set in the Jira settings matches the one
- your project needs to close an issue.
-
-- Make sure the Jira issue is not already marked as resolved:
- - Check the Jira issue resolution field is not set.
- - Check the issue is not struck through in Jira lists.
-
-### CAPTCHA
-
-CAPTCHA may be triggered after several consecutive failed login attempts,
-which may lead to a `401 unauthorized` error when testing your Jira integration.
-If CAPTCHA has been triggered, you can't use Jira's REST API to
-authenticate with the Jira site.
-
-To fix this error, sign in to your Jira instance
-and complete the CAPTCHA.
-
-### Jira integration does not work for imported project
-
-There is a [known bug](https://gitlab.com/gitlab-org/gitlab/-/issues/341571)
-where the Jira integration sometimes does not work for a project that has been imported.
-As a workaround, disable the integration and then re-enable it.
-
-### Bulk change all Jira integrations to Jira instance-level values
-
-To change all Jira projects to use instance-level integration settings:
-
-1. In a [Rails console](../../administration/operations/rails_console.md#starting-a-rails-console-session), run the following:
-
- ```ruby
- jira_integration_instance_id = Integrations::Jira.find_by(instance: true).id
- Integrations::Jira.where(active: true, instance: false, template: false, inherit_from_id: nil).find_each do |integration|
- integration.update_attribute(:inherit_from_id, jira_integration_instance_id)
- end
- ```
-
-1. Modify and save the instance-level integration from the UI to propagate the changes to all group-level and project-level integrations.
-
-### Check if Jira Cloud is linked
-
-You can use the [Rails console](../../administration/operations/rails_console.md#starting-a-rails-console-session) to check if Jira Cloud is linked to:
-
-A specified namespace:
-
-```ruby
-JiraConnectSubscription.where(namespace: Namespace.by_path('group/subgroup'))
-```
-
-A specified project:
-
-```ruby
-Project.find_by_full_path('path/to/project').jira_subscription_exists?
-```
-
-Any namespace:
-
-```ruby
-installation = JiraConnectInstallation.find_by_base_url("https://customer_name.atlassian.net")
-installation.subscriptions
-```
-
-### Bulk update the service integration password for all projects
-
-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.each do |project|
- project.jira_integration.update_attribute(:password, '<your-new-password>')
-end
-```
-
-### `500 Whoops` 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.
-Check [`production.log`](../../administration/logs/index.md#productionlog) to see if it contains a `:NoMethodError (undefined method 'duedate' for #<JIRA::Resource::Issue:0x00007f406d7b3180>)` exception. If that's the case, ensure the **Due date** field is visible for issues in the integrated Jira project.
diff --git a/doc/integration/jira/jira_server_configuration.md b/doc/integration/jira/jira_server_configuration.md
index 42de883753c..fd8e018fd0c 100644
--- a/doc/integration/jira/jira_server_configuration.md
+++ b/doc/integration/jira/jira_server_configuration.md
@@ -54,10 +54,12 @@ This process adds the `gitlab` user you created to a new group named `gitlab-dev
1. To add the `gitlab` user to the `gitlab-developers` group, select **Edit members**.
The `gitlab-developers` group should be listed in the leftmost box as a
selected group.
+<!-- vale gitlab.BadPlurals = NO -->
1. In the **Add members to selected group(s)** section, enter `gitlab`.
1. Select **Add selected users**.
The `gitlab` user appears in the **Group member(s)**
section.
+<!-- vale gitlab.BadPlurals = YES -->
![Jira added user to group](img/jira_added_user_to_group.png)
diff --git a/doc/integration/jira/troubleshooting.md b/doc/integration/jira/troubleshooting.md
new file mode 100644
index 00000000000..0e679693614
--- /dev/null
+++ b/doc/integration/jira/troubleshooting.md
@@ -0,0 +1,110 @@
+---
+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
+---
+
+# Troubleshooting Jira integrations **(FREE)**
+
+This page contains a list of common issues you might encounter when working with Jira integrations.
+
+## GitLab cannot comment on a Jira issue
+
+If GitLab cannot comment on Jira issues, make sure the Jira user you
+set up for the integration has permission to:
+
+- Post comments on a Jira issue.
+- Transition the Jira issue.
+
+Jira issue references and update comments do not work if the GitLab issue tracker is disabled.
+
+If you [restrict IP addresses for Jira access](https://support.atlassian.com/security-and-access-policies/docs/specify-ip-addresses-for-product-access/), make sure you add your self-managed IP addresses or [GitLab.com IP range](../../user/gitlab_com/index.md#ip-range) to the allowlist in Jira.
+
+## GitLab cannot close a Jira issue
+
+If GitLab cannot close a Jira issue:
+
+- Make sure the `Transition ID` you set in the Jira settings matches the one
+ your project needs to close an issue.
+
+- Make sure the Jira issue is not already marked as resolved:
+ - Check the Jira issue resolution field is not set.
+ - Check the issue is not struck through in Jira lists.
+
+## CAPTCHA
+
+CAPTCHA might be triggered after several consecutive failed login attempts,
+which might lead to a `401 unauthorized` error when testing your Jira integration.
+If CAPTCHA has been triggered, you can't use the Jira REST API to
+authenticate with the Jira site.
+
+To fix this error, sign in to your Jira instance
+and complete the CAPTCHA.
+
+## Jira integration does not work for imported project
+
+There is a [known bug](https://gitlab.com/gitlab-org/gitlab/-/issues/341571)
+where the Jira integration sometimes does not work for a project that has been imported.
+As a workaround, disable the integration and then re-enable it.
+
+## Bulk change all Jira integrations to Jira instance-level values
+
+To change all Jira projects to use instance-level integration settings:
+
+1. In a [Rails console](../../administration/operations/rails_console.md#starting-a-rails-console-session), run the following:
+
+ ```ruby
+ jira_integration_instance_id = Integrations::Jira.find_by(instance: true).id
+ Integrations::Jira.where(active: true, instance: false, template: false, inherit_from_id: nil).find_each do |integration|
+ integration.update_attribute(:inherit_from_id, jira_integration_instance_id)
+ end
+ ```
+
+1. Modify and save the instance-level integration from the UI to propagate the changes to all group-level and project-level integrations.
+
+## Check if Jira Cloud is linked
+
+You can use the [Rails console](../../administration/operations/rails_console.md#starting-a-rails-console-session) to check if Jira Cloud is linked to:
+
+A specified namespace:
+
+```ruby
+JiraConnectSubscription.where(namespace: Namespace.by_path('group/subgroup'))
+```
+
+A specified project:
+
+```ruby
+Project.find_by_full_path('path/to/project').jira_subscription_exists?
+```
+
+Any namespace:
+
+```ruby
+installation = JiraConnectInstallation.find_by_base_url("https://customer_name.atlassian.net")
+installation.subscriptions
+```
+
+## Bulk update the service integration password for all projects
+
+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.each do |project|
+ project.jira_integration.update_attribute(:password, '<your-new-password>')
+end
+```
+
+## `500 Whoops` 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.
+Check [`production.log`](../../administration/logs/index.md#productionlog) to see if it contains the following exception:
+
+```plaintext
+:NoMethodError (undefined method 'duedate' for #<JIRA::Resource::Issue:0x00007f406d7b3180>)
+```
+
+If that's the case, ensure the **Due date** field is visible for issues in the integrated Jira project.
diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md
index 964c5edcbc1..bedcbf23163 100644
--- a/doc/integration/oauth_provider.md
+++ b/doc/integration/oauth_provider.md
@@ -38,7 +38,7 @@ GitLab supports several ways of adding a new OAuth 2 application to an instance:
- [Instance-wide applications](#instance-wide-applications)
The only difference between these methods is the [permission](../user/permissions.md)
-levels. The default callback URL is `http://your-gitlab.example.com/users/auth/gitlab/callback`.
+levels. The default callback URL is `https://your-gitlab.example.com/users/auth/gitlab/callback` (you can also use a non-SSL URL, but you should use SSL URLs).
## User owned applications
@@ -137,17 +137,3 @@ On self-managed GitLab, by default, this feature is not available. To make it av
On GitLab.com, this feature is not available.
By default, OAuth application secrets are stored as plain text in the database. When enabled, OAuth application secrets are stored in the database in hashed format and are only available to users immediately after creating OAuth applications.
-
-## Hashed OAuth tokens
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/364110) in GitLab 15.3 [with a flag](../administration/feature_flags.md) named `hash_oauth_tokens`. Enabled on GitLab.com. Disabled by default for self-managed.
-> - [Enabled by default on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/337507) in GitLab 15.5.
-
-FLAG:
-On self-managed GitLab, by default, this feature is enabled. If you detect a problem, ask an administrator to
-[disable the feature flag](../administration/feature_flags.md) named `hash_oauth_tokens`. If the feature flag is disabled, any tokens that were stored
-in encrypted format are inaccessible. Users must reauthorize applications.
-On GitLab.com, this feature is enabled.
-
-By default, OAuth access tokens are stored in the database in PBKDF2+SHA512 format. GitLab administrators can disable this and OAuth access tokens are
-then stored in plaintext in the database.
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index 55d1d1bcbb8..af039c8a009 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -43,23 +43,19 @@ GitLab supports the following OmniAuth providers.
Before you configure the OmniAuth provider,
configure the settings that are common for all providers.
-Setting | Description | Default value
----------------------------|-------------|--------------
-`allow_single_sign_on` | Enables you to list the providers that automatically create a GitLab account. The provider names are available in the **OmniAuth provider name** column in the [supported providers table](#supported-providers). | The default is `false`. If `false`, users must be created manually, or they can't sign in using OmniAuth.
-`auto_link_ldap_user` | If enabled, creates an LDAP identity in GitLab for users that are created through an OmniAuth provider. You can enable this setting if you have [LDAP integration](../administration/auth/ldap/index.md) enabled. Requires the `uid` of the user to be the same in both LDAP and the OmniAuth provider. | The default is `false`.
-`block_auto_created_users` | If enabled, blocks users that are automatically created from signing in until they are approved by an administrator. | The default is `true`. If you set the value to `false`, make sure you only define providers for `allow_single_sign_on` that you can control, like SAML or Google. Otherwise, any user on the internet can sign in to GitLab without an administrator's approval.
+Omnibus, Docker, and source | Helm chart | Description | Default value
+----------------------------|------------|-------------|-----------
+`allow_single_sign_on` | `allowSingleSignOn` | List of providers that automatically create a GitLab account. The provider names are available in the **OmniAuth provider name** column in the [supported providers table](#supported-providers). | `false`, which means that signing in using your OmniAuth provider account without a pre-existing GitLab account is not allowed. You must create a GitLab account first, and then connect it to your OmniAuth provider account through your profile settings.
+`auto_link_ldap_user` | `autoLinkLdapUser` | Creates an LDAP identity in GitLab for users that are created through an OmniAuth provider. You can enable this setting if you have [LDAP integration](../administration/auth/ldap/index.md) enabled. Requires the `uid` of the user to be the same in both LDAP and the OmniAuth provider. | `false`
+`block_auto_created_users` | `blockAutoCreatedUsers` | Blocks users that are automatically created from signing in until they are approved by an administrator. | `true`. If you set the value to `false`, make sure you define providers that you can control, like SAML or Google. Otherwise, any user on the internet can sign in to GitLab without an administrator's approval.
To change these settings:
-- **For Omnibus package**
-
- 1. Open the configuration file:
+ ::Tabs
- ```shell
- sudo editor /etc/gitlab/gitlab.rb
- ```
+ :::TabTitle Omnibus
- 1. Update the following section:
+ 1. Edit `/etc/gitlab/gitlab.rb` and update the following section:
```ruby
# CAUTION!
@@ -71,13 +67,47 @@ To change these settings:
gitlab_rails['omniauth_block_auto_created_users'] = true
```
-- **For installations from source**
+ 1. Reconfigure GitLab:
+
+ ```shell
+ sudo gitlab-ctl reconfigure
+ ```
+
+ :::TabTitle Helm chart
+
+ 1. Export the Helm values:
+
+ ```shell
+ helm get values gitlab > gitlab_values.yaml
+ ```
+
+ 1. Edit `gitlab_values.yaml`, and update the `omniauth` section under `globals.appConfig`:
+
+ ```yaml
+ global:
+ appConfig:
+ omniauth:
+ enabled: true
+ allowSingleSignOn: ['saml', 'twitter']
+ autoLinkLdapUser: false
+ blockAutoCreatedUsers: true
+ ```
+
+ For more details, see the
+ [globals documentation](https://docs.gitlab.com/charts/charts/globals.html#omniauth).
+
+ 1. Apply the new values:
+
+ ```shell
+ helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
+ ```
+
+ :::TabTitle Source
1. Open the configuration file:
```shell
cd /home/git/gitlab
-
sudo -u git -H editor config/gitlab.yml
```
@@ -102,6 +132,14 @@ To change these settings:
block_auto_created_users: true
```
+ 1. Restart GitLab:
+
+ ```shell
+ sudo service gitlab restart
+ ```
+
+ ::EndTabs
+
After configuring these settings, you can configure
your chosen [provider](#supported-providers).
diff --git a/doc/integration/saml.md b/doc/integration/saml.md
index 0f7f3e336ef..fd01e9e0e56 100644
--- a/doc/integration/saml.md
+++ b/doc/integration/saml.md
@@ -660,7 +660,7 @@ balancer and include sensitive details in assertions that you do not want appear
in logs. Most organizations should not need additional encryption at this layer.
The SAML integration supports EncryptedAssertion. You should define the private
-key and the public certificate of your GitLab instance in the SAML settings:
+key and the public certificate of your GitLab instance in the SAML settings. When you define the key and certificate, replace all line feeds in the key file with `\n`. This makes the key file one long string with no line feeds.
```yaml
args: {
@@ -669,12 +669,8 @@ args: {
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
- certificate: '-----BEGIN CERTIFICATE-----
- <redacted>
- -----END CERTIFICATE-----',
- private_key: '-----BEGIN PRIVATE KEY-----
- <redacted>
- -----END PRIVATE KEY-----'
+ certificate: '-----BEGIN CERTIFICATE-----\n<redacted>\n-----END CERTIFICATE-----',
+ private_key: '-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----'
}
```
@@ -703,12 +699,8 @@ args: {
idp_sso_target_url: 'https://login.example.com/idp',
issuer: 'https://gitlab.example.com',
name_identifier_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
- certificate: '-----BEGIN CERTIFICATE-----
- <redacted>
- -----END CERTIFICATE-----',
- private_key: '-----BEGIN PRIVATE KEY-----
- <redacted>
- -----END PRIVATE KEY-----',
+ certificate: '-----BEGIN CERTIFICATE-----\n<redacted>\n-----END CERTIFICATE-----',
+ private_key: '-----BEGIN PRIVATE KEY-----\n<redacted>\n-----END PRIVATE KEY-----',
security: {
authn_requests_signed: true, # enable signature on AuthNRequest
want_assertions_signed: true, # enable the requirement of signed assertion
diff --git a/doc/integration/slash_commands.md b/doc/integration/slash_commands.md
index ff892f006a5..5eefa1138aa 100644
--- a/doc/integration/slash_commands.md
+++ b/doc/integration/slash_commands.md
@@ -32,7 +32,7 @@ Assuming `project-name` is the trigger command, the slash commands are:
| `/project-name deploy <from> to <to>` | [Deploys](#deploy-command) from the `<from>` environment to the `<to>` environment. |
| `/project-name run <job name> <arguments>` | Executes the [ChatOps](../ci/chatops/index.md) job `<job name>` on the default branch. |
-If you are using the [GitLab Slack application](../user/project/integrations/gitlab_slack_application.md) for
+If you are using the [GitLab for Slack app](../user/project/integrations/gitlab_slack_application.md) for
your GitLab.com projects, [add the `gitlab` keyword at the beginning of the command](../user/project/integrations/gitlab_slack_application.md#usage).
## Issue commands
diff --git a/doc/integration/vault.md b/doc/integration/vault.md
index ad807f9eb7a..2226dc4cfd4 100644
--- a/doc/integration/vault.md
+++ b/doc/integration/vault.md
@@ -18,7 +18,7 @@ GitLab by using our OpenID authentication feature.
## Prerequisites
-1. [Install Vault](https://www.vaultproject.io/docs/install).
+1. [Install Vault](https://developer.hashicorp.com/vault/docs/install).
1. Run Vault.
## Get the OpenID Connect client ID and secret from GitLab
@@ -29,7 +29,7 @@ for authenticating into Vault. To do this, sign in to GitLab and follow these st
1. In the top-right corner, select your avatar.
1. Select **Edit profile**.
1. On the left sidebar, select **Applications**.
-1. Fill out the application **Name** and [**Redirect URI**](https://www.vaultproject.io/docs/auth/jwt#redirect-uris).
+1. Fill out the application **Name** and [**Redirect URI**](https://developer.hashicorp.com/vault/docs/auth/jwt#redirect-uris).
1. Select the **OpenID** scope.
1. Select **Save application**.
1. Copy the **Client ID** and **Client Secret**, or keep the page open for reference.
@@ -78,7 +78,7 @@ Success! Data written to: auth/oidc/config
## Write the OIDC role configuration
-You must tell Vault the [**Redirect URIs**](https://www.vaultproject.io/docs/auth/jwt#redirect-uris)
+You must tell Vault the [**Redirect URIs**](https://developer.hashicorp.com/vault/docs/auth/jwt#redirect-uris)
and scopes given to GitLab when you created the application.
Run the following command in the terminal:
@@ -128,7 +128,7 @@ Otherwise, anyone with a public account can access your Vault instance.
## Sign in using the Vault CLI (optional)
-You can also sign into Vault using the [Vault CLI](https://www.vaultproject.io/docs/commands).
+You can also sign into Vault using the [Vault CLI](https://developer.hashicorp.com/vault/docs/commands).
1. To sign in with the role configuration you created in the previous example,
run the following command in your terminal:
@@ -143,7 +143,7 @@ You can also sign into Vault using the [Vault CLI](https://www.vaultproject.io/d
- `-method=oidc` to set Vault to use the `OIDC` sign-in method.
- `port=8250` to set the port that GitLab should redirect to. This port
number must match the port given to GitLab when listing
- [Redirect URIs](https://www.vaultproject.io/docs/auth/jwt#redirect-uris).
+ [Redirect URIs](https://developer.hashicorp.com/vault/docs/auth/jwt#redirect-uris).
After running this command, you should see a link in the terminal.
diff --git a/doc/legal/corporate_contributor_license_agreement.md b/doc/legal/corporate_contributor_license_agreement.md
index 257b26dd7c4..d98c8e54964 100644
--- a/doc/legal/corporate_contributor_license_agreement.md
+++ b/doc/legal/corporate_contributor_license_agreement.md
@@ -3,28 +3,29 @@ 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
---
+<!-- vale off -->
# Corporate contributor license agreement
You accept and agree to the following terms and conditions for Your present and future Contributions submitted to GitLab B.V.. Except for the license granted herein to GitLab B.V. and recipients of software distributed by GitLab B.V., You reserve all right, title, and interest in and to Your Contributions.
-- **Definitions:**
+"1." **Definitions:**
"You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab B.V.. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"Contribution" shall mean the code, documentation or other original works of authorship, including any modifications or additions to an existing work, that is submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
-- **Grant of Copyright License:**
+"2." **Grant of Copyright License:**
Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
-- **Grant of Patent License:**
+"3." **Grant of Patent License:**
Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
You represent that You are legally entitled to grant the above license. You represent further that each of Your employees is authorized to submit Contributions on Your behalf, but excluding employees that are designated in writing by You as "Not authorized to submit Contributions on behalf of (name of Your corporation here)." Such designations of exclusion for unauthorized employees are to be submitted via email to `legal@gitlab.com`. It is Your responsibility to notify GitLab B.V. when any change is required to the list of designated employees excluded from submitting Contributions on Your behalf. Such notification should also be sent via email to `legal@gitlab.com`.
-- **Contributions:**
+"4." **Contributions:**
You represent that each of Your Contributions is Your original creation.
diff --git a/doc/legal/developer_certificate_of_origin.md b/doc/legal/developer_certificate_of_origin.md
index 5c9f7f1fed7..eec89ce403e 100644
--- a/doc/legal/developer_certificate_of_origin.md
+++ b/doc/legal/developer_certificate_of_origin.md
@@ -3,6 +3,7 @@ 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
---
+<!-- vale off -->
# Developer Certificate of Origin Version 1.1
diff --git a/doc/legal/individual_contributor_license_agreement.md b/doc/legal/individual_contributor_license_agreement.md
index 125ab1e6a8e..5a6116befe0 100644
--- a/doc/legal/individual_contributor_license_agreement.md
+++ b/doc/legal/individual_contributor_license_agreement.md
@@ -3,28 +3,29 @@ 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
---
+<!-- vale off -->
# Individual contributor license agreement
You accept and agree to the following terms and conditions for Your present and future Contributions submitted to GitLab B.V.. Except for the license granted herein to GitLab B.V. and recipients of software distributed by GitLab B.V., You reserve all right, title, and interest in and to Your Contributions.
-- **Definitions:**
+"1." **Definitions:**
"You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab B.V.. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"Contribution" shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
-- **Grant of Copyright License:**
+"2." **Grant of Copyright License:**
Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
-- **Grant of Patent License:**
+"3." **Grant of Patent License:**
Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to GitLab B.V., or that your employer has executed a separate Corporate CLA with GitLab B.V..
-- **Contributions:**
+"4." **Contributions:**
You represent that each of Your Contributions is Your original creation. You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware and which are associated with any part of Your Contributions.
diff --git a/doc/operations/error_tracking.md b/doc/operations/error_tracking.md
index 3717eb46184..85b64eb7b3e 100644
--- a/doc/operations/error_tracking.md
+++ b/doc/operations/error_tracking.md
@@ -32,7 +32,7 @@ For error tracking to work, you need two pieces:
### Deploying Sentry
-You can sign up to the cloud hosted [Sentry](https://sentry.io), deploy your own [on-premise instance](https://github.com/getsentry/onpremise/), or use GitLab to [install Sentry to a Kubernetes cluster](../user/infrastructure/clusters/manage/management_project_applications/sentry.md).
+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
@@ -55,7 +55,7 @@ least Maintainer [permissions](../user/permissions.md) to enable the Sentry inte
1. Ensure the **Active** checkbox is selected.
1. In the **Sentry API URL** box, enter your Sentry hostname. For example, enter `https://sentry.example.com`. For the SaaS version of Sentry, the hostname is `https://sentry.io`.
1. In the **Auth Token** box, enter the token you previously generated.
-1. To test the connection to Sentry and populate the **Project** dropdown, select **Connect**.
+1. To test the connection to Sentry and populate the **Project** dropdown list, select **Connect**.
1. From the **Project** list, choose a Sentry project to link to your GitLab project.
1. Select **Save changes**.
@@ -131,12 +131,13 @@ If another event occurs, the error reverts to unresolved.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/329596) in GitLab 14.4.
> - [Disabled](https://gitlab.com/gitlab-org/gitlab/-/issues/353639) in GitLab 14.9 [with a flag](../administration/feature_flags.md) named `integrated_error_tracking`. Disabled by default.
+> - [Enabled on GitLab.com](https://gitlab.com/gitlab-com/gl-infra/production/-/issues/7586) in GitLab 15.6.
FLAG:
By default this feature is not available. To make it available on self-managed GitLab, ask an
administrator to [enable the feature flag](../administration/feature_flags.md)
named `integrated_error_tracking`. The feature is not ready for production use.
-On GitLab.com, please follow [our user guide](https://gitlab.com/gitlab-org/opstrace/opstrace/-/blob/main/docs/guides/user/error_tracking.md) to get started.
+On GitLab.com, this feature is available.
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
@@ -148,6 +149,14 @@ settings. By using a GitLab-provided DSN, your application connects to GitLab to
Those errors are stored in the GitLab database and rendered by the GitLab UI, in the same way as
Sentry integration.
+In GitLab 15.6 and later, the integrated error tracking is available as an
+[open Beta](../policy/alpha-beta-support.md#beta-features).
+It now 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.
+
+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).
+
### Project settings
You can find the feature configuration at **Settings > Monitor > Error Tracking**.
@@ -156,11 +165,11 @@ You can find the feature configuration at **Settings > Monitor > Error Tracking*
1. Select **GitLab** as the error tracking backend for your project:
- ![Error Tracking Settings](img/error_tracking_setting_v14_3.png)
+ ![Error Tracking Settings](img/error_tracking_setting_v14_3.png)
1. Select **Save changes**. After page reload you should see a text field with the DSN string. Copy it.
- ![Error Tracking Settings DSN](img/error_tracking_setting_dsn_v14_4.png)
+ ![Error Tracking Settings DSN](img/error_tracking_setting_dsn_v14_4.png)
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).
diff --git a/doc/operations/feature_flags.md b/doc/operations/feature_flags.md
index 0afba821363..fff2c8ffbf7 100644
--- a/doc/operations/feature_flags.md
+++ b/doc/operations/feature_flags.md
@@ -422,7 +422,7 @@ At the moment, the feature flag API falls into **Unauthenticated traffic (from a
in the [GitLab.com specific limits](../user/gitlab_com/index.md),
so it's **500 requests per minute**.
-Please note that the polling rate is configurable in SDKs. Provided that all clients are requesting from the same IP:
+The polling rate is configurable in SDKs. Provided that all clients are requesting from the same IP:
- Request once per minute ... 500 clients can be supported.
- Request once per 15 sec ... 125 clients can be supported.
diff --git a/doc/operations/incident_management/alerts.md b/doc/operations/incident_management/alerts.md
index 32603aa3753..d6293cf1479 100644
--- a/doc/operations/incident_management/alerts.md
+++ b/doc/operations/incident_management/alerts.md
@@ -8,7 +8,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Alerts are a critical entity in your incident management workflow. They represent a notable event that might indicate a service outage or disruption. GitLab provides a list view for triage and detail view for deeper investigation of what happened.
-## Alert List
+## Alert list
Users with at least the Developer role can
access the Alert list at **Monitor > Alerts** in your project's
@@ -103,31 +103,6 @@ When you upload an image, you can add text to the image and link it to the origi
If you add a link, it is shown above the uploaded image.
-#### View an alert's logs
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/201846) in GitLab Ultimate 12.8.
-> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/217768) in GitLab 13.3.
-> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25455) from GitLab Ultimate to GitLab Free in 12.9.
-
-Viewing logs from a metrics panel can be useful if you're triaging an
-application incident and need to [explore logs](../metrics/dashboards/index.md#chart-context-menu)
-from across your application. These logs help you understand what's affecting
-your application's performance and how to resolve any problems.
-
-Prerequisite:
-
-- You must have at least the Developer role.
-
-To view the logs for an alert:
-
-1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Monitor > Alerts**.
-1. Select the alert you want to view.
-1. Below the title of the alert, select the **Metrics** tab.
-1. Select the [menu](../metrics/dashboards/index.md#chart-context-menu) of
- the metric chart to view options.
-1. Select **View logs**.
-
### Activity feed tab
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3066) in GitLab 13.1.
@@ -137,7 +112,7 @@ timeline of the alert's investigation and assignment history.
The following actions result in a system note:
-- [Updating the status of an alert](#update-an-alerts-status)
+- [Updating the status of an alert](#change-an-alerts-status)
- [Creating an incident based on an alert](#create-an-incident-from-an-alert)
- [Assignment of an alert to a user](#assign-an-alert)
- [Escalation of an alert to on-call responders](paging.md#escalating-an-alert)
@@ -148,25 +123,55 @@ The following actions result in a system note:
There are different actions available in GitLab to help triage and respond to alerts.
-### Update an alert's status
+### Change an alert's status
+
+You can change the status of an alert.
-**Triggered** is the default status for new alerts. For users with the Developer role or higher, the
-alert status can be updated from these locations:
+The available statuses are:
-- [Alert list](#alert-list): select the status dropdown corresponding to an alert, then select an
- alternate status.
-- [Alert details page](#alert-details-page): select **Edit** in the right-hand side bar, then select
- an alternate status.
+- Triggered (default for new alerts)
+- Acknowledged
+- Resolved
+
+Prerequisites:
+
+- You must have at least the Developer role.
+
+To change an alert's status:
+
+- From the [alert list](#alert-list):
+
+ 1. In the **Status** column, next to an alert, select the status dropdown list.
+ 1. Select a status.
+
+- From the [alert details page](#alert-details-page):
+
+ 1. On the right sidebar, select **Edit**.
+ 1. Select a status.
To stop email notifications for alert reoccurrences in projects with [email notifications enabled](paging.md#email-notifications-for-alerts),
-[change the alert's status](alerts.md#update-an-alerts-status) away from **Triggered**.
+change the alert's status away from **Triggered**.
+
+#### Resolve an alert by closing the linked incident
+
+Prerequisites:
+
+- You must have at least the Reporter role.
+
+When you close an [incident](incidents.md) that is linked to an alert,
+the linked alert's status changes to **Resolved**.
+You are then credited with the alert's status change.
+
+#### As an on-call responder **(PREMIUM)**
+
+On-call responders can respond to [alert pages](paging.md#escalating-an-alert)
+by changing the alert status.
-In projects with GitLab Premium, on-call responders can respond to [alert pages](paging.md#escalating-an-alert)
-by changing the status. Setting the status to:
+Changing the status has the following effects:
-- **Resolved** silences all on-call pages for the alert.
-- **Acknowledged** limits on-call pages based on the project's [escalation policy](escalation_policies.md).
-- **Triggered** from **Resolved** restarts the alert escalating from the beginning.
+- To **Acknowledged**: limits on-call pages based on the project's [escalation policy](escalation_policies.md).
+- To **Resolved**: silences all on-call pages for the alert.
+- From **Resolved** to **Triggered**: restarts the alert escalating.
In GitLab 15.1 and earlier, updating the status of an [alert with an associated incident](alerts.md#create-an-incident-from-an-alert)
also updates the incident status. In [GitLab 15.2 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/356057),
@@ -183,7 +188,7 @@ alert by selecting the **View Issue** button.
You can also [create incidents for alerts automatically](incidents.md#create-incidents-automatically).
-Closing a GitLab issue associated with an alert [changes the alert's status](#update-an-alerts-status) to
+Closing a GitLab issue associated with an alert [changes the alert's status](#change-an-alerts-status) to
**Resolved**. See [Alert List](#alert-list) for more details
about alert statuses.
@@ -213,7 +218,7 @@ To assign an alert:
GitLab creates a [to-do item](../../user/todos.md) for each user.
After completing their portion of investigating or fixing the alert, users can
-unassign themselves from the alert. To remove an assignee, select **Edit** next to the **Assignee** dropdown menu
+unassign themselves from the alert. To remove an assignee, select **Edit** next to the **Assignee** dropdown list
and clear the user from the list of assignees, or select **Unassigned**.
### Create a to-do item from an alert
diff --git a/doc/operations/incident_management/img/timeline_event_for_severity_change_v15_6.png b/doc/operations/incident_management/img/timeline_event_for_severity_change_v15_6.png
new file mode 100644
index 00000000000..ae9d446f8b5
--- /dev/null
+++ b/doc/operations/incident_management/img/timeline_event_for_severity_change_v15_6.png
Binary files differ
diff --git a/doc/operations/incident_management/incident_timeline_events.md b/doc/operations/incident_management/incident_timeline_events.md
index 5f98335d7aa..58448222356 100644
--- a/doc/operations/incident_management/incident_timeline_events.md
+++ b/doc/operations/incident_management/incident_timeline_events.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/344059) in GitLab 15.2 [with a flag](../../administration/feature_flags.md) named `incident_timeline`. Enabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/353426) in GitLab 15.3.
-> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/353426) in GitLab 15.5. [Feature flag 'incident_timeline'](https://gitlab.com/gitlab-org/gitlab/-/issues/343386) removed.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/353426) in GitLab 15.5. [Feature flag `incident_timeline`](https://gitlab.com/gitlab-org/gitlab/-/issues/343386) removed.
Incident timelines are an important part of record keeping for incidents.
Timelines can show executives and external viewers what happened during an incident,
@@ -74,6 +74,15 @@ To create a timeline event from a comment on the incident:
The comment is shown on the incident timeline as a timeline event.
+### When incident severity changes
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375280) in GitLab 15.6.
+
+A new timeline event is created when someone [changes the severity](incidents.md#change-severity)
+of an incident.
+
+![Incident timeline event for severity change](img/timeline_event_for_severity_change_v15_6.png)
+
## Delete an event
You can also delete timeline events.
diff --git a/doc/operations/incident_management/incidents.md b/doc/operations/incident_management/incidents.md
index edbe07f166c..a5d38b1a27c 100644
--- a/doc/operations/incident_management/incidents.md
+++ b/doc/operations/incident_management/incidents.md
@@ -35,7 +35,7 @@ To create an incident from the Issues List:
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/230857) in GitLab 13.4.
1. Go to **Issues > List**, and select **New issue**.
-1. In the **Type** dropdown, select **Incident**. Only fields relevant to
+1. In the **Type** dropdown list, select **Incident**. Only fields relevant to
incidents are displayed on the page.
1. Create the incident as needed, and select **Create issue** to save the
incident.
diff --git a/doc/operations/incident_management/integrations.md b/doc/operations/incident_management/integrations.md
index ae6ffe549d5..a54556bd3a2 100644
--- a/doc/operations/incident_management/integrations.md
+++ b/doc/operations/incident_management/integrations.md
@@ -36,7 +36,7 @@ receive alert payloads in JSON format. You can always
1. Sign in to GitLab as a user with the Maintainer role
for a project.
1. Navigate to **Settings > Monitor** in your project.
-1. Expand the **Alerts** section, and in the **Select integration type** dropdown menu,
+1. Expand the **Alerts** section, and in the **Select integration type** dropdown list,
select **HTTP Endpoint**.
1. Toggle the **Active** alert setting. The URL and Authorization Key for the webhook configuration
are available in the **View credentials** tab after you save the integration. You must also input
@@ -57,7 +57,7 @@ and you can [customize the payload](#customize-the-alert-payload-outside-of-gitl
1. For each endpoint you want to create:
1. Select **Add new integration**.
- 1. In the **Select integration type** dropdown menu, select **HTTP Endpoint**.
+ 1. In the **Select integration type** dropdown list, select **HTTP Endpoint**.
1. Name the integration.
1. Toggle the **Active** alert setting. The **URL** and **Authorization Key** for the webhook
configuration are available in the **View credentials** tab after you save the integration.
diff --git a/doc/operations/incident_management/linked_resources.md b/doc/operations/incident_management/linked_resources.md
index 4c3ef34f634..a7be867608b 100644
--- a/doc/operations/incident_management/linked_resources.md
+++ b/doc/operations/incident_management/linked_resources.md
@@ -6,11 +6,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Linked resources in incidents **(PREMIUM)**
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/230852) in GitLab 15.3 [with a flag](../../administration/feature_flags.md) named `incident_resource_links_widget`. Enabled on GitLab.com. Disabled on self-managed.
-
-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_resource_links_widget`.
-On GitLab.com, this feature is available.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/230852) in GitLab 15.3 [with a flag](../../administration/feature_flags.md) named `incident_resource_links_widget`. Disabled by default.
+> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/364755) in GitLab 15.3.
+> - [Generally available](ihttps://gitlab.com/gitlab-org/gitlab/-/issues/364755) in GitLab 15.5. Feature flag `incident_resource_links_widget` removed.
To help your team members find the important links without having to search through many comments,
you can add linked resources to an incident issue.
diff --git a/doc/operations/incident_management/paging.md b/doc/operations/incident_management/paging.md
index 55e1c9dfbcc..dcb17048d35 100644
--- a/doc/operations/incident_management/paging.md
+++ b/doc/operations/incident_management/paging.md
@@ -34,7 +34,7 @@ a single email notification for new alerts.
**Send a single email notification to Owners and Maintainers for new alerts** checkbox.
1. Select **Save changes**.
-[Update the alert's status](alerts.md#update-an-alerts-status) to manage email notifications for an alert.
+[Update the alert's status](alerts.md#change-an-alerts-status) to manage email notifications for an alert.
## Paging **(PREMIUM)**
@@ -46,7 +46,7 @@ can be automatically paged about critical problems through email.
When an alert is triggered, it begins escalating to the on-call responders immediately.
For each escalation rule in the project's escalation policy, the designated on-call
responders receive one email when the rule fires. You can respond to a page
-or stop alert escalations by [updating the alert's status](alerts.md#update-an-alerts-status).
+or stop alert escalations by [updating the alert's status](alerts.md#change-an-alerts-status).
### Escalating an incident
diff --git a/doc/operations/index.md b/doc/operations/index.md
index 4f0d843f66e..ff13c617ea7 100644
--- a/doc/operations/index.md
+++ b/doc/operations/index.md
@@ -57,35 +57,6 @@ and the work required to fix them - all without leaving GitLab.
- Discover and view errors generated by your applications with
[Error Tracking](error_tracking.md).
-## Trace application health and performance (DEPRECATED)
-
-> [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346485) in GitLab 14.7.
-
-WARNING:
-This feature is in its end-of-life process. It is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346485)
-in GitLab 14.7, and is planned for removal in GitLab 15.0.
-
-Application tracing in GitLab is a way to measure an application's performance and
-health while it's running. After configuring your application to enable tracing, you
-gain in-depth insight into your application's layers. With application tracing,
-you can measure the execution time of a user journey for troubleshooting or
-optimization purposes.
-
-GitLab integrates with [Jaeger](https://www.jaegertracing.io/) - an open-source,
-end-to-end distributed tracing system tool used for monitoring and troubleshooting
-microservices-based distributed systems - and displays results within GitLab.
-
-- [Trace the performance and health](tracing.md) of a deployed application.
-
-<!--- start_remove The following content will be removed on remove_date: '2022-10-18'--->
-
-## Aggregate and store logs (removed) **(FREE SELF)**
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346485) in GitLab 14.7
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/360193) in GitLab 15.2.
-
-<!--- end_remove -->
-
## Manage your infrastructure in code
GitLab stores and executes your infrastructure as code, whether it's
@@ -105,5 +76,4 @@ an environment.
- Deploy to different [environments](../ci/environments/index.md).
- Connect your project to a [Kubernetes cluster](../user/infrastructure/clusters/index.md).
-- See how your application is used and analyze events with [Product Analytics](product_analytics.md).
- Create, toggle, and remove [Feature Flags](feature_flags.md).
diff --git a/doc/operations/metrics/dashboards/index.md b/doc/operations/metrics/dashboards/index.md
index 4e0b50d1e04..aef9bcb4b22 100644
--- a/doc/operations/metrics/dashboards/index.md
+++ b/doc/operations/metrics/dashboards/index.md
@@ -66,7 +66,7 @@ To create a new dashboard from the command line:
1. Save the file, commit, and push to your repository. The file must be present in your **default** branch.
1. Navigate to your project's **Monitor > Metrics** and choose the custom
- dashboard from the dropdown.
+ dashboard from the dropdown list.
Your custom dashboard is available at `https://example.com/project/-/metrics/custom_dashboard_name.yml`.
@@ -125,7 +125,7 @@ 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 box above the upper right corner of
+**{ellipsis_v}** **More actions** dropdown list above the upper right corner of
any chart on a dashboard:
![Context Menu](img/panel_context_menu_v14_0.png)
diff --git a/doc/operations/metrics/dashboards/templating_variables.md b/doc/operations/metrics/dashboards/templating_variables.md
index aac22236dc7..a1c2ce063bc 100644
--- a/doc/operations/metrics/dashboards/templating_variables.md
+++ b/doc/operations/metrics/dashboards/templating_variables.md
@@ -67,7 +67,7 @@ WARNING:
This variable type is an [Alpha](../../../policy/alpha-beta-support.md#alpha-features) feature, and is subject to change at any time
without prior notice!
-Each `custom` variable defined in the dashboard YAML creates a dropdown
+Each `custom` variable defined in the dashboard YAML creates a dropdown list
selector on the dashboard UI, allowing you to select a value for each variable.
The `custom` variable type supports a simple and a full syntax.
@@ -75,7 +75,7 @@ The `custom` variable type supports a simple and a full syntax.
### Simple syntax
This example creates a variable called `variable1`, with a default value of `value1`.
-The dashboard UI displays a dropdown with `value1`, `value2` and `value3`
+The dashboard UI displays a dropdown list with `value1`, `value2` and `value3`
as the choices.
```yaml
@@ -88,10 +88,10 @@ templating:
This example creates a variable called `variable1`, with a default value of `value_option_2`.
The label for the text box on the UI is the value of the `label` key.
-The dashboard UI displays a dropdown with `Option 1` and `Option 2`
+The dashboard UI displays a dropdown list with `Option 1` and `Option 2`
as the choices.
-If you select `Option 1` from the dropdown, the variable is replaced with `value option 1`.
+If you select `Option 1` from the dropdown list, the variable is replaced with `value option 1`.
Similarly, if you select `Option 2`, the variable is replaced with `value_option_2`:
```yaml
@@ -117,7 +117,7 @@ without prior notice!
### Full syntax
-This example creates a variable called `variable2`. The values of the dropdown are
+This example creates a variable called `variable2`. The values of the dropdown list are
all the different values of the `backend` label in the Prometheus series described by
`up{env="production"}`.
diff --git a/doc/operations/metrics/index.md b/doc/operations/metrics/index.md
index 3e5ea688fde..3c2790a96b7 100644
--- a/doc/operations/metrics/index.md
+++ b/doc/operations/metrics/index.md
@@ -148,7 +148,7 @@ suggested if this feature is used.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/208976) in GitLab 12.9.
You can edit existing additional custom metrics for your dashboard by selecting the
-**{ellipsis_v}** **More actions** dropdown and selecting **Edit metric**.
+**{ellipsis_v}** **More actions** dropdown list and selecting **Edit metric**.
![Edit metric](img/prometheus_dashboard_edit_metric_link_v_12_9.png)
@@ -158,7 +158,7 @@ You can edit existing additional custom metrics for your dashboard by selecting
You can use keyboard shortcuts to interact more quickly with your currently-focused
chart panel. To activate keyboard shortcuts, use keyboard tabs to highlight the
-**{ellipsis_v}** **More actions** dropdown menu, or hover over the dropdown menu
+**{ellipsis_v}** **More actions** dropdown list, or hover over the dropdown list
with your mouse, then press the key corresponding to your desired action:
- **Expand panel** - <kbd>e</kbd>
diff --git a/doc/operations/product_analytics.md b/doc/operations/product_analytics.md
deleted file mode 100644
index f9b92f61fd2..00000000000
--- a/doc/operations/product_analytics.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-stage: Analytics
-group: Product Analytics
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
----
-
-# Product Analytics **(FREE)**
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225167) in GitLab 13.3 [with a flag](../administration/feature_flags.md) named `product_analytics`. Disabled by default.
-
-FLAG:
-On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../administration/feature_flags.md) named `product_analytics`. On GitLab.com, this feature is not available. The feature is not ready for production use.
-
-GitLab enables you to go from planning an application to getting feedback. You can use
-Product Analytics to receive and analyze events sent from your application. This analysis
-provides observability information and feedback on how people use your product.
-
-Events are collected by a [Rails collector](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36443) and
-then processed with [Snowplow](https://github.com/snowplow/snowplow). Events are stored in a GitLab database.
-
-## View Product Analytics
-
-You can view the event data collected about your applications.
-
-Prerequisite:
-
-- You must have at least the Reporter role.
-
-To access Product Analytics:
-
-1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Monitor > Product Analytics**.
-
-The Product Analytics interface contains:
-
-- An Events tab that shows the recent events and a total count.
-- A Graph tab that shows graphs based on events of the last 30 days.
-- A Test tab that sends a sample event payload.
-- A Setup page containing the code to implement in your application.
-
-## Rate limits
-
-While Product Analytics is under development, it's rate-limited to
-**100 events per minute** per project. This limit prevents the events table in the
-database from growing too quickly.
diff --git a/doc/operations/tracing.md b/doc/operations/tracing.md
index 64d8f8a8707..b3c0763bbbc 100644
--- a/doc/operations/tracing.md
+++ b/doc/operations/tracing.md
@@ -2,50 +2,13 @@
stage: Monitor
group: Respond
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+remove_date: '2022-11-01'
+redirect_to: 'index.md'
---
-# Tracing (DEPRECATED) **(FREE SELF)**
+# Tracing (removed) **(FREE SELF)**
-> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/42645) from GitLab Ultimate to GitLab Free in 13.5.
-> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346540) in GitLab 14.7.
-> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/359904) behind a [feature flag](../administration/feature_flags.md) named `monitor_tracing` in GitLab 15.0. Disabled by default.
-
-WARNING:
-This feature is in its end-of-life process. It is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346540)
-in GitLab 14.7.
-It will be removed completely in GitLab 15.2.
-
-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 `monitor_tracing`.
-On GitLab.com, this feature is not available.
-This feature is not recommended for production use.
-
-Tracing provides insight into the performance and health of a deployed application, tracking each
-function or microservice that handles a given request. Tracing makes it easy to understand the
-end-to-end flow of a request, regardless of whether you are using a monolithic or distributed
-system.
-
-## Install Jaeger
-
-[Jaeger](https://www.jaegertracing.io/) is an open source, end-to-end distributed tracing system
-used for monitoring and troubleshooting microservices-based distributed systems. To learn more about
-installing Jaeger, read the official
-[Getting Started documentation](https://www.jaegertracing.io/docs/latest/getting-started/).
-
-See also:
-
-- An [all-in-one Docker image](https://www.jaegertracing.io/docs/latest/getting-started/#all-in-one).
-- Deployment options for:
- - [Kubernetes](https://github.com/jaegertracing/jaeger-kubernetes).
- - [OpenShift](https://github.com/jaegertracing/jaeger-openshift).
-
-## Link to Jaeger
-
-GitLab provides an easy way to open the Jaeger UI from within your project:
-
-1. [Set up Jaeger](https://www.jaegertracing.io) and configure your application using one of the
- [client libraries](https://www.jaegertracing.io/docs/latest/client-libraries/).
-1. Navigate to your project's **Settings > Monitor** and provide the Jaeger URL.
-1. Select **Save changes** for the changes to take effect.
-1. You can now visit **Monitor > Tracing** in your project's sidebar and GitLab redirects you to
- the configured Jaeger URL.
+This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/346540) in GitLab 14.7
+and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/346540) in GitLab 15.2.
+We are working on an alternative to replace tracing.
+To learn more, visit the [Observability direction page](https://about.gitlab.com/direction/monitor/observability/).
diff --git a/doc/raketasks/backup_gitlab.md b/doc/raketasks/backup_gitlab.md
index da004a1b774..47696fc1f99 100644
--- a/doc/raketasks/backup_gitlab.md
+++ b/doc/raketasks/backup_gitlab.md
@@ -139,7 +139,7 @@ For installation from source:
- `/home/git/gitlab/config/secrets.yml`
- `/home/git/gitlab/config/gitlab.yml`
-For [Docker installations](https://docs.gitlab.com/omnibus/docker/), you must
+For [Docker installations](../install/docker.md), you must
back up the volume where the configuration files are stored. If you created
the GitLab container according to the documentation, it should be in the
`/srv/gitlab/config` directory.
diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md
index 2fa6fc2e564..a67fec26a9b 100644
--- a/doc/raketasks/cleanup.md
+++ b/doc/raketasks/cleanup.md
@@ -152,6 +152,12 @@ NOTE:
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)
+[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.
+
When you notice there are more job artifacts files and/or directories on disk than there
should be, you can run:
diff --git a/doc/raketasks/index.md b/doc/raketasks/index.md
index 12d2d8b101a..4a157688a41 100644
--- a/doc/raketasks/index.md
+++ b/doc/raketasks/index.md
@@ -46,7 +46,7 @@ The following Rake tasks are available for use with GitLab:
| [Reset user passwords](../security/reset_user_password.md#use-a-rake-task) | Reset user passwords using Rake. |
| [Uploads migrate](../administration/raketasks/uploads/migrate.md) | Migrate uploads between local storage and object storage. |
| [Uploads sanitize](../administration/raketasks/uploads/sanitize.md) | Remove EXIF data from images uploaded to earlier versions of GitLab. |
-| [Service Data](../administration/troubleshooting/gitlab_rails_cheat_sheet.md#generate-service-ping) | Generate and troubleshoot [Service Ping](../development/service_ping/index.md). |
+| [Service Data](../development/service_ping/troubleshooting.md#generate-service-ping) | Generate and troubleshoot [Service Ping](../development/service_ping/index.md). |
| [User management](user_management.md) | Perform user management tasks. |
| [Webhooks administration](web_hooks.md) | Maintain project webhooks. |
| [X.509 signatures](x509_signatures.md) | Update X.509 commit signatures, which can be useful if the certificate store changed. |
diff --git a/doc/security/crime_vulnerability.md b/doc/security/crime_vulnerability.md
index e2aa4b5d4ab..463ccb7b629 100644
--- a/doc/security/crime_vulnerability.md
+++ b/doc/security/crime_vulnerability.md
@@ -70,6 +70,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/security/index.md b/doc/security/index.md
index ff0769e0d93..38eb5337f5a 100644
--- a/doc/security/index.md
+++ b/doc/security/index.md
@@ -6,7 +6,7 @@ comments: false
type: index
---
-# Security **(FREE)**
+# Secure your installation **(FREE)**
- [Passwords and OAuth tokens storage](password_storage.md)
- [Password length limits](password_length_limits.md)
diff --git a/doc/security/information_exclusivity.md b/doc/security/information_exclusivity.md
index 37a9fdfdd81..16facadd782 100644
--- a/doc/security/information_exclusivity.md
+++ b/doc/security/information_exclusivity.md
@@ -35,6 +35,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/security/password_length_limits.md b/doc/security/password_length_limits.md
index fe51022eea7..0211a326e0a 100644
--- a/doc/security/password_length_limits.md
+++ b/doc/security/password_length_limits.md
@@ -12,17 +12,11 @@ By default, GitLab supports passwords with the following lengths:
- Minimum: 8 characters
- Maximum: 128 characters
-GitLab administrators can modify password lengths:
+You can only change the minimum password length. Changing the minimum length does not affect existing user passwords.
+Existing users are not asked to reset their password to adhere to the new limits. The new limit restriction applies only
+during new user sign-ups and when an existing user performs a password reset.
-- Using the GitLab UI. [From](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20661) GitLab
- 12.6, this is the only available option.
-- Using configuration file. Up to GitLab 12.5.
-
-Changing the minimum or maximum length does not affect existing user passwords. Existing users are
-not asked to reset their password to adhere to the new limits. The new limit restriction applies
-only during new user sign-ups and when an existing user performs a password reset.
-
-## Modify minimum password length using GitLab UI
+## Modify minimum password length
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20661) in GitLab 12.6
@@ -32,39 +26,9 @@ To change the minimum password length using GitLab UI:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > General** and expand **Sign-up restrictions**.
-
- ![Minimum password length settings](../user/admin_area/img/minimum_password_length_settings_v12_6.png)
-
1. Enter a **Minimum password length** value greater than or equal to `8`.
1. Select **Save changes**.
-## Modify maximum password length using configuration file
-
-From GitLab 12.6, the minimum password length set in this configuration file is ignored. Minimum password lengths must instead be modified via the [GitLab UI](#modify-minimum-password-length-using-gitlab-ui).
-
-The user password length is set to a maximum of 128 characters by default.
-To change that for installations from source:
-
-1. Edit `devise_password_length.rb`:
-
- ```shell
- cd /home/git/gitlab
- sudo -u git -H cp config/initializers/devise_password_length.rb.example config/initializers/devise_password_length.rb
- sudo -u git -H editor config/initializers/devise_password_length.rb
- ```
-
-1. Change the new password length limits:
-
- ```ruby
- config.password_length = 12..135
- ```
-
- In this example, the minimum length is 12 characters, and the maximum length
- is 135 characters.
-
-1. [Restart GitLab](../administration/restart_gitlab.md#installations-from-source)
- for the changes to take effect.
-
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
@@ -73,6 +37,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/security/password_storage.md b/doc/security/password_storage.md
index 6b20f8619ae..bd514de6e2c 100644
--- a/doc/security/password_storage.md
+++ b/doc/security/password_storage.md
@@ -11,7 +11,8 @@ GitLab administrators can configure how passwords and OAuth tokens are stored.
## Password storage
-> PBKDF2 and SHA512 [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/360658) in GitLab 15.2 [with flags](../administration/feature_flags.md) named `pbkdf2_password_encryption` and `pbkdf2_password_encryption_write`. Disabled by default.
+> - PBKDF2+SHA512 [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/360658) in GitLab 15.2 [with flags](../administration/feature_flags.md) named `pbkdf2_password_encryption` and `pbkdf2_password_encryption_write`. Disabled by default.
+> - Feature flags [removed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/101691) in GitLab 15.6 and PBKDF2+SHA512 was made available to all GitLab instances running in [FIPS mode](../development/fips_compliance.md).
GitLab stores user passwords in a hashed format to prevent passwords from being
stored as plain text.
@@ -23,17 +24,9 @@ library to hash user passwords. Created password hashes have these attributes:
- **BCrypt**: By default, the [`bcrypt`](https://en.wikipedia.org/wiki/Bcrypt) hashing
function is used to generate the hash of the provided password. This cryptographic hashing function is
strong and industry-standard.
- - **PBKDF2 and SHA512**: Starting in GitLab 15.2, PBKDF2 and SHA512 are supported
- behind the following feature flags (disabled by default):
- - `pbkdf2_password_encryption` - Enables reading and comparison of PBKDF2 + SHA512
- hashed passwords and supports fallback for BCrypt hashed passwords.
- - `pbkdf2_password_encryption_write` - Enables new passwords to be saved
- using PBKDF2 and SHA512, and existing BCrypt passwords to be migrated when users sign in.
-
- FLAG:
- On self-managed GitLab, by default this feature is not available. To make it available,
- ask an administrator to [enable the feature flags](../administration/feature_flags.md) named `pbkdf2_password_encryption` and `pbkdf2_password_encryption_write`.
-
+ - **PBKDF2+SHA512**: PBKDF2+SHA512 is supported:
+ - In GitLab 15.2 to GitLab 15.5 when `pbkdf2_password_encryption` and `pbkdf2_password_encryption_write` [feature flags](../administration/feature_flags.md) are enabled.
+ - In GitLab 15.6 and later when [FIPS mode](../development/fips_compliance.md) is enabled (feature flags are not required).
- **Stretching**: Password hashes are [stretched](https://en.wikipedia.org/wiki/Key_stretching)
to harden against brute-force attacks. By default, GitLab uses a stretching
factor of 10 for BCrypt and 20,000 for PBKDF2 + SHA512.
@@ -45,9 +38,7 @@ library to hash user passwords. Created password hashes have these attributes:
## OAuth access token storage
> - PBKDF2+SHA512 [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/364110) in GitLab 15.3 [with flag](../administration/feature_flags.md) named `hash_oauth_tokens`.
-> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98242) in GitLab 15.5.
-
-Depending on your version of GitLab and configuration, OAuth access tokens are stored in the database in PBKDF2+SHA512 format. For version information, see
-the relevant [OAuth provider documentation](../integration/oauth_provider.md#hashed-oauth-tokens).
+> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/367570) in GitLab 15.5.
+> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/367570) in GitLab 15.6.
-As with PBKDF2+SHA512 password storage, access token values are [stretched](https://en.wikipedia.org/wiki/Key_stretching) 20,000 times to harden against brute-force attacks.
+OAuth access tokens are stored in the database in PBKDF2+SHA512 format. As with PBKDF2+SHA512 password storage, access token values are [stretched](https://en.wikipedia.org/wiki/Key_stretching) 20,000 times to harden against brute-force attacks.
diff --git a/doc/security/passwords_for_integrated_authentication_methods.md b/doc/security/passwords_for_integrated_authentication_methods.md
index 961d147871e..68fb097ab9a 100644
--- a/doc/security/passwords_for_integrated_authentication_methods.md
+++ b/doc/security/passwords_for_integrated_authentication_methods.md
@@ -14,4 +14,4 @@ However, to maintain data consistency, GitLab requires passwords for all user ac
For such accounts, we use the [`friendly_token`](https://github.com/heartcombo/devise/blob/f26e05c20079c9acded3c0ee16da0df435a28997/lib/devise.rb#L492) method provided by the Devise gem to generate a random, unique and secure password and sets it as the account password during sign up.
-The length of the generated password is the set based on the value of [maximum password length](password_length_limits.md#modify-maximum-password-length-using-configuration-file) as set in the Device configuration. The default value is 128 characters.
+The length of the generated password is [128 characters](password_length_limits.md).
diff --git a/doc/security/ssh_keys_restrictions.md b/doc/security/ssh_keys_restrictions.md
index 5a8450bb8e7..f15d71461d4 100644
--- a/doc/security/ssh_keys_restrictions.md
+++ b/doc/security/ssh_keys_restrictions.md
@@ -71,6 +71,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/security/two_factor_authentication.md b/doc/security/two_factor_authentication.md
index cc06e824d14..95915c4e03b 100644
--- a/doc/security/two_factor_authentication.md
+++ b/doc/security/two_factor_authentication.md
@@ -99,11 +99,13 @@ This is a permanent and irreversible action. Users must reactivate 2FA to use it
### For a single user
-To disable 2FA for non-administrator users, we recommend using the [API endpoint](../api/users.md#disable-two-factor-authentication)
+To disable 2FA for non-administrator users, you should use the [API endpoint](../api/users.md#disable-two-factor-authentication)
instead of the Rails console.
Using the [Rails console](../administration/operations/rails_console.md), 2FA for a single user can be disabled.
Connect to the Rails console and run:
+**In GitLab 13.5 and later:**
+
```ruby
admin = User.find_by_username('<USERNAME>')
user_to_disable = User.find_by_username('<USERNAME>')
@@ -111,6 +113,8 @@ user_to_disable = User.find_by_username('<USERNAME>')
TwoFactor::DestroyService.new(admin, user: user_to_disable).execute
```
+The target user is notified that 2FA has been disabled.
+
### For all users
There may be some special situations where you want to disable 2FA for everyone
@@ -167,6 +171,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/security/unlock_user.md b/doc/security/unlock_user.md
index 4eded22ddaa..9a1f60f2462 100644
--- a/doc/security/unlock_user.md
+++ b/doc/security/unlock_user.md
@@ -17,7 +17,7 @@ Users are locked after ten failed sign-in attempts. These users remain locked:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Overview > Users**.
1. Use the search bar to find the locked user.
-1. From the **User administration** dropdown select **Unlock**.
+1. From the **User administration** dropdown list select **Unlock**.
![Unlock a user from the Admin Area](img/unlock_user_v14_7.png)
@@ -66,6 +66,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/security/user_email_confirmation.md b/doc/security/user_email_confirmation.md
index 3f7c66b311b..ffc537c8f10 100644
--- a/doc/security/user_email_confirmation.md
+++ b/doc/security/user_email_confirmation.md
@@ -28,6 +28,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/security/user_file_uploads.md b/doc/security/user_file_uploads.md
index 63a5e51e3b5..db2948a8bd5 100644
--- a/doc/security/user_file_uploads.md
+++ b/doc/security/user_file_uploads.md
@@ -53,6 +53,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/security/webhooks.md b/doc/security/webhooks.md
index 49ab4215ea5..eeb6720dfb7 100644
--- a/doc/security/webhooks.md
+++ b/doc/security/webhooks.md
@@ -99,6 +99,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/subscriptions/gitlab_com/index.md b/doc/subscriptions/gitlab_com/index.md
index c9b066144f3..6f1bf0df044 100644
--- a/doc/subscriptions/gitlab_com/index.md
+++ b/doc/subscriptions/gitlab_com/index.md
@@ -29,7 +29,7 @@ Members of every subgroup and project in the group:
To subscribe to GitLab SaaS:
-1. View the [GitLab SaaS feature comparison](https://about.gitlab.com/pricing/gitlab-com/feature-comparison/)
+1. View the [GitLab SaaS feature comparison](https://about.gitlab.com/pricing/feature-comparison/)
and decide which tier you want.
1. Create a user account for yourself by using the
[sign up page](https://gitlab.com/users/sign_up).
@@ -190,6 +190,30 @@ If you add a member to a group by using the [share a group with another group](.
- Remove the member from the shared group. You must be a group owner to do this.
- From the group's membership page, remove access from the entire shared group.
+## Seat usage alerts
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/348481) in GitLab 15.2 [with a flag](../../administration/feature_flags.md) named `seat_flag_alerts`.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/362041) in GitLab 15.4. Feature flag `seat_flag_alerts` removed.
+
+If you have the Owner role of the top-level group, an alert notifies you
+of your total seat usage.
+
+The alert displays on group, subgroup, and project
+pages, and only for top-level groups linked to subscriptions enrolled
+in [quarterly subscription reconciliations](../quarterly_reconciliation.md).
+After you dismiss the alert, it doesn't display until another seat is used.
+
+The alert displays based on the following seat usage. You cannot configure the
+amounts at which the alert displays.
+
+| Seats in subscription | Seat usage |
+|-----------------------|------------------------------------------------------------------------|
+| 0-15 | One seat remaining in the subscription. |
+| 16-25 | Two seats remaining in the subscription. |
+| 26-99 | 10% of seats have been used. |
+| 100-999 | 8% of seats have been used. |
+| 1000+ | 5% of seats have been used |
+
## Upgrade your GitLab SaaS subscription tier
To upgrade your [GitLab tier](https://about.gitlab.com/pricing/):
@@ -309,6 +333,10 @@ locked. Projects can only be unlocked by purchasing more storage subscription un
### Purchase more storage and transfer
+Prerequisite:
+
+- You must have at least the Owner role.
+
You can purchase a storage subscription for your personal or group namespace.
NOTE:
@@ -324,9 +352,9 @@ You can [cancel the subscription](#enable-or-disable-automatic-subscription-rene
1. Select **Purchase more storage** and you are taken to the Customers Portal.
1. Select **Add new subscription**.
1. Scroll to **Purchase add-on subscriptions** and select **Buy storage subscription**.
-1. In the **Subscription details** section select the name of the user or group from the dropdown.
+1. In the **Subscription details** section select the name of the user or group from the dropdown list.
1. Enter the desired quantity of storage packs.
-1. In the **Billing information** section select the payment method from the dropdown.
+1. In the **Billing information** section select the payment method from the dropdown list.
1. Select the **Privacy Policy** and **Terms of Service** checkbox.
1. Select **Buy subscription**.
1. Sign out of the Customers Portal.
@@ -388,3 +416,8 @@ If your credit card is declined when purchasing a GitLab subscription, possible
Check with your financial institution to confirm if any of these reasons apply. If they don't
apply, contact [GitLab Support](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=360000071293).
+
+### Unable to link subcription to namespace
+
+If you cannot link a subscription to your namespace, ensure that you have the Owner role
+for that namespace.
diff --git a/doc/subscriptions/gitlab_dedicated/index.md b/doc/subscriptions/gitlab_dedicated/index.md
index 441a4d2aa30..c503c501eeb 100644
--- a/doc/subscriptions/gitlab_dedicated/index.md
+++ b/doc/subscriptions/gitlab_dedicated/index.md
@@ -30,7 +30,7 @@ GitLab Dedicated enables you to offload the operational overhead of managing the
- 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/self-managed/feature-comparison/) with the exception of the unsupported features [listed below](#features-that-are-not-available).
+- 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).
## Features that are not available
diff --git a/doc/subscriptions/index.md b/doc/subscriptions/index.md
index 1df222ac349..47c1f730746 100644
--- a/doc/subscriptions/index.md
+++ b/doc/subscriptions/index.md
@@ -77,6 +77,8 @@ With the [Customers Portal](https://customers.gitlab.com/) you can:
- [Change the namespace the subscription is linked to](#change-the-linked-namespace)
- [Change customers portal account password](#change-customers-portal-account-password)
+The Customers Portal is available only to customers who purchased their subscription from GitLab. If you made your purchase through a partner or reseller, you must contact them directly for assistance with your subscription.
+
### Change account owner information
Account owner personal details are used on invoices. The account owner email
@@ -151,11 +153,15 @@ To change the namespace linked to a subscription:
[linked](#change-the-linked-account) GitLab SaaS account.
1. Navigate to the **Manage Purchases** page.
1. Select **Change linked namespace**.
-1. Select the desired group from the **This subscription is for** dropdown. For a group to appear
- here, you must have the Owner role
- for that group.
+1. Select the desired group from the **Select user or group** dropdown list. For a group to appear
+ here, you must have the Owner role for that group.
1. Select **Proceed to checkout**.
+If the group you want to link does not appear in the dropdown list, check:
+
+- You have [linked your Customers Portal account with your GitLab.com account](#change-the-linked-account).
+- That the linked account is a member of the group you want to select, and you are assigned the Owner role.
+
Subscription charges are calculated based on the total number of users in a group, including its subgroups and nested projects. If the [total number of users](gitlab_com/index.md#view-seat-usage) exceeds the number of seats in your subscription, your account is charged for the additional users and you need to pay for the overage before you can change the linked namespace.
Only one namespace can be linked to a subscription.
@@ -177,7 +183,7 @@ For qualifying non-profit educational institutions, the [GitLab for Education Pr
### GitLab for Open Source
-For qualifying open source projects, the [GitLab for Open Source Program](https://about.gitlab.com/solutions/open-source/) provides GitLab Ultimate, plus 50,000 CI/CD minutes per month. For more information—including instructions for applying to the program and renewing program membership—see the [GitLab for Open Source Program page](https://about.gitlab.com/solutions/open-source/) and the [GitLab handbook](https://about.gitlab.com/handbook/marketing/community-relations/opensource-program/).
+For qualifying open source projects, the [GitLab for Open Source Program](https://about.gitlab.com/solutions/open-source/) provides GitLab Ultimate, plus 50,000 CI/CD minutes per month. For more information—including instructions for applying to the program and renewing program membership—see the [GitLab for Open Source Program page](https://about.gitlab.com/solutions/open-source/) and the [GitLab handbook](https://about.gitlab.com/handbook/marketing/community-relations/community-programs/opensource-program/).
#### Meeting GitLab for Open Source Program requirements
@@ -238,7 +244,7 @@ Exceptions to this public visibility requirement apply in select circumstances (
### GitLab for Startups
-For qualifying startups, the [GitLab for Startups](https://about.gitlab.com/solutions/startups/) program provides GitLab Ultimate, plus 50,000 CI/CD minutes per month for 12 months. For more information—including instructions for applying to the program and renewing program membership—see the [GitLab for Startups Program page](https://about.gitlab.com/solutions/startups/) and the [GitLab handbook](https://about.gitlab.com/handbook/marketing/community-relations/startups-program/).
+For qualifying startups, the [GitLab for Startups](https://about.gitlab.com/solutions/startups/) program provides GitLab Ultimate, plus 50,000 CI/CD minutes per month for 12 months. For more information—including instructions for applying to the program and renewing program membership—see the [GitLab for Startups Program page](https://about.gitlab.com/solutions/startups/) and the [GitLab handbook](https://about.gitlab.com/handbook/marketing/community-relations/community-programs/startups-program/).
## Contact Support
@@ -259,6 +265,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/subscriptions/self_managed/index.md b/doc/subscriptions/self_managed/index.md
index 4538e8587c9..c4110fe4638 100644
--- a/doc/subscriptions/self_managed/index.md
+++ b/doc/subscriptions/self_managed/index.md
@@ -33,7 +33,7 @@ The cost of a GitLab self-managed subscription is determined by the following:
Pricing is [tier-based](https://about.gitlab.com/pricing/), so you can choose
the features that fit your budget. For information on the features available
for each tier, see the
-[GitLab self-managed feature comparison](https://about.gitlab.com/pricing/self-managed/feature-comparison/).
+[GitLab self-managed feature comparison](https://about.gitlab.com/pricing/feature-comparison/).
## Subscription seats
@@ -212,7 +212,7 @@ Example of a license sync request:
### Troubleshoot automatic subscription sync
If the sync job is not working, ensure you allow network traffic from your GitLab instance
-to IP address `104.18.26.123:443` (`customers.gitlab.com`).
+to IP addresses `172.64.146.11:443` and `104.18.41.245:443` (`customers.gitlab.com`).
## Manually sync your subscription details
@@ -460,3 +460,38 @@ If your credit card is declined when purchasing a GitLab subscription, possible
Check with your financial institution to confirm if any of these reasons apply. If they don't
apply, contact [GitLab Support](https://support.gitlab.com/hc/en-us/requests/new?ticket_form_id=360000071293).
+
+### Check daily and historical billable users
+
+Administrators can get a list of daily and historical billable users in your GitLab instance.
+
+1. [Start a Rails console session](../../administration/operations/rails_console.md#starting-a-rails-console-session).
+1. Count the number of users in the instance:
+
+ ```ruby
+ User.billable.count
+ ```
+
+1. Get the historical maximum number of users on the instance from the past year:
+
+ ```ruby
+ ::HistoricalData.max_historical_user_count(from: 1.year.ago.beginning_of_day, to: Time.current.end_of_day)
+ ```
+
+### Update daily billable and historical users
+
+Administrators can trigger a manual update of the daily and historical billable users in your GitLab instance.
+
+1. [Start a Rails console session](../../administration/operations/rails_console.md#starting-a-rails-console-session).
+1. Force an update of the daily billable users:
+
+ ```ruby
+ identifier = Analytics::UsageTrends::Measurement.identifiers[:billable_users]
+ ::Analytics::UsageTrends::CounterJobWorker.new.perform(identifier, User.minimum(:id), User.maximum(:id), Time.zone.now)
+ ```
+
+1. Force an update of the historical max billable users:
+
+ ```ruby
+ ::HistoricalDataWorker.new.perform
+ ```
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 56f3de528b8..8a041b08a4d 100644
--- a/doc/topics/autodevops/cloud_deployments/auto_devops_with_gke.md
+++ b/doc/topics/autodevops/cloud_deployments/auto_devops_with_gke.md
@@ -101,13 +101,12 @@ or manually with Google Cloud Shell:
1. After the Cloud Shell starts, run these commands to install NGINX Ingress Controller:
```shell
- kubectl create ns gitlab-managed-apps
- helm repo add stable https://charts.helm.sh/stable
- helm repo update
- helm install ingress stable/nginx-ingress -n gitlab-managed-apps
+ 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-ingress-controller -n gitlab-managed-apps
+ kubectl get service ingress-nginx-controller -n gitlab-managed-apps
```
## Configure Auto DevOps
@@ -118,7 +117,7 @@ Follow these steps to configure the base domain and other settings required for
get the external IP address with the following command:
```shell
- kubectl get service ingress-nginx-ingress-controller -n gitlab-managed-apps -ojson | jq -r '.status.loadBalancer.ingress[].ip'
+ kubectl get service ingress-nginx-controller -n gitlab-managed-apps -ojson | jq -r '.status.loadBalancer.ingress[].ip'
```
Replace `gitlab-managed-apps` if you have overwritten your namespace.
diff --git a/doc/topics/autodevops/customize.md b/doc/topics/autodevops/customize.md
index 0d4afc3c464..264ac790453 100644
--- a/doc/topics/autodevops/customize.md
+++ b/doc/topics/autodevops/customize.md
@@ -159,7 +159,7 @@ to `CI_COMMIT_SHA,CI_ENVIRONMENT_NAME`.
```
When `AUTO_DEVOPS_BUILD_IMAGE_FORWARDED_CI_VARIABLES` is set, Auto DevOps
-enables the experimental [Docker BuildKit](https://docs.docker.com/develop/develop-images/build_enhancements/)
+enables the experimental [Docker BuildKit](https://docs.docker.com/build/buildkit/)
feature to use the `--secret` flag.
## Custom Helm Chart
@@ -400,6 +400,7 @@ applications.
| `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME` | Used to set a username to connect to the Helm repository. Defaults to no credentials. Also set `AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD`. |
| `AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD` | Used to set a password to connect to the Helm repository. Defaults to no credentials. Also set `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME`. |
| `AUTO_DEVOPS_CHART_REPOSITORY_PASS_CREDENTIALS` | From GitLab 14.2, set to a non-empty value to enable forwarding of the Helm repository credentials to the chart server when the chart artifacts are on a different host than repository. |
+| `AUTO_DEVOPS_COMMON_NAME` | From GitLab 15.5, set to a valid domain name to customize the common name used for the TLS certificate. Defaults to `le-$CI_PROJECT_ID.$KUBE_INGRESS_BASE_DOMAIN`. Set to `false` to not set this alternative host on the Ingress. |
| `AUTO_DEVOPS_DEPLOY_DEBUG` | From GitLab 13.1, if this variable is present, Helm outputs debug logs. |
| `AUTO_DEVOPS_ALLOW_TO_FORCE_DEPLOY_V<N>` | From [auto-deploy-image](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image) v1.0.0, if this variable is present, a new major version of chart is forcibly deployed. For more information, see [Ignore warnings and continue deploying](upgrading_auto_deploy_dependencies.md#ignore-warnings-and-continue-deploying). |
| `BUILDPACK_URL` | Buildpack's full URL. [Must point to a URL supported by Pack or Herokuish](#custom-buildpacks). |
diff --git a/doc/topics/autodevops/multiple_clusters_auto_devops.md b/doc/topics/autodevops/multiple_clusters_auto_devops.md
index 49ded4bfb9a..af8c54a8edd 100644
--- a/doc/topics/autodevops/multiple_clusters_auto_devops.md
+++ b/doc/topics/autodevops/multiple_clusters_auto_devops.md
@@ -14,7 +14,7 @@ The [Deploy Job template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib
- `staging`
- `production`
-These environments are tied to jobs using [Auto Deploy](stages.md#auto-deploy), so they must have different deployment domains. You must define separate [`KUBE_CONTEXT`](../../user/clusters/agent/ci_cd_workflow.md#using-the-agent-with-auto-devops) and [`KUBE_INGRESS_BASE_DOMAIN`](requirements.md#auto-devops-base-domain) variables for each of the three environments.
+These environments are tied to jobs using [Auto Deploy](stages.md#auto-deploy), so they must have different deployment domains. You must define separate [`KUBE_CONTEXT`](../../user/clusters/agent/ci_cd_workflow.md#environments-that-use-auto-devops) and [`KUBE_INGRESS_BASE_DOMAIN`](requirements.md#auto-devops-base-domain) variables for each of the three environments.
## Deploy to different clusters
diff --git a/doc/topics/autodevops/stages.md b/doc/topics/autodevops/stages.md
index 9458d1cc6f9..022ee131e40 100644
--- a/doc/topics/autodevops/stages.md
+++ b/doc/topics/autodevops/stages.md
@@ -316,7 +316,7 @@ To use a custom target instead of the auto-deployed review apps,
set a `DAST_WEBSITE` CI/CD variable to the URL for DAST to scan.
WARNING:
-If [DAST Full Scan](../../user/application_security/dast/index.md#full-scan) is
+If [DAST Full Scan](../../user/application_security/dast/proxy-based.md#full-scan) is
enabled, GitLab strongly advises **not**
to set `DAST_WEBSITE` to any staging or production environment. DAST Full Scan
actively attacks the target, which can take down your application and lead to
diff --git a/doc/topics/awesome_co.md b/doc/topics/awesome_co.md
index 0d725f64f3a..49e39542b2b 100644
--- a/doc/topics/awesome_co.md
+++ b/doc/topics/awesome_co.md
@@ -1,5 +1,5 @@
---
-stage: Ecosystem
+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/engineering/ux/technical-writing/#assignments
description: AwesomeCo test data harness created by the Test Data Working Group https://about.gitlab.com/company/team/structure/working-groups/demo-test-data/
diff --git a/doc/topics/git/how_to_install_git/index.md b/doc/topics/git/how_to_install_git/index.md
index 7d753374473..f3ea1431733 100644
--- a/doc/topics/git/how_to_install_git/index.md
+++ b/doc/topics/git/how_to_install_git/index.md
@@ -89,6 +89,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/topics/git/lfs/index.md b/doc/topics/git/lfs/index.md
index 1ab4a8a8acc..98710315652 100644
--- a/doc/topics/git/lfs/index.md
+++ b/doc/topics/git/lfs/index.md
@@ -43,6 +43,24 @@ Documentation for GitLab instance administrators is under [LFS administration do
[add the URL to Git configuration manually](#troubleshooting).
- [Group wikis](../../../user/project/wiki/group.md) do not support Git LFS.
+## How LFS objects affect repository size
+
+When you add an LFS object to a repository, GitLab:
+
+1. Creates an LFS object.
+1. Associates the LFS object with the repository.
+1. Queues a job to recalculate your project's statistics, including storage size and
+ LFS object storage. Your LFS object storage is the sum of the size of all LFS objects
+ associated with the repository.
+
+When your repository is forked, LFS objects from the upstream project are associated
+with the fork. When the fork is created, the LFS object storage for the fork is equal
+to the storage used by the upstream project. If new LFS objects are added to the fork,
+the total object storage changes for the fork, but not the upstream project.
+
+If you create a merge request from the fork back to the upstream project,
+any new LFS objects in the fork become associated with the upstream project.
+
## Using Git LFS
Let's take a look at the workflow for checking large files into your Git
diff --git a/doc/topics/git/lfs/migrate_to_git_lfs.md b/doc/topics/git/lfs/migrate_to_git_lfs.md
index 6e634cde8f0..07c89e52653 100644
--- a/doc/topics/git/lfs/migrate_to_git_lfs.md
+++ b/doc/topics/git/lfs/migrate_to_git_lfs.md
@@ -159,7 +159,7 @@ Consider an example upstream project, `git@gitlab.com:gitlab-tests/test-git-lfs-
1. Navigate to your project's **Settings > Repository** and
expand **Protected branches**.
- 1. Select the default branch from the **Branch** dropdown menu,
+ 1. Select the default branch from the **Branch** dropdown list,
and set up the
**Allowed to push** and **Allowed to merge** rules.
1. Select **Protect**.
@@ -172,7 +172,7 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/topics/git/merge_conflicts.md b/doc/topics/git/merge_conflicts.md
index 91b608ab705..ea37afe1b31 100644
--- a/doc/topics/git/merge_conflicts.md
+++ b/doc/topics/git/merge_conflicts.md
@@ -1,69 +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: '../../user/project/merge_requests/conflicts.md#resolve-conflicts-from-the-command-line'
+remove_date: '2023-02-01'
---
-# Merge conflicts **(FREE)**
+This document was moved to [another location](../../user/project/merge_requests/conflicts.md#resolve-conflicts-from-the-command-line).
-- Happen often
-- Learning to fix conflicts is hard
-- Practice makes perfect
-- Force push after fixing conflicts. Be careful!
-
-## Merge conflicts sample workflow
-
-1. Check out a new branch and edit `conflicts.rb`. Add 'Line4' and 'Line5'.
-1. Commit and push.
-1. Check out `main` and edit `conflicts.rb`. Add 'Line6' and 'Line7' below 'Line3'.
-1. Commit and push to `main``.
-1. Create a merge request and watch it fail.
-1. Rebase our new branch with `main`.
-1. Fix conflicts on the `conflicts.rb` file.
-1. Stage the file and continue rebasing.
-1. Force push the changes.
-1. Finally continue with the merge request.
-
-```shell
-git checkout -b conflicts_branch
-
-# vi conflicts.rb
-# Add 'Line4' and 'Line5'
-
-git commit -am "add line4 and line5"
-git push origin conflicts_branch
-
-git checkout main
-
-# vi conflicts.rb
-# Add 'Line6' and 'Line7'
-git commit -am "add line6 and line7"
-git push origin main
-```
-
-Create a merge request on the GitLab web UI, and a conflict warning displays.
-
-```shell
-git checkout conflicts_branch
-git fetch
-git rebase main
-
-# Fix conflicts by editing the files.
-
-git add conflicts.rb
-# No need to commit this file
-
-git rebase --continue
-
-# Remember that we have rewritten our commit history so we
-# need to force push so that our remote branch is restructured
-git push origin conflicts_branch -f
-```
-
-## Note
-
-- When to use `git merge` and when to use `git rebase`
-- Rebase when updating your branch with `main`
-- Merge when bringing changes from feature to `main`
-- Reference: <https://www.atlassian.com/git/tutorials/merging-vs-rebasing>
+<!-- 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/numerous_undo_possibilities_in_git/index.md b/doc/topics/git/numerous_undo_possibilities_in_git/index.md
index e1e4300f42c..678e03a2c13 100644
--- a/doc/topics/git/numerous_undo_possibilities_in_git/index.md
+++ b/doc/topics/git/numerous_undo_possibilities_in_git/index.md
@@ -402,7 +402,7 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/topics/git/useful_git_commands.md b/doc/topics/git/useful_git_commands.md
index 26ad155054b..4156a3078da 100644
--- a/doc/topics/git/useful_git_commands.md
+++ b/doc/topics/git/useful_git_commands.md
@@ -217,6 +217,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/topics/release_your_application.md b/doc/topics/release_your_application.md
index 6f1c7bb4a40..851396f9bf3 100644
--- a/doc/topics/release_your_application.md
+++ b/doc/topics/release_your_application.md
@@ -28,7 +28,7 @@ deployment using GitLab CI/CD.
With the extensive integration between GitLab and Kubernetes, you can safely deploy your applications
to Kubernetes clusters using the [GitLab agent](../user/clusters/agent/install/index.md).
-#### GitOps deployments **(PREMIUM)**
+#### GitOps deployments
With the [GitLab agent for Kubernetes](../user/clusters/agent/install/index.md), you can perform
[pull-based deployments of Kubernetes manifests](../user/clusters/agent/gitops.md). This provides a scalable, secure,
diff --git a/doc/tutorials/agile_sprint.md b/doc/tutorials/agile_sprint.md
new file mode 100644
index 00000000000..8e1886cf464
--- /dev/null
+++ b/doc/tutorials/agile_sprint.md
@@ -0,0 +1,101 @@
+---
+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: Use GitLab to run an Agile iteration
+
+To run an Agile development iteration in GitLab, you use multiple GitLab features
+that work together.
+
+To run an Agile iteration from GitLab:
+
+1. Create a group.
+1. Create a project.
+1. Set up an iteration cadence.
+1. Create scoped labels.
+1. Create your epics and issues.
+1. Create an issue board.
+
+After you've created these core components, you can begin running your iterations.
+
+## Create a group
+
+Iteration cadences are created at the group level, so start by
+[creating one](../user/group/manage.md#create-a-group) if you don't have one already.
+
+You use groups to manage one or more related projects at the same time.
+You add your users as members in the group, and assign them a role. Roles determine
+the [level of permissions](../user/permissions.md) each user has on the projects in the group.
+Membership automatically cascades down to all subgroups and projects.
+
+## Create a project
+
+Now [create one or more projects](../user/project/working_with_projects.md#create-a-project) in your group.
+There are several different ways to create a project. A project contains
+your code and pipelines, but also the issues that are used for planning your upcoming code changes.
+
+## Set up an iteration cadence
+
+Before you start creating epics or issues, create an
+[iteration cadence](../user/group/iterations/index.md#iteration-cadences).
+Iteration cadences contain the individual, sequential iteration timeboxes for planning and reporting
+on your issues.
+
+When creating an iteration cadence, you can decide whether to automatically manage the iterations or
+disable the automated scheduling to
+[manually manage the iterations](../user/group/iterations/index.md#manual-iteration-management).
+
+Similar to membership, iterations cascade down your group, subgroup, and project hierarchy. If your
+team works across many groups, subgroups, and projects, create the iteration cadence in the top-most
+group shared by all projects that contain the team's issues as illustrated by the diagram below.
+
+```mermaid
+graph TD
+ Group --> SubgroupA --> Project1
+ Group --> SubgroupB --> Project2
+ Group --> IterationCadence
+```
+
+## Create scoped labels
+
+You should also [create scoped labels](../user/project/labels.md) in the same group where you created
+your iteration cadence. Labels help you
+organize your epics, issues, and merge requests, as well as help you
+to visualize the flow of issues in boards. For example, you can use scoped labels like
+`workflow::planning`, `workflow::ready for development`, `workflow::in development`, and `workflow::complete`
+to indicate the status of an issue. You can also leverage scoped labels to denote the type of issue
+or epic such as `type::feature`, `type::defect`, and `type::maintenance`.
+
+## Create your epics and issues
+
+Now you can get started planning your iterations. Start by creating [epics](../user/group/epics/index.md)
+in the group where you created your iteration cadence,
+then create child [issues](../user/project/issues/index.md) in one or more of your projects.
+Add labels to each as needed.
+
+## Create an issue board
+
+[Issue boards](../user/project/issue_board.md) help you plan your upcoming iterations or visualize
+the workflow of the iteration currently in progress. List columns can be created based on label,
+assignee, iteration, or milestone. You can also filter the board by multiple attributes and group
+issues by their epic.
+
+In the group where you created your iteration cadence and labels,
+[create an issue board](../user/project/issue_board.md#create-an-issue-board) and name it
+"Iteration Planning." Then, create lists for each of your iterations. You can then drag issues from
+the "Open" list into iteration lists to schedule them for upcoming iterations.
+
+To visualize the workflow for issues in the current iteration, create another issue board called
+"Current Iteration." When you're creating the board:
+
+1. Select **Edit board**.
+1. Next to **Iteration**, select **Edit**.
+1. From the dropdown list, select **Current iteration**.
+1. Select **Save changes**.
+
+Your board will now only ever show issues that are in the current iteration.
+You can start adding lists for each of the `workflow::...` labels you created previously.
+
+Now you're ready to start development.
diff --git a/doc/tutorials/index.md b/doc/tutorials/index.md
index 92e96a059dc..9b264a8c636 100644
--- a/doc/tutorials/index.md
+++ b/doc/tutorials/index.md
@@ -1,6 +1,6 @@
---
stage: none
-group: unassigned
+group: Tutorials
info: For assistance with this tutorials page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-other-projects-and-subjects.
---
@@ -44,6 +44,8 @@ collaborating, and more.
|-------|-------------|--------------------|
| [Create a project from a template](https://gitlab.com/projects/new#create_from_template) | For hands-on learning, select **Sample GitLab Project** and create a project with example issues and merge requests. | **{star}** |
| [Migrate to GitLab](../user/project/import/index.md) | If you are coming to GitLab from another platform, you can import or convert your projects. | |
+| [Run an agile iteration](agile_sprint.md) | Use group, projects, and iterations to run an agile development iteration. |
+| <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Use GitLab for multi-team planning (SAFe)](https://www.youtube.com/watch?v=KmASFwSap7c) (37m 37s) | A use case of a multi-team organization that uses GitLab with [Scaled Agile Framework (SAFe)](https://about.gitlab.com/solutions/agile-delivery/scaled-agile/). |
## Use CI/CD pipelines
@@ -51,7 +53,7 @@ CI/CD pipelines are used to automatically build, test, and deploy your code.
| Topic | Description | Good for beginners |
|-------|-------------|--------------------|
-| [Get started: Create a pipeline](../ci/quick_start/index.md) | Create a `.gitlab-ci.yml` file and start a pipeline. | **{star}** |
+| [Create and run your first GitLab CI/CD pipeline](../ci/quick_start/index.md) | Create a `.gitlab-ci.yml` file and start a pipeline. | **{star}** |
| <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Get started: Learn about CI/CD](https://www.youtube.com/watch?v=sIegJaLy2ug) (9m 02s) | Learn about the `.gitlab-ci.yml` file and how it's used. | **{star}** |
| <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [CI deep dive](https://www.youtube.com/watch?v=ZVUbmVac-m8&list=PL05JrBw4t0KorkxIFgZGnzzxjZRCGROt_&index=27) (22m 51s) | Take a closer look at pipelines and continuous integration concepts. | |
| <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [CD deep dive](https://www.youtube.com/watch?v=Cn0rzND-Yjw&list=PL05JrBw4t0KorkxIFgZGnzzxjZRCGROt_&index=10) (47m 54s) | Learn about deploying in GitLab. | |
@@ -114,7 +116,6 @@ content:
- Find learning tracks and certification options at [GitLab Learn](https://about.gitlab.com/learn/).
GitLab learning platform login required (email and password for non-GitLab team members).
- For more information, see [First time login details](https://about.gitlab.com/handbook/people-group/learning-and-development/gitlab-learn/user/#first-time-login-to-gitlab-learn).
- Find recent tutorials on the GitLab blog by [searching by the `tutorial` tag](https://about.gitlab.com/blog/tags.html#tutorial).
diff --git a/doc/tutorials/make_your_first_git_commit.md b/doc/tutorials/make_your_first_git_commit.md
index cb6f41bff6c..3df65389c76 100644
--- a/doc/tutorials/make_your_first_git_commit.md
+++ b/doc/tutorials/make_your_first_git_commit.md
@@ -1,10 +1,10 @@
---
stage: none
-group: unassigned
+group: Tutorials
info: For assistance with this tutorial, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-other-projects-and-subjects.
---
-# Make your first Git commit
+# Tutorial: Make your first Git commit
This tutorial is going to teach you a little bit about how Git works. It walks
you through the steps of creating your own project, editing a file, and
@@ -37,11 +37,12 @@ Each time you push a change, Git records it as a unique *commit*. These commits
the history of when and how a file changed, and who changed it.
```mermaid
-graph TB
+graph LR
subgraph Repository commit history
- A(Author: Alex<br>Date: 3 Jan at 1PM<br>Commit message: Added sales figures for January<br> Commit ID: 123abc12) ---> B
- B(Author: Sam<br>Date: 4 Jan at 10AM<br>Commit message: Removed outdated marketing information<br> Commit ID: aabb1122) ---> C
- C(Author: Zhang<br>Date: 5 Jan at 3PM<br>Commit message: Added a new 'Invoices' file<br> Commit ID: ddee4455)
+ direction LR
+ A(Author: Alex<br>Date: 3 Jan at 1PM<br>Commit message: Added sales figures<br> Commit ID: 123abc12) ---> B
+ B(Author: Sam<br>Date: 4 Jan at 10AM<br>Commit message: Removed old info<br> Commit ID: aabb1122) ---> C
+ C(Author: Zhang<br>Date: 5 Jan at 3PM<br>Commit message: Added invoices<br> Commit ID: ddee4455)
end
```
@@ -54,15 +55,14 @@ of a repository are in a default branch. To make changes, you:
1. When you're ready, *merge* your branch into the default branch.
```mermaid
-flowchart TB
+flowchart LR
subgraph Default branch
A[Commit] --> B[Commit] --> C[Commit] --> D[Commit]
end
subgraph My branch
B --1. Create my branch--> E(Commit)
E --2. Add my commit--> F(Commit)
- F --2. Add my commit--> G(Commit)
- G --3. Merge my branch to default--> D
+ F --3. Merge my branch to default--> D
end
```
diff --git a/doc/tutorials/move_personal_project_to_a_group.md b/doc/tutorials/move_personal_project_to_a_group.md
index 2106f6ec1c9..ad86851393a 100644
--- a/doc/tutorials/move_personal_project_to_a_group.md
+++ b/doc/tutorials/move_personal_project_to_a_group.md
@@ -1,6 +1,6 @@
---
stage: none
-group: unassigned
+group: Tutorials
info: For assistance with this tutorial, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments-to-other-projects-and-subjects.
---
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index ed9b812525e..353fbf191b5 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -45,8 +45,138 @@ sole discretion of GitLab Inc.
<div class="announcement-milestone">
+## Announced in 15.6
+
+<div class="deprecation removal-160 breaking-change">
+
+### Configuration fields in GitLab Runner Helm Chart
+
+End of Support: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)<br />
+Planned removal: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+From GitLab 13.6, users can [specify any runner configuration in the GitLab Runner Helm chart](https://docs.gitlab.com/runner/install/kubernetes.html). When we implemented this feature, we deprecated values in the GitLab Helm Chart configuration that were specific to GitLab Runner. These fields are deprecated and we plan to remove them in v1.0 of the GitLab Runner Helm chart.
+
+</div>
+
+<div class="deprecation removal-160 breaking-change">
+
+### GitLab Runner registration token in Runner Operator
+
+End of Support: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)<br />
+Planned removal: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)
+
+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.
+
+</div>
+
+<div class="deprecation removal-160 breaking-change">
+
+### `POST /api/v4/runners` method to register runners
+
+End of Support: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)<br />
+Planned removal: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+The `POST` method operation on the `/api/v4/runners` endpoint is deprecated.
+This endpoint and method [registers](https://docs.gitlab.com/ee/api/runners.html#register-a-new-runner) a runner
+with a GitLab instance at the instance, group, or project level through the API. We plan to remove this endpoint
+and method in GitLab 16.0.
+
+In GitLab 15.8, 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/).
+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 16.0 and later, the runner registration methods implemented by the new GitLab Runner token architecture will be the only supported methods.
+
+</div>
+
+<div class="deprecation removal-160 breaking-change">
+
+### `gitlab-runner register` command
+
+End of Support: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)<br />
+Planned removal: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+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.8,
+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).
+The new method will involve passing a [runner authentication token](https://docs.gitlab.com/ee/security/token_overview.html#runner-authentication-tokens-also-called-runner-tokens)
+to a new `gitlab-runner deploy` command.
+
+</div>
+
+<div class="deprecation removal-160 breaking-change">
+
+### `runnerRegistrationToken` parameter for GitLab Runner Helm Chart
+
+End of Support: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)<br />
+Planned removal: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+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.
+- A unique system ID saved to the `config.toml`, which will ensure traceability between jobs and runners.
+From GitLab 16.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> (2023-05-22)
+
+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">
+
## Announced in 15.5
+<div class="deprecation removal-157 breaking-change">
+
+### File Type variable expansion in `.gitlab-ci.yml`
+
+Planned removal: GitLab <span class="removal-milestone">15.7</span> ()
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+Previously, variables that referenced or applied alias file variables expanded the value of the `File` type variable. For example, the file contents. This behavior was incorrect because it did not comply with typical shell variable expansion rules. To leak secrets or sensitive information stored in `File` type variables, a user could run an $echo command with the variable as an input parameter.
+
+This breaking change fixes this issue but could disrupt user workflows that work around the behavior. With this change, job variable expansions that reference or apply alias file variables, expand to the file name or path of the `File` type variable, instead of its value, such as the file contents.
+
+</div>
+
<div class="deprecation removal-160 breaking-change">
### GraphQL field `confidential` changed to `internal` on notes
@@ -1063,7 +1193,7 @@ WARNING:
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
Review the details carefully before upgrading.
-[Request profiling](https://docs.gitlab.com/ee/administration/monitoring/performance/request_profiling.html) is deprecated in GitLab 14.8 and scheduled for removal in GitLab 15.0.
+[Request profiling](https://docs.gitlab.com/ee/administration/monitoring/performance/index.html) is deprecated in GitLab 14.8 and scheduled for removal in GitLab 15.0.
We're working on [consolidating our profiling tools](https://gitlab.com/groups/gitlab-org/-/epics/7327) and making them more easily accessible.
We [evaluated](https://gitlab.com/gitlab-org/gitlab/-/issues/350152) the use of this feature and we found that it is not widely used.
@@ -1130,10 +1260,12 @@ In GitLab 15.4, GitLab SAST will no longer use the following analyzers:
- [Bandit](https://gitlab.com/gitlab-org/security-products/analyzers/bandit) (Python)
NOTE:
-This change was originally planned for GitLab 15.0 and has been postponed.
+This change was originally planned for GitLab 15.0 and was postponed to GitLab 15.4.
+See [the removal notice](./removals.md#sast-analyzer-consolidation-and-cicd-template-changes) for further details.
These analyzers will be removed from the [GitLab-managed SAST CI/CD template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml) and replaced with the [Semgrep-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep).
-They will no longer receive routine updates, except for security issues.
+Effective immediately, they will receive only security updates; other routine improvements or updates are not guaranteed.
+After these analyzers reach End of Support, no further updates will be provided.
We will not delete container images previously published for these analyzers; any such change would be announced as a [deprecation, removal, or breaking change announcement](https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations-removals-and-breaking-changes).
We will also remove Java from the scope of the [SpotBugs](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) analyzer and replace it with the [Semgrep-based analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep).
@@ -1656,7 +1788,7 @@ Planned removal: GitLab <span class="removal-milestone">15.0</span> (2022-05-22)
The Static Site Editor will no longer be available starting in GitLab 15.0. Improvements to the Markdown editing experience across GitLab will deliver smiliar benefit but with a wider reach. Incoming requests to the Static Site Editor will be redirected to the [Web IDE](https://docs.gitlab.com/ee/user/project/web_ide/index.html).
-Current users of the Static Site Editor can view the [documentation](https://docs.gitlab.com/ee/user/project/static_site_editor/) for more information, including how to remove the configuration files from existing projects.
+Current users of the Static Site Editor can view the [documentation](https://docs.gitlab.com/ee/user/project/web_ide/index.html) for more information, including how to remove the configuration files from existing projects.
</div>
@@ -1691,17 +1823,17 @@ only supported report file in 15.0, but this is the first step towards GitLab su
</div>
-<div class="deprecation removal-150 breaking-change">
+<div class="deprecation removal-160 breaking-change">
### merged_by API field
-Planned removal: GitLab <span class="removal-milestone">15.0</span> (2022-05-22)
+Planned removal: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)
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) is being deprecated and will be removed in GitLab 15.0. This field is being replaced with the `merge_user` field (already present in GraphQL) 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.
+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>
@@ -2090,7 +2222,7 @@ WARNING:
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
Review the details carefully before upgrading.
-[GitLab Serverless](https://docs.gitlab.com/ee/user/project/clusters/serverless/) is a feature set to support Knative-based serverless development with automatic deployments and monitoring.
+GitLab Serverless is a feature set to support Knative-based serverless development with automatic deployments and monitoring.
We decided to remove the GitLab Serverless features as they never really resonated with our users. Besides, given the continuous development of Kubernetes and Knative, our current implementations do not even work with recent versions.
diff --git a/doc/update/index.md b/doc/update/index.md
index 06609f03952..dbac4304897 100644
--- a/doc/update/index.md
+++ b/doc/update/index.md
@@ -143,6 +143,8 @@ GitLab 14.0 introduced [batched background migrations](../user/admin_area/monito
Some installations [may need to run GitLab 14.0 for at least a day](#1400) to complete the database changes introduced by that upgrade.
+Batched background migrations are handled by Sidekiq and [run in isolation](../development/database/batched_background_migrations.md#isolation), so an instance can remain operational while the migrations are processed. However, there may be performance degradation on larger instances that are heavily used while batched background migrations are run, so it's a good idea to [actively monitor the Sidekiq status](../user/admin_area/index.md#background-jobs) until all migrations are completed.
+
#### Check the status of batched background migrations
To check the status of batched background migrations:
@@ -376,24 +378,26 @@ Upgrading across multiple GitLab versions in one go is *only possible by accepti
The following examples assume downtime is acceptable while upgrading.
If you don't want any downtime, read how to [upgrade with zero downtime](zero_downtime.md).
+For a dynamic view of examples of supported upgrade paths, try the [Upgrade Path tool](https://gitlab-com.gitlab.io/support/toolbox/upgrade-path/) maintained by the [GitLab Support team](https://about.gitlab.com/handbook/support/#about-the-support-team). To share feedback and help improve the tool, create an issue or MR in the [upgrade-path project](https://gitlab.com/gitlab-com/support/toolbox/upgrade-path).
+
Find where your version sits in the upgrade path below, and upgrade GitLab
accordingly, while also consulting the
[version-specific upgrade instructions](#version-specific-upgrading-instructions):
-`8.11.Z` -> `8.12.0` -> `8.17.7` -> `9.5.10` -> `10.8.7` -> [`11.11.8`](#1200) -> `12.0.12` -> [`12.1.17`](#1210) -> [`12.10.14`](#12100) -> `13.0.14` -> [`13.1.11`](#1310) -> [`13.8.8`](#1388) -> [`13.12.15`](#13120) -> [`14.0.12`](#1400) -> [`14.3.6`](#1430) -> [`14.9.5`](#1490) -> [`14.10.Z`](#14100) -> [`15.0.Z`](#1500) -> [`15.4.0`](#1540) -> [latest `15.Y.Z`](https://gitlab.com/gitlab-org/gitlab/-/releases)
+`8.11.Z` -> `8.12.0` -> `8.17.7` -> `9.5.10` -> `10.8.7` -> [`11.11.8`](#1200) -> `12.0.12` -> [`12.1.17`](#1210) -> [`12.10.14`](#12100) -> `13.0.14` -> [`13.1.11`](#1310) -> [`13.8.8`](#1388) -> [`13.12.15`](#13120) -> [`14.0.12`](#1400) -> [`14.3.6`](#1430) -> [`14.9.5`](#1490) -> [`14.10.Z`](#14100) -> [`15.0.Z`](#1500) -> [`15.1.Z`](#1510) (for GitLab instances with multiple web nodes) -> [`15.4.0`](#1540) -> [latest `15.Y.Z`](https://gitlab.com/gitlab-org/gitlab/-/releases)
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
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.
The following table, while not exhaustive, shows some examples of the supported
upgrade paths.
Additional steps between the mentioned versions are possible. We list the minimally necessary steps only.
-For a dynamic view of examples of supported upgrade paths, try the [Upgrade Path tool](https://gitlab-com.gitlab.io/support/toolbox/upgrade-path/). The Upgrade Path tool is maintained by the [GitLab Support team](https://about.gitlab.com/handbook/support/#about-the-support-team). Share feedback and help improve the tool by raising an issue or MR in the [upgrade-path project](https://gitlab.com/gitlab-com/support/toolbox/upgrade-path).
-
| Target version | Your version | Supported upgrade path | Note |
| -------------- | ------------ | ---------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `15.1.0` | `14.6.2` | `14.6.2` -> `14.9.5` -> `14.10.5` -> `15.0.2` -> `15.1.0` | Three intermediate versions are required: `14.9` and `14.10`, `15.0`, then `15.1.0`. |
@@ -467,10 +471,32 @@ 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.6.0
+
+- Git 2.37.0 and later is required by Gitaly. For installations from source, we recommend you use the [Git version provided by Gitaly](../install/installation.md#git).
+
+### 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/extra_sidekiq_processes.md#queue-selector), this will cause [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
+ - The default routing rule has been reverted in 15.5.4, so upgrading to that version or later will return to the previous behavior.
+ - If a GitLab instance now listens only to the `default` queue (which is not currently recommended), it will be required to add this routing rule back in `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ sidekiq['routing_rules'] = [['*', 'default']]
+ ```
+
### 15.4.0
- GitLab 15.4.0 includes a [batched background migration](#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/extra_sidekiq_processes.md#queue-selector), this will cause [performance problems](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1991) as some Sidekiq processes will be idle.
+ - The default routing rule has been reverted in 15.4.5, so upgrading to that version or later will return to the previous behavior.
+ - If a GitLab instance now listens only to the `default` queue (which is not currently recommended), it will be required to add this routing rule back in `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ sidekiq['routing_rules'] = [['*', 'default']]
+ ```
### 15.3.3
diff --git a/doc/update/patch_versions.md b/doc/update/patch_versions.md
index 6e153d5132d..e0c0cdf31f9 100644
--- a/doc/update/patch_versions.md
+++ b/doc/update/patch_versions.md
@@ -60,11 +60,6 @@ sudo -u git -H bundle clean
# Run database migrations
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
-# Compile GetText PO files
-# Internationalization was added in `v9.2.0` so this command is only
-# required for versions equal or major to it.
-sudo -u git -H bundle exec rake gettext:compile RAILS_ENV=production
-
# Clean up assets and cache
sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile cache:clear RAILS_ENV=production NODE_ENV=production NODE_OPTIONS="--max_old_space_size=4096"
```
diff --git a/doc/update/removals.md b/doc/update/removals.md
index 392259176bb..0bc82403f60 100644
--- a/doc/update/removals.md
+++ b/doc/update/removals.md
@@ -31,6 +31,18 @@ For removal reviewers (Technical Writers only):
https://about.gitlab.com/handbook/marketing/blog/release-posts/#update-the-removals-doc
-->
+## Removed in 16.0
+
+### Changing merge request approvals with the `/approvals` API endpoint
+
+WARNING:
+This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
+Review the details carefully before upgrading.
+
+To change the approvals required for a merge request, you should no longer use the `/approvals` API endpoint, which was deprecated in GitLab 12.3.
+
+Instead, use the [`/approval_rules` endpoint](https://docs.gitlab.com/ee/api/merge_request_approvals.html#merge-request-level-mr-approvals) to [create](https://docs.gitlab.com/ee/api/merge_request_approvals.html#create-merge-request-level-rule) or [update](https://docs.gitlab.com/ee/api/merge_request_approvals.html#update-merge-request-level-rule) the approval rules for a merge request.
+
## Removed in 15.4
### SAST analyzer consolidation and CI/CD template changes
@@ -251,7 +263,7 @@ Elasticsearch 6.8 support has been removed in GitLab 15.0. Elasticsearch 6.8 has
If you use Elasticsearch 6.8, **you must upgrade your Elasticsearch version to 7.x** prior to upgrading to GitLab 15.0.
You should not upgrade to Elasticsearch 8 until you have completed the GitLab 15.0 upgrade.
-View the [version requirements](https://docs.gitlab.com/ee/integration/elasticsearch.html#version-requirements) for details.
+View the [version requirements](https://docs.gitlab.com/ee/integration/advanced_search/elasticsearch.html#version-requirements) for details.
### End of support for Python 3.6 in Dependency Scanning
@@ -444,7 +456,7 @@ WARNING:
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
Review the details carefully before upgrading.
-[Request profiling](https://docs.gitlab.com/ee/administration/monitoring/performance/request_profiling.html) has been removed in GitLab 15.0.
+[Request profiling](https://docs.gitlab.com/ee/administration/monitoring/performance/index.html) has been removed in GitLab 15.0.
We're working on [consolidating our profiling tools](https://gitlab.com/groups/gitlab-org/-/epics/7327) and making them more easily accessible.
We [evaluated](https://gitlab.com/gitlab-org/gitlab/-/issues/350152) the use of this feature and we found that it is not widely used.
@@ -574,7 +586,7 @@ If you installed GitLab from source, verify manually that both servers are confi
### Static Site Editor
-The Static Site Editor was deprecated in GitLab 14.7 and the feature is being removed in GitLab 15.0. Incoming requests to the Static Site Editor will be redirected and open the target file to edit in the Web IDE. Current users of the Static Site Editor can view the [documentation](https://docs.gitlab.com/ee/user/project/static_site_editor/) for more information, including how to remove the configuration files from existing projects. We will continue investing in improvements to the Markdown editing experience by [maturing the Content Editor](https://gitlab.com/groups/gitlab-org/-/epics/5401) and making it available as a way to edit content across GitLab.
+The Static Site Editor was deprecated in GitLab 14.7 and the feature is being removed in GitLab 15.0. Incoming requests to the Static Site Editor will be redirected and open the target file to edit in the Web IDE. Current users of the Static Site Editor can view the [documentation](https://docs.gitlab.com/ee/user/project/web_ide/index.html) for more information, including how to remove the configuration files from existing projects. We will continue investing in improvements to the Markdown editing experience by [maturing the Content Editor](https://gitlab.com/groups/gitlab-org/-/epics/5401) and making it available as a way to edit content across GitLab.
### Support for `gitaly['internal_socket_dir']`
@@ -849,7 +861,7 @@ WARNING:
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
Review the details carefully before upgrading.
-By default, the Code Quality feature has not provided support for Ruby 2.6+ if you're using the Code Quality template. To better support the latest versions of Ruby, the default RuboCop version is updated to add support for Ruby 2.4 through 3.0. As a result, support for Ruby 2.1, 2.2, and 2.3 is removed. You can re-enable support for older versions by [customizing your configuration](https://docs.gitlab.com/ee/user/project/merge_requests/code_quality.html#rubocop-errors).
+By default, the Code Quality feature has not provided support for Ruby 2.6+ if you're using the Code Quality template. To better support the latest versions of Ruby, the default RuboCop version is updated to add support for Ruby 2.4 through 3.0. As a result, support for Ruby 2.1, 2.2, and 2.3 is removed. You can re-enable support for older versions by [customizing your configuration](https://docs.gitlab.com/ee/ci/testing/code_quality.html#rubocop-errors).
Relevant Issue: [Default `codeclimate-rubocop` engine does not support Ruby 2.6+](https://gitlab.com/gitlab-org/ci-cd/codequality/-/issues/28)
@@ -892,7 +904,7 @@ WARNING:
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
Review the details carefully before upgrading.
-Browser Performance Testing has run in a job named `performance` by default. With the introduction of [Load Performance Testing](https://docs.gitlab.com/ee/user/project/merge_requests/load_performance_testing.html) in GitLab 13.2, this naming could be confusing. To make it clear which job is running [Browser Performance Testing](https://docs.gitlab.com/ee/user/project/merge_requests/browser_performance_testing.html), the default job name is changed from `performance` to `browser_performance` in the template in GitLab 14.0.
+Browser Performance Testing has run in a job named `performance` by default. With the introduction of [Load Performance Testing](https://docs.gitlab.com/ee/ci/testing/code_quality.html) in GitLab 13.2, this naming could be confusing. To make it clear which job is running [Browser Performance Testing](https://docs.gitlab.com/ee/ci/testing/browser_performance_testing.html), the default job name is changed from `performance` to `browser_performance` in the template in GitLab 14.0.
Relevant Issue: [Rename default Browser Performance Testing job](https://gitlab.com/gitlab-org/gitlab/-/issues/225914)
@@ -1158,7 +1170,7 @@ WARNING:
This is a [breaking change](https://docs.gitlab.com/ee/development/deprecation_guidelines/).
Review the details carefully before upgrading.
-The [deployment frequency project-level API](https://docs.gitlab.com/ee/api/dora4_project_analytics.html#list-project-deployment-frequencies) endpoint has been deprecated in favor of the [DORA 4 API](https://docs.gitlab.com/ee/api/dora/metrics.html), which consolidates all the metrics under one API with the specific metric as a required field. As a result, the timestamp field, which doesn't allow adding future extensions and causes performance issues, will be removed. With the old API, an example response would be `{ "2021-03-01": 3, "date": "2021-03-01", "value": 3 }`. The first key/value (`"2021-03-01": 3`) will be removed and replaced by the last two (`"date": "2021-03-01", "value": 3`).
+The [deployment frequency project-level API](https://docs.gitlab.com/ee/api/dora/metrics.html#list-project-deployment-frequencies) endpoint has been deprecated in favor of the [DORA 4 API](https://docs.gitlab.com/ee/api/dora/metrics.html), which consolidates all the metrics under one API with the specific metric as a required field. As a result, the timestamp field, which doesn't allow adding future extensions and causes performance issues, will be removed. With the old API, an example response would be `{ "2021-03-01": 3, "date": "2021-03-01", "value": 3 }`. The first key/value (`"2021-03-01": 3`) will be removed and replaced by the last two (`"date": "2021-03-01", "value": 3`).
### Release description in the Tags API
diff --git a/doc/update/upgrading_from_ce_to_ee.md b/doc/update/upgrading_from_ce_to_ee.md
index 9bb88755686..b99bb3d7992 100644
--- a/doc/update/upgrading_from_ce_to_ee.md
+++ b/doc/update/upgrading_from_ce_to_ee.md
@@ -75,9 +75,6 @@ sudo -u git -H bundle clean
# Run database migrations
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
-# Compile GetText PO files
-sudo -u git -H bundle exec rake gettext:compile RAILS_ENV=production
-
# Update node dependencies and recompile assets
sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile RAILS_ENV=production NODE_ENV=production NODE_OPTIONS="--max_old_space_size=4096"
diff --git a/doc/update/upgrading_from_source.md b/doc/update/upgrading_from_source.md
index bb9199560f9..f5b85330f3b 100644
--- a/doc/update/upgrading_from_source.md
+++ b/doc/update/upgrading_from_source.md
@@ -107,11 +107,11 @@ Download and install Go (for Linux, 64-bit):
# Remove former Go installation folder
sudo rm -rf /usr/local/go
-curl --remote-name --location --progress-bar "https://go.dev/dl/go1.17.10.linux-amd64.tar.gz"
-echo '87fc728c9c731e2f74e4a999ef53cf07302d7ed3504b0839027bd9c10edaa3fd go1.17.10.linux-amd64.tar.gz' | shasum -a256 -c - && \
- sudo tar -C /usr/local -xzf go1.17.10.linux-amd64.tar.gz
+curl --remote-name --location --progress-bar "https://go.dev/dl/go1.18.8.linux-amd64.tar.gz"
+echo '4d854c7bad52d53470cf32f1b287a5c0c441dc6b98306dea27358e099698142a go1.18.8.linux-amd64.tar.gz' | shasum -a256 -c - && \
+ sudo tar -C /usr/local -xzf go1.18.8.linux-amd64.tar.gz
sudo ln -sf /usr/local/go/bin/{go,gofmt} /usr/local/bin/
-rm go1.17.10.linux-amd64.tar.gz
+rm go1.18.8.linux-amd64.tar.gz
```
### 6. Update Git
@@ -310,9 +310,6 @@ sudo -u git -H bundle clean
# Run database migrations
sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
-# Compile GetText PO files
-sudo -u git -H bundle exec rake gettext:compile RAILS_ENV=production
-
# Update node dependencies and recompile assets
sudo -u git -H bundle exec rake yarn:install gitlab:assets:clean gitlab:assets:compile RAILS_ENV=production NODE_ENV=production NODE_OPTIONS="--max_old_space_size=4096"
diff --git a/doc/update/zero_downtime.md b/doc/update/zero_downtime.md
index aebd27f84a9..eb1d6cef606 100644
--- a/doc/update/zero_downtime.md
+++ b/doc/update/zero_downtime.md
@@ -395,7 +395,7 @@ HA.
#### In the application node
-According to [official Redis documentation](https://redis.io/docs/manual/admin/#upgrading-or-restarting-a-redis-instance-without-downtime),
+According to [official Redis documentation](https://redis.io/docs/management/admin/#upgrading-or-restarting-a-redis-instance-without-downtime),
the easiest way to update an HA instance using Sentinel is to upgrade the
secondaries one after the other, perform a manual failover from current
primary (running old version) to a recently upgraded secondary (running a new
diff --git a/doc/user/admin_area/appearance.md b/doc/user/admin_area/appearance.md
index 5513fa3585d..fc42c7770f2 100644
--- a/doc/user/admin_area/appearance.md
+++ b/doc/user/admin_area/appearance.md
@@ -94,6 +94,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/admin_area/broadcast_messages.md b/doc/user/admin_area/broadcast_messages.md
index e5d0a6e297e..acb3e92fff8 100644
--- a/doc/user/admin_area/broadcast_messages.md
+++ b/doc/user/admin_area/broadcast_messages.md
@@ -111,6 +111,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/admin_area/custom_project_templates.md b/doc/user/admin_area/custom_project_templates.md
index 551ed667250..de2856c2320 100644
--- a/doc/user/admin_area/custom_project_templates.md
+++ b/doc/user/admin_area/custom_project_templates.md
@@ -49,6 +49,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/admin_area/diff_limits.md b/doc/user/admin_area/diff_limits.md
index 3a1ecac6ee6..3d7c49c1f2b 100644
--- a/doc/user/admin_area/diff_limits.md
+++ b/doc/user/admin_area/diff_limits.md
@@ -47,6 +47,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/admin_area/email_from_gitlab.md b/doc/user/admin_area/email_from_gitlab.md
index c1d3521d60c..ba465fbea29 100644
--- a/doc/user/admin_area/email_from_gitlab.md
+++ b/doc/user/admin_area/email_from_gitlab.md
@@ -55,6 +55,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/admin_area/geo_nodes.md b/doc/user/admin_area/geo_nodes.md
deleted file mode 100644
index 710f37bb344..00000000000
--- a/doc/user/admin_area/geo_nodes.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: 'geo_sites.md'
-remove_date: '2022-10-05'
----
-
-This document was moved to [another location](geo_sites.md).
-
-<!-- This redirect file can be deleted after <2022-10-05>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (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/geo_sites.md b/doc/user/admin_area/geo_sites.md
index 093ed84f41a..f3be036fd38 100644
--- a/doc/user/admin_area/geo_sites.md
+++ b/doc/user/admin_area/geo_sites.md
@@ -112,6 +112,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/admin_area/img/minimum_password_length_settings_v12_6.png b/doc/user/admin_area/img/minimum_password_length_settings_v12_6.png
deleted file mode 100644
index 27634a02a8a..00000000000
--- a/doc/user/admin_area/img/minimum_password_length_settings_v12_6.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/admin_area/index.md b/doc/user/admin_area/index.md
index e6ddb810933..4c34d82dc02 100644
--- a/doc/user/admin_area/index.md
+++ b/doc/user/admin_area/index.md
@@ -136,15 +136,15 @@ For each user, the following are listed:
1. Date of last activity
To edit a user, select the **Edit** button in that user's
-row. To delete the user, or delete the user and their contributions, select the cog dropdown in
+row. To delete the user, or delete the user and their contributions, select the cog dropdown list in
that user's row, and select the desired option.
To change the sort order:
-1. Select the sort dropdown.
+1. Select the sort dropdown list.
1. Select the desired order.
-By default the sort dropdown shows **Name**.
+By default the sort dropdown list shows **Name**.
To search for users, enter your criteria in the search field. The user search is case
insensitive, and applies partial matching to name and username. To search for an email address,
@@ -260,7 +260,7 @@ number of members, and whether the group is private, internal, or public. To edi
the **Edit** button in that group's row. To delete the group, select the **Delete** button in
that group's row.
-To change the sort order, select the sort dropdown and select the desired order. The default
+To change the sort order, select the sort dropdown list and select the desired order. The default
sort order is by **Last created**.
To search for groups by name, enter your criteria in the search field. The group search is case
diff --git a/doc/user/admin_area/labels.md b/doc/user/admin_area/labels.md
index 524546d447c..8e1ca979707 100644
--- a/doc/user/admin_area/labels.md
+++ b/doc/user/admin_area/labels.md
@@ -22,6 +22,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/admin_area/license.md b/doc/user/admin_area/license.md
index 5211a18201b..5296a918f56 100644
--- a/doc/user/admin_area/license.md
+++ b/doc/user/admin_area/license.md
@@ -64,6 +64,17 @@ This error occurs when you use an activation code to activate your instance, but
You may have connectivity issues due to the following reasons:
-- **You have an offline environment**: Configure your setup to allow connection to GitLab servers. If connection to GitLab servers is not possible, contact [GitLab support](https://about.gitlab.com/support/#contact-support) to request a license key.
-- **Firewall settings**: Enable an encrypted HTTPS connection from your GitLab instance to `customers.gitlab.com` (with IP addresses 104.18.26.123 and 104.18.27.123) on port 443.
-- **Customers Portal is not operational**: To check for performance or service disruptions, check the Customers Portal [status](https://status.gitlab.com/).
+- **You have an offline environment**:
+ - Configure your setup to allow connection to GitLab servers. If connection to GitLab servers is not possible, contact your Sales Representative to request a license key. You can also contact [GitLab support](https://about.gitlab.com/support/#contact-support) if you need help finding your Sales Representative.
+- **Customers Portal is not operational**:
+ - To check for performance or service disruptions, check the Customers Portal [status](https://status.gitlab.com/).
+- **Firewall settings**:
+ - Check if your GitLab instance has an encrypted connection to `customers.gitlab.com` (with IP addresses 172.64.146.11 and 104.18.41.245) on port 443:
+
+ ```shell
+ curl --verbose "https://customers.gitlab.com/"
+ ```
+
+ - 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.
diff --git a/doc/user/admin_area/license_file.md b/doc/user/admin_area/license_file.md
index e6186fb9805..d821d9bab23 100644
--- a/doc/user/admin_area/license_file.md
+++ b/doc/user/admin_area/license_file.md
@@ -25,7 +25,7 @@ Otherwise, to add your license:
1. Select **Add license**.
NOTE:
-For GitLab versions 14.1.x or newer, you can access the **Add License** page directly from the URL, `<YourGitLabURL>/admin/license/new`.
+In GitLab 14.1.x through 14.10.x, you can access the **Add License** page directly from the URL, `<YourGitLabURL>/admin/license/new`. In GitLab 15.0 and later, the path is `<YourGitLabURL>/admin/subscription`.
## Add your license file during installation
@@ -147,3 +147,81 @@ the license.
### `Start GitLab Ultimate trial` still displays after adding license
To fix this issue, restart [Puma or your entire GitLab instance](../../administration/restart_gitlab.md).
+
+### License commands in the rails console
+
+The following commands can be run in the [rails console](../../administration/operations/rails_console.md#starting-a-rails-console-session).
+
+WARNING:
+Any command that changes data directly could be damaging if not run correctly, or under the right conditions.
+We highly recommend running them in a test environment with a backup of the instance ready to be restored, just in case.
+
+#### See current license information
+
+```ruby
+# License information (name, company, email address)
+License.current.licensee
+
+# Plan:
+License.current.plan
+
+# Uploaded:
+License.current.created_at
+
+# Started:
+License.current.starts_at
+
+# Expires at:
+License.current.expires_at
+
+# Is this a trial license?
+License.current.trial?
+
+# License ID for lookup on CustomersDot
+License.current.license_id
+
+# License data in Base64-encoded ASCII format
+License.current.data
+```
+
+#### Check if a project feature is available on the instance
+
+Features listed in <https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/models/license.rb>.
+
+```ruby
+License.current.feature_available?(:jira_dev_panel_integration)
+```
+
+#### Check if a project feature is available in a project
+
+Features listed in [`license.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/models/license.rb).
+
+```ruby
+p = Project.find_by_full_path('<group>/<project>')
+p.feature_available?(:jira_dev_panel_integration)
+```
+
+#### Add a license through the console
+
+```ruby
+key = "<key>"
+license = License.new(data: key)
+license.save
+License.current # check to make sure it applied
+```
+
+This is needed for example in a known edge-case with
+[expired license and multiple LDAP servers](../../administration/auth/ldap/ldap-troubleshooting.md#expired-license-causes-errors-with-multiple-ldap-servers).
+
+#### Remove licenses
+
+To clean up the [License History table](../../user/admin_area/license_file.md#view-license-details-and-history):
+
+```ruby
+TYPE = :trial?
+# or :expired?
+
+License.select(&TYPE).each(&:destroy!)
+
+# or even License.all.each(&:destroy!)
+```
diff --git a/doc/user/admin_area/moderate_users.md b/doc/user/admin_area/moderate_users.md
index ace1c6be5f8..c0daf029b1f 100644
--- a/doc/user/admin_area/moderate_users.md
+++ b/doc/user/admin_area/moderate_users.md
@@ -54,7 +54,7 @@ To approve or reject a user sign up:
1. On the left sidebar, select **Overview > Users**.
1. Select the **Pending approval** tab.
1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown.
+1. Select the **{settings}** **User administration** dropdown list.
1. Select **Approve** or **Reject**.
Approving a user:
@@ -78,7 +78,7 @@ by removing them in LDAP, or directly from the Admin Area. To do this:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Overview > Users**.
1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown.
+1. Select the **{settings}** **User administration** dropdown list.
1. Select **Block**.
A blocked user:
@@ -102,7 +102,7 @@ A blocked user can be unblocked from the Admin Area. To do this:
1. On the left sidebar, select **Overview > Users**.
1. Select the **Blocked** tab.
1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown.
+1. Select the **{settings}** **User administration** dropdown list.
1. Select **Unblock**.
The user's state is set to active and they consume a
@@ -156,13 +156,13 @@ A user can be deactivated from the Admin Area. To do this:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Overview > Users**.
1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown.
+1. Select the **{settings}** **User administration** dropdown list.
1. Select **Deactivate**.
For the deactivation option to be visible to an administrator, the user:
- Must be currently active.
-- Must not have signed in, or have any activity, in the last 90 days.
+- Must not be [dormant](#automatically-deactivate-dormant-users).
NOTE:
Users can also be deactivated using the [GitLab API](../../api/users.md#deactivate-user).
@@ -203,7 +203,7 @@ To do this:
1. On the left sidebar, select **Overview > Users**.
1. Select the **Deactivated** tab.
1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown.
+1. Select the **{settings}** **User administration** dropdown list.
1. Select **Activate**.
The user's state is set to active and they consume a
@@ -235,7 +235,7 @@ Users can be banned using the Admin Area. To do this:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Overview > Users**.
1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown.
+1. Select the **{settings}** **User administration** dropdown list.
1. Select **Ban user**.
The banned user does not consume a [seat](../../subscriptions/self_managed/index.md#billable-users).
@@ -248,7 +248,7 @@ A banned user can be unbanned using the Admin Area. To do this:
1. On the left sidebar, select **Overview > Users**.
1. Select the **Banned** tab.
1. Optional. Select a user.
-1. Select the **{settings}** **User administration** dropdown.
+1. Select the **{settings}** **User administration** dropdown list.
1. Select **Unban user**.
The user's state is set to active and they consume a
@@ -283,3 +283,68 @@ You can also delete a user and their contributions, such as merge requests, issu
NOTE:
Before 15.1, additionally groups of which deleted user were the only owner among direct members were deleted.
+
+## Troubleshooting
+
+When moderating users, you may need to perform bulk actions on them based on certain conditions. The following rails console scripts show some examples of this. You may [start a rails console session](../../administration/operations/rails_console.md#starting-a-rails-console-session) and use scripts similar to the following:
+
+### Deactivate users that have no recent activity
+
+Administrators can deactivate users that have no recent activity.
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
+```ruby
+days_inactive = 90
+inactive_users = User.active.where("last_activity_on <= ?", days_inactive.days.ago)
+
+inactive_users.each do |user|
+ puts "user '#{user.username}': #{user.last_activity_on}"
+ user.deactivate!
+end
+```
+
+### Block users that have no recent activity
+
+Administrators can block users that have no recent activity.
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
+```ruby
+days_inactive = 90
+inactive_users = User.active.where("last_activity_on <= ?", days_inactive.days.ago)
+
+inactive_users.each do |user|
+ puts "user '#{user.username}': #{user.last_activity_on}"
+ user.block!
+end
+```
+
+### Block or delete users that have no projects or groups
+
+Administrators can block or delete users that have no projects or groups.
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
+```ruby
+users = User.where('id NOT IN (select distinct(user_id) from project_authorizations)')
+
+# How many users are removed?
+users.count
+
+# If that count looks sane:
+
+# You can either block the users:
+users.each { |user| user.blocked? ? nil : user.block! }
+
+# Or you can delete them:
+ # need 'current user' (your user) for auditing purposes
+current_user = User.find_by(username: '<your username>')
+
+users.each do |user|
+ DeleteUserWorker.perform_async(current_user.id, user.id)
+end
+```
diff --git a/doc/user/admin_area/monitoring/health_check.md b/doc/user/admin_area/monitoring/health_check.md
index e6f9c045329..2939a8b0418 100644
--- a/doc/user/admin_area/monitoring/health_check.md
+++ b/doc/user/admin_area/monitoring/health_check.md
@@ -143,6 +143,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
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 432205d8fa2..f700b8b1ea3 100644
--- a/doc/user/admin_area/reporting/git_abuse_rate_limit.md
+++ b/doc/user/admin_area/reporting/git_abuse_rate_limit.md
@@ -4,18 +4,20 @@ group: Anti-Abuse
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Git abuse rate limit **(ULTIMATE SELF)**
+# Git abuse rate limit (administration) **(ULTIMATE SELF)**
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8066) in GitLab 15.2 [with flags](../../../administration/feature_flags.md) named `git_abuse_rate_limit_feature_flag` and `auto_ban_user_on_excessive_projects_download`. Both flags are disabled by default.
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8066) in GitLab 15.2 [with a flag](../../../administration/feature_flags.md) named `git_abuse_rate_limit_feature_flag`. 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](../../../administration/feature_flags.md) named `git_abuse_rate_limit_feature_flag` and `auto_ban_user_on_excessive_projects_download`.
+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 not available.
-Git abuse rate limiting is a feature to automatically [ban users](../moderate_users.md#ban-and-unban-users) who download more than a specified number of repositories in a given time. When the `git_abuse_rate_limit_feature_flag` feature flag is enabled, the administrator receives 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 within a given time frame. Banned users cannot sign in to the instance and cannot access any non-public group via HTTP or SSH.
-When the `auto_ban_user_on_excessive_projects_download` is not enabled, the user is not banned automatically. You can use this setup to determine the correct values of the rate limit settings.
+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.
-When both flags are enabled, the administrator receives an email when a user is about to be banned, and the user is automatically banned from the GitLab instance.
+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.
+
+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.
## Configure Git abuse rate limiting
@@ -24,6 +26,15 @@ When both flags are enabled, the administrator receives an email when a user is
1. Expand **Git abuse rate limit**.
1. Update the Git abuse rate limit settings:
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`. 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 users by adding them to the **Excluded users** field. Excluded users are not automatically banned.
+ 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. 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**.
+
+## Unban a user
+
+1. On the top bar, select **Main menu > Admin**.
+1. On the left sidebar, select **Overview > Users**.
+1. Select the **Banned** tab and search for the account you want to unban.
+1. From the **User administration** dropdown list select **Unban user**.
+1. On the confirmation dialog, select **Unban user**.
diff --git a/doc/user/admin_area/review_abuse_reports.md b/doc/user/admin_area/review_abuse_reports.md
index af2f6640f8e..b8531fded18 100644
--- a/doc/user/admin_area/review_abuse_reports.md
+++ b/doc/user/admin_area/review_abuse_reports.md
@@ -89,6 +89,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
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 cd1f20a2f4e..44a6bbb9d8e 100644
--- a/doc/user/admin_area/settings/account_and_limit_settings.md
+++ b/doc/user/admin_area/settings/account_and_limit_settings.md
@@ -259,18 +259,6 @@ Once a lifetime for access tokens is set, GitLab:
allowed lifetime. Three hours is given to allow administrators to change the allowed lifetime,
or remove it, before revocation takes place.
-<!-- start_remove The following content will be removed on remove_date: '2022-08-22' -->
-## Allow expired access tokens to be used (removed) **(ULTIMATE SELF)**
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214723) in GitLab 13.1.
-> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/296881) in GitLab 13.9.
-> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/351962) in GitLab 14.8.
-> - [Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/351962) in GitLab 15.0.
-
-This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/351962) in GitLab 14.8.
-This feature was [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/351962) in GitLab 15.0.
-<!-- end_remove -->
-
## Disable user profile name changes **(PREMIUM SELF)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24605) in GitLab 12.7.
@@ -288,11 +276,11 @@ When this ability is disabled, GitLab administrators can still use the
[Admin Area](../index.md#administering-users) or the
[API](../../../api/users.md#user-modification) to update usernames.
-## Prevent users from creating top-level groups
+## Prevent new users from creating top-level groups
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/367754) in GitLab 15.5.
-By default, new users can create top-level groups. GitLab administrators can prevent users from creating top-level groups:
+By default, new users can create top-level groups. GitLab administrators can prevent new users from creating top-level groups:
- In GitLab 15.5 and later, using either:
- The GitLab UI using the steps in this section.
@@ -301,7 +289,7 @@ By default, new users can create top-level groups. GitLab administrators can pre
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > General**, then expand **Account and limit**.
-1. Clear the **Allow users to create top-level groups** checkbox.
+1. Clear the **Allow new users to create top-level groups** checkbox.
## Troubleshooting
diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md
index afc9a006b39..adca9c85af1 100644
--- a/doc/user/admin_area/settings/continuous_integration.md
+++ b/doc/user/admin_area/settings/continuous_integration.md
@@ -20,10 +20,10 @@ for all projects:
1. Check (or uncheck to disable) the box that says **Default to Auto DevOps pipeline for all projects**.
1. Optionally, set up the [Auto DevOps base domain](../../../topics/autodevops/requirements.md#auto-devops-base-domain)
which is used for Auto Deploy and Auto Review Apps.
-1. Hit **Save changes** for the changes to take effect.
+1. Select **Save changes** for the changes to take effect.
From now on, every existing project and newly created ones that don't have a
-`.gitlab-ci.yml`, uses the Auto DevOps pipelines.
+`.gitlab-ci.yml` use the Auto DevOps pipelines.
If you want to disable it for a specific project, you can do so in
[its settings](../../../topics/autodevops/index.md#enable-or-disable-auto-devops).
@@ -71,7 +71,7 @@ runner settings:
To view the rendered details:
1. On the top bar, select **Main menu**, and:
- - For a project, select ***Projects** and find your project.
+ - 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 > CI/CD**.
1. Expand **Runners**.
@@ -132,7 +132,7 @@ NOTE:
Any changes to this setting applies to new artifacts only. The expiration time is not
be updated for artifacts created before this setting was changed.
The administrator may need to manually search for and expire previously-created
-artifacts, as described in the [troubleshooting documentation](../../../administration/troubleshooting/gitlab_rails_cheat_sheet.md#remove-artifacts-more-than-a-week-old).
+artifacts, as described in the [troubleshooting documentation](../../../administration/job_artifacts.md#delete-job-artifacts-from-jobs-completed-before-a-specific-date).
## Keep the latest artifacts for all jobs in the latest successful pipelines
@@ -174,7 +174,7 @@ To set the duration for which the jobs are considered as old and expired:
1. On the left sidebar, select **Settings > CI/CD**.
1. Expand the **Continuous Integration and Deployment** section.
1. Set the value of **Archive jobs**.
-1. Hit **Save changes** for the changes to take effect.
+1. Select **Save changes** for the changes to take effect.
After that time passes, the jobs are archived in the background and no longer able to be
retried. Make it empty to never expire jobs. It has to be no less than 1 day,
@@ -201,7 +201,7 @@ of your GitLab instance (`.gitlab-ci.yml` if not set):
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > CI/CD**.
1. Input the new file and path in the **Default CI/CD configuration file** field.
-1. Hit **Save changes** for the changes to take effect.
+1. Select **Save changes** for the changes to take effect.
It is also possible to specify a [custom CI/CD configuration file for a specific project](../../../ci/pipelines/settings.md#specify-a-custom-cicd-configuration-file).
@@ -244,7 +244,7 @@ To enable or disable the banner:
> [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/352316) from GitLab Premium to GitLab Ultimate in 15.0.
NOTE:
-An alternative [compliance solution](../../group/manage.md#configure-a-compliance-pipeline)
+An alternative [compliance solution](../../group/compliance_frameworks.md#configure-a-compliance-pipeline)
is available. We recommend this alternative solution because it provides greater flexibility,
allowing required pipelines to be assigned to specific compliance framework labels.
@@ -272,7 +272,7 @@ To select a CI/CD template for the required pipeline configuration:
1. On the top bar, select **Main menu > Admin**.
1. On the left sidebar, select **Settings > CI/CD**.
1. Expand the **Required pipeline configuration** section.
-1. Select a CI/CD template from the dropdown.
+1. Select a CI/CD template from the dropdown list.
1. Select **Save changes**.
## Package Registry configuration
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 279cac95fc9..8bf0ffd21a5 100644
--- a/doc/user/admin_area/settings/deprecated_api_rate_limits.md
+++ b/doc/user/admin_area/settings/deprecated_api_rate_limits.md
@@ -40,10 +40,10 @@ To override the general user and IP rate limits for requests to deprecated API e
1. Select the checkboxes for the types of rate limits you want to enable:
- **Unauthenticated API request rate limit**
- **Authenticated API request rate limit**
-1. _If you enabled unauthenticated API request rate limits:_
+1. If you selected **unauthenticated**:
1. Select the **Maximum unauthenticated API requests per period per IP**.
1. Select the **Unauthenticated API rate limit period in seconds**.
-1. _If you enabled authenticated API request rate limits:_
+1. If you selected **authenticated**:
1. Select the **Maximum authenticated API requests per period per user**.
1. Select the **Authenticated API rate limit period in seconds**.
diff --git a/doc/user/admin_area/settings/email.md b/doc/user/admin_area/settings/email.md
index 6a7c01ff98b..6d2a3c2cdae 100644
--- a/doc/user/admin_area/settings/email.md
+++ b/doc/user/admin_area/settings/email.md
@@ -92,6 +92,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/admin_area/settings/external_authorization.md b/doc/user/admin_area/settings/external_authorization.md
index 62d3d713616..a34ceac0d95 100644
--- a/doc/user/admin_area/settings/external_authorization.md
+++ b/doc/user/admin_area/settings/external_authorization.md
@@ -115,6 +115,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
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 e5f5064304c..ef9a3674c49 100644
--- a/doc/user/admin_area/settings/files_api_rate_limits.md
+++ b/doc/user/admin_area/settings/files_api_rate_limits.md
@@ -36,10 +36,10 @@ To override the general user and IP rate limits for requests to the Repository f
1. Select the checkboxes for the types of rate limits you want to enable:
- **Unauthenticated API request rate limit**
- **Authenticated API request rate limit**
-1. _If you enabled unauthenticated API request rate limits:_
+1. If you selected **unauthenticated**:
1. Select the **Max unauthenticated API requests per period per IP**.
1. Select the **Unauthenticated API rate limit period in seconds**.
-1. _If you enabled authenticated API request rate limits:_
+1. If you selected **authenticated**:
1. Select the **Max authenticated API requests per period per user**.
1. Select the **Authenticated API rate limit period in seconds**.
diff --git a/doc/user/admin_area/settings/floc.md b/doc/user/admin_area/settings/floc.md
index 08f3e8c09b2..f8137afa40f 100644
--- a/doc/user/admin_area/settings/floc.md
+++ b/doc/user/admin_area/settings/floc.md
@@ -36,6 +36,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/admin_area/settings/help_page.md b/doc/user/admin_area/settings/help_page.md
index a4072f8680b..8d0fef398af 100644
--- a/doc/user/admin_area/settings/help_page.md
+++ b/doc/user/admin_area/settings/help_page.md
@@ -56,7 +56,7 @@ GitLab marketing-related entries are occasionally shown on the Help page. To hid
You can specify a custom URL to which users are directed when they:
-- Select **Support** from the Help dropdown.
+- Select **Support** from the Help dropdown list.
- Select **See our website for help** on the Help page.
1. On the top bar, select **Main menu > Admin**.
@@ -106,6 +106,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/admin_area/settings/index.md b/doc/user/admin_area/settings/index.md
index 1bdacf486a2..08c4a0d0167 100644
--- a/doc/user/admin_area/settings/index.md
+++ b/doc/user/admin_area/settings/index.md
@@ -109,8 +109,8 @@ The **Metrics and profiling** settings contain:
Enable and configure Grafana.
- [Profiling - Performance bar](../../../administration/monitoring/performance/performance_bar.md#enable-the-performance-bar-for-non-administrators) -
Enable access to the Performance Bar for non-administrator users in a given group.
-- [Self monitoring](../../../administration/monitoring/gitlab_self_monitoring_project/index.md#create-the-self-monitoring-project) -
- Enable or disable instance self monitoring.
+- [Self-monitoring](../../../administration/monitoring/gitlab_self_monitoring_project/index.md#create-the-self-monitoring-project) -
+ Enable or disable instance self-monitoring.
- [Usage statistics](usage_statistics.md) - Enable or disable version check and Service Ping.
### Network
diff --git a/doc/user/admin_area/settings/instance_template_repository.md b/doc/user/admin_area/settings/instance_template_repository.md
index b74f4f68230..bf07c5b2808 100644
--- a/doc/user/admin_area/settings/instance_template_repository.md
+++ b/doc/user/admin_area/settings/instance_template_repository.md
@@ -28,7 +28,7 @@ To select a project to serve as the custom template repository:
1. Add custom templates to the selected repository.
After you add templates, you can use them for the entire instance.
-They are available in the [Web Editor's dropdown](../../project/repository/web_editor.md#template-dropdowns)
+They are available in the [Web Editor's dropdown list](../../project/repository/web_editor.md#template-dropdowns)
and through the [API settings](../../../api/settings.md).
## Supported file types and locations
@@ -67,9 +67,9 @@ extension and not be empty. So, the hierarchy should look like this:
|-- another_metrics-dashboard.yml
```
-Your custom templates are displayed on the dropdown menu when a new file is added through the GitLab UI:
+Your custom templates are displayed on the dropdown list when a new file is added through the GitLab UI:
-![Custom template dropdown menu](img/file_template_user_dropdown.png)
+![Custom template dropdown list](img/file_template_user_dropdown.png)
If this feature is disabled or no templates are present,
no **Custom** section displays in the selection dropdown.
@@ -82,6 +82,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/admin_area/settings/package_registry_rate_limits.md b/doc/user/admin_area/settings/package_registry_rate_limits.md
index 7e0c3482e3e..a5c5536f22d 100644
--- a/doc/user/admin_area/settings/package_registry_rate_limits.md
+++ b/doc/user/admin_area/settings/package_registry_rate_limits.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
type: reference
---
diff --git a/doc/user/admin_area/settings/sign_in_restrictions.md b/doc/user/admin_area/settings/sign_in_restrictions.md
index 320768e6e5a..4ea420d7ca6 100644
--- a/doc/user/admin_area/settings/sign_in_restrictions.md
+++ b/doc/user/admin_area/settings/sign_in_restrictions.md
@@ -32,27 +32,70 @@ In the event of an external authentication provider outage, use the [GitLab Rail
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2158) in GitLab 13.10.
-When this feature is enabled, instance administrators are limited as regular users. During that period,
-they do not have access to all projects, groups, or the **Admin Area** menu.
+If you are an administrator, you might want to work in GitLab without the access that
+comes from being an administrator. While you could create a separate user account that
+doesn't have administrator access, a more secure solution is to use *Admin Mode*.
-To access potentially dangerous resources, an administrator can activate Admin Mode by:
+With Admin Mode, your account does not have administrative access by default.
+You can continue to access groups and projects you are a member of, but to access
+administrative functionality, you must authenticate.
-- Selecting the *Enable Admin Mode* button
-- Trying to access any part of the UI that requires administrator access, specifically those which call `/admin` endpoints.
+When Admin Mode is enabled, it applies to all administrators on the instance.
-The main use case allows administrators to perform their regular tasks as a regular
-user, based on their memberships, without having to set up a second account for
-security reasons.
+When Admin Mode is enabled for an instance, administrators:
-When Admin Mode status is disabled, administrative users cannot access resources unless
-they've been explicitly granted access. For example, when Admin Mode is disabled, they
-get a `404` error if they try to open a private group or project, unless
-they are members of that group or project.
+- Are allowed to access group and projects for which they are members.
+- Cannot access the **Admin Area**.
-2FA should be enabled for administrators and is supported for the Admin Mode flow, as are
-OmniAuth providers and LDAP auth. The Admin Mode status is stored in the active user
-session and remains active until it is explicitly disabled (it will be disabled
-automatically after a timeout otherwise).
+### Enable Admin Mode for your instance
+
+Administrators can enable Admin Mode though the API, the Rails console, or the UI.
+
+#### Use the API to enable Admin Mode
+
+Make the following request to your instance endpoint:
+
+```shell
+curl --request PUT --header "PRIVATE-TOKEN:$ADMIN_TOKEN" "<gitlab.example.com>/api/v4/application/settings?admin_mode=true"
+```
+
+Replace `<gitlab.example.com>` with your instance URL.
+
+For more information, see the [list of settings that can be accessed through API calls](../../../api/settings.md).
+
+#### Use the Rails console to enable Admin Mode
+
+Open the [Rails console](../../../administration/operations/rails_console.md) and run the following:
+
+```ruby
+::Gitlab::CurrentSettings.update_attributes!(admin_mode: true)
+```
+
+#### Use the UI to enable Admin Mode
+
+To enable Admin Mode through the UI:
+
+1. On the top bar, select **Main menu > Admin**.
+1. On the left sidebar, select **Settings > General**.
+1. Expand **Sign-in restrictions**.
+1. In the **Admin Mode** section, select the **Require additional authentication for administrative tasks** checkbox.
+
+### Turn on Admin Mode for your session
+
+To turn on Admin Mode for your current session and access potentially dangerous resources:
+
+1. On the top bar, select **Enable Admin Mode**.
+1. Try to access any part of the UI with `/admin` in the URL (which requires administrator access).
+
+When Admin Mode status is disabled or turned off, administrators cannot access resources unless
+they've been explicitly granted access. For example, administrators get a `404` error
+if they try to open a private group or project, unless they are members of that group or project.
+
+2FA should be enabled for administrators. 2FA, OmniAuth providers, and LDAP
+authentication are supported by Admin Mode. Admin Mode status is stored in the current user session and remains active until either:
+
+- It is explicitly disabled.
+- It is disabled automatically after a timeout.
### Limitations of Admin Mode
diff --git a/doc/user/admin_area/settings/sign_up_restrictions.md b/doc/user/admin_area/settings/sign_up_restrictions.md
index 28fb188731b..76415596dce 100644
--- a/doc/user/admin_area/settings/sign_up_restrictions.md
+++ b/doc/user/admin_area/settings/sign_up_restrictions.md
@@ -115,7 +115,7 @@ create or update pipelines until their email address is confirmed.
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20661) in GitLab 12.6
-You can [change](../../../security/password_length_limits.md#modify-minimum-password-length-using-gitlab-ui)
+You can [change](../../../security/password_length_limits.md#modify-minimum-password-length)
the minimum number of characters a user must have in their password using the GitLab UI.
### Password complexity requirements **(PREMIUM SELF)**
@@ -198,6 +198,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/admin_area/settings/terms.md b/doc/user/admin_area/settings/terms.md
index 28fe352c684..9a02e50b23f 100644
--- a/doc/user/admin_area/settings/terms.md
+++ b/doc/user/admin_area/settings/terms.md
@@ -43,6 +43,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/admin_area/settings/third_party_offers.md b/doc/user/admin_area/settings/third_party_offers.md
index fbd282ed5ad..8d2ae72ba69 100644
--- a/doc/user/admin_area/settings/third_party_offers.md
+++ b/doc/user/admin_area/settings/third_party_offers.md
@@ -31,6 +31,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/admin_area/settings/usage_statistics.md b/doc/user/admin_area/settings/usage_statistics.md
index fb027b462df..df60268a8bf 100644
--- a/doc/user/admin_area/settings/usage_statistics.md
+++ b/doc/user/admin_area/settings/usage_statistics.md
@@ -48,7 +48,7 @@ tier. Users can continue to access the features in a paid tier without sharing u
### Features available in 14.4 and later
- [Repository size limit](../settings/account_and_limit_settings.md#repository-size-limit).
-- [Group access restriction by IP address](../../group/access_and_permissions.md#restrict-group-access-by-ip-address).
+- [Group access restriction by IP address](../../group/access_and_permissions.md#restrict-access-to-groups-by-ip-address).
NOTE:
Registration is not yet required for participation, but may be added in a future milestone.
@@ -202,6 +202,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/admin_area/settings/user_and_ip_rate_limits.md b/doc/user/admin_area/settings/user_and_ip_rate_limits.md
index 7431fc329d1..e285275f5bb 100644
--- a/doc/user/admin_area/settings/user_and_ip_rate_limits.md
+++ b/doc/user/admin_area/settings/user_and_ip_rate_limits.md
@@ -225,6 +225,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
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 d3132ae03c6..6d878bcb01c 100644
--- a/doc/user/admin_area/settings/visibility_and_access_controls.md
+++ b/doc/user/admin_area/settings/visibility_and_access_controls.md
@@ -45,7 +45,7 @@ By default both administrators and anyone with the **Owner** role can delete a p
1. Expand the **Visibility and access controls** section.
1. Scroll to:
- (GitLab 15.1 and later) **Allowed to delete projects**, and select **Administrators**.
- - (GitLab 15.0 and earlier) **Default project deletion projection** and select **Only admins can delete project**.
+ - (GitLab 15.0 and earlier) **Default project deletion protection** and select **Only admins can delete project**.
1. Select **Save changes**.
## Deletion protection **(PREMIUM SELF)**
@@ -82,8 +82,8 @@ To configure delayed project deletion:
1. On the left sidebar, select **Settings > General**.
1. Expand the **Visibility and access controls** section.
1. Scroll to:
- - (GitLab 15.1 and later) **Deletion projection** and select keep deleted groups and projects, and select a retention period.
- - (GitLab 15.0 and earlier) **Default delayed project projection** and select **Enable delayed project deletion by
+ - (GitLab 15.1 and later) **Deletion protection** and select keep deleted groups and projects, and select a retention period.
+ - (GitLab 15.0 and earlier) **Default delayed project protection** and select **Enable delayed project deletion by
default for newly-created groups.** Then set a retention period in **Default deletion delay**.
1. Select **Save changes**.
@@ -262,7 +262,7 @@ These options specify the permitted types and lengths for SSH keys.
To specify a restriction for each key type:
-1. Select the desired option from the dropdown.
+1. Select the desired option from the dropdown list.
1. Select **Save changes**.
For more details, see [SSH key restrictions](../../../security/ssh_keys_restrictions.md).
@@ -280,13 +280,13 @@ work in every repository. They can only be re-enabled by an administrator user o
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87579) in GitLab 15.1 [with a flag](../../../administration/feature_flags.md) named `group_ip_restrictions_allow_global`. Disabled by default.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/366445) in GitLab 15.4. [Feature flag `group_ip_restrictions_allow_global`](https://gitlab.com/gitlab-org/gitlab/-/issues/366445) removed.
-This setting allows you to set IP address ranges to be combined with group-level IP allowlists.
-It helps administrators prevent aspects of the GitLab installation from being blocked
-from working as intended when an IP allowlist is used.
+Administrators can set IP address ranges to be combined with [group-level IP restrictions](../../group/access_and_permissions.md#restrict-access-to-groups-by-ip-address).
+Use globally-allowed IP addresses to allow aspects of the GitLab installation to work even when group-level IP address
+restrictions are set.
-For example, if the GitLab Pages daemon runs on the `10.0.0.0/24` range, specify that range in this
-field, as otherwise any group-level restrictions that don't include that range cause the Pages
-daemon to be unable to fetch artifacts from the pipeline runs.
+For example, if the GitLab Pages daemon runs on the `10.0.0.0/24` range, you can specify that range as globally-allowed.
+This means GitLab Pages can still fetch artifacts from pipelines even if group-level IP address restrictions don't
+include the `10.0.0.0/24` range.
To add a IP address range to the group-level allowlist:
@@ -294,7 +294,11 @@ To add a IP address range to the group-level allowlist:
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. In **Globally-allowed IP ranges**, provide a value.
+1. In **Globally-allowed IP ranges**, provide a list of IP address ranges. This list:
+ - Has no limit on the number of IP address ranges.
+ - Has a size limit of 1 GB.
+ - Applies to both SSH or HTTP authorized IP address ranges. You cannot split
+ this list by type of authorization.
1. Select **Save changes**.
<!-- ## Troubleshooting
@@ -305,6 +309,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/analytics/ci_cd_analytics.md b/doc/user/analytics/ci_cd_analytics.md
index de9275b8599..ef2d3a76990 100644
--- a/doc/user/analytics/ci_cd_analytics.md
+++ b/doc/user/analytics/ci_cd_analytics.md
@@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# CI/CD analytics **(FREE)**
-Use the CI/CD analytics page to view pipeline success rates and duration, and the history of [DORA metrics](index.md#devops-research-and-assessment-dora-key-metrics) over time.
+Use the CI/CD analytics page to view pipeline success rates and duration, and the history of DORA metrics over time.
## Pipeline success and duration charts
@@ -35,7 +35,7 @@ To view CI/CD analytics:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Analytics > CI/CD Analytics**.
-## View deployment frequency chart **(ULTIMATE)**
+## View DORA deployment frequency chart **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/275991) in GitLab 13.8.
@@ -44,7 +44,7 @@ frequency to the `production` environment. The environment must be part of the
[production deployment tier](../../ci/environments/index.md#deployment-tier-of-environments)
for its deployment information to appear on the graphs.
- Deployment frequency is one of the four [DORA metrics](index.md#devops-research-and-assessment-dora-key-metrics) that DevOps teams use for measuring excellence in software delivery.
+ Deployment frequency is one of the four DORA metrics that DevOps teams use for measuring excellence in software delivery.
The deployment frequency chart is available for groups and projects.
@@ -56,7 +56,7 @@ To view the deployment frequency chart:
![Deployment frequency](img/deployment_frequency_charts_v13_12.png)
-## View lead time for changes chart **(ULTIMATE)**
+## View DORA lead time for changes chart **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/250329) in GitLab 13.11.
@@ -68,7 +68,7 @@ merge requests to be deployed to a production environment. This chart is availab
- For time periods in which no merge requests were deployed, the charts render a
red, dashed line.
- Lead time for changes is one of the four [DORA metrics](index.md#devops-research-and-assessment-dora-key-metrics) that DevOps teams use for measuring excellence in software delivery.
+ Lead time for changes is one of the four DORA metrics that DevOps teams use for measuring excellence in software delivery.
To view the lead time for changes chart:
@@ -78,13 +78,13 @@ To view the lead time for changes chart:
![Lead time](img/lead_time_chart_v13_11.png)
-## View time to restore service chart **(ULTIMATE)**
+## View DORA time to restore service chart **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/356959) in GitLab 15.1
The time to restore service chart shows information about the median time an incident was open in a production environment. This chart is available for groups and projects.
-Time to restore service is one of the four [DORA metrics](index.md#devops-research-and-assessment-dora-key-metrics) that DevOps teams use for measuring excellence in software delivery.
+Time to restore service is one of the four DORA metrics that DevOps teams use for measuring excellence in software delivery.
To view the time to restore service chart:
@@ -94,13 +94,13 @@ To view the time to restore service chart:
![Lead time](img/time_to_restore_service_charts_v15_1.png)
-## View change failure rate chart **(ULTIMATE)**
+## View DORA change failure rate chart **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357072) in GitLab 15.2
The change failure rate chart shows information about the percentage of deployments that cause an incident in a production environment. This chart is available for groups and projects.
-Change failure rate is one of the four [DORA metrics](index.md#devops-research-and-assessment-dora-key-metrics) that DevOps teams use for measuring excellence in software delivery.
+Change failure rate is one of the four DORA metrics that DevOps teams use for measuring excellence in software delivery.
To view the change failure rate chart:
diff --git a/doc/user/analytics/dora_metrics.md b/doc/user/analytics/dora_metrics.md
new file mode 100644
index 00000000000..b5f37203817
--- /dev/null
+++ b/doc/user/analytics/dora_metrics.md
@@ -0,0 +1,127 @@
+---
+stage: Plan
+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
+---
+
+# DevOps Research and Assessment (DORA) metrics **(ULTIMATE)**
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/275991) in GitLab 13.7.
+> - [Added support](https://gitlab.com/gitlab-org/gitlab/-/issues/291746) for lead time for changes in GitLab 13.10.
+
+The [DevOps Research and Assessment (DORA)](https://cloud.google.com/blog/products/devops-sre/using-the-four-keys-to-measure-your-devops-performance)
+team has identified four metrics that measure DevOps performance.
+Using these metrics helps improve DevOps efficiency and communicate performance to business stakeholders, which can accelerate business results.
+
+DORA includes four key metrics, divided into two core areas of DevOps:
+
+- [Deployment Frequency](#deployment-frequency) and [Lead Time for Change](#lead-time-for-changes) measure team velocity.
+- [Change Failure Rate](#change-failure-rate) and [Time to Restore Service](#time-to-restore-service) measure stability.
+
+For software leaders, tracking velocity alongside quality metrics ensures they're not sacrificing quality for speed.
+
+<div class="video-fallback">
+ For an overview, see <a href="https://www.youtube.com/watch?v=1BrcMV6rCDw">GitLab Speed Run: DORA metrics in GitLab One DevOps Platform</a>.
+</div>
+<figure class="video-container">
+ <iframe src="https://www.youtube.com/embed/1BrcMV6rCDw" frameborder="0" allowfullscreen="true"> </iframe>
+</figure>
+
+## 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).
+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.
+This enables teams and managers to understand all aspects of productivity, quality, and delivery, without the ["toolchain tax"](https://about.gitlab.com/solutions/value-stream-management/).
+
+## 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 displays in several charts:
+
+- [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)
+
+To retrieve metrics for deployment frequency, use the [GraphQL](../../api/graphql/reference/index.md) or the [REST](../../api/dora/metrics.md) APIs.
+
+## 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.
+
+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.
+
+Over time, the lead time for changes should decrease, while your team's performance should increase.
+
+Lead time for changes displays in several charts:
+
+- [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)
+
+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 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).
+
+## 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:
+
+- 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).
+
+Time to restore service displays in several charts:
+
+- [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)
+
+To retrieve metrics for time to restore service, use the [GraphQL](../../api/graphql/reference/index.md) or the [REST](../../api/dora/metrics.md) APIs.
+
+## 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:
+
+- 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.
+
+To retrieve metrics for change failure rate, use the [GraphQL](../../api/graphql/reference/index.md) or the [REST](../../api/dora/metrics.md) APIs.
+
+### Insights: Custom DORA reporting
+
+Custom charts to visualize DORA data with Insights YAML-based reports.
+
+With this new visualization, software leaders can track metrics improvements, understand patterns in their metrics trends, and compare performance between groups and projects.
+
+### Measure DORA metrics without using GitLab CI/CD pipelines
+
+Deployment frequency is calculated based on the deployments record, which is created for typical push-based deployments.
+These deployment records are not created for pull-based deployments, for example when Container Images are connected to GitLab with an agent.
+
+To track DORA metrics in these cases, you can [create a deployment record](../../api/deployments.md#create-a-deployment) using the Deployments API.
+
+### Supported DORA metrics in GitLab
+
+| Metric | Level | API | UI chart | Comments |
+|---------------------------|-------------------|-----------------------------------------------------|------------------------|----------|
+| `deployment_frequency` | Project | [GitLab 13.7 and later](../../api/dora/metrics.md) | GitLab 14.8 and later | The previous API endpoint was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/323713) in 13.10. |
+| `deployment_frequency` | Group | [GitLab 13.10 and later](../../api/dora/metrics.md) | GitLab 13.12 and later | |
+| `lead_time_for_changes` | Project | [GitLab 13.10 and later](../../api/dora/metrics.md) | GitLab 13.11 and later | Unit in seconds. Aggregation method is median. |
+| `lead_time_for_changes` | Group | [GitLab 13.10 and later](../../api/dora/metrics.md) | GitLab 14.0 and later | Unit in seconds. Aggregation method is median. |
+| `time_to_restore_service` | Project and group | [GitLab 14.9 and later](../../api/dora/metrics.md) | GitLab 15.1 and later | Unit in days. Aggregation method is median. |
+| `change_failure_rate` | Project and group | [GitLab 14.10 and later](../../api/dora/metrics.md) | GitLab 15.2 and later | Percentage of deployments. |
diff --git a/doc/user/analytics/index.md b/doc/user/analytics/index.md
index 56adbff9f59..01fe466755c 100644
--- a/doc/user/analytics/index.md
+++ b/doc/user/analytics/index.md
@@ -34,7 +34,7 @@ GitLab provides several analytics features at the group level. Some of these fea
You can use GitLab to review analytics at the project level. Some of these features require you to use a higher tier than GitLab Free.
- [Application Security](../application_security/security_dashboard/index.md)
-- [CI/CD](ci_cd_analytics.md)
+- [CI/CD & DORA](ci_cd_analytics.md)
- [Code Review](code_review_analytics.md)
- [Insights](../project/insights/index.md)
- [Issue](../group/issues_analytics/index.md)
@@ -51,93 +51,6 @@ The following analytics features are available for users to create personalized
Be sure to review the documentation page for this feature for GitLab tier requirements.
-## DevOps Research and Assessment (DORA) key metrics **(ULTIMATE)**
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/275991) in GitLab 13.7.
-> - [Added support](https://gitlab.com/gitlab-org/gitlab/-/issues/291746) for lead time for changes in GitLab 13.10.
-
-The [DevOps Research and Assessment (DORA)](https://cloud.google.com/blog/products/devops-sre/using-the-four-keys-to-measure-your-devops-performance)
-team developed several key metrics that you can use as performance indicators for software development
-teams.
-
-### 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 displays in several charts:
-
-- [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)
-
-To retrieve metrics for deployment frequency, use the [GraphQL](../../api/graphql/reference/index.md) or the [REST](../../api/dora/metrics.md) APIs.
-
-### Lead time for changes
-
-DORA Lead time for changes measures the time to successfully deliver a feature into production.
-This metric reflects the efficiency of CI/CD pipelines.
-
-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.
-
-Over time, the lead time for changes should decrease, while your team's performance should increase.
-
-Lead time for changes displays in several charts:
-
-- [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)
-
-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 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 issue to move from the moment it's requested (Issue created) to the time it's fulfilled and delivered (Issue closed).
-
-### 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:
-
-- 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).
-
-Time to restore service displays in several charts:
-
-- [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)
-
-To retrieve metrics for time to restore service, use the [GraphQL](../../api/graphql/reference/index.md) or the [REST](../../api/dora/metrics.md) APIs.
-
-### 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:
-
-- 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.
-
-To retrieve metrics for change failure rate, use the [GraphQL](../../api/graphql/reference/index.md) or the [REST](../../api/dora/metrics.md) APIs.
-
-### Supported DORA metrics in GitLab
-
-| Metric | Level | API | UI chart | Comments |
-|---------------------------|-------------------|-----------------------------------------------------|------------------------|----------|
-| `deployment_frequency` | Project | [GitLab 13.7 and later](../../api/dora/metrics.md) | GitLab 14.8 and later | The previous API endpoint was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/323713) in 13.10. |
-| `deployment_frequency` | Group | [GitLab 13.10 and later](../../api/dora/metrics.md) | GitLab 13.12 and later | |
-| `lead_time_for_changes` | Project | [GitLab 13.10 and later](../../api/dora/metrics.md) | GitLab 13.11 and later | Unit in seconds. Aggregation method is median. |
-| `lead_time_for_changes` | Group | [GitLab 13.10 and later](../../api/dora/metrics.md) | GitLab 14.0 and later | Unit in seconds. Aggregation method is median. |
-| `time_to_restore_service` | Project and group | [GitLab 14.9 and later](../../api/dora/metrics.md) | GitLab 15.1 and later | Unit in days. Aggregation method is median. |
-| `change_failure_rate` | Project and group | [GitLab 14.10 and later](../../api/dora/metrics.md) | GitLab 15.2 and later | Percentage of deployments. |
-
## Definitions
We use the following terms to describe GitLab analytics:
diff --git a/doc/user/application_security/api_fuzzing/create_har_files.md b/doc/user/application_security/api_fuzzing/create_har_files.md
index 445bcfb0444..e7eaf47121b 100644
--- a/doc/user/application_security/api_fuzzing/create_har_files.md
+++ b/doc/user/application_security/api_fuzzing/create_har_files.md
@@ -93,7 +93,7 @@ used in [Web API Fuzz Testing](index.md#http-archive-har).
1. Select **Export Data > Current Workspace**.
1. Select requests to include in the HAR file.
1. Select **Export**.
-1. In the **Select Export Type** dropdown select **HAR -- HTTP Archive Format**.
+1. In the **Select Export Type** dropdown list select **HAR -- HTTP Archive Format**.
1. Select **Done**.
1. Enter a location and filename for the HAR file.
@@ -109,7 +109,7 @@ responses in HAR format.
have an account, first create an account.
1. Browse pages that call an API. Fiddler automatically captures the requests.
1. Select one or more requests, then from the context menu, select **Export > Selected Sessions**.
-1. In the **Choose Format** dropdown select **HTTPArchive v1.2**.
+1. In the **Choose Format** dropdown list select **HTTPArchive v1.2**.
1. Enter a filename and select **Save**.
Fiddler shows a popup message confirming the export has succeeded.
diff --git a/doc/user/application_security/api_fuzzing/index.md b/doc/user/application_security/api_fuzzing/index.md
index d542c2d4be5..03eed6fdbf8 100644
--- a/doc/user/application_security/api_fuzzing/index.md
+++ b/doc/user/application_security/api_fuzzing/index.md
@@ -1211,7 +1211,7 @@ Example usage for setting a `body-json` override:
}
```
-Note that each JSON property name in the object `body-json` is set to a [JSON Path](https://goessner.net/articles/JsonPath/)
+Each JSON property name in the object `body-json` is set to a [JSON Path](https://goessner.net/articles/JsonPath/)
expression. The JSON Path expression `$.credentials.access-token` identifies the node to be
overridden with the value `iddqd!42.$`. The override engine uses `body-json` when the request body
has only [JSON](https://www.json.org/json-en.html) content.
@@ -1250,7 +1250,7 @@ the second entry overrides an XML element:
}
```
-Note that each JSON property name in the object `body-xml` is set to an
+Each JSON property name in the object `body-xml` is set to an
[XPath v2](https://www.w3.org/TR/xpath20/)
expression. The XPath expression `/credentials/@isEnabled` identifies the attribute node to override
with the value `true`. The XPath expression `/credentials/access-token/text()` identifies the
@@ -1392,7 +1392,7 @@ It is also possible to write messages from your script to a log file that is col
Adding some basic logging to your overrides script is useful in case the script fails unexpectedly during normal running of the job. The log file is automatically included as an artifact of the job, allowing you to download it after the job has finished.
-Following our example, we provided `renew_token.py` in the environmental variable `FUZZAPI_OVERRIDES_CMD`. Please notice two things in the script:
+Following our example, we provided `renew_token.py` in the environmental variable `FUZZAPI_OVERRIDES_CMD`. Notice two things in the script:
- Log file is saved in the location indicated by the environment variable `CI_PROJECT_DIR`.
- Log filename should match `gl-*.log`.
@@ -1871,7 +1871,7 @@ variables:
##### Excluding two URLs and their child resources
-In order to exclude the URLs: `http://target/api/buy` and `http://target/api/sell`, and their child resources. To provide multiple URLs we use the `,` character as follows:
+To exclude the URLs: `http://target/api/buy` and `http://target/api/sell`, and their child resources. To provide multiple URLs we use the `,` character as follows:
```yaml
stages:
@@ -1888,7 +1888,11 @@ variables:
##### Excluding URL using regular expressions
-In order to exclude exactly `https://target/api/v1/user/create` and `https://target/api/v2/user/create` or any other version (`v3`,`v4`, and more). We could use `https://target/api/v.*/user/create$`, in the previous regular expression `.` indicates any character and `*` indicates zero or more times, additionally `$` indicates that the URL should end there.
+To exclude exactly `https://target/api/v1/user/create` and `https://target/api/v2/user/create` or any other version (`v3`,`v4`, and more), we could use `https://target/api/v.*/user/create$`. In the previous regular expression:
+
+- `.` indicates any character.
+- `*` indicates zero or more times.
+- `$` indicates that the URL should end there.
```yaml
stages:
@@ -2211,9 +2215,235 @@ Setting `SECURE_ANALYZERS_PREFIX` changes the Docker image registry location for
For more information, see [Offline environments](../offline_deployments/index.md).
+## Performance tuning and testing speed
+
+Security tools that perform API fuzz testing, such as API Fuzzing, perform testing by sending requests to an instance of your running application. The requests are mutated by our fuzzing engine to trigger unexpected behavior that might exist in your application. The speed of an API fuzzing test depends on the following:
+
+- How many requests per second can be sent to your application by our tooling
+- How fast your application responds to requests
+- How many requests must be sent to test the application
+ - How many operations your API is comprised of
+ - How many fields are in each operation (think JSON bodies, headers, query string, cookies, etc.)
+
+If API Fuzzing testing job still takes longer than expected after following the advice in this performance guide, reach out to support for further assistance.
+
+### Diagnosing performance issues
+
+The first step to resolving performance issues is to understand what is contributing to the slower-than-expected testing time. Some common issues we see are:
+
+- API Fuzzing is running on a slow or single-CPU GitLab Runner (GitLab Shared Runners are single-CPU)
+- The application deployed to a slow/single-CPU instance and is not able to keep up with the testing load
+- The application contains a slow operation that impacts the overall test speed (> 1/2 second)
+- The application contains an operation that returns a large amount of data (> 500K+)
+- The application contains a large number of operations (> 40)
+
+#### The application contains a slow operation that impacts the overall test speed (> 1/2 second)
+
+The API Fuzzing job output contains helpful information about how fast we are testing, how fast each operation being tested responds, and summary information. Let's take a look at some sample output to see how it can be used in tracking down performance issues:
+
+```shell
+API Security: Loaded 10 operations from: assets/har-large-response/large_responses.har
+API Security:
+API Security: Testing operation [1/10]: 'GET http://target:7777/api/large_response_json'.
+API Security: - Parameters: (Headers: 4, Query: 0, Body: 0)
+API Security: - Request body size: 0 Bytes (0 bytes)
+API Security:
+API Security: Finished testing operation 'GET http://target:7777/api/large_response_json'.
+API Security: - Excluded Parameters: (Headers: 0, Query: 0, Body: 0)
+API Security: - Performed 767 requests
+API Security: - Average response body size: 130 MB
+API Security: - Average call time: 2 seconds and 82.69 milliseconds (2.082693 seconds)
+API Security: - Time to complete: 14 minutes, 8 seconds and 788.36 milliseconds (848.788358 seconds)
+```
+
+This job console output snippet starts by telling us how many operations were found (10), followed by notifications that testing has started on a specific operation and a summary of the operation has been completed. The summary is the most interesting part of this log output. In the summary, we can see that it took API Fuzzing 767 requests to fully test this operation and its related fields. We can also see that the average response time was 2 seconds and the time to complete was 14 minutes for this one operation.
+
+An average response time of 2 seconds is a good initial indicator that this specific operation takes a long time to test. Further, we can see that the response body size is quite large. The large body size is the culprit here, transferring that much data on each request is what takes the majority of that 2 seconds.
+
+For this issue, the team might decide to:
+
+- Use a multi-CPU runner. Using a multi-CPU runner allows API Fuzzing to parallelize the work being performed. This helps lower the test time, but getting the test down under 10 minutes might still be problematic without moving to a high CPU machine due to how long the operation takes to test.
+ - Trade off between how many CPUs and cost.
+- [Exclude this operation](#excluding-slow-operations) from the API Fuzzing test. While this is the simplest, it has the downside of a gap in security test coverage.
+- [Exclude the operation from feature branch API Fuzzing tests, but include it in the default branch test](#excluding-operations-in-feature-branches-but-not-default-branch).
+- [Split up the API Fuzzing testing into multiple jobs](#splitting-a-test-into-multiple-jobs).
+
+The likely solution is to use a combination of these solutions to reach an acceptable test time, assuming your team's requirements are in the 5-7 minute range.
+
+### Addressing performance issues
+
+The following sections document various options for addressing performance issues for API Fuzzing:
+
+- [Using a multi-CPU Runner](#using-a-multi-cpu-runner)
+- [Excluding slow operations](#excluding-slow-operations)
+- [Splitting a test into multiple jobs](#splitting-a-test-into-multiple-jobs)
+- [Excluding operations in feature branches, but not default branch](#excluding-operations-in-feature-branches-but-not-default-branch)
+
+#### Using a multi-CPU Runner
+
+One of the easiest performance boosts can be achieved using a multi-CPU runner with API Fuzzing. This table shows statistics collected during benchmarking of a Java Spring Boot REST API. In this benchmark, the target and API Fuzzing share a single runner instance.
+
+| CPU Count | Request per Second |
+|----------------------|--------------------|
+| 1 CPU (Shared Runner)| 75 |
+| 4 CPU | 255 |
+| 8 CPU | 400 |
+
+As we can see from this table, increasing the CPU count of the runner can have a large impact on testing speed/performance.
+
+To use a multi-CPU typically requires deploying a self-managed GitLab Runner onto a multi-CPU machine or cloud compute instance.
+
+When multiple types of GitLab Runners are available for use, the various instances are commonly set up with tags that can be used in the job definition to select a type of runner.
+
+Here is an example job definition for API Fuzzing that adds a `tags` section with the tag `multi-cpu`. The job automatically extends the job definition included through the API Fuzzing template.
+
+```yaml
+apifuzzer_fuzz:
+ tags:
+ - multi-cpu
+```
+
+To verify that API Fuzzing can detect multiple CPUs in the runner, download the `gl-api-security-scanner.log` file from a completed job's artifacts. Search the file for the string `Starting work item processor` and inspect the reported max DOP (degree of parallelism). The max DOP should be greater than or equal to the number of CPUs assigned to the runner. The value is never lower than 2, even on single CPU runners, unless forced through a configuration variable. If the value reported is less than the number of CPUs assigned to the runner, then something is wrong with the runner deployment. If unable to identify the problem, open a ticket with support to assist.
+
+Example log entry:
+
+`17:00:01.084 [INF] <Peach.Web.Core.Services.WebRunnerMachine> Starting work item processor with 2 max DOP`
+
+#### Excluding slow operations
+
+In the case of one or two slow operations, the team might decide to skip testing the operations. Excluding the operation is done using the `FUZZAPI_EXCLUDE_PATHS` configuration [variable as explained in this section.](#exclude-paths)
+
+In this example, we have an operation that returns a large amount of data. The operation is `GET http://target:7777/api/large_response_json`. To exclude it we provide the `FUZZAPI_EXCLUDE_PATHS` configuration variable with the path portion of our operation URL `/api/large_response_json`.
+
+To verify the operation is excluded, run the API Fuzzing job and review the job console output. It includes a list of included and excluded operations at the end of the test.
+
+```yaml
+apifuzzer_fuzz:
+ variables:
+ FUZZAPI_EXCLUDE_PATHS: /api/large_response_json
+```
+
+Excluding operations from testing could allow some vulnerabilities to go undetected.
+{: .alert .alert-warning}
+
+#### Splitting a test into multiple jobs
+
+Splitting a test into multiple jobs is supported by API Fuzzing through the use of [`FUZZAPI_EXCLUDE_PATHS`](#exclude-paths) and [`FUZZAPI_EXCLUDE_URLS`](#exclude-urls). When splitting a test up, a good pattern is to disable the `apifuzzer_fuzz` job and replace it with two jobs with identifying names. In this example we have two jobs, each job is testing a version of the API, so our names reflect that. However, this technique can be applied to any situation, not just with versions of an API.
+
+The rules we are using in the `apifuzzer_v1` and `apifuzzer_v2` jobs are copied from the [API Fuzzing template](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/DAST-API.gitlab-ci.yml).
+
+```yaml
+# Disable the main apifuzzer_fuzz job
+apifuzzer_fuzz:
+ rules:
+ - if: $CI_COMMIT_BRANCH
+ when: never
+
+apifuzzer_v1:
+ extends: apifuzzer_fuzz
+ variables:
+ FUZZAPI_EXCLUDE_PATHS: /api/v1/**
+ rules:
+ rules:
+ - if: $API_FUZZING_DISABLED
+ when: never
+ - if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ FUZZAPI_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH
+
+apifuzzer_v2:
+ variables:
+ FUZZAPI_EXCLUDE_PATHS: /api/v2/**
+ rules:
+ rules:
+ - if: $API_FUZZING_DISABLED
+ when: never
+ - if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ FUZZAPI_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH
+```
+
+#### Excluding operations in feature branches, but not default branch
+
+In the case of one or two slow operations, the team might decide to skip testing the operations, or exclude them from feature branch tests, but include them for default branch tests. Excluding the operation is done using the `FUZZAPI_EXCLUDE_PATHS` configuration [variable as explained in this section.](#exclude-paths)
+
+In this example, we have an operation that returns a large amount of data. The operation is `GET http://target:7777/api/large_response_json`. To exclude it we provide the `FUZZAPI_EXCLUDE_PATHS` configuration variable with the path portion of our operation URL `/api/large_response_json`. Our configuration disables the main `apifuzzer_fuzz` job and creates two new jobs `apifuzzer_main` and `apifuzzer_branch`. The `apifuzzer_branch` is set up to exclude the long operation and only run on non-default branches (e.g. feature branches). The `apifuzzer_main` branch is set up to only execute on the default branch (`main` in this example). The `apifuzzer_branch` jobs run faster, allowing for quick development cycles, while the `apifuzzer_main` job which only runs on default branch builds, takes longer to run.
+
+To verify the operation is excluded, run the API Fuzzing job and review the job console output. It includes a list of included and excluded operations at the end of the test.
+
+```yaml
+# Disable the main job so we can create two jobs with
+# different names
+apifuzzer_fuzz:
+ rules:
+ - if: $CI_COMMIT_BRANCH
+ when: never
+
+# API Fuzzing for feature branch work, excludes /api/large_response_json
+apifuzzer_branch:
+ extends: apifuzzer_fuzz
+ variables:
+ FUZZAPI_EXCLUDE_PATHS: /api/large_response_json
+ rules:
+ rules:
+ - if: $API_FUZZING_DISABLED
+ when: never
+ - if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ FUZZAPI_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+ when: never
+ - if: $CI_COMMIT_BRANCH
+
+# API Fuzzing for default branch (main in our case)
+# Includes the long running operations
+apifuzzer_main:
+ extends: apifuzzer_fuzz
+ rules:
+ - if: $API_FUZZING_DISABLED
+ when: never
+ - if: $API_FUZZING_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ FUZZAPI_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+```
+
## Troubleshooting
-### `Error waiting for API Security 'http://127.0.0.1:5000' to become available`
+### API Fuzzing job times out after N hours
+
+The top two reasons for the API Fuzzing job timing out are slow operations (> 1 second) and using a single-CPU runner for API Fuzzing (GitLab shared runners are single-CPU). Before you can diagnose the problem further, the job must complete so the output can be analyzed. We recommend to start with a multi-CPU runner first, then exclude portions of your API operations until the job completes and the output can be further reviewed.
+
+See the following documentation sections for assistance:
+
+- [Performance tuning and testing speed](#performance-tuning-and-testing-speed)
+- [Using a multi-CPU Runner](#using-a-multi-cpu-runner)
+- [Excluding operations by path](#exclude-paths)
+- [Excluding slow operations](#excluding-slow-operations)
+
+### API Fuzzing job takes too long to complete
+
+See [Performance Tuning and Testing Speed](#performance-tuning-and-testing-speed)
+
+### Error waiting for API Security 'http://127.0.0.1:5000' to become available
A bug exists in versions of the API Fuzzing analyzer prior to v1.6.196 that can cause a background process to fail under certain conditions. The solution is to update to a newer version of the API Fuzzing analyzer.
@@ -2281,16 +2511,16 @@ For OpenAPI Specifications that are generated automatically validation errors ar
1. Identify the validation errors.
1. Use the [Swagger Editor](https://editor.swagger.io/) to identify validation problems in your specification. The visual nature of the Swagger Editor makes it easier to understand what needs to change.
- 1. Alternatively, you can check the log output and look for schema validation warnings. They are prefixed with messages such as `OpenAPI 2.0 schema validation error` or `OpenAPI 3.0.x schema validation error`. Each failed validation provides extra information about `location` and `description`. Note that JSON Schema validation messages might not be easy to understand. This is why we recommend the use of editors to validate schema documents.
+ 1. Alternatively, you can check the log output and look for schema validation warnings. They are prefixed with messages such as `OpenAPI 2.0 schema validation error` or `OpenAPI 3.0.x schema validation error`. Each failed validation provides extra information about `location` and `description`. JSON Schema validation messages can be complex, and editors can help you validate schema documents.
1. Review the documentation for the OpenAPI generation your framework/tech stack is using. Identify the changes needed to produce a correct OpenAPI document.
-1. Once the validation issues are resolved, re-run your pipeline.
+1. After the validation issues are resolved, re-run your pipeline.
**For manually created OpenAPI Specifications**
1. Identify the validation errors.
1. The simplest solution is to use a visual tool to edit and validate the OpenAPI document. For example the [Swagger Editor](https://editor.swagger.io/) highlights schema errors and possible solutions.
- 1. Alternatively, you can check the log output and look for schema validation warnings. They are prefixed with messages such as `OpenAPI 2.0 schema validation error` or `OpenAPI 3.0.x schema validation error`. Each failed validation provides extra information about `location` and `description`. Correct each of the validation failures and then resubmit the OpenAPI doc. Note that JSON Schema validation message might not be easy to understand. This is why we recommend the use of editors to validate document.
-1. Once the validation issues are resolved, re-run your pipeline.
+ 1. Alternatively, you can check the log output and look for schema validation warnings. They are prefixed with messages such as `OpenAPI 2.0 schema validation error` or `OpenAPI 3.0.x schema validation error`. Each failed validation provides extra information about `location` and `description`. Correct each of the validation failures and then resubmit the OpenAPI doc. JSON Schema validation messages can be complex, and editors can help you validate schema documents.
+1. After the validation issues are resolved, re-run your pipeline.
### `Failed to start scanner session (version header not found)`
@@ -2312,7 +2542,10 @@ The API Fuzzing analyzer outputs an error message when it cannot determine the t
There is an order of precedence in which the API Fuzzing analyzer tries to get the target API when checking the different sources. First, it will try to use the `FUZZAPI_TARGET_URL`. If the environment variable has not been set, then the API Fuzzing analyzer will attempt to use the `environment_url.txt` file. If there is no file `environment_url.txt`, the API Fuzzing analyzer will then use the OpenAPI document contents and the URL provided in `FUZZAPI_OPENAPI` (if a URL is provided) to try to compute the target API.
-The best-suited solution will depend on whether or not your target API changes for each deployment. In static environments, the target API is the same for each deployment, in this case please refer to the [static environment solution](#static-environment-solution). If the target API changes for each deployment a [dynamic environment solution](#dynamic-environment-solutions) should be applied.
+The best-suited solution depends on whether or not your target API changes for each deployment:
+
+- If the target API is the same for each deployment (a static environment), use the [static environment solution](#static-environment-solution).
+- If the target API changes for each deployment, use a [dynamic environment solution](#dynamic-environment-solutions).
#### Static environment solution
@@ -2417,10 +2650,10 @@ API Fuzzing uses the specified media types in the OpenAPI document to generate r
## Get support or request an improvement
-To get support for your particular problem please use the [getting help channels](https://about.gitlab.com/get-help/).
+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.
-Please 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. Please 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/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.
[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.
@@ -2432,7 +2665,7 @@ When experiencing a behavior not working as expected, consider providing context
- Scanner log file available as a job artifact named `gl-api-security-scanner.log`.
WARNING:
-**Sanitize data attached to a support issue**. Please remove sensitive information, including: credentials, passwords, tokens, keys, and secrets.
+**Sanitize data attached to a support issue**. Remove sensitive information, including: credentials, passwords, tokens, keys, and secrets.
## Glossary
diff --git a/doc/user/application_security/configuration/index.md b/doc/user/application_security/configuration/index.md
index 5eb1b93eb76..d9ba4640855 100644
--- a/doc/user/application_security/configuration/index.md
+++ b/doc/user/application_security/configuration/index.md
@@ -55,7 +55,7 @@ You can configure the following security controls:
- [Dynamic Application Security Testing](../dast/index.md) (DAST)
- Select **Enable DAST** to configure DAST for the current project.
- Select **Manage scans** to manage the saved DAST scans, site profiles, and scanner profiles.
- For more details, read [DAST on-demand scans](../dast/index.md#on-demand-scans).
+ For more details, read [DAST on-demand scans](../dast/proxy-based.md#on-demand-scans).
- [Dependency Scanning](../dependency_scanning/index.md)
- Select **Configure with a merge request** to create a merge request with the changes required to
enable Dependency Scanning. For more details, see [Enable Dependency Scanning via an automatic merge request](../dependency_scanning/index.md#enable-dependency-scanning-via-an-automatic-merge-request).
diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md
index f6bd6157a28..6fc01a716b2 100644
--- a/doc/user/application_security/container_scanning/index.md
+++ b/doc/user/application_security/container_scanning/index.md
@@ -173,7 +173,7 @@ container_scanning:
before_script:
- ruby -r open-uri -e "IO.copy_stream(URI.open('https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip'), 'awscliv2.zip')"
- unzip awscliv2.zip
- - ./aws/install
+ - sudo ./aws/install
- aws --version
- export AWS_ECR_PASSWORD=$(aws ecr get-login-password --region region)
@@ -259,7 +259,7 @@ including a large number of false positives.
| `CS_IMAGE_SUFFIX` | `""` | Suffix added to `CS_ANALYZER_IMAGE`. If set to `-fips`, `FIPS-enabled` image is used for scan. See [FIPS-enabled images](#fips-enabled-images) for more details. [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/7630) in GitLab 14.10. | All |
| `CS_IGNORE_UNFIXED` | `"false"` | Ignore vulnerabilities that are not fixed. | All |
| `CS_REGISTRY_INSECURE` | `"false"` | Allow access to insecure registries (HTTP only). Should only be set to `true` when testing the image locally. Works with all scanners, but the registry must listen on port `80/tcp` for Trivy to work. | All |
-| `CS_SEVERITY_THRESHOLD` | `UNKNOWN` | Severity level threshold. The scanner outputs vulnerabilities with severity level higher than or equal to this threshold. Supported levels are Unknown, Low, Medium, High, and Critical. | Trivy |
+| `CS_SEVERITY_THRESHOLD` | `UNKNOWN` | Severity level threshold. The scanner outputs vulnerabilities with severity level higher than or equal to this threshold. Supported levels are `UNKNOWN`, `LOW`, `MEDIUM`, `HIGH`, and `CRITICAL`. | Trivy |
| <!-- start_remove The following content will be removed on remove_date: '2023-08-22' --> `DOCKER_IMAGE` | `$CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG` | **Deprecated** will be removed in GitLab 16.0. Replaced by `CS_IMAGE`. The Docker image to be scanned. If set, this variable overrides the `$CI_APPLICATION_REPOSITORY` and `$CI_APPLICATION_TAG` variables. | All |
| `DOCKER_PASSWORD` | `$CI_REGISTRY_PASSWORD` | **Deprecated** will be removed in GitLab 16.0. Replaced by `CS_REGISTRY_PASSWORD`. Password for accessing a Docker registry requiring authentication. The default is only set if `$DOCKER_IMAGE` resides at [`$CI_REGISTRY`](../../../ci/variables/predefined_variables.md). Not supported when [FIPS mode](../../../development/fips_compliance.md#enable-fips-mode) is enabled. | All |
| `DOCKER_USER` | `$CI_REGISTRY_USER` | **Deprecated** will be removed in GitLab 16.0. Replaced by `CS_REGISTRY_USER`. Username for accessing a Docker registry requiring authentication. The default is only set if `$DOCKER_IMAGE` resides at [`$CI_REGISTRY`](../../../ci/variables/predefined_variables.md). Not supported when [FIPS mode](../../../development/fips_compliance.md#enable-fips-mode) is enabled. | All |
@@ -359,46 +359,12 @@ The container-scanning analyzer can use different scanners, depending on the val
The following options are available:
-| Scanner name | `CS_ANALYZER_IMAGE` |
-| ------------ | ------------------- |
-| Default ([Trivy](https://github.com/aquasecurity/trivy)) | `registry.gitlab.com/security-products/container-scanning:5` |
+| Scanner name | `CS_ANALYZER_IMAGE` |
+|----------------------------------------------------------|--------------------------------------------------------------------|
+| Default ([Trivy](https://github.com/aquasecurity/trivy)) | `registry.gitlab.com/security-products/container-scanning:5` |
| [Grype](https://github.com/anchore/grype) | `registry.gitlab.com/security-products/container-scanning/grype:5` |
| Trivy | `registry.gitlab.com/security-products/container-scanning/trivy:5` |
-If you're migrating from a GitLab 13.x release to a GitLab 14.x release and have customized the
-`container_scanning` job or its CI variables, you might need to perform these migration steps in
-your CI file:
-
-1. Remove these variables:
-
- - `CS_MAJOR_VERSION`
- - `CS_PROJECT`
- - `SECURE_ANALYZERS_PREFIX`
-
-1. Review the `CS_ANALYZER_IMAGE` variable. It no longer depends on the variables above and its new
- default value is `registry.gitlab.com/security-products/container-scanning:5`. If you have an
- offline environment, see
- [Running container scanning in an offline environment](#running-container-scanning-in-an-offline-environment).
-
-1. If present, remove the `.cs_common` and `container_scanning_new` configuration sections.
-
-1. If the `container_scanning` section is present, it's safer to create one from scratch based on
- the new version of the [`Container-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml).
- Once finished, it should not have any variables that are only applicable to Klar or Clair. For a
- complete list of supported variables, see [available variables](#available-cicd-variables).
-
-1. Make any [necessary customizations](#customizing-the-container-scanning-settings)
- to the chosen scanner. We recommend that you minimize such customizations, as they might require
- changes in future GitLab major releases.
-
-1. Trigger a new run of a pipeline that includes the `container_scanning` job. Inspect the job
- output and ensure that the log messages do not mention Clair.
-
-NOTE:
-Prior to the GitLab 14.0 release, any variable defined under the scope `container_scanning` is not
-considered for scanners other than Clair. In GitLab 14.0 and later, all variables can be defined
-either as a global variable or under `container_scanning`.
-
### Setting the default branch image
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/338877) in GitLab 14.5.
diff --git a/doc/user/application_security/dast/browser_based.md b/doc/user/application_security/dast/browser_based.md
index 5a4acc78728..c0a97c0ff92 100644
--- a/doc/user/application_security/dast/browser_based.md
+++ b/doc/user/application_security/dast/browser_based.md
@@ -36,8 +36,8 @@ current DAST scanner is much more effective at finding and testing every page in
To enable the browser-based analyzer:
1. Ensure the DAST [prerequisites](index.md#prerequisites) are met.
-1. Include the [DAST CI/CD template](index.md#include-the-dast-template).
-1. Set the target website using the [`DAST_WEBSITE` CI/CD variable](index.md#available-cicd-variables).
+1. Include the [DAST CI/CD template](proxy-based.md#include-the-dast-template).
+1. Set the target website using the [`DAST_WEBSITE` CI/CD variable](proxy-based.md#available-cicd-variables).
1. Set the CI/CD variable `DAST_BROWSER_SCAN` to `true`.
Example extract of `.gitlab-ci.yml` file:
@@ -79,7 +79,7 @@ The browser-based crawler can be configured using CI/CD variables.
| `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_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. Note: When this selector is set, but the element is not found, the scanner waits for the period defined in `DAST_BROWSER_STABILITY_TIMEOUT` before continuing the scan. This can significantly increase scanning time if the element is not present on multiple pages within the site. |
-The [DAST variables](index.md#available-cicd-variables) `SECURE_ANALYZERS_PREFIX`, `DAST_FULL_SCAN_ENABLED`, `DAST_AUTO_UPDATE_ADDONS`, `DAST_EXCLUDE_RULES`, `DAST_REQUEST_HEADERS`, `DAST_HTML_REPORT`, `DAST_MARKDOWN_REPORT`, `DAST_XML_REPORT`,
+The [DAST variables](proxy-based.md#available-cicd-variables) `SECURE_ANALYZERS_PREFIX`, `DAST_FULL_SCAN_ENABLED`, `DAST_AUTO_UPDATE_ADDONS`, `DAST_EXCLUDE_RULES`, `DAST_REQUEST_HEADERS`, `DAST_HTML_REPORT`, `DAST_MARKDOWN_REPORT`, `DAST_XML_REPORT`,
`DAST_AUTH_URL`, `DAST_USERNAME`, `DAST_PASSWORD`, `DAST_USERNAME_FIELD`, `DAST_PASSWORD_FIELD`, `DAST_FIRST_SUBMIT_FIELD`, `DAST_SUBMIT_FIELD`, `DAST_EXCLUDE_URLS`, `DAST_AUTH_VERIFICATION_URL`, `DAST_BROWSER_AUTH_VERIFICATION_SELECTOR`, `DAST_BROWSER_AUTH_VERIFICATION_LOGIN_FORM`, `DAST_BROWSER_AUTH_REPORT`,
`DAST_INCLUDE_ALPHA_VULNERABILITIES`, `DAST_PATHS_FILE`, `DAST_PATHS`, `DAST_ZAP_CLI_OPTIONS`, and `DAST_ZAP_LOG_CONFIGURATION` are also compatible with browser-based crawler scans.
diff --git a/doc/user/application_security/dast/dast_troubleshooting.md b/doc/user/application_security/dast/dast_troubleshooting.md
index 194761797de..61a7520bf7c 100644
--- a/doc/user/application_security/dast/dast_troubleshooting.md
+++ b/doc/user/application_security/dast/dast_troubleshooting.md
@@ -20,7 +20,7 @@ A DAST job has two executing processes:
Enable the `DAST_DEBUG` CI/CD variable to debug scripts. This can help when troubleshooting the job,
and outputs statements indicating what percentage of the scan is complete.
-For details on using variables, see [Overriding the DAST template](index.md#customize-dast-settings).
+For details on using variables, see [Overriding the DAST template](proxy-based.md#customize-dast-settings).
Debug mode of the ZAP server can be enabled using the `DAST_ZAP_LOG_CONFIGURATION` variable.
The following table outlines examples of values that can be set and the effect that they have on the output that is logged.
diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md
index 6d1b7beefc7..d78a8fca98f 100644
--- a/doc/user/application_security/dast/index.md
+++ b/doc/user/application_security/dast/index.md
@@ -13,16 +13,7 @@ application server or incorrect assumptions about security controls may not be
visible from the source code.
Dynamic Application Security Testing (DAST) examines applications for
-vulnerabilities like these in deployed environments. DAST uses the open source
-tool [OWASP Zed Attack Proxy](https://www.zaproxy.org/) for analysis.
-
-After DAST creates its report, GitLab evaluates it for discovered
-vulnerabilities between the source and target branches. Relevant
-findings are noted in the merge request.
-
-The comparison logic uses only the latest pipeline executed for the target
-branch's base commit. Running the pipeline on other commits has no effect on
-the merge request.
+vulnerabilities like these in deployed environments.
NOTE:
To learn how four of the top six attacks were application-based and how
@@ -30,16 +21,88 @@ to protect your organization, download our
["A Seismic Shift in Application Security"](https://about.gitlab.com/resources/whitepaper-seismic-shift-application-security/)
whitepaper.
-## DAST application analysis
+## GitLab DAST
+
+GitLab provides the following DAST analyzers, one or more of which may be useful depending on the kind of application you're testing.
+
+For scanning websites, use one of:
+
+- The [DAST proxy-based analyzer](proxy-based.md) for scanning traditional applications serving simple HTML. The proxy-based analyzer can be run automatically or on-demand.
+- The [DAST browser-based analyzer](browser_based.md) for scanning applications that make heavy use of JavaScript. This includes single page web applications.
+
+For scanning APIs, use:
+
+- The [DAST API analyzer](../dast_api/index.md) for scanning web APIs. Web API technologies such as GraphQL, REST, and SOAP are supported.
+
+Analyzers follow the architectural patterns described in [Secure your application](../index.md).
+Each analyzer can be configured in the pipeline using a CI template and runs the scan in a Docker container. Scans output a [DAST report artifact](../../../ci/yaml/artifacts_reports.md#artifactsreportsdast)
+which GitLab uses to determine discovered vulnerabilities based on differences between scan results on the source and target branches.
+
+### Getting started
+
+#### Prerequisites
+
+- [GitLab Runner](../../../ci/runners/index.md) available, with the
+ [`docker` executor](https://docs.gitlab.com/runner/executors/docker.html) on Linux/amd64.
+- Target application deployed. For more details, read [Deployment options](#application-deployment-options).
+- `dast` stage added to the CI/CD pipeline definition. This should be added after the deploy step, for example:
+
+ ```yaml
+ stages:
+ - build
+ - test
+ - deploy
+ - dast
+ ```
+
+#### Recommendations
+
+- Take care if your pipeline is configured to deploy to the same web server in each run. Running a DAST scan while a server is being updated will lead to inaccurate and non-deterministic results.
+- Configure runners to use the [always pull policy](https://docs.gitlab.com/runner/executors/docker.html#using-the-always-pull-policy) to run the latest versions of the analyzers.
+- By default, DAST downloads all artifacts defined by previous jobs in the pipeline. If
+ your DAST job does not rely on `environment_url.txt` to define the URL under test or any other files created
+ in previous jobs, we recommend you don't download artifacts. To avoid downloading
+ artifacts, extend the analyzer CI/CD job to specify no dependencies. For example, for the DAST proxy-based analyzer add the following to your `.gitlab-ci.yml` file:
+
+ ```yaml
+ dast:
+ dependencies: []
+ ```
+
+#### Analyzer configuration
+
+Please see [DAST proxy-based analyzer](proxy-based.md), [DAST browser-based analyzer](browser_based.md) or [DAST API analyzer](../dast_api/index.md) for
+analyzer-specific configuration instructions.
+
+### View scan results
-DAST can analyze applications in two ways:
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/36332) in GitLab 13.1.
+
+Detected vulnerabilities are shown in [Merge requests](../index.md#view-security-scan-information-in-merge-requests), the [Pipeline security tab](../index.md#view-security-scan-information-in-the-pipeline-security-tab),
+and the [Vulnerability report](../index.md#view-security-scan-information-in-the-vulnerability-report).
-- Passive scan only (DAST default). DAST executes
- [ZAP's Baseline Scan](https://www.zaproxy.org/docs/docker/baseline-scan/) and doesn't
- actively attack your application.
-- Passive and active scan. DAST can be [configured](#full-scan) to also perform an active scan
- to attack your application and produce a more extensive security report. It can be very
- useful when combined with [Review Apps](../../../ci/review_apps/index.md).
+1. To see all vulnerabilities detected, either:
+ - From your project, select **Security & Compliance**, then **Vulnerability report**.
+ - From your pipeline, click on the **Security** tab.
+ - From the merge request, go to the **Security scanning** widget and click **Full report** tab.
+
+1. Select a DAST vulnerability's description. The following fields are examples of what a DAST analyzer may produce to aid investigation and rectification of the underlying cause. Each analyzer may output different fields.
+
+ | Field | Description |
+ |:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------ |
+ | Description | Description of the vulnerability. |
+ | Evidence | Evidence of the data found that verified the vulnerability. Often a snippet of the request or response, this can be used to help verify that the finding is a vulnerability. |
+ | Identifiers | Identifiers of the vulnerability. |
+ | Links | Links to further details of the detected vulnerability. |
+ | Method | HTTP method used to detect the vulnerability. |
+ | Project | Namespace and project in which the vulnerability was detected. |
+ | Request Headers | Headers of the request. |
+ | Response Headers | Headers of the response received from the application. |
+ | Response Status | Response status received from the application. |
+ | Scanner Type | Type of vulnerability report. |
+ | Severity | Severity of the vulnerability. |
+ | Solution | Details of a recommended solution to the vulnerability. |
+ | URL | URL at which the vulnerability was detected. |
NOTE:
A pipeline may consist of multiple jobs, including SAST and DAST scanning. If any job
@@ -48,17 +111,19 @@ example, if the DAST job finishes but the SAST job fails, the security dashboard
results. On failure, the analyzer outputs an
[exit code](../../../development/integrations/secure.md#exit-code).
-## Prerequisites
+#### List URLs scanned
-- [GitLab Runner](../../../ci/runners/index.md) available, with the
-[`docker` executor](https://docs.gitlab.com/runner/executors/docker.html) on Linux/amd64.
-- Target application deployed. For more details, read [Deployment options](#deployment-options).
-- DAST runs in the `dast` stage, which must be added manually to your `.gitlab-ci.yml`.
+When DAST completes scanning, the merge request page states the number of URLs scanned.
+Select **View details** to view the web console output which includes the list of scanned URLs.
+
+![DAST Widget](img/dast_urls_scanned_v12_10.png)
-### Deployment options
+### Application deployment options
+
+DAST requires a deployed application to be available to scan.
Depending on the complexity of the target application, there are a few options as to how to deploy and configure
-the DAST template. We provided a set of example applications with their configurations in our
+the DAST template. A set of example applications have been provided with their configurations in the
[DAST demonstrations](https://gitlab.com/gitlab-org/security-products/demos/dast/) project.
#### Review Apps
@@ -77,6 +142,8 @@ After your Docker build job completes and your image is added to your container
By using service definitions in your `.gitlab-ci.yml`, you can scan services with the DAST analyzer.
+When adding a `services` section to the job, the `alias` is used to define the hostname that can be used to access the service. In the following example, the `alias: yourapp` portion of the `dast` job definition means that the URL to the deployed application will use `yourapp` as the hostname (`https://yourapp/`).
+
```yaml
stages:
- build
@@ -105,6 +172,7 @@ dast:
alias: yourapp
variables:
+ DAST_WEBSITE: https://yourapp
DAST_FULL_SCAN_ENABLED: "true" # do a full scan
DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
```
@@ -122,1323 +190,3 @@ services: # use services to link the container to the dast job
- name: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
alias: yourapp
```
-
-### DAST job order
-
-When using the `DAST.gitlab-ci.yml` template, the `dast` stage is run last as shown in
-the example below. To ensure DAST scans the latest code, deploy your application
-in a stage before the `dast` stage.
-
-```yaml
- stages:
- - build
- - test
- - deploy
- - dast
-```
-
-Take care if your pipeline is configured to deploy to the same web server in each run. Running a
-pipeline while another is still running could result in one pipeline overwriting the code from
-another pipeline. The site to be scanned should be excluded from changes for the duration of a DAST
-scan. The only changes to the site should be from the DAST scanner.
-
-Changes to the site during a scan from any of the following could lead to inaccurate results:
-
-- Users.
-- Scheduled tasks.
-- Database changes.
-- Code changes.
-- Other pipelines.
-- Other scanners.
-
-## DAST run options
-
-You can use DAST to examine your web application:
-
-- Automatically, initiated by a merge request.
-- Manually, initiated on demand.
-
-Some of the differences between these run options:
-
-| Automatic scan | On-demand scan |
-|:-----------------------------------------------------------------|:------------------------------|
-| DAST scan is initiated by a merge request. | DAST scan is initiated manually, outside the DevOps life cycle. |
-| CI/CD variables are sourced from `.gitlab-ci.yml`. | CI/CD variables are provided in the UI. |
-| All [DAST CI/CD variables](#available-cicd-variables) available. | Subset of [DAST CI/CD variables](#available-cicd-variables) available. |
-| `DAST.gitlab-ci.yml` template. | `DAST-On-Demand-Scan.gitlab-ci.yml` template. |
-
-### Enable automatic DAST run
-
-To enable DAST to run automatically, either:
-
-- Enable [Auto DAST](../../../topics/autodevops/stages.md#auto-dast) (provided
- by [Auto DevOps](../../../topics/autodevops/index.md)).
-- [Include the DAST template](#include-the-dast-template) in your existing
- `.gitlab-ci.yml` file.
-- [Configure DAST using the UI](#configure-dast-using-the-ui).
-
-#### Include the DAST template
-
-> - This template was [updated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62597) to DAST_VERSION: 2 in GitLab 14.0.
-> - This template was [updated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87183) to DAST_VERSION: 3 in GitLab 15.0.
-
-If you want to manually add DAST to your application, the DAST job is defined
-in a CI/CD template file. Updates to the template are provided with GitLab
-upgrades, allowing you to benefit from any improvements and additions.
-
-To include the DAST template:
-
-1. Select the CI/CD template you want to use:
-
- - [`DAST.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml):
- Stable version of the DAST CI/CD template.
- - [`DAST.latest.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/DAST.latest.gitlab-ci.yml):
- Latest version of the DAST template. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/254325)
- in GitLab 13.8).
-
- WARNING:
- The latest version of the template may include breaking changes. Use the
- stable template unless you need a feature provided only in the latest template.
-
- For more information about template versioning, see the
- [CI/CD documentation](../../../development/cicd/templates.md#latest-version).
-
-1. Add a `dast` stage to your GitLab CI stages configuration:
-
- ```yaml
- stages:
- - dast
- ```
-
-1. Add the template to GitLab, based on your version of GitLab:
-
- - In GitLab 11.9 and later, [include](../../../ci/yaml/index.md#includetemplate)
- the template by adding the following to your `.gitlab-ci.yml` file:
-
- ```yaml
- include:
- - template: <template_file.yml>
-
- variables:
- DAST_WEBSITE: https://example.com
- ```
-
- - In GitLab 11.8 and earlier, add the contents of the template to your
- `.gitlab_ci.yml` file.
-
-1. Define the URL to be scanned by DAST by using one of these methods:
-
- - Set the `DAST_WEBSITE` [CI/CD variable](../../../ci/yaml/index.md#variables).
- If set, this value takes precedence.
-
- - Add the URL in an `environment_url.txt` file at the root of your project. This is
- useful for testing in dynamic environments. To run DAST against an application
- dynamically created during a GitLab CI/CD pipeline, a job that runs prior to
- the DAST scan must persist the application's domain in an `environment_url.txt`
- file. DAST automatically parses the `environment_url.txt` file to find its
- scan target.
-
- For example, in a job that runs prior to DAST, you could include code that
- looks similar to:
-
- ```yaml
- script:
- - echo http://${CI_PROJECT_ID}-${CI_ENVIRONMENT_SLUG}.domain.com > environment_url.txt
- artifacts:
- paths: [environment_url.txt]
- when: always
- ```
-
- You can see an example of this in our
- [Auto DevOps CI YAML](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml)
- file.
-
-The included template creates a `dast` job in your CI/CD pipeline and scans
-your project's running application for possible vulnerabilities.
-
-The results are saved as a
-[DAST report artifact](../../../ci/yaml/artifacts_reports.md#artifactsreportsdast)
-that you can later download and analyze. Due to implementation limitations, we
-always take the latest DAST artifact available. Behind the scenes, the
-[GitLab DAST Docker image](https://gitlab.com/security-products/dast)
-is used to run the tests on the specified URL and scan it for possible
-vulnerabilities.
-
-By default, the DAST template uses the latest major version of the DAST Docker
-image. Using the `DAST_VERSION` variable, you can choose how DAST updates:
-
-- Automatically update DAST with new features and fixes by pinning to a major
- version (such as `1`).
-- Only update fixes by pinning to a minor version (such as `1.6`).
-- Prevent all updates by pinning to a specific version (such as `1.6.4`).
-
-Find the latest DAST versions on the [Releases](https://gitlab.com/gitlab-org/security-products/dast/-/releases)
-page.
-
-#### Configure DAST using the UI
-
-You can enable or configure DAST settings using the UI. The generated settings are formatted so they
-can be conveniently pasted into the `.gitlab-ci.yml` file.
-
-1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Configuration**.
-1. In the **Dynamic Application Security Testing (DAST)** section, select **Enable DAST** or
- **Configure DAST**.
-1. Select the desired **Scanner profile**, or select **Create scanner profile** and save a
- scanner profile. For more details, see [scanner profiles](#scanner-profile).
-1. Select the desired **Site profile**, or select **Create site profile** and save a site
- profile. For more details, see [site profiles](#site-profile).
-1. Select **Generate code snippet**. A modal opens with the YAML snippet corresponding to the
- options you selected.
-1. Do one of the following:
- 1. To copy the snippet to your clipboard, select **Copy code only**.
- 1. To add the snippet to your project's `.gitlab-ci.yml` file, select
- **Copy code and open `.gitlab-ci.yml` file**. The Pipeline Editor opens.
- 1. Paste the snippet into the `.gitlab-ci.yml` file.
- 1. Select the **Lint** tab to confirm the edited `.gitlab-ci.yml` file is valid.
- 1. Select the **Edit** tab, then select **Commit changes**.
-
-When the snippet is committed to the `.gitlab-ci.yml` file, pipelines include a DAST job.
-
-#### Crawling web applications dependent on JavaScript
-
-GitLab has released a new browser-based crawler, an add-on to DAST that uses a browser to crawl web applications for content. This crawler replaces the standard DAST Spider and Ajax Crawler, and uses the same authentication mechanisms as a normal DAST scan.
-
-The browser-based crawler crawls websites by browsing web pages as a user would. This approach works well with web applications that make heavy use of JavaScript, such as Single Page Applications.
-
-For more details, including setup instructions, see [DAST browser-based crawler](browser_based.md).
-
-### Full scan
-
-DAST can be configured to perform [ZAP Full Scan](https://www.zaproxy.org/docs/docker/full-scan/), which
-includes both passive and active scanning against the same target website:
-
-```yaml
-include:
- - template: DAST.gitlab-ci.yml
-
-variables:
- DAST_FULL_SCAN_ENABLED: "true"
- DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
-```
-
-If your DAST job exceeds the job timeout and you need to reduce the scan duration, we shared some
-tips for optimizing DAST scans in a [blog post](https://about.gitlab.com/blog/2020/08/31/how-to-configure-dast-full-scans-for-complex-web-applications/).
-
-### API scan
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10928) in GitLab 12.10.
-> - A new DAST API scanning engine was introduced in GitLab 13.10.
-
-Using an API specification as a scan's target is a useful way to seed URLs for scanning an API.
-Vulnerability rules in an API scan are different than those in a normal website scan.
-
-A new DAST API scanning engine is available in GitLab 13.12 and later. For more details, see [DAST API scanning engine](../dast_api). The new scanning engine supports REST, SOAP, GraphQL, and generic APIs using forms, XML, and JSON. Testing can be performed using OpenAPI, Postman Collections, and HTTP Archive (HAR) documents.
-
-The target API instance's base URL is provided by using the `DAST_API_TARGET_URL` variable or an `environment_url.txt` file.
-
-#### Specification format
-
-API scans support OpenAPI V2 and OpenAPI V3 specifications. You can define these specifications using `JSON` or `YAML`.
-
-#### Import API specification from a URL
-
-If your API specification is accessible at a URL, you can pass that URL in directly as the target.
-The specification does not have to be hosted on the same host as the API being tested.
-
-```yaml
-include:
- - template: DAST-API.gitlab-ci.yml
-
-variables:
- DAST_API_SPECIFICATION: http://my.api/api-specification.yml
-```
-
-#### Import API specification from a file
-
-If your API specification file is in your repository, you can provide its filename as the target.
-
-```yaml
-dast:
- variables:
- GIT_STRATEGY: fetch
- DAST_API_SPECIFICATION: api-specification.yml
-```
-
-#### Full API scan
-
-API scans support full scanning, which can be enabled by using the `DAST_FULL_SCAN_ENABLED`
-CI/CD variable. Domain validation is not supported for full API scans.
-
-#### Host override
-
-Specifications often define a host, which contains a domain name and a port. The
-host referenced may be different than the host of the API's review instance.
-This can cause incorrect URLs to be imported, or a scan on an incorrect host.
-Use the `DAST_API_HOST_OVERRIDE` CI/CD variable to override these values.
-
-WARNING:
-When using the API host override feature, you cannot use the `$DAST_WEBSITE` variable to override the hostname.
-A host override is _only_ supported when importing the API specification from a URL. Attempts to override the
-host throw an error when the API specification is imported from a file. This is due to a limitation in the
-ZAP OpenAPI extension.
-
-For example, with a OpenAPI V3 specification containing:
-
-```yaml
-servers:
- - url: https://api.host.com
-```
-
-If the test version of the API is running at `https://api-test.host.com`, then
-the following DAST configuration can be used:
-
-```yaml
-include:
- - template: DAST-API.gitlab-ci.yml
-
-variables:
- DAST_API_SPECIFICATION: http://api-test.host.com/api-specification.yml
- DAST_API_HOST_OVERRIDE: api-test.host.com
-```
-
-#### Authentication using headers
-
-Tokens in request headers are often used as a way to authenticate API requests.
-You can achieve this by using the `DAST_REQUEST_HEADERS` CI/CD variable.
-Headers are applied to every request DAST makes.
-
-```yaml
-include:
- - template: DAST-API.gitlab-ci.yml
-
-variables:
- DAST_API_SPECIFICATION: http://api-test.api.com/api-specification.yml
- DAST_REQUEST_HEADERS: "Authorization: Bearer my.token"
-```
-
-### URL scan
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214120) in GitLab 13.4.
-> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/273141) in GitLab 13.11.
-
-A URL scan allows you to specify which parts of a website are scanned by DAST.
-
-#### Define the URLs to scan
-
-URLs to scan can be specified by either of the following methods:
-
-- Use `DAST_PATHS_FILE` CI/CD variable to specify the name of a file containing the paths.
-- Use `DAST_PATHS` variable to list the paths.
-
-##### Use `DAST_PATHS_FILE` CI/CD variable
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/258825) in GitLab 13.6.
-
-To define the URLs to scan in a file, create a plain text file with one path per line.
-
-```plaintext
-page1.html
-/page2.html
-category/shoes/page1.html
-```
-
-To scan the URLs in that file, set the CI/CD variable `DAST_PATHS_FILE` to the path of that file.
-The file can be checked into the project repository or generated as an artifact by a job that
-runs before DAST.
-
-By default, DAST scans do not clone the project repository. Instruct the DAST job to clone
-the project by setting `GIT_STRATEGY` to fetch. Give a file path relative to `CI_PROJECT_DIR` to `DAST_PATHS_FILE`.
-
-```yaml
-include:
- - template: DAST.gitlab-ci.yml
-
-variables:
- GIT_STRATEGY: fetch
- DAST_PATHS_FILE: url_file.txt # url_file.txt lives in the root directory of the project
- DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
-```
-
-##### Use `DAST_PATHS` CI/CD variable
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214120) in GitLab 13.4.
-
-To specify the paths to scan in a CI/CD variable, add a comma-separated list of the paths to the `DAST_PATHS`
-variable. Note that you can only scan paths of a single host.
-
-```yaml
-include:
- - template: DAST.gitlab-ci.yml
-
-variables:
- DAST_PATHS: "/page1.html,/category1/page1.html,/page3.html"
- DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
-```
-
-When using `DAST_PATHS` and `DAST_PATHS_FILE`, note the following:
-
-- `DAST_WEBSITE` must be defined when using either `DAST_PATHS_FILE` or `DAST_PATHS`. The paths listed in either use `DAST_WEBSITE` to build the URLs to scan
-- Spidering is disabled when `DAST_PATHS` or `DAST_PATHS_FILE` are defined
-- `DAST_PATHS_FILE` and `DAST_PATHS` cannot be used together
-- The `DAST_PATHS` variable has a limit of about 130kb. If you have a list or paths
- greater than this, use `DAST_PATHS_FILE`.
-
-#### Full Scan
-
-To perform a [full scan](#full-scan) on the listed paths, use the `DAST_FULL_SCAN_ENABLED` CI/CD variable.
-
-### List URLs scanned
-
-When DAST completes scanning, the merge request page states the number of URLs scanned.
-Select **View details** to view the web console output which includes the list of scanned URLs.
-
-![DAST Widget](img/dast_urls_scanned_v12_10.png)
-
-### View details of a vulnerability detected by DAST
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/36332) in GitLab 13.1.
-
-Vulnerabilities detected by DAST occur in the live web application. Addressing these types of
-vulnerabilities requires specific information. DAST provides the information required to
-investigate and rectify the underlying cause.
-
-To view details of vulnerabilities detected by DAST:
-
-1. To see all vulnerabilities detected, either:
- - Go to your project and select **Security & Compliance**.
- - Go to the merge request and select the **Security** tab.
-
-1. Select a vulnerability's description. The following details are provided:
-
- | Field | Description |
- |:-----------------|:------------------------------------------------------------------ |
- | Description | Description of the vulnerability. |
- | Project | Namespace and project in which the vulnerability was detected. |
- | Method | HTTP method used to detect the vulnerability. |
- | URL | URL at which the vulnerability was detected. |
- | Request Headers | Headers of the request. |
- | Response Status | Response status received from the application. |
- | Response Headers | Headers of the response received from the application. |
- | Evidence | Evidence of the data found that verified the vulnerability. Often a snippet of the request or response, this can be used to help verify that the finding is a vulnerability. |
- | Identifiers | Identifiers of the vulnerability. |
- | Severity | Severity of the vulnerability. |
- | Scanner Type | Type of vulnerability report. |
- | Links | Links to further details of the detected vulnerability. |
- | Solution | Details of a recommended solution to the vulnerability (optional). |
-
-## Customize DAST settings
-
-You can customize the behavior of DAST using both CI/CD variables and command-line options. Use of CI/CD
-variables overrides the values contained in the DAST template.
-
-### Customize DAST using CI/CD variables
-
-WARNING:
-Beginning in GitLab 13.0, the use of [`only` and `except`](../../../ci/yaml/index.md#only--except)
-is no longer supported. You must use [`rules`](../../../ci/yaml/index.md#rules) instead.
-
-The DAST settings can be changed through CI/CD variables by using the
-[`variables`](../../../ci/yaml/index.md#variables) parameter in `.gitlab-ci.yml`. For details of
-all DAST CI/CD variables, read [Available CI/CD variables](#available-cicd-variables).
-
-For example:
-
-```yaml
-include:
- - template: DAST.gitlab-ci.yml
-
-variables:
- DAST_WEBSITE: https://example.com
- DAST_SPIDER_MINS: 120
- DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
-```
-
-Because the template is [evaluated before](../../../ci/yaml/index.md#include) the pipeline
-configuration, the last mention of the variable takes precedence.
-
-#### Enable or disable rules
-
-A complete list of the rules that DAST uses to scan for vulnerabilities can be
-found in the [ZAP documentation](https://www.zaproxy.org/docs/alerts/).
-
-`DAST_EXCLUDE_RULES` disables the rules with the given IDs.
-
-`DAST_ONLY_INCLUDE_RULES` restricts the set of rules used in the scan to
-those with the given IDs.
-
-`DAST_EXCLUDE_RULES` and `DAST_ONLY_INCLUDE_RULES` are mutually exclusive and a
-DAST scan with both configured exits with an error.
-
-By default, several rules are disabled because they either take a long time to
-run or frequently generate false positives. The complete list of disabled rules
-can be found in [`exclude_rules.yml`](https://gitlab.com/gitlab-org/security-products/dast/-/blob/main/src/config/exclude_rules.yml).
-
-The lists for `DAST_EXCLUDE_RULES` and `DAST_ONLY_INCLUDE_RULES` **must** be enclosed in double
-quotes (`"`), otherwise they are interpreted as numeric values.
-
-#### Hide sensitive information
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/36332) in GitLab 13.1.
-
-HTTP request and response headers may contain sensitive information, including cookies and
-authorization credentials. By default, the following headers are masked:
-
-- `Authorization`.
-- `Proxy-Authorization`.
-- `Set-Cookie` (values only).
-- `Cookie` (values only).
-
-Using the [`DAST_MASK_HTTP_HEADERS` CI/CD variable](#available-cicd-variables), you can list the
-headers whose values you want masked. For details on how to mask headers, see
-[Customizing the DAST settings](#customize-dast-settings).
-
-#### Use Mutual TLS
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/299596) in GitLab 14.8.
-
-Mutual TLS allows a target application server to verify that requests are from a known source. Browser-based scans do not support Mutual TLS.
-
-**Requirements**
-
-- Base64-encoded PKCS12 certificate
-- Password of the base64-encoded PKCS12 certificate
-
-To enable Mutual TLS:
-
-1. If the PKCS12 certificate is not already base64-encoded, convert it to base64 encoding. For security reasons, we recommend encoding the certificate locally, **not** using a web-hosted conversion service. For example, to encode the certificate on either macOS or Linux:
-
- ```shell
- base64 <path-to-pkcs12-certificate-file>
- ```
-
-1. Create a [masked variable](../../../ci/variables/index.md) named `DAST_PKCS12_CERTIFICATE_BASE64` and store the base64-encoded PKCS12 certificate's value in that variable.
-1. Create a masked variable `DAST_PKCS12_PASSWORD` and store the PKCS12 certificate's password in that variable.
-
-#### Available CI/CD variables
-
-These CI/CD variables are specific to DAST. They can be used to customize the behavior of DAST to your requirements.
-
-WARNING:
-All customization of GitLab security scanning tools should be tested in a merge request before
-merging these changes to the default branch. Failure to do so can give unexpected results,
-including a large number of false positives.
-
-| CI/CD variable | Type | Description |
-|:-------------------------------------------------|:--------------|:------------------------------|
-| `DAST_ADVERTISE_SCAN` | boolean | 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_AGGREGATE_VULNERABILITIES` | boolean | Vulnerability aggregation is set to `true` by default. To disable this feature and see each vulnerability individually set to `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/254043) in GitLab 14.0. |
-| `DAST_API_HOST_OVERRIDE` <sup>1</sup> | string | Used to override domains defined in API specification files. Only supported when importing the API specification from a URL. Example: `example.com:8080`. |
-| `DAST_API_SPECIFICATION` <sup>1</sup> | URL or string | The API specification to import. The specification can be hosted at a URL, or the name of a file present in the `/zap/wrk` directory. The variable `DAST_WEBSITE` must be specified if this is omitted. |
-| `DAST_AUTH_REPORT` <sup>2</sup> | boolean | Used in combination with exporting the `gl-dast-debug-auth-report.html` artifact to aid in debugging authentication issues. |
-| `DAST_AUTH_EXCLUDE_URLS` <sup>2</sup> | URLs | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/289959)** in GitLab 14.0. Replaced by `DAST_EXCLUDE_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. Not supported for API scans. |
-| `DAST_AUTH_URL` <sup>1,2</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. Not supported for API scans. Example: `https://login.example.com`. |
-| `DAST_AUTH_VERIFICATION_LOGIN_FORM` <sup>2</sup> | boolean | Verifies successful authentication by checking for the lack of a login form once the login form has been submitted. |
-| `DAST_AUTH_VERIFICATION_SELECTOR` <sup>2</sup> | 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,2</sup> | URL | A URL only accessible to logged in users that DAST can use to confirm successful authentication. If provided, DAST exits if it cannot access the URL. Example: `"http://example.com/loggedin_page"`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/207335) in GitLab 13.8. |
-| `DAST_AUTO_UPDATE_ADDONS` | boolean | ZAP add-ons are pinned to specific versions in the DAST Docker image. Set to `true` to download the latest versions when the scan starts. Default: `false`. |
-| `DAST_BROWSER_PATH_TO_LOGIN_FORM` <sup>1,2</sup> | 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_DEBUG` <sup>1</sup> | boolean | Enable debug message output. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
-| `DAST_EXCLUDE_RULES` | string | Set to a comma-separated list of Vulnerability Rule IDs to exclude them from running during the scan. Rule IDs are numbers and can be found from the DAST log or on the [ZAP project](https://www.zaproxy.org/docs/alerts/). For example, `HTTP Parameter Override` has a rule ID of `10026`. Cannot be used when `DAST_ONLY_INCLUDE_RULES` is set. **Note:** In earlier versions of GitLab the excluded rules were executed but vulnerabilities they generated were suppressed. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118641) in GitLab 12.10. |
-| `DAST_EXCLUDE_URLS` <sup>1,2</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. Not supported for API scans. Example, `http://example.com/sign-out`. |
-| `DAST_FIRST_SUBMIT_FIELD` <sup>2</sup> | 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_FULL_SCAN_DOMAIN_VALIDATION_REQUIRED` | boolean | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/293595)** in GitLab 14.0. Set to `true` to require domain validation when running DAST full scans. Not supported for API scans. Default: `false` |
-| `DAST_FULL_SCAN_ENABLED` <sup>1</sup> | boolean | Set to `true` to run a [ZAP Full Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Full-Scan) instead of a [ZAP Baseline Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Baseline-Scan). Default: `false` |
-| `DAST_HTML_REPORT` | string | The filename of the HTML report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
-| `DAST_INCLUDE_ALPHA_VULNERABILITIES` | boolean | Set to `true` to include alpha passive and active scan rules. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
-| `DAST_MARKDOWN_REPORT` | string | The filename of the Markdown report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
-| `DAST_MASK_HTTP_HEADERS` | string | Comma-separated list of request and response headers to be masked (GitLab 13.1). Must contain **all** headers to be masked. Refer to [list of headers that are masked by default](#hide-sensitive-information). |
-| `DAST_MAX_URLS_PER_VULNERABILITY` | number | The maximum number of URLs reported for a single vulnerability. `DAST_MAX_URLS_PER_VULNERABILITY` is set to `50` by default. To list all the URLs set to `0`. [Introduced](https://gitlab.com/gitlab-org/security-products/dast/-/merge_requests/433) in GitLab 13.12. |
-| `DAST_ONLY_INCLUDE_RULES` | string | Set to a comma-separated list of Vulnerability Rule IDs to configure the scan to run only them. Rule IDs are numbers and can be found from the DAST log or on the [ZAP project](https://www.zaproxy.org/docs/alerts/). Cannot be used when `DAST_EXCLUDE_RULES` is set. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/250651) in GitLab 13.12. |
-| `DAST_PASSWORD` <sup>1,2</sup> | string | The password to authenticate to in the website. Example: `P@55w0rd!` |
-| `DAST_PASSWORD_FIELD` <sup>1,2</sup> | string | The selector of password field at the sign-in HTML form. Example: `id:password` |
-| `DAST_PATHS` | string | Set to a comma-separated list of URLs for DAST to scan. For example, `/page1.html,/category1/page3.html,/page2.html`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214120) in GitLab 13.4. |
-| `DAST_PATHS_FILE` | string | The file path containing the paths within `DAST_WEBSITE` to scan. The file must be plain text with one path per line. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/258825) in GitLab 13.6. |
-| `DAST_PKCS12_CERTIFICATE_BASE64` | string | The PKCS12 certificate used for sites that require Mutual TLS. Must be encoded as base64 text. |
-| `DAST_PKCS12_PASSWORD` | string | The password of the certificate used in `DAST_PKCS12_CERTIFICATE_BASE64`. |
-| `DAST_REQUEST_HEADERS` <sup>1</sup> | string | Set to a comma-separated list of request header names and values. Headers are added to every request made by DAST. For example, `Cache-control: no-cache,User-Agent: DAST/1.0` |
-| `DAST_SKIP_TARGET_CHECK` | boolean | Set to `true` to prevent DAST from checking that the target is available before scanning. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229067) in GitLab 13.8. |
-| `DAST_SPIDER_MINS` <sup>1</sup> | number | The maximum duration of the spider scan in minutes. Set to `0` for unlimited. Default: One minute, or unlimited when the scan is a full scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
-| `DAST_SPIDER_START_AT_HOST` | boolean | Set to `false` to prevent DAST from resetting the target to its host before scanning. When `true`, non-host targets `http://test.site/some_path` is reset to `http://test.site` before scan. Default: `true`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/258805) in GitLab 13.6. |
-| `DAST_SUBMIT_FIELD` <sup>2</sup> | 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_TARGET_AVAILABILITY_TIMEOUT` <sup>1</sup> | number | Time limit in seconds to wait for target availability. |
-| `DAST_USE_AJAX_SPIDER` <sup>1</sup> | boolean | Set to `true` to use the AJAX spider in addition to the traditional spider, useful for crawling sites that require JavaScript. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
-| `DAST_USERNAME` <sup>1,2</sup> | string | The username to authenticate to in the website. Example: `admin` |
-| `DAST_USERNAME_FIELD` <sup>1,2</sup> | string | The selector of username field at the sign-in HTML form. Example: `name:username` |
-| `DAST_XML_REPORT` | string | The filename of the XML report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
-| `DAST_WEBSITE` <sup>1</sup> | URL | The URL of the website to scan. The variable `DAST_API_SPECIFICATION` must be specified if this is omitted. |
-| `DAST_ZAP_CLI_OPTIONS` | string | ZAP server command-line options. For example, `-Xmx3072m` would set the Java maximum memory allocation pool size. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
-| `DAST_ZAP_LOG_CONFIGURATION` | string | Set to a semicolon-separated list of additional log4j properties for the ZAP Server. Example: `logger.httpsender.name=org.parosproxy.paros.network.HttpSender;logger.httpsender.level=debug;logger.sitemap.name=org.parosproxy.paros.model.SiteMap;logger.sitemap.level=debug;` |
-| `SECURE_ANALYZERS_PREFIX` | URL | Set the Docker registry base address from which to download the analyzer. |
-
-1. Available to an on-demand DAST scan.
-1. Used for authentication.
-
-### Customize DAST using command-line options
-
-Not all DAST configuration is available via CI/CD variables. To find out all
-possible options, run the following configuration.
-Available command-line options are printed to the job log:
-
-```yaml
-include:
- template: DAST.gitlab-ci.yml
-
-dast:
- script:
- - /analyze --help
-```
-
-You must then overwrite the `script` command to pass in the appropriate
-argument. For example, vulnerability definitions in alpha can be included with
-`-a`. The following configuration includes those definitions:
-
-```yaml
-include:
- template: DAST.gitlab-ci.yml
-
-dast:
- script:
- - export DAST_WEBSITE=${DAST_WEBSITE:-$(cat environment_url.txt)}
- - /analyze -a -t $DAST_WEBSITE
-```
-
-### Custom ZAProxy configuration
-
-The ZAProxy server contains many [useful configurable values](https://gitlab.com/gitlab-org/gitlab/-/issues/36437#note_245801885).
-Many key/values for `-config` remain undocumented, but there is an untested list of
-[possible keys](https://gitlab.com/gitlab-org/gitlab/-/issues/36437#note_244981023).
-Note that these options are not supported by DAST, and may break the DAST scan
-when used. An example of how to rewrite the Authorization header value with `TOKEN` follows:
-
-```yaml
-include:
- template: DAST.gitlab-ci.yml
-
-variables:
- DAST_ZAP_CLI_OPTIONS: "-config replacer.full_list(0).description=auth -config replacer.full_list(0).enabled=true -config replacer.full_list(0).matchtype=REQ_HEADER -config replacer.full_list(0).matchstr=Authorization -config replacer.full_list(0).regex=false -config replacer.full_list(0).replacement=TOKEN"
-```
-
-## Authentication
-
-NOTE:
-We highly recommend you configure the scanner to authenticate to the application. If you don't, it cannot check most of the application for security risks, as most
-of your application is likely not accessible without authentication. We also recommend
-you periodically confirm the scanner's authentication is still working, as this tends to break over
-time due to authentication changes to the application.
-
-Create masked CI/CD variables to pass the credentials that DAST uses.
-To create masked variables for the username and password, see [Create a custom variable in the UI](../../../ci/variables/index.md#custom-cicd-variables).
-The key of the username variable must be `DAST_USERNAME`,
-and the key of the password variable must be `DAST_PASSWORD`.
-
-After DAST has authenticated with the application, all cookies are collected from the web browser.
-For each cookie a matching session token is created for use by ZAP. This ensures ZAP is recognized
-by the application as correctly authenticated.
-
-Authentication supports single form logins, multi-step login forms, and authenticating to URLs outside of the configured target URL.
-
-WARNING:
-**Never** run an authenticated scan against a production server. When an authenticated
-scan is run, it may perform *any* function that the authenticated user can. This
-includes actions like modifying and deleting data, submitting forms, and following links.
-Only run an authenticated scan against a test server.
-
-### SSO
-
-DAST can authenticate to websites making use of SSO, with the following restrictions:
-
-- DAST cannot bypass a CAPTCHA if the authentication flow includes one.
-- DAST cannot handle multi-factor authentication like one-time passwords (OTP) by using SMS or authenticator apps.
-- DAST must get a cookie, or a local or session storage, with a sufficiently random value.
-
-The [authentication debug output](index.md#configure-the-authentication-debug-output) can be helpful for troubleshooting SSO authentication
-with DAST.
-
-### Log in using automatic detection of the login form
-
-By providing a `DAST_USERNAME`, `DAST_PASSWORD`, and `DAST_AUTH_URL`, DAST attempts to authenticate to the
-target application by locating the login form based on a determination about whether or not the form contains username or password fields.
-
-Automatic detection is "best-effort", and depending on the application being scanned may provide either a resilient login experience or one that fails to authenticate the user.
-
-Login process:
-
-1. The `DAST_AUTH_URL` is loaded into the browser, and any forms on the page are located.
- 1. If a form contains a username and password field, `DAST_USERNAME` and `DAST_PASSWORD` is inputted into the respective fields, the form submit button is selected and the user is logged in.
- 1. If a form contains only a username field, it is assumed that the login form is multi-step.
- 1. The `DAST_USERNAME` is inputted into the username field and the form submit button is selected.
- 1. The subsequent pages loads where it is expected that a form exists and contains a password field. If found, `DAST_PASSWORD` is inputted, form submit button is selected and the user is logged in.
-
-### Log in using explicit selection of the login form
-
-By providing a `DAST_USERNAME_FIELD`, `DAST_PASSWORD_FIELD`, and `DAST_SUBMIT_FIELD`, in addition to the fields required for automatic login,
-DAST attempts to authenticate to the target application by locating the login form based on the selectors provided.
-Most applications benefit from this approach to authentication.
-
-Login process:
-
-1. The `DAST_AUTH_URL` is loaded into the browser, and any forms on the page are located.
- 1. If the `DAST_FIRST_SUBMIT_FIELD` is not defined, then `DAST_USERNAME` is inputted into `DAST_USERNAME_FIELD`, `DAST_PASSWORD` is inputted into `DAST_PASSWORD_FIELD`, `DAST_SUBMIT_FIELD` is selected and the user is logged in.
- 1. If the `DAST_FIRST_SUBMIT_FIELD` is defined, then it is assumed that the login form is multi-step.
- 1. The `DAST_USERNAME` is inputted into the `DAST_USERNAME_FIELD` field and the `DAST_FIRST_SUBMIT_FIELD` is selected.
- 1. The subsequent pages loads where the `DAST_PASSWORD` is inputted into the `DAST_PASSWORD_FIELD` field, the `DAST_SUBMIT_FIELD` is selected and the user is logged in.
-
-### Verifying successful login
-
-Once the login form has been submitted, DAST determines if the login was successful. Unsuccessful attempts at authentication cause the scan to halt.
-
-Following the submission of the login form, authentication is determined to be unsuccessful when:
-
-- A `400` or `500` series HTTP response status code is returned.
-- A new cookie/browser storage value determined to be sufficiently random has not been set.
-
-In addition to these checks, the user can configure their own verification checks.
-Each of the following checks can be used in conjunction with one another, if none are configured by default the presence of a login form is checked.
-
-#### Verifying based on the URL
-
-When `DAST_AUTH_VERIFICATION_URL` is configured, the URL displayed in the browser tab post login form submission is directly compared to the URL in the CI/CD variable.
-If these are not exactly the same, authentication is deemed to be unsuccessful.
-
-For example:
-
-```yaml
-include:
- - template: DAST.gitlab-ci.yml
-
-dast:
- variables:
- DAST_WEBSITE: "https://example.com"
- DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
- ...
- DAST_AUTH_VERIFICATION_URL: "https://example.com/user/welcome"
-```
-
-#### Verify based on presence of an element
-
-When `DAST_AUTH_VERIFICATION_SELECTOR` is configured, the page displayed in the browser tab is searched for an element described by the selector in the CI/CD variable.
-If no element is found, authentication is deemed to be unsuccessful.
-
-For example:
-
-```yaml
-include:
- - template: DAST.gitlab-ci.yml
-
-dast:
- variables:
- DAST_WEBSITE: "https://example.com"
- DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
- ...
- DAST_AUTH_VERIFICATION_SELECTOR: "css:.welcome-user"
-```
-
-#### Verify based on presence of a login form
-
-When `DAST_AUTH_VERIFICATION_LOGIN_FORM` is configured, the page displayed in the browser tab is searched for a form that is detected to be a login form.
-If any such form is found, authentication is deemed to be unsuccessful.
-
-For example:
-
-```yaml
-include:
- - template: DAST.gitlab-ci.yml
-
-dast:
- variables:
- DAST_WEBSITE: "https://example.com"
- DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
- ...
- DAST_AUTH_VERIFICATION_LOGIN_FORM: "true"
-```
-
-### View the login form
-
-Many web applications show the user the login form in a pop-up (modal) window.
-For these applications, navigating to the form requires both:
-
-- A starting URL.
-- A list of elements to select to display the modal window.
-
-When `DAST_BROWSER_PATH_TO_LOGIN_FORM` is present, like in this example:
-
-```yaml
-include:
- - template: DAST.gitlab-ci.yml
-
-dast:
- variables:
- DAST_WEBSITE: "https://my.site.com"
- DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
- ...
- DAST_AUTH_URL: "https://my.site.com/admin"
- DAST_BROWSER_PATH_TO_LOGIN_FORM: "css:.navigation-menu,css:.login-menu-item"
-```
-
-DAST performs these actions:
-
-1. Load the `DAST_AUTH_URL` page, such as `https://my.site.com/admin`.
-1. After the page loads, DAST selects elements found by the selectors described
- in `DAST_BROWSER_PATH_TO_LOGIN_FORM`. This example opens the navigation menu
- and selects the login menu, to display the login modal window.
-1. To continue the authentication process, DAST fills in the username and password
- on the login form.
-
-### Configure the authentication debug output
-
-It is often difficult to understand the cause of an authentication failure when running DAST in a CI/CD pipeline.
-To assist users in debugging authentication issues, a debug report can be generated and saved as a job artifact.
-This HTML report contains all steps made during the login process, along with HTTP requests and responses, the Document Object Model (DOM) and screenshots.
-
-![dast-auth-report](img/dast_auth_report.jpg)
-
-An example configuration where the authentication debug report is exported may look like the following:
-
-```yaml
-dast:
- variables:
- DAST_WEBSITE: "https://example.com"
- DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
- ...
- DAST_AUTH_REPORT: "true"
- artifacts:
- paths: [gl-dast-debug-auth-report.html]
- when: always
-```
-
-### Selectors
-
-Selectors are used by CI/CD variables to specify the location of an element displayed on a page in a browser.
-Selectors have the format `type`:`search string`. The crawler searches for the selector using the search string based on the type.
-
-| Selector type | Example | Description |
-| ------------- | ---------------------------------- | ----------- |
-| `css` | `css:.password-field` | Searches for a HTML element having the supplied CSS selector. Selectors should be as specific as possible for performance reasons. |
-| `id` | `id:element` | Searches for an HTML element with the provided element ID. |
-| `name` | `name:element` | Searches for an HTML element with the provided element name. |
-| `xpath` | `xpath://input[@id="my-button"]/a` | Searches for a HTML element with the provided XPath. Note that XPath searches are expected to be less performant than other searches. |
-| None provided | `a.click-me` | Defaults to searching using a CSS selector. |
-
-#### Find selectors with Google Chrome
-
-Chrome DevTools element selector tool is an effective way to find a selector.
-
-1. Open Chrome and navigate to the page where you would like to find a selector, for example, the login page for your site.
-1. Open the `Elements` tab in Chrome DevTools with the keyboard shortcut `Command + Shift + c` in macOS or `Ctrl + Shift + c` in Windows.
-1. Select the `Select an element in the page to select it` tool.
- ![search-elements](img/dast_auth_browser_scan_search_elements.png)
-1. Select the field on your page that you would like to know the selector for.
-1. Once the tool is active, highlight a field you wish to view the details of.
- ![highlight](img/dast_auth_browser_scan_highlight.png)
-1. Once highlighted, you can see the element's details, including attributes that would make a good candidate for a selector.
-
-In this example, the `id="user_login"` appears to be a good candidate. You can use this as a selector as the DAST username field by setting
-`DAST_USERNAME_FIELD: "id:user_login"`.
-
-#### Choose the right selector
-
-Judicious choice of selector leads to a scan that is resilient to the application changing.
-
-In order of preference, it is recommended to choose as selectors:
-
-- `id` fields. These are generally unique on a page, and rarely change.
-- `name` fields. These are generally unique on a page, and rarely change.
-- `class` values specific to the field, such as the selector `"css:.username"` for the `username` class on the username field.
-- Presence of field specific data attributes, such as the selector, `"css:[data-username]"` when the `data-username` field has any value on the username field.
-- Multiple `class` hierarchy values, such as the selector `"css:.login-form .username"` when there are multiple elements with class `username` but only one nested inside the element with the class `login-form`.
-
-When using selectors to locate specific fields we recommend you avoid searching on:
-
-- Any `id`, `name`, `attribute`, `class` or `value` that is dynamically generated.
-- Generic class names, such as `column-10` and `dark-grey`.
-- XPath searches as they are less performant than other selector searches.
-- Unscoped searches, such as those beginning with `css:*` and `xpath://*`.
-
-### Bleeding-edge vulnerability definitions
-
-ZAP first creates rules in the `alpha` class. After a testing period with
-the community, they are promoted to `beta`. DAST uses `beta` definitions by
-default. To request `alpha` definitions, use the
-`DAST_INCLUDE_ALPHA_VULNERABILITIES` CI/CD variable as shown in the
-following configuration:
-
-```yaml
-include:
- template: DAST.gitlab-ci.yml
-
-variables:
- DAST_INCLUDE_ALPHA_VULNERABILITIES: "true"
-```
-
-### Cloning the project's repository
-
-The DAST job does not require the project's repository to be present when running, so by default
-[`GIT_STRATEGY`](../../../ci/runners/configure_runners.md#git-strategy) is set to `none`.
-
-## On-demand scans
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218465) in GitLab 13.2.
-> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/218465) in GitLab 13.3.
-> - The saved scans feature was [introduced](https://gitlab.com/groups/gitlab-org/-/epics/5100) in GitLab 13.9.
-> - The option to select a branch was [introduced](https://gitlab.com/groups/gitlab-org/-/epics/4847) in GitLab 13.10.
-> - DAST branch selection [feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/322672) in GitLab 13.11.
-> - Auditing for DAST profile management was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217872) in GitLab 14.1.
-
-An on-demand DAST scan runs outside the DevOps life cycle. Changes in your repository don't trigger
-the scan. You must either start it manually, or schedule it to run.
-
-An on-demand DAST scan:
-
-- Can run a specific combination of a [site profile](#site-profile) and a
- [scanner profile](#scanner-profile).
-- Is associated with your project's default branch.
-- Is saved on creation so it can be run later.
-
-### On-demand scan modes
-
-An on-demand scan can be run in active or passive mode:
-
-- _Passive mode_ is the default and runs a ZAP Baseline Scan.
-- _Active mode_ runs a ZAP Full Scan which is potentially harmful to the site being scanned. To
- minimize the risk of accidental damage, running an active scan requires a [validated site profile](#site-profile-validation).
-
-### View on-demand DAST scans
-
-To view running completed and scheduled on-demand DAST scans for a project, go to
-**Security & Compliance > On-demand Scans** in the left sidebar.
-
-- To view both running and completed scans, select **All**.
-- To view running scans only, select **Running**.
-- To view finished scans, select **Finished**. A finished scan is a scan that either succeeded,
- failed, or was canceled.
-- To view scheduled scans, select **Scheduled**. It shows on-demand scans that have a schedule
- set up. Those are _not_ included in the **All** tab.
-- To view saved on-demand scan profiles, select **Scan library**.
- Those are _not_ included in the **All** tab.
-
-#### Cancel an on-demand scan
-
-To cancel a pending or running on-demand scan, select **Cancel** (**{cancel}**) in the
-on-demand scans list.
-
-#### Retry an on-demand scan
-
-To retry a scan that failed or succeeded with warnings, select **Retry** (**{retry}**) in the
-on-demand scans list.
-
-#### View an on-demand scan's results
-
-To view a finished scan's results, select **View results** in the on-demand scans list.
-
-#### Edit an on-demand scan
-
-To edit an on-demand scan's settings, select **Edit** (**{pencil}**) in the **Scheduled** tab.
-
-### Run an on-demand DAST scan
-
-Prerequisites:
-
-- You must have permission to run an on-demand DAST scan against a protected branch. The default
- branch is automatically protected. For more information, read
- [Pipeline security on protected branches](../../../ci/pipelines/index.md#pipeline-security-on-protected-branches).
-- A [scanner profile](#create-a-scanner-profile).
-- A [site profile](#create-a-site-profile).
-- If you are running an active scan the site profile must have been [validated](#validate-a-site-profile).
-
-You can run an on-demand scan immediately, once at a scheduled date and time or at a specified
-frequency:
-
-- Every day
-- Every week
-- Every month
-- Every 3 months
-- Every 6 months
-- Every year
-
-To run an on-demand scan immediately, either:
-
-- [Create and run an on-demand scan immediately](#create-and-run-an-on-demand-scan-immediately).
-- [Run a previously saved on-demand scan](#run-a-saved-on-demand-scan).
-
-To run an on-demand scan either at a scheduled date or frequency, read
-[Schedule an on-demand scan](#schedule-an-on-demand-scan).
-
-#### Create and run an on-demand scan immediately
-
-1. From your project's home page, go to **Security & Compliance > On-demand Scans** in the left
- sidebar.
-1. Select **New scan**.
-1. Complete the **Scan name** and **Description** fields.
-1. In GitLab 13.10 and later, select the desired branch from the **Branch** dropdown.
-1. In **Scanner profile**, select a scanner profile from the dropdown.
-1. In **Site profile**, select a site profile from the dropdown.
-1. To run the on-demand scan immediately, select **Save and run scan**. Otherwise, select
- **Save scan** to [run](#run-a-saved-on-demand-scan) it later.
-
-The on-demand DAST scan runs and the project's dashboard shows the results.
-
-#### Run a saved on-demand scan
-
-To run a saved on-demand scan:
-
-1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > On-demand Scans**.
-1. Select the **Scan library** tab.
-1. In the scan's row, select **Run scan**.
-
- If the branch saved in the scan no longer exists, you must first
- [edit the scan](#edit-an-on-demand-scan), select a new branch, and save the edited scan.
-
-The on-demand DAST scan runs, and the project's dashboard shows the results.
-
-#### Schedule an on-demand scan
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/328749) in GitLab 14.3. [Deployed behind the `dast_on_demand_scans_scheduler` flag](../../../administration/feature_flags.md), disabled by default.
-> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/328749) in GitLab 14.4.
-> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/328749) in GitLab 14.4.
-> - [Feature flag `dast_on_demand_scans_scheduler` removed](https://gitlab.com/gitlab-org/gitlab/-/issues/328749) in GitLab 14.5.
-
-To schedule a scan:
-
-1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > On-demand Scans**.
-1. Select **New scan**.
-1. Complete the **Scan name** and **Description** text boxes.
-1. In GitLab 13.10 and later, from the **Branch** dropdown list, select the desired branch.
-1. In the **Scanner profile** section, from the dropdown list, select a scanner profile.
-1. In the **Site profile** section, from the dropdown list, select a site profile.
-1. Select **Schedule scan**.
-1. In the **Start time** section, select a time zone, date, and time.
-1. From the **Repeats** dropdown list, select your desired frequency:
- - To run the scan once, select **Never**.
- - For a recurring scan, select any other option.
-1. To run the on-demand scan immediately, select **Save and run scan**. To [run](#run-a-saved-on-demand-scan) it according to the schedule you set, select
- **Save scan**.
-
-#### List saved on-demand scans
-
-To list saved on-demand scans:
-
-1. From your project's home page, go to **Security & Compliance > On-demand Scans**.
-1. Select the **Scan library** tab.
-
-#### View details of an on-demand scan
-
-To view details of an on-demand scan:
-
-1. From your project's home page, go to **Security & Compliance > On-demand Scans**.
-1. Select the **Scan library** tab.
-1. In the saved scan's row select **More actions** (**{ellipsis_v}**), then select **Edit**.
-
-#### Edit an on-demand scan
-
-To edit an on-demand scan:
-
-1. From your project's home page, go to **Security & Compliance > On-demand Scans**.
-1. Select the **Scan library** tab.
-1. In the saved scan's row select **More actions** (**{ellipsis_v}**), then select **Edit**.
-1. Edit the form.
-1. Select **Save scan**.
-
-#### Delete an on-demand scan
-
-To delete an on-demand scan:
-
-1. From your project's home page, go to **Security & Compliance > On-demand Scans**.
-1. Select the **Scan library** tab.
-1. In the saved scan's row select **More actions** (**{ellipsis_v}**), then select **Delete**.
-1. Select **Delete** to confirm the deletion.
-
-## Site profile
-
-A site profile defines the attributes and configuration details of the deployed application,
-website, or API to be scanned by DAST. A site profile can be referenced in `.gitlab-ci.yml` and
-on-demand scans.
-
-A site profile contains:
-
-- **Profile name**: A name you assign to the site to be scanned. While a site profile is referenced
- in either `.gitlab-ci.yml` or an on-demand scan, it **cannot** be renamed.
-- **Site type**: The type of target to be scanned, either website or API scan.
-- **Target URL**: The URL that DAST runs against.
-- **Excluded URLs**: A comma-separated list of URLs to exclude from the scan.
-- **Request headers**: A comma-separated list of HTTP request headers, including names and values. These headers are added to every request made by DAST.
-- **Authentication**:
- - **Authenticated URL**: The URL of the page containing the sign-in HTML form on the target website. The username and password are submitted with the login form to create an authenticated scan.
- - **Username**: The username used to authenticate to the website.
- - **Password**: The password used to authenticate to the website.
- - **Username form field**: The name of username field at the sign-in HTML form.
- - **Password form field**: The name of password field at the sign-in HTML form.
- - **Submit form field**: The `id` or `name` of the element that when selected submits the sign-in HTML form.
-
-When an API site type is selected, a [host override](#host-override) is used to ensure the API being scanned is on the same host as the target. This is done to reduce the risk of running an active scan against the wrong API.
-
-When configured, request headers and password fields are encrypted using [`aes-256-gcm`](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) before being stored in the database.
-This data can only be read and decrypted with a valid secrets file.
-
-### Site profile validation
-
-> - Site profile validation [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/233020) in GitLab 13.8.
-> - Meta tag validation [introduced](https://gitlab.com/groups/gitlab-org/-/epics/6460) in GitLab 14.2.
-
-Site profile validation reduces the risk of running an active scan against the wrong website. A site
-must be validated before an active scan can run against it. The site validation methods are as
-follows:
-
-- _Text file validation_ requires a text file be uploaded to the target site. The text file is
- allocated a name and content that is unique to the project. The validation process checks the
- file's content.
-- _Header validation_ requires the header `Gitlab-On-Demand-DAST` be added to the target site,
- with a value unique to the project. The validation process checks that the header is present, and
- checks its value.
-- _Meta tag validation_ requires the meta tag named `gitlab-dast-validation` be added to the target site,
- with a value unique to the project. Make sure it's added to the `<head>` section of the page. The validation process checks that the meta tag is present, and
- checks its value.
-
-All these methods are equivalent in functionality. Use whichever is feasible.
-
-In [GitLab 14.2 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/324990), site profile
-validation happens in a CI job using the [GitLab Runner](../../../ci/runners/index.md).
-
-### Create a site profile
-
-To create a site profile:
-
-1. From your project's home page, go to **Security & Compliance > Configuration**.
-1. Select **Manage** in the **DAST Profiles** row.
-1. Select **New > Site Profile**.
-1. Complete the fields then select **Save profile**.
-
-The site profile is created.
-
-### Edit a site profile
-
-If a site profile is linked to a security policy, a user cannot edit the profile from this page. See
-[Scan execution policies](../policies/scan-execution-policies.md)
-for more information.
-
-When a validated site profile's file, header, or meta tag is edited, the site's
-[validation status](#site-profile-validation) is revoked.
-
-To edit a site profile:
-
-1. From your project's home page, go to **Security & Compliance > Configuration**.
-1. In the **DAST Profiles** row select **Manage**.
-1. Select the **Site Profiles** tab.
-1. In the profile's row select the **More actions** (**{ellipsis_v}**) menu, then select **Edit**.
-1. Edit the fields then select **Save profile**.
-
-### Delete a site profile
-
-If a site profile is linked to a security policy, a user cannot delete the profile from this page.
-See [Scan execution policies](../policies/scan-execution-policies.md)
-for more information.
-
-To delete a site profile:
-
-1. From your project's home page, go to **Security & Compliance > Configuration**.
-1. In the **DAST Profiles** row select **Manage**.
-1. Select the **Site Profiles** tab.
-1. In the profile's row, select the **More actions** (**{ellipsis_v}**) menu, then select **Delete**.
-1. Select **Delete** to confirm the deletion.
-
-### Validate a site profile
-
-Validating a site is required to run an active scan.
-
-To validate a site profile:
-
-1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Configuration**.
-1. In the **Dynamic Application Security Testing (DAST)** section, select **Manage profiles**.
-1. Select the **Site Profiles** tab.
-1. In the profile's row, select **Validate**.
-1. Select the validation method.
- 1. For **Text file validation**:
- 1. Download the validation file listed in **Step 2**.
- 1. Upload the validation file to the host, to the location in **Step 3** or any location you
- prefer.
- 1. If required, edit the file location in **Step 3**.
- 1. Select **Validate**.
- 1. For **Header validation**:
- 1. Select the clipboard icon in **Step 2**.
- 1. Edit the header of the site to validate, and paste the clipboard content.
- 1. Select the input field in **Step 3** and enter the location of the header.
- 1. Select **Validate**.
- 1. For **Meta tag validation**:
- 1. Select the clipboard icon in **Step 2**.
- 1. Edit the content of the site to validate, and paste the clipboard content.
- 1. Select the input field in **Step 3** and enter the location of the meta tag.
- 1. Select **Validate**.
-
-The site is validated and an active scan can run against it. A site profile's validation status is
-revoked only when it's revoked manually, or its file, header, or meta tag is edited.
-
-### Retry a failed validation
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/322609) in GitLab 14.3.
-> - [Deployed behind the `dast_failed_site_validations` flag](../../../administration/feature_flags.md), enabled by default.
-> - [Feature flag `dast_failed_site_validations` removed](https://gitlab.com/gitlab-org/gitlab/-/issues/323961) in GitLab 14.4.
-
-Failed site validation attempts are listed on the **Site profiles** tab of the **Manage profiles**
-page.
-
-To retry a site profile's failed validation:
-
-1. On the top bar, select **Main menu > Projects** and find your project.
-1. On the left sidebar, select **Security & Compliance > Configuration**.
-1. In the **Dynamic Application Security Testing (DAST)** section, select **Manage profiles**.
-1. Select the **Site Profiles** tab.
-1. In the profile's row, select **Retry validation**.
-
-### Revoke a site profile's validation status
-
-WARNING:
-When a site profile's validation status is revoked, all site profiles that share the same URL also
-have their validation status revoked.
-
-To revoke a site profile's validation status:
-
-1. From your project's home page, go to **Security & Compliance > Configuration**.
-1. In the **DAST Profiles** row select **Manage**.
-1. Beside the validated profile, select **Revoke validation**.
-
-The site profile's validation status is revoked.
-
-### Validated site profile headers
-
-The following are code samples of how you can provide the required site profile header in your
-application.
-
-#### Ruby on Rails example for on-demand scan
-
-Here's how you can add a custom header in a Ruby on Rails application:
-
-```ruby
-class DastWebsiteTargetController < ActionController::Base
- def dast_website_target
- response.headers['Gitlab-On-Demand-DAST'] = '0dd79c9a-7b29-4e26-a815-eaaf53fcab1c'
- head :ok
- end
-end
-```
-
-#### Django example for on-demand scan
-
-Here's how you can add a
-[custom header in Django](https://docs.djangoproject.com/en/2.2/ref/request-response/#setting-header-fields):
-
-```python
-class DastWebsiteTargetView(View):
- def head(self, *args, **kwargs):
- response = HttpResponse()
- response['Gitlab-On-Demand-DAST'] = '0dd79c9a-7b29-4e26-a815-eaaf53fcab1c'
-
- return response
-```
-
-#### Node (with Express) example for on-demand scan
-
-Here's how you can add a
-[custom header in Node (with Express)](https://expressjs.com/en/5x/api.html#res.append):
-
-```javascript
-app.get('/dast-website-target', function(req, res) {
- res.append('Gitlab-On-Demand-DAST', '0dd79c9a-7b29-4e26-a815-eaaf53fcab1c')
- res.send('Respond to DAST ping')
-})
-```
-
-## Scanner profile
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/222767) in GitLab 13.4.
-> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/225804) in GitLab 13.5: scan mode, AJAX spider, debug messages.
-
-A scanner profile defines the configuration details of a security scanner. A scanner profile can be
-referenced in `.gitlab-ci.yml` and on-demand scans.
-
-A scanner profile contains:
-
-- **Profile name:** A name you give the scanner profile. For example, "Spider_15". While a scanner
- profile is referenced in either `.gitlab-ci.yml` or an on-demand scan, it **cannot** be renamed.
-- **Scan mode:** A passive scan monitors all HTTP messages (requests and responses) sent to the target. An active scan attacks the target to find potential vulnerabilities.
-- **Spider timeout:** The maximum number of minutes allowed for the spider to traverse the site.
-- **Target timeout:** The maximum number of seconds DAST waits for the site to be available before
- starting the scan.
-- **AJAX spider:** Run the AJAX spider, in addition to the traditional spider, to crawl the target site.
-- **Debug messages:** Include debug messages in the DAST console output.
-
-### Create a scanner profile
-
-To create a scanner profile:
-
-1. From your project's home page, go to **Security & Compliance > Configuration**.
-1. In the **DAST Profiles** row, select **Manage**.
-1. Select **New > Scanner Profile**.
-1. Complete the form. For details of each field, see [Scanner profile](#scanner-profile).
-1. Select **Save profile**.
-
-### Edit a scanner profile
-
-If a scanner profile is linked to a security policy, a user cannot edit the profile from this page.
-See [Scan execution policies](../policies/scan-execution-policies.md)
-for more information.
-
-To edit a scanner profile:
-
-1. From your project's home page, go to **Security & Compliance > Configuration**.
-1. In the **DAST Profiles** row, select **Manage**.
-1. Select the **Scanner Profiles** tab.
-1. In the scanner's row, select the **More actions** (**{ellipsis_v}**) menu, then select **Edit**.
-1. Edit the form.
-1. Select **Save profile**.
-
-### Delete a scanner profile
-
-If a scanner profile is linked to a security policy, a user cannot delete the profile from this
-page. See [Scan execution policies](../policies/scan-execution-policies.md)
-for more information.
-
-To delete a scanner profile:
-
-1. From your project's home page, go to **Security & Compliance > Configuration**.
-1. In the **DAST Profiles** row, select **Manage**.
-1. Select the **Scanner Profiles** tab.
-1. In the scanner's row, select the **More actions** (**{ellipsis_v}**) menu, then select **Delete**.
-1. Select **Delete**.
-
-## Auditing
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217872) in GitLab 14.1.
-
-The creation, updating, and deletion of DAST profiles, DAST scanner profiles,
-and DAST site profiles are included in the [audit log](../../../administration/audit_events.md).
-
-## Reports
-
-The DAST tool outputs a `gl-dast-report.json` report file containing details of the scan and its results.
-This file is included in the job's artifacts. JSON is the default format, but
-you can output the report in Markdown, HTML, and XML formats. To specify an alternative
-format, use a [CI/CD variable](#available-cicd-variables). You can also use a CI/CD variable
-to configure the job to output the `gl-dast-debug-auth-report.html` file which helps when debugging
-authentication issues.
-
-For details of the report's schema, see the [schema for DAST reports](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/dast-report-format.json). Example reports can be found in the
-[DAST repository](https://gitlab.com/gitlab-org/security-products/dast/-/tree/main/test/end-to-end/expect).
-
-WARNING:
-The JSON report artifacts are not a public API of DAST and their format is expected to change in the
-future.
-
-## Optimizing DAST
-
-By default, DAST downloads all artifacts defined by previous jobs in the pipeline. If
-your DAST job does not rely on `environment_url.txt` to define the URL under test or any other files created
-in previous jobs, we recommend you don't download artifacts. To avoid downloading
-artifacts, add the following to your `.gitlab-ci.yml` file:
-
-```yaml
-dast:
- dependencies: []
-```
diff --git a/doc/user/application_security/dast/proxy-based.md b/doc/user/application_security/dast/proxy-based.md
new file mode 100644
index 00000000000..ec98b809fb7
--- /dev/null
+++ b/doc/user/application_security/dast/proxy-based.md
@@ -0,0 +1,1247 @@
+---
+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
+---
+
+# DAST proxy-based analyzer **(ULTIMATE)**
+
+The DAST proxy-based analyzer can be added to your [GitLab CI/CD](../../../ci/index.md) pipeline.
+This helps you discover vulnerabilities in web applications that do not use JavaScript heavily. For applications that do,
+please see the [DAST browser-based analyzer](browser_based.md).
+
+WARNING:
+Do not run DAST scans against a production server. Not only can it perform *any* function that
+a user can, such as clicking buttons or submitting forms, but it may also trigger bugs, leading to modification or loss of production data. Only run DAST scans against a test server.
+
+The analyzer uses the [OWASP Zed Attack Proxy](https://www.zaproxy.org/) (ZAP) to scan in two different ways:
+
+- Passive scan only (default). DAST executes
+ [ZAP's Baseline Scan](https://www.zaproxy.org/docs/docker/baseline-scan/) and doesn't
+ actively attack your application.
+- Passive and active (or full) scan. DAST can be [configured](#full-scan) to also perform an active scan
+ to attack your application and produce a more extensive security report. It can be very
+ useful when combined with [Review Apps](../../../ci/review_apps/index.md).
+
+## DAST run options
+
+You can use DAST to examine your web application:
+
+- Automatically, initiated by a merge request.
+- Manually, initiated on demand.
+
+Some of the differences between these run options:
+
+| Automatic scan | On-demand scan |
+|:-----------------------------------------------------------------|:------------------------------|
+| DAST scan is initiated by a merge request. | DAST scan is initiated manually, outside the DevOps life cycle. |
+| CI/CD variables are sourced from `.gitlab-ci.yml`. | CI/CD variables are provided in the UI. |
+| All [DAST CI/CD variables](#available-cicd-variables) available. | Subset of [DAST CI/CD variables](#available-cicd-variables) available. |
+| `DAST.gitlab-ci.yml` template. | `DAST-On-Demand-Scan.gitlab-ci.yml` template. |
+
+### Enable automatic DAST run
+
+To enable DAST to run automatically, either:
+
+- Enable [Auto DAST](../../../topics/autodevops/stages.md#auto-dast) (provided
+ by [Auto DevOps](../../../topics/autodevops/index.md)).
+- [Include the DAST template](#include-the-dast-template) in your existing
+ `.gitlab-ci.yml` file.
+- [Configure DAST using the UI](#configure-dast-using-the-ui).
+
+#### Include the DAST template
+
+> - This template was [updated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62597) to DAST_VERSION: 2 in GitLab 14.0.
+> - This template was [updated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87183) to DAST_VERSION: 3 in GitLab 15.0.
+
+If you want to manually add DAST to your application, the DAST job is defined
+in a CI/CD template file. Updates to the template are provided with GitLab
+upgrades, allowing you to benefit from any improvements and additions.
+
+To include the DAST template:
+
+1. Select the CI/CD template you want to use:
+
+ - [`DAST.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml):
+ Stable version of the DAST CI/CD template.
+ - [`DAST.latest.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/DAST.latest.gitlab-ci.yml):
+ Latest version of the DAST template. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/254325)
+ in GitLab 13.8).
+
+ WARNING:
+ The latest version of the template may include breaking changes. Use the
+ stable template unless you need a feature provided only in the latest template.
+
+ For more information about template versioning, see the
+ [CI/CD documentation](../../../development/cicd/templates.md#latest-version).
+
+1. Add a `dast` stage to your GitLab CI stages configuration:
+
+ ```yaml
+ stages:
+ - dast
+ ```
+
+1. Add the template to GitLab, based on your version of GitLab:
+
+ - In GitLab 11.9 and later, [include](../../../ci/yaml/index.md#includetemplate)
+ the template by adding the following to your `.gitlab-ci.yml` file:
+
+ ```yaml
+ include:
+ - template: <template_file.yml>
+
+ variables:
+ DAST_WEBSITE: https://example.com
+ ```
+
+ - In GitLab 11.8 and earlier, add the contents of the template to your
+ `.gitlab_ci.yml` file.
+
+1. Define the URL to be scanned by DAST by using one of these methods:
+
+ - Set the `DAST_WEBSITE` [CI/CD variable](../../../ci/yaml/index.md#variables).
+ If set, this value takes precedence.
+
+ - Add the URL in an `environment_url.txt` file at the root of your project. This is
+ useful for testing in dynamic environments. To run DAST against an application
+ dynamically created during a GitLab CI/CD pipeline, a job that runs prior to
+ the DAST scan must persist the application's domain in an `environment_url.txt`
+ file. DAST automatically parses the `environment_url.txt` file to find its
+ scan target.
+
+ For example, in a job that runs prior to DAST, you could include code that
+ looks similar to:
+
+ ```yaml
+ script:
+ - echo http://${CI_PROJECT_ID}-${CI_ENVIRONMENT_SLUG}.domain.com > environment_url.txt
+ artifacts:
+ paths: [environment_url.txt]
+ when: always
+ ```
+
+ You can see an example of this in our
+ [Auto DevOps CI YAML](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml)
+ file.
+
+The included template creates a `dast` job in your CI/CD pipeline and scans
+your project's running application for possible vulnerabilities.
+
+The results are saved as a
+[DAST report artifact](../../../ci/yaml/artifacts_reports.md#artifactsreportsdast)
+that you can later download and analyze. Due to implementation limitations, we
+always take the latest DAST artifact available. Behind the scenes, the
+[GitLab DAST Docker image](https://gitlab.com/security-products/dast)
+is used to run the tests on the specified URL and scan it for possible
+vulnerabilities.
+
+By default, the DAST template uses the latest major version of the DAST Docker
+image. Using the `DAST_VERSION` variable, you can choose how DAST updates:
+
+- Automatically update DAST with new features and fixes by pinning to a major
+ version (such as `1`).
+- Only update fixes by pinning to a minor version (such as `1.6`).
+- Prevent all updates by pinning to a specific version (such as `1.6.4`).
+
+Find the latest DAST versions on the [Releases](https://gitlab.com/gitlab-org/security-products/dast/-/releases)
+page.
+
+#### Configure DAST using the UI
+
+You can enable or configure DAST settings using the UI. The generated settings are formatted so they
+can be conveniently pasted into the `.gitlab-ci.yml` file.
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Security & Compliance > Configuration**.
+1. In the **Dynamic Application Security Testing (DAST)** section, select **Enable DAST** or
+ **Configure DAST**.
+1. Select the desired **Scanner profile**, or select **Create scanner profile** and save a
+ scanner profile. For more details, see [scanner profiles](#scanner-profile).
+1. Select the desired **Site profile**, or select **Create site profile** and save a site
+ profile. For more details, see [site profiles](#site-profile).
+1. Select **Generate code snippet**. A modal opens with the YAML snippet corresponding to the
+ options you selected.
+1. Do one of the following:
+ 1. To copy the snippet to your clipboard, select **Copy code only**.
+ 1. To add the snippet to your project's `.gitlab-ci.yml` file, select
+ **Copy code and open `.gitlab-ci.yml` file**. The Pipeline Editor opens.
+ 1. Paste the snippet into the `.gitlab-ci.yml` file.
+ 1. Select the **Lint** tab to confirm the edited `.gitlab-ci.yml` file is valid.
+ 1. Select the **Edit** tab, then select **Commit changes**.
+
+When the snippet is committed to the `.gitlab-ci.yml` file, pipelines include a DAST job.
+
+### API scan
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10928) in GitLab 12.10.
+> - A new DAST API scanning engine was introduced in GitLab 13.10.
+
+Using an API specification as a scan's target is a useful way to seed URLs for scanning an API.
+Vulnerability rules in an API scan are different than those in a normal website scan.
+
+A new DAST API scanning engine is available in GitLab 13.12 and later. For more details, see [DAST API scanning engine](../dast_api). The new scanning engine supports REST, SOAP, GraphQL, and generic APIs using forms, XML, and JSON. Testing can be performed using OpenAPI, Postman Collections, and HTTP Archive (HAR) documents.
+
+The target API instance's base URL is provided by using the `DAST_API_TARGET_URL` variable or an `environment_url.txt` file.
+
+#### Specification format
+
+API scans support OpenAPI V2 and OpenAPI V3 specifications. You can define these specifications using `JSON` or `YAML`.
+
+#### Import API specification from a URL
+
+If your API specification is accessible at a URL, you can pass that URL in directly as the target.
+The specification does not have to be hosted on the same host as the API being tested.
+
+```yaml
+include:
+ - template: DAST-API.gitlab-ci.yml
+
+variables:
+ DAST_API_SPECIFICATION: http://my.api/api-specification.yml
+```
+
+#### Import API specification from a file
+
+If your API specification file is in your repository, you can provide its filename as the target.
+
+```yaml
+dast:
+ variables:
+ GIT_STRATEGY: fetch
+ DAST_API_SPECIFICATION: api-specification.yml
+```
+
+#### Full API scan
+
+API scans support full scanning, which can be enabled by using the `DAST_FULL_SCAN_ENABLED`
+CI/CD variable. Domain validation is not supported for full API scans.
+
+#### Host override
+
+Specifications often define a host, which contains a domain name and a port. The
+host referenced may be different than the host of the API's review instance.
+This can cause incorrect URLs to be imported, or a scan on an incorrect host.
+Use the `DAST_API_HOST_OVERRIDE` CI/CD variable to override these values.
+
+WARNING:
+When using the API host override feature, you cannot use the `$DAST_WEBSITE` variable to override the hostname.
+A host override is _only_ supported when importing the API specification from a URL. Attempts to override the
+host throw an error when the API specification is imported from a file. This is due to a limitation in the
+ZAP OpenAPI extension.
+
+For example, with a OpenAPI V3 specification containing:
+
+```yaml
+servers:
+ - url: https://api.host.com
+```
+
+If the test version of the API is running at `https://api-test.host.com`, then
+the following DAST configuration can be used:
+
+```yaml
+include:
+ - template: DAST-API.gitlab-ci.yml
+
+variables:
+ DAST_API_SPECIFICATION: http://api-test.host.com/api-specification.yml
+ DAST_API_HOST_OVERRIDE: api-test.host.com
+```
+
+#### Authentication using headers
+
+Tokens in request headers are often used as a way to authenticate API requests.
+You can achieve this by using the `DAST_REQUEST_HEADERS` CI/CD variable.
+Headers are applied to every request DAST makes.
+
+```yaml
+include:
+ - template: DAST-API.gitlab-ci.yml
+
+variables:
+ DAST_API_SPECIFICATION: http://api-test.api.com/api-specification.yml
+ DAST_REQUEST_HEADERS: "Authorization: Bearer my.token"
+```
+
+### URL scan
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214120) in GitLab 13.4.
+> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/273141) in GitLab 13.11.
+
+A URL scan allows you to specify which parts of a website are scanned by DAST.
+
+#### Define the URLs to scan
+
+URLs to scan can be specified by either of the following methods:
+
+- Use `DAST_PATHS_FILE` CI/CD variable to specify the name of a file containing the paths.
+- Use `DAST_PATHS` variable to list the paths.
+
+##### Use `DAST_PATHS_FILE` CI/CD variable
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/258825) in GitLab 13.6.
+
+To define the URLs to scan in a file, create a plain text file with one path per line.
+
+```plaintext
+page1.html
+/page2.html
+category/shoes/page1.html
+```
+
+To scan the URLs in that file, set the CI/CD variable `DAST_PATHS_FILE` to the path of that file.
+The file can be checked into the project repository or generated as an artifact by a job that
+runs before DAST.
+
+By default, DAST scans do not clone the project repository. Instruct the DAST job to clone
+the project by setting `GIT_STRATEGY` to fetch. Give a file path relative to `CI_PROJECT_DIR` to `DAST_PATHS_FILE`.
+
+```yaml
+include:
+ - template: DAST.gitlab-ci.yml
+
+variables:
+ GIT_STRATEGY: fetch
+ DAST_PATHS_FILE: url_file.txt # url_file.txt lives in the root directory of the project
+ DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
+```
+
+##### Use `DAST_PATHS` CI/CD variable
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214120) in GitLab 13.4.
+
+To specify the paths to scan in a CI/CD variable, add a comma-separated list of the paths to the `DAST_PATHS`
+variable. Note that you can only scan paths of a single host.
+
+```yaml
+include:
+ - template: DAST.gitlab-ci.yml
+
+variables:
+ DAST_PATHS: "/page1.html,/category1/page1.html,/page3.html"
+ DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
+```
+
+When using `DAST_PATHS` and `DAST_PATHS_FILE`, note the following:
+
+- `DAST_WEBSITE` must be defined when using either `DAST_PATHS_FILE` or `DAST_PATHS`. The paths listed in either use `DAST_WEBSITE` to build the URLs to scan
+- Spidering is disabled when `DAST_PATHS` or `DAST_PATHS_FILE` are defined
+- `DAST_PATHS_FILE` and `DAST_PATHS` cannot be used together
+- The `DAST_PATHS` variable has a limit of about 130kb. If you have a list or paths
+ greater than this, use `DAST_PATHS_FILE`.
+
+#### Full Scan
+
+To perform a [full scan](#full-scan) on the listed paths, use the `DAST_FULL_SCAN_ENABLED` CI/CD variable.
+
+## Customize DAST settings
+
+You can customize the behavior of DAST using both CI/CD variables and command-line options. Use of CI/CD
+variables overrides the values contained in the DAST template.
+
+### Customize DAST using CI/CD variables
+
+WARNING:
+Beginning in GitLab 13.0, the use of [`only` and `except`](../../../ci/yaml/index.md#only--except)
+is no longer supported. You must use [`rules`](../../../ci/yaml/index.md#rules) instead.
+
+The DAST settings can be changed through CI/CD variables by using the
+[`variables`](../../../ci/yaml/index.md#variables) parameter in `.gitlab-ci.yml`. For details of
+all DAST CI/CD variables, read [Available CI/CD variables](#available-cicd-variables).
+
+For example:
+
+```yaml
+include:
+ - template: DAST.gitlab-ci.yml
+
+variables:
+ DAST_WEBSITE: https://example.com
+ DAST_SPIDER_MINS: 120
+ DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
+```
+
+Because the template is [evaluated before](../../../ci/yaml/index.md#include) the pipeline
+configuration, the last mention of the variable takes precedence.
+
+#### Enable or disable rules
+
+A complete list of the rules that DAST uses to scan for vulnerabilities can be
+found in the [ZAP documentation](https://www.zaproxy.org/docs/alerts/).
+
+`DAST_EXCLUDE_RULES` disables the rules with the given IDs.
+
+`DAST_ONLY_INCLUDE_RULES` restricts the set of rules used in the scan to
+those with the given IDs.
+
+`DAST_EXCLUDE_RULES` and `DAST_ONLY_INCLUDE_RULES` are mutually exclusive and a
+DAST scan with both configured exits with an error.
+
+By default, several rules are disabled because they either take a long time to
+run or frequently generate false positives. The complete list of disabled rules
+can be found in [`exclude_rules.yml`](https://gitlab.com/gitlab-org/security-products/dast/-/blob/main/src/config/exclude_rules.yml).
+
+The lists for `DAST_EXCLUDE_RULES` and `DAST_ONLY_INCLUDE_RULES` **must** be enclosed in double
+quotes (`"`), otherwise they are interpreted as numeric values.
+
+#### Hide sensitive information
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/36332) in GitLab 13.1.
+
+HTTP request and response headers may contain sensitive information, including cookies and
+authorization credentials. By default, the following headers are masked:
+
+- `Authorization`.
+- `Proxy-Authorization`.
+- `Set-Cookie` (values only).
+- `Cookie` (values only).
+
+Using the [`DAST_MASK_HTTP_HEADERS` CI/CD variable](#available-cicd-variables), you can list the
+headers whose values you want masked. For details on how to mask headers, see
+[Customizing the DAST settings](#customize-dast-settings).
+
+#### Use Mutual TLS
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/299596) in GitLab 14.8.
+
+Mutual TLS allows a target application server to verify that requests are from a known source. Browser-based scans do not support Mutual TLS.
+
+**Requirements**
+
+- Base64-encoded PKCS12 certificate
+- Password of the base64-encoded PKCS12 certificate
+
+To enable Mutual TLS:
+
+1. If the PKCS12 certificate is not already base64-encoded, convert it to base64 encoding. For security reasons, we recommend encoding the certificate locally, **not** using a web-hosted conversion service. For example, to encode the certificate on either macOS or Linux:
+
+ ```shell
+ base64 <path-to-pkcs12-certificate-file>
+ ```
+
+1. Create a [masked variable](../../../ci/variables/index.md) named `DAST_PKCS12_CERTIFICATE_BASE64` and store the base64-encoded PKCS12 certificate's value in that variable.
+1. Create a masked variable `DAST_PKCS12_PASSWORD` and store the PKCS12 certificate's password in that variable.
+
+#### Available CI/CD variables
+
+These CI/CD variables are specific to DAST. They can be used to customize the behavior of DAST to your requirements.
+
+WARNING:
+All customization of GitLab security scanning tools should be tested in a merge request before
+merging these changes to the default branch. Failure to do so can give unexpected results,
+including a large number of false positives.
+
+| CI/CD variable | Type | Description |
+|:-------------------------------------------------|:--------------|:------------------------------|
+| `DAST_ADVERTISE_SCAN` | boolean | 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_AGGREGATE_VULNERABILITIES` | boolean | Vulnerability aggregation is set to `true` by default. To disable this feature and see each vulnerability individually set to `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/254043) in GitLab 14.0. |
+| `DAST_API_HOST_OVERRIDE` <sup>1</sup> | string | Used to override domains defined in API specification files. Only supported when importing the API specification from a URL. Example: `example.com:8080`. |
+| `DAST_API_SPECIFICATION` <sup>1</sup> | URL or string | The API specification to import. The specification can be hosted at a URL, or the name of a file present in the `/zap/wrk` directory. The variable `DAST_WEBSITE` must be specified if this is omitted. |
+| `DAST_AUTH_REPORT` <sup>2</sup> | boolean | Used in combination with exporting the `gl-dast-debug-auth-report.html` artifact to aid in debugging authentication issues. |
+| `DAST_AUTH_EXCLUDE_URLS` <sup>2</sup> | URLs | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/289959)** in GitLab 14.0. Replaced by `DAST_EXCLUDE_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. Not supported for API scans. |
+| `DAST_AUTH_URL` <sup>1,2</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. Not supported for API scans. Example: `https://login.example.com`. |
+| `DAST_AUTH_VERIFICATION_LOGIN_FORM` <sup>2</sup> | boolean | Verifies successful authentication by checking for the lack of a login form once the login form has been submitted. |
+| `DAST_AUTH_VERIFICATION_SELECTOR` <sup>2</sup> | 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,2</sup> | URL | A URL only accessible to logged in users that DAST can use to confirm successful authentication. If provided, DAST exits if it cannot access the URL. Example: `"http://example.com/loggedin_page"`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/207335) in GitLab 13.8. |
+| `DAST_AUTO_UPDATE_ADDONS` | boolean | ZAP add-ons are pinned to specific versions in the DAST Docker image. Set to `true` to download the latest versions when the scan starts. Default: `false`. |
+| `DAST_BROWSER_PATH_TO_LOGIN_FORM` <sup>1,2</sup> | 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_DEBUG` <sup>1</sup> | boolean | Enable debug message output. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
+| `DAST_EXCLUDE_RULES` | string | Set to a comma-separated list of Vulnerability Rule IDs to exclude them from running during the scan. Rule IDs are numbers and can be found from the DAST log or on the [ZAP project](https://www.zaproxy.org/docs/alerts/). For example, `HTTP Parameter Override` has a rule ID of `10026`. Cannot be used when `DAST_ONLY_INCLUDE_RULES` is set. **Note:** In earlier versions of GitLab the excluded rules were executed but vulnerabilities they generated were suppressed. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118641) in GitLab 12.10. |
+| `DAST_EXCLUDE_URLS` <sup>1,2</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. Not supported for API scans. Example, `http://example.com/sign-out`. |
+| `DAST_FIRST_SUBMIT_FIELD` <sup>2</sup> | 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_FULL_SCAN_DOMAIN_VALIDATION_REQUIRED` | boolean | **{warning}** **[Removed](https://gitlab.com/gitlab-org/gitlab/-/issues/293595)** in GitLab 14.0. Set to `true` to require domain validation when running DAST full scans. Not supported for API scans. Default: `false` |
+| `DAST_FULL_SCAN_ENABLED` <sup>1</sup> | boolean | Set to `true` to run a [ZAP Full Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Full-Scan) instead of a [ZAP Baseline Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Baseline-Scan). Default: `false` |
+| `DAST_HTML_REPORT` | string | The filename of the HTML report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
+| `DAST_INCLUDE_ALPHA_VULNERABILITIES` | boolean | Set to `true` to include alpha passive and active scan rules. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
+| `DAST_MARKDOWN_REPORT` | string | The filename of the Markdown report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
+| `DAST_MASK_HTTP_HEADERS` | string | Comma-separated list of request and response headers to be masked (GitLab 13.1). Must contain **all** headers to be masked. Refer to [list of headers that are masked by default](#hide-sensitive-information). |
+| `DAST_MAX_URLS_PER_VULNERABILITY` | number | The maximum number of URLs reported for a single vulnerability. `DAST_MAX_URLS_PER_VULNERABILITY` is set to `50` by default. To list all the URLs set to `0`. [Introduced](https://gitlab.com/gitlab-org/security-products/dast/-/merge_requests/433) in GitLab 13.12. |
+| `DAST_ONLY_INCLUDE_RULES` | string | Set to a comma-separated list of Vulnerability Rule IDs to configure the scan to run only them. Rule IDs are numbers and can be found from the DAST log or on the [ZAP project](https://www.zaproxy.org/docs/alerts/). Cannot be used when `DAST_EXCLUDE_RULES` is set. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/250651) in GitLab 13.12. |
+| `DAST_PASSWORD` <sup>1,2</sup> | string | The password to authenticate to in the website. Example: `P@55w0rd!` |
+| `DAST_PASSWORD_FIELD` <sup>1,2</sup> | string | The selector of password field at the sign-in HTML form. Example: `id:password` |
+| `DAST_PATHS` | string | Set to a comma-separated list of URLs for DAST to scan. For example, `/page1.html,/category1/page3.html,/page2.html`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214120) in GitLab 13.4. |
+| `DAST_PATHS_FILE` | string | The file path containing the paths within `DAST_WEBSITE` to scan. The file must be plain text with one path per line. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/258825) in GitLab 13.6. |
+| `DAST_PKCS12_CERTIFICATE_BASE64` | string | The PKCS12 certificate used for sites that require Mutual TLS. Must be encoded as base64 text. |
+| `DAST_PKCS12_PASSWORD` | string | The password of the certificate used in `DAST_PKCS12_CERTIFICATE_BASE64`. |
+| `DAST_REQUEST_HEADERS` <sup>1</sup> | string | Set to a comma-separated list of request header names and values. Headers are added to every request made by DAST. For example, `Cache-control: no-cache,User-Agent: DAST/1.0` |
+| `DAST_SKIP_TARGET_CHECK` | boolean | Set to `true` to prevent DAST from checking that the target is available before scanning. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229067) in GitLab 13.8. |
+| `DAST_SPIDER_MINS` <sup>1</sup> | number | The maximum duration of the spider scan in minutes. Set to `0` for unlimited. Default: One minute, or unlimited when the scan is a full scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
+| `DAST_SPIDER_START_AT_HOST` | boolean | Set to `false` to prevent DAST from resetting the target to its host before scanning. When `true`, non-host targets `http://test.site/some_path` is reset to `http://test.site` before scan. Default: `true`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/258805) in GitLab 13.6. |
+| `DAST_SUBMIT_FIELD` <sup>2</sup> | 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_TARGET_AVAILABILITY_TIMEOUT` <sup>1</sup> | number | Time limit in seconds to wait for target availability. |
+| `DAST_USE_AJAX_SPIDER` <sup>1</sup> | boolean | Set to `true` to use the AJAX spider in addition to the traditional spider, useful for crawling sites that require JavaScript. Default: `false`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
+| `DAST_USERNAME` <sup>1,2</sup> | string | The username to authenticate to in the website. Example: `admin` |
+| `DAST_USERNAME_FIELD` <sup>1,2</sup> | string | The selector of username field at the sign-in HTML form. Example: `name:username` |
+| `DAST_XML_REPORT` | string | The filename of the XML report written at the end of a scan. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
+| `DAST_WEBSITE` <sup>1</sup> | URL | The URL of the website to scan. The variable `DAST_API_SPECIFICATION` must be specified if this is omitted. |
+| `DAST_ZAP_CLI_OPTIONS` | string | ZAP server command-line options. For example, `-Xmx3072m` would set the Java maximum memory allocation pool size. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12652) in GitLab 13.1. |
+| `DAST_ZAP_LOG_CONFIGURATION` | string | Set to a semicolon-separated list of additional log4j properties for the ZAP Server. Example: `logger.httpsender.name=org.parosproxy.paros.network.HttpSender;logger.httpsender.level=debug;logger.sitemap.name=org.parosproxy.paros.model.SiteMap;logger.sitemap.level=debug;` |
+| `SECURE_ANALYZERS_PREFIX` | URL | Set the Docker registry base address from which to download the analyzer. |
+
+1. Available to an on-demand DAST scan.
+1. Used for authentication.
+
+### Customize DAST using command-line options
+
+Not all DAST configuration is available via CI/CD variables. To find out all
+possible options, run the following configuration.
+Available command-line options are printed to the job log:
+
+```yaml
+include:
+ template: DAST.gitlab-ci.yml
+
+dast:
+ script:
+ - /analyze --help
+```
+
+You must then overwrite the `script` command to pass in the appropriate
+argument. For example, vulnerability definitions in alpha can be included with
+`-a`. The following configuration includes those definitions:
+
+```yaml
+include:
+ template: DAST.gitlab-ci.yml
+
+dast:
+ script:
+ - export DAST_WEBSITE=${DAST_WEBSITE:-$(cat environment_url.txt)}
+ - /analyze -a -t $DAST_WEBSITE
+```
+
+### Custom ZAProxy configuration
+
+The ZAProxy server contains many [useful configurable values](https://gitlab.com/gitlab-org/gitlab/-/issues/36437#note_245801885).
+Many key/values for `-config` remain undocumented, but there is an untested list of
+[possible keys](https://gitlab.com/gitlab-org/gitlab/-/issues/36437#note_244981023).
+Note that these options are not supported by DAST, and may break the DAST scan
+when used. An example of how to rewrite the Authorization header value with `TOKEN` follows:
+
+```yaml
+include:
+ template: DAST.gitlab-ci.yml
+
+variables:
+ DAST_ZAP_CLI_OPTIONS: "-config replacer.full_list(0).description=auth -config replacer.full_list(0).enabled=true -config replacer.full_list(0).matchtype=REQ_HEADER -config replacer.full_list(0).matchstr=Authorization -config replacer.full_list(0).regex=false -config replacer.full_list(0).replacement=TOKEN"
+```
+
+## Authentication
+
+NOTE:
+We highly recommend you configure the scanner to authenticate to the application. If you don't, it cannot check most of the application for security risks, as most
+of your application is likely not accessible without authentication. We also recommend
+you periodically confirm the scanner's authentication is still working, as this tends to break over
+time due to authentication changes to the application.
+
+Create masked CI/CD variables to pass the credentials that DAST uses.
+To create masked variables for the username and password, see [Create a custom variable in the UI](../../../ci/variables/index.md#custom-cicd-variables).
+The key of the username variable must be `DAST_USERNAME`,
+and the key of the password variable must be `DAST_PASSWORD`.
+
+After DAST has authenticated with the application, all cookies are collected from the web browser.
+For each cookie a matching session token is created for use by ZAP. This ensures ZAP is recognized
+by the application as correctly authenticated.
+
+Authentication supports single form logins, multi-step login forms, and authenticating to URLs outside of the configured target URL.
+
+WARNING:
+**Never** run an authenticated scan against a production server. When an authenticated
+scan is run, it may perform *any* function that the authenticated user can. This
+includes actions like modifying and deleting data, submitting forms, and following links.
+Only run an authenticated scan against a test server.
+
+### SSO
+
+DAST can authenticate to websites making use of SSO, with the following restrictions:
+
+- DAST cannot bypass a CAPTCHA if the authentication flow includes one.
+- DAST cannot handle multi-factor authentication like one-time passwords (OTP) by using SMS or authenticator apps.
+- DAST must get a cookie, or a local or session storage, with a sufficiently random value.
+
+The [authentication debug output](#configure-the-authentication-debug-output) can be helpful for troubleshooting SSO authentication
+with DAST.
+
+### Log in using automatic detection of the login form
+
+By providing a `DAST_USERNAME`, `DAST_PASSWORD`, and `DAST_AUTH_URL`, DAST attempts to authenticate to the
+target application by locating the login form based on a determination about whether or not the form contains username or password fields.
+
+Automatic detection is "best-effort", and depending on the application being scanned may provide either a resilient login experience or one that fails to authenticate the user.
+
+Login process:
+
+1. The `DAST_AUTH_URL` is loaded into the browser, and any forms on the page are located.
+ 1. If a form contains a username and password field, `DAST_USERNAME` and `DAST_PASSWORD` is inputted into the respective fields, the form submit button is selected and the user is logged in.
+ 1. If a form contains only a username field, it is assumed that the login form is multi-step.
+ 1. The `DAST_USERNAME` is inputted into the username field and the form submit button is selected.
+ 1. The subsequent pages loads where it is expected that a form exists and contains a password field. If found, `DAST_PASSWORD` is inputted, form submit button is selected and the user is logged in.
+
+### Log in using explicit selection of the login form
+
+By providing a `DAST_USERNAME_FIELD`, `DAST_PASSWORD_FIELD`, and `DAST_SUBMIT_FIELD`, in addition to the fields required for automatic login,
+DAST attempts to authenticate to the target application by locating the login form based on the selectors provided.
+Most applications benefit from this approach to authentication.
+
+Login process:
+
+1. The `DAST_AUTH_URL` is loaded into the browser, and any forms on the page are located.
+ 1. If the `DAST_FIRST_SUBMIT_FIELD` is not defined, then `DAST_USERNAME` is inputted into `DAST_USERNAME_FIELD`, `DAST_PASSWORD` is inputted into `DAST_PASSWORD_FIELD`, `DAST_SUBMIT_FIELD` is selected and the user is logged in.
+ 1. If the `DAST_FIRST_SUBMIT_FIELD` is defined, then it is assumed that the login form is multi-step.
+ 1. The `DAST_USERNAME` is inputted into the `DAST_USERNAME_FIELD` field and the `DAST_FIRST_SUBMIT_FIELD` is selected.
+ 1. The subsequent pages loads where the `DAST_PASSWORD` is inputted into the `DAST_PASSWORD_FIELD` field, the `DAST_SUBMIT_FIELD` is selected and the user is logged in.
+
+### Verifying successful login
+
+Once the login form has been submitted, DAST determines if the login was successful. Unsuccessful attempts at authentication cause the scan to halt.
+
+Following the submission of the login form, authentication is determined to be unsuccessful when:
+
+- A `400` or `500` series HTTP response status code is returned.
+- A new cookie/browser storage value determined to be sufficiently random has not been set.
+
+In addition to these checks, the user can configure their own verification checks.
+Each of the following checks can be used in conjunction with one another, if none are configured by default the presence of a login form is checked.
+
+#### Verifying based on the URL
+
+When `DAST_AUTH_VERIFICATION_URL` is configured, the URL displayed in the browser tab post login form submission is directly compared to the URL in the CI/CD variable.
+If these are not exactly the same, authentication is deemed to be unsuccessful.
+
+For example:
+
+```yaml
+include:
+ - template: DAST.gitlab-ci.yml
+
+dast:
+ variables:
+ DAST_WEBSITE: "https://example.com"
+ DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
+ ...
+ DAST_AUTH_VERIFICATION_URL: "https://example.com/user/welcome"
+```
+
+#### Verify based on presence of an element
+
+When `DAST_AUTH_VERIFICATION_SELECTOR` is configured, the page displayed in the browser tab is searched for an element described by the selector in the CI/CD variable.
+If no element is found, authentication is deemed to be unsuccessful.
+
+For example:
+
+```yaml
+include:
+ - template: DAST.gitlab-ci.yml
+
+dast:
+ variables:
+ DAST_WEBSITE: "https://example.com"
+ DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
+ ...
+ DAST_AUTH_VERIFICATION_SELECTOR: "css:.welcome-user"
+```
+
+#### Verify based on presence of a login form
+
+When `DAST_AUTH_VERIFICATION_LOGIN_FORM` is configured, the page displayed in the browser tab is searched for a form that is detected to be a login form.
+If any such form is found, authentication is deemed to be unsuccessful.
+
+For example:
+
+```yaml
+include:
+ - template: DAST.gitlab-ci.yml
+
+dast:
+ variables:
+ DAST_WEBSITE: "https://example.com"
+ DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
+ ...
+ DAST_AUTH_VERIFICATION_LOGIN_FORM: "true"
+```
+
+### View the login form
+
+Many web applications show the user the login form in a pop-up (modal) window.
+For these applications, navigating to the form requires both:
+
+- A starting URL.
+- A list of elements to select to display the modal window.
+
+When `DAST_BROWSER_PATH_TO_LOGIN_FORM` is present, like in this example:
+
+```yaml
+include:
+ - template: DAST.gitlab-ci.yml
+
+dast:
+ variables:
+ DAST_WEBSITE: "https://my.site.com"
+ DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
+ ...
+ DAST_AUTH_URL: "https://my.site.com/admin"
+ DAST_BROWSER_PATH_TO_LOGIN_FORM: "css:.navigation-menu,css:.login-menu-item"
+```
+
+DAST performs these actions:
+
+1. Load the `DAST_AUTH_URL` page, such as `https://my.site.com/admin`.
+1. After the page loads, DAST selects elements found by the selectors described
+ in `DAST_BROWSER_PATH_TO_LOGIN_FORM`. This example opens the navigation menu
+ and selects the login menu, to display the login modal window.
+1. To continue the authentication process, DAST fills in the username and password
+ on the login form.
+
+### Configure the authentication debug output
+
+It is often difficult to understand the cause of an authentication failure when running DAST in a CI/CD pipeline.
+To assist users in debugging authentication issues, a debug report can be generated and saved as a job artifact.
+This HTML report contains all steps made during the login process, along with HTTP requests and responses, the Document Object Model (DOM) and screenshots.
+
+![dast-auth-report](img/dast_auth_report.jpg)
+
+An example configuration where the authentication debug report is exported may look like the following:
+
+```yaml
+dast:
+ variables:
+ DAST_WEBSITE: "https://example.com"
+ DAST_BROWSER_SCAN: "true" # use the browser-based GitLab DAST crawler
+ ...
+ DAST_AUTH_REPORT: "true"
+ artifacts:
+ paths: [gl-dast-debug-auth-report.html]
+ when: always
+```
+
+### Selectors
+
+Selectors are used by CI/CD variables to specify the location of an element displayed on a page in a browser.
+Selectors have the format `type`:`search string`. The crawler searches for the selector using the search string based on the type.
+
+| Selector type | Example | Description |
+| ------------- | ---------------------------------- | ----------- |
+| `css` | `css:.password-field` | Searches for a HTML element having the supplied CSS selector. Selectors should be as specific as possible for performance reasons. |
+| `id` | `id:element` | Searches for an HTML element with the provided element ID. |
+| `name` | `name:element` | Searches for an HTML element with the provided element name. |
+| `xpath` | `xpath://input[@id="my-button"]/a` | Searches for a HTML element with the provided XPath. Note that XPath searches are expected to be less performant than other searches. |
+| None provided | `a.click-me` | Defaults to searching using a CSS selector. |
+
+#### Find selectors with Google Chrome
+
+Chrome DevTools element selector tool is an effective way to find a selector.
+
+1. Open Chrome and navigate to the page where you would like to find a selector, for example, the login page for your site.
+1. Open the `Elements` tab in Chrome DevTools with the keyboard shortcut `Command + Shift + c` in macOS or `Ctrl + Shift + c` in Windows.
+1. Select the `Select an element in the page to select it` tool.
+ ![search-elements](img/dast_auth_browser_scan_search_elements.png)
+1. Select the field on your page that you would like to know the selector for.
+1. Once the tool is active, highlight a field you wish to view the details of.
+ ![highlight](img/dast_auth_browser_scan_highlight.png)
+1. Once highlighted, you can see the element's details, including attributes that would make a good candidate for a selector.
+
+In this example, the `id="user_login"` appears to be a good candidate. You can use this as a selector as the DAST username field by setting
+`DAST_USERNAME_FIELD: "id:user_login"`.
+
+#### Choose the right selector
+
+Judicious choice of selector leads to a scan that is resilient to the application changing.
+
+In order of preference, it is recommended to choose as selectors:
+
+- `id` fields. These are generally unique on a page, and rarely change.
+- `name` fields. These are generally unique on a page, and rarely change.
+- `class` values specific to the field, such as the selector `"css:.username"` for the `username` class on the username field.
+- Presence of field specific data attributes, such as the selector, `"css:[data-username]"` when the `data-username` field has any value on the username field.
+- Multiple `class` hierarchy values, such as the selector `"css:.login-form .username"` when there are multiple elements with class `username` but only one nested inside the element with the class `login-form`.
+
+When using selectors to locate specific fields we recommend you avoid searching on:
+
+- Any `id`, `name`, `attribute`, `class` or `value` that is dynamically generated.
+- Generic class names, such as `column-10` and `dark-grey`.
+- XPath searches as they are less performant than other selector searches.
+- Unscoped searches, such as those beginning with `css:*` and `xpath://*`.
+
+### Bleeding-edge vulnerability definitions
+
+ZAP first creates rules in the `alpha` class. After a testing period with
+the community, they are promoted to `beta`. DAST uses `beta` definitions by
+default. To request `alpha` definitions, use the
+`DAST_INCLUDE_ALPHA_VULNERABILITIES` CI/CD variable as shown in the
+following configuration:
+
+```yaml
+include:
+ template: DAST.gitlab-ci.yml
+
+variables:
+ DAST_INCLUDE_ALPHA_VULNERABILITIES: "true"
+```
+
+### Cloning the project's repository
+
+The DAST job does not require the project's repository to be present when running, so by default
+[`GIT_STRATEGY`](../../../ci/runners/configure_runners.md#git-strategy) is set to `none`.
+
+## On-demand scans
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218465) in GitLab 13.2.
+> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/218465) in GitLab 13.3.
+> - The saved scans feature was [introduced](https://gitlab.com/groups/gitlab-org/-/epics/5100) in GitLab 13.9.
+> - The option to select a branch was [introduced](https://gitlab.com/groups/gitlab-org/-/epics/4847) in GitLab 13.10.
+> - DAST branch selection [feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/322672) in GitLab 13.11.
+> - Auditing for DAST profile management was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217872) in GitLab 14.1.
+
+An on-demand DAST scan runs outside the DevOps life cycle. Changes in your repository don't trigger
+the scan. You must either start it manually, or schedule it to run.
+
+An on-demand DAST scan:
+
+- Can run a specific combination of a [site profile](#site-profile) and a
+ [scanner profile](#scanner-profile).
+- Is associated with your project's default branch.
+- Is saved on creation so it can be run later.
+
+### On-demand scan modes
+
+An on-demand scan can be run in active or passive mode:
+
+- _Passive mode_ is the default and runs a ZAP Baseline Scan.
+- _Active mode_ runs a ZAP Full Scan which is potentially harmful to the site being scanned. To
+ minimize the risk of accidental damage, running an active scan requires a [validated site profile](#site-profile-validation).
+
+### View on-demand DAST scans
+
+To view running completed and scheduled on-demand DAST scans for a project, go to
+**Security & Compliance > On-demand Scans** in the left sidebar.
+
+- To view both running and completed scans, select **All**.
+- To view running scans only, select **Running**.
+- To view finished scans, select **Finished**. A finished scan is a scan that either succeeded,
+ failed, or was canceled.
+- To view scheduled scans, select **Scheduled**. It shows on-demand scans that have a schedule
+ set up. Those are _not_ included in the **All** tab.
+- To view saved on-demand scan profiles, select **Scan library**.
+ Those are _not_ included in the **All** tab.
+
+#### Cancel an on-demand scan
+
+To cancel a pending or running on-demand scan, select **Cancel** (**{cancel}**) in the
+on-demand scans list.
+
+#### Retry an on-demand scan
+
+To retry a scan that failed or succeeded with warnings, select **Retry** (**{retry}**) in the
+on-demand scans list.
+
+#### View an on-demand scan's results
+
+To view a finished scan's results, select **View results** in the on-demand scans list.
+
+#### Edit an on-demand scan
+
+To edit an on-demand scan's settings, select **Edit** (**{pencil}**) in the **Scheduled** tab.
+
+### Run an on-demand DAST scan
+
+Prerequisites:
+
+- You must have permission to run an on-demand DAST scan against a protected branch. The default
+ branch is automatically protected. For more information, read
+ [Pipeline security on protected branches](../../../ci/pipelines/index.md#pipeline-security-on-protected-branches).
+- A [scanner profile](#create-a-scanner-profile).
+- A [site profile](#create-a-site-profile).
+- If you are running an active scan the site profile must have been [validated](#validate-a-site-profile).
+
+You can run an on-demand scan immediately, once at a scheduled date and time or at a specified
+frequency:
+
+- Every day
+- Every week
+- Every month
+- Every 3 months
+- Every 6 months
+- Every year
+
+To run an on-demand scan immediately, either:
+
+- [Create and run an on-demand scan immediately](#create-and-run-an-on-demand-scan-immediately).
+- [Run a previously saved on-demand scan](#run-a-saved-on-demand-scan).
+
+To run an on-demand scan either at a scheduled date or frequency, read
+[Schedule an on-demand scan](#schedule-an-on-demand-scan).
+
+#### Create and run an on-demand scan immediately
+
+1. From your project's home page, go to **Security & Compliance > On-demand Scans** in the left
+ sidebar.
+1. Select **New scan**.
+1. Complete the **Scan name** and **Description** fields.
+1. In GitLab 13.10 and later, select the desired branch from the **Branch** dropdown list.
+1. In **Scanner profile**, select a scanner profile from the dropdown list.
+1. In **Site profile**, select a site profile from the dropdown list.
+1. To run the on-demand scan immediately, select **Save and run scan**. Otherwise, select
+ **Save scan** to [run](#run-a-saved-on-demand-scan) it later.
+
+The on-demand DAST scan runs and the project's dashboard shows the results.
+
+#### Run a saved on-demand scan
+
+To run a saved on-demand scan:
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Security & Compliance > On-demand Scans**.
+1. Select the **Scan library** tab.
+1. In the scan's row, select **Run scan**.
+
+ If the branch saved in the scan no longer exists, you must first
+ [edit the scan](#edit-an-on-demand-scan), select a new branch, and save the edited scan.
+
+The on-demand DAST scan runs, and the project's dashboard shows the results.
+
+#### Schedule an on-demand scan
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/328749) in GitLab 14.3. [Deployed behind the `dast_on_demand_scans_scheduler` flag](../../../administration/feature_flags.md), disabled by default.
+> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/328749) in GitLab 14.4.
+> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/328749) in GitLab 14.4.
+> - [Feature flag `dast_on_demand_scans_scheduler` removed](https://gitlab.com/gitlab-org/gitlab/-/issues/328749) in GitLab 14.5.
+
+To schedule a scan:
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Security & Compliance > On-demand Scans**.
+1. Select **New scan**.
+1. Complete the **Scan name** and **Description** text boxes.
+1. In GitLab 13.10 and later, from the **Branch** dropdown list, select the desired branch.
+1. In the **Scanner profile** section, from the dropdown list, select a scanner profile.
+1. In the **Site profile** section, from the dropdown list, select a site profile.
+1. Select **Schedule scan**.
+1. In the **Start time** section, select a time zone, date, and time.
+1. From the **Repeats** dropdown list, select your desired frequency:
+ - To run the scan once, select **Never**.
+ - For a recurring scan, select any other option.
+1. To run the on-demand scan immediately, select **Save and run scan**. To [run](#run-a-saved-on-demand-scan) it according to the schedule you set, select
+ **Save scan**.
+
+#### List saved on-demand scans
+
+To list saved on-demand scans:
+
+1. From your project's home page, go to **Security & Compliance > On-demand Scans**.
+1. Select the **Scan library** tab.
+
+#### View details of an on-demand scan
+
+To view details of an on-demand scan:
+
+1. From your project's home page, go to **Security & Compliance > On-demand Scans**.
+1. Select the **Scan library** tab.
+1. In the saved scan's row select **More actions** (**{ellipsis_v}**), then select **Edit**.
+
+#### Edit an on-demand scan
+
+To edit an on-demand scan:
+
+1. From your project's home page, go to **Security & Compliance > On-demand Scans**.
+1. Select the **Scan library** tab.
+1. In the saved scan's row select **More actions** (**{ellipsis_v}**), then select **Edit**.
+1. Edit the form.
+1. Select **Save scan**.
+
+#### Delete an on-demand scan
+
+To delete an on-demand scan:
+
+1. From your project's home page, go to **Security & Compliance > On-demand Scans**.
+1. Select the **Scan library** tab.
+1. In the saved scan's row select **More actions** (**{ellipsis_v}**), then select **Delete**.
+1. Select **Delete** to confirm the deletion.
+
+## Site profile
+
+> - Scan method [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/345837) in GitLab 15.6.
+> - File URL [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/345837) in GitLab 15.6.
+
+A site profile defines the attributes and configuration details of the deployed application,
+website, or API to be scanned by DAST. A site profile can be referenced in `.gitlab-ci.yml` and
+on-demand scans.
+
+A site profile contains:
+
+- **Profile name**: A name you assign to the site to be scanned. While a site profile is referenced
+ in either `.gitlab-ci.yml` or an on-demand scan, it **cannot** be renamed.
+- **Site type**: The type of target to be scanned, either website or API scan.
+- **Target URL**: The URL that DAST runs against.
+- **Excluded URLs**: A comma-separated list of URLs to exclude from the scan.
+- **Request headers**: A comma-separated list of HTTP request headers, including names and values. These headers are added to every request made by DAST.
+- **Authentication**:
+ - **Authenticated URL**: The URL of the page containing the sign-in HTML form on the target website. The username and password are submitted with the login form to create an authenticated scan.
+ - **Username**: The username used to authenticate to the website.
+ - **Password**: The password used to authenticate to the website.
+ - **Username form field**: The name of username field at the sign-in HTML form.
+ - **Password form field**: The name of password field at the sign-in HTML form.
+ - **Submit form field**: The `id` or `name` of the element that when selected submits the sign-in HTML form.
+
+- **Scan method**: A type of method to perform API testing. The supported methods are OpenAPI, Postman Collections, and HTTP Archive (HAR) documents.
+- **File URL**: The URL of the OpenAPI, Postman Collection, or HTTP Archive file.
+
+When an API site type is selected, a [host override](#host-override) is used to ensure the API being scanned is on the same host as the target. This is done to reduce the risk of running an active scan against the wrong API.
+
+When configured, request headers and password fields are encrypted using [`aes-256-gcm`](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) before being stored in the database.
+This data can only be read and decrypted with a valid secrets file.
+
+### Site profile validation
+
+> - Site profile validation [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/233020) in GitLab 13.8.
+> - Meta tag validation [introduced](https://gitlab.com/groups/gitlab-org/-/epics/6460) in GitLab 14.2.
+
+Site profile validation reduces the risk of running an active scan against the wrong website. A site
+must be validated before an active scan can run against it. The site validation methods are as
+follows:
+
+- _Text file validation_ requires a text file be uploaded to the target site. The text file is
+ allocated a name and content that is unique to the project. The validation process checks the
+ file's content.
+- _Header validation_ requires the header `Gitlab-On-Demand-DAST` be added to the target site,
+ with a value unique to the project. The validation process checks that the header is present, and
+ checks its value.
+- _Meta tag validation_ requires the meta tag named `gitlab-dast-validation` be added to the target site,
+ with a value unique to the project. Make sure it's added to the `<head>` section of the page. The validation process checks that the meta tag is present, and
+ checks its value.
+
+All these methods are equivalent in functionality. Use whichever is feasible.
+
+In [GitLab 14.2 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/324990), site profile
+validation happens in a CI job using the [GitLab Runner](../../../ci/runners/index.md).
+
+### Create a site profile
+
+To create a site profile:
+
+1. From your project's home page, go to **Security & Compliance > Configuration**.
+1. Select **Manage** in the **DAST Profiles** row.
+1. Select **New > Site Profile**.
+1. Complete the fields then select **Save profile**.
+
+The site profile is created.
+
+### Edit a site profile
+
+If a site profile is linked to a security policy, a user cannot edit the profile from this page. See
+[Scan execution policies](../policies/scan-execution-policies.md)
+for more information.
+
+When a validated site profile's file, header, or meta tag is edited, the site's
+[validation status](#site-profile-validation) is revoked.
+
+To edit a site profile:
+
+1. From your project's home page, go to **Security & Compliance > Configuration**.
+1. In the **DAST Profiles** row select **Manage**.
+1. Select the **Site Profiles** tab.
+1. In the profile's row select the **More actions** (**{ellipsis_v}**) menu, then select **Edit**.
+1. Edit the fields then select **Save profile**.
+
+### Delete a site profile
+
+If a site profile is linked to a security policy, a user cannot delete the profile from this page.
+See [Scan execution policies](../policies/scan-execution-policies.md)
+for more information.
+
+To delete a site profile:
+
+1. From your project's home page, go to **Security & Compliance > Configuration**.
+1. In the **DAST Profiles** row select **Manage**.
+1. Select the **Site Profiles** tab.
+1. In the profile's row, select the **More actions** (**{ellipsis_v}**) menu, then select **Delete**.
+1. Select **Delete** to confirm the deletion.
+
+### Validate a site profile
+
+Validating a site is required to run an active scan.
+
+To validate a site profile:
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Security & Compliance > Configuration**.
+1. In the **Dynamic Application Security Testing (DAST)** section, select **Manage profiles**.
+1. Select the **Site Profiles** tab.
+1. In the profile's row, select **Validate**.
+1. Select the validation method.
+ 1. For **Text file validation**:
+ 1. Download the validation file listed in **Step 2**.
+ 1. Upload the validation file to the host, to the location in **Step 3** or any location you
+ prefer.
+ 1. If required, edit the file location in **Step 3**.
+ 1. Select **Validate**.
+ 1. For **Header validation**:
+ 1. Select the clipboard icon in **Step 2**.
+ 1. Edit the header of the site to validate, and paste the clipboard content.
+ 1. Select the input field in **Step 3** and enter the location of the header.
+ 1. Select **Validate**.
+ 1. For **Meta tag validation**:
+ 1. Select the clipboard icon in **Step 2**.
+ 1. Edit the content of the site to validate, and paste the clipboard content.
+ 1. Select the input field in **Step 3** and enter the location of the meta tag.
+ 1. Select **Validate**.
+
+The site is validated and an active scan can run against it. A site profile's validation status is
+revoked only when it's revoked manually, or its file, header, or meta tag is edited.
+
+### Retry a failed validation
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/322609) in GitLab 14.3.
+> - [Deployed behind the `dast_failed_site_validations` flag](../../../administration/feature_flags.md), enabled by default.
+> - [Feature flag `dast_failed_site_validations` removed](https://gitlab.com/gitlab-org/gitlab/-/issues/323961) in GitLab 14.4.
+
+Failed site validation attempts are listed on the **Site profiles** tab of the **Manage profiles**
+page.
+
+To retry a site profile's failed validation:
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Security & Compliance > Configuration**.
+1. In the **Dynamic Application Security Testing (DAST)** section, select **Manage profiles**.
+1. Select the **Site Profiles** tab.
+1. In the profile's row, select **Retry validation**.
+
+### Revoke a site profile's validation status
+
+WARNING:
+When a site profile's validation status is revoked, all site profiles that share the same URL also
+have their validation status revoked.
+
+To revoke a site profile's validation status:
+
+1. From your project's home page, go to **Security & Compliance > Configuration**.
+1. In the **DAST Profiles** row select **Manage**.
+1. Beside the validated profile, select **Revoke validation**.
+
+The site profile's validation status is revoked.
+
+### Validated site profile headers
+
+The following are code samples of how you can provide the required site profile header in your
+application.
+
+#### Ruby on Rails example for on-demand scan
+
+Here's how you can add a custom header in a Ruby on Rails application:
+
+```ruby
+class DastWebsiteTargetController < ActionController::Base
+ def dast_website_target
+ response.headers['Gitlab-On-Demand-DAST'] = '0dd79c9a-7b29-4e26-a815-eaaf53fcab1c'
+ head :ok
+ end
+end
+```
+
+#### Django example for on-demand scan
+
+Here's how you can add a
+[custom header in Django](https://docs.djangoproject.com/en/2.2/ref/request-response/#setting-header-fields):
+
+```python
+class DastWebsiteTargetView(View):
+ def head(self, *args, **kwargs):
+ response = HttpResponse()
+ response['Gitlab-On-Demand-DAST'] = '0dd79c9a-7b29-4e26-a815-eaaf53fcab1c'
+
+ return response
+```
+
+#### Node (with Express) example for on-demand scan
+
+Here's how you can add a
+[custom header in Node (with Express)](https://expressjs.com/en/5x/api.html#res.append):
+
+```javascript
+app.get('/dast-website-target', function(req, res) {
+ res.append('Gitlab-On-Demand-DAST', '0dd79c9a-7b29-4e26-a815-eaaf53fcab1c')
+ res.send('Respond to DAST ping')
+})
+```
+
+## Scanner profile
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/222767) in GitLab 13.4.
+> - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/225804) in GitLab 13.5: scan mode, AJAX spider, debug messages.
+
+A scanner profile defines the configuration details of a security scanner. A scanner profile can be
+referenced in `.gitlab-ci.yml` and on-demand scans.
+
+A scanner profile contains:
+
+- **Profile name:** A name you give the scanner profile. For example, "Spider_15". While a scanner
+ profile is referenced in either `.gitlab-ci.yml` or an on-demand scan, it **cannot** be renamed.
+- **Scan mode:** A passive scan monitors all HTTP messages (requests and responses) sent to the target. An active scan attacks the target to find potential vulnerabilities.
+- **Spider timeout:** The maximum number of minutes allowed for the spider to traverse the site.
+- **Target timeout:** The maximum number of seconds DAST waits for the site to be available before
+ starting the scan.
+- **AJAX spider:** Run the AJAX spider, in addition to the traditional spider, to crawl the target site.
+- **Debug messages:** Include debug messages in the DAST console output.
+
+### Create a scanner profile
+
+To create a scanner profile:
+
+1. From your project's home page, go to **Security & Compliance > Configuration**.
+1. In the **DAST Profiles** row, select **Manage**.
+1. Select **New > Scanner Profile**.
+1. Complete the form. For details of each field, see [Scanner profile](#scanner-profile).
+1. Select **Save profile**.
+
+### Edit a scanner profile
+
+If a scanner profile is linked to a security policy, a user cannot edit the profile from this page.
+See [Scan execution policies](../policies/scan-execution-policies.md)
+for more information.
+
+To edit a scanner profile:
+
+1. From your project's home page, go to **Security & Compliance > Configuration**.
+1. In the **DAST Profiles** row, select **Manage**.
+1. Select the **Scanner Profiles** tab.
+1. In the scanner's row, select the **More actions** (**{ellipsis_v}**) menu, then select **Edit**.
+1. Edit the form.
+1. Select **Save profile**.
+
+### Delete a scanner profile
+
+If a scanner profile is linked to a security policy, a user cannot delete the profile from this
+page. See [Scan execution policies](../policies/scan-execution-policies.md)
+for more information.
+
+To delete a scanner profile:
+
+1. From your project's home page, go to **Security & Compliance > Configuration**.
+1. In the **DAST Profiles** row, select **Manage**.
+1. Select the **Scanner Profiles** tab.
+1. In the scanner's row, select the **More actions** (**{ellipsis_v}**) menu, then select **Delete**.
+1. Select **Delete**.
+
+## Auditing
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/217872) in GitLab 14.1.
+
+The creation, updating, and deletion of DAST profiles, DAST scanner profiles,
+and DAST site profiles are included in the [audit log](../../../administration/audit_events.md).
+
+## Reports
+
+The DAST tool outputs a `gl-dast-report.json` report file containing details of the scan and its results.
+This file is included in the job's artifacts. JSON is the default format, but
+you can output the report in Markdown, HTML, and XML formats. To specify an alternative
+format, use a [CI/CD variable](#available-cicd-variables). You can also use a CI/CD variable
+to configure the job to output the `gl-dast-debug-auth-report.html` file which helps when debugging
+authentication issues.
+
+For details of the report's schema, see the [schema for DAST reports](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/master/dist/dast-report-format.json). Example reports can be found in the
+[DAST repository](https://gitlab.com/gitlab-org/security-products/dast/-/tree/main/test/end-to-end/expect).
+
+WARNING:
+The JSON report artifacts are not a public API of DAST and their format is expected to change in the
+future.
diff --git a/doc/user/application_security/dast_api/index.md b/doc/user/application_security/dast_api/index.md
index eae32f789b8..d77be0f0ca9 100644
--- a/doc/user/application_security/dast_api/index.md
+++ b/doc/user/application_security/dast_api/index.md
@@ -7,20 +7,19 @@ type: reference, howto
# DAST API **(ULTIMATE)**
-You can add dynamic application security testing (DAST) of web APIs to your
-[GitLab CI/CD](../../../ci/index.md) pipelines. This helps you discover bugs and potential security
-issues that other QA processes may miss.
+> DAST API analyzer [became the default analyzer for on-demand DAST API scans](https://gitlab.com/groups/gitlab-org/-/epics/4254) in GitLab 15.6.
-We recommend that you use DAST API testing in addition to [GitLab Secure](../index.md)'s
-other security scanners and your own test processes. If you're using [GitLab CI/CD](../../../ci/index.md),
-you can run DAST API tests as part your CI/CD workflow.
+Perform Dynamic Application Security Testing (DAST) of web APIs to help discover bugs and potential
+security issues that other QA processes may miss. Use DAST API tests in addition to
+[GitLab Secure](../index.md)'s other security scanners and your own test processes. You can run DAST
+API tests either as part your CI/CD workflow, [on-demand](../dast/proxy-based.md#on-demand-scans), or both.
WARNING:
-Do not run DAST API testing against a production server. Not only can it perform *any* function that
+Do not run DAST API testing against a production server. Not only can it perform _any_ function that
the API can, it may also trigger bugs in the API. This includes actions like modifying and deleting
data. Only run DAST API against a test server.
-You can run DAST API scanning against the following web API types:
+DAST API can test the following web API types:
- REST API
- SOAP
@@ -29,9 +28,9 @@ You can run DAST API scanning against the following web API types:
## When DAST API scans run
-DAST API scanning runs in the `dast` stage by default. To ensure DAST API scanning examines the latest
-code, ensure your CI/CD pipeline deploys changes to a test environment in a stage before the `dast`
-stage.
+When run in your CI/CD pipeline, DAST API scanning runs in the `dast` stage by default. To ensure
+DAST API scanning examines the latest code, ensure your CI/CD pipeline deploys changes to a test
+environment in a stage before the `dast` stage.
If your pipeline is configured to deploy to the same web server on each run, running a pipeline
while another is still running could cause a race condition in which one pipeline overwrites the
@@ -2057,9 +2056,232 @@ Setting `SECURE_ANALYZERS_PREFIX` changes the Docker image registry location for
For more information, see [Offline environments](../offline_deployments/index.md).
+## Performance tuning and testing speed
+
+Security tools that perform dynamic analysis testing, such as DAST API, perform testing by sending requests to an instance of your running application. The requests are engineered to test for specific vulnerabilities that might exist in your application. The speed of a dynamic analysis test depends on the following:
+
+- How many requests per second can be sent to your application by our tooling
+- How fast your application responds to requests
+- How many requests must be sent to test the application
+ - How many operations your API is comprised of
+ - How many fields are in each operation (think JSON bodies, headers, query string, cookies, etc.)
+
+If the DAST API testing job still takes longer than expected reach after following the advice in this performance guide, reach out to support for further assistance.
+
+### Diagnosing performance issues
+
+The first step to resolving performance issues is to understand what is contributing to the slower-than-expected testing time. Some common issues we see are:
+
+- DAST API is running on a slow or single-CPU GitLab Runner (GitLab Shared Runners are single-CPU)
+- The application deployed to a slow/single-CPU instance and is not able to keep up with the testing load
+- The application contains a slow operation that impacts the overall test speed (> 1/2 second)
+- The application contains an operation that returns a large amount of data (> 500K+)
+- The application contains a large number of operations (> 40)
+
+#### The application contains a slow operation that impacts the overall test speed (> 1/2 second)
+
+The DAST API job output contains helpful information about how fast we are testing, how fast each operation being tested responds, and summary information. Let's take a look at some sample output to see how it can be used in tracking down performance issues:
+
+```shell
+API Security: Loaded 10 operations from: assets/har-large-response/large_responses.har
+API Security:
+API Security: Testing operation [1/10]: 'GET http://target:7777/api/large_response_json'.
+API Security: - Parameters: (Headers: 4, Query: 0, Body: 0)
+API Security: - Request body size: 0 Bytes (0 bytes)
+API Security:
+API Security: Finished testing operation 'GET http://target:7777/api/large_response_json'.
+API Security: - Excluded Parameters: (Headers: 0, Query: 0, Body: 0)
+API Security: - Performed 767 requests
+API Security: - Average response body size: 130 MB
+API Security: - Average call time: 2 seconds and 82.69 milliseconds (2.082693 seconds)
+API Security: - Time to complete: 14 minutes, 8 seconds and 788.36 milliseconds (848.788358 seconds)
+```
+
+This job console output snippet starts by telling us how many operations were found (10), followed by notifications that testing has started on a specific operation and a summary of the operation has been completed. The summary is the most interesting part of this log output. In the summary, we can see that it took DAST API 767 requests to fully test this operation and its related fields. We can also see that the average response time was 2 seconds and the time to complete was 14 minutes for this one operation.
+
+An average response time of 2 seconds is a good initial indicator that this specific operation takes a long time to test. Further, we can see that the response body size is quite large. The large body size is the culprit here, transferring that much data on each request is what takes the majority of that 2 seconds.
+
+For this issue, the team might decide to:
+
+- Use a multi-CPU runner. Using a multi-CPU runner allows DAST API to parallelize the work being performed. This helps lower the test time, but getting the test down under 10 minutes might still be problematic without moving to a high CPU machine due to how long the operation takes to test.
+ - Trade off between how many CPUs and cost.
+- [Exclude this operation](#excluding-slow-operations) from the DAST API test. While this is the simplest, it has the downside of a gap in security test coverage.
+- [Exclude the operation from feature branch DAST API tests, but include it in the default branch test](#excluding-operations-in-feature-branches-but-not-default-branch).
+- [Split up the DAST API testing into multiple jobs](#splitting-a-test-into-multiple-jobs).
+
+The likely solution is to use a combination of these solutions to reach an acceptable test time, assuming your team's requirements are in the 5-7 minute range.
+
+### Addressing performance issues
+
+The following sections document various options for addressing performance issues for DAST API:
+
+- [Using a multi-CPU Runner](#using-a-multi-cpu-runner)
+- [Excluding slow operations](#excluding-slow-operations)
+- [Splitting a test into multiple jobs](#splitting-a-test-into-multiple-jobs)
+- [Excluding operations in feature branches, but not default branch](#excluding-operations-in-feature-branches-but-not-default-branch)
+
+#### Using a multi-CPU Runner
+
+One of the easiest performance boosts can be achieved using a multi-CPU runner with DAST API. This table shows statistics collected during benchmarking of a Java Spring Boot REST API. In this benchmark, the target and DAST API share a single runner instance.
+
+| CPU Count | Request per Second |
+|----------------------|--------------------|
+| 1 CPU (Shared Runner)| 75 |
+| 4 CPU | 255 |
+| 8 CPU | 400 |
+
+As we can see from this table, increasing the CPU count of the runner can have a large impact on testing speed/performance.
+
+To use a multi-CPU typically requires deploying a self-managed GitLab Runner onto a multi-CPU machine or cloud compute instance.
+
+When multiple types of GitLab Runners are available for use, the various instances are commonly set up with tags that can be used in the job definition to select a type of runner.
+
+Here is an example job definition for DAST API that adds a `tags` section with the tag `multi-cpu`. The job automatically extends the job definition included through the DAST API template.
+
+```yaml
+dast_api:
+ tags:
+ - multi-cpu
+```
+
+To verify that DAST API can detect multiple CPUs in the runner, download the `gl-api-security-scanner.log` file from a completed job's artifacts. Search the file for the string `Starting work item processor` and inspect the reported max DOP (degree of parallelism). The max DOP should be greater than or equal to the number of CPUs assigned to the runner. The value is never lower than 2, even on single CPU runners, unless forced through a configuration variable. If the value reported is less than the number of CPUs assigned to the runner, then something is wrong with the runner deployment. If unable to identify the problem, open a ticket with support to assist.
+
+Example log entry:
+
+`17:00:01.084 [INF] <Peach.Web.Core.Services.WebRunnerMachine> Starting work item processor with 2 max DOP`
+
+#### Excluding slow operations
+
+In the case of one or two slow operations, the team might decide to skip testing the operations. Excluding the operation is done using the `DAST_API_EXCLUDE_PATHS` configuration [variable as explained in this section.](#exclude-paths)
+
+In this example, we have an operation that returns a large amount of data. The operation is `GET http://target:7777/api/large_response_json`. To exclude it we provide the `DAST_API_EXCLUDE_PATHS` configuration variable with the path portion of our operation URL `/api/large_response_json`.
+
+To verify the operation is excluded, run the DAST API job and review the job console output. It includes a list of included and excluded operations at the end of the test.
+
+```yaml
+dast_api:
+ variables:
+ DAST_API_EXCLUDE_PATHS: /api/large_response_json
+```
+
+Excluding operations from testing could allow some vulnerabilities to go undetected.
+{: .alert .alert-warning}
+
+#### Splitting a test into multiple jobs
+
+Splitting a test into multiple jobs is supported by DAST API through the use of [`DAST_API_EXCLUDE_PATHS`](#exclude-paths) and [`DAST_API_EXCLUDE_URLS`](#exclude-urls). When splitting a test up, a good pattern is to disable the `dast_api` job and replace it with two jobs with identifying names. In this example we have two jobs, each job is testing a version of the API, so our names reflect that. However, this technique can be applied to any situation, not just with versions of an API.
+
+The rules we are using in the `dast_api_v1` and `dast_api_v2` jobs are copied from the [DAST API template](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/DAST-API.gitlab-ci.yml).
+
+```yaml
+# Disable the main dast_api job
+dast_api:
+ rules:
+ - if: $CI_COMMIT_BRANCH
+ when: never
+
+dast_api_v1:
+ extends: dast_api
+ variables:
+ DAST_API_EXCLUDE_PATHS: /api/v1/**
+ rules:
+ - if: $DAST_API_DISABLED
+ when: never
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ DAST_API_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH
+
+dast_api_v2:
+ variables:
+ DAST_API_EXCLUDE_PATHS: /api/v2/**
+ rules:
+ - if: $DAST_API_DISABLED
+ when: never
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ DAST_API_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH
+```
+
+#### Excluding operations in feature branches, but not default branch
+
+In the case of one or two slow operations, the team might decide to skip testing the operations, or exclude them from feature branch tests, but include them for default branch tests. Excluding the operation is done using the `DAST_API_EXCLUDE_PATHS` configuration [variable as explained in this section.](#exclude-paths)
+
+In this example, we have an operation that returns a large amount of data. The operation is `GET http://target:7777/api/large_response_json`. To exclude it we provide the `DAST_API_EXCLUDE_PATHS` configuration variable with the path portion of our operation URL `/api/large_response_json`. Our configuration disables the main `dast_api` job and creates two new jobs `dast_api_main` and `dast_api_branch`. The `dast_api_branch` is set up to exclude the long operation and only run on non-default branches (e.g. feature branches). The `dast_api_main` branch is set up to only execute on the default branch (`main` in this example). The `dast_api_branch` jobs run faster, allowing for quick development cycles, while the `dast_api_main` job which only runs on default branch builds, takes longer to run.
+
+To verify the operation is excluded, run the DAST API job and review the job console output. It includes a list of included and excluded operations at the end of the test.
+
+```yaml
+# Disable the main job so we can create two jobs with
+# different names
+dast_api:
+ rules:
+ - if: $CI_COMMIT_BRANCH
+ when: never
+
+# DAST API for feature branch work, excludes /api/large_response_json
+dast_api_branch:
+ extends: dast_api
+ variables:
+ DAST_API_EXCLUDE_PATHS: /api/large_response_json
+ rules:
+ - if: $DAST_API_DISABLED
+ when: never
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ DAST_API_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+ when: never
+ - if: $CI_COMMIT_BRANCH
+
+# DAST API for default branch (main in our case)
+# Includes the long running operations
+dast_api_main:
+ extends: dast_api
+ rules:
+ - if: $DAST_API_DISABLED
+ when: never
+ - if: $DAST_API_DISABLED_FOR_DEFAULT_BRANCH &&
+ $CI_DEFAULT_BRANCH == $CI_COMMIT_REF_NAME
+ when: never
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ DAST_API_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
+```
+
## Troubleshooting
-### `Error waiting for API Security 'http://127.0.0.1:5000' to become available`
+### DAST API job times out after N hours
+
+The top two reasons for the DAST API job timing out are slow operations (> 1 second) and using a single-CPU runner for DAST API (GitLab shared runners are single-CPU). Before you can diagnose the problem further, the job must complete so the output can be analyzed. We recommend to start with a multi-CPU runner first, then exclude portions of your API operations until the job completes and the output can be further reviewed.
+
+See the following documentation sections for assistance:
+
+- [Performance tuning and testing speed](#performance-tuning-and-testing-speed)
+- [Using a multi-CPU Runner](#using-a-multi-cpu-runner)
+- [Excluding operations by path](#exclude-paths)
+- [Excluding slow operations](#excluding-slow-operations)
+
+### DAST API job takes too long to complete
+
+See [Performance Tuning and Testing Speed](#performance-tuning-and-testing-speed)
+
+### Error waiting for API Security 'http://127.0.0.1:5000' to become available
A bug exists in versions of the DAST API analyzer prior to v1.6.196 that can cause a background process to fail under certain conditions. The solution is to update to a newer version of the DAST API analyzer.
diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md
index a3c6c46b081..4ed9ceedb4d 100644
--- a/doc/user/application_security/dependency_scanning/index.md
+++ b/doc/user/application_security/dependency_scanning/index.md
@@ -221,7 +221,7 @@ table.supported-languages ul {
<td>N</td>
</tr>
<tr>
- <td rowspan="2">JavaScript</td>
+ <td rowspan="2">JavaScript and TypeScript</td>
<td>All versions</td>
<td><a href="https://www.npmjs.com/">npm</a></td>
<td>
@@ -501,11 +501,11 @@ From GitLab 14.8 the `gemnasium` analyzer scans supported JavaScript projects fo
#### Go
-When scanning a Go project, gemnasium invokes a builder and attempts to generate a [build list](https://go.dev/ref/mod#glos-build-list) using
-[Minimal Version Selection](https://go.dev/ref/mod#glos-minimal-version-selection). If a non-fatal error is encountered, the build process signals
-that the execution should proceed and falls back to parsing the available `go.sum` file.
+Multiple files are supported. When a `go.mod` file is detected, the analyzer attempts to generate a [build list](https://go.dev/ref/mod#glos-build-list) using
+[Minimal Version Selection](https://go.dev/ref/mod#glos-minimal-version-selection). If a non-fatal error is encountered, the analyzer falls back to parsing the
+available `go.sum` file. The process is repeated for every detected `go.mod` and `go.sum` file.
-#### PHP, Go, C, C++, .NET, C&#35;, Ruby, JavaScript
+#### PHP, C, C++, .NET, C&#35;, Ruby, JavaScript
The analyzer for these languages supports multiple lockfiles.
@@ -525,7 +525,7 @@ The [Security Scanner Integration](../../../development/integrations/secure.md)
To enable dependency scanning for GitLab 11.9 and later, you must
[include](../../../ci/yaml/index.md#includetemplate) the
-[`Dependency-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/Dependency-Scanning.gitlab-ci.yml)
+[`Dependency-Scanning.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml)
that is provided as a part of your GitLab installation.
For GitLab versions earlier than 11.9, you can copy and use the job as defined
that template.
@@ -534,7 +534,7 @@ Add the following to your `.gitlab-ci.yml` file:
```yaml
include:
- - template: Security/Dependency-Scanning.gitlab-ci.yml
+ - template: Jobs/Dependency-Scanning.gitlab-ci.yml
```
The included template creates dependency scanning jobs in your CI/CD
@@ -624,7 +624,6 @@ The following variables allow configuration of global dependency scanning settin
| ----------------------------|------------ |
| `ADDITIONAL_CA_CERT_BUNDLE` | Bundle of CA certs to trust. The bundle of certificates provided here is also used by other tools during the scanning process, such as `git`, `yarn`, or `npm`. See [Using a custom SSL CA certificate authority](#using-a-custom-ssl-ca-certificate-authority) for more details. |
| `DS_EXCLUDED_ANALYZERS` | Specify the analyzers (by name) to exclude from Dependency Scanning. For more information, see [Dependency Scanning Analyzers](analyzers.md). |
-| `DS_DEFAULT_ANALYZERS` | This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/287691) in GitLab 14.0 and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/333299) in 15.0. Use `DS_EXCLUDED_ANALYZERS` instead. |
| `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.) |
| `SECURE_ANALYZERS_PREFIX` | Override the name of the Docker registry providing the official default images (proxy). Read more about [customizing analyzers](analyzers.md). |
@@ -641,6 +640,7 @@ The following variables are used for configuring specific analyzers (used for a
| `GEMNASIUM_DB_REMOTE_URL` | `gemnasium` | `https://gitlab.com/gitlab-org/security-products/gemnasium-db.git` | Repository URL for fetching the Gemnasium database. |
| `GEMNASIUM_DB_REF_NAME` | `gemnasium` | `master` | Branch name for remote repository database. `GEMNASIUM_DB_REMOTE_URL` is required. |
| `DS_REMEDIATE` | `gemnasium` | `"true"`, `"false"` in FIPS mode | Enable automatic remediation of vulnerable dependencies. Not supported in FIPS mode. |
+| `DS_REMEDIATE_TIMEOUT` | `gemnasium` | `5m` | Timeout for auto-remediation. |
| `GEMNASIUM_LIBRARY_SCAN_ENABLED` | `gemnasium` | `"true"` | Enable detecting vulnerabilities in vendored JavaScript libraries. For now, `gemnasium` leverages [`Retire.js`](https://github.com/RetireJS/retire.js) to do this job. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/350512) in GitLab 14.8. |
| `DS_JAVA_VERSION` | `gemnasium-maven` | `17` | Version of Java. Available versions: `8`, `11`, `13`, `14`, `15`, `16`, `17`. Available versions in FIPS-enabled image: `8`, `11`, `17`. |
| `MAVEN_CLI_OPTS` | `gemnasium-maven` | `"-DskipTests --batch-mode"` | List of command line arguments that are passed to `maven` by the analyzer. See an example for [using private repositories](../index.md#using-private-maven-repositories). |
@@ -1311,6 +1311,11 @@ gemnasium-python-dependency_scanning:
- apt-get update && apt-get install -y libpq-dev
```
+### `NoSuchOptionException` when using `poetry config http-basic` with `CI_JOB_TOKEN`
+
+This error can occur when the automatically generated `CI_JOB_TOKEN` starts with a hyphen (`-`).
+To avoid this error, follow [Poetry's configuration advice](https://python-poetry.org/docs/repositories/#configuring-credentials).
+
### Error: Project has `<number>` unresolved dependencies
The error message `Project has <number> unresolved dependencies` indicates a dependency resolution problem caused by your `gradle.build` or `gradle.build.kts` file. In the current release, `gemnasium-maven` cannot continue processing when an unresolved dependency is encountered. However, There is an [open issue](https://gitlab.com/gitlab-org/gitlab/-/issues/337083) to allow `gemnasium-maven` to recover from unresolved dependency errors and produce a dependency graph. Until this issue has been resolved, you'll need to consult the [Gradle dependency resolution docs](https://docs.gradle.org/current/userguide/dependency_resolution.html) for details on how to fix your `gradle.build` file.
diff --git a/doc/user/application_security/get-started-security.md b/doc/user/application_security/get-started-security.md
index b6213a98f91..5774bf940b0 100644
--- a/doc/user/application_security/get-started-security.md
+++ b/doc/user/application_security/get-started-security.md
@@ -36,7 +36,7 @@ The following steps will help you get the most from GitLab application security
remediating existing vulnerabilities and preventing the introduction of new ones.
1. Enable other scan types such as [SAST](sast/index.md), [DAST](dast/index.md),
[Fuzz testing](coverage_fuzzing/index.md), or [Container Scanning](container_scanning/index.md).
-1. Use [Compliance Pipelines](../group/manage.md#configure-a-compliance-pipeline)
+1. Use [Compliance Pipelines](../group/compliance_frameworks.md#configure-a-compliance-pipeline)
or [Scan Execution Policies](policies/scan-execution-policies.md) to enforce required scan types
and ensure separation of duties between security and engineering.
1. Consider enabling [Review Apps](../../development/testing_guide/review_apps.md) to allow for DAST
diff --git a/doc/user/application_security/iac_scanning/index.md b/doc/user/application_security/iac_scanning/index.md
index 150c2b732d8..1c14c529523 100644
--- a/doc/user/application_security/iac_scanning/index.md
+++ b/doc/user/application_security/iac_scanning/index.md
@@ -4,25 +4,27 @@ 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
---
-# Infrastructure as Code (IaC) Scanning
+# Infrastructure as Code (IaC) Scanning **(FREE)**
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/6655) in GitLab 14.5.
Infrastructure as Code (IaC) Scanning scans your IaC configuration files for known vulnerabilities.
-Currently, IaC scanning supports configuration files for Terraform, Ansible, AWS CloudFormation, and Kubernetes.
+IaC Scanning supports configuration files for Terraform, Ansible, AWS CloudFormation, and Kubernetes.
## Requirements
IaC Scanning runs in the `test` stage, which is available by default. If you redefine the stages in the `.gitlab-ci.yml` file, the `test` stage is required.
-To run IaC scanning jobs, by default, you need GitLab Runner with the
+We recommend a minimum of 4GB RAM to ensure consistent performance.
+
+To run IaC Scanning jobs, by default, you need GitLab Runner with the
[`docker`](https://docs.gitlab.com/runner/executors/docker.html) or
[`kubernetes`](https://docs.gitlab.com/runner/install/kubernetes.html) executor.
If you're using the shared runners on GitLab.com, this is enabled by default.
WARNING:
-Our IaC scanning jobs require a Linux/amd64 container type. Windows containers are not yet supported.
+Our IaC Scanning jobs require a Linux/amd64 container type. Windows containers are not supported.
WARNING:
If you use your own runners, make sure the Docker version installed
@@ -30,20 +32,20 @@ is **not** `19.03.0`. See [troubleshooting information](../sast/index.md#error-r
## Supported languages and frameworks
-GitLab IaC scanning supports a variety of IaC configuration files. Our IaC security scanners also feature automatic language detection which works even for mixed-language projects. If any supported configuration files are detected in project source code we automatically run the appropriate IaC analyzers.
+GitLab IaC Scanning supports a variety of IaC configuration files. Our IaC security scanners also feature automatic language detection which works even for mixed-language projects. If any supported configuration files are detected in project source code we automatically run the appropriate IaC analyzers.
-| Configuration File Type | Scan tool | Introduced in GitLab Version |
-|------------------------------------------|----------------------------------|-------------------------------|
-| Ansible | [KICS](https://kics.io/) | 14.5 |
-| AWS CloudFormation | [KICS](https://kics.io/) | 14.5 |
-| Azure Resource Manager <sup>1</sup> | [KICS](https://kics.io/) | 14.5 |
-| Dockerfile | [KICS](https://kics.io/) | 14.5 |
-| Google Deployment Manager | [KICS](https://kics.io/) | 14.5 |
-| Kubernetes | [KICS](https://kics.io/) | 14.5 |
-| OpenAPI | [KICS](https://kics.io/) | 14.5 |
-| Terraform <sup>2</sup> | [KICS](https://kics.io/) | 14.5 |
+| Configuration file type | Scan tool | Introduced in GitLab version |
+| ----------------------------------- | ------------------------ | ---------------------------- |
+| Ansible | [KICS](https://kics.io/) | 14.5 |
+| AWS CloudFormation | [KICS](https://kics.io/) | 14.5 |
+| Azure Resource Manager <sup>1</sup> | [KICS](https://kics.io/) | 14.5 |
+| Dockerfile | [KICS](https://kics.io/) | 14.5 |
+| Google Deployment Manager | [KICS](https://kics.io/) | 14.5 |
+| Kubernetes | [KICS](https://kics.io/) | 14.5 |
+| OpenAPI | [KICS](https://kics.io/) | 14.5 |
+| Terraform <sup>2</sup> | [KICS](https://kics.io/) | 14.5 |
-1. IaC scanning can analyze Azure Resource Manager templates in JSON format. If you write templates in the [Bicep](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview) language, you must use [the bicep CLI](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-cli) to convert your Bicep files into JSON before GitLab IaC scanning can analyze them.
+1. IaC Scanning can analyze Azure Resource Manager templates in JSON format. If you write templates in the [Bicep](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/overview) language, you must use [the bicep CLI](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-cli) to convert your Bicep files into JSON before GitLab IaC Scanning can analyze them.
1. Terraform modules in a custom registry are not scanned for vulnerabilities. You can follow [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/357004) for the proposed feature.
### Supported distributions
@@ -77,7 +79,7 @@ Different features are available in different [GitLab tiers](https://about.gitla
as shown in the following table:
| Capability | In Free & Premium | In Ultimate |
-|:----------------------------------------------------------------|:--------------------|:-------------------|
+| :-------------------------------------------------------------- | :------------------ | :----------------- |
| [Configure IaC scanner](#configuration) | **{check-circle}** | **{check-circle}** |
| Download [JSON Report](#reports-json-format) | **{check-circle}** | **{check-circle}** |
| See new findings in merge request widget | **{dotted-circle}** | **{check-circle}** |
@@ -98,14 +100,14 @@ To configure IaC Scanning for a project you can:
### Configure IaC Scanning manually
To enable IaC Scanning you must [include](../../../ci/yaml/index.md#includetemplate) the
-[`SAST-IaC.gitlab-ci.yml template`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/SAST-IaC.gitlab-ci.yml) provided as part of your GitLab installation. Here is an example of how to include it:
+[`SAST-IaC.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/SAST-IaC.gitlab-ci.yml) provided as part of your GitLab installation. Here is an example of how to include it:
```yaml
include:
- template: Jobs/SAST-IaC.gitlab-ci.yml
```
-The included template creates IaC scanning jobs in your CI/CD pipeline and scans
+The included template creates IaC Scanning jobs in your CI/CD pipeline and scans
your project's configuration files for possible vulnerabilities.
The results are saved as a
@@ -121,7 +123,123 @@ To enable IaC Scanning in a project, you can create a merge request:
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.
-Pipelines now include an IaC job.
+Pipelines now include an IaC Scanning job.
+
+## Customize rulesets **(ULTIMATE)**
+
+> [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/235359) support for overriding rules in GitLab 14.8.
+
+You can customize the default IaC Scanning rules provided with GitLab.
+
+The following customization options can be used separately, or together:
+
+- [Disable predefined rules](#disable-predefined-analyzer-rules).
+- [Override predefined rules](#override-predefined-analyzer-rules).
+
+### Disable predefined analyzer rules
+
+If there are specific IaC Scanning rules that you don't want active, you can disable them.
+
+To disable analyzer rules:
+
+1. Create a `.gitlab` directory at the root of your project, if one doesn't already exist.
+1. Create a custom ruleset file named `sast-ruleset.toml` in the `.gitlab` directory, if
+ one doesn't already exist.
+1. Set the `disabled` flag to `true` in the context of a `ruleset` section.
+1. In one or more `ruleset` subsections, list the rules to disable. Every
+ `ruleset.identifier` section has:
+ - A `type` field for the rule. For IaC Scanning, the identifier type is `kics_id`.
+ - A `value` field for the rule identifier. KICS rule identifiers are alphanumeric strings. To find the rule identifier, you can:
+ - Find it in the [JSON report artifact](#reports-json-format).
+ - Search for the rule name in the [list of KICS queries](https://docs.kics.io/latest/queries/all-queries/) and copy the alphanumeric identifier that's shown. The rule name is shown on the [Vulnerability Page](../vulnerabilities/index.md) when a rule violation is detected.
+
+In the following example `sast-ruleset.toml` file, the disabled rules are assigned to
+the `kics` analyzer by matching the `type` and `value` of identifiers:
+
+```toml
+[kics]
+ [[kics.ruleset]]
+ disable = true
+ [kics.ruleset.identifier]
+ type = "kics_id"
+ value = "8212e2d7-e683-49bc-bf78-d6799075c5a7"
+
+ [[kics.ruleset]]
+ disable = true
+ [kics.ruleset.identifier]
+ type = "kics_id"
+ value = "b03a748a-542d-44f4-bb86-9199ab4fd2d5"
+```
+
+### Override predefined analyzer rules
+
+If there are specific IaC Scanning rules you want to customize, you can override them. For
+example, you might lower the severity of a rule or link to your own documentation about how to fix a finding.
+
+To override rules:
+
+1. Create a `.gitlab` directory at the root of your project, if one doesn't already exist.
+1. Create a custom ruleset file named `sast-ruleset.toml` in the `.gitlab` directory, if
+ one doesn't already exist.
+1. In one or more `ruleset.identifier` subsections, list the rules to override. Every
+ `ruleset.identifier` section has:
+ - A `type` field for the rule. For IaC Scanning, the identifier type is `kics_id`.
+ - A `value` field for the rule identifier. KICS rule identifiers are alphanumeric strings. To find the rule identifier, you can:
+ - Find it in the [JSON report artifact](#reports-json-format).
+ - Search for the rule name in the [list of KICS queries](https://docs.kics.io/latest/queries/all-queries/) and copy the alphanumeric identifier that's shown. The rule name is shown on the [Vulnerability Page](../vulnerabilities/index.md) when a rule violation is detected.
+1. In the `ruleset.override` context of a `ruleset` section,
+ provide the keys to override. Any combination of keys can be
+ overridden. Valid keys are:
+ - description
+ - message
+ - name
+ - severity (valid options are: Critical, High, Medium, Low, Unknown, Info)
+
+In the following example `sast-ruleset.toml` file, rules are matched by the `type` and
+`value` of identifiers and then overridden:
+
+```toml
+[kics]
+ [[kics.ruleset]]
+ [kics.ruleset.identifier]
+ type = "kics_id"
+ value = "8212e2d7-e683-49bc-bf78-d6799075c5a7"
+ [kics.ruleset.override]
+ description = "OVERRIDDEN description"
+ message = "OVERRIDDEN message"
+ name = "OVERRIDDEN name"
+ severity = "Info"
+```
+
+## Pinning to specific analyzer version
+
+The GitLab-managed CI/CD template specifies a major version and automatically pulls the latest analyzer release within that major version.
+
+In some cases, you may need to use a specific version.
+For example, you might need to avoid a regression in a later release.
+
+To override the automatic update behavior, set the `SAST_ANALYZER_IMAGE_TAG` CI/CD variable
+in your CI/CD configuration file after you include the [`SAST-IaC.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/SAST-IaC.gitlab-ci.yml).
+
+Only set this variable within a specific job.
+If you set it [at the top level](../../../ci/variables/index.md#create-a-custom-cicd-variable-in-the-gitlab-ciyml-file), the version you set will be used for other SAST analyzers.
+
+You can set the tag to:
+
+- A major version, like `3`. Your pipelines will use any minor or patch updates that are released within this major version.
+- A minor version, like `3.7`. Your pipelines will use any patch updates that are released within this minor version.
+- A patch version, like `3.7.0`. Your pipelines won't receive any updates.
+
+This example uses a specific minor version of the `KICS` analyzer:
+
+```yaml
+include:
+ - template: Security/SAST-IaC.gitlab-ci.yml
+
+kics-iac-sast:
+ variables:
+ SAST_ANALYZER_IMAGE_TAG: "3.1"
+```
## Reports JSON format
diff --git a/doc/user/application_security/img/secure_tools_and_cicd_stages.png b/doc/user/application_security/img/secure_tools_and_cicd_stages.png
index 3dbfd835baf..3284b376adc 100644
--- a/doc/user/application_security/img/secure_tools_and_cicd_stages.png
+++ b/doc/user/application_security/img/secure_tools_and_cicd_stages.png
Binary files differ
diff --git a/doc/user/application_security/index.md b/doc/user/application_security/index.md
index 809fa5f3764..5ddfa99fc81 100644
--- a/doc/user/application_security/index.md
+++ b/doc/user/application_security/index.md
@@ -227,7 +227,7 @@ The artifact generated by the secure analyzer contains all findings it discovers
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4393) in GitLab Free 13.5.
> - Made [available in all tiers](https://gitlab.com/gitlab-org/gitlab/-/issues/273205) in 13.6.
-> - Report download dropdown [added](https://gitlab.com/gitlab-org/gitlab/-/issues/273418) in 13.7.
+> - Report download dropdown list [added](https://gitlab.com/gitlab-org/gitlab/-/issues/273418) in 13.7.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/249550) in GitLab 13.9.
### All tiers
@@ -403,7 +403,7 @@ Learn more on overriding security jobs:
- [Overriding Dependency Scanning jobs](dependency_scanning/index.md#overriding-dependency-scanning-jobs).
- [Overriding Container Scanning jobs](container_scanning/index.md#overriding-the-container-scanning-template).
- [Overriding Secret Detection jobs](secret_detection/index.md#configure-scan-settings).
-- [Overriding DAST jobs](dast/index.md#customize-dast-settings).
+- [Overriding DAST jobs](dast/proxy-based.md#customize-dast-settings).
- [Overriding License Compliance jobs](../compliance/license_compliance/index.md#overriding-the-template).
All the security scanning tools define their stage, so this error can occur with all of them.
@@ -487,7 +487,7 @@ Security and compliance teams must ensure that security scans:
GitLab provides two methods of accomplishing this, each with advantages and disadvantages.
-- [Compliance framework pipelines](../group/manage.md#configure-a-compliance-pipeline)
+- [Compliance framework pipelines](../group/compliance_frameworks.md#configure-a-compliance-pipeline)
are recommended when:
- Scan execution enforcement is required for any scanner that uses a GitLab template, such as SAST IaC, DAST, Dependency Scanning,
@@ -499,8 +499,8 @@ GitLab provides two methods of accomplishing this, each with advantages and disa
are recommended when:
- Scan execution enforcement is required for DAST which uses a DAST site or scan profile.
- - Scan execution enforcement is required for SAST, Secret Detection, or Container Scanning with project-specific variable
- customizations. To accomplish this, users must create a separate security policy per project.
+ - Scan execution enforcement is required for SAST, Secret Detection, Dependency Scanning, or Container Scanning with project-specific
+variable customizations. To accomplish this, users must create a separate security policy per project.
- Scans are required to run on a regular, scheduled cadence.
- Either solution can be used equally well when:
@@ -514,7 +514,7 @@ Additional details about the differences between the two solutions are outlined
| | Compliance Framework Pipelines | Scan Execution Policies |
| ------ | ------ | ------ |
-| **Flexibility** | Supports anything that can be done in a CI file. | Limited to only the items for which GitLab has explicitly added support. DAST, SAST, Secret Detection, and Container Scanning scans are supported. |
+| **Flexibility** | Supports anything that can be done in a CI file. | Limited to only the items for which GitLab has explicitly added support. DAST, SAST, Secret Detection, Dependency Scanning, and Container Scanning scans are supported. |
| **Usability** | Requires knowledge of CI YAML. | Follows a `rules` and `actions`-based YAML structure. |
| **Inclusion in CI pipeline** | The compliance pipeline is executed instead of the project's `.gitlab-ci.yml` file. To include the project's `.gitlab-ci.yml` file, use an `include` statement. Defined variables aren't allowed to be overwritten by the included project's YAML file. | Forced inclusion of a new job into the CI pipeline. DAST jobs that must be customized on a per-project basis can have project-level Site Profiles and Scan Profiles defined. To ensure separation of duties, these profiles are immutable when referenced in a scan execution policy. All jobs can be customized as part of the security policy itself with the same variables that are normally available to the CI job. |
| **Schedulable** | Can be scheduled through a scheduled pipeline on the group. | Can be scheduled natively through the policy configuration itself. |
diff --git a/doc/user/application_security/policies/index.md b/doc/user/application_security/policies/index.md
index b1315329071..f6d22ab28cd 100644
--- a/doc/user/application_security/policies/index.md
+++ b/doc/user/application_security/policies/index.md
@@ -57,7 +57,7 @@ project and a project that you would like to designate as the security policy pr
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Security & Compliance > Policies**.
1. Select **Edit Policy Project**, and search for and select the
- project you would like to link from the dropdown menu.
+ project you would like to link from the dropdown list.
1. Select **Save**.
To unlink a security policy project, follow the same steps but instead select the trash can icon in
diff --git a/doc/user/application_security/policies/scan-execution-policies.md b/doc/user/application_security/policies/scan-execution-policies.md
index 41d25dfa8c8..f950d5116b1 100644
--- a/doc/user/application_security/policies/scan-execution-policies.md
+++ b/doc/user/application_security/policies/scan-execution-policies.md
@@ -15,7 +15,7 @@ with a long, random job name. In the unlikely event of a job name collision, the
any pre-existing job in the pipeline. If a policy is created at the group-level, it will apply to every child
project or subgroup. A group-level policy cannot be edited from a child project or subgroup.
-This feature has some overlap with [compliance framework pipelines](../../group/manage.md#configure-a-compliance-pipeline),
+This feature has some overlap with [compliance framework pipelines](../../group/compliance_frameworks.md#configure-a-compliance-pipeline),
as we have not [unified the user experience for these two features](https://gitlab.com/groups/gitlab-org/-/epics/7312).
For details on the similarities and differences between these features, see
[Enforce scan execution](../index.md#enforce-scan-execution).
@@ -129,14 +129,14 @@ rule in the defined policy are met.
| Field | Type | Possible values | Description |
|-------|------|-----------------|-------------|
-| `scan` | `string` | `dast`, `secret_detection`, `sast`, `container_scanning` | The action's type. |
-| `site_profile` | `string` | Name of the selected [DAST site profile](../dast/index.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/index.md#scanner-profile). | The DAST scanner profile to execute the DAST scan. This field should only be set if `scan` type is `dast`.|
+| `scan` | `string` | `dast`, `secret_detection`, `sast`, `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. |
Note the following:
-- You must create the [site profile](../dast/index.md#site-profile) and [scanner profile](../dast/index.md#scanner-profile)
+- You must create the [site profile](../dast/proxy-based.md#site-profile) and [scanner profile](../dast/proxy-based.md#scanner-profile)
with selected names for each project that is assigned to the selected Security Policy Project.
Otherwise, the policy is not applied and a job with an error message is created instead.
- Once you associate the site profile and scanner profile by name in the policy, it is not possible
@@ -152,7 +152,7 @@ Note the following:
mode when executed as part of a scheduled scan.
- A container scanning scan that is configured for the `pipeline` rule type ignores the agent defined in the `agents` object. The `agents` object is only considered for `schedule` rule types.
An agent with a name provided in the `agents` object must be created and configured for the project.
-- The SAST scan uses the default template and runs in a [child pipeline](../../../ci/pipelines/downstream_pipelines.md#parent-child-pipelines).
+- The Dependency Scanning and SAST scans use the default templates and run in a [child pipeline](../../../ci/pipelines/downstream_pipelines.md#parent-child-pipelines).
## Example security policies project
diff --git a/doc/user/application_security/policies/scan-result-policies.md b/doc/user/application_security/policies/scan-result-policies.md
index 45b715a52b8..7482df18cc3 100644
--- a/doc/user/application_security/policies/scan-result-policies.md
+++ b/doc/user/application_security/policies/scan-result-policies.md
@@ -6,6 +6,8 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Scan result policies **(ULTIMATE)**
+> Group-level scan result policies [introduced](https://gitlab.com/groups/gitlab-org/-/epics/7622) in GitLab 15.6.
+
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
@@ -20,7 +22,8 @@ job is fully executed. The following video gives you an overview of GitLab scan
## Scan result policy editor
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77814) in GitLab 14.8.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77814) in GitLab 14.8.
+> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/369473) in GitLab 15.6.
NOTE:
Only project Owners have the [permissions](../../permissions.md#project-members-permissions)
@@ -38,6 +41,9 @@ before the policy changes take effect.
The [policy editor](index.md#policy-editor) supports YAML mode and rule mode.
+NOTE:
+Propagating scan result policies created for groups with a large number of projects will take a while to complete.
+
## Scan result policies schema
The YAML file with scan result policies consists of an array of objects matching the scan result
diff --git a/doc/user/application_security/sast/analyzers.md b/doc/user/application_security/sast/analyzers.md
index dfb096f14cc..e83825636bf 100644
--- a/doc/user/application_security/sast/analyzers.md
+++ b/doc/user/application_security/sast/analyzers.md
@@ -12,7 +12,7 @@ Static Application Security Testing (SAST) uses analyzers
to detect vulnerabilities in source code. Each analyzer is a wrapper around a [scanner](../terminology/index.md#scanner), a third-party code analysis tool.
The analyzers are published as Docker images that SAST uses to launch dedicated containers for each
-analysis.
+analysis. We recommend a minimum of 4GB RAM to ensure consistent performance of the analyzers.
SAST default images are maintained by GitLab, but you can also integrate your own custom image.
@@ -134,6 +134,14 @@ In GitLab 15.4, we [removed the deprecated analyzers](https://gitlab.com/gitlab-
To preview the upcoming changes to the CI/CD configuration in GitLab 15.3 or earlier:
1. Open an MR to switch from the Stable CI/CD template, `SAST.gitlab-ci.yaml`, to [the Latest template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/SAST.latest.gitlab-ci.yml), `SAST.latest.gitlab-ci.yaml`.
+ - On GitLab.com, use the latest template directly:
+
+ ```yaml
+ include:
+ template: 'Jobs/SAST.latest.gitlab-ci.yaml'
+ ```
+
+ - On a Self-Managed instance, download the template from GitLab.com:
```yaml
include:
diff --git a/doc/user/application_security/sast/index.md b/doc/user/application_security/sast/index.md
index a7624db4604..b1bc9794ced 100644
--- a/doc/user/application_security/sast/index.md
+++ b/doc/user/application_security/sast/index.md
@@ -70,44 +70,45 @@ is **not** `19.03.0`. See [troubleshooting information](#error-response-from-dae
## Supported languages and frameworks
-GitLab SAST supports a variety of languages, package managers, and frameworks. Our SAST security scanners also feature automatic language detection which works even for mixed-language projects. If any supported language is detected in project source code we automatically run the appropriate SAST analyzers.
-
-You can also [view our language roadmap](https://about.gitlab.com/direction/secure/static-analysis/sast/#language-support) and [request other language support by opening an issue](https://gitlab.com/groups/gitlab-org/-/epics/297).
-
-| Language (package managers) / framework | Scan tool | Introduced in GitLab Version |
-|------------------------------------------------|-----------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------|
-| .NET Core | [Security Code Scan](https://security-code-scan.github.io) | 11.0 |
-| .NET Framework<sup>1</sup> | [Security Code Scan](https://security-code-scan.github.io) | 13.0 |
-| .NET (all versions, C# only) | [Semgrep](https://semgrep.dev) | 15.4 |
-| Apex (Salesforce) | [PMD](https://pmd.github.io/pmd/index.html) | 12.1 |
-| C | [Semgrep](https://semgrep.dev) | 14.2 |
-| C/C++ | [Flawfinder](https://github.com/david-a-wheeler/flawfinder) | 10.7 |
-| Elixir (Phoenix) | [Sobelow](https://github.com/nccgroup/sobelow) | 11.1 |
-| Go<sup>3</sup> | [Gosec](https://github.com/securego/gosec) | 10.7 |
-| Go | [Semgrep](https://semgrep.dev) | 14.4 |
-| Groovy<sup>2</sup> | [SpotBugs](https://spotbugs.github.io/) with the [find-sec-bugs](https://find-sec-bugs.github.io/) plugin | 11.3 (Gradle) & 11.9 (Maven, SBT) |
-| Helm Charts | [Kubesec](https://github.com/controlplaneio/kubesec) | 13.1 |
-| Java (any build system) | [Semgrep](https://semgrep.dev) | 14.10 |
-| Java<sup>2, 3</sup> | [SpotBugs](https://spotbugs.github.io/) with the [find-sec-bugs](https://find-sec-bugs.github.io/) plugin | 10.6 (Maven), 10.8 (Gradle) & 11.9 (SBT) |
-| Java (Android) | [MobSF (beta)](https://github.com/MobSF/Mobile-Security-Framework-MobSF) | 13.5 |
-| JavaScript<sup>3</sup> | [ESLint security plugin](https://github.com/nodesecurity/eslint-plugin-security) | 11.8 |
-| JavaScript | [Semgrep](https://semgrep.dev) | 13.10 |
-| Kotlin (Android) | [MobSF (beta)](https://github.com/MobSF/Mobile-Security-Framework-MobSF) | 13.5 |
-| Kotlin (General)<sup>2</sup> | [SpotBugs](https://spotbugs.github.io/) with the [find-sec-bugs](https://find-sec-bugs.github.io/) plugin | 13.11 |
-| Kubernetes manifests | [Kubesec](https://github.com/controlplaneio/kubesec) | 12.6 |
-| Node.js | [NodeJsScan](https://github.com/ajinabraham/NodeJsScan) | 11.1 |
-| Objective-C (iOS) | [MobSF (beta)](https://github.com/MobSF/Mobile-Security-Framework-MobSF) | 13.5 |
-| PHP | [phpcs-security-audit](https://github.com/FloeDesignTechnologies/phpcs-security-audit) | 10.8 |
-| Python<sup>3</sup> | [bandit](https://github.com/PyCQA/bandit) | 10.3 |
-| Python | [Semgrep](https://semgrep.dev) | 13.9 |
-| React<sup>3</sup> | [ESLint react plugin](https://github.com/yannickcr/eslint-plugin-react) | 12.5 |
-| React | [Semgrep](https://semgrep.dev) | 13.10 |
-| Ruby | [brakeman](https://brakemanscanner.org) | 13.9 |
-| Ruby on Rails | [brakeman](https://brakemanscanner.org) | 10.3 |
-| Scala<sup>2</sup> | [SpotBugs](https://spotbugs.github.io/) with the [find-sec-bugs](https://find-sec-bugs.github.io/) plugin | 11.0 (SBT) & 11.9 (Gradle, Maven) |
-| Swift (iOS) | [MobSF (beta)](https://github.com/MobSF/Mobile-Security-Framework-MobSF) | 13.5 |
-| TypeScript<sup>3</sup> | [ESLint security plugin](https://github.com/nodesecurity/eslint-plugin-security) | 11.9, [merged](https://gitlab.com/gitlab-org/gitlab/-/issues/36059) with ESLint in 13.2 |
-| TypeScript | [Semgrep](https://semgrep.dev) | 13.10 |
+GitLab SAST supports scanning a variety of programming languages and frameworks.
+Once you [enable SAST](#configuration), the right set of analyzers runs automatically even if your project uses more than one language.
+
+Check the [SAST direction page](https://about.gitlab.com/direction/secure/static-analysis/sast/#language-support) to learn more about our plans for language support in SAST.
+
+| Language / framework | [Analyzer](analyzers.md) used for scanning | Minimum supported GitLab version |
+|------------------------------|--------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------|
+| .NET Core | [Security Code Scan](https://gitlab.com/gitlab-org/security-products/analyzers/security-code-scan) | 11.0 |
+| .NET Framework<sup>1</sup> | [Security Code Scan](https://gitlab.com/gitlab-org/security-products/analyzers/security-code-scan) | 13.0 |
+| .NET (all versions, C# only) | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with GitLab-managed rules | 15.4 |
+| Apex (Salesforce) | [PMD](https://gitlab.com/gitlab-org/security-products/analyzers/pmd-apex) | 12.1 |
+| C | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with GitLab-managed rules | 14.2 |
+| C/C++ | [Flawfinder](https://gitlab.com/gitlab-org/security-products/analyzers/flawfinder) | 10.7 |
+| Elixir (Phoenix) | [Sobelow](https://gitlab.com/gitlab-org/security-products/analyzers/sobelow) | 11.1 |
+| Go<sup>3</sup> | [Gosec](https://gitlab.com/gitlab-org/security-products/analyzers/gosec) | 10.7 |
+| Go | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with GitLab-managed rules | 14.4 |
+| Groovy<sup>2</sup> | [SpotBugs](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) with the find-sec-bugs plugin | 11.3 (Gradle) & 11.9 (Maven, SBT) |
+| Helm Charts | [Kubesec](https://gitlab.com/gitlab-org/security-products/analyzers/kubesec) | 13.1 |
+| Java (any build system) | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with GitLab-managed rules | 14.10 |
+| Java<sup>2, 3</sup> | [SpotBugs](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) with the find-sec-bugs plugin | 10.6 (Maven), 10.8 (Gradle) & 11.9 (SBT) |
+| Java (Android) | [MobSF (beta)](https://gitlab.com/gitlab-org/security-products/analyzers/mobsf) | 13.5 |
+| JavaScript<sup>3</sup> | [ESLint security plugin](https://gitlab.com/gitlab-org/security-products/analyzers/eslint) | 11.8 |
+| JavaScript | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with GitLab-managed rules | 13.10 |
+| Kotlin (Android) | [MobSF (beta)](https://gitlab.com/gitlab-org/security-products/analyzers/mobsf) | 13.5 |
+| Kotlin (General)<sup>2</sup> | [SpotBugs](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) with the find-sec-bugs plugin | 13.11 |
+| Kubernetes manifests | [Kubesec](https://gitlab.com/gitlab-org/security-products/analyzers/kubesec) | 12.6 |
+| Node.js | [NodeJsScan](https://gitlab.com/gitlab-org/security-products/analyzers/nodejs-scan) | 11.1 |
+| Objective-C (iOS) | [MobSF (beta)](https://gitlab.com/gitlab-org/security-products/analyzers/mobsf) | 13.5 |
+| PHP | [phpcs-security-audit](https://gitlab.com/gitlab-org/security-products/analyzers/phpcs-security-audit) | 10.8 |
+| Python<sup>3</sup> | [bandit](https://gitlab.com/gitlab-org/security-products/analyzers/bandit) | 10.3 |
+| Python | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with GitLab-managed rules | 13.9 |
+| React<sup>3</sup> | [ESLint react plugin](https://gitlab.com/gitlab-org/security-products/analyzers/eslint) | 12.5 |
+| React | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with GitLab-managed rules | 13.10 |
+| Ruby | [brakeman](https://gitlab.com/gitlab-org/security-products/analyzers/brakeman) | 13.9 |
+| Ruby on Rails | [brakeman](https://gitlab.com/gitlab-org/security-products/analyzers/brakeman) | 10.3 |
+| Scala<sup>2</sup> | [SpotBugs](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) with the find-sec-bugs plugin | 11.0 (SBT) & 11.9 (Gradle, Maven) |
+| Swift (iOS) | [MobSF (beta)](https://gitlab.com/gitlab-org/security-products/analyzers/mobsf) | 13.5 |
+| TypeScript<sup>3</sup> | [ESLint security plugin](https://gitlab.com/gitlab-org/security-products/analyzers/eslint) | 11.9, [merged](https://gitlab.com/gitlab-org/gitlab/-/issues/36059) with ESLint in 13.2 |
+| TypeScript | [Semgrep](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) with GitLab-managed rules | 13.10 |
1. .NET 4 support is limited. The analyzer runs in a Linux container and does not have access to Windows-specific libraries or features. Use the Semgrep-based scanner if you need .NET 4 support.
1. The SpotBugs-based analyzer supports [Gradle](https://gradle.org/), [Maven](https://maven.apache.org/), and [SBT](https://www.scala-sbt.org/). It can also be used with variants like the
@@ -116,7 +117,7 @@ You can also [view our language roadmap](https://about.gitlab.com/direction/secu
and the [Maven wrapper](https://github.com/takari/maven-wrapper). However, SpotBugs has [limitations](https://gitlab.com/gitlab-org/gitlab/-/issues/350801) when used against [Ant](https://ant.apache.org/)-based projects. We recommend using the Semgrep-based analyzer for Ant-based Java projects.
1. These analyzers reached [End of Support](https://about.gitlab.com/handbook/product/gitlab-the-product/#end-of-support) status [in GitLab 15.4](https://gitlab.com/gitlab-org/gitlab/-/issues/352554).
-### Multi-project support
+## Multi-project support
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/4895) in GitLab 13.7.
@@ -136,16 +137,52 @@ The following analyzers have multi-project support:
- SpotBugs
- Sobelow
-#### Enable multi-project support for Security Code Scan
+### Enable multi-project support for Security Code Scan
Multi-project support in the Security Code Scan requires a Solution (`.sln`) file in the root of
the repository. For details on the Solution format, see the Microsoft reference [Solution (`.sln`) file](https://learn.microsoft.com/en-us/visualstudio/extensibility/internals/solution-dot-sln-file?view=vs-2019).
-### Supported distributions
+## False positive detection **(ULTIMATE)**
+
+> Introduced in GitLab 14.2.
+
+Vulnerabilities that have been detected and are false positives will be flagged as false positives in the security dashboard.
+
+False positive detection is available in a subset of the [supported languages](#supported-languages-and-frameworks) and [analyzers](analyzers.md):
+
+- Ruby, in the Brakeman-based analyzer
+
+![SAST false-positives show in Vulnerability Pages](img/sast_vulnerability_page_fp_detection_v15_2.png)
+
+## Advanced vulnerability tracking **(ULTIMATE)**
+
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5144) in GitLab 14.2.
+
+Source code is volatile; as developers make changes, source code may move within files or between files.
+Security analyzers may have already reported vulnerabilities that are being tracked in the [Vulnerability Report](../vulnerability_report/index.md).
+These vulnerabilities are linked to specific problematic code fragments so that they can be found and fixed.
+If the code fragments are not tracked reliably as they move, vulnerability management is harder because the same vulnerability could be reported again.
+
+GitLab SAST uses an advanced vulnerability tracking algorithm to more accurately identify when the same vulnerability has moved within a file due to refactoring or unrelated changes.
+
+Advanced vulnerability tracking is available in a subset of the [supported languages](#supported-languages-and-frameworks) and [analyzers](analyzers.md):
+
+- C, in the Semgrep-based analyzer only
+- Go, in the Gosec- and Semgrep-based analyzers
+- Java, in the Semgrep-based analyzer only
+- JavaScript, in the Semgrep-based analyzer only
+- Python, in the Semgrep-based analyzer only
+- Ruby, in the Brakeman-based analyzer
+
+Support for more languages and analyzers is tracked in [this epic](https://gitlab.com/groups/gitlab-org/-/epics/5144).
+
+For more information, see the confidential project `https://gitlab.com/gitlab-org/security-products/post-analyzers/tracking-calculator`. The content of this project is available only to GitLab team members.
+
+## Supported distributions
The default scanner images are build off a base Alpine image for size and maintainability.
-#### FIPS-enabled images
+### FIPS-enabled images
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/6479) in GitLab 14.10.
@@ -169,17 +206,14 @@ A FIPS-compliant image is only available for the Semgrep-based analyzer.
To use SAST in a FIPS-compliant manner, you must [exclude other analyzers from running](analyzers.md#customize-analyzers).
-### Making SAST analyzers available to all GitLab tiers
-
-All open source (OSS) analyzers have been moved to the GitLab Free tier as of GitLab 13.3.
-
-#### Summary of features per tier
+## Summary of features per tier
Different features are available in different [GitLab tiers](https://about.gitlab.com/pricing/),
as shown in the following table:
| Capability | In Free & Premium | In Ultimate |
|:---------------------------------------------------------------- -|:--------------------|:-------------------|
+| Automatically scan code with [appropriate analyzers](#supported-languages-and-frameworks) | **{check-circle}** | **{check-circle}** |
| [Configure SAST scanners](#configuration) | **{check-circle}** | **{check-circle}** |
| [Customize SAST settings](#available-cicd-variables) | **{check-circle}** | **{check-circle}** |
| Download [JSON Report](#reports-json-format) | **{check-circle}** | **{check-circle}** |
@@ -207,14 +241,14 @@ To configure SAST for a project you can:
### Configure SAST manually
To enable SAST you must [include](../../../ci/yaml/index.md#includetemplate)
-the [`SAST.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml)
+the [`SAST.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml)
provided as a part of your GitLab installation.
Add the following to your `.gitlab-ci.yml` file:
```yaml
include:
- - template: Security/SAST.gitlab-ci.yml
+ - template: Jobs/SAST.gitlab-ci.yml
```
The included template creates SAST jobs in your CI/CD pipeline and scans
@@ -300,14 +334,26 @@ spotbugs-sast:
FAIL_NEVER: 1
```
-#### Pinning to minor image version
+### Pinning to minor image version
+
+The GitLab-managed CI/CD template specifies a major version and automatically pulls the latest analyzer release within that major version.
-While our templates use `MAJOR` version pinning to always ensure the latest analyzer
-versions are pulled, there are certain cases where it can be beneficial to pin
-an analyzer to a specific release. To do so, override the `SAST_ANALYZER_IMAGE_TAG` CI/CD variable
-in the job template directly.
+In some cases, you may need to use a specific version.
+For example, you might need to avoid a regression in a later release.
-In the example below, we pin to a minor version of the `semgrep` analyzer and a specific patch version of the `brakeman` analyzer:
+To override the automatic update behavior, set the `SAST_ANALYZER_IMAGE_TAG` CI/CD variable
+in your CI/CD configuration file after you include the [`SAST.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/SAST.gitlab-ci.yml).
+
+Only set this variable within a specific job.
+If you set it [at the top level](../../../ci/variables/index.md#create-a-custom-cicd-variable-in-the-gitlab-ciyml-file), the version you set will be used for other SAST analyzers.
+
+You can set the tag to:
+
+- A major version, like `3`. Your pipelines will use any minor or patch updates that are released within this major version.
+- A minor version, like `3.7`. Your pipelines will use any patch updates that are released within this minor version.
+- A patch version, like `3.7.0`. Your pipelines won't receive any updates.
+
+This example uses a specific minor version of the `semgrep` analyzer and a specific patch version of the `brakeman` analyzer:
```yaml
include:
@@ -315,47 +361,13 @@ include:
semgrep-sast:
variables:
- SAST_ANALYZER_IMAGE_TAG: "2.16"
+ SAST_ANALYZER_IMAGE_TAG: "3.7"
brakeman-sast:
variables:
- SAST_ANALYZER_IMAGE_TAG: "2.21.1"
+ SAST_ANALYZER_IMAGE_TAG: "3.1.1"
```
-### False Positive Detection **(ULTIMATE)**
-
-> Introduced in GitLab 14.2.
-
-Vulnerabilities that have been detected and are false positives will be flagged as false positives in the security dashboard.
-
-False positive detection is available in a subset of the [supported languages](#supported-languages-and-frameworks) and [analyzers](analyzers.md):
-
-- Ruby, in the Brakeman-based analyzer
-
-![SAST false-positives show in Vulnerability Pages](img/sast_vulnerability_page_fp_detection_v15_2.png)
-
-### Advanced vulnerability tracking **(ULTIMATE)**
-
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5144) in GitLab 14.2.
-
-Source code is volatile; as developers make changes, source code may move within files or between files.
-Security analyzers may have already reported vulnerabilities that are being tracked in the [Vulnerability Report](../vulnerability_report/index.md).
-These vulnerabilities are linked to specific problematic code fragments so that they can be found and fixed.
-If the code fragments are not tracked reliably as they move, vulnerability management is harder because the same vulnerability could be reported again.
-
-GitLab SAST uses an advanced vulnerability tracking algorithm to more accurately identify when the same vulnerability has moved within a file due to refactoring or unrelated changes.
-
-Advanced vulnerability tracking is available in a subset of the [supported languages](#supported-languages-and-frameworks) and [analyzers](analyzers.md):
-
-- C, in the Semgrep-based analyzer only
-- Go, in the Gosec- and Semgrep-based analyzers
-- Java, in the Semgrep-based analyzer only
-- JavaScript, in the Semgrep-based analyzer only
-- Python, in the Semgrep-based analyzer only
-- Ruby, in the Brakeman-based analyzer
-
-Support for more languages and analyzers is tracked in [this epic](https://gitlab.com/groups/gitlab-org/-/epics/5144).
-
### Using CI/CD variables to pass credentials for private repositories
Some analyzers require downloading the project's dependencies to
@@ -665,16 +677,16 @@ import the following default SAST analyzer images from `registry.gitlab.com` int
[local Docker container registry](../../packages/container_registry/index.md):
```plaintext
-registry.gitlab.com/security-products/brakeman:2
-registry.gitlab.com/security-products/flawfinder:2
-registry.gitlab.com/security-products/kubesec:2
-registry.gitlab.com/security-products/nodejs-scan:2
-registry.gitlab.com/security-products/phpcs-security-audit:2
-registry.gitlab.com/security-products/pmd-apex:2
-registry.gitlab.com/security-products/security-code-scan:2
-registry.gitlab.com/security-products/semgrep:2
-registry.gitlab.com/security-products/sobelow:2
-registry.gitlab.com/security-products/spotbugs:2
+registry.gitlab.com/security-products/brakeman:3
+registry.gitlab.com/security-products/flawfinder:3
+registry.gitlab.com/security-products/kubesec:3
+registry.gitlab.com/security-products/nodejs-scan:3
+registry.gitlab.com/security-products/phpcs-security-audit:3
+registry.gitlab.com/security-products/pmd-apex:3
+registry.gitlab.com/security-products/security-code-scan:3
+registry.gitlab.com/security-products/semgrep:3
+registry.gitlab.com/security-products/sobelow:3
+registry.gitlab.com/security-products/spotbugs:3
```
The process for importing Docker images into a local offline Docker registry depends on
diff --git a/doc/user/application_security/secret_detection/index.md b/doc/user/application_security/secret_detection/index.md
index df6bb19ac25..8a066cf1be1 100644
--- a/doc/user/application_security/secret_detection/index.md
+++ b/doc/user/application_security/secret_detection/index.md
@@ -15,18 +15,18 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> `secret_detection_default_branch` and `secret_detection` were consolidated into one job,
> `secret_detection`.
-People may accidentally commit secrets to
-remote Git repositories. Secrets include keys, passwords, API tokens, and other sensitive
-information. Anyone with access to the repository could use the secrets for malicious purposes.
-Exposed secrets are compromised and must be replaced, which can be costly.
-
-To help prevent secrets from being committed to a Git repository, you can use Secret Detection
-to scan your repository for secrets. Scanning is language
-and framework agnostic, but does not support scanning binary files.
-
-Secret Detection uses a specific analyzer containing the
-[Gitleaks](https://github.com/zricethezav/gitleaks) tool to scan the repository for secrets, in a
-`secret-detection` job. The results are saved as a
+People may accidentally commit secrets (such as keys, passwords, and API tokens) to remote Git repositories.
+
+Anyone with access to the repository could use the secrets for malicious purposes. Exposed secrets
+must be considered compromised and be replaced, which can be costly.
+
+To help prevent secrets from being committed to a Git repository, you can use Secret Detection to
+scan your repository for secrets. Scanning is language and framework agnostic, but does not support
+scanning binary files.
+
+Secret Detection uses an analyzer containing the [Gitleaks](https://github.com/zricethezav/gitleaks)
+tool to scan the repository for secrets. Detection occurs in the `secret-detection` job. The results
+are saved as a
[Secret Detection report artifact](../../../ci/yaml/artifacts_reports.md#artifactsreportssecret_detection)
that you can later download and analyze. Due to implementation limitations, we always take the
latest Secret Detection artifact available.
@@ -38,7 +38,7 @@ All identified secrets are reported in the:
- Merge request widget
- Pipelines' **Security** tab
-- [Security Dashboard](../security_dashboard/index.md)
+- [Vulnerability Report](../vulnerability_report/index.md)
![Secret Detection in merge request widget](img/secret_detection_v13_2.png)
@@ -61,7 +61,7 @@ Different features are available in different [GitLab tiers](https://about.gitla
| Download [JSON Report](../sast/index.md#reports-json-format) | **{check-circle}** Yes | **{check-circle}** Yes |
| See new findings in the merge request widget | **{dotted-circle}** No | **{check-circle}** Yes |
| View identified secrets in the pipelines' **Security** tab | **{dotted-circle}** No | **{check-circle}** Yes |
-| [Manage vulnerabilities](../vulnerabilities/index.md) | **{dotted-circle}** No | **{check-circle}** Yes |
+| [Manage vulnerabilities](../vulnerability_report/index.md) | **{dotted-circle}** No | **{check-circle}** Yes |
| [Access the Security Dashboard](../security_dashboard/index.md) | **{dotted-circle}** No | **{check-circle}** Yes |
| [Customize Secret Detection rulesets](#custom-rulesets) | **{dotted-circle}** No | **{check-circle}** Yes |
@@ -88,13 +88,13 @@ To enable Secret Detection, either:
### Enable Secret Detection by including the template
-We recommend this method if you have an existing GitLab CI/CD configuration file.
+You should use this method if you have an existing GitLab CI/CD configuration file.
Add the following extract to your `.gitlab-ci.yml` file:
```yaml
include:
- - template: Security/Secret-Detection.gitlab-ci.yml
+ - template: Jobs/Secret-Detection.gitlab-ci.yml
```
Pipelines now include a Secret Detection job, and the results are included in the merge request
@@ -122,7 +122,34 @@ widget.
## Responding to a leaked secret
-If the scanner detects a secret we recommend you rotate it immediately. [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. Also, the secret remains in any forks of the repository.
+If the scanner detects a secret you should rotate it immediately. [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. Also, the secret remains in any forks of the repository.
+
+## Pinning to specific analyzer version
+
+The GitLab-managed CI/CD template specifies a major version and automatically pulls the latest analyzer release within that major version.
+
+In some cases, you may need to use a specific version.
+For example, you might need to avoid a regression in a later release.
+
+To override the automatic update behavior, set the `SECRETS_ANALYZER_VERSION` CI/CD variable
+in your CI/CD configuration file after you include the [`Secret-Detection.gitlab-ci.yml` template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Secret-Detection.gitlab-ci.yml).
+
+You can set the tag to:
+
+- A major version, like `4`. Your pipelines will use any minor or patch updates that are released within this major version.
+- A minor version, like `4.5`. Your pipelines will use any patch updates that are released within this minor version.
+- A patch version, like `4.5.0`. Your pipelines won't receive any updates.
+
+This example uses a specific minor version of the analyzer:
+
+```yaml
+include:
+ - template: Security/Secret-Detection.gitlab-ci.yml
+
+secret_detection:
+ variables:
+ SECRETS_ANALYZER_VERSION: "4.5"
+```
## Configure scan settings
@@ -154,11 +181,13 @@ secret_detection:
SECRET_DETECTION_HISTORIC_SCAN: "true"
```
-### Ignoring Secrets
+### Ignore secrets
-You might want to add a fake secret to your code base. For instance, you can use a fake secret as an example in your documentation or test suite.
+In some instances, you might want to ignore a secret. For example, you may have a fake secret in an
+example or a test suite. In these instances, you want to ignore the secret, instead of having it
+reported as a vulnerability.
-In these cases, Secret Detection can ignore the fake secret and not report it as a vulnerability. To ignore a secret, add `gitleaks:allow` as a comment to the line that contains the secret.
+To ignore a secret, add `gitleaks:allow` as a comment to the line that contains the secret.
For example:
@@ -172,7 +201,7 @@ Secret Detection can be customized by defining available CI/CD variables:
| CI/CD variable | Default value | Description |
|-----------------------------------|---------------|-------------|
-| `SECRET_DETECTION_EXCLUDED_PATHS` | "" | Exclude vulnerabilities from output based on the paths. This is 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. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225273) in GitLab 13.3. |
+| `SECRET_DETECTION_EXCLUDED_PATHS` | "" | Exclude vulnerabilities from output based on the paths. The paths are 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. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225273) in GitLab 13.3. |
| `SECRET_DETECTION_HISTORIC_SCAN` | false | Flag to enable a historic Gitleaks scan. |
| `SECRET_DETECTION_IMAGE_SUFFIX` | "" | Suffix added to the image name. If set to `-fips`, `FIPS-enabled` images are used for scan. See [Use FIPS-enabled images](#use-fips-enabled-images) for more details. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/355519) in GitLab 14.10. |
| `SECRET_DETECTION_LOG_OPTIONS` | "" | [`git log`](https://git-scm.com/docs/git-log) options used to define commit ranges. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/350660) in GitLab 15.1.|
@@ -214,7 +243,7 @@ By default, Secret Detection scans only the current state of the Git repository.
contained in the repository's history are not detected. To address this, Secret Detection can
scan the Git repository's full history.
-We recommend you do a full history scan only once, after enabling Secret Detection. A full history
+You should do a full history scan only once, after enabling Secret Detection. A full history
can take a long time, especially for larger repositories with lengthy Git histories. After
completing an initial full history scan, use only standard Secret Detection as part of your
pipeline.
@@ -349,15 +378,15 @@ In the `secret-detection-ruleset.toml` file, do one of the following:
## Running Secret Detection in an offline environment **(PREMIUM SELF)**
-For self-managed GitLab instances in an environment with limited, restricted, or intermittent access
-to external resources through the internet, some configuration changes are required for the Secret
-Detection job to run successfully. The instructions in this section must be completed together with
-the instructions detailed in [offline environments](../offline_deployments/index.md).
+An offline environment has limited, restricted, or intermittent access to external resources through
+the internet. For self-managed GitLab instances in such an environment, Secret Detection requires
+some configuration changes. The instructions in this section must be completed together with the
+instructions detailed in [offline environments](../offline_deployments/index.md).
### Configure GitLab Runner
By default, a runner tries to pull Docker images from the GitLab container registry even if a local
-copy is available. We recommend using this default setting, to ensure Docker images remain current.
+copy is available. You should use this default setting, to ensure Docker images remain current.
However, if no network connectivity is available, you must change the default GitLab Runner
`pull_policy` variable.
@@ -379,11 +408,11 @@ Prerequisites:
[local Docker container registry](../../packages/container_registry/index.md):
```plaintext
- registry.gitlab.com/security-products/secret-detection:3
+ registry.gitlab.com/security-products/secrets:4
```
The Secret Detection analyzer's image is [periodically updated](../index.md#vulnerability-scanner-maintenance)
- so you may need to periodically update the local copy.
+ so you should periodically update the local copy.
1. Set the CI/CD variable `SECURE_ANALYZERS_PREFIX` to the local Docker container registry.
@@ -454,14 +483,14 @@ secrets. If the number of commits in a merge request is greater than the value o
[`GIT_DEPTH` CI/CD variable](../../../ci/runners/configure_runners.md#shallow-cloning), Secret
Detection [fails to detect secrets](#error-couldnt-run-the-gitleaks-command-exit-status-2).
-For example, if a pipeline is triggered from a merge request containing 60 commits and the
-`GIT_DEPTH` variable's value is less than 60, the Secret Detection job fails as the clone is not
-deep enough to contain all of the relevant commits. To veridy the current value, see
+For example, you could have a pipeline triggered from a merge request containing 60 commits and the
+`GIT_DEPTH` variable set to less than 60. In that case the Secret Detection job fails because the
+clone is not deep enough to contain all of the relevant commits. To verify the current value, see
[pipeline configuration](../../../ci/pipelines/settings.md#limit-the-number-of-changes-fetched-during-clone).
-To confirm this as the cause of the error, set the [logging level](#set-the-logging-level) to `debug`, then
-rerun the pipeline. The logs should look similar to the following example. The text "object not
-found" is a symptom of this error.
+To confirm this as the cause of the error, set the [logging level](#set-the-logging-level) to
+`debug`, then rerun the pipeline. The logs should look similar to the following example. The text
+"object not found" is a symptom of this error.
```plaintext
ERRO[2020-11-18T18:05:52Z] object not found
diff --git a/doc/user/application_security/security_dashboard/index.md b/doc/user/application_security/security_dashboard/index.md
index af98fc783e7..7c44b49b78c 100644
--- a/doc/user/application_security/security_dashboard/index.md
+++ b/doc/user/application_security/security_dashboard/index.md
@@ -153,7 +153,7 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/application_security/terminology/index.md b/doc/user/application_security/terminology/index.md
index 085a762fffa..f156d60be8f 100644
--- a/doc/user/application_security/terminology/index.md
+++ b/doc/user/application_security/terminology/index.md
@@ -230,7 +230,7 @@ support for cheap scan is proposed in issue [349926](https://gitlab.com/gitlab-o
### Pre-filter
-An irreversible action that is done to filter out target(s) before analysis occurs. This is usually provided to allow
+An irreversible action that is done to filter out targets before analysis occurs. This is usually provided to allow
the user to reduce scope and noise as well as speed up the analysis. This should not be done if a record is needed as
we currently do not store anything related to the skipped/excluded code or assets.
diff --git a/doc/user/application_security/vulnerabilities/severities.md b/doc/user/application_security/vulnerabilities/severities.md
index 36f9578f999..e75d0a45f7d 100644
--- a/doc/user/application_security/vulnerabilities/severities.md
+++ b/doc/user/application_security/vulnerabilities/severities.md
@@ -42,15 +42,13 @@ the following tables:
| [`sobelow`](https://gitlab.com/gitlab-org/security-products/analyzers/sobelow) | **{check-circle}** Yes | Not applicable | Hardcodes all severity levels to `Unknown` |
| [`nodejs-scan`](https://gitlab.com/gitlab-org/security-products/analyzers/nodejs-scan) | **{check-circle}** Yes | String | `INFO`, `WARNING`, `ERROR` |
| [`flawfinder`](https://gitlab.com/gitlab-org/security-products/analyzers/flawfinder) | **{check-circle}** Yes | Integer | `0`, `1`, `2`, `3`, `4`, `5` |
-| [`eslint`](https://gitlab.com/gitlab-org/security-products/analyzers/eslint) | **{check-circle}** Yes | Not applicable | Hardcodes all severity levels to `Unknown` |
| [`SpotBugs`](https://gitlab.com/gitlab-org/security-products/analyzers/spotbugs) | **{check-circle}** Yes | Integer | `1`, `2`, `3`, `11`, `12`, `18` |
-| [`gosec`](https://gitlab.com/gitlab-org/security-products/analyzers/gosec) | **{check-circle}** Yes | String | `HIGH`, `MEDIUM`, `LOW` |
-| [`bandit`](https://gitlab.com/gitlab-org/security-products/analyzers/bandit) | **{check-circle}** Yes | String | `HIGH`, `MEDIUM`, `LOW` |
| [`phpcs-security-audit`](https://gitlab.com/gitlab-org/security-products/analyzers/phpcs-security-audit) | **{check-circle}** Yes | String | `ERROR`, `WARNING` |
| [`pmd-apex`](https://gitlab.com/gitlab-org/security-products/analyzers/pmd-apex) | **{check-circle}** Yes | Integer | `1`, `2`, `3`, `4`, `5` |
| [`kubesec`](https://gitlab.com/gitlab-org/security-products/analyzers/kubesec) | **{check-circle}** Yes | String | `CriticalSeverity`, `InfoSeverity` |
| [`secrets`](https://gitlab.com/gitlab-org/security-products/analyzers/secrets) | **{check-circle}** Yes | Not applicable | Hardcodes all severity levels to `Critical` |
| [`semgrep`](https://gitlab.com/gitlab-org/security-products/analyzers/semgrep) | **{check-circle}** Yes | String | `error`, `warning`, `note`, `none` |
+| [`kics`](https://gitlab.com/gitlab-org/security-products/analyzers/kics) | **{check-circle}** Yes | String | `error`, `warning`, `note`, `none` (gets mapped to `info` in [analyzer version 3.7.0 and later](https://gitlab.com/gitlab-org/security-products/analyzers/kics/-/releases/v3.7.0)) |
## Dependency Scanning
diff --git a/doc/user/application_security/vulnerability_report/index.md b/doc/user/application_security/vulnerability_report/index.md
index 59851fd192c..2b78dde4f63 100644
--- a/doc/user/application_security/vulnerability_report/index.md
+++ b/doc/user/application_security/vulnerability_report/index.md
@@ -216,6 +216,10 @@ Fields included are:
- [CVE](https://cve.mitre.org/) (Common Vulnerabilities and Exposures)
- [CWE](https://cwe.mitre.org/) (Common Weakness Enumeration)
- Other identifiers
+- Detected At
+- Location
+- Activity
+- Comments
NOTE:
Full details are available through our
diff --git a/doc/user/award_emojis.md b/doc/user/award_emojis.md
index d0aa9fa6119..5df38550c40 100644
--- a/doc/user/award_emojis.md
+++ b/doc/user/award_emojis.md
@@ -4,23 +4,23 @@ 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
---
-# Award emoji **(FREE)**
+# Award emojis **(FREE)**
When you're collaborating online, you get fewer opportunities for high-fives
-and thumbs-ups. Emoji can be awarded to [issues](project/issues/index.md), [merge requests](project/merge_requests/index.md),
+and thumbs-ups. Emojis can be awarded to [issues](project/issues/index.md), [merge requests](project/merge_requests/index.md),
[snippets](snippets.md), and anywhere you can have a thread.
![Award emoji](img/award_emoji_select_v14_6.png)
-Award emoji make it much easier to give and receive feedback without a long
+Award emojis make it much easier to give and receive feedback without a long
comment thread.
For information on the relevant API, see [Award Emoji API](../api/award_emoji.md).
## Sort issues and merge requests on vote count
-You can quickly sort issues and merge requests by the number of votes they
-have received. The sort options can be found in the dropdown menu as "Most
+You can quickly sort issues and merge requests by the number of votes ("thumbs up" and "thumbs down" emoji) they
+have received. The sort options can be found in the dropdown list as "Most
popular" and "Least popular".
![Votes sort options](img/award_emoji_votes_sort_options.png)
@@ -29,9 +29,9 @@ The total number of votes is not summed up. An issue with 18 upvotes and 5
downvotes is considered more popular than an issue with 17 upvotes and no
downvotes.
-## Award emoji for comments
+## Award emojis for comments
-Award emoji can also be applied to individual comments when you want to
+Award emojis can also be applied to individual comments when you want to
celebrate an accomplishment or agree with an opinion.
To add an award emoji:
@@ -40,3 +40,15 @@ To add an award emoji:
1. Select an emoji from the dropdown list.
To remove an award emoji, select the emoji again.
+
+## Custom emojis
+
+You can upload custom emojis to a GitLab instance with the GraphQL API.
+For more, visit [Use custom emojis with GraphQL](../api/graphql/custom_emoji.md).
+
+Custom emojis don't show in the emoji picker.
+To use them in a text box, type the filename without the extension and surrounded by colons.
+For example, for a file named `thank-you.png`, type `:thank-you:`.
+
+For the list of custom emojis available for GitLab.com, visit
+[the `custom_emoji` project](https://gitlab.com/custom_emoji/custom_emoji/-/tree/main/img).
diff --git a/doc/user/clusters/agent/ci_cd_workflow.md b/doc/user/clusters/agent/ci_cd_workflow.md
index 7a3c09687a5..454be3c53c7 100644
--- a/doc/user/clusters/agent/ci_cd_workflow.md
+++ b/doc/user/clusters/agent/ci_cd_workflow.md
@@ -58,7 +58,8 @@ Authorization configuration can take one or two minutes to propagate.
### Authorize the agent to access your projects
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/327850) in GitLab 14.4.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/327850) in GitLab 14.4.
+> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/346566) to remove hierarchy restrictions in GitLab 15.6.
To authorize the agent to access the GitLab project where you keep Kubernetes manifests:
@@ -72,7 +73,7 @@ To authorize the agent to access the GitLab project where you keep Kubernetes ma
- id: path/to/project
```
- - The Kubernetes projects must be in the same group hierarchy as the project where the agent's configuration is.
+ - Authorized projects must have the same root group as the agent's configuration project.
- You can install additional agents into the same cluster to accommodate additional hierarchies.
- You can authorize up to 100 projects.
@@ -81,7 +82,8 @@ Choose the context to run `kubectl` commands from your CI/CD scripts.
### Authorize the agent to access projects in your groups
-> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5784) in GitLab 14.3.
+> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5784) in GitLab 14.3.
+> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/346566) to remove hierarchy restrictions in GitLab 15.6.
To authorize the agent to access all of the GitLab projects in a group or subgroup:
@@ -95,7 +97,7 @@ To authorize the agent to access all of the GitLab projects in a group or subgro
- id: path/to/group/subgroup
```
- - The Kubernetes projects must be in the same group hierarchy as the project where the agent's configuration is.
+ - Authorized groups must have the same root group as the agent's configuration project.
- You can install additional agents into the same cluster to accommodate additional hierarchies.
- All of the subgroups of an authorized group also have access to the same agent (without being specified individually).
- You can authorize up to 100 groups.
@@ -125,6 +127,30 @@ deploy:
If you are not sure what your agent's context is, open a terminal and connect to your cluster.
Run `kubectl config get-contexts`.
+### Environments that use Auto DevOps
+
+If Auto DevOps is enabled, you must define the CI/CD variable `KUBE_CONTEXT`.
+Set the value of `KUBE_CONTEXT` to the context of the agent you want Auto DevOps to use:
+
+```yaml
+deploy:
+ variables:
+ KUBE_CONTEXT: <path_to_agent_config_repository>:<agent_name>
+```
+
+You can assign different agents to separate Auto DevOps jobs. For instance,
+Auto DevOps can use one agent for `staging` jobs, and another agent for `production` jobs.
+To use multiple agents, define an [environment-scoped CI/CD variable](../../../ci/variables/index.md#limit-the-environment-scope-of-a-cicd-variable)
+for each agent. For example:
+
+1. Define two variables named `KUBE_CONTEXT`.
+1. For the first variable:
+ 1. Set the `environment` to `staging`.
+ 1. Set the value to the context of your staging agent.
+1. For the second variable:
+ 1. Set the `environment` to `production`.
+ 1. Set the value to the context of your production agent.
+
### Environments with both certificate-based and agent-based connections
When you deploy to an environment that has both a
@@ -156,20 +182,6 @@ deploy:
# ... rest of your job configuration
```
-### Using the agent with Auto DevOps
-
-If Auto DevOps is enabled, you must define the `KUBE_CONTEXT` CI/CD variable. Set the value of `KUBE_CONTEXT` to the context of the agent you want to use in your Auto DevOps pipeline jobs (`<PATH_TO_AGENT_CONFIG_REPOSITORY>:<AGENT_NAME>`).
-
-You can also use different agents for different Auto DevOps jobs. For instance, you can use one agent for `staging` jobs and a different agent for `production` jobs. To use multiple agents, define a unique CI/CD variable for each agent.
-
-For example:
-
-1. Add two [environment-scoped CI/CD variables](../../../ci/variables/index.md#limit-the-environment-scope-of-a-cicd-variable) and name both `KUBE_CONTEXT`.
-1. Set the `environment` of the first variable to `staging`. Set the value of the variable to `<PATH_TO_AGENT_CONFIGURATION_PROJECT>:<STAGING_AGENT_NAME>`.
-1. Set the `environment` of the second variable to `production`. Set the value of the variable to `<PATH_TO_AGENT_CONFIGURATION_PROJECT>:<PRODUCTION_AGENT_NAME>`.
-
-When the `staging` job runs, it will connect to the cluster via the agent named `<STAGING_AGENT_NAME>`, and when the `production` job runs it will connect to the cluster via the agent named `<PRODUCTION_AGENT_NAME>`.
-
## Restrict project and group access by using impersonation **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345014) in GitLab 14.5.
@@ -281,13 +293,6 @@ See the [official Kubernetes documentation for details](https://kubernetes.io/do
## Troubleshooting
-### `kubectl` commands not supported
-
-The commands `kubectl exec`, `kubectl cp`, `kubectl attach`, `kubectl run --attach=true` and `kubectl port-forward` are not supported.
-Anything that uses these API endpoints does not work, because they use the deprecated
-SPDY protocol.
-[An issue exists](https://gitlab.com/gitlab-org/gitlab/-/issues/346248) to add support for these commands.
-
### Grant write permissions to `~/.kube/cache`
Tools like `kubectl`, Helm, `kpt`, and `kustomize` cache information about
diff --git a/doc/user/clusters/agent/gitops/helm.md b/doc/user/clusters/agent/gitops/helm.md
index af9f80618b5..0ec87376636 100644
--- a/doc/user/clusters/agent/gitops/helm.md
+++ b/doc/user/clusters/agent/gitops/helm.md
@@ -54,16 +54,50 @@ gitops:
path: dir-in-project/with/charts
namespace: my-ns
max_history: 1
+ values:
+ - inline:
+ someKey: example value
```
| Keyword | Description |
|--|--|
| `charts` | List of charts you want to be applied in your cluster. Charts are applied concurrently. |
| `release_name` | Required. Name of the release to use when applying the chart. |
-| `id` | Required. ID of the project where Helm chart is committed. No authentication mechanisms are currently supported. |
-| `path` | Optional. Path of the chart in the project repository. Root of the repository is used by default. This is the directory with the `Chart.yaml` file. |
+| `values` | Optional. [Custom values](#custom-values) for the release. An array of objects. Only supports `inline` values. |
| `namespace` | Optional. Namespace to use when applying the chart. Defaults to `default`. |
| `max_history` | Optional. Maximum number of release [revisions to store in the cluster](https://helm.sh/docs/helm/helm_history/). |
+| `source` | Required. From where the chart should get installed. Only supports project sources. |
+| `source.project.id` | Required. ID of the project where Helm chart is committed. Authentication is not supported. |
+| `source.project.path` | Optional. Path of the chart in the project repository. Root of the repository is used by default. Should be the directory with the `Chart.yaml` file. |
+
+## Custom values
+
+> [Introduced](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/merge_requests/766) in GitLab 15.6. Requires both GitLab and the installed agent to be version 15.6 or later.
+
+To customize the values for a release, set the `values` key. It must be
+an array of objects. Each object must have exactly one top-level key that describes
+where the values come from. The supported top-level keys are:
+
+- `inline`: Specify the values inline in YAML format, similar to a Helm values
+ file.
+
+When installing a chart with custom values:
+
+- Custom values get merged on top of the chart's default `values.yaml` file.
+- Values from subsequent entries in the `values` array overwrite values from
+ previous entries.
+
+Example:
+
+```yaml
+gitops:
+ charts:
+ - release_name: some-release
+ values:
+ - inline:
+ someKey: example value
+ # ...
+```
## Automatic drift remediation
@@ -98,7 +132,7 @@ The following are known issues:
[this epic](https://gitlab.com/groups/gitlab-org/-/epics/7704).
- Values for the chart must be in a `values.yaml` file. This file must be with the chart,
in the same project and path.
-- Because of drift detection and remediation, release history, stored in the cluster, is not useful.
+- Because of drift detection and remediation, the release history stored in the cluster is not useful.
A new release is created every five minutes and the oldest release is discarded.
Eventually history consists only of the same information.
View [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/372023) for details.
diff --git a/doc/user/clusters/agent/index.md b/doc/user/clusters/agent/index.md
index 7fdf0bb2bf0..8f4855a7f93 100644
--- a/doc/user/clusters/agent/index.md
+++ b/doc/user/clusters/agent/index.md
@@ -69,14 +69,15 @@ This workflow has a weaker security model and is not recommended for production
GitLab supports the following Kubernetes versions. You can upgrade your
Kubernetes version to a supported version at any time:
-- 1.24 (support ends on September 22, 2023 or when 1.27 becomes supported)
+- 1.25 (support ends on October 22, 2023 or when 1.28 becomes supported)
+- 1.24 (support ends on July 22, 2023 or when 1.27 becomes supported)
- 1.23 (support ends on February 22, 2023 or when 1.26 becomes supported)
-- 1.22 (support ends on October 22, 2022)
-- 1.21 (support ends on August 22, 2022)
GitLab aims to support a new minor Kubernetes version three months after its initial release. GitLab supports at least three production-ready Kubernetes minor
versions at any given time.
+When installing the agent, use a Helm version compatible with your Kubernetes version. Other versions of Helm might not work. For a list of compatible versions, see the [Helm version support policy](https://helm.sh/docs/topics/version_skew/).
+
Support for deprecated APIs can be removed from the GitLab codebase when we drop support for the Kubernetes version that only supports the deprecated API.
Some GitLab features might work on versions not listed here. [This epic](https://gitlab.com/groups/gitlab-org/-/epics/4827) tracks support for Kubernetes versions.
diff --git a/doc/user/clusters/agent/install/index.md b/doc/user/clusters/agent/install/index.md
index 19628419784..2030052e3b0 100644
--- a/doc/user/clusters/agent/install/index.md
+++ b/doc/user/clusters/agent/install/index.md
@@ -45,6 +45,8 @@ For configuration settings, the agent uses a YAML file in the GitLab project. Yo
- You use [a GitOps workflow](../gitops.md#gitops-workflow-steps).
- You use [a GitLab CI/CD workflow](../ci_cd_workflow.md#gitlab-cicd-workflow-steps) and want to authorize a different project to use the agent.
+Otherwise it is optional.
+
To create an agent configuration file:
1. Choose a name for your agent. The agent name follows the
@@ -90,7 +92,7 @@ You must register an agent before you can install the agent in your cluster. To
- If you already have an [agent configuration file](#create-an-agent-configuration-file), select it from the list.
1. Select **Register an agent**.
1. GitLab generates an access token for the agent. You need this token to install the agent
- in your cluster and to [update the agent](#update-the-agent-version) to another version.
+ in your cluster.
WARNING:
Securely store the agent access token. A bad actor can use this token to access source code in the agent's configuration project, access source code in any public project on the GitLab instance, or even, under very specific conditions, obtain a Kubernetes manifest.
diff --git a/doc/user/clusters/agent/troubleshooting.md b/doc/user/clusters/agent/troubleshooting.md
index 0c26c533cc3..6b5f58f8f76 100644
--- a/doc/user/clusters/agent/troubleshooting.md
+++ b/doc/user/clusters/agent/troubleshooting.md
@@ -208,3 +208,24 @@ kubectl delete jobs -l app.kubernetes.io/managed-by=starboard -n gitlab-agent
```
[We're working on making the cleanup of these jobs more robust.](https://gitlab.com/gitlab-org/gitlab/-/issues/362016)
+
+## Inventory policy prevented actuation (strategy: Apply, status: Empty, policy: MustMatch)
+
+```json
+{
+ "error":"inventory policy prevented actuation (strategy: Apply, status: Empty, policy: MustMatch)",
+ "group":"networking.k8s.io",
+ "kind":"Deployment",
+ "name":"resource-name",
+ "namespace":"namespace",
+ "status":"Skipped",
+ "timestamp":"2022-10-29T15:34:21Z",
+ "type":"apply"
+}
+```
+
+This error occurs when the GitLab agent tries to update an object and the object doesn't have the required annotations. To fix this error, you can:
+
+- Add the required annotations manually.
+- Delete the object and let the agent recreate it.
+- Change your [`inventory_policy`](../../infrastructure/clusters/deploy/inventory_object.md#inventory_policy-options) setting.
diff --git a/doc/user/clusters/management_project.md b/doc/user/clusters/management_project.md
index df338e8fcee..18317ae09ed 100644
--- a/doc/user/clusters/management_project.md
+++ b/doc/user/clusters/management_project.md
@@ -63,7 +63,7 @@ To associate a cluster management project with your cluster:
page.
- [Instance-level cluster](../instance/clusters/index.md), on the top bar, select **Main menu > Admin > Kubernetes**.
1. Expand **Advanced settings**.
-1. From the **Cluster management project** dropdown, select the cluster management project
+1. From the **Cluster management project** dropdown list, select the cluster management project
you created in the previous step.
### Configuring your pipeline
diff --git a/doc/user/clusters/management_project_template.md b/doc/user/clusters/management_project_template.md
index bdd11f11f9c..cbe577b9b74 100644
--- a/doc/user/clusters/management_project_template.md
+++ b/doc/user/clusters/management_project_template.md
@@ -103,7 +103,6 @@ The [built-in supported applications](https://gitlab.com/gitlab-org/project-temp
- [GitLab Runner](../infrastructure/clusters/manage/management_project_applications/runner.md)
- [Ingress](../infrastructure/clusters/manage/management_project_applications/ingress.md)
- [Prometheus](../infrastructure/clusters/manage/management_project_applications/prometheus.md)
-- [Sentry](../infrastructure/clusters/manage/management_project_applications/sentry.md)
- [Vault](../infrastructure/clusters/manage/management_project_applications/vault.md)
Each application has an `applications/{app}/values.yaml` file.
diff --git a/doc/user/compliance/compliance_report/index.md b/doc/user/compliance/compliance_report/index.md
index ac4b20b5166..0d33dfce30b 100644
--- a/doc/user/compliance/compliance_report/index.md
+++ b/doc/user/compliance/compliance_report/index.md
@@ -94,9 +94,7 @@ Our criteria for the separation of duties is as follows:
> - [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.
-
-FLAG:
-On self-managed GitLab, by default sending Chain of Custody reports through email is not available. To make it available, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `async_chain_of_custody_report`. On GitLab.com, this feature is not available.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/370100) in GitLab 15.5. Feature flag `async_chain_of_custody_report` removed.
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,
@@ -112,7 +110,7 @@ To generate the Chain of Custody report:
The Chain of Custody report is either:
- Available for download.
-- Sent through email. Requires GitLab 15.3 and later with `async_chain_of_custody_report` feature flag enabled.
+- Sent through email. Requires GitLab 15.5 and later.
### Commit-specific Chain of Custody report
@@ -131,7 +129,7 @@ Authenticated group owners can generate a commit-specific Chain of Custody repor
The Chain of Custody report is either:
- Available for download.
-- Sent through email. Requires GitLab 15.3 and later with `async_chain_of_custody_report` feature flag enabled.
+- Sent through email. Requires GitLab 15.5 and later.
- 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.
diff --git a/doc/user/crm/index.md b/doc/user/crm/index.md
index d7ab2195e2d..2d1aeaa1c07 100644
--- a/doc/user/crm/index.md
+++ b/doc/user/crm/index.md
@@ -79,6 +79,21 @@ To edit an existing contact:
You can also [edit](../../api/graphql/reference/index.md#mutationcustomerrelationscontactupdate)
contacts using the GraphQL API.
+#### Change the state of a contact
+
+Each contact can be in one of two states:
+
+- **Active**: contacts in this state can be added to an issue.
+- **Inactive**: contacts in this state cannot be added to an issue.
+
+To change the state of a contact:
+
+1. On the top bar, select **Main menu > Groups** and find your group.
+1. On the left sidebar, select **Customer relations > Contacts**.
+1. Next to the contact you wish to edit, select **Edit** (**{pencil}**).
+1. Select or clear the **Active** checkbox.
+1. Select **Save changes**.
+
## Organizations
### View organizations
@@ -153,7 +168,7 @@ API.
### Add contacts to an issue
-To add contacts to an issue use the `/add_contacts [contact:address@example.com]`
+To add [active](#change-the-state-of-a-contact) contacts to an issue use the `/add_contacts [contact:address@example.com]`
[quick action](../project/quick_actions.md).
You can also add, remove, or replace issue contacts using the
@@ -175,10 +190,15 @@ API.
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/352123) in GitLab 15.0.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/352123) in GitLab 15.2. [Feature flag `contacts_autocomplete`](https://gitlab.com/gitlab-org/gitlab/-/issues/352123) removed.
-When you use the `/add_contacts` or `/remove_contacts` quick actions, follow them with `[contact:` and an autocomplete list appears:
+When you use the `/add_contacts` quick action, follow it with `[contact:` and an autocomplete list with the [active](#change-the-state-of-a-contact) contacts appears:
```plaintext
/add_contacts [contact:
+```
+
+When you use the `/remove_contacts` quick action, follow it with `[contact:` and an autocomplete list with the contacts added to the issue appears:
+
+```plaintext
/remove_contacts [contact:
```
diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md
index 13d5b27ad41..d9cacb6395d 100644
--- a/doc/user/discussions/index.md
+++ b/doc/user/discussions/index.md
@@ -44,8 +44,9 @@ You can quickly see which comments involve you, because
mentions for yourself (the user currently signed in) are highlighted
in a different color.
-Avoid mentioning `@all` in issues and merge requests, because it sends an email notification
-to all the members of that project's group. This might be interpreted as spam.
+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.
Notifications and mentions can be disabled in
[a group's settings](../group/manage.md#disable-email-notifications).
@@ -77,7 +78,7 @@ To add a commit diff comment:
You can select multiple lines by dragging the **Comment** (**{comment}**) icon.
1. Enter your comment and select **Start a review** or **Add comment now**.
-The comment is displayed on the merge request's **Discussions** tab.
+The comment is displayed on the merge request's **Overview** tab.
The comment is not displayed on your project's **Repository > Commits** page.
@@ -143,7 +144,7 @@ If you edit an existing comment to add a user mention that wasn't there before,
- Creates a to-do item for the mentioned user.
- Does not send a notification email.
-## Prevent comments by locking an issue
+## Prevent comments by locking the discussion
You can prevent public comments in an issue or merge request.
When you do, only project members can add and edit comments.
@@ -153,6 +154,8 @@ Prerequisite:
- In merge requests, you must have at least the Developer role.
- In issues, you must have at least the Reporter role.
+To lock an issue or merge request:
+
1. On the right sidebar, next to **Lock issue** or **Lock merge request**, select **Edit**.
1. On the confirmation dialog, select **Lock**.
@@ -160,6 +163,9 @@ Notes are added to the page details.
If an issue or merge request is locked and closed, you cannot reopen it.
+<!-- Delete when the `moved_mr_sidebar` feature flag is removed -->
+If you don't see this action on the right sidebar, your project or instance might have [moved sidebar actions](../project/merge_requests/index.md#move-sidebar-actions) enabled.
+
## Add an internal note
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/207473) in GitLab 13.9 [with a flag](../../administration/feature_flags.md) named `confidential_notes`. Disabled by default.
@@ -167,12 +173,9 @@ If an issue or merge request is locked and closed, you cannot reopen it.
> - [Renamed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87403) from "confidential comments" to "internal notes" in GitLab 15.0.
> - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87383) in GitLab 15.0.
> - [Feature flag `confidential_notes`](https://gitlab.com/gitlab-org/gitlab/-/issues/362712) removed in GitLab 15.2.
+> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/363045) permissions in GitLab 15.5 to at least the Reporter role. In GitLab 15.4 and earlier, issue or epic authors and assignees could also read and create internal notes.
-You can add an internal note **to an issue or an epic**. It's then visible only to the following people:
-
-- Project members who have at least the Reporter role
-- Issue or epic author
-- Users assigned to the issue or epic
+You can add an internal note **to an issue or an epic**. It's then visible only to project members who have at least the Reporter role.
Keep in mind:
@@ -181,10 +184,7 @@ Keep in mind:
Prerequisites:
-- You must either:
- - Have at least the Reporter role for the project.
- - Be the issue or epic assignee.
- - Be the issue or epic author.
+- You must have at least the Reporter role for the project.
To add an internal note:
@@ -200,14 +200,14 @@ You can also mark an [issue as confidential](../project/issues/confidential_issu
For issues and merge requests with many comments, you can filter the page to show comments only.
-1. Open a merge request's **Discussion** tab, or epic or issue's **Overview** tab.
+1. Open the **Overview** tab in a merge request, issue, or epic.
1. On the right side of the page, select from the 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 options](img/index_notes_filters.png)
+![Notes filters dropdown list options](img/index_notes_filters.png)
GitLab saves your preference, so it persists when you visit the same page again
from any device you're logged into.
diff --git a/doc/user/feature_highlight.md b/doc/user/feature_highlight.md
deleted file mode 100644
index ef96d2524a6..00000000000
--- a/doc/user/feature_highlight.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-redirect_to: 'index.md'
-remove_date: '2022-10-29'
----
-
-This document was moved to [another location](index.md).
-
-<!-- This redirect file can be deleted after <2022-10-29>. -->
-<!-- Redirects that point to other docs in the same project expire in three months. -->
-<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. -->
-<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
diff --git a/doc/user/free_user_limit.md b/doc/user/free_user_limit.md
index 3fbfb2e1aa7..35777847947 100644
--- a/doc/user/free_user_limit.md
+++ b/doc/user/free_user_limit.md
@@ -29,6 +29,34 @@ If you need more time to manage your members, or to try GitLab features
with a team of more than five members, you can [start a trial](https://gitlab.com/-/trial_registrations/new?glm_source=docs.gitlab.com&glm_content=free-user-limit).
A trial lasts for 30 days and includes an unlimited number of members.
+## Determining namespace user counts
+
+Every unique user of a top-level namespace with private visibility counts towards the five-user limit. This includes every user of a group, subgroup, and project within a namespace.
+
+For example:
+
+The group `example-1` has:
+
+- One group owner, `A`.
+- One subgroup called `subgroup-1` with one member, `B`.
+ - `subgroup-1` inherits `A` as a member from `example-1`.
+- One project in `subgroup-1` called `project-1` with two members, `C` and `D`.
+ - `project-1` inherits `A` and `B` as members from `subgroup-1`.
+
+The namespace `example-1` has four unique members: `A`, `B`, `C`, and `D`. Because `example-1` has only four unique members, it is not impacted by the five-user limit.
+
+The group `example-2` has:
+
+- One group owner, `A`.
+- One subgroup called `subgroup-2` with one member, `B`.
+ - `subgroup-2` inherits `A` as a member from `example-2`.
+- One project in `subgroup-2` called `project-2a` with two members, `C` and `D`.
+ - `project-2a` inherits `A` and `B` as members from `subgroup-2`.
+- One project in `subgroup-2` called `project-2b` with two members, `E` and `F`.
+ - `project-2b` inherits `A` and `B` as members from `subgroup-2`.
+
+The namespace `example-2` has six unique members: `A`, `B`, `C`, `D`, `E`, and `F`. Because `example-2` has six unique users, it is impacted by the five-user limit.
+
## Related topics
- [GitLab SaaS Free tier frequently asked questions](https://about.gitlab.com/pricing/faq-efficient-free-tier/)
diff --git a/doc/user/group/access_and_permissions.md b/doc/user/group/access_and_permissions.md
index 395ed3c91c7..13a1fd31ee4 100644
--- a/doc/user/group/access_and_permissions.md
+++ b/doc/user/group/access_and_permissions.md
@@ -56,18 +56,20 @@ To change the permitted Git access protocols for a group:
1. Choose the permitted protocols from **Enabled Git access protocols**.
1. Select **Save changes**.
-## Restrict group access by IP address **(PREMIUM)**
+## Restrict access to groups by IP address **(PREMIUM)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1985) in GitLab 12.0.
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/215410) from GitLab Ultimate to GitLab Premium in 13.1.
-To ensure only people from your organization can access particular
-resources, you can restrict access to groups by IP address. This group-level setting
-applies to:
+To ensure only people from your organization can access particular resources, you can restrict access to groups by IP
+address. This group-level setting applies to:
- The GitLab UI, including subgroups, projects, and issues.
- [In GitLab 12.3 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/12874), the API.
+Administrators can combine restricted access by IP address with
+[globally-allowed IP addresses](../admin_area/settings/visibility_and_access_controls.md#configure-globally-allowed-ip-address-ranges).
+
### Security implications
You should consider some security implications before configuring IP address restrictions.
@@ -94,7 +96,12 @@ To restrict group access by IP address:
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **Settings > General**.
1. Expand the **Permissions and group features** section.
-1. In the **Restrict access by IP address** field, enter IPv4 or IPv6 address ranges in CIDR notation.
+1. In the **Restrict access by IP address** field, enter a list of IPv4 or IPv6
+ address ranges in CIDR notation. This list:
+ - Has no limit on the number of IP address ranges.
+ - Has a size limit of 1 GB.
+ - Applies to both SSH or HTTP authorized IP address ranges. You cannot split
+ this list by type of authorization.
1. Select **Save changes**.
In self-managed installations of GitLab 15.1 and later, you can also configure
@@ -290,5 +297,4 @@ If a user sees a 404 when they would normally expect access, and the problem is
- `json.message`: `'Attempting to access IP restricted group'`
- `json.allowed`: `false`
-In viewing the log entries, compare the `remote.ip` with the list of
-[allowed IPs](#restrict-group-access-by-ip-address) for the group.
+In viewing the log entries, compare the `remote.ip` with the list of [allowed IP addresses](#restrict-access-to-groups-by-ip-address) for the group.
diff --git a/doc/user/group/clusters/index.md b/doc/user/group/clusters/index.md
index c6cc828302f..62f5a3ba54f 100644
--- a/doc/user/group/clusters/index.md
+++ b/doc/user/group/clusters/index.md
@@ -187,6 +187,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/group/compliance_frameworks.md b/doc/user/group/compliance_frameworks.md
new file mode 100644
index 00000000000..7bd545003db
--- /dev/null
+++ b/doc/user/group/compliance_frameworks.md
@@ -0,0 +1,262 @@
+---
+stage: Govern
+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 frameworks **(PREMIUM)**
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276221) in GitLab 13.9.
+> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/287779) in GitLab 13.12.
+
+You can create a compliance framework that is a label to identify that your project has certain compliance
+requirements or needs additional oversight. The label can optionally enforce
+[compliance pipeline configuration](#configure-a-compliance-pipeline) to the projects on which it is
+[applied](../project/settings/index.md#add-a-compliance-framework-to-a-project).
+
+Group owners can create, edit, and delete compliance frameworks:
+
+1. On the top bar, select **Main menu > Groups > View all groups** and find your group.
+1. On the left sidebar, select **Settings** > **General**.
+1. Expand the **Compliance frameworks** section.
+1. Create, edit, or delete compliance frameworks.
+
+## Set a default compliance framework
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/375036) in GitLab 15.6.
+
+Group owners can set a default compliance framework. The default framework is applied to all the new projects
+that are created within that group. It does not affect the framework applied to the existing projects. The default
+framework cannot be deleted.
+
+### Example GraphQL mutations for setting a default compliance framework
+
+Creating a new compliance framework and setting it as the default framework for the group.
+
+```graphql
+mutation {
+ createComplianceFramework(
+ input: {params: {name: "SOX", description: "Sarbanes-Oxley Act", color: "#87CEEB", default: true}, namespacePath: "gitlab-org"}
+ ) {
+ framework {
+ id
+ name
+ default
+ description
+ color
+ pipelineConfigurationFullPath
+ }
+ errors
+ }
+}
+```
+
+Setting an existing compliance framework as the default framework the group.
+
+```graphql
+mutation {
+ updateComplianceFramework(
+ input: {id: "gid://gitlab/ComplianceManagement::Framework/<id>", params: {default: true}}
+ ) {
+ complianceFramework {
+ id
+ name
+ default
+ description
+ color
+ pipelineConfigurationFullPath
+ }
+ }
+}
+```
+
+## Configure a compliance pipeline **(ULTIMATE)**
+
+> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3156) in GitLab 13.9, disabled behind `ff_evaluate_group_level_compliance_pipeline` [feature flag](../../administration/feature_flags.md).
+> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/300324) in GitLab 13.11.
+> - [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.
+
+However, the compliance pipeline configuration can reference the `.gitlab-ci.yml` file of the labeled projects so that:
+
+- The compliance pipeline can also run jobs of labeled project pipelines. This allows for centralized control of
+ pipeline configuration.
+- Jobs and variables defined in the compliance pipeline can't be changed by variables in the labeled project's
+ `.gitlab-ci.yml` file.
+
+See [example configuration](#example-configuration) for help configuring a compliance pipeline that runs jobs from
+labeled project pipeline configuration.
+
+To configure a compliance pipeline:
+
+1. On the top bar, select **Main menu > Groups > View all groups** and find your group.
+1. On the left sidebar, select **Settings** > **General**.
+1. Expand the **Compliance frameworks** section.
+1. In **Compliance pipeline configuration (optional)**, add the path to the compliance framework configuration. Use the
+ `path/file.y[a]ml@group-name/project-name` format. For example:
+
+ - `.compliance-ci.yml@gitlab-org/gitlab`.
+ - `.compliance-ci.yaml@gitlab-org/gitlab`.
+
+This configuration is inherited by projects where the compliance framework label is
+[applied](../project/settings/index.md#add-a-compliance-framework-to-a-project). In projects with the applied compliance
+framework label, the compliance pipeline configuration is run instead of the labeled project's own pipeline configuration.
+
+The user running the pipeline in the labeled project must at least have the Reporter role on the compliance project.
+
+When used to enforce scan execution, this feature has some overlap with
+[scan execution policies](../application_security/policies/scan-execution-policies.md). We have not
+[unified the user experience for these two features](https://gitlab.com/groups/gitlab-org/-/epics/7312). For details on
+the similarities and differences between these features, see [Enforce scan execution](../application_security/index.md#enforce-scan-execution).
+
+### Example configuration
+
+The following example `.compliance-gitlab-ci.yml` includes the `include` keyword to ensure labeled project pipeline
+configuration is also executed.
+
+```yaml
+# Allows compliance team to control the ordering and interweaving of stages/jobs.
+# Stages without jobs defined will remain hidden.
+stages:
+ - pre-compliance
+ - build
+ - test
+ - pre-deploy-compliance
+ - deploy
+ - post-compliance
+
+variables: # Can be overridden by setting a job-specific variable in project's local .gitlab-ci.yml
+ FOO: sast
+
+sast: # None of these attributes can be overridden by a project's local .gitlab-ci.yml
+ variables:
+ FOO: sast
+ image: ruby:2.6
+ stage: pre-compliance
+ rules:
+ - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
+ when: never
+ - when: always # or when: on_success
+ allow_failure: false
+ before_script:
+ - "# No before scripts."
+ script:
+ - echo "running $FOO"
+ after_script:
+ - "# No after scripts."
+
+sanity check:
+ image: ruby:2.6
+ stage: pre-deploy-compliance
+ rules:
+ - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
+ when: never
+ - when: always # or when: on_success
+ allow_failure: false
+ before_script:
+ - "# No before scripts."
+ script:
+ - echo "running $FOO"
+ after_script:
+ - "# No after scripts."
+
+audit trail:
+ image: ruby:2.7
+ stage: post-compliance
+ rules:
+ - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
+ when: never
+ - when: always # or when: on_success
+ allow_failure: false
+ before_script:
+ - "# No before scripts."
+ script:
+ - echo "running $FOO"
+ after_script:
+ - "# 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_REF_NAME' # Must be defined or MR pipelines always use the use default branch
+```
+
+#### CF pipelines in Merge Requests originating in project forks
+
+When an MR originates in a fork, the branch to be merged usually only exists in the fork.
+When creating such an MR against a project with CF pipelines, the above snippet will fail with a
+`Project <project-name> reference <branch-name> does not exist!` error message.
+This is because in the context of the target project, `$CI_COMMIT_REF_NAME` evaluates to a non-existing branch name.
+
+To get the correct context, use `$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH` instead of `$CI_PROJECT_PATH`.
+This variable is only availabe in
+[merge request pipelines](../../ci/pipelines/merge_request_pipelines.md).
+
+For example, for a configuration that supports both merge request pipelines originating in project forks and branch pipelines,
+you need to [combine both `include` directives with `rules:if`](../../ci/yaml/includes.md#use-rules-with-include):
+
+```yaml
+include: # Execute individual project's configuration (if project contains .gitlab-ci.yml)
+ - project: '$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH'
+ file: '$CI_CONFIG_PATH'
+ ref: '$CI_COMMIT_REF_NAME'
+ rules:
+ - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+ - project: '$CI_PROJECT_PATH'
+ file: '$CI_CONFIG_PATH'
+ ref: '$CI_COMMIT_REF_NAME'
+ rules:
+ - if: $CI_PIPELINE_SOURCE != 'merge_request_event'
+```
+
+## Ensure compliance jobs are always run
+
+Compliance pipelines [use GitLab CI/CD](../../ci/index.md) to give you an incredible amount of flexibility
+for defining any sort of compliance jobs you like. Depending on your goals, these jobs
+can be configured to be:
+
+- Modified by users.
+- Non-modifiable.
+
+Generally, if a value in a compliance job:
+
+- Is set, it cannot be changed or overridden by project-level configurations.
+- Is not set, a project-level configuration may set.
+
+Either might be wanted or not depending on your use case.
+
+There are a few best practices for ensuring that these jobs are always run exactly
+as you define them and that downstream, project-level pipeline configurations
+cannot change them:
+
+- Add [a `rules:when:always` block](../../ci/yaml/index.md#when) to each of your compliance jobs. This ensures they are
+ non-modifiable and are always run.
+- Explicitly set any [variables](../../ci/yaml/index.md#variables) the job references. This:
+ - Ensures that project-level pipeline configurations do not set them and alter their
+ behavior.
+ - Includes any jobs that drive the logic of your job.
+- Explicitly set the [container image](../../ci/yaml/index.md#image) to run the job in. This ensures that your script
+ steps execute in the correct environment.
+- Explicitly set any relevant GitLab pre-defined [job keywords](../../ci/yaml/index.md#job-keywords).
+ This ensures that your job uses the settings you intend and that they are not overridden by
+ project-level pipelines.
+
+## Avoid parent and child pipelines in GitLab 14.7 and earlier
+
+NOTE:
+This advice does not apply to GitLab 14.8 and later because [a fix](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78878) added
+compatibility for combining compliance pipelines, and parent and child pipelines.
+
+Compliance pipelines start on the run of _every_ pipeline in a labeled project. This means that if a pipeline in the labeled project
+triggers a child pipeline, the compliance pipeline runs first. This can trigger the parent pipeline, instead of the child pipeline.
+
+Therefore, in projects with compliance frameworks, we recommend replacing
+[parent-child pipelines](../../ci/pipelines/downstream_pipelines.md#parent-child-pipelines) with the following:
+
+- Direct [`include`](../../ci/yaml/index.md#include) statements that provide the parent pipeline with child pipeline configuration.
+- Child pipelines placed in another project that are run using the [trigger API](../../ci/triggers/index.md) rather than the parent-child
+ pipeline feature.
+
+This alternative ensures the compliance pipeline does not re-start the parent pipeline.
diff --git a/doc/user/group/contribution_analytics/index.md b/doc/user/group/contribution_analytics/index.md
index 280781a4cad..b1efd2e9251 100644
--- a/doc/user/group/contribution_analytics/index.md
+++ b/doc/user/group/contribution_analytics/index.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/3090) in GitLab 12.2 for subgroups.
-With Contribution Analytics, you can get an overview of the [contribution events](../../profile/index.md#user-contribution-events) in your
+With Contribution Analytics, you can get an overview of the [contribution events](../../profile/contributions_calendar.md#user-contribution-events) in your
group.
- Analyze your team's contributions over a period of time.
@@ -43,7 +43,7 @@ You can choose from the following three periods:
- Last month
- Last three months
-Select the desired period from the calendar dropdown.
+Select the desired period from the calendar dropdown list.
![Contribution analytics choose period](img/group_stats_cal.png)
@@ -62,6 +62,10 @@ Contributions per group member are also presented in tabular format. Select a co
![Contribution analytics contributions table](img/group_stats_table.png)
+## Contribution analytics GraphQL API
+
+To retrieve metrics for user contributions, use the [GraphQL](../../../api/graphql/reference/index.md#groupcontributions) API.
+
<!-- ## Troubleshooting
Include any troubleshooting steps that you can foresee. If you know beforehand what issues
@@ -70,6 +74,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/group/custom_project_templates.md b/doc/user/group/custom_project_templates.md
index 7f77c2147e1..547e64df7c5 100644
--- a/doc/user/group/custom_project_templates.md
+++ b/doc/user/group/custom_project_templates.md
@@ -78,6 +78,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/group/epics/epic_boards.md b/doc/user/group/epics/epic_boards.md
index 78cc65f1923..64addd524ad 100644
--- a/doc/user/group/epics/epic_boards.md
+++ b/doc/user/group/epics/epic_boards.md
@@ -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 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 with the current board name in the upper left corner of the epic boards page.
+1. Select the dropdown list with the current board name in the upper left corner of the epic boards page.
1. Select **Delete board**.
1. Select **Delete**.
@@ -80,7 +80,7 @@ To create a new list:
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-right corner, select **Create list**.
-1. In the **New list** column expand the **Select a label** dropdown and select the label to use as
+1. In the **New list** column expand the **Select a label** dropdown list and select the label to use as
list scope.
1. Select **Add to board**.
diff --git a/doc/user/group/epics/index.md b/doc/user/group/epics/index.md
index da6e675f0eb..21c95f37aeb 100644
--- a/doc/user/group/epics/index.md
+++ b/doc/user/group/epics/index.md
@@ -37,15 +37,9 @@ Also, read more about possible [planning hierarchies](../planning_hierarchy/inde
### Child issues from different group hierarchies
-<!-- When feature flag is removed, integrate this info as a sentence in
-https://docs.gitlab.com/ee/user/group/epics/manage_epics.html#add-an-existing-issue-to-an-epic -->
-
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/371081) in GitLab 15.5 [with a flag](../../../administration/feature_flags.md) named `epic_issues_from_different_hierarchies`. Disabled by default.
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/373304) in GitLab 15.5.
-
-FLAG:
-On self-managed GitLab, by default this feature is unavailable. To make it available, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `epic_issues_from_different_hierarchies`.
-On GitLab.com, this feature is available.
+> - Feature flag `epic_issues_from_different_hierarchies` removed in GitLab 15.6.
You can add issues from a different group hierarchy to an epic.
To do it, paste the issue URL when
@@ -77,6 +71,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/group/epics/manage_epics.md b/doc/user/group/epics/manage_epics.md
index 0a12f551588..61aa5c5fe02 100644
--- a/doc/user/group/epics/manage_epics.md
+++ b/doc/user/group/epics/manage_epics.md
@@ -24,8 +24,8 @@ To create an epic in the group you're in:
1. Get to the New Epic form:
- Go to your group and from the left sidebar select **Epics**. Then select **New epic**.
- - From an epic in your group, select **New epic**.
- - From anywhere, in the top menu, select **New...** (**{plus-square}**) **> New epic**.
+ - From an epic in your group, select the vertical ellipsis (**{ellipsis_v}**). Then select **New epic**.
+ - From anywhere, in the top menu, select **New...** (**{plus-square}**). Then select **New epic**.
- In an empty [roadmap](../roadmap/index.md), select **New epic**.
1. Enter a title.
@@ -257,7 +257,7 @@ To filter:
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **Epics**.
1. Select the field **Search or filter results**.
-1. From the dropdown menu, select the scope or enter plain text to search by epic title or description.
+1. From the dropdown list, select the scope or enter plain text to search by epic title or description.
1. Press <kbd>Enter</kbd> on your keyboard. The list is filtered.
## Sort the list of epics
@@ -282,10 +282,10 @@ You can reverse the default order and interact with the activity feed sorted by
at the top. Your preference is saved via local storage and automatically applied to every epic and issue
you view.
-To change the activity sort order, select the **Oldest first** dropdown menu and select either oldest
+To change the activity sort order, select the **Oldest first** dropdown list and select either oldest
or newest items to be shown first.
-![Issue activity sort order dropdown button](img/epic_activity_sort_order_v13_2.png)
+![Issue activity sort order dropdown list](img/epic_activity_sort_order_v13_2.png)
## Make an epic confidential
@@ -311,6 +311,8 @@ To make an epic confidential:
- **In an existing epic:** on the right sidebar, select **Edit** next to **Confidentiality**, and then
select **Turn on**.
+In GitLab 15.6 and later, you can also use the `/confidential` [quick action](../../../user/project/quick_actions.md).
+
## Manage issues assigned to an epic
This section collects instructions for all the things you can do with [issues](../../project/issues/index.md)
@@ -339,9 +341,8 @@ automatically added to the epic.
#### Add an existing issue to an epic
-You can add existing issues to an epic, including issues in a project in an epic's group, or any of
-the epic's subgroups. Newly added issues appear at the top of the list of
-issues in the **Epics and Issues** tab.
+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.
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
@@ -359,7 +360,8 @@ To add an existing issue to an epic:
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).
+ 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.
If there are multiple issues to be added, press <kbd>Space</kbd> and repeat this step.
1. Select **Add**.
@@ -486,9 +488,26 @@ New child epics appear at the top of the list of epics in the **Epics and Issues
When you add an epic that's already linked to a parent epic, the link to its current parent is removed.
-Epics can contain multiple nested child epics, up to a total of seven levels deep.
+Epics can contain multiple nested child epics, up to a total of 7 levels deep.
+
+The maximum number of direct child epics is 100.
+
+### Child epics from other groups
+
+> [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.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available per group, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `child_epics_from_different_hierarchies`.
+On GitLab.com, this feature is not available. The feature is not ready for production use.
+
+You can add a child epic that belongs to a group that is different from the parent epic's group.
-Maximum number of direct child epics is 100.
+Prerequisites:
+
+- You must have at least the Reporter role for both the child and parent epics' groups.
+- Multi-level child epics must be available for both the child and parent epics' groups.
+
+To add a child epic from another group, paste the epic's URL when [adding an existing epic](#add-a-child-epic-to-an-epic).
### Add a child epic to an epic
@@ -496,14 +515,19 @@ Prerequisites:
- You must have at least the Reporter role for the parent epic's group.
-To add a child epic to an epic:
+To add a new epic as child epic:
-1. Select **Add**.
-1. Select **Add a new 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. Enter a title for the new epic.
+1. Select **Create epic**.
+
+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 ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9126) in GitLab 12.5).
+ - 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.
If there are multiple epics to be added, press <kbd>Space</kbd> and repeat this step.
1. Select **Add**.
diff --git a/doc/user/group/import/index.md b/doc/user/group/import/index.md
index ee50cfcf182..6dcc01242c2 100644
--- a/doc/user/group/import/index.md
+++ b/doc/user/group/import/index.md
@@ -4,7 +4,7 @@ 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
---
-# Migrating groups **(FREE)**
+# Migrating groups with GitLab Migration **(FREE)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/249160) in GitLab 13.7 for group resources [with a flag](../../feature_flags.md) named `bulk_import`. Disabled by default.
> - Group items [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/338985) in GitLab 14.3.
@@ -18,15 +18,15 @@ this feature, ask an administrator to [enable the feature flag](../../../adminis
`bulk_import_projects`. On GitLab.com, migrating group resources is available but migrating project resources is not
available.
-Users with the Owner role on a top-level group can migrate it to:
+Users with the Owner role on a top-level group can use GitLab Migration to migrate the group to:
- Another top-level group.
- The subgroup of any existing top-level group.
- Another GitLab instance, including GitLab.com.
-Migrating groups using the method documented here is not the same as [migrating groups using file exports](../settings/import_export.md).
+Migrating groups using GitLab Migration is not the same as [migrating groups using file exports](../settings/import_export.md).
Importing and exporting groups using file exports requires you to export a group to a file and then import that file in
-another GitLab instance. Migrating groups using the method documented here automates this step.
+another GitLab instance. Migrating groups using GitLab Migration automates this step.
## Import your groups into GitLab
@@ -139,6 +139,7 @@ Migrating projects with file exports uses the same export and import mechanisms
- 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)
- 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)
@@ -148,6 +149,7 @@ Migrating projects with file exports uses the same export and import mechanisms
- 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)
- Migrate Push Rules ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/339403) in GitLab 14.6)
- Pull Requests (including 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)
diff --git a/doc/user/group/insights/index.md b/doc/user/group/insights/index.md
index b4bca919498..9eb6d4387c1 100644
--- a/doc/user/group/insights/index.md
+++ b/doc/user/group/insights/index.md
@@ -79,6 +79,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/group/issues_analytics/index.md b/doc/user/group/issues_analytics/index.md
index 4764625ff83..dbade014ec2 100644
--- a/doc/user/group/issues_analytics/index.md
+++ b/doc/user/group/issues_analytics/index.md
@@ -55,6 +55,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/group/iterations/index.md b/doc/user/group/iterations/index.md
index a6435ae2aa3..518370fc7ac 100644
--- a/doc/user/group/iterations/index.md
+++ b/doc/user/group/iterations/index.md
@@ -278,8 +278,8 @@ To group issues by label:
1. On the top bar, select **Main menu > Groups** and find your group.
1. On the left sidebar, select **Issues > Iterations**.
-1. In the **Group by** dropdown, select **Label**.
-1. Select the **Filter by label** dropdown.
-1. Select the labels you want to group by in the labels dropdown.
+1. In the **Group by** dropdown list, select **Label**.
+1. Select the **Filter by label** dropdown list.
+1. Select the labels you want to group by in the labels dropdown list.
You can also search for labels by typing in the search input.
1. Select any area outside the label dropdown list. The page is now grouped by the selected labels.
diff --git a/doc/user/group/manage.md b/doc/user/group/manage.md
index f11d9035a52..a63e6c6dd7f 100644
--- a/doc/user/group/manage.md
+++ b/doc/user/group/manage.md
@@ -66,6 +66,7 @@ This action removes the group. It also adds a background job to delete all proje
Specifically:
- In [GitLab 12.8 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/33257), on [GitLab Premium](https://about.gitlab.com/pricing/premium/) or higher tiers, this action adds a background job to mark a group for deletion. By default, the job schedules the deletion 7 days in the future. You can modify this waiting period through the [instance settings](../admin_area/settings/visibility_and_access_controls.md#deletion-protection).
+
- In [GitLab 13.6 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/39504), if the user who sets up the deletion is removed from the group before the
deletion happens, the job is cancelled, and the group is no longer scheduled for deletion.
@@ -201,6 +202,13 @@ To remove a member from a group:
- To unassign the user from linked issues and merge requests, select the **Also unassign this user from linked issues and merge requests** checkbox.
1. Select **Remove member**.
+## Ensure removed users cannot invite themselves back
+
+Malicious users with the Maintainer or Owner role could exploit a race condition that allows
+them to invite themselves back to a group or project that a GitLab administrator has removed them from.
+
+To avoid this problem, GitLab administrators can [ensure removed users cannot invite themselves back](../project/members/index.md#ensure-removed-users-cannot-invite-themselves-back).
+
## Add projects to a group
There are two different ways to add a new project to a group:
@@ -255,6 +263,12 @@ If you are changing the path so it can be claimed by another group or user,
you must rename the group too. Both names and paths must
be unique.
+After you change the group path, the new group path is a new namespace and you must update the existing project URL in the following resources:
+
+- [Include statements](../../ci/yaml/includes.md#include-a-single-configuration-file).
+- Docker image references in CI files.
+- Variables that specify a project or namespace.
+
To retain ownership of the original namespace and protect the URL redirects,
create a new group and transfer projects to it instead.
@@ -303,9 +317,7 @@ for the group's projects to meet your group's needs.
[Feature flag `invite_members_group_modal`](https://gitlab.com/gitlab-org/gitlab/-/issues/352526) removed.
Similar to how you [share a project with a group](../project/members/share_project_with_groups.md),
-you can share a group with another group. To invite a group, you must be a member of it. Members get direct access
-to the shared group. This includes members who inherited group membership from a parent group.
-
+you can share a group with another group. To invite a group, you must be a member of it.
To share a given group, for example, `Frontend` with another group, for example,
`Engineering`:
@@ -320,7 +332,7 @@ After sharing the `Frontend` group with the `Engineering` group:
- The **Groups** tab lists the `Engineering` group.
- The **Groups** tab lists a group regardless of whether it is a public or private group.
-- All members of the `Engineering` group have access to the `Frontend` group. The same access levels of the members apply up to the maximum access level selected when sharing the group.
+- All direct members of the `Engineering` group have access to the `Frontend` group. Direct members of `Engineering` that gain access to the `Frontend` group keep their same access level as in `Engineering`, but up to the maximum access level selected when sharing the group. Inherited members of the `Engineering` group do not gain access to the `Frontend` group.
## Transfer a group
@@ -385,214 +397,6 @@ To enable delayed deletion of projects in a group:
NOTE:
In GitLab 13.11 and above the group setting for delayed project deletion is inherited by subgroups. As discussed in [Cascading settings](../../development/cascading_settings.md) inheritance can be overridden, unless enforced by an ancestor.
-## Compliance frameworks **(PREMIUM)**
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276221) in GitLab 13.9.
-> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/287779) in GitLab 13.12.
-
-You can create a compliance framework that is a label to identify that your project has certain compliance
-requirements or needs additional oversight. The label can optionally enforce
-[compliance pipeline configuration](#configure-a-compliance-pipeline) to the projects on which it is
-[applied](../project/settings/index.md#add-a-compliance-framework-to-a-project).
-
-Group owners can create, edit, and delete compliance frameworks:
-
-1. On the top bar, select **Main menu > Groups > View all groups** and find your group.
-1. On the left sidebar, select **Settings** > **General**.
-1. Expand the **Compliance frameworks** section.
-1. Create, edit, or delete compliance frameworks.
-
-### Configure a compliance pipeline **(ULTIMATE)**
-
-> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/3156) in GitLab 13.9, disabled behind `ff_evaluate_group_level_compliance_pipeline` [feature flag](../../administration/feature_flags.md).
-> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/300324) in GitLab 13.11.
-> - [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.
-
-However, the compliance pipeline configuration can reference the `.gitlab-ci.yml` file of the labeled projects so that:
-
-- The compliance pipeline can also run jobs of labeled project pipelines. This allows for centralized control of
- pipeline configuration.
-- Jobs and variables defined in the compliance pipeline can't be changed by variables in the labeled project's
- `.gitlab-ci.yml` file.
-
-See [example configuration](#example-configuration) for help configuring a compliance pipeline that runs jobs from
-labeled project pipeline configuration.
-
-To configure a compliance pipeline:
-
-1. On the top bar, select **Main menu > Groups > View all groups** and find your group.
-1. On the left sidebar, select **Settings** > **General**.
-1. Expand the **Compliance frameworks** section.
-1. In **Compliance pipeline configuration (optional)**, add the path to the compliance framework configuration. Use the
- `path/file.y[a]ml@group-name/project-name` format. For example:
-
- - `.compliance-ci.yml@gitlab-org/gitlab`.
- - `.compliance-ci.yaml@gitlab-org/gitlab`.
-
-This configuration is inherited by projects where the compliance framework label is
-[applied](../project/settings/index.md#add-a-compliance-framework-to-a-project). In projects with the applied compliance
-framework label, the compliance pipeline configuration is run instead of the labeled project's own pipeline configuration.
-
-The user running the pipeline in the labeled project must at least have the Reporter role on the compliance project.
-
-When used to enforce scan execution, this feature has some overlap with
-[scan execution policies](../application_security/policies/scan-execution-policies.md). We have not
-[unified the user experience for these two features](https://gitlab.com/groups/gitlab-org/-/epics/7312). For details on
-the similarities and differences between these features, see [Enforce scan execution](../application_security/index.md#enforce-scan-execution).
-
-#### Example configuration
-
-The following example `.compliance-gitlab-ci.yml` includes the `include` keyword to ensure labeled project pipeline
-configuration is also executed.
-
-```yaml
-# Allows compliance team to control the ordering and interweaving of stages/jobs.
-# Stages without jobs defined will remain hidden.
-stages:
- - pre-compliance
- - build
- - test
- - pre-deploy-compliance
- - deploy
- - post-compliance
-
-variables: # Can be overridden by setting a job-specific variable in project's local .gitlab-ci.yml
- FOO: sast
-
-sast: # None of these attributes can be overridden by a project's local .gitlab-ci.yml
- variables:
- FOO: sast
- image: ruby:2.6
- stage: pre-compliance
- rules:
- - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
- when: never
- - when: always # or when: on_success
- allow_failure: false
- before_script:
- - "# No before scripts."
- script:
- - echo "running $FOO"
- after_script:
- - "# No after scripts."
-
-sanity check:
- image: ruby:2.6
- stage: pre-deploy-compliance
- rules:
- - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
- when: never
- - when: always # or when: on_success
- allow_failure: false
- before_script:
- - "# No before scripts."
- script:
- - echo "running $FOO"
- after_script:
- - "# No after scripts."
-
-audit trail:
- image: ruby:2.7
- stage: post-compliance
- rules:
- - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS && $CI_PIPELINE_SOURCE == "push"
- when: never
- - when: always # or when: on_success
- allow_failure: false
- before_script:
- - "# No before scripts."
- script:
- - echo "running $FOO"
- after_script:
- - "# 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_REF_NAME' # Must be defined or MR pipelines always use the use default branch
-```
-
-##### CF pipelines in Merge Requests originating in project forks
-
-When an MR originates in a fork, the branch to be merged usually only exists in the fork.
-When creating such an MR against a project with CF pipelines, the above snippet will fail with a
-`Project <project-name> reference <branch-name> does not exist!` error message.
-This is because in the context of the target project, `$CI_COMMIT_REF_NAME` evaluates to a non-existing branch name.
-
-To get the correct context, use `$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH` instead of `$CI_PROJECT_PATH`.
-This variable is only availabe in
-[merge request pipelines](../../ci/pipelines/merge_request_pipelines.md).
-
-For example, for a configuration that supports both branch pipelines, as well as merge request pipelines originating in project forks,
-you need to [combine both `include` directives with `rules:if`](../../ci/yaml/includes.md#use-rules-with-include):
-
-```yaml
-include: # Execute individual project's configuration (if project contains .gitlab-ci.yml)
- - project: '$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH'
- file: '$CI_CONFIG_PATH'
- ref: '$CI_COMMIT_REF_NAME'
- rules:
- - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- - project: '$CI_PROJECT_PATH'
- file: '$CI_CONFIG_PATH'
- ref: '$CI_COMMIT_REF_NAME'
- rules:
- - if: $CI_PIPELINE_SOURCE != 'merge_request_event'
-```
-
-### Ensure compliance jobs are always run
-
-Compliance pipelines [use GitLab CI/CD](../../ci/index.md) to give you an incredible amount of flexibility
-for defining any sort of compliance jobs you like. Depending on your goals, these jobs
-can be configured to be:
-
-- Modified by users.
-- Non-modifiable.
-
-Generally, if a value in a compliance job:
-
-- Is set, it cannot be changed or overridden by project-level configurations.
-- Is not set, a project-level configuration may set.
-
-Either might be wanted or not depending on your use case.
-
-There are a few best practices for ensuring that these jobs are always run exactly
-as you define them and that downstream, project-level pipeline configurations
-cannot change them:
-
-- Add [a `rules:when:always` block](../../ci/yaml/index.md#when) to each of your compliance jobs. This ensures they are
- non-modifiable and are always run.
-- Explicitly set any [variables](../../ci/yaml/index.md#variables) the job references. This:
- - Ensures that project-level pipeline configurations do not set them and alter their
- behavior.
- - Includes any jobs that drive the logic of your job.
-- Explicitly set the [container image](../../ci/yaml/index.md#image) to run the job in. This ensures that your script
- steps execute in the correct environment.
-- Explicitly set any relevant GitLab pre-defined [job keywords](../../ci/yaml/index.md#job-keywords).
- This ensures that your job uses the settings you intend and that they are not overridden by
- project-level pipelines.
-
-### Avoid parent and child pipelines in GitLab 14.7 and earlier
-
-NOTE:
-This advice does not apply to GitLab 14.8 and later because [a fix](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78878) added
-compatibility for combining compliance pipelines, and parent and child pipelines.
-
-Compliance pipelines start on the run of _every_ pipeline in a labeled project. This means that if a pipeline in the labeled project
-triggers a child pipeline, the compliance pipeline runs first. This can trigger the parent pipeline, instead of the child pipeline.
-
-Therefore, in projects with compliance frameworks, we recommend replacing
-[parent-child pipelines](../../ci/pipelines/downstream_pipelines.md#parent-child-pipelines) with the following:
-
-- Direct [`include`](../../ci/yaml/index.md#include) statements that provide the parent pipeline with child pipeline configuration.
-- Child pipelines placed in another project that are run using the [trigger API](../../ci/triggers/index.md) rather than the parent-child
- pipeline feature.
-
-This alternative ensures the compliance pipeline does not re-start the parent pipeline.
-
## Disable email notifications
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23585) in GitLab 12.2.
@@ -722,7 +526,7 @@ This includes projects shared with the group, but it **excludes** projects in
subgroups or parent groups of the group being configured.
You can configure this feature for both subgroups and immediate parent groups. A project
-in a subgroup has access to the templates for that subgroup, as well as
+in a subgroup has access to the templates for that subgroup and
any immediate parent groups.
To learn how to create templates for issues and merge requests, see
@@ -811,7 +615,7 @@ Group.find_by_sql("SELECT * FROM namespaces WHERE name LIKE '%oup'")
If transferring a group doesn't work through the UI or API, you may want to attempt the transfer in a [Rails console session](../../administration/operations/rails_console.md#starting-a-rails-console-session):
WARNING:
-Any command that changes data directly could be damaging if not run correctly, or under the right conditions. We highly recommend running them in a test environment with a backup of the instance ready to be restored, just in case.
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
```ruby
user = User.find_by_username('<username>')
@@ -842,8 +646,27 @@ At times, a group deletion may get stuck. If needed, in a [Rails console session
you can attempt to delete a group using the following command:
WARNING:
-Any command that changes data directly could be damaging if not run correctly, or under the right conditions. We highly recommend running them in a test environment with a backup of the instance ready to be restored, just in case.
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
```ruby
GroupDestroyWorker.new.perform(group_id, user_id)
```
+
+### Find a user's maximum permissions for a group or project
+
+Administrators can find a user's maximum permissions for a group or project.
+
+1. Start a [Rails console session](../../administration/operations/rails_console.md#starting-a-rails-console-session).
+1. Run the following commands:
+
+ ```ruby
+ user = User.find_by_username 'username'
+ project = Project.find_by_full_path 'group/project'
+ user.max_member_access_for_project project.id
+ ```
+
+ ```ruby
+ user = User.find_by_username 'username'
+ group = Group.find_by_full_path 'group'
+ user.max_member_access_for_group group.id
+ ```
diff --git a/doc/user/group/planning_hierarchy/index.md b/doc/user/group/planning_hierarchy/index.md
index baa2a4d6046..f48a027ab2d 100644
--- a/doc/user/group/planning_hierarchy/index.md
+++ b/doc/user/group/planning_hierarchy/index.md
@@ -58,10 +58,10 @@ Epic "1"*-- "0..*" Issue
In an issue, you can view the parented epic above the issue in the right sidebar under **Epic**.
-![epics state dropdown](img/issue-view-parent-epic-in-sidebar_v14_6.png)
+![epics state dropdown list](img/issue-view-parent-epic-in-sidebar_v14_6.png)
## View ancestry of an epic
In an epic, you can view the ancestors as parents in the right sidebar under **Ancestors**.
-![epics state dropdown](img/epic-view-ancestors-in-sidebar_v14_6.png)
+![epics state dropdown list](img/epic-view-ancestors-in-sidebar_v14_6.png)
diff --git a/doc/user/group/reporting/git_abuse_rate_limit.md b/doc/user/group/reporting/git_abuse_rate_limit.md
new file mode 100644
index 00000000000..1cf3a9dbe7d
--- /dev/null
+++ b/doc/user/group/reporting/git_abuse_rate_limit.md
@@ -0,0 +1,36 @@
+---
+stage: Anti-Abuse
+group: Anti-Abuse
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Git abuse rate limit **(ULTIMATE SELF)**
+
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8066) in GitLab 15.2 [with a flag](../../../administration/feature_flags.md) named `limit_unique_project_downloads_per_namespace_user`. 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 `limit_unique_project_downloads_per_namespace_user`. On GitLab.com, this feature is not 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.
+
+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.
+
+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.
+
+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.
+
+## Configure Git abuse rate limiting
+
+1. On the left sidebar, select **Settings > Reporting**.
+1. Update the Git abuse rate limit settings:
+ 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. 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**.
+
+## Unban a user
+
+1. On the left sidebar, select **Group information > Members**.
+1. Select the **Banned** tab.
+1. For the account you want to unban, select **Unban**.
diff --git a/doc/user/group/repositories_analytics/index.md b/doc/user/group/repositories_analytics/index.md
index 0a4d7f5eae4..9971457f2ac 100644
--- a/doc/user/group/repositories_analytics/index.md
+++ b/doc/user/group/repositories_analytics/index.md
@@ -58,7 +58,7 @@ To get the report:
1. Select the projects and date range you want to include in the report.
1. Select **Download test coverage data (.csv)**.
-The projects dropdown shows up to 100 projects from your group. If the project you want to check is not in the dropdown list, you can select **All projects** to download the report for all projects in your group, including any projects that are not listed. There is a plan to improve this behavior in this [related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/250684).
+The projects dropdown list shows up to 100 projects from your group. If the project you want to check is not in the dropdown list, you can select **All projects** to download the report for all projects in your group, including any projects that are not listed. There is a plan to improve this behavior in this [related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/250684).
For each day that a coverage report was generated by a job in a project's pipeline, a row in the CSV includes:
@@ -82,6 +82,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/group/roadmap/img/roadmap_blocked_icon_v15_5.png b/doc/user/group/roadmap/img/roadmap_blocked_icon_v15_5.png
index 52130672e5a..625e4afc714 100644
--- a/doc/user/group/roadmap/img/roadmap_blocked_icon_v15_5.png
+++ b/doc/user/group/roadmap/img/roadmap_blocked_icon_v15_5.png
Binary files differ
diff --git a/doc/user/group/roadmap/index.md b/doc/user/group/roadmap/index.md
index 28431cb6b9a..3a9d0c833c1 100644
--- a/doc/user/group/roadmap/index.md
+++ b/doc/user/group/roadmap/index.md
@@ -164,6 +164,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/group/saml_sso/group_sync.md b/doc/user/group/saml_sso/group_sync.md
index 3a50470ce50..001c73b6979 100644
--- a/doc/user/group/saml_sso/group_sync.md
+++ b/doc/user/group/saml_sso/group_sync.md
@@ -77,12 +77,8 @@ Users granted:
### Automatic member removal
After a group sync, for GitLab subgroups, users who are not members of a mapped SAML
-group are removed from the group.
-
-FLAG:
-In [GitLab 15.1 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/364144), on GitLab.com, users in the top-level
-group are assigned the [default membership role](index.md#role) rather than removed. This setting is enabled with the
-`saml_group_sync_retain_default_membership` feature flag and can be configured by GitLab.com administrators only.
+group are removed from the group. Users in the top-level group are assigned the
+[default membership role](index.md#role).
For example, in the following diagram:
diff --git a/doc/user/group/saml_sso/img/member_enterprise_badge_v14_0.png b/doc/user/group/saml_sso/img/member_enterprise_badge_v14_0.png
deleted file mode 100644
index f9534b14a51..00000000000
--- a/doc/user/group/saml_sso/img/member_enterprise_badge_v14_0.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md
index fa6f378e811..1c5e7ff0115 100644
--- a/doc/user/group/saml_sso/index.md
+++ b/doc/user/group/saml_sso/index.md
@@ -121,11 +121,18 @@ It can also help to compare the XML response from your provider with our [exampl
> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/211962) in GitLab 13.8 with allowing group owners to not go through SSO.
> - [Improved](https://gitlab.com/gitlab-org/gitlab/-/issues/9152) in GitLab 13.11 with enforcing open SSO session to use Git if this setting is switched on.
> - [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. Enabled on GitLab.com.
+> - [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.
+
+FLAG:
+On self-managed GitLab, transparent SSO enforcement is unavailable. On GitLab.com, transparent SSO enforcement is unavailable and can be configured by GitLab.com administrators only.
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.
-When SAML SSO is enabled, SSO is enforced for each user with an existing SAML identity.
+SSO is enforced for each user with an existing SAML identity when the following is enabled:
+
+- SAML SSO.
+- The `:transparent_sso_enforcement` feature flag.
+
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.
@@ -142,6 +149,15 @@ However, users are not prompted to sign in through SSO on each visit. GitLab che
has authenticated through SSO. If it's been more than 1 day since the last sign-in, GitLab
prompts the user to sign in again through SSO.
+When the transparent SSO enforcement feature flag is enabled, SSO is enforced as follows:
+
+| Project/Group visibility | Enforce SSO setting | Member with identity | Member without identity | Non-member or not signed in |
+|--------------------------|---------------------|--------------------| ------ |------------------------------|
+| Private | Off | Enforced | Not enforced | No access |
+| Private | On | Enforced | Enforced | No access |
+| Public | Off | Enforced | Not enforced | Not enforced |
+| Public | On | Enforced | Enforced | Not enforced |
+
An [issue exists](https://gitlab.com/gitlab-org/gitlab/-/issues/297389) to add a similar SSO requirement for API activity.
SSO enforcement has the following effects when enabled:
@@ -306,9 +322,11 @@ To migrate users to a new email domain, users must:
## User access and management
-> SAML user provisioning [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/268142) in GitLab 13.7.
+> - SAML user provisioning [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/268142) in GitLab 13.7.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325712) in GitLab 14.0, GitLab users created by [SAML SSO](index.md#user-access-and-management) or SCIM provisioning are displayed with an **Enterprise** badge in the **Members** view.
-Once Group SSO is configured and enabled, users can access the GitLab.com group through the identity provider's dashboard. If [SCIM](scim_setup.md) is configured, see the [user access and linking setup section on the SCIM page](scim_setup.md#user-access-and-linking-setup).
+After group SSO is configured and enabled, users can access the GitLab.com group through the identity provider's dashboard.
+If [SCIM](scim_setup.md) is configured, see [user access](scim_setup.md#user-access) on the SCIM page.
When a user tries to sign in with Group SSO, GitLab attempts to find or create a user based on the following:
@@ -422,7 +440,7 @@ To rescind a user's access to the group when only SAML SSO is configured, either
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).
-To rescind a user's access to the group when also using SCIM, refer to [Blocking access](scim_setup.md#blocking-access).
+To rescind a user's access to the group when also using SCIM, refer to [Remove access](scim_setup.md#remove-access).
### Unlinking accounts
diff --git a/doc/user/group/saml_sso/scim_setup.md b/doc/user/group/saml_sso/scim_setup.md
index 55990336a50..18af39f4271 100644
--- a/doc/user/group/saml_sso/scim_setup.md
+++ b/doc/user/group/saml_sso/scim_setup.md
@@ -168,13 +168,16 @@ Prerequisites:
OneLogin provides a **GitLab (SaaS)** app in their catalog, which includes a SCIM integration. Contact OneLogin if you
encounter issues.
-## User access and linking setup
+## User access
-During the synchronization process, all of your users get GitLab accounts, welcoming them
-to their respective groups, with an invitation email. When implementing SCIM provisioning,
-you may want to warn your security-conscious employees about this email.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325712) in GitLab 14.0, GitLab users created by [SAML SSO](index.md#user-access-and-management) or SCIM provisioning are displayed with an **Enterprise** badge in the **Members** view.
-The following diagram is a general outline on what happens when you add users to your SCIM app:
+During the synchronization process, all new users:
+
+- Receive GitLab accounts.
+- Are welcomed to their groups with an invitation email. You may want to warn your employees to expect this email.
+
+The following diagram describes what happens when you add users to your SCIM app:
```mermaid
graph TD
@@ -186,29 +189,38 @@ graph TD
During provisioning:
- Both primary and secondary emails are considered when checking whether a GitLab user account exists.
-- Duplicate usernames are also handled, by adding suffix `1` upon user creation. For example,
- due to already existing `test_user` username, `test_user1` is used.
+- Duplicate usernames are handled by adding suffix `1` when creating the user. For example, if `test_user` already
+ exists, `test_user1` is used. If `test_user1` already exists, GitLab increments the suffix until an unused username
+ is found.
-If [Group SAML](index.md) has been configured and you have an existing GitLab.com account, you can link your SCIM and SAML identities:
+On subsequent visits, new and existing users can access groups either:
-1. Update the [primary email](../../profile/index.md#change-your-primary-email) address in your GitLab.com user account to match the
- user profile email address in your identity provider.
-1. [Link your SAML identity](index.md#linking-saml-to-your-existing-gitlabcom-account).
+- Through the identity provider's dashboard.
+- By visiting links directly.
-We recommend users do this prior to turning on sync, because while synchronization is active, there may be provisioning errors for existing users.
+For role information, see the [Group SAML](index.md#user-access-and-management) page.
-New users and existing users on subsequent visits can access the group through the identity provider's dashboard or by visiting links directly.
+### Link SCIM and SAML identities
-[In GitLab 14.0 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/325712), GitLab users created by [SAML SSO](index.md#user-access-and-management) or SCIM provisioning display with an **Enterprise** badge in the **Members** view.
+If [group SAML](index.md) is configured and you have an existing GitLab.com account, users can link their SCIM and SAML
+identities. Users should do this before synchronization is turned on because there can be provisioning errors for
+existing users when synchronization is active.
+
+To link your SCIM and SAML identities:
+
+1. Update the [primary email](../../profile/index.md#change-your-primary-email) address in your GitLab.com user account
+ to match the user profile email address in your identity provider.
+1. [Link your SAML identity](index.md#linking-saml-to-your-existing-gitlabcom-account).
-![Enterprise badge for users created with a SCIM identity](img/member_enterprise_badge_v14_0.png)
+### Remove access
-For role information, see the [Group SAML page](index.md#user-access-and-management)
+Remove or deactivate a user on the identity provider to remove their access to:
-### Blocking access
+- The top-level group.
+- All subgroups and projects.
-To rescind access to the top-level group, all subgroups, and projects, remove or deactivate the user
-on the identity provider. After the identity provider performs a sync, based on its configured schedule, the user's membership is revoked and they lose access.
+After the identity provider performs a sync based on its configured schedule, the user's membership is revoked and they
+lose access.
NOTE:
Deprovisioning does not delete the GitLab user account.
diff --git a/doc/user/group/saml_sso/troubleshooting.md b/doc/user/group/saml_sso/troubleshooting.md
index bde5ed1762a..7dafd2c5075 100644
--- a/doc/user/group/saml_sso/troubleshooting.md
+++ b/doc/user/group/saml_sso/troubleshooting.md
@@ -19,9 +19,10 @@ SAML responses are base64 encoded, so we recommend the following browser plugins
- [SAML-tracer](https://addons.mozilla.org/en-US/firefox/addon/saml-tracer/) for Firefox.
- [SAML Message Decoder](https://chrome.google.com/webstore/detail/saml-message-decoder/mpabchoaimgbdbbjjieoaeiibojelbhm?hl=en) for Chrome.
-Specific attention should be paid to:
+Pay specific attention to:
-- The NameID, which we use to identify which user is signing in. If the user has previously signed in, this [must match the value we have stored](#verifying-nameid).
+- The `NameID`, which we use to identify which user is signing in. If the user has previously signed in, this
+ [must match the value we have stored](#verify-nameid).
- The presence of a `X509Certificate`, which we require to verify the response signature.
- The `SubjectConfirmation` and `Conditions`, which can cause errors if misconfigured.
@@ -32,7 +33,7 @@ using an identity provider.
To generate a SAML Response:
-1. Install one of the browser debugging tools previously mentioned.
+1. Install one of the [browser debugging tools](#saml-debugging-tools).
1. Open a new browser tab.
1. Open the SAML tracer console:
- Chrome: On a context menu on the page, select **Inspect**, then select the **SAML** tab in the opened developer
@@ -43,16 +44,17 @@ To generate a SAML Response:
[example SAML response](index.md#example-saml-response).
1. Within the SAML tracer, select the **Export** icon to save the response in JSON format.
-## GitLab SAML Testing Environments
+## Testing GitLab SAML
-To troubleshoot, [a complete GitLab with SAML testing environment using Docker compose](https://gitlab.com/gitlab-com/support/toolbox/replication/tree/master/compose_files)
-is available.
+You can use one of the following to troubleshoot SAML:
-If you only require a SAML provider for testing, a [quick start guide to start a Docker container](../../../administration/troubleshooting/test_environments.md#saml) with a plug and play SAML 2.0 Identity Provider (identity provider) is available.
+- A [complete GitLab with SAML testing environment using Docker compose](https://gitlab.com/gitlab-com/support/toolbox/replication/tree/master/compose_files).
+- A [quick start guide to start a Docker container](../../../administration/troubleshooting/test_environments.md#saml)
+ with a plug and play SAML 2.0 identity provider if you only require a SAML provider.
+- A local environment by
+ [enabling SAML for groups on a self-managed instance](../../../integration/saml.md#configuring-group-saml-on-a-self-managed-gitlab-instance).
-You can test the SaaS feature locally by [enabling SAML for groups on a self-managed instance](../../../integration/saml.md#configuring-group-saml-on-a-self-managed-gitlab-instance).
-
-## Verifying configuration
+## Verify configuration
For convenience, we've included some [example resources](../../../user/group/saml_sso/example_saml_config.md) used by our Support Team. While they may help you verify the SAML app configuration, they are not guaranteed to reflect the current state of third-party products.
@@ -82,7 +84,7 @@ in case the customer has [configured SAML Group Sync](group_sync.md):
- `json.class`: `GroupSamlGroupSyncWorker`
- `json.args`: `<user ID> or <group ID>`
-In the relevant log entry, the:
+In the relevant log entry, the:
- `json.args` are in the form `<userID>, <group ID>,
[group link ID 1, group link ID 2, ..., group link ID N]`.
@@ -148,13 +150,13 @@ If you do not wish to use that GitLab user with the SAML login, you can [unlink
### Message: "SAML authentication failed: User has already been taken"
-The user that you're signed in with already has SAML linked to a different identity, or the NameID value has changed.
+The user that you're signed in with already has SAML linked to a different identity, or the `NameID` value has changed.
Here are possible causes and solutions:
| Cause | Solution |
| ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| You've tried to link multiple SAML identities to the same user, for a given identity provider. | Change the identity that you sign in with. To do so, [unlink the previous SAML identity](index.md#unlinking-accounts) from this GitLab account before attempting to sign in again. |
-| The NameID changes every time the user requests SSO identification | [Check the NameID](#verifying-nameid) is not set with `Transient` format, or the NameID is not changing on subsequent requests.|
+| The `NameID` changes every time the user requests SSO identification | [Check the `NameID`](#verify-nameid) is not set with `Transient` format, or the `NameID` is not changing on subsequent requests.|
### Message: "SAML authentication failed: Email has already been taken"
@@ -171,9 +173,9 @@ User accounts are created in one of the following ways:
### Message: "SAML authentication failed: Extern UID has already been taken, User has already been taken"
-Getting both of these errors at the same time suggests the NameID capitalization provided by the identity provider didn't exactly match the previous value for that user.
+Getting both of these errors at the same time suggests the `NameID` capitalization provided by the identity provider didn't exactly match the previous value for that user.
-This can be prevented by configuring the NameID to return a consistent value. Fixing this for an individual user involves changing the identifier for the user. For GitLab.com, the user needs to [unlink their SAML from the GitLab account](index.md#unlinking-accounts).
+This can be prevented by configuring the `NameID` to return a consistent value. Fixing this for an individual user involves changing the identifier for the user. For GitLab.com, the user needs to [unlink their SAML from the GitLab account](index.md#unlinking-accounts).
### Message: "Request to link SAML account must be authorized"
@@ -196,15 +198,15 @@ to [reset their password](https://gitlab.com/users/password/new) if both:
## Other user sign in issues
-### Verifying NameID
+### Verify `NameID`
-In troubleshooting, any authenticated user can use the API to verify the NameID GitLab already has linked to the user by visiting [`https://gitlab.com/api/v4/user`](https://gitlab.com/api/v4/user) and checking the `extern_uid` under identities.
+In troubleshooting, any authenticated user can use the API to verify the `NameID` GitLab already has linked to their user by visiting [`https://gitlab.com/api/v4/user`](https://gitlab.com/api/v4/user) and checking the `extern_uid` under identities.
For self-managed, administrators can use the [users API](../../../api/users.md) to see the same information.
When using SAML for groups, group members of a role with the appropriate permissions can make use of the [members API](../../../api/members.md) to view group SAML identity information for members of the group.
-This can then be compared to the NameID being sent by the identity provider by decoding the message with a [SAML debugging tool](#saml-debugging-tools). We require that these match to identify users.
+This can then be compared to the `NameID` being sent by the identity provider by decoding the message with a [SAML debugging tool](#saml-debugging-tools). We require that these match to identify users.
### Stuck in a login "loop"
diff --git a/doc/user/group/saml_sso/troubleshooting_scim.md b/doc/user/group/saml_sso/troubleshooting_scim.md
index 6f8aed4b386..22562c51e9e 100644
--- a/doc/user/group/saml_sso/troubleshooting_scim.md
+++ b/doc/user/group/saml_sso/troubleshooting_scim.md
@@ -8,93 +8,120 @@ info: To determine the technical writer assigned to the Stage/Group associated w
This section contains possible solutions for problems you might encounter.
-## How come I can't add a user after I removed them?
+## User cannot be added after they are removed
-As outlined in the [Blocking access section](scim_setup.md#blocking-access), when you remove a user, they are removed from the group. However, their account is not deleted.
+When you remove a user, they are removed from the group but their account is not deleted
+(see [remove access](scim_setup.md#remove-access)).
When the user is added back to the SCIM app, GitLab cannot create a new user because the user already exists.
-Solution: Have a user sign in directly to GitLab, then [manually link](scim_setup.md#user-access-and-linking-setup) their account.
+To solve this problem:
-## How do I diagnose why a user is unable to sign in
+1. Have the user sign in directly to GitLab.
+1. [Manually link](scim_setup.md#link-scim-and-saml-identities) their account.
-Ensure that the user has been added to the SCIM app.
+## User cannot sign in
-If you receive "User is not linked to a SAML account", then most likely the user already exists in GitLab. Have the user follow the [User access and linking setup](scim_setup.md#user-access-and-linking-setup) instructions.
+The following are possible solutions for problems where users cannot sign in:
-The **Identity** (`extern_uid`) value stored by GitLab is updated by SCIM whenever `id` or `externalId` changes. Users cannot sign in unless the GitLab Identity (`extern_uid`) value matches the `NameId` sent by SAML.
+- Ensure that the user was added to the SCIM app.
+- If you receive the `User is not linked to a SAML account` error, the user probably already exists in GitLab. Have the
+ user follow the [Link SCIM and SAML identities](scim_setup.md#link-scim-and-saml-identities) instructions.
+- The **Identity** (`extern_uid`) value stored by GitLab is updated by SCIM whenever `id` or `externalId` changes. Users
+ cannot sign in unless the GitLab Identity (`extern_uid`) value matches the `NameId` sent by SAML. This value is also
+ used by SCIM to match users on the `id`, and is updated by SCIM whenever the `id` or `externalId` values change.
+- The SCIM `id` and SCIM `externalId` must be configured to the same value as the SAML `NameId`. You can trace SAML responses
+ using [debugging tools](troubleshooting.md#saml-debugging-tools), and check any errors against the
+ [SAML troubleshooting](troubleshooting.md) information.
-This value is also used by SCIM to match users on the `id`, and is updated by SCIM whenever the `id` or `externalId` values change.
+## Unsure if user's SAML `NameId` matches the SCIM `externalId`
-It is important that this SCIM `id` and SCIM `externalId` are configured to the same value as the SAML `NameId`. SAML responses can be traced using [debugging tools](troubleshooting.md#saml-debugging-tools), and any errors can be checked against our [SAML troubleshooting docs](troubleshooting.md).
+To check if a user's SAML `NameId` matches their SCIM `externalId`:
-## How do I verify user's SAML NameId matches the SCIM externalId
+- Administrators can use the Admin Area to [list SCIM identities for a user](../../admin_area/index.md#user-identities).
+- Group owners can see the list of users and the identifier stored for each user in the group SAML SSO Settings page.
+- You can use the [SCIM API](../../../api/scim.md) to manually retrieve the `external_uid` GitLab has stored for users and compare the value for each user from the [SAML API](../../../api/saml.md) .
+- Have the user use a [SAML Tracer](troubleshooting.md#saml-debugging-tools) and compare the `external_uid` to
+ the value returned as the SAML `NameId`.
-Administrators can use the Admin Area to [list SCIM identities for a user](../../admin_area/index.md#user-identities).
+## Mismatched SCIM `extern_uid` and SAML `NameId`
-Group owners can see the list of users and the `externalId` stored for each user in the group SAML SSO Settings page.
+Whether the value was changed or you need to map to a different field, the following must map to the same field:
-A possible alternative is to use the [SCIM API](../../../api/scim.md) to manually retrieve the `externalId` we have stored for users, also called the `external_uid` or `NameId`.
+- `id`
+- `externalId`
+- `NameId`
-To see how the `external_uid` compares to the value returned as the SAML NameId, you can have the user use a [SAML Tracer](troubleshooting.md#saml-debugging-tools).
-
-## Update or fix mismatched SCIM externalId and SAML NameId
-
-Whether the value was changed or you need to map to a different field, ensure `id`, `externalId`, and `NameId` all map to the same field.
-
-If the GitLab `externalId` doesn't match the SAML NameId, it needs to be updated in order for the user to sign in. Ideally your identity provider is configured to do such an update, but in some cases it may be unable to do so, such as when looking up a user fails due to an ID change.
+If the GitLab `extern_uid` doesn't match the SAML `NameId`, it must be updated for the user to sign in. Your identity
+provider should be configured to do this update. In some cases the identity provider cannot do the update, for example
+when a user lookup fails because of an ID change.
Be cautious if you revise the fields used by your SCIM identity provider, typically `id` and `externalId`.
-We use these IDs to look up users. If the identity provider does not know the current values for these fields,
+GitLab uses these IDs to look up users. If the identity provider does not know the current values for these fields,
that provider may create duplicate users.
-If the `externalId` for a user is not correct, and also doesn't match the SAML NameID,
-you can address the problem in the following ways:
+If the `extern_uid` for a user is not correct, and also doesn't match the SAML `NameID`, either:
+
+- Have users unlink and relink themselves, based on the
+ [SAML authentication failed: User has already been taken](troubleshooting.md#message-saml-authentication-failed-user-has-already-been-taken)
+ section.
+- Unlink all users simultaneously by removing all users from the SCIM app while provisioning is turned on.
+- Use the [SCIM API](../../../api/scim.md) to manually correct the `extern_uid` stored for users to match the SAML
+ `NameId`. To look up a user, you must know the desired value that matches the `NameId` as well as the current
+ `extern_uid`.
-- You can have users unlink and relink themselves, based on the ["SAML authentication failed: User has already been taken"](troubleshooting.md#message-saml-authentication-failed-user-has-already-been-taken) section.
-- You can unlink all users simultaneously, by removing all users from the SAML app while provisioning is turned on.
-- Use the [SCIM API](../../../api/scim.md) to manually correct the `externalId` stored for users to match the SAML `NameId`.
- To look up a user, you need to know the desired value that matches the `NameId` as well as the current `externalId`.
+You must not:
-It is important not to update these to incorrect values, since this causes users to be unable to sign in. It is also important not to assign a value to the wrong user, as this causes users to get signed into the wrong account.
+- Update these to incorrect values because this causes users to be unable to sign in.
+- Assign a value to the wrong user because this causes users to be signed in to the wrong account.
-## I need to change my SCIM app
+## Change SCIM app
-Individual users can follow the instructions in the ["SAML authentication failed: User has already been taken"](index.md#change-the-saml-app) section.
+When the SCIM app changes:
-Alternatively, users can be removed from the SCIM app which de-links all removed users. Sync can then be turned on for the new SCIM app to [link existing users](scim_setup.md#user-access-and-linking-setup).
+- Users can follow the instructions in the [Change the SAML app](index.md#change-the-saml-app) 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).
-## The SCIM app is throwing `"User has already been taken","status":409` error message
+## SCIM app returns `"User has already been taken","status":409` error
Changing the SAML or SCIM configuration or provider can cause the following problems:
-| Problem | Solution |
-| ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| SAML and SCIM identity mismatch. | First [verify that the user's SAML NameId matches the SCIM externalId](#how-do-i-verify-users-saml-nameid-matches-the-scim-externalid) and then [update or fix the mismatched SCIM externalId and SAML NameId](#update-or-fix-mismatched-scim-externalid-and-saml-nameid). |
-| SCIM identity mismatch between GitLab and the identity provider SCIM app. | You can confirm whether you're hitting the error because of your SCIM identity mismatch between your SCIM app and GitLab.com by using the [SCIM API](../../../api/scim.md) which shows up in the `id` key and compares it with the user `externalId` in the SCIM app. You can use the same [SCIM API](../../../api/scim.md) to update the SCIM `id` for the user on GitLab.com. |
+- SAML and SCIM identity mismatch. To solve this problem:
+ 1. [Verify that the user's SAML `NameId` matches the SCIM `extern_uid`](#unsure-if-users-saml-nameid-matches-the-scim-externalid).
+ 1. [Update or fix the mismatched SCIM `extern_uid` and SAML `NameId`](#mismatched-scim-extern_uid-and-saml-nameid).
+- SCIM identity mismatch between GitLab and the identity provider SCIM app. To solve this problem:
+ 1. Use the [SCIM API](../../../api/scim.md), which displays the user's `extern_uid` stored in GitLab and compares it with the user `externalId` in
+ the SCIM app.
+ 1. Use the same SCIM API to update the SCIM `extern_uid` for the user on GitLab.com.
## Search Rails logs for SCIM requests
GitLab.com administrators can search for SCIM requests in the `api_json.log` using the `pubsub-rails-inf-gprd-*` index in
-[Kibana](https://about.gitlab.com/handbook/support/workflows/kibana.html#using-kibana). Use the following filters based on the internal
-[SCIM API](../../../development/internal_api/index.md#scim-api):
+[Kibana](https://about.gitlab.com/handbook/support/workflows/kibana.html#using-kibana). Use the following filters based
+on the internal [SCIM API](../../../development/internal_api/index.md#scim-api):
- `json.path`: `/scim/v2/groups/<group-path>`
- `json.params.value`: `<externalId>`
-In a relevant log entry, the `json.params.value` shows the values of SCIM parameters GitLab receives. These values can be used to verify if SCIM parameters configured in an
-identity provider's SCIM app are communicated to GitLab as intended. For example, we can use these values as a definitive source on why an account was provisioned with a certain
-set of details. This information can help where an account was SCIM provisioned with details that appear to be incongruent with what might have been configured within an identity
-provider's SCIM app.
+In a relevant log entry, the `json.params.value` shows the values of SCIM parameters GitLab receives. Use these values
+to verify if SCIM parameters configured in an identity provider's SCIM app are communicated to GitLab as intended.
-## Azure
+For example, use these values as a definitive source on why an account was provisioned with a certain set of
+details. This information can help where an account was SCIM provisioned with details that do not match
+the SCIM app configuration.
-### How do I verify my SCIM configuration is correct?
+## Azure Active Directory
-Review the following:
+The following troubleshooting information is specifically for SCIM provisioned through Azure Active Directory.
-- Ensure that the SCIM value for `id` matches the SAML value for `NameId`.
-- Ensure that the SCIM value for `externalId` matches the SAML value for `NameId`.
+### Verify my SCIM configuration is correct
+
+Ensure that:
+
+- The matching precedence for `externalId` is 1.
+- The SCIM value for `externalId` matches the SAML value for `NameId`.
Review the following SCIM parameters for sensible values:
@@ -102,28 +129,37 @@ Review the following SCIM parameters for sensible values:
- `displayName`
- `emails[type eq "work"].value`
-### Testing Azure connection: invalid credentials
+### `invalid credentials` error when testing connection
+
+When testing the connection, you may encounter an error:
+
+```plaintext
+You appear to have entered invalid credentials. Please confirm
+you are using the correct information for an administrative account
+```
-When testing the connection, you may encounter an error: **You appear to have entered invalid credentials. Please confirm you are using the correct information for an administrative account**. If `Tenant URL` and `secret token` are correct, check whether your group path contains characters that may be considered invalid JSON primitives (such as `.`). Removing such characters from the group path typically resolves the error.
+If `Tenant URL` and `secret token` are correct, check whether your group path contains characters that may be considered
+invalid JSON primitives (such as `.`). Removing or URL encoding these characters in the group path typically resolves the error.
-### (Field) can't be blank sync error
+### `(Field) can't be blank` sync error
-When checking the Audit Events for the Provisioning, you can sometimes see the
-error `Namespace can't be blank, Name can't be blank, and User can't be blank.`
+When checking the Audit Events for the provisioning, you sometimes see a `Namespace can't be blank, Name can't be blank,
+and User can't be blank.` error.
-This is likely caused because not all required fields (such as first name and last name) are present for all users being mapped.
+This error can occur because not all required fields (such as first name and last name) are present for all users
+being mapped.
As a workaround, try an alternate mapping:
-1. Follow the Azure mapping instructions from above.
+1. Follow the [Azure mapping instructions](scim_setup.md#configure-attribute-mappings).
1. Delete the `name.formatted` target attribute entry.
1. Change the `displayName` source attribute to have `name.formatted` target attribute.
-### Failed to match an entry in the source and target systems Group 'Group-Name'
+### `Failed to match an entry in the source and target systems Group 'Group-Name'` error
-Group provisioning in Azure can fail with the `Failed to match an entry in the source and target systems Group 'Group-Name'` error message,
-and the error response can include a HTML result of the GitLab URL `https://gitlab.com/users/sign_in`.
+Group provisioning in Azure can fail with the `Failed to match an entry in the source and target systems Group 'Group-Name'`
+error. The error response can include a HTML result of the GitLab URL `https://gitlab.com/users/sign_in`.
-This error is harmless and occurs because Group provisioning was turned on but GitLab SCIM integration does not support it nor require it. To
-remove the error, follow the instructions in the Azure configuration guide to disable the option
-[`Synchronize Azure Active Directory Groups to AppName`](scim_setup.md#configure-azure-active-directory).
+This error is harmless and occurs because group provisioning was turned on but GitLab SCIM integration does not support
+it nor require it. To remove the error, follow the instructions in the Azure configuration guide to disable the option
+to [synchronize Azure Active Directory groups to AppName](scim_setup.md#configure-azure-active-directory).
diff --git a/doc/user/group/subgroups/index.md b/doc/user/group/subgroups/index.md
index 58f5e476f26..95c8e60af5d 100644
--- a/doc/user/group/subgroups/index.md
+++ b/doc/user/group/subgroups/index.md
@@ -212,6 +212,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/group/value_stream_analytics/index.md b/doc/user/group/value_stream_analytics/index.md
index fcf4189aa32..980618ac3ae 100644
--- a/doc/user/group/value_stream_analytics/index.md
+++ b/doc/user/group/value_stream_analytics/index.md
@@ -104,7 +104,7 @@ The **Overview** dashboard shows the following key metrics that measure team per
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/355304) time to restore service tile in GitLab 15.0.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357071) change failure rate tile in GitLab 15.0.
-The value stream analytics **Overview** dashboard displays the following [DORA](../../../user/analytics/index.md) metrics:
+The value stream analytics **Overview** dashboard displays the following [DORA](../../../user/analytics/dora_metrics.md) metrics:
- Deployment Frequency.
- Lead time for changes.
diff --git a/doc/user/infrastructure/clusters/connect/new_civo_cluster.md b/doc/user/infrastructure/clusters/connect/new_civo_cluster.md
index 998548e3a5e..df785cce406 100644
--- a/doc/user/infrastructure/clusters/connect/new_civo_cluster.md
+++ b/doc/user/infrastructure/clusters/connect/new_civo_cluster.md
@@ -91,7 +91,7 @@ Refer to the [Civo Terraform provider](https://registry.terraform.io/providers/c
After configuring your project, manually trigger the provisioning of your cluster. In GitLab:
1. On the left sidebar, go to **CI/CD > Pipelines**.
-1. Next to **Play** (**{play}**), select the dropdown icon (**{chevron-lg-down}**).
+1. Next to **Play** (**{play}**), select the dropdown list icon (**{chevron-lg-down}**).
1. Select **Deploy** to manually trigger the deployment job.
When the pipeline finishes successfully, you can see your new cluster:
diff --git a/doc/user/infrastructure/clusters/connect/new_eks_cluster.md b/doc/user/infrastructure/clusters/connect/new_eks_cluster.md
index 164b426fd24..8a5c32150c9 100644
--- a/doc/user/infrastructure/clusters/connect/new_eks_cluster.md
+++ b/doc/user/infrastructure/clusters/connect/new_eks_cluster.md
@@ -92,7 +92,7 @@ View the [AWS Terraform provider](https://registry.terraform.io/providers/hashic
After configuring your project, manually trigger the provisioning of your cluster. In GitLab:
1. On the left sidebar, go to **CI/CD > Pipelines**.
-1. Next to **Play** (**{play}**), select the dropdown icon (**{chevron-lg-down}**).
+1. Next to **Play** (**{play}**), select the dropdown list icon (**{chevron-lg-down}**).
1. Select **Deploy** to manually trigger the deployment job.
When the pipeline finishes successfully, you can view the new cluster:
diff --git a/doc/user/infrastructure/clusters/connect/new_gke_cluster.md b/doc/user/infrastructure/clusters/connect/new_gke_cluster.md
index d04b14bf80f..6b8e2003b8d 100644
--- a/doc/user/infrastructure/clusters/connect/new_gke_cluster.md
+++ b/doc/user/infrastructure/clusters/connect/new_gke_cluster.md
@@ -20,7 +20,7 @@ by using the GitLab agent for Kubernetes.
**Prerequisites:**
-- A [Google Cloud Platform (GCP) service account](https://cloud.google.com/docs/authentication/getting-started).
+- A [Google Cloud Platform (GCP) service account](https://cloud.google.com/docs/authentication#service-accounts).
- [A runner](https://docs.gitlab.com/runner/install/) you can use to run the GitLab CI/CD pipeline.
**Steps:**
@@ -71,7 +71,7 @@ To create a GitLab agent for Kubernetes:
To set up your project to communicate to GCP and the GitLab API:
-1. To authenticate GCP with GitLab, create a [GCP service account](https://cloud.google.com/docs/authentication/getting-started)
+1. To authenticate GCP with GitLab, create a [GCP service account](https://cloud.google.com/docs/authentication#service-accounts)
with following roles: `Compute Network Viewer`, `Kubernetes Engine Admin`, `Service Account User`, and `Service Account Admin`. Both User and Admin
service accounts are necessary. The User role impersonates the [default service account](https://cloud.google.com/compute/docs/access/service-accounts#default_service_account)
when [creating the node pool](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/using_gke_with_terraform#node-pool-management).
@@ -117,7 +117,7 @@ Refer to the [Google Terraform provider](https://registry.terraform.io/providers
After configuring your project, manually trigger the provisioning of your cluster. In GitLab:
1. On the left sidebar, go to **CI/CD > Pipelines**.
-1. Next to **Play** (**{play}**), select the dropdown icon (**{chevron-lg-down}**).
+1. Next to **Play** (**{play}**), select the dropdown list icon (**{chevron-lg-down}**).
1. Select **Deploy** to manually trigger the deployment job.
When the pipeline finishes successfully, you can see your new cluster:
diff --git a/doc/user/infrastructure/clusters/manage/management_project_applications/ingress.md b/doc/user/infrastructure/clusters/manage/management_project_applications/ingress.md
index bf86fdb5a8f..14d3a7996e0 100644
--- a/doc/user/infrastructure/clusters/manage/management_project_applications/ingress.md
+++ b/doc/user/infrastructure/clusters/manage/management_project_applications/ingress.md
@@ -22,5 +22,5 @@ of your cluster.
You can customize the installation of Ingress by updating the
`applications/ingress/values.yaml` file in your cluster
management project. Refer to the
-[chart](https://github.com/helm/charts/tree/master/stable/nginx-ingress)
+[chart](https://github.com/kubernetes/ingress-nginx/tree/master/charts/ingress-nginx)
for the available configuration options.
diff --git a/doc/user/infrastructure/clusters/manage/management_project_applications/vault.md b/doc/user/infrastructure/clusters/manage/management_project_applications/vault.md
index 72a44ef2a21..c2190ad7cfa 100644
--- a/doc/user/infrastructure/clusters/manage/management_project_applications/vault.md
+++ b/doc/user/infrastructure/clusters/manage/management_project_applications/vault.md
@@ -36,17 +36,17 @@ Vault application causes downtime.
To optimally use Vault in a production environment, it's ideal to have a good understanding
of the internals of Vault and how to configure it. This can be done by reading
the [Vault Configuration guide](../../../../../ci/secrets/index.md#configure-your-vault-server),
-the [Vault documentation](https://www.vaultproject.io/docs/internals) and
+the [Vault documentation](https://developer.hashicorp.com/vault/docs/internals) and
the Vault Helm chart [`values.yaml` file](https://github.com/hashicorp/vault-helm/blob/v0.3.3/values.yaml).
At a minimum, most users set up:
-- A [seal](https://www.vaultproject.io/docs/configuration/seal) for extra encryption
+- A [seal](https://developer.hashicorp.com/vault/docs/configuration/seal) for extra encryption
of the main key.
-- A [storage backend](https://www.vaultproject.io/docs/configuration/storage) that's
+- A [storage backend](https://developer.hashicorp.com/vault/docs/configuration/storage) that's
suitable for environment and storage security requirements.
-- [HA Mode](https://www.vaultproject.io/docs/concepts/ha).
-- The [Vault UI](https://www.vaultproject.io/docs/configuration/ui).
+- [HA Mode](https://developer.hashicorp.com/vault/docs/concepts/ha).
+- The [Vault UI](https://developer.hashicorp.com/vault/docs/configuration/ui).
The following is an example values file (`applications/vault/values.yaml`)
that configures Google Key Management Service for auto-unseal, using a Google Cloud Storage backend, enabling
@@ -86,7 +86,7 @@ server:
```
After you have successfully installed Vault, you must
-[initialize the Vault](https://learn.hashicorp.com/tutorials/vault/getting-started-deploy#initializing-the-vault)
+[initialize the Vault](https://developer.hashicorp.com/vault/tutorials/getting-started/getting-started-deploy#initializing-the-vault)
and obtain the initial root token. You need access to your Kubernetes cluster that
Vault has been deployed into to do this. To initialize the Vault, get a
shell to one of the Vault pods running inside Kubernetes (typically this is done
diff --git a/doc/user/infrastructure/iac/index.md b/doc/user/infrastructure/iac/index.md
index c2285ecc773..866b16652fa 100644
--- a/doc/user/infrastructure/iac/index.md
+++ b/doc/user/infrastructure/iac/index.md
@@ -99,8 +99,8 @@ in the template you fetched to customize your configuration.
- To collaborate on Terraform code changes and Infrastructure-as-Code workflows, use the
[Terraform integration in merge requests](mr_integration.md).
- To manage GitLab resources like users, groups, and projects, use the
- [GitLab Terraform provider](https://github.com/gitlabhq/terraform-provider-gitlab). It is released separately from GitLab
- and its documentation is available on [the Terraform docs site](https://registry.terraform.io/providers/gitlabhq/gitlab/latest/docs).
+ [GitLab Terraform provider](https://gitlab.com/gitlab-org/terraform-provider-gitlab).
+ The GitLab Terraform provider documentation is available on [the Terraform docs site](https://registry.terraform.io/providers/gitlabhq/gitlab/latest/docs).
- [Create a new cluster on Amazon Elastic Kubernetes Service (EKS)](../clusters/connect/new_eks_cluster.md).
- [Create a new cluster on Google Kubernetes Engine (GKE)](../clusters/connect/new_gke_cluster.md).
- [Troubleshoot](troubleshooting.md) issues with GitLab and Terraform.
diff --git a/doc/user/infrastructure/iac/terraform_state.md b/doc/user/infrastructure/iac/terraform_state.md
index 9cb3fdd7aaf..a690cc78121 100644
--- a/doc/user/infrastructure/iac/terraform_state.md
+++ b/doc/user/infrastructure/iac/terraform_state.md
@@ -59,7 +59,7 @@ encrypt plan output or modify the project visibility settings.
To configure GitLab CI/CD as a backend:
1. In your Terraform project, in a `.tf` file like `backend.tf`,
- define the [HTTP backend](https://www.terraform.io/docs/language/settings/backends/http.html):
+ define the [HTTP backend](https://developer.hashicorp.com/terraform/language/settings/backends/http):
```hcl
terraform {
diff --git a/doc/user/infrastructure/iac/troubleshooting.md b/doc/user/infrastructure/iac/troubleshooting.md
index a1eecb909fb..3921c6a7dc8 100644
--- a/doc/user/infrastructure/iac/troubleshooting.md
+++ b/doc/user/infrastructure/iac/troubleshooting.md
@@ -121,3 +121,13 @@ To resolve this, ensure that:
- If you have set the `TF_HTTP_PASSWORD` CI/CD variable, make sure that you either:
- Set the same value as `TF_PASSWORD`
- Remove `TF_HTTP_PASSWORD` variable if your CI/CD job does not explicitly use it.
+
+### Enable Developer role access to destructive commands
+
+To permit a user with the Developer role to run destructive commands, you need a workaround:
+
+1. [Create a project access token](../../project/settings/project_access_tokens.md#create-a-project-access-token) with `api` scope.
+1. Add `TF_USERNAME` and `TF_PASSWORD` to your CI/CD variables:
+ 1. Set the value of `TF_USERNAME` to the username of your project access token.
+ 1. Set the value of `TF_PASSWORD` to the password of your project access token.
+ 1. Optional. Protect the variables to make them only available in pipelines that run on protected branches or protected tags.
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index 1a743ae99bb..b6f3ba1cfdd 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -331,7 +331,7 @@ However, you cannot mix the wrapping tags:
```
If your diff includes words in `` `code` `` font, make sure to escape each backtick `` ` `` with a
-backslash `\`. Otherwise the diff highlight does not render correctly:
+backslash <code>&#92;</code>. Otherwise the diff highlight does not render correctly:
```markdown
- {+ Just regular text +}
@@ -1160,17 +1160,15 @@ These details <em>remain</em> <strong>hidden</strong> until expanded.
Markdown inside these tags is also supported.
-NOTE:
-If your Markdown isn't rendering correctly, try adding
-`{::options parse_block_html="true" /}` to the top of the page, and add
-`markdown="span"` to the opening summary tag like this: `<summary markdown="span">`.
-
-Remember to leave a blank line after the `</summary>` tag and before the `</details>` tag,
-as shown in the example:
+Remember to leave a blank line before and after any Markdown sections, as shown in the example:
````html
<details>
-<summary>Click this to collapse/fold.</summary>
+<summary>
+
+Click this to _collapse/fold._
+
+</summary>
These details _remain_ **hidden** until expanded.
@@ -1187,7 +1185,7 @@ works correctly in GitLab.
-->
<details>
-<summary>Click this to collapse/fold.</summary>
+<summary>Click this to <em>collapse/fold.</em></summary>
These details <em>remain</em> <b>hidden</b> until expanded.
diff --git a/doc/user/packages/composer_repository/index.md b/doc/user/packages/composer_repository/index.md
index 5eafb74a144..49c54ec191e 100644
--- a/doc/user/packages/composer_repository/index.md
+++ b/doc/user/packages/composer_repository/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
@@ -25,58 +25,7 @@ client uses, see the [Composer API documentation](../../../api/packages/composer
Composer v2.0 is recommended. Composer v1.0 is supported, but it has lower performance when working
in groups with very large numbers of packages.
-## Create a Composer package
-
-If you do not have a Composer package, create one and check it in to
-a repository. This example shows a GitLab repository, but the repository
-can be any public or private repository.
-
-WARNING:
-If you are using a GitLab repository, the project must have been created from
-a group's namespace, rather than a user's namespace. Composer packages
-[can't be published to projects created from a user's namespace](https://gitlab.com/gitlab-org/gitlab/-/issues/235467).
-
-1. Create a directory called `my-composer-package` and change to that directory:
-
- ```shell
- mkdir my-composer-package && cd my-composer-package
- ```
-
-1. Run [`composer init`](https://getcomposer.org/doc/03-cli.md#init) and answer the prompts.
-
- For namespace, enter your unique [namespace](../../../user/namespace/index.md), like your GitLab username or group name.
-
- A file called `composer.json` is created:
-
- ```json
- {
- "name": "<namespace>/composer-test",
- "description": "Library XY",
- "type": "library",
- "license": "GPL-3.0-only",
- "authors": [
- {
- "name": "John Doe",
- "email": "john@example.com"
- }
- ],
- "require": {}
- }
- ```
-
-1. Run Git commands to tag the changes and push them to your repository:
-
- ```shell
- git init
- git add composer.json
- git commit -m 'Composer package test'
- git tag v1.0.0
- git remote add origin git@gitlab.example.com:<namespace>/<project-name>.git
- git push --set-upstream origin main
- git push origin v1.0.0
- ```
-
-The package is now in your GitLab Package Registry.
+Learn how to [build a Composer package](../workflows/build_packages.md#composer).
## Publish a Composer package by using the API
@@ -110,7 +59,7 @@ To publish the package with a personal access token:
- `<personal-access-token>` is your personal access token.
- `<project_id>` is your project ID.
- `<tag>` is the Git tag name of the version you want to publish.
- To publish a branch, use `branch=<branch>` instead of `tag=<tag>`.
+ To publish a branch, use `branch=<branch>` instead of `tag=<tag>`.
To publish the package with a deploy token:
@@ -125,7 +74,7 @@ To publish the package with a deploy token:
- `<deploy-token>` is your deploy token
- `<project_id>` is your project ID.
- `<tag>` is the Git tag name of the version you want to publish.
- To publish a branch, use `branch=<branch>` instead of `tag=<tag>`.
+ To publish a branch, use `branch=<branch>` instead of `tag=<tag>`.
You can view the published package by going to **Packages and registries > Package Registry** and
selecting the **Composer** tab.
diff --git a/doc/user/packages/conan_repository/index.md b/doc/user/packages/conan_repository/index.md
index cd5ce9a1135..3d3fe35fd65 100644
--- a/doc/user/packages/conan_repository/index.md
+++ b/doc/user/packages/conan_repository/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
@@ -29,105 +29,7 @@ Package Registry.
For documentation of the specific API endpoints that the Conan package manager
client uses, see the [Conan API documentation](../../../api/packages/conan.md).
-## Build a Conan package
-
-This section explains how to install Conan and build a package for your C/C++
-project.
-
-If you already use Conan and know how to build your own packages, go to the
-[next section](#add-the-package-registry-as-a-conan-remote).
-
-### Install Conan
-
-Download the Conan package manager to your local development environment by
-following the instructions at [conan.io](https://conan.io/downloads.html).
-
-When installation is complete, verify you can use Conan in your terminal by
-running:
-
-```shell
-conan --version
-```
-
-The Conan version is printed in the output:
-
-```plaintext
-Conan version 1.20.5
-```
-
-### Install CMake
-
-When you develop with C++ and Conan, you can select from many available
-compilers. This example uses the CMake build system generator.
-
-To install CMake:
-
-- For Mac, use [Homebrew](https://brew.sh/) and run `brew install cmake`.
-- For other operating systems, follow the instructions at [cmake.org](https://cmake.org/install/).
-
-When installation is complete, verify you can use CMake in your terminal by
-running:
-
-```shell
-cmake --version
-```
-
-The CMake version is printed in the output.
-
-### Create a project
-
-To test the Package Registry, you need a C++ project. If you don't already have
-one, you can clone the Conan [hello world starter project](https://github.com/conan-io/hello).
-
-### Build a package
-
-To build a package:
-
-1. Open a terminal and navigate to your project's root folder.
-1. Generate a new recipe by running `conan new` with a package name and version:
-
- ```shell
- conan new Hello/0.1 -t
- ```
-
-1. Create a package for the recipe by running `conan create` with the Conan user
- and channel:
-
- ```shell
- conan create . mycompany/beta
- ```
-
- NOTE:
- If you use an [instance remote](#add-a-remote-for-your-instance), you must
- follow a specific [naming convention](#package-recipe-naming-convention-for-instance-remotes).
-
-A package with the recipe `Hello/0.1@mycompany/beta` is created.
-
-For more details about creating and managing Conan packages, see the
-[Conan documentation](https://docs.conan.io/en/latest/creating_packages.html).
-
-#### Package without a username and a channel
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345055) in GitLab 14.6.
-
-Even though they are [recommended](https://docs.conan.io/en/latest/reference/conanfile/attributes.html#user-channel)
-to distinguish your package from a similarly named existing package,
-the username and channel are not mandatory fields for a Conan package.
-
-You can create a package without a username and channel by removing them from
-the `create` command:
-
-```shell
-conan create .
-```
-
-The username _and_ the channel must be blank. If only one of these fields is
-blank, the request is rejected.
-
-NOTE:
-Empty usernames and channels can only be used if you use a [project remote](#add-a-remote-for-your-project).
-If you use an [instance remote](#add-a-remote-for-your-instance), the username
-and the channel must be set.
+Learn how to [build a Conan package](../workflows/build_packages.md#conan).
## Add the Package Registry as a Conan remote
@@ -193,12 +95,12 @@ recipe `user` must be the plus sign (`+`) separated project path.
Example recipe names:
-| Project | Package | Supported |
-| ---------------------------------- | ----------------------------------------------- | --------- |
-| `foo/bar` | `my-package/1.0.0@foo+bar/stable` | Yes |
-| `foo/bar-baz/buz` | `my-package/1.0.0@foo+bar-baz+buz/stable` | Yes |
-| `gitlab-org/gitlab-ce` | `my-package/1.0.0@gitlab-org+gitlab-ce/stable` | Yes |
-| `gitlab-org/gitlab-ce` | `my-package/1.0.0@foo/stable` | No |
+| Project | Package | Supported |
+| ---------------------- | ---------------------------------------------- | --------- |
+| `foo/bar` | `my-package/1.0.0@foo+bar/stable` | Yes |
+| `foo/bar-baz/buz` | `my-package/1.0.0@foo+bar-baz+buz/stable` | Yes |
+| `gitlab-org/gitlab-ce` | `my-package/1.0.0@gitlab-org+gitlab-ce/stable` | Yes |
+| `gitlab-org/gitlab-ce` | `my-package/1.0.0@foo/stable` | No |
[Project remotes](#add-a-remote-for-your-project) have a more flexible naming
convention.
diff --git a/doc/user/packages/container_registry/index.md b/doc/user/packages/container_registry/index.md
index 1ac38979950..65e7918d827 100644
--- a/doc/user/packages/container_registry/index.md
+++ b/doc/user/packages/container_registry/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+group: Container 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
---
@@ -70,7 +70,7 @@ To download and run a container image hosted in the GitLab Container Registry:
[Authentication](#authenticate-with-the-container-registry) is needed to download images from private repository.
For more information on running Docker containers, visit the
-[Docker documentation](https://docs.docker.com/engine/userguide/intro/).
+[Docker documentation](https://docs.docker.com/get-started/).
## Image naming convention
@@ -81,9 +81,9 @@ Images follow this naming convention:
```
If your project is `gitlab.example.com/mynamespace/myproject`, for example,
-then your image must be named `gitlab.example.com/mynamespace/myproject/my-app` at a minimum.
+then your image must be named `gitlab.example.com/mynamespace/myproject` at a minimum.
-You can append additional names to the end of an image name, up to three levels deep.
+You can append additional names to the end of an image name, up to two levels deep.
For example, these are all valid image names for images within the project named `myproject`:
@@ -523,7 +523,7 @@ for more details about the permissions that this setting grants to users.
1. Go to your project's **Settings > General** page.
1. Expand the section **Visibility, project features, permissions**.
-1. Under **Container Registry**, select an option from the dropdown:
+1. Under **Container Registry**, select an option from the dropdown list:
- **Everyone With Access** (Default): The Container Registry is visible to everyone with access
to the project. If the project is public, the Container Registry is also public. If the project
@@ -556,7 +556,7 @@ this setting. However, disabling the Container Registry disables all Container R
## Troubleshooting the GitLab Container Registry
-## Migrating OCI container images to GitLab Container Registry
+### Migrating OCI container images to GitLab Container Registry
Migrating built container images to the GitLab registry is not a current feature. However, an [epic](https://gitlab.com/groups/gitlab-org/-/epics/5210) is open to track the work on this feature.
diff --git a/doc/user/packages/container_registry/reduce_container_registry_data_transfer.md b/doc/user/packages/container_registry/reduce_container_registry_data_transfer.md
index ff89e5f361f..74cbcba2ffc 100644
--- a/doc/user/packages/container_registry/reduce_container_registry_data_transfer.md
+++ b/doc/user/packages/container_registry/reduce_container_registry_data_transfer.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+group: Container 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
---
@@ -90,7 +90,7 @@ build process instead of trying to minify images afterward.
### Use multi-stage builds
-With [multi-stage builds](https://docs.docker.com/develop/develop-images/multistage-build/),
+With [multi-stage builds](https://docs.docker.com/build/building/multi-stage/),
you use multiple `FROM` statements in your Dockerfile. Each `FROM` instruction can use a different
base, and each begins a new build stage. You can selectively copy artifacts from one stage to
another, leaving behind everything you don't want in the final image. This is especially useful when
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 9c981aeac53..23d835ddf5f 100644
--- a/doc/user/packages/container_registry/reduce_container_registry_storage.md
+++ b/doc/user/packages/container_registry/reduce_container_registry_storage.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+group: Container 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
---
diff --git a/doc/user/packages/debian_repository/index.md b/doc/user/packages/debian_repository/index.md
index 90fc0bc3bb1..7db2a341743 100644
--- a/doc/user/packages/debian_repository/index.md
+++ b/doc/user/packages/debian_repository/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/user/packages/dependency_proxy/index.md b/doc/user/packages/dependency_proxy/index.md
index 3fb22437eb0..b7a9729c8ba 100644
--- a/doc/user/packages/dependency_proxy/index.md
+++ b/doc/user/packages/dependency_proxy/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+group: Container 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
---
@@ -299,7 +299,7 @@ hub_docker_quota_check:
## Troubleshooting
-## Authentication error: "HTTP Basic: Access Denied"
+### Authentication error: "HTTP Basic: Access Denied"
If you receive an `HTTP Basic: Access denied` error when authenticating against the Dependency Proxy, refer to the [two-factor authentication troubleshooting guide](../../profile/account/two_factor_authentication.md#troubleshooting).
diff --git a/doc/user/packages/dependency_proxy/reduce_dependency_proxy_storage.md b/doc/user/packages/dependency_proxy/reduce_dependency_proxy_storage.md
index 1239d1a97ae..3aaaf0c0186 100644
--- a/doc/user/packages/dependency_proxy/reduce_dependency_proxy_storage.md
+++ b/doc/user/packages/dependency_proxy/reduce_dependency_proxy_storage.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+group: Container 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
---
diff --git a/doc/user/packages/generic_packages/index.md b/doc/user/packages/generic_packages/index.md
index 930e0760eb3..563f35f2f4f 100644
--- a/doc/user/packages/generic_packages/index.md
+++ b/doc/user/packages/generic_packages/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/user/packages/go_proxy/index.md b/doc/user/packages/go_proxy/index.md
index 6f6dc084720..a147c3656b7 100644
--- a/doc/user/packages/go_proxy/index.md
+++ b/doc/user/packages/go_proxy/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/user/packages/harbor_container_registry/index.md b/doc/user/packages/harbor_container_registry/index.md
index 217d3d57416..f159522d77d 100644
--- a/doc/user/packages/harbor_container_registry/index.md
+++ b/doc/user/packages/harbor_container_registry/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+group: Container 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
---
diff --git a/doc/user/packages/helm_repository/index.md b/doc/user/packages/helm_repository/index.md
index 521f04226df..bba68494c2d 100644
--- a/doc/user/packages/helm_repository/index.md
+++ b/doc/user/packages/helm_repository/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
@@ -134,6 +134,8 @@ for any related errors. If you see `Validation failed: Version is invalid`, it m
version in your `Chart.yaml` file does not follow [Helm Chart versioning specifications](https://helm.sh/docs/topics/charts/#charts-and-versioning).
To fix the error, use the correct version syntax and upload the chart again.
+Support for providing better error messages for package processing errors in the UI is proposed in issue [330515](https://gitlab.com/gitlab-org/gitlab/-/issues/330515).
+
### `helm push` results in an error
Helm 3.7 introduced a breaking change for the `helm-push` plugin. You can update the
diff --git a/doc/user/packages/index.md b/doc/user/packages/index.md
index 84a10943879..7418977e0d1 100644
--- a/doc/user/packages/index.md
+++ b/doc/user/packages/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/user/packages/infrastructure_registry/index.md b/doc/user/packages/infrastructure_registry/index.md
index 8129b42905a..ac31b491a0e 100644
--- a/doc/user/packages/infrastructure_registry/index.md
+++ b/doc/user/packages/infrastructure_registry/index.md
@@ -1,6 +1,6 @@
---
-stage: Configure
-group: Configure
+stage: Package
+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
---
diff --git a/doc/user/packages/maven_repository/index.md b/doc/user/packages/maven_repository/index.md
index ec56255999a..2aa71e111fb 100644
--- a/doc/user/packages/maven_repository/index.md
+++ b/doc/user/packages/maven_repository/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
@@ -14,177 +14,7 @@ Then, install the packages whenever you need to use them as a dependency.
For documentation of the specific API endpoints that the Maven package manager
client uses, see the [Maven API documentation](../../../api/packages/maven.md).
-## Build a Maven package
-
-This section explains how to install Maven and build a package.
-
-If you already use Maven and know how to build your own packages, go to the
-[next section](#authenticate-to-the-package-registry-with-maven).
-
-Maven repositories work well with Gradle, too. To set up a Gradle project, see [get started with Gradle](#build-a-java-project-with-gradle).
-
-### Install Maven
-
-The required minimum versions are:
-
-- Java 11.0.5+
-- Maven 3.6+
-
-Follow the instructions at [maven.apache.org](https://maven.apache.org/install.html)
-to download and install Maven for your local development environment. After
-installation is complete, verify you can use Maven in your terminal by running:
-
-```shell
-mvn --version
-```
-
-The output should be similar to:
-
-```shell
-Apache Maven 3.6.1 (d66c9c0b3152b2e69ee9bac180bb8fcc8e6af555; 2019-04-04T20:00:29+01:00)
-Maven home: /Users/<your_user>/apache-maven-3.6.1
-Java version: 12.0.2, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk-12.0.2.jdk/Contents/Home
-Default locale: en_GB, platform encoding: UTF-8
-OS name: "mac os x", version: "10.15.2", arch: "x86_64", family: "mac"
-```
-
-### Create a project
-
-Follow these steps to create a Maven project that can be
-published to the GitLab Package Registry.
-
-1. Open your terminal and create a directory to store the project.
-1. From the new directory, run this Maven command to initialize a new package:
-
- ```shell
- mvn archetype:generate -DgroupId=com.mycompany.mydepartment -DartifactId=my-project -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
- ```
-
- The arguments are:
-
- - `DgroupId`: A unique string that identifies your package. Follow
- the [Maven naming conventions](https://maven.apache.org/guides/mini/guide-naming-conventions.html).
- - `DartifactId`: The name of the `JAR`, appended to the end of the `DgroupId`.
- - `DarchetypeArtifactId`: The archetype used to create the initial structure of
- the project.
- - `DinteractiveMode`: Create the project using batch mode (optional).
-
-This message indicates that the project was set up successfully:
-
-```shell
-...
-[INFO] ------------------------------------------------------------------------
-[INFO] BUILD SUCCESS
-[INFO] ------------------------------------------------------------------------
-[INFO] Total time: 3.429 s
-[INFO] Finished at: 2020-01-28T11:47:04Z
-[INFO] ------------------------------------------------------------------------
-```
-
-In the folder where you ran the command, a new directory should be displayed.
-The directory name should match the `DartifactId` parameter, which in this case,
-is `my-project`.
-
-## Build a Java project with Gradle
-
-This section explains how to install Gradle and initialize a Java project.
-
-If you already use Gradle and know how to build your own packages, go to the
-[next section](#authenticate-to-the-package-registry-with-maven).
-
-### Install Gradle
-
-If you want to create a new Gradle project, you must install Gradle. Follow
-instructions at [gradle.org](https://gradle.org/install/) to download and install
-Gradle for your local development environment.
-
-In your terminal, verify you can use Gradle by running:
-
-```shell
-gradle -version
-```
-
-To use an existing Gradle project, in the project directory,
-on Linux execute `gradlew`, or on Windows execute `gradlew.bat`.
-
-The output should be similar to:
-
-```plaintext
-------------------------------------------------------------
-Gradle 6.0.1
-------------------------------------------------------------
-
-Build time: 2019-11-18 20:25:01 UTC
-Revision: fad121066a68c4701acd362daf4287a7c309a0f5
-
-Kotlin: 1.3.50
-Groovy: 2.5.8
-Ant: Apache Ant(TM) version 1.10.7 compiled on September 1 2019
-JVM: 11.0.5 (Oracle Corporation 11.0.5+10)
-OS: Windows 10 10.0 amd64
-```
-
-### Create a Java project
-
-Follow these steps to create a Maven project that can be
-published to the GitLab Package Registry.
-
-1. Open your terminal and create a directory to store the project.
-1. From this new directory, run this Maven command to initialize a new package:
-
- ```shell
- gradle init
- ```
-
- The output should be:
-
- ```plaintext
- Select type of project to generate:
- 1: basic
- 2: application
- 3: library
- 4: Gradle plugin
- Enter selection (default: basic) [1..4]
- ```
-
-1. Enter `3` to create a new Library project. The output should be:
-
- ```plaintext
- Select implementation language:
- 1: C++
- 2: Groovy
- 3: Java
- 4: Kotlin
- 5: Scala
- 6: Swift
- ```
-
-1. Enter `3` to create a new Java Library project. The output should be:
-
- ```plaintext
- Select build script DSL:
- 1: Groovy
- 2: Kotlin
- Enter selection (default: Groovy) [1..2]
- ```
-
-1. Enter `1` to create a new Java Library project that is described in Groovy DSL, or `2` to create one that is described in Kotlin DSL. The output should be:
-
- ```plaintext
- Select test framework:
- 1: JUnit 4
- 2: TestNG
- 3: Spock
- 4: JUnit Jupiter
- ```
-
-1. Enter `1` to initialize the project with JUnit 4 testing libraries. The output should be:
-
- ```plaintext
- Project name (default: test):
- ```
-
-1. Enter a project name or press <kbd>Enter</kbd> to use the directory name as project name.
+Learn how to build a [Maven](../workflows/build_packages.md#maven) or [Gradle](../workflows/build_packages.md#gradle) package.
## Authenticate to the Package Registry with Maven
@@ -561,11 +391,11 @@ for download.
**Only packages that have the same path as the project** are exposed by
the instance-level endpoint.
-| Project | Package | Instance-level endpoint available |
-| ------- | ------- | --------------------------------- |
-| `foo/bar` | `foo/bar/1.0-SNAPSHOT` | Yes |
-| `gitlab-org/gitlab` | `foo/bar/1.0-SNAPSHOT` | No |
-| `gitlab-org/gitlab` | `gitlab-org/gitlab/1.0-SNAPSHOT` | Yes |
+| Project | Package | Instance-level endpoint available |
+| ------------------- | -------------------------------- | --------------------------------- |
+| `foo/bar` | `foo/bar/1.0-SNAPSHOT` | Yes |
+| `gitlab-org/gitlab` | `foo/bar/1.0-SNAPSHOT` | No |
+| `gitlab-org/gitlab` | `gitlab-org/gitlab/1.0-SNAPSHOT` | Yes |
This example shows how relevant `repository` section of your `pom.xml`.
You still need a project-specific URL in the `distributionManagement` section.
@@ -838,7 +668,7 @@ dependencies {
### Request forwarding to Maven Central
-> [Introduced](<https://gitlab.com/gitlab-org/gitlab/-/issues/362657>) behind a [feature flag](../../feature_flags.md), disabled by default in GitLab 15.4
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/362657) behind a [feature flag](../../feature_flags.md), disabled by default in GitLab 15.4
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 `maven_central_request_forwarding`.
@@ -1053,20 +883,20 @@ that you can use when performing tasks with GitLab CI/CD.
- Specify where to find the `pom.xml` file (`-f,--file`):
- ```yaml
- package:
- script:
- - 'mvn --no-transfer-progress -f helloworld/pom.xml package'
- ```
+ ```yaml
+ package:
+ script:
+ - 'mvn --no-transfer-progress -f helloworld/pom.xml package'
+ ```
- Specify where to find the user settings (`-s,--settings`) instead of
[the default location](https://maven.apache.org/settings.html). There's also a `-gs,--global-settings` option:
- ```yaml
- package:
- script:
- - 'mvn -s settings/ci.xml package'
- ```
+ ```yaml
+ package:
+ script:
+ - 'mvn -s settings/ci.xml package'
+ ```
### Verify your Maven settings
diff --git a/doc/user/packages/npm_registry/index.md b/doc/user/packages/npm_registry/index.md
index 44266559999..5d2efc52ba9 100644
--- a/doc/user/packages/npm_registry/index.md
+++ b/doc/user/packages/npm_registry/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
@@ -20,72 +20,7 @@ WARNING:
Never hardcode GitLab tokens (or any tokens) directly in `.npmrc` files or any other files that can
be committed to a repository.
-## Build an npm package
-
-This section covers how to install npm or Yarn and build a package for your
-JavaScript project.
-
-If you already use npm and know how to build your own packages, go to
-the [next section](#authenticate-to-the-package-registry).
-
-### Install npm
-
-Install Node.js and npm in your local development environment by following
-the instructions at [npmjs.com](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm/).
-
-When installation is complete, verify you can use npm in your terminal by
-running:
-
-```shell
-npm --version
-```
-
-The npm version is shown in the output:
-
-```plaintext
-6.10.3
-```
-
-### Install Yarn
-
-As an alternative to npm, you can install Yarn in your local environment by following the
-instructions at [classic.yarnpkg.com](https://classic.yarnpkg.com/en/docs/install).
-
-When installation is complete, verify you can use Yarn in your terminal by
-running:
-
-```shell
-yarn --version
-```
-
-The Yarn version is shown in the output:
-
-```plaintext
-1.19.1
-```
-
-### Create a project
-
-To create a project:
-
-1. Create an empty directory.
-1. Go to the directory and initialize an empty package by running:
-
- ```shell
- npm init
- ```
-
- Or if you're using Yarn:
-
- ```shell
- yarn init
- ```
-
-1. Enter responses to the questions. Ensure the **package name** follows
- the [naming convention](#package-naming-convention) and is scoped to the
- project or group where the registry exists.
-
-A `package.json` file is created.
+Learn how to build an [npm](../workflows/build_packages.md#npm) or [yarn](../workflows/build_packages.md#yarn) package.
## Use the GitLab endpoint for npm packages
@@ -244,15 +179,15 @@ In this case, the `@scope` needs to be `@registries-group` and not `@source-code
For example, if your project is `https://gitlab.example.com/my-org/engineering-group/team-amazing/analytics`,
the root namespace is `my-org`. When you publish a package, it must have `my-org` as the scope.
-| Project | Package | Supported |
-| ---------------------- | ----------------------- | --------- |
-| `my-org/bar` | `@my-org/bar` | Yes |
-| `my-org/bar/baz` | `@my-org/baz` | Yes |
-| `My-Org/Bar/baz` | `@my-org/Baz` | Yes |
-| `My-Org/Bar/baz` | `@My-Org/Baz` | Yes |
-| `my-org/bar/buz` | `@my-org/anything` | Yes |
-| `gitlab-org/gitlab` | `@gitlab-org/gitlab` | Yes |
-| `gitlab-org/gitlab` | `@foo/bar` | No |
+| Project | Package | Supported |
+| ------------------- | -------------------- | --------- |
+| `my-org/bar` | `@my-org/bar` | Yes |
+| `my-org/bar/baz` | `@my-org/baz` | Yes |
+| `My-Org/Bar/baz` | `@my-org/Baz` | Yes |
+| `My-Org/Bar/baz` | `@My-Org/Baz` | Yes |
+| `my-org/bar/buz` | `@my-org/anything` | Yes |
+| `gitlab-org/gitlab` | `@gitlab-org/gitlab` | Yes |
+| `gitlab-org/gitlab` | `@foo/bar` | No |
In GitLab, this regex validates all package names from all package managers:
@@ -290,7 +225,9 @@ You can also define `"publishConfig"` for your project in `package.json`. For ex
```json
{
-"publishConfig": { "@foo:registry":" https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/" }
+ "publishConfig": {
+ "@foo:registry": " https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/"
+ }
}
```
@@ -342,13 +279,13 @@ To publish and install with the project-level npm endpoint, set the following co
```yaml
npmScopes:
foo:
- npmRegistryServer: "https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/"
- npmPublishRegistry: "https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/"
+ npmRegistryServer: 'https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/'
+ npmPublishRegistry: 'https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/'
npmRegistries:
//gitlab.example.com/api/v4/projects/<your_project_id>/packages/npm/:
npmAlwaysAuth: true
- npmAuthToken: "<your_token>"
+ npmAuthToken: '<your_token>'
```
For the instance-level npm endpoint, use this Yarn 2 configuration in `.yarnrc.yml`:
@@ -356,12 +293,12 @@ For the instance-level npm endpoint, use this Yarn 2 configuration in `.yarnrc.y
```yaml
npmScopes:
foo:
- npmRegistryServer: "https://gitlab.example.com/api/v4/packages/npm/"
+ npmRegistryServer: 'https://gitlab.example.com/api/v4/packages/npm/'
npmRegistries:
//gitlab.example.com/api/v4/packages/npm/:
npmAlwaysAuth: true
- npmAuthToken: "<your_token>"
+ npmAuthToken: '<your_token>'
```
In this configuration:
@@ -561,7 +498,7 @@ should look like:
{
"name": "@foo/my-package",
"version": "1.0.0",
- "description": "Example package for GitLab npm registry",
+ "description": "Example package for GitLab npm registry"
}
```
diff --git a/doc/user/packages/nuget_repository/index.md b/doc/user/packages/nuget_repository/index.md
index d4b87d70447..956202bb990 100644
--- a/doc/user/packages/nuget_repository/index.md
+++ b/doc/user/packages/nuget_repository/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
@@ -22,47 +22,7 @@ The Package Registry works with:
For documentation of the specific API endpoints that these
clients use, see the [NuGet API documentation](../../../api/packages/nuget.md).
-## Install NuGet
-
-The required minimum versions are:
-
-- [NuGet CLI 5.1 or later](https://www.nuget.org/downloads). If you have
- [Visual Studio](https://visualstudio.microsoft.com/vs/), the NuGet CLI is
- probably already installed.
-- Alternatively, you can use [.NET SDK 3.0 or later](https://dotnet.microsoft.com/download/dotnet/3.0),
- which installs the NuGet CLI.
-- NuGet protocol version 3 or later.
-
-Verify that the [NuGet CLI](https://www.nuget.org/) is installed by running:
-
-```shell
-nuget help
-```
-
-The output should be similar to:
-
-```plaintext
-NuGet Version: 5.1.0.6013
-usage: NuGet <command> [args] [options]
-Type 'NuGet help <command>' for help on a specific command.
-
-Available commands:
-
-[output truncated]
-```
-
-### Install NuGet on macOS
-
-For macOS, you can use [Mono](https://www.mono-project.com/) to run the
-NuGet CLI.
-
-1. If you use Homebrew, to install Mono, run `brew install mono`.
-1. Download the Windows C# binary `nuget.exe` from the [NuGet CLI page](https://www.nuget.org/downloads).
-1. Run this command:
-
- ```shell
- mono nuget.exe
- ```
+Learn how to [install NuGet](../workflows/build_packages.md#nuget).
## Use the GitLab endpoint for NuGet Packages
@@ -162,6 +122,7 @@ To use the [project-level](#use-the-gitlab-endpoint-for-nuget-packages) NuGet en
1. In the **NuGet** section, select **Sources** to view a list of all your NuGet sources.
1. Select **Add**.
1. Complete the following fields:
+
- **Name**: Name for the source.
- **Location**: `https://gitlab.example.com/api/v4/projects/<your_project_id>/packages/nuget/index.json`,
where `<your_project_id>` is your project ID, and `gitlab.example.com` is
@@ -191,6 +152,7 @@ To use the [group-level](#use-the-gitlab-endpoint-for-nuget-packages) NuGet endp
1. In the **NuGet** section, select **Sources** to view a list of all your NuGet sources.
1. Select **Add**.
1. Complete the following fields:
+
- **Name**: Name for the source.
- **Location**: `https://gitlab.example.com/api/v4/groups/<your_group_id>/-/packages/nuget/index.json`,
where `<your_group_id>` is your group ID, and `gitlab.example.com` is
diff --git a/doc/user/packages/package_registry/index.md b/doc/user/packages/package_registry/index.md
index 2d8cb46f933..8e160cbb195 100644
--- a/doc/user/packages/package_registry/index.md
+++ b/doc/user/packages/package_registry/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
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 e6996d9dc3e..1085cf5c239 100644
--- a/doc/user/packages/package_registry/reduce_package_registry_storage.md
+++ b/doc/user/packages/package_registry/reduce_package_registry_storage.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/user/packages/pypi_repository/index.md b/doc/user/packages/pypi_repository/index.md
index fb1b9ce78ab..f6ed9654882 100644
--- a/doc/user/packages/pypi_repository/index.md
+++ b/doc/user/packages/pypi_repository/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
@@ -20,148 +20,7 @@ The Package Registry works with:
For documentation of the specific API endpoints that the `pip` and `twine`
clients use, see the [PyPI API documentation](../../../api/packages/pypi.md).
-## Build a PyPI package
-
-This section explains how to create a PyPI package.
-
-If you already use PyPI and know how to build your own packages, go to the
-[next section](#authenticate-with-the-package-registry).
-
-### Install pip and twine
-
-Install a recent version of [pip](https://pypi.org/project/pip/) and
-[twine](https://pypi.org/project/twine/).
-
-### Create a project
-
-Create a test project.
-
-1. Open your terminal.
-1. Create a directory called `MyPyPiPackage`, and then go to that directory:
-
- ```shell
- mkdir MyPyPiPackage && cd MyPyPiPackage
- ```
-
-1. Create another directory and go to it:
-
- ```shell
- mkdir mypypipackage && cd mypypipackage
- ```
-
-1. Create the required files in this directory:
-
- ```shell
- touch __init__.py
- touch greet.py
- ```
-
-1. Open the `greet.py` file, and then add:
-
- ```python
- def SayHello():
- print("Hello from MyPyPiPackage")
- return
- ```
-
-1. Open the `__init__.py` file, and then add:
-
- ```python
- from .greet import SayHello
- ```
-
-1. To test the code, in your `MyPyPiPackage` directory, start the Python prompt.
-
- ```shell
- python
- ```
-
-1. Run this command:
-
- ```python
- >>> from mypypipackage import SayHello
- >>> SayHello()
- ```
-
-A message indicates that the project was set up successfully:
-
-```plaintext
-Python 3.8.2 (v3.8.2:7b3ab5921f, Feb 24 2020, 17:52:18)
-[Clang 6.0 (clang-600.0.57)] on darwin
-Type "help", "copyright", "credits" or "license" for more information.
->>> from mypypipackage import SayHello
->>> SayHello()
-Hello from MyPyPiPackage
-```
-
-### Create a package
-
-After you create a project, you can create a package.
-
-1. In your terminal, go to the `MyPyPiPackage` directory.
-1. Create a `pyproject.toml` file:
-
- ```shell
- touch pyproject.toml
- ```
-
- This file contains all the information about the package. For more information
- about this file, see [creating `pyproject.toml`](https://packaging.python.org/en/latest/tutorials/packaging-projects/#creating-pyproject-toml).
- Because GitLab identifies packages based on
- [Python normalized names (PEP-503)](https://www.python.org/dev/peps/pep-0503/#normalized-names),
- ensure your package name meets these requirements. See the [installation section](#authenticate-with-a-ci-job-token)
- for details.
-
-1. Open the `pyproject.toml` file, and then add basic information:
-
- ```toml
- [build-system]
- requires = ["setuptools>=61.0"]
- build-backend = "setuptools.build_meta"
-
- [project]
- name = "mypypipackage"
- version = "0.0.1"
- authors = [
- { name="Example Author", email="author@example.com" },
- ]
- description = "A small example package"
- requires-python = ">=3.7"
- classifiers = [
- "Programming Language :: Python :: 3",
- "Operating System :: OS Independent",
- ]
-
- [tool.setuptools.packages]
- find = {}
- ```
-
-1. Save the file.
-1. Install the package build library:
-
- ```shell
- pip install build
- ```
-
-1. Build the package:
-
- ```shell
- python -m build
- ```
-
-The output should be visible in a newly-created `dist` folder:
-
-```shell
-ls dist
-```
-
-The output should appear similar to the following:
-
-```plaintext
-mypypipackage-0.0.1-py3-none-any.whl mypypipackage-0.0.1.tar.gz
-```
-
-The package is now ready to be published to the Package Registry.
+Learn how to [build a PyPI package](../workflows/build_packages.md#pypi).
## Authenticate with the Package Registry
diff --git a/doc/user/packages/rubygems_registry/index.md b/doc/user/packages/rubygems_registry/index.md
index f21b210f4f5..7710ad3db01 100644
--- a/doc/user/packages/rubygems_registry/index.md
+++ b/doc/user/packages/rubygems_registry/index.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/user/packages/terraform_module_registry/index.md b/doc/user/packages/terraform_module_registry/index.md
index 6dd118c39b4..2b99ff807ec 100644
--- a/doc/user/packages/terraform_module_registry/index.md
+++ b/doc/user/packages/terraform_module_registry/index.md
@@ -1,6 +1,6 @@
---
-stage: Configure
-group: Configure
+stage: Package
+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
---
@@ -24,9 +24,11 @@ When you publish a Terraform Module, if it does not exist, it is created.
Prerequisites:
-- A package with the same name and version must not already exist in the top-level namespace.
+- The package name and version [must be unique in the top-level namespace](../infrastructure_registry/index.md#how-module-resolution-works).
- Your project and group names must not include a dot (`.`). For example, `source = "gitlab.example.com/my.group/project.name"`.
- You must [authenticate with the API](../../../api/index.md#authentication). If authenticating with a deploy token, it must be configured with the `write_package_registry` scope.
+- The name of a module [must be unique within the scope of its group](../infrastructure_registry/index.md#how-module-resolution-works), otherwise an
+ [error occurs](#troubleshooting).
```plaintext
PUT /projects/:id/packages/terraform/modules/:module-name/:module-system/:module-version/file
@@ -141,3 +143,7 @@ For examples of the Terraform module registry, check the projects below:
- The [_GitLab local file_ project](https://gitlab.com/mattkasa/gitlab-local-file) creates a minimal Terraform module and uploads it into the Terraform module registry using GitLab CI/CD.
- The [_Terraform module test_ project](https://gitlab.com/mattkasa/terraform-module-test) uses the module from the previous example.
+
+## Troubleshooting
+
+- Publishing a module with a duplicate name results in a `{"message":"Access Denied"}` error. There's an ongoing discussion about allowing duplicate module names [in this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/368040).
diff --git a/doc/user/packages/workflows/build_packages.md b/doc/user/packages/workflows/build_packages.md
new file mode 100644
index 00000000000..ec971195ea9
--- /dev/null
+++ b/doc/user/packages/workflows/build_packages.md
@@ -0,0 +1,504 @@
+---
+stage: Package
+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
+---
+
+# Build packages
+
+Learn how to install and build packages different package formats.
+
+- [Composer](#composer)
+- [Conan](#conan)
+- [Maven](#maven)
+- [Gradle](#gradle)
+- [npm](#npm)
+- [Yarn](#yarn)
+- [NuGet](#nuget)
+- [PyPI](#pypi)
+
+## Composer
+
+1. Create a directory called `my-composer-package` and change to that directory:
+
+ ```shell
+ mkdir my-composer-package && cd my-composer-package
+ ```
+
+1. Run [`composer init`](https://getcomposer.org/doc/03-cli.md#init) and answer the prompts.
+
+ For namespace, enter your unique [namespace](../../../user/namespace/index.md), like your GitLab username or group name.
+
+ A file called `composer.json` is created:
+
+ ```json
+ {
+ "name": "<namespace>/composer-test",
+ "description": "Library XY",
+ "type": "library",
+ "license": "GPL-3.0-only",
+ "authors": [
+ {
+ "name": "John Doe",
+ "email": "john@example.com"
+ }
+ ],
+ "require": {}
+ }
+ ```
+
+## Conan
+
+### Install Conan
+
+Download the Conan package manager to your local development environment by
+following the instructions at [conan.io](https://conan.io/downloads.html).
+
+When installation is complete, verify you can use Conan in your terminal by
+running:
+
+```shell
+conan --version
+```
+
+The Conan version is printed in the output:
+
+```plaintext
+Conan version 1.20.5
+```
+
+### Install CMake
+
+When you develop with C++ and Conan, you can select from many available
+compilers. This example uses the CMake build system generator.
+
+To install CMake:
+
+- For Mac, use [Homebrew](https://brew.sh/) and run `brew install cmake`.
+- For other operating systems, follow the instructions at [cmake.org](https://cmake.org/install/).
+
+When installation is complete, verify you can use CMake in your terminal by
+running:
+
+```shell
+cmake --version
+```
+
+The CMake version is printed in the output.
+
+### Create a project
+
+To test the Package Registry, you need a C++ project. If you don't already have
+one, you can clone the Conan [hello world starter project](https://github.com/conan-io/hello).
+
+### Build a Conan package
+
+To build a package:
+
+1. Open a terminal and navigate to your project's root folder.
+1. Generate a new recipe by running `conan new` with a package name and version:
+
+ ```shell
+ conan new Hello/0.1 -t
+ ```
+
+1. Create a package for the recipe by running `conan create` with the Conan user
+ and channel:
+
+ ```shell
+ conan create . mycompany/beta
+ ```
+
+ NOTE:
+ If you use an [instance remote](../conan_repository/index.md#add-a-remote-for-your-instance), you must
+ follow a specific [naming convention](../conan_repository/index.md#package-recipe-naming-convention-for-instance-remotes).
+
+A package with the recipe `Hello/0.1@mycompany/beta` is created.
+
+For more details about creating and managing Conan packages, see the
+[Conan documentation](https://docs.conan.io/en/latest/creating_packages.html).
+
+## Maven
+
+### Install Maven
+
+The required minimum versions are:
+
+- Java 11.0.5+
+- Maven 3.6+
+
+Follow the instructions at [maven.apache.org](https://maven.apache.org/install.html)
+to download and install Maven for your local development environment. After
+installation is complete, verify you can use Maven in your terminal by running:
+
+```shell
+mvn --version
+```
+
+The output should be similar to:
+
+```shell
+Apache Maven 3.6.1 (d66c9c0b3152b2e69ee9bac180bb8fcc8e6af555; 2019-04-04T20:00:29+01:00)
+Maven home: /Users/<your_user>/apache-maven-3.6.1
+Java version: 12.0.2, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk-12.0.2.jdk/Contents/Home
+Default locale: en_GB, platform encoding: UTF-8
+OS name: "mac os x", version: "10.15.2", arch: "x86_64", family: "mac"
+```
+
+### Build a Maven package
+
+1. Open your terminal and create a directory to store the project.
+1. From the new directory, run this Maven command to initialize a new package:
+
+ ```shell
+ mvn archetype:generate -DgroupId=com.mycompany.mydepartment -DartifactId=my-project -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
+ ```
+
+ The arguments are:
+
+ - `DgroupId`: A unique string that identifies your package. Follow
+ the [Maven naming conventions](https://maven.apache.org/guides/mini/guide-naming-conventions.html).
+ - `DartifactId`: The name of the `JAR`, appended to the end of the `DgroupId`.
+ - `DarchetypeArtifactId`: The archetype used to create the initial structure of
+ the project.
+ - `DinteractiveMode`: Create the project using batch mode (optional).
+
+This message indicates that the project was set up successfully:
+
+```shell
+...
+[INFO] ------------------------------------------------------------------------
+[INFO] BUILD SUCCESS
+[INFO] ------------------------------------------------------------------------
+[INFO] Total time: 3.429 s
+[INFO] Finished at: 2020-01-28T11:47:04Z
+[INFO] ------------------------------------------------------------------------
+```
+
+In the folder where you ran the command, a new directory should be displayed.
+The directory name should match the `DartifactId` parameter, which in this case,
+is `my-project`.
+
+## Gradle
+
+### Install Gradle
+
+If you want to create a new Gradle project, you must install Gradle. Follow
+instructions at [gradle.org](https://gradle.org/install/) to download and install
+Gradle for your local development environment.
+
+In your terminal, verify you can use Gradle by running:
+
+```shell
+gradle -version
+```
+
+To use an existing Gradle project, in the project directory,
+on Linux execute `gradlew`, or on Windows execute `gradlew.bat`.
+
+The output should be similar to:
+
+```plaintext
+------------------------------------------------------------
+Gradle 6.0.1
+------------------------------------------------------------
+
+Build time: 2019-11-18 20:25:01 UTC
+Revision: fad121066a68c4701acd362daf4287a7c309a0f5
+
+Kotlin: 1.3.50
+Groovy: 2.5.8
+Ant: Apache Ant(TM) version 1.10.7 compiled on September 1 2019
+JVM: 11.0.5 (Oracle Corporation 11.0.5+10)
+OS: Windows 10 10.0 amd64
+```
+
+### Create a package
+
+1. Open your terminal and create a directory to store the project.
+1. From this new directory, run this command to initialize a new package:
+
+ ```shell
+ gradle init
+ ```
+
+ The output should be:
+
+ ```plaintext
+ Select type of project to generate:
+ 1: basic
+ 2: application
+ 3: library
+ 4: Gradle plugin
+ Enter selection (default: basic) [1..4]
+ ```
+
+1. Enter `3` to create a new Library project. The output should be:
+
+ ```plaintext
+ Select implementation language:
+ 1: C++
+ 2: Groovy
+ 3: Java
+ 4: Kotlin
+ 5: Scala
+ 6: Swift
+ ```
+
+1. Enter `3` to create a new Java Library project. The output should be:
+
+ ```plaintext
+ Select build script DSL:
+ 1: Groovy
+ 2: Kotlin
+ Enter selection (default: Groovy) [1..2]
+ ```
+
+1. Enter `1` to create a new Java Library project that is described in Groovy DSL, or `2` to create one that is described in Kotlin DSL. The output should be:
+
+ ```plaintext
+ Select test framework:
+ 1: JUnit 4
+ 2: TestNG
+ 3: Spock
+ 4: JUnit Jupiter
+ ```
+
+1. Enter `1` to initialize the project with JUnit 4 testing libraries. The output should be:
+
+ ```plaintext
+ Project name (default: test):
+ ```
+
+1. Enter a project name or press <kbd>Enter</kbd> to use the directory name as project name.
+
+## npm
+
+### Install npm
+
+Install Node.js and npm in your local development environment by following
+the instructions at [npmjs.com](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm/).
+
+When installation is complete, verify you can use npm in your terminal by
+running:
+
+```shell
+npm --version
+```
+
+The npm version is shown in the output:
+
+```plaintext
+6.10.3
+```
+
+### Create an npm package
+
+1. Create an empty directory.
+1. Go to the directory and initialize an empty package by running:
+
+ ```shell
+ npm init
+ ```
+
+1. Enter responses to the questions. Ensure the **package name** follows
+ the [naming convention](../npm_registry/index.md#package-naming-convention) and is scoped to the project or group where the registry exists.
+
+## Yarn
+
+### Install Yarn
+
+As an alternative to npm, you can install Yarn in your local environment by following the
+instructions at [classic.yarnpkg.com](https://classic.yarnpkg.com/en/docs/install).
+
+When installation is complete, verify you can use Yarn in your terminal by
+running:
+
+```shell
+yarn --version
+```
+
+The Yarn version is shown in the output:
+
+```plaintext
+1.19.1
+```
+
+### Create a package
+
+1. Create an empty directory.
+1. Go to the directory and initialize an empty package by running:
+
+ ```shell
+ yarn init
+ ```
+
+1. Enter responses to the questions. Ensure the **package name** follows
+ the [naming convention](../npm_registry/index.md#package-naming-convention) and is scoped to the
+ project or group where the registry exists.
+
+A `package.json` file is created.
+
+## NuGet
+
+### Install NuGet
+
+Follow the instructions from [Microsoft](https://learn.microsoft.com/en-us/nuget/install-nuget-client-tools) to install NuGet. If you have
+[Visual Studio](https://visualstudio.microsoft.com/vs/), NuGet is
+probably already installed.
+
+Verify that the [NuGet CLI](https://www.nuget.org/) is installed by running:
+
+```shell
+nuget help
+```
+
+The output should be similar to:
+
+```plaintext
+NuGet Version: 5.1.0.6013
+usage: NuGet <command> [args] [options]
+Type 'NuGet help <command>' for help on a specific command.
+
+Available commands:
+
+[output truncated]
+```
+
+## PyPI
+
+### Install pip and twine
+
+Install a recent version of [pip](https://pypi.org/project/pip/) and
+[twine](https://pypi.org/project/twine/).
+
+### Create a project
+
+Create a test project.
+
+1. Open your terminal.
+1. Create a directory called `MyPyPiPackage`, and then go to that directory:
+
+ ```shell
+ mkdir MyPyPiPackage && cd MyPyPiPackage
+ ```
+
+1. Create another directory and go to it:
+
+ ```shell
+ mkdir mypypipackage && cd mypypipackage
+ ```
+
+1. Create the required files in this directory:
+
+ ```shell
+ touch __init__.py
+ touch greet.py
+ ```
+
+1. Open the `greet.py` file, and then add:
+
+ ```python
+ def SayHello():
+ print("Hello from MyPyPiPackage")
+ return
+ ```
+
+1. Open the `__init__.py` file, and then add:
+
+ ```python
+ from .greet import SayHello
+ ```
+
+1. To test the code, in your `MyPyPiPackage` directory, start the Python prompt.
+
+ ```shell
+ python
+ ```
+
+1. Run this command:
+
+ ```python
+ >>> from mypypipackage import SayHello
+ >>> SayHello()
+ ```
+
+A message indicates that the project was set up successfully:
+
+```plaintext
+Python 3.8.2 (v3.8.2:7b3ab5921f, Feb 24 2020, 17:52:18)
+[Clang 6.0 (clang-600.0.57)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> from mypypipackage import SayHello
+>>> SayHello()
+Hello from MyPyPiPackage
+```
+
+### Create a PyPI package
+
+After you create a project, you can create a package.
+
+1. In your terminal, go to the `MyPyPiPackage` directory.
+1. Create a `pyproject.toml` file:
+
+ ```shell
+ touch pyproject.toml
+ ```
+
+ This file contains all the information about the package. For more information
+ about this file, see [creating `pyproject.toml`](https://packaging.python.org/en/latest/tutorials/packaging-projects/#creating-pyproject-toml).
+ Because GitLab identifies packages based on
+ [Python normalized names (PEP-503)](https://www.python.org/dev/peps/pep-0503/#normalized-names),
+ ensure your package name meets these requirements. See the [installation section](../pypi_repository/index.md#authenticate-with-a-ci-job-token)
+ for details.
+
+1. Open the `pyproject.toml` file, and then add basic information:
+
+ ```toml
+ [build-system]
+ requires = ["setuptools>=61.0"]
+ build-backend = "setuptools.build_meta"
+
+ [project]
+ name = "mypypipackage"
+ version = "0.0.1"
+ authors = [
+ { name="Example Author", email="author@example.com" },
+ ]
+ description = "A small example package"
+ requires-python = ">=3.7"
+ classifiers = [
+ "Programming Language :: Python :: 3",
+ "Operating System :: OS Independent",
+ ]
+
+ [tool.setuptools.packages]
+ find = {}
+ ```
+
+1. Save the file.
+1. Install the package build library:
+
+ ```shell
+ pip install build
+ ```
+
+1. Build the package:
+
+ ```shell
+ python -m build
+ ```
+
+The output should be visible in a newly-created `dist` folder:
+
+```shell
+ls dist
+```
+
+The output should appear similar to the following:
+
+```plaintext
+mypypipackage-0.0.1-py3-none-any.whl mypypipackage-0.0.1.tar.gz
+```
+
+The package is now ready to be published to the Package Registry.
diff --git a/doc/user/packages/workflows/project_registry.md b/doc/user/packages/workflows/project_registry.md
index 25c64c93b73..df4b087f6d5 100644
--- a/doc/user/packages/workflows/project_registry.md
+++ b/doc/user/packages/workflows/project_registry.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/user/packages/workflows/working_with_monorepos.md b/doc/user/packages/workflows/working_with_monorepos.md
index 5606e257ea8..572cd309e67 100644
--- a/doc/user/packages/workflows/working_with_monorepos.md
+++ b/doc/user/packages/workflows/working_with_monorepos.md
@@ -1,6 +1,6 @@
---
stage: Package
-group: Package
+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
---
diff --git a/doc/user/permissions.md b/doc/user/permissions.md
index 102abf2b427..8e152a8c190 100644
--- a/doc/user/permissions.md
+++ b/doc/user/permissions.md
@@ -64,7 +64,7 @@ The following table lists project permissions available for each role:
| [Analytics](analytics/index.md):<br>View [code review analytics](analytics/code_review_analytics.md) | | ✓ | ✓ | ✓ | ✓ |
| [Analytics](analytics/index.md):<br>View [repository analytics](analytics/repository_analytics.md) | | ✓ | ✓ | ✓ | ✓ |
| [Application security](application_security/index.md):<br>View licenses in [dependency list](application_security/dependency_list/index.md) | | | ✓ | ✓ | ✓ |
-| [Application security](application_security/index.md):<br>Create and run [on-demand DAST scans](application_security/dast/index.md#on-demand-scans) | | | ✓ | ✓ | ✓ |
+| [Application security](application_security/index.md):<br>Create and run [on-demand DAST scans](application_security/dast/proxy-based.md#on-demand-scans) | | | ✓ | ✓ | ✓ |
| [Application security](application_security/index.md):<br>Manage [security policy](application_security/policies/index.md) | | | ✓ | ✓ | ✓ |
| [Application security](application_security/index.md):<br>View [dependency list](application_security/dependency_list/index.md) | | | ✓ | ✓ | ✓ |
| [Application security](application_security/index.md):<br>Create a [CVE ID Request](application_security/cve_id_request.md) | | | | ✓ | ✓ |
@@ -73,16 +73,17 @@ The following table lists project permissions available for each role:
| [Clusters](infrastructure/clusters/index.md):<br>Manage clusters | | | | ✓ | ✓ |
| [Container Registry](packages/container_registry/index.md):<br>Create, edit, delete [cleanup policies](packages/container_registry/index.md#delete-images-by-using-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 | ✓ (*20*) | ✓ (*20*) | ✓ | ✓ | ✓ |
+| [Container Registry](packages/container_registry/index.md):<br>Pull an image from the Container Registry | ✓ (*19*) | ✓ (*19*) | ✓ | ✓ | ✓ |
| [Container Registry](packages/container_registry/index.md):<br>Remove a Container Registry image | | | ✓ | ✓ | ✓ |
-| [GitLab Pages](project/pages/index.md):<br>View Pages protected by [access control](project/pages/introduction.md#gitlab-pages-access-control) | ✓ | ✓ | ✓ | ✓ | ✓ |
+| [GitLab Pages](project/pages/index.md):<br>View Pages protected by [access control](project/pages/pages_access_control.md) | ✓ | ✓ | ✓ | ✓ | ✓ |
| [GitLab Pages](project/pages/index.md):<br>Manage | | | | ✓ | ✓ |
| [GitLab Pages](project/pages/index.md):<br>Manage GitLab Pages domains and certificates | | | | ✓ | ✓ |
| [GitLab Pages](project/pages/index.md):<br>Remove GitLab Pages | | | | ✓ | ✓ |
| [Incident Management](../operations/incident_management/index.md):<br>View [alerts](../operations/incident_management/alerts.md) | | ✓ | ✓ | ✓ | ✓ |
| [Incident Management](../operations/incident_management/index.md):<br>Assign an alert | ✓ | ✓ | ✓ | ✓ | ✓ |
+| [Incident Management](../operations/incident_management/index.md):<br>[Change an alert status](../operations/incident_management/alerts.md#change-an-alerts-status) | | ✓ | ✓ | ✓ | ✓ |
| [Incident Management](../operations/incident_management/index.md):<br>View [incident](../operations/incident_management/incidents.md) | ✓ | ✓ | ✓ | ✓ | ✓ |
-| [Incident Management](../operations/incident_management/index.md):<br>Create [incident](../operations/incident_management/incidents.md) | (*16*) | ✓ | ✓ | ✓ | ✓ |
+| [Incident Management](../operations/incident_management/index.md):<br>Create [incident](../operations/incident_management/incidents.md) | | ✓ | ✓ | ✓ | ✓ |
| [Incident Management](../operations/incident_management/index.md):<br>View [on-call schedules](../operations/incident_management/oncall_schedules.md) | | ✓ | ✓ | ✓ | ✓ |
| [Incident Management](../operations/incident_management/index.md):<br>Participate in on-call rotation | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Incident Management](../operations/incident_management/index.md):<br>View [escalation policies](../operations/incident_management/escalation_policies.md) | | ✓ | ✓ | ✓ | ✓ |
@@ -91,16 +92,16 @@ The following table lists project permissions available for each role:
| [Issue boards](project/issue_board.md):<br>Create or delete lists | | ✓ | ✓ | ✓ | ✓ |
| [Issue boards](project/issue_board.md):<br>Move issues between lists | | ✓ | ✓ | ✓ | ✓ |
| [Issues](project/issues/index.md):<br>Add Labels | ✓ (*15*) | ✓ | ✓ | ✓ | ✓ |
-| [Issues](project/issues/index.md):<br>Add to epic | | ✓ (*23*) | ✓ (*23*) | ✓ (*23*) | ✓ (*23*) |
+| [Issues](project/issues/index.md):<br>Add to epic | | ✓ (*22*) | ✓ (*22*) | ✓ (*22*) | ✓ (*22*) |
| [Issues](project/issues/index.md):<br>Assign | ✓ (*15*) | ✓ | ✓ | ✓ | ✓ |
-| [Issues](project/issues/index.md):<br>Create (*18*) | ✓ | ✓ | ✓ | ✓ | ✓ |
+| [Issues](project/issues/index.md):<br>Create (*17*) | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Issues](project/issues/index.md):<br>Create [confidential issues](project/issues/confidential_issues.md) | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Issues](project/issues/index.md):<br>View [Design Management](project/issues/design_management.md) pages | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Issues](project/issues/index.md):<br>View [related issues](project/issues/related_issues.md) | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Issues](project/issues/index.md):<br>Set [weight](project/issues/issue_weight.md) | ✓ (*15*) | ✓ | ✓ | ✓ | ✓ |
| [Issues](project/issues/index.md):<br>Set [parent epic](group/epics/manage_epics.md#add-an-existing-issue-to-an-epic) | | ✓ | ✓ | ✓ | ✓ |
| [Issues](project/issues/index.md):<br>View [confidential issues](project/issues/confidential_issues.md) | (*2*) | ✓ | ✓ | ✓ | ✓ |
-| [Issues](project/issues/index.md):<br>Close / reopen (*19*) | | ✓ | ✓ | ✓ | ✓ |
+| [Issues](project/issues/index.md):<br>Close / reopen (*18*) | | ✓ | ✓ | ✓ | ✓ |
| [Issues](project/issues/index.md):<br>Lock threads | | ✓ | ✓ | ✓ | ✓ |
| [Issues](project/issues/index.md):<br>Manage [related issues](project/issues/related_issues.md) | | ✓ | ✓ | ✓ | ✓ |
| [Issues](project/issues/index.md):<br>Manage tracker | | ✓ | ✓ | ✓ | ✓ |
@@ -118,7 +119,7 @@ The following table lists project permissions available for each role:
| [Merge requests](project/merge_requests/index.md):<br>Apply code change suggestions | | | ✓ | ✓ | ✓ |
| [Merge requests](project/merge_requests/index.md):<br>Approve (*8*) | | | ✓ | ✓ | ✓ |
| [Merge requests](project/merge_requests/index.md):<br>Assign | | | ✓ | ✓ | ✓ |
-| [Merge requests](project/merge_requests/index.md):<br>Create (*17*) | | | ✓ | ✓ | ✓ |
+| [Merge requests](project/merge_requests/index.md):<br>Create (*16*) | | | ✓ | ✓ | ✓ |
| [Merge requests](project/merge_requests/index.md):<br>Add labels | | | ✓ | ✓ | ✓ |
| [Merge requests](project/merge_requests/index.md):<br>Lock threads | | | ✓ | ✓ | ✓ |
| [Merge requests](project/merge_requests/index.md):<br>Manage or accept | | | ✓ | ✓ | ✓ |
@@ -153,7 +154,7 @@ The following table lists project permissions available for each role:
| [Projects](project/index.md):<br>View project [Audit Events](../administration/audit_events.md) | | | ✓ (*10*) | ✓ | ✓ |
| [Projects](project/index.md):<br>Add [deploy keys](project/deploy_keys/index.md) | | | | ✓ | ✓ |
| [Projects](project/index.md):<br>Add new [team members](project/members/index.md) | | | | ✓ | ✓ |
-| [Projects](project/index.md):<br>Manage [team members](project/members/index.md) | | | | ✓ (*21*) | ✓ |
+| [Projects](project/index.md):<br>Manage [team members](project/members/index.md) | | | | ✓ (*20*) | ✓ |
| [Projects](project/index.md):<br>Change [project features visibility](public_access.md) level | | | | ✓ (*13*) | ✓ |
| [Projects](project/index.md):<br>Configure [webhooks](project/integrations/webhooks.md) | | | | ✓ | ✓ |
| [Projects](project/index.md):<br>Delete [wiki](project/wiki/index.md) pages | | | ✓ | ✓ | ✓ |
@@ -161,7 +162,7 @@ The following table lists project permissions available for each role:
| [Projects](project/index.md):<br>Edit project badges | | | | ✓ | ✓ |
| [Projects](project/index.md):<br>Edit project settings | | | | ✓ | ✓ |
| [Projects](project/index.md):<br>Export project | | | | ✓ | ✓ |
-| [Projects](project/index.md):<br>Manage [project access tokens](project/settings/project_access_tokens.md) (*11*) | | | | ✓ (*21*) | ✓ |
+| [Projects](project/index.md):<br>Manage [project access tokens](project/settings/project_access_tokens.md) (*11*) | | | | ✓ (*20*) | ✓ |
| [Projects](project/index.md):<br>Manage [Project Operations](../operations/index.md) | | | | ✓ | ✓ |
| [Projects](project/index.md):<br>Rename project | | | | ✓ | ✓ |
| [Projects](project/index.md):<br>Share (invite) projects with groups | | | | ✓ (*7*) | ✓ (*7*) |
@@ -203,10 +204,10 @@ The following table lists project permissions available for each role:
| [Security dashboard](application_security/security_dashboard/index.md):<br>Use security dashboard | | | ✓ | ✓ | ✓ |
| [Security dashboard](application_security/security_dashboard/index.md):<br>View vulnerability | | | ✓ | ✓ | ✓ |
| [Security dashboard](application_security/security_dashboard/index.md):<br>View vulnerability findings in [dependency list](application_security/dependency_list/index.md) | | | ✓ | ✓ | ✓ |
-| [Tasks](tasks.md):<br>Create (*18*) | ✓ | ✓ | ✓ | ✓ | ✓ |
+| [Tasks](tasks.md):<br>Create (*17*) | ✓ | ✓ | ✓ | ✓ | ✓ |
| [Tasks](tasks.md):<br>Edit | | ✓ | ✓ | ✓ | ✓ |
| [Tasks](tasks.md):<br>Remove from issue | | ✓ | ✓ | ✓ | ✓ |
-| [Tasks](tasks.md):<br>Delete (*22*) | | | | | ✓ |
+| [Tasks](tasks.md):<br>Delete (*21*) | | | | | ✓ |
| [Terraform](infrastructure/index.md):<br>Read Terraform state | | | ✓ | ✓ | ✓ |
| [Terraform](infrastructure/index.md):<br>Manage Terraform state | | | | ✓ | ✓ |
| [Test cases](../ci/test_cases/index.md):<br>Archive | | ✓ | ✓ | ✓ | ✓ |
@@ -239,15 +240,13 @@ The following table lists project permissions available for each role:
Developer role.
15. Guest users can only set metadata (for example, labels, assignees, or milestones)
when creating an issue. They cannot change the metadata on existing issues.
-16. In GitLab 14.5 or later, Guests are not allowed to [create incidents](../operations/incident_management/incidents.md#incident-creation).
- In GitLab 15.1 and later, a Guest who created an issue that was promoted to an incident cannot edit, close, or reopen their incident.
-17. In projects that accept contributions from external members, users can create, edit, and close their own merge requests.
-18. Authors and assignees can modify the title and description even if they don't have the Reporter role.
-19. Authors and assignees can close and reopen issues even if they don't have the Reporter role.
-20. The ability to view the Container Registry and pull images is controlled by the [Container Registry's visibility permissions](packages/container_registry/index.md#container-registry-visibility-permissions).
-21. Maintainers cannot create, demote, or remove Owners, and they cannot promote users to the Owner role. They also cannot approve Owner role access requests.
-22. Authors of tasks can delete them even if they don't have the Owner role, but they have to have at least the Guest role for the project.
-23. You must have permission to [view the epic](group/epics/manage_epics.md#who-can-view-an-epic).
+16. In projects that accept contributions from external members, users can create, edit, and close their own merge requests.
+17. Authors and assignees can modify the title and description even if they don't have the Reporter role.
+18. Authors and assignees can close and reopen issues even if they don't have the Reporter role.
+19. The ability to view the Container Registry and pull images is controlled by the [Container Registry's visibility permissions](packages/container_registry/index.md#container-registry-visibility-permissions).
+20. Maintainers cannot create, demote, or remove Owners, and they cannot promote users to the Owner role. They also cannot approve Owner role access requests.
+21. Authors of tasks can delete them even if they don't have the Owner role, but they have to have at least the Guest role for the project.
+22. You must have permission to [view the epic](group/epics/manage_epics.md#who-can-view-an-epic).
<!-- markdownlint-enable MD029 -->
@@ -470,7 +469,7 @@ project and should only have access to that project.
External users:
-- Cannot create project, groups, and snippets within their personal namespaces.
+- Cannot create project, groups, and snippets in their personal namespaces.
- Can only create projects (including forks), subgroups, and snippets within top-level groups to which they are explicitly granted access.
- Can only access public projects and projects to which they are explicitly granted access,
thus hiding all other internal or private ones from them (like being
diff --git a/doc/user/product_analytics/index.md b/doc/user/product_analytics/index.md
new file mode 100644
index 00000000000..8e340fff32a
--- /dev/null
+++ b/doc/user/product_analytics/index.md
@@ -0,0 +1,48 @@
+---
+stage: Analyze
+group: Product Analytics
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
+---
+
+# Product analytics **(ULTIMATE)** **Alpha**
+
+> Introduced in GitLab 15.4 [with a flag](../../administration/feature_flags.md) named `cube_api_proxy`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `cube_api_proxy`.
+On GitLab.com, this feature is not available.
+This feature is not ready for production use.
+
+## Overview
+
+You can view the [product category](https://about.gitlab.com/direction/analytics/product-analytics/) page for more information about our direction. This page is a work in progress and will be updated as we add more features.
+
+## Product analytics dashboards
+
+Each project can define an unlimited number of dashboards. These dashboards are defined using our YAML schema and stored
+in the `.gitlab/product_analytics/dashboards/` directory. The name of the file is the name of the dashboard, and visualizations are shared across dashboards..
+
+Project maintainers can enforce approval rules on dashboard changes, and dashboards can be versioned in source control.
+
+### Define a dashboard
+
+To define a dashboard:
+
+1. In `.gitlab/product_analytics/dashboards/`, create a directory named like the dashboard. Each dashboard should have its own directory.
+1. In the new directory, create a `.yaml` file with the same name as the directory. This file contains the dashboard definition, and must conform to the JSON schema defined in `ee/app/validators/json_schemas/product_analytics_dashboard.json`.
+1. In the `.gitlab/product_analytics/dashboards/visualizations/` directory, create a `yaml` file. This file defines the visualization type for the dashboard, and must conform to the schema in
+`ee/app/validators/json_schemas/product_analytics_visualization.json`.
+
+The example below includes three dashboards and one visualization that applies to all dashboards.
+
+```plaintext
+.gitlab/product_analytics/dashboards
+├── conversion_funnels
+│ └── conversion_funnels.yaml
+├── demographic_breakdown
+│ └── demographic_breakdown.yaml
+├── north_star_metrics
+| └── north_star_metrics.yaml
+├── visualizations
+│ └── example_line_chart.yaml
+```
diff --git a/doc/user/profile/account/create_accounts.md b/doc/user/profile/account/create_accounts.md
index f2636fdaa68..60b8fe8ab88 100644
--- a/doc/user/profile/account/create_accounts.md
+++ b/doc/user/profile/account/create_accounts.md
@@ -49,3 +49,19 @@ Users are:
- Created when first signing with [Group SAML](../../group/saml_sso/index.md).
- Automatically created by [SCIM](../../group/saml_sso/scim_setup.md) when the user is created in
the identity provider.
+
+## Create users through the Rails console
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
+To create a user through the Rails console:
+
+1. [Start a Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session).
+1. Run the following commands:
+
+ ```ruby
+ u = User.new(username: 'test_user', email: 'test@example.com', name: 'Test User', password: 'password', password_confirmation: 'password')
+ u.skip_confirmation! # Use it only if you wish user to be automatically confirmed. If skipped, user receives confirmation e-mail
+ u.save!
+ ```
diff --git a/doc/user/profile/account/two_factor_authentication.md b/doc/user/profile/account/two_factor_authentication.md
index 3dc768f6606..39826bf59c4 100644
--- a/doc/user/profile/account/two_factor_authentication.md
+++ b/doc/user/profile/account/two_factor_authentication.md
@@ -61,7 +61,6 @@ To enable 2FA with a one-time password:
1. Install a compatible application. For example:
- Cloud-based (recommended because you can restore access if you lose the hardware device):
- [Authy](https://authy.com/)
- - [Duo Mobile](https://duo.com/product/multi-factor-authentication-mfa/duo-mobile-app)
- Other:
- [Google Authenticator](https://support.google.com/accounts/answer/1066447?hl=en)
- [Microsoft Authenticator](https://www.microsoft.com/en-us/security/mobile-authenticator-app)
@@ -73,6 +72,9 @@ 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.
diff --git a/doc/user/profile/active_sessions.md b/doc/user/profile/active_sessions.md
index d0600e5e80d..430d1c3dc9f 100644
--- a/doc/user/profile/active_sessions.md
+++ b/doc/user/profile/active_sessions.md
@@ -51,6 +51,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/profile/contributions_calendar.md b/doc/user/profile/contributions_calendar.md
new file mode 100644
index 00000000000..6df7ad56c5e
--- /dev/null
+++ b/doc/user/profile/contributions_calendar.md
@@ -0,0 +1,136 @@
+---
+stage: Manage
+group: Workspace
+info: To 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
+---
+
+# Contributions calendar **(FREE)**
+
+The contributions calendar displays a [user's events](#user-contribution-events) from the past 12 months.
+This includes contributions made in forked and [private](#show-private-contributions-on-your-user-profile-page) repositories.
+
+![Contributions calendar](img/contributions_calendar_v15_6.png)
+
+The gradient color of the tiles represents the number of contributions made per day. The gradient ranges from blank (0 contributions) to dark blue (more than 30 contributions).
+
+NOTE:
+The contribution calendar only displays contributions from the last 12 months, but issue [24264](https://gitlab.com/gitlab-org/gitlab/-/issues/24264) proposes to change this to more than 12 months. General improvements to the user profile are proposed in issue [8488](https://gitlab.com/groups/gitlab-org/-/epics/8488).
+
+## User contribution events
+
+GitLab tracks the following contribution events:
+
+- `approved`
+ - Merge request
+- `closed`
+ - [Epic](../group/epics/index.md)
+ - Issue
+ - Merge request
+ - Milestone
+- `commented` on any `Noteable` record.
+ - Alert
+ - Commit
+ - Design
+ - Issue
+ - Merge request
+ - Snippet
+- `created`
+ - Design
+ - [Epic](../group/epics/index.md)
+ - Issue
+ - Merge request
+ - Milestone
+ - Project
+ - Wiki page
+- `destroyed`
+ - Design
+ - Milestone
+ - Wiki page
+- `expired`
+ - Project membership
+- `joined`
+ - Project membership
+- `left`
+ - Project membership
+- `merged`
+ - Merge request
+- `pushed` commits to (or deleted commits from) a repository, individually or in bulk.
+ - Project
+- `reopened`
+ - [Epic](../group/epics/index.md)
+ - Issue
+ - Merge request
+ - Milestone
+- `updated`
+ - Design
+ - Wiki page
+
+### View daily contributions
+
+To view your daily contributions:
+
+1. On the top bar, in the top-right corner, select your avatar.
+1. Select your name from the dropdown list.
+1. In the contributions calendar:
+ - To view the number of contributions for a specific day, hover over a tile.
+ - To view all contributions for a specific day, select a tile. A list displays all contributions and the time they were made.
+
+### Show private contributions on your user profile page
+
+The contributions calendar graph and recent activity list displays your
+[contribution actions](#user-contribution-events) to private projects.
+
+To view private contributions:
+
+1. On the top bar, in the top-right corner, select your avatar.
+1. Select **Edit profile**.
+1. In the **Main settings** section, select the **Include private contributions on my profile** checkbox.
+1. Select **Update profile settings**.
+
+## User activity
+
+### Follow a user's activity
+
+You can follow users whose activity you're interested in.
+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 follow a user, either:
+
+- From a user's profile, select **Follow**.
+- Hover over a user's name, and select **Follow** ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76050)
+ in GitLab 15.0).
+
+To view the activity of users you follow:
+
+1. In the GitLab menu, select **Activity**.
+1. Select the **Followed users** tab.
+
+### Retrieve user activity as a feed
+
+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 top right, 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.
+You can add this URL to your feed reader.
+
+### Reset the user activity feed token
+
+Feed tokens are sensitive and can reveal information from confidential issues.
+If you think your feed token has been exposed, you should reset it.
+
+To reset your feed token:
+
+1. On the top bar, in the top right corner, select your avatar.
+1. Select **Edit profile**.
+1. On the left sidebar, select **Access Tokens**.
+1. Scroll down. In the **Feed token** section, select the
+ **reset this token** link.
+1. On the confirmation box, select **OK**.
+
+A new token is generated.
diff --git a/doc/user/profile/img/contributions_calendar_v15_6.png b/doc/user/profile/img/contributions_calendar_v15_6.png
new file mode 100644
index 00000000000..363636ec0cd
--- /dev/null
+++ b/doc/user/profile/img/contributions_calendar_v15_6.png
Binary files differ
diff --git a/doc/user/profile/index.md b/doc/user/profile/index.md
index 66f6b4b52de..4adf6c351df 100644
--- a/doc/user/profile/index.md
+++ b/doc/user/profile/index.md
@@ -137,7 +137,7 @@ To add links to other accounts:
## Show private contributions on your user profile page
-In the user contribution calendar graph and recent activity list, you can see your [contribution actions](#user-contribution-events) to private projects.
+In the user contribution calendar graph and recent activity list, you can see your [contribution actions](contributions_calendar.md#user-contribution-events) to private projects.
To show private contributions:
@@ -311,7 +311,7 @@ git config --global user.email <your email address>
## User activity
-GitLab tracks user contribution activity. You can follow or unfollow other users from either:
+GitLab tracks [user contribution activity](contributions_calendar.md). You can follow or unfollow other 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)
@@ -326,83 +326,6 @@ To view a user's activity in a top-level Activity view:
1. In the GitLab menu, select **Activity**.
1. Select the **Followed users** tab.
-### User contribution events
-
-Each of these contribution events is tracked:
-
-- `approved`
- - Merge request
-- `closed`
- - [Epic](../group/epics/index.md)
- - Issue
- - Merge request
- - Milestone
-- `commented` on any `Noteable` record.
- - Alert
- - Commit
- - Design
- - Issue
- - Merge request
- - Snippet
-- `created`
- - Design
- - [Epic](../group/epics/index.md)
- - Issue
- - Merge request
- - Milestone
- - Project
- - Wiki page
-- `destroyed`
- - Design
- - Milestone
- - Wiki page
-- `expired`
- - Project membership
-- `joined`
- - Project membership
-- `left`
- - Project membership
-- `merged`
- - Merge request
-- `pushed` commits to (or deleted commits from) a repository, individually or in bulk.
- - Project
-- `reopened`
- - [Epic](../group/epics/index.md)
- - Issue
- - Merge request
- - Milestone
-- `updated`
- - Design
- - Wiki page
-
-### Retrieve user activity as a feed
-
-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](#access-your-user-profile).
-1. In the top right, 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.
-You can add this URL to your feed reader.
-
-### Reset the user activity feed token
-
-Feed tokens are sensitive and can reveal information from confidential issues.
-If you think your feed token has been exposed, you should reset it.
-
-To reset your feed token:
-
-1. On the top bar, in the top right corner, select your avatar.
-1. Select **Edit profile**.
-1. On the left sidebar, select **Access Tokens**.
-1. Scroll down. In the **Feed token** section, select the
- **reset this token** link.
-1. On the confirmation box, select **OK**.
-
-A new token is generated.
-
## Troubleshooting
### Why do I keep getting signed out?
diff --git a/doc/user/profile/notifications.md b/doc/user/profile/notifications.md
index 7942ee38be9..1deb4842107 100644
--- a/doc/user/profile/notifications.md
+++ b/doc/user/profile/notifications.md
@@ -109,7 +109,7 @@ To select a notification level for a group, use either of these methods:
Or:
1. On the top bar, select **Main menu > Groups** and find your group.
-1. Select the notification dropdown, next to the bell icon (**{notifications}**).
+1. Select the notification dropdown list, next to the bell icon (**{notifications}**).
1. Select the desired [notification level](#notification-levels).
#### Change email address used for group notifications
@@ -140,7 +140,7 @@ To select a notification level for a project, use either of these methods:
Or:
1. On the top bar, select **Main menu > Projects** and find your project.
-1. Select the notification dropdown, next to the bell icon (**{notifications}**).
+1. Select the notification dropdown list, next to the bell icon (**{notifications}**).
1. Select the desired [notification level](#notification-levels).
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
@@ -194,6 +194,7 @@ Users are notified of the following events:
| Personal access tokens expiring soon | User | Security email, always sent. |
| Personal access tokens have been created | User | Security email, always sent. _[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/337591) in GitLab 14.9._ |
| Personal access tokens have expired | User | Security email, always sent. |
+| Personal access token has been revoked | User | Security email, always sent. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98911) in GitLab 15.5. |
| Project access level changed | User | Sent when user project access level is changed. |
| SSH key has expired | User | Security email, always sent. _[Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/322637) in GitLab 13.12._ |
| Two-factor authentication disabled | User | Security email, always sent. |
@@ -227,20 +228,20 @@ to change their user notification settings to **Watch** instead.
### Edit notification settings for issues, merge requests, and epics
-To enable notifications on a specific issue, merge request, or epic, you must turn on the
-**Notifications** toggle in the right sidebar.
+To toggle notifications on an issue, merge request, or epic: on the right sidebar, turn on or off the **Notifications** toggle.
-- To subscribe, **turn on** if you are not a participant in the discussion, but want to receive
- notifications on each update.
+When you **turn on** notifications, you start receiving notifications on each update, even if you
+haven't participated in the discussion.
+When you turn notifications on in an epic, you aren't automatically subscribed to the issues linked
+to the epic.
- When you turn notifications on in an epic, you aren't automatically subscribed to the issues linked
- to the epic.
-
-- To unsubscribe, **turn off** if you are receiving notifications for updates but no longer want to
- receive them.
+When you **turn off** notifications, you stop receiving notifications for updates.
+Turning this toggle off only unsubscribes you from updates related to this issue, merge request, or epic.
+Learn how to [opt out of all emails from GitLab](#opt-out-of-all-gitlab-emails).
- Turning this toggle off only unsubscribes you from updates related to this issue, merge request, or epic.
- Learn how to [opt out of all emails from GitLab](#opt-out-of-all-gitlab-emails).
+<!-- Delete when the `moved_mr_sidebar` feature flag is removed -->
+If you don't see this action on the right sidebar, your project or instance may have
+enabled a feature flag for [moved sidebar actions](../project/merge_requests/index.md#move-sidebar-actions).
### Notification events on issues, merge requests, and epics
@@ -356,13 +357,13 @@ a merge request or an issue.
The following table lists all GitLab-specific email headers:
| Header | Description |
-|---------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------|
+| ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `List-Id` | The path of the project in an RFC 2919 mailing list identifier. You can use it for email organization with filters. |
| `X-GitLab-(Resource)-ID` | The ID of the resource the notification is for. The resource, for example, can be `Issue`, `MergeRequest`, `Commit`, or another such resource. |
| `X-GitLab-Discussion-ID` | The ID of the thread the comment belongs to, in notification emails for comments. |
| `X-GitLab-Group-Id` | The group's ID. Only present on notification emails for [epics](../group/epics/index.md). |
| `X-GitLab-Group-Path` | The group's path. Only present on notification emails for [epics](../group/epics/index.md) |
-| [`X-GitLab-NotificationReason`](#x-gitlab-notificationreason) | The reason for the notification. This can be `mentioned`, `assigned`, or `own_activity`. |
+| `X-GitLab-NotificationReason` | The reason for the notification. [See possible values.](#x-gitlab-notificationreason). |
| `X-GitLab-Pipeline-Id` | The ID of the pipeline the notification is for, in notification emails for pipelines. |
| `X-GitLab-Project-Id` | The project's ID. |
| `X-GitLab-Project-Path` | The project's path. |
@@ -376,21 +377,35 @@ The value is one of the following, in order of priority:
- `own_activity`
- `assigned`
+- `review_requested`
- `mentioned`
+- `subscribed`
The reason for the notification is also included in the footer of the notification email.
For example, an email with the reason `assigned` has this sentence in the footer:
> You are receiving this email because you have been assigned an item on \<configured GitLab hostname>.
-For example, an alert notification email can have one of
-[the alert's](../../operations/incident_management/alerts.md) statuses:
+#### On-call alerts notifications **(PREMIUM)**
+
+An [on-call alert](../../operations/incident_management/oncall_schedules.md)
+notification email can have one of [the alert's](../../operations/incident_management/alerts.md) statuses:
- `alert_triggered`
- `alert_acknowledged`
- `alert_resolved`
- `alert_ignored`
+#### Incident escalation notifications **(PREMIUM)**
+
+An [incident escalation](../../operations/incident_management/escalation_policies.md)
+notification email can have one of [the incident's](../../operations/incident_management/incidents.md) status:
+
+- `incident_triggered`
+- `incident_acknowledged`
+- `incident_resolved`
+- `incident_ignored`
+
Expanding the list of events included in the `X-GitLab-NotificationReason` header is tracked in
[issue 20689](https://gitlab.com/gitlab-org/gitlab/-/issues/20689).
diff --git a/doc/user/profile/personal_access_tokens.md b/doc/user/profile/personal_access_tokens.md
index c7fe68c0609..507ad6378bc 100644
--- a/doc/user/profile/personal_access_tokens.md
+++ b/doc/user/profile/personal_access_tokens.md
@@ -89,8 +89,10 @@ At any time, you can revoke a personal access token.
## View the last time a token was used
-Token usage is updated once every 24 hours. It is updated each time the token is used to request
-[API resources](../../api/api_resources.md) and the [GraphQL API](../../api/graphql/index.md).
+Token usage information is updated every 24 hours. GitLab considers a token used when the token is used to:
+
+- Authenticate with the [REST](../../api/index.md) or [GraphQL](../../api/graphql/index.md) APIs.
+- Perform a Git operation.
To view the last time a token was used:
@@ -195,17 +197,29 @@ This code can be shortened into a single-line shell command using the
sudo gitlab-rails runner "PersonalAccessToken.find_by_token('token-string-here123').revoke!"
```
-<!-- ## Troubleshooting
+## Troubleshooting
+
+### Unrevoke a personal access token **(FREE SELF)**
+
+If a personal access token is revoked accidentally by any method, administrators can unrevoke that token.
+
+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.
+
+1. Open a [Rails console](../../administration/operations/rails_console.md#starting-a-rails-console-session).
+1. Unrevoke the token:
-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.
+ ```ruby
+ token = PersonalAccessToken.find_by_token('<token_string>')
+ token.update!(revoked:false)
+ ```
+
+ For example, to unrevoke a token of `token-string-here123`:
-Each scenario can be a third-level heading, e.g. `### 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. -->
+ ```ruby
+ token = PersonalAccessToken.find_by_token('token-string-here123')
+ token.update!(revoked:false)
+ ```
## Alternatives to personal access tokens
diff --git a/doc/user/profile/preferences.md b/doc/user/profile/preferences.md
index 6849918886a..dce8684d993 100644
--- a/doc/user/profile/preferences.md
+++ b/doc/user/profile/preferences.md
@@ -137,7 +137,7 @@ You can include the following options for your default dashboard view:
### Group overview content
-The **Group overview content** dropdown allows you to choose what information is
+The **Group overview content** dropdown list allows you to choose what information is
displayed on a group's home page.
You can choose between 2 options:
@@ -230,6 +230,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/profile/user_passwords.md b/doc/user/profile/user_passwords.md
index 04d149c9709..b8dbdcdd956 100644
--- a/doc/user/profile/user_passwords.md
+++ b/doc/user/profile/user_passwords.md
@@ -60,7 +60,8 @@ Self-managed installations can configure the following additional password requi
## Block weak passwords
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23610) in GitLab 15.4 [with a flag](../../administration/feature_flags.md) named `block_weak_passwords`, weak passwords aren't accepted. Disabled by default.
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23610) in GitLab 15.4 [with a flag](../../administration/feature_flags.md) named `block_weak_passwords`, weak passwords aren't accepted. Disabled by default on self-managed.
+> - [Enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/363445) on GitLab.com.
FLAG:
On self-managed GitLab, by default blocking weak passwords is not available. To make it available, ask an administrator
diff --git a/doc/user/project/badges.md b/doc/user/project/badges.md
index d43af92e9c6..5d1d10fc37d 100644
--- a/doc/user/project/badges.md
+++ b/doc/user/project/badges.md
@@ -128,7 +128,7 @@ To add a new badge to a group or project with a custom image:
1. Select **Add badge**.
To learn how to use custom images generated via a pipeline, see our documentation on
-[accessing the latest job artifacts by URL](../../ci/pipelines/job_artifacts.md#access-the-latest-job-artifacts-by-url).
+[accessing the latest job artifacts by URL](../../ci/pipelines/job_artifacts.md#access-the-latest-job-artifacts).
## API
diff --git a/doc/user/project/clusters/add_existing_cluster.md b/doc/user/project/clusters/add_existing_cluster.md
index 363197107f9..0b0555806ce 100644
--- a/doc/user/project/clusters/add_existing_cluster.md
+++ b/doc/user/project/clusters/add_existing_cluster.md
@@ -69,7 +69,7 @@ To add a Kubernetes cluster to your project, group, or instance:
1. Project's **{cloud-gear}** **Infrastructure > Kubernetes clusters** page, for a project-level cluster.
1. Group's **{cloud-gear}** **Kubernetes** page, for a group-level cluster.
1. **Main menu > Admin > Kubernetes** page, for an instance-level cluster.
-1. On the **Kubernetes clusters** page, select the **Connect with a certificate** option from the **Actions** dropdown menu.
+1. On the **Kubernetes clusters** page, select the **Connect with a certificate** option from the **Actions** dropdown list.
1. On the **Connect a cluster** page, fill in the details:
1. **Kubernetes cluster name** (required) - The name you wish to give the cluster.
1. **Environment scope** (required) - The
diff --git a/doc/user/project/clusters/deploy_to_cluster.md b/doc/user/project/clusters/deploy_to_cluster.md
index e8acf5a2727..65e4a5d9fde 100644
--- a/doc/user/project/clusters/deploy_to_cluster.md
+++ b/doc/user/project/clusters/deploy_to_cluster.md
@@ -131,7 +131,7 @@ However, sometimes GitLab cannot create them. In such instances, your job can fa
This job failed because the necessary resources were not successfully created.
```
-To find the cause of this error when creating a namespace and service account, check the [logs](../../../administration/logs/index.md#kuberneteslog).
+To find the cause of this error when creating a namespace and service account, check the [logs](../../../administration/logs/index.md#kuberneteslog-deprecated).
Reasons for failure include:
diff --git a/doc/user/project/clusters/kubernetes_pod_logs.md b/doc/user/project/clusters/kubernetes_pod_logs.md
deleted file mode 100644
index 51e4f1c2db2..00000000000
--- a/doc/user/project/clusters/kubernetes_pod_logs.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-stage: Monitor
-group: Respond
-info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
-remove_date: '2022-10-18'
-redirect_to: '../../clusters/agent/index.md'
----
-
-# Kubernetes Logs (removed) **(FREE SELF)**
-
-This feature was [deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5
-and [removed](https://gitlab.com/gitlab-org/gitlab/-/issues/360193) in GitLab 15.2.
diff --git a/doc/user/project/clusters/runbooks/index.md b/doc/user/project/clusters/runbooks/index.md
index c4ca82f7db4..df0ffff8561 100644
--- a/doc/user/project/clusters/runbooks/index.md
+++ b/doc/user/project/clusters/runbooks/index.md
@@ -166,11 +166,11 @@ the components outlined above and the pre-loaded demo runbook.
[GitLab Access Token](../../../profile/personal_access_tokens.md)
and your Project ID in the **Setup** section of the demo runbook:
- 1. Double-click the **DevOps-Runbook-Demo** folder located on the left panel.
+ 1. Select the **DevOps-Runbook-Demo** folder located on the left panel.
![demo runbook](img/demo-runbook.png)
- 1. Double-click the `Nurtch-DevOps-Demo.ipynb` runbook.
+ 1. Select the `Nurtch-DevOps-Demo.ipynb` runbook.
![sample runbook](img/sample-runbook.png)
diff --git a/doc/user/project/import/clearcase.md b/doc/user/project/import/clearcase.md
index 1dc62cbbe35..0878476d59f 100644
--- a/doc/user/project/import/clearcase.md
+++ b/doc/user/project/import/clearcase.md
@@ -27,7 +27,7 @@ The following table illustrates the main differences between ClearCase and Git:
| Server | UNIX, Windows legacy systems | UNIX, macOS |
| License | Proprietary | GPL |
-_Taken from the slides [ClearCase and the journey to Git](https://docplayer.net/42708453-Clearcase-the-journey-to-git-migrating-your-skills-and-vobs-to-git.html) provided by [collab.net](https://www.collab.net/)_
+_Taken from the slides [ClearCase and the journey to Git](https://docplayer.net/42708453-Clearcase-the-journey-to-git-migrating-your-skills-and-vobs-to-git.html) provided by `collab.net`_
## Why migrate
diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md
index 03f6fd20b0a..c0b13c76322 100644
--- a/doc/user/project/import/github.md
+++ b/doc/user/project/import/github.md
@@ -112,8 +112,8 @@ If you are not using the GitHub integration, you can still perform an authorizat
1. Select **Generate token**.
1. Copy the token hash.
1. Go back to GitLab and provide the token to the GitHub importer.
-1. Hit the **List Your GitHub Repositories** button and wait while GitLab reads your repositories' information.
- Once done, you are taken to the importer page to select the repositories to import.
+1. Select **List Your GitHub Repositories** and wait while GitLab reads your repositories' information.
+ When done, you are taken to the importer page to select the repositories to import.
To use a newer personal access token in imports after previously performing these steps, sign out of
your GitLab account and sign in again, or revoke the older personal access token in GitHub.
@@ -202,18 +202,21 @@ The following items of a project are imported:
- Merge 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 be imported
- [as an additional item](#select-additional-items-to-import). The feature flag was removed.
+ `github_importer_attachments_import` [feature flag](../../../administration/feature_flags.md). From GitLab 15.5, can
+ be imported [as an additional item](#select-additional-items-to-import). The feature flag was removed.
- Pull request review comments.
- Regular issue and pull request comments.
- [Git Large File Storage (LFS) Objects](../../../topics/git/lfs/index.md).
-- Pull request reviews (GitLab.com and GitLab 13.7 and later).
-- Pull request "merged by" information (GitLab.com and GitLab 13.7 and later).
-- Pull request comments replies in discussions ([GitLab.com and GitLab 14.5 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/336596)).
-- Diff Notes suggestions ([GitLab.com and GitLab 14.7 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/340624)).
-- 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 removed.
+- Pull request reviews.
+- Pull request assigned reviewers. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/355137) in GitLab 15.6.
+- 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.
+- 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
+ removed.
References to pull requests and issues are preserved. Each imported repository maintains visibility level unless that
[visibility level is restricted](../../public_access.md#restrict-use-of-public-or-internal-projects), in which case it
@@ -225,7 +228,13 @@ Supported GitHub branch protection rules are mapped to GitLab branch protection
- GitHub rule **Require conversation resolution before merging** for the project's default branch is mapped to the [**All threads must be resolved** GitLab setting](../../discussions/index.md#prevent-merge-unless-all-threads-are-resolved). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/371110) in GitLab 15.5.
- GitHub rule **Require a pull request before merging** is mapped to the **No one** option in the **Allowed to push** list of the branch protection rule. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/370951) in GitLab 15.5.
-- GitHub rule **Require signed commits** for the project's default branch is mapped to the **Reject unsigned commits** GitLab setting. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/370949) in GitLab 15.5.
+- GitHub rule **Require a pull request before merging - Require review from Code Owners** is mapped to the
+ [**Code owner approval** branch protection rule](../protected_branches.md#require-code-owner-approval-on-a-protected-branch). Requires GitLab Premium or higher.
+ [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/376683) in GitLab 15.6.
+- GitHub rule **Require signed commits** for the project's default branch is mapped to the **Reject unsigned commits** GitLab push rule. Requires GitLab Premium or higher.
+ [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/370949) in GitLab 15.5.
+- GitHub rule **Allow force pushes - Everyone** is mapped to the [**Allowed to force push** branch protection rule](../protected_branches.md#allow-force-push-on-a-protected-branch). [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/370943) in GitLab 15.6.
+- GitHub rule **Allow force pushes - Specify who can force push** is proposed in issue [370945](https://gitlab.com/gitlab-org/gitlab/-/issues/370945).
- Support for GitHub rule **Require status checks to pass before merging** was proposed in issue [370948](https://gitlab.com/gitlab-org/gitlab/-/issues/370948). However, this rule cannot be translated during project import into GitLab due to technical difficulties.
You can still create [status checks](../merge_requests/status_checks.md) in GitLab yourself.
@@ -263,6 +272,112 @@ To disable the feature, run this command:
Feature.disable(:github_importer_lower_per_page_limit, group)
```
+## Import from GitHub Enterprise on an internal network
+
+If your GitHub Enterprise instance is on a internal network that is unaccessible to the internet, you can use a reverse proxy
+to allow GitLab.com to access the instance.
+
+The proxy needs to:
+
+- Forward requests to the GitHub Enterprise instance.
+- Convert to the public proxy hostname all occurrences of the internal hostname in:
+ - The API response body.
+ - The API response `Link` header.
+
+GitHub API uses the `Link` header for pagination.
+
+After configuring the proxy, test it by making API requests. Below there are some examples of commands to test the API:
+
+```shell
+curl --header "Authorization: Bearer <YOUR-TOKEN>" "https://{PROXY_HOSTNAME}/user"
+
+### URLs in the response body should use the proxy hostname
+
+{
+ "login": "example_username",
+ "id": 1,
+ "url": "https://{PROXY_HOSTNAME}/users/example_username",
+ "html_url": "https://{PROXY_HOSTNAME}/example_username",
+ "followers_url": "https://{PROXY_HOSTNAME}/api/v3/users/example_username/followers",
+ ...
+ "created_at": "2014-02-11T17:03:25Z",
+ "updated_at": "2022-10-18T14:36:27Z"
+}
+```
+
+```shell
+curl --head --header "Authorization: Bearer <YOUR-TOKEN>" "https://{PROXY_DOMAIN}/api/v3/repos/{repository_path}/pulls?states=all&sort=created&direction=asc"
+
+### Link header should use the proxy hostname
+
+HTTP/1.1 200 OK
+Date: Tue, 18 Oct 2022 21:42:55 GMT
+Server: GitHub.com
+Content-Type: application/json; charset=utf-8
+Cache-Control: private, max-age=60, s-maxage=60
+...
+X-OAuth-Scopes: repo
+X-Accepted-OAuth-Scopes:
+github-authentication-token-expiration: 2022-11-22 18:13:46 UTC
+X-GitHub-Media-Type: github.v3; format=json
+X-RateLimit-Limit: 5000
+X-RateLimit-Remaining: 4997
+X-RateLimit-Reset: 1666132381
+X-RateLimit-Used: 3
+X-RateLimit-Resource: core
+Link: <https://{PROXY_DOMAIN}/api/v3/repositories/1/pulls?page=2>; rel="next", <https://{PROXY_DOMAIN}/api/v3/repositories/1/pulls?page=11>; rel="last"
+```
+
+Also test that cloning the repository using the proxy does not fail:
+
+```shell
+git clone -c http.extraHeader="Authorization: basic <base64 encode YOUR-TOKEN>" --mirror https://{PROXY_DOMAIN}/{REPOSITORY_PATH}.git
+```
+
+### Sample reverse proxy configuration
+
+The following configuration is an example on how to configure Apache HTTP Server as a reverse proxy
+
+WARNING:
+For simplicity, the snippet does not have configuration to encrypt the connection between the client and the proxy. However, for security reasons you should include that
+configuration. See [sample Apache TLS/SSL configuration](https://ssl-config.mozilla.org/#server=apache&version=2.4.41&config=intermediate&openssl=1.1.1k&guideline=5.6).
+
+```plaintext
+# Required modules
+LoadModule filter_module lib/httpd/modules/mod_filter.so
+LoadModule reflector_module lib/httpd/modules/mod_reflector.so
+LoadModule substitute_module lib/httpd/modules/mod_substitute.so
+LoadModule deflate_module lib/httpd/modules/mod_deflate.so
+LoadModule headers_module lib/httpd/modules/mod_headers.so
+LoadModule proxy_module lib/httpd/modules/mod_proxy.so
+LoadModule proxy_connect_module lib/httpd/modules/mod_proxy_connect.so
+LoadModule proxy_http_module lib/httpd/modules/mod_proxy_http.so
+LoadModule ssl_module lib/httpd/modules/mod_ssl.so
+
+<VirtualHost GITHUB_ENTERPRISE_HOSTNAME:80>
+ ServerName GITHUB_ENTERPRISE_HOSTNAME
+
+ # Enables reverse-proxy configuration with SSL support
+ SSLProxyEngine On
+ ProxyPass "/" "https://GITHUB_ENTERPRISE_HOSTNAME/"
+ ProxyPassReverse "/" "https://GITHUB_ENTERPRISE_HOSTNAME/"
+
+ # Replaces occurrences of the local GitHub Enterprise URL with the Proxy URL
+ # GitHub Enterprise compresses the responses, the filters INFLATE and DEFLATE needs to be used to
+ # decompress and compress the response back
+ AddOutputFilterByType INFLATE;SUBSTITUTE;DEFLATE application/json
+ Substitute "s|https://GITHUB_ENTERPRISE_HOSTNAME|https://PROXY_HOSTNAME|ni"
+ SubstituteMaxLineLength 50M
+
+ # GitHub API uses the response header "Link" for the API pagination
+ # For example:
+ # <https://example.com/api/v3/repositories/1/issues?page=2>; rel="next", <https://example.com/api/v3/repositories/1/issues?page=3>; rel="last"
+ # The directive below replaces all occurrences of the GitHub Enterprise URL with the Proxy URL if the
+ # response header Link is present
+ Header edit* Link "https://GITHUB_ENTERPRISE_HOSTNAME" "https://PROXY_HOSTNAME"
+</VirtualHost>
+```
+
## Automate group and project import **(PREMIUM)**
For information on automating user, group, and project import API calls, see
@@ -279,8 +394,8 @@ repository to be imported manually. Administrators can manually import the repos
1. Run the following series of commands in the console:
```ruby
- project_id = <PROJECT_ID>
- github_access_token = <GITHUB_ACCESS_TOKEN>
+ project_id = <PROJECT_ID>
+ github_access_token = <GITHUB_ACCESS_TOKEN>
github_repository_path = '<GROUP>/<REPOSITORY>'
github_repository_url = "https://#{github_access_token}@github.com/#{github_repository_path}.git"
diff --git a/doc/user/project/import/tfvc.md b/doc/user/project/import/tfvc.md
index 3625355340b..0a03513467e 100644
--- a/doc/user/project/import/tfvc.md
+++ b/doc/user/project/import/tfvc.md
@@ -7,7 +7,7 @@ type: concepts
# Migrate from TFVC to Git **(FREE)**
-Team Foundation Server (TFS), renamed [Azure DevOps Server](https://azure.microsoft.com/en-us/services/devops/server/)
+Team Foundation Server (TFS), renamed [Azure DevOps Server](https://azure.microsoft.com/en-us/products/devops/server/)
in 2019, is a set of tools developed by Microsoft which also includes
[Team Foundation Version Control](https://learn.microsoft.com/en-us/azure/devops/repos/tfvc/what-is-tfvc?view=azure-devops)
(TFVC), a centralized version control system similar to Git.
diff --git a/doc/user/project/integrations/gitlab_slack_application.md b/doc/user/project/integrations/gitlab_slack_application.md
index 07c99653a0e..8d6fdf882b7 100644
--- a/doc/user/project/integrations/gitlab_slack_application.md
+++ b/doc/user/project/integrations/gitlab_slack_application.md
@@ -4,35 +4,35 @@ 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 Slack application **(FREE SAAS)**
+# GitLab for Slack app **(FREE SAAS)**
NOTE:
-The GitLab Slack application is only configurable for GitLab.com. It will **not**
-work for on-premises installations where you can configure the
-[Slack slash commands](slack_slash_commands.md) integration instead. We're planning
-to make this configurable for all GitLab installations, but there's
-no ETA - see [#28164](https://gitlab.com/gitlab-org/gitlab/-/issues/28164).
+The GitLab for Slack app is only configurable for GitLab.com. It does **not**
+work for on-premises installations where you can configure
+[Slack slash commands](slack_slash_commands.md) instead. See
+[Slack application integration for self-managed instances](https://gitlab.com/gitlab-org/gitlab/-/issues/28164)
+for our plans to make the app configurable for all GitLab installations.
-Slack provides a native application which you can enable via your project's
+Slack provides a native application that you can enable with your project's
integrations on GitLab.com.
## Slack App Directory
-The simplest way to enable the GitLab Slack application for your workspace is to
-install the [GitLab application](https://slack-platform.slack.com/apps/A676ADMV5-gitlab) from
-the [Slack App Directory](https://slack.com/apps).
+To enable the GitLab for Slack app for your workspace,
+install the [GitLab application](https://slack-platform.slack.com/apps/A676ADMV5-gitlab)
+from the [Slack App Directory](https://slack.com/apps).
-Selecting install takes you to the [GitLab Slack application landing page](https://gitlab.com/-/profile/slack/edit)
-where you can select a project to enable the GitLab Slack application for.
+On the [GitLab for Slack app landing page](https://gitlab.com/-/profile/slack/edit),
+you can select a GitLab project to link with your Slack workspace.
## Configuration
-Alternatively, you can configure the Slack application with a project's
+Alternatively, you can configure the GitLab for Slack app with your project's
integration settings.
-Keep in mind that you must have the appropriate permissions for your Slack
-workspace to be able to install a new application. Read more in Slack's
-documentation on [Adding an app to your workspace](https://slack.com/help/articles/202035138-Add-apps-to-your-Slack-workspace).
+You must have the appropriate permissions for your Slack
+workspace to be able to install a new application. See
+[Add apps to your Slack workspace](https://slack.com/help/articles/202035138-Add-apps-to-your-Slack-workspace).
To enable the GitLab integration for your Slack workspace:
@@ -41,23 +41,21 @@ To enable the GitLab integration for your Slack workspace:
1. Select **Install Slack app**.
1. Select **Allow** on Slack's confirmation screen.
-That's all! You can now start using the Slack slash commands.
-
You can also select **Reinstall Slack app** to update the app in your Slack workspace
-to the latest version. See the [Version history](#version-history) for details.
+to the latest version. See [Version history](#version-history) for details.
## Create a project alias for Slack
To create a project alias on GitLab.com for Slack integration:
1. Go to your project's home page.
-1. Go to **Settings > Integrations** (only visible on GitLab.com)
+1. Go to **Settings > Integrations** (only visible on GitLab.com).
1. On the **Integrations** page, select **Slack application**.
1. The current **Project Alias**, if any, is displayed. To edit this value,
select **Edit**.
1. Enter your desired alias, and select **Save changes**.
-Some Slack commands require a project alias, and fail with the following error
+Some Slack commands require a project alias and fail with the following error
if the project alias is incorrect or missing from the command:
```plaintext
@@ -66,17 +64,15 @@ GitLab error: project or alias not found
## Usage
-After confirming the installation, you, and everyone else in your Slack workspace,
-can use all the [slash commands](../../../integration/slash_commands.md).
-
-When you perform your first slash command, you are asked to authorize your
-Slack user on GitLab.com.
+After installing the app, everyone in your Slack workspace can
+use the [slash commands](../../../integration/slash_commands.md).
+When you perform your first slash command, you are asked to
+authorize your Slack user on GitLab.com.
The only difference with the [manually configurable Slack slash commands](slack_slash_commands.md)
-is that all the commands should be prefixed with the `/gitlab` keyword.
-
-For example, to show the issue number `1001` under the `gitlab-org/gitlab`
-project, you would do:
+is that you must prefix all commands with the `/gitlab` keyword. For example,
+to show the issue number `1001` under the `gitlab-org/gitlab`
+project, you must run the following command:
```plaintext
/gitlab gitlab-org/gitlab issue show 1001
@@ -84,15 +80,11 @@ project, you would do:
## Version history
-### 15.0+
-
-In GitLab 15.0 the Slack app is updated to [Slack's new granular permissions app model](https://medium.com/slack-developer-blog/more-precision-less-restrictions-a3550006f9c3).
-
-There is no change in functionality. A reinstall is not required but recommended.
+In GitLab 15.0 and later, the GitLab for Slack app is updated to [Slack's new granular permissions model](https://medium.com/slack-developer-blog/more-precision-less-restrictions-a3550006f9c3). While there is no change in functionality, you should reinstall the app.
## Troubleshooting
-When you work with the Slack app, the
+When you work with the GitLab for Slack app, the
[App Home](https://api.slack.com/start/overview#app_home) might not display properly.
As a workaround, ensure your app is up to date.
diff --git a/doc/user/project/integrations/hangouts_chat.md b/doc/user/project/integrations/hangouts_chat.md
index 1be0db223ac..c6e102b1d74 100644
--- a/doc/user/project/integrations/hangouts_chat.md
+++ b/doc/user/project/integrations/hangouts_chat.md
@@ -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 menu on the top-left and select **Manage webhooks**.
+1. Open the room dropdown list on the top-left and 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/mlflow_client.md b/doc/user/project/integrations/mlflow_client.md
new file mode 100644
index 00000000000..82bfd08e926
--- /dev/null
+++ b/doc/user/project/integrations/mlflow_client.md
@@ -0,0 +1,81 @@
+---
+stage: Create
+group: Incubation
+info: Machine Learning Experiment Tracking is a GitLab Incubation Engineering program. No technical writer assigned to this group.
+---
+
+# MLFlow Client Integration **(FREE)**
+
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/8560) in GitLab 15.6 as an [Alpha](../../../policy/alpha-beta-support.md#alpha-features) release [with a flag](../../../administration/feature_flags.md) named `ml_experiment_tracking`. Disabled by default.
+
+DISCLAIMER:
+MLFlow Client Integration is an experimental feature being developed by the Incubation Engineering Department,
+and will receive significant changes over time.
+
+[MLFlow](https://mlflow.org/) is one of the most popular open source tools for Machine Learning Experiment Tracking.
+GitLabs works as a backend to the MLFlow Client, [logging experiments](../ml/experiment_tracking/index.md).
+Setting up your integrations requires minimal changes to existing code.
+
+GitLab plays the role of proxy server, both for artifact storage and tracking data. It reflects the
+MLFlow [Scenario 5](https://www.mlflow.org/docs/latest/tracking.html#scenario-5-mlflow-tracking-server-enabled-with-proxied-artifact-storage-access).
+
+## Enable MFlow Client Integration
+
+Complete this task to enable MFlow Client Integration.
+
+Prerequisites:
+
+- A [personal access token](../../../user/profile/personal_access_tokens.md) for the project, with minimum access level of `api`.
+- The project ID. To find the project ID, on the top bar, select **Main menu > Projects** and find your project. On the left sidebar, select **Settings > General**.
+
+1. Set the tracking URI and token environment variables on the host that runs the code (your local environment, CI pipeline, or remote host).
+
+ For example:
+
+ ```shell
+ export MLFLOW_TRACKING_URI="http://<your gitlab endpoint>/api/v4/projects/<your project id>/ml/mlflow"
+ export MLFLOW_TRACKING_TOKEN="<your_access_token>"
+ ```
+
+1. If your training code contains the call to `mlflow.set_tracking_uri()`, remove it.
+
+When running the training code, MLFlow will create experiments, runs, log parameters, metrics,
+and artifacts on GitLab.
+
+After experiments are logged, they are listed under `/<your project>/-/ml/experiments`. Runs are registered as Model Candidates,
+that can be explored by selecting an experiment.
+
+## Limitations
+
+- The API GitLab supports is the one defined at MLFlow version 1.28.0.
+- API endpoints not listed above are not supported.
+- During creation of experiments and runs, tags are ExperimentTags and RunTags are ignored.
+- MLFLow Model Registry is not supported.
+
+## Supported methods and caveats
+
+This is a list of methods we support from the MLFlow client. Other methods might be supported but were not
+tested. More information can be found in the [MLFlow Documentation](https://www.mlflow.org/docs/1.28.0/python_api/mlflow.html).
+
+### `set_experiment`
+
+Accepts both experiment_name and experiment_id
+
+### `start_run()`
+
+- Nested runs have not been tested.
+- `run_name` is not supported
+
+### `log_param()`, `log_params()`, `log_metric()`, `log_metrics()`
+
+Work as defined by the documentation
+
+### `log_artifact()`, `log_artifacts()`
+
+`artifact_path` must be empty string.
+
+### `log_model()`
+
+This is an experimental method in MLFlow, and partial support is offered. It stores the model artifacts, but does
+not log the model information. The `artifact_path` parameter must be set to `''`, because Generic Packages do not support folder
+structure.
diff --git a/doc/user/project/integrations/prometheus_library/nginx_ingress.md b/doc/user/project/integrations/prometheus_library/nginx_ingress.md
index 99466a67417..947210541f4 100644
--- a/doc/user/project/integrations/prometheus_library/nginx_ingress.md
+++ b/doc/user/project/integrations/prometheus_library/nginx_ingress.md
@@ -38,7 +38,7 @@ Next, the Ingress needs to be annotated for Prometheus monitoring. Two new annot
- `prometheus.io/scrape: "true"`
- `prometheus.io/port: "10254"`
-Managing these settings depends on how NGINX Ingress has been deployed. If you have deployed via the [official Helm chart](https://github.com/helm/charts/tree/master/stable/nginx-ingress), metrics can be enabled with `controller.stats.enabled` along with the required annotations. Alternatively it is possible to edit the NGINX Ingress YAML directly in the [Kubernetes dashboard](https://github.com/kubernetes/dashboard).
+Managing these settings depends on how NGINX Ingress has been deployed. If you have deployed via the [official Helm chart](https://github.com/kubernetes/ingress-nginx/tree/master/charts/ingress-nginx), metrics can be enabled with `controller.stats.enabled` along with the required annotations. Alternatively it is possible to edit the NGINX Ingress YAML directly in the [Kubernetes dashboard](https://github.com/kubernetes/dashboard).
## Specifying the Environment label
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 e26f93351a1..e6f2ac2753a 100644
--- a/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md
+++ b/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md
@@ -38,7 +38,7 @@ Next, the Ingress needs to be annotated for Prometheus monitoring. Two new annot
- `prometheus.io/scrape: "true"`
- `prometheus.io/port: "10254"`
-Managing these settings depends on how NGINX Ingress has been deployed. If you have deployed via the [official Helm chart](https://github.com/helm/charts/tree/master/stable/nginx-ingress), metrics can be enabled with `controller.stats.enabled` along with the required annotations. Alternatively it is possible edit the NGINX Ingress YAML directly in the [Kubernetes dashboard](https://github.com/kubernetes/dashboard).
+Managing these settings depends on how NGINX Ingress has been deployed. If you have deployed via the [official Helm chart](https://github.com/kubernetes/ingress-nginx/tree/master/charts/ingress-nginx), metrics can be enabled with `controller.stats.enabled` along with the required annotations. Alternatively it is possible edit the NGINX Ingress YAML directly in the [Kubernetes dashboard](https://github.com/kubernetes/dashboard).
## Specifying the Environment label
diff --git a/doc/user/project/integrations/servicenow.md b/doc/user/project/integrations/servicenow.md
index d528d1a5547..fcc8db7cb87 100644
--- a/doc/user/project/integrations/servicenow.md
+++ b/doc/user/project/integrations/servicenow.md
@@ -35,7 +35,5 @@ You can:
For more information, refer to the following ServiceNow resources:
- [ServiceNow DevOps home page](https://www.servicenow.com/products/devops.html)
-- [Install DevOps](https://docs.servicenow.com/bundle/paris-devops/page/product/enterprise-dev-ops/task/activate-dev-ops.html)
-- [Install DevOps Integrations](https://docs.servicenow.com/bundle/paris-devops/page/product/enterprise-dev-ops/task/activate-dev-ops-integrations.html)
+- [ServiceNow DevOps documentation](https://docs.servicenow.com/bundle/tokyo-devops/page/product/enterprise-dev-ops/concept/dev-ops-bundle-landing-page.html)
- [GitLab SCM and Continuous Integration for DevOps](https://store.servicenow.com/sn_appstore_store.do#!/store/application/54dc4eacdbc2dcd02805320b7c96191e/)
-- [Model a GitLab CI pipeline in DevOps](https://docs.servicenow.com/bundle/paris-devops/page/product/enterprise-dev-ops/task/model-gitlab-pipeline-dev-ops.html).
diff --git a/doc/user/project/integrations/slack.md b/doc/user/project/integrations/slack.md
index 9fe0c76ec4f..d34c558ebbc 100644
--- a/doc/user/project/integrations/slack.md
+++ b/doc/user/project/integrations/slack.md
@@ -4,9 +4,9 @@ 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
---
-# Slack notifications service **(FREE)**
+# Slack notifications integration **(FREE)**
-The Slack notifications service enables your GitLab project to send events
+The Slack notifications integration enables your GitLab project to send events
(such as issue creation) to your existing Slack team as notifications. Setting up
Slack notifications requires configuration changes for both Slack and GitLab.
@@ -45,7 +45,7 @@ to control GitLab from Slack. Slash commands are configured separately.
1. Optional. In **Username**, enter the username of the Slack bot that sends
the notifications.
1. Select the **Notify only broken pipelines** checkbox to notify only on failures.
-1. In the **Branches for which notifications are to be sent** dropdown, select which types of branches
+1. In the **Branches for which notifications are to be sent** dropdown list, select which types of branches
to send notifications for.
1. Leave the **Labels to be notified** field blank to get all notifications, or
add labels that the issue or merge request must have to trigger a
@@ -91,7 +91,7 @@ the error message and keep troubleshooting from there.
You might see an entry like the following in your Sidekiq log:
```plaintext
-2019-01-10_13:22:08.42572 2019-01-10T13:22:08.425Z 6877 TID-abcdefg Integrations::ExecuteWorker JID-3bade5fb3dd47a85db6d78c5 ERROR: {:class=>"Integrations::ExecuteWorker :service_class=>"SlackService", :message=>"SSL_connect returned=1 errno=0 state=error: certificate verify failed"}
+2019-01-10_13:22:08.42572 2019-01-10T13:22:08.425Z 6877 TID-abcdefg Integrations::ExecuteWorker JID-3bade5fb3dd47a85db6d78c5 ERROR: {:class=>"Integrations::ExecuteWorker :integration_class=>"SlackService", :message=>"SSL_connect returned=1 errno=0 state=error: certificate verify failed"}
```
This issue occurs when there is a problem with GitLab communicating with Slack,
@@ -128,20 +128,20 @@ the GitLab OpenSSL trust store is incorrect. Typical causes are:
- Overriding the trust store with `gitlab_rails['env'] = {"SSL_CERT_FILE" => "/path/to/file.pem"}`.
- Accidentally modifying the default CA bundle `/opt/gitlab/embedded/ssl/certs/cacert.pem`.
-### Bulk update to disable the Slack Notification service
+### Bulk update to disable the Slack Notification integration
To disable notifications for all projects that have Slack integration enabled,
[start a rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session) and use a script similar to the following:
WARNING:
-Any command that changes data directly could be damaging if not run correctly, or under the right conditions. We highly recommend running them in a test environment with a backup of the instance ready to be restored, just in case.
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
```ruby
# Grab all projects that have the Slack notifications enabled
p = Project.find_by_sql("SELECT p.id FROM projects p LEFT JOIN integrations s ON p.id = s.project_id WHERE s.type_new = 'Slack' AND s.active = true")
-# Disable the service on each of the projects that were found.
+# Disable the integration on each of the projects that were found.
p.each do |project|
- project.slack_service.update!(:active, false)
+ project.slack_integration.update!(:active, false)
end
```
diff --git a/doc/user/project/integrations/slack_slash_commands.md b/doc/user/project/integrations/slack_slash_commands.md
index cb698ac0ee0..f4c789239f3 100644
--- a/doc/user/project/integrations/slack_slash_commands.md
+++ b/doc/user/project/integrations/slack_slash_commands.md
@@ -14,7 +14,7 @@ GitLab can also send events (for example, `issue created`) to Slack as notificat
The [Slack notifications service](slack.md) is configured separately.
NOTE:
-For GitLab.com, use the [GitLab Slack app](gitlab_slack_application.md) instead.
+For GitLab.com, use the [GitLab for Slack app](gitlab_slack_application.md) instead.
## Configure GitLab and Slack
diff --git a/doc/user/project/integrations/unify_circuit.md b/doc/user/project/integrations/unify_circuit.md
index c13f642d9e9..77530b4b417 100644
--- a/doc/user/project/integrations/unify_circuit.md
+++ b/doc/user/project/integrations/unify_circuit.md
@@ -22,7 +22,7 @@ In GitLab:
1. Select the checkboxes corresponding to the GitLab events you want to receive in Unify Circuit.
1. Paste the **Webhook URL** that you copied from the Unify Circuit configuration step.
1. Select the **Notify only broken pipelines** checkbox to notify only on failures.
-1. In the **Branches for which notifications are to be sent** dropdown, select which types of branches to send notifications for.
+1. In the **Branches for which notifications are to be sent** dropdown list, select which types of branches to send notifications for.
1. Select `Save changes` or optionally select **Test settings**.
Your Unify Circuit conversation now starts receiving GitLab event notifications.
diff --git a/doc/user/project/integrations/webex_teams.md b/doc/user/project/integrations/webex_teams.md
index 930ca8e99b8..be4528ba70d 100644
--- a/doc/user/project/integrations/webex_teams.md
+++ b/doc/user/project/integrations/webex_teams.md
@@ -13,7 +13,7 @@ You can configure GitLab to send notifications to a Webex Teams space:
## Create a webhook for the space
-1. Go to the [Incoming Webhooks app page](https://apphub.webex.com/applications/incoming-webhooks-cisco-systems-38054-23307).
+1. Go to the [Incoming Webhooks app page](https://apphub.webex.com/applications/incoming-webhooks-cisco-systems-38054-23307-75252).
1. Select **Connect**, and sign in to Webex Teams if required.
1. Enter a name for the webhook and select the space to receive the notifications.
1. Select **ADD**.
diff --git a/doc/user/project/integrations/webhook_events.md b/doc/user/project/integrations/webhook_events.md
index c0f0f5a0cd4..60187b9a682 100644
--- a/doc/user/project/integrations/webhook_events.md
+++ b/doc/user/project/integrations/webhook_events.md
@@ -611,7 +611,8 @@ Payload example:
"name": "User1",
"username": "user1",
"avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=40\u0026d=identicon"
- }
+ },
+ "detailed_merge_status": "checking"
}
}
```
@@ -947,7 +948,8 @@ Payload example:
"type": "ProjectLabel",
"group_id": 41
}],
- "action": "open"
+ "action": "open",
+ "detailed_merge_status": "mergeable"
},
"labels": [{
"id": 206,
@@ -1017,7 +1019,7 @@ Payload example:
```
NOTE:
-The fields `assignee_id`, and `state` are deprecated.
+The fields `assignee_id`, `state`, `merge_status` are deprecated.
## Wiki page events
@@ -1132,6 +1134,7 @@ Payload example:
"target_project_id": 1,
"state": "opened",
"merge_status": "can_be_merged",
+ "detailed_merge_status": "mergeable",
"url": "http://192.168.64.1:3005/gitlab-org/gitlab-test/merge_requests/1"
},
"user":{
@@ -1359,6 +1362,15 @@ Payload example:
## Job events
+- Number of retries [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/382046) in GitLab 15.6 [with a flag](../../../administration/feature_flags.md)
+ named `job_webhook_retries_count`. 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
+`job_webhook_retries_count`.
+On GitLab.com, this feature is not available.
+
Job events are triggered when the status of a job changes.
The `commit.id` in the payload is the ID of the pipeline, not the ID of the commit.
@@ -1391,6 +1403,7 @@ Payload example:
"build_duration": null,
"build_allow_failure": false,
"build_failure_reason": "script_failure",
+ "retries_count": 2, // 2 indicates this is the 2nd retry of this job
"pipeline_id": 2366,
"project_id": 380,
"project_name": "gitlab-org/gitlab-test",
diff --git a/doc/user/project/integrations/webhooks.md b/doc/user/project/integrations/webhooks.md
index 9fc9d6e2eda..ef6957ac2d8 100644
--- a/doc/user/project/integrations/webhooks.md
+++ b/doc/user/project/integrations/webhooks.md
@@ -115,6 +115,15 @@ a test request to re-enable a [disabled webhook](#re-enable-disabled-webhooks).
For example, to test `push events`, your project should have at least one commit. The webhook uses this commit in the webhook.
+NOTE:
+Testing is not supported for some types of events for project and groups webhooks.
+Read more in [issue 379201](https://gitlab.com/gitlab-org/gitlab/-/issues/379201).
+
+Prerequisites:
+
+- To test project webhooks, you must have at least the Maintainer role for the project.
+- To test group webhooks, you must have the Owner role for the group.
+
To test a webhook:
1. In your project or group, on the left sidebar, select **Settings > Webhooks**.
@@ -177,9 +186,13 @@ that the request is legitimate.
## Filter push events by branch
-Push events can be filtered by branch using a branch name or wildcard pattern
-to limit which push events are sent to your webhook endpoint. By default,
-all push events are sent to your webhook endpoint. You can configure branch filtering
+You can filter push events by branch. Use one of the following options to filter which push events are sent to your webhook endpoint:
+
+- **All branches**: push events from all branches.
+- **Wildcard pattern**: push events from a branch that matches a wildcard pattern (for example, `*-stable` or `production/*`).
+- **Regular expression**: push events from a branch that matches a regular expression (for example, `(feature|hotfix)/*`).
+
+You can configure branch filtering
in the [webhook settings](#configure-a-webhook-in-gitlab) in your project.
## How image URLs are displayed in the webhook body
@@ -233,6 +246,11 @@ Webhook requests to your endpoint include the following headers:
GitLab records the history of each webhook request.
You can view requests made in the last 2 days in the **Recent events** table.
+Prerequisites:
+
+- To troubleshoot project webhooks, you must have at least the Maintainer role for the project.
+- To troubleshoot group webhooks, you must have the Owner role for the group.
+
To view the table:
1. In your project or group, on the left sidebar, select **Settings > Webhooks**.
diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md
index 1cf902d2290..c2952b23615 100644
--- a/doc/user/project/issue_board.md
+++ b/doc/user/project/issue_board.md
@@ -707,6 +707,14 @@ A few things to remember:
## Troubleshooting issue boards
+### `There was a problem fetching users` on group issue board when filtering by Author or Assignee
+
+If you get a banner with `There was a problem fetching users` error when filtering by author or assignee on
+group issue board, make sure that you are added as a member to the current group.
+Non-members do not have permission to list group members when filtering by author or assignee on issue boards.
+
+To fix this error, you should add all of your users to the top-level group with at least the Guest role.
+
### Use Rails console to fix issue boards not loading and timing out
If you see issue board not loading and timing out in UI, use Rails console to call the Issue Rebalancing service to fix it:
diff --git a/doc/user/project/issues/confidential_issues.md b/doc/user/project/issues/confidential_issues.md
index b1bb3f0dbf8..2b302a60d63 100644
--- a/doc/user/project/issues/confidential_issues.md
+++ b/doc/user/project/issues/confidential_issues.md
@@ -16,9 +16,9 @@ keep security vulnerabilities private or prevent surprises from leaking out.
You can make an issue confidential when you create or edit an issue.
When you create a new issue, a checkbox right below the text area is available
-to mark the issue as confidential. Check that box and hit the **Create issue**
-button to create the issue. For existing issues, edit them, check the
-confidential checkbox and hit **Save changes**.
+to mark the issue as confidential. Check that box and select **Create issue**
+to create the issue. For existing issues, edit them, check the
+confidential checkbox and select **Save changes**.
When you create a confidential issue in a project, the project becomes listed in the **Contributed projects** section in your [profile](../../profile/index.md). **Contributed projects** does not show information about the confidential issue; it only shows the project name.
diff --git a/doc/user/project/issues/design_management.md b/doc/user/project/issues/design_management.md
index 593557967ed..27d935d0ed1 100644
--- a/doc/user/project/issues/design_management.md
+++ b/doc/user/project/issues/design_management.md
@@ -4,7 +4,7 @@ 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
---
-# Design Management **(FREE)**
+# Design management **(FREE)**
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/660) in GitLab 12.2.
> - Support for SVGs [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12771) in GitLab 12.4.
diff --git a/doc/user/project/issues/due_dates.md b/doc/user/project/issues/due_dates.md
index 6293fe981de..f41c90a74a5 100644
--- a/doc/user/project/issues/due_dates.md
+++ b/doc/user/project/issues/due_dates.md
@@ -35,7 +35,7 @@ The last way to set a due date is by using [quick actions](../quick_actions.md),
You can see issues with their due dates in the issues list.
Overdue issues have their icon and date colored red.
-To sort issues by their due dates, select **Due date** from the dropdown menu on the right.
+To sort issues by their due dates, select **Due date** from the dropdown list on the right.
Issues are then sorted from the earliest due date to the latest.
To display issues with the latest due dates at the top, select **Sort direction** (**{sort-lowest}**).
diff --git a/doc/user/project/issues/managing_issues.md b/doc/user/project/issues/managing_issues.md
index 9ec6d5b300c..8cd211a51c7 100644
--- a/doc/user/project/issues/managing_issues.md
+++ b/doc/user/project/issues/managing_issues.md
@@ -207,7 +207,8 @@ the appropriate project and followed up from there.
### Fields in the new issue form
-> Adding the new issue to an epic [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13847) in GitLab 13.1.
+> - Adding the new issue to an epic [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/13847) in GitLab 13.1.
+> - Iteration field [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/233517) in GitLab 15.6.
When you're creating a new issue, you can complete the following fields:
@@ -222,6 +223,7 @@ When you're creating a new issue, you can complete the following fields:
- [Due date](due_dates.md)
- [Milestone](../milestones/index.md)
- [Labels](../labels.md)
+- [Iteration](../../group/iterations/index.md)
## Edit an issue
@@ -340,6 +342,29 @@ To move an issue:
### Bulk move issues **(FREE SELF)**
+#### From the issues list
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15991) in GitLab 15.6.
+
+You can move multiple issues at the same time when you’re in a project.
+You can't move tasks or test cases.
+
+Prerequisite:
+
+- You must have at least the Reporter role for the project.
+
+To move multiple issues at the same time:
+
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Issues**.
+1. Select **Edit issues**. A sidebar on the right of your screen appears.
+1. Select the checkboxes next to each issue you want to move.
+1. From the right sidebar, select **Move selected**.
+1. From the dropdown list, select the destination project.
+1. Select **Move**.
+
+#### From the Rails console
+
You can move all open issues from one project to another.
Prerequisites:
@@ -586,7 +611,7 @@ To filter the list of issues:
1. Select or type the operator to use for filtering the attribute. The following operators are
available:
- `=`: Is
- - `!=`: Is not ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18059) in GitLab 12.7)
+ - `!=`: Is not one of
1. Enter the text to filter the attribute by.
You can filter some attributes by **None** or **Any**.
1. Repeat this process to filter by multiple attributes. Multiple attributes are joined by a logical
@@ -595,6 +620,21 @@ To filter the list of issues:
GitLab displays the results on-screen, but you can also
[retrieve them as an RSS feed](../../search/index.md#retrieve-search-results-as-feed).
+### Filter with the OR operator
+
+> OR filtering for assignees was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/23532) in GitLab 15.6 [with a flag](../../../administration/feature_flags.md) named `or_issuable_queries`. 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 `or_issuable_queries`.
+The feature is not ready for production use.
+
+When this feature is enabled, you can use the OR operator (**is one of: `||`**)
+when you [filter the list of issues](#filter-the-list-of-issues).
+
+`is one of` represents an inclusive OR. For example, if you filter by `Assignee is one of Sidney Jones` and
+`Assignee is one of Zhang Wei`, GitLab shows issues where either Sidney, Zhang, or both of them are assignees.
+
### Filter issues by ID
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/39908) in GitLab 12.1.
@@ -648,7 +688,7 @@ you can see the change without having to refresh the page.
The following sections are updated in real time:
- [Assignee](#assignee)
-- Labels, [if enabled](../labels.md#real-time-changes-to-labels)
+- [Labels](../labels.md#assign-and-unassign-labels)
## Assignee
diff --git a/doc/user/project/issues/related_issues.md b/doc/user/project/issues/related_issues.md
index 53ad7196920..1a8f19b80ba 100644
--- a/doc/user/project/issues/related_issues.md
+++ b/doc/user/project/issues/related_issues.md
@@ -1,6 +1,6 @@
---
stage: Plan
-group: Project Management
+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
---
diff --git a/doc/user/project/labels.md b/doc/user/project/labels.md
index 826e0b21ea7..bb72ab0052d 100644
--- a/doc/user/project/labels.md
+++ b/doc/user/project/labels.md
@@ -28,10 +28,21 @@ You can use two types of labels in GitLab:
## Assign and unassign labels
-> Unassigning labels with the **X** button [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216881) in GitLab 13.5.
+> - Unassigning labels with the **X** button [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216881) in GitLab 13.5.
+> - Real-time updates in the sidebar [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/241538) in GitLab 14.10 with a [feature flag](../../administration/feature_flags.md) named `realtime_labels`, disabled by default.
+> - Real-time updates in the sidebar [enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/357370#note_991987201) in GitLab 15.1.
+> - Real-time updates in the sidebar [enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/357370) in GitLab 15.5.
+> - Real-time updates in the sidebar [generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/103199) in GitLab 15.6. Feature flag `realtime_labels` removed.
You can assign labels to any issue, merge request, or epic.
+Changed labels are immediately visible to other users, without refreshing the page, on the following:
+
+- Epics
+- Incidents
+- Issues
+- Merge requests
+
To assign or unassign a label:
1. In the **Labels** section of the sidebar, select **Edit**.
@@ -410,7 +421,7 @@ To subscribe to a label:
1. To the right of any label, select **Subscribe**.
1. Optional. If you are subscribing to a group label from a project, select either:
- **Subscribe at project level** to be notified about events in this project.
- - **Subscribe at group level**: to be notified about events in the whole group.
+ - **Subscribe at group level** to be notified about events in the whole group.
## Set label priority
@@ -444,23 +455,6 @@ The labels higher in the list get higher priority.
To learn what happens when you sort by priority or label priority, see
[Sorting and ordering issue lists](issues/sorting_issue_lists.md).
-## Real-time changes to labels
-
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/241538) in GitLab 14.10 with a [feature flag](../../administration/feature_flags.md) named `realtime_labels`, disabled by default.
-> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/357370#note_991987201) in GitLab 15.1.
-> - [Enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/357370) in GitLab 15.5.
-
-FLAG:
-On self-managed GitLab, to prevent updating labels in real-time, you can ask an administrator to [disable the feature flag](../../administration/feature_flags.md) named `realtime_labels`.
-On GitLab.com, this feature is available.
-
-Changed labels are immediately visible to other users, without refreshing the page, on the following:
-
-- Epics
-- Incidents
-- Issues
-- Merge requests
-
## Troubleshooting
### Some label titles end with `_duplicate<number>`
diff --git a/doc/user/project/members/index.md b/doc/user/project/members/index.md
index a8f1b634127..e8ec954df8f 100644
--- a/doc/user/project/members/index.md
+++ b/doc/user/project/members/index.md
@@ -45,26 +45,14 @@ flowchart RL
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 13.11 from a form to a modal window [with a flag](../../feature_flags.md). Disabled by default.
> - Modal window [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 14.8.
-> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/352526) in GitLab 14.9.
- [Feature flag `invite_members_group_modal`](https://gitlab.com/gitlab-org/gitlab/-/issues/352526) removed.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/352526) in GitLab 14.9. [Feature flag `invite_members_group_modal`](https://gitlab.com/gitlab-org/gitlab/-/issues/352526) removed.
Add users to a project so they become members and have permission
to perform actions.
-The maximum role (access level) you set depends on if you have the Owner or Maintainer role for the group. For example, the maximum
-role that can be set is:
-
-- Owner (`50`), if you have the Owner role for the project.
-- Maintainer (`40`), if you have the Maintainer role on the project.
-
-In GitLab 14.8 and earlier, direct members of a project have a maximum role of Maintainer.
-The Owner [role](../../permissions.md#project-members-permissions) can only be added at the group level.
-
Prerequisite:
-- You must have the Maintainer or Owner role:
- - To remove direct members with the Maintainer role and below, you must have the Maintainer role.
- - To remove members with the Owner role, you must have the Owner role.
+- You must have the Owner or Maintainer role.
To add a user to a project:
@@ -73,7 +61,7 @@ To add a user to a project:
1. Select **Invite members**.
1. Enter an email address and select a [role](../../permissions.md).
1. Optional. Select an **Access expiration date**.
- On that date, the user can no longer access the project.
+ From that date onwards, the user can no longer access the project.
1. Select **Invite**.
If the user has a GitLab account, they are added to the members list.
@@ -86,12 +74,22 @@ deleted after 90 days.
If the user does not have a GitLab account, they are prompted to create an account
using the email address the invitation was sent to.
+### Which roles you can assign
+
+The maximum role you can assign depends on whether you have the Owner or Maintainer
+role for the group. For example, the maximum role you can set is:
+
+- Owner (`50`), if you have the Owner role for the project.
+- Maintainer (`40`), if you have the Maintainer role on the project.
+
+In GitLab 14.8 and earlier, direct members of a project have a maximum role of Maintainer.
+The Owner [role](../../permissions.md#project-members-permissions) can be added for the group only.
+
## Add groups to a project
> - [Changed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 13.11 from a form to a modal window [with a flag](../../feature_flags.md). Disabled by default.
> - Modal window [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/247208) in GitLab 14.8.
-> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/352526) in GitLab 14.9.
- [Feature flag `invite_members_group_modal`](https://gitlab.com/gitlab-org/gitlab/-/issues/352526) removed.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/352526) in GitLab 14.9. [Feature flag `invite_members_group_modal`](https://gitlab.com/gitlab-org/gitlab/-/issues/352526) removed.
When you add a group to a project, each user in the group gets access to the project.
Each user's access is based on:
@@ -99,19 +97,20 @@ Each user's access is based on:
- The role they're assigned in the group.
- The maximum role you choose when you invite the group.
-Prerequisite:
+Prerequisites:
- You must have the Maintainer or Owner role.
- Sharing the project with other groups must not be [prevented](../../group/access_and_permissions.md#prevent-a-project-from-being-shared-with-groups).
-To add groups to a project:
+To add a group to a project:
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select **Project information > Members**.
1. Select **Invite a group**.
1. Select a group.
1. Select the highest [role](../../permissions.md) for users in the group.
-1. Optional. Select an **Access expiration date**. On that date, the group can no longer access the project.
+1. Optional. Select an **Access expiration date**.
+ From that date onwards, the group can no longer access the project.
1. Select **Invite**.
The members of the group are not displayed on the **Members** tab.
@@ -169,7 +168,9 @@ group itself.
Prerequisites:
-- You must have the Maintainer or Owner role.
+- To remove direct members with the:
+ - Maintainer, Developer, Reporter, or Guest role, you must have the Maintainer role.
+ - Owner role, you must have the Owner role.
- Optional. Unassign the member from all issues and merge requests that
are assigned to them.
@@ -187,6 +188,21 @@ To remove a member from a project:
[from being forked outside their group](../../group/access_and_permissions.md#prevent-project-forking-outside-group).
1. Select **Remove member**.
+## Ensure removed users cannot invite themselves back
+
+Malicious users with the Maintainer or Owner role could exploit a race condition that allows
+them to invite themselves back to a group or project that a GitLab administrator has removed them from.
+
+To avoid this problem, GitLab administrators can:
+
+- Remove the malicious user session from the [GitLab Rails console](../../../administration/operations/rails_console.md).
+- Impersonate the malicious user to:
+ - Remove the user from the project.
+ - Log the user out of GitLab.
+- Block the malicious user account.
+- Remove the malicious user account.
+- Change the password for the malicious user account.
+
## Filter and sort members
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21727) in GitLab 12.6.
diff --git a/doc/user/project/merge_requests/approvals/index.md b/doc/user/project/merge_requests/approvals/index.md
index ea03427161e..eb460225858 100644
--- a/doc/user/project/merge_requests/approvals/index.md
+++ b/doc/user/project/merge_requests/approvals/index.md
@@ -68,7 +68,7 @@ if a user approves a merge request and is shown in the reviewer list, a green ch
After a merge request receives the [number and type of approvals](rules.md) you configure, it can merge
unless it's blocked for another reason. Merge requests can be blocked by other problems,
-such as merge conflicts, [pending discussions](../../../discussions/index.md#prevent-merge-unless-all-threads-are-resolved),
+such as merge conflicts, [unresolved threads](../../../discussions/index.md#prevent-merge-unless-all-threads-are-resolved),
or a [failed CI/CD pipeline](../merge_when_pipeline_succeeds.md).
To prevent merge request authors from approving their own merge requests,
diff --git a/doc/user/project/merge_requests/authorization_for_merge_requests.md b/doc/user/project/merge_requests/authorization_for_merge_requests.md
index ba28432e90a..52944ee3143 100644
--- a/doc/user/project/merge_requests/authorization_for_merge_requests.md
+++ b/doc/user/project/merge_requests/authorization_for_merge_requests.md
@@ -68,6 +68,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/project/merge_requests/changes.md b/doc/user/project/merge_requests/changes.md
index 6703cbf8b03..6e8b0cb1a75 100644
--- a/doc/user/project/merge_requests/changes.md
+++ b/doc/user/project/merge_requests/changes.md
@@ -149,7 +149,7 @@ The feature is not ready for production use.
To avoid displaying the changes that are already on target branch in the diff,
we compare the merge request's source branch with HEAD of the target branch.
-When there are conflicts between the source and target branch, we show the
-conflicts on the merge request diff:
+When there are conflicts between the source and target branch, we show an alert
+per conflicted file on the merge request diff:
-![Example of a conflict shown in a merge request diff](img/conflict_ui_v14_0.png)
+![Example of a conflict alert shown in a merge request diff](img/conflict_ui_v15_6.png)
diff --git a/doc/user/project/merge_requests/conflicts.md b/doc/user/project/merge_requests/conflicts.md
index 902095bcbce..24f22924a08 100644
--- a/doc/user/project/merge_requests/conflicts.md
+++ b/doc/user/project/merge_requests/conflicts.md
@@ -172,6 +172,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/project/merge_requests/drafts.md b/doc/user/project/merge_requests/drafts.md
index 2beb7406518..0bc9b337e3b 100644
--- a/doc/user/project/merge_requests/drafts.md
+++ b/doc/user/project/merge_requests/drafts.md
@@ -88,6 +88,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/project/merge_requests/img/conflict_ui_v14_0.png b/doc/user/project/merge_requests/img/conflict_ui_v14_0.png
deleted file mode 100644
index 92c532351cb..00000000000
--- a/doc/user/project/merge_requests/img/conflict_ui_v14_0.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/merge_requests/img/conflict_ui_v15_6.png b/doc/user/project/merge_requests/img/conflict_ui_v15_6.png
new file mode 100644
index 00000000000..d5d5ad14edb
--- /dev/null
+++ b/doc/user/project/merge_requests/img/conflict_ui_v15_6.png
Binary files differ
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index e73c339e000..8309b04758a 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -250,6 +250,28 @@ This feature works only when a merge request is merged. Selecting **Remove sourc
after merging does not retarget open merge requests. This improvement is
[proposed as a follow-up](https://gitlab.com/gitlab-org/gitlab/-/issues/321559).
+## Move sidebar actions
+
+<!-- When the `moved_mr_sidebar` feature flag is removed, delete this topic and update the steps for these actions
+like in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87727/diffs?diff_id=522279685#5d9afba799c4af9920dab533571d7abb8b9e9163 -->
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85584) in GitLab 14.10 [with a flag](../../../administration/feature_flags.md) named `moved_mr_sidebar`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../../../administration/feature_flags.md) named `moved_mr_sidebar`.
+On GitLab.com, this feature is not available.
+
+When this feature flag is enabled, you can find the following actions in
+**Merge request actions** (**{ellipsis_v}**) on the top right:
+
+- 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)
+- Close merge request
+- [Lock discussion](../../discussions/index.md#prevent-comments-by-locking-the-discussion)
+- Copy reference
+
+When this feature flag is disabled, these actions are in the right sidebar.
+
## Merge request workflows
For a software developer working in a team:
@@ -289,3 +311,76 @@ For a web developer writing a webpage for your company's website:
- [Commits](commits.md)
- [CI/CD pipelines](../../../ci/index.md)
- [Push options](../push_options.md) for merge requests
+
+## Troubleshooting
+
+### Rebase a merge request from the Rails console **(FREE SELF)**
+
+In addition to the `/rebase` [quick action](../quick_actions.md#issues-merge-requests-and-epics),
+users with access to the [Rails console](../../../administration/operations/rails_console.md)
+can rebase a merge request from the Rails console. Replace `<username>`,
+`<namespace/project>`, and `<iid>` with appropriate values:
+
+WARNING:
+Any command that changes data directly could be damaging if not run correctly,
+or under the right conditions. We highly recommend running them in a test environment
+with a backup of the instance ready to be restored, just in case.
+
+```ruby
+u = User.find_by_username('<username>')
+p = Project.find_by_full_path('<namespace/project>')
+m = p.merge_requests.find_by(iid: <iid>)
+MergeRequests::RebaseService.new(project: m.target_project, current_user: u).execute(m)
+```
+
+### Fix incorrect merge request status **(FREE SELF)**
+
+If a merge request remains **Open** after its changes are merged,
+users with access to the [Rails console](../../../administration/operations/rails_console.md)
+can correct the merge request's status. Replace `<username>`, `<namespace/project>`,
+and `<iid>` with appropriate values:
+
+WARNING:
+Any command that changes data directly could be damaging if not run correctly,
+or under the right conditions. We highly recommend running them in a test environment
+with a backup of the instance ready to be restored, just in case.
+
+```ruby
+u = User.find_by_username('<username>')
+p = Project.find_by_full_path('<namespace/project>')
+m = p.merge_requests.find_by(iid: <iid>)
+MergeRequests::PostMergeService.new(project: p, current_user: u).execute(m)
+```
+
+Running this command against a merge request with unmerged changes causes the
+merge request to display an incorrect message: `merged into <branch-name>`.
+
+### Close a merge request from the Rails console **(FREE SELF)**
+
+If closing a merge request doesn't work through the UI or API, you may want to attempt to close it in a [Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session):
+
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
+```ruby
+u = User.find_by_username('<username>')
+p = Project.find_by_full_path('<namespace/project>')
+m = p.merge_requests.find_by(iid: <iid>)
+MergeRequests::CloseService.new(project: p, current_user: u).execute(m)
+```
+
+### Delete a merge request from the Rails console **(FREE SELF)**
+
+If deleting a merge request doesn't work through the UI or API, you may want to attempt to delete it in a [Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session):
+
+WARNING:
+Any command that changes data directly could be damaging if not run correctly,
+or under the right conditions. We highly recommend running them in a test environment
+with a backup of the instance ready to be restored, just in case.
+
+```ruby
+u = User.find_by_username('<username>')
+p = Project.find_by_full_path('<namespace/project>')
+m = p.merge_requests.find_by(iid: <iid>)
+Issuable::DestroyService.new(project: m.project, current_user: u).execute(m)
+```
diff --git a/doc/user/project/merge_requests/revert_changes.md b/doc/user/project/merge_requests/revert_changes.md
index 3b07f75a3a7..76f351f1346 100644
--- a/doc/user/project/merge_requests/revert_changes.md
+++ b/doc/user/project/merge_requests/revert_changes.md
@@ -95,6 +95,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/project/merge_requests/reviews/data_usage.md b/doc/user/project/merge_requests/reviews/data_usage.md
index 56fb84c8085..3a3af7a24bc 100644
--- a/doc/user/project/merge_requests/reviews/data_usage.md
+++ b/doc/user/project/merge_requests/reviews/data_usage.md
@@ -19,7 +19,7 @@ This data extraction job can take a few hours to complete (possibly up to a day)
### Generating suggestions
-Once Suggested Reviewers is enabled and the data extraction is complete, new merge requests or new commits to existing merge requests will automatically trigger a Suggested Reviewers ML model inference and generate up to 5 suggested reviewers. These suggestions are contextual to the changes in the merge request. Additional commits to merge requests may change the reviewer suggestions which will automatically update in the reviewer dropdown.
+Once Suggested Reviewers is enabled and the data extraction is complete, new merge requests or new commits to existing merge requests will automatically trigger a Suggested Reviewers ML model inference and generate up to 5 suggested reviewers. These suggestions are contextual to the changes in the merge request. Additional commits to merge requests may change the reviewer suggestions which will automatically update in the reviewer dropdown list.
## Progressive enhancement
diff --git a/doc/user/project/merge_requests/reviews/index.md b/doc/user/project/merge_requests/reviews/index.md
index ce1fc94395c..4c503211513 100644
--- a/doc/user/project/merge_requests/reviews/index.md
+++ b/doc/user/project/merge_requests/reviews/index.md
@@ -39,7 +39,7 @@ Project Maintainers or Owners can enable suggested reviewers by visiting the [pr
Enabling suggested reviewers will trigger GitLab to create an ML model for your project that will be used to generate reviewers. The larger your project, the longer this can take, but usually, the model will be ready to generate suggestions within a few hours.
-No action is required once the feature is enabled. Once the model is ready, recommendations will populate the Reviewer dropdown in the right-hand sidebar of a merge request with new commits.
+No action is required once the feature is enabled. Once the model is ready, recommendations will populate the Reviewer dropdown list in the right-hand sidebar of a merge request with new commits.
## Review a merge request
diff --git a/doc/user/project/merge_requests/reviews/suggestions.md b/doc/user/project/merge_requests/reviews/suggestions.md
index 2d3682c62d4..832f78d18a1 100644
--- a/doc/user/project/merge_requests/reviews/suggestions.md
+++ b/doc/user/project/merge_requests/reviews/suggestions.md
@@ -12,7 +12,7 @@ type: index, reference
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 with a click.
+[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
@@ -47,8 +47,11 @@ After the author applies a suggestion:
## 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.
+
Reviewers can also suggest changes to multiple lines with a single suggestion
-within merge request diff threads by adjusting the range offsets. The
+within merge request diff threads by selecting and dragging selection to all
+relevant line numbers or by adjusting the range offsets. The
offsets are relative to the position of the diff thread, and specify the
range to be replaced by the suggestion when it is applied.
diff --git a/doc/user/project/merge_requests/squash_and_merge.md b/doc/user/project/merge_requests/squash_and_merge.md
index e83e17072d6..9f87f1e2e0d 100644
--- a/doc/user/project/merge_requests/squash_and_merge.md
+++ b/doc/user/project/merge_requests/squash_and_merge.md
@@ -83,6 +83,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/project/merge_requests/versions.md b/doc/user/project/merge_requests/versions.md
index 6f29272f003..a864a9849b0 100644
--- a/doc/user/project/merge_requests/versions.md
+++ b/doc/user/project/merge_requests/versions.md
@@ -16,12 +16,12 @@ request diffs.
## Selecting a version
By default, the latest version of changes is shown. However, you
-can select an older one from version dropdown.
+can select an older one from version dropdown list.
-![Merge request versions dropdown](img/versions_dropdown.png)
+![Merge request versions dropdown list](img/versions_dropdown.png)
Merge request versions are based on push not on commit. So, if you pushed 5
-commits in a single push, it displays as a single option in the dropdown. If you
+commits in a single push, it displays as a single option in the dropdown list. If you
pushed 5 times, that counts for 5 options.
You can also compare the merge request version with an older one to see what has
@@ -76,6 +76,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/project/milestones/burndown_and_burnup_charts.md b/doc/user/project/milestones/burndown_and_burnup_charts.md
index 01eeee9d3b9..81b334c0a02 100644
--- a/doc/user/project/milestones/burndown_and_burnup_charts.md
+++ b/doc/user/project/milestones/burndown_and_burnup_charts.md
@@ -145,6 +145,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/project/milestones/index.md b/doc/user/project/milestones/index.md
index 76c5e32eb2b..bbe4aadc50d 100644
--- a/doc/user/project/milestones/index.md
+++ b/doc/user/project/milestones/index.md
@@ -238,6 +238,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/project/ml/experiment_tracking/img/candidates.png b/doc/user/project/ml/experiment_tracking/img/candidates.png
new file mode 100644
index 00000000000..df70a01a2bd
--- /dev/null
+++ b/doc/user/project/ml/experiment_tracking/img/candidates.png
Binary files differ
diff --git a/doc/user/project/ml/experiment_tracking/img/experiments.png b/doc/user/project/ml/experiment_tracking/img/experiments.png
new file mode 100644
index 00000000000..a6472406b90
--- /dev/null
+++ b/doc/user/project/ml/experiment_tracking/img/experiments.png
Binary files differ
diff --git a/doc/user/project/ml/experiment_tracking/index.md b/doc/user/project/ml/experiment_tracking/index.md
new file mode 100644
index 00000000000..e274bd7f38e
--- /dev/null
+++ b/doc/user/project/ml/experiment_tracking/index.md
@@ -0,0 +1,76 @@
+---
+stage: Create
+group: Incubation
+info: Machine Learning Experiment Tracking is a GitLab Incubation Engineering program. No technical writer assigned to this group.
+---
+
+# Machine Learning Experiment Tracking **(FREE)**
+
+DISCLAIMER:
+Machine Learning Experiment Tracking is an experimental feature being developed by the Incubation Engineering Department,
+and will receive significant changes over time. This feature is being release with the aim of getting user feedback, but
+is not stable and can lead to performance degradation. See below on how to disable this feature.
+
+When creating machine learning models, data scientists often experiment with different parameters, configurations, feature
+engineering, and so on, to improve the performance of the model. Keeping track of all this metadata and the associated
+artifacts so that the data scientist can later replicate the experiment is not trivial. Machine learning experiment
+tracking enables them to log parameters, metrics, and artifacts directly into GitLab, giving easy access later on.
+
+![List of Experiments](img/experiments.png)
+
+![Experiment Candidates](img/candidates.png)
+
+## What is an experiment?
+
+An experiment is a collection of comparable model candidates. Experiments can be long lived (for example, when they represent
+a use case), or short lived (results from hyperparameter tuning triggered by a merge request), but usually hold model candidates
+that have a similar set of parameters and metrics.
+
+## Model candidate
+
+A model candidate is a variation of the training of a machine learning model, that can be eventually promoted to a version
+of the model. The goal of a data scientist is to find the model candidate whose parameter values lead to the best model
+performance, as indicated by the given metrics.
+
+Example parameters:
+
+- Algorithm (linear regression, decision tree, and so on).
+- Hyperparameters for the algorithm (learning rate, tree depth, number of epochs).
+- Features included.
+
+## Usage
+
+### User access management
+
+An experiment is always associated to a project. Only users with access to the project an experiment is associated with
+can view that experiment data.
+
+### Tracking new experiments and trials
+
+Experiment and trials can only be tracked through the [MLFlow](https://www.mlflow.org/docs/latest/tracking.html) client
+integration. More information on how to use GitLab as a backend for MLFlow Client can be found [at the documentation page](../../integrations/mlflow_client.md).
+
+### Exploring model candidates
+
+To list the current active experiments, navigate to `https/-/ml/experiments`. To display all trials
+that have been logged, along with their metrics and parameters, selecting an experiment.
+
+### Logging artifacts
+
+Trial artifacts are saved as [generic packages](../../../packages/generic_packages/index.md), and follow all their
+conventions. After an artifact is logged for a candidate, all artifacts logged for the candidate are listed in the
+package registry. The package name for a candidate is `ml_candidate_<candidate_id>`, with version `-`.
+
+### Limitations and future
+
+- Searching experiments, searching trials, visual comparison of trials, and creating, deleting and updating experiments and trials through GitLab UI is under development.
+- No support for experiment and trial metadata that do not classify as parameters or metrics.
+
+## Disabling or enabling the Feature
+
+On self-managed GitLab, ML Experiment Tracking is disabled by default. To enable the feature, ask an administrator to [disable the feature flag](../../../../administration/feature_flags.md) named `ml_experiment_tracking`.
+On GitLab.com, this feature is currently on private testing.
+
+## Feedback, roadmap and reports
+
+For updates on the development, feedback and bug reports, refer to the [development epic](https://gitlab.com/groups/gitlab-org/-/epics/8560).
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 5ee1fa103a4..6378d962ffe 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
@@ -250,7 +250,7 @@ can use the following setup:
on the top nav.
- Select **Create Page Rule**.
- Enter the domain `www.domain.com` and select **+ Add a Setting**.
- - From the dropdown menu, choose **Forwarding URL**, then select the
+ - From the dropdown list, choose **Forwarding URL**, then select the
status code **301 - Permanent Redirect**.
- Enter the destination URL `https://domain.com`.
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 01583dbe45d..caf98e8a8a4 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
@@ -18,9 +18,9 @@ these steps, you may have to do additional configuration for the Pages site to g
1. On the top bar, select **Main menu > Projects** and find your project.
1. On the left sidebar, select the project's name.
-1. From the **Add** (**{plus}**) dropdown, select **New file**.
-1. From the **Select a template type** dropdown, select `.gitlab-ci.yml`.
-1. From the **Apply a template** dropdown, in the **Pages** section, select the name of your SSG.
+1. From the **Add** (**{plus}**) dropdown list, select **New file**.
+1. From the **Select a template type** dropdown list, select `.gitlab-ci.yml`.
+1. From the **Apply a template** dropdown list, in the **Pages** section, select the name of your SSG.
1. In the **Commit message** box, type the commit message.
1. Select **Commit changes**.
@@ -30,5 +30,9 @@ You can watch the pipeline run by navigating to **CI/CD > Pipelines**.
When the pipeline is finished, go to **Settings > Pages** to find the link to
your Pages website.
+To view the HTML and other assets that were created for the site,
+go to the **Pipelines** tab, view the job, and on the right side,
+select **Download artifacts**.
+
For every change pushed to your repository, GitLab CI/CD runs a new pipeline
that immediately publishes your changes to the Pages site.
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 33cf677e1be..69c60cab4b3 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
@@ -29,6 +29,10 @@ When the pipeline is finished, go to **Settings > Pages** to find the link to yo
For every change pushed to your repository, GitLab CI/CD runs a new pipeline
that immediately publishes your changes to the Pages site.
+To view the HTMl and other assets that were created for the site,
+go to the **Pipelines** tab, view the job, and on the right side,
+select **Download artifacts**.
+
You can take some **optional** further steps:
- Remove the fork relationship. If you want to contribute to the project you forked from,
diff --git a/doc/user/project/pages/getting_started/pages_from_scratch.md b/doc/user/project/pages/getting_started/pages_from_scratch.md
index e34544c96f8..c0a1e8f16e0 100644
--- a/doc/user/project/pages/getting_started/pages_from_scratch.md
+++ b/doc/user/project/pages/getting_started/pages_from_scratch.md
@@ -420,6 +420,10 @@ Now GitLab CI/CD not only builds the website, but also:
- **Caches** dependencies installed with Bundler.
- **Continuously deploys** every push to the `main` branch.
+To view the HTMl and other assets that were created for the site,
+go to the **Pipelines** tab, view the job, and on the right side,
+select **Download artifacts**.
+
## Related topics
For more information, see the following blog posts.
@@ -427,7 +431,7 @@ For more information, see the following blog posts.
- Use GitLab CI/CD `environments` to
[deploy your web app to staging and production](https://about.gitlab.com/blog/2021/02/05/ci-deployment-and-environments/).
- Learn how to run jobs
- [sequentially, in parallel, or build a custom pipeline](https://about.gitlab.com/blog/2016/07/29/the-basics-of-gitlab-ci/).
+ [sequentially, in parallel, or build a custom pipeline](https://about.gitlab.com/blog/2020/12/10/basics-of-gitlab-ci-updated/).
- Learn [how to pull specific directories from different projects](https://about.gitlab.com/blog/2016/12/07/building-a-new-gitlab-docs-site-with-nanoc-gitlab-ci-and-gitlab-pages/)
to deploy this website, <https://docs.gitlab.com>.
- Learn [how to use GitLab Pages to produce a code coverage report](https://about.gitlab.com/blog/2016/11/03/publish-code-coverage-report-with-gitlab-pages/).
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 d7e304dc6f8..e4890954d13 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
@@ -28,3 +28,7 @@ your Pages website.
For every change pushed to your repository, GitLab CI/CD runs a new pipeline
that immediately publishes your changes to the Pages site.
+
+To view the HTMl and other assets that were created for the site,
+go to the **Pipelines** tab, view the job, and on the right side,
+select **Download artifacts**.
diff --git a/doc/user/project/pages/getting_started/pages_ui.md b/doc/user/project/pages/getting_started/pages_ui.md
index 064255c094f..ba97fcb8749 100644
--- a/doc/user/project/pages/getting_started/pages_ui.md
+++ b/doc/user/project/pages/getting_started/pages_ui.md
@@ -41,6 +41,10 @@ To build your YAML file from the GitLab UI:
1. Commit your `.gitlab-ci.yml` to your repository. This commit triggers your first
GitLab Pages deployment.
+To view the HTMl and other assets that were created for the site,
+go to **CI/CD > Pipelines**, view the job, and on the right side,
+select **Download artifacts**.
+
## Troubleshooting
### If you can't see the "Get Started with Pages" interface
diff --git a/doc/user/project/pages/img/remove_pages_v15_3.png b/doc/user/project/pages/img/remove_pages_v15_3.png
deleted file mode 100644
index f740daf5c0b..00000000000
--- a/doc/user/project/pages/img/remove_pages_v15_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/pages/index.md b/doc/user/project/pages/index.md
index 47c0885c26b..9305b92bf7d 100644
--- a/doc/user/project/pages/index.md
+++ b/doc/user/project/pages/index.md
@@ -107,7 +107,7 @@ These GitLab Pages website examples can teach you advanced techniques to use
and adapt for your own needs:
- [Posting to your GitLab Pages blog from iOS](https://about.gitlab.com/blog/2016/08/19/posting-to-your-gitlab-pages-blog-from-ios/).
-- [GitLab CI: Run jobs sequentially, in parallel, or build a custom pipeline](https://about.gitlab.com/blog/2016/07/29/the-basics-of-gitlab-ci/).
+- [GitLab CI: Run jobs sequentially, in parallel, or build a custom pipeline](https://about.gitlab.com/blog/2020/12/10/basics-of-gitlab-ci-updated/).
- [GitLab CI: Deployment & environments](https://about.gitlab.com/blog/2021/02/05/ci-deployment-and-environments/).
- [Building a new GitLab docs site with Nanoc, GitLab CI, and GitLab Pages](https://about.gitlab.com/blog/2016/12/07/building-a-new-gitlab-docs-site-with-nanoc-gitlab-ci-and-gitlab-pages/).
- [Publish code coverage reports with GitLab Pages](https://about.gitlab.com/blog/2016/11/03/publish-code-coverage-report-with-gitlab-pages/).
diff --git a/doc/user/project/pages/introduction.md b/doc/user/project/pages/introduction.md
index ed154c0dfca..a9b8960d629 100644
--- a/doc/user/project/pages/introduction.md
+++ b/doc/user/project/pages/introduction.md
@@ -40,20 +40,19 @@ If you are using [GitLab Pages on GitLab.com](#gitlab-pages-on-gitlabcom) to hos
Visit the [GitLab Pages group](https://gitlab.com/groups/pages) for a complete list of example projects. Contributions are very welcome.
-## Custom error codes Pages
+## Custom error codes pages
-You can provide your own 403 and 404 error pages by creating the `403.html` and
-`404.html` files respectively in the root directory of the `public/` directory
-that are included in the artifacts. Usually this is the root directory of
-your project, but that may differ depending on your static generator
-configuration.
+You can provide your own `403` and `404` error pages by creating `403.html` and
+`404.html` files in the root of the `public/` directory. Usually this is
+the root directory of your project, but that may differ
+depending on your static generator configuration.
If the case of `404.html`, there are different scenarios. For example:
- If you use project Pages (served under `/projectname/`) and try to access
`/projectname/non/existing_file`, GitLab Pages tries to serve first
`/projectname/404.html`, and then `/404.html`.
-- If you use user/group Pages (served under `/`) and try to access
+- If you use user or group Pages (served under `/`) and try to access
`/non/existing_file` GitLab Pages tries to serve `/404.html`.
- If you use a custom domain and try to access `/non/existing_file`, GitLab
Pages tries to serve only `/404.html`.
@@ -63,34 +62,34 @@ If the case of `404.html`, there are different scenarios. For example:
You can configure redirects for your site using a `_redirects` file. To learn more, read
the [redirects documentation](redirects.md).
-## GitLab Pages Access Control
+## Remove your pages
-To restrict access to your website, enable [GitLab Pages Access Control](pages_access_control.md).
+To remove your pages:
-## Unpublishing your Pages
-
-If you ever feel the need to purge your Pages content, you can do so by going
-to your project's settings through the gear icon in the top right, and then
-navigating to **Pages**. Select the **Remove pages** button to delete your Pages
-website.
-
-![Remove pages](img/remove_pages_v15_3.png)
+1. On the top bar, select **Main menu > Projects** and find your project.
+1. On the left sidebar, select **Settings > Pages**.
+1. Select **Remove pages**.
## Subdomains of subdomains
When using Pages under the top-level domain of a GitLab instance (`*.example.io`), you can't use HTTPS with subdomains
of subdomains. If your namespace or group name contains a dot (for example, `foo.bar`) the domain
-`https://foo.bar.example.io` does _not_ work.
+`https://foo.bar.example.io` does **not** work.
This limitation is because of the [HTTP Over TLS protocol](https://www.rfc-editor.org/rfc/rfc2818#section-3.1). HTTP pages
work as long as you don't redirect HTTP to HTTPS.
-## GitLab Pages and subgroups
+## GitLab Pages in projects and groups
+
+You must host your GitLab Pages website in a project. This project can be
+[private, internal, or public](../../../user/public_access.md) and belong
+to a [group](../../group/index.md) or [subgroup](../../group/subgroups/index.md).
+
+For [group websites](../../project/pages/getting_started_part_one.md#user-and-group-website-examples),
+the group must be at the top level and not a subgroup.
-You must host your GitLab Pages website in a project. This project can belong to a [group](../../group/index.md) or
-[subgroup](../../group/subgroups/index.md). For
-[group websites](../../project/pages/getting_started_part_one.md#gitlab-pages-default-domain-names), the group must be
-at the top level and not a subgroup.
+For [project websites](../../project/pages/getting_started_part_one.md#project-website-examples),
+you can create your project first and access it under `http(s)://namespace.example.io/projectname`.
## Specific configuration options for Pages
@@ -129,7 +128,7 @@ pages:
See this document for a [step-by-step guide](getting_started/pages_from_scratch.md).
-### `.gitlab-ci.yml` for a repository where there's also actual code
+### `.gitlab-ci.yml` for a repository with code
Remember that GitLab Pages are by default branch/tag agnostic and their
deployment relies solely on what you specify in `.gitlab-ci.yml`. You can limit
@@ -257,26 +256,6 @@ instead. Here are some examples of what happens given the above Pages site:
Note that when `public/data/index.html` exists, it takes priority over the `public/data.html` file
for both the `/data` and `/data/` URL paths.
-## Frequently Asked Questions
-
-### Can you download your generated pages?
-
-Sure. All you need to do is download the artifacts archive from the job page.
-
-### Can you use GitLab Pages if your project is private?
-
-Yes. GitLab Pages doesn't care whether you set your project's visibility level
-to private, internal or public.
-
-### Can you create a personal or a group website?
-
-Yes. See the documentation about [GitLab Pages domain names, URLs, and base URLs](getting_started_part_one.md).
-
-### Do you need to create a user/group website before creating a project website?
-
-No, you don't. You can create your project first and access it under
-`http(s)://namespace.example.io/projectname`.
-
## Known issues
For a list of known issues, visit the GitLab [public issue tracker](https://gitlab.com/gitlab-org/gitlab/-/issues?label_name[]=Category%3APages).
diff --git a/doc/user/project/pages/pages_access_control.md b/doc/user/project/pages/pages_access_control.md
index be1ea236c87..b98772a6702 100644
--- a/doc/user/project/pages/pages_access_control.md
+++ b/doc/user/project/pages/pages_access_control.md
@@ -20,7 +20,7 @@ For a demonstration, see [Pages access controls](https://www.youtube.com/watch?v
1. Toggle the **Pages** button to enable the access control. If you don't see the toggle button,
that means it isn't enabled. Ask your administrator to [enable it](../../../administration/pages/index.md#access-control).
-1. The Pages access control dropdown allows you to set who can view pages hosted
+1. The Pages access control dropdown list allows you to set who can view pages hosted
with GitLab Pages, depending on your project's visibility:
- If your project is private:
diff --git a/doc/user/project/pages/public_folder.md b/doc/user/project/pages/public_folder.md
index b5d498402d5..a19e296b954 100644
--- a/doc/user/project/pages/public_folder.md
+++ b/doc/user/project/pages/public_folder.md
@@ -116,7 +116,7 @@ GitLab Pages supports only static sites.
```
1. Configure your Nuxt.js application for
- [Static Site Generation](https://nuxtjs.org/docs/features/deployment-targets#static-hosting).
+ [Static Site Generation](https://nuxtjs.org/docs/features/deployment-targets/#static-hosting).
### Vite
diff --git a/doc/user/project/protected_branches.md b/doc/user/project/protected_branches.md
index f9dcf838c33..ab97ff08123 100644
--- a/doc/user/project/protected_branches.md
+++ b/doc/user/project/protected_branches.md
@@ -260,6 +260,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/project/protected_tags.md b/doc/user/project/protected_tags.md
index 22ce81409a3..152a55d24b7 100644
--- a/doc/user/project/protected_tags.md
+++ b/doc/user/project/protected_tags.md
@@ -114,6 +114,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/project/quick_actions.md b/doc/user/project/quick_actions.md
index 3471123f8b5..7b7619cfeb5 100644
--- a/doc/user/project/quick_actions.md
+++ b/doc/user/project/quick_actions.md
@@ -52,7 +52,7 @@ threads. Some quick actions might not be available to all subscription tiers.
| Command | Issue | Merge request | Epic | Action |
|:-------------------------------------------------------------------------------------------------|:-----------------------|:-----------------------|:-----------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `/add_contacts [contact:email1@example.com] [contact:email2@example.com]` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add one or more [CRM contacts](../crm/index.md) ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73413) in GitLab 14.6). |
+| `/add_contacts [contact:email1@example.com] [contact:email2@example.com]` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add one or more active [CRM contacts](../crm/index.md) ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73413) in GitLab 14.6). |
| `/approve` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Approve the merge request. |
| `/assign @user1 @user2` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Assign one or more users. |
| `/assign me` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Assign yourself. |
@@ -65,7 +65,7 @@ threads. Some quick actions might not be available to all subscription tiers.
| `/clear_weight` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Clear weight. |
| `/clone <path/to/project> [--with_notes]` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Clone the issue to given project, or the current one if no arguments are given ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/9421) in GitLab 13.7). Copies as much data as possible as long as the target project contains equivalent labels, milestones, and so on. Does not copy comments or system notes unless `--with_notes` is provided as an argument. |
| `/close` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Close. |
-| `/confidential` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Make confidential. |
+| `/confidential` | **{check-circle}** Yes | **{dotted-circle}** No | **{check-circle}** Yes | Mark issue or epic as confidential. Support for epics [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213741) in GitLab 15.6. |
| `/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. |
@@ -74,13 +74,13 @@ threads. Some quick actions might not be available to all subscription tiers.
| `/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`. |
| `/duplicate <#issue>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Close this issue and mark as a duplicate of another issue. Also, mark both as related. |
| `/epic <epic>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add to epic `<epic>`. The `<epic>` value should be in the format of `&epic`, `group&epic`, or a URL to an epic. |
-| `/estimate <time>` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Set time estimate. For example, `/estimate 1mo 2w 3d 4h 5m`. Learn more about [time tracking](time_tracking.md). |
+| `/estimate <time>` or `/estimate_time <time>` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Set time estimate. For example, `/estimate 1mo 2w 3d 4h 5m`. Learn more about [time tracking](time_tracking.md). Alias `/estimate_time` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16501) in GitLab 15.6. |
| `/health_status <value>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set [health status](issues/managing_issues.md#health-status). Valid options for `<value>` are `on_track`, `needs_attention`, and `at_risk` ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/213814) in GitLab 14.7). |
| `/invite_email email1 email2` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add up to six email participants. This action is behind feature flag `issue_email_participants` and is not yet supported in issue templates. |
| `/iteration *iteration:"iteration name"` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Set iteration. For example, to set the `Late in July` iteration: `/iteration *iteration:"Late in July"` ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196795) in GitLab 13.1). |
| `/label ~label1 ~label2` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Add one or more labels. Label names can also start without a tilde (`~`), but mixed syntax is not supported. |
| `/lock` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Lock the discussions. |
-| `/link` | **{check-circle}** Yes | ****{dotted-circle}** No | **{dotted-circle}** No | Add a link and description to [linked resources](../../operations/incident_management/linked_resources.md) in an incident ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/374964) in GitLab 15.5). |
+| `/link` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Add a link and description to [linked resources](../../operations/incident_management/linked_resources.md) in an incident ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/374964) in GitLab 15.5). |
| `/merge` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Merge changes. Depending on the project setting, this may be [when the pipeline succeeds](merge_requests/merge_when_pipeline_succeeds.md), or adding to a [Merge Train](../../ci/pipelines/merge_trains.md). |
| `/milestone %milestone` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Set milestone. |
| `/move <path/to/project>` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Move this issue to another project. Be careful when moving an issue to a project with different access rules. Before moving the issue, make sure it does not contain sensitive data. |
@@ -99,7 +99,7 @@ threads. Some quick actions might not be available to all subscription tiers.
| `/remove_contacts [contact:email1@example.com] [contact:email2@example.com]` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Remove one or more [CRM contacts](../crm/index.md) ([introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/73413) in GitLab 14.6). |
| `/remove_due_date` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Remove due date. |
| `/remove_epic` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Remove from epic. |
-| `/remove_estimate` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Remove time estimate. |
+| `/remove_estimate` or `/remove_time_estimate` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Remove time estimate. Alias `/remove_time_estimate` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16501) in GitLab 15.6. |
| `/remove_iteration` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Remove iteration ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/196795) in GitLab 13.1). |
| `/remove_milestone` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Remove milestone. |
| `/remove_parent_epic` | **{dotted-circle}** No | **{dotted-circle}** No | **{check-circle}** Yes | Remove parent epic from epic ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10556) in GitLab 12.1). |
@@ -108,7 +108,7 @@ threads. Some quick actions might not be available to all subscription tiers.
| `/reopen` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Reopen. |
| `/severity <severity>` | **{check-circle}** Yes | **{check-circle}** No | **{check-circle}** No | Set the severity. Issue type must be `Incident`. Options for `<severity>` are `S1` ... `S4`, `critical`, `high`, `medium`, `low`, `unknown`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/334045) in GitLab 14.2. |
| `/shrug <comment>` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Append the comment with `¯\_(ツ)_/¯`. |
-| `/spend <time> [<date>]` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Add or subtract spent time. Optionally, specify the date that time was spent on. For example, `/spend 1mo 2w 3d 4h 5m 2018-08-26` or `/spend -1h 30m`. Learn more about [time tracking](time_tracking.md). |
+| `/spend <time> [<date>]` or `/spend_time <time> [<date>]` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Add or subtract spent time. Optionally, specify the date that time was spent on. For example, `/spend 1mo 2w 3d 4h 5m 2018-08-26` or `/spend -1h 30m`. Learn more about [time tracking](time_tracking.md). Alias `/spend_time` [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16501) in GitLab 15.6. |
| `/submit_review` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Submit a pending review ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/8041) in GitLab 12.7). |
| `/subscribe` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Subscribe to notifications. |
| `/tableflip <comment>` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Append the comment with `(╯°□°)╯︵ â”»â”â”»`. |
@@ -145,6 +145,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/project/releases/index.md b/doc/user/project/releases/index.md
index fd01dd451c2..75a25678125 100644
--- a/doc/user/project/releases/index.md
+++ b/doc/user/project/releases/index.md
@@ -462,6 +462,20 @@ In the API:
This includes associated Git-tag-names, release description, author information of the releases.
However, other repository-related information, such as [source code](release_fields.md#source-code), [release evidence](#release-evidence) are redacted.
+### Publish releases without giving access to source code
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216485) in GitLab 15.6.
+
+Releases can be made accessible to non-project members while keeping repository-related information such as
+[source code](release_fields.md#source-code) and [release evidence](#release-evidence) private. This is useful for
+projects that use releases as a way to give access to new versions of software but do not want the source code to
+be public.
+
+To make releases available publicly, set the following [project settings](../settings/index.md#project-feature-settings):
+
+- Repository is enabled and set to **Only Project Members**
+- Releases is enabled and set to **Everyone With Access**
+
### Create, update, and delete a release and its assets
- Users with at least the Developer role
diff --git a/doc/user/project/releases/release_fields.md b/doc/user/project/releases/release_fields.md
index 5ae1c69847d..c06e746268f 100644
--- a/doc/user/project/releases/release_fields.md
+++ b/doc/user/project/releases/release_fields.md
@@ -93,7 +93,7 @@ By default, GitLab fetches the release using `released_at` time. The use of the
The assets associated with a release are accessible through a permanent URL.
GitLab always redirects this URL to the actual asset
location, so even if the assets move to a different location, you can continue
-to use the same URL. This is defined during [link creation](../../../api/releases/links.md#create-a-link) or [updating](../../../api/releases/links.md#update-a-link) using the `filepath` API attribute.
+to use the same URL. This is defined during [link creation](../../../api/releases/links.md#create-a-release-link) or [updating](../../../api/releases/links.md#update-a-release-link) using the `filepath` API attribute.
The format of the URL is:
@@ -133,7 +133,7 @@ The format of the URL is:
https://host/namespace/project/-/releases/permalink/latest/downloads/:filepath
```
-If you have an asset with [`filepath`](../../../api/releases/links.md#create-a-link) for the `v11.9.0-rc2` latest release in the `gitlab-org`
+If you have an asset with [`filepath`](../../../api/releases/links.md#create-a-release-link) for the `v11.9.0-rc2` latest release in the `gitlab-org`
namespace and `gitlab-runner` project on `gitlab.com`, for example:
```json
diff --git a/doc/user/project/remote_development/index.md b/doc/user/project/remote_development/index.md
index 879978f550a..62220dd2fde 100644
--- a/doc/user/project/remote_development/index.md
+++ b/doc/user/project/remote_development/index.md
@@ -6,6 +6,14 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Remote Development **(FREE)**
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95169) in GitLab 15.6 [with a flag](../../../administration/feature_flags.md) named `vscode_web_ide`. 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 `vscode_web_ide`. On GitLab.com, this feature is available. The feature is not ready for production use.
+
+WARNING:
+This feature is in [Alpha](../../../policy/alpha-beta-support.md#alpha-features) and subject to change without notice.
+
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.
@@ -43,7 +51,7 @@ To point a domain to your remote machine, create an `A` record from `example.rem
#### Install Certbot
-[Certbot](https://certbot.eff.org/) is a free and open-source software tool that automatically uses Let's Encrypt certificates on manually administrated websites to enable HTTPS.
+[Certbot](https://certbot.eff.org/) is a free and open-source software tool that automatically uses Let's Encrypt certificates on manually administered websites to enable HTTPS.
To install Certbot, run the following command:
@@ -89,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 \
+ registry.gitlab.com/gitlab-com/create-stage/editor-poc/remote-development/gitlab-rd-web-ide-docker:0.1-alpha \
--log-level warn --domain "${DOMAIN}" --ignore-version-mismatch
```
diff --git a/doc/user/project/repository/branches/index.md b/doc/user/project/repository/branches/index.md
index 9755b5cb944..6cc7394e7b3 100644
--- a/doc/user/project/repository/branches/index.md
+++ b/doc/user/project/repository/branches/index.md
@@ -124,6 +124,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/project/repository/gpg_signed_commits/index.md b/doc/user/project/repository/gpg_signed_commits/index.md
index 910b09449d8..a1f57f51f26 100644
--- a/doc/user/project/repository/gpg_signed_commits/index.md
+++ b/doc/user/project/repository/gpg_signed_commits/index.md
@@ -253,3 +253,19 @@ If you must unverify both future and past commits,
- [OpenPGP Best Practices](https://riseup.net/en/security/message-security/openpgp/best-practices)
- [Creating a new GPG key with subkeys](https://www.void.gr/kargig/blog/2013/12/02/creating-a-new-gpg-key-with-subkeys/) (advanced)
- [Review existing GPG keys in your instance](../../../admin_area/credentials_inventory.md#review-existing-gpg-keys)
+
+## Troubleshooting
+
+### Fix verification problems with signed commits
+
+Commits can be signed with [X.509 certificates](../x509_signed_commits/index.md)
+or a GPG key. The verification process for both methods can fail for multiple reasons:
+
+| Value | Description | Possible Fixes |
+|-----------------------------|-------------|----------------|
+| `UNVERIFIED` | The commit signature is not valid. | Sign the commit with a valid signature. |
+| `SAME_USER_DIFFERENT_EMAIL` | The GPG key used to sign the commit does not contain the committer email, but does contain a different valid email for the committer. | Amend the commit to use an email address that matches the GPG key, or update the GPG key [to include the email address](https://security.stackexchange.com/a/261468). |
+| `OTHER_USER` | The signature and GPG key are valid, but the key belongs to a different user than the committer. | Amend the commit to use the correct email address, or amend the commit to use a GPG key associated with your user. |
+| `UNVERIFIED_KEY` | The key associated with the GPG signature has no verified email address associated with the committer. | Add and verify the email to your GitLab profile, [update the GPG key to include the email address](https://security.stackexchange.com/a/261468), or amend the commit to use a different committer email address. |
+| `UNKNOWN_KEY` | The GPG key associated with the GPG signature for this commit is unknown to GitLab. | [Add the GPG key](#add-a-gpg-key-to-your-account) to your GitLab profile. |
+| `MULTIPLE_SIGNATURES` | Multiple GPG or X.509 signatures have been found for the commit. | Amend the commit to use only one GPG or X.509 signature. |
diff --git a/doc/user/project/repository/index.md b/doc/user/project/repository/index.md
index bcdb626d0f2..83389c15eba 100644
--- a/doc/user/project/repository/index.md
+++ b/doc/user/project/repository/index.md
@@ -153,7 +153,7 @@ contents of the file's [markup language](https://en.wikipedia.org/wiki/Lightweig
| [reStructuredText](https://docutils.sourceforge.io/rst.html) | `rst` |
| [AsciiDoc](../../asciidoc.md) | `adoc`, `ad`, `asciidoc` |
| [Textile](https://textile-lang.com/) | `textile` |
-| [Rdoc](http://rdoc.sourceforge.net/doc/index.html) | `rdoc` |
+| [Rdoc](https://rdoc.sourceforge.net/doc/index.html) | `rdoc` |
| [Org mode](https://orgmode.org/) | `org` |
| [creole](http://www.wikicreole.org/) | `creole` |
| [MediaWiki](https://www.mediawiki.org/wiki/MediaWiki) | `wiki`, `mediawiki` |
diff --git a/doc/user/project/repository/jupyter_notebooks/index.md b/doc/user/project/repository/jupyter_notebooks/index.md
index 4f6cff576ea..28f0ffb6fbd 100644
--- a/doc/user/project/repository/jupyter_notebooks/index.md
+++ b/doc/user/project/repository/jupyter_notebooks/index.md
@@ -28,24 +28,20 @@ GitLab.
> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/6589) in GitLab 14.5 as an [Alpha](../../../../policy/alpha-beta-support.md#alpha-features) release [with a flag](../../../../administration/feature_flags.md) named `jupyter_clean_diffs`. Enabled by default.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75500) in GitLab 14.9. Feature flag `jupyter_clean_diffs` removed.
> - [Reintroduced toggle](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85079) in GitLab 15.0 [with a flag](../../../../administration/feature_flags.md) named `ipynb_semantic_diff`. Enabled by default.
-
-FLAG:
-On self-managed GitLab, by default semantic diffs are available. To hide the feature, ask an administrator to [disable the feature flag](../../../../administration/feature_flags.md) named `ipynb_semantic_diff`.
-On GitLab.com, this feature is available.
+> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95373) in GitLab 15.6. Feature flag `ipynb_semantic_diff` removed.
When commits include changes to Jupyter Notebook files, GitLab:
- Transforms the machine-readable `.ipynb` file into a human-readable Markdown file.
- Displays a cleaner version of the diff that includes syntax highlighting.
- Enables switching between raw and rendered diffs on the Commit and Compare pages. (Not available on merge request pages.)
+- Renders images on the diffs.
Code suggestions are not available on diffs and merge requests for `.ipynb` files.
-![Jupyter Notebook Clean Diff](img/jupyter_notebook_diff_v14_5.png)
+Cleaner notebook diffs are not generated when the notebook is too large.
-This feature is an [Alpha](../../../../policy/alpha-beta-support.md#alpha-features) release,
-and might lead to performance degradation. On self-managed GitLab, if unexpected issues
-arise, disable the feature.
+![Jupyter Notebook Clean Diff](img/jupyter_notebook_diff_v14_5.png)
## Jupyter Git integration
diff --git a/doc/user/project/repository/mirror/index.md b/doc/user/project/repository/mirror/index.md
index fa6d8d82559..2b578977bd2 100644
--- a/doc/user/project/repository/mirror/index.md
+++ b/doc/user/project/repository/mirror/index.md
@@ -325,6 +325,9 @@ Use case: If you have multiple users using their own GitHub credentials to set u
repository mirroring, mirroring breaks when people leave the company. Use this
script to migrate disparate mirroring users and tokens into a single service account:
+WARNING:
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
+
```ruby
svc_user = User.find_by(username: 'ourServiceUser')
token = 'githubAccessToken'
diff --git a/doc/user/project/repository/push_rules.md b/doc/user/project/repository/push_rules.md
index 917fca03967..7ae085812ae 100644
--- a/doc/user/project/repository/push_rules.md
+++ b/doc/user/project/repository/push_rules.md
@@ -267,7 +267,7 @@ to use them as normal characters in a match condition.
## Related topics
-- [Server hooks](../../../administration/server_hooks.md), to create complex custom push rules
+- [Git server hooks](../../../administration/server_hooks.md) (previously called server hooks), to create complex custom push rules
- [Signing commits with GPG](gpg_signed_commits/index.md)
- [Protected branches](../protected_branches.md)
@@ -304,7 +304,7 @@ For example, to enable **Check whether the commit author is a GitLab user** and
and create a filter for allowing commits from a specific email domain only through rails console:
WARNING:
-Any command that changes data directly could be damaging if not run correctly, or under the right conditions. We highly recommend running them in a test environment with a backup of the instance ready to be restored, just in case.
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
``` ruby
Project.find_each do |p|
diff --git a/doc/user/project/repository/reducing_the_repo_size_using_git.md b/doc/user/project/repository/reducing_the_repo_size_using_git.md
index c85dd4555ca..9c977e4da40 100644
--- a/doc/user/project/repository/reducing_the_repo_size_using_git.md
+++ b/doc/user/project/repository/reducing_the_repo_size_using_git.md
@@ -72,6 +72,12 @@ To purge files from a GitLab repository:
cd project.git
```
+1. Because cloning from a bundle file sets the `origin` remote to the local bundle file, change it to the URL of your repository:
+
+ ```shell
+ git remote set-url origin https://gitlab.example.com/<namespace>/<project_name>.git
+ ```
+
1. Using either `git filter-repo` or `git-sizer`, analyze your repository
and review the results to determine which items you want to purge:
@@ -84,38 +90,39 @@ To purge files from a GitLab repository:
git-sizer
```
-1. Proceed to purging any files from the history of your repository. Because we are
- trying to remove internal refs, we rely on the `commit-map` produced by each run to tell us
- which internal refs to remove.
-
- NOTE:
- `git filter-repo` creates a new `commit-map` file every run, and overwrites the `commit-map` from
- the previous run. You need this file from **every** run. Do the next step every time you run
- `git filter-repo`.
+1. Purge the history of your repository using relevant `git filter-repo` options.
+ Two common options are:
- To purge specific files, the `--path` and `--invert-paths` options can be combined:
+ - `--path` and `--invert-paths` to purge specific files:
- ```shell
- git filter-repo --path path/to/file.ext --invert-paths
- ```
+ ```shell
+ git filter-repo --path path/to/file.ext --invert-paths
+ ```
- To generally purge all files larger than 10M, the `--strip-blobs-bigger-than` option can be used:
+ - `--strip-blobs-bigger-than` to purge all files larger than for example 10M:
- ```shell
- git filter-repo --strip-blobs-bigger-than 10M
- ```
+ ```shell
+ git filter-repo --strip-blobs-bigger-than 10M
+ ```
See the
[`git filter-repo` documentation](https://htmlpreview.github.io/?https://github.com/newren/git-filter-repo/blob/docs/html/git-filter-repo.html#EXAMPLES)
for more examples and the complete documentation.
-1. Because cloning from a bundle file sets the `origin` remote to the local bundle file, delete this `origin` remote, and set it to the URL to your repository:
+1. Because you are trying to remove internal refs,
+ you'll later rely on `commit-map` files produced by each run
+ to tell you which internal refs to remove.
+ Every `git filter-repo` run creates a new `commit-map`,
+ and overwrites the `commit-map` from the previous run.
+ You can use the following command to back up each `commit-map` file:
```shell
- git remote remove origin
- git remote add origin https://gitlab.example.com/<namespace>/<project_name>.git
+ cp .git/filter-repo/commit-map ./_filter_repo_commit_map_$(date +%s)
```
+ Repeat this step and all following steps (including the [repository cleanup](#repository-cleanup) step)
+ every time you run any `git filter-repo` command.
+
1. Force push your changes to overwrite all branches on GitLab:
```shell
diff --git a/doc/user/project/repository/web_editor.md b/doc/user/project/repository/web_editor.md
index e1f05cd5501..773662edb17 100644
--- a/doc/user/project/repository/web_editor.md
+++ b/doc/user/project/repository/web_editor.md
@@ -10,13 +10,13 @@ Sometimes it's easier to make quick changes directly from the GitLab interface
than to clone the project and use the Git command-line tool. In this feature
highlight, we look at how you can create a new file, directory, branch, or
tag from the file browser. All of these actions are available from a single
-dropdown menu.
+dropdown list.
## Create a file
From a project's files page, select the '+' button to the right of the branch selector.
-Choose **New file** from the dropdown.
-![New file dropdown menu](img/web_editor_new_file_dropdown_v14_1.png)
+Choose **New file** from the dropdown list.
+![New file dropdown list](img/web_editor_new_file_dropdown_v14_1.png)
Enter a filename in the **Filename** box. Then, add file content in the editor
area. Add a descriptive commit message and choose a branch. The branch field
@@ -55,6 +55,18 @@ NOTE:
The **Set up CI/CD** button does not appear on an empty repository. For the button
to display, add a file to your repository.
+## Preview Markdown
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/378966) in GitLab 15.6.
+
+To preview Markdown content in the Web Editor, select the **Preview** tab.
+In this tab, you can see a live Markdown preview that updates as you type alongside your content.
+
+To close the preview panel, do one of the following:
+
+- Select the **Write** tab.
+- From the context menu, select **Hide Live Preview**.
+
## Highlight lines
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56159) in GitLab 13.10 for GitLab SaaS instances.
@@ -85,7 +97,7 @@ this case, you need to upload a file.
From a project's files page, select the '+' button to the right of the branch
selector. Choose **Upload file** from the dropdown:
-![Upload file dropdown menu](img/web_editor_upload_file_dropdown_v14_1.png)
+![Upload file dropdown list](img/web_editor_upload_file_dropdown_v14_1.png)
After the upload dialog pops up, there are two ways to upload your file. Either
drag and drop a file on the popup or use the **click to upload** link. After you
@@ -104,7 +116,7 @@ directory.
From a project's files page, select the plus button (`+`) to the right of the branch selector.
Choose **New directory** from the dropdown.
-![New directory dropdown](img/web_editor_new_directory_dropdown_v14_1.png)
+![New directory dropdown list](img/web_editor_new_directory_dropdown_v14_1.png)
In the new directory dialog, enter a directory name, a commit message, and choose
the target branch. Select **Create directory** to finish.
@@ -138,6 +150,7 @@ The **Create merge request** button doesn't display if:
- A branch with the same name already exists.
- A merge request already exists for this branch.
- Your project has an active fork relationship.
+- Your project is private and the issue is confidential.
To make this button appear, one possible workaround is to
[remove your project's fork relationship](../settings/index.md#remove-a-fork-relationship).
@@ -177,9 +190,9 @@ merge request is merged.
If you want to make changes to several files before creating a new merge
request, you can create a new branch upfront.
-1. From a project's files page, choose **New branch** from the dropdown.
+1. From a project's files page, choose **New branch** from the dropdown list.
- ![New branch dropdown](img/web_editor_new_branch_dropdown_v14_1.png)
+ ![New branch dropdown list](img/web_editor_new_branch_dropdown_v14_1.png)
1. Enter a new **Branch name**.
1. Optional. Change the **Create from** field to choose which branch, tag, or
@@ -202,9 +215,9 @@ Tags help you mark major milestones such as production releases and
release candidates. You can create a tag from a branch or a commit
SHA:
-1. From a project's files page, choose **New tag** from the dropdown.
+1. From a project's files page, choose **New tag** from the dropdown list.
- ![New tag dropdown](img/web_editor_new_tag_dropdown.png)
+ ![New tag dropdown list](img/web_editor_new_tag_dropdown.png)
1. Give the tag a name such as `v1.0.0`.
1. Choose the branch or SHA from which you want to create this new tag.
@@ -238,6 +251,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/project/repository/x509_signed_commits/index.md b/doc/user/project/repository/x509_signed_commits/index.md
index 4a17b2ab84c..e16f5e4defe 100644
--- a/doc/user/project/repository/x509_signed_commits/index.md
+++ b/doc/user/project/repository/x509_signed_commits/index.md
@@ -163,6 +163,11 @@ can start signing your tags:
## Troubleshooting
+For committers without administrator access, review the list of
+[verification problems with signed commits](../gpg_signed_commits/index.md#fix-verification-problems-with-signed-commits)
+for possible fixes. The other troubleshooting suggestions on this page require
+administrator access.
+
### Re-verify commits
GitLab stores the status of any checked commits in the database. You can use a
diff --git a/doc/user/project/requirements/index.md b/doc/user/project/requirements/index.md
index 3b1af1f688c..922accf9d28 100644
--- a/doc/user/project/requirements/index.md
+++ b/doc/user/project/requirements/index.md
@@ -5,7 +5,7 @@ group: Certify
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
-# Requirements Management **(ULTIMATE)**
+# Requirements management **(ULTIMATE)**
NOTE:
In 14.4, Requirements was moved under **Issues**.
@@ -120,8 +120,8 @@ You can search for a requirement from the requirements list page based on the fo
To search for a requirement:
1. In a project, go to **Issues > Requirements > List**.
-1. Select the **Search or filter results** field. A dropdown menu appears.
-1. Select the requirement author or status from the dropdown or enter plain text to search by requirement title.
+1. Select the **Search or filter results** field. A dropdown list appears.
+1. Select the requirement author or status from the dropdown list or enter plain text to search by requirement title.
1. Press <kbd>Enter</kbd> on your keyboard to filter the list.
You can also sort the requirements list by:
diff --git a/doc/user/project/settings/import_export.md b/doc/user/project/settings/import_export.md
index a47873f5179..3c12bb9b80f 100644
--- a/doc/user/project/settings/import_export.md
+++ b/doc/user/project/settings/import_export.md
@@ -254,168 +254,3 @@ and the exports between them are compatible.
- [Project import/export administration Rake tasks](../../../administration/raketasks/project_import_export.md)
- [Group import/export](../../group/settings/import_export.md)
- [Group import/export API](../../../api/group_import_export.md)
-
-## Troubleshooting
-
-### Project fails to import due to mismatch
-
-If the [shared runners enablement](../../../ci/runners/runners_scope.md#enable-shared-runners-for-a-project)
-does not match between the exported project, and the project import, the project fails to import.
-Review [issue 276930](https://gitlab.com/gitlab-org/gitlab/-/issues/276930), and either:
-
-- Ensure shared runners are enabled in both the source and destination projects.
-- Disable shared runners on the parent group when you import the project.
-
-### Import workarounds for large repositories
-
-[Maximum import size limitations](#import-a-project-and-its-data)
-can prevent an import from being successful. If changing the import limits is not possible, you can
-try one of the workarounds listed here.
-
-#### Workaround option 1
-
-The following local workflow can be used to temporarily
-reduce the repository size for another import attempt:
-
-1. Create a temporary working directory from the export:
-
- ```shell
- EXPORT=<filename-without-extension>
-
- 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
-
- 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"/ .
- ```
-
-1. Import this new, smaller file into GitLab.
-1. In a full clone of the original repository,
- use `git remote set-url origin <new-url> && git push --force --all`
- to complete the import.
-1. Update the imported repository's
- [branch protection rules](../protected_branches.md) and
- its [default branch](../repository/branches/default.md), and
- delete the temporary, `smaller-tmp-main` branch, and
- the local, temporary data.
-
-#### Workaround option 2
-
-NOTE:
-This workaround does not account for LFS objects.
-
-Rather than attempting to push all changes at once, this workaround:
-
-- Separates the project import from the Git Repository import
-- Incrementally pushes the repository to GitLab
-
-1. Make a local clone of the repository to migrate. In a later step, you push this clone outside of
- the project export.
-1. Download the export and remove the `project.bundle` (which contains the Git repository):
-
- ```shell
- tar -czvf new_export.tar.gz --exclude='project.bundle' @old_export.tar.gz
- ```
-
-1. Import the export without a Git repository. It asks you to confirm to import without a
- repository.
-1. Save this bash script as a file and run it after adding the appropriate origin.
-
- ```shell
- #!/bin/sh
-
- # ASSUMPTIONS:
- # - The GitLab location is "origin"
- # - The default branch is "main"
- # - This will attempt to push in chunks of 500MB (dividing the total size by 500MB).
- # Decrease this size to push in smaller chunks if you still receive timeouts.
-
- git gc
- SIZE=$(git count-objects -v 2> /dev/null | grep size-pack | awk '{print $2}')
-
- # Be conservative... and try to push 2GB at a time
- # (given this assumes each commit is the same size - which is wrong)
- BATCHES=$(($SIZE / 500000))
- TOTAL_COMMITS=$(git rev-list --count HEAD)
- if (( BATCHES > TOTAL_COMMITS )); then
- BATCHES=$TOTAL_COMMITS
- fi
-
- INCREMENTS=$(( ($TOTAL_COMMITS / $BATCHES) - 1 ))
-
- for (( BATCH=BATCHES; BATCH>=1; BATCH-- ))
- do
- COMMIT_NUM=$(( $BATCH - $INCREMENTS ))
- COMMIT_SHA=$(git log -n $COMMIT_NUM --format=format:%H | tail -1)
- git push -u origin ${COMMIT_SHA}:refs/heads/main
- done
- git push -u origin main
- git push -u origin --all
- git push -u origin --tags
- ```
-
-### Manually execute export steps
-
-Exports sometimes fail without giving enough information to troubleshoot. In these cases, it can be
-helpful to [open a rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
-and loop through [all the defined exporters](https://gitlab.com/gitlab-org/gitlab/-/blob/b67a5b5a12498d57cd877023b7385f7251e57de8/app/services/projects/import_export/export_service.rb#L65).
-Execute each line individually, rather than pasting the entire block at once, so you can see any
-errors each command returns.
-
-```shell
-# User needs to have permission to export
-u = User.find_by_username('someuser')
-p = Project.find_by_full_path('some/project')
-e = Projects::ImportExport::ExportService.new(p,u)
-
-e.send(:version_saver).send(:save)
-e.send(:repo_saver).send(:save)
-## continue using `e.send(:exporter_name).send(:save)` going through the list of exporters
-
-# The following line should show you the export_path similar to /var/opt/gitlab/gitlab-rails/shared/tmp/gitlab_exports/@hashed/49/94/4994....
-s = Gitlab::ImportExport::Saver.new(exportable: p, shared:p.import_export_shared)
-
-# To try and upload use:
-s.send(:compress_and_save)
-s.send(:save_upload)
-```
-
-### Import using the REST API fails when using a group access token
-
-[Group access tokens](../../group/settings/group_access_tokens.md)
-don't work for project or group import operations. When a group access token initiates an import,
-the import fails with this message:
-
-```plaintext
-Error adding importer user to Project members.
-Validation failed: User project bots cannot be added to other groups / projects
-```
-
-To use [Import REST API](../../../api/project_import_export.md),
-pass regular user account credentials such as [personal access tokens](../../profile/personal_access_tokens.md).
diff --git a/doc/user/project/settings/import_export_troubleshooting.md b/doc/user/project/settings/import_export_troubleshooting.md
new file mode 100644
index 00000000000..81ceba7139b
--- /dev/null
+++ b/doc/user/project/settings/import_export_troubleshooting.md
@@ -0,0 +1,280 @@
+---
+stage: Manage
+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"
+---
+
+# Troubleshooting file export project migrations
+
+If you have problems with [migrating projects using file exports](import_export.md), see the possible solutions below.
+
+## Troubleshooting commands
+
+Finds information about the status of the import and further logs using the JID:
+
+```ruby
+# Rails console
+Project.find_by_full_path('group/project').import_state.slice(:jid, :status, :last_error)
+> {"jid"=>"414dec93f941a593ea1a6894", "status"=>"finished", "last_error"=>nil}
+```
+
+```shell
+# Logs
+grep JID /var/log/gitlab/sidekiq/current
+grep "Import/Export error" /var/log/gitlab/sidekiq/current
+grep "Import/Export backtrace" /var/log/gitlab/sidekiq/current
+tail /var/log/gitlab/gitlab-rails/importer.log
+```
+
+## Project fails to import due to mismatch
+
+If the [shared runners enablement](../../../ci/runners/runners_scope.md#enable-shared-runners-for-a-project)
+does not match between the exported project, and the project import, the project fails to import.
+Review [issue 276930](https://gitlab.com/gitlab-org/gitlab/-/issues/276930), and either:
+
+- Ensure shared runners are enabled in both the source and destination projects.
+- Disable shared runners on the parent group when you import the project.
+
+## Import workarounds for large repositories
+
+[Maximum import size limitations](import_export.md#import-a-project-and-its-data)
+can prevent an import from being successful. If changing the import limits is not possible, you can
+try one of the workarounds listed here.
+
+### Workaround option 1
+
+The following local workflow can be used to temporarily
+reduce the repository size for another import attempt:
+
+1. Create a temporary working directory from the export:
+
+ ```shell
+ EXPORT=<filename-without-extension>
+
+ 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
+
+ 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"/ .
+ ```
+
+1. Import this new, smaller file into GitLab.
+1. In a full clone of the original repository,
+ use `git remote set-url origin <new-url> && git push --force --all`
+ to complete the import.
+1. Update the imported repository's
+ [branch protection rules](../protected_branches.md) and
+ its [default branch](../repository/branches/default.md), and
+ delete the temporary, `smaller-tmp-main` branch, and
+ the local, temporary data.
+
+### Workaround option 2
+
+NOTE:
+This workaround does not account for LFS objects.
+
+Rather than attempting to push all changes at once, this workaround:
+
+- Separates the project import from the Git Repository import
+- Incrementally pushes the repository to GitLab
+
+1. Make a local clone of the repository to migrate. In a later step, you push this clone outside of
+ the project export.
+1. Download the export and remove the `project.bundle` (which contains the Git repository):
+
+ ```shell
+ tar -czvf new_export.tar.gz --exclude='project.bundle' @old_export.tar.gz
+ ```
+
+1. Import the export without a Git repository. It asks you to confirm to import without a
+ repository.
+1. Save this bash script as a file and run it after adding the appropriate origin.
+
+ ```shell
+ #!/bin/sh
+
+ # ASSUMPTIONS:
+ # - The GitLab location is "origin"
+ # - The default branch is "main"
+ # - This will attempt to push in chunks of 500MB (dividing the total size by 500MB).
+ # Decrease this size to push in smaller chunks if you still receive timeouts.
+
+ git gc
+ SIZE=$(git count-objects -v 2> /dev/null | grep size-pack | awk '{print $2}')
+
+ # Be conservative... and try to push 2GB at a time
+ # (given this assumes each commit is the same size - which is wrong)
+ BATCHES=$(($SIZE / 500000))
+ TOTAL_COMMITS=$(git rev-list --count HEAD)
+ if (( BATCHES > TOTAL_COMMITS )); then
+ BATCHES=$TOTAL_COMMITS
+ fi
+
+ INCREMENTS=$(( ($TOTAL_COMMITS / $BATCHES) - 1 ))
+
+ for (( BATCH=BATCHES; BATCH>=1; BATCH-- ))
+ do
+ COMMIT_NUM=$(( $BATCH - $INCREMENTS ))
+ COMMIT_SHA=$(git log -n $COMMIT_NUM --format=format:%H | tail -1)
+ git push -u origin ${COMMIT_SHA}:refs/heads/main
+ done
+ git push -u origin main
+ git push -u origin --all
+ git push -u origin --tags
+ ```
+
+## Manually execute export steps
+
+You usually export a project through [the web interface](import_export.md#export-a-project-and-its-data) or through [the API](../../../api/project_import_export.md). Exporting using these
+methods can sometimes fail without giving enough information to troubleshoot. In these cases,
+[open a rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
+Execute each line individually, rather than pasting the entire block at once, so you can see any
+errors each command returns.
+
+```shell
+# User needs to have permission to export
+u = User.find_by_username('someuser')
+p = Project.find_by_full_path('some/project')
+e = Projects::ImportExport::ExportService.new(p,u)
+
+e.send(:version_saver).send(:save)
+e.send(:repo_saver).send(:save)
+## continue using `e.send(:exporter_name).send(:save)` going through the list of exporters
+
+# The following line should show you the export_path similar to /var/opt/gitlab/gitlab-rails/shared/tmp/gitlab_exports/@hashed/49/94/4994....
+s = Gitlab::ImportExport::Saver.new(exportable: p, shared:p.import_export_shared)
+
+# To try and upload use:
+s.send(:compress_and_save)
+s.send(:save_upload)
+```
+
+After the project is successfully uploaded, the exported project is located in a `.tar.gz` file in `/var/opt/gitlab/gitlab-rails/uploads/-/system/import_export_upload/export_file/`.
+
+## Import using the REST API fails when using a group access token
+
+[Group access tokens](../../group/settings/group_access_tokens.md)
+don't work for project or group import operations. When a group access token initiates an import,
+the import fails with this message:
+
+```plaintext
+Error adding importer user to Project members.
+Validation failed: User project bots cannot be added to other groups / projects
+```
+
+To use [Import REST API](../../../api/project_import_export.md),
+pass regular user account credentials such as [personal access tokens](../../profile/personal_access_tokens.md).
+
+## Troubleshooting performance issues
+
+Read through the current performance problems using the Import/Export below.
+
+### OOM errors
+
+Out of memory (OOM) errors are normally caused by the [Sidekiq Memory Killer](../../../administration/sidekiq/sidekiq_memory_killer.md):
+
+```shell
+SIDEKIQ_MEMORY_KILLER_MAX_RSS = 2000000
+SIDEKIQ_MEMORY_KILLER_HARD_LIMIT_RSS = 3000000
+SIDEKIQ_MEMORY_KILLER_GRACE_TIME = 900
+```
+
+An import status `started`, and the following Sidekiq logs signal a memory issue:
+
+```shell
+WARN: Work still in progress <struct with JID>
+```
+
+### Timeouts
+
+Timeout errors occur due to the `Gitlab::Import::StuckProjectImportJobsWorker` marking the process as failed:
+
+```ruby
+module Gitlab
+ module Import
+ class StuckProjectImportJobsWorker
+ include Gitlab::Import::StuckImportJob
+ # ...
+ end
+ end
+end
+
+module Gitlab
+ module Import
+ module StuckImportJob
+ # ...
+ IMPORT_JOBS_EXPIRATION = 15.hours.to_i
+ # ...
+ def perform
+ stuck_imports_without_jid_count = mark_imports_without_jid_as_failed!
+ stuck_imports_with_jid_count = mark_imports_with_jid_as_failed!
+
+ track_metrics(stuck_imports_with_jid_count, stuck_imports_without_jid_count)
+ end
+ # ...
+ end
+ end
+end
+```
+
+```shell
+Marked stuck import jobs as failed. JIDs: xyz
+```
+
+```plaintext
+ +-----------+ +-----------------------------------+
+ |Export Job |--->| Calls ActiveRecord `as_json` and |
+ +-----------+ | `to_json` on all project models |
+ +-----------------------------------+
+
+ +-----------+ +-----------------------------------+
+ |Import Job |--->| Loads all JSON in memory, then |
+ +-----------+ | inserts into the DB in batches |
+ +-----------------------------------+
+```
+
+### Problems and solutions
+
+| 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 |
+| | [Netflix Fast JSON API](https://github.com/Netflix/fast_jsonapi) may help |
+| | Batch reading/writing to disk and any SQL
+
+### Temporary solutions
+
+While the performance problems are not tackled, there is a process to workaround
+importing big projects, using a foreground import:
+
+[Foreground import](https://gitlab.com/gitlab-com/gl-infra/reliability/-/issues/5384) of big projects for customers.
+(Using the import template in the [infrastructure tracker](https://gitlab.com/gitlab-com/gl-infra/reliability/-/issues))
diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md
index 4407986f354..a872a339433 100644
--- a/doc/user/project/settings/index.md
+++ b/doc/user/project/settings/index.md
@@ -45,7 +45,7 @@ If you're an instance administrator, you can administer all project topics from
## Add a compliance framework to a project **(PREMIUM)**
-[Compliance frameworks](../../group/manage.md#compliance-frameworks) can be assigned to projects within group that has a
+[Compliance frameworks](../../group/compliance_frameworks.md) can be assigned to projects within group that has a
compliance framework using either:
- The GitLab UI:
@@ -91,9 +91,12 @@ Use the toggles to enable or disable features in the project.
| **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). |
-| **Operations** | ✓ | Control access to Operations-related features, including [Operations Dashboard](../../../operations/index.md), [Environments and Deployments](../../../ci/environments/index.md), [Feature Flags](../../../operations/feature_flags.md). |
| **Metrics Dashboard** | ✓ | Control access to [metrics dashboard](../integrations/prometheus.md). |
| **Releases** | ✓ | Control access to [Releases](../releases/index.md). |
+| **Environments** | ✓ | Control access to [Environments and Deployments](../../../ci/environments/index.md). |
+| **Feature flags** | ✓ | Control access to [Feature Flags](../../../operations/feature_flags.md). |
+| **Monitor** | ✓ | Control access to [Monitor](../../../operations/index.md) features. |
+| **Infrastructure** | ✓ | Control access to [Infrastructure](../../infrastructure/index.md) features. |
When you disable a feature, the following additional features are also disabled:
@@ -277,7 +280,7 @@ To delete a project:
1. In the "Delete project" section, select **Delete project**.
1. Confirm the action when asked to.
-This action deletes a project including all associated resources (issues, merge requests, and so on).
+This action deletes a project including all associated resources (such as issues and merge requests).
WARNING:
The default deletion behavior for projects was changed to [delayed project deletion](https://gitlab.com/gitlab-org/gitlab/-/issues/32935)
diff --git a/doc/user/project/web_ide/index.md b/doc/user/project/web_ide/index.md
index a0eac9376f2..0200e9c4e7d 100644
--- a/doc/user/project/web_ide/index.md
+++ b/doc/user/project/web_ide/index.md
@@ -202,12 +202,12 @@ left.
## Switching merge requests
To switch between your authored and assigned merge requests, select the
-dropdown in the top of the sidebar to open a list of merge requests. You must commit or discard all your changes before switching to a different merge
+dropdown list in the top of the sidebar to open a list of merge requests. You must commit or discard all your changes before switching to a different merge
request.
## Switching branches
-To switch between branches of the current project repository, select the dropdown
+To switch between branches of the current project repository, select the dropdown list
in the top of the sidebar to open a list of branches.
You must commit or discard all your changes before switching to a
different branch.
@@ -459,3 +459,12 @@ The Web IDE has a few limitations:
- If the terminal displays **Connection Failure**, then the terminal could not
connect to the runner. Try to stop and restart the terminal. If the
problem persists, double check your runner configuration.
+
+## VSCode Reimplementation
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95169) in GitLab 15.4 [with a flag](../../../administration/feature_flags.md) named `vscode_web_ide`. Disabled by default.
+
+As announced in [this blog post](https://about.gitlab.com/blog/2022/05/23/the-future-of-the-gitlab-web-ide/),
+the current implementation of the Web IDE will be replaced with a [VSCode inspired implementation](https://gitlab.com/groups/gitlab-org/-/epics/7683).
+
+This effort is currently under development. Follow [this epic](https://gitlab.com/groups/gitlab-org/-/epics/7683) for updates and more information.
diff --git a/doc/user/project/working_with_projects.md b/doc/user/project/working_with_projects.md
index 705e49df039..067a0303277 100644
--- a/doc/user/project/working_with_projects.md
+++ b/doc/user/project/working_with_projects.md
@@ -516,7 +516,7 @@ If a project or repository has been updated but the state is not reflected in th
You can do so through [a Rails console session](../../administration/operations/rails_console.md#starting-a-rails-console-session) and one of the following:
WARNING:
-Any command that changes data directly could be damaging if not run correctly, or under the right conditions. We highly recommend running them in a test environment with a backup of the instance ready to be restored, just in case.
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
```ruby
## Clear project cache
@@ -545,7 +545,7 @@ end
If a project cannot be deleted, you can attempt to delete it through [Rails console](../../administration/operations/rails_console.md#starting-a-rails-console-session).
WARNING:
-Any command that changes data directly could be damaging if not run correctly, or under the right conditions. We highly recommend running them in a test environment with a backup of the instance ready to be restored, just in case.
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
```ruby
project = Project.find_by_full_path('<project_path>')
@@ -569,7 +569,7 @@ To toggle a specific feature, you can [start a Rails console session](../../admi
and run the following function:
WARNING:
-Any command that changes data directly could be damaging if not run correctly, or under the right conditions. We highly recommend running them in a test environment with a backup of the instance ready to be restored, just in case.
+Commands that change data can cause damage if not run correctly or under the right conditions. Always run commands in a test environment first and have a backup instance ready to restore.
```ruby
projects = Group.find_by_name('_group_name').projects
diff --git a/doc/user/public_access.md b/doc/user/public_access.md
index 703932e50f6..bdc711f2098 100644
--- a/doc/user/public_access.md
+++ b/doc/user/public_access.md
@@ -18,6 +18,11 @@ for your GitLab instance). For example, <https://gitlab.com/public>.
You can control the visibility of individual features with
[project feature settings](permissions.md#project-features).
+The visibility setting of a project must be at least as restrictive
+as the visibility of its parent group.
+For example, a private group can include only private projects,
+while a public group can include private, internal, and public projects.
+
## Public projects and groups
Public projects can be cloned **without any** authentication over HTTPS.
@@ -73,11 +78,12 @@ Prerequisite:
## Change group visibility
-Prerequisite:
+Prerequisites:
- You must have the Owner role for a group.
- Subgroups and projects must already have visibility settings that are at least as
- restrictive as the new setting of the parent group.
+ restrictive as the new setting of the parent group. For example, you cannot set a group
+ to private if a subgroup or project in that group is public.
1. On the top bar, select **Main menu > Groups** and find your project.
1. On the left sidebar, select **Settings > General**.
@@ -101,6 +107,6 @@ important to describe those, too. Think of things that may go wrong and include
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, e.g. `### Getting error message X`.
+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. -->
diff --git a/doc/user/reserved_names.md b/doc/user/reserved_names.md
index f8c735eaea8..1ab22fb846d 100644
--- a/doc/user/reserved_names.md
+++ b/doc/user/reserved_names.md
@@ -26,7 +26,7 @@ under the `TOP_LEVEL_ROUTES`, `PROJECT_WILDCARD_ROUTES` and `GROUP_ROUTES` lists
## Reserved project names
-It is currently not possible to create a project with the following names:
+It is not possible to create a project with the following names:
- `\-`
- `badges`
@@ -52,7 +52,7 @@ It is currently not possible to create a project with the following names:
## Reserved group names
-Currently, the following names are reserved as top level groups:
+The following names are reserved as top level groups:
- `\-`
- `.well-known`
diff --git a/doc/user/search/advanced_search.md b/doc/user/search/advanced_search.md
index 86b59572e77..925fc7e6036 100644
--- a/doc/user/search/advanced_search.md
+++ b/doc/user/search/advanced_search.md
@@ -37,9 +37,39 @@ You can use Advanced Search in:
## Syntax
-See [Advanced Search syntax](global_search/advanced_search_syntax.md) for more information.
+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.
-## Search by ID
+<!-- markdownlint-disable -->
-- To search by issue ID, use the `#` prefix followed by the issue ID (for example, [`#23456`](https://gitlab.com/search?snippets=&scope=issues&repository_ref=&search=%2323456&group_id=9970&project_id=278964)).
-- To search by merge request ID, use the `!` prefix followed by the merge request ID (for example, [`!23456`](https://gitlab.com/search?snippets=&scope=merge_requests&repository_ref=&search=%2123456&group_id=9970&project_id=278964)).
+| Syntax | Description | Example |
+|--------------|---------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `"` | Exact search | [`"gem sidekiq"`](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=%22gem+sidekiq%22) |
+| <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) |
+| `*` | Partial | [`bug error 50*`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=bug+error+50%2A&snippets=) |
+| `\` | Escape | [`\*md`](https://gitlab.com/search?snippets=&scope=blobs&repository_ref=&search=%5C*md&group_id=9970&project_id=278964) |
+| `#` | 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) |
+
+### 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) |
+
+`extension:` and `blob:` return exact matches only.
+
+### Examples
+
+| Query | Description |
+|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------|
+| [`rails -filename:gemfile.lock`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=rails+-filename%3Agemfile.lock&snippets=) | Returns `rails` in all files except the `gemfile.lock` file. |
+| [`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. |
+
+<!-- markdownlint-enable -->
diff --git a/doc/user/search/global_search/advanced_search_syntax.md b/doc/user/search/global_search/advanced_search_syntax.md
index cd4bff0a20e..c34c5c0c8fc 100644
--- a/doc/user/search/global_search/advanced_search_syntax.md
+++ b/doc/user/search/global_search/advanced_search_syntax.md
@@ -1,52 +1,11 @@
---
-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
+redirect_to: '../advanced_search.md'
+remove_date: '2023-02-02'
---
-# Advanced Search syntax **(PREMIUM)**
+This document was moved to [another location](../advanced_search.md).
-With [Advanced Search](../advanced_search.md), you can perform a thorough
-search of your entire GitLab instance.
-
-The Advanced Search syntax supports fuzzy or exact search queries with prefixes,
-boolean operators, and more. Advanced Search uses
-[Elasticsearch's syntax](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-simple-query-string-query.html#simple-query-string-syntax).
-
-WARNING:
-Advanced Search searches default project branches only.
-
-## General search
-
-<!-- markdownlint-disable -->
-
-| Use | Description | Example |
-|-----|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
-| `"` | Exact search | [`"gem sidekiq"`](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=%22gem+sidekiq%22) |
-| <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) |
-| `*` | Partial | [`bug error 50*`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=bug+error+50%2A&snippets=) |
-| `\` | Escape | [`\*md`](https://gitlab.com/search?snippets=&scope=blobs&repository_ref=&search=%5C*md&group_id=9970&project_id=278964) |
-
-## Code search
-
-| Use | 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 the `.` | [`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) |
-
-`extension` and `blob` return exact matches only.
-
-## Examples
-
-| Example | Description |
-|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------|
-| [`rails -filename:gemfile.lock`](https://gitlab.com/search?group_id=9970&project_id=278964&repository_ref=&scope=blobs&search=rails+-filename%3Agemfile.lock&snippets=) | Show _rails_ in all files except the _`gemfile.lock`_ file. |
-| [`RSpec.describe Resolvers -*builder`](https://gitlab.com/search?group_id=9970&project_id=278964&scope=blobs&search=RSpec.describe+Resolvers+-*builder) | Show all _RSpec.describe Resolvers_ that don't 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) | Show _bug_ **or** _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=) | Show _helper_ in all files, except for files with _`.yml`_ **or** _`.js`_ extensions. |
-
-<!-- markdownlint-enable -->
+<!-- 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/shortcuts.md b/doc/user/shortcuts.md
index bf233bef6a2..f9e61ad78ad 100644
--- a/doc/user/shortcuts.md
+++ b/doc/user/shortcuts.md
@@ -272,7 +272,8 @@ These shortcuts are available when editing a file with the
| <kbd>Command</kbd> + <kbd>Shift</kbd> + <kbd>8</kbd> | <kbd>Control</kbd> + <kbd>Shift</kbd> + <kbd>8</kbd> | Unordered list |
| <kbd>Command</kbd> + <kbd>Shift</kbd> + <kbd>9</kbd> | <kbd>Control</kbd> + <kbd>Shift</kbd> + <kbd>9</kbd> | Task list |
| <kbd>Command</kbd> + <kbd>Shift</kbd> + <kbd>b</kbd> | <kbd>Control</kbd> + <kbd>Shift</kbd> + <kbd>b</kbd> | Blockquote |
-| <kbd>Command</kbd> + <kbd>Alt</kbd> + <kbd>c</kbd> | <kbd>Control</kbd> + <kbd>Shift</kbd> + <kbd>c</kbd> | Code block |
+| <kbd>Command</kbd> + <kbd>Alt</kbd> + <kbd>c</kbd> | <kbd>Control</kbd> + <kbd>Alt</kbd> + <kbd>c</kbd> | Code block |
+| <kbd>Command</kbd> + <kbd>Shift</kbd> + <kbd>h</kbd> | <kbd>Control</kbd> + <kbd>Shift</kbd> + <kbd>h</kbd> | Highlight |
| <kbd>Command</kbd> + <kbd>,</kbd> | <kbd>Control</kbd> + <kbd>,</kbd> | Subscript |
| <kbd>Command</kbd> + <kbd>.</kbd> | <kbd>Control</kbd> + <kbd>.</kbd> | Superscript |
| <kbd>Tab</kbd> | <kbd>Tab</kbd> | Indent list |
diff --git a/doc/user/ssh.md b/doc/user/ssh.md
index be76ce487b6..85332446334 100644
--- a/doc/user/ssh.md
+++ b/doc/user/ssh.md
@@ -252,6 +252,29 @@ To generate ED25519_SK or ECDSA_SK SSH keys, you must use OpenSSH 8.2 or later:
A public and private key are generated.
[Add the public SSH key to your GitLab account](#add-an-ssh-key-to-your-gitlab-account).
+## Generate an SSH key pair with a password manager
+
+### Generate an SSH key pair with 1Password
+
+You can use [1Password](https://1password.com/) and the [1Password browser extension](https://support.1password.com/getting-started-browser/) to either:
+
+- Automatically generate a new SSH key.
+- Use an existing SSH in your 1Password vault to authenticate with GitLab.
+
+1. Sign in to GitLab.
+1. On the top bar, in the top right corner, select your avatar.
+1. Select **Preferences**.
+1. On the left sidebar, select **SSH Keys**.
+1. Select **Key**, and you should see the 1Password helper appear.
+1. Select the 1Password icon and unlock 1Password.
+1. You can then select **Create SSH Key** or select an existing SSH key to fill in the public key.
+1. In the **Title** box, type a description, like `Work Laptop` or
+ `Home Workstation`.
+1. Optional. Update **Expiration date** to modify the default expiration date.
+1. Select **Add key**.
+
+To learn more about using 1Password with SSH keys, see [1Password's documentation](https://developer.1password.com/docs/ssh/get-started).
+
## Add an SSH key to your GitLab account
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/271239) in GitLab 15.4, default expiration date suggested in UI.
@@ -499,4 +522,4 @@ You can troubleshoot this by trying the following:
- Verify your IDO/U2F hardware security key supports
the key type provided.
- Verify the version of OpenSSH is 8.2 or greater by
- running `ssh -v`.
+ running `ssh -V`.
diff --git a/doc/user/tasks.md b/doc/user/tasks.md
index 10a86724bf1..5c9290e57cb 100644
--- a/doc/user/tasks.md
+++ b/doc/user/tasks.md
@@ -18,7 +18,7 @@ For the latest updates, check the [Tasks Roadmap](https://gitlab.com/groups/gitl
FLAG:
On self-managed GitLab, by default this feature is available. To hide the feature,
-ask an administrator to [disable the feature flags](../administration/feature_flags.md) named `work_items` and `work_items_hierarchy`.
+ask an administrator to [disable the feature flags](../administration/feature_flags.md) named `work_items`.
On GitLab.com, this feature is available.
Use tasks to track steps needed for the [issue](project/issues/index.md) to be closed.
@@ -50,9 +50,26 @@ Prerequisites:
To create a task:
1. In the issue description, in the **Tasks** section, select **Add**.
+1. Select **New task**.
1. Enter the task title.
1. Select **Create task**.
+## Add existing tasks to an issue
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/381868) in GitLab 15.6.
+
+Prerequisites:
+
+- You must have at least the Guest role for the project, or the project must be public.
+
+To add a task:
+
+1. In the issue description, in the **Tasks** section, select **Add**.
+1. Select **Existing task**.
+1. Search tasks by title.
+1. Select one or multiple tasks to add to the issue.
+1. Select **Add task**.
+
## Edit a task
Prerequisites:
@@ -159,6 +176,30 @@ To set a start date:
The due date must be the same or later than the start date.
If you select a start date to be later than the due date, the due date is then changed to the same day.
+## Add a task to a milestone
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/367463) in GitLab 15.5 [with a flag](../administration/feature_flags.md) named `work_items_mvc_2`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available per group, ask an administrator to [enable the feature flag](../administration/feature_flags.md) named `work_items_mvc_2`. On GitLab.com, this feature is not available. The feature is not ready for production use.
+
+You can add a task to a [milestone](project/milestones/index.md).
+You can see the milestone title when you view a task.
+If you create a task for an issue that already belongs to a milestone,
+the new task inherits the milestone.
+
+Prerequisites:
+
+- You must have at least the Reporter role for the project.
+
+To add a task to a milestone:
+
+1. In the issue description, in the **Tasks** section, select the title of the task you want to edit.
+ The task window opens.
+1. Next to **Milestone**, select **Add to milestone**.
+If a task already belongs to a milestone, the dropdown list shows the current milestone.
+1. From the dropdown list, select the milestone to be associated with the task.
+
## Set task weight **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/362550) in GitLab 15.3.
diff --git a/doc/user/usage_quotas.md b/doc/user/usage_quotas.md
index 1b265e86dd4..7df5ade215d 100644
--- a/doc/user/usage_quotas.md
+++ b/doc/user/usage_quotas.md
@@ -7,52 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Storage usage quota **(FREE)**
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/13294) in GitLab 12.0.
-> - Moved to GitLab Free.
-
-## Namespace storage limit
-
-Namespaces on GitLab SaaS have a storage limit. For more information, see our [pricing page](https://about.gitlab.com/pricing/).
-This limit is not visible on the Usage quotas page, but will be prior to the limit being [applied](#namespace-storage-limit-application-schedule). Self-managed deployments are not affected.
-
-Storage types that add to the total namespace storage are:
-
-- Git repository
-- Git LFS
-- Artifacts
-- Container registry
-- Package registry
-- Dependency proxy
-- Wiki
-- Snippets
-
-If your total namespace storage exceeds the available namespace storage quota, all projects under the namespace are locked.
-A locked project cannot push to the repository, run pipelines and jobs, or build and push packages.
-
-To prevent exceeding the namespace storage quota, you can:
-
-- Reduce storage consumption by following the suggestions in the [Manage Your Storage Usage](#manage-your-storage-usage) section of this page.
-- Apply for [GitLab for Education](https://about.gitlab.com/solutions/education/join/), [GitLab for Open Source](https://about.gitlab.com/solutions/open-source/join/), or [GitLab for Startups](https://about.gitlab.com/solutions/startups/) if you meet the eligibility requirements.
-- Consider using a [self-managed instance](../subscriptions/self_managed/index.md) of GitLab which does not have these limits on the free tier.
-- [Purchase additional storage](../subscriptions/gitlab_com/index.md#purchase-more-storage-and-transfer) units at $60/year for 10GB of storage.
-- [Start a trial](https://about.gitlab.com/free-trial/) or [upgrade to GitLab Premium or Ultimate](https://about.gitlab.com/pricing) which include higher limits and features that enable growing teams to ship faster without sacrificing on quality.
-- [Talk to an expert](https://page.gitlab.com/usage_limits_help.html) to learn more about your options and ask questions.
-
-### Namespace storage limit application schedule
-
-Information on when namespace-level storage limits will be applied is available on these FAQ pages for the [Free](https://about.gitlab.com/pricing/faq-efficient-free-tier/#storage-limits-on-gitlab-saas-free-tier) and [Paid](https://about.gitlab.com/pricing/faq-paid-storage-transfer/) tier.
-
-## Project storage limit
-
-Projects on GitLab SaaS have a 10GB storage limit on their Git repository and LFS storage.
-After namespace-level storage limits are applied, the project limit will be removed. A namespace has either a namespace-level storage limit or a project-level storage limit, but not both.
-
-When a project's repository and LFS reaches the quota, the project is locked.
-You cannot push changes to a locked project. To monitor the size of each
-repository in a namespace, including a breakdown for each project,
-[view storage usage](#view-storage-usage). To allow a project's repository and LFS to exceed the free quota
-you must purchase additional storage. For more details, see [Excess storage usage](#excess-storage-usage).
-
## View storage usage
Prerequisites:
@@ -72,7 +26,7 @@ is updated every 90 minutes.
If your namespace shows `'Not applicable.'`, push a commit to any project in the
namespace to recalculate the storage.
-## Storage usage statistics
+### Storage usage statistics
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68898) project-level graph in GitLab 14.4 [with a flag](../administration/feature_flags.md) named `project_storage_ui`. Disabled by default.
> - Enabled on GitLab.com in GitLab 14.4.
@@ -97,7 +51,22 @@ Depending on your role, you can also use the following methods to manage or redu
- [Reduce container registry storage](packages/container_registry/reduce_container_registry_storage.md).
- [Reduce wiki repository size](../administration/wikis/index.md#reduce-wiki-repository-size).
-## Excess storage usage
+## Manage your transfer usage
+
+Depending on your role, to manage your transfer usage you can [reduce Container Registry data transfers](packages/container_registry/reduce_container_registry_data_transfer.md).
+
+## Project storage limit
+
+Projects on GitLab SaaS have a 10GB storage limit on their Git repository and LFS storage.
+After namespace-level storage limits are applied, the project limit will be removed. A namespace has either a namespace-level storage limit or a project-level storage limit, but not both.
+
+When a project's repository and LFS reaches the quota, the project is locked.
+You cannot push changes to a locked project. To monitor the size of each
+repository in a namespace, including a breakdown for each project,
+[view storage usage](#view-storage-usage). To allow a project's repository and LFS to exceed the free quota
+you must purchase additional storage. For more details, see [Excess storage usage](#excess-storage-usage).
+
+### Excess storage usage
Excess storage usage is the amount that a project's repository and LFS exceeds the [project storage limit](#project-storage-limit). If no
purchased storage is available the project is locked. You cannot push changes to a locked project.
@@ -112,7 +81,7 @@ The **Storage** tab of the **Usage Quotas** page warns you of the following:
- Projects that are locked because purchased storage available is zero. Locked projects are
marked with an information icon (**{information-o}**) beside their name.
-### Excess storage example
+#### Excess storage example
The following example describes an excess storage scenario for a namespace:
@@ -141,8 +110,34 @@ available decreases. All projects remain unlocked because 40 GB purchased storag
| Yellow | 5 GB | 0 GB | 10 GB | Not locked |
| **Totals** | **45 GB** | **10 GB** | - | - |
-## Manage your transfer usage
+## Namespace storage limit
-Depending on your role, you can use the following methods to manage or reduce your transfer:
+Namespaces on GitLab SaaS have a storage limit. For more information, see our [pricing page](https://about.gitlab.com/pricing/).
+This limit is not visible on the **Usage quotas** page, but will be prior to the limit being [applied](#namespace-storage-limit-application-schedule). Self-managed deployments are not affected.
+
+Storage types that add to the total namespace storage are:
+
+- Git repository
+- Git LFS
+- Artifacts
+- Container registry
+- Package registry
+- Dependency proxy
+- Wiki
+- Snippets
+
+If your total namespace storage exceeds the available namespace storage quota, all projects under the namespace are locked.
+A locked project cannot push to the repository, run pipelines and jobs, or build and push packages.
+
+To prevent exceeding the namespace storage quota, you can:
+
+- Reduce storage consumption by following the suggestions in the [Manage Your Storage Usage](#manage-your-storage-usage) section of this page.
+- Apply for [GitLab for Education](https://about.gitlab.com/solutions/education/join/), [GitLab for Open Source](https://about.gitlab.com/solutions/open-source/join/), or [GitLab for Startups](https://about.gitlab.com/solutions/startups/) if you meet the eligibility requirements.
+- Consider using a [self-managed instance](../subscriptions/self_managed/index.md) of GitLab which does not have these limits on the free tier.
+- [Purchase additional storage](../subscriptions/gitlab_com/index.md#purchase-more-storage-and-transfer) units at $60/year for 10GB of storage.
+- [Start a trial](https://about.gitlab.com/free-trial/) or [upgrade to GitLab Premium or Ultimate](https://about.gitlab.com/pricing/) which include higher limits and features that enable growing teams to ship faster without sacrificing on quality.
+- [Talk to an expert](https://page.gitlab.com/usage_limits_help.html) to learn more about your options and ask questions.
+
+### Namespace storage limit application schedule
-- [Reduce Container Registry data transfers](packages/container_registry/reduce_container_registry_data_transfer.md).
+Information on when namespace-level storage limits will be applied is available on these FAQ pages for the [Free](https://about.gitlab.com/pricing/faq-efficient-free-tier/#storage-limits-on-gitlab-saas-free-tier) and [Paid](https://about.gitlab.com/pricing/faq-paid-storage-transfer/) tier.
diff --git a/doc/user/workspace/index.md b/doc/user/workspace/index.md
index d7e014672aa..5bcd96cd4a5 100644
--- a/doc/user/workspace/index.md
+++ b/doc/user/workspace/index.md
@@ -15,7 +15,7 @@ The development, release, and timing of any products, features, or functionality
sole discretion of GitLab Inc.
NOTE:
-Workspace is currently in development.
+Workspace is in development.
Workspace will be above the [top-level namespaces](../namespace/index.md) for you to manage
everything you do as a GitLab administrator, including:
diff --git a/generator_templates/usage_metric_definition/metric_definition.yml b/generator_templates/usage_metric_definition/metric_definition.yml
index f8920b8d963..ca4f00866ab 100644
--- a/generator_templates/usage_metric_definition/metric_definition.yml
+++ b/generator_templates/usage_metric_definition/metric_definition.yml
@@ -13,7 +13,7 @@ time_frame: <%= time_frame %>
data_source:
data_category: optional
instrumentation_class: <%= class_name %>
-performance_indicator_type:
+performance_indicator_type: []
distribution:
<%= distribution %>
tier:
diff --git a/glfm_specification/example_snapshots/examples_index.yml b/glfm_specification/example_snapshots/examples_index.yml
deleted file mode 100644
index c0739912399..00000000000
--- a/glfm_specification/example_snapshots/examples_index.yml
+++ /dev/null
@@ -1,2086 +0,0 @@
----
-02_01_00__preliminaries__tabs__001:
- spec_txt_example_position: 1
- source_specification: commonmark
-02_01_00__preliminaries__tabs__002:
- spec_txt_example_position: 2
- source_specification: commonmark
-02_01_00__preliminaries__tabs__003:
- spec_txt_example_position: 3
- source_specification: commonmark
-02_01_00__preliminaries__tabs__004:
- spec_txt_example_position: 4
- source_specification: commonmark
-02_01_00__preliminaries__tabs__005:
- spec_txt_example_position: 5
- source_specification: commonmark
-02_01_00__preliminaries__tabs__006:
- spec_txt_example_position: 6
- source_specification: commonmark
-02_01_00__preliminaries__tabs__007:
- spec_txt_example_position: 7
- source_specification: commonmark
-02_01_00__preliminaries__tabs__008:
- spec_txt_example_position: 8
- source_specification: commonmark
-02_01_00__preliminaries__tabs__009:
- spec_txt_example_position: 9
- source_specification: commonmark
-02_01_00__preliminaries__tabs__010:
- spec_txt_example_position: 10
- source_specification: commonmark
-02_01_00__preliminaries__tabs__011:
- spec_txt_example_position: 11
- source_specification: commonmark
-03_01_00__blocks_and_inlines__precedence__001:
- spec_txt_example_position: 12
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__001:
- spec_txt_example_position: 13
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__002:
- spec_txt_example_position: 14
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__003:
- spec_txt_example_position: 15
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__004:
- spec_txt_example_position: 16
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__005:
- spec_txt_example_position: 17
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__006:
- spec_txt_example_position: 18
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__007:
- spec_txt_example_position: 19
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__008:
- spec_txt_example_position: 20
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__009:
- spec_txt_example_position: 21
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__010:
- spec_txt_example_position: 22
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__011:
- spec_txt_example_position: 23
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__012:
- spec_txt_example_position: 24
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__013:
- spec_txt_example_position: 25
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__014:
- spec_txt_example_position: 26
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__015:
- spec_txt_example_position: 27
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__016:
- spec_txt_example_position: 28
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__017:
- spec_txt_example_position: 29
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__018:
- spec_txt_example_position: 30
- source_specification: commonmark
-04_01_00__leaf_blocks__thematic_breaks__019:
- spec_txt_example_position: 31
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__001:
- spec_txt_example_position: 32
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__002:
- spec_txt_example_position: 33
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__003:
- spec_txt_example_position: 34
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__004:
- spec_txt_example_position: 35
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__005:
- spec_txt_example_position: 36
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__006:
- spec_txt_example_position: 37
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__007:
- spec_txt_example_position: 38
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__008:
- spec_txt_example_position: 39
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__009:
- spec_txt_example_position: 40
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__010:
- spec_txt_example_position: 41
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__011:
- spec_txt_example_position: 42
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__012:
- spec_txt_example_position: 43
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__013:
- spec_txt_example_position: 44
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__014:
- spec_txt_example_position: 45
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__015:
- spec_txt_example_position: 46
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__016:
- spec_txt_example_position: 47
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__017:
- spec_txt_example_position: 48
- source_specification: commonmark
-04_02_00__leaf_blocks__atx_headings__018:
- spec_txt_example_position: 49
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__001:
- spec_txt_example_position: 50
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__002:
- spec_txt_example_position: 51
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__003:
- spec_txt_example_position: 52
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__004:
- spec_txt_example_position: 53
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__005:
- spec_txt_example_position: 54
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__006:
- spec_txt_example_position: 55
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__007:
- spec_txt_example_position: 56
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__008:
- spec_txt_example_position: 57
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__009:
- spec_txt_example_position: 58
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__010:
- spec_txt_example_position: 59
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__011:
- spec_txt_example_position: 60
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__012:
- spec_txt_example_position: 61
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__013:
- spec_txt_example_position: 62
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__014:
- spec_txt_example_position: 63
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__015:
- spec_txt_example_position: 64
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__016:
- spec_txt_example_position: 65
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__017:
- spec_txt_example_position: 66
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__018:
- spec_txt_example_position: 67
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__019:
- spec_txt_example_position: 68
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__020:
- spec_txt_example_position: 69
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__021:
- spec_txt_example_position: 70
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__022:
- spec_txt_example_position: 71
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__023:
- spec_txt_example_position: 72
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__024:
- spec_txt_example_position: 73
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__025:
- spec_txt_example_position: 74
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__026:
- spec_txt_example_position: 75
- source_specification: commonmark
-04_03_00__leaf_blocks__setext_headings__027:
- spec_txt_example_position: 76
- source_specification: commonmark
-04_04_00__leaf_blocks__indented_code_blocks__001:
- spec_txt_example_position: 77
- source_specification: commonmark
-04_04_00__leaf_blocks__indented_code_blocks__002:
- spec_txt_example_position: 78
- source_specification: commonmark
-04_04_00__leaf_blocks__indented_code_blocks__003:
- spec_txt_example_position: 79
- source_specification: commonmark
-04_04_00__leaf_blocks__indented_code_blocks__004:
- spec_txt_example_position: 80
- source_specification: commonmark
-04_04_00__leaf_blocks__indented_code_blocks__005:
- spec_txt_example_position: 81
- source_specification: commonmark
-04_04_00__leaf_blocks__indented_code_blocks__006:
- spec_txt_example_position: 82
- source_specification: commonmark
-04_04_00__leaf_blocks__indented_code_blocks__007:
- spec_txt_example_position: 83
- source_specification: commonmark
-04_04_00__leaf_blocks__indented_code_blocks__008:
- spec_txt_example_position: 84
- source_specification: commonmark
-04_04_00__leaf_blocks__indented_code_blocks__009:
- spec_txt_example_position: 85
- source_specification: commonmark
-04_04_00__leaf_blocks__indented_code_blocks__010:
- spec_txt_example_position: 86
- source_specification: commonmark
-04_04_00__leaf_blocks__indented_code_blocks__011:
- spec_txt_example_position: 87
- source_specification: commonmark
-04_04_00__leaf_blocks__indented_code_blocks__012:
- spec_txt_example_position: 88
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__001:
- spec_txt_example_position: 89
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__002:
- spec_txt_example_position: 90
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__003:
- spec_txt_example_position: 91
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__004:
- spec_txt_example_position: 92
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__005:
- spec_txt_example_position: 93
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__006:
- spec_txt_example_position: 94
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__007:
- spec_txt_example_position: 95
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__008:
- spec_txt_example_position: 96
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__009:
- spec_txt_example_position: 97
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__010:
- spec_txt_example_position: 98
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__011:
- spec_txt_example_position: 99
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__012:
- spec_txt_example_position: 100
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__013:
- spec_txt_example_position: 101
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__014:
- spec_txt_example_position: 102
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__015:
- spec_txt_example_position: 103
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__016:
- spec_txt_example_position: 104
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__017:
- spec_txt_example_position: 105
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__018:
- spec_txt_example_position: 106
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__019:
- spec_txt_example_position: 107
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__020:
- spec_txt_example_position: 108
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__021:
- spec_txt_example_position: 109
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__022:
- spec_txt_example_position: 110
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__023:
- spec_txt_example_position: 111
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__024:
- spec_txt_example_position: 112
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__025:
- spec_txt_example_position: 113
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__026:
- spec_txt_example_position: 114
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__027:
- spec_txt_example_position: 115
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__028:
- spec_txt_example_position: 116
- source_specification: commonmark
-04_05_00__leaf_blocks__fenced_code_blocks__029:
- spec_txt_example_position: 117
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__001:
- spec_txt_example_position: 118
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__002:
- spec_txt_example_position: 119
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__003:
- spec_txt_example_position: 120
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__004:
- spec_txt_example_position: 121
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__005:
- spec_txt_example_position: 122
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__006:
- spec_txt_example_position: 123
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__007:
- spec_txt_example_position: 124
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__008:
- spec_txt_example_position: 125
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__009:
- spec_txt_example_position: 126
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__010:
- spec_txt_example_position: 127
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__011:
- spec_txt_example_position: 128
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__012:
- spec_txt_example_position: 129
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__013:
- spec_txt_example_position: 130
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__014:
- spec_txt_example_position: 131
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__015:
- spec_txt_example_position: 132
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__016:
- spec_txt_example_position: 133
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__017:
- spec_txt_example_position: 134
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__018:
- spec_txt_example_position: 135
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__019:
- spec_txt_example_position: 136
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__020:
- spec_txt_example_position: 137
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__021:
- spec_txt_example_position: 138
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__022:
- spec_txt_example_position: 139
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__023:
- spec_txt_example_position: 140
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__024:
- spec_txt_example_position: 141
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__025:
- spec_txt_example_position: 142
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__026:
- spec_txt_example_position: 143
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__027:
- spec_txt_example_position: 144
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__028:
- spec_txt_example_position: 145
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__029:
- spec_txt_example_position: 146
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__030:
- spec_txt_example_position: 147
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__031:
- spec_txt_example_position: 148
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__032:
- spec_txt_example_position: 149
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__033:
- spec_txt_example_position: 150
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__034:
- spec_txt_example_position: 151
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__035:
- spec_txt_example_position: 152
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__036:
- spec_txt_example_position: 153
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__037:
- spec_txt_example_position: 154
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__038:
- spec_txt_example_position: 155
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__039:
- spec_txt_example_position: 156
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__040:
- spec_txt_example_position: 157
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__041:
- spec_txt_example_position: 158
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__042:
- spec_txt_example_position: 159
- source_specification: commonmark
-04_06_00__leaf_blocks__html_blocks__043:
- spec_txt_example_position: 160
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__001:
- spec_txt_example_position: 161
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__002:
- spec_txt_example_position: 162
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__003:
- spec_txt_example_position: 163
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__004:
- spec_txt_example_position: 164
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__005:
- spec_txt_example_position: 165
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__006:
- spec_txt_example_position: 166
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__007:
- spec_txt_example_position: 167
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__008:
- spec_txt_example_position: 168
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__009:
- spec_txt_example_position: 169
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__010:
- spec_txt_example_position: 170
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__011:
- spec_txt_example_position: 171
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__012:
- spec_txt_example_position: 172
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__013:
- spec_txt_example_position: 173
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__014:
- spec_txt_example_position: 174
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__015:
- spec_txt_example_position: 175
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__016:
- spec_txt_example_position: 176
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__017:
- spec_txt_example_position: 177
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__018:
- spec_txt_example_position: 178
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__019:
- spec_txt_example_position: 179
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__020:
- spec_txt_example_position: 180
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__021:
- spec_txt_example_position: 181
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__022:
- spec_txt_example_position: 182
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__023:
- spec_txt_example_position: 183
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__024:
- spec_txt_example_position: 184
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__025:
- spec_txt_example_position: 185
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__026:
- spec_txt_example_position: 186
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__027:
- spec_txt_example_position: 187
- source_specification: commonmark
-04_07_00__leaf_blocks__link_reference_definitions__028:
- spec_txt_example_position: 188
- source_specification: commonmark
-04_08_00__leaf_blocks__paragraphs__001:
- spec_txt_example_position: 189
- source_specification: commonmark
-04_08_00__leaf_blocks__paragraphs__002:
- spec_txt_example_position: 190
- source_specification: commonmark
-04_08_00__leaf_blocks__paragraphs__003:
- spec_txt_example_position: 191
- source_specification: commonmark
-04_08_00__leaf_blocks__paragraphs__004:
- spec_txt_example_position: 192
- source_specification: commonmark
-04_08_00__leaf_blocks__paragraphs__005:
- spec_txt_example_position: 193
- source_specification: commonmark
-04_08_00__leaf_blocks__paragraphs__006:
- spec_txt_example_position: 194
- source_specification: commonmark
-04_08_00__leaf_blocks__paragraphs__007:
- spec_txt_example_position: 195
- source_specification: commonmark
-04_08_00__leaf_blocks__paragraphs__008:
- spec_txt_example_position: 196
- source_specification: commonmark
-04_09_00__leaf_blocks__blank_lines__001:
- spec_txt_example_position: 197
- source_specification: commonmark
-04_10_00__leaf_blocks__tables_extension__001:
- spec_txt_example_position: 198
- source_specification: github
-04_10_00__leaf_blocks__tables_extension__002:
- spec_txt_example_position: 199
- source_specification: github
-04_10_00__leaf_blocks__tables_extension__003:
- spec_txt_example_position: 200
- source_specification: github
-04_10_00__leaf_blocks__tables_extension__004:
- spec_txt_example_position: 201
- source_specification: github
-04_10_00__leaf_blocks__tables_extension__005:
- spec_txt_example_position: 202
- source_specification: github
-04_10_00__leaf_blocks__tables_extension__006:
- spec_txt_example_position: 203
- source_specification: github
-04_10_00__leaf_blocks__tables_extension__007:
- spec_txt_example_position: 204
- source_specification: github
-04_10_00__leaf_blocks__tables_extension__008:
- spec_txt_example_position: 205
- source_specification: github
-05_01_00__container_blocks__block_quotes__001:
- spec_txt_example_position: 206
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__002:
- spec_txt_example_position: 207
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__003:
- spec_txt_example_position: 208
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__004:
- spec_txt_example_position: 209
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__005:
- spec_txt_example_position: 210
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__006:
- spec_txt_example_position: 211
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__007:
- spec_txt_example_position: 212
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__008:
- spec_txt_example_position: 213
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__009:
- spec_txt_example_position: 214
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__010:
- spec_txt_example_position: 215
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__011:
- spec_txt_example_position: 216
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__012:
- spec_txt_example_position: 217
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__013:
- spec_txt_example_position: 218
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__014:
- spec_txt_example_position: 219
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__015:
- spec_txt_example_position: 220
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__016:
- spec_txt_example_position: 221
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__017:
- spec_txt_example_position: 222
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__018:
- spec_txt_example_position: 223
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__019:
- spec_txt_example_position: 224
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__020:
- spec_txt_example_position: 225
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__021:
- spec_txt_example_position: 226
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__022:
- spec_txt_example_position: 227
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__023:
- spec_txt_example_position: 228
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__024:
- spec_txt_example_position: 229
- source_specification: commonmark
-05_01_00__container_blocks__block_quotes__025:
- spec_txt_example_position: 230
- source_specification: commonmark
-05_02_00__container_blocks__list_items__001:
- spec_txt_example_position: 231
- source_specification: commonmark
-05_02_00__container_blocks__list_items__002:
- spec_txt_example_position: 232
- source_specification: commonmark
-05_02_00__container_blocks__list_items__003:
- spec_txt_example_position: 233
- source_specification: commonmark
-05_02_00__container_blocks__list_items__004:
- spec_txt_example_position: 234
- source_specification: commonmark
-05_02_00__container_blocks__list_items__005:
- spec_txt_example_position: 235
- source_specification: commonmark
-05_02_00__container_blocks__list_items__006:
- spec_txt_example_position: 236
- source_specification: commonmark
-05_02_00__container_blocks__list_items__007:
- spec_txt_example_position: 237
- source_specification: commonmark
-05_02_00__container_blocks__list_items__008:
- spec_txt_example_position: 238
- source_specification: commonmark
-05_02_00__container_blocks__list_items__009:
- spec_txt_example_position: 239
- source_specification: commonmark
-05_02_00__container_blocks__list_items__010:
- spec_txt_example_position: 240
- source_specification: commonmark
-05_02_00__container_blocks__list_items__011:
- spec_txt_example_position: 241
- source_specification: commonmark
-05_02_00__container_blocks__list_items__012:
- spec_txt_example_position: 242
- source_specification: commonmark
-05_02_00__container_blocks__list_items__013:
- spec_txt_example_position: 243
- source_specification: commonmark
-05_02_00__container_blocks__list_items__014:
- spec_txt_example_position: 244
- source_specification: commonmark
-05_02_00__container_blocks__list_items__015:
- spec_txt_example_position: 245
- source_specification: commonmark
-05_02_00__container_blocks__list_items__016:
- spec_txt_example_position: 246
- source_specification: commonmark
-05_02_00__container_blocks__list_items__017:
- spec_txt_example_position: 247
- source_specification: commonmark
-05_02_00__container_blocks__list_items__018:
- spec_txt_example_position: 248
- source_specification: commonmark
-05_02_00__container_blocks__list_items__019:
- spec_txt_example_position: 249
- source_specification: commonmark
-05_02_00__container_blocks__list_items__020:
- spec_txt_example_position: 250
- source_specification: commonmark
-05_02_00__container_blocks__list_items__021:
- spec_txt_example_position: 251
- source_specification: commonmark
-05_02_00__container_blocks__list_items__022:
- spec_txt_example_position: 252
- source_specification: commonmark
-05_02_00__container_blocks__list_items__023:
- spec_txt_example_position: 253
- source_specification: commonmark
-05_02_00__container_blocks__list_items__024:
- spec_txt_example_position: 254
- source_specification: commonmark
-05_02_00__container_blocks__list_items__025:
- spec_txt_example_position: 255
- source_specification: commonmark
-05_02_00__container_blocks__list_items__026:
- spec_txt_example_position: 256
- source_specification: commonmark
-05_02_00__container_blocks__list_items__027:
- spec_txt_example_position: 257
- source_specification: commonmark
-05_02_00__container_blocks__list_items__028:
- spec_txt_example_position: 258
- source_specification: commonmark
-05_02_00__container_blocks__list_items__029:
- spec_txt_example_position: 259
- source_specification: commonmark
-05_02_00__container_blocks__list_items__030:
- spec_txt_example_position: 260
- source_specification: commonmark
-05_02_00__container_blocks__list_items__031:
- spec_txt_example_position: 261
- source_specification: commonmark
-05_02_00__container_blocks__list_items__032:
- spec_txt_example_position: 262
- source_specification: commonmark
-05_02_00__container_blocks__list_items__033:
- spec_txt_example_position: 263
- source_specification: commonmark
-05_02_00__container_blocks__list_items__034:
- spec_txt_example_position: 264
- source_specification: commonmark
-05_02_00__container_blocks__list_items__035:
- spec_txt_example_position: 265
- source_specification: commonmark
-05_02_00__container_blocks__list_items__036:
- spec_txt_example_position: 266
- source_specification: commonmark
-05_02_00__container_blocks__list_items__037:
- spec_txt_example_position: 267
- source_specification: commonmark
-05_02_00__container_blocks__list_items__038:
- spec_txt_example_position: 268
- source_specification: commonmark
-05_02_00__container_blocks__list_items__039:
- spec_txt_example_position: 269
- source_specification: commonmark
-05_02_00__container_blocks__list_items__040:
- spec_txt_example_position: 270
- source_specification: commonmark
-05_02_00__container_blocks__list_items__041:
- spec_txt_example_position: 271
- source_specification: commonmark
-05_02_00__container_blocks__list_items__042:
- spec_txt_example_position: 272
- source_specification: commonmark
-05_02_00__container_blocks__list_items__043:
- spec_txt_example_position: 273
- source_specification: commonmark
-05_02_00__container_blocks__list_items__044:
- spec_txt_example_position: 274
- source_specification: commonmark
-05_02_00__container_blocks__list_items__045:
- spec_txt_example_position: 275
- source_specification: commonmark
-05_02_00__container_blocks__list_items__046:
- spec_txt_example_position: 276
- source_specification: commonmark
-05_02_00__container_blocks__list_items__047:
- spec_txt_example_position: 277
- source_specification: commonmark
-05_02_00__container_blocks__list_items__048:
- spec_txt_example_position: 278
- source_specification: commonmark
-05_04_00__container_blocks__lists__001:
- spec_txt_example_position: 281
- source_specification: commonmark
-05_04_00__container_blocks__lists__002:
- spec_txt_example_position: 282
- source_specification: commonmark
-05_04_00__container_blocks__lists__003:
- spec_txt_example_position: 283
- source_specification: commonmark
-05_04_00__container_blocks__lists__004:
- spec_txt_example_position: 284
- source_specification: commonmark
-05_04_00__container_blocks__lists__005:
- spec_txt_example_position: 285
- source_specification: commonmark
-05_04_00__container_blocks__lists__006:
- spec_txt_example_position: 286
- source_specification: commonmark
-05_04_00__container_blocks__lists__007:
- spec_txt_example_position: 287
- source_specification: commonmark
-05_04_00__container_blocks__lists__008:
- spec_txt_example_position: 288
- source_specification: commonmark
-05_04_00__container_blocks__lists__009:
- spec_txt_example_position: 289
- source_specification: commonmark
-05_04_00__container_blocks__lists__010:
- spec_txt_example_position: 290
- source_specification: commonmark
-05_04_00__container_blocks__lists__011:
- spec_txt_example_position: 291
- source_specification: commonmark
-05_04_00__container_blocks__lists__012:
- spec_txt_example_position: 292
- source_specification: commonmark
-05_04_00__container_blocks__lists__013:
- spec_txt_example_position: 293
- source_specification: commonmark
-05_04_00__container_blocks__lists__014:
- spec_txt_example_position: 294
- source_specification: commonmark
-05_04_00__container_blocks__lists__015:
- spec_txt_example_position: 295
- source_specification: commonmark
-05_04_00__container_blocks__lists__016:
- spec_txt_example_position: 296
- source_specification: commonmark
-05_04_00__container_blocks__lists__017:
- spec_txt_example_position: 297
- source_specification: commonmark
-05_04_00__container_blocks__lists__018:
- spec_txt_example_position: 298
- source_specification: commonmark
-05_04_00__container_blocks__lists__019:
- spec_txt_example_position: 299
- source_specification: commonmark
-05_04_00__container_blocks__lists__020:
- spec_txt_example_position: 300
- source_specification: commonmark
-05_04_00__container_blocks__lists__021:
- spec_txt_example_position: 301
- source_specification: commonmark
-05_04_00__container_blocks__lists__022:
- spec_txt_example_position: 302
- source_specification: commonmark
-05_04_00__container_blocks__lists__023:
- spec_txt_example_position: 303
- source_specification: commonmark
-05_04_00__container_blocks__lists__024:
- spec_txt_example_position: 304
- source_specification: commonmark
-05_04_00__container_blocks__lists__025:
- spec_txt_example_position: 305
- source_specification: commonmark
-05_04_00__container_blocks__lists__026:
- spec_txt_example_position: 306
- source_specification: commonmark
-06_01_00__inlines__001:
- spec_txt_example_position: 307
- source_specification: commonmark
-06_02_00__inlines__backslash_escapes__001:
- spec_txt_example_position: 308
- source_specification: commonmark
-06_02_00__inlines__backslash_escapes__002:
- spec_txt_example_position: 309
- source_specification: commonmark
-06_02_00__inlines__backslash_escapes__003:
- spec_txt_example_position: 310
- source_specification: commonmark
-06_02_00__inlines__backslash_escapes__004:
- spec_txt_example_position: 311
- source_specification: commonmark
-06_02_00__inlines__backslash_escapes__005:
- spec_txt_example_position: 312
- source_specification: commonmark
-06_02_00__inlines__backslash_escapes__006:
- spec_txt_example_position: 313
- source_specification: commonmark
-06_02_00__inlines__backslash_escapes__007:
- spec_txt_example_position: 314
- source_specification: commonmark
-06_02_00__inlines__backslash_escapes__008:
- spec_txt_example_position: 315
- source_specification: commonmark
-06_02_00__inlines__backslash_escapes__009:
- spec_txt_example_position: 316
- source_specification: commonmark
-06_02_00__inlines__backslash_escapes__010:
- spec_txt_example_position: 317
- source_specification: commonmark
-06_02_00__inlines__backslash_escapes__011:
- spec_txt_example_position: 318
- source_specification: commonmark
-06_02_00__inlines__backslash_escapes__012:
- spec_txt_example_position: 319
- source_specification: commonmark
-06_02_00__inlines__backslash_escapes__013:
- spec_txt_example_position: 320
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__001:
- spec_txt_example_position: 321
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__002:
- spec_txt_example_position: 322
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__003:
- spec_txt_example_position: 323
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__004:
- spec_txt_example_position: 324
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__005:
- spec_txt_example_position: 325
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__006:
- spec_txt_example_position: 326
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__007:
- spec_txt_example_position: 327
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__008:
- spec_txt_example_position: 328
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__009:
- spec_txt_example_position: 329
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__010:
- spec_txt_example_position: 330
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__011:
- spec_txt_example_position: 331
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__012:
- spec_txt_example_position: 332
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__013:
- spec_txt_example_position: 333
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__014:
- spec_txt_example_position: 334
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__015:
- spec_txt_example_position: 335
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__016:
- spec_txt_example_position: 336
- source_specification: commonmark
-06_03_00__inlines__entity_and_numeric_character_references__017:
- spec_txt_example_position: 337
- source_specification: commonmark
-06_04_00__inlines__code_spans__001:
- spec_txt_example_position: 338
- source_specification: commonmark
-06_04_00__inlines__code_spans__002:
- spec_txt_example_position: 339
- source_specification: commonmark
-06_04_00__inlines__code_spans__003:
- spec_txt_example_position: 340
- source_specification: commonmark
-06_04_00__inlines__code_spans__004:
- spec_txt_example_position: 341
- source_specification: commonmark
-06_04_00__inlines__code_spans__005:
- spec_txt_example_position: 342
- source_specification: commonmark
-06_04_00__inlines__code_spans__006:
- spec_txt_example_position: 343
- source_specification: commonmark
-06_04_00__inlines__code_spans__007:
- spec_txt_example_position: 344
- source_specification: commonmark
-06_04_00__inlines__code_spans__008:
- spec_txt_example_position: 345
- source_specification: commonmark
-06_04_00__inlines__code_spans__009:
- spec_txt_example_position: 346
- source_specification: commonmark
-06_04_00__inlines__code_spans__010:
- spec_txt_example_position: 347
- source_specification: commonmark
-06_04_00__inlines__code_spans__011:
- spec_txt_example_position: 348
- source_specification: commonmark
-06_04_00__inlines__code_spans__012:
- spec_txt_example_position: 349
- source_specification: commonmark
-06_04_00__inlines__code_spans__013:
- spec_txt_example_position: 350
- source_specification: commonmark
-06_04_00__inlines__code_spans__014:
- spec_txt_example_position: 351
- source_specification: commonmark
-06_04_00__inlines__code_spans__015:
- spec_txt_example_position: 352
- source_specification: commonmark
-06_04_00__inlines__code_spans__016:
- spec_txt_example_position: 353
- source_specification: commonmark
-06_04_00__inlines__code_spans__017:
- spec_txt_example_position: 354
- source_specification: commonmark
-06_04_00__inlines__code_spans__018:
- spec_txt_example_position: 355
- source_specification: commonmark
-06_04_00__inlines__code_spans__019:
- spec_txt_example_position: 356
- source_specification: commonmark
-06_04_00__inlines__code_spans__020:
- spec_txt_example_position: 357
- source_specification: commonmark
-06_04_00__inlines__code_spans__021:
- spec_txt_example_position: 358
- source_specification: commonmark
-06_04_00__inlines__code_spans__022:
- spec_txt_example_position: 359
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__001:
- spec_txt_example_position: 360
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__002:
- spec_txt_example_position: 361
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__003:
- spec_txt_example_position: 362
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__004:
- spec_txt_example_position: 363
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__005:
- spec_txt_example_position: 364
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__006:
- spec_txt_example_position: 365
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__007:
- spec_txt_example_position: 366
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__008:
- spec_txt_example_position: 367
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__009:
- spec_txt_example_position: 368
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__010:
- spec_txt_example_position: 369
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__011:
- spec_txt_example_position: 370
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__012:
- spec_txt_example_position: 371
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__013:
- spec_txt_example_position: 372
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__014:
- spec_txt_example_position: 373
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__015:
- spec_txt_example_position: 374
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__016:
- spec_txt_example_position: 375
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__017:
- spec_txt_example_position: 376
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__018:
- spec_txt_example_position: 377
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__019:
- spec_txt_example_position: 378
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__020:
- spec_txt_example_position: 379
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__021:
- spec_txt_example_position: 380
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__022:
- spec_txt_example_position: 381
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__023:
- spec_txt_example_position: 382
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__024:
- spec_txt_example_position: 383
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__025:
- spec_txt_example_position: 384
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__026:
- spec_txt_example_position: 385
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__027:
- spec_txt_example_position: 386
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__028:
- spec_txt_example_position: 387
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__029:
- spec_txt_example_position: 388
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__030:
- spec_txt_example_position: 389
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__031:
- spec_txt_example_position: 390
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__032:
- spec_txt_example_position: 391
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__033:
- spec_txt_example_position: 392
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__034:
- spec_txt_example_position: 393
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__035:
- spec_txt_example_position: 394
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__036:
- spec_txt_example_position: 395
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__037:
- spec_txt_example_position: 396
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__038:
- spec_txt_example_position: 397
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__039:
- spec_txt_example_position: 398
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__040:
- spec_txt_example_position: 399
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__041:
- spec_txt_example_position: 400
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__042:
- spec_txt_example_position: 401
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__043:
- spec_txt_example_position: 402
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__044:
- spec_txt_example_position: 403
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__045:
- spec_txt_example_position: 404
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__046:
- spec_txt_example_position: 405
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__047:
- spec_txt_example_position: 406
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__048:
- spec_txt_example_position: 407
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__049:
- spec_txt_example_position: 408
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__050:
- spec_txt_example_position: 409
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__051:
- spec_txt_example_position: 410
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__052:
- spec_txt_example_position: 411
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__053:
- spec_txt_example_position: 412
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__054:
- spec_txt_example_position: 413
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__055:
- spec_txt_example_position: 414
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__056:
- spec_txt_example_position: 415
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__057:
- spec_txt_example_position: 416
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__058:
- spec_txt_example_position: 417
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__059:
- spec_txt_example_position: 418
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__060:
- spec_txt_example_position: 419
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__061:
- spec_txt_example_position: 420
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__062:
- spec_txt_example_position: 421
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__063:
- spec_txt_example_position: 422
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__064:
- spec_txt_example_position: 423
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__065:
- spec_txt_example_position: 424
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__066:
- spec_txt_example_position: 425
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__067:
- spec_txt_example_position: 426
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__068:
- spec_txt_example_position: 427
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__069:
- spec_txt_example_position: 428
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__070:
- spec_txt_example_position: 429
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__071:
- spec_txt_example_position: 430
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__072:
- spec_txt_example_position: 431
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__073:
- spec_txt_example_position: 432
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__074:
- spec_txt_example_position: 433
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__075:
- spec_txt_example_position: 434
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__076:
- spec_txt_example_position: 435
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__077:
- spec_txt_example_position: 436
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__078:
- spec_txt_example_position: 437
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__079:
- spec_txt_example_position: 438
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__080:
- spec_txt_example_position: 439
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__081:
- spec_txt_example_position: 440
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__082:
- spec_txt_example_position: 441
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__083:
- spec_txt_example_position: 442
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__084:
- spec_txt_example_position: 443
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__085:
- spec_txt_example_position: 444
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__086:
- spec_txt_example_position: 445
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__087:
- spec_txt_example_position: 446
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__088:
- spec_txt_example_position: 447
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__089:
- spec_txt_example_position: 448
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__090:
- spec_txt_example_position: 449
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__091:
- spec_txt_example_position: 450
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__092:
- spec_txt_example_position: 451
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__093:
- spec_txt_example_position: 452
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__094:
- spec_txt_example_position: 453
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__095:
- spec_txt_example_position: 454
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__096:
- spec_txt_example_position: 455
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__097:
- spec_txt_example_position: 456
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__098:
- spec_txt_example_position: 457
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__099:
- spec_txt_example_position: 458
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__100:
- spec_txt_example_position: 459
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__101:
- spec_txt_example_position: 460
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__102:
- spec_txt_example_position: 461
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__103:
- spec_txt_example_position: 462
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__104:
- spec_txt_example_position: 463
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__105:
- spec_txt_example_position: 464
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__106:
- spec_txt_example_position: 465
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__107:
- spec_txt_example_position: 466
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__108:
- spec_txt_example_position: 467
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__109:
- spec_txt_example_position: 468
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__110:
- spec_txt_example_position: 469
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__111:
- spec_txt_example_position: 470
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__112:
- spec_txt_example_position: 471
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__113:
- spec_txt_example_position: 472
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__114:
- spec_txt_example_position: 473
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__115:
- spec_txt_example_position: 474
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__116:
- spec_txt_example_position: 475
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__117:
- spec_txt_example_position: 476
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__118:
- spec_txt_example_position: 477
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__119:
- spec_txt_example_position: 478
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__120:
- spec_txt_example_position: 479
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__121:
- spec_txt_example_position: 480
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__122:
- spec_txt_example_position: 481
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__123:
- spec_txt_example_position: 482
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__124:
- spec_txt_example_position: 483
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__125:
- spec_txt_example_position: 484
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__126:
- spec_txt_example_position: 485
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__127:
- spec_txt_example_position: 486
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__128:
- spec_txt_example_position: 487
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__129:
- spec_txt_example_position: 488
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__130:
- spec_txt_example_position: 489
- source_specification: commonmark
-06_05_00__inlines__emphasis_and_strong_emphasis__131:
- spec_txt_example_position: 490
- source_specification: commonmark
-06_06_00__inlines__strikethrough_extension__001:
- spec_txt_example_position: 491
- source_specification: github
-06_06_00__inlines__strikethrough_extension__002:
- spec_txt_example_position: 492
- source_specification: github
-06_07_00__inlines__links__001:
- spec_txt_example_position: 493
- source_specification: commonmark
-06_07_00__inlines__links__002:
- spec_txt_example_position: 494
- source_specification: commonmark
-06_07_00__inlines__links__003:
- spec_txt_example_position: 495
- source_specification: commonmark
-06_07_00__inlines__links__004:
- spec_txt_example_position: 496
- source_specification: commonmark
-06_07_00__inlines__links__005:
- spec_txt_example_position: 497
- source_specification: commonmark
-06_07_00__inlines__links__006:
- spec_txt_example_position: 498
- source_specification: commonmark
-06_07_00__inlines__links__007:
- spec_txt_example_position: 499
- source_specification: commonmark
-06_07_00__inlines__links__008:
- spec_txt_example_position: 500
- source_specification: commonmark
-06_07_00__inlines__links__009:
- spec_txt_example_position: 501
- source_specification: commonmark
-06_07_00__inlines__links__010:
- spec_txt_example_position: 502
- source_specification: commonmark
-06_07_00__inlines__links__011:
- spec_txt_example_position: 503
- source_specification: commonmark
-06_07_00__inlines__links__012:
- spec_txt_example_position: 504
- source_specification: commonmark
-06_07_00__inlines__links__013:
- spec_txt_example_position: 505
- source_specification: commonmark
-06_07_00__inlines__links__014:
- spec_txt_example_position: 506
- source_specification: commonmark
-06_07_00__inlines__links__015:
- spec_txt_example_position: 507
- source_specification: commonmark
-06_07_00__inlines__links__016:
- spec_txt_example_position: 508
- source_specification: commonmark
-06_07_00__inlines__links__017:
- spec_txt_example_position: 509
- source_specification: commonmark
-06_07_00__inlines__links__018:
- spec_txt_example_position: 510
- source_specification: commonmark
-06_07_00__inlines__links__019:
- spec_txt_example_position: 511
- source_specification: commonmark
-06_07_00__inlines__links__020:
- spec_txt_example_position: 512
- source_specification: commonmark
-06_07_00__inlines__links__021:
- spec_txt_example_position: 513
- source_specification: commonmark
-06_07_00__inlines__links__022:
- spec_txt_example_position: 514
- source_specification: commonmark
-06_07_00__inlines__links__023:
- spec_txt_example_position: 515
- source_specification: commonmark
-06_07_00__inlines__links__024:
- spec_txt_example_position: 516
- source_specification: commonmark
-06_07_00__inlines__links__025:
- spec_txt_example_position: 517
- source_specification: commonmark
-06_07_00__inlines__links__026:
- spec_txt_example_position: 518
- source_specification: commonmark
-06_07_00__inlines__links__027:
- spec_txt_example_position: 519
- source_specification: commonmark
-06_07_00__inlines__links__028:
- spec_txt_example_position: 520
- source_specification: commonmark
-06_07_00__inlines__links__029:
- spec_txt_example_position: 521
- source_specification: commonmark
-06_07_00__inlines__links__030:
- spec_txt_example_position: 522
- source_specification: commonmark
-06_07_00__inlines__links__031:
- spec_txt_example_position: 523
- source_specification: commonmark
-06_07_00__inlines__links__032:
- spec_txt_example_position: 524
- source_specification: commonmark
-06_07_00__inlines__links__033:
- spec_txt_example_position: 525
- source_specification: commonmark
-06_07_00__inlines__links__034:
- spec_txt_example_position: 526
- source_specification: commonmark
-06_07_00__inlines__links__035:
- spec_txt_example_position: 527
- source_specification: commonmark
-06_07_00__inlines__links__036:
- spec_txt_example_position: 528
- source_specification: commonmark
-06_07_00__inlines__links__037:
- spec_txt_example_position: 529
- source_specification: commonmark
-06_07_00__inlines__links__038:
- spec_txt_example_position: 530
- source_specification: commonmark
-06_07_00__inlines__links__039:
- spec_txt_example_position: 531
- source_specification: commonmark
-06_07_00__inlines__links__040:
- spec_txt_example_position: 532
- source_specification: commonmark
-06_07_00__inlines__links__041:
- spec_txt_example_position: 533
- source_specification: commonmark
-06_07_00__inlines__links__042:
- spec_txt_example_position: 534
- source_specification: commonmark
-06_07_00__inlines__links__043:
- spec_txt_example_position: 535
- source_specification: commonmark
-06_07_00__inlines__links__044:
- spec_txt_example_position: 536
- source_specification: commonmark
-06_07_00__inlines__links__045:
- spec_txt_example_position: 537
- source_specification: commonmark
-06_07_00__inlines__links__046:
- spec_txt_example_position: 538
- source_specification: commonmark
-06_07_00__inlines__links__047:
- spec_txt_example_position: 539
- source_specification: commonmark
-06_07_00__inlines__links__048:
- spec_txt_example_position: 540
- source_specification: commonmark
-06_07_00__inlines__links__049:
- spec_txt_example_position: 541
- source_specification: commonmark
-06_07_00__inlines__links__050:
- spec_txt_example_position: 542
- source_specification: commonmark
-06_07_00__inlines__links__051:
- spec_txt_example_position: 543
- source_specification: commonmark
-06_07_00__inlines__links__052:
- spec_txt_example_position: 544
- source_specification: commonmark
-06_07_00__inlines__links__053:
- spec_txt_example_position: 545
- source_specification: commonmark
-06_07_00__inlines__links__054:
- spec_txt_example_position: 546
- source_specification: commonmark
-06_07_00__inlines__links__055:
- spec_txt_example_position: 547
- source_specification: commonmark
-06_07_00__inlines__links__056:
- spec_txt_example_position: 548
- source_specification: commonmark
-06_07_00__inlines__links__057:
- spec_txt_example_position: 549
- source_specification: commonmark
-06_07_00__inlines__links__058:
- spec_txt_example_position: 550
- source_specification: commonmark
-06_07_00__inlines__links__059:
- spec_txt_example_position: 551
- source_specification: commonmark
-06_07_00__inlines__links__060:
- spec_txt_example_position: 552
- source_specification: commonmark
-06_07_00__inlines__links__061:
- spec_txt_example_position: 553
- source_specification: commonmark
-06_07_00__inlines__links__062:
- spec_txt_example_position: 554
- source_specification: commonmark
-06_07_00__inlines__links__063:
- spec_txt_example_position: 555
- source_specification: commonmark
-06_07_00__inlines__links__064:
- spec_txt_example_position: 556
- source_specification: commonmark
-06_07_00__inlines__links__065:
- spec_txt_example_position: 557
- source_specification: commonmark
-06_07_00__inlines__links__066:
- spec_txt_example_position: 558
- source_specification: commonmark
-06_07_00__inlines__links__067:
- spec_txt_example_position: 559
- source_specification: commonmark
-06_07_00__inlines__links__068:
- spec_txt_example_position: 560
- source_specification: commonmark
-06_07_00__inlines__links__069:
- spec_txt_example_position: 561
- source_specification: commonmark
-06_07_00__inlines__links__070:
- spec_txt_example_position: 562
- source_specification: commonmark
-06_07_00__inlines__links__071:
- spec_txt_example_position: 563
- source_specification: commonmark
-06_07_00__inlines__links__072:
- spec_txt_example_position: 564
- source_specification: commonmark
-06_07_00__inlines__links__073:
- spec_txt_example_position: 565
- source_specification: commonmark
-06_07_00__inlines__links__074:
- spec_txt_example_position: 566
- source_specification: commonmark
-06_07_00__inlines__links__075:
- spec_txt_example_position: 567
- source_specification: commonmark
-06_07_00__inlines__links__076:
- spec_txt_example_position: 568
- source_specification: commonmark
-06_07_00__inlines__links__077:
- spec_txt_example_position: 569
- source_specification: commonmark
-06_07_00__inlines__links__078:
- spec_txt_example_position: 570
- source_specification: commonmark
-06_07_00__inlines__links__079:
- spec_txt_example_position: 571
- source_specification: commonmark
-06_07_00__inlines__links__080:
- spec_txt_example_position: 572
- source_specification: commonmark
-06_07_00__inlines__links__081:
- spec_txt_example_position: 573
- source_specification: commonmark
-06_07_00__inlines__links__082:
- spec_txt_example_position: 574
- source_specification: commonmark
-06_07_00__inlines__links__083:
- spec_txt_example_position: 575
- source_specification: commonmark
-06_07_00__inlines__links__084:
- spec_txt_example_position: 576
- source_specification: commonmark
-06_07_00__inlines__links__085:
- spec_txt_example_position: 577
- source_specification: commonmark
-06_07_00__inlines__links__086:
- spec_txt_example_position: 578
- source_specification: commonmark
-06_07_00__inlines__links__087:
- spec_txt_example_position: 579
- source_specification: commonmark
-06_08_00__inlines__images__001:
- spec_txt_example_position: 580
- source_specification: commonmark
-06_08_00__inlines__images__002:
- spec_txt_example_position: 581
- source_specification: commonmark
-06_08_00__inlines__images__003:
- spec_txt_example_position: 582
- source_specification: commonmark
-06_08_00__inlines__images__004:
- spec_txt_example_position: 583
- source_specification: commonmark
-06_08_00__inlines__images__005:
- spec_txt_example_position: 584
- source_specification: commonmark
-06_08_00__inlines__images__006:
- spec_txt_example_position: 585
- source_specification: commonmark
-06_08_00__inlines__images__007:
- spec_txt_example_position: 586
- source_specification: commonmark
-06_08_00__inlines__images__008:
- spec_txt_example_position: 587
- source_specification: commonmark
-06_08_00__inlines__images__009:
- spec_txt_example_position: 588
- source_specification: commonmark
-06_08_00__inlines__images__010:
- spec_txt_example_position: 589
- source_specification: commonmark
-06_08_00__inlines__images__011:
- spec_txt_example_position: 590
- source_specification: commonmark
-06_08_00__inlines__images__012:
- spec_txt_example_position: 591
- source_specification: commonmark
-06_08_00__inlines__images__013:
- spec_txt_example_position: 592
- source_specification: commonmark
-06_08_00__inlines__images__014:
- spec_txt_example_position: 593
- source_specification: commonmark
-06_08_00__inlines__images__015:
- spec_txt_example_position: 594
- source_specification: commonmark
-06_08_00__inlines__images__016:
- spec_txt_example_position: 595
- source_specification: commonmark
-06_08_00__inlines__images__017:
- spec_txt_example_position: 596
- source_specification: commonmark
-06_08_00__inlines__images__018:
- spec_txt_example_position: 597
- source_specification: commonmark
-06_08_00__inlines__images__019:
- spec_txt_example_position: 598
- source_specification: commonmark
-06_08_00__inlines__images__020:
- spec_txt_example_position: 599
- source_specification: commonmark
-06_08_00__inlines__images__021:
- spec_txt_example_position: 600
- source_specification: commonmark
-06_08_00__inlines__images__022:
- spec_txt_example_position: 601
- source_specification: commonmark
-06_09_00__inlines__autolinks__001:
- spec_txt_example_position: 602
- source_specification: commonmark
-06_09_00__inlines__autolinks__002:
- spec_txt_example_position: 603
- source_specification: commonmark
-06_09_00__inlines__autolinks__003:
- spec_txt_example_position: 604
- source_specification: commonmark
-06_09_00__inlines__autolinks__004:
- spec_txt_example_position: 605
- source_specification: commonmark
-06_09_00__inlines__autolinks__005:
- spec_txt_example_position: 606
- source_specification: commonmark
-06_09_00__inlines__autolinks__006:
- spec_txt_example_position: 607
- source_specification: commonmark
-06_09_00__inlines__autolinks__007:
- spec_txt_example_position: 608
- source_specification: commonmark
-06_09_00__inlines__autolinks__008:
- spec_txt_example_position: 609
- source_specification: commonmark
-06_09_00__inlines__autolinks__009:
- spec_txt_example_position: 610
- source_specification: commonmark
-06_09_00__inlines__autolinks__010:
- spec_txt_example_position: 611
- source_specification: commonmark
-06_09_00__inlines__autolinks__011:
- spec_txt_example_position: 612
- source_specification: commonmark
-06_09_00__inlines__autolinks__012:
- spec_txt_example_position: 613
- source_specification: commonmark
-06_09_00__inlines__autolinks__013:
- spec_txt_example_position: 614
- source_specification: commonmark
-06_09_00__inlines__autolinks__014:
- spec_txt_example_position: 615
- source_specification: commonmark
-06_09_00__inlines__autolinks__015:
- spec_txt_example_position: 616
- source_specification: commonmark
-06_09_00__inlines__autolinks__016:
- spec_txt_example_position: 617
- source_specification: commonmark
-06_09_00__inlines__autolinks__017:
- spec_txt_example_position: 618
- source_specification: commonmark
-06_09_00__inlines__autolinks__018:
- spec_txt_example_position: 619
- source_specification: commonmark
-06_09_00__inlines__autolinks__019:
- spec_txt_example_position: 620
- source_specification: commonmark
-06_10_00__inlines__autolinks_extension__001:
- spec_txt_example_position: 621
- source_specification: github
-06_10_00__inlines__autolinks_extension__002:
- spec_txt_example_position: 622
- source_specification: github
-06_10_00__inlines__autolinks_extension__003:
- spec_txt_example_position: 623
- source_specification: github
-06_10_00__inlines__autolinks_extension__004:
- spec_txt_example_position: 624
- source_specification: github
-06_10_00__inlines__autolinks_extension__005:
- spec_txt_example_position: 625
- source_specification: github
-06_10_00__inlines__autolinks_extension__006:
- spec_txt_example_position: 626
- source_specification: github
-06_10_00__inlines__autolinks_extension__007:
- spec_txt_example_position: 627
- source_specification: github
-06_10_00__inlines__autolinks_extension__008:
- spec_txt_example_position: 628
- source_specification: github
-06_10_00__inlines__autolinks_extension__009:
- spec_txt_example_position: 629
- source_specification: github
-06_10_00__inlines__autolinks_extension__010:
- spec_txt_example_position: 630
- source_specification: github
-06_10_00__inlines__autolinks_extension__011:
- spec_txt_example_position: 631
- source_specification: github
-06_11_00__inlines__raw_html__001:
- spec_txt_example_position: 632
- source_specification: commonmark
-06_11_00__inlines__raw_html__002:
- spec_txt_example_position: 633
- source_specification: commonmark
-06_11_00__inlines__raw_html__003:
- spec_txt_example_position: 634
- source_specification: commonmark
-06_11_00__inlines__raw_html__004:
- spec_txt_example_position: 635
- source_specification: commonmark
-06_11_00__inlines__raw_html__005:
- spec_txt_example_position: 636
- source_specification: commonmark
-06_11_00__inlines__raw_html__006:
- spec_txt_example_position: 637
- source_specification: commonmark
-06_11_00__inlines__raw_html__007:
- spec_txt_example_position: 638
- source_specification: commonmark
-06_11_00__inlines__raw_html__008:
- spec_txt_example_position: 639
- source_specification: commonmark
-06_11_00__inlines__raw_html__009:
- spec_txt_example_position: 640
- source_specification: commonmark
-06_11_00__inlines__raw_html__010:
- spec_txt_example_position: 641
- source_specification: commonmark
-06_11_00__inlines__raw_html__011:
- spec_txt_example_position: 642
- source_specification: commonmark
-06_11_00__inlines__raw_html__012:
- spec_txt_example_position: 643
- source_specification: commonmark
-06_11_00__inlines__raw_html__013:
- spec_txt_example_position: 644
- source_specification: commonmark
-06_11_00__inlines__raw_html__014:
- spec_txt_example_position: 645
- source_specification: commonmark
-06_11_00__inlines__raw_html__015:
- spec_txt_example_position: 646
- source_specification: commonmark
-06_11_00__inlines__raw_html__016:
- spec_txt_example_position: 647
- source_specification: commonmark
-06_11_00__inlines__raw_html__017:
- spec_txt_example_position: 648
- source_specification: commonmark
-06_11_00__inlines__raw_html__018:
- spec_txt_example_position: 649
- source_specification: commonmark
-06_11_00__inlines__raw_html__019:
- spec_txt_example_position: 650
- source_specification: commonmark
-06_11_00__inlines__raw_html__020:
- spec_txt_example_position: 651
- source_specification: commonmark
-06_11_00__inlines__raw_html__021:
- spec_txt_example_position: 652
- source_specification: commonmark
-06_12_00__inlines__disallowed_raw_html_extension__001:
- spec_txt_example_position: 653
- source_specification: github
-06_13_00__inlines__hard_line_breaks__001:
- spec_txt_example_position: 654
- source_specification: commonmark
-06_13_00__inlines__hard_line_breaks__002:
- spec_txt_example_position: 655
- source_specification: commonmark
-06_13_00__inlines__hard_line_breaks__003:
- spec_txt_example_position: 656
- source_specification: commonmark
-06_13_00__inlines__hard_line_breaks__004:
- spec_txt_example_position: 657
- source_specification: commonmark
-06_13_00__inlines__hard_line_breaks__005:
- spec_txt_example_position: 658
- source_specification: commonmark
-06_13_00__inlines__hard_line_breaks__006:
- spec_txt_example_position: 659
- source_specification: commonmark
-06_13_00__inlines__hard_line_breaks__007:
- spec_txt_example_position: 660
- source_specification: commonmark
-06_13_00__inlines__hard_line_breaks__008:
- spec_txt_example_position: 661
- source_specification: commonmark
-06_13_00__inlines__hard_line_breaks__009:
- spec_txt_example_position: 662
- source_specification: commonmark
-06_13_00__inlines__hard_line_breaks__010:
- spec_txt_example_position: 663
- source_specification: commonmark
-06_13_00__inlines__hard_line_breaks__011:
- spec_txt_example_position: 664
- source_specification: commonmark
-06_13_00__inlines__hard_line_breaks__012:
- spec_txt_example_position: 665
- source_specification: commonmark
-06_13_00__inlines__hard_line_breaks__013:
- spec_txt_example_position: 666
- source_specification: commonmark
-06_13_00__inlines__hard_line_breaks__014:
- spec_txt_example_position: 667
- source_specification: commonmark
-06_13_00__inlines__hard_line_breaks__015:
- spec_txt_example_position: 668
- source_specification: commonmark
-06_14_00__inlines__soft_line_breaks__001:
- spec_txt_example_position: 669
- source_specification: commonmark
-06_14_00__inlines__soft_line_breaks__002:
- spec_txt_example_position: 670
- source_specification: commonmark
-06_15_00__inlines__textual_content__001:
- spec_txt_example_position: 671
- source_specification: commonmark
-06_15_00__inlines__textual_content__002:
- spec_txt_example_position: 672
- source_specification: commonmark
-06_15_00__inlines__textual_content__003:
- spec_txt_example_position: 673
- source_specification: commonmark
-07_01_00__gitlab_official_specification_markdown__footnotes__001:
- spec_txt_example_position: 674
- source_specification: gitlab
-07_02_00__gitlab_official_specification_markdown__task_list_items__001:
- spec_txt_example_position: 675
- source_specification: gitlab
-07_02_00__gitlab_official_specification_markdown__task_list_items__002:
- spec_txt_example_position: 676
- source_specification: gitlab
-07_02_00__gitlab_official_specification_markdown__task_list_items__003:
- spec_txt_example_position: 677
- source_specification: gitlab
-07_02_00__gitlab_official_specification_markdown__task_list_items__004:
- spec_txt_example_position: 678
- source_specification: gitlab
-07_03_00__gitlab_official_specification_markdown__front_matter__001:
- spec_txt_example_position: 679
- source_specification: gitlab
-07_03_00__gitlab_official_specification_markdown__front_matter__002:
- spec_txt_example_position: 680
- source_specification: gitlab
-07_03_00__gitlab_official_specification_markdown__front_matter__003:
- spec_txt_example_position: 681
- source_specification: gitlab
-07_03_00__gitlab_official_specification_markdown__front_matter__004:
- spec_txt_example_position: 682
- source_specification: gitlab
-07_03_00__gitlab_official_specification_markdown__front_matter__005:
- spec_txt_example_position: 683
- source_specification: gitlab
-07_04_00__gitlab_official_specification_markdown__table_of_contents__001:
- spec_txt_example_position: 684
- source_specification: gitlab
-07_04_00__gitlab_official_specification_markdown__table_of_contents__002:
- spec_txt_example_position: 685
- source_specification: gitlab
-07_04_00__gitlab_official_specification_markdown__table_of_contents__003:
- spec_txt_example_position: 686
- source_specification: gitlab
-07_04_00__gitlab_official_specification_markdown__table_of_contents__004:
- spec_txt_example_position: 687
- source_specification: gitlab
-08_01_00__gitlab_internal_extension_markdown__audio__001:
- spec_txt_example_position: 688
- source_specification: gitlab
-08_01_00__gitlab_internal_extension_markdown__audio__002:
- spec_txt_example_position: 689
- source_specification: gitlab
-08_02_00__gitlab_internal_extension_markdown__video__001:
- spec_txt_example_position: 690
- source_specification: gitlab
-08_02_00__gitlab_internal_extension_markdown__video__002:
- spec_txt_example_position: 691
- source_specification: gitlab
-08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__001:
- spec_txt_example_position: 692
- source_specification: gitlab
-08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__002:
- spec_txt_example_position: 693
- source_specification: gitlab
-08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__003:
- spec_txt_example_position: 694
- source_specification: gitlab
-08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__004:
- spec_txt_example_position: 695
- source_specification: gitlab
-08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__005:
- spec_txt_example_position: 696
- source_specification: gitlab
-08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__006:
- spec_txt_example_position: 697
- source_specification: gitlab
diff --git a/glfm_specification/example_snapshots/html.yml b/glfm_specification/example_snapshots/html.yml
deleted file mode 100644
index ef2ba39f925..00000000000
--- a/glfm_specification/example_snapshots/html.yml
+++ /dev/null
@@ -1,7955 +0,0 @@
----
-02_01_00__preliminaries__tabs__001:
- canonical: "<pre><code>foo\tbaz\t\tbim\n</code></pre>\n"
- static: "<div class=\"gl-relative markdown-code-block js-markdown-code\">\n<pre
- data-sourcepos=\"1:2-1:13\" class=\"code highlight js-syntax-highlight language-plaintext\"
- lang=\"plaintext\" data-canonical-lang=\"\" v-pre=\"true\"><code><span id=\"LC1\"
- class=\"line\" lang=\"plaintext\">foo\tbaz\t\tbim</span></code></pre>\n<copy-code></copy-code>\n</div>"
- wysiwyg: "<pre class=\"content-editor-code-block undefined code highlight\"><code>foo\tbaz\t\tbim</code></pre>"
-02_01_00__preliminaries__tabs__002:
- canonical: "<pre><code>foo\tbaz\t\tbim\n</code></pre>\n"
- static: "<div class=\"gl-relative markdown-code-block js-markdown-code\">\n<pre
- data-sourcepos=\"1:4-1:15\" class=\"code highlight js-syntax-highlight language-plaintext\"
- lang=\"plaintext\" data-canonical-lang=\"\" v-pre=\"true\"><code><span id=\"LC1\"
- class=\"line\" lang=\"plaintext\">foo\tbaz\t\tbim</span></code></pre>\n<copy-code></copy-code>\n</div>"
- wysiwyg: "<pre class=\"content-editor-code-block undefined code highlight\"><code>foo\tbaz\t\tbim</code></pre>"
-02_01_00__preliminaries__tabs__003:
- canonical: "<pre><code>a\ta\ná½\ta\n</code></pre>\n"
- static: "<div class=\"gl-relative markdown-code-block js-markdown-code\">\n<pre
- data-sourcepos=\"1:5-2:9\" class=\"code highlight js-syntax-highlight language-plaintext\"
- lang=\"plaintext\" data-canonical-lang=\"\" v-pre=\"true\"><code><span id=\"LC1\"
- class=\"line\" lang=\"plaintext\">a\ta</span>\n<span id=\"LC2\" class=\"line\"
- lang=\"plaintext\">á½\ta</span></code></pre>\n<copy-code></copy-code>\n</div>"
- wysiwyg: "<pre class=\"content-editor-code-block undefined code highlight\"><code>a\ta\ná½\ta</code></pre>"
-02_01_00__preliminaries__tabs__004:
- canonical: |
- <ul>
- <li>
- <p>foo</p>
- <p>bar</p>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:3-3:4" dir="auto">
- <li data-sourcepos="1:3-3:4">
- <p data-sourcepos="1:5-1:7">foo</p>
- <p data-sourcepos="3:2-3:4">bar</p>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p><p>bar</p></li></ul>
-02_01_00__preliminaries__tabs__005:
- canonical: |
- <ul>
- <li>
- <p>foo</p>
- <pre><code> bar
- </code></pre>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-3:5" dir="auto">
- <li data-sourcepos="1:1-3:5">
- <p data-sourcepos="1:3-1:5">foo</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="3:2-3:5" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> bar</span></code></pre>
- <copy-code></copy-code>
- </div>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p><pre class="content-editor-code-block undefined code highlight"><code> bar</code></pre></li></ul>
-02_01_00__preliminaries__tabs__006:
- canonical: |
- <blockquote>
- <pre><code> foo
- </code></pre>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-1:6" dir="auto">
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:3-1:6" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span></code></pre>
- <copy-code></copy-code>
- </div>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><pre class="content-editor-code-block undefined code highlight"><code> foo</code></pre></blockquote>
-02_01_00__preliminaries__tabs__007:
- canonical: |
- <ul>
- <li>
- <pre><code> foo
- </code></pre>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-1:6" dir="auto">
- <li data-sourcepos="1:1-1:6">
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:3-1:6" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span></code></pre>
- <copy-code></copy-code>
- </div>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p></p><pre class="content-editor-code-block undefined code highlight"><code> foo</code></pre></li></ul>
-02_01_00__preliminaries__tabs__008:
- canonical: |
- <pre><code>foo
- bar
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-2:4" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span>
- <span id="LC2" class="line" lang="plaintext">bar</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>foo
- bar</code></pre>
-02_01_00__preliminaries__tabs__009:
- canonical: |
- <ul>
- <li>foo
- <ul>
- <li>bar
- <ul>
- <li>baz</li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:2-3:7" dir="auto">
- <li data-sourcepos="1:2-3:7">foo
- <ul data-sourcepos="2:4-3:7">
- <li data-sourcepos="2:4-3:7">bar
- <ul data-sourcepos="3:3-3:7">
- <li data-sourcepos="3:3-3:7">baz</li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p><ul bullet="*"><li><p>bar</p><ul bullet="*"><li><p>baz</p></li></ul></li></ul></li></ul>
-02_01_00__preliminaries__tabs__010:
- canonical: |
- <h1>Foo</h1>
- static: |-
- <h1 data-sourcepos="1:1-1:5" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h1>
- wysiwyg: |-
- <h1>Foo</h1>
-02_01_00__preliminaries__tabs__011:
- canonical: |
- <hr />
- static: |-
- <hr data-sourcepos="1:1-1:6">
- wysiwyg: |-
- <hr>
-03_01_00__blocks_and_inlines__precedence__001:
- canonical: |
- <ul>
- <li>`one</li>
- <li>two`</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-2:6" dir="auto">
- <li data-sourcepos="1:1-1:6">`one</li>
- <li data-sourcepos="2:1-2:6">two`</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>`one</p></li><li><p>two`</p></li></ul>
-04_01_00__leaf_blocks__thematic_breaks__001:
- canonical: |
- <hr />
- <hr />
- <hr />
- static: |-
- <hr data-sourcepos="1:1-1:3">
- <hr data-sourcepos="2:1-2:3">
- <hr data-sourcepos="3:1-3:3">
- wysiwyg: |-
- <hr>
- <hr>
- <hr>
-04_01_00__leaf_blocks__thematic_breaks__002:
- canonical: |
- <p>+++</p>
- static: |-
- <p data-sourcepos="1:1-1:3" dir="auto">+++</p>
- wysiwyg: |-
- <p>+++</p>
-04_01_00__leaf_blocks__thematic_breaks__003:
- canonical: |
- <p>===</p>
- static: |-
- <p data-sourcepos="1:1-1:3" dir="auto">===</p>
- wysiwyg: |-
- <p>===</p>
-04_01_00__leaf_blocks__thematic_breaks__004:
- canonical: |
- <p>--
- **
- __</p>
- static: |-
- <p data-sourcepos="1:1-3:2" dir="auto">--
- **
- __</p>
- wysiwyg: |-
- <p>--
- **
- __</p>
-04_01_00__leaf_blocks__thematic_breaks__005:
- canonical: |
- <hr />
- <hr />
- <hr />
- static: |-
- <hr data-sourcepos="1:2-1:4">
- <hr data-sourcepos="2:3-2:5">
- <hr data-sourcepos="3:4-3:6">
- wysiwyg: |-
- <hr>
- <hr>
- <hr>
-04_01_00__leaf_blocks__thematic_breaks__006:
- canonical: |
- <pre><code>***
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-1:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">***</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>***</code></pre>
-04_01_00__leaf_blocks__thematic_breaks__007:
- canonical: |
- <p>Foo
- ***</p>
- static: |-
- <p data-sourcepos="1:1-2:7" dir="auto">Foo
- ***</p>
- wysiwyg: |-
- <p>Foo
- ***</p>
-04_01_00__leaf_blocks__thematic_breaks__008:
- canonical: |
- <hr />
- static: |-
- <hr data-sourcepos="1:1-1:37">
- wysiwyg: |-
- <hr>
-04_01_00__leaf_blocks__thematic_breaks__009:
- canonical: |
- <hr />
- static: |-
- <hr data-sourcepos="1:2-1:6">
- wysiwyg: |-
- <hr>
-04_01_00__leaf_blocks__thematic_breaks__010:
- canonical: |
- <hr />
- static: |-
- <hr data-sourcepos="1:2-1:19">
- wysiwyg: |-
- <hr>
-04_01_00__leaf_blocks__thematic_breaks__011:
- canonical: |
- <hr />
- static: |-
- <hr data-sourcepos="1:1-1:21">
- wysiwyg: |-
- <hr>
-04_01_00__leaf_blocks__thematic_breaks__012:
- canonical: |
- <hr />
- static: |-
- <hr data-sourcepos="1:1-1:11">
- wysiwyg: |-
- <hr>
-04_01_00__leaf_blocks__thematic_breaks__013:
- canonical: |
- <p>_ _ _ _ a</p>
- <p>a------</p>
- <p>---a---</p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto">_ _ _ _ a</p>
- <p data-sourcepos="3:1-3:7" dir="auto">a------</p>
- <p data-sourcepos="5:1-5:7" dir="auto">---a---</p>
- wysiwyg: |-
- <p>_ _ _ _ a</p>
- <p>a------</p>
- <p>---a---</p>
-04_01_00__leaf_blocks__thematic_breaks__014:
- canonical: |
- <p><em>-</em></p>
- static: |-
- <p data-sourcepos="1:2-1:4" dir="auto"><em>-</em></p>
- wysiwyg: |-
- <p><em>-</em></p>
-04_01_00__leaf_blocks__thematic_breaks__015:
- canonical: |
- <ul>
- <li>foo</li>
- </ul>
- <hr />
- <ul>
- <li>bar</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-1:5" dir="auto">
- <li data-sourcepos="1:1-1:5">foo</li>
- </ul>
- <hr data-sourcepos="2:1-2:3">
- <ul data-sourcepos="3:1-3:5" dir="auto">
- <li data-sourcepos="3:1-3:5">bar</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p></li></ul>
- <hr>
- <ul bullet="*"><li><p>bar</p></li></ul>
-04_01_00__leaf_blocks__thematic_breaks__016:
- canonical: |
- <p>Foo</p>
- <hr />
- <p>bar</p>
- static: |-
- <p data-sourcepos="1:1-1:3" dir="auto">Foo</p>
- <hr data-sourcepos="2:1-2:3">
- <p data-sourcepos="3:1-3:3" dir="auto">bar</p>
- wysiwyg: |-
- <p>Foo</p>
- <hr>
- <p>bar</p>
-04_01_00__leaf_blocks__thematic_breaks__017:
- canonical: |
- <h2>Foo</h2>
- <p>bar</p>
- static: |-
- <h2 data-sourcepos="1:1-3:3" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h2>
- <p data-sourcepos="3:1-3:3" dir="auto">bar</p>
- wysiwyg: |-
- <h2>Foo</h2>
- <p>bar</p>
-04_01_00__leaf_blocks__thematic_breaks__018:
- canonical: |
- <ul>
- <li>Foo</li>
- </ul>
- <hr />
- <ul>
- <li>Bar</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-1:5" dir="auto">
- <li data-sourcepos="1:1-1:5">Foo</li>
- </ul>
- <hr data-sourcepos="2:1-2:5">
- <ul data-sourcepos="3:1-3:5" dir="auto">
- <li data-sourcepos="3:1-3:5">Bar</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>Foo</p></li></ul>
- <hr>
- <ul bullet="*"><li><p>Bar</p></li></ul>
-04_01_00__leaf_blocks__thematic_breaks__019:
- canonical: |
- <ul>
- <li>Foo</li>
- <li>
- <hr />
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-2:7" dir="auto">
- <li data-sourcepos="1:1-1:5">Foo</li>
- <li data-sourcepos="2:1-2:7">
- <hr data-sourcepos="2:3-2:7">
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>Foo</p></li><li><p></p><hr></li></ul>
-04_02_00__leaf_blocks__atx_headings__001:
- canonical: |
- <h1>foo</h1>
- <h2>foo</h2>
- <h3>foo</h3>
- <h4>foo</h4>
- <h5>foo</h5>
- <h6>foo</h6>
- static: |-
- <h1 data-sourcepos="1:1-1:5" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h1>
- <h2 data-sourcepos="2:1-2:6" dir="auto">
- <a id="user-content-foo-1" class="anchor" href="#foo-1" aria-hidden="true"></a>foo</h2>
- <h3 data-sourcepos="3:1-3:7" dir="auto">
- <a id="user-content-foo-2" class="anchor" href="#foo-2" aria-hidden="true"></a>foo</h3>
- <h4 data-sourcepos="4:1-4:8" dir="auto">
- <a id="user-content-foo-3" class="anchor" href="#foo-3" aria-hidden="true"></a>foo</h4>
- <h5 data-sourcepos="5:1-5:9" dir="auto">
- <a id="user-content-foo-4" class="anchor" href="#foo-4" aria-hidden="true"></a>foo</h5>
- <h6 data-sourcepos="6:1-6:10" dir="auto">
- <a id="user-content-foo-5" class="anchor" href="#foo-5" aria-hidden="true"></a>foo</h6>
- wysiwyg: |-
- <h1>foo</h1>
- <h2>foo</h2>
- <h3>foo</h3>
- <h4>foo</h4>
- <h5>foo</h5>
- <h6>foo</h6>
-04_02_00__leaf_blocks__atx_headings__002:
- canonical: |
- <p>####### foo</p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto">####### foo</p>
- wysiwyg: |-
- <p>####### foo</p>
-04_02_00__leaf_blocks__atx_headings__003:
- canonical: |
- <p>#5 bolt</p>
- <p>#hashtag</p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto">#5 bolt</p>
- <p data-sourcepos="3:1-3:8" dir="auto">#hashtag</p>
- wysiwyg: |-
- <p>#5 bolt</p>
- <p>#hashtag</p>
-04_02_00__leaf_blocks__atx_headings__004:
- canonical: |
- <p>## foo</p>
- static: |-
- <p data-sourcepos="1:1-1:27" dir="auto"><span>#</span># foo</p>
- wysiwyg: |-
- <p>## foo</p>
-04_02_00__leaf_blocks__atx_headings__005:
- canonical: |
- <h1>foo <em>bar</em> *baz*</h1>
- static: |-
- <h1 data-sourcepos="1:1-1:19" dir="auto">
- <a id="user-content-foo-bar-baz" class="anchor" href="#foo-bar-baz" aria-hidden="true"></a>foo <em>bar</em> *baz*</h1>
- wysiwyg: |-
- <h1>foo <em>bar</em> *baz*</h1>
-04_02_00__leaf_blocks__atx_headings__006:
- canonical: |
- <h1>foo</h1>
- static: |-
- <h1 data-sourcepos="1:1-1:22" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h1>
- wysiwyg: |-
- <h1>foo</h1>
-04_02_00__leaf_blocks__atx_headings__007:
- canonical: |
- <h3>foo</h3>
- <h2>foo</h2>
- <h1>foo</h1>
- static: |-
- <h3 data-sourcepos="1:2-1:8" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h3>
- <h2 data-sourcepos="2:3-2:8" dir="auto">
- <a id="user-content-foo-1" class="anchor" href="#foo-1" aria-hidden="true"></a>foo</h2>
- <h1 data-sourcepos="3:4-3:8" dir="auto">
- <a id="user-content-foo-2" class="anchor" href="#foo-2" aria-hidden="true"></a>foo</h1>
- wysiwyg: |-
- <h3>foo</h3>
- <h2>foo</h2>
- <h1>foo</h1>
-04_02_00__leaf_blocks__atx_headings__008:
- canonical: |
- <pre><code># foo
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-1:9" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># foo</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code># foo</code></pre>
-04_02_00__leaf_blocks__atx_headings__009:
- canonical: |
- <p>foo
- # bar</p>
- static: |-
- <p data-sourcepos="1:1-2:9" dir="auto">foo
- # bar</p>
- wysiwyg: |-
- <p>foo
- # bar</p>
-04_02_00__leaf_blocks__atx_headings__010:
- canonical: |
- <h2>foo</h2>
- <h3>bar</h3>
- static: |-
- <h2 data-sourcepos="1:1-1:6" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h2>
- <h3 data-sourcepos="2:3-2:11" dir="auto">
- <a id="user-content-bar" class="anchor" href="#bar" aria-hidden="true"></a>bar</h3>
- wysiwyg: |-
- <h2>foo</h2>
- <h3>bar</h3>
-04_02_00__leaf_blocks__atx_headings__011:
- canonical: |
- <h1>foo</h1>
- <h5>foo</h5>
- static: |-
- <h1 data-sourcepos="1:1-1:5" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h1>
- <h5 data-sourcepos="2:1-2:9" dir="auto">
- <a id="user-content-foo-1" class="anchor" href="#foo-1" aria-hidden="true"></a>foo</h5>
- wysiwyg: |-
- <h1>foo</h1>
- <h5>foo</h5>
-04_02_00__leaf_blocks__atx_headings__012:
- canonical: |
- <h3>foo</h3>
- static: |-
- <h3 data-sourcepos="1:1-1:7" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h3>
- wysiwyg: |-
- <h3>foo</h3>
-04_02_00__leaf_blocks__atx_headings__013:
- canonical: |
- <h3>foo ### b</h3>
- static: |-
- <h3 data-sourcepos="1:1-1:13" dir="auto">
- <a id="user-content-foo-b" class="anchor" href="#foo-b" aria-hidden="true"></a>foo ### b</h3>
- wysiwyg: |-
- <h3>foo ### b</h3>
-04_02_00__leaf_blocks__atx_headings__014:
- canonical: |
- <h1>foo#</h1>
- static: |-
- <h1 data-sourcepos="1:1-1:6" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo#</h1>
- wysiwyg: |-
- <h1>foo#</h1>
-04_02_00__leaf_blocks__atx_headings__015:
- canonical: |
- <h3>foo ###</h3>
- <h2>foo ###</h2>
- <h1>foo #</h1>
- static: |-
- <h3 data-sourcepos="1:1-1:32" dir="auto">
- <a id="user-content-foo-" class="anchor" href="#foo-" aria-hidden="true"></a>foo <span>#</span>##</h3>
- <h2 data-sourcepos="2:1-2:31" dir="auto">
- <a id="user-content-foo--1" class="anchor" href="#foo--1" aria-hidden="true"></a>foo #<span>#</span>#</h2>
- <h1 data-sourcepos="3:1-3:28" dir="auto">
- <a id="user-content-foo--2" class="anchor" href="#foo--2" aria-hidden="true"></a>foo <span>#</span>
- </h1>
- wysiwyg: |-
- <h3>foo ###</h3>
- <h2>foo ###</h2>
- <h1>foo #</h1>
-04_02_00__leaf_blocks__atx_headings__016:
- canonical: |
- <hr />
- <h2>foo</h2>
- <hr />
- static: |-
- <hr data-sourcepos="1:1-1:4">
- <h2 data-sourcepos="2:1-2:6" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h2>
- <hr data-sourcepos="3:1-3:4">
- wysiwyg: |-
- <hr>
- <h2>foo</h2>
- <hr>
-04_02_00__leaf_blocks__atx_headings__017:
- canonical: |
- <p>Foo bar</p>
- <h1>baz</h1>
- <p>Bar foo</p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto">Foo bar</p>
- <h1 data-sourcepos="2:1-2:5" dir="auto">
- <a id="user-content-baz" class="anchor" href="#baz" aria-hidden="true"></a>baz</h1>
- <p data-sourcepos="3:1-3:7" dir="auto">Bar foo</p>
- wysiwyg: |-
- <p>Foo bar</p>
- <h1>baz</h1>
- <p>Bar foo</p>
-04_02_00__leaf_blocks__atx_headings__018:
- canonical: |
- <h2></h2>
- <h1></h1>
- <h3></h3>
- static: |-
- <h2 data-sourcepos="1:1-1:3" dir="auto"></h2>
- <h1 data-sourcepos="2:1-2:1" dir="auto"></h1>
- <h3 data-sourcepos="3:1-3:3" dir="auto"></h3>
- wysiwyg: |-
- <h2></h2>
- <h1></h1>
- <h3></h3>
-04_03_00__leaf_blocks__setext_headings__001:
- canonical: |
- <h1>Foo <em>bar</em></h1>
- <h2>Foo <em>bar</em></h2>
- static: |-
- <h1 data-sourcepos="1:1-3:0" dir="auto">
- <a id="user-content-foo-bar" class="anchor" href="#foo-bar" aria-hidden="true"></a>Foo <em>bar</em>
- </h1>
- <h2 data-sourcepos="4:1-5:9" dir="auto">
- <a id="user-content-foo-bar-1" class="anchor" href="#foo-bar-1" aria-hidden="true"></a>Foo <em>bar</em>
- </h2>
- wysiwyg: |-
- <h1>Foo <em>bar</em></h1>
- <h2>Foo <em>bar</em></h2>
-04_03_00__leaf_blocks__setext_headings__002:
- canonical: |
- <h1>Foo <em>bar
- baz</em></h1>
- static: |-
- <h1 data-sourcepos="1:1-3:4" dir="auto">
- <a id="user-content-foo-barbaz" class="anchor" href="#foo-barbaz" aria-hidden="true"></a>Foo <em>bar
- baz</em>
- </h1>
- wysiwyg: |-
- <h1>Foo <em>bar
- baz</em></h1>
-04_03_00__leaf_blocks__setext_headings__003:
- canonical: |
- <h1>Foo <em>bar
- baz</em></h1>
- static: |-
- <h1 data-sourcepos="1:3-3:4" dir="auto">
- <a id="user-content-foo-barbaz" class="anchor" href="#foo-barbaz" aria-hidden="true"></a>Foo <em>bar
- baz</em>
- </h1>
- wysiwyg: |-
- <h1>Foo <em>bar
- baz</em></h1>
-04_03_00__leaf_blocks__setext_headings__004:
- canonical: |
- <h2>Foo</h2>
- <h1>Foo</h1>
- static: |-
- <h2 data-sourcepos="1:1-3:0" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h2>
- <h1 data-sourcepos="4:1-5:1" dir="auto">
- <a id="user-content-foo-1" class="anchor" href="#foo-1" aria-hidden="true"></a>Foo</h1>
- wysiwyg: |-
- <h2>Foo</h2>
- <h1>Foo</h1>
-04_03_00__leaf_blocks__setext_headings__005:
- canonical: |
- <h2>Foo</h2>
- <h2>Foo</h2>
- <h1>Foo</h1>
- static: |-
- <h2 data-sourcepos="1:4-3:0" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h2>
- <h2 data-sourcepos="4:3-6:0" dir="auto">
- <a id="user-content-foo-1" class="anchor" href="#foo-1" aria-hidden="true"></a>Foo</h2>
- <h1 data-sourcepos="7:3-8:5" dir="auto">
- <a id="user-content-foo-2" class="anchor" href="#foo-2" aria-hidden="true"></a>Foo</h1>
- wysiwyg: |-
- <h2>Foo</h2>
- <h2>Foo</h2>
- <h1>Foo</h1>
-04_03_00__leaf_blocks__setext_headings__006:
- canonical: |
- <pre><code>Foo
- ---
-
- Foo
- </code></pre>
- <hr />
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-4:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
- <span id="LC2" class="line" lang="plaintext">---</span>
- <span id="LC3" class="line" lang="plaintext"></span>
- <span id="LC4" class="line" lang="plaintext">Foo</span></code></pre>
- <copy-code></copy-code>
- </div>
- <hr data-sourcepos="5:1-5:3">
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>Foo
- ---
-
- Foo</code></pre>
- <hr>
-04_03_00__leaf_blocks__setext_headings__007:
- canonical: |
- <h2>Foo</h2>
- static: |-
- <h2 data-sourcepos="1:1-2:13" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h2>
- wysiwyg: |-
- <h2>Foo</h2>
-04_03_00__leaf_blocks__setext_headings__008:
- canonical: |
- <p>Foo
- ---</p>
- static: |-
- <p data-sourcepos="1:1-2:7" dir="auto">Foo
- ---</p>
- wysiwyg: |-
- <p>Foo
- ---</p>
-04_03_00__leaf_blocks__setext_headings__009:
- canonical: |
- <p>Foo
- = =</p>
- <p>Foo</p>
- <hr />
- static: |-
- <p data-sourcepos="1:1-2:3" dir="auto">Foo
- = =</p>
- <p data-sourcepos="4:1-4:3" dir="auto">Foo</p>
- <hr data-sourcepos="5:1-5:5">
- wysiwyg: |-
- <p>Foo
- = =</p>
- <p>Foo</p>
- <hr>
-04_03_00__leaf_blocks__setext_headings__010:
- canonical: |
- <h2>Foo</h2>
- static: |-
- <h2 data-sourcepos="1:1-2:5" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h2>
- wysiwyg: |-
- <h2>Foo</h2>
-04_03_00__leaf_blocks__setext_headings__011:
- canonical: |
- <h2>Foo\</h2>
- static: |-
- <h2 data-sourcepos="1:1-2:4" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo\</h2>
- wysiwyg: |-
- <h2>Foo\</h2>
-04_03_00__leaf_blocks__setext_headings__012:
- canonical: |
- <h2>`Foo</h2>
- <p>`</p>
- <h2>&lt;a title=&quot;a lot</h2>
- <p>of dashes&quot;/&gt;</p>
- static: |-
- <h2 data-sourcepos="1:1-3:1" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>`Foo</h2>
- <p data-sourcepos="3:1-3:1" dir="auto">`</p>
- <h2 data-sourcepos="5:1-7:12" dir="auto">
- <a id="user-content-a-titlea-lot" class="anchor" href="#a-titlea-lot" aria-hidden="true"></a>&lt;a title="a lot</h2>
- <p data-sourcepos="7:1-7:12" dir="auto">of dashes"/&gt;</p>
- wysiwyg: |-
- <h2>`Foo</h2>
- <p>`</p>
- <h2>&lt;a title="a lot</h2>
- <p>of dashes"/&gt;</p>
-04_03_00__leaf_blocks__setext_headings__013:
- canonical: |
- <blockquote>
- <p>Foo</p>
- </blockquote>
- <hr />
- static: |-
- <blockquote data-sourcepos="1:1-1:5" dir="auto">
- <p data-sourcepos="1:3-1:5">Foo</p>
- </blockquote>
- <hr data-sourcepos="2:1-2:3">
- wysiwyg: |-
- <blockquote multiline="false"><p>Foo</p></blockquote>
- <hr>
-04_03_00__leaf_blocks__setext_headings__014:
- canonical: |
- <blockquote>
- <p>foo
- bar
- ===</p>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-3:3" dir="auto">
- <p data-sourcepos="1:3-3:3">foo
- bar
- ===</p>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><p>foo
- bar
- ===</p></blockquote>
-04_03_00__leaf_blocks__setext_headings__015:
- canonical: |
- <ul>
- <li>Foo</li>
- </ul>
- <hr />
- static: |-
- <ul data-sourcepos="1:1-1:5" dir="auto">
- <li data-sourcepos="1:1-1:5">Foo</li>
- </ul>
- <hr data-sourcepos="2:1-2:3">
- wysiwyg: |-
- <ul bullet="*"><li><p>Foo</p></li></ul>
- <hr>
-04_03_00__leaf_blocks__setext_headings__016:
- canonical: |
- <h2>Foo
- Bar</h2>
- static: |-
- <h2 data-sourcepos="1:1-3:3" dir="auto">
- <a id="user-content-foobar" class="anchor" href="#foobar" aria-hidden="true"></a>Foo
- Bar</h2>
- wysiwyg: |-
- <h2>Foo
- Bar</h2>
-04_03_00__leaf_blocks__setext_headings__017:
- canonical: |
- <hr />
- <h2>Foo</h2>
- <h2>Bar</h2>
- <p>Baz</p>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-yaml" lang="yaml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="yaml"><span class="s">Foo</span></span></code></pre>
- <copy-code></copy-code>
- </div>
- <h2 data-sourcepos="4:1-6:3" dir="auto">
- <a id="user-content-bar" class="anchor" href="#bar" aria-hidden="true"></a>Bar</h2>
- <p data-sourcepos="6:1-6:3" dir="auto">Baz</p>
- wysiwyg: |-
- <pre language="yaml" class="content-editor-code-block undefined code highlight" isfrontmatter="true"><code>Foo</code></pre>
- <h2>Bar</h2>
- <p>Baz</p>
-04_03_00__leaf_blocks__setext_headings__018:
- canonical: |
- <p>====</p>
- static: |-
- <p data-sourcepos="2:1-2:4" dir="auto">====</p>
- wysiwyg: |-
- <p>====</p>
-04_03_00__leaf_blocks__setext_headings__019:
- canonical: |
- <hr />
- <hr />
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-2:3" class="code highlight js-syntax-highlight language-yaml" lang="yaml" data-lang-params="frontmatter" v-pre="true"><code></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre language="yaml" class="content-editor-code-block undefined code highlight" isfrontmatter="true"><code></code></pre>
-04_03_00__leaf_blocks__setext_headings__020:
- canonical: |
- <ul>
- <li>foo</li>
- </ul>
- <hr />
- static: |-
- <ul data-sourcepos="1:1-1:5" dir="auto">
- <li data-sourcepos="1:1-1:5">foo</li>
- </ul>
- <hr data-sourcepos="2:1-2:5">
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p></li></ul>
- <hr>
-04_03_00__leaf_blocks__setext_headings__021:
- canonical: |
- <pre><code>foo
- </code></pre>
- <hr />
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-1:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
- <copy-code></copy-code>
- </div>
- <hr data-sourcepos="2:1-2:3">
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
- <hr>
-04_03_00__leaf_blocks__setext_headings__022:
- canonical: |
- <blockquote>
- <p>foo</p>
- </blockquote>
- <hr />
- static: |-
- <blockquote data-sourcepos="1:1-1:5" dir="auto">
- <p data-sourcepos="1:3-1:5">foo</p>
- </blockquote>
- <hr data-sourcepos="2:1-2:5">
- wysiwyg: |-
- <blockquote multiline="false"><p>foo</p></blockquote>
- <hr>
-04_03_00__leaf_blocks__setext_headings__023:
- canonical: |
- <h2>&gt; foo</h2>
- static: |-
- <h2 data-sourcepos="1:1-2:6" dir="auto">
- <a id="user-content--foo" class="anchor" href="#-foo" aria-hidden="true"></a>&gt; foo</h2>
- wysiwyg: |-
- <h2>&gt; foo</h2>
-04_03_00__leaf_blocks__setext_headings__024:
- canonical: |
- <p>Foo</p>
- <h2>bar</h2>
- <p>baz</p>
- static: |-
- <p data-sourcepos="1:1-1:3" dir="auto">Foo</p>
- <h2 data-sourcepos="3:1-5:3" dir="auto">
- <a id="user-content-bar" class="anchor" href="#bar" aria-hidden="true"></a>bar</h2>
- <p data-sourcepos="5:1-5:3" dir="auto">baz</p>
- wysiwyg: |-
- <p>Foo</p>
- <h2>bar</h2>
- <p>baz</p>
-04_03_00__leaf_blocks__setext_headings__025:
- canonical: |
- <p>Foo
- bar</p>
- <hr />
- <p>baz</p>
- static: |-
- <p data-sourcepos="1:1-2:3" dir="auto">Foo
- bar</p>
- <hr data-sourcepos="4:1-5:0">
- <p data-sourcepos="6:1-6:3" dir="auto">baz</p>
- wysiwyg: |-
- <p>Foo
- bar</p>
- <hr>
- <p>baz</p>
-04_03_00__leaf_blocks__setext_headings__026:
- canonical: |
- <p>Foo
- bar</p>
- <hr />
- <p>baz</p>
- static: |-
- <p data-sourcepos="1:1-2:3" dir="auto">Foo
- bar</p>
- <hr data-sourcepos="3:1-3:5">
- <p data-sourcepos="4:1-4:3" dir="auto">baz</p>
- wysiwyg: |-
- <p>Foo
- bar</p>
- <hr>
- <p>baz</p>
-04_03_00__leaf_blocks__setext_headings__027:
- canonical: |
- <p>Foo
- bar
- ---
- baz</p>
- static: |-
- <p data-sourcepos="1:1-4:3" dir="auto">Foo
- bar
- ---
- baz</p>
- wysiwyg: |-
- <p>Foo
- bar
- ---
- baz</p>
-04_04_00__leaf_blocks__indented_code_blocks__001:
- canonical: |
- <pre><code>a simple
- indented code block
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-2:25" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">a simple</span>
- <span id="LC2" class="line" lang="plaintext"> indented code block</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>a simple
- indented code block</code></pre>
-04_04_00__leaf_blocks__indented_code_blocks__002:
- canonical: |
- <ul>
- <li>
- <p>foo</p>
- <p>bar</p>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:3-3:7" dir="auto">
- <li data-sourcepos="1:3-3:7">
- <p data-sourcepos="1:5-1:7">foo</p>
- <p data-sourcepos="3:5-3:7">bar</p>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p><p>bar</p></li></ul>
-04_04_00__leaf_blocks__indented_code_blocks__003:
- canonical: |
- <ol>
- <li>
- <p>foo</p>
- <ul>
- <li>bar</li>
- </ul>
- </li>
- </ol>
- static: |-
- <ol data-sourcepos="1:1-3:9" dir="auto">
- <li data-sourcepos="1:1-3:9">
- <p data-sourcepos="1:5-1:7">foo</p>
- <ul data-sourcepos="3:5-3:9">
- <li data-sourcepos="3:5-3:9">bar</li>
- </ul>
- </li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>foo</p><ul bullet="*"><li><p>bar</p></li></ul></li></ol>
-04_04_00__leaf_blocks__indented_code_blocks__004:
- canonical: |
- <pre><code>&lt;a/&gt;
- *hi*
-
- - one
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-4:9" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a/&gt;</span>
- <span id="LC2" class="line" lang="plaintext">*hi*</span>
- <span id="LC3" class="line" lang="plaintext"></span>
- <span id="LC4" class="line" lang="plaintext">- one</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>&lt;a/&gt;
- *hi*
-
- - one</code></pre>
-04_04_00__leaf_blocks__indented_code_blocks__005:
- canonical: |
- <pre><code>chunk1
-
- chunk2
-
-
-
- chunk3
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-7:10" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">chunk1</span>
- <span id="LC2" class="line" lang="plaintext"></span>
- <span id="LC3" class="line" lang="plaintext">chunk2</span>
- <span id="LC4" class="line" lang="plaintext"></span>
- <span id="LC5" class="line" lang="plaintext"></span>
- <span id="LC6" class="line" lang="plaintext"></span>
- <span id="LC7" class="line" lang="plaintext">chunk3</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>chunk1
-
- chunk2
-
-
-
- chunk3</code></pre>
-04_04_00__leaf_blocks__indented_code_blocks__006:
- canonical: "<pre><code>chunk1\n \n chunk2\n</code></pre>\n"
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-3:12" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">chunk1</span>
- <span id="LC2" class="line" lang="plaintext"> </span>
- <span id="LC3" class="line" lang="plaintext"> chunk2</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: "<pre class=\"content-editor-code-block undefined code highlight\"><code>chunk1\n
- \ \n chunk2</code></pre>"
-04_04_00__leaf_blocks__indented_code_blocks__007:
- canonical: |
- <p>Foo
- bar</p>
- static: |-
- <p data-sourcepos="1:1-2:7" dir="auto">Foo
- bar</p>
- wysiwyg: |-
- <p>Foo
- bar</p>
-04_04_00__leaf_blocks__indented_code_blocks__008:
- canonical: |
- <pre><code>foo
- </code></pre>
- <p>bar</p>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-1:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
- <copy-code></copy-code>
- </div>
- <p data-sourcepos="2:1-2:3" dir="auto">bar</p>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
- <p>bar</p>
-04_04_00__leaf_blocks__indented_code_blocks__009:
- canonical: |
- <h1>Heading</h1>
- <pre><code>foo
- </code></pre>
- <h2>Heading</h2>
- <pre><code>foo
- </code></pre>
- <hr />
- static: |-
- <h1 data-sourcepos="1:1-1:9" dir="auto">
- <a id="user-content-heading" class="anchor" href="#heading" aria-hidden="true"></a>Heading</h1>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="2:5-2:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
- <copy-code></copy-code>
- </div>
- <h2 data-sourcepos="3:1-5:7" dir="auto">
- <a id="user-content-heading-1" class="anchor" href="#heading-1" aria-hidden="true"></a>Heading</h2>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="5:5-5:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
- <copy-code></copy-code>
- </div>
- <hr data-sourcepos="6:1-6:4">
- wysiwyg: |-
- <h1>Heading</h1>
- <pre class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
- <h2>Heading</h2>
- <pre class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
- <hr>
-04_04_00__leaf_blocks__indented_code_blocks__010:
- canonical: |
- <pre><code> foo
- bar
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-2:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span>
- <span id="LC2" class="line" lang="plaintext">bar</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code> foo
- bar</code></pre>
-04_04_00__leaf_blocks__indented_code_blocks__011:
- canonical: |
- <pre><code>foo
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="3:5-5:0" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
-04_04_00__leaf_blocks__indented_code_blocks__012:
- canonical: "<pre><code>foo \n</code></pre>\n"
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-1:9" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo </span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>foo </code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__001:
- canonical: |
- <pre><code>&lt;
- &gt;
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-4:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;</span>
- <span id="LC2" class="line" lang="plaintext"> &gt;</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>&lt;
- &gt;</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__002:
- canonical: |
- <pre><code>&lt;
- &gt;
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-4:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;</span>
- <span id="LC2" class="line" lang="plaintext"> &gt;</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>&lt;
- &gt;</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__003:
- canonical: |
- <p><code>foo</code></p>
- static: |-
- <p data-sourcepos="1:1-3:2" dir="auto"><code>foo</code></p>
- wysiwyg: |-
- <p><code>foo</code></p>
-04_05_00__leaf_blocks__fenced_code_blocks__004:
- canonical: |
- <pre><code>aaa
- ~~~
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-4:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
- <span id="LC2" class="line" lang="plaintext">~~~</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>aaa
- ~~~</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__005:
- canonical: |
- <pre><code>aaa
- ```
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-4:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
- <span id="LC2" class="line" lang="plaintext">```</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>aaa
- ```</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__006:
- canonical: |
- <pre><code>aaa
- ```
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-4:6" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
- <span id="LC2" class="line" lang="plaintext">```</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>aaa
- ```</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__007:
- canonical: |
- <pre><code>aaa
- ~~~
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-4:4" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
- <span id="LC2" class="line" lang="plaintext">~~~</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>aaa
- ~~~</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__008:
- canonical: |
- <pre><code></code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-1:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code></code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__009:
- canonical: |
- <pre><code>
- ```
- aaa
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-4:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"></span>
- <span id="LC2" class="line" lang="plaintext">```</span>
- <span id="LC3" class="line" lang="plaintext">aaa</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>
- ```
- aaa</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__010:
- canonical: |
- <blockquote>
- <pre><code>aaa
- </code></pre>
- </blockquote>
- <p>bbb</p>
- static: |-
- <blockquote data-sourcepos="1:1-2:5" dir="auto">
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:3-3:0" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span></code></pre>
- <copy-code></copy-code>
- </div>
- </blockquote>
- <p data-sourcepos="4:1-4:3" dir="auto">bbb</p>
- wysiwyg: |-
- <blockquote multiline="false"><pre class="content-editor-code-block undefined code highlight"><code>aaa</code></pre></blockquote>
- <p>bbb</p>
-04_05_00__leaf_blocks__fenced_code_blocks__011:
- canonical: "<pre><code>\n \n</code></pre>\n"
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-4:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"></span>
- <span id="LC2" class="line" lang="plaintext"> </span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code></code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__012:
- canonical: |
- <pre><code></code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-2:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code></code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__013:
- canonical: |
- <pre><code>aaa
- aaa
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:2-4:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
- <span id="LC2" class="line" lang="plaintext">aaa</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>aaa
- aaa</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__014:
- canonical: |
- <pre><code>aaa
- aaa
- aaa
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:3-5:5" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
- <span id="LC2" class="line" lang="plaintext">aaa</span>
- <span id="LC3" class="line" lang="plaintext">aaa</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>aaa
- aaa
- aaa</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__015:
- canonical: |
- <pre><code>aaa
- aaa
- aaa
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:4-5:6" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
- <span id="LC2" class="line" lang="plaintext"> aaa</span>
- <span id="LC3" class="line" lang="plaintext">aaa</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>aaa
- aaa
- aaa</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__016:
- canonical: |
- <pre><code>```
- aaa
- ```
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-3:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
- <span id="LC2" class="line" lang="plaintext">aaa</span>
- <span id="LC3" class="line" lang="plaintext">```</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>```
- aaa
- ```</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__017:
- canonical: |
- <pre><code>aaa
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:5" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>aaa</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__018:
- canonical: |
- <pre><code>aaa
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:4-3:5" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>aaa</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__019:
- canonical: |
- <pre><code>aaa
- ```
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
- <span id="LC2" class="line" lang="plaintext"> ```</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>aaa
- ```</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__020:
- canonical: |
- <p><code> </code>
- aaa</p>
- static: |-
- <p data-sourcepos="1:1-2:3" dir="auto"><code> </code>
- aaa</p>
- wysiwyg: |-
- <p>
- aaa</p>
-04_05_00__leaf_blocks__fenced_code_blocks__021:
- canonical: |
- <pre><code>aaa
- ~~~ ~~
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:6" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
- <span id="LC2" class="line" lang="plaintext">~~~ ~~</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>aaa
- ~~~ ~~</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__022:
- canonical: |
- <p>foo</p>
- <pre><code>bar
- </code></pre>
- <p>baz</p>
- static: |-
- <p data-sourcepos="1:1-1:3" dir="auto">foo</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="2:1-4:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span></code></pre>
- <copy-code></copy-code>
- </div>
- <p data-sourcepos="5:1-5:3" dir="auto">baz</p>
- wysiwyg: |-
- <p>foo</p>
- <pre class="content-editor-code-block undefined code highlight"><code>bar</code></pre>
- <p>baz</p>
-04_05_00__leaf_blocks__fenced_code_blocks__023:
- canonical: |
- <h2>foo</h2>
- <pre><code>bar
- </code></pre>
- <h1>baz</h1>
- static: |-
- <h2 data-sourcepos="1:1-3:3" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h2>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="3:1-5:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span></code></pre>
- <copy-code></copy-code>
- </div>
- <h1 data-sourcepos="6:1-6:5" dir="auto">
- <a id="user-content-baz" class="anchor" href="#baz" aria-hidden="true"></a>baz</h1>
- wysiwyg: |-
- <h2>foo</h2>
- <pre class="content-editor-code-block undefined code highlight"><code>bar</code></pre>
- <h1>baz</h1>
-04_05_00__leaf_blocks__fenced_code_blocks__024:
- canonical: |
- <pre><code class="language-ruby">def foo(x)
- return 3
- end
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-5:3" class="code highlight js-syntax-highlight language-ruby" lang="ruby" v-pre="true"><code><span id="LC1" class="line" lang="ruby"><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">x</span><span class="p">)</span></span>
- <span id="LC2" class="line" lang="ruby"> <span class="k">return</span> <span class="mi">3</span></span>
- <span id="LC3" class="line" lang="ruby"><span class="k">end</span></span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre language="ruby" class="content-editor-code-block undefined code highlight"><code>def foo(x)
- return 3
- end</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__025:
- canonical: |
- <pre><code class="language-ruby">def foo(x)
- return 3
- end
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-5:7" class="code highlight js-syntax-highlight language-ruby" lang="ruby" v-pre="true"><code><span id="LC1" class="line" lang="ruby"><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">x</span><span class="p">)</span></span>
- <span id="LC2" class="line" lang="ruby"> <span class="k">return</span> <span class="mi">3</span></span>
- <span id="LC3" class="line" lang="ruby"><span class="k">end</span></span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre language="ruby" class="content-editor-code-block undefined code highlight"><code>def foo(x)
- return 3
- end</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__026:
- canonical: |
- <pre><code class="language-;"></code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-2:4" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang=";" v-pre="true"><code></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre language=";" class="content-editor-code-block undefined code highlight"><code></code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__027:
- canonical: |
- <p><code>aa</code>
- foo</p>
- static: |-
- <p data-sourcepos="1:1-2:3" dir="auto"><code>aa</code>
- foo</p>
- wysiwyg: |-
- <p><code>aa</code>
- foo</p>
-04_05_00__leaf_blocks__fenced_code_blocks__028:
- canonical: |
- <pre><code class="language-aa">foo
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="aa" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre language="aa" class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
-04_05_00__leaf_blocks__fenced_code_blocks__029:
- canonical: |
- <pre><code>``` aaa
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``` aaa</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>``` aaa</code></pre>
-04_06_00__leaf_blocks__html_blocks__001:
- canonical: |
- <table><tr><td>
- <pre>
- **Hello**,
- <p><em>world</em>.
- </pre></p>
- </td></tr></table>
- static: |-
- <table dir="auto"><tr><td>
- <pre>
- **Hello**,
- <p data-sourcepos="5:1-6:6"><em>world</em>.
- </p></pre>
- </td></tr></table>
- wysiwyg: |-
- <table><tbody><tr><td colspan="1" rowspan="1"><pre><p>**Hello**,
- </p><p><em>world</em>.
- </p></pre><p></p></td></tr></tbody></table>
-04_06_00__leaf_blocks__html_blocks__002:
- canonical: |
- <table>
- <tr>
- <td>
- hi
- </td>
- </tr>
- </table>
- <p>okay.</p>
- static: |-
- <table dir="auto">
- <tr>
- <td>
- hi
- </td>
- </tr>
- </table>
- <p data-sourcepos="9:1-9:5" dir="auto">okay.</p>
- wysiwyg: |-
- <table><tbody><tr><td colspan="1" rowspan="1"><p>
- hi
- </p></td></tr></tbody></table>
- <p>okay.</p>
-04_06_00__leaf_blocks__html_blocks__003:
- canonical: |2
- <div>
- *hello*
- <foo><a>
- static: |2-
- <div>
- *hello*
- <a></a>
- </div>
- wysiwyg: |-
- <div><p>
- *hello*
- </p></div>
-04_06_00__leaf_blocks__html_blocks__004:
- canonical: |
- </div>
- *foo*
- static: |2-
-
- *foo*
- wysiwyg: |-
- <p>
- *foo*</p>
-04_06_00__leaf_blocks__html_blocks__005:
- canonical: |
- <DIV CLASS="foo">
- <p><em>Markdown</em></p>
- </DIV>
- static: |-
- <div>
- <p data-sourcepos="3:1-3:10"><em>Markdown</em></p>
- </div>
- wysiwyg: |-
- <div><p><em>Markdown</em></p></div>
-04_06_00__leaf_blocks__html_blocks__006:
- canonical: |
- <div id="foo"
- class="bar">
- </div>
- static: |-
- <div>
- </div>
- wysiwyg: |-
- <div></div>
-04_06_00__leaf_blocks__html_blocks__007:
- canonical: |
- <div id="foo" class="bar
- baz">
- </div>
- static: |-
- <div>
- </div>
- wysiwyg: |-
- <div></div>
-04_06_00__leaf_blocks__html_blocks__008:
- canonical: |
- <div>
- *foo*
- <p><em>bar</em></p>
- static: |-
- <div>
- *foo*
- <p data-sourcepos="4:1-4:5"><em>bar</em></p>
- </div>
- wysiwyg: |-
- <div><p>
- *foo*
- </p><p><em>bar</em></p></div>
-04_06_00__leaf_blocks__html_blocks__009:
- canonical: |
- <div id="foo"
- *hi*
- static: |-
- <div></div>
- wysiwyg: |-
- <p></p>
-04_06_00__leaf_blocks__html_blocks__010:
- canonical: |
- <div class
- foo
- static: |-
- <div></div>
- wysiwyg: |-
- <p></p>
-04_06_00__leaf_blocks__html_blocks__011:
- canonical: |
- <div *???-&&&-<---
- *foo*
- static: |-
- <div></div>
- wysiwyg: |-
- <p></p>
-04_06_00__leaf_blocks__html_blocks__012:
- canonical: |
- <div><a href="bar">*foo*</a></div>
- static: |-
- <div><a href="bar">*foo*</a></div>
- wysiwyg: |-
- <div><p><a target="_blank" rel="noopener noreferrer nofollow" href="bar">*foo*</a></p></div>
-04_06_00__leaf_blocks__html_blocks__013:
- canonical: |
- <table><tr><td>
- foo
- </td></tr></table>
- static: |-
- <table dir="auto"><tr><td>
- foo
- </td></tr></table>
- wysiwyg: |-
- <table><tbody><tr><td colspan="1" rowspan="1"><p>
- foo
- </p></td></tr></tbody></table>
-04_06_00__leaf_blocks__html_blocks__014:
- canonical: |
- <div></div>
- ``` c
- int x = 33;
- ```
- static: |-
- <div></div>
- ``` c
- int x = 33;
- ```
- wysiwyg: |-
- <div></div>
- <p>
- ``` c
- int x = 33;
- ```</p>
-04_06_00__leaf_blocks__html_blocks__015:
- canonical: |
- <a href="foo">
- *bar*
- </a>
- static: |-
- <a href="foo">
- *bar*
- </a>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="foo">
- *bar*
- </a></p>
-04_06_00__leaf_blocks__html_blocks__016:
- canonical: |
- <Warning>
- *bar*
- </Warning>
- static: |2
-
- *bar*
- wysiwyg: |-
- <p></p>
-04_06_00__leaf_blocks__html_blocks__017:
- canonical: |
- <i class="foo">
- *bar*
- </i>
- static: |-
- <i>
- *bar*
- </i>
- wysiwyg: |-
- <p><em>
- *bar*
- </em></p>
-04_06_00__leaf_blocks__html_blocks__018:
- canonical: |
- </ins>
- *bar*
- static: |2-
-
- *bar*
- wysiwyg: |-
- <p>
- *bar*</p>
-04_06_00__leaf_blocks__html_blocks__019:
- canonical: |
- <del>
- *foo*
- </del>
- static: |-
- <del>
- *foo*
- </del>
- wysiwyg: |-
- <p><s>
- *foo*
- </s></p>
-04_06_00__leaf_blocks__html_blocks__020:
- canonical: |
- <del>
- <p><em>foo</em></p>
- </del>
- static: |-
- <del>
- <p data-sourcepos="3:1-3:5"><em>foo</em></p>
- </del>
- wysiwyg: |-
- <p><em><s>foo</s></em></p>
-04_06_00__leaf_blocks__html_blocks__021:
- canonical: |
- <p><del><em>foo</em></del></p>
- static: |-
- <p data-sourcepos="1:1-1:16" dir="auto"><del><em>foo</em></del></p>
- wysiwyg: |-
- <p><em><s>foo</s></em></p>
-04_06_00__leaf_blocks__html_blocks__022:
- canonical: |
- <pre language="haskell"><code>
- import Text.HTML.TagSoup
-
- main :: IO ()
- main = print $ parseTags tags
- </code></pre>
- <p>okay</p>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"></span>
- <span id="LC2" class="line" lang="plaintext">import Text.HTML.TagSoup</span>
- <span id="LC3" class="line" lang="plaintext"></span>
- <span id="LC4" class="line" lang="plaintext">main :: IO ()</span>
- <span id="LC5" class="line" lang="plaintext">main = print $ parseTags tags</span></code></pre>
- <copy-code></copy-code>
- </div>
- <p data-sourcepos="7:1-7:4" dir="auto">okay</p>
- wysiwyg: |-
- <pre><p><code>
- import Text.HTML.TagSoup
-
- main :: IO ()
- main = print $ parseTags tags
- </code></p></pre>
- <p>okay</p>
-04_06_00__leaf_blocks__html_blocks__023:
- canonical: |
- <script type="text/javascript">
- // JavaScript example
-
- document.getElementById("demo").innerHTML = "Hello JavaScript!";
- </script>
- <p>okay</p>
- static: |2-
-
- <p data-sourcepos="6:1-6:4" dir="auto">okay</p>
- wysiwyg: |-
- <p>okay</p>
-04_06_00__leaf_blocks__html_blocks__024:
- canonical: |
- <style
- type="text/css">
- h1 {color:red;}
-
- p {color:blue;}
- </style>
- <p>okay</p>
- static: |2-
-
- h1 {color:red;}
-
- p {color:blue;}
-
- <p data-sourcepos="7:1-7:4" dir="auto">okay</p>
- wysiwyg: |-
- <p>okay</p>
-04_06_00__leaf_blocks__html_blocks__025:
- canonical: |
- <style
- type="text/css">
-
- foo
- static: |2-
-
-
- foo
- wysiwyg: |-
- <p></p>
-04_06_00__leaf_blocks__html_blocks__026:
- canonical: |
- <blockquote>
- <div>
- foo
- </blockquote>
- <p>bar</p>
- static: |-
- <blockquote data-sourcepos="1:1-2:5" dir="auto">
- <div>
- foo
-
- <p data-sourcepos="4:1-4:3">bar</p>
- </div>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><div><p>
- foo
- </p></div></blockquote>
- <p>bar</p>
-04_06_00__leaf_blocks__html_blocks__027:
- canonical: |
- <ul>
- <li>
- <div>
- </li>
- <li>foo</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-2:5" dir="auto">
- <li data-sourcepos="1:1-1:7">
- <div>
-
- <li data-sourcepos="2:1-2:5">foo</li>
- </div>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p></p><div></div></li><li><p>foo</p></li></ul>
-04_06_00__leaf_blocks__html_blocks__028:
- canonical: |
- <style>p{color:red;}</style>
- <p><em>foo</em></p>
- static: |-
- p{color:red;}
- <p data-sourcepos="2:1-2:5" dir="auto"><em>foo</em></p>
- wysiwyg: |-
- <p><em>foo</em></p>
-04_06_00__leaf_blocks__html_blocks__029:
- canonical: |
- <!-- foo -->*bar*
- <p><em>baz</em></p>
- static: |-
- *bar*
- <p data-sourcepos="2:1-2:5" dir="auto"><em>baz</em></p>
- wysiwyg: |-
- <p>*bar*
- </p>
- <p><em>baz</em></p>
-04_06_00__leaf_blocks__html_blocks__030:
- canonical: |
- <script>
- foo
- </script>1. *bar*
- static: |-
- 1. *bar*
- wysiwyg: |-
- <p>1. *bar*</p>
-04_06_00__leaf_blocks__html_blocks__031:
- canonical: |
- <!-- Foo
-
- bar
- baz -->
- <p>okay</p>
- static: |2-
-
- <p data-sourcepos="5:1-5:4" dir="auto">okay</p>
- wysiwyg: |-
- <p>okay</p>
-04_06_00__leaf_blocks__html_blocks__032:
- canonical: |
- <?php
-
- echo '>';
-
- ?>
- <p>okay</p>
- static: |-
- <?php echo '>';
-
- ?&gt;
- <p data-sourcepos="6:1-6:4" dir="auto">okay</p>
- wysiwyg: |-
- <p>';
-
- ?&gt;
- </p>
- <p>okay</p>
-04_06_00__leaf_blocks__html_blocks__033:
- canonical: |
- <!DOCTYPE html>
- static: ""
- wysiwyg: |-
- <p></p>
-04_06_00__leaf_blocks__html_blocks__034:
- canonical: |
- <![CDATA[
- function matchwo(a,b)
- {
- if (a < b && a < 0) then {
- return 1;
-
- } else {
-
- return 0;
- }
- }
- ]]>
- <p>okay</p>
- static: |-
- &lt;![CDATA[
- function matchwo(a,b)
- {
- if (a &lt; b &amp;&amp; a &lt; 0) then {
- return 1;
-
- } else {
-
- return 0;
- }
- }
- ]]&gt;
- <p data-sourcepos="13:1-13:4" dir="auto">okay</p>
- wysiwyg: |-
- <p>okay</p>
-04_06_00__leaf_blocks__html_blocks__035:
- canonical: |2
- <!-- foo -->
- <pre><code>&lt;!-- foo --&gt;
- </code></pre>
- static: " \n<div class=\"gl-relative markdown-code-block js-markdown-code\">\n<pre
- data-sourcepos=\"3:5-3:16\" class=\"code highlight js-syntax-highlight language-plaintext\"
- lang=\"plaintext\" data-canonical-lang=\"\" v-pre=\"true\"><code><span id=\"LC1\"
- class=\"line\" lang=\"plaintext\">&lt;!-- foo --&gt;</span></code></pre>\n<copy-code></copy-code>\n</div>"
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>&lt;!-- foo --&gt;</code></pre>
-04_06_00__leaf_blocks__html_blocks__036:
- canonical: |2
- <div>
- <pre><code>&lt;div&gt;
- </code></pre>
- static: |2-
- <div>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="3:5-3:9" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;</span></code></pre>
- <copy-code></copy-code>
- </div>
- </div>
- wysiwyg: |-
- <div><pre class="content-editor-code-block undefined code highlight"><code>&lt;div&gt;</code></pre></div>
-04_06_00__leaf_blocks__html_blocks__037:
- canonical: |
- <p>Foo</p>
- <div>
- bar
- </div>
- static: |-
- <p data-sourcepos="1:1-1:3" dir="auto">Foo</p>
- <div>
- bar
- </div>
- wysiwyg: |-
- <p>Foo</p>
- <div><p>
- bar
- </p></div>
-04_06_00__leaf_blocks__html_blocks__038:
- canonical: |
- <div>
- bar
- </div>
- *foo*
- static: |-
- <div>
- bar
- </div>
- *foo*
- wysiwyg: |-
- <div><p>
- bar
- </p></div>
- <p>
- *foo*</p>
-04_06_00__leaf_blocks__html_blocks__039:
- canonical: |
- <p>Foo
- <a href="bar">
- baz</p>
- static: |-
- <p data-sourcepos="1:1-3:3" dir="auto">Foo
- <a href="bar">
- baz</a></p>
- wysiwyg: |-
- <p>Foo
- <a target="_blank" rel="noopener noreferrer nofollow" href="bar">
- baz</a></p>
-04_06_00__leaf_blocks__html_blocks__040:
- canonical: |
- <div>
- <p><em>Emphasized</em> text.</p>
- </div>
- static: |-
- <div>
- <p data-sourcepos="3:1-3:18"><em>Emphasized</em> text.</p>
- </div>
- wysiwyg: |-
- <div><p><em>Emphasized</em> text.</p></div>
-04_06_00__leaf_blocks__html_blocks__041:
- canonical: |
- <div>
- *Emphasized* text.
- </div>
- static: |-
- <div>
- *Emphasized* text.
- </div>
- wysiwyg: |-
- <div><p>
- *Emphasized* text.
- </p></div>
-04_06_00__leaf_blocks__html_blocks__042:
- canonical: |
- <table>
- <tr>
- <td>
- Hi
- </td>
- </tr>
- </table>
- static: |-
- <table dir="auto">
- <tr>
- <td>
- Hi
- </td>
- </tr>
- </table>
- wysiwyg: |-
- <table><tbody><tr><td colspan="1" rowspan="1"><p>
- Hi
- </p></td></tr></tbody></table>
-04_06_00__leaf_blocks__html_blocks__043:
- canonical: |
- <table>
- <tr>
- <pre><code>&lt;td&gt;
- Hi
- &lt;/td&gt;
- </code></pre>
- </tr>
- </table>
- static: |-
- <table dir="auto">
- <tr>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="5:5-8:0" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;td&gt;</span>
- <span id="LC2" class="line" lang="plaintext"> Hi</span>
- <span id="LC3" class="line" lang="plaintext">&lt;/td&gt;</span></code></pre>
- <copy-code></copy-code>
- </div>
- </tr>
- </table>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>&lt;td&gt;
- Hi
- &lt;/td&gt;</code></pre>
- <table><tbody><tr></tr></tbody></table>
-04_07_00__leaf_blocks__link_reference_definitions__001:
- canonical: |
- <p><a href="/url" title="title">foo</a></p>
- static: |-
- <p data-sourcepos="3:1-3:5" dir="auto"><a href="/url" title="title">foo</a></p>
- wysiwyg: |-
- <pre>[foo]: /url "title"</pre>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">foo</a></p>
-04_07_00__leaf_blocks__link_reference_definitions__002:
- canonical: |
- <p><a href="/url" title="the title">foo</a></p>
- static: |-
- <p data-sourcepos="5:1-5:5" dir="auto"><a href="/url" title="the title">foo</a></p>
- wysiwyg: |-
- <pre>[foo]: /url "the title"</pre>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="the title">foo</a></p>
-04_07_00__leaf_blocks__link_reference_definitions__003:
- canonical: |
- <p><a href="my_(url)" title="title (with parens)">Foo*bar]</a></p>
- static: |-
- <p data-sourcepos="3:1-3:11" dir="auto"><a href="my_(url)" title="title (with parens)">Foo*bar]</a></p>
- wysiwyg: |-
- <pre>[foo*bar\]]: my_(url) "title (with parens)"</pre>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="my_(url)" title="title (with parens)">Foo*bar]</a></p>
-04_07_00__leaf_blocks__link_reference_definitions__004:
- canonical: |
- <p><a href="my%20url" title="title">Foo bar</a></p>
- static: |-
- <p data-sourcepos="5:1-5:9" dir="auto"><a href="my%20url" title="title">Foo bar</a></p>
- wysiwyg: |-
- <pre>[foo bar]: my url "title"</pre>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="my%20url" title="title">Foo bar</a></p>
-04_07_00__leaf_blocks__link_reference_definitions__005:
- canonical: |
- <p><a href="/url" title="
- title
- line1
- line2
- ">foo</a></p>
- static: |-
- <p data-sourcepos="7:1-7:5" dir="auto"><a href="/url" title="
- title
- line1
- line2
- ">foo</a></p>
- wysiwyg: |-
- <pre>[foo]: /url "
- title
- line1
- line2
- "</pre>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="
- title
- line1
- line2
- ">foo</a></p>
-04_07_00__leaf_blocks__link_reference_definitions__006:
- canonical: |
- <p>[foo]: /url 'title</p>
- <p>with blank line'</p>
- <p>[foo]</p>
- static: |-
- <p data-sourcepos="1:1-1:18" dir="auto">[foo]: /url 'title</p>
- <p data-sourcepos="3:1-3:16" dir="auto">with blank line'</p>
- <p data-sourcepos="5:1-5:5" dir="auto">[foo]</p>
- wysiwyg: |-
- <p>[foo]: /url 'title</p>
- <p>with blank line'</p>
- <p>[foo]</p>
-04_07_00__leaf_blocks__link_reference_definitions__007:
- canonical: |
- <p><a href="/url">foo</a></p>
- static: |-
- <p data-sourcepos="4:1-4:5" dir="auto"><a href="/url">foo</a></p>
- wysiwyg: |-
- <pre>[foo]: /url</pre>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url">foo</a></p>
-04_07_00__leaf_blocks__link_reference_definitions__008:
- canonical: |
- <p>[foo]:</p>
- <p>[foo]</p>
- static: |-
- <p data-sourcepos="1:1-1:6" dir="auto">[foo]:</p>
- <p data-sourcepos="3:1-3:5" dir="auto">[foo]</p>
- wysiwyg: |-
- <p>[foo]:</p>
- <p>[foo]</p>
-04_07_00__leaf_blocks__link_reference_definitions__009:
- canonical: |
- <p><a href="">foo</a></p>
- static: |-
- <p data-sourcepos="3:1-3:5" dir="auto"><a href="">foo</a></p>
- wysiwyg: |-
- <pre>[foo]: </pre>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="">foo</a></p>
-04_07_00__leaf_blocks__link_reference_definitions__010:
- canonical: |
- <p>[foo]: <bar>(baz)</p>
- <p>[foo]</p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto">[foo]: (baz)</p>
- <p data-sourcepos="3:1-3:5" dir="auto">[foo]</p>
- wysiwyg: |-
- <p>[foo]: </p>
- <p>[foo]</p>
-04_07_00__leaf_blocks__link_reference_definitions__011:
- canonical: |
- <p><a href="/url%5Cbar*baz" title="foo&quot;bar\baz">foo</a></p>
- static: |-
- <p data-sourcepos="3:1-3:5" dir="auto"><a href="/url%5Cbar*baz" title='foo"bar\baz'>foo</a></p>
- wysiwyg: |-
- <pre>[foo]: /url\bar*baz "foo"bar\baz"</pre>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url%5Cbar*baz" title="foo&quot;bar\baz">foo</a></p>
-04_07_00__leaf_blocks__link_reference_definitions__012:
- canonical: |
- <p><a href="url">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:5" dir="auto"><a href="url">foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="url">foo</a></p>
- <pre>[foo]: url</pre>
-04_07_00__leaf_blocks__link_reference_definitions__013:
- canonical: |
- <p><a href="first">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:5" dir="auto"><a href="first">foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="first">foo</a></p>
- <pre>[foo]: first</pre>
- <pre>[foo]: second</pre>
-04_07_00__leaf_blocks__link_reference_definitions__014:
- canonical: |
- <p><a href="/url">Foo</a></p>
- static: |-
- <p data-sourcepos="3:1-3:5" dir="auto"><a href="/url">Foo</a></p>
- wysiwyg: |-
- <pre>[foo]: /url</pre>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url">Foo</a></p>
-04_07_00__leaf_blocks__link_reference_definitions__015:
- canonical: |
- <p><a href="/%CF%86%CE%BF%CF%85">αγω</a></p>
- static: |-
- <p data-sourcepos="3:1-3:8" dir="auto"><a href="/%CF%86%CE%BF%CF%85">αγω</a></p>
- wysiwyg: |-
- <pre>[αγω]: /φου</pre>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/%CF%86%CE%BF%CF%85">αγω</a></p>
-04_07_00__leaf_blocks__link_reference_definitions__016:
- canonical: ""
- static: ""
- wysiwyg: |-
- <pre>[foo]: /url</pre>
-04_07_00__leaf_blocks__link_reference_definitions__017:
- canonical: |
- <p>bar</p>
- static: |-
- <p data-sourcepos="1:1-4:3" dir="auto">bar</p>
- wysiwyg: |-
- <pre>[foo]: /url</pre>
- <p>bar</p>
-04_07_00__leaf_blocks__link_reference_definitions__018:
- canonical: |
- <p>[foo]: /url &quot;title&quot; ok</p>
- static: |-
- <p data-sourcepos="1:1-1:22" dir="auto">[foo]: /url "title" ok</p>
- wysiwyg: |-
- <p>[foo]: /url "title" ok</p>
-04_07_00__leaf_blocks__link_reference_definitions__019:
- canonical: |
- <p>&quot;title&quot; ok</p>
- static: |-
- <p data-sourcepos="1:1-2:10" dir="auto">"title" ok</p>
- wysiwyg: |-
- <pre>[foo]: /url</pre>
- <p>"title" ok</p>
-04_07_00__leaf_blocks__link_reference_definitions__020:
- canonical: |
- <pre><code>[foo]: /url &quot;title&quot;
- </code></pre>
- <p>[foo]</p>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-2:0" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url "title"</span></code></pre>
- <copy-code></copy-code>
- </div>
- <p data-sourcepos="3:1-3:5" dir="auto">[foo]</p>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>[foo]: /url "title"</code></pre>
- <p>[foo]</p>
-04_07_00__leaf_blocks__link_reference_definitions__021:
- canonical: |
- <pre><code>[foo]: /url
- </code></pre>
- <p>[foo]</p>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url</span></code></pre>
- <copy-code></copy-code>
- </div>
- <p data-sourcepos="5:1-5:5" dir="auto">[foo]</p>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>[foo]: /url</code></pre>
- <p>[foo]</p>
-04_07_00__leaf_blocks__link_reference_definitions__022:
- canonical: |
- <p>Foo
- [bar]: /baz</p>
- <p>[bar]</p>
- static: |-
- <p data-sourcepos="1:1-2:11" dir="auto">Foo
- [bar]: /baz</p>
- <p data-sourcepos="4:1-4:5" dir="auto">[bar]</p>
- wysiwyg: |-
- <p>Foo
- [bar]: /baz</p>
- <p>[bar]</p>
-04_07_00__leaf_blocks__link_reference_definitions__023:
- canonical: |
- <h1><a href="/url">Foo</a></h1>
- <blockquote>
- <p>bar</p>
- </blockquote>
- static: |-
- <h1 data-sourcepos="1:1-1:7" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a><a href="/url">Foo</a>
- </h1>
- <blockquote data-sourcepos="3:1-3:5" dir="auto">
- <p data-sourcepos="3:3-3:5">bar</p>
- </blockquote>
- wysiwyg: |-
- <h1><a target="_blank" rel="noopener noreferrer nofollow" href="/url">Foo</a></h1>
- <pre>[foo]: /url</pre>
- <blockquote multiline="false"><p>bar</p></blockquote>
-04_07_00__leaf_blocks__link_reference_definitions__024:
- canonical: |
- <h1>bar</h1>
- <p><a href="/url">foo</a></p>
- static: |-
- <h1 data-sourcepos="1:1-4:5" dir="auto">
- <a id="user-content-bar" class="anchor" href="#bar" aria-hidden="true"></a>bar</h1>
- <p data-sourcepos="4:1-4:5" dir="auto"><a href="/url">foo</a></p>
- wysiwyg: |-
- <pre>[foo]: /url</pre>
- <h1>bar</h1>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url">foo</a></p>
-04_07_00__leaf_blocks__link_reference_definitions__025:
- canonical: |
- <p>===
- <a href="/url">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-3:5" dir="auto">===
- <a href="/url">foo</a></p>
- wysiwyg: |-
- <pre>[foo]: /url</pre>
- <p>===
- <a target="_blank" rel="noopener noreferrer nofollow" href="/url">foo</a></p>
-04_07_00__leaf_blocks__link_reference_definitions__026:
- canonical: |
- <p><a href="/foo-url" title="foo">foo</a>,
- <a href="/bar-url" title="bar">bar</a>,
- <a href="/baz-url">baz</a></p>
- static: |-
- <p data-sourcepos="6:1-8:5" dir="auto"><a href="/foo-url" title="foo">foo</a>,
- <a href="/bar-url" title="bar">bar</a>,
- <a href="/baz-url">baz</a></p>
- wysiwyg: |-
- <pre>[foo]: /foo-url "foo"</pre>
- <pre>[bar]: /bar-url "bar"</pre>
- <pre>[baz]: /baz-url</pre>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/foo-url" title="foo">foo</a>,
- <a target="_blank" rel="noopener noreferrer nofollow" href="/bar-url" title="bar">bar</a>,
- <a target="_blank" rel="noopener noreferrer nofollow" href="/baz-url">baz</a></p>
-04_07_00__leaf_blocks__link_reference_definitions__027:
- canonical: |
- <p><a href="/url">foo</a></p>
- <blockquote>
- </blockquote>
- static: |-
- <p data-sourcepos="1:1-1:5" dir="auto"><a href="/url">foo</a></p>
- <blockquote data-sourcepos="3:1-3:13" dir="auto">
- </blockquote>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url">foo</a></p>
- <blockquote multiline="false"><pre>[foo]: /url</pre></blockquote>
-04_07_00__leaf_blocks__link_reference_definitions__028:
- canonical: ""
- static: ""
- wysiwyg: |-
- <pre>[foo]: /url</pre>
-04_08_00__leaf_blocks__paragraphs__001:
- canonical: |
- <p>aaa</p>
- <p>bbb</p>
- static: |-
- <p data-sourcepos="1:1-1:3" dir="auto">aaa</p>
- <p data-sourcepos="3:1-3:3" dir="auto">bbb</p>
- wysiwyg: |-
- <p>aaa</p>
- <p>bbb</p>
-04_08_00__leaf_blocks__paragraphs__002:
- canonical: |
- <p>aaa
- bbb</p>
- <p>ccc
- ddd</p>
- static: |-
- <p data-sourcepos="1:1-2:3" dir="auto">aaa
- bbb</p>
- <p data-sourcepos="4:1-5:3" dir="auto">ccc
- ddd</p>
- wysiwyg: |-
- <p>aaa
- bbb</p>
- <p>ccc
- ddd</p>
-04_08_00__leaf_blocks__paragraphs__003:
- canonical: |
- <p>aaa</p>
- <p>bbb</p>
- static: |-
- <p data-sourcepos="1:1-1:3" dir="auto">aaa</p>
- <p data-sourcepos="4:1-4:3" dir="auto">bbb</p>
- wysiwyg: |-
- <p>aaa</p>
- <p>bbb</p>
-04_08_00__leaf_blocks__paragraphs__004:
- canonical: |
- <p>aaa
- bbb</p>
- static: |-
- <p data-sourcepos="1:3-2:4" dir="auto">aaa
- bbb</p>
- wysiwyg: |-
- <p>aaa
- bbb</p>
-04_08_00__leaf_blocks__paragraphs__005:
- canonical: |
- <p>aaa
- bbb
- ccc</p>
- static: |-
- <p data-sourcepos="1:1-3:42" dir="auto">aaa
- bbb
- ccc</p>
- wysiwyg: |-
- <p>aaa
- bbb
- ccc</p>
-04_08_00__leaf_blocks__paragraphs__006:
- canonical: |
- <p>aaa
- bbb</p>
- static: |-
- <p data-sourcepos="1:4-2:3" dir="auto">aaa
- bbb</p>
- wysiwyg: |-
- <p>aaa
- bbb</p>
-04_08_00__leaf_blocks__paragraphs__007:
- canonical: |
- <pre><code>aaa
- </code></pre>
- <p>bbb</p>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-1:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span></code></pre>
- <copy-code></copy-code>
- </div>
- <p data-sourcepos="2:1-2:3" dir="auto">bbb</p>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>aaa</code></pre>
- <p>bbb</p>
-04_08_00__leaf_blocks__paragraphs__008:
- canonical: |
- <p>aaa<br />
- bbb</p>
- static: |-
- <p data-sourcepos="1:1-2:8" dir="auto">aaa<br>
- bbb</p>
- wysiwyg: |-
- <p>aaa<br>
- bbb</p>
-04_09_00__leaf_blocks__blank_lines__001:
- canonical: |
- <p>aaa</p>
- <h1>aaa</h1>
- static: |-
- <p data-sourcepos="3:1-3:3" dir="auto">aaa</p>
- <h1 data-sourcepos="6:1-6:5" dir="auto">
- <a id="user-content-aaa" class="anchor" href="#aaa" aria-hidden="true"></a>aaa</h1>
- wysiwyg: |-
- <p>aaa</p>
- <h1>aaa</h1>
-04_10_00__leaf_blocks__tables_extension__001:
- canonical: |
- <table>
- <thead>
- <tr>
- <th>foo</th>
- <th>bar</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>baz</td>
- <td>bim</td>
- </tr>
- </tbody>
- </table>
- static: |-
- <table data-sourcepos="1:1-3:13" dir="auto">
- <thead>
- <tr data-sourcepos="1:1-1:13">
- <th data-sourcepos="1:2-1:6">foo</th>
- <th data-sourcepos="1:8-1:12">bar</th>
- </tr>
- </thead>
- <tbody>
- <tr data-sourcepos="3:1-3:13">
- <td data-sourcepos="3:2-3:6">baz</td>
- <td data-sourcepos="3:8-3:12">bim</td>
- </tr>
- </tbody>
- </table>
- wysiwyg: |-
- <table><tbody><tr><th colspan="1" rowspan="1"><p>foo</p></th><th colspan="1" rowspan="1"><p>bar</p></th></tr><tr><td colspan="1" rowspan="1"><p>baz</p></td><td colspan="1" rowspan="1"><p>bim</p></td></tr></tbody></table>
-04_10_00__leaf_blocks__tables_extension__002:
- canonical: |
- <table>
- <thead>
- <tr>
- <th align="center">abc</th>
- <th align="right">defghi</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td align="center">bar</td>
- <td align="right">baz</td>
- </tr>
- </tbody>
- </table>
- static: |-
- <table data-sourcepos="1:1-3:9" dir="auto">
- <thead>
- <tr data-sourcepos="1:1-1:16">
- <th align="center" data-sourcepos="1:2-1:6">abc</th>
- <th align="right" data-sourcepos="1:8-1:15">defghi</th>
- </tr>
- </thead>
- <tbody>
- <tr data-sourcepos="3:1-3:9">
- <td align="center" data-sourcepos="3:1-3:4">bar</td>
- <td align="right" data-sourcepos="3:6-3:9">baz</td>
- </tr>
- </tbody>
- </table>
- wysiwyg: |-
- <table><tbody><tr><th colspan="1" rowspan="1"><p>abc</p></th><th colspan="1" rowspan="1"><p>defghi</p></th></tr><tr><td colspan="1" rowspan="1"><p>bar</p></td><td colspan="1" rowspan="1"><p>baz</p></td></tr></tbody></table>
-04_10_00__leaf_blocks__tables_extension__003:
- canonical: |
- <table>
- <thead>
- <tr>
- <th>f|oo</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>b <code>|</code> az</td>
- </tr>
- <tr>
- <td>b <strong>|</strong> im</td>
- </tr>
- </tbody>
- </table>
- static: |-
- <table data-sourcepos="1:1-4:15" dir="auto">
- <thead>
- <tr data-sourcepos="1:1-1:10">
- <th data-sourcepos="1:2-1:9">f|oo</th>
- </tr>
- </thead>
- <tbody>
- <tr data-sourcepos="3:1-3:13">
- <td data-sourcepos="3:2-3:12">b <code>|</code> az</td>
- </tr>
- <tr data-sourcepos="4:1-4:15">
- <td data-sourcepos="4:2-4:14">b <strong>|</strong> im</td>
- </tr>
- </tbody>
- </table>
- wysiwyg: |-
- <table><tbody><tr><th colspan="1" rowspan="1"><p>f|oo</p></th></tr><tr><td colspan="1" rowspan="1"><p>b <code>|</code> az</p></td></tr><tr><td colspan="1" rowspan="1"><p>b <strong>|</strong> im</p></td></tr></tbody></table>
-04_10_00__leaf_blocks__tables_extension__004:
- canonical: |
- <table>
- <thead>
- <tr>
- <th>abc</th>
- <th>def</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>bar</td>
- <td>baz</td>
- </tr>
- </tbody>
- </table>
- <blockquote>
- <p>bar</p>
- </blockquote>
- static: |-
- <table data-sourcepos="1:1-3:13" dir="auto">
- <thead>
- <tr data-sourcepos="1:1-1:13">
- <th data-sourcepos="1:2-1:6">abc</th>
- <th data-sourcepos="1:8-1:12">def</th>
- </tr>
- </thead>
- <tbody>
- <tr data-sourcepos="3:1-3:13">
- <td data-sourcepos="3:2-3:6">bar</td>
- <td data-sourcepos="3:8-3:12">baz</td>
- </tr>
- </tbody>
- </table>
- <blockquote data-sourcepos="4:1-4:5" dir="auto">
- <p data-sourcepos="4:3-4:5">bar</p>
- </blockquote>
- wysiwyg: |-
- <table><tbody><tr><th colspan="1" rowspan="1"><p>abc</p></th><th colspan="1" rowspan="1"><p>def</p></th></tr><tr><td colspan="1" rowspan="1"><p>bar</p></td><td colspan="1" rowspan="1"><p>baz</p></td></tr></tbody></table>
- <blockquote multiline="false"><p>bar</p></blockquote>
-04_10_00__leaf_blocks__tables_extension__005:
- canonical: |
- <table>
- <thead>
- <tr>
- <th>abc</th>
- <th>def</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>bar</td>
- <td>baz</td>
- </tr>
- <tr>
- <td>bar</td>
- <td></td>
- </tr>
- </tbody>
- </table>
- <p>bar</p>
- static: |-
- <table data-sourcepos="1:1-4:3" dir="auto">
- <thead>
- <tr data-sourcepos="1:1-1:13">
- <th data-sourcepos="1:2-1:6">abc</th>
- <th data-sourcepos="1:8-1:12">def</th>
- </tr>
- </thead>
- <tbody>
- <tr data-sourcepos="3:1-3:13">
- <td data-sourcepos="3:2-3:6">bar</td>
- <td data-sourcepos="3:8-3:12">baz</td>
- </tr>
- <tr data-sourcepos="4:1-4:3">
- <td data-sourcepos="4:1-4:3">bar</td>
- <td data-sourcepos="4:0-4:0"></td>
- </tr>
- </tbody>
- </table>
- <p data-sourcepos="6:1-6:3" dir="auto">bar</p>
- wysiwyg: |-
- <table><tbody><tr><th colspan="1" rowspan="1"><p>abc</p></th><th colspan="1" rowspan="1"><p>def</p></th></tr><tr><td colspan="1" rowspan="1"><p>bar</p></td><td colspan="1" rowspan="1"><p>baz</p></td></tr><tr><td colspan="1" rowspan="1"><p>bar</p></td><td colspan="1" rowspan="1"><p></p></td></tr></tbody></table>
- <p>bar</p>
-04_10_00__leaf_blocks__tables_extension__006:
- canonical: |
- <p>| abc | def |
- | --- |
- | bar |</p>
- static: |-
- <p data-sourcepos="1:1-3:7" dir="auto">| abc | def |
- | --- |
- | bar |</p>
- wysiwyg: |-
- <p>| abc | def |
- | --- |
- | bar |</p>
-04_10_00__leaf_blocks__tables_extension__007:
- canonical: |
- <table>
- <thead>
- <tr>
- <th>abc</th>
- <th>def</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>bar</td>
- <td></td>
- </tr>
- <tr>
- <td>bar</td>
- <td>baz</td>
- </tr>
- </tbody>
- </table>
- static: |-
- <table data-sourcepos="1:1-4:19" dir="auto">
- <thead>
- <tr data-sourcepos="1:1-1:13">
- <th data-sourcepos="1:2-1:6">abc</th>
- <th data-sourcepos="1:8-1:12">def</th>
- </tr>
- </thead>
- <tbody>
- <tr data-sourcepos="3:1-3:7">
- <td data-sourcepos="3:2-3:6">bar</td>
- <td data-sourcepos="3:0-3:0"></td>
- </tr>
- <tr data-sourcepos="4:1-4:19">
- <td data-sourcepos="4:2-4:6">bar</td>
- <td data-sourcepos="4:8-4:12">baz</td>
- </tr>
- </tbody>
- </table>
- wysiwyg: |-
- <table><tbody><tr><th colspan="1" rowspan="1"><p>abc</p></th><th colspan="1" rowspan="1"><p>def</p></th></tr><tr><td colspan="1" rowspan="1"><p>bar</p></td><td colspan="1" rowspan="1"><p></p></td></tr><tr><td colspan="1" rowspan="1"><p>bar</p></td><td colspan="1" rowspan="1"><p>baz</p></td></tr></tbody></table>
-04_10_00__leaf_blocks__tables_extension__008:
- canonical: |
- <table>
- <thead>
- <tr>
- <th>abc</th>
- <th>def</th>
- </tr>
- </thead>
- </table>
- static: |-
- <table data-sourcepos="1:1-2:13" dir="auto">
- <thead>
- <tr data-sourcepos="1:1-1:13">
- <th data-sourcepos="1:2-1:6">abc</th>
- <th data-sourcepos="1:8-1:12">def</th>
- </tr>
- </thead>
- </table>
- wysiwyg: |-
- <table><tbody><tr><th colspan="1" rowspan="1"><p>abc</p></th><th colspan="1" rowspan="1"><p>def</p></th></tr></tbody></table>
-05_01_00__container_blocks__block_quotes__001:
- canonical: |
- <blockquote>
- <h1>Foo</h1>
- <p>bar
- baz</p>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-3:5" dir="auto">
- <h1 data-sourcepos="1:3-1:7">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h1>
- <p data-sourcepos="2:3-3:5">bar
- baz</p>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><h1>Foo</h1><p>bar
- baz</p></blockquote>
-05_01_00__container_blocks__block_quotes__002:
- canonical: |
- <blockquote>
- <h1>Foo</h1>
- <p>bar
- baz</p>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-3:5" dir="auto">
- <h1 data-sourcepos="1:2-1:6">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h1>
- <p data-sourcepos="2:2-3:5">bar
- baz</p>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><h1>Foo</h1><p>bar
- baz</p></blockquote>
-05_01_00__container_blocks__block_quotes__003:
- canonical: |
- <blockquote>
- <h1>Foo</h1>
- <p>bar
- baz</p>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:4-3:6" dir="auto">
- <h1 data-sourcepos="1:6-1:10">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h1>
- <p data-sourcepos="2:6-3:6">bar
- baz</p>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><h1>Foo</h1><p>bar
- baz</p></blockquote>
-05_01_00__container_blocks__block_quotes__004:
- canonical: |
- <pre><code>&gt; # Foo
- &gt; bar
- &gt; baz
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-3:9" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; # Foo</span>
- <span id="LC2" class="line" lang="plaintext">&gt; bar</span>
- <span id="LC3" class="line" lang="plaintext">&gt; baz</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>&gt; # Foo
- &gt; bar
- &gt; baz</code></pre>
-05_01_00__container_blocks__block_quotes__005:
- canonical: |
- <blockquote>
- <h1>Foo</h1>
- <p>bar
- baz</p>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-3:3" dir="auto">
- <h1 data-sourcepos="1:3-1:7">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h1>
- <p data-sourcepos="2:3-3:3">bar
- baz</p>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><h1>Foo</h1><p>bar
- baz</p></blockquote>
-05_01_00__container_blocks__block_quotes__006:
- canonical: |
- <blockquote>
- <p>bar
- baz
- foo</p>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-3:5" dir="auto">
- <p data-sourcepos="1:3-3:5">bar
- baz
- foo</p>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><p>bar
- baz
- foo</p></blockquote>
-05_01_00__container_blocks__block_quotes__007:
- canonical: |
- <blockquote>
- <p>foo</p>
- </blockquote>
- <hr />
- static: |-
- <blockquote data-sourcepos="1:1-1:5" dir="auto">
- <p data-sourcepos="1:3-1:5">foo</p>
- </blockquote>
- <hr data-sourcepos="2:1-2:3">
- wysiwyg: |-
- <blockquote multiline="false"><p>foo</p></blockquote>
- <hr>
-05_01_00__container_blocks__block_quotes__008:
- canonical: |
- <blockquote>
- <ul>
- <li>foo</li>
- </ul>
- </blockquote>
- <ul>
- <li>bar</li>
- </ul>
- static: |-
- <blockquote data-sourcepos="1:1-1:7" dir="auto">
- <ul data-sourcepos="1:3-1:7">
- <li data-sourcepos="1:3-1:7">foo</li>
- </ul>
- </blockquote>
- <ul data-sourcepos="2:1-2:5" dir="auto">
- <li data-sourcepos="2:1-2:5">bar</li>
- </ul>
- wysiwyg: |-
- <blockquote multiline="false"><ul bullet="*"><li><p>foo</p></li></ul></blockquote>
- <ul bullet="*"><li><p>bar</p></li></ul>
-05_01_00__container_blocks__block_quotes__009:
- canonical: |
- <blockquote>
- <pre><code>foo
- </code></pre>
- </blockquote>
- <pre><code>bar
- </code></pre>
- static: |-
- <blockquote data-sourcepos="1:1-1:9" dir="auto">
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:7-1:9" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
- <copy-code></copy-code>
- </div>
- </blockquote>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="2:5-2:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <blockquote multiline="false"><pre class="content-editor-code-block undefined code highlight"><code>foo</code></pre></blockquote>
- <pre class="content-editor-code-block undefined code highlight"><code>bar</code></pre>
-05_01_00__container_blocks__block_quotes__010:
- canonical: |
- <blockquote>
- <pre><code></code></pre>
- </blockquote>
- <p>foo</p>
- <pre><code></code></pre>
- static: |-
- <blockquote data-sourcepos="1:1-1:5" dir="auto">
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:3-2:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code></code></pre>
- <copy-code></copy-code>
- </div>
- </blockquote>
- <p data-sourcepos="2:1-2:3" dir="auto">foo</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="3:1-3:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <blockquote multiline="false"><pre class="content-editor-code-block undefined code highlight"><code></code></pre></blockquote>
- <p>foo</p>
- <pre class="content-editor-code-block undefined code highlight"><code></code></pre>
-05_01_00__container_blocks__block_quotes__011:
- canonical: |
- <blockquote>
- <p>foo
- - bar</p>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-2:9" dir="auto">
- <p data-sourcepos="1:3-2:9">foo
- - bar</p>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><p>foo
- - bar</p></blockquote>
-05_01_00__container_blocks__block_quotes__012:
- canonical: |
- <blockquote>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-1:1" dir="auto">
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><p></p></blockquote>
-05_01_00__container_blocks__block_quotes__013:
- canonical: |
- <blockquote>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-3:2" dir="auto">
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><p></p></blockquote>
-05_01_00__container_blocks__block_quotes__014:
- canonical: |
- <blockquote>
- <p>foo</p>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-3:3" dir="auto">
- <p data-sourcepos="2:3-2:5">foo</p>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><p>foo</p></blockquote>
-05_01_00__container_blocks__block_quotes__015:
- canonical: |
- <blockquote>
- <p>foo</p>
- </blockquote>
- <blockquote>
- <p>bar</p>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-1:5" dir="auto">
- <p data-sourcepos="1:3-1:5">foo</p>
- </blockquote>
- <blockquote data-sourcepos="3:1-3:5" dir="auto">
- <p data-sourcepos="3:3-3:5">bar</p>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><p>foo</p></blockquote>
- <blockquote multiline="false"><p>bar</p></blockquote>
-05_01_00__container_blocks__block_quotes__016:
- canonical: |
- <blockquote>
- <p>foo
- bar</p>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-2:5" dir="auto">
- <p data-sourcepos="1:3-2:5">foo
- bar</p>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><p>foo
- bar</p></blockquote>
-05_01_00__container_blocks__block_quotes__017:
- canonical: |
- <blockquote>
- <p>foo</p>
- <p>bar</p>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-3:5" dir="auto">
- <p data-sourcepos="1:3-1:5">foo</p>
- <p data-sourcepos="3:3-3:5">bar</p>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><p>foo</p><p>bar</p></blockquote>
-05_01_00__container_blocks__block_quotes__018:
- canonical: |
- <p>foo</p>
- <blockquote>
- <p>bar</p>
- </blockquote>
- static: |-
- <p data-sourcepos="1:1-1:3" dir="auto">foo</p>
- <blockquote data-sourcepos="2:1-2:5" dir="auto">
- <p data-sourcepos="2:3-2:5">bar</p>
- </blockquote>
- wysiwyg: |-
- <p>foo</p>
- <blockquote multiline="false"><p>bar</p></blockquote>
-05_01_00__container_blocks__block_quotes__019:
- canonical: |
- <blockquote>
- <p>aaa</p>
- </blockquote>
- <hr />
- <blockquote>
- <p>bbb</p>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-1:5" dir="auto">
- <p data-sourcepos="1:3-1:5">aaa</p>
- </blockquote>
- <hr data-sourcepos="2:1-2:3">
- <blockquote data-sourcepos="3:1-3:5" dir="auto">
- <p data-sourcepos="3:3-3:5">bbb</p>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><p>aaa</p></blockquote>
- <hr>
- <blockquote multiline="false"><p>bbb</p></blockquote>
-05_01_00__container_blocks__block_quotes__020:
- canonical: |
- <blockquote>
- <p>bar
- baz</p>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-2:3" dir="auto">
- <p data-sourcepos="1:3-2:3">bar
- baz</p>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><p>bar
- baz</p></blockquote>
-05_01_00__container_blocks__block_quotes__021:
- canonical: |
- <blockquote>
- <p>bar</p>
- </blockquote>
- <p>baz</p>
- static: |-
- <blockquote data-sourcepos="1:1-1:5" dir="auto">
- <p data-sourcepos="1:3-1:5">bar</p>
- </blockquote>
- <p data-sourcepos="3:1-3:3" dir="auto">baz</p>
- wysiwyg: |-
- <blockquote multiline="false"><p>bar</p></blockquote>
- <p>baz</p>
-05_01_00__container_blocks__block_quotes__022:
- canonical: |
- <blockquote>
- <p>bar</p>
- </blockquote>
- <p>baz</p>
- static: |-
- <blockquote data-sourcepos="1:1-2:1" dir="auto">
- <p data-sourcepos="1:3-1:5">bar</p>
- </blockquote>
- <p data-sourcepos="3:1-3:3" dir="auto">baz</p>
- wysiwyg: |-
- <blockquote multiline="false"><p>bar</p></blockquote>
- <p>baz</p>
-05_01_00__container_blocks__block_quotes__023:
- canonical: |
- <blockquote>
- <blockquote>
- <blockquote>
- <p>foo
- bar</p>
- </blockquote>
- </blockquote>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-2:3" dir="auto">
- <blockquote data-sourcepos="1:3-2:3">
- <blockquote data-sourcepos="1:5-2:3">
- <p data-sourcepos="1:7-2:3">foo
- bar</p>
- </blockquote>
- </blockquote>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><blockquote multiline="false"><blockquote multiline="false"><p>foo
- bar</p></blockquote></blockquote></blockquote>
-05_01_00__container_blocks__block_quotes__024:
- canonical: |
- <blockquote>
- <blockquote>
- <blockquote>
- <p>foo
- bar
- baz</p>
- </blockquote>
- </blockquote>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-3:5" dir="auto">
- <blockquote data-sourcepos="1:2-3:5">
- <blockquote data-sourcepos="1:3-3:5">
- <p data-sourcepos="1:5-3:5">foo
- bar
- baz</p>
- </blockquote>
- </blockquote>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><blockquote multiline="false"><blockquote multiline="false"><p>foo
- bar
- baz</p></blockquote></blockquote></blockquote>
-05_01_00__container_blocks__block_quotes__025:
- canonical: |
- <blockquote>
- <pre><code>code
- </code></pre>
- </blockquote>
- <blockquote>
- <p>not code</p>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-1:10" dir="auto">
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:7-1:10" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">code</span></code></pre>
- <copy-code></copy-code>
- </div>
- </blockquote>
- <blockquote data-sourcepos="3:1-3:13" dir="auto">
- <p data-sourcepos="3:6-3:13">not code</p>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><pre class="content-editor-code-block undefined code highlight"><code>code</code></pre></blockquote>
- <blockquote multiline="false"><p>not code</p></blockquote>
-05_02_00__container_blocks__list_items__001:
- canonical: |
- <p>A paragraph
- with two lines.</p>
- <pre><code>indented code
- </code></pre>
- <blockquote>
- <p>A block quote.</p>
- </blockquote>
- static: |-
- <p data-sourcepos="1:1-2:15" dir="auto">A paragraph
- with two lines.</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="4:5-5:0" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
- <copy-code></copy-code>
- </div>
- <blockquote data-sourcepos="6:1-6:16" dir="auto">
- <p data-sourcepos="6:3-6:16">A block quote.</p>
- </blockquote>
- wysiwyg: |-
- <p>A paragraph
- with two lines.</p>
- <pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre>
- <blockquote multiline="false"><p>A block quote.</p></blockquote>
-05_02_00__container_blocks__list_items__002:
- canonical: |
- <ol>
- <li>
- <p>A paragraph
- with two lines.</p>
- <pre><code>indented code
- </code></pre>
- <blockquote>
- <p>A block quote.</p>
- </blockquote>
- </li>
- </ol>
- static: |-
- <ol data-sourcepos="1:1-6:20" dir="auto">
- <li data-sourcepos="1:1-6:20">
- <p data-sourcepos="1:5-2:19">A paragraph
- with two lines.</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="4:9-5:0" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
- <copy-code></copy-code>
- </div>
- <blockquote data-sourcepos="6:5-6:20">
- <p data-sourcepos="6:7-6:20">A block quote.</p>
- </blockquote>
- </li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>A paragraph
- with two lines.</p><pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre><blockquote multiline="false"><p>A block quote.</p></blockquote></li></ol>
-05_02_00__container_blocks__list_items__003:
- canonical: |
- <ul>
- <li>one</li>
- </ul>
- <p>two</p>
- static: |-
- <ul data-sourcepos="1:1-2:0" dir="auto">
- <li data-sourcepos="1:1-2:0">one</li>
- </ul>
- <p data-sourcepos="3:2-3:4" dir="auto">two</p>
- wysiwyg: |-
- <ul bullet="*"><li><p>one</p></li></ul>
- <p>two</p>
-05_02_00__container_blocks__list_items__004:
- canonical: |
- <ul>
- <li>
- <p>one</p>
- <p>two</p>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-3:5" dir="auto">
- <li data-sourcepos="1:1-3:5">
- <p data-sourcepos="1:3-1:5">one</p>
- <p data-sourcepos="3:3-3:5">two</p>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>one</p><p>two</p></li></ul>
-05_02_00__container_blocks__list_items__005:
- canonical: |
- <ul>
- <li>one</li>
- </ul>
- <pre><code> two
- </code></pre>
- static: |-
- <ul data-sourcepos="1:2-2:0" dir="auto">
- <li data-sourcepos="1:2-2:0">one</li>
- </ul>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="3:5-3:8" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> two</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <ul bullet="*"><li><p>one</p></li></ul>
- <pre class="content-editor-code-block undefined code highlight"><code> two</code></pre>
-05_02_00__container_blocks__list_items__006:
- canonical: |
- <ul>
- <li>
- <p>one</p>
- <p>two</p>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:2-3:9" dir="auto">
- <li data-sourcepos="1:2-3:9">
- <p data-sourcepos="1:7-1:9">one</p>
- <p data-sourcepos="3:7-3:9">two</p>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>one</p><p>two</p></li></ul>
-05_02_00__container_blocks__list_items__007:
- canonical: |
- <blockquote>
- <blockquote>
- <ol>
- <li>
- <p>one</p>
- <p>two</p>
- </li>
- </ol>
- </blockquote>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:4-3:10" dir="auto">
- <blockquote data-sourcepos="1:6-3:10">
- <ol data-sourcepos="1:8-3:10">
- <li data-sourcepos="1:8-3:10">
- <p data-sourcepos="1:12-1:14">one</p>
- <p data-sourcepos="3:8-3:10">two</p>
- </li>
- </ol>
- </blockquote>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><blockquote multiline="false"><ol parens="false"><li><p>one</p><p>two</p></li></ol></blockquote></blockquote>
-05_02_00__container_blocks__list_items__008:
- canonical: |
- <blockquote>
- <blockquote>
- <ul>
- <li>one</li>
- </ul>
- <p>two</p>
- </blockquote>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-3:10" dir="auto">
- <blockquote data-sourcepos="1:2-3:10">
- <ul data-sourcepos="1:3-2:2">
- <li data-sourcepos="1:3-2:2">one</li>
- </ul>
- <p data-sourcepos="3:8-3:10">two</p>
- </blockquote>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><blockquote multiline="false"><ul bullet="*"><li><p>one</p></li></ul><p>two</p></blockquote></blockquote>
-05_02_00__container_blocks__list_items__009:
- canonical: |
- <p>-one</p>
- <p>2.two</p>
- static: |-
- <p data-sourcepos="1:1-1:4" dir="auto">-one</p>
- <p data-sourcepos="3:1-3:5" dir="auto">2.two</p>
- wysiwyg: |-
- <p>-one</p>
- <p>2.two</p>
-05_02_00__container_blocks__list_items__010:
- canonical: |
- <ul>
- <li>
- <p>foo</p>
- <p>bar</p>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-4:5" dir="auto">
- <li data-sourcepos="1:1-4:5">
- <p data-sourcepos="1:3-1:5">foo</p>
- <p data-sourcepos="4:3-4:5">bar</p>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p><p>bar</p></li></ul>
-05_02_00__container_blocks__list_items__011:
- canonical: |
- <ol>
- <li>
- <p>foo</p>
- <pre><code>bar
- </code></pre>
- <p>baz</p>
- <blockquote>
- <p>bam</p>
- </blockquote>
- </li>
- </ol>
- static: |-
- <ol data-sourcepos="1:1-9:9" dir="auto">
- <li data-sourcepos="1:1-9:9">
- <p data-sourcepos="1:5-1:7">foo</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="3:5-5:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span></code></pre>
- <copy-code></copy-code>
- </div>
- <p data-sourcepos="7:5-7:7">baz</p>
- <blockquote data-sourcepos="9:5-9:9">
- <p data-sourcepos="9:7-9:9">bam</p>
- </blockquote>
- </li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>foo</p><pre class="content-editor-code-block undefined code highlight"><code>bar</code></pre><p>baz</p><blockquote multiline="false"><p>bam</p></blockquote></li></ol>
-05_02_00__container_blocks__list_items__012:
- canonical: |
- <ul>
- <li>
- <p>Foo</p>
- <pre><code>bar
-
-
- baz
- </code></pre>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-6:9" dir="auto">
- <li data-sourcepos="1:1-6:9">
- <p data-sourcepos="1:3-1:5">Foo</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="3:7-6:9" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span>
- <span id="LC2" class="line" lang="plaintext"></span>
- <span id="LC3" class="line" lang="plaintext"></span>
- <span id="LC4" class="line" lang="plaintext">baz</span></code></pre>
- <copy-code></copy-code>
- </div>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>Foo</p><pre class="content-editor-code-block undefined code highlight"><code>bar
-
-
- baz</code></pre></li></ul>
-05_02_00__container_blocks__list_items__013:
- canonical: |
- <ol start="123456789">
- <li>ok</li>
- </ol>
- static: |-
- <ol start="123456789" data-sourcepos="1:1-1:13" dir="auto">
- <li data-sourcepos="1:1-1:13">ok</li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>ok</p></li></ol>
-05_02_00__container_blocks__list_items__014:
- canonical: |
- <p>1234567890. not ok</p>
- static: |-
- <p data-sourcepos="1:1-1:18" dir="auto">1234567890. not ok</p>
- wysiwyg: |-
- <p>1234567890. not ok</p>
-05_02_00__container_blocks__list_items__015:
- canonical: |
- <ol start="0">
- <li>ok</li>
- </ol>
- static: |-
- <ol start="0" data-sourcepos="1:1-1:5" dir="auto">
- <li data-sourcepos="1:1-1:5">ok</li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>ok</p></li></ol>
-05_02_00__container_blocks__list_items__016:
- canonical: |
- <ol start="3">
- <li>ok</li>
- </ol>
- static: |-
- <ol start="3" data-sourcepos="1:1-1:7" dir="auto">
- <li data-sourcepos="1:1-1:7">ok</li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>ok</p></li></ol>
-05_02_00__container_blocks__list_items__017:
- canonical: |
- <p>-1. not ok</p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto">-1. not ok</p>
- wysiwyg: |-
- <p>-1. not ok</p>
-05_02_00__container_blocks__list_items__018:
- canonical: |
- <ul>
- <li>
- <p>foo</p>
- <pre><code>bar
- </code></pre>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-3:9" dir="auto">
- <li data-sourcepos="1:1-3:9">
- <p data-sourcepos="1:3-1:5">foo</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="3:7-3:9" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span></code></pre>
- <copy-code></copy-code>
- </div>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p><pre class="content-editor-code-block undefined code highlight"><code>bar</code></pre></li></ul>
-05_02_00__container_blocks__list_items__019:
- canonical: |
- <ol start="10">
- <li>
- <p>foo</p>
- <pre><code>bar
- </code></pre>
- </li>
- </ol>
- static: |-
- <ol start="10" data-sourcepos="1:3-3:14" dir="auto">
- <li data-sourcepos="1:3-3:14">
- <p data-sourcepos="1:8-1:10">foo</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="3:12-3:14" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span></code></pre>
- <copy-code></copy-code>
- </div>
- </li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>foo</p><pre class="content-editor-code-block undefined code highlight"><code>bar</code></pre></li></ol>
-05_02_00__container_blocks__list_items__020:
- canonical: |
- <pre><code>indented code
- </code></pre>
- <p>paragraph</p>
- <pre><code>more code
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-2:0" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
- <copy-code></copy-code>
- </div>
- <p data-sourcepos="3:1-3:9" dir="auto">paragraph</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="5:5-5:13" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">more code</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre>
- <p>paragraph</p>
- <pre class="content-editor-code-block undefined code highlight"><code>more code</code></pre>
-05_02_00__container_blocks__list_items__021:
- canonical: |
- <ol>
- <li>
- <pre><code>indented code
- </code></pre>
- <p>paragraph</p>
- <pre><code>more code
- </code></pre>
- </li>
- </ol>
- static: |-
- <ol data-sourcepos="1:1-5:16" dir="auto">
- <li data-sourcepos="1:1-5:16">
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:8-2:0" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
- <copy-code></copy-code>
- </div>
- <p data-sourcepos="3:4-3:12">paragraph</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="5:8-5:16" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">more code</span></code></pre>
- <copy-code></copy-code>
- </div>
- </li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p></p><pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre><p>paragraph</p><pre class="content-editor-code-block undefined code highlight"><code>more code</code></pre></li></ol>
-05_02_00__container_blocks__list_items__022:
- canonical: |
- <ol>
- <li>
- <pre><code> indented code
- </code></pre>
- <p>paragraph</p>
- <pre><code>more code
- </code></pre>
- </li>
- </ol>
- static: |-
- <ol data-sourcepos="1:1-5:16" dir="auto">
- <li data-sourcepos="1:1-5:16">
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:8-2:0" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> indented code</span></code></pre>
- <copy-code></copy-code>
- </div>
- <p data-sourcepos="3:4-3:12">paragraph</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="5:8-5:16" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">more code</span></code></pre>
- <copy-code></copy-code>
- </div>
- </li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p></p><pre class="content-editor-code-block undefined code highlight"><code> indented code</code></pre><p>paragraph</p><pre class="content-editor-code-block undefined code highlight"><code>more code</code></pre></li></ol>
-05_02_00__container_blocks__list_items__023:
- canonical: |
- <p>foo</p>
- <p>bar</p>
- static: |-
- <p data-sourcepos="1:4-1:6" dir="auto">foo</p>
- <p data-sourcepos="3:1-3:3" dir="auto">bar</p>
- wysiwyg: |-
- <p>foo</p>
- <p>bar</p>
-05_02_00__container_blocks__list_items__024:
- canonical: |
- <ul>
- <li>foo</li>
- </ul>
- <p>bar</p>
- static: |-
- <ul data-sourcepos="1:1-2:0" dir="auto">
- <li data-sourcepos="1:1-2:0">foo</li>
- </ul>
- <p data-sourcepos="3:3-3:5" dir="auto">bar</p>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p></li></ul>
- <p>bar</p>
-05_02_00__container_blocks__list_items__025:
- canonical: |
- <ul>
- <li>
- <p>foo</p>
- <p>bar</p>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-3:6" dir="auto">
- <li data-sourcepos="1:1-3:6">
- <p data-sourcepos="1:4-1:6">foo</p>
- <p data-sourcepos="3:4-3:6">bar</p>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p><p>bar</p></li></ul>
-05_02_00__container_blocks__list_items__026:
- canonical: |
- <ul>
- <li>foo</li>
- <li>
- <pre><code>bar
- </code></pre>
- </li>
- <li>
- <pre><code>baz
- </code></pre>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-8:9" dir="auto">
- <li data-sourcepos="1:1-2:5">foo</li>
- <li data-sourcepos="3:1-6:5">
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="4:3-6:5" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span></code></pre>
- <copy-code></copy-code>
- </div>
- </li>
- <li data-sourcepos="7:1-8:9">
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="8:7-8:9" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">baz</span></code></pre>
- <copy-code></copy-code>
- </div>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p></li><li><p></p><pre class="content-editor-code-block undefined code highlight"><code>bar</code></pre></li><li><p></p><pre class="content-editor-code-block undefined code highlight"><code>baz</code></pre></li></ul>
-05_02_00__container_blocks__list_items__027:
- canonical: |
- <ul>
- <li>foo</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-2:5" dir="auto">
- <li data-sourcepos="1:1-2:5">foo</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p></li></ul>
-05_02_00__container_blocks__list_items__028:
- canonical: |
- <ul>
- <li></li>
- </ul>
- <p>foo</p>
- static: |-
- <ul data-sourcepos="1:1-2:0" dir="auto">
- <li data-sourcepos="1:1-1:1">
- </li>
- </ul>
- <p data-sourcepos="3:3-3:5" dir="auto">foo</p>
- wysiwyg: |-
- <ul bullet="*"><li><p></p></li></ul>
- <p>foo</p>
-05_02_00__container_blocks__list_items__029:
- canonical: |
- <ul>
- <li>foo</li>
- <li></li>
- <li>bar</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-3:5" dir="auto">
- <li data-sourcepos="1:1-1:5">foo</li>
- <li data-sourcepos="2:1-2:1">
- </li>
- <li data-sourcepos="3:1-3:5">bar</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p></li><li><p></p></li><li><p>bar</p></li></ul>
-05_02_00__container_blocks__list_items__030:
- canonical: |
- <ul>
- <li>foo</li>
- <li></li>
- <li>bar</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-3:5" dir="auto">
- <li data-sourcepos="1:1-1:5">foo</li>
- <li data-sourcepos="2:1-2:4">
- </li>
- <li data-sourcepos="3:1-3:5">bar</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p></li><li><p></p></li><li><p>bar</p></li></ul>
-05_02_00__container_blocks__list_items__031:
- canonical: |
- <ol>
- <li>foo</li>
- <li></li>
- <li>bar</li>
- </ol>
- static: |-
- <ol data-sourcepos="1:1-3:6" dir="auto">
- <li data-sourcepos="1:1-1:6">foo</li>
- <li data-sourcepos="2:1-2:2">
- </li>
- <li data-sourcepos="3:1-3:6">bar</li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>foo</p></li><li><p></p></li><li><p>bar</p></li></ol>
-05_02_00__container_blocks__list_items__032:
- canonical: |
- <ul>
- <li></li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-1:1" dir="auto">
- <li data-sourcepos="1:1-1:1">
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p></p></li></ul>
-05_02_00__container_blocks__list_items__033:
- canonical: |
- <p>foo
- *</p>
- <p>foo
- 1.</p>
- static: |-
- <p data-sourcepos="1:1-2:1" dir="auto">foo
- *</p>
- <p data-sourcepos="4:1-5:2" dir="auto">foo
- 1.</p>
- wysiwyg: |-
- <p>foo
- *</p>
- <p>foo
- 1.</p>
-05_02_00__container_blocks__list_items__034:
- canonical: |
- <ol>
- <li>
- <p>A paragraph
- with two lines.</p>
- <pre><code>indented code
- </code></pre>
- <blockquote>
- <p>A block quote.</p>
- </blockquote>
- </li>
- </ol>
- static: |-
- <ol data-sourcepos="1:2-6:21" dir="auto">
- <li data-sourcepos="1:2-6:21">
- <p data-sourcepos="1:6-2:20">A paragraph
- with two lines.</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="4:10-5:0" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
- <copy-code></copy-code>
- </div>
- <blockquote data-sourcepos="6:6-6:21">
- <p data-sourcepos="6:8-6:21">A block quote.</p>
- </blockquote>
- </li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>A paragraph
- with two lines.</p><pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre><blockquote multiline="false"><p>A block quote.</p></blockquote></li></ol>
-05_02_00__container_blocks__list_items__035:
- canonical: |
- <ol>
- <li>
- <p>A paragraph
- with two lines.</p>
- <pre><code>indented code
- </code></pre>
- <blockquote>
- <p>A block quote.</p>
- </blockquote>
- </li>
- </ol>
- static: |-
- <ol data-sourcepos="1:3-6:22" dir="auto">
- <li data-sourcepos="1:3-6:22">
- <p data-sourcepos="1:7-2:21">A paragraph
- with two lines.</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="4:11-5:0" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
- <copy-code></copy-code>
- </div>
- <blockquote data-sourcepos="6:7-6:22">
- <p data-sourcepos="6:9-6:22">A block quote.</p>
- </blockquote>
- </li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>A paragraph
- with two lines.</p><pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre><blockquote multiline="false"><p>A block quote.</p></blockquote></li></ol>
-05_02_00__container_blocks__list_items__036:
- canonical: |
- <ol>
- <li>
- <p>A paragraph
- with two lines.</p>
- <pre><code>indented code
- </code></pre>
- <blockquote>
- <p>A block quote.</p>
- </blockquote>
- </li>
- </ol>
- static: |-
- <ol data-sourcepos="1:4-6:23" dir="auto">
- <li data-sourcepos="1:4-6:23">
- <p data-sourcepos="1:8-2:22">A paragraph
- with two lines.</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="4:12-5:0" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
- <copy-code></copy-code>
- </div>
- <blockquote data-sourcepos="6:8-6:23">
- <p data-sourcepos="6:10-6:23">A block quote.</p>
- </blockquote>
- </li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>A paragraph
- with two lines.</p><pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre><blockquote multiline="false"><p>A block quote.</p></blockquote></li></ol>
-05_02_00__container_blocks__list_items__037:
- canonical: |
- <pre><code>1. A paragraph
- with two lines.
-
- indented code
-
- &gt; A block quote.
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-6:24" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. A paragraph</span>
- <span id="LC2" class="line" lang="plaintext"> with two lines.</span>
- <span id="LC3" class="line" lang="plaintext"></span>
- <span id="LC4" class="line" lang="plaintext"> indented code</span>
- <span id="LC5" class="line" lang="plaintext"></span>
- <span id="LC6" class="line" lang="plaintext"> &gt; A block quote.</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>1. A paragraph
- with two lines.
-
- indented code
-
- &gt; A block quote.</code></pre>
-05_02_00__container_blocks__list_items__038:
- canonical: |
- <ol>
- <li>
- <p>A paragraph
- with two lines.</p>
- <pre><code>indented code
- </code></pre>
- <blockquote>
- <p>A block quote.</p>
- </blockquote>
- </li>
- </ol>
- static: |-
- <ol data-sourcepos="1:3-6:22" dir="auto">
- <li data-sourcepos="1:3-6:22">
- <p data-sourcepos="1:7-2:15">A paragraph
- with two lines.</p>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="4:11-5:0" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
- <copy-code></copy-code>
- </div>
- <blockquote data-sourcepos="6:7-6:22">
- <p data-sourcepos="6:9-6:22">A block quote.</p>
- </blockquote>
- </li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>A paragraph
- with two lines.</p><pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre><blockquote multiline="false"><p>A block quote.</p></blockquote></li></ol>
-05_02_00__container_blocks__list_items__039:
- canonical: |
- <ol>
- <li>A paragraph
- with two lines.</li>
- </ol>
- static: |-
- <ol data-sourcepos="1:3-2:19" dir="auto">
- <li data-sourcepos="1:3-2:19">A paragraph
- with two lines.</li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>A paragraph
- with two lines.</p></li></ol>
-05_02_00__container_blocks__list_items__040:
- canonical: |
- <blockquote>
- <ol>
- <li>
- <blockquote>
- <p>Blockquote
- continued here.</p>
- </blockquote>
- </li>
- </ol>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-2:15" dir="auto">
- <ol data-sourcepos="1:3-2:15">
- <li data-sourcepos="1:3-2:15">
- <blockquote data-sourcepos="1:6-2:15">
- <p data-sourcepos="1:8-2:15">Blockquote
- continued here.</p>
- </blockquote>
- </li>
- </ol>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><ol parens="false"><li><p></p><blockquote multiline="false"><p>Blockquote
- continued here.</p></blockquote></li></ol></blockquote>
-05_02_00__container_blocks__list_items__041:
- canonical: |
- <blockquote>
- <ol>
- <li>
- <blockquote>
- <p>Blockquote
- continued here.</p>
- </blockquote>
- </li>
- </ol>
- </blockquote>
- static: |-
- <blockquote data-sourcepos="1:1-2:17" dir="auto">
- <ol data-sourcepos="1:3-2:17">
- <li data-sourcepos="1:3-2:17">
- <blockquote data-sourcepos="1:6-2:17">
- <p data-sourcepos="1:8-2:17">Blockquote
- continued here.</p>
- </blockquote>
- </li>
- </ol>
- </blockquote>
- wysiwyg: |-
- <blockquote multiline="false"><ol parens="false"><li><p></p><blockquote multiline="false"><p>Blockquote
- continued here.</p></blockquote></li></ol></blockquote>
-05_02_00__container_blocks__list_items__042:
- canonical: |
- <ul>
- <li>foo
- <ul>
- <li>bar
- <ul>
- <li>baz
- <ul>
- <li>boo</li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-4:11" dir="auto">
- <li data-sourcepos="1:1-4:11">foo
- <ul data-sourcepos="2:3-4:11">
- <li data-sourcepos="2:3-4:11">bar
- <ul data-sourcepos="3:5-4:11">
- <li data-sourcepos="3:5-4:11">baz
- <ul data-sourcepos="4:7-4:11">
- <li data-sourcepos="4:7-4:11">boo</li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p><ul bullet="*"><li><p>bar</p><ul bullet="*"><li><p>baz</p><ul bullet="*"><li><p>boo</p></li></ul></li></ul></li></ul></li></ul>
-05_02_00__container_blocks__list_items__043:
- canonical: |
- <ul>
- <li>foo</li>
- <li>bar</li>
- <li>baz</li>
- <li>boo</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-4:8" dir="auto">
- <li data-sourcepos="1:1-1:5">foo</li>
- <li data-sourcepos="2:2-2:6">bar</li>
- <li data-sourcepos="3:3-3:7">baz</li>
- <li data-sourcepos="4:4-4:8">boo</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p></li><li><p>bar</p></li><li><p>baz</p></li><li><p>boo</p></li></ul>
-05_02_00__container_blocks__list_items__044:
- canonical: |
- <ol start="10">
- <li>foo
- <ul>
- <li>bar</li>
- </ul>
- </li>
- </ol>
- static: |-
- <ol start="10" data-sourcepos="1:1-2:9" dir="auto">
- <li data-sourcepos="1:1-2:9">foo
- <ul data-sourcepos="2:5-2:9">
- <li data-sourcepos="2:5-2:9">bar</li>
- </ul>
- </li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>foo</p><ul bullet="*"><li><p>bar</p></li></ul></li></ol>
-05_02_00__container_blocks__list_items__045:
- canonical: |
- <ol start="10">
- <li>foo</li>
- </ol>
- <ul>
- <li>bar</li>
- </ul>
- static: |-
- <ol start="10" data-sourcepos="1:1-1:7" dir="auto">
- <li data-sourcepos="1:1-1:7">foo</li>
- </ol>
- <ul data-sourcepos="2:4-2:8" dir="auto">
- <li data-sourcepos="2:4-2:8">bar</li>
- </ul>
- wysiwyg: |-
- <ol parens="false"><li><p>foo</p></li></ol>
- <ul bullet="*"><li><p>bar</p></li></ul>
-05_02_00__container_blocks__list_items__046:
- canonical: |
- <ul>
- <li>
- <ul>
- <li>foo</li>
- </ul>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-1:7" dir="auto">
- <li data-sourcepos="1:1-1:7">
- <ul data-sourcepos="1:3-1:7">
- <li data-sourcepos="1:3-1:7">foo</li>
- </ul>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p></p><ul bullet="*"><li><p>foo</p></li></ul></li></ul>
-05_02_00__container_blocks__list_items__047:
- canonical: |
- <ol>
- <li>
- <ul>
- <li>
- <ol start="2">
- <li>foo</li>
- </ol>
- </li>
- </ul>
- </li>
- </ol>
- static: |-
- <ol data-sourcepos="1:1-1:11" dir="auto">
- <li data-sourcepos="1:1-1:11">
- <ul data-sourcepos="1:4-1:11">
- <li data-sourcepos="1:4-1:11">
- <ol start="2" data-sourcepos="1:6-1:11">
- <li data-sourcepos="1:6-1:11">foo</li>
- </ol>
- </li>
- </ul>
- </li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p></p><ul bullet="*"><li><p></p><ol parens="false"><li><p>foo</p></li></ol></li></ul></li></ol>
-05_02_00__container_blocks__list_items__048:
- canonical: |
- <ul>
- <li>
- <h1>Foo</h1>
- </li>
- <li>
- <h2>Bar</h2>
- baz</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-4:5" dir="auto">
- <li data-sourcepos="1:1-1:7">
- <h1 data-sourcepos="1:3-1:7">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h1>
- </li>
- <li data-sourcepos="2:1-4:5">
- <h2 data-sourcepos="2:3-4:5">
- <a id="user-content-bar" class="anchor" href="#bar" aria-hidden="true"></a>Bar</h2>
- baz</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p></p><h1>Foo</h1></li><li><p></p><h2>Bar</h2><p>
- baz</p></li></ul>
-05_04_00__container_blocks__lists__001:
- canonical: |
- <ul>
- <li>foo</li>
- <li>bar</li>
- </ul>
- <ul>
- <li>baz</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-2:5" dir="auto">
- <li data-sourcepos="1:1-1:5">foo</li>
- <li data-sourcepos="2:1-2:5">bar</li>
- </ul>
- <ul data-sourcepos="3:1-3:5" dir="auto">
- <li data-sourcepos="3:1-3:5">baz</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p></li><li><p>bar</p></li></ul>
- <ul bullet="*"><li><p>baz</p></li></ul>
-05_04_00__container_blocks__lists__002:
- canonical: |
- <ol>
- <li>foo</li>
- <li>bar</li>
- </ol>
- <ol start="3">
- <li>baz</li>
- </ol>
- static: |-
- <ol data-sourcepos="1:1-2:6" dir="auto">
- <li data-sourcepos="1:1-1:6">foo</li>
- <li data-sourcepos="2:1-2:6">bar</li>
- </ol>
- <ol start="3" data-sourcepos="3:1-3:6" dir="auto">
- <li data-sourcepos="3:1-3:6">baz</li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>foo</p></li><li><p>bar</p></li></ol>
- <ol parens="false"><li><p>baz</p></li></ol>
-05_04_00__container_blocks__lists__003:
- canonical: |
- <p>Foo</p>
- <ul>
- <li>bar</li>
- <li>baz</li>
- </ul>
- static: |-
- <p data-sourcepos="1:1-1:3" dir="auto">Foo</p>
- <ul data-sourcepos="2:1-3:5" dir="auto">
- <li data-sourcepos="2:1-2:5">bar</li>
- <li data-sourcepos="3:1-3:5">baz</li>
- </ul>
- wysiwyg: |-
- <p>Foo</p>
- <ul bullet="*"><li><p>bar</p></li><li><p>baz</p></li></ul>
-05_04_00__container_blocks__lists__004:
- canonical: |
- <p>The number of windows in my house is
- 14. The number of doors is 6.</p>
- static: |-
- <p data-sourcepos="1:1-2:30" dir="auto">The number of windows in my house is
- 14. The number of doors is 6.</p>
- wysiwyg: |-
- <p>The number of windows in my house is
- 14. The number of doors is 6.</p>
-05_04_00__container_blocks__lists__005:
- canonical: |
- <p>The number of windows in my house is</p>
- <ol>
- <li>The number of doors is 6.</li>
- </ol>
- static: |-
- <p data-sourcepos="1:1-1:36" dir="auto">The number of windows in my house is</p>
- <ol data-sourcepos="2:1-2:29" dir="auto">
- <li data-sourcepos="2:1-2:29">The number of doors is 6.</li>
- </ol>
- wysiwyg: |-
- <p>The number of windows in my house is</p>
- <ol parens="false"><li><p>The number of doors is 6.</p></li></ol>
-05_04_00__container_blocks__lists__006:
- canonical: |
- <ul>
- <li>
- <p>foo</p>
- </li>
- <li>
- <p>bar</p>
- </li>
- <li>
- <p>baz</p>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-6:5" dir="auto">
- <li data-sourcepos="1:1-2:0">
- <p data-sourcepos="1:3-1:5">foo</p>
- </li>
- <li data-sourcepos="3:1-5:0">
- <p data-sourcepos="3:3-3:5">bar</p>
- </li>
- <li data-sourcepos="6:1-6:5">
- <p data-sourcepos="6:3-6:5">baz</p>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p></li><li><p>bar</p></li><li><p>baz</p></li></ul>
-05_04_00__container_blocks__lists__007:
- canonical: |
- <ul>
- <li>foo
- <ul>
- <li>bar
- <ul>
- <li>
- <p>baz</p>
- <p>bim</p>
- </li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-6:9" dir="auto">
- <li data-sourcepos="1:1-6:9">foo
- <ul data-sourcepos="2:3-6:9">
- <li data-sourcepos="2:3-6:9">bar
- <ul data-sourcepos="3:5-6:9">
- <li data-sourcepos="3:5-6:9">
- <p data-sourcepos="3:7-3:9">baz</p>
- <p data-sourcepos="6:7-6:9">bim</p>
- </li>
- </ul>
- </li>
- </ul>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p><ul bullet="*"><li><p>bar</p><ul bullet="*"><li><p>baz</p><p>bim</p></li></ul></li></ul></li></ul>
-05_04_00__container_blocks__lists__008:
- canonical: |
- <ul>
- <li>foo</li>
- <li>bar</li>
- </ul>
- <!-- -->
- <ul>
- <li>baz</li>
- <li>bim</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-3:0" dir="auto">
- <li data-sourcepos="1:1-1:5">foo</li>
- <li data-sourcepos="2:1-3:0">bar</li>
- </ul>
-
- <ul data-sourcepos="6:1-7:5" dir="auto">
- <li data-sourcepos="6:1-6:5">baz</li>
- <li data-sourcepos="7:1-7:5">bim</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p></li><li><p>bar</p></li></ul>
- <ul bullet="*"><li><p>baz</p></li><li><p>bim</p></li></ul>
-05_04_00__container_blocks__lists__009:
- canonical: |
- <ul>
- <li>
- <p>foo</p>
- <p>notcode</p>
- </li>
- <li>
- <p>foo</p>
- </li>
- </ul>
- <!-- -->
- <pre><code>code
- </code></pre>
- static: |-
- <ul data-sourcepos="1:1-6:0" dir="auto">
- <li data-sourcepos="1:1-4:0">
- <p data-sourcepos="1:5-1:7">foo</p>
- <p data-sourcepos="3:5-3:11">notcode</p>
- </li>
- <li data-sourcepos="5:1-6:0">
- <p data-sourcepos="5:5-5:7">foo</p>
- </li>
- </ul>
-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="9:5-9:8" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">code</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p><p>notcode</p></li><li><p>foo</p></li></ul>
- <pre class="content-editor-code-block undefined code highlight"><code>code</code></pre>
-05_04_00__container_blocks__lists__010:
- canonical: |
- <ul>
- <li>a</li>
- <li>b</li>
- <li>c</li>
- <li>d</li>
- <li>e</li>
- <li>f</li>
- <li>g</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-7:3" dir="auto">
- <li data-sourcepos="1:1-1:3">a</li>
- <li data-sourcepos="2:2-2:4">b</li>
- <li data-sourcepos="3:3-3:5">c</li>
- <li data-sourcepos="4:4-4:6">d</li>
- <li data-sourcepos="5:3-5:5">e</li>
- <li data-sourcepos="6:2-6:4">f</li>
- <li data-sourcepos="7:1-7:3">g</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>a</p></li><li><p>b</p></li><li><p>c</p></li><li><p>d</p></li><li><p>e</p></li><li><p>f</p></li><li><p>g</p></li></ul>
-05_04_00__container_blocks__lists__011:
- canonical: |
- <ol>
- <li>
- <p>a</p>
- </li>
- <li>
- <p>b</p>
- </li>
- <li>
- <p>c</p>
- </li>
- </ol>
- static: |-
- <ol data-sourcepos="1:1-5:7" dir="auto">
- <li data-sourcepos="1:1-2:0">
- <p data-sourcepos="1:4-1:4">a</p>
- </li>
- <li data-sourcepos="3:3-4:0">
- <p data-sourcepos="3:6-3:6">b</p>
- </li>
- <li data-sourcepos="5:4-5:7">
- <p data-sourcepos="5:7-5:7">c</p>
- </li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p>a</p></li><li><p>b</p></li><li><p>c</p></li></ol>
-05_04_00__container_blocks__lists__012:
- canonical: |
- <ul>
- <li>a</li>
- <li>b</li>
- <li>c</li>
- <li>d
- - e</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-5:7" dir="auto">
- <li data-sourcepos="1:1-1:3">a</li>
- <li data-sourcepos="2:2-2:4">b</li>
- <li data-sourcepos="3:3-3:5">c</li>
- <li data-sourcepos="4:4-5:7">d
- - e</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>a</p></li><li><p>b</p></li><li><p>c</p></li><li><p>d
- - e</p></li></ul>
-05_04_00__container_blocks__lists__013:
- canonical: |
- <ol>
- <li>
- <p>a</p>
- </li>
- <li>
- <p>b</p>
- </li>
- </ol>
- <pre><code>3. c
- </code></pre>
- static: |-
- <ol data-sourcepos="1:1-4:0" dir="auto">
- <li data-sourcepos="1:1-2:0">
- <p data-sourcepos="1:4-1:4">a</p>
- </li>
- <li data-sourcepos="3:3-4:0">
- <p data-sourcepos="3:6-3:6">b</p>
- </li>
- </ol>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="5:5-5:8" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">3. c</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <ol parens="false"><li><p>a</p></li><li><p>b</p></li></ol>
- <pre class="content-editor-code-block undefined code highlight"><code>3. c</code></pre>
-05_04_00__container_blocks__lists__014:
- canonical: |
- <ul>
- <li>
- <p>a</p>
- </li>
- <li>
- <p>b</p>
- </li>
- <li>
- <p>c</p>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-4:3" dir="auto">
- <li data-sourcepos="1:1-1:3">
- <p data-sourcepos="1:3-1:3">a</p>
- </li>
- <li data-sourcepos="2:1-3:0">
- <p data-sourcepos="2:3-2:3">b</p>
- </li>
- <li data-sourcepos="4:1-4:3">
- <p data-sourcepos="4:3-4:3">c</p>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>a</p></li><li><p>b</p></li><li><p>c</p></li></ul>
-05_04_00__container_blocks__lists__015:
- canonical: |
- <ul>
- <li>
- <p>a</p>
- </li>
- <li></li>
- <li>
- <p>c</p>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-4:3" dir="auto">
- <li data-sourcepos="1:1-1:3">
- <p data-sourcepos="1:3-1:3">a</p>
- </li>
- <li data-sourcepos="2:1-2:1">
- </li>
- <li data-sourcepos="4:1-4:3">
- <p data-sourcepos="4:3-4:3">c</p>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>a</p></li><li><p></p></li><li><p>c</p></li></ul>
-05_04_00__container_blocks__lists__016:
- canonical: |
- <ul>
- <li>
- <p>a</p>
- </li>
- <li>
- <p>b</p>
- <p>c</p>
- </li>
- <li>
- <p>d</p>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-5:3" dir="auto">
- <li data-sourcepos="1:1-1:3">
- <p data-sourcepos="1:3-1:3">a</p>
- </li>
- <li data-sourcepos="2:1-4:3">
- <p data-sourcepos="2:3-2:3">b</p>
- <p data-sourcepos="4:3-4:3">c</p>
- </li>
- <li data-sourcepos="5:1-5:3">
- <p data-sourcepos="5:3-5:3">d</p>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>a</p></li><li><p>b</p><p>c</p></li><li><p>d</p></li></ul>
-05_04_00__container_blocks__lists__017:
- canonical: |
- <ul>
- <li>
- <p>a</p>
- </li>
- <li>
- <p>b</p>
- </li>
- <li>
- <p>d</p>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-5:3" dir="auto">
- <li data-sourcepos="1:1-1:3">
- <p data-sourcepos="1:3-1:3">a</p>
- </li>
- <li data-sourcepos="2:1-4:13">
- <p data-sourcepos="2:3-2:3">b</p>
- </li>
- <li data-sourcepos="5:1-5:3">
- <p data-sourcepos="5:3-5:3">d</p>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>a</p></li><li><p>b</p><pre>[ref]: /url</pre></li><li><p>d</p></li></ul>
-05_04_00__container_blocks__lists__018:
- canonical: |
- <ul>
- <li>a</li>
- <li>
- <pre><code>b
-
-
- </code></pre>
- </li>
- <li>c</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-7:3" dir="auto">
- <li data-sourcepos="1:1-1:3">a</li>
- <li data-sourcepos="2:1-6:5">
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="2:3-6:5" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">b</span>
- <span id="LC2" class="line" lang="plaintext"></span>
- <span id="LC3" class="line" lang="plaintext"></span></code></pre>
- <copy-code></copy-code>
- </div>
- </li>
- <li data-sourcepos="7:1-7:3">c</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>a</p></li><li><p></p><pre class="content-editor-code-block undefined code highlight"><code>b</code></pre></li><li><p>c</p></li></ul>
-05_04_00__container_blocks__lists__019:
- canonical: |
- <ul>
- <li>a
- <ul>
- <li>
- <p>b</p>
- <p>c</p>
- </li>
- </ul>
- </li>
- <li>d</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-5:3" dir="auto">
- <li data-sourcepos="1:1-4:5">a
- <ul data-sourcepos="2:3-4:5">
- <li data-sourcepos="2:3-4:5">
- <p data-sourcepos="2:5-2:5">b</p>
- <p data-sourcepos="4:5-4:5">c</p>
- </li>
- </ul>
- </li>
- <li data-sourcepos="5:1-5:3">d</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>a</p><ul bullet="*"><li><p>b</p><p>c</p></li></ul></li><li><p>d</p></li></ul>
-05_04_00__container_blocks__lists__020:
- canonical: |
- <ul>
- <li>a
- <blockquote>
- <p>b</p>
- </blockquote>
- </li>
- <li>c</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-4:3" dir="auto">
- <li data-sourcepos="1:1-3:3">a
- <blockquote data-sourcepos="2:3-3:3">
- <p data-sourcepos="2:5-2:5">b</p>
- </blockquote>
- </li>
- <li data-sourcepos="4:1-4:3">c</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>a</p><blockquote multiline="false"><p>b</p></blockquote></li><li><p>c</p></li></ul>
-05_04_00__container_blocks__lists__021:
- canonical: |
- <ul>
- <li>a
- <blockquote>
- <p>b</p>
- </blockquote>
- <pre><code>c
- </code></pre>
- </li>
- <li>d</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-6:3" dir="auto">
- <li data-sourcepos="1:1-5:5">a
- <blockquote data-sourcepos="2:3-2:5">
- <p data-sourcepos="2:5-2:5">b</p>
- </blockquote>
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="3:3-5:5" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">c</span></code></pre>
- <copy-code></copy-code>
- </div>
- </li>
- <li data-sourcepos="6:1-6:3">d</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>a</p><blockquote multiline="false"><p>b</p></blockquote><pre class="content-editor-code-block undefined code highlight"><code>c</code></pre></li><li><p>d</p></li></ul>
-05_04_00__container_blocks__lists__022:
- canonical: |
- <ul>
- <li>a</li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-1:3" dir="auto">
- <li data-sourcepos="1:1-1:3">a</li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>a</p></li></ul>
-05_04_00__container_blocks__lists__023:
- canonical: |
- <ul>
- <li>a
- <ul>
- <li>b</li>
- </ul>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-2:5" dir="auto">
- <li data-sourcepos="1:1-2:5">a
- <ul data-sourcepos="2:3-2:5">
- <li data-sourcepos="2:3-2:5">b</li>
- </ul>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>a</p><ul bullet="*"><li><p>b</p></li></ul></li></ul>
-05_04_00__container_blocks__lists__024:
- canonical: |
- <ol>
- <li>
- <pre><code>foo
- </code></pre>
- <p>bar</p>
- </li>
- </ol>
- static: |-
- <ol data-sourcepos="1:1-5:6" dir="auto">
- <li data-sourcepos="1:1-5:6">
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:4-3:6" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
- <copy-code></copy-code>
- </div>
- <p data-sourcepos="5:4-5:6">bar</p>
- </li>
- </ol>
- wysiwyg: |-
- <ol parens="false"><li><p></p><pre class="content-editor-code-block undefined code highlight"><code>foo</code></pre><p>bar</p></li></ol>
-05_04_00__container_blocks__lists__025:
- canonical: |
- <ul>
- <li>
- <p>foo</p>
- <ul>
- <li>bar</li>
- </ul>
- <p>baz</p>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-4:5" dir="auto">
- <li data-sourcepos="1:1-4:5">
- <p data-sourcepos="1:3-1:5">foo</p>
- <ul data-sourcepos="2:3-3:0">
- <li data-sourcepos="2:3-3:0">bar</li>
- </ul>
- <p data-sourcepos="4:3-4:5">baz</p>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>foo</p><ul bullet="*"><li><p>bar</p></li></ul><p>baz</p></li></ul>
-05_04_00__container_blocks__lists__026:
- canonical: |
- <ul>
- <li>
- <p>a</p>
- <ul>
- <li>b</li>
- <li>c</li>
- </ul>
- </li>
- <li>
- <p>d</p>
- <ul>
- <li>e</li>
- <li>f</li>
- </ul>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-7:5" dir="auto">
- <li data-sourcepos="1:1-4:0">
- <p data-sourcepos="1:3-1:3">a</p>
- <ul data-sourcepos="2:3-4:0">
- <li data-sourcepos="2:3-2:5">b</li>
- <li data-sourcepos="3:3-4:0">c</li>
- </ul>
- </li>
- <li data-sourcepos="5:1-7:5">
- <p data-sourcepos="5:3-5:3">d</p>
- <ul data-sourcepos="6:3-7:5">
- <li data-sourcepos="6:3-6:5">e</li>
- <li data-sourcepos="7:3-7:5">f</li>
- </ul>
- </li>
- </ul>
- wysiwyg: |-
- <ul bullet="*"><li><p>a</p><ul bullet="*"><li><p>b</p></li><li><p>c</p></li></ul></li><li><p>d</p><ul bullet="*"><li><p>e</p></li><li><p>f</p></li></ul></li></ul>
-06_01_00__inlines__001:
- canonical: |
- <p><code>hi</code>lo`</p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto"><code>hi</code>lo`</p>
- wysiwyg: |-
- <p><code>hi</code>lo`</p>
-06_02_00__inlines__backslash_escapes__001:
- canonical: |
- <p>!&quot;#$%&amp;'()*+,-./:;&lt;=&gt;?@[\]^_`{|}~</p>
- static: |-
- <p data-sourcepos="1:1-1:224" dir="auto"><span>!</span>"<span>#</span><span>$</span><span>%</span><span>&amp;</span>'()*+,-./:;&lt;=&gt;?<span>@</span>[\]<span>^</span>_`{|}<span>~</span></p>
- wysiwyg: |-
- <p>!"#$%&amp;'()*+,-./:;&lt;=&gt;?@[\]^_`{|}~</p>
-06_02_00__inlines__backslash_escapes__002:
- canonical: "<p>\\\t\\A\\a\\ \\3\\φ\\«</p>\n"
- static: "<p data-sourcepos=\"1:1-1:16\" dir=\"auto\">\\\t\\A\\a\\ \\3\\φ\\«</p>"
- wysiwyg: "<p>\\\t\\A\\a\\ \\3\\φ\\«</p>"
-06_02_00__inlines__backslash_escapes__003:
- canonical: |
- <p>*not emphasized*
- &lt;br/&gt; not a tag
- [not a link](/foo)
- `not code`
- 1. not a list
- * not a list
- # not a heading
- [foo]: /url &quot;not a reference&quot;
- &amp;ouml; not a character entity</p>
- static: |-
- <p data-sourcepos="1:1-9:50" dir="auto">*not emphasized*
- &lt;br/&gt; not a tag
- <a href="/foo">not a link</a>
- `not code`
- 1. not a list
- * not a list
- <span>#</span> not a heading
- [foo]: /url "not a reference"
- <span>&amp;</span>ouml; not a character entity</p>
- wysiwyg: |-
- <p>*not emphasized*
- &lt;br/&gt; not a tag
- [not a link](/foo)
- `not code`
- 1. not a list
- * not a list
- # not a heading
- [foo]: /url "not a reference"
- &amp;ouml; not a character entity</p>
-06_02_00__inlines__backslash_escapes__004:
- canonical: |
- <p>\<em>emphasis</em></p>
- static: |-
- <p data-sourcepos="1:1-1:12" dir="auto">\<em>emphasis</em></p>
- wysiwyg: |-
- <p>\<em>emphasis</em></p>
-06_02_00__inlines__backslash_escapes__005:
- canonical: |
- <p>foo<br />
- bar</p>
- static: |-
- <p data-sourcepos="1:1-2:3" dir="auto">foo<br>
- bar</p>
- wysiwyg: |-
- <p>foo<br>
- bar</p>
-06_02_00__inlines__backslash_escapes__006:
- canonical: |
- <p><code>\[\`</code></p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto"><code>\[\`</code></p>
- wysiwyg: |-
- <p><code>\[\`</code></p>
-06_02_00__inlines__backslash_escapes__007:
- canonical: |
- <pre><code>\[\]
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-1:8" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\[\]</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>\[\]</code></pre>
-06_02_00__inlines__backslash_escapes__008:
- canonical: |
- <pre><code>\[\]
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\[\]</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>\[\]</code></pre>
-06_02_00__inlines__backslash_escapes__009:
- canonical: |
- <p><a href="http://example.com?find=%5C*">http://example.com?find=\*</a></p>
- static: |-
- <p data-sourcepos="1:1-1:28" dir="auto"><a href="http://example.com?find=%5C*" rel="nofollow noreferrer noopener" target="_blank">http://example.com?find=\*</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://example.com?find=%5C*">http://example.com?find=\*</a></p>
-06_02_00__inlines__backslash_escapes__010:
- canonical: |
- <a href="/bar\/)">
- static: |-
- <a href="/bar%5C/)" rel="nofollow noreferrer noopener" target="_blank"></a>
- wysiwyg: |-
- <p></p>
-06_02_00__inlines__backslash_escapes__011:
- canonical: |
- <p><a href="/bar*" title="ti*tle">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:23" dir="auto"><a href="/bar*" title="ti*tle">foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/bar*" title="ti*tle">foo</a></p>
-06_02_00__inlines__backslash_escapes__012:
- canonical: |
- <p><a href="/bar*" title="ti*tle">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:5" dir="auto"><a href="/bar*" title="ti*tle">foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/bar*" title="ti*tle">foo</a></p>
- <pre>[foo]: /bar* "ti*tle"</pre>
-06_02_00__inlines__backslash_escapes__013:
- canonical: |
- <pre><code class="language-foo+bar">foo
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="foo+bar" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre language="foo+bar" class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
-06_03_00__inlines__entity_and_numeric_character_references__001:
- canonical: |
- <p>  &amp; © Æ Ď
- ¾ ℋ ⅆ
- ∲ ≧̸</p>
- static: |-
- <p data-sourcepos="1:1-3:32" dir="auto">  &amp; © Æ Ď
- ¾ ℋ ⅆ
- ∲ ≧̸</p>
- wysiwyg: |-
- <p>&nbsp; &amp; © Æ Ď
- ¾ ℋ ⅆ
- ∲ ≧̸</p>
-06_03_00__inlines__entity_and_numeric_character_references__002:
- canonical: |
- <p># Ӓ Ϡ �</p>
- static: |-
- <p data-sourcepos="1:1-1:25" dir="auto"># Ӓ Ϡ �</p>
- wysiwyg: |-
- <p># Ӓ Ϡ �</p>
-06_03_00__inlines__entity_and_numeric_character_references__003:
- canonical: |
- <p>&quot; ആ ಫ</p>
- static: |-
- <p data-sourcepos="1:1-1:22" dir="auto">" ആ ಫ</p>
- wysiwyg: |-
- <p>" ആ ಫ</p>
-06_03_00__inlines__entity_and_numeric_character_references__004:
- canonical: |
- <p>&amp;nbsp &amp;x; &amp;#; &amp;#x;
- &amp;#987654321;
- &amp;#abcdef0;
- &amp;ThisIsNotDefined; &amp;hi?;</p>
- static: |-
- <p data-sourcepos="1:1-4:24" dir="auto">&amp;nbsp &amp;x; &amp;#; &amp;#x;
- &amp;#987654321;
- &amp;#abcdef0;
- &amp;ThisIsNotDefined; &amp;hi?;</p>
- wysiwyg: |-
- <p>&amp;nbsp &amp;x; &amp;#; &amp;#x;
- &amp;#987654321;
- &amp;#abcdef0;
- &amp;ThisIsNotDefined; &amp;hi?;</p>
-06_03_00__inlines__entity_and_numeric_character_references__005:
- canonical: |
- <p>&amp;copy</p>
- static: |-
- <p data-sourcepos="1:1-1:5" dir="auto">&amp;copy</p>
- wysiwyg: |-
- <p>&amp;copy</p>
-06_03_00__inlines__entity_and_numeric_character_references__006:
- canonical: |
- <p>&amp;MadeUpEntity;</p>
- static: |-
- <p data-sourcepos="1:1-1:14" dir="auto">&amp;MadeUpEntity;</p>
- wysiwyg: |-
- <p>&amp;MadeUpEntity;</p>
-06_03_00__inlines__entity_and_numeric_character_references__007:
- canonical: |
- <a href="&ouml;&ouml;.html">
- static: |-
- <a href="%C3%B6%C3%B6.html" rel="nofollow noreferrer noopener" target="_blank"></a>
- wysiwyg: |-
- <p></p>
-06_03_00__inlines__entity_and_numeric_character_references__008:
- canonical: |
- <p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:37" dir="auto"><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
-06_03_00__inlines__entity_and_numeric_character_references__009:
- canonical: |
- <p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:5" dir="auto"><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
- <pre>[foo]: /föö "föö"</pre>
-06_03_00__inlines__entity_and_numeric_character_references__010:
- canonical: |
- <pre><code class="language-föö">foo
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="föö" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre language="föö" class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
-06_03_00__inlines__entity_and_numeric_character_references__011:
- canonical: |
- <p><code>f&amp;ouml;&amp;ouml;</code></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><code>f&amp;ouml;&amp;ouml;</code></p>
- wysiwyg: |-
- <p><code>f&amp;ouml;&amp;ouml;</code></p>
-06_03_00__inlines__entity_and_numeric_character_references__012:
- canonical: |
- <pre><code>f&amp;ouml;f&amp;ouml;
- </code></pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:5-1:18" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">f&amp;ouml;f&amp;ouml;</span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre class="content-editor-code-block undefined code highlight"><code>f&amp;ouml;f&amp;ouml;</code></pre>
-06_03_00__inlines__entity_and_numeric_character_references__013:
- canonical: |
- <p>*foo*
- <em>foo</em></p>
- static: |-
- <p data-sourcepos="1:1-2:5" dir="auto">*foo*
- <em>foo</em></p>
- wysiwyg: |-
- <p>*foo*
- <em>foo</em></p>
-06_03_00__inlines__entity_and_numeric_character_references__014:
- canonical: |
- <p>* foo</p>
- <ul>
- <li>foo</li>
- </ul>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto">* foo</p>
- <ul data-sourcepos="3:1-3:5" dir="auto">
- <li data-sourcepos="3:1-3:5">foo</li>
- </ul>
- wysiwyg: |-
- <p>* foo</p>
- <ul bullet="*"><li><p>foo</p></li></ul>
-06_03_00__inlines__entity_and_numeric_character_references__015:
- canonical: |
- <p>foo
-
- bar</p>
- static: |-
- <p data-sourcepos="1:1-1:16" dir="auto">foo
-
- bar</p>
- wysiwyg: |-
- <p>foo
-
- bar</p>
-06_03_00__inlines__entity_and_numeric_character_references__016:
- canonical: "<p>\tfoo</p>\n"
- static: "<p data-sourcepos=\"1:1-1:7\" dir=\"auto\">\tfoo</p>"
- wysiwyg: "<p>\tfoo</p>"
-06_03_00__inlines__entity_and_numeric_character_references__017:
- canonical: |
- <p>[a](url &quot;tit&quot;)</p>
- static: |-
- <p data-sourcepos="1:1-1:24" dir="auto"><a href="url" title="tit">a</a></p>
- wysiwyg: |-
- <p>[a](url "tit")</p>
-06_04_00__inlines__code_spans__001:
- canonical: |
- <p><code>foo</code></p>
- static: |-
- <p data-sourcepos="1:1-1:5" dir="auto"><code>foo</code></p>
- wysiwyg: |-
- <p><code>foo</code></p>
-06_04_00__inlines__code_spans__002:
- canonical: |
- <p><code>foo ` bar</code></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><code>foo ` bar</code></p>
- wysiwyg: |-
- <p><code>foo ` bar</code></p>
-06_04_00__inlines__code_spans__003:
- canonical: |
- <p><code>``</code></p>
- static: |-
- <p data-sourcepos="1:1-1:6" dir="auto"><code>``</code></p>
- wysiwyg: |-
- <p><code>``</code></p>
-06_04_00__inlines__code_spans__004:
- canonical: |
- <p><code> `` </code></p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto"><code> `` </code></p>
- wysiwyg: |-
- <p><code> `` </code></p>
-06_04_00__inlines__code_spans__005:
- canonical: |
- <p><code> a</code></p>
- static: |-
- <p data-sourcepos="1:1-1:4" dir="auto"><code> a</code></p>
- wysiwyg: |-
- <p><code> a</code></p>
-06_04_00__inlines__code_spans__006:
- canonical: |
- <p><code> b </code></p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto"><code> b </code></p>
- wysiwyg: |-
- <p><code>&nbsp;b&nbsp;</code></p>
-06_04_00__inlines__code_spans__007:
- canonical: |
- <p><code> </code>
- <code> </code></p>
- static: |-
- <p data-sourcepos="1:1-2:4" dir="auto"><code> </code>
- <code> </code></p>
- wysiwyg: |-
- <p></p>
-06_04_00__inlines__code_spans__008:
- canonical: |
- <p><code>foo bar baz</code></p>
- static: |-
- <p data-sourcepos="1:1-5:2" dir="auto"><code>foo bar baz</code></p>
- wysiwyg: |-
- <p><code>foo bar baz</code></p>
-06_04_00__inlines__code_spans__009:
- canonical: |
- <p><code>foo </code></p>
- static: |-
- <p data-sourcepos="1:1-3:2" dir="auto"><code>foo </code></p>
- wysiwyg: |-
- <p><code>foo </code></p>
-06_04_00__inlines__code_spans__010:
- canonical: |
- <p><code>foo bar baz</code></p>
- static: |-
- <p data-sourcepos="1:1-2:4" dir="auto"><code>foo bar baz</code></p>
- wysiwyg: |-
- <p><code>foo bar baz</code></p>
-06_04_00__inlines__code_spans__011:
- canonical: |
- <p><code>foo\</code>bar`</p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto"><code>foo\</code>bar`</p>
- wysiwyg: |-
- <p><code>foo\</code>bar`</p>
-06_04_00__inlines__code_spans__012:
- canonical: |
- <p><code>foo`bar</code></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto"><code>foo`bar</code></p>
- wysiwyg: |-
- <p><code>foo`bar</code></p>
-06_04_00__inlines__code_spans__013:
- canonical: |
- <p><code>foo `` bar</code></p>
- static: |-
- <p data-sourcepos="1:1-1:14" dir="auto"><code>foo `` bar</code></p>
- wysiwyg: |-
- <p><code>foo `` bar</code></p>
-06_04_00__inlines__code_spans__014:
- canonical: |
- <p>*foo<code>*</code></p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto">*foo<code>*</code></p>
- wysiwyg: |-
- <p>*foo<code>*</code></p>
-06_04_00__inlines__code_spans__015:
- canonical: |
- <p>[not a <code>link](/foo</code>)</p>
- static: |-
- <p data-sourcepos="1:1-1:20" dir="auto">[not a <code>link](/foo</code>)</p>
- wysiwyg: |-
- <p>[not a <code>link](/foo</code>)</p>
-06_04_00__inlines__code_spans__016:
- canonical: |
- <p><code>&lt;a href=&quot;</code>&quot;&gt;`</p>
- static: |-
- <p data-sourcepos="1:1-1:14" dir="auto"><code>&lt;a href="</code>"&gt;`</p>
- wysiwyg: |-
- <p><code>&lt;a href="</code>"&gt;`</p>
-06_04_00__inlines__code_spans__017:
- canonical: |
- <p><a href="`">`</p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto"><a href="%60" rel="nofollow noreferrer noopener" target="_blank">`</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="`">`</a></p>
-06_04_00__inlines__code_spans__018:
- canonical: |
- <p><code>&lt;http://foo.bar.</code>baz&gt;`</p>
- static: |-
- <p data-sourcepos="1:1-1:23" dir="auto"><code>&lt;http://foo.bar.</code>baz&gt;`</p>
- wysiwyg: |-
- <p><code>&lt;http://foo.bar.</code>baz&gt;`</p>
-06_04_00__inlines__code_spans__019:
- canonical: |
- <p><a href="http://foo.bar.%60baz">http://foo.bar.`baz</a>`</p>
- static: |-
- <p data-sourcepos="1:1-1:22" dir="auto"><a href="http://foo.bar.%60baz" rel="nofollow noreferrer noopener" target="_blank">http://foo.bar.`baz</a>`</p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://foo.bar.%60baz">http://foo.bar.`baz</a>`</p>
-06_04_00__inlines__code_spans__020:
- canonical: |
- <p>```foo``</p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto">```foo``</p>
- wysiwyg: |-
- <p>```foo``</p>
-06_04_00__inlines__code_spans__021:
- canonical: |
- <p>`foo</p>
- static: |-
- <p data-sourcepos="1:1-1:4" dir="auto">`foo</p>
- wysiwyg: |-
- <p>`foo</p>
-06_04_00__inlines__code_spans__022:
- canonical: |
- <p>`foo<code>bar</code></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto">`foo<code>bar</code></p>
- wysiwyg: |-
- <p>`foo<code>bar</code></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__001:
- canonical: |
- <p><em>foo bar</em></p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto"><em>foo bar</em></p>
- wysiwyg: |-
- <p><em>foo bar</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__002:
- canonical: |
- <p>a * foo bar*</p>
- static: |-
- <p data-sourcepos="1:1-1:12" dir="auto">a * foo bar*</p>
- wysiwyg: |-
- <p>a * foo bar*</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__003:
- canonical: |
- <p>a*&quot;foo&quot;*</p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto">a*"foo"*</p>
- wysiwyg: |-
- <p>a*"foo"*</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__004:
- canonical: |
- <p>* a *</p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto">* a *</p>
- wysiwyg: |-
- <p>*&nbsp;a&nbsp;*</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__005:
- canonical: |
- <p>foo<em>bar</em></p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto">foo<em>bar</em></p>
- wysiwyg: |-
- <p>foo<em>bar</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__006:
- canonical: |
- <p>5<em>6</em>78</p>
- static: |-
- <p data-sourcepos="1:1-1:6" dir="auto">5<em>6</em>78</p>
- wysiwyg: |-
- <p>5<em>6</em>78</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__007:
- canonical: |
- <p><em>foo bar</em></p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto"><em>foo bar</em></p>
- wysiwyg: |-
- <p><em>foo bar</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__008:
- canonical: |
- <p>_ foo bar_</p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto">_ foo bar_</p>
- wysiwyg: |-
- <p>_ foo bar_</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__009:
- canonical: |
- <p>a_&quot;foo&quot;_</p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto">a_"foo"_</p>
- wysiwyg: |-
- <p>a_"foo"_</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__010:
- canonical: |
- <p>foo_bar_</p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto">foo_bar_</p>
- wysiwyg: |-
- <p>foo_bar_</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__011:
- canonical: |
- <p>5_6_78</p>
- static: |-
- <p data-sourcepos="1:1-1:6" dir="auto">5_6_78</p>
- wysiwyg: |-
- <p>5_6_78</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__012:
- canonical: |
- <p>приÑтанÑм_ÑтремÑÑ‚ÑÑ_</p>
- static: |-
- <p data-sourcepos="1:1-1:38" dir="auto">приÑтанÑм_ÑтремÑÑ‚ÑÑ_</p>
- wysiwyg: |-
- <p>приÑтанÑм_ÑтремÑÑ‚ÑÑ_</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__013:
- canonical: |
- <p>aa_&quot;bb&quot;_cc</p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto">aa_"bb"_cc</p>
- wysiwyg: |-
- <p>aa_"bb"_cc</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__014:
- canonical: |
- <p>foo-<em>(bar)</em></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto">foo-<em>(bar)</em></p>
- wysiwyg: |-
- <p>foo-<em>(bar)</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__015:
- canonical: |
- <p>_foo*</p>
- static: |-
- <p data-sourcepos="1:1-1:5" dir="auto">_foo*</p>
- wysiwyg: |-
- <p>_foo*</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__016:
- canonical: |
- <p>*foo bar *</p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto">*foo bar *</p>
- wysiwyg: |-
- <p>*foo bar *</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__017:
- canonical: |
- <p>*foo bar
- *</p>
- static: |-
- <p data-sourcepos="1:1-2:1" dir="auto">*foo bar
- *</p>
- wysiwyg: |-
- <p>*foo bar
- *</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__018:
- canonical: |
- <p>*(*foo)</p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto">*(*foo)</p>
- wysiwyg: |-
- <p>*(*foo)</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__019:
- canonical: |
- <p><em>(<em>foo</em>)</em></p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto"><em>(<em>foo</em>)</em></p>
- wysiwyg: |-
- <p><em>(foo</em>)</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__020:
- canonical: |
- <p><em>foo</em>bar</p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto"><em>foo</em>bar</p>
- wysiwyg: |-
- <p><em>foo</em>bar</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__021:
- canonical: |
- <p>_foo bar _</p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto">_foo bar _</p>
- wysiwyg: |-
- <p>_foo bar _</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__022:
- canonical: |
- <p>_(_foo)</p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto">_(_foo)</p>
- wysiwyg: |-
- <p>_(_foo)</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__023:
- canonical: |
- <p><em>(<em>foo</em>)</em></p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto"><em>(<em>foo</em>)</em></p>
- wysiwyg: |-
- <p><em>(foo</em>)</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__024:
- canonical: |
- <p>_foo_bar</p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto">_foo_bar</p>
- wysiwyg: |-
- <p>_foo_bar</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__025:
- canonical: |
- <p>_приÑтанÑм_ÑтремÑÑ‚ÑÑ</p>
- static: |-
- <p data-sourcepos="1:1-1:38" dir="auto">_приÑтанÑм_ÑтремÑÑ‚ÑÑ</p>
- wysiwyg: |-
- <p>_приÑтанÑм_ÑтремÑÑ‚ÑÑ</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__026:
- canonical: |
- <p><em>foo_bar_baz</em></p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto"><em>foo_bar_baz</em></p>
- wysiwyg: |-
- <p><em>foo_bar_baz</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__027:
- canonical: |
- <p><em>(bar)</em>.</p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto"><em>(bar)</em>.</p>
- wysiwyg: |-
- <p><em>(bar)</em>.</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__028:
- canonical: |
- <p><strong>foo bar</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto"><strong>foo bar</strong></p>
- wysiwyg: |-
- <p><strong>foo bar</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__029:
- canonical: |
- <p>** foo bar**</p>
- static: |-
- <p data-sourcepos="1:1-1:12" dir="auto">** foo bar**</p>
- wysiwyg: |-
- <p>** foo bar**</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__030:
- canonical: |
- <p>a**&quot;foo&quot;**</p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto">a**"foo"**</p>
- wysiwyg: |-
- <p>a**"foo"**</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__031:
- canonical: |
- <p>foo<strong>bar</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto">foo<strong>bar</strong></p>
- wysiwyg: |-
- <p>foo<strong>bar</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__032:
- canonical: |
- <p><strong>foo bar</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto"><strong>foo bar</strong></p>
- wysiwyg: |-
- <p><strong>foo bar</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__033:
- canonical: |
- <p>__ foo bar__</p>
- static: |-
- <p data-sourcepos="1:1-1:12" dir="auto">__ foo bar__</p>
- wysiwyg: |-
- <p>__ foo bar__</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__034:
- canonical: |
- <p>__
- foo bar__</p>
- static: |-
- <p data-sourcepos="1:1-2:9" dir="auto">__
- foo bar__</p>
- wysiwyg: |-
- <p>__
- foo bar__</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__035:
- canonical: |
- <p>a__&quot;foo&quot;__</p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto">a__"foo"__</p>
- wysiwyg: |-
- <p>a__"foo"__</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__036:
- canonical: |
- <p>foo__bar__</p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto">foo__bar__</p>
- wysiwyg: |-
- <p>foo__bar__</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__037:
- canonical: |
- <p>5__6__78</p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto">5__6__78</p>
- wysiwyg: |-
- <p>5__6__78</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__038:
- canonical: |
- <p>приÑтанÑм__ÑтремÑÑ‚ÑÑ__</p>
- static: |-
- <p data-sourcepos="1:1-1:40" dir="auto">приÑтанÑм__ÑтремÑÑ‚ÑÑ__</p>
- wysiwyg: |-
- <p>приÑтанÑм__ÑтремÑÑ‚ÑÑ__</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__039:
- canonical: |
- <p><strong>foo, <strong>bar</strong>, baz</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:21" dir="auto"><strong>foo, <strong>bar</strong>, baz</strong></p>
- wysiwyg: |-
- <p><strong>foo, bar</strong>, baz</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__040:
- canonical: |
- <p>foo-<strong>(bar)</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto">foo-<strong>(bar)</strong></p>
- wysiwyg: |-
- <p>foo-<strong>(bar)</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__041:
- canonical: |
- <p>**foo bar **</p>
- static: |-
- <p data-sourcepos="1:1-1:12" dir="auto">**foo bar **</p>
- wysiwyg: |-
- <p>**foo bar **</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__042:
- canonical: |
- <p>**(**foo)</p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto">**(**foo)</p>
- wysiwyg: |-
- <p>**(**foo)</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__043:
- canonical: |
- <p><em>(<strong>foo</strong>)</em></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto"><em>(<strong>foo</strong>)</em></p>
- wysiwyg: |-
- <p><em>(</em><strong><em>foo</em></strong><em>)</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__044:
- canonical: |
- <p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.
- <em>Asclepias physocarpa</em>)</strong></p>
- static: |-
- <p data-sourcepos="1:1-2:25" dir="auto"><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.
- <em>Asclepias physocarpa</em>)</strong></p>
- wysiwyg: |-
- <p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.
- <em>Asclepias physocarpa</em>)</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__045:
- canonical: |
- <p><strong>foo &quot;<em>bar</em>&quot; foo</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:19" dir="auto"><strong>foo "<em>bar</em>" foo</strong></p>
- wysiwyg: |-
- <p><strong>foo "<em>bar</em>" foo</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__046:
- canonical: |
- <p><strong>foo</strong>bar</p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto"><strong>foo</strong>bar</p>
- wysiwyg: |-
- <p><strong>foo</strong>bar</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__047:
- canonical: |
- <p>__foo bar __</p>
- static: |-
- <p data-sourcepos="1:1-1:12" dir="auto">__foo bar __</p>
- wysiwyg: |-
- <p>__foo bar __</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__048:
- canonical: |
- <p>__(__foo)</p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto">__(__foo)</p>
- wysiwyg: |-
- <p>__(__foo)</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__049:
- canonical: |
- <p><em>(<strong>foo</strong>)</em></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto"><em>(<strong>foo</strong>)</em></p>
- wysiwyg: |-
- <p><em>(</em><strong><em>foo</em></strong><em>)</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__050:
- canonical: |
- <p>__foo__bar</p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto">__foo__bar</p>
- wysiwyg: |-
- <p>__foo__bar</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__051:
- canonical: |
- <p>__приÑтанÑм__ÑтремÑÑ‚ÑÑ</p>
- static: |-
- <p data-sourcepos="1:1-1:40" dir="auto">__приÑтанÑм__ÑтремÑÑ‚ÑÑ</p>
- wysiwyg: |-
- <p>__приÑтанÑм__ÑтремÑÑ‚ÑÑ</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__052:
- canonical: |
- <p><strong>foo__bar__baz</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto"><strong>foo__bar__baz</strong></p>
- wysiwyg: |-
- <p><strong>foo__bar__baz</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__053:
- canonical: |
- <p><strong>(bar)</strong>.</p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto"><strong>(bar)</strong>.</p>
- wysiwyg: |-
- <p><strong>(bar)</strong>.</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__054:
- canonical: |
- <p><em>foo <a href="/url">bar</a></em></p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto"><em>foo <a href="/url">bar</a></em></p>
- wysiwyg: |-
- <p><em>foo </em><a target="_blank" rel="noopener noreferrer nofollow" href="/url"><em>bar</em></a></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__055:
- canonical: |
- <p><em>foo
- bar</em></p>
- static: |-
- <p data-sourcepos="1:1-2:4" dir="auto"><em>foo
- bar</em></p>
- wysiwyg: |-
- <p><em>foo
- bar</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__056:
- canonical: |
- <p><em>foo <strong>bar</strong> baz</em></p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto"><em>foo <strong>bar</strong> baz</em></p>
- wysiwyg: |-
- <p><em>foo </em><strong><em>bar</em></strong><em> baz</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__057:
- canonical: |
- <p><em>foo <em>bar</em> baz</em></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><em>foo <em>bar</em> baz</em></p>
- wysiwyg: |-
- <p><em>foo bar</em> baz</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__058:
- canonical: |
- <p><em><em>foo</em> bar</em></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto"><em><em>foo</em> bar</em></p>
- wysiwyg: |-
- <p><em>foo</em> bar</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__059:
- canonical: |
- <p><em>foo <em>bar</em></em></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto"><em>foo <em>bar</em></em></p>
- wysiwyg: |-
- <p><em>foo bar</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__060:
- canonical: |
- <p><em>foo <strong>bar</strong> baz</em></p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto"><em>foo <strong>bar</strong> baz</em></p>
- wysiwyg: |-
- <p><em>foo </em><strong><em>bar</em></strong><em> baz</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__061:
- canonical: |
- <p><em>foo<strong>bar</strong>baz</em></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><em>foo<strong>bar</strong>baz</em></p>
- wysiwyg: |-
- <p><em>foo</em><strong><em>bar</em></strong><em>baz</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__062:
- canonical: |
- <p><em>foo**bar</em></p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto"><em>foo**bar</em></p>
- wysiwyg: |-
- <p><em>foo**bar</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__063:
- canonical: |
- <p><em><strong>foo</strong> bar</em></p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto"><em><strong>foo</strong> bar</em></p>
- wysiwyg: |-
- <p><strong><em>foo</em></strong><em> bar</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__064:
- canonical: |
- <p><em>foo <strong>bar</strong></em></p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto"><em>foo <strong>bar</strong></em></p>
- wysiwyg: |-
- <p><em>foo </em><strong><em>bar</em></strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__065:
- canonical: |
- <p><em>foo<strong>bar</strong></em></p>
- static: |-
- <p data-sourcepos="1:1-1:12" dir="auto"><em>foo<strong>bar</strong></em></p>
- wysiwyg: |-
- <p><em>foo</em><strong><em>bar</em></strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__066:
- canonical: |
- <p>foo<em><strong>bar</strong></em>baz</p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto">foo<em><strong>bar</strong></em>baz</p>
- wysiwyg: |-
- <p>foo<strong><em>bar</em></strong>baz</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__067:
- canonical: |
- <p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>
- static: |-
- <p data-sourcepos="1:1-1:24" dir="auto">foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>
- wysiwyg: |-
- <p>foo<strong>bar</strong>***baz</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__068:
- canonical: |
- <p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>
- static: |-
- <p data-sourcepos="1:1-1:27" dir="auto"><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>
- wysiwyg: |-
- <p><em>foo </em><strong><em>bar baz</em> bim</strong> bop</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__069:
- canonical: |
- <p><em>foo <a href="/url"><em>bar</em></a></em></p>
- static: |-
- <p data-sourcepos="1:1-1:19" dir="auto"><em>foo <a href="/url"><em>bar</em></a></em></p>
- wysiwyg: |-
- <p><em>foo </em><a target="_blank" rel="noopener noreferrer nofollow" href="/url"><em>bar</em></a></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__070:
- canonical: |
- <p>** is not an empty emphasis</p>
- static: |-
- <p data-sourcepos="1:1-1:27" dir="auto">** is not an empty emphasis</p>
- wysiwyg: |-
- <p>** is not an empty emphasis</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__071:
- canonical: |
- <p>**** is not an empty strong emphasis</p>
- static: |-
- <p data-sourcepos="1:1-1:36" dir="auto">**** is not an empty strong emphasis</p>
- wysiwyg: |-
- <p>**** is not an empty strong emphasis</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__072:
- canonical: |
- <p><strong>foo <a href="/url">bar</a></strong></p>
- static: |-
- <p data-sourcepos="1:1-1:19" dir="auto"><strong>foo <a href="/url">bar</a></strong></p>
- wysiwyg: |-
- <p><strong>foo </strong><a target="_blank" rel="noopener noreferrer nofollow" href="/url"><strong>bar</strong></a></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__073:
- canonical: |
- <p><strong>foo
- bar</strong></p>
- static: |-
- <p data-sourcepos="1:1-2:5" dir="auto"><strong>foo
- bar</strong></p>
- wysiwyg: |-
- <p><strong>foo
- bar</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__074:
- canonical: |
- <p><strong>foo <em>bar</em> baz</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto"><strong>foo <em>bar</em> baz</strong></p>
- wysiwyg: |-
- <p><strong>foo <em>bar</em> baz</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__075:
- canonical: |
- <p><strong>foo <strong>bar</strong> baz</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:19" dir="auto"><strong>foo <strong>bar</strong> baz</strong></p>
- wysiwyg: |-
- <p><strong>foo bar</strong> baz</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__076:
- canonical: |
- <p><strong><strong>foo</strong> bar</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><strong><strong>foo</strong> bar</strong></p>
- wysiwyg: |-
- <p><strong>foo</strong> bar</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__077:
- canonical: |
- <p><strong>foo <strong>bar</strong></strong></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><strong>foo <strong>bar</strong></strong></p>
- wysiwyg: |-
- <p><strong>foo bar</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__078:
- canonical: |
- <p><strong>foo <em>bar</em> baz</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto"><strong>foo <em>bar</em> baz</strong></p>
- wysiwyg: |-
- <p><strong>foo <em>bar</em> baz</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__079:
- canonical: |
- <p><strong>foo<em>bar</em>baz</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><strong>foo<em>bar</em>baz</strong></p>
- wysiwyg: |-
- <p><strong>foo<em>bar</em>baz</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__080:
- canonical: |
- <p><strong><em>foo</em> bar</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto"><strong><em>foo</em> bar</strong></p>
- wysiwyg: |-
- <p><strong><em>foo</em> bar</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__081:
- canonical: |
- <p><strong>foo <em>bar</em></strong></p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto"><strong>foo <em>bar</em></strong></p>
- wysiwyg: |-
- <p><strong>foo <em>bar</em></strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__082:
- canonical: |
- <p><strong>foo <em>bar <strong>baz</strong>
- bim</em> bop</strong></p>
- static: |-
- <p data-sourcepos="1:1-2:10" dir="auto"><strong>foo <em>bar <strong>baz</strong>
- bim</em> bop</strong></p>
- wysiwyg: |-
- <p><strong>foo <em>bar baz</em></strong><em>
- bim</em> bop</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__083:
- canonical: |
- <p><strong>foo <a href="/url"><em>bar</em></a></strong></p>
- static: |-
- <p data-sourcepos="1:1-1:21" dir="auto"><strong>foo <a href="/url"><em>bar</em></a></strong></p>
- wysiwyg: |-
- <p><strong>foo </strong><a target="_blank" rel="noopener noreferrer nofollow" href="/url"><strong><em>bar</em></strong></a></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__084:
- canonical: |
- <p>__ is not an empty emphasis</p>
- static: |-
- <p data-sourcepos="1:1-1:27" dir="auto">__ is not an empty emphasis</p>
- wysiwyg: |-
- <p>__ is not an empty emphasis</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__085:
- canonical: |
- <p>____ is not an empty strong emphasis</p>
- static: |-
- <p data-sourcepos="1:1-1:36" dir="auto">____ is not an empty strong emphasis</p>
- wysiwyg: |-
- <p>____ is not an empty strong emphasis</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__086:
- canonical: |
- <p>foo ***</p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto">foo ***</p>
- wysiwyg: |-
- <p>foo ***</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__087:
- canonical: |
- <p>foo <em>*</em></p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto">foo <em>*</em></p>
- wysiwyg: |-
- <p>foo <em>*</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__088:
- canonical: |
- <p>foo <em>_</em></p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto">foo <em>_</em></p>
- wysiwyg: |-
- <p>foo <em>_</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__089:
- canonical: |
- <p>foo *****</p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto">foo *****</p>
- wysiwyg: |-
- <p>foo *****</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__090:
- canonical: |
- <p>foo <strong>*</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto">foo <strong>*</strong></p>
- wysiwyg: |-
- <p>foo <strong>*</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__091:
- canonical: |
- <p>foo <strong>_</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto">foo <strong>_</strong></p>
- wysiwyg: |-
- <p>foo <strong>_</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__092:
- canonical: |
- <p>*<em>foo</em></p>
- static: |-
- <p data-sourcepos="1:1-1:6" dir="auto">*<em>foo</em></p>
- wysiwyg: |-
- <p>*<em>foo</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__093:
- canonical: |
- <p><em>foo</em>*</p>
- static: |-
- <p data-sourcepos="1:1-1:6" dir="auto"><em>foo</em>*</p>
- wysiwyg: |-
- <p><em>foo</em>*</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__094:
- canonical: |
- <p>*<strong>foo</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto">*<strong>foo</strong></p>
- wysiwyg: |-
- <p>*<strong>foo</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__095:
- canonical: |
- <p>***<em>foo</em></p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto">***<em>foo</em></p>
- wysiwyg: |-
- <p>***<em>foo</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__096:
- canonical: |
- <p><strong>foo</strong>*</p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto"><strong>foo</strong>*</p>
- wysiwyg: |-
- <p><strong>foo</strong>*</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__097:
- canonical: |
- <p><em>foo</em>***</p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto"><em>foo</em>***</p>
- wysiwyg: |-
- <p><em>foo</em>***</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__098:
- canonical: |
- <p>foo ___</p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto">foo ___</p>
- wysiwyg: |-
- <p>foo ___</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__099:
- canonical: |
- <p>foo <em>_</em></p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto">foo <em>_</em></p>
- wysiwyg: |-
- <p>foo <em>_</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__100:
- canonical: |
- <p>foo <em>*</em></p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto">foo <em>*</em></p>
- wysiwyg: |-
- <p>foo <em>*</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__101:
- canonical: |
- <p>foo _____</p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto">foo _____</p>
- wysiwyg: |-
- <p>foo _____</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__102:
- canonical: |
- <p>foo <strong>_</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto">foo <strong>_</strong></p>
- wysiwyg: |-
- <p>foo <strong>_</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__103:
- canonical: |
- <p>foo <strong>*</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto">foo <strong>*</strong></p>
- wysiwyg: |-
- <p>foo <strong>*</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__104:
- canonical: |
- <p>_<em>foo</em></p>
- static: |-
- <p data-sourcepos="1:1-1:6" dir="auto">_<em>foo</em></p>
- wysiwyg: |-
- <p>_<em>foo</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__105:
- canonical: |
- <p><em>foo</em>_</p>
- static: |-
- <p data-sourcepos="1:1-1:6" dir="auto"><em>foo</em>_</p>
- wysiwyg: |-
- <p><em>foo</em>_</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__106:
- canonical: |
- <p>_<strong>foo</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto">_<strong>foo</strong></p>
- wysiwyg: |-
- <p>_<strong>foo</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__107:
- canonical: |
- <p>___<em>foo</em></p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto">___<em>foo</em></p>
- wysiwyg: |-
- <p>___<em>foo</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__108:
- canonical: |
- <p><strong>foo</strong>_</p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto"><strong>foo</strong>_</p>
- wysiwyg: |-
- <p><strong>foo</strong>_</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__109:
- canonical: |
- <p><em>foo</em>___</p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto"><em>foo</em>___</p>
- wysiwyg: |-
- <p><em>foo</em>___</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__110:
- canonical: |
- <p><strong>foo</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto"><strong>foo</strong></p>
- wysiwyg: |-
- <p><strong>foo</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__111:
- canonical: |
- <p><em><em>foo</em></em></p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto"><em><em>foo</em></em></p>
- wysiwyg: |-
- <p><em>foo</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__112:
- canonical: |
- <p><strong>foo</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto"><strong>foo</strong></p>
- wysiwyg: |-
- <p><strong>foo</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__113:
- canonical: |
- <p><em><em>foo</em></em></p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto"><em><em>foo</em></em></p>
- wysiwyg: |-
- <p><em>foo</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__114:
- canonical: |
- <p><strong><strong>foo</strong></strong></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto"><strong><strong>foo</strong></strong></p>
- wysiwyg: |-
- <p><strong>foo</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__115:
- canonical: |
- <p><strong><strong>foo</strong></strong></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto"><strong><strong>foo</strong></strong></p>
- wysiwyg: |-
- <p><strong>foo</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__116:
- canonical: |
- <p><strong><strong><strong>foo</strong></strong></strong></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><strong><strong><strong>foo</strong></strong></strong></p>
- wysiwyg: |-
- <p><strong>foo</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__117:
- canonical: |
- <p><em><strong>foo</strong></em></p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto"><em><strong>foo</strong></em></p>
- wysiwyg: |-
- <p><strong><em>foo</em></strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__118:
- canonical: |
- <p><em><strong><strong>foo</strong></strong></em></p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto"><em><strong><strong>foo</strong></strong></em></p>
- wysiwyg: |-
- <p><strong><em>foo</em></strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__119:
- canonical: |
- <p><em>foo _bar</em> baz_</p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><em>foo _bar</em> baz_</p>
- wysiwyg: |-
- <p><em>foo _bar</em> baz_</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__120:
- canonical: |
- <p><em>foo <strong>bar *baz bim</strong> bam</em></p>
- static: |-
- <p data-sourcepos="1:1-1:26" dir="auto"><em>foo <strong>bar *baz bim</strong> bam</em></p>
- wysiwyg: |-
- <p><em>foo </em><strong><em>bar *baz bim</em></strong><em> bam</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__121:
- canonical: |
- <p>**foo <strong>bar baz</strong></p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto">**foo <strong>bar baz</strong></p>
- wysiwyg: |-
- <p>**foo <strong>bar baz</strong></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__122:
- canonical: |
- <p>*foo <em>bar baz</em></p>
- static: |-
- <p data-sourcepos="1:1-1:14" dir="auto">*foo <em>bar baz</em></p>
- wysiwyg: |-
- <p>*foo <em>bar baz</em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__123:
- canonical: |
- <p>*<a href="/url">bar*</a></p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto">*<a href="/url">bar*</a></p>
- wysiwyg: |-
- <p>*<a target="_blank" rel="noopener noreferrer nofollow" href="/url">bar*</a></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__124:
- canonical: |
- <p>_foo <a href="/url">bar_</a></p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto">_foo <a href="/url">bar_</a></p>
- wysiwyg: |-
- <p>_foo <a target="_blank" rel="noopener noreferrer nofollow" href="/url">bar_</a></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__125:
- canonical: |
- <p>*<img src="foo" title="*"/></p>
- static: |-
- <p data-sourcepos="1:1-1:27" dir="auto">*<a class="no-attachment-icon" href="foo" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" title="*" decoding="async" class="lazy" data-src="foo"></a></p>
- wysiwyg: |-
- <p>*<img src="foo" title="*"></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__126:
- canonical: |
- <p>**<a href="**"></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto">**<a href="**"></a></p>
- wysiwyg: |-
- <p>**</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__127:
- canonical: |
- <p>__<a href="__"></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto">__<a href="__"></a></p>
- wysiwyg: |-
- <p>__</p>
-06_05_00__inlines__emphasis_and_strong_emphasis__128:
- canonical: |
- <p><em>a <code>*</code></em></p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto"><em>a <code>*</code></em></p>
- wysiwyg: |-
- <p><em>a <code>*</code></em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__129:
- canonical: |
- <p><em>a <code>_</code></em></p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto"><em>a <code>_</code></em></p>
- wysiwyg: |-
- <p><em>a <code>_</code></em></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__130:
- canonical: |
- <p>**a<a href="http://foo.bar/?q=**">http://foo.bar/?q=**</a></p>
- static: |-
- <p data-sourcepos="1:1-1:25" dir="auto">**a<a href="http://foo.bar/?q=**" rel="nofollow noreferrer noopener" target="_blank">http://foo.bar/?q=**</a></p>
- wysiwyg: |-
- <p>**a<a target="_blank" rel="noopener noreferrer nofollow" href="http://foo.bar/?q=**">http://foo.bar/?q=**</a></p>
-06_05_00__inlines__emphasis_and_strong_emphasis__131:
- canonical: |
- <p>__a<a href="http://foo.bar/?q=__">http://foo.bar/?q=__</a></p>
- static: |-
- <p data-sourcepos="1:1-1:25" dir="auto">__a<a href="http://foo.bar/?q=__" rel="nofollow noreferrer noopener" target="_blank">http://foo.bar/?q=__</a></p>
- wysiwyg: |-
- <p>__a<a target="_blank" rel="noopener noreferrer nofollow" href="http://foo.bar/?q=__">http://foo.bar/?q=__</a></p>
-06_06_00__inlines__strikethrough_extension__001:
- canonical: |
- <p><del>Hi</del> Hello, world!</p>
- static: |-
- <p data-sourcepos="1:1-1:20" dir="auto"><del>Hi</del> Hello, world!</p>
- wysiwyg: |-
- <p><s>Hi</s> Hello, world!</p>
-06_06_00__inlines__strikethrough_extension__002:
- canonical: |
- <p>This ~~has a</p>
- <p>new paragraph~~.</p>
- static: |-
- <p data-sourcepos="1:1-1:12" dir="auto">This ~~has a</p>
- <p data-sourcepos="3:1-3:16" dir="auto">new paragraph~~.</p>
- wysiwyg: |-
- <p>This ~~has a</p>
- <p>new paragraph~~.</p>
-06_07_00__inlines__links__001:
- canonical: |
- <p><a href="/uri" title="title">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:20" dir="auto"><a href="/uri" title="title">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri" title="title">link</a></p>
-06_07_00__inlines__links__002:
- canonical: |
- <p><a href="/uri">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:12" dir="auto"><a href="/uri">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">link</a></p>
-06_07_00__inlines__links__003:
- canonical: |
- <p><a href="">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto"><a href="">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="">link</a></p>
-06_07_00__inlines__links__004:
- canonical: |
- <p><a href="">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto"><a href="">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="">link</a></p>
-06_07_00__inlines__links__005:
- canonical: |
- <p>[link](/my uri)</p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><a href="/my%20uri">link</a></p>
- wysiwyg: |-
- <p>[link](/my uri)</p>
-06_07_00__inlines__links__006:
- canonical: |
- <p><a href="/my%20uri">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto"><a href="/my%20uri">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/my%20uri">link</a></p>
-06_07_00__inlines__links__007:
- canonical: |
- <p>[link](foo
- bar)</p>
- static: |-
- <p data-sourcepos="1:1-2:4" dir="auto">[link](foo
- bar)</p>
- wysiwyg: |-
- <p>[link](foo
- bar)</p>
-06_07_00__inlines__links__008:
- canonical: |
- <p>[link](<foo
- bar>)</p>
- static: |-
- <p data-sourcepos="1:1-2:5" dir="auto">[link]()</p>
- wysiwyg: |-
- <p>[link](</p>
-06_07_00__inlines__links__009:
- canonical: |
- <p><a href="b)c">a</a></p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto"><a href="b)c">a</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="b)c">a</a></p>
-06_07_00__inlines__links__010:
- canonical: |
- <p>[link](&lt;foo&gt;)</p>
- static: |-
- <p data-sourcepos="1:1-1:14" dir="auto"><a href="%3Cfoo%3E">link</a></p>
- wysiwyg: |-
- <p>[link](&lt;foo&gt;)</p>
-06_07_00__inlines__links__011:
- canonical: |
- <p>[a](&lt;b)c
- [a](&lt;b)c&gt;
- [a](<b>c)</p>
- static: |-
- <p data-sourcepos="1:1-3:9" dir="auto"><a href="%3Cb">a</a>c
- <a href="%3Cb">a</a>c&gt;
- [a](<b>c)</b></p>
- wysiwyg: |-
- <p>[a](&lt;b)c
- [a](&lt;b)c&gt;
- [a](<strong>c)</strong></p>
-06_07_00__inlines__links__012:
- canonical: |
- <p><a href="(foo)">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><a href="(foo)">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="(foo)">link</a></p>
-06_07_00__inlines__links__013:
- canonical: |
- <p><a href="foo(and(bar))">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:21" dir="auto"><a href="foo(and(bar))">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="foo(and(bar))">link</a></p>
-06_07_00__inlines__links__014:
- canonical: |
- <p><a href="foo(and(bar)">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:23" dir="auto"><a href="foo(and(bar)">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="foo(and(bar)">link</a></p>
-06_07_00__inlines__links__015:
- canonical: |
- <p><a href="foo(and(bar)">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:22" dir="auto"><a href="foo(and(bar)">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="foo(and(bar)">link</a></p>
-06_07_00__inlines__links__016:
- canonical: |
- <p><a href="foo):">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><a>link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="foo):">link</a></p>
-06_07_00__inlines__links__017:
- canonical: |
- <p><a href="#fragment">link</a></p>
- <p><a href="http://example.com#fragment">link</a></p>
- <p><a href="http://example.com?foo=3#frag">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto"><a href="#fragment">link</a></p>
- <p data-sourcepos="3:1-3:35" dir="auto"><a href="http://example.com#fragment" rel="nofollow noreferrer noopener" target="_blank">link</a></p>
- <p data-sourcepos="5:1-5:37" dir="auto"><a href="http://example.com?foo=3#frag" rel="nofollow noreferrer noopener" target="_blank">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="#fragment">link</a></p>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://example.com#fragment">link</a></p>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://example.com?foo=3#frag">link</a></p>
-06_07_00__inlines__links__018:
- canonical: |
- <p><a href="foo%5Cbar">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><a href="foo%5Cbar">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="foo%5Cbar">link</a></p>
-06_07_00__inlines__links__019:
- canonical: |
- <p><a href="foo%20b%C3%A4">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:21" dir="auto"><a href="foo%20b%C3%A4">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="foo%20b%C3%A4">link</a></p>
-06_07_00__inlines__links__020:
- canonical: |
- <p><a href="%22title%22">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><a href="%22title%22">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="%22title%22">link</a></p>
-06_07_00__inlines__links__021:
- canonical: |
- <p><a href="/url" title="title">link</a>
- <a href="/url" title="title">link</a>
- <a href="/url" title="title">link</a></p>
- static: |-
- <p data-sourcepos="1:1-3:20" dir="auto"><a href="/url" title="title">link</a>
- <a href="/url" title="title">link</a>
- <a href="/url" title="title">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">linklinklink</a></p>
-06_07_00__inlines__links__022:
- canonical: |
- <p><a href="/url" title="title &quot;&quot;">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:29" dir="auto"><a href="/url" title='title ""'>link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title &quot;&quot;">link</a></p>
-06_07_00__inlines__links__023:
- canonical: |
- <p><a href="/url%C2%A0%22title%22">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:21" dir="auto"><a href="/url%C2%A0%22title%22">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url%C2%A0%22title%22">link</a></p>
-06_07_00__inlines__links__024:
- canonical: |
- <p>[link](/url &quot;title &quot;and&quot; title&quot;)</p>
- static: |-
- <p data-sourcepos="1:1-1:32" dir="auto">[link](/url "title "and" title")</p>
- wysiwyg: |-
- <p>[link](/url "title "and" title")</p>
-06_07_00__inlines__links__025:
- canonical: |
- <p><a href="/url" title="title &quot;and&quot; title">link</a></p>
- static: |-
- <p data-sourcepos="1:1-1:32" dir="auto"><a href="/url" title='title "and" title'>link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title &quot;and&quot; title">link</a></p>
-06_07_00__inlines__links__026:
- canonical: |
- <p><a href="/uri" title="title">link</a></p>
- static: |-
- <p data-sourcepos="1:1-2:12" dir="auto"><a href="/uri" title="title">link</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri" title="title">link</a></p>
-06_07_00__inlines__links__027:
- canonical: |
- <p>[link] (/uri)</p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto">[link] (/uri)</p>
- wysiwyg: |-
- <p>[link] (/uri)</p>
-06_07_00__inlines__links__028:
- canonical: |
- <p><a href="/uri">link [foo [bar]]</a></p>
- static: |-
- <p data-sourcepos="1:1-1:24" dir="auto"><a href="/uri">link [foo [bar]]</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">link [foo [bar]]</a></p>
-06_07_00__inlines__links__029:
- canonical: |
- <p>[link] bar](/uri)</p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto">[link] bar](/uri)</p>
- wysiwyg: |-
- <p>[link] bar](/uri)</p>
-06_07_00__inlines__links__030:
- canonical: |
- <p>[link <a href="/uri">bar</a></p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto">[link <a href="/uri">bar</a></p>
- wysiwyg: |-
- <p>[link <a target="_blank" rel="noopener noreferrer nofollow" href="/uri">bar</a></p>
-06_07_00__inlines__links__031:
- canonical: |
- <p><a href="/uri">link [bar</a></p>
- static: |-
- <p data-sourcepos="1:1-1:18" dir="auto"><a href="/uri">link [bar</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">link [bar</a></p>
-06_07_00__inlines__links__032:
- canonical: |
- <p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
- static: |-
- <p data-sourcepos="1:1-1:30" dir="auto"><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">link <em>foo </em><strong><em>bar<code>#</code></em></strong></a></p>
-06_07_00__inlines__links__033:
- canonical: |
- <p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
- static: |-
- <p data-sourcepos="1:1-1:25" dir="auto"><a href="/uri"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="moon" decoding="async" class="lazy" data-src="moon.jpg"></a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri"><img src="moon.jpg" alt="moon"></a></p>
-06_07_00__inlines__links__034:
- canonical: |
- <p>[foo <a href="/uri">bar</a>](/uri)</p>
- static: |-
- <p data-sourcepos="1:1-1:23" dir="auto">[foo <a href="/uri">bar</a>](/uri)</p>
- wysiwyg: |-
- <p>[foo <a target="_blank" rel="noopener noreferrer nofollow" href="/uri">bar</a>](/uri)</p>
-06_07_00__inlines__links__035:
- canonical: |
- <p>[foo <em>[bar <a href="/uri">baz</a>](/uri)</em>](/uri)</p>
- static: |-
- <p data-sourcepos="1:1-1:37" dir="auto">[foo <em>[bar <a href="/uri">baz</a>](/uri)</em>](/uri)</p>
- wysiwyg: |-
- <p>[foo <em>[bar </em><a target="_blank" rel="noopener noreferrer nofollow" href="/uri"><em>baz</em></a><em>](/uri)</em>](/uri)</p>
-06_07_00__inlines__links__036:
- canonical: |
- <p><img src="uri3" alt="[foo](uri2)" /></p>
- static: |-
- <p data-sourcepos="1:1-1:28" dir="auto"><a class="no-attachment-icon" href="uri3" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="[foo](uri2)" decoding="async" class="lazy" data-src="uri3"></a></p>
- wysiwyg: |-
- <p><img src="uri3" alt="[foo](uri2)"></p>
-06_07_00__inlines__links__037:
- canonical: |
- <p>*<a href="/uri">foo*</a></p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto">*<a href="/uri">foo*</a></p>
- wysiwyg: |-
- <p>*<a target="_blank" rel="noopener noreferrer nofollow" href="/uri">foo*</a></p>
-06_07_00__inlines__links__038:
- canonical: |
- <p><a href="baz*">foo *bar</a></p>
- static: |-
- <p data-sourcepos="1:1-1:16" dir="auto"><a href="baz*">foo *bar</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="baz*">foo *bar</a></p>
-06_07_00__inlines__links__039:
- canonical: |
- <p><em>foo [bar</em> baz]</p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><em>foo [bar</em> baz]</p>
- wysiwyg: |-
- <p><em>foo [bar</em> baz]</p>
-06_07_00__inlines__links__040:
- canonical: |
- <p>[foo <bar attr="](baz)"></p>
- static: |-
- <p data-sourcepos="1:1-1:24" dir="auto">[foo </p>
- wysiwyg: |-
- <p>[foo </p>
-06_07_00__inlines__links__041:
- canonical: |
- <p>[foo<code>](/uri)</code></p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto">[foo<code>](/uri)</code></p>
- wysiwyg: |-
- <p>[foo<code>](/uri)</code></p>
-06_07_00__inlines__links__042:
- canonical: |
- <p>[foo<a href="http://example.com/?search=%5D(uri)">http://example.com/?search=](uri)</a></p>
- static: |-
- <p data-sourcepos="1:1-1:39" dir="auto">[foo<a href="http://example.com/?search=%5D(uri)" rel="nofollow noreferrer noopener" target="_blank">http://example.com/?search=](uri)</a></p>
- wysiwyg: |-
- <p>[foo<a target="_blank" rel="noopener noreferrer nofollow" href="http://example.com/?search=%5D(uri)">http://example.com/?search=](uri)</a></p>
-06_07_00__inlines__links__043:
- canonical: |
- <p><a href="/url" title="title">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto"><a href="/url" title="title">foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">foo</a></p>
- <pre>[bar]: /url "title"</pre>
-06_07_00__inlines__links__044:
- canonical: |
- <p><a href="/uri">link [foo [bar]]</a></p>
- static: |-
- <p data-sourcepos="1:1-1:23" dir="auto"><a href="/uri">link [foo [bar]]</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">link [foo [bar]]</a></p>
- <pre>[ref]: /uri</pre>
-06_07_00__inlines__links__045:
- canonical: |
- <p><a href="/uri">link [bar</a></p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto"><a href="/uri">link [bar</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">link [bar</a></p>
- <pre>[ref]: /uri</pre>
-06_07_00__inlines__links__046:
- canonical: |
- <p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
- static: |-
- <p data-sourcepos="1:1-1:29" dir="auto"><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">link <em>foo </em><strong><em>bar<code>#</code></em></strong></a></p>
- <pre>[ref]: /uri</pre>
-06_07_00__inlines__links__047:
- canonical: |
- <p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
- static: |-
- <p data-sourcepos="1:1-1:24" dir="auto"><a href="/uri"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="moon" decoding="async" class="lazy" data-src="moon.jpg"></a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri"><img src="moon.jpg" alt="moon"></a></p>
- <pre>[ref]: /uri</pre>
-06_07_00__inlines__links__048:
- canonical: |
- <p>[foo <a href="/uri">bar</a>]<a href="/uri">ref</a></p>
- static: |-
- <p data-sourcepos="1:1-1:22" dir="auto">[foo <a href="/uri">bar</a>]<a href="/uri">ref</a></p>
- wysiwyg: |-
- <p>[foo <a target="_blank" rel="noopener noreferrer nofollow" href="/uri">bar</a>]<a target="_blank" rel="noopener noreferrer nofollow" href="/uri">ref</a></p>
- <pre>[ref]: /uri</pre>
-06_07_00__inlines__links__049:
- canonical: |
- <p>[foo <em>bar <a href="/uri">baz</a></em>]<a href="/uri">ref</a></p>
- static: |-
- <p data-sourcepos="1:1-1:27" dir="auto">[foo <em>bar <a href="/uri">baz</a></em>]<a href="/uri">ref</a></p>
- wysiwyg: |-
- <p>[foo <em>bar </em><a target="_blank" rel="noopener noreferrer nofollow" href="/uri"><em>baz</em></a>]<a target="_blank" rel="noopener noreferrer nofollow" href="/uri">ref</a></p>
- <pre>[ref]: /uri</pre>
-06_07_00__inlines__links__050:
- canonical: |
- <p>*<a href="/uri">foo*</a></p>
- static: |-
- <p data-sourcepos="1:1-1:12" dir="auto">*<a href="/uri">foo*</a></p>
- wysiwyg: |-
- <p>*<a target="_blank" rel="noopener noreferrer nofollow" href="/uri">foo*</a></p>
- <pre>[ref]: /uri</pre>
-06_07_00__inlines__links__051:
- canonical: |
- <p><a href="/uri">foo *bar</a></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><a href="/uri">foo *bar</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">foo *bar</a></p>
- <pre>[ref]: /uri</pre>
-06_07_00__inlines__links__052:
- canonical: |
- <p>[foo <bar attr="][ref]"></p>
- static: |-
- <p data-sourcepos="1:1-1:24" dir="auto">[foo </p>
- wysiwyg: |-
- <p>[foo </p>
- <pre>[ref]: /uri</pre>
-06_07_00__inlines__links__053:
- canonical: |
- <p>[foo<code>][ref]</code></p>
- static: |-
- <p data-sourcepos="1:1-1:12" dir="auto">[foo<code>][ref]</code></p>
- wysiwyg: |-
- <p>[foo<code>][ref]</code></p>
- <pre>[ref]: /uri</pre>
-06_07_00__inlines__links__054:
- canonical: |
- <p>[foo<a href="http://example.com/?search=%5D%5Bref%5D">http://example.com/?search=][ref]</a></p>
- static: |-
- <p data-sourcepos="1:1-1:39" dir="auto">[foo<a href="http://example.com/?search=%5D%5Bref%5D" rel="nofollow noreferrer noopener" target="_blank">http://example.com/?search=][ref]</a></p>
- wysiwyg: |-
- <p>[foo<a target="_blank" rel="noopener noreferrer nofollow" href="http://example.com/?search=%5D%5Bref%5D">http://example.com/?search=][ref]</a></p>
- <pre>[ref]: /uri</pre>
-06_07_00__inlines__links__055:
- canonical: |
- <p><a href="/url" title="title">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto"><a href="/url" title="title">foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">foo</a></p>
- <pre>[bar]: /url "title"</pre>
-06_07_00__inlines__links__056:
- canonical: |
- <p><a href="/url">Толпой</a> is a Russian word.</p>
- static: |-
- <p data-sourcepos="1:1-1:47" dir="auto"><a href="/url">Толпой</a> is a Russian word.</p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url">Толпой</a> is a Russian word.</p>
- <pre>[толпой]: /url</pre>
-06_07_00__inlines__links__057:
- canonical: |
- <p><a href="/url">Baz</a></p>
- static: |-
- <p data-sourcepos="4:1-4:14" dir="auto"><a href="/url">Baz</a></p>
- wysiwyg: |-
- <pre>[foo bar]: /url</pre>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url">Baz</a></p>
-06_07_00__inlines__links__058:
- canonical: |
- <p>[foo] <a href="/url" title="title">bar</a></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto">[foo] <a href="/url" title="title">bar</a></p>
- wysiwyg: |-
- <p>[foo] <a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">bar</a></p>
- <pre>[bar]: /url "title"</pre>
-06_07_00__inlines__links__059:
- canonical: |
- <p>[foo]
- <a href="/url" title="title">bar</a></p>
- static: |-
- <p data-sourcepos="1:1-2:5" dir="auto">[foo]
- <a href="/url" title="title">bar</a></p>
- wysiwyg: |-
- <p>[foo]
- <a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">bar</a></p>
- <pre>[bar]: /url "title"</pre>
-06_07_00__inlines__links__060:
- canonical: |
- <p><a href="/url1">bar</a></p>
- static: |-
- <p data-sourcepos="5:1-5:10" dir="auto"><a href="/url1">bar</a></p>
- wysiwyg: |-
- <pre>[foo]: /url1</pre>
- <pre>[foo]: /url2</pre>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url1">bar</a></p>
-06_07_00__inlines__links__061:
- canonical: |
- <p>[bar][foo!]</p>
- static: |-
- <p data-sourcepos="1:1-1:32" dir="auto">[bar][foo<span>!</span>]</p>
- wysiwyg: |-
- <p>[bar][foo!]</p>
- <pre>[foo!]: /url</pre>
-06_07_00__inlines__links__062:
- canonical: |
- <p>[foo][ref[]</p>
- <p>[ref[]: /uri</p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto">[foo][ref[]</p>
- <p data-sourcepos="3:1-3:12" dir="auto">[ref[]: /uri</p>
- wysiwyg: |-
- <p>[foo][ref[]</p>
- <p>[ref[]: /uri</p>
-06_07_00__inlines__links__063:
- canonical: |
- <p>[foo][ref[bar]]</p>
- <p>[ref[bar]]: /uri</p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto">[foo][ref[bar]]</p>
- <p data-sourcepos="3:1-3:16" dir="auto">[ref[bar]]: /uri</p>
- wysiwyg: |-
- <p>[foo][ref[bar]]</p>
- <p>[ref[bar]]: /uri</p>
-06_07_00__inlines__links__064:
- canonical: |
- <p>[[[foo]]]</p>
- <p>[[[foo]]]: /url</p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto">[[[foo]]]</p>
- <p data-sourcepos="3:1-3:15" dir="auto">[[[foo]]]: /url</p>
- wysiwyg: |-
- <p>[[[foo]]]</p>
- <p>[[[foo]]]: /url</p>
-06_07_00__inlines__links__065:
- canonical: |
- <p><a href="/uri">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:12" dir="auto"><a href="/uri">foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">foo</a></p>
- <pre>[ref\[]: /uri</pre>
-06_07_00__inlines__links__066:
- canonical: |
- <p><a href="/uri">bar\</a></p>
- static: |-
- <p data-sourcepos="3:1-3:7" dir="auto"><a href="/uri">bar\</a></p>
- wysiwyg: |-
- <pre>[bar\\]: /uri</pre>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">bar\</a></p>
-06_07_00__inlines__links__067:
- canonical: |
- <p>[]</p>
- <p>[]: /uri</p>
- static: |-
- <p data-sourcepos="1:1-1:2" dir="auto">[]</p>
- <p data-sourcepos="3:1-3:8" dir="auto">[]: /uri</p>
- wysiwyg: |-
- <p>[]</p>
- <p>[]: /uri</p>
-06_07_00__inlines__links__068:
- canonical: |
- <p>[
- ]</p>
- <p>[
- ]: /uri</p>
- static: |-
- <p data-sourcepos="1:1-2:2" dir="auto">[
- ]</p>
- <p data-sourcepos="4:1-5:8" dir="auto">[
- ]: /uri</p>
- wysiwyg: |-
- <p>[
- ]</p>
- <p>[
- ]: /uri</p>
-06_07_00__inlines__links__069:
- canonical: |
- <p><a href="/url" title="title">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto"><a href="/url" title="title">foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">foo</a></p>
- <pre>[foo]: /url "title"</pre>
-06_07_00__inlines__links__070:
- canonical: |
- <p><a href="/url" title="title"><em>foo</em> bar</a></p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto"><a href="/url" title="title"><em>foo</em> bar</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title"><em>foo</em> bar</a></p>
- <pre>[*foo* bar]: /url "title"</pre>
-06_07_00__inlines__links__071:
- canonical: |
- <p><a href="/url" title="title">Foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto"><a href="/url" title="title">Foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">Foo</a></p>
- <pre>[foo]: /url "title"</pre>
-06_07_00__inlines__links__072:
- canonical: |
- <p><a href="/url" title="title">foo</a>
- []</p>
- static: |-
- <p data-sourcepos="1:1-2:2" dir="auto"><a href="/url" title="title">foo</a>
- []</p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">foo</a>
- []</p>
- <pre>[foo]: /url "title"</pre>
-06_07_00__inlines__links__073:
- canonical: |
- <p><a href="/url" title="title">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:5" dir="auto"><a href="/url" title="title">foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">foo</a></p>
- <pre>[foo]: /url "title"</pre>
-06_07_00__inlines__links__074:
- canonical: |
- <p><a href="/url" title="title"><em>foo</em> bar</a></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto"><a href="/url" title="title"><em>foo</em> bar</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title"><em>foo</em> bar</a></p>
- <pre>[*foo* bar]: /url "title"</pre>
-06_07_00__inlines__links__075:
- canonical: |
- <p>[<a href="/url" title="title"><em>foo</em> bar</a>]</p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto">[<a href="/url" title="title"><em>foo</em> bar</a>]</p>
- wysiwyg: |-
- <p>[<a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title"><em>foo</em> bar</a>]</p>
- <pre>[*foo* bar]: /url "title"</pre>
-06_07_00__inlines__links__076:
- canonical: |
- <p>[[bar <a href="/url">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto">[[bar <a href="/url">foo</a></p>
- wysiwyg: |-
- <p>[[bar <a target="_blank" rel="noopener noreferrer nofollow" href="/url">foo</a></p>
- <pre>[foo]: /url</pre>
-06_07_00__inlines__links__077:
- canonical: |
- <p><a href="/url" title="title">Foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:5" dir="auto"><a href="/url" title="title">Foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">Foo</a></p>
- <pre>[foo]: /url "title"</pre>
-06_07_00__inlines__links__078:
- canonical: |
- <p><a href="/url">foo</a> bar</p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto"><a href="/url">foo</a> bar</p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url">foo</a> bar</p>
- <pre>[foo]: /url</pre>
-06_07_00__inlines__links__079:
- canonical: |
- <p>[foo]</p>
- static: |-
- <p data-sourcepos="1:1-1:6" dir="auto">[foo]</p>
- wysiwyg: |-
- <p>[foo]</p>
- <pre>[foo]: /url "title"</pre>
-06_07_00__inlines__links__080:
- canonical: |
- <p>*<a href="/url">foo*</a></p>
- static: |-
- <p data-sourcepos="3:1-3:7" dir="auto">*<a href="/url">foo*</a></p>
- wysiwyg: |-
- <pre>[foo*]: /url</pre>
- <p>*<a target="_blank" rel="noopener noreferrer nofollow" href="/url">foo*</a></p>
-06_07_00__inlines__links__081:
- canonical: |
- <p><a href="/url2">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:10" dir="auto"><a href="/url2">foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url2">foo</a></p>
- <pre>[foo]: /url1</pre>
- <pre>[bar]: /url2</pre>
-06_07_00__inlines__links__082:
- canonical: |
- <p><a href="/url1">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto"><a href="/url1">foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url1">foo</a></p>
- <pre>[foo]: /url1</pre>
-06_07_00__inlines__links__083:
- canonical: |
- <p><a href="">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto"><a href="">foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="">foo</a></p>
- <pre>[foo]: /url1</pre>
-06_07_00__inlines__links__084:
- canonical: |
- <p><a href="/url1">foo</a>(not a link)</p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto"><a href="/url1">foo</a>(not a link)</p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url1">foo</a>(not a link)</p>
- <pre>[foo]: /url1</pre>
-06_07_00__inlines__links__085:
- canonical: |
- <p>[foo]<a href="/url">bar</a></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto">[foo]<a href="/url">bar</a></p>
- wysiwyg: |-
- <p>[foo]<a target="_blank" rel="noopener noreferrer nofollow" href="/url">bar</a></p>
- <pre>[baz]: /url</pre>
-06_07_00__inlines__links__086:
- canonical: |
- <p><a href="/url2">foo</a><a href="/url1">baz</a></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto"><a href="/url2">foo</a><a href="/url1">baz</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url2">foo</a><a target="_blank" rel="noopener noreferrer nofollow" href="/url1">baz</a></p>
- <pre>[baz]: /url1</pre>
- <pre>[bar]: /url2</pre>
-06_07_00__inlines__links__087:
- canonical: |
- <p>[foo]<a href="/url1">bar</a></p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto">[foo]<a href="/url1">bar</a></p>
- wysiwyg: |-
- <p>[foo]<a target="_blank" rel="noopener noreferrer nofollow" href="/url1">bar</a></p>
- <pre>[baz]: /url1</pre>
- <pre>[foo]: /url2</pre>
-06_08_00__inlines__images__001:
- canonical: |
- <p><img src="/url" alt="foo" title="title" /></p>
- static: |-
- <p data-sourcepos="1:1-1:20" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" title="title" decoding="async" class="lazy" data-src="/url"></a></p>
- wysiwyg: |-
- <p><img src="/url" alt="foo" title="title"></p>
-06_08_00__inlines__images__002:
- canonical: |
- <p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
- static: |-
- <p data-sourcepos="1:1-1:12" dir="auto"><a class="no-attachment-icon" href="train.jpg" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" title="train &amp; tracks" decoding="async" class="lazy" data-src="train.jpg"></a></p>
- wysiwyg: |-
- <p><img src="train.jpg" alt="foo bar" title="train &amp; tracks"></p>
- <pre>[foo *bar*]: train.jpg "train &amp; tracks"</pre>
-06_08_00__inlines__images__003:
- canonical: |
- <p><img src="/url2" alt="foo bar" /></p>
- static: |-
- <p data-sourcepos="1:1-1:26" dir="auto"><a class="no-attachment-icon" href="/url2" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" decoding="async" class="lazy" data-src="/url2"></a></p>
- wysiwyg: |-
- <p><img src="/url2" alt="foo bar"></p>
-06_08_00__inlines__images__004:
- canonical: |
- <p><img src="/url2" alt="foo bar" /></p>
- static: |-
- <p data-sourcepos="1:1-1:25" dir="auto"><a class="no-attachment-icon" href="/url2" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" decoding="async" class="lazy" data-src="/url2"></a></p>
- wysiwyg: |-
- <p><img src="/url2" alt="foo bar"></p>
-06_08_00__inlines__images__005:
- canonical: |
- <p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
- static: |-
- <p data-sourcepos="1:1-1:14" dir="auto"><a class="no-attachment-icon" href="train.jpg" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" title="train &amp; tracks" decoding="async" class="lazy" data-src="train.jpg"></a></p>
- wysiwyg: |-
- <p><img src="train.jpg" alt="foo bar" title="train &amp; tracks"></p>
- <pre>[foo *bar*]: train.jpg "train &amp; tracks"</pre>
-06_08_00__inlines__images__006:
- canonical: |
- <p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
- static: |-
- <p data-sourcepos="1:1-1:20" dir="auto"><a class="no-attachment-icon" href="train.jpg" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" title="train &amp; tracks" decoding="async" class="lazy" data-src="train.jpg"></a></p>
- wysiwyg: |-
- <p><img src="train.jpg" alt="foo bar" title="train &amp; tracks"></p>
- <pre>[foobar]: train.jpg "train &amp; tracks"</pre>
-06_08_00__inlines__images__007:
- canonical: |
- <p><img src="train.jpg" alt="foo" /></p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto"><a class="no-attachment-icon" href="train.jpg" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" decoding="async" class="lazy" data-src="train.jpg"></a></p>
- wysiwyg: |-
- <p><img src="train.jpg" alt="foo"></p>
-06_08_00__inlines__images__008:
- canonical: |
- <p>My <img src="/path/to/train.jpg" alt="foo bar" title="title" /></p>
- static: |-
- <p data-sourcepos="1:1-1:45" dir="auto">My <a class="no-attachment-icon" href="/path/to/train.jpg" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" title="title" decoding="async" class="lazy" data-src="/path/to/train.jpg"></a></p>
- wysiwyg: |-
- <p>My <img src="/path/to/train.jpg" alt="foo bar" title="title"></p>
-06_08_00__inlines__images__009:
- canonical: |
- <p><img src="url" alt="foo" /></p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto"><a class="no-attachment-icon" href="url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" decoding="async" class="lazy" data-src="url"></a></p>
- wysiwyg: |-
- <p><img src="url" alt="foo"></p>
-06_08_00__inlines__images__010:
- canonical: |
- <p><img src="/url" alt="" /></p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" decoding="async" class="lazy" data-src="/url"></a></p>
- wysiwyg: |-
- <p><img src="/url" alt=""></p>
-06_08_00__inlines__images__011:
- canonical: |
- <p><img src="/url" alt="foo" /></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" decoding="async" class="lazy" data-src="/url"></a></p>
- wysiwyg: |-
- <p><img src="/url" alt="foo"></p>
- <pre>[bar]: /url</pre>
-06_08_00__inlines__images__012:
- canonical: |
- <p><img src="/url" alt="foo" /></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" decoding="async" class="lazy" data-src="/url"></a></p>
- wysiwyg: |-
- <p><img src="/url" alt="foo"></p>
- <pre>[bar]: /url</pre>
-06_08_00__inlines__images__013:
- canonical: |
- <p><img src="/url" alt="foo" title="title" /></p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" title="title" decoding="async" class="lazy" data-src="/url"></a></p>
- wysiwyg: |-
- <p><img src="/url" alt="foo" title="title"></p>
- <pre>[foo]: /url "title"</pre>
-06_08_00__inlines__images__014:
- canonical: |
- <p><img src="/url" alt="foo bar" title="title" /></p>
- static: |-
- <p data-sourcepos="1:1-1:14" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" title="title" decoding="async" class="lazy" data-src="/url"></a></p>
- wysiwyg: |-
- <p><img src="/url" alt="foo bar" title="title"></p>
- <pre>[*foo* bar]: /url "title"</pre>
-06_08_00__inlines__images__015:
- canonical: |
- <p><img src="/url" alt="Foo" title="title" /></p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="Foo" title="title" decoding="async" class="lazy" data-src="/url"></a></p>
- wysiwyg: |-
- <p><img src="/url" alt="Foo" title="title"></p>
- <pre>[foo]: /url "title"</pre>
-06_08_00__inlines__images__016:
- canonical: |
- <p><img src="/url" alt="foo" title="title" />
- []</p>
- static: |-
- <p data-sourcepos="1:1-2:2" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" title="title" decoding="async" class="lazy" data-src="/url"></a>
- []</p>
- wysiwyg: |-
- <p><img src="/url" alt="foo" title="title">
- []</p>
- <pre>[foo]: /url "title"</pre>
-06_08_00__inlines__images__017:
- canonical: |
- <p><img src="/url" alt="foo" title="title" /></p>
- static: |-
- <p data-sourcepos="1:1-1:6" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" title="title" decoding="async" class="lazy" data-src="/url"></a></p>
- wysiwyg: |-
- <p><img src="/url" alt="foo" title="title"></p>
- <pre>[foo]: /url "title"</pre>
-06_08_00__inlines__images__018:
- canonical: |
- <p><img src="/url" alt="foo bar" title="title" /></p>
- static: |-
- <p data-sourcepos="1:1-1:12" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" title="title" decoding="async" class="lazy" data-src="/url"></a></p>
- wysiwyg: |-
- <p><img src="/url" alt="foo bar" title="title"></p>
- <pre>[*foo* bar]: /url "title"</pre>
-06_08_00__inlines__images__019:
- canonical: |
- <p>![[foo]]</p>
- <p>[[foo]]: /url &quot;title&quot;</p>
- static: |-
- <p data-sourcepos="1:1-1:8" dir="auto">![[foo]]</p>
- <p data-sourcepos="3:1-3:21" dir="auto">[[foo]]: /url "title"</p>
- wysiwyg: |-
- <p>![[foo]]</p>
- <p>[[foo]]: /url "title"</p>
-06_08_00__inlines__images__020:
- canonical: |
- <p><img src="/url" alt="Foo" title="title" /></p>
- static: |-
- <p data-sourcepos="1:1-1:6" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="Foo" title="title" decoding="async" class="lazy" data-src="/url"></a></p>
- wysiwyg: |-
- <p><img src="/url" alt="Foo" title="title"></p>
- <pre>[foo]: /url "title"</pre>
-06_08_00__inlines__images__021:
- canonical: |
- <p>![foo]</p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto">![foo]</p>
- wysiwyg: |-
- <p>![foo]</p>
- <pre>[foo]: /url "title"</pre>
-06_08_00__inlines__images__022:
- canonical: |
- <p>!<a href="/url" title="title">foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:27" dir="auto"><span>!</span><a href="/url" title="title">foo</a></p>
- wysiwyg: |-
- <p>!<a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">foo</a></p>
- <pre>[foo]: /url "title"</pre>
-06_09_00__inlines__autolinks__001:
- canonical: |
- <p><a href="http://foo.bar.baz">http://foo.bar.baz</a></p>
- static: |-
- <p data-sourcepos="1:1-1:20" dir="auto"><a href="http://foo.bar.baz" rel="nofollow noreferrer noopener" target="_blank">http://foo.bar.baz</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://foo.bar.baz">http://foo.bar.baz</a></p>
-06_09_00__inlines__autolinks__002:
- canonical: |
- <p><a href="http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean">http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean</a></p>
- static: |-
- <p data-sourcepos="1:1-1:47" dir="auto"><a href="http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean" rel="nofollow noreferrer noopener" target="_blank">http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean">http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean</a></p>
-06_09_00__inlines__autolinks__003:
- canonical: |
- <p><a href="irc://foo.bar:2233/baz">irc://foo.bar:2233/baz</a></p>
- static: |-
- <p data-sourcepos="1:1-1:24" dir="auto"><a href="irc://foo.bar:2233/baz">irc://foo.bar:2233/baz</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow">irc://foo.bar:2233/baz</a></p>
-06_09_00__inlines__autolinks__004:
- canonical: |
- <p><a href="MAILTO:FOO@BAR.BAZ">MAILTO:FOO@BAR.BAZ</a></p>
- static: |-
- <p data-sourcepos="1:1-1:20" dir="auto"><a href="mailto:FOO@BAR.BAZ">MAILTO:FOO@BAR.BAZ</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="MAILTO:FOO@BAR.BAZ">MAILTO:FOO@BAR.BAZ</a></p>
-06_09_00__inlines__autolinks__005:
- canonical: |
- <p><a href="a+b+c:d">a+b+c:d</a></p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto"><a href="a+b+c:d">a+b+c:d</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow">a+b+c:d</a></p>
-06_09_00__inlines__autolinks__006:
- canonical: |
- <p><a href="made-up-scheme://foo,bar">made-up-scheme://foo,bar</a></p>
- static: |-
- <p data-sourcepos="1:1-1:26" dir="auto"><a href="made-up-scheme://foo,bar">made-up-scheme://foo,bar</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow">made-up-scheme://foo,bar</a></p>
-06_09_00__inlines__autolinks__007:
- canonical: |
- <p><a href="http://../">http://../</a></p>
- static: |-
- <p data-sourcepos="1:1-1:12" dir="auto"><a href="http://../" rel="nofollow noreferrer noopener" target="_blank">http://../</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://../">http://../</a></p>
-06_09_00__inlines__autolinks__008:
- canonical: |
- <p><a href="localhost:5001/foo">localhost:5001/foo</a></p>
- static: |-
- <p data-sourcepos="1:1-1:20" dir="auto"><a href="localhost:5001/foo">localhost:5001/foo</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow">localhost:5001/foo</a></p>
-06_09_00__inlines__autolinks__009:
- canonical: |
- <p>&lt;http://foo.bar/baz bim&gt;</p>
- static: |-
- <p data-sourcepos="1:1-1:24" dir="auto">&lt;<a href="http://foo.bar/baz" rel="nofollow noreferrer noopener" target="_blank">http://foo.bar/baz</a> bim&gt;</p>
- wysiwyg: |-
- <p>&lt;<a target="_blank" rel="noopener noreferrer nofollow" href="http://foo.bar/baz">http://foo.bar/baz</a> bim&gt;</p>
-06_09_00__inlines__autolinks__010:
- canonical: |
- <p><a href="http://example.com/%5C%5B%5C">http://example.com/\[\</a></p>
- static: |-
- <p data-sourcepos="1:1-1:24" dir="auto"><a href="http://example.com/%5C%5B%5C" rel="nofollow noreferrer noopener" target="_blank">http://example.com/\[\</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://example.com/%5C%5B%5C">http://example.com/\[\</a></p>
-06_09_00__inlines__autolinks__011:
- canonical: |
- <p><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
- static: |-
- <p data-sourcepos="1:1-1:21" dir="auto"><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
-06_09_00__inlines__autolinks__012:
- canonical: |
- <p><a href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p>
- static: |-
- <p data-sourcepos="1:1-1:30" dir="auto"><a href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p>
-06_09_00__inlines__autolinks__013:
- canonical: |
- <p>&lt;foo+@bar.example.com&gt;</p>
- static: |-
- <p data-sourcepos="1:1-1:23" dir="auto">&lt;<a href="mailto:foo+@bar.example.com">foo+@bar.example.com</a>&gt;</p>
- wysiwyg: |-
- <p>&lt;<a target="_blank" rel="noopener noreferrer nofollow" href="mailto:foo+@bar.example.com">foo+@bar.example.com</a>&gt;</p>
-06_09_00__inlines__autolinks__014:
- canonical: |
- <p>&lt;&gt;</p>
- static: |-
- <p data-sourcepos="1:1-1:2" dir="auto">&lt;&gt;</p>
- wysiwyg: |-
- <p>&lt;&gt;</p>
-06_09_00__inlines__autolinks__015:
- canonical: |
- <p>&lt; http://foo.bar &gt;</p>
- static: |-
- <p data-sourcepos="1:1-1:18" dir="auto">&lt; <a href="http://foo.bar" rel="nofollow noreferrer noopener" target="_blank">http://foo.bar</a> &gt;</p>
- wysiwyg: |-
- <p>&lt; <a target="_blank" rel="noopener noreferrer nofollow" href="http://foo.bar">http://foo.bar</a> &gt;</p>
-06_09_00__inlines__autolinks__016:
- canonical: |
- <p>&lt;m:abc&gt;</p>
- static: |-
- <p data-sourcepos="1:1-1:7" dir="auto">&lt;m:abc&gt;</p>
- wysiwyg: |-
- <p>&lt;m:abc&gt;</p>
-06_09_00__inlines__autolinks__017:
- canonical: |
- <p>&lt;foo.bar.baz&gt;</p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto">&lt;foo.bar.baz&gt;</p>
- wysiwyg: |-
- <p>&lt;foo.bar.baz&gt;</p>
-06_09_00__inlines__autolinks__018:
- canonical: |
- <p>http://example.com</p>
- static: |-
- <p data-sourcepos="1:1-1:18" dir="auto"><a href="http://example.com" rel="nofollow noreferrer noopener" target="_blank">http://example.com</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://example.com">http://example.com</a></p>
-06_09_00__inlines__autolinks__019:
- canonical: |
- <p>foo@bar.example.com</p>
- static: |-
- <p data-sourcepos="1:1-1:19" dir="auto"><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
-06_10_00__inlines__autolinks_extension__001:
- canonical: |
- <p><a href="http://www.commonmark.org">www.commonmark.org</a></p>
- static: |-
- <p data-sourcepos="1:1-1:18" dir="auto"><a href="http://www.commonmark.org" rel="nofollow noreferrer noopener" target="_blank">www.commonmark.org</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://www.commonmark.org">www.commonmark.org</a></p>
-06_10_00__inlines__autolinks_extension__002:
- canonical: |
- <p>Visit <a href="http://www.commonmark.org/help">www.commonmark.org/help</a> for more information.</p>
- static: |-
- <p data-sourcepos="1:1-1:51" dir="auto">Visit <a href="http://www.commonmark.org/help" rel="nofollow noreferrer noopener" target="_blank">www.commonmark.org/help</a> for more information.</p>
- wysiwyg: |-
- <p>Visit <a target="_blank" rel="noopener noreferrer nofollow" href="http://www.commonmark.org/help">www.commonmark.org/help</a> for more information.</p>
-06_10_00__inlines__autolinks_extension__003:
- canonical: |
- <p>Visit <a href="http://www.commonmark.org">www.commonmark.org</a>.</p>
- <p>Visit <a href="http://www.commonmark.org/a.b">www.commonmark.org/a.b</a>.</p>
- static: |-
- <p data-sourcepos="1:1-1:25" dir="auto">Visit <a href="http://www.commonmark.org" rel="nofollow noreferrer noopener" target="_blank">www.commonmark.org</a>.</p>
- <p data-sourcepos="3:1-3:29" dir="auto">Visit <a href="http://www.commonmark.org/a.b" rel="nofollow noreferrer noopener" target="_blank">www.commonmark.org/a.b</a>.</p>
- wysiwyg: |-
- <p>Visit <a target="_blank" rel="noopener noreferrer nofollow" href="http://www.commonmark.org">www.commonmark.org</a>.</p>
- <p>Visit <a target="_blank" rel="noopener noreferrer nofollow" href="http://www.commonmark.org/a.b">www.commonmark.org/a.b</a>.</p>
-06_10_00__inlines__autolinks_extension__004:
- canonical: |
- <p><a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
- <p><a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>))</p>
- <p>(<a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>)</p>
- <p>(<a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
- static: |-
- <p data-sourcepos="1:1-1:41" dir="auto"><a href="http://www.google.com/search?q=Markup+(business)" rel="nofollow noreferrer noopener" target="_blank">www.google.com/search?q=Markup+(business)</a></p>
- <p data-sourcepos="3:1-3:43" dir="auto"><a href="http://www.google.com/search?q=Markup+(business)" rel="nofollow noreferrer noopener" target="_blank">www.google.com/search?q=Markup+(business)</a>))</p>
- <p data-sourcepos="5:1-5:43" dir="auto">(<a href="http://www.google.com/search?q=Markup+(business)" rel="nofollow noreferrer noopener" target="_blank">www.google.com/search?q=Markup+(business)</a>)</p>
- <p data-sourcepos="7:1-7:42" dir="auto">(<a href="http://www.google.com/search?q=Markup+(business)" rel="nofollow noreferrer noopener" target="_blank">www.google.com/search?q=Markup+(business)</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>))</p>
- <p>(<a target="_blank" rel="noopener noreferrer nofollow" href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>)</p>
- <p>(<a target="_blank" rel="noopener noreferrer nofollow" href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
-06_10_00__inlines__autolinks_extension__005:
- canonical: |
- <p><a href="http://www.google.com/search?q=(business))+ok">www.google.com/search?q=(business))+ok</a></p>
- static: |-
- <p data-sourcepos="1:1-1:38" dir="auto"><a href="http://www.google.com/search?q=(business))+ok" rel="nofollow noreferrer noopener" target="_blank">www.google.com/search?q=(business))+ok</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://www.google.com/search?q=(business))+ok">www.google.com/search?q=(business))+ok</a></p>
-06_10_00__inlines__autolinks_extension__006:
- canonical: |
- <p><a href="http://www.google.com/search?q=commonmark&amp;hl=en">www.google.com/search?q=commonmark&amp;hl=en</a></p>
- <p><a href="http://www.google.com/search?q=commonmark">www.google.com/search?q=commonmark</a>&amp;hl;</p>
- static: |-
- <p data-sourcepos="1:1-1:40" dir="auto"><a href="http://www.google.com/search?q=commonmark&amp;hl=en" rel="nofollow noreferrer noopener" target="_blank">www.google.com/search?q=commonmark&amp;hl=en</a></p>
- <p data-sourcepos="3:1-3:38" dir="auto"><a href="http://www.google.com/search?q=commonmark" rel="nofollow noreferrer noopener" target="_blank">www.google.com/search?q=commonmark</a>&amp;hl;</p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://www.google.com/search?q=commonmark&amp;hl=en">www.google.com/search?q=commonmark&amp;hl=en</a></p>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://www.google.com/search?q=commonmark">www.google.com/search?q=commonmark</a>&amp;hl;</p>
-06_10_00__inlines__autolinks_extension__007:
- canonical: |
- <p><a href="http://www.commonmark.org/he">www.commonmark.org/he</a>&lt;lp</p>
- static: |-
- <p data-sourcepos="1:1-1:24" dir="auto"><a href="http://www.commonmark.org/he" rel="nofollow noreferrer noopener" target="_blank">www.commonmark.org/he</a>&lt;lp</p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://www.commonmark.org/he">www.commonmark.org/he</a>&lt;lp</p>
-06_10_00__inlines__autolinks_extension__008:
- canonical: |
- <p><a href="http://commonmark.org">http://commonmark.org</a></p>
- <p>(Visit <a href="https://encrypted.google.com/search?q=Markup+(business)">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>
- <p>Anonymous FTP is available at <a href="ftp://foo.bar.baz">ftp://foo.bar.baz</a>.</p>
- static: |-
- <p data-sourcepos="1:1-1:21" dir="auto"><a href="http://commonmark.org" rel="nofollow noreferrer noopener" target="_blank">http://commonmark.org</a></p>
- <p data-sourcepos="3:1-3:63" dir="auto">(Visit <a href="https://encrypted.google.com/search?q=Markup+(business)" rel="nofollow noreferrer noopener" target="_blank">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>
- <p data-sourcepos="5:1-5:48" dir="auto">Anonymous FTP is available at <a href="ftp://foo.bar.baz/">ftp://foo.bar.baz</a>.</p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://commonmark.org">http://commonmark.org</a></p>
- <p>(Visit <a target="_blank" rel="noopener noreferrer nofollow" href="https://encrypted.google.com/search?q=Markup+(business)">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>
- <p>Anonymous FTP is available at ftp://foo.bar.baz.</p>
-06_10_00__inlines__autolinks_extension__009:
- canonical: |
- <p><a href="mailto:foo@bar.baz">foo@bar.baz</a></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto"><a href="mailto:foo@bar.baz">foo@bar.baz</a></p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="mailto:foo@bar.baz">foo@bar.baz</a></p>
-06_10_00__inlines__autolinks_extension__010:
- canonical: |
- <p>hello@mail+xyz.example isn't valid, but <a href="mailto:hello+xyz@mail.example">hello+xyz@mail.example</a> is.</p>
- static: |-
- <p data-sourcepos="1:1-1:66" dir="auto">hello@mail+xyz.example isn't valid, but <a href="mailto:hello+xyz@mail.example">hello+xyz@mail.example</a> is.</p>
- wysiwyg: |-
- <p>hello@mail+xyz.example isn't valid, but <a target="_blank" rel="noopener noreferrer nofollow" href="mailto:hello+xyz@mail.example">hello+xyz@mail.example</a> is.</p>
-06_10_00__inlines__autolinks_extension__011:
- canonical: |
- <p><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a></p>
- <p><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a>.</p>
- <p>a.b-c_d@a.b-</p>
- <p>a.b-c_d@a.b_</p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto"><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a></p>
- <p data-sourcepos="3:1-3:12" dir="auto"><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a>.</p>
- <p data-sourcepos="5:1-5:12" dir="auto">a.b-c_d@a.b-</p>
- <p data-sourcepos="7:1-7:12" dir="auto">a.b-c_d@a.b_</p>
- wysiwyg: |-
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a></p>
- <p><a target="_blank" rel="noopener noreferrer nofollow" href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a>.</p>
- <p>a.b-c_d@a.b-</p>
- <p>a.b-c_d@a.b_</p>
-06_11_00__inlines__raw_html__001:
- canonical: |
- <p><a><bab><c2c></p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto"><a></a></p>
- wysiwyg: |-
- <p></p>
-06_11_00__inlines__raw_html__002:
- canonical: |
- <p><a/><b2/></p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto"><a></a></p>
- wysiwyg: |-
- <p></p>
-06_11_00__inlines__raw_html__003:
- canonical: |
- <p><a /><b2
- data="foo" ></p>
- static: |-
- <p data-sourcepos="1:1-2:12" dir="auto"><a></a></p>
- wysiwyg: |-
- <p></p>
-06_11_00__inlines__raw_html__004:
- canonical: |
- <p><a foo="bar" bam = 'baz <em>"</em>'
- _boolean zoop:33=zoop:33 /></p>
- static: |-
- <p data-sourcepos="1:1-2:27" dir="auto"><a></a></p>
- wysiwyg: |-
- <p></p>
-06_11_00__inlines__raw_html__005:
- canonical: |
- <p>Foo <responsive-image src="foo.jpg" /></p>
- static: |-
- <p data-sourcepos="1:1-1:38" dir="auto">Foo </p>
- wysiwyg: |-
- <p>Foo </p>
-06_11_00__inlines__raw_html__006:
- canonical: |
- <p>&lt;33&gt; &lt;__&gt;</p>
- static: |-
- <p data-sourcepos="1:1-1:9" dir="auto">&lt;33&gt; &lt;__&gt;</p>
- wysiwyg: |-
- <p>&lt;33&gt; &lt;__&gt;</p>
-06_11_00__inlines__raw_html__007:
- canonical: |
- <p>&lt;a h*#ref=&quot;hi&quot;&gt;</p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto">&lt;a h*#ref="hi"&gt;</p>
- wysiwyg: |-
- <p>&lt;a h*#ref="hi"&gt;</p>
-06_11_00__inlines__raw_html__008:
- canonical: |
- <p>&lt;a href=&quot;hi'&gt; &lt;a href=hi'&gt;</p>
- static: |-
- <p data-sourcepos="1:1-1:26" dir="auto">&lt;a href="hi'&gt; &lt;a href=hi'&gt;</p>
- wysiwyg: |-
- <p>&lt;a href="hi'&gt; &lt;a href=hi'&gt;</p>
-06_11_00__inlines__raw_html__009:
- canonical: |
- <p>&lt; a&gt;&lt;
- foo&gt;&lt;bar/ &gt;
- &lt;foo bar=baz
- bim!bop /&gt;</p>
- static: |-
- <p data-sourcepos="1:1-4:10" dir="auto">&lt; a&gt;&lt;
- foo&gt;&lt;bar/ &gt;
- &lt;foo bar=baz
- bim!bop /&gt;</p>
- wysiwyg: |-
- <p>&lt; a&gt;&lt;
- foo&gt;&lt;bar/ &gt;
- &lt;foo bar=baz
- bim!bop /&gt;</p>
-06_11_00__inlines__raw_html__010:
- canonical: |
- <p>&lt;a href='bar'title=title&gt;</p>
- static: |-
- <p data-sourcepos="1:1-1:25" dir="auto">&lt;a href='bar'title=title&gt;</p>
- wysiwyg: |-
- <p>&lt;a href='bar'title=title&gt;</p>
-06_11_00__inlines__raw_html__011:
- canonical: |
- <p></a></foo ></p>
- static: |-
- <p data-sourcepos="1:1-1:11" dir="auto"></p>
- wysiwyg: |-
- <p></p>
-06_11_00__inlines__raw_html__012:
- canonical: |
- <p>&lt;/a href=&quot;foo&quot;&gt;</p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto">&lt;/a href="foo"&gt;</p>
- wysiwyg: |-
- <p>&lt;/a href="foo"&gt;</p>
-06_11_00__inlines__raw_html__013:
- canonical: |
- <p>foo <!-- this is a
- comment - with hyphen --></p>
- static: |-
- <p data-sourcepos="1:1-2:25" dir="auto">foo </p>
- wysiwyg: |-
- <p>foo </p>
-06_11_00__inlines__raw_html__014:
- canonical: |
- <p>foo &lt;!-- not a comment -- two hyphens --&gt;</p>
- static: |-
- <p data-sourcepos="1:1-1:41" dir="auto">foo &lt;!-- not a comment -- two hyphens --&gt;</p>
- wysiwyg: |-
- <p>foo &lt;!-- not a comment -- two hyphens --&gt;</p>
-06_11_00__inlines__raw_html__015:
- canonical: |
- <p>foo &lt;!--&gt; foo --&gt;</p>
- <p>foo &lt;!-- foo---&gt;</p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto">foo &lt;!--&gt; foo --&gt;</p>
- <p data-sourcepos="3:1-3:16" dir="auto">foo &lt;!-- foo---&gt;</p>
- wysiwyg: |-
- <p>foo &lt;!--&gt; foo --&gt;</p>
- <p>foo &lt;!-- foo---&gt;</p>
-06_11_00__inlines__raw_html__016:
- canonical: |
- <p>foo <?php echo $a; ?></p>
- static: |-
- <p data-sourcepos="1:1-1:21" dir="auto">foo <?php echo $a; ?></p>
- wysiwyg: |-
- <p>foo </p>
-06_11_00__inlines__raw_html__017:
- canonical: |
- <p>foo <!ELEMENT br EMPTY></p>
- static: |-
- <p data-sourcepos="1:1-1:23" dir="auto">foo &lt;!ELEMENT br EMPTY&gt;</p>
- wysiwyg: |-
- <p>foo </p>
-06_11_00__inlines__raw_html__018:
- canonical: |
- <p>foo <![CDATA[>&<]]></p>
- static: |-
- <p data-sourcepos="1:1-1:19" dir="auto">foo &lt;![CDATA[&gt;&amp;&lt;]]&gt;</p>
- wysiwyg: |-
- <p>foo &amp;&lt;]]&gt;</p>
-06_11_00__inlines__raw_html__019:
- canonical: |
- <p>foo <a href="&ouml;"></p>
- static: |-
- <p data-sourcepos="1:1-1:21" dir="auto">foo <a href="%C3%B6" rel="nofollow noreferrer noopener" target="_blank"></a></p>
- wysiwyg: |-
- <p>foo </p>
-06_11_00__inlines__raw_html__020:
- canonical: |
- <p>foo <a href="\*"></p>
- static: |-
- <p data-sourcepos="1:1-1:17" dir="auto">foo <a href="%5C*" rel="nofollow noreferrer noopener" target="_blank"></a></p>
- wysiwyg: |-
- <p>foo </p>
-06_11_00__inlines__raw_html__021:
- canonical: |
- <p>&lt;a href=&quot;&quot;&quot;&gt;</p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto">&lt;a href="""&gt;</p>
- wysiwyg: |-
- <p>&lt;a href="""&gt;</p>
-06_12_00__inlines__disallowed_raw_html_extension__001:
- canonical: |
- <p><strong> &lt;title> &lt;style> <em></p>
- <blockquote>
- &lt;xmp> is disallowed. &lt;XMP> is also disallowed.
- </blockquote>
- static: |-
- <p data-sourcepos="1:1-1:29" dir="auto"><strong> &lt;em&gt;&lt;/p&gt;
- &lt;blockquote&gt;
- &lt;xmp&gt; is disallowed. &lt;XMP&gt; is also disallowed.
- &lt;/blockquote&gt;</strong></p>
- wysiwyg: |-
- <p></p>
- <blockquote multiline="false"><p></p></blockquote>
-06_13_00__inlines__hard_line_breaks__001:
- canonical: |
- <p>foo<br />
- baz</p>
- static: |-
- <p data-sourcepos="1:1-2:3" dir="auto">foo<br>
- baz</p>
- wysiwyg: |-
- <p>foo<br>
- baz</p>
-06_13_00__inlines__hard_line_breaks__002:
- canonical: |
- <p>foo<br />
- baz</p>
- static: |-
- <p data-sourcepos="1:1-2:3" dir="auto">foo<br>
- baz</p>
- wysiwyg: |-
- <p>foo<br>
- baz</p>
-06_13_00__inlines__hard_line_breaks__003:
- canonical: |
- <p>foo<br />
- baz</p>
- static: |-
- <p data-sourcepos="1:1-2:3" dir="auto">foo<br>
- baz</p>
- wysiwyg: |-
- <p>foo<br>
- baz</p>
-06_13_00__inlines__hard_line_breaks__004:
- canonical: |
- <p>foo<br />
- bar</p>
- static: |-
- <p data-sourcepos="1:1-2:8" dir="auto">foo<br>
- bar</p>
- wysiwyg: |-
- <p>foo<br>
- bar</p>
-06_13_00__inlines__hard_line_breaks__005:
- canonical: |
- <p>foo<br />
- bar</p>
- static: |-
- <p data-sourcepos="1:1-2:8" dir="auto">foo<br>
- bar</p>
- wysiwyg: |-
- <p>foo<br>
- bar</p>
-06_13_00__inlines__hard_line_breaks__006:
- canonical: |
- <p><em>foo<br />
- bar</em></p>
- static: |-
- <p data-sourcepos="1:1-2:4" dir="auto"><em>foo<br>
- bar</em></p>
- wysiwyg: |-
- <p><em>foo<br>
- bar</em></p>
-06_13_00__inlines__hard_line_breaks__007:
- canonical: |
- <p><em>foo<br />
- bar</em></p>
- static: |-
- <p data-sourcepos="1:1-2:4" dir="auto"><em>foo<br>
- bar</em></p>
- wysiwyg: |-
- <p><em>foo<br>
- bar</em></p>
-06_13_00__inlines__hard_line_breaks__008:
- canonical: |
- <p><code>code span</code></p>
- static: |-
- <p data-sourcepos="1:1-2:5" dir="auto"><code>code span</code></p>
- wysiwyg: |-
- <p><code>code span</code></p>
-06_13_00__inlines__hard_line_breaks__009:
- canonical: |
- <p><code>code\ span</code></p>
- static: |-
- <p data-sourcepos="1:1-2:5" dir="auto"><code>code\ span</code></p>
- wysiwyg: |-
- <p><code>code\ span</code></p>
-06_13_00__inlines__hard_line_breaks__010:
- canonical: "<p><a href=\"foo \nbar\"></p>\n"
- static: |-
- <p data-sourcepos="1:1-2:5" dir="auto"><a href="foo%20%20%0Abar" rel="nofollow noreferrer noopener" target="_blank"></a></p>
- wysiwyg: |-
- <p></p>
-06_13_00__inlines__hard_line_breaks__011:
- canonical: |
- <p><a href="foo\
- bar"></p>
- static: |-
- <p data-sourcepos="1:1-2:5" dir="auto"><a href="foo%5C%0Abar" rel="nofollow noreferrer noopener" target="_blank"></a></p>
- wysiwyg: |-
- <p></p>
-06_13_00__inlines__hard_line_breaks__012:
- canonical: |
- <p>foo\</p>
- static: |-
- <p data-sourcepos="1:1-1:4" dir="auto">foo\</p>
- wysiwyg: |-
- <p>foo\</p>
-06_13_00__inlines__hard_line_breaks__013:
- canonical: |
- <p>foo</p>
- static: |-
- <p data-sourcepos="1:1-1:5" dir="auto">foo</p>
- wysiwyg: |-
- <p>foo</p>
-06_13_00__inlines__hard_line_breaks__014:
- canonical: |
- <h3>foo\</h3>
- static: |-
- <h3 data-sourcepos="1:1-1:8" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo\</h3>
- wysiwyg: |-
- <h3>foo\</h3>
-06_13_00__inlines__hard_line_breaks__015:
- canonical: |
- <h3>foo</h3>
- static: |-
- <h3 data-sourcepos="1:1-1:7" dir="auto">
- <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h3>
- wysiwyg: |-
- <h3>foo</h3>
-06_14_00__inlines__soft_line_breaks__001:
- canonical: |
- <p>foo
- baz</p>
- static: |-
- <p data-sourcepos="1:1-2:3" dir="auto">foo
- baz</p>
- wysiwyg: |-
- <p>foo
- baz</p>
-06_14_00__inlines__soft_line_breaks__002:
- canonical: |
- <p>foo
- baz</p>
- static: |-
- <p data-sourcepos="1:1-2:4" dir="auto">foo
- baz</p>
- wysiwyg: |-
- <p>foo
- baz</p>
-06_15_00__inlines__textual_content__001:
- canonical: |
- <p>hello $.;'there</p>
- static: |-
- <p data-sourcepos="1:1-1:15" dir="auto">hello $.;'there</p>
- wysiwyg: |-
- <p>hello $.;'there</p>
-06_15_00__inlines__textual_content__002:
- canonical: |
- <p>Foo χÏῆν</p>
- static: |-
- <p data-sourcepos="1:1-1:13" dir="auto">Foo χÏῆν</p>
- wysiwyg: |-
- <p>Foo χÏῆν</p>
-06_15_00__inlines__textual_content__003:
- canonical: |
- <p>Multiple spaces</p>
- static: |-
- <p data-sourcepos="1:1-1:19" dir="auto">Multiple spaces</p>
- wysiwyg: |-
- <p>Multiple spaces</p>
-07_01_00__gitlab_official_specification_markdown__footnotes__001:
- canonical: |
- <p>
- footnote reference tag
- <sup>
- <a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref>
- 1
- </a>
- </sup>
- </p>
- <section data-footnotes>
- <ol>
- <li id="fn-fortytwo-42">
- <p>
- footnote text
- <a href="#fnref-fortytwo-42" data-footnote-backref>
- </a>
- </p>
- </li>
- </ol>
- </section>
- static: |-
- <p data-sourcepos="1:1-1:34" dir="auto">footnote reference tag <sup class="footnote-ref"><a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref>1</a></sup></p>
- <section data-footnotes class="footnotes">
- <ol>
- <li id="fn-fortytwo-42">
- <p data-sourcepos="3:14-3:26">footnote text <a href="#fnref-fortytwo-42" data-footnote-backref aria-label="Back to content" class="footnote-backref"><gl-emoji title="leftwards arrow with hook" data-name="leftwards_arrow_with_hook" data-unicode-version="1.1">↩</gl-emoji></a></p>
- </li>
- </ol>
- </section>
- wysiwyg: |-
- <p>footnote reference tag <sup identifier="fortytwo">fortytwo</sup></p>
- <div node="footnoteDefinition(paragraph(&quot;footnote text&quot;))" htmlattributes="[object Object]"><p>footnote text</p></div>
-07_02_00__gitlab_official_specification_markdown__task_list_items__001:
- canonical: |
- <ul>
- <li>
- <task-button/>
- <input type="checkbox" disabled/>
- incomplete
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-1:16" class="task-list" dir="auto">
- <li data-sourcepos="1:1-1:16" class="task-list-item">
- <task-button></task-button><input type="checkbox" class="task-list-item-checkbox" disabled> incomplete</li>
- </ul>
- wysiwyg: |-
- <ul start="1" parens="false" data-type="taskList"><li data-checked="false" data-type="taskItem"><label><input type="checkbox"><span></span></label><div><p>incomplete</p></div></li></ul>
-07_02_00__gitlab_official_specification_markdown__task_list_items__002:
- canonical: |
- <ul>
- <li>
- <task-button/>
- <input type="checkbox" checked disabled/>
- completed
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-1:15" class="task-list" dir="auto">
- <li data-sourcepos="1:1-1:15" class="task-list-item">
- <task-button></task-button><input type="checkbox" class="task-list-item-checkbox" checked disabled> completed</li>
- </ul>
- wysiwyg: |-
- <ul start="1" parens="false" data-type="taskList"><li data-checked="true" data-type="taskItem"><label><input type="checkbox" checked="checked"><span></span></label><div><p>completed</p></div></li></ul>
-07_02_00__gitlab_official_specification_markdown__task_list_items__003:
- canonical: |
- <ul>
- <li>
- <task-button/>
- <input type="checkbox" data-inapplicable disabled>
- <s>
- inapplicable
- </s>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-1:18" class="task-list" dir="auto">
- <li data-sourcepos="1:1-1:18" class="task-list-item inapplicable">
- <task-button></task-button><input type="checkbox" class="task-list-item-checkbox" data-inapplicable disabled> <s>inapplicable</s>
- </li>
- </ul>
-07_02_00__gitlab_official_specification_markdown__task_list_items__004:
- canonical: |
- <ul>
- <li>
- <p>
- <task-button/>
- <input type="checkbox" data-inapplicable disabled>
- <s>
- inapplicable
- </s>
- </p>
- <p>
- text in loose list
- </p>
- </li>
- </ul>
- static: |-
- <ul data-sourcepos="1:1-3:20" class="task-list" dir="auto">
- <li data-sourcepos="1:1-3:20" class="task-list-item inapplicable">
- <p data-sourcepos="1:3-1:18"><task-button></task-button><input type="checkbox" class="task-list-item-checkbox" data-inapplicable disabled> <s>inapplicable</s></p>
- <p data-sourcepos="3:3-3:20">text in loose list</p>
- </li>
- </ul>
-07_03_00__gitlab_official_specification_markdown__front_matter__001:
- canonical: |
- <pre>
- <code>
- title: YAML front matter
- </code>
- </pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-yaml" lang="yaml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="yaml"><span class="na">title</span><span class="pi">:</span> <span class="s">YAML front matter</span></span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre language="yaml" class="content-editor-code-block undefined code highlight" isfrontmatter="true"><code>title: YAML front matter</code></pre>
-07_03_00__gitlab_official_specification_markdown__front_matter__002:
- canonical: |
- <pre>
- <code>
- title: TOML front matter
- </code>
- </pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-toml" lang="toml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="toml"><span class="err">title:</span> <span class="err">TOML</span> <span class="err">front</span> <span class="err">matter</span></span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre language="toml" class="content-editor-code-block undefined code highlight" isfrontmatter="true"><code>title: TOML front matter</code></pre>
-07_03_00__gitlab_official_specification_markdown__front_matter__003:
- canonical: |
- <pre>
- <code>
- {
- "title": "JSON front matter"
- }
- </code>
- </pre>
- static: |-
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-5:3" class="code highlight js-syntax-highlight language-json" lang="json" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="json"><span class="p">{</span></span>
- <span id="LC2" class="line" lang="json"><span class="w"> </span><span class="nl">"title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"JSON front matter"</span></span>
- <span id="LC3" class="line" lang="json"><span class="p">}</span></span></code></pre>
- <copy-code></copy-code>
- </div>
- wysiwyg: |-
- <pre language="json" class="content-editor-code-block undefined code highlight" isfrontmatter="true"><code>{
- "title": "JSON front matter"
- }</code></pre>
-07_03_00__gitlab_official_specification_markdown__front_matter__004:
- canonical: |
- <p>text</p>
- <hr>
- <h2>title: YAML front matter</h2>
- static: |-
- <p data-sourcepos="1:1-1:4" dir="auto">text</p>
- <hr data-sourcepos="3:1-3:3">
- <h2 data-sourcepos="4:1-5:3" dir="auto">
- <a id="user-content-title-yaml-front-matter" class="anchor" href="#title-yaml-front-matter" aria-hidden="true"></a>title: YAML front matter</h2>
- wysiwyg: |-
- <p>text</p>
- <hr>
- <h2>title: YAML front matter</h2>
-07_03_00__gitlab_official_specification_markdown__front_matter__005:
- canonical: |
- <hr>
- <h2>title: YAML front matter</h2>
- static: |-
- <hr data-sourcepos="1:2-1:4">
- <h2 data-sourcepos="2:1-3:3" dir="auto">
- <a id="user-content-title-yaml-front-matter" class="anchor" href="#title-yaml-front-matter" aria-hidden="true"></a>title: YAML front matter</h2>
- wysiwyg: |-
- <hr>
- <h2>title: YAML front matter</h2>
-07_04_00__gitlab_official_specification_markdown__table_of_contents__001:
- canonical: |
- <nav>
- <ul>
- <li><a href="#heading-1">Heading 1</a></li>
- <ul>
- <li><a href="#heading-2">Heading 2</a></li>
- </ul>
- </ul>
- </nav>
- <h1>Heading 1</h1>
- <h2>Heading 2</h2>
- static: |-
- <ul class="section-nav"><li>
- <a href="#heading-1">Heading 1</a><ul><li><a href="#heading-2">Heading 2</a></li></ul>
- </li></ul>
- <h1 data-sourcepos="3:1-3:11" dir="auto">
- <a id="user-content-heading-1" class="anchor" href="#heading-1" aria-hidden="true"></a>Heading 1</h1>
- <h2 data-sourcepos="5:1-5:12" dir="auto">
- <a id="user-content-heading-2" class="anchor" href="#heading-2" aria-hidden="true"></a>Heading 2</h2>
- wysiwyg: |-
- <div class="table-of-contents gl-border-1 gl-border-solid gl-text-center gl-border-gray-100 gl-mb-5">Table of contents</div>
- <h1>Heading 1</h1>
- <h2>Heading 2</h2>
-07_04_00__gitlab_official_specification_markdown__table_of_contents__002:
- canonical: |
- <nav>
- <ul>
- <li><a href="#heading-1">Heading 1</a></li>
- <ul>
- <li><a href="#heading-2">Heading 2</a></li>
- </ul>
- </ul>
- </nav>
- <h1>Heading 1</h1>
- <h2>Heading 2</h2>
- static: |-
- <ul class="section-nav"><li>
- <a href="#heading-1">Heading 1</a><ul><li><a href="#heading-2">Heading 2</a></li></ul>
- </li></ul>
- <h1 data-sourcepos="3:1-3:11" dir="auto">
- <a id="user-content-heading-1" class="anchor" href="#heading-1" aria-hidden="true"></a>Heading 1</h1>
- <h2 data-sourcepos="5:1-5:12" dir="auto">
- <a id="user-content-heading-2" class="anchor" href="#heading-2" aria-hidden="true"></a>Heading 2</h2>
- wysiwyg: |-
- <div class="table-of-contents gl-border-1 gl-border-solid gl-text-center gl-border-gray-100 gl-mb-5">Table of contents</div>
- <h1>Heading 1</h1>
- <h2>Heading 2</h2>
-07_04_00__gitlab_official_specification_markdown__table_of_contents__003:
- canonical: |
- <p>[[<em>TOC</em>]]text</p>
- <p>text[TOC]</p>
- static: |-
- <p data-sourcepos="1:1-2:4" dir="auto">[[<em>TOC</em>]]
- text</p>
- <p data-sourcepos="4:1-5:5" dir="auto">text
- [TOC]</p>
- wysiwyg: |-
- <p>[[<em>TOC</em>]]
- text</p>
- <p>text
- [TOC]</p>
-07_04_00__gitlab_official_specification_markdown__table_of_contents__004:
- canonical: |
- <nav>
- <ul>
- <li><a href="#heading-1">Heading 1</a></li>
- </ul>
- </nav>
- <h1>Heading 1</h1>
- static: |-
- <ul class="section-nav"><li><a href="#heading-1">Heading 1</a></li></ul>
- <h1 data-sourcepos="3:1-3:11" dir="auto">
- <a id="user-content-heading-1" class="anchor" href="#heading-1" aria-hidden="true"></a>Heading 1</h1>
- wysiwyg: |-
- <div class="table-of-contents gl-border-1 gl-border-solid gl-text-center gl-border-gray-100 gl-mb-5">Table of contents</div>
- <h1>Heading 1</h1>
-08_01_00__gitlab_internal_extension_markdown__audio__001:
- canonical: |
- <p><audio src="audio.oga" title="audio title"></audio></p>
- static: |-
- <p data-sourcepos="1:1-1:33" dir="auto"><span class="media-container audio-container"><audio src="audio.oga" controls="true" data-setup="{}" data-title="audio title"></audio><a href="audio.oga" target="_blank" rel="noopener noreferrer" title="Download 'audio title'">audio title</a></span></p>
- wysiwyg: |-
- <p><span class="media-container audio-container"><audio src="audio.oga" controls="true" data-setup="{}" data-title="audio"></audio><a href="audio.oga">audio</a></span></p>
-08_01_00__gitlab_internal_extension_markdown__audio__002:
- canonical: |
- <p><audio src="audio.oga" title="audio title"></audio></p>
- static: |-
- <p data-sourcepos="3:1-3:15" dir="auto"><span class="media-container audio-container"><audio src="audio.oga" controls="true" data-setup="{}" data-title="audio title"></audio><a href="audio.oga" target="_blank" rel="noopener noreferrer" title="Download 'audio title'">audio title</a></span></p>
- wysiwyg: |-
- <pre>[audio]: audio.oga "audio title"</pre>
- <p><span class="media-container audio-container"><audio src="audio.oga" controls="true" data-setup="{}" data-title="audio"></audio><a href="audio.oga">audio</a></span></p>
-08_02_00__gitlab_internal_extension_markdown__video__001:
- canonical: |
- <p><video src="video.m4v" title="video title"></video></p>
- static: |-
- <p data-sourcepos="1:1-1:33" dir="auto"><span class="media-container video-container"><video src="video.m4v" controls="true" data-setup="{}" data-title="video title" width="400" preload="metadata"></video><a href="video.m4v" target="_blank" rel="noopener noreferrer" title="Download 'video title'">video title</a></span></p>
- wysiwyg: |-
- <p><span class="media-container video-container"><video src="video.m4v" controls="true" data-setup="{}" data-title="video"></video><a href="video.m4v">video</a></span></p>
-08_02_00__gitlab_internal_extension_markdown__video__002:
- canonical: |
- <p><video src="video.mov" title="video title"></video></p>
- static: |-
- <p data-sourcepos="3:1-3:15" dir="auto"><span class="media-container video-container"><video src="video.mov" controls="true" data-setup="{}" data-title="video title" width="400" preload="metadata"></video><a href="video.mov" target="_blank" rel="noopener noreferrer" title="Download 'video title'">video title</a></span></p>
- wysiwyg: |-
- <pre>[video]: video.mov "video title"</pre>
- <p><span class="media-container video-container"><video src="video.mov" controls="true" data-setup="{}" data-title="video"></video><a href="video.mov">video</a></span></p>
-08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__001:
- canonical: |
- <p><a href="groups-test-file">groups-test-file</a></p>
- static: |-
- <p data-sourcepos="1:1-1:45" dir="auto"><a href="/groups/glfm_group/-/uploads/groups-test-file" data-canonical-src="/uploads/groups-test-file" data-link="true" class="gfm">groups-test-file</a></p>
-08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__002:
- canonical: |
- <p><a href="projects-test-file">projects-test-file</a></p>
- static: |-
- <p data-sourcepos="1:1-1:40" dir="auto"><a href="/glfm_group/glfm_project/-/blob/master/projects-test-file">projects-test-file</a></p>
-08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__003:
- canonical: |
- <p>This project snippet ID reference IS filtered: $88888</p>
- static: |-
- <p data-sourcepos="1:1-1:53" dir="auto">This project snippet ID reference IS filtered: <a href="/glfm_group/glfm_project/-/snippets/88888" data-reference-type="snippet" data-original="$88888" data-link="false" data-link-reference="false" data-project="77777" data-snippet="88888" data-container="body" data-placement="top" title="glfm_project_snippet" class="gfm gfm-snippet has-tooltip">$88888</a></p>
-08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__004:
- canonical: |
- <p>This personal snippet ID reference is not filtered: $99999</p>
- static: |-
- <p data-sourcepos="1:1-1:58" dir="auto">This personal snippet ID reference is not filtered: $99999</p>
-08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__005:
- canonical: |
- <p><a href="project-wikis-test-file">project-wikis-test-file</a></p>
- static: |-
- <p data-sourcepos="1:1-1:50" dir="auto"><a href="/glfm_group/glfm_project/-/wikis/project-wikis-test-file" data-canonical-src="project-wikis-test-file">project-wikis-test-file</a></p>
-08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__006:
- canonical: |
- <p><a href="group-wikis-test-file">group-wikis-test-file</a></p>
- static: |-
- <p data-sourcepos="1:1-1:46" dir="auto"><a href="/groups/glfm_group/-/wikis/group-wikis-test-file" data-canonical-src="group-wikis-test-file">group-wikis-test-file</a></p>
diff --git a/glfm_specification/input/gitlab_flavored_markdown/glfm_internal_extension_examples.md b/glfm_specification/input/gitlab_flavored_markdown/glfm_internal_extension_examples.md
deleted file mode 100644
index 171a8e430d3..00000000000
--- a/glfm_specification/input/gitlab_flavored_markdown/glfm_internal_extension_examples.md
+++ /dev/null
@@ -1,111 +0,0 @@
-# GitLab Internal Extension Markdown
-
-## Audio
-
-See
-[audio](https://docs.gitlab.com/ee/user/markdown.html#audio) in the GitLab Flavored Markdown documentation.
-
-GLFM renders image elements as an audio player as long as the resource’s file extension is
-one of the following supported audio extensions `.mp3`, `.oga`, `.ogg`, `.spx`, and `.wav`.
-Audio ignore the alternative text part of an image declaration.
-
-```````````````````````````````` example gitlab
-![audio](audio.oga "audio title")
-.
-<p><audio src="audio.oga" title="audio title"></audio></p>
-````````````````````````````````
-
-Reference definitions work audio as well:
-
-```````````````````````````````` example gitlab
-[audio]: audio.oga "audio title"
-
-![audio][audio]
-.
-<p><audio src="audio.oga" title="audio title"></audio></p>
-````````````````````````````````
-
-## Video
-
-See
-[videos](https://docs.gitlab.com/ee/user/markdown.html#videos) in the GitLab Flavored Markdown documentation.
-
-GLFM renders image elements as a video player as long as the resource’s file extension is
-one of the following supported video extensions `.mp4`, `.m4v`, `.mov`, `.webm`, and `.ogv`.
-Videos ignore the alternative text part of an image declaration.
-
-
-```````````````````````````````` example gitlab
-![video](video.m4v "video title")
-.
-<p><video src="video.m4v" title="video title"></video></p>
-````````````````````````````````
-
-Reference definitions work video as well:
-
-```````````````````````````````` example gitlab
-[video]: video.mov "video title"
-
-![video][video]
-.
-<p><video src="video.mov" title="video title"></video></p>
-````````````````````````````````
-
-## Markdown Preview API Request Overrides
-
-This section contains examples of all controllers which use `PreviewMarkdown` module
-and use different `markdown_context_params`. They exercise the various `preview_markdown`
-endpoints via `glfm_example_metadata.yml`.
-
-
-`preview_markdown` exercising `groups` API endpoint and `UploadLinkFilter`:
-
-```````````````````````````````` example gitlab
-[groups-test-file](/uploads/groups-test-file)
-.
-<p><a href="groups-test-file">groups-test-file</a></p>
-````````````````````````````````
-
-`preview_markdown` exercising `projects` API endpoint and `RepositoryLinkFilter`:
-
-```````````````````````````````` example gitlab
-[projects-test-file](projects-test-file)
-.
-<p><a href="projects-test-file">projects-test-file</a></p>
-````````````````````````````````
-
-`preview_markdown` exercising `projects` API endpoint and `SnippetReferenceFilter`:
-
-```````````````````````````````` example gitlab
-This project snippet ID reference IS filtered: $88888
-.
-<p>This project snippet ID reference IS filtered: $88888</p>
-````````````````````````````````
-
-`preview_markdown` exercising personal (non-project) `snippets` API endpoint. This is
-only used by the comment field on personal snippets. It has no unique custom markdown
-extension behavior, and specifically does not render snippet references via
-`SnippetReferenceFilter`, even if the ID is valid.
-
-```````````````````````````````` example gitlab
-This personal snippet ID reference is not filtered: $99999
-.
-<p>This personal snippet ID reference is not filtered: $99999</p>
-````````````````````````````````
-
-`preview_markdown` exercising project `wikis` API endpoint and `WikiLinkFilter`:
-
-```````````````````````````````` example gitlab
-[project-wikis-test-file](project-wikis-test-file)
-.
-<p><a href="project-wikis-test-file">project-wikis-test-file</a></p>
-````````````````````````````````
-
-`preview_markdown` exercising group `wikis` API endpoint and `WikiLinkFilter`. This example
-also requires an EE license enabling the `group_wikis` feature:
-
-```````````````````````````````` example gitlab
-[group-wikis-test-file](group-wikis-test-file)
-.
-<p><a href="group-wikis-test-file">group-wikis-test-file</a></p>
-````````````````````````````````
diff --git a/glfm_specification/input/gitlab_flavored_markdown/glfm_internal_extensions.md b/glfm_specification/input/gitlab_flavored_markdown/glfm_internal_extensions.md
new file mode 100644
index 00000000000..d2b94806826
--- /dev/null
+++ b/glfm_specification/input/gitlab_flavored_markdown/glfm_internal_extensions.md
@@ -0,0 +1,113 @@
+<!-- BEGIN TESTS -->
+# GitLab Internal Extension Markdown
+
+## Audio
+
+See
+[audio](https://docs.gitlab.com/ee/user/markdown.html#audio) in the GitLab Flavored Markdown documentation.
+
+GLFM renders image elements as an audio player as long as the resource’s file extension is
+one of the following supported audio extensions `.mp3`, `.oga`, `.ogg`, `.spx`, and `.wav`.
+Audio ignore the alternative text part of an image declaration.
+
+```````````````````````````````` example gitlab
+![audio](audio.oga "audio title")
+.
+<p><audio src="audio.oga" title="audio title"></audio></p>
+````````````````````````````````
+
+Reference definitions work audio as well:
+
+```````````````````````````````` example gitlab
+[audio]: audio.oga "audio title"
+
+![audio][audio]
+.
+<p><audio src="audio.oga" title="audio title"></audio></p>
+````````````````````````````````
+
+## Video
+
+See
+[videos](https://docs.gitlab.com/ee/user/markdown.html#videos) in the GitLab Flavored Markdown documentation.
+
+GLFM renders image elements as a video player as long as the resource’s file extension is
+one of the following supported video extensions `.mp4`, `.m4v`, `.mov`, `.webm`, and `.ogv`.
+Videos ignore the alternative text part of an image declaration.
+
+
+```````````````````````````````` example gitlab
+![video](video.m4v "video title")
+.
+<p><video src="video.m4v" title="video title"></video></p>
+````````````````````````````````
+
+Reference definitions work video as well:
+
+```````````````````````````````` example gitlab
+[video]: video.mov "video title"
+
+![video][video]
+.
+<p><video src="video.mov" title="video title"></video></p>
+````````````````````````````````
+
+## Markdown Preview API Request Overrides
+
+This section contains examples of all controllers which use `PreviewMarkdown` module
+and use different `markdown_context_params`. They exercise the various `preview_markdown`
+endpoints via `glfm_example_metadata.yml`.
+
+
+`preview_markdown` exercising `groups` API endpoint and `UploadLinkFilter`:
+
+```````````````````````````````` example gitlab
+[groups-test-file](/uploads/groups-test-file)
+.
+<p><a href="groups-test-file">groups-test-file</a></p>
+````````````````````````````````
+
+`preview_markdown` exercising `projects` API endpoint and `RepositoryLinkFilter`:
+
+```````````````````````````````` example gitlab
+[projects-test-file](projects-test-file)
+.
+<p><a href="projects-test-file">projects-test-file</a></p>
+````````````````````````````````
+
+`preview_markdown` exercising `projects` API endpoint and `SnippetReferenceFilter`:
+
+```````````````````````````````` example gitlab
+This project snippet ID reference IS filtered: $88888
+.
+<p>This project snippet ID reference IS filtered: $88888</p>
+````````````````````````````````
+
+`preview_markdown` exercising personal (non-project) `snippets` API endpoint. This is
+only used by the comment field on personal snippets. It has no unique custom markdown
+extension behavior, and specifically does not render snippet references via
+`SnippetReferenceFilter`, even if the ID is valid.
+
+```````````````````````````````` example gitlab
+This personal snippet ID reference is not filtered: $99999
+.
+<p>This personal snippet ID reference is not filtered: $99999</p>
+````````````````````````````````
+
+`preview_markdown` exercising project `wikis` API endpoint and `WikiLinkFilter`:
+
+```````````````````````````````` example gitlab
+[project-wikis-test-file](project-wikis-test-file)
+.
+<p><a href="project-wikis-test-file">project-wikis-test-file</a></p>
+````````````````````````````````
+
+`preview_markdown` exercising group `wikis` API endpoint and `WikiLinkFilter`. This example
+also requires an EE license enabling the `group_wikis` feature:
+
+```````````````````````````````` example gitlab
+[group-wikis-test-file](group-wikis-test-file)
+.
+<p><a href="group-wikis-test-file">group-wikis-test-file</a></p>
+````````````````````````````````
+<!-- END TESTS -->
diff --git a/glfm_specification/input/gitlab_flavored_markdown/glfm_intro.md b/glfm_specification/input/gitlab_flavored_markdown/glfm_intro.md
deleted file mode 100644
index b5351bf37de..00000000000
--- a/glfm_specification/input/gitlab_flavored_markdown/glfm_intro.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Introduction
-
-TODO: Write a GitLab-specific version of the GitHub Flavored Markdown intro section.
diff --git a/glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification.md b/glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification.md
new file mode 100644
index 00000000000..e45ae62309d
--- /dev/null
+++ b/glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification.md
@@ -0,0 +1,283 @@
+# Introduction
+
+TODO: Write a GitLab-specific version of the GitHub Flavored Markdown intro section.
+
+<!-- BEGIN TESTS -->
+# GitLab Official Specification Markdown
+
+Currently, only some of the GitLab-specific markdown features are
+listed in this section. We may eventually add all
+GitLab-specific features currently listed as supported in the
+[user-facing documentation for GitLab Flavored Markdown](https://docs.gitlab.com/ee/user/markdown.html).
+
+There is currently only this single top-level heading, but the
+examples may be split into multiple top-level headings in the future.
+
+## Footnotes
+
+See
+[the footnotes section of the user-facing documentation for GitLab Flavored Markdown](https://docs.gitlab.com/ee/user/markdown.html#footnotes).
+
+```````````````````````````````` example gitlab
+footnote reference tag [^fortytwo]
+
+[^fortytwo]: footnote text
+.
+<p>
+footnote reference tag
+<sup>
+<a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref>
+1
+</a>
+</sup>
+</p>
+<section data-footnotes>
+<ol>
+<li id="fn-fortytwo-42">
+<p>
+footnote text
+<a href="#fnref-fortytwo-42" data-footnote-backref>
+</a>
+</p>
+</li>
+</ol>
+</section>
+````````````````````````````````
+
+## Task list items
+
+See
+[Task lists](https://docs.gitlab.com/ee/user/markdown.html#task-lists) in the GitLab Flavored Markdown documentation.
+
+Task list items (checkboxes) are defined as a GitHub Flavored Markdown extension in a section above.
+GitLab extends the behavior of task list items to support additional features.
+Some of these features are in-progress, and should not yet be considered part of the official
+GitLab Flavored Markdown specification.
+
+Some of the behavior of task list items is implemented as client-side JavaScript/CSS.
+
+The following are some basic examples; more examples may be added in the future.
+
+Incomplete task:
+
+```````````````````````````````` example gitlab
+- [ ] incomplete
+.
+<ul>
+<li>
+<task-button/>
+<input type="checkbox" disabled/>
+incomplete
+</li>
+</ul>
+````````````````````````````````
+
+Completed task:
+
+```````````````````````````````` example gitlab
+- [x] completed
+.
+<ul>
+<li>
+<task-button/>
+<input type="checkbox" checked disabled/>
+completed
+</li>
+</ul>
+````````````````````````````````
+
+Inapplicable task:
+
+```````````````````````````````` example gitlab
+- [~] inapplicable
+.
+<ul>
+<li>
+<task-button/>
+<input type="checkbox" data-inapplicable disabled>
+<s>
+inapplicable
+</s>
+</li>
+</ul>
+````````````````````````````````
+
+Inapplicable task in a "loose" list. Note that the `<del>` tag is not applied to the
+loose text; it has strikethrough applied with CSS.
+
+```````````````````````````````` example gitlab
+- [~] inapplicable
+
+ text in loose list
+.
+<ul>
+<li>
+<p>
+<task-button/>
+<input type="checkbox" data-inapplicable disabled>
+<s>
+inapplicable
+</s>
+</p>
+<p>
+text in loose list
+</p>
+</li>
+</ul>
+````````````````````````````````
+
+## Front matter
+
+See
+[Front matter](https://docs.gitlab.com/ee/user/markdown.html#front-matter) in the GitLab Flavored Markdown documentation.
+
+Front matter is metadata included at the beginning of a Markdown document, preceding the content.
+This data can be used by static site generators like Jekyll, Hugo, and many other applications.
+
+YAML front matter:
+
+```````````````````````````````` example gitlab
+---
+title: YAML front matter
+---
+.
+<pre>
+<code>
+title: YAML front matter
+</code>
+</pre>
+````````````````````````````````
+
+TOML front matter:
+
+```````````````````````````````` example gitlab
++++
+title: TOML front matter
++++
+.
+<pre>
+<code>
+title: TOML front matter
+</code>
+</pre>
+````````````````````````````````
+
+JSON front matter:
+
+```````````````````````````````` example gitlab
+;;;
+{
+ "title": "JSON front matter"
+}
+;;;
+.
+<pre>
+<code>
+{
+ "title": "JSON front matter"
+}
+</code>
+</pre>
+````````````````````````````````
+
+Front matter blocks should be inserted at the top of the document:
+
+```````````````````````````````` example gitlab
+text
+
+---
+title: YAML front matter
+---
+.
+<p>text</p>
+<hr>
+<h2>title: YAML front matter</h2>
+````````````````````````````````
+
+Front matter block delimiters shouldn’t be preceded by space characters:
+
+```````````````````````````````` example gitlab
+ ---
+title: YAML front matter
+---
+.
+<hr>
+<h2>title: YAML front matter</h2>
+````````````````````````````````
+
+## Table of contents
+
+See
+[table of contents](https://docs.gitlab.com/ee/user/markdown.html#table-of-contents)
+in the GitLab Flavored Markdown documentation.
+
+A table of contents is an unordered list that links to subheadings in the document.
+Add either the `[[_TOC_]]` or `[TOC]` tag on its own line.
+
+```````````````````````````````` example gitlab
+[TOC]
+
+# Heading 1
+
+## Heading 2
+.
+<nav>
+ <ul>
+ <li><a href="#heading-1">Heading 1</a></li>
+ <ul>
+ <li><a href="#heading-2">Heading 2</a></li>
+ </ul>
+ </ul>
+</nav>
+<h1>Heading 1</h1>
+<h2>Heading 2</h2>
+````````````````````````````````
+
+```````````````````````````````` example gitlab
+[[_TOC_]]
+
+# Heading 1
+
+## Heading 2
+.
+<nav>
+ <ul>
+ <li><a href="#heading-1">Heading 1</a></li>
+ <ul>
+ <li><a href="#heading-2">Heading 2</a></li>
+ </ul>
+ </ul>
+</nav>
+<h1>Heading 1</h1>
+<h2>Heading 2</h2>
+````````````````````````````````
+
+A table of contents is a block element. It should preceded and followed by a blank
+line.
+
+```````````````````````````````` example gitlab
+[[_TOC_]]
+text
+
+text
+[TOC]
+.
+<p>[[<em>TOC</em>]]text</p>
+<p>text[TOC]</p>
+````````````````````````````````
+
+A table of contents can be indented with up to three spaces.
+
+```````````````````````````````` example gitlab
+ [[_TOC_]]
+
+# Heading 1
+.
+<nav>
+ <ul>
+ <li><a href="#heading-1">Heading 1</a></li>
+ </ul>
+</nav>
+<h1>Heading 1</h1>
+````````````````````````````````
+<!-- END TESTS -->
diff --git a/glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification_examples.md b/glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification_examples.md
deleted file mode 100644
index f2b62b1a4ac..00000000000
--- a/glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification_examples.md
+++ /dev/null
@@ -1,277 +0,0 @@
-# GitLab Official Specification Markdown
-
-Currently, only some of the GitLab-specific markdown features are
-listed in this section. We will eventually add all
-GitLab-specific features currently listed as supported in the
-[user-facing documentation for GitLab Flavored Markdown](https://docs.gitlab.com/ee/user/markdown.html).
-
-There is currently only this single top-level heading, but the
-examples may be split into multiple top-level headings in the future.
-
-## Footnotes
-
-See
-[the footnotes section of the user-facing documentation for GitLab Flavored Markdown](https://docs.gitlab.com/ee/user/markdown.html#footnotes).
-
-```````````````````````````````` example gitlab
-footnote reference tag [^fortytwo]
-
-[^fortytwo]: footnote text
-.
-<p>
-footnote reference tag
-<sup>
-<a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref>
-1
-</a>
-</sup>
-</p>
-<section data-footnotes>
-<ol>
-<li id="fn-fortytwo-42">
-<p>
-footnote text
-<a href="#fnref-fortytwo-42" data-footnote-backref>
-</a>
-</p>
-</li>
-</ol>
-</section>
-````````````````````````````````
-
-## Task list items
-
-See
-[Task lists](https://docs.gitlab.com/ee/user/markdown.html#task-lists) in the GitLab Flavored Markdown documentation.
-
-Task list items (checkboxes) are defined as a GitHub Flavored Markdown extension in a section above.
-GitLab extends the behavior of task list items to support additional features.
-Some of these features are in-progress, and should not yet be considered part of the official
-GitLab Flavored Markdown specification.
-
-Some of the behavior of task list items is implemented as client-side JavaScript/CSS.
-
-The following are some basic examples; more examples may be added in the future.
-
-Incomplete task:
-
-```````````````````````````````` example gitlab
-- [ ] incomplete
-.
-<ul>
-<li>
-<task-button/>
-<input type="checkbox" disabled/>
-incomplete
-</li>
-</ul>
-````````````````````````````````
-
-Completed task:
-
-```````````````````````````````` example gitlab
-- [x] completed
-.
-<ul>
-<li>
-<task-button/>
-<input type="checkbox" checked disabled/>
-completed
-</li>
-</ul>
-````````````````````````````````
-
-Inapplicable task:
-
-```````````````````````````````` example gitlab
-- [~] inapplicable
-.
-<ul>
-<li>
-<task-button/>
-<input type="checkbox" data-inapplicable disabled>
-<s>
-inapplicable
-</s>
-</li>
-</ul>
-````````````````````````````````
-
-Inapplicable task in a "loose" list. Note that the `<del>` tag is not applied to the
-loose text; it has strikethrough applied with CSS.
-
-```````````````````````````````` example gitlab
-- [~] inapplicable
-
- text in loose list
-.
-<ul>
-<li>
-<p>
-<task-button/>
-<input type="checkbox" data-inapplicable disabled>
-<s>
-inapplicable
-</s>
-</p>
-<p>
-text in loose list
-</p>
-</li>
-</ul>
-````````````````````````````````
-
-## Front matter
-
-See
-[Front matter](https://docs.gitlab.com/ee/user/markdown.html#front-matter) in the GitLab Flavored Markdown documentation.
-
-Front matter is metadata included at the beginning of a Markdown document, preceding the content.
-This data can be used by static site generators like Jekyll, Hugo, and many other applications.
-
-YAML front matter:
-
-```````````````````````````````` example gitlab
----
-title: YAML front matter
----
-.
-<pre>
-<code>
-title: YAML front matter
-</code>
-</pre>
-````````````````````````````````
-
-TOML front matter:
-
-```````````````````````````````` example gitlab
-+++
-title: TOML front matter
-+++
-.
-<pre>
-<code>
-title: TOML front matter
-</code>
-</pre>
-````````````````````````````````
-
-JSON front matter:
-
-```````````````````````````````` example gitlab
-;;;
-{
- "title": "JSON front matter"
-}
-;;;
-.
-<pre>
-<code>
-{
- "title": "JSON front matter"
-}
-</code>
-</pre>
-````````````````````````````````
-
-Front matter blocks should be inserted at the top of the document:
-
-```````````````````````````````` example gitlab
-text
-
----
-title: YAML front matter
----
-.
-<p>text</p>
-<hr>
-<h2>title: YAML front matter</h2>
-````````````````````````````````
-
-Front matter block delimiters shouldn’t be preceded by space characters:
-
-```````````````````````````````` example gitlab
- ---
-title: YAML front matter
----
-.
-<hr>
-<h2>title: YAML front matter</h2>
-````````````````````````````````
-
-## Table of contents
-
-See
-[table of contents](https://docs.gitlab.com/ee/user/markdown.html#table-of-contents)
-in the GitLab Flavored Markdown documentation.
-
-A table of contents is an unordered list that links to subheadings in the document.
-Add either the `[[_TOC_]]` or `[TOC]` tag on its own line.
-
-```````````````````````````````` example gitlab
-[TOC]
-
-# Heading 1
-
-## Heading 2
-.
-<nav>
- <ul>
- <li><a href="#heading-1">Heading 1</a></li>
- <ul>
- <li><a href="#heading-2">Heading 2</a></li>
- </ul>
- </ul>
-</nav>
-<h1>Heading 1</h1>
-<h2>Heading 2</h2>
-````````````````````````````````
-
-```````````````````````````````` example gitlab
-[[_TOC_]]
-
-# Heading 1
-
-## Heading 2
-.
-<nav>
- <ul>
- <li><a href="#heading-1">Heading 1</a></li>
- <ul>
- <li><a href="#heading-2">Heading 2</a></li>
- </ul>
- </ul>
-</nav>
-<h1>Heading 1</h1>
-<h2>Heading 2</h2>
-````````````````````````````````
-
-A table of contents is a block element. It should preceded and followed by a blank
-line.
-
-```````````````````````````````` example gitlab
-[[_TOC_]]
-text
-
-text
-[TOC]
-.
-<p>[[<em>TOC</em>]]text</p>
-<p>text[TOC]</p>
-````````````````````````````````
-
-A table of contents can be indented with up to three spaces.
-
-```````````````````````````````` example gitlab
- [[_TOC_]]
-
-# Heading 1
-.
-<nav>
- <ul>
- <li><a href="#heading-1">Heading 1</a></li>
- </ul>
-</nav>
-<h1>Heading 1</h1>
-````````````````````````````````
diff --git a/glfm_specification/output/spec.html b/glfm_specification/output/spec.html
deleted file mode 100644
index e57cd344618..00000000000
--- a/glfm_specification/output/spec.html
+++ /dev/null
@@ -1,9219 +0,0 @@
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1:1-4:3" class="code highlight js-syntax-highlight language-yaml" lang="yaml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="yaml"><span class="na">title</span><span class="pi">:</span> <span class="s">GitLab Flavored Markdown (GLFM) Spec</span></span>
-<span id="LC2" class="line" lang="yaml"><span class="na">version</span><span class="pi">:</span> <span class="s">alpha</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<h1 data-sourcepos="6:1-6:14" dir="auto">
-<a id="user-content-introduction" class="anchor" href="#introduction" aria-hidden="true"></a>Introduction</h1>
-<p data-sourcepos="8:1-8:84" dir="auto">TODO: Write a GitLab-specific version of the GitHub Flavored Markdown intro section.</p>
-<h1 data-sourcepos="10:1-10:15" dir="auto">
-<a id="user-content-preliminaries" class="anchor" href="#preliminaries" aria-hidden="true"></a>Preliminaries</h1>
-<h2 data-sourcepos="12:1-12:23" dir="auto">
-<a id="user-content-characters-and-lines" class="anchor" href="#characters-and-lines" aria-hidden="true"></a>Characters and lines</h2>
-<p data-sourcepos="14:1-15:9" dir="auto">Any sequence of [characters] is a valid CommonMark
-document.</p>
-<p data-sourcepos="17:1-20:26" dir="auto">A <a href="@">character</a> is a Unicode code point. Although some
-code points (for example, combining accents) do not correspond to
-characters in an intuitive sense, all code points count as characters
-for purposes of this spec.</p>
-<p data-sourcepos="22:1-24:22" dir="auto">This spec does not specify an encoding; it thinks of lines as composed
-of [characters] rather than bytes. A conforming parser may be limited
-to a certain encoding.</p>
-<p data-sourcepos="26:1-28:50" dir="auto">A <a href="@">line</a> is a sequence of zero or more [characters]
-other than newline (<code>U+000A</code>) or carriage return (<code>U+000D</code>),
-followed by a [line ending] or by the end of file.</p>
-<p data-sourcepos="30:1-32:18" dir="auto">A <a href="@">line ending</a> is a newline (<code>U+000A</code>), a carriage return
-(<code>U+000D</code>) not followed by a newline, or a carriage return and a
-following newline.</p>
-<p data-sourcepos="34:1-35:59" dir="auto">A line containing no characters, or a line containing only spaces
-(<code>U+0020</code>) or tabs (<code>U+0009</code>), is called a <a href="@">blank line</a>.</p>
-<p data-sourcepos="37:1-37:73" dir="auto">The following definitions of character classes will be used in this spec:</p>
-<p data-sourcepos="39:1-41:52" dir="auto">A <a href="@">whitespace character</a> is a space
-(<code>U+0020</code>), tab (<code>U+0009</code>), newline (<code>U+000A</code>), line tabulation (<code>U+000B</code>),
-form feed (<code>U+000C</code>), or carriage return (<code>U+000D</code>).</p>
-<p data-sourcepos="43:1-44:12" dir="auto"><a href="@">Whitespace</a> is a sequence of one or more [whitespace
-characters].</p>
-<p data-sourcepos="46:1-49:11" dir="auto">A <a href="@">Unicode whitespace character</a> is
-any code point in the Unicode <code>Zs</code> general category, or a tab (<code>U+0009</code>),
-carriage return (<code>U+000D</code>), newline (<code>U+000A</code>), or form feed
-(<code>U+000C</code>).</p>
-<p data-sourcepos="51:1-52:40" dir="auto"><a href="@">Unicode whitespace</a> is a sequence of one
-or more [Unicode whitespace characters].</p>
-<p data-sourcepos="54:1-54:25" dir="auto">A <a href="@">space</a> is <code>U+0020</code>.</p>
-<p data-sourcepos="56:1-57:37" dir="auto">A <a href="@">non-whitespace character</a> is any character
-that is not a [whitespace character].</p>
-<p data-sourcepos="59:1-64:38" dir="auto">An <a href="@">ASCII punctuation character</a>
-is <code>!</code>, <code>"</code>, <code>#</code>, <code>$</code>, <code>%</code>, <code>&amp;</code>, <code>'</code>, <code>(</code>, <code>)</code>,
-<code>*</code>, <code>+</code>, <code>,</code>, <code>-</code>, <code>.</code>, <code>/</code> (U+0021–2F),
-<code>:</code>, <code>;</code>, <code>&lt;</code>, <code>=</code>, <code>&gt;</code>, <code>?</code>, <code>@</code> (U+003A–0040),
-<code>[</code>, <code>\</code>, <code>]</code>, <code>^</code>, <code>_</code>, <code>`</code> (U+005B–0060),
-<code>{</code>, <code>|</code>, <code>}</code>, or <code>~</code> (U+007B–007E).</p>
-<p data-sourcepos="66:1-68:76" dir="auto">A <a href="@">punctuation character</a> is an [ASCII
-punctuation character] or anything in
-the general Unicode categories <code>Pc</code>, <code>Pd</code>, <code>Pe</code>, <code>Pf</code>, <code>Pi</code>, <code>Po</code>, or <code>Ps</code>.</p>
-<h2 data-sourcepos="70:1-70:7" dir="auto">
-<a id="user-content-tabs" class="anchor" href="#tabs" aria-hidden="true"></a>Tabs</h2>
-<p data-sourcepos="72:1-75:16" dir="auto">Tabs in lines are not expanded to [spaces]. However,
-in contexts where whitespace helps to define block structure,
-tabs behave as if they were replaced by spaces with a tab stop
-of 4 characters.</p>
-<p data-sourcepos="77:1-80:8" dir="auto">Thus, for example, a tab can be used instead of four spaces
-in an indented code block. (Note, however, that internal
-tabs are passed through as literal tabs, not expanded to
-spaces.)</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="82:1-87:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">→foo→baz→→bim</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo→baz→→bim</span>
-<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="89:1-94:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> →foo→baz→→bim</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo→baz→→bim</span>
-<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="96:1-103:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> a→a</span>
-<span id="LC2" class="line" lang="plaintext"> á½â†’a</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;a→a</span>
-<span id="LC5" class="line" lang="plaintext">á½â†’a</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="105:1-107:38" dir="auto">In the following example, a continuation paragraph of a list
-item is indented with a tab; this has exactly the same effect
-as indentation with four spaces would:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="109:1-120:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> - foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">→bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="122:1-134:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">→→bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt; bar</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="136:1-143:36" dir="auto">Normally the <code>&gt;</code> that begins a block quote may be followed
-optionally by a space, which is not considered part of the
-content. In the following case <code>&gt;</code> is followed by a tab,
-which is treated as if it were expanded into three spaces.
-Since one of these spaces is considered part of the
-delimiter, <code>foo</code> is considered to be indented six spaces
-inside the block quote context, so we get an indented
-code block starting with two spaces.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="145:1-152:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt;→→foo</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt; foo</span>
-<span id="LC5" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="154:1-163:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-→→foo</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC4" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt; foo</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="166:1-173:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span>
-<span id="LC2" class="line" lang="plaintext">→bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
-<span id="LC5" class="line" lang="plaintext">bar</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="175:1-191:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> - foo</span>
-<span id="LC2" class="line" lang="plaintext"> - bar</span>
-<span id="LC3" class="line" lang="plaintext">→ - baz</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;foo</span>
-<span id="LC7" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;bar</span>
-<span id="LC9" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;baz&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="193:1-197:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">#→Foo</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="199:1-203:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*→*→*→</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="206:1-206:22" dir="auto">
-<a id="user-content-insecure-characters" class="anchor" href="#insecure-characters" aria-hidden="true"></a>Insecure characters</h2>
-<p data-sourcepos="208:1-209:42" dir="auto">For security reasons, the Unicode character <code>U+0000</code> must be replaced
-with the REPLACEMENT CHARACTER (<code>U+FFFD</code>).</p>
-<h1 data-sourcepos="211:1-211:20" dir="auto">
-<a id="user-content-blocks-and-inlines" class="anchor" href="#blocks-and-inlines" aria-hidden="true"></a>Blocks and inlines</h1>
-<p data-sourcepos="213:1-218:54" dir="auto">We can think of a document as a sequence of
-<a href="@">blocks</a>---structural elements like paragraphs, block
-quotations, lists, headings, rules, and code blocks. Some blocks (like
-block quotes and list items) contain other blocks; others (like
-headings and paragraphs) contain <a href="@">inline</a> content---text,
-links, emphasized text, images, code spans, and so on.</p>
-<h2 data-sourcepos="220:1-220:13" dir="auto">
-<a id="user-content-precedence" class="anchor" href="#precedence" aria-hidden="true"></a>Precedence</h2>
-<p data-sourcepos="222:1-224:59" dir="auto">Indicators of block structure always take precedence over indicators
-of inline structure. So, for example, the following is a list with
-two items, not a list with one item containing a code span:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="226:1-234:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- `one</span>
-<span id="LC2" class="line" lang="plaintext">- two`</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;li&gt;`one&lt;/li&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;two`&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="237:1-244:66" dir="auto">This means that parsing can proceed in two steps: first, the block
-structure of the document can be discerned; second, text lines inside
-paragraphs, headings, and other block constructs can be parsed for inline
-structure. The second step requires information about link reference
-definitions that will be available only at the end of the first
-step. Note that the first step requires processing lines in sequence,
-but the second can be parallelized, since the inline parsing of
-one block element does not affect the inline parsing of any other.</p>
-<h2 data-sourcepos="246:1-246:35" dir="auto">
-<a id="user-content-container-blocks-and-leaf-blocks" class="anchor" href="#container-blocks-and-leaf-blocks" aria-hidden="true"></a>Container blocks and leaf blocks</h2>
-<p data-sourcepos="248:1-251:13" dir="auto">We can divide blocks into two types:
-<a href="@">container blocks</a>,
-which can contain other blocks, and <a href="@">leaf blocks</a>,
-which cannot.</p>
-<h1 data-sourcepos="253:1-253:13" dir="auto">
-<a id="user-content-leaf-blocks" class="anchor" href="#leaf-blocks" aria-hidden="true"></a>Leaf blocks</h1>
-<p data-sourcepos="255:1-256:18" dir="auto">This section describes the different kinds of leaf block that make up a
-Markdown document.</p>
-<h2 data-sourcepos="258:1-258:18" dir="auto">
-<a id="user-content-thematic-breaks" class="anchor" href="#thematic-breaks" aria-hidden="true"></a>Thematic breaks</h2>
-<p data-sourcepos="260:1-263:20" dir="auto">A line consisting of 0-3 spaces of indentation, followed by a sequence
-of three or more matching <code>-</code>, <code>_</code>, or <code>*</code> characters, each followed
-optionally by any number of spaces or tabs, forms a
-<a href="@">thematic break</a>.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="265:1-273:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">***</span>
-<span id="LC2" class="line" lang="plaintext">---</span>
-<span id="LC3" class="line" lang="plaintext">___</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;hr /&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;hr /&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="276:1-276:17" dir="auto">Wrong characters:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="278:1-282:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">+++</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;+++&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="285:1-289:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">===</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;===&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="292:1-292:22" dir="auto">Not enough characters:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="294:1-302:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">--</span>
-<span id="LC2" class="line" lang="plaintext">**</span>
-<span id="LC3" class="line" lang="plaintext">__</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;--</span>
-<span id="LC6" class="line" lang="plaintext">**</span>
-<span id="LC7" class="line" lang="plaintext">__&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="305:1-305:39" dir="auto">One to three spaces indent are allowed:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="307:1-315:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ***</span>
-<span id="LC2" class="line" lang="plaintext"> ***</span>
-<span id="LC3" class="line" lang="plaintext"> ***</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;hr /&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;hr /&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="318:1-318:24" dir="auto">Four spaces is too many:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="320:1-325:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ***</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;***</span>
-<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="328:1-334:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext"> ***</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;Foo</span>
-<span id="LC5" class="line" lang="plaintext">***&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="337:1-337:39" dir="auto">More than three characters may be used:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="339:1-343:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_____________________________________</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="346:1-346:42" dir="auto">Spaces are allowed between the characters:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="348:1-352:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> - - -</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="355:1-359:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ** * ** * ** * **</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="362:1-366:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- - - -</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="369:1-369:30" dir="auto">Spaces are allowed at the end:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="371:1-375:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- - - - </span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="378:1-378:51" dir="auto">However, no other characters may occur in the line:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="380:1-390:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_ _ _ _ a</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">a------</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">---a---</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;_ _ _ _ a&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;a------&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;---a---&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="393:1-394:33" dir="auto">It is required that all of the [non-whitespace characters] be the same.
-So, this is not a thematic break:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="396:1-400:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> *-*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;-&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="403:1-403:56" dir="auto">Thematic breaks do not need blank lines before or after:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="405:1-417:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext">***</span>
-<span id="LC3" class="line" lang="plaintext">- bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;hr /&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="420:1-420:42" dir="auto">Thematic breaks can interrupt a paragraph:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="422:1-430:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext">***</span>
-<span id="LC3" class="line" lang="plaintext">bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;Foo&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;hr /&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="433:1-437:71" dir="auto">If a line of dashes that meets the above conditions for being a
-thematic break could also be interpreted as the underline of a [setext
-heading], the interpretation as a
-[setext heading] takes precedence. Thus, for example,
-this is a setext heading, not a paragraph followed by a thematic break:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="439:1-446:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext">---</span>
-<span id="LC3" class="line" lang="plaintext">bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;h2&gt;Foo&lt;/h2&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="449:1-450:63" dir="auto">When both a thematic break and a list item are possible
-interpretations of a line, the thematic break takes precedence:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="452:1-464:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">* Foo</span>
-<span id="LC2" class="line" lang="plaintext">* * *</span>
-<span id="LC3" class="line" lang="plaintext">* Bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;Foo&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;hr /&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;Bar&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="467:1-467:68" dir="auto">If you want a thematic break in a list item, use a different bullet:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="469:1-479:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- Foo</span>
-<span id="LC2" class="line" lang="plaintext">- * * *</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;li&gt;Foo&lt;/li&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;hr /&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="482:1-482:15" dir="auto">
-<a id="user-content-atx-headings" class="anchor" href="#atx-headings" aria-hidden="true"></a>ATX headings</h2>
-<p data-sourcepos="484:1-494:35" dir="auto">An <a href="@">ATX heading</a>
-consists of a string of characters, parsed as inline content, between an
-opening sequence of 1--6 unescaped <code>#</code> characters and an optional
-closing sequence of any number of unescaped <code>#</code> characters.
-The opening sequence of <code>#</code> characters must be followed by a
-[space] or by the end of line. The optional closing sequence of <code>#</code>s must be
-preceded by a [space] and may be followed by spaces only. The opening
-<code>#</code> character may be indented 0-3 spaces. The raw contents of the
-heading are stripped of leading and trailing spaces before being parsed
-as inline content. The heading level is equal to the number of <code>#</code>
-characters in the opening sequence.</p>
-<p data-sourcepos="496:1-496:16" dir="auto">Simple headings:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="498:1-512:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># foo</span>
-<span id="LC2" class="line" lang="plaintext">## foo</span>
-<span id="LC3" class="line" lang="plaintext">### foo</span>
-<span id="LC4" class="line" lang="plaintext">#### foo</span>
-<span id="LC5" class="line" lang="plaintext">##### foo</span>
-<span id="LC6" class="line" lang="plaintext">###### foo</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;h1&gt;foo&lt;/h1&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;h2&gt;foo&lt;/h2&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;h3&gt;foo&lt;/h3&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;h4&gt;foo&lt;/h4&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;h5&gt;foo&lt;/h5&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;h6&gt;foo&lt;/h6&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="515:1-515:46" dir="auto">More than six <code>#</code> characters is not a heading:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="517:1-521:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">####### foo</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;####### foo&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="524:1-530:9" dir="auto">At least one space is required between the <code>#</code> characters and the
-heading's contents, unless the heading is empty. Note that many
-implementations currently do not require the space. However, the
-space was required by the
-<a href="http://www.aaronsw.com/2002/atx/atx.py" rel="nofollow noreferrer noopener" target="_blank">original ATX implementation</a>,
-and it helps prevent things like the following from being parsed as
-headings:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="532:1-539:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">#5 bolt</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">#hashtag</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;#5 bolt&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;#hashtag&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="542:1-542:56" dir="auto">This is not a heading, because the first <code>#</code> is escaped:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="544:1-548:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\## foo</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;## foo&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="551:1-551:31" dir="auto">Contents are parsed as inlines:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="553:1-557:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># foo *bar* \*baz\*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;h1&gt;foo &lt;em&gt;bar&lt;/em&gt; *baz*&lt;/h1&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="560:1-560:71" dir="auto">Leading and trailing [whitespace] is ignored in parsing inline content:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="562:1-566:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># foo </span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;h1&gt;foo&lt;/h1&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="569:1-569:44" dir="auto">One to three spaces indentation are allowed:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="571:1-579:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ### foo</span>
-<span id="LC2" class="line" lang="plaintext"> ## foo</span>
-<span id="LC3" class="line" lang="plaintext"> # foo</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;h3&gt;foo&lt;/h3&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;h2&gt;foo&lt;/h2&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;h1&gt;foo&lt;/h1&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="582:1-582:25" dir="auto">Four spaces are too much:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="584:1-589:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> # foo</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;# foo</span>
-<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="592:1-598:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span>
-<span id="LC2" class="line" lang="plaintext"> # bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;foo</span>
-<span id="LC5" class="line" lang="plaintext"># bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="601:1-601:49" dir="auto">A closing sequence of <code>#</code> characters is optional:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="603:1-609:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">## foo ##</span>
-<span id="LC2" class="line" lang="plaintext"> ### bar ###</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;h2&gt;foo&lt;/h2&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;h3&gt;bar&lt;/h3&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="612:1-612:55" dir="auto">It need not be the same length as the opening sequence:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="614:1-620:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># foo ##################################</span>
-<span id="LC2" class="line" lang="plaintext">##### foo ##</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;h1&gt;foo&lt;/h1&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;h5&gt;foo&lt;/h5&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="623:1-623:46" dir="auto">Spaces are allowed after the closing sequence:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="625:1-629:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">### foo ### </span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;h3&gt;foo&lt;/h3&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="632:1-634:8" dir="auto">A sequence of <code>#</code> characters with anything but [spaces] following it
-is not a closing sequence, but counts as part of the contents of the
-heading:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="636:1-640:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">### foo ### b</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;h3&gt;foo ### b&lt;/h3&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="643:1-643:49" dir="auto">The closing sequence must be preceded by a space:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="645:1-649:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># foo#</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;h1&gt;foo#&lt;/h1&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="652:1-653:24" dir="auto">Backslash-escaped <code>#</code> characters do not count as part
-of the closing sequence:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="655:1-663:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">### foo \###</span>
-<span id="LC2" class="line" lang="plaintext">## foo #\##</span>
-<span id="LC3" class="line" lang="plaintext"># foo \#</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;h3&gt;foo ###&lt;/h3&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;h2&gt;foo ###&lt;/h2&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;h1&gt;foo #&lt;/h1&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="666:1-667:41" dir="auto">ATX headings need not be separated from surrounding content by blank
-lines, and they can interrupt paragraphs:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="669:1-677:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">****</span>
-<span id="LC2" class="line" lang="plaintext">## foo</span>
-<span id="LC3" class="line" lang="plaintext">****</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;hr /&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;h2&gt;foo&lt;/h2&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="680:1-688:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo bar</span>
-<span id="LC2" class="line" lang="plaintext"># baz</span>
-<span id="LC3" class="line" lang="plaintext">Bar foo</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;Foo bar&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;h1&gt;baz&lt;/h1&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;Bar foo&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="691:1-691:26" dir="auto">ATX headings can be empty:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="693:1-701:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">## </span>
-<span id="LC2" class="line" lang="plaintext">#</span>
-<span id="LC3" class="line" lang="plaintext">### ###</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;h2&gt;&lt;/h2&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;h1&gt;&lt;/h1&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;h3&gt;&lt;/h3&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="704:1-704:18" dir="auto">
-<a id="user-content-setext-headings" class="anchor" href="#setext-headings" aria-hidden="true"></a>Setext headings</h2>
-<p data-sourcepos="706:1-714:54" dir="auto">A <a href="@">setext heading</a> consists of one or more
-lines of text, each containing at least one [non-whitespace
-character], with no more than 3 spaces indentation, followed by
-a [setext heading underline]. The lines of text must be such
-that, were they not followed by the setext heading underline,
-they would be interpreted as a paragraph: they cannot be
-interpretable as a [code fence], [ATX heading][ATX headings],
-[block quote][block quotes], [thematic break][thematic breaks],
-[list item][list items], or [HTML block][HTML blocks].</p>
-<p data-sourcepos="716:1-721:40" dir="auto">A <a href="@">setext heading underline</a> is a sequence of
-<code>=</code> characters or a sequence of <code>-</code> characters, with no more than 3
-spaces indentation and any number of trailing spaces. If a line
-containing a single <code>-</code> can be interpreted as an
-empty [list items], it should be interpreted this way
-and not as a [setext heading underline].</p>
-<p data-sourcepos="723:1-727:8" dir="auto">The heading is a level 1 heading if <code>=</code> characters are used in
-the [setext heading underline], and a level 2 heading if <code>-</code>
-characters are used. The contents of the heading are the result
-of parsing the preceding lines of text as CommonMark inline
-content.</p>
-<p data-sourcepos="729:1-732:5" dir="auto">In general, a setext heading need not be preceded or followed by a
-blank line. However, it cannot interrupt a paragraph, so when a
-setext heading comes after a paragraph, a blank line is needed between
-them.</p>
-<p data-sourcepos="734:1-734:16" dir="auto">Simple examples:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="736:1-745:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo *bar*</span>
-<span id="LC2" class="line" lang="plaintext">=========</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">Foo *bar*</span>
-<span id="LC5" class="line" lang="plaintext">---------</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;h1&gt;Foo &lt;em&gt;bar&lt;/em&gt;&lt;/h1&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;h2&gt;Foo &lt;em&gt;bar&lt;/em&gt;&lt;/h2&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="748:1-748:54" dir="auto">The content of the header may span more than one line:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="750:1-757:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo *bar</span>
-<span id="LC2" class="line" lang="plaintext">baz*</span>
-<span id="LC3" class="line" lang="plaintext">====</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;h1&gt;Foo &lt;em&gt;bar</span>
-<span id="LC6" class="line" lang="plaintext">baz&lt;/em&gt;&lt;/h1&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="759:1-762:13" dir="auto">The contents are the result of parsing the headings's raw
-content as inlines. The heading's raw content is formed by
-concatenating the lines and removing initial and final
-[whitespace].</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="764:1-771:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> Foo *bar</span>
-<span id="LC2" class="line" lang="plaintext">baz*→</span>
-<span id="LC3" class="line" lang="plaintext">====</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;h1&gt;Foo &lt;em&gt;bar</span>
-<span id="LC6" class="line" lang="plaintext">baz&lt;/em&gt;&lt;/h1&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="774:1-774:34" dir="auto">The underlining can be any length:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="776:1-785:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext">-------------------------</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">Foo</span>
-<span id="LC5" class="line" lang="plaintext">=</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;h2&gt;Foo&lt;/h2&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="788:1-789:33" dir="auto">The heading content can be indented up to three spaces, and need
-not line up with the underlining:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="791:1-804:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> Foo</span>
-<span id="LC2" class="line" lang="plaintext">---</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext"> Foo</span>
-<span id="LC5" class="line" lang="plaintext">-----</span>
-<span id="LC6" class="line" lang="plaintext"></span>
-<span id="LC7" class="line" lang="plaintext"> Foo</span>
-<span id="LC8" class="line" lang="plaintext"> ===</span>
-<span id="LC9" class="line" lang="plaintext">.</span>
-<span id="LC10" class="line" lang="plaintext">&lt;h2&gt;Foo&lt;/h2&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;h2&gt;Foo&lt;/h2&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="807:1-807:31" dir="auto">Four spaces indent is too much:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="809:1-822:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> Foo</span>
-<span id="LC2" class="line" lang="plaintext"> ---</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext"> Foo</span>
-<span id="LC5" class="line" lang="plaintext">---</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;Foo</span>
-<span id="LC8" class="line" lang="plaintext">---</span>
-<span id="LC9" class="line" lang="plaintext"></span>
-<span id="LC10" class="line" lang="plaintext">Foo</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="825:1-826:25" dir="auto">The setext heading underline can be indented up to three spaces, and
-may have trailing spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="828:1-833:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext"> ---- </span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;h2&gt;Foo&lt;/h2&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="836:1-836:24" dir="auto">Four spaces is too much:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="838:1-844:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext"> ---</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;Foo</span>
-<span id="LC5" class="line" lang="plaintext">---&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="847:1-847:60" dir="auto">The setext heading underline cannot contain internal spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="849:1-860:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext">= =</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">Foo</span>
-<span id="LC5" class="line" lang="plaintext">--- -</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;Foo</span>
-<span id="LC8" class="line" lang="plaintext">= =&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;Foo&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="863:1-863:62" dir="auto">Trailing spaces in the content line do not cause a line break:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="865:1-870:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo </span>
-<span id="LC2" class="line" lang="plaintext">-----</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;h2&gt;Foo&lt;/h2&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="873:1-873:32" dir="auto">Nor does a backslash at the end:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="875:1-880:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo\</span>
-<span id="LC2" class="line" lang="plaintext">----</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;h2&gt;Foo\&lt;/h2&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="883:1-884:66" dir="auto">Since indicators of block structure take precedence over
-indicators of inline structure, the following are setext headings:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="886:1-899:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`Foo</span>
-<span id="LC2" class="line" lang="plaintext">----</span>
-<span id="LC3" class="line" lang="plaintext">`</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">&lt;a title="a lot</span>
-<span id="LC6" class="line" lang="plaintext">---</span>
-<span id="LC7" class="line" lang="plaintext">of dashes"/&gt;</span>
-<span id="LC8" class="line" lang="plaintext">.</span>
-<span id="LC9" class="line" lang="plaintext">&lt;h2&gt;`Foo&lt;/h2&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;`&lt;/p&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;h2&gt;&amp;lt;a title=&amp;quot;a lot&lt;/h2&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;p&gt;of dashes&amp;quot;/&amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="902:1-903:36" dir="auto">The setext heading underline cannot be a [lazy continuation
-line] in a list item or block quote:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="905:1-913:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; Foo</span>
-<span id="LC2" class="line" lang="plaintext">---</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;Foo&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="916:1-926:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
-<span id="LC2" class="line" lang="plaintext">bar</span>
-<span id="LC3" class="line" lang="plaintext">===</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;foo</span>
-<span id="LC7" class="line" lang="plaintext">bar</span>
-<span id="LC8" class="line" lang="plaintext">===&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="929:1-937:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- Foo</span>
-<span id="LC2" class="line" lang="plaintext">---</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;li&gt;Foo&lt;/li&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="940:1-942:25" dir="auto">A blank line is needed between a paragraph and a following
-setext heading, since otherwise the paragraph becomes part
-of the heading's content:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="944:1-951:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext">Bar</span>
-<span id="LC3" class="line" lang="plaintext">---</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;h2&gt;Foo</span>
-<span id="LC6" class="line" lang="plaintext">Bar&lt;/h2&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="954:1-955:16" dir="auto">But in general a blank line is not required before or after
-setext headings:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="957:1-969:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">---</span>
-<span id="LC2" class="line" lang="plaintext">Foo</span>
-<span id="LC3" class="line" lang="plaintext">---</span>
-<span id="LC4" class="line" lang="plaintext">Bar</span>
-<span id="LC5" class="line" lang="plaintext">---</span>
-<span id="LC6" class="line" lang="plaintext">Baz</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;hr /&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;h2&gt;Foo&lt;/h2&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;h2&gt;Bar&lt;/h2&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;p&gt;Baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="972:1-972:32" dir="auto">Setext headings cannot be empty:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="974:1-979:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"></span>
-<span id="LC2" class="line" lang="plaintext">====</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;====&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="982:1-984:55" dir="auto">Setext heading text lines must not be interpretable as block
-constructs other than paragraphs. So, the line of dashes
-in these examples gets interpreted as a thematic break:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="986:1-992:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">---</span>
-<span id="LC2" class="line" lang="plaintext">---</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;hr /&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="995:1-1003:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext">-----</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1006:1-1013:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span>
-<span id="LC2" class="line" lang="plaintext">---</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
-<span id="LC5" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1016:1-1024:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
-<span id="LC2" class="line" lang="plaintext">-----</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1027:1-1028:22" dir="auto">If you want a heading with <code>&gt; foo</code> as its literal text, you can
-use backslash escapes:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1030:1-1035:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\&gt; foo</span>
-<span id="LC2" class="line" lang="plaintext">------</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;h2&gt;&amp;gt; foo&lt;/h2&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1038:1-1040:48" dir="auto"><strong>Compatibility note:</strong> Most existing Markdown implementations
-do not allow the text of setext headings to span multiple lines.
-But there is no consensus about how to interpret</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1042:1-1047:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown">Foo</span>
-<span id="LC2" class="line" lang="markdown"><span class="gh">bar</span></span>
-<span id="LC3" class="line" lang="markdown"><span class="gh">---</span></span>
-<span id="LC4" class="line" lang="markdown">baz</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1049:1-1049:44" dir="auto">One can find four different interpretations:</p>
-<ol data-sourcepos="1051:1-1055:0" dir="auto">
-<li data-sourcepos="1051:1-1051:50">paragraph "Foo", heading "bar", paragraph "baz"</li>
-<li data-sourcepos="1052:1-1052:55">paragraph "Foo bar", thematic break, paragraph "baz"</li>
-<li data-sourcepos="1053:1-1053:30">paragraph "Foo bar --- baz"</li>
-<li data-sourcepos="1054:1-1055:0">heading "Foo bar", paragraph "baz"</li>
-</ol>
-<p data-sourcepos="1056:1-1059:43" dir="auto">We find interpretation 4 most natural, and interpretation 4
-increases the expressive power of CommonMark, by allowing
-multiline headings. Authors who want interpretation 1 can
-put a blank line after the first paragraph:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1061:1-1071:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">bar</span>
-<span id="LC4" class="line" lang="plaintext">---</span>
-<span id="LC5" class="line" lang="plaintext">baz</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;Foo&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;h2&gt;bar&lt;/h2&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1074:1-1075:19" dir="auto">Authors who want interpretation 2 can put blank lines around
-the thematic break,</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1077:1-1089:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext">bar</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">---</span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext">baz</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;Foo</span>
-<span id="LC9" class="line" lang="plaintext">bar&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;hr /&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1092:1-1093:19" dir="auto">or use a thematic break that cannot count as a [setext heading
-underline], such as</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1095:1-1105:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext">bar</span>
-<span id="LC3" class="line" lang="plaintext">* * *</span>
-<span id="LC4" class="line" lang="plaintext">baz</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;Foo</span>
-<span id="LC7" class="line" lang="plaintext">bar&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;hr /&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1108:1-1108:60" dir="auto">Authors who want interpretation 3 can use backslash escapes:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1110:1-1120:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext">bar</span>
-<span id="LC3" class="line" lang="plaintext">\---</span>
-<span id="LC4" class="line" lang="plaintext">baz</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;Foo</span>
-<span id="LC7" class="line" lang="plaintext">bar</span>
-<span id="LC8" class="line" lang="plaintext">---</span>
-<span id="LC9" class="line" lang="plaintext">baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="1123:1-1123:23" dir="auto">
-<a id="user-content-indented-code-blocks" class="anchor" href="#indented-code-blocks" aria-hidden="true"></a>Indented code blocks</h2>
-<p data-sourcepos="1125:1-1131:44" dir="auto">An <a href="@">indented code block</a> is composed of one or more
-[indented chunks] separated by blank lines.
-An <a href="@">indented chunk</a> is a sequence of non-blank lines,
-each indented four or more spaces. The contents of the code block are
-the literal contents of the lines, including trailing
-[line endings], minus four spaces of indentation.
-An indented code block has no [info string].</p>
-<p data-sourcepos="1133:1-1136:11" dir="auto">An indented code block cannot interrupt a paragraph, so there must be
-a blank line between a paragraph and a following indented code block.
-(A blank line is not needed, however, between a code block and a following
-paragraph.)</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1138:1-1145:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> a simple</span>
-<span id="LC2" class="line" lang="plaintext"> indented code block</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;a simple</span>
-<span id="LC5" class="line" lang="plaintext"> indented code block</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1148:1-1150:65" dir="auto">If there is any ambiguity between an interpretation of indentation
-as a code block and as indicating that material belongs to a [list
-item][list items], the list item interpretation takes precedence:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1152:1-1163:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> - foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1166:1-1179:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> - bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1183:1-1184:12" dir="auto">The contents of a code block are literal text, and do not get parsed
-as Markdown:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1186:1-1197:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &lt;a/&gt;</span>
-<span id="LC2" class="line" lang="plaintext"> *hi*</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext"> - one</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&amp;lt;a/&amp;gt;</span>
-<span id="LC7" class="line" lang="plaintext">*hi*</span>
-<span id="LC8" class="line" lang="plaintext"></span>
-<span id="LC9" class="line" lang="plaintext">- one</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1200:1-1200:51" dir="auto">Here we have three chunks separated by blank lines:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1202:1-1219:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> chunk1</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> chunk2</span>
-<span id="LC4" class="line" lang="plaintext"> </span>
-<span id="LC5" class="line" lang="plaintext"> </span>
-<span id="LC6" class="line" lang="plaintext"> </span>
-<span id="LC7" class="line" lang="plaintext"> chunk3</span>
-<span id="LC8" class="line" lang="plaintext">.</span>
-<span id="LC9" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;chunk1</span>
-<span id="LC10" class="line" lang="plaintext"></span>
-<span id="LC11" class="line" lang="plaintext">chunk2</span>
-<span id="LC12" class="line" lang="plaintext"></span>
-<span id="LC13" class="line" lang="plaintext"></span>
-<span id="LC14" class="line" lang="plaintext"></span>
-<span id="LC15" class="line" lang="plaintext">chunk3</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1222:1-1223:24" dir="auto">Any initial spaces beyond four will be included in the content, even
-in interior blank lines:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1225:1-1234:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> chunk1</span>
-<span id="LC2" class="line" lang="plaintext"> </span>
-<span id="LC3" class="line" lang="plaintext"> chunk2</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;chunk1</span>
-<span id="LC6" class="line" lang="plaintext"> </span>
-<span id="LC7" class="line" lang="plaintext"> chunk2</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1237:1-1238:37" dir="auto">An indented code block cannot interrupt a paragraph. (This
-allows hanging indents and the like.)</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1240:1-1247:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext"> bar</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;Foo</span>
-<span id="LC6" class="line" lang="plaintext">bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1250:1-1252:20" dir="auto">However, any non-blank line with fewer than four leading spaces ends
-the code block immediately. So a paragraph may occur immediately
-after indented code:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1254:1-1261:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span>
-<span id="LC2" class="line" lang="plaintext">bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
-<span id="LC5" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1264:1-1265:7" dir="auto">And indented code can occur immediately before and after other kinds of
-blocks:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1267:1-1282:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># Heading</span>
-<span id="LC2" class="line" lang="plaintext"> foo</span>
-<span id="LC3" class="line" lang="plaintext">Heading</span>
-<span id="LC4" class="line" lang="plaintext">------</span>
-<span id="LC5" class="line" lang="plaintext"> foo</span>
-<span id="LC6" class="line" lang="plaintext">----</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;h1&gt;Heading&lt;/h1&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;h2&gt;Heading&lt;/h2&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1285:1-1285:53" dir="auto">The first line can be indented more than four spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1287:1-1294:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span>
-<span id="LC2" class="line" lang="plaintext"> bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt; foo</span>
-<span id="LC5" class="line" lang="plaintext">bar</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1297:1-1298:23" dir="auto">Blank lines preceding or following an indented code block
-are not included in it:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1300:1-1309:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"></span>
-<span id="LC2" class="line" lang="plaintext"> </span>
-<span id="LC3" class="line" lang="plaintext"> foo</span>
-<span id="LC4" class="line" lang="plaintext"> </span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1312:1-1312:57" dir="auto">Trailing spaces are included in the code block's content:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1314:1-1319:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo </span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo </span>
-<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="1323:1-1323:21" dir="auto">
-<a id="user-content-fenced-code-blocks" class="anchor" href="#fenced-code-blocks" aria-hidden="true"></a>Fenced code blocks</h2>
-<p data-sourcepos="1325:1-1329:61" dir="auto">A <a href="@">code fence</a> is a sequence
-of at least three consecutive backtick characters (<code>`</code>) or
-tildes (<code>~</code>). (Tildes and backticks cannot be mixed.)
-A <a href="@">fenced code block</a>
-begins with a code fence, indented no more than three spaces.</p>
-<p data-sourcepos="1331:1-1337:34" dir="auto">The line with the opening code fence may optionally contain some text
-following the code fence; this is trimmed of leading and trailing
-whitespace and called the <a href="@">info string</a>. If the [info string] comes
-after a backtick fence, it may not contain any backtick
-characters. (The reason for this restriction is that otherwise
-some inline code would be incorrectly interpreted as the
-beginning of a fenced code block.)</p>
-<p data-sourcepos="1339:1-1346:43" dir="auto">The content of the code block consists of all subsequent lines, until
-a closing [code fence] of the same type as the code block
-began with (backticks or tildes), and with at least as many backticks
-or tildes as the opening code fence. If the leading code fence is
-indented N spaces, then up to N spaces of indentation are removed from
-each line of the content (if present). (If a content line is not
-indented, it is preserved unchanged. If it is indented less than N
-spaces, all of the indentation is removed.)</p>
-<p data-sourcepos="1348:1-1356:25" dir="auto">The closing code fence may be indented up to three spaces, and may be
-followed only by spaces, which are ignored. If the end of the
-containing block (or document) is reached and no closing code fence
-has been found, the code block contains all of the lines after the
-opening code fence until the end of the containing block (or
-document). (An alternative spec would require backtracking in the
-event that a closing code fence is not found. But this makes parsing
-much less efficient, and there seems to be no real down side to the
-behavior described here.)</p>
-<p data-sourcepos="1358:1-1359:36" dir="auto">A fenced code block may interrupt a paragraph, and does not require
-a blank line either before or after.</p>
-<p data-sourcepos="1361:1-1365:42" dir="auto">The content of a code fence is treated as literal text, not parsed
-as inlines. The first word of the [info string] is typically used to
-specify the language of the code sample, and rendered in the <code>class</code>
-attribute of the <code>code</code> tag. However, this spec does not mandate any
-particular treatment of the [info string].</p>
-<p data-sourcepos="1367:1-1367:40" dir="auto">Here is a simple example with backticks:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1369:1-1378:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
-<span id="LC2" class="line" lang="plaintext">&lt;</span>
-<span id="LC3" class="line" lang="plaintext"> &gt;</span>
-<span id="LC4" class="line" lang="plaintext">```</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&amp;lt;</span>
-<span id="LC7" class="line" lang="plaintext"> &amp;gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1381:1-1381:12" dir="auto">With tildes:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1383:1-1392:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~~</span>
-<span id="LC2" class="line" lang="plaintext">&lt;</span>
-<span id="LC3" class="line" lang="plaintext"> &gt;</span>
-<span id="LC4" class="line" lang="plaintext">~~~</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&amp;lt;</span>
-<span id="LC7" class="line" lang="plaintext"> &amp;gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1394:1-1394:41" dir="auto">Fewer than three backticks is not enough:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1396:1-1402:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``</span>
-<span id="LC2" class="line" lang="plaintext">foo</span>
-<span id="LC3" class="line" lang="plaintext">``</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1404:1-1405:6" dir="auto">The closing code fence must use the same character as the opening
-fence:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1407:1-1416:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
-<span id="LC2" class="line" lang="plaintext">aaa</span>
-<span id="LC3" class="line" lang="plaintext">~~~</span>
-<span id="LC4" class="line" lang="plaintext">```</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
-<span id="LC7" class="line" lang="plaintext">~~~</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1419:1-1428:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~~</span>
-<span id="LC2" class="line" lang="plaintext">aaa</span>
-<span id="LC3" class="line" lang="plaintext">```</span>
-<span id="LC4" class="line" lang="plaintext">~~~</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
-<span id="LC7" class="line" lang="plaintext">```</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1431:1-1431:69" dir="auto">The closing code fence must be at least as long as the opening fence:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1433:1-1442:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">````</span>
-<span id="LC2" class="line" lang="plaintext">aaa</span>
-<span id="LC3" class="line" lang="plaintext">```</span>
-<span id="LC4" class="line" lang="plaintext">``````</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
-<span id="LC7" class="line" lang="plaintext">```</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1445:1-1454:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~~~</span>
-<span id="LC2" class="line" lang="plaintext">aaa</span>
-<span id="LC3" class="line" lang="plaintext">~~~</span>
-<span id="LC4" class="line" lang="plaintext">~~~~</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
-<span id="LC7" class="line" lang="plaintext">~~~</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1457:1-1458:74" dir="auto">Unclosed code blocks are closed by the end of the document
-(or the enclosing [block quote][block quotes] or [list item][list items]):</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1460:1-1464:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1467:1-1477:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`````</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">```</span>
-<span id="LC4" class="line" lang="plaintext">aaa</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;</span>
-<span id="LC7" class="line" lang="plaintext">```</span>
-<span id="LC8" class="line" lang="plaintext">aaa</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1480:1-1491:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; ```</span>
-<span id="LC2" class="line" lang="plaintext">&gt; aaa</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">bbb</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;bbb&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1494:1-1494:53" dir="auto">A code block can have all empty lines as its content:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1496:1-1505:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> </span>
-<span id="LC4" class="line" lang="plaintext">```</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;</span>
-<span id="LC7" class="line" lang="plaintext"> </span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1508:1-1508:26" dir="auto">A code block can be empty:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1510:1-1515:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
-<span id="LC2" class="line" lang="plaintext">```</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1518:1-1520:11" dir="auto">Fences can be indented. If the opening fence is indented,
-content lines will have equivalent opening indentation removed,
-if present:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1522:1-1531:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ```</span>
-<span id="LC2" class="line" lang="plaintext"> aaa</span>
-<span id="LC3" class="line" lang="plaintext">aaa</span>
-<span id="LC4" class="line" lang="plaintext">```</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
-<span id="LC7" class="line" lang="plaintext">aaa</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1534:1-1545:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ```</span>
-<span id="LC2" class="line" lang="plaintext">aaa</span>
-<span id="LC3" class="line" lang="plaintext"> aaa</span>
-<span id="LC4" class="line" lang="plaintext">aaa</span>
-<span id="LC5" class="line" lang="plaintext"> ```</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
-<span id="LC8" class="line" lang="plaintext">aaa</span>
-<span id="LC9" class="line" lang="plaintext">aaa</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1548:1-1559:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ```</span>
-<span id="LC2" class="line" lang="plaintext"> aaa</span>
-<span id="LC3" class="line" lang="plaintext"> aaa</span>
-<span id="LC4" class="line" lang="plaintext"> aaa</span>
-<span id="LC5" class="line" lang="plaintext"> ```</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
-<span id="LC8" class="line" lang="plaintext"> aaa</span>
-<span id="LC9" class="line" lang="plaintext">aaa</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1562:1-1562:56" dir="auto">Four spaces indentation produces an indented code block:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1564:1-1573:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ```</span>
-<span id="LC2" class="line" lang="plaintext"> aaa</span>
-<span id="LC3" class="line" lang="plaintext"> ```</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;```</span>
-<span id="LC6" class="line" lang="plaintext">aaa</span>
-<span id="LC7" class="line" lang="plaintext">```</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1576:1-1577:41" dir="auto">Closing fences may be indented by 0-3 spaces, and their indentation
-need not match that of the opening fence:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1579:1-1586:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
-<span id="LC2" class="line" lang="plaintext">aaa</span>
-<span id="LC3" class="line" lang="plaintext"> ```</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1589:1-1596:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ```</span>
-<span id="LC2" class="line" lang="plaintext">aaa</span>
-<span id="LC3" class="line" lang="plaintext"> ```</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1599:1-1599:61" dir="auto">This is not a closing fence, because it is indented 4 spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1601:1-1609:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
-<span id="LC2" class="line" lang="plaintext">aaa</span>
-<span id="LC3" class="line" lang="plaintext"> ```</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
-<span id="LC6" class="line" lang="plaintext"> ```</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1613:1-1613:65" dir="auto">Code fences (opening and closing) cannot contain internal spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1615:1-1621:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``` ```</span>
-<span id="LC2" class="line" lang="plaintext">aaa</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt; &lt;/code&gt;</span>
-<span id="LC5" class="line" lang="plaintext">aaa&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1624:1-1632:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~~~~~</span>
-<span id="LC2" class="line" lang="plaintext">aaa</span>
-<span id="LC3" class="line" lang="plaintext">~~~ ~~</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
-<span id="LC6" class="line" lang="plaintext">~~~ ~~</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1635:1-1636:53" dir="auto">Fenced code blocks can interrupt paragraphs, and can be followed
-directly by paragraphs, without a blank line between:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1638:1-1649:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span>
-<span id="LC2" class="line" lang="plaintext">```</span>
-<span id="LC3" class="line" lang="plaintext">bar</span>
-<span id="LC4" class="line" lang="plaintext">```</span>
-<span id="LC5" class="line" lang="plaintext">baz</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1652:1-1653:34" dir="auto">Other blocks can also occur before and after fenced code blocks
-without an intervening blank line:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1655:1-1667:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span>
-<span id="LC2" class="line" lang="plaintext">---</span>
-<span id="LC3" class="line" lang="plaintext">~~~</span>
-<span id="LC4" class="line" lang="plaintext">bar</span>
-<span id="LC5" class="line" lang="plaintext">~~~</span>
-<span id="LC6" class="line" lang="plaintext"># baz</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;h2&gt;foo&lt;/h2&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;h1&gt;baz&lt;/h1&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1670:1-1675:45" dir="auto">An [info string] can be provided after the opening code fence.
-Although this spec doesn't mandate any particular treatment of
-the info string, the first word is typically used to specify
-the language of the code block. In HTML output, the language is
-normally indicated by adding a class to the <code>code</code> element consisting
-of <code>language-</code> followed by the language name.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1677:1-1688:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```ruby</span>
-<span id="LC2" class="line" lang="plaintext">def foo(x)</span>
-<span id="LC3" class="line" lang="plaintext"> return 3</span>
-<span id="LC4" class="line" lang="plaintext">end</span>
-<span id="LC5" class="line" lang="plaintext">```</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;pre&gt;&lt;code class="language-ruby"&gt;def foo(x)</span>
-<span id="LC8" class="line" lang="plaintext"> return 3</span>
-<span id="LC9" class="line" lang="plaintext">end</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1691:1-1702:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~~~ ruby startline=3 $%@#$</span>
-<span id="LC2" class="line" lang="plaintext">def foo(x)</span>
-<span id="LC3" class="line" lang="plaintext"> return 3</span>
-<span id="LC4" class="line" lang="plaintext">end</span>
-<span id="LC5" class="line" lang="plaintext">~~~~~~~</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;pre&gt;&lt;code class="language-ruby"&gt;def foo(x)</span>
-<span id="LC8" class="line" lang="plaintext"> return 3</span>
-<span id="LC9" class="line" lang="plaintext">end</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1705:1-1710:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">````;</span>
-<span id="LC2" class="line" lang="plaintext">````</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code class="language-;"&gt;&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1713:1-1713:65" dir="auto">[Info strings] for backtick code blocks cannot contain backticks:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1715:1-1721:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``` aa ```</span>
-<span id="LC2" class="line" lang="plaintext">foo</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;aa&lt;/code&gt;</span>
-<span id="LC5" class="line" lang="plaintext">foo&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1724:1-1724:70" dir="auto">[Info strings] for tilde code blocks can contain backticks and tildes:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1726:1-1733:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~~ aa ``` ~~~</span>
-<span id="LC2" class="line" lang="plaintext">foo</span>
-<span id="LC3" class="line" lang="plaintext">~~~</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code class="language-aa"&gt;foo</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1736:1-1736:47" dir="auto">Closing code fences cannot have [info strings]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1738:1-1745:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
-<span id="LC2" class="line" lang="plaintext">``` aaa</span>
-<span id="LC3" class="line" lang="plaintext">```</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;``` aaa</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="1749:1-1749:14" dir="auto">
-<a id="user-content-html-blocks" class="anchor" href="#html-blocks" aria-hidden="true"></a>HTML blocks</h2>
-<p data-sourcepos="1751:1-1752:53" dir="auto">An <a href="@">HTML block</a> is a group of lines that is treated
-as raw HTML (and will not be escaped in HTML output).</p>
-<p data-sourcepos="1754:1-1762:50" dir="auto">There are seven kinds of [HTML block], which can be defined by their
-start and end conditions. The block begins with a line that meets a
-<a href="@">start condition</a> (after up to three spaces optional indentation).
-It ends with the first subsequent line that meets a matching <a href="@">end
-condition</a>, or the last line of the document, or the last line of
-the <a href="#container-blocks">container block</a> containing the current HTML
-block, if no line is encountered that meets the [end condition]. If
-the first line meets both the [start condition] and the [end
-condition], the block will contain just that line.</p>
-<ol data-sourcepos="1764:1-1805:0" dir="auto">
-<li data-sourcepos="1764:1-1770:0">
-<p data-sourcepos="1764:5-1769:30"><strong>Start condition:</strong> line begins with the string <code>&lt;script</code>,
-<code>&lt;pre</code>, or <code>&lt;style</code> (case-insensitive), followed by whitespace,
-the string <code>&gt;</code>, or the end of the line.<br>
-<strong>End condition:</strong> line contains an end tag
-<code>&lt;/script&gt;</code>, <code>&lt;/pre&gt;</code>, or <code>&lt;/style&gt;</code> (case-insensitive; it
-need not match the start tag).</p>
-</li>
-<li data-sourcepos="1771:1-1773:0">
-<p data-sourcepos="1771:5-1772:51"><strong>Start condition:</strong> line begins with the string <code>&lt;!--</code>.<br>
-<strong>End condition:</strong> line contains the string <code>--&gt;</code>.</p>
-</li>
-<li data-sourcepos="1774:1-1776:0">
-<p data-sourcepos="1774:5-1775:49"><strong>Start condition:</strong> line begins with the string <code>&lt;?</code>.<br>
-<strong>End condition:</strong> line contains the string <code>?&gt;</code>.</p>
-</li>
-<li data-sourcepos="1777:1-1780:0">
-<p data-sourcepos="1777:5-1779:51"><strong>Start condition:</strong> line begins with the string <code>&lt;!</code>
-followed by an uppercase ASCII letter.<br>
-<strong>End condition:</strong> line contains the character <code>&gt;</code>.</p>
-</li>
-<li data-sourcepos="1781:1-1784:0">
-<p data-sourcepos="1781:5-1783:50"><strong>Start condition:</strong> line begins with the string
-<code>&lt;![CDATA[</code>.<br>
-<strong>End condition:</strong> line contains the string <code>]]&gt;</code>.</p>
-</li>
-<li data-sourcepos="1785:1-1799:0">
-<p data-sourcepos="1785:5-1798:54"><strong>Start condition:</strong> line begins the string <code>&lt;</code> or <code>&lt;/</code>
-followed by one of the strings (case-insensitive) <code>address</code>,
-<code>article</code>, <code>aside</code>, <code>base</code>, <code>basefont</code>, <code>blockquote</code>, <code>body</code>,
-<code>caption</code>, <code>center</code>, <code>col</code>, <code>colgroup</code>, <code>dd</code>, <code>details</code>, <code>dialog</code>,
-<code>dir</code>, <code>div</code>, <code>dl</code>, <code>dt</code>, <code>fieldset</code>, <code>figcaption</code>, <code>figure</code>,
-<code>footer</code>, <code>form</code>, <code>frame</code>, <code>frameset</code>,
-<code>h1</code>, <code>h2</code>, <code>h3</code>, <code>h4</code>, <code>h5</code>, <code>h6</code>, <code>head</code>, <code>header</code>, <code>hr</code>,
-<code>html</code>, <code>iframe</code>, <code>legend</code>, <code>li</code>, <code>link</code>, <code>main</code>, <code>menu</code>, <code>menuitem</code>,
-<code>nav</code>, <code>noframes</code>, <code>ol</code>, <code>optgroup</code>, <code>option</code>, <code>p</code>, <code>param</code>,
-<code>section</code>, <code>summary</code>, <code>table</code>, <code>tbody</code>, <code>td</code>,
-<code>tfoot</code>, <code>th</code>, <code>thead</code>, <code>title</code>, <code>tr</code>, <code>track</code>, <code>ul</code>, followed
-by [whitespace], the end of the line, the string <code>&gt;</code>, or
-the string <code>/&gt;</code>.<br>
-<strong>End condition:</strong> line is followed by a [blank line].</p>
-</li>
-<li data-sourcepos="1800:1-1805:0">
-<p data-sourcepos="1800:5-1804:54"><strong>Start condition:</strong> line begins with a complete [open tag]
-(with any [tag name] other than <code>script</code>,
-<code>style</code>, or <code>pre</code>) or a complete [closing tag],
-followed only by [whitespace] or the end of the line.<br>
-<strong>End condition:</strong> line is followed by a [blank line].</p>
-</li>
-</ol>
-<p data-sourcepos="1806:1-1811:19" dir="auto">HTML blocks continue until they are closed by their appropriate
-[end condition], or the last line of the document or other <a href="#container-blocks">container
-block</a>. This means any HTML <strong>within an HTML
-block</strong> that might otherwise be recognised as a start condition will
-be ignored by the parser and passed through as-is, without changing
-the parser's state.</p>
-<p data-sourcepos="1813:1-1815:51" dir="auto">For instance, <code>&lt;pre&gt;</code> within a HTML block started by <code>&lt;table&gt;</code> will not affect
-the parser state; as the HTML block was started in by start condition 6, it
-will end at any blank line. This can be surprising:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1817:1-1832:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;&lt;tr&gt;&lt;td&gt;</span>
-<span id="LC2" class="line" lang="plaintext">&lt;pre&gt;</span>
-<span id="LC3" class="line" lang="plaintext">**Hello**,</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">_world_.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/pre&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</span>
-<span id="LC8" class="line" lang="plaintext">.</span>
-<span id="LC9" class="line" lang="plaintext">&lt;table&gt;&lt;tr&gt;&lt;td&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;pre&gt;</span>
-<span id="LC11" class="line" lang="plaintext">**Hello**,</span>
-<span id="LC12" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;world&lt;/em&gt;.</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/pre&gt;&lt;/p&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1834:1-1836:55" dir="auto">In this case, the HTML block is terminated by the newline — the <code>**Hello**</code>
-text remains verbatim — and regular parsing resumes, with a paragraph,
-emphasised <code>world</code> and inline and block HTML following.</p>
-<p data-sourcepos="1838:1-1841:65" dir="auto">All types of [HTML blocks] except type 7 may interrupt
-a paragraph. Blocks of type 7 may not interrupt a paragraph.
-(This restriction is intended to prevent unwanted interpretation
-of long tags inside a wrapped paragraph as starting HTML blocks.)</p>
-<p data-sourcepos="1843:1-1844:10" dir="auto">Some simple examples follow. Here are some basic HTML blocks
-of type 6:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1846:1-1865:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
-<span id="LC2" class="line" lang="plaintext"> &lt;tr&gt;</span>
-<span id="LC3" class="line" lang="plaintext"> &lt;td&gt;</span>
-<span id="LC4" class="line" lang="plaintext"> hi</span>
-<span id="LC5" class="line" lang="plaintext"> &lt;/td&gt;</span>
-<span id="LC6" class="line" lang="plaintext"> &lt;/tr&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/table&gt;</span>
-<span id="LC8" class="line" lang="plaintext"></span>
-<span id="LC9" class="line" lang="plaintext">okay.</span>
-<span id="LC10" class="line" lang="plaintext">.</span>
-<span id="LC11" class="line" lang="plaintext">&lt;table&gt;</span>
-<span id="LC12" class="line" lang="plaintext"> &lt;tr&gt;</span>
-<span id="LC13" class="line" lang="plaintext"> &lt;td&gt;</span>
-<span id="LC14" class="line" lang="plaintext"> hi</span>
-<span id="LC15" class="line" lang="plaintext"> &lt;/td&gt;</span>
-<span id="LC16" class="line" lang="plaintext"> &lt;/tr&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/table&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;p&gt;okay.&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1868:1-1876:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &lt;div&gt;</span>
-<span id="LC2" class="line" lang="plaintext"> *hello*</span>
-<span id="LC3" class="line" lang="plaintext"> &lt;foo&gt;&lt;a&gt;</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext"> &lt;div&gt;</span>
-<span id="LC6" class="line" lang="plaintext"> *hello*</span>
-<span id="LC7" class="line" lang="plaintext"> &lt;foo&gt;&lt;a&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1879:1-1879:42" dir="auto">A block can also start with a closing tag:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1881:1-1887:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;/div&gt;</span>
-<span id="LC2" class="line" lang="plaintext">*foo*</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;/div&gt;</span>
-<span id="LC5" class="line" lang="plaintext">*foo*</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1890:1-1890:68" dir="auto">Here we have two HTML blocks with a Markdown paragraph between them:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1892:1-1902:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;DIV CLASS="foo"&gt;</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">*Markdown*</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">&lt;/DIV&gt;</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;DIV CLASS="foo"&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;Markdown&lt;/em&gt;&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/DIV&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1905:1-1906:47" dir="auto">The tag on the first line can be partial, as long
-as it is split where there would be whitespace:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1908:1-1916:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div id="foo"</span>
-<span id="LC2" class="line" lang="plaintext"> class="bar"&gt;</span>
-<span id="LC3" class="line" lang="plaintext">&lt;/div&gt;</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;div id="foo"</span>
-<span id="LC6" class="line" lang="plaintext"> class="bar"&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/div&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1919:1-1927:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div id="foo" class="bar</span>
-<span id="LC2" class="line" lang="plaintext"> baz"&gt;</span>
-<span id="LC3" class="line" lang="plaintext">&lt;/div&gt;</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;div id="foo" class="bar</span>
-<span id="LC6" class="line" lang="plaintext"> baz"&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/div&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1930:1-1930:31" dir="auto">An open tag need not be closed:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1931:1-1940:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;</span>
-<span id="LC2" class="line" lang="plaintext">*foo*</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">*bar*</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;div&gt;</span>
-<span id="LC7" class="line" lang="plaintext">*foo*</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1944:1-1945:17" dir="auto">A partial tag need not even be completed (garbage
-in, garbage out):</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1947:1-1953:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div id="foo"</span>
-<span id="LC2" class="line" lang="plaintext">*hi*</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;div id="foo"</span>
-<span id="LC5" class="line" lang="plaintext">*hi*</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1956:1-1962:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div class</span>
-<span id="LC2" class="line" lang="plaintext">foo</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;div class</span>
-<span id="LC5" class="line" lang="plaintext">foo</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1965:1-1966:35" dir="auto">The initial tag doesn't even need to be a valid
-tag, as long as it starts like one:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1968:1-1974:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div *???-&amp;&amp;&amp;-&lt;---</span>
-<span id="LC2" class="line" lang="plaintext">*foo*</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;div *???-&amp;&amp;&amp;-&lt;---</span>
-<span id="LC5" class="line" lang="plaintext">*foo*</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1977:1-1978:7" dir="auto">In type 6 blocks, the initial tag need not be on a line by
-itself:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1980:1-1984:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;&lt;a href="bar"&gt;*foo*&lt;/a&gt;&lt;/div&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;div&gt;&lt;a href="bar"&gt;*foo*&lt;/a&gt;&lt;/div&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="1987:1-1995:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;&lt;tr&gt;&lt;td&gt;</span>
-<span id="LC2" class="line" lang="plaintext">foo</span>
-<span id="LC3" class="line" lang="plaintext">&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;table&gt;&lt;tr&gt;&lt;td&gt;</span>
-<span id="LC6" class="line" lang="plaintext">foo</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="1998:1-2002:43" dir="auto">Everything until the next blank line or end of document
-gets included in the HTML block. So, in the following
-example, what looks like a Markdown code block
-is actually part of the HTML block, which continues until a blank
-line or the end of the document is reached:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2004:1-2014:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;&lt;/div&gt;</span>
-<span id="LC2" class="line" lang="plaintext">``` c</span>
-<span id="LC3" class="line" lang="plaintext">int x = 33;</span>
-<span id="LC4" class="line" lang="plaintext">```</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;div&gt;&lt;/div&gt;</span>
-<span id="LC7" class="line" lang="plaintext">``` c</span>
-<span id="LC8" class="line" lang="plaintext">int x = 33;</span>
-<span id="LC9" class="line" lang="plaintext">```</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2017:1-2019:51" dir="auto">To start an [HTML block] with a tag that is <em>not</em> in the
-list of block-level tags in (6), you must put the tag by
-itself on the first line (and it must be complete):</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2021:1-2029:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="foo"&gt;</span>
-<span id="LC2" class="line" lang="plaintext">*bar*</span>
-<span id="LC3" class="line" lang="plaintext">&lt;/a&gt;</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;a href="foo"&gt;</span>
-<span id="LC6" class="line" lang="plaintext">*bar*</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/a&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2032:1-2032:49" dir="auto">In type 7 blocks, the [tag name] can be anything:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2034:1-2042:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;Warning&gt;</span>
-<span id="LC2" class="line" lang="plaintext">*bar*</span>
-<span id="LC3" class="line" lang="plaintext">&lt;/Warning&gt;</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;Warning&gt;</span>
-<span id="LC6" class="line" lang="plaintext">*bar*</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/Warning&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2045:1-2053:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;i class="foo"&gt;</span>
-<span id="LC2" class="line" lang="plaintext">*bar*</span>
-<span id="LC3" class="line" lang="plaintext">&lt;/i&gt;</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;i class="foo"&gt;</span>
-<span id="LC6" class="line" lang="plaintext">*bar*</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/i&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2056:1-2062:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;/ins&gt;</span>
-<span id="LC2" class="line" lang="plaintext">*bar*</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;/ins&gt;</span>
-<span id="LC5" class="line" lang="plaintext">*bar*</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2065:1-2069:59" dir="auto">These rules are designed to allow us to work with tags that
-can function as either block-level or inline-level tags.
-The <code>&lt;del&gt;</code> tag is a nice example. We can surround content with
-<code>&lt;del&gt;</code> tags in three different ways. In this case, we get a raw
-HTML block, because the <code>&lt;del&gt;</code> tag is on a line by itself:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2071:1-2079:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;del&gt;</span>
-<span id="LC2" class="line" lang="plaintext">*foo*</span>
-<span id="LC3" class="line" lang="plaintext">&lt;/del&gt;</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;del&gt;</span>
-<span id="LC6" class="line" lang="plaintext">*foo*</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/del&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2082:1-2084:54" dir="auto">In this case, we get a raw HTML block that just includes
-the <code>&lt;del&gt;</code> tag (because it ends with the following blank
-line). So the contents get interpreted as CommonMark:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2086:1-2096:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;del&gt;</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">*foo*</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">&lt;/del&gt;</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;del&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;/em&gt;&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/del&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2099:1-2102:29" dir="auto">Finally, in this case, the <code>&lt;del&gt;</code> tags are interpreted
-as [raw HTML] <em>inside</em> the CommonMark paragraph. (Because
-the tag is not on a line by itself, we get inline HTML
-rather than an [HTML block].)</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2104:1-2108:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;del&gt;*foo*&lt;/del&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;del&gt;&lt;em&gt;foo&lt;/em&gt;&lt;/del&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2111:1-2116:50" dir="auto">HTML tags designed to contain literal content
-(<code>script</code>, <code>style</code>, <code>pre</code>), comments, processing instructions,
-and declarations are treated somewhat differently.
-Instead of ending at the first blank line, these blocks
-end at the first line containing a corresponding end tag.
-As a result, these blocks can contain blank lines:</p>
-<p data-sourcepos="2118:1-2118:19" dir="auto">A pre tag (type 1):</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2120:1-2136:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre language="haskell"&gt;&lt;code&gt;</span>
-<span id="LC2" class="line" lang="plaintext">import Text.HTML.TagSoup</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">main :: IO ()</span>
-<span id="LC5" class="line" lang="plaintext">main = print $ parseTags tags</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC7" class="line" lang="plaintext">okay</span>
-<span id="LC8" class="line" lang="plaintext">.</span>
-<span id="LC9" class="line" lang="plaintext">&lt;pre language="haskell"&gt;&lt;code&gt;</span>
-<span id="LC10" class="line" lang="plaintext">import Text.HTML.TagSoup</span>
-<span id="LC11" class="line" lang="plaintext"></span>
-<span id="LC12" class="line" lang="plaintext">main :: IO ()</span>
-<span id="LC13" class="line" lang="plaintext">main = print $ parseTags tags</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;p&gt;okay&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2139:1-2139:22" dir="auto">A script tag (type 1):</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2141:1-2155:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;script type="text/javascript"&gt;</span>
-<span id="LC2" class="line" lang="plaintext">// JavaScript example</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">document.getElementById("demo").innerHTML = "Hello JavaScript!";</span>
-<span id="LC5" class="line" lang="plaintext">&lt;/script&gt;</span>
-<span id="LC6" class="line" lang="plaintext">okay</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;script type="text/javascript"&gt;</span>
-<span id="LC9" class="line" lang="plaintext">// JavaScript example</span>
-<span id="LC10" class="line" lang="plaintext"></span>
-<span id="LC11" class="line" lang="plaintext">document.getElementById("demo").innerHTML = "Hello JavaScript!";</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/script&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;p&gt;okay&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2158:1-2158:21" dir="auto">A style tag (type 1):</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2160:1-2176:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;style</span>
-<span id="LC2" class="line" lang="plaintext"> type="text/css"&gt;</span>
-<span id="LC3" class="line" lang="plaintext">h1 {color:red;}</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">p {color:blue;}</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/style&gt;</span>
-<span id="LC7" class="line" lang="plaintext">okay</span>
-<span id="LC8" class="line" lang="plaintext">.</span>
-<span id="LC9" class="line" lang="plaintext">&lt;style</span>
-<span id="LC10" class="line" lang="plaintext"> type="text/css"&gt;</span>
-<span id="LC11" class="line" lang="plaintext">h1 {color:red;}</span>
-<span id="LC12" class="line" lang="plaintext"></span>
-<span id="LC13" class="line" lang="plaintext">p {color:blue;}</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/style&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;p&gt;okay&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2179:1-2181:28" dir="auto">If there is no matching end tag, the block will end at the
-end of the document (or the enclosing [block quote][block quotes]
-or [list item][list items]):</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2183:1-2193:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;style</span>
-<span id="LC2" class="line" lang="plaintext"> type="text/css"&gt;</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">foo</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;style</span>
-<span id="LC7" class="line" lang="plaintext"> type="text/css"&gt;</span>
-<span id="LC8" class="line" lang="plaintext"></span>
-<span id="LC9" class="line" lang="plaintext">foo</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2196:1-2207:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; &lt;div&gt;</span>
-<span id="LC2" class="line" lang="plaintext">&gt; foo</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">bar</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;div&gt;</span>
-<span id="LC8" class="line" lang="plaintext">foo</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2210:1-2220:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- &lt;div&gt;</span>
-<span id="LC2" class="line" lang="plaintext">- foo</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;div&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2223:1-2223:56" dir="auto">The end tag can occur on the same line as the start tag:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2225:1-2231:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;style&gt;p{color:red;}&lt;/style&gt;</span>
-<span id="LC2" class="line" lang="plaintext">*foo*</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;style&gt;p{color:red;}&lt;/style&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2234:1-2240:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;!-- foo --&gt;*bar*</span>
-<span id="LC2" class="line" lang="plaintext">*baz*</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;!-- foo --&gt;*bar*</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;baz&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2243:1-2244:45" dir="auto">Note that anything on the last line after the
-end tag will be included in the [HTML block]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2246:1-2254:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;script&gt;</span>
-<span id="LC2" class="line" lang="plaintext">foo</span>
-<span id="LC3" class="line" lang="plaintext">&lt;/script&gt;1. *bar*</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;script&gt;</span>
-<span id="LC6" class="line" lang="plaintext">foo</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/script&gt;1. *bar*</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2257:1-2257:19" dir="auto">A comment (type 2):</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2259:1-2271:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;!-- Foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">bar</span>
-<span id="LC4" class="line" lang="plaintext"> baz --&gt;</span>
-<span id="LC5" class="line" lang="plaintext">okay</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;!-- Foo</span>
-<span id="LC8" class="line" lang="plaintext"></span>
-<span id="LC9" class="line" lang="plaintext">bar</span>
-<span id="LC10" class="line" lang="plaintext"> baz --&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;p&gt;okay&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2275:1-2275:34" dir="auto">A processing instruction (type 3):</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2277:1-2291:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;?php</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> echo '&gt;';</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">?&gt;</span>
-<span id="LC6" class="line" lang="plaintext">okay</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;?php</span>
-<span id="LC9" class="line" lang="plaintext"></span>
-<span id="LC10" class="line" lang="plaintext"> echo '&gt;';</span>
-<span id="LC11" class="line" lang="plaintext"></span>
-<span id="LC12" class="line" lang="plaintext">?&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;p&gt;okay&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2294:1-2294:23" dir="auto">A declaration (type 4):</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2296:1-2300:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;!DOCTYPE html&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;!DOCTYPE html&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2303:1-2303:15" dir="auto">CDATA (type 5):</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2305:1-2333:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;![CDATA[</span>
-<span id="LC2" class="line" lang="plaintext">function matchwo(a,b)</span>
-<span id="LC3" class="line" lang="plaintext">{</span>
-<span id="LC4" class="line" lang="plaintext"> if (a &lt; b &amp;&amp; a &lt; 0) then {</span>
-<span id="LC5" class="line" lang="plaintext"> return 1;</span>
-<span id="LC6" class="line" lang="plaintext"></span>
-<span id="LC7" class="line" lang="plaintext"> } else {</span>
-<span id="LC8" class="line" lang="plaintext"></span>
-<span id="LC9" class="line" lang="plaintext"> return 0;</span>
-<span id="LC10" class="line" lang="plaintext"> }</span>
-<span id="LC11" class="line" lang="plaintext">}</span>
-<span id="LC12" class="line" lang="plaintext">]]&gt;</span>
-<span id="LC13" class="line" lang="plaintext">okay</span>
-<span id="LC14" class="line" lang="plaintext">.</span>
-<span id="LC15" class="line" lang="plaintext">&lt;![CDATA[</span>
-<span id="LC16" class="line" lang="plaintext">function matchwo(a,b)</span>
-<span id="LC17" class="line" lang="plaintext">{</span>
-<span id="LC18" class="line" lang="plaintext"> if (a &lt; b &amp;&amp; a &lt; 0) then {</span>
-<span id="LC19" class="line" lang="plaintext"> return 1;</span>
-<span id="LC20" class="line" lang="plaintext"></span>
-<span id="LC21" class="line" lang="plaintext"> } else {</span>
-<span id="LC22" class="line" lang="plaintext"></span>
-<span id="LC23" class="line" lang="plaintext"> return 0;</span>
-<span id="LC24" class="line" lang="plaintext"> }</span>
-<span id="LC25" class="line" lang="plaintext">}</span>
-<span id="LC26" class="line" lang="plaintext">]]&gt;</span>
-<span id="LC27" class="line" lang="plaintext">&lt;p&gt;okay&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2336:1-2336:54" dir="auto">The opening tag can be indented 1-3 spaces, but not 4:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2338:1-2346:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &lt;!-- foo --&gt;</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> &lt;!-- foo --&gt;</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext"> &lt;!-- foo --&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&amp;lt;!-- foo --&amp;gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2349:1-2357:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &lt;div&gt;</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> &lt;div&gt;</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext"> &lt;div&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&amp;lt;div&amp;gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2360:1-2361:25" dir="auto">An HTML block of types 1--6 can interrupt a paragraph, and need not be
-preceded by a blank line.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2363:1-2373:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext">&lt;div&gt;</span>
-<span id="LC3" class="line" lang="plaintext">bar</span>
-<span id="LC4" class="line" lang="plaintext">&lt;/div&gt;</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;Foo&lt;/p&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;div&gt;</span>
-<span id="LC8" class="line" lang="plaintext">bar</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/div&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2376:1-2378:7" dir="auto">However, a following blank line is needed, except at the end of
-a document, and except for blocks of types 1--5, [above][HTML
-block]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2380:1-2390:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;</span>
-<span id="LC2" class="line" lang="plaintext">bar</span>
-<span id="LC3" class="line" lang="plaintext">&lt;/div&gt;</span>
-<span id="LC4" class="line" lang="plaintext">*foo*</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;div&gt;</span>
-<span id="LC7" class="line" lang="plaintext">bar</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/div&gt;</span>
-<span id="LC9" class="line" lang="plaintext">*foo*</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2393:1-2393:51" dir="auto">HTML blocks of type 7 cannot interrupt a paragraph:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2395:1-2403:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext">&lt;a href="bar"&gt;</span>
-<span id="LC3" class="line" lang="plaintext">baz</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;Foo</span>
-<span id="LC6" class="line" lang="plaintext">&lt;a href="bar"&gt;</span>
-<span id="LC7" class="line" lang="plaintext">baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2406:1-2407:26" dir="auto">This rule differs from John Gruber's original Markdown syntax
-specification, which says:</p>
-<blockquote data-sourcepos="2409:1-2412:51" dir="auto">
-<p data-sourcepos="2409:3-2412:51">The only restrictions are that block-level HTML elements —
-e.g. <code>&lt;div&gt;</code>, <code>&lt;table&gt;</code>, <code>&lt;pre&gt;</code>, <code>&lt;p&gt;</code>, etc. — must be separated from
-surrounding content by blank lines, and the start and end tags of the
-block should not be indented with tabs or spaces.</p>
-</blockquote>
-<p data-sourcepos="2414:1-2415:5" dir="auto">In some ways Gruber's rule is more restrictive than the one given
-here:</p>
-<ul data-sourcepos="2417:1-2421:0" dir="auto">
-<li data-sourcepos="2417:1-2417:61">It requires that an HTML block be preceded by a blank line.</li>
-<li data-sourcepos="2418:1-2418:49">It does not allow the start tag to be indented.</li>
-<li data-sourcepos="2419:1-2421:0">It requires a matching end tag, which it also does not allow to
-be indented.</li>
-</ul>
-<p data-sourcepos="2422:1-2423:34" dir="auto">Most Markdown implementations (including some of Gruber's own) do not
-respect all of these restrictions.</p>
-<p data-sourcepos="2425:1-2432:61" dir="auto">There is one respect, however, in which Gruber's rule is more liberal
-than the one given here, since it allows blank lines to occur inside
-an HTML block. There are two reasons for disallowing them here.
-First, it removes the need to parse balanced tags, which is
-expensive and can require backtracking from the end of the document
-if no matching end tag is found. Second, it provides a very simple
-and flexible way of including Markdown content inside HTML tags:
-simply separate the Markdown from the HTML using blank lines:</p>
-<p data-sourcepos="2434:1-2434:8" dir="auto">Compare:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2436:1-2446:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">*Emphasized* text.</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">&lt;/div&gt;</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;div&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;Emphasized&lt;/em&gt; text.&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/div&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2449:1-2457:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;</span>
-<span id="LC2" class="line" lang="plaintext">*Emphasized* text.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;/div&gt;</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;div&gt;</span>
-<span id="LC6" class="line" lang="plaintext">*Emphasized* text.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/div&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2460:1-2464:22" dir="auto">Some Markdown implementations have adopted a convention of
-interpreting content inside tags as text if the open tag has
-the attribute <code>markdown=1</code>. The rule given above seems a simpler and
-more elegant way of achieving the same expressive power, which is also
-much simpler to parse.</p>
-<p data-sourcepos="2466:1-2469:59" dir="auto">The main potential drawback is that one can no longer paste HTML
-blocks into Markdown documents with 100% reliability. However,
-<em>in most cases</em> this will work fine, because the blank lines in
-HTML are usually followed by HTML block tags. For example:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2471:1-2491:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">&lt;td&gt;</span>
-<span id="LC6" class="line" lang="plaintext">Hi</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/td&gt;</span>
-<span id="LC8" class="line" lang="plaintext"></span>
-<span id="LC9" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC10" class="line" lang="plaintext"></span>
-<span id="LC11" class="line" lang="plaintext">&lt;/table&gt;</span>
-<span id="LC12" class="line" lang="plaintext">.</span>
-<span id="LC13" class="line" lang="plaintext">&lt;table&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;td&gt;</span>
-<span id="LC16" class="line" lang="plaintext">Hi</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/td&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC19" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2494:1-2496:23" dir="auto">There are problems, however, if the inner tags are indented
-<em>and</em> separated by spaces, as then they will be interpreted as
-an indented code block:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2498:1-2519:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> &lt;tr&gt;</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext"> &lt;td&gt;</span>
-<span id="LC6" class="line" lang="plaintext"> Hi</span>
-<span id="LC7" class="line" lang="plaintext"> &lt;/td&gt;</span>
-<span id="LC8" class="line" lang="plaintext"></span>
-<span id="LC9" class="line" lang="plaintext"> &lt;/tr&gt;</span>
-<span id="LC10" class="line" lang="plaintext"></span>
-<span id="LC11" class="line" lang="plaintext">&lt;/table&gt;</span>
-<span id="LC12" class="line" lang="plaintext">.</span>
-<span id="LC13" class="line" lang="plaintext">&lt;table&gt;</span>
-<span id="LC14" class="line" lang="plaintext"> &lt;tr&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&amp;lt;td&amp;gt;</span>
-<span id="LC16" class="line" lang="plaintext"> Hi</span>
-<span id="LC17" class="line" lang="plaintext">&amp;lt;/td&amp;gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC19" class="line" lang="plaintext"> &lt;/tr&gt;</span>
-<span id="LC20" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2522:1-2525:26" dir="auto">Fortunately, blank lines are usually not necessary and can be
-deleted. The exception is inside <code>&lt;pre&gt;</code> tags, but as described
-[above][HTML blocks], raw HTML blocks starting with <code>&lt;pre&gt;</code>
-<em>can</em> contain blank lines.</p>
-<h2 data-sourcepos="2527:1-2527:29" dir="auto">
-<a id="user-content-link-reference-definitions" class="anchor" href="#link-reference-definitions" aria-hidden="true"></a>Link reference definitions</h2>
-<p data-sourcepos="2529:1-2537:61" dir="auto">A <a href="@">link reference definition</a>
-consists of a [link label], indented up to three spaces, followed
-by a colon (<code>:</code>), optional [whitespace] (including up to one
-[line ending]), a [link destination],
-optional [whitespace] (including up to one
-[line ending]), and an optional [link
-title], which if it is present must be separated
-from the [link destination] by [whitespace].
-No further [non-whitespace characters] may occur on the line.</p>
-<p data-sourcepos="2539:1-2544:5" dir="auto">A [link reference definition]
-does not correspond to a structural element of a document. Instead, it
-defines a label which can be used in [reference links]
-and reference-style [images] elsewhere in the document. [Link
-reference definitions] can come either before or after the links that use
-them.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2546:1-2552:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url "title"</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2555:1-2563:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> [foo]: </span>
-<span id="LC2" class="line" lang="plaintext"> /url </span>
-<span id="LC3" class="line" lang="plaintext"> 'the title' </span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">[foo]</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="the title"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2566:1-2572:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[Foo*bar\]]:my_(url) 'title (with parens)'</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[Foo*bar\]]</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="my_(url)" title="title (with parens)"&gt;Foo*bar]&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2575:1-2583:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[Foo bar]:</span>
-<span id="LC2" class="line" lang="plaintext">&lt;my url&gt;</span>
-<span id="LC3" class="line" lang="plaintext">'title'</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">[Foo bar]</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;&lt;a href="my%20url" title="title"&gt;Foo bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2586:1-2586:41" dir="auto">The title may extend over multiple lines:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2588:1-2602:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url '</span>
-<span id="LC2" class="line" lang="plaintext">title</span>
-<span id="LC3" class="line" lang="plaintext">line1</span>
-<span id="LC4" class="line" lang="plaintext">line2</span>
-<span id="LC5" class="line" lang="plaintext">'</span>
-<span id="LC6" class="line" lang="plaintext"></span>
-<span id="LC7" class="line" lang="plaintext">[foo]</span>
-<span id="LC8" class="line" lang="plaintext">.</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="</span>
-<span id="LC10" class="line" lang="plaintext">title</span>
-<span id="LC11" class="line" lang="plaintext">line1</span>
-<span id="LC12" class="line" lang="plaintext">line2</span>
-<span id="LC13" class="line" lang="plaintext">"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2605:1-2605:43" dir="auto">However, it may not contain a [blank line]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2607:1-2617:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url 'title</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">with blank line'</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">[foo]</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;[foo]: /url 'title&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;with blank line'&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2620:1-2620:25" dir="auto">The title may be omitted:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2622:1-2629:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]:</span>
-<span id="LC2" class="line" lang="plaintext">/url</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">[foo]</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2632:1-2632:40" dir="auto">The link destination may not be omitted:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2634:1-2641:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]:</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[foo]:&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2643:2-2644:16" dir="auto">However, an empty link destination may be specified using
-angle brackets:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2646:1-2652:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: &lt;&gt;</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href=""&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2654:1-2655:11" dir="auto">The title must be separated from the link destination by
-whitespace:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2657:1-2664:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: &lt;bar&gt;(baz)</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[foo]: &lt;bar&gt;(baz)&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2667:1-2668:24" dir="auto">Both title and destination can contain backslash escapes
-and literal backslashes:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2670:1-2676:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url\bar\*baz "foo\"bar\baz"</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url%5Cbar*baz" title="foo&amp;quot;bar\baz"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2679:1-2679:52" dir="auto">A link can come before its corresponding definition:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2681:1-2687:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: url</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="url"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2690:1-2691:11" dir="auto">If there are several matching definitions, the first one takes
-precedence:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2693:1-2700:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: first</span>
-<span id="LC4" class="line" lang="plaintext">[foo]: second</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;&lt;a href="first"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2703:1-2704:33" dir="auto">As noted in the section on [Links], matching of labels is
-case-insensitive (see [matches]).</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2706:1-2712:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[FOO]: /url</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[Foo]</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url"&gt;Foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2715:1-2721:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[ΑΓΩ]: /φου</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[αγω]</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/%CF%86%CE%BF%CF%85"&gt;αγω&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2724:1-2725:39" dir="auto">Here is a link reference definition with no corresponding link.
-It contributes nothing to the document.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2727:1-2730:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url</span>
-<span id="LC2" class="line" lang="plaintext">.</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2733:1-2733:20" dir="auto">Here is another one:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2735:1-2742:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[</span>
-<span id="LC2" class="line" lang="plaintext">foo</span>
-<span id="LC3" class="line" lang="plaintext">]: /url</span>
-<span id="LC4" class="line" lang="plaintext">bar</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2745:1-2746:44" dir="auto">This is not a link reference definition, because there are
-[non-whitespace characters] after the title:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2748:1-2752:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url "title" ok</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[foo]: /url &amp;quot;title&amp;quot; ok&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2755:1-2755:57" dir="auto">This is a link reference definition, but it has no title:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2757:1-2762:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url</span>
-<span id="LC2" class="line" lang="plaintext">"title" ok</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&amp;quot;title&amp;quot; ok&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2765:1-2766:12" dir="auto">This is not a link reference definition, because it is indented
-four spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2768:1-2776:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> [foo]: /url "title"</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;[foo]: /url &amp;quot;title&amp;quot;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2779:1-2780:13" dir="auto">This is not a link reference definition, because it occurs inside
-a code block:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2782:1-2792:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
-<span id="LC2" class="line" lang="plaintext">[foo]: /url</span>
-<span id="LC3" class="line" lang="plaintext">```</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">[foo]</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;[foo]: /url</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2795:1-2795:59" dir="auto">A [link reference definition] cannot interrupt a paragraph.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2797:1-2806:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext">[bar]: /baz</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">[bar]</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;Foo</span>
-<span id="LC7" class="line" lang="plaintext">[bar]: /baz&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;[bar]&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2809:1-2810:65" dir="auto">However, it can directly follow other block elements, such as headings
-and thematic breaks, and it need not be followed by a blank line.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2812:1-2821:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># [Foo]</span>
-<span id="LC2" class="line" lang="plaintext">[foo]: /url</span>
-<span id="LC3" class="line" lang="plaintext">&gt; bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;h1&gt;&lt;a href="/url"&gt;Foo&lt;/a&gt;&lt;/h1&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2823:1-2831:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url</span>
-<span id="LC2" class="line" lang="plaintext">bar</span>
-<span id="LC3" class="line" lang="plaintext">===</span>
-<span id="LC4" class="line" lang="plaintext">[foo]</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;h1&gt;bar&lt;/h1&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2833:1-2840:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url</span>
-<span id="LC2" class="line" lang="plaintext">===</span>
-<span id="LC3" class="line" lang="plaintext">[foo]</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;===</span>
-<span id="LC6" class="line" lang="plaintext">&lt;a href="/url"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2843:1-2844:61" dir="auto">Several [link reference definitions]
-can occur one after another, without intervening blank lines.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2846:1-2859:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /foo-url "foo"</span>
-<span id="LC2" class="line" lang="plaintext">[bar]: /bar-url</span>
-<span id="LC3" class="line" lang="plaintext"> "bar"</span>
-<span id="LC4" class="line" lang="plaintext">[baz]: /baz-url</span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext">[foo],</span>
-<span id="LC7" class="line" lang="plaintext">[bar],</span>
-<span id="LC8" class="line" lang="plaintext">[baz]</span>
-<span id="LC9" class="line" lang="plaintext">.</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/foo-url" title="foo"&gt;foo&lt;/a&gt;,</span>
-<span id="LC11" class="line" lang="plaintext">&lt;a href="/bar-url" title="bar"&gt;bar&lt;/a&gt;,</span>
-<span id="LC12" class="line" lang="plaintext">&lt;a href="/baz-url"&gt;baz&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2862:1-2865:12" dir="auto">[Link reference definitions] can occur
-inside block containers, like lists and block quotations. They
-affect the entire document, not just the container in which they
-are defined:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2867:1-2875:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">&gt; [foo]: /url</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url"&gt;foo&lt;/a&gt;&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2878:1-2882:19" dir="auto">Whether something is a [link reference definition] is
-independent of whether the link reference it defines is
-used in the document. Thus, for example, the following
-document contains just a link reference definition, and
-no visible content:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2884:1-2887:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url</span>
-<span id="LC2" class="line" lang="plaintext">.</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="2890:1-2890:13" dir="auto">
-<a id="user-content-paragraphs" class="anchor" href="#paragraphs" aria-hidden="true"></a>Paragraphs</h2>
-<p data-sourcepos="2892:1-2897:13" dir="auto">A sequence of non-blank lines that cannot be interpreted as other
-kinds of blocks forms a <a href="@">paragraph</a>.
-The contents of the paragraph are the result of parsing the
-paragraph's raw content as inlines. The paragraph's raw content
-is formed by concatenating the lines and removing initial and final
-[whitespace].</p>
-<p data-sourcepos="2899:1-2899:37" dir="auto">A simple example with two paragraphs:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2901:1-2908:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">bbb</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;aaa&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;bbb&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2911:1-2911:58" dir="auto">Paragraphs can contain multiple lines, but no blank lines:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2913:1-2924:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
-<span id="LC2" class="line" lang="plaintext">bbb</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">ccc</span>
-<span id="LC5" class="line" lang="plaintext">ddd</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;aaa</span>
-<span id="LC8" class="line" lang="plaintext">bbb&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;ccc</span>
-<span id="LC10" class="line" lang="plaintext">ddd&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2927:1-2927:54" dir="auto">Multiple blank lines between paragraph have no effect:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2929:1-2937:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">bbb</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;aaa&lt;/p&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;bbb&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2940:1-2940:27" dir="auto">Leading spaces are skipped:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2942:1-2948:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> aaa</span>
-<span id="LC2" class="line" lang="plaintext"> bbb</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;aaa</span>
-<span id="LC5" class="line" lang="plaintext">bbb&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2951:1-2952:40" dir="auto">Lines after the first may be indented any amount, since indented
-code blocks cannot interrupt paragraphs.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2954:1-2962:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
-<span id="LC2" class="line" lang="plaintext"> bbb</span>
-<span id="LC3" class="line" lang="plaintext"> ccc</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;aaa</span>
-<span id="LC6" class="line" lang="plaintext">bbb</span>
-<span id="LC7" class="line" lang="plaintext">ccc&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2965:1-2966:44" dir="auto">However, the first line may be indented at most three spaces,
-or an indented code block will be triggered:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2968:1-2974:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> aaa</span>
-<span id="LC2" class="line" lang="plaintext">bbb</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;aaa</span>
-<span id="LC5" class="line" lang="plaintext">bbb&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2977:1-2984:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> aaa</span>
-<span id="LC2" class="line" lang="plaintext">bbb</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
-<span id="LC5" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;bbb&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="2987:1-2989:7" dir="auto">Final spaces are stripped before inline parsing, so a paragraph
-that ends with two or more spaces will not end with a [hard line
-break]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="2991:1-2997:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa </span>
-<span id="LC2" class="line" lang="plaintext">bbb </span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;aaa&lt;br /&gt;</span>
-<span id="LC5" class="line" lang="plaintext">bbb&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="3000:1-3000:14" dir="auto">
-<a id="user-content-blank-lines" class="anchor" href="#blank-lines" aria-hidden="true"></a>Blank lines</h2>
-<p data-sourcepos="3002:1-3004:22" dir="auto">[Blank lines] between block-level elements are ignored,
-except for the role they play in determining whether a [list]
-is [tight] or [loose].</p>
-<p data-sourcepos="3006:1-3006:70" dir="auto">Blank lines at the beginning and end of the document are also ignored.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3008:1-3020:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> </span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">aaa</span>
-<span id="LC4" class="line" lang="plaintext"> </span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext"># aaa</span>
-<span id="LC7" class="line" lang="plaintext"></span>
-<span id="LC8" class="line" lang="plaintext"> </span>
-<span id="LC9" class="line" lang="plaintext">.</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;aaa&lt;/p&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;h1&gt;aaa&lt;/h1&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div>
-<h2 data-sourcepos="3024:1-3024:21">
-<a id="user-content-tables-extension" class="anchor" href="#tables-extension" aria-hidden="true"></a>Tables (extension)</h2>
-<p data-sourcepos="3026:1-3027:10">GFM enables the <code>table</code> extension, where an additional leaf block type is
-available.</p>
-<p data-sourcepos="3029:1-3031:23">A <a href="@">table</a> is an arrangement of data with rows and columns, consisting of a
-single header row, a [delimiter row] separating the header from the data, and
-zero or more data rows.</p>
-<p data-sourcepos="3033:1-3037:23">Each row consists of cells containing arbitrary text, in which [inlines] are
-parsed, separated by pipes (<code>|</code>). A leading and trailing pipe is also
-recommended for clarity of reading, and if there's otherwise parsing ambiguity.
-Spaces between pipes and cell content are trimmed. Block-level elements cannot
-be inserted in a table.</p>
-<p data-sourcepos="3039:1-3041:40">The <a href="@">delimiter row</a> consists of cells whose only content are hyphens (<code>-</code>),
-and optionally, a leading or trailing colon (<code>:</code>), or both, to indicate left,
-right, or center alignment respectively.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3043:1-3062:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| foo | bar |</span>
-<span id="LC2" class="line" lang="plaintext">| --- | --- |</span>
-<span id="LC3" class="line" lang="plaintext">| baz | bim |</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;table&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;thead&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;th&gt;foo&lt;/th&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;th&gt;bar&lt;/th&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/thead&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;tbody&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;td&gt;baz&lt;/td&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;td&gt;bim&lt;/td&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/tbody&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3064:1-3065:74">Cells in one column don't need to match length, though it's easier to read if
-they are. Likewise, use of leading and trailing pipes may be inconsistent:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3067:1-3086:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| abc | defghi |</span>
-<span id="LC2" class="line" lang="plaintext">:-: | -----------:</span>
-<span id="LC3" class="line" lang="plaintext">bar | baz</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;table&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;thead&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;th align="center"&gt;abc&lt;/th&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;th align="right"&gt;defghi&lt;/th&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/thead&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;tbody&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;td align="center"&gt;bar&lt;/td&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;td align="right"&gt;baz&lt;/td&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/tbody&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3088:1-3089:13">Include a pipe in a cell's content by escaping it, including inside other
-inline spans:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3091:1-3112:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| f\|oo |</span>
-<span id="LC2" class="line" lang="plaintext">| ------ |</span>
-<span id="LC3" class="line" lang="plaintext">| b `\|` az |</span>
-<span id="LC4" class="line" lang="plaintext">| b **\|** im |</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;table&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;thead&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;th&gt;f|oo&lt;/th&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/thead&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;tbody&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;td&gt;b &lt;code&gt;|&lt;/code&gt; az&lt;/td&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;td&gt;b &lt;strong&gt;|&lt;/strong&gt; im&lt;/td&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC19" class="line" lang="plaintext">&lt;/tbody&gt;</span>
-<span id="LC20" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3114:1-3115:22">The table is broken at the first empty line, or beginning of another
-block-level structure:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3117:1-3140:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| abc | def |</span>
-<span id="LC2" class="line" lang="plaintext">| --- | --- |</span>
-<span id="LC3" class="line" lang="plaintext">| bar | baz |</span>
-<span id="LC4" class="line" lang="plaintext">&gt; bar</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;table&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;thead&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;th&gt;abc&lt;/th&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;th&gt;def&lt;/th&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/thead&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;tbody&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;td&gt;bar&lt;/td&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;td&gt;baz&lt;/td&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/tbody&gt;</span>
-<span id="LC19" class="line" lang="plaintext">&lt;/table&gt;</span>
-<span id="LC20" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC21" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
-<span id="LC22" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3142:1-3169:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| abc | def |</span>
-<span id="LC2" class="line" lang="plaintext">| --- | --- |</span>
-<span id="LC3" class="line" lang="plaintext">| bar | baz |</span>
-<span id="LC4" class="line" lang="plaintext">bar</span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext">bar</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;table&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;thead&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;th&gt;abc&lt;/th&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;th&gt;def&lt;/th&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/thead&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;tbody&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;td&gt;bar&lt;/td&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;td&gt;baz&lt;/td&gt;</span>
-<span id="LC19" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC20" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC21" class="line" lang="plaintext">&lt;td&gt;bar&lt;/td&gt;</span>
-<span id="LC22" class="line" lang="plaintext">&lt;td&gt;&lt;/td&gt;</span>
-<span id="LC23" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC24" class="line" lang="plaintext">&lt;/tbody&gt;</span>
-<span id="LC25" class="line" lang="plaintext">&lt;/table&gt;</span>
-<span id="LC26" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3171:1-3172:31">The header row must match the [delimiter row] in the number of cells. If not,
-a table will not be recognized:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3174:1-3182:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| abc | def |</span>
-<span id="LC2" class="line" lang="plaintext">| --- |</span>
-<span id="LC3" class="line" lang="plaintext">| bar |</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;| abc | def |</span>
-<span id="LC6" class="line" lang="plaintext">| --- |</span>
-<span id="LC7" class="line" lang="plaintext">| bar |&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3184:1-3186:65">The remainder of the table's rows may vary in the number of cells. If there
-are a number of cells fewer than the number of cells in the header row, empty
-cells are inserted. If there are greater, the excess is ignored:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3188:1-3212:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| abc | def |</span>
-<span id="LC2" class="line" lang="plaintext">| --- | --- |</span>
-<span id="LC3" class="line" lang="plaintext">| bar |</span>
-<span id="LC4" class="line" lang="plaintext">| bar | baz | boo |</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;table&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;thead&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;th&gt;abc&lt;/th&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;th&gt;def&lt;/th&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/thead&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;tbody&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;td&gt;bar&lt;/td&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;td&gt;&lt;/td&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC19" class="line" lang="plaintext">&lt;td&gt;bar&lt;/td&gt;</span>
-<span id="LC20" class="line" lang="plaintext">&lt;td&gt;baz&lt;/td&gt;</span>
-<span id="LC21" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC22" class="line" lang="plaintext">&lt;/tbody&gt;</span>
-<span id="LC23" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3214:1-3214:75">If there are no rows in the body, no <code>&lt;tbody&gt;</code> is generated in HTML output:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3216:1-3228:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| abc | def |</span>
-<span id="LC2" class="line" lang="plaintext">| --- | --- |</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;table&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;thead&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;tr&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;th&gt;abc&lt;/th&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;th&gt;def&lt;/th&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/tr&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/thead&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-</div>
-<h1 data-sourcepos="3232:1-3232:18" dir="auto">
-<a id="user-content-container-blocks" class="anchor" href="#container-blocks" aria-hidden="true"></a>Container blocks</h1>
-<p data-sourcepos="3234:1-3237:45" dir="auto">A <a href="#container-blocks">container block</a> is a block that has other
-blocks as its contents. There are two basic kinds of container blocks:
-[block quotes] and [list items].
-[Lists] are meta-containers for [list items].</p>
-<p data-sourcepos="3239:1-3240:26" dir="auto">We define the syntax for container blocks recursively. The general
-form of the definition is:</p>
-<blockquote data-sourcepos="3242:1-3244:35" dir="auto">
-<p data-sourcepos="3242:3-3244:35">If X is a sequence of blocks, then the result of
-transforming X in such-and-such a way is a container of type Y
-with these blocks as its content.</p>
-</blockquote>
-<p data-sourcepos="3246:1-3250:52" dir="auto">So, we explain what counts as a block quote or list item by explaining
-how these can be <em>generated</em> from their contents. This should suffice
-to define the syntax, although it does not give a recipe for <em>parsing</em>
-these constructions. (A recipe is provided below in the section entitled
-<a href="#appendix-a-parsing-strategy">A parsing strategy</a>.)</p>
-<h2 data-sourcepos="3252:1-3252:15" dir="auto">
-<a id="user-content-block-quotes" class="anchor" href="#block-quotes" aria-hidden="true"></a>Block quotes</h2>
-<p data-sourcepos="3254:1-3256:78" dir="auto">A <a href="@">block quote marker</a>
-consists of 0-3 spaces of initial indent, plus (a) the character <code>&gt;</code> together
-with a following space, or (b) a single character <code>&gt;</code> not followed by a space.</p>
-<p data-sourcepos="3258:1-3258:42" dir="auto">The following rules define [block quotes]:</p>
-<ol data-sourcepos="3260:1-3277:0" dir="auto">
-<li data-sourcepos="3260:1-3264:0">
-<p data-sourcepos="3260:5-3263:54"><strong>Basic case.</strong> If a string of lines <em>Ls</em> constitute a sequence
-of blocks <em>Bs</em>, then the result of prepending a [block quote
-marker] to the beginning of each line in <em>Ls</em>
-is a <a href="#block-quotes">block quote</a> containing <em>Bs</em>.</p>
-</li>
-<li data-sourcepos="3265:1-3274:0">
-<p data-sourcepos="3265:5-3273:48"><strong>Laziness.</strong> If a string of lines <em>Ls</em> constitute a <a href="#block-quotes">block
-quote</a> with contents <em>Bs</em>, then the result of deleting
-the initial [block quote marker] from one or
-more lines in which the next [non-whitespace character] after the [block
-quote marker] is [paragraph continuation
-text] is a block quote with <em>Bs</em> as its content.
-<a href="@">Paragraph continuation text</a> is text
-that will be parsed as part of the content of a paragraph, but does
-not occur at the beginning of the paragraph.</p>
-</li>
-<li data-sourcepos="3275:1-3277:0">
-<p data-sourcepos="3275:5-3276:65"><strong>Consecutiveness.</strong> A document cannot contain two [block
-quotes] in a row unless there is a [blank line] between them.</p>
-</li>
-</ol>
-<p data-sourcepos="3278:1-3278:54" dir="auto">Nothing else counts as a <a href="#block-quotes">block quote</a>.</p>
-<p data-sourcepos="3280:1-3280:25" dir="auto">Here is a simple example:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3282:1-3292:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; # Foo</span>
-<span id="LC2" class="line" lang="plaintext">&gt; bar</span>
-<span id="LC3" class="line" lang="plaintext">&gt; baz</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;bar</span>
-<span id="LC8" class="line" lang="plaintext">baz&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3295:1-3295:51" dir="auto">The spaces after the <code>&gt;</code> characters can be omitted:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3297:1-3307:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt;# Foo</span>
-<span id="LC2" class="line" lang="plaintext">&gt;bar</span>
-<span id="LC3" class="line" lang="plaintext">&gt; baz</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;bar</span>
-<span id="LC8" class="line" lang="plaintext">baz&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3310:1-3310:46" dir="auto">The <code>&gt;</code> characters can be indented 1-3 spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3312:1-3322:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &gt; # Foo</span>
-<span id="LC2" class="line" lang="plaintext"> &gt; bar</span>
-<span id="LC3" class="line" lang="plaintext"> &gt; baz</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;bar</span>
-<span id="LC8" class="line" lang="plaintext">baz&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3325:1-3325:34" dir="auto">Four spaces gives us a code block:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3327:1-3336:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &gt; # Foo</span>
-<span id="LC2" class="line" lang="plaintext"> &gt; bar</span>
-<span id="LC3" class="line" lang="plaintext"> &gt; baz</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&amp;gt; # Foo</span>
-<span id="LC6" class="line" lang="plaintext">&amp;gt; bar</span>
-<span id="LC7" class="line" lang="plaintext">&amp;gt; baz</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3339:1-3340:30" dir="auto">The Laziness clause allows us to omit the <code>&gt;</code> before
-[paragraph continuation text]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3342:1-3352:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; # Foo</span>
-<span id="LC2" class="line" lang="plaintext">&gt; bar</span>
-<span id="LC3" class="line" lang="plaintext">baz</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;bar</span>
-<span id="LC8" class="line" lang="plaintext">baz&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3355:1-3356:19" dir="auto">A block quote can contain some lazy and some non-lazy
-continuation lines:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3358:1-3368:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; bar</span>
-<span id="LC2" class="line" lang="plaintext">baz</span>
-<span id="LC3" class="line" lang="plaintext">&gt; foo</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;bar</span>
-<span id="LC7" class="line" lang="plaintext">baz</span>
-<span id="LC8" class="line" lang="plaintext">foo&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3371:1-3373:61" dir="auto">Laziness only applies to lines that would have been continuations of
-paragraphs had they been prepended with [block quote markers].
-For example, the <code>&gt; </code> cannot be omitted in the second line of</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3375:1-3378:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="gt">&gt; foo</span></span>
-<span id="LC2" class="line" lang="markdown"><span class="gt">&gt; ---</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3380:1-3380:29" dir="auto">without changing the meaning:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3382:1-3390:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
-<span id="LC2" class="line" lang="plaintext">---</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3393:1-3393:52" dir="auto">Similarly, if we omit the <code>&gt; </code> in the second line of</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3395:1-3398:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="gt">&gt; - foo</span></span>
-<span id="LC2" class="line" lang="markdown"><span class="gt">&gt; - bar</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3400:1-3400:47" dir="auto">then the block quote ends after the first line:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3402:1-3414:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; - foo</span>
-<span id="LC2" class="line" lang="plaintext">- bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3417:1-3418:53" dir="auto">For the same reason, we can't omit the <code>&gt; </code> in front of
-subsequent lines of an indented or fenced code block:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3420:1-3430:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
-<span id="LC2" class="line" lang="plaintext"> bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3433:1-3443:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; ```</span>
-<span id="LC2" class="line" lang="plaintext">foo</span>
-<span id="LC3" class="line" lang="plaintext">```</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3446:1-3447:19" dir="auto">Note that in the following case, we have a [lazy
-continuation line]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3449:1-3457:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
-<span id="LC2" class="line" lang="plaintext"> - bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;foo</span>
-<span id="LC6" class="line" lang="plaintext">- bar&lt;/p&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3460:1-3460:24" dir="auto">To see why, note that in</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3462:1-3465:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="gt">&gt; foo</span></span>
-<span id="LC2" class="line" lang="markdown"><span class="gt">&gt; - bar</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3467:1-3469:61" dir="auto">the <code>- bar</code> is indented too far to start a list, and can't
-be an indented code block because indented code blocks cannot
-interrupt paragraphs, so it is [paragraph continuation text].</p>
-<p data-sourcepos="3471:1-3471:27" dir="auto">A block quote can be empty:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3473:1-3478:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC4" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3481:1-3488:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt;</span>
-<span id="LC2" class="line" lang="plaintext">&gt; </span>
-<span id="LC3" class="line" lang="plaintext">&gt; </span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3491:1-3491:52" dir="auto">A block quote can have initial or final blank lines:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3493:1-3501:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt;</span>
-<span id="LC2" class="line" lang="plaintext">&gt; foo</span>
-<span id="LC3" class="line" lang="plaintext">&gt; </span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3504:1-3504:43" dir="auto">A blank line always separates block quotes:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3506:1-3517:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">&gt; bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3520:1-3523:44" dir="auto">(Most current Markdown implementations, including John Gruber's
-original <code>Markdown.pl</code>, will parse this example as a single block quote
-with two paragraphs. But it seems better to allow the author to decide
-whether two block quotes or one are wanted.)</p>
-<p data-sourcepos="3525:1-3526:28" dir="auto">Consecutiveness means that if we put these block quotes together,
-we get a single block quote:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3528:1-3536:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
-<span id="LC2" class="line" lang="plaintext">&gt; bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;foo</span>
-<span id="LC6" class="line" lang="plaintext">bar&lt;/p&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3539:1-3539:46" dir="auto">To get a block quote with two paragraphs, use:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3541:1-3550:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
-<span id="LC2" class="line" lang="plaintext">&gt;</span>
-<span id="LC3" class="line" lang="plaintext">&gt; bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3553:1-3553:38" dir="auto">Block quotes can interrupt paragraphs:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3555:1-3563:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span>
-<span id="LC2" class="line" lang="plaintext">&gt; bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3566:1-3567:7" dir="auto">In general, blank lines are not needed before or after block
-quotes:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3569:1-3581:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; aaa</span>
-<span id="LC2" class="line" lang="plaintext">***</span>
-<span id="LC3" class="line" lang="plaintext">&gt; bbb</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;aaa&lt;/p&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;hr /&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;bbb&lt;/p&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3584:1-3585:40" dir="auto">However, because of laziness, a blank line is needed between
-a block quote and a following paragraph:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3587:1-3595:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; bar</span>
-<span id="LC2" class="line" lang="plaintext">baz</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;bar</span>
-<span id="LC6" class="line" lang="plaintext">baz&lt;/p&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3598:1-3607:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; bar</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">baz</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3610:1-3619:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; bar</span>
-<span id="LC2" class="line" lang="plaintext">&gt;</span>
-<span id="LC3" class="line" lang="plaintext">baz</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3622:1-3624:19" dir="auto">It is a consequence of the Laziness rule that any number
-of initial <code>&gt;</code>s may be omitted on a continuation line of a
-nested block quote:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3626:1-3638:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; &gt; &gt; foo</span>
-<span id="LC2" class="line" lang="plaintext">bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;foo</span>
-<span id="LC8" class="line" lang="plaintext">bar&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3641:1-3655:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt;&gt;&gt; foo</span>
-<span id="LC2" class="line" lang="plaintext">&gt; bar</span>
-<span id="LC3" class="line" lang="plaintext">&gt;&gt;baz</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;foo</span>
-<span id="LC9" class="line" lang="plaintext">bar</span>
-<span id="LC10" class="line" lang="plaintext">baz&lt;/p&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3658:1-3661:8" dir="auto">When including an indented code block in a block quote,
-remember that the [block quote marker] includes
-both the <code>&gt;</code> and a following space. So <em>five spaces</em> are needed after
-the <code>&gt;</code>:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3663:1-3675:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; code</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">&gt; not code</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;code</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;not code&lt;/p&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="3679:1-3679:13" dir="auto">
-<a id="user-content-list-items" class="anchor" href="#list-items" aria-hidden="true"></a>List items</h2>
-<p data-sourcepos="3681:1-3682:49" dir="auto">A <a href="@">list marker</a> is a
-[bullet list marker] or an [ordered list marker].</p>
-<p data-sourcepos="3684:1-3685:32" dir="auto">A <a href="@">bullet list marker</a>
-is a <code>-</code>, <code>+</code>, or <code>*</code> character.</p>
-<p data-sourcepos="3687:1-3691:18" dir="auto">An <a href="@">ordered list marker</a>
-is a sequence of 1--9 arabic digits (<code>0-9</code>), followed by either a
-<code>.</code> character or a <code>)</code> character. (The reason for the length
-limit is that with 10 digits we start seeing integer overflows
-in some browsers.)</p>
-<p data-sourcepos="3693:1-3693:40" dir="auto">The following rules define [list items]:</p>
-<ol data-sourcepos="3695:1-3714:0" dir="auto">
-<li data-sourcepos="3695:1-3714:0">
-<p data-sourcepos="3695:5-3703:45"><strong>Basic case.</strong> If a sequence of lines <em>Ls</em> constitute a sequence of
-blocks <em>Bs</em> starting with a [non-whitespace character], and <em>M</em> is a
-list marker of width <em>W</em> followed by 1 ≤ <em>N</em> ≤ 4 spaces, then the result
-of prepending <em>M</em> and the following spaces to the first line of
-<em>Ls</em>, and indenting subsequent lines of <em>Ls</em> by <em>W + N</em> spaces, is a
-list item with <em>Bs</em> as its contents. The type of the list item
-(bullet or ordered) is determined by the type of its list marker.
-If the list item is ordered, then it is also assigned a start
-number, based on the ordered list marker.</p>
-<p data-sourcepos="3705:5-3705:15">Exceptions:</p>
-<ol data-sourcepos="3707:5-3714:0">
-<li data-sourcepos="3707:5-3711:57">When the first list item in a [list] interrupts
-a paragraph---that is, when it starts on a line that would
-otherwise count as [paragraph continuation text]---then (a)
-the lines <em>Ls</em> must not begin with a blank line, and (b) if
-the list item is ordered, the start number must be 1.</li>
-<li data-sourcepos="3712:5-3714:0">If any line is a [thematic break][thematic breaks] then
-that line is not a list item.</li>
-</ol>
-</li>
-</ol>
-<p data-sourcepos="3715:1-3715:34" dir="auto">For example, let <em>Ls</em> be the lines</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3717:1-3732:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">A paragraph</span>
-<span id="LC2" class="line" lang="plaintext">with two lines.</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext"> indented code</span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext">&gt; A block quote.</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;A paragraph</span>
-<span id="LC9" class="line" lang="plaintext">with two lines.&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;p&gt;A block quote.&lt;/p&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3735:1-3737:30" dir="auto">And let <em>M</em> be the marker <code>1.</code>, and <em>N</em> = 2. Then rule #1 says
-that the following is an ordered list item with start number 1,
-and the same contents as <em>Ls</em>:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3739:1-3758:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. A paragraph</span>
-<span id="LC2" class="line" lang="plaintext"> with two lines.</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext"> indented code</span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext"> &gt; A block quote.</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;A paragraph</span>
-<span id="LC11" class="line" lang="plaintext">with two lines.&lt;/p&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;p&gt;A block quote.&lt;/p&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3761:1-3767:5" dir="auto">The most important thing to notice is that the position of
-the text after the list marker determines how much indentation
-is needed in subsequent blocks in the list item. If the list
-marker takes up two spaces, and there are three spaces between
-the list marker and the next [non-whitespace character], then blocks
-must be indented five spaces in order to fall under the list
-item.</p>
-<p data-sourcepos="3769:1-3770:24" dir="auto">Here are some examples showing how far content must be indented to be
-put under the list item:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3772:1-3781:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- one</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> two</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;one&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;two&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3784:1-3795:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- one</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> two</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;one&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;two&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3798:1-3808:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> - one</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> two</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;one&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt; two</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3811:1-3822:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> - one</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> two</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;one&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;two&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3825:1-3831:13" dir="auto">It is tempting to think of this in terms of columns: the continuation
-blocks must be indented at least to the column of the first
-[non-whitespace character] after the list marker. However, that is not quite right.
-The spaces after the list marker determine how much relative indentation
-is needed. Which column this indentation reaches will depend on
-how the list item is embedded in other constructions, as shown by
-this example:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3833:1-3848:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &gt; &gt; 1. one</span>
-<span id="LC2" class="line" lang="plaintext">&gt;&gt;</span>
-<span id="LC3" class="line" lang="plaintext">&gt;&gt; two</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;one&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;two&lt;/p&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/ol&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3851:1-3853:67" dir="auto">Here <code>two</code> occurs in the same column as the list marker <code>1.</code>,
-but is actually contained in the list item, because there is
-sufficient indentation after the last containing blockquote marker.</p>
-<p data-sourcepos="3855:1-3858:38" dir="auto">The converse is also possible. In the following example, the word <code>two</code>
-occurs far to the right of the initial text of the list item, <code>one</code>, but
-it is not considered part of the list item, because it is not indented
-far enough past the blockquote marker:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3860:1-3873:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt;&gt;- one</span>
-<span id="LC2" class="line" lang="plaintext">&gt;&gt;</span>
-<span id="LC3" class="line" lang="plaintext"> &gt; &gt; two</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;one&lt;/li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;two&lt;/p&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3876:1-3877:51" dir="auto">Note that at least one space is needed between the list marker and
-any following content, so these are not list items:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3879:1-3886:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-one</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">2.two</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;-one&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;2.two&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3889:1-3890:15" dir="auto">A list item may contain blocks that are separated by more than
-one blank line.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3892:1-3904:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext"> bar</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3907:1-3907:42" dir="auto">A list item may contain any kind of block:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3909:1-3931:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> ```</span>
-<span id="LC4" class="line" lang="plaintext"> bar</span>
-<span id="LC5" class="line" lang="plaintext"> ```</span>
-<span id="LC6" class="line" lang="plaintext"></span>
-<span id="LC7" class="line" lang="plaintext"> baz</span>
-<span id="LC8" class="line" lang="plaintext"></span>
-<span id="LC9" class="line" lang="plaintext"> &gt; bam</span>
-<span id="LC10" class="line" lang="plaintext">.</span>
-<span id="LC11" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
-<span id="LC15" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;p&gt;bam&lt;/p&gt;</span>
-<span id="LC19" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC20" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC21" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3934:1-3935:43" dir="auto">A list item that contains an indented code block will preserve
-empty lines within the code block verbatim.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3937:1-3955:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- Foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> bar</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext"> baz</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;Foo&lt;/p&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
-<span id="LC12" class="line" lang="plaintext"></span>
-<span id="LC13" class="line" lang="plaintext"></span>
-<span id="LC14" class="line" lang="plaintext">baz</span>
-<span id="LC15" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3957:1-3957:65" dir="auto">Note that ordered list start numbers must be nine digits or less:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3959:1-3965:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">123456789. ok</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;ol start="123456789"&gt;</span>
-<span id="LC4" class="line" lang="plaintext">&lt;li&gt;ok&lt;/li&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3968:1-3972:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1234567890. not ok</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;1234567890. not ok&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3975:1-3975:33" dir="auto">A start number may begin with 0s:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3977:1-3983:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">0. ok</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;ol start="0"&gt;</span>
-<span id="LC4" class="line" lang="plaintext">&lt;li&gt;ok&lt;/li&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3986:1-3992:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">003. ok</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;ol start="3"&gt;</span>
-<span id="LC4" class="line" lang="plaintext">&lt;li&gt;ok&lt;/li&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="3995:1-3995:35" dir="auto">A start number may not be negative:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="3997:1-4001:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-1. not ok</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;-1. not ok&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<ol start="2" data-sourcepos="4005:1-4015:0" dir="auto">
-<li data-sourcepos="4005:1-4015:0">
-<strong>Item starting with indented code.</strong> If a sequence of lines <em>Ls</em>
-constitute a sequence of blocks <em>Bs</em> starting with an indented code
-block, and <em>M</em> is a list marker of width <em>W</em> followed by
-one space, then the result of prepending <em>M</em> and the following
-space to the first line of <em>Ls</em>, and indenting subsequent lines of
-<em>Ls</em> by <em>W + 1</em> spaces, is a list item with <em>Bs</em> as its contents.
-If a line is empty, then it need not be indented. The type of the
-list item (bullet or ordered) is determined by the type of its list
-marker. If the list item is ordered, then it is also assigned a
-start number, based on the ordered list marker.</li>
-</ol>
-<p data-sourcepos="4016:1-4018:39" dir="auto">An indented code block will have to be indented four spaces beyond
-the edge of the region where text will be included in the list item.
-In the following case that is 6 spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4020:1-4032:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4035:1-4035:33" dir="auto">And in this case it is 11 spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4037:1-4049:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> 10. foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ol start="10"&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4052:1-4054:12" dir="auto">If the <em>first</em> block in the list item is an indented code block,
-then by rule #2, the contents must be indented <em>one</em> space after the
-list marker:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4056:1-4068:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> indented code</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">paragraph</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext"> more code</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;paragraph&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;more code</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4071:1-4087:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. indented code</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> paragraph</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext"> more code</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;p&gt;paragraph&lt;/p&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;more code</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4090:1-4091:22" dir="auto">Note that an additional space indent is interpreted as space
-inside the code block:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4093:1-4109:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. indented code</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> paragraph</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext"> more code</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt; indented code</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;p&gt;paragraph&lt;/p&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;more code</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4112:1-4118:55" dir="auto">Note that rules #1 and #2 only apply to two cases: (a) cases
-in which the lines to be included in a list item begin with a
-[non-whitespace character], and (b) cases in which
-they begin with an indented code
-block. In a case like the following, where the first block begins with
-a three-space indent, the rules do not allow us to form a list item by
-indenting the whole thing and prepending a list marker:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4120:1-4127:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4130:1-4139:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4142:1-4145:15" dir="auto">This is not a significant restriction, because when a block begins
-with 1-3 spaces indent, the indentation can always be removed without
-a change in interpretation, allowing rule #1 to be applied. So, in
-the above case:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4147:1-4158:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<ol start="3" data-sourcepos="4161:1-4172:0" dir="auto">
-<li data-sourcepos="4161:1-4172:0">
-<strong>Item starting with a blank line.</strong> If a sequence of lines <em>Ls</em>
-starting with a single [blank line] constitute a (possibly empty)
-sequence of blocks <em>Bs</em>, not separated from each other by more than
-one blank line, and <em>M</em> is a list marker of width <em>W</em>,
-then the result of prepending <em>M</em> to the first line of <em>Ls</em>, and
-indenting subsequent lines of <em>Ls</em> by <em>W + 1</em> spaces, is a list
-item with <em>Bs</em> as its contents.
-If a line is empty, then it need not be indented. The type of the
-list item (bullet or ordered) is determined by the type of its list
-marker. If the list item is ordered, then it is also assigned a
-start number, based on the ordered list marker.</li>
-</ol>
-<p data-sourcepos="4173:1-4173:72" dir="auto">Here are some list items that start with a blank line but are not empty:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4175:1-4196:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-</span>
-<span id="LC2" class="line" lang="plaintext"> foo</span>
-<span id="LC3" class="line" lang="plaintext">-</span>
-<span id="LC4" class="line" lang="plaintext"> ```</span>
-<span id="LC5" class="line" lang="plaintext"> bar</span>
-<span id="LC6" class="line" lang="plaintext"> ```</span>
-<span id="LC7" class="line" lang="plaintext">-</span>
-<span id="LC8" class="line" lang="plaintext"> baz</span>
-<span id="LC9" class="line" lang="plaintext">.</span>
-<span id="LC10" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;baz</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC19" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC20" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4198:1-4199:66" dir="auto">When the list item starts with a blank line, the number of spaces
-following the list marker doesn't change the required indentation:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4201:1-4208:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- </span>
-<span id="LC2" class="line" lang="plaintext"> foo</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4211:1-4213:5" dir="auto">A list item can begin with at most one blank line.
-In the following example, <code>foo</code> is not part of the list
-item:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4215:1-4224:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> foo</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4227:1-4227:34" dir="auto">Here is an empty bullet list item:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4229:1-4239:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext">-</span>
-<span id="LC3" class="line" lang="plaintext">- bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;&lt;/li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4242:1-4242:72" dir="auto">It does not matter whether there are spaces following the [list marker]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4244:1-4254:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext">- </span>
-<span id="LC3" class="line" lang="plaintext">- bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;&lt;/li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4257:1-4257:35" dir="auto">Here is an empty ordered list item:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4259:1-4269:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. foo</span>
-<span id="LC2" class="line" lang="plaintext">2.</span>
-<span id="LC3" class="line" lang="plaintext">3. bar</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;&lt;/li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4272:1-4272:48" dir="auto">A list may start or end with an empty list item:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4274:1-4280:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC4" class="line" lang="plaintext">&lt;li&gt;&lt;/li&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4282:1-4282:57" dir="auto">However, an empty list item cannot interrupt a paragraph:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4284:1-4295:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span>
-<span id="LC2" class="line" lang="plaintext">*</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">foo</span>
-<span id="LC5" class="line" lang="plaintext">1.</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;foo</span>
-<span id="LC8" class="line" lang="plaintext">*&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;foo</span>
-<span id="LC10" class="line" lang="plaintext">1.&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<ol start="4" data-sourcepos="4298:1-4303:0" dir="auto">
-<li data-sourcepos="4298:1-4303:0">
-<strong>Indentation.</strong> If a sequence of lines <em>Ls</em> constitutes a list item
-according to rule #1, #2, or #3, then the result of indenting each line
-of <em>Ls</em> by 1-3 spaces (the same for each line) also constitutes a
-list item with the same contents and attributes. If a line is
-empty, then it need not be indented.</li>
-</ol>
-<p data-sourcepos="4304:1-4304:19" dir="auto">Indented one space:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4306:1-4325:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> 1. A paragraph</span>
-<span id="LC2" class="line" lang="plaintext"> with two lines.</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext"> indented code</span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext"> &gt; A block quote.</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;A paragraph</span>
-<span id="LC11" class="line" lang="plaintext">with two lines.&lt;/p&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;p&gt;A block quote.&lt;/p&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4328:1-4328:20" dir="auto">Indented two spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4330:1-4349:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> 1. A paragraph</span>
-<span id="LC2" class="line" lang="plaintext"> with two lines.</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext"> indented code</span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext"> &gt; A block quote.</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;A paragraph</span>
-<span id="LC11" class="line" lang="plaintext">with two lines.&lt;/p&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;p&gt;A block quote.&lt;/p&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4352:1-4352:22" dir="auto">Indented three spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4354:1-4373:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> 1. A paragraph</span>
-<span id="LC2" class="line" lang="plaintext"> with two lines.</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext"> indented code</span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext"> &gt; A block quote.</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;A paragraph</span>
-<span id="LC11" class="line" lang="plaintext">with two lines.&lt;/p&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;p&gt;A block quote.&lt;/p&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4376:1-4376:38" dir="auto">Four spaces indent gives a code block:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4378:1-4393:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> 1. A paragraph</span>
-<span id="LC2" class="line" lang="plaintext"> with two lines.</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext"> indented code</span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext"> &gt; A block quote.</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;1. A paragraph</span>
-<span id="LC9" class="line" lang="plaintext"> with two lines.</span>
-<span id="LC10" class="line" lang="plaintext"></span>
-<span id="LC11" class="line" lang="plaintext"> indented code</span>
-<span id="LC12" class="line" lang="plaintext"></span>
-<span id="LC13" class="line" lang="plaintext"> &amp;gt; A block quote.</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<ol start="5" data-sourcepos="4397:1-4405:0" dir="auto">
-<li data-sourcepos="4397:1-4405:0">
-<strong>Laziness.</strong> If a string of lines <em>Ls</em> constitute a <a href="#list-items">list
-item</a> with contents <em>Bs</em>, then the result of deleting
-some or all of the indentation from one or more lines in which the
-next [non-whitespace character] after the indentation is
-[paragraph continuation text] is a
-list item with the same contents and attributes. The unindented
-lines are called
-<a href="@">lazy continuation line</a>s.</li>
-</ol>
-<p data-sourcepos="4406:1-4406:50" dir="auto">Here is an example with [lazy continuation lines]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4408:1-4427:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> 1. A paragraph</span>
-<span id="LC2" class="line" lang="plaintext">with two lines.</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext"> indented code</span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext"> &gt; A block quote.</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;A paragraph</span>
-<span id="LC11" class="line" lang="plaintext">with two lines.&lt;/p&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;p&gt;A block quote.&lt;/p&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4430:1-4430:37" dir="auto">Indentation can be partially deleted:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4432:1-4440:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> 1. A paragraph</span>
-<span id="LC2" class="line" lang="plaintext"> with two lines.</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;li&gt;A paragraph</span>
-<span id="LC6" class="line" lang="plaintext">with two lines.&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4443:1-4443:63" dir="auto">These examples show how laziness can work in nested structures:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4445:1-4459:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; 1. &gt; Blockquote</span>
-<span id="LC2" class="line" lang="plaintext">continued here.</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;Blockquote</span>
-<span id="LC9" class="line" lang="plaintext">continued here.&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/ol&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4462:1-4476:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; 1. &gt; Blockquote</span>
-<span id="LC2" class="line" lang="plaintext">&gt; continued here.</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;Blockquote</span>
-<span id="LC9" class="line" lang="plaintext">continued here.&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/ol&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<ol start="6" data-sourcepos="4480:1-4482:0" dir="auto">
-<li data-sourcepos="4480:1-4482:0">
-<strong>That's all.</strong> Nothing that is not counted as a list item by rules
-#1--5 counts as a <a href="#list-items">list item</a>.</li>
-</ol>
-<p data-sourcepos="4483:1-4486:17" dir="auto">The rules for sublists follow from the general rules
-[above][List items]. A sublist must be indented the same number
-of spaces a paragraph would need to be in order to be included
-in the list item.</p>
-<p data-sourcepos="4488:1-4488:43" dir="auto">So, in this case we need two spaces indent:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4490:1-4511:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext"> - bar</span>
-<span id="LC3" class="line" lang="plaintext"> - baz</span>
-<span id="LC4" class="line" lang="plaintext"> - boo</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;foo</span>
-<span id="LC8" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;li&gt;bar</span>
-<span id="LC10" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;li&gt;baz</span>
-<span id="LC12" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;li&gt;boo&lt;/li&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC19" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC20" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4514:1-4514:18" dir="auto">One is not enough:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4516:1-4528:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext"> - bar</span>
-<span id="LC3" class="line" lang="plaintext"> - baz</span>
-<span id="LC4" class="line" lang="plaintext"> - boo</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;li&gt;baz&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;boo&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4531:1-4531:52" dir="auto">Here we need four, because the list marker is wider:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4533:1-4544:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">10) foo</span>
-<span id="LC2" class="line" lang="plaintext"> - bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;ol start="10"&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;li&gt;foo</span>
-<span id="LC6" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4547:1-4547:20" dir="auto">Three is not enough:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4549:1-4559:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">10) foo</span>
-<span id="LC2" class="line" lang="plaintext"> - bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;ol start="10"&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/ol&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4562:1-4562:45" dir="auto">A list may be the first block in a list item:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4564:1-4574:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- - foo</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC4" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4577:1-4591:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. - 2. foo</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC4" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;ol start="2"&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/ol&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4594:1-4594:34" dir="auto">A list item can contain a heading:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4596:1-4610:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- # Foo</span>
-<span id="LC2" class="line" lang="plaintext">- Bar</span>
-<span id="LC3" class="line" lang="plaintext"> ---</span>
-<span id="LC4" class="line" lang="plaintext"> baz</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;h2&gt;Bar&lt;/h2&gt;</span>
-<span id="LC12" class="line" lang="plaintext">baz&lt;/li&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h3 data-sourcepos="4613:1-4613:14" dir="auto">
-<a id="user-content-motivation" class="anchor" href="#motivation" aria-hidden="true"></a>Motivation</h3>
-<p data-sourcepos="4615:1-4615:64" dir="auto">John Gruber's Markdown spec says the following about list items:</p>
-<ol data-sourcepos="4617:1-4636:0" dir="auto">
-<li data-sourcepos="4617:1-4620:0">
-<p data-sourcepos="4617:4-4619:20">"List markers typically start at the left margin, but may be indented
-by up to three spaces. List markers must be followed by one or more
-spaces or a tab."</p>
-</li>
-<li data-sourcepos="4621:1-4623:0">
-<p data-sourcepos="4621:4-4622:48">"To make lists look nice, you can wrap items with hanging indents....
-But if you don't want to, you don't have to."</p>
-</li>
-<li data-sourcepos="4624:1-4627:0">
-<p data-sourcepos="4624:4-4626:8">"List items may consist of multiple paragraphs. Each subsequent
-paragraph in a list item must be indented by either 4 spaces or one
-tab."</p>
-</li>
-<li data-sourcepos="4628:1-4630:0">
-<p data-sourcepos="4628:4-4629:55">"It looks nice if you indent every line of the subsequent paragraphs,
-but here again, Markdown will allow you to be lazy."</p>
-</li>
-<li data-sourcepos="4631:1-4633:0">
-<p data-sourcepos="4631:4-4632:35">"To put a blockquote within a list item, the blockquote's <code>&gt;</code>
-delimiters need to be indented."</p>
-</li>
-<li data-sourcepos="4634:1-4636:0">
-<p data-sourcepos="4634:4-4635:44">"To put a code block within a list item, the code block needs to be
-indented twice — 8 spaces or two tabs."</p>
-</li>
-</ol>
-<p data-sourcepos="4637:1-4646:18" dir="auto">These rules specify that a paragraph under a list item must be indented
-four spaces (presumably, from the left margin, rather than the start of
-the list marker, but this is not said), and that code under a list item
-must be indented eight spaces instead of the usual four. They also say
-that a block quote must be indented, but not by how much; however, the
-example given has four spaces indentation. Although nothing is said
-about other kinds of block-level content, it is certainly reasonable to
-infer that <em>all</em> block elements under a list item, including other
-lists, must be indented four spaces. This principle has been called the
-<em>four-space rule</em>.</p>
-<p data-sourcepos="4648:1-4659:48" dir="auto">The four-space rule is clear and principled, and if the reference
-implementation <code>Markdown.pl</code> had followed it, it probably would have
-become the standard. However, <code>Markdown.pl</code> allowed paragraphs and
-sublists to start with only two spaces indentation, at least on the
-outer level. Worse, its behavior was inconsistent: a sublist of an
-outer-level list needed two spaces indentation, but a sublist of this
-sublist needed three spaces. It is not surprising, then, that different
-implementations of Markdown have developed very different rules for
-determining what comes under a list item. (Pandoc and python-Markdown,
-for example, stuck with Gruber's syntax description and the four-space
-rule, while discount, redcarpet, marked, PHP Markdown, and others
-followed <code>Markdown.pl</code>'s behavior more closely.)</p>
-<p data-sourcepos="4661:1-4666:45" dir="auto">Unfortunately, given the divergences between implementations, there
-is no way to give a spec for list items that will be guaranteed not
-to break any existing documents. However, the spec given here should
-correctly handle lists formatted with either the four-space rule or
-the more forgiving <code>Markdown.pl</code> behavior, provided they are laid out
-in a way that is natural for a human to read.</p>
-<p data-sourcepos="4668:1-4674:22" dir="auto">The strategy here is to let the width and indentation of the list marker
-determine the indentation necessary for blocks to fall under the list
-item, rather than having a fixed and arbitrary number. The writer can
-think of the body of the list item as a unit which gets indented to the
-right enough to fit the list marker (and any indentation on the list
-marker). (The laziness rule, #5, then allows continuation lines to be
-unindented if needed.)</p>
-<p data-sourcepos="4676:1-4678:39" dir="auto">This rule is superior, we claim, to any rule requiring a fixed level of
-indentation from the margin. The four-space rule is clear but
-unnatural. It is quite unintuitive that</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4680:1-4686:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="p">-</span> foo</span>
-<span id="LC2" class="line" lang="markdown"></span>
-<span id="LC3" class="line" lang="markdown"> bar</span>
-<span id="LC4" class="line" lang="markdown"></span>
-<span id="LC5" class="line" lang="markdown"><span class="p"> -</span> baz</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4688:1-4688:60" dir="auto">should be parsed as two lists with an intervening paragraph,</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4690:1-4698:3" class="code highlight js-syntax-highlight language-html" lang="html" v-pre="true"><code><span id="LC1" class="line" lang="html"><span class="nt">&lt;ul&gt;</span></span>
-<span id="LC2" class="line" lang="html"><span class="nt">&lt;li&gt;</span>foo<span class="nt">&lt;/li&gt;</span></span>
-<span id="LC3" class="line" lang="html"><span class="nt">&lt;/ul&gt;</span></span>
-<span id="LC4" class="line" lang="html"><span class="nt">&lt;p&gt;</span>bar<span class="nt">&lt;/p&gt;</span></span>
-<span id="LC5" class="line" lang="html"><span class="nt">&lt;ul&gt;</span></span>
-<span id="LC6" class="line" lang="html"><span class="nt">&lt;li&gt;</span>baz<span class="nt">&lt;/li&gt;</span></span>
-<span id="LC7" class="line" lang="html"><span class="nt">&lt;/ul&gt;</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4700:1-4700:58" dir="auto">as the four-space rule demands, rather than a single list,</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4702:1-4712:3" class="code highlight js-syntax-highlight language-html" lang="html" v-pre="true"><code><span id="LC1" class="line" lang="html"><span class="nt">&lt;ul&gt;</span></span>
-<span id="LC2" class="line" lang="html"><span class="nt">&lt;li&gt;</span></span>
-<span id="LC3" class="line" lang="html"><span class="nt">&lt;p&gt;</span>foo<span class="nt">&lt;/p&gt;</span></span>
-<span id="LC4" class="line" lang="html"><span class="nt">&lt;p&gt;</span>bar<span class="nt">&lt;/p&gt;</span></span>
-<span id="LC5" class="line" lang="html"><span class="nt">&lt;ul&gt;</span></span>
-<span id="LC6" class="line" lang="html"><span class="nt">&lt;li&gt;</span>baz<span class="nt">&lt;/li&gt;</span></span>
-<span id="LC7" class="line" lang="html"><span class="nt">&lt;/ul&gt;</span></span>
-<span id="LC8" class="line" lang="html"><span class="nt">&lt;/li&gt;</span></span>
-<span id="LC9" class="line" lang="html"><span class="nt">&lt;/ul&gt;</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4714:1-4715:62" dir="auto">The choice of four spaces is arbitrary. It can be learned, but it is
-not likely to be guessed, and it trips up beginners regularly.</p>
-<p data-sourcepos="4717:1-4721:20" dir="auto">Would it help to adopt a two-space rule? The problem is that such
-a rule, together with the rule allowing 1--3 spaces indentation of the
-initial list marker, allows text that is indented <em>less than</em> the
-original list marker to be included in the list item. For example,
-<code>Markdown.pl</code> parses</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4723:1-4727:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="p"> -</span> one</span>
-<span id="LC2" class="line" lang="markdown"></span>
-<span id="LC3" class="line" lang="markdown"> two</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4729:1-4729:59" dir="auto">as a single list item, with <code>two</code> a continuation paragraph:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4731:1-4738:3" class="code highlight js-syntax-highlight language-html" lang="html" v-pre="true"><code><span id="LC1" class="line" lang="html"><span class="nt">&lt;ul&gt;</span></span>
-<span id="LC2" class="line" lang="html"><span class="nt">&lt;li&gt;</span></span>
-<span id="LC3" class="line" lang="html"><span class="nt">&lt;p&gt;</span>one<span class="nt">&lt;/p&gt;</span></span>
-<span id="LC4" class="line" lang="html"><span class="nt">&lt;p&gt;</span>two<span class="nt">&lt;/p&gt;</span></span>
-<span id="LC5" class="line" lang="html"><span class="nt">&lt;/li&gt;</span></span>
-<span id="LC6" class="line" lang="html"><span class="nt">&lt;/ul&gt;</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4740:1-4740:13" dir="auto">and similarly</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4742:1-4746:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="gt">&gt; - one</span></span>
-<span id="LC2" class="line" lang="markdown"><span class="gt">&gt;</span></span>
-<span id="LC3" class="line" lang="markdown"><span class="gt">&gt; two</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4748:1-4748:2" dir="auto">as</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4750:1-4759:3" class="code highlight js-syntax-highlight language-html" lang="html" v-pre="true"><code><span id="LC1" class="line" lang="html"><span class="nt">&lt;blockquote&gt;</span></span>
-<span id="LC2" class="line" lang="html"><span class="nt">&lt;ul&gt;</span></span>
-<span id="LC3" class="line" lang="html"><span class="nt">&lt;li&gt;</span></span>
-<span id="LC4" class="line" lang="html"><span class="nt">&lt;p&gt;</span>one<span class="nt">&lt;/p&gt;</span></span>
-<span id="LC5" class="line" lang="html"><span class="nt">&lt;p&gt;</span>two<span class="nt">&lt;/p&gt;</span></span>
-<span id="LC6" class="line" lang="html"><span class="nt">&lt;/li&gt;</span></span>
-<span id="LC7" class="line" lang="html"><span class="nt">&lt;/ul&gt;</span></span>
-<span id="LC8" class="line" lang="html"><span class="nt">&lt;/blockquote&gt;</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4761:1-4761:30" dir="auto">This is extremely unintuitive.</p>
-<p data-sourcepos="4763:1-4768:52" dir="auto">Rather than requiring a fixed indent from the margin, we could require
-a fixed indent (say, two spaces, or even one space) from the list marker (which
-may itself be indented). This proposal would remove the last anomaly
-discussed. Unlike the spec presented above, it would count the following
-as a list item with a subparagraph, even though the paragraph <code>bar</code>
-is not indented as far as the first paragraph <code>foo</code>:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4770:1-4774:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="p"> 10.</span> foo</span>
-<span id="LC2" class="line" lang="markdown"></span>
-<span id="LC3" class="line" lang="markdown"> bar </span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4776:1-4779:62" dir="auto">Arguably this text does read like a list item with <code>bar</code> as a subparagraph,
-which may count in favor of the proposal. However, on this proposal indented
-code would have to be indented six spaces after the list marker. And this
-would break a lot of existing Markdown, which has the pattern:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4781:1-4785:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="p">1.</span> foo</span>
-<span id="LC2" class="line" lang="markdown"></span>
-<span id="LC3" class="line" lang="markdown"><span class="sb"> indented code</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4787:1-4789:28" dir="auto">where the code is indented eight spaces. The spec above, by contrast, will
-parse this text as expected, since the code block's indentation is measured
-from the beginning of <code>foo</code>.</p>
-<p data-sourcepos="4791:1-4797:62" dir="auto">The one case that needs special treatment is a list item that <em>starts</em>
-with indented code. How much indentation is required in that case, since
-we don't have a "first paragraph" to measure from? Rule #2 simply stipulates
-that in such cases, we require one space indentation from the list marker
-(and then the normal four spaces for the indented code). This will match the
-four-space rule in cases where the list marker plus its initial indentation
-takes four spaces (a common case), but diverge in other cases.</p>
-<div>
-<h2 data-sourcepos="4801:1-4801:30">
-<a id="user-content-task-list-items-extension" class="anchor" href="#task-list-items-extension" aria-hidden="true"></a>Task list items (extension)</h2>
-<p data-sourcepos="4803:1-4804:26">GFM enables the <code>tasklist</code> extension, where an additional processing step is
-performed on [list items].</p>
-<p data-sourcepos="4806:1-4808:46">A <a href="@">task list item</a> is a [list item][list items] where the first block in it
-is a paragraph which begins with a [task list item marker] and at least one
-whitespace character before any other content.</p>
-<p data-sourcepos="4810:1-4812:55">A <a href="@">task list item marker</a> consists of an optional number of spaces, a left
-bracket (<code>[</code>), either a whitespace character or the letter <code>x</code> in either
-lowercase or uppercase, and then a right bracket (<code>]</code>).</p>
-<p data-sourcepos="4814:1-4815:70">When rendered, the [task list item marker] is replaced with a semantic checkbox element;
-in an HTML output, this would be an <code>&lt;input type="checkbox"&gt;</code> element.</p>
-<p data-sourcepos="4817:1-4818:50">If the character between the brackets is a whitespace character, the checkbox
-is unchecked. Otherwise, the checkbox is checked.</p>
-<p data-sourcepos="4820:1-4823:28">This spec does not define how the checkbox elements are interacted with: in practice,
-implementors are free to render the checkboxes as disabled or inmutable elements,
-or they may dynamically handle dynamic interactions (i.e. checking, unchecking) in
-the final rendered document.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4825:1-4833:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [ ] foo</span>
-<span id="LC2" class="line" lang="plaintext">- [x] bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; foo&lt;/li&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; bar&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4835:1-4835:37">Task lists can be arbitrarily nested:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4837:1-4852:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [x] foo</span>
-<span id="LC2" class="line" lang="plaintext"> - [ ] bar</span>
-<span id="LC3" class="line" lang="plaintext"> - [x] baz</span>
-<span id="LC4" class="line" lang="plaintext">- [ ] bim</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; foo</span>
-<span id="LC8" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; bar&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; baz&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; bim&lt;/li&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-</div>
-<h2 data-sourcepos="4856:1-4856:8" dir="auto">
-<a id="user-content-lists" class="anchor" href="#lists" aria-hidden="true"></a>Lists</h2>
-<p data-sourcepos="4858:1-4860:46" dir="auto">A <a href="@">list</a> is a sequence of one or more
-list items [of the same type]. The list items
-may be separated by any number of blank lines.</p>
-<p data-sourcepos="4862:1-4867:30" dir="auto">Two list items are <a href="@">of the same type</a>
-if they begin with a [list marker] of the same type.
-Two list markers are of the
-same type if (a) they are bullet list markers using the same character
-(<code>-</code>, <code>+</code>, or <code>*</code>) or (b) they are ordered list numbers with the same
-delimiter (either <code>.</code> or <code>)</code>).</p>
-<p data-sourcepos="4869:1-4873:39" dir="auto">A list is an <a href="@">ordered list</a>
-if its constituent list items begin with
-[ordered list markers], and a
-<a href="@">bullet list</a> if its constituent list
-items begin with [bullet list markers].</p>
-<p data-sourcepos="4875:1-4878:12" dir="auto">The <a href="@">start number</a>
-of an [ordered list] is determined by the list number of
-its initial list item. The numbers of subsequent list items are
-disregarded.</p>
-<p data-sourcepos="4880:1-4885:65" dir="auto">A list is <a href="@">loose</a> if any of its constituent
-list items are separated by blank lines, or if any of its constituent
-list items directly contain two block-level elements with a blank line
-between them. Otherwise a list is <a href="@">tight</a>.
-(The difference in HTML output is that paragraphs in a loose list are
-wrapped in <code>&lt;p&gt;</code> tags, while paragraphs in a tight list are not.)</p>
-<p data-sourcepos="4887:1-4887:64" dir="auto">Changing the bullet or ordered list delimiter starts a new list:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4889:1-4901:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext">- bar</span>
-<span id="LC3" class="line" lang="plaintext">+ baz</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;baz&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4904:1-4916:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. foo</span>
-<span id="LC2" class="line" lang="plaintext">2. bar</span>
-<span id="LC3" class="line" lang="plaintext">3) baz</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/ol&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;ol start="3"&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;baz&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4919:1-4921:5" dir="auto">In CommonMark, a list can interrupt a paragraph. That is,
-no blank line is needed to separate a paragraph from a following
-list:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4923:1-4933:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
-<span id="LC2" class="line" lang="plaintext">- bar</span>
-<span id="LC3" class="line" lang="plaintext">- baz</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;Foo&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;baz&lt;/li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4935:1-4936:37" dir="auto"><code>Markdown.pl</code> does not allow this, through fear of triggering a list
-via a numeral in a hard-wrapped line:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4938:1-4941:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown">The number of windows in my house is</span>
-<span id="LC2" class="line" lang="markdown"><span class="p">14.</span> The number of doors is 6.</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4943:1-4945:6" dir="auto">Oddly, though, <code>Markdown.pl</code> <em>does</em> allow a blockquote to
-interrupt a paragraph, even though the same considerations might
-apply.</p>
-<p data-sourcepos="4947:1-4949:35" dir="auto">In CommonMark, we do allow lists to interrupt paragraphs, for
-two reasons. First, it is natural and not uncommon for people
-to start lists without blank lines:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4951:1-4956:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown">I need to buy</span>
-<span id="LC2" class="line" lang="markdown"><span class="p">-</span> new shoes</span>
-<span id="LC3" class="line" lang="markdown"><span class="p">-</span> a coat</span>
-<span id="LC4" class="line" lang="markdown"><span class="p">-</span> a plane ticket</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4958:1-4958:29" dir="auto">Second, we are attracted to a</p>
-<blockquote data-sourcepos="4960:1-4963:54" dir="auto">
-<p data-sourcepos="4960:3-4963:54"><a href="@">principle of uniformity</a>:
-if a chunk of text has a certain
-meaning, it will continue to have the same meaning when put into a
-container block (such as a list item or blockquote).</p>
-</blockquote>
-<p data-sourcepos="4965:1-4966:47" dir="auto">(Indeed, the spec for [list items] and [block quotes] presupposes
-this principle.) This principle implies that if</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4968:1-4973:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="p"> *</span> I need to buy</span>
-<span id="LC2" class="line" lang="markdown"><span class="p"> -</span> new shoes</span>
-<span id="LC3" class="line" lang="markdown"><span class="p"> -</span> a coat</span>
-<span id="LC4" class="line" lang="markdown"><span class="p"> -</span> a plane ticket</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4975:1-4978:4" dir="auto">is a list item containing a paragraph followed by a nested sublist,
-as all Markdown implementations agree it is (though the paragraph
-may be rendered without <code>&lt;p&gt;</code> tags, since the list is "tight"),
-then</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="4980:1-4985:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown">I need to buy</span>
-<span id="LC2" class="line" lang="markdown"><span class="p">-</span> new shoes</span>
-<span id="LC3" class="line" lang="markdown"><span class="p">-</span> a coat</span>
-<span id="LC4" class="line" lang="markdown"><span class="p">-</span> a plane ticket</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="4987:1-4987:61" dir="auto">by itself should be a paragraph followed by a nested sublist.</p>
-<p data-sourcepos="4989:1-4994:30" dir="auto">Since it is well established Markdown practice to allow lists to
-interrupt paragraphs inside list items, the [principle of
-uniformity] requires us to allow this outside list items as
-well. (<a href="http://docutils.sourceforge.net/rst.html" rel="nofollow noreferrer noopener" target="_blank">reStructuredText</a>
-takes a different approach, requiring blank lines before lists
-even inside other list items.)</p>
-<p data-sourcepos="4996:1-4998:28" dir="auto">In order to solve of unwanted lists in paragraphs with
-hard-wrapped numerals, we allow only lists starting with <code>1</code> to
-interrupt paragraphs. Thus,</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5000:1-5006:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">The number of windows in my house is</span>
-<span id="LC2" class="line" lang="plaintext">14. The number of doors is 6.</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;The number of windows in my house is</span>
-<span id="LC5" class="line" lang="plaintext">14. The number of doors is 6.&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5008:1-5008:51" dir="auto">We may still get an unintended result in cases like</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5010:1-5018:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">The number of windows in my house is</span>
-<span id="LC2" class="line" lang="plaintext">1. The number of doors is 6.</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;The number of windows in my house is&lt;/p&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;The number of doors is 6.&lt;/li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5020:1-5020:57" dir="auto">but this rule should prevent most spurious list captures.</p>
-<p data-sourcepos="5022:1-5022:53" dir="auto">There can be any number of blank lines between items:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5024:1-5043:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">- bar</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext">- baz</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5045:1-5067:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext"> - bar</span>
-<span id="LC3" class="line" lang="plaintext"> - baz</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext"> bim</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;li&gt;foo</span>
-<span id="LC10" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;li&gt;bar</span>
-<span id="LC12" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;p&gt;bim&lt;/p&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC19" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC20" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC21" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5070:1-5073:8" dir="auto">To separate consecutive lists of the same type, or to separate a
-list from an indented code block that would otherwise be parsed
-as a subparagraph of the final list item, you can insert a blank HTML
-comment:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5075:1-5093:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext">- bar</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">&lt;!-- --&gt;</span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext">- baz</span>
-<span id="LC7" class="line" lang="plaintext">- bim</span>
-<span id="LC8" class="line" lang="plaintext">.</span>
-<span id="LC9" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;!-- --&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;li&gt;baz&lt;/li&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;li&gt;bim&lt;/li&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5096:1-5119:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> notcode</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">- foo</span>
-<span id="LC6" class="line" lang="plaintext"></span>
-<span id="LC7" class="line" lang="plaintext">&lt;!-- --&gt;</span>
-<span id="LC8" class="line" lang="plaintext"></span>
-<span id="LC9" class="line" lang="plaintext"> code</span>
-<span id="LC10" class="line" lang="plaintext">.</span>
-<span id="LC11" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;p&gt;notcode&lt;/p&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC19" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC20" class="line" lang="plaintext">&lt;!-- --&gt;</span>
-<span id="LC21" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;code</span>
-<span id="LC22" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5122:1-5125:5" dir="auto">List items need not be indented to the same level. The following
-list items will be treated as items at the same list level,
-since none is indented enough to belong to the previous list
-item:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5127:1-5145:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
-<span id="LC2" class="line" lang="plaintext"> - b</span>
-<span id="LC3" class="line" lang="plaintext"> - c</span>
-<span id="LC4" class="line" lang="plaintext"> - d</span>
-<span id="LC5" class="line" lang="plaintext"> - e</span>
-<span id="LC6" class="line" lang="plaintext"> - f</span>
-<span id="LC7" class="line" lang="plaintext">- g</span>
-<span id="LC8" class="line" lang="plaintext">.</span>
-<span id="LC9" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;a&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;li&gt;b&lt;/li&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;li&gt;c&lt;/li&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;li&gt;d&lt;/li&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;li&gt;e&lt;/li&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;li&gt;f&lt;/li&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;li&gt;g&lt;/li&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5148:1-5166:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. a</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> 2. b</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext"> 3. c</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;a&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;p&gt;c&lt;/p&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5168:1-5170:52" dir="auto">Note, however, that list items may not be indented more than
-three spaces. Here <code>- e</code> is treated as a paragraph continuation
-line, because it is indented more than three spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5172:1-5186:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
-<span id="LC2" class="line" lang="plaintext"> - b</span>
-<span id="LC3" class="line" lang="plaintext"> - c</span>
-<span id="LC4" class="line" lang="plaintext"> - d</span>
-<span id="LC5" class="line" lang="plaintext"> - e</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;a&lt;/li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;li&gt;b&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;c&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;li&gt;d</span>
-<span id="LC12" class="line" lang="plaintext">- e&lt;/li&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5188:1-5190:11" dir="auto">And here, <code>3. c</code> is treated as in indented code block,
-because it is indented four spaces and preceded by a
-blank line.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5192:1-5209:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. a</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> 2. b</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext"> 3. c</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;a&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/ol&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;3. c</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5212:1-5213:22" dir="auto">This is a loose list, because there is a blank line between
-two of the list items:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5215:1-5232:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
-<span id="LC2" class="line" lang="plaintext">- b</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">- c</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;a&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;p&gt;c&lt;/p&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5235:1-5235:37" dir="auto">So is this, with a empty second item:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5237:1-5252:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">* a</span>
-<span id="LC2" class="line" lang="plaintext">*</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">* c</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;a&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;p&gt;c&lt;/p&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5255:1-5257:31" dir="auto">These are loose lists, even though there is no space between the items,
-because one of the items directly contains two block-level elements
-with a blank line between them:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5259:1-5278:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
-<span id="LC2" class="line" lang="plaintext">- b</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext"> c</span>
-<span id="LC5" class="line" lang="plaintext">- d</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;a&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;p&gt;c&lt;/p&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;p&gt;d&lt;/p&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5281:1-5299:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
-<span id="LC2" class="line" lang="plaintext">- b</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext"> [ref]: /url</span>
-<span id="LC5" class="line" lang="plaintext">- d</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;a&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;p&gt;d&lt;/p&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5302:1-5302:66" dir="auto">This is a tight list, because the blank lines are in a code block:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5304:1-5323:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
-<span id="LC2" class="line" lang="plaintext">- ```</span>
-<span id="LC3" class="line" lang="plaintext"> b</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext"></span>
-<span id="LC6" class="line" lang="plaintext"> ```</span>
-<span id="LC7" class="line" lang="plaintext">- c</span>
-<span id="LC8" class="line" lang="plaintext">.</span>
-<span id="LC9" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;a&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;b</span>
-<span id="LC13" class="line" lang="plaintext"></span>
-<span id="LC14" class="line" lang="plaintext"></span>
-<span id="LC15" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;li&gt;c&lt;/li&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5326:1-5328:24" dir="auto">This is a tight list, because the blank line is between two
-paragraphs of a sublist. So the sublist is loose while
-the outer list is tight:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5330:1-5348:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
-<span id="LC2" class="line" lang="plaintext"> - b</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext"> c</span>
-<span id="LC5" class="line" lang="plaintext">- d</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;a</span>
-<span id="LC9" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;p&gt;c&lt;/p&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;li&gt;d&lt;/li&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5351:1-5352:12" dir="auto">This is a tight list, because the blank line is inside the
-block quote:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5354:1-5368:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">* a</span>
-<span id="LC2" class="line" lang="plaintext"> &gt; b</span>
-<span id="LC3" class="line" lang="plaintext"> &gt;</span>
-<span id="LC4" class="line" lang="plaintext">* c</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;a</span>
-<span id="LC8" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;li&gt;c&lt;/li&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5371:1-5372:33" dir="auto">This list is tight, because the consecutive block elements
-are not separated by blank lines:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5374:1-5392:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
-<span id="LC2" class="line" lang="plaintext"> &gt; b</span>
-<span id="LC3" class="line" lang="plaintext"> ```</span>
-<span id="LC4" class="line" lang="plaintext"> c</span>
-<span id="LC5" class="line" lang="plaintext"> ```</span>
-<span id="LC6" class="line" lang="plaintext">- d</span>
-<span id="LC7" class="line" lang="plaintext">.</span>
-<span id="LC8" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;li&gt;a</span>
-<span id="LC10" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;c</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;li&gt;d&lt;/li&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5395:1-5395:33" dir="auto">A single-paragraph list is tight:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5397:1-5403:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC4" class="line" lang="plaintext">&lt;li&gt;a&lt;/li&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5406:1-5417:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
-<span id="LC2" class="line" lang="plaintext"> - b</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;li&gt;a</span>
-<span id="LC6" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;b&lt;/li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5420:1-5421:36" dir="auto">This list is loose, because of the blank line between the
-two block elements in the list item:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5423:1-5437:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. ```</span>
-<span id="LC2" class="line" lang="plaintext"> foo</span>
-<span id="LC3" class="line" lang="plaintext"> ```</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext"> bar</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5440:1-5440:51" dir="auto">Here the outer list is loose, the inner list tight:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5442:1-5457:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">* foo</span>
-<span id="LC2" class="line" lang="plaintext"> * bar</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext"> baz</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5460:1-5485:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
-<span id="LC2" class="line" lang="plaintext"> - b</span>
-<span id="LC3" class="line" lang="plaintext"> - c</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">- d</span>
-<span id="LC6" class="line" lang="plaintext"> - e</span>
-<span id="LC7" class="line" lang="plaintext"> - f</span>
-<span id="LC8" class="line" lang="plaintext">.</span>
-<span id="LC9" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;p&gt;a&lt;/p&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;li&gt;b&lt;/li&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;li&gt;c&lt;/li&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;p&gt;d&lt;/p&gt;</span>
-<span id="LC19" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC20" class="line" lang="plaintext">&lt;li&gt;e&lt;/li&gt;</span>
-<span id="LC21" class="line" lang="plaintext">&lt;li&gt;f&lt;/li&gt;</span>
-<span id="LC22" class="line" lang="plaintext">&lt;/ul&gt;</span>
-<span id="LC23" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC24" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h1 data-sourcepos="5488:1-5488:9" dir="auto">
-<a id="user-content-inlines" class="anchor" href="#inlines" aria-hidden="true"></a>Inlines</h1>
-<p data-sourcepos="5490:1-5492:21" dir="auto">Inlines are parsed sequentially from the beginning of the character
-stream to the end (left to right, in left-to-right languages).
-Thus, for example, in</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5494:1-5498:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`hi`lo`</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;hi&lt;/code&gt;lo`&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5500:1-5501:9" dir="auto"><code>hi</code> is parsed as code, leaving the backtick at the end as a literal
-backtick.</p>
-<h2 data-sourcepos="5504:1-5504:20" dir="auto">
-<a id="user-content-backslash-escapes" class="anchor" href="#backslash-escapes" aria-hidden="true"></a>Backslash escapes</h2>
-<p data-sourcepos="5506:1-5506:57" dir="auto">Any ASCII punctuation character may be backslash-escaped:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5508:1-5512:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\!\"\#\$\%\&amp;\'\(\)\*\+\,\-\.\/\:\;\&lt;\=\&gt;\?\@\[\\\]\^\_\`\{\|\}\~</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;!&amp;quot;#$%&amp;amp;'()*+,-./:;&amp;lt;=&amp;gt;?@[\]^_`{|}~&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5515:1-5516:12" dir="auto">Backslashes before other characters are treated as literal
-backslashes:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5518:1-5522:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\→\A\a\ \3\φ\«</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;\→\A\a\ \3\φ\«&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5525:1-5526:39" dir="auto">Escaped characters are treated as regular characters and do
-not have their usual Markdown meanings:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5528:1-5548:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\*not emphasized*</span>
-<span id="LC2" class="line" lang="plaintext">\&lt;br/&gt; not a tag</span>
-<span id="LC3" class="line" lang="plaintext">\[not a link](/foo)</span>
-<span id="LC4" class="line" lang="plaintext">\`not code`</span>
-<span id="LC5" class="line" lang="plaintext">1\. not a list</span>
-<span id="LC6" class="line" lang="plaintext">\* not a list</span>
-<span id="LC7" class="line" lang="plaintext">\# not a heading</span>
-<span id="LC8" class="line" lang="plaintext">\[foo]: /url "not a reference"</span>
-<span id="LC9" class="line" lang="plaintext">\&amp;ouml; not a character entity</span>
-<span id="LC10" class="line" lang="plaintext">.</span>
-<span id="LC11" class="line" lang="plaintext">&lt;p&gt;*not emphasized*</span>
-<span id="LC12" class="line" lang="plaintext">&amp;lt;br/&amp;gt; not a tag</span>
-<span id="LC13" class="line" lang="plaintext">[not a link](/foo)</span>
-<span id="LC14" class="line" lang="plaintext">`not code`</span>
-<span id="LC15" class="line" lang="plaintext">1. not a list</span>
-<span id="LC16" class="line" lang="plaintext">* not a list</span>
-<span id="LC17" class="line" lang="plaintext"># not a heading</span>
-<span id="LC18" class="line" lang="plaintext">[foo]: /url &amp;quot;not a reference&amp;quot;</span>
-<span id="LC19" class="line" lang="plaintext">&amp;amp;ouml; not a character entity&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5551:1-5551:65" dir="auto">If a backslash is itself escaped, the following character is not:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5553:1-5557:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\\*emphasis*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;\&lt;em&gt;emphasis&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5560:1-5560:58" dir="auto">A backslash at the end of the line is a [hard line break]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5562:1-5568:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo\</span>
-<span id="LC2" class="line" lang="plaintext">bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;foo&lt;br /&gt;</span>
-<span id="LC5" class="line" lang="plaintext">bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5571:1-5572:9" dir="auto">Backslash escapes do not work in code blocks, code spans, autolinks, or
-raw HTML:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5574:1-5578:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`` \[\` ``</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;\[\`&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5581:1-5586:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> \[\]</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;\[\]</span>
-<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5589:1-5596:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~~</span>
-<span id="LC2" class="line" lang="plaintext">\[\]</span>
-<span id="LC3" class="line" lang="plaintext">~~~</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;\[\]</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5599:1-5603:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;http://example.com?find=\*&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://example.com?find=%5C*"&gt;http://example.com?find=\*&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5606:1-5610:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="/bar\/)"&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;a href="/bar\/)"&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5613:1-5614:60" dir="auto">But they work in all other contexts, including URLs and link titles,
-link references, and [info strings] in [fenced code blocks]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5616:1-5620:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo](/bar\* "ti\*tle")</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/bar*" title="ti*tle"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5623:1-5629:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /bar\* "ti\*tle"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/bar*" title="ti*tle"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5632:1-5639:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``` foo\+bar</span>
-<span id="LC2" class="line" lang="plaintext">foo</span>
-<span id="LC3" class="line" lang="plaintext">```</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code class="language-foo+bar"&gt;foo</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="5643:1-5643:42" dir="auto">
-<a id="user-content-entity-and-numeric-character-references" class="anchor" href="#entity-and-numeric-character-references" aria-hidden="true"></a>Entity and numeric character references</h2>
-<p data-sourcepos="5645:1-5647:30" dir="auto">Valid HTML entity references and numeric character references
-can be used in place of the corresponding Unicode character,
-with the following exceptions:</p>
-<ul data-sourcepos="5649:1-5658:0" dir="auto">
-<li data-sourcepos="5649:1-5651:0">
-<p data-sourcepos="5649:3-5650:24">Entity and character references are not recognized in code
-blocks and code spans.</p>
-</li>
-<li data-sourcepos="5652:1-5658:0">
-<p data-sourcepos="5652:3-5657:9">Entity and character references cannot stand in place of
-special characters that define structural elements in
-CommonMark. For example, although <code>&amp;#42;</code> can be used
-in place of a literal <code>*</code> character, <code>&amp;#42;</code> cannot replace
-<code>*</code> in emphasis delimiters, bullet list markers, or thematic
-breaks.</p>
-</li>
-</ul>
-<p data-sourcepos="5659:1-5661:49" dir="auto">Conforming CommonMark parsers need not store information about
-whether a particular character was represented in the source
-using a Unicode character or an entity reference.</p>
-<p data-sourcepos="5663:1-5667:47" dir="auto"><a href="@">Entity references</a> consist of <code>&amp;</code> + any of the valid
-HTML5 entity names + <code>;</code>. The
-document <a href="https://html.spec.whatwg.org/multipage/entities.json" rel="nofollow noreferrer noopener" target="_blank">https://html.spec.whatwg.org/multipage/entities.json</a>
-is used as an authoritative source for the valid entity
-references and their corresponding code points.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5669:1-5677:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;nbsp; &amp;amp; &amp;copy; &amp;AElig; &amp;Dcaron;</span>
-<span id="LC2" class="line" lang="plaintext">&amp;frac34; &amp;HilbertSpace; &amp;DifferentialD;</span>
-<span id="LC3" class="line" lang="plaintext">&amp;ClockwiseContourIntegral; &amp;ngE;</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;  &amp;amp; © Æ Ď</span>
-<span id="LC6" class="line" lang="plaintext">¾ ℋ ⅆ</span>
-<span id="LC7" class="line" lang="plaintext">∲ ≧̸&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5680:1-5686:58" dir="auto"><a href="@">Decimal numeric character
-references</a>
-consist of <code>&amp;#</code> + a string of 1--7 arabic digits + <code>;</code>. A
-numeric character reference is parsed as the corresponding
-Unicode character. Invalid Unicode code points will be replaced by
-the REPLACEMENT CHARACTER (<code>U+FFFD</code>). For security reasons,
-the code point <code>U+0000</code> will also be replaced by <code>U+FFFD</code>.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5688:1-5692:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;#35; &amp;#1234; &amp;#992; &amp;#0;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;# Ӓ Ϡ �&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5695:1-5699:62" dir="auto"><a href="@">Hexadecimal numeric character
-references</a> consist of <code>&amp;#</code> +
-either <code>X</code> or <code>x</code> + a string of 1-6 hexadecimal digits + <code>;</code>.
-They too are parsed as the corresponding Unicode character (this
-time specified with a hexadecimal numeral instead of decimal).</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5701:1-5705:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;#X22; &amp;#XD06; &amp;#xcab;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&amp;quot; ആ ಫ&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5708:1-5708:26" dir="auto">Here are some nonentities:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5710:1-5720:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;nbsp &amp;x; &amp;#; &amp;#x;</span>
-<span id="LC2" class="line" lang="plaintext">&amp;#987654321;</span>
-<span id="LC3" class="line" lang="plaintext">&amp;#abcdef0;</span>
-<span id="LC4" class="line" lang="plaintext">&amp;ThisIsNotDefined; &amp;hi?;</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;&amp;amp;nbsp &amp;amp;x; &amp;amp;#; &amp;amp;#x;</span>
-<span id="LC7" class="line" lang="plaintext">&amp;amp;#987654321;</span>
-<span id="LC8" class="line" lang="plaintext">&amp;amp;#abcdef0;</span>
-<span id="LC9" class="line" lang="plaintext">&amp;amp;ThisIsNotDefined; &amp;amp;hi?;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5723:1-5725:60" dir="auto">Although HTML5 does accept some entity references
-without a trailing semicolon (such as <code>&amp;copy</code>), these are not
-recognized here, because it makes the grammar too ambiguous:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5727:1-5731:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;copy</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&amp;amp;copy&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5734:1-5735:39" dir="auto">Strings that are not on the list of HTML5 named entities are not
-recognized as entity references either:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5737:1-5741:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;MadeUpEntity;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&amp;amp;MadeUpEntity;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5744:1-5746:62" dir="auto">Entity and numeric character references are recognized in any
-context besides code spans or code blocks, including
-URLs, [link titles], and [fenced code block][] [info strings]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5748:1-5752:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="&amp;ouml;&amp;ouml;.html"&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;a href="&amp;ouml;&amp;ouml;.html"&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5755:1-5759:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo](/f&amp;ouml;&amp;ouml; "f&amp;ouml;&amp;ouml;")</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/f%C3%B6%C3%B6" title="föö"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5762:1-5768:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /f&amp;ouml;&amp;ouml; "f&amp;ouml;&amp;ouml;"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/f%C3%B6%C3%B6" title="föö"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5771:1-5778:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``` f&amp;ouml;&amp;ouml;</span>
-<span id="LC2" class="line" lang="plaintext">foo</span>
-<span id="LC3" class="line" lang="plaintext">```</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code class="language-föö"&gt;foo</span>
-<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5781:1-5782:35" dir="auto">Entity and numeric character references are treated as literal
-text in code spans and code blocks:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5784:1-5788:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`f&amp;ouml;&amp;ouml;`</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;f&amp;amp;ouml;&amp;amp;ouml;&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5791:1-5796:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> f&amp;ouml;f&amp;ouml;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;f&amp;amp;ouml;f&amp;amp;ouml;</span>
-<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5799:1-5801:10" dir="auto">Entity and numeric character references cannot be used
-in place of symbols indicating structure in CommonMark
-documents.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5803:1-5809:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;#42;foo&amp;#42;</span>
-<span id="LC2" class="line" lang="plaintext">*foo*</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;*foo*</span>
-<span id="LC5" class="line" lang="plaintext">&lt;em&gt;foo&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5811:1-5820:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;#42; foo</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">* foo</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;* foo&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5822:1-5828:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo&amp;#10;&amp;#10;bar</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5830:1-5834:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;#9;foo</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;→foo&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5837:1-5841:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[a](url &amp;quot;tit&amp;quot;)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[a](url &amp;quot;tit&amp;quot;)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="5844:1-5844:13" dir="auto">
-<a id="user-content-code-spans" class="anchor" href="#code-spans" aria-hidden="true"></a>Code spans</h2>
-<p data-sourcepos="5846:1-5848:36" dir="auto">A <a href="@">backtick string</a>
-is a string of one or more backtick characters (<code>`</code>) that is neither
-preceded nor followed by a backtick.</p>
-<p data-sourcepos="5850:1-5853:15" dir="auto">A <a href="@">code span</a> begins with a backtick string and ends with
-a backtick string of equal length. The contents of the code span are
-the characters between the two backtick strings, normalized in the
-following ways:</p>
-<ul data-sourcepos="5855:1-5862:0" dir="auto">
-<li data-sourcepos="5855:1-5855:50">First, [line endings] are converted to [spaces].</li>
-<li data-sourcepos="5856:1-5862:0">If the resulting string both begins <em>and</em> ends with a [space]
-character, but does not consist entirely of [space]
-characters, a single [space] character is removed from the
-front and back. This allows you to include code that begins
-or ends with backtick characters, which must be separated by
-whitespace from the opening or closing backtick strings.</li>
-</ul>
-<p data-sourcepos="5863:1-5863:27" dir="auto">This is a simple code span:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5865:1-5869:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`foo`</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5872:1-5874:15" dir="auto">Here two backticks are used, because the code contains a backtick.
-This example also illustrates stripping of a single leading and
-trailing space:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5876:1-5880:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`` foo ` bar ``</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo ` bar&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5883:1-5884:7" dir="auto">This example shows the motivation for stripping leading and trailing
-spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5886:1-5890:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">` `` `</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;``&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5892:1-5892:39" dir="auto">Note that only <em>one</em> space is stripped:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5894:1-5898:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">` `` `</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt; `` &lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5900:1-5901:20" dir="auto">The stripping only happens if the space is on both
-sides of the string:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5903:1-5907:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">` a`</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt; a&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5909:1-5910:21" dir="auto">Only [spaces], and not [unicode whitespace] in general, are
-stripped in this way:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5912:1-5916:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">` b `</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt; b &lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5918:1-5918:58" dir="auto">No stripping occurs if the code span contains only spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5920:1-5926:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">` `</span>
-<span id="LC2" class="line" lang="plaintext">` `</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt; &lt;/code&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;code&gt; &lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5929:1-5929:39" dir="auto">[Line endings] are treated like spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5931:1-5939:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``</span>
-<span id="LC2" class="line" lang="plaintext">foo</span>
-<span id="LC3" class="line" lang="plaintext">bar </span>
-<span id="LC4" class="line" lang="plaintext">baz</span>
-<span id="LC5" class="line" lang="plaintext">``</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo bar baz&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5941:1-5947:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``</span>
-<span id="LC2" class="line" lang="plaintext">foo </span>
-<span id="LC3" class="line" lang="plaintext">``</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo &lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5950:1-5950:34" dir="auto">Interior spaces are not collapsed:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5952:1-5957:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`foo bar </span>
-<span id="LC2" class="line" lang="plaintext">baz`</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo bar baz&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5959:1-5961:26" dir="auto">Note that browsers will typically collapse consecutive spaces
-when rendering <code>&lt;code&gt;</code> elements, so it is recommended that
-the following CSS be used:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5963:5-5965:0" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">code{white-space: pre-wrap;}</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5966:1-5967:22" dir="auto">Note that backslash escapes do not work in code spans. All backslashes
-are treated literally:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5969:1-5973:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`foo\`bar`</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo\&lt;/code&gt;bar`&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5976:1-5978:59" dir="auto">Backslash escapes are never needed, because one can always choose a
-string of <em>n</em> backtick characters as delimiters, where the code does
-not contain any strings of exactly <em>n</em> backtick characters.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5980:1-5984:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``foo`bar``</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo`bar&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5986:1-5990:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">` foo `` bar `</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo `` bar&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="5993:1-5996:5" dir="auto">Code span backticks have higher precedence than any other inline
-constructs except HTML tags and autolinks. Thus, for example, this is
-not parsed as emphasized text, since the second <code>*</code> is part of a code
-span:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="5998:1-6002:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo`*`</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;*foo&lt;code&gt;*&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6005:1-6005:33" dir="auto">And this is not parsed as a link:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6007:1-6011:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[not a `link](/foo`)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[not a &lt;code&gt;link](/foo&lt;/code&gt;)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6014:1-6015:19" dir="auto">Code spans, HTML tags, and autolinks have the same precedence.
-Thus, this is code:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6017:1-6021:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`&lt;a href="`"&gt;`</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;&amp;lt;a href=&amp;quot;&lt;/code&gt;&amp;quot;&amp;gt;`&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6024:1-6024:24" dir="auto">But this is an HTML tag:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6026:1-6030:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="`"&gt;`</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="`"&gt;`&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6033:1-6033:17" dir="auto">And this is code:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6035:1-6039:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`&lt;http://foo.bar.`baz&gt;`</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;&amp;lt;http://foo.bar.&lt;/code&gt;baz&amp;gt;`&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6042:1-6042:24" dir="auto">But this is an autolink:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6044:1-6048:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;http://foo.bar.`baz&gt;`</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://foo.bar.%60baz"&gt;http://foo.bar.`baz&lt;/a&gt;`&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6051:1-6052:31" dir="auto">When a backtick string is not closed by a matching backtick string,
-we just have literal backticks:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6054:1-6058:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```foo``</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;```foo``&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6061:1-6065:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`foo</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;`foo&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6067:1-6068:47" dir="auto">The following case also illustrates the need for opening and
-closing backtick strings to be equal in length:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6070:1-6074:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`foo``bar``</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;`foo&lt;code&gt;bar&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="6077:1-6077:31" dir="auto">
-<a id="user-content-emphasis-and-strong-emphasis" class="anchor" href="#emphasis-and-strong-emphasis" aria-hidden="true"></a>Emphasis and strong emphasis</h2>
-<p data-sourcepos="6079:1-6080:73" dir="auto">John Gruber's original <a href="http://daringfireball.net/projects/markdown/syntax#em" rel="nofollow noreferrer noopener" target="_blank">Markdown syntax
-description</a> says:</p>
-<blockquote data-sourcepos="6082:1-6085:6" dir="auto">
-<p data-sourcepos="6082:3-6085:6">Markdown treats asterisks (<code>*</code>) and underscores (<code>_</code>) as indicators of
-emphasis. Text wrapped with one <code>*</code> or <code>_</code> will be wrapped with an HTML
-<code>&lt;em&gt;</code> tag; double <code>*</code>'s or <code>_</code>'s will be wrapped with an HTML <code>&lt;strong&gt;</code>
-tag.</p>
-</blockquote>
-<p data-sourcepos="6087:1-6091:57" dir="auto">This is enough for most users, but these rules leave much undecided,
-especially when it comes to nested emphasis. The original
-<code>Markdown.pl</code> test suite makes it clear that triple <code>***</code> and
-<code>___</code> delimiters can be used for strong emphasis, and most
-implementations have also allowed the following patterns:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6093:1-6099:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="gs">***strong emph**</span><span class="err">*</span></span>
-<span id="LC2" class="line" lang="markdown"><span class="gs">***strong**</span> in emph<span class="err">*</span></span>
-<span id="LC3" class="line" lang="markdown"><span class="gs">***emph* in strong**</span></span>
-<span id="LC4" class="line" lang="markdown"><span class="gs">**in strong *emph**</span><span class="err">*</span></span>
-<span id="LC5" class="line" lang="markdown"><span class="ge">*in emph **strong***</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6101:1-6103:9" dir="auto">The following patterns are less widely supported, but the intent
-is clear and they are useful (especially in contexts like bibliography
-entries):</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6105:1-6108:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="ge">*emph *</span>with emph<span class="ge">* in it*</span></span>
-<span id="LC2" class="line" lang="markdown"><span class="gs">**strong **</span>with strong<span class="gs">** in it**</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6110:1-6113:31" dir="auto">Many implementations have also restricted intraword emphasis to
-the <code>*</code> forms, to avoid unwanted emphasis in words containing
-internal underscores. (It is best practice to put these in code
-spans, but users often do not.)</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6115:1-6118:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown">internal emphasis: foo<span class="ge">*bar*</span>baz</span>
-<span id="LC2" class="line" lang="markdown">no emphasis: foo_bar_baz</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6120:1-6121:55" dir="auto">The rules given below capture all of these patterns, while allowing
-for efficient parsing strategies that do not backtrack.</p>
-<p data-sourcepos="6123:1-6127:38" dir="auto">First, some definitions. A <a href="@">delimiter run</a> is either
-a sequence of one or more <code>*</code> characters that is not preceded or
-followed by a non-backslash-escaped <code>*</code> character, or a sequence
-of one or more <code>_</code> characters that is not preceded or followed by
-a non-backslash-escaped <code>_</code> character.</p>
-<p data-sourcepos="6129:1-6135:37" dir="auto">A <a href="@">left-flanking delimiter run</a> is
-a [delimiter run] that is (1) not followed by [Unicode whitespace],
-and either (2a) not followed by a [punctuation character], or
-(2b) followed by a [punctuation character] and
-preceded by [Unicode whitespace] or a [punctuation character].
-For purposes of this definition, the beginning and the end of
-the line count as Unicode whitespace.</p>
-<p data-sourcepos="6137:1-6143:37" dir="auto">A <a href="@">right-flanking delimiter run</a> is
-a [delimiter run] that is (1) not preceded by [Unicode whitespace],
-and either (2a) not preceded by a [punctuation character], or
-(2b) preceded by a [punctuation character] and
-followed by [Unicode whitespace] or a [punctuation character].
-For purposes of this definition, the beginning and the end of
-the line count as Unicode whitespace.</p>
-<p data-sourcepos="6145:1-6145:41" dir="auto">Here are some examples of delimiter runs.</p>
-<ul data-sourcepos="6147:3-6178:0" dir="auto">
-<li data-sourcepos="6147:3-6155:0">
-<p data-sourcepos="6147:5-6147:41">left-flanking but not right-flanking:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6149:5-6154:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">***abc</span>
-<span id="LC2" class="line" lang="plaintext"> _abc</span>
-<span id="LC3" class="line" lang="plaintext">**"abc"</span>
-<span id="LC4" class="line" lang="plaintext"> _"abc"</span></code></pre>
-<copy-code></copy-code>
-</div>
-</li>
-<li data-sourcepos="6156:3-6164:0">
-<p data-sourcepos="6156:5-6156:41">right-flanking but not left-flanking:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6158:5-6163:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> abc***</span>
-<span id="LC2" class="line" lang="plaintext"> abc_</span>
-<span id="LC3" class="line" lang="plaintext">"abc"**</span>
-<span id="LC4" class="line" lang="plaintext">"abc"_</span></code></pre>
-<copy-code></copy-code>
-</div>
-</li>
-<li data-sourcepos="6165:3-6171:0">
-<p data-sourcepos="6165:5-6165:33">Both left and right-flanking:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6167:5-6170:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> abc***def</span>
-<span id="LC2" class="line" lang="plaintext">"abc"_"def"</span></code></pre>
-<copy-code></copy-code>
-</div>
-</li>
-<li data-sourcepos="6172:3-6178:0">
-<p data-sourcepos="6172:5-6172:36">Neither left nor right-flanking:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6174:5-6177:7" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">abc *** def</span>
-<span id="LC2" class="line" lang="plaintext">a _ b</span></code></pre>
-<copy-code></copy-code>
-</div>
-</li>
-</ul>
-<p data-sourcepos="6179:1-6185:49" dir="auto">(The idea of distinguishing left-flanking and right-flanking
-delimiter runs based on the character before and the character
-after comes from Roopesh Chander's
-<a href="http://www.vfmd.org/vfmd-spec/specification/#procedure-for-identifying-emphasis-tags" rel="nofollow noreferrer noopener" target="_blank">vfmd</a>.
-vfmd uses the terminology "emphasis indicator string" instead of "delimiter
-run," and its rules for distinguishing left- and right-flanking runs
-are a bit more complex than the ones given here.)</p>
-<p data-sourcepos="6187:1-6187:56" dir="auto">The following rules define emphasis and strong emphasis:</p>
-<ol data-sourcepos="6189:1-6253:0" dir="auto">
-<li data-sourcepos="6189:1-6191:0">
-<p data-sourcepos="6189:5-6190:71">A single <code>*</code> character <a href="@">can open emphasis</a>
-iff (if and only if) it is part of a [left-flanking delimiter run].</p>
-</li>
-<li data-sourcepos="6192:1-6197:0">
-<p data-sourcepos="6192:5-6196:28">A single <code>_</code> character [can open emphasis] iff
-it is part of a [left-flanking delimiter run]
-and either (a) not part of a [right-flanking delimiter run]
-or (b) part of a [right-flanking delimiter run]
-preceded by punctuation.</p>
-</li>
-<li data-sourcepos="6198:1-6200:0">
-<p data-sourcepos="6198:5-6199:55">A single <code>*</code> character <a href="@">can close emphasis</a>
-iff it is part of a [right-flanking delimiter run].</p>
-</li>
-<li data-sourcepos="6201:1-6206:0">
-<p data-sourcepos="6201:5-6205:28">A single <code>_</code> character [can close emphasis] iff
-it is part of a [right-flanking delimiter run]
-and either (a) not part of a [left-flanking delimiter run]
-or (b) part of a [left-flanking delimiter run]
-followed by punctuation.</p>
-</li>
-<li data-sourcepos="6207:1-6209:0">
-<p data-sourcepos="6207:5-6208:54">A double <code>**</code> <a href="@">can open strong emphasis</a>
-iff it is part of a [left-flanking delimiter run].</p>
-</li>
-<li data-sourcepos="6210:1-6215:0">
-<p data-sourcepos="6210:5-6214:28">A double <code>__</code> [can open strong emphasis] iff
-it is part of a [left-flanking delimiter run]
-and either (a) not part of a [right-flanking delimiter run]
-or (b) part of a [right-flanking delimiter run]
-preceded by punctuation.</p>
-</li>
-<li data-sourcepos="6216:1-6218:0">
-<p data-sourcepos="6216:5-6217:55">A double <code>**</code> <a href="@">can close strong emphasis</a>
-iff it is part of a [right-flanking delimiter run].</p>
-</li>
-<li data-sourcepos="6219:1-6224:0">
-<p data-sourcepos="6219:5-6223:28">A double <code>__</code> [can close strong emphasis] iff
-it is part of a [right-flanking delimiter run]
-and either (a) not part of a [left-flanking delimiter run]
-or (b) part of a [left-flanking delimiter run]
-followed by punctuation.</p>
-</li>
-<li data-sourcepos="6225:1-6234:0">
-<p data-sourcepos="6225:5-6233:19">Emphasis begins with a delimiter that [can open emphasis] and ends
-with a delimiter that [can close emphasis], and that uses the same
-character (<code>_</code> or <code>*</code>) as the opening delimiter. The
-opening and closing delimiters must belong to separate
-[delimiter runs]. If one of the delimiters can both
-open and close emphasis, then the sum of the lengths of the
-delimiter runs containing the opening and closing delimiters
-must not be a multiple of 3 unless both lengths are
-multiples of 3.</p>
-</li>
-<li data-sourcepos="6235:1-6245:0">
-<p data-sourcepos="6235:5-6244:23">Strong emphasis begins with a delimiter that
-[can open strong emphasis] and ends with a delimiter that
-[can close strong emphasis], and that uses the same character
-(<code>_</code> or <code>*</code>) as the opening delimiter. The
-opening and closing delimiters must belong to separate
-[delimiter runs]. If one of the delimiters can both open
-and close strong emphasis, then the sum of the lengths of
-the delimiter runs containing the opening and closing
-delimiters must not be a multiple of 3 unless both lengths
-are multiples of 3.</p>
-</li>
-<li data-sourcepos="6246:1-6249:0">
-<p data-sourcepos="6246:5-6248:25">A literal <code>*</code> character cannot occur at the beginning or end of
-<code>*</code>-delimited emphasis or <code>**</code>-delimited strong emphasis, unless it
-is backslash-escaped.</p>
-</li>
-<li data-sourcepos="6250:1-6253:0">
-<p data-sourcepos="6250:5-6252:25">A literal <code>_</code> character cannot occur at the beginning or end of
-<code>_</code>-delimited emphasis or <code>__</code>-delimited strong emphasis, unless it
-is backslash-escaped.</p>
-</li>
-</ol>
-<p data-sourcepos="6254:1-6255:43" dir="auto">Where rules 1--12 above are compatible with multiple parsings,
-the following principles resolve ambiguity:</p>
-<ol start="13" data-sourcepos="6257:1-6282:0" dir="auto">
-<li data-sourcepos="6257:1-6260:0">
-<p data-sourcepos="6257:5-6259:28">The number of nestings should be minimized. Thus, for example,
-an interpretation <code>&lt;strong&gt;...&lt;/strong&gt;</code> is always preferred to
-<code>&lt;em&gt;&lt;em&gt;...&lt;/em&gt;&lt;/em&gt;</code>.</p>
-</li>
-<li data-sourcepos="6261:1-6263:0">
-<p data-sourcepos="6261:5-6262:49">An interpretation <code>&lt;em&gt;&lt;strong&gt;...&lt;/strong&gt;&lt;/em&gt;</code> is always
-preferred to <code>&lt;strong&gt;&lt;em&gt;...&lt;/em&gt;&lt;/strong&gt;</code>.</p>
-</li>
-<li data-sourcepos="6264:1-6269:0">
-<p data-sourcepos="6264:5-6268:34">When two potential emphasis or strong emphasis spans overlap,
-so that the second begins before the first ends and ends after
-the first ends, the first takes precedence. Thus, for example,
-<code>*foo _bar* baz_</code> is parsed as <code>&lt;em&gt;foo _bar&lt;/em&gt; baz_</code> rather
-than <code>*foo &lt;em&gt;bar* baz&lt;/em&gt;</code>.</p>
-</li>
-<li data-sourcepos="6270:1-6275:0">
-<p data-sourcepos="6270:5-6274:49">When there are two potential emphasis or strong emphasis spans
-with the same closing delimiter, the shorter one (the one that
-opens later) takes precedence. Thus, for example,
-<code>**foo **bar baz**</code> is parsed as <code>**foo &lt;strong&gt;bar baz&lt;/strong&gt;</code>
-rather than <code>&lt;strong&gt;foo **bar baz&lt;/strong&gt;</code>.</p>
-</li>
-<li data-sourcepos="6276:1-6282:0">
-<p data-sourcepos="6276:5-6281:26">Inline code spans, links, images, and HTML tags group more tightly
-than emphasis. So, when there is a choice between an interpretation
-that contains one of these elements and one that does not, the
-former always wins. Thus, for example, <code>*[foo*](bar)</code> is
-parsed as <code>*&lt;a href="bar"&gt;foo*&lt;/a&gt;</code> rather than as
-<code>&lt;em&gt;[foo&lt;/em&gt;](bar)</code>.</p>
-</li>
-</ol>
-<p data-sourcepos="6283:1-6283:60" dir="auto">These rules can be illustrated through a series of examples.</p>
-<p data-sourcepos="6285:1-6285:7" dir="auto">Rule 1:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6287:1-6291:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo bar*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6294:1-6295:66" dir="auto">This is not emphasis, because the opening <code>*</code> is followed by
-whitespace, and hence not part of a [left-flanking delimiter run]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6297:1-6301:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">a * foo bar*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;a * foo bar*&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6304:1-6306:44" dir="auto">This is not emphasis, because the opening <code>*</code> is preceded
-by an alphanumeric and followed by punctuation, and hence
-not part of a [left-flanking delimiter run]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6308:1-6312:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">a*"foo"*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;a*&amp;quot;foo&amp;quot;*&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6315:1-6315:52" dir="auto">Unicode nonbreaking spaces count as whitespace, too:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6317:1-6321:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">* a *</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;* a *&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6324:1-6324:41" dir="auto">Intraword emphasis with <code>*</code> is permitted:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6326:1-6330:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo*bar*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;em&gt;bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6333:1-6337:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">5*6*78</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;5&lt;em&gt;6&lt;/em&gt;78&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6340:1-6340:7" dir="auto">Rule 2:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6342:1-6346:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo bar_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6349:1-6350:11" dir="auto">This is not emphasis, because the opening <code>_</code> is followed by
-whitespace:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6352:1-6356:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_ foo bar_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;_ foo bar_&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6359:1-6360:47" dir="auto">This is not emphasis, because the opening <code>_</code> is preceded
-by an alphanumeric and followed by punctuation:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6362:1-6366:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">a_"foo"_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;a_&amp;quot;foo&amp;quot;_&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6369:1-6369:46" dir="auto">Emphasis with <code>_</code> is not allowed inside words:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6371:1-6375:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo_bar_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo_bar_&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6378:1-6382:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">5_6_78</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;5_6_78&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6385:1-6389:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">приÑтанÑм_ÑтремÑÑ‚ÑÑ_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;приÑтанÑм_ÑтремÑÑ‚ÑÑ_&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6392:1-6393:47" dir="auto">Here <code>_</code> does not generate emphasis, because the first delimiter run
-is right-flanking and the second left-flanking:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6395:1-6399:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aa_"bb"_cc</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;aa_&amp;quot;bb&amp;quot;_cc&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6402:1-6404:12" dir="auto">This is emphasis, even though the opening delimiter is
-both left- and right-flanking, because it is preceded by
-punctuation:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6406:1-6410:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo-_(bar)_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo-&lt;em&gt;(bar)&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6413:1-6413:7" dir="auto">Rule 3:</p>
-<p data-sourcepos="6415:1-6416:32" dir="auto">This is not emphasis, because the closing delimiter does
-not match the opening delimiter:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6418:1-6422:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;_foo*&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6425:1-6426:11" dir="auto">This is not emphasis, because the closing <code>*</code> is preceded by
-whitespace:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6428:1-6432:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo bar *</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;*foo bar *&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6435:1-6435:36" dir="auto">A newline also counts as whitespace:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6437:1-6443:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo bar</span>
-<span id="LC2" class="line" lang="plaintext">*</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;*foo bar</span>
-<span id="LC5" class="line" lang="plaintext">*&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6446:1-6448:58" dir="auto">This is not emphasis, because the second <code>*</code> is
-preceded by punctuation and followed by an alphanumeric
-(hence it is not part of a [right-flanking delimiter run]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6450:1-6454:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*(*foo)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;*(*foo)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6457:1-6458:18" dir="auto">The point of this restriction is more easily appreciated
-with this example:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6460:1-6464:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*(*foo*)*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;(&lt;em&gt;foo&lt;/em&gt;)&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6467:1-6467:39" dir="auto">Intraword emphasis with <code>*</code> is allowed:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6469:1-6473:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo*bar</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;/em&gt;bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6477:1-6477:7" dir="auto">Rule 4:</p>
-<p data-sourcepos="6479:1-6480:11" dir="auto">This is not emphasis, because the closing <code>_</code> is preceded by
-whitespace:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6482:1-6486:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo bar _</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;_foo bar _&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6489:1-6490:56" dir="auto">This is not emphasis, because the second <code>_</code> is
-preceded by punctuation and followed by an alphanumeric:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6492:1-6496:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_(_foo)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;_(_foo)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6499:1-6499:33" dir="auto">This is emphasis within emphasis:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6501:1-6505:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_(_foo_)_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;(&lt;em&gt;foo&lt;/em&gt;)&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6508:1-6508:41" dir="auto">Intraword emphasis is disallowed for <code>_</code>:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6510:1-6514:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo_bar</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;_foo_bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6517:1-6521:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_приÑтанÑм_ÑтремÑÑ‚ÑÑ</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;_приÑтанÑм_ÑтремÑÑ‚ÑÑ&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6524:1-6528:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo_bar_baz_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo_bar_baz&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6531:1-6533:12" dir="auto">This is emphasis, even though the closing delimiter is
-both left- and right-flanking, because it is followed by
-punctuation:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6535:1-6539:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_(bar)_.</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;(bar)&lt;/em&gt;.&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6542:1-6542:7" dir="auto">Rule 5:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6544:1-6548:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo bar**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo bar&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6551:1-6552:23" dir="auto">This is not strong emphasis, because the opening delimiter is
-followed by whitespace:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6554:1-6558:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">** foo bar**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;** foo bar**&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6561:1-6563:44" dir="auto">This is not strong emphasis, because the opening <code>**</code> is preceded
-by an alphanumeric and followed by punctuation, and hence
-not part of a [left-flanking delimiter run]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6565:1-6569:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">a**"foo"**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;a**&amp;quot;foo&amp;quot;**&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6572:1-6572:49" dir="auto">Intraword strong emphasis with <code>**</code> is permitted:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6574:1-6578:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo**bar**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;strong&gt;bar&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6581:1-6581:7" dir="auto">Rule 6:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6583:1-6587:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo bar__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo bar&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6590:1-6591:23" dir="auto">This is not strong emphasis, because the opening delimiter is
-followed by whitespace:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6593:1-6597:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__ foo bar__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;__ foo bar__&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6600:1-6600:31" dir="auto">A newline counts as whitespace:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6601:1-6607:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__</span>
-<span id="LC2" class="line" lang="plaintext">foo bar__</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;__</span>
-<span id="LC5" class="line" lang="plaintext">foo bar__&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6610:1-6611:47" dir="auto">This is not strong emphasis, because the opening <code>__</code> is preceded
-by an alphanumeric and followed by punctuation:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6613:1-6617:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">a__"foo"__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;a__&amp;quot;foo&amp;quot;__&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6620:1-6620:49" dir="auto">Intraword strong emphasis is forbidden with <code>__</code>:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6622:1-6626:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo__bar__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo__bar__&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6629:1-6633:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">5__6__78</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;5__6__78&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6636:1-6640:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">приÑтанÑм__ÑтремÑÑ‚ÑÑ__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;приÑтанÑм__ÑтремÑÑ‚ÑÑ__&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6643:1-6647:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo, __bar__, baz__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo, &lt;strong&gt;bar&lt;/strong&gt;, baz&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6650:1-6652:12" dir="auto">This is strong emphasis, even though the opening delimiter is
-both left- and right-flanking, because it is preceded by
-punctuation:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6654:1-6658:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo-__(bar)__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo-&lt;strong&gt;(bar)&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6662:1-6662:7" dir="auto">Rule 7:</p>
-<p data-sourcepos="6664:1-6665:14" dir="auto">This is not strong emphasis, because the closing delimiter is preceded
-by whitespace:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6667:1-6671:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo bar **</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;**foo bar **&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6674:1-6675:9" dir="auto">(Nor can it be interpreted as an emphasized <code>*foo bar *</code>, because of
-Rule 11.)</p>
-<p data-sourcepos="6677:1-6678:56" dir="auto">This is not strong emphasis, because the second <code>**</code> is
-preceded by punctuation and followed by an alphanumeric:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6680:1-6684:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**(**foo)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;**(**foo)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6687:1-6688:20" dir="auto">The point of this restriction is more easily appreciated
-with these examples:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6690:1-6694:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*(**foo**)*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;(&lt;strong&gt;foo&lt;/strong&gt;)&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6697:1-6703:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**Gomphocarpus (*Gomphocarpus physocarpus*, syn.</span>
-<span id="LC2" class="line" lang="plaintext">*Asclepias physocarpa*)**</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;Gomphocarpus (&lt;em&gt;Gomphocarpus physocarpus&lt;/em&gt;, syn.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;em&gt;Asclepias physocarpa&lt;/em&gt;)&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6706:1-6710:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo "*bar*" foo**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &amp;quot;&lt;em&gt;bar&lt;/em&gt;&amp;quot; foo&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6713:1-6713:19" dir="auto">Intraword emphasis:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6715:1-6719:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo**bar</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo&lt;/strong&gt;bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6722:1-6722:7" dir="auto">Rule 8:</p>
-<p data-sourcepos="6724:1-6725:23" dir="auto">This is not strong emphasis, because the closing delimiter is
-preceded by whitespace:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6727:1-6731:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo bar __</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;__foo bar __&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6734:1-6735:56" dir="auto">This is not strong emphasis, because the second <code>__</code> is
-preceded by punctuation and followed by an alphanumeric:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6737:1-6741:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__(__foo)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;__(__foo)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6744:1-6745:18" dir="auto">The point of this restriction is more easily appreciated
-with this example:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6747:1-6751:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_(__foo__)_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;(&lt;strong&gt;foo&lt;/strong&gt;)&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6754:1-6754:49" dir="auto">Intraword strong emphasis is forbidden with <code>__</code>:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6756:1-6760:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo__bar</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;__foo__bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6763:1-6767:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__приÑтанÑм__ÑтремÑÑ‚ÑÑ</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;__приÑтанÑм__ÑтремÑÑ‚ÑÑ&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6770:1-6774:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo__bar__baz__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo__bar__baz&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6777:1-6779:12" dir="auto">This is strong emphasis, even though the closing delimiter is
-both left- and right-flanking, because it is followed by
-punctuation:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6781:1-6785:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__(bar)__.</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;(bar)&lt;/strong&gt;.&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6788:1-6788:7" dir="auto">Rule 9:</p>
-<p data-sourcepos="6790:1-6791:16" dir="auto">Any nonempty sequence of inline elements can be the contents of an
-emphasized span.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6793:1-6797:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo [bar](/url)*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;a href="/url"&gt;bar&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6800:1-6806:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo</span>
-<span id="LC2" class="line" lang="plaintext">bar*</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo</span>
-<span id="LC5" class="line" lang="plaintext">bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6809:1-6810:16" dir="auto">In particular, emphasis and strong emphasis can be nested
-inside emphasis:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6812:1-6816:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo __bar__ baz_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;strong&gt;bar&lt;/strong&gt; baz&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6819:1-6823:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo _bar_ baz_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;em&gt;bar&lt;/em&gt; baz&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6826:1-6830:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo_ bar_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;&lt;em&gt;foo&lt;/em&gt; bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6833:1-6837:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo *bar**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;em&gt;bar&lt;/em&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6840:1-6844:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo **bar** baz*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;strong&gt;bar&lt;/strong&gt; baz&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6846:1-6850:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo**bar**baz*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;strong&gt;bar&lt;/strong&gt;baz&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6852:1-6852:51" dir="auto">Note that in the preceding case, the interpretation</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6854:1-6856:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="nt">&lt;p&gt;&lt;em&gt;</span>foo<span class="nt">&lt;/em&gt;&lt;em&gt;</span>bar<span class="nt">&lt;em&gt;&lt;/em&gt;</span>baz<span class="nt">&lt;/em&gt;&lt;/p&gt;</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6859:1-6864:32" dir="auto">is precluded by the condition that a delimiter that
-can both open and close (like the <code>*</code> after <code>foo</code>)
-cannot form emphasis if the sum of the lengths of
-the delimiter runs containing the opening and
-closing delimiters is a multiple of 3 unless
-both lengths are multiples of 3.</p>
-<p data-sourcepos="6867:1-6868:34" dir="auto">For the same reason, we don't get two consecutive
-emphasis sections in this example:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6870:1-6874:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo**bar*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo**bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6877:1-6880:8" dir="auto">The same condition ensures that the following
-cases are all strong emphasis nested inside
-emphasis, even when the interior spaces are
-omitted:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6883:1-6887:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">***foo** bar*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;&lt;strong&gt;foo&lt;/strong&gt; bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6890:1-6894:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo **bar***</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;strong&gt;bar&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6897:1-6901:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo**bar***</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;strong&gt;bar&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6904:1-6906:34" dir="auto">When the lengths of the interior closing and opening
-delimiter runs are <em>both</em> multiples of 3, though,
-they can match to create emphasis:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6908:1-6912:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo***bar***baz</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;em&gt;&lt;strong&gt;bar&lt;/strong&gt;&lt;/em&gt;baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6914:1-6918:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo******bar*********baz</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;strong&gt;&lt;strong&gt;&lt;strong&gt;bar&lt;/strong&gt;&lt;/strong&gt;&lt;/strong&gt;***baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6921:1-6921:42" dir="auto">Indefinite levels of nesting are possible:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6923:1-6927:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo **bar *baz* bim** bop*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;strong&gt;bar &lt;em&gt;baz&lt;/em&gt; bim&lt;/strong&gt; bop&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6930:1-6934:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo [*bar*](/url)*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;a href="/url"&gt;&lt;em&gt;bar&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6937:1-6937:50" dir="auto">There can be no empty emphasis or strong emphasis:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6939:1-6943:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">** is not an empty emphasis</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;** is not an empty emphasis&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6946:1-6950:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**** is not an empty strong emphasis</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;**** is not an empty strong emphasis&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6954:1-6954:8" dir="auto">Rule 10:</p>
-<p data-sourcepos="6956:1-6957:25" dir="auto">Any nonempty sequence of inline elements can be the contents of an
-strongly emphasized span.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6959:1-6963:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo [bar](/url)**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;a href="/url"&gt;bar&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6966:1-6972:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo</span>
-<span id="LC2" class="line" lang="plaintext">bar**</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo</span>
-<span id="LC5" class="line" lang="plaintext">bar&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="6975:1-6976:23" dir="auto">In particular, emphasis and strong emphasis can be nested
-inside strong emphasis:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6978:1-6982:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo _bar_ baz__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;em&gt;bar&lt;/em&gt; baz&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6985:1-6989:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo __bar__ baz__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;strong&gt;bar&lt;/strong&gt; baz&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6992:1-6996:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">____foo__ bar__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;&lt;strong&gt;foo&lt;/strong&gt; bar&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="6999:1-7003:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo **bar****</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;strong&gt;bar&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7006:1-7010:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo *bar* baz**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;em&gt;bar&lt;/em&gt; baz&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7013:1-7017:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo*bar*baz**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo&lt;em&gt;bar&lt;/em&gt;baz&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7020:1-7024:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">***foo* bar**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;&lt;em&gt;foo&lt;/em&gt; bar&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7027:1-7031:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo *bar***</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;em&gt;bar&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7034:1-7034:42" dir="auto">Indefinite levels of nesting are possible:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7036:1-7042:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo *bar **baz**</span>
-<span id="LC2" class="line" lang="plaintext">bim* bop**</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;em&gt;bar &lt;strong&gt;baz&lt;/strong&gt;</span>
-<span id="LC5" class="line" lang="plaintext">bim&lt;/em&gt; bop&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7045:1-7049:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo [*bar*](/url)**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;a href="/url"&gt;&lt;em&gt;bar&lt;/em&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7052:1-7052:50" dir="auto">There can be no empty emphasis or strong emphasis:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7054:1-7058:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__ is not an empty emphasis</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;__ is not an empty emphasis&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7061:1-7065:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">____ is not an empty strong emphasis</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;____ is not an empty strong emphasis&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7069:1-7069:8" dir="auto">Rule 11:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7071:1-7075:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo ***</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo ***&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7078:1-7082:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo *\**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo &lt;em&gt;*&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7085:1-7089:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo *_*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo &lt;em&gt;_&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7092:1-7096:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo *****</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo *****&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7099:1-7103:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo **\***</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo &lt;strong&gt;*&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7106:1-7110:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo **_**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo &lt;strong&gt;_&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7113:1-7115:32" dir="auto">Note that when delimiters do not match evenly, Rule 11 determines
-that the excess literal <code>*</code> characters will appear outside of the
-emphasis, rather than inside it:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7117:1-7121:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;*&lt;em&gt;foo&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7124:1-7128:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;/em&gt;*&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7131:1-7135:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">***foo**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;*&lt;strong&gt;foo&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7138:1-7142:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">****foo*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;***&lt;em&gt;foo&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7145:1-7149:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo***</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo&lt;/strong&gt;*&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7152:1-7156:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo****</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;/em&gt;***&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7160:1-7160:8" dir="auto">Rule 12:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7162:1-7166:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo ___</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo ___&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7169:1-7173:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo _\__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo &lt;em&gt;_&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7176:1-7180:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo _*_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo &lt;em&gt;*&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7183:1-7187:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo _____</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo _____&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7190:1-7194:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo __\___</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo &lt;strong&gt;_&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7197:1-7201:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo __*__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo &lt;strong&gt;*&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7204:1-7208:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;_&lt;em&gt;foo&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7211:1-7213:32" dir="auto">Note that when delimiters do not match evenly, Rule 12 determines
-that the excess literal <code>_</code> characters will appear outside of the
-emphasis, rather than inside it:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7215:1-7219:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;/em&gt;_&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7222:1-7226:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">___foo__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;_&lt;strong&gt;foo&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7229:1-7233:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">____foo_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;___&lt;em&gt;foo&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7236:1-7240:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo___</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo&lt;/strong&gt;_&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7243:1-7247:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo____</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;/em&gt;___&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7250:1-7251:44" dir="auto">Rule 13 implies that if you want emphasis nested directly inside
-emphasis, you must use different delimiters:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7253:1-7257:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7260:1-7264:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*_foo_*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;&lt;em&gt;foo&lt;/em&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7267:1-7271:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo__</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7274:1-7278:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_*foo*_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;&lt;em&gt;foo&lt;/em&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7281:1-7282:21" dir="auto">However, strong emphasis within strong emphasis is possible without
-switching delimiters:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7284:1-7288:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">****foo****</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;&lt;strong&gt;foo&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7291:1-7295:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">____foo____</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;&lt;strong&gt;foo&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7299:1-7300:11" dir="auto">Rule 13 can be applied to arbitrarily long sequences of
-delimiters:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7302:1-7306:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">******foo******</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;&lt;strong&gt;&lt;strong&gt;foo&lt;/strong&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7309:1-7309:8" dir="auto">Rule 14:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7311:1-7315:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">***foo***</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;&lt;strong&gt;foo&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7318:1-7322:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_____foo_____</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;&lt;strong&gt;&lt;strong&gt;foo&lt;/strong&gt;&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7325:1-7325:8" dir="auto">Rule 15:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7327:1-7331:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo _bar* baz_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo _bar&lt;/em&gt; baz_&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7334:1-7338:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo __bar *baz bim__ bam*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;strong&gt;bar *baz bim&lt;/strong&gt; bam&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7341:1-7341:8" dir="auto">Rule 16:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7343:1-7347:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo **bar baz**</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;**foo &lt;strong&gt;bar baz&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7350:1-7354:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo *bar baz*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;*foo &lt;em&gt;bar baz&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7357:1-7357:8" dir="auto">Rule 17:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7359:1-7363:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*[bar*](/url)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;*&lt;a href="/url"&gt;bar*&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7366:1-7370:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo [bar_](/url)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;_foo &lt;a href="/url"&gt;bar_&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7373:1-7377:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*&lt;img src="foo" title="*"/&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;*&lt;img src="foo" title="*"/&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7380:1-7384:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**&lt;a href="**"&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;**&lt;a href="**"&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7387:1-7391:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__&lt;a href="__"&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;__&lt;a href="__"&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7394:1-7398:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*a `*`*</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;a &lt;code&gt;*&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7401:1-7405:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_a `_`_</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;a &lt;code&gt;_&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7408:1-7412:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**a&lt;http://foo.bar/?q=**&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;**a&lt;a href="http://foo.bar/?q=**"&gt;http://foo.bar/?q=**&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7415:1-7419:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__a&lt;http://foo.bar/?q=__&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;__a&lt;a href="http://foo.bar/?q=__"&gt;http://foo.bar/?q=__&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div>
-<h2 data-sourcepos="7424:1-7424:28">
-<a id="user-content-strikethrough-extension" class="anchor" href="#strikethrough-extension" aria-hidden="true"></a>Strikethrough (extension)</h2>
-<p data-sourcepos="7426:1-7427:10">GFM enables the <code>strikethrough</code> extension, where an additional emphasis type is
-available.</p>
-<p data-sourcepos="7429:1-7429:59">Strikethrough text is any text wrapped in two tildes (<code>~</code>).</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7431:1-7435:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~Hi~~ Hello, world!</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;del&gt;Hi&lt;/del&gt; Hello, world!&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7437:1-7438:17">As with regular emphasis delimiters, a new paragraph will cause strikethrough
-parsing to cease:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7440:1-7447:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This ~~has a</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">new paragraph~~.</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;This ~~has a&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;new paragraph~~.&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-</div>
-<h2 data-sourcepos="7451:1-7451:8" dir="auto">
-<a id="user-content-links" class="anchor" href="#links" aria-hidden="true"></a>Links</h2>
-<p data-sourcepos="7453:1-7458:13" dir="auto">A link contains [link text] (the visible text), a [link destination]
-(the URI that is the link destination), and optionally a [link title].
-There are two basic kinds of links in Markdown. In [inline links] the
-destination and title are given immediately after the link text. In
-[reference links] the destination and title are defined elsewhere in
-the document.</p>
-<p data-sourcepos="7460:1-7462:22" dir="auto">A <a href="@">link text</a> consists of a sequence of zero or more
-inline elements enclosed by square brackets (<code>[</code> and <code>]</code>). The
-following rules apply:</p>
-<ul data-sourcepos="7464:1-7480:0" dir="auto">
-<li data-sourcepos="7464:1-7467:0">
-<p data-sourcepos="7464:3-7466:43">Links may not contain other links, at any level of nesting. If
-multiple otherwise valid link definitions appear nested inside each
-other, the inner-most definition is used.</p>
-</li>
-<li data-sourcepos="7468:1-7472:0">
-<p data-sourcepos="7468:3-7471:22">Brackets are allowed in the [link text] only if (a) they
-are backslash-escaped or (b) they appear as a matched pair of brackets,
-with an open bracket <code>[</code>, a sequence of zero or more inlines, and
-a close bracket <code>]</code>.</p>
-</li>
-<li data-sourcepos="7473:1-7477:0">
-<p data-sourcepos="7473:3-7476:25">Backtick [code spans], [autolinks], and raw [HTML tags] bind more tightly
-than the brackets in link text. Thus, for example,
-<code>[foo`]`</code> could not be a link text, since the second <code>]</code>
-is part of a code span.</p>
-</li>
-<li data-sourcepos="7478:1-7480:0">
-<p data-sourcepos="7478:3-7479:78">The brackets in link text bind more tightly than markers for
-[emphasis and strong emphasis]. Thus, for example, <code>*[foo*](url)</code> is a link.</p>
-</li>
-</ul>
-<p data-sourcepos="7481:1-7481:42" dir="auto">A <a href="@">link destination</a> consists of either</p>
-<ul data-sourcepos="7483:1-7494:0" dir="auto">
-<li data-sourcepos="7483:1-7486:0">
-<p data-sourcepos="7483:3-7485:27">a sequence of zero or more characters between an opening <code>&lt;</code> and a
-closing <code>&gt;</code> that contains no line breaks or unescaped
-<code>&lt;</code> or <code>&gt;</code> characters, or</p>
-</li>
-<li data-sourcepos="7487:1-7494:0">
-<p data-sourcepos="7487:3-7493:23">a nonempty sequence of characters that does not start with
-<code>&lt;</code>, does not include ASCII space or control characters, and
-includes parentheses only if (a) they are backslash-escaped or
-(b) they are part of a balanced pair of unescaped parentheses.
-(Implementations may impose limits on parentheses nesting to
-avoid performance issues, but at least three levels of nesting
-should be supported.)</p>
-</li>
-</ul>
-<p data-sourcepos="7495:1-7495:37" dir="auto">A <a href="@">link title</a> consists of either</p>
-<ul data-sourcepos="7497:1-7508:0" dir="auto">
-<li data-sourcepos="7497:1-7500:0">
-<p data-sourcepos="7497:3-7499:23">a sequence of zero or more characters between straight double-quote
-characters (<code>"</code>), including a <code>"</code> character only if it is
-backslash-escaped, or</p>
-</li>
-<li data-sourcepos="7501:1-7504:0">
-<p data-sourcepos="7501:3-7503:23">a sequence of zero or more characters between straight single-quote
-characters (<code>'</code>), including a <code>'</code> character only if it is
-backslash-escaped, or</p>
-</li>
-<li data-sourcepos="7505:1-7508:0">
-<p data-sourcepos="7505:3-7507:20">a sequence of zero or more characters between matching parentheses
-(<code>(...)</code>), including a <code>(</code> or <code>)</code> character only if it is
-backslash-escaped.</p>
-</li>
-</ul>
-<p data-sourcepos="7509:1-7510:15" dir="auto">Although [link titles] may span multiple lines, they may not contain
-a [blank line].</p>
-<p data-sourcepos="7512:1-7522:6" dir="auto">An <a href="@">inline link</a> consists of a [link text] followed immediately
-by a left parenthesis <code>(</code>, optional [whitespace], an optional
-[link destination], an optional [link title] separated from the link
-destination by [whitespace], optional [whitespace], and a right
-parenthesis <code>)</code>. The link's text consists of the inlines contained
-in the [link text] (excluding the enclosing square brackets).
-The link's URI consists of the link destination, excluding enclosing
-<code>&lt;...&gt;</code> if present, with backslash-escapes in effect as described
-above. The link's title consists of the link title, excluding its
-enclosing delimiters, with backslash-escapes in effect as described
-above.</p>
-<p data-sourcepos="7524:1-7524:29" dir="auto">Here is a simple inline link:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7526:1-7530:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/uri "title")</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri" title="title"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7533:1-7533:25" dir="auto">The title may be omitted:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7535:1-7539:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/uri)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7542:1-7542:50" dir="auto">Both the title and the destination may be omitted:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7544:1-7548:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link]()</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href=""&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7551:1-7555:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](&lt;&gt;)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href=""&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7557:1-7558:28" dir="auto">The destination can only contain spaces if it is
-enclosed in pointy brackets:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7560:1-7564:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/my uri)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[link](/my uri)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7566:1-7570:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](&lt;/my uri&gt;)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/my%20uri"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7572:1-7573:36" dir="auto">The destination cannot contain line breaks,
-even if enclosed in pointy brackets:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7575:1-7581:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](foo</span>
-<span id="LC2" class="line" lang="plaintext">bar)</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;[link](foo</span>
-<span id="LC5" class="line" lang="plaintext">bar)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7583:1-7589:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](&lt;foo</span>
-<span id="LC2" class="line" lang="plaintext">bar&gt;)</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;[link](&lt;foo</span>
-<span id="LC5" class="line" lang="plaintext">bar&gt;)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7591:1-7592:19" dir="auto">The destination can contain <code>)</code> if it is enclosed
-in pointy brackets:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7594:1-7598:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[a](&lt;b)c&gt;)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="b)c"&gt;a&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7600:1-7600:53" dir="auto">Pointy brackets that enclose links must be unescaped:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7602:1-7606:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](&lt;foo\&gt;)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[link](&amp;lt;foo&amp;gt;)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7608:1-7609:24" dir="auto">These are not links, because the opening pointy bracket
-is not matched properly:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7611:1-7619:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[a](&lt;b)c</span>
-<span id="LC2" class="line" lang="plaintext">[a](&lt;b)c&gt;</span>
-<span id="LC3" class="line" lang="plaintext">[a](&lt;b&gt;c)</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[a](&amp;lt;b)c</span>
-<span id="LC6" class="line" lang="plaintext">[a](&amp;lt;b)c&amp;gt;</span>
-<span id="LC7" class="line" lang="plaintext">[a](&lt;b&gt;c)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7621:1-7621:55" dir="auto">Parentheses inside the link destination may be escaped:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7623:1-7627:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](\(foo\))</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="(foo)"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7629:1-7630:9" dir="auto">Any number of parentheses are allowed without escaping, as long as they are
-balanced:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7632:1-7636:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](foo(and(bar)))</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo(and(bar))"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7638:1-7639:13" dir="auto">However, if you have unbalanced parentheses, you need to escape or use the
-<code>&lt;...&gt;</code> form:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7641:1-7645:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](foo\(and\(bar\))</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo(and(bar)"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7648:1-7652:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](&lt;foo(and(bar)&gt;)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo(and(bar)"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7655:1-7656:12" dir="auto">Parentheses and other symbols can also be escaped, as usual
-in Markdown:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7658:1-7662:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](foo\)\:)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo):"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7665:1-7665:52" dir="auto">A link can contain fragment identifiers and queries:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7667:1-7677:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](#fragment)</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[link](http://example.com#fragment)</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">[link](http://example.com?foo=3#frag)</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;&lt;a href="#fragment"&gt;link&lt;/a&gt;&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://example.com#fragment"&gt;link&lt;/a&gt;&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://example.com?foo=3#frag"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7680:1-7681:17" dir="auto">Note that a backslash before a non-escapable character is
-just a backslash:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7683:1-7687:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](foo\bar)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo%5Cbar"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7690:1-7697:52" dir="auto">URL-escaping should be left alone inside the destination, as all
-URL-escaped characters are also valid URL characters. Entity and
-numerical character references in the destination will be parsed
-into the corresponding Unicode code points, as usual. These may
-be optionally URL-escaped when written as HTML, but this spec
-does not enforce any particular policy for rendering URLs in
-HTML or other formats. Renderers may make different decisions
-about how to escape or normalize URLs in the output.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7699:1-7703:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](foo%20b&amp;auml;)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo%20b%C3%A4"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7706:1-7708:23" dir="auto">Note that, because titles can often be parsed as destinations,
-if you try to omit the destination and keep the title, you'll
-get unexpected results:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7710:1-7714:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link]("title")</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="%22title%22"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7717:1-7717:62" dir="auto">Titles may be in single quotes, double quotes, or parentheses:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7719:1-7727:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/url "title")</span>
-<span id="LC2" class="line" lang="plaintext">[link](/url 'title')</span>
-<span id="LC3" class="line" lang="plaintext">[link](/url (title))</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;link&lt;/a&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;a href="/url" title="title"&gt;link&lt;/a&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;a href="/url" title="title"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7730:1-7731:22" dir="auto">Backslash escapes and entity and numeric character references
-may be used in titles:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7733:1-7737:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/url "title \"&amp;quot;")</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title &amp;quot;&amp;quot;"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7740:1-7741:64" dir="auto">Titles must be separated from the link using a [whitespace].
-Other [Unicode whitespace] like non-breaking space doesn't work.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7743:1-7747:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/url "title")</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url%C2%A0%22title%22"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7750:1-7750:56" dir="auto">Nested balanced quotes are not allowed without escaping:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7752:1-7756:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/url "title "and" title")</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[link](/url &amp;quot;title &amp;quot;and&amp;quot; title&amp;quot;)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7759:1-7759:67" dir="auto">But it is easy to work around this by using a different quote type:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7761:1-7765:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/url 'title "and" title')</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title &amp;quot;and&amp;quot; title"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7768:1-7781:61" dir="auto">(Note: <code>Markdown.pl</code> did allow double quotes inside a double-quoted
-title, and its test suite included a test demonstrating this.
-But it is hard to see a good rationale for the extra complexity this
-brings, since there are already many ways---backslash escaping,
-entity and numeric character references, or using a different
-quote type for the enclosing title---to write titles containing
-double quotes. <code>Markdown.pl</code>'s handling of titles has a number
-of other strange features. For example, it allows single-quoted
-titles in inline links, but not reference links. And, in
-reference links but not inline links, it allows a title to begin
-with <code>"</code> and end with <code>)</code>. <code>Markdown.pl</code> 1.0.1 even allows
-titles with no closing quotation mark, though 1.0.2b8 does not.
-It seems preferable to adopt a simple, rational rule that works
-the same way in inline links and link reference definitions.)</p>
-<p data-sourcepos="7783:1-7783:57" dir="auto">[Whitespace] is allowed around the destination and title:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7785:1-7790:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link]( /uri</span>
-<span id="LC2" class="line" lang="plaintext"> "title" )</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri" title="title"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7793:1-7794:22" dir="auto">But it is not allowed between the link text and the
-following parenthesis:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7796:1-7800:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link] (/uri)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[link] (/uri)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7803:1-7804:24" dir="auto">The link text may contain balanced brackets, but not unbalanced ones,
-unless they are escaped:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7806:1-7810:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link [foo [bar]]](/uri)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;link [foo [bar]]&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7813:1-7817:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link] bar](/uri)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[link] bar](/uri)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7820:1-7824:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link [bar](/uri)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[link &lt;a href="/uri"&gt;bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7827:1-7831:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link \[bar](/uri)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;link [bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7834:1-7834:41" dir="auto">The link text may contain inline content:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7836:1-7840:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link *foo **bar** `#`*](/uri)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;link &lt;em&gt;foo &lt;strong&gt;bar&lt;/strong&gt; &lt;code&gt;#&lt;/code&gt;&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7843:1-7847:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[![moon](moon.jpg)](/uri)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;&lt;img src="moon.jpg" alt="moon" /&gt;&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7850:1-7850:68" dir="auto">However, links may not contain other links, at any level of nesting.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7852:1-7856:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo [bar](/uri)](/uri)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[foo &lt;a href="/uri"&gt;bar&lt;/a&gt;](/uri)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7859:1-7863:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo *[bar [baz](/uri)](/uri)*](/uri)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[foo &lt;em&gt;[bar &lt;a href="/uri"&gt;baz&lt;/a&gt;](/uri)&lt;/em&gt;](/uri)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7866:1-7870:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![[[foo](uri1)](uri2)](uri3)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;img src="uri3" alt="[foo](uri2)" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7873:1-7874:18" dir="auto">These cases illustrate the precedence of link text grouping over
-emphasis grouping:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7876:1-7880:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*[foo*](/uri)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;*&lt;a href="/uri"&gt;foo*&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7883:1-7887:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo *bar](baz*)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="baz*"&gt;foo *bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7890:1-7891:11" dir="auto">Note that brackets that <em>aren't</em> part of links do not take
-precedence:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7893:1-7897:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo [bar* baz]</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo [bar&lt;/em&gt; baz]&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7900:1-7901:33" dir="auto">These cases illustrate the precedence of HTML tags, code spans,
-and autolinks over link grouping:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7903:1-7907:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo &lt;bar attr="](baz)"&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[foo &lt;bar attr="](baz)"&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7910:1-7914:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo`](/uri)`</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[foo&lt;code&gt;](/uri)&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7917:1-7921:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo&lt;http://example.com/?search=](uri)&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[foo&lt;a href="http://example.com/?search=%5D(uri)"&gt;http://example.com/?search=](uri)&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7924:1-7926:41" dir="auto">There are three kinds of <a href="@">reference link</a>s:
-<a href="#full-reference-link">full</a>, <a href="#collapsed-reference-link">collapsed</a>,
-and <a href="#shortcut-reference-link">shortcut</a>.</p>
-<p data-sourcepos="7928:1-7930:71" dir="auto">A <a href="@">full reference link</a>
-consists of a [link text] immediately followed by a [link label]
-that [matches] a [link reference definition] elsewhere in the document.</p>
-<p data-sourcepos="7932:1-7938:9" dir="auto">A <a href="@">link label</a> begins with a left bracket (<code>[</code>) and ends
-with the first right bracket (<code>]</code>) that is not backslash-escaped.
-Between these brackets there must be at least one [non-whitespace character].
-Unescaped square bracket characters are not allowed inside the
-opening and closing square brackets of [link labels]. A link
-label can have at most 999 characters inside the square
-brackets.</p>
-<p data-sourcepos="7940:1-7947:69" dir="auto">One label <a href="@">matches</a>
-another just in case their normalized forms are equal. To normalize a
-label, strip off the opening and closing brackets,
-perform the <em>Unicode case fold</em>, strip leading and trailing
-[whitespace] and collapse consecutive internal
-[whitespace] to a single space. If there are multiple
-matching reference link definitions, the one that comes first in the
-document is used. (It is desirable in such cases to emit a warning.)</p>
-<p data-sourcepos="7949:1-7951:37" dir="auto">The contents of the first link label are parsed as inlines, which are
-used as the link's text. The link's URI and title are provided by the
-matching [link reference definition].</p>
-<p data-sourcepos="7953:1-7953:25" dir="auto">Here is a simple example:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7955:1-7961:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][bar]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[bar]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7964:1-7965:22" dir="auto">The rules for the [link text] are the same as with
-[inline links]. Thus:</p>
-<p data-sourcepos="7967:1-7968:24" dir="auto">The link text may contain balanced brackets, but not unbalanced ones,
-unless they are escaped:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7970:1-7976:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link [foo [bar]]][ref]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;link [foo [bar]]&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7979:1-7985:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link \[bar][ref]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;link [bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="7988:1-7988:41" dir="auto">The link text may contain inline content:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7990:1-7996:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link *foo **bar** `#`*][ref]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;link &lt;em&gt;foo &lt;strong&gt;bar&lt;/strong&gt; &lt;code&gt;#&lt;/code&gt;&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="7999:1-8005:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[![moon](moon.jpg)][ref]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;&lt;img src="moon.jpg" alt="moon" /&gt;&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8008:1-8008:68" dir="auto">However, links may not contain other links, at any level of nesting.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8010:1-8016:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo [bar](/uri)][ref]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[foo &lt;a href="/uri"&gt;bar&lt;/a&gt;]&lt;a href="/uri"&gt;ref&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8019:1-8025:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo *bar [baz][ref]*][ref]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[foo &lt;em&gt;bar &lt;a href="/uri"&gt;baz&lt;/a&gt;&lt;/em&gt;]&lt;a href="/uri"&gt;ref&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8028:1-8029:38" dir="auto">(In the examples above, we have two [shortcut reference links]
-instead of one [full reference link].)</p>
-<p data-sourcepos="8031:1-8032:18" dir="auto">The following cases illustrate the precedence of link text grouping over
-emphasis grouping:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8034:1-8040:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*[foo*][ref]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;*&lt;a href="/uri"&gt;foo*&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8043:1-8049:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo *bar][ref]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;foo *bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8052:1-8053:33" dir="auto">These cases illustrate the precedence of HTML tags, code spans,
-and autolinks over link grouping:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8055:1-8061:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo &lt;bar attr="][ref]"&gt;</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[foo &lt;bar attr="][ref]"&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8064:1-8070:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo`][ref]`</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[foo&lt;code&gt;][ref]&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8073:1-8079:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo&lt;http://example.com/?search=][ref]&gt;</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[foo&lt;a href="http://example.com/?search=%5D%5Bref%5D"&gt;http://example.com/?search=][ref]&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8082:1-8082:29" dir="auto">Matching is case-insensitive:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8084:1-8090:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][BaR]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[bar]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8093:1-8093:26" dir="auto">Unicode case fold is used:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8095:1-8101:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[Толпой][Толпой] is a Russian word.</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[ТОЛПОЙ]: /url</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url"&gt;Толпой&lt;/a&gt; is a Russian word.&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8104:1-8105:33" dir="auto">Consecutive internal [whitespace] is treated as one space for
-purposes of determining matching:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8107:1-8114:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[Foo</span>
-<span id="LC2" class="line" lang="plaintext"> bar]: /url</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">[Baz][Foo bar]</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url"&gt;Baz&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8117:1-8118:13" dir="auto">No [whitespace] is allowed between the [link text] and the
-[link label]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8120:1-8126:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo] [bar]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[bar]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[foo] &lt;a href="/url" title="title"&gt;bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8129:1-8137:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]</span>
-<span id="LC2" class="line" lang="plaintext">[bar]</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">[bar]: /url "title"</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;[foo]</span>
-<span id="LC7" class="line" lang="plaintext">&lt;a href="/url" title="title"&gt;bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8140:1-8149:9" dir="auto">This is a departure from John Gruber's original Markdown syntax
-description, which explicitly allows whitespace between the link
-text and the link label. It brings reference links in line with
-[inline links], which (according to both original Markdown and
-this spec) cannot have whitespace after the link text. More
-importantly, it prevents inadvertent capture of consecutive
-[shortcut reference links]. If whitespace is allowed between the
-link text and the link label, then in the following we will have
-a single reference link, not two shortcut reference links, as
-intended:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8151:1-8157:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown">[foo]</span>
-<span id="LC2" class="line" lang="markdown">[bar]</span>
-<span id="LC3" class="line" lang="markdown"></span>
-<span id="LC4" class="line" lang="markdown"><span class="p">[</span><span class="ss">foo</span><span class="p">]:</span> <span class="sx">/url1</span></span>
-<span id="LC5" class="line" lang="markdown"><span class="p">[</span><span class="ss">bar</span><span class="p">]:</span> <span class="sx">/url2</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8159:1-8165:20" dir="auto">(Note that [shortcut reference links] were introduced by Gruber
-himself in a beta version of <code>Markdown.pl</code>, but never included
-in the official syntax description. Without shortcut reference
-links, it is harmless to allow space between the link text and
-link label; but once shortcut references are introduced, it is
-too dangerous to allow this, as it frequently leads to
-unintended results.)</p>
-<p data-sourcepos="8167:1-8168:18" dir="auto">When there are multiple matching [link reference definitions],
-the first is used:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8170:1-8178:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url1</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url2</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">[bar][foo]</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url1"&gt;bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8181:1-8183:40" dir="auto">Note that matching is performed on normalized strings, not parsed
-inline content. So the following does not match, even though the
-labels define equivalent inline content:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8185:1-8191:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[bar][foo\!]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo!]: /url</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[bar][foo!]&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8194:1-8195:18" dir="auto">[Link labels] cannot contain brackets, unless they are
-backslash-escaped:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8197:1-8204:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][ref[]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[ref[]: /uri</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[foo][ref[]&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;[ref[]: /uri&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8207:1-8214:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][ref[bar]]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[ref[bar]]: /uri</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[foo][ref[bar]]&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;[ref[bar]]: /uri&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8217:1-8224:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[[[foo]]]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[[[foo]]]: /url</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[[[foo]]]&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;[[[foo]]]: /url&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8227:1-8233:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][ref\[]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[ref\[]: /uri</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8236:1-8236:55" dir="auto">Note that in this example <code>]</code> is not backslash-escaped:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8238:1-8244:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[bar\\]: /uri</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[bar\\]</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;bar\&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8247:1-8247:68" dir="auto">A [link label] must contain at least one [non-whitespace character]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8249:1-8256:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[]: /uri</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[]&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;[]: /uri&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8259:1-8270:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[</span>
-<span id="LC2" class="line" lang="plaintext"> ]</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">[</span>
-<span id="LC5" class="line" lang="plaintext"> ]: /uri</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;[</span>
-<span id="LC8" class="line" lang="plaintext">]&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;[</span>
-<span id="LC10" class="line" lang="plaintext">]: /uri&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8273:1-8280:40" dir="auto">A <a href="@">collapsed reference link</a>
-consists of a [link label] that [matches] a
-[link reference definition] elsewhere in the
-document, followed by the string <code>[]</code>.
-The contents of the first link label are parsed as inlines,
-which are used as the link's text. The link's URI and title are
-provided by the matching reference link definition. Thus,
-<code>[foo][]</code> is equivalent to <code>[foo][foo]</code>.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8282:1-8288:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8291:1-8297:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[*foo* bar][]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[*foo* bar]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;&lt;em&gt;foo&lt;/em&gt; bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8300:1-8300:37" dir="auto">The link labels are case-insensitive:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8302:1-8308:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[Foo][]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;Foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8312:1-8313:41" dir="auto">As with full reference links, [whitespace] is not
-allowed between the two sets of brackets:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8315:1-8323:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo] </span>
-<span id="LC2" class="line" lang="plaintext">[]</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">[foo]: /url "title"</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;foo&lt;/a&gt;</span>
-<span id="LC7" class="line" lang="plaintext">[]&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8326:1-8333:41" dir="auto">A <a href="@">shortcut reference link</a>
-consists of a [link label] that [matches] a
-[link reference definition] elsewhere in the
-document and is not followed by <code>[]</code> or a link label.
-The contents of the first link label are parsed as inlines,
-which are used as the link's text. The link's URI and title
-are provided by the matching link reference definition.
-Thus, <code>[foo]</code> is equivalent to <code>[foo][]</code>.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8335:1-8341:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8344:1-8350:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[*foo* bar]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[*foo* bar]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;&lt;em&gt;foo&lt;/em&gt; bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8353:1-8359:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[[*foo* bar]]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[*foo* bar]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[&lt;a href="/url" title="title"&gt;&lt;em&gt;foo&lt;/em&gt; bar&lt;/a&gt;]&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8362:1-8368:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[[bar [foo]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[[bar &lt;a href="/url"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8371:1-8371:37" dir="auto">The link labels are case-insensitive:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8373:1-8379:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[Foo]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;Foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8382:1-8382:48" dir="auto">A space after the link text should be preserved:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8384:1-8390:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo] bar</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url"&gt;foo&lt;/a&gt; bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8393:1-8394:31" dir="auto">If you just want bracketed text, you can backslash-escape the
-opening bracket to avoid links:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8396:1-8402:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\[foo]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8405:1-8406:26" dir="auto">Note that this is a link, because a link label ends with the first
-following closing bracket:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8408:1-8414:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo*]: /url</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">*[foo*]</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;*&lt;a href="/url"&gt;foo*&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8417:1-8418:11" dir="auto">Full and compact references take precedence over shortcut
-references:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8420:1-8427:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][bar]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url1</span>
-<span id="LC4" class="line" lang="plaintext">[bar]: /url2</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url2"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8429:1-8435:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url1</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url1"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8437:1-8437:34" dir="auto">Inline links also take precedence:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8439:1-8445:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]()</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url1</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href=""&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8447:1-8453:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo](not a link)</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url1</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url1"&gt;foo&lt;/a&gt;(not a link)&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8455:1-8456:23" dir="auto">In the following case <code>[bar][baz]</code> is parsed as a reference,
-<code>[foo]</code> as normal text:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8458:1-8464:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][bar][baz]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[baz]: /url</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;a href="/url"&gt;bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8467:1-8468:19" dir="auto">Here, though, <code>[foo][bar]</code> is parsed as a reference, since
-<code>[bar]</code> is defined:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8470:1-8477:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][bar][baz]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[baz]: /url1</span>
-<span id="LC4" class="line" lang="plaintext">[bar]: /url2</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url2"&gt;foo&lt;/a&gt;&lt;a href="/url1"&gt;baz&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8480:1-8481:65" dir="auto">Here <code>[foo]</code> is not parsed as a shortcut reference, because it
-is followed by a link label (even though <code>[bar]</code> is not defined):</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8483:1-8490:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][bar][baz]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[baz]: /url1</span>
-<span id="LC4" class="line" lang="plaintext">[foo]: /url2</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;a href="/url1"&gt;bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="8494:1-8494:9" dir="auto">
-<a id="user-content-images" class="anchor" href="#images" aria-hidden="true"></a>Images</h2>
-<p data-sourcepos="8496:1-8504:55" dir="auto">Syntax for images is like the syntax for links, with one
-difference. Instead of [link text], we have an
-<a href="@">image description</a>. The rules for this are the
-same as for [link text], except that (a) an
-image description starts with <code>![</code> rather than <code>[</code>, and
-(b) an image description may contain links.
-An image description has inline elements
-as its contents. When an image is rendered to HTML,
-this is standardly used as the image's <code>alt</code> attribute.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8506:1-8510:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo](/url "title")</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo" title="title" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8513:1-8519:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo *bar*]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo *bar*]: train.jpg "train &amp; tracks"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;img src="train.jpg" alt="foo bar" title="train &amp;amp; tracks" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8522:1-8526:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo ![bar](/url)](/url2)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url2" alt="foo bar" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8529:1-8533:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo [bar](/url)](/url2)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url2" alt="foo bar" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8536:1-8541:40" dir="auto">Though this spec is concerned with parsing, not rendering, it is
-recommended that in rendering to HTML, only the plain string content
-of the [image description] be used. Note that in
-the above example, the alt attribute's value is <code>foo bar</code>, not <code>foo [bar](/url)</code> or <code>foo &lt;a href="/url"&gt;bar&lt;/a&gt;</code>. Only the plain string
-content is rendered, without formatting.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8543:1-8549:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo *bar*][]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo *bar*]: train.jpg "train &amp; tracks"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;img src="train.jpg" alt="foo bar" title="train &amp;amp; tracks" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8552:1-8558:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo *bar*][foobar]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[FOOBAR]: train.jpg "train &amp; tracks"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;img src="train.jpg" alt="foo bar" title="train &amp;amp; tracks" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8561:1-8565:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo](train.jpg)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;img src="train.jpg" alt="foo" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8568:1-8572:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">My ![foo bar](/path/to/train.jpg "title" )</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;My &lt;img src="/path/to/train.jpg" alt="foo bar" title="title" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8575:1-8579:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo](&lt;url&gt;)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;img src="url" alt="foo" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8582:1-8586:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![](/url)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8589:1-8589:16" dir="auto">Reference-style:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8591:1-8597:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo][bar]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[bar]: /url</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8600:1-8606:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo][bar]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[BAR]: /url</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8609:1-8609:10" dir="auto">Collapsed:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8611:1-8617:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo][]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo" title="title" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8620:1-8626:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![*foo* bar][]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[*foo* bar]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo bar" title="title" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8629:1-8629:32" dir="auto">The labels are case-insensitive:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8631:1-8637:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![Foo][]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="Foo" title="title" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8640:1-8641:33" dir="auto">As with reference links, [whitespace] is not allowed
-between the two sets of brackets:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8643:1-8651:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo] </span>
-<span id="LC2" class="line" lang="plaintext">[]</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">[foo]: /url "title"</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo" title="title" /&gt;</span>
-<span id="LC7" class="line" lang="plaintext">[]&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8654:1-8654:9" dir="auto">Shortcut:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8656:1-8662:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo" title="title" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8665:1-8671:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![*foo* bar]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[*foo* bar]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo bar" title="title" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8674:1-8674:56" dir="auto">Note that link labels cannot contain unescaped brackets:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8676:1-8683:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![[foo]]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[[foo]]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;![[foo]]&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;[[foo]]: /url &amp;quot;title&amp;quot;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8686:1-8686:37" dir="auto">The link labels are case-insensitive:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8688:1-8694:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![Foo]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="Foo" title="title" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8697:1-8698:33" dir="auto">If you just want a literal <code>!</code> followed by bracketed text, you can
-backslash-escape the opening <code>[</code>:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8700:1-8706:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">!\[foo]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;![foo]&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8709:1-8710:4" dir="auto">If you want a link after a literal <code>!</code>, backslash-escape the
-<code>!</code>:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8712:1-8718:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\![foo]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;!&lt;a href="/url" title="title"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="8721:1-8721:12" dir="auto">
-<a id="user-content-autolinks" class="anchor" href="#autolinks" aria-hidden="true"></a>Autolinks</h2>
-<p data-sourcepos="8723:1-8725:18" dir="auto"><a href="@">Autolink</a>s are absolute URIs and email addresses inside
-<code>&lt;</code> and <code>&gt;</code>. They are parsed as links, with the URL or email address
-as the link label.</p>
-<p data-sourcepos="8727:1-8729:52" dir="auto">A <a href="@">URI autolink</a> consists of <code>&lt;</code>, followed by an
-[absolute URI] followed by <code>&gt;</code>. It is parsed as
-a link to the URI, with the URI as the link's label.</p>
-<p data-sourcepos="8731:1-8736:25" dir="auto">An <a href="@">absolute URI</a>,
-for these purposes, consists of a [scheme] followed by a colon (<code>:</code>)
-followed by zero or more characters other than ASCII
-[whitespace] and control characters, <code>&lt;</code>, and <code>&gt;</code>. If
-the URI includes these characters, they must be percent-encoded
-(e.g. <code>%20</code> for a space).</p>
-<p data-sourcepos="8738:1-8741:37" dir="auto">For purposes of this spec, a <a href="@">scheme</a> is any sequence
-of 2--32 characters beginning with an ASCII letter and followed
-by any combination of ASCII letters, digits, or the symbols plus
-("+"), period ("."), or hyphen ("-").</p>
-<p data-sourcepos="8743:1-8743:30" dir="auto">Here are some valid autolinks:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8745:1-8749:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;http://foo.bar.baz&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://foo.bar.baz"&gt;http://foo.bar.baz&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8752:1-8756:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://foo.bar.baz/test?q=hello&amp;amp;id=22&amp;amp;boolean"&gt;http://foo.bar.baz/test?q=hello&amp;amp;id=22&amp;amp;boolean&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8759:1-8763:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;irc://foo.bar:2233/baz&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="irc://foo.bar:2233/baz"&gt;irc://foo.bar:2233/baz&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8766:1-8766:23" dir="auto">Uppercase is also fine:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8768:1-8772:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;MAILTO:FOO@BAR.BAZ&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="MAILTO:FOO@BAR.BAZ"&gt;MAILTO:FOO@BAR.BAZ&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8775:1-8778:18" dir="auto">Note that many strings that count as [absolute URIs] for
-purposes of this spec are not valid URIs, because their
-schemes are not registered or because of other problems
-with their syntax:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8780:1-8784:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a+b+c:d&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="a+b+c:d"&gt;a+b+c:d&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8787:1-8791:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;made-up-scheme://foo,bar&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="made-up-scheme://foo,bar"&gt;made-up-scheme://foo,bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8794:1-8798:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;http://../&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://../"&gt;http://../&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8801:1-8805:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;localhost:5001/foo&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="localhost:5001/foo"&gt;localhost:5001/foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8808:1-8808:36" dir="auto">Spaces are not allowed in autolinks:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8810:1-8814:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;http://foo.bar/baz bim&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&amp;lt;http://foo.bar/baz bim&amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8817:1-8817:47" dir="auto">Backslash-escapes do not work inside autolinks:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8819:1-8823:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;http://example.com/\[\&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://example.com/%5C%5B%5C"&gt;http://example.com/\[\&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8826:1-8829:55" dir="auto">An <a href="@">email autolink</a>
-consists of <code>&lt;</code>, followed by an [email address],
-followed by <code>&gt;</code>. The link's label is the email address,
-and the URL is <code>mailto:</code> followed by the email address.</p>
-<p data-sourcepos="8831:1-8834:83" dir="auto">An <a href="@">email address</a>,
-for these purposes, is anything that matches
-the <a href="https://html.spec.whatwg.org/multipage/forms.html#e-mail-state-(type=email)" rel="nofollow noreferrer noopener" target="_blank">non-normative regex from the HTML5
-spec</a>:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8836:5-8838:0" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">/^[a-zA-Z0-9.!#$%&amp;'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?</span>
-<span id="LC2" class="line" lang="plaintext">(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8839:1-8839:28" dir="auto">Examples of email autolinks:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8841:1-8845:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;foo@bar.example.com&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="mailto:foo@bar.example.com"&gt;foo@bar.example.com&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8848:1-8852:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;foo+special@Bar.baz-bar0.com&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="mailto:foo+special@Bar.baz-bar0.com"&gt;foo+special@Bar.baz-bar0.com&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8855:1-8855:53" dir="auto">Backslash-escapes do not work inside email autolinks:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8857:1-8861:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;foo\+@bar.example.com&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&amp;lt;foo+@bar.example.com&amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8864:1-8864:24" dir="auto">These are not autolinks:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8866:1-8870:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&amp;lt;&amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8873:1-8877:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt; http://foo.bar &gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&amp;lt; http://foo.bar &amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8880:1-8884:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;m:abc&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&amp;lt;m:abc&amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8887:1-8891:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;foo.bar.baz&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&amp;lt;foo.bar.baz&amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8894:1-8898:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">http://example.com</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;http://example.com&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8901:1-8905:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo@bar.example.com</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo@bar.example.com&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div>
-<h2 data-sourcepos="8909:1-8909:24">
-<a id="user-content-autolinks-extension" class="anchor" href="#autolinks-extension" aria-hidden="true"></a>Autolinks (extension)</h2>
-<p data-sourcepos="8911:1-8912:29">GFM enables the <code>autolink</code> extension, where autolinks will be recognised in a
-greater number of conditions.</p>
-<p data-sourcepos="8914:1-8918:8">[Autolink]s can also be constructed without requiring the use of <code>&lt;</code> and to <code>&gt;</code>
-to delimit them, although they will be recognized under a smaller set of
-circumstances. All such recognized autolinks can only come at the beginning of
-a line, after whitespace, or any of the delimiting characters <code>*</code>, <code>_</code>, <code>~</code>,
-and <code>(</code>.</p>
-<p data-sourcepos="8920:1-8926:73">An <a href="@">extended www autolink</a> will be recognized
-when the text <code>www.</code> is found followed by a [valid domain].
-A <a href="@">valid domain</a> consists of segments
-of alphanumeric characters, underscores (<code>_</code>) and hyphens (<code>-</code>)
-separated by periods (<code>.</code>).
-There must be at least one period,
-and no underscores may be present in the last two segments of the domain.</p>
-<p data-sourcepos="8928:1-8928:49">The scheme <code>http</code> will be inserted automatically:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8930:1-8934:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">www.commonmark.org</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://www.commonmark.org"&gt;www.commonmark.org&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8936:1-8936:77">After a [valid domain], zero or more non-space non-<code>&lt;</code> characters may follow:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8938:1-8942:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Visit www.commonmark.org/help for more information.</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;Visit &lt;a href="http://www.commonmark.org/help"&gt;www.commonmark.org/help&lt;/a&gt; for more information.&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8944:1-8944:64">We then apply <a href="@">extended autolink path validation</a> as follows:</p>
-<p data-sourcepos="8946:1-8948:21">Trailing punctuation (specifically, <code>?</code>, <code>!</code>, <code>.</code>, <code>,</code>, <code>:</code>, <code>*</code>, <code>_</code>, and <code>~</code>)
-will not be considered part of the autolink, though they may be included in the
-interior of the link:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8950:1-8957:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Visit www.commonmark.org.</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">Visit www.commonmark.org/a.b.</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;Visit &lt;a href="http://www.commonmark.org"&gt;www.commonmark.org&lt;/a&gt;.&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;Visit &lt;a href="http://www.commonmark.org/a.b"&gt;www.commonmark.org/a.b&lt;/a&gt;.&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8959:1-8962:76">When an autolink ends in <code>)</code>, we scan the entire autolink for the total number
-of parentheses. If there is a greater number of closing parentheses than
-opening ones, we don't consider the unmatched trailing parentheses part of the
-autolink, in order to facilitate including an autolink inside a parenthesis:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8964:1-8977:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">www.google.com/search?q=Markup+(business)</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">www.google.com/search?q=Markup+(business)))</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">(www.google.com/search?q=Markup+(business))</span>
-<span id="LC6" class="line" lang="plaintext"></span>
-<span id="LC7" class="line" lang="plaintext">(www.google.com/search?q=Markup+(business)</span>
-<span id="LC8" class="line" lang="plaintext">.</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://www.google.com/search?q=Markup+(business)"&gt;www.google.com/search?q=Markup+(business)&lt;/a&gt;&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://www.google.com/search?q=Markup+(business)"&gt;www.google.com/search?q=Markup+(business)&lt;/a&gt;))&lt;/p&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;p&gt;(&lt;a href="http://www.google.com/search?q=Markup+(business)"&gt;www.google.com/search?q=Markup+(business)&lt;/a&gt;)&lt;/p&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;p&gt;(&lt;a href="http://www.google.com/search?q=Markup+(business)"&gt;www.google.com/search?q=Markup+(business)&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8979:1-8981:8">This check is only done when the link ends in a closing parentheses <code>)</code>, so if
-the only parentheses are in the interior of the autolink, no special rules are
-applied:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8983:1-8987:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">www.google.com/search?q=(business))+ok</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://www.google.com/search?q=(business))+ok"&gt;www.google.com/search?q=(business))+ok&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="8989:1-8992:13">If an autolink ends in a semicolon (<code>;</code>), we check to see if it appears to
-resemble an [entity reference][entity references]; if the preceding text is <code>&amp;</code>
-followed by one or more alphanumeric characters. If so, it is excluded from
-the autolink:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="8994:1-9001:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">www.google.com/search?q=commonmark&amp;hl=en</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">www.google.com/search?q=commonmark&amp;hl;</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://www.google.com/search?q=commonmark&amp;amp;hl=en"&gt;www.google.com/search?q=commonmark&amp;amp;hl=en&lt;/a&gt;&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://www.google.com/search?q=commonmark"&gt;www.google.com/search?q=commonmark&lt;/a&gt;&amp;amp;hl;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9003:1-9003:33"><code>&lt;</code> immediately ends an autolink.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9005:1-9009:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">www.commonmark.org/he&lt;lp</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://www.commonmark.org/he"&gt;www.commonmark.org/he&lt;/a&gt;&amp;lt;lp&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9011:1-9014:36">An <a href="@">extended url autolink</a> will be recognised when one of the schemes
-<code>http://</code>, <code>https://</code>, or <code>ftp://</code>, followed by a [valid domain], then zero or
-more non-space non-<code>&lt;</code> characters according to
-[extended autolink path validation]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9016:1-9026:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">http://commonmark.org</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">(Visit https://encrypted.google.com/search?q=Markup+(business))</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">Anonymous FTP is available at ftp://foo.bar.baz.</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://commonmark.org"&gt;http://commonmark.org&lt;/a&gt;&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;(Visit &lt;a href="https://encrypted.google.com/search?q=Markup+(business)"&gt;https://encrypted.google.com/search?q=Markup+(business)&lt;/a&gt;)&lt;/p&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;Anonymous FTP is available at &lt;a href="ftp://foo.bar.baz"&gt;ftp://foo.bar.baz&lt;/a&gt;.&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9029:1-9031:20">An <a href="@">extended email autolink</a> will be recognised when an email address is
-recognised within any text node. Email addresses are recognised according to
-the following rules:</p>
-<ul data-sourcepos="9033:1-9039:0">
-<li data-sourcepos="9033:1-9033:75">One ore more characters which are alphanumeric, or <code>.</code>, <code>-</code>, <code>_</code>, or <code>+</code>.</li>
-<li data-sourcepos="9034:1-9034:16">An <code>@</code> symbol.</li>
-<li data-sourcepos="9035:1-9039:0">One or more characters which are alphanumeric, or <code>-</code> or <code>_</code>,
-separated by periods (<code>.</code>).
-There must be at least one period.
-The last character must not be one of <code>-</code> or <code>_</code>.</li>
-</ul>
-<p data-sourcepos="9040:1-9040:71">The scheme <code>mailto:</code> will automatically be added to the generated link:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9042:1-9046:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo@bar.baz</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="mailto:foo@bar.baz"&gt;foo@bar.baz&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9048:1-9048:44"><code>+</code> can occur before the <code>@</code>, but not after.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9050:1-9054:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">hello@mail+xyz.example isn't valid, but hello+xyz@mail.example is.</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;hello@mail+xyz.example isn't valid, but &lt;a href="mailto:hello+xyz@mail.example"&gt;hello+xyz@mail.example&lt;/a&gt; is.&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9056:1-9058:12"><code>.</code>, <code>-</code>, and <code>_</code> can occur on both sides of the <code>@</code>, but only <code>.</code> may occur at
-the end of the email address, in which case it will not be considered part of
-the address:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9060:1-9073:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">a.b-c_d@a.b</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">a.b-c_d@a.b.</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">a.b-c_d@a.b-</span>
-<span id="LC6" class="line" lang="plaintext"></span>
-<span id="LC7" class="line" lang="plaintext">a.b-c_d@a.b_</span>
-<span id="LC8" class="line" lang="plaintext">.</span>
-<span id="LC9" class="line" lang="plaintext">&lt;p&gt;&lt;a href="mailto:a.b-c_d@a.b"&gt;a.b-c_d@a.b&lt;/a&gt;&lt;/p&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;p&gt;&lt;a href="mailto:a.b-c_d@a.b"&gt;a.b-c_d@a.b&lt;/a&gt;.&lt;/p&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;p&gt;a.b-c_d@a.b-&lt;/p&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;p&gt;a.b-c_d@a.b_&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-</div>
-<h2 data-sourcepos="9077:1-9077:11" dir="auto">
-<a id="user-content-raw-html" class="anchor" href="#raw-html" aria-hidden="true"></a>Raw HTML</h2>
-<p data-sourcepos="9079:1-9082:57" dir="auto">Text between <code>&lt;</code> and <code>&gt;</code> that looks like an HTML tag is parsed as a
-raw HTML tag and will be rendered in HTML without escaping.
-Tag and attribute names are not limited to current HTML tags,
-so custom tags (and even, say, DocBook tags) may be used.</p>
-<p data-sourcepos="9084:1-9084:29" dir="auto">Here is the grammar for tags:</p>
-<p data-sourcepos="9086:1-9088:14" dir="auto">A <a href="@">tag name</a> consists of an ASCII letter
-followed by zero or more ASCII letters, digits, or
-hyphens (<code>-</code>).</p>
-<p data-sourcepos="9090:1-9092:32" dir="auto">An <a href="@">attribute</a> consists of [whitespace],
-an [attribute name], and an optional
-[attribute value specification].</p>
-<p data-sourcepos="9094:1-9097:52" dir="auto">An <a href="@">attribute name</a>
-consists of an ASCII letter, <code>_</code>, or <code>:</code>, followed by zero or more ASCII
-letters, digits, <code>_</code>, <code>.</code>, <code>:</code>, or <code>-</code>. (Note: This is the XML
-specification restricted to ASCII. HTML5 is laxer.)</p>
-<p data-sourcepos="9099:1-9102:7" dir="auto">An <a href="@">attribute value specification</a>
-consists of optional [whitespace],
-a <code>=</code> character, optional [whitespace], and an [attribute
-value].</p>
-<p data-sourcepos="9104:1-9106:72" dir="auto">An <a href="@">attribute value</a>
-consists of an [unquoted attribute value],
-a [single-quoted attribute value], or a [double-quoted attribute value].</p>
-<p data-sourcepos="9108:1-9110:60" dir="auto">An <a href="@">unquoted attribute value</a>
-is a nonempty string of characters not
-including [whitespace], <code>"</code>, <code>'</code>, <code>=</code>, <code>&lt;</code>, <code>&gt;</code>, or <code>`</code>.</p>
-<p data-sourcepos="9112:1-9114:46" dir="auto">A <a href="@">single-quoted attribute value</a>
-consists of <code>'</code>, zero or more
-characters not including <code>'</code>, and a final <code>'</code>.</p>
-<p data-sourcepos="9116:1-9118:46" dir="auto">A <a href="@">double-quoted attribute value</a>
-consists of <code>"</code>, zero or more
-characters not including <code>"</code>, and a final <code>"</code>.</p>
-<p data-sourcepos="9120:1-9122:31" dir="auto">An <a href="@">open tag</a> consists of a <code>&lt;</code> character, a [tag name],
-zero or more [attributes], optional [whitespace], an optional <code>/</code>
-character, and a <code>&gt;</code> character.</p>
-<p data-sourcepos="9124:1-9125:57" dir="auto">A <a href="@">closing tag</a> consists of the string <code>&lt;/</code>, a
-[tag name], optional [whitespace], and the character <code>&gt;</code>.</p>
-<p data-sourcepos="9127:1-9130:63" dir="auto">An <a href="@">HTML comment</a> consists of <code>&lt;!--</code> + <em>text</em> + <code>--&gt;</code>,
-where <em>text</em> does not start with <code>&gt;</code> or <code>-&gt;</code>, does not end with <code>-</code>,
-and does not contain <code>--</code>. (See the
-<a href="http://www.w3.org/TR/html5/syntax.html#comments" rel="nofollow noreferrer noopener" target="_blank">HTML5 spec</a>.)</p>
-<p data-sourcepos="9132:1-9135:5" dir="auto">A <a href="@">processing instruction</a>
-consists of the string <code>&lt;?</code>, a string
-of characters not including the string <code>?&gt;</code>, and the string
-<code>?&gt;</code>.</p>
-<p data-sourcepos="9137:1-9140:37" dir="auto">A <a href="@">declaration</a> consists of the
-string <code>&lt;!</code>, a name consisting of one or more uppercase ASCII letters,
-[whitespace], a string of characters not including the
-character <code>&gt;</code>, and the character <code>&gt;</code>.</p>
-<p data-sourcepos="9142:1-9144:28" dir="auto">A <a href="@">CDATA section</a> consists of
-the string <code>&lt;![CDATA[</code>, a string of characters not including the string
-<code>]]&gt;</code>, and the string <code>]]&gt;</code>.</p>
-<p data-sourcepos="9146:1-9148:21" dir="auto">An <a href="@">HTML tag</a> consists of an [open tag], a [closing tag],
-an [HTML comment], a [processing instruction], a [declaration],
-or a [CDATA section].</p>
-<p data-sourcepos="9150:1-9150:31" dir="auto">Here are some simple open tags:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9152:1-9156:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a&gt;&lt;bab&gt;&lt;c2c&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a&gt;&lt;bab&gt;&lt;c2c&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9159:1-9159:15" dir="auto">Empty elements:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9161:1-9165:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a/&gt;&lt;b2/&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a/&gt;&lt;b2/&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9168:1-9168:24" dir="auto">[Whitespace] is allowed:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9170:1-9176:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a /&gt;&lt;b2</span>
-<span id="LC2" class="line" lang="plaintext">data="foo" &gt;</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;a /&gt;&lt;b2</span>
-<span id="LC5" class="line" lang="plaintext">data="foo" &gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9179:1-9179:16" dir="auto">With attributes:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9181:1-9187:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a foo="bar" bam = 'baz &lt;em&gt;"&lt;/em&gt;'</span>
-<span id="LC2" class="line" lang="plaintext">_boolean zoop:33=zoop:33 /&gt;</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;a foo="bar" bam = 'baz &lt;em&gt;"&lt;/em&gt;'</span>
-<span id="LC5" class="line" lang="plaintext">_boolean zoop:33=zoop:33 /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9190:1-9190:29" dir="auto">Custom tag names can be used:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9192:1-9196:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo &lt;responsive-image src="foo.jpg" /&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;Foo &lt;responsive-image src="foo.jpg" /&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9199:1-9199:38" dir="auto">Illegal tag names, not parsed as HTML:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9201:1-9205:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;33&gt; &lt;__&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&amp;lt;33&amp;gt; &amp;lt;__&amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9208:1-9208:24" dir="auto">Illegal attribute names:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9210:1-9214:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a h*#ref="hi"&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&amp;lt;a h*#ref=&amp;quot;hi&amp;quot;&amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9217:1-9217:25" dir="auto">Illegal attribute values:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9219:1-9223:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="hi'&gt; &lt;a href=hi'&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&amp;lt;a href=&amp;quot;hi'&amp;gt; &amp;lt;a href=hi'&amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9226:1-9226:21" dir="auto">Illegal [whitespace]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9228:1-9238:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt; a&gt;&lt;</span>
-<span id="LC2" class="line" lang="plaintext">foo&gt;&lt;bar/ &gt;</span>
-<span id="LC3" class="line" lang="plaintext">&lt;foo bar=baz</span>
-<span id="LC4" class="line" lang="plaintext">bim!bop /&gt;</span>
-<span id="LC5" class="line" lang="plaintext">.</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;&amp;lt; a&amp;gt;&amp;lt;</span>
-<span id="LC7" class="line" lang="plaintext">foo&amp;gt;&amp;lt;bar/ &amp;gt;</span>
-<span id="LC8" class="line" lang="plaintext">&amp;lt;foo bar=baz</span>
-<span id="LC9" class="line" lang="plaintext">bim!bop /&amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9241:1-9241:21" dir="auto">Missing [whitespace]:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9243:1-9247:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href='bar'title=title&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&amp;lt;a href='bar'title=title&amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9250:1-9250:13" dir="auto">Closing tags:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9252:1-9256:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;/a&gt;&lt;/foo &gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;/a&gt;&lt;/foo &gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9259:1-9259:34" dir="auto">Illegal attributes in closing tag:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9261:1-9265:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;/a href="foo"&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&amp;lt;/a href=&amp;quot;foo&amp;quot;&amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9268:1-9268:9" dir="auto">Comments:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9270:1-9276:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;!-- this is a</span>
-<span id="LC2" class="line" lang="plaintext">comment - with hyphen --&gt;</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;foo &lt;!-- this is a</span>
-<span id="LC5" class="line" lang="plaintext">comment - with hyphen --&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9279:1-9283:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;!-- not a comment -- two hyphens --&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo &amp;lt;!-- not a comment -- two hyphens --&amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9286:1-9286:13" dir="auto">Not comments:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9288:1-9295:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;!--&gt; foo --&gt;</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">foo &lt;!-- foo---&gt;</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;foo &amp;lt;!--&amp;gt; foo --&amp;gt;&lt;/p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;p&gt;foo &amp;lt;!-- foo---&amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9298:1-9298:24" dir="auto">Processing instructions:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9300:1-9304:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;?php echo $a; ?&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo &lt;?php echo $a; ?&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9307:1-9307:13" dir="auto">Declarations:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9309:1-9313:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;!ELEMENT br EMPTY&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo &lt;!ELEMENT br EMPTY&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9316:1-9316:15" dir="auto">CDATA sections:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9318:1-9322:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;![CDATA[&gt;&amp;&lt;]]&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo &lt;![CDATA[&gt;&amp;&lt;]]&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9325:1-9326:11" dir="auto">Entity and numeric character references are preserved in HTML
-attributes:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9328:1-9332:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;a href="&amp;ouml;"&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo &lt;a href="&amp;ouml;"&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9335:1-9335:49" dir="auto">Backslash escapes do not work in HTML attributes:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9337:1-9341:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;a href="\*"&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo &lt;a href="\*"&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9344:1-9348:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="\""&gt;</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&amp;lt;a href=&amp;quot;&amp;quot;&amp;quot;&amp;gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div>
-<h2 data-sourcepos="9353:1-9353:34">
-<a id="user-content-disallowed-raw-html-extension" class="anchor" href="#disallowed-raw-html-extension" aria-hidden="true"></a>Disallowed Raw HTML (extension)</h2>
-<p data-sourcepos="9355:1-9356:36">GFM enables the <code>tagfilter</code> extension, where the following HTML tags will be
-filtered when rendering HTML output:</p>
-<ul data-sourcepos="9358:1-9367:0">
-<li data-sourcepos="9358:1-9358:11"><code>&lt;title&gt;</code></li>
-<li data-sourcepos="9359:1-9359:14"><code>&lt;textarea&gt;</code></li>
-<li data-sourcepos="9360:1-9360:11"><code>&lt;style&gt;</code></li>
-<li data-sourcepos="9361:1-9361:9"><code>&lt;xmp&gt;</code></li>
-<li data-sourcepos="9362:1-9362:12"><code>&lt;iframe&gt;</code></li>
-<li data-sourcepos="9363:1-9363:13"><code>&lt;noembed&gt;</code></li>
-<li data-sourcepos="9364:1-9364:14"><code>&lt;noframes&gt;</code></li>
-<li data-sourcepos="9365:1-9365:12"><code>&lt;script&gt;</code></li>
-<li data-sourcepos="9366:1-9367:0"><code>&lt;plaintext&gt;</code></li>
-</ul>
-<p data-sourcepos="9368:1-9371:71">Filtering is done by replacing the leading <code>&lt;</code> with the entity <code>&amp;lt;</code>. These
-tags are chosen in particular as they change how HTML is interpreted in a way
-unique to them (i.e. nested HTML is interpreted differently), and this is
-usually undesireable in the context of other rendered Markdown content.</p>
-<p data-sourcepos="9373:1-9373:39">All other HTML tags are left untouched.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9375:1-9386:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;strong&gt; &lt;title&gt; &lt;style&gt; &lt;em&gt;</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC4" class="line" lang="plaintext"> &lt;xmp&gt; is disallowed. &lt;XMP&gt; is also disallowed.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt; &amp;lt;title&gt; &amp;lt;style&gt; &lt;em&gt;&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;blockquote&gt;</span>
-<span id="LC9" class="line" lang="plaintext"> &amp;lt;xmp&gt; is disallowed. &amp;lt;XMP&gt; is also disallowed.</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-</div>
-<h2 data-sourcepos="9390:1-9390:19" dir="auto">
-<a id="user-content-hard-line-breaks" class="anchor" href="#hard-line-breaks" aria-hidden="true"></a>Hard line breaks</h2>
-<p data-sourcepos="9392:1-9395:27" dir="auto">A line break (not in a code span or HTML tag) that is preceded
-by two or more spaces and does not occur at the end of a block
-is parsed as a <a href="@">hard line break</a> (rendered
-in HTML as a <code>&lt;br /&gt;</code> tag):</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9397:1-9403:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo </span>
-<span id="LC2" class="line" lang="plaintext">baz</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;foo&lt;br /&gt;</span>
-<span id="LC5" class="line" lang="plaintext">baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9406:1-9407:48" dir="auto">For a more visible alternative, a backslash before the
-[line ending] may be used instead of two spaces:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9409:1-9415:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo\</span>
-<span id="LC2" class="line" lang="plaintext">baz</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;foo&lt;br /&gt;</span>
-<span id="LC5" class="line" lang="plaintext">baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9418:1-9418:33" dir="auto">More than two spaces can be used:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9420:1-9426:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo </span>
-<span id="LC2" class="line" lang="plaintext">baz</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;foo&lt;br /&gt;</span>
-<span id="LC5" class="line" lang="plaintext">baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9429:1-9429:61" dir="auto">Leading spaces at the beginning of the next line are ignored:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9431:1-9437:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo </span>
-<span id="LC2" class="line" lang="plaintext"> bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;foo&lt;br /&gt;</span>
-<span id="LC5" class="line" lang="plaintext">bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9440:1-9446:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo\</span>
-<span id="LC2" class="line" lang="plaintext"> bar</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;foo&lt;br /&gt;</span>
-<span id="LC5" class="line" lang="plaintext">bar&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9449:1-9450:26" dir="auto">Line breaks can occur inside emphasis, links, and other constructs
-that allow inline content:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9452:1-9458:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo </span>
-<span id="LC2" class="line" lang="plaintext">bar*</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;br /&gt;</span>
-<span id="LC5" class="line" lang="plaintext">bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9461:1-9467:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo\</span>
-<span id="LC2" class="line" lang="plaintext">bar*</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;br /&gt;</span>
-<span id="LC5" class="line" lang="plaintext">bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9470:1-9470:42" dir="auto">Line breaks do not occur inside code spans</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9472:1-9477:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`code </span>
-<span id="LC2" class="line" lang="plaintext">span`</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;code span&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9480:1-9485:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`code\</span>
-<span id="LC2" class="line" lang="plaintext">span`</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;code\ span&lt;/code&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9488:1-9488:13" dir="auto">or HTML tags:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9490:1-9496:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="foo </span>
-<span id="LC2" class="line" lang="plaintext">bar"&gt;</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo </span>
-<span id="LC5" class="line" lang="plaintext">bar"&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9499:1-9505:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="foo\</span>
-<span id="LC2" class="line" lang="plaintext">bar"&gt;</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo\</span>
-<span id="LC5" class="line" lang="plaintext">bar"&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9508:1-9510:20" dir="auto">Hard line breaks are for separating inline content within a block.
-Neither syntax for hard line breaks works at the end of a paragraph or
-other block element:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9512:1-9516:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo\</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo\&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9519:1-9523:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo </span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9526:1-9530:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">### foo\</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;h3&gt;foo\&lt;/h3&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9533:1-9537:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">### foo </span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;h3&gt;foo&lt;/h3&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="9540:1-9540:19" dir="auto">
-<a id="user-content-soft-line-breaks" class="anchor" href="#soft-line-breaks" aria-hidden="true"></a>Soft line breaks</h2>
-<p data-sourcepos="9542:1-9546:62" dir="auto">A regular line break (not in a code span or HTML tag) that is not
-preceded by two or more spaces or a backslash is parsed as a
-<a href="@">softbreak</a>. (A softbreak may be rendered in HTML either as a
-[line ending] or as a space. The result will be the same in
-browsers. In the examples here, a [line ending] will be used.)</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9548:1-9554:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span>
-<span id="LC2" class="line" lang="plaintext">baz</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;foo</span>
-<span id="LC5" class="line" lang="plaintext">baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9557:1-9558:8" dir="auto">Spaces at the end of the line and beginning of the next line are
-removed:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9560:1-9566:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo </span>
-<span id="LC2" class="line" lang="plaintext"> baz</span>
-<span id="LC3" class="line" lang="plaintext">.</span>
-<span id="LC4" class="line" lang="plaintext">&lt;p&gt;foo</span>
-<span id="LC5" class="line" lang="plaintext">baz&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9569:1-9570:25" dir="auto">A conforming parser may render a soft line break in HTML either as a
-line break or as a space.</p>
-<p data-sourcepos="9572:1-9573:20" dir="auto">A renderer may also provide an option to render soft line breaks
-as hard line breaks.</p>
-<h2 data-sourcepos="9575:1-9575:18" dir="auto">
-<a id="user-content-textual-content" class="anchor" href="#textual-content" aria-hidden="true"></a>Textual content</h2>
-<p data-sourcepos="9577:1-9578:35" dir="auto">Any characters not given an interpretation by the above rules will
-be parsed as plain textual content.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9580:1-9584:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">hello $.;'there</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;hello $.;'there&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9587:1-9591:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo χÏῆν</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;Foo χÏῆν&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9594:1-9594:39" dir="auto">Internal spaces are preserved verbatim:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9596:1-9600:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Multiple spaces</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;Multiple spaces&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h1 data-sourcepos="9603:1-9603:40" dir="auto">
-<a id="user-content-gitlab-official-specification-markdown" class="anchor" href="#gitlab-official-specification-markdown" aria-hidden="true"></a>GitLab Official Specification Markdown</h1>
-<p data-sourcepos="9605:1-9608:104" dir="auto">Currently, only some of the GitLab-specific markdown features are
-listed in this section. We will eventually add all
-GitLab-specific features currently listed as supported in the
-<a href="https://docs.gitlab.com/ee/user/markdown.html" rel="nofollow noreferrer noopener" target="_blank">user-facing documentation for GitLab Flavored Markdown</a>.</p>
-<p data-sourcepos="9610:1-9611:69" dir="auto">There is currently only this single top-level heading, but the
-examples may be split into multiple top-level headings in the future.</p>
-<h2 data-sourcepos="9613:1-9613:12" dir="auto">
-<a id="user-content-footnotes" class="anchor" href="#footnotes" aria-hidden="true"></a>Footnotes</h2>
-<p data-sourcepos="9615:1-9616:143" dir="auto">See
-<a href="https://docs.gitlab.com/ee/user/markdown.html#footnotes" rel="nofollow noreferrer noopener" target="_blank">the footnotes section of the user-facing documentation for GitLab Flavored Markdown</a>.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9618:1-9642:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">footnote reference tag [^fortytwo]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">[^fortytwo]: footnote text</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;</span>
-<span id="LC6" class="line" lang="plaintext">footnote reference tag</span>
-<span id="LC7" class="line" lang="plaintext">&lt;sup&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref&gt;</span>
-<span id="LC9" class="line" lang="plaintext">1</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/a&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/sup&gt;</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/p&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;section data-footnotes&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;ol&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;li id="fn-fortytwo-42"&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;p&gt;</span>
-<span id="LC17" class="line" lang="plaintext">footnote text</span>
-<span id="LC18" class="line" lang="plaintext">&lt;a href="#fnref-fortytwo-42" data-footnote-backref&gt;</span>
-<span id="LC19" class="line" lang="plaintext">&lt;/a&gt;</span>
-<span id="LC20" class="line" lang="plaintext">&lt;/p&gt;</span>
-<span id="LC21" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC22" class="line" lang="plaintext">&lt;/ol&gt;</span>
-<span id="LC23" class="line" lang="plaintext">&lt;/section&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="9644:1-9644:18" dir="auto">
-<a id="user-content-task-list-items" class="anchor" href="#task-list-items" aria-hidden="true"></a>Task list items</h2>
-<p data-sourcepos="9646:1-9647:117" dir="auto">See
-<a href="https://docs.gitlab.com/ee/user/markdown.html#task-lists" rel="nofollow noreferrer noopener" target="_blank">Task lists</a> in the GitLab Flavored Markdown documentation.</p>
-<p data-sourcepos="9649:1-9652:39" dir="auto">Task list items (checkboxes) are defined as a GitHub Flavored Markdown extension in a section above.
-GitLab extends the behavior of task list items to support additional features.
-Some of these features are in-progress, and should not yet be considered part of the official
-GitLab Flavored Markdown specification.</p>
-<p data-sourcepos="9654:1-9654:85" dir="auto">Some of the behavior of task list items is implemented as client-side JavaScript/CSS.</p>
-<p data-sourcepos="9656:1-9656:80" dir="auto">The following are some basic examples; more examples may be added in the future.</p>
-<p data-sourcepos="9658:1-9658:16" dir="auto">Incomplete task:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9660:1-9670:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [ ] incomplete</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC4" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;task-button/&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;input type="checkbox" disabled/&gt;</span>
-<span id="LC7" class="line" lang="plaintext">incomplete</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9672:1-9672:15" dir="auto">Completed task:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9674:1-9684:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [x] completed</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC4" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;task-button/&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;input type="checkbox" checked disabled/&gt;</span>
-<span id="LC7" class="line" lang="plaintext">completed</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9686:1-9686:18" dir="auto">Inapplicable task:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9688:1-9700:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [~] inapplicable</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC4" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC5" class="line" lang="plaintext">&lt;task-button/&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;input type="checkbox" data-inapplicable disabled&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;s&gt;</span>
-<span id="LC8" class="line" lang="plaintext">inapplicable</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/s&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9702:1-9703:50" dir="auto">Inapplicable task in a "loose" list. Note that the <code>&lt;del&gt;</code> tag is not applied to the
-loose text; it has strikethrough applied with CSS.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9705:1-9724:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [~] inapplicable</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"> text in loose list</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;task-button/&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;input type="checkbox" data-inapplicable disabled&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;s&gt;</span>
-<span id="LC11" class="line" lang="plaintext">inapplicable</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/s&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/p&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;p&gt;</span>
-<span id="LC15" class="line" lang="plaintext">text in loose list</span>
-<span id="LC16" class="line" lang="plaintext">&lt;/p&gt;</span>
-<span id="LC17" class="line" lang="plaintext">&lt;/li&gt;</span>
-<span id="LC18" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="9726:1-9726:15" dir="auto">
-<a id="user-content-front-matter" class="anchor" href="#front-matter" aria-hidden="true"></a>Front matter</h2>
-<p data-sourcepos="9728:1-9729:121" dir="auto">See
-<a href="https://docs.gitlab.com/ee/user/markdown.html#front-matter" rel="nofollow noreferrer noopener" target="_blank">Front matter</a> in the GitLab Flavored Markdown documentation.</p>
-<p data-sourcepos="9731:1-9732:95" dir="auto">Front matter is metadata included at the beginning of a Markdown document, preceding the content.
-This data can be used by static site generators like Jekyll, Hugo, and many other applications.</p>
-<p data-sourcepos="9734:1-9734:18" dir="auto">YAML front matter:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9736:1-9746:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">---</span>
-<span id="LC2" class="line" lang="plaintext">title: YAML front matter</span>
-<span id="LC3" class="line" lang="plaintext">---</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;code&gt;</span>
-<span id="LC7" class="line" lang="plaintext">title: YAML front matter</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9748:1-9748:18" dir="auto">TOML front matter:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9750:1-9760:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">+++</span>
-<span id="LC2" class="line" lang="plaintext">title: TOML front matter</span>
-<span id="LC3" class="line" lang="plaintext">+++</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;code&gt;</span>
-<span id="LC7" class="line" lang="plaintext">title: TOML front matter</span>
-<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9762:1-9762:18" dir="auto">JSON front matter:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9764:1-9778:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">;;;</span>
-<span id="LC2" class="line" lang="plaintext">{</span>
-<span id="LC3" class="line" lang="plaintext"> "title": "JSON front matter"</span>
-<span id="LC4" class="line" lang="plaintext">}</span>
-<span id="LC5" class="line" lang="plaintext">;;;</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;pre&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;code&gt;</span>
-<span id="LC9" class="line" lang="plaintext">{</span>
-<span id="LC10" class="line" lang="plaintext"> "title": "JSON front matter"</span>
-<span id="LC11" class="line" lang="plaintext">}</span>
-<span id="LC12" class="line" lang="plaintext">&lt;/code&gt;</span>
-<span id="LC13" class="line" lang="plaintext">&lt;/pre&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9780:1-9780:66" dir="auto">Front matter blocks should be inserted at the top of the document:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9782:1-9792:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">text</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">---</span>
-<span id="LC4" class="line" lang="plaintext">title: YAML front matter</span>
-<span id="LC5" class="line" lang="plaintext">---</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;text&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;hr&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;h2&gt;title: YAML front matter&lt;/h2&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9794:1-9794:74" dir="auto">Front matter block delimiters shouldn’t be preceded by space characters:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9796:1-9803:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ---</span>
-<span id="LC2" class="line" lang="plaintext">title: YAML front matter</span>
-<span id="LC3" class="line" lang="plaintext">---</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;hr&gt;</span>
-<span id="LC6" class="line" lang="plaintext">&lt;h2&gt;title: YAML front matter&lt;/h2&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="9805:1-9805:20" dir="auto">
-<a id="user-content-table-of-contents" class="anchor" href="#table-of-contents" aria-hidden="true"></a>Table of contents</h2>
-<p data-sourcepos="9807:1-9809:46" dir="auto">See
-<a href="https://docs.gitlab.com/ee/user/markdown.html#table-of-contents" rel="nofollow noreferrer noopener" target="_blank">table of contents</a>
-in the GitLab Flavored Markdown documentation.</p>
-<p data-sourcepos="9811:1-9812:58" dir="auto">A table of contents is an unordered list that links to subheadings in the document.
-Add either the <code>[[_TOC_]]</code> or </p><ul class="section-nav">
-<li><a href="#introduction">Introduction</a></li>
-<li>
-<a href="#preliminaries">Preliminaries</a><ul>
-<li><a href="#characters-and-lines">Characters and lines</a></li>
-<li><a href="#tabs">Tabs</a></li>
-<li><a href="#insecure-characters">Insecure characters</a></li>
-</ul>
-</li>
-<li>
-<a href="#blocks-and-inlines">Blocks and inlines</a><ul>
-<li><a href="#precedence">Precedence</a></li>
-<li><a href="#container-blocks-and-leaf-blocks">Container blocks and leaf blocks</a></li>
-</ul>
-</li>
-<li>
-<a href="#leaf-blocks">Leaf blocks</a><ul>
-<li><a href="#thematic-breaks">Thematic breaks</a></li>
-<li><a href="#atx-headings">ATX headings</a></li>
-<li><a href="#setext-headings">Setext headings</a></li>
-<li><a href="#indented-code-blocks">Indented code blocks</a></li>
-<li><a href="#fenced-code-blocks">Fenced code blocks</a></li>
-<li><a href="#html-blocks">HTML blocks</a></li>
-<li><a href="#link-reference-definitions">Link reference definitions</a></li>
-<li><a href="#paragraphs">Paragraphs</a></li>
-<li><a href="#blank-lines">Blank lines</a></li>
-<li><a href="#tables-extension">Tables (extension)</a></li>
-</ul>
-</li>
-<li>
-<a href="#container-blocks">Container blocks</a><ul>
-<li><a href="#block-quotes">Block quotes</a></li>
-<li>
-<a href="#list-items">List items</a><ul><li><a href="#motivation">Motivation</a></li></ul>
-</li>
-<li><a href="#task-list-items-extension">Task list items (extension)</a></li>
-<li><a href="#lists">Lists</a></li>
-</ul>
-</li>
-<li>
-<a href="#inlines">Inlines</a><ul>
-<li><a href="#backslash-escapes">Backslash escapes</a></li>
-<li><a href="#entity-and-numeric-character-references">Entity and numeric character references</a></li>
-<li><a href="#code-spans">Code spans</a></li>
-<li><a href="#emphasis-and-strong-emphasis">Emphasis and strong emphasis</a></li>
-<li><a href="#strikethrough-extension">Strikethrough (extension)</a></li>
-<li><a href="#links">Links</a></li>
-<li><a href="#images">Images</a></li>
-<li><a href="#autolinks">Autolinks</a></li>
-<li><a href="#autolinks-extension">Autolinks (extension)</a></li>
-<li><a href="#raw-html">Raw HTML</a></li>
-<li><a href="#disallowed-raw-html-extension">Disallowed Raw HTML (extension)</a></li>
-<li><a href="#hard-line-breaks">Hard line breaks</a></li>
-<li><a href="#soft-line-breaks">Soft line breaks</a></li>
-<li><a href="#textual-content">Textual content</a></li>
-</ul>
-</li>
-<li>
-<a href="#gitlab-official-specification-markdown">GitLab Official Specification Markdown</a><ul>
-<li><a href="#footnotes">Footnotes</a></li>
-<li><a href="#task-list-items">Task list items</a></li>
-<li><a href="#front-matter">Front matter</a></li>
-<li><a href="#table-of-contents">Table of contents</a></li>
-</ul>
-</li>
-<li>
-<a href="#gitlab-internal-extension-markdown">GitLab Internal Extension Markdown</a><ul>
-<li><a href="#audio">Audio</a></li>
-<li><a href="#video">Video</a></li>
-<li><a href="#markdown-preview-api-request-overrides">Markdown Preview API Request Overrides</a></li>
-</ul>
-</li>
-<li>
-<a href="#appendix-a-parsing-strategy">Appendix: A parsing strategy</a><ul>
-<li><a href="#overview">Overview</a></li>
-<li><a href="#phase-1-block-structure">Phase 1: block structure</a></li>
-<li>
-<a href="#phase-2-inline-structure">Phase 2: inline structure</a><ul><li>
-<a href="#an-algorithm-for-parsing-nested-emphasis-and-links">An algorithm for parsing nested emphasis and links</a><ul>
-<li><a href="#look-for-link-or-image">look for link or image</a></li>
-<li><a href="#process-emphasis">process emphasis</a></li>
-</ul>
-</li></ul>
-</li>
-</ul>
-</li>
-</ul> tag on its own line.
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9814:1-9831:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[TOC]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"># Heading 1</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">## Heading 2</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;nav&gt;</span>
-<span id="LC8" class="line" lang="plaintext"> &lt;ul&gt;</span>
-<span id="LC9" class="line" lang="plaintext"> &lt;li&gt;&lt;a href="#heading-1"&gt;Heading 1&lt;/a&gt;&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext"> &lt;ul&gt;</span>
-<span id="LC11" class="line" lang="plaintext"> &lt;li&gt;&lt;a href="#heading-2"&gt;Heading 2&lt;/a&gt;&lt;/li&gt;</span>
-<span id="LC12" class="line" lang="plaintext"> &lt;/ul&gt;</span>
-<span id="LC13" class="line" lang="plaintext"> &lt;/ul&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/nav&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;h1&gt;Heading 1&lt;/h1&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;h2&gt;Heading 2&lt;/h2&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9833:1-9850:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[[_TOC_]]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"># Heading 1</span>
-<span id="LC4" class="line" lang="plaintext"></span>
-<span id="LC5" class="line" lang="plaintext">## Heading 2</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;nav&gt;</span>
-<span id="LC8" class="line" lang="plaintext"> &lt;ul&gt;</span>
-<span id="LC9" class="line" lang="plaintext"> &lt;li&gt;&lt;a href="#heading-1"&gt;Heading 1&lt;/a&gt;&lt;/li&gt;</span>
-<span id="LC10" class="line" lang="plaintext"> &lt;ul&gt;</span>
-<span id="LC11" class="line" lang="plaintext"> &lt;li&gt;&lt;a href="#heading-2"&gt;Heading 2&lt;/a&gt;&lt;/li&gt;</span>
-<span id="LC12" class="line" lang="plaintext"> &lt;/ul&gt;</span>
-<span id="LC13" class="line" lang="plaintext"> &lt;/ul&gt;</span>
-<span id="LC14" class="line" lang="plaintext">&lt;/nav&gt;</span>
-<span id="LC15" class="line" lang="plaintext">&lt;h1&gt;Heading 1&lt;/h1&gt;</span>
-<span id="LC16" class="line" lang="plaintext">&lt;h2&gt;Heading 2&lt;/h2&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9852:1-9853:5" dir="auto">A table of contents is a block element. It should preceded and followed by a blank
-line.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9855:1-9864:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[[_TOC_]]</span>
-<span id="LC2" class="line" lang="plaintext">text</span>
-<span id="LC3" class="line" lang="plaintext"></span>
-<span id="LC4" class="line" lang="plaintext">text</span>
-<span id="LC5" class="line" lang="plaintext">[TOC]</span>
-<span id="LC6" class="line" lang="plaintext">.</span>
-<span id="LC7" class="line" lang="plaintext">&lt;p&gt;[[&lt;em&gt;TOC&lt;/em&gt;]]text&lt;/p&gt;</span>
-<span id="LC8" class="line" lang="plaintext">&lt;p&gt;text[TOC]&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9866:1-9866:60" dir="auto">A table of contents can be indented with up to three spaces.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9868:1-9879:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> [[_TOC_]]</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext"># Heading 1</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;nav&gt;</span>
-<span id="LC6" class="line" lang="plaintext"> &lt;ul&gt;</span>
-<span id="LC7" class="line" lang="plaintext"> &lt;li&gt;&lt;a href="#heading-1"&gt;Heading 1&lt;/a&gt;&lt;/li&gt;</span>
-<span id="LC8" class="line" lang="plaintext"> &lt;/ul&gt;</span>
-<span id="LC9" class="line" lang="plaintext">&lt;/nav&gt;</span>
-<span id="LC10" class="line" lang="plaintext">&lt;h1&gt;Heading 1&lt;/h1&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h1 data-sourcepos="9881:1-9881:36" dir="auto">
-<a id="user-content-gitlab-internal-extension-markdown" class="anchor" href="#gitlab-internal-extension-markdown" aria-hidden="true"></a>GitLab Internal Extension Markdown</h1>
-<h2 data-sourcepos="9883:1-9883:8" dir="auto">
-<a id="user-content-audio" class="anchor" href="#audio" aria-hidden="true"></a>Audio</h2>
-<p data-sourcepos="9885:1-9886:107" dir="auto">See
-<a href="https://docs.gitlab.com/ee/user/markdown.html#audio" rel="nofollow noreferrer noopener" target="_blank">audio</a> in the GitLab Flavored Markdown documentation.</p>
-<p data-sourcepos="9888:1-9890:63" dir="auto">GLFM renders image elements as an audio player as long as the resource’s file extension is
-one of the following supported audio extensions <code>.mp3</code>, <code>.oga</code>, <code>.ogg</code>, <code>.spx</code>, and <code>.wav</code>.
-Audio ignore the alternative text part of an image declaration.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9892:1-9896:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![audio](audio.oga "audio title")</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;audio src="audio.oga" title="audio title"&gt;&lt;/audio&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9898:1-9898:41" dir="auto">Reference definitions work audio as well:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9900:1-9906:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[audio]: audio.oga "audio title"</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">![audio][audio]</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;audio src="audio.oga" title="audio title"&gt;&lt;/audio&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="9908:1-9908:8" dir="auto">
-<a id="user-content-video" class="anchor" href="#video" aria-hidden="true"></a>Video</h2>
-<p data-sourcepos="9910:1-9911:109" dir="auto">See
-<a href="https://docs.gitlab.com/ee/user/markdown.html#videos" rel="nofollow noreferrer noopener" target="_blank">videos</a> in the GitLab Flavored Markdown documentation.</p>
-<p data-sourcepos="9913:1-9915:64" dir="auto">GLFM renders image elements as a video player as long as the resource’s file extension is
-one of the following supported video extensions <code>.mp4</code>, <code>.m4v</code>, <code>.mov</code>, <code>.webm</code>, and <code>.ogv</code>.
-Videos ignore the alternative text part of an image declaration.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9918:1-9922:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![video](video.m4v "video title")</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;video src="video.m4v" title="video title"&gt;&lt;/video&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9924:1-9924:41" dir="auto">Reference definitions work video as well:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9926:1-9932:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[video]: video.mov "video title"</span>
-<span id="LC2" class="line" lang="plaintext"></span>
-<span id="LC3" class="line" lang="plaintext">![video][video]</span>
-<span id="LC4" class="line" lang="plaintext">.</span>
-<span id="LC5" class="line" lang="plaintext">&lt;p&gt;&lt;video src="video.mov" title="video title"&gt;&lt;/video&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="9934:1-9934:41" dir="auto">
-<a id="user-content-markdown-preview-api-request-overrides" class="anchor" href="#markdown-preview-api-request-overrides" aria-hidden="true"></a>Markdown Preview API Request Overrides</h2>
-<p data-sourcepos="9936:1-9938:42" dir="auto">This section contains examples of all controllers which use <code>PreviewMarkdown</code> module
-and use different <code>markdown_context_params</code>. They exercise the various <code>preview_markdown</code>
-endpoints via <code>glfm_example_metadata.yml</code>.</p>
-<p data-sourcepos="9941:1-9941:75" dir="auto"><code>preview_markdown</code> exercising <code>groups</code> API endpoint and <code>UploadLinkFilter</code>:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9943:1-9947:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[groups-test-file](/uploads/groups-test-file)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="groups-test-file"&gt;groups-test-file&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9949:1-9949:81" dir="auto"><code>preview_markdown</code> exercising <code>projects</code> API endpoint and <code>RepositoryLinkFilter</code>:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9951:1-9955:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[projects-test-file](projects-test-file)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="projects-test-file"&gt;projects-test-file&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9957:1-9957:83" dir="auto"><code>preview_markdown</code> exercising <code>projects</code> API endpoint and <code>SnippetReferenceFilter</code>:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9959:1-9963:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This project snippet ID reference IS filtered: $88888</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;This project snippet ID reference IS filtered: $88888&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9965:1-9968:50" dir="auto"><code>preview_markdown</code> exercising personal (non-project) <code>snippets</code> API endpoint. This is
-only used by the comment field on personal snippets. It has no unique custom markdown
-extension behavior, and specifically does not render snippet references via
-<code>SnippetReferenceFilter</code>, even if the ID is valid.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9970:1-9974:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This personal snippet ID reference is not filtered: $99999</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;This personal snippet ID reference is not filtered: $99999&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9976:1-9976:80" dir="auto"><code>preview_markdown</code> exercising project <code>wikis</code> API endpoint and <code>WikiLinkFilter</code>:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9978:1-9982:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[project-wikis-test-file](project-wikis-test-file)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="project-wikis-test-file"&gt;project-wikis-test-file&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="9984:1-9985:63" dir="auto"><code>preview_markdown</code> exercising group <code>wikis</code> API endpoint and <code>WikiLinkFilter</code>. This example
-also requires an EE license enabling the <code>group_wikis</code> feature:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="9987:1-9991:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[group-wikis-test-file](group-wikis-test-file)</span>
-<span id="LC2" class="line" lang="plaintext">.</span>
-<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="group-wikis-test-file"&gt;group-wikis-test-file&lt;/a&gt;&lt;/p&gt;</span></code></pre>
-<copy-code></copy-code>
-</div>
-
-<h1 data-sourcepos="9995:1-9995:30" dir="auto">
-<a id="user-content-appendix-a-parsing-strategy" class="anchor" href="#appendix-a-parsing-strategy" aria-hidden="true"></a>Appendix: A parsing strategy</h1>
-<p data-sourcepos="9997:1-9998:49" dir="auto">In this appendix we describe some features of the parsing strategy
-used in the CommonMark reference implementations.</p>
-<h2 data-sourcepos="10000:1-10000:11" dir="auto">
-<a id="user-content-overview" class="anchor" href="#overview" aria-hidden="true"></a>Overview</h2>
-<p data-sourcepos="10002:1-10002:23" dir="auto">Parsing has two phases:</p>
-<ol data-sourcepos="10004:1-10014:0" dir="auto">
-<li data-sourcepos="10004:1-10009:0">
-<p data-sourcepos="10004:4-10008:28">In the first phase, lines of input are consumed and the block
-structure of the document---its division into paragraphs, block quotes,
-list items, and so on---is constructed. Text is assigned to these
-blocks but not parsed. Link reference definitions are parsed and a
-map of links is constructed.</p>
-</li>
-<li data-sourcepos="10010:1-10014:0">
-<p data-sourcepos="10010:4-10013:34">In the second phase, the raw text contents of paragraphs and headings
-are parsed into sequences of Markdown inline elements (strings,
-code spans, links, emphasis, and so on), using the map of link
-references constructed in phase 1.</p>
-</li>
-</ol>
-<p data-sourcepos="10015:1-10022:17" dir="auto">At each point in processing, the document is represented as a tree of
-<strong>blocks</strong>. The root of the tree is a <code>document</code> block. The <code>document</code>
-may have any number of other blocks as <strong>children</strong>. These children
-may, in turn, have other blocks as children. The last child of a block
-is normally considered <strong>open</strong>, meaning that subsequent lines of input
-can alter its contents. (Blocks that are not open are <strong>closed</strong>.)
-Here, for example, is a possible document tree, with the open blocks
-marked by arrows:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="10024:1-10036:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="tree" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-&gt; document</span>
-<span id="LC2" class="line" lang="plaintext"> -&gt; block_quote</span>
-<span id="LC3" class="line" lang="plaintext"> paragraph</span>
-<span id="LC4" class="line" lang="plaintext"> "Lorem ipsum dolor\nsit amet."</span>
-<span id="LC5" class="line" lang="plaintext"> -&gt; list (type=bullet tight=true bullet_char=-)</span>
-<span id="LC6" class="line" lang="plaintext"> list_item</span>
-<span id="LC7" class="line" lang="plaintext"> paragraph</span>
-<span id="LC8" class="line" lang="plaintext"> "Qui *quodsi iracundia*"</span>
-<span id="LC9" class="line" lang="plaintext"> -&gt; list_item</span>
-<span id="LC10" class="line" lang="plaintext"> -&gt; paragraph</span>
-<span id="LC11" class="line" lang="plaintext"> "aliquando id"</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="10038:1-10038:27" dir="auto">
-<a id="user-content-phase-1-block-structure" class="anchor" href="#phase-1-block-structure" aria-hidden="true"></a>Phase 1: block structure</h2>
-<p data-sourcepos="10040:1-10042:37" dir="auto">Each line that is processed has an effect on this tree. The line is
-analyzed and, depending on its contents, the document may be altered
-in one or more of the following ways:</p>
-<ol data-sourcepos="10044:1-10049:0" dir="auto">
-<li data-sourcepos="10044:1-10044:41">One or more open blocks may be closed.</li>
-<li data-sourcepos="10045:1-10046:19">One or more new blocks may be created as children of the
-last open block.</li>
-<li data-sourcepos="10047:1-10049:0">Text may be added to the last (deepest) open block remaining
-on the tree.</li>
-</ol>
-<p data-sourcepos="10050:1-10051:54" dir="auto">Once a line has been incorporated into the tree in this way,
-it can be discarded, so input can be read in a stream.</p>
-<p data-sourcepos="10053:1-10053:40" dir="auto">For each line, we follow this procedure:</p>
-<ol data-sourcepos="10055:1-10074:0" dir="auto">
-<li data-sourcepos="10055:1-10063:0">
-<p data-sourcepos="10055:4-10062:25">First we iterate through the open blocks, starting with the
-root document, and descending through last children down to the last
-open block. Each block imposes a condition that the line must satisfy
-if the block is to remain open. For example, a block quote requires a
-<code>&gt;</code> character. A paragraph requires a non-blank line.
-In this phase we may match all or just some of the open
-blocks. But we cannot close unmatched blocks yet, because we may have a
-[lazy continuation line].</p>
-</li>
-<li data-sourcepos="10064:1-10069:0">
-<p data-sourcepos="10064:5-10068:14">Next, after consuming the continuation markers for existing
-blocks, we look for new block starts (e.g. <code>&gt;</code> for a block quote).
-If we encounter a new block start, we close any blocks unmatched
-in step 1 before creating the new block as a child of the last
-matched block.</p>
-</li>
-<li data-sourcepos="10070:1-10074:0">
-<p data-sourcepos="10070:5-10073:54">Finally, we look at the remainder of the line (after block
-markers like <code>&gt;</code>, list markers, and indentation have been consumed).
-This is text that can be incorporated into the last open
-block (a paragraph, code block, heading, or raw HTML).</p>
-</li>
-</ol>
-<p data-sourcepos="10075:1-10076:37" dir="auto">Setext headings are formed when we see a line of a paragraph
-that is a [setext heading underline].</p>
-<p data-sourcepos="10078:1-10081:17" dir="auto">Reference link definitions are detected when a paragraph is closed;
-the accumulated text lines are parsed to see if they begin with
-one or more reference link definitions. Any remainder becomes a
-normal paragraph.</p>
-<p data-sourcepos="10083:1-10084:36" dir="auto">We can see how this works by considering how the tree above is
-generated by four lines of Markdown:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="10086:1-10091:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="gt">&gt; Lorem ipsum dolor</span></span>
-<span id="LC2" class="line" lang="markdown">sit amet.</span>
-<span id="LC3" class="line" lang="markdown"><span class="gt">&gt; - Qui *quodsi iracundia*</span></span>
-<span id="LC4" class="line" lang="markdown"><span class="gt">&gt; - aliquando id</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="10093:1-10093:41" dir="auto">At the outset, our document model is just</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="10095:1-10097:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="tree" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-&gt; document</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="10099:1-10099:27" dir="auto">The first line of our text,</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="10101:1-10103:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="gt">&gt; Lorem ipsum dolor</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="10105:1-10108:23" dir="auto">causes a <code>block_quote</code> block to be created as a child of our
-open <code>document</code> block, and a <code>paragraph</code> block as a child of
-the <code>block_quote</code>. Then the text is added to the last open
-block, the <code>paragraph</code>:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="10110:1-10115:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="tree" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-&gt; document</span>
-<span id="LC2" class="line" lang="plaintext"> -&gt; block_quote</span>
-<span id="LC3" class="line" lang="plaintext"> -&gt; paragraph</span>
-<span id="LC4" class="line" lang="plaintext"> "Lorem ipsum dolor"</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="10117:1-10117:14" dir="auto">The next line,</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="10119:1-10121:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown">sit amet.</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="10123:1-10124:24" dir="auto">is a "lazy continuation" of the open <code>paragraph</code>, so it gets added
-to the paragraph's text:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="10126:1-10131:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="tree" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-&gt; document</span>
-<span id="LC2" class="line" lang="plaintext"> -&gt; block_quote</span>
-<span id="LC3" class="line" lang="plaintext"> -&gt; paragraph</span>
-<span id="LC4" class="line" lang="plaintext"> "Lorem ipsum dolor\nsit amet."</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="10133:1-10133:15" dir="auto">The third line,</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="10135:1-10137:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="gt">&gt; - Qui *quodsi iracundia*</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="10139:1-10142:64" dir="auto">causes the <code>paragraph</code> block to be closed, and a new <code>list</code> block
-opened as a child of the <code>block_quote</code>. A <code>list_item</code> is also
-added as a child of the <code>list</code>, and a <code>paragraph</code> as a child of
-the <code>list_item</code>. The text is then added to the new <code>paragraph</code>:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="10144:1-10153:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="tree" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-&gt; document</span>
-<span id="LC2" class="line" lang="plaintext"> -&gt; block_quote</span>
-<span id="LC3" class="line" lang="plaintext"> paragraph</span>
-<span id="LC4" class="line" lang="plaintext"> "Lorem ipsum dolor\nsit amet."</span>
-<span id="LC5" class="line" lang="plaintext"> -&gt; list (type=bullet tight=true bullet_char=-)</span>
-<span id="LC6" class="line" lang="plaintext"> -&gt; list_item</span>
-<span id="LC7" class="line" lang="plaintext"> -&gt; paragraph</span>
-<span id="LC8" class="line" lang="plaintext"> "Qui *quodsi iracundia*"</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="10155:1-10155:16" dir="auto">The fourth line,</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="10157:1-10159:3" class="code highlight js-syntax-highlight language-markdown" lang="markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="gt">&gt; - aliquando id</span></span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="10161:1-10164:30" dir="auto">causes the <code>list_item</code> (and its child the <code>paragraph</code>) to be closed,
-and a new <code>list_item</code> opened up as child of the <code>list</code>. A <code>paragraph</code>
-is added as a child of the new <code>list_item</code>, to contain the text.
-We thus obtain the final tree:</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="10166:1-10178:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="tree" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-&gt; document</span>
-<span id="LC2" class="line" lang="plaintext"> -&gt; block_quote</span>
-<span id="LC3" class="line" lang="plaintext"> paragraph</span>
-<span id="LC4" class="line" lang="plaintext"> "Lorem ipsum dolor\nsit amet."</span>
-<span id="LC5" class="line" lang="plaintext"> -&gt; list (type=bullet tight=true bullet_char=-)</span>
-<span id="LC6" class="line" lang="plaintext"> list_item</span>
-<span id="LC7" class="line" lang="plaintext"> paragraph</span>
-<span id="LC8" class="line" lang="plaintext"> "Qui *quodsi iracundia*"</span>
-<span id="LC9" class="line" lang="plaintext"> -&gt; list_item</span>
-<span id="LC10" class="line" lang="plaintext"> -&gt; paragraph</span>
-<span id="LC11" class="line" lang="plaintext"> "aliquando id"</span></code></pre>
-<copy-code></copy-code>
-</div>
-<h2 data-sourcepos="10180:1-10180:28" dir="auto">
-<a id="user-content-phase-2-inline-structure" class="anchor" href="#phase-2-inline-structure" aria-hidden="true"></a>Phase 2: inline structure</h2>
-<p data-sourcepos="10182:1-10182:66" dir="auto">Once all of the input has been parsed, all open blocks are closed.</p>
-<p data-sourcepos="10184:1-10187:33" dir="auto">We then "walk the tree," visiting every node, and parse raw
-string contents of paragraphs and headings as inlines. At this
-point we have seen all the link reference definitions, so we can
-resolve reference links as we go.</p>
-<div class="gl-relative markdown-code-block js-markdown-code">
-<pre data-sourcepos="10189:1-10205:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="tree" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">document</span>
-<span id="LC2" class="line" lang="plaintext"> block_quote</span>
-<span id="LC3" class="line" lang="plaintext"> paragraph</span>
-<span id="LC4" class="line" lang="plaintext"> str "Lorem ipsum dolor"</span>
-<span id="LC5" class="line" lang="plaintext"> softbreak</span>
-<span id="LC6" class="line" lang="plaintext"> str "sit amet."</span>
-<span id="LC7" class="line" lang="plaintext"> list (type=bullet tight=true bullet_char=-)</span>
-<span id="LC8" class="line" lang="plaintext"> list_item</span>
-<span id="LC9" class="line" lang="plaintext"> paragraph</span>
-<span id="LC10" class="line" lang="plaintext"> str "Qui "</span>
-<span id="LC11" class="line" lang="plaintext"> emph</span>
-<span id="LC12" class="line" lang="plaintext"> str "quodsi iracundia"</span>
-<span id="LC13" class="line" lang="plaintext"> list_item</span>
-<span id="LC14" class="line" lang="plaintext"> paragraph</span>
-<span id="LC15" class="line" lang="plaintext"> str "aliquando id"</span></code></pre>
-<copy-code></copy-code>
-</div>
-<p data-sourcepos="10207:1-10209:22" dir="auto">Notice how the [line ending] in the first paragraph has
-been parsed as a <code>softbreak</code>, and the asterisks in the first list item
-have become an <code>emph</code>.</p>
-<h3 data-sourcepos="10211:1-10211:54" dir="auto">
-<a id="user-content-an-algorithm-for-parsing-nested-emphasis-and-links" class="anchor" href="#an-algorithm-for-parsing-nested-emphasis-and-links" aria-hidden="true"></a>An algorithm for parsing nested emphasis and links</h3>
-<p data-sourcepos="10213:1-10215:10" dir="auto">By far the trickiest part of inline parsing is handling emphasis,
-strong emphasis, links, and images. This is done using the following
-algorithm.</p>
-<p data-sourcepos="10217:1-10217:44" dir="auto">When we're parsing inlines and we hit either</p>
-<ul data-sourcepos="10219:1-10221:0" dir="auto">
-<li data-sourcepos="10219:1-10219:36">a run of <code>*</code> or <code>_</code> characters, or</li>
-<li data-sourcepos="10220:1-10221:0">a <code>[</code> or <code>![</code>
-</li>
-</ul>
-<p data-sourcepos="10222:1-10223:60" dir="auto">we insert a text node with these symbols as its literal content, and we
-add a pointer to this text node to the <a href="@">delimiter stack</a>.</p>
-<p data-sourcepos="10225:1-10226:65" dir="auto">The [delimiter stack] is a doubly linked list. Each
-element contains a pointer to a text node, plus information about</p>
-<ul data-sourcepos="10228:1-10234:0" dir="auto">
-<li data-sourcepos="10228:1-10228:45">the type of delimiter (<code>[</code>, <code>![</code>, <code>*</code>, <code>_</code>)</li>
-<li data-sourcepos="10229:1-10229:27">the number of delimiters,</li>
-<li data-sourcepos="10230:1-10230:66">whether the delimiter is "active" (all are active to start), and</li>
-<li data-sourcepos="10231:1-10234:0">whether the delimiter is a potential opener, a potential closer,
-or both (which depends on what sort of characters precede
-and follow the delimiters).</li>
-</ul>
-<p data-sourcepos="10235:1-10236:22" dir="auto">When we hit a <code>]</code> character, we call the <em>look for link or image</em>
-procedure (see below).</p>
-<p data-sourcepos="10238:1-10239:50" dir="auto">When we hit the end of the input, we call the <em>process emphasis</em>
-procedure (see below), with <code>stack_bottom</code> = NULL.</p>
-<h4 data-sourcepos="10241:1-10241:29" dir="auto">
-<a id="user-content-look-for-link-or-image" class="anchor" href="#look-for-link-or-image" aria-hidden="true"></a><em>look for link or image</em>
-</h4>
-<p data-sourcepos="10243:1-10244:55" dir="auto">Starting at the top of the delimiter stack, we look backwards
-through the stack for an opening <code>[</code> or <code>![</code> delimiter.</p>
-<ul data-sourcepos="10246:1-10271:0" dir="auto">
-<li data-sourcepos="10246:1-10247:0">
-<p data-sourcepos="10246:3-10246:58">If we don't find one, we return a literal text node <code>]</code>.</p>
-</li>
-<li data-sourcepos="10248:1-10250:0">
-<p data-sourcepos="10248:3-10249:63">If we do find one, but it's not <em>active</em>, we remove the inactive
-delimiter from the stack, and return a literal text node <code>]</code>.</p>
-</li>
-<li data-sourcepos="10251:1-10271:0">
-<p data-sourcepos="10251:3-10253:47">If we find one and it's active, then we parse ahead to see if
-we have an inline link/image, reference link/image, compact reference
-link/image, or shortcut reference link/image.</p>
-<ul data-sourcepos="10255:3-10271:0">
-<li data-sourcepos="10255:3-10257:0">
-<p data-sourcepos="10255:5-10256:55">If we don't, then we remove the opening delimiter from the
-delimiter stack and return a literal text node <code>]</code>.</p>
-</li>
-<li data-sourcepos="10258:3-10271:0">
-<p data-sourcepos="10258:5-10258:18">If we do, then</p>
-<ul data-sourcepos="10260:5-10271:0">
-<li data-sourcepos="10260:5-10262:0">
-<p data-sourcepos="10260:7-10261:62">We return a link or image node whose children are the inlines
-after the text node pointed to by the opening delimiter.</p>
-</li>
-<li data-sourcepos="10263:5-10265:0">
-<p data-sourcepos="10263:7-10264:24">We run <em>process emphasis</em> on these inlines, with the <code>[</code> opener
-as <code>stack_bottom</code>.</p>
-</li>
-<li data-sourcepos="10266:5-10267:0">
-<p data-sourcepos="10266:7-10266:38">We remove the opening delimiter.</p>
-</li>
-<li data-sourcepos="10268:5-10271:0">
-<p data-sourcepos="10268:7-10270:55">If we have a link (and not an image), we also set all
-<code>[</code> delimiters before the opening delimiter to <em>inactive</em>. (This
-will prevent us from getting links within links.)</p>
-</li>
-</ul>
-</li>
-</ul>
-</li>
-</ul>
-<h4 data-sourcepos="10272:1-10272:23" dir="auto">
-<a id="user-content-process-emphasis" class="anchor" href="#process-emphasis" aria-hidden="true"></a><em>process emphasis</em>
-</h4>
-<p data-sourcepos="10274:1-10277:24" dir="auto">Parameter <code>stack_bottom</code> sets a lower bound to how far we
-descend in the [delimiter stack]. If it is NULL, we can
-go all the way to the bottom. Otherwise, we stop before
-visiting <code>stack_bottom</code>.</p>
-<p data-sourcepos="10279:1-10281:9" dir="auto">Let <code>current_position</code> point to the element on the [delimiter stack]
-just above <code>stack_bottom</code> (or the first element if <code>stack_bottom</code>
-is NULL).</p>
-<p data-sourcepos="10283:1-10285:47" dir="auto">We keep track of the <code>openers_bottom</code> for each delimiter
-type (<code>*</code>, <code>_</code>) and each length of the closing delimiter run
-(modulo 3). Initialize this to <code>stack_bottom</code>.</p>
-<p data-sourcepos="10287:1-10288:8" dir="auto">Then we repeat the following until we run out of potential
-closers:</p>
-<ul data-sourcepos="10290:1-10328:0" dir="auto">
-<li data-sourcepos="10290:1-10294:0">
-<p data-sourcepos="10290:3-10293:65">Move <code>current_position</code> forward in the delimiter stack (if needed)
-until we find the first potential closer with delimiter <code>*</code> or <code>_</code>.
-(This will be the potential closer closest
-to the beginning of the input -- the first one in parse order.)</p>
-</li>
-<li data-sourcepos="10295:1-10298:0">
-<p data-sourcepos="10295:3-10297:68">Now, look back in the stack (staying above <code>stack_bottom</code> and
-the <code>openers_bottom</code> for this delimiter type) for the
-first matching potential opener ("matching" means same delimiter).</p>
-</li>
-<li data-sourcepos="10299:1-10316:0">
-<p data-sourcepos="10299:3-10299:18">If one is found:</p>
-<ul data-sourcepos="10301:3-10316:0">
-<li data-sourcepos="10301:3-10304:0">
-<p data-sourcepos="10301:5-10303:30">Figure out whether we have emphasis or strong emphasis:
-if both closer and opener spans have length &gt;= 2, we have
-strong, otherwise regular.</p>
-</li>
-<li data-sourcepos="10305:3-10307:0">
-<p data-sourcepos="10305:5-10306:46">Insert an emph or strong emph node accordingly, after
-the text node corresponding to the opener.</p>
-</li>
-<li data-sourcepos="10308:3-10310:0">
-<p data-sourcepos="10308:5-10309:24">Remove any delimiters between the opener and closer from
-the delimiter stack.</p>
-</li>
-<li data-sourcepos="10311:3-10316:0">
-<p data-sourcepos="10311:5-10315:56">Remove 1 (for regular emph) or 2 (for strong emph) delimiters
-from the opening and closing text nodes. If they become empty
-as a result, remove them and remove the corresponding element
-of the delimiter stack. If the closing node is removed, reset
-<code>current_position</code> to the next element in the stack.</p>
-</li>
-</ul>
-</li>
-<li data-sourcepos="10317:1-10328:0">
-<p data-sourcepos="10317:3-10317:19">If none is found:</p>
-<ul data-sourcepos="10319:3-10328:0">
-<li data-sourcepos="10319:3-10322:0">
-<p data-sourcepos="10319:5-10321:73">Set <code>openers_bottom</code> to the element before <code>current_position</code>.
-(We know that there are no openers for this kind of closer up to and
-including this point, so this puts a lower bound on future searches.)</p>
-</li>
-<li data-sourcepos="10323:3-10326:0">
-<p data-sourcepos="10323:5-10325:24">If the closer at <code>current_position</code> is not a potential opener,
-remove it from the delimiter stack (since we know it can't
-be a closer either).</p>
-</li>
-<li data-sourcepos="10327:3-10328:0">
-<p data-sourcepos="10327:5-10327:64">Advance <code>current_position</code> to the next element in the stack.</p>
-</li>
-</ul>
-</li>
-</ul>
-<p data-sourcepos="10329:1-10330:16" dir="auto">After we're done, we remove all delimiters above <code>stack_bottom</code> from the
-delimiter stack.</p>
diff --git a/glfm_specification/output/spec.txt b/glfm_specification/output/spec.txt
deleted file mode 100644
index a8565b15bc3..00000000000
--- a/glfm_specification/output/spec.txt
+++ /dev/null
@@ -1,10330 +0,0 @@
----
-title: GitLab Flavored Markdown (GLFM) Spec
-version: alpha
-...
-
-# Introduction
-
-TODO: Write a GitLab-specific version of the GitHub Flavored Markdown intro section.
-
-# Preliminaries
-
-## Characters and lines
-
-Any sequence of [characters] is a valid CommonMark
-document.
-
-A [character](@) is a Unicode code point. Although some
-code points (for example, combining accents) do not correspond to
-characters in an intuitive sense, all code points count as characters
-for purposes of this spec.
-
-This spec does not specify an encoding; it thinks of lines as composed
-of [characters] rather than bytes. A conforming parser may be limited
-to a certain encoding.
-
-A [line](@) is a sequence of zero or more [characters]
-other than newline (`U+000A`) or carriage return (`U+000D`),
-followed by a [line ending] or by the end of file.
-
-A [line ending](@) is a newline (`U+000A`), a carriage return
-(`U+000D`) not followed by a newline, or a carriage return and a
-following newline.
-
-A line containing no characters, or a line containing only spaces
-(`U+0020`) or tabs (`U+0009`), is called a [blank line](@).
-
-The following definitions of character classes will be used in this spec:
-
-A [whitespace character](@) is a space
-(`U+0020`), tab (`U+0009`), newline (`U+000A`), line tabulation (`U+000B`),
-form feed (`U+000C`), or carriage return (`U+000D`).
-
-[Whitespace](@) is a sequence of one or more [whitespace
-characters].
-
-A [Unicode whitespace character](@) is
-any code point in the Unicode `Zs` general category, or a tab (`U+0009`),
-carriage return (`U+000D`), newline (`U+000A`), or form feed
-(`U+000C`).
-
-[Unicode whitespace](@) is a sequence of one
-or more [Unicode whitespace characters].
-
-A [space](@) is `U+0020`.
-
-A [non-whitespace character](@) is any character
-that is not a [whitespace character].
-
-An [ASCII punctuation character](@)
-is `!`, `"`, `#`, `$`, `%`, `&`, `'`, `(`, `)`,
-`*`, `+`, `,`, `-`, `.`, `/` (U+0021–2F),
-`:`, `;`, `<`, `=`, `>`, `?`, `@` (U+003A–0040),
-`[`, `\`, `]`, `^`, `_`, `` ` `` (U+005B–0060),
-`{`, `|`, `}`, or `~` (U+007B–007E).
-
-A [punctuation character](@) is an [ASCII
-punctuation character] or anything in
-the general Unicode categories `Pc`, `Pd`, `Pe`, `Pf`, `Pi`, `Po`, or `Ps`.
-
-## Tabs
-
-Tabs in lines are not expanded to [spaces]. However,
-in contexts where whitespace helps to define block structure,
-tabs behave as if they were replaced by spaces with a tab stop
-of 4 characters.
-
-Thus, for example, a tab can be used instead of four spaces
-in an indented code block. (Note, however, that internal
-tabs are passed through as literal tabs, not expanded to
-spaces.)
-
-```````````````````````````````` example
-→foo→baz→→bim
-.
-<pre><code>foo→baz→→bim
-</code></pre>
-````````````````````````````````
-
-```````````````````````````````` example
- →foo→baz→→bim
-.
-<pre><code>foo→baz→→bim
-</code></pre>
-````````````````````````````````
-
-```````````````````````````````` example
- a→a
- á½â†’a
-.
-<pre><code>a→a
-á½â†’a
-</code></pre>
-````````````````````````````````
-
-In the following example, a continuation paragraph of a list
-item is indented with a tab; this has exactly the same effect
-as indentation with four spaces would:
-
-```````````````````````````````` example
- - foo
-
-→bar
-.
-<ul>
-<li>
-<p>foo</p>
-<p>bar</p>
-</li>
-</ul>
-````````````````````````````````
-
-```````````````````````````````` example
-- foo
-
-→→bar
-.
-<ul>
-<li>
-<p>foo</p>
-<pre><code> bar
-</code></pre>
-</li>
-</ul>
-````````````````````````````````
-
-Normally the `>` that begins a block quote may be followed
-optionally by a space, which is not considered part of the
-content. In the following case `>` is followed by a tab,
-which is treated as if it were expanded into three spaces.
-Since one of these spaces is considered part of the
-delimiter, `foo` is considered to be indented six spaces
-inside the block quote context, so we get an indented
-code block starting with two spaces.
-
-```````````````````````````````` example
->→→foo
-.
-<blockquote>
-<pre><code> foo
-</code></pre>
-</blockquote>
-````````````````````````````````
-
-```````````````````````````````` example
--→→foo
-.
-<ul>
-<li>
-<pre><code> foo
-</code></pre>
-</li>
-</ul>
-````````````````````````````````
-
-
-```````````````````````````````` example
- foo
-→bar
-.
-<pre><code>foo
-bar
-</code></pre>
-````````````````````````````````
-
-```````````````````````````````` example
- - foo
- - bar
-→ - baz
-.
-<ul>
-<li>foo
-<ul>
-<li>bar
-<ul>
-<li>baz</li>
-</ul>
-</li>
-</ul>
-</li>
-</ul>
-````````````````````````````````
-
-```````````````````````````````` example
-#→Foo
-.
-<h1>Foo</h1>
-````````````````````````````````
-
-```````````````````````````````` example
-*→*→*→
-.
-<hr />
-````````````````````````````````
-
-
-## Insecure characters
-
-For security reasons, the Unicode character `U+0000` must be replaced
-with the REPLACEMENT CHARACTER (`U+FFFD`).
-
-# Blocks and inlines
-
-We can think of a document as a sequence of
-[blocks](@)---structural elements like paragraphs, block
-quotations, lists, headings, rules, and code blocks. Some blocks (like
-block quotes and list items) contain other blocks; others (like
-headings and paragraphs) contain [inline](@) content---text,
-links, emphasized text, images, code spans, and so on.
-
-## Precedence
-
-Indicators of block structure always take precedence over indicators
-of inline structure. So, for example, the following is a list with
-two items, not a list with one item containing a code span:
-
-```````````````````````````````` example
-- `one
-- two`
-.
-<ul>
-<li>`one</li>
-<li>two`</li>
-</ul>
-````````````````````````````````
-
-
-This means that parsing can proceed in two steps: first, the block
-structure of the document can be discerned; second, text lines inside
-paragraphs, headings, and other block constructs can be parsed for inline
-structure. The second step requires information about link reference
-definitions that will be available only at the end of the first
-step. Note that the first step requires processing lines in sequence,
-but the second can be parallelized, since the inline parsing of
-one block element does not affect the inline parsing of any other.
-
-## Container blocks and leaf blocks
-
-We can divide blocks into two types:
-[container blocks](@),
-which can contain other blocks, and [leaf blocks](@),
-which cannot.
-
-# Leaf blocks
-
-This section describes the different kinds of leaf block that make up a
-Markdown document.
-
-## Thematic breaks
-
-A line consisting of 0-3 spaces of indentation, followed by a sequence
-of three or more matching `-`, `_`, or `*` characters, each followed
-optionally by any number of spaces or tabs, forms a
-[thematic break](@).
-
-```````````````````````````````` example
-***
----
-___
-.
-<hr />
-<hr />
-<hr />
-````````````````````````````````
-
-
-Wrong characters:
-
-```````````````````````````````` example
-+++
-.
-<p>+++</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-===
-.
-<p>===</p>
-````````````````````````````````
-
-
-Not enough characters:
-
-```````````````````````````````` example
---
-**
-__
-.
-<p>--
-**
-__</p>
-````````````````````````````````
-
-
-One to three spaces indent are allowed:
-
-```````````````````````````````` example
- ***
- ***
- ***
-.
-<hr />
-<hr />
-<hr />
-````````````````````````````````
-
-
-Four spaces is too many:
-
-```````````````````````````````` example
- ***
-.
-<pre><code>***
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
-Foo
- ***
-.
-<p>Foo
-***</p>
-````````````````````````````````
-
-
-More than three characters may be used:
-
-```````````````````````````````` example
-_____________________________________
-.
-<hr />
-````````````````````````````````
-
-
-Spaces are allowed between the characters:
-
-```````````````````````````````` example
- - - -
-.
-<hr />
-````````````````````````````````
-
-
-```````````````````````````````` example
- ** * ** * ** * **
-.
-<hr />
-````````````````````````````````
-
-
-```````````````````````````````` example
-- - - -
-.
-<hr />
-````````````````````````````````
-
-
-Spaces are allowed at the end:
-
-```````````````````````````````` example
-- - - -
-.
-<hr />
-````````````````````````````````
-
-
-However, no other characters may occur in the line:
-
-```````````````````````````````` example
-_ _ _ _ a
-
-a------
-
----a---
-.
-<p>_ _ _ _ a</p>
-<p>a------</p>
-<p>---a---</p>
-````````````````````````````````
-
-
-It is required that all of the [non-whitespace characters] be the same.
-So, this is not a thematic break:
-
-```````````````````````````````` example
- *-*
-.
-<p><em>-</em></p>
-````````````````````````````````
-
-
-Thematic breaks do not need blank lines before or after:
-
-```````````````````````````````` example
-- foo
-***
-- bar
-.
-<ul>
-<li>foo</li>
-</ul>
-<hr />
-<ul>
-<li>bar</li>
-</ul>
-````````````````````````````````
-
-
-Thematic breaks can interrupt a paragraph:
-
-```````````````````````````````` example
-Foo
-***
-bar
-.
-<p>Foo</p>
-<hr />
-<p>bar</p>
-````````````````````````````````
-
-
-If a line of dashes that meets the above conditions for being a
-thematic break could also be interpreted as the underline of a [setext
-heading], the interpretation as a
-[setext heading] takes precedence. Thus, for example,
-this is a setext heading, not a paragraph followed by a thematic break:
-
-```````````````````````````````` example
-Foo
----
-bar
-.
-<h2>Foo</h2>
-<p>bar</p>
-````````````````````````````````
-
-
-When both a thematic break and a list item are possible
-interpretations of a line, the thematic break takes precedence:
-
-```````````````````````````````` example
-* Foo
-* * *
-* Bar
-.
-<ul>
-<li>Foo</li>
-</ul>
-<hr />
-<ul>
-<li>Bar</li>
-</ul>
-````````````````````````````````
-
-
-If you want a thematic break in a list item, use a different bullet:
-
-```````````````````````````````` example
-- Foo
-- * * *
-.
-<ul>
-<li>Foo</li>
-<li>
-<hr />
-</li>
-</ul>
-````````````````````````````````
-
-
-## ATX headings
-
-An [ATX heading](@)
-consists of a string of characters, parsed as inline content, between an
-opening sequence of 1--6 unescaped `#` characters and an optional
-closing sequence of any number of unescaped `#` characters.
-The opening sequence of `#` characters must be followed by a
-[space] or by the end of line. The optional closing sequence of `#`s must be
-preceded by a [space] and may be followed by spaces only. The opening
-`#` character may be indented 0-3 spaces. The raw contents of the
-heading are stripped of leading and trailing spaces before being parsed
-as inline content. The heading level is equal to the number of `#`
-characters in the opening sequence.
-
-Simple headings:
-
-```````````````````````````````` example
-# foo
-## foo
-### foo
-#### foo
-##### foo
-###### foo
-.
-<h1>foo</h1>
-<h2>foo</h2>
-<h3>foo</h3>
-<h4>foo</h4>
-<h5>foo</h5>
-<h6>foo</h6>
-````````````````````````````````
-
-
-More than six `#` characters is not a heading:
-
-```````````````````````````````` example
-####### foo
-.
-<p>####### foo</p>
-````````````````````````````````
-
-
-At least one space is required between the `#` characters and the
-heading's contents, unless the heading is empty. Note that many
-implementations currently do not require the space. However, the
-space was required by the
-[original ATX implementation](http://www.aaronsw.com/2002/atx/atx.py),
-and it helps prevent things like the following from being parsed as
-headings:
-
-```````````````````````````````` example
-#5 bolt
-
-#hashtag
-.
-<p>#5 bolt</p>
-<p>#hashtag</p>
-````````````````````````````````
-
-
-This is not a heading, because the first `#` is escaped:
-
-```````````````````````````````` example
-\## foo
-.
-<p>## foo</p>
-````````````````````````````````
-
-
-Contents are parsed as inlines:
-
-```````````````````````````````` example
-# foo *bar* \*baz\*
-.
-<h1>foo <em>bar</em> *baz*</h1>
-````````````````````````````````
-
-
-Leading and trailing [whitespace] is ignored in parsing inline content:
-
-```````````````````````````````` example
-# foo
-.
-<h1>foo</h1>
-````````````````````````````````
-
-
-One to three spaces indentation are allowed:
-
-```````````````````````````````` example
- ### foo
- ## foo
- # foo
-.
-<h3>foo</h3>
-<h2>foo</h2>
-<h1>foo</h1>
-````````````````````````````````
-
-
-Four spaces are too much:
-
-```````````````````````````````` example
- # foo
-.
-<pre><code># foo
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
-foo
- # bar
-.
-<p>foo
-# bar</p>
-````````````````````````````````
-
-
-A closing sequence of `#` characters is optional:
-
-```````````````````````````````` example
-## foo ##
- ### bar ###
-.
-<h2>foo</h2>
-<h3>bar</h3>
-````````````````````````````````
-
-
-It need not be the same length as the opening sequence:
-
-```````````````````````````````` example
-# foo ##################################
-##### foo ##
-.
-<h1>foo</h1>
-<h5>foo</h5>
-````````````````````````````````
-
-
-Spaces are allowed after the closing sequence:
-
-```````````````````````````````` example
-### foo ###
-.
-<h3>foo</h3>
-````````````````````````````````
-
-
-A sequence of `#` characters with anything but [spaces] following it
-is not a closing sequence, but counts as part of the contents of the
-heading:
-
-```````````````````````````````` example
-### foo ### b
-.
-<h3>foo ### b</h3>
-````````````````````````````````
-
-
-The closing sequence must be preceded by a space:
-
-```````````````````````````````` example
-# foo#
-.
-<h1>foo#</h1>
-````````````````````````````````
-
-
-Backslash-escaped `#` characters do not count as part
-of the closing sequence:
-
-```````````````````````````````` example
-### foo \###
-## foo #\##
-# foo \#
-.
-<h3>foo ###</h3>
-<h2>foo ###</h2>
-<h1>foo #</h1>
-````````````````````````````````
-
-
-ATX headings need not be separated from surrounding content by blank
-lines, and they can interrupt paragraphs:
-
-```````````````````````````````` example
-****
-## foo
-****
-.
-<hr />
-<h2>foo</h2>
-<hr />
-````````````````````````````````
-
-
-```````````````````````````````` example
-Foo bar
-# baz
-Bar foo
-.
-<p>Foo bar</p>
-<h1>baz</h1>
-<p>Bar foo</p>
-````````````````````````````````
-
-
-ATX headings can be empty:
-
-```````````````````````````````` example
-##
-#
-### ###
-.
-<h2></h2>
-<h1></h1>
-<h3></h3>
-````````````````````````````````
-
-
-## Setext headings
-
-A [setext heading](@) consists of one or more
-lines of text, each containing at least one [non-whitespace
-character], with no more than 3 spaces indentation, followed by
-a [setext heading underline]. The lines of text must be such
-that, were they not followed by the setext heading underline,
-they would be interpreted as a paragraph: they cannot be
-interpretable as a [code fence], [ATX heading][ATX headings],
-[block quote][block quotes], [thematic break][thematic breaks],
-[list item][list items], or [HTML block][HTML blocks].
-
-A [setext heading underline](@) is a sequence of
-`=` characters or a sequence of `-` characters, with no more than 3
-spaces indentation and any number of trailing spaces. If a line
-containing a single `-` can be interpreted as an
-empty [list items], it should be interpreted this way
-and not as a [setext heading underline].
-
-The heading is a level 1 heading if `=` characters are used in
-the [setext heading underline], and a level 2 heading if `-`
-characters are used. The contents of the heading are the result
-of parsing the preceding lines of text as CommonMark inline
-content.
-
-In general, a setext heading need not be preceded or followed by a
-blank line. However, it cannot interrupt a paragraph, so when a
-setext heading comes after a paragraph, a blank line is needed between
-them.
-
-Simple examples:
-
-```````````````````````````````` example
-Foo *bar*
-=========
-
-Foo *bar*
----------
-.
-<h1>Foo <em>bar</em></h1>
-<h2>Foo <em>bar</em></h2>
-````````````````````````````````
-
-
-The content of the header may span more than one line:
-
-```````````````````````````````` example
-Foo *bar
-baz*
-====
-.
-<h1>Foo <em>bar
-baz</em></h1>
-````````````````````````````````
-
-The contents are the result of parsing the headings's raw
-content as inlines. The heading's raw content is formed by
-concatenating the lines and removing initial and final
-[whitespace].
-
-```````````````````````````````` example
- Foo *bar
-baz*→
-====
-.
-<h1>Foo <em>bar
-baz</em></h1>
-````````````````````````````````
-
-
-The underlining can be any length:
-
-```````````````````````````````` example
-Foo
--------------------------
-
-Foo
-=
-.
-<h2>Foo</h2>
-<h1>Foo</h1>
-````````````````````````````````
-
-
-The heading content can be indented up to three spaces, and need
-not line up with the underlining:
-
-```````````````````````````````` example
- Foo
----
-
- Foo
------
-
- Foo
- ===
-.
-<h2>Foo</h2>
-<h2>Foo</h2>
-<h1>Foo</h1>
-````````````````````````````````
-
-
-Four spaces indent is too much:
-
-```````````````````````````````` example
- Foo
- ---
-
- Foo
----
-.
-<pre><code>Foo
----
-
-Foo
-</code></pre>
-<hr />
-````````````````````````````````
-
-
-The setext heading underline can be indented up to three spaces, and
-may have trailing spaces:
-
-```````````````````````````````` example
-Foo
- ----
-.
-<h2>Foo</h2>
-````````````````````````````````
-
-
-Four spaces is too much:
-
-```````````````````````````````` example
-Foo
- ---
-.
-<p>Foo
----</p>
-````````````````````````````````
-
-
-The setext heading underline cannot contain internal spaces:
-
-```````````````````````````````` example
-Foo
-= =
-
-Foo
---- -
-.
-<p>Foo
-= =</p>
-<p>Foo</p>
-<hr />
-````````````````````````````````
-
-
-Trailing spaces in the content line do not cause a line break:
-
-```````````````````````````````` example
-Foo
------
-.
-<h2>Foo</h2>
-````````````````````````````````
-
-
-Nor does a backslash at the end:
-
-```````````````````````````````` example
-Foo\
-----
-.
-<h2>Foo\</h2>
-````````````````````````````````
-
-
-Since indicators of block structure take precedence over
-indicators of inline structure, the following are setext headings:
-
-```````````````````````````````` example
-`Foo
-----
-`
-
-<a title="a lot
----
-of dashes"/>
-.
-<h2>`Foo</h2>
-<p>`</p>
-<h2>&lt;a title=&quot;a lot</h2>
-<p>of dashes&quot;/&gt;</p>
-````````````````````````````````
-
-
-The setext heading underline cannot be a [lazy continuation
-line] in a list item or block quote:
-
-```````````````````````````````` example
-> Foo
----
-.
-<blockquote>
-<p>Foo</p>
-</blockquote>
-<hr />
-````````````````````````````````
-
-
-```````````````````````````````` example
-> foo
-bar
-===
-.
-<blockquote>
-<p>foo
-bar
-===</p>
-</blockquote>
-````````````````````````````````
-
-
-```````````````````````````````` example
-- Foo
----
-.
-<ul>
-<li>Foo</li>
-</ul>
-<hr />
-````````````````````````````````
-
-
-A blank line is needed between a paragraph and a following
-setext heading, since otherwise the paragraph becomes part
-of the heading's content:
-
-```````````````````````````````` example
-Foo
-Bar
----
-.
-<h2>Foo
-Bar</h2>
-````````````````````````````````
-
-
-But in general a blank line is not required before or after
-setext headings:
-
-```````````````````````````````` example
----
-Foo
----
-Bar
----
-Baz
-.
-<hr />
-<h2>Foo</h2>
-<h2>Bar</h2>
-<p>Baz</p>
-````````````````````````````````
-
-
-Setext headings cannot be empty:
-
-```````````````````````````````` example
-
-====
-.
-<p>====</p>
-````````````````````````````````
-
-
-Setext heading text lines must not be interpretable as block
-constructs other than paragraphs. So, the line of dashes
-in these examples gets interpreted as a thematic break:
-
-```````````````````````````````` example
----
----
-.
-<hr />
-<hr />
-````````````````````````````````
-
-
-```````````````````````````````` example
-- foo
------
-.
-<ul>
-<li>foo</li>
-</ul>
-<hr />
-````````````````````````````````
-
-
-```````````````````````````````` example
- foo
----
-.
-<pre><code>foo
-</code></pre>
-<hr />
-````````````````````````````````
-
-
-```````````````````````````````` example
-> foo
------
-.
-<blockquote>
-<p>foo</p>
-</blockquote>
-<hr />
-````````````````````````````````
-
-
-If you want a heading with `> foo` as its literal text, you can
-use backslash escapes:
-
-```````````````````````````````` example
-\> foo
-------
-.
-<h2>&gt; foo</h2>
-````````````````````````````````
-
-
-**Compatibility note:** Most existing Markdown implementations
-do not allow the text of setext headings to span multiple lines.
-But there is no consensus about how to interpret
-
-``` markdown
-Foo
-bar
----
-baz
-```
-
-One can find four different interpretations:
-
-1. paragraph "Foo", heading "bar", paragraph "baz"
-2. paragraph "Foo bar", thematic break, paragraph "baz"
-3. paragraph "Foo bar --- baz"
-4. heading "Foo bar", paragraph "baz"
-
-We find interpretation 4 most natural, and interpretation 4
-increases the expressive power of CommonMark, by allowing
-multiline headings. Authors who want interpretation 1 can
-put a blank line after the first paragraph:
-
-```````````````````````````````` example
-Foo
-
-bar
----
-baz
-.
-<p>Foo</p>
-<h2>bar</h2>
-<p>baz</p>
-````````````````````````````````
-
-
-Authors who want interpretation 2 can put blank lines around
-the thematic break,
-
-```````````````````````````````` example
-Foo
-bar
-
----
-
-baz
-.
-<p>Foo
-bar</p>
-<hr />
-<p>baz</p>
-````````````````````````````````
-
-
-or use a thematic break that cannot count as a [setext heading
-underline], such as
-
-```````````````````````````````` example
-Foo
-bar
-* * *
-baz
-.
-<p>Foo
-bar</p>
-<hr />
-<p>baz</p>
-````````````````````````````````
-
-
-Authors who want interpretation 3 can use backslash escapes:
-
-```````````````````````````````` example
-Foo
-bar
-\---
-baz
-.
-<p>Foo
-bar
----
-baz</p>
-````````````````````````````````
-
-
-## Indented code blocks
-
-An [indented code block](@) is composed of one or more
-[indented chunks] separated by blank lines.
-An [indented chunk](@) is a sequence of non-blank lines,
-each indented four or more spaces. The contents of the code block are
-the literal contents of the lines, including trailing
-[line endings], minus four spaces of indentation.
-An indented code block has no [info string].
-
-An indented code block cannot interrupt a paragraph, so there must be
-a blank line between a paragraph and a following indented code block.
-(A blank line is not needed, however, between a code block and a following
-paragraph.)
-
-```````````````````````````````` example
- a simple
- indented code block
-.
-<pre><code>a simple
- indented code block
-</code></pre>
-````````````````````````````````
-
-
-If there is any ambiguity between an interpretation of indentation
-as a code block and as indicating that material belongs to a [list
-item][list items], the list item interpretation takes precedence:
-
-```````````````````````````````` example
- - foo
-
- bar
-.
-<ul>
-<li>
-<p>foo</p>
-<p>bar</p>
-</li>
-</ul>
-````````````````````````````````
-
-
-```````````````````````````````` example
-1. foo
-
- - bar
-.
-<ol>
-<li>
-<p>foo</p>
-<ul>
-<li>bar</li>
-</ul>
-</li>
-</ol>
-````````````````````````````````
-
-
-
-The contents of a code block are literal text, and do not get parsed
-as Markdown:
-
-```````````````````````````````` example
- <a/>
- *hi*
-
- - one
-.
-<pre><code>&lt;a/&gt;
-*hi*
-
-- one
-</code></pre>
-````````````````````````````````
-
-
-Here we have three chunks separated by blank lines:
-
-```````````````````````````````` example
- chunk1
-
- chunk2
-
-
-
- chunk3
-.
-<pre><code>chunk1
-
-chunk2
-
-
-
-chunk3
-</code></pre>
-````````````````````````````````
-
-
-Any initial spaces beyond four will be included in the content, even
-in interior blank lines:
-
-```````````````````````````````` example
- chunk1
-
- chunk2
-.
-<pre><code>chunk1
-
- chunk2
-</code></pre>
-````````````````````````````````
-
-
-An indented code block cannot interrupt a paragraph. (This
-allows hanging indents and the like.)
-
-```````````````````````````````` example
-Foo
- bar
-
-.
-<p>Foo
-bar</p>
-````````````````````````````````
-
-
-However, any non-blank line with fewer than four leading spaces ends
-the code block immediately. So a paragraph may occur immediately
-after indented code:
-
-```````````````````````````````` example
- foo
-bar
-.
-<pre><code>foo
-</code></pre>
-<p>bar</p>
-````````````````````````````````
-
-
-And indented code can occur immediately before and after other kinds of
-blocks:
-
-```````````````````````````````` example
-# Heading
- foo
-Heading
-------
- foo
-----
-.
-<h1>Heading</h1>
-<pre><code>foo
-</code></pre>
-<h2>Heading</h2>
-<pre><code>foo
-</code></pre>
-<hr />
-````````````````````````````````
-
-
-The first line can be indented more than four spaces:
-
-```````````````````````````````` example
- foo
- bar
-.
-<pre><code> foo
-bar
-</code></pre>
-````````````````````````````````
-
-
-Blank lines preceding or following an indented code block
-are not included in it:
-
-```````````````````````````````` example
-
-
- foo
-
-
-.
-<pre><code>foo
-</code></pre>
-````````````````````````````````
-
-
-Trailing spaces are included in the code block's content:
-
-```````````````````````````````` example
- foo
-.
-<pre><code>foo
-</code></pre>
-````````````````````````````````
-
-
-
-## Fenced code blocks
-
-A [code fence](@) is a sequence
-of at least three consecutive backtick characters (`` ` ``) or
-tildes (`~`). (Tildes and backticks cannot be mixed.)
-A [fenced code block](@)
-begins with a code fence, indented no more than three spaces.
-
-The line with the opening code fence may optionally contain some text
-following the code fence; this is trimmed of leading and trailing
-whitespace and called the [info string](@). If the [info string] comes
-after a backtick fence, it may not contain any backtick
-characters. (The reason for this restriction is that otherwise
-some inline code would be incorrectly interpreted as the
-beginning of a fenced code block.)
-
-The content of the code block consists of all subsequent lines, until
-a closing [code fence] of the same type as the code block
-began with (backticks or tildes), and with at least as many backticks
-or tildes as the opening code fence. If the leading code fence is
-indented N spaces, then up to N spaces of indentation are removed from
-each line of the content (if present). (If a content line is not
-indented, it is preserved unchanged. If it is indented less than N
-spaces, all of the indentation is removed.)
-
-The closing code fence may be indented up to three spaces, and may be
-followed only by spaces, which are ignored. If the end of the
-containing block (or document) is reached and no closing code fence
-has been found, the code block contains all of the lines after the
-opening code fence until the end of the containing block (or
-document). (An alternative spec would require backtracking in the
-event that a closing code fence is not found. But this makes parsing
-much less efficient, and there seems to be no real down side to the
-behavior described here.)
-
-A fenced code block may interrupt a paragraph, and does not require
-a blank line either before or after.
-
-The content of a code fence is treated as literal text, not parsed
-as inlines. The first word of the [info string] is typically used to
-specify the language of the code sample, and rendered in the `class`
-attribute of the `code` tag. However, this spec does not mandate any
-particular treatment of the [info string].
-
-Here is a simple example with backticks:
-
-```````````````````````````````` example
-```
-<
- >
-```
-.
-<pre><code>&lt;
- &gt;
-</code></pre>
-````````````````````````````````
-
-
-With tildes:
-
-```````````````````````````````` example
-~~~
-<
- >
-~~~
-.
-<pre><code>&lt;
- &gt;
-</code></pre>
-````````````````````````````````
-
-Fewer than three backticks is not enough:
-
-```````````````````````````````` example
-``
-foo
-``
-.
-<p><code>foo</code></p>
-````````````````````````````````
-
-The closing code fence must use the same character as the opening
-fence:
-
-```````````````````````````````` example
-```
-aaa
-~~~
-```
-.
-<pre><code>aaa
-~~~
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
-~~~
-aaa
-```
-~~~
-.
-<pre><code>aaa
-```
-</code></pre>
-````````````````````````````````
-
-
-The closing code fence must be at least as long as the opening fence:
-
-```````````````````````````````` example
-````
-aaa
-```
-``````
-.
-<pre><code>aaa
-```
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
-~~~~
-aaa
-~~~
-~~~~
-.
-<pre><code>aaa
-~~~
-</code></pre>
-````````````````````````````````
-
-
-Unclosed code blocks are closed by the end of the document
-(or the enclosing [block quote][block quotes] or [list item][list items]):
-
-```````````````````````````````` example
-```
-.
-<pre><code></code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
-`````
-
-```
-aaa
-.
-<pre><code>
-```
-aaa
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
-> ```
-> aaa
-
-bbb
-.
-<blockquote>
-<pre><code>aaa
-</code></pre>
-</blockquote>
-<p>bbb</p>
-````````````````````````````````
-
-
-A code block can have all empty lines as its content:
-
-```````````````````````````````` example
-```
-
-
-```
-.
-<pre><code>
-
-</code></pre>
-````````````````````````````````
-
-
-A code block can be empty:
-
-```````````````````````````````` example
-```
-```
-.
-<pre><code></code></pre>
-````````````````````````````````
-
-
-Fences can be indented. If the opening fence is indented,
-content lines will have equivalent opening indentation removed,
-if present:
-
-```````````````````````````````` example
- ```
- aaa
-aaa
-```
-.
-<pre><code>aaa
-aaa
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
- ```
-aaa
- aaa
-aaa
- ```
-.
-<pre><code>aaa
-aaa
-aaa
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
- ```
- aaa
- aaa
- aaa
- ```
-.
-<pre><code>aaa
- aaa
-aaa
-</code></pre>
-````````````````````````````````
-
-
-Four spaces indentation produces an indented code block:
-
-```````````````````````````````` example
- ```
- aaa
- ```
-.
-<pre><code>```
-aaa
-```
-</code></pre>
-````````````````````````````````
-
-
-Closing fences may be indented by 0-3 spaces, and their indentation
-need not match that of the opening fence:
-
-```````````````````````````````` example
-```
-aaa
- ```
-.
-<pre><code>aaa
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
- ```
-aaa
- ```
-.
-<pre><code>aaa
-</code></pre>
-````````````````````````````````
-
-
-This is not a closing fence, because it is indented 4 spaces:
-
-```````````````````````````````` example
-```
-aaa
- ```
-.
-<pre><code>aaa
- ```
-</code></pre>
-````````````````````````````````
-
-
-
-Code fences (opening and closing) cannot contain internal spaces:
-
-```````````````````````````````` example
-``` ```
-aaa
-.
-<p><code> </code>
-aaa</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-~~~~~~
-aaa
-~~~ ~~
-.
-<pre><code>aaa
-~~~ ~~
-</code></pre>
-````````````````````````````````
-
-
-Fenced code blocks can interrupt paragraphs, and can be followed
-directly by paragraphs, without a blank line between:
-
-```````````````````````````````` example
-foo
-```
-bar
-```
-baz
-.
-<p>foo</p>
-<pre><code>bar
-</code></pre>
-<p>baz</p>
-````````````````````````````````
-
-
-Other blocks can also occur before and after fenced code blocks
-without an intervening blank line:
-
-```````````````````````````````` example
-foo
----
-~~~
-bar
-~~~
-# baz
-.
-<h2>foo</h2>
-<pre><code>bar
-</code></pre>
-<h1>baz</h1>
-````````````````````````````````
-
-
-An [info string] can be provided after the opening code fence.
-Although this spec doesn't mandate any particular treatment of
-the info string, the first word is typically used to specify
-the language of the code block. In HTML output, the language is
-normally indicated by adding a class to the `code` element consisting
-of `language-` followed by the language name.
-
-```````````````````````````````` example
-```ruby
-def foo(x)
- return 3
-end
-```
-.
-<pre><code class="language-ruby">def foo(x)
- return 3
-end
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
-~~~~ ruby startline=3 $%@#$
-def foo(x)
- return 3
-end
-~~~~~~~
-.
-<pre><code class="language-ruby">def foo(x)
- return 3
-end
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
-````;
-````
-.
-<pre><code class="language-;"></code></pre>
-````````````````````````````````
-
-
-[Info strings] for backtick code blocks cannot contain backticks:
-
-```````````````````````````````` example
-``` aa ```
-foo
-.
-<p><code>aa</code>
-foo</p>
-````````````````````````````````
-
-
-[Info strings] for tilde code blocks can contain backticks and tildes:
-
-```````````````````````````````` example
-~~~ aa ``` ~~~
-foo
-~~~
-.
-<pre><code class="language-aa">foo
-</code></pre>
-````````````````````````````````
-
-
-Closing code fences cannot have [info strings]:
-
-```````````````````````````````` example
-```
-``` aaa
-```
-.
-<pre><code>``` aaa
-</code></pre>
-````````````````````````````````
-
-
-
-## HTML blocks
-
-An [HTML block](@) is a group of lines that is treated
-as raw HTML (and will not be escaped in HTML output).
-
-There are seven kinds of [HTML block], which can be defined by their
-start and end conditions. The block begins with a line that meets a
-[start condition](@) (after up to three spaces optional indentation).
-It ends with the first subsequent line that meets a matching [end
-condition](@), or the last line of the document, or the last line of
-the [container block](#container-blocks) containing the current HTML
-block, if no line is encountered that meets the [end condition]. If
-the first line meets both the [start condition] and the [end
-condition], the block will contain just that line.
-
-1. **Start condition:** line begins with the string `<script`,
-`<pre`, or `<style` (case-insensitive), followed by whitespace,
-the string `>`, or the end of the line.\
-**End condition:** line contains an end tag
-`</script>`, `</pre>`, or `</style>` (case-insensitive; it
-need not match the start tag).
-
-2. **Start condition:** line begins with the string `<!--`.\
-**End condition:** line contains the string `-->`.
-
-3. **Start condition:** line begins with the string `<?`.\
-**End condition:** line contains the string `?>`.
-
-4. **Start condition:** line begins with the string `<!`
-followed by an uppercase ASCII letter.\
-**End condition:** line contains the character `>`.
-
-5. **Start condition:** line begins with the string
-`<![CDATA[`.\
-**End condition:** line contains the string `]]>`.
-
-6. **Start condition:** line begins the string `<` or `</`
-followed by one of the strings (case-insensitive) `address`,
-`article`, `aside`, `base`, `basefont`, `blockquote`, `body`,
-`caption`, `center`, `col`, `colgroup`, `dd`, `details`, `dialog`,
-`dir`, `div`, `dl`, `dt`, `fieldset`, `figcaption`, `figure`,
-`footer`, `form`, `frame`, `frameset`,
-`h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `head`, `header`, `hr`,
-`html`, `iframe`, `legend`, `li`, `link`, `main`, `menu`, `menuitem`,
-`nav`, `noframes`, `ol`, `optgroup`, `option`, `p`, `param`,
-`section`, `summary`, `table`, `tbody`, `td`,
-`tfoot`, `th`, `thead`, `title`, `tr`, `track`, `ul`, followed
-by [whitespace], the end of the line, the string `>`, or
-the string `/>`.\
-**End condition:** line is followed by a [blank line].
-
-7. **Start condition:** line begins with a complete [open tag]
-(with any [tag name] other than `script`,
-`style`, or `pre`) or a complete [closing tag],
-followed only by [whitespace] or the end of the line.\
-**End condition:** line is followed by a [blank line].
-
-HTML blocks continue until they are closed by their appropriate
-[end condition], or the last line of the document or other [container
-block](#container-blocks). This means any HTML **within an HTML
-block** that might otherwise be recognised as a start condition will
-be ignored by the parser and passed through as-is, without changing
-the parser's state.
-
-For instance, `<pre>` within a HTML block started by `<table>` will not affect
-the parser state; as the HTML block was started in by start condition 6, it
-will end at any blank line. This can be surprising:
-
-```````````````````````````````` example
-<table><tr><td>
-<pre>
-**Hello**,
-
-_world_.
-</pre>
-</td></tr></table>
-.
-<table><tr><td>
-<pre>
-**Hello**,
-<p><em>world</em>.
-</pre></p>
-</td></tr></table>
-````````````````````````````````
-
-In this case, the HTML block is terminated by the newline — the `**Hello**`
-text remains verbatim — and regular parsing resumes, with a paragraph,
-emphasised `world` and inline and block HTML following.
-
-All types of [HTML blocks] except type 7 may interrupt
-a paragraph. Blocks of type 7 may not interrupt a paragraph.
-(This restriction is intended to prevent unwanted interpretation
-of long tags inside a wrapped paragraph as starting HTML blocks.)
-
-Some simple examples follow. Here are some basic HTML blocks
-of type 6:
-
-```````````````````````````````` example
-<table>
- <tr>
- <td>
- hi
- </td>
- </tr>
-</table>
-
-okay.
-.
-<table>
- <tr>
- <td>
- hi
- </td>
- </tr>
-</table>
-<p>okay.</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
- <div>
- *hello*
- <foo><a>
-.
- <div>
- *hello*
- <foo><a>
-````````````````````````````````
-
-
-A block can also start with a closing tag:
-
-```````````````````````````````` example
-</div>
-*foo*
-.
-</div>
-*foo*
-````````````````````````````````
-
-
-Here we have two HTML blocks with a Markdown paragraph between them:
-
-```````````````````````````````` example
-<DIV CLASS="foo">
-
-*Markdown*
-
-</DIV>
-.
-<DIV CLASS="foo">
-<p><em>Markdown</em></p>
-</DIV>
-````````````````````````````````
-
-
-The tag on the first line can be partial, as long
-as it is split where there would be whitespace:
-
-```````````````````````````````` example
-<div id="foo"
- class="bar">
-</div>
-.
-<div id="foo"
- class="bar">
-</div>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<div id="foo" class="bar
- baz">
-</div>
-.
-<div id="foo" class="bar
- baz">
-</div>
-````````````````````````````````
-
-
-An open tag need not be closed:
-```````````````````````````````` example
-<div>
-*foo*
-
-*bar*
-.
-<div>
-*foo*
-<p><em>bar</em></p>
-````````````````````````````````
-
-
-
-A partial tag need not even be completed (garbage
-in, garbage out):
-
-```````````````````````````````` example
-<div id="foo"
-*hi*
-.
-<div id="foo"
-*hi*
-````````````````````````````````
-
-
-```````````````````````````````` example
-<div class
-foo
-.
-<div class
-foo
-````````````````````````````````
-
-
-The initial tag doesn't even need to be a valid
-tag, as long as it starts like one:
-
-```````````````````````````````` example
-<div *???-&&&-<---
-*foo*
-.
-<div *???-&&&-<---
-*foo*
-````````````````````````````````
-
-
-In type 6 blocks, the initial tag need not be on a line by
-itself:
-
-```````````````````````````````` example
-<div><a href="bar">*foo*</a></div>
-.
-<div><a href="bar">*foo*</a></div>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<table><tr><td>
-foo
-</td></tr></table>
-.
-<table><tr><td>
-foo
-</td></tr></table>
-````````````````````````````````
-
-
-Everything until the next blank line or end of document
-gets included in the HTML block. So, in the following
-example, what looks like a Markdown code block
-is actually part of the HTML block, which continues until a blank
-line or the end of the document is reached:
-
-```````````````````````````````` example
-<div></div>
-``` c
-int x = 33;
-```
-.
-<div></div>
-``` c
-int x = 33;
-```
-````````````````````````````````
-
-
-To start an [HTML block] with a tag that is *not* in the
-list of block-level tags in (6), you must put the tag by
-itself on the first line (and it must be complete):
-
-```````````````````````````````` example
-<a href="foo">
-*bar*
-</a>
-.
-<a href="foo">
-*bar*
-</a>
-````````````````````````````````
-
-
-In type 7 blocks, the [tag name] can be anything:
-
-```````````````````````````````` example
-<Warning>
-*bar*
-</Warning>
-.
-<Warning>
-*bar*
-</Warning>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<i class="foo">
-*bar*
-</i>
-.
-<i class="foo">
-*bar*
-</i>
-````````````````````````````````
-
-
-```````````````````````````````` example
-</ins>
-*bar*
-.
-</ins>
-*bar*
-````````````````````````````````
-
-
-These rules are designed to allow us to work with tags that
-can function as either block-level or inline-level tags.
-The `<del>` tag is a nice example. We can surround content with
-`<del>` tags in three different ways. In this case, we get a raw
-HTML block, because the `<del>` tag is on a line by itself:
-
-```````````````````````````````` example
-<del>
-*foo*
-</del>
-.
-<del>
-*foo*
-</del>
-````````````````````````````````
-
-
-In this case, we get a raw HTML block that just includes
-the `<del>` tag (because it ends with the following blank
-line). So the contents get interpreted as CommonMark:
-
-```````````````````````````````` example
-<del>
-
-*foo*
-
-</del>
-.
-<del>
-<p><em>foo</em></p>
-</del>
-````````````````````````````````
-
-
-Finally, in this case, the `<del>` tags are interpreted
-as [raw HTML] *inside* the CommonMark paragraph. (Because
-the tag is not on a line by itself, we get inline HTML
-rather than an [HTML block].)
-
-```````````````````````````````` example
-<del>*foo*</del>
-.
-<p><del><em>foo</em></del></p>
-````````````````````````````````
-
-
-HTML tags designed to contain literal content
-(`script`, `style`, `pre`), comments, processing instructions,
-and declarations are treated somewhat differently.
-Instead of ending at the first blank line, these blocks
-end at the first line containing a corresponding end tag.
-As a result, these blocks can contain blank lines:
-
-A pre tag (type 1):
-
-```````````````````````````````` example
-<pre language="haskell"><code>
-import Text.HTML.TagSoup
-
-main :: IO ()
-main = print $ parseTags tags
-</code></pre>
-okay
-.
-<pre language="haskell"><code>
-import Text.HTML.TagSoup
-
-main :: IO ()
-main = print $ parseTags tags
-</code></pre>
-<p>okay</p>
-````````````````````````````````
-
-
-A script tag (type 1):
-
-```````````````````````````````` example
-<script type="text/javascript">
-// JavaScript example
-
-document.getElementById("demo").innerHTML = "Hello JavaScript!";
-</script>
-okay
-.
-<script type="text/javascript">
-// JavaScript example
-
-document.getElementById("demo").innerHTML = "Hello JavaScript!";
-</script>
-<p>okay</p>
-````````````````````````````````
-
-
-A style tag (type 1):
-
-```````````````````````````````` example
-<style
- type="text/css">
-h1 {color:red;}
-
-p {color:blue;}
-</style>
-okay
-.
-<style
- type="text/css">
-h1 {color:red;}
-
-p {color:blue;}
-</style>
-<p>okay</p>
-````````````````````````````````
-
-
-If there is no matching end tag, the block will end at the
-end of the document (or the enclosing [block quote][block quotes]
-or [list item][list items]):
-
-```````````````````````````````` example
-<style
- type="text/css">
-
-foo
-.
-<style
- type="text/css">
-
-foo
-````````````````````````````````
-
-
-```````````````````````````````` example
-> <div>
-> foo
-
-bar
-.
-<blockquote>
-<div>
-foo
-</blockquote>
-<p>bar</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-- <div>
-- foo
-.
-<ul>
-<li>
-<div>
-</li>
-<li>foo</li>
-</ul>
-````````````````````````````````
-
-
-The end tag can occur on the same line as the start tag:
-
-```````````````````````````````` example
-<style>p{color:red;}</style>
-*foo*
-.
-<style>p{color:red;}</style>
-<p><em>foo</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<!-- foo -->*bar*
-*baz*
-.
-<!-- foo -->*bar*
-<p><em>baz</em></p>
-````````````````````````````````
-
-
-Note that anything on the last line after the
-end tag will be included in the [HTML block]:
-
-```````````````````````````````` example
-<script>
-foo
-</script>1. *bar*
-.
-<script>
-foo
-</script>1. *bar*
-````````````````````````````````
-
-
-A comment (type 2):
-
-```````````````````````````````` example
-<!-- Foo
-
-bar
- baz -->
-okay
-.
-<!-- Foo
-
-bar
- baz -->
-<p>okay</p>
-````````````````````````````````
-
-
-
-A processing instruction (type 3):
-
-```````````````````````````````` example
-<?php
-
- echo '>';
-
-?>
-okay
-.
-<?php
-
- echo '>';
-
-?>
-<p>okay</p>
-````````````````````````````````
-
-
-A declaration (type 4):
-
-```````````````````````````````` example
-<!DOCTYPE html>
-.
-<!DOCTYPE html>
-````````````````````````````````
-
-
-CDATA (type 5):
-
-```````````````````````````````` example
-<![CDATA[
-function matchwo(a,b)
-{
- if (a < b && a < 0) then {
- return 1;
-
- } else {
-
- return 0;
- }
-}
-]]>
-okay
-.
-<![CDATA[
-function matchwo(a,b)
-{
- if (a < b && a < 0) then {
- return 1;
-
- } else {
-
- return 0;
- }
-}
-]]>
-<p>okay</p>
-````````````````````````````````
-
-
-The opening tag can be indented 1-3 spaces, but not 4:
-
-```````````````````````````````` example
- <!-- foo -->
-
- <!-- foo -->
-.
- <!-- foo -->
-<pre><code>&lt;!-- foo --&gt;
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
- <div>
-
- <div>
-.
- <div>
-<pre><code>&lt;div&gt;
-</code></pre>
-````````````````````````````````
-
-
-An HTML block of types 1--6 can interrupt a paragraph, and need not be
-preceded by a blank line.
-
-```````````````````````````````` example
-Foo
-<div>
-bar
-</div>
-.
-<p>Foo</p>
-<div>
-bar
-</div>
-````````````````````````````````
-
-
-However, a following blank line is needed, except at the end of
-a document, and except for blocks of types 1--5, [above][HTML
-block]:
-
-```````````````````````````````` example
-<div>
-bar
-</div>
-*foo*
-.
-<div>
-bar
-</div>
-*foo*
-````````````````````````````````
-
-
-HTML blocks of type 7 cannot interrupt a paragraph:
-
-```````````````````````````````` example
-Foo
-<a href="bar">
-baz
-.
-<p>Foo
-<a href="bar">
-baz</p>
-````````````````````````````````
-
-
-This rule differs from John Gruber's original Markdown syntax
-specification, which says:
-
-> The only restrictions are that block-level HTML elements —
-> e.g. `<div>`, `<table>`, `<pre>`, `<p>`, etc. — must be separated from
-> surrounding content by blank lines, and the start and end tags of the
-> block should not be indented with tabs or spaces.
-
-In some ways Gruber's rule is more restrictive than the one given
-here:
-
-- It requires that an HTML block be preceded by a blank line.
-- It does not allow the start tag to be indented.
-- It requires a matching end tag, which it also does not allow to
- be indented.
-
-Most Markdown implementations (including some of Gruber's own) do not
-respect all of these restrictions.
-
-There is one respect, however, in which Gruber's rule is more liberal
-than the one given here, since it allows blank lines to occur inside
-an HTML block. There are two reasons for disallowing them here.
-First, it removes the need to parse balanced tags, which is
-expensive and can require backtracking from the end of the document
-if no matching end tag is found. Second, it provides a very simple
-and flexible way of including Markdown content inside HTML tags:
-simply separate the Markdown from the HTML using blank lines:
-
-Compare:
-
-```````````````````````````````` example
-<div>
-
-*Emphasized* text.
-
-</div>
-.
-<div>
-<p><em>Emphasized</em> text.</p>
-</div>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<div>
-*Emphasized* text.
-</div>
-.
-<div>
-*Emphasized* text.
-</div>
-````````````````````````````````
-
-
-Some Markdown implementations have adopted a convention of
-interpreting content inside tags as text if the open tag has
-the attribute `markdown=1`. The rule given above seems a simpler and
-more elegant way of achieving the same expressive power, which is also
-much simpler to parse.
-
-The main potential drawback is that one can no longer paste HTML
-blocks into Markdown documents with 100% reliability. However,
-*in most cases* this will work fine, because the blank lines in
-HTML are usually followed by HTML block tags. For example:
-
-```````````````````````````````` example
-<table>
-
-<tr>
-
-<td>
-Hi
-</td>
-
-</tr>
-
-</table>
-.
-<table>
-<tr>
-<td>
-Hi
-</td>
-</tr>
-</table>
-````````````````````````````````
-
-
-There are problems, however, if the inner tags are indented
-*and* separated by spaces, as then they will be interpreted as
-an indented code block:
-
-```````````````````````````````` example
-<table>
-
- <tr>
-
- <td>
- Hi
- </td>
-
- </tr>
-
-</table>
-.
-<table>
- <tr>
-<pre><code>&lt;td&gt;
- Hi
-&lt;/td&gt;
-</code></pre>
- </tr>
-</table>
-````````````````````````````````
-
-
-Fortunately, blank lines are usually not necessary and can be
-deleted. The exception is inside `<pre>` tags, but as described
-[above][HTML blocks], raw HTML blocks starting with `<pre>`
-*can* contain blank lines.
-
-## Link reference definitions
-
-A [link reference definition](@)
-consists of a [link label], indented up to three spaces, followed
-by a colon (`:`), optional [whitespace] (including up to one
-[line ending]), a [link destination],
-optional [whitespace] (including up to one
-[line ending]), and an optional [link
-title], which if it is present must be separated
-from the [link destination] by [whitespace].
-No further [non-whitespace characters] may occur on the line.
-
-A [link reference definition]
-does not correspond to a structural element of a document. Instead, it
-defines a label which can be used in [reference links]
-and reference-style [images] elsewhere in the document. [Link
-reference definitions] can come either before or after the links that use
-them.
-
-```````````````````````````````` example
-[foo]: /url "title"
-
-[foo]
-.
-<p><a href="/url" title="title">foo</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
- [foo]:
- /url
- 'the title'
-
-[foo]
-.
-<p><a href="/url" title="the title">foo</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[Foo*bar\]]:my_(url) 'title (with parens)'
-
-[Foo*bar\]]
-.
-<p><a href="my_(url)" title="title (with parens)">Foo*bar]</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[Foo bar]:
-<my url>
-'title'
-
-[Foo bar]
-.
-<p><a href="my%20url" title="title">Foo bar</a></p>
-````````````````````````````````
-
-
-The title may extend over multiple lines:
-
-```````````````````````````````` example
-[foo]: /url '
-title
-line1
-line2
-'
-
-[foo]
-.
-<p><a href="/url" title="
-title
-line1
-line2
-">foo</a></p>
-````````````````````````````````
-
-
-However, it may not contain a [blank line]:
-
-```````````````````````````````` example
-[foo]: /url 'title
-
-with blank line'
-
-[foo]
-.
-<p>[foo]: /url 'title</p>
-<p>with blank line'</p>
-<p>[foo]</p>
-````````````````````````````````
-
-
-The title may be omitted:
-
-```````````````````````````````` example
-[foo]:
-/url
-
-[foo]
-.
-<p><a href="/url">foo</a></p>
-````````````````````````````````
-
-
-The link destination may not be omitted:
-
-```````````````````````````````` example
-[foo]:
-
-[foo]
-.
-<p>[foo]:</p>
-<p>[foo]</p>
-````````````````````````````````
-
- However, an empty link destination may be specified using
- angle brackets:
-
-```````````````````````````````` example
-[foo]: <>
-
-[foo]
-.
-<p><a href="">foo</a></p>
-````````````````````````````````
-
-The title must be separated from the link destination by
-whitespace:
-
-```````````````````````````````` example
-[foo]: <bar>(baz)
-
-[foo]
-.
-<p>[foo]: <bar>(baz)</p>
-<p>[foo]</p>
-````````````````````````````````
-
-
-Both title and destination can contain backslash escapes
-and literal backslashes:
-
-```````````````````````````````` example
-[foo]: /url\bar\*baz "foo\"bar\baz"
-
-[foo]
-.
-<p><a href="/url%5Cbar*baz" title="foo&quot;bar\baz">foo</a></p>
-````````````````````````````````
-
-
-A link can come before its corresponding definition:
-
-```````````````````````````````` example
-[foo]
-
-[foo]: url
-.
-<p><a href="url">foo</a></p>
-````````````````````````````````
-
-
-If there are several matching definitions, the first one takes
-precedence:
-
-```````````````````````````````` example
-[foo]
-
-[foo]: first
-[foo]: second
-.
-<p><a href="first">foo</a></p>
-````````````````````````````````
-
-
-As noted in the section on [Links], matching of labels is
-case-insensitive (see [matches]).
-
-```````````````````````````````` example
-[FOO]: /url
-
-[Foo]
-.
-<p><a href="/url">Foo</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[ΑΓΩ]: /φου
-
-[αγω]
-.
-<p><a href="/%CF%86%CE%BF%CF%85">αγω</a></p>
-````````````````````````````````
-
-
-Here is a link reference definition with no corresponding link.
-It contributes nothing to the document.
-
-```````````````````````````````` example
-[foo]: /url
-.
-````````````````````````````````
-
-
-Here is another one:
-
-```````````````````````````````` example
-[
-foo
-]: /url
-bar
-.
-<p>bar</p>
-````````````````````````````````
-
-
-This is not a link reference definition, because there are
-[non-whitespace characters] after the title:
-
-```````````````````````````````` example
-[foo]: /url "title" ok
-.
-<p>[foo]: /url &quot;title&quot; ok</p>
-````````````````````````````````
-
-
-This is a link reference definition, but it has no title:
-
-```````````````````````````````` example
-[foo]: /url
-"title" ok
-.
-<p>&quot;title&quot; ok</p>
-````````````````````````````````
-
-
-This is not a link reference definition, because it is indented
-four spaces:
-
-```````````````````````````````` example
- [foo]: /url "title"
-
-[foo]
-.
-<pre><code>[foo]: /url &quot;title&quot;
-</code></pre>
-<p>[foo]</p>
-````````````````````````````````
-
-
-This is not a link reference definition, because it occurs inside
-a code block:
-
-```````````````````````````````` example
-```
-[foo]: /url
-```
-
-[foo]
-.
-<pre><code>[foo]: /url
-</code></pre>
-<p>[foo]</p>
-````````````````````````````````
-
-
-A [link reference definition] cannot interrupt a paragraph.
-
-```````````````````````````````` example
-Foo
-[bar]: /baz
-
-[bar]
-.
-<p>Foo
-[bar]: /baz</p>
-<p>[bar]</p>
-````````````````````````````````
-
-
-However, it can directly follow other block elements, such as headings
-and thematic breaks, and it need not be followed by a blank line.
-
-```````````````````````````````` example
-# [Foo]
-[foo]: /url
-> bar
-.
-<h1><a href="/url">Foo</a></h1>
-<blockquote>
-<p>bar</p>
-</blockquote>
-````````````````````````````````
-
-```````````````````````````````` example
-[foo]: /url
-bar
-===
-[foo]
-.
-<h1>bar</h1>
-<p><a href="/url">foo</a></p>
-````````````````````````````````
-
-```````````````````````````````` example
-[foo]: /url
-===
-[foo]
-.
-<p>===
-<a href="/url">foo</a></p>
-````````````````````````````````
-
-
-Several [link reference definitions]
-can occur one after another, without intervening blank lines.
-
-```````````````````````````````` example
-[foo]: /foo-url "foo"
-[bar]: /bar-url
- "bar"
-[baz]: /baz-url
-
-[foo],
-[bar],
-[baz]
-.
-<p><a href="/foo-url" title="foo">foo</a>,
-<a href="/bar-url" title="bar">bar</a>,
-<a href="/baz-url">baz</a></p>
-````````````````````````````````
-
-
-[Link reference definitions] can occur
-inside block containers, like lists and block quotations. They
-affect the entire document, not just the container in which they
-are defined:
-
-```````````````````````````````` example
-[foo]
-
-> [foo]: /url
-.
-<p><a href="/url">foo</a></p>
-<blockquote>
-</blockquote>
-````````````````````````````````
-
-
-Whether something is a [link reference definition] is
-independent of whether the link reference it defines is
-used in the document. Thus, for example, the following
-document contains just a link reference definition, and
-no visible content:
-
-```````````````````````````````` example
-[foo]: /url
-.
-````````````````````````````````
-
-
-## Paragraphs
-
-A sequence of non-blank lines that cannot be interpreted as other
-kinds of blocks forms a [paragraph](@).
-The contents of the paragraph are the result of parsing the
-paragraph's raw content as inlines. The paragraph's raw content
-is formed by concatenating the lines and removing initial and final
-[whitespace].
-
-A simple example with two paragraphs:
-
-```````````````````````````````` example
-aaa
-
-bbb
-.
-<p>aaa</p>
-<p>bbb</p>
-````````````````````````````````
-
-
-Paragraphs can contain multiple lines, but no blank lines:
-
-```````````````````````````````` example
-aaa
-bbb
-
-ccc
-ddd
-.
-<p>aaa
-bbb</p>
-<p>ccc
-ddd</p>
-````````````````````````````````
-
-
-Multiple blank lines between paragraph have no effect:
-
-```````````````````````````````` example
-aaa
-
-
-bbb
-.
-<p>aaa</p>
-<p>bbb</p>
-````````````````````````````````
-
-
-Leading spaces are skipped:
-
-```````````````````````````````` example
- aaa
- bbb
-.
-<p>aaa
-bbb</p>
-````````````````````````````````
-
-
-Lines after the first may be indented any amount, since indented
-code blocks cannot interrupt paragraphs.
-
-```````````````````````````````` example
-aaa
- bbb
- ccc
-.
-<p>aaa
-bbb
-ccc</p>
-````````````````````````````````
-
-
-However, the first line may be indented at most three spaces,
-or an indented code block will be triggered:
-
-```````````````````````````````` example
- aaa
-bbb
-.
-<p>aaa
-bbb</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
- aaa
-bbb
-.
-<pre><code>aaa
-</code></pre>
-<p>bbb</p>
-````````````````````````````````
-
-
-Final spaces are stripped before inline parsing, so a paragraph
-that ends with two or more spaces will not end with a [hard line
-break]:
-
-```````````````````````````````` example
-aaa
-bbb
-.
-<p>aaa<br />
-bbb</p>
-````````````````````````````````
-
-
-## Blank lines
-
-[Blank lines] between block-level elements are ignored,
-except for the role they play in determining whether a [list]
-is [tight] or [loose].
-
-Blank lines at the beginning and end of the document are also ignored.
-
-```````````````````````````````` example
-
-
-aaa
-
-
-# aaa
-
-
-.
-<p>aaa</p>
-<h1>aaa</h1>
-````````````````````````````````
-
-<div class="extension">
-
-## Tables (extension)
-
-GFM enables the `table` extension, where an additional leaf block type is
-available.
-
-A [table](@) is an arrangement of data with rows and columns, consisting of a
-single header row, a [delimiter row] separating the header from the data, and
-zero or more data rows.
-
-Each row consists of cells containing arbitrary text, in which [inlines] are
-parsed, separated by pipes (`|`). A leading and trailing pipe is also
-recommended for clarity of reading, and if there's otherwise parsing ambiguity.
-Spaces between pipes and cell content are trimmed. Block-level elements cannot
-be inserted in a table.
-
-The [delimiter row](@) consists of cells whose only content are hyphens (`-`),
-and optionally, a leading or trailing colon (`:`), or both, to indicate left,
-right, or center alignment respectively.
-
-```````````````````````````````` example table
-| foo | bar |
-| --- | --- |
-| baz | bim |
-.
-<table>
-<thead>
-<tr>
-<th>foo</th>
-<th>bar</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td>baz</td>
-<td>bim</td>
-</tr>
-</tbody>
-</table>
-````````````````````````````````
-
-Cells in one column don't need to match length, though it's easier to read if
-they are. Likewise, use of leading and trailing pipes may be inconsistent:
-
-```````````````````````````````` example table
-| abc | defghi |
-:-: | -----------:
-bar | baz
-.
-<table>
-<thead>
-<tr>
-<th align="center">abc</th>
-<th align="right">defghi</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td align="center">bar</td>
-<td align="right">baz</td>
-</tr>
-</tbody>
-</table>
-````````````````````````````````
-
-Include a pipe in a cell's content by escaping it, including inside other
-inline spans:
-
-```````````````````````````````` example table
-| f\|oo |
-| ------ |
-| b `\|` az |
-| b **\|** im |
-.
-<table>
-<thead>
-<tr>
-<th>f|oo</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td>b <code>|</code> az</td>
-</tr>
-<tr>
-<td>b <strong>|</strong> im</td>
-</tr>
-</tbody>
-</table>
-````````````````````````````````
-
-The table is broken at the first empty line, or beginning of another
-block-level structure:
-
-```````````````````````````````` example table
-| abc | def |
-| --- | --- |
-| bar | baz |
-> bar
-.
-<table>
-<thead>
-<tr>
-<th>abc</th>
-<th>def</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td>bar</td>
-<td>baz</td>
-</tr>
-</tbody>
-</table>
-<blockquote>
-<p>bar</p>
-</blockquote>
-````````````````````````````````
-
-```````````````````````````````` example table
-| abc | def |
-| --- | --- |
-| bar | baz |
-bar
-
-bar
-.
-<table>
-<thead>
-<tr>
-<th>abc</th>
-<th>def</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td>bar</td>
-<td>baz</td>
-</tr>
-<tr>
-<td>bar</td>
-<td></td>
-</tr>
-</tbody>
-</table>
-<p>bar</p>
-````````````````````````````````
-
-The header row must match the [delimiter row] in the number of cells. If not,
-a table will not be recognized:
-
-```````````````````````````````` example table
-| abc | def |
-| --- |
-| bar |
-.
-<p>| abc | def |
-| --- |
-| bar |</p>
-````````````````````````````````
-
-The remainder of the table's rows may vary in the number of cells. If there
-are a number of cells fewer than the number of cells in the header row, empty
-cells are inserted. If there are greater, the excess is ignored:
-
-```````````````````````````````` example table
-| abc | def |
-| --- | --- |
-| bar |
-| bar | baz | boo |
-.
-<table>
-<thead>
-<tr>
-<th>abc</th>
-<th>def</th>
-</tr>
-</thead>
-<tbody>
-<tr>
-<td>bar</td>
-<td></td>
-</tr>
-<tr>
-<td>bar</td>
-<td>baz</td>
-</tr>
-</tbody>
-</table>
-````````````````````````````````
-
-If there are no rows in the body, no `<tbody>` is generated in HTML output:
-
-```````````````````````````````` example table
-| abc | def |
-| --- | --- |
-.
-<table>
-<thead>
-<tr>
-<th>abc</th>
-<th>def</th>
-</tr>
-</thead>
-</table>
-````````````````````````````````
-
-</div>
-
-# Container blocks
-
-A [container block](#container-blocks) is a block that has other
-blocks as its contents. There are two basic kinds of container blocks:
-[block quotes] and [list items].
-[Lists] are meta-containers for [list items].
-
-We define the syntax for container blocks recursively. The general
-form of the definition is:
-
-> If X is a sequence of blocks, then the result of
-> transforming X in such-and-such a way is a container of type Y
-> with these blocks as its content.
-
-So, we explain what counts as a block quote or list item by explaining
-how these can be *generated* from their contents. This should suffice
-to define the syntax, although it does not give a recipe for *parsing*
-these constructions. (A recipe is provided below in the section entitled
-[A parsing strategy](#appendix-a-parsing-strategy).)
-
-## Block quotes
-
-A [block quote marker](@)
-consists of 0-3 spaces of initial indent, plus (a) the character `>` together
-with a following space, or (b) a single character `>` not followed by a space.
-
-The following rules define [block quotes]:
-
-1. **Basic case.** If a string of lines *Ls* constitute a sequence
- of blocks *Bs*, then the result of prepending a [block quote
- marker] to the beginning of each line in *Ls*
- is a [block quote](#block-quotes) containing *Bs*.
-
-2. **Laziness.** If a string of lines *Ls* constitute a [block
- quote](#block-quotes) with contents *Bs*, then the result of deleting
- the initial [block quote marker] from one or
- more lines in which the next [non-whitespace character] after the [block
- quote marker] is [paragraph continuation
- text] is a block quote with *Bs* as its content.
- [Paragraph continuation text](@) is text
- that will be parsed as part of the content of a paragraph, but does
- not occur at the beginning of the paragraph.
-
-3. **Consecutiveness.** A document cannot contain two [block
- quotes] in a row unless there is a [blank line] between them.
-
-Nothing else counts as a [block quote](#block-quotes).
-
-Here is a simple example:
-
-```````````````````````````````` example
-> # Foo
-> bar
-> baz
-.
-<blockquote>
-<h1>Foo</h1>
-<p>bar
-baz</p>
-</blockquote>
-````````````````````````````````
-
-
-The spaces after the `>` characters can be omitted:
-
-```````````````````````````````` example
-># Foo
->bar
-> baz
-.
-<blockquote>
-<h1>Foo</h1>
-<p>bar
-baz</p>
-</blockquote>
-````````````````````````````````
-
-
-The `>` characters can be indented 1-3 spaces:
-
-```````````````````````````````` example
- > # Foo
- > bar
- > baz
-.
-<blockquote>
-<h1>Foo</h1>
-<p>bar
-baz</p>
-</blockquote>
-````````````````````````````````
-
-
-Four spaces gives us a code block:
-
-```````````````````````````````` example
- > # Foo
- > bar
- > baz
-.
-<pre><code>&gt; # Foo
-&gt; bar
-&gt; baz
-</code></pre>
-````````````````````````````````
-
-
-The Laziness clause allows us to omit the `>` before
-[paragraph continuation text]:
-
-```````````````````````````````` example
-> # Foo
-> bar
-baz
-.
-<blockquote>
-<h1>Foo</h1>
-<p>bar
-baz</p>
-</blockquote>
-````````````````````````````````
-
-
-A block quote can contain some lazy and some non-lazy
-continuation lines:
-
-```````````````````````````````` example
-> bar
-baz
-> foo
-.
-<blockquote>
-<p>bar
-baz
-foo</p>
-</blockquote>
-````````````````````````````````
-
-
-Laziness only applies to lines that would have been continuations of
-paragraphs had they been prepended with [block quote markers].
-For example, the `> ` cannot be omitted in the second line of
-
-``` markdown
-> foo
-> ---
-```
-
-without changing the meaning:
-
-```````````````````````````````` example
-> foo
----
-.
-<blockquote>
-<p>foo</p>
-</blockquote>
-<hr />
-````````````````````````````````
-
-
-Similarly, if we omit the `> ` in the second line of
-
-``` markdown
-> - foo
-> - bar
-```
-
-then the block quote ends after the first line:
-
-```````````````````````````````` example
-> - foo
-- bar
-.
-<blockquote>
-<ul>
-<li>foo</li>
-</ul>
-</blockquote>
-<ul>
-<li>bar</li>
-</ul>
-````````````````````````````````
-
-
-For the same reason, we can't omit the `> ` in front of
-subsequent lines of an indented or fenced code block:
-
-```````````````````````````````` example
-> foo
- bar
-.
-<blockquote>
-<pre><code>foo
-</code></pre>
-</blockquote>
-<pre><code>bar
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
-> ```
-foo
-```
-.
-<blockquote>
-<pre><code></code></pre>
-</blockquote>
-<p>foo</p>
-<pre><code></code></pre>
-````````````````````````````````
-
-
-Note that in the following case, we have a [lazy
-continuation line]:
-
-```````````````````````````````` example
-> foo
- - bar
-.
-<blockquote>
-<p>foo
-- bar</p>
-</blockquote>
-````````````````````````````````
-
-
-To see why, note that in
-
-```markdown
-> foo
-> - bar
-```
-
-the `- bar` is indented too far to start a list, and can't
-be an indented code block because indented code blocks cannot
-interrupt paragraphs, so it is [paragraph continuation text].
-
-A block quote can be empty:
-
-```````````````````````````````` example
->
-.
-<blockquote>
-</blockquote>
-````````````````````````````````
-
-
-```````````````````````````````` example
->
->
->
-.
-<blockquote>
-</blockquote>
-````````````````````````````````
-
-
-A block quote can have initial or final blank lines:
-
-```````````````````````````````` example
->
-> foo
->
-.
-<blockquote>
-<p>foo</p>
-</blockquote>
-````````````````````````````````
-
-
-A blank line always separates block quotes:
-
-```````````````````````````````` example
-> foo
-
-> bar
-.
-<blockquote>
-<p>foo</p>
-</blockquote>
-<blockquote>
-<p>bar</p>
-</blockquote>
-````````````````````````````````
-
-
-(Most current Markdown implementations, including John Gruber's
-original `Markdown.pl`, will parse this example as a single block quote
-with two paragraphs. But it seems better to allow the author to decide
-whether two block quotes or one are wanted.)
-
-Consecutiveness means that if we put these block quotes together,
-we get a single block quote:
-
-```````````````````````````````` example
-> foo
-> bar
-.
-<blockquote>
-<p>foo
-bar</p>
-</blockquote>
-````````````````````````````````
-
-
-To get a block quote with two paragraphs, use:
-
-```````````````````````````````` example
-> foo
->
-> bar
-.
-<blockquote>
-<p>foo</p>
-<p>bar</p>
-</blockquote>
-````````````````````````````````
-
-
-Block quotes can interrupt paragraphs:
-
-```````````````````````````````` example
-foo
-> bar
-.
-<p>foo</p>
-<blockquote>
-<p>bar</p>
-</blockquote>
-````````````````````````````````
-
-
-In general, blank lines are not needed before or after block
-quotes:
-
-```````````````````````````````` example
-> aaa
-***
-> bbb
-.
-<blockquote>
-<p>aaa</p>
-</blockquote>
-<hr />
-<blockquote>
-<p>bbb</p>
-</blockquote>
-````````````````````````````````
-
-
-However, because of laziness, a blank line is needed between
-a block quote and a following paragraph:
-
-```````````````````````````````` example
-> bar
-baz
-.
-<blockquote>
-<p>bar
-baz</p>
-</blockquote>
-````````````````````````````````
-
-
-```````````````````````````````` example
-> bar
-
-baz
-.
-<blockquote>
-<p>bar</p>
-</blockquote>
-<p>baz</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-> bar
->
-baz
-.
-<blockquote>
-<p>bar</p>
-</blockquote>
-<p>baz</p>
-````````````````````````````````
-
-
-It is a consequence of the Laziness rule that any number
-of initial `>`s may be omitted on a continuation line of a
-nested block quote:
-
-```````````````````````````````` example
-> > > foo
-bar
-.
-<blockquote>
-<blockquote>
-<blockquote>
-<p>foo
-bar</p>
-</blockquote>
-</blockquote>
-</blockquote>
-````````````````````````````````
-
-
-```````````````````````````````` example
->>> foo
-> bar
->>baz
-.
-<blockquote>
-<blockquote>
-<blockquote>
-<p>foo
-bar
-baz</p>
-</blockquote>
-</blockquote>
-</blockquote>
-````````````````````````````````
-
-
-When including an indented code block in a block quote,
-remember that the [block quote marker] includes
-both the `>` and a following space. So *five spaces* are needed after
-the `>`:
-
-```````````````````````````````` example
-> code
-
-> not code
-.
-<blockquote>
-<pre><code>code
-</code></pre>
-</blockquote>
-<blockquote>
-<p>not code</p>
-</blockquote>
-````````````````````````````````
-
-
-
-## List items
-
-A [list marker](@) is a
-[bullet list marker] or an [ordered list marker].
-
-A [bullet list marker](@)
-is a `-`, `+`, or `*` character.
-
-An [ordered list marker](@)
-is a sequence of 1--9 arabic digits (`0-9`), followed by either a
-`.` character or a `)` character. (The reason for the length
-limit is that with 10 digits we start seeing integer overflows
-in some browsers.)
-
-The following rules define [list items]:
-
-1. **Basic case.** If a sequence of lines *Ls* constitute a sequence of
- blocks *Bs* starting with a [non-whitespace character], and *M* is a
- list marker of width *W* followed by 1 ≤ *N* ≤ 4 spaces, then the result
- of prepending *M* and the following spaces to the first line of
- *Ls*, and indenting subsequent lines of *Ls* by *W + N* spaces, is a
- list item with *Bs* as its contents. The type of the list item
- (bullet or ordered) is determined by the type of its list marker.
- If the list item is ordered, then it is also assigned a start
- number, based on the ordered list marker.
-
- Exceptions:
-
- 1. When the first list item in a [list] interrupts
- a paragraph---that is, when it starts on a line that would
- otherwise count as [paragraph continuation text]---then (a)
- the lines *Ls* must not begin with a blank line, and (b) if
- the list item is ordered, the start number must be 1.
- 2. If any line is a [thematic break][thematic breaks] then
- that line is not a list item.
-
-For example, let *Ls* be the lines
-
-```````````````````````````````` example
-A paragraph
-with two lines.
-
- indented code
-
-> A block quote.
-.
-<p>A paragraph
-with two lines.</p>
-<pre><code>indented code
-</code></pre>
-<blockquote>
-<p>A block quote.</p>
-</blockquote>
-````````````````````````````````
-
-
-And let *M* be the marker `1.`, and *N* = 2. Then rule #1 says
-that the following is an ordered list item with start number 1,
-and the same contents as *Ls*:
-
-```````````````````````````````` example
-1. A paragraph
- with two lines.
-
- indented code
-
- > A block quote.
-.
-<ol>
-<li>
-<p>A paragraph
-with two lines.</p>
-<pre><code>indented code
-</code></pre>
-<blockquote>
-<p>A block quote.</p>
-</blockquote>
-</li>
-</ol>
-````````````````````````````````
-
-
-The most important thing to notice is that the position of
-the text after the list marker determines how much indentation
-is needed in subsequent blocks in the list item. If the list
-marker takes up two spaces, and there are three spaces between
-the list marker and the next [non-whitespace character], then blocks
-must be indented five spaces in order to fall under the list
-item.
-
-Here are some examples showing how far content must be indented to be
-put under the list item:
-
-```````````````````````````````` example
-- one
-
- two
-.
-<ul>
-<li>one</li>
-</ul>
-<p>two</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-- one
-
- two
-.
-<ul>
-<li>
-<p>one</p>
-<p>two</p>
-</li>
-</ul>
-````````````````````````````````
-
-
-```````````````````````````````` example
- - one
-
- two
-.
-<ul>
-<li>one</li>
-</ul>
-<pre><code> two
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
- - one
-
- two
-.
-<ul>
-<li>
-<p>one</p>
-<p>two</p>
-</li>
-</ul>
-````````````````````````````````
-
-
-It is tempting to think of this in terms of columns: the continuation
-blocks must be indented at least to the column of the first
-[non-whitespace character] after the list marker. However, that is not quite right.
-The spaces after the list marker determine how much relative indentation
-is needed. Which column this indentation reaches will depend on
-how the list item is embedded in other constructions, as shown by
-this example:
-
-```````````````````````````````` example
- > > 1. one
->>
->> two
-.
-<blockquote>
-<blockquote>
-<ol>
-<li>
-<p>one</p>
-<p>two</p>
-</li>
-</ol>
-</blockquote>
-</blockquote>
-````````````````````````````````
-
-
-Here `two` occurs in the same column as the list marker `1.`,
-but is actually contained in the list item, because there is
-sufficient indentation after the last containing blockquote marker.
-
-The converse is also possible. In the following example, the word `two`
-occurs far to the right of the initial text of the list item, `one`, but
-it is not considered part of the list item, because it is not indented
-far enough past the blockquote marker:
-
-```````````````````````````````` example
->>- one
->>
- > > two
-.
-<blockquote>
-<blockquote>
-<ul>
-<li>one</li>
-</ul>
-<p>two</p>
-</blockquote>
-</blockquote>
-````````````````````````````````
-
-
-Note that at least one space is needed between the list marker and
-any following content, so these are not list items:
-
-```````````````````````````````` example
--one
-
-2.two
-.
-<p>-one</p>
-<p>2.two</p>
-````````````````````````````````
-
-
-A list item may contain blocks that are separated by more than
-one blank line.
-
-```````````````````````````````` example
-- foo
-
-
- bar
-.
-<ul>
-<li>
-<p>foo</p>
-<p>bar</p>
-</li>
-</ul>
-````````````````````````````````
-
-
-A list item may contain any kind of block:
-
-```````````````````````````````` example
-1. foo
-
- ```
- bar
- ```
-
- baz
-
- > bam
-.
-<ol>
-<li>
-<p>foo</p>
-<pre><code>bar
-</code></pre>
-<p>baz</p>
-<blockquote>
-<p>bam</p>
-</blockquote>
-</li>
-</ol>
-````````````````````````````````
-
-
-A list item that contains an indented code block will preserve
-empty lines within the code block verbatim.
-
-```````````````````````````````` example
-- Foo
-
- bar
-
-
- baz
-.
-<ul>
-<li>
-<p>Foo</p>
-<pre><code>bar
-
-
-baz
-</code></pre>
-</li>
-</ul>
-````````````````````````````````
-
-Note that ordered list start numbers must be nine digits or less:
-
-```````````````````````````````` example
-123456789. ok
-.
-<ol start="123456789">
-<li>ok</li>
-</ol>
-````````````````````````````````
-
-
-```````````````````````````````` example
-1234567890. not ok
-.
-<p>1234567890. not ok</p>
-````````````````````````````````
-
-
-A start number may begin with 0s:
-
-```````````````````````````````` example
-0. ok
-.
-<ol start="0">
-<li>ok</li>
-</ol>
-````````````````````````````````
-
-
-```````````````````````````````` example
-003. ok
-.
-<ol start="3">
-<li>ok</li>
-</ol>
-````````````````````````````````
-
-
-A start number may not be negative:
-
-```````````````````````````````` example
--1. not ok
-.
-<p>-1. not ok</p>
-````````````````````````````````
-
-
-
-2. **Item starting with indented code.** If a sequence of lines *Ls*
- constitute a sequence of blocks *Bs* starting with an indented code
- block, and *M* is a list marker of width *W* followed by
- one space, then the result of prepending *M* and the following
- space to the first line of *Ls*, and indenting subsequent lines of
- *Ls* by *W + 1* spaces, is a list item with *Bs* as its contents.
- If a line is empty, then it need not be indented. The type of the
- list item (bullet or ordered) is determined by the type of its list
- marker. If the list item is ordered, then it is also assigned a
- start number, based on the ordered list marker.
-
-An indented code block will have to be indented four spaces beyond
-the edge of the region where text will be included in the list item.
-In the following case that is 6 spaces:
-
-```````````````````````````````` example
-- foo
-
- bar
-.
-<ul>
-<li>
-<p>foo</p>
-<pre><code>bar
-</code></pre>
-</li>
-</ul>
-````````````````````````````````
-
-
-And in this case it is 11 spaces:
-
-```````````````````````````````` example
- 10. foo
-
- bar
-.
-<ol start="10">
-<li>
-<p>foo</p>
-<pre><code>bar
-</code></pre>
-</li>
-</ol>
-````````````````````````````````
-
-
-If the *first* block in the list item is an indented code block,
-then by rule #2, the contents must be indented *one* space after the
-list marker:
-
-```````````````````````````````` example
- indented code
-
-paragraph
-
- more code
-.
-<pre><code>indented code
-</code></pre>
-<p>paragraph</p>
-<pre><code>more code
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
-1. indented code
-
- paragraph
-
- more code
-.
-<ol>
-<li>
-<pre><code>indented code
-</code></pre>
-<p>paragraph</p>
-<pre><code>more code
-</code></pre>
-</li>
-</ol>
-````````````````````````````````
-
-
-Note that an additional space indent is interpreted as space
-inside the code block:
-
-```````````````````````````````` example
-1. indented code
-
- paragraph
-
- more code
-.
-<ol>
-<li>
-<pre><code> indented code
-</code></pre>
-<p>paragraph</p>
-<pre><code>more code
-</code></pre>
-</li>
-</ol>
-````````````````````````````````
-
-
-Note that rules #1 and #2 only apply to two cases: (a) cases
-in which the lines to be included in a list item begin with a
-[non-whitespace character], and (b) cases in which
-they begin with an indented code
-block. In a case like the following, where the first block begins with
-a three-space indent, the rules do not allow us to form a list item by
-indenting the whole thing and prepending a list marker:
-
-```````````````````````````````` example
- foo
-
-bar
-.
-<p>foo</p>
-<p>bar</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-- foo
-
- bar
-.
-<ul>
-<li>foo</li>
-</ul>
-<p>bar</p>
-````````````````````````````````
-
-
-This is not a significant restriction, because when a block begins
-with 1-3 spaces indent, the indentation can always be removed without
-a change in interpretation, allowing rule #1 to be applied. So, in
-the above case:
-
-```````````````````````````````` example
-- foo
-
- bar
-.
-<ul>
-<li>
-<p>foo</p>
-<p>bar</p>
-</li>
-</ul>
-````````````````````````````````
-
-
-3. **Item starting with a blank line.** If a sequence of lines *Ls*
- starting with a single [blank line] constitute a (possibly empty)
- sequence of blocks *Bs*, not separated from each other by more than
- one blank line, and *M* is a list marker of width *W*,
- then the result of prepending *M* to the first line of *Ls*, and
- indenting subsequent lines of *Ls* by *W + 1* spaces, is a list
- item with *Bs* as its contents.
- If a line is empty, then it need not be indented. The type of the
- list item (bullet or ordered) is determined by the type of its list
- marker. If the list item is ordered, then it is also assigned a
- start number, based on the ordered list marker.
-
-Here are some list items that start with a blank line but are not empty:
-
-```````````````````````````````` example
--
- foo
--
- ```
- bar
- ```
--
- baz
-.
-<ul>
-<li>foo</li>
-<li>
-<pre><code>bar
-</code></pre>
-</li>
-<li>
-<pre><code>baz
-</code></pre>
-</li>
-</ul>
-````````````````````````````````
-
-When the list item starts with a blank line, the number of spaces
-following the list marker doesn't change the required indentation:
-
-```````````````````````````````` example
--
- foo
-.
-<ul>
-<li>foo</li>
-</ul>
-````````````````````````````````
-
-
-A list item can begin with at most one blank line.
-In the following example, `foo` is not part of the list
-item:
-
-```````````````````````````````` example
--
-
- foo
-.
-<ul>
-<li></li>
-</ul>
-<p>foo</p>
-````````````````````````````````
-
-
-Here is an empty bullet list item:
-
-```````````````````````````````` example
-- foo
--
-- bar
-.
-<ul>
-<li>foo</li>
-<li></li>
-<li>bar</li>
-</ul>
-````````````````````````````````
-
-
-It does not matter whether there are spaces following the [list marker]:
-
-```````````````````````````````` example
-- foo
--
-- bar
-.
-<ul>
-<li>foo</li>
-<li></li>
-<li>bar</li>
-</ul>
-````````````````````````````````
-
-
-Here is an empty ordered list item:
-
-```````````````````````````````` example
-1. foo
-2.
-3. bar
-.
-<ol>
-<li>foo</li>
-<li></li>
-<li>bar</li>
-</ol>
-````````````````````````````````
-
-
-A list may start or end with an empty list item:
-
-```````````````````````````````` example
-*
-.
-<ul>
-<li></li>
-</ul>
-````````````````````````````````
-
-However, an empty list item cannot interrupt a paragraph:
-
-```````````````````````````````` example
-foo
-*
-
-foo
-1.
-.
-<p>foo
-*</p>
-<p>foo
-1.</p>
-````````````````````````````````
-
-
-4. **Indentation.** If a sequence of lines *Ls* constitutes a list item
- according to rule #1, #2, or #3, then the result of indenting each line
- of *Ls* by 1-3 spaces (the same for each line) also constitutes a
- list item with the same contents and attributes. If a line is
- empty, then it need not be indented.
-
-Indented one space:
-
-```````````````````````````````` example
- 1. A paragraph
- with two lines.
-
- indented code
-
- > A block quote.
-.
-<ol>
-<li>
-<p>A paragraph
-with two lines.</p>
-<pre><code>indented code
-</code></pre>
-<blockquote>
-<p>A block quote.</p>
-</blockquote>
-</li>
-</ol>
-````````````````````````````````
-
-
-Indented two spaces:
-
-```````````````````````````````` example
- 1. A paragraph
- with two lines.
-
- indented code
-
- > A block quote.
-.
-<ol>
-<li>
-<p>A paragraph
-with two lines.</p>
-<pre><code>indented code
-</code></pre>
-<blockquote>
-<p>A block quote.</p>
-</blockquote>
-</li>
-</ol>
-````````````````````````````````
-
-
-Indented three spaces:
-
-```````````````````````````````` example
- 1. A paragraph
- with two lines.
-
- indented code
-
- > A block quote.
-.
-<ol>
-<li>
-<p>A paragraph
-with two lines.</p>
-<pre><code>indented code
-</code></pre>
-<blockquote>
-<p>A block quote.</p>
-</blockquote>
-</li>
-</ol>
-````````````````````````````````
-
-
-Four spaces indent gives a code block:
-
-```````````````````````````````` example
- 1. A paragraph
- with two lines.
-
- indented code
-
- > A block quote.
-.
-<pre><code>1. A paragraph
- with two lines.
-
- indented code
-
- &gt; A block quote.
-</code></pre>
-````````````````````````````````
-
-
-
-5. **Laziness.** If a string of lines *Ls* constitute a [list
- item](#list-items) with contents *Bs*, then the result of deleting
- some or all of the indentation from one or more lines in which the
- next [non-whitespace character] after the indentation is
- [paragraph continuation text] is a
- list item with the same contents and attributes. The unindented
- lines are called
- [lazy continuation line](@)s.
-
-Here is an example with [lazy continuation lines]:
-
-```````````````````````````````` example
- 1. A paragraph
-with two lines.
-
- indented code
-
- > A block quote.
-.
-<ol>
-<li>
-<p>A paragraph
-with two lines.</p>
-<pre><code>indented code
-</code></pre>
-<blockquote>
-<p>A block quote.</p>
-</blockquote>
-</li>
-</ol>
-````````````````````````````````
-
-
-Indentation can be partially deleted:
-
-```````````````````````````````` example
- 1. A paragraph
- with two lines.
-.
-<ol>
-<li>A paragraph
-with two lines.</li>
-</ol>
-````````````````````````````````
-
-
-These examples show how laziness can work in nested structures:
-
-```````````````````````````````` example
-> 1. > Blockquote
-continued here.
-.
-<blockquote>
-<ol>
-<li>
-<blockquote>
-<p>Blockquote
-continued here.</p>
-</blockquote>
-</li>
-</ol>
-</blockquote>
-````````````````````````````````
-
-
-```````````````````````````````` example
-> 1. > Blockquote
-> continued here.
-.
-<blockquote>
-<ol>
-<li>
-<blockquote>
-<p>Blockquote
-continued here.</p>
-</blockquote>
-</li>
-</ol>
-</blockquote>
-````````````````````````````````
-
-
-
-6. **That's all.** Nothing that is not counted as a list item by rules
- #1--5 counts as a [list item](#list-items).
-
-The rules for sublists follow from the general rules
-[above][List items]. A sublist must be indented the same number
-of spaces a paragraph would need to be in order to be included
-in the list item.
-
-So, in this case we need two spaces indent:
-
-```````````````````````````````` example
-- foo
- - bar
- - baz
- - boo
-.
-<ul>
-<li>foo
-<ul>
-<li>bar
-<ul>
-<li>baz
-<ul>
-<li>boo</li>
-</ul>
-</li>
-</ul>
-</li>
-</ul>
-</li>
-</ul>
-````````````````````````````````
-
-
-One is not enough:
-
-```````````````````````````````` example
-- foo
- - bar
- - baz
- - boo
-.
-<ul>
-<li>foo</li>
-<li>bar</li>
-<li>baz</li>
-<li>boo</li>
-</ul>
-````````````````````````````````
-
-
-Here we need four, because the list marker is wider:
-
-```````````````````````````````` example
-10) foo
- - bar
-.
-<ol start="10">
-<li>foo
-<ul>
-<li>bar</li>
-</ul>
-</li>
-</ol>
-````````````````````````````````
-
-
-Three is not enough:
-
-```````````````````````````````` example
-10) foo
- - bar
-.
-<ol start="10">
-<li>foo</li>
-</ol>
-<ul>
-<li>bar</li>
-</ul>
-````````````````````````````````
-
-
-A list may be the first block in a list item:
-
-```````````````````````````````` example
-- - foo
-.
-<ul>
-<li>
-<ul>
-<li>foo</li>
-</ul>
-</li>
-</ul>
-````````````````````````````````
-
-
-```````````````````````````````` example
-1. - 2. foo
-.
-<ol>
-<li>
-<ul>
-<li>
-<ol start="2">
-<li>foo</li>
-</ol>
-</li>
-</ul>
-</li>
-</ol>
-````````````````````````````````
-
-
-A list item can contain a heading:
-
-```````````````````````````````` example
-- # Foo
-- Bar
- ---
- baz
-.
-<ul>
-<li>
-<h1>Foo</h1>
-</li>
-<li>
-<h2>Bar</h2>
-baz</li>
-</ul>
-````````````````````````````````
-
-
-### Motivation
-
-John Gruber's Markdown spec says the following about list items:
-
-1. "List markers typically start at the left margin, but may be indented
- by up to three spaces. List markers must be followed by one or more
- spaces or a tab."
-
-2. "To make lists look nice, you can wrap items with hanging indents....
- But if you don't want to, you don't have to."
-
-3. "List items may consist of multiple paragraphs. Each subsequent
- paragraph in a list item must be indented by either 4 spaces or one
- tab."
-
-4. "It looks nice if you indent every line of the subsequent paragraphs,
- but here again, Markdown will allow you to be lazy."
-
-5. "To put a blockquote within a list item, the blockquote's `>`
- delimiters need to be indented."
-
-6. "To put a code block within a list item, the code block needs to be
- indented twice — 8 spaces or two tabs."
-
-These rules specify that a paragraph under a list item must be indented
-four spaces (presumably, from the left margin, rather than the start of
-the list marker, but this is not said), and that code under a list item
-must be indented eight spaces instead of the usual four. They also say
-that a block quote must be indented, but not by how much; however, the
-example given has four spaces indentation. Although nothing is said
-about other kinds of block-level content, it is certainly reasonable to
-infer that *all* block elements under a list item, including other
-lists, must be indented four spaces. This principle has been called the
-*four-space rule*.
-
-The four-space rule is clear and principled, and if the reference
-implementation `Markdown.pl` had followed it, it probably would have
-become the standard. However, `Markdown.pl` allowed paragraphs and
-sublists to start with only two spaces indentation, at least on the
-outer level. Worse, its behavior was inconsistent: a sublist of an
-outer-level list needed two spaces indentation, but a sublist of this
-sublist needed three spaces. It is not surprising, then, that different
-implementations of Markdown have developed very different rules for
-determining what comes under a list item. (Pandoc and python-Markdown,
-for example, stuck with Gruber's syntax description and the four-space
-rule, while discount, redcarpet, marked, PHP Markdown, and others
-followed `Markdown.pl`'s behavior more closely.)
-
-Unfortunately, given the divergences between implementations, there
-is no way to give a spec for list items that will be guaranteed not
-to break any existing documents. However, the spec given here should
-correctly handle lists formatted with either the four-space rule or
-the more forgiving `Markdown.pl` behavior, provided they are laid out
-in a way that is natural for a human to read.
-
-The strategy here is to let the width and indentation of the list marker
-determine the indentation necessary for blocks to fall under the list
-item, rather than having a fixed and arbitrary number. The writer can
-think of the body of the list item as a unit which gets indented to the
-right enough to fit the list marker (and any indentation on the list
-marker). (The laziness rule, #5, then allows continuation lines to be
-unindented if needed.)
-
-This rule is superior, we claim, to any rule requiring a fixed level of
-indentation from the margin. The four-space rule is clear but
-unnatural. It is quite unintuitive that
-
-``` markdown
-- foo
-
- bar
-
- - baz
-```
-
-should be parsed as two lists with an intervening paragraph,
-
-``` html
-<ul>
-<li>foo</li>
-</ul>
-<p>bar</p>
-<ul>
-<li>baz</li>
-</ul>
-```
-
-as the four-space rule demands, rather than a single list,
-
-``` html
-<ul>
-<li>
-<p>foo</p>
-<p>bar</p>
-<ul>
-<li>baz</li>
-</ul>
-</li>
-</ul>
-```
-
-The choice of four spaces is arbitrary. It can be learned, but it is
-not likely to be guessed, and it trips up beginners regularly.
-
-Would it help to adopt a two-space rule? The problem is that such
-a rule, together with the rule allowing 1--3 spaces indentation of the
-initial list marker, allows text that is indented *less than* the
-original list marker to be included in the list item. For example,
-`Markdown.pl` parses
-
-``` markdown
- - one
-
- two
-```
-
-as a single list item, with `two` a continuation paragraph:
-
-``` html
-<ul>
-<li>
-<p>one</p>
-<p>two</p>
-</li>
-</ul>
-```
-
-and similarly
-
-``` markdown
-> - one
->
-> two
-```
-
-as
-
-``` html
-<blockquote>
-<ul>
-<li>
-<p>one</p>
-<p>two</p>
-</li>
-</ul>
-</blockquote>
-```
-
-This is extremely unintuitive.
-
-Rather than requiring a fixed indent from the margin, we could require
-a fixed indent (say, two spaces, or even one space) from the list marker (which
-may itself be indented). This proposal would remove the last anomaly
-discussed. Unlike the spec presented above, it would count the following
-as a list item with a subparagraph, even though the paragraph `bar`
-is not indented as far as the first paragraph `foo`:
-
-``` markdown
- 10. foo
-
- bar
-```
-
-Arguably this text does read like a list item with `bar` as a subparagraph,
-which may count in favor of the proposal. However, on this proposal indented
-code would have to be indented six spaces after the list marker. And this
-would break a lot of existing Markdown, which has the pattern:
-
-``` markdown
-1. foo
-
- indented code
-```
-
-where the code is indented eight spaces. The spec above, by contrast, will
-parse this text as expected, since the code block's indentation is measured
-from the beginning of `foo`.
-
-The one case that needs special treatment is a list item that *starts*
-with indented code. How much indentation is required in that case, since
-we don't have a "first paragraph" to measure from? Rule #2 simply stipulates
-that in such cases, we require one space indentation from the list marker
-(and then the normal four spaces for the indented code). This will match the
-four-space rule in cases where the list marker plus its initial indentation
-takes four spaces (a common case), but diverge in other cases.
-
-<div class="extension">
-
-## Task list items (extension)
-
-GFM enables the `tasklist` extension, where an additional processing step is
-performed on [list items].
-
-A [task list item](@) is a [list item][list items] where the first block in it
-is a paragraph which begins with a [task list item marker] and at least one
-whitespace character before any other content.
-
-A [task list item marker](@) consists of an optional number of spaces, a left
-bracket (`[`), either a whitespace character or the letter `x` in either
-lowercase or uppercase, and then a right bracket (`]`).
-
-When rendered, the [task list item marker] is replaced with a semantic checkbox element;
-in an HTML output, this would be an `<input type="checkbox">` element.
-
-If the character between the brackets is a whitespace character, the checkbox
-is unchecked. Otherwise, the checkbox is checked.
-
-This spec does not define how the checkbox elements are interacted with: in practice,
-implementors are free to render the checkboxes as disabled or inmutable elements,
-or they may dynamically handle dynamic interactions (i.e. checking, unchecking) in
-the final rendered document.
-
-```````````````````````````````` example disabled
-- [ ] foo
-- [x] bar
-.
-<ul>
-<li><input disabled="" type="checkbox"> foo</li>
-<li><input checked="" disabled="" type="checkbox"> bar</li>
-</ul>
-````````````````````````````````
-
-Task lists can be arbitrarily nested:
-
-```````````````````````````````` example disabled
-- [x] foo
- - [ ] bar
- - [x] baz
-- [ ] bim
-.
-<ul>
-<li><input checked="" disabled="" type="checkbox"> foo
-<ul>
-<li><input disabled="" type="checkbox"> bar</li>
-<li><input checked="" disabled="" type="checkbox"> baz</li>
-</ul>
-</li>
-<li><input disabled="" type="checkbox"> bim</li>
-</ul>
-````````````````````````````````
-
-</div>
-
-## Lists
-
-A [list](@) is a sequence of one or more
-list items [of the same type]. The list items
-may be separated by any number of blank lines.
-
-Two list items are [of the same type](@)
-if they begin with a [list marker] of the same type.
-Two list markers are of the
-same type if (a) they are bullet list markers using the same character
-(`-`, `+`, or `*`) or (b) they are ordered list numbers with the same
-delimiter (either `.` or `)`).
-
-A list is an [ordered list](@)
-if its constituent list items begin with
-[ordered list markers], and a
-[bullet list](@) if its constituent list
-items begin with [bullet list markers].
-
-The [start number](@)
-of an [ordered list] is determined by the list number of
-its initial list item. The numbers of subsequent list items are
-disregarded.
-
-A list is [loose](@) if any of its constituent
-list items are separated by blank lines, or if any of its constituent
-list items directly contain two block-level elements with a blank line
-between them. Otherwise a list is [tight](@).
-(The difference in HTML output is that paragraphs in a loose list are
-wrapped in `<p>` tags, while paragraphs in a tight list are not.)
-
-Changing the bullet or ordered list delimiter starts a new list:
-
-```````````````````````````````` example
-- foo
-- bar
-+ baz
-.
-<ul>
-<li>foo</li>
-<li>bar</li>
-</ul>
-<ul>
-<li>baz</li>
-</ul>
-````````````````````````````````
-
-
-```````````````````````````````` example
-1. foo
-2. bar
-3) baz
-.
-<ol>
-<li>foo</li>
-<li>bar</li>
-</ol>
-<ol start="3">
-<li>baz</li>
-</ol>
-````````````````````````````````
-
-
-In CommonMark, a list can interrupt a paragraph. That is,
-no blank line is needed to separate a paragraph from a following
-list:
-
-```````````````````````````````` example
-Foo
-- bar
-- baz
-.
-<p>Foo</p>
-<ul>
-<li>bar</li>
-<li>baz</li>
-</ul>
-````````````````````````````````
-
-`Markdown.pl` does not allow this, through fear of triggering a list
-via a numeral in a hard-wrapped line:
-
-``` markdown
-The number of windows in my house is
-14. The number of doors is 6.
-```
-
-Oddly, though, `Markdown.pl` *does* allow a blockquote to
-interrupt a paragraph, even though the same considerations might
-apply.
-
-In CommonMark, we do allow lists to interrupt paragraphs, for
-two reasons. First, it is natural and not uncommon for people
-to start lists without blank lines:
-
-``` markdown
-I need to buy
-- new shoes
-- a coat
-- a plane ticket
-```
-
-Second, we are attracted to a
-
-> [principle of uniformity](@):
-> if a chunk of text has a certain
-> meaning, it will continue to have the same meaning when put into a
-> container block (such as a list item or blockquote).
-
-(Indeed, the spec for [list items] and [block quotes] presupposes
-this principle.) This principle implies that if
-
-``` markdown
- * I need to buy
- - new shoes
- - a coat
- - a plane ticket
-```
-
-is a list item containing a paragraph followed by a nested sublist,
-as all Markdown implementations agree it is (though the paragraph
-may be rendered without `<p>` tags, since the list is "tight"),
-then
-
-``` markdown
-I need to buy
-- new shoes
-- a coat
-- a plane ticket
-```
-
-by itself should be a paragraph followed by a nested sublist.
-
-Since it is well established Markdown practice to allow lists to
-interrupt paragraphs inside list items, the [principle of
-uniformity] requires us to allow this outside list items as
-well. ([reStructuredText](http://docutils.sourceforge.net/rst.html)
-takes a different approach, requiring blank lines before lists
-even inside other list items.)
-
-In order to solve of unwanted lists in paragraphs with
-hard-wrapped numerals, we allow only lists starting with `1` to
-interrupt paragraphs. Thus,
-
-```````````````````````````````` example
-The number of windows in my house is
-14. The number of doors is 6.
-.
-<p>The number of windows in my house is
-14. The number of doors is 6.</p>
-````````````````````````````````
-
-We may still get an unintended result in cases like
-
-```````````````````````````````` example
-The number of windows in my house is
-1. The number of doors is 6.
-.
-<p>The number of windows in my house is</p>
-<ol>
-<li>The number of doors is 6.</li>
-</ol>
-````````````````````````````````
-
-but this rule should prevent most spurious list captures.
-
-There can be any number of blank lines between items:
-
-```````````````````````````````` example
-- foo
-
-- bar
-
-
-- baz
-.
-<ul>
-<li>
-<p>foo</p>
-</li>
-<li>
-<p>bar</p>
-</li>
-<li>
-<p>baz</p>
-</li>
-</ul>
-````````````````````````````````
-
-```````````````````````````````` example
-- foo
- - bar
- - baz
-
-
- bim
-.
-<ul>
-<li>foo
-<ul>
-<li>bar
-<ul>
-<li>
-<p>baz</p>
-<p>bim</p>
-</li>
-</ul>
-</li>
-</ul>
-</li>
-</ul>
-````````````````````````````````
-
-
-To separate consecutive lists of the same type, or to separate a
-list from an indented code block that would otherwise be parsed
-as a subparagraph of the final list item, you can insert a blank HTML
-comment:
-
-```````````````````````````````` example
-- foo
-- bar
-
-<!-- -->
-
-- baz
-- bim
-.
-<ul>
-<li>foo</li>
-<li>bar</li>
-</ul>
-<!-- -->
-<ul>
-<li>baz</li>
-<li>bim</li>
-</ul>
-````````````````````````````````
-
-
-```````````````````````````````` example
-- foo
-
- notcode
-
-- foo
-
-<!-- -->
-
- code
-.
-<ul>
-<li>
-<p>foo</p>
-<p>notcode</p>
-</li>
-<li>
-<p>foo</p>
-</li>
-</ul>
-<!-- -->
-<pre><code>code
-</code></pre>
-````````````````````````````````
-
-
-List items need not be indented to the same level. The following
-list items will be treated as items at the same list level,
-since none is indented enough to belong to the previous list
-item:
-
-```````````````````````````````` example
-- a
- - b
- - c
- - d
- - e
- - f
-- g
-.
-<ul>
-<li>a</li>
-<li>b</li>
-<li>c</li>
-<li>d</li>
-<li>e</li>
-<li>f</li>
-<li>g</li>
-</ul>
-````````````````````````````````
-
-
-```````````````````````````````` example
-1. a
-
- 2. b
-
- 3. c
-.
-<ol>
-<li>
-<p>a</p>
-</li>
-<li>
-<p>b</p>
-</li>
-<li>
-<p>c</p>
-</li>
-</ol>
-````````````````````````````````
-
-Note, however, that list items may not be indented more than
-three spaces. Here `- e` is treated as a paragraph continuation
-line, because it is indented more than three spaces:
-
-```````````````````````````````` example
-- a
- - b
- - c
- - d
- - e
-.
-<ul>
-<li>a</li>
-<li>b</li>
-<li>c</li>
-<li>d
-- e</li>
-</ul>
-````````````````````````````````
-
-And here, `3. c` is treated as in indented code block,
-because it is indented four spaces and preceded by a
-blank line.
-
-```````````````````````````````` example
-1. a
-
- 2. b
-
- 3. c
-.
-<ol>
-<li>
-<p>a</p>
-</li>
-<li>
-<p>b</p>
-</li>
-</ol>
-<pre><code>3. c
-</code></pre>
-````````````````````````````````
-
-
-This is a loose list, because there is a blank line between
-two of the list items:
-
-```````````````````````````````` example
-- a
-- b
-
-- c
-.
-<ul>
-<li>
-<p>a</p>
-</li>
-<li>
-<p>b</p>
-</li>
-<li>
-<p>c</p>
-</li>
-</ul>
-````````````````````````````````
-
-
-So is this, with a empty second item:
-
-```````````````````````````````` example
-* a
-*
-
-* c
-.
-<ul>
-<li>
-<p>a</p>
-</li>
-<li></li>
-<li>
-<p>c</p>
-</li>
-</ul>
-````````````````````````````````
-
-
-These are loose lists, even though there is no space between the items,
-because one of the items directly contains two block-level elements
-with a blank line between them:
-
-```````````````````````````````` example
-- a
-- b
-
- c
-- d
-.
-<ul>
-<li>
-<p>a</p>
-</li>
-<li>
-<p>b</p>
-<p>c</p>
-</li>
-<li>
-<p>d</p>
-</li>
-</ul>
-````````````````````````````````
-
-
-```````````````````````````````` example
-- a
-- b
-
- [ref]: /url
-- d
-.
-<ul>
-<li>
-<p>a</p>
-</li>
-<li>
-<p>b</p>
-</li>
-<li>
-<p>d</p>
-</li>
-</ul>
-````````````````````````````````
-
-
-This is a tight list, because the blank lines are in a code block:
-
-```````````````````````````````` example
-- a
-- ```
- b
-
-
- ```
-- c
-.
-<ul>
-<li>a</li>
-<li>
-<pre><code>b
-
-
-</code></pre>
-</li>
-<li>c</li>
-</ul>
-````````````````````````````````
-
-
-This is a tight list, because the blank line is between two
-paragraphs of a sublist. So the sublist is loose while
-the outer list is tight:
-
-```````````````````````````````` example
-- a
- - b
-
- c
-- d
-.
-<ul>
-<li>a
-<ul>
-<li>
-<p>b</p>
-<p>c</p>
-</li>
-</ul>
-</li>
-<li>d</li>
-</ul>
-````````````````````````````````
-
-
-This is a tight list, because the blank line is inside the
-block quote:
-
-```````````````````````````````` example
-* a
- > b
- >
-* c
-.
-<ul>
-<li>a
-<blockquote>
-<p>b</p>
-</blockquote>
-</li>
-<li>c</li>
-</ul>
-````````````````````````````````
-
-
-This list is tight, because the consecutive block elements
-are not separated by blank lines:
-
-```````````````````````````````` example
-- a
- > b
- ```
- c
- ```
-- d
-.
-<ul>
-<li>a
-<blockquote>
-<p>b</p>
-</blockquote>
-<pre><code>c
-</code></pre>
-</li>
-<li>d</li>
-</ul>
-````````````````````````````````
-
-
-A single-paragraph list is tight:
-
-```````````````````````````````` example
-- a
-.
-<ul>
-<li>a</li>
-</ul>
-````````````````````````````````
-
-
-```````````````````````````````` example
-- a
- - b
-.
-<ul>
-<li>a
-<ul>
-<li>b</li>
-</ul>
-</li>
-</ul>
-````````````````````````````````
-
-
-This list is loose, because of the blank line between the
-two block elements in the list item:
-
-```````````````````````````````` example
-1. ```
- foo
- ```
-
- bar
-.
-<ol>
-<li>
-<pre><code>foo
-</code></pre>
-<p>bar</p>
-</li>
-</ol>
-````````````````````````````````
-
-
-Here the outer list is loose, the inner list tight:
-
-```````````````````````````````` example
-* foo
- * bar
-
- baz
-.
-<ul>
-<li>
-<p>foo</p>
-<ul>
-<li>bar</li>
-</ul>
-<p>baz</p>
-</li>
-</ul>
-````````````````````````````````
-
-
-```````````````````````````````` example
-- a
- - b
- - c
-
-- d
- - e
- - f
-.
-<ul>
-<li>
-<p>a</p>
-<ul>
-<li>b</li>
-<li>c</li>
-</ul>
-</li>
-<li>
-<p>d</p>
-<ul>
-<li>e</li>
-<li>f</li>
-</ul>
-</li>
-</ul>
-````````````````````````````````
-
-
-# Inlines
-
-Inlines are parsed sequentially from the beginning of the character
-stream to the end (left to right, in left-to-right languages).
-Thus, for example, in
-
-```````````````````````````````` example
-`hi`lo`
-.
-<p><code>hi</code>lo`</p>
-````````````````````````````````
-
-`hi` is parsed as code, leaving the backtick at the end as a literal
-backtick.
-
-
-## Backslash escapes
-
-Any ASCII punctuation character may be backslash-escaped:
-
-```````````````````````````````` example
-\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~
-.
-<p>!&quot;#$%&amp;'()*+,-./:;&lt;=&gt;?@[\]^_`{|}~</p>
-````````````````````````````````
-
-
-Backslashes before other characters are treated as literal
-backslashes:
-
-```````````````````````````````` example
-\→\A\a\ \3\φ\«
-.
-<p>\→\A\a\ \3\φ\«</p>
-````````````````````````````````
-
-
-Escaped characters are treated as regular characters and do
-not have their usual Markdown meanings:
-
-```````````````````````````````` example
-\*not emphasized*
-\<br/> not a tag
-\[not a link](/foo)
-\`not code`
-1\. not a list
-\* not a list
-\# not a heading
-\[foo]: /url "not a reference"
-\&ouml; not a character entity
-.
-<p>*not emphasized*
-&lt;br/&gt; not a tag
-[not a link](/foo)
-`not code`
-1. not a list
-* not a list
-# not a heading
-[foo]: /url &quot;not a reference&quot;
-&amp;ouml; not a character entity</p>
-````````````````````````````````
-
-
-If a backslash is itself escaped, the following character is not:
-
-```````````````````````````````` example
-\\*emphasis*
-.
-<p>\<em>emphasis</em></p>
-````````````````````````````````
-
-
-A backslash at the end of the line is a [hard line break]:
-
-```````````````````````````````` example
-foo\
-bar
-.
-<p>foo<br />
-bar</p>
-````````````````````````````````
-
-
-Backslash escapes do not work in code blocks, code spans, autolinks, or
-raw HTML:
-
-```````````````````````````````` example
-`` \[\` ``
-.
-<p><code>\[\`</code></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
- \[\]
-.
-<pre><code>\[\]
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
-~~~
-\[\]
-~~~
-.
-<pre><code>\[\]
-</code></pre>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<http://example.com?find=\*>
-.
-<p><a href="http://example.com?find=%5C*">http://example.com?find=\*</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<a href="/bar\/)">
-.
-<a href="/bar\/)">
-````````````````````````````````
-
-
-But they work in all other contexts, including URLs and link titles,
-link references, and [info strings] in [fenced code blocks]:
-
-```````````````````````````````` example
-[foo](/bar\* "ti\*tle")
-.
-<p><a href="/bar*" title="ti*tle">foo</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[foo]
-
-[foo]: /bar\* "ti\*tle"
-.
-<p><a href="/bar*" title="ti*tle">foo</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-``` foo\+bar
-foo
-```
-.
-<pre><code class="language-foo+bar">foo
-</code></pre>
-````````````````````````````````
-
-
-
-## Entity and numeric character references
-
-Valid HTML entity references and numeric character references
-can be used in place of the corresponding Unicode character,
-with the following exceptions:
-
-- Entity and character references are not recognized in code
- blocks and code spans.
-
-- Entity and character references cannot stand in place of
- special characters that define structural elements in
- CommonMark. For example, although `&#42;` can be used
- in place of a literal `*` character, `&#42;` cannot replace
- `*` in emphasis delimiters, bullet list markers, or thematic
- breaks.
-
-Conforming CommonMark parsers need not store information about
-whether a particular character was represented in the source
-using a Unicode character or an entity reference.
-
-[Entity references](@) consist of `&` + any of the valid
-HTML5 entity names + `;`. The
-document <https://html.spec.whatwg.org/multipage/entities.json>
-is used as an authoritative source for the valid entity
-references and their corresponding code points.
-
-```````````````````````````````` example
-&nbsp; &amp; &copy; &AElig; &Dcaron;
-&frac34; &HilbertSpace; &DifferentialD;
-&ClockwiseContourIntegral; &ngE;
-.
-<p>  &amp; © Æ Ď
-¾ ℋ ⅆ
-∲ ≧̸</p>
-````````````````````````````````
-
-
-[Decimal numeric character
-references](@)
-consist of `&#` + a string of 1--7 arabic digits + `;`. A
-numeric character reference is parsed as the corresponding
-Unicode character. Invalid Unicode code points will be replaced by
-the REPLACEMENT CHARACTER (`U+FFFD`). For security reasons,
-the code point `U+0000` will also be replaced by `U+FFFD`.
-
-```````````````````````````````` example
-&#35; &#1234; &#992; &#0;
-.
-<p># Ӓ Ϡ �</p>
-````````````````````````````````
-
-
-[Hexadecimal numeric character
-references](@) consist of `&#` +
-either `X` or `x` + a string of 1-6 hexadecimal digits + `;`.
-They too are parsed as the corresponding Unicode character (this
-time specified with a hexadecimal numeral instead of decimal).
-
-```````````````````````````````` example
-&#X22; &#XD06; &#xcab;
-.
-<p>&quot; ആ ಫ</p>
-````````````````````````````````
-
-
-Here are some nonentities:
-
-```````````````````````````````` example
-&nbsp &x; &#; &#x;
-&#987654321;
-&#abcdef0;
-&ThisIsNotDefined; &hi?;
-.
-<p>&amp;nbsp &amp;x; &amp;#; &amp;#x;
-&amp;#987654321;
-&amp;#abcdef0;
-&amp;ThisIsNotDefined; &amp;hi?;</p>
-````````````````````````````````
-
-
-Although HTML5 does accept some entity references
-without a trailing semicolon (such as `&copy`), these are not
-recognized here, because it makes the grammar too ambiguous:
-
-```````````````````````````````` example
-&copy
-.
-<p>&amp;copy</p>
-````````````````````````````````
-
-
-Strings that are not on the list of HTML5 named entities are not
-recognized as entity references either:
-
-```````````````````````````````` example
-&MadeUpEntity;
-.
-<p>&amp;MadeUpEntity;</p>
-````````````````````````````````
-
-
-Entity and numeric character references are recognized in any
-context besides code spans or code blocks, including
-URLs, [link titles], and [fenced code block][] [info strings]:
-
-```````````````````````````````` example
-<a href="&ouml;&ouml;.html">
-.
-<a href="&ouml;&ouml;.html">
-````````````````````````````````
-
-
-```````````````````````````````` example
-[foo](/f&ouml;&ouml; "f&ouml;&ouml;")
-.
-<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[foo]
-
-[foo]: /f&ouml;&ouml; "f&ouml;&ouml;"
-.
-<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-``` f&ouml;&ouml;
-foo
-```
-.
-<pre><code class="language-föö">foo
-</code></pre>
-````````````````````````````````
-
-
-Entity and numeric character references are treated as literal
-text in code spans and code blocks:
-
-```````````````````````````````` example
-`f&ouml;&ouml;`
-.
-<p><code>f&amp;ouml;&amp;ouml;</code></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
- f&ouml;f&ouml;
-.
-<pre><code>f&amp;ouml;f&amp;ouml;
-</code></pre>
-````````````````````````````````
-
-
-Entity and numeric character references cannot be used
-in place of symbols indicating structure in CommonMark
-documents.
-
-```````````````````````````````` example
-&#42;foo&#42;
-*foo*
-.
-<p>*foo*
-<em>foo</em></p>
-````````````````````````````````
-
-```````````````````````````````` example
-&#42; foo
-
-* foo
-.
-<p>* foo</p>
-<ul>
-<li>foo</li>
-</ul>
-````````````````````````````````
-
-```````````````````````````````` example
-foo&#10;&#10;bar
-.
-<p>foo
-
-bar</p>
-````````````````````````````````
-
-```````````````````````````````` example
-&#9;foo
-.
-<p>→foo</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[a](url &quot;tit&quot;)
-.
-<p>[a](url &quot;tit&quot;)</p>
-````````````````````````````````
-
-
-## Code spans
-
-A [backtick string](@)
-is a string of one or more backtick characters (`` ` ``) that is neither
-preceded nor followed by a backtick.
-
-A [code span](@) begins with a backtick string and ends with
-a backtick string of equal length. The contents of the code span are
-the characters between the two backtick strings, normalized in the
-following ways:
-
-- First, [line endings] are converted to [spaces].
-- If the resulting string both begins *and* ends with a [space]
- character, but does not consist entirely of [space]
- characters, a single [space] character is removed from the
- front and back. This allows you to include code that begins
- or ends with backtick characters, which must be separated by
- whitespace from the opening or closing backtick strings.
-
-This is a simple code span:
-
-```````````````````````````````` example
-`foo`
-.
-<p><code>foo</code></p>
-````````````````````````````````
-
-
-Here two backticks are used, because the code contains a backtick.
-This example also illustrates stripping of a single leading and
-trailing space:
-
-```````````````````````````````` example
-`` foo ` bar ``
-.
-<p><code>foo ` bar</code></p>
-````````````````````````````````
-
-
-This example shows the motivation for stripping leading and trailing
-spaces:
-
-```````````````````````````````` example
-` `` `
-.
-<p><code>``</code></p>
-````````````````````````````````
-
-Note that only *one* space is stripped:
-
-```````````````````````````````` example
-` `` `
-.
-<p><code> `` </code></p>
-````````````````````````````````
-
-The stripping only happens if the space is on both
-sides of the string:
-
-```````````````````````````````` example
-` a`
-.
-<p><code> a</code></p>
-````````````````````````````````
-
-Only [spaces], and not [unicode whitespace] in general, are
-stripped in this way:
-
-```````````````````````````````` example
-` b `
-.
-<p><code> b </code></p>
-````````````````````````````````
-
-No stripping occurs if the code span contains only spaces:
-
-```````````````````````````````` example
-` `
-` `
-.
-<p><code> </code>
-<code> </code></p>
-````````````````````````````````
-
-
-[Line endings] are treated like spaces:
-
-```````````````````````````````` example
-``
-foo
-bar
-baz
-``
-.
-<p><code>foo bar baz</code></p>
-````````````````````````````````
-
-```````````````````````````````` example
-``
-foo
-``
-.
-<p><code>foo </code></p>
-````````````````````````````````
-
-
-Interior spaces are not collapsed:
-
-```````````````````````````````` example
-`foo bar
-baz`
-.
-<p><code>foo bar baz</code></p>
-````````````````````````````````
-
-Note that browsers will typically collapse consecutive spaces
-when rendering `<code>` elements, so it is recommended that
-the following CSS be used:
-
- code{white-space: pre-wrap;}
-
-
-Note that backslash escapes do not work in code spans. All backslashes
-are treated literally:
-
-```````````````````````````````` example
-`foo\`bar`
-.
-<p><code>foo\</code>bar`</p>
-````````````````````````````````
-
-
-Backslash escapes are never needed, because one can always choose a
-string of *n* backtick characters as delimiters, where the code does
-not contain any strings of exactly *n* backtick characters.
-
-```````````````````````````````` example
-``foo`bar``
-.
-<p><code>foo`bar</code></p>
-````````````````````````````````
-
-```````````````````````````````` example
-` foo `` bar `
-.
-<p><code>foo `` bar</code></p>
-````````````````````````````````
-
-
-Code span backticks have higher precedence than any other inline
-constructs except HTML tags and autolinks. Thus, for example, this is
-not parsed as emphasized text, since the second `*` is part of a code
-span:
-
-```````````````````````````````` example
-*foo`*`
-.
-<p>*foo<code>*</code></p>
-````````````````````````````````
-
-
-And this is not parsed as a link:
-
-```````````````````````````````` example
-[not a `link](/foo`)
-.
-<p>[not a <code>link](/foo</code>)</p>
-````````````````````````````````
-
-
-Code spans, HTML tags, and autolinks have the same precedence.
-Thus, this is code:
-
-```````````````````````````````` example
-`<a href="`">`
-.
-<p><code>&lt;a href=&quot;</code>&quot;&gt;`</p>
-````````````````````````````````
-
-
-But this is an HTML tag:
-
-```````````````````````````````` example
-<a href="`">`
-.
-<p><a href="`">`</p>
-````````````````````````````````
-
-
-And this is code:
-
-```````````````````````````````` example
-`<http://foo.bar.`baz>`
-.
-<p><code>&lt;http://foo.bar.</code>baz&gt;`</p>
-````````````````````````````````
-
-
-But this is an autolink:
-
-```````````````````````````````` example
-<http://foo.bar.`baz>`
-.
-<p><a href="http://foo.bar.%60baz">http://foo.bar.`baz</a>`</p>
-````````````````````````````````
-
-
-When a backtick string is not closed by a matching backtick string,
-we just have literal backticks:
-
-```````````````````````````````` example
-```foo``
-.
-<p>```foo``</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-`foo
-.
-<p>`foo</p>
-````````````````````````````````
-
-The following case also illustrates the need for opening and
-closing backtick strings to be equal in length:
-
-```````````````````````````````` example
-`foo``bar``
-.
-<p>`foo<code>bar</code></p>
-````````````````````````````````
-
-
-## Emphasis and strong emphasis
-
-John Gruber's original [Markdown syntax
-description](http://daringfireball.net/projects/markdown/syntax#em) says:
-
-> Markdown treats asterisks (`*`) and underscores (`_`) as indicators of
-> emphasis. Text wrapped with one `*` or `_` will be wrapped with an HTML
-> `<em>` tag; double `*`'s or `_`'s will be wrapped with an HTML `<strong>`
-> tag.
-
-This is enough for most users, but these rules leave much undecided,
-especially when it comes to nested emphasis. The original
-`Markdown.pl` test suite makes it clear that triple `***` and
-`___` delimiters can be used for strong emphasis, and most
-implementations have also allowed the following patterns:
-
-``` markdown
-***strong emph***
-***strong** in emph*
-***emph* in strong**
-**in strong *emph***
-*in emph **strong***
-```
-
-The following patterns are less widely supported, but the intent
-is clear and they are useful (especially in contexts like bibliography
-entries):
-
-``` markdown
-*emph *with emph* in it*
-**strong **with strong** in it**
-```
-
-Many implementations have also restricted intraword emphasis to
-the `*` forms, to avoid unwanted emphasis in words containing
-internal underscores. (It is best practice to put these in code
-spans, but users often do not.)
-
-``` markdown
-internal emphasis: foo*bar*baz
-no emphasis: foo_bar_baz
-```
-
-The rules given below capture all of these patterns, while allowing
-for efficient parsing strategies that do not backtrack.
-
-First, some definitions. A [delimiter run](@) is either
-a sequence of one or more `*` characters that is not preceded or
-followed by a non-backslash-escaped `*` character, or a sequence
-of one or more `_` characters that is not preceded or followed by
-a non-backslash-escaped `_` character.
-
-A [left-flanking delimiter run](@) is
-a [delimiter run] that is (1) not followed by [Unicode whitespace],
-and either (2a) not followed by a [punctuation character], or
-(2b) followed by a [punctuation character] and
-preceded by [Unicode whitespace] or a [punctuation character].
-For purposes of this definition, the beginning and the end of
-the line count as Unicode whitespace.
-
-A [right-flanking delimiter run](@) is
-a [delimiter run] that is (1) not preceded by [Unicode whitespace],
-and either (2a) not preceded by a [punctuation character], or
-(2b) preceded by a [punctuation character] and
-followed by [Unicode whitespace] or a [punctuation character].
-For purposes of this definition, the beginning and the end of
-the line count as Unicode whitespace.
-
-Here are some examples of delimiter runs.
-
- - left-flanking but not right-flanking:
-
- ```
- ***abc
- _abc
- **"abc"
- _"abc"
- ```
-
- - right-flanking but not left-flanking:
-
- ```
- abc***
- abc_
- "abc"**
- "abc"_
- ```
-
- - Both left and right-flanking:
-
- ```
- abc***def
- "abc"_"def"
- ```
-
- - Neither left nor right-flanking:
-
- ```
- abc *** def
- a _ b
- ```
-
-(The idea of distinguishing left-flanking and right-flanking
-delimiter runs based on the character before and the character
-after comes from Roopesh Chander's
-[vfmd](http://www.vfmd.org/vfmd-spec/specification/#procedure-for-identifying-emphasis-tags).
-vfmd uses the terminology "emphasis indicator string" instead of "delimiter
-run," and its rules for distinguishing left- and right-flanking runs
-are a bit more complex than the ones given here.)
-
-The following rules define emphasis and strong emphasis:
-
-1. A single `*` character [can open emphasis](@)
- iff (if and only if) it is part of a [left-flanking delimiter run].
-
-2. A single `_` character [can open emphasis] iff
- it is part of a [left-flanking delimiter run]
- and either (a) not part of a [right-flanking delimiter run]
- or (b) part of a [right-flanking delimiter run]
- preceded by punctuation.
-
-3. A single `*` character [can close emphasis](@)
- iff it is part of a [right-flanking delimiter run].
-
-4. A single `_` character [can close emphasis] iff
- it is part of a [right-flanking delimiter run]
- and either (a) not part of a [left-flanking delimiter run]
- or (b) part of a [left-flanking delimiter run]
- followed by punctuation.
-
-5. A double `**` [can open strong emphasis](@)
- iff it is part of a [left-flanking delimiter run].
-
-6. A double `__` [can open strong emphasis] iff
- it is part of a [left-flanking delimiter run]
- and either (a) not part of a [right-flanking delimiter run]
- or (b) part of a [right-flanking delimiter run]
- preceded by punctuation.
-
-7. A double `**` [can close strong emphasis](@)
- iff it is part of a [right-flanking delimiter run].
-
-8. A double `__` [can close strong emphasis] iff
- it is part of a [right-flanking delimiter run]
- and either (a) not part of a [left-flanking delimiter run]
- or (b) part of a [left-flanking delimiter run]
- followed by punctuation.
-
-9. Emphasis begins with a delimiter that [can open emphasis] and ends
- with a delimiter that [can close emphasis], and that uses the same
- character (`_` or `*`) as the opening delimiter. The
- opening and closing delimiters must belong to separate
- [delimiter runs]. If one of the delimiters can both
- open and close emphasis, then the sum of the lengths of the
- delimiter runs containing the opening and closing delimiters
- must not be a multiple of 3 unless both lengths are
- multiples of 3.
-
-10. Strong emphasis begins with a delimiter that
- [can open strong emphasis] and ends with a delimiter that
- [can close strong emphasis], and that uses the same character
- (`_` or `*`) as the opening delimiter. The
- opening and closing delimiters must belong to separate
- [delimiter runs]. If one of the delimiters can both open
- and close strong emphasis, then the sum of the lengths of
- the delimiter runs containing the opening and closing
- delimiters must not be a multiple of 3 unless both lengths
- are multiples of 3.
-
-11. A literal `*` character cannot occur at the beginning or end of
- `*`-delimited emphasis or `**`-delimited strong emphasis, unless it
- is backslash-escaped.
-
-12. A literal `_` character cannot occur at the beginning or end of
- `_`-delimited emphasis or `__`-delimited strong emphasis, unless it
- is backslash-escaped.
-
-Where rules 1--12 above are compatible with multiple parsings,
-the following principles resolve ambiguity:
-
-13. The number of nestings should be minimized. Thus, for example,
- an interpretation `<strong>...</strong>` is always preferred to
- `<em><em>...</em></em>`.
-
-14. An interpretation `<em><strong>...</strong></em>` is always
- preferred to `<strong><em>...</em></strong>`.
-
-15. When two potential emphasis or strong emphasis spans overlap,
- so that the second begins before the first ends and ends after
- the first ends, the first takes precedence. Thus, for example,
- `*foo _bar* baz_` is parsed as `<em>foo _bar</em> baz_` rather
- than `*foo <em>bar* baz</em>`.
-
-16. When there are two potential emphasis or strong emphasis spans
- with the same closing delimiter, the shorter one (the one that
- opens later) takes precedence. Thus, for example,
- `**foo **bar baz**` is parsed as `**foo <strong>bar baz</strong>`
- rather than `<strong>foo **bar baz</strong>`.
-
-17. Inline code spans, links, images, and HTML tags group more tightly
- than emphasis. So, when there is a choice between an interpretation
- that contains one of these elements and one that does not, the
- former always wins. Thus, for example, `*[foo*](bar)` is
- parsed as `*<a href="bar">foo*</a>` rather than as
- `<em>[foo</em>](bar)`.
-
-These rules can be illustrated through a series of examples.
-
-Rule 1:
-
-```````````````````````````````` example
-*foo bar*
-.
-<p><em>foo bar</em></p>
-````````````````````````````````
-
-
-This is not emphasis, because the opening `*` is followed by
-whitespace, and hence not part of a [left-flanking delimiter run]:
-
-```````````````````````````````` example
-a * foo bar*
-.
-<p>a * foo bar*</p>
-````````````````````````````````
-
-
-This is not emphasis, because the opening `*` is preceded
-by an alphanumeric and followed by punctuation, and hence
-not part of a [left-flanking delimiter run]:
-
-```````````````````````````````` example
-a*"foo"*
-.
-<p>a*&quot;foo&quot;*</p>
-````````````````````````````````
-
-
-Unicode nonbreaking spaces count as whitespace, too:
-
-```````````````````````````````` example
-* a *
-.
-<p>* a *</p>
-````````````````````````````````
-
-
-Intraword emphasis with `*` is permitted:
-
-```````````````````````````````` example
-foo*bar*
-.
-<p>foo<em>bar</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-5*6*78
-.
-<p>5<em>6</em>78</p>
-````````````````````````````````
-
-
-Rule 2:
-
-```````````````````````````````` example
-_foo bar_
-.
-<p><em>foo bar</em></p>
-````````````````````````````````
-
-
-This is not emphasis, because the opening `_` is followed by
-whitespace:
-
-```````````````````````````````` example
-_ foo bar_
-.
-<p>_ foo bar_</p>
-````````````````````````````````
-
-
-This is not emphasis, because the opening `_` is preceded
-by an alphanumeric and followed by punctuation:
-
-```````````````````````````````` example
-a_"foo"_
-.
-<p>a_&quot;foo&quot;_</p>
-````````````````````````````````
-
-
-Emphasis with `_` is not allowed inside words:
-
-```````````````````````````````` example
-foo_bar_
-.
-<p>foo_bar_</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-5_6_78
-.
-<p>5_6_78</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-приÑтанÑм_ÑтремÑÑ‚ÑÑ_
-.
-<p>приÑтанÑм_ÑтремÑÑ‚ÑÑ_</p>
-````````````````````````````````
-
-
-Here `_` does not generate emphasis, because the first delimiter run
-is right-flanking and the second left-flanking:
-
-```````````````````````````````` example
-aa_"bb"_cc
-.
-<p>aa_&quot;bb&quot;_cc</p>
-````````````````````````````````
-
-
-This is emphasis, even though the opening delimiter is
-both left- and right-flanking, because it is preceded by
-punctuation:
-
-```````````````````````````````` example
-foo-_(bar)_
-.
-<p>foo-<em>(bar)</em></p>
-````````````````````````````````
-
-
-Rule 3:
-
-This is not emphasis, because the closing delimiter does
-not match the opening delimiter:
-
-```````````````````````````````` example
-_foo*
-.
-<p>_foo*</p>
-````````````````````````````````
-
-
-This is not emphasis, because the closing `*` is preceded by
-whitespace:
-
-```````````````````````````````` example
-*foo bar *
-.
-<p>*foo bar *</p>
-````````````````````````````````
-
-
-A newline also counts as whitespace:
-
-```````````````````````````````` example
-*foo bar
-*
-.
-<p>*foo bar
-*</p>
-````````````````````````````````
-
-
-This is not emphasis, because the second `*` is
-preceded by punctuation and followed by an alphanumeric
-(hence it is not part of a [right-flanking delimiter run]:
-
-```````````````````````````````` example
-*(*foo)
-.
-<p>*(*foo)</p>
-````````````````````````````````
-
-
-The point of this restriction is more easily appreciated
-with this example:
-
-```````````````````````````````` example
-*(*foo*)*
-.
-<p><em>(<em>foo</em>)</em></p>
-````````````````````````````````
-
-
-Intraword emphasis with `*` is allowed:
-
-```````````````````````````````` example
-*foo*bar
-.
-<p><em>foo</em>bar</p>
-````````````````````````````````
-
-
-
-Rule 4:
-
-This is not emphasis, because the closing `_` is preceded by
-whitespace:
-
-```````````````````````````````` example
-_foo bar _
-.
-<p>_foo bar _</p>
-````````````````````````````````
-
-
-This is not emphasis, because the second `_` is
-preceded by punctuation and followed by an alphanumeric:
-
-```````````````````````````````` example
-_(_foo)
-.
-<p>_(_foo)</p>
-````````````````````````````````
-
-
-This is emphasis within emphasis:
-
-```````````````````````````````` example
-_(_foo_)_
-.
-<p><em>(<em>foo</em>)</em></p>
-````````````````````````````````
-
-
-Intraword emphasis is disallowed for `_`:
-
-```````````````````````````````` example
-_foo_bar
-.
-<p>_foo_bar</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-_приÑтанÑм_ÑтремÑÑ‚ÑÑ
-.
-<p>_приÑтанÑм_ÑтремÑÑ‚ÑÑ</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-_foo_bar_baz_
-.
-<p><em>foo_bar_baz</em></p>
-````````````````````````````````
-
-
-This is emphasis, even though the closing delimiter is
-both left- and right-flanking, because it is followed by
-punctuation:
-
-```````````````````````````````` example
-_(bar)_.
-.
-<p><em>(bar)</em>.</p>
-````````````````````````````````
-
-
-Rule 5:
-
-```````````````````````````````` example
-**foo bar**
-.
-<p><strong>foo bar</strong></p>
-````````````````````````````````
-
-
-This is not strong emphasis, because the opening delimiter is
-followed by whitespace:
-
-```````````````````````````````` example
-** foo bar**
-.
-<p>** foo bar**</p>
-````````````````````````````````
-
-
-This is not strong emphasis, because the opening `**` is preceded
-by an alphanumeric and followed by punctuation, and hence
-not part of a [left-flanking delimiter run]:
-
-```````````````````````````````` example
-a**"foo"**
-.
-<p>a**&quot;foo&quot;**</p>
-````````````````````````````````
-
-
-Intraword strong emphasis with `**` is permitted:
-
-```````````````````````````````` example
-foo**bar**
-.
-<p>foo<strong>bar</strong></p>
-````````````````````````````````
-
-
-Rule 6:
-
-```````````````````````````````` example
-__foo bar__
-.
-<p><strong>foo bar</strong></p>
-````````````````````````````````
-
-
-This is not strong emphasis, because the opening delimiter is
-followed by whitespace:
-
-```````````````````````````````` example
-__ foo bar__
-.
-<p>__ foo bar__</p>
-````````````````````````````````
-
-
-A newline counts as whitespace:
-```````````````````````````````` example
-__
-foo bar__
-.
-<p>__
-foo bar__</p>
-````````````````````````````````
-
-
-This is not strong emphasis, because the opening `__` is preceded
-by an alphanumeric and followed by punctuation:
-
-```````````````````````````````` example
-a__"foo"__
-.
-<p>a__&quot;foo&quot;__</p>
-````````````````````````````````
-
-
-Intraword strong emphasis is forbidden with `__`:
-
-```````````````````````````````` example
-foo__bar__
-.
-<p>foo__bar__</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-5__6__78
-.
-<p>5__6__78</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-приÑтанÑм__ÑтремÑÑ‚ÑÑ__
-.
-<p>приÑтанÑм__ÑтремÑÑ‚ÑÑ__</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-__foo, __bar__, baz__
-.
-<p><strong>foo, <strong>bar</strong>, baz</strong></p>
-````````````````````````````````
-
-
-This is strong emphasis, even though the opening delimiter is
-both left- and right-flanking, because it is preceded by
-punctuation:
-
-```````````````````````````````` example
-foo-__(bar)__
-.
-<p>foo-<strong>(bar)</strong></p>
-````````````````````````````````
-
-
-
-Rule 7:
-
-This is not strong emphasis, because the closing delimiter is preceded
-by whitespace:
-
-```````````````````````````````` example
-**foo bar **
-.
-<p>**foo bar **</p>
-````````````````````````````````
-
-
-(Nor can it be interpreted as an emphasized `*foo bar *`, because of
-Rule 11.)
-
-This is not strong emphasis, because the second `**` is
-preceded by punctuation and followed by an alphanumeric:
-
-```````````````````````````````` example
-**(**foo)
-.
-<p>**(**foo)</p>
-````````````````````````````````
-
-
-The point of this restriction is more easily appreciated
-with these examples:
-
-```````````````````````````````` example
-*(**foo**)*
-.
-<p><em>(<strong>foo</strong>)</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-**Gomphocarpus (*Gomphocarpus physocarpus*, syn.
-*Asclepias physocarpa*)**
-.
-<p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.
-<em>Asclepias physocarpa</em>)</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-**foo "*bar*" foo**
-.
-<p><strong>foo &quot;<em>bar</em>&quot; foo</strong></p>
-````````````````````````````````
-
-
-Intraword emphasis:
-
-```````````````````````````````` example
-**foo**bar
-.
-<p><strong>foo</strong>bar</p>
-````````````````````````````````
-
-
-Rule 8:
-
-This is not strong emphasis, because the closing delimiter is
-preceded by whitespace:
-
-```````````````````````````````` example
-__foo bar __
-.
-<p>__foo bar __</p>
-````````````````````````````````
-
-
-This is not strong emphasis, because the second `__` is
-preceded by punctuation and followed by an alphanumeric:
-
-```````````````````````````````` example
-__(__foo)
-.
-<p>__(__foo)</p>
-````````````````````````````````
-
-
-The point of this restriction is more easily appreciated
-with this example:
-
-```````````````````````````````` example
-_(__foo__)_
-.
-<p><em>(<strong>foo</strong>)</em></p>
-````````````````````````````````
-
-
-Intraword strong emphasis is forbidden with `__`:
-
-```````````````````````````````` example
-__foo__bar
-.
-<p>__foo__bar</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-__приÑтанÑм__ÑтремÑÑ‚ÑÑ
-.
-<p>__приÑтанÑм__ÑтремÑÑ‚ÑÑ</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-__foo__bar__baz__
-.
-<p><strong>foo__bar__baz</strong></p>
-````````````````````````````````
-
-
-This is strong emphasis, even though the closing delimiter is
-both left- and right-flanking, because it is followed by
-punctuation:
-
-```````````````````````````````` example
-__(bar)__.
-.
-<p><strong>(bar)</strong>.</p>
-````````````````````````````````
-
-
-Rule 9:
-
-Any nonempty sequence of inline elements can be the contents of an
-emphasized span.
-
-```````````````````````````````` example
-*foo [bar](/url)*
-.
-<p><em>foo <a href="/url">bar</a></em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-*foo
-bar*
-.
-<p><em>foo
-bar</em></p>
-````````````````````````````````
-
-
-In particular, emphasis and strong emphasis can be nested
-inside emphasis:
-
-```````````````````````````````` example
-_foo __bar__ baz_
-.
-<p><em>foo <strong>bar</strong> baz</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-_foo _bar_ baz_
-.
-<p><em>foo <em>bar</em> baz</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-__foo_ bar_
-.
-<p><em><em>foo</em> bar</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-*foo *bar**
-.
-<p><em>foo <em>bar</em></em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-*foo **bar** baz*
-.
-<p><em>foo <strong>bar</strong> baz</em></p>
-````````````````````````````````
-
-```````````````````````````````` example
-*foo**bar**baz*
-.
-<p><em>foo<strong>bar</strong>baz</em></p>
-````````````````````````````````
-
-Note that in the preceding case, the interpretation
-
-``` markdown
-<p><em>foo</em><em>bar<em></em>baz</em></p>
-```
-
-
-is precluded by the condition that a delimiter that
-can both open and close (like the `*` after `foo`)
-cannot form emphasis if the sum of the lengths of
-the delimiter runs containing the opening and
-closing delimiters is a multiple of 3 unless
-both lengths are multiples of 3.
-
-
-For the same reason, we don't get two consecutive
-emphasis sections in this example:
-
-```````````````````````````````` example
-*foo**bar*
-.
-<p><em>foo**bar</em></p>
-````````````````````````````````
-
-
-The same condition ensures that the following
-cases are all strong emphasis nested inside
-emphasis, even when the interior spaces are
-omitted:
-
-
-```````````````````````````````` example
-***foo** bar*
-.
-<p><em><strong>foo</strong> bar</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-*foo **bar***
-.
-<p><em>foo <strong>bar</strong></em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-*foo**bar***
-.
-<p><em>foo<strong>bar</strong></em></p>
-````````````````````````````````
-
-
-When the lengths of the interior closing and opening
-delimiter runs are *both* multiples of 3, though,
-they can match to create emphasis:
-
-```````````````````````````````` example
-foo***bar***baz
-.
-<p>foo<em><strong>bar</strong></em>baz</p>
-````````````````````````````````
-
-```````````````````````````````` example
-foo******bar*********baz
-.
-<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>
-````````````````````````````````
-
-
-Indefinite levels of nesting are possible:
-
-```````````````````````````````` example
-*foo **bar *baz* bim** bop*
-.
-<p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-*foo [*bar*](/url)*
-.
-<p><em>foo <a href="/url"><em>bar</em></a></em></p>
-````````````````````````````````
-
-
-There can be no empty emphasis or strong emphasis:
-
-```````````````````````````````` example
-** is not an empty emphasis
-.
-<p>** is not an empty emphasis</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-**** is not an empty strong emphasis
-.
-<p>**** is not an empty strong emphasis</p>
-````````````````````````````````
-
-
-
-Rule 10:
-
-Any nonempty sequence of inline elements can be the contents of an
-strongly emphasized span.
-
-```````````````````````````````` example
-**foo [bar](/url)**
-.
-<p><strong>foo <a href="/url">bar</a></strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-**foo
-bar**
-.
-<p><strong>foo
-bar</strong></p>
-````````````````````````````````
-
-
-In particular, emphasis and strong emphasis can be nested
-inside strong emphasis:
-
-```````````````````````````````` example
-__foo _bar_ baz__
-.
-<p><strong>foo <em>bar</em> baz</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-__foo __bar__ baz__
-.
-<p><strong>foo <strong>bar</strong> baz</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-____foo__ bar__
-.
-<p><strong><strong>foo</strong> bar</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-**foo **bar****
-.
-<p><strong>foo <strong>bar</strong></strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-**foo *bar* baz**
-.
-<p><strong>foo <em>bar</em> baz</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-**foo*bar*baz**
-.
-<p><strong>foo<em>bar</em>baz</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-***foo* bar**
-.
-<p><strong><em>foo</em> bar</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-**foo *bar***
-.
-<p><strong>foo <em>bar</em></strong></p>
-````````````````````````````````
-
-
-Indefinite levels of nesting are possible:
-
-```````````````````````````````` example
-**foo *bar **baz**
-bim* bop**
-.
-<p><strong>foo <em>bar <strong>baz</strong>
-bim</em> bop</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-**foo [*bar*](/url)**
-.
-<p><strong>foo <a href="/url"><em>bar</em></a></strong></p>
-````````````````````````````````
-
-
-There can be no empty emphasis or strong emphasis:
-
-```````````````````````````````` example
-__ is not an empty emphasis
-.
-<p>__ is not an empty emphasis</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-____ is not an empty strong emphasis
-.
-<p>____ is not an empty strong emphasis</p>
-````````````````````````````````
-
-
-
-Rule 11:
-
-```````````````````````````````` example
-foo ***
-.
-<p>foo ***</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-foo *\**
-.
-<p>foo <em>*</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-foo *_*
-.
-<p>foo <em>_</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-foo *****
-.
-<p>foo *****</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-foo **\***
-.
-<p>foo <strong>*</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-foo **_**
-.
-<p>foo <strong>_</strong></p>
-````````````````````````````````
-
-
-Note that when delimiters do not match evenly, Rule 11 determines
-that the excess literal `*` characters will appear outside of the
-emphasis, rather than inside it:
-
-```````````````````````````````` example
-**foo*
-.
-<p>*<em>foo</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-*foo**
-.
-<p><em>foo</em>*</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-***foo**
-.
-<p>*<strong>foo</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-****foo*
-.
-<p>***<em>foo</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-**foo***
-.
-<p><strong>foo</strong>*</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-*foo****
-.
-<p><em>foo</em>***</p>
-````````````````````````````````
-
-
-
-Rule 12:
-
-```````````````````````````````` example
-foo ___
-.
-<p>foo ___</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-foo _\__
-.
-<p>foo <em>_</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-foo _*_
-.
-<p>foo <em>*</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-foo _____
-.
-<p>foo _____</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-foo __\___
-.
-<p>foo <strong>_</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-foo __*__
-.
-<p>foo <strong>*</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-__foo_
-.
-<p>_<em>foo</em></p>
-````````````````````````````````
-
-
-Note that when delimiters do not match evenly, Rule 12 determines
-that the excess literal `_` characters will appear outside of the
-emphasis, rather than inside it:
-
-```````````````````````````````` example
-_foo__
-.
-<p><em>foo</em>_</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-___foo__
-.
-<p>_<strong>foo</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-____foo_
-.
-<p>___<em>foo</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-__foo___
-.
-<p><strong>foo</strong>_</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-_foo____
-.
-<p><em>foo</em>___</p>
-````````````````````````````````
-
-
-Rule 13 implies that if you want emphasis nested directly inside
-emphasis, you must use different delimiters:
-
-```````````````````````````````` example
-**foo**
-.
-<p><strong>foo</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-*_foo_*
-.
-<p><em><em>foo</em></em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-__foo__
-.
-<p><strong>foo</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-_*foo*_
-.
-<p><em><em>foo</em></em></p>
-````````````````````````````````
-
-
-However, strong emphasis within strong emphasis is possible without
-switching delimiters:
-
-```````````````````````````````` example
-****foo****
-.
-<p><strong><strong>foo</strong></strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-____foo____
-.
-<p><strong><strong>foo</strong></strong></p>
-````````````````````````````````
-
-
-
-Rule 13 can be applied to arbitrarily long sequences of
-delimiters:
-
-```````````````````````````````` example
-******foo******
-.
-<p><strong><strong><strong>foo</strong></strong></strong></p>
-````````````````````````````````
-
-
-Rule 14:
-
-```````````````````````````````` example
-***foo***
-.
-<p><em><strong>foo</strong></em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-_____foo_____
-.
-<p><em><strong><strong>foo</strong></strong></em></p>
-````````````````````````````````
-
-
-Rule 15:
-
-```````````````````````````````` example
-*foo _bar* baz_
-.
-<p><em>foo _bar</em> baz_</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-*foo __bar *baz bim__ bam*
-.
-<p><em>foo <strong>bar *baz bim</strong> bam</em></p>
-````````````````````````````````
-
-
-Rule 16:
-
-```````````````````````````````` example
-**foo **bar baz**
-.
-<p>**foo <strong>bar baz</strong></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-*foo *bar baz*
-.
-<p>*foo <em>bar baz</em></p>
-````````````````````````````````
-
-
-Rule 17:
-
-```````````````````````````````` example
-*[bar*](/url)
-.
-<p>*<a href="/url">bar*</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-_foo [bar_](/url)
-.
-<p>_foo <a href="/url">bar_</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-*<img src="foo" title="*"/>
-.
-<p>*<img src="foo" title="*"/></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-**<a href="**">
-.
-<p>**<a href="**"></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-__<a href="__">
-.
-<p>__<a href="__"></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-*a `*`*
-.
-<p><em>a <code>*</code></em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-_a `_`_
-.
-<p><em>a <code>_</code></em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-**a<http://foo.bar/?q=**>
-.
-<p>**a<a href="http://foo.bar/?q=**">http://foo.bar/?q=**</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-__a<http://foo.bar/?q=__>
-.
-<p>__a<a href="http://foo.bar/?q=__">http://foo.bar/?q=__</a></p>
-````````````````````````````````
-
-
-<div class="extension">
-
-## Strikethrough (extension)
-
-GFM enables the `strikethrough` extension, where an additional emphasis type is
-available.
-
-Strikethrough text is any text wrapped in two tildes (`~`).
-
-```````````````````````````````` example strikethrough
-~~Hi~~ Hello, world!
-.
-<p><del>Hi</del> Hello, world!</p>
-````````````````````````````````
-
-As with regular emphasis delimiters, a new paragraph will cause strikethrough
-parsing to cease:
-
-```````````````````````````````` example strikethrough
-This ~~has a
-
-new paragraph~~.
-.
-<p>This ~~has a</p>
-<p>new paragraph~~.</p>
-````````````````````````````````
-
-</div>
-
-## Links
-
-A link contains [link text] (the visible text), a [link destination]
-(the URI that is the link destination), and optionally a [link title].
-There are two basic kinds of links in Markdown. In [inline links] the
-destination and title are given immediately after the link text. In
-[reference links] the destination and title are defined elsewhere in
-the document.
-
-A [link text](@) consists of a sequence of zero or more
-inline elements enclosed by square brackets (`[` and `]`). The
-following rules apply:
-
-- Links may not contain other links, at any level of nesting. If
- multiple otherwise valid link definitions appear nested inside each
- other, the inner-most definition is used.
-
-- Brackets are allowed in the [link text] only if (a) they
- are backslash-escaped or (b) they appear as a matched pair of brackets,
- with an open bracket `[`, a sequence of zero or more inlines, and
- a close bracket `]`.
-
-- Backtick [code spans], [autolinks], and raw [HTML tags] bind more tightly
- than the brackets in link text. Thus, for example,
- `` [foo`]` `` could not be a link text, since the second `]`
- is part of a code span.
-
-- The brackets in link text bind more tightly than markers for
- [emphasis and strong emphasis]. Thus, for example, `*[foo*](url)` is a link.
-
-A [link destination](@) consists of either
-
-- a sequence of zero or more characters between an opening `<` and a
- closing `>` that contains no line breaks or unescaped
- `<` or `>` characters, or
-
-- a nonempty sequence of characters that does not start with
- `<`, does not include ASCII space or control characters, and
- includes parentheses only if (a) they are backslash-escaped or
- (b) they are part of a balanced pair of unescaped parentheses.
- (Implementations may impose limits on parentheses nesting to
- avoid performance issues, but at least three levels of nesting
- should be supported.)
-
-A [link title](@) consists of either
-
-- a sequence of zero or more characters between straight double-quote
- characters (`"`), including a `"` character only if it is
- backslash-escaped, or
-
-- a sequence of zero or more characters between straight single-quote
- characters (`'`), including a `'` character only if it is
- backslash-escaped, or
-
-- a sequence of zero or more characters between matching parentheses
- (`(...)`), including a `(` or `)` character only if it is
- backslash-escaped.
-
-Although [link titles] may span multiple lines, they may not contain
-a [blank line].
-
-An [inline link](@) consists of a [link text] followed immediately
-by a left parenthesis `(`, optional [whitespace], an optional
-[link destination], an optional [link title] separated from the link
-destination by [whitespace], optional [whitespace], and a right
-parenthesis `)`. The link's text consists of the inlines contained
-in the [link text] (excluding the enclosing square brackets).
-The link's URI consists of the link destination, excluding enclosing
-`<...>` if present, with backslash-escapes in effect as described
-above. The link's title consists of the link title, excluding its
-enclosing delimiters, with backslash-escapes in effect as described
-above.
-
-Here is a simple inline link:
-
-```````````````````````````````` example
-[link](/uri "title")
-.
-<p><a href="/uri" title="title">link</a></p>
-````````````````````````````````
-
-
-The title may be omitted:
-
-```````````````````````````````` example
-[link](/uri)
-.
-<p><a href="/uri">link</a></p>
-````````````````````````````````
-
-
-Both the title and the destination may be omitted:
-
-```````````````````````````````` example
-[link]()
-.
-<p><a href="">link</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[link](<>)
-.
-<p><a href="">link</a></p>
-````````````````````````````````
-
-The destination can only contain spaces if it is
-enclosed in pointy brackets:
-
-```````````````````````````````` example
-[link](/my uri)
-.
-<p>[link](/my uri)</p>
-````````````````````````````````
-
-```````````````````````````````` example
-[link](</my uri>)
-.
-<p><a href="/my%20uri">link</a></p>
-````````````````````````````````
-
-The destination cannot contain line breaks,
-even if enclosed in pointy brackets:
-
-```````````````````````````````` example
-[link](foo
-bar)
-.
-<p>[link](foo
-bar)</p>
-````````````````````````````````
-
-```````````````````````````````` example
-[link](<foo
-bar>)
-.
-<p>[link](<foo
-bar>)</p>
-````````````````````````````````
-
-The destination can contain `)` if it is enclosed
-in pointy brackets:
-
-```````````````````````````````` example
-[a](<b)c>)
-.
-<p><a href="b)c">a</a></p>
-````````````````````````````````
-
-Pointy brackets that enclose links must be unescaped:
-
-```````````````````````````````` example
-[link](<foo\>)
-.
-<p>[link](&lt;foo&gt;)</p>
-````````````````````````````````
-
-These are not links, because the opening pointy bracket
-is not matched properly:
-
-```````````````````````````````` example
-[a](<b)c
-[a](<b)c>
-[a](<b>c)
-.
-<p>[a](&lt;b)c
-[a](&lt;b)c&gt;
-[a](<b>c)</p>
-````````````````````````````````
-
-Parentheses inside the link destination may be escaped:
-
-```````````````````````````````` example
-[link](\(foo\))
-.
-<p><a href="(foo)">link</a></p>
-````````````````````````````````
-
-Any number of parentheses are allowed without escaping, as long as they are
-balanced:
-
-```````````````````````````````` example
-[link](foo(and(bar)))
-.
-<p><a href="foo(and(bar))">link</a></p>
-````````````````````````````````
-
-However, if you have unbalanced parentheses, you need to escape or use the
-`<...>` form:
-
-```````````````````````````````` example
-[link](foo\(and\(bar\))
-.
-<p><a href="foo(and(bar)">link</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[link](<foo(and(bar)>)
-.
-<p><a href="foo(and(bar)">link</a></p>
-````````````````````````````````
-
-
-Parentheses and other symbols can also be escaped, as usual
-in Markdown:
-
-```````````````````````````````` example
-[link](foo\)\:)
-.
-<p><a href="foo):">link</a></p>
-````````````````````````````````
-
-
-A link can contain fragment identifiers and queries:
-
-```````````````````````````````` example
-[link](#fragment)
-
-[link](http://example.com#fragment)
-
-[link](http://example.com?foo=3#frag)
-.
-<p><a href="#fragment">link</a></p>
-<p><a href="http://example.com#fragment">link</a></p>
-<p><a href="http://example.com?foo=3#frag">link</a></p>
-````````````````````````````````
-
-
-Note that a backslash before a non-escapable character is
-just a backslash:
-
-```````````````````````````````` example
-[link](foo\bar)
-.
-<p><a href="foo%5Cbar">link</a></p>
-````````````````````````````````
-
-
-URL-escaping should be left alone inside the destination, as all
-URL-escaped characters are also valid URL characters. Entity and
-numerical character references in the destination will be parsed
-into the corresponding Unicode code points, as usual. These may
-be optionally URL-escaped when written as HTML, but this spec
-does not enforce any particular policy for rendering URLs in
-HTML or other formats. Renderers may make different decisions
-about how to escape or normalize URLs in the output.
-
-```````````````````````````````` example
-[link](foo%20b&auml;)
-.
-<p><a href="foo%20b%C3%A4">link</a></p>
-````````````````````````````````
-
-
-Note that, because titles can often be parsed as destinations,
-if you try to omit the destination and keep the title, you'll
-get unexpected results:
-
-```````````````````````````````` example
-[link]("title")
-.
-<p><a href="%22title%22">link</a></p>
-````````````````````````````````
-
-
-Titles may be in single quotes, double quotes, or parentheses:
-
-```````````````````````````````` example
-[link](/url "title")
-[link](/url 'title')
-[link](/url (title))
-.
-<p><a href="/url" title="title">link</a>
-<a href="/url" title="title">link</a>
-<a href="/url" title="title">link</a></p>
-````````````````````````````````
-
-
-Backslash escapes and entity and numeric character references
-may be used in titles:
-
-```````````````````````````````` example
-[link](/url "title \"&quot;")
-.
-<p><a href="/url" title="title &quot;&quot;">link</a></p>
-````````````````````````````````
-
-
-Titles must be separated from the link using a [whitespace].
-Other [Unicode whitespace] like non-breaking space doesn't work.
-
-```````````````````````````````` example
-[link](/url "title")
-.
-<p><a href="/url%C2%A0%22title%22">link</a></p>
-````````````````````````````````
-
-
-Nested balanced quotes are not allowed without escaping:
-
-```````````````````````````````` example
-[link](/url "title "and" title")
-.
-<p>[link](/url &quot;title &quot;and&quot; title&quot;)</p>
-````````````````````````````````
-
-
-But it is easy to work around this by using a different quote type:
-
-```````````````````````````````` example
-[link](/url 'title "and" title')
-.
-<p><a href="/url" title="title &quot;and&quot; title">link</a></p>
-````````````````````````````````
-
-
-(Note: `Markdown.pl` did allow double quotes inside a double-quoted
-title, and its test suite included a test demonstrating this.
-But it is hard to see a good rationale for the extra complexity this
-brings, since there are already many ways---backslash escaping,
-entity and numeric character references, or using a different
-quote type for the enclosing title---to write titles containing
-double quotes. `Markdown.pl`'s handling of titles has a number
-of other strange features. For example, it allows single-quoted
-titles in inline links, but not reference links. And, in
-reference links but not inline links, it allows a title to begin
-with `"` and end with `)`. `Markdown.pl` 1.0.1 even allows
-titles with no closing quotation mark, though 1.0.2b8 does not.
-It seems preferable to adopt a simple, rational rule that works
-the same way in inline links and link reference definitions.)
-
-[Whitespace] is allowed around the destination and title:
-
-```````````````````````````````` example
-[link]( /uri
- "title" )
-.
-<p><a href="/uri" title="title">link</a></p>
-````````````````````````````````
-
-
-But it is not allowed between the link text and the
-following parenthesis:
-
-```````````````````````````````` example
-[link] (/uri)
-.
-<p>[link] (/uri)</p>
-````````````````````````````````
-
-
-The link text may contain balanced brackets, but not unbalanced ones,
-unless they are escaped:
-
-```````````````````````````````` example
-[link [foo [bar]]](/uri)
-.
-<p><a href="/uri">link [foo [bar]]</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[link] bar](/uri)
-.
-<p>[link] bar](/uri)</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[link [bar](/uri)
-.
-<p>[link <a href="/uri">bar</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[link \[bar](/uri)
-.
-<p><a href="/uri">link [bar</a></p>
-````````````````````````````````
-
-
-The link text may contain inline content:
-
-```````````````````````````````` example
-[link *foo **bar** `#`*](/uri)
-.
-<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[![moon](moon.jpg)](/uri)
-.
-<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
-````````````````````````````````
-
-
-However, links may not contain other links, at any level of nesting.
-
-```````````````````````````````` example
-[foo [bar](/uri)](/uri)
-.
-<p>[foo <a href="/uri">bar</a>](/uri)</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[foo *[bar [baz](/uri)](/uri)*](/uri)
-.
-<p>[foo <em>[bar <a href="/uri">baz</a>](/uri)</em>](/uri)</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-![[[foo](uri1)](uri2)](uri3)
-.
-<p><img src="uri3" alt="[foo](uri2)" /></p>
-````````````````````````````````
-
-
-These cases illustrate the precedence of link text grouping over
-emphasis grouping:
-
-```````````````````````````````` example
-*[foo*](/uri)
-.
-<p>*<a href="/uri">foo*</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[foo *bar](baz*)
-.
-<p><a href="baz*">foo *bar</a></p>
-````````````````````````````````
-
-
-Note that brackets that *aren't* part of links do not take
-precedence:
-
-```````````````````````````````` example
-*foo [bar* baz]
-.
-<p><em>foo [bar</em> baz]</p>
-````````````````````````````````
-
-
-These cases illustrate the precedence of HTML tags, code spans,
-and autolinks over link grouping:
-
-```````````````````````````````` example
-[foo <bar attr="](baz)">
-.
-<p>[foo <bar attr="](baz)"></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[foo`](/uri)`
-.
-<p>[foo<code>](/uri)</code></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[foo<http://example.com/?search=](uri)>
-.
-<p>[foo<a href="http://example.com/?search=%5D(uri)">http://example.com/?search=](uri)</a></p>
-````````````````````````````````
-
-
-There are three kinds of [reference link](@)s:
-[full](#full-reference-link), [collapsed](#collapsed-reference-link),
-and [shortcut](#shortcut-reference-link).
-
-A [full reference link](@)
-consists of a [link text] immediately followed by a [link label]
-that [matches] a [link reference definition] elsewhere in the document.
-
-A [link label](@) begins with a left bracket (`[`) and ends
-with the first right bracket (`]`) that is not backslash-escaped.
-Between these brackets there must be at least one [non-whitespace character].
-Unescaped square bracket characters are not allowed inside the
-opening and closing square brackets of [link labels]. A link
-label can have at most 999 characters inside the square
-brackets.
-
-One label [matches](@)
-another just in case their normalized forms are equal. To normalize a
-label, strip off the opening and closing brackets,
-perform the *Unicode case fold*, strip leading and trailing
-[whitespace] and collapse consecutive internal
-[whitespace] to a single space. If there are multiple
-matching reference link definitions, the one that comes first in the
-document is used. (It is desirable in such cases to emit a warning.)
-
-The contents of the first link label are parsed as inlines, which are
-used as the link's text. The link's URI and title are provided by the
-matching [link reference definition].
-
-Here is a simple example:
-
-```````````````````````````````` example
-[foo][bar]
-
-[bar]: /url "title"
-.
-<p><a href="/url" title="title">foo</a></p>
-````````````````````````````````
-
-
-The rules for the [link text] are the same as with
-[inline links]. Thus:
-
-The link text may contain balanced brackets, but not unbalanced ones,
-unless they are escaped:
-
-```````````````````````````````` example
-[link [foo [bar]]][ref]
-
-[ref]: /uri
-.
-<p><a href="/uri">link [foo [bar]]</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[link \[bar][ref]
-
-[ref]: /uri
-.
-<p><a href="/uri">link [bar</a></p>
-````````````````````````````````
-
-
-The link text may contain inline content:
-
-```````````````````````````````` example
-[link *foo **bar** `#`*][ref]
-
-[ref]: /uri
-.
-<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[![moon](moon.jpg)][ref]
-
-[ref]: /uri
-.
-<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
-````````````````````````````````
-
-
-However, links may not contain other links, at any level of nesting.
-
-```````````````````````````````` example
-[foo [bar](/uri)][ref]
-
-[ref]: /uri
-.
-<p>[foo <a href="/uri">bar</a>]<a href="/uri">ref</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[foo *bar [baz][ref]*][ref]
-
-[ref]: /uri
-.
-<p>[foo <em>bar <a href="/uri">baz</a></em>]<a href="/uri">ref</a></p>
-````````````````````````````````
-
-
-(In the examples above, we have two [shortcut reference links]
-instead of one [full reference link].)
-
-The following cases illustrate the precedence of link text grouping over
-emphasis grouping:
-
-```````````````````````````````` example
-*[foo*][ref]
-
-[ref]: /uri
-.
-<p>*<a href="/uri">foo*</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[foo *bar][ref]
-
-[ref]: /uri
-.
-<p><a href="/uri">foo *bar</a></p>
-````````````````````````````````
-
-
-These cases illustrate the precedence of HTML tags, code spans,
-and autolinks over link grouping:
-
-```````````````````````````````` example
-[foo <bar attr="][ref]">
-
-[ref]: /uri
-.
-<p>[foo <bar attr="][ref]"></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[foo`][ref]`
-
-[ref]: /uri
-.
-<p>[foo<code>][ref]</code></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[foo<http://example.com/?search=][ref]>
-
-[ref]: /uri
-.
-<p>[foo<a href="http://example.com/?search=%5D%5Bref%5D">http://example.com/?search=][ref]</a></p>
-````````````````````````````````
-
-
-Matching is case-insensitive:
-
-```````````````````````````````` example
-[foo][BaR]
-
-[bar]: /url "title"
-.
-<p><a href="/url" title="title">foo</a></p>
-````````````````````````````````
-
-
-Unicode case fold is used:
-
-```````````````````````````````` example
-[Толпой][Толпой] is a Russian word.
-
-[ТОЛПОЙ]: /url
-.
-<p><a href="/url">Толпой</a> is a Russian word.</p>
-````````````````````````````````
-
-
-Consecutive internal [whitespace] is treated as one space for
-purposes of determining matching:
-
-```````````````````````````````` example
-[Foo
- bar]: /url
-
-[Baz][Foo bar]
-.
-<p><a href="/url">Baz</a></p>
-````````````````````````````````
-
-
-No [whitespace] is allowed between the [link text] and the
-[link label]:
-
-```````````````````````````````` example
-[foo] [bar]
-
-[bar]: /url "title"
-.
-<p>[foo] <a href="/url" title="title">bar</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[foo]
-[bar]
-
-[bar]: /url "title"
-.
-<p>[foo]
-<a href="/url" title="title">bar</a></p>
-````````````````````````````````
-
-
-This is a departure from John Gruber's original Markdown syntax
-description, which explicitly allows whitespace between the link
-text and the link label. It brings reference links in line with
-[inline links], which (according to both original Markdown and
-this spec) cannot have whitespace after the link text. More
-importantly, it prevents inadvertent capture of consecutive
-[shortcut reference links]. If whitespace is allowed between the
-link text and the link label, then in the following we will have
-a single reference link, not two shortcut reference links, as
-intended:
-
-``` markdown
-[foo]
-[bar]
-
-[foo]: /url1
-[bar]: /url2
-```
-
-(Note that [shortcut reference links] were introduced by Gruber
-himself in a beta version of `Markdown.pl`, but never included
-in the official syntax description. Without shortcut reference
-links, it is harmless to allow space between the link text and
-link label; but once shortcut references are introduced, it is
-too dangerous to allow this, as it frequently leads to
-unintended results.)
-
-When there are multiple matching [link reference definitions],
-the first is used:
-
-```````````````````````````````` example
-[foo]: /url1
-
-[foo]: /url2
-
-[bar][foo]
-.
-<p><a href="/url1">bar</a></p>
-````````````````````````````````
-
-
-Note that matching is performed on normalized strings, not parsed
-inline content. So the following does not match, even though the
-labels define equivalent inline content:
-
-```````````````````````````````` example
-[bar][foo\!]
-
-[foo!]: /url
-.
-<p>[bar][foo!]</p>
-````````````````````````````````
-
-
-[Link labels] cannot contain brackets, unless they are
-backslash-escaped:
-
-```````````````````````````````` example
-[foo][ref[]
-
-[ref[]: /uri
-.
-<p>[foo][ref[]</p>
-<p>[ref[]: /uri</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[foo][ref[bar]]
-
-[ref[bar]]: /uri
-.
-<p>[foo][ref[bar]]</p>
-<p>[ref[bar]]: /uri</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[[[foo]]]
-
-[[[foo]]]: /url
-.
-<p>[[[foo]]]</p>
-<p>[[[foo]]]: /url</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[foo][ref\[]
-
-[ref\[]: /uri
-.
-<p><a href="/uri">foo</a></p>
-````````````````````````````````
-
-
-Note that in this example `]` is not backslash-escaped:
-
-```````````````````````````````` example
-[bar\\]: /uri
-
-[bar\\]
-.
-<p><a href="/uri">bar\</a></p>
-````````````````````````````````
-
-
-A [link label] must contain at least one [non-whitespace character]:
-
-```````````````````````````````` example
-[]
-
-[]: /uri
-.
-<p>[]</p>
-<p>[]: /uri</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[
- ]
-
-[
- ]: /uri
-.
-<p>[
-]</p>
-<p>[
-]: /uri</p>
-````````````````````````````````
-
-
-A [collapsed reference link](@)
-consists of a [link label] that [matches] a
-[link reference definition] elsewhere in the
-document, followed by the string `[]`.
-The contents of the first link label are parsed as inlines,
-which are used as the link's text. The link's URI and title are
-provided by the matching reference link definition. Thus,
-`[foo][]` is equivalent to `[foo][foo]`.
-
-```````````````````````````````` example
-[foo][]
-
-[foo]: /url "title"
-.
-<p><a href="/url" title="title">foo</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[*foo* bar][]
-
-[*foo* bar]: /url "title"
-.
-<p><a href="/url" title="title"><em>foo</em> bar</a></p>
-````````````````````````````````
-
-
-The link labels are case-insensitive:
-
-```````````````````````````````` example
-[Foo][]
-
-[foo]: /url "title"
-.
-<p><a href="/url" title="title">Foo</a></p>
-````````````````````````````````
-
-
-
-As with full reference links, [whitespace] is not
-allowed between the two sets of brackets:
-
-```````````````````````````````` example
-[foo]
-[]
-
-[foo]: /url "title"
-.
-<p><a href="/url" title="title">foo</a>
-[]</p>
-````````````````````````````````
-
-
-A [shortcut reference link](@)
-consists of a [link label] that [matches] a
-[link reference definition] elsewhere in the
-document and is not followed by `[]` or a link label.
-The contents of the first link label are parsed as inlines,
-which are used as the link's text. The link's URI and title
-are provided by the matching link reference definition.
-Thus, `[foo]` is equivalent to `[foo][]`.
-
-```````````````````````````````` example
-[foo]
-
-[foo]: /url "title"
-.
-<p><a href="/url" title="title">foo</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[*foo* bar]
-
-[*foo* bar]: /url "title"
-.
-<p><a href="/url" title="title"><em>foo</em> bar</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[[*foo* bar]]
-
-[*foo* bar]: /url "title"
-.
-<p>[<a href="/url" title="title"><em>foo</em> bar</a>]</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-[[bar [foo]
-
-[foo]: /url
-.
-<p>[[bar <a href="/url">foo</a></p>
-````````````````````````````````
-
-
-The link labels are case-insensitive:
-
-```````````````````````````````` example
-[Foo]
-
-[foo]: /url "title"
-.
-<p><a href="/url" title="title">Foo</a></p>
-````````````````````````````````
-
-
-A space after the link text should be preserved:
-
-```````````````````````````````` example
-[foo] bar
-
-[foo]: /url
-.
-<p><a href="/url">foo</a> bar</p>
-````````````````````````````````
-
-
-If you just want bracketed text, you can backslash-escape the
-opening bracket to avoid links:
-
-```````````````````````````````` example
-\[foo]
-
-[foo]: /url "title"
-.
-<p>[foo]</p>
-````````````````````````````````
-
-
-Note that this is a link, because a link label ends with the first
-following closing bracket:
-
-```````````````````````````````` example
-[foo*]: /url
-
-*[foo*]
-.
-<p>*<a href="/url">foo*</a></p>
-````````````````````````````````
-
-
-Full and compact references take precedence over shortcut
-references:
-
-```````````````````````````````` example
-[foo][bar]
-
-[foo]: /url1
-[bar]: /url2
-.
-<p><a href="/url2">foo</a></p>
-````````````````````````````````
-
-```````````````````````````````` example
-[foo][]
-
-[foo]: /url1
-.
-<p><a href="/url1">foo</a></p>
-````````````````````````````````
-
-Inline links also take precedence:
-
-```````````````````````````````` example
-[foo]()
-
-[foo]: /url1
-.
-<p><a href="">foo</a></p>
-````````````````````````````````
-
-```````````````````````````````` example
-[foo](not a link)
-
-[foo]: /url1
-.
-<p><a href="/url1">foo</a>(not a link)</p>
-````````````````````````````````
-
-In the following case `[bar][baz]` is parsed as a reference,
-`[foo]` as normal text:
-
-```````````````````````````````` example
-[foo][bar][baz]
-
-[baz]: /url
-.
-<p>[foo]<a href="/url">bar</a></p>
-````````````````````````````````
-
-
-Here, though, `[foo][bar]` is parsed as a reference, since
-`[bar]` is defined:
-
-```````````````````````````````` example
-[foo][bar][baz]
-
-[baz]: /url1
-[bar]: /url2
-.
-<p><a href="/url2">foo</a><a href="/url1">baz</a></p>
-````````````````````````````````
-
-
-Here `[foo]` is not parsed as a shortcut reference, because it
-is followed by a link label (even though `[bar]` is not defined):
-
-```````````````````````````````` example
-[foo][bar][baz]
-
-[baz]: /url1
-[foo]: /url2
-.
-<p>[foo]<a href="/url1">bar</a></p>
-````````````````````````````````
-
-
-
-## Images
-
-Syntax for images is like the syntax for links, with one
-difference. Instead of [link text], we have an
-[image description](@). The rules for this are the
-same as for [link text], except that (a) an
-image description starts with `![` rather than `[`, and
-(b) an image description may contain links.
-An image description has inline elements
-as its contents. When an image is rendered to HTML,
-this is standardly used as the image's `alt` attribute.
-
-```````````````````````````````` example
-![foo](/url "title")
-.
-<p><img src="/url" alt="foo" title="title" /></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-![foo *bar*]
-
-[foo *bar*]: train.jpg "train & tracks"
-.
-<p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-![foo ![bar](/url)](/url2)
-.
-<p><img src="/url2" alt="foo bar" /></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-![foo [bar](/url)](/url2)
-.
-<p><img src="/url2" alt="foo bar" /></p>
-````````````````````````````````
-
-
-Though this spec is concerned with parsing, not rendering, it is
-recommended that in rendering to HTML, only the plain string content
-of the [image description] be used. Note that in
-the above example, the alt attribute's value is `foo bar`, not `foo
-[bar](/url)` or `foo <a href="/url">bar</a>`. Only the plain string
-content is rendered, without formatting.
-
-```````````````````````````````` example
-![foo *bar*][]
-
-[foo *bar*]: train.jpg "train & tracks"
-.
-<p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-![foo *bar*][foobar]
-
-[FOOBAR]: train.jpg "train & tracks"
-.
-<p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-![foo](train.jpg)
-.
-<p><img src="train.jpg" alt="foo" /></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-My ![foo bar](/path/to/train.jpg "title" )
-.
-<p>My <img src="/path/to/train.jpg" alt="foo bar" title="title" /></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-![foo](<url>)
-.
-<p><img src="url" alt="foo" /></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-![](/url)
-.
-<p><img src="/url" alt="" /></p>
-````````````````````````````````
-
-
-Reference-style:
-
-```````````````````````````````` example
-![foo][bar]
-
-[bar]: /url
-.
-<p><img src="/url" alt="foo" /></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-![foo][bar]
-
-[BAR]: /url
-.
-<p><img src="/url" alt="foo" /></p>
-````````````````````````````````
-
-
-Collapsed:
-
-```````````````````````````````` example
-![foo][]
-
-[foo]: /url "title"
-.
-<p><img src="/url" alt="foo" title="title" /></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-![*foo* bar][]
-
-[*foo* bar]: /url "title"
-.
-<p><img src="/url" alt="foo bar" title="title" /></p>
-````````````````````````````````
-
-
-The labels are case-insensitive:
-
-```````````````````````````````` example
-![Foo][]
-
-[foo]: /url "title"
-.
-<p><img src="/url" alt="Foo" title="title" /></p>
-````````````````````````````````
-
-
-As with reference links, [whitespace] is not allowed
-between the two sets of brackets:
-
-```````````````````````````````` example
-![foo]
-[]
-
-[foo]: /url "title"
-.
-<p><img src="/url" alt="foo" title="title" />
-[]</p>
-````````````````````````````````
-
-
-Shortcut:
-
-```````````````````````````````` example
-![foo]
-
-[foo]: /url "title"
-.
-<p><img src="/url" alt="foo" title="title" /></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-![*foo* bar]
-
-[*foo* bar]: /url "title"
-.
-<p><img src="/url" alt="foo bar" title="title" /></p>
-````````````````````````````````
-
-
-Note that link labels cannot contain unescaped brackets:
-
-```````````````````````````````` example
-![[foo]]
-
-[[foo]]: /url "title"
-.
-<p>![[foo]]</p>
-<p>[[foo]]: /url &quot;title&quot;</p>
-````````````````````````````````
-
-
-The link labels are case-insensitive:
-
-```````````````````````````````` example
-![Foo]
-
-[foo]: /url "title"
-.
-<p><img src="/url" alt="Foo" title="title" /></p>
-````````````````````````````````
-
-
-If you just want a literal `!` followed by bracketed text, you can
-backslash-escape the opening `[`:
-
-```````````````````````````````` example
-!\[foo]
-
-[foo]: /url "title"
-.
-<p>![foo]</p>
-````````````````````````````````
-
-
-If you want a link after a literal `!`, backslash-escape the
-`!`:
-
-```````````````````````````````` example
-\![foo]
-
-[foo]: /url "title"
-.
-<p>!<a href="/url" title="title">foo</a></p>
-````````````````````````````````
-
-
-## Autolinks
-
-[Autolink](@)s are absolute URIs and email addresses inside
-`<` and `>`. They are parsed as links, with the URL or email address
-as the link label.
-
-A [URI autolink](@) consists of `<`, followed by an
-[absolute URI] followed by `>`. It is parsed as
-a link to the URI, with the URI as the link's label.
-
-An [absolute URI](@),
-for these purposes, consists of a [scheme] followed by a colon (`:`)
-followed by zero or more characters other than ASCII
-[whitespace] and control characters, `<`, and `>`. If
-the URI includes these characters, they must be percent-encoded
-(e.g. `%20` for a space).
-
-For purposes of this spec, a [scheme](@) is any sequence
-of 2--32 characters beginning with an ASCII letter and followed
-by any combination of ASCII letters, digits, or the symbols plus
-("+"), period ("."), or hyphen ("-").
-
-Here are some valid autolinks:
-
-```````````````````````````````` example
-<http://foo.bar.baz>
-.
-<p><a href="http://foo.bar.baz">http://foo.bar.baz</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<http://foo.bar.baz/test?q=hello&id=22&boolean>
-.
-<p><a href="http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean">http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<irc://foo.bar:2233/baz>
-.
-<p><a href="irc://foo.bar:2233/baz">irc://foo.bar:2233/baz</a></p>
-````````````````````````````````
-
-
-Uppercase is also fine:
-
-```````````````````````````````` example
-<MAILTO:FOO@BAR.BAZ>
-.
-<p><a href="MAILTO:FOO@BAR.BAZ">MAILTO:FOO@BAR.BAZ</a></p>
-````````````````````````````````
-
-
-Note that many strings that count as [absolute URIs] for
-purposes of this spec are not valid URIs, because their
-schemes are not registered or because of other problems
-with their syntax:
-
-```````````````````````````````` example
-<a+b+c:d>
-.
-<p><a href="a+b+c:d">a+b+c:d</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<made-up-scheme://foo,bar>
-.
-<p><a href="made-up-scheme://foo,bar">made-up-scheme://foo,bar</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<http://../>
-.
-<p><a href="http://../">http://../</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<localhost:5001/foo>
-.
-<p><a href="localhost:5001/foo">localhost:5001/foo</a></p>
-````````````````````````````````
-
-
-Spaces are not allowed in autolinks:
-
-```````````````````````````````` example
-<http://foo.bar/baz bim>
-.
-<p>&lt;http://foo.bar/baz bim&gt;</p>
-````````````````````````````````
-
-
-Backslash-escapes do not work inside autolinks:
-
-```````````````````````````````` example
-<http://example.com/\[\>
-.
-<p><a href="http://example.com/%5C%5B%5C">http://example.com/\[\</a></p>
-````````````````````````````````
-
-
-An [email autolink](@)
-consists of `<`, followed by an [email address],
-followed by `>`. The link's label is the email address,
-and the URL is `mailto:` followed by the email address.
-
-An [email address](@),
-for these purposes, is anything that matches
-the [non-normative regex from the HTML5
-spec](https://html.spec.whatwg.org/multipage/forms.html#e-mail-state-(type=email)):
-
- /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?
- (?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
-
-Examples of email autolinks:
-
-```````````````````````````````` example
-<foo@bar.example.com>
-.
-<p><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<foo+special@Bar.baz-bar0.com>
-.
-<p><a href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p>
-````````````````````````````````
-
-
-Backslash-escapes do not work inside email autolinks:
-
-```````````````````````````````` example
-<foo\+@bar.example.com>
-.
-<p>&lt;foo+@bar.example.com&gt;</p>
-````````````````````````````````
-
-
-These are not autolinks:
-
-```````````````````````````````` example
-<>
-.
-<p>&lt;&gt;</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-< http://foo.bar >
-.
-<p>&lt; http://foo.bar &gt;</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<m:abc>
-.
-<p>&lt;m:abc&gt;</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<foo.bar.baz>
-.
-<p>&lt;foo.bar.baz&gt;</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-http://example.com
-.
-<p>http://example.com</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-foo@bar.example.com
-.
-<p>foo@bar.example.com</p>
-````````````````````````````````
-
-<div class="extension">
-
-## Autolinks (extension)
-
-GFM enables the `autolink` extension, where autolinks will be recognised in a
-greater number of conditions.
-
-[Autolink]s can also be constructed without requiring the use of `<` and to `>`
-to delimit them, although they will be recognized under a smaller set of
-circumstances. All such recognized autolinks can only come at the beginning of
-a line, after whitespace, or any of the delimiting characters `*`, `_`, `~`,
-and `(`.
-
-An [extended www autolink](@) will be recognized
-when the text `www.` is found followed by a [valid domain].
-A [valid domain](@) consists of segments
-of alphanumeric characters, underscores (`_`) and hyphens (`-`)
-separated by periods (`.`).
-There must be at least one period,
-and no underscores may be present in the last two segments of the domain.
-
-The scheme `http` will be inserted automatically:
-
-```````````````````````````````` example autolink
-www.commonmark.org
-.
-<p><a href="http://www.commonmark.org">www.commonmark.org</a></p>
-````````````````````````````````
-
-After a [valid domain], zero or more non-space non-`<` characters may follow:
-
-```````````````````````````````` example autolink
-Visit www.commonmark.org/help for more information.
-.
-<p>Visit <a href="http://www.commonmark.org/help">www.commonmark.org/help</a> for more information.</p>
-````````````````````````````````
-
-We then apply [extended autolink path validation](@) as follows:
-
-Trailing punctuation (specifically, `?`, `!`, `.`, `,`, `:`, `*`, `_`, and `~`)
-will not be considered part of the autolink, though they may be included in the
-interior of the link:
-
-```````````````````````````````` example autolink
-Visit www.commonmark.org.
-
-Visit www.commonmark.org/a.b.
-.
-<p>Visit <a href="http://www.commonmark.org">www.commonmark.org</a>.</p>
-<p>Visit <a href="http://www.commonmark.org/a.b">www.commonmark.org/a.b</a>.</p>
-````````````````````````````````
-
-When an autolink ends in `)`, we scan the entire autolink for the total number
-of parentheses. If there is a greater number of closing parentheses than
-opening ones, we don't consider the unmatched trailing parentheses part of the
-autolink, in order to facilitate including an autolink inside a parenthesis:
-
-```````````````````````````````` example autolink
-www.google.com/search?q=Markup+(business)
-
-www.google.com/search?q=Markup+(business)))
-
-(www.google.com/search?q=Markup+(business))
-
-(www.google.com/search?q=Markup+(business)
-.
-<p><a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
-<p><a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>))</p>
-<p>(<a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>)</p>
-<p>(<a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
-````````````````````````````````
-
-This check is only done when the link ends in a closing parentheses `)`, so if
-the only parentheses are in the interior of the autolink, no special rules are
-applied:
-
-```````````````````````````````` example autolink
-www.google.com/search?q=(business))+ok
-.
-<p><a href="http://www.google.com/search?q=(business))+ok">www.google.com/search?q=(business))+ok</a></p>
-````````````````````````````````
-
-If an autolink ends in a semicolon (`;`), we check to see if it appears to
-resemble an [entity reference][entity references]; if the preceding text is `&`
-followed by one or more alphanumeric characters. If so, it is excluded from
-the autolink:
-
-```````````````````````````````` example autolink
-www.google.com/search?q=commonmark&hl=en
-
-www.google.com/search?q=commonmark&hl;
-.
-<p><a href="http://www.google.com/search?q=commonmark&amp;hl=en">www.google.com/search?q=commonmark&amp;hl=en</a></p>
-<p><a href="http://www.google.com/search?q=commonmark">www.google.com/search?q=commonmark</a>&amp;hl;</p>
-````````````````````````````````
-
-`<` immediately ends an autolink.
-
-```````````````````````````````` example autolink
-www.commonmark.org/he<lp
-.
-<p><a href="http://www.commonmark.org/he">www.commonmark.org/he</a>&lt;lp</p>
-````````````````````````````````
-
-An [extended url autolink](@) will be recognised when one of the schemes
-`http://`, `https://`, or `ftp://`, followed by a [valid domain], then zero or
-more non-space non-`<` characters according to
-[extended autolink path validation]:
-
-```````````````````````````````` example autolink
-http://commonmark.org
-
-(Visit https://encrypted.google.com/search?q=Markup+(business))
-
-Anonymous FTP is available at ftp://foo.bar.baz.
-.
-<p><a href="http://commonmark.org">http://commonmark.org</a></p>
-<p>(Visit <a href="https://encrypted.google.com/search?q=Markup+(business)">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>
-<p>Anonymous FTP is available at <a href="ftp://foo.bar.baz">ftp://foo.bar.baz</a>.</p>
-````````````````````````````````
-
-
-An [extended email autolink](@) will be recognised when an email address is
-recognised within any text node. Email addresses are recognised according to
-the following rules:
-
-* One ore more characters which are alphanumeric, or `.`, `-`, `_`, or `+`.
-* An `@` symbol.
-* One or more characters which are alphanumeric, or `-` or `_`,
- separated by periods (`.`).
- There must be at least one period.
- The last character must not be one of `-` or `_`.
-
-The scheme `mailto:` will automatically be added to the generated link:
-
-```````````````````````````````` example autolink
-foo@bar.baz
-.
-<p><a href="mailto:foo@bar.baz">foo@bar.baz</a></p>
-````````````````````````````````
-
-`+` can occur before the `@`, but not after.
-
-```````````````````````````````` example autolink
-hello@mail+xyz.example isn't valid, but hello+xyz@mail.example is.
-.
-<p>hello@mail+xyz.example isn't valid, but <a href="mailto:hello+xyz@mail.example">hello+xyz@mail.example</a> is.</p>
-````````````````````````````````
-
-`.`, `-`, and `_` can occur on both sides of the `@`, but only `.` may occur at
-the end of the email address, in which case it will not be considered part of
-the address:
-
-```````````````````````````````` example autolink
-a.b-c_d@a.b
-
-a.b-c_d@a.b.
-
-a.b-c_d@a.b-
-
-a.b-c_d@a.b_
-.
-<p><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a></p>
-<p><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a>.</p>
-<p>a.b-c_d@a.b-</p>
-<p>a.b-c_d@a.b_</p>
-````````````````````````````````
-
-</div>
-
-## Raw HTML
-
-Text between `<` and `>` that looks like an HTML tag is parsed as a
-raw HTML tag and will be rendered in HTML without escaping.
-Tag and attribute names are not limited to current HTML tags,
-so custom tags (and even, say, DocBook tags) may be used.
-
-Here is the grammar for tags:
-
-A [tag name](@) consists of an ASCII letter
-followed by zero or more ASCII letters, digits, or
-hyphens (`-`).
-
-An [attribute](@) consists of [whitespace],
-an [attribute name], and an optional
-[attribute value specification].
-
-An [attribute name](@)
-consists of an ASCII letter, `_`, or `:`, followed by zero or more ASCII
-letters, digits, `_`, `.`, `:`, or `-`. (Note: This is the XML
-specification restricted to ASCII. HTML5 is laxer.)
-
-An [attribute value specification](@)
-consists of optional [whitespace],
-a `=` character, optional [whitespace], and an [attribute
-value].
-
-An [attribute value](@)
-consists of an [unquoted attribute value],
-a [single-quoted attribute value], or a [double-quoted attribute value].
-
-An [unquoted attribute value](@)
-is a nonempty string of characters not
-including [whitespace], `"`, `'`, `=`, `<`, `>`, or `` ` ``.
-
-A [single-quoted attribute value](@)
-consists of `'`, zero or more
-characters not including `'`, and a final `'`.
-
-A [double-quoted attribute value](@)
-consists of `"`, zero or more
-characters not including `"`, and a final `"`.
-
-An [open tag](@) consists of a `<` character, a [tag name],
-zero or more [attributes], optional [whitespace], an optional `/`
-character, and a `>` character.
-
-A [closing tag](@) consists of the string `</`, a
-[tag name], optional [whitespace], and the character `>`.
-
-An [HTML comment](@) consists of `<!--` + *text* + `-->`,
-where *text* does not start with `>` or `->`, does not end with `-`,
-and does not contain `--`. (See the
-[HTML5 spec](http://www.w3.org/TR/html5/syntax.html#comments).)
-
-A [processing instruction](@)
-consists of the string `<?`, a string
-of characters not including the string `?>`, and the string
-`?>`.
-
-A [declaration](@) consists of the
-string `<!`, a name consisting of one or more uppercase ASCII letters,
-[whitespace], a string of characters not including the
-character `>`, and the character `>`.
-
-A [CDATA section](@) consists of
-the string `<![CDATA[`, a string of characters not including the string
-`]]>`, and the string `]]>`.
-
-An [HTML tag](@) consists of an [open tag], a [closing tag],
-an [HTML comment], a [processing instruction], a [declaration],
-or a [CDATA section].
-
-Here are some simple open tags:
-
-```````````````````````````````` example
-<a><bab><c2c>
-.
-<p><a><bab><c2c></p>
-````````````````````````````````
-
-
-Empty elements:
-
-```````````````````````````````` example
-<a/><b2/>
-.
-<p><a/><b2/></p>
-````````````````````````````````
-
-
-[Whitespace] is allowed:
-
-```````````````````````````````` example
-<a /><b2
-data="foo" >
-.
-<p><a /><b2
-data="foo" ></p>
-````````````````````````````````
-
-
-With attributes:
-
-```````````````````````````````` example
-<a foo="bar" bam = 'baz <em>"</em>'
-_boolean zoop:33=zoop:33 />
-.
-<p><a foo="bar" bam = 'baz <em>"</em>'
-_boolean zoop:33=zoop:33 /></p>
-````````````````````````````````
-
-
-Custom tag names can be used:
-
-```````````````````````````````` example
-Foo <responsive-image src="foo.jpg" />
-.
-<p>Foo <responsive-image src="foo.jpg" /></p>
-````````````````````````````````
-
-
-Illegal tag names, not parsed as HTML:
-
-```````````````````````````````` example
-<33> <__>
-.
-<p>&lt;33&gt; &lt;__&gt;</p>
-````````````````````````````````
-
-
-Illegal attribute names:
-
-```````````````````````````````` example
-<a h*#ref="hi">
-.
-<p>&lt;a h*#ref=&quot;hi&quot;&gt;</p>
-````````````````````````````````
-
-
-Illegal attribute values:
-
-```````````````````````````````` example
-<a href="hi'> <a href=hi'>
-.
-<p>&lt;a href=&quot;hi'&gt; &lt;a href=hi'&gt;</p>
-````````````````````````````````
-
-
-Illegal [whitespace]:
-
-```````````````````````````````` example
-< a><
-foo><bar/ >
-<foo bar=baz
-bim!bop />
-.
-<p>&lt; a&gt;&lt;
-foo&gt;&lt;bar/ &gt;
-&lt;foo bar=baz
-bim!bop /&gt;</p>
-````````````````````````````````
-
-
-Missing [whitespace]:
-
-```````````````````````````````` example
-<a href='bar'title=title>
-.
-<p>&lt;a href='bar'title=title&gt;</p>
-````````````````````````````````
-
-
-Closing tags:
-
-```````````````````````````````` example
-</a></foo >
-.
-<p></a></foo ></p>
-````````````````````````````````
-
-
-Illegal attributes in closing tag:
-
-```````````````````````````````` example
-</a href="foo">
-.
-<p>&lt;/a href=&quot;foo&quot;&gt;</p>
-````````````````````````````````
-
-
-Comments:
-
-```````````````````````````````` example
-foo <!-- this is a
-comment - with hyphen -->
-.
-<p>foo <!-- this is a
-comment - with hyphen --></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-foo <!-- not a comment -- two hyphens -->
-.
-<p>foo &lt;!-- not a comment -- two hyphens --&gt;</p>
-````````````````````````````````
-
-
-Not comments:
-
-```````````````````````````````` example
-foo <!--> foo -->
-
-foo <!-- foo--->
-.
-<p>foo &lt;!--&gt; foo --&gt;</p>
-<p>foo &lt;!-- foo---&gt;</p>
-````````````````````````````````
-
-
-Processing instructions:
-
-```````````````````````````````` example
-foo <?php echo $a; ?>
-.
-<p>foo <?php echo $a; ?></p>
-````````````````````````````````
-
-
-Declarations:
-
-```````````````````````````````` example
-foo <!ELEMENT br EMPTY>
-.
-<p>foo <!ELEMENT br EMPTY></p>
-````````````````````````````````
-
-
-CDATA sections:
-
-```````````````````````````````` example
-foo <![CDATA[>&<]]>
-.
-<p>foo <![CDATA[>&<]]></p>
-````````````````````````````````
-
-
-Entity and numeric character references are preserved in HTML
-attributes:
-
-```````````````````````````````` example
-foo <a href="&ouml;">
-.
-<p>foo <a href="&ouml;"></p>
-````````````````````````````````
-
-
-Backslash escapes do not work in HTML attributes:
-
-```````````````````````````````` example
-foo <a href="\*">
-.
-<p>foo <a href="\*"></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<a href="\"">
-.
-<p>&lt;a href=&quot;&quot;&quot;&gt;</p>
-````````````````````````````````
-
-
-<div class="extension">
-
-## Disallowed Raw HTML (extension)
-
-GFM enables the `tagfilter` extension, where the following HTML tags will be
-filtered when rendering HTML output:
-
-* `<title>`
-* `<textarea>`
-* `<style>`
-* `<xmp>`
-* `<iframe>`
-* `<noembed>`
-* `<noframes>`
-* `<script>`
-* `<plaintext>`
-
-Filtering is done by replacing the leading `<` with the entity `&lt;`. These
-tags are chosen in particular as they change how HTML is interpreted in a way
-unique to them (i.e. nested HTML is interpreted differently), and this is
-usually undesireable in the context of other rendered Markdown content.
-
-All other HTML tags are left untouched.
-
-```````````````````````````````` example tagfilter
-<strong> <title> <style> <em>
-
-<blockquote>
- <xmp> is disallowed. <XMP> is also disallowed.
-</blockquote>
-.
-<p><strong> &lt;title> &lt;style> <em></p>
-<blockquote>
- &lt;xmp> is disallowed. &lt;XMP> is also disallowed.
-</blockquote>
-````````````````````````````````
-
-</div>
-
-## Hard line breaks
-
-A line break (not in a code span or HTML tag) that is preceded
-by two or more spaces and does not occur at the end of a block
-is parsed as a [hard line break](@) (rendered
-in HTML as a `<br />` tag):
-
-```````````````````````````````` example
-foo
-baz
-.
-<p>foo<br />
-baz</p>
-````````````````````````````````
-
-
-For a more visible alternative, a backslash before the
-[line ending] may be used instead of two spaces:
-
-```````````````````````````````` example
-foo\
-baz
-.
-<p>foo<br />
-baz</p>
-````````````````````````````````
-
-
-More than two spaces can be used:
-
-```````````````````````````````` example
-foo
-baz
-.
-<p>foo<br />
-baz</p>
-````````````````````````````````
-
-
-Leading spaces at the beginning of the next line are ignored:
-
-```````````````````````````````` example
-foo
- bar
-.
-<p>foo<br />
-bar</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-foo\
- bar
-.
-<p>foo<br />
-bar</p>
-````````````````````````````````
-
-
-Line breaks can occur inside emphasis, links, and other constructs
-that allow inline content:
-
-```````````````````````````````` example
-*foo
-bar*
-.
-<p><em>foo<br />
-bar</em></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-*foo\
-bar*
-.
-<p><em>foo<br />
-bar</em></p>
-````````````````````````````````
-
-
-Line breaks do not occur inside code spans
-
-```````````````````````````````` example
-`code
-span`
-.
-<p><code>code span</code></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-`code\
-span`
-.
-<p><code>code\ span</code></p>
-````````````````````````````````
-
-
-or HTML tags:
-
-```````````````````````````````` example
-<a href="foo
-bar">
-.
-<p><a href="foo
-bar"></p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-<a href="foo\
-bar">
-.
-<p><a href="foo\
-bar"></p>
-````````````````````````````````
-
-
-Hard line breaks are for separating inline content within a block.
-Neither syntax for hard line breaks works at the end of a paragraph or
-other block element:
-
-```````````````````````````````` example
-foo\
-.
-<p>foo\</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-foo
-.
-<p>foo</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-### foo\
-.
-<h3>foo\</h3>
-````````````````````````````````
-
-
-```````````````````````````````` example
-### foo
-.
-<h3>foo</h3>
-````````````````````````````````
-
-
-## Soft line breaks
-
-A regular line break (not in a code span or HTML tag) that is not
-preceded by two or more spaces or a backslash is parsed as a
-[softbreak](@). (A softbreak may be rendered in HTML either as a
-[line ending] or as a space. The result will be the same in
-browsers. In the examples here, a [line ending] will be used.)
-
-```````````````````````````````` example
-foo
-baz
-.
-<p>foo
-baz</p>
-````````````````````````````````
-
-
-Spaces at the end of the line and beginning of the next line are
-removed:
-
-```````````````````````````````` example
-foo
- baz
-.
-<p>foo
-baz</p>
-````````````````````````````````
-
-
-A conforming parser may render a soft line break in HTML either as a
-line break or as a space.
-
-A renderer may also provide an option to render soft line breaks
-as hard line breaks.
-
-## Textual content
-
-Any characters not given an interpretation by the above rules will
-be parsed as plain textual content.
-
-```````````````````````````````` example
-hello $.;'there
-.
-<p>hello $.;'there</p>
-````````````````````````````````
-
-
-```````````````````````````````` example
-Foo χÏῆν
-.
-<p>Foo χÏῆν</p>
-````````````````````````````````
-
-
-Internal spaces are preserved verbatim:
-
-```````````````````````````````` example
-Multiple spaces
-.
-<p>Multiple spaces</p>
-````````````````````````````````
-
-
-# GitLab Official Specification Markdown
-
-Currently, only some of the GitLab-specific markdown features are
-listed in this section. We will eventually add all
-GitLab-specific features currently listed as supported in the
-[user-facing documentation for GitLab Flavored Markdown](https://docs.gitlab.com/ee/user/markdown.html).
-
-There is currently only this single top-level heading, but the
-examples may be split into multiple top-level headings in the future.
-
-## Footnotes
-
-See
-[the footnotes section of the user-facing documentation for GitLab Flavored Markdown](https://docs.gitlab.com/ee/user/markdown.html#footnotes).
-
-```````````````````````````````` example gitlab
-footnote reference tag [^fortytwo]
-
-[^fortytwo]: footnote text
-.
-<p>
-footnote reference tag
-<sup>
-<a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref>
-1
-</a>
-</sup>
-</p>
-<section data-footnotes>
-<ol>
-<li id="fn-fortytwo-42">
-<p>
-footnote text
-<a href="#fnref-fortytwo-42" data-footnote-backref>
-</a>
-</p>
-</li>
-</ol>
-</section>
-````````````````````````````````
-
-## Task list items
-
-See
-[Task lists](https://docs.gitlab.com/ee/user/markdown.html#task-lists) in the GitLab Flavored Markdown documentation.
-
-Task list items (checkboxes) are defined as a GitHub Flavored Markdown extension in a section above.
-GitLab extends the behavior of task list items to support additional features.
-Some of these features are in-progress, and should not yet be considered part of the official
-GitLab Flavored Markdown specification.
-
-Some of the behavior of task list items is implemented as client-side JavaScript/CSS.
-
-The following are some basic examples; more examples may be added in the future.
-
-Incomplete task:
-
-```````````````````````````````` example gitlab
-- [ ] incomplete
-.
-<ul>
-<li>
-<task-button/>
-<input type="checkbox" disabled/>
-incomplete
-</li>
-</ul>
-````````````````````````````````
-
-Completed task:
-
-```````````````````````````````` example gitlab
-- [x] completed
-.
-<ul>
-<li>
-<task-button/>
-<input type="checkbox" checked disabled/>
-completed
-</li>
-</ul>
-````````````````````````````````
-
-Inapplicable task:
-
-```````````````````````````````` example gitlab
-- [~] inapplicable
-.
-<ul>
-<li>
-<task-button/>
-<input type="checkbox" data-inapplicable disabled>
-<s>
-inapplicable
-</s>
-</li>
-</ul>
-````````````````````````````````
-
-Inapplicable task in a "loose" list. Note that the `<del>` tag is not applied to the
-loose text; it has strikethrough applied with CSS.
-
-```````````````````````````````` example gitlab
-- [~] inapplicable
-
- text in loose list
-.
-<ul>
-<li>
-<p>
-<task-button/>
-<input type="checkbox" data-inapplicable disabled>
-<s>
-inapplicable
-</s>
-</p>
-<p>
-text in loose list
-</p>
-</li>
-</ul>
-````````````````````````````````
-
-## Front matter
-
-See
-[Front matter](https://docs.gitlab.com/ee/user/markdown.html#front-matter) in the GitLab Flavored Markdown documentation.
-
-Front matter is metadata included at the beginning of a Markdown document, preceding the content.
-This data can be used by static site generators like Jekyll, Hugo, and many other applications.
-
-YAML front matter:
-
-```````````````````````````````` example gitlab
----
-title: YAML front matter
----
-.
-<pre>
-<code>
-title: YAML front matter
-</code>
-</pre>
-````````````````````````````````
-
-TOML front matter:
-
-```````````````````````````````` example gitlab
-+++
-title: TOML front matter
-+++
-.
-<pre>
-<code>
-title: TOML front matter
-</code>
-</pre>
-````````````````````````````````
-
-JSON front matter:
-
-```````````````````````````````` example gitlab
-;;;
-{
- "title": "JSON front matter"
-}
-;;;
-.
-<pre>
-<code>
-{
- "title": "JSON front matter"
-}
-</code>
-</pre>
-````````````````````````````````
-
-Front matter blocks should be inserted at the top of the document:
-
-```````````````````````````````` example gitlab
-text
-
----
-title: YAML front matter
----
-.
-<p>text</p>
-<hr>
-<h2>title: YAML front matter</h2>
-````````````````````````````````
-
-Front matter block delimiters shouldn’t be preceded by space characters:
-
-```````````````````````````````` example gitlab
- ---
-title: YAML front matter
----
-.
-<hr>
-<h2>title: YAML front matter</h2>
-````````````````````````````````
-
-## Table of contents
-
-See
-[table of contents](https://docs.gitlab.com/ee/user/markdown.html#table-of-contents)
-in the GitLab Flavored Markdown documentation.
-
-A table of contents is an unordered list that links to subheadings in the document.
-Add either the `[[_TOC_]]` or `[TOC]` tag on its own line.
-
-```````````````````````````````` example gitlab
-[TOC]
-
-# Heading 1
-
-## Heading 2
-.
-<nav>
- <ul>
- <li><a href="#heading-1">Heading 1</a></li>
- <ul>
- <li><a href="#heading-2">Heading 2</a></li>
- </ul>
- </ul>
-</nav>
-<h1>Heading 1</h1>
-<h2>Heading 2</h2>
-````````````````````````````````
-
-```````````````````````````````` example gitlab
-[[_TOC_]]
-
-# Heading 1
-
-## Heading 2
-.
-<nav>
- <ul>
- <li><a href="#heading-1">Heading 1</a></li>
- <ul>
- <li><a href="#heading-2">Heading 2</a></li>
- </ul>
- </ul>
-</nav>
-<h1>Heading 1</h1>
-<h2>Heading 2</h2>
-````````````````````````````````
-
-A table of contents is a block element. It should preceded and followed by a blank
-line.
-
-```````````````````````````````` example gitlab
-[[_TOC_]]
-text
-
-text
-[TOC]
-.
-<p>[[<em>TOC</em>]]text</p>
-<p>text[TOC]</p>
-````````````````````````````````
-
-A table of contents can be indented with up to three spaces.
-
-```````````````````````````````` example gitlab
- [[_TOC_]]
-
-# Heading 1
-.
-<nav>
- <ul>
- <li><a href="#heading-1">Heading 1</a></li>
- </ul>
-</nav>
-<h1>Heading 1</h1>
-````````````````````````````````
-
-# GitLab Internal Extension Markdown
-
-## Audio
-
-See
-[audio](https://docs.gitlab.com/ee/user/markdown.html#audio) in the GitLab Flavored Markdown documentation.
-
-GLFM renders image elements as an audio player as long as the resource’s file extension is
-one of the following supported audio extensions `.mp3`, `.oga`, `.ogg`, `.spx`, and `.wav`.
-Audio ignore the alternative text part of an image declaration.
-
-```````````````````````````````` example gitlab
-![audio](audio.oga "audio title")
-.
-<p><audio src="audio.oga" title="audio title"></audio></p>
-````````````````````````````````
-
-Reference definitions work audio as well:
-
-```````````````````````````````` example gitlab
-[audio]: audio.oga "audio title"
-
-![audio][audio]
-.
-<p><audio src="audio.oga" title="audio title"></audio></p>
-````````````````````````````````
-
-## Video
-
-See
-[videos](https://docs.gitlab.com/ee/user/markdown.html#videos) in the GitLab Flavored Markdown documentation.
-
-GLFM renders image elements as a video player as long as the resource’s file extension is
-one of the following supported video extensions `.mp4`, `.m4v`, `.mov`, `.webm`, and `.ogv`.
-Videos ignore the alternative text part of an image declaration.
-
-
-```````````````````````````````` example gitlab
-![video](video.m4v "video title")
-.
-<p><video src="video.m4v" title="video title"></video></p>
-````````````````````````````````
-
-Reference definitions work video as well:
-
-```````````````````````````````` example gitlab
-[video]: video.mov "video title"
-
-![video][video]
-.
-<p><video src="video.mov" title="video title"></video></p>
-````````````````````````````````
-
-## Markdown Preview API Request Overrides
-
-This section contains examples of all controllers which use `PreviewMarkdown` module
-and use different `markdown_context_params`. They exercise the various `preview_markdown`
-endpoints via `glfm_example_metadata.yml`.
-
-
-`preview_markdown` exercising `groups` API endpoint and `UploadLinkFilter`:
-
-```````````````````````````````` example gitlab
-[groups-test-file](/uploads/groups-test-file)
-.
-<p><a href="groups-test-file">groups-test-file</a></p>
-````````````````````````````````
-
-`preview_markdown` exercising `projects` API endpoint and `RepositoryLinkFilter`:
-
-```````````````````````````````` example gitlab
-[projects-test-file](projects-test-file)
-.
-<p><a href="projects-test-file">projects-test-file</a></p>
-````````````````````````````````
-
-`preview_markdown` exercising `projects` API endpoint and `SnippetReferenceFilter`:
-
-```````````````````````````````` example gitlab
-This project snippet ID reference IS filtered: $88888
-.
-<p>This project snippet ID reference IS filtered: $88888</p>
-````````````````````````````````
-
-`preview_markdown` exercising personal (non-project) `snippets` API endpoint. This is
-only used by the comment field on personal snippets. It has no unique custom markdown
-extension behavior, and specifically does not render snippet references via
-`SnippetReferenceFilter`, even if the ID is valid.
-
-```````````````````````````````` example gitlab
-This personal snippet ID reference is not filtered: $99999
-.
-<p>This personal snippet ID reference is not filtered: $99999</p>
-````````````````````````````````
-
-`preview_markdown` exercising project `wikis` API endpoint and `WikiLinkFilter`:
-
-```````````````````````````````` example gitlab
-[project-wikis-test-file](project-wikis-test-file)
-.
-<p><a href="project-wikis-test-file">project-wikis-test-file</a></p>
-````````````````````````````````
-
-`preview_markdown` exercising group `wikis` API endpoint and `WikiLinkFilter`. This example
-also requires an EE license enabling the `group_wikis` feature:
-
-```````````````````````````````` example gitlab
-[group-wikis-test-file](group-wikis-test-file)
-.
-<p><a href="group-wikis-test-file">group-wikis-test-file</a></p>
-````````````````````````````````
-
-<!-- END TESTS -->
-
-# Appendix: A parsing strategy
-
-In this appendix we describe some features of the parsing strategy
-used in the CommonMark reference implementations.
-
-## Overview
-
-Parsing has two phases:
-
-1. In the first phase, lines of input are consumed and the block
-structure of the document---its division into paragraphs, block quotes,
-list items, and so on---is constructed. Text is assigned to these
-blocks but not parsed. Link reference definitions are parsed and a
-map of links is constructed.
-
-2. In the second phase, the raw text contents of paragraphs and headings
-are parsed into sequences of Markdown inline elements (strings,
-code spans, links, emphasis, and so on), using the map of link
-references constructed in phase 1.
-
-At each point in processing, the document is represented as a tree of
-**blocks**. The root of the tree is a `document` block. The `document`
-may have any number of other blocks as **children**. These children
-may, in turn, have other blocks as children. The last child of a block
-is normally considered **open**, meaning that subsequent lines of input
-can alter its contents. (Blocks that are not open are **closed**.)
-Here, for example, is a possible document tree, with the open blocks
-marked by arrows:
-
-``` tree
--> document
- -> block_quote
- paragraph
- "Lorem ipsum dolor\nsit amet."
- -> list (type=bullet tight=true bullet_char=-)
- list_item
- paragraph
- "Qui *quodsi iracundia*"
- -> list_item
- -> paragraph
- "aliquando id"
-```
-
-## Phase 1: block structure
-
-Each line that is processed has an effect on this tree. The line is
-analyzed and, depending on its contents, the document may be altered
-in one or more of the following ways:
-
-1. One or more open blocks may be closed.
-2. One or more new blocks may be created as children of the
- last open block.
-3. Text may be added to the last (deepest) open block remaining
- on the tree.
-
-Once a line has been incorporated into the tree in this way,
-it can be discarded, so input can be read in a stream.
-
-For each line, we follow this procedure:
-
-1. First we iterate through the open blocks, starting with the
-root document, and descending through last children down to the last
-open block. Each block imposes a condition that the line must satisfy
-if the block is to remain open. For example, a block quote requires a
-`>` character. A paragraph requires a non-blank line.
-In this phase we may match all or just some of the open
-blocks. But we cannot close unmatched blocks yet, because we may have a
-[lazy continuation line].
-
-2. Next, after consuming the continuation markers for existing
-blocks, we look for new block starts (e.g. `>` for a block quote).
-If we encounter a new block start, we close any blocks unmatched
-in step 1 before creating the new block as a child of the last
-matched block.
-
-3. Finally, we look at the remainder of the line (after block
-markers like `>`, list markers, and indentation have been consumed).
-This is text that can be incorporated into the last open
-block (a paragraph, code block, heading, or raw HTML).
-
-Setext headings are formed when we see a line of a paragraph
-that is a [setext heading underline].
-
-Reference link definitions are detected when a paragraph is closed;
-the accumulated text lines are parsed to see if they begin with
-one or more reference link definitions. Any remainder becomes a
-normal paragraph.
-
-We can see how this works by considering how the tree above is
-generated by four lines of Markdown:
-
-``` markdown
-> Lorem ipsum dolor
-sit amet.
-> - Qui *quodsi iracundia*
-> - aliquando id
-```
-
-At the outset, our document model is just
-
-``` tree
--> document
-```
-
-The first line of our text,
-
-``` markdown
-> Lorem ipsum dolor
-```
-
-causes a `block_quote` block to be created as a child of our
-open `document` block, and a `paragraph` block as a child of
-the `block_quote`. Then the text is added to the last open
-block, the `paragraph`:
-
-``` tree
--> document
- -> block_quote
- -> paragraph
- "Lorem ipsum dolor"
-```
-
-The next line,
-
-``` markdown
-sit amet.
-```
-
-is a "lazy continuation" of the open `paragraph`, so it gets added
-to the paragraph's text:
-
-``` tree
--> document
- -> block_quote
- -> paragraph
- "Lorem ipsum dolor\nsit amet."
-```
-
-The third line,
-
-``` markdown
-> - Qui *quodsi iracundia*
-```
-
-causes the `paragraph` block to be closed, and a new `list` block
-opened as a child of the `block_quote`. A `list_item` is also
-added as a child of the `list`, and a `paragraph` as a child of
-the `list_item`. The text is then added to the new `paragraph`:
-
-``` tree
--> document
- -> block_quote
- paragraph
- "Lorem ipsum dolor\nsit amet."
- -> list (type=bullet tight=true bullet_char=-)
- -> list_item
- -> paragraph
- "Qui *quodsi iracundia*"
-```
-
-The fourth line,
-
-``` markdown
-> - aliquando id
-```
-
-causes the `list_item` (and its child the `paragraph`) to be closed,
-and a new `list_item` opened up as child of the `list`. A `paragraph`
-is added as a child of the new `list_item`, to contain the text.
-We thus obtain the final tree:
-
-``` tree
--> document
- -> block_quote
- paragraph
- "Lorem ipsum dolor\nsit amet."
- -> list (type=bullet tight=true bullet_char=-)
- list_item
- paragraph
- "Qui *quodsi iracundia*"
- -> list_item
- -> paragraph
- "aliquando id"
-```
-
-## Phase 2: inline structure
-
-Once all of the input has been parsed, all open blocks are closed.
-
-We then "walk the tree," visiting every node, and parse raw
-string contents of paragraphs and headings as inlines. At this
-point we have seen all the link reference definitions, so we can
-resolve reference links as we go.
-
-``` tree
-document
- block_quote
- paragraph
- str "Lorem ipsum dolor"
- softbreak
- str "sit amet."
- list (type=bullet tight=true bullet_char=-)
- list_item
- paragraph
- str "Qui "
- emph
- str "quodsi iracundia"
- list_item
- paragraph
- str "aliquando id"
-```
-
-Notice how the [line ending] in the first paragraph has
-been parsed as a `softbreak`, and the asterisks in the first list item
-have become an `emph`.
-
-### An algorithm for parsing nested emphasis and links
-
-By far the trickiest part of inline parsing is handling emphasis,
-strong emphasis, links, and images. This is done using the following
-algorithm.
-
-When we're parsing inlines and we hit either
-
-- a run of `*` or `_` characters, or
-- a `[` or `![`
-
-we insert a text node with these symbols as its literal content, and we
-add a pointer to this text node to the [delimiter stack](@).
-
-The [delimiter stack] is a doubly linked list. Each
-element contains a pointer to a text node, plus information about
-
-- the type of delimiter (`[`, `![`, `*`, `_`)
-- the number of delimiters,
-- whether the delimiter is "active" (all are active to start), and
-- whether the delimiter is a potential opener, a potential closer,
- or both (which depends on what sort of characters precede
- and follow the delimiters).
-
-When we hit a `]` character, we call the *look for link or image*
-procedure (see below).
-
-When we hit the end of the input, we call the *process emphasis*
-procedure (see below), with `stack_bottom` = NULL.
-
-#### *look for link or image*
-
-Starting at the top of the delimiter stack, we look backwards
-through the stack for an opening `[` or `![` delimiter.
-
-- If we don't find one, we return a literal text node `]`.
-
-- If we do find one, but it's not *active*, we remove the inactive
- delimiter from the stack, and return a literal text node `]`.
-
-- If we find one and it's active, then we parse ahead to see if
- we have an inline link/image, reference link/image, compact reference
- link/image, or shortcut reference link/image.
-
- + If we don't, then we remove the opening delimiter from the
- delimiter stack and return a literal text node `]`.
-
- + If we do, then
-
- * We return a link or image node whose children are the inlines
- after the text node pointed to by the opening delimiter.
-
- * We run *process emphasis* on these inlines, with the `[` opener
- as `stack_bottom`.
-
- * We remove the opening delimiter.
-
- * If we have a link (and not an image), we also set all
- `[` delimiters before the opening delimiter to *inactive*. (This
- will prevent us from getting links within links.)
-
-#### *process emphasis*
-
-Parameter `stack_bottom` sets a lower bound to how far we
-descend in the [delimiter stack]. If it is NULL, we can
-go all the way to the bottom. Otherwise, we stop before
-visiting `stack_bottom`.
-
-Let `current_position` point to the element on the [delimiter stack]
-just above `stack_bottom` (or the first element if `stack_bottom`
-is NULL).
-
-We keep track of the `openers_bottom` for each delimiter
-type (`*`, `_`) and each length of the closing delimiter run
-(modulo 3). Initialize this to `stack_bottom`.
-
-Then we repeat the following until we run out of potential
-closers:
-
-- Move `current_position` forward in the delimiter stack (if needed)
- until we find the first potential closer with delimiter `*` or `_`.
- (This will be the potential closer closest
- to the beginning of the input -- the first one in parse order.)
-
-- Now, look back in the stack (staying above `stack_bottom` and
- the `openers_bottom` for this delimiter type) for the
- first matching potential opener ("matching" means same delimiter).
-
-- If one is found:
-
- + Figure out whether we have emphasis or strong emphasis:
- if both closer and opener spans have length >= 2, we have
- strong, otherwise regular.
-
- + Insert an emph or strong emph node accordingly, after
- the text node corresponding to the opener.
-
- + Remove any delimiters between the opener and closer from
- the delimiter stack.
-
- + Remove 1 (for regular emph) or 2 (for strong emph) delimiters
- from the opening and closing text nodes. If they become empty
- as a result, remove them and remove the corresponding element
- of the delimiter stack. If the closing node is removed, reset
- `current_position` to the next element in the stack.
-
-- If none is found:
-
- + Set `openers_bottom` to the element before `current_position`.
- (We know that there are no openers for this kind of closer up to and
- including this point, so this puts a lower bound on future searches.)
-
- + If the closer at `current_position` is not a potential opener,
- remove it from the delimiter stack (since we know it can't
- be a closer either).
-
- + Advance `current_position` to the next element in the stack.
-
-After we're done, we remove all delimiters above `stack_bottom` from the
-delimiter stack.
diff --git a/glfm_specification/output_example_snapshots/examples_index.yml b/glfm_specification/output_example_snapshots/examples_index.yml
new file mode 100644
index 00000000000..45d10679a71
--- /dev/null
+++ b/glfm_specification/output_example_snapshots/examples_index.yml
@@ -0,0 +1,2086 @@
+---
+02_01_00__preliminaries__tabs__001:
+ spec_example_position: 1
+ source_specification: commonmark
+02_01_00__preliminaries__tabs__002:
+ spec_example_position: 2
+ source_specification: commonmark
+02_01_00__preliminaries__tabs__003:
+ spec_example_position: 3
+ source_specification: commonmark
+02_01_00__preliminaries__tabs__004:
+ spec_example_position: 4
+ source_specification: commonmark
+02_01_00__preliminaries__tabs__005:
+ spec_example_position: 5
+ source_specification: commonmark
+02_01_00__preliminaries__tabs__006:
+ spec_example_position: 6
+ source_specification: commonmark
+02_01_00__preliminaries__tabs__007:
+ spec_example_position: 7
+ source_specification: commonmark
+02_01_00__preliminaries__tabs__008:
+ spec_example_position: 8
+ source_specification: commonmark
+02_01_00__preliminaries__tabs__009:
+ spec_example_position: 9
+ source_specification: commonmark
+02_01_00__preliminaries__tabs__010:
+ spec_example_position: 10
+ source_specification: commonmark
+02_01_00__preliminaries__tabs__011:
+ spec_example_position: 11
+ source_specification: commonmark
+03_01_00__blocks_and_inlines__precedence__001:
+ spec_example_position: 12
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__001:
+ spec_example_position: 13
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__002:
+ spec_example_position: 14
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__003:
+ spec_example_position: 15
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__004:
+ spec_example_position: 16
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__005:
+ spec_example_position: 17
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__006:
+ spec_example_position: 18
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__007:
+ spec_example_position: 19
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__008:
+ spec_example_position: 20
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__009:
+ spec_example_position: 21
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__010:
+ spec_example_position: 22
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__011:
+ spec_example_position: 23
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__012:
+ spec_example_position: 24
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__013:
+ spec_example_position: 25
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__014:
+ spec_example_position: 26
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__015:
+ spec_example_position: 27
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__016:
+ spec_example_position: 28
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__017:
+ spec_example_position: 29
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__018:
+ spec_example_position: 30
+ source_specification: commonmark
+04_01_00__leaf_blocks__thematic_breaks__019:
+ spec_example_position: 31
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__001:
+ spec_example_position: 32
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__002:
+ spec_example_position: 33
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__003:
+ spec_example_position: 34
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__004:
+ spec_example_position: 35
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__005:
+ spec_example_position: 36
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__006:
+ spec_example_position: 37
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__007:
+ spec_example_position: 38
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__008:
+ spec_example_position: 39
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__009:
+ spec_example_position: 40
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__010:
+ spec_example_position: 41
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__011:
+ spec_example_position: 42
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__012:
+ spec_example_position: 43
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__013:
+ spec_example_position: 44
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__014:
+ spec_example_position: 45
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__015:
+ spec_example_position: 46
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__016:
+ spec_example_position: 47
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__017:
+ spec_example_position: 48
+ source_specification: commonmark
+04_02_00__leaf_blocks__atx_headings__018:
+ spec_example_position: 49
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__001:
+ spec_example_position: 50
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__002:
+ spec_example_position: 51
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__003:
+ spec_example_position: 52
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__004:
+ spec_example_position: 53
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__005:
+ spec_example_position: 54
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__006:
+ spec_example_position: 55
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__007:
+ spec_example_position: 56
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__008:
+ spec_example_position: 57
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__009:
+ spec_example_position: 58
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__010:
+ spec_example_position: 59
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__011:
+ spec_example_position: 60
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__012:
+ spec_example_position: 61
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__013:
+ spec_example_position: 62
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__014:
+ spec_example_position: 63
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__015:
+ spec_example_position: 64
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__016:
+ spec_example_position: 65
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__017:
+ spec_example_position: 66
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__018:
+ spec_example_position: 67
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__019:
+ spec_example_position: 68
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__020:
+ spec_example_position: 69
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__021:
+ spec_example_position: 70
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__022:
+ spec_example_position: 71
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__023:
+ spec_example_position: 72
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__024:
+ spec_example_position: 73
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__025:
+ spec_example_position: 74
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__026:
+ spec_example_position: 75
+ source_specification: commonmark
+04_03_00__leaf_blocks__setext_headings__027:
+ spec_example_position: 76
+ source_specification: commonmark
+04_04_00__leaf_blocks__indented_code_blocks__001:
+ spec_example_position: 77
+ source_specification: commonmark
+04_04_00__leaf_blocks__indented_code_blocks__002:
+ spec_example_position: 78
+ source_specification: commonmark
+04_04_00__leaf_blocks__indented_code_blocks__003:
+ spec_example_position: 79
+ source_specification: commonmark
+04_04_00__leaf_blocks__indented_code_blocks__004:
+ spec_example_position: 80
+ source_specification: commonmark
+04_04_00__leaf_blocks__indented_code_blocks__005:
+ spec_example_position: 81
+ source_specification: commonmark
+04_04_00__leaf_blocks__indented_code_blocks__006:
+ spec_example_position: 82
+ source_specification: commonmark
+04_04_00__leaf_blocks__indented_code_blocks__007:
+ spec_example_position: 83
+ source_specification: commonmark
+04_04_00__leaf_blocks__indented_code_blocks__008:
+ spec_example_position: 84
+ source_specification: commonmark
+04_04_00__leaf_blocks__indented_code_blocks__009:
+ spec_example_position: 85
+ source_specification: commonmark
+04_04_00__leaf_blocks__indented_code_blocks__010:
+ spec_example_position: 86
+ source_specification: commonmark
+04_04_00__leaf_blocks__indented_code_blocks__011:
+ spec_example_position: 87
+ source_specification: commonmark
+04_04_00__leaf_blocks__indented_code_blocks__012:
+ spec_example_position: 88
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__001:
+ spec_example_position: 89
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__002:
+ spec_example_position: 90
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__003:
+ spec_example_position: 91
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__004:
+ spec_example_position: 92
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__005:
+ spec_example_position: 93
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__006:
+ spec_example_position: 94
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__007:
+ spec_example_position: 95
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__008:
+ spec_example_position: 96
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__009:
+ spec_example_position: 97
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__010:
+ spec_example_position: 98
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__011:
+ spec_example_position: 99
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__012:
+ spec_example_position: 100
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__013:
+ spec_example_position: 101
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__014:
+ spec_example_position: 102
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__015:
+ spec_example_position: 103
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__016:
+ spec_example_position: 104
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__017:
+ spec_example_position: 105
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__018:
+ spec_example_position: 106
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__019:
+ spec_example_position: 107
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__020:
+ spec_example_position: 108
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__021:
+ spec_example_position: 109
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__022:
+ spec_example_position: 110
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__023:
+ spec_example_position: 111
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__024:
+ spec_example_position: 112
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__025:
+ spec_example_position: 113
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__026:
+ spec_example_position: 114
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__027:
+ spec_example_position: 115
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__028:
+ spec_example_position: 116
+ source_specification: commonmark
+04_05_00__leaf_blocks__fenced_code_blocks__029:
+ spec_example_position: 117
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__001:
+ spec_example_position: 118
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__002:
+ spec_example_position: 119
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__003:
+ spec_example_position: 120
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__004:
+ spec_example_position: 121
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__005:
+ spec_example_position: 122
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__006:
+ spec_example_position: 123
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__007:
+ spec_example_position: 124
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__008:
+ spec_example_position: 125
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__009:
+ spec_example_position: 126
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__010:
+ spec_example_position: 127
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__011:
+ spec_example_position: 128
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__012:
+ spec_example_position: 129
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__013:
+ spec_example_position: 130
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__014:
+ spec_example_position: 131
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__015:
+ spec_example_position: 132
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__016:
+ spec_example_position: 133
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__017:
+ spec_example_position: 134
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__018:
+ spec_example_position: 135
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__019:
+ spec_example_position: 136
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__020:
+ spec_example_position: 137
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__021:
+ spec_example_position: 138
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__022:
+ spec_example_position: 139
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__023:
+ spec_example_position: 140
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__024:
+ spec_example_position: 141
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__025:
+ spec_example_position: 142
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__026:
+ spec_example_position: 143
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__027:
+ spec_example_position: 144
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__028:
+ spec_example_position: 145
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__029:
+ spec_example_position: 146
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__030:
+ spec_example_position: 147
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__031:
+ spec_example_position: 148
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__032:
+ spec_example_position: 149
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__033:
+ spec_example_position: 150
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__034:
+ spec_example_position: 151
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__035:
+ spec_example_position: 152
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__036:
+ spec_example_position: 153
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__037:
+ spec_example_position: 154
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__038:
+ spec_example_position: 155
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__039:
+ spec_example_position: 156
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__040:
+ spec_example_position: 157
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__041:
+ spec_example_position: 158
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__042:
+ spec_example_position: 159
+ source_specification: commonmark
+04_06_00__leaf_blocks__html_blocks__043:
+ spec_example_position: 160
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__001:
+ spec_example_position: 161
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__002:
+ spec_example_position: 162
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__003:
+ spec_example_position: 163
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__004:
+ spec_example_position: 164
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__005:
+ spec_example_position: 165
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__006:
+ spec_example_position: 166
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__007:
+ spec_example_position: 167
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__008:
+ spec_example_position: 168
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__009:
+ spec_example_position: 169
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__010:
+ spec_example_position: 170
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__011:
+ spec_example_position: 171
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__012:
+ spec_example_position: 172
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__013:
+ spec_example_position: 173
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__014:
+ spec_example_position: 174
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__015:
+ spec_example_position: 175
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__016:
+ spec_example_position: 176
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__017:
+ spec_example_position: 177
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__018:
+ spec_example_position: 178
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__019:
+ spec_example_position: 179
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__020:
+ spec_example_position: 180
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__021:
+ spec_example_position: 181
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__022:
+ spec_example_position: 182
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__023:
+ spec_example_position: 183
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__024:
+ spec_example_position: 184
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__025:
+ spec_example_position: 185
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__026:
+ spec_example_position: 186
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__027:
+ spec_example_position: 187
+ source_specification: commonmark
+04_07_00__leaf_blocks__link_reference_definitions__028:
+ spec_example_position: 188
+ source_specification: commonmark
+04_08_00__leaf_blocks__paragraphs__001:
+ spec_example_position: 189
+ source_specification: commonmark
+04_08_00__leaf_blocks__paragraphs__002:
+ spec_example_position: 190
+ source_specification: commonmark
+04_08_00__leaf_blocks__paragraphs__003:
+ spec_example_position: 191
+ source_specification: commonmark
+04_08_00__leaf_blocks__paragraphs__004:
+ spec_example_position: 192
+ source_specification: commonmark
+04_08_00__leaf_blocks__paragraphs__005:
+ spec_example_position: 193
+ source_specification: commonmark
+04_08_00__leaf_blocks__paragraphs__006:
+ spec_example_position: 194
+ source_specification: commonmark
+04_08_00__leaf_blocks__paragraphs__007:
+ spec_example_position: 195
+ source_specification: commonmark
+04_08_00__leaf_blocks__paragraphs__008:
+ spec_example_position: 196
+ source_specification: commonmark
+04_09_00__leaf_blocks__blank_lines__001:
+ spec_example_position: 197
+ source_specification: commonmark
+04_10_00__leaf_blocks__tables_extension__001:
+ spec_example_position: 198
+ source_specification: github
+04_10_00__leaf_blocks__tables_extension__002:
+ spec_example_position: 199
+ source_specification: github
+04_10_00__leaf_blocks__tables_extension__003:
+ spec_example_position: 200
+ source_specification: github
+04_10_00__leaf_blocks__tables_extension__004:
+ spec_example_position: 201
+ source_specification: github
+04_10_00__leaf_blocks__tables_extension__005:
+ spec_example_position: 202
+ source_specification: github
+04_10_00__leaf_blocks__tables_extension__006:
+ spec_example_position: 203
+ source_specification: github
+04_10_00__leaf_blocks__tables_extension__007:
+ spec_example_position: 204
+ source_specification: github
+04_10_00__leaf_blocks__tables_extension__008:
+ spec_example_position: 205
+ source_specification: github
+05_01_00__container_blocks__block_quotes__001:
+ spec_example_position: 206
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__002:
+ spec_example_position: 207
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__003:
+ spec_example_position: 208
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__004:
+ spec_example_position: 209
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__005:
+ spec_example_position: 210
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__006:
+ spec_example_position: 211
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__007:
+ spec_example_position: 212
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__008:
+ spec_example_position: 213
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__009:
+ spec_example_position: 214
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__010:
+ spec_example_position: 215
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__011:
+ spec_example_position: 216
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__012:
+ spec_example_position: 217
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__013:
+ spec_example_position: 218
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__014:
+ spec_example_position: 219
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__015:
+ spec_example_position: 220
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__016:
+ spec_example_position: 221
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__017:
+ spec_example_position: 222
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__018:
+ spec_example_position: 223
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__019:
+ spec_example_position: 224
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__020:
+ spec_example_position: 225
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__021:
+ spec_example_position: 226
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__022:
+ spec_example_position: 227
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__023:
+ spec_example_position: 228
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__024:
+ spec_example_position: 229
+ source_specification: commonmark
+05_01_00__container_blocks__block_quotes__025:
+ spec_example_position: 230
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__001:
+ spec_example_position: 231
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__002:
+ spec_example_position: 232
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__003:
+ spec_example_position: 233
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__004:
+ spec_example_position: 234
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__005:
+ spec_example_position: 235
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__006:
+ spec_example_position: 236
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__007:
+ spec_example_position: 237
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__008:
+ spec_example_position: 238
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__009:
+ spec_example_position: 239
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__010:
+ spec_example_position: 240
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__011:
+ spec_example_position: 241
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__012:
+ spec_example_position: 242
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__013:
+ spec_example_position: 243
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__014:
+ spec_example_position: 244
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__015:
+ spec_example_position: 245
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__016:
+ spec_example_position: 246
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__017:
+ spec_example_position: 247
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__018:
+ spec_example_position: 248
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__019:
+ spec_example_position: 249
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__020:
+ spec_example_position: 250
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__021:
+ spec_example_position: 251
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__022:
+ spec_example_position: 252
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__023:
+ spec_example_position: 253
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__024:
+ spec_example_position: 254
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__025:
+ spec_example_position: 255
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__026:
+ spec_example_position: 256
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__027:
+ spec_example_position: 257
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__028:
+ spec_example_position: 258
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__029:
+ spec_example_position: 259
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__030:
+ spec_example_position: 260
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__031:
+ spec_example_position: 261
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__032:
+ spec_example_position: 262
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__033:
+ spec_example_position: 263
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__034:
+ spec_example_position: 264
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__035:
+ spec_example_position: 265
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__036:
+ spec_example_position: 266
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__037:
+ spec_example_position: 267
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__038:
+ spec_example_position: 268
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__039:
+ spec_example_position: 269
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__040:
+ spec_example_position: 270
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__041:
+ spec_example_position: 271
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__042:
+ spec_example_position: 272
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__043:
+ spec_example_position: 273
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__044:
+ spec_example_position: 274
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__045:
+ spec_example_position: 275
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__046:
+ spec_example_position: 276
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__047:
+ spec_example_position: 277
+ source_specification: commonmark
+05_02_00__container_blocks__list_items__048:
+ spec_example_position: 278
+ source_specification: commonmark
+05_04_00__container_blocks__lists__001:
+ spec_example_position: 281
+ source_specification: commonmark
+05_04_00__container_blocks__lists__002:
+ spec_example_position: 282
+ source_specification: commonmark
+05_04_00__container_blocks__lists__003:
+ spec_example_position: 283
+ source_specification: commonmark
+05_04_00__container_blocks__lists__004:
+ spec_example_position: 284
+ source_specification: commonmark
+05_04_00__container_blocks__lists__005:
+ spec_example_position: 285
+ source_specification: commonmark
+05_04_00__container_blocks__lists__006:
+ spec_example_position: 286
+ source_specification: commonmark
+05_04_00__container_blocks__lists__007:
+ spec_example_position: 287
+ source_specification: commonmark
+05_04_00__container_blocks__lists__008:
+ spec_example_position: 288
+ source_specification: commonmark
+05_04_00__container_blocks__lists__009:
+ spec_example_position: 289
+ source_specification: commonmark
+05_04_00__container_blocks__lists__010:
+ spec_example_position: 290
+ source_specification: commonmark
+05_04_00__container_blocks__lists__011:
+ spec_example_position: 291
+ source_specification: commonmark
+05_04_00__container_blocks__lists__012:
+ spec_example_position: 292
+ source_specification: commonmark
+05_04_00__container_blocks__lists__013:
+ spec_example_position: 293
+ source_specification: commonmark
+05_04_00__container_blocks__lists__014:
+ spec_example_position: 294
+ source_specification: commonmark
+05_04_00__container_blocks__lists__015:
+ spec_example_position: 295
+ source_specification: commonmark
+05_04_00__container_blocks__lists__016:
+ spec_example_position: 296
+ source_specification: commonmark
+05_04_00__container_blocks__lists__017:
+ spec_example_position: 297
+ source_specification: commonmark
+05_04_00__container_blocks__lists__018:
+ spec_example_position: 298
+ source_specification: commonmark
+05_04_00__container_blocks__lists__019:
+ spec_example_position: 299
+ source_specification: commonmark
+05_04_00__container_blocks__lists__020:
+ spec_example_position: 300
+ source_specification: commonmark
+05_04_00__container_blocks__lists__021:
+ spec_example_position: 301
+ source_specification: commonmark
+05_04_00__container_blocks__lists__022:
+ spec_example_position: 302
+ source_specification: commonmark
+05_04_00__container_blocks__lists__023:
+ spec_example_position: 303
+ source_specification: commonmark
+05_04_00__container_blocks__lists__024:
+ spec_example_position: 304
+ source_specification: commonmark
+05_04_00__container_blocks__lists__025:
+ spec_example_position: 305
+ source_specification: commonmark
+05_04_00__container_blocks__lists__026:
+ spec_example_position: 306
+ source_specification: commonmark
+06_01_00__inlines__001:
+ spec_example_position: 307
+ source_specification: commonmark
+06_02_00__inlines__backslash_escapes__001:
+ spec_example_position: 308
+ source_specification: commonmark
+06_02_00__inlines__backslash_escapes__002:
+ spec_example_position: 309
+ source_specification: commonmark
+06_02_00__inlines__backslash_escapes__003:
+ spec_example_position: 310
+ source_specification: commonmark
+06_02_00__inlines__backslash_escapes__004:
+ spec_example_position: 311
+ source_specification: commonmark
+06_02_00__inlines__backslash_escapes__005:
+ spec_example_position: 312
+ source_specification: commonmark
+06_02_00__inlines__backslash_escapes__006:
+ spec_example_position: 313
+ source_specification: commonmark
+06_02_00__inlines__backslash_escapes__007:
+ spec_example_position: 314
+ source_specification: commonmark
+06_02_00__inlines__backslash_escapes__008:
+ spec_example_position: 315
+ source_specification: commonmark
+06_02_00__inlines__backslash_escapes__009:
+ spec_example_position: 316
+ source_specification: commonmark
+06_02_00__inlines__backslash_escapes__010:
+ spec_example_position: 317
+ source_specification: commonmark
+06_02_00__inlines__backslash_escapes__011:
+ spec_example_position: 318
+ source_specification: commonmark
+06_02_00__inlines__backslash_escapes__012:
+ spec_example_position: 319
+ source_specification: commonmark
+06_02_00__inlines__backslash_escapes__013:
+ spec_example_position: 320
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__001:
+ spec_example_position: 321
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__002:
+ spec_example_position: 322
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__003:
+ spec_example_position: 323
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__004:
+ spec_example_position: 324
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__005:
+ spec_example_position: 325
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__006:
+ spec_example_position: 326
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__007:
+ spec_example_position: 327
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__008:
+ spec_example_position: 328
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__009:
+ spec_example_position: 329
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__010:
+ spec_example_position: 330
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__011:
+ spec_example_position: 331
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__012:
+ spec_example_position: 332
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__013:
+ spec_example_position: 333
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__014:
+ spec_example_position: 334
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__015:
+ spec_example_position: 335
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__016:
+ spec_example_position: 336
+ source_specification: commonmark
+06_03_00__inlines__entity_and_numeric_character_references__017:
+ spec_example_position: 337
+ source_specification: commonmark
+06_04_00__inlines__code_spans__001:
+ spec_example_position: 338
+ source_specification: commonmark
+06_04_00__inlines__code_spans__002:
+ spec_example_position: 339
+ source_specification: commonmark
+06_04_00__inlines__code_spans__003:
+ spec_example_position: 340
+ source_specification: commonmark
+06_04_00__inlines__code_spans__004:
+ spec_example_position: 341
+ source_specification: commonmark
+06_04_00__inlines__code_spans__005:
+ spec_example_position: 342
+ source_specification: commonmark
+06_04_00__inlines__code_spans__006:
+ spec_example_position: 343
+ source_specification: commonmark
+06_04_00__inlines__code_spans__007:
+ spec_example_position: 344
+ source_specification: commonmark
+06_04_00__inlines__code_spans__008:
+ spec_example_position: 345
+ source_specification: commonmark
+06_04_00__inlines__code_spans__009:
+ spec_example_position: 346
+ source_specification: commonmark
+06_04_00__inlines__code_spans__010:
+ spec_example_position: 347
+ source_specification: commonmark
+06_04_00__inlines__code_spans__011:
+ spec_example_position: 348
+ source_specification: commonmark
+06_04_00__inlines__code_spans__012:
+ spec_example_position: 349
+ source_specification: commonmark
+06_04_00__inlines__code_spans__013:
+ spec_example_position: 350
+ source_specification: commonmark
+06_04_00__inlines__code_spans__014:
+ spec_example_position: 351
+ source_specification: commonmark
+06_04_00__inlines__code_spans__015:
+ spec_example_position: 352
+ source_specification: commonmark
+06_04_00__inlines__code_spans__016:
+ spec_example_position: 353
+ source_specification: commonmark
+06_04_00__inlines__code_spans__017:
+ spec_example_position: 354
+ source_specification: commonmark
+06_04_00__inlines__code_spans__018:
+ spec_example_position: 355
+ source_specification: commonmark
+06_04_00__inlines__code_spans__019:
+ spec_example_position: 356
+ source_specification: commonmark
+06_04_00__inlines__code_spans__020:
+ spec_example_position: 357
+ source_specification: commonmark
+06_04_00__inlines__code_spans__021:
+ spec_example_position: 358
+ source_specification: commonmark
+06_04_00__inlines__code_spans__022:
+ spec_example_position: 359
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__001:
+ spec_example_position: 360
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__002:
+ spec_example_position: 361
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__003:
+ spec_example_position: 362
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__004:
+ spec_example_position: 363
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__005:
+ spec_example_position: 364
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__006:
+ spec_example_position: 365
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__007:
+ spec_example_position: 366
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__008:
+ spec_example_position: 367
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__009:
+ spec_example_position: 368
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__010:
+ spec_example_position: 369
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__011:
+ spec_example_position: 370
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__012:
+ spec_example_position: 371
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__013:
+ spec_example_position: 372
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__014:
+ spec_example_position: 373
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__015:
+ spec_example_position: 374
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__016:
+ spec_example_position: 375
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__017:
+ spec_example_position: 376
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__018:
+ spec_example_position: 377
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__019:
+ spec_example_position: 378
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__020:
+ spec_example_position: 379
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__021:
+ spec_example_position: 380
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__022:
+ spec_example_position: 381
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__023:
+ spec_example_position: 382
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__024:
+ spec_example_position: 383
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__025:
+ spec_example_position: 384
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__026:
+ spec_example_position: 385
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__027:
+ spec_example_position: 386
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__028:
+ spec_example_position: 387
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__029:
+ spec_example_position: 388
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__030:
+ spec_example_position: 389
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__031:
+ spec_example_position: 390
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__032:
+ spec_example_position: 391
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__033:
+ spec_example_position: 392
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__034:
+ spec_example_position: 393
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__035:
+ spec_example_position: 394
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__036:
+ spec_example_position: 395
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__037:
+ spec_example_position: 396
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__038:
+ spec_example_position: 397
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__039:
+ spec_example_position: 398
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__040:
+ spec_example_position: 399
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__041:
+ spec_example_position: 400
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__042:
+ spec_example_position: 401
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__043:
+ spec_example_position: 402
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__044:
+ spec_example_position: 403
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__045:
+ spec_example_position: 404
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__046:
+ spec_example_position: 405
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__047:
+ spec_example_position: 406
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__048:
+ spec_example_position: 407
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__049:
+ spec_example_position: 408
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__050:
+ spec_example_position: 409
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__051:
+ spec_example_position: 410
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__052:
+ spec_example_position: 411
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__053:
+ spec_example_position: 412
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__054:
+ spec_example_position: 413
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__055:
+ spec_example_position: 414
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__056:
+ spec_example_position: 415
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__057:
+ spec_example_position: 416
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__058:
+ spec_example_position: 417
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__059:
+ spec_example_position: 418
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__060:
+ spec_example_position: 419
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__061:
+ spec_example_position: 420
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__062:
+ spec_example_position: 421
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__063:
+ spec_example_position: 422
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__064:
+ spec_example_position: 423
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__065:
+ spec_example_position: 424
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__066:
+ spec_example_position: 425
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__067:
+ spec_example_position: 426
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__068:
+ spec_example_position: 427
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__069:
+ spec_example_position: 428
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__070:
+ spec_example_position: 429
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__071:
+ spec_example_position: 430
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__072:
+ spec_example_position: 431
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__073:
+ spec_example_position: 432
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__074:
+ spec_example_position: 433
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__075:
+ spec_example_position: 434
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__076:
+ spec_example_position: 435
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__077:
+ spec_example_position: 436
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__078:
+ spec_example_position: 437
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__079:
+ spec_example_position: 438
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__080:
+ spec_example_position: 439
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__081:
+ spec_example_position: 440
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__082:
+ spec_example_position: 441
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__083:
+ spec_example_position: 442
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__084:
+ spec_example_position: 443
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__085:
+ spec_example_position: 444
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__086:
+ spec_example_position: 445
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__087:
+ spec_example_position: 446
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__088:
+ spec_example_position: 447
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__089:
+ spec_example_position: 448
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__090:
+ spec_example_position: 449
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__091:
+ spec_example_position: 450
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__092:
+ spec_example_position: 451
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__093:
+ spec_example_position: 452
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__094:
+ spec_example_position: 453
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__095:
+ spec_example_position: 454
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__096:
+ spec_example_position: 455
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__097:
+ spec_example_position: 456
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__098:
+ spec_example_position: 457
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__099:
+ spec_example_position: 458
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__100:
+ spec_example_position: 459
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__101:
+ spec_example_position: 460
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__102:
+ spec_example_position: 461
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__103:
+ spec_example_position: 462
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__104:
+ spec_example_position: 463
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__105:
+ spec_example_position: 464
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__106:
+ spec_example_position: 465
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__107:
+ spec_example_position: 466
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__108:
+ spec_example_position: 467
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__109:
+ spec_example_position: 468
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__110:
+ spec_example_position: 469
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__111:
+ spec_example_position: 470
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__112:
+ spec_example_position: 471
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__113:
+ spec_example_position: 472
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__114:
+ spec_example_position: 473
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__115:
+ spec_example_position: 474
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__116:
+ spec_example_position: 475
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__117:
+ spec_example_position: 476
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__118:
+ spec_example_position: 477
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__119:
+ spec_example_position: 478
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__120:
+ spec_example_position: 479
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__121:
+ spec_example_position: 480
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__122:
+ spec_example_position: 481
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__123:
+ spec_example_position: 482
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__124:
+ spec_example_position: 483
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__125:
+ spec_example_position: 484
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__126:
+ spec_example_position: 485
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__127:
+ spec_example_position: 486
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__128:
+ spec_example_position: 487
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__129:
+ spec_example_position: 488
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__130:
+ spec_example_position: 489
+ source_specification: commonmark
+06_05_00__inlines__emphasis_and_strong_emphasis__131:
+ spec_example_position: 490
+ source_specification: commonmark
+06_06_00__inlines__strikethrough_extension__001:
+ spec_example_position: 491
+ source_specification: github
+06_06_00__inlines__strikethrough_extension__002:
+ spec_example_position: 492
+ source_specification: github
+06_07_00__inlines__links__001:
+ spec_example_position: 493
+ source_specification: commonmark
+06_07_00__inlines__links__002:
+ spec_example_position: 494
+ source_specification: commonmark
+06_07_00__inlines__links__003:
+ spec_example_position: 495
+ source_specification: commonmark
+06_07_00__inlines__links__004:
+ spec_example_position: 496
+ source_specification: commonmark
+06_07_00__inlines__links__005:
+ spec_example_position: 497
+ source_specification: commonmark
+06_07_00__inlines__links__006:
+ spec_example_position: 498
+ source_specification: commonmark
+06_07_00__inlines__links__007:
+ spec_example_position: 499
+ source_specification: commonmark
+06_07_00__inlines__links__008:
+ spec_example_position: 500
+ source_specification: commonmark
+06_07_00__inlines__links__009:
+ spec_example_position: 501
+ source_specification: commonmark
+06_07_00__inlines__links__010:
+ spec_example_position: 502
+ source_specification: commonmark
+06_07_00__inlines__links__011:
+ spec_example_position: 503
+ source_specification: commonmark
+06_07_00__inlines__links__012:
+ spec_example_position: 504
+ source_specification: commonmark
+06_07_00__inlines__links__013:
+ spec_example_position: 505
+ source_specification: commonmark
+06_07_00__inlines__links__014:
+ spec_example_position: 506
+ source_specification: commonmark
+06_07_00__inlines__links__015:
+ spec_example_position: 507
+ source_specification: commonmark
+06_07_00__inlines__links__016:
+ spec_example_position: 508
+ source_specification: commonmark
+06_07_00__inlines__links__017:
+ spec_example_position: 509
+ source_specification: commonmark
+06_07_00__inlines__links__018:
+ spec_example_position: 510
+ source_specification: commonmark
+06_07_00__inlines__links__019:
+ spec_example_position: 511
+ source_specification: commonmark
+06_07_00__inlines__links__020:
+ spec_example_position: 512
+ source_specification: commonmark
+06_07_00__inlines__links__021:
+ spec_example_position: 513
+ source_specification: commonmark
+06_07_00__inlines__links__022:
+ spec_example_position: 514
+ source_specification: commonmark
+06_07_00__inlines__links__023:
+ spec_example_position: 515
+ source_specification: commonmark
+06_07_00__inlines__links__024:
+ spec_example_position: 516
+ source_specification: commonmark
+06_07_00__inlines__links__025:
+ spec_example_position: 517
+ source_specification: commonmark
+06_07_00__inlines__links__026:
+ spec_example_position: 518
+ source_specification: commonmark
+06_07_00__inlines__links__027:
+ spec_example_position: 519
+ source_specification: commonmark
+06_07_00__inlines__links__028:
+ spec_example_position: 520
+ source_specification: commonmark
+06_07_00__inlines__links__029:
+ spec_example_position: 521
+ source_specification: commonmark
+06_07_00__inlines__links__030:
+ spec_example_position: 522
+ source_specification: commonmark
+06_07_00__inlines__links__031:
+ spec_example_position: 523
+ source_specification: commonmark
+06_07_00__inlines__links__032:
+ spec_example_position: 524
+ source_specification: commonmark
+06_07_00__inlines__links__033:
+ spec_example_position: 525
+ source_specification: commonmark
+06_07_00__inlines__links__034:
+ spec_example_position: 526
+ source_specification: commonmark
+06_07_00__inlines__links__035:
+ spec_example_position: 527
+ source_specification: commonmark
+06_07_00__inlines__links__036:
+ spec_example_position: 528
+ source_specification: commonmark
+06_07_00__inlines__links__037:
+ spec_example_position: 529
+ source_specification: commonmark
+06_07_00__inlines__links__038:
+ spec_example_position: 530
+ source_specification: commonmark
+06_07_00__inlines__links__039:
+ spec_example_position: 531
+ source_specification: commonmark
+06_07_00__inlines__links__040:
+ spec_example_position: 532
+ source_specification: commonmark
+06_07_00__inlines__links__041:
+ spec_example_position: 533
+ source_specification: commonmark
+06_07_00__inlines__links__042:
+ spec_example_position: 534
+ source_specification: commonmark
+06_07_00__inlines__links__043:
+ spec_example_position: 535
+ source_specification: commonmark
+06_07_00__inlines__links__044:
+ spec_example_position: 536
+ source_specification: commonmark
+06_07_00__inlines__links__045:
+ spec_example_position: 537
+ source_specification: commonmark
+06_07_00__inlines__links__046:
+ spec_example_position: 538
+ source_specification: commonmark
+06_07_00__inlines__links__047:
+ spec_example_position: 539
+ source_specification: commonmark
+06_07_00__inlines__links__048:
+ spec_example_position: 540
+ source_specification: commonmark
+06_07_00__inlines__links__049:
+ spec_example_position: 541
+ source_specification: commonmark
+06_07_00__inlines__links__050:
+ spec_example_position: 542
+ source_specification: commonmark
+06_07_00__inlines__links__051:
+ spec_example_position: 543
+ source_specification: commonmark
+06_07_00__inlines__links__052:
+ spec_example_position: 544
+ source_specification: commonmark
+06_07_00__inlines__links__053:
+ spec_example_position: 545
+ source_specification: commonmark
+06_07_00__inlines__links__054:
+ spec_example_position: 546
+ source_specification: commonmark
+06_07_00__inlines__links__055:
+ spec_example_position: 547
+ source_specification: commonmark
+06_07_00__inlines__links__056:
+ spec_example_position: 548
+ source_specification: commonmark
+06_07_00__inlines__links__057:
+ spec_example_position: 549
+ source_specification: commonmark
+06_07_00__inlines__links__058:
+ spec_example_position: 550
+ source_specification: commonmark
+06_07_00__inlines__links__059:
+ spec_example_position: 551
+ source_specification: commonmark
+06_07_00__inlines__links__060:
+ spec_example_position: 552
+ source_specification: commonmark
+06_07_00__inlines__links__061:
+ spec_example_position: 553
+ source_specification: commonmark
+06_07_00__inlines__links__062:
+ spec_example_position: 554
+ source_specification: commonmark
+06_07_00__inlines__links__063:
+ spec_example_position: 555
+ source_specification: commonmark
+06_07_00__inlines__links__064:
+ spec_example_position: 556
+ source_specification: commonmark
+06_07_00__inlines__links__065:
+ spec_example_position: 557
+ source_specification: commonmark
+06_07_00__inlines__links__066:
+ spec_example_position: 558
+ source_specification: commonmark
+06_07_00__inlines__links__067:
+ spec_example_position: 559
+ source_specification: commonmark
+06_07_00__inlines__links__068:
+ spec_example_position: 560
+ source_specification: commonmark
+06_07_00__inlines__links__069:
+ spec_example_position: 561
+ source_specification: commonmark
+06_07_00__inlines__links__070:
+ spec_example_position: 562
+ source_specification: commonmark
+06_07_00__inlines__links__071:
+ spec_example_position: 563
+ source_specification: commonmark
+06_07_00__inlines__links__072:
+ spec_example_position: 564
+ source_specification: commonmark
+06_07_00__inlines__links__073:
+ spec_example_position: 565
+ source_specification: commonmark
+06_07_00__inlines__links__074:
+ spec_example_position: 566
+ source_specification: commonmark
+06_07_00__inlines__links__075:
+ spec_example_position: 567
+ source_specification: commonmark
+06_07_00__inlines__links__076:
+ spec_example_position: 568
+ source_specification: commonmark
+06_07_00__inlines__links__077:
+ spec_example_position: 569
+ source_specification: commonmark
+06_07_00__inlines__links__078:
+ spec_example_position: 570
+ source_specification: commonmark
+06_07_00__inlines__links__079:
+ spec_example_position: 571
+ source_specification: commonmark
+06_07_00__inlines__links__080:
+ spec_example_position: 572
+ source_specification: commonmark
+06_07_00__inlines__links__081:
+ spec_example_position: 573
+ source_specification: commonmark
+06_07_00__inlines__links__082:
+ spec_example_position: 574
+ source_specification: commonmark
+06_07_00__inlines__links__083:
+ spec_example_position: 575
+ source_specification: commonmark
+06_07_00__inlines__links__084:
+ spec_example_position: 576
+ source_specification: commonmark
+06_07_00__inlines__links__085:
+ spec_example_position: 577
+ source_specification: commonmark
+06_07_00__inlines__links__086:
+ spec_example_position: 578
+ source_specification: commonmark
+06_07_00__inlines__links__087:
+ spec_example_position: 579
+ source_specification: commonmark
+06_08_00__inlines__images__001:
+ spec_example_position: 580
+ source_specification: commonmark
+06_08_00__inlines__images__002:
+ spec_example_position: 581
+ source_specification: commonmark
+06_08_00__inlines__images__003:
+ spec_example_position: 582
+ source_specification: commonmark
+06_08_00__inlines__images__004:
+ spec_example_position: 583
+ source_specification: commonmark
+06_08_00__inlines__images__005:
+ spec_example_position: 584
+ source_specification: commonmark
+06_08_00__inlines__images__006:
+ spec_example_position: 585
+ source_specification: commonmark
+06_08_00__inlines__images__007:
+ spec_example_position: 586
+ source_specification: commonmark
+06_08_00__inlines__images__008:
+ spec_example_position: 587
+ source_specification: commonmark
+06_08_00__inlines__images__009:
+ spec_example_position: 588
+ source_specification: commonmark
+06_08_00__inlines__images__010:
+ spec_example_position: 589
+ source_specification: commonmark
+06_08_00__inlines__images__011:
+ spec_example_position: 590
+ source_specification: commonmark
+06_08_00__inlines__images__012:
+ spec_example_position: 591
+ source_specification: commonmark
+06_08_00__inlines__images__013:
+ spec_example_position: 592
+ source_specification: commonmark
+06_08_00__inlines__images__014:
+ spec_example_position: 593
+ source_specification: commonmark
+06_08_00__inlines__images__015:
+ spec_example_position: 594
+ source_specification: commonmark
+06_08_00__inlines__images__016:
+ spec_example_position: 595
+ source_specification: commonmark
+06_08_00__inlines__images__017:
+ spec_example_position: 596
+ source_specification: commonmark
+06_08_00__inlines__images__018:
+ spec_example_position: 597
+ source_specification: commonmark
+06_08_00__inlines__images__019:
+ spec_example_position: 598
+ source_specification: commonmark
+06_08_00__inlines__images__020:
+ spec_example_position: 599
+ source_specification: commonmark
+06_08_00__inlines__images__021:
+ spec_example_position: 600
+ source_specification: commonmark
+06_08_00__inlines__images__022:
+ spec_example_position: 601
+ source_specification: commonmark
+06_09_00__inlines__autolinks__001:
+ spec_example_position: 602
+ source_specification: commonmark
+06_09_00__inlines__autolinks__002:
+ spec_example_position: 603
+ source_specification: commonmark
+06_09_00__inlines__autolinks__003:
+ spec_example_position: 604
+ source_specification: commonmark
+06_09_00__inlines__autolinks__004:
+ spec_example_position: 605
+ source_specification: commonmark
+06_09_00__inlines__autolinks__005:
+ spec_example_position: 606
+ source_specification: commonmark
+06_09_00__inlines__autolinks__006:
+ spec_example_position: 607
+ source_specification: commonmark
+06_09_00__inlines__autolinks__007:
+ spec_example_position: 608
+ source_specification: commonmark
+06_09_00__inlines__autolinks__008:
+ spec_example_position: 609
+ source_specification: commonmark
+06_09_00__inlines__autolinks__009:
+ spec_example_position: 610
+ source_specification: commonmark
+06_09_00__inlines__autolinks__010:
+ spec_example_position: 611
+ source_specification: commonmark
+06_09_00__inlines__autolinks__011:
+ spec_example_position: 612
+ source_specification: commonmark
+06_09_00__inlines__autolinks__012:
+ spec_example_position: 613
+ source_specification: commonmark
+06_09_00__inlines__autolinks__013:
+ spec_example_position: 614
+ source_specification: commonmark
+06_09_00__inlines__autolinks__014:
+ spec_example_position: 615
+ source_specification: commonmark
+06_09_00__inlines__autolinks__015:
+ spec_example_position: 616
+ source_specification: commonmark
+06_09_00__inlines__autolinks__016:
+ spec_example_position: 617
+ source_specification: commonmark
+06_09_00__inlines__autolinks__017:
+ spec_example_position: 618
+ source_specification: commonmark
+06_09_00__inlines__autolinks__018:
+ spec_example_position: 619
+ source_specification: commonmark
+06_09_00__inlines__autolinks__019:
+ spec_example_position: 620
+ source_specification: commonmark
+06_10_00__inlines__autolinks_extension__001:
+ spec_example_position: 621
+ source_specification: github
+06_10_00__inlines__autolinks_extension__002:
+ spec_example_position: 622
+ source_specification: github
+06_10_00__inlines__autolinks_extension__003:
+ spec_example_position: 623
+ source_specification: github
+06_10_00__inlines__autolinks_extension__004:
+ spec_example_position: 624
+ source_specification: github
+06_10_00__inlines__autolinks_extension__005:
+ spec_example_position: 625
+ source_specification: github
+06_10_00__inlines__autolinks_extension__006:
+ spec_example_position: 626
+ source_specification: github
+06_10_00__inlines__autolinks_extension__007:
+ spec_example_position: 627
+ source_specification: github
+06_10_00__inlines__autolinks_extension__008:
+ spec_example_position: 628
+ source_specification: github
+06_10_00__inlines__autolinks_extension__009:
+ spec_example_position: 629
+ source_specification: github
+06_10_00__inlines__autolinks_extension__010:
+ spec_example_position: 630
+ source_specification: github
+06_10_00__inlines__autolinks_extension__011:
+ spec_example_position: 631
+ source_specification: github
+06_11_00__inlines__raw_html__001:
+ spec_example_position: 632
+ source_specification: commonmark
+06_11_00__inlines__raw_html__002:
+ spec_example_position: 633
+ source_specification: commonmark
+06_11_00__inlines__raw_html__003:
+ spec_example_position: 634
+ source_specification: commonmark
+06_11_00__inlines__raw_html__004:
+ spec_example_position: 635
+ source_specification: commonmark
+06_11_00__inlines__raw_html__005:
+ spec_example_position: 636
+ source_specification: commonmark
+06_11_00__inlines__raw_html__006:
+ spec_example_position: 637
+ source_specification: commonmark
+06_11_00__inlines__raw_html__007:
+ spec_example_position: 638
+ source_specification: commonmark
+06_11_00__inlines__raw_html__008:
+ spec_example_position: 639
+ source_specification: commonmark
+06_11_00__inlines__raw_html__009:
+ spec_example_position: 640
+ source_specification: commonmark
+06_11_00__inlines__raw_html__010:
+ spec_example_position: 641
+ source_specification: commonmark
+06_11_00__inlines__raw_html__011:
+ spec_example_position: 642
+ source_specification: commonmark
+06_11_00__inlines__raw_html__012:
+ spec_example_position: 643
+ source_specification: commonmark
+06_11_00__inlines__raw_html__013:
+ spec_example_position: 644
+ source_specification: commonmark
+06_11_00__inlines__raw_html__014:
+ spec_example_position: 645
+ source_specification: commonmark
+06_11_00__inlines__raw_html__015:
+ spec_example_position: 646
+ source_specification: commonmark
+06_11_00__inlines__raw_html__016:
+ spec_example_position: 647
+ source_specification: commonmark
+06_11_00__inlines__raw_html__017:
+ spec_example_position: 648
+ source_specification: commonmark
+06_11_00__inlines__raw_html__018:
+ spec_example_position: 649
+ source_specification: commonmark
+06_11_00__inlines__raw_html__019:
+ spec_example_position: 650
+ source_specification: commonmark
+06_11_00__inlines__raw_html__020:
+ spec_example_position: 651
+ source_specification: commonmark
+06_11_00__inlines__raw_html__021:
+ spec_example_position: 652
+ source_specification: commonmark
+06_12_00__inlines__disallowed_raw_html_extension__001:
+ spec_example_position: 653
+ source_specification: github
+06_13_00__inlines__hard_line_breaks__001:
+ spec_example_position: 654
+ source_specification: commonmark
+06_13_00__inlines__hard_line_breaks__002:
+ spec_example_position: 655
+ source_specification: commonmark
+06_13_00__inlines__hard_line_breaks__003:
+ spec_example_position: 656
+ source_specification: commonmark
+06_13_00__inlines__hard_line_breaks__004:
+ spec_example_position: 657
+ source_specification: commonmark
+06_13_00__inlines__hard_line_breaks__005:
+ spec_example_position: 658
+ source_specification: commonmark
+06_13_00__inlines__hard_line_breaks__006:
+ spec_example_position: 659
+ source_specification: commonmark
+06_13_00__inlines__hard_line_breaks__007:
+ spec_example_position: 660
+ source_specification: commonmark
+06_13_00__inlines__hard_line_breaks__008:
+ spec_example_position: 661
+ source_specification: commonmark
+06_13_00__inlines__hard_line_breaks__009:
+ spec_example_position: 662
+ source_specification: commonmark
+06_13_00__inlines__hard_line_breaks__010:
+ spec_example_position: 663
+ source_specification: commonmark
+06_13_00__inlines__hard_line_breaks__011:
+ spec_example_position: 664
+ source_specification: commonmark
+06_13_00__inlines__hard_line_breaks__012:
+ spec_example_position: 665
+ source_specification: commonmark
+06_13_00__inlines__hard_line_breaks__013:
+ spec_example_position: 666
+ source_specification: commonmark
+06_13_00__inlines__hard_line_breaks__014:
+ spec_example_position: 667
+ source_specification: commonmark
+06_13_00__inlines__hard_line_breaks__015:
+ spec_example_position: 668
+ source_specification: commonmark
+06_14_00__inlines__soft_line_breaks__001:
+ spec_example_position: 669
+ source_specification: commonmark
+06_14_00__inlines__soft_line_breaks__002:
+ spec_example_position: 670
+ source_specification: commonmark
+06_15_00__inlines__textual_content__001:
+ spec_example_position: 671
+ source_specification: commonmark
+06_15_00__inlines__textual_content__002:
+ spec_example_position: 672
+ source_specification: commonmark
+06_15_00__inlines__textual_content__003:
+ spec_example_position: 673
+ source_specification: commonmark
+07_01_00__gitlab_official_specification_markdown__footnotes__001:
+ spec_example_position: 674
+ source_specification: gitlab
+07_02_00__gitlab_official_specification_markdown__task_list_items__001:
+ spec_example_position: 675
+ source_specification: gitlab
+07_02_00__gitlab_official_specification_markdown__task_list_items__002:
+ spec_example_position: 676
+ source_specification: gitlab
+07_02_00__gitlab_official_specification_markdown__task_list_items__003:
+ spec_example_position: 677
+ source_specification: gitlab
+07_02_00__gitlab_official_specification_markdown__task_list_items__004:
+ spec_example_position: 678
+ source_specification: gitlab
+07_03_00__gitlab_official_specification_markdown__front_matter__001:
+ spec_example_position: 679
+ source_specification: gitlab
+07_03_00__gitlab_official_specification_markdown__front_matter__002:
+ spec_example_position: 680
+ source_specification: gitlab
+07_03_00__gitlab_official_specification_markdown__front_matter__003:
+ spec_example_position: 681
+ source_specification: gitlab
+07_03_00__gitlab_official_specification_markdown__front_matter__004:
+ spec_example_position: 682
+ source_specification: gitlab
+07_03_00__gitlab_official_specification_markdown__front_matter__005:
+ spec_example_position: 683
+ source_specification: gitlab
+07_04_00__gitlab_official_specification_markdown__table_of_contents__001:
+ spec_example_position: 684
+ source_specification: gitlab
+07_04_00__gitlab_official_specification_markdown__table_of_contents__002:
+ spec_example_position: 685
+ source_specification: gitlab
+07_04_00__gitlab_official_specification_markdown__table_of_contents__003:
+ spec_example_position: 686
+ source_specification: gitlab
+07_04_00__gitlab_official_specification_markdown__table_of_contents__004:
+ spec_example_position: 687
+ source_specification: gitlab
+08_01_00__gitlab_internal_extension_markdown__audio__001:
+ spec_example_position: 688
+ source_specification: gitlab
+08_01_00__gitlab_internal_extension_markdown__audio__002:
+ spec_example_position: 689
+ source_specification: gitlab
+08_02_00__gitlab_internal_extension_markdown__video__001:
+ spec_example_position: 690
+ source_specification: gitlab
+08_02_00__gitlab_internal_extension_markdown__video__002:
+ spec_example_position: 691
+ source_specification: gitlab
+08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__001:
+ spec_example_position: 692
+ source_specification: gitlab
+08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__002:
+ spec_example_position: 693
+ source_specification: gitlab
+08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__003:
+ spec_example_position: 694
+ source_specification: gitlab
+08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__004:
+ spec_example_position: 695
+ source_specification: gitlab
+08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__005:
+ spec_example_position: 696
+ source_specification: gitlab
+08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__006:
+ spec_example_position: 697
+ source_specification: gitlab
diff --git a/glfm_specification/output_example_snapshots/html.yml b/glfm_specification/output_example_snapshots/html.yml
new file mode 100644
index 00000000000..bdd0777ce17
--- /dev/null
+++ b/glfm_specification/output_example_snapshots/html.yml
@@ -0,0 +1,7944 @@
+---
+02_01_00__preliminaries__tabs__001:
+ canonical: "<pre><code>foo\tbaz\t\tbim\n</code></pre>\n"
+ static: "<div class=\"gl-relative markdown-code-block js-markdown-code\">\n<pre
+ data-sourcepos=\"1:2-1:13\" lang=\"plaintext\" class=\"code highlight js-syntax-highlight
+ language-plaintext\" data-canonical-lang=\"\" v-pre=\"true\"><code><span id=\"LC1\"
+ class=\"line\" lang=\"plaintext\">foo\tbaz\t\tbim</span></code></pre>\n<copy-code></copy-code>\n</div>"
+ wysiwyg: "<pre class=\"content-editor-code-block undefined code highlight\"><code>foo\tbaz\t\tbim</code></pre>"
+02_01_00__preliminaries__tabs__002:
+ canonical: "<pre><code>foo\tbaz\t\tbim\n</code></pre>\n"
+ static: "<div class=\"gl-relative markdown-code-block js-markdown-code\">\n<pre
+ data-sourcepos=\"1:4-1:15\" lang=\"plaintext\" class=\"code highlight js-syntax-highlight
+ language-plaintext\" data-canonical-lang=\"\" v-pre=\"true\"><code><span id=\"LC1\"
+ class=\"line\" lang=\"plaintext\">foo\tbaz\t\tbim</span></code></pre>\n<copy-code></copy-code>\n</div>"
+ wysiwyg: "<pre class=\"content-editor-code-block undefined code highlight\"><code>foo\tbaz\t\tbim</code></pre>"
+02_01_00__preliminaries__tabs__003:
+ canonical: "<pre><code>a\ta\ná½\ta\n</code></pre>\n"
+ static: "<div class=\"gl-relative markdown-code-block js-markdown-code\">\n<pre
+ data-sourcepos=\"1:5-2:9\" lang=\"plaintext\" class=\"code highlight js-syntax-highlight
+ language-plaintext\" data-canonical-lang=\"\" v-pre=\"true\"><code><span id=\"LC1\"
+ class=\"line\" lang=\"plaintext\">a\ta</span>\n<span id=\"LC2\" class=\"line\"
+ lang=\"plaintext\">á½\ta</span></code></pre>\n<copy-code></copy-code>\n</div>"
+ wysiwyg: "<pre class=\"content-editor-code-block undefined code highlight\"><code>a\ta\ná½\ta</code></pre>"
+02_01_00__preliminaries__tabs__004:
+ canonical: |
+ <ul>
+ <li>
+ <p>foo</p>
+ <p>bar</p>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:3-3:4" dir="auto">
+ <li data-sourcepos="1:3-3:4">
+ <p data-sourcepos="1:5-1:7">foo</p>
+ <p data-sourcepos="3:2-3:4">bar</p>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p><p>bar</p></li></ul>
+02_01_00__preliminaries__tabs__005:
+ canonical: |
+ <ul>
+ <li>
+ <p>foo</p>
+ <pre><code> bar
+ </code></pre>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-3:5" dir="auto">
+ <li data-sourcepos="1:1-3:5">
+ <p data-sourcepos="1:3-1:5">foo</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="3:2-3:5" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> bar</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p><pre class="content-editor-code-block undefined code highlight"><code> bar</code></pre></li></ul>
+02_01_00__preliminaries__tabs__006:
+ canonical: |
+ <blockquote>
+ <pre><code> foo
+ </code></pre>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-1:6" dir="auto">
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:3-1:6" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><pre class="content-editor-code-block undefined code highlight"><code> foo</code></pre></blockquote>
+02_01_00__preliminaries__tabs__007:
+ canonical: |
+ <ul>
+ <li>
+ <pre><code> foo
+ </code></pre>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-1:6" dir="auto">
+ <li data-sourcepos="1:1-1:6">
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:3-1:6" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p></p><pre class="content-editor-code-block undefined code highlight"><code> foo</code></pre></li></ul>
+02_01_00__preliminaries__tabs__008:
+ canonical: |
+ <pre><code>foo
+ bar
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-2:4" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span>
+ <span id="LC2" class="line" lang="plaintext">bar</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>foo
+ bar</code></pre>
+02_01_00__preliminaries__tabs__009:
+ canonical: |
+ <ul>
+ <li>foo
+ <ul>
+ <li>bar
+ <ul>
+ <li>baz</li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:2-3:7" dir="auto">
+ <li data-sourcepos="1:2-3:7">foo
+ <ul data-sourcepos="2:4-3:7">
+ <li data-sourcepos="2:4-3:7">bar
+ <ul data-sourcepos="3:3-3:7">
+ <li data-sourcepos="3:3-3:7">baz</li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p><ul bullet="*"><li><p>bar</p><ul bullet="*"><li><p>baz</p></li></ul></li></ul></li></ul>
+02_01_00__preliminaries__tabs__010:
+ canonical: |
+ <h1>Foo</h1>
+ static: |-
+ <h1 data-sourcepos="1:1-1:5" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h1>
+ wysiwyg: |-
+ <h1>Foo</h1>
+02_01_00__preliminaries__tabs__011:
+ canonical: |
+ <hr />
+ static: |-
+ <hr data-sourcepos="1:1-1:6">
+ wysiwyg: |-
+ <hr>
+03_01_00__blocks_and_inlines__precedence__001:
+ canonical: |
+ <ul>
+ <li>`one</li>
+ <li>two`</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-2:6" dir="auto">
+ <li data-sourcepos="1:1-1:6">`one</li>
+ <li data-sourcepos="2:1-2:6">two`</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>`one</p></li><li><p>two`</p></li></ul>
+04_01_00__leaf_blocks__thematic_breaks__001:
+ canonical: |
+ <hr />
+ <hr />
+ <hr />
+ static: |-
+ <hr data-sourcepos="1:1-1:3">
+ <hr data-sourcepos="2:1-2:3">
+ <hr data-sourcepos="3:1-3:3">
+ wysiwyg: |-
+ <hr>
+ <hr>
+ <hr>
+04_01_00__leaf_blocks__thematic_breaks__002:
+ canonical: |
+ <p>+++</p>
+ static: |-
+ <p data-sourcepos="1:1-1:3" dir="auto">+++</p>
+ wysiwyg: |-
+ <p>+++</p>
+04_01_00__leaf_blocks__thematic_breaks__003:
+ canonical: |
+ <p>===</p>
+ static: |-
+ <p data-sourcepos="1:1-1:3" dir="auto">===</p>
+ wysiwyg: |-
+ <p>===</p>
+04_01_00__leaf_blocks__thematic_breaks__004:
+ canonical: |
+ <p>--
+ **
+ __</p>
+ static: |-
+ <p data-sourcepos="1:1-3:2" dir="auto">--
+ **
+ __</p>
+ wysiwyg: |-
+ <p>--
+ **
+ __</p>
+04_01_00__leaf_blocks__thematic_breaks__005:
+ canonical: |
+ <hr />
+ <hr />
+ <hr />
+ static: |-
+ <hr data-sourcepos="1:2-1:4">
+ <hr data-sourcepos="2:3-2:5">
+ <hr data-sourcepos="3:4-3:6">
+ wysiwyg: |-
+ <hr>
+ <hr>
+ <hr>
+04_01_00__leaf_blocks__thematic_breaks__006:
+ canonical: |
+ <pre><code>***
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-1:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">***</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>***</code></pre>
+04_01_00__leaf_blocks__thematic_breaks__007:
+ canonical: |
+ <p>Foo
+ ***</p>
+ static: |-
+ <p data-sourcepos="1:1-2:7" dir="auto">Foo
+ ***</p>
+ wysiwyg: |-
+ <p>Foo
+ ***</p>
+04_01_00__leaf_blocks__thematic_breaks__008:
+ canonical: |
+ <hr />
+ static: |-
+ <hr data-sourcepos="1:1-1:37">
+ wysiwyg: |-
+ <hr>
+04_01_00__leaf_blocks__thematic_breaks__009:
+ canonical: |
+ <hr />
+ static: |-
+ <hr data-sourcepos="1:2-1:6">
+ wysiwyg: |-
+ <hr>
+04_01_00__leaf_blocks__thematic_breaks__010:
+ canonical: |
+ <hr />
+ static: |-
+ <hr data-sourcepos="1:2-1:19">
+ wysiwyg: |-
+ <hr>
+04_01_00__leaf_blocks__thematic_breaks__011:
+ canonical: |
+ <hr />
+ static: |-
+ <hr data-sourcepos="1:1-1:21">
+ wysiwyg: |-
+ <hr>
+04_01_00__leaf_blocks__thematic_breaks__012:
+ canonical: |
+ <hr />
+ static: |-
+ <hr data-sourcepos="1:1-1:11">
+ wysiwyg: |-
+ <hr>
+04_01_00__leaf_blocks__thematic_breaks__013:
+ canonical: |
+ <p>_ _ _ _ a</p>
+ <p>a------</p>
+ <p>---a---</p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto">_ _ _ _ a</p>
+ <p data-sourcepos="3:1-3:7" dir="auto">a------</p>
+ <p data-sourcepos="5:1-5:7" dir="auto">---a---</p>
+ wysiwyg: |-
+ <p>_ _ _ _ a</p>
+ <p>a------</p>
+ <p>---a---</p>
+04_01_00__leaf_blocks__thematic_breaks__014:
+ canonical: |
+ <p><em>-</em></p>
+ static: |-
+ <p data-sourcepos="1:2-1:4" dir="auto"><em>-</em></p>
+ wysiwyg: |-
+ <p><em>-</em></p>
+04_01_00__leaf_blocks__thematic_breaks__015:
+ canonical: |
+ <ul>
+ <li>foo</li>
+ </ul>
+ <hr />
+ <ul>
+ <li>bar</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-1:5" dir="auto">
+ <li data-sourcepos="1:1-1:5">foo</li>
+ </ul>
+ <hr data-sourcepos="2:1-2:3">
+ <ul data-sourcepos="3:1-3:5" dir="auto">
+ <li data-sourcepos="3:1-3:5">bar</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p></li></ul>
+ <hr>
+ <ul bullet="*"><li><p>bar</p></li></ul>
+04_01_00__leaf_blocks__thematic_breaks__016:
+ canonical: |
+ <p>Foo</p>
+ <hr />
+ <p>bar</p>
+ static: |-
+ <p data-sourcepos="1:1-1:3" dir="auto">Foo</p>
+ <hr data-sourcepos="2:1-2:3">
+ <p data-sourcepos="3:1-3:3" dir="auto">bar</p>
+ wysiwyg: |-
+ <p>Foo</p>
+ <hr>
+ <p>bar</p>
+04_01_00__leaf_blocks__thematic_breaks__017:
+ canonical: |
+ <h2>Foo</h2>
+ <p>bar</p>
+ static: |-
+ <h2 data-sourcepos="1:1-3:3" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h2>
+ <p data-sourcepos="3:1-3:3" dir="auto">bar</p>
+ wysiwyg: |-
+ <h2>Foo</h2>
+ <p>bar</p>
+04_01_00__leaf_blocks__thematic_breaks__018:
+ canonical: |
+ <ul>
+ <li>Foo</li>
+ </ul>
+ <hr />
+ <ul>
+ <li>Bar</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-1:5" dir="auto">
+ <li data-sourcepos="1:1-1:5">Foo</li>
+ </ul>
+ <hr data-sourcepos="2:1-2:5">
+ <ul data-sourcepos="3:1-3:5" dir="auto">
+ <li data-sourcepos="3:1-3:5">Bar</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>Foo</p></li></ul>
+ <hr>
+ <ul bullet="*"><li><p>Bar</p></li></ul>
+04_01_00__leaf_blocks__thematic_breaks__019:
+ canonical: |
+ <ul>
+ <li>Foo</li>
+ <li>
+ <hr />
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-2:7" dir="auto">
+ <li data-sourcepos="1:1-1:5">Foo</li>
+ <li data-sourcepos="2:1-2:7">
+ <hr data-sourcepos="2:3-2:7">
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>Foo</p></li><li><p></p><hr></li></ul>
+04_02_00__leaf_blocks__atx_headings__001:
+ canonical: |
+ <h1>foo</h1>
+ <h2>foo</h2>
+ <h3>foo</h3>
+ <h4>foo</h4>
+ <h5>foo</h5>
+ <h6>foo</h6>
+ static: |-
+ <h1 data-sourcepos="1:1-1:5" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h1>
+ <h2 data-sourcepos="2:1-2:6" dir="auto">
+ <a id="user-content-foo-1" class="anchor" href="#foo-1" aria-hidden="true"></a>foo</h2>
+ <h3 data-sourcepos="3:1-3:7" dir="auto">
+ <a id="user-content-foo-2" class="anchor" href="#foo-2" aria-hidden="true"></a>foo</h3>
+ <h4 data-sourcepos="4:1-4:8" dir="auto">
+ <a id="user-content-foo-3" class="anchor" href="#foo-3" aria-hidden="true"></a>foo</h4>
+ <h5 data-sourcepos="5:1-5:9" dir="auto">
+ <a id="user-content-foo-4" class="anchor" href="#foo-4" aria-hidden="true"></a>foo</h5>
+ <h6 data-sourcepos="6:1-6:10" dir="auto">
+ <a id="user-content-foo-5" class="anchor" href="#foo-5" aria-hidden="true"></a>foo</h6>
+ wysiwyg: |-
+ <h1>foo</h1>
+ <h2>foo</h2>
+ <h3>foo</h3>
+ <h4>foo</h4>
+ <h5>foo</h5>
+ <h6>foo</h6>
+04_02_00__leaf_blocks__atx_headings__002:
+ canonical: |
+ <p>####### foo</p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto">####### foo</p>
+ wysiwyg: |-
+ <p>####### foo</p>
+04_02_00__leaf_blocks__atx_headings__003:
+ canonical: |
+ <p>#5 bolt</p>
+ <p>#hashtag</p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto">#5 bolt</p>
+ <p data-sourcepos="3:1-3:8" dir="auto">#hashtag</p>
+ wysiwyg: |-
+ <p>#5 bolt</p>
+ <p>#hashtag</p>
+04_02_00__leaf_blocks__atx_headings__004:
+ canonical: |
+ <p>## foo</p>
+ static: |-
+ <p data-sourcepos="1:1-1:27" dir="auto"><span>#</span># foo</p>
+ wysiwyg: |-
+ <p>## foo</p>
+04_02_00__leaf_blocks__atx_headings__005:
+ canonical: |
+ <h1>foo <em>bar</em> *baz*</h1>
+ static: |-
+ <h1 data-sourcepos="1:1-1:19" dir="auto">
+ <a id="user-content-foo-bar-baz" class="anchor" href="#foo-bar-baz" aria-hidden="true"></a>foo <em>bar</em> *baz*</h1>
+ wysiwyg: |-
+ <h1>foo <em>bar</em> *baz*</h1>
+04_02_00__leaf_blocks__atx_headings__006:
+ canonical: |
+ <h1>foo</h1>
+ static: |-
+ <h1 data-sourcepos="1:1-1:22" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h1>
+ wysiwyg: |-
+ <h1>foo</h1>
+04_02_00__leaf_blocks__atx_headings__007:
+ canonical: |
+ <h3>foo</h3>
+ <h2>foo</h2>
+ <h1>foo</h1>
+ static: |-
+ <h3 data-sourcepos="1:2-1:8" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h3>
+ <h2 data-sourcepos="2:3-2:8" dir="auto">
+ <a id="user-content-foo-1" class="anchor" href="#foo-1" aria-hidden="true"></a>foo</h2>
+ <h1 data-sourcepos="3:4-3:8" dir="auto">
+ <a id="user-content-foo-2" class="anchor" href="#foo-2" aria-hidden="true"></a>foo</h1>
+ wysiwyg: |-
+ <h3>foo</h3>
+ <h2>foo</h2>
+ <h1>foo</h1>
+04_02_00__leaf_blocks__atx_headings__008:
+ canonical: |
+ <pre><code># foo
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-1:9" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># foo</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code># foo</code></pre>
+04_02_00__leaf_blocks__atx_headings__009:
+ canonical: |
+ <p>foo
+ # bar</p>
+ static: |-
+ <p data-sourcepos="1:1-2:9" dir="auto">foo
+ # bar</p>
+ wysiwyg: |-
+ <p>foo
+ # bar</p>
+04_02_00__leaf_blocks__atx_headings__010:
+ canonical: |
+ <h2>foo</h2>
+ <h3>bar</h3>
+ static: |-
+ <h2 data-sourcepos="1:1-1:6" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h2>
+ <h3 data-sourcepos="2:3-2:11" dir="auto">
+ <a id="user-content-bar" class="anchor" href="#bar" aria-hidden="true"></a>bar</h3>
+ wysiwyg: |-
+ <h2>foo</h2>
+ <h3>bar</h3>
+04_02_00__leaf_blocks__atx_headings__011:
+ canonical: |
+ <h1>foo</h1>
+ <h5>foo</h5>
+ static: |-
+ <h1 data-sourcepos="1:1-1:5" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h1>
+ <h5 data-sourcepos="2:1-2:9" dir="auto">
+ <a id="user-content-foo-1" class="anchor" href="#foo-1" aria-hidden="true"></a>foo</h5>
+ wysiwyg: |-
+ <h1>foo</h1>
+ <h5>foo</h5>
+04_02_00__leaf_blocks__atx_headings__012:
+ canonical: |
+ <h3>foo</h3>
+ static: |-
+ <h3 data-sourcepos="1:1-1:7" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h3>
+ wysiwyg: |-
+ <h3>foo</h3>
+04_02_00__leaf_blocks__atx_headings__013:
+ canonical: |
+ <h3>foo ### b</h3>
+ static: |-
+ <h3 data-sourcepos="1:1-1:13" dir="auto">
+ <a id="user-content-foo-b" class="anchor" href="#foo-b" aria-hidden="true"></a>foo ### b</h3>
+ wysiwyg: |-
+ <h3>foo ### b</h3>
+04_02_00__leaf_blocks__atx_headings__014:
+ canonical: |
+ <h1>foo#</h1>
+ static: |-
+ <h1 data-sourcepos="1:1-1:6" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo#</h1>
+ wysiwyg: |-
+ <h1>foo#</h1>
+04_02_00__leaf_blocks__atx_headings__015:
+ canonical: |
+ <h3>foo ###</h3>
+ <h2>foo ###</h2>
+ <h1>foo #</h1>
+ static: |-
+ <h3 data-sourcepos="1:1-1:32" dir="auto">
+ <a id="user-content-foo-" class="anchor" href="#foo-" aria-hidden="true"></a>foo <span>#</span>##</h3>
+ <h2 data-sourcepos="2:1-2:31" dir="auto">
+ <a id="user-content-foo--1" class="anchor" href="#foo--1" aria-hidden="true"></a>foo #<span>#</span>#</h2>
+ <h1 data-sourcepos="3:1-3:28" dir="auto">
+ <a id="user-content-foo--2" class="anchor" href="#foo--2" aria-hidden="true"></a>foo <span>#</span>
+ </h1>
+ wysiwyg: |-
+ <h3>foo ###</h3>
+ <h2>foo ###</h2>
+ <h1>foo #</h1>
+04_02_00__leaf_blocks__atx_headings__016:
+ canonical: |
+ <hr />
+ <h2>foo</h2>
+ <hr />
+ static: |-
+ <hr data-sourcepos="1:1-1:4">
+ <h2 data-sourcepos="2:1-2:6" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h2>
+ <hr data-sourcepos="3:1-3:4">
+ wysiwyg: |-
+ <hr>
+ <h2>foo</h2>
+ <hr>
+04_02_00__leaf_blocks__atx_headings__017:
+ canonical: |
+ <p>Foo bar</p>
+ <h1>baz</h1>
+ <p>Bar foo</p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto">Foo bar</p>
+ <h1 data-sourcepos="2:1-2:5" dir="auto">
+ <a id="user-content-baz" class="anchor" href="#baz" aria-hidden="true"></a>baz</h1>
+ <p data-sourcepos="3:1-3:7" dir="auto">Bar foo</p>
+ wysiwyg: |-
+ <p>Foo bar</p>
+ <h1>baz</h1>
+ <p>Bar foo</p>
+04_02_00__leaf_blocks__atx_headings__018:
+ canonical: |
+ <h2></h2>
+ <h1></h1>
+ <h3></h3>
+ static: |-
+ <h2 data-sourcepos="1:1-1:3" dir="auto"></h2>
+ <h1 data-sourcepos="2:1-2:1" dir="auto"></h1>
+ <h3 data-sourcepos="3:1-3:3" dir="auto"></h3>
+ wysiwyg: |-
+ <h2></h2>
+ <h1></h1>
+ <h3></h3>
+04_03_00__leaf_blocks__setext_headings__001:
+ canonical: |
+ <h1>Foo <em>bar</em></h1>
+ <h2>Foo <em>bar</em></h2>
+ static: |-
+ <h1 data-sourcepos="1:1-3:0" dir="auto">
+ <a id="user-content-foo-bar" class="anchor" href="#foo-bar" aria-hidden="true"></a>Foo <em>bar</em>
+ </h1>
+ <h2 data-sourcepos="4:1-5:9" dir="auto">
+ <a id="user-content-foo-bar-1" class="anchor" href="#foo-bar-1" aria-hidden="true"></a>Foo <em>bar</em>
+ </h2>
+ wysiwyg: |-
+ <h1>Foo <em>bar</em></h1>
+ <h2>Foo <em>bar</em></h2>
+04_03_00__leaf_blocks__setext_headings__002:
+ canonical: |
+ <h1>Foo <em>bar
+ baz</em></h1>
+ static: |-
+ <h1 data-sourcepos="1:1-3:4" dir="auto">
+ <a id="user-content-foo-barbaz" class="anchor" href="#foo-barbaz" aria-hidden="true"></a>Foo <em>bar
+ baz</em>
+ </h1>
+ wysiwyg: |-
+ <h1>Foo <em>bar
+ baz</em></h1>
+04_03_00__leaf_blocks__setext_headings__003:
+ canonical: |
+ <h1>Foo <em>bar
+ baz</em></h1>
+ static: |-
+ <h1 data-sourcepos="1:3-3:4" dir="auto">
+ <a id="user-content-foo-barbaz" class="anchor" href="#foo-barbaz" aria-hidden="true"></a>Foo <em>bar
+ baz</em>
+ </h1>
+ wysiwyg: |-
+ <h1>Foo <em>bar
+ baz</em></h1>
+04_03_00__leaf_blocks__setext_headings__004:
+ canonical: |
+ <h2>Foo</h2>
+ <h1>Foo</h1>
+ static: |-
+ <h2 data-sourcepos="1:1-3:0" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h2>
+ <h1 data-sourcepos="4:1-5:1" dir="auto">
+ <a id="user-content-foo-1" class="anchor" href="#foo-1" aria-hidden="true"></a>Foo</h1>
+ wysiwyg: |-
+ <h2>Foo</h2>
+ <h1>Foo</h1>
+04_03_00__leaf_blocks__setext_headings__005:
+ canonical: |
+ <h2>Foo</h2>
+ <h2>Foo</h2>
+ <h1>Foo</h1>
+ static: |-
+ <h2 data-sourcepos="1:4-3:0" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h2>
+ <h2 data-sourcepos="4:3-6:0" dir="auto">
+ <a id="user-content-foo-1" class="anchor" href="#foo-1" aria-hidden="true"></a>Foo</h2>
+ <h1 data-sourcepos="7:3-8:5" dir="auto">
+ <a id="user-content-foo-2" class="anchor" href="#foo-2" aria-hidden="true"></a>Foo</h1>
+ wysiwyg: |-
+ <h2>Foo</h2>
+ <h2>Foo</h2>
+ <h1>Foo</h1>
+04_03_00__leaf_blocks__setext_headings__006:
+ canonical: |
+ <pre><code>Foo
+ ---
+
+ Foo
+ </code></pre>
+ <hr />
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-4:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+ <span id="LC2" class="line" lang="plaintext">---</span>
+ <span id="LC3" class="line" lang="plaintext"></span>
+ <span id="LC4" class="line" lang="plaintext">Foo</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <hr data-sourcepos="5:1-5:3">
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>Foo
+ ---
+
+ Foo</code></pre>
+ <hr>
+04_03_00__leaf_blocks__setext_headings__007:
+ canonical: |
+ <h2>Foo</h2>
+ static: |-
+ <h2 data-sourcepos="1:1-2:13" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h2>
+ wysiwyg: |-
+ <h2>Foo</h2>
+04_03_00__leaf_blocks__setext_headings__008:
+ canonical: |
+ <p>Foo
+ ---</p>
+ static: |-
+ <p data-sourcepos="1:1-2:7" dir="auto">Foo
+ ---</p>
+ wysiwyg: |-
+ <p>Foo
+ ---</p>
+04_03_00__leaf_blocks__setext_headings__009:
+ canonical: |
+ <p>Foo
+ = =</p>
+ <p>Foo</p>
+ <hr />
+ static: |-
+ <p data-sourcepos="1:1-2:3" dir="auto">Foo
+ = =</p>
+ <p data-sourcepos="4:1-4:3" dir="auto">Foo</p>
+ <hr data-sourcepos="5:1-5:5">
+ wysiwyg: |-
+ <p>Foo
+ = =</p>
+ <p>Foo</p>
+ <hr>
+04_03_00__leaf_blocks__setext_headings__010:
+ canonical: |
+ <h2>Foo</h2>
+ static: |-
+ <h2 data-sourcepos="1:1-2:5" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h2>
+ wysiwyg: |-
+ <h2>Foo</h2>
+04_03_00__leaf_blocks__setext_headings__011:
+ canonical: |
+ <h2>Foo\</h2>
+ static: |-
+ <h2 data-sourcepos="1:1-2:4" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo\</h2>
+ wysiwyg: |-
+ <h2>Foo\</h2>
+04_03_00__leaf_blocks__setext_headings__012:
+ canonical: |
+ <h2>`Foo</h2>
+ <p>`</p>
+ <h2>&lt;a title=&quot;a lot</h2>
+ <p>of dashes&quot;/&gt;</p>
+ static: |-
+ <h2 data-sourcepos="1:1-3:1" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>`Foo</h2>
+ <p data-sourcepos="3:1-3:1" dir="auto">`</p>
+ <h2 data-sourcepos="5:1-7:12" dir="auto">
+ <a id="user-content-a-titlea-lot" class="anchor" href="#a-titlea-lot" aria-hidden="true"></a>&lt;a title="a lot</h2>
+ <p data-sourcepos="7:1-7:12" dir="auto">of dashes"/&gt;</p>
+ wysiwyg: |-
+ <h2>`Foo</h2>
+ <p>`</p>
+ <h2>&lt;a title="a lot</h2>
+ <p>of dashes"/&gt;</p>
+04_03_00__leaf_blocks__setext_headings__013:
+ canonical: |
+ <blockquote>
+ <p>Foo</p>
+ </blockquote>
+ <hr />
+ static: |-
+ <blockquote data-sourcepos="1:1-1:5" dir="auto">
+ <p data-sourcepos="1:3-1:5">Foo</p>
+ </blockquote>
+ <hr data-sourcepos="2:1-2:3">
+ wysiwyg: |-
+ <blockquote multiline="false"><p>Foo</p></blockquote>
+ <hr>
+04_03_00__leaf_blocks__setext_headings__014:
+ canonical: |
+ <blockquote>
+ <p>foo
+ bar
+ ===</p>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-3:3" dir="auto">
+ <p data-sourcepos="1:3-3:3">foo
+ bar
+ ===</p>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><p>foo
+ bar
+ ===</p></blockquote>
+04_03_00__leaf_blocks__setext_headings__015:
+ canonical: |
+ <ul>
+ <li>Foo</li>
+ </ul>
+ <hr />
+ static: |-
+ <ul data-sourcepos="1:1-1:5" dir="auto">
+ <li data-sourcepos="1:1-1:5">Foo</li>
+ </ul>
+ <hr data-sourcepos="2:1-2:3">
+ wysiwyg: |-
+ <ul bullet="*"><li><p>Foo</p></li></ul>
+ <hr>
+04_03_00__leaf_blocks__setext_headings__016:
+ canonical: |
+ <h2>Foo
+ Bar</h2>
+ static: |-
+ <h2 data-sourcepos="1:1-3:3" dir="auto">
+ <a id="user-content-foobar" class="anchor" href="#foobar" aria-hidden="true"></a>Foo
+ Bar</h2>
+ wysiwyg: |-
+ <h2>Foo
+ Bar</h2>
+04_03_00__leaf_blocks__setext_headings__017:
+ canonical: |
+ <hr />
+ <h2>Foo</h2>
+ <h2>Bar</h2>
+ <p>Baz</p>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-3:3" lang="yaml" class="code highlight js-syntax-highlight language-yaml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="yaml"><span class="s">Foo</span></span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <h2 data-sourcepos="4:1-6:3" dir="auto">
+ <a id="user-content-bar" class="anchor" href="#bar" aria-hidden="true"></a>Bar</h2>
+ <p data-sourcepos="6:1-6:3" dir="auto">Baz</p>
+ wysiwyg: |-
+ <pre language="yaml" class="content-editor-code-block undefined code highlight" isfrontmatter="true"><code>Foo</code></pre>
+ <h2>Bar</h2>
+ <p>Baz</p>
+04_03_00__leaf_blocks__setext_headings__018:
+ canonical: |
+ <p>====</p>
+ static: |-
+ <p data-sourcepos="2:1-2:4" dir="auto">====</p>
+ wysiwyg: |-
+ <p>====</p>
+04_03_00__leaf_blocks__setext_headings__019:
+ canonical: |
+ <hr />
+ <hr />
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-2:3" lang="yaml" class="code highlight js-syntax-highlight language-yaml" data-lang-params="frontmatter" v-pre="true"><code></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre language="yaml" class="content-editor-code-block undefined code highlight" isfrontmatter="true"><code></code></pre>
+04_03_00__leaf_blocks__setext_headings__020:
+ canonical: |
+ <ul>
+ <li>foo</li>
+ </ul>
+ <hr />
+ static: |-
+ <ul data-sourcepos="1:1-1:5" dir="auto">
+ <li data-sourcepos="1:1-1:5">foo</li>
+ </ul>
+ <hr data-sourcepos="2:1-2:5">
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p></li></ul>
+ <hr>
+04_03_00__leaf_blocks__setext_headings__021:
+ canonical: |
+ <pre><code>foo
+ </code></pre>
+ <hr />
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-1:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <hr data-sourcepos="2:1-2:3">
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
+ <hr>
+04_03_00__leaf_blocks__setext_headings__022:
+ canonical: |
+ <blockquote>
+ <p>foo</p>
+ </blockquote>
+ <hr />
+ static: |-
+ <blockquote data-sourcepos="1:1-1:5" dir="auto">
+ <p data-sourcepos="1:3-1:5">foo</p>
+ </blockquote>
+ <hr data-sourcepos="2:1-2:5">
+ wysiwyg: |-
+ <blockquote multiline="false"><p>foo</p></blockquote>
+ <hr>
+04_03_00__leaf_blocks__setext_headings__023:
+ canonical: |
+ <h2>&gt; foo</h2>
+ static: |-
+ <h2 data-sourcepos="1:1-2:6" dir="auto">
+ <a id="user-content--foo" class="anchor" href="#-foo" aria-hidden="true"></a>&gt; foo</h2>
+ wysiwyg: |-
+ <h2>&gt; foo</h2>
+04_03_00__leaf_blocks__setext_headings__024:
+ canonical: |
+ <p>Foo</p>
+ <h2>bar</h2>
+ <p>baz</p>
+ static: |-
+ <p data-sourcepos="1:1-1:3" dir="auto">Foo</p>
+ <h2 data-sourcepos="3:1-5:3" dir="auto">
+ <a id="user-content-bar" class="anchor" href="#bar" aria-hidden="true"></a>bar</h2>
+ <p data-sourcepos="5:1-5:3" dir="auto">baz</p>
+ wysiwyg: |-
+ <p>Foo</p>
+ <h2>bar</h2>
+ <p>baz</p>
+04_03_00__leaf_blocks__setext_headings__025:
+ canonical: |
+ <p>Foo
+ bar</p>
+ <hr />
+ <p>baz</p>
+ static: |-
+ <p data-sourcepos="1:1-2:3" dir="auto">Foo
+ bar</p>
+ <hr data-sourcepos="4:1-5:0">
+ <p data-sourcepos="6:1-6:3" dir="auto">baz</p>
+ wysiwyg: |-
+ <p>Foo
+ bar</p>
+ <hr>
+ <p>baz</p>
+04_03_00__leaf_blocks__setext_headings__026:
+ canonical: |
+ <p>Foo
+ bar</p>
+ <hr />
+ <p>baz</p>
+ static: |-
+ <p data-sourcepos="1:1-2:3" dir="auto">Foo
+ bar</p>
+ <hr data-sourcepos="3:1-3:5">
+ <p data-sourcepos="4:1-4:3" dir="auto">baz</p>
+ wysiwyg: |-
+ <p>Foo
+ bar</p>
+ <hr>
+ <p>baz</p>
+04_03_00__leaf_blocks__setext_headings__027:
+ canonical: |
+ <p>Foo
+ bar
+ ---
+ baz</p>
+ static: |-
+ <p data-sourcepos="1:1-4:3" dir="auto">Foo
+ bar
+ ---
+ baz</p>
+ wysiwyg: |-
+ <p>Foo
+ bar
+ ---
+ baz</p>
+04_04_00__leaf_blocks__indented_code_blocks__001:
+ canonical: |
+ <pre><code>a simple
+ indented code block
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-2:25" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">a simple</span>
+ <span id="LC2" class="line" lang="plaintext"> indented code block</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>a simple
+ indented code block</code></pre>
+04_04_00__leaf_blocks__indented_code_blocks__002:
+ canonical: |
+ <ul>
+ <li>
+ <p>foo</p>
+ <p>bar</p>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:3-3:7" dir="auto">
+ <li data-sourcepos="1:3-3:7">
+ <p data-sourcepos="1:5-1:7">foo</p>
+ <p data-sourcepos="3:5-3:7">bar</p>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p><p>bar</p></li></ul>
+04_04_00__leaf_blocks__indented_code_blocks__003:
+ canonical: |
+ <ol>
+ <li>
+ <p>foo</p>
+ <ul>
+ <li>bar</li>
+ </ul>
+ </li>
+ </ol>
+ static: |-
+ <ol data-sourcepos="1:1-3:9" dir="auto">
+ <li data-sourcepos="1:1-3:9">
+ <p data-sourcepos="1:5-1:7">foo</p>
+ <ul data-sourcepos="3:5-3:9">
+ <li data-sourcepos="3:5-3:9">bar</li>
+ </ul>
+ </li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>foo</p><ul bullet="*"><li><p>bar</p></li></ul></li></ol>
+04_04_00__leaf_blocks__indented_code_blocks__004:
+ canonical: |
+ <pre><code>&lt;a/&gt;
+ *hi*
+
+ - one
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-4:9" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a/&gt;</span>
+ <span id="LC2" class="line" lang="plaintext">*hi*</span>
+ <span id="LC3" class="line" lang="plaintext"></span>
+ <span id="LC4" class="line" lang="plaintext">- one</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>&lt;a/&gt;
+ *hi*
+
+ - one</code></pre>
+04_04_00__leaf_blocks__indented_code_blocks__005:
+ canonical: |
+ <pre><code>chunk1
+
+ chunk2
+
+
+
+ chunk3
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-7:10" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">chunk1</span>
+ <span id="LC2" class="line" lang="plaintext"></span>
+ <span id="LC3" class="line" lang="plaintext">chunk2</span>
+ <span id="LC4" class="line" lang="plaintext"></span>
+ <span id="LC5" class="line" lang="plaintext"></span>
+ <span id="LC6" class="line" lang="plaintext"></span>
+ <span id="LC7" class="line" lang="plaintext">chunk3</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>chunk1
+
+ chunk2
+
+
+
+ chunk3</code></pre>
+04_04_00__leaf_blocks__indented_code_blocks__006:
+ canonical: "<pre><code>chunk1\n \n chunk2\n</code></pre>\n"
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-3:12" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">chunk1</span>
+ <span id="LC2" class="line" lang="plaintext"> </span>
+ <span id="LC3" class="line" lang="plaintext"> chunk2</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: "<pre class=\"content-editor-code-block undefined code highlight\"><code>chunk1\n
+ \ \n chunk2</code></pre>"
+04_04_00__leaf_blocks__indented_code_blocks__007:
+ canonical: |
+ <p>Foo
+ bar</p>
+ static: |-
+ <p data-sourcepos="1:1-2:7" dir="auto">Foo
+ bar</p>
+ wysiwyg: |-
+ <p>Foo
+ bar</p>
+04_04_00__leaf_blocks__indented_code_blocks__008:
+ canonical: |
+ <pre><code>foo
+ </code></pre>
+ <p>bar</p>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-1:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <p data-sourcepos="2:1-2:3" dir="auto">bar</p>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
+ <p>bar</p>
+04_04_00__leaf_blocks__indented_code_blocks__009:
+ canonical: |
+ <h1>Heading</h1>
+ <pre><code>foo
+ </code></pre>
+ <h2>Heading</h2>
+ <pre><code>foo
+ </code></pre>
+ <hr />
+ static: |-
+ <h1 data-sourcepos="1:1-1:9" dir="auto">
+ <a id="user-content-heading" class="anchor" href="#heading" aria-hidden="true"></a>Heading</h1>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="2:5-2:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <h2 data-sourcepos="3:1-5:7" dir="auto">
+ <a id="user-content-heading-1" class="anchor" href="#heading-1" aria-hidden="true"></a>Heading</h2>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="5:5-5:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <hr data-sourcepos="6:1-6:4">
+ wysiwyg: |-
+ <h1>Heading</h1>
+ <pre class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
+ <h2>Heading</h2>
+ <pre class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
+ <hr>
+04_04_00__leaf_blocks__indented_code_blocks__010:
+ canonical: |
+ <pre><code> foo
+ bar
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-2:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span>
+ <span id="LC2" class="line" lang="plaintext">bar</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code> foo
+ bar</code></pre>
+04_04_00__leaf_blocks__indented_code_blocks__011:
+ canonical: |
+ <pre><code>foo
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="3:5-5:0" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
+04_04_00__leaf_blocks__indented_code_blocks__012:
+ canonical: "<pre><code>foo \n</code></pre>\n"
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-1:9" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo </span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>foo </code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__001:
+ canonical: |
+ <pre><code>&lt;
+ &gt;
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-4:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;</span>
+ <span id="LC2" class="line" lang="plaintext"> &gt;</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>&lt;
+ &gt;</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__002:
+ canonical: |
+ <pre><code>&lt;
+ &gt;
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-4:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;</span>
+ <span id="LC2" class="line" lang="plaintext"> &gt;</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>&lt;
+ &gt;</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__003:
+ canonical: |
+ <p><code>foo</code></p>
+ static: |-
+ <p data-sourcepos="1:1-3:2" dir="auto"><code>foo</code></p>
+ wysiwyg: |-
+ <p><code>foo</code></p>
+04_05_00__leaf_blocks__fenced_code_blocks__004:
+ canonical: |
+ <pre><code>aaa
+ ~~~
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-4:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
+ <span id="LC2" class="line" lang="plaintext">~~~</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>aaa
+ ~~~</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__005:
+ canonical: |
+ <pre><code>aaa
+ ```
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-4:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
+ <span id="LC2" class="line" lang="plaintext">```</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>aaa
+ ```</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__006:
+ canonical: |
+ <pre><code>aaa
+ ```
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-4:6" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
+ <span id="LC2" class="line" lang="plaintext">```</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>aaa
+ ```</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__007:
+ canonical: |
+ <pre><code>aaa
+ ~~~
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-4:4" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
+ <span id="LC2" class="line" lang="plaintext">~~~</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>aaa
+ ~~~</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__008:
+ canonical: |
+ <pre><code></code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-1:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code></code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__009:
+ canonical: |
+ <pre><code>
+ ```
+ aaa
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-4:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"></span>
+ <span id="LC2" class="line" lang="plaintext">```</span>
+ <span id="LC3" class="line" lang="plaintext">aaa</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>
+ ```
+ aaa</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__010:
+ canonical: |
+ <blockquote>
+ <pre><code>aaa
+ </code></pre>
+ </blockquote>
+ <p>bbb</p>
+ static: |-
+ <blockquote data-sourcepos="1:1-2:5" dir="auto">
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:3-3:0" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </blockquote>
+ <p data-sourcepos="4:1-4:3" dir="auto">bbb</p>
+ wysiwyg: |-
+ <blockquote multiline="false"><pre class="content-editor-code-block undefined code highlight"><code>aaa</code></pre></blockquote>
+ <p>bbb</p>
+04_05_00__leaf_blocks__fenced_code_blocks__011:
+ canonical: "<pre><code>\n \n</code></pre>\n"
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-4:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"></span>
+ <span id="LC2" class="line" lang="plaintext"> </span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code></code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__012:
+ canonical: |
+ <pre><code></code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-2:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code></code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__013:
+ canonical: |
+ <pre><code>aaa
+ aaa
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:2-4:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
+ <span id="LC2" class="line" lang="plaintext">aaa</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>aaa
+ aaa</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__014:
+ canonical: |
+ <pre><code>aaa
+ aaa
+ aaa
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:3-5:5" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
+ <span id="LC2" class="line" lang="plaintext">aaa</span>
+ <span id="LC3" class="line" lang="plaintext">aaa</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>aaa
+ aaa
+ aaa</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__015:
+ canonical: |
+ <pre><code>aaa
+ aaa
+ aaa
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:4-5:6" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
+ <span id="LC2" class="line" lang="plaintext"> aaa</span>
+ <span id="LC3" class="line" lang="plaintext">aaa</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>aaa
+ aaa
+ aaa</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__016:
+ canonical: |
+ <pre><code>```
+ aaa
+ ```
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-3:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
+ <span id="LC2" class="line" lang="plaintext">aaa</span>
+ <span id="LC3" class="line" lang="plaintext">```</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>```
+ aaa
+ ```</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__017:
+ canonical: |
+ <pre><code>aaa
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-3:5" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>aaa</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__018:
+ canonical: |
+ <pre><code>aaa
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:4-3:5" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>aaa</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__019:
+ canonical: |
+ <pre><code>aaa
+ ```
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-3:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
+ <span id="LC2" class="line" lang="plaintext"> ```</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>aaa
+ ```</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__020:
+ canonical: |
+ <p><code> </code>
+ aaa</p>
+ static: |-
+ <p data-sourcepos="1:1-2:3" dir="auto"><code> </code>
+ aaa</p>
+ wysiwyg: |-
+ <p>
+ aaa</p>
+04_05_00__leaf_blocks__fenced_code_blocks__021:
+ canonical: |
+ <pre><code>aaa
+ ~~~ ~~
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-3:6" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
+ <span id="LC2" class="line" lang="plaintext">~~~ ~~</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>aaa
+ ~~~ ~~</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__022:
+ canonical: |
+ <p>foo</p>
+ <pre><code>bar
+ </code></pre>
+ <p>baz</p>
+ static: |-
+ <p data-sourcepos="1:1-1:3" dir="auto">foo</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="2:1-4:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <p data-sourcepos="5:1-5:3" dir="auto">baz</p>
+ wysiwyg: |-
+ <p>foo</p>
+ <pre class="content-editor-code-block undefined code highlight"><code>bar</code></pre>
+ <p>baz</p>
+04_05_00__leaf_blocks__fenced_code_blocks__023:
+ canonical: |
+ <h2>foo</h2>
+ <pre><code>bar
+ </code></pre>
+ <h1>baz</h1>
+ static: |-
+ <h2 data-sourcepos="1:1-3:3" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h2>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="3:1-5:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <h1 data-sourcepos="6:1-6:5" dir="auto">
+ <a id="user-content-baz" class="anchor" href="#baz" aria-hidden="true"></a>baz</h1>
+ wysiwyg: |-
+ <h2>foo</h2>
+ <pre class="content-editor-code-block undefined code highlight"><code>bar</code></pre>
+ <h1>baz</h1>
+04_05_00__leaf_blocks__fenced_code_blocks__024:
+ canonical: |
+ <pre><code class="language-ruby">def foo(x)
+ return 3
+ end
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-5:3" lang="ruby" class="code highlight js-syntax-highlight language-ruby" v-pre="true"><code><span id="LC1" class="line" lang="ruby"><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">x</span><span class="p">)</span></span>
+ <span id="LC2" class="line" lang="ruby"> <span class="k">return</span> <span class="mi">3</span></span>
+ <span id="LC3" class="line" lang="ruby"><span class="k">end</span></span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre language="ruby" class="content-editor-code-block undefined code highlight"><code>def foo(x)
+ return 3
+ end</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__025:
+ canonical: |
+ <pre><code class="language-ruby">def foo(x)
+ return 3
+ end
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-5:7" lang="ruby" class="code highlight js-syntax-highlight language-ruby" v-pre="true"><code><span id="LC1" class="line" lang="ruby"><span class="k">def</span> <span class="nf">foo</span><span class="p">(</span><span class="n">x</span><span class="p">)</span></span>
+ <span id="LC2" class="line" lang="ruby"> <span class="k">return</span> <span class="mi">3</span></span>
+ <span id="LC3" class="line" lang="ruby"><span class="k">end</span></span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre language="ruby" class="content-editor-code-block undefined code highlight"><code>def foo(x)
+ return 3
+ end</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__026:
+ canonical: |
+ <pre><code class="language-;"></code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-2:4" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang=";" v-pre="true"><code></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre language=";" class="content-editor-code-block undefined code highlight"><code></code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__027:
+ canonical: |
+ <p><code>aa</code>
+ foo</p>
+ static: |-
+ <p data-sourcepos="1:1-2:3" dir="auto"><code>aa</code>
+ foo</p>
+ wysiwyg: |-
+ <p><code>aa</code>
+ foo</p>
+04_05_00__leaf_blocks__fenced_code_blocks__028:
+ canonical: |
+ <pre><code class="language-aa">foo
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-3:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="aa" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre language="aa" class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
+04_05_00__leaf_blocks__fenced_code_blocks__029:
+ canonical: |
+ <pre><code>``` aaa
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-3:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``` aaa</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>``` aaa</code></pre>
+04_06_00__leaf_blocks__html_blocks__001:
+ canonical: |
+ <table><tr><td>
+ <pre>
+ **Hello**,
+ <p><em>world</em>.
+ </pre></p>
+ </td></tr></table>
+ static: |-
+ <table dir="auto"><tr><td>
+ <pre>
+ **Hello**,
+ <p data-sourcepos="5:1-6:6"><em>world</em>.
+ </p></pre>
+ </td></tr></table>
+ wysiwyg: |-
+ <table><tbody><tr><td colspan="1" rowspan="1"><pre><p>**Hello**,
+ </p><p><em>world</em>.
+ </p></pre><p></p></td></tr></tbody></table>
+04_06_00__leaf_blocks__html_blocks__002:
+ canonical: |
+ <table>
+ <tr>
+ <td>
+ hi
+ </td>
+ </tr>
+ </table>
+ <p>okay.</p>
+ static: |-
+ <table dir="auto">
+ <tr>
+ <td>
+ hi
+ </td>
+ </tr>
+ </table>
+ <p data-sourcepos="9:1-9:5" dir="auto">okay.</p>
+ wysiwyg: |-
+ <table><tbody><tr><td colspan="1" rowspan="1"><p>
+ hi
+ </p></td></tr></tbody></table>
+ <p>okay.</p>
+04_06_00__leaf_blocks__html_blocks__003:
+ canonical: |2
+ <div>
+ *hello*
+ <foo><a>
+ static: |2-
+ <div>
+ *hello*
+ <a></a>
+ </div>
+ wysiwyg: |-
+ <div><p>
+ *hello*
+ </p></div>
+04_06_00__leaf_blocks__html_blocks__004:
+ canonical: |
+ </div>
+ *foo*
+ static: |2-
+
+ *foo*
+ wysiwyg: |-
+ <p>
+ *foo*</p>
+04_06_00__leaf_blocks__html_blocks__005:
+ canonical: |
+ <DIV CLASS="foo">
+ <p><em>Markdown</em></p>
+ </DIV>
+ static: |-
+ <div>
+ <p data-sourcepos="3:1-3:10"><em>Markdown</em></p>
+ </div>
+ wysiwyg: |-
+ <div><p><em>Markdown</em></p></div>
+04_06_00__leaf_blocks__html_blocks__006:
+ canonical: |
+ <div id="foo"
+ class="bar">
+ </div>
+ static: |-
+ <div>
+ </div>
+ wysiwyg: |-
+ <div></div>
+04_06_00__leaf_blocks__html_blocks__007:
+ canonical: |
+ <div id="foo" class="bar
+ baz">
+ </div>
+ static: |-
+ <div>
+ </div>
+ wysiwyg: |-
+ <div></div>
+04_06_00__leaf_blocks__html_blocks__008:
+ canonical: |
+ <div>
+ *foo*
+ <p><em>bar</em></p>
+ static: |-
+ <div>
+ *foo*
+ <p data-sourcepos="4:1-4:5"><em>bar</em></p>
+ </div>
+ wysiwyg: |-
+ <div><p>
+ *foo*
+ </p><p><em>bar</em></p></div>
+04_06_00__leaf_blocks__html_blocks__009:
+ canonical: |
+ <div id="foo"
+ *hi*
+ static: |-
+ <div></div>
+ wysiwyg: |-
+ <p></p>
+04_06_00__leaf_blocks__html_blocks__010:
+ canonical: |
+ <div class
+ foo
+ static: |-
+ <div></div>
+ wysiwyg: |-
+ <p></p>
+04_06_00__leaf_blocks__html_blocks__011:
+ canonical: |
+ <div *???-&&&-<---
+ *foo*
+ static: |-
+ <div></div>
+ wysiwyg: |-
+ <p></p>
+04_06_00__leaf_blocks__html_blocks__012:
+ canonical: |
+ <div><a href="bar">*foo*</a></div>
+ static: |-
+ <div><a href="bar">*foo*</a></div>
+ wysiwyg: |-
+ <div><p><a target="_blank" rel="noopener noreferrer nofollow" href="bar">*foo*</a></p></div>
+04_06_00__leaf_blocks__html_blocks__013:
+ canonical: |
+ <table><tr><td>
+ foo
+ </td></tr></table>
+ static: |-
+ <table dir="auto"><tr><td>
+ foo
+ </td></tr></table>
+ wysiwyg: |-
+ <table><tbody><tr><td colspan="1" rowspan="1"><p>
+ foo
+ </p></td></tr></tbody></table>
+04_06_00__leaf_blocks__html_blocks__014:
+ canonical: |
+ <div></div>
+ ``` c
+ int x = 33;
+ ```
+ static: |-
+ <div></div>
+ ``` c
+ int x = 33;
+ ```
+ wysiwyg: |-
+ <div></div>
+ <p>
+ ``` c
+ int x = 33;
+ ```</p>
+04_06_00__leaf_blocks__html_blocks__015:
+ canonical: |
+ <a href="foo">
+ *bar*
+ </a>
+ static: |-
+ <a href="foo">
+ *bar*
+ </a>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="foo">
+ *bar*
+ </a></p>
+04_06_00__leaf_blocks__html_blocks__016:
+ canonical: |
+ <Warning>
+ *bar*
+ </Warning>
+ static: |2
+
+ *bar*
+ wysiwyg: |-
+ <p></p>
+04_06_00__leaf_blocks__html_blocks__017:
+ canonical: |
+ <i class="foo">
+ *bar*
+ </i>
+ static: |-
+ <i>
+ *bar*
+ </i>
+ wysiwyg: |-
+ <p><em>
+ *bar*
+ </em></p>
+04_06_00__leaf_blocks__html_blocks__018:
+ canonical: |
+ </ins>
+ *bar*
+ static: |2-
+
+ *bar*
+ wysiwyg: |-
+ <p>
+ *bar*</p>
+04_06_00__leaf_blocks__html_blocks__019:
+ canonical: |
+ <del>
+ *foo*
+ </del>
+ static: |-
+ <del>
+ *foo*
+ </del>
+ wysiwyg: |-
+ <p><s>
+ *foo*
+ </s></p>
+04_06_00__leaf_blocks__html_blocks__020:
+ canonical: |
+ <del>
+ <p><em>foo</em></p>
+ </del>
+ static: |-
+ <del>
+ <p data-sourcepos="3:1-3:5"><em>foo</em></p>
+ </del>
+ wysiwyg: |-
+ <p><em><s>foo</s></em></p>
+04_06_00__leaf_blocks__html_blocks__021:
+ canonical: |
+ <p><del><em>foo</em></del></p>
+ static: |-
+ <p data-sourcepos="1:1-1:16" dir="auto"><del><em>foo</em></del></p>
+ wysiwyg: |-
+ <p><em><s>foo</s></em></p>
+04_06_00__leaf_blocks__html_blocks__022:
+ canonical: |
+ <pre language="haskell"><code>
+ import Text.HTML.TagSoup
+
+ main :: IO ()
+ main = print $ parseTags tags
+ </code></pre>
+ <p>okay</p>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"></span>
+ <span id="LC2" class="line" lang="plaintext">import Text.HTML.TagSoup</span>
+ <span id="LC3" class="line" lang="plaintext"></span>
+ <span id="LC4" class="line" lang="plaintext">main :: IO ()</span>
+ <span id="LC5" class="line" lang="plaintext">main = print $ parseTags tags</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <p data-sourcepos="7:1-7:4" dir="auto">okay</p>
+ wysiwyg: |-
+ <pre><p><code>
+ import Text.HTML.TagSoup
+
+ main :: IO ()
+ main = print $ parseTags tags
+ </code></p></pre>
+ <p>okay</p>
+04_06_00__leaf_blocks__html_blocks__023:
+ canonical: |
+ <script type="text/javascript">
+ // JavaScript example
+
+ document.getElementById("demo").innerHTML = "Hello JavaScript!";
+ </script>
+ <p>okay</p>
+ static: |2-
+
+ <p data-sourcepos="6:1-6:4" dir="auto">okay</p>
+ wysiwyg: |-
+ <p>okay</p>
+04_06_00__leaf_blocks__html_blocks__024:
+ canonical: |
+ <style
+ type="text/css">
+ h1 {color:red;}
+
+ p {color:blue;}
+ </style>
+ <p>okay</p>
+ static: |2-
+
+ h1 {color:red;}
+
+ p {color:blue;}
+
+ <p data-sourcepos="7:1-7:4" dir="auto">okay</p>
+ wysiwyg: |-
+ <p>okay</p>
+04_06_00__leaf_blocks__html_blocks__025:
+ canonical: |
+ <style
+ type="text/css">
+
+ foo
+ static: |2-
+
+
+ foo
+ wysiwyg: |-
+ <p></p>
+04_06_00__leaf_blocks__html_blocks__026:
+ canonical: |
+ <blockquote>
+ <div>
+ foo
+ </blockquote>
+ <p>bar</p>
+ static: |-
+ <blockquote data-sourcepos="1:1-2:5" dir="auto">
+ <div>
+ foo
+
+ <p data-sourcepos="4:1-4:3">bar</p>
+ </div>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><div><p>
+ foo
+ </p></div></blockquote>
+ <p>bar</p>
+04_06_00__leaf_blocks__html_blocks__027:
+ canonical: |
+ <ul>
+ <li>
+ <div>
+ </li>
+ <li>foo</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-2:5" dir="auto">
+ <li data-sourcepos="1:1-1:7">
+ <div>
+
+ <li data-sourcepos="2:1-2:5">foo</li>
+ </div>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p></p><div></div></li><li><p>foo</p></li></ul>
+04_06_00__leaf_blocks__html_blocks__028:
+ canonical: |
+ <style>p{color:red;}</style>
+ <p><em>foo</em></p>
+ static: |-
+ p{color:red;}
+ <p data-sourcepos="2:1-2:5" dir="auto"><em>foo</em></p>
+ wysiwyg: |-
+ <p><em>foo</em></p>
+04_06_00__leaf_blocks__html_blocks__029:
+ canonical: |
+ <!-- foo -->*bar*
+ <p><em>baz</em></p>
+ static: |-
+ *bar*
+ <p data-sourcepos="2:1-2:5" dir="auto"><em>baz</em></p>
+ wysiwyg: |-
+ <p>*bar*
+ </p>
+ <p><em>baz</em></p>
+04_06_00__leaf_blocks__html_blocks__030:
+ canonical: |
+ <script>
+ foo
+ </script>1. *bar*
+ static: |-
+ 1. *bar*
+ wysiwyg: |-
+ <p>1. *bar*</p>
+04_06_00__leaf_blocks__html_blocks__031:
+ canonical: |
+ <!-- Foo
+
+ bar
+ baz -->
+ <p>okay</p>
+ static: |2-
+
+ <p data-sourcepos="5:1-5:4" dir="auto">okay</p>
+ wysiwyg: |-
+ <p>okay</p>
+04_06_00__leaf_blocks__html_blocks__032:
+ canonical: |
+ <?php
+
+ echo '>';
+
+ ?>
+ <p>okay</p>
+ static: |-
+ <?php echo '>';
+
+ ?&gt;
+ <p data-sourcepos="6:1-6:4" dir="auto">okay</p>
+ wysiwyg: |-
+ <p>';
+
+ ?&gt;
+ </p>
+ <p>okay</p>
+04_06_00__leaf_blocks__html_blocks__033:
+ canonical: |
+ <!DOCTYPE html>
+ static: ""
+ wysiwyg: |-
+ <p></p>
+04_06_00__leaf_blocks__html_blocks__034:
+ canonical: |
+ <![CDATA[
+ function matchwo(a,b)
+ {
+ if (a < b && a < 0) then {
+ return 1;
+
+ } else {
+
+ return 0;
+ }
+ }
+ ]]>
+ <p>okay</p>
+ static: |2-
+
+ <p data-sourcepos="13:1-13:4" dir="auto">okay</p>
+ wysiwyg: |-
+ <p>okay</p>
+04_06_00__leaf_blocks__html_blocks__035:
+ canonical: |2
+ <!-- foo -->
+ <pre><code>&lt;!-- foo --&gt;
+ </code></pre>
+ static: " \n<div class=\"gl-relative markdown-code-block js-markdown-code\">\n<pre
+ data-sourcepos=\"3:5-3:16\" lang=\"plaintext\" class=\"code highlight js-syntax-highlight
+ language-plaintext\" data-canonical-lang=\"\" v-pre=\"true\"><code><span id=\"LC1\"
+ class=\"line\" lang=\"plaintext\">&lt;!-- foo --&gt;</span></code></pre>\n<copy-code></copy-code>\n</div>"
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>&lt;!-- foo --&gt;</code></pre>
+04_06_00__leaf_blocks__html_blocks__036:
+ canonical: |2
+ <div>
+ <pre><code>&lt;div&gt;
+ </code></pre>
+ static: |2-
+ <div>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="3:5-3:9" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </div>
+ wysiwyg: |-
+ <div><pre class="content-editor-code-block undefined code highlight"><code>&lt;div&gt;</code></pre></div>
+04_06_00__leaf_blocks__html_blocks__037:
+ canonical: |
+ <p>Foo</p>
+ <div>
+ bar
+ </div>
+ static: |-
+ <p data-sourcepos="1:1-1:3" dir="auto">Foo</p>
+ <div>
+ bar
+ </div>
+ wysiwyg: |-
+ <p>Foo</p>
+ <div><p>
+ bar
+ </p></div>
+04_06_00__leaf_blocks__html_blocks__038:
+ canonical: |
+ <div>
+ bar
+ </div>
+ *foo*
+ static: |-
+ <div>
+ bar
+ </div>
+ *foo*
+ wysiwyg: |-
+ <div><p>
+ bar
+ </p></div>
+ <p>
+ *foo*</p>
+04_06_00__leaf_blocks__html_blocks__039:
+ canonical: |
+ <p>Foo
+ <a href="bar">
+ baz</p>
+ static: |-
+ <p data-sourcepos="1:1-3:3" dir="auto">Foo
+ <a href="bar">
+ baz</a></p>
+ wysiwyg: |-
+ <p>Foo
+ <a target="_blank" rel="noopener noreferrer nofollow" href="bar">
+ baz</a></p>
+04_06_00__leaf_blocks__html_blocks__040:
+ canonical: |
+ <div>
+ <p><em>Emphasized</em> text.</p>
+ </div>
+ static: |-
+ <div>
+ <p data-sourcepos="3:1-3:18"><em>Emphasized</em> text.</p>
+ </div>
+ wysiwyg: |-
+ <div><p><em>Emphasized</em> text.</p></div>
+04_06_00__leaf_blocks__html_blocks__041:
+ canonical: |
+ <div>
+ *Emphasized* text.
+ </div>
+ static: |-
+ <div>
+ *Emphasized* text.
+ </div>
+ wysiwyg: |-
+ <div><p>
+ *Emphasized* text.
+ </p></div>
+04_06_00__leaf_blocks__html_blocks__042:
+ canonical: |
+ <table>
+ <tr>
+ <td>
+ Hi
+ </td>
+ </tr>
+ </table>
+ static: |-
+ <table dir="auto">
+ <tr>
+ <td>
+ Hi
+ </td>
+ </tr>
+ </table>
+ wysiwyg: |-
+ <table><tbody><tr><td colspan="1" rowspan="1"><p>
+ Hi
+ </p></td></tr></tbody></table>
+04_06_00__leaf_blocks__html_blocks__043:
+ canonical: |
+ <table>
+ <tr>
+ <pre><code>&lt;td&gt;
+ Hi
+ &lt;/td&gt;
+ </code></pre>
+ </tr>
+ </table>
+ static: |-
+ <table dir="auto">
+ <tr>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="5:5-8:0" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;td&gt;</span>
+ <span id="LC2" class="line" lang="plaintext"> Hi</span>
+ <span id="LC3" class="line" lang="plaintext">&lt;/td&gt;</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </tr>
+ </table>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>&lt;td&gt;
+ Hi
+ &lt;/td&gt;</code></pre>
+ <table><tbody><tr></tr></tbody></table>
+04_07_00__leaf_blocks__link_reference_definitions__001:
+ canonical: |
+ <p><a href="/url" title="title">foo</a></p>
+ static: |-
+ <p data-sourcepos="3:1-3:5" dir="auto"><a href="/url" title="title">foo</a></p>
+ wysiwyg: |-
+ <pre>[foo]: /url "title"</pre>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">foo</a></p>
+04_07_00__leaf_blocks__link_reference_definitions__002:
+ canonical: |
+ <p><a href="/url" title="the title">foo</a></p>
+ static: |-
+ <p data-sourcepos="5:1-5:5" dir="auto"><a href="/url" title="the title">foo</a></p>
+ wysiwyg: |-
+ <pre>[foo]: /url "the title"</pre>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="the title">foo</a></p>
+04_07_00__leaf_blocks__link_reference_definitions__003:
+ canonical: |
+ <p><a href="my_(url)" title="title (with parens)">Foo*bar]</a></p>
+ static: |-
+ <p data-sourcepos="3:1-3:11" dir="auto"><a href="my_(url)" title="title (with parens)">Foo*bar]</a></p>
+ wysiwyg: |-
+ <pre>[foo*bar\]]: my_(url) "title (with parens)"</pre>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="my_(url)" title="title (with parens)">Foo*bar]</a></p>
+04_07_00__leaf_blocks__link_reference_definitions__004:
+ canonical: |
+ <p><a href="my%20url" title="title">Foo bar</a></p>
+ static: |-
+ <p data-sourcepos="5:1-5:9" dir="auto"><a href="my%20url" title="title">Foo bar</a></p>
+ wysiwyg: |-
+ <pre>[foo bar]: my url "title"</pre>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="my%20url" title="title">Foo bar</a></p>
+04_07_00__leaf_blocks__link_reference_definitions__005:
+ canonical: |
+ <p><a href="/url" title="
+ title
+ line1
+ line2
+ ">foo</a></p>
+ static: |-
+ <p data-sourcepos="7:1-7:5" dir="auto"><a href="/url" title="
+ title
+ line1
+ line2
+ ">foo</a></p>
+ wysiwyg: |-
+ <pre>[foo]: /url "
+ title
+ line1
+ line2
+ "</pre>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="
+ title
+ line1
+ line2
+ ">foo</a></p>
+04_07_00__leaf_blocks__link_reference_definitions__006:
+ canonical: |
+ <p>[foo]: /url 'title</p>
+ <p>with blank line'</p>
+ <p>[foo]</p>
+ static: |-
+ <p data-sourcepos="1:1-1:18" dir="auto">[foo]: /url 'title</p>
+ <p data-sourcepos="3:1-3:16" dir="auto">with blank line'</p>
+ <p data-sourcepos="5:1-5:5" dir="auto">[foo]</p>
+ wysiwyg: |-
+ <p>[foo]: /url 'title</p>
+ <p>with blank line'</p>
+ <p>[foo]</p>
+04_07_00__leaf_blocks__link_reference_definitions__007:
+ canonical: |
+ <p><a href="/url">foo</a></p>
+ static: |-
+ <p data-sourcepos="4:1-4:5" dir="auto"><a href="/url">foo</a></p>
+ wysiwyg: |-
+ <pre>[foo]: /url</pre>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url">foo</a></p>
+04_07_00__leaf_blocks__link_reference_definitions__008:
+ canonical: |
+ <p>[foo]:</p>
+ <p>[foo]</p>
+ static: |-
+ <p data-sourcepos="1:1-1:6" dir="auto">[foo]:</p>
+ <p data-sourcepos="3:1-3:5" dir="auto">[foo]</p>
+ wysiwyg: |-
+ <p>[foo]:</p>
+ <p>[foo]</p>
+04_07_00__leaf_blocks__link_reference_definitions__009:
+ canonical: |
+ <p><a href="">foo</a></p>
+ static: |-
+ <p data-sourcepos="3:1-3:5" dir="auto"><a href="">foo</a></p>
+ wysiwyg: |-
+ <pre>[foo]: </pre>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="">foo</a></p>
+04_07_00__leaf_blocks__link_reference_definitions__010:
+ canonical: |
+ <p>[foo]: <bar>(baz)</p>
+ <p>[foo]</p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto">[foo]: (baz)</p>
+ <p data-sourcepos="3:1-3:5" dir="auto">[foo]</p>
+ wysiwyg: |-
+ <p>[foo]: </p>
+ <p>[foo]</p>
+04_07_00__leaf_blocks__link_reference_definitions__011:
+ canonical: |
+ <p><a href="/url%5Cbar*baz" title="foo&quot;bar\baz">foo</a></p>
+ static: |-
+ <p data-sourcepos="3:1-3:5" dir="auto"><a href="/url%5Cbar*baz" title='foo"bar\baz'>foo</a></p>
+ wysiwyg: |-
+ <pre>[foo]: /url\bar*baz "foo"bar\baz"</pre>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url%5Cbar*baz" title="foo&quot;bar\baz">foo</a></p>
+04_07_00__leaf_blocks__link_reference_definitions__012:
+ canonical: |
+ <p><a href="url">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:5" dir="auto"><a href="url">foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="url">foo</a></p>
+ <pre>[foo]: url</pre>
+04_07_00__leaf_blocks__link_reference_definitions__013:
+ canonical: |
+ <p><a href="first">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:5" dir="auto"><a href="first">foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="first">foo</a></p>
+ <pre>[foo]: first</pre>
+ <pre>[foo]: second</pre>
+04_07_00__leaf_blocks__link_reference_definitions__014:
+ canonical: |
+ <p><a href="/url">Foo</a></p>
+ static: |-
+ <p data-sourcepos="3:1-3:5" dir="auto"><a href="/url">Foo</a></p>
+ wysiwyg: |-
+ <pre>[foo]: /url</pre>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url">Foo</a></p>
+04_07_00__leaf_blocks__link_reference_definitions__015:
+ canonical: |
+ <p><a href="/%CF%86%CE%BF%CF%85">αγω</a></p>
+ static: |-
+ <p data-sourcepos="3:1-3:8" dir="auto"><a href="/%CF%86%CE%BF%CF%85">αγω</a></p>
+ wysiwyg: |-
+ <pre>[αγω]: /φου</pre>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/%CF%86%CE%BF%CF%85">αγω</a></p>
+04_07_00__leaf_blocks__link_reference_definitions__016:
+ canonical: ""
+ static: ""
+ wysiwyg: |-
+ <pre>[foo]: /url</pre>
+04_07_00__leaf_blocks__link_reference_definitions__017:
+ canonical: |
+ <p>bar</p>
+ static: |-
+ <p data-sourcepos="1:1-4:3" dir="auto">bar</p>
+ wysiwyg: |-
+ <pre>[foo]: /url</pre>
+ <p>bar</p>
+04_07_00__leaf_blocks__link_reference_definitions__018:
+ canonical: |
+ <p>[foo]: /url &quot;title&quot; ok</p>
+ static: |-
+ <p data-sourcepos="1:1-1:22" dir="auto">[foo]: /url "title" ok</p>
+ wysiwyg: |-
+ <p>[foo]: /url "title" ok</p>
+04_07_00__leaf_blocks__link_reference_definitions__019:
+ canonical: |
+ <p>&quot;title&quot; ok</p>
+ static: |-
+ <p data-sourcepos="1:1-2:10" dir="auto">"title" ok</p>
+ wysiwyg: |-
+ <pre>[foo]: /url</pre>
+ <p>"title" ok</p>
+04_07_00__leaf_blocks__link_reference_definitions__020:
+ canonical: |
+ <pre><code>[foo]: /url &quot;title&quot;
+ </code></pre>
+ <p>[foo]</p>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-2:0" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url "title"</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <p data-sourcepos="3:1-3:5" dir="auto">[foo]</p>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>[foo]: /url "title"</code></pre>
+ <p>[foo]</p>
+04_07_00__leaf_blocks__link_reference_definitions__021:
+ canonical: |
+ <pre><code>[foo]: /url
+ </code></pre>
+ <p>[foo]</p>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-3:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <p data-sourcepos="5:1-5:5" dir="auto">[foo]</p>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>[foo]: /url</code></pre>
+ <p>[foo]</p>
+04_07_00__leaf_blocks__link_reference_definitions__022:
+ canonical: |
+ <p>Foo
+ [bar]: /baz</p>
+ <p>[bar]</p>
+ static: |-
+ <p data-sourcepos="1:1-2:11" dir="auto">Foo
+ [bar]: /baz</p>
+ <p data-sourcepos="4:1-4:5" dir="auto">[bar]</p>
+ wysiwyg: |-
+ <p>Foo
+ [bar]: /baz</p>
+ <p>[bar]</p>
+04_07_00__leaf_blocks__link_reference_definitions__023:
+ canonical: |
+ <h1><a href="/url">Foo</a></h1>
+ <blockquote>
+ <p>bar</p>
+ </blockquote>
+ static: |-
+ <h1 data-sourcepos="1:1-1:7" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a><a href="/url">Foo</a>
+ </h1>
+ <blockquote data-sourcepos="3:1-3:5" dir="auto">
+ <p data-sourcepos="3:3-3:5">bar</p>
+ </blockquote>
+ wysiwyg: |-
+ <h1><a target="_blank" rel="noopener noreferrer nofollow" href="/url">Foo</a></h1>
+ <pre>[foo]: /url</pre>
+ <blockquote multiline="false"><p>bar</p></blockquote>
+04_07_00__leaf_blocks__link_reference_definitions__024:
+ canonical: |
+ <h1>bar</h1>
+ <p><a href="/url">foo</a></p>
+ static: |-
+ <h1 data-sourcepos="1:1-4:5" dir="auto">
+ <a id="user-content-bar" class="anchor" href="#bar" aria-hidden="true"></a>bar</h1>
+ <p data-sourcepos="4:1-4:5" dir="auto"><a href="/url">foo</a></p>
+ wysiwyg: |-
+ <pre>[foo]: /url</pre>
+ <h1>bar</h1>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url">foo</a></p>
+04_07_00__leaf_blocks__link_reference_definitions__025:
+ canonical: |
+ <p>===
+ <a href="/url">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-3:5" dir="auto">===
+ <a href="/url">foo</a></p>
+ wysiwyg: |-
+ <pre>[foo]: /url</pre>
+ <p>===
+ <a target="_blank" rel="noopener noreferrer nofollow" href="/url">foo</a></p>
+04_07_00__leaf_blocks__link_reference_definitions__026:
+ canonical: |
+ <p><a href="/foo-url" title="foo">foo</a>,
+ <a href="/bar-url" title="bar">bar</a>,
+ <a href="/baz-url">baz</a></p>
+ static: |-
+ <p data-sourcepos="6:1-8:5" dir="auto"><a href="/foo-url" title="foo">foo</a>,
+ <a href="/bar-url" title="bar">bar</a>,
+ <a href="/baz-url">baz</a></p>
+ wysiwyg: |-
+ <pre>[foo]: /foo-url "foo"</pre>
+ <pre>[bar]: /bar-url "bar"</pre>
+ <pre>[baz]: /baz-url</pre>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/foo-url" title="foo">foo</a>,
+ <a target="_blank" rel="noopener noreferrer nofollow" href="/bar-url" title="bar">bar</a>,
+ <a target="_blank" rel="noopener noreferrer nofollow" href="/baz-url">baz</a></p>
+04_07_00__leaf_blocks__link_reference_definitions__027:
+ canonical: |
+ <p><a href="/url">foo</a></p>
+ <blockquote>
+ </blockquote>
+ static: |-
+ <p data-sourcepos="1:1-1:5" dir="auto"><a href="/url">foo</a></p>
+ <blockquote data-sourcepos="3:1-3:13" dir="auto">
+ </blockquote>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url">foo</a></p>
+ <blockquote multiline="false"><pre>[foo]: /url</pre></blockquote>
+04_07_00__leaf_blocks__link_reference_definitions__028:
+ canonical: ""
+ static: ""
+ wysiwyg: |-
+ <pre>[foo]: /url</pre>
+04_08_00__leaf_blocks__paragraphs__001:
+ canonical: |
+ <p>aaa</p>
+ <p>bbb</p>
+ static: |-
+ <p data-sourcepos="1:1-1:3" dir="auto">aaa</p>
+ <p data-sourcepos="3:1-3:3" dir="auto">bbb</p>
+ wysiwyg: |-
+ <p>aaa</p>
+ <p>bbb</p>
+04_08_00__leaf_blocks__paragraphs__002:
+ canonical: |
+ <p>aaa
+ bbb</p>
+ <p>ccc
+ ddd</p>
+ static: |-
+ <p data-sourcepos="1:1-2:3" dir="auto">aaa
+ bbb</p>
+ <p data-sourcepos="4:1-5:3" dir="auto">ccc
+ ddd</p>
+ wysiwyg: |-
+ <p>aaa
+ bbb</p>
+ <p>ccc
+ ddd</p>
+04_08_00__leaf_blocks__paragraphs__003:
+ canonical: |
+ <p>aaa</p>
+ <p>bbb</p>
+ static: |-
+ <p data-sourcepos="1:1-1:3" dir="auto">aaa</p>
+ <p data-sourcepos="4:1-4:3" dir="auto">bbb</p>
+ wysiwyg: |-
+ <p>aaa</p>
+ <p>bbb</p>
+04_08_00__leaf_blocks__paragraphs__004:
+ canonical: |
+ <p>aaa
+ bbb</p>
+ static: |-
+ <p data-sourcepos="1:3-2:4" dir="auto">aaa
+ bbb</p>
+ wysiwyg: |-
+ <p>aaa
+ bbb</p>
+04_08_00__leaf_blocks__paragraphs__005:
+ canonical: |
+ <p>aaa
+ bbb
+ ccc</p>
+ static: |-
+ <p data-sourcepos="1:1-3:42" dir="auto">aaa
+ bbb
+ ccc</p>
+ wysiwyg: |-
+ <p>aaa
+ bbb
+ ccc</p>
+04_08_00__leaf_blocks__paragraphs__006:
+ canonical: |
+ <p>aaa
+ bbb</p>
+ static: |-
+ <p data-sourcepos="1:4-2:3" dir="auto">aaa
+ bbb</p>
+ wysiwyg: |-
+ <p>aaa
+ bbb</p>
+04_08_00__leaf_blocks__paragraphs__007:
+ canonical: |
+ <pre><code>aaa
+ </code></pre>
+ <p>bbb</p>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-1:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <p data-sourcepos="2:1-2:3" dir="auto">bbb</p>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>aaa</code></pre>
+ <p>bbb</p>
+04_08_00__leaf_blocks__paragraphs__008:
+ canonical: |
+ <p>aaa<br />
+ bbb</p>
+ static: |-
+ <p data-sourcepos="1:1-2:8" dir="auto">aaa<br>
+ bbb</p>
+ wysiwyg: |-
+ <p>aaa<br>
+ bbb</p>
+04_09_00__leaf_blocks__blank_lines__001:
+ canonical: |
+ <p>aaa</p>
+ <h1>aaa</h1>
+ static: |-
+ <p data-sourcepos="3:1-3:3" dir="auto">aaa</p>
+ <h1 data-sourcepos="6:1-6:5" dir="auto">
+ <a id="user-content-aaa" class="anchor" href="#aaa" aria-hidden="true"></a>aaa</h1>
+ wysiwyg: |-
+ <p>aaa</p>
+ <h1>aaa</h1>
+04_10_00__leaf_blocks__tables_extension__001:
+ canonical: |
+ <table>
+ <thead>
+ <tr>
+ <th>foo</th>
+ <th>bar</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>baz</td>
+ <td>bim</td>
+ </tr>
+ </tbody>
+ </table>
+ static: |-
+ <table data-sourcepos="1:1-3:13" dir="auto">
+ <thead>
+ <tr data-sourcepos="1:1-1:13">
+ <th data-sourcepos="1:2-1:6">foo</th>
+ <th data-sourcepos="1:8-1:12">bar</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr data-sourcepos="3:1-3:13">
+ <td data-sourcepos="3:2-3:6">baz</td>
+ <td data-sourcepos="3:8-3:12">bim</td>
+ </tr>
+ </tbody>
+ </table>
+ wysiwyg: |-
+ <table><tbody><tr><th colspan="1" rowspan="1"><p>foo</p></th><th colspan="1" rowspan="1"><p>bar</p></th></tr><tr><td colspan="1" rowspan="1"><p>baz</p></td><td colspan="1" rowspan="1"><p>bim</p></td></tr></tbody></table>
+04_10_00__leaf_blocks__tables_extension__002:
+ canonical: |
+ <table>
+ <thead>
+ <tr>
+ <th align="center">abc</th>
+ <th align="right">defghi</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td align="center">bar</td>
+ <td align="right">baz</td>
+ </tr>
+ </tbody>
+ </table>
+ static: |-
+ <table data-sourcepos="1:1-3:9" dir="auto">
+ <thead>
+ <tr data-sourcepos="1:1-1:16">
+ <th align="center" data-sourcepos="1:2-1:6">abc</th>
+ <th align="right" data-sourcepos="1:8-1:15">defghi</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr data-sourcepos="3:1-3:9">
+ <td align="center" data-sourcepos="3:1-3:4">bar</td>
+ <td align="right" data-sourcepos="3:6-3:9">baz</td>
+ </tr>
+ </tbody>
+ </table>
+ wysiwyg: |-
+ <table><tbody><tr><th colspan="1" rowspan="1"><p>abc</p></th><th colspan="1" rowspan="1"><p>defghi</p></th></tr><tr><td colspan="1" rowspan="1"><p>bar</p></td><td colspan="1" rowspan="1"><p>baz</p></td></tr></tbody></table>
+04_10_00__leaf_blocks__tables_extension__003:
+ canonical: |
+ <table>
+ <thead>
+ <tr>
+ <th>f|oo</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>b <code>|</code> az</td>
+ </tr>
+ <tr>
+ <td>b <strong>|</strong> im</td>
+ </tr>
+ </tbody>
+ </table>
+ static: |-
+ <table data-sourcepos="1:1-4:15" dir="auto">
+ <thead>
+ <tr data-sourcepos="1:1-1:10">
+ <th data-sourcepos="1:2-1:9">f|oo</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr data-sourcepos="3:1-3:13">
+ <td data-sourcepos="3:2-3:12">b <code>|</code> az</td>
+ </tr>
+ <tr data-sourcepos="4:1-4:15">
+ <td data-sourcepos="4:2-4:14">b <strong>|</strong> im</td>
+ </tr>
+ </tbody>
+ </table>
+ wysiwyg: |-
+ <table><tbody><tr><th colspan="1" rowspan="1"><p>f|oo</p></th></tr><tr><td colspan="1" rowspan="1"><p>b <code>|</code> az</p></td></tr><tr><td colspan="1" rowspan="1"><p>b <strong>|</strong> im</p></td></tr></tbody></table>
+04_10_00__leaf_blocks__tables_extension__004:
+ canonical: |
+ <table>
+ <thead>
+ <tr>
+ <th>abc</th>
+ <th>def</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>bar</td>
+ <td>baz</td>
+ </tr>
+ </tbody>
+ </table>
+ <blockquote>
+ <p>bar</p>
+ </blockquote>
+ static: |-
+ <table data-sourcepos="1:1-3:13" dir="auto">
+ <thead>
+ <tr data-sourcepos="1:1-1:13">
+ <th data-sourcepos="1:2-1:6">abc</th>
+ <th data-sourcepos="1:8-1:12">def</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr data-sourcepos="3:1-3:13">
+ <td data-sourcepos="3:2-3:6">bar</td>
+ <td data-sourcepos="3:8-3:12">baz</td>
+ </tr>
+ </tbody>
+ </table>
+ <blockquote data-sourcepos="4:1-4:5" dir="auto">
+ <p data-sourcepos="4:3-4:5">bar</p>
+ </blockquote>
+ wysiwyg: |-
+ <table><tbody><tr><th colspan="1" rowspan="1"><p>abc</p></th><th colspan="1" rowspan="1"><p>def</p></th></tr><tr><td colspan="1" rowspan="1"><p>bar</p></td><td colspan="1" rowspan="1"><p>baz</p></td></tr></tbody></table>
+ <blockquote multiline="false"><p>bar</p></blockquote>
+04_10_00__leaf_blocks__tables_extension__005:
+ canonical: |
+ <table>
+ <thead>
+ <tr>
+ <th>abc</th>
+ <th>def</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>bar</td>
+ <td>baz</td>
+ </tr>
+ <tr>
+ <td>bar</td>
+ <td></td>
+ </tr>
+ </tbody>
+ </table>
+ <p>bar</p>
+ static: |-
+ <table data-sourcepos="1:1-4:3" dir="auto">
+ <thead>
+ <tr data-sourcepos="1:1-1:13">
+ <th data-sourcepos="1:2-1:6">abc</th>
+ <th data-sourcepos="1:8-1:12">def</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr data-sourcepos="3:1-3:13">
+ <td data-sourcepos="3:2-3:6">bar</td>
+ <td data-sourcepos="3:8-3:12">baz</td>
+ </tr>
+ <tr data-sourcepos="4:1-4:3">
+ <td data-sourcepos="4:1-4:3">bar</td>
+ <td data-sourcepos="4:0-4:0"></td>
+ </tr>
+ </tbody>
+ </table>
+ <p data-sourcepos="6:1-6:3" dir="auto">bar</p>
+ wysiwyg: |-
+ <table><tbody><tr><th colspan="1" rowspan="1"><p>abc</p></th><th colspan="1" rowspan="1"><p>def</p></th></tr><tr><td colspan="1" rowspan="1"><p>bar</p></td><td colspan="1" rowspan="1"><p>baz</p></td></tr><tr><td colspan="1" rowspan="1"><p>bar</p></td><td colspan="1" rowspan="1"><p></p></td></tr></tbody></table>
+ <p>bar</p>
+04_10_00__leaf_blocks__tables_extension__006:
+ canonical: |
+ <p>| abc | def |
+ | --- |
+ | bar |</p>
+ static: |-
+ <p data-sourcepos="1:1-3:7" dir="auto">| abc | def |
+ | --- |
+ | bar |</p>
+ wysiwyg: |-
+ <p>| abc | def |
+ | --- |
+ | bar |</p>
+04_10_00__leaf_blocks__tables_extension__007:
+ canonical: |
+ <table>
+ <thead>
+ <tr>
+ <th>abc</th>
+ <th>def</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>bar</td>
+ <td></td>
+ </tr>
+ <tr>
+ <td>bar</td>
+ <td>baz</td>
+ </tr>
+ </tbody>
+ </table>
+ static: |-
+ <table data-sourcepos="1:1-4:19" dir="auto">
+ <thead>
+ <tr data-sourcepos="1:1-1:13">
+ <th data-sourcepos="1:2-1:6">abc</th>
+ <th data-sourcepos="1:8-1:12">def</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr data-sourcepos="3:1-3:7">
+ <td data-sourcepos="3:2-3:6">bar</td>
+ <td data-sourcepos="3:0-3:0"></td>
+ </tr>
+ <tr data-sourcepos="4:1-4:19">
+ <td data-sourcepos="4:2-4:6">bar</td>
+ <td data-sourcepos="4:8-4:12">baz</td>
+ </tr>
+ </tbody>
+ </table>
+ wysiwyg: |-
+ <table><tbody><tr><th colspan="1" rowspan="1"><p>abc</p></th><th colspan="1" rowspan="1"><p>def</p></th></tr><tr><td colspan="1" rowspan="1"><p>bar</p></td><td colspan="1" rowspan="1"><p></p></td></tr><tr><td colspan="1" rowspan="1"><p>bar</p></td><td colspan="1" rowspan="1"><p>baz</p></td></tr></tbody></table>
+04_10_00__leaf_blocks__tables_extension__008:
+ canonical: |
+ <table>
+ <thead>
+ <tr>
+ <th>abc</th>
+ <th>def</th>
+ </tr>
+ </thead>
+ </table>
+ static: |-
+ <table data-sourcepos="1:1-2:13" dir="auto">
+ <thead>
+ <tr data-sourcepos="1:1-1:13">
+ <th data-sourcepos="1:2-1:6">abc</th>
+ <th data-sourcepos="1:8-1:12">def</th>
+ </tr>
+ </thead>
+ </table>
+ wysiwyg: |-
+ <table><tbody><tr><th colspan="1" rowspan="1"><p>abc</p></th><th colspan="1" rowspan="1"><p>def</p></th></tr></tbody></table>
+05_01_00__container_blocks__block_quotes__001:
+ canonical: |
+ <blockquote>
+ <h1>Foo</h1>
+ <p>bar
+ baz</p>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-3:5" dir="auto">
+ <h1 data-sourcepos="1:3-1:7">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h1>
+ <p data-sourcepos="2:3-3:5">bar
+ baz</p>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><h1>Foo</h1><p>bar
+ baz</p></blockquote>
+05_01_00__container_blocks__block_quotes__002:
+ canonical: |
+ <blockquote>
+ <h1>Foo</h1>
+ <p>bar
+ baz</p>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-3:5" dir="auto">
+ <h1 data-sourcepos="1:2-1:6">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h1>
+ <p data-sourcepos="2:2-3:5">bar
+ baz</p>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><h1>Foo</h1><p>bar
+ baz</p></blockquote>
+05_01_00__container_blocks__block_quotes__003:
+ canonical: |
+ <blockquote>
+ <h1>Foo</h1>
+ <p>bar
+ baz</p>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:4-3:6" dir="auto">
+ <h1 data-sourcepos="1:6-1:10">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h1>
+ <p data-sourcepos="2:6-3:6">bar
+ baz</p>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><h1>Foo</h1><p>bar
+ baz</p></blockquote>
+05_01_00__container_blocks__block_quotes__004:
+ canonical: |
+ <pre><code>&gt; # Foo
+ &gt; bar
+ &gt; baz
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-3:9" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; # Foo</span>
+ <span id="LC2" class="line" lang="plaintext">&gt; bar</span>
+ <span id="LC3" class="line" lang="plaintext">&gt; baz</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>&gt; # Foo
+ &gt; bar
+ &gt; baz</code></pre>
+05_01_00__container_blocks__block_quotes__005:
+ canonical: |
+ <blockquote>
+ <h1>Foo</h1>
+ <p>bar
+ baz</p>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-3:3" dir="auto">
+ <h1 data-sourcepos="1:3-1:7">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h1>
+ <p data-sourcepos="2:3-3:3">bar
+ baz</p>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><h1>Foo</h1><p>bar
+ baz</p></blockquote>
+05_01_00__container_blocks__block_quotes__006:
+ canonical: |
+ <blockquote>
+ <p>bar
+ baz
+ foo</p>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-3:5" dir="auto">
+ <p data-sourcepos="1:3-3:5">bar
+ baz
+ foo</p>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><p>bar
+ baz
+ foo</p></blockquote>
+05_01_00__container_blocks__block_quotes__007:
+ canonical: |
+ <blockquote>
+ <p>foo</p>
+ </blockquote>
+ <hr />
+ static: |-
+ <blockquote data-sourcepos="1:1-1:5" dir="auto">
+ <p data-sourcepos="1:3-1:5">foo</p>
+ </blockquote>
+ <hr data-sourcepos="2:1-2:3">
+ wysiwyg: |-
+ <blockquote multiline="false"><p>foo</p></blockquote>
+ <hr>
+05_01_00__container_blocks__block_quotes__008:
+ canonical: |
+ <blockquote>
+ <ul>
+ <li>foo</li>
+ </ul>
+ </blockquote>
+ <ul>
+ <li>bar</li>
+ </ul>
+ static: |-
+ <blockquote data-sourcepos="1:1-1:7" dir="auto">
+ <ul data-sourcepos="1:3-1:7">
+ <li data-sourcepos="1:3-1:7">foo</li>
+ </ul>
+ </blockquote>
+ <ul data-sourcepos="2:1-2:5" dir="auto">
+ <li data-sourcepos="2:1-2:5">bar</li>
+ </ul>
+ wysiwyg: |-
+ <blockquote multiline="false"><ul bullet="*"><li><p>foo</p></li></ul></blockquote>
+ <ul bullet="*"><li><p>bar</p></li></ul>
+05_01_00__container_blocks__block_quotes__009:
+ canonical: |
+ <blockquote>
+ <pre><code>foo
+ </code></pre>
+ </blockquote>
+ <pre><code>bar
+ </code></pre>
+ static: |-
+ <blockquote data-sourcepos="1:1-1:9" dir="auto">
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:7-1:9" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </blockquote>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="2:5-2:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <blockquote multiline="false"><pre class="content-editor-code-block undefined code highlight"><code>foo</code></pre></blockquote>
+ <pre class="content-editor-code-block undefined code highlight"><code>bar</code></pre>
+05_01_00__container_blocks__block_quotes__010:
+ canonical: |
+ <blockquote>
+ <pre><code></code></pre>
+ </blockquote>
+ <p>foo</p>
+ <pre><code></code></pre>
+ static: |-
+ <blockquote data-sourcepos="1:1-1:5" dir="auto">
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:3-2:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </blockquote>
+ <p data-sourcepos="2:1-2:3" dir="auto">foo</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="3:1-3:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <blockquote multiline="false"><pre class="content-editor-code-block undefined code highlight"><code></code></pre></blockquote>
+ <p>foo</p>
+ <pre class="content-editor-code-block undefined code highlight"><code></code></pre>
+05_01_00__container_blocks__block_quotes__011:
+ canonical: |
+ <blockquote>
+ <p>foo
+ - bar</p>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-2:9" dir="auto">
+ <p data-sourcepos="1:3-2:9">foo
+ - bar</p>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><p>foo
+ - bar</p></blockquote>
+05_01_00__container_blocks__block_quotes__012:
+ canonical: |
+ <blockquote>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-1:1" dir="auto">
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><p></p></blockquote>
+05_01_00__container_blocks__block_quotes__013:
+ canonical: |
+ <blockquote>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-3:2" dir="auto">
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><p></p></blockquote>
+05_01_00__container_blocks__block_quotes__014:
+ canonical: |
+ <blockquote>
+ <p>foo</p>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-3:3" dir="auto">
+ <p data-sourcepos="2:3-2:5">foo</p>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><p>foo</p></blockquote>
+05_01_00__container_blocks__block_quotes__015:
+ canonical: |
+ <blockquote>
+ <p>foo</p>
+ </blockquote>
+ <blockquote>
+ <p>bar</p>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-1:5" dir="auto">
+ <p data-sourcepos="1:3-1:5">foo</p>
+ </blockquote>
+ <blockquote data-sourcepos="3:1-3:5" dir="auto">
+ <p data-sourcepos="3:3-3:5">bar</p>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><p>foo</p></blockquote>
+ <blockquote multiline="false"><p>bar</p></blockquote>
+05_01_00__container_blocks__block_quotes__016:
+ canonical: |
+ <blockquote>
+ <p>foo
+ bar</p>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-2:5" dir="auto">
+ <p data-sourcepos="1:3-2:5">foo
+ bar</p>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><p>foo
+ bar</p></blockquote>
+05_01_00__container_blocks__block_quotes__017:
+ canonical: |
+ <blockquote>
+ <p>foo</p>
+ <p>bar</p>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-3:5" dir="auto">
+ <p data-sourcepos="1:3-1:5">foo</p>
+ <p data-sourcepos="3:3-3:5">bar</p>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><p>foo</p><p>bar</p></blockquote>
+05_01_00__container_blocks__block_quotes__018:
+ canonical: |
+ <p>foo</p>
+ <blockquote>
+ <p>bar</p>
+ </blockquote>
+ static: |-
+ <p data-sourcepos="1:1-1:3" dir="auto">foo</p>
+ <blockquote data-sourcepos="2:1-2:5" dir="auto">
+ <p data-sourcepos="2:3-2:5">bar</p>
+ </blockquote>
+ wysiwyg: |-
+ <p>foo</p>
+ <blockquote multiline="false"><p>bar</p></blockquote>
+05_01_00__container_blocks__block_quotes__019:
+ canonical: |
+ <blockquote>
+ <p>aaa</p>
+ </blockquote>
+ <hr />
+ <blockquote>
+ <p>bbb</p>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-1:5" dir="auto">
+ <p data-sourcepos="1:3-1:5">aaa</p>
+ </blockquote>
+ <hr data-sourcepos="2:1-2:3">
+ <blockquote data-sourcepos="3:1-3:5" dir="auto">
+ <p data-sourcepos="3:3-3:5">bbb</p>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><p>aaa</p></blockquote>
+ <hr>
+ <blockquote multiline="false"><p>bbb</p></blockquote>
+05_01_00__container_blocks__block_quotes__020:
+ canonical: |
+ <blockquote>
+ <p>bar
+ baz</p>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-2:3" dir="auto">
+ <p data-sourcepos="1:3-2:3">bar
+ baz</p>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><p>bar
+ baz</p></blockquote>
+05_01_00__container_blocks__block_quotes__021:
+ canonical: |
+ <blockquote>
+ <p>bar</p>
+ </blockquote>
+ <p>baz</p>
+ static: |-
+ <blockquote data-sourcepos="1:1-1:5" dir="auto">
+ <p data-sourcepos="1:3-1:5">bar</p>
+ </blockquote>
+ <p data-sourcepos="3:1-3:3" dir="auto">baz</p>
+ wysiwyg: |-
+ <blockquote multiline="false"><p>bar</p></blockquote>
+ <p>baz</p>
+05_01_00__container_blocks__block_quotes__022:
+ canonical: |
+ <blockquote>
+ <p>bar</p>
+ </blockquote>
+ <p>baz</p>
+ static: |-
+ <blockquote data-sourcepos="1:1-2:1" dir="auto">
+ <p data-sourcepos="1:3-1:5">bar</p>
+ </blockquote>
+ <p data-sourcepos="3:1-3:3" dir="auto">baz</p>
+ wysiwyg: |-
+ <blockquote multiline="false"><p>bar</p></blockquote>
+ <p>baz</p>
+05_01_00__container_blocks__block_quotes__023:
+ canonical: |
+ <blockquote>
+ <blockquote>
+ <blockquote>
+ <p>foo
+ bar</p>
+ </blockquote>
+ </blockquote>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-2:3" dir="auto">
+ <blockquote data-sourcepos="1:3-2:3">
+ <blockquote data-sourcepos="1:5-2:3">
+ <p data-sourcepos="1:7-2:3">foo
+ bar</p>
+ </blockquote>
+ </blockquote>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><blockquote multiline="false"><blockquote multiline="false"><p>foo
+ bar</p></blockquote></blockquote></blockquote>
+05_01_00__container_blocks__block_quotes__024:
+ canonical: |
+ <blockquote>
+ <blockquote>
+ <blockquote>
+ <p>foo
+ bar
+ baz</p>
+ </blockquote>
+ </blockquote>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-3:5" dir="auto">
+ <blockquote data-sourcepos="1:2-3:5">
+ <blockquote data-sourcepos="1:3-3:5">
+ <p data-sourcepos="1:5-3:5">foo
+ bar
+ baz</p>
+ </blockquote>
+ </blockquote>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><blockquote multiline="false"><blockquote multiline="false"><p>foo
+ bar
+ baz</p></blockquote></blockquote></blockquote>
+05_01_00__container_blocks__block_quotes__025:
+ canonical: |
+ <blockquote>
+ <pre><code>code
+ </code></pre>
+ </blockquote>
+ <blockquote>
+ <p>not code</p>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-1:10" dir="auto">
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:7-1:10" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">code</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </blockquote>
+ <blockquote data-sourcepos="3:1-3:13" dir="auto">
+ <p data-sourcepos="3:6-3:13">not code</p>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><pre class="content-editor-code-block undefined code highlight"><code>code</code></pre></blockquote>
+ <blockquote multiline="false"><p>not code</p></blockquote>
+05_02_00__container_blocks__list_items__001:
+ canonical: |
+ <p>A paragraph
+ with two lines.</p>
+ <pre><code>indented code
+ </code></pre>
+ <blockquote>
+ <p>A block quote.</p>
+ </blockquote>
+ static: |-
+ <p data-sourcepos="1:1-2:15" dir="auto">A paragraph
+ with two lines.</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="4:5-5:0" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <blockquote data-sourcepos="6:1-6:16" dir="auto">
+ <p data-sourcepos="6:3-6:16">A block quote.</p>
+ </blockquote>
+ wysiwyg: |-
+ <p>A paragraph
+ with two lines.</p>
+ <pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre>
+ <blockquote multiline="false"><p>A block quote.</p></blockquote>
+05_02_00__container_blocks__list_items__002:
+ canonical: |
+ <ol>
+ <li>
+ <p>A paragraph
+ with two lines.</p>
+ <pre><code>indented code
+ </code></pre>
+ <blockquote>
+ <p>A block quote.</p>
+ </blockquote>
+ </li>
+ </ol>
+ static: |-
+ <ol data-sourcepos="1:1-6:20" dir="auto">
+ <li data-sourcepos="1:1-6:20">
+ <p data-sourcepos="1:5-2:19">A paragraph
+ with two lines.</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="4:9-5:0" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <blockquote data-sourcepos="6:5-6:20">
+ <p data-sourcepos="6:7-6:20">A block quote.</p>
+ </blockquote>
+ </li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>A paragraph
+ with two lines.</p><pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre><blockquote multiline="false"><p>A block quote.</p></blockquote></li></ol>
+05_02_00__container_blocks__list_items__003:
+ canonical: |
+ <ul>
+ <li>one</li>
+ </ul>
+ <p>two</p>
+ static: |-
+ <ul data-sourcepos="1:1-2:0" dir="auto">
+ <li data-sourcepos="1:1-2:0">one</li>
+ </ul>
+ <p data-sourcepos="3:2-3:4" dir="auto">two</p>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>one</p></li></ul>
+ <p>two</p>
+05_02_00__container_blocks__list_items__004:
+ canonical: |
+ <ul>
+ <li>
+ <p>one</p>
+ <p>two</p>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-3:5" dir="auto">
+ <li data-sourcepos="1:1-3:5">
+ <p data-sourcepos="1:3-1:5">one</p>
+ <p data-sourcepos="3:3-3:5">two</p>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>one</p><p>two</p></li></ul>
+05_02_00__container_blocks__list_items__005:
+ canonical: |
+ <ul>
+ <li>one</li>
+ </ul>
+ <pre><code> two
+ </code></pre>
+ static: |-
+ <ul data-sourcepos="1:2-2:0" dir="auto">
+ <li data-sourcepos="1:2-2:0">one</li>
+ </ul>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="3:5-3:8" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> two</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>one</p></li></ul>
+ <pre class="content-editor-code-block undefined code highlight"><code> two</code></pre>
+05_02_00__container_blocks__list_items__006:
+ canonical: |
+ <ul>
+ <li>
+ <p>one</p>
+ <p>two</p>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:2-3:9" dir="auto">
+ <li data-sourcepos="1:2-3:9">
+ <p data-sourcepos="1:7-1:9">one</p>
+ <p data-sourcepos="3:7-3:9">two</p>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>one</p><p>two</p></li></ul>
+05_02_00__container_blocks__list_items__007:
+ canonical: |
+ <blockquote>
+ <blockquote>
+ <ol>
+ <li>
+ <p>one</p>
+ <p>two</p>
+ </li>
+ </ol>
+ </blockquote>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:4-3:10" dir="auto">
+ <blockquote data-sourcepos="1:6-3:10">
+ <ol data-sourcepos="1:8-3:10">
+ <li data-sourcepos="1:8-3:10">
+ <p data-sourcepos="1:12-1:14">one</p>
+ <p data-sourcepos="3:8-3:10">two</p>
+ </li>
+ </ol>
+ </blockquote>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><blockquote multiline="false"><ol parens="false"><li><p>one</p><p>two</p></li></ol></blockquote></blockquote>
+05_02_00__container_blocks__list_items__008:
+ canonical: |
+ <blockquote>
+ <blockquote>
+ <ul>
+ <li>one</li>
+ </ul>
+ <p>two</p>
+ </blockquote>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-3:10" dir="auto">
+ <blockquote data-sourcepos="1:2-3:10">
+ <ul data-sourcepos="1:3-2:2">
+ <li data-sourcepos="1:3-2:2">one</li>
+ </ul>
+ <p data-sourcepos="3:8-3:10">two</p>
+ </blockquote>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><blockquote multiline="false"><ul bullet="*"><li><p>one</p></li></ul><p>two</p></blockquote></blockquote>
+05_02_00__container_blocks__list_items__009:
+ canonical: |
+ <p>-one</p>
+ <p>2.two</p>
+ static: |-
+ <p data-sourcepos="1:1-1:4" dir="auto">-one</p>
+ <p data-sourcepos="3:1-3:5" dir="auto">2.two</p>
+ wysiwyg: |-
+ <p>-one</p>
+ <p>2.two</p>
+05_02_00__container_blocks__list_items__010:
+ canonical: |
+ <ul>
+ <li>
+ <p>foo</p>
+ <p>bar</p>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-4:5" dir="auto">
+ <li data-sourcepos="1:1-4:5">
+ <p data-sourcepos="1:3-1:5">foo</p>
+ <p data-sourcepos="4:3-4:5">bar</p>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p><p>bar</p></li></ul>
+05_02_00__container_blocks__list_items__011:
+ canonical: |
+ <ol>
+ <li>
+ <p>foo</p>
+ <pre><code>bar
+ </code></pre>
+ <p>baz</p>
+ <blockquote>
+ <p>bam</p>
+ </blockquote>
+ </li>
+ </ol>
+ static: |-
+ <ol data-sourcepos="1:1-9:9" dir="auto">
+ <li data-sourcepos="1:1-9:9">
+ <p data-sourcepos="1:5-1:7">foo</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="3:5-5:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <p data-sourcepos="7:5-7:7">baz</p>
+ <blockquote data-sourcepos="9:5-9:9">
+ <p data-sourcepos="9:7-9:9">bam</p>
+ </blockquote>
+ </li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>foo</p><pre class="content-editor-code-block undefined code highlight"><code>bar</code></pre><p>baz</p><blockquote multiline="false"><p>bam</p></blockquote></li></ol>
+05_02_00__container_blocks__list_items__012:
+ canonical: |
+ <ul>
+ <li>
+ <p>Foo</p>
+ <pre><code>bar
+
+
+ baz
+ </code></pre>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-6:9" dir="auto">
+ <li data-sourcepos="1:1-6:9">
+ <p data-sourcepos="1:3-1:5">Foo</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="3:7-6:9" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span>
+ <span id="LC2" class="line" lang="plaintext"></span>
+ <span id="LC3" class="line" lang="plaintext"></span>
+ <span id="LC4" class="line" lang="plaintext">baz</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>Foo</p><pre class="content-editor-code-block undefined code highlight"><code>bar
+
+
+ baz</code></pre></li></ul>
+05_02_00__container_blocks__list_items__013:
+ canonical: |
+ <ol start="123456789">
+ <li>ok</li>
+ </ol>
+ static: |-
+ <ol start="123456789" data-sourcepos="1:1-1:13" dir="auto">
+ <li data-sourcepos="1:1-1:13">ok</li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>ok</p></li></ol>
+05_02_00__container_blocks__list_items__014:
+ canonical: |
+ <p>1234567890. not ok</p>
+ static: |-
+ <p data-sourcepos="1:1-1:18" dir="auto">1234567890. not ok</p>
+ wysiwyg: |-
+ <p>1234567890. not ok</p>
+05_02_00__container_blocks__list_items__015:
+ canonical: |
+ <ol start="0">
+ <li>ok</li>
+ </ol>
+ static: |-
+ <ol start="0" data-sourcepos="1:1-1:5" dir="auto">
+ <li data-sourcepos="1:1-1:5">ok</li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>ok</p></li></ol>
+05_02_00__container_blocks__list_items__016:
+ canonical: |
+ <ol start="3">
+ <li>ok</li>
+ </ol>
+ static: |-
+ <ol start="3" data-sourcepos="1:1-1:7" dir="auto">
+ <li data-sourcepos="1:1-1:7">ok</li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>ok</p></li></ol>
+05_02_00__container_blocks__list_items__017:
+ canonical: |
+ <p>-1. not ok</p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto">-1. not ok</p>
+ wysiwyg: |-
+ <p>-1. not ok</p>
+05_02_00__container_blocks__list_items__018:
+ canonical: |
+ <ul>
+ <li>
+ <p>foo</p>
+ <pre><code>bar
+ </code></pre>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-3:9" dir="auto">
+ <li data-sourcepos="1:1-3:9">
+ <p data-sourcepos="1:3-1:5">foo</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="3:7-3:9" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p><pre class="content-editor-code-block undefined code highlight"><code>bar</code></pre></li></ul>
+05_02_00__container_blocks__list_items__019:
+ canonical: |
+ <ol start="10">
+ <li>
+ <p>foo</p>
+ <pre><code>bar
+ </code></pre>
+ </li>
+ </ol>
+ static: |-
+ <ol start="10" data-sourcepos="1:3-3:14" dir="auto">
+ <li data-sourcepos="1:3-3:14">
+ <p data-sourcepos="1:8-1:10">foo</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="3:12-3:14" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>foo</p><pre class="content-editor-code-block undefined code highlight"><code>bar</code></pre></li></ol>
+05_02_00__container_blocks__list_items__020:
+ canonical: |
+ <pre><code>indented code
+ </code></pre>
+ <p>paragraph</p>
+ <pre><code>more code
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-2:0" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <p data-sourcepos="3:1-3:9" dir="auto">paragraph</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="5:5-5:13" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">more code</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre>
+ <p>paragraph</p>
+ <pre class="content-editor-code-block undefined code highlight"><code>more code</code></pre>
+05_02_00__container_blocks__list_items__021:
+ canonical: |
+ <ol>
+ <li>
+ <pre><code>indented code
+ </code></pre>
+ <p>paragraph</p>
+ <pre><code>more code
+ </code></pre>
+ </li>
+ </ol>
+ static: |-
+ <ol data-sourcepos="1:1-5:16" dir="auto">
+ <li data-sourcepos="1:1-5:16">
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:8-2:0" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <p data-sourcepos="3:4-3:12">paragraph</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="5:8-5:16" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">more code</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p></p><pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre><p>paragraph</p><pre class="content-editor-code-block undefined code highlight"><code>more code</code></pre></li></ol>
+05_02_00__container_blocks__list_items__022:
+ canonical: |
+ <ol>
+ <li>
+ <pre><code> indented code
+ </code></pre>
+ <p>paragraph</p>
+ <pre><code>more code
+ </code></pre>
+ </li>
+ </ol>
+ static: |-
+ <ol data-sourcepos="1:1-5:16" dir="auto">
+ <li data-sourcepos="1:1-5:16">
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:8-2:0" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> indented code</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <p data-sourcepos="3:4-3:12">paragraph</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="5:8-5:16" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">more code</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p></p><pre class="content-editor-code-block undefined code highlight"><code> indented code</code></pre><p>paragraph</p><pre class="content-editor-code-block undefined code highlight"><code>more code</code></pre></li></ol>
+05_02_00__container_blocks__list_items__023:
+ canonical: |
+ <p>foo</p>
+ <p>bar</p>
+ static: |-
+ <p data-sourcepos="1:4-1:6" dir="auto">foo</p>
+ <p data-sourcepos="3:1-3:3" dir="auto">bar</p>
+ wysiwyg: |-
+ <p>foo</p>
+ <p>bar</p>
+05_02_00__container_blocks__list_items__024:
+ canonical: |
+ <ul>
+ <li>foo</li>
+ </ul>
+ <p>bar</p>
+ static: |-
+ <ul data-sourcepos="1:1-2:0" dir="auto">
+ <li data-sourcepos="1:1-2:0">foo</li>
+ </ul>
+ <p data-sourcepos="3:3-3:5" dir="auto">bar</p>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p></li></ul>
+ <p>bar</p>
+05_02_00__container_blocks__list_items__025:
+ canonical: |
+ <ul>
+ <li>
+ <p>foo</p>
+ <p>bar</p>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-3:6" dir="auto">
+ <li data-sourcepos="1:1-3:6">
+ <p data-sourcepos="1:4-1:6">foo</p>
+ <p data-sourcepos="3:4-3:6">bar</p>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p><p>bar</p></li></ul>
+05_02_00__container_blocks__list_items__026:
+ canonical: |
+ <ul>
+ <li>foo</li>
+ <li>
+ <pre><code>bar
+ </code></pre>
+ </li>
+ <li>
+ <pre><code>baz
+ </code></pre>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-8:9" dir="auto">
+ <li data-sourcepos="1:1-2:5">foo</li>
+ <li data-sourcepos="3:1-6:5">
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="4:3-6:5" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">bar</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </li>
+ <li data-sourcepos="7:1-8:9">
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="8:7-8:9" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">baz</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p></li><li><p></p><pre class="content-editor-code-block undefined code highlight"><code>bar</code></pre></li><li><p></p><pre class="content-editor-code-block undefined code highlight"><code>baz</code></pre></li></ul>
+05_02_00__container_blocks__list_items__027:
+ canonical: |
+ <ul>
+ <li>foo</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-2:5" dir="auto">
+ <li data-sourcepos="1:1-2:5">foo</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p></li></ul>
+05_02_00__container_blocks__list_items__028:
+ canonical: |
+ <ul>
+ <li></li>
+ </ul>
+ <p>foo</p>
+ static: |-
+ <ul data-sourcepos="1:1-2:0" dir="auto">
+ <li data-sourcepos="1:1-1:1">
+ </li>
+ </ul>
+ <p data-sourcepos="3:3-3:5" dir="auto">foo</p>
+ wysiwyg: |-
+ <ul bullet="*"><li><p></p></li></ul>
+ <p>foo</p>
+05_02_00__container_blocks__list_items__029:
+ canonical: |
+ <ul>
+ <li>foo</li>
+ <li></li>
+ <li>bar</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-3:5" dir="auto">
+ <li data-sourcepos="1:1-1:5">foo</li>
+ <li data-sourcepos="2:1-2:1">
+ </li>
+ <li data-sourcepos="3:1-3:5">bar</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p></li><li><p></p></li><li><p>bar</p></li></ul>
+05_02_00__container_blocks__list_items__030:
+ canonical: |
+ <ul>
+ <li>foo</li>
+ <li></li>
+ <li>bar</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-3:5" dir="auto">
+ <li data-sourcepos="1:1-1:5">foo</li>
+ <li data-sourcepos="2:1-2:4">
+ </li>
+ <li data-sourcepos="3:1-3:5">bar</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p></li><li><p></p></li><li><p>bar</p></li></ul>
+05_02_00__container_blocks__list_items__031:
+ canonical: |
+ <ol>
+ <li>foo</li>
+ <li></li>
+ <li>bar</li>
+ </ol>
+ static: |-
+ <ol data-sourcepos="1:1-3:6" dir="auto">
+ <li data-sourcepos="1:1-1:6">foo</li>
+ <li data-sourcepos="2:1-2:2">
+ </li>
+ <li data-sourcepos="3:1-3:6">bar</li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>foo</p></li><li><p></p></li><li><p>bar</p></li></ol>
+05_02_00__container_blocks__list_items__032:
+ canonical: |
+ <ul>
+ <li></li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-1:1" dir="auto">
+ <li data-sourcepos="1:1-1:1">
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p></p></li></ul>
+05_02_00__container_blocks__list_items__033:
+ canonical: |
+ <p>foo
+ *</p>
+ <p>foo
+ 1.</p>
+ static: |-
+ <p data-sourcepos="1:1-2:1" dir="auto">foo
+ *</p>
+ <p data-sourcepos="4:1-5:2" dir="auto">foo
+ 1.</p>
+ wysiwyg: |-
+ <p>foo
+ *</p>
+ <p>foo
+ 1.</p>
+05_02_00__container_blocks__list_items__034:
+ canonical: |
+ <ol>
+ <li>
+ <p>A paragraph
+ with two lines.</p>
+ <pre><code>indented code
+ </code></pre>
+ <blockquote>
+ <p>A block quote.</p>
+ </blockquote>
+ </li>
+ </ol>
+ static: |-
+ <ol data-sourcepos="1:2-6:21" dir="auto">
+ <li data-sourcepos="1:2-6:21">
+ <p data-sourcepos="1:6-2:20">A paragraph
+ with two lines.</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="4:10-5:0" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <blockquote data-sourcepos="6:6-6:21">
+ <p data-sourcepos="6:8-6:21">A block quote.</p>
+ </blockquote>
+ </li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>A paragraph
+ with two lines.</p><pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre><blockquote multiline="false"><p>A block quote.</p></blockquote></li></ol>
+05_02_00__container_blocks__list_items__035:
+ canonical: |
+ <ol>
+ <li>
+ <p>A paragraph
+ with two lines.</p>
+ <pre><code>indented code
+ </code></pre>
+ <blockquote>
+ <p>A block quote.</p>
+ </blockquote>
+ </li>
+ </ol>
+ static: |-
+ <ol data-sourcepos="1:3-6:22" dir="auto">
+ <li data-sourcepos="1:3-6:22">
+ <p data-sourcepos="1:7-2:21">A paragraph
+ with two lines.</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="4:11-5:0" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <blockquote data-sourcepos="6:7-6:22">
+ <p data-sourcepos="6:9-6:22">A block quote.</p>
+ </blockquote>
+ </li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>A paragraph
+ with two lines.</p><pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre><blockquote multiline="false"><p>A block quote.</p></blockquote></li></ol>
+05_02_00__container_blocks__list_items__036:
+ canonical: |
+ <ol>
+ <li>
+ <p>A paragraph
+ with two lines.</p>
+ <pre><code>indented code
+ </code></pre>
+ <blockquote>
+ <p>A block quote.</p>
+ </blockquote>
+ </li>
+ </ol>
+ static: |-
+ <ol data-sourcepos="1:4-6:23" dir="auto">
+ <li data-sourcepos="1:4-6:23">
+ <p data-sourcepos="1:8-2:22">A paragraph
+ with two lines.</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="4:12-5:0" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <blockquote data-sourcepos="6:8-6:23">
+ <p data-sourcepos="6:10-6:23">A block quote.</p>
+ </blockquote>
+ </li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>A paragraph
+ with two lines.</p><pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre><blockquote multiline="false"><p>A block quote.</p></blockquote></li></ol>
+05_02_00__container_blocks__list_items__037:
+ canonical: |
+ <pre><code>1. A paragraph
+ with two lines.
+
+ indented code
+
+ &gt; A block quote.
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-6:24" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. A paragraph</span>
+ <span id="LC2" class="line" lang="plaintext"> with two lines.</span>
+ <span id="LC3" class="line" lang="plaintext"></span>
+ <span id="LC4" class="line" lang="plaintext"> indented code</span>
+ <span id="LC5" class="line" lang="plaintext"></span>
+ <span id="LC6" class="line" lang="plaintext"> &gt; A block quote.</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>1. A paragraph
+ with two lines.
+
+ indented code
+
+ &gt; A block quote.</code></pre>
+05_02_00__container_blocks__list_items__038:
+ canonical: |
+ <ol>
+ <li>
+ <p>A paragraph
+ with two lines.</p>
+ <pre><code>indented code
+ </code></pre>
+ <blockquote>
+ <p>A block quote.</p>
+ </blockquote>
+ </li>
+ </ol>
+ static: |-
+ <ol data-sourcepos="1:3-6:22" dir="auto">
+ <li data-sourcepos="1:3-6:22">
+ <p data-sourcepos="1:7-2:15">A paragraph
+ with two lines.</p>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="4:11-5:0" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">indented code</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <blockquote data-sourcepos="6:7-6:22">
+ <p data-sourcepos="6:9-6:22">A block quote.</p>
+ </blockquote>
+ </li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>A paragraph
+ with two lines.</p><pre class="content-editor-code-block undefined code highlight"><code>indented code</code></pre><blockquote multiline="false"><p>A block quote.</p></blockquote></li></ol>
+05_02_00__container_blocks__list_items__039:
+ canonical: |
+ <ol>
+ <li>A paragraph
+ with two lines.</li>
+ </ol>
+ static: |-
+ <ol data-sourcepos="1:3-2:19" dir="auto">
+ <li data-sourcepos="1:3-2:19">A paragraph
+ with two lines.</li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>A paragraph
+ with two lines.</p></li></ol>
+05_02_00__container_blocks__list_items__040:
+ canonical: |
+ <blockquote>
+ <ol>
+ <li>
+ <blockquote>
+ <p>Blockquote
+ continued here.</p>
+ </blockquote>
+ </li>
+ </ol>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-2:15" dir="auto">
+ <ol data-sourcepos="1:3-2:15">
+ <li data-sourcepos="1:3-2:15">
+ <blockquote data-sourcepos="1:6-2:15">
+ <p data-sourcepos="1:8-2:15">Blockquote
+ continued here.</p>
+ </blockquote>
+ </li>
+ </ol>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><ol parens="false"><li><p></p><blockquote multiline="false"><p>Blockquote
+ continued here.</p></blockquote></li></ol></blockquote>
+05_02_00__container_blocks__list_items__041:
+ canonical: |
+ <blockquote>
+ <ol>
+ <li>
+ <blockquote>
+ <p>Blockquote
+ continued here.</p>
+ </blockquote>
+ </li>
+ </ol>
+ </blockquote>
+ static: |-
+ <blockquote data-sourcepos="1:1-2:17" dir="auto">
+ <ol data-sourcepos="1:3-2:17">
+ <li data-sourcepos="1:3-2:17">
+ <blockquote data-sourcepos="1:6-2:17">
+ <p data-sourcepos="1:8-2:17">Blockquote
+ continued here.</p>
+ </blockquote>
+ </li>
+ </ol>
+ </blockquote>
+ wysiwyg: |-
+ <blockquote multiline="false"><ol parens="false"><li><p></p><blockquote multiline="false"><p>Blockquote
+ continued here.</p></blockquote></li></ol></blockquote>
+05_02_00__container_blocks__list_items__042:
+ canonical: |
+ <ul>
+ <li>foo
+ <ul>
+ <li>bar
+ <ul>
+ <li>baz
+ <ul>
+ <li>boo</li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-4:11" dir="auto">
+ <li data-sourcepos="1:1-4:11">foo
+ <ul data-sourcepos="2:3-4:11">
+ <li data-sourcepos="2:3-4:11">bar
+ <ul data-sourcepos="3:5-4:11">
+ <li data-sourcepos="3:5-4:11">baz
+ <ul data-sourcepos="4:7-4:11">
+ <li data-sourcepos="4:7-4:11">boo</li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p><ul bullet="*"><li><p>bar</p><ul bullet="*"><li><p>baz</p><ul bullet="*"><li><p>boo</p></li></ul></li></ul></li></ul></li></ul>
+05_02_00__container_blocks__list_items__043:
+ canonical: |
+ <ul>
+ <li>foo</li>
+ <li>bar</li>
+ <li>baz</li>
+ <li>boo</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-4:8" dir="auto">
+ <li data-sourcepos="1:1-1:5">foo</li>
+ <li data-sourcepos="2:2-2:6">bar</li>
+ <li data-sourcepos="3:3-3:7">baz</li>
+ <li data-sourcepos="4:4-4:8">boo</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p></li><li><p>bar</p></li><li><p>baz</p></li><li><p>boo</p></li></ul>
+05_02_00__container_blocks__list_items__044:
+ canonical: |
+ <ol start="10">
+ <li>foo
+ <ul>
+ <li>bar</li>
+ </ul>
+ </li>
+ </ol>
+ static: |-
+ <ol start="10" data-sourcepos="1:1-2:9" dir="auto">
+ <li data-sourcepos="1:1-2:9">foo
+ <ul data-sourcepos="2:5-2:9">
+ <li data-sourcepos="2:5-2:9">bar</li>
+ </ul>
+ </li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>foo</p><ul bullet="*"><li><p>bar</p></li></ul></li></ol>
+05_02_00__container_blocks__list_items__045:
+ canonical: |
+ <ol start="10">
+ <li>foo</li>
+ </ol>
+ <ul>
+ <li>bar</li>
+ </ul>
+ static: |-
+ <ol start="10" data-sourcepos="1:1-1:7" dir="auto">
+ <li data-sourcepos="1:1-1:7">foo</li>
+ </ol>
+ <ul data-sourcepos="2:4-2:8" dir="auto">
+ <li data-sourcepos="2:4-2:8">bar</li>
+ </ul>
+ wysiwyg: |-
+ <ol parens="false"><li><p>foo</p></li></ol>
+ <ul bullet="*"><li><p>bar</p></li></ul>
+05_02_00__container_blocks__list_items__046:
+ canonical: |
+ <ul>
+ <li>
+ <ul>
+ <li>foo</li>
+ </ul>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-1:7" dir="auto">
+ <li data-sourcepos="1:1-1:7">
+ <ul data-sourcepos="1:3-1:7">
+ <li data-sourcepos="1:3-1:7">foo</li>
+ </ul>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p></p><ul bullet="*"><li><p>foo</p></li></ul></li></ul>
+05_02_00__container_blocks__list_items__047:
+ canonical: |
+ <ol>
+ <li>
+ <ul>
+ <li>
+ <ol start="2">
+ <li>foo</li>
+ </ol>
+ </li>
+ </ul>
+ </li>
+ </ol>
+ static: |-
+ <ol data-sourcepos="1:1-1:11" dir="auto">
+ <li data-sourcepos="1:1-1:11">
+ <ul data-sourcepos="1:4-1:11">
+ <li data-sourcepos="1:4-1:11">
+ <ol start="2" data-sourcepos="1:6-1:11">
+ <li data-sourcepos="1:6-1:11">foo</li>
+ </ol>
+ </li>
+ </ul>
+ </li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p></p><ul bullet="*"><li><p></p><ol parens="false"><li><p>foo</p></li></ol></li></ul></li></ol>
+05_02_00__container_blocks__list_items__048:
+ canonical: |
+ <ul>
+ <li>
+ <h1>Foo</h1>
+ </li>
+ <li>
+ <h2>Bar</h2>
+ baz</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-4:5" dir="auto">
+ <li data-sourcepos="1:1-1:7">
+ <h1 data-sourcepos="1:3-1:7">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>Foo</h1>
+ </li>
+ <li data-sourcepos="2:1-4:5">
+ <h2 data-sourcepos="2:3-4:5">
+ <a id="user-content-bar" class="anchor" href="#bar" aria-hidden="true"></a>Bar</h2>
+ baz</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p></p><h1>Foo</h1></li><li><p></p><h2>Bar</h2><p>
+ baz</p></li></ul>
+05_04_00__container_blocks__lists__001:
+ canonical: |
+ <ul>
+ <li>foo</li>
+ <li>bar</li>
+ </ul>
+ <ul>
+ <li>baz</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-2:5" dir="auto">
+ <li data-sourcepos="1:1-1:5">foo</li>
+ <li data-sourcepos="2:1-2:5">bar</li>
+ </ul>
+ <ul data-sourcepos="3:1-3:5" dir="auto">
+ <li data-sourcepos="3:1-3:5">baz</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p></li><li><p>bar</p></li></ul>
+ <ul bullet="*"><li><p>baz</p></li></ul>
+05_04_00__container_blocks__lists__002:
+ canonical: |
+ <ol>
+ <li>foo</li>
+ <li>bar</li>
+ </ol>
+ <ol start="3">
+ <li>baz</li>
+ </ol>
+ static: |-
+ <ol data-sourcepos="1:1-2:6" dir="auto">
+ <li data-sourcepos="1:1-1:6">foo</li>
+ <li data-sourcepos="2:1-2:6">bar</li>
+ </ol>
+ <ol start="3" data-sourcepos="3:1-3:6" dir="auto">
+ <li data-sourcepos="3:1-3:6">baz</li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>foo</p></li><li><p>bar</p></li></ol>
+ <ol parens="false"><li><p>baz</p></li></ol>
+05_04_00__container_blocks__lists__003:
+ canonical: |
+ <p>Foo</p>
+ <ul>
+ <li>bar</li>
+ <li>baz</li>
+ </ul>
+ static: |-
+ <p data-sourcepos="1:1-1:3" dir="auto">Foo</p>
+ <ul data-sourcepos="2:1-3:5" dir="auto">
+ <li data-sourcepos="2:1-2:5">bar</li>
+ <li data-sourcepos="3:1-3:5">baz</li>
+ </ul>
+ wysiwyg: |-
+ <p>Foo</p>
+ <ul bullet="*"><li><p>bar</p></li><li><p>baz</p></li></ul>
+05_04_00__container_blocks__lists__004:
+ canonical: |
+ <p>The number of windows in my house is
+ 14. The number of doors is 6.</p>
+ static: |-
+ <p data-sourcepos="1:1-2:30" dir="auto">The number of windows in my house is
+ 14. The number of doors is 6.</p>
+ wysiwyg: |-
+ <p>The number of windows in my house is
+ 14. The number of doors is 6.</p>
+05_04_00__container_blocks__lists__005:
+ canonical: |
+ <p>The number of windows in my house is</p>
+ <ol>
+ <li>The number of doors is 6.</li>
+ </ol>
+ static: |-
+ <p data-sourcepos="1:1-1:36" dir="auto">The number of windows in my house is</p>
+ <ol data-sourcepos="2:1-2:29" dir="auto">
+ <li data-sourcepos="2:1-2:29">The number of doors is 6.</li>
+ </ol>
+ wysiwyg: |-
+ <p>The number of windows in my house is</p>
+ <ol parens="false"><li><p>The number of doors is 6.</p></li></ol>
+05_04_00__container_blocks__lists__006:
+ canonical: |
+ <ul>
+ <li>
+ <p>foo</p>
+ </li>
+ <li>
+ <p>bar</p>
+ </li>
+ <li>
+ <p>baz</p>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-6:5" dir="auto">
+ <li data-sourcepos="1:1-2:0">
+ <p data-sourcepos="1:3-1:5">foo</p>
+ </li>
+ <li data-sourcepos="3:1-5:0">
+ <p data-sourcepos="3:3-3:5">bar</p>
+ </li>
+ <li data-sourcepos="6:1-6:5">
+ <p data-sourcepos="6:3-6:5">baz</p>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p></li><li><p>bar</p></li><li><p>baz</p></li></ul>
+05_04_00__container_blocks__lists__007:
+ canonical: |
+ <ul>
+ <li>foo
+ <ul>
+ <li>bar
+ <ul>
+ <li>
+ <p>baz</p>
+ <p>bim</p>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-6:9" dir="auto">
+ <li data-sourcepos="1:1-6:9">foo
+ <ul data-sourcepos="2:3-6:9">
+ <li data-sourcepos="2:3-6:9">bar
+ <ul data-sourcepos="3:5-6:9">
+ <li data-sourcepos="3:5-6:9">
+ <p data-sourcepos="3:7-3:9">baz</p>
+ <p data-sourcepos="6:7-6:9">bim</p>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p><ul bullet="*"><li><p>bar</p><ul bullet="*"><li><p>baz</p><p>bim</p></li></ul></li></ul></li></ul>
+05_04_00__container_blocks__lists__008:
+ canonical: |
+ <ul>
+ <li>foo</li>
+ <li>bar</li>
+ </ul>
+ <!-- -->
+ <ul>
+ <li>baz</li>
+ <li>bim</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-3:0" dir="auto">
+ <li data-sourcepos="1:1-1:5">foo</li>
+ <li data-sourcepos="2:1-3:0">bar</li>
+ </ul>
+
+ <ul data-sourcepos="6:1-7:5" dir="auto">
+ <li data-sourcepos="6:1-6:5">baz</li>
+ <li data-sourcepos="7:1-7:5">bim</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p></li><li><p>bar</p></li></ul>
+ <ul bullet="*"><li><p>baz</p></li><li><p>bim</p></li></ul>
+05_04_00__container_blocks__lists__009:
+ canonical: |
+ <ul>
+ <li>
+ <p>foo</p>
+ <p>notcode</p>
+ </li>
+ <li>
+ <p>foo</p>
+ </li>
+ </ul>
+ <!-- -->
+ <pre><code>code
+ </code></pre>
+ static: |-
+ <ul data-sourcepos="1:1-6:0" dir="auto">
+ <li data-sourcepos="1:1-4:0">
+ <p data-sourcepos="1:5-1:7">foo</p>
+ <p data-sourcepos="3:5-3:11">notcode</p>
+ </li>
+ <li data-sourcepos="5:1-6:0">
+ <p data-sourcepos="5:5-5:7">foo</p>
+ </li>
+ </ul>
+
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="9:5-9:8" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">code</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p><p>notcode</p></li><li><p>foo</p></li></ul>
+ <pre class="content-editor-code-block undefined code highlight"><code>code</code></pre>
+05_04_00__container_blocks__lists__010:
+ canonical: |
+ <ul>
+ <li>a</li>
+ <li>b</li>
+ <li>c</li>
+ <li>d</li>
+ <li>e</li>
+ <li>f</li>
+ <li>g</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-7:3" dir="auto">
+ <li data-sourcepos="1:1-1:3">a</li>
+ <li data-sourcepos="2:2-2:4">b</li>
+ <li data-sourcepos="3:3-3:5">c</li>
+ <li data-sourcepos="4:4-4:6">d</li>
+ <li data-sourcepos="5:3-5:5">e</li>
+ <li data-sourcepos="6:2-6:4">f</li>
+ <li data-sourcepos="7:1-7:3">g</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>a</p></li><li><p>b</p></li><li><p>c</p></li><li><p>d</p></li><li><p>e</p></li><li><p>f</p></li><li><p>g</p></li></ul>
+05_04_00__container_blocks__lists__011:
+ canonical: |
+ <ol>
+ <li>
+ <p>a</p>
+ </li>
+ <li>
+ <p>b</p>
+ </li>
+ <li>
+ <p>c</p>
+ </li>
+ </ol>
+ static: |-
+ <ol data-sourcepos="1:1-5:7" dir="auto">
+ <li data-sourcepos="1:1-2:0">
+ <p data-sourcepos="1:4-1:4">a</p>
+ </li>
+ <li data-sourcepos="3:3-4:0">
+ <p data-sourcepos="3:6-3:6">b</p>
+ </li>
+ <li data-sourcepos="5:4-5:7">
+ <p data-sourcepos="5:7-5:7">c</p>
+ </li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p>a</p></li><li><p>b</p></li><li><p>c</p></li></ol>
+05_04_00__container_blocks__lists__012:
+ canonical: |
+ <ul>
+ <li>a</li>
+ <li>b</li>
+ <li>c</li>
+ <li>d
+ - e</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-5:7" dir="auto">
+ <li data-sourcepos="1:1-1:3">a</li>
+ <li data-sourcepos="2:2-2:4">b</li>
+ <li data-sourcepos="3:3-3:5">c</li>
+ <li data-sourcepos="4:4-5:7">d
+ - e</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>a</p></li><li><p>b</p></li><li><p>c</p></li><li><p>d
+ - e</p></li></ul>
+05_04_00__container_blocks__lists__013:
+ canonical: |
+ <ol>
+ <li>
+ <p>a</p>
+ </li>
+ <li>
+ <p>b</p>
+ </li>
+ </ol>
+ <pre><code>3. c
+ </code></pre>
+ static: |-
+ <ol data-sourcepos="1:1-4:0" dir="auto">
+ <li data-sourcepos="1:1-2:0">
+ <p data-sourcepos="1:4-1:4">a</p>
+ </li>
+ <li data-sourcepos="3:3-4:0">
+ <p data-sourcepos="3:6-3:6">b</p>
+ </li>
+ </ol>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="5:5-5:8" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">3. c</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <ol parens="false"><li><p>a</p></li><li><p>b</p></li></ol>
+ <pre class="content-editor-code-block undefined code highlight"><code>3. c</code></pre>
+05_04_00__container_blocks__lists__014:
+ canonical: |
+ <ul>
+ <li>
+ <p>a</p>
+ </li>
+ <li>
+ <p>b</p>
+ </li>
+ <li>
+ <p>c</p>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-4:3" dir="auto">
+ <li data-sourcepos="1:1-1:3">
+ <p data-sourcepos="1:3-1:3">a</p>
+ </li>
+ <li data-sourcepos="2:1-3:0">
+ <p data-sourcepos="2:3-2:3">b</p>
+ </li>
+ <li data-sourcepos="4:1-4:3">
+ <p data-sourcepos="4:3-4:3">c</p>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>a</p></li><li><p>b</p></li><li><p>c</p></li></ul>
+05_04_00__container_blocks__lists__015:
+ canonical: |
+ <ul>
+ <li>
+ <p>a</p>
+ </li>
+ <li></li>
+ <li>
+ <p>c</p>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-4:3" dir="auto">
+ <li data-sourcepos="1:1-1:3">
+ <p data-sourcepos="1:3-1:3">a</p>
+ </li>
+ <li data-sourcepos="2:1-2:1">
+ </li>
+ <li data-sourcepos="4:1-4:3">
+ <p data-sourcepos="4:3-4:3">c</p>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>a</p></li><li><p></p></li><li><p>c</p></li></ul>
+05_04_00__container_blocks__lists__016:
+ canonical: |
+ <ul>
+ <li>
+ <p>a</p>
+ </li>
+ <li>
+ <p>b</p>
+ <p>c</p>
+ </li>
+ <li>
+ <p>d</p>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-5:3" dir="auto">
+ <li data-sourcepos="1:1-1:3">
+ <p data-sourcepos="1:3-1:3">a</p>
+ </li>
+ <li data-sourcepos="2:1-4:3">
+ <p data-sourcepos="2:3-2:3">b</p>
+ <p data-sourcepos="4:3-4:3">c</p>
+ </li>
+ <li data-sourcepos="5:1-5:3">
+ <p data-sourcepos="5:3-5:3">d</p>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>a</p></li><li><p>b</p><p>c</p></li><li><p>d</p></li></ul>
+05_04_00__container_blocks__lists__017:
+ canonical: |
+ <ul>
+ <li>
+ <p>a</p>
+ </li>
+ <li>
+ <p>b</p>
+ </li>
+ <li>
+ <p>d</p>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-5:3" dir="auto">
+ <li data-sourcepos="1:1-1:3">
+ <p data-sourcepos="1:3-1:3">a</p>
+ </li>
+ <li data-sourcepos="2:1-4:13">
+ <p data-sourcepos="2:3-2:3">b</p>
+ </li>
+ <li data-sourcepos="5:1-5:3">
+ <p data-sourcepos="5:3-5:3">d</p>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>a</p></li><li><p>b</p><pre>[ref]: /url</pre></li><li><p>d</p></li></ul>
+05_04_00__container_blocks__lists__018:
+ canonical: |
+ <ul>
+ <li>a</li>
+ <li>
+ <pre><code>b
+
+
+ </code></pre>
+ </li>
+ <li>c</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-7:3" dir="auto">
+ <li data-sourcepos="1:1-1:3">a</li>
+ <li data-sourcepos="2:1-6:5">
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="2:3-6:5" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">b</span>
+ <span id="LC2" class="line" lang="plaintext"></span>
+ <span id="LC3" class="line" lang="plaintext"></span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </li>
+ <li data-sourcepos="7:1-7:3">c</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>a</p></li><li><p></p><pre class="content-editor-code-block undefined code highlight"><code>b</code></pre></li><li><p>c</p></li></ul>
+05_04_00__container_blocks__lists__019:
+ canonical: |
+ <ul>
+ <li>a
+ <ul>
+ <li>
+ <p>b</p>
+ <p>c</p>
+ </li>
+ </ul>
+ </li>
+ <li>d</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-5:3" dir="auto">
+ <li data-sourcepos="1:1-4:5">a
+ <ul data-sourcepos="2:3-4:5">
+ <li data-sourcepos="2:3-4:5">
+ <p data-sourcepos="2:5-2:5">b</p>
+ <p data-sourcepos="4:5-4:5">c</p>
+ </li>
+ </ul>
+ </li>
+ <li data-sourcepos="5:1-5:3">d</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>a</p><ul bullet="*"><li><p>b</p><p>c</p></li></ul></li><li><p>d</p></li></ul>
+05_04_00__container_blocks__lists__020:
+ canonical: |
+ <ul>
+ <li>a
+ <blockquote>
+ <p>b</p>
+ </blockquote>
+ </li>
+ <li>c</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-4:3" dir="auto">
+ <li data-sourcepos="1:1-3:3">a
+ <blockquote data-sourcepos="2:3-3:3">
+ <p data-sourcepos="2:5-2:5">b</p>
+ </blockquote>
+ </li>
+ <li data-sourcepos="4:1-4:3">c</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>a</p><blockquote multiline="false"><p>b</p></blockquote></li><li><p>c</p></li></ul>
+05_04_00__container_blocks__lists__021:
+ canonical: |
+ <ul>
+ <li>a
+ <blockquote>
+ <p>b</p>
+ </blockquote>
+ <pre><code>c
+ </code></pre>
+ </li>
+ <li>d</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-6:3" dir="auto">
+ <li data-sourcepos="1:1-5:5">a
+ <blockquote data-sourcepos="2:3-2:5">
+ <p data-sourcepos="2:5-2:5">b</p>
+ </blockquote>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="3:3-5:5" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">c</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </li>
+ <li data-sourcepos="6:1-6:3">d</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>a</p><blockquote multiline="false"><p>b</p></blockquote><pre class="content-editor-code-block undefined code highlight"><code>c</code></pre></li><li><p>d</p></li></ul>
+05_04_00__container_blocks__lists__022:
+ canonical: |
+ <ul>
+ <li>a</li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-1:3" dir="auto">
+ <li data-sourcepos="1:1-1:3">a</li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>a</p></li></ul>
+05_04_00__container_blocks__lists__023:
+ canonical: |
+ <ul>
+ <li>a
+ <ul>
+ <li>b</li>
+ </ul>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-2:5" dir="auto">
+ <li data-sourcepos="1:1-2:5">a
+ <ul data-sourcepos="2:3-2:5">
+ <li data-sourcepos="2:3-2:5">b</li>
+ </ul>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>a</p><ul bullet="*"><li><p>b</p></li></ul></li></ul>
+05_04_00__container_blocks__lists__024:
+ canonical: |
+ <ol>
+ <li>
+ <pre><code>foo
+ </code></pre>
+ <p>bar</p>
+ </li>
+ </ol>
+ static: |-
+ <ol data-sourcepos="1:1-5:6" dir="auto">
+ <li data-sourcepos="1:1-5:6">
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:4-3:6" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <p data-sourcepos="5:4-5:6">bar</p>
+ </li>
+ </ol>
+ wysiwyg: |-
+ <ol parens="false"><li><p></p><pre class="content-editor-code-block undefined code highlight"><code>foo</code></pre><p>bar</p></li></ol>
+05_04_00__container_blocks__lists__025:
+ canonical: |
+ <ul>
+ <li>
+ <p>foo</p>
+ <ul>
+ <li>bar</li>
+ </ul>
+ <p>baz</p>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-4:5" dir="auto">
+ <li data-sourcepos="1:1-4:5">
+ <p data-sourcepos="1:3-1:5">foo</p>
+ <ul data-sourcepos="2:3-3:0">
+ <li data-sourcepos="2:3-3:0">bar</li>
+ </ul>
+ <p data-sourcepos="4:3-4:5">baz</p>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>foo</p><ul bullet="*"><li><p>bar</p></li></ul><p>baz</p></li></ul>
+05_04_00__container_blocks__lists__026:
+ canonical: |
+ <ul>
+ <li>
+ <p>a</p>
+ <ul>
+ <li>b</li>
+ <li>c</li>
+ </ul>
+ </li>
+ <li>
+ <p>d</p>
+ <ul>
+ <li>e</li>
+ <li>f</li>
+ </ul>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-7:5" dir="auto">
+ <li data-sourcepos="1:1-4:0">
+ <p data-sourcepos="1:3-1:3">a</p>
+ <ul data-sourcepos="2:3-4:0">
+ <li data-sourcepos="2:3-2:5">b</li>
+ <li data-sourcepos="3:3-4:0">c</li>
+ </ul>
+ </li>
+ <li data-sourcepos="5:1-7:5">
+ <p data-sourcepos="5:3-5:3">d</p>
+ <ul data-sourcepos="6:3-7:5">
+ <li data-sourcepos="6:3-6:5">e</li>
+ <li data-sourcepos="7:3-7:5">f</li>
+ </ul>
+ </li>
+ </ul>
+ wysiwyg: |-
+ <ul bullet="*"><li><p>a</p><ul bullet="*"><li><p>b</p></li><li><p>c</p></li></ul></li><li><p>d</p><ul bullet="*"><li><p>e</p></li><li><p>f</p></li></ul></li></ul>
+06_01_00__inlines__001:
+ canonical: |
+ <p><code>hi</code>lo`</p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto"><code>hi</code>lo`</p>
+ wysiwyg: |-
+ <p><code>hi</code>lo`</p>
+06_02_00__inlines__backslash_escapes__001:
+ canonical: |
+ <p>!&quot;#$%&amp;'()*+,-./:;&lt;=&gt;?@[\]^_`{|}~</p>
+ static: |-
+ <p data-sourcepos="1:1-1:224" dir="auto"><span>!</span>"<span>#</span><span>$</span><span>%</span><span>&amp;</span>'()*+,-./:;&lt;=&gt;?<span>@</span>[\]<span>^</span>_`{|}<span>~</span></p>
+ wysiwyg: |-
+ <p>!"#$%&amp;'()*+,-./:;&lt;=&gt;?@[\]^_`{|}~</p>
+06_02_00__inlines__backslash_escapes__002:
+ canonical: "<p>\\\t\\A\\a\\ \\3\\φ\\«</p>\n"
+ static: "<p data-sourcepos=\"1:1-1:16\" dir=\"auto\">\\\t\\A\\a\\ \\3\\φ\\«</p>"
+ wysiwyg: "<p>\\\t\\A\\a\\ \\3\\φ\\«</p>"
+06_02_00__inlines__backslash_escapes__003:
+ canonical: |
+ <p>*not emphasized*
+ &lt;br/&gt; not a tag
+ [not a link](/foo)
+ `not code`
+ 1. not a list
+ * not a list
+ # not a heading
+ [foo]: /url &quot;not a reference&quot;
+ &amp;ouml; not a character entity</p>
+ static: |-
+ <p data-sourcepos="1:1-9:50" dir="auto">*not emphasized*
+ &lt;br/&gt; not a tag
+ <a href="/foo">not a link</a>
+ `not code`
+ 1. not a list
+ * not a list
+ <span>#</span> not a heading
+ [foo]: /url "not a reference"
+ <span>&amp;</span>ouml; not a character entity</p>
+ wysiwyg: |-
+ <p>*not emphasized*
+ &lt;br/&gt; not a tag
+ [not a link](/foo)
+ `not code`
+ 1. not a list
+ * not a list
+ # not a heading
+ [foo]: /url "not a reference"
+ &amp;ouml; not a character entity</p>
+06_02_00__inlines__backslash_escapes__004:
+ canonical: |
+ <p>\<em>emphasis</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:12" dir="auto">\<em>emphasis</em></p>
+ wysiwyg: |-
+ <p>\<em>emphasis</em></p>
+06_02_00__inlines__backslash_escapes__005:
+ canonical: |
+ <p>foo<br />
+ bar</p>
+ static: |-
+ <p data-sourcepos="1:1-2:3" dir="auto">foo<br>
+ bar</p>
+ wysiwyg: |-
+ <p>foo<br>
+ bar</p>
+06_02_00__inlines__backslash_escapes__006:
+ canonical: |
+ <p><code>\[\`</code></p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto"><code>\[\`</code></p>
+ wysiwyg: |-
+ <p><code>\[\`</code></p>
+06_02_00__inlines__backslash_escapes__007:
+ canonical: |
+ <pre><code>\[\]
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-1:8" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\[\]</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>\[\]</code></pre>
+06_02_00__inlines__backslash_escapes__008:
+ canonical: |
+ <pre><code>\[\]
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-3:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\[\]</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>\[\]</code></pre>
+06_02_00__inlines__backslash_escapes__009:
+ canonical: |
+ <p><a href="http://example.com?find=%5C*">http://example.com?find=\*</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:28" dir="auto"><a href="http://example.com?find=%5C*" rel="nofollow noreferrer noopener" target="_blank">http://example.com?find=\*</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://example.com?find=%5C*">http://example.com?find=\*</a></p>
+06_02_00__inlines__backslash_escapes__010:
+ canonical: |
+ <a href="/bar\/)">
+ static: |-
+ <a href="/bar%5C/)" rel="nofollow noreferrer noopener" target="_blank"></a>
+ wysiwyg: |-
+ <p></p>
+06_02_00__inlines__backslash_escapes__011:
+ canonical: |
+ <p><a href="/bar*" title="ti*tle">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:23" dir="auto"><a href="/bar*" title="ti*tle">foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/bar*" title="ti*tle">foo</a></p>
+06_02_00__inlines__backslash_escapes__012:
+ canonical: |
+ <p><a href="/bar*" title="ti*tle">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:5" dir="auto"><a href="/bar*" title="ti*tle">foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/bar*" title="ti*tle">foo</a></p>
+ <pre>[foo]: /bar* "ti*tle"</pre>
+06_02_00__inlines__backslash_escapes__013:
+ canonical: |
+ <pre><code class="language-foo+bar">foo
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-3:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="foo+bar" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre language="foo+bar" class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
+06_03_00__inlines__entity_and_numeric_character_references__001:
+ canonical: |
+ <p>  &amp; © Æ Ď
+ ¾ ℋ ⅆ
+ ∲ ≧̸</p>
+ static: |-
+ <p data-sourcepos="1:1-3:32" dir="auto">  &amp; © Æ Ď
+ ¾ ℋ ⅆ
+ ∲ ≧̸</p>
+ wysiwyg: |-
+ <p>&nbsp; &amp; © Æ Ď
+ ¾ ℋ ⅆ
+ ∲ ≧̸</p>
+06_03_00__inlines__entity_and_numeric_character_references__002:
+ canonical: |
+ <p># Ӓ Ϡ �</p>
+ static: |-
+ <p data-sourcepos="1:1-1:25" dir="auto"># Ӓ Ϡ �</p>
+ wysiwyg: |-
+ <p># Ӓ Ϡ �</p>
+06_03_00__inlines__entity_and_numeric_character_references__003:
+ canonical: |
+ <p>&quot; ആ ಫ</p>
+ static: |-
+ <p data-sourcepos="1:1-1:22" dir="auto">" ആ ಫ</p>
+ wysiwyg: |-
+ <p>" ആ ಫ</p>
+06_03_00__inlines__entity_and_numeric_character_references__004:
+ canonical: |
+ <p>&amp;nbsp &amp;x; &amp;#; &amp;#x;
+ &amp;#987654321;
+ &amp;#abcdef0;
+ &amp;ThisIsNotDefined; &amp;hi?;</p>
+ static: |-
+ <p data-sourcepos="1:1-4:24" dir="auto">&amp;nbsp &amp;x; &amp;#; &amp;#x;
+ &amp;#987654321;
+ &amp;#abcdef0;
+ &amp;ThisIsNotDefined; &amp;hi?;</p>
+ wysiwyg: |-
+ <p>&amp;nbsp &amp;x; &amp;#; &amp;#x;
+ &amp;#987654321;
+ &amp;#abcdef0;
+ &amp;ThisIsNotDefined; &amp;hi?;</p>
+06_03_00__inlines__entity_and_numeric_character_references__005:
+ canonical: |
+ <p>&amp;copy</p>
+ static: |-
+ <p data-sourcepos="1:1-1:5" dir="auto">&amp;copy</p>
+ wysiwyg: |-
+ <p>&amp;copy</p>
+06_03_00__inlines__entity_and_numeric_character_references__006:
+ canonical: |
+ <p>&amp;MadeUpEntity;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:14" dir="auto">&amp;MadeUpEntity;</p>
+ wysiwyg: |-
+ <p>&amp;MadeUpEntity;</p>
+06_03_00__inlines__entity_and_numeric_character_references__007:
+ canonical: |
+ <a href="&ouml;&ouml;.html">
+ static: |-
+ <a href="%C3%B6%C3%B6.html" rel="nofollow noreferrer noopener" target="_blank"></a>
+ wysiwyg: |-
+ <p></p>
+06_03_00__inlines__entity_and_numeric_character_references__008:
+ canonical: |
+ <p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:37" dir="auto"><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+06_03_00__inlines__entity_and_numeric_character_references__009:
+ canonical: |
+ <p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:5" dir="auto"><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+ <pre>[foo]: /föö "föö"</pre>
+06_03_00__inlines__entity_and_numeric_character_references__010:
+ canonical: |
+ <pre><code class="language-föö">foo
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-3:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="föö" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre language="föö" class="content-editor-code-block undefined code highlight"><code>foo</code></pre>
+06_03_00__inlines__entity_and_numeric_character_references__011:
+ canonical: |
+ <p><code>f&amp;ouml;&amp;ouml;</code></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><code>f&amp;ouml;&amp;ouml;</code></p>
+ wysiwyg: |-
+ <p><code>f&amp;ouml;&amp;ouml;</code></p>
+06_03_00__inlines__entity_and_numeric_character_references__012:
+ canonical: |
+ <pre><code>f&amp;ouml;f&amp;ouml;
+ </code></pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:5-1:18" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">f&amp;ouml;f&amp;ouml;</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre class="content-editor-code-block undefined code highlight"><code>f&amp;ouml;f&amp;ouml;</code></pre>
+06_03_00__inlines__entity_and_numeric_character_references__013:
+ canonical: |
+ <p>*foo*
+ <em>foo</em></p>
+ static: |-
+ <p data-sourcepos="1:1-2:5" dir="auto">*foo*
+ <em>foo</em></p>
+ wysiwyg: |-
+ <p>*foo*
+ <em>foo</em></p>
+06_03_00__inlines__entity_and_numeric_character_references__014:
+ canonical: |
+ <p>* foo</p>
+ <ul>
+ <li>foo</li>
+ </ul>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto">* foo</p>
+ <ul data-sourcepos="3:1-3:5" dir="auto">
+ <li data-sourcepos="3:1-3:5">foo</li>
+ </ul>
+ wysiwyg: |-
+ <p>* foo</p>
+ <ul bullet="*"><li><p>foo</p></li></ul>
+06_03_00__inlines__entity_and_numeric_character_references__015:
+ canonical: |
+ <p>foo
+
+ bar</p>
+ static: |-
+ <p data-sourcepos="1:1-1:16" dir="auto">foo
+
+ bar</p>
+ wysiwyg: |-
+ <p>foo
+
+ bar</p>
+06_03_00__inlines__entity_and_numeric_character_references__016:
+ canonical: "<p>\tfoo</p>\n"
+ static: "<p data-sourcepos=\"1:1-1:7\" dir=\"auto\">\tfoo</p>"
+ wysiwyg: "<p>\tfoo</p>"
+06_03_00__inlines__entity_and_numeric_character_references__017:
+ canonical: |
+ <p>[a](url &quot;tit&quot;)</p>
+ static: |-
+ <p data-sourcepos="1:1-1:24" dir="auto"><a href="url" title="tit">a</a></p>
+ wysiwyg: |-
+ <p>[a](url "tit")</p>
+06_04_00__inlines__code_spans__001:
+ canonical: |
+ <p><code>foo</code></p>
+ static: |-
+ <p data-sourcepos="1:1-1:5" dir="auto"><code>foo</code></p>
+ wysiwyg: |-
+ <p><code>foo</code></p>
+06_04_00__inlines__code_spans__002:
+ canonical: |
+ <p><code>foo ` bar</code></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><code>foo ` bar</code></p>
+ wysiwyg: |-
+ <p><code>foo ` bar</code></p>
+06_04_00__inlines__code_spans__003:
+ canonical: |
+ <p><code>``</code></p>
+ static: |-
+ <p data-sourcepos="1:1-1:6" dir="auto"><code>``</code></p>
+ wysiwyg: |-
+ <p><code>``</code></p>
+06_04_00__inlines__code_spans__004:
+ canonical: |
+ <p><code> `` </code></p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto"><code> `` </code></p>
+ wysiwyg: |-
+ <p><code> `` </code></p>
+06_04_00__inlines__code_spans__005:
+ canonical: |
+ <p><code> a</code></p>
+ static: |-
+ <p data-sourcepos="1:1-1:4" dir="auto"><code> a</code></p>
+ wysiwyg: |-
+ <p><code> a</code></p>
+06_04_00__inlines__code_spans__006:
+ canonical: |
+ <p><code> b </code></p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto"><code> b </code></p>
+ wysiwyg: |-
+ <p><code>&nbsp;b&nbsp;</code></p>
+06_04_00__inlines__code_spans__007:
+ canonical: |
+ <p><code> </code>
+ <code> </code></p>
+ static: |-
+ <p data-sourcepos="1:1-2:4" dir="auto"><code> </code>
+ <code> </code></p>
+ wysiwyg: |-
+ <p></p>
+06_04_00__inlines__code_spans__008:
+ canonical: |
+ <p><code>foo bar baz</code></p>
+ static: |-
+ <p data-sourcepos="1:1-5:2" dir="auto"><code>foo bar baz</code></p>
+ wysiwyg: |-
+ <p><code>foo bar baz</code></p>
+06_04_00__inlines__code_spans__009:
+ canonical: |
+ <p><code>foo </code></p>
+ static: |-
+ <p data-sourcepos="1:1-3:2" dir="auto"><code>foo </code></p>
+ wysiwyg: |-
+ <p><code>foo </code></p>
+06_04_00__inlines__code_spans__010:
+ canonical: |
+ <p><code>foo bar baz</code></p>
+ static: |-
+ <p data-sourcepos="1:1-2:4" dir="auto"><code>foo bar baz</code></p>
+ wysiwyg: |-
+ <p><code>foo bar baz</code></p>
+06_04_00__inlines__code_spans__011:
+ canonical: |
+ <p><code>foo\</code>bar`</p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto"><code>foo\</code>bar`</p>
+ wysiwyg: |-
+ <p><code>foo\</code>bar`</p>
+06_04_00__inlines__code_spans__012:
+ canonical: |
+ <p><code>foo`bar</code></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto"><code>foo`bar</code></p>
+ wysiwyg: |-
+ <p><code>foo`bar</code></p>
+06_04_00__inlines__code_spans__013:
+ canonical: |
+ <p><code>foo `` bar</code></p>
+ static: |-
+ <p data-sourcepos="1:1-1:14" dir="auto"><code>foo `` bar</code></p>
+ wysiwyg: |-
+ <p><code>foo `` bar</code></p>
+06_04_00__inlines__code_spans__014:
+ canonical: |
+ <p>*foo<code>*</code></p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto">*foo<code>*</code></p>
+ wysiwyg: |-
+ <p>*foo<code>*</code></p>
+06_04_00__inlines__code_spans__015:
+ canonical: |
+ <p>[not a <code>link](/foo</code>)</p>
+ static: |-
+ <p data-sourcepos="1:1-1:20" dir="auto">[not a <code>link](/foo</code>)</p>
+ wysiwyg: |-
+ <p>[not a <code>link](/foo</code>)</p>
+06_04_00__inlines__code_spans__016:
+ canonical: |
+ <p><code>&lt;a href=&quot;</code>&quot;&gt;`</p>
+ static: |-
+ <p data-sourcepos="1:1-1:14" dir="auto"><code>&lt;a href="</code>"&gt;`</p>
+ wysiwyg: |-
+ <p><code>&lt;a href="</code>"&gt;`</p>
+06_04_00__inlines__code_spans__017:
+ canonical: |
+ <p><a href="`">`</p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto"><a href="%60" rel="nofollow noreferrer noopener" target="_blank">`</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="`">`</a></p>
+06_04_00__inlines__code_spans__018:
+ canonical: |
+ <p><code>&lt;http://foo.bar.</code>baz&gt;`</p>
+ static: |-
+ <p data-sourcepos="1:1-1:23" dir="auto"><code>&lt;http://foo.bar.</code>baz&gt;`</p>
+ wysiwyg: |-
+ <p><code>&lt;http://foo.bar.</code>baz&gt;`</p>
+06_04_00__inlines__code_spans__019:
+ canonical: |
+ <p><a href="http://foo.bar.%60baz">http://foo.bar.`baz</a>`</p>
+ static: |-
+ <p data-sourcepos="1:1-1:22" dir="auto"><a href="http://foo.bar.%60baz" rel="nofollow noreferrer noopener" target="_blank">http://foo.bar.`baz</a>`</p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://foo.bar.%60baz">http://foo.bar.`baz</a>`</p>
+06_04_00__inlines__code_spans__020:
+ canonical: |
+ <p>```foo``</p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto">```foo``</p>
+ wysiwyg: |-
+ <p>```foo``</p>
+06_04_00__inlines__code_spans__021:
+ canonical: |
+ <p>`foo</p>
+ static: |-
+ <p data-sourcepos="1:1-1:4" dir="auto">`foo</p>
+ wysiwyg: |-
+ <p>`foo</p>
+06_04_00__inlines__code_spans__022:
+ canonical: |
+ <p>`foo<code>bar</code></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto">`foo<code>bar</code></p>
+ wysiwyg: |-
+ <p>`foo<code>bar</code></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__001:
+ canonical: |
+ <p><em>foo bar</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto"><em>foo bar</em></p>
+ wysiwyg: |-
+ <p><em>foo bar</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__002:
+ canonical: |
+ <p>a * foo bar*</p>
+ static: |-
+ <p data-sourcepos="1:1-1:12" dir="auto">a * foo bar*</p>
+ wysiwyg: |-
+ <p>a * foo bar*</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__003:
+ canonical: |
+ <p>a*&quot;foo&quot;*</p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto">a*"foo"*</p>
+ wysiwyg: |-
+ <p>a*"foo"*</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__004:
+ canonical: |
+ <p>* a *</p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto">* a *</p>
+ wysiwyg: |-
+ <p>*&nbsp;a&nbsp;*</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__005:
+ canonical: |
+ <p>foo<em>bar</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto">foo<em>bar</em></p>
+ wysiwyg: |-
+ <p>foo<em>bar</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__006:
+ canonical: |
+ <p>5<em>6</em>78</p>
+ static: |-
+ <p data-sourcepos="1:1-1:6" dir="auto">5<em>6</em>78</p>
+ wysiwyg: |-
+ <p>5<em>6</em>78</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__007:
+ canonical: |
+ <p><em>foo bar</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto"><em>foo bar</em></p>
+ wysiwyg: |-
+ <p><em>foo bar</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__008:
+ canonical: |
+ <p>_ foo bar_</p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto">_ foo bar_</p>
+ wysiwyg: |-
+ <p>_ foo bar_</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__009:
+ canonical: |
+ <p>a_&quot;foo&quot;_</p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto">a_"foo"_</p>
+ wysiwyg: |-
+ <p>a_"foo"_</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__010:
+ canonical: |
+ <p>foo_bar_</p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto">foo_bar_</p>
+ wysiwyg: |-
+ <p>foo_bar_</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__011:
+ canonical: |
+ <p>5_6_78</p>
+ static: |-
+ <p data-sourcepos="1:1-1:6" dir="auto">5_6_78</p>
+ wysiwyg: |-
+ <p>5_6_78</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__012:
+ canonical: |
+ <p>приÑтанÑм_ÑтремÑÑ‚ÑÑ_</p>
+ static: |-
+ <p data-sourcepos="1:1-1:38" dir="auto">приÑтанÑм_ÑтремÑÑ‚ÑÑ_</p>
+ wysiwyg: |-
+ <p>приÑтанÑм_ÑтремÑÑ‚ÑÑ_</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__013:
+ canonical: |
+ <p>aa_&quot;bb&quot;_cc</p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto">aa_"bb"_cc</p>
+ wysiwyg: |-
+ <p>aa_"bb"_cc</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__014:
+ canonical: |
+ <p>foo-<em>(bar)</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto">foo-<em>(bar)</em></p>
+ wysiwyg: |-
+ <p>foo-<em>(bar)</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__015:
+ canonical: |
+ <p>_foo*</p>
+ static: |-
+ <p data-sourcepos="1:1-1:5" dir="auto">_foo*</p>
+ wysiwyg: |-
+ <p>_foo*</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__016:
+ canonical: |
+ <p>*foo bar *</p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto">*foo bar *</p>
+ wysiwyg: |-
+ <p>*foo bar *</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__017:
+ canonical: |
+ <p>*foo bar
+ *</p>
+ static: |-
+ <p data-sourcepos="1:1-2:1" dir="auto">*foo bar
+ *</p>
+ wysiwyg: |-
+ <p>*foo bar
+ *</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__018:
+ canonical: |
+ <p>*(*foo)</p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto">*(*foo)</p>
+ wysiwyg: |-
+ <p>*(*foo)</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__019:
+ canonical: |
+ <p><em>(<em>foo</em>)</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto"><em>(<em>foo</em>)</em></p>
+ wysiwyg: |-
+ <p><em>(foo</em>)</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__020:
+ canonical: |
+ <p><em>foo</em>bar</p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto"><em>foo</em>bar</p>
+ wysiwyg: |-
+ <p><em>foo</em>bar</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__021:
+ canonical: |
+ <p>_foo bar _</p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto">_foo bar _</p>
+ wysiwyg: |-
+ <p>_foo bar _</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__022:
+ canonical: |
+ <p>_(_foo)</p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto">_(_foo)</p>
+ wysiwyg: |-
+ <p>_(_foo)</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__023:
+ canonical: |
+ <p><em>(<em>foo</em>)</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto"><em>(<em>foo</em>)</em></p>
+ wysiwyg: |-
+ <p><em>(foo</em>)</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__024:
+ canonical: |
+ <p>_foo_bar</p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto">_foo_bar</p>
+ wysiwyg: |-
+ <p>_foo_bar</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__025:
+ canonical: |
+ <p>_приÑтанÑм_ÑтремÑÑ‚ÑÑ</p>
+ static: |-
+ <p data-sourcepos="1:1-1:38" dir="auto">_приÑтанÑм_ÑтремÑÑ‚ÑÑ</p>
+ wysiwyg: |-
+ <p>_приÑтанÑм_ÑтремÑÑ‚ÑÑ</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__026:
+ canonical: |
+ <p><em>foo_bar_baz</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto"><em>foo_bar_baz</em></p>
+ wysiwyg: |-
+ <p><em>foo_bar_baz</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__027:
+ canonical: |
+ <p><em>(bar)</em>.</p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto"><em>(bar)</em>.</p>
+ wysiwyg: |-
+ <p><em>(bar)</em>.</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__028:
+ canonical: |
+ <p><strong>foo bar</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto"><strong>foo bar</strong></p>
+ wysiwyg: |-
+ <p><strong>foo bar</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__029:
+ canonical: |
+ <p>** foo bar**</p>
+ static: |-
+ <p data-sourcepos="1:1-1:12" dir="auto">** foo bar**</p>
+ wysiwyg: |-
+ <p>** foo bar**</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__030:
+ canonical: |
+ <p>a**&quot;foo&quot;**</p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto">a**"foo"**</p>
+ wysiwyg: |-
+ <p>a**"foo"**</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__031:
+ canonical: |
+ <p>foo<strong>bar</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto">foo<strong>bar</strong></p>
+ wysiwyg: |-
+ <p>foo<strong>bar</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__032:
+ canonical: |
+ <p><strong>foo bar</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto"><strong>foo bar</strong></p>
+ wysiwyg: |-
+ <p><strong>foo bar</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__033:
+ canonical: |
+ <p>__ foo bar__</p>
+ static: |-
+ <p data-sourcepos="1:1-1:12" dir="auto">__ foo bar__</p>
+ wysiwyg: |-
+ <p>__ foo bar__</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__034:
+ canonical: |
+ <p>__
+ foo bar__</p>
+ static: |-
+ <p data-sourcepos="1:1-2:9" dir="auto">__
+ foo bar__</p>
+ wysiwyg: |-
+ <p>__
+ foo bar__</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__035:
+ canonical: |
+ <p>a__&quot;foo&quot;__</p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto">a__"foo"__</p>
+ wysiwyg: |-
+ <p>a__"foo"__</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__036:
+ canonical: |
+ <p>foo__bar__</p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto">foo__bar__</p>
+ wysiwyg: |-
+ <p>foo__bar__</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__037:
+ canonical: |
+ <p>5__6__78</p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto">5__6__78</p>
+ wysiwyg: |-
+ <p>5__6__78</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__038:
+ canonical: |
+ <p>приÑтанÑм__ÑтремÑÑ‚ÑÑ__</p>
+ static: |-
+ <p data-sourcepos="1:1-1:40" dir="auto">приÑтанÑм__ÑтремÑÑ‚ÑÑ__</p>
+ wysiwyg: |-
+ <p>приÑтанÑм__ÑтремÑÑ‚ÑÑ__</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__039:
+ canonical: |
+ <p><strong>foo, <strong>bar</strong>, baz</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:21" dir="auto"><strong>foo, <strong>bar</strong>, baz</strong></p>
+ wysiwyg: |-
+ <p><strong>foo, bar</strong>, baz</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__040:
+ canonical: |
+ <p>foo-<strong>(bar)</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto">foo-<strong>(bar)</strong></p>
+ wysiwyg: |-
+ <p>foo-<strong>(bar)</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__041:
+ canonical: |
+ <p>**foo bar **</p>
+ static: |-
+ <p data-sourcepos="1:1-1:12" dir="auto">**foo bar **</p>
+ wysiwyg: |-
+ <p>**foo bar **</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__042:
+ canonical: |
+ <p>**(**foo)</p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto">**(**foo)</p>
+ wysiwyg: |-
+ <p>**(**foo)</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__043:
+ canonical: |
+ <p><em>(<strong>foo</strong>)</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto"><em>(<strong>foo</strong>)</em></p>
+ wysiwyg: |-
+ <p><em>(</em><strong><em>foo</em></strong><em>)</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__044:
+ canonical: |
+ <p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.
+ <em>Asclepias physocarpa</em>)</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-2:25" dir="auto"><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.
+ <em>Asclepias physocarpa</em>)</strong></p>
+ wysiwyg: |-
+ <p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.
+ <em>Asclepias physocarpa</em>)</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__045:
+ canonical: |
+ <p><strong>foo &quot;<em>bar</em>&quot; foo</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:19" dir="auto"><strong>foo "<em>bar</em>" foo</strong></p>
+ wysiwyg: |-
+ <p><strong>foo "<em>bar</em>" foo</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__046:
+ canonical: |
+ <p><strong>foo</strong>bar</p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto"><strong>foo</strong>bar</p>
+ wysiwyg: |-
+ <p><strong>foo</strong>bar</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__047:
+ canonical: |
+ <p>__foo bar __</p>
+ static: |-
+ <p data-sourcepos="1:1-1:12" dir="auto">__foo bar __</p>
+ wysiwyg: |-
+ <p>__foo bar __</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__048:
+ canonical: |
+ <p>__(__foo)</p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto">__(__foo)</p>
+ wysiwyg: |-
+ <p>__(__foo)</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__049:
+ canonical: |
+ <p><em>(<strong>foo</strong>)</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto"><em>(<strong>foo</strong>)</em></p>
+ wysiwyg: |-
+ <p><em>(</em><strong><em>foo</em></strong><em>)</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__050:
+ canonical: |
+ <p>__foo__bar</p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto">__foo__bar</p>
+ wysiwyg: |-
+ <p>__foo__bar</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__051:
+ canonical: |
+ <p>__приÑтанÑм__ÑтремÑÑ‚ÑÑ</p>
+ static: |-
+ <p data-sourcepos="1:1-1:40" dir="auto">__приÑтанÑм__ÑтремÑÑ‚ÑÑ</p>
+ wysiwyg: |-
+ <p>__приÑтанÑм__ÑтремÑÑ‚ÑÑ</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__052:
+ canonical: |
+ <p><strong>foo__bar__baz</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto"><strong>foo__bar__baz</strong></p>
+ wysiwyg: |-
+ <p><strong>foo__bar__baz</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__053:
+ canonical: |
+ <p><strong>(bar)</strong>.</p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto"><strong>(bar)</strong>.</p>
+ wysiwyg: |-
+ <p><strong>(bar)</strong>.</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__054:
+ canonical: |
+ <p><em>foo <a href="/url">bar</a></em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto"><em>foo <a href="/url">bar</a></em></p>
+ wysiwyg: |-
+ <p><em>foo </em><a target="_blank" rel="noopener noreferrer nofollow" href="/url"><em>bar</em></a></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__055:
+ canonical: |
+ <p><em>foo
+ bar</em></p>
+ static: |-
+ <p data-sourcepos="1:1-2:4" dir="auto"><em>foo
+ bar</em></p>
+ wysiwyg: |-
+ <p><em>foo
+ bar</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__056:
+ canonical: |
+ <p><em>foo <strong>bar</strong> baz</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto"><em>foo <strong>bar</strong> baz</em></p>
+ wysiwyg: |-
+ <p><em>foo </em><strong><em>bar</em></strong><em> baz</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__057:
+ canonical: |
+ <p><em>foo <em>bar</em> baz</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><em>foo <em>bar</em> baz</em></p>
+ wysiwyg: |-
+ <p><em>foo bar</em> baz</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__058:
+ canonical: |
+ <p><em><em>foo</em> bar</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto"><em><em>foo</em> bar</em></p>
+ wysiwyg: |-
+ <p><em>foo</em> bar</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__059:
+ canonical: |
+ <p><em>foo <em>bar</em></em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto"><em>foo <em>bar</em></em></p>
+ wysiwyg: |-
+ <p><em>foo bar</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__060:
+ canonical: |
+ <p><em>foo <strong>bar</strong> baz</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto"><em>foo <strong>bar</strong> baz</em></p>
+ wysiwyg: |-
+ <p><em>foo </em><strong><em>bar</em></strong><em> baz</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__061:
+ canonical: |
+ <p><em>foo<strong>bar</strong>baz</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><em>foo<strong>bar</strong>baz</em></p>
+ wysiwyg: |-
+ <p><em>foo</em><strong><em>bar</em></strong><em>baz</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__062:
+ canonical: |
+ <p><em>foo**bar</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto"><em>foo**bar</em></p>
+ wysiwyg: |-
+ <p><em>foo**bar</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__063:
+ canonical: |
+ <p><em><strong>foo</strong> bar</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto"><em><strong>foo</strong> bar</em></p>
+ wysiwyg: |-
+ <p><strong><em>foo</em></strong><em> bar</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__064:
+ canonical: |
+ <p><em>foo <strong>bar</strong></em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto"><em>foo <strong>bar</strong></em></p>
+ wysiwyg: |-
+ <p><em>foo </em><strong><em>bar</em></strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__065:
+ canonical: |
+ <p><em>foo<strong>bar</strong></em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:12" dir="auto"><em>foo<strong>bar</strong></em></p>
+ wysiwyg: |-
+ <p><em>foo</em><strong><em>bar</em></strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__066:
+ canonical: |
+ <p>foo<em><strong>bar</strong></em>baz</p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto">foo<em><strong>bar</strong></em>baz</p>
+ wysiwyg: |-
+ <p>foo<strong><em>bar</em></strong>baz</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__067:
+ canonical: |
+ <p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>
+ static: |-
+ <p data-sourcepos="1:1-1:24" dir="auto">foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>
+ wysiwyg: |-
+ <p>foo<strong>bar</strong>***baz</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__068:
+ canonical: |
+ <p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:27" dir="auto"><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>
+ wysiwyg: |-
+ <p><em>foo </em><strong><em>bar baz</em> bim</strong> bop</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__069:
+ canonical: |
+ <p><em>foo <a href="/url"><em>bar</em></a></em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:19" dir="auto"><em>foo <a href="/url"><em>bar</em></a></em></p>
+ wysiwyg: |-
+ <p><em>foo </em><a target="_blank" rel="noopener noreferrer nofollow" href="/url"><em>bar</em></a></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__070:
+ canonical: |
+ <p>** is not an empty emphasis</p>
+ static: |-
+ <p data-sourcepos="1:1-1:27" dir="auto">** is not an empty emphasis</p>
+ wysiwyg: |-
+ <p>** is not an empty emphasis</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__071:
+ canonical: |
+ <p>**** is not an empty strong emphasis</p>
+ static: |-
+ <p data-sourcepos="1:1-1:36" dir="auto">**** is not an empty strong emphasis</p>
+ wysiwyg: |-
+ <p>**** is not an empty strong emphasis</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__072:
+ canonical: |
+ <p><strong>foo <a href="/url">bar</a></strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:19" dir="auto"><strong>foo <a href="/url">bar</a></strong></p>
+ wysiwyg: |-
+ <p><strong>foo </strong><a target="_blank" rel="noopener noreferrer nofollow" href="/url"><strong>bar</strong></a></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__073:
+ canonical: |
+ <p><strong>foo
+ bar</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-2:5" dir="auto"><strong>foo
+ bar</strong></p>
+ wysiwyg: |-
+ <p><strong>foo
+ bar</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__074:
+ canonical: |
+ <p><strong>foo <em>bar</em> baz</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto"><strong>foo <em>bar</em> baz</strong></p>
+ wysiwyg: |-
+ <p><strong>foo <em>bar</em> baz</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__075:
+ canonical: |
+ <p><strong>foo <strong>bar</strong> baz</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:19" dir="auto"><strong>foo <strong>bar</strong> baz</strong></p>
+ wysiwyg: |-
+ <p><strong>foo bar</strong> baz</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__076:
+ canonical: |
+ <p><strong><strong>foo</strong> bar</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><strong><strong>foo</strong> bar</strong></p>
+ wysiwyg: |-
+ <p><strong>foo</strong> bar</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__077:
+ canonical: |
+ <p><strong>foo <strong>bar</strong></strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><strong>foo <strong>bar</strong></strong></p>
+ wysiwyg: |-
+ <p><strong>foo bar</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__078:
+ canonical: |
+ <p><strong>foo <em>bar</em> baz</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto"><strong>foo <em>bar</em> baz</strong></p>
+ wysiwyg: |-
+ <p><strong>foo <em>bar</em> baz</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__079:
+ canonical: |
+ <p><strong>foo<em>bar</em>baz</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><strong>foo<em>bar</em>baz</strong></p>
+ wysiwyg: |-
+ <p><strong>foo<em>bar</em>baz</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__080:
+ canonical: |
+ <p><strong><em>foo</em> bar</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto"><strong><em>foo</em> bar</strong></p>
+ wysiwyg: |-
+ <p><strong><em>foo</em> bar</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__081:
+ canonical: |
+ <p><strong>foo <em>bar</em></strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto"><strong>foo <em>bar</em></strong></p>
+ wysiwyg: |-
+ <p><strong>foo <em>bar</em></strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__082:
+ canonical: |
+ <p><strong>foo <em>bar <strong>baz</strong>
+ bim</em> bop</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-2:10" dir="auto"><strong>foo <em>bar <strong>baz</strong>
+ bim</em> bop</strong></p>
+ wysiwyg: |-
+ <p><strong>foo <em>bar baz</em></strong><em>
+ bim</em> bop</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__083:
+ canonical: |
+ <p><strong>foo <a href="/url"><em>bar</em></a></strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:21" dir="auto"><strong>foo <a href="/url"><em>bar</em></a></strong></p>
+ wysiwyg: |-
+ <p><strong>foo </strong><a target="_blank" rel="noopener noreferrer nofollow" href="/url"><strong><em>bar</em></strong></a></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__084:
+ canonical: |
+ <p>__ is not an empty emphasis</p>
+ static: |-
+ <p data-sourcepos="1:1-1:27" dir="auto">__ is not an empty emphasis</p>
+ wysiwyg: |-
+ <p>__ is not an empty emphasis</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__085:
+ canonical: |
+ <p>____ is not an empty strong emphasis</p>
+ static: |-
+ <p data-sourcepos="1:1-1:36" dir="auto">____ is not an empty strong emphasis</p>
+ wysiwyg: |-
+ <p>____ is not an empty strong emphasis</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__086:
+ canonical: |
+ <p>foo ***</p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto">foo ***</p>
+ wysiwyg: |-
+ <p>foo ***</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__087:
+ canonical: |
+ <p>foo <em>*</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto">foo <em>*</em></p>
+ wysiwyg: |-
+ <p>foo <em>*</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__088:
+ canonical: |
+ <p>foo <em>_</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto">foo <em>_</em></p>
+ wysiwyg: |-
+ <p>foo <em>_</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__089:
+ canonical: |
+ <p>foo *****</p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto">foo *****</p>
+ wysiwyg: |-
+ <p>foo *****</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__090:
+ canonical: |
+ <p>foo <strong>*</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto">foo <strong>*</strong></p>
+ wysiwyg: |-
+ <p>foo <strong>*</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__091:
+ canonical: |
+ <p>foo <strong>_</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto">foo <strong>_</strong></p>
+ wysiwyg: |-
+ <p>foo <strong>_</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__092:
+ canonical: |
+ <p>*<em>foo</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:6" dir="auto">*<em>foo</em></p>
+ wysiwyg: |-
+ <p>*<em>foo</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__093:
+ canonical: |
+ <p><em>foo</em>*</p>
+ static: |-
+ <p data-sourcepos="1:1-1:6" dir="auto"><em>foo</em>*</p>
+ wysiwyg: |-
+ <p><em>foo</em>*</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__094:
+ canonical: |
+ <p>*<strong>foo</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto">*<strong>foo</strong></p>
+ wysiwyg: |-
+ <p>*<strong>foo</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__095:
+ canonical: |
+ <p>***<em>foo</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto">***<em>foo</em></p>
+ wysiwyg: |-
+ <p>***<em>foo</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__096:
+ canonical: |
+ <p><strong>foo</strong>*</p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto"><strong>foo</strong>*</p>
+ wysiwyg: |-
+ <p><strong>foo</strong>*</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__097:
+ canonical: |
+ <p><em>foo</em>***</p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto"><em>foo</em>***</p>
+ wysiwyg: |-
+ <p><em>foo</em>***</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__098:
+ canonical: |
+ <p>foo ___</p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto">foo ___</p>
+ wysiwyg: |-
+ <p>foo ___</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__099:
+ canonical: |
+ <p>foo <em>_</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto">foo <em>_</em></p>
+ wysiwyg: |-
+ <p>foo <em>_</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__100:
+ canonical: |
+ <p>foo <em>*</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto">foo <em>*</em></p>
+ wysiwyg: |-
+ <p>foo <em>*</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__101:
+ canonical: |
+ <p>foo _____</p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto">foo _____</p>
+ wysiwyg: |-
+ <p>foo _____</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__102:
+ canonical: |
+ <p>foo <strong>_</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto">foo <strong>_</strong></p>
+ wysiwyg: |-
+ <p>foo <strong>_</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__103:
+ canonical: |
+ <p>foo <strong>*</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto">foo <strong>*</strong></p>
+ wysiwyg: |-
+ <p>foo <strong>*</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__104:
+ canonical: |
+ <p>_<em>foo</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:6" dir="auto">_<em>foo</em></p>
+ wysiwyg: |-
+ <p>_<em>foo</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__105:
+ canonical: |
+ <p><em>foo</em>_</p>
+ static: |-
+ <p data-sourcepos="1:1-1:6" dir="auto"><em>foo</em>_</p>
+ wysiwyg: |-
+ <p><em>foo</em>_</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__106:
+ canonical: |
+ <p>_<strong>foo</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto">_<strong>foo</strong></p>
+ wysiwyg: |-
+ <p>_<strong>foo</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__107:
+ canonical: |
+ <p>___<em>foo</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto">___<em>foo</em></p>
+ wysiwyg: |-
+ <p>___<em>foo</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__108:
+ canonical: |
+ <p><strong>foo</strong>_</p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto"><strong>foo</strong>_</p>
+ wysiwyg: |-
+ <p><strong>foo</strong>_</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__109:
+ canonical: |
+ <p><em>foo</em>___</p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto"><em>foo</em>___</p>
+ wysiwyg: |-
+ <p><em>foo</em>___</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__110:
+ canonical: |
+ <p><strong>foo</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto"><strong>foo</strong></p>
+ wysiwyg: |-
+ <p><strong>foo</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__111:
+ canonical: |
+ <p><em><em>foo</em></em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto"><em><em>foo</em></em></p>
+ wysiwyg: |-
+ <p><em>foo</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__112:
+ canonical: |
+ <p><strong>foo</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto"><strong>foo</strong></p>
+ wysiwyg: |-
+ <p><strong>foo</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__113:
+ canonical: |
+ <p><em><em>foo</em></em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto"><em><em>foo</em></em></p>
+ wysiwyg: |-
+ <p><em>foo</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__114:
+ canonical: |
+ <p><strong><strong>foo</strong></strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto"><strong><strong>foo</strong></strong></p>
+ wysiwyg: |-
+ <p><strong>foo</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__115:
+ canonical: |
+ <p><strong><strong>foo</strong></strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto"><strong><strong>foo</strong></strong></p>
+ wysiwyg: |-
+ <p><strong>foo</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__116:
+ canonical: |
+ <p><strong><strong><strong>foo</strong></strong></strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><strong><strong><strong>foo</strong></strong></strong></p>
+ wysiwyg: |-
+ <p><strong>foo</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__117:
+ canonical: |
+ <p><em><strong>foo</strong></em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto"><em><strong>foo</strong></em></p>
+ wysiwyg: |-
+ <p><strong><em>foo</em></strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__118:
+ canonical: |
+ <p><em><strong><strong>foo</strong></strong></em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto"><em><strong><strong>foo</strong></strong></em></p>
+ wysiwyg: |-
+ <p><strong><em>foo</em></strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__119:
+ canonical: |
+ <p><em>foo _bar</em> baz_</p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><em>foo _bar</em> baz_</p>
+ wysiwyg: |-
+ <p><em>foo _bar</em> baz_</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__120:
+ canonical: |
+ <p><em>foo <strong>bar *baz bim</strong> bam</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:26" dir="auto"><em>foo <strong>bar *baz bim</strong> bam</em></p>
+ wysiwyg: |-
+ <p><em>foo </em><strong><em>bar *baz bim</em></strong><em> bam</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__121:
+ canonical: |
+ <p>**foo <strong>bar baz</strong></p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto">**foo <strong>bar baz</strong></p>
+ wysiwyg: |-
+ <p>**foo <strong>bar baz</strong></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__122:
+ canonical: |
+ <p>*foo <em>bar baz</em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:14" dir="auto">*foo <em>bar baz</em></p>
+ wysiwyg: |-
+ <p>*foo <em>bar baz</em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__123:
+ canonical: |
+ <p>*<a href="/url">bar*</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto">*<a href="/url">bar*</a></p>
+ wysiwyg: |-
+ <p>*<a target="_blank" rel="noopener noreferrer nofollow" href="/url">bar*</a></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__124:
+ canonical: |
+ <p>_foo <a href="/url">bar_</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto">_foo <a href="/url">bar_</a></p>
+ wysiwyg: |-
+ <p>_foo <a target="_blank" rel="noopener noreferrer nofollow" href="/url">bar_</a></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__125:
+ canonical: |
+ <p>*<img src="foo" title="*"/></p>
+ static: |-
+ <p data-sourcepos="1:1-1:27" dir="auto">*<a class="no-attachment-icon" href="foo" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" title="*" decoding="async" class="lazy" data-src="foo"></a></p>
+ wysiwyg: |-
+ <p>*<img src="foo" title="*"></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__126:
+ canonical: |
+ <p>**<a href="**"></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto">**<a href="**"></a></p>
+ wysiwyg: |-
+ <p>**</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__127:
+ canonical: |
+ <p>__<a href="__"></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto">__<a href="__"></a></p>
+ wysiwyg: |-
+ <p>__</p>
+06_05_00__inlines__emphasis_and_strong_emphasis__128:
+ canonical: |
+ <p><em>a <code>*</code></em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto"><em>a <code>*</code></em></p>
+ wysiwyg: |-
+ <p><em>a <code>*</code></em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__129:
+ canonical: |
+ <p><em>a <code>_</code></em></p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto"><em>a <code>_</code></em></p>
+ wysiwyg: |-
+ <p><em>a <code>_</code></em></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__130:
+ canonical: |
+ <p>**a<a href="http://foo.bar/?q=**">http://foo.bar/?q=**</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:25" dir="auto">**a<a href="http://foo.bar/?q=**" rel="nofollow noreferrer noopener" target="_blank">http://foo.bar/?q=**</a></p>
+ wysiwyg: |-
+ <p>**a<a target="_blank" rel="noopener noreferrer nofollow" href="http://foo.bar/?q=**">http://foo.bar/?q=**</a></p>
+06_05_00__inlines__emphasis_and_strong_emphasis__131:
+ canonical: |
+ <p>__a<a href="http://foo.bar/?q=__">http://foo.bar/?q=__</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:25" dir="auto">__a<a href="http://foo.bar/?q=__" rel="nofollow noreferrer noopener" target="_blank">http://foo.bar/?q=__</a></p>
+ wysiwyg: |-
+ <p>__a<a target="_blank" rel="noopener noreferrer nofollow" href="http://foo.bar/?q=__">http://foo.bar/?q=__</a></p>
+06_06_00__inlines__strikethrough_extension__001:
+ canonical: |
+ <p><del>Hi</del> Hello, world!</p>
+ static: |-
+ <p data-sourcepos="1:1-1:20" dir="auto"><del>Hi</del> Hello, world!</p>
+ wysiwyg: |-
+ <p><s>Hi</s> Hello, world!</p>
+06_06_00__inlines__strikethrough_extension__002:
+ canonical: |
+ <p>This ~~has a</p>
+ <p>new paragraph~~.</p>
+ static: |-
+ <p data-sourcepos="1:1-1:12" dir="auto">This ~~has a</p>
+ <p data-sourcepos="3:1-3:16" dir="auto">new paragraph~~.</p>
+ wysiwyg: |-
+ <p>This ~~has a</p>
+ <p>new paragraph~~.</p>
+06_07_00__inlines__links__001:
+ canonical: |
+ <p><a href="/uri" title="title">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:20" dir="auto"><a href="/uri" title="title">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri" title="title">link</a></p>
+06_07_00__inlines__links__002:
+ canonical: |
+ <p><a href="/uri">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:12" dir="auto"><a href="/uri">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">link</a></p>
+06_07_00__inlines__links__003:
+ canonical: |
+ <p><a href="">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto"><a href="">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="">link</a></p>
+06_07_00__inlines__links__004:
+ canonical: |
+ <p><a href="">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto"><a href="">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="">link</a></p>
+06_07_00__inlines__links__005:
+ canonical: |
+ <p>[link](/my uri)</p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><a href="/my%20uri">link</a></p>
+ wysiwyg: |-
+ <p>[link](/my uri)</p>
+06_07_00__inlines__links__006:
+ canonical: |
+ <p><a href="/my%20uri">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto"><a href="/my%20uri">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/my%20uri">link</a></p>
+06_07_00__inlines__links__007:
+ canonical: |
+ <p>[link](foo
+ bar)</p>
+ static: |-
+ <p data-sourcepos="1:1-2:4" dir="auto">[link](foo
+ bar)</p>
+ wysiwyg: |-
+ <p>[link](foo
+ bar)</p>
+06_07_00__inlines__links__008:
+ canonical: |
+ <p>[link](<foo
+ bar>)</p>
+ static: |-
+ <p data-sourcepos="1:1-2:5" dir="auto">[link]()</p>
+ wysiwyg: |-
+ <p>[link](</p>
+06_07_00__inlines__links__009:
+ canonical: |
+ <p><a href="b)c">a</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto"><a href="b)c">a</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="b)c">a</a></p>
+06_07_00__inlines__links__010:
+ canonical: |
+ <p>[link](&lt;foo&gt;)</p>
+ static: |-
+ <p data-sourcepos="1:1-1:14" dir="auto"><a href="%3Cfoo%3E">link</a></p>
+ wysiwyg: |-
+ <p>[link](&lt;foo&gt;)</p>
+06_07_00__inlines__links__011:
+ canonical: |
+ <p>[a](&lt;b)c
+ [a](&lt;b)c&gt;
+ [a](<b>c)</p>
+ static: |-
+ <p data-sourcepos="1:1-3:9" dir="auto"><a href="%3Cb">a</a>c
+ <a href="%3Cb">a</a>c&gt;
+ [a](<b>c)</b></p>
+ wysiwyg: |-
+ <p>[a](&lt;b)c
+ [a](&lt;b)c&gt;
+ [a](<strong>c)</strong></p>
+06_07_00__inlines__links__012:
+ canonical: |
+ <p><a href="(foo)">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><a href="(foo)">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="(foo)">link</a></p>
+06_07_00__inlines__links__013:
+ canonical: |
+ <p><a href="foo(and(bar))">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:21" dir="auto"><a href="foo(and(bar))">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="foo(and(bar))">link</a></p>
+06_07_00__inlines__links__014:
+ canonical: |
+ <p><a href="foo(and(bar)">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:23" dir="auto"><a href="foo(and(bar)">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="foo(and(bar)">link</a></p>
+06_07_00__inlines__links__015:
+ canonical: |
+ <p><a href="foo(and(bar)">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:22" dir="auto"><a href="foo(and(bar)">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="foo(and(bar)">link</a></p>
+06_07_00__inlines__links__016:
+ canonical: |
+ <p><a href="foo):">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><a>link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="foo):">link</a></p>
+06_07_00__inlines__links__017:
+ canonical: |
+ <p><a href="#fragment">link</a></p>
+ <p><a href="http://example.com#fragment">link</a></p>
+ <p><a href="http://example.com?foo=3#frag">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto"><a href="#fragment">link</a></p>
+ <p data-sourcepos="3:1-3:35" dir="auto"><a href="http://example.com#fragment" rel="nofollow noreferrer noopener" target="_blank">link</a></p>
+ <p data-sourcepos="5:1-5:37" dir="auto"><a href="http://example.com?foo=3#frag" rel="nofollow noreferrer noopener" target="_blank">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="#fragment">link</a></p>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://example.com#fragment">link</a></p>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://example.com?foo=3#frag">link</a></p>
+06_07_00__inlines__links__018:
+ canonical: |
+ <p><a href="foo%5Cbar">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><a href="foo%5Cbar">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="foo%5Cbar">link</a></p>
+06_07_00__inlines__links__019:
+ canonical: |
+ <p><a href="foo%20b%C3%A4">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:21" dir="auto"><a href="foo%20b%C3%A4">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="foo%20b%C3%A4">link</a></p>
+06_07_00__inlines__links__020:
+ canonical: |
+ <p><a href="%22title%22">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><a href="%22title%22">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="%22title%22">link</a></p>
+06_07_00__inlines__links__021:
+ canonical: |
+ <p><a href="/url" title="title">link</a>
+ <a href="/url" title="title">link</a>
+ <a href="/url" title="title">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-3:20" dir="auto"><a href="/url" title="title">link</a>
+ <a href="/url" title="title">link</a>
+ <a href="/url" title="title">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">linklinklink</a></p>
+06_07_00__inlines__links__022:
+ canonical: |
+ <p><a href="/url" title="title &quot;&quot;">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:29" dir="auto"><a href="/url" title='title ""'>link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title &quot;&quot;">link</a></p>
+06_07_00__inlines__links__023:
+ canonical: |
+ <p><a href="/url%C2%A0%22title%22">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:21" dir="auto"><a href="/url%C2%A0%22title%22">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url%C2%A0%22title%22">link</a></p>
+06_07_00__inlines__links__024:
+ canonical: |
+ <p>[link](/url &quot;title &quot;and&quot; title&quot;)</p>
+ static: |-
+ <p data-sourcepos="1:1-1:32" dir="auto">[link](/url "title "and" title")</p>
+ wysiwyg: |-
+ <p>[link](/url "title "and" title")</p>
+06_07_00__inlines__links__025:
+ canonical: |
+ <p><a href="/url" title="title &quot;and&quot; title">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:32" dir="auto"><a href="/url" title='title "and" title'>link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title &quot;and&quot; title">link</a></p>
+06_07_00__inlines__links__026:
+ canonical: |
+ <p><a href="/uri" title="title">link</a></p>
+ static: |-
+ <p data-sourcepos="1:1-2:12" dir="auto"><a href="/uri" title="title">link</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri" title="title">link</a></p>
+06_07_00__inlines__links__027:
+ canonical: |
+ <p>[link] (/uri)</p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto">[link] (/uri)</p>
+ wysiwyg: |-
+ <p>[link] (/uri)</p>
+06_07_00__inlines__links__028:
+ canonical: |
+ <p><a href="/uri">link [foo [bar]]</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:24" dir="auto"><a href="/uri">link [foo [bar]]</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">link [foo [bar]]</a></p>
+06_07_00__inlines__links__029:
+ canonical: |
+ <p>[link] bar](/uri)</p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto">[link] bar](/uri)</p>
+ wysiwyg: |-
+ <p>[link] bar](/uri)</p>
+06_07_00__inlines__links__030:
+ canonical: |
+ <p>[link <a href="/uri">bar</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto">[link <a href="/uri">bar</a></p>
+ wysiwyg: |-
+ <p>[link <a target="_blank" rel="noopener noreferrer nofollow" href="/uri">bar</a></p>
+06_07_00__inlines__links__031:
+ canonical: |
+ <p><a href="/uri">link [bar</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:18" dir="auto"><a href="/uri">link [bar</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">link [bar</a></p>
+06_07_00__inlines__links__032:
+ canonical: |
+ <p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:30" dir="auto"><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">link <em>foo </em><strong><em>bar<code>#</code></em></strong></a></p>
+06_07_00__inlines__links__033:
+ canonical: |
+ <p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:25" dir="auto"><a href="/uri"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="moon" decoding="async" class="lazy" data-src="moon.jpg"></a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri"><img src="moon.jpg" alt="moon"></a></p>
+06_07_00__inlines__links__034:
+ canonical: |
+ <p>[foo <a href="/uri">bar</a>](/uri)</p>
+ static: |-
+ <p data-sourcepos="1:1-1:23" dir="auto">[foo <a href="/uri">bar</a>](/uri)</p>
+ wysiwyg: |-
+ <p>[foo <a target="_blank" rel="noopener noreferrer nofollow" href="/uri">bar</a>](/uri)</p>
+06_07_00__inlines__links__035:
+ canonical: |
+ <p>[foo <em>[bar <a href="/uri">baz</a>](/uri)</em>](/uri)</p>
+ static: |-
+ <p data-sourcepos="1:1-1:37" dir="auto">[foo <em>[bar <a href="/uri">baz</a>](/uri)</em>](/uri)</p>
+ wysiwyg: |-
+ <p>[foo <em>[bar </em><a target="_blank" rel="noopener noreferrer nofollow" href="/uri"><em>baz</em></a><em>](/uri)</em>](/uri)</p>
+06_07_00__inlines__links__036:
+ canonical: |
+ <p><img src="uri3" alt="[foo](uri2)" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:28" dir="auto"><a class="no-attachment-icon" href="uri3" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="[foo](uri2)" decoding="async" class="lazy" data-src="uri3"></a></p>
+ wysiwyg: |-
+ <p><img src="uri3" alt="[foo](uri2)"></p>
+06_07_00__inlines__links__037:
+ canonical: |
+ <p>*<a href="/uri">foo*</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto">*<a href="/uri">foo*</a></p>
+ wysiwyg: |-
+ <p>*<a target="_blank" rel="noopener noreferrer nofollow" href="/uri">foo*</a></p>
+06_07_00__inlines__links__038:
+ canonical: |
+ <p><a href="baz*">foo *bar</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:16" dir="auto"><a href="baz*">foo *bar</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="baz*">foo *bar</a></p>
+06_07_00__inlines__links__039:
+ canonical: |
+ <p><em>foo [bar</em> baz]</p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><em>foo [bar</em> baz]</p>
+ wysiwyg: |-
+ <p><em>foo [bar</em> baz]</p>
+06_07_00__inlines__links__040:
+ canonical: |
+ <p>[foo <bar attr="](baz)"></p>
+ static: |-
+ <p data-sourcepos="1:1-1:24" dir="auto">[foo </p>
+ wysiwyg: |-
+ <p>[foo </p>
+06_07_00__inlines__links__041:
+ canonical: |
+ <p>[foo<code>](/uri)</code></p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto">[foo<code>](/uri)</code></p>
+ wysiwyg: |-
+ <p>[foo<code>](/uri)</code></p>
+06_07_00__inlines__links__042:
+ canonical: |
+ <p>[foo<a href="http://example.com/?search=%5D(uri)">http://example.com/?search=](uri)</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:39" dir="auto">[foo<a href="http://example.com/?search=%5D(uri)" rel="nofollow noreferrer noopener" target="_blank">http://example.com/?search=](uri)</a></p>
+ wysiwyg: |-
+ <p>[foo<a target="_blank" rel="noopener noreferrer nofollow" href="http://example.com/?search=%5D(uri)">http://example.com/?search=](uri)</a></p>
+06_07_00__inlines__links__043:
+ canonical: |
+ <p><a href="/url" title="title">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto"><a href="/url" title="title">foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">foo</a></p>
+ <pre>[bar]: /url "title"</pre>
+06_07_00__inlines__links__044:
+ canonical: |
+ <p><a href="/uri">link [foo [bar]]</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:23" dir="auto"><a href="/uri">link [foo [bar]]</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">link [foo [bar]]</a></p>
+ <pre>[ref]: /uri</pre>
+06_07_00__inlines__links__045:
+ canonical: |
+ <p><a href="/uri">link [bar</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto"><a href="/uri">link [bar</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">link [bar</a></p>
+ <pre>[ref]: /uri</pre>
+06_07_00__inlines__links__046:
+ canonical: |
+ <p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:29" dir="auto"><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">link <em>foo </em><strong><em>bar<code>#</code></em></strong></a></p>
+ <pre>[ref]: /uri</pre>
+06_07_00__inlines__links__047:
+ canonical: |
+ <p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:24" dir="auto"><a href="/uri"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="moon" decoding="async" class="lazy" data-src="moon.jpg"></a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri"><img src="moon.jpg" alt="moon"></a></p>
+ <pre>[ref]: /uri</pre>
+06_07_00__inlines__links__048:
+ canonical: |
+ <p>[foo <a href="/uri">bar</a>]<a href="/uri">ref</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:22" dir="auto">[foo <a href="/uri">bar</a>]<a href="/uri">ref</a></p>
+ wysiwyg: |-
+ <p>[foo <a target="_blank" rel="noopener noreferrer nofollow" href="/uri">bar</a>]<a target="_blank" rel="noopener noreferrer nofollow" href="/uri">ref</a></p>
+ <pre>[ref]: /uri</pre>
+06_07_00__inlines__links__049:
+ canonical: |
+ <p>[foo <em>bar <a href="/uri">baz</a></em>]<a href="/uri">ref</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:27" dir="auto">[foo <em>bar <a href="/uri">baz</a></em>]<a href="/uri">ref</a></p>
+ wysiwyg: |-
+ <p>[foo <em>bar </em><a target="_blank" rel="noopener noreferrer nofollow" href="/uri"><em>baz</em></a>]<a target="_blank" rel="noopener noreferrer nofollow" href="/uri">ref</a></p>
+ <pre>[ref]: /uri</pre>
+06_07_00__inlines__links__050:
+ canonical: |
+ <p>*<a href="/uri">foo*</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:12" dir="auto">*<a href="/uri">foo*</a></p>
+ wysiwyg: |-
+ <p>*<a target="_blank" rel="noopener noreferrer nofollow" href="/uri">foo*</a></p>
+ <pre>[ref]: /uri</pre>
+06_07_00__inlines__links__051:
+ canonical: |
+ <p><a href="/uri">foo *bar</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><a href="/uri">foo *bar</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">foo *bar</a></p>
+ <pre>[ref]: /uri</pre>
+06_07_00__inlines__links__052:
+ canonical: |
+ <p>[foo <bar attr="][ref]"></p>
+ static: |-
+ <p data-sourcepos="1:1-1:24" dir="auto">[foo </p>
+ wysiwyg: |-
+ <p>[foo </p>
+ <pre>[ref]: /uri</pre>
+06_07_00__inlines__links__053:
+ canonical: |
+ <p>[foo<code>][ref]</code></p>
+ static: |-
+ <p data-sourcepos="1:1-1:12" dir="auto">[foo<code>][ref]</code></p>
+ wysiwyg: |-
+ <p>[foo<code>][ref]</code></p>
+ <pre>[ref]: /uri</pre>
+06_07_00__inlines__links__054:
+ canonical: |
+ <p>[foo<a href="http://example.com/?search=%5D%5Bref%5D">http://example.com/?search=][ref]</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:39" dir="auto">[foo<a href="http://example.com/?search=%5D%5Bref%5D" rel="nofollow noreferrer noopener" target="_blank">http://example.com/?search=][ref]</a></p>
+ wysiwyg: |-
+ <p>[foo<a target="_blank" rel="noopener noreferrer nofollow" href="http://example.com/?search=%5D%5Bref%5D">http://example.com/?search=][ref]</a></p>
+ <pre>[ref]: /uri</pre>
+06_07_00__inlines__links__055:
+ canonical: |
+ <p><a href="/url" title="title">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto"><a href="/url" title="title">foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">foo</a></p>
+ <pre>[bar]: /url "title"</pre>
+06_07_00__inlines__links__056:
+ canonical: |
+ <p><a href="/url">Толпой</a> is a Russian word.</p>
+ static: |-
+ <p data-sourcepos="1:1-1:47" dir="auto"><a href="/url">Толпой</a> is a Russian word.</p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url">Толпой</a> is a Russian word.</p>
+ <pre>[толпой]: /url</pre>
+06_07_00__inlines__links__057:
+ canonical: |
+ <p><a href="/url">Baz</a></p>
+ static: |-
+ <p data-sourcepos="4:1-4:14" dir="auto"><a href="/url">Baz</a></p>
+ wysiwyg: |-
+ <pre>[foo bar]: /url</pre>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url">Baz</a></p>
+06_07_00__inlines__links__058:
+ canonical: |
+ <p>[foo] <a href="/url" title="title">bar</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto">[foo] <a href="/url" title="title">bar</a></p>
+ wysiwyg: |-
+ <p>[foo] <a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">bar</a></p>
+ <pre>[bar]: /url "title"</pre>
+06_07_00__inlines__links__059:
+ canonical: |
+ <p>[foo]
+ <a href="/url" title="title">bar</a></p>
+ static: |-
+ <p data-sourcepos="1:1-2:5" dir="auto">[foo]
+ <a href="/url" title="title">bar</a></p>
+ wysiwyg: |-
+ <p>[foo]
+ <a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">bar</a></p>
+ <pre>[bar]: /url "title"</pre>
+06_07_00__inlines__links__060:
+ canonical: |
+ <p><a href="/url1">bar</a></p>
+ static: |-
+ <p data-sourcepos="5:1-5:10" dir="auto"><a href="/url1">bar</a></p>
+ wysiwyg: |-
+ <pre>[foo]: /url1</pre>
+ <pre>[foo]: /url2</pre>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url1">bar</a></p>
+06_07_00__inlines__links__061:
+ canonical: |
+ <p>[bar][foo!]</p>
+ static: |-
+ <p data-sourcepos="1:1-1:32" dir="auto">[bar][foo<span>!</span>]</p>
+ wysiwyg: |-
+ <p>[bar][foo!]</p>
+ <pre>[foo!]: /url</pre>
+06_07_00__inlines__links__062:
+ canonical: |
+ <p>[foo][ref[]</p>
+ <p>[ref[]: /uri</p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto">[foo][ref[]</p>
+ <p data-sourcepos="3:1-3:12" dir="auto">[ref[]: /uri</p>
+ wysiwyg: |-
+ <p>[foo][ref[]</p>
+ <p>[ref[]: /uri</p>
+06_07_00__inlines__links__063:
+ canonical: |
+ <p>[foo][ref[bar]]</p>
+ <p>[ref[bar]]: /uri</p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto">[foo][ref[bar]]</p>
+ <p data-sourcepos="3:1-3:16" dir="auto">[ref[bar]]: /uri</p>
+ wysiwyg: |-
+ <p>[foo][ref[bar]]</p>
+ <p>[ref[bar]]: /uri</p>
+06_07_00__inlines__links__064:
+ canonical: |
+ <p>[[[foo]]]</p>
+ <p>[[[foo]]]: /url</p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto">[[[foo]]]</p>
+ <p data-sourcepos="3:1-3:15" dir="auto">[[[foo]]]: /url</p>
+ wysiwyg: |-
+ <p>[[[foo]]]</p>
+ <p>[[[foo]]]: /url</p>
+06_07_00__inlines__links__065:
+ canonical: |
+ <p><a href="/uri">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:12" dir="auto"><a href="/uri">foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">foo</a></p>
+ <pre>[ref\[]: /uri</pre>
+06_07_00__inlines__links__066:
+ canonical: |
+ <p><a href="/uri">bar\</a></p>
+ static: |-
+ <p data-sourcepos="3:1-3:7" dir="auto"><a href="/uri">bar\</a></p>
+ wysiwyg: |-
+ <pre>[bar\\]: /uri</pre>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/uri">bar\</a></p>
+06_07_00__inlines__links__067:
+ canonical: |
+ <p>[]</p>
+ <p>[]: /uri</p>
+ static: |-
+ <p data-sourcepos="1:1-1:2" dir="auto">[]</p>
+ <p data-sourcepos="3:1-3:8" dir="auto">[]: /uri</p>
+ wysiwyg: |-
+ <p>[]</p>
+ <p>[]: /uri</p>
+06_07_00__inlines__links__068:
+ canonical: |
+ <p>[
+ ]</p>
+ <p>[
+ ]: /uri</p>
+ static: |-
+ <p data-sourcepos="1:1-2:2" dir="auto">[
+ ]</p>
+ <p data-sourcepos="4:1-5:8" dir="auto">[
+ ]: /uri</p>
+ wysiwyg: |-
+ <p>[
+ ]</p>
+ <p>[
+ ]: /uri</p>
+06_07_00__inlines__links__069:
+ canonical: |
+ <p><a href="/url" title="title">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto"><a href="/url" title="title">foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">foo</a></p>
+ <pre>[foo]: /url "title"</pre>
+06_07_00__inlines__links__070:
+ canonical: |
+ <p><a href="/url" title="title"><em>foo</em> bar</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto"><a href="/url" title="title"><em>foo</em> bar</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title"><em>foo</em> bar</a></p>
+ <pre>[*foo* bar]: /url "title"</pre>
+06_07_00__inlines__links__071:
+ canonical: |
+ <p><a href="/url" title="title">Foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto"><a href="/url" title="title">Foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">Foo</a></p>
+ <pre>[foo]: /url "title"</pre>
+06_07_00__inlines__links__072:
+ canonical: |
+ <p><a href="/url" title="title">foo</a>
+ []</p>
+ static: |-
+ <p data-sourcepos="1:1-2:2" dir="auto"><a href="/url" title="title">foo</a>
+ []</p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">foo</a>
+ []</p>
+ <pre>[foo]: /url "title"</pre>
+06_07_00__inlines__links__073:
+ canonical: |
+ <p><a href="/url" title="title">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:5" dir="auto"><a href="/url" title="title">foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">foo</a></p>
+ <pre>[foo]: /url "title"</pre>
+06_07_00__inlines__links__074:
+ canonical: |
+ <p><a href="/url" title="title"><em>foo</em> bar</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto"><a href="/url" title="title"><em>foo</em> bar</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title"><em>foo</em> bar</a></p>
+ <pre>[*foo* bar]: /url "title"</pre>
+06_07_00__inlines__links__075:
+ canonical: |
+ <p>[<a href="/url" title="title"><em>foo</em> bar</a>]</p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto">[<a href="/url" title="title"><em>foo</em> bar</a>]</p>
+ wysiwyg: |-
+ <p>[<a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title"><em>foo</em> bar</a>]</p>
+ <pre>[*foo* bar]: /url "title"</pre>
+06_07_00__inlines__links__076:
+ canonical: |
+ <p>[[bar <a href="/url">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto">[[bar <a href="/url">foo</a></p>
+ wysiwyg: |-
+ <p>[[bar <a target="_blank" rel="noopener noreferrer nofollow" href="/url">foo</a></p>
+ <pre>[foo]: /url</pre>
+06_07_00__inlines__links__077:
+ canonical: |
+ <p><a href="/url" title="title">Foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:5" dir="auto"><a href="/url" title="title">Foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">Foo</a></p>
+ <pre>[foo]: /url "title"</pre>
+06_07_00__inlines__links__078:
+ canonical: |
+ <p><a href="/url">foo</a> bar</p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto"><a href="/url">foo</a> bar</p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url">foo</a> bar</p>
+ <pre>[foo]: /url</pre>
+06_07_00__inlines__links__079:
+ canonical: |
+ <p>[foo]</p>
+ static: |-
+ <p data-sourcepos="1:1-1:6" dir="auto">[foo]</p>
+ wysiwyg: |-
+ <p>[foo]</p>
+ <pre>[foo]: /url "title"</pre>
+06_07_00__inlines__links__080:
+ canonical: |
+ <p>*<a href="/url">foo*</a></p>
+ static: |-
+ <p data-sourcepos="3:1-3:7" dir="auto">*<a href="/url">foo*</a></p>
+ wysiwyg: |-
+ <pre>[foo*]: /url</pre>
+ <p>*<a target="_blank" rel="noopener noreferrer nofollow" href="/url">foo*</a></p>
+06_07_00__inlines__links__081:
+ canonical: |
+ <p><a href="/url2">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:10" dir="auto"><a href="/url2">foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url2">foo</a></p>
+ <pre>[foo]: /url1</pre>
+ <pre>[bar]: /url2</pre>
+06_07_00__inlines__links__082:
+ canonical: |
+ <p><a href="/url1">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto"><a href="/url1">foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url1">foo</a></p>
+ <pre>[foo]: /url1</pre>
+06_07_00__inlines__links__083:
+ canonical: |
+ <p><a href="">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto"><a href="">foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="">foo</a></p>
+ <pre>[foo]: /url1</pre>
+06_07_00__inlines__links__084:
+ canonical: |
+ <p><a href="/url1">foo</a>(not a link)</p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto"><a href="/url1">foo</a>(not a link)</p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url1">foo</a>(not a link)</p>
+ <pre>[foo]: /url1</pre>
+06_07_00__inlines__links__085:
+ canonical: |
+ <p>[foo]<a href="/url">bar</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto">[foo]<a href="/url">bar</a></p>
+ wysiwyg: |-
+ <p>[foo]<a target="_blank" rel="noopener noreferrer nofollow" href="/url">bar</a></p>
+ <pre>[baz]: /url</pre>
+06_07_00__inlines__links__086:
+ canonical: |
+ <p><a href="/url2">foo</a><a href="/url1">baz</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto"><a href="/url2">foo</a><a href="/url1">baz</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="/url2">foo</a><a target="_blank" rel="noopener noreferrer nofollow" href="/url1">baz</a></p>
+ <pre>[baz]: /url1</pre>
+ <pre>[bar]: /url2</pre>
+06_07_00__inlines__links__087:
+ canonical: |
+ <p>[foo]<a href="/url1">bar</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto">[foo]<a href="/url1">bar</a></p>
+ wysiwyg: |-
+ <p>[foo]<a target="_blank" rel="noopener noreferrer nofollow" href="/url1">bar</a></p>
+ <pre>[baz]: /url1</pre>
+ <pre>[foo]: /url2</pre>
+06_08_00__inlines__images__001:
+ canonical: |
+ <p><img src="/url" alt="foo" title="title" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:20" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" title="title" decoding="async" class="lazy" data-src="/url"></a></p>
+ wysiwyg: |-
+ <p><img src="/url" alt="foo" title="title"></p>
+06_08_00__inlines__images__002:
+ canonical: |
+ <p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:12" dir="auto"><a class="no-attachment-icon" href="train.jpg" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" title="train &amp; tracks" decoding="async" class="lazy" data-src="train.jpg"></a></p>
+ wysiwyg: |-
+ <p><img src="train.jpg" alt="foo bar" title="train &amp; tracks"></p>
+ <pre>[foo *bar*]: train.jpg "train &amp; tracks"</pre>
+06_08_00__inlines__images__003:
+ canonical: |
+ <p><img src="/url2" alt="foo bar" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:26" dir="auto"><a class="no-attachment-icon" href="/url2" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" decoding="async" class="lazy" data-src="/url2"></a></p>
+ wysiwyg: |-
+ <p><img src="/url2" alt="foo bar"></p>
+06_08_00__inlines__images__004:
+ canonical: |
+ <p><img src="/url2" alt="foo bar" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:25" dir="auto"><a class="no-attachment-icon" href="/url2" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" decoding="async" class="lazy" data-src="/url2"></a></p>
+ wysiwyg: |-
+ <p><img src="/url2" alt="foo bar"></p>
+06_08_00__inlines__images__005:
+ canonical: |
+ <p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:14" dir="auto"><a class="no-attachment-icon" href="train.jpg" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" title="train &amp; tracks" decoding="async" class="lazy" data-src="train.jpg"></a></p>
+ wysiwyg: |-
+ <p><img src="train.jpg" alt="foo bar" title="train &amp; tracks"></p>
+ <pre>[foo *bar*]: train.jpg "train &amp; tracks"</pre>
+06_08_00__inlines__images__006:
+ canonical: |
+ <p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:20" dir="auto"><a class="no-attachment-icon" href="train.jpg" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" title="train &amp; tracks" decoding="async" class="lazy" data-src="train.jpg"></a></p>
+ wysiwyg: |-
+ <p><img src="train.jpg" alt="foo bar" title="train &amp; tracks"></p>
+ <pre>[foobar]: train.jpg "train &amp; tracks"</pre>
+06_08_00__inlines__images__007:
+ canonical: |
+ <p><img src="train.jpg" alt="foo" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto"><a class="no-attachment-icon" href="train.jpg" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" decoding="async" class="lazy" data-src="train.jpg"></a></p>
+ wysiwyg: |-
+ <p><img src="train.jpg" alt="foo"></p>
+06_08_00__inlines__images__008:
+ canonical: |
+ <p>My <img src="/path/to/train.jpg" alt="foo bar" title="title" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:45" dir="auto">My <a class="no-attachment-icon" href="/path/to/train.jpg" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" title="title" decoding="async" class="lazy" data-src="/path/to/train.jpg"></a></p>
+ wysiwyg: |-
+ <p>My <img src="/path/to/train.jpg" alt="foo bar" title="title"></p>
+06_08_00__inlines__images__009:
+ canonical: |
+ <p><img src="url" alt="foo" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto"><a class="no-attachment-icon" href="url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" decoding="async" class="lazy" data-src="url"></a></p>
+ wysiwyg: |-
+ <p><img src="url" alt="foo"></p>
+06_08_00__inlines__images__010:
+ canonical: |
+ <p><img src="/url" alt="" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="" decoding="async" class="lazy" data-src="/url"></a></p>
+ wysiwyg: |-
+ <p><img src="/url" alt=""></p>
+06_08_00__inlines__images__011:
+ canonical: |
+ <p><img src="/url" alt="foo" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" decoding="async" class="lazy" data-src="/url"></a></p>
+ wysiwyg: |-
+ <p><img src="/url" alt="foo"></p>
+ <pre>[bar]: /url</pre>
+06_08_00__inlines__images__012:
+ canonical: |
+ <p><img src="/url" alt="foo" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" decoding="async" class="lazy" data-src="/url"></a></p>
+ wysiwyg: |-
+ <p><img src="/url" alt="foo"></p>
+ <pre>[bar]: /url</pre>
+06_08_00__inlines__images__013:
+ canonical: |
+ <p><img src="/url" alt="foo" title="title" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" title="title" decoding="async" class="lazy" data-src="/url"></a></p>
+ wysiwyg: |-
+ <p><img src="/url" alt="foo" title="title"></p>
+ <pre>[foo]: /url "title"</pre>
+06_08_00__inlines__images__014:
+ canonical: |
+ <p><img src="/url" alt="foo bar" title="title" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:14" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" title="title" decoding="async" class="lazy" data-src="/url"></a></p>
+ wysiwyg: |-
+ <p><img src="/url" alt="foo bar" title="title"></p>
+ <pre>[*foo* bar]: /url "title"</pre>
+06_08_00__inlines__images__015:
+ canonical: |
+ <p><img src="/url" alt="Foo" title="title" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="Foo" title="title" decoding="async" class="lazy" data-src="/url"></a></p>
+ wysiwyg: |-
+ <p><img src="/url" alt="Foo" title="title"></p>
+ <pre>[foo]: /url "title"</pre>
+06_08_00__inlines__images__016:
+ canonical: |
+ <p><img src="/url" alt="foo" title="title" />
+ []</p>
+ static: |-
+ <p data-sourcepos="1:1-2:2" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" title="title" decoding="async" class="lazy" data-src="/url"></a>
+ []</p>
+ wysiwyg: |-
+ <p><img src="/url" alt="foo" title="title">
+ []</p>
+ <pre>[foo]: /url "title"</pre>
+06_08_00__inlines__images__017:
+ canonical: |
+ <p><img src="/url" alt="foo" title="title" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:6" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo" title="title" decoding="async" class="lazy" data-src="/url"></a></p>
+ wysiwyg: |-
+ <p><img src="/url" alt="foo" title="title"></p>
+ <pre>[foo]: /url "title"</pre>
+06_08_00__inlines__images__018:
+ canonical: |
+ <p><img src="/url" alt="foo bar" title="title" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:12" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="foo bar" title="title" decoding="async" class="lazy" data-src="/url"></a></p>
+ wysiwyg: |-
+ <p><img src="/url" alt="foo bar" title="title"></p>
+ <pre>[*foo* bar]: /url "title"</pre>
+06_08_00__inlines__images__019:
+ canonical: |
+ <p>![[foo]]</p>
+ <p>[[foo]]: /url &quot;title&quot;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:8" dir="auto">![[foo]]</p>
+ <p data-sourcepos="3:1-3:21" dir="auto">[[foo]]: /url "title"</p>
+ wysiwyg: |-
+ <p>![[foo]]</p>
+ <p>[[foo]]: /url "title"</p>
+06_08_00__inlines__images__020:
+ canonical: |
+ <p><img src="/url" alt="Foo" title="title" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:6" dir="auto"><a class="no-attachment-icon" href="/url" target="_blank" rel="noopener noreferrer"><img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" alt="Foo" title="title" decoding="async" class="lazy" data-src="/url"></a></p>
+ wysiwyg: |-
+ <p><img src="/url" alt="Foo" title="title"></p>
+ <pre>[foo]: /url "title"</pre>
+06_08_00__inlines__images__021:
+ canonical: |
+ <p>![foo]</p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto">![foo]</p>
+ wysiwyg: |-
+ <p>![foo]</p>
+ <pre>[foo]: /url "title"</pre>
+06_08_00__inlines__images__022:
+ canonical: |
+ <p>!<a href="/url" title="title">foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:27" dir="auto"><span>!</span><a href="/url" title="title">foo</a></p>
+ wysiwyg: |-
+ <p>!<a target="_blank" rel="noopener noreferrer nofollow" href="/url" title="title">foo</a></p>
+ <pre>[foo]: /url "title"</pre>
+06_09_00__inlines__autolinks__001:
+ canonical: |
+ <p><a href="http://foo.bar.baz">http://foo.bar.baz</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:20" dir="auto"><a href="http://foo.bar.baz" rel="nofollow noreferrer noopener" target="_blank">http://foo.bar.baz</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://foo.bar.baz">http://foo.bar.baz</a></p>
+06_09_00__inlines__autolinks__002:
+ canonical: |
+ <p><a href="http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean">http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:47" dir="auto"><a href="http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean" rel="nofollow noreferrer noopener" target="_blank">http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean">http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean</a></p>
+06_09_00__inlines__autolinks__003:
+ canonical: |
+ <p><a href="irc://foo.bar:2233/baz">irc://foo.bar:2233/baz</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:24" dir="auto"><a href="irc://foo.bar:2233/baz">irc://foo.bar:2233/baz</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow">irc://foo.bar:2233/baz</a></p>
+06_09_00__inlines__autolinks__004:
+ canonical: |
+ <p><a href="MAILTO:FOO@BAR.BAZ">MAILTO:FOO@BAR.BAZ</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:20" dir="auto"><a href="mailto:FOO@BAR.BAZ">MAILTO:FOO@BAR.BAZ</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="MAILTO:FOO@BAR.BAZ">MAILTO:FOO@BAR.BAZ</a></p>
+06_09_00__inlines__autolinks__005:
+ canonical: |
+ <p><a href="a+b+c:d">a+b+c:d</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto"><a href="a+b+c:d">a+b+c:d</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow">a+b+c:d</a></p>
+06_09_00__inlines__autolinks__006:
+ canonical: |
+ <p><a href="made-up-scheme://foo,bar">made-up-scheme://foo,bar</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:26" dir="auto"><a href="made-up-scheme://foo,bar">made-up-scheme://foo,bar</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow">made-up-scheme://foo,bar</a></p>
+06_09_00__inlines__autolinks__007:
+ canonical: |
+ <p><a href="http://../">http://../</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:12" dir="auto"><a href="http://../" rel="nofollow noreferrer noopener" target="_blank">http://../</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://../">http://../</a></p>
+06_09_00__inlines__autolinks__008:
+ canonical: |
+ <p><a href="localhost:5001/foo">localhost:5001/foo</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:20" dir="auto"><a href="localhost:5001/foo">localhost:5001/foo</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow">localhost:5001/foo</a></p>
+06_09_00__inlines__autolinks__009:
+ canonical: |
+ <p>&lt;http://foo.bar/baz bim&gt;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:24" dir="auto">&lt;<a href="http://foo.bar/baz" rel="nofollow noreferrer noopener" target="_blank">http://foo.bar/baz</a> bim&gt;</p>
+ wysiwyg: |-
+ <p>&lt;<a target="_blank" rel="noopener noreferrer nofollow" href="http://foo.bar/baz">http://foo.bar/baz</a> bim&gt;</p>
+06_09_00__inlines__autolinks__010:
+ canonical: |
+ <p><a href="http://example.com/%5C%5B%5C">http://example.com/\[\</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:24" dir="auto"><a href="http://example.com/%5C%5B%5C" rel="nofollow noreferrer noopener" target="_blank">http://example.com/\[\</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://example.com/%5C%5B%5C">http://example.com/\[\</a></p>
+06_09_00__inlines__autolinks__011:
+ canonical: |
+ <p><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:21" dir="auto"><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
+06_09_00__inlines__autolinks__012:
+ canonical: |
+ <p><a href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:30" dir="auto"><a href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p>
+06_09_00__inlines__autolinks__013:
+ canonical: |
+ <p>&lt;foo+@bar.example.com&gt;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:23" dir="auto">&lt;<a href="mailto:foo+@bar.example.com">foo+@bar.example.com</a>&gt;</p>
+ wysiwyg: |-
+ <p>&lt;<a target="_blank" rel="noopener noreferrer nofollow" href="mailto:foo+@bar.example.com">foo+@bar.example.com</a>&gt;</p>
+06_09_00__inlines__autolinks__014:
+ canonical: |
+ <p>&lt;&gt;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:2" dir="auto">&lt;&gt;</p>
+ wysiwyg: |-
+ <p>&lt;&gt;</p>
+06_09_00__inlines__autolinks__015:
+ canonical: |
+ <p>&lt; http://foo.bar &gt;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:18" dir="auto">&lt; <a href="http://foo.bar" rel="nofollow noreferrer noopener" target="_blank">http://foo.bar</a> &gt;</p>
+ wysiwyg: |-
+ <p>&lt; <a target="_blank" rel="noopener noreferrer nofollow" href="http://foo.bar">http://foo.bar</a> &gt;</p>
+06_09_00__inlines__autolinks__016:
+ canonical: |
+ <p>&lt;m:abc&gt;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:7" dir="auto">&lt;m:abc&gt;</p>
+ wysiwyg: |-
+ <p>&lt;m:abc&gt;</p>
+06_09_00__inlines__autolinks__017:
+ canonical: |
+ <p>&lt;foo.bar.baz&gt;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto">&lt;foo.bar.baz&gt;</p>
+ wysiwyg: |-
+ <p>&lt;foo.bar.baz&gt;</p>
+06_09_00__inlines__autolinks__018:
+ canonical: |
+ <p>http://example.com</p>
+ static: |-
+ <p data-sourcepos="1:1-1:18" dir="auto"><a href="http://example.com" rel="nofollow noreferrer noopener" target="_blank">http://example.com</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://example.com">http://example.com</a></p>
+06_09_00__inlines__autolinks__019:
+ canonical: |
+ <p>foo@bar.example.com</p>
+ static: |-
+ <p data-sourcepos="1:1-1:19" dir="auto"><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
+06_10_00__inlines__autolinks_extension__001:
+ canonical: |
+ <p><a href="http://www.commonmark.org">www.commonmark.org</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:18" dir="auto"><a href="http://www.commonmark.org" rel="nofollow noreferrer noopener" target="_blank">www.commonmark.org</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://www.commonmark.org">www.commonmark.org</a></p>
+06_10_00__inlines__autolinks_extension__002:
+ canonical: |
+ <p>Visit <a href="http://www.commonmark.org/help">www.commonmark.org/help</a> for more information.</p>
+ static: |-
+ <p data-sourcepos="1:1-1:51" dir="auto">Visit <a href="http://www.commonmark.org/help" rel="nofollow noreferrer noopener" target="_blank">www.commonmark.org/help</a> for more information.</p>
+ wysiwyg: |-
+ <p>Visit <a target="_blank" rel="noopener noreferrer nofollow" href="http://www.commonmark.org/help">www.commonmark.org/help</a> for more information.</p>
+06_10_00__inlines__autolinks_extension__003:
+ canonical: |
+ <p>Visit <a href="http://www.commonmark.org">www.commonmark.org</a>.</p>
+ <p>Visit <a href="http://www.commonmark.org/a.b">www.commonmark.org/a.b</a>.</p>
+ static: |-
+ <p data-sourcepos="1:1-1:25" dir="auto">Visit <a href="http://www.commonmark.org" rel="nofollow noreferrer noopener" target="_blank">www.commonmark.org</a>.</p>
+ <p data-sourcepos="3:1-3:29" dir="auto">Visit <a href="http://www.commonmark.org/a.b" rel="nofollow noreferrer noopener" target="_blank">www.commonmark.org/a.b</a>.</p>
+ wysiwyg: |-
+ <p>Visit <a target="_blank" rel="noopener noreferrer nofollow" href="http://www.commonmark.org">www.commonmark.org</a>.</p>
+ <p>Visit <a target="_blank" rel="noopener noreferrer nofollow" href="http://www.commonmark.org/a.b">www.commonmark.org/a.b</a>.</p>
+06_10_00__inlines__autolinks_extension__004:
+ canonical: |
+ <p><a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
+ <p><a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>))</p>
+ <p>(<a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>)</p>
+ <p>(<a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:41" dir="auto"><a href="http://www.google.com/search?q=Markup+(business)" rel="nofollow noreferrer noopener" target="_blank">www.google.com/search?q=Markup+(business)</a></p>
+ <p data-sourcepos="3:1-3:43" dir="auto"><a href="http://www.google.com/search?q=Markup+(business)" rel="nofollow noreferrer noopener" target="_blank">www.google.com/search?q=Markup+(business)</a>))</p>
+ <p data-sourcepos="5:1-5:43" dir="auto">(<a href="http://www.google.com/search?q=Markup+(business)" rel="nofollow noreferrer noopener" target="_blank">www.google.com/search?q=Markup+(business)</a>)</p>
+ <p data-sourcepos="7:1-7:42" dir="auto">(<a href="http://www.google.com/search?q=Markup+(business)" rel="nofollow noreferrer noopener" target="_blank">www.google.com/search?q=Markup+(business)</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>))</p>
+ <p>(<a target="_blank" rel="noopener noreferrer nofollow" href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>)</p>
+ <p>(<a target="_blank" rel="noopener noreferrer nofollow" href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
+06_10_00__inlines__autolinks_extension__005:
+ canonical: |
+ <p><a href="http://www.google.com/search?q=(business))+ok">www.google.com/search?q=(business))+ok</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:38" dir="auto"><a href="http://www.google.com/search?q=(business))+ok" rel="nofollow noreferrer noopener" target="_blank">www.google.com/search?q=(business))+ok</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://www.google.com/search?q=(business))+ok">www.google.com/search?q=(business))+ok</a></p>
+06_10_00__inlines__autolinks_extension__006:
+ canonical: |
+ <p><a href="http://www.google.com/search?q=commonmark&amp;hl=en">www.google.com/search?q=commonmark&amp;hl=en</a></p>
+ <p><a href="http://www.google.com/search?q=commonmark">www.google.com/search?q=commonmark</a>&amp;hl;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:40" dir="auto"><a href="http://www.google.com/search?q=commonmark&amp;hl=en" rel="nofollow noreferrer noopener" target="_blank">www.google.com/search?q=commonmark&amp;hl=en</a></p>
+ <p data-sourcepos="3:1-3:38" dir="auto"><a href="http://www.google.com/search?q=commonmark" rel="nofollow noreferrer noopener" target="_blank">www.google.com/search?q=commonmark</a>&amp;hl;</p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://www.google.com/search?q=commonmark&amp;hl=en">www.google.com/search?q=commonmark&amp;hl=en</a></p>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://www.google.com/search?q=commonmark">www.google.com/search?q=commonmark</a>&amp;hl;</p>
+06_10_00__inlines__autolinks_extension__007:
+ canonical: |
+ <p><a href="http://www.commonmark.org/he">www.commonmark.org/he</a>&lt;lp</p>
+ static: |-
+ <p data-sourcepos="1:1-1:24" dir="auto"><a href="http://www.commonmark.org/he" rel="nofollow noreferrer noopener" target="_blank">www.commonmark.org/he</a>&lt;lp</p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://www.commonmark.org/he">www.commonmark.org/he</a>&lt;lp</p>
+06_10_00__inlines__autolinks_extension__008:
+ canonical: |
+ <p><a href="http://commonmark.org">http://commonmark.org</a></p>
+ <p>(Visit <a href="https://encrypted.google.com/search?q=Markup+(business)">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>
+ <p>Anonymous FTP is available at <a href="ftp://foo.bar.baz">ftp://foo.bar.baz</a>.</p>
+ static: |-
+ <p data-sourcepos="1:1-1:21" dir="auto"><a href="http://commonmark.org" rel="nofollow noreferrer noopener" target="_blank">http://commonmark.org</a></p>
+ <p data-sourcepos="3:1-3:63" dir="auto">(Visit <a href="https://encrypted.google.com/search?q=Markup+(business)" rel="nofollow noreferrer noopener" target="_blank">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>
+ <p data-sourcepos="5:1-5:48" dir="auto">Anonymous FTP is available at <a href="ftp://foo.bar.baz/">ftp://foo.bar.baz</a>.</p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="http://commonmark.org">http://commonmark.org</a></p>
+ <p>(Visit <a target="_blank" rel="noopener noreferrer nofollow" href="https://encrypted.google.com/search?q=Markup+(business)">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>
+ <p>Anonymous FTP is available at ftp://foo.bar.baz.</p>
+06_10_00__inlines__autolinks_extension__009:
+ canonical: |
+ <p><a href="mailto:foo@bar.baz">foo@bar.baz</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto"><a href="mailto:foo@bar.baz">foo@bar.baz</a></p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="mailto:foo@bar.baz">foo@bar.baz</a></p>
+06_10_00__inlines__autolinks_extension__010:
+ canonical: |
+ <p>hello@mail+xyz.example isn't valid, but <a href="mailto:hello+xyz@mail.example">hello+xyz@mail.example</a> is.</p>
+ static: |-
+ <p data-sourcepos="1:1-1:66" dir="auto">hello@mail+xyz.example isn't valid, but <a href="mailto:hello+xyz@mail.example">hello+xyz@mail.example</a> is.</p>
+ wysiwyg: |-
+ <p>hello@mail+xyz.example isn't valid, but <a target="_blank" rel="noopener noreferrer nofollow" href="mailto:hello+xyz@mail.example">hello+xyz@mail.example</a> is.</p>
+06_10_00__inlines__autolinks_extension__011:
+ canonical: |
+ <p><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a></p>
+ <p><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a>.</p>
+ <p>a.b-c_d@a.b-</p>
+ <p>a.b-c_d@a.b_</p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto"><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a></p>
+ <p data-sourcepos="3:1-3:12" dir="auto"><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a>.</p>
+ <p data-sourcepos="5:1-5:12" dir="auto">a.b-c_d@a.b-</p>
+ <p data-sourcepos="7:1-7:12" dir="auto">a.b-c_d@a.b_</p>
+ wysiwyg: |-
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a></p>
+ <p><a target="_blank" rel="noopener noreferrer nofollow" href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a>.</p>
+ <p>a.b-c_d@a.b-</p>
+ <p>a.b-c_d@a.b_</p>
+06_11_00__inlines__raw_html__001:
+ canonical: |
+ <p><a><bab><c2c></p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto"><a></a></p>
+ wysiwyg: |-
+ <p></p>
+06_11_00__inlines__raw_html__002:
+ canonical: |
+ <p><a/><b2/></p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto"><a></a></p>
+ wysiwyg: |-
+ <p></p>
+06_11_00__inlines__raw_html__003:
+ canonical: |
+ <p><a /><b2
+ data="foo" ></p>
+ static: |-
+ <p data-sourcepos="1:1-2:12" dir="auto"><a></a></p>
+ wysiwyg: |-
+ <p></p>
+06_11_00__inlines__raw_html__004:
+ canonical: |
+ <p><a foo="bar" bam = 'baz <em>"</em>'
+ _boolean zoop:33=zoop:33 /></p>
+ static: |-
+ <p data-sourcepos="1:1-2:27" dir="auto"><a></a></p>
+ wysiwyg: |-
+ <p></p>
+06_11_00__inlines__raw_html__005:
+ canonical: |
+ <p>Foo <responsive-image src="foo.jpg" /></p>
+ static: |-
+ <p data-sourcepos="1:1-1:38" dir="auto">Foo </p>
+ wysiwyg: |-
+ <p>Foo </p>
+06_11_00__inlines__raw_html__006:
+ canonical: |
+ <p>&lt;33&gt; &lt;__&gt;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:9" dir="auto">&lt;33&gt; &lt;__&gt;</p>
+ wysiwyg: |-
+ <p>&lt;33&gt; &lt;__&gt;</p>
+06_11_00__inlines__raw_html__007:
+ canonical: |
+ <p>&lt;a h*#ref=&quot;hi&quot;&gt;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto">&lt;a h*#ref="hi"&gt;</p>
+ wysiwyg: |-
+ <p>&lt;a h*#ref="hi"&gt;</p>
+06_11_00__inlines__raw_html__008:
+ canonical: |
+ <p>&lt;a href=&quot;hi'&gt; &lt;a href=hi'&gt;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:26" dir="auto">&lt;a href="hi'&gt; &lt;a href=hi'&gt;</p>
+ wysiwyg: |-
+ <p>&lt;a href="hi'&gt; &lt;a href=hi'&gt;</p>
+06_11_00__inlines__raw_html__009:
+ canonical: |
+ <p>&lt; a&gt;&lt;
+ foo&gt;&lt;bar/ &gt;
+ &lt;foo bar=baz
+ bim!bop /&gt;</p>
+ static: |-
+ <p data-sourcepos="1:1-4:10" dir="auto">&lt; a&gt;&lt;
+ foo&gt;&lt;bar/ &gt;
+ &lt;foo bar=baz
+ bim!bop /&gt;</p>
+ wysiwyg: |-
+ <p>&lt; a&gt;&lt;
+ foo&gt;&lt;bar/ &gt;
+ &lt;foo bar=baz
+ bim!bop /&gt;</p>
+06_11_00__inlines__raw_html__010:
+ canonical: |
+ <p>&lt;a href='bar'title=title&gt;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:25" dir="auto">&lt;a href='bar'title=title&gt;</p>
+ wysiwyg: |-
+ <p>&lt;a href='bar'title=title&gt;</p>
+06_11_00__inlines__raw_html__011:
+ canonical: |
+ <p></a></foo ></p>
+ static: |-
+ <p data-sourcepos="1:1-1:11" dir="auto"></p>
+ wysiwyg: |-
+ <p></p>
+06_11_00__inlines__raw_html__012:
+ canonical: |
+ <p>&lt;/a href=&quot;foo&quot;&gt;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto">&lt;/a href="foo"&gt;</p>
+ wysiwyg: |-
+ <p>&lt;/a href="foo"&gt;</p>
+06_11_00__inlines__raw_html__013:
+ canonical: |
+ <p>foo <!-- this is a
+ comment - with hyphen --></p>
+ static: |-
+ <p data-sourcepos="1:1-2:25" dir="auto">foo </p>
+ wysiwyg: |-
+ <p>foo </p>
+06_11_00__inlines__raw_html__014:
+ canonical: |
+ <p>foo &lt;!-- not a comment -- two hyphens --&gt;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:41" dir="auto">foo &lt;!-- not a comment -- two hyphens --&gt;</p>
+ wysiwyg: |-
+ <p>foo &lt;!-- not a comment -- two hyphens --&gt;</p>
+06_11_00__inlines__raw_html__015:
+ canonical: |
+ <p>foo &lt;!--&gt; foo --&gt;</p>
+ <p>foo &lt;!-- foo---&gt;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto">foo &lt;!--&gt; foo --&gt;</p>
+ <p data-sourcepos="3:1-3:16" dir="auto">foo &lt;!-- foo---&gt;</p>
+ wysiwyg: |-
+ <p>foo &lt;!--&gt; foo --&gt;</p>
+ <p>foo &lt;!-- foo---&gt;</p>
+06_11_00__inlines__raw_html__016:
+ canonical: |
+ <p>foo <?php echo $a; ?></p>
+ static: |-
+ <p data-sourcepos="1:1-1:21" dir="auto">foo <?php echo $a; ?></p>
+ wysiwyg: |-
+ <p>foo </p>
+06_11_00__inlines__raw_html__017:
+ canonical: |
+ <p>foo <!ELEMENT br EMPTY></p>
+ static: |-
+ <p data-sourcepos="1:1-1:23" dir="auto">foo </p>
+ wysiwyg: |-
+ <p>foo </p>
+06_11_00__inlines__raw_html__018:
+ canonical: |
+ <p>foo <![CDATA[>&<]]></p>
+ static: |-
+ <p data-sourcepos="1:1-1:19" dir="auto">foo &amp;&lt;]]&gt;</p>
+ wysiwyg: |-
+ <p>foo &amp;&lt;]]&gt;</p>
+06_11_00__inlines__raw_html__019:
+ canonical: |
+ <p>foo <a href="&ouml;"></p>
+ static: |-
+ <p data-sourcepos="1:1-1:21" dir="auto">foo <a href="%C3%B6" rel="nofollow noreferrer noopener" target="_blank"></a></p>
+ wysiwyg: |-
+ <p>foo </p>
+06_11_00__inlines__raw_html__020:
+ canonical: |
+ <p>foo <a href="\*"></p>
+ static: |-
+ <p data-sourcepos="1:1-1:17" dir="auto">foo <a href="%5C*" rel="nofollow noreferrer noopener" target="_blank"></a></p>
+ wysiwyg: |-
+ <p>foo </p>
+06_11_00__inlines__raw_html__021:
+ canonical: |
+ <p>&lt;a href=&quot;&quot;&quot;&gt;</p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto">&lt;a href="""&gt;</p>
+ wysiwyg: |-
+ <p>&lt;a href="""&gt;</p>
+06_12_00__inlines__disallowed_raw_html_extension__001:
+ canonical: |
+ <p><strong> &lt;title> &lt;style> <em></p>
+ <blockquote>
+ &lt;xmp> is disallowed. &lt;XMP> is also disallowed.
+ </blockquote>
+ static: |-
+ <p data-sourcepos="1:1-1:29" dir="auto"><strong> &lt;em&gt;&lt;/p&gt;
+ &lt;blockquote&gt;
+ &lt;xmp&gt; is disallowed. &lt;XMP&gt; is also disallowed.
+ &lt;/blockquote&gt;</strong></p>
+ wysiwyg: |-
+ <p></p>
+ <blockquote multiline="false"><p></p></blockquote>
+06_13_00__inlines__hard_line_breaks__001:
+ canonical: |
+ <p>foo<br />
+ baz</p>
+ static: |-
+ <p data-sourcepos="1:1-2:3" dir="auto">foo<br>
+ baz</p>
+ wysiwyg: |-
+ <p>foo<br>
+ baz</p>
+06_13_00__inlines__hard_line_breaks__002:
+ canonical: |
+ <p>foo<br />
+ baz</p>
+ static: |-
+ <p data-sourcepos="1:1-2:3" dir="auto">foo<br>
+ baz</p>
+ wysiwyg: |-
+ <p>foo<br>
+ baz</p>
+06_13_00__inlines__hard_line_breaks__003:
+ canonical: |
+ <p>foo<br />
+ baz</p>
+ static: |-
+ <p data-sourcepos="1:1-2:3" dir="auto">foo<br>
+ baz</p>
+ wysiwyg: |-
+ <p>foo<br>
+ baz</p>
+06_13_00__inlines__hard_line_breaks__004:
+ canonical: |
+ <p>foo<br />
+ bar</p>
+ static: |-
+ <p data-sourcepos="1:1-2:8" dir="auto">foo<br>
+ bar</p>
+ wysiwyg: |-
+ <p>foo<br>
+ bar</p>
+06_13_00__inlines__hard_line_breaks__005:
+ canonical: |
+ <p>foo<br />
+ bar</p>
+ static: |-
+ <p data-sourcepos="1:1-2:8" dir="auto">foo<br>
+ bar</p>
+ wysiwyg: |-
+ <p>foo<br>
+ bar</p>
+06_13_00__inlines__hard_line_breaks__006:
+ canonical: |
+ <p><em>foo<br />
+ bar</em></p>
+ static: |-
+ <p data-sourcepos="1:1-2:4" dir="auto"><em>foo<br>
+ bar</em></p>
+ wysiwyg: |-
+ <p><em>foo<br>
+ bar</em></p>
+06_13_00__inlines__hard_line_breaks__007:
+ canonical: |
+ <p><em>foo<br />
+ bar</em></p>
+ static: |-
+ <p data-sourcepos="1:1-2:4" dir="auto"><em>foo<br>
+ bar</em></p>
+ wysiwyg: |-
+ <p><em>foo<br>
+ bar</em></p>
+06_13_00__inlines__hard_line_breaks__008:
+ canonical: |
+ <p><code>code span</code></p>
+ static: |-
+ <p data-sourcepos="1:1-2:5" dir="auto"><code>code span</code></p>
+ wysiwyg: |-
+ <p><code>code span</code></p>
+06_13_00__inlines__hard_line_breaks__009:
+ canonical: |
+ <p><code>code\ span</code></p>
+ static: |-
+ <p data-sourcepos="1:1-2:5" dir="auto"><code>code\ span</code></p>
+ wysiwyg: |-
+ <p><code>code\ span</code></p>
+06_13_00__inlines__hard_line_breaks__010:
+ canonical: "<p><a href=\"foo \nbar\"></p>\n"
+ static: |-
+ <p data-sourcepos="1:1-2:5" dir="auto"><a href="foo%20%20%0Abar" rel="nofollow noreferrer noopener" target="_blank"></a></p>
+ wysiwyg: |-
+ <p></p>
+06_13_00__inlines__hard_line_breaks__011:
+ canonical: |
+ <p><a href="foo\
+ bar"></p>
+ static: |-
+ <p data-sourcepos="1:1-2:5" dir="auto"><a href="foo%5C%0Abar" rel="nofollow noreferrer noopener" target="_blank"></a></p>
+ wysiwyg: |-
+ <p></p>
+06_13_00__inlines__hard_line_breaks__012:
+ canonical: |
+ <p>foo\</p>
+ static: |-
+ <p data-sourcepos="1:1-1:4" dir="auto">foo\</p>
+ wysiwyg: |-
+ <p>foo\</p>
+06_13_00__inlines__hard_line_breaks__013:
+ canonical: |
+ <p>foo</p>
+ static: |-
+ <p data-sourcepos="1:1-1:5" dir="auto">foo</p>
+ wysiwyg: |-
+ <p>foo</p>
+06_13_00__inlines__hard_line_breaks__014:
+ canonical: |
+ <h3>foo\</h3>
+ static: |-
+ <h3 data-sourcepos="1:1-1:8" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo\</h3>
+ wysiwyg: |-
+ <h3>foo\</h3>
+06_13_00__inlines__hard_line_breaks__015:
+ canonical: |
+ <h3>foo</h3>
+ static: |-
+ <h3 data-sourcepos="1:1-1:7" dir="auto">
+ <a id="user-content-foo" class="anchor" href="#foo" aria-hidden="true"></a>foo</h3>
+ wysiwyg: |-
+ <h3>foo</h3>
+06_14_00__inlines__soft_line_breaks__001:
+ canonical: |
+ <p>foo
+ baz</p>
+ static: |-
+ <p data-sourcepos="1:1-2:3" dir="auto">foo
+ baz</p>
+ wysiwyg: |-
+ <p>foo
+ baz</p>
+06_14_00__inlines__soft_line_breaks__002:
+ canonical: |
+ <p>foo
+ baz</p>
+ static: |-
+ <p data-sourcepos="1:1-2:4" dir="auto">foo
+ baz</p>
+ wysiwyg: |-
+ <p>foo
+ baz</p>
+06_15_00__inlines__textual_content__001:
+ canonical: |
+ <p>hello $.;'there</p>
+ static: |-
+ <p data-sourcepos="1:1-1:15" dir="auto">hello $.;'there</p>
+ wysiwyg: |-
+ <p>hello $.;'there</p>
+06_15_00__inlines__textual_content__002:
+ canonical: |
+ <p>Foo χÏῆν</p>
+ static: |-
+ <p data-sourcepos="1:1-1:13" dir="auto">Foo χÏῆν</p>
+ wysiwyg: |-
+ <p>Foo χÏῆν</p>
+06_15_00__inlines__textual_content__003:
+ canonical: |
+ <p>Multiple spaces</p>
+ static: |-
+ <p data-sourcepos="1:1-1:19" dir="auto">Multiple spaces</p>
+ wysiwyg: |-
+ <p>Multiple spaces</p>
+07_01_00__gitlab_official_specification_markdown__footnotes__001:
+ canonical: |
+ <p>
+ footnote reference tag
+ <sup>
+ <a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref>
+ 1
+ </a>
+ </sup>
+ </p>
+ <section data-footnotes>
+ <ol>
+ <li id="fn-fortytwo-42">
+ <p>
+ footnote text
+ <a href="#fnref-fortytwo-42" data-footnote-backref>
+ </a>
+ </p>
+ </li>
+ </ol>
+ </section>
+ static: |-
+ <p data-sourcepos="1:1-1:34" dir="auto">footnote reference tag <sup class="footnote-ref"><a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref>1</a></sup></p>
+ <section data-footnotes class="footnotes">
+ <ol>
+ <li id="fn-fortytwo-42">
+ <p data-sourcepos="3:14-3:26">footnote text <a href="#fnref-fortytwo-42" data-footnote-backref aria-label="Back to content" class="footnote-backref"><gl-emoji title="leftwards arrow with hook" data-name="leftwards_arrow_with_hook" data-unicode-version="1.1">↩</gl-emoji></a></p>
+ </li>
+ </ol>
+ </section>
+ wysiwyg: |-
+ <p>footnote reference tag <sup identifier="fortytwo">fortytwo</sup></p>
+ <div node="footnoteDefinition(paragraph(&quot;footnote text&quot;))" htmlattributes="[object Object]"><p>footnote text</p></div>
+07_02_00__gitlab_official_specification_markdown__task_list_items__001:
+ canonical: |
+ <ul>
+ <li>
+ <task-button/>
+ <input type="checkbox" disabled/>
+ incomplete
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-1:16" class="task-list" dir="auto">
+ <li data-sourcepos="1:1-1:16" class="task-list-item">
+ <task-button></task-button><input type="checkbox" class="task-list-item-checkbox" disabled> incomplete</li>
+ </ul>
+ wysiwyg: |-
+ <ul start="1" parens="false" data-type="taskList"><li data-checked="false" data-type="taskItem"><label><input type="checkbox"><span></span></label><div><p>incomplete</p></div></li></ul>
+07_02_00__gitlab_official_specification_markdown__task_list_items__002:
+ canonical: |
+ <ul>
+ <li>
+ <task-button/>
+ <input type="checkbox" checked disabled/>
+ completed
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-1:15" class="task-list" dir="auto">
+ <li data-sourcepos="1:1-1:15" class="task-list-item">
+ <task-button></task-button><input type="checkbox" class="task-list-item-checkbox" checked disabled> completed</li>
+ </ul>
+ wysiwyg: |-
+ <ul start="1" parens="false" data-type="taskList"><li data-checked="true" data-type="taskItem"><label><input type="checkbox" checked="checked"><span></span></label><div><p>completed</p></div></li></ul>
+07_02_00__gitlab_official_specification_markdown__task_list_items__003:
+ canonical: |
+ <ul>
+ <li>
+ <task-button/>
+ <input type="checkbox" data-inapplicable disabled>
+ <s>
+ inapplicable
+ </s>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-1:18" class="task-list" dir="auto">
+ <li data-sourcepos="1:1-1:18" class="task-list-item inapplicable">
+ <task-button></task-button><input type="checkbox" class="task-list-item-checkbox" data-inapplicable disabled> <s>inapplicable</s>
+ </li>
+ </ul>
+07_02_00__gitlab_official_specification_markdown__task_list_items__004:
+ canonical: |
+ <ul>
+ <li>
+ <p>
+ <task-button/>
+ <input type="checkbox" data-inapplicable disabled>
+ <s>
+ inapplicable
+ </s>
+ </p>
+ <p>
+ text in loose list
+ </p>
+ </li>
+ </ul>
+ static: |-
+ <ul data-sourcepos="1:1-3:20" class="task-list" dir="auto">
+ <li data-sourcepos="1:1-3:20" class="task-list-item inapplicable">
+ <p data-sourcepos="1:3-1:18"><task-button></task-button><input type="checkbox" class="task-list-item-checkbox" data-inapplicable disabled> <s>inapplicable</s></p>
+ <p data-sourcepos="3:3-3:20">text in loose list</p>
+ </li>
+ </ul>
+07_03_00__gitlab_official_specification_markdown__front_matter__001:
+ canonical: |
+ <pre>
+ <code>
+ title: YAML front matter
+ </code>
+ </pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-3:3" lang="yaml" class="code highlight js-syntax-highlight language-yaml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="yaml"><span class="na">title</span><span class="pi">:</span> <span class="s">YAML front matter</span></span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre language="yaml" class="content-editor-code-block undefined code highlight" isfrontmatter="true"><code>title: YAML front matter</code></pre>
+07_03_00__gitlab_official_specification_markdown__front_matter__002:
+ canonical: |
+ <pre>
+ <code>
+ title: TOML front matter
+ </code>
+ </pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-3:3" lang="toml" class="code highlight js-syntax-highlight language-toml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="toml"><span class="err">title:</span> <span class="err">TOML</span> <span class="err">front</span> <span class="err">matter</span></span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre language="toml" class="content-editor-code-block undefined code highlight" isfrontmatter="true"><code>title: TOML front matter</code></pre>
+07_03_00__gitlab_official_specification_markdown__front_matter__003:
+ canonical: |
+ <pre>
+ <code>
+ {
+ "title": "JSON front matter"
+ }
+ </code>
+ </pre>
+ static: |-
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-5:3" lang="json" class="code highlight js-syntax-highlight language-json" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="json"><span class="p">{</span></span>
+ <span id="LC2" class="line" lang="json"><span class="w"> </span><span class="nl">"title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"JSON front matter"</span></span>
+ <span id="LC3" class="line" lang="json"><span class="p">}</span></span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ wysiwyg: |-
+ <pre language="json" class="content-editor-code-block undefined code highlight" isfrontmatter="true"><code>{
+ "title": "JSON front matter"
+ }</code></pre>
+07_03_00__gitlab_official_specification_markdown__front_matter__004:
+ canonical: |
+ <p>text</p>
+ <hr>
+ <h2>title: YAML front matter</h2>
+ static: |-
+ <p data-sourcepos="1:1-1:4" dir="auto">text</p>
+ <hr data-sourcepos="3:1-3:3">
+ <h2 data-sourcepos="4:1-5:3" dir="auto">
+ <a id="user-content-title-yaml-front-matter" class="anchor" href="#title-yaml-front-matter" aria-hidden="true"></a>title: YAML front matter</h2>
+ wysiwyg: |-
+ <p>text</p>
+ <hr>
+ <h2>title: YAML front matter</h2>
+07_03_00__gitlab_official_specification_markdown__front_matter__005:
+ canonical: |
+ <hr>
+ <h2>title: YAML front matter</h2>
+ static: |-
+ <hr data-sourcepos="1:2-1:4">
+ <h2 data-sourcepos="2:1-3:3" dir="auto">
+ <a id="user-content-title-yaml-front-matter" class="anchor" href="#title-yaml-front-matter" aria-hidden="true"></a>title: YAML front matter</h2>
+ wysiwyg: |-
+ <hr>
+ <h2>title: YAML front matter</h2>
+07_04_00__gitlab_official_specification_markdown__table_of_contents__001:
+ canonical: |
+ <nav>
+ <ul>
+ <li><a href="#heading-1">Heading 1</a></li>
+ <ul>
+ <li><a href="#heading-2">Heading 2</a></li>
+ </ul>
+ </ul>
+ </nav>
+ <h1>Heading 1</h1>
+ <h2>Heading 2</h2>
+ static: |-
+ <ul class="section-nav"><li>
+ <a href="#heading-1">Heading 1</a><ul><li><a href="#heading-2">Heading 2</a></li></ul>
+ </li></ul>
+ <h1 data-sourcepos="3:1-3:11" dir="auto">
+ <a id="user-content-heading-1" class="anchor" href="#heading-1" aria-hidden="true"></a>Heading 1</h1>
+ <h2 data-sourcepos="5:1-5:12" dir="auto">
+ <a id="user-content-heading-2" class="anchor" href="#heading-2" aria-hidden="true"></a>Heading 2</h2>
+ wysiwyg: |-
+ <div class="table-of-contents gl-border-1 gl-border-solid gl-text-center gl-border-gray-100 gl-mb-5">Table of contents</div>
+ <h1>Heading 1</h1>
+ <h2>Heading 2</h2>
+07_04_00__gitlab_official_specification_markdown__table_of_contents__002:
+ canonical: |
+ <nav>
+ <ul>
+ <li><a href="#heading-1">Heading 1</a></li>
+ <ul>
+ <li><a href="#heading-2">Heading 2</a></li>
+ </ul>
+ </ul>
+ </nav>
+ <h1>Heading 1</h1>
+ <h2>Heading 2</h2>
+ static: |-
+ <ul class="section-nav"><li>
+ <a href="#heading-1">Heading 1</a><ul><li><a href="#heading-2">Heading 2</a></li></ul>
+ </li></ul>
+ <h1 data-sourcepos="3:1-3:11" dir="auto">
+ <a id="user-content-heading-1" class="anchor" href="#heading-1" aria-hidden="true"></a>Heading 1</h1>
+ <h2 data-sourcepos="5:1-5:12" dir="auto">
+ <a id="user-content-heading-2" class="anchor" href="#heading-2" aria-hidden="true"></a>Heading 2</h2>
+ wysiwyg: |-
+ <div class="table-of-contents gl-border-1 gl-border-solid gl-text-center gl-border-gray-100 gl-mb-5">Table of contents</div>
+ <h1>Heading 1</h1>
+ <h2>Heading 2</h2>
+07_04_00__gitlab_official_specification_markdown__table_of_contents__003:
+ canonical: |
+ <p>[[<em>TOC</em>]]text</p>
+ <p>text[TOC]</p>
+ static: |-
+ <p data-sourcepos="1:1-2:4" dir="auto">[[<em>TOC</em>]]
+ text</p>
+ <p data-sourcepos="4:1-5:5" dir="auto">text
+ [TOC]</p>
+ wysiwyg: |-
+ <p>[[<em>TOC</em>]]
+ text</p>
+ <p>text
+ [TOC]</p>
+07_04_00__gitlab_official_specification_markdown__table_of_contents__004:
+ canonical: |
+ <nav>
+ <ul>
+ <li><a href="#heading-1">Heading 1</a></li>
+ </ul>
+ </nav>
+ <h1>Heading 1</h1>
+ static: |-
+ <ul class="section-nav"><li><a href="#heading-1">Heading 1</a></li></ul>
+ <h1 data-sourcepos="3:1-3:11" dir="auto">
+ <a id="user-content-heading-1" class="anchor" href="#heading-1" aria-hidden="true"></a>Heading 1</h1>
+ wysiwyg: |-
+ <div class="table-of-contents gl-border-1 gl-border-solid gl-text-center gl-border-gray-100 gl-mb-5">Table of contents</div>
+ <h1>Heading 1</h1>
+08_01_00__gitlab_internal_extension_markdown__audio__001:
+ canonical: |
+ <p><audio src="audio.oga" title="audio title"></audio></p>
+ static: |-
+ <p data-sourcepos="1:1-1:33" dir="auto"><span class="media-container audio-container"><audio src="audio.oga" controls="true" data-setup="{}" data-title="audio title"></audio><a href="audio.oga" target="_blank" rel="noopener noreferrer" title="Download 'audio title'">audio title</a></span></p>
+ wysiwyg: |-
+ <p><span class="media-container audio-container"><audio src="audio.oga" controls="true" data-setup="{}" data-title="audio"></audio><a href="audio.oga">audio</a></span></p>
+08_01_00__gitlab_internal_extension_markdown__audio__002:
+ canonical: |
+ <p><audio src="audio.oga" title="audio title"></audio></p>
+ static: |-
+ <p data-sourcepos="3:1-3:15" dir="auto"><span class="media-container audio-container"><audio src="audio.oga" controls="true" data-setup="{}" data-title="audio title"></audio><a href="audio.oga" target="_blank" rel="noopener noreferrer" title="Download 'audio title'">audio title</a></span></p>
+ wysiwyg: |-
+ <pre>[audio]: audio.oga "audio title"</pre>
+ <p><span class="media-container audio-container"><audio src="audio.oga" controls="true" data-setup="{}" data-title="audio"></audio><a href="audio.oga">audio</a></span></p>
+08_02_00__gitlab_internal_extension_markdown__video__001:
+ canonical: |
+ <p><video src="video.m4v" title="video title"></video></p>
+ static: |-
+ <p data-sourcepos="1:1-1:33" dir="auto"><span class="media-container video-container"><video src="video.m4v" controls="true" data-setup="{}" data-title="video title" width="400" preload="metadata"></video><a href="video.m4v" target="_blank" rel="noopener noreferrer" title="Download 'video title'">video title</a></span></p>
+ wysiwyg: |-
+ <p><span class="media-container video-container"><video src="video.m4v" controls="true" data-setup="{}" data-title="video"></video><a href="video.m4v">video</a></span></p>
+08_02_00__gitlab_internal_extension_markdown__video__002:
+ canonical: |
+ <p><video src="video.mov" title="video title"></video></p>
+ static: |-
+ <p data-sourcepos="3:1-3:15" dir="auto"><span class="media-container video-container"><video src="video.mov" controls="true" data-setup="{}" data-title="video title" width="400" preload="metadata"></video><a href="video.mov" target="_blank" rel="noopener noreferrer" title="Download 'video title'">video title</a></span></p>
+ wysiwyg: |-
+ <pre>[video]: video.mov "video title"</pre>
+ <p><span class="media-container video-container"><video src="video.mov" controls="true" data-setup="{}" data-title="video"></video><a href="video.mov">video</a></span></p>
+08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__001:
+ canonical: |
+ <p><a href="groups-test-file">groups-test-file</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:45" dir="auto"><a href="/groups/glfm_group/-/uploads/groups-test-file" data-canonical-src="/uploads/groups-test-file" data-link="true" class="gfm">groups-test-file</a></p>
+08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__002:
+ canonical: |
+ <p><a href="projects-test-file">projects-test-file</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:40" dir="auto"><a href="/glfm_group/glfm_project/-/blob/master/projects-test-file" class="gfm">projects-test-file</a></p>
+08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__003:
+ canonical: |
+ <p>This project snippet ID reference IS filtered: $88888</p>
+ static: |-
+ <p data-sourcepos="1:1-1:53" dir="auto">This project snippet ID reference IS filtered: <a href="/glfm_group/glfm_project/-/snippets/88888" data-reference-type="snippet" data-original="$88888" data-link="false" data-link-reference="false" data-project="77777" data-snippet="88888" data-container="body" data-placement="top" title="glfm_project_snippet" class="gfm gfm-snippet has-tooltip">$88888</a></p>
+08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__004:
+ canonical: |
+ <p>This personal snippet ID reference is not filtered: $99999</p>
+ static: |-
+ <p data-sourcepos="1:1-1:58" dir="auto">This personal snippet ID reference is not filtered: $99999</p>
+08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__005:
+ canonical: |
+ <p><a href="project-wikis-test-file">project-wikis-test-file</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:50" dir="auto"><a href="/glfm_group/glfm_project/-/wikis/project-wikis-test-file" data-canonical-src="project-wikis-test-file">project-wikis-test-file</a></p>
+08_03_00__gitlab_internal_extension_markdown__markdown_preview_api_request_overrides__006:
+ canonical: |
+ <p><a href="group-wikis-test-file">group-wikis-test-file</a></p>
+ static: |-
+ <p data-sourcepos="1:1-1:46" dir="auto"><a href="/groups/glfm_group/-/wikis/group-wikis-test-file" data-canonical-src="group-wikis-test-file">group-wikis-test-file</a></p>
diff --git a/glfm_specification/example_snapshots/markdown.yml b/glfm_specification/output_example_snapshots/markdown.yml
index 867108a6cc5..867108a6cc5 100644
--- a/glfm_specification/example_snapshots/markdown.yml
+++ b/glfm_specification/output_example_snapshots/markdown.yml
diff --git a/glfm_specification/example_snapshots/prosemirror_json.yml b/glfm_specification/output_example_snapshots/prosemirror_json.yml
index de54518a574..de54518a574 100644
--- a/glfm_specification/example_snapshots/prosemirror_json.yml
+++ b/glfm_specification/output_example_snapshots/prosemirror_json.yml
diff --git a/glfm_specification/output_example_snapshots/snapshot_spec.html b/glfm_specification/output_example_snapshots/snapshot_spec.html
new file mode 100644
index 00000000000..20cfc4cf84f
--- /dev/null
+++ b/glfm_specification/output_example_snapshots/snapshot_spec.html
@@ -0,0 +1,10245 @@
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1:1-4:3" lang="yaml" class="code highlight js-syntax-highlight language-yaml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="yaml"><span class="na">title</span><span class="pi">:</span> <span class="s">GitLab Flavored Markdown (GLFM) Spec</span></span>
+<span id="LC2" class="line" lang="yaml"><span class="na">version</span><span class="pi">:</span> <span class="s">alpha</span></span></code></pre>
+<copy-code></copy-code>
+</div>
+<h1 data-sourcepos="5:1-5:15" dir="auto">
+<a id="user-content-preliminaries" class="anchor" href="#preliminaries" aria-hidden="true"></a>Preliminaries</h1>
+<h2 data-sourcepos="7:1-7:23" dir="auto">
+<a id="user-content-characters-and-lines" class="anchor" href="#characters-and-lines" aria-hidden="true"></a>Characters and lines</h2>
+<p data-sourcepos="9:1-10:9" dir="auto">Any sequence of [characters] is a valid CommonMark
+document.</p>
+<p data-sourcepos="12:1-15:26" dir="auto">A <a href="@">character</a> is a Unicode code point. Although some
+code points (for example, combining accents) do not correspond to
+characters in an intuitive sense, all code points count as characters
+for purposes of this spec.</p>
+<p data-sourcepos="17:1-19:22" dir="auto">This spec does not specify an encoding; it thinks of lines as composed
+of [characters] rather than bytes. A conforming parser may be limited
+to a certain encoding.</p>
+<p data-sourcepos="21:1-23:50" dir="auto">A <a href="@">line</a> is a sequence of zero or more [characters]
+other than newline (<code>U+000A</code>) or carriage return (<code>U+000D</code>),
+followed by a [line ending] or by the end of file.</p>
+<p data-sourcepos="25:1-27:18" dir="auto">A <a href="@">line ending</a> is a newline (<code>U+000A</code>), a carriage return
+(<code>U+000D</code>) not followed by a newline, or a carriage return and a
+following newline.</p>
+<p data-sourcepos="29:1-30:59" dir="auto">A line containing no characters, or a line containing only spaces
+(<code>U+0020</code>) or tabs (<code>U+0009</code>), is called a <a href="@">blank line</a>.</p>
+<p data-sourcepos="32:1-32:73" dir="auto">The following definitions of character classes will be used in this spec:</p>
+<p data-sourcepos="34:1-36:52" dir="auto">A <a href="@">whitespace character</a> is a space
+(<code>U+0020</code>), tab (<code>U+0009</code>), newline (<code>U+000A</code>), line tabulation (<code>U+000B</code>),
+form feed (<code>U+000C</code>), or carriage return (<code>U+000D</code>).</p>
+<p data-sourcepos="38:1-39:12" dir="auto"><a href="@">Whitespace</a> is a sequence of one or more [whitespace
+characters].</p>
+<p data-sourcepos="41:1-44:11" dir="auto">A <a href="@">Unicode whitespace character</a> is
+any code point in the Unicode <code>Zs</code> general category, or a tab (<code>U+0009</code>),
+carriage return (<code>U+000D</code>), newline (<code>U+000A</code>), or form feed
+(<code>U+000C</code>).</p>
+<p data-sourcepos="46:1-47:40" dir="auto"><a href="@">Unicode whitespace</a> is a sequence of one
+or more [Unicode whitespace characters].</p>
+<p data-sourcepos="49:1-49:25" dir="auto">A <a href="@">space</a> is <code>U+0020</code>.</p>
+<p data-sourcepos="51:1-52:37" dir="auto">A <a href="@">non-whitespace character</a> is any character
+that is not a [whitespace character].</p>
+<p data-sourcepos="54:1-59:38" dir="auto">An <a href="@">ASCII punctuation character</a>
+is <code>!</code>, <code>"</code>, <code>#</code>, <code>$</code>, <code>%</code>, <code>&amp;</code>, <code>'</code>, <code>(</code>, <code>)</code>,
+<code>*</code>, <code>+</code>, <code>,</code>, <code>-</code>, <code>.</code>, <code>/</code> (U+0021–2F),
+<code>:</code>, <code>;</code>, <code>&lt;</code>, <code>=</code>, <code>&gt;</code>, <code>?</code>, <code>@</code> (U+003A–0040),
+<code>[</code>, <code>\</code>, <code>]</code>, <code>^</code>, <code>_</code>, <code>`</code> (U+005B–0060),
+<code>{</code>, <code>|</code>, <code>}</code>, or <code>~</code> (U+007B–007E).</p>
+<p data-sourcepos="61:1-63:76" dir="auto">A <a href="@">punctuation character</a> is an [ASCII
+punctuation character] or anything in
+the general Unicode categories <code>Pc</code>, <code>Pd</code>, <code>Pe</code>, <code>Pf</code>, <code>Pi</code>, <code>Po</code>, or <code>Ps</code>.</p>
+<h2 data-sourcepos="65:1-65:7" dir="auto">
+<a id="user-content-tabs" class="anchor" href="#tabs" aria-hidden="true"></a>Tabs</h2>
+<p data-sourcepos="67:1-70:16" dir="auto">Tabs in lines are not expanded to [spaces]. However,
+in contexts where whitespace helps to define block structure,
+tabs behave as if they were replaced by spaces with a tab stop
+of 4 characters.</p>
+<p data-sourcepos="72:1-75:8" dir="auto">Thus, for example, a tab can be used instead of four spaces
+in an indented code block. (Note, however, that internal
+tabs are passed through as literal tabs, not expanded to
+spaces.)</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="77:1-79:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">→foo→baz→→bim</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="81:1-84:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo→baz→→bim</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="86:1-88:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> →foo→baz→→bim</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="90:1-93:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo→baz→→bim</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="95:1-98:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> a→a</span>
+<span id="LC2" class="line" lang="plaintext"> á½â†’a</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="100:1-104:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;a→a</span>
+<span id="LC2" class="line" lang="plaintext">á½â†’a</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="106:1-108:38" dir="auto">In the following example, a continuation paragraph of a list
+item is indented with a tab; this has exactly the same effect
+as indentation with four spaces would:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="110:1-114:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> - foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">→bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="116:1-123:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="125:1-129:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">→→bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="131:1-139:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt; bar</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="141:1-148:36" dir="auto">Normally the <code>&gt;</code> that begins a block quote may be followed
+optionally by a space, which is not considered part of the
+content. In the following case <code>&gt;</code> is followed by a tab,
+which is treated as if it were expanded into three spaces.
+Since one of these spaces is considered part of the
+delimiter, <code>foo</code> is considered to be indented six spaces
+inside the block quote context, so we get an indented
+code block starting with two spaces.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="150:1-152:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt;→→foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="154:1-159:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt; foo</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="161:1-163:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-→→foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="165:1-172:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt; foo</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="175:1-178:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span>
+<span id="LC2" class="line" lang="plaintext">→bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="180:1-184:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
+<span id="LC2" class="line" lang="plaintext">bar</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="186:1-190:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> - foo</span>
+<span id="LC2" class="line" lang="plaintext"> - bar</span>
+<span id="LC3" class="line" lang="plaintext">→ - baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="192:1-204:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo</span>
+<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;bar</span>
+<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;li&gt;baz&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="206:1-208:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">#→Foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="210:1-212:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="214:1-216:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*→*→*→</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="218:1-220:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="223:1-223:22" dir="auto">
+<a id="user-content-insecure-characters" class="anchor" href="#insecure-characters" aria-hidden="true"></a>Insecure characters</h2>
+<p data-sourcepos="225:1-226:42" dir="auto">For security reasons, the Unicode character <code>U+0000</code> must be replaced
+with the REPLACEMENT CHARACTER (<code>U+FFFD</code>).</p>
+<h1 data-sourcepos="228:1-228:20" dir="auto">
+<a id="user-content-blocks-and-inlines" class="anchor" href="#blocks-and-inlines" aria-hidden="true"></a>Blocks and inlines</h1>
+<p data-sourcepos="230:1-235:54" dir="auto">We can think of a document as a sequence of
+<a href="@">blocks</a>---structural elements like paragraphs, block
+quotations, lists, headings, rules, and code blocks. Some blocks (like
+block quotes and list items) contain other blocks; others (like
+headings and paragraphs) contain <a href="@">inline</a> content---text,
+links, emphasized text, images, code spans, and so on.</p>
+<h2 data-sourcepos="237:1-237:13" dir="auto">
+<a id="user-content-precedence" class="anchor" href="#precedence" aria-hidden="true"></a>Precedence</h2>
+<p data-sourcepos="239:1-241:59" dir="auto">Indicators of block structure always take precedence over indicators
+of inline structure. So, for example, the following is a list with
+two items, not a list with one item containing a code span:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="243:1-246:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- `one</span>
+<span id="LC2" class="line" lang="plaintext">- two`</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="248:1-253:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;`one&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;two`&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="256:1-263:66" dir="auto">This means that parsing can proceed in two steps: first, the block
+structure of the document can be discerned; second, text lines inside
+paragraphs, headings, and other block constructs can be parsed for inline
+structure. The second step requires information about link reference
+definitions that will be available only at the end of the first
+step. Note that the first step requires processing lines in sequence,
+but the second can be parallelized, since the inline parsing of
+one block element does not affect the inline parsing of any other.</p>
+<h2 data-sourcepos="265:1-265:35" dir="auto">
+<a id="user-content-container-blocks-and-leaf-blocks" class="anchor" href="#container-blocks-and-leaf-blocks" aria-hidden="true"></a>Container blocks and leaf blocks</h2>
+<p data-sourcepos="267:1-270:13" dir="auto">We can divide blocks into two types:
+<a href="@">container blocks</a>,
+which can contain other blocks, and <a href="@">leaf blocks</a>,
+which cannot.</p>
+<h1 data-sourcepos="272:1-272:13" dir="auto">
+<a id="user-content-leaf-blocks" class="anchor" href="#leaf-blocks" aria-hidden="true"></a>Leaf blocks</h1>
+<p data-sourcepos="274:1-275:18" dir="auto">This section describes the different kinds of leaf block that make up a
+Markdown document.</p>
+<h2 data-sourcepos="277:1-277:18" dir="auto">
+<a id="user-content-thematic-breaks" class="anchor" href="#thematic-breaks" aria-hidden="true"></a>Thematic breaks</h2>
+<p data-sourcepos="279:1-282:20" dir="auto">A line consisting of 0-3 spaces of indentation, followed by a sequence
+of three or more matching <code>-</code>, <code>_</code>, or <code>*</code> characters, each followed
+optionally by any number of spaces or tabs, forms a
+<a href="@">thematic break</a>.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="284:1-288:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">***</span>
+<span id="LC2" class="line" lang="plaintext">---</span>
+<span id="LC3" class="line" lang="plaintext">___</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="290:1-294:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;hr /&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;hr /&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="297:1-297:17" dir="auto">Wrong characters:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="299:1-301:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">+++</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="303:1-305:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;+++&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="308:1-310:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">===</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="312:1-314:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;===&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="317:1-317:22" dir="auto">Not enough characters:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="319:1-323:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">--</span>
+<span id="LC2" class="line" lang="plaintext">**</span>
+<span id="LC3" class="line" lang="plaintext">__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="325:1-329:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;--</span>
+<span id="LC2" class="line" lang="plaintext">**</span>
+<span id="LC3" class="line" lang="plaintext">__&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="332:1-332:39" dir="auto">One to three spaces indent are allowed:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="334:1-338:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ***</span>
+<span id="LC2" class="line" lang="plaintext"> ***</span>
+<span id="LC3" class="line" lang="plaintext"> ***</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="340:1-344:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;hr /&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;hr /&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="347:1-347:24" dir="auto">Four spaces is too many:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="349:1-351:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ***</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="353:1-356:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;***</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="359:1-362:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext"> ***</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="364:1-367:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo</span>
+<span id="LC2" class="line" lang="plaintext">***&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="370:1-370:39" dir="auto">More than three characters may be used:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="372:1-374:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_____________________________________</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="376:1-378:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="381:1-381:42" dir="auto">Spaces are allowed between the characters:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="383:1-385:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> - - -</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="387:1-389:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="392:1-394:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ** * ** * ** * **</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="396:1-398:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="401:1-403:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- - - -</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="405:1-407:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="410:1-410:30" dir="auto">Spaces are allowed at the end:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="412:1-414:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- - - - </span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="416:1-418:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="421:1-421:51" dir="auto">However, no other characters may occur in the line:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="423:1-429:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_ _ _ _ a</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">a------</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">---a---</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="431:1-435:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;_ _ _ _ a&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;a------&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;---a---&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="438:1-439:33" dir="auto">It is required that all of the [non-whitespace characters] be the same.
+So, this is not a thematic break:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="441:1-443:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> *-*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="445:1-447:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;-&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="450:1-450:56" dir="auto">Thematic breaks do not need blank lines before or after:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="452:1-456:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext">***</span>
+<span id="LC3" class="line" lang="plaintext">- bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="458:1-466:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;hr /&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="469:1-469:42" dir="auto">Thematic breaks can interrupt a paragraph:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="471:1-475:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext">***</span>
+<span id="LC3" class="line" lang="plaintext">bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="477:1-481:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;hr /&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="484:1-488:71" dir="auto">If a line of dashes that meets the above conditions for being a
+thematic break could also be interpreted as the underline of a [setext
+heading], the interpretation as a
+[setext heading] takes precedence. Thus, for example,
+this is a setext heading, not a paragraph followed by a thematic break:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="490:1-494:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext">---</span>
+<span id="LC3" class="line" lang="plaintext">bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="496:1-499:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h2&gt;Foo&lt;/h2&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="502:1-503:63" dir="auto">When both a thematic break and a list item are possible
+interpretations of a line, the thematic break takes precedence:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="505:1-509:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">* Foo</span>
+<span id="LC2" class="line" lang="plaintext">* * *</span>
+<span id="LC3" class="line" lang="plaintext">* Bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="511:1-519:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;Foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;hr /&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;li&gt;Bar&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="522:1-522:68" dir="auto">If you want a thematic break in a list item, use a different bullet:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="524:1-527:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- Foo</span>
+<span id="LC2" class="line" lang="plaintext">- * * *</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="529:1-536:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;Foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;hr /&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="539:1-539:15" dir="auto">
+<a id="user-content-atx-headings" class="anchor" href="#atx-headings" aria-hidden="true"></a>ATX headings</h2>
+<p data-sourcepos="541:1-551:35" dir="auto">An <a href="@">ATX heading</a>
+consists of a string of characters, parsed as inline content, between an
+opening sequence of 1--6 unescaped <code>#</code> characters and an optional
+closing sequence of any number of unescaped <code>#</code> characters.
+The opening sequence of <code>#</code> characters must be followed by a
+[space] or by the end of line. The optional closing sequence of <code>#</code>s must be
+preceded by a [space] and may be followed by spaces only. The opening
+<code>#</code> character may be indented 0-3 spaces. The raw contents of the
+heading are stripped of leading and trailing spaces before being parsed
+as inline content. The heading level is equal to the number of <code>#</code>
+characters in the opening sequence.</p>
+<p data-sourcepos="553:1-553:16" dir="auto">Simple headings:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="555:1-562:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># foo</span>
+<span id="LC2" class="line" lang="plaintext">## foo</span>
+<span id="LC3" class="line" lang="plaintext">### foo</span>
+<span id="LC4" class="line" lang="plaintext">#### foo</span>
+<span id="LC5" class="line" lang="plaintext">##### foo</span>
+<span id="LC6" class="line" lang="plaintext">###### foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="564:1-571:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h1&gt;foo&lt;/h1&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h2&gt;foo&lt;/h2&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;h3&gt;foo&lt;/h3&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;h4&gt;foo&lt;/h4&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;h5&gt;foo&lt;/h5&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;h6&gt;foo&lt;/h6&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="574:1-574:46" dir="auto">More than six <code>#</code> characters is not a heading:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="576:1-578:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">####### foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="580:1-582:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;####### foo&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="585:1-591:9" dir="auto">At least one space is required between the <code>#</code> characters and the
+heading's contents, unless the heading is empty. Note that many
+implementations currently do not require the space. However, the
+space was required by the
+<a href="http://www.aaronsw.com/2002/atx/atx.py" rel="nofollow noreferrer noopener" target="_blank">original ATX implementation</a>,
+and it helps prevent things like the following from being parsed as
+headings:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="593:1-597:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">#5 bolt</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">#hashtag</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="599:1-602:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;#5 bolt&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;#hashtag&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="605:1-605:56" dir="auto">This is not a heading, because the first <code>#</code> is escaped:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="607:1-609:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\## foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="611:1-613:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;## foo&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="616:1-616:31" dir="auto">Contents are parsed as inlines:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="618:1-620:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># foo *bar* \*baz\*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="622:1-624:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h1&gt;foo &lt;em&gt;bar&lt;/em&gt; *baz*&lt;/h1&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="627:1-627:71" dir="auto">Leading and trailing [whitespace] is ignored in parsing inline content:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="629:1-631:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># foo </span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="633:1-635:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h1&gt;foo&lt;/h1&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="638:1-638:44" dir="auto">One to three spaces indentation are allowed:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="640:1-644:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ### foo</span>
+<span id="LC2" class="line" lang="plaintext"> ## foo</span>
+<span id="LC3" class="line" lang="plaintext"> # foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="646:1-650:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h3&gt;foo&lt;/h3&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h2&gt;foo&lt;/h2&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;h1&gt;foo&lt;/h1&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="653:1-653:25" dir="auto">Four spaces are too much:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="655:1-657:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> # foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="659:1-662:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;# foo</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="665:1-668:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span>
+<span id="LC2" class="line" lang="plaintext"> # bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="670:1-673:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo</span>
+<span id="LC2" class="line" lang="plaintext"># bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="676:1-676:49" dir="auto">A closing sequence of <code>#</code> characters is optional:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="678:1-681:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">## foo ##</span>
+<span id="LC2" class="line" lang="plaintext"> ### bar ###</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="683:1-686:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h2&gt;foo&lt;/h2&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h3&gt;bar&lt;/h3&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="689:1-689:55" dir="auto">It need not be the same length as the opening sequence:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="691:1-694:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># foo ##################################</span>
+<span id="LC2" class="line" lang="plaintext">##### foo ##</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="696:1-699:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h1&gt;foo&lt;/h1&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h5&gt;foo&lt;/h5&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="702:1-702:46" dir="auto">Spaces are allowed after the closing sequence:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="704:1-706:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">### foo ### </span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="708:1-710:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h3&gt;foo&lt;/h3&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="713:1-715:8" dir="auto">A sequence of <code>#</code> characters with anything but [spaces] following it
+is not a closing sequence, but counts as part of the contents of the
+heading:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="717:1-719:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">### foo ### b</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="721:1-723:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h3&gt;foo ### b&lt;/h3&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="726:1-726:49" dir="auto">The closing sequence must be preceded by a space:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="728:1-730:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># foo#</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="732:1-734:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h1&gt;foo#&lt;/h1&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="737:1-738:24" dir="auto">Backslash-escaped <code>#</code> characters do not count as part
+of the closing sequence:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="740:1-744:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">### foo \###</span>
+<span id="LC2" class="line" lang="plaintext">## foo #\##</span>
+<span id="LC3" class="line" lang="plaintext"># foo \#</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="746:1-750:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h3&gt;foo ###&lt;/h3&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h2&gt;foo ###&lt;/h2&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;h1&gt;foo #&lt;/h1&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="753:1-754:41" dir="auto">ATX headings need not be separated from surrounding content by blank
+lines, and they can interrupt paragraphs:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="756:1-760:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">****</span>
+<span id="LC2" class="line" lang="plaintext">## foo</span>
+<span id="LC3" class="line" lang="plaintext">****</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="762:1-766:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;hr /&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h2&gt;foo&lt;/h2&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="769:1-773:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo bar</span>
+<span id="LC2" class="line" lang="plaintext"># baz</span>
+<span id="LC3" class="line" lang="plaintext">Bar foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="775:1-779:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo bar&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h1&gt;baz&lt;/h1&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;Bar foo&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="782:1-782:26" dir="auto">ATX headings can be empty:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="784:1-788:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">## </span>
+<span id="LC2" class="line" lang="plaintext">#</span>
+<span id="LC3" class="line" lang="plaintext">### ###</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="790:1-794:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h2&gt;&lt;/h2&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h1&gt;&lt;/h1&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;h3&gt;&lt;/h3&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="797:1-797:18" dir="auto">
+<a id="user-content-setext-headings" class="anchor" href="#setext-headings" aria-hidden="true"></a>Setext headings</h2>
+<p data-sourcepos="799:1-807:54" dir="auto">A <a href="@">setext heading</a> consists of one or more
+lines of text, each containing at least one [non-whitespace
+character], with no more than 3 spaces indentation, followed by
+a [setext heading underline]. The lines of text must be such
+that, were they not followed by the setext heading underline,
+they would be interpreted as a paragraph: they cannot be
+interpretable as a [code fence], [ATX heading][ATX headings],
+[block quote][block quotes], [thematic break][thematic breaks],
+[list item][list items], or [HTML block][HTML blocks].</p>
+<p data-sourcepos="809:1-814:40" dir="auto">A <a href="@">setext heading underline</a> is a sequence of
+<code>=</code> characters or a sequence of <code>-</code> characters, with no more than 3
+spaces indentation and any number of trailing spaces. If a line
+containing a single <code>-</code> can be interpreted as an
+empty [list items], it should be interpreted this way
+and not as a [setext heading underline].</p>
+<p data-sourcepos="816:1-820:8" dir="auto">The heading is a level 1 heading if <code>=</code> characters are used in
+the [setext heading underline], and a level 2 heading if <code>-</code>
+characters are used. The contents of the heading are the result
+of parsing the preceding lines of text as CommonMark inline
+content.</p>
+<p data-sourcepos="822:1-825:5" dir="auto">In general, a setext heading need not be preceded or followed by a
+blank line. However, it cannot interrupt a paragraph, so when a
+setext heading comes after a paragraph, a blank line is needed between
+them.</p>
+<p data-sourcepos="827:1-827:16" dir="auto">Simple examples:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="829:1-835:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo *bar*</span>
+<span id="LC2" class="line" lang="plaintext">=========</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">Foo *bar*</span>
+<span id="LC5" class="line" lang="plaintext">---------</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="837:1-840:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h1&gt;Foo &lt;em&gt;bar&lt;/em&gt;&lt;/h1&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h2&gt;Foo &lt;em&gt;bar&lt;/em&gt;&lt;/h2&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="843:1-843:54" dir="auto">The content of the header may span more than one line:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="845:1-849:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo *bar</span>
+<span id="LC2" class="line" lang="plaintext">baz*</span>
+<span id="LC3" class="line" lang="plaintext">====</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="851:1-854:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h1&gt;Foo &lt;em&gt;bar</span>
+<span id="LC2" class="line" lang="plaintext">baz&lt;/em&gt;&lt;/h1&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="856:1-859:13" dir="auto">The contents are the result of parsing the headings's raw
+content as inlines. The heading's raw content is formed by
+concatenating the lines and removing initial and final
+[whitespace].</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="861:1-865:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> Foo *bar</span>
+<span id="LC2" class="line" lang="plaintext">baz*→</span>
+<span id="LC3" class="line" lang="plaintext">====</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="867:1-870:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h1&gt;Foo &lt;em&gt;bar</span>
+<span id="LC2" class="line" lang="plaintext">baz&lt;/em&gt;&lt;/h1&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="873:1-873:34" dir="auto">The underlining can be any length:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="875:1-881:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext">-------------------------</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">Foo</span>
+<span id="LC5" class="line" lang="plaintext">=</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="883:1-886:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h2&gt;Foo&lt;/h2&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="889:1-890:33" dir="auto">The heading content can be indented up to three spaces, and need
+not line up with the underlining:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="892:1-901:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> Foo</span>
+<span id="LC2" class="line" lang="plaintext">---</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> Foo</span>
+<span id="LC5" class="line" lang="plaintext">-----</span>
+<span id="LC6" class="line" lang="plaintext"></span>
+<span id="LC7" class="line" lang="plaintext"> Foo</span>
+<span id="LC8" class="line" lang="plaintext"> ===</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="903:1-907:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h2&gt;Foo&lt;/h2&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h2&gt;Foo&lt;/h2&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="910:1-910:31" dir="auto">Four spaces indent is too much:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="912:1-918:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> Foo</span>
+<span id="LC2" class="line" lang="plaintext"> ---</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> Foo</span>
+<span id="LC5" class="line" lang="plaintext">---</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="920:1-927:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;Foo</span>
+<span id="LC2" class="line" lang="plaintext">---</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">Foo</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="930:1-931:25" dir="auto">The setext heading underline can be indented up to three spaces, and
+may have trailing spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="933:1-936:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext"> ---- </span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="938:1-940:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h2&gt;Foo&lt;/h2&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="943:1-943:24" dir="auto">Four spaces is too much:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="945:1-948:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext"> ---</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="950:1-953:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo</span>
+<span id="LC2" class="line" lang="plaintext">---&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="956:1-956:60" dir="auto">The setext heading underline cannot contain internal spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="958:1-964:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext">= =</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">Foo</span>
+<span id="LC5" class="line" lang="plaintext">--- -</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="966:1-971:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo</span>
+<span id="LC2" class="line" lang="plaintext">= =&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;Foo&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="974:1-974:62" dir="auto">Trailing spaces in the content line do not cause a line break:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="976:1-979:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo </span>
+<span id="LC2" class="line" lang="plaintext">-----</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="981:1-983:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h2&gt;Foo&lt;/h2&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="986:1-986:32" dir="auto">Nor does a backslash at the end:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="988:1-991:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo\</span>
+<span id="LC2" class="line" lang="plaintext">----</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="993:1-995:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h2&gt;Foo\&lt;/h2&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="998:1-999:66" dir="auto">Since indicators of block structure take precedence over
+indicators of inline structure, the following are setext headings:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1001:1-1009:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`Foo</span>
+<span id="LC2" class="line" lang="plaintext">----</span>
+<span id="LC3" class="line" lang="plaintext">`</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">&lt;a title="a lot</span>
+<span id="LC6" class="line" lang="plaintext">---</span>
+<span id="LC7" class="line" lang="plaintext">of dashes"/&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1011:1-1016:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h2&gt;`Foo&lt;/h2&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;`&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;h2&gt;&amp;lt;a title=&amp;quot;a lot&lt;/h2&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;of dashes&amp;quot;/&amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1019:1-1020:36" dir="auto">The setext heading underline cannot be a [lazy continuation
+line] in a list item or block quote:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1022:1-1025:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; Foo</span>
+<span id="LC2" class="line" lang="plaintext">---</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1027:1-1032:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;Foo&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1035:1-1039:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
+<span id="LC2" class="line" lang="plaintext">bar</span>
+<span id="LC3" class="line" lang="plaintext">===</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1041:1-1047:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;foo</span>
+<span id="LC3" class="line" lang="plaintext">bar</span>
+<span id="LC4" class="line" lang="plaintext">===&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1050:1-1053:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- Foo</span>
+<span id="LC2" class="line" lang="plaintext">---</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1055:1-1060:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;Foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1063:1-1065:25" dir="auto">A blank line is needed between a paragraph and a following
+setext heading, since otherwise the paragraph becomes part
+of the heading's content:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1067:1-1071:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext">Bar</span>
+<span id="LC3" class="line" lang="plaintext">---</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1073:1-1076:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h2&gt;Foo</span>
+<span id="LC2" class="line" lang="plaintext">Bar&lt;/h2&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1079:1-1080:16" dir="auto">But in general a blank line is not required before or after
+setext headings:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1082:1-1089:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">---</span>
+<span id="LC2" class="line" lang="plaintext">Foo</span>
+<span id="LC3" class="line" lang="plaintext">---</span>
+<span id="LC4" class="line" lang="plaintext">Bar</span>
+<span id="LC5" class="line" lang="plaintext">---</span>
+<span id="LC6" class="line" lang="plaintext">Baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1091:1-1096:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;hr /&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h2&gt;Foo&lt;/h2&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;h2&gt;Bar&lt;/h2&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;Baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1099:1-1099:32" dir="auto">Setext headings cannot be empty:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1101:1-1104:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"></span>
+<span id="LC2" class="line" lang="plaintext">====</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1106:1-1108:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;====&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1111:1-1113:55" dir="auto">Setext heading text lines must not be interpretable as block
+constructs other than paragraphs. So, the line of dashes
+in these examples gets interpreted as a thematic break:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1115:1-1118:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">---</span>
+<span id="LC2" class="line" lang="plaintext">---</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1120:1-1123:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;hr /&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1126:1-1129:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext">-----</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1131:1-1136:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1139:1-1142:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span>
+<span id="LC2" class="line" lang="plaintext">---</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1144:1-1148:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1151:1-1154:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
+<span id="LC2" class="line" lang="plaintext">-----</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1156:1-1161:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1164:1-1165:22" dir="auto">If you want a heading with <code>&gt; foo</code> as its literal text, you can
+use backslash escapes:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1167:1-1170:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\&gt; foo</span>
+<span id="LC2" class="line" lang="plaintext">------</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1172:1-1174:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h2&gt;&amp;gt; foo&lt;/h2&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1177:1-1179:48" dir="auto"><strong>Compatibility note:</strong> Most existing Markdown implementations
+do not allow the text of setext headings to span multiple lines.
+But there is no consensus about how to interpret</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1181:1-1186:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown">Foo</span>
+<span id="LC2" class="line" lang="markdown"><span class="gh">bar</span></span>
+<span id="LC3" class="line" lang="markdown"><span class="gh">---</span></span>
+<span id="LC4" class="line" lang="markdown">baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1188:1-1188:44" dir="auto">One can find four different interpretations:</p>
+<ol data-sourcepos="1190:1-1194:0" dir="auto">
+<li data-sourcepos="1190:1-1190:50">paragraph "Foo", heading "bar", paragraph "baz"</li>
+<li data-sourcepos="1191:1-1191:55">paragraph "Foo bar", thematic break, paragraph "baz"</li>
+<li data-sourcepos="1192:1-1192:30">paragraph "Foo bar --- baz"</li>
+<li data-sourcepos="1193:1-1194:0">heading "Foo bar", paragraph "baz"</li>
+</ol>
+<p data-sourcepos="1195:1-1198:43" dir="auto">We find interpretation 4 most natural, and interpretation 4
+increases the expressive power of CommonMark, by allowing
+multiline headings. Authors who want interpretation 1 can
+put a blank line after the first paragraph:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1200:1-1206:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">bar</span>
+<span id="LC4" class="line" lang="plaintext">---</span>
+<span id="LC5" class="line" lang="plaintext">baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1208:1-1212:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h2&gt;bar&lt;/h2&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1215:1-1216:19" dir="auto">Authors who want interpretation 2 can put blank lines around
+the thematic break,</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1218:1-1225:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext">bar</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">---</span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext">baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1227:1-1232:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo</span>
+<span id="LC2" class="line" lang="plaintext">bar&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;hr /&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1235:1-1236:19" dir="auto">or use a thematic break that cannot count as a [setext heading
+underline], such as</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1238:1-1243:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext">bar</span>
+<span id="LC3" class="line" lang="plaintext">* * *</span>
+<span id="LC4" class="line" lang="plaintext">baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1245:1-1250:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo</span>
+<span id="LC2" class="line" lang="plaintext">bar&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;hr /&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1253:1-1253:60" dir="auto">Authors who want interpretation 3 can use backslash escapes:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1255:1-1260:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext">bar</span>
+<span id="LC3" class="line" lang="plaintext">\---</span>
+<span id="LC4" class="line" lang="plaintext">baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1262:1-1267:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo</span>
+<span id="LC2" class="line" lang="plaintext">bar</span>
+<span id="LC3" class="line" lang="plaintext">---</span>
+<span id="LC4" class="line" lang="plaintext">baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="1270:1-1270:23" dir="auto">
+<a id="user-content-indented-code-blocks" class="anchor" href="#indented-code-blocks" aria-hidden="true"></a>Indented code blocks</h2>
+<p data-sourcepos="1272:1-1278:44" dir="auto">An <a href="@">indented code block</a> is composed of one or more
+[indented chunks] separated by blank lines.
+An <a href="@">indented chunk</a> is a sequence of non-blank lines,
+each indented four or more spaces. The contents of the code block are
+the literal contents of the lines, including trailing
+[line endings], minus four spaces of indentation.
+An indented code block has no [info string].</p>
+<p data-sourcepos="1280:1-1283:11" dir="auto">An indented code block cannot interrupt a paragraph, so there must be
+a blank line between a paragraph and a following indented code block.
+(A blank line is not needed, however, between a code block and a following
+paragraph.)</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1285:1-1288:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> a simple</span>
+<span id="LC2" class="line" lang="plaintext"> indented code block</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1290:1-1294:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;a simple</span>
+<span id="LC2" class="line" lang="plaintext"> indented code block</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1297:1-1299:65" dir="auto">If there is any ambiguity between an interpretation of indentation
+as a code block and as indicating that material belongs to a [list
+item][list items], the list item interpretation takes precedence:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1301:1-1305:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> - foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1307:1-1314:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1317:1-1321:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> - bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1323:1-1332:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1336:1-1337:12" dir="auto">The contents of a code block are literal text, and do not get parsed
+as Markdown:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1339:1-1344:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &lt;a/&gt;</span>
+<span id="LC2" class="line" lang="plaintext"> *hi*</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> - one</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1346:1-1352:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&amp;lt;a/&amp;gt;</span>
+<span id="LC2" class="line" lang="plaintext">*hi*</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">- one</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1355:1-1355:51" dir="auto">Here we have three chunks separated by blank lines:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1357:1-1365:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> chunk1</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> chunk2</span>
+<span id="LC4" class="line" lang="plaintext"> </span>
+<span id="LC5" class="line" lang="plaintext"> </span>
+<span id="LC6" class="line" lang="plaintext"> </span>
+<span id="LC7" class="line" lang="plaintext"> chunk3</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1367:1-1376:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;chunk1</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">chunk2</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext"></span>
+<span id="LC7" class="line" lang="plaintext">chunk3</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1379:1-1380:24" dir="auto">Any initial spaces beyond four will be included in the content, even
+in interior blank lines:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1382:1-1386:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> chunk1</span>
+<span id="LC2" class="line" lang="plaintext"> </span>
+<span id="LC3" class="line" lang="plaintext"> chunk2</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1388:1-1393:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;chunk1</span>
+<span id="LC2" class="line" lang="plaintext"> </span>
+<span id="LC3" class="line" lang="plaintext"> chunk2</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1396:1-1397:37" dir="auto">An indented code block cannot interrupt a paragraph. (This
+allows hanging indents and the like.)</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1399:1-1403:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext"> bar</span>
+<span id="LC3" class="line" lang="plaintext"></span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1405:1-1408:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo</span>
+<span id="LC2" class="line" lang="plaintext">bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1411:1-1413:20" dir="auto">However, any non-blank line with fewer than four leading spaces ends
+the code block immediately. So a paragraph may occur immediately
+after indented code:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1415:1-1418:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span>
+<span id="LC2" class="line" lang="plaintext">bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1420:1-1424:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1427:1-1428:7" dir="auto">And indented code can occur immediately before and after other kinds of
+blocks:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1430:1-1437:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># Heading</span>
+<span id="LC2" class="line" lang="plaintext"> foo</span>
+<span id="LC3" class="line" lang="plaintext">Heading</span>
+<span id="LC4" class="line" lang="plaintext">------</span>
+<span id="LC5" class="line" lang="plaintext"> foo</span>
+<span id="LC6" class="line" lang="plaintext">----</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1439:1-1447:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h1&gt;Heading&lt;/h1&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;h2&gt;Heading&lt;/h2&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1450:1-1450:53" dir="auto">The first line can be indented more than four spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1452:1-1455:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span>
+<span id="LC2" class="line" lang="plaintext"> bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1457:1-1461:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt; foo</span>
+<span id="LC2" class="line" lang="plaintext">bar</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1464:1-1465:23" dir="auto">Blank lines preceding or following an indented code block
+are not included in it:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1467:1-1473:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"></span>
+<span id="LC2" class="line" lang="plaintext"> </span>
+<span id="LC3" class="line" lang="plaintext"> foo</span>
+<span id="LC4" class="line" lang="plaintext"> </span>
+<span id="LC5" class="line" lang="plaintext"></span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1475:1-1478:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1481:1-1481:57" dir="auto">Trailing spaces are included in the code block's content:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1483:1-1485:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo </span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1487:1-1490:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo </span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="1494:1-1494:21" dir="auto">
+<a id="user-content-fenced-code-blocks" class="anchor" href="#fenced-code-blocks" aria-hidden="true"></a>Fenced code blocks</h2>
+<p data-sourcepos="1496:1-1500:61" dir="auto">A <a href="@">code fence</a> is a sequence
+of at least three consecutive backtick characters (<code>`</code>) or
+tildes (<code>~</code>). (Tildes and backticks cannot be mixed.)
+A <a href="@">fenced code block</a>
+begins with a code fence, indented no more than three spaces.</p>
+<p data-sourcepos="1502:1-1508:34" dir="auto">The line with the opening code fence may optionally contain some text
+following the code fence; this is trimmed of leading and trailing
+whitespace and called the <a href="@">info string</a>. If the [info string] comes
+after a backtick fence, it may not contain any backtick
+characters. (The reason for this restriction is that otherwise
+some inline code would be incorrectly interpreted as the
+beginning of a fenced code block.)</p>
+<p data-sourcepos="1510:1-1517:43" dir="auto">The content of the code block consists of all subsequent lines, until
+a closing [code fence] of the same type as the code block
+began with (backticks or tildes), and with at least as many backticks
+or tildes as the opening code fence. If the leading code fence is
+indented N spaces, then up to N spaces of indentation are removed from
+each line of the content (if present). (If a content line is not
+indented, it is preserved unchanged. If it is indented less than N
+spaces, all of the indentation is removed.)</p>
+<p data-sourcepos="1519:1-1527:25" dir="auto">The closing code fence may be indented up to three spaces, and may be
+followed only by spaces, which are ignored. If the end of the
+containing block (or document) is reached and no closing code fence
+has been found, the code block contains all of the lines after the
+opening code fence until the end of the containing block (or
+document). (An alternative spec would require backtracking in the
+event that a closing code fence is not found. But this makes parsing
+much less efficient, and there seems to be no real down side to the
+behavior described here.)</p>
+<p data-sourcepos="1529:1-1530:36" dir="auto">A fenced code block may interrupt a paragraph, and does not require
+a blank line either before or after.</p>
+<p data-sourcepos="1532:1-1536:42" dir="auto">The content of a code fence is treated as literal text, not parsed
+as inlines. The first word of the [info string] is typically used to
+specify the language of the code sample, and rendered in the <code>class</code>
+attribute of the <code>code</code> tag. However, this spec does not mandate any
+particular treatment of the [info string].</p>
+<p data-sourcepos="1538:1-1538:40" dir="auto">Here is a simple example with backticks:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1540:1-1545:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
+<span id="LC2" class="line" lang="plaintext">&lt;</span>
+<span id="LC3" class="line" lang="plaintext"> &gt;</span>
+<span id="LC4" class="line" lang="plaintext">```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1547:1-1551:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&amp;lt;</span>
+<span id="LC2" class="line" lang="plaintext"> &amp;gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1554:1-1554:12" dir="auto">With tildes:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1556:1-1561:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~~</span>
+<span id="LC2" class="line" lang="plaintext">&lt;</span>
+<span id="LC3" class="line" lang="plaintext"> &gt;</span>
+<span id="LC4" class="line" lang="plaintext">~~~</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1563:1-1567:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&amp;lt;</span>
+<span id="LC2" class="line" lang="plaintext"> &amp;gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1569:1-1569:41" dir="auto">Fewer than three backticks is not enough:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1571:1-1575:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``</span>
+<span id="LC2" class="line" lang="plaintext">foo</span>
+<span id="LC3" class="line" lang="plaintext">``</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1577:1-1579:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1581:1-1582:6" dir="auto">The closing code fence must use the same character as the opening
+fence:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1584:1-1589:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
+<span id="LC2" class="line" lang="plaintext">aaa</span>
+<span id="LC3" class="line" lang="plaintext">~~~</span>
+<span id="LC4" class="line" lang="plaintext">```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1591:1-1595:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext">~~~</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1598:1-1603:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~~</span>
+<span id="LC2" class="line" lang="plaintext">aaa</span>
+<span id="LC3" class="line" lang="plaintext">```</span>
+<span id="LC4" class="line" lang="plaintext">~~~</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1605:1-1609:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext">```</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1612:1-1612:69" dir="auto">The closing code fence must be at least as long as the opening fence:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1614:1-1619:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">````</span>
+<span id="LC2" class="line" lang="plaintext">aaa</span>
+<span id="LC3" class="line" lang="plaintext">```</span>
+<span id="LC4" class="line" lang="plaintext">``````</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1621:1-1625:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext">```</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1628:1-1633:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~~~</span>
+<span id="LC2" class="line" lang="plaintext">aaa</span>
+<span id="LC3" class="line" lang="plaintext">~~~</span>
+<span id="LC4" class="line" lang="plaintext">~~~~</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1635:1-1639:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext">~~~</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1642:1-1643:74" dir="auto">Unclosed code blocks are closed by the end of the document
+(or the enclosing [block quote][block quotes] or [list item][list items]):</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1645:1-1647:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1649:1-1651:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1654:1-1659:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`````</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">```</span>
+<span id="LC4" class="line" lang="plaintext">aaa</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1661:1-1666:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;</span>
+<span id="LC2" class="line" lang="plaintext">```</span>
+<span id="LC3" class="line" lang="plaintext">aaa</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1669:1-1674:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; ```</span>
+<span id="LC2" class="line" lang="plaintext">&gt; aaa</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">bbb</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1676:1-1682:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;p&gt;bbb&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1685:1-1685:53" dir="auto">A code block can have all empty lines as its content:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1687:1-1692:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> </span>
+<span id="LC4" class="line" lang="plaintext">```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1694:1-1698:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;</span>
+<span id="LC2" class="line" lang="plaintext"> </span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1701:1-1701:26" dir="auto">A code block can be empty:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1703:1-1706:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
+<span id="LC2" class="line" lang="plaintext">```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1708:1-1710:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1713:1-1715:11" dir="auto">Fences can be indented. If the opening fence is indented,
+content lines will have equivalent opening indentation removed,
+if present:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1717:1-1722:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ```</span>
+<span id="LC2" class="line" lang="plaintext"> aaa</span>
+<span id="LC3" class="line" lang="plaintext">aaa</span>
+<span id="LC4" class="line" lang="plaintext">```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1724:1-1728:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext">aaa</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1731:1-1737:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ```</span>
+<span id="LC2" class="line" lang="plaintext">aaa</span>
+<span id="LC3" class="line" lang="plaintext"> aaa</span>
+<span id="LC4" class="line" lang="plaintext">aaa</span>
+<span id="LC5" class="line" lang="plaintext"> ```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1739:1-1744:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext">aaa</span>
+<span id="LC3" class="line" lang="plaintext">aaa</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1747:1-1753:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ```</span>
+<span id="LC2" class="line" lang="plaintext"> aaa</span>
+<span id="LC3" class="line" lang="plaintext"> aaa</span>
+<span id="LC4" class="line" lang="plaintext"> aaa</span>
+<span id="LC5" class="line" lang="plaintext"> ```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1755:1-1760:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext"> aaa</span>
+<span id="LC3" class="line" lang="plaintext">aaa</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1763:1-1763:56" dir="auto">Four spaces indentation produces an indented code block:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1765:1-1769:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ```</span>
+<span id="LC2" class="line" lang="plaintext"> aaa</span>
+<span id="LC3" class="line" lang="plaintext"> ```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1771:1-1776:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;```</span>
+<span id="LC2" class="line" lang="plaintext">aaa</span>
+<span id="LC3" class="line" lang="plaintext">```</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1779:1-1780:41" dir="auto">Closing fences may be indented by 0-3 spaces, and their indentation
+need not match that of the opening fence:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1782:1-1786:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
+<span id="LC2" class="line" lang="plaintext">aaa</span>
+<span id="LC3" class="line" lang="plaintext"> ```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1788:1-1791:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1794:1-1798:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ```</span>
+<span id="LC2" class="line" lang="plaintext">aaa</span>
+<span id="LC3" class="line" lang="plaintext"> ```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1800:1-1803:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1806:1-1806:61" dir="auto">This is not a closing fence, because it is indented 4 spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1808:1-1812:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
+<span id="LC2" class="line" lang="plaintext">aaa</span>
+<span id="LC3" class="line" lang="plaintext"> ```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1814:1-1818:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext"> ```</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1822:1-1822:65" dir="auto">Code fences (opening and closing) cannot contain internal spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1824:1-1827:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``` ```</span>
+<span id="LC2" class="line" lang="plaintext">aaa</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1829:1-1832:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt; &lt;/code&gt;</span>
+<span id="LC2" class="line" lang="plaintext">aaa&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1835:1-1839:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~~~~~</span>
+<span id="LC2" class="line" lang="plaintext">aaa</span>
+<span id="LC3" class="line" lang="plaintext">~~~ ~~</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1841:1-1845:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext">~~~ ~~</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1848:1-1849:53" dir="auto">Fenced code blocks can interrupt paragraphs, and can be followed
+directly by paragraphs, without a blank line between:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1851:1-1857:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span>
+<span id="LC2" class="line" lang="plaintext">```</span>
+<span id="LC3" class="line" lang="plaintext">bar</span>
+<span id="LC4" class="line" lang="plaintext">```</span>
+<span id="LC5" class="line" lang="plaintext">baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1859:1-1864:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1867:1-1868:34" dir="auto">Other blocks can also occur before and after fenced code blocks
+without an intervening blank line:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1870:1-1877:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span>
+<span id="LC2" class="line" lang="plaintext">---</span>
+<span id="LC3" class="line" lang="plaintext">~~~</span>
+<span id="LC4" class="line" lang="plaintext">bar</span>
+<span id="LC5" class="line" lang="plaintext">~~~</span>
+<span id="LC6" class="line" lang="plaintext"># baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1879:1-1884:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h2&gt;foo&lt;/h2&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;h1&gt;baz&lt;/h1&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1887:1-1892:45" dir="auto">An [info string] can be provided after the opening code fence.
+Although this spec doesn't mandate any particular treatment of
+the info string, the first word is typically used to specify
+the language of the code block. In HTML output, the language is
+normally indicated by adding a class to the <code>code</code> element consisting
+of <code>language-</code> followed by the language name.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1894:1-1900:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```ruby</span>
+<span id="LC2" class="line" lang="plaintext">def foo(x)</span>
+<span id="LC3" class="line" lang="plaintext"> return 3</span>
+<span id="LC4" class="line" lang="plaintext">end</span>
+<span id="LC5" class="line" lang="plaintext">```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1902:1-1907:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code class="language-ruby"&gt;def foo(x)</span>
+<span id="LC2" class="line" lang="plaintext"> return 3</span>
+<span id="LC3" class="line" lang="plaintext">end</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1910:1-1916:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~~~ ruby startline=3 $%@#$</span>
+<span id="LC2" class="line" lang="plaintext">def foo(x)</span>
+<span id="LC3" class="line" lang="plaintext"> return 3</span>
+<span id="LC4" class="line" lang="plaintext">end</span>
+<span id="LC5" class="line" lang="plaintext">~~~~~~~</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1918:1-1923:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code class="language-ruby"&gt;def foo(x)</span>
+<span id="LC2" class="line" lang="plaintext"> return 3</span>
+<span id="LC3" class="line" lang="plaintext">end</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1926:1-1929:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">````;</span>
+<span id="LC2" class="line" lang="plaintext">````</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1931:1-1933:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code class="language-;"&gt;&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1936:1-1936:65" dir="auto">[Info strings] for backtick code blocks cannot contain backticks:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1938:1-1941:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``` aa ```</span>
+<span id="LC2" class="line" lang="plaintext">foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1943:1-1946:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;aa&lt;/code&gt;</span>
+<span id="LC2" class="line" lang="plaintext">foo&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1949:1-1949:70" dir="auto">[Info strings] for tilde code blocks can contain backticks and tildes:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1951:1-1955:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~~ aa ``` ~~~</span>
+<span id="LC2" class="line" lang="plaintext">foo</span>
+<span id="LC3" class="line" lang="plaintext">~~~</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1957:1-1960:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code class="language-aa"&gt;foo</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="1963:1-1963:47" dir="auto">Closing code fences cannot have [info strings]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1965:1-1969:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
+<span id="LC2" class="line" lang="plaintext">``` aaa</span>
+<span id="LC3" class="line" lang="plaintext">```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1971:1-1974:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;``` aaa</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="1978:1-1978:14" dir="auto">
+<a id="user-content-html-blocks" class="anchor" href="#html-blocks" aria-hidden="true"></a>HTML blocks</h2>
+<p data-sourcepos="1980:1-1981:53" dir="auto">An <a href="@">HTML block</a> is a group of lines that is treated
+as raw HTML (and will not be escaped in HTML output).</p>
+<p data-sourcepos="1983:1-1991:50" dir="auto">There are seven kinds of [HTML block], which can be defined by their
+start and end conditions. The block begins with a line that meets a
+<a href="@">start condition</a> (after up to three spaces optional indentation).
+It ends with the first subsequent line that meets a matching <a href="@">end
+condition</a>, or the last line of the document, or the last line of
+the <a href="#container-blocks">container block</a> containing the current HTML
+block, if no line is encountered that meets the [end condition]. If
+the first line meets both the [start condition] and the [end
+condition], the block will contain just that line.</p>
+<ol data-sourcepos="1993:1-2034:0" dir="auto">
+<li data-sourcepos="1993:1-1999:0">
+<p data-sourcepos="1993:5-1998:30"><strong>Start condition:</strong> line begins with the string <code>&lt;script</code>,
+<code>&lt;pre</code>, or <code>&lt;style</code> (case-insensitive), followed by whitespace,
+the string <code>&gt;</code>, or the end of the line.<br>
+<strong>End condition:</strong> line contains an end tag
+<code>&lt;/script&gt;</code>, <code>&lt;/pre&gt;</code>, or <code>&lt;/style&gt;</code> (case-insensitive; it
+need not match the start tag).</p>
+</li>
+<li data-sourcepos="2000:1-2002:0">
+<p data-sourcepos="2000:5-2001:51"><strong>Start condition:</strong> line begins with the string <code>&lt;!--</code>.<br>
+<strong>End condition:</strong> line contains the string <code>--&gt;</code>.</p>
+</li>
+<li data-sourcepos="2003:1-2005:0">
+<p data-sourcepos="2003:5-2004:49"><strong>Start condition:</strong> line begins with the string <code>&lt;?</code>.<br>
+<strong>End condition:</strong> line contains the string <code>?&gt;</code>.</p>
+</li>
+<li data-sourcepos="2006:1-2009:0">
+<p data-sourcepos="2006:5-2008:51"><strong>Start condition:</strong> line begins with the string <code>&lt;!</code>
+followed by an uppercase ASCII letter.<br>
+<strong>End condition:</strong> line contains the character <code>&gt;</code>.</p>
+</li>
+<li data-sourcepos="2010:1-2013:0">
+<p data-sourcepos="2010:5-2012:50"><strong>Start condition:</strong> line begins with the string
+<code>&lt;![CDATA[</code>.<br>
+<strong>End condition:</strong> line contains the string <code>]]&gt;</code>.</p>
+</li>
+<li data-sourcepos="2014:1-2028:0">
+<p data-sourcepos="2014:5-2027:54"><strong>Start condition:</strong> line begins the string <code>&lt;</code> or <code>&lt;/</code>
+followed by one of the strings (case-insensitive) <code>address</code>,
+<code>article</code>, <code>aside</code>, <code>base</code>, <code>basefont</code>, <code>blockquote</code>, <code>body</code>,
+<code>caption</code>, <code>center</code>, <code>col</code>, <code>colgroup</code>, <code>dd</code>, <code>details</code>, <code>dialog</code>,
+<code>dir</code>, <code>div</code>, <code>dl</code>, <code>dt</code>, <code>fieldset</code>, <code>figcaption</code>, <code>figure</code>,
+<code>footer</code>, <code>form</code>, <code>frame</code>, <code>frameset</code>,
+<code>h1</code>, <code>h2</code>, <code>h3</code>, <code>h4</code>, <code>h5</code>, <code>h6</code>, <code>head</code>, <code>header</code>, <code>hr</code>,
+<code>html</code>, <code>iframe</code>, <code>legend</code>, <code>li</code>, <code>link</code>, <code>main</code>, <code>menu</code>, <code>menuitem</code>,
+<code>nav</code>, <code>noframes</code>, <code>ol</code>, <code>optgroup</code>, <code>option</code>, <code>p</code>, <code>param</code>,
+<code>section</code>, <code>summary</code>, <code>table</code>, <code>tbody</code>, <code>td</code>,
+<code>tfoot</code>, <code>th</code>, <code>thead</code>, <code>title</code>, <code>tr</code>, <code>track</code>, <code>ul</code>, followed
+by [whitespace], the end of the line, the string <code>&gt;</code>, or
+the string <code>/&gt;</code>.<br>
+<strong>End condition:</strong> line is followed by a [blank line].</p>
+</li>
+<li data-sourcepos="2029:1-2034:0">
+<p data-sourcepos="2029:5-2033:54"><strong>Start condition:</strong> line begins with a complete [open tag]
+(with any [tag name] other than <code>script</code>,
+<code>style</code>, or <code>pre</code>) or a complete [closing tag],
+followed only by [whitespace] or the end of the line.<br>
+<strong>End condition:</strong> line is followed by a [blank line].</p>
+</li>
+</ol>
+<p data-sourcepos="2035:1-2040:19" dir="auto">HTML blocks continue until they are closed by their appropriate
+[end condition], or the last line of the document or other <a href="#container-blocks">container
+block</a>. This means any HTML <strong>within an HTML
+block</strong> that might otherwise be recognised as a start condition will
+be ignored by the parser and passed through as-is, without changing
+the parser's state.</p>
+<p data-sourcepos="2042:1-2044:51" dir="auto">For instance, <code>&lt;pre&gt;</code> within a HTML block started by <code>&lt;table&gt;</code> will not affect
+the parser state; as the HTML block was started in by start condition 6, it
+will end at any blank line. This can be surprising:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2046:1-2054:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;&lt;tr&gt;&lt;td&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;pre&gt;</span>
+<span id="LC3" class="line" lang="plaintext">**Hello**,</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">_world_.</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/pre&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2056:1-2063:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;&lt;tr&gt;&lt;td&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;pre&gt;</span>
+<span id="LC3" class="line" lang="plaintext">**Hello**,</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;world&lt;/em&gt;.</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/pre&gt;&lt;/p&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2065:1-2067:55" dir="auto">In this case, the HTML block is terminated by the newline — the <code>**Hello**</code>
+text remains verbatim — and regular parsing resumes, with a paragraph,
+emphasised <code>world</code> and inline and block HTML following.</p>
+<p data-sourcepos="2069:1-2072:65" dir="auto">All types of [HTML blocks] except type 7 may interrupt
+a paragraph. Blocks of type 7 may not interrupt a paragraph.
+(This restriction is intended to prevent unwanted interpretation
+of long tags inside a wrapped paragraph as starting HTML blocks.)</p>
+<p data-sourcepos="2074:1-2075:10" dir="auto">Some simple examples follow. Here are some basic HTML blocks
+of type 6:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2077:1-2087:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
+<span id="LC2" class="line" lang="plaintext"> &lt;tr&gt;</span>
+<span id="LC3" class="line" lang="plaintext"> &lt;td&gt;</span>
+<span id="LC4" class="line" lang="plaintext"> hi</span>
+<span id="LC5" class="line" lang="plaintext"> &lt;/td&gt;</span>
+<span id="LC6" class="line" lang="plaintext"> &lt;/tr&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/table&gt;</span>
+<span id="LC8" class="line" lang="plaintext"></span>
+<span id="LC9" class="line" lang="plaintext">okay.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2089:1-2098:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
+<span id="LC2" class="line" lang="plaintext"> &lt;tr&gt;</span>
+<span id="LC3" class="line" lang="plaintext"> &lt;td&gt;</span>
+<span id="LC4" class="line" lang="plaintext"> hi</span>
+<span id="LC5" class="line" lang="plaintext"> &lt;/td&gt;</span>
+<span id="LC6" class="line" lang="plaintext"> &lt;/tr&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/table&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;p&gt;okay.&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2101:1-2105:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &lt;div&gt;</span>
+<span id="LC2" class="line" lang="plaintext"> *hello*</span>
+<span id="LC3" class="line" lang="plaintext"> &lt;foo&gt;&lt;a&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2107:1-2111:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &lt;div&gt;</span>
+<span id="LC2" class="line" lang="plaintext"> *hello*</span>
+<span id="LC3" class="line" lang="plaintext"> &lt;foo&gt;&lt;a&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2114:1-2114:42" dir="auto">A block can also start with a closing tag:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2116:1-2119:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;/div&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*foo*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2121:1-2124:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;/div&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*foo*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2127:1-2127:68" dir="auto">Here we have two HTML blocks with a Markdown paragraph between them:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2129:1-2135:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;DIV CLASS="foo"&gt;</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">*Markdown*</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">&lt;/DIV&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2137:1-2141:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;DIV CLASS="foo"&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;Markdown&lt;/em&gt;&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/DIV&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2144:1-2145:47" dir="auto">The tag on the first line can be partial, as long
+as it is split where there would be whitespace:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2147:1-2151:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div id="foo"</span>
+<span id="LC2" class="line" lang="plaintext"> class="bar"&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/div&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2153:1-2157:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div id="foo"</span>
+<span id="LC2" class="line" lang="plaintext"> class="bar"&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/div&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2160:1-2164:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div id="foo" class="bar</span>
+<span id="LC2" class="line" lang="plaintext"> baz"&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/div&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2166:1-2170:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div id="foo" class="bar</span>
+<span id="LC2" class="line" lang="plaintext"> baz"&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/div&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2173:1-2173:31" dir="auto">An open tag need not be closed:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2174:1-2179:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*foo*</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">*bar*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2181:1-2185:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*foo*</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2189:1-2190:17" dir="auto">A partial tag need not even be completed (garbage
+in, garbage out):</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2192:1-2195:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div id="foo"</span>
+<span id="LC2" class="line" lang="plaintext">*hi*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2197:1-2200:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div id="foo"</span>
+<span id="LC2" class="line" lang="plaintext">*hi*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2203:1-2206:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div class</span>
+<span id="LC2" class="line" lang="plaintext">foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2208:1-2211:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div class</span>
+<span id="LC2" class="line" lang="plaintext">foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2214:1-2215:35" dir="auto">The initial tag doesn't even need to be a valid
+tag, as long as it starts like one:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2217:1-2220:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div *???-&amp;&amp;&amp;-&lt;---</span>
+<span id="LC2" class="line" lang="plaintext">*foo*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2222:1-2225:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div *???-&amp;&amp;&amp;-&lt;---</span>
+<span id="LC2" class="line" lang="plaintext">*foo*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2228:1-2229:7" dir="auto">In type 6 blocks, the initial tag need not be on a line by
+itself:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2231:1-2233:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;&lt;a href="bar"&gt;*foo*&lt;/a&gt;&lt;/div&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2235:1-2237:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;&lt;a href="bar"&gt;*foo*&lt;/a&gt;&lt;/div&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2240:1-2244:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;&lt;tr&gt;&lt;td&gt;</span>
+<span id="LC2" class="line" lang="plaintext">foo</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2246:1-2250:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;&lt;tr&gt;&lt;td&gt;</span>
+<span id="LC2" class="line" lang="plaintext">foo</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2253:1-2257:43" dir="auto">Everything until the next blank line or end of document
+gets included in the HTML block. So, in the following
+example, what looks like a Markdown code block
+is actually part of the HTML block, which continues until a blank
+line or the end of the document is reached:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2259:1-2264:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;&lt;/div&gt;</span>
+<span id="LC2" class="line" lang="plaintext">``` c</span>
+<span id="LC3" class="line" lang="plaintext">int x = 33;</span>
+<span id="LC4" class="line" lang="plaintext">```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2266:1-2271:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;&lt;/div&gt;</span>
+<span id="LC2" class="line" lang="plaintext">``` c</span>
+<span id="LC3" class="line" lang="plaintext">int x = 33;</span>
+<span id="LC4" class="line" lang="plaintext">```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2274:1-2276:51" dir="auto">To start an [HTML block] with a tag that is <em>not</em> in the
+list of block-level tags in (6), you must put the tag by
+itself on the first line (and it must be complete):</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2278:1-2282:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="foo"&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*bar*</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/a&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2284:1-2288:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="foo"&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*bar*</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/a&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2291:1-2291:49" dir="auto">In type 7 blocks, the [tag name] can be anything:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2293:1-2297:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;Warning&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*bar*</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/Warning&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2299:1-2303:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;Warning&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*bar*</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/Warning&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2306:1-2310:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;i class="foo"&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*bar*</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/i&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2312:1-2316:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;i class="foo"&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*bar*</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/i&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2319:1-2322:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;/ins&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*bar*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2324:1-2327:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;/ins&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*bar*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2330:1-2334:59" dir="auto">These rules are designed to allow us to work with tags that
+can function as either block-level or inline-level tags.
+The <code>&lt;del&gt;</code> tag is a nice example. We can surround content with
+<code>&lt;del&gt;</code> tags in three different ways. In this case, we get a raw
+HTML block, because the <code>&lt;del&gt;</code> tag is on a line by itself:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2336:1-2340:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;del&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*foo*</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/del&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2342:1-2346:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;del&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*foo*</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/del&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2349:1-2351:54" dir="auto">In this case, we get a raw HTML block that just includes
+the <code>&lt;del&gt;</code> tag (because it ends with the following blank
+line). So the contents get interpreted as CommonMark:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2353:1-2359:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;del&gt;</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">*foo*</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">&lt;/del&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2361:1-2365:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;del&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;/em&gt;&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/del&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2368:1-2371:29" dir="auto">Finally, in this case, the <code>&lt;del&gt;</code> tags are interpreted
+as [raw HTML] <em>inside</em> the CommonMark paragraph. (Because
+the tag is not on a line by itself, we get inline HTML
+rather than an [HTML block].)</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2373:1-2375:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;del&gt;*foo*&lt;/del&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2377:1-2379:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;del&gt;&lt;em&gt;foo&lt;/em&gt;&lt;/del&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2382:1-2387:50" dir="auto">HTML tags designed to contain literal content
+(<code>script</code>, <code>style</code>, <code>pre</code>), comments, processing instructions,
+and declarations are treated somewhat differently.
+Instead of ending at the first blank line, these blocks
+end at the first line containing a corresponding end tag.
+As a result, these blocks can contain blank lines:</p>
+<p data-sourcepos="2389:1-2389:19" dir="auto">A pre tag (type 1):</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2391:1-2399:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre language="haskell"&gt;&lt;code&gt;</span>
+<span id="LC2" class="line" lang="plaintext">import Text.HTML.TagSoup</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">main :: IO ()</span>
+<span id="LC5" class="line" lang="plaintext">main = print $ parseTags tags</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC7" class="line" lang="plaintext">okay</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2401:1-2409:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre language="haskell"&gt;&lt;code&gt;</span>
+<span id="LC2" class="line" lang="plaintext">import Text.HTML.TagSoup</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">main :: IO ()</span>
+<span id="LC5" class="line" lang="plaintext">main = print $ parseTags tags</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;p&gt;okay&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2412:1-2412:22" dir="auto">A script tag (type 1):</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2414:1-2421:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;script type="text/javascript"&gt;</span>
+<span id="LC2" class="line" lang="plaintext">// JavaScript example</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">document.getElementById("demo").innerHTML = "Hello JavaScript!";</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/script&gt;</span>
+<span id="LC6" class="line" lang="plaintext">okay</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2423:1-2430:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;script type="text/javascript"&gt;</span>
+<span id="LC2" class="line" lang="plaintext">// JavaScript example</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">document.getElementById("demo").innerHTML = "Hello JavaScript!";</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/script&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;p&gt;okay&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2433:1-2433:21" dir="auto">A style tag (type 1):</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2435:1-2443:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;style</span>
+<span id="LC2" class="line" lang="plaintext"> type="text/css"&gt;</span>
+<span id="LC3" class="line" lang="plaintext">h1 {color:red;}</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">p {color:blue;}</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/style&gt;</span>
+<span id="LC7" class="line" lang="plaintext">okay</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2445:1-2453:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;style</span>
+<span id="LC2" class="line" lang="plaintext"> type="text/css"&gt;</span>
+<span id="LC3" class="line" lang="plaintext">h1 {color:red;}</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">p {color:blue;}</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/style&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;p&gt;okay&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2456:1-2458:28" dir="auto">If there is no matching end tag, the block will end at the
+end of the document (or the enclosing [block quote][block quotes]
+or [list item][list items]):</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2460:1-2465:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;style</span>
+<span id="LC2" class="line" lang="plaintext"> type="text/css"&gt;</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2467:1-2472:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;style</span>
+<span id="LC2" class="line" lang="plaintext"> type="text/css"&gt;</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2475:1-2480:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; &lt;div&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&gt; foo</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2482:1-2488:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;div&gt;</span>
+<span id="LC3" class="line" lang="plaintext">foo</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2491:1-2494:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- &lt;div&gt;</span>
+<span id="LC2" class="line" lang="plaintext">- foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2496:1-2503:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;div&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2506:1-2506:56" dir="auto">The end tag can occur on the same line as the start tag:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2508:1-2511:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;style&gt;p{color:red;}&lt;/style&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*foo*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2513:1-2516:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;style&gt;p{color:red;}&lt;/style&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2519:1-2522:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;!-- foo --&gt;*bar*</span>
+<span id="LC2" class="line" lang="plaintext">*baz*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2524:1-2527:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;!-- foo --&gt;*bar*</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;baz&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2530:1-2531:45" dir="auto">Note that anything on the last line after the
+end tag will be included in the [HTML block]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2533:1-2537:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;script&gt;</span>
+<span id="LC2" class="line" lang="plaintext">foo</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/script&gt;1. *bar*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2539:1-2543:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;script&gt;</span>
+<span id="LC2" class="line" lang="plaintext">foo</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/script&gt;1. *bar*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2546:1-2546:19" dir="auto">A comment (type 2):</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2548:1-2554:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;!-- Foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">bar</span>
+<span id="LC4" class="line" lang="plaintext"> baz --&gt;</span>
+<span id="LC5" class="line" lang="plaintext">okay</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2556:1-2562:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;!-- Foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">bar</span>
+<span id="LC4" class="line" lang="plaintext"> baz --&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;p&gt;okay&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2566:1-2566:34" dir="auto">A processing instruction (type 3):</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2568:1-2575:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;?php</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> echo '&gt;';</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">?&gt;</span>
+<span id="LC6" class="line" lang="plaintext">okay</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2577:1-2584:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;?php</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> echo '&gt;';</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">?&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;p&gt;okay&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2587:1-2587:23" dir="auto">A declaration (type 4):</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2589:1-2591:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;!DOCTYPE html&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2593:1-2595:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;!DOCTYPE html&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2598:1-2598:15" dir="auto">CDATA (type 5):</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2600:1-2614:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;![CDATA[</span>
+<span id="LC2" class="line" lang="plaintext">function matchwo(a,b)</span>
+<span id="LC3" class="line" lang="plaintext">{</span>
+<span id="LC4" class="line" lang="plaintext"> if (a &lt; b &amp;&amp; a &lt; 0) then {</span>
+<span id="LC5" class="line" lang="plaintext"> return 1;</span>
+<span id="LC6" class="line" lang="plaintext"></span>
+<span id="LC7" class="line" lang="plaintext"> } else {</span>
+<span id="LC8" class="line" lang="plaintext"></span>
+<span id="LC9" class="line" lang="plaintext"> return 0;</span>
+<span id="LC10" class="line" lang="plaintext"> }</span>
+<span id="LC11" class="line" lang="plaintext">}</span>
+<span id="LC12" class="line" lang="plaintext">]]&gt;</span>
+<span id="LC13" class="line" lang="plaintext">okay</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2616:1-2630:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;![CDATA[</span>
+<span id="LC2" class="line" lang="plaintext">function matchwo(a,b)</span>
+<span id="LC3" class="line" lang="plaintext">{</span>
+<span id="LC4" class="line" lang="plaintext"> if (a &lt; b &amp;&amp; a &lt; 0) then {</span>
+<span id="LC5" class="line" lang="plaintext"> return 1;</span>
+<span id="LC6" class="line" lang="plaintext"></span>
+<span id="LC7" class="line" lang="plaintext"> } else {</span>
+<span id="LC8" class="line" lang="plaintext"></span>
+<span id="LC9" class="line" lang="plaintext"> return 0;</span>
+<span id="LC10" class="line" lang="plaintext"> }</span>
+<span id="LC11" class="line" lang="plaintext">}</span>
+<span id="LC12" class="line" lang="plaintext">]]&gt;</span>
+<span id="LC13" class="line" lang="plaintext">&lt;p&gt;okay&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2633:1-2633:54" dir="auto">The opening tag can be indented 1-3 spaces, but not 4:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2635:1-2639:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &lt;!-- foo --&gt;</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> &lt;!-- foo --&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2641:1-2645:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &lt;!-- foo --&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&amp;lt;!-- foo --&amp;gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2648:1-2652:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &lt;div&gt;</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> &lt;div&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2654:1-2658:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &lt;div&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&amp;lt;div&amp;gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2661:1-2662:25" dir="auto">An HTML block of types 1--6 can interrupt a paragraph, and need not be
+preceded by a blank line.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2664:1-2669:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext">&lt;div&gt;</span>
+<span id="LC3" class="line" lang="plaintext">bar</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/div&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2671:1-2676:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;div&gt;</span>
+<span id="LC3" class="line" lang="plaintext">bar</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/div&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2679:1-2681:7" dir="auto">However, a following blank line is needed, except at the end of
+a document, and except for blocks of types 1--5, [above][HTML
+block]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2683:1-2688:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;</span>
+<span id="LC2" class="line" lang="plaintext">bar</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/div&gt;</span>
+<span id="LC4" class="line" lang="plaintext">*foo*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2690:1-2695:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;</span>
+<span id="LC2" class="line" lang="plaintext">bar</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/div&gt;</span>
+<span id="LC4" class="line" lang="plaintext">*foo*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2698:1-2698:51" dir="auto">HTML blocks of type 7 cannot interrupt a paragraph:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2700:1-2704:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext">&lt;a href="bar"&gt;</span>
+<span id="LC3" class="line" lang="plaintext">baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2706:1-2710:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo</span>
+<span id="LC2" class="line" lang="plaintext">&lt;a href="bar"&gt;</span>
+<span id="LC3" class="line" lang="plaintext">baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2713:1-2714:26" dir="auto">This rule differs from John Gruber's original Markdown syntax
+specification, which says:</p>
+<blockquote data-sourcepos="2716:1-2719:51" dir="auto">
+<p data-sourcepos="2716:3-2719:51">The only restrictions are that block-level HTML elements —
+e.g. <code>&lt;div&gt;</code>, <code>&lt;table&gt;</code>, <code>&lt;pre&gt;</code>, <code>&lt;p&gt;</code>, etc. — must be separated from
+surrounding content by blank lines, and the start and end tags of the
+block should not be indented with tabs or spaces.</p>
+</blockquote>
+<p data-sourcepos="2721:1-2722:5" dir="auto">In some ways Gruber's rule is more restrictive than the one given
+here:</p>
+<ul data-sourcepos="2724:1-2728:0" dir="auto">
+<li data-sourcepos="2724:1-2724:61">It requires that an HTML block be preceded by a blank line.</li>
+<li data-sourcepos="2725:1-2725:49">It does not allow the start tag to be indented.</li>
+<li data-sourcepos="2726:1-2728:0">It requires a matching end tag, which it also does not allow to
+be indented.</li>
+</ul>
+<p data-sourcepos="2729:1-2730:34" dir="auto">Most Markdown implementations (including some of Gruber's own) do not
+respect all of these restrictions.</p>
+<p data-sourcepos="2732:1-2739:61" dir="auto">There is one respect, however, in which Gruber's rule is more liberal
+than the one given here, since it allows blank lines to occur inside
+an HTML block. There are two reasons for disallowing them here.
+First, it removes the need to parse balanced tags, which is
+expensive and can require backtracking from the end of the document
+if no matching end tag is found. Second, it provides a very simple
+and flexible way of including Markdown content inside HTML tags:
+simply separate the Markdown from the HTML using blank lines:</p>
+<p data-sourcepos="2741:1-2741:8" dir="auto">Compare:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2743:1-2749:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">*Emphasized* text.</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">&lt;/div&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2751:1-2755:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;Emphasized&lt;/em&gt; text.&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/div&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2758:1-2762:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*Emphasized* text.</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/div&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2764:1-2768:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;div&gt;</span>
+<span id="LC2" class="line" lang="plaintext">*Emphasized* text.</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/div&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2771:1-2775:22" dir="auto">Some Markdown implementations have adopted a convention of
+interpreting content inside tags as text if the open tag has
+the attribute <code>markdown=1</code>. The rule given above seems a simpler and
+more elegant way of achieving the same expressive power, which is also
+much simpler to parse.</p>
+<p data-sourcepos="2777:1-2780:59" dir="auto">The main potential drawback is that one can no longer paste HTML
+blocks into Markdown documents with 100% reliability. However,
+<em>in most cases</em> this will work fine, because the blank lines in
+HTML are usually followed by HTML block tags. For example:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2782:1-2794:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">&lt;td&gt;</span>
+<span id="LC6" class="line" lang="plaintext">Hi</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/td&gt;</span>
+<span id="LC8" class="line" lang="plaintext"></span>
+<span id="LC9" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC10" class="line" lang="plaintext"></span>
+<span id="LC11" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2796:1-2804:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;td&gt;</span>
+<span id="LC4" class="line" lang="plaintext">Hi</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/td&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2807:1-2809:23" dir="auto">There are problems, however, if the inner tags are indented
+<em>and</em> separated by spaces, as then they will be interpreted as
+an indented code block:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2811:1-2823:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> &lt;tr&gt;</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext"> &lt;td&gt;</span>
+<span id="LC6" class="line" lang="plaintext"> Hi</span>
+<span id="LC7" class="line" lang="plaintext"> &lt;/td&gt;</span>
+<span id="LC8" class="line" lang="plaintext"></span>
+<span id="LC9" class="line" lang="plaintext"> &lt;/tr&gt;</span>
+<span id="LC10" class="line" lang="plaintext"></span>
+<span id="LC11" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2825:1-2834:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
+<span id="LC2" class="line" lang="plaintext"> &lt;tr&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&amp;lt;td&amp;gt;</span>
+<span id="LC4" class="line" lang="plaintext"> Hi</span>
+<span id="LC5" class="line" lang="plaintext">&amp;lt;/td&amp;gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC7" class="line" lang="plaintext"> &lt;/tr&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2837:1-2840:26" dir="auto">Fortunately, blank lines are usually not necessary and can be
+deleted. The exception is inside <code>&lt;pre&gt;</code> tags, but as described
+[above][HTML blocks], raw HTML blocks starting with <code>&lt;pre&gt;</code>
+<em>can</em> contain blank lines.</p>
+<h2 data-sourcepos="2842:1-2842:29" dir="auto">
+<a id="user-content-link-reference-definitions" class="anchor" href="#link-reference-definitions" aria-hidden="true"></a>Link reference definitions</h2>
+<p data-sourcepos="2844:1-2852:61" dir="auto">A <a href="@">link reference definition</a>
+consists of a [link label], indented up to three spaces, followed
+by a colon (<code>:</code>), optional [whitespace] (including up to one
+[line ending]), a [link destination],
+optional [whitespace] (including up to one
+[line ending]), and an optional [link
+title], which if it is present must be separated
+from the [link destination] by [whitespace].
+No further [non-whitespace characters] may occur on the line.</p>
+<p data-sourcepos="2854:1-2859:5" dir="auto">A [link reference definition]
+does not correspond to a structural element of a document. Instead, it
+defines a label which can be used in [reference links]
+and reference-style [images] elsewhere in the document. [Link
+reference definitions] can come either before or after the links that use
+them.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2861:1-2865:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url "title"</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2867:1-2869:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2872:1-2878:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> [foo]: </span>
+<span id="LC2" class="line" lang="plaintext"> /url </span>
+<span id="LC3" class="line" lang="plaintext"> 'the title' </span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">[foo]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2880:1-2882:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="the title"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2885:1-2889:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[Foo*bar\]]:my_(url) 'title (with parens)'</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[Foo*bar\]]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2891:1-2893:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="my_(url)" title="title (with parens)"&gt;Foo*bar]&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2896:1-2902:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[Foo bar]:</span>
+<span id="LC2" class="line" lang="plaintext">&lt;my url&gt;</span>
+<span id="LC3" class="line" lang="plaintext">'title'</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">[Foo bar]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2904:1-2906:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="my%20url" title="title"&gt;Foo bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2909:1-2909:41" dir="auto">The title may extend over multiple lines:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2911:1-2919:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url '</span>
+<span id="LC2" class="line" lang="plaintext">title</span>
+<span id="LC3" class="line" lang="plaintext">line1</span>
+<span id="LC4" class="line" lang="plaintext">line2</span>
+<span id="LC5" class="line" lang="plaintext">'</span>
+<span id="LC6" class="line" lang="plaintext"></span>
+<span id="LC7" class="line" lang="plaintext">[foo]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2921:1-2927:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="</span>
+<span id="LC2" class="line" lang="plaintext">title</span>
+<span id="LC3" class="line" lang="plaintext">line1</span>
+<span id="LC4" class="line" lang="plaintext">line2</span>
+<span id="LC5" class="line" lang="plaintext">"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2930:1-2930:43" dir="auto">However, it may not contain a [blank line]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2932:1-2938:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url 'title</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">with blank line'</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">[foo]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2940:1-2944:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo]: /url 'title&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;with blank line'&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2947:1-2947:25" dir="auto">The title may be omitted:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2949:1-2954:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]:</span>
+<span id="LC2" class="line" lang="plaintext">/url</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">[foo]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2956:1-2958:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2961:1-2961:40" dir="auto">The link destination may not be omitted:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2963:1-2967:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]:</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2969:1-2972:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo]:&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2974:2-2975:16" dir="auto">However, an empty link destination may be specified using
+angle brackets:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2977:1-2981:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: &lt;&gt;</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2983:1-2985:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href=""&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="2987:1-2988:11" dir="auto">The title must be separated from the link destination by
+whitespace:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2990:1-2994:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: &lt;bar&gt;(baz)</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="2996:1-2999:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo]: &lt;bar&gt;(baz)&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3002:1-3003:24" dir="auto">Both title and destination can contain backslash escapes
+and literal backslashes:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3005:1-3009:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url\bar\*baz "foo\"bar\baz"</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3011:1-3013:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url%5Cbar*baz" title="foo&amp;quot;bar\baz"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3016:1-3016:52" dir="auto">A link can come before its corresponding definition:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3018:1-3022:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: url</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3024:1-3026:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="url"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3029:1-3030:11" dir="auto">If there are several matching definitions, the first one takes
+precedence:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3032:1-3037:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: first</span>
+<span id="LC4" class="line" lang="plaintext">[foo]: second</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3039:1-3041:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="first"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3044:1-3045:33" dir="auto">As noted in the section on [Links], matching of labels is
+case-insensitive (see [matches]).</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3047:1-3051:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[FOO]: /url</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[Foo]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3053:1-3055:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url"&gt;Foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3058:1-3062:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[ΑΓΩ]: /φου</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[αγω]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3064:1-3066:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/%CF%86%CE%BF%CF%85"&gt;αγω&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3069:1-3070:39" dir="auto">Here is a link reference definition with no corresponding link.
+It contributes nothing to the document.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3072:1-3074:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3076:1-3077:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3080:1-3080:20" dir="auto">Here is another one:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3082:1-3087:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[</span>
+<span id="LC2" class="line" lang="plaintext">foo</span>
+<span id="LC3" class="line" lang="plaintext">]: /url</span>
+<span id="LC4" class="line" lang="plaintext">bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3089:1-3091:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3094:1-3095:44" dir="auto">This is not a link reference definition, because there are
+[non-whitespace characters] after the title:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3097:1-3099:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url "title" ok</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3101:1-3103:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo]: /url &amp;quot;title&amp;quot; ok&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3106:1-3106:57" dir="auto">This is a link reference definition, but it has no title:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3108:1-3111:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url</span>
+<span id="LC2" class="line" lang="plaintext">"title" ok</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3113:1-3115:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;quot;title&amp;quot; ok&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3118:1-3119:12" dir="auto">This is not a link reference definition, because it is indented
+four spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3121:1-3125:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> [foo]: /url "title"</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3127:1-3131:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;[foo]: /url &amp;quot;title&amp;quot;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3134:1-3135:13" dir="auto">This is not a link reference definition, because it occurs inside
+a code block:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3137:1-3143:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```</span>
+<span id="LC2" class="line" lang="plaintext">[foo]: /url</span>
+<span id="LC3" class="line" lang="plaintext">```</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">[foo]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3145:1-3149:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;[foo]: /url</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3152:1-3152:59" dir="auto">A [link reference definition] cannot interrupt a paragraph.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3154:1-3159:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext">[bar]: /baz</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">[bar]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3161:1-3165:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo</span>
+<span id="LC2" class="line" lang="plaintext">[bar]: /baz&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[bar]&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3168:1-3169:65" dir="auto">However, it can directly follow other block elements, such as headings
+and thematic breaks, and it need not be followed by a blank line.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3171:1-3175:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"># [Foo]</span>
+<span id="LC2" class="line" lang="plaintext">[foo]: /url</span>
+<span id="LC3" class="line" lang="plaintext">&gt; bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3177:1-3182:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h1&gt;&lt;a href="/url"&gt;Foo&lt;/a&gt;&lt;/h1&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3184:1-3189:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url</span>
+<span id="LC2" class="line" lang="plaintext">bar</span>
+<span id="LC3" class="line" lang="plaintext">===</span>
+<span id="LC4" class="line" lang="plaintext">[foo]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3191:1-3194:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h1&gt;bar&lt;/h1&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3196:1-3200:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url</span>
+<span id="LC2" class="line" lang="plaintext">===</span>
+<span id="LC3" class="line" lang="plaintext">[foo]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3202:1-3205:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;===</span>
+<span id="LC2" class="line" lang="plaintext">&lt;a href="/url"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3208:1-3209:61" dir="auto">Several [link reference definitions]
+can occur one after another, without intervening blank lines.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3211:1-3220:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /foo-url "foo"</span>
+<span id="LC2" class="line" lang="plaintext">[bar]: /bar-url</span>
+<span id="LC3" class="line" lang="plaintext"> "bar"</span>
+<span id="LC4" class="line" lang="plaintext">[baz]: /baz-url</span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext">[foo],</span>
+<span id="LC7" class="line" lang="plaintext">[bar],</span>
+<span id="LC8" class="line" lang="plaintext">[baz]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3222:1-3226:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/foo-url" title="foo"&gt;foo&lt;/a&gt;,</span>
+<span id="LC2" class="line" lang="plaintext">&lt;a href="/bar-url" title="bar"&gt;bar&lt;/a&gt;,</span>
+<span id="LC3" class="line" lang="plaintext">&lt;a href="/baz-url"&gt;baz&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3229:1-3232:12" dir="auto">[Link reference definitions] can occur
+inside block containers, like lists and block quotations. They
+affect the entire document, not just the container in which they
+are defined:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3234:1-3238:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">&gt; [foo]: /url</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3240:1-3244:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url"&gt;foo&lt;/a&gt;&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3247:1-3251:19" dir="auto">Whether something is a [link reference definition] is
+independent of whether the link reference it defines is
+used in the document. Thus, for example, the following
+document contains just a link reference definition, and
+no visible content:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3253:1-3255:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3257:1-3258:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="3261:1-3261:13" dir="auto">
+<a id="user-content-paragraphs" class="anchor" href="#paragraphs" aria-hidden="true"></a>Paragraphs</h2>
+<p data-sourcepos="3263:1-3268:13" dir="auto">A sequence of non-blank lines that cannot be interpreted as other
+kinds of blocks forms a <a href="@">paragraph</a>.
+The contents of the paragraph are the result of parsing the
+paragraph's raw content as inlines. The paragraph's raw content
+is formed by concatenating the lines and removing initial and final
+[whitespace].</p>
+<p data-sourcepos="3270:1-3270:37" dir="auto">A simple example with two paragraphs:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3272:1-3276:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">bbb</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3278:1-3281:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;aaa&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;bbb&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3284:1-3284:58" dir="auto">Paragraphs can contain multiple lines, but no blank lines:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3286:1-3292:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
+<span id="LC2" class="line" lang="plaintext">bbb</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">ccc</span>
+<span id="LC5" class="line" lang="plaintext">ddd</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3294:1-3299:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext">bbb&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;ccc</span>
+<span id="LC4" class="line" lang="plaintext">ddd&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3302:1-3302:54" dir="auto">Multiple blank lines between paragraph have no effect:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3304:1-3309:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">bbb</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3311:1-3314:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;aaa&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;bbb&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3317:1-3317:27" dir="auto">Leading spaces are skipped:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3319:1-3322:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> aaa</span>
+<span id="LC2" class="line" lang="plaintext"> bbb</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3324:1-3327:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext">bbb&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3330:1-3331:40" dir="auto">Lines after the first may be indented any amount, since indented
+code blocks cannot interrupt paragraphs.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3333:1-3337:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa</span>
+<span id="LC2" class="line" lang="plaintext"> bbb</span>
+<span id="LC3" class="line" lang="plaintext"> ccc</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3339:1-3343:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext">bbb</span>
+<span id="LC3" class="line" lang="plaintext">ccc&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3346:1-3347:44" dir="auto">However, the first line may be indented at most three spaces,
+or an indented code block will be triggered:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3349:1-3352:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> aaa</span>
+<span id="LC2" class="line" lang="plaintext">bbb</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3354:1-3357:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext">bbb&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3360:1-3363:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> aaa</span>
+<span id="LC2" class="line" lang="plaintext">bbb</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3365:1-3369:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;aaa</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;bbb&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3372:1-3374:7" dir="auto">Final spaces are stripped before inline parsing, so a paragraph
+that ends with two or more spaces will not end with a [hard line
+break]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3376:1-3379:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aaa </span>
+<span id="LC2" class="line" lang="plaintext">bbb </span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3381:1-3384:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;aaa&lt;br /&gt;</span>
+<span id="LC2" class="line" lang="plaintext">bbb&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="3387:1-3387:14" dir="auto">
+<a id="user-content-blank-lines" class="anchor" href="#blank-lines" aria-hidden="true"></a>Blank lines</h2>
+<p data-sourcepos="3389:1-3391:22" dir="auto">[Blank lines] between block-level elements are ignored,
+except for the role they play in determining whether a [list]
+is [tight] or [loose].</p>
+<p data-sourcepos="3393:1-3393:70" dir="auto">Blank lines at the beginning and end of the document are also ignored.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3395:1-3404:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> </span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">aaa</span>
+<span id="LC4" class="line" lang="plaintext"> </span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext"># aaa</span>
+<span id="LC7" class="line" lang="plaintext"></span>
+<span id="LC8" class="line" lang="plaintext"> </span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3406:1-3409:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;aaa&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h1&gt;aaa&lt;/h1&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div>
+<h2 data-sourcepos="3413:1-3413:21">
+<a id="user-content-tables-extension" class="anchor" href="#tables-extension" aria-hidden="true"></a>Tables (extension)</h2>
+<p data-sourcepos="3415:1-3416:10">GFM enables the <code>table</code> extension, where an additional leaf block type is
+available.</p>
+<p data-sourcepos="3418:1-3420:23">A <a href="@">table</a> is an arrangement of data with rows and columns, consisting of a
+single header row, a [delimiter row] separating the header from the data, and
+zero or more data rows.</p>
+<p data-sourcepos="3422:1-3426:23">Each row consists of cells containing arbitrary text, in which [inlines] are
+parsed, separated by pipes (<code>|</code>). A leading and trailing pipe is also
+recommended for clarity of reading, and if there's otherwise parsing ambiguity.
+Spaces between pipes and cell content are trimmed. Block-level elements cannot
+be inserted in a table.</p>
+<p data-sourcepos="3428:1-3430:40">The <a href="@">delimiter row</a> consists of cells whose only content are hyphens (<code>-</code>),
+and optionally, a leading or trailing colon (<code>:</code>), or both, to indicate left,
+right, or center alignment respectively.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3432:1-3436:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| foo | bar |</span>
+<span id="LC2" class="line" lang="plaintext">| --- | --- |</span>
+<span id="LC3" class="line" lang="plaintext">| baz | bim |</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3438:1-3453:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;thead&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;th&gt;foo&lt;/th&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;th&gt;bar&lt;/th&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/thead&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;tbody&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;td&gt;baz&lt;/td&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;td&gt;bim&lt;/td&gt;</span>
+<span id="LC12" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC13" class="line" lang="plaintext">&lt;/tbody&gt;</span>
+<span id="LC14" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3455:1-3456:74">Cells in one column don't need to match length, though it's easier to read if
+they are. Likewise, use of leading and trailing pipes may be inconsistent:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3458:1-3462:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| abc | defghi |</span>
+<span id="LC2" class="line" lang="plaintext">:-: | -----------:</span>
+<span id="LC3" class="line" lang="plaintext">bar | baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3464:1-3479:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;thead&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;th align="center"&gt;abc&lt;/th&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;th align="right"&gt;defghi&lt;/th&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/thead&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;tbody&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;td align="center"&gt;bar&lt;/td&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;td align="right"&gt;baz&lt;/td&gt;</span>
+<span id="LC12" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC13" class="line" lang="plaintext">&lt;/tbody&gt;</span>
+<span id="LC14" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3481:1-3482:13">Include a pipe in a cell's content by escaping it, including inside other
+inline spans:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3484:1-3489:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| f\|oo |</span>
+<span id="LC2" class="line" lang="plaintext">| ------ |</span>
+<span id="LC3" class="line" lang="plaintext">| b `\|` az |</span>
+<span id="LC4" class="line" lang="plaintext">| b **\|** im |</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3491:1-3507:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;thead&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;th&gt;f|oo&lt;/th&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/thead&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;tbody&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;td&gt;b &lt;code&gt;|&lt;/code&gt; az&lt;/td&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC12" class="line" lang="plaintext">&lt;td&gt;b &lt;strong&gt;|&lt;/strong&gt; im&lt;/td&gt;</span>
+<span id="LC13" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC14" class="line" lang="plaintext">&lt;/tbody&gt;</span>
+<span id="LC15" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3509:1-3510:22">The table is broken at the first empty line, or beginning of another
+block-level structure:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3512:1-3517:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| abc | def |</span>
+<span id="LC2" class="line" lang="plaintext">| --- | --- |</span>
+<span id="LC3" class="line" lang="plaintext">| bar | baz |</span>
+<span id="LC4" class="line" lang="plaintext">&gt; bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3519:1-3537:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;thead&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;th&gt;abc&lt;/th&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;th&gt;def&lt;/th&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/thead&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;tbody&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;td&gt;bar&lt;/td&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;td&gt;baz&lt;/td&gt;</span>
+<span id="LC12" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC13" class="line" lang="plaintext">&lt;/tbody&gt;</span>
+<span id="LC14" class="line" lang="plaintext">&lt;/table&gt;</span>
+<span id="LC15" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC16" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
+<span id="LC17" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3539:1-3546:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| abc | def |</span>
+<span id="LC2" class="line" lang="plaintext">| --- | --- |</span>
+<span id="LC3" class="line" lang="plaintext">| bar | baz |</span>
+<span id="LC4" class="line" lang="plaintext">bar</span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext">bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3548:1-3568:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;thead&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;th&gt;abc&lt;/th&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;th&gt;def&lt;/th&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/thead&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;tbody&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;td&gt;bar&lt;/td&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;td&gt;baz&lt;/td&gt;</span>
+<span id="LC12" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC13" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC14" class="line" lang="plaintext">&lt;td&gt;bar&lt;/td&gt;</span>
+<span id="LC15" class="line" lang="plaintext">&lt;td&gt;&lt;/td&gt;</span>
+<span id="LC16" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC17" class="line" lang="plaintext">&lt;/tbody&gt;</span>
+<span id="LC18" class="line" lang="plaintext">&lt;/table&gt;</span>
+<span id="LC19" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3570:1-3571:31">The header row must match the [delimiter row] in the number of cells. If not,
+a table will not be recognized:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3573:1-3577:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| abc | def |</span>
+<span id="LC2" class="line" lang="plaintext">| --- |</span>
+<span id="LC3" class="line" lang="plaintext">| bar |</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3579:1-3583:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;| abc | def |</span>
+<span id="LC2" class="line" lang="plaintext">| --- |</span>
+<span id="LC3" class="line" lang="plaintext">| bar |&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3585:1-3587:65">The remainder of the table's rows may vary in the number of cells. If there
+are a number of cells fewer than the number of cells in the header row, empty
+cells are inserted. If there are greater, the excess is ignored:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3589:1-3594:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| abc | def |</span>
+<span id="LC2" class="line" lang="plaintext">| --- | --- |</span>
+<span id="LC3" class="line" lang="plaintext">| bar |</span>
+<span id="LC4" class="line" lang="plaintext">| bar | baz | boo |</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3596:1-3615:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;thead&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;th&gt;abc&lt;/th&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;th&gt;def&lt;/th&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/thead&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;tbody&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;td&gt;bar&lt;/td&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;td&gt;&lt;/td&gt;</span>
+<span id="LC12" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC13" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC14" class="line" lang="plaintext">&lt;td&gt;bar&lt;/td&gt;</span>
+<span id="LC15" class="line" lang="plaintext">&lt;td&gt;baz&lt;/td&gt;</span>
+<span id="LC16" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC17" class="line" lang="plaintext">&lt;/tbody&gt;</span>
+<span id="LC18" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3617:1-3617:75">If there are no rows in the body, no <code>&lt;tbody&gt;</code> is generated in HTML output:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3619:1-3622:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">| abc | def |</span>
+<span id="LC2" class="line" lang="plaintext">| --- | --- |</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3624:1-3633:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;table&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;thead&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;tr&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;th&gt;abc&lt;/th&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;th&gt;def&lt;/th&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/tr&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/thead&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/table&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+</div>
+<h1 data-sourcepos="3637:1-3637:18" dir="auto">
+<a id="user-content-container-blocks" class="anchor" href="#container-blocks" aria-hidden="true"></a>Container blocks</h1>
+<p data-sourcepos="3639:1-3642:45" dir="auto">A <a href="#container-blocks">container block</a> is a block that has other
+blocks as its contents. There are two basic kinds of container blocks:
+[block quotes] and [list items].
+[Lists] are meta-containers for [list items].</p>
+<p data-sourcepos="3644:1-3645:26" dir="auto">We define the syntax for container blocks recursively. The general
+form of the definition is:</p>
+<blockquote data-sourcepos="3647:1-3649:35" dir="auto">
+<p data-sourcepos="3647:3-3649:35">If X is a sequence of blocks, then the result of
+transforming X in such-and-such a way is a container of type Y
+with these blocks as its content.</p>
+</blockquote>
+<p data-sourcepos="3651:1-3655:52" dir="auto">So, we explain what counts as a block quote or list item by explaining
+how these can be <em>generated</em> from their contents. This should suffice
+to define the syntax, although it does not give a recipe for <em>parsing</em>
+these constructions. (A recipe is provided below in the section entitled
+<a href="#appendix-a-parsing-strategy">A parsing strategy</a>.)</p>
+<h2 data-sourcepos="3657:1-3657:15" dir="auto">
+<a id="user-content-block-quotes" class="anchor" href="#block-quotes" aria-hidden="true"></a>Block quotes</h2>
+<p data-sourcepos="3659:1-3661:78" dir="auto">A <a href="@">block quote marker</a>
+consists of 0-3 spaces of initial indent, plus (a) the character <code>&gt;</code> together
+with a following space, or (b) a single character <code>&gt;</code> not followed by a space.</p>
+<p data-sourcepos="3663:1-3663:42" dir="auto">The following rules define [block quotes]:</p>
+<ol data-sourcepos="3665:1-3682:0" dir="auto">
+<li data-sourcepos="3665:1-3669:0">
+<p data-sourcepos="3665:5-3668:54"><strong>Basic case.</strong> If a string of lines <em>Ls</em> constitute a sequence
+of blocks <em>Bs</em>, then the result of prepending a [block quote
+marker] to the beginning of each line in <em>Ls</em>
+is a <a href="#block-quotes">block quote</a> containing <em>Bs</em>.</p>
+</li>
+<li data-sourcepos="3670:1-3679:0">
+<p data-sourcepos="3670:5-3678:48"><strong>Laziness.</strong> If a string of lines <em>Ls</em> constitute a <a href="#block-quotes">block
+quote</a> with contents <em>Bs</em>, then the result of deleting
+the initial [block quote marker] from one or
+more lines in which the next [non-whitespace character] after the [block
+quote marker] is [paragraph continuation
+text] is a block quote with <em>Bs</em> as its content.
+<a href="@">Paragraph continuation text</a> is text
+that will be parsed as part of the content of a paragraph, but does
+not occur at the beginning of the paragraph.</p>
+</li>
+<li data-sourcepos="3680:1-3682:0">
+<p data-sourcepos="3680:5-3681:65"><strong>Consecutiveness.</strong> A document cannot contain two [block
+quotes] in a row unless there is a [blank line] between them.</p>
+</li>
+</ol>
+<p data-sourcepos="3683:1-3683:54" dir="auto">Nothing else counts as a <a href="#block-quotes">block quote</a>.</p>
+<p data-sourcepos="3685:1-3685:25" dir="auto">Here is a simple example:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3687:1-3691:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; # Foo</span>
+<span id="LC2" class="line" lang="plaintext">&gt; bar</span>
+<span id="LC3" class="line" lang="plaintext">&gt; baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3693:1-3699:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;bar</span>
+<span id="LC4" class="line" lang="plaintext">baz&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3702:1-3702:51" dir="auto">The spaces after the <code>&gt;</code> characters can be omitted:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3704:1-3708:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt;# Foo</span>
+<span id="LC2" class="line" lang="plaintext">&gt;bar</span>
+<span id="LC3" class="line" lang="plaintext">&gt; baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3710:1-3716:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;bar</span>
+<span id="LC4" class="line" lang="plaintext">baz&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3719:1-3719:46" dir="auto">The <code>&gt;</code> characters can be indented 1-3 spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3721:1-3725:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &gt; # Foo</span>
+<span id="LC2" class="line" lang="plaintext"> &gt; bar</span>
+<span id="LC3" class="line" lang="plaintext"> &gt; baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3727:1-3733:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;bar</span>
+<span id="LC4" class="line" lang="plaintext">baz&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3736:1-3736:34" dir="auto">Four spaces gives us a code block:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3738:1-3742:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &gt; # Foo</span>
+<span id="LC2" class="line" lang="plaintext"> &gt; bar</span>
+<span id="LC3" class="line" lang="plaintext"> &gt; baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3744:1-3749:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&amp;gt; # Foo</span>
+<span id="LC2" class="line" lang="plaintext">&amp;gt; bar</span>
+<span id="LC3" class="line" lang="plaintext">&amp;gt; baz</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3752:1-3753:30" dir="auto">The Laziness clause allows us to omit the <code>&gt;</code> before
+[paragraph continuation text]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3755:1-3759:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; # Foo</span>
+<span id="LC2" class="line" lang="plaintext">&gt; bar</span>
+<span id="LC3" class="line" lang="plaintext">baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3761:1-3767:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;bar</span>
+<span id="LC4" class="line" lang="plaintext">baz&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3770:1-3771:19" dir="auto">A block quote can contain some lazy and some non-lazy
+continuation lines:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3773:1-3777:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; bar</span>
+<span id="LC2" class="line" lang="plaintext">baz</span>
+<span id="LC3" class="line" lang="plaintext">&gt; foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3779:1-3785:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;bar</span>
+<span id="LC3" class="line" lang="plaintext">baz</span>
+<span id="LC4" class="line" lang="plaintext">foo&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3788:1-3790:61" dir="auto">Laziness only applies to lines that would have been continuations of
+paragraphs had they been prepended with [block quote markers].
+For example, the <code>&gt; </code> cannot be omitted in the second line of</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3792:1-3795:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="gt">&gt; foo</span></span>
+<span id="LC2" class="line" lang="markdown"><span class="gt">&gt; ---</span></span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3797:1-3797:29" dir="auto">without changing the meaning:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3799:1-3802:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
+<span id="LC2" class="line" lang="plaintext">---</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3804:1-3809:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;hr /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3812:1-3812:52" dir="auto">Similarly, if we omit the <code>&gt; </code> in the second line of</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3814:1-3817:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="gt">&gt; - foo</span></span>
+<span id="LC2" class="line" lang="markdown"><span class="gt">&gt; - bar</span></span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3819:1-3819:47" dir="auto">then the block quote ends after the first line:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3821:1-3824:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; - foo</span>
+<span id="LC2" class="line" lang="plaintext">- bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3826:1-3835:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3838:1-3839:53" dir="auto">For the same reason, we can't omit the <code>&gt; </code> in front of
+subsequent lines of an indented or fenced code block:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3841:1-3844:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
+<span id="LC2" class="line" lang="plaintext"> bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3846:1-3853:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3856:1-3860:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; ```</span>
+<span id="LC2" class="line" lang="plaintext">foo</span>
+<span id="LC3" class="line" lang="plaintext">```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3862:1-3868:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3871:1-3872:19" dir="auto">Note that in the following case, we have a [lazy
+continuation line]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3874:1-3877:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
+<span id="LC2" class="line" lang="plaintext"> - bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3879:1-3884:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;foo</span>
+<span id="LC3" class="line" lang="plaintext">- bar&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3887:1-3887:24" dir="auto">To see why, note that in</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3889:1-3892:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="gt">&gt; foo</span></span>
+<span id="LC2" class="line" lang="markdown"><span class="gt">&gt; - bar</span></span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3894:1-3896:61" dir="auto">the <code>- bar</code> is indented too far to start a list, and can't
+be an indented code block because indented code blocks cannot
+interrupt paragraphs, so it is [paragraph continuation text].</p>
+<p data-sourcepos="3898:1-3898:27" dir="auto">A block quote can be empty:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3900:1-3902:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3904:1-3907:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3910:1-3914:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&gt; </span>
+<span id="LC3" class="line" lang="plaintext">&gt; </span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3916:1-3919:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3922:1-3922:52" dir="auto">A block quote can have initial or final blank lines:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3924:1-3928:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&gt; foo</span>
+<span id="LC3" class="line" lang="plaintext">&gt; </span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3930:1-3934:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3937:1-3937:43" dir="auto">A blank line always separates block quotes:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3939:1-3943:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">&gt; bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3945:1-3952:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3955:1-3958:44" dir="auto">(Most current Markdown implementations, including John Gruber's
+original <code>Markdown.pl</code>, will parse this example as a single block quote
+with two paragraphs. But it seems better to allow the author to decide
+whether two block quotes or one are wanted.)</p>
+<p data-sourcepos="3960:1-3961:28" dir="auto">Consecutiveness means that if we put these block quotes together,
+we get a single block quote:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3963:1-3966:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
+<span id="LC2" class="line" lang="plaintext">&gt; bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3968:1-3973:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;foo</span>
+<span id="LC3" class="line" lang="plaintext">bar&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3976:1-3976:46" dir="auto">To get a block quote with two paragraphs, use:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3978:1-3982:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; foo</span>
+<span id="LC2" class="line" lang="plaintext">&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&gt; bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3984:1-3989:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="3992:1-3992:38" dir="auto">Block quotes can interrupt paragraphs:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3994:1-3997:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span>
+<span id="LC2" class="line" lang="plaintext">&gt; bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="3999:1-4004:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4007:1-4008:7" dir="auto">In general, blank lines are not needed before or after block
+quotes:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4010:1-4014:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; aaa</span>
+<span id="LC2" class="line" lang="plaintext">***</span>
+<span id="LC3" class="line" lang="plaintext">&gt; bbb</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4016:1-4024:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;aaa&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;hr /&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;p&gt;bbb&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4027:1-4028:40" dir="auto">However, because of laziness, a blank line is needed between
+a block quote and a following paragraph:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4030:1-4033:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; bar</span>
+<span id="LC2" class="line" lang="plaintext">baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4035:1-4040:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;bar</span>
+<span id="LC3" class="line" lang="plaintext">baz&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4043:1-4047:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; bar</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4049:1-4054:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4057:1-4061:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; bar</span>
+<span id="LC2" class="line" lang="plaintext">&gt;</span>
+<span id="LC3" class="line" lang="plaintext">baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4063:1-4068:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4071:1-4073:19" dir="auto">It is a consequence of the Laziness rule that any number
+of initial <code>&gt;</code>s may be omitted on a continuation line of a
+nested block quote:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4075:1-4078:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; &gt; &gt; foo</span>
+<span id="LC2" class="line" lang="plaintext">bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4080:1-4089:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;foo</span>
+<span id="LC5" class="line" lang="plaintext">bar&lt;/p&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4092:1-4096:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt;&gt;&gt; foo</span>
+<span id="LC2" class="line" lang="plaintext">&gt; bar</span>
+<span id="LC3" class="line" lang="plaintext">&gt;&gt;baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4098:1-4108:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;foo</span>
+<span id="LC5" class="line" lang="plaintext">bar</span>
+<span id="LC6" class="line" lang="plaintext">baz&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4111:1-4114:8" dir="auto">When including an indented code block in a block quote,
+remember that the [block quote marker] includes
+both the <code>&gt;</code> and a following space. So <em>five spaces</em> are needed after
+the <code>&gt;</code>:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4116:1-4120:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; code</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">&gt; not code</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4122:1-4130:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;code</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;p&gt;not code&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="4134:1-4134:13" dir="auto">
+<a id="user-content-list-items" class="anchor" href="#list-items" aria-hidden="true"></a>List items</h2>
+<p data-sourcepos="4136:1-4137:49" dir="auto">A <a href="@">list marker</a> is a
+[bullet list marker] or an [ordered list marker].</p>
+<p data-sourcepos="4139:1-4140:32" dir="auto">A <a href="@">bullet list marker</a>
+is a <code>-</code>, <code>+</code>, or <code>*</code> character.</p>
+<p data-sourcepos="4142:1-4146:18" dir="auto">An <a href="@">ordered list marker</a>
+is a sequence of 1--9 arabic digits (<code>0-9</code>), followed by either a
+<code>.</code> character or a <code>)</code> character. (The reason for the length
+limit is that with 10 digits we start seeing integer overflows
+in some browsers.)</p>
+<p data-sourcepos="4148:1-4148:40" dir="auto">The following rules define [list items]:</p>
+<ol data-sourcepos="4150:1-4169:0" dir="auto">
+<li data-sourcepos="4150:1-4169:0">
+<p data-sourcepos="4150:5-4158:45"><strong>Basic case.</strong> If a sequence of lines <em>Ls</em> constitute a sequence of
+blocks <em>Bs</em> starting with a [non-whitespace character], and <em>M</em> is a
+list marker of width <em>W</em> followed by 1 ≤ <em>N</em> ≤ 4 spaces, then the result
+of prepending <em>M</em> and the following spaces to the first line of
+<em>Ls</em>, and indenting subsequent lines of <em>Ls</em> by <em>W + N</em> spaces, is a
+list item with <em>Bs</em> as its contents. The type of the list item
+(bullet or ordered) is determined by the type of its list marker.
+If the list item is ordered, then it is also assigned a start
+number, based on the ordered list marker.</p>
+<p data-sourcepos="4160:5-4160:15">Exceptions:</p>
+<ol data-sourcepos="4162:5-4169:0">
+<li data-sourcepos="4162:5-4166:57">When the first list item in a [list] interrupts
+a paragraph---that is, when it starts on a line that would
+otherwise count as [paragraph continuation text]---then (a)
+the lines <em>Ls</em> must not begin with a blank line, and (b) if
+the list item is ordered, the start number must be 1.</li>
+<li data-sourcepos="4167:5-4169:0">If any line is a [thematic break][thematic breaks] then
+that line is not a list item.</li>
+</ol>
+</li>
+</ol>
+<p data-sourcepos="4170:1-4170:34" dir="auto">For example, let <em>Ls</em> be the lines</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4172:1-4179:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">A paragraph</span>
+<span id="LC2" class="line" lang="plaintext">with two lines.</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> indented code</span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext">&gt; A block quote.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4181:1-4189:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;A paragraph</span>
+<span id="LC2" class="line" lang="plaintext">with two lines.&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;p&gt;A block quote.&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4192:1-4194:30" dir="auto">And let <em>M</em> be the marker <code>1.</code>, and <em>N</em> = 2. Then rule #1 says
+that the following is an ordered list item with start number 1,
+and the same contents as <em>Ls</em>:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4196:1-4203:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. A paragraph</span>
+<span id="LC2" class="line" lang="plaintext"> with two lines.</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> indented code</span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext"> &gt; A block quote.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4205:1-4217:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;A paragraph</span>
+<span id="LC4" class="line" lang="plaintext">with two lines.&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;p&gt;A block quote.&lt;/p&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4220:1-4226:5" dir="auto">The most important thing to notice is that the position of
+the text after the list marker determines how much indentation
+is needed in subsequent blocks in the list item. If the list
+marker takes up two spaces, and there are three spaces between
+the list marker and the next [non-whitespace character], then blocks
+must be indented five spaces in order to fall under the list
+item.</p>
+<p data-sourcepos="4228:1-4229:24" dir="auto">Here are some examples showing how far content must be indented to be
+put under the list item:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4231:1-4235:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- one</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> two</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4237:1-4242:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;one&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;two&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4245:1-4249:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- one</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> two</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4251:1-4258:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;one&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;two&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4261:1-4265:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> - one</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> two</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4267:1-4273:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;one&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt; two</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4276:1-4280:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> - one</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> two</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4282:1-4289:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;one&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;two&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4292:1-4298:13" dir="auto">It is tempting to think of this in terms of columns: the continuation
+blocks must be indented at least to the column of the first
+[non-whitespace character] after the list marker. However, that is not quite right.
+The spaces after the list marker determine how much relative indentation
+is needed. Which column this indentation reaches will depend on
+how the list item is embedded in other constructions, as shown by
+this example:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4300:1-4304:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> &gt; &gt; 1. one</span>
+<span id="LC2" class="line" lang="plaintext">&gt;&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&gt;&gt; two</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4306:1-4317:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;p&gt;one&lt;/p&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;p&gt;two&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/ol&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4320:1-4322:67" dir="auto">Here <code>two</code> occurs in the same column as the list marker <code>1.</code>,
+but is actually contained in the list item, because there is
+sufficient indentation after the last containing blockquote marker.</p>
+<p data-sourcepos="4324:1-4327:38" dir="auto">The converse is also possible. In the following example, the word <code>two</code>
+occurs far to the right of the initial text of the list item, <code>one</code>, but
+it is not considered part of the list item, because it is not indented
+far enough past the blockquote marker:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4329:1-4333:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt;&gt;- one</span>
+<span id="LC2" class="line" lang="plaintext">&gt;&gt;</span>
+<span id="LC3" class="line" lang="plaintext"> &gt; &gt; two</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4335:1-4344:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;one&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;p&gt;two&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4347:1-4348:51" dir="auto">Note that at least one space is needed between the list marker and
+any following content, so these are not list items:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4350:1-4354:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-one</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">2.two</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4356:1-4359:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;-one&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;2.two&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4362:1-4363:15" dir="auto">A list item may contain blocks that are separated by more than
+one blank line.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4365:1-4370:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4372:1-4379:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4382:1-4382:42" dir="auto">A list item may contain any kind of block:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4384:1-4394:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> ```</span>
+<span id="LC4" class="line" lang="plaintext"> bar</span>
+<span id="LC5" class="line" lang="plaintext"> ```</span>
+<span id="LC6" class="line" lang="plaintext"></span>
+<span id="LC7" class="line" lang="plaintext"> baz</span>
+<span id="LC8" class="line" lang="plaintext"></span>
+<span id="LC9" class="line" lang="plaintext"> &gt; bam</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4396:1-4408:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;p&gt;bam&lt;/p&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4411:1-4412:43" dir="auto">A list item that contains an indented code block will preserve
+empty lines within the code block verbatim.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4414:1-4421:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- Foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> bar</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext"> baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4423:1-4434:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;Foo&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext"></span>
+<span id="LC7" class="line" lang="plaintext">baz</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4436:1-4436:65" dir="auto">Note that ordered list start numbers must be nine digits or less:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4438:1-4440:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">123456789. ok</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4442:1-4446:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol start="123456789"&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;ok&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4449:1-4451:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1234567890. not ok</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4453:1-4455:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;1234567890. not ok&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4458:1-4458:33" dir="auto">A start number may begin with 0s:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4460:1-4462:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">0. ok</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4464:1-4468:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol start="0"&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;ok&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4471:1-4473:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">003. ok</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4475:1-4479:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol start="3"&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;ok&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4482:1-4482:35" dir="auto">A start number may not be negative:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4484:1-4486:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-1. not ok</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4488:1-4490:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;-1. not ok&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<ol start="2" data-sourcepos="4494:1-4504:0" dir="auto">
+<li data-sourcepos="4494:1-4504:0">
+<strong>Item starting with indented code.</strong> If a sequence of lines <em>Ls</em>
+constitute a sequence of blocks <em>Bs</em> starting with an indented code
+block, and <em>M</em> is a list marker of width <em>W</em> followed by
+one space, then the result of prepending <em>M</em> and the following
+space to the first line of <em>Ls</em>, and indenting subsequent lines of
+<em>Ls</em> by <em>W + 1</em> spaces, is a list item with <em>Bs</em> as its contents.
+If a line is empty, then it need not be indented. The type of the
+list item (bullet or ordered) is determined by the type of its list
+marker. If the list item is ordered, then it is also assigned a
+start number, based on the ordered list marker.</li>
+</ol>
+<p data-sourcepos="4505:1-4507:39" dir="auto">An indented code block will have to be indented four spaces beyond
+the edge of the region where text will be included in the list item.
+In the following case that is 6 spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4509:1-4513:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4515:1-4523:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4526:1-4526:33" dir="auto">And in this case it is 11 spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4528:1-4532:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> 10. foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4534:1-4542:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol start="10"&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4545:1-4547:12" dir="auto">If the <em>first</em> block in the list item is an indented code block,
+then by rule #2, the contents must be indented <em>one</em> space after the
+list marker:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4549:1-4555:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> indented code</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">paragraph</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext"> more code</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4557:1-4563:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;paragraph&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;more code</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4566:1-4572:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. indented code</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> paragraph</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext"> more code</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4574:1-4584:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;p&gt;paragraph&lt;/p&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;more code</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4587:1-4588:22" dir="auto">Note that an additional space indent is interpreted as space
+inside the code block:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4590:1-4596:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. indented code</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> paragraph</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext"> more code</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4598:1-4608:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt; indented code</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;p&gt;paragraph&lt;/p&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;more code</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4611:1-4617:55" dir="auto">Note that rules #1 and #2 only apply to two cases: (a) cases
+in which the lines to be included in a list item begin with a
+[non-whitespace character], and (b) cases in which
+they begin with an indented code
+block. In a case like the following, where the first block begins with
+a three-space indent, the rules do not allow us to form a list item by
+indenting the whole thing and prepending a list marker:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4619:1-4623:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4625:1-4628:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4631:1-4635:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4637:1-4642:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4645:1-4648:15" dir="auto">This is not a significant restriction, because when a block begins
+with 1-3 spaces indent, the indentation can always be removed without
+a change in interpretation, allowing rule #1 to be applied. So, in
+the above case:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4650:1-4654:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4656:1-4663:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<ol start="3" data-sourcepos="4666:1-4677:0" dir="auto">
+<li data-sourcepos="4666:1-4677:0">
+<strong>Item starting with a blank line.</strong> If a sequence of lines <em>Ls</em>
+starting with a single [blank line] constitute a (possibly empty)
+sequence of blocks <em>Bs</em>, not separated from each other by more than
+one blank line, and <em>M</em> is a list marker of width <em>W</em>,
+then the result of prepending <em>M</em> to the first line of <em>Ls</em>, and
+indenting subsequent lines of <em>Ls</em> by <em>W + 1</em> spaces, is a list
+item with <em>Bs</em> as its contents.
+If a line is empty, then it need not be indented. The type of the
+list item (bullet or ordered) is determined by the type of its list
+marker. If the list item is ordered, then it is also assigned a
+start number, based on the ordered list marker.</li>
+</ol>
+<p data-sourcepos="4678:1-4678:72" dir="auto">Here are some list items that start with a blank line but are not empty:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4680:1-4689:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-</span>
+<span id="LC2" class="line" lang="plaintext"> foo</span>
+<span id="LC3" class="line" lang="plaintext">-</span>
+<span id="LC4" class="line" lang="plaintext"> ```</span>
+<span id="LC5" class="line" lang="plaintext"> bar</span>
+<span id="LC6" class="line" lang="plaintext"> ```</span>
+<span id="LC7" class="line" lang="plaintext">-</span>
+<span id="LC8" class="line" lang="plaintext"> baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4691:1-4703:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;bar</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;baz</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4705:1-4706:66" dir="auto">When the list item starts with a blank line, the number of spaces
+following the list marker doesn't change the required indentation:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4708:1-4711:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- </span>
+<span id="LC2" class="line" lang="plaintext"> foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4713:1-4717:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4720:1-4722:5" dir="auto">A list item can begin with at most one blank line.
+In the following example, <code>foo</code> is not part of the list
+item:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4724:1-4728:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">-</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4730:1-4735:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4738:1-4738:34" dir="auto">Here is an empty bullet list item:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4740:1-4744:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext">-</span>
+<span id="LC3" class="line" lang="plaintext">- bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4746:1-4752:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4755:1-4755:72" dir="auto">It does not matter whether there are spaces following the [list marker]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4757:1-4761:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext">- </span>
+<span id="LC3" class="line" lang="plaintext">- bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4763:1-4769:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4772:1-4772:35" dir="auto">Here is an empty ordered list item:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4774:1-4778:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. foo</span>
+<span id="LC2" class="line" lang="plaintext">2.</span>
+<span id="LC3" class="line" lang="plaintext">3. bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4780:1-4786:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4789:1-4789:48" dir="auto">A list may start or end with an empty list item:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4791:1-4793:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4795:1-4799:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4801:1-4801:57" dir="auto">However, an empty list item cannot interrupt a paragraph:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4803:1-4809:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span>
+<span id="LC2" class="line" lang="plaintext">*</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">foo</span>
+<span id="LC5" class="line" lang="plaintext">1.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4811:1-4816:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo</span>
+<span id="LC2" class="line" lang="plaintext">*&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo</span>
+<span id="LC4" class="line" lang="plaintext">1.&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<ol start="4" data-sourcepos="4819:1-4824:0" dir="auto">
+<li data-sourcepos="4819:1-4824:0">
+<strong>Indentation.</strong> If a sequence of lines <em>Ls</em> constitutes a list item
+according to rule #1, #2, or #3, then the result of indenting each line
+of <em>Ls</em> by 1-3 spaces (the same for each line) also constitutes a
+list item with the same contents and attributes. If a line is
+empty, then it need not be indented.</li>
+</ol>
+<p data-sourcepos="4825:1-4825:19" dir="auto">Indented one space:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4827:1-4834:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> 1. A paragraph</span>
+<span id="LC2" class="line" lang="plaintext"> with two lines.</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> indented code</span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext"> &gt; A block quote.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4836:1-4848:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;A paragraph</span>
+<span id="LC4" class="line" lang="plaintext">with two lines.&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;p&gt;A block quote.&lt;/p&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4851:1-4851:20" dir="auto">Indented two spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4853:1-4860:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> 1. A paragraph</span>
+<span id="LC2" class="line" lang="plaintext"> with two lines.</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> indented code</span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext"> &gt; A block quote.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4862:1-4874:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;A paragraph</span>
+<span id="LC4" class="line" lang="plaintext">with two lines.&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;p&gt;A block quote.&lt;/p&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4877:1-4877:22" dir="auto">Indented three spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4879:1-4886:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> 1. A paragraph</span>
+<span id="LC2" class="line" lang="plaintext"> with two lines.</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> indented code</span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext"> &gt; A block quote.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4888:1-4900:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;A paragraph</span>
+<span id="LC4" class="line" lang="plaintext">with two lines.&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;p&gt;A block quote.&lt;/p&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4903:1-4903:38" dir="auto">Four spaces indent gives a code block:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4905:1-4912:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> 1. A paragraph</span>
+<span id="LC2" class="line" lang="plaintext"> with two lines.</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> indented code</span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext"> &gt; A block quote.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4914:1-4922:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;1. A paragraph</span>
+<span id="LC2" class="line" lang="plaintext"> with two lines.</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> indented code</span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext"> &amp;gt; A block quote.</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<ol start="5" data-sourcepos="4926:1-4934:0" dir="auto">
+<li data-sourcepos="4926:1-4934:0">
+<strong>Laziness.</strong> If a string of lines <em>Ls</em> constitute a <a href="#list-items">list
+item</a> with contents <em>Bs</em>, then the result of deleting
+some or all of the indentation from one or more lines in which the
+next [non-whitespace character] after the indentation is
+[paragraph continuation text] is a
+list item with the same contents and attributes. The unindented
+lines are called
+<a href="@">lazy continuation line</a>s.</li>
+</ol>
+<p data-sourcepos="4935:1-4935:50" dir="auto">Here is an example with [lazy continuation lines]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4937:1-4944:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> 1. A paragraph</span>
+<span id="LC2" class="line" lang="plaintext">with two lines.</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> indented code</span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext"> &gt; A block quote.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4946:1-4958:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;A paragraph</span>
+<span id="LC4" class="line" lang="plaintext">with two lines.&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;indented code</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;p&gt;A block quote.&lt;/p&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4961:1-4961:37" dir="auto">Indentation can be partially deleted:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4963:1-4966:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> 1. A paragraph</span>
+<span id="LC2" class="line" lang="plaintext"> with two lines.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4968:1-4973:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;A paragraph</span>
+<span id="LC3" class="line" lang="plaintext">with two lines.&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="4976:1-4976:63" dir="auto">These examples show how laziness can work in nested structures:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4978:1-4981:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; 1. &gt; Blockquote</span>
+<span id="LC2" class="line" lang="plaintext">continued here.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4983:1-4994:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;p&gt;Blockquote</span>
+<span id="LC6" class="line" lang="plaintext">continued here.&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/ol&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="4997:1-5000:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&gt; 1. &gt; Blockquote</span>
+<span id="LC2" class="line" lang="plaintext">&gt; continued here.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5002:1-5013:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;p&gt;Blockquote</span>
+<span id="LC6" class="line" lang="plaintext">continued here.&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/ol&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<ol start="6" data-sourcepos="5017:1-5019:0" dir="auto">
+<li data-sourcepos="5017:1-5019:0">
+<strong>That's all.</strong> Nothing that is not counted as a list item by rules
+#1--5 counts as a <a href="#list-items">list item</a>.</li>
+</ol>
+<p data-sourcepos="5020:1-5023:17" dir="auto">The rules for sublists follow from the general rules
+[above][List items]. A sublist must be indented the same number
+of spaces a paragraph would need to be in order to be included
+in the list item.</p>
+<p data-sourcepos="5025:1-5025:43" dir="auto">So, in this case we need two spaces indent:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5027:1-5032:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext"> - bar</span>
+<span id="LC3" class="line" lang="plaintext"> - baz</span>
+<span id="LC4" class="line" lang="plaintext"> - boo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5034:1-5050:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo</span>
+<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;bar</span>
+<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;li&gt;baz</span>
+<span id="LC7" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;li&gt;boo&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC12" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC13" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC14" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC15" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5053:1-5053:18" dir="auto">One is not enough:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5055:1-5060:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext"> - bar</span>
+<span id="LC3" class="line" lang="plaintext"> - baz</span>
+<span id="LC4" class="line" lang="plaintext"> - boo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5062:1-5069:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;baz&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;boo&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5072:1-5072:52" dir="auto">Here we need four, because the list marker is wider:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5074:1-5077:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">10) foo</span>
+<span id="LC2" class="line" lang="plaintext"> - bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5079:1-5087:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol start="10"&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo</span>
+<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5090:1-5090:20" dir="auto">Three is not enough:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5092:1-5095:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">10) foo</span>
+<span id="LC2" class="line" lang="plaintext"> - bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5097:1-5104:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol start="10"&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/ol&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5107:1-5107:45" dir="auto">A list may be the first block in a list item:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5109:1-5111:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- - foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5113:1-5121:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5124:1-5126:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. - 2. foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5128:1-5140:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;ol start="2"&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ol&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5143:1-5143:34" dir="auto">A list item can contain a heading:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5145:1-5150:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- # Foo</span>
+<span id="LC2" class="line" lang="plaintext">- Bar</span>
+<span id="LC3" class="line" lang="plaintext"> ---</span>
+<span id="LC4" class="line" lang="plaintext"> baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5152:1-5161:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;h1&gt;Foo&lt;/h1&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;h2&gt;Bar&lt;/h2&gt;</span>
+<span id="LC7" class="line" lang="plaintext">baz&lt;/li&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h3 data-sourcepos="5164:1-5164:14" dir="auto">
+<a id="user-content-motivation" class="anchor" href="#motivation" aria-hidden="true"></a>Motivation</h3>
+<p data-sourcepos="5166:1-5166:64" dir="auto">John Gruber's Markdown spec says the following about list items:</p>
+<ol data-sourcepos="5168:1-5187:0" dir="auto">
+<li data-sourcepos="5168:1-5171:0">
+<p data-sourcepos="5168:4-5170:20">"List markers typically start at the left margin, but may be indented
+by up to three spaces. List markers must be followed by one or more
+spaces or a tab."</p>
+</li>
+<li data-sourcepos="5172:1-5174:0">
+<p data-sourcepos="5172:4-5173:48">"To make lists look nice, you can wrap items with hanging indents....
+But if you don't want to, you don't have to."</p>
+</li>
+<li data-sourcepos="5175:1-5178:0">
+<p data-sourcepos="5175:4-5177:8">"List items may consist of multiple paragraphs. Each subsequent
+paragraph in a list item must be indented by either 4 spaces or one
+tab."</p>
+</li>
+<li data-sourcepos="5179:1-5181:0">
+<p data-sourcepos="5179:4-5180:55">"It looks nice if you indent every line of the subsequent paragraphs,
+but here again, Markdown will allow you to be lazy."</p>
+</li>
+<li data-sourcepos="5182:1-5184:0">
+<p data-sourcepos="5182:4-5183:35">"To put a blockquote within a list item, the blockquote's <code>&gt;</code>
+delimiters need to be indented."</p>
+</li>
+<li data-sourcepos="5185:1-5187:0">
+<p data-sourcepos="5185:4-5186:44">"To put a code block within a list item, the code block needs to be
+indented twice — 8 spaces or two tabs."</p>
+</li>
+</ol>
+<p data-sourcepos="5188:1-5197:18" dir="auto">These rules specify that a paragraph under a list item must be indented
+four spaces (presumably, from the left margin, rather than the start of
+the list marker, but this is not said), and that code under a list item
+must be indented eight spaces instead of the usual four. They also say
+that a block quote must be indented, but not by how much; however, the
+example given has four spaces indentation. Although nothing is said
+about other kinds of block-level content, it is certainly reasonable to
+infer that <em>all</em> block elements under a list item, including other
+lists, must be indented four spaces. This principle has been called the
+<em>four-space rule</em>.</p>
+<p data-sourcepos="5199:1-5210:48" dir="auto">The four-space rule is clear and principled, and if the reference
+implementation <code>Markdown.pl</code> had followed it, it probably would have
+become the standard. However, <code>Markdown.pl</code> allowed paragraphs and
+sublists to start with only two spaces indentation, at least on the
+outer level. Worse, its behavior was inconsistent: a sublist of an
+outer-level list needed two spaces indentation, but a sublist of this
+sublist needed three spaces. It is not surprising, then, that different
+implementations of Markdown have developed very different rules for
+determining what comes under a list item. (Pandoc and python-Markdown,
+for example, stuck with Gruber's syntax description and the four-space
+rule, while discount, redcarpet, marked, PHP Markdown, and others
+followed <code>Markdown.pl</code>'s behavior more closely.)</p>
+<p data-sourcepos="5212:1-5217:45" dir="auto">Unfortunately, given the divergences between implementations, there
+is no way to give a spec for list items that will be guaranteed not
+to break any existing documents. However, the spec given here should
+correctly handle lists formatted with either the four-space rule or
+the more forgiving <code>Markdown.pl</code> behavior, provided they are laid out
+in a way that is natural for a human to read.</p>
+<p data-sourcepos="5219:1-5225:22" dir="auto">The strategy here is to let the width and indentation of the list marker
+determine the indentation necessary for blocks to fall under the list
+item, rather than having a fixed and arbitrary number. The writer can
+think of the body of the list item as a unit which gets indented to the
+right enough to fit the list marker (and any indentation on the list
+marker). (The laziness rule, #5, then allows continuation lines to be
+unindented if needed.)</p>
+<p data-sourcepos="5227:1-5229:39" dir="auto">This rule is superior, we claim, to any rule requiring a fixed level of
+indentation from the margin. The four-space rule is clear but
+unnatural. It is quite unintuitive that</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5231:1-5237:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="p">-</span> foo</span>
+<span id="LC2" class="line" lang="markdown"></span>
+<span id="LC3" class="line" lang="markdown"> bar</span>
+<span id="LC4" class="line" lang="markdown"></span>
+<span id="LC5" class="line" lang="markdown"><span class="p"> -</span> baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5239:1-5239:60" dir="auto">should be parsed as two lists with an intervening paragraph,</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5241:1-5249:3" lang="html" class="code highlight js-syntax-highlight language-html" v-pre="true"><code><span id="LC1" class="line" lang="html"><span class="nt">&lt;ul&gt;</span></span>
+<span id="LC2" class="line" lang="html"><span class="nt">&lt;li&gt;</span>foo<span class="nt">&lt;/li&gt;</span></span>
+<span id="LC3" class="line" lang="html"><span class="nt">&lt;/ul&gt;</span></span>
+<span id="LC4" class="line" lang="html"><span class="nt">&lt;p&gt;</span>bar<span class="nt">&lt;/p&gt;</span></span>
+<span id="LC5" class="line" lang="html"><span class="nt">&lt;ul&gt;</span></span>
+<span id="LC6" class="line" lang="html"><span class="nt">&lt;li&gt;</span>baz<span class="nt">&lt;/li&gt;</span></span>
+<span id="LC7" class="line" lang="html"><span class="nt">&lt;/ul&gt;</span></span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5251:1-5251:58" dir="auto">as the four-space rule demands, rather than a single list,</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5253:1-5263:3" lang="html" class="code highlight js-syntax-highlight language-html" v-pre="true"><code><span id="LC1" class="line" lang="html"><span class="nt">&lt;ul&gt;</span></span>
+<span id="LC2" class="line" lang="html"><span class="nt">&lt;li&gt;</span></span>
+<span id="LC3" class="line" lang="html"><span class="nt">&lt;p&gt;</span>foo<span class="nt">&lt;/p&gt;</span></span>
+<span id="LC4" class="line" lang="html"><span class="nt">&lt;p&gt;</span>bar<span class="nt">&lt;/p&gt;</span></span>
+<span id="LC5" class="line" lang="html"><span class="nt">&lt;ul&gt;</span></span>
+<span id="LC6" class="line" lang="html"><span class="nt">&lt;li&gt;</span>baz<span class="nt">&lt;/li&gt;</span></span>
+<span id="LC7" class="line" lang="html"><span class="nt">&lt;/ul&gt;</span></span>
+<span id="LC8" class="line" lang="html"><span class="nt">&lt;/li&gt;</span></span>
+<span id="LC9" class="line" lang="html"><span class="nt">&lt;/ul&gt;</span></span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5265:1-5266:62" dir="auto">The choice of four spaces is arbitrary. It can be learned, but it is
+not likely to be guessed, and it trips up beginners regularly.</p>
+<p data-sourcepos="5268:1-5272:20" dir="auto">Would it help to adopt a two-space rule? The problem is that such
+a rule, together with the rule allowing 1--3 spaces indentation of the
+initial list marker, allows text that is indented <em>less than</em> the
+original list marker to be included in the list item. For example,
+<code>Markdown.pl</code> parses</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5274:1-5278:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="p"> -</span> one</span>
+<span id="LC2" class="line" lang="markdown"></span>
+<span id="LC3" class="line" lang="markdown"> two</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5280:1-5280:59" dir="auto">as a single list item, with <code>two</code> a continuation paragraph:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5282:1-5289:3" lang="html" class="code highlight js-syntax-highlight language-html" v-pre="true"><code><span id="LC1" class="line" lang="html"><span class="nt">&lt;ul&gt;</span></span>
+<span id="LC2" class="line" lang="html"><span class="nt">&lt;li&gt;</span></span>
+<span id="LC3" class="line" lang="html"><span class="nt">&lt;p&gt;</span>one<span class="nt">&lt;/p&gt;</span></span>
+<span id="LC4" class="line" lang="html"><span class="nt">&lt;p&gt;</span>two<span class="nt">&lt;/p&gt;</span></span>
+<span id="LC5" class="line" lang="html"><span class="nt">&lt;/li&gt;</span></span>
+<span id="LC6" class="line" lang="html"><span class="nt">&lt;/ul&gt;</span></span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5291:1-5291:13" dir="auto">and similarly</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5293:1-5297:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="gt">&gt; - one</span></span>
+<span id="LC2" class="line" lang="markdown"><span class="gt">&gt;</span></span>
+<span id="LC3" class="line" lang="markdown"><span class="gt">&gt; two</span></span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5299:1-5299:2" dir="auto">as</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5301:1-5310:3" lang="html" class="code highlight js-syntax-highlight language-html" v-pre="true"><code><span id="LC1" class="line" lang="html"><span class="nt">&lt;blockquote&gt;</span></span>
+<span id="LC2" class="line" lang="html"><span class="nt">&lt;ul&gt;</span></span>
+<span id="LC3" class="line" lang="html"><span class="nt">&lt;li&gt;</span></span>
+<span id="LC4" class="line" lang="html"><span class="nt">&lt;p&gt;</span>one<span class="nt">&lt;/p&gt;</span></span>
+<span id="LC5" class="line" lang="html"><span class="nt">&lt;p&gt;</span>two<span class="nt">&lt;/p&gt;</span></span>
+<span id="LC6" class="line" lang="html"><span class="nt">&lt;/li&gt;</span></span>
+<span id="LC7" class="line" lang="html"><span class="nt">&lt;/ul&gt;</span></span>
+<span id="LC8" class="line" lang="html"><span class="nt">&lt;/blockquote&gt;</span></span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5312:1-5312:30" dir="auto">This is extremely unintuitive.</p>
+<p data-sourcepos="5314:1-5319:52" dir="auto">Rather than requiring a fixed indent from the margin, we could require
+a fixed indent (say, two spaces, or even one space) from the list marker (which
+may itself be indented). This proposal would remove the last anomaly
+discussed. Unlike the spec presented above, it would count the following
+as a list item with a subparagraph, even though the paragraph <code>bar</code>
+is not indented as far as the first paragraph <code>foo</code>:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5321:1-5325:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="p"> 10.</span> foo</span>
+<span id="LC2" class="line" lang="markdown"></span>
+<span id="LC3" class="line" lang="markdown"> bar </span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5327:1-5330:62" dir="auto">Arguably this text does read like a list item with <code>bar</code> as a subparagraph,
+which may count in favor of the proposal. However, on this proposal indented
+code would have to be indented six spaces after the list marker. And this
+would break a lot of existing Markdown, which has the pattern:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5332:1-5336:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="p">1.</span> foo</span>
+<span id="LC2" class="line" lang="markdown"></span>
+<span id="LC3" class="line" lang="markdown"><span class="sb"> indented code</span></span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5338:1-5340:28" dir="auto">where the code is indented eight spaces. The spec above, by contrast, will
+parse this text as expected, since the code block's indentation is measured
+from the beginning of <code>foo</code>.</p>
+<p data-sourcepos="5342:1-5348:62" dir="auto">The one case that needs special treatment is a list item that <em>starts</em>
+with indented code. How much indentation is required in that case, since
+we don't have a "first paragraph" to measure from? Rule #2 simply stipulates
+that in such cases, we require one space indentation from the list marker
+(and then the normal four spaces for the indented code). This will match the
+four-space rule in cases where the list marker plus its initial indentation
+takes four spaces (a common case), but diverge in other cases.</p>
+<div>
+<h2 data-sourcepos="5352:1-5352:30">
+<a id="user-content-task-list-items-extension" class="anchor" href="#task-list-items-extension" aria-hidden="true"></a>Task list items (extension)</h2>
+<p data-sourcepos="5354:1-5355:26">GFM enables the <code>tasklist</code> extension, where an additional processing step is
+performed on [list items].</p>
+<p data-sourcepos="5357:1-5359:46">A <a href="@">task list item</a> is a [list item][list items] where the first block in it
+is a paragraph which begins with a [task list item marker] and at least one
+whitespace character before any other content.</p>
+<p data-sourcepos="5361:1-5363:55">A <a href="@">task list item marker</a> consists of an optional number of spaces, a left
+bracket (<code>[</code>), either a whitespace character or the letter <code>x</code> in either
+lowercase or uppercase, and then a right bracket (<code>]</code>).</p>
+<p data-sourcepos="5365:1-5366:70">When rendered, the [task list item marker] is replaced with a semantic checkbox element;
+in an HTML output, this would be an <code>&lt;input type="checkbox"&gt;</code> element.</p>
+<p data-sourcepos="5368:1-5369:50">If the character between the brackets is a whitespace character, the checkbox
+is unchecked. Otherwise, the checkbox is checked.</p>
+<p data-sourcepos="5371:1-5374:28">This spec does not define how the checkbox elements are interacted with: in practice,
+implementors are free to render the checkboxes as disabled or inmutable elements,
+or they may dynamically handle dynamic interactions (i.e. checking, unchecking) in
+the final rendered document.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5376:1-5379:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [ ] foo</span>
+<span id="LC2" class="line" lang="plaintext">- [x] bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5381:1-5386:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; bar&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5388:1-5388:37">Task lists can be arbitrarily nested:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5390:1-5395:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [x] foo</span>
+<span id="LC2" class="line" lang="plaintext"> - [ ] bar</span>
+<span id="LC3" class="line" lang="plaintext"> - [x] baz</span>
+<span id="LC4" class="line" lang="plaintext">- [ ] bim</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5397:1-5407:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; foo</span>
+<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; bar&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;&lt;input checked="" disabled="" type="checkbox"&gt; baz&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;li&gt;&lt;input disabled="" type="checkbox"&gt; bim&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+</div>
+<h2 data-sourcepos="5411:1-5411:8" dir="auto">
+<a id="user-content-lists" class="anchor" href="#lists" aria-hidden="true"></a>Lists</h2>
+<p data-sourcepos="5413:1-5415:46" dir="auto">A <a href="@">list</a> is a sequence of one or more
+list items [of the same type]. The list items
+may be separated by any number of blank lines.</p>
+<p data-sourcepos="5417:1-5422:30" dir="auto">Two list items are <a href="@">of the same type</a>
+if they begin with a [list marker] of the same type.
+Two list markers are of the
+same type if (a) they are bullet list markers using the same character
+(<code>-</code>, <code>+</code>, or <code>*</code>) or (b) they are ordered list numbers with the same
+delimiter (either <code>.</code> or <code>)</code>).</p>
+<p data-sourcepos="5424:1-5428:39" dir="auto">A list is an <a href="@">ordered list</a>
+if its constituent list items begin with
+[ordered list markers], and a
+<a href="@">bullet list</a> if its constituent list
+items begin with [bullet list markers].</p>
+<p data-sourcepos="5430:1-5433:12" dir="auto">The <a href="@">start number</a>
+of an [ordered list] is determined by the list number of
+its initial list item. The numbers of subsequent list items are
+disregarded.</p>
+<p data-sourcepos="5435:1-5440:65" dir="auto">A list is <a href="@">loose</a> if any of its constituent
+list items are separated by blank lines, or if any of its constituent
+list items directly contain two block-level elements with a blank line
+between them. Otherwise a list is <a href="@">tight</a>.
+(The difference in HTML output is that paragraphs in a loose list are
+wrapped in <code>&lt;p&gt;</code> tags, while paragraphs in a tight list are not.)</p>
+<p data-sourcepos="5442:1-5442:64" dir="auto">Changing the bullet or ordered list delimiter starts a new list:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5444:1-5448:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext">- bar</span>
+<span id="LC3" class="line" lang="plaintext">+ baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5450:1-5458:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;li&gt;baz&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5461:1-5465:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. foo</span>
+<span id="LC2" class="line" lang="plaintext">2. bar</span>
+<span id="LC3" class="line" lang="plaintext">3) baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5467:1-5475:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/ol&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;ol start="3"&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;li&gt;baz&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5478:1-5480:5" dir="auto">In CommonMark, a list can interrupt a paragraph. That is,
+no blank line is needed to separate a paragraph from a following
+list:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5482:1-5486:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo</span>
+<span id="LC2" class="line" lang="plaintext">- bar</span>
+<span id="LC3" class="line" lang="plaintext">- baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5488:1-5494:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;baz&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5496:1-5497:37" dir="auto"><code>Markdown.pl</code> does not allow this, through fear of triggering a list
+via a numeral in a hard-wrapped line:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5499:1-5502:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown">The number of windows in my house is</span>
+<span id="LC2" class="line" lang="markdown"><span class="p">14.</span> The number of doors is 6.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5504:1-5506:6" dir="auto">Oddly, though, <code>Markdown.pl</code> <em>does</em> allow a blockquote to
+interrupt a paragraph, even though the same considerations might
+apply.</p>
+<p data-sourcepos="5508:1-5510:35" dir="auto">In CommonMark, we do allow lists to interrupt paragraphs, for
+two reasons. First, it is natural and not uncommon for people
+to start lists without blank lines:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5512:1-5517:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown">I need to buy</span>
+<span id="LC2" class="line" lang="markdown"><span class="p">-</span> new shoes</span>
+<span id="LC3" class="line" lang="markdown"><span class="p">-</span> a coat</span>
+<span id="LC4" class="line" lang="markdown"><span class="p">-</span> a plane ticket</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5519:1-5519:29" dir="auto">Second, we are attracted to a</p>
+<blockquote data-sourcepos="5521:1-5524:54" dir="auto">
+<p data-sourcepos="5521:3-5524:54"><a href="@">principle of uniformity</a>:
+if a chunk of text has a certain
+meaning, it will continue to have the same meaning when put into a
+container block (such as a list item or blockquote).</p>
+</blockquote>
+<p data-sourcepos="5526:1-5527:47" dir="auto">(Indeed, the spec for [list items] and [block quotes] presupposes
+this principle.) This principle implies that if</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5529:1-5534:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="p"> *</span> I need to buy</span>
+<span id="LC2" class="line" lang="markdown"><span class="p"> -</span> new shoes</span>
+<span id="LC3" class="line" lang="markdown"><span class="p"> -</span> a coat</span>
+<span id="LC4" class="line" lang="markdown"><span class="p"> -</span> a plane ticket</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5536:1-5539:4" dir="auto">is a list item containing a paragraph followed by a nested sublist,
+as all Markdown implementations agree it is (though the paragraph
+may be rendered without <code>&lt;p&gt;</code> tags, since the list is "tight"),
+then</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5541:1-5546:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown">I need to buy</span>
+<span id="LC2" class="line" lang="markdown"><span class="p">-</span> new shoes</span>
+<span id="LC3" class="line" lang="markdown"><span class="p">-</span> a coat</span>
+<span id="LC4" class="line" lang="markdown"><span class="p">-</span> a plane ticket</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5548:1-5548:61" dir="auto">by itself should be a paragraph followed by a nested sublist.</p>
+<p data-sourcepos="5550:1-5555:30" dir="auto">Since it is well established Markdown practice to allow lists to
+interrupt paragraphs inside list items, the [principle of
+uniformity] requires us to allow this outside list items as
+well. (<a href="http://docutils.sourceforge.net/rst.html" rel="nofollow noreferrer noopener" target="_blank">reStructuredText</a>
+takes a different approach, requiring blank lines before lists
+even inside other list items.)</p>
+<p data-sourcepos="5557:1-5559:28" dir="auto">In order to solve of unwanted lists in paragraphs with
+hard-wrapped numerals, we allow only lists starting with <code>1</code> to
+interrupt paragraphs. Thus,</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5561:1-5564:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">The number of windows in my house is</span>
+<span id="LC2" class="line" lang="plaintext">14. The number of doors is 6.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5566:1-5569:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;The number of windows in my house is</span>
+<span id="LC2" class="line" lang="plaintext">14. The number of doors is 6.&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5571:1-5571:51" dir="auto">We may still get an unintended result in cases like</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5573:1-5576:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">The number of windows in my house is</span>
+<span id="LC2" class="line" lang="plaintext">1. The number of doors is 6.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5578:1-5583:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;The number of windows in my house is&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;The number of doors is 6.&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5585:1-5585:57" dir="auto">but this rule should prevent most spurious list captures.</p>
+<p data-sourcepos="5587:1-5587:53" dir="auto">There can be any number of blank lines between items:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5589:1-5596:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">- bar</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext">- baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5598:1-5610:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5612:1-5619:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext"> - bar</span>
+<span id="LC3" class="line" lang="plaintext"> - baz</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext"> bim</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5621:1-5636:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo</span>
+<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;bar</span>
+<span id="LC5" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;p&gt;bim&lt;/p&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC12" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC13" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC14" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5639:1-5642:8" dir="auto">To separate consecutive lists of the same type, or to separate a
+list from an indented code block that would otherwise be parsed
+as a subparagraph of the final list item, you can insert a blank HTML
+comment:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5644:1-5652:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext">- bar</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">&lt;!-- --&gt;</span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext">- baz</span>
+<span id="LC7" class="line" lang="plaintext">- bim</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5654:1-5664:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;!-- --&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;li&gt;baz&lt;/li&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;li&gt;bim&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5667:1-5677:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> notcode</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">- foo</span>
+<span id="LC6" class="line" lang="plaintext"></span>
+<span id="LC7" class="line" lang="plaintext">&lt;!-- --&gt;</span>
+<span id="LC8" class="line" lang="plaintext"></span>
+<span id="LC9" class="line" lang="plaintext"> code</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5679:1-5692:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;notcode&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;!-- --&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;code</span>
+<span id="LC12" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5695:1-5698:5" dir="auto">List items need not be indented to the same level. The following
+list items will be treated as items at the same list level,
+since none is indented enough to belong to the previous list
+item:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5700:1-5708:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
+<span id="LC2" class="line" lang="plaintext"> - b</span>
+<span id="LC3" class="line" lang="plaintext"> - c</span>
+<span id="LC4" class="line" lang="plaintext"> - d</span>
+<span id="LC5" class="line" lang="plaintext"> - e</span>
+<span id="LC6" class="line" lang="plaintext"> - f</span>
+<span id="LC7" class="line" lang="plaintext">- g</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5710:1-5720:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;a&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;b&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;c&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;d&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;li&gt;e&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;li&gt;f&lt;/li&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;li&gt;g&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5723:1-5729:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. a</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> 2. b</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext"> 3. c</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5731:1-5743:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;a&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;p&gt;c&lt;/p&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5745:1-5747:52" dir="auto">Note, however, that list items may not be indented more than
+three spaces. Here <code>- e</code> is treated as a paragraph continuation
+line, because it is indented more than three spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5749:1-5755:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
+<span id="LC2" class="line" lang="plaintext"> - b</span>
+<span id="LC3" class="line" lang="plaintext"> - c</span>
+<span id="LC4" class="line" lang="plaintext"> - d</span>
+<span id="LC5" class="line" lang="plaintext"> - e</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5757:1-5765:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;a&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;b&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;c&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;d</span>
+<span id="LC6" class="line" lang="plaintext">- e&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5767:1-5769:11" dir="auto">And here, <code>3. c</code> is treated as in indented code block,
+because it is indented four spaces and preceded by a
+blank line.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5771:1-5777:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. a</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> 2. b</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext"> 3. c</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5779:1-5790:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;a&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/ol&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;3. c</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5793:1-5794:22" dir="auto">This is a loose list, because there is a blank line between
+two of the list items:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5796:1-5801:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
+<span id="LC2" class="line" lang="plaintext">- b</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">- c</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5803:1-5815:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;a&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;p&gt;c&lt;/p&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5818:1-5818:37" dir="auto">So is this, with a empty second item:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5820:1-5825:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">* a</span>
+<span id="LC2" class="line" lang="plaintext">*</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">* c</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5827:1-5837:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;a&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;p&gt;c&lt;/p&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5840:1-5842:31" dir="auto">These are loose lists, even though there is no space between the items,
+because one of the items directly contains two block-level elements
+with a blank line between them:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5844:1-5850:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
+<span id="LC2" class="line" lang="plaintext">- b</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> c</span>
+<span id="LC5" class="line" lang="plaintext">- d</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5852:1-5865:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;a&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;p&gt;c&lt;/p&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;p&gt;d&lt;/p&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC12" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5868:1-5874:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
+<span id="LC2" class="line" lang="plaintext">- b</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> [ref]: /url</span>
+<span id="LC5" class="line" lang="plaintext">- d</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5876:1-5888:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;a&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;p&gt;d&lt;/p&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5891:1-5891:66" dir="auto">This is a tight list, because the blank lines are in a code block:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5893:1-5901:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
+<span id="LC2" class="line" lang="plaintext">- ```</span>
+<span id="LC3" class="line" lang="plaintext"> b</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext"> ```</span>
+<span id="LC7" class="line" lang="plaintext">- c</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5903:1-5914:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;a&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;b</span>
+<span id="LC5" class="line" lang="plaintext"></span>
+<span id="LC6" class="line" lang="plaintext"></span>
+<span id="LC7" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;li&gt;c&lt;/li&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5917:1-5919:24" dir="auto">This is a tight list, because the blank line is between two
+paragraphs of a sublist. So the sublist is loose while
+the outer list is tight:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5921:1-5927:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
+<span id="LC2" class="line" lang="plaintext"> - b</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> c</span>
+<span id="LC5" class="line" lang="plaintext">- d</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5929:1-5941:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;a</span>
+<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;p&gt;c&lt;/p&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;li&gt;d&lt;/li&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5944:1-5945:12" dir="auto">This is a tight list, because the blank line is inside the
+block quote:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5947:1-5952:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">* a</span>
+<span id="LC2" class="line" lang="plaintext"> &gt; b</span>
+<span id="LC3" class="line" lang="plaintext"> &gt;</span>
+<span id="LC4" class="line" lang="plaintext">* c</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5954:1-5963:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;a</span>
+<span id="LC3" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;li&gt;c&lt;/li&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5966:1-5967:33" dir="auto">This list is tight, because the consecutive block elements
+are not separated by blank lines:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5969:1-5976:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
+<span id="LC2" class="line" lang="plaintext"> &gt; b</span>
+<span id="LC3" class="line" lang="plaintext"> ```</span>
+<span id="LC4" class="line" lang="plaintext"> c</span>
+<span id="LC5" class="line" lang="plaintext"> ```</span>
+<span id="LC6" class="line" lang="plaintext">- d</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5978:1-5989:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;a</span>
+<span id="LC3" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;b&lt;/p&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/blockquote&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;c</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;li&gt;d&lt;/li&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="5992:1-5992:33" dir="auto">A single-paragraph list is tight:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5994:1-5996:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="5998:1-6002:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;a&lt;/li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6005:1-6008:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
+<span id="LC2" class="line" lang="plaintext"> - b</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6010:1-6018:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;a</span>
+<span id="LC3" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;li&gt;b&lt;/li&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6021:1-6022:36" dir="auto">This list is loose, because of the blank line between the
+two block elements in the list item:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6024:1-6030:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">1. ```</span>
+<span id="LC2" class="line" lang="plaintext"> foo</span>
+<span id="LC3" class="line" lang="plaintext"> ```</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext"> bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6032:1-6040:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;foo</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;p&gt;bar&lt;/p&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ol&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6043:1-6043:51" dir="auto">Here the outer list is loose, the inner list tight:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6045:1-6050:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">* foo</span>
+<span id="LC2" class="line" lang="plaintext"> * bar</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext"> baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6052:1-6062:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;bar&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;p&gt;baz&lt;/p&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6065:1-6073:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- a</span>
+<span id="LC2" class="line" lang="plaintext"> - b</span>
+<span id="LC3" class="line" lang="plaintext"> - c</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">- d</span>
+<span id="LC6" class="line" lang="plaintext"> - e</span>
+<span id="LC7" class="line" lang="plaintext"> - f</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6075:1-6092:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;a&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;li&gt;b&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;li&gt;c&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;p&gt;d&lt;/p&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC12" class="line" lang="plaintext">&lt;li&gt;e&lt;/li&gt;</span>
+<span id="LC13" class="line" lang="plaintext">&lt;li&gt;f&lt;/li&gt;</span>
+<span id="LC14" class="line" lang="plaintext">&lt;/ul&gt;</span>
+<span id="LC15" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC16" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h1 data-sourcepos="6095:1-6095:9" dir="auto">
+<a id="user-content-inlines" class="anchor" href="#inlines" aria-hidden="true"></a>Inlines</h1>
+<p data-sourcepos="6097:1-6099:21" dir="auto">Inlines are parsed sequentially from the beginning of the character
+stream to the end (left to right, in left-to-right languages).
+Thus, for example, in</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6101:1-6103:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`hi`lo`</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6105:1-6107:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;hi&lt;/code&gt;lo`&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6109:1-6110:9" dir="auto"><code>hi</code> is parsed as code, leaving the backtick at the end as a literal
+backtick.</p>
+<h2 data-sourcepos="6113:1-6113:20" dir="auto">
+<a id="user-content-backslash-escapes" class="anchor" href="#backslash-escapes" aria-hidden="true"></a>Backslash escapes</h2>
+<p data-sourcepos="6115:1-6115:57" dir="auto">Any ASCII punctuation character may be backslash-escaped:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6117:1-6119:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\!\"\#\$\%\&amp;\'\(\)\*\+\,\-\.\/\:\;\&lt;\=\&gt;\?\@\[\\\]\^\_\`\{\|\}\~</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6121:1-6123:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;!&amp;quot;#$%&amp;amp;'()*+,-./:;&amp;lt;=&amp;gt;?@[\]^_`{|}~&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6126:1-6127:12" dir="auto">Backslashes before other characters are treated as literal
+backslashes:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6129:1-6131:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\→\A\a\ \3\φ\«</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6133:1-6135:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;\→\A\a\ \3\φ\«&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6138:1-6139:39" dir="auto">Escaped characters are treated as regular characters and do
+not have their usual Markdown meanings:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6141:1-6151:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\*not emphasized*</span>
+<span id="LC2" class="line" lang="plaintext">\&lt;br/&gt; not a tag</span>
+<span id="LC3" class="line" lang="plaintext">\[not a link](/foo)</span>
+<span id="LC4" class="line" lang="plaintext">\`not code`</span>
+<span id="LC5" class="line" lang="plaintext">1\. not a list</span>
+<span id="LC6" class="line" lang="plaintext">\* not a list</span>
+<span id="LC7" class="line" lang="plaintext">\# not a heading</span>
+<span id="LC8" class="line" lang="plaintext">\[foo]: /url "not a reference"</span>
+<span id="LC9" class="line" lang="plaintext">\&amp;ouml; not a character entity</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6153:1-6163:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;*not emphasized*</span>
+<span id="LC2" class="line" lang="plaintext">&amp;lt;br/&amp;gt; not a tag</span>
+<span id="LC3" class="line" lang="plaintext">[not a link](/foo)</span>
+<span id="LC4" class="line" lang="plaintext">`not code`</span>
+<span id="LC5" class="line" lang="plaintext">1. not a list</span>
+<span id="LC6" class="line" lang="plaintext">* not a list</span>
+<span id="LC7" class="line" lang="plaintext"># not a heading</span>
+<span id="LC8" class="line" lang="plaintext">[foo]: /url &amp;quot;not a reference&amp;quot;</span>
+<span id="LC9" class="line" lang="plaintext">&amp;amp;ouml; not a character entity&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6166:1-6166:65" dir="auto">If a backslash is itself escaped, the following character is not:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6168:1-6170:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\\*emphasis*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6172:1-6174:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;\&lt;em&gt;emphasis&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6177:1-6177:58" dir="auto">A backslash at the end of the line is a [hard line break]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6179:1-6182:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo\</span>
+<span id="LC2" class="line" lang="plaintext">bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6184:1-6187:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo&lt;br /&gt;</span>
+<span id="LC2" class="line" lang="plaintext">bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6190:1-6191:9" dir="auto">Backslash escapes do not work in code blocks, code spans, autolinks, or
+raw HTML:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6193:1-6195:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`` \[\` ``</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6197:1-6199:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;\[\`&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6202:1-6204:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> \[\]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6206:1-6209:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;\[\]</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6212:1-6216:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~~</span>
+<span id="LC2" class="line" lang="plaintext">\[\]</span>
+<span id="LC3" class="line" lang="plaintext">~~~</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6218:1-6221:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;\[\]</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6224:1-6226:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;http://example.com?find=\*&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6228:1-6230:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://example.com?find=%5C*"&gt;http://example.com?find=\*&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6233:1-6235:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="/bar\/)"&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6237:1-6239:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="/bar\/)"&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6242:1-6243:60" dir="auto">But they work in all other contexts, including URLs and link titles,
+link references, and [info strings] in [fenced code blocks]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6245:1-6247:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo](/bar\* "ti\*tle")</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6249:1-6251:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/bar*" title="ti*tle"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6254:1-6258:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /bar\* "ti\*tle"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6260:1-6262:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/bar*" title="ti*tle"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6265:1-6269:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``` foo\+bar</span>
+<span id="LC2" class="line" lang="plaintext">foo</span>
+<span id="LC3" class="line" lang="plaintext">```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6271:1-6274:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code class="language-foo+bar"&gt;foo</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="6278:1-6278:42" dir="auto">
+<a id="user-content-entity-and-numeric-character-references" class="anchor" href="#entity-and-numeric-character-references" aria-hidden="true"></a>Entity and numeric character references</h2>
+<p data-sourcepos="6280:1-6282:30" dir="auto">Valid HTML entity references and numeric character references
+can be used in place of the corresponding Unicode character,
+with the following exceptions:</p>
+<ul data-sourcepos="6284:1-6293:0" dir="auto">
+<li data-sourcepos="6284:1-6286:0">
+<p data-sourcepos="6284:3-6285:24">Entity and character references are not recognized in code
+blocks and code spans.</p>
+</li>
+<li data-sourcepos="6287:1-6293:0">
+<p data-sourcepos="6287:3-6292:9">Entity and character references cannot stand in place of
+special characters that define structural elements in
+CommonMark. For example, although <code>&amp;#42;</code> can be used
+in place of a literal <code>*</code> character, <code>&amp;#42;</code> cannot replace
+<code>*</code> in emphasis delimiters, bullet list markers, or thematic
+breaks.</p>
+</li>
+</ul>
+<p data-sourcepos="6294:1-6296:49" dir="auto">Conforming CommonMark parsers need not store information about
+whether a particular character was represented in the source
+using a Unicode character or an entity reference.</p>
+<p data-sourcepos="6298:1-6302:47" dir="auto"><a href="@">Entity references</a> consist of <code>&amp;</code> + any of the valid
+HTML5 entity names + <code>;</code>. The
+document <a href="https://html.spec.whatwg.org/multipage/entities.json" rel="nofollow noreferrer noopener" target="_blank">https://html.spec.whatwg.org/multipage/entities.json</a>
+is used as an authoritative source for the valid entity
+references and their corresponding code points.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6304:1-6308:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;nbsp; &amp;amp; &amp;copy; &amp;AElig; &amp;Dcaron;</span>
+<span id="LC2" class="line" lang="plaintext">&amp;frac34; &amp;HilbertSpace; &amp;DifferentialD;</span>
+<span id="LC3" class="line" lang="plaintext">&amp;ClockwiseContourIntegral; &amp;ngE;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6310:1-6314:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;  &amp;amp; © Æ Ď</span>
+<span id="LC2" class="line" lang="plaintext">¾ ℋ ⅆ</span>
+<span id="LC3" class="line" lang="plaintext">∲ ≧̸&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6317:1-6323:58" dir="auto"><a href="@">Decimal numeric character
+references</a>
+consist of <code>&amp;#</code> + a string of 1--7 arabic digits + <code>;</code>. A
+numeric character reference is parsed as the corresponding
+Unicode character. Invalid Unicode code points will be replaced by
+the REPLACEMENT CHARACTER (<code>U+FFFD</code>). For security reasons,
+the code point <code>U+0000</code> will also be replaced by <code>U+FFFD</code>.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6325:1-6327:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;#35; &amp;#1234; &amp;#992; &amp;#0;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6329:1-6331:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;# Ӓ Ϡ �&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6334:1-6338:62" dir="auto"><a href="@">Hexadecimal numeric character
+references</a> consist of <code>&amp;#</code> +
+either <code>X</code> or <code>x</code> + a string of 1-6 hexadecimal digits + <code>;</code>.
+They too are parsed as the corresponding Unicode character (this
+time specified with a hexadecimal numeral instead of decimal).</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6340:1-6342:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;#X22; &amp;#XD06; &amp;#xcab;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6344:1-6346:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;quot; ആ ಫ&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6349:1-6349:26" dir="auto">Here are some nonentities:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6351:1-6356:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;nbsp &amp;x; &amp;#; &amp;#x;</span>
+<span id="LC2" class="line" lang="plaintext">&amp;#987654321;</span>
+<span id="LC3" class="line" lang="plaintext">&amp;#abcdef0;</span>
+<span id="LC4" class="line" lang="plaintext">&amp;ThisIsNotDefined; &amp;hi?;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6358:1-6363:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;amp;nbsp &amp;amp;x; &amp;amp;#; &amp;amp;#x;</span>
+<span id="LC2" class="line" lang="plaintext">&amp;amp;#987654321;</span>
+<span id="LC3" class="line" lang="plaintext">&amp;amp;#abcdef0;</span>
+<span id="LC4" class="line" lang="plaintext">&amp;amp;ThisIsNotDefined; &amp;amp;hi?;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6366:1-6368:60" dir="auto">Although HTML5 does accept some entity references
+without a trailing semicolon (such as <code>&amp;copy</code>), these are not
+recognized here, because it makes the grammar too ambiguous:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6370:1-6372:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;copy</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6374:1-6376:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;amp;copy&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6379:1-6380:39" dir="auto">Strings that are not on the list of HTML5 named entities are not
+recognized as entity references either:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6382:1-6384:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;MadeUpEntity;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6386:1-6388:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;amp;MadeUpEntity;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6391:1-6393:62" dir="auto">Entity and numeric character references are recognized in any
+context besides code spans or code blocks, including
+URLs, [link titles], and [fenced code block][] [info strings]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6395:1-6397:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="&amp;ouml;&amp;ouml;.html"&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6399:1-6401:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="&amp;ouml;&amp;ouml;.html"&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6404:1-6406:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo](/f&amp;ouml;&amp;ouml; "f&amp;ouml;&amp;ouml;")</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6408:1-6410:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/f%C3%B6%C3%B6" title="föö"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6413:1-6417:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /f&amp;ouml;&amp;ouml; "f&amp;ouml;&amp;ouml;"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6419:1-6421:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/f%C3%B6%C3%B6" title="föö"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6424:1-6428:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``` f&amp;ouml;&amp;ouml;</span>
+<span id="LC2" class="line" lang="plaintext">foo</span>
+<span id="LC3" class="line" lang="plaintext">```</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6430:1-6433:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code class="language-föö"&gt;foo</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6436:1-6437:35" dir="auto">Entity and numeric character references are treated as literal
+text in code spans and code blocks:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6439:1-6441:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`f&amp;ouml;&amp;ouml;`</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6443:1-6445:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;f&amp;amp;ouml;&amp;amp;ouml;&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6448:1-6450:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> f&amp;ouml;f&amp;ouml;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6452:1-6455:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;&lt;code&gt;f&amp;amp;ouml;f&amp;amp;ouml;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;/code&gt;&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6458:1-6460:10" dir="auto">Entity and numeric character references cannot be used
+in place of symbols indicating structure in CommonMark
+documents.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6462:1-6465:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;#42;foo&amp;#42;</span>
+<span id="LC2" class="line" lang="plaintext">*foo*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6467:1-6470:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;*foo*</span>
+<span id="LC2" class="line" lang="plaintext">&lt;em&gt;foo&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6472:1-6476:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;#42; foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">* foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6478:1-6483:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;* foo&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;li&gt;foo&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6485:1-6487:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo&amp;#10;&amp;#10;bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6489:1-6493:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6495:1-6497:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&amp;#9;foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6499:1-6501:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;→foo&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6504:1-6506:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[a](url &amp;quot;tit&amp;quot;)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6508:1-6510:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[a](url &amp;quot;tit&amp;quot;)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="6513:1-6513:13" dir="auto">
+<a id="user-content-code-spans" class="anchor" href="#code-spans" aria-hidden="true"></a>Code spans</h2>
+<p data-sourcepos="6515:1-6517:36" dir="auto">A <a href="@">backtick string</a>
+is a string of one or more backtick characters (<code>`</code>) that is neither
+preceded nor followed by a backtick.</p>
+<p data-sourcepos="6519:1-6522:15" dir="auto">A <a href="@">code span</a> begins with a backtick string and ends with
+a backtick string of equal length. The contents of the code span are
+the characters between the two backtick strings, normalized in the
+following ways:</p>
+<ul data-sourcepos="6524:1-6531:0" dir="auto">
+<li data-sourcepos="6524:1-6524:50">First, [line endings] are converted to [spaces].</li>
+<li data-sourcepos="6525:1-6531:0">If the resulting string both begins <em>and</em> ends with a [space]
+character, but does not consist entirely of [space]
+characters, a single [space] character is removed from the
+front and back. This allows you to include code that begins
+or ends with backtick characters, which must be separated by
+whitespace from the opening or closing backtick strings.</li>
+</ul>
+<p data-sourcepos="6532:1-6532:27" dir="auto">This is a simple code span:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6534:1-6536:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`foo`</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6538:1-6540:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6543:1-6545:15" dir="auto">Here two backticks are used, because the code contains a backtick.
+This example also illustrates stripping of a single leading and
+trailing space:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6547:1-6549:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`` foo ` bar ``</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6551:1-6553:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo ` bar&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6556:1-6557:7" dir="auto">This example shows the motivation for stripping leading and trailing
+spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6559:1-6561:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">` `` `</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6563:1-6565:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;``&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6567:1-6567:39" dir="auto">Note that only <em>one</em> space is stripped:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6569:1-6571:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">` `` `</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6573:1-6575:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt; `` &lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6577:1-6578:20" dir="auto">The stripping only happens if the space is on both
+sides of the string:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6580:1-6582:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">` a`</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6584:1-6586:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt; a&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6588:1-6589:21" dir="auto">Only [spaces], and not [unicode whitespace] in general, are
+stripped in this way:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6591:1-6593:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">` b `</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6595:1-6597:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt; b &lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6599:1-6599:58" dir="auto">No stripping occurs if the code span contains only spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6601:1-6604:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">` `</span>
+<span id="LC2" class="line" lang="plaintext">` `</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6606:1-6609:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt; &lt;/code&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;code&gt; &lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6612:1-6612:39" dir="auto">[Line endings] are treated like spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6614:1-6620:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``</span>
+<span id="LC2" class="line" lang="plaintext">foo</span>
+<span id="LC3" class="line" lang="plaintext">bar </span>
+<span id="LC4" class="line" lang="plaintext">baz</span>
+<span id="LC5" class="line" lang="plaintext">``</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6622:1-6624:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo bar baz&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6626:1-6630:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``</span>
+<span id="LC2" class="line" lang="plaintext">foo </span>
+<span id="LC3" class="line" lang="plaintext">``</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6632:1-6634:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo &lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6637:1-6637:34" dir="auto">Interior spaces are not collapsed:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6639:1-6642:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`foo bar </span>
+<span id="LC2" class="line" lang="plaintext">baz`</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6644:1-6646:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo bar baz&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6648:1-6650:26" dir="auto">Note that browsers will typically collapse consecutive spaces
+when rendering <code>&lt;code&gt;</code> elements, so it is recommended that
+the following CSS be used:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6652:5-6654:0" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">code{white-space: pre-wrap;}</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6655:1-6656:22" dir="auto">Note that backslash escapes do not work in code spans. All backslashes
+are treated literally:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6658:1-6660:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`foo\`bar`</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6662:1-6664:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo\&lt;/code&gt;bar`&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6667:1-6669:59" dir="auto">Backslash escapes are never needed, because one can always choose a
+string of <em>n</em> backtick characters as delimiters, where the code does
+not contain any strings of exactly <em>n</em> backtick characters.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6671:1-6673:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">``foo`bar``</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6675:1-6677:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo`bar&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6679:1-6681:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">` foo `` bar `</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6683:1-6685:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;foo `` bar&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6688:1-6691:5" dir="auto">Code span backticks have higher precedence than any other inline
+constructs except HTML tags and autolinks. Thus, for example, this is
+not parsed as emphasized text, since the second <code>*</code> is part of a code
+span:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6693:1-6695:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo`*`</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6697:1-6699:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;*foo&lt;code&gt;*&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6702:1-6702:33" dir="auto">And this is not parsed as a link:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6704:1-6706:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[not a `link](/foo`)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6708:1-6710:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[not a &lt;code&gt;link](/foo&lt;/code&gt;)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6713:1-6714:19" dir="auto">Code spans, HTML tags, and autolinks have the same precedence.
+Thus, this is code:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6716:1-6718:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`&lt;a href="`"&gt;`</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6720:1-6722:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;&amp;lt;a href=&amp;quot;&lt;/code&gt;&amp;quot;&amp;gt;`&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6725:1-6725:24" dir="auto">But this is an HTML tag:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6727:1-6729:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="`"&gt;`</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6731:1-6733:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="`"&gt;`&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6736:1-6736:17" dir="auto">And this is code:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6738:1-6740:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`&lt;http://foo.bar.`baz&gt;`</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6742:1-6744:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;&amp;lt;http://foo.bar.&lt;/code&gt;baz&amp;gt;`&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6747:1-6747:24" dir="auto">But this is an autolink:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6749:1-6751:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;http://foo.bar.`baz&gt;`</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6753:1-6755:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://foo.bar.%60baz"&gt;http://foo.bar.`baz&lt;/a&gt;`&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6758:1-6759:31" dir="auto">When a backtick string is not closed by a matching backtick string,
+we just have literal backticks:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6761:1-6763:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">```foo``</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6765:1-6767:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;```foo``&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6770:1-6772:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`foo</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6774:1-6776:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;`foo&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6778:1-6779:47" dir="auto">The following case also illustrates the need for opening and
+closing backtick strings to be equal in length:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6781:1-6783:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`foo``bar``</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6785:1-6787:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;`foo&lt;code&gt;bar&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="6790:1-6790:31" dir="auto">
+<a id="user-content-emphasis-and-strong-emphasis" class="anchor" href="#emphasis-and-strong-emphasis" aria-hidden="true"></a>Emphasis and strong emphasis</h2>
+<p data-sourcepos="6792:1-6793:73" dir="auto">John Gruber's original <a href="http://daringfireball.net/projects/markdown/syntax#em" rel="nofollow noreferrer noopener" target="_blank">Markdown syntax
+description</a> says:</p>
+<blockquote data-sourcepos="6795:1-6798:6" dir="auto">
+<p data-sourcepos="6795:3-6798:6">Markdown treats asterisks (<code>*</code>) and underscores (<code>_</code>) as indicators of
+emphasis. Text wrapped with one <code>*</code> or <code>_</code> will be wrapped with an HTML
+<code>&lt;em&gt;</code> tag; double <code>*</code>'s or <code>_</code>'s will be wrapped with an HTML <code>&lt;strong&gt;</code>
+tag.</p>
+</blockquote>
+<p data-sourcepos="6800:1-6804:57" dir="auto">This is enough for most users, but these rules leave much undecided,
+especially when it comes to nested emphasis. The original
+<code>Markdown.pl</code> test suite makes it clear that triple <code>***</code> and
+<code>___</code> delimiters can be used for strong emphasis, and most
+implementations have also allowed the following patterns:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6806:1-6812:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="gs">***strong emph**</span><span class="err">*</span></span>
+<span id="LC2" class="line" lang="markdown"><span class="gs">***strong**</span> in emph<span class="err">*</span></span>
+<span id="LC3" class="line" lang="markdown"><span class="gs">***emph* in strong**</span></span>
+<span id="LC4" class="line" lang="markdown"><span class="gs">**in strong *emph**</span><span class="err">*</span></span>
+<span id="LC5" class="line" lang="markdown"><span class="ge">*in emph **strong***</span></span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6814:1-6816:9" dir="auto">The following patterns are less widely supported, but the intent
+is clear and they are useful (especially in contexts like bibliography
+entries):</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6818:1-6821:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="ge">*emph *</span>with emph<span class="ge">* in it*</span></span>
+<span id="LC2" class="line" lang="markdown"><span class="gs">**strong **</span>with strong<span class="gs">** in it**</span></span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6823:1-6826:31" dir="auto">Many implementations have also restricted intraword emphasis to
+the <code>*</code> forms, to avoid unwanted emphasis in words containing
+internal underscores. (It is best practice to put these in code
+spans, but users often do not.)</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6828:1-6831:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown">internal emphasis: foo<span class="ge">*bar*</span>baz</span>
+<span id="LC2" class="line" lang="markdown">no emphasis: foo_bar_baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="6833:1-6834:55" dir="auto">The rules given below capture all of these patterns, while allowing
+for efficient parsing strategies that do not backtrack.</p>
+<p data-sourcepos="6836:1-6840:38" dir="auto">First, some definitions. A <a href="@">delimiter run</a> is either
+a sequence of one or more <code>*</code> characters that is not preceded or
+followed by a non-backslash-escaped <code>*</code> character, or a sequence
+of one or more <code>_</code> characters that is not preceded or followed by
+a non-backslash-escaped <code>_</code> character.</p>
+<p data-sourcepos="6842:1-6848:37" dir="auto">A <a href="@">left-flanking delimiter run</a> is
+a [delimiter run] that is (1) not followed by [Unicode whitespace],
+and either (2a) not followed by a [punctuation character], or
+(2b) followed by a [punctuation character] and
+preceded by [Unicode whitespace] or a [punctuation character].
+For purposes of this definition, the beginning and the end of
+the line count as Unicode whitespace.</p>
+<p data-sourcepos="6850:1-6856:37" dir="auto">A <a href="@">right-flanking delimiter run</a> is
+a [delimiter run] that is (1) not preceded by [Unicode whitespace],
+and either (2a) not preceded by a [punctuation character], or
+(2b) preceded by a [punctuation character] and
+followed by [Unicode whitespace] or a [punctuation character].
+For purposes of this definition, the beginning and the end of
+the line count as Unicode whitespace.</p>
+<p data-sourcepos="6858:1-6858:41" dir="auto">Here are some examples of delimiter runs.</p>
+<ul data-sourcepos="6860:3-6891:0" dir="auto">
+<li data-sourcepos="6860:3-6868:0">
+<p data-sourcepos="6860:5-6860:41">left-flanking but not right-flanking:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6862:5-6867:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">***abc</span>
+<span id="LC2" class="line" lang="plaintext"> _abc</span>
+<span id="LC3" class="line" lang="plaintext">**"abc"</span>
+<span id="LC4" class="line" lang="plaintext"> _"abc"</span></code></pre>
+<copy-code></copy-code>
+</div>
+</li>
+<li data-sourcepos="6869:3-6877:0">
+<p data-sourcepos="6869:5-6869:41">right-flanking but not left-flanking:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6871:5-6876:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> abc***</span>
+<span id="LC2" class="line" lang="plaintext"> abc_</span>
+<span id="LC3" class="line" lang="plaintext">"abc"**</span>
+<span id="LC4" class="line" lang="plaintext">"abc"_</span></code></pre>
+<copy-code></copy-code>
+</div>
+</li>
+<li data-sourcepos="6878:3-6884:0">
+<p data-sourcepos="6878:5-6878:33">Both left and right-flanking:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6880:5-6883:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> abc***def</span>
+<span id="LC2" class="line" lang="plaintext">"abc"_"def"</span></code></pre>
+<copy-code></copy-code>
+</div>
+</li>
+<li data-sourcepos="6885:3-6891:0">
+<p data-sourcepos="6885:5-6885:36">Neither left nor right-flanking:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="6887:5-6890:7" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">abc *** def</span>
+<span id="LC2" class="line" lang="plaintext">a _ b</span></code></pre>
+<copy-code></copy-code>
+</div>
+</li>
+</ul>
+<p data-sourcepos="6892:1-6898:49" dir="auto">(The idea of distinguishing left-flanking and right-flanking
+delimiter runs based on the character before and the character
+after comes from Roopesh Chander's
+<a href="http://www.vfmd.org/vfmd-spec/specification/#procedure-for-identifying-emphasis-tags" rel="nofollow noreferrer noopener" target="_blank">vfmd</a>.
+vfmd uses the terminology "emphasis indicator string" instead of "delimiter
+run," and its rules for distinguishing left- and right-flanking runs
+are a bit more complex than the ones given here.)</p>
+<p data-sourcepos="6900:1-6900:56" dir="auto">The following rules define emphasis and strong emphasis:</p>
+<ol data-sourcepos="6902:1-6966:0" dir="auto">
+<li data-sourcepos="6902:1-6904:0">
+<p data-sourcepos="6902:5-6903:71">A single <code>*</code> character <a href="@">can open emphasis</a>
+iff (if and only if) it is part of a [left-flanking delimiter run].</p>
+</li>
+<li data-sourcepos="6905:1-6910:0">
+<p data-sourcepos="6905:5-6909:28">A single <code>_</code> character [can open emphasis] iff
+it is part of a [left-flanking delimiter run]
+and either (a) not part of a [right-flanking delimiter run]
+or (b) part of a [right-flanking delimiter run]
+preceded by punctuation.</p>
+</li>
+<li data-sourcepos="6911:1-6913:0">
+<p data-sourcepos="6911:5-6912:55">A single <code>*</code> character <a href="@">can close emphasis</a>
+iff it is part of a [right-flanking delimiter run].</p>
+</li>
+<li data-sourcepos="6914:1-6919:0">
+<p data-sourcepos="6914:5-6918:28">A single <code>_</code> character [can close emphasis] iff
+it is part of a [right-flanking delimiter run]
+and either (a) not part of a [left-flanking delimiter run]
+or (b) part of a [left-flanking delimiter run]
+followed by punctuation.</p>
+</li>
+<li data-sourcepos="6920:1-6922:0">
+<p data-sourcepos="6920:5-6921:54">A double <code>**</code> <a href="@">can open strong emphasis</a>
+iff it is part of a [left-flanking delimiter run].</p>
+</li>
+<li data-sourcepos="6923:1-6928:0">
+<p data-sourcepos="6923:5-6927:28">A double <code>__</code> [can open strong emphasis] iff
+it is part of a [left-flanking delimiter run]
+and either (a) not part of a [right-flanking delimiter run]
+or (b) part of a [right-flanking delimiter run]
+preceded by punctuation.</p>
+</li>
+<li data-sourcepos="6929:1-6931:0">
+<p data-sourcepos="6929:5-6930:55">A double <code>**</code> <a href="@">can close strong emphasis</a>
+iff it is part of a [right-flanking delimiter run].</p>
+</li>
+<li data-sourcepos="6932:1-6937:0">
+<p data-sourcepos="6932:5-6936:28">A double <code>__</code> [can close strong emphasis] iff
+it is part of a [right-flanking delimiter run]
+and either (a) not part of a [left-flanking delimiter run]
+or (b) part of a [left-flanking delimiter run]
+followed by punctuation.</p>
+</li>
+<li data-sourcepos="6938:1-6947:0">
+<p data-sourcepos="6938:5-6946:19">Emphasis begins with a delimiter that [can open emphasis] and ends
+with a delimiter that [can close emphasis], and that uses the same
+character (<code>_</code> or <code>*</code>) as the opening delimiter. The
+opening and closing delimiters must belong to separate
+[delimiter runs]. If one of the delimiters can both
+open and close emphasis, then the sum of the lengths of the
+delimiter runs containing the opening and closing delimiters
+must not be a multiple of 3 unless both lengths are
+multiples of 3.</p>
+</li>
+<li data-sourcepos="6948:1-6958:0">
+<p data-sourcepos="6948:5-6957:23">Strong emphasis begins with a delimiter that
+[can open strong emphasis] and ends with a delimiter that
+[can close strong emphasis], and that uses the same character
+(<code>_</code> or <code>*</code>) as the opening delimiter. The
+opening and closing delimiters must belong to separate
+[delimiter runs]. If one of the delimiters can both open
+and close strong emphasis, then the sum of the lengths of
+the delimiter runs containing the opening and closing
+delimiters must not be a multiple of 3 unless both lengths
+are multiples of 3.</p>
+</li>
+<li data-sourcepos="6959:1-6962:0">
+<p data-sourcepos="6959:5-6961:25">A literal <code>*</code> character cannot occur at the beginning or end of
+<code>*</code>-delimited emphasis or <code>**</code>-delimited strong emphasis, unless it
+is backslash-escaped.</p>
+</li>
+<li data-sourcepos="6963:1-6966:0">
+<p data-sourcepos="6963:5-6965:25">A literal <code>_</code> character cannot occur at the beginning or end of
+<code>_</code>-delimited emphasis or <code>__</code>-delimited strong emphasis, unless it
+is backslash-escaped.</p>
+</li>
+</ol>
+<p data-sourcepos="6967:1-6968:43" dir="auto">Where rules 1--12 above are compatible with multiple parsings,
+the following principles resolve ambiguity:</p>
+<ol start="13" data-sourcepos="6970:1-6995:0" dir="auto">
+<li data-sourcepos="6970:1-6973:0">
+<p data-sourcepos="6970:5-6972:28">The number of nestings should be minimized. Thus, for example,
+an interpretation <code>&lt;strong&gt;...&lt;/strong&gt;</code> is always preferred to
+<code>&lt;em&gt;&lt;em&gt;...&lt;/em&gt;&lt;/em&gt;</code>.</p>
+</li>
+<li data-sourcepos="6974:1-6976:0">
+<p data-sourcepos="6974:5-6975:49">An interpretation <code>&lt;em&gt;&lt;strong&gt;...&lt;/strong&gt;&lt;/em&gt;</code> is always
+preferred to <code>&lt;strong&gt;&lt;em&gt;...&lt;/em&gt;&lt;/strong&gt;</code>.</p>
+</li>
+<li data-sourcepos="6977:1-6982:0">
+<p data-sourcepos="6977:5-6981:34">When two potential emphasis or strong emphasis spans overlap,
+so that the second begins before the first ends and ends after
+the first ends, the first takes precedence. Thus, for example,
+<code>*foo _bar* baz_</code> is parsed as <code>&lt;em&gt;foo _bar&lt;/em&gt; baz_</code> rather
+than <code>*foo &lt;em&gt;bar* baz&lt;/em&gt;</code>.</p>
+</li>
+<li data-sourcepos="6983:1-6988:0">
+<p data-sourcepos="6983:5-6987:49">When there are two potential emphasis or strong emphasis spans
+with the same closing delimiter, the shorter one (the one that
+opens later) takes precedence. Thus, for example,
+<code>**foo **bar baz**</code> is parsed as <code>**foo &lt;strong&gt;bar baz&lt;/strong&gt;</code>
+rather than <code>&lt;strong&gt;foo **bar baz&lt;/strong&gt;</code>.</p>
+</li>
+<li data-sourcepos="6989:1-6995:0">
+<p data-sourcepos="6989:5-6994:26">Inline code spans, links, images, and HTML tags group more tightly
+than emphasis. So, when there is a choice between an interpretation
+that contains one of these elements and one that does not, the
+former always wins. Thus, for example, <code>*[foo*](bar)</code> is
+parsed as <code>*&lt;a href="bar"&gt;foo*&lt;/a&gt;</code> rather than as
+<code>&lt;em&gt;[foo&lt;/em&gt;](bar)</code>.</p>
+</li>
+</ol>
+<p data-sourcepos="6996:1-6996:60" dir="auto">These rules can be illustrated through a series of examples.</p>
+<p data-sourcepos="6998:1-6998:7" dir="auto">Rule 1:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7000:1-7002:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo bar*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7004:1-7006:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7009:1-7010:66" dir="auto">This is not emphasis, because the opening <code>*</code> is followed by
+whitespace, and hence not part of a [left-flanking delimiter run]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7012:1-7014:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">a * foo bar*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7016:1-7018:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;a * foo bar*&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7021:1-7023:44" dir="auto">This is not emphasis, because the opening <code>*</code> is preceded
+by an alphanumeric and followed by punctuation, and hence
+not part of a [left-flanking delimiter run]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7025:1-7027:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">a*"foo"*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7029:1-7031:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;a*&amp;quot;foo&amp;quot;*&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7034:1-7034:52" dir="auto">Unicode nonbreaking spaces count as whitespace, too:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7036:1-7038:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">* a *</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7040:1-7042:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;* a *&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7045:1-7045:41" dir="auto">Intraword emphasis with <code>*</code> is permitted:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7047:1-7049:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo*bar*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7051:1-7053:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo&lt;em&gt;bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7056:1-7058:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">5*6*78</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7060:1-7062:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;5&lt;em&gt;6&lt;/em&gt;78&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7065:1-7065:7" dir="auto">Rule 2:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7067:1-7069:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo bar_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7071:1-7073:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7076:1-7077:11" dir="auto">This is not emphasis, because the opening <code>_</code> is followed by
+whitespace:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7079:1-7081:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_ foo bar_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7083:1-7085:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;_ foo bar_&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7088:1-7089:47" dir="auto">This is not emphasis, because the opening <code>_</code> is preceded
+by an alphanumeric and followed by punctuation:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7091:1-7093:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">a_"foo"_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7095:1-7097:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;a_&amp;quot;foo&amp;quot;_&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7100:1-7100:46" dir="auto">Emphasis with <code>_</code> is not allowed inside words:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7102:1-7104:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo_bar_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7106:1-7108:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo_bar_&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7111:1-7113:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">5_6_78</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7115:1-7117:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;5_6_78&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7120:1-7122:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">приÑтанÑм_ÑтремÑÑ‚ÑÑ_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7124:1-7126:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;приÑтанÑм_ÑтремÑÑ‚ÑÑ_&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7129:1-7130:47" dir="auto">Here <code>_</code> does not generate emphasis, because the first delimiter run
+is right-flanking and the second left-flanking:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7132:1-7134:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">aa_"bb"_cc</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7136:1-7138:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;aa_&amp;quot;bb&amp;quot;_cc&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7141:1-7143:12" dir="auto">This is emphasis, even though the opening delimiter is
+both left- and right-flanking, because it is preceded by
+punctuation:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7145:1-7147:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo-_(bar)_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7149:1-7151:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo-&lt;em&gt;(bar)&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7154:1-7154:7" dir="auto">Rule 3:</p>
+<p data-sourcepos="7156:1-7157:32" dir="auto">This is not emphasis, because the closing delimiter does
+not match the opening delimiter:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7159:1-7161:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7163:1-7165:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;_foo*&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7168:1-7169:11" dir="auto">This is not emphasis, because the closing <code>*</code> is preceded by
+whitespace:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7171:1-7173:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo bar *</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7175:1-7177:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;*foo bar *&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7180:1-7180:36" dir="auto">A newline also counts as whitespace:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7182:1-7185:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo bar</span>
+<span id="LC2" class="line" lang="plaintext">*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7187:1-7190:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;*foo bar</span>
+<span id="LC2" class="line" lang="plaintext">*&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7193:1-7195:58" dir="auto">This is not emphasis, because the second <code>*</code> is
+preceded by punctuation and followed by an alphanumeric
+(hence it is not part of a [right-flanking delimiter run]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7197:1-7199:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*(*foo)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7201:1-7203:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;*(*foo)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7206:1-7207:18" dir="auto">The point of this restriction is more easily appreciated
+with this example:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7209:1-7211:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*(*foo*)*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7213:1-7215:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;(&lt;em&gt;foo&lt;/em&gt;)&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7218:1-7218:39" dir="auto">Intraword emphasis with <code>*</code> is allowed:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7220:1-7222:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo*bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7224:1-7226:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;/em&gt;bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7230:1-7230:7" dir="auto">Rule 4:</p>
+<p data-sourcepos="7232:1-7233:11" dir="auto">This is not emphasis, because the closing <code>_</code> is preceded by
+whitespace:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7235:1-7237:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo bar _</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7239:1-7241:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;_foo bar _&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7244:1-7245:56" dir="auto">This is not emphasis, because the second <code>_</code> is
+preceded by punctuation and followed by an alphanumeric:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7247:1-7249:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_(_foo)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7251:1-7253:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;_(_foo)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7256:1-7256:33" dir="auto">This is emphasis within emphasis:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7258:1-7260:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_(_foo_)_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7262:1-7264:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;(&lt;em&gt;foo&lt;/em&gt;)&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7267:1-7267:41" dir="auto">Intraword emphasis is disallowed for <code>_</code>:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7269:1-7271:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo_bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7273:1-7275:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;_foo_bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7278:1-7280:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_приÑтанÑм_ÑтремÑÑ‚ÑÑ</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7282:1-7284:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;_приÑтанÑм_ÑтремÑÑ‚ÑÑ&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7287:1-7289:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo_bar_baz_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7291:1-7293:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo_bar_baz&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7296:1-7298:12" dir="auto">This is emphasis, even though the closing delimiter is
+both left- and right-flanking, because it is followed by
+punctuation:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7300:1-7302:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_(bar)_.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7304:1-7306:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;(bar)&lt;/em&gt;.&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7309:1-7309:7" dir="auto">Rule 5:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7311:1-7313:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo bar**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7315:1-7317:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo bar&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7320:1-7321:23" dir="auto">This is not strong emphasis, because the opening delimiter is
+followed by whitespace:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7323:1-7325:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">** foo bar**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7327:1-7329:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;** foo bar**&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7332:1-7334:44" dir="auto">This is not strong emphasis, because the opening <code>**</code> is preceded
+by an alphanumeric and followed by punctuation, and hence
+not part of a [left-flanking delimiter run]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7336:1-7338:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">a**"foo"**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7340:1-7342:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;a**&amp;quot;foo&amp;quot;**&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7345:1-7345:49" dir="auto">Intraword strong emphasis with <code>**</code> is permitted:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7347:1-7349:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo**bar**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7351:1-7353:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo&lt;strong&gt;bar&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7356:1-7356:7" dir="auto">Rule 6:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7358:1-7360:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo bar__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7362:1-7364:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo bar&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7367:1-7368:23" dir="auto">This is not strong emphasis, because the opening delimiter is
+followed by whitespace:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7370:1-7372:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__ foo bar__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7374:1-7376:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;__ foo bar__&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7379:1-7379:31" dir="auto">A newline counts as whitespace:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7380:1-7383:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__</span>
+<span id="LC2" class="line" lang="plaintext">foo bar__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7385:1-7388:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;__</span>
+<span id="LC2" class="line" lang="plaintext">foo bar__&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7391:1-7392:47" dir="auto">This is not strong emphasis, because the opening <code>__</code> is preceded
+by an alphanumeric and followed by punctuation:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7394:1-7396:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">a__"foo"__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7398:1-7400:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;a__&amp;quot;foo&amp;quot;__&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7403:1-7403:49" dir="auto">Intraword strong emphasis is forbidden with <code>__</code>:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7405:1-7407:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo__bar__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7409:1-7411:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo__bar__&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7414:1-7416:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">5__6__78</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7418:1-7420:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;5__6__78&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7423:1-7425:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">приÑтанÑм__ÑтремÑÑ‚ÑÑ__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7427:1-7429:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;приÑтанÑм__ÑтремÑÑ‚ÑÑ__&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7432:1-7434:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo, __bar__, baz__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7436:1-7438:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo, &lt;strong&gt;bar&lt;/strong&gt;, baz&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7441:1-7443:12" dir="auto">This is strong emphasis, even though the opening delimiter is
+both left- and right-flanking, because it is preceded by
+punctuation:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7445:1-7447:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo-__(bar)__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7449:1-7451:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo-&lt;strong&gt;(bar)&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7455:1-7455:7" dir="auto">Rule 7:</p>
+<p data-sourcepos="7457:1-7458:14" dir="auto">This is not strong emphasis, because the closing delimiter is preceded
+by whitespace:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7460:1-7462:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo bar **</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7464:1-7466:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;**foo bar **&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7469:1-7470:9" dir="auto">(Nor can it be interpreted as an emphasized <code>*foo bar *</code>, because of
+Rule 11.)</p>
+<p data-sourcepos="7472:1-7473:56" dir="auto">This is not strong emphasis, because the second <code>**</code> is
+preceded by punctuation and followed by an alphanumeric:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7475:1-7477:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**(**foo)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7479:1-7481:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;**(**foo)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7484:1-7485:20" dir="auto">The point of this restriction is more easily appreciated
+with these examples:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7487:1-7489:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*(**foo**)*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7491:1-7493:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;(&lt;strong&gt;foo&lt;/strong&gt;)&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7496:1-7499:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**Gomphocarpus (*Gomphocarpus physocarpus*, syn.</span>
+<span id="LC2" class="line" lang="plaintext">*Asclepias physocarpa*)**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7501:1-7504:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;Gomphocarpus (&lt;em&gt;Gomphocarpus physocarpus&lt;/em&gt;, syn.</span>
+<span id="LC2" class="line" lang="plaintext">&lt;em&gt;Asclepias physocarpa&lt;/em&gt;)&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7507:1-7509:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo "*bar*" foo**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7511:1-7513:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &amp;quot;&lt;em&gt;bar&lt;/em&gt;&amp;quot; foo&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7516:1-7516:19" dir="auto">Intraword emphasis:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7518:1-7520:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo**bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7522:1-7524:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo&lt;/strong&gt;bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7527:1-7527:7" dir="auto">Rule 8:</p>
+<p data-sourcepos="7529:1-7530:23" dir="auto">This is not strong emphasis, because the closing delimiter is
+preceded by whitespace:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7532:1-7534:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo bar __</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7536:1-7538:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;__foo bar __&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7541:1-7542:56" dir="auto">This is not strong emphasis, because the second <code>__</code> is
+preceded by punctuation and followed by an alphanumeric:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7544:1-7546:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__(__foo)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7548:1-7550:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;__(__foo)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7553:1-7554:18" dir="auto">The point of this restriction is more easily appreciated
+with this example:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7556:1-7558:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_(__foo__)_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7560:1-7562:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;(&lt;strong&gt;foo&lt;/strong&gt;)&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7565:1-7565:49" dir="auto">Intraword strong emphasis is forbidden with <code>__</code>:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7567:1-7569:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo__bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7571:1-7573:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;__foo__bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7576:1-7578:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__приÑтанÑм__ÑтремÑÑ‚ÑÑ</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7580:1-7582:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;__приÑтанÑм__ÑтремÑÑ‚ÑÑ&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7585:1-7587:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo__bar__baz__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7589:1-7591:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo__bar__baz&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7594:1-7596:12" dir="auto">This is strong emphasis, even though the closing delimiter is
+both left- and right-flanking, because it is followed by
+punctuation:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7598:1-7600:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__(bar)__.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7602:1-7604:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;(bar)&lt;/strong&gt;.&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7607:1-7607:7" dir="auto">Rule 9:</p>
+<p data-sourcepos="7609:1-7610:16" dir="auto">Any nonempty sequence of inline elements can be the contents of an
+emphasized span.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7612:1-7614:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo [bar](/url)*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7616:1-7618:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;a href="/url"&gt;bar&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7621:1-7624:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo</span>
+<span id="LC2" class="line" lang="plaintext">bar*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7626:1-7629:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo</span>
+<span id="LC2" class="line" lang="plaintext">bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7632:1-7633:16" dir="auto">In particular, emphasis and strong emphasis can be nested
+inside emphasis:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7635:1-7637:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo __bar__ baz_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7639:1-7641:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;strong&gt;bar&lt;/strong&gt; baz&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7644:1-7646:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo _bar_ baz_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7648:1-7650:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;em&gt;bar&lt;/em&gt; baz&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7653:1-7655:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo_ bar_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7657:1-7659:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;&lt;em&gt;foo&lt;/em&gt; bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7662:1-7664:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo *bar**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7666:1-7668:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;em&gt;bar&lt;/em&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7671:1-7673:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo **bar** baz*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7675:1-7677:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;strong&gt;bar&lt;/strong&gt; baz&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7679:1-7681:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo**bar**baz*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7683:1-7685:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;strong&gt;bar&lt;/strong&gt;baz&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7687:1-7687:51" dir="auto">Note that in the preceding case, the interpretation</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7689:1-7691:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown"><span class="nt">&lt;p&gt;&lt;em&gt;</span>foo<span class="nt">&lt;/em&gt;&lt;em&gt;</span>bar<span class="nt">&lt;em&gt;&lt;/em&gt;</span>baz<span class="nt">&lt;/em&gt;&lt;/p&gt;</span></span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7694:1-7699:32" dir="auto">is precluded by the condition that a delimiter that
+can both open and close (like the <code>*</code> after <code>foo</code>)
+cannot form emphasis if the sum of the lengths of
+the delimiter runs containing the opening and
+closing delimiters is a multiple of 3 unless
+both lengths are multiples of 3.</p>
+<p data-sourcepos="7702:1-7703:34" dir="auto">For the same reason, we don't get two consecutive
+emphasis sections in this example:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7705:1-7707:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo**bar*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7709:1-7711:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo**bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7714:1-7717:8" dir="auto">The same condition ensures that the following
+cases are all strong emphasis nested inside
+emphasis, even when the interior spaces are
+omitted:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7720:1-7722:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">***foo** bar*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7724:1-7726:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;&lt;strong&gt;foo&lt;/strong&gt; bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7729:1-7731:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo **bar***</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7733:1-7735:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;strong&gt;bar&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7738:1-7740:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo**bar***</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7742:1-7744:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;strong&gt;bar&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7747:1-7749:34" dir="auto">When the lengths of the interior closing and opening
+delimiter runs are <em>both</em> multiples of 3, though,
+they can match to create emphasis:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7751:1-7753:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo***bar***baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7755:1-7757:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo&lt;em&gt;&lt;strong&gt;bar&lt;/strong&gt;&lt;/em&gt;baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7759:1-7761:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo******bar*********baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7763:1-7765:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo&lt;strong&gt;&lt;strong&gt;&lt;strong&gt;bar&lt;/strong&gt;&lt;/strong&gt;&lt;/strong&gt;***baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7768:1-7768:42" dir="auto">Indefinite levels of nesting are possible:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7770:1-7772:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo **bar *baz* bim** bop*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7774:1-7776:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;strong&gt;bar &lt;em&gt;baz&lt;/em&gt; bim&lt;/strong&gt; bop&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7779:1-7781:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo [*bar*](/url)*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7783:1-7785:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;a href="/url"&gt;&lt;em&gt;bar&lt;/em&gt;&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7788:1-7788:50" dir="auto">There can be no empty emphasis or strong emphasis:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7790:1-7792:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">** is not an empty emphasis</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7794:1-7796:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;** is not an empty emphasis&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7799:1-7801:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**** is not an empty strong emphasis</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7803:1-7805:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;**** is not an empty strong emphasis&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7809:1-7809:8" dir="auto">Rule 10:</p>
+<p data-sourcepos="7811:1-7812:25" dir="auto">Any nonempty sequence of inline elements can be the contents of an
+strongly emphasized span.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7814:1-7816:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo [bar](/url)**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7818:1-7820:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;a href="/url"&gt;bar&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7823:1-7826:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo</span>
+<span id="LC2" class="line" lang="plaintext">bar**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7828:1-7831:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo</span>
+<span id="LC2" class="line" lang="plaintext">bar&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7834:1-7835:23" dir="auto">In particular, emphasis and strong emphasis can be nested
+inside strong emphasis:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7837:1-7839:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo _bar_ baz__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7841:1-7843:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;em&gt;bar&lt;/em&gt; baz&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7846:1-7848:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo __bar__ baz__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7850:1-7852:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;strong&gt;bar&lt;/strong&gt; baz&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7855:1-7857:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">____foo__ bar__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7859:1-7861:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;&lt;strong&gt;foo&lt;/strong&gt; bar&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7864:1-7866:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo **bar****</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7868:1-7870:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;strong&gt;bar&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7873:1-7875:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo *bar* baz**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7877:1-7879:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;em&gt;bar&lt;/em&gt; baz&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7882:1-7884:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo*bar*baz**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7886:1-7888:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo&lt;em&gt;bar&lt;/em&gt;baz&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7891:1-7893:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">***foo* bar**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7895:1-7897:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;&lt;em&gt;foo&lt;/em&gt; bar&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7900:1-7902:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo *bar***</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7904:1-7906:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;em&gt;bar&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7909:1-7909:42" dir="auto">Indefinite levels of nesting are possible:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7911:1-7914:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo *bar **baz**</span>
+<span id="LC2" class="line" lang="plaintext">bim* bop**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7916:1-7919:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;em&gt;bar &lt;strong&gt;baz&lt;/strong&gt;</span>
+<span id="LC2" class="line" lang="plaintext">bim&lt;/em&gt; bop&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7922:1-7924:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo [*bar*](/url)**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7926:1-7928:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo &lt;a href="/url"&gt;&lt;em&gt;bar&lt;/em&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7931:1-7931:50" dir="auto">There can be no empty emphasis or strong emphasis:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7933:1-7935:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__ is not an empty emphasis</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7937:1-7939:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;__ is not an empty emphasis&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7942:1-7944:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">____ is not an empty strong emphasis</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7946:1-7948:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;____ is not an empty strong emphasis&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="7952:1-7952:8" dir="auto">Rule 11:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7954:1-7956:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo ***</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7958:1-7960:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo ***&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7963:1-7965:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo *\**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7967:1-7969:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &lt;em&gt;*&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7972:1-7974:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo *_*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7976:1-7978:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &lt;em&gt;_&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7981:1-7983:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo *****</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7985:1-7987:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo *****&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7990:1-7992:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo **\***</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7994:1-7996:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &lt;strong&gt;*&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="7999:1-8001:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo **_**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8003:1-8005:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &lt;strong&gt;_&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8008:1-8010:32" dir="auto">Note that when delimiters do not match evenly, Rule 11 determines
+that the excess literal <code>*</code> characters will appear outside of the
+emphasis, rather than inside it:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8012:1-8014:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8016:1-8018:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;*&lt;em&gt;foo&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8021:1-8023:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8025:1-8027:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;/em&gt;*&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8030:1-8032:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">***foo**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8034:1-8036:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;*&lt;strong&gt;foo&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8039:1-8041:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">****foo*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8043:1-8045:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;***&lt;em&gt;foo&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8048:1-8050:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo***</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8052:1-8054:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo&lt;/strong&gt;*&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8057:1-8059:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo****</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8061:1-8063:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;/em&gt;***&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8067:1-8067:8" dir="auto">Rule 12:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8069:1-8071:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo ___</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8073:1-8075:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo ___&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8078:1-8080:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo _\__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8082:1-8084:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &lt;em&gt;_&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8087:1-8089:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo _*_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8091:1-8093:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &lt;em&gt;*&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8096:1-8098:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo _____</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8100:1-8102:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo _____&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8105:1-8107:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo __\___</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8109:1-8111:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &lt;strong&gt;_&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8114:1-8116:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo __*__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8118:1-8120:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &lt;strong&gt;*&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8123:1-8125:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8127:1-8129:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;_&lt;em&gt;foo&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8132:1-8134:32" dir="auto">Note that when delimiters do not match evenly, Rule 12 determines
+that the excess literal <code>_</code> characters will appear outside of the
+emphasis, rather than inside it:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8136:1-8138:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8140:1-8142:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;/em&gt;_&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8145:1-8147:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">___foo__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8149:1-8151:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;_&lt;strong&gt;foo&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8154:1-8156:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">____foo_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8158:1-8160:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;___&lt;em&gt;foo&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8163:1-8165:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo___</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8167:1-8169:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo&lt;/strong&gt;_&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8172:1-8174:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo____</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8176:1-8178:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;/em&gt;___&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8181:1-8182:44" dir="auto">Rule 13 implies that if you want emphasis nested directly inside
+emphasis, you must use different delimiters:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8184:1-8186:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8188:1-8190:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8193:1-8195:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*_foo_*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8197:1-8199:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;&lt;em&gt;foo&lt;/em&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8202:1-8204:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__foo__</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8206:1-8208:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;foo&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8211:1-8213:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_*foo*_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8215:1-8217:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;&lt;em&gt;foo&lt;/em&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8220:1-8221:21" dir="auto">However, strong emphasis within strong emphasis is possible without
+switching delimiters:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8223:1-8225:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">****foo****</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8227:1-8229:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;&lt;strong&gt;foo&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8232:1-8234:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">____foo____</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8236:1-8238:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;&lt;strong&gt;foo&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8242:1-8243:11" dir="auto">Rule 13 can be applied to arbitrarily long sequences of
+delimiters:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8245:1-8247:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">******foo******</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8249:1-8251:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;&lt;strong&gt;&lt;strong&gt;foo&lt;/strong&gt;&lt;/strong&gt;&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8254:1-8254:8" dir="auto">Rule 14:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8256:1-8258:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">***foo***</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8260:1-8262:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;&lt;strong&gt;foo&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8265:1-8267:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_____foo_____</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8269:1-8271:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;&lt;strong&gt;&lt;strong&gt;foo&lt;/strong&gt;&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8274:1-8274:8" dir="auto">Rule 15:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8276:1-8278:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo _bar* baz_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8280:1-8282:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo _bar&lt;/em&gt; baz_&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8285:1-8287:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo __bar *baz bim__ bam*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8289:1-8291:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo &lt;strong&gt;bar *baz bim&lt;/strong&gt; bam&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8294:1-8294:8" dir="auto">Rule 16:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8296:1-8298:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**foo **bar baz**</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8300:1-8302:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;**foo &lt;strong&gt;bar baz&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8305:1-8307:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo *bar baz*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8309:1-8311:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;*foo &lt;em&gt;bar baz&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8314:1-8314:8" dir="auto">Rule 17:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8316:1-8318:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*[bar*](/url)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8320:1-8322:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;*&lt;a href="/url"&gt;bar*&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8325:1-8327:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_foo [bar_](/url)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8329:1-8331:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;_foo &lt;a href="/url"&gt;bar_&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8334:1-8336:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*&lt;img src="foo" title="*"/&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8338:1-8340:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;*&lt;img src="foo" title="*"/&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8343:1-8345:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**&lt;a href="**"&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8347:1-8349:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;**&lt;a href="**"&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8352:1-8354:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__&lt;a href="__"&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8356:1-8358:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;__&lt;a href="__"&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8361:1-8363:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*a `*`*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8365:1-8367:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;a &lt;code&gt;*&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8370:1-8372:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_a `_`_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8374:1-8376:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;a &lt;code&gt;_&lt;/code&gt;&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8379:1-8381:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">**a&lt;http://foo.bar/?q=**&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8383:1-8385:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;**a&lt;a href="http://foo.bar/?q=**"&gt;http://foo.bar/?q=**&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8388:1-8390:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__a&lt;http://foo.bar/?q=__&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8392:1-8394:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;__a&lt;a href="http://foo.bar/?q=__"&gt;http://foo.bar/?q=__&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div>
+<h2 data-sourcepos="8399:1-8399:28">
+<a id="user-content-strikethrough-extension" class="anchor" href="#strikethrough-extension" aria-hidden="true"></a>Strikethrough (extension)</h2>
+<p data-sourcepos="8401:1-8402:10">GFM enables the <code>strikethrough</code> extension, where an additional emphasis type is
+available.</p>
+<p data-sourcepos="8404:1-8404:59">Strikethrough text is any text wrapped in two tildes (<code>~</code>).</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8406:1-8408:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">~~Hi~~ Hello, world!</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8410:1-8412:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;del&gt;Hi&lt;/del&gt; Hello, world!&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8414:1-8415:17">As with regular emphasis delimiters, a new paragraph will cause strikethrough
+parsing to cease:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8417:1-8421:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This ~~has a</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">new paragraph~~.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8423:1-8426:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;This ~~has a&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;new paragraph~~.&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+</div>
+<h2 data-sourcepos="8430:1-8430:8" dir="auto">
+<a id="user-content-links" class="anchor" href="#links" aria-hidden="true"></a>Links</h2>
+<p data-sourcepos="8432:1-8437:13" dir="auto">A link contains [link text] (the visible text), a [link destination]
+(the URI that is the link destination), and optionally a [link title].
+There are two basic kinds of links in Markdown. In [inline links] the
+destination and title are given immediately after the link text. In
+[reference links] the destination and title are defined elsewhere in
+the document.</p>
+<p data-sourcepos="8439:1-8441:22" dir="auto">A <a href="@">link text</a> consists of a sequence of zero or more
+inline elements enclosed by square brackets (<code>[</code> and <code>]</code>). The
+following rules apply:</p>
+<ul data-sourcepos="8443:1-8459:0" dir="auto">
+<li data-sourcepos="8443:1-8446:0">
+<p data-sourcepos="8443:3-8445:43">Links may not contain other links, at any level of nesting. If
+multiple otherwise valid link definitions appear nested inside each
+other, the inner-most definition is used.</p>
+</li>
+<li data-sourcepos="8447:1-8451:0">
+<p data-sourcepos="8447:3-8450:22">Brackets are allowed in the [link text] only if (a) they
+are backslash-escaped or (b) they appear as a matched pair of brackets,
+with an open bracket <code>[</code>, a sequence of zero or more inlines, and
+a close bracket <code>]</code>.</p>
+</li>
+<li data-sourcepos="8452:1-8456:0">
+<p data-sourcepos="8452:3-8455:25">Backtick [code spans], [autolinks], and raw [HTML tags] bind more tightly
+than the brackets in link text. Thus, for example,
+<code>[foo`]`</code> could not be a link text, since the second <code>]</code>
+is part of a code span.</p>
+</li>
+<li data-sourcepos="8457:1-8459:0">
+<p data-sourcepos="8457:3-8458:78">The brackets in link text bind more tightly than markers for
+[emphasis and strong emphasis]. Thus, for example, <code>*[foo*](url)</code> is a link.</p>
+</li>
+</ul>
+<p data-sourcepos="8460:1-8460:42" dir="auto">A <a href="@">link destination</a> consists of either</p>
+<ul data-sourcepos="8462:1-8473:0" dir="auto">
+<li data-sourcepos="8462:1-8465:0">
+<p data-sourcepos="8462:3-8464:27">a sequence of zero or more characters between an opening <code>&lt;</code> and a
+closing <code>&gt;</code> that contains no line breaks or unescaped
+<code>&lt;</code> or <code>&gt;</code> characters, or</p>
+</li>
+<li data-sourcepos="8466:1-8473:0">
+<p data-sourcepos="8466:3-8472:23">a nonempty sequence of characters that does not start with
+<code>&lt;</code>, does not include ASCII space or control characters, and
+includes parentheses only if (a) they are backslash-escaped or
+(b) they are part of a balanced pair of unescaped parentheses.
+(Implementations may impose limits on parentheses nesting to
+avoid performance issues, but at least three levels of nesting
+should be supported.)</p>
+</li>
+</ul>
+<p data-sourcepos="8474:1-8474:37" dir="auto">A <a href="@">link title</a> consists of either</p>
+<ul data-sourcepos="8476:1-8487:0" dir="auto">
+<li data-sourcepos="8476:1-8479:0">
+<p data-sourcepos="8476:3-8478:23">a sequence of zero or more characters between straight double-quote
+characters (<code>"</code>), including a <code>"</code> character only if it is
+backslash-escaped, or</p>
+</li>
+<li data-sourcepos="8480:1-8483:0">
+<p data-sourcepos="8480:3-8482:23">a sequence of zero or more characters between straight single-quote
+characters (<code>'</code>), including a <code>'</code> character only if it is
+backslash-escaped, or</p>
+</li>
+<li data-sourcepos="8484:1-8487:0">
+<p data-sourcepos="8484:3-8486:20">a sequence of zero or more characters between matching parentheses
+(<code>(...)</code>), including a <code>(</code> or <code>)</code> character only if it is
+backslash-escaped.</p>
+</li>
+</ul>
+<p data-sourcepos="8488:1-8489:15" dir="auto">Although [link titles] may span multiple lines, they may not contain
+a [blank line].</p>
+<p data-sourcepos="8491:1-8501:6" dir="auto">An <a href="@">inline link</a> consists of a [link text] followed immediately
+by a left parenthesis <code>(</code>, optional [whitespace], an optional
+[link destination], an optional [link title] separated from the link
+destination by [whitespace], optional [whitespace], and a right
+parenthesis <code>)</code>. The link's text consists of the inlines contained
+in the [link text] (excluding the enclosing square brackets).
+The link's URI consists of the link destination, excluding enclosing
+<code>&lt;...&gt;</code> if present, with backslash-escapes in effect as described
+above. The link's title consists of the link title, excluding its
+enclosing delimiters, with backslash-escapes in effect as described
+above.</p>
+<p data-sourcepos="8503:1-8503:29" dir="auto">Here is a simple inline link:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8505:1-8507:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/uri "title")</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8509:1-8511:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri" title="title"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8514:1-8514:25" dir="auto">The title may be omitted:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8516:1-8518:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/uri)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8520:1-8522:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8525:1-8525:50" dir="auto">Both the title and the destination may be omitted:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8527:1-8529:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link]()</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8531:1-8533:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href=""&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8536:1-8538:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](&lt;&gt;)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8540:1-8542:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href=""&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8544:1-8545:28" dir="auto">The destination can only contain spaces if it is
+enclosed in pointy brackets:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8547:1-8549:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/my uri)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8551:1-8553:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[link](/my uri)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8555:1-8557:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](&lt;/my uri&gt;)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8559:1-8561:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/my%20uri"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8563:1-8564:36" dir="auto">The destination cannot contain line breaks,
+even if enclosed in pointy brackets:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8566:1-8569:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](foo</span>
+<span id="LC2" class="line" lang="plaintext">bar)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8571:1-8574:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[link](foo</span>
+<span id="LC2" class="line" lang="plaintext">bar)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8576:1-8579:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](&lt;foo</span>
+<span id="LC2" class="line" lang="plaintext">bar&gt;)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8581:1-8584:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[link](&lt;foo</span>
+<span id="LC2" class="line" lang="plaintext">bar&gt;)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8586:1-8587:19" dir="auto">The destination can contain <code>)</code> if it is enclosed
+in pointy brackets:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8589:1-8591:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[a](&lt;b)c&gt;)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8593:1-8595:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="b)c"&gt;a&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8597:1-8597:53" dir="auto">Pointy brackets that enclose links must be unescaped:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8599:1-8601:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](&lt;foo\&gt;)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8603:1-8605:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[link](&amp;lt;foo&amp;gt;)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8607:1-8608:24" dir="auto">These are not links, because the opening pointy bracket
+is not matched properly:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8610:1-8614:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[a](&lt;b)c</span>
+<span id="LC2" class="line" lang="plaintext">[a](&lt;b)c&gt;</span>
+<span id="LC3" class="line" lang="plaintext">[a](&lt;b&gt;c)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8616:1-8620:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[a](&amp;lt;b)c</span>
+<span id="LC2" class="line" lang="plaintext">[a](&amp;lt;b)c&amp;gt;</span>
+<span id="LC3" class="line" lang="plaintext">[a](&lt;b&gt;c)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8622:1-8622:55" dir="auto">Parentheses inside the link destination may be escaped:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8624:1-8626:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](\(foo\))</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8628:1-8630:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="(foo)"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8632:1-8633:9" dir="auto">Any number of parentheses are allowed without escaping, as long as they are
+balanced:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8635:1-8637:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](foo(and(bar)))</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8639:1-8641:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo(and(bar))"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8643:1-8644:13" dir="auto">However, if you have unbalanced parentheses, you need to escape or use the
+<code>&lt;...&gt;</code> form:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8646:1-8648:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](foo\(and\(bar\))</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8650:1-8652:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo(and(bar)"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8655:1-8657:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](&lt;foo(and(bar)&gt;)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8659:1-8661:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo(and(bar)"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8664:1-8665:12" dir="auto">Parentheses and other symbols can also be escaped, as usual
+in Markdown:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8667:1-8669:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](foo\)\:)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8671:1-8673:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo):"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8676:1-8676:52" dir="auto">A link can contain fragment identifiers and queries:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8678:1-8684:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](#fragment)</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[link](http://example.com#fragment)</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">[link](http://example.com?foo=3#frag)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8686:1-8690:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="#fragment"&gt;link&lt;/a&gt;&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://example.com#fragment"&gt;link&lt;/a&gt;&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://example.com?foo=3#frag"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8693:1-8694:17" dir="auto">Note that a backslash before a non-escapable character is
+just a backslash:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8696:1-8698:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](foo\bar)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8700:1-8702:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo%5Cbar"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8705:1-8712:52" dir="auto">URL-escaping should be left alone inside the destination, as all
+URL-escaped characters are also valid URL characters. Entity and
+numerical character references in the destination will be parsed
+into the corresponding Unicode code points, as usual. These may
+be optionally URL-escaped when written as HTML, but this spec
+does not enforce any particular policy for rendering URLs in
+HTML or other formats. Renderers may make different decisions
+about how to escape or normalize URLs in the output.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8714:1-8716:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](foo%20b&amp;auml;)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8718:1-8720:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo%20b%C3%A4"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8723:1-8725:23" dir="auto">Note that, because titles can often be parsed as destinations,
+if you try to omit the destination and keep the title, you'll
+get unexpected results:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8727:1-8729:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link]("title")</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8731:1-8733:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="%22title%22"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8736:1-8736:62" dir="auto">Titles may be in single quotes, double quotes, or parentheses:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8738:1-8742:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/url "title")</span>
+<span id="LC2" class="line" lang="plaintext">[link](/url 'title')</span>
+<span id="LC3" class="line" lang="plaintext">[link](/url (title))</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8744:1-8748:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;link&lt;/a&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;a href="/url" title="title"&gt;link&lt;/a&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;a href="/url" title="title"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8751:1-8752:22" dir="auto">Backslash escapes and entity and numeric character references
+may be used in titles:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8754:1-8756:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/url "title \"&amp;quot;")</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8758:1-8760:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title &amp;quot;&amp;quot;"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8763:1-8764:64" dir="auto">Titles must be separated from the link using a [whitespace].
+Other [Unicode whitespace] like non-breaking space doesn't work.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8766:1-8768:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/url "title")</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8770:1-8772:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url%C2%A0%22title%22"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8775:1-8775:56" dir="auto">Nested balanced quotes are not allowed without escaping:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8777:1-8779:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/url "title "and" title")</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8781:1-8783:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[link](/url &amp;quot;title &amp;quot;and&amp;quot; title&amp;quot;)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8786:1-8786:67" dir="auto">But it is easy to work around this by using a different quote type:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8788:1-8790:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link](/url 'title "and" title')</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8792:1-8794:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title &amp;quot;and&amp;quot; title"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8797:1-8810:61" dir="auto">(Note: <code>Markdown.pl</code> did allow double quotes inside a double-quoted
+title, and its test suite included a test demonstrating this.
+But it is hard to see a good rationale for the extra complexity this
+brings, since there are already many ways---backslash escaping,
+entity and numeric character references, or using a different
+quote type for the enclosing title---to write titles containing
+double quotes. <code>Markdown.pl</code>'s handling of titles has a number
+of other strange features. For example, it allows single-quoted
+titles in inline links, but not reference links. And, in
+reference links but not inline links, it allows a title to begin
+with <code>"</code> and end with <code>)</code>. <code>Markdown.pl</code> 1.0.1 even allows
+titles with no closing quotation mark, though 1.0.2b8 does not.
+It seems preferable to adopt a simple, rational rule that works
+the same way in inline links and link reference definitions.)</p>
+<p data-sourcepos="8812:1-8812:57" dir="auto">[Whitespace] is allowed around the destination and title:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8814:1-8817:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link]( /uri</span>
+<span id="LC2" class="line" lang="plaintext"> "title" )</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8819:1-8821:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri" title="title"&gt;link&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8824:1-8825:22" dir="auto">But it is not allowed between the link text and the
+following parenthesis:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8827:1-8829:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link] (/uri)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8831:1-8833:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[link] (/uri)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8836:1-8837:24" dir="auto">The link text may contain balanced brackets, but not unbalanced ones,
+unless they are escaped:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8839:1-8841:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link [foo [bar]]](/uri)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8843:1-8845:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;link [foo [bar]]&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8848:1-8850:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link] bar](/uri)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8852:1-8854:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[link] bar](/uri)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8857:1-8859:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link [bar](/uri)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8861:1-8863:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[link &lt;a href="/uri"&gt;bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8866:1-8868:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link \[bar](/uri)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8870:1-8872:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;link [bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8875:1-8875:41" dir="auto">The link text may contain inline content:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8877:1-8879:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link *foo **bar** `#`*](/uri)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8881:1-8883:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;link &lt;em&gt;foo &lt;strong&gt;bar&lt;/strong&gt; &lt;code&gt;#&lt;/code&gt;&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8886:1-8888:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[![moon](moon.jpg)](/uri)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8890:1-8892:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;&lt;img src="moon.jpg" alt="moon" /&gt;&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8895:1-8895:68" dir="auto">However, links may not contain other links, at any level of nesting.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8897:1-8899:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo [bar](/uri)](/uri)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8901:1-8903:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo &lt;a href="/uri"&gt;bar&lt;/a&gt;](/uri)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8906:1-8908:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo *[bar [baz](/uri)](/uri)*](/uri)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8910:1-8912:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo &lt;em&gt;[bar &lt;a href="/uri"&gt;baz&lt;/a&gt;](/uri)&lt;/em&gt;](/uri)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8915:1-8917:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![[[foo](uri1)](uri2)](uri3)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8919:1-8921:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="uri3" alt="[foo](uri2)" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8924:1-8925:18" dir="auto">These cases illustrate the precedence of link text grouping over
+emphasis grouping:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8927:1-8929:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*[foo*](/uri)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8931:1-8933:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;*&lt;a href="/uri"&gt;foo*&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8936:1-8938:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo *bar](baz*)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8940:1-8942:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="baz*"&gt;foo *bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8945:1-8946:11" dir="auto">Note that brackets that <em>aren't</em> part of links do not take
+precedence:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8948:1-8950:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo [bar* baz]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8952:1-8954:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo [bar&lt;/em&gt; baz]&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8957:1-8958:33" dir="auto">These cases illustrate the precedence of HTML tags, code spans,
+and autolinks over link grouping:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8960:1-8962:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo &lt;bar attr="](baz)"&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8964:1-8966:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo &lt;bar attr="](baz)"&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8969:1-8971:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo`](/uri)`</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8973:1-8975:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo&lt;code&gt;](/uri)&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8978:1-8980:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo&lt;http://example.com/?search=](uri)&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="8982:1-8984:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo&lt;a href="http://example.com/?search=%5D(uri)"&gt;http://example.com/?search=](uri)&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="8987:1-8989:41" dir="auto">There are three kinds of <a href="@">reference link</a>s:
+<a href="#full-reference-link">full</a>, <a href="#collapsed-reference-link">collapsed</a>,
+and <a href="#shortcut-reference-link">shortcut</a>.</p>
+<p data-sourcepos="8991:1-8993:71" dir="auto">A <a href="@">full reference link</a>
+consists of a [link text] immediately followed by a [link label]
+that [matches] a [link reference definition] elsewhere in the document.</p>
+<p data-sourcepos="8995:1-9001:9" dir="auto">A <a href="@">link label</a> begins with a left bracket (<code>[</code>) and ends
+with the first right bracket (<code>]</code>) that is not backslash-escaped.
+Between these brackets there must be at least one [non-whitespace character].
+Unescaped square bracket characters are not allowed inside the
+opening and closing square brackets of [link labels]. A link
+label can have at most 999 characters inside the square
+brackets.</p>
+<p data-sourcepos="9003:1-9010:69" dir="auto">One label <a href="@">matches</a>
+another just in case their normalized forms are equal. To normalize a
+label, strip off the opening and closing brackets,
+perform the <em>Unicode case fold</em>, strip leading and trailing
+[whitespace] and collapse consecutive internal
+[whitespace] to a single space. If there are multiple
+matching reference link definitions, the one that comes first in the
+document is used. (It is desirable in such cases to emit a warning.)</p>
+<p data-sourcepos="9012:1-9014:37" dir="auto">The contents of the first link label are parsed as inlines, which are
+used as the link's text. The link's URI and title are provided by the
+matching [link reference definition].</p>
+<p data-sourcepos="9016:1-9016:25" dir="auto">Here is a simple example:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9018:1-9022:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][bar]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[bar]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9024:1-9026:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9029:1-9030:22" dir="auto">The rules for the [link text] are the same as with
+[inline links]. Thus:</p>
+<p data-sourcepos="9032:1-9033:24" dir="auto">The link text may contain balanced brackets, but not unbalanced ones,
+unless they are escaped:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9035:1-9039:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link [foo [bar]]][ref]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9041:1-9043:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;link [foo [bar]]&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9046:1-9050:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link \[bar][ref]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9052:1-9054:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;link [bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9057:1-9057:41" dir="auto">The link text may contain inline content:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9059:1-9063:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[link *foo **bar** `#`*][ref]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9065:1-9067:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;link &lt;em&gt;foo &lt;strong&gt;bar&lt;/strong&gt; &lt;code&gt;#&lt;/code&gt;&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9070:1-9074:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[![moon](moon.jpg)][ref]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9076:1-9078:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;&lt;img src="moon.jpg" alt="moon" /&gt;&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9081:1-9081:68" dir="auto">However, links may not contain other links, at any level of nesting.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9083:1-9087:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo [bar](/uri)][ref]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9089:1-9091:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo &lt;a href="/uri"&gt;bar&lt;/a&gt;]&lt;a href="/uri"&gt;ref&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9094:1-9098:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo *bar [baz][ref]*][ref]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9100:1-9102:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo &lt;em&gt;bar &lt;a href="/uri"&gt;baz&lt;/a&gt;&lt;/em&gt;]&lt;a href="/uri"&gt;ref&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9105:1-9106:38" dir="auto">(In the examples above, we have two [shortcut reference links]
+instead of one [full reference link].)</p>
+<p data-sourcepos="9108:1-9109:18" dir="auto">The following cases illustrate the precedence of link text grouping over
+emphasis grouping:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9111:1-9115:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*[foo*][ref]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9117:1-9119:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;*&lt;a href="/uri"&gt;foo*&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9122:1-9126:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo *bar][ref]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9128:1-9130:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;foo *bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9133:1-9134:33" dir="auto">These cases illustrate the precedence of HTML tags, code spans,
+and autolinks over link grouping:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9136:1-9140:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo &lt;bar attr="][ref]"&gt;</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9142:1-9144:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo &lt;bar attr="][ref]"&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9147:1-9151:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo`][ref]`</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9153:1-9155:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo&lt;code&gt;][ref]&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9158:1-9162:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo&lt;http://example.com/?search=][ref]&gt;</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[ref]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9164:1-9166:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo&lt;a href="http://example.com/?search=%5D%5Bref%5D"&gt;http://example.com/?search=][ref]&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9169:1-9169:29" dir="auto">Matching is case-insensitive:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9171:1-9175:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][BaR]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[bar]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9177:1-9179:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9182:1-9182:26" dir="auto">Unicode case fold is used:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9184:1-9188:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[Толпой][Толпой] is a Russian word.</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[ТОЛПОЙ]: /url</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9190:1-9192:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url"&gt;Толпой&lt;/a&gt; is a Russian word.&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9195:1-9196:33" dir="auto">Consecutive internal [whitespace] is treated as one space for
+purposes of determining matching:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9198:1-9203:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[Foo</span>
+<span id="LC2" class="line" lang="plaintext"> bar]: /url</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">[Baz][Foo bar]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9205:1-9207:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url"&gt;Baz&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9210:1-9211:13" dir="auto">No [whitespace] is allowed between the [link text] and the
+[link label]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9213:1-9217:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo] [bar]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[bar]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9219:1-9221:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo] &lt;a href="/url" title="title"&gt;bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9224:1-9229:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]</span>
+<span id="LC2" class="line" lang="plaintext">[bar]</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">[bar]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9231:1-9234:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo]</span>
+<span id="LC2" class="line" lang="plaintext">&lt;a href="/url" title="title"&gt;bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9237:1-9246:9" dir="auto">This is a departure from John Gruber's original Markdown syntax
+description, which explicitly allows whitespace between the link
+text and the link label. It brings reference links in line with
+[inline links], which (according to both original Markdown and
+this spec) cannot have whitespace after the link text. More
+importantly, it prevents inadvertent capture of consecutive
+[shortcut reference links]. If whitespace is allowed between the
+link text and the link label, then in the following we will have
+a single reference link, not two shortcut reference links, as
+intended:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9248:1-9254:3" lang="markdown" class="code highlight js-syntax-highlight language-markdown" v-pre="true"><code><span id="LC1" class="line" lang="markdown">[foo]</span>
+<span id="LC2" class="line" lang="markdown">[bar]</span>
+<span id="LC3" class="line" lang="markdown"></span>
+<span id="LC4" class="line" lang="markdown"><span class="p">[</span><span class="ss">foo</span><span class="p">]:</span> <span class="sx">/url1</span></span>
+<span id="LC5" class="line" lang="markdown"><span class="p">[</span><span class="ss">bar</span><span class="p">]:</span> <span class="sx">/url2</span></span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9256:1-9262:20" dir="auto">(Note that [shortcut reference links] were introduced by Gruber
+himself in a beta version of <code>Markdown.pl</code>, but never included
+in the official syntax description. Without shortcut reference
+links, it is harmless to allow space between the link text and
+link label; but once shortcut references are introduced, it is
+too dangerous to allow this, as it frequently leads to
+unintended results.)</p>
+<p data-sourcepos="9264:1-9265:18" dir="auto">When there are multiple matching [link reference definitions],
+the first is used:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9267:1-9273:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]: /url1</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url2</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">[bar][foo]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9275:1-9277:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url1"&gt;bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9280:1-9282:40" dir="auto">Note that matching is performed on normalized strings, not parsed
+inline content. So the following does not match, even though the
+labels define equivalent inline content:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9284:1-9288:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[bar][foo\!]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo!]: /url</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9290:1-9292:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[bar][foo!]&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9295:1-9296:18" dir="auto">[Link labels] cannot contain brackets, unless they are
+backslash-escaped:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9298:1-9302:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][ref[]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[ref[]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9304:1-9307:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo][ref[]&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;[ref[]: /uri&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9310:1-9314:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][ref[bar]]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[ref[bar]]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9316:1-9319:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo][ref[bar]]&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;[ref[bar]]: /uri&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9322:1-9326:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[[[foo]]]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[[[foo]]]: /url</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9328:1-9331:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[[[foo]]]&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;[[[foo]]]: /url&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9334:1-9338:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][ref\[]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[ref\[]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9340:1-9342:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9345:1-9345:55" dir="auto">Note that in this example <code>]</code> is not backslash-escaped:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9347:1-9351:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[bar\\]: /uri</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[bar\\]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9353:1-9355:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/uri"&gt;bar\&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9358:1-9358:68" dir="auto">A [link label] must contain at least one [non-whitespace character]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9360:1-9364:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9366:1-9369:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[]&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;[]: /uri&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9372:1-9378:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[</span>
+<span id="LC2" class="line" lang="plaintext"> ]</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">[</span>
+<span id="LC5" class="line" lang="plaintext"> ]: /uri</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9380:1-9385:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[</span>
+<span id="LC2" class="line" lang="plaintext">]&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;[</span>
+<span id="LC4" class="line" lang="plaintext">]: /uri&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9388:1-9395:40" dir="auto">A <a href="@">collapsed reference link</a>
+consists of a [link label] that [matches] a
+[link reference definition] elsewhere in the
+document, followed by the string <code>[]</code>.
+The contents of the first link label are parsed as inlines,
+which are used as the link's text. The link's URI and title are
+provided by the matching reference link definition. Thus,
+<code>[foo][]</code> is equivalent to <code>[foo][foo]</code>.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9397:1-9401:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9403:1-9405:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9408:1-9412:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[*foo* bar][]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[*foo* bar]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9414:1-9416:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;&lt;em&gt;foo&lt;/em&gt; bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9419:1-9419:37" dir="auto">The link labels are case-insensitive:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9421:1-9425:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[Foo][]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9427:1-9429:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;Foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9433:1-9434:41" dir="auto">As with full reference links, [whitespace] is not
+allowed between the two sets of brackets:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9436:1-9441:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo] </span>
+<span id="LC2" class="line" lang="plaintext">[]</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">[foo]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9443:1-9446:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;foo&lt;/a&gt;</span>
+<span id="LC2" class="line" lang="plaintext">[]&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9449:1-9456:41" dir="auto">A <a href="@">shortcut reference link</a>
+consists of a [link label] that [matches] a
+[link reference definition] elsewhere in the
+document and is not followed by <code>[]</code> or a link label.
+The contents of the first link label are parsed as inlines,
+which are used as the link's text. The link's URI and title
+are provided by the matching link reference definition.
+Thus, <code>[foo]</code> is equivalent to <code>[foo][]</code>.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9458:1-9462:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9464:1-9466:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9469:1-9473:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[*foo* bar]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[*foo* bar]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9475:1-9477:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;&lt;em&gt;foo&lt;/em&gt; bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9480:1-9484:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[[*foo* bar]]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[*foo* bar]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9486:1-9488:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[&lt;a href="/url" title="title"&gt;&lt;em&gt;foo&lt;/em&gt; bar&lt;/a&gt;]&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9491:1-9495:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[[bar [foo]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9497:1-9499:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[[bar &lt;a href="/url"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9502:1-9502:37" dir="auto">The link labels are case-insensitive:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9504:1-9508:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[Foo]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9510:1-9512:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url" title="title"&gt;Foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9515:1-9515:48" dir="auto">A space after the link text should be preserved:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9517:1-9521:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo] bar</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9523:1-9525:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url"&gt;foo&lt;/a&gt; bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9528:1-9529:31" dir="auto">If you just want bracketed text, you can backslash-escape the
+opening bracket to avoid links:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9531:1-9535:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\[foo]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9537:1-9539:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9542:1-9543:26" dir="auto">Note that this is a link, because a link label ends with the first
+following closing bracket:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9545:1-9549:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo*]: /url</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">*[foo*]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9551:1-9553:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;*&lt;a href="/url"&gt;foo*&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9556:1-9557:11" dir="auto">Full and compact references take precedence over shortcut
+references:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9559:1-9564:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][bar]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url1</span>
+<span id="LC4" class="line" lang="plaintext">[bar]: /url2</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9566:1-9568:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url2"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9570:1-9574:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url1</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9576:1-9578:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url1"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9580:1-9580:34" dir="auto">Inline links also take precedence:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9582:1-9586:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo]()</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url1</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9588:1-9590:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href=""&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9592:1-9596:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo](not a link)</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url1</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9598:1-9600:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url1"&gt;foo&lt;/a&gt;(not a link)&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9602:1-9603:23" dir="auto">In the following case <code>[bar][baz]</code> is parsed as a reference,
+<code>[foo]</code> as normal text:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9605:1-9609:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][bar][baz]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[baz]: /url</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9611:1-9613:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;a href="/url"&gt;bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9616:1-9617:19" dir="auto">Here, though, <code>[foo][bar]</code> is parsed as a reference, since
+<code>[bar]</code> is defined:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9619:1-9624:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][bar][baz]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[baz]: /url1</span>
+<span id="LC4" class="line" lang="plaintext">[bar]: /url2</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9626:1-9628:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="/url2"&gt;foo&lt;/a&gt;&lt;a href="/url1"&gt;baz&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9631:1-9632:65" dir="auto">Here <code>[foo]</code> is not parsed as a shortcut reference, because it
+is followed by a link label (even though <code>[bar]</code> is not defined):</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9634:1-9639:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[foo][bar][baz]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[baz]: /url1</span>
+<span id="LC4" class="line" lang="plaintext">[foo]: /url2</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9641:1-9643:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[foo]&lt;a href="/url1"&gt;bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="9647:1-9647:9" dir="auto">
+<a id="user-content-images" class="anchor" href="#images" aria-hidden="true"></a>Images</h2>
+<p data-sourcepos="9649:1-9657:55" dir="auto">Syntax for images is like the syntax for links, with one
+difference. Instead of [link text], we have an
+<a href="@">image description</a>. The rules for this are the
+same as for [link text], except that (a) an
+image description starts with <code>![</code> rather than <code>[</code>, and
+(b) an image description may contain links.
+An image description has inline elements
+as its contents. When an image is rendered to HTML,
+this is standardly used as the image's <code>alt</code> attribute.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9659:1-9661:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo](/url "title")</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9663:1-9665:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo" title="title" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9668:1-9672:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo *bar*]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo *bar*]: train.jpg "train &amp; tracks"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9674:1-9676:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="train.jpg" alt="foo bar" title="train &amp;amp; tracks" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9679:1-9681:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo ![bar](/url)](/url2)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9683:1-9685:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url2" alt="foo bar" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9688:1-9690:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo [bar](/url)](/url2)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9692:1-9694:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url2" alt="foo bar" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9697:1-9702:40" dir="auto">Though this spec is concerned with parsing, not rendering, it is
+recommended that in rendering to HTML, only the plain string content
+of the [image description] be used. Note that in
+the above example, the alt attribute's value is <code>foo bar</code>, not <code>foo [bar](/url)</code> or <code>foo &lt;a href="/url"&gt;bar&lt;/a&gt;</code>. Only the plain string
+content is rendered, without formatting.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9704:1-9708:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo *bar*][]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo *bar*]: train.jpg "train &amp; tracks"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9710:1-9712:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="train.jpg" alt="foo bar" title="train &amp;amp; tracks" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9715:1-9719:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo *bar*][foobar]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[FOOBAR]: train.jpg "train &amp; tracks"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9721:1-9723:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="train.jpg" alt="foo bar" title="train &amp;amp; tracks" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9726:1-9728:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo](train.jpg)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9730:1-9732:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="train.jpg" alt="foo" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9735:1-9737:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">My ![foo bar](/path/to/train.jpg "title" )</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9739:1-9741:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;My &lt;img src="/path/to/train.jpg" alt="foo bar" title="title" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9744:1-9746:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo](&lt;url&gt;)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9748:1-9750:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="url" alt="foo" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9753:1-9755:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![](/url)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9757:1-9759:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9762:1-9762:16" dir="auto">Reference-style:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9764:1-9768:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo][bar]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[bar]: /url</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9770:1-9772:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9775:1-9779:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo][bar]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[BAR]: /url</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9781:1-9783:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9786:1-9786:10" dir="auto">Collapsed:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9788:1-9792:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo][]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9794:1-9796:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo" title="title" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9799:1-9803:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![*foo* bar][]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[*foo* bar]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9805:1-9807:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo bar" title="title" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9810:1-9810:32" dir="auto">The labels are case-insensitive:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9812:1-9816:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![Foo][]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9818:1-9820:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="Foo" title="title" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9823:1-9824:33" dir="auto">As with reference links, [whitespace] is not allowed
+between the two sets of brackets:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9826:1-9831:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo] </span>
+<span id="LC2" class="line" lang="plaintext">[]</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">[foo]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9833:1-9836:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo" title="title" /&gt;</span>
+<span id="LC2" class="line" lang="plaintext">[]&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9839:1-9839:9" dir="auto">Shortcut:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9841:1-9845:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![foo]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9847:1-9849:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo" title="title" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9852:1-9856:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![*foo* bar]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[*foo* bar]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9858:1-9860:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="foo bar" title="title" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9863:1-9863:56" dir="auto">Note that link labels cannot contain unescaped brackets:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9865:1-9869:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![[foo]]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[[foo]]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9871:1-9874:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;![[foo]]&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;[[foo]]: /url &amp;quot;title&amp;quot;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9877:1-9877:37" dir="auto">The link labels are case-insensitive:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9879:1-9883:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![Foo]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9885:1-9887:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;img src="/url" alt="Foo" title="title" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9890:1-9891:33" dir="auto">If you just want a literal <code>!</code> followed by bracketed text, you can
+backslash-escape the opening <code>[</code>:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9893:1-9897:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">!\[foo]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9899:1-9901:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;![foo]&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9904:1-9905:4" dir="auto">If you want a link after a literal <code>!</code>, backslash-escape the
+<code>!</code>:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9907:1-9911:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">\![foo]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[foo]: /url "title"</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9913:1-9915:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;!&lt;a href="/url" title="title"&gt;foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="9918:1-9918:12" dir="auto">
+<a id="user-content-autolinks" class="anchor" href="#autolinks" aria-hidden="true"></a>Autolinks</h2>
+<p data-sourcepos="9920:1-9922:18" dir="auto"><a href="@">Autolink</a>s are absolute URIs and email addresses inside
+<code>&lt;</code> and <code>&gt;</code>. They are parsed as links, with the URL or email address
+as the link label.</p>
+<p data-sourcepos="9924:1-9926:52" dir="auto">A <a href="@">URI autolink</a> consists of <code>&lt;</code>, followed by an
+[absolute URI] followed by <code>&gt;</code>. It is parsed as
+a link to the URI, with the URI as the link's label.</p>
+<p data-sourcepos="9928:1-9933:25" dir="auto">An <a href="@">absolute URI</a>,
+for these purposes, consists of a [scheme] followed by a colon (<code>:</code>)
+followed by zero or more characters other than ASCII
+[whitespace] and control characters, <code>&lt;</code>, and <code>&gt;</code>. If
+the URI includes these characters, they must be percent-encoded
+(e.g. <code>%20</code> for a space).</p>
+<p data-sourcepos="9935:1-9938:37" dir="auto">For purposes of this spec, a <a href="@">scheme</a> is any sequence
+of 2--32 characters beginning with an ASCII letter and followed
+by any combination of ASCII letters, digits, or the symbols plus
+("+"), period ("."), or hyphen ("-").</p>
+<p data-sourcepos="9940:1-9940:30" dir="auto">Here are some valid autolinks:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9942:1-9944:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;http://foo.bar.baz&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9946:1-9948:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://foo.bar.baz"&gt;http://foo.bar.baz&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9951:1-9953:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9955:1-9957:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://foo.bar.baz/test?q=hello&amp;amp;id=22&amp;amp;boolean"&gt;http://foo.bar.baz/test?q=hello&amp;amp;id=22&amp;amp;boolean&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9960:1-9962:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;irc://foo.bar:2233/baz&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9964:1-9966:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="irc://foo.bar:2233/baz"&gt;irc://foo.bar:2233/baz&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9969:1-9969:23" dir="auto">Uppercase is also fine:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9971:1-9973:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;MAILTO:FOO@BAR.BAZ&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9975:1-9977:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="MAILTO:FOO@BAR.BAZ"&gt;MAILTO:FOO@BAR.BAZ&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="9980:1-9983:18" dir="auto">Note that many strings that count as [absolute URIs] for
+purposes of this spec are not valid URIs, because their
+schemes are not registered or because of other problems
+with their syntax:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9985:1-9987:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a+b+c:d&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9989:1-9991:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="a+b+c:d"&gt;a+b+c:d&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9994:1-9996:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;made-up-scheme://foo,bar&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="9998:1-10000:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="made-up-scheme://foo,bar"&gt;made-up-scheme://foo,bar&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10003:1-10005:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;http://../&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10007:1-10009:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://../"&gt;http://../&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10012:1-10014:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;localhost:5001/foo&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10016:1-10018:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="localhost:5001/foo"&gt;localhost:5001/foo&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10021:1-10021:36" dir="auto">Spaces are not allowed in autolinks:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10023:1-10025:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;http://foo.bar/baz bim&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10027:1-10029:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;lt;http://foo.bar/baz bim&amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10032:1-10032:47" dir="auto">Backslash-escapes do not work inside autolinks:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10034:1-10036:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;http://example.com/\[\&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10038:1-10040:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://example.com/%5C%5B%5C"&gt;http://example.com/\[\&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10043:1-10046:55" dir="auto">An <a href="@">email autolink</a>
+consists of <code>&lt;</code>, followed by an [email address],
+followed by <code>&gt;</code>. The link's label is the email address,
+and the URL is <code>mailto:</code> followed by the email address.</p>
+<p data-sourcepos="10048:1-10051:83" dir="auto">An <a href="@">email address</a>,
+for these purposes, is anything that matches
+the <a href="https://html.spec.whatwg.org/multipage/forms.html#e-mail-state-(type=email)" rel="nofollow noreferrer noopener" target="_blank">non-normative regex from the HTML5
+spec</a>:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10053:5-10055:0" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">/^[a-zA-Z0-9.!#$%&amp;'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?</span>
+<span id="LC2" class="line" lang="plaintext">(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10056:1-10056:28" dir="auto">Examples of email autolinks:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10058:1-10060:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;foo@bar.example.com&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10062:1-10064:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="mailto:foo@bar.example.com"&gt;foo@bar.example.com&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10067:1-10069:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;foo+special@Bar.baz-bar0.com&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10071:1-10073:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="mailto:foo+special@Bar.baz-bar0.com"&gt;foo+special@Bar.baz-bar0.com&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10076:1-10076:53" dir="auto">Backslash-escapes do not work inside email autolinks:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10078:1-10080:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;foo\+@bar.example.com&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10082:1-10084:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;lt;foo+@bar.example.com&amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10087:1-10087:24" dir="auto">These are not autolinks:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10089:1-10091:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10093:1-10095:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;lt;&amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10098:1-10100:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt; http://foo.bar &gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10102:1-10104:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;lt; http://foo.bar &amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10107:1-10109:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;m:abc&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10111:1-10113:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;lt;m:abc&amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10116:1-10118:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;foo.bar.baz&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10120:1-10122:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;lt;foo.bar.baz&amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10125:1-10127:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">http://example.com</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10129:1-10131:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;http://example.com&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10134:1-10136:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo@bar.example.com</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10138:1-10140:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo@bar.example.com&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div>
+<h2 data-sourcepos="10144:1-10144:24">
+<a id="user-content-autolinks-extension" class="anchor" href="#autolinks-extension" aria-hidden="true"></a>Autolinks (extension)</h2>
+<p data-sourcepos="10146:1-10147:29">GFM enables the <code>autolink</code> extension, where autolinks will be recognised in a
+greater number of conditions.</p>
+<p data-sourcepos="10149:1-10153:8">[Autolink]s can also be constructed without requiring the use of <code>&lt;</code> and to <code>&gt;</code>
+to delimit them, although they will be recognized under a smaller set of
+circumstances. All such recognized autolinks can only come at the beginning of
+a line, after whitespace, or any of the delimiting characters <code>*</code>, <code>_</code>, <code>~</code>,
+and <code>(</code>.</p>
+<p data-sourcepos="10155:1-10161:73">An <a href="@">extended www autolink</a> will be recognized
+when the text <code>www.</code> is found followed by a [valid domain].
+A <a href="@">valid domain</a> consists of segments
+of alphanumeric characters, underscores (<code>_</code>) and hyphens (<code>-</code>)
+separated by periods (<code>.</code>).
+There must be at least one period,
+and no underscores may be present in the last two segments of the domain.</p>
+<p data-sourcepos="10163:1-10163:49">The scheme <code>http</code> will be inserted automatically:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10165:1-10167:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">www.commonmark.org</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10169:1-10171:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://www.commonmark.org"&gt;www.commonmark.org&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10173:1-10173:77">After a [valid domain], zero or more non-space non-<code>&lt;</code> characters may follow:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10175:1-10177:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Visit www.commonmark.org/help for more information.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10179:1-10181:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Visit &lt;a href="http://www.commonmark.org/help"&gt;www.commonmark.org/help&lt;/a&gt; for more information.&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10183:1-10183:64">We then apply <a href="@">extended autolink path validation</a> as follows:</p>
+<p data-sourcepos="10185:1-10187:21">Trailing punctuation (specifically, <code>?</code>, <code>!</code>, <code>.</code>, <code>,</code>, <code>:</code>, <code>*</code>, <code>_</code>, and <code>~</code>)
+will not be considered part of the autolink, though they may be included in the
+interior of the link:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10189:1-10193:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Visit www.commonmark.org.</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">Visit www.commonmark.org/a.b.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10195:1-10198:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Visit &lt;a href="http://www.commonmark.org"&gt;www.commonmark.org&lt;/a&gt;.&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;Visit &lt;a href="http://www.commonmark.org/a.b"&gt;www.commonmark.org/a.b&lt;/a&gt;.&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10200:1-10203:76">When an autolink ends in <code>)</code>, we scan the entire autolink for the total number
+of parentheses. If there is a greater number of closing parentheses than
+opening ones, we don't consider the unmatched trailing parentheses part of the
+autolink, in order to facilitate including an autolink inside a parenthesis:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10205:1-10213:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">www.google.com/search?q=Markup+(business)</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">www.google.com/search?q=Markup+(business)))</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">(www.google.com/search?q=Markup+(business))</span>
+<span id="LC6" class="line" lang="plaintext"></span>
+<span id="LC7" class="line" lang="plaintext">(www.google.com/search?q=Markup+(business)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10215:1-10220:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://www.google.com/search?q=Markup+(business)"&gt;www.google.com/search?q=Markup+(business)&lt;/a&gt;&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://www.google.com/search?q=Markup+(business)"&gt;www.google.com/search?q=Markup+(business)&lt;/a&gt;))&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;(&lt;a href="http://www.google.com/search?q=Markup+(business)"&gt;www.google.com/search?q=Markup+(business)&lt;/a&gt;)&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;(&lt;a href="http://www.google.com/search?q=Markup+(business)"&gt;www.google.com/search?q=Markup+(business)&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10222:1-10224:8">This check is only done when the link ends in a closing parentheses <code>)</code>, so if
+the only parentheses are in the interior of the autolink, no special rules are
+applied:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10226:1-10228:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">www.google.com/search?q=(business))+ok</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10230:1-10232:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://www.google.com/search?q=(business))+ok"&gt;www.google.com/search?q=(business))+ok&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10234:1-10237:13">If an autolink ends in a semicolon (<code>;</code>), we check to see if it appears to
+resemble an [entity reference][entity references]; if the preceding text is <code>&amp;</code>
+followed by one or more alphanumeric characters. If so, it is excluded from
+the autolink:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10239:1-10243:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">www.google.com/search?q=commonmark&amp;hl=en</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">www.google.com/search?q=commonmark&amp;hl;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10245:1-10248:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://www.google.com/search?q=commonmark&amp;amp;hl=en"&gt;www.google.com/search?q=commonmark&amp;amp;hl=en&lt;/a&gt;&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://www.google.com/search?q=commonmark"&gt;www.google.com/search?q=commonmark&lt;/a&gt;&amp;amp;hl;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10250:1-10250:33"><code>&lt;</code> immediately ends an autolink.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10252:1-10254:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">www.commonmark.org/he&lt;lp</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10256:1-10258:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://www.commonmark.org/he"&gt;www.commonmark.org/he&lt;/a&gt;&amp;lt;lp&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10260:1-10263:36">An <a href="@">extended url autolink</a> will be recognised when one of the schemes
+<code>http://</code>, <code>https://</code>, or <code>ftp://</code>, followed by a [valid domain], then zero or
+more non-space non-<code>&lt;</code> characters according to
+[extended autolink path validation]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10265:1-10271:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">http://commonmark.org</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">(Visit https://encrypted.google.com/search?q=Markup+(business))</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">Anonymous FTP is available at ftp://foo.bar.baz.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10273:1-10277:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="http://commonmark.org"&gt;http://commonmark.org&lt;/a&gt;&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;(Visit &lt;a href="https://encrypted.google.com/search?q=Markup+(business)"&gt;https://encrypted.google.com/search?q=Markup+(business)&lt;/a&gt;)&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;Anonymous FTP is available at &lt;a href="ftp://foo.bar.baz"&gt;ftp://foo.bar.baz&lt;/a&gt;.&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10280:1-10282:20">An <a href="@">extended email autolink</a> will be recognised when an email address is
+recognised within any text node. Email addresses are recognised according to
+the following rules:</p>
+<ul data-sourcepos="10284:1-10290:0">
+<li data-sourcepos="10284:1-10284:75">One ore more characters which are alphanumeric, or <code>.</code>, <code>-</code>, <code>_</code>, or <code>+</code>.</li>
+<li data-sourcepos="10285:1-10285:16">An <code>@</code> symbol.</li>
+<li data-sourcepos="10286:1-10290:0">One or more characters which are alphanumeric, or <code>-</code> or <code>_</code>,
+separated by periods (<code>.</code>).
+There must be at least one period.
+The last character must not be one of <code>-</code> or <code>_</code>.</li>
+</ul>
+<p data-sourcepos="10291:1-10291:71">The scheme <code>mailto:</code> will automatically be added to the generated link:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10293:1-10295:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo@bar.baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10297:1-10299:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="mailto:foo@bar.baz"&gt;foo@bar.baz&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10301:1-10301:44"><code>+</code> can occur before the <code>@</code>, but not after.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10303:1-10305:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">hello@mail+xyz.example isn't valid, but hello+xyz@mail.example is.</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10307:1-10309:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;hello@mail+xyz.example isn't valid, but &lt;a href="mailto:hello+xyz@mail.example"&gt;hello+xyz@mail.example&lt;/a&gt; is.&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10311:1-10313:12"><code>.</code>, <code>-</code>, and <code>_</code> can occur on both sides of the <code>@</code>, but only <code>.</code> may occur at
+the end of the email address, in which case it will not be considered part of
+the address:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10315:1-10323:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">a.b-c_d@a.b</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">a.b-c_d@a.b.</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">a.b-c_d@a.b-</span>
+<span id="LC6" class="line" lang="plaintext"></span>
+<span id="LC7" class="line" lang="plaintext">a.b-c_d@a.b_</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10325:1-10330:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="mailto:a.b-c_d@a.b"&gt;a.b-c_d@a.b&lt;/a&gt;&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;&lt;a href="mailto:a.b-c_d@a.b"&gt;a.b-c_d@a.b&lt;/a&gt;.&lt;/p&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;a.b-c_d@a.b-&lt;/p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;p&gt;a.b-c_d@a.b_&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+</div>
+<h2 data-sourcepos="10334:1-10334:11" dir="auto">
+<a id="user-content-raw-html" class="anchor" href="#raw-html" aria-hidden="true"></a>Raw HTML</h2>
+<p data-sourcepos="10336:1-10339:57" dir="auto">Text between <code>&lt;</code> and <code>&gt;</code> that looks like an HTML tag is parsed as a
+raw HTML tag and will be rendered in HTML without escaping.
+Tag and attribute names are not limited to current HTML tags,
+so custom tags (and even, say, DocBook tags) may be used.</p>
+<p data-sourcepos="10341:1-10341:29" dir="auto">Here is the grammar for tags:</p>
+<p data-sourcepos="10343:1-10345:14" dir="auto">A <a href="@">tag name</a> consists of an ASCII letter
+followed by zero or more ASCII letters, digits, or
+hyphens (<code>-</code>).</p>
+<p data-sourcepos="10347:1-10349:32" dir="auto">An <a href="@">attribute</a> consists of [whitespace],
+an [attribute name], and an optional
+[attribute value specification].</p>
+<p data-sourcepos="10351:1-10354:52" dir="auto">An <a href="@">attribute name</a>
+consists of an ASCII letter, <code>_</code>, or <code>:</code>, followed by zero or more ASCII
+letters, digits, <code>_</code>, <code>.</code>, <code>:</code>, or <code>-</code>. (Note: This is the XML
+specification restricted to ASCII. HTML5 is laxer.)</p>
+<p data-sourcepos="10356:1-10359:7" dir="auto">An <a href="@">attribute value specification</a>
+consists of optional [whitespace],
+a <code>=</code> character, optional [whitespace], and an [attribute
+value].</p>
+<p data-sourcepos="10361:1-10363:72" dir="auto">An <a href="@">attribute value</a>
+consists of an [unquoted attribute value],
+a [single-quoted attribute value], or a [double-quoted attribute value].</p>
+<p data-sourcepos="10365:1-10367:60" dir="auto">An <a href="@">unquoted attribute value</a>
+is a nonempty string of characters not
+including [whitespace], <code>"</code>, <code>'</code>, <code>=</code>, <code>&lt;</code>, <code>&gt;</code>, or <code>`</code>.</p>
+<p data-sourcepos="10369:1-10371:46" dir="auto">A <a href="@">single-quoted attribute value</a>
+consists of <code>'</code>, zero or more
+characters not including <code>'</code>, and a final <code>'</code>.</p>
+<p data-sourcepos="10373:1-10375:46" dir="auto">A <a href="@">double-quoted attribute value</a>
+consists of <code>"</code>, zero or more
+characters not including <code>"</code>, and a final <code>"</code>.</p>
+<p data-sourcepos="10377:1-10379:31" dir="auto">An <a href="@">open tag</a> consists of a <code>&lt;</code> character, a [tag name],
+zero or more [attributes], optional [whitespace], an optional <code>/</code>
+character, and a <code>&gt;</code> character.</p>
+<p data-sourcepos="10381:1-10382:57" dir="auto">A <a href="@">closing tag</a> consists of the string <code>&lt;/</code>, a
+[tag name], optional [whitespace], and the character <code>&gt;</code>.</p>
+<p data-sourcepos="10384:1-10387:63" dir="auto">An <a href="@">HTML comment</a> consists of <code>&lt;!--</code> + <em>text</em> + <code>--&gt;</code>,
+where <em>text</em> does not start with <code>&gt;</code> or <code>-&gt;</code>, does not end with <code>-</code>,
+and does not contain <code>--</code>. (See the
+<a href="http://www.w3.org/TR/html5/syntax.html#comments" rel="nofollow noreferrer noopener" target="_blank">HTML5 spec</a>.)</p>
+<p data-sourcepos="10389:1-10392:5" dir="auto">A <a href="@">processing instruction</a>
+consists of the string <code>&lt;?</code>, a string
+of characters not including the string <code>?&gt;</code>, and the string
+<code>?&gt;</code>.</p>
+<p data-sourcepos="10394:1-10397:37" dir="auto">A <a href="@">declaration</a> consists of the
+string <code>&lt;!</code>, a name consisting of one or more uppercase ASCII letters,
+[whitespace], a string of characters not including the
+character <code>&gt;</code>, and the character <code>&gt;</code>.</p>
+<p data-sourcepos="10399:1-10401:28" dir="auto">A <a href="@">CDATA section</a> consists of
+the string <code>&lt;![CDATA[</code>, a string of characters not including the string
+<code>]]&gt;</code>, and the string <code>]]&gt;</code>.</p>
+<p data-sourcepos="10403:1-10405:21" dir="auto">An <a href="@">HTML tag</a> consists of an [open tag], a [closing tag],
+an [HTML comment], a [processing instruction], a [declaration],
+or a [CDATA section].</p>
+<p data-sourcepos="10407:1-10407:31" dir="auto">Here are some simple open tags:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10409:1-10411:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a&gt;&lt;bab&gt;&lt;c2c&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10413:1-10415:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a&gt;&lt;bab&gt;&lt;c2c&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10418:1-10418:15" dir="auto">Empty elements:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10420:1-10422:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a/&gt;&lt;b2/&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10424:1-10426:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a/&gt;&lt;b2/&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10429:1-10429:24" dir="auto">[Whitespace] is allowed:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10431:1-10434:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a /&gt;&lt;b2</span>
+<span id="LC2" class="line" lang="plaintext">data="foo" &gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10436:1-10439:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a /&gt;&lt;b2</span>
+<span id="LC2" class="line" lang="plaintext">data="foo" &gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10442:1-10442:16" dir="auto">With attributes:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10444:1-10447:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a foo="bar" bam = 'baz &lt;em&gt;"&lt;/em&gt;'</span>
+<span id="LC2" class="line" lang="plaintext">_boolean zoop:33=zoop:33 /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10449:1-10452:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a foo="bar" bam = 'baz &lt;em&gt;"&lt;/em&gt;'</span>
+<span id="LC2" class="line" lang="plaintext">_boolean zoop:33=zoop:33 /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10455:1-10455:29" dir="auto">Custom tag names can be used:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10457:1-10459:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo &lt;responsive-image src="foo.jpg" /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10461:1-10463:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo &lt;responsive-image src="foo.jpg" /&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10466:1-10466:38" dir="auto">Illegal tag names, not parsed as HTML:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10468:1-10470:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;33&gt; &lt;__&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10472:1-10474:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;lt;33&amp;gt; &amp;lt;__&amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10477:1-10477:24" dir="auto">Illegal attribute names:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10479:1-10481:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a h*#ref="hi"&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10483:1-10485:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;lt;a h*#ref=&amp;quot;hi&amp;quot;&amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10488:1-10488:25" dir="auto">Illegal attribute values:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10490:1-10492:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="hi'&gt; &lt;a href=hi'&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10494:1-10496:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;lt;a href=&amp;quot;hi'&amp;gt; &amp;lt;a href=hi'&amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10499:1-10499:21" dir="auto">Illegal [whitespace]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10501:1-10506:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt; a&gt;&lt;</span>
+<span id="LC2" class="line" lang="plaintext">foo&gt;&lt;bar/ &gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;foo bar=baz</span>
+<span id="LC4" class="line" lang="plaintext">bim!bop /&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10508:1-10513:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;lt; a&amp;gt;&amp;lt;</span>
+<span id="LC2" class="line" lang="plaintext">foo&amp;gt;&amp;lt;bar/ &amp;gt;</span>
+<span id="LC3" class="line" lang="plaintext">&amp;lt;foo bar=baz</span>
+<span id="LC4" class="line" lang="plaintext">bim!bop /&amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10516:1-10516:21" dir="auto">Missing [whitespace]:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10518:1-10520:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href='bar'title=title&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10522:1-10524:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;lt;a href='bar'title=title&amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10527:1-10527:13" dir="auto">Closing tags:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10529:1-10531:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;/a&gt;&lt;/foo &gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10533:1-10535:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;/a&gt;&lt;/foo &gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10538:1-10538:34" dir="auto">Illegal attributes in closing tag:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10540:1-10542:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;/a href="foo"&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10544:1-10546:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;lt;/a href=&amp;quot;foo&amp;quot;&amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10549:1-10549:9" dir="auto">Comments:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10551:1-10554:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;!-- this is a</span>
+<span id="LC2" class="line" lang="plaintext">comment - with hyphen --&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10556:1-10559:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &lt;!-- this is a</span>
+<span id="LC2" class="line" lang="plaintext">comment - with hyphen --&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10562:1-10564:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;!-- not a comment -- two hyphens --&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10566:1-10568:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &amp;lt;!-- not a comment -- two hyphens --&amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10571:1-10571:13" dir="auto">Not comments:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10573:1-10577:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;!--&gt; foo --&gt;</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">foo &lt;!-- foo---&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10579:1-10582:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &amp;lt;!--&amp;gt; foo --&amp;gt;&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;foo &amp;lt;!-- foo---&amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10585:1-10585:24" dir="auto">Processing instructions:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10587:1-10589:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;?php echo $a; ?&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10591:1-10593:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &lt;?php echo $a; ?&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10596:1-10596:13" dir="auto">Declarations:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10598:1-10600:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;!ELEMENT br EMPTY&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10602:1-10604:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &lt;!ELEMENT br EMPTY&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10607:1-10607:15" dir="auto">CDATA sections:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10609:1-10611:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;![CDATA[&gt;&amp;&lt;]]&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10613:1-10615:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &lt;![CDATA[&gt;&amp;&lt;]]&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10618:1-10619:11" dir="auto">Entity and numeric character references are preserved in HTML
+attributes:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10621:1-10623:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;a href="&amp;ouml;"&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10625:1-10627:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &lt;a href="&amp;ouml;"&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10630:1-10630:49" dir="auto">Backslash escapes do not work in HTML attributes:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10632:1-10634:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo &lt;a href="\*"&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10636:1-10638:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo &lt;a href="\*"&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10641:1-10643:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="\""&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10645:1-10647:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&amp;lt;a href=&amp;quot;&amp;quot;&amp;quot;&amp;gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div>
+<h2 data-sourcepos="10652:1-10652:34">
+<a id="user-content-disallowed-raw-html-extension" class="anchor" href="#disallowed-raw-html-extension" aria-hidden="true"></a>Disallowed Raw HTML (extension)</h2>
+<p data-sourcepos="10654:1-10655:36">GFM enables the <code>tagfilter</code> extension, where the following HTML tags will be
+filtered when rendering HTML output:</p>
+<ul data-sourcepos="10657:1-10666:0">
+<li data-sourcepos="10657:1-10657:11"><code>&lt;title&gt;</code></li>
+<li data-sourcepos="10658:1-10658:14"><code>&lt;textarea&gt;</code></li>
+<li data-sourcepos="10659:1-10659:11"><code>&lt;style&gt;</code></li>
+<li data-sourcepos="10660:1-10660:9"><code>&lt;xmp&gt;</code></li>
+<li data-sourcepos="10661:1-10661:12"><code>&lt;iframe&gt;</code></li>
+<li data-sourcepos="10662:1-10662:13"><code>&lt;noembed&gt;</code></li>
+<li data-sourcepos="10663:1-10663:14"><code>&lt;noframes&gt;</code></li>
+<li data-sourcepos="10664:1-10664:12"><code>&lt;script&gt;</code></li>
+<li data-sourcepos="10665:1-10666:0"><code>&lt;plaintext&gt;</code></li>
+</ul>
+<p data-sourcepos="10667:1-10670:71">Filtering is done by replacing the leading <code>&lt;</code> with the entity <code>&amp;lt;</code>. These
+tags are chosen in particular as they change how HTML is interpreted in a way
+unique to them (i.e. nested HTML is interpreted differently), and this is
+usually undesireable in the context of other rendered Markdown content.</p>
+<p data-sourcepos="10672:1-10672:39">All other HTML tags are left untouched.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10674:1-10680:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;strong&gt; &lt;title&gt; &lt;style&gt; &lt;em&gt;</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC4" class="line" lang="plaintext"> &lt;xmp&gt; is disallowed. &lt;XMP&gt; is also disallowed.</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10682:1-10687:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt; &amp;lt;title&gt; &amp;lt;style&gt; &lt;em&gt;&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;blockquote&gt;</span>
+<span id="LC3" class="line" lang="plaintext"> &amp;lt;xmp&gt; is disallowed. &amp;lt;XMP&gt; is also disallowed.</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/blockquote&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+</div>
+<h2 data-sourcepos="10691:1-10691:19" dir="auto">
+<a id="user-content-hard-line-breaks" class="anchor" href="#hard-line-breaks" aria-hidden="true"></a>Hard line breaks</h2>
+<p data-sourcepos="10693:1-10696:27" dir="auto">A line break (not in a code span or HTML tag) that is preceded
+by two or more spaces and does not occur at the end of a block
+is parsed as a <a href="@">hard line break</a> (rendered
+in HTML as a <code>&lt;br /&gt;</code> tag):</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10698:1-10701:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo </span>
+<span id="LC2" class="line" lang="plaintext">baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10703:1-10706:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo&lt;br /&gt;</span>
+<span id="LC2" class="line" lang="plaintext">baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10709:1-10710:48" dir="auto">For a more visible alternative, a backslash before the
+[line ending] may be used instead of two spaces:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10712:1-10715:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo\</span>
+<span id="LC2" class="line" lang="plaintext">baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10717:1-10720:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo&lt;br /&gt;</span>
+<span id="LC2" class="line" lang="plaintext">baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10723:1-10723:33" dir="auto">More than two spaces can be used:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10725:1-10728:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo </span>
+<span id="LC2" class="line" lang="plaintext">baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10730:1-10733:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo&lt;br /&gt;</span>
+<span id="LC2" class="line" lang="plaintext">baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10736:1-10736:61" dir="auto">Leading spaces at the beginning of the next line are ignored:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10738:1-10741:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo </span>
+<span id="LC2" class="line" lang="plaintext"> bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10743:1-10746:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo&lt;br /&gt;</span>
+<span id="LC2" class="line" lang="plaintext">bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10749:1-10752:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo\</span>
+<span id="LC2" class="line" lang="plaintext"> bar</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10754:1-10757:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo&lt;br /&gt;</span>
+<span id="LC2" class="line" lang="plaintext">bar&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10760:1-10761:26" dir="auto">Line breaks can occur inside emphasis, links, and other constructs
+that allow inline content:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10763:1-10766:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo </span>
+<span id="LC2" class="line" lang="plaintext">bar*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10768:1-10771:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;br /&gt;</span>
+<span id="LC2" class="line" lang="plaintext">bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10774:1-10777:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">*foo\</span>
+<span id="LC2" class="line" lang="plaintext">bar*</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10779:1-10782:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;foo&lt;br /&gt;</span>
+<span id="LC2" class="line" lang="plaintext">bar&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10785:1-10785:42" dir="auto">Line breaks do not occur inside code spans</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10787:1-10790:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`code </span>
+<span id="LC2" class="line" lang="plaintext">span`</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10792:1-10794:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;code span&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10797:1-10800:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">`code\</span>
+<span id="LC2" class="line" lang="plaintext">span`</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10802:1-10804:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;code&gt;code\ span&lt;/code&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10807:1-10807:13" dir="auto">or HTML tags:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10809:1-10812:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="foo </span>
+<span id="LC2" class="line" lang="plaintext">bar"&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10814:1-10817:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo </span>
+<span id="LC2" class="line" lang="plaintext">bar"&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10820:1-10823:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;a href="foo\</span>
+<span id="LC2" class="line" lang="plaintext">bar"&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10825:1-10828:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="foo\</span>
+<span id="LC2" class="line" lang="plaintext">bar"&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10831:1-10833:20" dir="auto">Hard line breaks are for separating inline content within a block.
+Neither syntax for hard line breaks works at the end of a paragraph or
+other block element:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10835:1-10837:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo\</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10839:1-10841:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo\&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10844:1-10846:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo </span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10848:1-10850:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10853:1-10855:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">### foo\</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10857:1-10859:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h3&gt;foo\&lt;/h3&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10862:1-10864:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">### foo </span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10866:1-10868:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;h3&gt;foo&lt;/h3&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="10871:1-10871:19" dir="auto">
+<a id="user-content-soft-line-breaks" class="anchor" href="#soft-line-breaks" aria-hidden="true"></a>Soft line breaks</h2>
+<p data-sourcepos="10873:1-10877:62" dir="auto">A regular line break (not in a code span or HTML tag) that is not
+preceded by two or more spaces or a backslash is parsed as a
+<a href="@">softbreak</a>. (A softbreak may be rendered in HTML either as a
+[line ending] or as a space. The result will be the same in
+browsers. In the examples here, a [line ending] will be used.)</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10879:1-10882:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo</span>
+<span id="LC2" class="line" lang="plaintext">baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10884:1-10887:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo</span>
+<span id="LC2" class="line" lang="plaintext">baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10890:1-10891:8" dir="auto">Spaces at the end of the line and beginning of the next line are
+removed:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10893:1-10896:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">foo </span>
+<span id="LC2" class="line" lang="plaintext"> baz</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10898:1-10901:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;foo</span>
+<span id="LC2" class="line" lang="plaintext">baz&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10904:1-10905:25" dir="auto">A conforming parser may render a soft line break in HTML either as a
+line break or as a space.</p>
+<p data-sourcepos="10907:1-10908:20" dir="auto">A renderer may also provide an option to render soft line breaks
+as hard line breaks.</p>
+<h2 data-sourcepos="10910:1-10910:18" dir="auto">
+<a id="user-content-textual-content" class="anchor" href="#textual-content" aria-hidden="true"></a>Textual content</h2>
+<p data-sourcepos="10912:1-10913:35" dir="auto">Any characters not given an interpretation by the above rules will
+be parsed as plain textual content.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10915:1-10917:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">hello $.;'there</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10919:1-10921:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;hello $.;'there&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10924:1-10926:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Foo χÏῆν</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10928:1-10930:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Foo χÏῆν&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="10933:1-10933:39" dir="auto">Internal spaces are preserved verbatim:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10935:1-10937:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">Multiple spaces</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10939:1-10941:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;Multiple spaces&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h1 data-sourcepos="10944:1-10944:40" dir="auto">
+<a id="user-content-gitlab-official-specification-markdown" class="anchor" href="#gitlab-official-specification-markdown" aria-hidden="true"></a>GitLab Official Specification Markdown</h1>
+<p data-sourcepos="10946:1-10949:104" dir="auto">Currently, only some of the GitLab-specific markdown features are
+listed in this section. We may eventually add all
+GitLab-specific features currently listed as supported in the
+<a href="https://docs.gitlab.com/ee/user/markdown.html" rel="nofollow noreferrer noopener" target="_blank">user-facing documentation for GitLab Flavored Markdown</a>.</p>
+<p data-sourcepos="10951:1-10952:69" dir="auto">There is currently only this single top-level heading, but the
+examples may be split into multiple top-level headings in the future.</p>
+<h2 data-sourcepos="10954:1-10954:12" dir="auto">
+<a id="user-content-footnotes" class="anchor" href="#footnotes" aria-hidden="true"></a>Footnotes</h2>
+<p data-sourcepos="10956:1-10957:143" dir="auto">See
+<a href="https://docs.gitlab.com/ee/user/markdown.html#footnotes" rel="nofollow noreferrer noopener" target="_blank">the footnotes section of the user-facing documentation for GitLab Flavored Markdown</a>.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10959:1-10963:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">footnote reference tag [^fortytwo]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[^fortytwo]: footnote text</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="10965:1-10985:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">footnote reference tag</span>
+<span id="LC3" class="line" lang="plaintext">&lt;sup&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref&gt;</span>
+<span id="LC5" class="line" lang="plaintext">1</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/a&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/sup&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/p&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;section data-footnotes&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;li id="fn-fortytwo-42"&gt;</span>
+<span id="LC12" class="line" lang="plaintext">&lt;p&gt;</span>
+<span id="LC13" class="line" lang="plaintext">footnote text</span>
+<span id="LC14" class="line" lang="plaintext">&lt;a href="#fnref-fortytwo-42" data-footnote-backref&gt;</span>
+<span id="LC15" class="line" lang="plaintext">&lt;/a&gt;</span>
+<span id="LC16" class="line" lang="plaintext">&lt;/p&gt;</span>
+<span id="LC17" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC18" class="line" lang="plaintext">&lt;/ol&gt;</span>
+<span id="LC19" class="line" lang="plaintext">&lt;/section&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="10987:1-10987:18" dir="auto">
+<a id="user-content-task-list-items" class="anchor" href="#task-list-items" aria-hidden="true"></a>Task list items</h2>
+<p data-sourcepos="10989:1-10990:117" dir="auto">See
+<a href="https://docs.gitlab.com/ee/user/markdown.html#task-lists" rel="nofollow noreferrer noopener" target="_blank">Task lists</a> in the GitLab Flavored Markdown documentation.</p>
+<p data-sourcepos="10992:1-10995:39" dir="auto">Task list items (checkboxes) are defined as a GitHub Flavored Markdown extension in a section above.
+GitLab extends the behavior of task list items to support additional features.
+Some of these features are in-progress, and should not yet be considered part of the official
+GitLab Flavored Markdown specification.</p>
+<p data-sourcepos="10997:1-10997:85" dir="auto">Some of the behavior of task list items is implemented as client-side JavaScript/CSS.</p>
+<p data-sourcepos="10999:1-10999:80" dir="auto">The following are some basic examples; more examples may be added in the future.</p>
+<p data-sourcepos="11001:1-11001:16" dir="auto">Incomplete task:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11003:1-11005:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [ ] incomplete</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11007:1-11015:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;task-button/&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;input type="checkbox" disabled/&gt;</span>
+<span id="LC5" class="line" lang="plaintext">incomplete</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11017:1-11017:15" dir="auto">Completed task:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11019:1-11021:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [x] completed</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11023:1-11031:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;task-button/&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;input type="checkbox" checked disabled/&gt;</span>
+<span id="LC5" class="line" lang="plaintext">completed</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11033:1-11033:18" dir="auto">Inapplicable task:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11035:1-11037:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [~] inapplicable</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11039:1-11049:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;task-button/&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;input type="checkbox" data-inapplicable disabled&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;s&gt;</span>
+<span id="LC6" class="line" lang="plaintext">inapplicable</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/s&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11051:1-11052:50" dir="auto">Inapplicable task in a "loose" list. Note that the <code>&lt;del&gt;</code> tag is not applied to the
+loose text; it has strikethrough applied with CSS.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11054:1-11058:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [~] inapplicable</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> text in loose list</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11060:1-11075:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;task-button/&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;input type="checkbox" data-inapplicable disabled&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;s&gt;</span>
+<span id="LC7" class="line" lang="plaintext">inapplicable</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/s&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/p&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;p&gt;</span>
+<span id="LC11" class="line" lang="plaintext">text in loose list</span>
+<span id="LC12" class="line" lang="plaintext">&lt;/p&gt;</span>
+<span id="LC13" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC14" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="11077:1-11077:15" dir="auto">
+<a id="user-content-front-matter" class="anchor" href="#front-matter" aria-hidden="true"></a>Front matter</h2>
+<p data-sourcepos="11079:1-11080:121" dir="auto">See
+<a href="https://docs.gitlab.com/ee/user/markdown.html#front-matter" rel="nofollow noreferrer noopener" target="_blank">Front matter</a> in the GitLab Flavored Markdown documentation.</p>
+<p data-sourcepos="11082:1-11083:95" dir="auto">Front matter is metadata included at the beginning of a Markdown document, preceding the content.
+This data can be used by static site generators like Jekyll, Hugo, and many other applications.</p>
+<p data-sourcepos="11085:1-11085:18" dir="auto">YAML front matter:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11087:1-11091:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">---</span>
+<span id="LC2" class="line" lang="plaintext">title: YAML front matter</span>
+<span id="LC3" class="line" lang="plaintext">---</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11093:1-11099:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;code&gt;</span>
+<span id="LC3" class="line" lang="plaintext">title: YAML front matter</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11101:1-11101:18" dir="auto">TOML front matter:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11103:1-11107:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">+++</span>
+<span id="LC2" class="line" lang="plaintext">title: TOML front matter</span>
+<span id="LC3" class="line" lang="plaintext">+++</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11109:1-11115:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;code&gt;</span>
+<span id="LC3" class="line" lang="plaintext">title: TOML front matter</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11117:1-11117:18" dir="auto">JSON front matter:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11119:1-11125:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">;;;</span>
+<span id="LC2" class="line" lang="plaintext">{</span>
+<span id="LC3" class="line" lang="plaintext"> "title": "JSON front matter"</span>
+<span id="LC4" class="line" lang="plaintext">}</span>
+<span id="LC5" class="line" lang="plaintext">;;;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11127:1-11135:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;code&gt;</span>
+<span id="LC3" class="line" lang="plaintext">{</span>
+<span id="LC4" class="line" lang="plaintext"> "title": "JSON front matter"</span>
+<span id="LC5" class="line" lang="plaintext">}</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11137:1-11137:66" dir="auto">Front matter blocks should be inserted at the top of the document:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11139:1-11145:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">text</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">---</span>
+<span id="LC4" class="line" lang="plaintext">title: YAML front matter</span>
+<span id="LC5" class="line" lang="plaintext">---</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11147:1-11151:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;text&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;hr&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;h2&gt;title: YAML front matter&lt;/h2&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11153:1-11153:74" dir="auto">Front matter block delimiters shouldn’t be preceded by space characters:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11155:1-11159:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ---</span>
+<span id="LC2" class="line" lang="plaintext">title: YAML front matter</span>
+<span id="LC3" class="line" lang="plaintext">---</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11161:1-11164:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;hr&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h2&gt;title: YAML front matter&lt;/h2&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="11166:1-11166:20" dir="auto">
+<a id="user-content-table-of-contents" class="anchor" href="#table-of-contents" aria-hidden="true"></a>Table of contents</h2>
+<p data-sourcepos="11168:1-11170:46" dir="auto">See
+<a href="https://docs.gitlab.com/ee/user/markdown.html#table-of-contents" rel="nofollow noreferrer noopener" target="_blank">table of contents</a>
+in the GitLab Flavored Markdown documentation.</p>
+<p data-sourcepos="11172:1-11173:58" dir="auto">A table of contents is an unordered list that links to subheadings in the document.
+Add either the <code>[[_TOC_]]</code> or </p><ul class="section-nav">
+<li>
+<a href="#preliminaries">Preliminaries</a><ul>
+<li><a href="#characters-and-lines">Characters and lines</a></li>
+<li><a href="#tabs">Tabs</a></li>
+<li><a href="#insecure-characters">Insecure characters</a></li>
+</ul>
+</li>
+<li>
+<a href="#blocks-and-inlines">Blocks and inlines</a><ul>
+<li><a href="#precedence">Precedence</a></li>
+<li><a href="#container-blocks-and-leaf-blocks">Container blocks and leaf blocks</a></li>
+</ul>
+</li>
+<li>
+<a href="#leaf-blocks">Leaf blocks</a><ul>
+<li><a href="#thematic-breaks">Thematic breaks</a></li>
+<li><a href="#atx-headings">ATX headings</a></li>
+<li><a href="#setext-headings">Setext headings</a></li>
+<li><a href="#indented-code-blocks">Indented code blocks</a></li>
+<li><a href="#fenced-code-blocks">Fenced code blocks</a></li>
+<li><a href="#html-blocks">HTML blocks</a></li>
+<li><a href="#link-reference-definitions">Link reference definitions</a></li>
+<li><a href="#paragraphs">Paragraphs</a></li>
+<li><a href="#blank-lines">Blank lines</a></li>
+<li><a href="#tables-extension">Tables (extension)</a></li>
+</ul>
+</li>
+<li>
+<a href="#container-blocks">Container blocks</a><ul>
+<li><a href="#block-quotes">Block quotes</a></li>
+<li>
+<a href="#list-items">List items</a><ul><li><a href="#motivation">Motivation</a></li></ul>
+</li>
+<li><a href="#task-list-items-extension">Task list items (extension)</a></li>
+<li><a href="#lists">Lists</a></li>
+</ul>
+</li>
+<li>
+<a href="#inlines">Inlines</a><ul>
+<li><a href="#backslash-escapes">Backslash escapes</a></li>
+<li><a href="#entity-and-numeric-character-references">Entity and numeric character references</a></li>
+<li><a href="#code-spans">Code spans</a></li>
+<li><a href="#emphasis-and-strong-emphasis">Emphasis and strong emphasis</a></li>
+<li><a href="#strikethrough-extension">Strikethrough (extension)</a></li>
+<li><a href="#links">Links</a></li>
+<li><a href="#images">Images</a></li>
+<li><a href="#autolinks">Autolinks</a></li>
+<li><a href="#autolinks-extension">Autolinks (extension)</a></li>
+<li><a href="#raw-html">Raw HTML</a></li>
+<li><a href="#disallowed-raw-html-extension">Disallowed Raw HTML (extension)</a></li>
+<li><a href="#hard-line-breaks">Hard line breaks</a></li>
+<li><a href="#soft-line-breaks">Soft line breaks</a></li>
+<li><a href="#textual-content">Textual content</a></li>
+</ul>
+</li>
+<li>
+<a href="#gitlab-official-specification-markdown">GitLab Official Specification Markdown</a><ul>
+<li><a href="#footnotes">Footnotes</a></li>
+<li><a href="#task-list-items">Task list items</a></li>
+<li><a href="#front-matter">Front matter</a></li>
+<li><a href="#table-of-contents">Table of contents</a></li>
+</ul>
+</li>
+<li>
+<a href="#gitlab-internal-extension-markdown">GitLab Internal Extension Markdown</a><ul>
+<li><a href="#audio">Audio</a></li>
+<li><a href="#video">Video</a></li>
+<li><a href="#markdown-preview-api-request-overrides">Markdown Preview API Request Overrides</a></li>
+</ul>
+</li>
+</ul> tag on its own line.
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11175:1-11181:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[TOC]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"># Heading 1</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">## Heading 2</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11183:1-11194:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;nav&gt;</span>
+<span id="LC2" class="line" lang="plaintext"> &lt;ul&gt;</span>
+<span id="LC3" class="line" lang="plaintext"> &lt;li&gt;&lt;a href="#heading-1"&gt;Heading 1&lt;/a&gt;&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext"> &lt;ul&gt;</span>
+<span id="LC5" class="line" lang="plaintext"> &lt;li&gt;&lt;a href="#heading-2"&gt;Heading 2&lt;/a&gt;&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext"> &lt;/ul&gt;</span>
+<span id="LC7" class="line" lang="plaintext"> &lt;/ul&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/nav&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;h1&gt;Heading 1&lt;/h1&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;h2&gt;Heading 2&lt;/h2&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11196:1-11202:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[[_TOC_]]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"># Heading 1</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">## Heading 2</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11204:1-11215:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;nav&gt;</span>
+<span id="LC2" class="line" lang="plaintext"> &lt;ul&gt;</span>
+<span id="LC3" class="line" lang="plaintext"> &lt;li&gt;&lt;a href="#heading-1"&gt;Heading 1&lt;/a&gt;&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext"> &lt;ul&gt;</span>
+<span id="LC5" class="line" lang="plaintext"> &lt;li&gt;&lt;a href="#heading-2"&gt;Heading 2&lt;/a&gt;&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext"> &lt;/ul&gt;</span>
+<span id="LC7" class="line" lang="plaintext"> &lt;/ul&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/nav&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;h1&gt;Heading 1&lt;/h1&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;h2&gt;Heading 2&lt;/h2&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11217:1-11218:5" dir="auto">A table of contents is a block element. It should preceded and followed by a blank
+line.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11220:1-11226:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[[_TOC_]]</span>
+<span id="LC2" class="line" lang="plaintext">text</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">text</span>
+<span id="LC5" class="line" lang="plaintext">[TOC]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11228:1-11231:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[[&lt;em&gt;TOC&lt;/em&gt;]]text&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;text[TOC]&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11233:1-11233:60" dir="auto">A table of contents can be indented with up to three spaces.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11235:1-11239:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> [[_TOC_]]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"># Heading 1</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11241:1-11248:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;nav&gt;</span>
+<span id="LC2" class="line" lang="plaintext"> &lt;ul&gt;</span>
+<span id="LC3" class="line" lang="plaintext"> &lt;li&gt;&lt;a href="#heading-1"&gt;Heading 1&lt;/a&gt;&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext"> &lt;/ul&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/nav&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;h1&gt;Heading 1&lt;/h1&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h1 data-sourcepos="11250:1-11250:36" dir="auto">
+<a id="user-content-gitlab-internal-extension-markdown" class="anchor" href="#gitlab-internal-extension-markdown" aria-hidden="true"></a>GitLab Internal Extension Markdown</h1>
+<h2 data-sourcepos="11252:1-11252:8" dir="auto">
+<a id="user-content-audio" class="anchor" href="#audio" aria-hidden="true"></a>Audio</h2>
+<p data-sourcepos="11254:1-11255:107" dir="auto">See
+<a href="https://docs.gitlab.com/ee/user/markdown.html#audio" rel="nofollow noreferrer noopener" target="_blank">audio</a> in the GitLab Flavored Markdown documentation.</p>
+<p data-sourcepos="11257:1-11259:63" dir="auto">GLFM renders image elements as an audio player as long as the resource’s file extension is
+one of the following supported audio extensions <code>.mp3</code>, <code>.oga</code>, <code>.ogg</code>, <code>.spx</code>, and <code>.wav</code>.
+Audio ignore the alternative text part of an image declaration.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11261:1-11263:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![audio](audio.oga "audio title")</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11265:1-11267:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;audio src="audio.oga" title="audio title"&gt;&lt;/audio&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11269:1-11269:41" dir="auto">Reference definitions work audio as well:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11271:1-11275:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[audio]: audio.oga "audio title"</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">![audio][audio]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11277:1-11279:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;audio src="audio.oga" title="audio title"&gt;&lt;/audio&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="11281:1-11281:8" dir="auto">
+<a id="user-content-video" class="anchor" href="#video" aria-hidden="true"></a>Video</h2>
+<p data-sourcepos="11283:1-11284:109" dir="auto">See
+<a href="https://docs.gitlab.com/ee/user/markdown.html#videos" rel="nofollow noreferrer noopener" target="_blank">videos</a> in the GitLab Flavored Markdown documentation.</p>
+<p data-sourcepos="11286:1-11288:64" dir="auto">GLFM renders image elements as a video player as long as the resource’s file extension is
+one of the following supported video extensions <code>.mp4</code>, <code>.m4v</code>, <code>.mov</code>, <code>.webm</code>, and <code>.ogv</code>.
+Videos ignore the alternative text part of an image declaration.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11291:1-11293:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">![video](video.m4v "video title")</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11295:1-11297:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;video src="video.m4v" title="video title"&gt;&lt;/video&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11299:1-11299:41" dir="auto">Reference definitions work video as well:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11301:1-11305:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[video]: video.mov "video title"</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">![video][video]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11307:1-11309:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;video src="video.mov" title="video title"&gt;&lt;/video&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="11311:1-11311:41" dir="auto">
+<a id="user-content-markdown-preview-api-request-overrides" class="anchor" href="#markdown-preview-api-request-overrides" aria-hidden="true"></a>Markdown Preview API Request Overrides</h2>
+<p data-sourcepos="11313:1-11315:42" dir="auto">This section contains examples of all controllers which use <code>PreviewMarkdown</code> module
+and use different <code>markdown_context_params</code>. They exercise the various <code>preview_markdown</code>
+endpoints via <code>glfm_example_metadata.yml</code>.</p>
+<p data-sourcepos="11318:1-11318:75" dir="auto"><code>preview_markdown</code> exercising <code>groups</code> API endpoint and <code>UploadLinkFilter</code>:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11320:1-11322:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[groups-test-file](/uploads/groups-test-file)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11324:1-11326:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="groups-test-file"&gt;groups-test-file&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11328:1-11328:81" dir="auto"><code>preview_markdown</code> exercising <code>projects</code> API endpoint and <code>RepositoryLinkFilter</code>:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11330:1-11332:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[projects-test-file](projects-test-file)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11334:1-11336:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="projects-test-file"&gt;projects-test-file&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11338:1-11338:83" dir="auto"><code>preview_markdown</code> exercising <code>projects</code> API endpoint and <code>SnippetReferenceFilter</code>:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11340:1-11342:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This project snippet ID reference IS filtered: $88888</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11344:1-11346:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;This project snippet ID reference IS filtered: $88888&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11348:1-11351:50" dir="auto"><code>preview_markdown</code> exercising personal (non-project) <code>snippets</code> API endpoint. This is
+only used by the comment field on personal snippets. It has no unique custom markdown
+extension behavior, and specifically does not render snippet references via
+<code>SnippetReferenceFilter</code>, even if the ID is valid.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11353:1-11355:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This personal snippet ID reference is not filtered: $99999</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11357:1-11359:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;This personal snippet ID reference is not filtered: $99999&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11361:1-11361:80" dir="auto"><code>preview_markdown</code> exercising project <code>wikis</code> API endpoint and <code>WikiLinkFilter</code>:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11363:1-11365:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[project-wikis-test-file](project-wikis-test-file)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11367:1-11369:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="project-wikis-test-file"&gt;project-wikis-test-file&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="11371:1-11372:63" dir="auto"><code>preview_markdown</code> exercising group <code>wikis</code> API endpoint and <code>WikiLinkFilter</code>. This example
+also requires an EE license enabling the <code>group_wikis</code> feature:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11374:1-11376:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[group-wikis-test-file](group-wikis-test-file)</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="11378:1-11380:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;a href="group-wikis-test-file"&gt;group-wikis-test-file&lt;/a&gt;&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
diff --git a/glfm_specification/output_example_snapshots/snapshot_spec.md b/glfm_specification/output_example_snapshots/snapshot_spec.md
new file mode 100644
index 00000000000..ed96c36a58a
--- /dev/null
+++ b/glfm_specification/output_example_snapshots/snapshot_spec.md
@@ -0,0 +1,9986 @@
+---
+title: GitLab Flavored Markdown (GLFM) Spec
+version: alpha
+...
+# Preliminaries
+
+## Characters and lines
+
+Any sequence of [characters] is a valid CommonMark
+document.
+
+A [character](@) is a Unicode code point. Although some
+code points (for example, combining accents) do not correspond to
+characters in an intuitive sense, all code points count as characters
+for purposes of this spec.
+
+This spec does not specify an encoding; it thinks of lines as composed
+of [characters] rather than bytes. A conforming parser may be limited
+to a certain encoding.
+
+A [line](@) is a sequence of zero or more [characters]
+other than newline (`U+000A`) or carriage return (`U+000D`),
+followed by a [line ending] or by the end of file.
+
+A [line ending](@) is a newline (`U+000A`), a carriage return
+(`U+000D`) not followed by a newline, or a carriage return and a
+following newline.
+
+A line containing no characters, or a line containing only spaces
+(`U+0020`) or tabs (`U+0009`), is called a [blank line](@).
+
+The following definitions of character classes will be used in this spec:
+
+A [whitespace character](@) is a space
+(`U+0020`), tab (`U+0009`), newline (`U+000A`), line tabulation (`U+000B`),
+form feed (`U+000C`), or carriage return (`U+000D`).
+
+[Whitespace](@) is a sequence of one or more [whitespace
+characters].
+
+A [Unicode whitespace character](@) is
+any code point in the Unicode `Zs` general category, or a tab (`U+0009`),
+carriage return (`U+000D`), newline (`U+000A`), or form feed
+(`U+000C`).
+
+[Unicode whitespace](@) is a sequence of one
+or more [Unicode whitespace characters].
+
+A [space](@) is `U+0020`.
+
+A [non-whitespace character](@) is any character
+that is not a [whitespace character].
+
+An [ASCII punctuation character](@)
+is `!`, `"`, `#`, `$`, `%`, `&`, `'`, `(`, `)`,
+`*`, `+`, `,`, `-`, `.`, `/` (U+0021–2F),
+`:`, `;`, `<`, `=`, `>`, `?`, `@` (U+003A–0040),
+`[`, `\`, `]`, `^`, `_`, `` ` `` (U+005B–0060),
+`{`, `|`, `}`, or `~` (U+007B–007E).
+
+A [punctuation character](@) is an [ASCII
+punctuation character] or anything in
+the general Unicode categories `Pc`, `Pd`, `Pe`, `Pf`, `Pi`, `Po`, or `Ps`.
+
+## Tabs
+
+Tabs in lines are not expanded to [spaces]. However,
+in contexts where whitespace helps to define block structure,
+tabs behave as if they were replaced by spaces with a tab stop
+of 4 characters.
+
+Thus, for example, a tab can be used instead of four spaces
+in an indented code block. (Note, however, that internal
+tabs are passed through as literal tabs, not expanded to
+spaces.)
+
+```````````````````````````````` example
+→foo→baz→→bim
+.
+<pre><code>foo→baz→→bim
+</code></pre>
+````````````````````````````````
+
+```````````````````````````````` example
+ →foo→baz→→bim
+.
+<pre><code>foo→baz→→bim
+</code></pre>
+````````````````````````````````
+
+```````````````````````````````` example
+ a→a
+ á½â†’a
+.
+<pre><code>a→a
+á½â†’a
+</code></pre>
+````````````````````````````````
+
+In the following example, a continuation paragraph of a list
+item is indented with a tab; this has exactly the same effect
+as indentation with four spaces would:
+
+```````````````````````````````` example
+ - foo
+
+→bar
+.
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+````````````````````````````````
+
+```````````````````````````````` example
+- foo
+
+→→bar
+.
+<ul>
+<li>
+<p>foo</p>
+<pre><code> bar
+</code></pre>
+</li>
+</ul>
+````````````````````````````````
+
+Normally the `>` that begins a block quote may be followed
+optionally by a space, which is not considered part of the
+content. In the following case `>` is followed by a tab,
+which is treated as if it were expanded into three spaces.
+Since one of these spaces is considered part of the
+delimiter, `foo` is considered to be indented six spaces
+inside the block quote context, so we get an indented
+code block starting with two spaces.
+
+```````````````````````````````` example
+>→→foo
+.
+<blockquote>
+<pre><code> foo
+</code></pre>
+</blockquote>
+````````````````````````````````
+
+```````````````````````````````` example
+-→→foo
+.
+<ul>
+<li>
+<pre><code> foo
+</code></pre>
+</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ foo
+→bar
+.
+<pre><code>foo
+bar
+</code></pre>
+````````````````````````````````
+
+```````````````````````````````` example
+ - foo
+ - bar
+→ - baz
+.
+<ul>
+<li>foo
+<ul>
+<li>bar
+<ul>
+<li>baz</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+````````````````````````````````
+
+```````````````````````````````` example
+#→Foo
+.
+<h1>Foo</h1>
+````````````````````````````````
+
+```````````````````````````````` example
+*→*→*→
+.
+<hr />
+````````````````````````````````
+
+
+## Insecure characters
+
+For security reasons, the Unicode character `U+0000` must be replaced
+with the REPLACEMENT CHARACTER (`U+FFFD`).
+
+# Blocks and inlines
+
+We can think of a document as a sequence of
+[blocks](@)---structural elements like paragraphs, block
+quotations, lists, headings, rules, and code blocks. Some blocks (like
+block quotes and list items) contain other blocks; others (like
+headings and paragraphs) contain [inline](@) content---text,
+links, emphasized text, images, code spans, and so on.
+
+## Precedence
+
+Indicators of block structure always take precedence over indicators
+of inline structure. So, for example, the following is a list with
+two items, not a list with one item containing a code span:
+
+```````````````````````````````` example
+- `one
+- two`
+.
+<ul>
+<li>`one</li>
+<li>two`</li>
+</ul>
+````````````````````````````````
+
+
+This means that parsing can proceed in two steps: first, the block
+structure of the document can be discerned; second, text lines inside
+paragraphs, headings, and other block constructs can be parsed for inline
+structure. The second step requires information about link reference
+definitions that will be available only at the end of the first
+step. Note that the first step requires processing lines in sequence,
+but the second can be parallelized, since the inline parsing of
+one block element does not affect the inline parsing of any other.
+
+## Container blocks and leaf blocks
+
+We can divide blocks into two types:
+[container blocks](@),
+which can contain other blocks, and [leaf blocks](@),
+which cannot.
+
+# Leaf blocks
+
+This section describes the different kinds of leaf block that make up a
+Markdown document.
+
+## Thematic breaks
+
+A line consisting of 0-3 spaces of indentation, followed by a sequence
+of three or more matching `-`, `_`, or `*` characters, each followed
+optionally by any number of spaces or tabs, forms a
+[thematic break](@).
+
+```````````````````````````````` example
+***
+---
+___
+.
+<hr />
+<hr />
+<hr />
+````````````````````````````````
+
+
+Wrong characters:
+
+```````````````````````````````` example
++++
+.
+<p>+++</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+===
+.
+<p>===</p>
+````````````````````````````````
+
+
+Not enough characters:
+
+```````````````````````````````` example
+--
+**
+__
+.
+<p>--
+**
+__</p>
+````````````````````````````````
+
+
+One to three spaces indent are allowed:
+
+```````````````````````````````` example
+ ***
+ ***
+ ***
+.
+<hr />
+<hr />
+<hr />
+````````````````````````````````
+
+
+Four spaces is too many:
+
+```````````````````````````````` example
+ ***
+.
+<pre><code>***
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+Foo
+ ***
+.
+<p>Foo
+***</p>
+````````````````````````````````
+
+
+More than three characters may be used:
+
+```````````````````````````````` example
+_____________________________________
+.
+<hr />
+````````````````````````````````
+
+
+Spaces are allowed between the characters:
+
+```````````````````````````````` example
+ - - -
+.
+<hr />
+````````````````````````````````
+
+
+```````````````````````````````` example
+ ** * ** * ** * **
+.
+<hr />
+````````````````````````````````
+
+
+```````````````````````````````` example
+- - - -
+.
+<hr />
+````````````````````````````````
+
+
+Spaces are allowed at the end:
+
+```````````````````````````````` example
+- - - -
+.
+<hr />
+````````````````````````````````
+
+
+However, no other characters may occur in the line:
+
+```````````````````````````````` example
+_ _ _ _ a
+
+a------
+
+---a---
+.
+<p>_ _ _ _ a</p>
+<p>a------</p>
+<p>---a---</p>
+````````````````````````````````
+
+
+It is required that all of the [non-whitespace characters] be the same.
+So, this is not a thematic break:
+
+```````````````````````````````` example
+ *-*
+.
+<p><em>-</em></p>
+````````````````````````````````
+
+
+Thematic breaks do not need blank lines before or after:
+
+```````````````````````````````` example
+- foo
+***
+- bar
+.
+<ul>
+<li>foo</li>
+</ul>
+<hr />
+<ul>
+<li>bar</li>
+</ul>
+````````````````````````````````
+
+
+Thematic breaks can interrupt a paragraph:
+
+```````````````````````````````` example
+Foo
+***
+bar
+.
+<p>Foo</p>
+<hr />
+<p>bar</p>
+````````````````````````````````
+
+
+If a line of dashes that meets the above conditions for being a
+thematic break could also be interpreted as the underline of a [setext
+heading], the interpretation as a
+[setext heading] takes precedence. Thus, for example,
+this is a setext heading, not a paragraph followed by a thematic break:
+
+```````````````````````````````` example
+Foo
+---
+bar
+.
+<h2>Foo</h2>
+<p>bar</p>
+````````````````````````````````
+
+
+When both a thematic break and a list item are possible
+interpretations of a line, the thematic break takes precedence:
+
+```````````````````````````````` example
+* Foo
+* * *
+* Bar
+.
+<ul>
+<li>Foo</li>
+</ul>
+<hr />
+<ul>
+<li>Bar</li>
+</ul>
+````````````````````````````````
+
+
+If you want a thematic break in a list item, use a different bullet:
+
+```````````````````````````````` example
+- Foo
+- * * *
+.
+<ul>
+<li>Foo</li>
+<li>
+<hr />
+</li>
+</ul>
+````````````````````````````````
+
+
+## ATX headings
+
+An [ATX heading](@)
+consists of a string of characters, parsed as inline content, between an
+opening sequence of 1--6 unescaped `#` characters and an optional
+closing sequence of any number of unescaped `#` characters.
+The opening sequence of `#` characters must be followed by a
+[space] or by the end of line. The optional closing sequence of `#`s must be
+preceded by a [space] and may be followed by spaces only. The opening
+`#` character may be indented 0-3 spaces. The raw contents of the
+heading are stripped of leading and trailing spaces before being parsed
+as inline content. The heading level is equal to the number of `#`
+characters in the opening sequence.
+
+Simple headings:
+
+```````````````````````````````` example
+# foo
+## foo
+### foo
+#### foo
+##### foo
+###### foo
+.
+<h1>foo</h1>
+<h2>foo</h2>
+<h3>foo</h3>
+<h4>foo</h4>
+<h5>foo</h5>
+<h6>foo</h6>
+````````````````````````````````
+
+
+More than six `#` characters is not a heading:
+
+```````````````````````````````` example
+####### foo
+.
+<p>####### foo</p>
+````````````````````````````````
+
+
+At least one space is required between the `#` characters and the
+heading's contents, unless the heading is empty. Note that many
+implementations currently do not require the space. However, the
+space was required by the
+[original ATX implementation](http://www.aaronsw.com/2002/atx/atx.py),
+and it helps prevent things like the following from being parsed as
+headings:
+
+```````````````````````````````` example
+#5 bolt
+
+#hashtag
+.
+<p>#5 bolt</p>
+<p>#hashtag</p>
+````````````````````````````````
+
+
+This is not a heading, because the first `#` is escaped:
+
+```````````````````````````````` example
+\## foo
+.
+<p>## foo</p>
+````````````````````````````````
+
+
+Contents are parsed as inlines:
+
+```````````````````````````````` example
+# foo *bar* \*baz\*
+.
+<h1>foo <em>bar</em> *baz*</h1>
+````````````````````````````````
+
+
+Leading and trailing [whitespace] is ignored in parsing inline content:
+
+```````````````````````````````` example
+# foo
+.
+<h1>foo</h1>
+````````````````````````````````
+
+
+One to three spaces indentation are allowed:
+
+```````````````````````````````` example
+ ### foo
+ ## foo
+ # foo
+.
+<h3>foo</h3>
+<h2>foo</h2>
+<h1>foo</h1>
+````````````````````````````````
+
+
+Four spaces are too much:
+
+```````````````````````````````` example
+ # foo
+.
+<pre><code># foo
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo
+ # bar
+.
+<p>foo
+# bar</p>
+````````````````````````````````
+
+
+A closing sequence of `#` characters is optional:
+
+```````````````````````````````` example
+## foo ##
+ ### bar ###
+.
+<h2>foo</h2>
+<h3>bar</h3>
+````````````````````````````````
+
+
+It need not be the same length as the opening sequence:
+
+```````````````````````````````` example
+# foo ##################################
+##### foo ##
+.
+<h1>foo</h1>
+<h5>foo</h5>
+````````````````````````````````
+
+
+Spaces are allowed after the closing sequence:
+
+```````````````````````````````` example
+### foo ###
+.
+<h3>foo</h3>
+````````````````````````````````
+
+
+A sequence of `#` characters with anything but [spaces] following it
+is not a closing sequence, but counts as part of the contents of the
+heading:
+
+```````````````````````````````` example
+### foo ### b
+.
+<h3>foo ### b</h3>
+````````````````````````````````
+
+
+The closing sequence must be preceded by a space:
+
+```````````````````````````````` example
+# foo#
+.
+<h1>foo#</h1>
+````````````````````````````````
+
+
+Backslash-escaped `#` characters do not count as part
+of the closing sequence:
+
+```````````````````````````````` example
+### foo \###
+## foo #\##
+# foo \#
+.
+<h3>foo ###</h3>
+<h2>foo ###</h2>
+<h1>foo #</h1>
+````````````````````````````````
+
+
+ATX headings need not be separated from surrounding content by blank
+lines, and they can interrupt paragraphs:
+
+```````````````````````````````` example
+****
+## foo
+****
+.
+<hr />
+<h2>foo</h2>
+<hr />
+````````````````````````````````
+
+
+```````````````````````````````` example
+Foo bar
+# baz
+Bar foo
+.
+<p>Foo bar</p>
+<h1>baz</h1>
+<p>Bar foo</p>
+````````````````````````````````
+
+
+ATX headings can be empty:
+
+```````````````````````````````` example
+##
+#
+### ###
+.
+<h2></h2>
+<h1></h1>
+<h3></h3>
+````````````````````````````````
+
+
+## Setext headings
+
+A [setext heading](@) consists of one or more
+lines of text, each containing at least one [non-whitespace
+character], with no more than 3 spaces indentation, followed by
+a [setext heading underline]. The lines of text must be such
+that, were they not followed by the setext heading underline,
+they would be interpreted as a paragraph: they cannot be
+interpretable as a [code fence], [ATX heading][ATX headings],
+[block quote][block quotes], [thematic break][thematic breaks],
+[list item][list items], or [HTML block][HTML blocks].
+
+A [setext heading underline](@) is a sequence of
+`=` characters or a sequence of `-` characters, with no more than 3
+spaces indentation and any number of trailing spaces. If a line
+containing a single `-` can be interpreted as an
+empty [list items], it should be interpreted this way
+and not as a [setext heading underline].
+
+The heading is a level 1 heading if `=` characters are used in
+the [setext heading underline], and a level 2 heading if `-`
+characters are used. The contents of the heading are the result
+of parsing the preceding lines of text as CommonMark inline
+content.
+
+In general, a setext heading need not be preceded or followed by a
+blank line. However, it cannot interrupt a paragraph, so when a
+setext heading comes after a paragraph, a blank line is needed between
+them.
+
+Simple examples:
+
+```````````````````````````````` example
+Foo *bar*
+=========
+
+Foo *bar*
+---------
+.
+<h1>Foo <em>bar</em></h1>
+<h2>Foo <em>bar</em></h2>
+````````````````````````````````
+
+
+The content of the header may span more than one line:
+
+```````````````````````````````` example
+Foo *bar
+baz*
+====
+.
+<h1>Foo <em>bar
+baz</em></h1>
+````````````````````````````````
+
+The contents are the result of parsing the headings's raw
+content as inlines. The heading's raw content is formed by
+concatenating the lines and removing initial and final
+[whitespace].
+
+```````````````````````````````` example
+ Foo *bar
+baz*→
+====
+.
+<h1>Foo <em>bar
+baz</em></h1>
+````````````````````````````````
+
+
+The underlining can be any length:
+
+```````````````````````````````` example
+Foo
+-------------------------
+
+Foo
+=
+.
+<h2>Foo</h2>
+<h1>Foo</h1>
+````````````````````````````````
+
+
+The heading content can be indented up to three spaces, and need
+not line up with the underlining:
+
+```````````````````````````````` example
+ Foo
+---
+
+ Foo
+-----
+
+ Foo
+ ===
+.
+<h2>Foo</h2>
+<h2>Foo</h2>
+<h1>Foo</h1>
+````````````````````````````````
+
+
+Four spaces indent is too much:
+
+```````````````````````````````` example
+ Foo
+ ---
+
+ Foo
+---
+.
+<pre><code>Foo
+---
+
+Foo
+</code></pre>
+<hr />
+````````````````````````````````
+
+
+The setext heading underline can be indented up to three spaces, and
+may have trailing spaces:
+
+```````````````````````````````` example
+Foo
+ ----
+.
+<h2>Foo</h2>
+````````````````````````````````
+
+
+Four spaces is too much:
+
+```````````````````````````````` example
+Foo
+ ---
+.
+<p>Foo
+---</p>
+````````````````````````````````
+
+
+The setext heading underline cannot contain internal spaces:
+
+```````````````````````````````` example
+Foo
+= =
+
+Foo
+--- -
+.
+<p>Foo
+= =</p>
+<p>Foo</p>
+<hr />
+````````````````````````````````
+
+
+Trailing spaces in the content line do not cause a line break:
+
+```````````````````````````````` example
+Foo
+-----
+.
+<h2>Foo</h2>
+````````````````````````````````
+
+
+Nor does a backslash at the end:
+
+```````````````````````````````` example
+Foo\
+----
+.
+<h2>Foo\</h2>
+````````````````````````````````
+
+
+Since indicators of block structure take precedence over
+indicators of inline structure, the following are setext headings:
+
+```````````````````````````````` example
+`Foo
+----
+`
+
+<a title="a lot
+---
+of dashes"/>
+.
+<h2>`Foo</h2>
+<p>`</p>
+<h2>&lt;a title=&quot;a lot</h2>
+<p>of dashes&quot;/&gt;</p>
+````````````````````````````````
+
+
+The setext heading underline cannot be a [lazy continuation
+line] in a list item or block quote:
+
+```````````````````````````````` example
+> Foo
+---
+.
+<blockquote>
+<p>Foo</p>
+</blockquote>
+<hr />
+````````````````````````````````
+
+
+```````````````````````````````` example
+> foo
+bar
+===
+.
+<blockquote>
+<p>foo
+bar
+===</p>
+</blockquote>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- Foo
+---
+.
+<ul>
+<li>Foo</li>
+</ul>
+<hr />
+````````````````````````````````
+
+
+A blank line is needed between a paragraph and a following
+setext heading, since otherwise the paragraph becomes part
+of the heading's content:
+
+```````````````````````````````` example
+Foo
+Bar
+---
+.
+<h2>Foo
+Bar</h2>
+````````````````````````````````
+
+
+But in general a blank line is not required before or after
+setext headings:
+
+```````````````````````````````` example
+---
+Foo
+---
+Bar
+---
+Baz
+.
+<hr />
+<h2>Foo</h2>
+<h2>Bar</h2>
+<p>Baz</p>
+````````````````````````````````
+
+
+Setext headings cannot be empty:
+
+```````````````````````````````` example
+
+====
+.
+<p>====</p>
+````````````````````````````````
+
+
+Setext heading text lines must not be interpretable as block
+constructs other than paragraphs. So, the line of dashes
+in these examples gets interpreted as a thematic break:
+
+```````````````````````````````` example
+---
+---
+.
+<hr />
+<hr />
+````````````````````````````````
+
+
+```````````````````````````````` example
+- foo
+-----
+.
+<ul>
+<li>foo</li>
+</ul>
+<hr />
+````````````````````````````````
+
+
+```````````````````````````````` example
+ foo
+---
+.
+<pre><code>foo
+</code></pre>
+<hr />
+````````````````````````````````
+
+
+```````````````````````````````` example
+> foo
+-----
+.
+<blockquote>
+<p>foo</p>
+</blockquote>
+<hr />
+````````````````````````````````
+
+
+If you want a heading with `> foo` as its literal text, you can
+use backslash escapes:
+
+```````````````````````````````` example
+\> foo
+------
+.
+<h2>&gt; foo</h2>
+````````````````````````````````
+
+
+**Compatibility note:** Most existing Markdown implementations
+do not allow the text of setext headings to span multiple lines.
+But there is no consensus about how to interpret
+
+``` markdown
+Foo
+bar
+---
+baz
+```
+
+One can find four different interpretations:
+
+1. paragraph "Foo", heading "bar", paragraph "baz"
+2. paragraph "Foo bar", thematic break, paragraph "baz"
+3. paragraph "Foo bar --- baz"
+4. heading "Foo bar", paragraph "baz"
+
+We find interpretation 4 most natural, and interpretation 4
+increases the expressive power of CommonMark, by allowing
+multiline headings. Authors who want interpretation 1 can
+put a blank line after the first paragraph:
+
+```````````````````````````````` example
+Foo
+
+bar
+---
+baz
+.
+<p>Foo</p>
+<h2>bar</h2>
+<p>baz</p>
+````````````````````````````````
+
+
+Authors who want interpretation 2 can put blank lines around
+the thematic break,
+
+```````````````````````````````` example
+Foo
+bar
+
+---
+
+baz
+.
+<p>Foo
+bar</p>
+<hr />
+<p>baz</p>
+````````````````````````````````
+
+
+or use a thematic break that cannot count as a [setext heading
+underline], such as
+
+```````````````````````````````` example
+Foo
+bar
+* * *
+baz
+.
+<p>Foo
+bar</p>
+<hr />
+<p>baz</p>
+````````````````````````````````
+
+
+Authors who want interpretation 3 can use backslash escapes:
+
+```````````````````````````````` example
+Foo
+bar
+\---
+baz
+.
+<p>Foo
+bar
+---
+baz</p>
+````````````````````````````````
+
+
+## Indented code blocks
+
+An [indented code block](@) is composed of one or more
+[indented chunks] separated by blank lines.
+An [indented chunk](@) is a sequence of non-blank lines,
+each indented four or more spaces. The contents of the code block are
+the literal contents of the lines, including trailing
+[line endings], minus four spaces of indentation.
+An indented code block has no [info string].
+
+An indented code block cannot interrupt a paragraph, so there must be
+a blank line between a paragraph and a following indented code block.
+(A blank line is not needed, however, between a code block and a following
+paragraph.)
+
+```````````````````````````````` example
+ a simple
+ indented code block
+.
+<pre><code>a simple
+ indented code block
+</code></pre>
+````````````````````````````````
+
+
+If there is any ambiguity between an interpretation of indentation
+as a code block and as indicating that material belongs to a [list
+item][list items], the list item interpretation takes precedence:
+
+```````````````````````````````` example
+ - foo
+
+ bar
+.
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+1. foo
+
+ - bar
+.
+<ol>
+<li>
+<p>foo</p>
+<ul>
+<li>bar</li>
+</ul>
+</li>
+</ol>
+````````````````````````````````
+
+
+
+The contents of a code block are literal text, and do not get parsed
+as Markdown:
+
+```````````````````````````````` example
+ <a/>
+ *hi*
+
+ - one
+.
+<pre><code>&lt;a/&gt;
+*hi*
+
+- one
+</code></pre>
+````````````````````````````````
+
+
+Here we have three chunks separated by blank lines:
+
+```````````````````````````````` example
+ chunk1
+
+ chunk2
+
+
+
+ chunk3
+.
+<pre><code>chunk1
+
+chunk2
+
+
+
+chunk3
+</code></pre>
+````````````````````````````````
+
+
+Any initial spaces beyond four will be included in the content, even
+in interior blank lines:
+
+```````````````````````````````` example
+ chunk1
+
+ chunk2
+.
+<pre><code>chunk1
+
+ chunk2
+</code></pre>
+````````````````````````````````
+
+
+An indented code block cannot interrupt a paragraph. (This
+allows hanging indents and the like.)
+
+```````````````````````````````` example
+Foo
+ bar
+
+.
+<p>Foo
+bar</p>
+````````````````````````````````
+
+
+However, any non-blank line with fewer than four leading spaces ends
+the code block immediately. So a paragraph may occur immediately
+after indented code:
+
+```````````````````````````````` example
+ foo
+bar
+.
+<pre><code>foo
+</code></pre>
+<p>bar</p>
+````````````````````````````````
+
+
+And indented code can occur immediately before and after other kinds of
+blocks:
+
+```````````````````````````````` example
+# Heading
+ foo
+Heading
+------
+ foo
+----
+.
+<h1>Heading</h1>
+<pre><code>foo
+</code></pre>
+<h2>Heading</h2>
+<pre><code>foo
+</code></pre>
+<hr />
+````````````````````````````````
+
+
+The first line can be indented more than four spaces:
+
+```````````````````````````````` example
+ foo
+ bar
+.
+<pre><code> foo
+bar
+</code></pre>
+````````````````````````````````
+
+
+Blank lines preceding or following an indented code block
+are not included in it:
+
+```````````````````````````````` example
+
+
+ foo
+
+
+.
+<pre><code>foo
+</code></pre>
+````````````````````````````````
+
+
+Trailing spaces are included in the code block's content:
+
+```````````````````````````````` example
+ foo
+.
+<pre><code>foo
+</code></pre>
+````````````````````````````````
+
+
+
+## Fenced code blocks
+
+A [code fence](@) is a sequence
+of at least three consecutive backtick characters (`` ` ``) or
+tildes (`~`). (Tildes and backticks cannot be mixed.)
+A [fenced code block](@)
+begins with a code fence, indented no more than three spaces.
+
+The line with the opening code fence may optionally contain some text
+following the code fence; this is trimmed of leading and trailing
+whitespace and called the [info string](@). If the [info string] comes
+after a backtick fence, it may not contain any backtick
+characters. (The reason for this restriction is that otherwise
+some inline code would be incorrectly interpreted as the
+beginning of a fenced code block.)
+
+The content of the code block consists of all subsequent lines, until
+a closing [code fence] of the same type as the code block
+began with (backticks or tildes), and with at least as many backticks
+or tildes as the opening code fence. If the leading code fence is
+indented N spaces, then up to N spaces of indentation are removed from
+each line of the content (if present). (If a content line is not
+indented, it is preserved unchanged. If it is indented less than N
+spaces, all of the indentation is removed.)
+
+The closing code fence may be indented up to three spaces, and may be
+followed only by spaces, which are ignored. If the end of the
+containing block (or document) is reached and no closing code fence
+has been found, the code block contains all of the lines after the
+opening code fence until the end of the containing block (or
+document). (An alternative spec would require backtracking in the
+event that a closing code fence is not found. But this makes parsing
+much less efficient, and there seems to be no real down side to the
+behavior described here.)
+
+A fenced code block may interrupt a paragraph, and does not require
+a blank line either before or after.
+
+The content of a code fence is treated as literal text, not parsed
+as inlines. The first word of the [info string] is typically used to
+specify the language of the code sample, and rendered in the `class`
+attribute of the `code` tag. However, this spec does not mandate any
+particular treatment of the [info string].
+
+Here is a simple example with backticks:
+
+```````````````````````````````` example
+```
+<
+ >
+```
+.
+<pre><code>&lt;
+ &gt;
+</code></pre>
+````````````````````````````````
+
+
+With tildes:
+
+```````````````````````````````` example
+~~~
+<
+ >
+~~~
+.
+<pre><code>&lt;
+ &gt;
+</code></pre>
+````````````````````````````````
+
+Fewer than three backticks is not enough:
+
+```````````````````````````````` example
+``
+foo
+``
+.
+<p><code>foo</code></p>
+````````````````````````````````
+
+The closing code fence must use the same character as the opening
+fence:
+
+```````````````````````````````` example
+```
+aaa
+~~~
+```
+.
+<pre><code>aaa
+~~~
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+~~~
+aaa
+```
+~~~
+.
+<pre><code>aaa
+```
+</code></pre>
+````````````````````````````````
+
+
+The closing code fence must be at least as long as the opening fence:
+
+```````````````````````````````` example
+````
+aaa
+```
+``````
+.
+<pre><code>aaa
+```
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+~~~~
+aaa
+~~~
+~~~~
+.
+<pre><code>aaa
+~~~
+</code></pre>
+````````````````````````````````
+
+
+Unclosed code blocks are closed by the end of the document
+(or the enclosing [block quote][block quotes] or [list item][list items]):
+
+```````````````````````````````` example
+```
+.
+<pre><code></code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+`````
+
+```
+aaa
+.
+<pre><code>
+```
+aaa
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+> ```
+> aaa
+
+bbb
+.
+<blockquote>
+<pre><code>aaa
+</code></pre>
+</blockquote>
+<p>bbb</p>
+````````````````````````````````
+
+
+A code block can have all empty lines as its content:
+
+```````````````````````````````` example
+```
+
+
+```
+.
+<pre><code>
+
+</code></pre>
+````````````````````````````````
+
+
+A code block can be empty:
+
+```````````````````````````````` example
+```
+```
+.
+<pre><code></code></pre>
+````````````````````````````````
+
+
+Fences can be indented. If the opening fence is indented,
+content lines will have equivalent opening indentation removed,
+if present:
+
+```````````````````````````````` example
+ ```
+ aaa
+aaa
+```
+.
+<pre><code>aaa
+aaa
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ ```
+aaa
+ aaa
+aaa
+ ```
+.
+<pre><code>aaa
+aaa
+aaa
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ ```
+ aaa
+ aaa
+ aaa
+ ```
+.
+<pre><code>aaa
+ aaa
+aaa
+</code></pre>
+````````````````````````````````
+
+
+Four spaces indentation produces an indented code block:
+
+```````````````````````````````` example
+ ```
+ aaa
+ ```
+.
+<pre><code>```
+aaa
+```
+</code></pre>
+````````````````````````````````
+
+
+Closing fences may be indented by 0-3 spaces, and their indentation
+need not match that of the opening fence:
+
+```````````````````````````````` example
+```
+aaa
+ ```
+.
+<pre><code>aaa
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ ```
+aaa
+ ```
+.
+<pre><code>aaa
+</code></pre>
+````````````````````````````````
+
+
+This is not a closing fence, because it is indented 4 spaces:
+
+```````````````````````````````` example
+```
+aaa
+ ```
+.
+<pre><code>aaa
+ ```
+</code></pre>
+````````````````````````````````
+
+
+
+Code fences (opening and closing) cannot contain internal spaces:
+
+```````````````````````````````` example
+``` ```
+aaa
+.
+<p><code> </code>
+aaa</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+~~~~~~
+aaa
+~~~ ~~
+.
+<pre><code>aaa
+~~~ ~~
+</code></pre>
+````````````````````````````````
+
+
+Fenced code blocks can interrupt paragraphs, and can be followed
+directly by paragraphs, without a blank line between:
+
+```````````````````````````````` example
+foo
+```
+bar
+```
+baz
+.
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+<p>baz</p>
+````````````````````````````````
+
+
+Other blocks can also occur before and after fenced code blocks
+without an intervening blank line:
+
+```````````````````````````````` example
+foo
+---
+~~~
+bar
+~~~
+# baz
+.
+<h2>foo</h2>
+<pre><code>bar
+</code></pre>
+<h1>baz</h1>
+````````````````````````````````
+
+
+An [info string] can be provided after the opening code fence.
+Although this spec doesn't mandate any particular treatment of
+the info string, the first word is typically used to specify
+the language of the code block. In HTML output, the language is
+normally indicated by adding a class to the `code` element consisting
+of `language-` followed by the language name.
+
+```````````````````````````````` example
+```ruby
+def foo(x)
+ return 3
+end
+```
+.
+<pre><code class="language-ruby">def foo(x)
+ return 3
+end
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+~~~~ ruby startline=3 $%@#$
+def foo(x)
+ return 3
+end
+~~~~~~~
+.
+<pre><code class="language-ruby">def foo(x)
+ return 3
+end
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+````;
+````
+.
+<pre><code class="language-;"></code></pre>
+````````````````````````````````
+
+
+[Info strings] for backtick code blocks cannot contain backticks:
+
+```````````````````````````````` example
+``` aa ```
+foo
+.
+<p><code>aa</code>
+foo</p>
+````````````````````````````````
+
+
+[Info strings] for tilde code blocks can contain backticks and tildes:
+
+```````````````````````````````` example
+~~~ aa ``` ~~~
+foo
+~~~
+.
+<pre><code class="language-aa">foo
+</code></pre>
+````````````````````````````````
+
+
+Closing code fences cannot have [info strings]:
+
+```````````````````````````````` example
+```
+``` aaa
+```
+.
+<pre><code>``` aaa
+</code></pre>
+````````````````````````````````
+
+
+
+## HTML blocks
+
+An [HTML block](@) is a group of lines that is treated
+as raw HTML (and will not be escaped in HTML output).
+
+There are seven kinds of [HTML block], which can be defined by their
+start and end conditions. The block begins with a line that meets a
+[start condition](@) (after up to three spaces optional indentation).
+It ends with the first subsequent line that meets a matching [end
+condition](@), or the last line of the document, or the last line of
+the [container block](#container-blocks) containing the current HTML
+block, if no line is encountered that meets the [end condition]. If
+the first line meets both the [start condition] and the [end
+condition], the block will contain just that line.
+
+1. **Start condition:** line begins with the string `<script`,
+`<pre`, or `<style` (case-insensitive), followed by whitespace,
+the string `>`, or the end of the line.\
+**End condition:** line contains an end tag
+`</script>`, `</pre>`, or `</style>` (case-insensitive; it
+need not match the start tag).
+
+2. **Start condition:** line begins with the string `<!--`.\
+**End condition:** line contains the string `-->`.
+
+3. **Start condition:** line begins with the string `<?`.\
+**End condition:** line contains the string `?>`.
+
+4. **Start condition:** line begins with the string `<!`
+followed by an uppercase ASCII letter.\
+**End condition:** line contains the character `>`.
+
+5. **Start condition:** line begins with the string
+`<![CDATA[`.\
+**End condition:** line contains the string `]]>`.
+
+6. **Start condition:** line begins the string `<` or `</`
+followed by one of the strings (case-insensitive) `address`,
+`article`, `aside`, `base`, `basefont`, `blockquote`, `body`,
+`caption`, `center`, `col`, `colgroup`, `dd`, `details`, `dialog`,
+`dir`, `div`, `dl`, `dt`, `fieldset`, `figcaption`, `figure`,
+`footer`, `form`, `frame`, `frameset`,
+`h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `head`, `header`, `hr`,
+`html`, `iframe`, `legend`, `li`, `link`, `main`, `menu`, `menuitem`,
+`nav`, `noframes`, `ol`, `optgroup`, `option`, `p`, `param`,
+`section`, `summary`, `table`, `tbody`, `td`,
+`tfoot`, `th`, `thead`, `title`, `tr`, `track`, `ul`, followed
+by [whitespace], the end of the line, the string `>`, or
+the string `/>`.\
+**End condition:** line is followed by a [blank line].
+
+7. **Start condition:** line begins with a complete [open tag]
+(with any [tag name] other than `script`,
+`style`, or `pre`) or a complete [closing tag],
+followed only by [whitespace] or the end of the line.\
+**End condition:** line is followed by a [blank line].
+
+HTML blocks continue until they are closed by their appropriate
+[end condition], or the last line of the document or other [container
+block](#container-blocks). This means any HTML **within an HTML
+block** that might otherwise be recognised as a start condition will
+be ignored by the parser and passed through as-is, without changing
+the parser's state.
+
+For instance, `<pre>` within a HTML block started by `<table>` will not affect
+the parser state; as the HTML block was started in by start condition 6, it
+will end at any blank line. This can be surprising:
+
+```````````````````````````````` example
+<table><tr><td>
+<pre>
+**Hello**,
+
+_world_.
+</pre>
+</td></tr></table>
+.
+<table><tr><td>
+<pre>
+**Hello**,
+<p><em>world</em>.
+</pre></p>
+</td></tr></table>
+````````````````````````````````
+
+In this case, the HTML block is terminated by the newline — the `**Hello**`
+text remains verbatim — and regular parsing resumes, with a paragraph,
+emphasised `world` and inline and block HTML following.
+
+All types of [HTML blocks] except type 7 may interrupt
+a paragraph. Blocks of type 7 may not interrupt a paragraph.
+(This restriction is intended to prevent unwanted interpretation
+of long tags inside a wrapped paragraph as starting HTML blocks.)
+
+Some simple examples follow. Here are some basic HTML blocks
+of type 6:
+
+```````````````````````````````` example
+<table>
+ <tr>
+ <td>
+ hi
+ </td>
+ </tr>
+</table>
+
+okay.
+.
+<table>
+ <tr>
+ <td>
+ hi
+ </td>
+ </tr>
+</table>
+<p>okay.</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ <div>
+ *hello*
+ <foo><a>
+.
+ <div>
+ *hello*
+ <foo><a>
+````````````````````````````````
+
+
+A block can also start with a closing tag:
+
+```````````````````````````````` example
+</div>
+*foo*
+.
+</div>
+*foo*
+````````````````````````````````
+
+
+Here we have two HTML blocks with a Markdown paragraph between them:
+
+```````````````````````````````` example
+<DIV CLASS="foo">
+
+*Markdown*
+
+</DIV>
+.
+<DIV CLASS="foo">
+<p><em>Markdown</em></p>
+</DIV>
+````````````````````````````````
+
+
+The tag on the first line can be partial, as long
+as it is split where there would be whitespace:
+
+```````````````````````````````` example
+<div id="foo"
+ class="bar">
+</div>
+.
+<div id="foo"
+ class="bar">
+</div>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<div id="foo" class="bar
+ baz">
+</div>
+.
+<div id="foo" class="bar
+ baz">
+</div>
+````````````````````````````````
+
+
+An open tag need not be closed:
+```````````````````````````````` example
+<div>
+*foo*
+
+*bar*
+.
+<div>
+*foo*
+<p><em>bar</em></p>
+````````````````````````````````
+
+
+
+A partial tag need not even be completed (garbage
+in, garbage out):
+
+```````````````````````````````` example
+<div id="foo"
+*hi*
+.
+<div id="foo"
+*hi*
+````````````````````````````````
+
+
+```````````````````````````````` example
+<div class
+foo
+.
+<div class
+foo
+````````````````````````````````
+
+
+The initial tag doesn't even need to be a valid
+tag, as long as it starts like one:
+
+```````````````````````````````` example
+<div *???-&&&-<---
+*foo*
+.
+<div *???-&&&-<---
+*foo*
+````````````````````````````````
+
+
+In type 6 blocks, the initial tag need not be on a line by
+itself:
+
+```````````````````````````````` example
+<div><a href="bar">*foo*</a></div>
+.
+<div><a href="bar">*foo*</a></div>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<table><tr><td>
+foo
+</td></tr></table>
+.
+<table><tr><td>
+foo
+</td></tr></table>
+````````````````````````````````
+
+
+Everything until the next blank line or end of document
+gets included in the HTML block. So, in the following
+example, what looks like a Markdown code block
+is actually part of the HTML block, which continues until a blank
+line or the end of the document is reached:
+
+```````````````````````````````` example
+<div></div>
+``` c
+int x = 33;
+```
+.
+<div></div>
+``` c
+int x = 33;
+```
+````````````````````````````````
+
+
+To start an [HTML block] with a tag that is *not* in the
+list of block-level tags in (6), you must put the tag by
+itself on the first line (and it must be complete):
+
+```````````````````````````````` example
+<a href="foo">
+*bar*
+</a>
+.
+<a href="foo">
+*bar*
+</a>
+````````````````````````````````
+
+
+In type 7 blocks, the [tag name] can be anything:
+
+```````````````````````````````` example
+<Warning>
+*bar*
+</Warning>
+.
+<Warning>
+*bar*
+</Warning>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<i class="foo">
+*bar*
+</i>
+.
+<i class="foo">
+*bar*
+</i>
+````````````````````````````````
+
+
+```````````````````````````````` example
+</ins>
+*bar*
+.
+</ins>
+*bar*
+````````````````````````````````
+
+
+These rules are designed to allow us to work with tags that
+can function as either block-level or inline-level tags.
+The `<del>` tag is a nice example. We can surround content with
+`<del>` tags in three different ways. In this case, we get a raw
+HTML block, because the `<del>` tag is on a line by itself:
+
+```````````````````````````````` example
+<del>
+*foo*
+</del>
+.
+<del>
+*foo*
+</del>
+````````````````````````````````
+
+
+In this case, we get a raw HTML block that just includes
+the `<del>` tag (because it ends with the following blank
+line). So the contents get interpreted as CommonMark:
+
+```````````````````````````````` example
+<del>
+
+*foo*
+
+</del>
+.
+<del>
+<p><em>foo</em></p>
+</del>
+````````````````````````````````
+
+
+Finally, in this case, the `<del>` tags are interpreted
+as [raw HTML] *inside* the CommonMark paragraph. (Because
+the tag is not on a line by itself, we get inline HTML
+rather than an [HTML block].)
+
+```````````````````````````````` example
+<del>*foo*</del>
+.
+<p><del><em>foo</em></del></p>
+````````````````````````````````
+
+
+HTML tags designed to contain literal content
+(`script`, `style`, `pre`), comments, processing instructions,
+and declarations are treated somewhat differently.
+Instead of ending at the first blank line, these blocks
+end at the first line containing a corresponding end tag.
+As a result, these blocks can contain blank lines:
+
+A pre tag (type 1):
+
+```````````````````````````````` example
+<pre language="haskell"><code>
+import Text.HTML.TagSoup
+
+main :: IO ()
+main = print $ parseTags tags
+</code></pre>
+okay
+.
+<pre language="haskell"><code>
+import Text.HTML.TagSoup
+
+main :: IO ()
+main = print $ parseTags tags
+</code></pre>
+<p>okay</p>
+````````````````````````````````
+
+
+A script tag (type 1):
+
+```````````````````````````````` example
+<script type="text/javascript">
+// JavaScript example
+
+document.getElementById("demo").innerHTML = "Hello JavaScript!";
+</script>
+okay
+.
+<script type="text/javascript">
+// JavaScript example
+
+document.getElementById("demo").innerHTML = "Hello JavaScript!";
+</script>
+<p>okay</p>
+````````````````````````````````
+
+
+A style tag (type 1):
+
+```````````````````````````````` example
+<style
+ type="text/css">
+h1 {color:red;}
+
+p {color:blue;}
+</style>
+okay
+.
+<style
+ type="text/css">
+h1 {color:red;}
+
+p {color:blue;}
+</style>
+<p>okay</p>
+````````````````````````````````
+
+
+If there is no matching end tag, the block will end at the
+end of the document (or the enclosing [block quote][block quotes]
+or [list item][list items]):
+
+```````````````````````````````` example
+<style
+ type="text/css">
+
+foo
+.
+<style
+ type="text/css">
+
+foo
+````````````````````````````````
+
+
+```````````````````````````````` example
+> <div>
+> foo
+
+bar
+.
+<blockquote>
+<div>
+foo
+</blockquote>
+<p>bar</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- <div>
+- foo
+.
+<ul>
+<li>
+<div>
+</li>
+<li>foo</li>
+</ul>
+````````````````````````````````
+
+
+The end tag can occur on the same line as the start tag:
+
+```````````````````````````````` example
+<style>p{color:red;}</style>
+*foo*
+.
+<style>p{color:red;}</style>
+<p><em>foo</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<!-- foo -->*bar*
+*baz*
+.
+<!-- foo -->*bar*
+<p><em>baz</em></p>
+````````````````````````````````
+
+
+Note that anything on the last line after the
+end tag will be included in the [HTML block]:
+
+```````````````````````````````` example
+<script>
+foo
+</script>1. *bar*
+.
+<script>
+foo
+</script>1. *bar*
+````````````````````````````````
+
+
+A comment (type 2):
+
+```````````````````````````````` example
+<!-- Foo
+
+bar
+ baz -->
+okay
+.
+<!-- Foo
+
+bar
+ baz -->
+<p>okay</p>
+````````````````````````````````
+
+
+
+A processing instruction (type 3):
+
+```````````````````````````````` example
+<?php
+
+ echo '>';
+
+?>
+okay
+.
+<?php
+
+ echo '>';
+
+?>
+<p>okay</p>
+````````````````````````````````
+
+
+A declaration (type 4):
+
+```````````````````````````````` example
+<!DOCTYPE html>
+.
+<!DOCTYPE html>
+````````````````````````````````
+
+
+CDATA (type 5):
+
+```````````````````````````````` example
+<![CDATA[
+function matchwo(a,b)
+{
+ if (a < b && a < 0) then {
+ return 1;
+
+ } else {
+
+ return 0;
+ }
+}
+]]>
+okay
+.
+<![CDATA[
+function matchwo(a,b)
+{
+ if (a < b && a < 0) then {
+ return 1;
+
+ } else {
+
+ return 0;
+ }
+}
+]]>
+<p>okay</p>
+````````````````````````````````
+
+
+The opening tag can be indented 1-3 spaces, but not 4:
+
+```````````````````````````````` example
+ <!-- foo -->
+
+ <!-- foo -->
+.
+ <!-- foo -->
+<pre><code>&lt;!-- foo --&gt;
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ <div>
+
+ <div>
+.
+ <div>
+<pre><code>&lt;div&gt;
+</code></pre>
+````````````````````````````````
+
+
+An HTML block of types 1--6 can interrupt a paragraph, and need not be
+preceded by a blank line.
+
+```````````````````````````````` example
+Foo
+<div>
+bar
+</div>
+.
+<p>Foo</p>
+<div>
+bar
+</div>
+````````````````````````````````
+
+
+However, a following blank line is needed, except at the end of
+a document, and except for blocks of types 1--5, [above][HTML
+block]:
+
+```````````````````````````````` example
+<div>
+bar
+</div>
+*foo*
+.
+<div>
+bar
+</div>
+*foo*
+````````````````````````````````
+
+
+HTML blocks of type 7 cannot interrupt a paragraph:
+
+```````````````````````````````` example
+Foo
+<a href="bar">
+baz
+.
+<p>Foo
+<a href="bar">
+baz</p>
+````````````````````````````````
+
+
+This rule differs from John Gruber's original Markdown syntax
+specification, which says:
+
+> The only restrictions are that block-level HTML elements —
+> e.g. `<div>`, `<table>`, `<pre>`, `<p>`, etc. — must be separated from
+> surrounding content by blank lines, and the start and end tags of the
+> block should not be indented with tabs or spaces.
+
+In some ways Gruber's rule is more restrictive than the one given
+here:
+
+- It requires that an HTML block be preceded by a blank line.
+- It does not allow the start tag to be indented.
+- It requires a matching end tag, which it also does not allow to
+ be indented.
+
+Most Markdown implementations (including some of Gruber's own) do not
+respect all of these restrictions.
+
+There is one respect, however, in which Gruber's rule is more liberal
+than the one given here, since it allows blank lines to occur inside
+an HTML block. There are two reasons for disallowing them here.
+First, it removes the need to parse balanced tags, which is
+expensive and can require backtracking from the end of the document
+if no matching end tag is found. Second, it provides a very simple
+and flexible way of including Markdown content inside HTML tags:
+simply separate the Markdown from the HTML using blank lines:
+
+Compare:
+
+```````````````````````````````` example
+<div>
+
+*Emphasized* text.
+
+</div>
+.
+<div>
+<p><em>Emphasized</em> text.</p>
+</div>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<div>
+*Emphasized* text.
+</div>
+.
+<div>
+*Emphasized* text.
+</div>
+````````````````````````````````
+
+
+Some Markdown implementations have adopted a convention of
+interpreting content inside tags as text if the open tag has
+the attribute `markdown=1`. The rule given above seems a simpler and
+more elegant way of achieving the same expressive power, which is also
+much simpler to parse.
+
+The main potential drawback is that one can no longer paste HTML
+blocks into Markdown documents with 100% reliability. However,
+*in most cases* this will work fine, because the blank lines in
+HTML are usually followed by HTML block tags. For example:
+
+```````````````````````````````` example
+<table>
+
+<tr>
+
+<td>
+Hi
+</td>
+
+</tr>
+
+</table>
+.
+<table>
+<tr>
+<td>
+Hi
+</td>
+</tr>
+</table>
+````````````````````````````````
+
+
+There are problems, however, if the inner tags are indented
+*and* separated by spaces, as then they will be interpreted as
+an indented code block:
+
+```````````````````````````````` example
+<table>
+
+ <tr>
+
+ <td>
+ Hi
+ </td>
+
+ </tr>
+
+</table>
+.
+<table>
+ <tr>
+<pre><code>&lt;td&gt;
+ Hi
+&lt;/td&gt;
+</code></pre>
+ </tr>
+</table>
+````````````````````````````````
+
+
+Fortunately, blank lines are usually not necessary and can be
+deleted. The exception is inside `<pre>` tags, but as described
+[above][HTML blocks], raw HTML blocks starting with `<pre>`
+*can* contain blank lines.
+
+## Link reference definitions
+
+A [link reference definition](@)
+consists of a [link label], indented up to three spaces, followed
+by a colon (`:`), optional [whitespace] (including up to one
+[line ending]), a [link destination],
+optional [whitespace] (including up to one
+[line ending]), and an optional [link
+title], which if it is present must be separated
+from the [link destination] by [whitespace].
+No further [non-whitespace characters] may occur on the line.
+
+A [link reference definition]
+does not correspond to a structural element of a document. Instead, it
+defines a label which can be used in [reference links]
+and reference-style [images] elsewhere in the document. [Link
+reference definitions] can come either before or after the links that use
+them.
+
+```````````````````````````````` example
+[foo]: /url "title"
+
+[foo]
+.
+<p><a href="/url" title="title">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ [foo]:
+ /url
+ 'the title'
+
+[foo]
+.
+<p><a href="/url" title="the title">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[Foo*bar\]]:my_(url) 'title (with parens)'
+
+[Foo*bar\]]
+.
+<p><a href="my_(url)" title="title (with parens)">Foo*bar]</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[Foo bar]:
+<my url>
+'title'
+
+[Foo bar]
+.
+<p><a href="my%20url" title="title">Foo bar</a></p>
+````````````````````````````````
+
+
+The title may extend over multiple lines:
+
+```````````````````````````````` example
+[foo]: /url '
+title
+line1
+line2
+'
+
+[foo]
+.
+<p><a href="/url" title="
+title
+line1
+line2
+">foo</a></p>
+````````````````````````````````
+
+
+However, it may not contain a [blank line]:
+
+```````````````````````````````` example
+[foo]: /url 'title
+
+with blank line'
+
+[foo]
+.
+<p>[foo]: /url 'title</p>
+<p>with blank line'</p>
+<p>[foo]</p>
+````````````````````````````````
+
+
+The title may be omitted:
+
+```````````````````````````````` example
+[foo]:
+/url
+
+[foo]
+.
+<p><a href="/url">foo</a></p>
+````````````````````````````````
+
+
+The link destination may not be omitted:
+
+```````````````````````````````` example
+[foo]:
+
+[foo]
+.
+<p>[foo]:</p>
+<p>[foo]</p>
+````````````````````````````````
+
+ However, an empty link destination may be specified using
+ angle brackets:
+
+```````````````````````````````` example
+[foo]: <>
+
+[foo]
+.
+<p><a href="">foo</a></p>
+````````````````````````````````
+
+The title must be separated from the link destination by
+whitespace:
+
+```````````````````````````````` example
+[foo]: <bar>(baz)
+
+[foo]
+.
+<p>[foo]: <bar>(baz)</p>
+<p>[foo]</p>
+````````````````````````````````
+
+
+Both title and destination can contain backslash escapes
+and literal backslashes:
+
+```````````````````````````````` example
+[foo]: /url\bar\*baz "foo\"bar\baz"
+
+[foo]
+.
+<p><a href="/url%5Cbar*baz" title="foo&quot;bar\baz">foo</a></p>
+````````````````````````````````
+
+
+A link can come before its corresponding definition:
+
+```````````````````````````````` example
+[foo]
+
+[foo]: url
+.
+<p><a href="url">foo</a></p>
+````````````````````````````````
+
+
+If there are several matching definitions, the first one takes
+precedence:
+
+```````````````````````````````` example
+[foo]
+
+[foo]: first
+[foo]: second
+.
+<p><a href="first">foo</a></p>
+````````````````````````````````
+
+
+As noted in the section on [Links], matching of labels is
+case-insensitive (see [matches]).
+
+```````````````````````````````` example
+[FOO]: /url
+
+[Foo]
+.
+<p><a href="/url">Foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[ΑΓΩ]: /φου
+
+[αγω]
+.
+<p><a href="/%CF%86%CE%BF%CF%85">αγω</a></p>
+````````````````````````````````
+
+
+Here is a link reference definition with no corresponding link.
+It contributes nothing to the document.
+
+```````````````````````````````` example
+[foo]: /url
+.
+````````````````````````````````
+
+
+Here is another one:
+
+```````````````````````````````` example
+[
+foo
+]: /url
+bar
+.
+<p>bar</p>
+````````````````````````````````
+
+
+This is not a link reference definition, because there are
+[non-whitespace characters] after the title:
+
+```````````````````````````````` example
+[foo]: /url "title" ok
+.
+<p>[foo]: /url &quot;title&quot; ok</p>
+````````````````````````````````
+
+
+This is a link reference definition, but it has no title:
+
+```````````````````````````````` example
+[foo]: /url
+"title" ok
+.
+<p>&quot;title&quot; ok</p>
+````````````````````````````````
+
+
+This is not a link reference definition, because it is indented
+four spaces:
+
+```````````````````````````````` example
+ [foo]: /url "title"
+
+[foo]
+.
+<pre><code>[foo]: /url &quot;title&quot;
+</code></pre>
+<p>[foo]</p>
+````````````````````````````````
+
+
+This is not a link reference definition, because it occurs inside
+a code block:
+
+```````````````````````````````` example
+```
+[foo]: /url
+```
+
+[foo]
+.
+<pre><code>[foo]: /url
+</code></pre>
+<p>[foo]</p>
+````````````````````````````````
+
+
+A [link reference definition] cannot interrupt a paragraph.
+
+```````````````````````````````` example
+Foo
+[bar]: /baz
+
+[bar]
+.
+<p>Foo
+[bar]: /baz</p>
+<p>[bar]</p>
+````````````````````````````````
+
+
+However, it can directly follow other block elements, such as headings
+and thematic breaks, and it need not be followed by a blank line.
+
+```````````````````````````````` example
+# [Foo]
+[foo]: /url
+> bar
+.
+<h1><a href="/url">Foo</a></h1>
+<blockquote>
+<p>bar</p>
+</blockquote>
+````````````````````````````````
+
+```````````````````````````````` example
+[foo]: /url
+bar
+===
+[foo]
+.
+<h1>bar</h1>
+<p><a href="/url">foo</a></p>
+````````````````````````````````
+
+```````````````````````````````` example
+[foo]: /url
+===
+[foo]
+.
+<p>===
+<a href="/url">foo</a></p>
+````````````````````````````````
+
+
+Several [link reference definitions]
+can occur one after another, without intervening blank lines.
+
+```````````````````````````````` example
+[foo]: /foo-url "foo"
+[bar]: /bar-url
+ "bar"
+[baz]: /baz-url
+
+[foo],
+[bar],
+[baz]
+.
+<p><a href="/foo-url" title="foo">foo</a>,
+<a href="/bar-url" title="bar">bar</a>,
+<a href="/baz-url">baz</a></p>
+````````````````````````````````
+
+
+[Link reference definitions] can occur
+inside block containers, like lists and block quotations. They
+affect the entire document, not just the container in which they
+are defined:
+
+```````````````````````````````` example
+[foo]
+
+> [foo]: /url
+.
+<p><a href="/url">foo</a></p>
+<blockquote>
+</blockquote>
+````````````````````````````````
+
+
+Whether something is a [link reference definition] is
+independent of whether the link reference it defines is
+used in the document. Thus, for example, the following
+document contains just a link reference definition, and
+no visible content:
+
+```````````````````````````````` example
+[foo]: /url
+.
+````````````````````````````````
+
+
+## Paragraphs
+
+A sequence of non-blank lines that cannot be interpreted as other
+kinds of blocks forms a [paragraph](@).
+The contents of the paragraph are the result of parsing the
+paragraph's raw content as inlines. The paragraph's raw content
+is formed by concatenating the lines and removing initial and final
+[whitespace].
+
+A simple example with two paragraphs:
+
+```````````````````````````````` example
+aaa
+
+bbb
+.
+<p>aaa</p>
+<p>bbb</p>
+````````````````````````````````
+
+
+Paragraphs can contain multiple lines, but no blank lines:
+
+```````````````````````````````` example
+aaa
+bbb
+
+ccc
+ddd
+.
+<p>aaa
+bbb</p>
+<p>ccc
+ddd</p>
+````````````````````````````````
+
+
+Multiple blank lines between paragraph have no effect:
+
+```````````````````````````````` example
+aaa
+
+
+bbb
+.
+<p>aaa</p>
+<p>bbb</p>
+````````````````````````````````
+
+
+Leading spaces are skipped:
+
+```````````````````````````````` example
+ aaa
+ bbb
+.
+<p>aaa
+bbb</p>
+````````````````````````````````
+
+
+Lines after the first may be indented any amount, since indented
+code blocks cannot interrupt paragraphs.
+
+```````````````````````````````` example
+aaa
+ bbb
+ ccc
+.
+<p>aaa
+bbb
+ccc</p>
+````````````````````````````````
+
+
+However, the first line may be indented at most three spaces,
+or an indented code block will be triggered:
+
+```````````````````````````````` example
+ aaa
+bbb
+.
+<p>aaa
+bbb</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ aaa
+bbb
+.
+<pre><code>aaa
+</code></pre>
+<p>bbb</p>
+````````````````````````````````
+
+
+Final spaces are stripped before inline parsing, so a paragraph
+that ends with two or more spaces will not end with a [hard line
+break]:
+
+```````````````````````````````` example
+aaa
+bbb
+.
+<p>aaa<br />
+bbb</p>
+````````````````````````````````
+
+
+## Blank lines
+
+[Blank lines] between block-level elements are ignored,
+except for the role they play in determining whether a [list]
+is [tight] or [loose].
+
+Blank lines at the beginning and end of the document are also ignored.
+
+```````````````````````````````` example
+
+
+aaa
+
+
+# aaa
+
+
+.
+<p>aaa</p>
+<h1>aaa</h1>
+````````````````````````````````
+
+<div class="extension">
+
+## Tables (extension)
+
+GFM enables the `table` extension, where an additional leaf block type is
+available.
+
+A [table](@) is an arrangement of data with rows and columns, consisting of a
+single header row, a [delimiter row] separating the header from the data, and
+zero or more data rows.
+
+Each row consists of cells containing arbitrary text, in which [inlines] are
+parsed, separated by pipes (`|`). A leading and trailing pipe is also
+recommended for clarity of reading, and if there's otherwise parsing ambiguity.
+Spaces between pipes and cell content are trimmed. Block-level elements cannot
+be inserted in a table.
+
+The [delimiter row](@) consists of cells whose only content are hyphens (`-`),
+and optionally, a leading or trailing colon (`:`), or both, to indicate left,
+right, or center alignment respectively.
+
+```````````````````````````````` example table
+| foo | bar |
+| --- | --- |
+| baz | bim |
+.
+<table>
+<thead>
+<tr>
+<th>foo</th>
+<th>bar</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>baz</td>
+<td>bim</td>
+</tr>
+</tbody>
+</table>
+````````````````````````````````
+
+Cells in one column don't need to match length, though it's easier to read if
+they are. Likewise, use of leading and trailing pipes may be inconsistent:
+
+```````````````````````````````` example table
+| abc | defghi |
+:-: | -----------:
+bar | baz
+.
+<table>
+<thead>
+<tr>
+<th align="center">abc</th>
+<th align="right">defghi</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="center">bar</td>
+<td align="right">baz</td>
+</tr>
+</tbody>
+</table>
+````````````````````````````````
+
+Include a pipe in a cell's content by escaping it, including inside other
+inline spans:
+
+```````````````````````````````` example table
+| f\|oo |
+| ------ |
+| b `\|` az |
+| b **\|** im |
+.
+<table>
+<thead>
+<tr>
+<th>f|oo</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>b <code>|</code> az</td>
+</tr>
+<tr>
+<td>b <strong>|</strong> im</td>
+</tr>
+</tbody>
+</table>
+````````````````````````````````
+
+The table is broken at the first empty line, or beginning of another
+block-level structure:
+
+```````````````````````````````` example table
+| abc | def |
+| --- | --- |
+| bar | baz |
+> bar
+.
+<table>
+<thead>
+<tr>
+<th>abc</th>
+<th>def</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>bar</td>
+<td>baz</td>
+</tr>
+</tbody>
+</table>
+<blockquote>
+<p>bar</p>
+</blockquote>
+````````````````````````````````
+
+```````````````````````````````` example table
+| abc | def |
+| --- | --- |
+| bar | baz |
+bar
+
+bar
+.
+<table>
+<thead>
+<tr>
+<th>abc</th>
+<th>def</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>bar</td>
+<td>baz</td>
+</tr>
+<tr>
+<td>bar</td>
+<td></td>
+</tr>
+</tbody>
+</table>
+<p>bar</p>
+````````````````````````````````
+
+The header row must match the [delimiter row] in the number of cells. If not,
+a table will not be recognized:
+
+```````````````````````````````` example table
+| abc | def |
+| --- |
+| bar |
+.
+<p>| abc | def |
+| --- |
+| bar |</p>
+````````````````````````````````
+
+The remainder of the table's rows may vary in the number of cells. If there
+are a number of cells fewer than the number of cells in the header row, empty
+cells are inserted. If there are greater, the excess is ignored:
+
+```````````````````````````````` example table
+| abc | def |
+| --- | --- |
+| bar |
+| bar | baz | boo |
+.
+<table>
+<thead>
+<tr>
+<th>abc</th>
+<th>def</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>bar</td>
+<td></td>
+</tr>
+<tr>
+<td>bar</td>
+<td>baz</td>
+</tr>
+</tbody>
+</table>
+````````````````````````````````
+
+If there are no rows in the body, no `<tbody>` is generated in HTML output:
+
+```````````````````````````````` example table
+| abc | def |
+| --- | --- |
+.
+<table>
+<thead>
+<tr>
+<th>abc</th>
+<th>def</th>
+</tr>
+</thead>
+</table>
+````````````````````````````````
+
+</div>
+
+# Container blocks
+
+A [container block](#container-blocks) is a block that has other
+blocks as its contents. There are two basic kinds of container blocks:
+[block quotes] and [list items].
+[Lists] are meta-containers for [list items].
+
+We define the syntax for container blocks recursively. The general
+form of the definition is:
+
+> If X is a sequence of blocks, then the result of
+> transforming X in such-and-such a way is a container of type Y
+> with these blocks as its content.
+
+So, we explain what counts as a block quote or list item by explaining
+how these can be *generated* from their contents. This should suffice
+to define the syntax, although it does not give a recipe for *parsing*
+these constructions. (A recipe is provided below in the section entitled
+[A parsing strategy](#appendix-a-parsing-strategy).)
+
+## Block quotes
+
+A [block quote marker](@)
+consists of 0-3 spaces of initial indent, plus (a) the character `>` together
+with a following space, or (b) a single character `>` not followed by a space.
+
+The following rules define [block quotes]:
+
+1. **Basic case.** If a string of lines *Ls* constitute a sequence
+ of blocks *Bs*, then the result of prepending a [block quote
+ marker] to the beginning of each line in *Ls*
+ is a [block quote](#block-quotes) containing *Bs*.
+
+2. **Laziness.** If a string of lines *Ls* constitute a [block
+ quote](#block-quotes) with contents *Bs*, then the result of deleting
+ the initial [block quote marker] from one or
+ more lines in which the next [non-whitespace character] after the [block
+ quote marker] is [paragraph continuation
+ text] is a block quote with *Bs* as its content.
+ [Paragraph continuation text](@) is text
+ that will be parsed as part of the content of a paragraph, but does
+ not occur at the beginning of the paragraph.
+
+3. **Consecutiveness.** A document cannot contain two [block
+ quotes] in a row unless there is a [blank line] between them.
+
+Nothing else counts as a [block quote](#block-quotes).
+
+Here is a simple example:
+
+```````````````````````````````` example
+> # Foo
+> bar
+> baz
+.
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+````````````````````````````````
+
+
+The spaces after the `>` characters can be omitted:
+
+```````````````````````````````` example
+># Foo
+>bar
+> baz
+.
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+````````````````````````````````
+
+
+The `>` characters can be indented 1-3 spaces:
+
+```````````````````````````````` example
+ > # Foo
+ > bar
+ > baz
+.
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+````````````````````````````````
+
+
+Four spaces gives us a code block:
+
+```````````````````````````````` example
+ > # Foo
+ > bar
+ > baz
+.
+<pre><code>&gt; # Foo
+&gt; bar
+&gt; baz
+</code></pre>
+````````````````````````````````
+
+
+The Laziness clause allows us to omit the `>` before
+[paragraph continuation text]:
+
+```````````````````````````````` example
+> # Foo
+> bar
+baz
+.
+<blockquote>
+<h1>Foo</h1>
+<p>bar
+baz</p>
+</blockquote>
+````````````````````````````````
+
+
+A block quote can contain some lazy and some non-lazy
+continuation lines:
+
+```````````````````````````````` example
+> bar
+baz
+> foo
+.
+<blockquote>
+<p>bar
+baz
+foo</p>
+</blockquote>
+````````````````````````````````
+
+
+Laziness only applies to lines that would have been continuations of
+paragraphs had they been prepended with [block quote markers].
+For example, the `> ` cannot be omitted in the second line of
+
+``` markdown
+> foo
+> ---
+```
+
+without changing the meaning:
+
+```````````````````````````````` example
+> foo
+---
+.
+<blockquote>
+<p>foo</p>
+</blockquote>
+<hr />
+````````````````````````````````
+
+
+Similarly, if we omit the `> ` in the second line of
+
+``` markdown
+> - foo
+> - bar
+```
+
+then the block quote ends after the first line:
+
+```````````````````````````````` example
+> - foo
+- bar
+.
+<blockquote>
+<ul>
+<li>foo</li>
+</ul>
+</blockquote>
+<ul>
+<li>bar</li>
+</ul>
+````````````````````````````````
+
+
+For the same reason, we can't omit the `> ` in front of
+subsequent lines of an indented or fenced code block:
+
+```````````````````````````````` example
+> foo
+ bar
+.
+<blockquote>
+<pre><code>foo
+</code></pre>
+</blockquote>
+<pre><code>bar
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+> ```
+foo
+```
+.
+<blockquote>
+<pre><code></code></pre>
+</blockquote>
+<p>foo</p>
+<pre><code></code></pre>
+````````````````````````````````
+
+
+Note that in the following case, we have a [lazy
+continuation line]:
+
+```````````````````````````````` example
+> foo
+ - bar
+.
+<blockquote>
+<p>foo
+- bar</p>
+</blockquote>
+````````````````````````````````
+
+
+To see why, note that in
+
+```markdown
+> foo
+> - bar
+```
+
+the `- bar` is indented too far to start a list, and can't
+be an indented code block because indented code blocks cannot
+interrupt paragraphs, so it is [paragraph continuation text].
+
+A block quote can be empty:
+
+```````````````````````````````` example
+>
+.
+<blockquote>
+</blockquote>
+````````````````````````````````
+
+
+```````````````````````````````` example
+>
+>
+>
+.
+<blockquote>
+</blockquote>
+````````````````````````````````
+
+
+A block quote can have initial or final blank lines:
+
+```````````````````````````````` example
+>
+> foo
+>
+.
+<blockquote>
+<p>foo</p>
+</blockquote>
+````````````````````````````````
+
+
+A blank line always separates block quotes:
+
+```````````````````````````````` example
+> foo
+
+> bar
+.
+<blockquote>
+<p>foo</p>
+</blockquote>
+<blockquote>
+<p>bar</p>
+</blockquote>
+````````````````````````````````
+
+
+(Most current Markdown implementations, including John Gruber's
+original `Markdown.pl`, will parse this example as a single block quote
+with two paragraphs. But it seems better to allow the author to decide
+whether two block quotes or one are wanted.)
+
+Consecutiveness means that if we put these block quotes together,
+we get a single block quote:
+
+```````````````````````````````` example
+> foo
+> bar
+.
+<blockquote>
+<p>foo
+bar</p>
+</blockquote>
+````````````````````````````````
+
+
+To get a block quote with two paragraphs, use:
+
+```````````````````````````````` example
+> foo
+>
+> bar
+.
+<blockquote>
+<p>foo</p>
+<p>bar</p>
+</blockquote>
+````````````````````````````````
+
+
+Block quotes can interrupt paragraphs:
+
+```````````````````````````````` example
+foo
+> bar
+.
+<p>foo</p>
+<blockquote>
+<p>bar</p>
+</blockquote>
+````````````````````````````````
+
+
+In general, blank lines are not needed before or after block
+quotes:
+
+```````````````````````````````` example
+> aaa
+***
+> bbb
+.
+<blockquote>
+<p>aaa</p>
+</blockquote>
+<hr />
+<blockquote>
+<p>bbb</p>
+</blockquote>
+````````````````````````````````
+
+
+However, because of laziness, a blank line is needed between
+a block quote and a following paragraph:
+
+```````````````````````````````` example
+> bar
+baz
+.
+<blockquote>
+<p>bar
+baz</p>
+</blockquote>
+````````````````````````````````
+
+
+```````````````````````````````` example
+> bar
+
+baz
+.
+<blockquote>
+<p>bar</p>
+</blockquote>
+<p>baz</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+> bar
+>
+baz
+.
+<blockquote>
+<p>bar</p>
+</blockquote>
+<p>baz</p>
+````````````````````````````````
+
+
+It is a consequence of the Laziness rule that any number
+of initial `>`s may be omitted on a continuation line of a
+nested block quote:
+
+```````````````````````````````` example
+> > > foo
+bar
+.
+<blockquote>
+<blockquote>
+<blockquote>
+<p>foo
+bar</p>
+</blockquote>
+</blockquote>
+</blockquote>
+````````````````````````````````
+
+
+```````````````````````````````` example
+>>> foo
+> bar
+>>baz
+.
+<blockquote>
+<blockquote>
+<blockquote>
+<p>foo
+bar
+baz</p>
+</blockquote>
+</blockquote>
+</blockquote>
+````````````````````````````````
+
+
+When including an indented code block in a block quote,
+remember that the [block quote marker] includes
+both the `>` and a following space. So *five spaces* are needed after
+the `>`:
+
+```````````````````````````````` example
+> code
+
+> not code
+.
+<blockquote>
+<pre><code>code
+</code></pre>
+</blockquote>
+<blockquote>
+<p>not code</p>
+</blockquote>
+````````````````````````````````
+
+
+
+## List items
+
+A [list marker](@) is a
+[bullet list marker] or an [ordered list marker].
+
+A [bullet list marker](@)
+is a `-`, `+`, or `*` character.
+
+An [ordered list marker](@)
+is a sequence of 1--9 arabic digits (`0-9`), followed by either a
+`.` character or a `)` character. (The reason for the length
+limit is that with 10 digits we start seeing integer overflows
+in some browsers.)
+
+The following rules define [list items]:
+
+1. **Basic case.** If a sequence of lines *Ls* constitute a sequence of
+ blocks *Bs* starting with a [non-whitespace character], and *M* is a
+ list marker of width *W* followed by 1 ≤ *N* ≤ 4 spaces, then the result
+ of prepending *M* and the following spaces to the first line of
+ *Ls*, and indenting subsequent lines of *Ls* by *W + N* spaces, is a
+ list item with *Bs* as its contents. The type of the list item
+ (bullet or ordered) is determined by the type of its list marker.
+ If the list item is ordered, then it is also assigned a start
+ number, based on the ordered list marker.
+
+ Exceptions:
+
+ 1. When the first list item in a [list] interrupts
+ a paragraph---that is, when it starts on a line that would
+ otherwise count as [paragraph continuation text]---then (a)
+ the lines *Ls* must not begin with a blank line, and (b) if
+ the list item is ordered, the start number must be 1.
+ 2. If any line is a [thematic break][thematic breaks] then
+ that line is not a list item.
+
+For example, let *Ls* be the lines
+
+```````````````````````````````` example
+A paragraph
+with two lines.
+
+ indented code
+
+> A block quote.
+.
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+````````````````````````````````
+
+
+And let *M* be the marker `1.`, and *N* = 2. Then rule #1 says
+that the following is an ordered list item with start number 1,
+and the same contents as *Ls*:
+
+```````````````````````````````` example
+1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+.
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+````````````````````````````````
+
+
+The most important thing to notice is that the position of
+the text after the list marker determines how much indentation
+is needed in subsequent blocks in the list item. If the list
+marker takes up two spaces, and there are three spaces between
+the list marker and the next [non-whitespace character], then blocks
+must be indented five spaces in order to fall under the list
+item.
+
+Here are some examples showing how far content must be indented to be
+put under the list item:
+
+```````````````````````````````` example
+- one
+
+ two
+.
+<ul>
+<li>one</li>
+</ul>
+<p>two</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- one
+
+ two
+.
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ - one
+
+ two
+.
+<ul>
+<li>one</li>
+</ul>
+<pre><code> two
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ - one
+
+ two
+.
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+It is tempting to think of this in terms of columns: the continuation
+blocks must be indented at least to the column of the first
+[non-whitespace character] after the list marker. However, that is not quite right.
+The spaces after the list marker determine how much relative indentation
+is needed. Which column this indentation reaches will depend on
+how the list item is embedded in other constructions, as shown by
+this example:
+
+```````````````````````````````` example
+ > > 1. one
+>>
+>> two
+.
+<blockquote>
+<blockquote>
+<ol>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ol>
+</blockquote>
+</blockquote>
+````````````````````````````````
+
+
+Here `two` occurs in the same column as the list marker `1.`,
+but is actually contained in the list item, because there is
+sufficient indentation after the last containing blockquote marker.
+
+The converse is also possible. In the following example, the word `two`
+occurs far to the right of the initial text of the list item, `one`, but
+it is not considered part of the list item, because it is not indented
+far enough past the blockquote marker:
+
+```````````````````````````````` example
+>>- one
+>>
+ > > two
+.
+<blockquote>
+<blockquote>
+<ul>
+<li>one</li>
+</ul>
+<p>two</p>
+</blockquote>
+</blockquote>
+````````````````````````````````
+
+
+Note that at least one space is needed between the list marker and
+any following content, so these are not list items:
+
+```````````````````````````````` example
+-one
+
+2.two
+.
+<p>-one</p>
+<p>2.two</p>
+````````````````````````````````
+
+
+A list item may contain blocks that are separated by more than
+one blank line.
+
+```````````````````````````````` example
+- foo
+
+
+ bar
+.
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+A list item may contain any kind of block:
+
+```````````````````````````````` example
+1. foo
+
+ ```
+ bar
+ ```
+
+ baz
+
+ > bam
+.
+<ol>
+<li>
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+<p>baz</p>
+<blockquote>
+<p>bam</p>
+</blockquote>
+</li>
+</ol>
+````````````````````````````````
+
+
+A list item that contains an indented code block will preserve
+empty lines within the code block verbatim.
+
+```````````````````````````````` example
+- Foo
+
+ bar
+
+
+ baz
+.
+<ul>
+<li>
+<p>Foo</p>
+<pre><code>bar
+
+
+baz
+</code></pre>
+</li>
+</ul>
+````````````````````````````````
+
+Note that ordered list start numbers must be nine digits or less:
+
+```````````````````````````````` example
+123456789. ok
+.
+<ol start="123456789">
+<li>ok</li>
+</ol>
+````````````````````````````````
+
+
+```````````````````````````````` example
+1234567890. not ok
+.
+<p>1234567890. not ok</p>
+````````````````````````````````
+
+
+A start number may begin with 0s:
+
+```````````````````````````````` example
+0. ok
+.
+<ol start="0">
+<li>ok</li>
+</ol>
+````````````````````````````````
+
+
+```````````````````````````````` example
+003. ok
+.
+<ol start="3">
+<li>ok</li>
+</ol>
+````````````````````````````````
+
+
+A start number may not be negative:
+
+```````````````````````````````` example
+-1. not ok
+.
+<p>-1. not ok</p>
+````````````````````````````````
+
+
+
+2. **Item starting with indented code.** If a sequence of lines *Ls*
+ constitute a sequence of blocks *Bs* starting with an indented code
+ block, and *M* is a list marker of width *W* followed by
+ one space, then the result of prepending *M* and the following
+ space to the first line of *Ls*, and indenting subsequent lines of
+ *Ls* by *W + 1* spaces, is a list item with *Bs* as its contents.
+ If a line is empty, then it need not be indented. The type of the
+ list item (bullet or ordered) is determined by the type of its list
+ marker. If the list item is ordered, then it is also assigned a
+ start number, based on the ordered list marker.
+
+An indented code block will have to be indented four spaces beyond
+the edge of the region where text will be included in the list item.
+In the following case that is 6 spaces:
+
+```````````````````````````````` example
+- foo
+
+ bar
+.
+<ul>
+<li>
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+</li>
+</ul>
+````````````````````````````````
+
+
+And in this case it is 11 spaces:
+
+```````````````````````````````` example
+ 10. foo
+
+ bar
+.
+<ol start="10">
+<li>
+<p>foo</p>
+<pre><code>bar
+</code></pre>
+</li>
+</ol>
+````````````````````````````````
+
+
+If the *first* block in the list item is an indented code block,
+then by rule #2, the contents must be indented *one* space after the
+list marker:
+
+```````````````````````````````` example
+ indented code
+
+paragraph
+
+ more code
+.
+<pre><code>indented code
+</code></pre>
+<p>paragraph</p>
+<pre><code>more code
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+1. indented code
+
+ paragraph
+
+ more code
+.
+<ol>
+<li>
+<pre><code>indented code
+</code></pre>
+<p>paragraph</p>
+<pre><code>more code
+</code></pre>
+</li>
+</ol>
+````````````````````````````````
+
+
+Note that an additional space indent is interpreted as space
+inside the code block:
+
+```````````````````````````````` example
+1. indented code
+
+ paragraph
+
+ more code
+.
+<ol>
+<li>
+<pre><code> indented code
+</code></pre>
+<p>paragraph</p>
+<pre><code>more code
+</code></pre>
+</li>
+</ol>
+````````````````````````````````
+
+
+Note that rules #1 and #2 only apply to two cases: (a) cases
+in which the lines to be included in a list item begin with a
+[non-whitespace character], and (b) cases in which
+they begin with an indented code
+block. In a case like the following, where the first block begins with
+a three-space indent, the rules do not allow us to form a list item by
+indenting the whole thing and prepending a list marker:
+
+```````````````````````````````` example
+ foo
+
+bar
+.
+<p>foo</p>
+<p>bar</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- foo
+
+ bar
+.
+<ul>
+<li>foo</li>
+</ul>
+<p>bar</p>
+````````````````````````````````
+
+
+This is not a significant restriction, because when a block begins
+with 1-3 spaces indent, the indentation can always be removed without
+a change in interpretation, allowing rule #1 to be applied. So, in
+the above case:
+
+```````````````````````````````` example
+- foo
+
+ bar
+.
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+3. **Item starting with a blank line.** If a sequence of lines *Ls*
+ starting with a single [blank line] constitute a (possibly empty)
+ sequence of blocks *Bs*, not separated from each other by more than
+ one blank line, and *M* is a list marker of width *W*,
+ then the result of prepending *M* to the first line of *Ls*, and
+ indenting subsequent lines of *Ls* by *W + 1* spaces, is a list
+ item with *Bs* as its contents.
+ If a line is empty, then it need not be indented. The type of the
+ list item (bullet or ordered) is determined by the type of its list
+ marker. If the list item is ordered, then it is also assigned a
+ start number, based on the ordered list marker.
+
+Here are some list items that start with a blank line but are not empty:
+
+```````````````````````````````` example
+-
+ foo
+-
+ ```
+ bar
+ ```
+-
+ baz
+.
+<ul>
+<li>foo</li>
+<li>
+<pre><code>bar
+</code></pre>
+</li>
+<li>
+<pre><code>baz
+</code></pre>
+</li>
+</ul>
+````````````````````````````````
+
+When the list item starts with a blank line, the number of spaces
+following the list marker doesn't change the required indentation:
+
+```````````````````````````````` example
+-
+ foo
+.
+<ul>
+<li>foo</li>
+</ul>
+````````````````````````````````
+
+
+A list item can begin with at most one blank line.
+In the following example, `foo` is not part of the list
+item:
+
+```````````````````````````````` example
+-
+
+ foo
+.
+<ul>
+<li></li>
+</ul>
+<p>foo</p>
+````````````````````````````````
+
+
+Here is an empty bullet list item:
+
+```````````````````````````````` example
+- foo
+-
+- bar
+.
+<ul>
+<li>foo</li>
+<li></li>
+<li>bar</li>
+</ul>
+````````````````````````````````
+
+
+It does not matter whether there are spaces following the [list marker]:
+
+```````````````````````````````` example
+- foo
+-
+- bar
+.
+<ul>
+<li>foo</li>
+<li></li>
+<li>bar</li>
+</ul>
+````````````````````````````````
+
+
+Here is an empty ordered list item:
+
+```````````````````````````````` example
+1. foo
+2.
+3. bar
+.
+<ol>
+<li>foo</li>
+<li></li>
+<li>bar</li>
+</ol>
+````````````````````````````````
+
+
+A list may start or end with an empty list item:
+
+```````````````````````````````` example
+*
+.
+<ul>
+<li></li>
+</ul>
+````````````````````````````````
+
+However, an empty list item cannot interrupt a paragraph:
+
+```````````````````````````````` example
+foo
+*
+
+foo
+1.
+.
+<p>foo
+*</p>
+<p>foo
+1.</p>
+````````````````````````````````
+
+
+4. **Indentation.** If a sequence of lines *Ls* constitutes a list item
+ according to rule #1, #2, or #3, then the result of indenting each line
+ of *Ls* by 1-3 spaces (the same for each line) also constitutes a
+ list item with the same contents and attributes. If a line is
+ empty, then it need not be indented.
+
+Indented one space:
+
+```````````````````````````````` example
+ 1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+.
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+````````````````````````````````
+
+
+Indented two spaces:
+
+```````````````````````````````` example
+ 1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+.
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+````````````````````````````````
+
+
+Indented three spaces:
+
+```````````````````````````````` example
+ 1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+.
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+````````````````````````````````
+
+
+Four spaces indent gives a code block:
+
+```````````````````````````````` example
+ 1. A paragraph
+ with two lines.
+
+ indented code
+
+ > A block quote.
+.
+<pre><code>1. A paragraph
+ with two lines.
+
+ indented code
+
+ &gt; A block quote.
+</code></pre>
+````````````````````````````````
+
+
+
+5. **Laziness.** If a string of lines *Ls* constitute a [list
+ item](#list-items) with contents *Bs*, then the result of deleting
+ some or all of the indentation from one or more lines in which the
+ next [non-whitespace character] after the indentation is
+ [paragraph continuation text] is a
+ list item with the same contents and attributes. The unindented
+ lines are called
+ [lazy continuation line](@)s.
+
+Here is an example with [lazy continuation lines]:
+
+```````````````````````````````` example
+ 1. A paragraph
+with two lines.
+
+ indented code
+
+ > A block quote.
+.
+<ol>
+<li>
+<p>A paragraph
+with two lines.</p>
+<pre><code>indented code
+</code></pre>
+<blockquote>
+<p>A block quote.</p>
+</blockquote>
+</li>
+</ol>
+````````````````````````````````
+
+
+Indentation can be partially deleted:
+
+```````````````````````````````` example
+ 1. A paragraph
+ with two lines.
+.
+<ol>
+<li>A paragraph
+with two lines.</li>
+</ol>
+````````````````````````````````
+
+
+These examples show how laziness can work in nested structures:
+
+```````````````````````````````` example
+> 1. > Blockquote
+continued here.
+.
+<blockquote>
+<ol>
+<li>
+<blockquote>
+<p>Blockquote
+continued here.</p>
+</blockquote>
+</li>
+</ol>
+</blockquote>
+````````````````````````````````
+
+
+```````````````````````````````` example
+> 1. > Blockquote
+> continued here.
+.
+<blockquote>
+<ol>
+<li>
+<blockquote>
+<p>Blockquote
+continued here.</p>
+</blockquote>
+</li>
+</ol>
+</blockquote>
+````````````````````````````````
+
+
+
+6. **That's all.** Nothing that is not counted as a list item by rules
+ #1--5 counts as a [list item](#list-items).
+
+The rules for sublists follow from the general rules
+[above][List items]. A sublist must be indented the same number
+of spaces a paragraph would need to be in order to be included
+in the list item.
+
+So, in this case we need two spaces indent:
+
+```````````````````````````````` example
+- foo
+ - bar
+ - baz
+ - boo
+.
+<ul>
+<li>foo
+<ul>
+<li>bar
+<ul>
+<li>baz
+<ul>
+<li>boo</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+````````````````````````````````
+
+
+One is not enough:
+
+```````````````````````````````` example
+- foo
+ - bar
+ - baz
+ - boo
+.
+<ul>
+<li>foo</li>
+<li>bar</li>
+<li>baz</li>
+<li>boo</li>
+</ul>
+````````````````````````````````
+
+
+Here we need four, because the list marker is wider:
+
+```````````````````````````````` example
+10) foo
+ - bar
+.
+<ol start="10">
+<li>foo
+<ul>
+<li>bar</li>
+</ul>
+</li>
+</ol>
+````````````````````````````````
+
+
+Three is not enough:
+
+```````````````````````````````` example
+10) foo
+ - bar
+.
+<ol start="10">
+<li>foo</li>
+</ol>
+<ul>
+<li>bar</li>
+</ul>
+````````````````````````````````
+
+
+A list may be the first block in a list item:
+
+```````````````````````````````` example
+- - foo
+.
+<ul>
+<li>
+<ul>
+<li>foo</li>
+</ul>
+</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+1. - 2. foo
+.
+<ol>
+<li>
+<ul>
+<li>
+<ol start="2">
+<li>foo</li>
+</ol>
+</li>
+</ul>
+</li>
+</ol>
+````````````````````````````````
+
+
+A list item can contain a heading:
+
+```````````````````````````````` example
+- # Foo
+- Bar
+ ---
+ baz
+.
+<ul>
+<li>
+<h1>Foo</h1>
+</li>
+<li>
+<h2>Bar</h2>
+baz</li>
+</ul>
+````````````````````````````````
+
+
+### Motivation
+
+John Gruber's Markdown spec says the following about list items:
+
+1. "List markers typically start at the left margin, but may be indented
+ by up to three spaces. List markers must be followed by one or more
+ spaces or a tab."
+
+2. "To make lists look nice, you can wrap items with hanging indents....
+ But if you don't want to, you don't have to."
+
+3. "List items may consist of multiple paragraphs. Each subsequent
+ paragraph in a list item must be indented by either 4 spaces or one
+ tab."
+
+4. "It looks nice if you indent every line of the subsequent paragraphs,
+ but here again, Markdown will allow you to be lazy."
+
+5. "To put a blockquote within a list item, the blockquote's `>`
+ delimiters need to be indented."
+
+6. "To put a code block within a list item, the code block needs to be
+ indented twice — 8 spaces or two tabs."
+
+These rules specify that a paragraph under a list item must be indented
+four spaces (presumably, from the left margin, rather than the start of
+the list marker, but this is not said), and that code under a list item
+must be indented eight spaces instead of the usual four. They also say
+that a block quote must be indented, but not by how much; however, the
+example given has four spaces indentation. Although nothing is said
+about other kinds of block-level content, it is certainly reasonable to
+infer that *all* block elements under a list item, including other
+lists, must be indented four spaces. This principle has been called the
+*four-space rule*.
+
+The four-space rule is clear and principled, and if the reference
+implementation `Markdown.pl` had followed it, it probably would have
+become the standard. However, `Markdown.pl` allowed paragraphs and
+sublists to start with only two spaces indentation, at least on the
+outer level. Worse, its behavior was inconsistent: a sublist of an
+outer-level list needed two spaces indentation, but a sublist of this
+sublist needed three spaces. It is not surprising, then, that different
+implementations of Markdown have developed very different rules for
+determining what comes under a list item. (Pandoc and python-Markdown,
+for example, stuck with Gruber's syntax description and the four-space
+rule, while discount, redcarpet, marked, PHP Markdown, and others
+followed `Markdown.pl`'s behavior more closely.)
+
+Unfortunately, given the divergences between implementations, there
+is no way to give a spec for list items that will be guaranteed not
+to break any existing documents. However, the spec given here should
+correctly handle lists formatted with either the four-space rule or
+the more forgiving `Markdown.pl` behavior, provided they are laid out
+in a way that is natural for a human to read.
+
+The strategy here is to let the width and indentation of the list marker
+determine the indentation necessary for blocks to fall under the list
+item, rather than having a fixed and arbitrary number. The writer can
+think of the body of the list item as a unit which gets indented to the
+right enough to fit the list marker (and any indentation on the list
+marker). (The laziness rule, #5, then allows continuation lines to be
+unindented if needed.)
+
+This rule is superior, we claim, to any rule requiring a fixed level of
+indentation from the margin. The four-space rule is clear but
+unnatural. It is quite unintuitive that
+
+``` markdown
+- foo
+
+ bar
+
+ - baz
+```
+
+should be parsed as two lists with an intervening paragraph,
+
+``` html
+<ul>
+<li>foo</li>
+</ul>
+<p>bar</p>
+<ul>
+<li>baz</li>
+</ul>
+```
+
+as the four-space rule demands, rather than a single list,
+
+``` html
+<ul>
+<li>
+<p>foo</p>
+<p>bar</p>
+<ul>
+<li>baz</li>
+</ul>
+</li>
+</ul>
+```
+
+The choice of four spaces is arbitrary. It can be learned, but it is
+not likely to be guessed, and it trips up beginners regularly.
+
+Would it help to adopt a two-space rule? The problem is that such
+a rule, together with the rule allowing 1--3 spaces indentation of the
+initial list marker, allows text that is indented *less than* the
+original list marker to be included in the list item. For example,
+`Markdown.pl` parses
+
+``` markdown
+ - one
+
+ two
+```
+
+as a single list item, with `two` a continuation paragraph:
+
+``` html
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+```
+
+and similarly
+
+``` markdown
+> - one
+>
+> two
+```
+
+as
+
+``` html
+<blockquote>
+<ul>
+<li>
+<p>one</p>
+<p>two</p>
+</li>
+</ul>
+</blockquote>
+```
+
+This is extremely unintuitive.
+
+Rather than requiring a fixed indent from the margin, we could require
+a fixed indent (say, two spaces, or even one space) from the list marker (which
+may itself be indented). This proposal would remove the last anomaly
+discussed. Unlike the spec presented above, it would count the following
+as a list item with a subparagraph, even though the paragraph `bar`
+is not indented as far as the first paragraph `foo`:
+
+``` markdown
+ 10. foo
+
+ bar
+```
+
+Arguably this text does read like a list item with `bar` as a subparagraph,
+which may count in favor of the proposal. However, on this proposal indented
+code would have to be indented six spaces after the list marker. And this
+would break a lot of existing Markdown, which has the pattern:
+
+``` markdown
+1. foo
+
+ indented code
+```
+
+where the code is indented eight spaces. The spec above, by contrast, will
+parse this text as expected, since the code block's indentation is measured
+from the beginning of `foo`.
+
+The one case that needs special treatment is a list item that *starts*
+with indented code. How much indentation is required in that case, since
+we don't have a "first paragraph" to measure from? Rule #2 simply stipulates
+that in such cases, we require one space indentation from the list marker
+(and then the normal four spaces for the indented code). This will match the
+four-space rule in cases where the list marker plus its initial indentation
+takes four spaces (a common case), but diverge in other cases.
+
+<div class="extension">
+
+## Task list items (extension)
+
+GFM enables the `tasklist` extension, where an additional processing step is
+performed on [list items].
+
+A [task list item](@) is a [list item][list items] where the first block in it
+is a paragraph which begins with a [task list item marker] and at least one
+whitespace character before any other content.
+
+A [task list item marker](@) consists of an optional number of spaces, a left
+bracket (`[`), either a whitespace character or the letter `x` in either
+lowercase or uppercase, and then a right bracket (`]`).
+
+When rendered, the [task list item marker] is replaced with a semantic checkbox element;
+in an HTML output, this would be an `<input type="checkbox">` element.
+
+If the character between the brackets is a whitespace character, the checkbox
+is unchecked. Otherwise, the checkbox is checked.
+
+This spec does not define how the checkbox elements are interacted with: in practice,
+implementors are free to render the checkboxes as disabled or inmutable elements,
+or they may dynamically handle dynamic interactions (i.e. checking, unchecking) in
+the final rendered document.
+
+```````````````````````````````` example disabled
+- [ ] foo
+- [x] bar
+.
+<ul>
+<li><input disabled="" type="checkbox"> foo</li>
+<li><input checked="" disabled="" type="checkbox"> bar</li>
+</ul>
+````````````````````````````````
+
+Task lists can be arbitrarily nested:
+
+```````````````````````````````` example disabled
+- [x] foo
+ - [ ] bar
+ - [x] baz
+- [ ] bim
+.
+<ul>
+<li><input checked="" disabled="" type="checkbox"> foo
+<ul>
+<li><input disabled="" type="checkbox"> bar</li>
+<li><input checked="" disabled="" type="checkbox"> baz</li>
+</ul>
+</li>
+<li><input disabled="" type="checkbox"> bim</li>
+</ul>
+````````````````````````````````
+
+</div>
+
+## Lists
+
+A [list](@) is a sequence of one or more
+list items [of the same type]. The list items
+may be separated by any number of blank lines.
+
+Two list items are [of the same type](@)
+if they begin with a [list marker] of the same type.
+Two list markers are of the
+same type if (a) they are bullet list markers using the same character
+(`-`, `+`, or `*`) or (b) they are ordered list numbers with the same
+delimiter (either `.` or `)`).
+
+A list is an [ordered list](@)
+if its constituent list items begin with
+[ordered list markers], and a
+[bullet list](@) if its constituent list
+items begin with [bullet list markers].
+
+The [start number](@)
+of an [ordered list] is determined by the list number of
+its initial list item. The numbers of subsequent list items are
+disregarded.
+
+A list is [loose](@) if any of its constituent
+list items are separated by blank lines, or if any of its constituent
+list items directly contain two block-level elements with a blank line
+between them. Otherwise a list is [tight](@).
+(The difference in HTML output is that paragraphs in a loose list are
+wrapped in `<p>` tags, while paragraphs in a tight list are not.)
+
+Changing the bullet or ordered list delimiter starts a new list:
+
+```````````````````````````````` example
+- foo
+- bar
++ baz
+.
+<ul>
+<li>foo</li>
+<li>bar</li>
+</ul>
+<ul>
+<li>baz</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+1. foo
+2. bar
+3) baz
+.
+<ol>
+<li>foo</li>
+<li>bar</li>
+</ol>
+<ol start="3">
+<li>baz</li>
+</ol>
+````````````````````````````````
+
+
+In CommonMark, a list can interrupt a paragraph. That is,
+no blank line is needed to separate a paragraph from a following
+list:
+
+```````````````````````````````` example
+Foo
+- bar
+- baz
+.
+<p>Foo</p>
+<ul>
+<li>bar</li>
+<li>baz</li>
+</ul>
+````````````````````````````````
+
+`Markdown.pl` does not allow this, through fear of triggering a list
+via a numeral in a hard-wrapped line:
+
+``` markdown
+The number of windows in my house is
+14. The number of doors is 6.
+```
+
+Oddly, though, `Markdown.pl` *does* allow a blockquote to
+interrupt a paragraph, even though the same considerations might
+apply.
+
+In CommonMark, we do allow lists to interrupt paragraphs, for
+two reasons. First, it is natural and not uncommon for people
+to start lists without blank lines:
+
+``` markdown
+I need to buy
+- new shoes
+- a coat
+- a plane ticket
+```
+
+Second, we are attracted to a
+
+> [principle of uniformity](@):
+> if a chunk of text has a certain
+> meaning, it will continue to have the same meaning when put into a
+> container block (such as a list item or blockquote).
+
+(Indeed, the spec for [list items] and [block quotes] presupposes
+this principle.) This principle implies that if
+
+``` markdown
+ * I need to buy
+ - new shoes
+ - a coat
+ - a plane ticket
+```
+
+is a list item containing a paragraph followed by a nested sublist,
+as all Markdown implementations agree it is (though the paragraph
+may be rendered without `<p>` tags, since the list is "tight"),
+then
+
+``` markdown
+I need to buy
+- new shoes
+- a coat
+- a plane ticket
+```
+
+by itself should be a paragraph followed by a nested sublist.
+
+Since it is well established Markdown practice to allow lists to
+interrupt paragraphs inside list items, the [principle of
+uniformity] requires us to allow this outside list items as
+well. ([reStructuredText](http://docutils.sourceforge.net/rst.html)
+takes a different approach, requiring blank lines before lists
+even inside other list items.)
+
+In order to solve of unwanted lists in paragraphs with
+hard-wrapped numerals, we allow only lists starting with `1` to
+interrupt paragraphs. Thus,
+
+```````````````````````````````` example
+The number of windows in my house is
+14. The number of doors is 6.
+.
+<p>The number of windows in my house is
+14. The number of doors is 6.</p>
+````````````````````````````````
+
+We may still get an unintended result in cases like
+
+```````````````````````````````` example
+The number of windows in my house is
+1. The number of doors is 6.
+.
+<p>The number of windows in my house is</p>
+<ol>
+<li>The number of doors is 6.</li>
+</ol>
+````````````````````````````````
+
+but this rule should prevent most spurious list captures.
+
+There can be any number of blank lines between items:
+
+```````````````````````````````` example
+- foo
+
+- bar
+
+
+- baz
+.
+<ul>
+<li>
+<p>foo</p>
+</li>
+<li>
+<p>bar</p>
+</li>
+<li>
+<p>baz</p>
+</li>
+</ul>
+````````````````````````````````
+
+```````````````````````````````` example
+- foo
+ - bar
+ - baz
+
+
+ bim
+.
+<ul>
+<li>foo
+<ul>
+<li>bar
+<ul>
+<li>
+<p>baz</p>
+<p>bim</p>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+````````````````````````````````
+
+
+To separate consecutive lists of the same type, or to separate a
+list from an indented code block that would otherwise be parsed
+as a subparagraph of the final list item, you can insert a blank HTML
+comment:
+
+```````````````````````````````` example
+- foo
+- bar
+
+<!-- -->
+
+- baz
+- bim
+.
+<ul>
+<li>foo</li>
+<li>bar</li>
+</ul>
+<!-- -->
+<ul>
+<li>baz</li>
+<li>bim</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- foo
+
+ notcode
+
+- foo
+
+<!-- -->
+
+ code
+.
+<ul>
+<li>
+<p>foo</p>
+<p>notcode</p>
+</li>
+<li>
+<p>foo</p>
+</li>
+</ul>
+<!-- -->
+<pre><code>code
+</code></pre>
+````````````````````````````````
+
+
+List items need not be indented to the same level. The following
+list items will be treated as items at the same list level,
+since none is indented enough to belong to the previous list
+item:
+
+```````````````````````````````` example
+- a
+ - b
+ - c
+ - d
+ - e
+ - f
+- g
+.
+<ul>
+<li>a</li>
+<li>b</li>
+<li>c</li>
+<li>d</li>
+<li>e</li>
+<li>f</li>
+<li>g</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+1. a
+
+ 2. b
+
+ 3. c
+.
+<ol>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+<li>
+<p>c</p>
+</li>
+</ol>
+````````````````````````````````
+
+Note, however, that list items may not be indented more than
+three spaces. Here `- e` is treated as a paragraph continuation
+line, because it is indented more than three spaces:
+
+```````````````````````````````` example
+- a
+ - b
+ - c
+ - d
+ - e
+.
+<ul>
+<li>a</li>
+<li>b</li>
+<li>c</li>
+<li>d
+- e</li>
+</ul>
+````````````````````````````````
+
+And here, `3. c` is treated as in indented code block,
+because it is indented four spaces and preceded by a
+blank line.
+
+```````````````````````````````` example
+1. a
+
+ 2. b
+
+ 3. c
+.
+<ol>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+</ol>
+<pre><code>3. c
+</code></pre>
+````````````````````````````````
+
+
+This is a loose list, because there is a blank line between
+two of the list items:
+
+```````````````````````````````` example
+- a
+- b
+
+- c
+.
+<ul>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+<li>
+<p>c</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+So is this, with a empty second item:
+
+```````````````````````````````` example
+* a
+*
+
+* c
+.
+<ul>
+<li>
+<p>a</p>
+</li>
+<li></li>
+<li>
+<p>c</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+These are loose lists, even though there is no space between the items,
+because one of the items directly contains two block-level elements
+with a blank line between them:
+
+```````````````````````````````` example
+- a
+- b
+
+ c
+- d
+.
+<ul>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+<p>c</p>
+</li>
+<li>
+<p>d</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- a
+- b
+
+ [ref]: /url
+- d
+.
+<ul>
+<li>
+<p>a</p>
+</li>
+<li>
+<p>b</p>
+</li>
+<li>
+<p>d</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+This is a tight list, because the blank lines are in a code block:
+
+```````````````````````````````` example
+- a
+- ```
+ b
+
+
+ ```
+- c
+.
+<ul>
+<li>a</li>
+<li>
+<pre><code>b
+
+
+</code></pre>
+</li>
+<li>c</li>
+</ul>
+````````````````````````````````
+
+
+This is a tight list, because the blank line is between two
+paragraphs of a sublist. So the sublist is loose while
+the outer list is tight:
+
+```````````````````````````````` example
+- a
+ - b
+
+ c
+- d
+.
+<ul>
+<li>a
+<ul>
+<li>
+<p>b</p>
+<p>c</p>
+</li>
+</ul>
+</li>
+<li>d</li>
+</ul>
+````````````````````````````````
+
+
+This is a tight list, because the blank line is inside the
+block quote:
+
+```````````````````````````````` example
+* a
+ > b
+ >
+* c
+.
+<ul>
+<li>a
+<blockquote>
+<p>b</p>
+</blockquote>
+</li>
+<li>c</li>
+</ul>
+````````````````````````````````
+
+
+This list is tight, because the consecutive block elements
+are not separated by blank lines:
+
+```````````````````````````````` example
+- a
+ > b
+ ```
+ c
+ ```
+- d
+.
+<ul>
+<li>a
+<blockquote>
+<p>b</p>
+</blockquote>
+<pre><code>c
+</code></pre>
+</li>
+<li>d</li>
+</ul>
+````````````````````````````````
+
+
+A single-paragraph list is tight:
+
+```````````````````````````````` example
+- a
+.
+<ul>
+<li>a</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- a
+ - b
+.
+<ul>
+<li>a
+<ul>
+<li>b</li>
+</ul>
+</li>
+</ul>
+````````````````````````````````
+
+
+This list is loose, because of the blank line between the
+two block elements in the list item:
+
+```````````````````````````````` example
+1. ```
+ foo
+ ```
+
+ bar
+.
+<ol>
+<li>
+<pre><code>foo
+</code></pre>
+<p>bar</p>
+</li>
+</ol>
+````````````````````````````````
+
+
+Here the outer list is loose, the inner list tight:
+
+```````````````````````````````` example
+* foo
+ * bar
+
+ baz
+.
+<ul>
+<li>
+<p>foo</p>
+<ul>
+<li>bar</li>
+</ul>
+<p>baz</p>
+</li>
+</ul>
+````````````````````````````````
+
+
+```````````````````````````````` example
+- a
+ - b
+ - c
+
+- d
+ - e
+ - f
+.
+<ul>
+<li>
+<p>a</p>
+<ul>
+<li>b</li>
+<li>c</li>
+</ul>
+</li>
+<li>
+<p>d</p>
+<ul>
+<li>e</li>
+<li>f</li>
+</ul>
+</li>
+</ul>
+````````````````````````````````
+
+
+# Inlines
+
+Inlines are parsed sequentially from the beginning of the character
+stream to the end (left to right, in left-to-right languages).
+Thus, for example, in
+
+```````````````````````````````` example
+`hi`lo`
+.
+<p><code>hi</code>lo`</p>
+````````````````````````````````
+
+`hi` is parsed as code, leaving the backtick at the end as a literal
+backtick.
+
+
+## Backslash escapes
+
+Any ASCII punctuation character may be backslash-escaped:
+
+```````````````````````````````` example
+\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~
+.
+<p>!&quot;#$%&amp;'()*+,-./:;&lt;=&gt;?@[\]^_`{|}~</p>
+````````````````````````````````
+
+
+Backslashes before other characters are treated as literal
+backslashes:
+
+```````````````````````````````` example
+\→\A\a\ \3\φ\«
+.
+<p>\→\A\a\ \3\φ\«</p>
+````````````````````````````````
+
+
+Escaped characters are treated as regular characters and do
+not have their usual Markdown meanings:
+
+```````````````````````````````` example
+\*not emphasized*
+\<br/> not a tag
+\[not a link](/foo)
+\`not code`
+1\. not a list
+\* not a list
+\# not a heading
+\[foo]: /url "not a reference"
+\&ouml; not a character entity
+.
+<p>*not emphasized*
+&lt;br/&gt; not a tag
+[not a link](/foo)
+`not code`
+1. not a list
+* not a list
+# not a heading
+[foo]: /url &quot;not a reference&quot;
+&amp;ouml; not a character entity</p>
+````````````````````````````````
+
+
+If a backslash is itself escaped, the following character is not:
+
+```````````````````````````````` example
+\\*emphasis*
+.
+<p>\<em>emphasis</em></p>
+````````````````````````````````
+
+
+A backslash at the end of the line is a [hard line break]:
+
+```````````````````````````````` example
+foo\
+bar
+.
+<p>foo<br />
+bar</p>
+````````````````````````````````
+
+
+Backslash escapes do not work in code blocks, code spans, autolinks, or
+raw HTML:
+
+```````````````````````````````` example
+`` \[\` ``
+.
+<p><code>\[\`</code></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ \[\]
+.
+<pre><code>\[\]
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+~~~
+\[\]
+~~~
+.
+<pre><code>\[\]
+</code></pre>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<http://example.com?find=\*>
+.
+<p><a href="http://example.com?find=%5C*">http://example.com?find=\*</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<a href="/bar\/)">
+.
+<a href="/bar\/)">
+````````````````````````````````
+
+
+But they work in all other contexts, including URLs and link titles,
+link references, and [info strings] in [fenced code blocks]:
+
+```````````````````````````````` example
+[foo](/bar\* "ti\*tle")
+.
+<p><a href="/bar*" title="ti*tle">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo]
+
+[foo]: /bar\* "ti\*tle"
+.
+<p><a href="/bar*" title="ti*tle">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+``` foo\+bar
+foo
+```
+.
+<pre><code class="language-foo+bar">foo
+</code></pre>
+````````````````````````````````
+
+
+
+## Entity and numeric character references
+
+Valid HTML entity references and numeric character references
+can be used in place of the corresponding Unicode character,
+with the following exceptions:
+
+- Entity and character references are not recognized in code
+ blocks and code spans.
+
+- Entity and character references cannot stand in place of
+ special characters that define structural elements in
+ CommonMark. For example, although `&#42;` can be used
+ in place of a literal `*` character, `&#42;` cannot replace
+ `*` in emphasis delimiters, bullet list markers, or thematic
+ breaks.
+
+Conforming CommonMark parsers need not store information about
+whether a particular character was represented in the source
+using a Unicode character or an entity reference.
+
+[Entity references](@) consist of `&` + any of the valid
+HTML5 entity names + `;`. The
+document <https://html.spec.whatwg.org/multipage/entities.json>
+is used as an authoritative source for the valid entity
+references and their corresponding code points.
+
+```````````````````````````````` example
+&nbsp; &amp; &copy; &AElig; &Dcaron;
+&frac34; &HilbertSpace; &DifferentialD;
+&ClockwiseContourIntegral; &ngE;
+.
+<p>  &amp; © Æ Ď
+¾ ℋ ⅆ
+∲ ≧̸</p>
+````````````````````````````````
+
+
+[Decimal numeric character
+references](@)
+consist of `&#` + a string of 1--7 arabic digits + `;`. A
+numeric character reference is parsed as the corresponding
+Unicode character. Invalid Unicode code points will be replaced by
+the REPLACEMENT CHARACTER (`U+FFFD`). For security reasons,
+the code point `U+0000` will also be replaced by `U+FFFD`.
+
+```````````````````````````````` example
+&#35; &#1234; &#992; &#0;
+.
+<p># Ӓ Ϡ �</p>
+````````````````````````````````
+
+
+[Hexadecimal numeric character
+references](@) consist of `&#` +
+either `X` or `x` + a string of 1-6 hexadecimal digits + `;`.
+They too are parsed as the corresponding Unicode character (this
+time specified with a hexadecimal numeral instead of decimal).
+
+```````````````````````````````` example
+&#X22; &#XD06; &#xcab;
+.
+<p>&quot; ആ ಫ</p>
+````````````````````````````````
+
+
+Here are some nonentities:
+
+```````````````````````````````` example
+&nbsp &x; &#; &#x;
+&#987654321;
+&#abcdef0;
+&ThisIsNotDefined; &hi?;
+.
+<p>&amp;nbsp &amp;x; &amp;#; &amp;#x;
+&amp;#987654321;
+&amp;#abcdef0;
+&amp;ThisIsNotDefined; &amp;hi?;</p>
+````````````````````````````````
+
+
+Although HTML5 does accept some entity references
+without a trailing semicolon (such as `&copy`), these are not
+recognized here, because it makes the grammar too ambiguous:
+
+```````````````````````````````` example
+&copy
+.
+<p>&amp;copy</p>
+````````````````````````````````
+
+
+Strings that are not on the list of HTML5 named entities are not
+recognized as entity references either:
+
+```````````````````````````````` example
+&MadeUpEntity;
+.
+<p>&amp;MadeUpEntity;</p>
+````````````````````````````````
+
+
+Entity and numeric character references are recognized in any
+context besides code spans or code blocks, including
+URLs, [link titles], and [fenced code block][] [info strings]:
+
+```````````````````````````````` example
+<a href="&ouml;&ouml;.html">
+.
+<a href="&ouml;&ouml;.html">
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo](/f&ouml;&ouml; "f&ouml;&ouml;")
+.
+<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo]
+
+[foo]: /f&ouml;&ouml; "f&ouml;&ouml;"
+.
+<p><a href="/f%C3%B6%C3%B6" title="föö">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+``` f&ouml;&ouml;
+foo
+```
+.
+<pre><code class="language-föö">foo
+</code></pre>
+````````````````````````````````
+
+
+Entity and numeric character references are treated as literal
+text in code spans and code blocks:
+
+```````````````````````````````` example
+`f&ouml;&ouml;`
+.
+<p><code>f&amp;ouml;&amp;ouml;</code></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+ f&ouml;f&ouml;
+.
+<pre><code>f&amp;ouml;f&amp;ouml;
+</code></pre>
+````````````````````````````````
+
+
+Entity and numeric character references cannot be used
+in place of symbols indicating structure in CommonMark
+documents.
+
+```````````````````````````````` example
+&#42;foo&#42;
+*foo*
+.
+<p>*foo*
+<em>foo</em></p>
+````````````````````````````````
+
+```````````````````````````````` example
+&#42; foo
+
+* foo
+.
+<p>* foo</p>
+<ul>
+<li>foo</li>
+</ul>
+````````````````````````````````
+
+```````````````````````````````` example
+foo&#10;&#10;bar
+.
+<p>foo
+
+bar</p>
+````````````````````````````````
+
+```````````````````````````````` example
+&#9;foo
+.
+<p>→foo</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[a](url &quot;tit&quot;)
+.
+<p>[a](url &quot;tit&quot;)</p>
+````````````````````````````````
+
+
+## Code spans
+
+A [backtick string](@)
+is a string of one or more backtick characters (`` ` ``) that is neither
+preceded nor followed by a backtick.
+
+A [code span](@) begins with a backtick string and ends with
+a backtick string of equal length. The contents of the code span are
+the characters between the two backtick strings, normalized in the
+following ways:
+
+- First, [line endings] are converted to [spaces].
+- If the resulting string both begins *and* ends with a [space]
+ character, but does not consist entirely of [space]
+ characters, a single [space] character is removed from the
+ front and back. This allows you to include code that begins
+ or ends with backtick characters, which must be separated by
+ whitespace from the opening or closing backtick strings.
+
+This is a simple code span:
+
+```````````````````````````````` example
+`foo`
+.
+<p><code>foo</code></p>
+````````````````````````````````
+
+
+Here two backticks are used, because the code contains a backtick.
+This example also illustrates stripping of a single leading and
+trailing space:
+
+```````````````````````````````` example
+`` foo ` bar ``
+.
+<p><code>foo ` bar</code></p>
+````````````````````````````````
+
+
+This example shows the motivation for stripping leading and trailing
+spaces:
+
+```````````````````````````````` example
+` `` `
+.
+<p><code>``</code></p>
+````````````````````````````````
+
+Note that only *one* space is stripped:
+
+```````````````````````````````` example
+` `` `
+.
+<p><code> `` </code></p>
+````````````````````````````````
+
+The stripping only happens if the space is on both
+sides of the string:
+
+```````````````````````````````` example
+` a`
+.
+<p><code> a</code></p>
+````````````````````````````````
+
+Only [spaces], and not [unicode whitespace] in general, are
+stripped in this way:
+
+```````````````````````````````` example
+` b `
+.
+<p><code> b </code></p>
+````````````````````````````````
+
+No stripping occurs if the code span contains only spaces:
+
+```````````````````````````````` example
+` `
+` `
+.
+<p><code> </code>
+<code> </code></p>
+````````````````````````````````
+
+
+[Line endings] are treated like spaces:
+
+```````````````````````````````` example
+``
+foo
+bar
+baz
+``
+.
+<p><code>foo bar baz</code></p>
+````````````````````````````````
+
+```````````````````````````````` example
+``
+foo
+``
+.
+<p><code>foo </code></p>
+````````````````````````````````
+
+
+Interior spaces are not collapsed:
+
+```````````````````````````````` example
+`foo bar
+baz`
+.
+<p><code>foo bar baz</code></p>
+````````````````````````````````
+
+Note that browsers will typically collapse consecutive spaces
+when rendering `<code>` elements, so it is recommended that
+the following CSS be used:
+
+ code{white-space: pre-wrap;}
+
+
+Note that backslash escapes do not work in code spans. All backslashes
+are treated literally:
+
+```````````````````````````````` example
+`foo\`bar`
+.
+<p><code>foo\</code>bar`</p>
+````````````````````````````````
+
+
+Backslash escapes are never needed, because one can always choose a
+string of *n* backtick characters as delimiters, where the code does
+not contain any strings of exactly *n* backtick characters.
+
+```````````````````````````````` example
+``foo`bar``
+.
+<p><code>foo`bar</code></p>
+````````````````````````````````
+
+```````````````````````````````` example
+` foo `` bar `
+.
+<p><code>foo `` bar</code></p>
+````````````````````````````````
+
+
+Code span backticks have higher precedence than any other inline
+constructs except HTML tags and autolinks. Thus, for example, this is
+not parsed as emphasized text, since the second `*` is part of a code
+span:
+
+```````````````````````````````` example
+*foo`*`
+.
+<p>*foo<code>*</code></p>
+````````````````````````````````
+
+
+And this is not parsed as a link:
+
+```````````````````````````````` example
+[not a `link](/foo`)
+.
+<p>[not a <code>link](/foo</code>)</p>
+````````````````````````````````
+
+
+Code spans, HTML tags, and autolinks have the same precedence.
+Thus, this is code:
+
+```````````````````````````````` example
+`<a href="`">`
+.
+<p><code>&lt;a href=&quot;</code>&quot;&gt;`</p>
+````````````````````````````````
+
+
+But this is an HTML tag:
+
+```````````````````````````````` example
+<a href="`">`
+.
+<p><a href="`">`</p>
+````````````````````````````````
+
+
+And this is code:
+
+```````````````````````````````` example
+`<http://foo.bar.`baz>`
+.
+<p><code>&lt;http://foo.bar.</code>baz&gt;`</p>
+````````````````````````````````
+
+
+But this is an autolink:
+
+```````````````````````````````` example
+<http://foo.bar.`baz>`
+.
+<p><a href="http://foo.bar.%60baz">http://foo.bar.`baz</a>`</p>
+````````````````````````````````
+
+
+When a backtick string is not closed by a matching backtick string,
+we just have literal backticks:
+
+```````````````````````````````` example
+```foo``
+.
+<p>```foo``</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+`foo
+.
+<p>`foo</p>
+````````````````````````````````
+
+The following case also illustrates the need for opening and
+closing backtick strings to be equal in length:
+
+```````````````````````````````` example
+`foo``bar``
+.
+<p>`foo<code>bar</code></p>
+````````````````````````````````
+
+
+## Emphasis and strong emphasis
+
+John Gruber's original [Markdown syntax
+description](http://daringfireball.net/projects/markdown/syntax#em) says:
+
+> Markdown treats asterisks (`*`) and underscores (`_`) as indicators of
+> emphasis. Text wrapped with one `*` or `_` will be wrapped with an HTML
+> `<em>` tag; double `*`'s or `_`'s will be wrapped with an HTML `<strong>`
+> tag.
+
+This is enough for most users, but these rules leave much undecided,
+especially when it comes to nested emphasis. The original
+`Markdown.pl` test suite makes it clear that triple `***` and
+`___` delimiters can be used for strong emphasis, and most
+implementations have also allowed the following patterns:
+
+``` markdown
+***strong emph***
+***strong** in emph*
+***emph* in strong**
+**in strong *emph***
+*in emph **strong***
+```
+
+The following patterns are less widely supported, but the intent
+is clear and they are useful (especially in contexts like bibliography
+entries):
+
+``` markdown
+*emph *with emph* in it*
+**strong **with strong** in it**
+```
+
+Many implementations have also restricted intraword emphasis to
+the `*` forms, to avoid unwanted emphasis in words containing
+internal underscores. (It is best practice to put these in code
+spans, but users often do not.)
+
+``` markdown
+internal emphasis: foo*bar*baz
+no emphasis: foo_bar_baz
+```
+
+The rules given below capture all of these patterns, while allowing
+for efficient parsing strategies that do not backtrack.
+
+First, some definitions. A [delimiter run](@) is either
+a sequence of one or more `*` characters that is not preceded or
+followed by a non-backslash-escaped `*` character, or a sequence
+of one or more `_` characters that is not preceded or followed by
+a non-backslash-escaped `_` character.
+
+A [left-flanking delimiter run](@) is
+a [delimiter run] that is (1) not followed by [Unicode whitespace],
+and either (2a) not followed by a [punctuation character], or
+(2b) followed by a [punctuation character] and
+preceded by [Unicode whitespace] or a [punctuation character].
+For purposes of this definition, the beginning and the end of
+the line count as Unicode whitespace.
+
+A [right-flanking delimiter run](@) is
+a [delimiter run] that is (1) not preceded by [Unicode whitespace],
+and either (2a) not preceded by a [punctuation character], or
+(2b) preceded by a [punctuation character] and
+followed by [Unicode whitespace] or a [punctuation character].
+For purposes of this definition, the beginning and the end of
+the line count as Unicode whitespace.
+
+Here are some examples of delimiter runs.
+
+ - left-flanking but not right-flanking:
+
+ ```
+ ***abc
+ _abc
+ **"abc"
+ _"abc"
+ ```
+
+ - right-flanking but not left-flanking:
+
+ ```
+ abc***
+ abc_
+ "abc"**
+ "abc"_
+ ```
+
+ - Both left and right-flanking:
+
+ ```
+ abc***def
+ "abc"_"def"
+ ```
+
+ - Neither left nor right-flanking:
+
+ ```
+ abc *** def
+ a _ b
+ ```
+
+(The idea of distinguishing left-flanking and right-flanking
+delimiter runs based on the character before and the character
+after comes from Roopesh Chander's
+[vfmd](http://www.vfmd.org/vfmd-spec/specification/#procedure-for-identifying-emphasis-tags).
+vfmd uses the terminology "emphasis indicator string" instead of "delimiter
+run," and its rules for distinguishing left- and right-flanking runs
+are a bit more complex than the ones given here.)
+
+The following rules define emphasis and strong emphasis:
+
+1. A single `*` character [can open emphasis](@)
+ iff (if and only if) it is part of a [left-flanking delimiter run].
+
+2. A single `_` character [can open emphasis] iff
+ it is part of a [left-flanking delimiter run]
+ and either (a) not part of a [right-flanking delimiter run]
+ or (b) part of a [right-flanking delimiter run]
+ preceded by punctuation.
+
+3. A single `*` character [can close emphasis](@)
+ iff it is part of a [right-flanking delimiter run].
+
+4. A single `_` character [can close emphasis] iff
+ it is part of a [right-flanking delimiter run]
+ and either (a) not part of a [left-flanking delimiter run]
+ or (b) part of a [left-flanking delimiter run]
+ followed by punctuation.
+
+5. A double `**` [can open strong emphasis](@)
+ iff it is part of a [left-flanking delimiter run].
+
+6. A double `__` [can open strong emphasis] iff
+ it is part of a [left-flanking delimiter run]
+ and either (a) not part of a [right-flanking delimiter run]
+ or (b) part of a [right-flanking delimiter run]
+ preceded by punctuation.
+
+7. A double `**` [can close strong emphasis](@)
+ iff it is part of a [right-flanking delimiter run].
+
+8. A double `__` [can close strong emphasis] iff
+ it is part of a [right-flanking delimiter run]
+ and either (a) not part of a [left-flanking delimiter run]
+ or (b) part of a [left-flanking delimiter run]
+ followed by punctuation.
+
+9. Emphasis begins with a delimiter that [can open emphasis] and ends
+ with a delimiter that [can close emphasis], and that uses the same
+ character (`_` or `*`) as the opening delimiter. The
+ opening and closing delimiters must belong to separate
+ [delimiter runs]. If one of the delimiters can both
+ open and close emphasis, then the sum of the lengths of the
+ delimiter runs containing the opening and closing delimiters
+ must not be a multiple of 3 unless both lengths are
+ multiples of 3.
+
+10. Strong emphasis begins with a delimiter that
+ [can open strong emphasis] and ends with a delimiter that
+ [can close strong emphasis], and that uses the same character
+ (`_` or `*`) as the opening delimiter. The
+ opening and closing delimiters must belong to separate
+ [delimiter runs]. If one of the delimiters can both open
+ and close strong emphasis, then the sum of the lengths of
+ the delimiter runs containing the opening and closing
+ delimiters must not be a multiple of 3 unless both lengths
+ are multiples of 3.
+
+11. A literal `*` character cannot occur at the beginning or end of
+ `*`-delimited emphasis or `**`-delimited strong emphasis, unless it
+ is backslash-escaped.
+
+12. A literal `_` character cannot occur at the beginning or end of
+ `_`-delimited emphasis or `__`-delimited strong emphasis, unless it
+ is backslash-escaped.
+
+Where rules 1--12 above are compatible with multiple parsings,
+the following principles resolve ambiguity:
+
+13. The number of nestings should be minimized. Thus, for example,
+ an interpretation `<strong>...</strong>` is always preferred to
+ `<em><em>...</em></em>`.
+
+14. An interpretation `<em><strong>...</strong></em>` is always
+ preferred to `<strong><em>...</em></strong>`.
+
+15. When two potential emphasis or strong emphasis spans overlap,
+ so that the second begins before the first ends and ends after
+ the first ends, the first takes precedence. Thus, for example,
+ `*foo _bar* baz_` is parsed as `<em>foo _bar</em> baz_` rather
+ than `*foo <em>bar* baz</em>`.
+
+16. When there are two potential emphasis or strong emphasis spans
+ with the same closing delimiter, the shorter one (the one that
+ opens later) takes precedence. Thus, for example,
+ `**foo **bar baz**` is parsed as `**foo <strong>bar baz</strong>`
+ rather than `<strong>foo **bar baz</strong>`.
+
+17. Inline code spans, links, images, and HTML tags group more tightly
+ than emphasis. So, when there is a choice between an interpretation
+ that contains one of these elements and one that does not, the
+ former always wins. Thus, for example, `*[foo*](bar)` is
+ parsed as `*<a href="bar">foo*</a>` rather than as
+ `<em>[foo</em>](bar)`.
+
+These rules can be illustrated through a series of examples.
+
+Rule 1:
+
+```````````````````````````````` example
+*foo bar*
+.
+<p><em>foo bar</em></p>
+````````````````````````````````
+
+
+This is not emphasis, because the opening `*` is followed by
+whitespace, and hence not part of a [left-flanking delimiter run]:
+
+```````````````````````````````` example
+a * foo bar*
+.
+<p>a * foo bar*</p>
+````````````````````````````````
+
+
+This is not emphasis, because the opening `*` is preceded
+by an alphanumeric and followed by punctuation, and hence
+not part of a [left-flanking delimiter run]:
+
+```````````````````````````````` example
+a*"foo"*
+.
+<p>a*&quot;foo&quot;*</p>
+````````````````````````````````
+
+
+Unicode nonbreaking spaces count as whitespace, too:
+
+```````````````````````````````` example
+* a *
+.
+<p>* a *</p>
+````````````````````````````````
+
+
+Intraword emphasis with `*` is permitted:
+
+```````````````````````````````` example
+foo*bar*
+.
+<p>foo<em>bar</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+5*6*78
+.
+<p>5<em>6</em>78</p>
+````````````````````````````````
+
+
+Rule 2:
+
+```````````````````````````````` example
+_foo bar_
+.
+<p><em>foo bar</em></p>
+````````````````````````````````
+
+
+This is not emphasis, because the opening `_` is followed by
+whitespace:
+
+```````````````````````````````` example
+_ foo bar_
+.
+<p>_ foo bar_</p>
+````````````````````````````````
+
+
+This is not emphasis, because the opening `_` is preceded
+by an alphanumeric and followed by punctuation:
+
+```````````````````````````````` example
+a_"foo"_
+.
+<p>a_&quot;foo&quot;_</p>
+````````````````````````````````
+
+
+Emphasis with `_` is not allowed inside words:
+
+```````````````````````````````` example
+foo_bar_
+.
+<p>foo_bar_</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+5_6_78
+.
+<p>5_6_78</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+приÑтанÑм_ÑтремÑÑ‚ÑÑ_
+.
+<p>приÑтанÑм_ÑтремÑÑ‚ÑÑ_</p>
+````````````````````````````````
+
+
+Here `_` does not generate emphasis, because the first delimiter run
+is right-flanking and the second left-flanking:
+
+```````````````````````````````` example
+aa_"bb"_cc
+.
+<p>aa_&quot;bb&quot;_cc</p>
+````````````````````````````````
+
+
+This is emphasis, even though the opening delimiter is
+both left- and right-flanking, because it is preceded by
+punctuation:
+
+```````````````````````````````` example
+foo-_(bar)_
+.
+<p>foo-<em>(bar)</em></p>
+````````````````````````````````
+
+
+Rule 3:
+
+This is not emphasis, because the closing delimiter does
+not match the opening delimiter:
+
+```````````````````````````````` example
+_foo*
+.
+<p>_foo*</p>
+````````````````````````````````
+
+
+This is not emphasis, because the closing `*` is preceded by
+whitespace:
+
+```````````````````````````````` example
+*foo bar *
+.
+<p>*foo bar *</p>
+````````````````````````````````
+
+
+A newline also counts as whitespace:
+
+```````````````````````````````` example
+*foo bar
+*
+.
+<p>*foo bar
+*</p>
+````````````````````````````````
+
+
+This is not emphasis, because the second `*` is
+preceded by punctuation and followed by an alphanumeric
+(hence it is not part of a [right-flanking delimiter run]:
+
+```````````````````````````````` example
+*(*foo)
+.
+<p>*(*foo)</p>
+````````````````````````````````
+
+
+The point of this restriction is more easily appreciated
+with this example:
+
+```````````````````````````````` example
+*(*foo*)*
+.
+<p><em>(<em>foo</em>)</em></p>
+````````````````````````````````
+
+
+Intraword emphasis with `*` is allowed:
+
+```````````````````````````````` example
+*foo*bar
+.
+<p><em>foo</em>bar</p>
+````````````````````````````````
+
+
+
+Rule 4:
+
+This is not emphasis, because the closing `_` is preceded by
+whitespace:
+
+```````````````````````````````` example
+_foo bar _
+.
+<p>_foo bar _</p>
+````````````````````````````````
+
+
+This is not emphasis, because the second `_` is
+preceded by punctuation and followed by an alphanumeric:
+
+```````````````````````````````` example
+_(_foo)
+.
+<p>_(_foo)</p>
+````````````````````````````````
+
+
+This is emphasis within emphasis:
+
+```````````````````````````````` example
+_(_foo_)_
+.
+<p><em>(<em>foo</em>)</em></p>
+````````````````````````````````
+
+
+Intraword emphasis is disallowed for `_`:
+
+```````````````````````````````` example
+_foo_bar
+.
+<p>_foo_bar</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_приÑтанÑм_ÑтремÑÑ‚ÑÑ
+.
+<p>_приÑтанÑм_ÑтремÑÑ‚ÑÑ</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_foo_bar_baz_
+.
+<p><em>foo_bar_baz</em></p>
+````````````````````````````````
+
+
+This is emphasis, even though the closing delimiter is
+both left- and right-flanking, because it is followed by
+punctuation:
+
+```````````````````````````````` example
+_(bar)_.
+.
+<p><em>(bar)</em>.</p>
+````````````````````````````````
+
+
+Rule 5:
+
+```````````````````````````````` example
+**foo bar**
+.
+<p><strong>foo bar</strong></p>
+````````````````````````````````
+
+
+This is not strong emphasis, because the opening delimiter is
+followed by whitespace:
+
+```````````````````````````````` example
+** foo bar**
+.
+<p>** foo bar**</p>
+````````````````````````````````
+
+
+This is not strong emphasis, because the opening `**` is preceded
+by an alphanumeric and followed by punctuation, and hence
+not part of a [left-flanking delimiter run]:
+
+```````````````````````````````` example
+a**"foo"**
+.
+<p>a**&quot;foo&quot;**</p>
+````````````````````````````````
+
+
+Intraword strong emphasis with `**` is permitted:
+
+```````````````````````````````` example
+foo**bar**
+.
+<p>foo<strong>bar</strong></p>
+````````````````````````````````
+
+
+Rule 6:
+
+```````````````````````````````` example
+__foo bar__
+.
+<p><strong>foo bar</strong></p>
+````````````````````````````````
+
+
+This is not strong emphasis, because the opening delimiter is
+followed by whitespace:
+
+```````````````````````````````` example
+__ foo bar__
+.
+<p>__ foo bar__</p>
+````````````````````````````````
+
+
+A newline counts as whitespace:
+```````````````````````````````` example
+__
+foo bar__
+.
+<p>__
+foo bar__</p>
+````````````````````````````````
+
+
+This is not strong emphasis, because the opening `__` is preceded
+by an alphanumeric and followed by punctuation:
+
+```````````````````````````````` example
+a__"foo"__
+.
+<p>a__&quot;foo&quot;__</p>
+````````````````````````````````
+
+
+Intraword strong emphasis is forbidden with `__`:
+
+```````````````````````````````` example
+foo__bar__
+.
+<p>foo__bar__</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+5__6__78
+.
+<p>5__6__78</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+приÑтанÑм__ÑтремÑÑ‚ÑÑ__
+.
+<p>приÑтанÑм__ÑтремÑÑ‚ÑÑ__</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__foo, __bar__, baz__
+.
+<p><strong>foo, <strong>bar</strong>, baz</strong></p>
+````````````````````````````````
+
+
+This is strong emphasis, even though the opening delimiter is
+both left- and right-flanking, because it is preceded by
+punctuation:
+
+```````````````````````````````` example
+foo-__(bar)__
+.
+<p>foo-<strong>(bar)</strong></p>
+````````````````````````````````
+
+
+
+Rule 7:
+
+This is not strong emphasis, because the closing delimiter is preceded
+by whitespace:
+
+```````````````````````````````` example
+**foo bar **
+.
+<p>**foo bar **</p>
+````````````````````````````````
+
+
+(Nor can it be interpreted as an emphasized `*foo bar *`, because of
+Rule 11.)
+
+This is not strong emphasis, because the second `**` is
+preceded by punctuation and followed by an alphanumeric:
+
+```````````````````````````````` example
+**(**foo)
+.
+<p>**(**foo)</p>
+````````````````````````````````
+
+
+The point of this restriction is more easily appreciated
+with these examples:
+
+```````````````````````````````` example
+*(**foo**)*
+.
+<p><em>(<strong>foo</strong>)</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**Gomphocarpus (*Gomphocarpus physocarpus*, syn.
+*Asclepias physocarpa*)**
+.
+<p><strong>Gomphocarpus (<em>Gomphocarpus physocarpus</em>, syn.
+<em>Asclepias physocarpa</em>)</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo "*bar*" foo**
+.
+<p><strong>foo &quot;<em>bar</em>&quot; foo</strong></p>
+````````````````````````````````
+
+
+Intraword emphasis:
+
+```````````````````````````````` example
+**foo**bar
+.
+<p><strong>foo</strong>bar</p>
+````````````````````````````````
+
+
+Rule 8:
+
+This is not strong emphasis, because the closing delimiter is
+preceded by whitespace:
+
+```````````````````````````````` example
+__foo bar __
+.
+<p>__foo bar __</p>
+````````````````````````````````
+
+
+This is not strong emphasis, because the second `__` is
+preceded by punctuation and followed by an alphanumeric:
+
+```````````````````````````````` example
+__(__foo)
+.
+<p>__(__foo)</p>
+````````````````````````````````
+
+
+The point of this restriction is more easily appreciated
+with this example:
+
+```````````````````````````````` example
+_(__foo__)_
+.
+<p><em>(<strong>foo</strong>)</em></p>
+````````````````````````````````
+
+
+Intraword strong emphasis is forbidden with `__`:
+
+```````````````````````````````` example
+__foo__bar
+.
+<p>__foo__bar</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__приÑтанÑм__ÑтремÑÑ‚ÑÑ
+.
+<p>__приÑтанÑм__ÑтремÑÑ‚ÑÑ</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__foo__bar__baz__
+.
+<p><strong>foo__bar__baz</strong></p>
+````````````````````````````````
+
+
+This is strong emphasis, even though the closing delimiter is
+both left- and right-flanking, because it is followed by
+punctuation:
+
+```````````````````````````````` example
+__(bar)__.
+.
+<p><strong>(bar)</strong>.</p>
+````````````````````````````````
+
+
+Rule 9:
+
+Any nonempty sequence of inline elements can be the contents of an
+emphasized span.
+
+```````````````````````````````` example
+*foo [bar](/url)*
+.
+<p><em>foo <a href="/url">bar</a></em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo
+bar*
+.
+<p><em>foo
+bar</em></p>
+````````````````````````````````
+
+
+In particular, emphasis and strong emphasis can be nested
+inside emphasis:
+
+```````````````````````````````` example
+_foo __bar__ baz_
+.
+<p><em>foo <strong>bar</strong> baz</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_foo _bar_ baz_
+.
+<p><em>foo <em>bar</em> baz</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__foo_ bar_
+.
+<p><em><em>foo</em> bar</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo *bar**
+.
+<p><em>foo <em>bar</em></em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo **bar** baz*
+.
+<p><em>foo <strong>bar</strong> baz</em></p>
+````````````````````````````````
+
+```````````````````````````````` example
+*foo**bar**baz*
+.
+<p><em>foo<strong>bar</strong>baz</em></p>
+````````````````````````````````
+
+Note that in the preceding case, the interpretation
+
+``` markdown
+<p><em>foo</em><em>bar<em></em>baz</em></p>
+```
+
+
+is precluded by the condition that a delimiter that
+can both open and close (like the `*` after `foo`)
+cannot form emphasis if the sum of the lengths of
+the delimiter runs containing the opening and
+closing delimiters is a multiple of 3 unless
+both lengths are multiples of 3.
+
+
+For the same reason, we don't get two consecutive
+emphasis sections in this example:
+
+```````````````````````````````` example
+*foo**bar*
+.
+<p><em>foo**bar</em></p>
+````````````````````````````````
+
+
+The same condition ensures that the following
+cases are all strong emphasis nested inside
+emphasis, even when the interior spaces are
+omitted:
+
+
+```````````````````````````````` example
+***foo** bar*
+.
+<p><em><strong>foo</strong> bar</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo **bar***
+.
+<p><em>foo <strong>bar</strong></em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo**bar***
+.
+<p><em>foo<strong>bar</strong></em></p>
+````````````````````````````````
+
+
+When the lengths of the interior closing and opening
+delimiter runs are *both* multiples of 3, though,
+they can match to create emphasis:
+
+```````````````````````````````` example
+foo***bar***baz
+.
+<p>foo<em><strong>bar</strong></em>baz</p>
+````````````````````````````````
+
+```````````````````````````````` example
+foo******bar*********baz
+.
+<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>
+````````````````````````````````
+
+
+Indefinite levels of nesting are possible:
+
+```````````````````````````````` example
+*foo **bar *baz* bim** bop*
+.
+<p><em>foo <strong>bar <em>baz</em> bim</strong> bop</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo [*bar*](/url)*
+.
+<p><em>foo <a href="/url"><em>bar</em></a></em></p>
+````````````````````````````````
+
+
+There can be no empty emphasis or strong emphasis:
+
+```````````````````````````````` example
+** is not an empty emphasis
+.
+<p>** is not an empty emphasis</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**** is not an empty strong emphasis
+.
+<p>**** is not an empty strong emphasis</p>
+````````````````````````````````
+
+
+
+Rule 10:
+
+Any nonempty sequence of inline elements can be the contents of an
+strongly emphasized span.
+
+```````````````````````````````` example
+**foo [bar](/url)**
+.
+<p><strong>foo <a href="/url">bar</a></strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo
+bar**
+.
+<p><strong>foo
+bar</strong></p>
+````````````````````````````````
+
+
+In particular, emphasis and strong emphasis can be nested
+inside strong emphasis:
+
+```````````````````````````````` example
+__foo _bar_ baz__
+.
+<p><strong>foo <em>bar</em> baz</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__foo __bar__ baz__
+.
+<p><strong>foo <strong>bar</strong> baz</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+____foo__ bar__
+.
+<p><strong><strong>foo</strong> bar</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo **bar****
+.
+<p><strong>foo <strong>bar</strong></strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo *bar* baz**
+.
+<p><strong>foo <em>bar</em> baz</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo*bar*baz**
+.
+<p><strong>foo<em>bar</em>baz</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+***foo* bar**
+.
+<p><strong><em>foo</em> bar</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo *bar***
+.
+<p><strong>foo <em>bar</em></strong></p>
+````````````````````````````````
+
+
+Indefinite levels of nesting are possible:
+
+```````````````````````````````` example
+**foo *bar **baz**
+bim* bop**
+.
+<p><strong>foo <em>bar <strong>baz</strong>
+bim</em> bop</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo [*bar*](/url)**
+.
+<p><strong>foo <a href="/url"><em>bar</em></a></strong></p>
+````````````````````````````````
+
+
+There can be no empty emphasis or strong emphasis:
+
+```````````````````````````````` example
+__ is not an empty emphasis
+.
+<p>__ is not an empty emphasis</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+____ is not an empty strong emphasis
+.
+<p>____ is not an empty strong emphasis</p>
+````````````````````````````````
+
+
+
+Rule 11:
+
+```````````````````````````````` example
+foo ***
+.
+<p>foo ***</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo *\**
+.
+<p>foo <em>*</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo *_*
+.
+<p>foo <em>_</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo *****
+.
+<p>foo *****</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo **\***
+.
+<p>foo <strong>*</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo **_**
+.
+<p>foo <strong>_</strong></p>
+````````````````````````````````
+
+
+Note that when delimiters do not match evenly, Rule 11 determines
+that the excess literal `*` characters will appear outside of the
+emphasis, rather than inside it:
+
+```````````````````````````````` example
+**foo*
+.
+<p>*<em>foo</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo**
+.
+<p><em>foo</em>*</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+***foo**
+.
+<p>*<strong>foo</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+****foo*
+.
+<p>***<em>foo</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**foo***
+.
+<p><strong>foo</strong>*</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo****
+.
+<p><em>foo</em>***</p>
+````````````````````````````````
+
+
+
+Rule 12:
+
+```````````````````````````````` example
+foo ___
+.
+<p>foo ___</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo _\__
+.
+<p>foo <em>_</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo _*_
+.
+<p>foo <em>*</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo _____
+.
+<p>foo _____</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo __\___
+.
+<p>foo <strong>_</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo __*__
+.
+<p>foo <strong>*</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__foo_
+.
+<p>_<em>foo</em></p>
+````````````````````````````````
+
+
+Note that when delimiters do not match evenly, Rule 12 determines
+that the excess literal `_` characters will appear outside of the
+emphasis, rather than inside it:
+
+```````````````````````````````` example
+_foo__
+.
+<p><em>foo</em>_</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+___foo__
+.
+<p>_<strong>foo</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+____foo_
+.
+<p>___<em>foo</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__foo___
+.
+<p><strong>foo</strong>_</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_foo____
+.
+<p><em>foo</em>___</p>
+````````````````````````````````
+
+
+Rule 13 implies that if you want emphasis nested directly inside
+emphasis, you must use different delimiters:
+
+```````````````````````````````` example
+**foo**
+.
+<p><strong>foo</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*_foo_*
+.
+<p><em><em>foo</em></em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__foo__
+.
+<p><strong>foo</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_*foo*_
+.
+<p><em><em>foo</em></em></p>
+````````````````````````````````
+
+
+However, strong emphasis within strong emphasis is possible without
+switching delimiters:
+
+```````````````````````````````` example
+****foo****
+.
+<p><strong><strong>foo</strong></strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+____foo____
+.
+<p><strong><strong>foo</strong></strong></p>
+````````````````````````````````
+
+
+
+Rule 13 can be applied to arbitrarily long sequences of
+delimiters:
+
+```````````````````````````````` example
+******foo******
+.
+<p><strong><strong><strong>foo</strong></strong></strong></p>
+````````````````````````````````
+
+
+Rule 14:
+
+```````````````````````````````` example
+***foo***
+.
+<p><em><strong>foo</strong></em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_____foo_____
+.
+<p><em><strong><strong>foo</strong></strong></em></p>
+````````````````````````````````
+
+
+Rule 15:
+
+```````````````````````````````` example
+*foo _bar* baz_
+.
+<p><em>foo _bar</em> baz_</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo __bar *baz bim__ bam*
+.
+<p><em>foo <strong>bar *baz bim</strong> bam</em></p>
+````````````````````````````````
+
+
+Rule 16:
+
+```````````````````````````````` example
+**foo **bar baz**
+.
+<p>**foo <strong>bar baz</strong></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo *bar baz*
+.
+<p>*foo <em>bar baz</em></p>
+````````````````````````````````
+
+
+Rule 17:
+
+```````````````````````````````` example
+*[bar*](/url)
+.
+<p>*<a href="/url">bar*</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_foo [bar_](/url)
+.
+<p>_foo <a href="/url">bar_</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*<img src="foo" title="*"/>
+.
+<p>*<img src="foo" title="*"/></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**<a href="**">
+.
+<p>**<a href="**"></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__<a href="__">
+.
+<p>__<a href="__"></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*a `*`*
+.
+<p><em>a <code>*</code></em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+_a `_`_
+.
+<p><em>a <code>_</code></em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+**a<http://foo.bar/?q=**>
+.
+<p>**a<a href="http://foo.bar/?q=**">http://foo.bar/?q=**</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+__a<http://foo.bar/?q=__>
+.
+<p>__a<a href="http://foo.bar/?q=__">http://foo.bar/?q=__</a></p>
+````````````````````````````````
+
+
+<div class="extension">
+
+## Strikethrough (extension)
+
+GFM enables the `strikethrough` extension, where an additional emphasis type is
+available.
+
+Strikethrough text is any text wrapped in two tildes (`~`).
+
+```````````````````````````````` example strikethrough
+~~Hi~~ Hello, world!
+.
+<p><del>Hi</del> Hello, world!</p>
+````````````````````````````````
+
+As with regular emphasis delimiters, a new paragraph will cause strikethrough
+parsing to cease:
+
+```````````````````````````````` example strikethrough
+This ~~has a
+
+new paragraph~~.
+.
+<p>This ~~has a</p>
+<p>new paragraph~~.</p>
+````````````````````````````````
+
+</div>
+
+## Links
+
+A link contains [link text] (the visible text), a [link destination]
+(the URI that is the link destination), and optionally a [link title].
+There are two basic kinds of links in Markdown. In [inline links] the
+destination and title are given immediately after the link text. In
+[reference links] the destination and title are defined elsewhere in
+the document.
+
+A [link text](@) consists of a sequence of zero or more
+inline elements enclosed by square brackets (`[` and `]`). The
+following rules apply:
+
+- Links may not contain other links, at any level of nesting. If
+ multiple otherwise valid link definitions appear nested inside each
+ other, the inner-most definition is used.
+
+- Brackets are allowed in the [link text] only if (a) they
+ are backslash-escaped or (b) they appear as a matched pair of brackets,
+ with an open bracket `[`, a sequence of zero or more inlines, and
+ a close bracket `]`.
+
+- Backtick [code spans], [autolinks], and raw [HTML tags] bind more tightly
+ than the brackets in link text. Thus, for example,
+ `` [foo`]` `` could not be a link text, since the second `]`
+ is part of a code span.
+
+- The brackets in link text bind more tightly than markers for
+ [emphasis and strong emphasis]. Thus, for example, `*[foo*](url)` is a link.
+
+A [link destination](@) consists of either
+
+- a sequence of zero or more characters between an opening `<` and a
+ closing `>` that contains no line breaks or unescaped
+ `<` or `>` characters, or
+
+- a nonempty sequence of characters that does not start with
+ `<`, does not include ASCII space or control characters, and
+ includes parentheses only if (a) they are backslash-escaped or
+ (b) they are part of a balanced pair of unescaped parentheses.
+ (Implementations may impose limits on parentheses nesting to
+ avoid performance issues, but at least three levels of nesting
+ should be supported.)
+
+A [link title](@) consists of either
+
+- a sequence of zero or more characters between straight double-quote
+ characters (`"`), including a `"` character only if it is
+ backslash-escaped, or
+
+- a sequence of zero or more characters between straight single-quote
+ characters (`'`), including a `'` character only if it is
+ backslash-escaped, or
+
+- a sequence of zero or more characters between matching parentheses
+ (`(...)`), including a `(` or `)` character only if it is
+ backslash-escaped.
+
+Although [link titles] may span multiple lines, they may not contain
+a [blank line].
+
+An [inline link](@) consists of a [link text] followed immediately
+by a left parenthesis `(`, optional [whitespace], an optional
+[link destination], an optional [link title] separated from the link
+destination by [whitespace], optional [whitespace], and a right
+parenthesis `)`. The link's text consists of the inlines contained
+in the [link text] (excluding the enclosing square brackets).
+The link's URI consists of the link destination, excluding enclosing
+`<...>` if present, with backslash-escapes in effect as described
+above. The link's title consists of the link title, excluding its
+enclosing delimiters, with backslash-escapes in effect as described
+above.
+
+Here is a simple inline link:
+
+```````````````````````````````` example
+[link](/uri "title")
+.
+<p><a href="/uri" title="title">link</a></p>
+````````````````````````````````
+
+
+The title may be omitted:
+
+```````````````````````````````` example
+[link](/uri)
+.
+<p><a href="/uri">link</a></p>
+````````````````````````````````
+
+
+Both the title and the destination may be omitted:
+
+```````````````````````````````` example
+[link]()
+.
+<p><a href="">link</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[link](<>)
+.
+<p><a href="">link</a></p>
+````````````````````````````````
+
+The destination can only contain spaces if it is
+enclosed in pointy brackets:
+
+```````````````````````````````` example
+[link](/my uri)
+.
+<p>[link](/my uri)</p>
+````````````````````````````````
+
+```````````````````````````````` example
+[link](</my uri>)
+.
+<p><a href="/my%20uri">link</a></p>
+````````````````````````````````
+
+The destination cannot contain line breaks,
+even if enclosed in pointy brackets:
+
+```````````````````````````````` example
+[link](foo
+bar)
+.
+<p>[link](foo
+bar)</p>
+````````````````````````````````
+
+```````````````````````````````` example
+[link](<foo
+bar>)
+.
+<p>[link](<foo
+bar>)</p>
+````````````````````````````````
+
+The destination can contain `)` if it is enclosed
+in pointy brackets:
+
+```````````````````````````````` example
+[a](<b)c>)
+.
+<p><a href="b)c">a</a></p>
+````````````````````````````````
+
+Pointy brackets that enclose links must be unescaped:
+
+```````````````````````````````` example
+[link](<foo\>)
+.
+<p>[link](&lt;foo&gt;)</p>
+````````````````````````````````
+
+These are not links, because the opening pointy bracket
+is not matched properly:
+
+```````````````````````````````` example
+[a](<b)c
+[a](<b)c>
+[a](<b>c)
+.
+<p>[a](&lt;b)c
+[a](&lt;b)c&gt;
+[a](<b>c)</p>
+````````````````````````````````
+
+Parentheses inside the link destination may be escaped:
+
+```````````````````````````````` example
+[link](\(foo\))
+.
+<p><a href="(foo)">link</a></p>
+````````````````````````````````
+
+Any number of parentheses are allowed without escaping, as long as they are
+balanced:
+
+```````````````````````````````` example
+[link](foo(and(bar)))
+.
+<p><a href="foo(and(bar))">link</a></p>
+````````````````````````````````
+
+However, if you have unbalanced parentheses, you need to escape or use the
+`<...>` form:
+
+```````````````````````````````` example
+[link](foo\(and\(bar\))
+.
+<p><a href="foo(and(bar)">link</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[link](<foo(and(bar)>)
+.
+<p><a href="foo(and(bar)">link</a></p>
+````````````````````````````````
+
+
+Parentheses and other symbols can also be escaped, as usual
+in Markdown:
+
+```````````````````````````````` example
+[link](foo\)\:)
+.
+<p><a href="foo):">link</a></p>
+````````````````````````````````
+
+
+A link can contain fragment identifiers and queries:
+
+```````````````````````````````` example
+[link](#fragment)
+
+[link](http://example.com#fragment)
+
+[link](http://example.com?foo=3#frag)
+.
+<p><a href="#fragment">link</a></p>
+<p><a href="http://example.com#fragment">link</a></p>
+<p><a href="http://example.com?foo=3#frag">link</a></p>
+````````````````````````````````
+
+
+Note that a backslash before a non-escapable character is
+just a backslash:
+
+```````````````````````````````` example
+[link](foo\bar)
+.
+<p><a href="foo%5Cbar">link</a></p>
+````````````````````````````````
+
+
+URL-escaping should be left alone inside the destination, as all
+URL-escaped characters are also valid URL characters. Entity and
+numerical character references in the destination will be parsed
+into the corresponding Unicode code points, as usual. These may
+be optionally URL-escaped when written as HTML, but this spec
+does not enforce any particular policy for rendering URLs in
+HTML or other formats. Renderers may make different decisions
+about how to escape or normalize URLs in the output.
+
+```````````````````````````````` example
+[link](foo%20b&auml;)
+.
+<p><a href="foo%20b%C3%A4">link</a></p>
+````````````````````````````````
+
+
+Note that, because titles can often be parsed as destinations,
+if you try to omit the destination and keep the title, you'll
+get unexpected results:
+
+```````````````````````````````` example
+[link]("title")
+.
+<p><a href="%22title%22">link</a></p>
+````````````````````````````````
+
+
+Titles may be in single quotes, double quotes, or parentheses:
+
+```````````````````````````````` example
+[link](/url "title")
+[link](/url 'title')
+[link](/url (title))
+.
+<p><a href="/url" title="title">link</a>
+<a href="/url" title="title">link</a>
+<a href="/url" title="title">link</a></p>
+````````````````````````````````
+
+
+Backslash escapes and entity and numeric character references
+may be used in titles:
+
+```````````````````````````````` example
+[link](/url "title \"&quot;")
+.
+<p><a href="/url" title="title &quot;&quot;">link</a></p>
+````````````````````````````````
+
+
+Titles must be separated from the link using a [whitespace].
+Other [Unicode whitespace] like non-breaking space doesn't work.
+
+```````````````````````````````` example
+[link](/url "title")
+.
+<p><a href="/url%C2%A0%22title%22">link</a></p>
+````````````````````````````````
+
+
+Nested balanced quotes are not allowed without escaping:
+
+```````````````````````````````` example
+[link](/url "title "and" title")
+.
+<p>[link](/url &quot;title &quot;and&quot; title&quot;)</p>
+````````````````````````````````
+
+
+But it is easy to work around this by using a different quote type:
+
+```````````````````````````````` example
+[link](/url 'title "and" title')
+.
+<p><a href="/url" title="title &quot;and&quot; title">link</a></p>
+````````````````````````````````
+
+
+(Note: `Markdown.pl` did allow double quotes inside a double-quoted
+title, and its test suite included a test demonstrating this.
+But it is hard to see a good rationale for the extra complexity this
+brings, since there are already many ways---backslash escaping,
+entity and numeric character references, or using a different
+quote type for the enclosing title---to write titles containing
+double quotes. `Markdown.pl`'s handling of titles has a number
+of other strange features. For example, it allows single-quoted
+titles in inline links, but not reference links. And, in
+reference links but not inline links, it allows a title to begin
+with `"` and end with `)`. `Markdown.pl` 1.0.1 even allows
+titles with no closing quotation mark, though 1.0.2b8 does not.
+It seems preferable to adopt a simple, rational rule that works
+the same way in inline links and link reference definitions.)
+
+[Whitespace] is allowed around the destination and title:
+
+```````````````````````````````` example
+[link]( /uri
+ "title" )
+.
+<p><a href="/uri" title="title">link</a></p>
+````````````````````````````````
+
+
+But it is not allowed between the link text and the
+following parenthesis:
+
+```````````````````````````````` example
+[link] (/uri)
+.
+<p>[link] (/uri)</p>
+````````````````````````````````
+
+
+The link text may contain balanced brackets, but not unbalanced ones,
+unless they are escaped:
+
+```````````````````````````````` example
+[link [foo [bar]]](/uri)
+.
+<p><a href="/uri">link [foo [bar]]</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[link] bar](/uri)
+.
+<p>[link] bar](/uri)</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[link [bar](/uri)
+.
+<p>[link <a href="/uri">bar</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[link \[bar](/uri)
+.
+<p><a href="/uri">link [bar</a></p>
+````````````````````````````````
+
+
+The link text may contain inline content:
+
+```````````````````````````````` example
+[link *foo **bar** `#`*](/uri)
+.
+<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[![moon](moon.jpg)](/uri)
+.
+<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
+````````````````````````````````
+
+
+However, links may not contain other links, at any level of nesting.
+
+```````````````````````````````` example
+[foo [bar](/uri)](/uri)
+.
+<p>[foo <a href="/uri">bar</a>](/uri)</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo *[bar [baz](/uri)](/uri)*](/uri)
+.
+<p>[foo <em>[bar <a href="/uri">baz</a>](/uri)</em>](/uri)</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![[[foo](uri1)](uri2)](uri3)
+.
+<p><img src="uri3" alt="[foo](uri2)" /></p>
+````````````````````````````````
+
+
+These cases illustrate the precedence of link text grouping over
+emphasis grouping:
+
+```````````````````````````````` example
+*[foo*](/uri)
+.
+<p>*<a href="/uri">foo*</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo *bar](baz*)
+.
+<p><a href="baz*">foo *bar</a></p>
+````````````````````````````````
+
+
+Note that brackets that *aren't* part of links do not take
+precedence:
+
+```````````````````````````````` example
+*foo [bar* baz]
+.
+<p><em>foo [bar</em> baz]</p>
+````````````````````````````````
+
+
+These cases illustrate the precedence of HTML tags, code spans,
+and autolinks over link grouping:
+
+```````````````````````````````` example
+[foo <bar attr="](baz)">
+.
+<p>[foo <bar attr="](baz)"></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo`](/uri)`
+.
+<p>[foo<code>](/uri)</code></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo<http://example.com/?search=](uri)>
+.
+<p>[foo<a href="http://example.com/?search=%5D(uri)">http://example.com/?search=](uri)</a></p>
+````````````````````````````````
+
+
+There are three kinds of [reference link](@)s:
+[full](#full-reference-link), [collapsed](#collapsed-reference-link),
+and [shortcut](#shortcut-reference-link).
+
+A [full reference link](@)
+consists of a [link text] immediately followed by a [link label]
+that [matches] a [link reference definition] elsewhere in the document.
+
+A [link label](@) begins with a left bracket (`[`) and ends
+with the first right bracket (`]`) that is not backslash-escaped.
+Between these brackets there must be at least one [non-whitespace character].
+Unescaped square bracket characters are not allowed inside the
+opening and closing square brackets of [link labels]. A link
+label can have at most 999 characters inside the square
+brackets.
+
+One label [matches](@)
+another just in case their normalized forms are equal. To normalize a
+label, strip off the opening and closing brackets,
+perform the *Unicode case fold*, strip leading and trailing
+[whitespace] and collapse consecutive internal
+[whitespace] to a single space. If there are multiple
+matching reference link definitions, the one that comes first in the
+document is used. (It is desirable in such cases to emit a warning.)
+
+The contents of the first link label are parsed as inlines, which are
+used as the link's text. The link's URI and title are provided by the
+matching [link reference definition].
+
+Here is a simple example:
+
+```````````````````````````````` example
+[foo][bar]
+
+[bar]: /url "title"
+.
+<p><a href="/url" title="title">foo</a></p>
+````````````````````````````````
+
+
+The rules for the [link text] are the same as with
+[inline links]. Thus:
+
+The link text may contain balanced brackets, but not unbalanced ones,
+unless they are escaped:
+
+```````````````````````````````` example
+[link [foo [bar]]][ref]
+
+[ref]: /uri
+.
+<p><a href="/uri">link [foo [bar]]</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[link \[bar][ref]
+
+[ref]: /uri
+.
+<p><a href="/uri">link [bar</a></p>
+````````````````````````````````
+
+
+The link text may contain inline content:
+
+```````````````````````````````` example
+[link *foo **bar** `#`*][ref]
+
+[ref]: /uri
+.
+<p><a href="/uri">link <em>foo <strong>bar</strong> <code>#</code></em></a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[![moon](moon.jpg)][ref]
+
+[ref]: /uri
+.
+<p><a href="/uri"><img src="moon.jpg" alt="moon" /></a></p>
+````````````````````````````````
+
+
+However, links may not contain other links, at any level of nesting.
+
+```````````````````````````````` example
+[foo [bar](/uri)][ref]
+
+[ref]: /uri
+.
+<p>[foo <a href="/uri">bar</a>]<a href="/uri">ref</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo *bar [baz][ref]*][ref]
+
+[ref]: /uri
+.
+<p>[foo <em>bar <a href="/uri">baz</a></em>]<a href="/uri">ref</a></p>
+````````````````````````````````
+
+
+(In the examples above, we have two [shortcut reference links]
+instead of one [full reference link].)
+
+The following cases illustrate the precedence of link text grouping over
+emphasis grouping:
+
+```````````````````````````````` example
+*[foo*][ref]
+
+[ref]: /uri
+.
+<p>*<a href="/uri">foo*</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo *bar][ref]
+
+[ref]: /uri
+.
+<p><a href="/uri">foo *bar</a></p>
+````````````````````````````````
+
+
+These cases illustrate the precedence of HTML tags, code spans,
+and autolinks over link grouping:
+
+```````````````````````````````` example
+[foo <bar attr="][ref]">
+
+[ref]: /uri
+.
+<p>[foo <bar attr="][ref]"></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo`][ref]`
+
+[ref]: /uri
+.
+<p>[foo<code>][ref]</code></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo<http://example.com/?search=][ref]>
+
+[ref]: /uri
+.
+<p>[foo<a href="http://example.com/?search=%5D%5Bref%5D">http://example.com/?search=][ref]</a></p>
+````````````````````````````````
+
+
+Matching is case-insensitive:
+
+```````````````````````````````` example
+[foo][BaR]
+
+[bar]: /url "title"
+.
+<p><a href="/url" title="title">foo</a></p>
+````````````````````````````````
+
+
+Unicode case fold is used:
+
+```````````````````````````````` example
+[Толпой][Толпой] is a Russian word.
+
+[ТОЛПОЙ]: /url
+.
+<p><a href="/url">Толпой</a> is a Russian word.</p>
+````````````````````````````````
+
+
+Consecutive internal [whitespace] is treated as one space for
+purposes of determining matching:
+
+```````````````````````````````` example
+[Foo
+ bar]: /url
+
+[Baz][Foo bar]
+.
+<p><a href="/url">Baz</a></p>
+````````````````````````````````
+
+
+No [whitespace] is allowed between the [link text] and the
+[link label]:
+
+```````````````````````````````` example
+[foo] [bar]
+
+[bar]: /url "title"
+.
+<p>[foo] <a href="/url" title="title">bar</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo]
+[bar]
+
+[bar]: /url "title"
+.
+<p>[foo]
+<a href="/url" title="title">bar</a></p>
+````````````````````````````````
+
+
+This is a departure from John Gruber's original Markdown syntax
+description, which explicitly allows whitespace between the link
+text and the link label. It brings reference links in line with
+[inline links], which (according to both original Markdown and
+this spec) cannot have whitespace after the link text. More
+importantly, it prevents inadvertent capture of consecutive
+[shortcut reference links]. If whitespace is allowed between the
+link text and the link label, then in the following we will have
+a single reference link, not two shortcut reference links, as
+intended:
+
+``` markdown
+[foo]
+[bar]
+
+[foo]: /url1
+[bar]: /url2
+```
+
+(Note that [shortcut reference links] were introduced by Gruber
+himself in a beta version of `Markdown.pl`, but never included
+in the official syntax description. Without shortcut reference
+links, it is harmless to allow space between the link text and
+link label; but once shortcut references are introduced, it is
+too dangerous to allow this, as it frequently leads to
+unintended results.)
+
+When there are multiple matching [link reference definitions],
+the first is used:
+
+```````````````````````````````` example
+[foo]: /url1
+
+[foo]: /url2
+
+[bar][foo]
+.
+<p><a href="/url1">bar</a></p>
+````````````````````````````````
+
+
+Note that matching is performed on normalized strings, not parsed
+inline content. So the following does not match, even though the
+labels define equivalent inline content:
+
+```````````````````````````````` example
+[bar][foo\!]
+
+[foo!]: /url
+.
+<p>[bar][foo!]</p>
+````````````````````````````````
+
+
+[Link labels] cannot contain brackets, unless they are
+backslash-escaped:
+
+```````````````````````````````` example
+[foo][ref[]
+
+[ref[]: /uri
+.
+<p>[foo][ref[]</p>
+<p>[ref[]: /uri</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo][ref[bar]]
+
+[ref[bar]]: /uri
+.
+<p>[foo][ref[bar]]</p>
+<p>[ref[bar]]: /uri</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[[[foo]]]
+
+[[[foo]]]: /url
+.
+<p>[[[foo]]]</p>
+<p>[[[foo]]]: /url</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[foo][ref\[]
+
+[ref\[]: /uri
+.
+<p><a href="/uri">foo</a></p>
+````````````````````````````````
+
+
+Note that in this example `]` is not backslash-escaped:
+
+```````````````````````````````` example
+[bar\\]: /uri
+
+[bar\\]
+.
+<p><a href="/uri">bar\</a></p>
+````````````````````````````````
+
+
+A [link label] must contain at least one [non-whitespace character]:
+
+```````````````````````````````` example
+[]
+
+[]: /uri
+.
+<p>[]</p>
+<p>[]: /uri</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[
+ ]
+
+[
+ ]: /uri
+.
+<p>[
+]</p>
+<p>[
+]: /uri</p>
+````````````````````````````````
+
+
+A [collapsed reference link](@)
+consists of a [link label] that [matches] a
+[link reference definition] elsewhere in the
+document, followed by the string `[]`.
+The contents of the first link label are parsed as inlines,
+which are used as the link's text. The link's URI and title are
+provided by the matching reference link definition. Thus,
+`[foo][]` is equivalent to `[foo][foo]`.
+
+```````````````````````````````` example
+[foo][]
+
+[foo]: /url "title"
+.
+<p><a href="/url" title="title">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[*foo* bar][]
+
+[*foo* bar]: /url "title"
+.
+<p><a href="/url" title="title"><em>foo</em> bar</a></p>
+````````````````````````````````
+
+
+The link labels are case-insensitive:
+
+```````````````````````````````` example
+[Foo][]
+
+[foo]: /url "title"
+.
+<p><a href="/url" title="title">Foo</a></p>
+````````````````````````````````
+
+
+
+As with full reference links, [whitespace] is not
+allowed between the two sets of brackets:
+
+```````````````````````````````` example
+[foo]
+[]
+
+[foo]: /url "title"
+.
+<p><a href="/url" title="title">foo</a>
+[]</p>
+````````````````````````````````
+
+
+A [shortcut reference link](@)
+consists of a [link label] that [matches] a
+[link reference definition] elsewhere in the
+document and is not followed by `[]` or a link label.
+The contents of the first link label are parsed as inlines,
+which are used as the link's text. The link's URI and title
+are provided by the matching link reference definition.
+Thus, `[foo]` is equivalent to `[foo][]`.
+
+```````````````````````````````` example
+[foo]
+
+[foo]: /url "title"
+.
+<p><a href="/url" title="title">foo</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[*foo* bar]
+
+[*foo* bar]: /url "title"
+.
+<p><a href="/url" title="title"><em>foo</em> bar</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[[*foo* bar]]
+
+[*foo* bar]: /url "title"
+.
+<p>[<a href="/url" title="title"><em>foo</em> bar</a>]</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+[[bar [foo]
+
+[foo]: /url
+.
+<p>[[bar <a href="/url">foo</a></p>
+````````````````````````````````
+
+
+The link labels are case-insensitive:
+
+```````````````````````````````` example
+[Foo]
+
+[foo]: /url "title"
+.
+<p><a href="/url" title="title">Foo</a></p>
+````````````````````````````````
+
+
+A space after the link text should be preserved:
+
+```````````````````````````````` example
+[foo] bar
+
+[foo]: /url
+.
+<p><a href="/url">foo</a> bar</p>
+````````````````````````````````
+
+
+If you just want bracketed text, you can backslash-escape the
+opening bracket to avoid links:
+
+```````````````````````````````` example
+\[foo]
+
+[foo]: /url "title"
+.
+<p>[foo]</p>
+````````````````````````````````
+
+
+Note that this is a link, because a link label ends with the first
+following closing bracket:
+
+```````````````````````````````` example
+[foo*]: /url
+
+*[foo*]
+.
+<p>*<a href="/url">foo*</a></p>
+````````````````````````````````
+
+
+Full and compact references take precedence over shortcut
+references:
+
+```````````````````````````````` example
+[foo][bar]
+
+[foo]: /url1
+[bar]: /url2
+.
+<p><a href="/url2">foo</a></p>
+````````````````````````````````
+
+```````````````````````````````` example
+[foo][]
+
+[foo]: /url1
+.
+<p><a href="/url1">foo</a></p>
+````````````````````````````````
+
+Inline links also take precedence:
+
+```````````````````````````````` example
+[foo]()
+
+[foo]: /url1
+.
+<p><a href="">foo</a></p>
+````````````````````````````````
+
+```````````````````````````````` example
+[foo](not a link)
+
+[foo]: /url1
+.
+<p><a href="/url1">foo</a>(not a link)</p>
+````````````````````````````````
+
+In the following case `[bar][baz]` is parsed as a reference,
+`[foo]` as normal text:
+
+```````````````````````````````` example
+[foo][bar][baz]
+
+[baz]: /url
+.
+<p>[foo]<a href="/url">bar</a></p>
+````````````````````````````````
+
+
+Here, though, `[foo][bar]` is parsed as a reference, since
+`[bar]` is defined:
+
+```````````````````````````````` example
+[foo][bar][baz]
+
+[baz]: /url1
+[bar]: /url2
+.
+<p><a href="/url2">foo</a><a href="/url1">baz</a></p>
+````````````````````````````````
+
+
+Here `[foo]` is not parsed as a shortcut reference, because it
+is followed by a link label (even though `[bar]` is not defined):
+
+```````````````````````````````` example
+[foo][bar][baz]
+
+[baz]: /url1
+[foo]: /url2
+.
+<p>[foo]<a href="/url1">bar</a></p>
+````````````````````````````````
+
+
+
+## Images
+
+Syntax for images is like the syntax for links, with one
+difference. Instead of [link text], we have an
+[image description](@). The rules for this are the
+same as for [link text], except that (a) an
+image description starts with `![` rather than `[`, and
+(b) an image description may contain links.
+An image description has inline elements
+as its contents. When an image is rendered to HTML,
+this is standardly used as the image's `alt` attribute.
+
+```````````````````````````````` example
+![foo](/url "title")
+.
+<p><img src="/url" alt="foo" title="title" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![foo *bar*]
+
+[foo *bar*]: train.jpg "train & tracks"
+.
+<p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![foo ![bar](/url)](/url2)
+.
+<p><img src="/url2" alt="foo bar" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![foo [bar](/url)](/url2)
+.
+<p><img src="/url2" alt="foo bar" /></p>
+````````````````````````````````
+
+
+Though this spec is concerned with parsing, not rendering, it is
+recommended that in rendering to HTML, only the plain string content
+of the [image description] be used. Note that in
+the above example, the alt attribute's value is `foo bar`, not `foo
+[bar](/url)` or `foo <a href="/url">bar</a>`. Only the plain string
+content is rendered, without formatting.
+
+```````````````````````````````` example
+![foo *bar*][]
+
+[foo *bar*]: train.jpg "train & tracks"
+.
+<p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![foo *bar*][foobar]
+
+[FOOBAR]: train.jpg "train & tracks"
+.
+<p><img src="train.jpg" alt="foo bar" title="train &amp; tracks" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![foo](train.jpg)
+.
+<p><img src="train.jpg" alt="foo" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+My ![foo bar](/path/to/train.jpg "title" )
+.
+<p>My <img src="/path/to/train.jpg" alt="foo bar" title="title" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![foo](<url>)
+.
+<p><img src="url" alt="foo" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![](/url)
+.
+<p><img src="/url" alt="" /></p>
+````````````````````````````````
+
+
+Reference-style:
+
+```````````````````````````````` example
+![foo][bar]
+
+[bar]: /url
+.
+<p><img src="/url" alt="foo" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![foo][bar]
+
+[BAR]: /url
+.
+<p><img src="/url" alt="foo" /></p>
+````````````````````````````````
+
+
+Collapsed:
+
+```````````````````````````````` example
+![foo][]
+
+[foo]: /url "title"
+.
+<p><img src="/url" alt="foo" title="title" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![*foo* bar][]
+
+[*foo* bar]: /url "title"
+.
+<p><img src="/url" alt="foo bar" title="title" /></p>
+````````````````````````````````
+
+
+The labels are case-insensitive:
+
+```````````````````````````````` example
+![Foo][]
+
+[foo]: /url "title"
+.
+<p><img src="/url" alt="Foo" title="title" /></p>
+````````````````````````````````
+
+
+As with reference links, [whitespace] is not allowed
+between the two sets of brackets:
+
+```````````````````````````````` example
+![foo]
+[]
+
+[foo]: /url "title"
+.
+<p><img src="/url" alt="foo" title="title" />
+[]</p>
+````````````````````````````````
+
+
+Shortcut:
+
+```````````````````````````````` example
+![foo]
+
+[foo]: /url "title"
+.
+<p><img src="/url" alt="foo" title="title" /></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+![*foo* bar]
+
+[*foo* bar]: /url "title"
+.
+<p><img src="/url" alt="foo bar" title="title" /></p>
+````````````````````````````````
+
+
+Note that link labels cannot contain unescaped brackets:
+
+```````````````````````````````` example
+![[foo]]
+
+[[foo]]: /url "title"
+.
+<p>![[foo]]</p>
+<p>[[foo]]: /url &quot;title&quot;</p>
+````````````````````````````````
+
+
+The link labels are case-insensitive:
+
+```````````````````````````````` example
+![Foo]
+
+[foo]: /url "title"
+.
+<p><img src="/url" alt="Foo" title="title" /></p>
+````````````````````````````````
+
+
+If you just want a literal `!` followed by bracketed text, you can
+backslash-escape the opening `[`:
+
+```````````````````````````````` example
+!\[foo]
+
+[foo]: /url "title"
+.
+<p>![foo]</p>
+````````````````````````````````
+
+
+If you want a link after a literal `!`, backslash-escape the
+`!`:
+
+```````````````````````````````` example
+\![foo]
+
+[foo]: /url "title"
+.
+<p>!<a href="/url" title="title">foo</a></p>
+````````````````````````````````
+
+
+## Autolinks
+
+[Autolink](@)s are absolute URIs and email addresses inside
+`<` and `>`. They are parsed as links, with the URL or email address
+as the link label.
+
+A [URI autolink](@) consists of `<`, followed by an
+[absolute URI] followed by `>`. It is parsed as
+a link to the URI, with the URI as the link's label.
+
+An [absolute URI](@),
+for these purposes, consists of a [scheme] followed by a colon (`:`)
+followed by zero or more characters other than ASCII
+[whitespace] and control characters, `<`, and `>`. If
+the URI includes these characters, they must be percent-encoded
+(e.g. `%20` for a space).
+
+For purposes of this spec, a [scheme](@) is any sequence
+of 2--32 characters beginning with an ASCII letter and followed
+by any combination of ASCII letters, digits, or the symbols plus
+("+"), period ("."), or hyphen ("-").
+
+Here are some valid autolinks:
+
+```````````````````````````````` example
+<http://foo.bar.baz>
+.
+<p><a href="http://foo.bar.baz">http://foo.bar.baz</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<http://foo.bar.baz/test?q=hello&id=22&boolean>
+.
+<p><a href="http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean">http://foo.bar.baz/test?q=hello&amp;id=22&amp;boolean</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<irc://foo.bar:2233/baz>
+.
+<p><a href="irc://foo.bar:2233/baz">irc://foo.bar:2233/baz</a></p>
+````````````````````````````````
+
+
+Uppercase is also fine:
+
+```````````````````````````````` example
+<MAILTO:FOO@BAR.BAZ>
+.
+<p><a href="MAILTO:FOO@BAR.BAZ">MAILTO:FOO@BAR.BAZ</a></p>
+````````````````````````````````
+
+
+Note that many strings that count as [absolute URIs] for
+purposes of this spec are not valid URIs, because their
+schemes are not registered or because of other problems
+with their syntax:
+
+```````````````````````````````` example
+<a+b+c:d>
+.
+<p><a href="a+b+c:d">a+b+c:d</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<made-up-scheme://foo,bar>
+.
+<p><a href="made-up-scheme://foo,bar">made-up-scheme://foo,bar</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<http://../>
+.
+<p><a href="http://../">http://../</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<localhost:5001/foo>
+.
+<p><a href="localhost:5001/foo">localhost:5001/foo</a></p>
+````````````````````````````````
+
+
+Spaces are not allowed in autolinks:
+
+```````````````````````````````` example
+<http://foo.bar/baz bim>
+.
+<p>&lt;http://foo.bar/baz bim&gt;</p>
+````````````````````````````````
+
+
+Backslash-escapes do not work inside autolinks:
+
+```````````````````````````````` example
+<http://example.com/\[\>
+.
+<p><a href="http://example.com/%5C%5B%5C">http://example.com/\[\</a></p>
+````````````````````````````````
+
+
+An [email autolink](@)
+consists of `<`, followed by an [email address],
+followed by `>`. The link's label is the email address,
+and the URL is `mailto:` followed by the email address.
+
+An [email address](@),
+for these purposes, is anything that matches
+the [non-normative regex from the HTML5
+spec](https://html.spec.whatwg.org/multipage/forms.html#e-mail-state-(type=email)):
+
+ /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?
+ (?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
+
+Examples of email autolinks:
+
+```````````````````````````````` example
+<foo@bar.example.com>
+.
+<p><a href="mailto:foo@bar.example.com">foo@bar.example.com</a></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<foo+special@Bar.baz-bar0.com>
+.
+<p><a href="mailto:foo+special@Bar.baz-bar0.com">foo+special@Bar.baz-bar0.com</a></p>
+````````````````````````````````
+
+
+Backslash-escapes do not work inside email autolinks:
+
+```````````````````````````````` example
+<foo\+@bar.example.com>
+.
+<p>&lt;foo+@bar.example.com&gt;</p>
+````````````````````````````````
+
+
+These are not autolinks:
+
+```````````````````````````````` example
+<>
+.
+<p>&lt;&gt;</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+< http://foo.bar >
+.
+<p>&lt; http://foo.bar &gt;</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<m:abc>
+.
+<p>&lt;m:abc&gt;</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<foo.bar.baz>
+.
+<p>&lt;foo.bar.baz&gt;</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+http://example.com
+.
+<p>http://example.com</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo@bar.example.com
+.
+<p>foo@bar.example.com</p>
+````````````````````````````````
+
+<div class="extension">
+
+## Autolinks (extension)
+
+GFM enables the `autolink` extension, where autolinks will be recognised in a
+greater number of conditions.
+
+[Autolink]s can also be constructed without requiring the use of `<` and to `>`
+to delimit them, although they will be recognized under a smaller set of
+circumstances. All such recognized autolinks can only come at the beginning of
+a line, after whitespace, or any of the delimiting characters `*`, `_`, `~`,
+and `(`.
+
+An [extended www autolink](@) will be recognized
+when the text `www.` is found followed by a [valid domain].
+A [valid domain](@) consists of segments
+of alphanumeric characters, underscores (`_`) and hyphens (`-`)
+separated by periods (`.`).
+There must be at least one period,
+and no underscores may be present in the last two segments of the domain.
+
+The scheme `http` will be inserted automatically:
+
+```````````````````````````````` example autolink
+www.commonmark.org
+.
+<p><a href="http://www.commonmark.org">www.commonmark.org</a></p>
+````````````````````````````````
+
+After a [valid domain], zero or more non-space non-`<` characters may follow:
+
+```````````````````````````````` example autolink
+Visit www.commonmark.org/help for more information.
+.
+<p>Visit <a href="http://www.commonmark.org/help">www.commonmark.org/help</a> for more information.</p>
+````````````````````````````````
+
+We then apply [extended autolink path validation](@) as follows:
+
+Trailing punctuation (specifically, `?`, `!`, `.`, `,`, `:`, `*`, `_`, and `~`)
+will not be considered part of the autolink, though they may be included in the
+interior of the link:
+
+```````````````````````````````` example autolink
+Visit www.commonmark.org.
+
+Visit www.commonmark.org/a.b.
+.
+<p>Visit <a href="http://www.commonmark.org">www.commonmark.org</a>.</p>
+<p>Visit <a href="http://www.commonmark.org/a.b">www.commonmark.org/a.b</a>.</p>
+````````````````````````````````
+
+When an autolink ends in `)`, we scan the entire autolink for the total number
+of parentheses. If there is a greater number of closing parentheses than
+opening ones, we don't consider the unmatched trailing parentheses part of the
+autolink, in order to facilitate including an autolink inside a parenthesis:
+
+```````````````````````````````` example autolink
+www.google.com/search?q=Markup+(business)
+
+www.google.com/search?q=Markup+(business)))
+
+(www.google.com/search?q=Markup+(business))
+
+(www.google.com/search?q=Markup+(business)
+.
+<p><a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
+<p><a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>))</p>
+<p>(<a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>)</p>
+<p>(<a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
+````````````````````````````````
+
+This check is only done when the link ends in a closing parentheses `)`, so if
+the only parentheses are in the interior of the autolink, no special rules are
+applied:
+
+```````````````````````````````` example autolink
+www.google.com/search?q=(business))+ok
+.
+<p><a href="http://www.google.com/search?q=(business))+ok">www.google.com/search?q=(business))+ok</a></p>
+````````````````````````````````
+
+If an autolink ends in a semicolon (`;`), we check to see if it appears to
+resemble an [entity reference][entity references]; if the preceding text is `&`
+followed by one or more alphanumeric characters. If so, it is excluded from
+the autolink:
+
+```````````````````````````````` example autolink
+www.google.com/search?q=commonmark&hl=en
+
+www.google.com/search?q=commonmark&hl;
+.
+<p><a href="http://www.google.com/search?q=commonmark&amp;hl=en">www.google.com/search?q=commonmark&amp;hl=en</a></p>
+<p><a href="http://www.google.com/search?q=commonmark">www.google.com/search?q=commonmark</a>&amp;hl;</p>
+````````````````````````````````
+
+`<` immediately ends an autolink.
+
+```````````````````````````````` example autolink
+www.commonmark.org/he<lp
+.
+<p><a href="http://www.commonmark.org/he">www.commonmark.org/he</a>&lt;lp</p>
+````````````````````````````````
+
+An [extended url autolink](@) will be recognised when one of the schemes
+`http://`, `https://`, or `ftp://`, followed by a [valid domain], then zero or
+more non-space non-`<` characters according to
+[extended autolink path validation]:
+
+```````````````````````````````` example autolink
+http://commonmark.org
+
+(Visit https://encrypted.google.com/search?q=Markup+(business))
+
+Anonymous FTP is available at ftp://foo.bar.baz.
+.
+<p><a href="http://commonmark.org">http://commonmark.org</a></p>
+<p>(Visit <a href="https://encrypted.google.com/search?q=Markup+(business)">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>
+<p>Anonymous FTP is available at <a href="ftp://foo.bar.baz">ftp://foo.bar.baz</a>.</p>
+````````````````````````````````
+
+
+An [extended email autolink](@) will be recognised when an email address is
+recognised within any text node. Email addresses are recognised according to
+the following rules:
+
+* One ore more characters which are alphanumeric, or `.`, `-`, `_`, or `+`.
+* An `@` symbol.
+* One or more characters which are alphanumeric, or `-` or `_`,
+ separated by periods (`.`).
+ There must be at least one period.
+ The last character must not be one of `-` or `_`.
+
+The scheme `mailto:` will automatically be added to the generated link:
+
+```````````````````````````````` example autolink
+foo@bar.baz
+.
+<p><a href="mailto:foo@bar.baz">foo@bar.baz</a></p>
+````````````````````````````````
+
+`+` can occur before the `@`, but not after.
+
+```````````````````````````````` example autolink
+hello@mail+xyz.example isn't valid, but hello+xyz@mail.example is.
+.
+<p>hello@mail+xyz.example isn't valid, but <a href="mailto:hello+xyz@mail.example">hello+xyz@mail.example</a> is.</p>
+````````````````````````````````
+
+`.`, `-`, and `_` can occur on both sides of the `@`, but only `.` may occur at
+the end of the email address, in which case it will not be considered part of
+the address:
+
+```````````````````````````````` example autolink
+a.b-c_d@a.b
+
+a.b-c_d@a.b.
+
+a.b-c_d@a.b-
+
+a.b-c_d@a.b_
+.
+<p><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a></p>
+<p><a href="mailto:a.b-c_d@a.b">a.b-c_d@a.b</a>.</p>
+<p>a.b-c_d@a.b-</p>
+<p>a.b-c_d@a.b_</p>
+````````````````````````````````
+
+</div>
+
+## Raw HTML
+
+Text between `<` and `>` that looks like an HTML tag is parsed as a
+raw HTML tag and will be rendered in HTML without escaping.
+Tag and attribute names are not limited to current HTML tags,
+so custom tags (and even, say, DocBook tags) may be used.
+
+Here is the grammar for tags:
+
+A [tag name](@) consists of an ASCII letter
+followed by zero or more ASCII letters, digits, or
+hyphens (`-`).
+
+An [attribute](@) consists of [whitespace],
+an [attribute name], and an optional
+[attribute value specification].
+
+An [attribute name](@)
+consists of an ASCII letter, `_`, or `:`, followed by zero or more ASCII
+letters, digits, `_`, `.`, `:`, or `-`. (Note: This is the XML
+specification restricted to ASCII. HTML5 is laxer.)
+
+An [attribute value specification](@)
+consists of optional [whitespace],
+a `=` character, optional [whitespace], and an [attribute
+value].
+
+An [attribute value](@)
+consists of an [unquoted attribute value],
+a [single-quoted attribute value], or a [double-quoted attribute value].
+
+An [unquoted attribute value](@)
+is a nonempty string of characters not
+including [whitespace], `"`, `'`, `=`, `<`, `>`, or `` ` ``.
+
+A [single-quoted attribute value](@)
+consists of `'`, zero or more
+characters not including `'`, and a final `'`.
+
+A [double-quoted attribute value](@)
+consists of `"`, zero or more
+characters not including `"`, and a final `"`.
+
+An [open tag](@) consists of a `<` character, a [tag name],
+zero or more [attributes], optional [whitespace], an optional `/`
+character, and a `>` character.
+
+A [closing tag](@) consists of the string `</`, a
+[tag name], optional [whitespace], and the character `>`.
+
+An [HTML comment](@) consists of `<!--` + *text* + `-->`,
+where *text* does not start with `>` or `->`, does not end with `-`,
+and does not contain `--`. (See the
+[HTML5 spec](http://www.w3.org/TR/html5/syntax.html#comments).)
+
+A [processing instruction](@)
+consists of the string `<?`, a string
+of characters not including the string `?>`, and the string
+`?>`.
+
+A [declaration](@) consists of the
+string `<!`, a name consisting of one or more uppercase ASCII letters,
+[whitespace], a string of characters not including the
+character `>`, and the character `>`.
+
+A [CDATA section](@) consists of
+the string `<![CDATA[`, a string of characters not including the string
+`]]>`, and the string `]]>`.
+
+An [HTML tag](@) consists of an [open tag], a [closing tag],
+an [HTML comment], a [processing instruction], a [declaration],
+or a [CDATA section].
+
+Here are some simple open tags:
+
+```````````````````````````````` example
+<a><bab><c2c>
+.
+<p><a><bab><c2c></p>
+````````````````````````````````
+
+
+Empty elements:
+
+```````````````````````````````` example
+<a/><b2/>
+.
+<p><a/><b2/></p>
+````````````````````````````````
+
+
+[Whitespace] is allowed:
+
+```````````````````````````````` example
+<a /><b2
+data="foo" >
+.
+<p><a /><b2
+data="foo" ></p>
+````````````````````````````````
+
+
+With attributes:
+
+```````````````````````````````` example
+<a foo="bar" bam = 'baz <em>"</em>'
+_boolean zoop:33=zoop:33 />
+.
+<p><a foo="bar" bam = 'baz <em>"</em>'
+_boolean zoop:33=zoop:33 /></p>
+````````````````````````````````
+
+
+Custom tag names can be used:
+
+```````````````````````````````` example
+Foo <responsive-image src="foo.jpg" />
+.
+<p>Foo <responsive-image src="foo.jpg" /></p>
+````````````````````````````````
+
+
+Illegal tag names, not parsed as HTML:
+
+```````````````````````````````` example
+<33> <__>
+.
+<p>&lt;33&gt; &lt;__&gt;</p>
+````````````````````````````````
+
+
+Illegal attribute names:
+
+```````````````````````````````` example
+<a h*#ref="hi">
+.
+<p>&lt;a h*#ref=&quot;hi&quot;&gt;</p>
+````````````````````````````````
+
+
+Illegal attribute values:
+
+```````````````````````````````` example
+<a href="hi'> <a href=hi'>
+.
+<p>&lt;a href=&quot;hi'&gt; &lt;a href=hi'&gt;</p>
+````````````````````````````````
+
+
+Illegal [whitespace]:
+
+```````````````````````````````` example
+< a><
+foo><bar/ >
+<foo bar=baz
+bim!bop />
+.
+<p>&lt; a&gt;&lt;
+foo&gt;&lt;bar/ &gt;
+&lt;foo bar=baz
+bim!bop /&gt;</p>
+````````````````````````````````
+
+
+Missing [whitespace]:
+
+```````````````````````````````` example
+<a href='bar'title=title>
+.
+<p>&lt;a href='bar'title=title&gt;</p>
+````````````````````````````````
+
+
+Closing tags:
+
+```````````````````````````````` example
+</a></foo >
+.
+<p></a></foo ></p>
+````````````````````````````````
+
+
+Illegal attributes in closing tag:
+
+```````````````````````````````` example
+</a href="foo">
+.
+<p>&lt;/a href=&quot;foo&quot;&gt;</p>
+````````````````````````````````
+
+
+Comments:
+
+```````````````````````````````` example
+foo <!-- this is a
+comment - with hyphen -->
+.
+<p>foo <!-- this is a
+comment - with hyphen --></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo <!-- not a comment -- two hyphens -->
+.
+<p>foo &lt;!-- not a comment -- two hyphens --&gt;</p>
+````````````````````````````````
+
+
+Not comments:
+
+```````````````````````````````` example
+foo <!--> foo -->
+
+foo <!-- foo--->
+.
+<p>foo &lt;!--&gt; foo --&gt;</p>
+<p>foo &lt;!-- foo---&gt;</p>
+````````````````````````````````
+
+
+Processing instructions:
+
+```````````````````````````````` example
+foo <?php echo $a; ?>
+.
+<p>foo <?php echo $a; ?></p>
+````````````````````````````````
+
+
+Declarations:
+
+```````````````````````````````` example
+foo <!ELEMENT br EMPTY>
+.
+<p>foo <!ELEMENT br EMPTY></p>
+````````````````````````````````
+
+
+CDATA sections:
+
+```````````````````````````````` example
+foo <![CDATA[>&<]]>
+.
+<p>foo <![CDATA[>&<]]></p>
+````````````````````````````````
+
+
+Entity and numeric character references are preserved in HTML
+attributes:
+
+```````````````````````````````` example
+foo <a href="&ouml;">
+.
+<p>foo <a href="&ouml;"></p>
+````````````````````````````````
+
+
+Backslash escapes do not work in HTML attributes:
+
+```````````````````````````````` example
+foo <a href="\*">
+.
+<p>foo <a href="\*"></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<a href="\"">
+.
+<p>&lt;a href=&quot;&quot;&quot;&gt;</p>
+````````````````````````````````
+
+
+<div class="extension">
+
+## Disallowed Raw HTML (extension)
+
+GFM enables the `tagfilter` extension, where the following HTML tags will be
+filtered when rendering HTML output:
+
+* `<title>`
+* `<textarea>`
+* `<style>`
+* `<xmp>`
+* `<iframe>`
+* `<noembed>`
+* `<noframes>`
+* `<script>`
+* `<plaintext>`
+
+Filtering is done by replacing the leading `<` with the entity `&lt;`. These
+tags are chosen in particular as they change how HTML is interpreted in a way
+unique to them (i.e. nested HTML is interpreted differently), and this is
+usually undesireable in the context of other rendered Markdown content.
+
+All other HTML tags are left untouched.
+
+```````````````````````````````` example tagfilter
+<strong> <title> <style> <em>
+
+<blockquote>
+ <xmp> is disallowed. <XMP> is also disallowed.
+</blockquote>
+.
+<p><strong> &lt;title> &lt;style> <em></p>
+<blockquote>
+ &lt;xmp> is disallowed. &lt;XMP> is also disallowed.
+</blockquote>
+````````````````````````````````
+
+</div>
+
+## Hard line breaks
+
+A line break (not in a code span or HTML tag) that is preceded
+by two or more spaces and does not occur at the end of a block
+is parsed as a [hard line break](@) (rendered
+in HTML as a `<br />` tag):
+
+```````````````````````````````` example
+foo
+baz
+.
+<p>foo<br />
+baz</p>
+````````````````````````````````
+
+
+For a more visible alternative, a backslash before the
+[line ending] may be used instead of two spaces:
+
+```````````````````````````````` example
+foo\
+baz
+.
+<p>foo<br />
+baz</p>
+````````````````````````````````
+
+
+More than two spaces can be used:
+
+```````````````````````````````` example
+foo
+baz
+.
+<p>foo<br />
+baz</p>
+````````````````````````````````
+
+
+Leading spaces at the beginning of the next line are ignored:
+
+```````````````````````````````` example
+foo
+ bar
+.
+<p>foo<br />
+bar</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo\
+ bar
+.
+<p>foo<br />
+bar</p>
+````````````````````````````````
+
+
+Line breaks can occur inside emphasis, links, and other constructs
+that allow inline content:
+
+```````````````````````````````` example
+*foo
+bar*
+.
+<p><em>foo<br />
+bar</em></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+*foo\
+bar*
+.
+<p><em>foo<br />
+bar</em></p>
+````````````````````````````````
+
+
+Line breaks do not occur inside code spans
+
+```````````````````````````````` example
+`code
+span`
+.
+<p><code>code span</code></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+`code\
+span`
+.
+<p><code>code\ span</code></p>
+````````````````````````````````
+
+
+or HTML tags:
+
+```````````````````````````````` example
+<a href="foo
+bar">
+.
+<p><a href="foo
+bar"></p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+<a href="foo\
+bar">
+.
+<p><a href="foo\
+bar"></p>
+````````````````````````````````
+
+
+Hard line breaks are for separating inline content within a block.
+Neither syntax for hard line breaks works at the end of a paragraph or
+other block element:
+
+```````````````````````````````` example
+foo\
+.
+<p>foo\</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+foo
+.
+<p>foo</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+### foo\
+.
+<h3>foo\</h3>
+````````````````````````````````
+
+
+```````````````````````````````` example
+### foo
+.
+<h3>foo</h3>
+````````````````````````````````
+
+
+## Soft line breaks
+
+A regular line break (not in a code span or HTML tag) that is not
+preceded by two or more spaces or a backslash is parsed as a
+[softbreak](@). (A softbreak may be rendered in HTML either as a
+[line ending] or as a space. The result will be the same in
+browsers. In the examples here, a [line ending] will be used.)
+
+```````````````````````````````` example
+foo
+baz
+.
+<p>foo
+baz</p>
+````````````````````````````````
+
+
+Spaces at the end of the line and beginning of the next line are
+removed:
+
+```````````````````````````````` example
+foo
+ baz
+.
+<p>foo
+baz</p>
+````````````````````````````````
+
+
+A conforming parser may render a soft line break in HTML either as a
+line break or as a space.
+
+A renderer may also provide an option to render soft line breaks
+as hard line breaks.
+
+## Textual content
+
+Any characters not given an interpretation by the above rules will
+be parsed as plain textual content.
+
+```````````````````````````````` example
+hello $.;'there
+.
+<p>hello $.;'there</p>
+````````````````````````````````
+
+
+```````````````````````````````` example
+Foo χÏῆν
+.
+<p>Foo χÏῆν</p>
+````````````````````````````````
+
+
+Internal spaces are preserved verbatim:
+
+```````````````````````````````` example
+Multiple spaces
+.
+<p>Multiple spaces</p>
+````````````````````````````````
+
+
+# GitLab Official Specification Markdown
+
+Currently, only some of the GitLab-specific markdown features are
+listed in this section. We may eventually add all
+GitLab-specific features currently listed as supported in the
+[user-facing documentation for GitLab Flavored Markdown](https://docs.gitlab.com/ee/user/markdown.html).
+
+There is currently only this single top-level heading, but the
+examples may be split into multiple top-level headings in the future.
+
+## Footnotes
+
+See
+[the footnotes section of the user-facing documentation for GitLab Flavored Markdown](https://docs.gitlab.com/ee/user/markdown.html#footnotes).
+
+```````````````````````````````` example gitlab
+footnote reference tag [^fortytwo]
+
+[^fortytwo]: footnote text
+.
+<p>
+footnote reference tag
+<sup>
+<a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref>
+1
+</a>
+</sup>
+</p>
+<section data-footnotes>
+<ol>
+<li id="fn-fortytwo-42">
+<p>
+footnote text
+<a href="#fnref-fortytwo-42" data-footnote-backref>
+</a>
+</p>
+</li>
+</ol>
+</section>
+````````````````````````````````
+
+## Task list items
+
+See
+[Task lists](https://docs.gitlab.com/ee/user/markdown.html#task-lists) in the GitLab Flavored Markdown documentation.
+
+Task list items (checkboxes) are defined as a GitHub Flavored Markdown extension in a section above.
+GitLab extends the behavior of task list items to support additional features.
+Some of these features are in-progress, and should not yet be considered part of the official
+GitLab Flavored Markdown specification.
+
+Some of the behavior of task list items is implemented as client-side JavaScript/CSS.
+
+The following are some basic examples; more examples may be added in the future.
+
+Incomplete task:
+
+```````````````````````````````` example gitlab
+- [ ] incomplete
+.
+<ul>
+<li>
+<task-button/>
+<input type="checkbox" disabled/>
+incomplete
+</li>
+</ul>
+````````````````````````````````
+
+Completed task:
+
+```````````````````````````````` example gitlab
+- [x] completed
+.
+<ul>
+<li>
+<task-button/>
+<input type="checkbox" checked disabled/>
+completed
+</li>
+</ul>
+````````````````````````````````
+
+Inapplicable task:
+
+```````````````````````````````` example gitlab
+- [~] inapplicable
+.
+<ul>
+<li>
+<task-button/>
+<input type="checkbox" data-inapplicable disabled>
+<s>
+inapplicable
+</s>
+</li>
+</ul>
+````````````````````````````````
+
+Inapplicable task in a "loose" list. Note that the `<del>` tag is not applied to the
+loose text; it has strikethrough applied with CSS.
+
+```````````````````````````````` example gitlab
+- [~] inapplicable
+
+ text in loose list
+.
+<ul>
+<li>
+<p>
+<task-button/>
+<input type="checkbox" data-inapplicable disabled>
+<s>
+inapplicable
+</s>
+</p>
+<p>
+text in loose list
+</p>
+</li>
+</ul>
+````````````````````````````````
+
+## Front matter
+
+See
+[Front matter](https://docs.gitlab.com/ee/user/markdown.html#front-matter) in the GitLab Flavored Markdown documentation.
+
+Front matter is metadata included at the beginning of a Markdown document, preceding the content.
+This data can be used by static site generators like Jekyll, Hugo, and many other applications.
+
+YAML front matter:
+
+```````````````````````````````` example gitlab
+---
+title: YAML front matter
+---
+.
+<pre>
+<code>
+title: YAML front matter
+</code>
+</pre>
+````````````````````````````````
+
+TOML front matter:
+
+```````````````````````````````` example gitlab
++++
+title: TOML front matter
++++
+.
+<pre>
+<code>
+title: TOML front matter
+</code>
+</pre>
+````````````````````````````````
+
+JSON front matter:
+
+```````````````````````````````` example gitlab
+;;;
+{
+ "title": "JSON front matter"
+}
+;;;
+.
+<pre>
+<code>
+{
+ "title": "JSON front matter"
+}
+</code>
+</pre>
+````````````````````````````````
+
+Front matter blocks should be inserted at the top of the document:
+
+```````````````````````````````` example gitlab
+text
+
+---
+title: YAML front matter
+---
+.
+<p>text</p>
+<hr>
+<h2>title: YAML front matter</h2>
+````````````````````````````````
+
+Front matter block delimiters shouldn’t be preceded by space characters:
+
+```````````````````````````````` example gitlab
+ ---
+title: YAML front matter
+---
+.
+<hr>
+<h2>title: YAML front matter</h2>
+````````````````````````````````
+
+## Table of contents
+
+See
+[table of contents](https://docs.gitlab.com/ee/user/markdown.html#table-of-contents)
+in the GitLab Flavored Markdown documentation.
+
+A table of contents is an unordered list that links to subheadings in the document.
+Add either the `[[_TOC_]]` or `[TOC]` tag on its own line.
+
+```````````````````````````````` example gitlab
+[TOC]
+
+# Heading 1
+
+## Heading 2
+.
+<nav>
+ <ul>
+ <li><a href="#heading-1">Heading 1</a></li>
+ <ul>
+ <li><a href="#heading-2">Heading 2</a></li>
+ </ul>
+ </ul>
+</nav>
+<h1>Heading 1</h1>
+<h2>Heading 2</h2>
+````````````````````````````````
+
+```````````````````````````````` example gitlab
+[[_TOC_]]
+
+# Heading 1
+
+## Heading 2
+.
+<nav>
+ <ul>
+ <li><a href="#heading-1">Heading 1</a></li>
+ <ul>
+ <li><a href="#heading-2">Heading 2</a></li>
+ </ul>
+ </ul>
+</nav>
+<h1>Heading 1</h1>
+<h2>Heading 2</h2>
+````````````````````````````````
+
+A table of contents is a block element. It should preceded and followed by a blank
+line.
+
+```````````````````````````````` example gitlab
+[[_TOC_]]
+text
+
+text
+[TOC]
+.
+<p>[[<em>TOC</em>]]text</p>
+<p>text[TOC]</p>
+````````````````````````````````
+
+A table of contents can be indented with up to three spaces.
+
+```````````````````````````````` example gitlab
+ [[_TOC_]]
+
+# Heading 1
+.
+<nav>
+ <ul>
+ <li><a href="#heading-1">Heading 1</a></li>
+ </ul>
+</nav>
+<h1>Heading 1</h1>
+````````````````````````````````
+
+# GitLab Internal Extension Markdown
+
+## Audio
+
+See
+[audio](https://docs.gitlab.com/ee/user/markdown.html#audio) in the GitLab Flavored Markdown documentation.
+
+GLFM renders image elements as an audio player as long as the resource’s file extension is
+one of the following supported audio extensions `.mp3`, `.oga`, `.ogg`, `.spx`, and `.wav`.
+Audio ignore the alternative text part of an image declaration.
+
+```````````````````````````````` example gitlab
+![audio](audio.oga "audio title")
+.
+<p><audio src="audio.oga" title="audio title"></audio></p>
+````````````````````````````````
+
+Reference definitions work audio as well:
+
+```````````````````````````````` example gitlab
+[audio]: audio.oga "audio title"
+
+![audio][audio]
+.
+<p><audio src="audio.oga" title="audio title"></audio></p>
+````````````````````````````````
+
+## Video
+
+See
+[videos](https://docs.gitlab.com/ee/user/markdown.html#videos) in the GitLab Flavored Markdown documentation.
+
+GLFM renders image elements as a video player as long as the resource’s file extension is
+one of the following supported video extensions `.mp4`, `.m4v`, `.mov`, `.webm`, and `.ogv`.
+Videos ignore the alternative text part of an image declaration.
+
+
+```````````````````````````````` example gitlab
+![video](video.m4v "video title")
+.
+<p><video src="video.m4v" title="video title"></video></p>
+````````````````````````````````
+
+Reference definitions work video as well:
+
+```````````````````````````````` example gitlab
+[video]: video.mov "video title"
+
+![video][video]
+.
+<p><video src="video.mov" title="video title"></video></p>
+````````````````````````````````
+
+## Markdown Preview API Request Overrides
+
+This section contains examples of all controllers which use `PreviewMarkdown` module
+and use different `markdown_context_params`. They exercise the various `preview_markdown`
+endpoints via `glfm_example_metadata.yml`.
+
+
+`preview_markdown` exercising `groups` API endpoint and `UploadLinkFilter`:
+
+```````````````````````````````` example gitlab
+[groups-test-file](/uploads/groups-test-file)
+.
+<p><a href="groups-test-file">groups-test-file</a></p>
+````````````````````````````````
+
+`preview_markdown` exercising `projects` API endpoint and `RepositoryLinkFilter`:
+
+```````````````````````````````` example gitlab
+[projects-test-file](projects-test-file)
+.
+<p><a href="projects-test-file">projects-test-file</a></p>
+````````````````````````````````
+
+`preview_markdown` exercising `projects` API endpoint and `SnippetReferenceFilter`:
+
+```````````````````````````````` example gitlab
+This project snippet ID reference IS filtered: $88888
+.
+<p>This project snippet ID reference IS filtered: $88888</p>
+````````````````````````````````
+
+`preview_markdown` exercising personal (non-project) `snippets` API endpoint. This is
+only used by the comment field on personal snippets. It has no unique custom markdown
+extension behavior, and specifically does not render snippet references via
+`SnippetReferenceFilter`, even if the ID is valid.
+
+```````````````````````````````` example gitlab
+This personal snippet ID reference is not filtered: $99999
+.
+<p>This personal snippet ID reference is not filtered: $99999</p>
+````````````````````````````````
+
+`preview_markdown` exercising project `wikis` API endpoint and `WikiLinkFilter`:
+
+```````````````````````````````` example gitlab
+[project-wikis-test-file](project-wikis-test-file)
+.
+<p><a href="project-wikis-test-file">project-wikis-test-file</a></p>
+````````````````````````````````
+
+`preview_markdown` exercising group `wikis` API endpoint and `WikiLinkFilter`. This example
+also requires an EE license enabling the `group_wikis` feature:
+
+```````````````````````````````` example gitlab
+[group-wikis-test-file](group-wikis-test-file)
+.
+<p><a href="group-wikis-test-file">group-wikis-test-file</a></p>
+````````````````````````````````
diff --git a/glfm_specification/output_spec/spec.html b/glfm_specification/output_spec/spec.html
new file mode 100644
index 00000000000..a10b7f91d91
--- /dev/null
+++ b/glfm_specification/output_spec/spec.html
@@ -0,0 +1,304 @@
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="1:1-4:3" lang="yaml" class="code highlight js-syntax-highlight language-yaml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="yaml"><span class="na">title</span><span class="pi">:</span> <span class="s">GitLab Flavored Markdown (GLFM) Spec</span></span>
+<span id="LC2" class="line" lang="yaml"><span class="na">version</span><span class="pi">:</span> <span class="s">alpha</span></span></code></pre>
+<copy-code></copy-code>
+</div>
+<h1 data-sourcepos="5:1-5:14" dir="auto">
+<a id="user-content-introduction" class="anchor" href="#introduction" aria-hidden="true"></a>Introduction</h1>
+<p data-sourcepos="7:1-7:84" dir="auto">TODO: Write a GitLab-specific version of the GitHub Flavored Markdown intro section.</p>
+
+<h1 data-sourcepos="10:1-10:40" dir="auto">
+<a id="user-content-gitlab-official-specification-markdown" class="anchor" href="#gitlab-official-specification-markdown" aria-hidden="true"></a>GitLab Official Specification Markdown</h1>
+<p data-sourcepos="12:1-15:104" dir="auto">Currently, only some of the GitLab-specific markdown features are
+listed in this section. We may eventually add all
+GitLab-specific features currently listed as supported in the
+<a href="https://docs.gitlab.com/ee/user/markdown.html" rel="nofollow noreferrer noopener" target="_blank">user-facing documentation for GitLab Flavored Markdown</a>.</p>
+<p data-sourcepos="17:1-18:69" dir="auto">There is currently only this single top-level heading, but the
+examples may be split into multiple top-level headings in the future.</p>
+<h2 data-sourcepos="20:1-20:12" dir="auto">
+<a id="user-content-footnotes" class="anchor" href="#footnotes" aria-hidden="true"></a>Footnotes</h2>
+<p data-sourcepos="22:1-23:143" dir="auto">See
+<a href="https://docs.gitlab.com/ee/user/markdown.html#footnotes" rel="nofollow noreferrer noopener" target="_blank">the footnotes section of the user-facing documentation for GitLab Flavored Markdown</a>.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="25:1-29:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">footnote reference tag [^fortytwo]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">[^fortytwo]: footnote text</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="31:1-51:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">footnote reference tag</span>
+<span id="LC3" class="line" lang="plaintext">&lt;sup&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref&gt;</span>
+<span id="LC5" class="line" lang="plaintext">1</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/a&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/sup&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/p&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;section data-footnotes&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;ol&gt;</span>
+<span id="LC11" class="line" lang="plaintext">&lt;li id="fn-fortytwo-42"&gt;</span>
+<span id="LC12" class="line" lang="plaintext">&lt;p&gt;</span>
+<span id="LC13" class="line" lang="plaintext">footnote text</span>
+<span id="LC14" class="line" lang="plaintext">&lt;a href="#fnref-fortytwo-42" data-footnote-backref&gt;</span>
+<span id="LC15" class="line" lang="plaintext">&lt;/a&gt;</span>
+<span id="LC16" class="line" lang="plaintext">&lt;/p&gt;</span>
+<span id="LC17" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC18" class="line" lang="plaintext">&lt;/ol&gt;</span>
+<span id="LC19" class="line" lang="plaintext">&lt;/section&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="53:1-53:18" dir="auto">
+<a id="user-content-task-list-items" class="anchor" href="#task-list-items" aria-hidden="true"></a>Task list items</h2>
+<p data-sourcepos="55:1-56:117" dir="auto">See
+<a href="https://docs.gitlab.com/ee/user/markdown.html#task-lists" rel="nofollow noreferrer noopener" target="_blank">Task lists</a> in the GitLab Flavored Markdown documentation.</p>
+<p data-sourcepos="58:1-61:39" dir="auto">Task list items (checkboxes) are defined as a GitHub Flavored Markdown extension in a section above.
+GitLab extends the behavior of task list items to support additional features.
+Some of these features are in-progress, and should not yet be considered part of the official
+GitLab Flavored Markdown specification.</p>
+<p data-sourcepos="63:1-63:85" dir="auto">Some of the behavior of task list items is implemented as client-side JavaScript/CSS.</p>
+<p data-sourcepos="65:1-65:80" dir="auto">The following are some basic examples; more examples may be added in the future.</p>
+<p data-sourcepos="67:1-67:16" dir="auto">Incomplete task:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="69:1-71:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [ ] incomplete</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="73:1-81:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;task-button/&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;input type="checkbox" disabled/&gt;</span>
+<span id="LC5" class="line" lang="plaintext">incomplete</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="83:1-83:15" dir="auto">Completed task:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="85:1-87:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [x] completed</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="89:1-97:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;task-button/&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;input type="checkbox" checked disabled/&gt;</span>
+<span id="LC5" class="line" lang="plaintext">completed</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="99:1-99:18" dir="auto">Inapplicable task:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="101:1-103:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [~] inapplicable</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="105:1-115:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;task-button/&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;input type="checkbox" data-inapplicable disabled&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;s&gt;</span>
+<span id="LC6" class="line" lang="plaintext">inapplicable</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/s&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="117:1-118:50" dir="auto">Inapplicable task in a "loose" list. Note that the <code>&lt;del&gt;</code> tag is not applied to the
+loose text; it has strikethrough applied with CSS.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="120:1-124:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">- [~] inapplicable</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"> text in loose list</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="126:1-141:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;ul&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;li&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;p&gt;</span>
+<span id="LC4" class="line" lang="plaintext">&lt;task-button/&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;input type="checkbox" data-inapplicable disabled&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;s&gt;</span>
+<span id="LC7" class="line" lang="plaintext">inapplicable</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/s&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;/p&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;p&gt;</span>
+<span id="LC11" class="line" lang="plaintext">text in loose list</span>
+<span id="LC12" class="line" lang="plaintext">&lt;/p&gt;</span>
+<span id="LC13" class="line" lang="plaintext">&lt;/li&gt;</span>
+<span id="LC14" class="line" lang="plaintext">&lt;/ul&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="143:1-143:15" dir="auto">
+<a id="user-content-front-matter" class="anchor" href="#front-matter" aria-hidden="true"></a>Front matter</h2>
+<p data-sourcepos="145:1-146:121" dir="auto">See
+<a href="https://docs.gitlab.com/ee/user/markdown.html#front-matter" rel="nofollow noreferrer noopener" target="_blank">Front matter</a> in the GitLab Flavored Markdown documentation.</p>
+<p data-sourcepos="148:1-149:95" dir="auto">Front matter is metadata included at the beginning of a Markdown document, preceding the content.
+This data can be used by static site generators like Jekyll, Hugo, and many other applications.</p>
+<p data-sourcepos="151:1-151:18" dir="auto">YAML front matter:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="153:1-157:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">---</span>
+<span id="LC2" class="line" lang="plaintext">title: YAML front matter</span>
+<span id="LC3" class="line" lang="plaintext">---</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="159:1-165:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;code&gt;</span>
+<span id="LC3" class="line" lang="plaintext">title: YAML front matter</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="167:1-167:18" dir="auto">TOML front matter:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="169:1-173:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">+++</span>
+<span id="LC2" class="line" lang="plaintext">title: TOML front matter</span>
+<span id="LC3" class="line" lang="plaintext">+++</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="175:1-181:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;code&gt;</span>
+<span id="LC3" class="line" lang="plaintext">title: TOML front matter</span>
+<span id="LC4" class="line" lang="plaintext">&lt;/code&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="183:1-183:18" dir="auto">JSON front matter:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="185:1-191:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">;;;</span>
+<span id="LC2" class="line" lang="plaintext">{</span>
+<span id="LC3" class="line" lang="plaintext"> "title": "JSON front matter"</span>
+<span id="LC4" class="line" lang="plaintext">}</span>
+<span id="LC5" class="line" lang="plaintext">;;;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="193:1-201:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;pre&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;code&gt;</span>
+<span id="LC3" class="line" lang="plaintext">{</span>
+<span id="LC4" class="line" lang="plaintext"> "title": "JSON front matter"</span>
+<span id="LC5" class="line" lang="plaintext">}</span>
+<span id="LC6" class="line" lang="plaintext">&lt;/code&gt;</span>
+<span id="LC7" class="line" lang="plaintext">&lt;/pre&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="203:1-203:66" dir="auto">Front matter blocks should be inserted at the top of the document:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="205:1-211:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">text</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext">---</span>
+<span id="LC4" class="line" lang="plaintext">title: YAML front matter</span>
+<span id="LC5" class="line" lang="plaintext">---</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="213:1-217:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;text&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;hr&gt;</span>
+<span id="LC3" class="line" lang="plaintext">&lt;h2&gt;title: YAML front matter&lt;/h2&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="219:1-219:74" dir="auto">Front matter block delimiters shouldn’t be preceded by space characters:</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="221:1-225:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> ---</span>
+<span id="LC2" class="line" lang="plaintext">title: YAML front matter</span>
+<span id="LC3" class="line" lang="plaintext">---</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="227:1-230:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;hr&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;h2&gt;title: YAML front matter&lt;/h2&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<h2 data-sourcepos="232:1-232:20" dir="auto">
+<a id="user-content-table-of-contents" class="anchor" href="#table-of-contents" aria-hidden="true"></a>Table of contents</h2>
+<p data-sourcepos="234:1-236:46" dir="auto">See
+<a href="https://docs.gitlab.com/ee/user/markdown.html#table-of-contents" rel="nofollow noreferrer noopener" target="_blank">table of contents</a>
+in the GitLab Flavored Markdown documentation.</p>
+<p data-sourcepos="238:1-239:58" dir="auto">A table of contents is an unordered list that links to subheadings in the document.
+Add either the <code>[[_TOC_]]</code> or </p><ul class="section-nav">
+<li><a href="#introduction">Introduction</a></li>
+<li>
+<a href="#gitlab-official-specification-markdown">GitLab Official Specification Markdown</a><ul>
+<li><a href="#footnotes">Footnotes</a></li>
+<li><a href="#task-list-items">Task list items</a></li>
+<li><a href="#front-matter">Front matter</a></li>
+<li><a href="#table-of-contents">Table of contents</a></li>
+</ul>
+</li>
+</ul> tag on its own line.
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="241:1-247:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[TOC]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"># Heading 1</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">## Heading 2</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="249:1-260:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;nav&gt;</span>
+<span id="LC2" class="line" lang="plaintext"> &lt;ul&gt;</span>
+<span id="LC3" class="line" lang="plaintext"> &lt;li&gt;&lt;a href="#heading-1"&gt;Heading 1&lt;/a&gt;&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext"> &lt;ul&gt;</span>
+<span id="LC5" class="line" lang="plaintext"> &lt;li&gt;&lt;a href="#heading-2"&gt;Heading 2&lt;/a&gt;&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext"> &lt;/ul&gt;</span>
+<span id="LC7" class="line" lang="plaintext"> &lt;/ul&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/nav&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;h1&gt;Heading 1&lt;/h1&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;h2&gt;Heading 2&lt;/h2&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="262:1-268:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[[_TOC_]]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"># Heading 1</span>
+<span id="LC4" class="line" lang="plaintext"></span>
+<span id="LC5" class="line" lang="plaintext">## Heading 2</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="270:1-281:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;nav&gt;</span>
+<span id="LC2" class="line" lang="plaintext"> &lt;ul&gt;</span>
+<span id="LC3" class="line" lang="plaintext"> &lt;li&gt;&lt;a href="#heading-1"&gt;Heading 1&lt;/a&gt;&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext"> &lt;ul&gt;</span>
+<span id="LC5" class="line" lang="plaintext"> &lt;li&gt;&lt;a href="#heading-2"&gt;Heading 2&lt;/a&gt;&lt;/li&gt;</span>
+<span id="LC6" class="line" lang="plaintext"> &lt;/ul&gt;</span>
+<span id="LC7" class="line" lang="plaintext"> &lt;/ul&gt;</span>
+<span id="LC8" class="line" lang="plaintext">&lt;/nav&gt;</span>
+<span id="LC9" class="line" lang="plaintext">&lt;h1&gt;Heading 1&lt;/h1&gt;</span>
+<span id="LC10" class="line" lang="plaintext">&lt;h2&gt;Heading 2&lt;/h2&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="283:1-284:5" dir="auto">A table of contents is a block element. It should preceded and followed by a blank
+line.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="286:1-292:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">[[_TOC_]]</span>
+<span id="LC2" class="line" lang="plaintext">text</span>
+<span id="LC3" class="line" lang="plaintext"></span>
+<span id="LC4" class="line" lang="plaintext">text</span>
+<span id="LC5" class="line" lang="plaintext">[TOC]</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="294:1-297:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;[[&lt;em&gt;TOC&lt;/em&gt;]]text&lt;/p&gt;</span>
+<span id="LC2" class="line" lang="plaintext">&lt;p&gt;text[TOC]&lt;/p&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+<p data-sourcepos="299:1-299:60" dir="auto">A table of contents can be indented with up to three spaces.</p>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="301:1-305:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> [[_TOC_]]</span>
+<span id="LC2" class="line" lang="plaintext"></span>
+<span id="LC3" class="line" lang="plaintext"># Heading 1</span></code></pre>
+<copy-code></copy-code>
+</div>
+<div class="gl-relative markdown-code-block js-markdown-code">
+<pre data-sourcepos="307:1-314:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;nav&gt;</span>
+<span id="LC2" class="line" lang="plaintext"> &lt;ul&gt;</span>
+<span id="LC3" class="line" lang="plaintext"> &lt;li&gt;&lt;a href="#heading-1"&gt;Heading 1&lt;/a&gt;&lt;/li&gt;</span>
+<span id="LC4" class="line" lang="plaintext"> &lt;/ul&gt;</span>
+<span id="LC5" class="line" lang="plaintext">&lt;/nav&gt;</span>
+<span id="LC6" class="line" lang="plaintext">&lt;h1&gt;Heading 1&lt;/h1&gt;</span></code></pre>
+<copy-code></copy-code>
+</div>
+
diff --git a/glfm_specification/output_spec/spec.txt b/glfm_specification/output_spec/spec.txt
new file mode 100644
index 00000000000..e16975ac51f
--- /dev/null
+++ b/glfm_specification/output_spec/spec.txt
@@ -0,0 +1,287 @@
+---
+title: GitLab Flavored Markdown (GLFM) Spec
+version: alpha
+...
+# Introduction
+
+TODO: Write a GitLab-specific version of the GitHub Flavored Markdown intro section.
+
+<!-- BEGIN TESTS -->
+# GitLab Official Specification Markdown
+
+Currently, only some of the GitLab-specific markdown features are
+listed in this section. We may eventually add all
+GitLab-specific features currently listed as supported in the
+[user-facing documentation for GitLab Flavored Markdown](https://docs.gitlab.com/ee/user/markdown.html).
+
+There is currently only this single top-level heading, but the
+examples may be split into multiple top-level headings in the future.
+
+## Footnotes
+
+See
+[the footnotes section of the user-facing documentation for GitLab Flavored Markdown](https://docs.gitlab.com/ee/user/markdown.html#footnotes).
+
+```````````````````````````````` example gitlab
+footnote reference tag [^fortytwo]
+
+[^fortytwo]: footnote text
+.
+<p>
+footnote reference tag
+<sup>
+<a href="#fn-fortytwo-42" id="fnref-fortytwo-42" data-footnote-ref>
+1
+</a>
+</sup>
+</p>
+<section data-footnotes>
+<ol>
+<li id="fn-fortytwo-42">
+<p>
+footnote text
+<a href="#fnref-fortytwo-42" data-footnote-backref>
+</a>
+</p>
+</li>
+</ol>
+</section>
+````````````````````````````````
+
+## Task list items
+
+See
+[Task lists](https://docs.gitlab.com/ee/user/markdown.html#task-lists) in the GitLab Flavored Markdown documentation.
+
+Task list items (checkboxes) are defined as a GitHub Flavored Markdown extension in a section above.
+GitLab extends the behavior of task list items to support additional features.
+Some of these features are in-progress, and should not yet be considered part of the official
+GitLab Flavored Markdown specification.
+
+Some of the behavior of task list items is implemented as client-side JavaScript/CSS.
+
+The following are some basic examples; more examples may be added in the future.
+
+Incomplete task:
+
+```````````````````````````````` example gitlab
+- [ ] incomplete
+.
+<ul>
+<li>
+<task-button/>
+<input type="checkbox" disabled/>
+incomplete
+</li>
+</ul>
+````````````````````````````````
+
+Completed task:
+
+```````````````````````````````` example gitlab
+- [x] completed
+.
+<ul>
+<li>
+<task-button/>
+<input type="checkbox" checked disabled/>
+completed
+</li>
+</ul>
+````````````````````````````````
+
+Inapplicable task:
+
+```````````````````````````````` example gitlab
+- [~] inapplicable
+.
+<ul>
+<li>
+<task-button/>
+<input type="checkbox" data-inapplicable disabled>
+<s>
+inapplicable
+</s>
+</li>
+</ul>
+````````````````````````````````
+
+Inapplicable task in a "loose" list. Note that the `<del>` tag is not applied to the
+loose text; it has strikethrough applied with CSS.
+
+```````````````````````````````` example gitlab
+- [~] inapplicable
+
+ text in loose list
+.
+<ul>
+<li>
+<p>
+<task-button/>
+<input type="checkbox" data-inapplicable disabled>
+<s>
+inapplicable
+</s>
+</p>
+<p>
+text in loose list
+</p>
+</li>
+</ul>
+````````````````````````````````
+
+## Front matter
+
+See
+[Front matter](https://docs.gitlab.com/ee/user/markdown.html#front-matter) in the GitLab Flavored Markdown documentation.
+
+Front matter is metadata included at the beginning of a Markdown document, preceding the content.
+This data can be used by static site generators like Jekyll, Hugo, and many other applications.
+
+YAML front matter:
+
+```````````````````````````````` example gitlab
+---
+title: YAML front matter
+---
+.
+<pre>
+<code>
+title: YAML front matter
+</code>
+</pre>
+````````````````````````````````
+
+TOML front matter:
+
+```````````````````````````````` example gitlab
++++
+title: TOML front matter
++++
+.
+<pre>
+<code>
+title: TOML front matter
+</code>
+</pre>
+````````````````````````````````
+
+JSON front matter:
+
+```````````````````````````````` example gitlab
+;;;
+{
+ "title": "JSON front matter"
+}
+;;;
+.
+<pre>
+<code>
+{
+ "title": "JSON front matter"
+}
+</code>
+</pre>
+````````````````````````````````
+
+Front matter blocks should be inserted at the top of the document:
+
+```````````````````````````````` example gitlab
+text
+
+---
+title: YAML front matter
+---
+.
+<p>text</p>
+<hr>
+<h2>title: YAML front matter</h2>
+````````````````````````````````
+
+Front matter block delimiters shouldn’t be preceded by space characters:
+
+```````````````````````````````` example gitlab
+ ---
+title: YAML front matter
+---
+.
+<hr>
+<h2>title: YAML front matter</h2>
+````````````````````````````````
+
+## Table of contents
+
+See
+[table of contents](https://docs.gitlab.com/ee/user/markdown.html#table-of-contents)
+in the GitLab Flavored Markdown documentation.
+
+A table of contents is an unordered list that links to subheadings in the document.
+Add either the `[[_TOC_]]` or `[TOC]` tag on its own line.
+
+```````````````````````````````` example gitlab
+[TOC]
+
+# Heading 1
+
+## Heading 2
+.
+<nav>
+ <ul>
+ <li><a href="#heading-1">Heading 1</a></li>
+ <ul>
+ <li><a href="#heading-2">Heading 2</a></li>
+ </ul>
+ </ul>
+</nav>
+<h1>Heading 1</h1>
+<h2>Heading 2</h2>
+````````````````````````````````
+
+```````````````````````````````` example gitlab
+[[_TOC_]]
+
+# Heading 1
+
+## Heading 2
+.
+<nav>
+ <ul>
+ <li><a href="#heading-1">Heading 1</a></li>
+ <ul>
+ <li><a href="#heading-2">Heading 2</a></li>
+ </ul>
+ </ul>
+</nav>
+<h1>Heading 1</h1>
+<h2>Heading 2</h2>
+````````````````````````````````
+
+A table of contents is a block element. It should preceded and followed by a blank
+line.
+
+```````````````````````````````` example gitlab
+[[_TOC_]]
+text
+
+text
+[TOC]
+.
+<p>[[<em>TOC</em>]]text</p>
+<p>text[TOC]</p>
+````````````````````````````````
+
+A table of contents can be indented with up to three spaces.
+
+```````````````````````````````` example gitlab
+ [[_TOC_]]
+
+# Heading 1
+.
+<nav>
+ <ul>
+ <li><a href="#heading-1">Heading 1</a></li>
+ </ul>
+</nav>
+<h1>Heading 1</h1>
+````````````````````````````````
+<!-- END TESTS -->
diff --git a/jest.config.base.js b/jest.config.base.js
index a6c22a8877c..30e11122f81 100644
--- a/jest.config.base.js
+++ b/jest.config.base.js
@@ -159,7 +159,7 @@ module.exports = (path, options = {}) => {
return {
clearMocks: true,
testMatch,
- moduleFileExtensions: ['js', 'json', 'vue', 'gql', 'graphql', 'yaml'],
+ moduleFileExtensions: ['js', 'json', 'vue', 'gql', 'graphql', 'yaml', 'yml'],
moduleNameMapper,
collectCoverageFrom,
coverageDirectory: coverageDirectory(),
@@ -180,7 +180,7 @@ module.exports = (path, options = {}) => {
'^.+\\.vue$': '@vue/vue2-jest',
'spec/frontend/editor/schema/ci/yaml_tests/.+\\.(yml|yaml)$':
'./spec/frontend/__helpers__/yaml_transformer.js',
- '^.+\\.(md|zip|png|yml|yaml)$': 'jest-raw-loader',
+ '^.+\\.(md|zip|png|yml|yaml)$': './spec/frontend/__helpers__/raw_transformer.js',
},
transformIgnorePatterns: [`node_modules/(?!(${transformIgnoreNodeModules.join('|')}))`],
timers: 'legacy',
diff --git a/lefthook.yml b/lefthook.yml
index a2819358bdf..dc2c0b70c6f 100644
--- a/lefthook.yml
+++ b/lefthook.yml
@@ -54,7 +54,7 @@ pre-push:
glob: 'doc/*.md'
run: 'if [ $VALE_WARNINGS ]; then minWarnings=warning; else minWarnings=error; fi; if command -v vale > /dev/null 2>&1; then if ! vale --config .vale.ini --minAlertLevel $minWarnings {files}; then echo "ERROR: Fix any linting errors and make sure you are using the latest version of Vale."; exit 1; fi; else echo "ERROR: Vale not found. For more information, see https://docs.errata.ai/vale/install."; exit 1; fi'
gettext:
- 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/full_guide.md#skipping-commands
+ 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
tags: backend frontend view haml
files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD | while read file;do git diff --unified=1 $(git merge-base origin/master HEAD)..HEAD $file | grep -Fqe '_(' && echo $file;done; true
glob: "*.{haml,rb,js,vue}"
@@ -79,3 +79,7 @@ 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
+ secrets-detection:
+ tags: secrets
+ files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD
+ run: 'if command -v ripsecrets > /dev/null 2>&1; then ripsecrets --strict-ignore {files}; else echo "WARNING: ripsecrets is not installed. Please install it."; fi'
diff --git a/lib/api/access_requests.rb b/lib/api/access_requests.rb
index 74f6515f07f..38a9856ca58 100644
--- a/lib/api/access_requests.rb
+++ b/lib/api/access_requests.rb
@@ -19,6 +19,7 @@ module API
desc "Gets a list of access requests for a #{source_type}." do
detail 'This feature was introduced in GitLab 8.11.'
success Entities::AccessRequester
+ tags %w[access_requests]
end
params do
use :pagination
@@ -37,6 +38,24 @@ module API
desc "Requests access for the authenticated user to a #{source_type}." do
detail 'This feature was introduced in GitLab 8.11.'
success Entities::AccessRequester
+ success [
+ {
+ code: 200,
+ model: Entities::AccessRequester,
+ message: 'successful operation',
+ examples: {
+ successfull_response: {
+ "id" => 1,
+ "username" => "raymond_smith",
+ "name" => "Raymond Smith",
+ "state" => "active",
+ "created_at" => "2012-10-22T14:13:35Z",
+ "access_level" => 20
+ }
+ }
+ }
+ ]
+ tags %w[access_requests]
end
post ":id/access_requests" do
source = find_source(source_type, params[:id])
@@ -51,7 +70,24 @@ module API
desc 'Approves an access request for the given user.' do
detail 'This feature was introduced in GitLab 8.11.'
- success Entities::Member
+ success [
+ {
+ code: 200,
+ model: Entities::AccessRequester,
+ message: 'successful operation',
+ examples: {
+ successfull_response: {
+ "id" => 1,
+ "username" => "raymond_smith",
+ "name" => "Raymond Smith",
+ "state" => "active",
+ "created_at" => "2012-10-22T14:13:35Z",
+ "access_level" => 20
+ }
+ }
+ }
+ ]
+ tags %w[access_requests]
end
params do
requires :user_id, type: Integer, desc: 'The user ID of the access requester'
@@ -74,6 +110,7 @@ module API
desc 'Denies an access request for the given user.' do
detail 'This feature was introduced in GitLab 8.11.'
+ tags %w[access_requests]
end
params do
requires :user_id, type: Integer, desc: 'The user ID of the access requester'
diff --git a/lib/api/admin/ci/variables.rb b/lib/api/admin/ci/variables.rb
index 0462878c90c..bc351e27f99 100644
--- a/lib/api/admin/ci/variables.rb
+++ b/lib/api/admin/ci/variables.rb
@@ -13,8 +13,9 @@ module API
namespace 'admin' do
namespace 'ci' do
namespace 'variables' do
- desc 'Get instance-level variables' do
+ desc 'List all instance-level variables' do
success Entities::Ci::Variable
+ tags %w[ci_variables]
end
params do
use :pagination
@@ -25,11 +26,13 @@ module API
present paginate(variables), with: Entities::Ci::Variable
end
- desc 'Get a specific variable from a group' do
+ desc 'Get the details of a specific instance-level variable' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Instance Variable Not Found' }]
+ tags %w[ci_variables]
end
params do
- requires :key, type: String, desc: 'The key of the variable'
+ requires :key, type: String, desc: 'The key of a variable'
end
get ':key' do
key = params[:key]
@@ -42,28 +45,35 @@ module API
desc 'Create a new instance-level variable' do
success Entities::Ci::Variable
+ failure [{ code: 400, message: '400 Bad Request' }]
+ tags %w[ci_variables]
end
+ route_setting :log_safety, { safe: %w[key], unsafe: %w[value] }
params do
requires :key,
type: String,
- desc: 'The key of the variable'
+ desc: 'The key of the variable. Max 255 characters'
requires :value,
type: String,
- desc: 'The value of the variable'
+ desc: 'The value of a variable'
optional :protected,
- type: String,
+ type: Boolean,
desc: 'Whether the variable is protected'
optional :masked,
- type: String,
+ type: Boolean,
desc: 'Whether the variable is masked'
+ optional :raw,
+ type: Boolean,
+ desc: 'Whether the variable will be expanded'
+
optional :variable_type,
type: String,
values: ::Ci::InstanceVariable.variable_types.keys,
- desc: 'The type of variable, must be one of env_var or file. Defaults to env_var'
+ desc: 'The type of a variable. Available types are: env_var (default) and file'
end
post '/' do
variable_params = declared_params(include_missing: false)
@@ -77,30 +87,37 @@ module API
end
end
- desc 'Update an existing instance-variable' do
+ desc 'Update an instance-level variable' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Instance Variable Not Found' }]
+ tags %w[ci_variables]
end
+ route_setting :log_safety, { safe: %w[key], unsafe: %w[value] }
params do
optional :key,
type: String,
- desc: 'The key of the variable'
+ desc: 'The key of a variable'
optional :value,
type: String,
- desc: 'The value of the variable'
+ desc: 'The value of a variable'
optional :protected,
- type: String,
+ type: Boolean,
desc: 'Whether the variable is protected'
optional :masked,
- type: String,
+ type: Boolean,
desc: 'Whether the variable is masked'
+ optional :raw,
+ type: Boolean,
+ desc: 'Whether the variable will be expanded'
+
optional :variable_type,
type: String,
values: ::Ci::InstanceVariable.variable_types.keys,
- desc: 'The type of variable, must be one of env_var or file'
+ desc: 'The type of a variable. Available types are: env_var (default) and file'
end
put ':key' do
variable = ::Ci::InstanceVariable.find_by_key(params[:key])
@@ -118,9 +135,11 @@ module API
desc 'Delete an existing instance-level variable' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Instance Variable Not Found' }]
+ tags %w[ci_variables]
end
params do
- requires :key, type: String, desc: 'The key of the variable'
+ requires :key, type: String, desc: 'The key of a variable'
end
delete ':key' do
variable = ::Ci::InstanceVariable.find_by_key(params[:key])
diff --git a/lib/api/admin/instance_clusters.rb b/lib/api/admin/instance_clusters.rb
index 7163225777a..f848103d9a0 100644
--- a/lib/api/admin/instance_clusters.rb
+++ b/lib/api/admin/instance_clusters.rb
@@ -14,16 +14,28 @@ module API
end
namespace 'admin' do
- desc "Get list of all instance clusters" do
- detail "This feature was introduced in GitLab 13.2."
+ desc 'List instance clusters' do
+ detail 'This feature was introduced in GitLab 13.2. Returns a list of instance clusters.'
+ success Entities::Cluster
+ failure [
+ { code: 403, message: 'Forbidden' }
+ ]
+ is_array true
+ tags %w[clusters]
end
get '/clusters' do
authorize! :read_cluster, clusterable_instance
present paginate(clusters_for_current_user), with: Entities::Cluster
end
- desc "Get a single instance cluster" do
- detail "This feature was introduced in GitLab 13.2."
+ desc 'Get a single instance cluster' do
+ detail 'This feature was introduced in GitLab 13.2. Returns a single instance cluster.'
+ success Entities::Cluster
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: "The cluster ID"
@@ -34,8 +46,15 @@ module API
present cluster, with: Entities::Cluster
end
- desc "Add an instance cluster" do
- detail "This feature was introduced in GitLab 13.2."
+ desc 'Add existing instance cluster' do
+ detail 'This feature was introduced in GitLab 13.2. Adds an existing Kubernetes instance cluster.'
+ success Entities::Cluster
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :name, type: String, desc: 'Cluster name'
@@ -67,8 +86,15 @@ module API
end
end
- desc "Update an instance cluster" do
- detail "This feature was introduced in GitLab 13.2."
+ desc 'Edit instance cluster' do
+ detail 'This feature was introduced in GitLab 13.2. Updates an existing instance cluster.'
+ success Entities::Cluster
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
@@ -98,8 +124,14 @@ module API
end
end
- desc "Remove a cluster" do
- detail "This feature was introduced in GitLab 13.2."
+ desc 'Delete instance cluster' do
+ detail 'This feature was introduced in GitLab 13.2. Deletes an existing instance cluster. Does not remove existing resources within the connected Kubernetes cluster.'
+ success Entities::Cluster
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: "The cluster ID"
diff --git a/lib/api/admin/plan_limits.rb b/lib/api/admin/plan_limits.rb
index 7ce70d85d46..49b41b44a18 100644
--- a/lib/api/admin/plan_limits.rb
+++ b/lib/api/admin/plan_limits.rb
@@ -5,6 +5,8 @@ module API
class PlanLimits < ::API::Base
before { authenticated_as_admin! }
+ PLAN_LIMITS_TAGS = %w[plan_limits].freeze
+
feature_category :not_owned # rubocop:todo Gitlab/AvoidFeatureCategoryNotOwned
helpers do
@@ -17,10 +19,17 @@ module API
end
desc 'Get current plan limits' do
+ detail 'List the current limits of a plan on the GitLab instance.'
success Entities::PlanLimit
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' }
+ ]
+ tags PLAN_LIMITS_TAGS
end
params do
- optional :plan_name, type: String, values: Plan.all_plans, default: Plan::DEFAULT, desc: 'Name of the plan'
+ optional :plan_name, type: String, values: Plan.all_plans, default: Plan::DEFAULT,
+ desc: 'Name of the plan to get the limits from. Default: default.'
end
get "application/plan_limits" do
params = declared_params(include_missing: false)
@@ -29,16 +38,24 @@ module API
present plan.actual_limits, with: Entities::PlanLimit
end
- desc 'Modify plan limits' do
+ desc 'Change plan limits' do
+ detail 'Modify the limits of a plan on the GitLab instance.'
success Entities::PlanLimit
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' }
+ ]
+ tags PLAN_LIMITS_TAGS
end
params do
- requires :plan_name, type: String, values: Plan.all_plans, desc: 'Name of the plan'
+ requires :plan_name, type: String, values: Plan.all_plans, desc: 'Name of the plan to update'
optional :ci_pipeline_size, type: Integer, desc: 'Maximum number of jobs in a single pipeline'
optional :ci_active_jobs, type: Integer, desc: 'Total number of jobs in currently active pipelines'
optional :ci_active_pipelines, type: Integer, desc: 'Maximum number of active pipelines per project'
- optional :ci_project_subscriptions, type: Integer, desc: 'Maximum number of pipeline subscriptions to and from a project'
+ optional :ci_project_subscriptions, type: Integer,
+ desc: 'Maximum number of pipeline subscriptions to and from a project'
optional :ci_pipeline_schedules, type: Integer, desc: 'Maximum number of pipeline schedules'
optional :ci_needs_size_limit, type: Integer, desc: 'Maximum number of DAG dependencies that a job can have'
optional :ci_registered_group_runners, type: Integer, desc: 'Maximum number of runners registered per group'
@@ -50,7 +67,8 @@ module API
optional :npm_max_file_size, type: Integer, desc: 'Maximum NPM package file size in bytes'
optional :nuget_max_file_size, type: Integer, desc: 'Maximum NuGet package file size in bytes'
optional :pypi_max_file_size, type: Integer, desc: 'Maximum PyPI package file size in bytes'
- optional :terraform_module_max_file_size, type: Integer, desc: 'Maximum Terraform Module package file size in bytes'
+ optional :terraform_module_max_file_size, type: Integer,
+ desc: 'Maximum Terraform Module package file size in bytes'
optional :storage_size_limit, type: Integer, desc: 'Maximum storage size for the root namespace in megabytes'
end
put "application/plan_limits" do
diff --git a/lib/api/alert_management_alerts.rb b/lib/api/alert_management_alerts.rb
index f03f133f6f7..f57b7d00c81 100644
--- a/lib/api/alert_management_alerts.rb
+++ b/lib/api/alert_management_alerts.rb
@@ -6,7 +6,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
requires :alert_iid, type: Integer, desc: 'The IID of the Alert'
end
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 933c3f69075..ffb0cdf8991 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -13,13 +13,14 @@ module API
USER_REQUIREMENTS = { user_id: NO_SLASH_URL_PART_REGEX }.freeze
LOG_FILTERS = ::Rails.application.config.filter_parameters + [/^output$/]
LOG_FORMATTER = Gitlab::GrapeLogging::Formatters::LogrageWithTimestamp.new
+ LOGGER = Logger.new(LOG_FILENAME)
insert_before Grape::Middleware::Error,
GrapeLogging::Middleware::RequestLogger,
- logger: Logger.new(LOG_FILENAME),
+ logger: LOGGER,
formatter: LOG_FORMATTER,
include: [
- GrapeLogging::Loggers::FilterParameters.new(LOG_FILTERS),
+ Gitlab::GrapeLogging::Loggers::FilterParameters.new(LOG_FILTERS),
Gitlab::GrapeLogging::Loggers::ClientEnvLogger.new,
Gitlab::GrapeLogging::Loggers::RouteLogger.new,
Gitlab::GrapeLogging::Loggers::UserLogger.new,
@@ -168,42 +169,111 @@ module API
# Mount endpoints to include in the OpenAPI V2 documentation here
namespace do
+ # Keep in alphabetical order
+ mount ::API::AccessRequests
+ mount ::API::Admin::Ci::Variables
+ mount ::API::Admin::InstanceClusters
+ mount ::API::Admin::PlanLimits
+ mount ::API::Appearance
+ mount ::API::Applications
+ mount ::API::Avatar
+ mount ::API::Badges
+ mount ::API::Branches
+ mount ::API::BroadcastMessages
+ mount ::API::BulkImports
+ mount ::API::Ci::Jobs
+ mount ::API::Ci::ResourceGroups
+ mount ::API::Ci::Runner
+ mount ::API::Ci::Runners
+ mount ::API::Ci::Pipelines
+ mount ::API::Ci::PipelineSchedules
+ mount ::API::Ci::Triggers
+ mount ::API::Ci::Variables
+ mount ::API::Clusters::AgentTokens
+ mount ::API::Clusters::Agents
+ mount ::API::Commits
+ mount ::API::CommitStatuses
+ mount ::API::DependencyProxy
+ mount ::API::DeployKeys
+ mount ::API::DeployTokens
+ mount ::API::Deployments
+ mount ::API::Environments
+ mount ::API::ErrorTracking::ClientKeys
+ mount ::API::ErrorTracking::ProjectSettings
+ mount ::API::FeatureFlags
+ mount ::API::FeatureFlagsUserLists
+ mount ::API::Features
+ mount ::API::Files
+ mount ::API::FreezePeriods
+ mount ::API::Geo
+ mount ::API::GoProxy
+ mount ::API::GroupAvatar
+ mount ::API::GroupClusters
+ mount ::API::GroupContainerRepositories
+ mount ::API::GroupExport
+ mount ::API::GroupImport
+ mount ::API::GroupPackages
+ mount ::API::GroupVariables
+ mount ::API::ImportBitbucketServer
+ mount ::API::ImportGithub
+ mount ::API::Integrations
+ mount ::API::Invitations
+ mount ::API::IssueLinks
+ mount ::API::Keys
+ mount ::API::Lint
+ mount ::API::Markdown
+ mount ::API::MergeRequestApprovals
+ mount ::API::MergeRequestDiffs
mount ::API::Metadata
+ mount ::API::Metrics::Dashboard::Annotations
+ mount ::API::Metrics::UserStarredDashboards
+ mount ::API::PackageFiles
+ mount ::API::PersonalAccessTokens::SelfInformation
+ mount ::API::PersonalAccessTokens
+ mount ::API::ProjectClusters
+ mount ::API::ProjectEvents
+ mount ::API::ProjectExport
+ mount ::API::ProjectHooks
+ mount ::API::ProjectImport
+ mount ::API::ProjectRepositoryStorageMoves
+ mount ::API::ProjectSnippets
+ mount ::API::ProjectSnapshots
+ mount ::API::ProjectStatistics
+ mount ::API::ProjectTemplates
+ mount ::API::ProtectedBranches
+ mount ::API::ProtectedTags
+ mount ::API::Releases
+ mount ::API::Release::Links
+ mount ::API::RemoteMirrors
+ mount ::API::Repositories
+ mount ::API::ResourceAccessTokens
+ mount ::API::ResourceMilestoneEvents
+ mount ::API::Snippets
+ mount ::API::SnippetRepositoryStorageMoves
+ mount ::API::Statistics
+ mount ::API::Submodules
+ mount ::API::Suggestions
+ mount ::API::SystemHooks
+ mount ::API::Tags
+ mount ::API::Terraform::Modules::V1::Packages
+ mount ::API::Terraform::State
+ mount ::API::Terraform::StateVersion
+ mount ::API::Topics
+ mount ::API::Unleash
+ mount ::API::UserCounts
+ mount ::API::Wikis
add_open_api_documentation!
end
# Keep in alphabetical order
- mount ::API::AccessRequests
mount ::API::Admin::BatchedBackgroundMigrations
- mount ::API::Admin::Ci::Variables
- mount ::API::Admin::InstanceClusters
- mount ::API::Admin::PlanLimits
mount ::API::Admin::Sidekiq
mount ::API::AlertManagementAlerts
- mount ::API::Appearance
- mount ::API::Applications
- mount ::API::Avatar
mount ::API::AwardEmoji
- mount ::API::Badges
mount ::API::Boards
- mount ::API::Branches
- mount ::API::BroadcastMessages
- mount ::API::BulkImports
mount ::API::Ci::JobArtifacts
- mount ::API::Ci::Jobs
- mount ::API::Ci::PipelineSchedules
- mount ::API::Ci::Pipelines
- mount ::API::Ci::ResourceGroups
- mount ::API::Ci::Runner
- mount ::API::Ci::Runners
mount ::API::Ci::SecureFiles
- mount ::API::Ci::Triggers
- mount ::API::Ci::Variables
- mount ::API::Clusters::Agents
- mount ::API::Clusters::AgentTokens
- mount ::API::CommitStatuses
- mount ::API::Commits
mount ::API::ComposerPackages
mount ::API::ConanInstancePackages
mount ::API::ConanProjectPackages
@@ -211,55 +281,22 @@ module API
mount ::API::ContainerRepositories
mount ::API::DebianGroupPackages
mount ::API::DebianProjectPackages
- mount ::API::DependencyProxy
- mount ::API::DeployKeys
- mount ::API::DeployTokens
- mount ::API::Deployments
mount ::API::Discussions
- mount ::API::Environments
- mount ::API::ErrorTracking::ClientKeys
mount ::API::ErrorTracking::Collector
- mount ::API::ErrorTracking::ProjectSettings
mount ::API::Events
- mount ::API::FeatureFlags
- mount ::API::FeatureFlagsUserLists
- mount ::API::Features
- mount ::API::Files
- mount ::API::FreezePeriods
mount ::API::GenericPackages
- mount ::API::Geo
- mount ::API::GoProxy
- mount ::API::GroupAvatar
mount ::API::GroupBoards
- mount ::API::GroupClusters
- mount ::API::GroupContainerRepositories
mount ::API::GroupDebianDistributions
- mount ::API::GroupExport
- mount ::API::GroupImport
mount ::API::GroupLabels
mount ::API::GroupMilestones
- mount ::API::GroupPackages
- mount ::API::GroupVariables
mount ::API::Groups
mount ::API::HelmPackages
- mount ::API::ImportBitbucketServer
- mount ::API::ImportGithub
- mount ::API::Integrations
mount ::API::Integrations::JiraConnect::Subscriptions
- mount ::API::Invitations
- mount ::API::IssueLinks
mount ::API::Issues
- mount ::API::Keys
mount ::API::Labels
- mount ::API::Lint
- mount ::API::Markdown
mount ::API::MavenPackages
mount ::API::Members
- mount ::API::MergeRequestApprovals
- mount ::API::MergeRequestDiffs
mount ::API::MergeRequests
- mount ::API::Metrics::Dashboard::Annotations
- mount ::API::Metrics::UserStarredDashboards
mount ::API::Namespaces
mount ::API::Notes
mount ::API::NotificationSettings
@@ -267,63 +304,31 @@ module API
mount ::API::NpmProjectPackages
mount ::API::NugetGroupPackages
mount ::API::NugetProjectPackages
- mount ::API::PackageFiles
mount ::API::Pages
mount ::API::PagesDomains
- mount ::API::PersonalAccessTokens::SelfInformation
- mount ::API::PersonalAccessTokens
- mount ::API::ProjectClusters
mount ::API::ProjectContainerRepositories
mount ::API::ProjectDebianDistributions
mount ::API::ProjectEvents
- mount ::API::ProjectExport
- mount ::API::ProjectHooks
- mount ::API::ProjectImport
mount ::API::ProjectMilestones
mount ::API::ProjectPackages
- mount ::API::ProjectRepositoryStorageMoves
- mount ::API::ProjectSnapshots
- mount ::API::ProjectSnippets
- mount ::API::ProjectStatistics
- mount ::API::ProjectTemplates
mount ::API::Projects
- mount ::API::ProtectedBranches
mount ::API::ProtectedTags
mount ::API::PypiPackages
- mount ::API::Release::Links
- mount ::API::Releases
- mount ::API::RemoteMirrors
- mount ::API::Repositories
- mount ::API::ResourceAccessTokens
mount ::API::ResourceLabelEvents
- mount ::API::ResourceMilestoneEvents
mount ::API::ResourceStateEvents
mount ::API::RpmProjectPackages
mount ::API::RubygemPackages
mount ::API::Search
mount ::API::Settings
mount ::API::SidekiqMetrics
- mount ::API::SnippetRepositoryStorageMoves
- mount ::API::Snippets
- mount ::API::Statistics
- mount ::API::Submodules
mount ::API::Subscriptions
- mount ::API::Suggestions
- mount ::API::SystemHooks
mount ::API::Tags
mount ::API::Templates
- mount ::API::Terraform::Modules::V1::Packages
- mount ::API::Terraform::State
- mount ::API::Terraform::StateVersion
mount ::API::Todos
- mount ::API::Topics
- mount ::API::Unleash
mount ::API::UsageData
mount ::API::UsageDataNonSqlMetrics
mount ::API::UsageDataQueries
- mount ::API::UserCounts
mount ::API::Users
- mount ::API::Wikis
mount ::API::Ml::Mlflow
end
diff --git a/lib/api/appearance.rb b/lib/api/appearance.rb
index e599abf4aaf..69f1521ef2a 100644
--- a/lib/api/appearance.rb
+++ b/lib/api/appearance.rb
@@ -22,6 +22,7 @@ module API
desc 'Modify appearance' do
success Entities::Appearance
+ consumes ['multipart/form-data']
end
params do
optional :title, type: String, desc: 'Instance title on the sign in / sign up page'
diff --git a/lib/api/applications.rb b/lib/api/applications.rb
index 4048215160f..6fc9408a570 100644
--- a/lib/api/applications.rb
+++ b/lib/api/applications.rb
@@ -10,17 +10,21 @@ module API
resource :applications do
desc 'Create a new application' do
detail 'This feature was introduced in GitLab 10.5'
- success Entities::ApplicationWithSecret
+ success code: 200, model: Entities::ApplicationWithSecret
end
params do
- requires :name, type: String, desc: 'Application name'
- requires :redirect_uri, type: String, desc: 'Application redirect URI'
- requires :scopes, type: String, desc: 'Application scopes', allow_blank: false
+ requires :name, type: String, desc: 'Name of the application.', documentation: { example: 'MyApplication' }
+ requires :redirect_uri, type: String, desc: 'Redirect URI of the application.', documentation: { example: 'https://redirect.uri' }
+ requires :scopes, type: String,
+ desc: 'Scopes of the application. You can specify multiple scopes by separating\
+ each scope using a space',
+ allow_blank: false
optional :confidential,
type: Boolean,
default: true,
- desc: 'Application will be used where the client secret is confidential'
+ desc: 'The application is used where the client secret can be kept confidential. Native mobile apps \
+ and Single Page Apps are considered non-confidential. Defaults to true if not supplied'
end
post do
application = Doorkeeper::Application.new(declared_params)
@@ -33,14 +37,19 @@ module API
end
desc 'Get applications' do
+ detail 'List all registered applications'
success Entities::Application
+ is_array true
end
get do
applications = ApplicationsFinder.new.execute
present applications, with: Entities::Application
end
- desc 'Delete an application'
+ desc 'Delete an application' do
+ detail 'Delete a specific application'
+ success code: 204
+ end
params do
requires :id, type: Integer, desc: 'The ID of the application (not the application_id)'
end
diff --git a/lib/api/badges.rb b/lib/api/badges.rb
index 0a3f247ffd6..020ba53b9ee 100644
--- a/lib/api/badges.rb
+++ b/lib/api/badges.rb
@@ -28,6 +28,8 @@ module API
desc "Gets a list of #{source_type} badges viewable by the authenticated user." do
detail 'This feature was introduced in GitLab 10.6.'
success Entities::Badge
+ is_array true
+ tags %w[badges]
end
params do
use :pagination
@@ -46,6 +48,7 @@ module API
desc "Preview a badge from a #{source_type}." do
detail 'This feature was introduced in GitLab 10.6.'
success Entities::BasicBadgeDetails
+ tags %w[badges]
end
params do
requires :link_url, type: String, desc: 'URL of the badge link'
@@ -69,6 +72,7 @@ module API
desc "Gets a badge of a #{source_type}." do
detail 'This feature was introduced in GitLab 10.6.'
success Entities::Badge
+ tags %w[badges]
end
params do
requires :badge_id, type: Integer, desc: 'The badge ID'
@@ -86,6 +90,7 @@ module API
desc "Adds a badge to a #{source_type}." do
detail 'This feature was introduced in GitLab 10.6.'
success Entities::Badge
+ tags %w[badges]
end
params do
requires :link_url, type: String, desc: 'URL of the badge link'
@@ -107,6 +112,7 @@ module API
desc "Updates a badge of a #{source_type}." do
detail 'This feature was introduced in GitLab 10.6.'
success Entities::Badge
+ tags %w[badges]
end
params do
optional :link_url, type: String, desc: 'URL of the badge link'
@@ -127,8 +133,9 @@ module API
end
end
- desc 'Removes a badge from a project or group.' do
+ desc "Removes a badge from the #{source_type}." do
detail 'This feature was introduced in GitLab 10.6.'
+ tags %w[badges]
end
params do
requires :badge_id, type: Integer, desc: 'The badge ID'
diff --git a/lib/api/boards.rb b/lib/api/boards.rb
index 6e3005ce676..0e0f6441da7 100644
--- a/lib/api/boards.rb
+++ b/lib/api/boards.rb
@@ -19,7 +19,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
segment ':id/boards' do
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index 7e6b0214c03..845e42c2ed8 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -14,7 +14,7 @@ module API
before do
require_repository_enabled!
- authorize! :download_code, user_project
+ authorize! :read_code, user_project
end
rescue_from Gitlab::Git::Repository::NoRepository do
@@ -29,17 +29,21 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a project repository branches' do
success Entities::Branch
+ success code: 200, model: Entities::Branch
+ failure [{ code: 404, message: '404 Project Not Found' }]
+ tags %w[branches]
+ is_array true
end
params do
use :pagination
use :filter_params
- optional :page_token, type: String, desc: 'Name of branch to start the paginaition from'
+ optional :page_token, type: String, desc: 'Name of branch to start the pagination from'
end
get ':id/repository/branches', urgency: :low do
cache_action([user_project, :branches, current_user, declared_params], expires_in: 30.seconds) do
@@ -65,15 +69,23 @@ module API
end
resource ':id/repository/branches/:branch', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
- desc 'Get a single branch' do
- success Entities::Branch
- end
params do
requires :branch, type: String, desc: 'The name of the branch'
end
+ desc 'Check if a branch exists' do
+ success [{ code: 204, message: 'No Content' }]
+ failure [{ code: 404, message: 'Not Found' }]
+ tags %w[branches]
+ end
head do
user_project.repository.branch_exists?(params[:branch]) ? no_content! : not_found!
end
+ desc 'Get a single repository branch' do
+ success Entities::Branch
+ success code: 200, model: Entities::Branch
+ failure [{ code: 404, message: 'Branch Not Found' }, { code: 404, message: 'Project Not Found' }]
+ tags %w[branches]
+ end
get '/', urgency: :low do
branch = find_branch!(params[:branch])
@@ -87,6 +99,9 @@ module API
# but it works with the changed data model to infer `developers_can_merge` and `developers_can_push`.
desc 'Protect a single branch' do
success Entities::Branch
+ success code: 200, model: Entities::Branch
+ failure [{ code: 404, message: '404 Branch Not Found' }]
+ tags %w[branches]
end
params do
requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
@@ -126,6 +141,9 @@ module API
# Note: This API will be deprecated in favor of the protected branches API.
desc 'Unprotect a single branch' do
success Entities::Branch
+ success code: 200, model: Entities::Branch
+ failure [{ code: 404, message: '404 Project Not Found' }, { code: 404, message: '404 Branch Not Found' }]
+ tags %w[branches]
end
params do
requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
@@ -145,6 +163,9 @@ module API
desc 'Create branch' do
success Entities::Branch
+ success code: 201, model: Entities::Branch
+ failure [{ code: 400, message: 'Failed to create branch' }, { code: 400, message: 'Branch already exists' }]
+ tags %w[branches]
end
params do
requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
@@ -166,7 +187,11 @@ module API
end
end
- desc 'Delete a branch'
+ desc 'Delete a branch' do
+ success code: 204
+ failure [{ code: 404, message: 'Branch Not Found' }]
+ tags %w[branches]
+ end
params do
requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
end
@@ -187,7 +212,11 @@ module API
end
end
- desc 'Delete all merged branches'
+ desc 'Delete all merged branches' do
+ success code: 202, message: '202 Accepted'
+ failure [{ code: 404, message: '404 Project Not Found' }]
+ tags %w[branches]
+ end
delete ':id/repository/merged_branches' do
::Branches::DeleteMergedService.new(user_project, current_user).async_execute
diff --git a/lib/api/bulk_imports.rb b/lib/api/bulk_imports.rb
index c54632919be..a28db321348 100644
--- a/lib/api/bulk_imports.rb
+++ b/lib/api/bulk_imports.rb
@@ -41,7 +41,15 @@ module API
resource :bulk_imports do
desc 'Start a new GitLab Migration' do
detail 'This feature was introduced in GitLab 14.2.'
- success Entities::BulkImport
+ success code: 200, model: Entities::BulkImport
+ consumes ['application/x-www-form-urlencoded']
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
params do
requires :configuration, type: Hash, desc: 'The source GitLab instance configuration' do
@@ -88,7 +96,13 @@ module API
desc 'List all GitLab Migrations' do
detail 'This feature was introduced in GitLab 14.1.'
- success Entities::BulkImport
+ is_array true
+ success code: 200, model: Entities::BulkImport
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
params do
use :pagination
@@ -103,7 +117,13 @@ module API
desc "List all GitLab Migrations' entities" do
detail 'This feature was introduced in GitLab 14.1.'
- success Entities::BulkImports::Entity
+ is_array true
+ success code: 200, model: Entities::BulkImports::Entity
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
params do
use :pagination
@@ -123,7 +143,12 @@ module API
desc 'Get GitLab Migration details' do
detail 'This feature was introduced in GitLab 14.1.'
- success Entities::BulkImport
+ success code: 200, model: Entities::BulkImport
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
params do
requires :import_id, type: Integer, desc: "The ID of user's GitLab Migration"
@@ -134,7 +159,13 @@ module API
desc "List GitLab Migration entities" do
detail 'This feature was introduced in GitLab 14.1.'
- success Entities::BulkImports::Entity
+ is_array true
+ success code: 200, model: Entities::BulkImports::Entity
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
params do
requires :import_id, type: Integer, desc: "The ID of user's GitLab Migration"
@@ -148,7 +179,12 @@ module API
desc 'Get GitLab Migration entity details' do
detail 'This feature was introduced in GitLab 14.1.'
- success Entities::BulkImports::Entity
+ success code: 200, model: Entities::BulkImports::Entity
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
params do
requires :import_id, type: Integer, desc: "The ID of user's GitLab Migration"
diff --git a/lib/api/ci/helpers/runner.rb b/lib/api/ci/helpers/runner.rb
index 269f2fa7ddc..be4d82bc500 100644
--- a/lib/api/ci/helpers/runner.rb
+++ b/lib/api/ci/helpers/runner.rb
@@ -53,7 +53,7 @@ module API
# HTTP status codes to terminate the job on GitLab Runner:
# - 403
- def authenticate_job!(require_running: true, heartbeat_runner: false)
+ def authenticate_job!(heartbeat_runner: false)
job = current_job
# 404 is not returned here because we want to terminate the job if it's
@@ -66,10 +66,7 @@ module API
forbidden!('Project has been deleted!') if job.project.nil? || job.project.pending_delete?
forbidden!('Job has been erased!') if job.erased?
-
- if require_running
- job_forbidden!(job, 'Job is not running') unless job.running?
- end
+ job_forbidden!(job, 'Job is not running') unless job.running?
# Only some requests (like updating the job or patching the trace) should trigger
# runner heartbeat. Operations like artifacts uploading are executed in context of
@@ -87,9 +84,9 @@ module API
end
def authenticate_job_via_dependent_job!
- forbidden! unless current_authenticated_job
+ authenticate!
forbidden! unless current_job
- forbidden! unless can?(current_authenticated_job.user, :read_build, current_job)
+ forbidden! unless can?(current_user, :read_build, current_job)
end
def current_job
@@ -106,21 +103,6 @@ module API
end
end
- # TODO: Replace this with `#current_authenticated_job from API::Helpers`
- # after the feature flag `ci_authenticate_running_job_token_for_artifacts`
- # is removed.
- #
- # For the time being, this needs to be overridden because the API
- # GET api/v4/jobs/:id/artifacts
- # needs to allow requests using token whose job is not running.
- #
- # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83713#note_942368526
- def current_authenticated_job
- strong_memoize(:current_authenticated_job) do
- ::Ci::AuthJobFinder.new(token: job_token).execute
- end
- end
-
# The token used by runner to authenticate a request.
# In most cases, the runner uses the token belonging to the requested job.
# However, when requesting for job artifacts, the runner would use
@@ -151,10 +133,6 @@ module API
{ config: attributes_for_keys(%w(gpus), params.dig('info', 'config')) }
end
- def request_using_running_job_token?
- current_job.present? && current_authenticated_job.present? && current_job != current_authenticated_job
- end
-
def metrics
strong_memoize(:metrics) { ::Gitlab::Ci::Runner::Metrics.new }
end
diff --git a/lib/api/ci/job_artifacts.rb b/lib/api/ci/job_artifacts.rb
index 37c7cc73c46..352ad04c982 100644
--- a/lib/api/ci/job_artifacts.rb
+++ b/lib/api/ci/job_artifacts.rb
@@ -19,7 +19,7 @@ module API
prepend_mod_with('API::Ci::JobArtifacts') # rubocop: disable Cop/InjectEnterpriseEditionModule
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Download the artifacts archive from a job' do
@@ -38,7 +38,7 @@ module API
latest_build = user_project.latest_successful_build_for_ref!(params[:job], params[:ref_name])
authorize_read_job_artifacts!(latest_build)
- present_artifacts_file!(latest_build.artifacts_file, project: latest_build.project)
+ present_artifacts_file!(latest_build.artifacts_file)
end
desc 'Download a specific file from artifacts archive from a ref' do
@@ -80,7 +80,7 @@ module API
build = find_build!(params[:job_id])
authorize_read_job_artifacts!(build)
- present_artifacts_file!(build.artifacts_file, project: build.project)
+ present_artifacts_file!(build.artifacts_file)
end
desc 'Download a specific file from artifacts archive' do
diff --git a/lib/api/ci/jobs.rb b/lib/api/ci/jobs.rb
index 6049993bf6f..9e41e1c0d8f 100644
--- a/lib/api/ci/jobs.rb
+++ b/lib/api/ci/jobs.rb
@@ -11,12 +11,12 @@ module API
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
helpers do
params :optional_scope do
- optional :scope, types: [String, Array[String]], desc: 'The scope of builds to show',
+ optional :scope, type: Array[String], desc: 'The scope of builds to show',
values: ::CommitStatus::AVAILABLE_STATUSES,
coerce_with: ->(scope) {
case scope
@@ -29,12 +29,19 @@ module API
else
['unknown']
end
- }
+ },
+ documentation: { example: %w[pending running] }
end
end
desc 'Get a projects jobs' do
- success Entities::Ci::Job
+ success code: 200, model: Entities::Ci::Job
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
use :optional_scope
@@ -53,10 +60,15 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
desc 'Get a specific job of a project' do
- success Entities::Ci::Job
+ success code: 200, model: Entities::Ci::Job
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :job_id, type: Integer, desc: 'The ID of a job'
+ requires :job_id, type: Integer, desc: 'The ID of a job', documentation: { example: 88 }
end
get ':id/jobs/:job_id', urgency: :low, feature_category: :continuous_integration do
authorize_read_builds!
@@ -69,9 +81,16 @@ module API
# TODO: We should use `present_disk_file!` and leave this implementation for backward compatibility (when build trace
# is saved in the DB instead of file). But before that, we need to consider how to replace the value of
# `runners_token` with some mask (like `xxxxxx`) when sending trace file directly by workhorse.
- desc 'Get a trace of a specific job of a project'
+ desc 'Get a trace of a specific job of a project' do
+ success code: 200, model: Entities::Ci::Job
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ end
params do
- requires :job_id, type: Integer, desc: 'The ID of a job'
+ requires :job_id, type: Integer, desc: 'The ID of a job', documentation: { example: 88 }
end
get ':id/jobs/:job_id/trace', urgency: :low, feature_category: :continuous_integration do
authorize_read_builds!
@@ -90,10 +109,15 @@ module API
end
desc 'Cancel a specific job of a project' do
- success Entities::Ci::Job
+ success code: 201, model: Entities::Ci::Job
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :job_id, type: Integer, desc: 'The ID of a job'
+ requires :job_id, type: Integer, desc: 'The ID of a job', documentation: { example: 88 }
end
post ':id/jobs/:job_id/cancel', urgency: :low, feature_category: :continuous_integration do
authorize_update_builds!
@@ -107,10 +131,15 @@ module API
end
desc 'Retry a specific build of a project' do
- success Entities::Ci::Job
+ success code: 201, model: Entities::Ci::Job
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :job_id, type: Integer, desc: 'The ID of a build'
+ requires :job_id, type: Integer, desc: 'The ID of a build', documentation: { example: 88 }
end
post ':id/jobs/:job_id/retry', urgency: :low, feature_category: :continuous_integration do
authorize_update_builds!
@@ -128,10 +157,16 @@ module API
end
desc 'Erase job (remove artifacts and the trace)' do
- success Entities::Ci::Job
+ success code: 201, model: Entities::Ci::Job
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Conflict' }
+ ]
end
params do
- requires :job_id, type: Integer, desc: 'The ID of a build'
+ requires :job_id, type: Integer, desc: 'The ID of a build', documentation: { example: 88 }
end
post ':id/jobs/:job_id/erase', urgency: :low, feature_category: :continuous_integration do
authorize_update_builds!
@@ -148,15 +183,21 @@ module API
end
desc 'Trigger an actionable job (manual, delayed, etc)' do
- success Entities::Ci::JobBasic
detail 'This feature was added in GitLab 8.11'
+ success code: 200, model: Entities::Ci::JobBasic
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :job_id, type: Integer, desc: 'The ID of a Job'
+ requires :job_id, type: Integer, desc: 'The ID of a Job', documentation: { example: 88 }
optional :job_variables_attributes,
type: Array, desc: 'User defined variables that will be included when running the job' do
- requires :key, type: String, desc: 'The name of the variable'
- requires :value, type: String, desc: 'The value of the variable'
+ requires :key, type: String, desc: 'The name of the variable', documentation: { example: 'foo' }
+ requires :value, type: String, desc: 'The value of the variable', documentation: { example: 'bar' }
end
end
@@ -183,7 +224,12 @@ module API
resource :job do
desc 'Get current job using job token' do
- success Entities::Ci::Job
+ success code: 200, model: Entities::Ci::Job
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
end
route_setting :authentication, job_token_allowed: true
get '', feature_category: :continuous_integration, urgency: :low do
@@ -194,6 +240,12 @@ module API
desc 'Get current agents' do
detail 'Retrieves a list of agents for the given job token'
+ success code: 200, model: Entities::Ci::Job
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
end
route_setting :authentication, job_token_allowed: true
get '/allowed_agents', urgency: :low, feature_category: :kubernetes_management do
@@ -210,7 +262,7 @@ module API
.select { |_role, role_access_level| role_access_level <= user_access_level }
.map(&:first)
- environment = if persisted_environment = current_authenticated_job.persisted_environment
+ environment = if persisted_environment = current_authenticated_job.actual_persisted_environment
{ tier: persisted_environment.tier, slug: persisted_environment.slug }
end
@@ -244,6 +296,8 @@ module API
# current_authenticated_job will be nil if user is using
# a valid authentication (like PRIVATE-TOKEN) that is not CI_JOB_TOKEN
not_found!('Job') unless current_authenticated_job
+
+ ::Gitlab::ApplicationContext.push(job: current_authenticated_job)
end
end
end
diff --git a/lib/api/ci/pipeline_schedules.rb b/lib/api/ci/pipeline_schedules.rb
index 886c3509c51..afb3754f2ae 100644
--- a/lib/api/ci/pipeline_schedules.rb
+++ b/lib/api/ci/pipeline_schedules.rb
@@ -11,16 +11,24 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project',
+ documentation: { example: 18 }
end
resource :projects, requirements: ::API::API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get all pipeline schedules' do
- success Entities::Ci::PipelineSchedule
+ success code: 200, model: Entities::Ci::PipelineSchedule
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
use :pagination
optional :scope, type: String, values: %w[active inactive],
- desc: 'The scope of pipeline schedules'
+ desc: 'The scope of pipeline schedules',
+ documentation: { example: 'active' }
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/pipeline_schedules' do
@@ -33,34 +41,51 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
desc 'Get a single pipeline schedule' do
- success Entities::Ci::PipelineScheduleDetails
+ success code: 200, model: Entities::Ci::PipelineScheduleDetails
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
end
get ':id/pipeline_schedules/:pipeline_schedule_id' do
present pipeline_schedule, with: Entities::Ci::PipelineScheduleDetails, user: current_user
end
desc 'Get all pipelines triggered from a pipeline schedule' do
- success Entities::Ci::PipelineBasic
+ success code: 200, model: Entities::Ci::PipelineBasic
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule ID'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule ID', documentation: { example: 13 }
end
get ':id/pipeline_schedules/:pipeline_schedule_id/pipelines' do
present paginate(pipeline_schedule.pipelines), with: Entities::Ci::PipelineBasic
end
desc 'Create a new pipeline schedule' do
- success Entities::Ci::PipelineScheduleDetails
+ success code: 201, model: Entities::Ci::PipelineScheduleDetails
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :description, type: String, desc: 'The description of pipeline schedule'
- requires :ref, type: String, desc: 'The branch/tag name will be triggered', allow_blank: false
- requires :cron, type: String, desc: 'The cron'
- optional :cron_timezone, type: String, default: 'UTC', desc: 'The timezone'
- optional :active, type: Boolean, default: true, desc: 'The activation of pipeline schedule'
+ requires :description, type: String, desc: 'The description of pipeline schedule', documentation: { example: 'Test schedule pipeline' }
+ requires :ref, type: String, desc: 'The branch/tag name will be triggered', allow_blank: false, documentation: { example: 'develop' }
+ requires :cron, type: String, desc: 'The cron', documentation: { example: '* * * * *' }
+ optional :cron_timezone, type: String, default: 'UTC', desc: 'The timezone', documentation: { example: 'Asia/Tokyo' }
+ optional :active, type: Boolean, default: true, desc: 'The activation of pipeline schedule', documentation: { example: true }
end
post ':id/pipeline_schedules' do
authorize! :create_pipeline_schedule, user_project
@@ -77,15 +102,21 @@ module API
end
desc 'Edit a pipeline schedule' do
- success Entities::Ci::PipelineScheduleDetails
+ success code: 200, model: Entities::Ci::PipelineScheduleDetails
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
- optional :description, type: String, desc: 'The description of pipeline schedule'
- optional :ref, type: String, desc: 'The branch/tag name will be triggered'
- optional :cron, type: String, desc: 'The cron'
- optional :cron_timezone, type: String, desc: 'The timezone'
- optional :active, type: Boolean, desc: 'The activation of pipeline schedule'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
+ optional :description, type: String, desc: 'The description of pipeline schedule', documentation: { example: 'Test schedule pipeline' }
+ optional :ref, type: String, desc: 'The branch/tag name will be triggered', documentation: { example: 'develop' }
+ optional :cron, type: String, desc: 'The cron', documentation: { example: '* * * * *' }
+ optional :cron_timezone, type: String, desc: 'The timezone', documentation: { example: 'Asia/Tokyo' }
+ optional :active, type: Boolean, desc: 'The activation of pipeline schedule', documentation: { example: true }
end
put ':id/pipeline_schedules/:pipeline_schedule_id' do
authorize! :update_pipeline_schedule, pipeline_schedule
@@ -98,10 +129,16 @@ module API
end
desc 'Take ownership of a pipeline schedule' do
- success Entities::Ci::PipelineScheduleDetails
+ success code: 201, model: Entities::Ci::PipelineScheduleDetails
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
+ 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
@@ -114,10 +151,16 @@ module API
end
desc 'Delete a pipeline schedule' do
- success Entities::Ci::PipelineScheduleDetails
+ success code: 204
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 412, message: 'Precondition Failed' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
end
delete ':id/pipeline_schedules/:pipeline_schedule_id' do
authorize! :admin_pipeline_schedule, pipeline_schedule
@@ -127,9 +170,15 @@ module API
desc 'Play a scheduled pipeline immediately' do
detail 'This feature was added in GitLab 12.8'
+ success code: 201
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
end
post ':id/pipeline_schedules/:pipeline_schedule_id/play' do
authorize! :play_pipeline_schedule, pipeline_schedule
@@ -145,13 +194,20 @@ module API
end
desc 'Create a new pipeline schedule variable' do
- success Entities::Ci::Variable
+ success code: 201, model: Entities::Ci::Variable
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
- requires :key, type: String, desc: 'The key of the variable'
- requires :value, type: String, desc: 'The value of the variable'
- optional :variable_type, type: String, values: ::Ci::PipelineScheduleVariable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file. Defaults to env_var'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
+ requires :key, type: String, desc: 'The key of the variable', documentation: { example: 'NEW_VARIABLE' }
+ requires :value, type: String, desc: 'The value of the variable', documentation: { example: 'new value' }
+ optional :variable_type, type: String, values: ::Ci::PipelineScheduleVariable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file. Defaults to env_var',
+ documentation: { default: 'env_var' }
end
post ':id/pipeline_schedules/:pipeline_schedule_id/variables' do
authorize! :update_pipeline_schedule, pipeline_schedule
@@ -166,13 +222,20 @@ module API
end
desc 'Edit a pipeline schedule variable' do
- success Entities::Ci::Variable
+ success code: 200, model: Entities::Ci::Variable
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
- requires :key, type: String, desc: 'The key of the variable'
- optional :value, type: String, desc: 'The value of the variable'
- optional :variable_type, type: String, values: ::Ci::PipelineScheduleVariable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
+ requires :key, type: String, desc: 'The key of the variable', documentation: { example: 'NEW_VARIABLE' }
+ optional :value, type: String, desc: 'The value of the variable', documentation: { example: 'new value' }
+ optional :variable_type, type: String, values: ::Ci::PipelineScheduleVariable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file',
+ documentation: { default: 'env_var' }
end
put ':id/pipeline_schedules/:pipeline_schedule_id/variables/:key' do
authorize! :update_pipeline_schedule, pipeline_schedule
@@ -185,11 +248,16 @@ module API
end
desc 'Delete a pipeline schedule variable' do
- success Entities::Ci::Variable
+ success code: 202, model: Entities::Ci::Variable
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id'
- requires :key, type: String, desc: 'The key of the variable'
+ requires :pipeline_schedule_id, type: Integer, desc: 'The pipeline schedule id', documentation: { example: 13 }
+ requires :key, type: String, desc: 'The key of the variable', documentation: { example: 'NEW_VARIABLE' }
end
delete ':id/pipeline_schedules/:pipeline_schedule_id/variables/:key' do
authorize! :admin_pipeline_schedule, pipeline_schedule
diff --git a/lib/api/ci/pipelines.rb b/lib/api/ci/pipelines.rb
index 72a81330e71..c055512e54e 100644
--- a/lib/api/ci/pipelines.rb
+++ b/lib/api/ci/pipelines.rb
@@ -10,12 +10,17 @@ module API
before { authenticate_non_get! }
params do
- requires :id, type: String, desc: 'The project ID'
+ requires :id, type: String, desc: 'The project ID or URL-encoded path', documentation: { example: 11 }
end
resource :projects, requirements: ::API::API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get all Pipelines of the project' do
detail 'This feature was introduced in GitLab 8.11.'
- success Entities::Ci::PipelineBasic
+ success status: 200, model: Entities::Ci::PipelineBasic
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' }
+ ]
+ is_array true
end
helpers do
@@ -31,27 +36,39 @@ module API
else
['unknown']
end
- }
+ },
+ documentation: { example: %w[pending running] }
end
end
params do
use :pagination
optional :scope, type: String, values: %w[running pending finished branches tags],
- desc: 'The scope of pipelines'
+ desc: 'The scope of pipelines',
+ documentation: { example: 'pending' }
optional :status, type: String, values: ::Ci::HasStatus::AVAILABLE_STATUSES,
- desc: 'The status of pipelines'
- optional :ref, type: String, desc: 'The ref of pipelines'
- optional :sha, type: String, desc: 'The sha of pipelines'
- optional :yaml_errors, type: Boolean, desc: 'Returns pipelines with invalid configurations'
- optional :username, type: String, desc: 'The username of the user who triggered pipelines'
- optional :updated_before, type: DateTime, desc: 'Return pipelines updated before the specified datetime. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ'
- optional :updated_after, type: DateTime, desc: 'Return pipelines updated after the specified datetime. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ'
+ desc: 'The status of pipelines',
+ documentation: { example: 'pending' }
+ optional :ref, type: String, desc: 'The ref of pipelines',
+ documentation: { example: 'develop' }
+ optional :sha, type: String, desc: 'The sha of pipelines',
+ documentation: { example: 'a91957a858320c0e17f3a0eca7cfacbff50ea29a' }
+ optional :yaml_errors, type: Boolean, desc: 'Returns pipelines with invalid configurations',
+ documentation: { example: false }
+ optional :username, type: String, desc: 'The username of the user who triggered pipelines',
+ documentation: { example: 'root' }
+ optional :updated_before, type: DateTime, desc: 'Return pipelines updated before the specified datetime. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ',
+ documentation: { example: '2015-12-24T15:51:21.880Z' }
+ optional :updated_after, type: DateTime, desc: 'Return pipelines updated after the specified datetime. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ',
+ documentation: { example: '2015-12-24T15:51:21.880Z' }
optional :order_by, type: String, values: ::Ci::PipelinesFinder::ALLOWED_INDEXED_COLUMNS, default: 'id',
- desc: 'Order pipelines'
+ desc: 'Order pipelines',
+ documentation: { example: 'status' }
optional :sort, type: String, values: %w[asc desc], default: 'desc',
- desc: 'Sort pipelines'
- optional :source, type: String, values: ::Ci::Pipeline.sources.keys
+ desc: 'Sort pipelines',
+ documentation: { example: 'asc' }
+ optional :source, type: String, values: ::Ci::Pipeline.sources.keys,
+ documentation: { example: 'push' }
end
get ':id/pipelines', urgency: :low, feature_category: :continuous_integration do
authorize! :read_pipeline, user_project
@@ -63,11 +80,22 @@ module API
desc 'Create a new pipeline' do
detail 'This feature was introduced in GitLab 8.14'
- success Entities::Ci::Pipeline
+ success status: 201, model: Entities::Ci::Pipeline
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :ref, type: String, desc: 'Reference'
- optional :variables, Array, desc: 'Array of variables available in the pipeline'
+ requires :ref, type: String, desc: 'Reference',
+ documentation: { example: 'develop' }
+ optional :variables, type: Array, desc: 'Array of variables available in the pipeline' do
+ optional :key, type: String, desc: 'The key of the variable', documentation: { example: 'UPLOAD_TO_S3' }
+ optional :value, type: String, desc: 'The value of the variable', documentation: { example: 'true' }
+ optional :variable_type, type: String, values: ::Ci::PipelineVariable.variable_types.keys, default: 'env_var', desc: 'The type of variable, must be one of env_var or file. Defaults to env_var'
+ end
end
post ':id/pipeline', urgency: :low, feature_category: :continuous_integration do
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/20711')
@@ -89,12 +117,18 @@ module API
end
end
- desc 'Gets a the latest pipeline for the project branch' do
+ desc 'Gets the latest pipeline for the project branch' do
detail 'This feature was introduced in GitLab 12.3'
- success Entities::Ci::Pipeline
+ success status: 200, model: Entities::Ci::Pipeline
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- optional :ref, type: String, desc: 'branch ref of pipeline'
+ optional :ref, type: String, desc: 'Branch ref of pipeline. Uses project default branch if not specified.',
+ documentation: { example: 'develop' }
end
get ':id/pipelines/latest', urgency: :low, feature_category: :continuous_integration do
authorize! :read_pipeline, latest_pipeline
@@ -104,10 +138,15 @@ module API
desc 'Gets a specific pipeline for the project' do
detail 'This feature was introduced in GitLab 8.11'
- success Entities::Ci::Pipeline
+ success status: 200, model: Entities::Ci::Pipeline
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
end
get ':id/pipelines/:pipeline_id', urgency: :low, feature_category: :continuous_integration do
authorize! :read_pipeline, pipeline
@@ -116,10 +155,16 @@ module API
end
desc 'Get pipeline jobs' do
- success Entities::Ci::Job
+ success status: 200, model: Entities::Ci::Job
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
optional :include_retried, type: Boolean, default: false, desc: 'Includes retried jobs'
use :optional_scope
use :pagination
@@ -140,10 +185,16 @@ module API
end
desc 'Get pipeline bridge jobs' do
- success Entities::Ci::Bridge
+ success status: 200, model: Entities::Ci::Bridge
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
use :optional_scope
use :pagination
end
@@ -163,10 +214,16 @@ module API
desc 'Gets the variables for a given pipeline' do
detail 'This feature was introduced in GitLab 11.11'
- success Entities::Ci::Variable
+ success status: 200, model: Entities::Ci::Variable
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ 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
authorize! :read_pipeline_variable, pipeline
@@ -176,10 +233,15 @@ module API
desc 'Gets the test report for a given pipeline' do
detail 'This feature was introduced in GitLab 13.0.'
- success TestReportEntity
+ success status: 200, model: TestReportEntity
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
end
get ':id/pipelines/:pipeline_id/test_report', feature_category: :code_testing, urgency: :low do
authorize! :read_build, pipeline
@@ -189,10 +251,15 @@ module API
desc 'Gets the test report summary for a given pipeline' do
detail 'This feature was introduced in GitLab 14.2'
- success TestReportSummaryEntity
+ success status: 200, model: TestReportSummaryEntity
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
end
get ':id/pipelines/:pipeline_id/test_report_summary', feature_category: :code_testing do
authorize! :read_build, pipeline
@@ -205,7 +272,7 @@ module API
http_codes [[204, 'Pipeline was deleted'], [403, 'Forbidden']]
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
end
delete ':id/pipelines/:pipeline_id', urgency: :low, feature_category: :continuous_integration do
authorize! :destroy_pipeline, pipeline
@@ -219,10 +286,15 @@ module API
desc 'Retry builds in the pipeline' do
detail 'This feature was introduced in GitLab 8.11.'
- success Entities::Ci::Pipeline
+ success status: 201, model: Entities::Ci::Pipeline
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
end
post ':id/pipelines/:pipeline_id/retry', urgency: :low, feature_category: :continuous_integration do
authorize! :update_pipeline, pipeline
@@ -238,10 +310,15 @@ module API
desc 'Cancel all builds in the pipeline' do
detail 'This feature was introduced in GitLab 8.11.'
- success Entities::Ci::Pipeline
+ success status: 200, model: Entities::Ci::Pipeline
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :pipeline_id, type: Integer, desc: 'The pipeline ID'
+ requires :pipeline_id, type: Integer, desc: 'The pipeline ID', documentation: { example: 18 }
end
post ':id/pipelines/:pipeline_id/cancel', urgency: :low, feature_category: :continuous_integration do
authorize! :update_pipeline, pipeline
diff --git a/lib/api/ci/resource_groups.rb b/lib/api/ci/resource_groups.rb
index ea6d3cc8fd4..79a9fe58a7d 100644
--- a/lib/api/ci/resource_groups.rb
+++ b/lib/api/ci/resource_groups.rb
@@ -5,17 +5,30 @@ module API
class ResourceGroups < ::API::Base
include PaginationParams
+ ci_resource_groups_tags = %w[ci_resource_groups]
+
+ RESOURCE_GROUP_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
+ .merge(key: API::NO_SLASH_URL_PART_REGEX)
+
before { authenticate! }
feature_category :continuous_delivery
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id,
+ types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: ::API::API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get all resource groups for this project' do
+ desc 'Get all resource groups for a project' do
success Entities::Ci::ResourceGroup
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags ci_resource_groups_tags
end
params do
use :pagination
@@ -26,27 +39,38 @@ module API
present paginate(user_project.resource_groups), with: Entities::Ci::ResourceGroup
end
- desc 'Get a single resource group' do
+ desc 'Get a specific resource group' do
success Entities::Ci::ResourceGroup
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags ci_resource_groups_tags
end
params do
requires :key, type: String, desc: 'The key of the resource group'
end
- get ':id/resource_groups/:key' do
+ get ':id/resource_groups/:key', requirements: RESOURCE_GROUP_ENDPOINT_REQUIREMENTS do
authorize! :read_resource_group, resource_group
present resource_group, with: Entities::Ci::ResourceGroup
end
- desc 'List upcoming jobs of a resource group' do
+ desc 'List upcoming jobs for a specific resource group' do
success Entities::Ci::JobBasic
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags ci_resource_groups_tags
end
params do
requires :key, type: String, desc: 'The key of the resource group'
use :pagination
end
- get ':id/resource_groups/:key/upcoming_jobs' do
+ get ':id/resource_groups/:key/upcoming_jobs', requirements: RESOURCE_GROUP_ENDPOINT_REQUIREMENTS do
authorize! :read_resource_group, resource_group
authorize! :read_build, user_project
@@ -57,15 +81,25 @@ module API
present paginate(upcoming_processables), with: Entities::Ci::JobBasic
end
- desc 'Edit a resource group' do
+ desc 'Edit an existing resource group' do
+ detail "Updates an existing resource group's properties."
success Entities::Ci::ResourceGroup
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags ci_resource_groups_tags
end
params do
requires :key, type: String, desc: 'The key of the resource group'
- optional :process_mode, type: String, desc: 'The process mode',
- values: ::Ci::ResourceGroup.process_modes.keys
+
+ optional :process_mode,
+ type: String,
+ desc: 'The process mode of the resource group',
+ values: ::Ci::ResourceGroup.process_modes.keys
end
- put ':id/resource_groups/:key' do
+ put ':id/resource_groups/:key', requirements: RESOURCE_GROUP_ENDPOINT_REQUIREMENTS do
authorize! :update_resource_group, resource_group
if resource_group.update(declared_params(include_missing: false))
diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb
index 2d2dcc544f9..c7d1887638a 100644
--- a/lib/api/ci/runner.rb
+++ b/lib/api/ci/runner.rb
@@ -8,25 +8,38 @@ module API
content_type :txt, 'text/plain'
resource :runners do
- desc 'Registers a new Runner' do
+ desc 'Register a new runner' do
+ detail "Register a new runner for the instance"
success Entities::Ci::RunnerRegistrationDetails
- http_codes [[201, 'Runner was created'], [403, 'Forbidden']]
+ failure [[400, 'Bad Request'], [403, 'Forbidden']]
end
params do
requires :token, type: String, desc: 'Registration token'
optional :description, type: String, desc: %q(Runner's description)
- optional :maintainer_note, type: String, desc: %q(Deprecated: Use :maintenance_note instead. Runner's maintenance notes)
- optional :maintenance_note, type: String, desc: %q(Runner's maintenance notes)
- optional :info, type: Hash, desc: %q(Runner's metadata)
- optional :active, type: Boolean, desc: 'Deprecated: Use `:paused` instead. Should runner be active'
- optional :paused, type: Boolean, desc: 'Whether the runner should ignore new jobs'
- optional :locked, type: Boolean, desc: 'Whether the runner should be locked for current project'
+ optional :maintainer_note, type: String, desc: %q(Deprecated: see `maintenance_note`)
+ optional :maintenance_note, type: String,
+ desc: %q(Free-form maintenance notes for the runner (1024 characters))
+ optional :info, type: Hash, desc: %q(Runner's metadata) do
+ optional :name, type: String, desc: %q(Runner's name)
+ optional :version, type: String, desc: %q(Runner's version)
+ optional :revision, type: String, desc: %q(Runner's revision)
+ optional :platform, type: String, desc: %q(Runner's platform)
+ optional :architecture, type: String, desc: %q(Runner's architecture)
+ end
+ optional :active, type: Boolean,
+ desc: 'Deprecated: Use `paused` instead. Specifies whether the runner is allowed ' \
+ 'to receive new jobs'
+ optional :paused, type: Boolean, desc: 'Specifies whether the runner should ignore new jobs'
+ optional :locked, type: Boolean, desc: 'Specifies whether the runner should be locked for the current project'
optional :access_level, type: String, values: ::Ci::Runner.access_levels.keys,
- desc: 'The access_level of the runner; `not_protected` or `ref_protected`'
- optional :run_untagged, type: Boolean, desc: 'Whether the runner should handle untagged jobs'
- optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: %q(List of Runner's tags)
- optional :maximum_timeout, type: Integer, desc: 'Maximum timeout set when this runner handles the job'
- mutually_exclusive :maintainer_note, :maintainer_note
+ desc: 'The access level of the runner'
+ optional :run_untagged, type: Boolean, desc: 'Specifies whether the runner should handle untagged jobs'
+ optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ desc: %q(A list of runner tags)
+ optional :maximum_timeout, type: Integer,
+ desc: 'Maximum timeout that limits the amount of time (in seconds) ' \
+ 'that runners can run jobs'
+ mutually_exclusive :maintainer_note, :maintenance_note
mutually_exclusive :active, :paused
end
post '/', urgency: :low, feature_category: :runner do
@@ -49,11 +62,12 @@ module API
end
end
- desc 'Deletes a registered Runner' do
- http_codes [[204, 'Runner was deleted'], [403, 'Forbidden']]
+ desc 'Delete a registered runner' do
+ summary "Delete a runner by authentication token"
+ failure [[403, 'Forbidden']]
end
params do
- requires :token, type: String, desc: %q(Runner's authentication token)
+ requires :token, type: String, desc: %q(The runner's authentication token)
end
delete '/', urgency: :low, feature_category: :runner do
authenticate_runner!
@@ -61,11 +75,12 @@ module API
destroy_conditionally!(current_runner) { ::Ci::Runners::UnregisterRunnerService.new(current_runner, params[:token]).execute }
end
- desc 'Validates authentication credentials' do
+ desc 'Validate authentication credentials' do
+ summary "Verify authentication for a registered runner"
http_codes [[200, 'Credentials are valid'], [403, 'Forbidden']]
end
params do
- requires :token, type: String, desc: %q(Runner's authentication token)
+ requires :token, type: String, desc: %q(The runner's authentication token)
end
post '/verify', urgency: :low, feature_category: :runner do
authenticate_runner!
@@ -75,6 +90,7 @@ module API
desc 'Reset runner authentication token with current token' do
success Entities::Ci::ResetTokenResult
+ failure [[403, 'Forbidden']]
end
params do
requires :token, type: String, desc: 'The current authentication token of the runner'
@@ -94,7 +110,8 @@ module API
success Entities::Ci::JobRequest::Response
http_codes [[201, 'Job was scheduled'],
[204, 'No job for Runner'],
- [403, 'Forbidden']]
+ [403, 'Forbidden'],
+ [409, 'Conflict']]
end
params do
requires :token, type: String, desc: %q(Runner's authentication token)
@@ -168,14 +185,14 @@ module API
end
end
- desc 'Updates a job' do
+ desc 'Update a job' do
http_codes [[200, 'Job was updated'],
[202, 'Update accepted'],
[400, 'Unknown parameters'],
[403, 'Forbidden']]
end
params do
- requires :token, type: String, desc: %q(Runners's authentication token)
+ requires :token, type: String, desc: %q(Runner's authentication token)
requires :id, type: Integer, desc: %q(Job's ID)
optional :state, type: String, desc: %q(Job's status: success, failed)
optional :checksum, type: String, desc: %q(Job's trace CRC32 checksum)
@@ -203,7 +220,7 @@ module API
end
end
- desc 'Appends a patch to the job trace' do
+ desc 'Append a patch to the job trace' do
http_codes [[202, 'Trace was patched'],
[400, 'Missing Content-Range header'],
[403, 'Forbidden'],
@@ -285,14 +302,14 @@ module API
end
params do
requires :id, type: Integer, desc: %q(Job's ID)
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: %(The artifact file to store (generated by Multipart middleware))
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: %(The artifact file to store (generated by Multipart middleware)), documentation: { type: 'file' }
optional :token, type: String, desc: %q(Job's authentication token)
optional :expire_in, type: String, desc: %q(Specify when artifacts should expire)
optional :artifact_type, type: String, desc: %q(The type of artifact),
default: 'archive', values: ::Ci::JobArtifact.file_types.keys
optional :artifact_format, type: String, desc: %q(The format of artifact),
default: 'zip', values: ::Ci::JobArtifact.file_formats.keys
- optional :metadata, type: ::API::Validations::Types::WorkhorseFile, desc: %(The artifact metadata to store (generated by Multipart middleware))
+ optional :metadata, type: ::API::Validations::Types::WorkhorseFile, desc: %(The artifact metadata to store (generated by Multipart middleware)), documentation: { type: 'file' }
end
post '/:id/artifacts', feature_category: :build_artifacts, urgency: :low do
not_allowed! unless Gitlab.config.artifacts.enabled
@@ -317,6 +334,7 @@ module API
desc 'Download the artifacts file for job' do
http_codes [[200, 'Upload allowed'],
+ [401, 'Unauthorized'],
[403, 'Forbidden'],
[404, 'Artifact not found']]
end
@@ -325,14 +343,11 @@ module API
optional :token, type: String, desc: %q(Job's authentication token)
optional :direct_download, default: false, type: Boolean, desc: %q(Perform direct download from remote storage instead of proxying artifacts)
end
+ route_setting :authentication, job_token_allowed: true
get '/:id/artifacts', feature_category: :build_artifacts do
- if request_using_running_job_token?
- authenticate_job_via_dependent_job!
- else
- authenticate_job!(require_running: false)
- end
+ authenticate_job_via_dependent_job!
- present_artifacts_file!(current_job.artifacts_file, project: current_job.project, supports_direct_download: params[:direct_download])
+ present_artifacts_file!(current_job.artifacts_file, supports_direct_download: params[:direct_download])
end
end
end
diff --git a/lib/api/ci/runners.rb b/lib/api/ci/runners.rb
index 4b578f8b7e5..988c3f4f566 100644
--- a/lib/api/ci/runners.rb
+++ b/lib/api/ci/runners.rb
@@ -10,20 +10,98 @@ module API
feature_category :runner
urgency :low
+ helpers do
+ params :deprecated_filter_params do
+ optional :scope, type: String, values: ::Ci::Runner::AVAILABLE_SCOPES,
+ desc: 'Deprecated: Use `type` or `status` instead. The scope of specific runners to return'
+ end
+
+ params :filter_params do
+ optional :type, type: String, values: ::Ci::Runner::AVAILABLE_TYPES, desc: 'The type of runners to return'
+ optional :paused, type: Boolean,
+ desc: 'Whether to include only runners that are accepting or ignoring new jobs'
+ optional :status, type: String, values: ::Ci::Runner::AVAILABLE_STATUSES,
+ desc: 'The status of runners to return'
+ optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ desc: 'A list of runner tags', documentation: { example: "['macos', 'shell']" }
+ use :pagination
+ end
+
+ def filter_runners(runners, scope, allowed_scopes: ::Ci::Runner::AVAILABLE_SCOPES)
+ return runners unless scope.present?
+
+ unless allowed_scopes.include?(scope)
+ render_api_error!('Scope contains invalid value', 400)
+ end
+
+ # Support deprecated scopes
+ if runners.respond_to?("deprecated_#{scope}")
+ scope = "deprecated_#{scope}"
+ end
+
+ runners.public_send(scope) # rubocop:disable GitlabSecurity/PublicSend
+ end
+
+ def apply_filter(runners, params)
+ runners = filter_runners(runners, params[:type], allowed_scopes: ::Ci::Runner::AVAILABLE_TYPES)
+ runners = filter_runners(runners, params[:status], allowed_scopes: ::Ci::Runner::AVAILABLE_STATUSES)
+ runners = filter_runners(runners, params[:paused] ? 'paused' : 'active', allowed_scopes: %w[paused active]) if params.include?(:paused)
+ runners = runners.tagged_with(params[:tag_list]) if params[:tag_list]
+
+ runners
+ end
+
+ def get_runner(id)
+ runner = ::Ci::Runner.find(id)
+ not_found!('Runner') unless runner
+ runner
+ end
+
+ def authenticate_show_runner!(runner)
+ return if runner.instance_type? || current_user.admin?
+
+ forbidden!("No access granted") unless can?(current_user, :read_runner, runner)
+ end
+
+ def authenticate_update_runner!(runner)
+ return if current_user.admin?
+
+ forbidden!("No access granted") unless can?(current_user, :update_runner, runner)
+ end
+
+ def authenticate_delete_runner!(runner)
+ return if current_user.admin?
+
+ forbidden!("Runner associated with more than one project") if runner.runner_projects.count > 1
+ forbidden!("No access granted") unless can?(current_user, :delete_runner, runner)
+ end
+
+ def authenticate_enable_runner!(runner)
+ forbidden!("Runner is a group runner") if runner.group_type?
+
+ return if current_user.admin?
+
+ forbidden!("Runner is locked") if runner.locked?
+ forbidden!("No access granted") unless can?(current_user, :assign_runner, runner)
+ end
+
+ def authenticate_list_runners_jobs!(runner)
+ return if current_user.admin?
+
+ forbidden!("No access granted") unless can?(current_user, :read_builds, runner)
+ end
+ end
+
resource :runners do
desc 'Get runners available for user' do
+ summary 'List owned runners'
success Entities::Ci::Runner
+ failure [[400, 'Scope contains invalid value'], [401, 'Unauthorized']]
+ tags %w[runners]
end
params do
- optional :scope, type: String, values: ::Ci::Runner::AVAILABLE_STATUSES,
- desc: 'The scope of specific runners to show'
- optional :type, type: String, values: ::Ci::Runner::AVAILABLE_TYPES,
- desc: 'The type of the runners to show'
- optional :paused, type: Boolean, desc: 'Whether to include only runners that are accepting or ignoring new jobs'
- optional :status, type: String, values: ::Ci::Runner::AVAILABLE_STATUSES,
- desc: 'The status of the runners to show'
- optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The tags of the runners to show'
- use :pagination
+ use :deprecated_filter_params
+ use :filter_params
end
get do
runners = current_user.ci_owned_runners
@@ -34,18 +112,16 @@ module API
end
desc 'Get all runners - shared and specific' do
+ summary 'List all runners'
+ detail 'Get a list of all runners in the GitLab instance (specific and shared). ' \
+ 'Access is restricted to users with administrator access.'
success Entities::Ci::Runner
+ failure [[400, 'Scope contains invalid value'], [401, 'Unauthorized']]
+ tags %w[runners]
end
params do
- optional :scope, type: String, values: ::Ci::Runner::AVAILABLE_SCOPES,
- desc: 'The scope of specific runners to show'
- optional :type, type: String, values: ::Ci::Runner::AVAILABLE_TYPES,
- desc: 'The type of the runners to show'
- optional :paused, type: Boolean, desc: 'Whether to include only runners that are accepting or ignoring new jobs'
- optional :status, type: String, values: ::Ci::Runner::AVAILABLE_STATUSES,
- desc: 'The status of the runners to show'
- optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The tags of the runners to show'
- use :pagination
+ use :deprecated_filter_params
+ use :filter_params
end
get 'all' do
authenticated_as_admin!
@@ -58,10 +134,13 @@ module API
end
desc "Get runner's details" do
+ detail 'At least the Maintainer role is required to get runner details at the project and group level. ' \
+ 'Instance-level runner details via this endpoint are available to all signed in users.'
success Entities::Ci::RunnerDetails
+ failure [[401, 'Unauthorized'], [403, 'No access granted'], [404, 'Runner not found']]
end
params do
- requires :id, type: Integer, desc: 'The ID of the runner'
+ requires :id, type: Integer, desc: 'The ID of a runner'
end
get ':id' do
runner = get_runner(params[:id])
@@ -71,19 +150,24 @@ module API
end
desc "Update runner's details" do
+ summary "Update details of a runner"
success Entities::Ci::RunnerDetails
+ failure [[400, 'Bad Request'], [401, 'Unauthorized'], [403, 'No access granted'], [404, 'Runner not found']]
end
params do
- requires :id, type: Integer, desc: 'The ID of the runner'
+ requires :id, type: Integer, desc: 'The ID of a runner'
optional :description, type: String, desc: 'The description of the runner'
- optional :active, type: Boolean, desc: 'Deprecated: Use `:paused` instead. Flag indicating whether the runner is allowed to receive jobs'
- optional :paused, type: Boolean, desc: 'Flag indicating whether the runner should ignore new jobs'
- optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The list of tags for a runner'
- optional :run_untagged, type: Boolean, desc: 'Flag indicating whether the runner can execute untagged jobs'
- optional :locked, type: Boolean, desc: 'Flag indicating the runner is locked'
+ optional :active, type: Boolean, desc: 'Deprecated: Use `paused` instead. Flag indicating whether the runner is allowed to receive jobs'
+ optional :paused, type: Boolean, desc: 'Specifies whether the runner should ignore new jobs'
+ optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ desc: 'The list of tags for a runner', documentation: { example: "['macos', 'shell']" }
+ optional :run_untagged, type: Boolean, desc: 'Specifies whether the runner can execute untagged jobs'
+ optional :locked, type: Boolean, desc: 'Specifies whether the runner is locked'
optional :access_level, type: String, values: ::Ci::Runner.access_levels.keys,
- desc: 'The access_level of the runner'
- optional :maximum_timeout, type: Integer, desc: 'Maximum timeout set when this Runner will handle the job'
+ desc: 'The access level of the runner'
+ optional :maximum_timeout, type: Integer,
+ desc: 'Maximum timeout that limits the amount of time (in seconds) ' \
+ 'that runners can run jobs'
at_least_one_of :description, :active, :paused, :tag_list, :run_untagged, :locked, :access_level, :maximum_timeout
mutually_exclusive :active, :paused
end
@@ -101,10 +185,15 @@ module API
end
desc 'Remove a runner' do
+ summary 'Delete a runner'
success Entities::Ci::Runner
+ failure [[401, 'Unauthorized'], [403, 'No access granted'],
+ [403, 'Runner associated with more than one project'], [404, 'Runner not found'],
+ [412, 'Precondition Failed']]
+ tags %w[runners]
end
params do
- requires :id, type: Integer, desc: 'The ID of the runner'
+ requires :id, type: Integer, desc: 'The ID of a runner'
end
delete ':id' do
runner = get_runner(params[:id])
@@ -115,13 +204,19 @@ module API
end
desc 'List jobs running on a runner' do
+ summary "List runner's jobs"
+ detail 'List jobs that are being processed or were processed by the specified runner. ' \
+ 'The list of jobs is limited to projects where the user has at least the Reporter role.'
success Entities::Ci::JobBasicWithProject
+ failure [[401, 'Unauthorized'], [403, 'No access granted'], [404, 'Runner not found']]
+ tags %w[runners jobs]
end
params do
- requires :id, type: Integer, desc: 'The ID of the runner'
+ requires :id, type: Integer, desc: 'The ID of a runner'
optional :status, type: String, desc: 'Status of the job', values: ::Ci::Build::AVAILABLE_STATUSES
- optional :order_by, type: String, desc: 'Order by `id` or not', values: ::Ci::RunnerJobsFinder::ALLOWED_INDEXED_COLUMNS
- optional :sort, type: String, values: %w[asc desc], default: 'desc', desc: 'Sort by asc (ascending) or desc (descending)'
+ optional :order_by, type: String, desc: 'Order by `id`', values: ::Ci::RunnerJobsFinder::ALLOWED_INDEXED_COLUMNS
+ optional :sort, type: String, values: %w[asc desc], default: 'desc', desc: 'Sort by `asc` or `desc` order. ' \
+ 'Specify `order_by` as well, including for `id`'
use :pagination
end
get ':id/jobs' do
@@ -143,7 +238,10 @@ module API
end
desc 'Reset runner authentication token' do
+ summary "Reset runner's authentication token"
success Entities::Ci::ResetTokenResult
+ failure [[403, 'No access granted'], [404, 'Runner not found']]
+ tags %w[runners]
end
params do
requires :id, type: Integer, desc: 'The ID of the runner'
@@ -158,24 +256,24 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id,
+ types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authorize_admin_project }
desc 'Get runners available for project' do
+ summary "List project's runners"
+ detail 'List all runners available in the project, including from ancestor groups ' \
+ 'and any allowed shared runners.'
success Entities::Ci::Runner
+ failure [[400, 'Scope contains invalid value'], [403, 'No access granted']]
+ tags %w[runners projects]
end
params do
- optional :scope, type: String, values: ::Ci::Runner::AVAILABLE_SCOPES,
- desc: 'The scope of specific runners to show'
- optional :type, type: String, values: ::Ci::Runner::AVAILABLE_TYPES,
- desc: 'The type of the runners to show'
- optional :paused, type: Boolean, desc: 'Whether to include only runners that are accepting or ignoring new jobs'
- optional :status, type: String, values: ::Ci::Runner::AVAILABLE_STATUSES,
- desc: 'The status of the runners to show'
- optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The tags of the runners to show'
- use :pagination
+ use :deprecated_filter_params
+ use :filter_params
end
get ':id/runners' do
runners = ::Ci::Runner.owned_or_instance_wide(user_project.id)
@@ -187,11 +285,16 @@ module API
present paginate(runners), with: Entities::Ci::Runner
end
- desc 'Enable a runner for a project' do
+ desc 'Enable a runner in project' do
+ detail "Enable an available specific runner in the project."
success Entities::Ci::Runner
+ failure [[400, 'Bad Request'],
+ [403, 'No access granted'], [403, 'Runner is a group runner'], [403, 'Runner is locked'],
+ [404, 'Runner not found']]
+ tags %w[runners projects]
end
params do
- requires :runner_id, type: Integer, desc: 'The ID of the runner'
+ requires :runner_id, type: Integer, desc: 'The ID of a runner'
end
post ':id/runners' do
runner = get_runner(params[:runner_id])
@@ -205,10 +308,17 @@ module API
end
desc "Disable project's runner" do
+ summary "Disable a specific runner from the project"
+ detail "It works only if the project isn't the only project associated with the specified runner. " \
+ "If so, an error is returned. Use the call to delete a runner instead."
success Entities::Ci::Runner
+ failure [[400, 'Bad Request'],
+ [403, 'Only one project associated with the runner. Please remove the runner instead'],
+ [404, 'Runner not found'], [412, 'Precondition Failed']]
+ tags %w[runners projects]
end
params do
- requires :runner_id, type: Integer, desc: 'The ID of the runner'
+ requires :runner_id, type: Integer, desc: 'The ID of a runner'
end
# rubocop: disable CodeReuse/ActiveRecord
delete ':id/runners/:runner_id' do
@@ -230,16 +340,15 @@ module API
before { authorize_admin_group }
desc 'Get runners available for group' do
+ summary "List group's runners"
+ detail 'List all runners available in the group as well as its ancestor groups, ' \
+ 'including any allowed shared runners.'
success Entities::Ci::Runner
+ failure [[400, 'Scope contains invalid value'], [403, 'Forbidden']]
+ tags %w[runners groups]
end
params do
- optional :type, type: String, values: ::Ci::Runner::AVAILABLE_TYPES,
- desc: 'The type of the runners to show'
- optional :paused, type: Boolean, desc: 'Whether to include only runners that are accepting or ignoring new jobs'
- optional :status, type: String, values: ::Ci::Runner::AVAILABLE_STATUSES,
- desc: 'The status of the runners to show'
- optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The tags of the runners to show'
- use :pagination
+ use :filter_params
end
get ':id/runners' do
runners = ::Ci::Runner.group_or_instance_wide(user_group)
@@ -252,8 +361,11 @@ module API
resource :runners do
before { authenticate_non_get! }
- desc 'Resets runner registration token' do
+ desc 'Reset runner registration token' do
+ summary "Reset instance's runner registration token"
success Entities::Ci::ResetTokenResult
+ failure [[403, 'Forbidden']]
+ tags %w[runners groups]
end
post 'reset_registration_token' do
authorize! :update_runners_registration_token, ApplicationSetting.current
@@ -269,8 +381,11 @@ module API
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authenticate_non_get! }
- desc 'Resets runner registration token' do
+ desc 'Reset runner registration token' do
+ summary "Reset the runner registration token for a project"
success Entities::Ci::ResetTokenResult
+ failure [[401, 'Unauthorized'], [403, 'Forbidden'], [404, 'Project Not Found']]
+ tags %w[runners projects]
end
post ':id/runners/reset_registration_token' do
project = find_project! user_project.id
@@ -287,8 +402,11 @@ module API
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authenticate_non_get! }
- desc 'Resets runner registration token' do
+ desc 'Reset runner registration token' do
+ summary "Reset the runner registration token for a group"
success Entities::Ci::ResetTokenResult
+ failure [[401, 'Unauthorized'], [403, 'Forbidden'], [404, 'Group Not Found']]
+ tags %w[runners groups]
end
post ':id/runners/reset_registration_token' do
group = find_group! user_group.id
@@ -298,72 +416,6 @@ module API
present group.runners_token_with_expiration, with: Entities::Ci::ResetTokenResult
end
end
-
- helpers do
- def filter_runners(runners, scope, allowed_scopes: ::Ci::Runner::AVAILABLE_SCOPES)
- return runners unless scope.present?
-
- unless allowed_scopes.include?(scope)
- render_api_error!('Scope contains invalid value', 400)
- end
-
- # Support deprecated scopes
- if runners.respond_to?("deprecated_#{scope}")
- scope = "deprecated_#{scope}"
- end
-
- runners.public_send(scope) # rubocop:disable GitlabSecurity/PublicSend
- end
-
- def apply_filter(runners, params)
- runners = filter_runners(runners, params[:type], allowed_scopes: ::Ci::Runner::AVAILABLE_TYPES)
- runners = filter_runners(runners, params[:status], allowed_scopes: ::Ci::Runner::AVAILABLE_STATUSES)
- runners = filter_runners(runners, params[:paused] ? 'paused' : 'active', allowed_scopes: %w[paused active]) if params.include?(:paused)
- runners = runners.tagged_with(params[:tag_list]) if params[:tag_list]
-
- runners
- end
-
- def get_runner(id)
- runner = ::Ci::Runner.find(id)
- not_found!('Runner') unless runner
- runner
- end
-
- def authenticate_show_runner!(runner)
- return if runner.instance_type? || current_user.admin?
-
- forbidden!("No access granted") unless can?(current_user, :read_runner, runner)
- end
-
- def authenticate_update_runner!(runner)
- return if current_user.admin?
-
- forbidden!("No access granted") unless can?(current_user, :update_runner, runner)
- end
-
- def authenticate_delete_runner!(runner)
- return if current_user.admin?
-
- forbidden!("Runner associated with more than one project") if runner.runner_projects.count > 1
- forbidden!("No access granted") unless can?(current_user, :delete_runner, runner)
- end
-
- def authenticate_enable_runner!(runner)
- forbidden!("Runner is a group runner") if runner.group_type?
-
- return if current_user.admin?
-
- forbidden!("Runner is locked") if runner.locked?
- forbidden!("No access granted") unless can?(current_user, :assign_runner, runner)
- end
-
- def authenticate_list_runners_jobs!(runner)
- return if current_user.admin?
-
- forbidden!("No access granted") unless can?(current_user, :read_builds, runner)
- end
- end
end
end
end
diff --git a/lib/api/ci/secure_files.rb b/lib/api/ci/secure_files.rb
index 511b6e06cd3..dd628a3413f 100644
--- a/lib/api/ci/secure_files.rb
+++ b/lib/api/ci/secure_files.rb
@@ -16,7 +16,7 @@ module API
default_format :json
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -61,7 +61,7 @@ module API
desc 'Upload a Secure File'
params do
requires :name, type: String, desc: 'The name of the file'
- requires :file, types: [Rack::Multipart::UploadedFile, ::API::Validations::Types::WorkhorseFile], desc: 'The secure file to be uploaded'
+ requires :file, types: [Rack::Multipart::UploadedFile, ::API::Validations::Types::WorkhorseFile], desc: 'The secure file to be uploaded', documentation: { type: 'file' }
end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: true
post ':id/secure_files' do
diff --git a/lib/api/ci/triggers.rb b/lib/api/ci/triggers.rb
index c49f1c9e9e1..c202d188e43 100644
--- a/lib/api/ci/triggers.rb
+++ b/lib/api/ci/triggers.rb
@@ -11,16 +11,26 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project',
+ documentation: { example: 18 }
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Trigger a GitLab project pipeline' do
- success Entities::Ci::Pipeline
+ success code: 201, model: Entities::Ci::Pipeline
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :ref, type: String, desc: 'The commit sha or name of a branch or tag', allow_blank: false
- requires :token, type: String, desc: 'The unique token of trigger or job token'
- optional :variables, type: Hash, desc: 'The list of variables to be injected into build'
+ requires :ref, type: String, desc: 'The commit sha or name of a branch or tag', allow_blank: false,
+ documentation: { example: 'develop' }
+ requires :token, type: String, desc: 'The unique token of trigger or job token',
+ documentation: { example: '6d056f63e50fe6f8c5f8f4aa10edb7' }
+ optional :variables, type: Hash, desc: 'The list of variables to be injected into build',
+ documentation: { example: { VAR1: "value1", VAR2: "value2" } }
end
post ":id/(ref/:ref/)trigger/pipeline", requirements: { ref: /.+/ } do
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/20758')
@@ -47,7 +57,13 @@ module API
end
desc 'Get triggers list' do
- success Entities::Trigger
+ success code: 200, model: Entities::Trigger
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
use :pagination
@@ -64,10 +80,15 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
desc 'Get specific trigger of a project' do
- success Entities::Trigger
+ success code: 200, model: Entities::Trigger
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :trigger_id, type: Integer, desc: 'The trigger ID'
+ requires :trigger_id, type: Integer, desc: 'The trigger ID', documentation: { example: 10 }
end
get ':id/triggers/:trigger_id' do
authenticate!
@@ -80,10 +101,17 @@ module API
end
desc 'Create a trigger' do
- success Entities::Trigger
+ success code: 201, model: Entities::Trigger
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :description, type: String, desc: 'The trigger description'
+ requires :description, type: String, desc: 'The trigger description',
+ documentation: { example: 'my trigger description' }
end
post ':id/triggers' do
authenticate!
@@ -100,7 +128,13 @@ module API
end
desc 'Update a trigger' do
- success Entities::Trigger
+ success code: 200, model: Entities::Trigger
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :trigger_id, type: Integer, desc: 'The trigger ID'
@@ -123,10 +157,16 @@ module API
end
desc 'Delete a trigger' do
- success Entities::Trigger
+ success code: 204
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 412, message: 'Precondition Failed' }
+ ]
end
params do
- requires :trigger_id, type: Integer, desc: 'The trigger ID'
+ requires :trigger_id, type: Integer, desc: 'The trigger ID', documentation: { example: 10 }
end
delete ':id/triggers/:trigger_id' do
authenticate!
diff --git a/lib/api/ci/variables.rb b/lib/api/ci/variables.rb
index c9e1d115d03..5a6b5987228 100644
--- a/lib/api/ci/variables.rb
+++ b/lib/api/ci/variables.rb
@@ -13,12 +13,13 @@ module API
helpers ::API::Helpers::VariablesHelpers
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID of a project or URL-encoded NAMESPACE/PROJECT_NAME of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get project variables' do
success Entities::Ci::Variable
+ tags %w[ci_variables]
end
params do
use :pagination
@@ -28,13 +29,15 @@ module API
present paginate(variables), with: Entities::Ci::Variable
end
- desc 'Get a specific variable from a project' do
+ desc 'Get the details of a single variable from a project' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Variable Not Found' }]
+ tags %w[ci_variables]
end
params do
- requires :key, type: String, desc: 'The key of the variable'
+ requires :key, type: String, desc: 'The key of a variable'
optional :filter, type: Hash, desc: 'Available filters: [environment_scope]. Example: filter[environment_scope]=production' do
- optional :environment_scope, type: String, desc: 'The environment scope of the variable'
+ optional :environment_scope, type: String, desc: 'The environment scope of a variable'
end
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -48,13 +51,17 @@ module API
desc 'Create a new variable in a project' do
success Entities::Ci::Variable
+ failure [{ code: 400, message: '400 Bad Request' }]
+ tags %w[ci_variables]
end
+ route_setting :log_safety, { safe: %w[key], unsafe: %w[value] }
params do
- requires :key, type: String, desc: 'The key of the variable'
- requires :value, type: String, desc: 'The value of the variable'
+ requires :key, type: String, desc: 'The key of a variable'
+ requires :value, type: String, desc: 'The value of a variable'
optional :protected, type: Boolean, desc: 'Whether the variable is protected'
optional :masked, type: Boolean, desc: 'Whether the variable is masked'
- optional :variable_type, type: String, values: ::Ci::Variable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file. Defaults to env_var'
+ optional :raw, type: Boolean, desc: 'Whether the variable will be expanded'
+ optional :variable_type, type: String, values: ::Ci::Variable.variable_types.keys, desc: 'The type of the variable. Default: env_var'
optional :environment_scope, type: String, desc: 'The environment_scope of the variable'
end
post ':id/variables' do
@@ -73,16 +80,20 @@ module API
desc 'Update an existing variable from a project' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Variable Not Found' }]
+ tags %w[ci_variables]
end
+ route_setting :log_safety, { safe: %w[key], unsafe: %w[value] }
params do
- optional :key, type: String, desc: 'The key of the variable'
- optional :value, type: String, desc: 'The value of the variable'
+ optional :key, type: String, desc: 'The key of a variable'
+ optional :value, type: String, desc: 'The value of a variable'
optional :protected, type: Boolean, desc: 'Whether the variable is protected'
optional :masked, type: Boolean, desc: 'Whether the variable is masked'
- optional :variable_type, type: String, values: ::Ci::Variable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file'
- optional :environment_scope, type: String, desc: 'The environment_scope of the variable'
+ optional :environment_scope, type: String, desc: 'The environment_scope of a variable'
+ optional :raw, type: Boolean, desc: 'Whether the variable will be expanded'
+ optional :variable_type, type: String, values: ::Ci::Variable.variable_types.keys, desc: 'The type of the variable. Default: env_var'
optional :filter, type: Hash, desc: 'Available filters: [environment_scope]. Example: filter[environment_scope]=production' do
- optional :environment_scope, type: String, desc: 'The environment scope of the variable'
+ optional :environment_scope, type: String, desc: 'The environment scope of a variable'
end
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -106,9 +117,11 @@ module API
desc 'Delete an existing variable from a project' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Variable Not Found' }]
+ tags %w[ci_variables]
end
params do
- requires :key, type: String, desc: 'The key of the variable'
+ requires :key, type: String, desc: 'The key of a variable'
optional :filter, type: Hash, desc: 'Available filters: [environment_scope]. Example: filter[environment_scope]=production' do
optional :environment_scope, type: String, desc: 'The environment scope of the variable'
end
diff --git a/lib/api/clusters/agent_tokens.rb b/lib/api/clusters/agent_tokens.rb
index 1f9c8700d7a..f65ae465b3d 100644
--- a/lib/api/clusters/agent_tokens.rb
+++ b/lib/api/clusters/agent_tokens.rb
@@ -10,7 +10,7 @@ module API
feature_category :kubernetes_management
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
params do
@@ -18,22 +18,24 @@ module API
end
resource ':id/cluster_agents/:agent_id' do
resource :tokens do
- desc 'List agent tokens' do
- detail 'This feature was introduced in GitLab 15.0.'
+ desc 'List tokens for an agent' do
+ detail 'This feature was introduced in GitLab 15.0. Returns a list of tokens for an agent.'
success Entities::Clusters::AgentTokenBasic
+ tags %w[cluster_agents]
end
params do
use :pagination
end
get do
- agent = ::Clusters::AgentsFinder.new(user_project, current_user).find(params[:agent_id])
+ agent_tokens = ::Clusters::AgentTokensFinder.new(user_project, current_user, params[:agent_id]).execute
- present paginate(agent.agent_tokens), with: Entities::Clusters::AgentTokenBasic
+ present paginate(agent_tokens), with: Entities::Clusters::AgentTokenBasic
end
desc 'Get a single agent token' do
- detail 'This feature was introduced in GitLab 15.0.'
+ detail 'This feature was introduced in GitLab 15.0. Gets a single agent token.'
success Entities::Clusters::AgentToken
+ tags %w[cluster_agents]
end
params do
requires :token_id, type: Integer, desc: 'The ID of the agent token'
@@ -47,8 +49,9 @@ module API
end
desc 'Create an agent token' do
- detail 'This feature was introduced in GitLab 15.0.'
+ detail 'This feature was introduced in GitLab 15.0. Creates a new token for an agent.'
success Entities::Clusters::AgentTokenWithToken
+ tags %w[cluster_agents]
end
params do
requires :name, type: String, desc: 'The name for the token'
@@ -71,7 +74,8 @@ module API
end
desc 'Revoke an agent token' do
- detail 'This feature was introduced in GitLab 15.0.'
+ detail 'This feature was introduced in GitLab 15.0. Revokes an agent token.'
+ tags %w[cluster_agents]
end
params do
requires :token_id, type: Integer, desc: 'The ID of the agent token'
diff --git a/lib/api/clusters/agents.rb b/lib/api/clusters/agents.rb
index 2affd9680b6..62d4fb009c6 100644
--- a/lib/api/clusters/agents.rb
+++ b/lib/api/clusters/agents.rb
@@ -11,12 +11,13 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'List agents' do
- detail 'This feature was introduced in GitLab 14.10.'
+ desc 'List the agents for a project' do
+ detail 'This feature was introduced in GitLab 14.10. Returns the list of agents registered for the project.'
success Entities::Clusters::Agent
+ tags %w[cluster_agents]
end
params do
use :pagination
@@ -29,9 +30,10 @@ module API
present paginate(agents), with: Entities::Clusters::Agent
end
- desc 'Get single agent' do
- detail 'This feature was introduced in GitLab 14.10.'
+ desc 'Get details about an agent' do
+ detail 'This feature was introduced in GitLab 14.10. Gets a single agent details.'
success Entities::Clusters::Agent
+ tags %w[cluster_agents]
end
params do
requires :agent_id, type: Integer, desc: 'The ID of an agent'
@@ -42,9 +44,10 @@ module API
present agent, with: Entities::Clusters::Agent
end
- desc 'Add an agent to a project' do
- detail 'This feature was introduced in GitLab 14.10.'
+ desc 'Register an agent with a project' do
+ detail 'This feature was introduced in GitLab 14.10. Registers an agent to the project.'
success Entities::Clusters::Agent
+ tags %w[cluster_agents]
end
params do
requires :name, type: String, desc: 'The name of the agent'
@@ -61,8 +64,9 @@ module API
present result[:cluster_agent], with: Entities::Clusters::Agent
end
- desc 'Delete an agent' do
- detail 'This feature was introduced in GitLab 14.10.'
+ desc 'Delete a registered agent' do
+ detail 'This feature was introduced in GitLab 14.10. Deletes an existing agent registration.'
+ tags %w[cluster_agents]
end
params do
requires :agent_id, type: Integer, desc: 'The ID of an agent'
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index 7d8b58fd7b6..954b572c9b1 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -8,7 +8,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
include PaginationParams
@@ -16,14 +16,20 @@ module API
before { authenticate! }
desc "Get a commit's statuses" do
- success Entities::CommitStatus
+ success code: 200, model: Entities::CommitStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
end
params do
- requires :sha, type: String, desc: 'The commit hash'
- optional :ref, type: String, desc: 'The ref'
- optional :stage, type: String, desc: 'The stage'
- optional :name, type: String, desc: 'The name'
- optional :all, type: String, desc: 'Show all statuses, default: false'
+ requires :sha, type: String, desc: 'The commit hash', documentation: { example: '18f3e63d05582537db6d183d9d557be09e1f90c8' }
+ optional :ref, type: String, desc: 'The ref', documentation: { example: 'develop' }
+ optional :stage, type: String, desc: 'The stage', documentation: { example: 'test' }
+ optional :name, type: String, desc: 'The name', documentation: { example: 'bundler:audit' }
+ optional :all, type: Boolean, desc: 'Show all statuses', documentation: { default: false }
use :pagination
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -43,19 +49,32 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
desc 'Post status to a commit' do
- success Entities::CommitStatus
+ success code: 200, model: Entities::CommitStatus
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :sha, type: String, desc: 'The commit hash'
- requires :state, type: String, desc: 'The state of the status',
- values: %w(pending running success failed canceled)
- optional :ref, type: String, desc: 'The ref'
- optional :target_url, type: String, desc: 'The target URL to associate with this status'
- optional :description, type: String, desc: 'A short description of the status'
- optional :name, type: String, desc: 'A string label to differentiate this status from the status of other systems. Default: "default"', documentation: { default: 'default' }
- optional :context, type: String, desc: 'A string label to differentiate this status from the status of other systems. Default: "default"', documentation: { default: 'default' }
- optional :coverage, type: Float, desc: 'The total code coverage'
- optional :pipeline_id, type: Integer, desc: 'An existing pipeline ID, when multiple pipelines on the same commit SHA have been triggered'
+ requires :sha, type: String, desc: 'The commit hash',
+ documentation: { example: '18f3e63d05582537db6d183d9d557be09e1f90c8' }
+ requires :state, type: String, desc: 'The state of the status',
+ values: %w(pending running success failed canceled),
+ documentation: { example: 'pending' }
+ optional :ref, type: String, desc: 'The ref',
+ documentation: { example: 'develop' }
+ optional :target_url, type: String, desc: 'The target URL to associate with this status',
+ documentation: { example: 'https://gitlab.example.com/janedoe/gitlab-foss/builds/91' }
+ optional :description, type: String, desc: 'A short description of the status'
+ optional :name, type: String, desc: 'A string label to differentiate this status from the status of other systems',
+ documentation: { example: 'coverage', default: 'default' }
+ optional :context, type: String, desc: 'A string label to differentiate this status from the status of other systems',
+ documentation: { example: 'coverage', default: 'default' }
+ optional :coverage, type: Float, desc: 'The total code coverage',
+ documentation: { example: 100.0 }
+ optional :pipeline_id, type: Integer, desc: 'An existing pipeline ID, when multiple pipelines on the same commit SHA have been triggered'
end
# rubocop: disable CodeReuse/ActiveRecord
post ':id/statuses/:sha' do
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index 50d0687ba75..63a13b83a9b 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -9,7 +9,7 @@ module API
before do
require_repository_enabled!
- authorize! :download_code, user_project
+ authorize! :read_code, user_project
verify_pagination_params!
end
@@ -27,17 +27,35 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS, urgency: :low do
desc 'Get a project repository commits' do
- success Entities::Commit
+ success code: 200, model: Entities::Commit
+ tags %w[commits]
+ is_array true
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- optional :ref_name, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
- optional :since, type: DateTime, desc: 'Only commits after or on this date will be returned'
- optional :until, type: DateTime, desc: 'Only commits before or on this date will be returned'
- optional :path, type: String, desc: 'The file path'
+ optional :ref_name,
+ type: String,
+ desc: 'The name of a repository branch or tag, if not given the default branch is used',
+ documentation: { example: 'v1.1.0' }
+ optional :since,
+ type: DateTime,
+ desc: 'Only commits after or on this date will be returned',
+ documentation: { example: '2021-09-20T11:50:22.001' }
+ optional :until,
+ type: DateTime,
+ desc: 'Only commits before or on this date will be returned',
+ documentation: { example: '2021-09-20T11:50:22.001' }
+ optional :path,
+ type: String,
+ desc: 'The file path',
+ documentation: { example: 'README.md' }
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'
@@ -81,40 +99,87 @@ module API
end
desc 'Commit multiple file changes as one commit' do
- success Entities::CommitDetail
+ success code: 200, model: Entities::CommitDetail
+ tags %w[commits]
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' }
+ ]
detail 'This feature was introduced in GitLab 8.13'
end
params do
- requires :branch, type: String, desc: 'Name of the branch to commit into. To create a new branch, also provide either `start_branch` or `start_sha`, and optionally `start_project`.', allow_blank: false
- requires :commit_message, type: String, desc: 'Commit message'
- requires :actions, type: Array, desc: 'Actions to perform in commit' do
- requires :action, type: String, desc: 'The action to perform, `create`, `delete`, `move`, `update`, `chmod`', values: %w[create update move delete chmod].freeze, allow_blank: false
- requires :file_path, type: String, desc: 'Full path to the file. Ex. `lib/class.rb`'
+ requires :branch,
+ type: String,
+ desc: 'Name of the branch to commit into. To create a new branch, also provide either `start_branch` or `start_sha`, and optionally `start_project`.',
+ allow_blank: false,
+ documentation: { example: 'master' }
+ requires :commit_message,
+ type: String,
+ desc: 'Commit message',
+ documentation: { example: 'initial commit' }
+ requires :actions,
+ type: Array,
+ desc: 'Actions to perform in commit' do
+ requires :action,
+ type: String,
+ desc: 'The action to perform, `create`, `delete`, `move`, `update`, `chmod`', values: %w[create update move delete chmod].freeze,
+ allow_blank: false
+ requires :file_path,
+ type: String,
+ desc: 'Full path to the file.',
+ documentation: { example: 'lib/class.rb' }
given action: ->(action) { action == 'move' } do
- requires :previous_path, type: String, desc: 'Original full path to the file being moved. Ex. `lib/class1.rb`'
+ requires :previous_path,
+ type: String,
+ desc: 'Original full path to the file being moved.',
+ documentation: { example: 'lib/class.rb' }
end
given action: ->(action) { %w[create move].include? action } do
- optional :content, type: String, desc: 'File content'
+ optional :content,
+ type: String,
+ desc: 'File content',
+ documentation: { example: 'Some file content' }
end
given action: ->(action) { action == 'update' } do
- requires :content, type: String, desc: 'File content'
+ requires :content,
+ type: String,
+ desc: 'File content',
+ documentation: { example: 'Some file content' }
end
optional :encoding, type: String, desc: '`text` or `base64`', default: 'text', values: %w[text base64]
given action: ->(action) { %w[update move delete].include? action } do
- optional :last_commit_id, type: String, desc: 'Last known file commit id'
+ optional :last_commit_id,
+ type: String,
+ desc: 'Last known file commit id',
+ documentation: { example: '2695effb5807a22ff3d138d593fd856244e155e7' }
end
given action: ->(action) { action == 'chmod' } do
requires :execute_filemode, type: Boolean, desc: 'When `true/false` enables/disables the execute flag on the file.'
end
end
- optional :start_branch, type: String, desc: 'Name of the branch to start the new branch from'
- optional :start_sha, type: String, desc: 'SHA of the commit to start the new branch from'
+ optional :start_branch,
+ type: String,
+ desc: 'Name of the branch to start the new branch from',
+ documentation: { example: 'staging' }
+ optional :start_sha,
+ type: String,
+ desc: 'SHA of the commit to start the new branch from',
+ documentation: { example: '2695effb5807a22ff3d138d593fd856244e155e7' }
mutually_exclusive :start_branch, :start_sha
- optional :start_project, types: [Integer, String], desc: 'The ID or path of the project to start the new branch from'
- optional :author_email, type: String, desc: 'Author email for commit'
- optional :author_name, type: String, desc: 'Author name for commit'
+ optional :start_project,
+ types: [Integer, String],
+ desc: 'The ID or path of the project to start the new branch from',
+ documentation: { example: 1 }
+ optional :author_email,
+ type: String,
+ desc: 'Author email for commit',
+ documentation: { example: 'janedoe@example.com' }
+ optional :author_name,
+ type: String,
+ desc: 'Author name for commit',
+ documentation: { example: 'Jane Doe' }
optional :stats, type: Boolean, default: true, desc: 'Include commit stats'
optional :force, type: Boolean, default: false, desc: 'When `true` overwrites the target branch with a new commit based on the `start_branch` or `start_sha`'
end
@@ -151,8 +216,11 @@ module API
end
desc 'Get a specific commit of a project' do
- success Entities::CommitDetail
- failure [[404, 'Commit Not Found']]
+ success code: 200, model: Entities::CommitDetail
+ tags %w[commits]
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
@@ -167,7 +235,12 @@ module API
end
desc 'Get the diff for a specific commit of a project' do
- failure [[404, 'Commit Not Found']]
+ success code: 200, model: Entities::Diff
+ tags %w[commits]
+ is_array true
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
@@ -184,8 +257,12 @@ module API
end
desc "Get a commit's comments" do
- success Entities::CommitNote
- failure [[404, 'Commit Not Found']]
+ success code: 200, model: Entities::CommitNote
+ tags %w[commits]
+ is_array true
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
end
params do
use :pagination
@@ -202,13 +279,25 @@ module API
desc 'Cherry pick commit into a branch' do
detail 'This feature was introduced in GitLab 8.15'
- success Entities::Commit
+ success code: 200, model: Entities::Commit
+ tags %w[commits]
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag to be cherry picked'
- requires :branch, type: String, desc: 'The name of the branch', allow_blank: false
+ requires :branch,
+ type: String,
+ desc: 'The name of the branch',
+ allow_blank: false,
+ documentation: { example: 'master' }
optional :dry_run, type: Boolean, default: false, desc: "Does not commit any changes"
- optional :message, type: String, desc: 'A custom commit message to use for the picked commit'
+ optional :message,
+ type: String,
+ desc: 'A custom commit message to use for the picked commit',
+ documentation: { example: 'Initial commit' }
end
post ':id/repository/commits/:sha/cherry_pick', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
authorize_push_to_branch!(params[:branch])
@@ -248,11 +337,20 @@ module API
desc 'Revert a commit in a branch' do
detail 'This feature was introduced in GitLab 11.5'
- success Entities::Commit
+ success code: 200, model: Entities::Commit
+ tags %w[commits]
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'Commit SHA to revert'
- requires :branch, type: String, desc: 'Target branch name', allow_blank: false
+ requires :branch,
+ type: String,
+ desc: 'Target branch name',
+ allow_blank: false,
+ documentation: { example: 'master' }
optional :dry_run, type: Boolean, default: false, desc: "Does not commit any changes"
end
post ':id/repository/commits/:sha/revert', requirements: API::COMMIT_ENDPOINT_REQUIREMENTS do
@@ -292,7 +390,12 @@ module API
desc 'Get all references a commit is pushed to' do
detail 'This feature was introduced in GitLab 10.6'
- success Entities::BasicRef
+ success code: 200, model: Entities::BasicRef
+ tags %w[commits]
+ is_array true
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'A commit sha'
@@ -312,14 +415,28 @@ module API
end
desc 'Post comment to commit' do
- success Entities::CommitNote
+ success code: 200, model: Entities::CommitNote
+ tags %w[commits]
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag on which to post a comment'
- requires :note, type: String, desc: 'The text of the comment'
- optional :path, type: String, desc: 'The file path'
+ requires :note,
+ type: String,
+ desc: 'The text of the comment',
+ documentation: { example: 'Nice code!' }
+ optional :path,
+ type: String,
+ desc: 'The file path',
+ documentation: { example: 'doc/update/5.4-to-6.0.md' }
given :path do
- requires :line, type: Integer, desc: 'The line number'
+ requires :line,
+ type: Integer,
+ desc: 'The line number',
+ documentation: { example: 11 }
requires :line_type, type: String, values: %w[new old], default: 'new', desc: 'The type of the line'
end
end
@@ -361,7 +478,12 @@ module API
end
desc 'Get Merge Requests associated with a commit' do
- success Entities::MergeRequestBasic
+ success code: 200, model: Entities::MergeRequestBasic
+ tags %w[commits]
+ is_array true
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag on which to find Merge Requests'
@@ -383,7 +505,11 @@ module API
end
desc "Get a commit's signature" do
- success Entities::CommitSignature
+ success code: 200, model: Entities::CommitSignature
+ tags %w[commits]
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :sha, type: String, desc: 'A commit sha, or the name of a branch or tag'
diff --git a/lib/api/concerns/packages/conan_endpoints.rb b/lib/api/concerns/packages/conan_endpoints.rb
index d8c2eb4ff33..fdbffb1689b 100644
--- a/lib/api/concerns/packages/conan_endpoints.rb
+++ b/lib/api/concerns/packages/conan_endpoints.rb
@@ -29,7 +29,7 @@ module API
CONAN_REVISION_REGEX = Gitlab::Regex.conan_revision_regex
CONAN_REVISION_USER_CHANNEL_REGEX = Gitlab::Regex.conan_recipe_user_channel_regex
- CONAN_FILES = (Gitlab::Regex::Packages::CONAN_RECIPE_FILES + Gitlab::Regex::Packages::CONAN_PACKAGE_FILES).freeze
+ CONAN_FILES = (Gitlab::Regex::Packages::CONAN_RECIPE_FILES + Gitlab::Regex::Packages::CONAN_PACKAGE_FILES).uniq.freeze
included do
feature_category :package_registry
@@ -307,7 +307,7 @@ module API
end
params do
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
end
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
@@ -358,7 +358,7 @@ module API
end
params do
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
end
route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true
diff --git a/lib/api/container_registry_event.rb b/lib/api/container_registry_event.rb
index 66689f8d7c8..9acf2fca1b3 100644
--- a/lib/api/container_registry_event.rb
+++ b/lib/api/container_registry_event.rb
@@ -23,8 +23,20 @@ module API
content_type :json, DOCKER_DISTRIBUTION_EVENTS_V1_JSON
format :json
+ desc 'Receives notifications from the container registry when an operation occurs' do
+ detail 'This feature was introduced in GitLab 12.10'
+ consumes [:json, DOCKER_DISTRIBUTION_EVENTS_V1_JSON]
+ end
params do
- requires :events, type: Array
+ requires :events, type: Array, desc: 'Event notifications' do
+ requires :action, type: String, desc: 'The action to perform, `push`, `delete`',
+ values: %w[push delete].freeze
+ optional :target, type: Hash, desc: 'The target of the action' do
+ optional :tag, type: String, desc: 'The target tag'
+ optional :repository, type: String, desc: 'The target repository'
+ optional :digest, type: String, desc: 'Unique identifier for target image manifest'
+ end
+ end
end
# This endpoint is used by Docker Registry to push a set of event
diff --git a/lib/api/container_repositories.rb b/lib/api/container_repositories.rb
index d4fa6153a92..f2dd1fa21fd 100644
--- a/lib/api/container_repositories.rb
+++ b/lib/api/container_repositories.rb
@@ -14,7 +14,7 @@ module API
namespace 'registry' do
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :repositories, requirements: { id: /[0-9]*/ } do
desc 'Get a container repository' do
diff --git a/lib/api/debian_project_packages.rb b/lib/api/debian_project_packages.rb
index 03f0f97b805..df3b6e774ae 100644
--- a/lib/api/debian_project_packages.rb
+++ b/lib/api/debian_project_packages.rb
@@ -34,7 +34,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
namespace ':id/packages/debian' do
@@ -64,7 +64,7 @@ module API
# PUT {projects|groups}/:id/packages/debian/:file_name
params do
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
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/dependency_proxy.rb b/lib/api/dependency_proxy.rb
index 290a90934d7..fcf18a2792a 100644
--- a/lib/api/dependency_proxy.rb
+++ b/lib/api/dependency_proxy.rb
@@ -12,11 +12,18 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a group'
+ requires :id, types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the group owned by the authenticated user'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Deletes all dependency_proxy_blobs for a group' do
- detail 'This feature was introduced in GitLab 12.10'
+ desc 'Purge the dependency proxy for a group' do
+ detail 'Schedules for deletion the cached manifests and blobs for a group.'\
+ 'This endpoint requires the Owner role for the group.'
+ success code: 202
+ failure [
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags %w[dependency_proxy]
end
delete ':id/dependency_proxy/cache' do
not_found! unless user_group.dependency_proxy_feature_available?
diff --git a/lib/api/deploy_keys.rb b/lib/api/deploy_keys.rb
index c53f4bca5a7..ffe0b6589bc 100644
--- a/lib/api/deploy_keys.rb
+++ b/lib/api/deploy_keys.rb
@@ -4,6 +4,8 @@ module API
class DeployKeys < ::API::Base
include PaginationParams
+ deploy_keys_tags = %w[deploy_keys]
+
before { authenticate! }
feature_category :continuous_delivery
@@ -21,7 +23,16 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
end
- desc 'Return all deploy keys'
+ desc 'List all deploy keys' do
+ detail 'Get a list of all deploy keys across all projects of the GitLab instance. This endpoint requires administrator access and is not available on GitLab.com.'
+ success Entities::DeployKey
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' }
+ ]
+ is_array true
+ tags deploy_keys_tags
+ end
params do
use :pagination
optional :public, type: Boolean, default: false, desc: "Only return deploy keys that are public"
@@ -35,13 +46,20 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of the project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authorize_admin_project }
- desc "Get a specific project's deploy keys" do
+ desc 'List deploy keys for project' do
+ detail "Get a list of a project's deploy keys."
success Entities::DeployKeysProject
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags deploy_keys_tags
end
params do
use :pagination
@@ -54,8 +72,14 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
- desc 'Get single deploy key' do
+ desc 'Get a single deploy key' do
+ detail 'Get a single key.'
success Entities::DeployKeysProject
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_keys_tags
end
params do
requires :key_id, type: Integer, desc: 'The ID of the deploy key'
@@ -66,12 +90,19 @@ module API
present key, with: Entities::DeployKeysProject
end
- desc 'Add new deploy key to a project' do
+ desc 'Add deploy key' do
+ detail "Creates a new deploy key for a project. If the deploy key already exists in another project, it's joined to the current project only if the original one is accessible by the same user."
success Entities::DeployKeysProject
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_keys_tags
end
params do
- requires :key, type: String, desc: 'The new deploy key'
- requires :title, type: String, desc: 'The name of the deploy key'
+ requires :key, type: String, desc: 'New deploy key'
+ requires :title, type: String, desc: "New deploy key's title"
optional :can_push, type: Boolean, desc: "Can deploy key push to the project's repository"
end
# rubocop: disable CodeReuse/ActiveRecord
@@ -109,12 +140,20 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
- desc 'Update an existing deploy key for a project' do
+ desc 'Update deploy key' do
+ detail 'Updates a deploy key for a project.'
success Entities::DeployKey
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_keys_tags
end
params do
requires :key_id, type: Integer, desc: 'The ID of the deploy key'
- optional :title, type: String, desc: 'The name of the deploy key'
+ optional :title, type: String, desc: "New deploy key's title"
optional :can_push, type: Boolean, desc: "Can deploy key push to the project's repository"
at_least_one_of :title, :can_push
end
@@ -143,9 +182,14 @@ module API
end
end
- desc 'Enable a deploy key for a project' do
- detail 'This feature was added in GitLab 8.11'
+ desc 'Enable a deploy key' do
+ detail 'Enables a deploy key for a project so this can be used. Returns the enabled key, with a status code 201 when successful. This feature was added in GitLab 8.11.'
success Entities::DeployKey
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_keys_tags
end
params do
requires :key_id, type: Integer, desc: 'The ID of the deploy key'
@@ -161,7 +205,14 @@ module API
end
end
- desc 'Delete deploy key for a project'
+ desc 'Delete deploy key' do
+ detail "Removes a deploy key from the project. If the deploy key is used only for this project, it's deleted from the system."
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_keys_tags
+ end
params do
requires :key_id, type: Integer, desc: 'The ID of the deploy key'
end
diff --git a/lib/api/deploy_tokens.rb b/lib/api/deploy_tokens.rb
index 3955e29621f..975a65af285 100644
--- a/lib/api/deploy_tokens.rb
+++ b/lib/api/deploy_tokens.rb
@@ -4,6 +4,8 @@ module API
class DeployTokens < ::API::Base
include PaginationParams
+ deploy_tokens_tags = %w[deploy_tokens]
+
feature_category :continuous_delivery
urgency :low
@@ -25,9 +27,15 @@ module API
end
end
- desc 'Return all deploy tokens' do
- detail 'This feature was introduced in GitLab 12.9.'
+ desc 'List all deploy tokens' do
+ detail 'Get a list of all deploy tokens across the GitLab instance. This endpoint requires administrator access. This feature was introduced in GitLab 12.9.'
success Entities::DeployToken
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' }
+ ]
+ is_array true
+ tags deploy_tokens_tags
end
params do
use :pagination
@@ -46,16 +54,23 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
params do
use :pagination
use :filter_params
end
- desc 'List deploy tokens for a project' do
- detail 'This feature was introduced in GitLab 12.9'
+ desc 'List project deploy tokens' do
+ detail "Get a list of a project's deploy tokens. This feature was introduced in GitLab 12.9."
success Entities::DeployToken
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags deploy_tokens_tags
end
get ':id/deploy_tokens' do
authorize!(:read_deploy_token, user_project)
@@ -75,13 +90,19 @@ module API
type: Array[String],
coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
values: ::DeployToken::AVAILABLE_SCOPES.map(&:to_s),
- desc: 'Indicates the deploy token scopes. Must be at least one of "read_repository", "read_registry", "write_registry", "read_package_registry", or "write_package_registry".'
- optional :expires_at, type: DateTime, desc: 'Expiration date for the deploy token. Does not expire if no value is provided.'
+ desc: 'Indicates the deploy token scopes. Must be at least one of `read_repository`, `read_registry`, `write_registry`, `read_package_registry`, or `write_package_registry`.'
+ optional :expires_at, type: DateTime, desc: 'Expiration date for the deploy token. Does not expire if no value is provided. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`).'
optional :username, type: String, desc: 'Username for deploy token. Default is `gitlab+deploy-token-{n}`'
end
desc 'Create a project deploy token' do
- detail 'This feature was introduced in GitLab 12.9'
+ detail 'Creates a new deploy token for a project. This feature was introduced in GitLab 12.9.'
success Entities::DeployTokenWithToken
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_tokens_tags
end
post ':id/deploy_tokens' do
authorize!(:create_deploy_token, user_project)
@@ -98,11 +119,16 @@ module API
end
desc 'Get a project deploy token' do
- detail 'This feature was introduced in GitLab 14.9'
+ detail "Get a single project's deploy token by ID. This feature was introduced in GitLab 14.9."
success Entities::DeployToken
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_tokens_tags
end
params do
- requires :token_id, type: Integer, desc: 'The deploy token ID'
+ requires :token_id, type: Integer, desc: 'The ID of the deploy token'
end
get ':id/deploy_tokens/:token_id' do
authorize!(:read_deploy_token, user_project)
@@ -113,10 +139,15 @@ module API
end
desc 'Delete a project deploy token' do
- detail 'This feature was introduced in GitLab 12.9'
+ detail 'This feature was introduced in GitLab 12.9.'
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_tokens_tags
end
params do
- requires :token_id, type: Integer, desc: 'The deploy token ID'
+ requires :token_id, type: Integer, desc: 'The ID of the deploy token'
end
delete ':id/deploy_tokens/:token_id' do
authorize!(:destroy_deploy_token, user_project)
@@ -130,16 +161,23 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a group'
+ requires :id, types: [Integer, String], desc: 'The ID or URL-encoded path of the group owned by the authenticated user'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
params do
use :pagination
use :filter_params
end
- desc 'List deploy tokens for a group' do
- detail 'This feature was introduced in GitLab 12.9'
+ desc 'List group deploy tokens' do
+ detail "Get a list of a group's deploy tokens. This feature was introduced in GitLab 12.9."
success Entities::DeployToken
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags deploy_tokens_tags
end
get ':id/deploy_tokens' do
authorize!(:read_deploy_token, user_group)
@@ -154,18 +192,24 @@ module API
end
params do
- requires :name, type: String, desc: 'The name of the deploy token'
+ requires :name, type: String, desc: "New deploy token's name"
requires :scopes,
type: Array[String],
coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
values: ::DeployToken::AVAILABLE_SCOPES.map(&:to_s),
- desc: 'Indicates the deploy token scopes. Must be at least one of "read_repository", "read_registry", "write_registry", "read_package_registry", or "write_package_registry".'
- optional :expires_at, type: DateTime, desc: 'Expiration date for the deploy token. Does not expire if no value is provided.'
+ desc: 'Indicates the deploy token scopes. Must be at least one of `read_repository`, `read_registry`, `write_registry`, `read_package_registry`, or `write_package_registry`'
+ optional :expires_at, type: DateTime, desc: 'Expiration date for the deploy token. Does not expire if no value is provided. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`)'
optional :username, type: String, desc: 'Username for deploy token. Default is `gitlab+deploy-token-{n}`'
end
desc 'Create a group deploy token' do
- detail 'This feature was introduced in GitLab 12.9'
+ detail 'Creates a new deploy token for a group. This feature was introduced in GitLab 12.9.'
success Entities::DeployTokenWithToken
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_tokens_tags
end
post ':id/deploy_tokens' do
authorize!(:create_deploy_token, user_group)
@@ -182,11 +226,16 @@ module API
end
desc 'Get a group deploy token' do
- detail 'This feature was introduced in GitLab 14.9'
+ detail "Get a single group's deploy token by ID. This feature was introduced in GitLab 14.9. "
success Entities::DeployToken
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_tokens_tags
end
params do
- requires :token_id, type: Integer, desc: 'The deploy token ID'
+ requires :token_id, type: Integer, desc: 'The ID of the deploy token'
end
get ':id/deploy_tokens/:token_id' do
authorize!(:read_deploy_token, user_group)
@@ -197,10 +246,15 @@ module API
end
desc 'Delete a group deploy token' do
- detail 'This feature was introduced in GitLab 12.9'
+ detail 'Removes a deploy token from the group. This feature was introduced in GitLab 12.9.'
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deploy_tokens_tags
end
params do
- requires :token_id, type: Integer, desc: 'The deploy token ID'
+ requires :token_id, type: Integer, desc: 'The ID of the deploy token'
end
delete ':id/deploy_tokens/:token_id' do
authorize!(:destroy_deploy_token, user_group)
diff --git a/lib/api/deployments.rb b/lib/api/deployments.rb
index ee0a026d7ac..141f089b5e1 100644
--- a/lib/api/deployments.rb
+++ b/lib/api/deployments.rb
@@ -5,25 +5,51 @@ module API
class Deployments < ::API::Base
include PaginationParams
+ deployments_tags = %w[deployments]
+
before { authenticate! }
feature_category :continuous_delivery
urgency :low
params do
- requires :id, type: String, desc: 'The project ID'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get all deployments of the project' do
- detail 'This feature was introduced in GitLab 8.11.'
+ desc 'List project deployments' do
+ detail 'Get a list of deployments in a project. This feature was introduced in GitLab 8.11.'
success Entities::Deployment
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags deployments_tags
end
params do
use :pagination
- optional :order_by, type: String, values: DeploymentsFinder::ALLOWED_SORT_VALUES, default: DeploymentsFinder::DEFAULT_SORT_VALUE, desc: 'Return deployments ordered by specified value'
- optional :sort, type: String, values: DeploymentsFinder::ALLOWED_SORT_DIRECTIONS, default: DeploymentsFinder::DEFAULT_SORT_DIRECTION, desc: 'Sort by asc (ascending) or desc (descending)'
- optional :updated_after, type: DateTime, desc: 'Return deployments updated after the specified date'
- optional :updated_before, type: DateTime, desc: 'Return deployments updated before the specified date'
+
+ optional :order_by,
+ type: String,
+ values: DeploymentsFinder::ALLOWED_SORT_VALUES,
+ default: DeploymentsFinder::DEFAULT_SORT_VALUE,
+ desc: 'Return deployments ordered by either one of `id`, `iid`, `created_at`, `updated_at` or `ref` fields. Default is `id`'
+
+ optional :sort,
+ type: String,
+ values: DeploymentsFinder::ALLOWED_SORT_DIRECTIONS,
+ default: DeploymentsFinder::DEFAULT_SORT_DIRECTION,
+ desc: 'Return deployments sorted in `asc` or `desc` order. Default is `asc`'
+
+ optional :updated_after,
+ type: DateTime,
+ desc: 'Return deployments updated after the specified date. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`)'
+
+ optional :updated_before,
+ type: DateTime,
+ desc: 'Return deployments updated before the specified date. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`)'
+
optional :environment,
type: String,
desc: 'The name of the environment to filter deployments by'
@@ -31,7 +57,7 @@ module API
optional :status,
type: String,
values: Deployment.statuses.keys,
- desc: 'The status to filter deployments by'
+ desc: 'The status to filter deployments by. One of `created`, `running`, `success`, `failed`, `canceled`, or `blocked`'
end
get ':id/deployments' do
@@ -46,12 +72,17 @@ module API
bad_request!(e.message)
end
- desc 'Gets a specific deployment' do
+ desc 'Get a specific deployment' do
detail 'This feature was introduced in GitLab 8.11.'
success Entities::DeploymentExtended
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deployments_tags
end
params do
- requires :deployment_id, type: Integer, desc: 'The deployment ID'
+ requires :deployment_id, type: Integer, desc: 'The ID of the deployment'
end
get ':id/deployments/:deployment_id' do
authorize! :read_deployment, user_project
@@ -61,30 +92,36 @@ module API
present deployment, with: Entities::DeploymentExtended
end
- desc 'Creates a new deployment' do
- detail 'This feature was introduced in GitLab 12.4'
+ desc 'Create a deployment' do
+ detail 'This feature was introduced in GitLab 12.4.'
success Entities::DeploymentExtended
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deployments_tags
end
params do
requires :environment,
type: String,
- desc: 'The name of the environment to deploy to'
+ desc: 'The name of the environment to create the deployment for'
requires :sha,
type: String,
- desc: 'The SHA of the commit that was deployed'
+ desc: 'The SHA of the commit that is deployed'
requires :ref,
type: String,
- desc: 'The name of the branch or tag that was deployed'
+ desc: 'The name of the branch or tag that is deployed'
requires :tag,
type: Boolean,
- desc: 'A boolean indicating if the deployment ran for a tag'
+ desc: 'A boolean that indicates if the deployed ref is a tag (`true`) or not (`false`)'
requires :status,
type: String,
- desc: 'The status of the deployment',
+ desc: 'The status to filter deployments by. One of `running`, `success`, `failed`, or `canceled`',
values: %w[running success failed canceled]
end
post ':id/deployments' do
@@ -96,7 +133,7 @@ module API
.find_or_create_by_name(params[:environment])
unless environment.persisted?
- render_validation_error!(deployment)
+ render_validation_error!(environment)
end
authorize!(:create_deployment, environment)
@@ -113,14 +150,21 @@ module API
end
end
- desc 'Updates an existing deployment' do
- detail 'This feature was introduced in GitLab 12.4'
+ desc 'Update a deployment' do
+ detail 'This feature was introduced in GitLab 12.4.'
success Entities::DeploymentExtended
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags deployments_tags
end
params do
requires :status,
type: String,
- desc: 'The new status of the deployment',
+ desc: 'The new status of the deployment. One of `running`, `success`, `failed`, or `canceled`',
values: %w[running success failed canceled]
end
put ':id/deployments/:deployment_id' do
@@ -143,12 +187,17 @@ module API
end
end
- desc 'Deletes an existing deployment' do
- detail 'This feature was introduced in GitLab 15.3'
- http_codes [[204, 'Deployment was deleted'], [403, 'Forbidden'], [400, 'Cannot destroy']]
+ desc 'Delete a specific deployment' do
+ detail 'Delete a specific deployment that is not currently the last deployment for an environment or in a running state. This feature was introduced in GitLab 15.3.'
+ http_codes [
+ [204, 'Deployment destroyed'],
+ [403, 'Forbidden'],
+ [400, '"Cannot destroy running deployment" or "Deployment currently deployed to environment"']
+ ]
+ tags deployments_tags
end
params do
- requires :deployment_id, type: Integer, desc: 'The deployment ID'
+ requires :deployment_id, type: Integer, desc: 'The ID of the deployment'
end
delete ':id/deployments/:deployment_id' do
deployment = user_project.deployments.find(params[:deployment_id])
@@ -166,13 +215,21 @@ module API
helpers Helpers::MergeRequestsHelpers
- desc 'Get all merge requests of a deployment' do
- detail 'This feature was introduced in GitLab 12.7.'
+ desc 'List of merge requests associated with a deployment' do
+ detail 'Retrieves the list of merge requests shipped with a given deployment. This feature was introduced in GitLab 12.7.'
success Entities::MergeRequestBasic
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags deployments_tags
end
params do
use :pagination
- requires :deployment_id, type: Integer, desc: 'The deployment ID'
+
+ requires :deployment_id, type: Integer, desc: 'The ID of the deployment'
+
use :merge_requests_base_params
end
diff --git a/lib/api/discussions.rb b/lib/api/discussions.rb
index f73e4b621ab..d3a25a076a0 100644
--- a/lib/api/discussions.rb
+++ b/lib/api/discussions.rb
@@ -18,17 +18,19 @@ module API
Helpers::DiscussionsHelpers.feature_category_per_noteable_type.each do |noteable_type, feature_category|
parent_type = noteable_type.parent_class.to_s.underscore
noteables_str = noteable_type.to_s.underscore.pluralize
+ notable_name = noteable_type.to_s.underscore.humanize.downcase
+ notable_id_type = noteable_type == Commit ? String : Integer
noteables_path = noteable_type == Commit ? "repository/#{noteables_str}" : noteables_str
params do
requires :id, type: String, desc: "The ID of a #{parent_type}"
end
resource parent_type.pluralize.to_sym, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc "Get a list of #{noteable_type.to_s.downcase} discussions" do
+ desc "Get a list of #{notable_name} discussions" do
success Entities::Discussion
end
params do
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
use :pagination
end
@@ -41,12 +43,12 @@ module API
present Discussion.build_collection(notes, noteable), with: Entities::Discussion
end
- desc "Get a single #{noteable_type.to_s.downcase} discussion" do
+ desc "Get a single #{notable_name} discussion" do
success Entities::Discussion
end
params do
requires :discussion_id, type: String, desc: 'The ID of a discussion'
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
end
get ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id", feature_category: feature_category do
noteable = find_noteable(noteable_type, params[:noteable_id])
@@ -61,39 +63,44 @@ module API
present discussion, with: Entities::Discussion
end
- desc "Create a new #{noteable_type.to_s.downcase} discussion" do
+ desc "Create a new #{notable_name} discussion" do
success Entities::Discussion
end
params do
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
requires :body, type: String, desc: 'The content of a note'
optional :created_at, type: String, desc: 'The creation date of the note'
- optional :position, type: Hash do
- requires :base_sha, type: String, desc: 'Base commit SHA in the source branch'
- requires :start_sha, type: String, desc: 'SHA referencing commit in target branch'
- requires :head_sha, type: String, desc: 'SHA referencing HEAD of this merge request'
- requires :position_type, type: String, desc: 'Type of the position reference', values: %w(text image)
- optional :new_path, type: String, desc: 'File path after change'
- optional :new_line, type: Integer, desc: 'Line number after change'
- optional :old_path, type: String, desc: 'File path before change'
- optional :old_line, type: Integer, desc: 'Line number before change'
- optional :width, type: Integer, desc: 'Width of the image'
- optional :height, type: Integer, desc: 'Height of the image'
- optional :x, type: Integer, desc: 'X coordinate in the image'
- optional :y, type: Integer, desc: 'Y coordinate in the image'
-
- optional :line_range, type: Hash, desc: 'Multi-line start and end' do
- optional :start, type: Hash do
- optional :line_code, type: String, desc: 'Start line code for multi-line note'
- optional :type, type: String, desc: 'Start line type for multi-line note'
- optional :old_line, type: String, desc: 'Start old_line line number'
- optional :new_line, type: String, desc: 'Start new_line line number'
- end
- optional :end, type: Hash do
- optional :line_code, type: String, desc: 'End line code for multi-line note'
- optional :type, type: String, desc: 'End line type for multi-line note'
- optional :old_line, type: String, desc: 'End old_line line number'
- optional :new_line, type: String, desc: 'End new_line line number'
+
+ if [Commit, MergeRequest].include?(noteable_type)
+ optional :position, type: Hash do
+ requires :base_sha, type: String, desc: 'Base commit SHA in the source branch'
+ requires :start_sha, type: String, desc: 'SHA referencing commit in target branch'
+ requires :head_sha, type: String, desc: 'SHA referencing HEAD of this merge request'
+ requires :position_type, type: String, desc: 'Type of the position reference', values: %w(text image)
+ optional :new_path, type: String, desc: 'File path after change'
+ optional :new_line, type: Integer, desc: 'Line number after change'
+ optional :old_path, type: String, desc: 'File path before change'
+ optional :old_line, type: Integer, desc: 'Line number before change'
+ optional :width, type: Integer, desc: 'Width of the image'
+ optional :height, type: Integer, desc: 'Height of the image'
+ optional :x, type: Integer, desc: 'X coordinate in the image'
+ optional :y, type: Integer, desc: 'Y coordinate in the image'
+
+ if noteable_type == MergeRequest
+ optional :line_range, type: Hash, desc: 'Multi-line start and end' do
+ optional :start, type: Hash do
+ optional :line_code, type: String, desc: 'Start line code for multi-line note'
+ optional :type, type: String, desc: 'Start line type for multi-line note'
+ optional :old_line, type: String, desc: 'Start old_line line number'
+ optional :new_line, type: String, desc: 'Start new_line line number'
+ end
+ optional :end, type: Hash do
+ optional :line_code, type: String, desc: 'End line code for multi-line note'
+ optional :type, type: String, desc: 'End line type for multi-line note'
+ optional :old_line, type: String, desc: 'End old_line line number'
+ optional :new_line, type: String, desc: 'End new_line line number'
+ end
+ end
end
end
end
@@ -122,12 +129,12 @@ module API
end
end
- desc "Get comments in a single #{noteable_type.to_s.downcase} discussion" do
+ desc "Get comments in a single #{notable_name} discussion" do
success Entities::Discussion
end
params do
requires :discussion_id, type: String, desc: 'The ID of a discussion'
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
end
get ":id/#{noteables_path}/:noteable_id/discussions/:discussion_id/notes", feature_category: feature_category do
noteable = find_noteable(noteable_type, params[:noteable_id])
@@ -140,11 +147,11 @@ module API
present notes, with: Entities::Note
end
- desc "Add a comment to a #{noteable_type.to_s.downcase} discussion" do
+ desc "Add a comment to a #{notable_name} discussion" do
success Entities::Note
end
params do
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
requires :discussion_id, type: String, desc: 'The ID of a discussion'
requires :body, type: String, desc: 'The content of a note'
optional :created_at, type: String, desc: 'The creation date of the note'
@@ -175,11 +182,11 @@ module API
end
end
- desc "Get a comment in a #{noteable_type.to_s.downcase} discussion" do
+ desc "Get a comment in a #{notable_name} discussion" do
success Entities::Note
end
params do
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
requires :discussion_id, type: String, desc: 'The ID of a discussion'
requires :note_id, type: Integer, desc: 'The ID of a note'
end
@@ -189,11 +196,11 @@ module API
get_note(noteable, params[:note_id])
end
- desc "Edit a comment in a #{noteable_type.to_s.downcase} discussion" do
+ desc "Edit a comment in a #{notable_name} discussion" do
success Entities::Note
end
params do
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
requires :discussion_id, type: String, desc: 'The ID of a discussion'
requires :note_id, type: Integer, desc: 'The ID of a note'
optional :body, type: String, desc: 'The content of a note'
@@ -210,11 +217,11 @@ module API
end
end
- desc "Delete a comment in a #{noteable_type.to_s.downcase} discussion" do
+ desc "Delete a comment in a #{notable_name} discussion" do
success Entities::Note
end
params do
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
requires :discussion_id, type: String, desc: 'The ID of a discussion'
requires :note_id, type: Integer, desc: 'The ID of a note'
end
@@ -225,11 +232,11 @@ module API
end
if Noteable.resolvable_types.include?(noteable_type.to_s)
- desc "Resolve/unresolve an existing #{noteable_type.to_s.downcase} discussion" do
+ desc "Resolve/unresolve an existing #{notable_name} discussion" do
success Entities::Discussion
end
params do
- requires :noteable_id, types: [Integer, String], desc: 'The ID of the noteable'
+ requires :noteable_id, type: notable_id_type, desc: "The ID of the #{notable_name}"
requires :discussion_id, type: String, desc: 'The ID of a discussion'
requires :resolved, type: Boolean, desc: 'Mark discussion resolved/unresolved'
end
diff --git a/lib/api/entities/application.rb b/lib/api/entities/application.rb
index 33514200424..c3d8f9667c3 100644
--- a/lib/api/entities/application.rb
+++ b/lib/api/entities/application.rb
@@ -4,10 +4,12 @@ module API
module Entities
class Application < Grape::Entity
expose :id
- expose :uid, as: :application_id
- expose :name, as: :application_name
- expose :redirect_uri, as: :callback_url
- expose :confidential
+ expose :uid, as: :application_id,
+ documentation: { type: 'string',
+ example: '5832fc6e14300a0d962240a8144466eef4ee93ef0d218477e55f11cf12fc3737' }
+ expose :name, as: :application_name, documentation: { type: 'string', example: 'MyApplication' }
+ expose :redirect_uri, as: :callback_url, documentation: { type: 'string', example: 'https://redirect.uri' }
+ expose :confidential, documentation: { type: 'boolean', example: true }
end
end
end
diff --git a/lib/api/entities/application_statistics.rb b/lib/api/entities/application_statistics.rb
index 4bcba1da464..7e75ef23675 100644
--- a/lib/api/entities/application_statistics.rb
+++ b/lib/api/entities/application_statistics.rb
@@ -6,47 +6,57 @@ module API
include ActionView::Helpers::NumberHelper
include CountHelper
- expose :forks do |counts|
+ expose :forks,
+ documentation: { type: 'integer', example: 6, desc: 'Approximate number of repo forks' } do |counts|
approximate_fork_count_with_delimiters(counts)
end
- expose :issues do |counts|
+ expose :issues,
+ documentation: { type: 'integer', example: 121, desc: 'Approximate number of issues' } do |counts|
approximate_count_with_delimiters(counts, ::Issue)
end
- expose :merge_requests do |counts|
+ expose :merge_requests,
+ documentation: { type: 'integer', example: 49, desc: 'Approximate number of merge requests' } do |counts|
approximate_count_with_delimiters(counts, ::MergeRequest)
end
- expose :notes do |counts|
+ expose :notes,
+ documentation: { type: 'integer', example: 6, desc: 'Approximate number of notes' } do |counts|
approximate_count_with_delimiters(counts, ::Note)
end
- expose :snippets do |counts|
+ expose :snippets,
+ documentation: { type: 'integer', example: 4, desc: 'Approximate number of snippets' } do |counts|
approximate_count_with_delimiters(counts, ::Snippet)
end
- expose :ssh_keys do |counts|
+ expose :ssh_keys,
+ documentation: { type: 'integer', example: 11, desc: 'Approximate number of SSH keys' } do |counts|
approximate_count_with_delimiters(counts, ::Key)
end
- expose :milestones do |counts|
+ expose :milestones,
+ documentation: { type: 'integer', example: 3, desc: 'Approximate number of milestones' } do |counts|
approximate_count_with_delimiters(counts, ::Milestone)
end
- expose :users do |counts|
+ expose :users, documentation: { type: 'integer', example: 22, desc: 'Approximate number of users' } do |counts|
approximate_count_with_delimiters(counts, ::User)
end
- expose :projects do |counts|
+ expose :projects,
+ documentation: { type: 'integer', example: 4, desc: 'Approximate number of projects' } do |counts|
approximate_count_with_delimiters(counts, ::Project)
end
- expose :groups do |counts|
+ expose :groups,
+ documentation: { type: 'integer', example: 1, desc: 'Approximate number of projects' } do |counts|
approximate_count_with_delimiters(counts, ::Group)
end
- expose :active_users do |_|
+ expose :active_users,
+ documentation: { type: 'integer', example: 21, desc: 'Number of active users' } do |_|
number_with_delimiter(::User.active.count)
end
end
diff --git a/lib/api/entities/application_with_secret.rb b/lib/api/entities/application_with_secret.rb
index 3e540381d89..1d0acee8624 100644
--- a/lib/api/entities/application_with_secret.rb
+++ b/lib/api/entities/application_with_secret.rb
@@ -4,7 +4,8 @@ module API
module Entities
# Use with care, this exposes the secret
class ApplicationWithSecret < Entities::Application
- expose :secret
+ expose :secret, documentation: { type: 'string',
+ example: 'ee1dd64b6adc89cf7e2c23099301ccc2c61b441064e9324d963c46902a85ec34' }
end
end
end
diff --git a/lib/api/entities/basic_project_details.rb b/lib/api/entities/basic_project_details.rb
index e96504db53e..2585b2d0b6d 100644
--- a/lib/api/entities/basic_project_details.rb
+++ b/lib/api/entities/basic_project_details.rb
@@ -6,15 +6,18 @@ module API
include ::API::ProjectsRelationBuilder
include Gitlab::Utils::StrongMemoize
- expose :default_branch_or_main, as: :default_branch, if: -> (project, options) { Ability.allowed?(options[:current_user], :download_code, project) }
+ expose :default_branch_or_main, documentation: { type: 'string', example: 'main' }, as: :default_branch, if: -> (project, options) { Ability.allowed?(options[:current_user], :read_code, project) }
# Avoids an N+1 query: https://github.com/mbleigh/acts-as-taggable-on/issues/91#issuecomment-168273770
- expose :topic_names, as: :tag_list
- expose :topic_names, as: :topics
+ expose :topic_names, as: :tag_list, documentation: { type: 'string', is_array: true, example: 'tag' }
+ expose :topic_names, as: :topics, documentation: { type: 'string', is_array: true, example: 'topic' }
- expose :ssh_url_to_repo, :http_url_to_repo, :web_url, :readme_url
+ expose :ssh_url_to_repo, documentation: { type: 'string', example: 'git@gitlab.example.com:gitlab/gitlab.git' }
+ expose :http_url_to_repo, documentation: { type: 'string', example: 'https://gitlab.example.com/gitlab/gitlab.git' }
+ expose :web_url, documentation: { type: 'string', example: 'https://gitlab.example.com/gitlab/gitlab' }
+ expose :readme_url, documentation: { type: 'string', example: 'https://gitlab.example.com/gitlab/gitlab/blob/master/README.md' }
- expose :license_url, if: :license do |project|
+ expose :license_url, if: :license, documentation: { type: 'string', example: 'https://gitlab.example.com/gitlab/gitlab/blob/master/LICENCE' } do |project|
license = project.repository.license_blob
if license
@@ -26,13 +29,13 @@ module API
project.repository.license
end
- expose :avatar_url do |project, options|
+ expose :avatar_url, documentation: { type: 'string', example: 'http://example.com/uploads/project/avatar/3/uploads/avatar.png' } do |project, options|
project.avatar_url(only_path: false)
end
- expose :forks_count
- expose :star_count
- expose :last_activity_at
+ expose :forks_count, documentation: { type: 'integer', example: 1 }
+ expose :star_count, documentation: { type: 'integer', example: 1 }
+ expose :last_activity_at, documentation: { type: 'dateTime', example: '2013-09-30T13:46:02Z' }
expose :namespace, using: 'API::Entities::NamespaceBasic'
expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes
@@ -57,6 +60,8 @@ module API
super
end
+ def self.postload_relation(projects_relation, options = {}) end
+
private
alias_method :project, :object
diff --git a/lib/api/entities/basic_ref.rb b/lib/api/entities/basic_ref.rb
index 79c15075d99..1b821a5b0ec 100644
--- a/lib/api/entities/basic_ref.rb
+++ b/lib/api/entities/basic_ref.rb
@@ -3,7 +3,8 @@
module API
module Entities
class BasicRef < Grape::Entity
- expose :type, :name
+ expose :type, documentation: { type: 'string', example: 'tag' }
+ expose :name, documentation: { type: 'string', example: 'v1.1.0' }
end
end
end
diff --git a/lib/api/entities/basic_release_details.rb b/lib/api/entities/basic_release_details.rb
index d13080f32f4..dba19b3abd7 100644
--- a/lib/api/entities/basic_release_details.rb
+++ b/lib/api/entities/basic_release_details.rb
@@ -5,12 +5,12 @@ module API
class BasicReleaseDetails < Grape::Entity
include ::API::Helpers::Presentable
- expose :name
- expose :tag, as: :tag_name
- expose :description
- expose :created_at
- expose :released_at
- expose :upcoming_release?, as: :upcoming_release
+ expose :name, documentation: { type: 'string', example: 'Release v1.0' }
+ expose :tag, documentation: { type: 'string', example: 'v1.0' }, as: :tag_name
+ expose :description, documentation: { type: 'string', example: 'Finally released v1.0' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2019-01-03T01:56:19.539Z' }
+ expose :released_at, documentation: { type: 'dateTime', example: '2019-01-03T01:56:19.539Z' }
+ expose :upcoming_release?, documentation: { type: 'boolean' }, as: :upcoming_release
end
end
end
diff --git a/lib/api/entities/basic_repository_storage_move.rb b/lib/api/entities/basic_repository_storage_move.rb
index 3ee112fb9a2..83b4f428a56 100644
--- a/lib/api/entities/basic_repository_storage_move.rb
+++ b/lib/api/entities/basic_repository_storage_move.rb
@@ -3,11 +3,11 @@
module API
module Entities
class BasicRepositoryStorageMove < Grape::Entity
- expose :id
- expose :created_at
- expose :human_state_name, as: :state
- expose :source_storage_name
- expose :destination_storage_name
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :created_at, documentation: { type: 'dateTime', example: '2020-05-07T04:27:17.234Z' }
+ expose :human_state_name, as: :state, documentation: { type: 'string', example: 'scheduled' }
+ expose :source_storage_name, documentation: { type: 'string', example: 'default' }
+ expose :destination_storage_name, documentation: { type: 'string', example: 'storage1' }
end
end
end
diff --git a/lib/api/entities/basic_snippet.rb b/lib/api/entities/basic_snippet.rb
index 26297514798..0e9977fd81b 100644
--- a/lib/api/entities/basic_snippet.rb
+++ b/lib/api/entities/basic_snippet.rb
@@ -3,16 +3,30 @@
module API
module Entities
class BasicSnippet < Grape::Entity
- expose :id, :title, :description, :visibility
- expose :updated_at, :created_at
- expose :project_id
- expose :web_url do |snippet|
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :title, documentation: { type: 'string', example: 'test' }
+ expose :description, documentation: { type: 'string', example: 'Ruby test snippet' }
+ expose :visibility, documentation: { type: 'string', example: 'public' }
+ expose :author, using: Entities::UserBasic, documentation: { type: 'Entities::UserBasic' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2012-06-28T10:52:04Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2012-06-28T10:52:04Z' }
+ expose :project_id, documentation: { type: 'integer', example: 1 }
+ expose :web_url, documentation: {
+ type: 'string', example: 'http://example.com/example/example/snippets/1'
+ } do |snippet|
Gitlab::UrlBuilder.build(snippet)
end
- expose :raw_url do |snippet|
+ expose :raw_url, documentation: {
+ type: 'string', example: 'http://example.com/example/example/snippets/1/raw'
+ } do |snippet|
Gitlab::UrlBuilder.build(snippet, raw: true)
end
- expose :ssh_url_to_repo, :http_url_to_repo, if: ->(snippet) { snippet.repository_exists? }
+ expose :ssh_url_to_repo, documentation: {
+ type: 'string', example: 'ssh://user@gitlab.example.com/snippets/65.git'
+ }, if: ->(snippet) { snippet.repository_exists? }
+ expose :http_url_to_repo, documentation: {
+ type: 'string', example: 'https://gitlab.example.com/snippets/65.git'
+ }, if: ->(snippet) { snippet.repository_exists? }
end
end
end
diff --git a/lib/api/entities/branch.rb b/lib/api/entities/branch.rb
index 6a75dcddeda..01eaf5c8d31 100644
--- a/lib/api/entities/branch.rb
+++ b/lib/api/entities/branch.rb
@@ -5,13 +5,17 @@ module API
class Branch < Grape::Entity
include Gitlab::Routing
- expose :name
+ expose :name, documentation: { type: 'string', example: 'master' }
expose :commit, using: Entities::Commit do |repo_branch, options|
options[:project].repository.commit(repo_branch.dereferenced_target)
end
- expose :merged do |repo_branch, options|
+ expose :merged,
+ documentation: {
+ type: 'boolean',
+ example: true
+ } do |repo_branch, options|
if options[:merged_branch_names]
options[:merged_branch_names].include?(repo_branch.name)
else
@@ -19,27 +23,51 @@ module API
end
end
- expose :protected do |repo_branch, options|
+ expose :protected,
+ documentation: {
+ type: 'boolean',
+ example: true
+ } do |repo_branch, options|
::ProtectedBranch.protected?(options[:project], repo_branch.name)
end
- expose :developers_can_push do |repo_branch, options|
+ expose :developers_can_push,
+ documentation: {
+ type: 'boolean',
+ example: true
+ } do |repo_branch, options|
::ProtectedBranch.developers_can?(:push, repo_branch.name, protected_refs: options[:project].protected_branches)
end
- expose :developers_can_merge do |repo_branch, options|
+ expose :developers_can_merge,
+ documentation: {
+ type: 'boolean',
+ example: true
+ } do |repo_branch, options|
::ProtectedBranch.developers_can?(:merge, repo_branch.name, protected_refs: options[:project].protected_branches)
end
- expose :can_push do |repo_branch, options|
+ expose :can_push,
+ documentation: {
+ type: 'boolean',
+ example: true
+ } do |repo_branch, options|
Gitlab::UserAccess.new(options[:current_user], container: options[:project]).can_push_to_branch?(repo_branch.name)
end
- expose :default do |repo_branch, options|
+ expose :default,
+ documentation: {
+ type: 'boolean',
+ example: true
+ } do |repo_branch, options|
options[:project].default_branch == repo_branch.name
end
- expose :web_url do |repo_branch|
+ expose :web_url,
+ documentation: {
+ type: 'string',
+ example: 'https://gitlab.example.com/Commit921/the-dude/-/tree/master'
+ } do |repo_branch|
project_tree_url(options[:project], repo_branch.name)
end
end
diff --git a/lib/api/entities/bulk_import.rb b/lib/api/entities/bulk_import.rb
index 373ae486dcf..75989cb4180 100644
--- a/lib/api/entities/bulk_import.rb
+++ b/lib/api/entities/bulk_import.rb
@@ -3,11 +3,13 @@
module API
module Entities
class BulkImport < Grape::Entity
- expose :id
- expose :status_name, as: :status
- expose :source_type
- expose :created_at
- expose :updated_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :status_name, as: :status, documentation: {
+ type: 'string', example: 'finished', values: %w[created started finished timeout failed]
+ }
+ expose :source_type, documentation: { type: 'string', example: 'gitlab' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
end
end
end
diff --git a/lib/api/entities/bulk_imports/entity.rb b/lib/api/entities/bulk_imports/entity.rb
index 142bfaf2149..8f9fbe57935 100644
--- a/lib/api/entities/bulk_imports/entity.rb
+++ b/lib/api/entities/bulk_imports/entity.rb
@@ -4,19 +4,21 @@ module API
module Entities
module BulkImports
class Entity < Grape::Entity
- expose :id
- expose :bulk_import_id
- expose :status_name, as: :status
- expose :source_full_path
- expose :destination_name # deprecated
- expose :destination_slug
- expose :destination_namespace
- expose :parent_id
- expose :namespace_id
- expose :project_id
- expose :created_at
- expose :updated_at
- expose :failures, using: EntityFailure
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :bulk_import_id, documentation: { type: 'integer', example: 1 }
+ expose :status_name, as: :status, documentation: {
+ type: 'string', example: 'created', values: %w[created started finished timeout failed]
+ }
+ expose :source_full_path, documentation: { type: 'string', example: 'source_group' }
+ expose :destination_name, documentation: { type: 'string', example: 'destination_slug' } # deprecated
+ expose :destination_slug, documentation: { type: 'string', example: 'destination_slug' }
+ expose :destination_namespace, documentation: { type: 'string', example: 'destination_path' }
+ expose :parent_id, documentation: { type: 'integer', example: 1 }
+ expose :namespace_id, documentation: { type: 'integer', example: 1 }
+ expose :project_id, documentation: { type: 'integer', example: 1 }
+ expose :created_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :failures, using: EntityFailure, documentation: { is_array: true }
end
end
end
diff --git a/lib/api/entities/bulk_imports/entity_failure.rb b/lib/api/entities/bulk_imports/entity_failure.rb
index 56312745868..3e69e7fa2aa 100644
--- a/lib/api/entities/bulk_imports/entity_failure.rb
+++ b/lib/api/entities/bulk_imports/entity_failure.rb
@@ -4,16 +4,18 @@ module API
module Entities
module BulkImports
class EntityFailure < Grape::Entity
- expose :relation
- expose :pipeline_step, as: :step
- expose :exception_message do |failure|
+ expose :relation, documentation: { type: 'string', example: 'group' }
+ expose :pipeline_step, as: :step, documentation: { type: 'string', example: 'extractor' }
+ expose :exception_message, documentation: { type: 'string', example: 'error message' } do |failure|
::Projects::ImportErrorFilter.filter_message(failure.exception_message.truncate(72))
end
- expose :exception_class
- expose :correlation_id_value
- expose :created_at
- expose :pipeline_class
- expose :pipeline_step
+ expose :exception_class, documentation: { type: 'string', example: 'Exception' }
+ expose :correlation_id_value, documentation: { type: 'string', example: 'dfcf583058ed4508e4c7c617bd7f0edd' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :pipeline_class, documentation: {
+ type: 'string', example: 'BulkImports::Groups::Pipelines::GroupPipeline'
+ }
+ expose :pipeline_step, documentation: { type: 'string', example: 'extractor' }
end
end
end
diff --git a/lib/api/entities/bulk_imports/export_status.rb b/lib/api/entities/bulk_imports/export_status.rb
index c9c7f34a16a..fee983c6fd8 100644
--- a/lib/api/entities/bulk_imports/export_status.rb
+++ b/lib/api/entities/bulk_imports/export_status.rb
@@ -4,10 +4,10 @@ module API
module Entities
module BulkImports
class ExportStatus < Grape::Entity
- expose :relation
- expose :status
- expose :error
- expose :updated_at
+ expose :relation, documentation: { type: 'string', example: 'issues' }
+ expose :status, documentation: { type: 'string', example: 'started', values: %w[started finished failed] }
+ expose :error, documentation: { type: 'string', example: 'Error message' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
end
end
end
diff --git a/lib/api/entities/ci/job.rb b/lib/api/entities/ci/job.rb
index cf87684ce55..d9e6b7eed75 100644
--- a/lib/api/entities/ci/job.rb
+++ b/lib/api/entities/ci/job.rb
@@ -6,10 +6,17 @@ module API
class Job < JobBasic
# artifacts_file is included in job_artifacts, but kept for backward compatibility (remove in api/v5)
expose :artifacts_file, using: ::API::Entities::Ci::JobArtifactFile, if: -> (job, opts) { job.artifacts? }
- expose :job_artifacts, as: :artifacts, using: ::API::Entities::Ci::JobArtifact
+ expose :job_artifacts, as: :artifacts,
+ using: ::API::Entities::Ci::JobArtifact,
+ documentation: { is_array: true }
expose :runner, with: ::API::Entities::Ci::Runner
- expose :artifacts_expire_at
- expose :tag_list do |job|
+ expose :artifacts_expire_at,
+ documentation: { type: 'dateTime', example: '2016-01-19T09:05:50.355Z' }
+
+ expose(
+ :tag_list,
+ documentation: { type: 'string', is_array: true, example: ['ubuntu18', 'docker runner'] }
+ ) do |job|
job.tags.map(&:name).sort
end
end
diff --git a/lib/api/entities/ci/job_artifact.rb b/lib/api/entities/ci/job_artifact.rb
index 9e504aee383..8276c0f4073 100644
--- a/lib/api/entities/ci/job_artifact.rb
+++ b/lib/api/entities/ci/job_artifact.rb
@@ -4,7 +4,12 @@ module API
module Entities
module Ci
class JobArtifact < Grape::Entity
- expose :file_type, :size, :filename, :file_format
+ expose :file_type,
+ documentation: { type: 'string', values: ::Ci::JobArtifact.file_types.keys, example: 'archive' }
+ expose :size, documentation: { type: 'integer', example: 1000 }
+ expose :filename, documentation: { type: 'string', example: 'artifacts.zip' }
+ expose :file_format,
+ documentation: { type: 'string', values: ::Ci::JobArtifact.file_formats.keys, example: 'zip' }
end
end
end
diff --git a/lib/api/entities/ci/job_artifact_file.rb b/lib/api/entities/ci/job_artifact_file.rb
index 418eb408ab6..0266f99cd6d 100644
--- a/lib/api/entities/ci/job_artifact_file.rb
+++ b/lib/api/entities/ci/job_artifact_file.rb
@@ -4,8 +4,8 @@ module API
module Entities
module Ci
class JobArtifactFile < Grape::Entity
- expose :filename
- expose :cached_size, as: :size
+ expose :filename, documentation: { type: 'string', example: 'artifacts.zip' }
+ expose :cached_size, as: :size, documentation: { type: 'integer', example: 1000 }
end
end
end
diff --git a/lib/api/entities/ci/job_basic.rb b/lib/api/entities/ci/job_basic.rb
index fb975475cf5..3cbb8aad313 100644
--- a/lib/api/entities/ci/job_basic.rb
+++ b/lib/api/entities/ci/job_basic.rb
@@ -4,23 +4,36 @@ module API
module Entities
module Ci
class JobBasic < Grape::Entity
- expose :id, :status, :stage, :name, :ref, :tag, :coverage, :allow_failure
- expose :created_at, :started_at, :finished_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :status, documentation: { type: 'string', example: 'waiting_for_resource' }
+ expose :stage, documentation: { type: 'string', example: 'deploy' }
+ expose :name, documentation: { type: 'string', example: 'deploy_to_production' }
+ expose :ref, documentation: { type: 'string', example: 'main' }
+ expose :tag, documentation: { type: 'boolean' }
+ expose :coverage, documentation: { type: 'number', format: 'float', example: 98.29 }
+ expose :allow_failure, documentation: { type: 'boolean' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2015-12-24T15:51:21.880Z' }
+ expose :started_at, documentation: { type: 'dateTime', example: '2015-12-24T17:54:30.733Z' }
+ expose :finished_at, documentation: { type: 'dateTime', example: '2015-12-24T17:54:31.198Z' }
expose :duration,
- documentation: { type: 'Floating', desc: 'Time spent running' }
+ documentation: { type: 'number', format: 'float', desc: 'Time spent running', example: 0.465 }
expose :queued_duration,
- documentation: { type: 'Floating', desc: 'Time spent enqueued' }
+ documentation: { type: 'number', format: 'float', desc: 'Time spent enqueued', example: 0.123 }
expose :user, with: ::API::Entities::User
expose :commit, with: ::API::Entities::Commit
expose :pipeline, with: ::API::Entities::Ci::PipelineBasic
- expose :failure_reason, if: -> (job) { job.failed? }
+ expose :failure_reason,
+ documentation: { type: 'string', example: 'script_failure' }, if: -> (job) { job.failed? }
- expose :web_url do |job, _options|
+ expose(
+ :web_url,
+ documentation: { type: 'string', example: 'https://example.com/foo/bar/-/jobs/1' }
+ ) do |job, _options|
Gitlab::Routing.url_helpers.project_job_url(job.project, job)
end
expose :project do
- expose :ci_job_token_scope_enabled do |job|
+ expose :ci_job_token_scope_enabled, documentation: { type: 'string', example: false } do |job|
job.project.ci_outbound_job_token_scope_enabled?
end
end
diff --git a/lib/api/entities/ci/lint/result.rb b/lib/api/entities/ci/lint/result.rb
index b44a6e13463..698b02d3b4a 100644
--- a/lib/api/entities/ci/lint/result.rb
+++ b/lib/api/entities/ci/lint/result.rb
@@ -5,12 +5,17 @@ module API
module Ci
module Lint
class Result < Grape::Entity
- expose :valid?, as: :valid
- expose :errors
- expose :warnings
- expose :merged_yaml
- expose :includes
- expose :jobs, if: -> (result, options) { options[:include_jobs] }
+ expose :valid?, as: :valid, documentation: { type: 'boolean' }
+ expose :errors, documentation: { is_array: true, type: 'string',
+ example: 'variables config should be a hash of key value pairs' }
+ expose :warnings, documentation: { is_array: true, type: 'string',
+ example: 'jobs:job may allow multiple pipelines ...' }
+ expose :merged_yaml, documentation: { type: 'string', example: '---\n:another_test:\n :stage: test\n
+ :script: echo 2\n:test:\n :stage: test\n :script: echo 1\n' }
+ expose :includes, documentation: { is_array: true, type: 'object',
+ example: '{ "blob": "https://gitlab.com/root/example-project/-/blob/...' }
+ expose :jobs, if: -> (result, options) { options[:include_jobs] },
+ documentation: { is_array: true, type: 'object', example: '{ "name": "test: .... }' }
end
end
end
diff --git a/lib/api/entities/ci/pipeline.rb b/lib/api/entities/ci/pipeline.rb
index a8033a21044..7631cf60dbd 100644
--- a/lib/api/entities/ci/pipeline.rb
+++ b/lib/api/entities/ci/pipeline.rb
@@ -4,13 +4,21 @@ module API
module Entities
module Ci
class Pipeline < PipelineBasic
- expose :before_sha, :tag, :yaml_errors
+ expose :before_sha, documentation: { type: 'string', example: 'a91957a858320c0e17f3a0eca7cfacbff50ea29a' }
+ expose :tag, documentation: { type: 'boolean', example: false }
+ expose :yaml_errors, documentation: { type: 'string', example: "widgets:build: needs 'widgets:test'" }
expose :user, with: Entities::UserBasic
- expose :created_at, :updated_at, :started_at, :finished_at, :committed_at
- expose :duration
- expose :queued_duration
- expose :coverage do |pipeline|
+ expose :created_at, documentation: { type: 'dateTime', example: '2015-12-24T15:51:21.880Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2015-12-24T17:54:31.198Z' }
+ expose :started_at, documentation: { type: 'dateTime', example: '2015-12-24T17:54:30.733Z' }
+ expose :finished_at, documentation: { type: 'dateTime', example: '2015-12-24T17:54:31.198Z' }
+ expose :committed_at, documentation: { type: 'dateTime', example: '2015-12-24T15:51:21.880Z' }
+ expose :duration,
+ documentation: { type: 'integer', desc: 'Time spent running in seconds', example: 127 }
+ expose :queued_duration,
+ documentation: { type: 'integer', desc: 'Time spent enqueued in seconds', example: 63 }
+ expose :coverage, documentation: { type: 'number', format: 'float', example: 98.29 } do |pipeline|
pipeline.present.coverage
end
expose :detailed_status, using: DetailedStatusEntity do |pipeline, options|
diff --git a/lib/api/entities/ci/pipeline_basic.rb b/lib/api/entities/ci/pipeline_basic.rb
index a2a5a98920a..6d82cca1bf1 100644
--- a/lib/api/entities/ci/pipeline_basic.rb
+++ b/lib/api/entities/ci/pipeline_basic.rb
@@ -4,10 +4,21 @@ module API
module Entities
module Ci
class PipelineBasic < Grape::Entity
- expose :id, :iid, :project_id, :sha, :ref, :status, :source
- expose :created_at, :updated_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :iid, documentation: { type: 'integer', example: 2 }
+ expose :project_id, documentation: { type: 'integer', example: 3 }
+ expose :sha, documentation: { type: 'string', example: '0ec9e58fdfca6cdd6652c083c9edb53abc0bad52' }
+ expose :ref, documentation: { type: 'string', example: 'feature-branch' }
+ expose :status, documentation: { type: 'string', example: 'success' }
+ expose :source, documentation: { type: 'string', example: 'push' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2022-10-21T16:49:48.000+02:00' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2022-10-21T16:49:48.000+02:00' }
- expose :web_url do |pipeline, _options|
+ expose :web_url,
+ documentation: {
+ type: 'string',
+ example: 'https://gitlab.example.com/gitlab-org/gitlab-foss/-/pipelines/61'
+ } do |pipeline, _options|
Gitlab::Routing.url_helpers.project_pipeline_url(pipeline.project, pipeline)
end
end
diff --git a/lib/api/entities/ci/pipeline_schedule.rb b/lib/api/entities/ci/pipeline_schedule.rb
index f1596b7d285..58496bded03 100644
--- a/lib/api/entities/ci/pipeline_schedule.rb
+++ b/lib/api/entities/ci/pipeline_schedule.rb
@@ -4,9 +4,15 @@ module API
module Entities
module Ci
class PipelineSchedule < Grape::Entity
- expose :id
- expose :description, :ref, :cron, :cron_timezone, :next_run_at, :active
- expose :created_at, :updated_at
+ expose :id, documentation: { type: 'integer', example: 13 }
+ expose :description, documentation: { type: 'string', example: 'Test schedule pipeline' }
+ expose :ref, documentation: { type: 'string', example: 'develop' }
+ expose :cron, documentation: { type: 'string', example: '* * * * *' }
+ expose :cron_timezone, documentation: { type: 'string', example: 'Asia/Tokyo' }
+ expose :next_run_at, documentation: { type: 'dateTime', example: '2017-05-19T13:41:00.000Z' }
+ expose :active, documentation: { type: 'boolean', example: true }
+ expose :created_at, documentation: { type: 'dateTime', example: '2017-05-19T13:31:08.849Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2017-05-19T13:40:17.727Z' }
expose :owner, using: ::API::Entities::UserBasic
end
end
diff --git a/lib/api/entities/ci/resource_group.rb b/lib/api/entities/ci/resource_group.rb
index 0afadfa9e2a..c14e32d32b1 100644
--- a/lib/api/entities/ci/resource_group.rb
+++ b/lib/api/entities/ci/resource_group.rb
@@ -4,7 +4,11 @@ module API
module Entities
module Ci
class ResourceGroup < Grape::Entity
- expose :id, :key, :process_mode, :created_at, :updated_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :key, documentation: { type: 'string', example: 'production' }
+ expose :process_mode, documentation: { type: 'string', example: 'unordered' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2021-09-01T08:04:59.650Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2021-09-01T08:04:59.650Z' }
end
end
end
diff --git a/lib/api/entities/ci/runner.rb b/lib/api/entities/ci/runner.rb
index f034eb5c94c..9361709b6ed 100644
--- a/lib/api/entities/ci/runner.rb
+++ b/lib/api/entities/ci/runner.rb
@@ -4,20 +4,22 @@ module API
module Entities
module Ci
class Runner < Grape::Entity
- expose :id
- expose :description
- expose :ip_address
- expose :active # TODO Remove in v5 in favor of `paused` for REST calls, see https://gitlab.com/gitlab-org/gitlab/-/issues/375709
- expose :paused do |runner|
+ expose :id, documentation: { type: 'integer', example: 8 }
+ expose :description, documentation: { type: 'string', example: 'test-1-20150125' }
+ expose :ip_address, documentation: { type: 'string', example: '127.0.0.1' }
+ # TODO Remove in v5 in favor of `paused` for REST calls, see https://gitlab.com/gitlab-org/gitlab/-/issues/375709
+ expose :active, documentation: { type: 'boolean', example: true }
+ expose :paused, documentation: { type: 'boolean', example: false } do |runner|
!runner.active
end
- expose :instance_type?, as: :is_shared
- expose :runner_type
- expose :name
- expose :online?, as: :online
+ expose :instance_type?, as: :is_shared, documentation: { type: 'boolean', example: true }
+ expose :runner_type,
+ documentation: { type: 'string', values: ::Ci::Runner.runner_types.keys, example: 'instance_type' }
+ expose :name, documentation: { type: 'string', example: 'test' }
+ expose :online?, as: :online, documentation: { type: 'boolean', example: true }
# DEPRECATED
# TODO Remove in v5 in favor of `status` for REST calls, see https://gitlab.com/gitlab-org/gitlab/-/issues/375709
- expose :deprecated_rest_status, as: :status
+ expose :deprecated_rest_status, as: :status, documentation: { type: 'string', example: 'online' }
end
end
end
diff --git a/lib/api/entities/ci/secure_file.rb b/lib/api/entities/ci/secure_file.rb
index 639615e5779..d957e4488fd 100644
--- a/lib/api/entities/ci/secure_file.rb
+++ b/lib/api/entities/ci/secure_file.rb
@@ -9,6 +9,8 @@ module API
expose :checksum
expose :checksum_algorithm
expose :created_at
+ expose :expires_at
+ expose :metadata
end
end
end
diff --git a/lib/api/entities/ci/variable.rb b/lib/api/entities/ci/variable.rb
index f4d5248245a..47597cb77be 100644
--- a/lib/api/entities/ci/variable.rb
+++ b/lib/api/entities/ci/variable.rb
@@ -4,10 +4,16 @@ module API
module Entities
module Ci
class Variable < Grape::Entity
- expose :variable_type, :key, :value
- expose :protected?, as: :protected, if: -> (entity, _) { entity.respond_to?(:protected?) }
- expose :masked?, as: :masked, if: -> (entity, _) { entity.respond_to?(:masked?) }
- expose :environment_scope, if: -> (entity, _) { entity.respond_to?(:environment_scope) }
+ expose :variable_type, documentation: { type: 'string', example: 'env_var' }
+ expose :key, documentation: { type: 'string', example: 'TEST_VARIABLE_1' }
+ expose :value, documentation: { type: 'string', example: 'TEST_1' }
+ expose :protected?, as: :protected, if: -> (entity, _) { entity.respond_to?(:protected?) },
+ documentation: { type: 'boolean' }
+ expose :masked?, as: :masked, if: -> (entity, _) { entity.respond_to?(:masked?) },
+ documentation: { type: 'boolean' }
+ expose :raw?, as: :raw, if: -> (entity, _) { entity.respond_to?(:raw?) }, documentation: { type: 'boolean' }
+ expose :environment_scope, if: -> (entity, _) { entity.respond_to?(:environment_scope) },
+ documentation: { type: 'string', example: '*' }
end
end
end
diff --git a/lib/api/entities/commit.rb b/lib/api/entities/commit.rb
index 6cd180cd584..ab1f51289d7 100644
--- a/lib/api/entities/commit.rb
+++ b/lib/api/entities/commit.rb
@@ -3,15 +3,26 @@
module API
module Entities
class Commit < Grape::Entity
- expose :id, :short_id, :created_at
- expose :parent_ids
- expose :full_title, as: :title
- expose :safe_message, as: :message
- expose :author_name, :author_email, :authored_date
- expose :committer_name, :committer_email, :committed_date
- expose :trailers
+ expose :id, documentation: { type: 'string', example: '2695effb5807a22ff3d138d593fd856244e155e7' }
+ expose :short_id, documentation: { type: 'string', example: '2695effb' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2017-07-26T11:08:53.000+02:00' }
+ expose :parent_ids,
+ documentation: { type: 'string', is_array: true, example: '2a4b78934375d7f53875269ffd4f45fd83a84ebe' }
+ expose :full_title, as: :title, documentation: { type: 'string', example: 'Initial commit' }
+ expose :safe_message, as: :message, documentation: { type: 'string', example: 'Initial commit' }
+ expose :author_name, documentation: { type: 'string', example: 'John Smith' }
+ expose :author_email, documentation: { type: 'string', example: 'john@example.com' }
+ expose :authored_date, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :committer_name, documentation: { type: 'string', example: 'Jack Smith' }
+ expose :committer_email, documentation: { type: 'string', example: 'jack@example.com' }
+ expose :committed_date, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :trailers, documentation: { type: 'object', example: '{ "Merged-By": "Jane Doe janedoe@gitlab.com" }' }
- expose :web_url do |commit, _options|
+ expose :web_url,
+ documentation: {
+ type: 'string',
+ example: 'https://gitlab.example.com/janedoe/gitlab-foss/-/commit/ed899a2f4b50b4370feeea94676502b42383c746'
+ } do |commit, _options|
c = commit
c = c.__subject__ if c.is_a?(Gitlab::View::Presenter::Base)
Gitlab::UrlBuilder.build(c)
diff --git a/lib/api/entities/commit_detail.rb b/lib/api/entities/commit_detail.rb
index cc529639359..428c53f7fe3 100644
--- a/lib/api/entities/commit_detail.rb
+++ b/lib/api/entities/commit_detail.rb
@@ -6,10 +6,10 @@ module API
include ::API::Helpers::Presentable
expose :stats, using: Entities::CommitStats, if: :include_stats
- expose :status_for, as: :status
- expose :project_id
+ expose :status_for, as: :status, documentation: { type: 'string', example: 'success' }
+ expose :project_id, documentation: { type: 'integer', example: 1 }
- expose :last_pipeline do |commit, options|
+ expose :last_pipeline, documentation: { type: ::API::Entities::Ci::PipelineBasic.to_s } do |commit, options|
pipeline = commit.last_pipeline if can_read_pipeline?
::API::Entities::Ci::PipelineBasic.represent(pipeline, options)
end
diff --git a/lib/api/entities/commit_note.rb b/lib/api/entities/commit_note.rb
index fe91712b48d..0632dc467b8 100644
--- a/lib/api/entities/commit_note.rb
+++ b/lib/api/entities/commit_note.rb
@@ -3,12 +3,22 @@
module API
module Entities
class CommitNote < Grape::Entity
- expose :note
- expose(:path) { |note| note.diff_file.try(:file_path) if note.diff_note? }
- expose(:line) { |note| note.diff_line.try(:line) if note.diff_note? }
- expose(:line_type) { |note| note.diff_line.try(:type) if note.diff_note? }
+ expose :note, documentation: { type: 'string', example: 'this doc is really nice' }
+
+ expose :path, documentation: { type: 'string', example: 'README.md' } do |note|
+ note.diff_file.try(:file_path) if note.diff_note?
+ end
+
+ expose :line, documentation: { type: 'integer', example: 11 } do |note|
+ note.diff_line.try(:line) if note.diff_note?
+ end
+
+ expose :line_type, documentation: { type: 'string', example: 'new' } do |note|
+ note.diff_line.try(:type) if note.diff_note?
+ end
+
expose :author, using: Entities::UserBasic
- expose :created_at
+ expose :created_at, documentation: { type: 'dateTime', example: '2016-01-19T09:44:55.600Z' }
end
end
end
diff --git a/lib/api/entities/commit_signature.rb b/lib/api/entities/commit_signature.rb
index 0d8e977a9f5..9430dd5e2a2 100644
--- a/lib/api/entities/commit_signature.rb
+++ b/lib/api/entities/commit_signature.rb
@@ -3,7 +3,7 @@
module API
module Entities
class CommitSignature < Grape::Entity
- expose :signature_type
+ expose :signature_type, documentation: { type: 'string', example: 'PGP' }
expose :signature, merge: true do |commit, options|
if commit.signature.is_a?(::CommitSignatures::GpgSignature) || commit.raw_commit_from_rugged?
@@ -13,7 +13,7 @@ module API
end
end
- expose :commit_source do |commit, _|
+ expose :commit_source, documentation: { type: 'string', example: 'gitaly' } do |commit, _|
commit.raw_commit_from_rugged? ? "rugged" : "gitaly"
end
diff --git a/lib/api/entities/commit_stats.rb b/lib/api/entities/commit_stats.rb
index d9ba99c8eb0..e07483e5d97 100644
--- a/lib/api/entities/commit_stats.rb
+++ b/lib/api/entities/commit_stats.rb
@@ -3,7 +3,9 @@
module API
module Entities
class CommitStats < Grape::Entity
- expose :additions, :deletions, :total
+ expose :additions, documentation: { type: 'integer', example: 1 }
+ expose :deletions, documentation: { type: 'integer', example: 0 }
+ expose :total, documentation: { type: 'integer', example: 1 }
end
end
end
diff --git a/lib/api/entities/commit_status.rb b/lib/api/entities/commit_status.rb
index 61b8bf89cfe..df6a41895ff 100644
--- a/lib/api/entities/commit_status.rb
+++ b/lib/api/entities/commit_status.rb
@@ -3,8 +3,22 @@
module API
module Entities
class CommitStatus < Grape::Entity
- expose :id, :sha, :ref, :status, :name, :target_url, :description,
- :created_at, :started_at, :finished_at, :allow_failure, :coverage
+ expose :id, documentation: { type: 'integer', example: 93 }
+ expose :sha, documentation: { type: 'string', example: '18f3e63d05582537db6d183d9d557be09e1f90c8' }
+ expose :ref, documentation: { type: 'string', example: 'develop' }
+ expose :status, documentation: { type: 'string', example: 'success' }
+ expose :name, documentation: { type: 'string', example: 'default' }
+ expose :target_url, documentation: {
+ type: 'string',
+ example: 'https://gitlab.example.com/janedoe/gitlab-foss/builds/91'
+ }
+ expose :description, documentation: { type: 'string' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2016-01-19T09:05:50.355Z' }
+ expose :started_at, documentation: { type: 'dateTime', example: '2016-01-20T08:40:25.832Z' }
+ expose :finished_at, documentation: { type: 'dateTime', example: '2016-01-21T08:40:25.832Z' }
+ expose :allow_failure, documentation: { type: 'boolean', example: false }
+ expose :coverage, documentation: { type: 'number', format: 'float', example: 98.29 }
+
expose :author, using: Entities::UserBasic
end
end
diff --git a/lib/api/entities/compare.rb b/lib/api/entities/compare.rb
index 75a36d9bb01..92066868d3c 100644
--- a/lib/api/entities/compare.rb
+++ b/lib/api/entities/compare.rb
@@ -7,21 +7,24 @@ module API
compare.commits.last
end
- expose :commits, using: Entities::Commit do |compare, _|
+ expose :commits, documentation: { is_array: true }, using: Entities::Commit do |compare, _|
compare.commits
end
- expose :diffs, using: Entities::Diff do |compare, _|
+ expose :diffs, documentation: { is_array: true }, using: Entities::Diff do |compare, _|
compare.diffs.diffs.to_a
end
- expose :compare_timeout do |compare, _|
+ expose :compare_timeout, documentation: { type: 'boolean' } do |compare, _|
compare.diffs.diffs.overflow?
end
- expose :same, as: :compare_same_ref
+ expose :same, as: :compare_same_ref, documentation: { type: 'boolean' }
- expose :web_url do |compare, _|
+ expose :web_url,
+ documentation: {
+ example: "https://gitlab.example.com/gitlab/gitlab-foss/-/compare/main...feature"
+ } do |compare, _|
Gitlab::UrlBuilder.build(compare)
end
end
diff --git a/lib/api/entities/container_registry.rb b/lib/api/entities/container_registry.rb
index 2fdfac40c32..d12c8142e69 100644
--- a/lib/api/entities/container_registry.rb
+++ b/lib/api/entities/container_registry.rb
@@ -12,13 +12,13 @@ module API
class Repository < Grape::Entity
include ::API::Helpers::RelatedResourcesHelpers
- expose :id
- expose :name
- expose :path
- expose :project_id
- expose :location
- expose :created_at
- expose :expiration_policy_started_at, as: :cleanup_policy_started_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'releases' }
+ expose :path, documentation: { type: 'string', example: 'group/project/releases' }
+ expose :project_id, documentation: { type: 'integer', example: 9 }
+ expose :location, documentation: { type: 'string', example: 'gitlab.example.com/group/project/releases' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2019-01-10T13:39:08.229Z' }
+ expose :expiration_policy_started_at, as: :cleanup_policy_started_at, documentation: { type: 'dateTime', example: '2020-08-17T03:12:35.489Z' }
expose :tags_count, if: -> (_, options) { options[:tags_count] }
expose :tags, using: Tag, if: -> (_, options) { options[:tags] }
expose :delete_api_path, if: ->(object, options) { Ability.allowed?(options[:user], :admin_container_image, object) }
diff --git a/lib/api/entities/contributor.rb b/lib/api/entities/contributor.rb
index 8763822b674..4fab953f0f6 100644
--- a/lib/api/entities/contributor.rb
+++ b/lib/api/entities/contributor.rb
@@ -3,7 +3,11 @@
module API
module Entities
class Contributor < Grape::Entity
- expose :name, :email, :commits, :additions, :deletions
+ expose :name, documentation: { example: 'John Doe' }
+ expose :email, documentation: { example: 'johndoe@example.com' }
+ expose :commits, documentation: { type: 'integer', example: 117 }
+ expose :additions, documentation: { type: 'integer', example: 3 }
+ expose :deletions, documentation: { type: 'integer', example: 5 }
end
end
end
diff --git a/lib/api/entities/custom_attribute.rb b/lib/api/entities/custom_attribute.rb
index f949b709517..883b572ac75 100644
--- a/lib/api/entities/custom_attribute.rb
+++ b/lib/api/entities/custom_attribute.rb
@@ -3,8 +3,8 @@
module API
module Entities
class CustomAttribute < Grape::Entity
- expose :key
- expose :value
+ expose :key, documentation: { type: 'string', example: 'foo' }
+ expose :value, documentation: { type: 'string', example: 'bar' }
end
end
end
diff --git a/lib/api/entities/deploy_key.rb b/lib/api/entities/deploy_key.rb
index 2c9c33549a1..1bcd06f2c88 100644
--- a/lib/api/entities/deploy_key.rb
+++ b/lib/api/entities/deploy_key.rb
@@ -3,9 +3,15 @@
module API
module Entities
class DeployKey < Entities::SSHKey
- expose :key
- expose :fingerprint, if: ->(key, _) { key.fingerprint.present? }
- expose :fingerprint_sha256
+ expose :key,
+ documentation: { type: 'string', example: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDNJAkI3Wdf0r13c8a5pEExB2YowPWCSVzfZV22pNBc1CuEbyYLHpUyaD0GwpGvFdx2aP7lMEk35k6Rz3ccBF6jRaVJyhsn5VNnW92PMpBJ/P1UebhXwsFHdQf5rTt082cSxWuk61kGWRQtk4ozt/J2DF/dIUVaLvc+z4HomT41fQ==' }
+
+ expose :fingerprint,
+ documentation: { type: 'string', example: '4a:9d:64:15:ed:3a:e6:07:6e:89:36:b3:3b:03:05:d9' },
+ if: ->(key, _) { key.fingerprint.present? }
+
+ expose :fingerprint_sha256,
+ documentation: { type: 'string', example: 'SHA256:Jrs3LD1Ji30xNLtTVf9NDCj7kkBgPBb2pjvTZ3HfIgU' }
expose :projects_with_write_access, using: Entities::ProjectIdentity, if: -> (_, options) { options[:include_projects_with_write_access] }
end
diff --git a/lib/api/entities/deploy_keys_project.rb b/lib/api/entities/deploy_keys_project.rb
index 12a86fbdf8e..4501af88067 100644
--- a/lib/api/entities/deploy_keys_project.rb
+++ b/lib/api/entities/deploy_keys_project.rb
@@ -4,7 +4,7 @@ module API
module Entities
class DeployKeysProject < Grape::Entity
expose :deploy_key, merge: true, using: Entities::DeployKey
- expose :can_push
+ expose :can_push, documentation: { type: 'boolean' }
end
end
end
diff --git a/lib/api/entities/deploy_token.rb b/lib/api/entities/deploy_token.rb
index daee104ba6b..9861467e35d 100644
--- a/lib/api/entities/deploy_token.rb
+++ b/lib/api/entities/deploy_token.rb
@@ -4,8 +4,13 @@ module API
module Entities
class DeployToken < Grape::Entity
# exposing :token is a security risk and should be avoided
- expose :id, :name, :username, :expires_at, :scopes, :revoked
- expose :expired?, as: :expired
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'MyToken' }
+ expose :username, documentation: { type: 'string', example: 'gitlab+deploy-token-1' }
+ expose :expires_at, documentation: { type: 'dateTime', example: '2020-02-14T00:00:00.000Z' }
+ expose :scopes, documentation: { type: 'array', example: ['read_repository'] }
+ expose :revoked, documentation: { type: 'boolean' }
+ expose :expired?, documentation: { type: 'boolean' }, as: :expired
end
end
end
diff --git a/lib/api/entities/deploy_token_with_token.rb b/lib/api/entities/deploy_token_with_token.rb
index 11efe3720fa..a96051e1403 100644
--- a/lib/api/entities/deploy_token_with_token.rb
+++ b/lib/api/entities/deploy_token_with_token.rb
@@ -3,7 +3,7 @@
module API
module Entities
class DeployTokenWithToken < Entities::DeployToken
- expose :token
+ expose :token, documentation: { type: 'string', example: 'jMRvtPNxrn3crTAGukpZ' }
end
end
end
diff --git a/lib/api/entities/deployment.rb b/lib/api/entities/deployment.rb
index 4e3a4c289d9..426e92e7723 100644
--- a/lib/api/entities/deployment.rb
+++ b/lib/api/entities/deployment.rb
@@ -3,11 +3,16 @@
module API
module Entities
class Deployment < Grape::Entity
- expose :id, :iid, :ref, :sha, :created_at, :updated_at
+ expose :id, documentation: { type: 'integer', example: 41 }
+ expose :iid, documentation: { type: 'integer', example: 1 }
+ expose :ref, documentation: { type: 'string', example: 'main' }
+ expose :sha, documentation: { type: 'string', example: '99d03678b90d914dbb1b109132516d71a4a03ea8' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2016-08-11T11:32:35.444Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2016-08-11T11:32:35.444Z' }
expose :user, using: Entities::UserBasic
expose :environment, using: Entities::EnvironmentBasic
expose :deployable, using: Entities::Ci::Job
- expose :status
+ expose :status, documentation: { type: 'string', example: 'created' }
end
end
end
diff --git a/lib/api/entities/diff.rb b/lib/api/entities/diff.rb
index e92bc5d6b68..e9650f07f00 100644
--- a/lib/api/entities/diff.rb
+++ b/lib/api/entities/diff.rb
@@ -3,11 +3,17 @@
module API
module Entities
class Diff < Grape::Entity
- expose :old_path, :new_path, :a_mode, :b_mode
- expose :new_file?, as: :new_file
- expose :renamed_file?, as: :renamed_file
- expose :deleted_file?, as: :deleted_file
- expose :json_safe_diff, as: :diff
+ expose :json_safe_diff, as: :diff, documentation: {
+ type: 'string',
+ example: '--- a/doc/update/5.4-to-6.0.md\n+++ b/doc/update/5.4-to-6.0.md\n@@ -71,6 +71,8 @@\n...'
+ }
+ expose :new_path, documentation: { type: 'string', example: 'doc/update/5.4-to-6.0.md' }
+ expose :old_path, documentation: { type: 'string', example: 'doc/update/5.4-to-6.0.md' }
+ expose :a_mode, documentation: { type: 'string', example: '100755' }
+ expose :b_mode, documentation: { type: 'string', example: '100644' }
+ expose :new_file?, as: :new_file, documentation: { type: 'boolean' }
+ expose :renamed_file?, as: :renamed_file, documentation: { type: 'boolean' }
+ expose :deleted_file?, as: :deleted_file, documentation: { type: 'boolean' }
end
end
end
diff --git a/lib/api/entities/entity_helpers.rb b/lib/api/entities/entity_helpers.rb
index 3a68044ad35..6fb04bb8ad6 100644
--- a/lib/api/entities/entity_helpers.rb
+++ b/lib/api/entities/entity_helpers.rb
@@ -11,8 +11,8 @@ module API
->(obj, opts) { Ability.allowed?(opts[:user], "destroy_#{attr}".to_sym, yield(obj)) }
end
- def expose_restricted(attr, &block)
- expose attr, if: can_read(attr, &block)
+ def expose_restricted(attr, documentation: {}, &block)
+ expose attr, documentation: documentation, if: can_read(attr, &block)
end
end
end
diff --git a/lib/api/entities/environment.rb b/lib/api/entities/environment.rb
index 3b6ed94c3f1..dc9911d5acb 100644
--- a/lib/api/entities/environment.rb
+++ b/lib/api/entities/environment.rb
@@ -5,10 +5,10 @@ module API
class Environment < Entities::EnvironmentBasic
include RequestAwareEntity
- expose :tier
+ expose :tier, documentation: { type: 'string', example: 'development' }
expose :project, using: Entities::BasicProjectDetails
expose :last_deployment, using: Entities::Deployment, if: { last_deployment: true }
- expose :state
+ expose :state, documentation: { type: 'string', example: 'available' }
end
end
end
diff --git a/lib/api/entities/environment_basic.rb b/lib/api/entities/environment_basic.rb
index d9894eac147..1b4a9371820 100644
--- a/lib/api/entities/environment_basic.rb
+++ b/lib/api/entities/environment_basic.rb
@@ -3,7 +3,12 @@
module API
module Entities
class EnvironmentBasic < Grape::Entity
- expose :id, :name, :slug, :external_url, :created_at, :updated_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'deploy' }
+ expose :slug, documentation: { type: 'string', example: 'deploy' }
+ expose :external_url, documentation: { type: 'string', example: 'https://deploy.gitlab.example.com' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2019-05-25T18:55:13.252Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2019-05-25T18:55:13.252Z' }
end
end
end
diff --git a/lib/api/entities/error_tracking.rb b/lib/api/entities/error_tracking.rb
index 163bda92680..5e3b983c58c 100644
--- a/lib/api/entities/error_tracking.rb
+++ b/lib/api/entities/error_tracking.rb
@@ -4,11 +4,11 @@ module API
module Entities
module ErrorTracking
class ProjectSetting < Grape::Entity
- expose :enabled, as: :active
- expose :project_name
- expose :sentry_external_url
- expose :api_url
- expose :integrated
+ expose :enabled, as: :active, documentation: { type: 'boolean' }
+ expose :project_name, documentation: { type: 'string', example: 'sample sentry project' }
+ expose :sentry_external_url, documentation: { type: 'string', example: 'https://sentry.io/myawesomeproject/project' }
+ expose :api_url, documentation: { type: 'string', example: 'https://sentry.io/api/0/projects/myawesomeproject/project' }
+ expose :integrated, documentation: { type: 'boolean' }
def integrated
return false unless ::Feature.enabled?(:integrated_error_tracking, object.project)
@@ -18,10 +18,10 @@ module API
end
class ClientKey < Grape::Entity
- expose :id
- expose :active
- expose :public_key
- expose :sentry_dsn
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :active, documentation: { type: 'boolean' }
+ expose :public_key, documentation: { type: 'string', example: 'glet_aa77551d849c083f76d0bc545ed053a3' }
+ expose :sentry_dsn, documentation: { type: 'string', example: 'https://glet_aa77551d849c083f76d0bc545ed053a3@gitlab.example.com/api/v4/error_tracking/collector/5' }
end
end
end
diff --git a/lib/api/entities/feature.rb b/lib/api/entities/feature.rb
index d1151849cd7..48dd5a22a7e 100644
--- a/lib/api/entities/feature.rb
+++ b/lib/api/entities/feature.rb
@@ -3,8 +3,8 @@
module API
module Entities
class Feature < Grape::Entity
- expose :name
- expose :state
+ expose :name, documentation: { type: 'string', example: 'experimental_feature' }
+ expose :state, documentation: { type: 'string', example: 'off' }
expose :gates, using: Entities::FeatureGate do |model|
model.gates.map do |gate|
value = model.gate_values[gate.key]
diff --git a/lib/api/entities/feature_flag.rb b/lib/api/entities/feature_flag.rb
index 9dec3873504..273307357a2 100644
--- a/lib/api/entities/feature_flag.rb
+++ b/lib/api/entities/feature_flag.rb
@@ -3,12 +3,12 @@
module API
module Entities
class FeatureFlag < Grape::Entity
- expose :name
- expose :description
- expose :active
- expose :version
- expose :created_at
- expose :updated_at
+ expose :name, documentation: { type: 'string', example: 'merge_train' }
+ expose :description, documentation: { type: 'string', example: 'merge train feature flag' }
+ expose :active, documentation: { type: 'boolean' }
+ expose :version, documentation: { type: 'string', example: 'new_version_flag' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2019-11-04T08:13:51.423Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2019-11-04T08:13:51.423Z' }
expose :scopes do |_ff|
[]
end
diff --git a/lib/api/entities/feature_flag/scope.rb b/lib/api/entities/feature_flag/scope.rb
index 906fe718257..e29793c250a 100644
--- a/lib/api/entities/feature_flag/scope.rb
+++ b/lib/api/entities/feature_flag/scope.rb
@@ -4,8 +4,8 @@ module API
module Entities
class FeatureFlag < Grape::Entity
class Scope < Grape::Entity
- expose :id
- expose :environment_scope
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :environment_scope, documentation: { type: 'string', example: 'production' }
end
end
end
diff --git a/lib/api/entities/feature_flag/strategy.rb b/lib/api/entities/feature_flag/strategy.rb
index 32699be0ee3..62178420370 100644
--- a/lib/api/entities/feature_flag/strategy.rb
+++ b/lib/api/entities/feature_flag/strategy.rb
@@ -4,9 +4,9 @@ module API
module Entities
class FeatureFlag < Grape::Entity
class Strategy < Grape::Entity
- expose :id
- expose :name
- expose :parameters
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'userWithId' }
+ expose :parameters, documentation: { type: 'string', example: '{"userIds": "user1"}' }
expose :scopes, using: FeatureFlag::Scope
end
end
diff --git a/lib/api/entities/feature_flag/user_list.rb b/lib/api/entities/feature_flag/user_list.rb
index bc8b12ea22e..efb3261658a 100644
--- a/lib/api/entities/feature_flag/user_list.rb
+++ b/lib/api/entities/feature_flag/user_list.rb
@@ -6,13 +6,13 @@ module API
class UserList < Grape::Entity
include RequestAwareEntity
- expose :id
- expose :iid
- expose :project_id
- expose :created_at
- expose :updated_at
- expose :name
- expose :user_xids
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :iid, documentation: { type: 'integer', example: 1 }
+ expose :project_id, documentation: { type: 'integer', example: 2 }
+ expose :created_at, documentation: { type: 'dateTime', example: '2020-02-04T08:13:10.507Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2020-02-04T08:13:10.507Z' }
+ expose :name, documentation: { type: 'string', example: 'user_list' }
+ expose :user_xids, documentation: { type: 'string', example: 'user1,user2' }
expose :path do |list|
project_feature_flags_user_list_path(list.project, list)
diff --git a/lib/api/entities/feature_gate.rb b/lib/api/entities/feature_gate.rb
index bea9c9474b3..ad4702bf210 100644
--- a/lib/api/entities/feature_gate.rb
+++ b/lib/api/entities/feature_gate.rb
@@ -3,8 +3,8 @@
module API
module Entities
class FeatureGate < Grape::Entity
- expose :key
- expose :value
+ expose :key, documentation: { type: 'string', example: 'percentage_of_actors' }
+ expose :value, documentation: { type: 'integer', example: 34 }
end
end
end
diff --git a/lib/api/entities/freeze_period.rb b/lib/api/entities/freeze_period.rb
index 9b5f08925db..d6853c544a5 100644
--- a/lib/api/entities/freeze_period.rb
+++ b/lib/api/entities/freeze_period.rb
@@ -3,9 +3,11 @@
module API
module Entities
class FreezePeriod < Grape::Entity
- expose :id
- expose :freeze_start, :freeze_end, :cron_timezone
- expose :created_at, :updated_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :freeze_start, documentation: { type: 'string', example: '0 23 * * 5' }
+ expose :freeze_end, documentation: { type: 'string', example: '0 8 * * 1' }
+ expose :cron_timezone, documentation: { type: 'string', example: 'UTC' }
+ expose :created_at, :updated_at, documentation: { type: 'dateTime', example: '2020-05-15T17:03:35.702Z' }
end
end
end
diff --git a/lib/api/entities/go_module_version.rb b/lib/api/entities/go_module_version.rb
index 643e25df9e0..b9dd88982dd 100644
--- a/lib/api/entities/go_module_version.rb
+++ b/lib/api/entities/go_module_version.rb
@@ -3,8 +3,8 @@
module API
module Entities
class GoModuleVersion < Grape::Entity
- expose :name, as: 'Version'
- expose :time, as: 'Time'
+ expose :name, as: 'Version', documentation: { type: 'string', example: 'v1.0.0' }
+ expose :time, as: 'Time', documentation: { type: 'string', example: '1617822312 -0600' }
end
end
end
diff --git a/lib/api/entities/hook.rb b/lib/api/entities/hook.rb
index 95924321221..e24e201ac57 100644
--- a/lib/api/entities/hook.rb
+++ b/lib/api/entities/hook.rb
@@ -3,12 +3,18 @@
module API
module Entities
class Hook < Grape::Entity
- expose :id, :url, :created_at, :push_events, :tag_push_events, :merge_requests_events, :repository_update_events
- expose :enable_ssl_verification
+ expose :id, documentation: { type: 'string', example: 1 }
+ expose :url, documentation: { type: 'string', example: 'https://webhook.site' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :push_events, documentation: { type: 'boolean' }
+ expose :tag_push_events, documentation: { type: 'boolean' }
+ expose :merge_requests_events, documentation: { type: 'boolean' }
+ expose :repository_update_events, documentation: { type: 'boolean' }
+ expose :enable_ssl_verification, documentation: { type: 'boolean' }
- expose :alert_status
- expose :disabled_until
- expose :url_variables
+ expose :alert_status, documentation: { type: 'symbol', example: :executable }
+ expose :disabled_until, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :url_variables, documentation: { type: 'Hash', example: { "token" => "secr3t" }, is_array: true }
def url_variables
object.url_variables.keys.map { { key: _1 } }
diff --git a/lib/api/entities/issuable_entity.rb b/lib/api/entities/issuable_entity.rb
index e2c674c0b8b..4e70f945a48 100644
--- a/lib/api/entities/issuable_entity.rb
+++ b/lib/api/entities/issuable_entity.rb
@@ -3,10 +3,16 @@
module API
module Entities
class IssuableEntity < Grape::Entity
- expose :id, :iid
- expose(:project_id) { |entity| entity&.project.try(:id) }
- expose :title, :description
- expose :state, :created_at, :updated_at
+ expose :id, documentation: { type: 'integer', example: 84 }
+ expose :iid, documentation: { type: 'integer', example: 14 }
+ expose :project_id, documentation: { type: 'integer', example: 4 } do |entity|
+ entity&.project.try(:id)
+ end
+ expose :title, documentation: { type: 'string', example: 'Impedit et ut et dolores vero provident ullam est' }
+ expose :description, documentation: { type: 'string', example: 'Repellendus impedit et vel velit dignissimos.' }
+ expose :state, documentation: { type: 'string', example: 'closed' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2022-08-17T12:46:35.053Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2022-11-14T17:22:01.470Z' }
def presented
lazy_issuable_metadata
diff --git a/lib/api/entities/issue_basic.rb b/lib/api/entities/issue_basic.rb
index 20f66c026e6..89fb8bbe1c0 100644
--- a/lib/api/entities/issue_basic.rb
+++ b/lib/api/entities/issue_basic.rb
@@ -7,10 +7,10 @@ module API
item.upcase if item.respond_to?(:upcase)
end
- expose :closed_at
+ expose :closed_at, documentation: { type: 'dateTime', example: '2022-11-15T08:30:55.232Z' }
expose :closed_by, using: Entities::UserBasic
- expose :labels do |issue, options|
+ expose :labels, documentation: { type: 'string', is_array: true, example: 'bug' } do |issue, options|
if options[:with_labels_details]
::API::Entities::LabelBasic.represent(issue.labels.sort_by(&:title))
else
@@ -23,7 +23,7 @@ module API
expose :issue_type,
as: :type,
format_with: :upcase,
- documentation: { type: "String", desc: "One of #{::WorkItems::Type.allowed_types_for_issues.map(&:upcase)}" }
+ documentation: { type: 'String', example: 'ISSUE', desc: "One of #{::WorkItems::Type.allowed_types_for_issues.map(&:upcase)}" }
expose :assignee, using: ::API::Entities::UserBasic do |issue|
issue.assignees.first
@@ -33,12 +33,12 @@ module API
expose(:merge_requests_count) { |issue, options| issuable_metadata.merge_requests_count }
expose(:upvotes) { |issue, options| issuable_metadata.upvotes }
expose(:downvotes) { |issue, options| issuable_metadata.downvotes }
- expose :due_date
- expose :confidential
- expose :discussion_locked
- expose :issue_type
+ expose :due_date, documentation: { type: 'date', example: '2022-11-20' }
+ expose :confidential, documentation: { type: 'boolean' }
+ expose :discussion_locked, documentation: { type: 'boolean' }
+ expose :issue_type, documentation: { type: 'string', example: 'issue' }
- expose :web_url do |issue|
+ expose :web_url, documentation: { type: 'string', example: 'http://example.com/example/example/issues/14' } do |issue|
Gitlab::UrlBuilder.build(issue)
end
diff --git a/lib/api/entities/license.rb b/lib/api/entities/license.rb
index 8ecf8a430fe..6318fec6774 100644
--- a/lib/api/entities/license.rb
+++ b/lib/api/entities/license.rb
@@ -4,12 +4,25 @@ module API
module Entities
# Serializes a Licensee::License
class License < Entities::LicenseBasic
- expose :popular?, as: :popular
- expose(:description) { |license| license.meta['description'] }
- expose(:conditions) { |license| license.meta['conditions'] }
- expose(:permissions) { |license| license.meta['permissions'] }
- expose(:limitations) { |license| license.meta['limitations'] }
- expose :content
+ expose :popular?, as: :popular, documentation: { type: 'boolean' }
+
+ expose :description, documentation: { type: 'string', example: 'A simple license' } do |license|
+ license.meta['description']
+ end
+
+ expose :conditions, documentation: { type: 'string', is_array: true, example: 'include-copyright' } do |license|
+ license.meta['conditions']
+ end
+
+ expose :permissions, documentation: { type: 'string', is_array: true, example: 'commercial-use' } do |license|
+ license.meta['permissions']
+ end
+
+ expose :limitations, documentation: { type: 'string', is_array: true, example: 'liability' } do |license|
+ license.meta['limitations']
+ end
+
+ expose :content, documentation: { type: 'string', example: 'GNU GENERAL PUBLIC LICENSE' }
end
end
end
diff --git a/lib/api/entities/license_basic.rb b/lib/api/entities/license_basic.rb
index 0916738d21d..e3bb55d4104 100644
--- a/lib/api/entities/license_basic.rb
+++ b/lib/api/entities/license_basic.rb
@@ -4,8 +4,10 @@ module API
module Entities
# Serializes a Gitlab::Git::DeclaredLicense
class LicenseBasic < Grape::Entity
- expose :key, :name, :nickname
- expose :url, as: :html_url
+ expose :key, documentation: { type: 'string', example: 'gpl-3.0' }
+ expose :name, documentation: { type: 'string', example: 'GNU General Public License v3.0' }
+ expose :nickname, documentation: { type: 'string', example: 'GNU GPLv3' }
+ expose :url, as: :html_url, documentation: { example: 'http://choosealicense.com/licenses/gpl-3.0' }
# This was dropped:
# https://github.com/github/choosealicense.com/commit/325806b42aa3d5b78e84120327ec877bc936dbdd#diff-66df8f1997786f7052d29010f2cbb4c66391d60d24ca624c356acc0ab986f139
diff --git a/lib/api/entities/markdown.rb b/lib/api/entities/markdown.rb
new file mode 100644
index 00000000000..0fbaec4375e
--- /dev/null
+++ b/lib/api/entities/markdown.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class Markdown < Grape::Entity
+ expose :html, documentation: { type: 'string', example: '<p dir=\"auto\">Hello world!</p>"' }
+ end
+ end
+end
diff --git a/lib/api/entities/merge_request_approvals.rb b/lib/api/entities/merge_request_approvals.rb
index 6810952b2fc..54f196e0d74 100644
--- a/lib/api/entities/merge_request_approvals.rb
+++ b/lib/api/entities/merge_request_approvals.rb
@@ -3,15 +3,15 @@
module API
module Entities
class MergeRequestApprovals < Grape::Entity
- expose :user_has_approved do |merge_request, options|
+ expose :user_has_approved, documentation: { type: 'boolean' } do |merge_request, options|
merge_request.approved_by?(options[:current_user])
end
- expose :user_can_approve do |merge_request, options|
+ expose :user_can_approve, documentation: { type: 'boolean' } do |merge_request, options|
merge_request.eligible_for_approval_by?(options[:current_user])
end
- expose :approved do |merge_request|
+ expose :approved, documentation: { type: 'boolean' } do |merge_request|
merge_request.approvals.present?
end
diff --git a/lib/api/entities/merge_request_basic.rb b/lib/api/entities/merge_request_basic.rb
index 55d58166590..27f6e6ade06 100644
--- a/lib/api/entities/merge_request_basic.rb
+++ b/lib/api/entities/merge_request_basic.rb
@@ -58,6 +58,7 @@ module API
merge_request.check_mergeability(async: true) unless options[:skip_merge_status_recheck]
merge_request.public_merge_status
end
+ expose :detailed_merge_status
expose :diff_head_sha, as: :sha
expose :merge_commit_sha
expose :squash_commit_sha
@@ -93,6 +94,12 @@ module API
expose :task_completion_status
expose :cannot_be_merged?, as: :has_conflicts
expose :mergeable_discussions_state?, as: :blocking_discussions_resolved
+
+ private
+
+ def detailed_merge_status
+ ::MergeRequests::Mergeability::DetailedMergeStatusService.new(merge_request: object).execute
+ end
end
end
end
diff --git a/lib/api/entities/merge_request_simple.rb b/lib/api/entities/merge_request_simple.rb
index f3ff4cc18a8..d5c511ad9a4 100644
--- a/lib/api/entities/merge_request_simple.rb
+++ b/lib/api/entities/merge_request_simple.rb
@@ -3,8 +3,11 @@
module API
module Entities
class MergeRequestSimple < IssuableEntity
- expose :title
- expose :web_url do |merge_request, options|
+ expose :title, documentation: { type: 'string', example: 'Test MR 1580978354' }
+ expose :web_url,
+ documentation: {
+ type: 'string', example: 'http://local.gitlab.test:8181/root/merge-train-race-condition/-/merge_requests/59'
+ } do |merge_request, options|
Gitlab::UrlBuilder.build(merge_request)
end
end
diff --git a/lib/api/entities/metadata.rb b/lib/api/entities/metadata.rb
index daa491ec42a..7dfcad2ccab 100644
--- a/lib/api/entities/metadata.rb
+++ b/lib/api/entities/metadata.rb
@@ -3,13 +3,14 @@
module API
module Entities
class Metadata < Grape::Entity
- expose :version
- expose :revision
+ expose :version, documentation: { type: 'string', example: '15.2-pre' }
+ expose :revision, documentation: { type: 'string', example: 'c401a659d0c' }
expose :kas do
expose :enabled, documentation: { type: 'boolean' }
- expose :externalUrl
- expose :version
+ expose :externalUrl, documentation: { type: 'string', example: 'grpc://gitlab.example.com:8150' }
+ expose :version, documentation: { type: 'string', example: '15.0.0' }
end
+ expose :enterprise, documentation: { type: 'boolean' }
end
end
end
diff --git a/lib/api/entities/metrics/dashboard/annotation.rb b/lib/api/entities/metrics/dashboard/annotation.rb
index 66bd09d84f9..08d1a333259 100644
--- a/lib/api/entities/metrics/dashboard/annotation.rb
+++ b/lib/api/entities/metrics/dashboard/annotation.rb
@@ -5,13 +5,13 @@ module API
module Metrics
module Dashboard
class Annotation < Grape::Entity
- expose :id
- expose :starting_at
- expose :ending_at
- expose :dashboard_path
- expose :description
- expose :environment_id
- expose :cluster_id
+ expose :id, documentation: { type: 'integer', example: 4 }
+ expose :starting_at, documentation: { type: 'dateTime', example: '2016-04-08T03:45:40.000Z' }
+ expose :ending_at, documentation: { type: 'dateTime', example: '2016-08-08T09:00:00.000Z' }
+ expose :dashboard_path, documentation: { type: 'string', example: '.gitlab/dashboards/custom_metrics.yml' }
+ expose :description, documentation: { type: 'string', example: 'annotation description' }
+ expose :environment_id, documentation: { type: 'integer', example: 1 }
+ expose :cluster_id, documentation: { type: 'integer', example: 2 }
end
end
end
diff --git a/lib/api/entities/metrics/user_starred_dashboard.rb b/lib/api/entities/metrics/user_starred_dashboard.rb
index d774160e3ea..1d2a8a39547 100644
--- a/lib/api/entities/metrics/user_starred_dashboard.rb
+++ b/lib/api/entities/metrics/user_starred_dashboard.rb
@@ -4,7 +4,10 @@ module API
module Entities
module Metrics
class UserStarredDashboard < Grape::Entity
- expose :id, :dashboard_path, :user_id, :project_id
+ expose :id, documentation: { type: 'integer', example: 5 }
+ expose :dashboard_path, documentation: { type: 'string', example: 'config/prometheus/common_metrics.yml' }
+ expose :user_id, documentation: { type: 'integer', example: 1 }
+ expose :project_id, documentation: { type: 'integer', example: 20 }
end
end
end
diff --git a/lib/api/entities/ml/mlflow/run.rb b/lib/api/entities/ml/mlflow/run.rb
index a8e1cfe08dd..8b16c67611f 100644
--- a/lib/api/entities/ml/mlflow/run.rb
+++ b/lib/api/entities/ml/mlflow/run.rb
@@ -6,7 +6,7 @@ module API
module Mlflow
class Run < Grape::Entity
expose :run do
- expose(:info) { |candidate| RunInfo.represent(candidate) }
+ expose :itself, using: RunInfo, as: :info
expose :data do
expose :metrics, using: Metric
expose :params, using: RunParam
diff --git a/lib/api/entities/ml/mlflow/run_info.rb b/lib/api/entities/ml/mlflow/run_info.rb
index 096950e349d..d3934545ba4 100644
--- a/lib/api/entities/ml/mlflow/run_info.rb
+++ b/lib/api/entities/ml/mlflow/run_info.rb
@@ -11,7 +11,7 @@ module API
expose(:start_time) { |candidate| candidate.start_time || 0 }
expose :end_time, expose_nil: false
expose(:status) { |candidate| candidate.status.to_s.upcase }
- expose(:artifact_uri) { |candidate| 'not_implemented' }
+ expose(:artifact_uri) { |candidate, options| "#{options[:packages_url]}#{candidate.artifact_root}" }
expose(:lifecycle_stage) { |candidate| 'active' }
expose(:user_id) { |candidate| candidate.user_id.to_s }
diff --git a/lib/api/entities/ml/mlflow/update_run.rb b/lib/api/entities/ml/mlflow/update_run.rb
index 090d69b8895..55def810ef5 100644
--- a/lib/api/entities/ml/mlflow/update_run.rb
+++ b/lib/api/entities/ml/mlflow/update_run.rb
@@ -5,13 +5,7 @@ module API
module Ml
module Mlflow
class UpdateRun < Grape::Entity
- expose :run_info
-
- private
-
- def run_info
- RunInfo.represent object
- end
+ expose :itself, using: RunInfo, as: :run_info
end
end
end
diff --git a/lib/api/entities/package.rb b/lib/api/entities/package.rb
index 18fc0576dd4..c92a4677220 100644
--- a/lib/api/entities/package.rb
+++ b/lib/api/entities/package.rb
@@ -4,11 +4,12 @@ module API
module Entities
class Package < Grape::Entity
include ::API::Helpers::RelatedResourcesHelpers
+ include ::Routing::PackagesHelper
extend ::API::Entities::EntityHelpers
- expose :id
+ expose :id, documentation: { type: 'integer', example: 1 }
- expose :name do |package|
+ expose :name, documentation: { type: 'string', example: '@foo/bar' } do |package|
if package.conan?
package.conan_recipe
else
@@ -20,17 +21,13 @@ module API
package.name
end
- expose :version
- expose :package_type
- expose :status
+ expose :version, documentation: { type: 'string', example: '1.0.3' }
+ expose :package_type, documentation: { type: 'string', example: 'npm' }
+ expose :status, documentation: { type: 'string', example: 'default' }
expose :_links do
- expose :web_path do |package, opts|
- if package.infrastructure_package?
- ::Gitlab::Routing.url_helpers.namespace_project_infrastructure_registry_path(opts[:namespace], package.project, package)
- else
- ::Gitlab::Routing.url_helpers.project_package_path(package.project, package)
- end
+ expose :web_path do |package|
+ package_path(package)
end
expose :delete_api_path, if: can_destroy(:package, &:project) do |package|
@@ -38,10 +35,12 @@ module API
end
end
- expose :created_at
- expose :last_downloaded_at
- expose :project_id, if: ->(_, opts) { opts[:group] }
- expose :project_path, if: ->(obj, opts) { opts[:group] && Ability.allowed?(opts[:user], :read_project, obj.project) }
+ expose :created_at, documentation: { type: 'dateTime', example: '2022-09-16T12:47:31.949Z' }
+ expose :last_downloaded_at, documentation: { type: 'dateTime', example: '2022-09-19T11:32:35.169Z' }
+ expose :project_id, documentation: { type: 'integer', example: 2 }, if: ->(_, opts) { opts[:group] }
+ expose :project_path, documentation: { type: 'string', example: 'gitlab/foo/bar' }, if: ->(obj, opts) do
+ opts[:group] && Ability.allowed?(opts[:user], :read_project, obj.project)
+ end
expose :tags
expose :pipeline, if: ->(package) { package.original_build_info }, using: Package::Pipeline
diff --git a/lib/api/entities/package_file.rb b/lib/api/entities/package_file.rb
index e34a6a7aa1d..19372b75012 100644
--- a/lib/api/entities/package_file.rb
+++ b/lib/api/entities/package_file.rb
@@ -3,9 +3,14 @@
module API
module Entities
class PackageFile < Grape::Entity
- expose :id, :package_id, :created_at
- expose :file_name, :size
- expose :file_md5, :file_sha1, :file_sha256
+ expose :id, documentation: { type: 'integer', example: 225 }
+ expose :package_id, documentation: { type: 'integer', example: 4 }
+ expose :created_at, documentation: { type: 'dateTime', example: '2018-11-07T15:25:52.199Z' }
+ expose :file_name, documentation: { type: 'string', example: 'my-app-1.5-20181107.152550-1.jar' }
+ expose :size, documentation: { type: 'integer', example: '2421' }
+ expose :file_md5, documentation: { type: 'string', example: '58e6a45a629910c6ff99145a688971ac' }
+ expose :file_sha1, documentation: { type: 'string', example: 'ebd193463d3915d7e22219f52740056dfd26cbfe' }
+ expose :file_sha256, documentation: { type: 'string', example: 'a903393463d3915d7e22219f52740056dfd26cbfeff321b' }
expose :pipelines, if: ->(package_file) { package_file.pipelines.present? }, using: Package::Pipeline
end
end
diff --git a/lib/api/entities/personal_access_token.rb b/lib/api/entities/personal_access_token.rb
index 55764daef9d..3ec91ca5fc9 100644
--- a/lib/api/entities/personal_access_token.rb
+++ b/lib/api/entities/personal_access_token.rb
@@ -3,9 +3,16 @@
module API
module Entities
class PersonalAccessToken < Grape::Entity
- expose :id, :name, :revoked, :created_at, :scopes, :user_id, :last_used_at
- expose :active?, as: :active
- expose :expires_at do |personal_access_token|
+ expose :id, documentation: { type: 'integer', example: 2 }
+ expose :name, documentation: { type: 'string', example: 'John Doe' }
+ expose :revoked, documentation: { type: 'boolean' }
+ expose :created_at, documentation: { type: 'dateTime' }
+ expose :scopes, documentation: { type: 'array', example: ['api'] }
+ expose :user_id, documentation: { type: 'integer', example: 3 }
+ expose :last_used_at, documentation: { type: 'dateTime', example: '2020-08-31T15:53:00.073Z' }
+ expose :active?, as: :active, documentation: { type: 'boolean' }
+ expose :expires_at, documentation:
+ { type: 'dateTime', example: '2020-08-31T15:53:00.073Z' } do |personal_access_token|
personal_access_token.expires_at ? personal_access_token.expires_at.strftime("%Y-%m-%d") : nil
end
end
diff --git a/lib/api/entities/plan_limit.rb b/lib/api/entities/plan_limit.rb
index 94e50f19b35..34018f03eb1 100644
--- a/lib/api/entities/plan_limit.rb
+++ b/lib/api/entities/plan_limit.rb
@@ -3,23 +3,23 @@
module API
module Entities
class PlanLimit < Grape::Entity
- expose :ci_pipeline_size
- expose :ci_active_jobs
- expose :ci_active_pipelines
- expose :ci_project_subscriptions
- expose :ci_pipeline_schedules
- expose :ci_needs_size_limit
- expose :ci_registered_group_runners
- expose :ci_registered_project_runners
- expose :conan_max_file_size
- expose :generic_packages_max_file_size
- expose :helm_max_file_size
- expose :maven_max_file_size
- expose :npm_max_file_size
- expose :nuget_max_file_size
- expose :pypi_max_file_size
- expose :terraform_module_max_file_size
- expose :storage_size_limit
+ expose :ci_pipeline_size, documentation: { type: 'integer', example: 0 }
+ expose :ci_active_jobs, documentation: { type: 'integer', example: 0 }
+ expose :ci_active_pipelines, documentation: { type: 'integer', example: 0 }
+ expose :ci_project_subscriptions, documentation: { type: 'integer', example: 2 }
+ expose :ci_pipeline_schedules, documentation: { type: 'integer', example: 10 }
+ expose :ci_needs_size_limit, documentation: { type: 'integer', example: 50 }
+ expose :ci_registered_group_runners, documentation: { type: 'integer', example: 1000 }
+ expose :ci_registered_project_runners, documentation: { type: 'integer', example: 1000 }
+ expose :conan_max_file_size, documentation: { type: 'integer', example: 3221225472 }
+ expose :generic_packages_max_file_size, documentation: { type: 'integer', example: 5368709120 }
+ expose :helm_max_file_size, documentation: { type: 'integer', example: 5242880 }
+ expose :maven_max_file_size, documentation: { type: 'integer', example: 3221225472 }
+ expose :npm_max_file_size, documentation: { type: 'integer', example: 524288000 }
+ expose :nuget_max_file_size, documentation: { type: 'integer', example: 524288000 }
+ expose :pypi_max_file_size, documentation: { type: 'integer', example: 3221225472 }
+ expose :terraform_module_max_file_size, documentation: { type: 'integer', example: 1073741824 }
+ expose :storage_size_limit, documentation: { type: 'integer', example: 15000 }
end
end
end
diff --git a/lib/api/entities/project.rb b/lib/api/entities/project.rb
index f158695f605..1c1bafbf161 100644
--- a/lib/api/entities/project.rb
+++ b/lib/api/entities/project.rb
@@ -5,147 +5,148 @@ module API
class Project < BasicProjectDetails
include ::API::Helpers::RelatedResourcesHelpers
- expose :container_registry_url, as: :container_registry_image_prefix, if: -> (_, _) { Gitlab.config.registry.enabled }
+ expose :container_registry_url, as: :container_registry_image_prefix, documentation: { type: 'string', example: 'registry.gitlab.example.com/gitlab/gitlab-client' }, if: -> (_, _) { Gitlab.config.registry.enabled }
expose :_links do
- expose :self do |project|
+ expose :self, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4' } do |project|
expose_url(api_v4_projects_path(id: project.id))
end
- expose :issues, if: -> (project, options) { issues_available?(project, options) } do |project|
+ expose :issues, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4/issues' }, if: -> (project, options) { issues_available?(project, options) } do |project|
expose_url(api_v4_projects_issues_path(id: project.id))
end
- expose :merge_requests, if: -> (project, options) { mrs_available?(project, options) } do |project|
+ expose :merge_requests, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4/merge_requests' }, if: -> (project, options) { mrs_available?(project, options) } do |project|
expose_url(api_v4_projects_merge_requests_path(id: project.id))
end
- expose :repo_branches do |project|
+ expose :repo_branches, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4/repository/branches' } do |project|
expose_url(api_v4_projects_repository_branches_path(id: project.id))
end
- expose :labels do |project|
+ expose :labels, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4/labels' } do |project|
expose_url(api_v4_projects_labels_path(id: project.id))
end
- expose :events do |project|
+ expose :events, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4/events' } do |project|
expose_url(api_v4_projects_events_path(id: project.id))
end
- expose :members do |project|
+ expose :members, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4/members' } do |project|
expose_url(api_v4_projects_members_path(id: project.id))
end
- expose :cluster_agents do |project|
+ expose :cluster_agents, documentation: { type: 'string', example: 'https://gitlab.example.com/api/v4/projects/4/cluster_agents' } do |project|
expose_url(api_v4_projects_cluster_agents_path(id: project.id))
end
end
- expose :packages_enabled
- expose :empty_repo?, as: :empty_repo
- expose :archived?, as: :archived
- expose :visibility
+ expose :packages_enabled, documentation: { type: 'boolean' }
+ expose :empty_repo?, as: :empty_repo, documentation: { type: 'boolean' }
+ expose :archived?, as: :archived, documentation: { type: 'boolean' }
+ expose :visibility, documentation: { type: 'string', example: 'public' }
expose :owner, using: Entities::UserBasic, unless: ->(project, options) { project.group }
- expose :resolve_outdated_diff_discussions
+ expose :resolve_outdated_diff_discussions, documentation: { type: 'boolean' }
expose :container_expiration_policy,
using: Entities::ContainerExpirationPolicy,
if: -> (project, _) { project.container_expiration_policy }
# Expose old field names with the new permissions methods to keep API compatible
# TODO: remove in API v5, replaced by *_access_level
- expose(:issues_enabled) { |project, options| project.feature_available?(:issues, options[:current_user]) }
- expose(:merge_requests_enabled) { |project, options| project.feature_available?(:merge_requests, options[:current_user]) }
- expose(:wiki_enabled) { |project, options| project.feature_available?(:wiki, options[:current_user]) }
- expose(:jobs_enabled) { |project, options| project.feature_available?(:builds, options[:current_user]) }
- expose(:snippets_enabled) { |project, options| project.feature_available?(:snippets, options[:current_user]) }
- expose(:container_registry_enabled) { |project, options| project.feature_available?(:container_registry, options[:current_user]) }
- expose :service_desk_enabled
- expose :service_desk_address, if: -> (project, options) do
+ expose(:issues_enabled, documentation: { type: 'boolean' }) { |project, options| project.feature_available?(:issues, options[:current_user]) }
+ expose(:merge_requests_enabled, documentation: { type: 'boolean' }) { |project, options| project.feature_available?(:merge_requests, options[:current_user]) }
+ expose(:wiki_enabled, documentation: { type: 'boolean' }) { |project, options| project.feature_available?(:wiki, options[:current_user]) }
+ expose(:jobs_enabled, documentation: { type: 'boolean' }) { |project, options| project.feature_available?(:builds, options[:current_user]) }
+ expose(:snippets_enabled, documentation: { type: 'boolean' }) { |project, options| project.feature_available?(:snippets, options[:current_user]) }
+ expose(:container_registry_enabled, documentation: { type: 'boolean' }) { |project, options| project.feature_available?(:container_registry, options[:current_user]) }
+ expose :service_desk_enabled, documentation: { type: 'boolean' }
+ expose :service_desk_address, documentation: { type: 'string', example: 'address@example.com' }, if: -> (project, options) do
Ability.allowed?(options[:current_user], :admin_issue, project)
end
- expose(:can_create_merge_request_in) do |project, options|
+ expose(:can_create_merge_request_in, documentation: { type: 'boolean' }) do |project, options|
Ability.allowed?(options[:current_user], :create_merge_request_in, project)
end
- expose(:issues_access_level) { |project, options| project_feature_string_access_level(project, :issues) }
- expose(:repository_access_level) { |project, options| project_feature_string_access_level(project, :repository) }
- expose(:merge_requests_access_level) { |project, options| project_feature_string_access_level(project, :merge_requests) }
- expose(:forking_access_level) { |project, options| project_feature_string_access_level(project, :forking) }
- expose(:wiki_access_level) { |project, options| project_feature_string_access_level(project, :wiki) }
- expose(:builds_access_level) { |project, options| project_feature_string_access_level(project, :builds) }
- expose(:snippets_access_level) { |project, options| project_feature_string_access_level(project, :snippets) }
- expose(:pages_access_level) { |project, options| project_feature_string_access_level(project, :pages) }
- expose(:operations_access_level) { |project, options| project_feature_string_access_level(project, :operations) }
- expose(:analytics_access_level) { |project, options| project_feature_string_access_level(project, :analytics) }
- expose(:container_registry_access_level) { |project, options| project_feature_string_access_level(project, :container_registry) }
- expose(:security_and_compliance_access_level) { |project, options| project_feature_string_access_level(project, :security_and_compliance) }
- expose(:releases_access_level) { |project, options| project_feature_string_access_level(project, :releases) }
-
- expose :emails_disabled
- expose :shared_runners_enabled
- expose :lfs_enabled?, as: :lfs_enabled
- expose :creator_id
+ expose(:issues_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :issues) }
+ expose(:repository_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :repository) }
+ expose(:merge_requests_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :merge_requests) }
+ expose(:forking_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :forking) }
+ expose(:wiki_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :wiki) }
+ expose(:builds_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :builds) }
+ expose(:snippets_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :snippets) }
+ expose(:pages_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :pages) }
+ expose(:operations_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :operations) }
+ expose(:analytics_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :analytics) }
+ expose(:container_registry_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :container_registry) }
+ expose(:security_and_compliance_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :security_and_compliance) }
+ expose(:releases_access_level, documentation: { type: 'string', example: 'enabled' }) { |project, options| project_feature_string_access_level(project, :releases) }
+
+ expose :emails_disabled, documentation: { type: 'boolean' }
+ expose :shared_runners_enabled, documentation: { type: 'boolean' }
+ expose :lfs_enabled?, as: :lfs_enabled, documentation: { type: 'boolean' }
+ expose :creator_id, documentation: { type: 'integer', example: 1 }
expose :forked_from_project, using: Entities::BasicProjectDetails, if: ->(project, options) do
project.forked? && Ability.allowed?(options[:current_user], :read_project, project.forked_from_project)
end
- expose :mr_default_target_self, if: -> (project) { project.forked? }
+ expose :mr_default_target_self, if: -> (project) { project.forked? }, documentation: { type: 'boolean' }
- expose :import_url, if: -> (project, options) { Ability.allowed?(options[:current_user], :admin_project, project) } do |project|
+ expose :import_url, documentation: { type: 'string', example: 'https://gitlab.com/gitlab/gitlab.git' }, if: -> (project, options) { Ability.allowed?(options[:current_user], :admin_project, project) } do |project|
project[:import_url]
end
- expose :import_type, if: -> (project, options) { Ability.allowed?(options[:current_user], :admin_project, project) }
- expose :import_status
- expose :import_error, if: lambda { |_project, options| options[:user_can_admin_project] } do |project|
+ expose :import_type, documentation: { type: 'string', example: 'git' }, if: -> (project, options) { Ability.allowed?(options[:current_user], :admin_project, project) }
+ expose :import_status, documentation: { type: 'string', example: 'none' }
+ expose :import_error, documentation: { type: 'string', example: 'Import error' }, if: lambda { |_project, options| options[:user_can_admin_project] } do |project|
project.import_state&.last_error
end
- expose :open_issues_count, if: lambda { |project, options| project.feature_available?(:issues, options[:current_user]) }
- expose :runners_token, if: lambda { |_project, options| options[:user_can_admin_project] }
- expose :ci_default_git_depth
- expose :ci_forward_deployment_enabled
- expose(:ci_job_token_scope_enabled) { |p, _| p.ci_outbound_job_token_scope_enabled? }
- expose :ci_separated_caches
- expose :ci_opt_in_jwt
- expose :ci_allow_fork_pipelines_to_run_in_parent_project
- expose :public_builds, as: :public_jobs
- expose :build_git_strategy, if: lambda { |project, options| options[:user_can_admin_project] } do |project, options|
+ expose :open_issues_count, documentation: { type: 'integer', example: 1 }, if: lambda { |project, options| project.feature_available?(:issues, options[:current_user]) }
+ expose :runners_token, documentation: { type: 'string', example: 'b8547b1dc37721d05889db52fa2f02' }, if: lambda { |_project, options| options[:user_can_admin_project] }
+ expose :ci_default_git_depth, documentation: { type: 'integer', example: 20 }
+ expose :ci_forward_deployment_enabled, documentation: { type: 'boolean' }
+ expose(:ci_job_token_scope_enabled, documentation: { type: 'boolean' }) { |p, _| p.ci_outbound_job_token_scope_enabled? }
+ expose :ci_separated_caches, documentation: { type: 'boolean' }
+ expose :ci_opt_in_jwt, documentation: { type: 'boolean' }
+ expose :ci_allow_fork_pipelines_to_run_in_parent_project, documentation: { type: 'boolean' }
+ expose :public_builds, as: :public_jobs, documentation: { type: 'boolean' }
+ expose :build_git_strategy, documentation: { type: 'string', example: 'fetch' }, if: lambda { |project, options| options[:user_can_admin_project] } do |project, options|
project.build_allow_git_fetch ? 'fetch' : 'clone'
end
- expose :build_timeout
- expose :auto_cancel_pending_pipelines
- expose :ci_config_path, if: -> (project, options) { Ability.allowed?(options[:current_user], :download_code, project) }
- expose :shared_with_groups do |project, options|
+ expose :build_timeout, documentation: { type: 'integer', example: 3600 }
+ expose :auto_cancel_pending_pipelines, documentation: { type: 'string', example: 'enabled' }
+ expose :ci_config_path, documentation: { type: 'string', example: '' }, if: -> (project, options) { Ability.allowed?(options[:current_user], :read_code, project) }
+ expose :shared_with_groups, documentation: { is_array: true } do |project, options|
user = options[:current_user]
SharedGroupWithProject.represent(project.visible_group_links(for_user: user), options)
end
- expose :only_allow_merge_if_pipeline_succeeds
- expose :allow_merge_on_skipped_pipeline
- expose :restrict_user_defined_variables
- expose :request_access_enabled
- expose :only_allow_merge_if_all_discussions_are_resolved
- expose :remove_source_branch_after_merge
- expose :printing_merge_request_link_enabled
- expose :merge_method
- expose :squash_option
- expose :enforce_auth_checks_on_uploads
- expose :suggestion_commit_message
- expose :merge_commit_template
- expose :squash_commit_template
+ expose :only_allow_merge_if_pipeline_succeeds, documentation: { type: 'boolean' }
+ expose :allow_merge_on_skipped_pipeline, documentation: { type: 'boolean' }
+ expose :restrict_user_defined_variables, documentation: { type: 'boolean' }
+ expose :request_access_enabled, documentation: { type: 'boolean' }
+ expose :only_allow_merge_if_all_discussions_are_resolved, documentation: { type: 'boolean' }
+ expose :remove_source_branch_after_merge, documentation: { type: 'boolean' }
+ expose :printing_merge_request_link_enabled, documentation: { type: 'boolean' }
+ expose :merge_method, documentation: { type: 'string', example: 'merge' }
+ expose :squash_option, documentation: { type: 'string', example: 'default_off' }
+ expose :enforce_auth_checks_on_uploads, documentation: { type: 'boolean' }
+ expose :suggestion_commit_message, documentation: { type: 'string', example: 'Suggestion message' }
+ expose :merge_commit_template, documentation: { type: 'string', example: '%(title)' }
+ expose :squash_commit_template, documentation: { type: 'string', example: '%(source_branch)' }
+ expose :issue_branch_template, documentation: { type: 'string', example: '%(title)' }
expose :statistics, using: 'API::Entities::ProjectStatistics', if: -> (project, options) {
options[:statistics] && Ability.allowed?(options[:current_user], :read_statistics, project)
}
- expose :auto_devops_enabled?, as: :auto_devops_enabled
- expose :auto_devops_deploy_strategy do |project, options|
+ expose :auto_devops_enabled?, as: :auto_devops_enabled, documentation: { type: 'boolean' }
+ expose :auto_devops_deploy_strategy, documentation: { type: 'string', example: 'continuous' } do |project, options|
project.auto_devops.nil? ? 'continuous' : project.auto_devops.deploy_strategy
end
- expose :autoclose_referenced_issues
- expose :repository_storage, if: ->(project, options) {
+ expose :autoclose_referenced_issues, documentation: { type: 'boolean' }
+ expose :repository_storage, documentation: { type: 'string', example: 'default' }, if: ->(project, options) {
Ability.allowed?(options[:current_user], :change_repository_storage, project)
}
- expose :keep_latest_artifacts_available?, as: :keep_latest_artifact
- expose :runner_token_expiration_interval
+ expose :keep_latest_artifacts_available?, as: :keep_latest_artifact, documentation: { type: 'boolean' }
+ expose :runner_token_expiration_interval, documentation: { type: 'integer', example: 3600 }
# rubocop: disable CodeReuse/ActiveRecord
def self.preload_resource(project)
diff --git a/lib/api/entities/project_daily_fetches.rb b/lib/api/entities/project_daily_fetches.rb
index 036b5dc99b8..8797aeb9521 100644
--- a/lib/api/entities/project_daily_fetches.rb
+++ b/lib/api/entities/project_daily_fetches.rb
@@ -3,8 +3,8 @@
module API
module Entities
class ProjectDailyFetches < Grape::Entity
- expose :fetch_count, as: :count
- expose :date
+ expose :fetch_count, as: :count, documentation: { type: 'integer', example: 3 }
+ expose :date, documentation: { type: 'date', example: '2022-01-01' }
end
end
end
diff --git a/lib/api/entities/project_daily_statistics.rb b/lib/api/entities/project_daily_statistics.rb
index 803ee445851..555ecc6be39 100644
--- a/lib/api/entities/project_daily_statistics.rb
+++ b/lib/api/entities/project_daily_statistics.rb
@@ -4,8 +4,8 @@ module API
module Entities
class ProjectDailyStatistics < Grape::Entity
expose :fetches do
- expose :total_fetch_count, as: :total
- expose :fetches, as: :days, using: ProjectDailyFetches
+ expose :total_fetch_count, as: :total, documentation: { type: 'integer', example: 3 }
+ expose :fetches, as: :days, using: ProjectDailyFetches, documentation: { is_array: true }
end
end
end
diff --git a/lib/api/entities/project_export_status.rb b/lib/api/entities/project_export_status.rb
index ad84a45996a..9a2aeb7a6bb 100644
--- a/lib/api/entities/project_export_status.rb
+++ b/lib/api/entities/project_export_status.rb
@@ -5,13 +5,21 @@ module API
class ProjectExportStatus < ProjectIdentity
include ::API::Helpers::RelatedResourcesHelpers
- expose :export_status
+ expose :export_status, documentation: {
+ type: 'string', example: 'finished', values: %w[queued started finished failed]
+ }
expose :_links, if: lambda { |project, _options| project.export_status == :finished } do
- expose :api_url do |project|
+ expose :api_url, documentation: {
+ type: 'string',
+ example: 'https://gitlab.example.com/api/v4/projects/1/export/download'
+ } do |project|
expose_url(api_v4_projects_export_download_path(id: project.id))
end
- expose :web_url do |project|
+ expose :web_url, documentation: {
+ type: 'string',
+ example: 'https://gitlab.example.com/gitlab-org/gitlab-test/download_export'
+ } do |project|
Gitlab::Routing.url_helpers.download_export_project_url(project)
end
end
diff --git a/lib/api/entities/project_group_link.rb b/lib/api/entities/project_group_link.rb
index 89138854e67..b5d5991ec7f 100644
--- a/lib/api/entities/project_group_link.rb
+++ b/lib/api/entities/project_group_link.rb
@@ -3,7 +3,11 @@
module API
module Entities
class ProjectGroupLink < Grape::Entity
- expose :id, :project_id, :group_id, :group_access, :expires_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :project_id, documentation: { type: 'integer', example: 1 }
+ expose :group_id, documentation: { type: 'integer', example: 1 }
+ expose :group_access, documentation: { type: 'integer', example: 10 }
+ expose :expires_at, documentation: { type: 'date', example: '2016-09-26' }
end
end
end
diff --git a/lib/api/entities/project_hook.rb b/lib/api/entities/project_hook.rb
index 6c71e5d317c..bffb057abed 100644
--- a/lib/api/entities/project_hook.rb
+++ b/lib/api/entities/project_hook.rb
@@ -3,10 +3,17 @@
module API
module Entities
class ProjectHook < Hook
- expose :project_id, :issues_events, :confidential_issues_events
- expose :note_events, :confidential_note_events, :pipeline_events, :wiki_page_events, :deployment_events
- expose :job_events, :releases_events
- expose :push_events_branch_filter
+ expose :project_id, documentation: { type: 'string', example: 1 }
+ expose :issues_events, documentation: { type: 'boolean' }
+ expose :confidential_issues_events, documentation: { type: 'boolean' }
+ expose :note_events, documentation: { type: 'boolean' }
+ expose :confidential_note_events, documentation: { type: 'boolean' }
+ expose :pipeline_events, documentation: { type: 'boolean' }
+ expose :wiki_page_events, documentation: { type: 'boolean' }
+ expose :deployment_events, documentation: { type: 'boolean' }
+ expose :job_events, documentation: { type: 'boolean' }
+ expose :releases_events, documentation: { type: 'boolean' }
+ expose :push_events_branch_filter, documentation: { type: 'string', example: 'my-branch-*' }
end
end
end
diff --git a/lib/api/entities/project_identity.rb b/lib/api/entities/project_identity.rb
index 2055195eea0..14aef05b95e 100644
--- a/lib/api/entities/project_identity.rb
+++ b/lib/api/entities/project_identity.rb
@@ -3,10 +3,13 @@
module API
module Entities
class ProjectIdentity < Grape::Entity
- expose :id, :description
- expose :name, :name_with_namespace
- expose :path, :path_with_namespace
- expose :created_at
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :description, documentation: { type: 'string', example: 'desc' }
+ expose :name, documentation: { type: 'string', example: 'project1' }
+ expose :name_with_namespace, documentation: { type: 'string', example: 'John Doe / project1' }
+ expose :path, documentation: { type: 'string', example: 'project1' }
+ expose :path_with_namespace, documentation: { type: 'string', example: 'namespace1/project1' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2020-05-07T04:27:17.016Z' }
end
end
end
diff --git a/lib/api/entities/project_import_failed_relation.rb b/lib/api/entities/project_import_failed_relation.rb
index 26cfae7260c..543cc62f364 100644
--- a/lib/api/entities/project_import_failed_relation.rb
+++ b/lib/api/entities/project_import_failed_relation.rb
@@ -3,14 +3,17 @@
module API
module Entities
class ProjectImportFailedRelation < Grape::Entity
- expose :id, :created_at, :exception_class, :source
+ expose :id, documentation: { type: 'string', example: 1 }
+ expose :created_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
+ expose :exception_class, documentation: { type: 'string', example: 'StandardError' }
+ expose :source, documentation: { type: 'string', example: 'ImportRepositoryWorker' }
- expose :exception_message do |_|
+ expose :exception_message, documentation: { type: 'string' } do |_|
nil
end
- expose :relation_key, as: :relation_name
- expose :relation_index, as: :line_number
+ expose :relation_key, as: :relation_name, documentation: { type: 'string', example: 'issues' }
+ expose :relation_index, as: :line_number, documentation: { type: 'integer', example: 1 }
end
end
end
diff --git a/lib/api/entities/project_import_status.rb b/lib/api/entities/project_import_status.rb
index 5daae4a70f2..59388aacafd 100644
--- a/lib/api/entities/project_import_status.rb
+++ b/lib/api/entities/project_import_status.rb
@@ -3,21 +3,25 @@
module API
module Entities
class ProjectImportStatus < ProjectIdentity
- expose :import_status
- expose :import_type
- expose :correlation_id do |project, _options|
+ expose :import_status, documentation: { type: 'string', example: 'scheduled' }
+ expose :import_type, documentation: { type: 'string', example: 'gitlab_project' }
+ expose :correlation_id, documentation: {
+ type: 'string', example: 'dfcf583058ed4508e4c7c617bd7f0edd'
+ } do |project, _options|
project.import_state&.correlation_id
end
- expose :failed_relations, using: Entities::ProjectImportFailedRelation do |project, _options|
+ expose :failed_relations, using: Entities::ProjectImportFailedRelation, documentation: {
+ is_array: true
+ } do |project, _options|
project.import_state&.relation_hard_failures(limit: 100) || []
end
- expose :import_error do |project, _options|
+ expose :import_error, documentation: { type: 'string', example: 'Error message' } do |project, _options|
project.import_state&.last_error
end
- expose :stats do |project, _options|
+ expose :stats, documentation: { type: 'object' } do |project, _options|
if project.github_import?
::Gitlab::GithubImport::ObjectCounter.summary(project)
end
diff --git a/lib/api/entities/project_integration.rb b/lib/api/entities/project_integration.rb
index 155136d2f80..29bb60a19e5 100644
--- a/lib/api/entities/project_integration.rb
+++ b/lib/api/entities/project_integration.rb
@@ -4,7 +4,7 @@ module API
module Entities
class ProjectIntegration < Entities::ProjectIntegrationBasic
# Expose serialized properties
- expose :properties do |integration, options|
+ expose :properties, documentation: { type: 'Hash', example: { "token" => "secr3t" } } do |integration, options|
integration.api_field_names.to_h do |name|
[name, integration.public_send(name)] # rubocop:disable GitlabSecurity/PublicSend
end
diff --git a/lib/api/entities/project_integration_basic.rb b/lib/api/entities/project_integration_basic.rb
index 2870123b83d..aa0ad158b83 100644
--- a/lib/api/entities/project_integration_basic.rb
+++ b/lib/api/entities/project_integration_basic.rb
@@ -3,15 +3,26 @@
module API
module Entities
class ProjectIntegrationBasic < Grape::Entity
- expose :id, :title
- expose :slug do |integration|
+ expose :id, documentation: { type: 'integer', example: 75 }
+ expose :title, documentation: { type: 'string', example: 'Jenkins CI' }
+ expose :slug, documentation: { type: 'integer', example: 'jenkins' } do |integration|
integration.to_param.dasherize
end
- expose :created_at, :updated_at, :active
- expose :commit_events, :push_events, :issues_events, :confidential_issues_events
- expose :merge_requests_events, :tag_push_events, :note_events
- expose :confidential_note_events, :pipeline_events, :wiki_page_events
- expose :job_events, :comment_on_event_enabled
+ expose :created_at, documentation: { type: 'dateTime', example: '2019-11-20T11:20:25.297Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2019-11-20T12:24:37.498Z' }
+ expose :active, documentation: { type: 'boolean' }
+ expose :commit_events, documentation: { type: 'boolean' }
+ expose :push_events, documentation: { type: 'boolean' }
+ expose :issues_events, documentation: { type: 'boolean' }
+ expose :confidential_issues_events, documentation: { type: 'boolean' }
+ expose :merge_requests_events, documentation: { type: 'boolean' }
+ expose :tag_push_events, documentation: { type: 'boolean' }
+ expose :note_events, documentation: { type: 'boolean' }
+ expose :confidential_note_events, documentation: { type: 'boolean' }
+ expose :pipeline_events, documentation: { type: 'boolean' }
+ expose :wiki_page_events, documentation: { type: 'boolean' }
+ expose :job_events, documentation: { type: 'boolean' }
+ expose :comment_on_event_enabled, documentation: { type: 'boolean' }
end
end
end
diff --git a/lib/api/entities/project_repository_storage.rb b/lib/api/entities/project_repository_storage.rb
index 0816bebde2c..ae5039601d7 100644
--- a/lib/api/entities/project_repository_storage.rb
+++ b/lib/api/entities/project_repository_storage.rb
@@ -5,12 +5,16 @@ module API
class ProjectRepositoryStorage < Grape::Entity
include Gitlab::Routing
- expose :disk_path do |project|
+ expose :disk_path, documentation: {
+ type: 'string',
+ example: '@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b'
+ } do |project|
project.repository.disk_path
end
- expose :id, as: :project_id
- expose :repository_storage, :created_at
+ expose :id, as: :project_id, documentation: { type: 'integer', example: 1 }
+ expose :repository_storage, documentation: { type: 'string', example: 'default' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2012-10-12T17:04:47Z' }
end
end
end
diff --git a/lib/api/entities/project_with_access.rb b/lib/api/entities/project_with_access.rb
index b541ccbadcf..9722b8806d4 100644
--- a/lib/api/entities/project_with_access.rb
+++ b/lib/api/entities/project_with_access.rb
@@ -25,23 +25,41 @@ module API
# rubocop: disable CodeReuse/ActiveRecord
def self.preload_relation(projects_relation, options = {})
- relation = super(projects_relation, options)
- # use reselect to override the existing select and
- # prevent an error `subquery has too many columns`
- project_ids = relation.reselect('projects.id')
- namespace_ids = relation.reselect(:namespace_id)
+ if ::Feature.enabled?(:projects_preloader_fix)
+ super(projects_relation, options)
+ else
+ relation = super(projects_relation, options)
+ # use reselect to override the existing select and
+ # prevent an error `subquery has too many columns`
+ project_ids = relation.reselect('projects.id')
+ namespace_ids = relation.reselect(:namespace_id)
+
+ options[:project_members] = options[:current_user]
+ .project_members
+ .where(source_id: project_ids)
+ .preload(:source, user: [notification_settings: :source])
+
+ options[:group_members] = options[:current_user]
+ .group_members
+ .where(source_id: namespace_ids)
+ .preload(:source, user: [notification_settings: :source])
+
+ relation
+ end
+ end
+
+ def self.postload_relation(projects_relation, options = {})
+ return unless ::Feature.enabled?(:projects_preloader_fix)
options[:project_members] = options[:current_user]
.project_members
- .where(source_id: project_ids)
+ .where(source_id: projects_relation.subquery(:id))
.preload(:source, user: [notification_settings: :source])
options[:group_members] = options[:current_user]
.group_members
- .where(source_id: namespace_ids)
+ .where(source_id: projects_relation.subquery(:namespace_id))
.preload(:source, user: [notification_settings: :source])
-
- relation
end
# rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/lib/api/entities/protected_branch.rb b/lib/api/entities/protected_branch.rb
index ac44d06e69c..42f721b40a6 100644
--- a/lib/api/entities/protected_branch.rb
+++ b/lib/api/entities/protected_branch.rb
@@ -3,11 +3,11 @@
module API
module Entities
class ProtectedBranch < Grape::Entity
- expose :id
- expose :name
- expose :push_access_levels, using: Entities::ProtectedRefAccess
- expose :merge_access_levels, using: Entities::ProtectedRefAccess
- expose :allow_force_push
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'main' }
+ expose :push_access_levels, using: Entities::ProtectedRefAccess, documentation: { is_array: true }
+ expose :merge_access_levels, using: Entities::ProtectedRefAccess, documentation: { is_array: true }
+ expose :allow_force_push, documentation: { type: 'boolean' }
end
end
end
diff --git a/lib/api/entities/protected_ref_access.rb b/lib/api/entities/protected_ref_access.rb
index 443277e23cf..ba28c724448 100644
--- a/lib/api/entities/protected_ref_access.rb
+++ b/lib/api/entities/protected_ref_access.rb
@@ -3,10 +3,12 @@
module API
module Entities
class ProtectedRefAccess < Grape::Entity
- expose :access_level
- expose :access_level_description do |protected_ref_access|
- protected_ref_access.humanize
- end
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :access_level, documentation: { type: 'integer', example: 40 }
+ expose :access_level_description,
+ documentation: { type: 'string', example: 'Maintainers' } do |protected_ref_access|
+ protected_ref_access.humanize
+ end
end
end
end
diff --git a/lib/api/entities/protected_tag.rb b/lib/api/entities/protected_tag.rb
index dc397f01af6..ba984ae79b8 100644
--- a/lib/api/entities/protected_tag.rb
+++ b/lib/api/entities/protected_tag.rb
@@ -3,7 +3,7 @@
module API
module Entities
class ProtectedTag < Grape::Entity
- expose :name
+ expose :name, documentation: { type: 'string', example: 'release-1-0' }
expose :create_access_levels, using: Entities::ProtectedRefAccess
end
end
diff --git a/lib/api/entities/pull_mirror.rb b/lib/api/entities/pull_mirror.rb
new file mode 100644
index 00000000000..72a5220987e
--- /dev/null
+++ b/lib/api/entities/pull_mirror.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class PullMirror < Grape::Entity
+ expose :id, documentation: { type: 'integer', example: 101486 }
+ expose :status, as: :update_status, documentation: { type: 'string', example: 'finished' }
+ expose :url,
+documentation: { type: 'string',
+ example: 'https://*****:*****@gitlab.com/gitlab-org/security/gitlab.git' } do |import_state|
+ import_state.project.safe_import_url
+ end
+ expose :last_error, documentation: { type: 'string', example: nil }
+ expose :last_update_at, documentation: { type: 'dateTime', example: '2020-01-06T17:32:02.823Z' }
+ expose :last_update_started_at, documentation: { type: 'dateTime', example: '2020-01-06T17:32:02.823Z' }
+ expose :last_successful_update_at, documentation: { type: 'dateTime', example: '2020-01-06T17:32:02.823Z' }
+ end
+ end
+end
diff --git a/lib/api/entities/release.rb b/lib/api/entities/release.rb
index 2403c907f7f..c1a48a46d64 100644
--- a/lib/api/entities/release.rb
+++ b/lib/api/entities/release.rb
@@ -9,22 +9,24 @@ module API
MarkupHelper.markdown_field(entity, :description, current_user: options[:current_user])
end
expose :author, using: Entities::UserBasic, if: -> (release, _) { release.author.present? }
- expose :commit, using: Entities::Commit, if: ->(_, _) { can_download_code? }
+ expose :commit, using: Entities::Commit, if: ->(_, _) { can_read_code? }
expose :milestones,
using: Entities::MilestoneWithStats,
if: -> (release, _) { release.milestones.present? && can_read_milestone? } do |release, _|
release.milestones.order_by_dates_and_title
end
- expose :commit_path, expose_nil: false
- expose :tag_path, expose_nil: false
+ expose :commit_path,
+ documentation: { type: 'string', example: '/root/app/commit/588440f66559714280628a4f9799f0c4eb880a4a' },
+ expose_nil: false
+ expose :tag_path, documentation: { type: 'string', example: '/root/app/-/tags/v1.0' }, expose_nil: false
expose :assets do
- expose :assets_count, as: :count
- expose :sources, using: Entities::Releases::Source, if: ->(_, _) { can_download_code? }
+ expose :assets_count, documentation: { type: 'integer', example: 2 }, as: :count
+ expose :sources, using: Entities::Releases::Source, if: ->(_, _) { can_read_code? }
expose :sorted_links, as: :links, using: Entities::Releases::Link
end
- expose :evidences, using: Entities::Releases::Evidence, expose_nil: false, if: ->(_, _) { can_download_code? }
+ expose :evidences, using: Entities::Releases::Evidence, expose_nil: false, if: ->(_, _) { can_read_code? }
expose :_links do
expose :self_url, as: :self, expose_nil: false
expose :edit_url, expose_nil: false
@@ -32,8 +34,8 @@ module API
private
- def can_download_code?
- Ability.allowed?(options[:current_user], :download_code, object.project)
+ def can_read_code?
+ Ability.allowed?(options[:current_user], :read_code, object.project)
end
def can_read_milestone?
diff --git a/lib/api/entities/releases/evidence.rb b/lib/api/entities/releases/evidence.rb
index 01603a71dbf..9d324309213 100644
--- a/lib/api/entities/releases/evidence.rb
+++ b/lib/api/entities/releases/evidence.rb
@@ -6,9 +6,9 @@ module API
class Evidence < Grape::Entity
include ::API::Helpers::Presentable
- expose :sha
- expose :filepath
- expose :collected_at
+ expose :sha, documentation: { type: 'string', example: '760d6cdfb0879c3ffedec13af470e0f71cf52c6cde4d' }
+ expose :filepath, documentation: { type: 'string', example: 'https://gitlab.example.com/root/app/-/releases/v1.0/evidence.json' }
+ expose :collected_at, documentation: { type: 'dateTime', example: '2019-01-03T01:56:19.539Z' }
end
end
end
diff --git a/lib/api/entities/releases/link.rb b/lib/api/entities/releases/link.rb
index 5157645af69..abf380e11d5 100644
--- a/lib/api/entities/releases/link.rb
+++ b/lib/api/entities/releases/link.rb
@@ -4,14 +4,22 @@ module API
module Entities
module Releases
class Link < Grape::Entity
- expose :id
- expose :name
- expose :url
- expose :direct_asset_url do |link|
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :name, documentation: { type: 'string', example: 'app-v1.0.dmg' }
+ expose :url, documentation:
+ {
+ type: 'string',
+ example: 'https://gitlab.example.com/root/app/-/jobs/688/artifacts/raw/bin/app-v1.0.dmg'
+ }
+ expose :direct_asset_url, documentation:
+ {
+ type: 'string',
+ example: 'https://gitlab.example.com/root/app/-/releases/v1.0/downloads/app-v1.0.dmg'
+ } do |link|
::Releases::LinkPresenter.new(link).direct_asset_url
end
- expose :external?, as: :external
- expose :link_type
+ expose :external?, documentation: { type: 'boolean' }, as: :external
+ expose :link_type, documentation: { type: 'string', example: 'other' }
end
end
end
diff --git a/lib/api/entities/releases/source.rb b/lib/api/entities/releases/source.rb
index 2b0c8038ddf..8c6750d6142 100644
--- a/lib/api/entities/releases/source.rb
+++ b/lib/api/entities/releases/source.rb
@@ -4,8 +4,8 @@ module API
module Entities
module Releases
class Source < Grape::Entity
- expose :format
- expose :url
+ expose :format, documentation: { type: 'string', example: 'zip' }
+ expose :url, documentation: { type: 'string', example: 'https://gitlab.example.com/root/app/-/archive/v1.0/app-v1.0.zip' }
end
end
end
diff --git a/lib/api/entities/remote_mirror.rb b/lib/api/entities/remote_mirror.rb
index 87daef9a05c..9fb5b2697bc 100644
--- a/lib/api/entities/remote_mirror.rb
+++ b/lib/api/entities/remote_mirror.rb
@@ -3,16 +3,16 @@
module API
module Entities
class RemoteMirror < Grape::Entity
- expose :id
- expose :enabled
- expose :safe_url, as: :url
- expose :update_status
- expose :last_update_at
- expose :last_update_started_at
- expose :last_successful_update_at
- expose :last_error
- expose :only_protected_branches
- expose :keep_divergent_refs
+ expose :id, documentation: { type: 'integer', example: 101486 }
+ expose :enabled, documentation: { type: 'boolean', example: true }
+ expose :safe_url, as: :url, documentation: { type: 'string', example: 'https://*****:*****@example.com/gitlab/example.git' }
+ expose :update_status, documentation: { type: 'string', example: 'finished' }
+ expose :last_update_at, documentation: { type: 'dateTime', example: '2020-01-06T17:32:02.823Z' }
+ expose :last_update_started_at, documentation: { type: 'dateTime', example: '2020-01-06T17:32:02.823Z' }
+ expose :last_successful_update_at, documentation: { type: 'dateTime', example: '2020-01-06T17:31:55.864Z' }
+ expose :last_error, documentation: { type: 'integer', example: 'The remote mirror URL is invalid.' }
+ expose :only_protected_branches, documentation: { type: 'boolean' }
+ expose :keep_divergent_refs, documentation: { type: 'boolean' }
end
end
end
diff --git a/lib/api/entities/resource_access_token.rb b/lib/api/entities/resource_access_token.rb
index 569fd16f488..e4f140d3fc0 100644
--- a/lib/api/entities/resource_access_token.rb
+++ b/lib/api/entities/resource_access_token.rb
@@ -3,7 +3,12 @@
module API
module Entities
class ResourceAccessToken < Entities::PersonalAccessToken
- expose :access_level do |token, options|
+ expose :access_level,
+ documentation: { type: 'integer',
+ example: 40,
+ description: 'Access level. Valid values are 10 (Guest), 20 (Reporter), 30 (Developer) \
+ , 40 (Maintainer), and 50 (Owner). Defaults to 40.',
+ values: [10, 20, 30, 40, 50] } do |token, options|
options[:resource].member(token.user).access_level
end
end
diff --git a/lib/api/entities/resource_milestone_event.rb b/lib/api/entities/resource_milestone_event.rb
index 26dc6620cbe..b301f5b7d0a 100644
--- a/lib/api/entities/resource_milestone_event.rb
+++ b/lib/api/entities/resource_milestone_event.rb
@@ -3,18 +3,18 @@
module API
module Entities
class ResourceMilestoneEvent < Grape::Entity
- expose :id
+ expose :id, documentation: { type: 'integer', example: 142 }
expose :user, using: Entities::UserBasic
- expose :created_at
- expose :resource_type do |event, _options|
+ expose :created_at, documentation: { type: 'dateTime', example: '2018-08-20T13:38:20.077Z' }
+ expose :resource_type, documentation: { type: 'string', example: 'Issue' } do |event, _options|
event.issuable.class.name
end
- expose :resource_id do |event, _options|
+ expose :resource_id, documentation: { type: 'integer', example: 253 } do |event, _options|
event.issuable.id
end
expose :milestone, using: Entities::Milestone
- expose :action
- expose :state
+ expose :action, documentation: { type: 'string', example: 'add' }
+ expose :state, documentation: { type: 'string', example: 'active' }
end
end
end
diff --git a/lib/api/entities/snippet.rb b/lib/api/entities/snippet.rb
index af885aaf0eb..709566944ed 100644
--- a/lib/api/entities/snippet.rb
+++ b/lib/api/entities/snippet.rb
@@ -3,11 +3,13 @@
module API
module Entities
class Snippet < BasicSnippet
- expose :author, using: Entities::UserBasic
- expose :file_name do |snippet|
+ expose :author, using: Entities::UserBasic, documentation: { type: 'Entities::UserBasic' }
+ expose :file_name, documentation: { type: 'string', example: 'add.rb' } do |snippet|
snippet_files.first || snippet.file_name
end
- expose :files do |snippet, options|
+ expose :files, documentation: {
+ is_array: true, example: 'e0d123e5f316bef78bfdf5a008837577'
+ } do |snippet, options|
snippet_files.map do |file|
{
path: file,
diff --git a/lib/api/entities/snippets/repository_storage_move.rb b/lib/api/entities/snippets/repository_storage_move.rb
index 4e14d1dfba2..711d07545fb 100644
--- a/lib/api/entities/snippets/repository_storage_move.rb
+++ b/lib/api/entities/snippets/repository_storage_move.rb
@@ -4,7 +4,7 @@ module API
module Entities
module Snippets
class RepositoryStorageMove < BasicRepositoryStorageMove
- expose :snippet, using: Entities::BasicSnippet
+ expose :snippet, using: Entities::BasicSnippet, documentation: { type: 'Entities::BasicSnippet' }
end
end
end
diff --git a/lib/api/entities/ssh_key.rb b/lib/api/entities/ssh_key.rb
index e1554730cb6..3db10bb8ec2 100644
--- a/lib/api/entities/ssh_key.rb
+++ b/lib/api/entities/ssh_key.rb
@@ -3,8 +3,15 @@
module API
module Entities
class SSHKey < Grape::Entity
- expose :id, :title, :created_at, :expires_at
- expose :publishable_key, as: :key
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :title, documentation: { type: 'string', example: 'Sample key 25' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2015-09-03T07:24:44.627Z' }
+ expose :expires_at, documentation: { type: 'dateTime', example: '2020-09-03T07:24:44.627Z' }
+ expose :publishable_key, as: :key, documentation:
+ { type: 'string',
+ example: 'ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt1256k6Yjz\
+ GGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCdd\
+ NaP0L+hM7zhFNzjFvpaMgJw0=' }
end
end
end
diff --git a/lib/api/entities/tag.rb b/lib/api/entities/tag.rb
index 2d3569bb9bb..713bae64d5c 100644
--- a/lib/api/entities/tag.rb
+++ b/lib/api/entities/tag.rb
@@ -3,7 +3,9 @@
module API
module Entities
class Tag < Grape::Entity
- expose :name, :message, :target
+ expose :name, documentation: { type: 'string', example: 'v1.0.0' }
+ expose :message, documentation: { type: 'string', example: 'Release v1.0.0' }
+ expose :target, documentation: { type: 'string', example: '2695effb5807a22ff3d138d593fd856244e155e7' }
expose :commit, using: Entities::Commit do |repo_tag, options|
options[:project].repository.commit(repo_tag.dereferenced_target)
@@ -15,7 +17,7 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
- expose :protected do |repo_tag, options|
+ expose :protected, documentation: { type: 'boolean', example: true } do |repo_tag, options|
::ProtectedTag.protected?(options[:project], repo_tag.name)
end
end
diff --git a/lib/api/entities/tag_release.rb b/lib/api/entities/tag_release.rb
index d5f73d60332..66d1eeeab4a 100644
--- a/lib/api/entities/tag_release.rb
+++ b/lib/api/entities/tag_release.rb
@@ -4,8 +4,8 @@ module API
module Entities
# deprecated old Release representation
class TagRelease < Grape::Entity
- expose :tag, as: :tag_name
- expose :description
+ expose :tag, as: :tag_name, documentation: { type: 'string', example: '1.0.0' }
+ expose :description, documentation: { type: 'string', example: 'Amazing release. Wow' }
end
end
end
diff --git a/lib/api/entities/templates_list.rb b/lib/api/entities/templates_list.rb
index 8e8aa1bd285..eba80bd04d3 100644
--- a/lib/api/entities/templates_list.rb
+++ b/lib/api/entities/templates_list.rb
@@ -3,8 +3,8 @@
module API
module Entities
class TemplatesList < Grape::Entity
- expose :key
- expose :name
+ expose :key, documentation: { type: 'string', example: 'mit' }
+ expose :name, documentation: { type: 'string', example: 'MIT License' }
end
end
end
diff --git a/lib/api/entities/tree_object.rb b/lib/api/entities/tree_object.rb
index e4e840ebe43..1f542885169 100644
--- a/lib/api/entities/tree_object.rb
+++ b/lib/api/entities/tree_object.rb
@@ -3,9 +3,12 @@
module API
module Entities
class TreeObject < Grape::Entity
- expose :id, :name, :type, :path
+ expose :id, documentation: { example: 'a1e8f8d745cc87e3a9248358d9352bb7f9a0aeba' }
+ expose :name, documentation: { example: 'html' }
+ expose :type, documentation: { example: 'tree' }
+ expose :path, documentation: { example: 'files/html' }
- expose :mode do |obj, options|
+ expose :mode, documentation: { example: '040000' } do |obj, options|
filemode = obj.mode
filemode = "0" + filemode if filemode.length < 6
filemode
diff --git a/lib/api/entities/trigger.rb b/lib/api/entities/trigger.rb
index 6a9f772fc6b..ccdaeb6a07a 100644
--- a/lib/api/entities/trigger.rb
+++ b/lib/api/entities/trigger.rb
@@ -5,10 +5,12 @@ module API
class Trigger < Grape::Entity
include ::API::Helpers::Presentable
- expose :id
- expose :token
- expose :description
- expose :created_at, :updated_at, :last_used
+ expose :id, documentation: { type: 'integer', example: 10 }
+ expose :token, documentation: { type: 'string', example: '6d056f63e50fe6f8c5f8f4aa10edb7' }
+ expose :description, documentation: { type: 'string', example: 'test' }
+ expose :created_at, documentation: { type: 'dateTime', example: '2015-12-24T15:51:21.880Z' }
+ expose :updated_at, documentation: { type: 'dateTime', example: '2015-12-24T17:54:31.198Z' }
+ expose :last_used, documentation: { type: 'dateTime', example: '2015-12-24T17:54:31.198Z' }
expose :owner, using: Entities::UserBasic
end
end
diff --git a/lib/api/entities/user_agent_detail.rb b/lib/api/entities/user_agent_detail.rb
index a2d02c16589..eb6d909794e 100644
--- a/lib/api/entities/user_agent_detail.rb
+++ b/lib/api/entities/user_agent_detail.rb
@@ -3,9 +3,9 @@
module API
module Entities
class UserAgentDetail < Grape::Entity
- expose :user_agent
- expose :ip_address
- expose :submitted, as: :akismet_submitted
+ expose :user_agent, documentation: { type: 'string', example: 'AppleWebKit/537.36' }
+ expose :ip_address, documentation: { type: 'string', example: '127.0.0.1' }
+ expose :submitted, as: :akismet_submitted, documentation: { type: 'boolean', example: false }
end
end
end
diff --git a/lib/api/entities/user_associations_count.rb b/lib/api/entities/user_associations_count.rb
new file mode 100644
index 00000000000..af744d2d49a
--- /dev/null
+++ b/lib/api/entities/user_associations_count.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class UserAssociationsCount < Grape::Entity
+ expose :groups_count do |user|
+ user.groups.size
+ end
+
+ expose :projects_count do |user|
+ user.projects.size
+ end
+
+ expose :issues_count do |user|
+ user.issues.size
+ end
+
+ expose :merge_requests_count do |user|
+ user.merge_requests.size
+ end
+ end
+ end
+end
diff --git a/lib/api/entities/user_basic.rb b/lib/api/entities/user_basic.rb
index b8ee4e5a6e0..32e066b9f7e 100644
--- a/lib/api/entities/user_basic.rb
+++ b/lib/api/entities/user_basic.rb
@@ -3,16 +3,25 @@
module API
module Entities
class UserBasic < UserSafe
- expose :state
+ expose :state, documentation: { type: 'string', example: 'active' }
- expose :avatar_url do |user, options|
+ expose :avatar_url, documentation: { type: 'string', example: 'https://gravatar.com/avatar/1' } do |user, options|
user.avatar_url(only_path: false)
end
- expose :avatar_path, if: ->(user, options) { options.fetch(:only_path, false) && user.avatar_path }
- expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes
+ expose(
+ :avatar_path,
+ documentation: {
+ type: 'string',
+ example: '/user/avatar/28/The-Big-Lebowski-400-400.png'
+ },
+ if: ->(user, options) { options.fetch(:only_path, false) && user.avatar_path }
+ )
- expose :web_url do |user, options|
+ expose :custom_attributes, using: 'API::Entities::CustomAttribute', if: :with_custom_attributes,
+ documentation: { is_array: true }
+
+ expose :web_url, documentation: { type: 'string', example: 'https://gitlab.example.com/root' } do |user, options|
Gitlab::Routing.url_helpers.user_url(user)
end
end
diff --git a/lib/api/entities/user_counts.rb b/lib/api/entities/user_counts.rb
new file mode 100644
index 00000000000..e86454c249b
--- /dev/null
+++ b/lib/api/entities/user_counts.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module API
+ module Entities
+ class UserCounts < Grape::Entity
+ expose(
+ :assigned_open_merge_requests_count, # @deprecated
+ as: :merge_requests,
+ documentation: { type: 'integer', example: 10 }
+ )
+ expose :assigned_open_issues_count, as: :assigned_issues, documentation: { type: 'integer', example: 10 }
+ expose(
+ :assigned_open_merge_requests_count,
+ as: :assigned_merge_requests,
+ documentation: { type: 'integer', example: 10 }
+ )
+ expose(
+ :review_requested_open_merge_requests_count,
+ as: :review_requested_merge_requests,
+ documentation: { type: 'integer', example: 10 }
+ )
+ expose :todos_pending_count, as: :todos, documentation: { type: 'integer', example: 10 }
+ end
+ end
+end
diff --git a/lib/api/entities/user_public.rb b/lib/api/entities/user_public.rb
index 5d0e464abe1..eda72d2cfc6 100644
--- a/lib/api/entities/user_public.rb
+++ b/lib/api/entities/user_public.rb
@@ -3,17 +3,23 @@
module API
module Entities
class UserPublic < Entities::User
- expose :last_sign_in_at
- expose :confirmed_at
- expose :last_activity_on
- expose :email
- expose :theme_id, :color_scheme_id, :projects_limit, :current_sign_in_at
+ expose :last_sign_in_at, documentation: { type: 'dateTime', example: '2015-09-03T07:24:01.670Z' }
+ expose :confirmed_at, documentation: { type: 'dateTime', example: '2015-09-03T07:24:01.670Z' }
+ expose :last_activity_on, documentation: { type: 'dateTime', example: '2015-09-03T07:24:01.670Z' }
+ expose :email, documentation: { type: 'string', example: 'john@example.com' }
+ expose :theme_id, documentation: { type: 'integer', example: 2 }
+ expose :color_scheme_id, documentation: { type: 'integer', example: 1 }
+ expose :projects_limit, documentation: { type: 'integer', example: 10 }
+ expose :current_sign_in_at, documentation: { type: 'dateTime', example: '2015-09-03T07:24:01.670Z' }
expose :identities, using: Entities::Identity
- expose :can_create_group?, as: :can_create_group
- expose :can_create_project?, as: :can_create_project
- expose :two_factor_enabled?, as: :two_factor_enabled
+ expose :can_create_group?, as: :can_create_group, documentation: { type: 'boolean', example: true }
+ expose :can_create_project?, as: :can_create_project, documentation: { type: 'boolean', example: true }
+
+ expose :two_factor_enabled?, as: :two_factor_enabled, documentation: { type: 'boolean', example: true }
+
expose :external
- expose :private_profile
+
+ expose :private_profile, documentation: { type: 'boolean', example: :null }
expose :commit_email_or_default, as: :commit_email
end
end
diff --git a/lib/api/entities/user_safe.rb b/lib/api/entities/user_safe.rb
index 127a8ef2160..0fbb10307cf 100644
--- a/lib/api/entities/user_safe.rb
+++ b/lib/api/entities/user_safe.rb
@@ -5,8 +5,9 @@ module API
class UserSafe < Grape::Entity
include RequestAwareEntity
- expose :id, :username
- expose :name do |user|
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :username, documentation: { type: 'string', example: 'admin' }
+ expose :name, documentation: { type: 'string', example: 'Administrator' } do |user|
current_user = request.respond_to?(:current_user) ? request.current_user : options.fetch(:current_user, nil)
user.redacted_name(current_user)
diff --git a/lib/api/entities/wiki_attachment.rb b/lib/api/entities/wiki_attachment.rb
index 03a6cc8d644..8629261cfc6 100644
--- a/lib/api/entities/wiki_attachment.rb
+++ b/lib/api/entities/wiki_attachment.rb
@@ -5,12 +5,16 @@ module API
class WikiAttachment < Grape::Entity
include Gitlab::FileMarkdownLinkBuilder
- expose :file_name
- expose :file_path
- expose :branch
+ expose :file_name, documentation: { type: 'string', example: 'dk.png' }
+ expose :file_path, documentation: { type: 'string', example: 'uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png' }
+ expose :branch, documentation: { type: 'string', example: 'main' }
expose :link do
- expose :file_path, as: :url
- expose :markdown do |_entity|
+ expose :file_path, as: :url, documentation: {
+ type: 'string', example: 'uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png'
+ }
+ expose :markdown, documentation: {
+ type: 'string', example: '![dk](uploads/6a061c4cf9f1c28cb22c384b4b8d4e3c/dk.png)'
+ } do |_entity|
self.markdown_link
end
end
diff --git a/lib/api/entities/wiki_page.rb b/lib/api/entities/wiki_page.rb
index 5bba4271396..07ef4a4a156 100644
--- a/lib/api/entities/wiki_page.rb
+++ b/lib/api/entities/wiki_page.rb
@@ -5,7 +5,9 @@ module API
class WikiPage < WikiPageBasic
include ::MarkupHelper
- expose :content do |wiki_page, options|
+ expose :content, documentation: {
+ type: 'string', example: 'Here is an instruction how to deploy this project.'
+ } do |wiki_page, options|
if options[:render_html]
render_wiki_content(
wiki_page,
@@ -17,7 +19,7 @@ module API
end
end
- expose :encoding do |wiki_page|
+ expose :encoding, documentation: { type: 'string', example: 'UTF-8' } do |wiki_page|
wiki_page.content.encoding.name
end
end
diff --git a/lib/api/entities/wiki_page_basic.rb b/lib/api/entities/wiki_page_basic.rb
index e10c0e6d553..088a0d1bf55 100644
--- a/lib/api/entities/wiki_page_basic.rb
+++ b/lib/api/entities/wiki_page_basic.rb
@@ -3,9 +3,9 @@
module API
module Entities
class WikiPageBasic < Grape::Entity
- expose :format
- expose :slug
- expose :title
+ expose :format, documentation: { type: 'string', example: 'markdown' }
+ expose :slug, documentation: { type: 'string', example: 'deploy' }
+ expose :title, documentation: { type: 'string', example: 'deploy' }
end
end
end
diff --git a/lib/api/entities/x509_certificate.rb b/lib/api/entities/x509_certificate.rb
index aad11339148..95d4948906e 100644
--- a/lib/api/entities/x509_certificate.rb
+++ b/lib/api/entities/x509_certificate.rb
@@ -3,13 +3,16 @@
module API
module Entities
class X509Certificate < Grape::Entity
- expose :id
- expose :subject
- expose :subject_key_identifier
- expose :email
- expose :serial_number
- expose :certificate_status
- expose :x509_issuer, using: 'API::Entities::X509Issuer'
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :subject, documentation: { type: 'string', example: 'CN=gitlab@example.org,OU=Example,O=World' }
+ expose :subject_key_identifier, documentation: {
+ type: 'string',
+ example: 'BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC:BC'
+ }
+ expose :email, documentation: { type: 'string', example: 'gitlab@example.org' }
+ expose :serial_number, documentation: { type: 'integer', example: 278969561018901340486471282831158785578 }
+ expose :certificate_status, documentation: { type: 'string', example: 'good' }
+ expose :x509_issuer, using: 'API::Entities::X509Issuer', documentation: { type: 'string', example: '100755' }
end
end
end
diff --git a/lib/api/entities/x509_issuer.rb b/lib/api/entities/x509_issuer.rb
index b480bc107bc..22429560c72 100644
--- a/lib/api/entities/x509_issuer.rb
+++ b/lib/api/entities/x509_issuer.rb
@@ -3,10 +3,13 @@
module API
module Entities
class X509Issuer < Grape::Entity
- expose :id
- expose :subject
- expose :subject_key_identifier
- expose :crl_url
+ expose :id, documentation: { type: 'integer', example: 1 }
+ expose :subject, documentation: { type: 'string', example: 'CN=PKI,OU=Example,O=World' }
+ expose :subject_key_identifier, documentation: {
+ type: 'string',
+ example: 'AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB:AB'
+ }
+ expose :crl_url, documentation: { type: 'string', example: 'http://example.com/pki.crl' }
end
end
end
diff --git a/lib/api/entities/x509_signature.rb b/lib/api/entities/x509_signature.rb
index 909b630288c..c3f0cb3659d 100644
--- a/lib/api/entities/x509_signature.rb
+++ b/lib/api/entities/x509_signature.rb
@@ -3,7 +3,7 @@
module API
module Entities
class X509Signature < Grape::Entity
- expose :verification_status
+ expose :verification_status, documentation: { type: 'string', example: 'unverified' }
expose :x509_certificate, using: 'API::Entities::X509Certificate'
end
end
diff --git a/lib/api/environments.rb b/lib/api/environments.rb
index 42d5e6a73b3..01d46ee7bfb 100644
--- a/lib/api/environments.rb
+++ b/lib/api/environments.rb
@@ -5,24 +5,35 @@ module API
class Environments < ::API::Base
include PaginationParams
+ environments_tags = %w[environments]
+
before { authenticate! }
feature_category :continuous_delivery
urgency :low
params do
- requires :id, type: String, desc: 'The project ID'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get all environments of the project' do
- detail 'This feature was introduced in GitLab 8.11.'
+ desc 'List environments' do
+ detail 'Get all environments for a given project. This feature was introduced in GitLab 8.11.'
success Entities::Environment
+ is_array true
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags environments_tags
end
params do
use :pagination
- optional :name, type: String, desc: 'Returns the environment with this name'
- optional :search, type: String, desc: 'Returns list of environments matching the search criteria'
- optional :states, type: String, values: Environment.valid_states.map(&:to_s), desc: 'List all environments that match a specific state'
+ optional :name, type: String, desc: 'Return the environment with this name. Mutually exclusive with search'
+ optional :search, type: String, desc: 'Return list of environments matching the search criteria. Mutually exclusive with name'
+ optional :states,
+ type: String,
+ values: Environment.valid_states.map(&:to_s),
+ desc: 'List all environments that match a specific state. Accepted values: `available`, `stopping`, or `stopped`. If no state value given, returns all environments'
mutually_exclusive :name, :search, message: 'cannot be used together'
end
get ':id/environments' do
@@ -33,15 +44,21 @@ module API
present paginate(environments), with: Entities::Environment, current_user: current_user
end
- desc 'Creates a new environment' do
- detail 'This feature was introduced in GitLab 8.11.'
+ desc 'Create a new environment' do
+ detail 'Creates a new environment with the given name and `external_url`. It returns `201` if the environment was successfully created, `400` for wrong parameters. This feature was introduced in GitLab 8.11.'
success Entities::Environment
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags environments_tags
end
params do
- requires :name, type: String, desc: 'The name of the environment to be created'
- optional :external_url, type: String, desc: 'URL on which this deployment is viewable'
+ requires :name, type: String, desc: 'The name of the environment'
+ optional :external_url, type: String, desc: 'Place to link to for this environment'
optional :slug, absence: { message: "is automatically generated and cannot be changed" }, documentation: { hidden: true }
- optional :tier, type: String, values: Environment.tiers.keys, desc: 'The tier of the environment to be created'
+ optional :tier, type: String, values: Environment.tiers.keys, desc: 'The tier of the new environment. Allowed values are `production`, `staging`, `testing`, `development`, and `other`'
end
post ':id/environments' do
authorize! :create_environment, user_project
@@ -55,17 +72,23 @@ module API
end
end
- desc 'Updates an existing environment' do
- detail 'This feature was introduced in GitLab 8.11.'
+ desc 'Update an existing environment' do
+ detail 'Updates an existing environment name and/or `external_url`. It returns `200` if the environment was successfully updated. In case of an error, a status code `400` is returned. This feature was introduced in GitLab 8.11.'
success Entities::Environment
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags environments_tags
end
params do
- requires :environment_id, type: Integer, desc: 'The environment ID'
+ requires :environment_id, type: Integer, desc: 'The ID of the environment'
# TODO: disallow renaming via the API https://gitlab.com/gitlab-org/gitlab/-/issues/338897
optional :name, type: String, desc: 'DEPRECATED: Renaming environment can lead to errors, this will be removed in 15.0'
optional :external_url, type: String, desc: 'The new URL on which this deployment is viewable'
optional :slug, absence: { message: "is automatically generated and cannot be changed" }, documentation: { hidden: true }
- optional :tier, type: String, values: Environment.tiers.keys, desc: 'The tier of the environment to be created'
+ optional :tier, type: String, values: Environment.tiers.keys, desc: 'The tier of the new environment. Allowed values are `production`, `staging`, `testing`, `development`, and `other`'
end
put ':id/environments/:environment_id' do
authorize! :update_environment, user_project
@@ -80,14 +103,21 @@ module API
end
end
- desc "Delete multiple stopped review apps" do
- detail "Remove multiple stopped review environments older than a specific age"
+ desc 'Delete multiple stopped review apps' do
+ detail 'It schedules for deletion multiple environments that have already been stopped and are in the review app folder. The actual deletion is performed after 1 week from the time of execution. By default, it only deletes environments 30 days or older. You can change this default using the `before` parameter.'
success Entities::EnvironmentBasic
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Conflict' }
+ ]
+ tags environments_tags
end
params do
- optional :before, type: Time, desc: "The timestamp before which environments can be deleted. Defaults to 30 days ago.", default: -> { 30.days.ago }
- optional :limit, type: Integer, desc: "Maximum number of environments to delete. Defaults to 100.", default: 100, values: 1..1000
- optional :dry_run, type: Boolean, desc: "If set, perform a dry run where no actual deletions will be performed. Defaults to true.", default: true
+ optional :before, type: Time, desc: "The date before which environments can be deleted. Defaults to 30 days ago. Expected in ISO 8601 format (`YYYY-MM-DDTHH:MM:SSZ`)", default: -> { 30.days.ago }
+ optional :limit, type: Integer, desc: "Maximum number of environments to delete. Defaults to 100", default: 100, values: 1..1000
+ optional :dry_run, type: Boolean, desc: "Defaults to true for safety reasons. It performs a dry run where no actual deletion will be performed. Set to false to actually delete the environment", default: true
end
delete ":id/environments/review_apps" do
authorize! :read_environment, user_project
@@ -107,12 +137,17 @@ module API
end
end
- desc 'Deletes an existing environment' do
- detail 'This feature was introduced in GitLab 8.11.'
+ desc 'Delete an environment' do
+ detail 'It returns 204 if the environment was successfully deleted, and 404 if the environment does not exist. This feature was introduced in GitLab 8.11.'
success Entities::Environment
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[environments]
end
params do
- requires :environment_id, type: Integer, desc: 'The environment ID'
+ requires :environment_id, type: Integer, desc: 'The ID of the environment'
end
delete ':id/environments/:environment_id' do
authorize! :read_environment, user_project
@@ -123,12 +158,18 @@ module API
destroy_conditionally!(environment)
end
- desc 'Stops an existing environment' do
+ desc 'Stop an environment' do
+ detail 'It returns 200 if the environment was successfully stopped, and 404 if the environment does not exist.'
success Entities::Environment
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[environments]
end
params do
- requires :environment_id, type: Integer, desc: 'The environment ID'
- optional :force, type: Boolean, default: false
+ requires :environment_id, type: Integer, desc: 'The ID of the environment'
+ optional :force, type: Boolean, default: false, desc: 'Force environment to stop without executing `on_stop` actions'
end
post ':id/environments/:environment_id/stop' do
authorize! :read_environment, user_project
@@ -141,11 +182,16 @@ module API
present environment, with: Entities::Environment, current_user: current_user
end
- desc 'Get a single environment' do
+ desc 'Get a specific environment' do
success Entities::Environment
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[environments]
end
params do
- requires :environment_id, type: Integer, desc: 'The environment ID'
+ requires :environment_id, type: Integer, desc: 'The ID of the environment'
end
get ':id/environments/:environment_id' do
authorize! :read_environment, user_project
diff --git a/lib/api/error_tracking/client_keys.rb b/lib/api/error_tracking/client_keys.rb
index c1c378111a7..8a0a5e2a9b7 100644
--- a/lib/api/error_tracking/client_keys.rb
+++ b/lib/api/error_tracking/client_keys.rb
@@ -4,11 +4,14 @@ module API
class ErrorTracking::ClientKeys < ::API::Base
before { authenticate! }
+ ERROR_TRACKING_CLIENT_KEYS_TAGS = %w[error_tracking_client_keys].freeze
+
feature_category :error_tracking
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -17,9 +20,11 @@ module API
authorize! :admin_operations, user_project
end
- desc 'List all client keys' do
- detail 'This feature was introduced in GitLab 14.3.'
+ desc 'List project client keys' do
+ detail 'List all client keys. This feature was introduced in GitLab 14.3.'
success Entities::ErrorTracking::ClientKey
+ is_array true
+ tags ERROR_TRACKING_CLIENT_KEYS_TAGS
end
get '/client_keys' do
collection = user_project.error_tracking_client_keys
@@ -28,8 +33,10 @@ module API
end
desc 'Create a client key' do
- detail 'This feature was introduced in GitLab 14.3.'
+ detail 'Creates a new client key for a project. The public key attribute is generated automatically.'\
+ 'This feature was introduced in GitLab 14.3.'
success Entities::ErrorTracking::ClientKey
+ tags ERROR_TRACKING_CLIENT_KEYS_TAGS
end
post '/client_keys' do
key = user_project.error_tracking_client_keys.create!
@@ -38,8 +45,14 @@ module API
end
desc 'Delete a client key' do
- detail 'This feature was introduced in GitLab 14.3.'
+ detail 'Removes a client key from the project. This feature was introduced in GitLab 14.3.'
success Entities::ErrorTracking::ClientKey
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags ERROR_TRACKING_CLIENT_KEYS_TAGS
end
delete '/client_keys/:key_id' do
key = user_project.error_tracking_client_keys.find(params[:key_id])
diff --git a/lib/api/error_tracking/collector.rb b/lib/api/error_tracking/collector.rb
index eea0fd2bce9..e10125e02c6 100644
--- a/lib/api/error_tracking/collector.rb
+++ b/lib/api/error_tracking/collector.rb
@@ -67,7 +67,7 @@ module API
detail 'This feature was introduced in GitLab 14.1.'
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
post 'error_tracking/collector/api/:id/envelope' do
# There is a reason why we have such uncommon path.
@@ -119,7 +119,7 @@ module API
detail 'This feature was introduced in GitLab 14.1.'
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
post 'error_tracking/collector/api/:id/store' do
# There is a reason why we have such uncommon path.
diff --git a/lib/api/error_tracking/project_settings.rb b/lib/api/error_tracking/project_settings.rb
index fefc2098137..ec1d6a8b87f 100644
--- a/lib/api/error_tracking/project_settings.rb
+++ b/lib/api/error_tracking/project_settings.rb
@@ -4,6 +4,8 @@ module API
class ErrorTracking::ProjectSettings < ::API::Base
before { authenticate! }
+ ERROR_TRACKING_PROJECT_SETTINGS_TAGS = %w[error_tracking_project_settings].freeze
+
feature_category :error_tracking
urgency :low
@@ -14,7 +16,8 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -24,22 +27,35 @@ module API
not_found!('Error Tracking Setting') unless project_setting
end
- desc 'Get error tracking settings for the project' do
- detail 'This feature was introduced in GitLab 12.7.'
+ desc 'Get Error Tracking settings' do
+ detail 'Get error tracking settings for the project. This feature was introduced in GitLab 12.7.'
success Entities::ErrorTracking::ProjectSetting
+ tags ERROR_TRACKING_PROJECT_SETTINGS_TAGS
end
get ':id/error_tracking/settings' do
present project_setting, with: Entities::ErrorTracking::ProjectSetting
end
- desc 'Enable or disable error tracking settings for the project' do
- detail 'This feature was introduced in GitLab 12.8.'
+ desc 'Enable or disable the Error Tracking project settings' do
+ detail 'The API allows you to enable or disable the Error Tracking settings for a project.'\
+ 'Only for users with the 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: 'Specifying whether to enable or disable error tracking settings', allow_blank: false
- optional :integrated, type: Boolean, desc: 'Specifying whether to enable or disable integrated error tracking'
+ requires :active,
+ type: Boolean,
+ desc: 'Pass true to enable the already configured Error Tracking settings or false to disable it.',
+ allow_blank: false
+ optional :integrated,
+ type: Boolean,
+ desc: 'Pass true to enable the integrated Error Tracking backend. Available in GitLab 14.2 and later.'
end
patch ':id/error_tracking/settings/' do
diff --git a/lib/api/feature_flags.rb b/lib/api/feature_flags.rb
index 67e96284449..1846ddf6833 100644
--- a/lib/api/feature_flags.rb
+++ b/lib/api/feature_flags.rb
@@ -4,6 +4,8 @@ module API
class FeatureFlags < ::API::Base
include PaginationParams
+ feature_flags_tags = %w[feature_flags]
+
FEATURE_FLAG_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
.merge(name: API::NO_SLASH_URL_PART_REGEX)
@@ -15,18 +17,24 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
resource :feature_flags do
- desc 'Get all feature flags of a project' do
- detail 'This feature was introduced in GitLab 12.5'
+ desc 'List feature flags for a project' do
+ detail 'Gets all feature flags of the requested project. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags feature_flags_tags
end
params do
optional :scope,
type: String,
- desc: 'The scope of feature flags',
+ desc: 'The scope of feature flags, one of: `enabled`, `disabled`',
values: %w[enabled disabled]
use :pagination
end
@@ -39,22 +47,23 @@ module API
end
desc 'Create a new feature flag' do
- detail 'This feature was introduced in GitLab 12.5'
+ detail 'Creates a new feature flag. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' }
+ ]
+ tags feature_flags_tags
end
params do
- requires :name, type: String, desc: 'The name of feature flag'
+ requires :name, type: String, desc: 'The name of the feature flag'
optional :description, type: String, desc: 'The description of the feature flag'
- optional :active, type: Boolean, desc: 'Active/inactive value of the flag'
- optional :version, type: String, desc: 'The version of the feature flag'
- optional :scopes, type: Array do
- requires :environment_scope, type: String, desc: 'The environment scope of the scope'
- requires :active, type: Boolean, desc: 'Active/inactive of the scope'
- requires :strategies, type: JSON, desc: 'The strategies of the scope'
- end
+ optional :active, type: Boolean, desc: 'The active state of the flag. Defaults to `true`. Supported in GitLab 13.3 and later'
+ optional :version, type: String, desc: 'The version of the feature flag. Must be `new_version_flag`. Omit to create a Legacy feature flag.'
optional :strategies, type: Array do
- requires :name, type: String, desc: 'The strategy name'
- requires :parameters, type: JSON, desc: 'The strategy parameters'
+ requires :name, type: String, desc: 'The strategy name. Can be `default`, `gradualRolloutUserId`, `userWithId`, or `gitlabUserList`. In GitLab 13.5 and later, can be `flexibleRollout`'
+ requires :parameters, type: JSON, desc: 'The strategy parameters as a JSON-formatted string e.g. `{"userIds":"user1"}`', documentation: { type: 'String' }
optional :scopes, type: Array do
requires :environment_scope, type: String, desc: 'The environment scope of the scope'
end
@@ -87,9 +96,14 @@ module API
requires :feature_flag_name, type: String, desc: 'The name of the feature flag'
end
resource 'feature_flags/:feature_flag_name', requirements: FEATURE_FLAG_ENDPOINT_REQUIREMENTS do
- desc 'Get a feature flag of a project' do
- detail 'This feature was introduced in GitLab 12.5'
+ desc 'Get a single feature flag' do
+ detail 'Gets a single feature flag. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags feature_flags_tags
end
get do
authorize_read_feature_flag!
@@ -99,20 +113,27 @@ module API
end
desc 'Update a feature flag' do
- detail 'This feature was introduced in GitLab 13.2'
+ detail 'Updates a feature flag. This feature was introduced in GitLab 13.2.'
success ::API::Entities::FeatureFlag
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags feature_flags_tags
end
params do
- optional :name, type: String, desc: 'The name of the feature flag'
+ optional :name, type: String, desc: 'The new name of the feature flag. Supported in GitLab 13.3 and later'
optional :description, type: String, desc: 'The description of the feature flag'
- optional :active, type: Boolean, desc: 'Active/inactive value of the flag'
+ optional :active, type: Boolean, desc: 'The active state of the flag. Supported in GitLab 13.3 and later'
optional :strategies, type: Array do
- optional :id, type: Integer, desc: 'The strategy id'
- optional :name, type: String, desc: 'The strategy type'
- optional :parameters, type: JSON, desc: 'The strategy parameters'
+ optional :id, type: Integer, desc: 'The feature flag strategy ID'
+ optional :name, type: String, desc: 'The strategy name'
+ optional :parameters, type: JSON, desc: 'The strategy parameters as a JSON-formatted string e.g. `{"userIds":"user1"}`', documentation: { type: 'String' }
optional :_destroy, type: Boolean, desc: 'Delete the strategy when true'
optional :scopes, type: Array do
- optional :id, type: Integer, desc: 'The environment scope id'
+ optional :id, type: Integer, desc: 'The scope id'
optional :environment_scope, type: String, desc: 'The environment scope of the scope'
optional :_destroy, type: Boolean, desc: 'Delete the scope when true'
end
@@ -142,8 +163,14 @@ module API
end
desc 'Delete a feature flag' do
- detail 'This feature was introduced in GitLab 12.5'
+ detail 'Deletes a feature flag. This feature was introduced in GitLab 12.5.'
success ::API::Entities::FeatureFlag
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags feature_flags_tags
end
delete do
authorize_destroy_feature_flag!
diff --git a/lib/api/feature_flags_user_lists.rb b/lib/api/feature_flags_user_lists.rb
index f4771c07260..aed277d28a2 100644
--- a/lib/api/feature_flags_user_lists.rb
+++ b/lib/api/feature_flags_user_lists.rb
@@ -4,6 +4,8 @@ module API
class FeatureFlagsUserLists < ::API::Base
include PaginationParams
+ feature_flags_user_lists_tags = %w[feature_flags_user_lists]
+
error_formatter :json, -> (message, _backtrace, _options, _env, _original_exception) {
message.is_a?(String) ? { message: message }.to_json : message.to_json
}
@@ -16,16 +18,23 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
resource :feature_flags_user_lists do
- desc 'Get all feature flags user lists of a project' do
- detail 'This feature was introduced in GitLab 12.10'
+ desc 'List all feature flag user lists for a project' do
+ detail 'Gets all feature flag user lists for the requested project. ' \
+ 'This feature was introduced in GitLab 12.10.'
success ::API::Entities::FeatureFlag::UserList
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags feature_flags_user_lists_tags
end
params do
- optional :search, type: String, desc: 'Returns the list of user lists matching the search critiera'
+ optional :search, type: String, desc: 'Return user lists matching the search criteria'
use :pagination
end
@@ -35,9 +44,15 @@ module API
with: ::API::Entities::FeatureFlag::UserList
end
- desc 'Create a feature flags user list for a project' do
- detail 'This feature was introduced in GitLab 12.10'
+ desc 'Create a feature flag user list' do
+ detail 'Creates a feature flag user list. This feature was introduced in GitLab 12.10.'
success ::API::Entities::FeatureFlag::UserList
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags feature_flags_user_lists_tags
end
params do
requires :name, type: String, desc: 'The name of the list'
@@ -59,12 +74,17 @@ module API
end
params do
- requires :iid, type: String, desc: 'The internal ID of the user list'
+ requires :iid, types: [String, Integer], desc: "The internal ID of the project's feature flag user list"
end
resource 'feature_flags_user_lists/:iid' do
- desc 'Get a single feature flag user list belonging to a project' do
- detail 'This feature was introduced in GitLab 12.10'
+ desc 'Get a feature flag user list' do
+ detail 'Gets a feature flag user list. This feature was introduced in GitLab 12.10.'
success ::API::Entities::FeatureFlag::UserList
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags feature_flags_user_lists_tags
end
get do
present user_project.operations_feature_flags_user_lists.find_by_iid!(params[:iid]),
@@ -72,8 +92,14 @@ module API
end
desc 'Update a feature flag user list' do
- detail 'This feature was introduced in GitLab 12.10'
+ detail 'Updates a feature flag user list. This feature was introduced in GitLab 12.10.'
success ::API::Entities::FeatureFlag::UserList
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags feature_flags_user_lists_tags
end
params do
optional :name, type: String, desc: 'The name of the list'
@@ -93,8 +119,14 @@ module API
end
end
- desc 'Delete a feature flag user list' do
- detail 'This feature was introduced in GitLab 12.10'
+ desc 'Delete feature flag user list' do
+ detail 'Deletes a feature flag user list. This feature was introduced in GitLab 12.10.'
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Conflict' }
+ ]
+ tags feature_flags_user_lists_tags
end
delete do
# TODO: Move the business logic to a service class in app/services/feature_flags.
diff --git a/lib/api/features.rb b/lib/api/features.rb
index 9d4e6eee82c..6b6f5cbfb3f 100644
--- a/lib/api/features.rb
+++ b/lib/api/features.rb
@@ -4,6 +4,8 @@ module API
class Features < ::API::Base
before { authenticated_as_admin! }
+ features_tags = %w[features]
+
feature_category :feature_flags
urgency :low
@@ -44,8 +46,11 @@ module API
end
resource :features do
- desc 'Get a list of all features' do
+ desc 'List all features' do
+ detail 'Get a list of all persisted features, with its gate values.'
success Entities::Feature
+ is_array true
+ tags features_tags
end
get do
features = Feature.all
@@ -53,8 +58,11 @@ module API
present features, with: Entities::Feature, current_user: current_user
end
- desc 'Get a list of all feature definitions' do
+ desc 'List all feature definitions' do
+ detail 'Get a list of all feature definitions.'
success Entities::Feature::Definition
+ is_array true
+ tags features_tags
end
get :definitions do
definitions = ::Feature::Definition.definitions.values.map(&:to_h)
@@ -62,30 +70,44 @@ module API
present definitions, with: Entities::Feature::Definition, current_user: current_user
end
- desc 'Set the gate value for the given feature' do
+ desc 'Set or create a feature' do
+ detail "Set a feature's gate value. If a feature with the given name doesn't exist yet, it's created. " \
+ "The value can be a boolean, or an integer to indicate percentage of time."
success Entities::Feature
+ failure [
+ { code: 400, message: 'Bad request' }
+ ]
+ tags features_tags
end
params do
- requires :value, type: String, desc: '`true` or `false` to enable/disable, a float for percentage of time'
- optional :key, type: String, desc: '`percentage_of_actors` or the default `percentage_of_time`'
+ requires :value,
+ types: [String, Integer],
+ desc: '`true` or `false` to enable/disable, or an integer for percentage of time'
+ optional :key, type: String, desc: '`percentage_of_actors` or `percentage_of_time` (default)'
optional :feature_group, type: String, desc: 'A Feature group name'
optional :user, type: String, desc: 'A GitLab username or comma-separated multiple usernames'
optional :group,
type: String,
- desc: "A GitLab group's path, such as 'gitlab-org', or comma-separated multiple group paths"
+ desc: "A GitLab group's path, for example `gitlab-org`, or comma-separated multiple group paths"
optional :namespace,
type: String,
- desc: "A GitLab group or user namespace path, such as 'john-doe', or comma-separated multiple namespace paths"
+ desc: "A GitLab group or user namespace's path, for example `john-doe`, or comma-separated " \
+ "multiple namespace paths. Introduced in GitLab 15.0."
optional :project,
type: String,
- desc: "A projects path, such as `gitlab-org/gitlab-ce`, or comma-separated multiple project paths"
- optional :force, type: Boolean, desc: 'Skip feature flag validation checks, ie. YAML definition'
+ desc: "A projects path, for example `gitlab-org/gitlab-foss`, or comma-separated multiple project paths"
+ optional :repository,
+ type: String,
+ desc: "A repository path, for example `gitlab-org/gitlab-test.git`, `gitlab-org/gitlab-test.wiki.git`, " \
+ "`snippets/21.git`, to name a few. Use comma to separate multiple repository paths"
+ optional :force, type: Boolean, desc: 'Skip feature flag validation checks, such as a YAML definition'
mutually_exclusive :key, :feature_group
mutually_exclusive :key, :user
mutually_exclusive :key, :group
mutually_exclusive :key, :namespace
mutually_exclusive :key, :project
+ mutually_exclusive :key, :repository
end
post ':name' do
if Feature.enabled?(:set_feature_flag_service)
@@ -135,7 +157,10 @@ module API
bad_request!(e.message)
end
- desc 'Remove the gate value for the given feature'
+ desc 'Delete a feature' do
+ detail "Removes a feature gate. Response is equal when the gate exists, or doesn't."
+ tags features_tags
+ end
delete ':name' do
Feature.remove(params[:name])
diff --git a/lib/api/files.rb b/lib/api/files.rb
index fd574ca865b..fa749299b9a 100644
--- a/lib/api/files.rb
+++ b/lib/api/files.rb
@@ -30,7 +30,7 @@ module API
end
def assign_file_vars!
- authorize! :download_code, user_project
+ authorize! :read_code, user_project
@commit = user_project.commit(params[:ref])
not_found!('Commit') unless @commit
@@ -82,33 +82,44 @@ module API
end
params :simple_file_params do
- requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
- requires :branch, type: String, desc: 'Name of the branch to commit into. To create a new branch, also provide `start_branch`.', allow_blank: false
- requires :commit_message, type: String, allow_blank: false, desc: 'Commit message'
- optional :start_branch, type: String, desc: 'Name of the branch to start the new commit from'
- optional :author_email, type: String, desc: 'The email of the author'
- optional :author_name, type: String, desc: 'The name of the author'
+ requires :file_path, type: String, file_path: true,
+ desc: 'The url encoded path to the file.', documentation: { example: 'lib%2Fclass%2Erb' }
+ requires :branch, type: String,
+ desc: 'Name of the branch to commit into. To create a new branch, also provide `start_branch`.', allow_blank: false,
+ documentation: { example: 'main' }
+ requires :commit_message, type: String,
+ allow_blank: false, desc: 'Commit message', documentation: { example: 'Initial commit' }
+ optional :start_branch, type: String,
+ desc: 'Name of the branch to start the new commit from', documentation: { example: 'main' }
+ optional :author_email, type: String,
+ desc: 'The email of the author', documentation: { example: 'johndoe@example.com' }
+ optional :author_name, type: String,
+ desc: 'The name of the author', documentation: { example: 'John Doe' }
end
params :extended_file_params do
use :simple_file_params
- requires :content, type: String, desc: 'File content'
- optional :encoding, type: String, values: %w[base64], desc: 'File encoding'
- optional :last_commit_id, type: String, desc: 'Last known commit id for this file'
+ requires :content, type: String, desc: 'File content', documentation: { example: 'file content' }
+ optional :encoding, type: String, values: %w[base64 text], default: 'text', desc: 'File encoding'
+ optional :last_commit_id, type: String,
+ desc: 'Last known commit id for this file',
+ documentation: { example: '2695effb5807a22ff3d138d593fd856244e155e7' }
optional :execute_filemode, type: Boolean, desc: 'Enable / Disable the executable flag on the file path'
end
end
params do
- requires :id, type: String, desc: 'The project ID'
+ requires :id, type: String, desc: 'The project ID', documentation: { example: 'gitlab-org/gitlab' }
end
resource :projects, requirements: FILE_ENDPOINT_REQUIREMENTS do
allow_access_with_scope :read_repository, if: -> (request) { request.get? || request.head? }
desc 'Get blame file metadata from repository'
params do
- requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
- requires :ref, type: String, desc: 'The name of branch, tag or commit', allow_blank: false
+ requires :file_path, type: String, file_path: true,
+ desc: 'The url encoded path to the file.', documentation: { example: 'lib%2Fclass%2Erb' }
+ requires :ref, type: String,
+ desc: 'The name of branch, tag or commit', allow_blank: false, documentation: { example: 'main' }
end
head ":id/repository/files/:file_path/blame", requirements: FILE_ENDPOINT_REQUIREMENTS do
assign_file_vars!
@@ -118,11 +129,15 @@ module API
desc 'Get blame file from the repository'
params do
- requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
- requires :ref, type: String, desc: 'The name of branch, tag or commit', allow_blank: false
+ requires :file_path, type: String, file_path: true,
+ desc: 'The url encoded path to the file.', documentation: { example: 'lib%2Fclass%2Erb' }
+ requires :ref, type: String,
+ desc: 'The name of branch, tag or commit', allow_blank: false, documentation: { example: 'main' }
optional :range, type: Hash do
- requires :start, type: Integer, desc: 'The first line of the range to blame', allow_blank: false, values: ->(v) { v > 0 }
- requires :end, type: Integer, desc: 'The last line of the range to blame', allow_blank: false, values: ->(v) { v > 0 }
+ requires :start, type: Integer,
+ desc: 'The first line of the range to blame', allow_blank: false, values: ->(v) { v > 0 }
+ requires :end, type: Integer,
+ desc: 'The last line of the range to blame', allow_blank: false, values: ->(v) { v > 0 }
end
end
get ":id/repository/files/:file_path/blame", requirements: FILE_ENDPOINT_REQUIREMENTS do
@@ -138,8 +153,10 @@ module API
desc 'Get raw file metadata from repository'
params do
- requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
- optional :ref, type: String, desc: 'The name of branch, tag or commit', allow_blank: false
+ requires :file_path, type: String, file_path: true,
+ desc: 'The url encoded path to the file.', documentation: { example: 'lib%2Fclass%2Erb' }
+ optional :ref, type: String,
+ desc: 'The name of branch, tag or commit', allow_blank: false, documentation: { example: 'main' }
end
head ":id/repository/files/:file_path/raw", requirements: FILE_ENDPOINT_REQUIREMENTS, urgency: :low do
assign_file_vars!
@@ -147,10 +164,14 @@ module API
set_http_headers(blob_data)
end
- desc 'Get raw file contents from the repository'
+ desc 'Get raw file contents from the repository' do
+ success File
+ end
params do
- requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
- optional :ref, type: String, desc: 'The name of branch, tag or commit', allow_blank: false
+ requires :file_path, type: String, file_path: true,
+ desc: 'The url encoded path to the file.', documentation: { example: 'lib%2Fclass%2Erb' }
+ optional :ref, type: String,
+ desc: 'The name of branch, tag or commit', allow_blank: false, documentation: { example: 'main' }
end
get ":id/repository/files/:file_path/raw", requirements: FILE_ENDPOINT_REQUIREMENTS, urgency: :low do
assign_file_vars!
@@ -163,8 +184,10 @@ module API
desc 'Get file metadata from repository'
params do
- requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
- requires :ref, type: String, desc: 'The name of branch, tag or commit', allow_blank: false
+ requires :file_path, type: String, file_path: true,
+ desc: 'The url encoded path to the file.', documentation: { example: 'lib%2Fclass%2Erb' }
+ requires :ref, type: String,
+ desc: 'The name of branch, tag or commit', allow_blank: false, documentation: { example: 'main' }
end
head ":id/repository/files/:file_path", requirements: FILE_ENDPOINT_REQUIREMENTS, urgency: :low do
assign_file_vars!
@@ -174,8 +197,10 @@ module API
desc 'Get a file from the repository'
params do
- requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file. Ex. lib%2Fclass%2Erb'
- requires :ref, type: String, desc: 'The name of branch, tag or commit', allow_blank: false
+ requires :file_path, type: String, file_path: true,
+ desc: 'The url encoded path to the file.', documentation: { example: 'lib%2Fclass%2Erb' }
+ requires :ref, type: String,
+ desc: 'The name of branch, tag or commit', allow_blank: false, documentation: { example: 'main' }
end
get ":id/repository/files/:file_path", requirements: FILE_ENDPOINT_REQUIREMENTS do
assign_file_vars!
diff --git a/lib/api/freeze_periods.rb b/lib/api/freeze_periods.rb
index e69baeee97f..40f1be83028 100644
--- a/lib/api/freeze_periods.rb
+++ b/lib/api/freeze_periods.rb
@@ -4,19 +4,28 @@ module API
class FreezePeriods < ::API::Base
include PaginationParams
+ freeze_periods_tags = %w[freeze_periods]
+
before { authenticate! }
feature_category :continuous_delivery
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get project freeze periods' do
- detail 'This feature was introduced in GitLab 13.0.'
+ desc 'List freeze periods' do
+ detail 'Paginated list of Freeze Periods, sorted by created_at in ascending order. ' \
+ 'This feature was introduced in GitLab 13.0.'
success Entities::FreezePeriod
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags freeze_periods_tags
end
params do
use :pagination
@@ -30,12 +39,17 @@ module API
present paginate(freeze_periods), with: Entities::FreezePeriod, current_user: current_user
end
- desc 'Get a single freeze period' do
- detail 'This feature was introduced in GitLab 13.0.'
+ desc 'Get a freeze period' do
+ detail 'Get a freeze period for the given `freeze_period_id`. This feature was introduced in GitLab 13.0.'
success Entities::FreezePeriod
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags freeze_periods_tags
end
params do
- requires :freeze_period_id, type: Integer, desc: 'The ID of a project freeze period'
+ requires :freeze_period_id, type: Integer, desc: 'The ID of the freeze period'
end
get ":id/freeze_periods/:freeze_period_id" do
authorize! :read_freeze_period, user_project
@@ -43,14 +57,21 @@ module API
present freeze_period, with: Entities::FreezePeriod, current_user: current_user
end
- desc 'Create a new freeze period' do
- detail 'This feature was introduced in GitLab 13.0.'
+ desc 'Create a freeze period' do
+ detail 'Creates a freeze period. This feature was introduced in GitLab 13.0.'
success Entities::FreezePeriod
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags freeze_periods_tags
end
params do
- requires :freeze_start, type: String, desc: 'Freeze Period start'
- requires :freeze_end, type: String, desc: 'Freeze Period end'
- optional :cron_timezone, type: String, desc: 'Timezone'
+ requires :freeze_start, type: String, desc: 'Start of the freeze period in cron format.'
+ requires :freeze_end, type: String, desc: 'End of the freeze period in cron format'
+ optional :cron_timezone,
+ type: String,
+ desc: 'The time zone for the cron fields, defaults to UTC if not provided'
end
post ':id/freeze_periods' do
authorize! :create_freeze_period, user_project
@@ -67,13 +88,18 @@ module API
end
desc 'Update a freeze period' do
- detail 'This feature was introduced in GitLab 13.0.'
+ detail 'Updates a freeze period for the given `freeze_period_id`. This feature was introduced in GitLab 13.0.'
success Entities::FreezePeriod
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags freeze_periods_tags
end
params do
- optional :freeze_start, type: String, desc: 'Freeze Period start'
- optional :freeze_end, type: String, desc: 'Freeze Period end'
- optional :cron_timezone, type: String, desc: 'Freeze Period Timezone'
+ optional :freeze_start, type: String, desc: 'Start of the freeze period in cron format'
+ optional :freeze_end, type: String, desc: 'End of the freeze period in cron format'
+ optional :cron_timezone, type: String, desc: 'The time zone for the cron fields'
end
put ':id/freeze_periods/:freeze_period_id' do
authorize! :update_freeze_period, user_project
@@ -88,11 +114,15 @@ module API
end
desc 'Delete a freeze period' do
- detail 'This feature was introduced in GitLab 13.0.'
+ detail 'Deletes a freeze period for the given `freeze_period_id`. This feature was introduced in GitLab 13.0.'
success Entities::FreezePeriod
+ failure [
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags freeze_periods_tags
end
params do
- requires :freeze_period_id, type: Integer, desc: 'Freeze Period ID'
+ requires :freeze_period_id, type: Integer, desc: 'The ID of the freeze period'
end
delete ':id/freeze_periods/:freeze_period_id' do
authorize! :destroy_freeze_period, user_project
diff --git a/lib/api/generic_packages.rb b/lib/api/generic_packages.rb
index 0098b074f05..3584f8d025a 100644
--- a/lib/api/generic_packages.rb
+++ b/lib/api/generic_packages.rb
@@ -18,7 +18,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -54,7 +54,7 @@ module API
requires :package_version, type: String, desc: 'Package version', regexp: Gitlab::Regex.generic_package_version_regex
requires :file_name, type: String, desc: 'Package file name', regexp: Gitlab::Regex.generic_package_file_name_regex, file_path: true
optional :status, type: String, values: ALLOWED_STATUSES, desc: 'Package status'
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
optional :select, type: String, values: %w[package_file]
end
diff --git a/lib/api/geo.rb b/lib/api/geo.rb
index cb04d2a4e1e..8798b76b52b 100644
--- a/lib/api/geo.rb
+++ b/lib/api/geo.rb
@@ -13,6 +13,13 @@ module API
end
resource :geo do
+ desc 'Returns a Geo proxy response' do
+ summary "Determine if a Geo site should proxy requests"
+ success code: 200
+ failure [{ code: 403, message: 'Forbidden' }]
+ tags %w[geo]
+ end
+
# Workhorse calls this to determine if it is a Geo site that should proxy
# requests. Workhorse doesn't know if it's in a FOSS/EE context.
get '/proxy' do
diff --git a/lib/api/go_proxy.rb b/lib/api/go_proxy.rb
index 2d9c0cd6ce1..8fde40a4713 100755
--- a/lib/api/go_proxy.rb
+++ b/lib/api/go_proxy.rb
@@ -4,6 +4,8 @@ module API
helpers Gitlab::Golang
helpers ::API::Helpers::PackagesHelpers
+ GO_PROXY_TAGS = %w[go_proxy].freeze
+
feature_category :package_registry
urgency :low
@@ -17,6 +19,10 @@ module API
before { require_packages_enabled! }
helpers do
+ def project
+ user_project(action: :read_package)
+ end
+
def case_decode(str)
# Converts "github.com/!azure" to "github.com/Azure"
#
@@ -32,12 +38,12 @@ module API
end
def find_module
- not_found! unless Feature.enabled?(:go_proxy, user_project)
+ not_found! unless Feature.enabled?(:go_proxy, project)
module_name = case_decode params[:module_name]
bad_request_missing_attribute!('Module Name') if module_name.blank?
- mod = ::Packages::Go::ModuleFinder.new(user_project, module_name).execute
+ mod = ::Packages::Go::ModuleFinder.new(project, module_name).execute
not_found! unless mod
@@ -58,18 +64,21 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
- requires :module_name, type: String, desc: 'Module name', coerce_with: ->(val) { CGI.unescape(val) }
+ requires :id, types: [String, Integer], desc: 'The project ID or full path of a project'
+ requires :module_name, type: String, desc: 'The name of the Go module', coerce_with: ->(val) { CGI.unescape(val) }
end
- route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true, authenticate_non_public: true
+ route_setting :authentication, job_token_allowed: true, basic_auth_personal_access_token: true,
+ authenticate_non_public: true
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before do
- authorize_read_package!
+ authorize_read_package!(project)
end
namespace ':id/packages/go/*module_name/@v' do
- desc 'Get all tagged versions for a given Go module' do
- detail 'See `go help goproxy`, GET $GOPROXY/<module>/@v/list. This feature was introduced in GitLab 13.1.'
+ desc 'List' do
+ detail 'Get all tagged versions for a given Go module.'\
+ 'See `go help goproxy`, GET $GOPROXY/<module>/@v/list. This feature was introduced in GitLab 13.1.'
+ tags GO_PROXY_TAGS
end
get 'list' do
mod = find_module
@@ -78,12 +87,14 @@ module API
mod.versions.map { |t| t.name }.join("\n")
end
- desc 'Get information about the given module version' do
- detail 'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.info. This feature was introduced in GitLab 13.1.'
+ desc 'Version metadata' do
+ detail 'Get all tagged versions for a given Go module.'\
+ 'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.info. This feature was introduced in GitLab 13.1'
success ::API::Entities::GoModuleVersion
+ tags GO_PROXY_TAGS
end
params do
- requires :module_version, type: String, desc: 'Module version'
+ requires :module_version, type: String, desc: 'The version of the Go module'
end
get ':module_version.info', requirements: MODULE_VERSION_REQUIREMENTS do
ver = find_version
@@ -91,11 +102,13 @@ module API
present ::Packages::Go::ModuleVersionPresenter.new(ver), with: ::API::Entities::GoModuleVersion
end
- desc 'Get the module file of the given module version' do
- detail 'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.mod. This feature was introduced in GitLab 13.1.'
+ desc 'Download module file' do
+ detail 'Get the module file of a given module version.'\
+ 'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.mod. This feature was introduced in GitLab 13.1.'
+ tags GO_PROXY_TAGS
end
params do
- requires :module_version, type: String, desc: 'Module version'
+ requires :module_version, type: String, desc: 'The version of the Go module'
end
get ':module_version.mod', requirements: MODULE_VERSION_REQUIREMENTS do
ver = find_version
@@ -104,18 +117,21 @@ module API
ver.gomod
end
- desc 'Get a zip of the source of the given module version' do
- detail 'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.zip. This feature was introduced in GitLab 13.1.'
+ desc 'Download module source' do
+ detail 'Get a zip of the source of the given module version.'\
+ 'See `go help goproxy`, GET $GOPROXY/<module>/@v/<version>.zip. This feature was introduced in GitLab 13.1.'
+ tags GO_PROXY_TAGS
end
params do
- requires :module_version, type: String, desc: 'Module version'
+ requires :module_version, type: String, desc: 'The version of the Go module'
end
get ':module_version.zip', requirements: MODULE_VERSION_REQUIREMENTS do
ver = find_version
content_type 'application/zip'
env['api.format'] = :binary
- header['Content-Disposition'] = ActionDispatch::Http::ContentDisposition.format(disposition: 'attachment', filename: ver.name + '.zip')
+ header['Content-Disposition'] =
+ ActionDispatch::Http::ContentDisposition.format(disposition: 'attachment', filename: "#{ver.name}.zip")
header['Content-Transfer-Encoding'] = 'binary'
status :ok
body ver.archive.string
diff --git a/lib/api/group_avatar.rb b/lib/api/group_avatar.rb
index 9063040c763..0820011fd89 100644
--- a/lib/api/group_avatar.rb
+++ b/lib/api/group_avatar.rb
@@ -7,11 +7,13 @@ module API
feature_category :subgroups
params do
- requires :id, type: String, desc: 'The ID of a group'
+ requires :id, type: String, desc: 'The ID of the group'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Download the group avatar' do
detail 'This feature was introduced in GitLab 14.0'
+ tags %w[group_avatar]
+ success code: 200
end
get ':id/avatar' do
avatar = user_group.avatar
diff --git a/lib/api/group_clusters.rb b/lib/api/group_clusters.rb
index edaa32c26c4..de5ca0f86ae 100644
--- a/lib/api/group_clusters.rb
+++ b/lib/api/group_clusters.rb
@@ -16,8 +16,14 @@ module API
requires :id, type: String, desc: 'The ID of the group'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get all clusters from the group' do
+ desc 'List group clusters' do
+ detail 'This feature was introduced in GitLab 12.1. Returns a list of group clusters.'
success Entities::Cluster
+ failure [
+ { code: 403, message: 'Forbidden' }
+ ]
+ is_array true
+ tags %w[clusters]
end
params do
use :pagination
@@ -28,8 +34,14 @@ module API
present paginate(clusters_for_current_user), with: Entities::Cluster
end
- desc 'Get specific cluster for the group' do
+ desc 'Get a single group cluster' do
+ detail 'This feature was introduced in GitLab 12.1. Gets a single group cluster.'
success Entities::ClusterGroup
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
@@ -40,8 +52,15 @@ module API
present cluster, with: Entities::ClusterGroup
end
- desc 'Adds an existing cluster' do
+ desc 'Add existing cluster to group' do
+ detail 'This feature was introduced in GitLab 12.1. Adds an existing Kubernetes cluster to the group.'
success Entities::ClusterGroup
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :name, type: String, desc: 'Cluster name'
@@ -73,8 +92,15 @@ module API
end
end
- desc 'Update an existing cluster' do
+ desc 'Edit group cluster' do
+ detail 'This feature was introduced in GitLab 12.1. Updates an existing group cluster.'
success Entities::ClusterGroup
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
@@ -104,8 +130,14 @@ module API
end
end
- desc 'Remove a cluster' do
+ desc 'Delete group cluster' do
+ detail 'This feature was introduced in GitLab 12.1. Deletes an existing group cluster. Does not remove existing resources within the connected Kubernetes cluster.'
success Entities::ClusterGroup
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The Cluster ID'
diff --git a/lib/api/group_container_repositories.rb b/lib/api/group_container_repositories.rb
index b834d177a12..753f0db10c1 100644
--- a/lib/api/group_container_repositories.rb
+++ b/lib/api/group_container_repositories.rb
@@ -16,12 +16,19 @@ module API
tag_name: API::NO_SLASH_URL_PART_REGEX)
params do
- requires :id, type: String, desc: "Group's ID or path"
+ requires :id, types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the group accessible by the authenticated user'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get a list of all repositories within a group' do
- detail 'This feature was introduced in GitLab 12.2.'
+ desc 'List registry repositories within a group' do
+ detail 'Get a list of registry repositories in a group. This feature was introduced in GitLab 12.2.'
success Entities::ContainerRegistry::Repository
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Group Not Found' }
+ ]
+ is_array true
+ tags %w[container_registry]
end
params do
use :pagination
diff --git a/lib/api/group_export.rb b/lib/api/group_export.rb
index 2948960a9b4..eb0a01e0d3d 100644
--- a/lib/api/group_export.rb
+++ b/lib/api/group_export.rb
@@ -15,6 +15,16 @@ module API
resource :groups, requirements: { id: %r{[^/]+} } do
desc 'Download export' do
detail 'This feature was introduced in GitLab 12.5.'
+ tags %w[group_export]
+ produces %w[application/octet-stream application/json]
+ success code: 200
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
get ':id/export/download' do
check_rate_limit! :group_download_export, scope: [current_user, user_group]
@@ -32,6 +42,15 @@ module API
desc 'Start export' do
detail 'This feature was introduced in GitLab 12.5.'
+ tags %w[group_export]
+ success code: 202
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 429, message: 'Too many requests' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
post ':id/export' do
check_rate_limit! :group_export, scope: current_user
@@ -47,6 +66,14 @@ module API
desc 'Start relations export' do
detail 'This feature was introduced in GitLab 13.12'
+ tags %w[group_export]
+ success code: 202
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
post ':id/export_relations' do
response = ::BulkImports::ExportService.new(portable: user_group, user: current_user).execute
@@ -60,6 +87,15 @@ module API
desc 'Download relations export' do
detail 'This feature was introduced in GitLab 13.12'
+ produces %w[application/octet-stream application/json]
+ tags %w[group_export]
+ success code: 200
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
params do
requires :relation, type: String, desc: 'Group relation name'
@@ -77,6 +113,15 @@ module API
desc 'Relations export status' do
detail 'This feature was introduced in GitLab 13.12'
+ is_array true
+ tags %w[group_export]
+ success code: 200, model: Entities::BulkImports::ExportStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
get ':id/export_relations/status' do
present user_group.bulk_import_exports, with: Entities::BulkImports::ExportStatus
diff --git a/lib/api/group_import.rb b/lib/api/group_import.rb
index cef9b542c9e..609a7ed0ef0 100644
--- a/lib/api/group_import.rb
+++ b/lib/api/group_import.rb
@@ -32,6 +32,7 @@ module API
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Workhorse authorize the group import upload' do
detail 'This feature was introduced in GitLab 12.8'
+ tags ['group_import']
end
post 'import/authorize' do
require_gitlab_workhorse!
@@ -49,7 +50,15 @@ module API
desc 'Create a new group import' do
detail 'This feature was introduced in GitLab 12.8'
- success Entities::Group
+ success code: 202
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 400, message: 'Bad request' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ consumes ['multipart/form-data']
+ tags ['group_import']
end
params do
requires :path, type: String, desc: 'Group path'
diff --git a/lib/api/group_packages.rb b/lib/api/group_packages.rb
index 72d67b41c31..c2b4cbf732f 100644
--- a/lib/api/group_packages.rb
+++ b/lib/api/group_packages.rb
@@ -14,13 +14,19 @@ module API
helpers ::API::Helpers::PackagesHelpers
params do
- requires :id, type: String, desc: "Group's ID or path"
+ requires :id, types: [String, Integer], desc: 'ID or URL-encoded path of the group'
optional :exclude_subgroups, type: Boolean, default: false, desc: 'Determines if subgroups should be excluded'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get all project packages within a group' do
- detail 'This feature was introduced in GitLab 12.5'
+ desc 'List packages within a group' do
+ detail 'Get a list of project packages at the group level. This feature was introduced in GitLab 12.5'
success ::API::Entities::Package
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Group Not Found' }
+ ]
+ is_array true
+ tags %w[group_packages]
end
params do
use :pagination
@@ -53,10 +59,13 @@ module API
packages = Packages::GroupPackagesFinder.new(
current_user,
user_group,
- declared(params).slice(:exclude_subgroups, :order_by, :sort, :package_type, :package_name, :include_versionless, :status)
+ declared(params).slice(
+ :exclude_subgroups, :order_by, :sort, :package_type, :package_name, :include_versionless, :status
+ )
).execute
- present paginate(packages), with: ::API::Entities::Package, user: current_user, group: true, namespace: user_group
+ present paginate(packages), with: ::API::Entities::Package, user: current_user, group: true,
+ namespace: user_group
end
end
end
diff --git a/lib/api/group_variables.rb b/lib/api/group_variables.rb
index 2235746b254..a42f9045b9d 100644
--- a/lib/api/group_variables.rb
+++ b/lib/api/group_variables.rb
@@ -11,12 +11,14 @@ module API
helpers ::API::Helpers::VariablesHelpers
params do
- requires :id, type: String, desc: 'The ID of a group'
+ requires :id, type: String, desc: 'The ID of a group or URL-encoded path of the group owned by the authenticated
+ user'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get group-level variables' do
+ desc 'Get a list of group-level variables' do
success Entities::Ci::Variable
+ tags %w[ci_variables]
end
params do
use :pagination
@@ -26,8 +28,10 @@ module API
present paginate(variables), with: Entities::Ci::Variable
end
- desc 'Get a specific variable from a group' do
+ desc 'Get the details of a group’s specific variable' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Group Variable Not Found' }]
+ tags %w[ci_variables]
end
params do
requires :key, type: String, desc: 'The key of the variable'
@@ -42,14 +46,19 @@ module API
desc 'Create a new variable in a group' do
success Entities::Ci::Variable
+ failure [{ code: 400, message: '400 Bad Request' }]
+ tags %w[ci_variables]
end
+ route_setting :log_safety, { safe: %w[key], unsafe: %w[value] }
params do
- requires :key, type: String, desc: 'The key of the variable'
- requires :value, type: String, desc: 'The value of the variable'
+ requires :key, type: String, desc: 'The ID of a group or URL-encoded path of the group owned by the
+ authenticated user'
+ requires :value, type: String, desc: 'The value of a variable'
optional :protected, type: String, desc: 'Whether the variable is protected'
optional :masked, type: String, desc: 'Whether the variable is masked'
- optional :variable_type, type: String, values: ::Ci::GroupVariable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file. Defaults to env_var'
-
+ optional :raw, type: String, desc: 'Whether the variable will be expanded'
+ optional :variable_type, type: String, values: ::Ci::GroupVariable.variable_types.keys, desc: 'The type of the variable. Default: env_var'
+ optional :environment_scope, type: String, desc: 'The environment scope of a variable'
use :optional_group_variable_params_ee
end
post ':id/variables' do
@@ -73,13 +82,18 @@ module API
desc 'Update an existing variable from a group' do
success Entities::Ci::Variable
+ failure [{ code: 400, message: '400 Bad Request' }, { code: 404, message: 'Group Variable Not Found' }]
+ tags %w[ci_variables]
end
+ route_setting :log_safety, { safe: %w[key], unsafe: %w[value] }
params do
- optional :key, type: String, desc: 'The key of the variable'
- optional :value, type: String, desc: 'The value of the variable'
+ optional :key, type: String, desc: 'The key of a variable'
+ optional :value, type: String, desc: 'The value of a variable'
optional :protected, type: String, desc: 'Whether the variable is protected'
optional :masked, type: String, desc: 'Whether the variable is masked'
- optional :variable_type, type: String, values: ::Ci::GroupVariable.variable_types.keys, desc: 'The type of variable, must be one of env_var or file'
+ optional :raw, type: String, desc: 'Whether the variable will be expanded'
+ optional :variable_type, type: String, values: ::Ci::GroupVariable.variable_types.keys, desc: 'The type of the variable. Default: env_var'
+ optional :environment_scope, type: String, desc: 'The environment scope of a variable'
use :optional_group_variable_params_ee
end
@@ -106,9 +120,11 @@ module API
desc 'Delete an existing variable from a group' do
success Entities::Ci::Variable
+ failure [{ code: 404, message: 'Group Variable Not Found' }]
+ tags %w[ci_variables]
end
params do
- requires :key, type: String, desc: 'The key of the variable'
+ requires :key, type: String, desc: 'The key of a variable'
end
delete ':id/variables/:key' do
variable = find_variable(user_group, params)
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 0eb4fbb196c..75e7612bd5b 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -592,19 +592,19 @@ module API
end
end
- def present_artifacts_file!(file, project:, **args)
+ def present_artifacts_file!(file, **args)
log_artifacts_filesize(file&.model)
- present_carrierwave_file!(file, project: project, **args)
+ present_carrierwave_file!(file, **args)
end
- def present_carrierwave_file!(file, project: nil, supports_direct_download: true)
+ def present_carrierwave_file!(file, supports_direct_download: true)
return not_found! unless file&.exists?
if file.file_storage?
present_disk_file!(file.path, file.filename)
elsif supports_direct_download && file.class.direct_download_enabled?
- redirect(cdn_fronted_url(file, project))
+ redirect(cdn_fronted_url(file))
else
header(*Gitlab::Workhorse.send_url(file.url))
status :ok
@@ -612,9 +612,9 @@ module API
end
end
- def cdn_fronted_url(file, project)
+ def cdn_fronted_url(file)
if file.respond_to?(:cdn_enabled_url)
- result = file.cdn_enabled_url(project, ip_address)
+ result = file.cdn_enabled_url(ip_address)
Gitlab::ApplicationContext.push(artifact_used_cdn: result.used_cdn)
result.url
else
@@ -673,7 +673,6 @@ module API
finder_params[:with_issues_enabled] = true if params[:with_issues_enabled].present?
finder_params[:with_merge_requests_enabled] = true if params[:with_merge_requests_enabled].present?
- finder_params[:without_deleted] = true
finder_params[:search_namespaces] = true if params[:search_namespaces].present?
finder_params[:user] = params.delete(:user) if params[:user]
finder_params[:id_after] = sanitize_id_param(params[:id_after]) if params[:id_after]
diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb
index e03f029a6ef..56db6ee4c5c 100644
--- a/lib/api/helpers/internal_helpers.rb
+++ b/lib/api/helpers/internal_helpers.rb
@@ -124,7 +124,12 @@ module API
repository: repository.gitaly_repository.to_h,
address: Gitlab::GitalyClient.address(repository.shard),
token: Gitlab::GitalyClient.token(repository.shard),
- features: Feature::Gitaly.server_feature_flags(repository.project)
+ features: Feature::Gitaly.server_feature_flags(
+ user: ::Feature::Gitaly.user_actor(actor.user),
+ repository: repository,
+ project: ::Feature::Gitaly.project_actor(repository.container),
+ group: ::Feature::Gitaly.group_actor(repository.container)
+ )
}
end
end
diff --git a/lib/api/helpers/label_helpers.rb b/lib/api/helpers/label_helpers.rb
index 8572cc89e71..b3ba962666f 100644
--- a/lib/api/helpers/label_helpers.rb
+++ b/lib/api/helpers/label_helpers.rb
@@ -137,9 +137,10 @@ module API
end
def create_service_params(parent)
- if parent.is_a?(Project)
+ case parent
+ when Project
{ project: parent }
- elsif parent.is_a?(Group)
+ when Group
{ group: parent }
else
raise TypeError, 'Parent type is not supported'
diff --git a/lib/api/helpers/merge_requests_helpers.rb b/lib/api/helpers/merge_requests_helpers.rb
index 85648cd166d..eed9fa30d3c 100644
--- a/lib/api/helpers/merge_requests_helpers.rb
+++ b/lib/api/helpers/merge_requests_helpers.rb
@@ -8,6 +8,9 @@ module API
UNPROCESSABLE_ERROR_KEYS = [:project_access, :branch_conflict, :validate_fork, :base].freeze
+ params :ee_approval_params do
+ end
+
params :merge_requests_negatable_params do
optional :author_id, type: Integer, desc: 'Return merge requests which are authored by the user with the given ID'
optional :author_username, type: String, desc: 'Return merge requests which are authored by the user with the given username'
@@ -136,3 +139,5 @@ module API
end
end
end
+
+API::Helpers::MergeRequestsHelpers.prepend_mod_with('API::Helpers::MergeRequestsHelpers')
diff --git a/lib/api/helpers/packages/dependency_proxy_helpers.rb b/lib/api/helpers/packages/dependency_proxy_helpers.rb
index dc81e5e1b51..1ae863a5a25 100644
--- a/lib/api/helpers/packages/dependency_proxy_helpers.rb
+++ b/lib/api/helpers/packages/dependency_proxy_helpers.rb
@@ -45,7 +45,7 @@ module API
raise ArgumentError, "Can't find application setting for package_type #{package_type}" unless application_setting_name
- if target.present? && Feature.enabled?(:cascade_package_forwarding_settings, target)
+ if target.present?
target.public_send(application_setting_name) # rubocop:disable GitlabSecurity/PublicSend
else
::Gitlab::CurrentSettings
diff --git a/lib/api/helpers/packages/npm.rb b/lib/api/helpers/packages/npm.rb
index 34e126c73fc..352d77f472c 100644
--- a/lib/api/helpers/packages/npm.rb
+++ b/lib/api/helpers/packages/npm.rb
@@ -19,7 +19,7 @@ module API
strong_memoize(:project) do
case endpoint_scope
when :project
- user_project
+ user_project(action: :read_package)
when :instance
# Simulate the same behavior as #user_project by re-using #find_project!
# but take care if the project_id is nil as #find_project! is not designed
diff --git a/lib/api/helpers/packages_helpers.rb b/lib/api/helpers/packages_helpers.rb
index 687c8330cc8..96a10d43401 100644
--- a/lib/api/helpers/packages_helpers.rb
+++ b/lib/api/helpers/packages_helpers.rb
@@ -3,6 +3,8 @@
module API
module Helpers
module PackagesHelpers
+ extend ::Gitlab::Utils::Override
+
MAX_PACKAGE_FILE_SIZE = 50.megabytes.freeze
def require_packages_enabled!
@@ -48,6 +50,34 @@ module API
require_gitlab_workhorse!
end
+ override :user_project
+ def user_project(action: :read_project)
+ case action
+ when :read_project
+ super()
+ when :read_package
+ user_project_with_read_package
+ else
+ raise ArgumentError, "unexpected action: #{action}"
+ end
+ end
+
+ # This function is similar to the `find_project!` function, but it considers the `read_package` ability.
+ def user_project_with_read_package
+ strong_memoize(:user_project_with_read_package) do
+ project = find_project(params[:id])
+
+ next forbidden! unless authorized_project_scope?(project)
+
+ next project if can?(current_user, :read_package, project&.packages_policy_subject)
+ # guest users can have :read_project but not :read_package
+ next forbidden! if can?(current_user, :read_project, project)
+ next unauthorized! if authenticate_non_public?
+
+ not_found!('Project')
+ end
+ end
+
def track_package_event(event_name, scope, **args)
::Packages::CreateEventService.new(nil, current_user, event_name: event_name, scope: scope).execute
category = args.delete(:category) || self.options[:for].name
diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb
index 9839828a5b4..c95bf0f0c21 100644
--- a/lib/api/helpers/projects_helpers.rb
+++ b/lib/api/helpers/projects_helpers.rb
@@ -65,6 +65,7 @@ module API
optional :suggestion_commit_message, type: String, desc: 'The commit message used to apply merge request suggestions'
optional :merge_commit_template, type: String, desc: 'Template used to create merge commit message'
optional :squash_commit_template, type: String, desc: 'Template used to create squash commit message'
+ optional :issue_branch_template, type: String, desc: 'Template used to create a branch from an issue'
optional :initialize_with_readme, type: Boolean, desc: "Initialize a project with a README.md"
optional :ci_default_git_depth, type: Integer, desc: 'Default number of revisions for shallow cloning'
optional :auto_devops_enabled, type: Boolean, desc: 'Flag indication if Auto DevOps is enabled'
@@ -96,7 +97,7 @@ module API
end
params :optional_update_params_ce do
- optional :ci_forward_deployment_enabled, type: Boolean, desc: 'Skip older deployment jobs that are still pending'
+ optional :ci_forward_deployment_enabled, type: Boolean, desc: 'Prevent older deployment jobs that are still pending'
optional :ci_allow_fork_pipelines_to_run_in_parent_project, type: Boolean, desc: 'Allow fork merge request pipelines to run in parent project'
optional :ci_separated_caches, type: Boolean, desc: 'Enable or disable separated caches based on branch protection.'
optional :restrict_user_defined_variables, type: Boolean, desc: 'Restrict use of user-defined variables when triggering a pipeline'
@@ -174,6 +175,7 @@ module API
:suggestion_commit_message,
:merge_commit_template,
:squash_commit_template,
+ :issue_branch_template,
:repository_storage,
:packages_enabled,
:service_desk_enabled,
diff --git a/lib/api/helpers/users_helpers.rb b/lib/api/helpers/users_helpers.rb
index 1a019283bc6..e80b89488a2 100644
--- a/lib/api/helpers/users_helpers.rb
+++ b/lib/api/helpers/users_helpers.rb
@@ -18,6 +18,13 @@ module API
error_messages[:bio] = error_messages.delete(:"user_detail.bio") if error_messages.has_key?(:"user_detail.bio")
end
end
+
+ # rubocop: disable CodeReuse/ActiveRecord
+ def find_user_by_id(params)
+ id = params[:user_id] || params[:id]
+ User.find_by(id: id) || not_found!('User')
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
end
end
end
diff --git a/lib/api/helpers/web_hooks_helpers.rb b/lib/api/helpers/web_hooks_helpers.rb
index a71e56af4c3..5d5067bc70e 100644
--- a/lib/api/helpers/web_hooks_helpers.rb
+++ b/lib/api/helpers/web_hooks_helpers.rb
@@ -6,7 +6,7 @@ module API
extend Grape::API::Helpers
params :requires_url do
- requires :url, type: String, desc: "The URL to send the request to"
+ requires :url, type: String, desc: "The URL to send the request to", documentation: { example: 'http://example.com/hook' }
end
params :optional_url do
@@ -15,8 +15,8 @@ module API
params :url_variables do
optional :url_variables, type: Array, desc: 'URL variables for interpolation' do
- requires :key, type: String, desc: 'Name of the variable'
- requires :value, type: String, desc: 'Value of the variable'
+ requires :key, type: String, desc: 'Name of the variable', documentation: { example: 'token' }
+ requires :value, type: String, desc: 'Value of the variable', documentation: { example: '123' }
end
end
diff --git a/lib/api/import_bitbucket_server.rb b/lib/api/import_bitbucket_server.rb
index 0f2d6239d0d..f315ae5afff 100644
--- a/lib/api/import_bitbucket_server.rb
+++ b/lib/api/import_bitbucket_server.rb
@@ -22,6 +22,14 @@ module API
desc 'Import a BitBucket Server repository' do
detail 'This feature was introduced in GitLab 13.2.'
success ::ProjectEntity
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 422, message: 'Unprocessable entity' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_import_bitbucket']
end
params do
diff --git a/lib/api/import_github.rb b/lib/api/import_github.rb
index 493cc038f46..d742e3732a8 100644
--- a/lib/api/import_github.rb
+++ b/lib/api/import_github.rb
@@ -2,6 +2,8 @@
module API
class ImportGithub < ::API::Base
+ before { authenticate! }
+
feature_category :importers
urgency :low
@@ -35,7 +37,15 @@ module API
desc 'Import a GitHub project' do
detail 'This feature was introduced in GitLab 11.3.4.'
- success ::ProjectEntity
+ success code: 201, model: ::ProjectEntity
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 422, message: 'Unprocessable entity' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_import_github']
end
params do
requires :personal_access_token, type: String, desc: 'GitHub personal access token'
@@ -56,6 +66,18 @@ module API
end
end
+ desc 'Cancel GitHub project import' do
+ detail 'This feature was introduced in GitLab 15.5'
+ success code: 200, model: ProjectImportEntity
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_import_github']
+ end
params do
requires :project_id, type: Integer, desc: 'ID of importing project to be canceled'
end
diff --git a/lib/api/integrations.rb b/lib/api/integrations.rb
index 71c55704ddf..408fa038b0d 100644
--- a/lib/api/integrations.rb
+++ b/lib/api/integrations.rb
@@ -3,6 +3,8 @@ module API
class Integrations < ::API::Base
feature_category :integrations
+ INTEGRATIONS_TAGS = %w[integrations].freeze
+
integrations = Helpers::IntegrationsHelpers.integrations
integration_classes = Helpers::IntegrationsHelpers.integration_classes
@@ -65,14 +67,21 @@ module API
# The support for `:id/services` can be dropped if we create an API V5.
[':id/services', ':id/integrations'].each do |path|
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authenticate! }
before { authorize_admin_project }
- desc 'Get all active project integrations' do
+ desc 'List all active integrations' do
+ detail 'Get a list of all active project integrations.'
success Entities::ProjectIntegrationBasic
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags INTEGRATIONS_TAGS
end
get path do
integrations = user_project.integrations.active
@@ -81,7 +90,16 @@ module API
end
INTEGRATIONS.each do |slug, settings|
- desc "Set #{slug} integration for project"
+ desc "Create/Edit #{slug.titleize} integration" do
+ detail "Set #{slug.titleize} integration for a project."
+ success Entities::ProjectIntegrationBasic
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags INTEGRATIONS_TAGS
+ end
params do
settings.each do |setting|
if setting[:required]
@@ -103,7 +121,16 @@ module API
end
end
- desc "Delete an integration from a project"
+ desc "Disable an integration" do
+ detail "Disable the integration for a project. Integration settings are preserved."
+ success code: 204
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags INTEGRATIONS_TAGS
+ end
params do
requires :slug, type: String, values: INTEGRATIONS.keys, desc: 'The name of the integration'
end
@@ -124,8 +151,15 @@ module API
end
end
- desc 'Get the integration settings for a project' do
+ desc "Get an integration settings" do
+ detail "Get the integration settings for a project."
success Entities::ProjectIntegration
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags INTEGRATIONS_TAGS
end
params do
requires :slug, type: String, values: INTEGRATIONS.keys, desc: 'The name of the integration'
@@ -149,11 +183,16 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "Trigger a slash command for #{integration_slug}" do
detail 'Added in GitLab 8.13'
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags INTEGRATIONS_TAGS
end
params do
settings.each do |setting|
diff --git a/lib/api/internal/kubernetes.rb b/lib/api/internal/kubernetes.rb
index 6f964d5636b..d06d1e9862a 100644
--- a/lib/api/internal/kubernetes.rb
+++ b/lib/api/internal/kubernetes.rb
@@ -61,15 +61,6 @@ module API
Guest.can?(:download_code, project) || agent.has_access_to?(project)
end
- def count_events
- strong_memoize(:count_events) do
- events = params.slice(:gitops_sync_count, :k8s_api_proxy_request_count)
- events.transform_keys! { |event| event.to_s.chomp('_count') }
- events = params[:counters]&.slice(:gitops_sync, :k8s_api_proxy_request) unless events.present?
- events
- end
- end
-
def increment_unique_events
events = params[:unique_counters]&.slice(:agent_users_using_ci_tunnel)
@@ -77,6 +68,12 @@ module API
increment_unique_values(event, entity_ids)
end
end
+
+ def increment_count_events
+ events = params[:counters]&.slice(:gitops_sync, :k8s_api_proxy_request)
+
+ Gitlab::UsageDataCounters::KubernetesAgentCounter.increment_event_counts(events)
+ end
end
namespace 'internal' do
@@ -144,26 +141,17 @@ module API
detail 'Updates usage metrics for agent'
end
params do
- # Todo: Remove gitops_sync_count and k8s_api_proxy_request_count in the next milestone
- # https://gitlab.com/gitlab-org/gitlab/-/issues/369489
- # We're only keeping it for backwards compatibility until KAS is released
- # using `counts:` instead
- optional :gitops_sync_count, type: Integer, desc: 'The count to increment the gitops_sync metric by'
- optional :k8s_api_proxy_request_count, type: Integer, desc: 'The count to increment the k8s_api_proxy_request_count metric by'
optional :counters, type: Hash do
optional :gitops_sync, type: Integer, desc: 'The count to increment the gitops_sync metric by'
- optional :k8s_api_proxy_request, type: Integer, desc: 'The count to increment the k8s_api_proxy_request_count metric by'
+ optional :k8s_api_proxy_request, type: Integer, desc: 'The count to increment the k8s_api_proxy_request metric by'
end
- mutually_exclusive :counters, :gitops_sync_count
- mutually_exclusive :counters, :k8s_api_proxy_request_count
optional :unique_counters, type: Hash do
optional :agent_users_using_ci_tunnel, type: Set[Integer], desc: 'A set of user ids that have interacted a CI Tunnel to'
end
end
post '/' do
- Gitlab::UsageDataCounters::KubernetesAgentCounter.increment_event_counts(count_events) if count_events
-
+ increment_count_events
increment_unique_events
no_content!
diff --git a/lib/api/internal/pages.rb b/lib/api/internal/pages.rb
index 6be2679af14..771059053ac 100644
--- a/lib/api/internal/pages.rb
+++ b/lib/api/internal/pages.rb
@@ -5,6 +5,7 @@ module API
module Internal
class Pages < ::API::Base
feature_category :pages
+ urgency :low
before do
authenticate_gitlab_pages_request!
diff --git a/lib/api/invitations.rb b/lib/api/invitations.rb
index 6fb3eca0ba8..6aefdf146cf 100644
--- a/lib/api/invitations.rb
+++ b/lib/api/invitations.rb
@@ -18,11 +18,12 @@ module API
desc 'Invite non-members by email address to a group or project.' do
detail 'This feature was introduced in GitLab 13.6'
success Entities::Invitation
+ tags %w[invitations]
end
params do
requires :access_level, type: Integer, values: Gitlab::Access.all_values, desc: 'A valid access level (defaults: `30`, developer access level)'
- optional :email, types: [String, Array[String]], email_or_email_list: true, desc: 'The email address to invite, or multiple emails separated by comma'
- optional :user_id, types: [Integer, String], desc: 'The user ID of the new member or multiple IDs separated by commas.'
+ optional :email, type: Array[String], email_or_email_list: true, coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The email address to invite, or multiple emails separated by comma'
+ optional :user_id, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The user ID of the new member or multiple IDs separated by commas.'
optional :expires_at, type: DateTime, desc: 'Date string in the format YEAR-MONTH-DAY'
optional :invite_source, type: String, desc: 'Source that triggered the member creation process', default: 'invitations-api'
optional :tasks_to_be_done, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Tasks the inviter wants the member to do'
@@ -44,8 +45,12 @@ module API
desc 'Get a list of group or project invitations viewable by the authenticated user' do
detail 'This feature was introduced in GitLab 13.6'
success Entities::Invitation
+ is_array true
+ tags %w[invitations]
end
params do
+ optional :page, type: Integer, desc: 'Page to retrieve'
+ optional :per_page, type: Integer, desc: 'Number of member invitations to return per page'
optional :query, type: String, desc: 'A query string to search for members'
use :pagination
end
@@ -62,6 +67,7 @@ module API
desc 'Updates a group or project invitation.' do
success Entities::Member
+ tags %w[invitations]
end
params do
requires :email, type: String, desc: 'The email address of the invitation'
@@ -93,7 +99,15 @@ module API
end
end
- desc 'Removes an invitation from a group or project.'
+ desc 'Removes an invitation from a group or project.' do
+ success code: 204
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Could not delete invitation' }
+ ]
+ tags %w[invitations]
+ end
params do
requires :email, type: String, desc: 'The email address of the invitation'
end
diff --git a/lib/api/issue_links.rb b/lib/api/issue_links.rb
index 563fb3358ed..020b02248a0 100644
--- a/lib/api/issue_links.rb
+++ b/lib/api/issue_links.rb
@@ -6,16 +6,27 @@ module API
before { authenticate! }
+ ISSUE_LINKS_TAGS = %w[issue_links].freeze
+
feature_category :team_planning
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
- requires :issue_iid, type: Integer, desc: 'The internal ID of a project issue'
+ requires :id, types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project owned by the authenticated user'
+ requires :issue_iid, type: Integer, desc: 'The internal ID of a project’s issue'
end
resource :projects, requirements: { id: %r{[^/]+} } do
- desc 'Get related issues' do
+ desc 'List issue relations' do
+ detail 'Get a list of a given issue’s linked issues, sorted by the relationship creation datetime (ascending).'\
+ 'Issues are filtered according to the user authorizations.'
success Entities::RelatedIssue
+ is_array true
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags ISSUE_LINKS_TAGS
end
get ':id/issues/:issue_iid/links' do
source_issue = find_project_issue(params[:issue_iid])
@@ -30,14 +41,23 @@ module API
include_subscribed: false
end
- desc 'Relate issues' do
+ desc 'Create an issue link' do
+ detail 'Creates a two-way relation between two issues.'\
+ 'The user must be allowed to update both issues to succeed.'
success Entities::IssueLink
+ failure [
+ { code: 400, message: 'Bad Request' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags ISSUE_LINKS_TAGS
end
params do
- requires :target_project_id, type: String, desc: 'The ID of the target project'
- requires :target_issue_iid, type: Integer, desc: 'The IID of the target issue'
+ requires :target_project_id, types: [String, Integer],
+ desc: 'The ID or URL-encoded path of a target project'
+ requires :target_issue_iid, types: [String, Integer], desc: 'The internal ID of a target project’s issue'
optional :link_type, type: String, values: IssueLink.link_types.keys,
- desc: 'The type of the relation'
+ desc: 'The type of the relation (“relates_toâ€, “blocksâ€, “is_blocked_byâ€),'\
+ 'defaults to “relates_toâ€)'
end
# rubocop: disable CodeReuse/ActiveRecord
post ':id/issues/:issue_iid/links' do
@@ -61,12 +81,17 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
- desc 'Get issues relation' do
- detail 'This feature was introduced in GitLab 15.1.'
+ desc 'Get an issue link' do
+ detail 'Gets details about an issue link. This feature was introduced in GitLab 15.1.'
success Entities::IssueLink
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags ISSUE_LINKS_TAGS
end
params do
- requires :issue_link_id, type: Integer, desc: 'The ID of an issue link'
+ requires :issue_link_id, types: [String, Integer], desc: 'ID of an issue relationship'
end
get ':id/issues/:issue_iid/links/:issue_link_id' do
issue = find_project_issue(params[:issue_iid])
@@ -77,11 +102,17 @@ module API
present issue_link, with: Entities::IssueLink
end
- desc 'Remove issues relation' do
+ desc 'Delete an issue link' do
+ detail 'Deletes an issue link, thus removes the two-way relationship.'
success Entities::IssueLink
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags ISSUE_LINKS_TAGS
end
params do
- requires :issue_link_id, type: Integer, desc: 'The ID of an issue link'
+ requires :issue_link_id, types: [String, Integer], desc: 'The ID of an issue relationship'
end
delete ':id/issues/:issue_iid/links/:issue_link_id' do
issue = find_project_issue(params[:issue_iid])
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index b8b4019765d..b08819e34e3 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -198,7 +198,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
include TimeTrackingEndpoints
diff --git a/lib/api/keys.rb b/lib/api/keys.rb
index fb1bedd5e92..77952bac01a 100644
--- a/lib/api/keys.rb
+++ b/lib/api/keys.rb
@@ -9,8 +9,13 @@ module API
resource :keys do
desc 'Get single ssh key by id. Only available to admin users' do
+ detail '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'
success Entities::SSHKeyWithUser
end
+ params do
+ requires :id, types: [String, Integer], desc: 'The ID of an SSH key', documentation: { example: '2' }
+ end
get ":id" do
authenticated_as_admin!
@@ -19,11 +24,14 @@ module API
present key, with: Entities::SSHKeyWithUser, current_user: current_user
end
- desc 'Get SSH Key information' do
+ desc 'Get user by fingerprint of SSH key' do
success Entities::UserWithAdmin
+ detail 'You can search for a user that owns a specific SSH key. Note only administrators can lookup SSH key\
+ with the fingerprint of an SSH key'
end
params do
- requires :fingerprint, type: String, desc: 'Search for a SSH fingerprint'
+ requires :fingerprint, type: String, desc: 'The fingerprint of an SSH key',
+ documentation: { example: 'ba:81:59:68:d7:6c:cd:02:02:bf:6a:9b:55:4e:af:d1' }
end
get do
authenticated_with_can_read_all_resources!
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index 0a107a96d61..2e00affbbdf 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -15,7 +15,7 @@ module API
label_id: API::NO_SLASH_URL_PART_REGEX)
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: LABEL_ENDPOINT_REQUIREMENTS do
desc 'Get all labels of the project' do
diff --git a/lib/api/lint.rb b/lib/api/lint.rb
index f65ecf3b4a6..89787ba00c2 100644
--- a/lib/api/lint.rb
+++ b/lib/api/lint.rb
@@ -15,12 +15,18 @@ module API
end
namespace :ci do
- desc 'Validation of .gitlab-ci.yml content'
+ desc 'Validates the .gitlab-ci.yml content' do
+ detail 'Checks if CI/CD YAML configuration is valid'
+ success code: 200, model: Entities::Ci::Lint::Result
+ tags %w[ci_lint]
+ end
params do
- requires :content, type: String, desc: 'Content of .gitlab-ci.yml'
- optional :include_merged_yaml, type: Boolean, desc: 'Whether or not to include merged CI config yaml in the response'
- optional :include_jobs, type: Boolean, desc: 'Whether or not to include CI jobs in the response'
+ requires :content, type: String, desc: 'The CI/CD configuration content'
+ optional :include_merged_yaml, type: Boolean, desc: 'If the expanded CI/CD configuration should be included in the response'
+ optional :include_jobs, type: Boolean, desc: 'If the list of jobs should be included in the response. This is
+ false by default'
end
+
post '/lint', urgency: :low do
unauthorized! unless can_lint_ci?
@@ -36,16 +42,21 @@ module API
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Validation of .gitlab-ci.yml content' do
- detail 'This feature was introduced in GitLab 13.5.'
+ desc 'Validates a CI YAML configuration with a namespace' do
+ detail 'Checks if a project’s latest (HEAD of the project’s default branch) .gitlab-ci.yml configuration is
+ valid'
+ success Entities::Ci::Lint::Result
+ tags %w[ci_lint]
end
params do
- optional :dry_run, type: Boolean, default: false, desc: 'Run pipeline creation simulation, or only do static check.'
- optional :include_jobs, type: Boolean, desc: 'Whether or not to include CI jobs in the response'
+ optional :dry_run, type: Boolean, default: false, desc: 'Run pipeline creation simulation, or only do static check. This is false by default'
+ optional :include_jobs, type: Boolean, desc: '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'
optional :ref, type: String, desc: 'Branch or tag used to execute a dry run. Defaults to the default branch of the project. Only used when dry_run is true'
end
+
get ':id/ci/lint', urgency: :low do
- authorize! :download_code, user_project
+ authorize! :read_code, user_project
if user_project.commit.present?
content = user_project.repository.gitlab_ci_yml_for(user_project.commit.id, user_project.ci_config_path_or_default)
@@ -60,15 +71,19 @@ module API
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Validation of .gitlab-ci.yml content' do
- detail 'This feature was introduced in GitLab 13.6.'
+ desc 'Validate a CI YAML configuration with a namespace' do
+ detail 'Checks if CI/CD YAML configuration is valid. This endpoint has namespace specific context'
+ success code: 200, model: Entities::Ci::Lint::Result
+ tags %w[ci_lint]
end
params do
requires :content, type: String, desc: 'Content of .gitlab-ci.yml'
- optional :dry_run, type: Boolean, default: false, desc: 'Run pipeline creation simulation, or only do static check.'
- optional :include_jobs, type: Boolean, desc: 'Whether or not to include CI jobs in the response'
- optional :ref, type: String, desc: 'Branch or tag used to execute a dry run. Defaults to the default branch of the project. Only used when dry_run is true'
+ optional :dry_run, type: Boolean, default: false, desc: 'Run pipeline creation simulation, or only do static check. This is false by default'
+ optional :include_jobs, type: Boolean, desc: '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'
+ optional :ref, type: String, desc: 'When dry_run is true, sets the branch or tag to use. Defaults to the project’s default branch when not set'
end
+
post ':id/ci/lint', urgency: :low do
authorize! :create_pipeline, user_project
diff --git a/lib/api/markdown.rb b/lib/api/markdown.rb
index 1f8255fd6a4..276560f3433 100644
--- a/lib/api/markdown.rb
+++ b/lib/api/markdown.rb
@@ -7,13 +7,19 @@ module API
feature_category :team_planning
params do
- requires :text, type: String, desc: "The markdown text to render"
- optional :gfm, type: Boolean, desc: "Render text using GitLab Flavored Markdown"
- optional :project, type: String, desc: "The full path of a project to use as the context when creating references using GitLab Flavored Markdown"
+ requires :text, type: String, desc: "The Markdown text to render"
+ optional :gfm, type: Boolean, desc: "Render text using GitLab Flavored Markdown. Default is false"
+ optional :project, type: String, desc: "Use project as a context when creating references using GitLab Flavored Markdown"
end
resource :markdown do
- desc "Render markdown text" do
+ desc "Render an arbitrary Markdown document" do
detail "This feature was introduced in GitLab 11.0."
+ success ::API::Entities::Markdown
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags %w[markdown]
end
post do
context = { only_path: false, current_user: current_user }
@@ -29,7 +35,7 @@ module API
context[:skip_project_check] = true
end
- { html: Banzai.render_and_post_process(params[:text], context) }
+ present({ html: Banzai.render_and_post_process(params[:text], context) }, with: Entities::Markdown)
end
end
end
diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb
index 72313d6a588..30cdaba76ba 100644
--- a/lib/api/maven_packages.rb
+++ b/lib/api/maven_packages.rb
@@ -220,7 +220,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Download the maven package file' do
@@ -232,18 +232,20 @@ module API
end
route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true
get ':id/packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do
+ project = user_project(action: :read_package)
+
# return a similar failure to user_project
- unless Feature.enabled?(:maven_central_request_forwarding, user_project&.root_ancestor)
+ unless Feature.enabled?(:maven_central_request_forwarding, project&.root_ancestor)
not_found!('Project') unless path_exists?(params[:path])
end
- authorize_read_package!(user_project)
+ authorize_read_package!(project)
file_name, format = extract_format(params[:file_name])
- package = fetch_package(file_name: file_name, project: user_project)
+ package = fetch_package(file_name: file_name, project: project)
- find_and_present_package_file(package, file_name, format, params.merge(target: user_project))
+ find_and_present_package_file(package, file_name, format, params.merge(target: project))
end
desc 'Workhorse authorize the maven package file upload' do
@@ -268,7 +270,7 @@ module API
params do
requires :path, type: String, desc: 'Package path'
requires :file_name, type: String, desc: 'Package file name', regexp: Gitlab::Regex.maven_file_name_regex
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
end
route_setting :authentication, job_token_allowed: true, deploy_token_allowed: true
put ':id/packages/maven/*path/:file_name', requirements: MAVEN_ENDPOINT_REQUIREMENTS do
diff --git a/lib/api/merge_request_approvals.rb b/lib/api/merge_request_approvals.rb
index 71ca8331ed6..7622ec717cc 100644
--- a/lib/api/merge_request_approvals.rb
+++ b/lib/api/merge_request_approvals.rb
@@ -6,10 +6,9 @@ module API
feature_category :source_code_management
- helpers do
- params :ee_approval_params do
- end
+ helpers ::API::Helpers::MergeRequestsHelpers
+ helpers do
def present_approval(merge_request)
present merge_request, with: ::API::Entities::MergeRequestApprovals, current_user: current_user
end
@@ -24,7 +23,12 @@ module API
# merge_request_iid (required) - IID of MR
# Examples:
# GET /projects/:id/merge_requests/:merge_request_iid/approvals
- desc 'List approvals for merge request'
+ desc 'List approvals for merge request' do
+ success ::API::Entities::MergeRequestApprovals
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ end
get 'approvals', urgency: :low do
merge_request = find_merge_request_with_access(params[:merge_request_iid])
@@ -39,7 +43,13 @@ module API
# Examples:
# POST /projects/:id/merge_requests/:merge_request_iid/approve
#
- desc 'Approve a merge request'
+ desc 'Approve a merge request' do
+ success code: 201, model: ::API::Entities::MergeRequestApprovals
+ failure [
+ { code: 404, message: 'Not found' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ end
params do
optional :sha, type: String, desc: 'When present, must have the HEAD SHA of the source branch'
@@ -60,7 +70,13 @@ module API
present_approval(merge_request)
end
- desc 'Remove an approval from a merge request'
+ desc 'Remove an approval from a merge request' do
+ success code: 201, model: ::API::Entities::MergeRequestApprovals
+ failure [
+ { code: 404, message: 'Not found' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ end
post 'unapprove', urgency: :low do
merge_request = find_merge_request_with_access(params[:merge_request_iid], :approve_merge_request)
diff --git a/lib/api/merge_request_diffs.rb b/lib/api/merge_request_diffs.rb
index 87623568a04..c7f0f88eacc 100644
--- a/lib/api/merge_request_diffs.rb
+++ b/lib/api/merge_request_diffs.rb
@@ -10,16 +10,18 @@ module API
feature_category :code_review
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a list of merge request diff versions' do
detail 'This feature was introduced in GitLab 8.12.'
success Entities::MergeRequestDiff
+ tags %w[merge_requests]
+ is_array true
end
params do
- requires :merge_request_iid, type: Integer, desc: 'The IID of a merge request'
+ requires :merge_request_iid, type: Integer, desc: 'The internal ID of the merge request'
use :pagination
end
get ":id/merge_requests/:merge_request_iid/versions" do
@@ -31,11 +33,12 @@ module API
desc 'Get a single merge request diff version' do
detail 'This feature was introduced in GitLab 8.12.'
success Entities::MergeRequestDiffFull
+ tags %w[merge_requests]
end
params do
- requires :merge_request_iid, type: Integer, desc: 'The IID of a merge request'
- requires :version_id, type: Integer, desc: 'The ID of a merge request diff version'
+ requires :merge_request_iid, type: Integer, desc: 'The internal ID of the merge request'
+ requires :version_id, type: Integer, desc: 'The ID of the merge request diff version'
end
get ":id/merge_requests/:merge_request_iid/versions/:version_id", urgency: :low do
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index a0e7d0b10cd..bb2861aa221 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -170,7 +170,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
include TimeTrackingEndpoints
diff --git a/lib/api/metadata.rb b/lib/api/metadata.rb
index 3e42ffe336a..788d9843c63 100644
--- a/lib/api/metadata.rb
+++ b/lib/api/metadata.rb
@@ -9,6 +9,8 @@ module API
before { authenticate! }
+ METADATA_TAGS = %w[metadata].freeze
+
feature_category :not_owned # rubocop:todo Gitlab/AvoidFeatureCategoryNotOwned
METADATA_QUERY = <<~EOF
@@ -21,6 +23,7 @@ module API
externalUrl
version
}
+ enterprise
}
}
EOF
@@ -35,30 +38,13 @@ module API
end
end
- desc 'Retrieve metadata information for this GitLab instance.' do
+ desc 'Retrieve metadata information for this GitLab instance' do
detail 'This feature was introduced in GitLab 15.2.'
- success [
- {
- code: 200,
- model: Entities::Metadata,
- message: 'successful operation',
- examples: {
- successful_response: {
- 'value' => {
- version: "15.0-pre",
- revision: "c401a659d0c",
- kas: {
- enabled: true,
- externalUrl: "grpc://gitlab.example.com:8150",
- version: "15.0.0"
- }
- }
- }
- }
- }
+ success Entities::Metadata
+ failure [
+ { code: 401, message: 'Unauthorized' }
]
- failure [{ code: 401, message: 'unauthorized operation' }]
- tags %w[metadata]
+ tags METADATA_TAGS
end
get '/metadata' do
run_metadata_query
@@ -66,31 +52,14 @@ module API
# Support the deprecated `/version` route.
# See https://gitlab.com/gitlab-org/gitlab/-/issues/366287
- desc 'Get the version information of the GitLab instance.' do
+ desc 'Retrieves version information for the GitLab instance' do
detail 'This feature was introduced in GitLab 8.13 and deprecated in 15.5. ' \
'We recommend you instead use the Metadata API.'
- success [
- {
- code: 200,
- model: Entities::Metadata,
- message: 'successful operation',
- examples: {
- 'Example' => {
- 'value' => {
- version: "15.0-pre",
- revision: "c401a659d0c",
- kas: {
- enabled: true,
- externalUrl: "grpc://gitlab.example.com:8150",
- version: "15.0.0"
- }
- }
- }
- }
- }
+ success Entities::Metadata
+ failure [
+ { code: 401, message: 'Unauthorized' }
]
- failure [{ code: 401, message: 'unauthorized operation' }]
- tags %w[metadata]
+ tags METADATA_TAGS
end
get '/version' do
diff --git a/lib/api/metrics/dashboard/annotations.rb b/lib/api/metrics/dashboard/annotations.rb
index 478adcdce70..6ba154191be 100644
--- a/lib/api/metrics/dashboard/annotations.rb
+++ b/lib/api/metrics/dashboard/annotations.rb
@@ -7,8 +7,15 @@ module API
feature_category :metrics
urgency :low
- desc 'Create a new monitoring dashboard annotation' do
+ desc 'Create a new annotation' do
+ detail 'Creates a new monitoring dashboard annotation'
success Entities::Metrics::Dashboard::Annotation
+ failure [
+ { code: 400, message: 'Bad Request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not Found' }
+ ]
+ tags %w[dashboard_annotations]
end
ANNOTATIONS_SOURCES = [
@@ -20,12 +27,16 @@ module API
resource annotations_source[:resource] do
params do
requires :starting_at, type: DateTime,
- desc: 'Date time indicating starting moment to which the annotation relates.'
+ desc: 'Date time string, ISO 8601 formatted, such as 2016-03-11T03:45:40Z.'\
+ 'Timestamp marking start point of annotation.'
optional :ending_at, type: DateTime,
- desc: 'Date time indicating ending moment to which the annotation relates.'
+ desc: 'Date time string, ISO 8601 formatted, such as 2016-03-11T03:45:40Z.'\
+ 'Timestamp marking end point of annotation.'\
+ 'When not supplied, an annotation displays as a single event at the start point.'
requires :dashboard_path, type: String, coerce_with: -> (val) { CGI.unescape(val) },
- desc: 'The path to a file defining the dashboard on which the annotation should be added'
- requires :description, type: String, desc: 'The description of the annotation'
+ desc: 'ID of the dashboard which needs to be annotated.'\
+ 'Treated as a CGI-escaped path, and automatically un-escaped.'
+ requires :description, type: String, desc: 'Description of the annotation.'
end
post ':id/metrics_dashboard/annotations' do
@@ -33,7 +44,9 @@ module API
forbidden! unless can?(current_user, :create_metrics_dashboard_annotation, annotations_source_object)
- create_service_params = declared(params).merge(annotations_source[:create_service_param_key] => annotations_source_object)
+ create_service_params = declared(params).merge(
+ annotations_source[:create_service_param_key] => annotations_source_object
+ )
result = ::Metrics::Dashboard::Annotations::CreateService.new(current_user, create_service_params).execute
diff --git a/lib/api/metrics/user_starred_dashboards.rb b/lib/api/metrics/user_starred_dashboards.rb
index 4d5396acccb..0a91e914d52 100644
--- a/lib/api/metrics/user_starred_dashboards.rb
+++ b/lib/api/metrics/user_starred_dashboards.rb
@@ -6,14 +6,22 @@ module API
feature_category :metrics
urgency :low
+ USER_STARRED_DASHBOARDS_TAGS = %w[user_starred_dashboards].freeze
+
resource :projects do
- desc 'Marks selected metrics dashboard as starred' do
+ desc 'Add a star to a dashboard' do
+ detail 'Marks selected metrics dashboard as starred. Introduced in GitLab 13.0.'
success Entities::Metrics::UserStarredDashboard
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags USER_STARRED_DASHBOARDS_TAGS
end
params do
requires :dashboard_path, type: String, allow_blank: false, coerce_with: ->(val) { CGI.unescape(val) },
- desc: 'Url encoded path to a file defining the dashboard to which the star should be added'
+ desc: 'URL-encoded path to file defining the dashboard which should be marked as favorite'
end
post ':id/metrics/user_starred_dashboards' do
@@ -26,7 +34,15 @@ module API
end
end
- desc 'Remove star from selected metrics dashboard'
+ desc 'Remove a star from a dashboard' do
+ detail 'Remove star from selected metrics dashboard. Introduced in GitLab 13.0.'
+ success code: 200
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags USER_STARRED_DASHBOARDS_TAGS
+ end
params do
optional :dashboard_path, type: String, allow_blank: false, coerce_with: ->(val) { CGI.unescape(val) },
diff --git a/lib/api/ml/mlflow.rb b/lib/api/ml/mlflow.rb
index 2ffb04ebcbd..56bfac1530e 100644
--- a/lib/api/ml/mlflow.rb
+++ b/lib/api/ml/mlflow.rb
@@ -68,10 +68,19 @@ module API
def find_candidate!(iid)
candidate_repository.by_iid(iid) || resource_not_found!
end
+
+ def packages_url
+ path = api_v4_projects_packages_generic_package_version_path(
+ id: user_project.id, package_name: '', file_name: ''
+ )
+ path = path.delete_suffix('/package_version')
+
+ "#{request.base_url}#{path}"
+ end
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'API to interface with MLFlow Client, REST API version 1.28.0' do
@@ -130,8 +139,7 @@ module API
resource :runs do
desc 'Creates a Run.' do
success Entities::Ml::Mlflow::Run
- detail ['https://www.mlflow.org/docs/1.28.0/rest-api.html#create-run',
- 'MLFlow Runs map to GitLab Candidates']
+ detail 'MLFlow Runs map to GitLab Candidates. https://www.mlflow.org/docs/1.28.0/rest-api.html#create-run'
end
params do
requires :experiment_id, type: Integer,
@@ -143,7 +151,8 @@ module API
optional :tags, type: Array, desc: 'This will be ignored'
end
post 'create', urgency: :low do
- present candidate_repository.create!(experiment, params[:start_time]), with: Entities::Ml::Mlflow::Run
+ present candidate_repository.create!(experiment, params[:start_time]),
+ with: Entities::Ml::Mlflow::Run, packages_url: packages_url
end
desc 'Gets an MLFlow Run, which maps to GitLab Candidates' do
@@ -155,13 +164,12 @@ module API
optional :run_uuid, type: String, desc: 'This parameter is ignored'
end
get 'get', urgency: :low do
- present candidate, with: Entities::Ml::Mlflow::Run
+ present candidate, with: Entities::Ml::Mlflow::Run, packages_url: packages_url
end
desc 'Updates a Run.' do
success Entities::Ml::Mlflow::UpdateRun
- detail ['https://www.mlflow.org/docs/1.28.0/rest-api.html#update-run',
- 'MLFlow Runs map to GitLab Candidates']
+ detail 'MLFlow Runs map to GitLab Candidates. https://www.mlflow.org/docs/1.28.0/rest-api.html#update-run'
end
params do
requires :run_id, type: String, desc: 'UUID of the candidate.'
@@ -174,7 +182,7 @@ module API
post 'update', urgency: :low do
candidate_repository.update(candidate, params[:status], params[:end_time])
- present candidate, with: Entities::Ml::Mlflow::UpdateRun
+ present candidate, with: Entities::Ml::Mlflow::UpdateRun, packages_url: packages_url
end
desc 'Logs a metric to a run.' do
diff --git a/lib/api/npm_project_packages.rb b/lib/api/npm_project_packages.rb
index 166c0b755fe..494b493f5e0 100644
--- a/lib/api/npm_project_packages.rb
+++ b/lib/api/npm_project_packages.rb
@@ -11,7 +11,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
namespace 'projects/:id/packages/npm' do
desc 'Download the NPM tarball' do
diff --git a/lib/api/nuget_project_packages.rb b/lib/api/nuget_project_packages.rb
index 3e05ea13311..d549a8be035 100644
--- a/lib/api/nuget_project_packages.rb
+++ b/lib/api/nuget_project_packages.rb
@@ -35,7 +35,7 @@ module API
helpers do
params :file_params do
- requires :package, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :package, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
end
def project_or_group
@@ -91,7 +91,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project', regexp: ::API::Concerns::Packages::NugetEndpoints::POSITIVE_INTEGER_REGEX
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project', regexp: ::API::Concerns::Packages::NugetEndpoints::POSITIVE_INTEGER_REGEX
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
namespace ':id/packages/nuget' do
diff --git a/lib/api/package_files.rb b/lib/api/package_files.rb
index 278dc4c2044..bb9f96cdbb1 100644
--- a/lib/api/package_files.rb
+++ b/lib/api/package_files.rb
@@ -8,19 +8,23 @@ module API
authorize_packages_access!(user_project)
end
+ PACKAGE_FILES_TAGS = %w[package_files].freeze
+
feature_category :package_registry
urgency :low
helpers ::API::Helpers::PackagesHelpers
params do
- requires :id, type: String, desc: 'The ID of a project'
- requires :package_id, type: Integer, desc: 'The ID of a package'
+ requires :id, types: [String, Integer], desc: 'ID or URL-encoded path of the project'
+ requires :package_id, type: Integer, desc: 'ID of a package'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get all package files' do
- detail 'This feature was introduced in GitLab 11.8'
+ desc 'List package files' do
+ detail 'Get a list of package files of a single package'
success ::API::Entities::PackageFile
+ is_array true
+ tags PACKAGE_FILES_TAGS
end
params do
use :pagination
@@ -35,11 +39,17 @@ module API
present paginate(package_files), with: ::API::Entities::PackageFile
end
- desc 'Remove a package file' do
+ desc 'Delete a package file' do
detail 'This feature was introduced in GitLab 13.12'
+ success code: 204
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags PACKAGE_FILES_TAGS
end
params do
- requires :package_file_id, type: Integer, desc: 'The ID of a package file'
+ requires :package_file_id, type: Integer, desc: 'ID of a package file'
end
delete ':id/packages/:package_id/package_files/:package_file_id' do
authorize_destroy_package!(user_project)
diff --git a/lib/api/pages.rb b/lib/api/pages.rb
index 5f695f3853d..7e230bd3c67 100644
--- a/lib/api/pages.rb
+++ b/lib/api/pages.rb
@@ -10,7 +10,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Unpublish pages' do
diff --git a/lib/api/pages_domains.rb b/lib/api/pages_domains.rb
index 9cf61967ba4..967847a8e62 100644
--- a/lib/api/pages_domains.rb
+++ b/lib/api/pages_domains.rb
@@ -54,7 +54,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before do
diff --git a/lib/api/pagination_params.rb b/lib/api/pagination_params.rb
index bdb69d0ba44..c3505780396 100644
--- a/lib/api/pagination_params.rb
+++ b/lib/api/pagination_params.rb
@@ -17,8 +17,9 @@ module API
included do
helpers do
params :pagination do
- optional :page, type: Integer, default: 1, desc: 'Current page number'
- optional :per_page, type: Integer, default: 20, desc: 'Number of items per page', except_values: [0]
+ optional :page, type: Integer, default: 1, desc: 'Current page number', documentation: { example: 1 }
+ optional :per_page, type: Integer, default: 20,
+ desc: 'Number of items per page', except_values: [0], documentation: { example: 20 }
end
def verify_pagination_params!
diff --git a/lib/api/personal_access_tokens.rb b/lib/api/personal_access_tokens.rb
index a2903faa4ad..66930ecd797 100644
--- a/lib/api/personal_access_tokens.rb
+++ b/lib/api/personal_access_tokens.rb
@@ -6,24 +6,6 @@ module API
feature_category :authentication_and_authorization
- desc 'Get all Personal Access Tokens' do
- detail 'This feature was added in GitLab 13.3'
- success Entities::PersonalAccessToken
- end
- params do
- optional :user_id, type: Integer, desc: 'Filter PATs by User ID'
- optional :revoked, type: Boolean, desc: 'Filter PATs where revoked state matches parameter'
- optional :state, type: String, desc: 'Filter PATs which are either active or not',
- values: %w[active inactive]
- optional :created_before, type: DateTime, desc: 'Filter PATs which were created before given datetime'
- optional :created_after, type: DateTime, desc: 'Filter PATs which were created after given datetime'
- optional :last_used_before, type: DateTime, desc: 'Filter PATs which were used before given datetime'
- optional :last_used_after, type: DateTime, desc: 'Filter PATs which were used after given datetime'
- optional :search, type: String, desc: 'Filters PATs by its name'
-
- use :pagination
- end
-
before do
authenticate!
restrict_non_admins! unless current_user.can_admin_all_resources?
@@ -32,12 +14,47 @@ module API
helpers ::API::Helpers::PersonalAccessTokensHelpers
resources :personal_access_tokens do
+ desc 'List personal access tokens' do
+ detail 'Get all personal access tokens the authenticated user has access to.'
+ is_array true
+ success Entities::PersonalAccessToken
+ tags %w[personal_access_tokens]
+ failure [
+ { code: 401, message: 'Unauthorized' }
+ ]
+ end
+ params do
+ optional :user_id, type: Integer, desc: 'Filter PATs by User ID', documentation: { example: 2 }
+ optional :revoked, type: Boolean, desc: 'Filter PATs where revoked state matches parameter',
+ documentation: { example: false }
+ optional :state, type: String, desc: 'Filter PATs which are either active or not',
+ values: %w[active inactive], documentation: { example: 'active' }
+ optional :created_before, type: DateTime, desc: 'Filter PATs which were created before given datetime',
+ documentation: { example: '2022-01-01' }
+ optional :created_after, type: DateTime, desc: 'Filter PATs which were created after given datetime',
+ documentation: { example: '2021-01-01' }
+ optional :last_used_before, type: DateTime, desc: 'Filter PATs which were used before given datetime',
+ documentation: { example: '2021-01-01' }
+ optional :last_used_after, type: DateTime, desc: 'Filter PATs which were used after given datetime',
+ documentation: { example: '2022-01-01' }
+ optional :search, type: String, desc: 'Filters PATs by its name', documentation: { example: 'token' }
+
+ use :pagination
+ end
get do
tokens = PersonalAccessTokensFinder.new(finder_params(current_user), current_user).execute
present paginate(tokens), with: Entities::PersonalAccessToken
end
+ desc 'Get single personal access token' do
+ detail 'Get a personal access token by using the ID of the personal access token.'
+ success Entities::PersonalAccessToken
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ end
get ':id' do
token = PersonalAccessToken.find_by_id(params[:id])
@@ -51,6 +68,13 @@ module API
end
end
+ desc 'Revoke a personal access token' do
+ detail 'Revoke a personal access token by using the ID of the personal access token.'
+ success code: 204
+ failure [
+ { code: 400, message: 'Bad Request' }
+ ]
+ end
delete ':id' do
token = find_token(params[:id])
diff --git a/lib/api/personal_access_tokens/self_information.rb b/lib/api/personal_access_tokens/self_information.rb
index 89850614f94..5735fe49f33 100644
--- a/lib/api/personal_access_tokens/self_information.rb
+++ b/lib/api/personal_access_tokens/self_information.rb
@@ -17,10 +17,28 @@ module API
before { authenticate! }
resource :personal_access_tokens do
+ desc "Get single personal access token" do
+ detail 'Get the details of a personal access token by passing it to the API in a header'
+ success code: 200, model: Entities::PersonalAccessToken
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[personal_access_tokens]
+ end
get 'self' do
present access_token, with: Entities::PersonalAccessToken
end
+ desc "Revoke a personal access token" do
+ detail 'Revoke a personal access token by passing it to the API in a header'
+ success code: 204
+ failure [
+ { code: 400, message: 'Bad Request' }
+ ]
+ tags %w[personal_access_tokens]
+ end
+
delete 'self' do
revoke_token(access_token)
end
diff --git a/lib/api/project_clusters.rb b/lib/api/project_clusters.rb
index 4644d38ea80..21f1ee69613 100644
--- a/lib/api/project_clusters.rb
+++ b/lib/api/project_clusters.rb
@@ -13,12 +13,17 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of the project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get all clusters from the project' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'List project clusters' do
+ detail 'This feature was introduced in GitLab 11.7. Returns a list of project clusters.'
success Entities::Cluster
+ failure [
+ { code: 403, message: 'Forbidden' }
+ ]
+ is_array true
+ tags %w[clusters]
end
params do
use :pagination
@@ -29,9 +34,14 @@ module API
present paginate(clusters_for_current_user), with: Entities::Cluster
end
- desc 'Get specific cluster for the project' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Get a single project cluster' do
+ detail 'This feature was introduced in GitLab 11.7. Gets a single project cluster.'
success Entities::ClusterProject
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
@@ -42,9 +52,15 @@ module API
present cluster, with: Entities::ClusterProject
end
- desc 'Adds an existing cluster' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Add existing cluster to project' do
+ detail 'This feature was introduced in GitLab 11.7. Adds an existing Kubernetes cluster to the project.'
success Entities::ClusterProject
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :name, type: String, desc: 'Cluster name'
@@ -76,9 +92,15 @@ module API
end
end
- desc 'Update an existing cluster' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Edit project cluster' do
+ detail 'This feature was introduced in GitLab 11.7. Updates an existing project cluster.'
success Entities::ClusterProject
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The cluster ID'
@@ -108,9 +130,14 @@ module API
end
end
- desc 'Remove a cluster' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Delete project cluster' do
+ detail 'This feature was introduced in GitLab 11.7. Deletes an existing project cluster. Does not remove existing resources within the connected Kubernetes cluster.'
success Entities::ClusterProject
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[clusters]
end
params do
requires :cluster_id, type: Integer, desc: 'The Cluster ID'
diff --git a/lib/api/project_container_repositories.rb b/lib/api/project_container_repositories.rb
index 6a6275ed02a..c5add42decc 100644
--- a/lib/api/project_container_repositories.rb
+++ b/lib/api/project_container_repositories.rb
@@ -16,7 +16,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
route_setting :authentication, job_token_allowed: true, job_token_scope: :project
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -47,8 +47,12 @@ module API
end
delete ':id/registry/repositories/:repository_id', requirements: REPOSITORY_ENDPOINT_REQUIREMENTS do
authorize_admin_container_image!
+ repository.delete_scheduled!
+
+ unless Feature.enabled?(:container_registry_delete_repository_with_cron_worker)
+ DeleteContainerRepositoryWorker.perform_async(current_user.id, repository.id) # rubocop:disable CodeReuse/Worker
+ end
- DeleteContainerRepositoryWorker.perform_async(current_user.id, repository.id) # rubocop:disable CodeReuse/Worker
track_package_event('delete_repository', :container, user: current_user, project: user_project, namespace: user_project.namespace)
status :accepted
diff --git a/lib/api/project_debian_distributions.rb b/lib/api/project_debian_distributions.rb
index b8ca9428fa3..1e27f5c8856 100644
--- a/lib/api/project_debian_distributions.rb
+++ b/lib/api/project_debian_distributions.rb
@@ -3,7 +3,7 @@
module API
class ProjectDebianDistributions < ::API::Base
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
before do
diff --git a/lib/api/project_events.rb b/lib/api/project_events.rb
index e8829216336..d90ce32c354 100644
--- a/lib/api/project_events.rb
+++ b/lib/api/project_events.rb
@@ -12,10 +12,15 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
+ optional :action, type: String, desc: 'Include only events of a particular action type'
+ optional :target_type, type: String, desc: 'Include only events of a particular target type'
+ optional :before, type: DateTime, desc: 'Include only events created before a particular date'
+ optional :after, type: DateTime, desc: 'Include only events created after a particular date'
+ optional :sort, type: String, desc: 'Sort events in asc or desc order by created_at. Default is desc'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc "List a Project's visible events" do
+ desc "List a project's visible events" do
success Entities::Event
end
params do
diff --git a/lib/api/project_export.rb b/lib/api/project_export.rb
index 29fdfe45566..e4e950fb603 100644
--- a/lib/api/project_export.rb
+++ b/lib/api/project_export.rb
@@ -11,12 +11,19 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: { id: %r{[^/]+} } do
desc 'Get export status' do
detail 'This feature was introduced in GitLab 10.6.'
- success Entities::ProjectExportStatus
+ success code: 200, model: Entities::ProjectExportStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_export']
end
get ':id/export' do
present user_project, with: Entities::ProjectExportStatus
@@ -24,6 +31,15 @@ module API
desc 'Download export' do
detail 'This feature was introduced in GitLab 10.6.'
+ success code: 200
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_export']
+ produces %w[application/octet-stream application/json]
end
get ':id/export/download' do
check_rate_limit! :project_download_export, scope: [current_user, user_project.namespace]
@@ -41,6 +57,16 @@ module API
desc 'Start export' do
detail 'This feature was introduced in GitLab 10.6.'
+ success code: 202
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 429, message: 'Too many requests' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_export']
end
params do
optional :description, type: String, desc: 'Override the project description'
@@ -86,6 +112,15 @@ module API
desc 'Start relations export' do
detail 'This feature was introduced in GitLab 14.4'
+ success code: 202
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_export']
end
post ':id/export_relations' do
response = ::BulkImports::ExportService.new(portable: user_project, user: current_user).execute
@@ -93,12 +128,23 @@ module API
if response.success?
accepted!
else
- render_api_error!(message: 'Project relations export could not be started.')
+ render_api_error!('Project relations export could not be started.', 500)
end
end
desc 'Download relations export' do
detail 'This feature was introduced in GitLab 14.4'
+ success code: 200
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 500, message: 'Internal Server Error' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_export']
+ produces %w[application/octet-stream application/json]
end
params do
requires :relation,
@@ -119,6 +165,15 @@ module API
desc 'Relations export status' do
detail 'This feature was introduced in GitLab 14.4'
+ is_array true
+ success code: 200, model: Entities::BulkImports::ExportStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_export']
end
get ':id/export_relations/status' do
present user_project.bulk_import_exports, with: Entities::BulkImports::ExportStatus
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index 466e80d68c8..ced8ecec883 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -4,6 +4,8 @@ module API
class ProjectHooks < ::API::Base
include PaginationParams
+ project_hooks_tags = %w[project_hooks]
+
before { authenticate! }
before { authorize_admin_project }
@@ -37,15 +39,18 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
namespace ':id/hooks' do
mount ::API::Hooks::UrlVariables
end
- desc 'Get project hooks' do
+ desc 'List project hooks' do
+ detail 'Get a list of project hooks'
success Entities::ProjectHook
+ is_array true
+ tags project_hooks_tags
end
params do
use :pagination
@@ -54,8 +59,13 @@ module API
present paginate(user_project.hooks), with: Entities::ProjectHook
end
- desc 'Get a project hook' do
+ desc 'Get project hook' do
+ detail 'Get a specific hook for a project'
success Entities::ProjectHook
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags project_hooks_tags
end
params do
requires :hook_id, type: Integer, desc: 'The ID of a project hook'
@@ -65,8 +75,15 @@ module API
present hook, with: Entities::ProjectHook
end
- desc 'Add hook to project' do
+ desc 'Add project hook' do
+ detail 'Adds a hook to a specified project'
success Entities::ProjectHook
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags project_hooks_tags
end
params do
use :requires_url
@@ -79,11 +96,18 @@ module API
save_hook(hook, Entities::ProjectHook)
end
- desc 'Update an existing hook' do
+ desc 'Edit project hook' do
+ detail 'Edits a hook for a specified project.'
success Entities::ProjectHook
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags project_hooks_tags
end
params do
- requires :hook_id, type: Integer, desc: "The ID of the hook to update"
+ requires :hook_id, type: Integer, desc: 'The ID of the project hook'
use :optional_url
use :common_hook_parameters
end
@@ -91,11 +115,16 @@ module API
update_hook(entity: Entities::ProjectHook)
end
- desc 'Deletes project hook' do
+ desc 'Delete a project hook' do
+ detail 'Removes a hook from a project. This is an idempotent method and can be called multiple times. Either the hook is available or not.'
success Entities::ProjectHook
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags project_hooks_tags
end
params do
- requires :hook_id, type: Integer, desc: 'The ID of the hook to delete'
+ requires :hook_id, type: Integer, desc: 'The ID of the project hook'
end
delete ":id/hooks/:hook_id" do
hook = find_hook
diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb
index 0da8c1ecedd..02f0d9a2a70 100644
--- a/lib/api/project_import.rb
+++ b/lib/api/project_import.rb
@@ -40,6 +40,7 @@ module API
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Workhorse authorize the project import upload' do
detail 'This feature was introduced in GitLab 12.9'
+ tags ['project_import']
end
post 'import/authorize' do
require_gitlab_workhorse!
@@ -77,7 +78,16 @@ module API
end
desc 'Create a new project import' do
detail 'This feature was introduced in GitLab 10.6.'
- success Entities::ProjectImportStatus
+ success code: 201, model: Entities::ProjectImportStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_import']
+ consumes ['multipart/form-data']
end
post 'import' do
require_gitlab_workhorse!
@@ -108,11 +118,19 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
desc 'Get a project import status' do
detail 'This feature was introduced in GitLab 10.6.'
- success Entities::ProjectImportStatus
+ success code: 200, model: Entities::ProjectImportStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags ['project_import']
end
route_setting :skip_authentication, true
get ':id/import' do
@@ -133,7 +151,17 @@ module API
end
desc 'Create a new project import using a remote object storage path' do
detail 'This feature was introduced in GitLab 13.2.'
- success Entities::ProjectImportStatus
+ consumes ['multipart/form-data']
+ tags ['project_import']
+ success code: 201, model: Entities::ProjectImportStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' },
+ { code: 429, message: 'Too many requests' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
post 'remote-import' do
check_rate_limit! :project_import, scope: [current_user, :project_import]
@@ -176,7 +204,17 @@ module API
end
desc 'Create a new project import using a file from AWS S3' do
detail 'This feature was introduced in GitLab 14.9.'
- success Entities::ProjectImportStatus
+ consumes ['multipart/form-data']
+ tags ['project_import']
+ success code: 201, model: Entities::ProjectImportStatus
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 400, message: 'Bad request' },
+ { code: 404, message: 'Not found' },
+ { code: 429, message: 'Too many requests' },
+ { code: 503, message: 'Service unavailable' }
+ ]
end
post 'remote-import-s3' do
not_found! unless ::Feature.enabled?(:import_project_from_remote_file_s3)
diff --git a/lib/api/project_milestones.rb b/lib/api/project_milestones.rb
index 9f82dbf9813..a7a583aaa23 100644
--- a/lib/api/project_milestones.rb
+++ b/lib/api/project_milestones.rb
@@ -11,7 +11,7 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a list of project milestones' do
diff --git a/lib/api/project_packages.rb b/lib/api/project_packages.rb
index 800966408fc..d09c481403f 100644
--- a/lib/api/project_packages.rb
+++ b/lib/api/project_packages.rb
@@ -14,7 +14,7 @@ module API
helpers ::API::Helpers::PackagesHelpers
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get all project packages' do
diff --git a/lib/api/project_repository_storage_moves.rb b/lib/api/project_repository_storage_moves.rb
index ab5d8b3a888..5777b8754e7 100644
--- a/lib/api/project_repository_storage_moves.rb
+++ b/lib/api/project_repository_storage_moves.rb
@@ -11,7 +11,8 @@ module API
resource :project_repository_storage_moves do
desc 'Get a list of all project repository storage moves' do
detail 'This feature was introduced in GitLab 13.0.'
- success Entities::Projects::RepositoryStorageMove
+ is_array true
+ success code: 200, model: Entities::Projects::RepositoryStorageMove
end
params do
use :pagination
@@ -24,7 +25,7 @@ module API
desc 'Get a project repository storage move' do
detail 'This feature was introduced in GitLab 13.0.'
- success Entities::Projects::RepositoryStorageMove
+ success code: 200, model: Entities::Projects::RepositoryStorageMove
end
params do
requires :repository_storage_move_id, type: Integer, desc: 'The ID of a project repository storage move'
@@ -37,6 +38,7 @@ module API
desc 'Schedule bulk project repository storage moves' do
detail 'This feature was introduced in GitLab 13.7.'
+ success code: 202
end
params do
requires :source_storage_name, type: String, desc: 'The source storage shard', values: -> { Gitlab.config.repositories.storages.keys }
@@ -53,12 +55,13 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a list of all project repository storage moves' do
detail 'This feature was introduced in GitLab 13.1.'
- success Entities::Projects::RepositoryStorageMove
+ is_array true
+ success code: 200, model: Entities::Projects::RepositoryStorageMove
end
params do
use :pagination
@@ -71,7 +74,7 @@ module API
desc 'Get a project repository storage move' do
detail 'This feature was introduced in GitLab 13.1.'
- success Entities::Projects::RepositoryStorageMove
+ success code: 200, model: Entities::Projects::RepositoryStorageMove
end
params do
requires :repository_storage_move_id, type: Integer, desc: 'The ID of a project repository storage move'
@@ -84,14 +87,14 @@ module API
desc 'Schedule a project repository storage move' do
detail 'This feature was introduced in GitLab 13.1.'
- success Entities::Projects::RepositoryStorageMove
+ success code: 201, model: Entities::Projects::RepositoryStorageMove
end
params do
optional :destination_storage_name, type: String, desc: 'The destination storage shard'
end
post ':id/repository_storage_moves' do
storage_move = user_project.repository_storage_moves.build(
- declared_params.merge(source_storage_name: user_project.repository_storage)
+ declared_params.compact.merge(source_storage_name: user_project.repository_storage)
)
if storage_move.schedule
diff --git a/lib/api/project_snapshots.rb b/lib/api/project_snapshots.rb
index d33d2976b1c..d2ed7f75fb7 100644
--- a/lib/api/project_snapshots.rb
+++ b/lib/api/project_snapshots.rb
@@ -11,6 +11,11 @@ module API
resource :projects do
desc 'Download a (possibly inconsistent) snapshot of a repository' do
detail 'This feature was introduced in GitLab 10.7'
+ success File
+ produces 'application/x-tar'
+ failure [
+ { code: 401, message: 'Unauthorized' }
+ ]
end
params do
optional :wiki, type: Boolean, desc: 'Set to true to receive the wiki repository'
diff --git a/lib/api/project_snippets.rb b/lib/api/project_snippets.rb
index 14792730eae..93ffb23fea8 100644
--- a/lib/api/project_snippets.rb
+++ b/lib/api/project_snippets.rb
@@ -9,7 +9,7 @@ module API
feature_category :snippets
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
helpers Helpers::SnippetsHelpers
@@ -34,6 +34,11 @@ module API
desc 'Get all project snippets' do
success Entities::ProjectSnippet
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[project_snippets]
+ is_array true
end
params do
use :pagination
@@ -46,6 +51,10 @@ module API
desc 'Get a single project snippet' do
success Entities::ProjectSnippet
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[project_snippets]
end
params do
requires :snippet_id, type: Integer, desc: 'The ID of a project snippet'
@@ -60,6 +69,12 @@ module API
desc 'Create a new project snippet' do
success Entities::ProjectSnippet
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[project_snippets]
end
params do
requires :title, type: String, allow_blank: false, desc: 'The title of the snippet'
@@ -91,6 +106,12 @@ module API
desc 'Update an existing project snippet' do
success Entities::ProjectSnippet
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[project_snippets]
end
params do
requires :snippet_id, type: Integer, desc: 'The ID of a project snippet'
@@ -132,7 +153,14 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
- desc 'Delete a project snippet'
+ desc 'Delete a project snippet' do
+ success code: 204
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[project_snippets]
+ end
params do
requires :snippet_id, type: Integer, desc: 'The ID of a project snippet'
end
@@ -156,7 +184,13 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
- desc 'Get a raw project snippet'
+ desc 'Get a raw project snippet' do
+ success Entities::ProjectSnippet
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[project_snippets]
+ end
params do
requires :snippet_id, type: Integer, desc: 'The ID of a project snippet'
end
@@ -168,7 +202,13 @@ module API
present content_for(snippet)
end
- desc 'Get raw project snippet file contents from the repository'
+ desc 'Get raw project snippet file contents from the repository' do
+ success Entities::ProjectSnippet
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[project_snippets]
+ end
params do
use :raw_file_params
end
@@ -182,6 +222,10 @@ module API
desc 'Get the user agent details for a project snippet' do
success Entities::UserAgentDetail
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[project_snippets]
end
params do
requires :snippet_id, type: Integer, desc: 'The ID of a project snippet'
diff --git a/lib/api/project_statistics.rb b/lib/api/project_statistics.rb
index 3db8d20ebac..859e53b6981 100644
--- a/lib/api/project_statistics.rb
+++ b/lib/api/project_statistics.rb
@@ -10,10 +10,18 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc 'Get the list of project fetch statistics for the last 30 days'
+ desc 'Get the list of project fetch statistics for the last 30 days' do
+ success Entities::ProjectDailyStatistics
+ failure [
+ { code: 404, message: '404 Project Not Found' },
+ { code: 401, message: '401 Unauthorized' }
+ ]
+ tags %w[projects]
+ end
+
get ":id/statistics" do
statistic_finder = ::Projects::DailyStatisticsFinder.new(user_project)
diff --git a/lib/api/project_templates.rb b/lib/api/project_templates.rb
index f6e1286d616..8ec67988e39 100644
--- a/lib/api/project_templates.rb
+++ b/lib/api/project_templates.rb
@@ -15,12 +15,18 @@ module API
feature_category :source_code_management
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
requires :type, type: String, values: TEMPLATE_TYPES, desc: 'The type (dockerfiles|gitignores|gitlab_ci_ymls|licenses|metrics_dashboard_ymls|issues|merge_requests) of the template'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a list of templates available to this project' do
detail 'This endpoint was introduced in GitLab 11.4'
+ is_array true
+ success Entities::TemplatesList
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
use :pagination
@@ -33,13 +39,24 @@ module API
desc 'Download a template available to this project' do
detail 'This endpoint was introduced in GitLab 11.4'
+ success Entities::License
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
- requires :name, type: String, desc: 'The name of the template'
+ requires :name, type: String,
+ desc: 'The key of the template, as obtained from the collection endpoint.', documentation: { example: 'MIT' }
optional :source_template_project_id, type: Integer,
- desc: 'The project id where a given template is being stored. This is useful when multiple templates from different projects have the same name'
- optional :project, type: String, desc: 'The project name to use when expanding placeholders in the template. Only affects licenses'
- optional :fullname, type: String, desc: 'The full name of the copyright holder to use when expanding placeholders in the template. Only affects licenses'
+ desc: 'The project id where a given template is being stored. This is useful when multiple templates from different projects have the same name',
+ documentation: { example: 1 }
+ optional :project, type: String,
+ desc: 'The project name to use when expanding placeholders in the template. Only affects licenses',
+ documentation: { example: 'GitLab' }
+ optional :fullname, type: String,
+ desc: 'The full name of the copyright holder to use when expanding placeholders in the template. Only affects licenses',
+ documentation: { example: 'GitLab B.V.' }
end
get ':id/templates/:type/:name', requirements: TEMPLATE_NAMES_ENDPOINT_REQUIREMENTS do
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index bb97f4fa7ce..fc898c30a71 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -151,7 +151,6 @@ module API
project_params = project_finder_params
support_order_by_similarity!(project_params)
verify_project_filters!(project_params)
-
ProjectsFinder.new(current_user: current_user, params: project_params).execute
end
@@ -336,7 +335,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a single project' do
@@ -424,7 +423,7 @@ module API
end
desc 'Check pages access of this project'
- get ':id/pages_access', feature_category: :pages do
+ get ':id/pages_access', urgency: :low, feature_category: :pages do
authorize! :read_pages_content, user_project unless user_project.public_pages?
status 200
end
@@ -654,7 +653,7 @@ module API
desc 'Upload a file'
params do
- requires :file, types: [Rack::Multipart::UploadedFile, ::API::Validations::Types::WorkhorseFile], desc: 'The attachment file to be uploaded'
+ requires :file, types: [Rack::Multipart::UploadedFile, ::API::Validations::Types::WorkhorseFile], desc: 'The attachment file to be uploaded', documentation: { type: 'file' }
end
post ":id/uploads", feature_category: :not_owned do # rubocop:todo Gitlab/AvoidFeatureCategoryNotOwned
log_if_upload_exceed_max_size(user_project, params[:file])
diff --git a/lib/api/projects_relation_builder.rb b/lib/api/projects_relation_builder.rb
index fb782b49f02..bb1420534f1 100644
--- a/lib/api/projects_relation_builder.rb
+++ b/lib/api/projects_relation_builder.rb
@@ -10,9 +10,13 @@ module API
execute_batch_counting(projects_relation)
+ postload_relation(projects_relation, options)
+
preload_repository_cache(projects_relation)
Preloaders::UserMaxAccessLevelInProjectsPreloader.new(projects_relation, options[:current_user]).execute if options[:current_user]
+
+ options[:current_user].preloaded_member_roles_for_projects(projects_relation) if options[:current_user]
Preloaders::SingleHierarchyProjectGroupPlansPreloader.new(projects_relation).execute if options[:single_hierarchy]
preload_groups(projects_relation) if options[:with] == Entities::Project
diff --git a/lib/api/protected_branches.rb b/lib/api/protected_branches.rb
index 38bafac25b2..786045684b8 100644
--- a/lib/api/protected_branches.rb
+++ b/lib/api/protected_branches.rb
@@ -13,15 +13,23 @@ module API
helpers Helpers::ProtectedBranchesHelpers
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id,
+ types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project',
+ documentation: { example: 'gitlab-org/gitlab' }
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "Get a project's protected branches" do
- success Entities::ProtectedBranch
+ success code: 200, model: Entities::ProtectedBranch
+ is_array true
+ failure [
+ { code: 404, message: '404 Project Not Found' },
+ { code: 401, message: '401 Unauthorized' }
+ ]
end
params do
use :pagination
- optional :search, type: String, desc: 'Search for a protected branch by name'
+ optional :search, type: String, desc: 'Search for a protected branch by name', documentation: { example: 'mai' }
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/protected_branches' do
@@ -36,10 +44,14 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
desc 'Get a single protected branch' do
- success Entities::ProtectedBranch
+ success code: 200, model: Entities::ProtectedBranch
+ failure [
+ { code: 404, message: '404 Project Not Found' },
+ { code: 401, message: '401 Unauthorized' }
+ ]
end
params do
- requires :name, type: String, desc: 'The name of the branch or wildcard'
+ requires :name, type: String, desc: 'The name of the branch or wildcard', documentation: { example: 'main' }
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/protected_branches/:name', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
@@ -50,10 +62,16 @@ module API
# rubocop: enable CodeReuse/ActiveRecord
desc 'Protect a single branch' do
- success Entities::ProtectedBranch
+ success code: 201, model: Entities::ProtectedBranch
+ failure [
+ { code: 422, message: 'name is missing' },
+ { code: 409, message: "Protected branch 'main' already exists" },
+ { code: 404, message: '404 Project Not Found' },
+ { code: 401, message: '401 Unauthorized' }
+ ]
end
params do
- requires :name, type: String, desc: 'The name of the protected branch'
+ requires :name, type: String, desc: 'The name of the protected branch', documentation: { example: 'main' }
optional :push_access_level, type: Integer,
values: ProtectedBranch::PushAccessLevel.allowed_access_levels,
desc: 'Access levels allowed to push (defaults: `40`, maintainer access level)'
@@ -86,9 +104,47 @@ module API
end
# rubocop: enable CodeReuse/ActiveRecord
+ desc 'Update a protected branch' do
+ success code: 200, model: Entities::ProtectedBranch
+ 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' }
+ ]
+ 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.'
+
+ use :optional_params_ee
+ end
+ # rubocop: disable CodeReuse/ActiveRecord
+ patch ':id/protected_branches/:name', requirements: BRANCH_ENDPOINT_REQUIREMENTS do
+ protected_branch = user_project.protected_branches.find_by!(name: params[:name])
+
+ declared_params = declared_params(include_missing: false)
+ api_service = ::ProtectedBranches::ApiService.new(user_project, current_user, declared_params)
+ protected_branch = api_service.update(protected_branch)
+
+ if protected_branch.valid?
+ present protected_branch, with: Entities::ProtectedBranch, project: user_project
+ else
+ render_api_error!(protected_branch.errors.full_messages, 422)
+ end
+ end
+ # rubocop: enable CodeReuse/ActiveRecord
+
desc 'Unprotect a single branch'
params do
- requires :name, type: String, desc: 'The name of the protected branch'
+ requires :name, type: String, desc: 'The name of the protected branch', documentation: { example: 'main' }
+ end
+ desc 'Unprotect a single branch' do
+ success code: 204
+ failure [
+ { code: 404, message: '404 Project Not Found' },
+ { code: 401, message: '401 Unauthorized' }
+ ]
end
# rubocop: disable CodeReuse/ActiveRecord
delete ':id/protected_branches/:name', requirements: BRANCH_ENDPOINT_REQUIREMENTS, urgency: :low do
diff --git a/lib/api/protected_tags.rb b/lib/api/protected_tags.rb
index 4611ee58479..7b55b1fd61d 100644
--- a/lib/api/protected_tags.rb
+++ b/lib/api/protected_tags.rb
@@ -13,12 +13,18 @@ module API
helpers Helpers::ProtectedTagsHelpers
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "Get a project's protected tags" do
detail 'This feature was introduced in GitLab 11.3.'
- success Entities::ProtectedTag
+ is_array true
+ success code: 200, model: Entities::ProtectedTag
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[protected_tags]
end
params do
use :pagination
@@ -33,10 +39,15 @@ module API
desc 'Get a single protected tag' do
detail 'This feature was introduced in GitLab 11.3.'
- success Entities::ProtectedTag
+ success code: 200, model: Entities::ProtectedTag
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[protected_tags]
end
params do
- requires :name, type: String, desc: 'The name of the tag or wildcard'
+ requires :name, type: String, desc: 'The name of the tag or wildcard', documentation: { example: 'release*' }
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/protected_tags/:name', requirements: TAG_ENDPOINT_REQUIREMENTS do
@@ -48,13 +59,21 @@ module API
desc 'Protect a single tag or wildcard' do
detail 'This feature was introduced in GitLab 11.3.'
- success Entities::ProtectedTag
+ success code: 201, model: Entities::ProtectedTag
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[protected_tags]
end
params do
- requires :name, type: String, desc: 'The name of the protected tag'
- optional :create_access_level, type: Integer,
- values: ProtectedTag::CreateAccessLevel.allowed_access_levels,
- desc: 'Access levels allowed to create (defaults: `40`, maintainer access level)'
+ requires :name, type: String, desc: 'The name of the protected tag', documentation: { example: 'release-1-0' }
+ optional :create_access_level,
+ type: Integer,
+ values: ProtectedTag::CreateAccessLevel.allowed_access_levels,
+ desc: 'Access levels allowed to create (defaults: `40`, maintainer access level)',
+ documentation: { example: 30 }
use :optional_params_ee
end
post ':id/protected_tags' do
@@ -76,9 +95,16 @@ module API
desc 'Unprotect a single tag' do
detail 'This feature was introduced in GitLab 11.3.'
+ success code: 204
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' },
+ { code: 412, message: 'Precondition Failed' }
+ ]
+ tags %w[protected_tags]
end
params do
- requires :name, type: String, desc: 'The name of the protected tag'
+ requires :name, type: String, desc: 'The name of the protected tag', documentation: { example: 'release-1-0' }
end
# rubocop: disable CodeReuse/ActiveRecord
delete ':id/protected_tags/:name', requirements: TAG_ENDPOINT_REQUIREMENTS do
diff --git a/lib/api/pypi_packages.rb b/lib/api/pypi_packages.rb
index 1f27fcce879..6c649483da1 100644
--- a/lib/api/pypi_packages.rb
+++ b/lib/api/pypi_packages.rb
@@ -95,9 +95,9 @@ module API
find_authorized_group!
end
- def ensure_project!
+ def project!(action: :read_package)
find_project(params[:id]) || not_found!
- authorized_user_project
+ authorized_user_project(action: action)
end
end
@@ -157,14 +157,10 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- before do
- ensure_project!
- end
-
namespace ':id/packages/pypi' do
desc 'The PyPi package download endpoint' do
detail 'This feature was introduced in GitLab 12.10'
@@ -176,8 +172,7 @@ module API
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
get 'files/:sha256/*file_identifier' do
- project = authorized_user_project
- authorize_read_package!(project)
+ project = project!
filename = "#{params[:file_identifier]}.#{params[:format]}"
package = Packages::Pypi::PackageFinder.new(current_user, project, { filename: filename, sha256: params[:sha256] }).execute
@@ -196,7 +191,7 @@ module API
# PyPi simple API returns a list of packages as a simple HTML file.
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
get 'simple', format: :txt do
- present_simple_index(authorized_user_project)
+ present_simple_index(project!)
end
desc 'The PyPi Simple Project Package Endpoint' do
@@ -211,7 +206,7 @@ module API
# PyPi simple API returns the package descriptor as a simple HTML file.
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
get 'simple/*package_name', format: :txt do
- present_simple_package(authorized_user_project)
+ present_simple_package(project!)
end
desc 'The PyPi Package upload endpoint' do
@@ -219,7 +214,7 @@ module API
end
params do
- requires :content, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :content, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
requires :name, type: String
requires :version, type: String
optional :requires_python, type: String
@@ -229,15 +224,16 @@ module API
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
post do
- authorize_upload!(authorized_user_project)
- bad_request!('File is too large') if authorized_user_project.actual_limits.exceeded?(:pypi_max_file_size, params[:content].size)
+ project = project!(action: :read_project)
+ 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: authorized_user_project, user: current_user, namespace: authorized_user_project.namespace)
+ track_package_event('push_package', :pypi, project: project, user: current_user, namespace: project.namespace)
unprocessable_entity! if Gitlab::FIPS.enabled? && declared_params[:md5_digest].present?
::Packages::Pypi::CreatePackageService
- .new(authorized_user_project, current_user, declared_params.merge(build: current_authenticated_job))
+ .new(project, current_user, declared_params.merge(build: current_authenticated_job))
.execute
created!
@@ -249,10 +245,11 @@ module API
route_setting :authentication, deploy_token_allowed: true, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
post 'authorize' do
+ project = project!(action: :read_project)
authorize_workhorse!(
- subject: authorized_user_project,
+ subject: project,
has_length: false,
- maximum_size: authorized_user_project.actual_limits.pypi_max_file_size
+ maximum_size: project.actual_limits.pypi_max_file_size
)
end
end
diff --git a/lib/api/release/links.rb b/lib/api/release/links.rb
index 8b9380b332e..c72f90dfdf3 100644
--- a/lib/api/release/links.rb
+++ b/lib/api/release/links.rb
@@ -5,6 +5,8 @@ module API
class Links < ::API::Base
include PaginationParams
+ release_links_tags = %w[release_links]
+
RELEASE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
.merge(tag_name: API::NO_SLASH_URL_PART_REGEX)
@@ -14,17 +16,23 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, type: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource 'projects/:id', requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
+ requires :tag_name, type: String, desc: 'The tag associated with the release', as: :tag
end
resource 'releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
resource :assets do
- desc 'Get a list of links of a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'List links of a release' do
+ detail 'Get assets as links from a release. This feature was introduced in GitLab 11.7.'
success Entities::Releases::Link
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags release_links_tags
end
params do
use :pagination
@@ -36,15 +44,24 @@ module API
present paginate(release.links.sorted), with: Entities::Releases::Link
end
- desc 'Create a link of a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Create a release link' do
+ detail 'Create an asset as a link from a release. This feature was introduced in GitLab 11.7.'
success Entities::Releases::Link
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags release_links_tags
end
params do
- requires :name, type: String, desc: 'The name of the link'
- requires :url, type: String, desc: 'The URL of the link'
- optional :filepath, type: String, desc: 'The filepath of the link'
- optional :link_type, type: String, desc: 'The link type, one of: "runbook", "image", "package" or "other"'
+ requires :name, type: String, desc: 'The name of the link. Link names must be unique in the release'
+ requires :url, type: String, desc: 'The URL of the link. Link URLs must be unique in the release.'
+ optional :filepath, type: String, desc: 'Optional path for a direct asset link'
+ optional :link_type,
+ type: String,
+ values: %w[other runbook image package],
+ default: 'other',
+ desc: 'The type of the link: `other`, `runbook`, `image`, or `package`. Defaults to `other`'
end
route_setting :authentication, job_token_allowed: true
post 'links' do
@@ -60,12 +77,17 @@ module API
end
params do
- requires :link_id, type: String, desc: 'The ID of the link'
+ requires :link_id, type: Integer, desc: 'The ID of the link'
end
resource 'links/:link_id' do
- desc 'Get a link detail of a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Get a release link' do
+ detail 'Get an asset as a link from a release. This feature was introduced in GitLab 11.7.'
success Entities::Releases::Link
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags release_links_tags
end
route_setting :authentication, job_token_allowed: true
get do
@@ -74,15 +96,25 @@ module API
present link, with: Entities::Releases::Link
end
- desc 'Update a link of a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Update a release link' do
+ detail 'Update an asset as a link from a release. This feature was introduced in GitLab 11.7.'
success Entities::Releases::Link
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags release_links_tags
end
params do
optional :name, type: String, desc: 'The name of the link'
optional :url, type: String, desc: 'The URL of the link'
- optional :filepath, type: String, desc: 'The filepath of the link'
- optional :link_type, type: String, desc: 'The link type'
+ optional :filepath, type: String, desc: 'Optional path for a direct asset link'
+ optional :link_type,
+ type: String,
+ values: %w[other runbook image package],
+ default: 'other',
+ desc: 'The type of the link: `other`, `runbook`, `image`, or `package`. Defaults to `other`'
+
at_least_one_of :name, :url
end
route_setting :authentication, job_token_allowed: true
@@ -96,9 +128,14 @@ module API
end
end
- desc 'Delete a link of a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Delete a release link' do
+ detail 'Deletes an asset as a link from a release. This feature was introduced in GitLab 11.7.'
success Entities::Releases::Link
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' }
+ ]
+ tags release_links_tags
end
route_setting :authentication, job_token_allowed: true
delete do
diff --git a/lib/api/releases.rb b/lib/api/releases.rb
index cdfcce9dddb..e6884e66200 100644
--- a/lib/api/releases.rb
+++ b/lib/api/releases.rb
@@ -4,6 +4,8 @@ module API
class Releases < ::API::Base
include PaginationParams
+ releases_tags = %w[releases]
+
RELEASE_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS
.merge(tag_name: API::NO_SLASH_URL_PART_REGEX)
RELEASE_CLI_USER_AGENT = 'GitLab-release-cli'
@@ -12,20 +14,37 @@ module API
urgency :low
params do
- requires :id, type: String, desc: 'The ID of a group'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the group'
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authorize_read_group_releases! }
- desc 'Get a list of releases for projects in this group.' do
+ desc 'List group releases' do
+ detail 'Returns a list of group releases.'
success Entities::Release
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ is_array true
+ tags releases_tags
end
params do
- requires :id, type: Integer, desc: 'The ID of the group to get releases for'
- optional :sort, type: String, values: %w[asc desc], default: 'desc',
- desc: 'Return projects sorted in ascending and descending order by released_at'
- optional :simple, type: Boolean, default: false,
- desc: 'Return only the ID, URL, name, and path of each project'
+ requires :id,
+ types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the group owned by the authenticated user'
+
+ optional :sort,
+ type: String,
+ values: %w[asc desc],
+ default: 'desc',
+ desc: 'The direction of the order. Either `desc` (default) for descending order or `asc` for ascending order'
+
+ optional :simple,
+ type: Boolean,
+ default: false,
+ desc: 'Return only limited fields for each release'
use :pagination
end
@@ -42,26 +61,38 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
before { authorize_read_releases! }
after { track_release_event }
- desc 'Get a project releases' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'List Releases' do
+ detail 'Returns a paginated list of releases. This feature was introduced in GitLab 11.7.'
named 'get_releases'
+ is_array true
success Entities::Release
+ tags releases_tags
end
params do
use :pagination
- optional :order_by, type: String, values: %w[released_at created_at], default: 'released_at',
- desc: 'Return releases ordered by `released_at` or `created_at`.'
- optional :sort, type: String, values: %w[asc desc], default: 'desc',
- desc: 'Return releases sorted in `asc` or `desc` order.'
- optional :include_html_description, type: Boolean,
- desc: 'If `true`, a response includes HTML rendered markdown of the release description.'
+
+ optional :order_by,
+ type: String,
+ values: %w[released_at created_at],
+ default: 'released_at',
+ desc: 'The field to use as order. Either `released_at` (default) or `created_at`'
+
+ optional :sort,
+ type: String,
+ values: %w[asc desc],
+ default: 'desc',
+ desc: 'The direction of the order. Either `desc` (default) for descending order or `asc` for ascending order'
+
+ optional :include_html_description,
+ type: Boolean,
+ desc: 'If `true`, a response includes HTML rendered markdown of the release description'
end
route_setting :authentication, job_token_allowed: true
get ':id/releases' do
@@ -81,19 +112,26 @@ module API
include_html_description: params[:include_html_description]
end
- desc 'Get a single project release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Get a release by a tag name' do
+ detail 'Gets a release for the given tag. This feature was introduced in GitLab 11.7.'
named 'get_release'
success Entities::Release
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags releases_tags
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
- optional :include_html_description, type: Boolean,
- desc: 'If `true`, a response includes HTML rendered markdown of the release description.'
+ requires :tag_name, type: String, desc: 'The Git tag the release is associated with', as: :tag
+
+ optional :include_html_description,
+ type: Boolean,
+ desc: 'If `true`, a response includes HTML rendered markdown of the release description'
end
route_setting :authentication, job_token_allowed: true
get ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
- authorize_download_code!
+ authorize_read_code!
not_found! unless release
@@ -103,17 +141,23 @@ module API
desc 'Download a project release asset file' do
detail 'This feature was introduced in GitLab 15.4.'
named 'download_release_asset_file'
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags releases_tags
end
params do
- requires :tag_name, type: String,
- desc: 'The name of the tag.', as: :tag
- requires :file_path, type: String,
- file_path: true,
- desc: 'The path to the file to download, as specified when creating the release asset.'
+ requires :tag_name, type: String, desc: 'The Git tag the release is associated with', as: :tag
+
+ requires :file_path,
+ type: String,
+ file_path: true,
+ desc: 'The path to the file to download, as specified when creating the release asset'
end
route_setting :authentication, job_token_allowed: true
get ':id/releases/:tag_name/downloads/*file_path', format: false, requirements: RELEASE_ENDPOINT_REQUIREMENTS do
- authorize_download_code!
+ authorize_read_code!
not_found! unless release
@@ -127,13 +171,21 @@ module API
desc 'Get the latest project release' do
detail 'This feature was introduced in GitLab 15.4.'
named 'get_latest_release'
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags releases_tags
end
params do
- requires :suffix_path, type: String, file_path: true, desc: 'The path to be suffixed to the latest release'
+ requires :suffix_path,
+ type: String,
+ file_path: true,
+ desc: 'The path to be suffixed to the latest release'
end
route_setting :authentication, job_token_allowed: true
get ':id/releases/permalink/latest(/)(*suffix_path)', format: false, requirements: RELEASE_ENDPOINT_REQUIREMENTS do
- authorize_download_code!
+ authorize_read_code!
# Try to find the latest release
latest_release = find_latest_release
@@ -156,27 +208,50 @@ module API
redirect redirect_url
end
- desc 'Create a new release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ desc 'Create a release' do
+ detail 'Creates a release. Developer level access to the project is required to create a release. This feature was introduced in GitLab 11.7.'
named 'create_release'
success Entities::Release
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Conflict' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags releases_tags
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
+ requires :tag_name, type: String, desc: 'The tag where the release is created from', as: :tag
optional :tag_message, type: String, desc: 'Message to use if creating a new annotated tag'
- optional :name, type: String, desc: 'The name of the release'
- optional :description, type: String, desc: 'The release notes'
- optional :ref, type: String, desc: 'Commit SHA or branch name to use if creating a new tag'
+ optional :name, type: String, desc: 'The release name'
+ optional :description, type: String, desc: 'The description of the release. You can use Markdown'
+
+ optional :ref,
+ type: String,
+ desc: "If a tag specified in `tag_name` doesn't exist, the release is created from `ref` and tagged " \
+ "with `tag_name`. It can be a commit SHA, another tag name, or a branch name."
+
optional :assets, type: Hash do
optional :links, type: Array do
- requires :name, type: String, desc: 'The name of the link'
- requires :url, type: String, desc: 'The URL of the link'
- optional :filepath, type: String, desc: 'The filepath of the link'
- optional :link_type, type: String, desc: 'The link type, one of: "runbook", "image", "package" or "other"'
+ requires :name, type: String, desc: 'The name of the link. Link names must be unique within the release'
+ requires :url, type: String, desc: 'The URL of the link. Link URLs must be unique within the release'
+ optional :filepath, type: String, desc: 'Optional path for a direct asset link'
+ optional :link_type, type: String, desc: 'The type of the link: `other`, `runbook`, `image`, `package`. Defaults to `other`'
end
end
- optional :milestones, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The titles of the related milestones', default: []
- optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready. Defaults to the current time.'
+
+ optional :milestones,
+ type: Array[String],
+ coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ desc: 'The title of each milestone the release is associated with. GitLab Premium customers can specify group milestones',
+ default: []
+
+ optional :released_at,
+ type: DateTime,
+ desc: 'Date and time for the release. Defaults to the current time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`). ' \
+ 'Only provide this field if creating an upcoming or historical release.'
end
route_setting :authentication, job_token_allowed: true
post ':id/releases' do
@@ -196,16 +271,27 @@ module API
end
desc 'Update a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ detail 'Updates a release. Developer level access to the project is required to update a release. This feature was introduced in GitLab 11.7.'
named 'update_release'
success Entities::Release
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags releases_tags
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
- optional :name, type: String, desc: 'The name of the release'
- optional :description, type: String, desc: 'Release notes with markdown support'
- optional :released_at, type: DateTime, desc: 'The date when the release will be/was ready.'
- optional :milestones, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The titles of the related milestones'
+ requires :tag_name, type: String, desc: 'The Git tag the release is associated with', as: :tag
+ optional :name, type: String, desc: 'The release name'
+ optional :description, type: String, desc: 'The description of the release. You can use Markdown'
+ optional :released_at, type: DateTime, desc: 'The date when the release is/was ready. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`)'
+
+ optional :milestones,
+ type: Array[String],
+ coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ desc: 'The title of each milestone to associate with the release. GitLab Premium customers can specify group milestones. To remove all milestones from the release, specify `[]`'
end
route_setting :authentication, job_token_allowed: true
put ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
@@ -226,12 +312,19 @@ module API
end
desc 'Delete a release' do
- detail 'This feature was introduced in GitLab 11.7.'
+ detail "Delete a release. Deleting a release doesn't delete the associated tag. Maintainer level access to the project is required to delete a release. This feature was introduced in GitLab 11.7."
named 'delete_release'
success Entities::Release
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags releases_tags
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag', as: :tag
+ requires :tag_name, type: String, desc: 'The Git tag the release is associated with', as: :tag
end
route_setting :authentication, job_token_allowed: true
delete ':id/releases/:tag_name', requirements: RELEASE_ENDPOINT_REQUIREMENTS do
@@ -280,6 +373,10 @@ module API
authorize! :download_code, user_project
end
+ def authorize_read_code!
+ authorize! :read_code, user_project
+ end
+
def authorize_create_evidence!
# extended in EE
end
diff --git a/lib/api/remote_mirrors.rb b/lib/api/remote_mirrors.rb
index 8de155312fb..f7ea5a6ad2b 100644
--- a/lib/api/remote_mirrors.rb
+++ b/lib/api/remote_mirrors.rb
@@ -11,11 +11,17 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc "List the project's remote mirrors" do
- success Entities::RemoteMirror
+ success code: 200, model: Entities::RemoteMirror
+ is_array true
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[remote_mirrors]
end
params do
use :pagination
@@ -26,7 +32,12 @@ module API
end
desc 'Get a single remote mirror' do
- success Entities::RemoteMirror
+ success code: 200, model: Entities::RemoteMirror
+ failure [
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[remote_mirrors]
end
params do
requires :mirror_id, type: String, desc: 'The ID of a remote mirror'
@@ -38,13 +49,21 @@ module API
end
desc 'Create remote mirror for a project' do
- success Entities::RemoteMirror
+ success code: 201, model: Entities::RemoteMirror
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[remote_mirrors]
end
params do
- requires :url, type: String, desc: 'The URL for a remote mirror'
- optional :enabled, type: Boolean, desc: 'Determines if the mirror is enabled'
- optional :only_protected_branches, type: Boolean, desc: 'Determines if only protected branches are mirrored'
- optional :keep_divergent_refs, type: Boolean, desc: 'Determines if divergent refs are kept on the target'
+ requires :url, type: String, desc: 'The URL for a remote mirror', documentation: { example: 'https://*****:*****@example.com/gitlab/example.git' }
+ optional :enabled, type: Boolean, desc: 'Determines if the mirror is enabled', documentation: { example: false }
+ optional :only_protected_branches, type: Boolean, desc: 'Determines if only protected branches are mirrored',
+ documentation: { example: false }
+ optional :keep_divergent_refs, type: Boolean, desc: 'Determines if divergent refs are kept on the target',
+ documentation: { example: false }
end
post ':id/remote_mirrors' do
create_params = declared_params(include_missing: false)
@@ -59,13 +78,21 @@ module API
end
desc 'Update the attributes of a single remote mirror' do
- success Entities::RemoteMirror
+ success code: 200, model: Entities::RemoteMirror
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[remote_mirrors]
end
params do
requires :mirror_id, type: String, desc: 'The ID of a remote mirror'
- optional :enabled, type: Boolean, desc: 'Determines if the mirror is enabled'
- optional :only_protected_branches, type: Boolean, desc: 'Determines if only protected branches are mirrored'
- optional :keep_divergent_refs, type: Boolean, desc: 'Determines if divergent refs are kept on the target'
+ optional :enabled, type: Boolean, desc: 'Determines if the mirror is enabled', documentation: { example: true }
+ optional :only_protected_branches, type: Boolean, desc: 'Determines if only protected branches are mirrored',
+ documentation: { example: false }
+ optional :keep_divergent_refs, type: Boolean, desc: 'Determines if divergent refs are kept on the target',
+ documentation: { example: false }
end
put ':id/remote_mirrors/:mirror_id' do
mirror = user_project.remote_mirrors.find(params[:mirror_id])
@@ -88,6 +115,13 @@ module API
desc 'Delete a single remote mirror' do
detail 'This feature was introduced in GitLab 14.10'
+ success code: 204
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[remote_mirrors]
end
params do
requires :mirror_id, type: String, desc: 'The ID of a remote mirror'
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index c6a2d582d8a..70535496b12 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -15,33 +15,40 @@ module API
requires :version,
type: String,
regexp: Gitlab::Regex.unbounded_semver_regex,
- desc: 'The version of the release, using the semantic versioning format'
+ desc: 'The version of the release, using the semantic versioning format',
+ documentation: { example: '1.0.0' }
optional :from,
type: String,
- desc: 'The first commit in the range of commits to use for the changelog'
+ desc: 'The first commit in the range of commits to use for the changelog',
+ documentation: { example: 'ed899a2f4b50b4370feeea94676502b42383c746' }
optional :to,
type: String,
- desc: 'The last commit in the range of commits to use for the changelog'
+ desc: 'The last commit in the range of commits to use for the changelog',
+ documentation: { example: '6104942438c14ec7bd21c6cd5bd995272b3faff6' }
optional :date,
type: DateTime,
- desc: 'The date and time of the release'
+ desc: 'The date and time of the release',
+ documentation: { type: 'dateTime', example: '2021-09-20T11:50:22.001+00:00' }
optional :trailer,
type: String,
desc: 'The Git trailer to use for determining if commits are to be included in the changelog',
- default: ::Repositories::ChangelogService::DEFAULT_TRAILER
+ default: ::Repositories::ChangelogService::DEFAULT_TRAILER,
+ documentation: { example: 'Changelog' }
end
end
- before { authorize! :download_code, user_project }
+ before { authorize! :read_code, user_project }
feature_category :source_code_management
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer],
+ desc: 'The ID or URL-encoded path of the project',
+ documentation: { example: 1 }
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
helpers do
@@ -56,7 +63,7 @@ module API
end
def assign_blob_vars!(limit:)
- authorize! :download_code, user_project
+ authorize! :read_code, user_project
@repo = user_project.repository
@@ -94,15 +101,19 @@ module API
success Entities::TreeObject
end
params do
- optional :ref, type: String, desc: 'The name of a repository branch or tag, if not given the default branch is used'
- optional :path, type: String, desc: 'The path of the tree'
+ optional :ref, type: String,
+ desc: 'The name of a repository branch or tag, if not given the default branch is used',
+ documentation: { example: 'main' }
+ optional :path, type: String, desc: 'The path of the tree', documentation: { example: 'files/html' }
optional :recursive, type: Boolean, default: false, desc: 'Used to get a recursive tree'
use :pagination
optional :pagination, type: String, values: %w(legacy keyset none), default: 'legacy', desc: 'Specify the pagination method ("none" is only valid if "recursive" is true)'
given pagination: ->(value) { value == 'keyset' } do
- optional :page_token, type: String, desc: 'Record from which to start the keyset pagination'
+ optional :page_token, type: String,
+ desc: 'Record from which to start the keyset pagination',
+ documentation: { example: 'a1e8f8d745cc87e3a9248358d9352bb7f9a0aeba' }
end
given pagination: ->(value) { value == 'none' } do
@@ -123,7 +134,8 @@ module API
desc 'Get raw blob contents from the repository'
params do
- requires :sha, type: String, desc: 'The commit hash'
+ requires :sha, type: String,
+ desc: 'The commit hash', documentation: { example: '7d70e02340bac451f281cecf0a980907974bd8be' }
end
get ':id/repository/blobs/:sha/raw' do
# Load metadata enough to ask Workhorse to load the whole blob
@@ -136,7 +148,8 @@ module API
desc 'Get a blob from the repository'
params do
- requires :sha, type: String, desc: 'The commit hash'
+ requires :sha, type: String,
+ desc: 'The commit hash', documentation: { example: '7d70e02340bac451f281cecf0a980907974bd8be' }
end
get ':id/repository/blobs/:sha' do
assign_blob_vars!(limit: -1)
@@ -151,9 +164,12 @@ module API
desc 'Get an archive of the repository'
params do
- optional :sha, type: String, desc: 'The commit sha of the archive to be downloaded'
- optional :format, type: String, desc: 'The archive format'
- optional :path, type: String, desc: 'Subfolder of the repository to be downloaded'
+ optional :sha, type: String,
+ desc: 'The commit sha of the archive to be downloaded',
+ documentation: { example: '7d70e02340bac451f281cecf0a980907974bd8be' }
+ optional :format, type: String, desc: 'The archive format', documentation: { example: 'tar.gz' }
+ optional :path, type: String,
+ desc: 'Subfolder of the repository to be downloaded', documentation: { example: 'files/archives' }
end
get ':id/repository/archive', requirements: { format: Gitlab::PathRegex.archive_formats_regex } do
check_archive_rate_limit!(current_user, user_project) do
@@ -171,9 +187,13 @@ module API
success Entities::Compare
end
params do
- requires :from, type: String, desc: 'The commit, branch name, or tag name to start comparison'
- requires :to, type: String, desc: 'The commit, branch name, or tag name to stop comparison'
- optional :from_project_id, type: String, desc: 'The project to compare from'
+ requires :from, type: String,
+ desc: 'The commit, branch name, or tag name to start comparison',
+ documentation: { example: 'main' }
+ requires :to, type: String,
+ desc: 'The commit, branch name, or tag name to stop comparison',
+ documentation: { example: 'feature' }
+ optional :from_project_id, type: Integer, desc: 'The project to compare from', documentation: { example: 1 }
optional :straight, type: Boolean, desc: 'Comparison method, `true` for direct comparison between `from` and `to` (`from`..`to`), `false` to compare using merge base (`from`...`to`)', default: false
end
get ':id/repository/compare', urgency: :low do
@@ -215,7 +235,10 @@ module API
success Entities::Commit
end
params do
- requires :refs, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce
+ requires :refs, type: Array[String],
+ coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce,
+ desc: 'The refs to find the common ancestor of, multiple refs can be passed',
+ documentation: { example: 'main' }
end
get ':id/repository/merge_base' do
refs = params[:refs]
@@ -241,12 +264,14 @@ module API
desc 'Generates a changelog section for a release and returns it' do
detail 'This feature was introduced in GitLab 14.6'
+ success Entities::Changelog
end
params do
use :release_params
optional :config_file,
type: String,
+ documentation: { example: '.gitlab/changelog_config.yml' },
desc: "The file path to the configuration file as stored in the project's Git repository. Defaults to '.gitlab/changelog_config.yml'"
end
get ':id/repository/changelog' do
@@ -264,26 +289,31 @@ module API
desc 'Generates a changelog section for a release and commits it in a changelog file' do
detail 'This feature was introduced in GitLab 13.9'
+ success code: 200
end
params do
use :release_params
optional :branch,
type: String,
- desc: 'The branch to commit the changelog changes to'
+ desc: 'The branch to commit the changelog changes to',
+ documentation: { example: 'main' }
optional :config_file,
type: String,
+ documentation: { example: '.gitlab/changelog_config.yml' },
desc: "The file path to the configuration file as stored in the project's Git repository. Defaults to '.gitlab/changelog_config.yml'"
optional :file,
type: String,
desc: 'The file to commit the changelog changes to',
- default: ::Repositories::ChangelogService::DEFAULT_FILE
+ default: ::Repositories::ChangelogService::DEFAULT_FILE,
+ documentation: { example: 'CHANGELOG.md' }
optional :message,
type: String,
- desc: 'The commit message to use when committing the changelog'
+ desc: 'The commit message to use when committing the changelog',
+ documentation: { example: 'Initial commit' }
end
post ':id/repository/changelog' do
branch = params[:branch] || user_project.default_branch_or_main
diff --git a/lib/api/resource_access_tokens.rb b/lib/api/resource_access_tokens.rb
index 2ba109b7092..754dfadb5fc 100644
--- a/lib/api/resource_access_tokens.rb
+++ b/lib/api/resource_access_tokens.rb
@@ -4,6 +4,8 @@ module API
class ResourceAccessTokens < ::API::Base
include PaginationParams
+ ALLOWED_RESOURCE_ACCESS_LEVELS = Gitlab::Access.options_with_owner.freeze
+
before { authenticate! }
feature_category :authentication_and_authorization
@@ -12,9 +14,12 @@ module API
resource source_type.pluralize, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get list of all access tokens for the specified resource' do
detail 'This feature was introduced in GitLab 13.9.'
+ is_array true
+ tags ["#{source_type}_access_tokens"]
+ success Entities::ResourceAccessToken
end
params do
- requires :id, type: String, desc: "The #{source_type} ID"
+ requires :id, types: [String, Integer], desc: "ID or URL-encoded path of the #{source_type}"
end
get ":id/access_tokens" do
resource = find_source(source_type, params[:id])
@@ -29,9 +34,11 @@ module API
desc 'Get an access token for the specified resource by ID' do
detail 'This feature was introduced in GitLab 14.10.'
+ tags ["#{source_type}_access_tokens"]
+ success Entities::ResourceAccessToken
end
params do
- requires :id, type: String, desc: "The #{source_type} ID"
+ requires :id, types: [String, Integer], desc: "ID or URL-encoded path of the #{source_type}"
requires :token_id, type: String, desc: "The ID of the token"
end
get ":id/access_tokens/:token_id" do
@@ -51,6 +58,12 @@ module API
desc 'Revoke a resource access token' do
detail 'This feature was introduced in GitLab 13.9.'
+ tags ["#{source_type}_access_tokens"]
+ success code: 204
+ failure [
+ { code: 400, message: 'Bad Request' },
+ { code: 404, message: 'Not found' }
+ ]
end
params do
requires :id, type: String, desc: "The #{source_type} ID"
@@ -75,13 +88,21 @@ module API
desc 'Create a resource access token' do
detail 'This feature was introduced in GitLab 13.9.'
+ tags ["#{source_type}_access_tokens"]
+ success Entities::ResourceAccessTokenWithToken
end
params do
- requires :id, type: String, desc: "The #{source_type} ID"
- requires :name, type: String, desc: "Resource access token name"
- requires :scopes, type: Array[String], desc: "The permissions of the token"
- optional :access_level, type: Integer, desc: "The access level of the token in the #{source_type}"
- optional :expires_at, type: Date, desc: "The expiration date of the token"
+ requires :id, type: String, desc: "The #{source_type} ID", documentation: { example: 2 }
+ requires :name, type: String, desc: "Resource access token name", documentation: { example: 'test' }
+ requires :scopes, type: Array[String], values: ::Gitlab::Auth.resource_bot_scopes.map(&:to_s),
+ desc: "The permissions of the token",
+ documentation: { example: %w[api read_repository] }
+ optional :access_level, type: Integer,
+ values: ALLOWED_RESOURCE_ACCESS_LEVELS.values,
+ default: Gitlab::Access::MAINTAINER,
+ desc: "The access level of the token in the #{source_type}",
+ documentation: { example: 40 }
+ optional :expires_at, type: Date, desc: "The expiration date of the token", documentation: { example: '"2021-01-31' }
end
post ':id/access_tokens' do
resource = find_source(source_type, params[:id])
diff --git a/lib/api/resource_milestone_events.rb b/lib/api/resource_milestone_events.rb
index 04d71faa56a..5640e88ae6e 100644
--- a/lib/api/resource_milestone_events.rb
+++ b/lib/api/resource_milestone_events.rb
@@ -5,6 +5,8 @@ module API
include PaginationParams
helpers ::API::Helpers::NotesHelpers
+ resource_milestone_events_tags = %w[resource_milestone_events]
+
before { authenticate! }
{
@@ -15,17 +17,19 @@ module API
eventables_str = eventable_type.to_s.underscore.pluralize
params do
- requires :id, type: String, desc: "The ID of a #{parent_type}"
+ requires :id, types: [String, Integer], desc: "The ID or URL-encoded path of the #{parent_type}"
end
resource parent_type.pluralize.to_sym, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
- desc "Get a list of #{eventable_type.to_s.downcase} resource milestone events" do
+ desc "List project #{eventable_type.underscore.humanize} milestone events" do
+ detail "Gets a list of all milestone events for a single #{eventable_type.underscore.humanize}"
success Entities::ResourceMilestoneEvent
+ is_array true
+ tags resource_milestone_events_tags
end
params do
requires :eventable_id, types: [Integer, String], desc: 'The ID of the eventable'
use :pagination
end
-
get ":id/#{eventables_str}/:eventable_id/resource_milestone_events", feature_category: feature_category, urgency: :low do
eventable = find_noteable(eventable_type, params[:eventable_id])
@@ -34,8 +38,13 @@ module API
present paginate(events), with: Entities::ResourceMilestoneEvent
end
- desc "Get a single #{eventable_type.to_s.downcase} resource milestone event" do
+ desc "Get single #{eventable_type.underscore.humanize} milestone event" do
+ detail "Returns a single milestone event for a specific project #{eventable_type.underscore.humanize}"
success Entities::ResourceMilestoneEvent
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags resource_milestone_events_tags
end
params do
requires :event_id, type: String, desc: 'The ID of a resource milestone event'
diff --git a/lib/api/rpm_project_packages.rb b/lib/api/rpm_project_packages.rb
index d17470ae92d..40b8d022c6c 100644
--- a/lib/api/rpm_project_packages.rb
+++ b/lib/api/rpm_project_packages.rb
@@ -21,7 +21,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
namespace ':id/packages/rpm' do
@@ -30,7 +30,14 @@ module API
requires :file_name, type: String, desc: 'Repository metadata file name'
end
get 'repodata/*file_name', requirements: { file_name: API::NO_SLASH_URL_PART_REGEX } do
- not_found!
+ authorize_read_package!(authorized_user_project)
+
+ repository_file = Packages::Rpm::RepositoryFile.find_by_project_id_and_file_name!(
+ authorized_user_project.id,
+ "#{params['file_name']}.#{params['format']}"
+ )
+
+ present_carrierwave_file!(repository_file.file)
end
desc 'Download RPM package files'
@@ -39,6 +46,13 @@ module API
requires :file_name, type: String, desc: 'RPM package file name'
end
get '*package_file_id/*file_name', requirements: { file_name: API::NO_SLASH_URL_PART_REGEX } do
+ track_package_event(
+ 'pull_package',
+ :rpm,
+ category: self.class.name,
+ project: authorized_user_project,
+ namespace: authorized_user_project.namespace
+ )
not_found!
end
@@ -50,6 +64,15 @@ module API
bad_request!('File is too large')
end
+ track_package_event(
+ 'push_package',
+ :rpm,
+ user: current_user,
+ category: self.class.name,
+ project: authorized_user_project,
+ namespace: authorized_user_project.namespace
+ )
+
not_found!
end
diff --git a/lib/api/rubygem_packages.rb b/lib/api/rubygem_packages.rb
index b4d02613e4c..87cf1f66223 100644
--- a/lib/api/rubygem_packages.rb
+++ b/lib/api/rubygem_packages.rb
@@ -93,7 +93,7 @@ module API
detail 'This feature was introduced in GitLab 13.9'
end
params do
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
end
post 'gems' do
authorize_upload!(user_project)
diff --git a/lib/api/search.rb b/lib/api/search.rb
index ff17696ed3e..cf6a1385783 100644
--- a/lib/api/search.rb
+++ b/lib/api/search.rb
@@ -67,8 +67,8 @@ module API
Gitlab::Metrics::GlobalSearchSlis.record_apdex(
elapsed: @search_duration_s,
- search_type: search_type,
- search_level: search_service.level,
+ search_type: search_type(additional_params),
+ search_level: search_service(additional_params).level,
search_scope: search_scope
)
@@ -81,7 +81,7 @@ module API
# with a 200 status code, but an empty @search_duration_s.
Gitlab::Metrics::GlobalSearchSlis.record_error_rate(
error: @search_duration_s.nil? || (status < 200 || status >= 400),
- search_type: search_type,
+ search_type: search_type(additional_params),
search_level: search_service(additional_params).level,
search_scope: search_scope
)
@@ -171,7 +171,7 @@ module API
detail 'This feature was introduced in GitLab 10.5.'
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
requires :search, type: String, desc: 'The expression it should be searched for'
requires :scope,
type: String,
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index 8c8b6c0a1ba..26b7e58bc7a 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -53,6 +53,7 @@ module API
optional :default_project_visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The default project visibility'
optional :default_projects_limit, type: Integer, desc: 'The maximum number of personal projects'
optional :default_snippet_visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The default snippet visibility'
+ optional :disable_admin_oauth_scopes, type: Boolean, desc: 'Stop administrators from connecting to non-trusted OAuth applications.'
optional :disable_feed_token, type: Boolean, desc: 'Disable display of RSS/Atom and Calendar `feed_tokens`'
optional :disabled_oauth_sign_in_sources, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Disable certain OAuth sign-in sources'
optional :domain_denylist_enabled, type: Boolean, desc: 'Enable domain denylist for sign ups'
diff --git a/lib/api/snippet_repository_storage_moves.rb b/lib/api/snippet_repository_storage_moves.rb
index e3034191641..92eb10b3bb8 100644
--- a/lib/api/snippet_repository_storage_moves.rb
+++ b/lib/api/snippet_repository_storage_moves.rb
@@ -11,7 +11,8 @@ module API
resource :snippet_repository_storage_moves do
desc 'Get a list of all snippet repository storage moves' do
detail 'This feature was introduced in GitLab 13.8.'
- success Entities::Snippets::RepositoryStorageMove
+ is_array true
+ success code: 200, model: Entities::Snippets::RepositoryStorageMove
end
params do
use :pagination
@@ -24,7 +25,7 @@ module API
desc 'Get a snippet repository storage move' do
detail 'This feature was introduced in GitLab 13.8.'
- success Entities::Snippets::RepositoryStorageMove
+ success code: 200, model: Entities::Snippets::RepositoryStorageMove
end
params do
requires :repository_storage_move_id, type: Integer, desc: 'The ID of a snippet repository storage move'
@@ -37,6 +38,7 @@ module API
desc 'Schedule bulk snippet repository storage moves' do
detail 'This feature was introduced in GitLab 13.8.'
+ success code: 202
end
params do
requires :source_storage_name, type: String, desc: 'The source storage shard', values: -> { Gitlab.config.repositories.storages.keys }
@@ -68,7 +70,8 @@ module API
desc 'Get a list of all snippets repository storage moves' do
detail 'This feature was introduced in GitLab 13.8.'
- success Entities::Snippets::RepositoryStorageMove
+ is_array true
+ success code: 200, model: Entities::Snippets::RepositoryStorageMove
end
params do
use :pagination
@@ -81,7 +84,7 @@ module API
desc 'Get a snippet repository storage move' do
detail 'This feature was introduced in GitLab 13.8.'
- success Entities::Snippets::RepositoryStorageMove
+ success code: 200, model: Entities::Snippets::RepositoryStorageMove
end
params do
requires :repository_storage_move_id, type: Integer, desc: 'The ID of a snippet repository storage move'
@@ -94,14 +97,14 @@ module API
desc 'Schedule a snippet repository storage move' do
detail 'This feature was introduced in GitLab 13.8.'
- success Entities::Snippets::RepositoryStorageMove
+ success code: 201, model: Entities::Snippets::RepositoryStorageMove
end
params do
optional :destination_storage_name, type: String, desc: 'The destination storage shard'
end
post ':id/repository_storage_moves' do
storage_move = user_snippet.repository_storage_moves.build(
- declared_params.merge(source_storage_name: user_snippet.repository_storage)
+ declared_params.compact.merge(source_storage_name: user_snippet.repository_storage)
)
if storage_move.schedule
diff --git a/lib/api/snippets.rb b/lib/api/snippets.rb
index 5f8e6c806cb..36698a220bd 100644
--- a/lib/api/snippets.rb
+++ b/lib/api/snippets.rb
@@ -28,6 +28,11 @@ module API
desc 'Get a snippets list for an authenticated user' do
detail 'This feature was introduced in GitLab 8.15.'
success Entities::Snippet
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[snippets]
+ is_array true
end
params do
optional :created_after, type: DateTime, desc: 'Return snippets created after the specified time'
@@ -45,6 +50,11 @@ module API
desc 'List all public personal snippets current_user has access to' do
detail 'This feature was introduced in GitLab 8.15.'
success Entities::PersonalSnippet
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[snippets]
+ is_array true
end
params do
optional :created_after, type: DateTime, desc: 'Return snippets created after the specified time'
@@ -62,6 +72,10 @@ module API
desc 'Get a single snippet' do
detail 'This feature was introduced in GitLab 8.15.'
success Entities::PersonalSnippet
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[snippets]
end
params do
requires :id, type: Integer, desc: 'The ID of a snippet'
@@ -77,6 +91,12 @@ module API
desc 'Create new snippet' do
detail 'This feature was introduced in GitLab 8.15.'
success Entities::PersonalSnippet
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[snippets]
end
params do
requires :title, type: String, allow_blank: false, desc: 'The title of a snippet'
@@ -110,6 +130,12 @@ module API
desc 'Update an existing snippet' do
detail 'This feature was introduced in GitLab 8.15.'
success Entities::PersonalSnippet
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[snippets]
end
params do
@@ -154,6 +180,11 @@ module API
desc 'Remove snippet' do
detail 'This feature was introduced in GitLab 8.15.'
success Entities::PersonalSnippet
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[snippets]
end
params do
requires :id, type: Integer, desc: 'The ID of a snippet'
@@ -178,6 +209,10 @@ module API
desc 'Get a raw snippet' do
detail 'This feature was introduced in GitLab 8.15.'
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[snippets]
end
params do
requires :id, type: Integer, desc: 'The ID of a snippet'
@@ -189,7 +224,12 @@ module API
present content_for(snippet)
end
- desc 'Get raw snippet file contents from the repository'
+ desc 'Get raw snippet file contents from the repository' do
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[snippets]
+ end
params do
use :raw_file_params
end
@@ -202,6 +242,10 @@ module API
desc 'Get the user agent details for a snippet' do
success Entities::UserAgentDetail
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[snippets]
end
params do
requires :id, type: Integer, desc: 'The ID of a snippet'
diff --git a/lib/api/statistics.rb b/lib/api/statistics.rb
index a12a2ed08d7..1af83c0737a 100644
--- a/lib/api/statistics.rb
+++ b/lib/api/statistics.rb
@@ -10,7 +10,7 @@ module API
MergeRequest, Note, Snippet, Key, Milestone].freeze
desc 'Get the current application statistics' do
- success Entities::ApplicationStatistics
+ success code: 200, model: Entities::ApplicationStatistics
end
get "application/statistics", urgency: :low do
counts = Gitlab::Database::Count.approximate_counts(COUNTED_ITEMS)
diff --git a/lib/api/submodules.rb b/lib/api/submodules.rb
index 2b51ab91c40..6638ac57f69 100644
--- a/lib/api/submodules.rb
+++ b/lib/api/submodules.rb
@@ -18,17 +18,34 @@ module API
end
params do
- requires :id, type: String, desc: 'The project ID'
+ requires :id,
+ type: String,
+ desc: 'The ID or URL-encoded path of a project',
+ documentation: { example: 'gitlab-org/gitlab' }
end
- resource :projects, requirements: Files::FILE_ENDPOINT_REQUIREMENTS do
+ resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Update existing submodule reference in repository' do
- success Entities::Commit
+ success code: 200, model: Entities::CommitDetail
+ failure [
+ { code: 404, message: '404 Project Not Found' },
+ { code: 401, message: '401 Unauthorized' },
+ { code: 400, message: 'The repository is empty' }
+ ]
end
params do
- requires :submodule, type: String, desc: 'Url encoded full path to submodule.'
- requires :commit_sha, type: String, desc: 'Commit sha to update the submodule to.'
- requires :branch, type: String, desc: 'Name of the branch to commit into.'
- optional :commit_message, type: String, desc: 'Commit message. If no message is provided a default one will be set.'
+ requires :submodule,
+ type: String,
+ desc: 'Url encoded full path to submodule.',
+ documentation: { example: 'gitlab-org/gitlab-shell' }
+ requires :commit_sha,
+ type: String,
+ desc: 'Commit sha to update the submodule to.',
+ documentation: { example: 'ed899a2f4b50b4370feeea94676502b42383c746' }
+ requires :branch, type: String, desc: 'Name of the branch to commit into.', documentation: { example: 'main' }
+ optional :commit_message,
+ type: String,
+ desc: 'Commit message. If no message is provided a default one will be set.',
+ documentation: { example: 'Commit message' }
end
put ":id/repository/submodules/:submodule", requirements: Files::FILE_ENDPOINT_REQUIREMENTS do
authorize! :push_code, user_project
diff --git a/lib/api/suggestions.rb b/lib/api/suggestions.rb
index 0697169b49a..6260983087f 100644
--- a/lib/api/suggestions.rb
+++ b/lib/api/suggestions.rb
@@ -9,9 +9,10 @@ module API
resource :suggestions do
desc 'Apply suggestion patch in the Merge Request it was created' do
success Entities::Suggestion
+ tags %w[suggestions]
end
params do
- requires :id, type: String, desc: 'The suggestion ID'
+ requires :id, type: Integer, desc: 'The ID of the suggestion'
optional :commit_message, type: String, desc: "A custom commit message to use instead of the default generated message or the project's default message"
end
put ':id/apply', urgency: :low do
@@ -26,9 +27,10 @@ module API
desc 'Apply multiple suggestion patches in the Merge Request where they were created' do
success Entities::Suggestion
+ tags %w[suggestions]
end
params do
- requires :ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: "An array of suggestion ID's"
+ requires :ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: "An array of the suggestion IDs"
optional :commit_message, type: String, desc: "A custom commit message to use instead of the default generated message or the project's default message"
end
put 'batch_apply', urgency: :low do
diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb
index 804cedfefe9..f2019d785a0 100644
--- a/lib/api/system_hooks.rb
+++ b/lib/api/system_hooks.rb
@@ -4,6 +4,8 @@ module API
class SystemHooks < ::API::Base
include PaginationParams
+ system_hooks_tags = %w[system_hooks]
+
feature_category :integrations
before do
@@ -19,12 +21,13 @@ module API
end
params :hook_parameters do
- optional :token, type: String, desc: 'The token used to validate payloads'
- optional :push_events, type: Boolean, desc: "Trigger hook on push events"
- optional :tag_push_events, type: Boolean, desc: "Trigger hook on tag push events"
- optional :merge_requests_events, type: Boolean, desc: "Trigger hook on tag push events"
- optional :repository_update_events, type: Boolean, desc: "Trigger hook on repository update events"
- optional :enable_ssl_verification, type: Boolean, desc: "Do SSL verification when triggering the hook"
+ optional :token, type: String,
+ desc: "Secret token to validate received payloads; this isn't returned in the response"
+ optional :push_events, type: Boolean, desc: 'When true, the hook fires on push events'
+ optional :tag_push_events, type: Boolean, desc: 'When true, the hook fires on new tags being pushed'
+ optional :merge_requests_events, type: Boolean, desc: 'Trigger hook on merge requests events'
+ optional :repository_update_events, type: Boolean, desc: 'Trigger hook on repository update events'
+ optional :enable_ssl_verification, type: Boolean, desc: 'Do SSL verification when triggering the hook'
use :url_variables
end
end
@@ -32,8 +35,11 @@ module API
resource :hooks do
mount ::API::Hooks::UrlVariables
- desc 'Get the list of system hooks' do
+ desc 'List system hooks' do
+ detail 'Get a list of all system hooks'
success Entities::Hook
+ is_array true
+ tags system_hooks_tags
end
params do
use :pagination
@@ -42,8 +48,13 @@ module API
present paginate(SystemHook.all), with: Entities::Hook
end
- desc 'Get a hook' do
+ desc 'Get system hook' do
+ detail 'Get a system hook by its ID. Introduced in GitLab 14.9.'
success Entities::Hook
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags system_hooks_tags
end
params do
requires :hook_id, type: Integer, desc: 'The ID of the system hook'
@@ -52,8 +63,15 @@ module API
present find_hook, with: Entities::Hook
end
- desc 'Create a new system hook' do
+ desc 'Add new system hook' do
+ detail 'Add a new system hook'
success Entities::Hook
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags system_hooks_tags
end
params do
use :requires_url
@@ -66,11 +84,18 @@ module API
save_hook(hook, Entities::Hook)
end
- desc 'Update an existing system hook' do
+ desc 'Edit system hook' do
+ detail 'Edits a system hook'
success Entities::Hook
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags system_hooks_tags
end
params do
- requires :hook_id, type: Integer, desc: "The ID of the hook to update"
+ requires :hook_id, type: Integer, desc: 'The ID of the system hook'
use :optional_url
use :hook_parameters
end
@@ -90,8 +115,13 @@ module API
kind: 'system_hooks'
}
- desc 'Delete a hook' do
+ desc 'Delete system hook' do
+ detail 'Deletes a system hook'
success Entities::Hook
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags system_hooks_tags
end
params do
requires :hook_id, type: Integer, desc: 'The ID of the system hook'
diff --git a/lib/api/tags.rb b/lib/api/tags.rb
index c8ac68189f5..b412a17bc6f 100644
--- a/lib/api/tags.rb
+++ b/lib/api/tags.rb
@@ -7,17 +7,25 @@ module API
TAG_ENDPOINT_REQUIREMENTS = API::NAMESPACE_OR_PROJECT_REQUIREMENTS.merge(tag_name: API::NO_SLASH_URL_PART_REGEX)
before do
- authorize! :download_code, user_project
+ authorize! :read_code, user_project
not_found! unless user_project.repo_exists?
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
desc 'Get a project repository tags' do
- success Entities::Tag
+ is_array true
+ success code: 200, model: Entities::Tag
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' },
+ { code: 503, message: 'Service unavailable' }
+ ]
+ tags %w[tags]
end
params do
optional :sort, type: String, values: %w[asc desc], default: 'desc',
@@ -46,7 +54,12 @@ module API
end
desc 'Get a single repository tag' do
- success Entities::Tag
+ success code: 200, model: Entities::Tag
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[tags]
end
params do
requires :tag_name, type: String, desc: 'The name of the tag'
@@ -59,12 +72,18 @@ module API
end
desc 'Create a new repository tag' do
- success Entities::Tag
+ success code: 201, model: Entities::Tag
+ failure [
+ { code: 400, message: 'Bad request' },
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[tags]
end
params do
- requires :tag_name, type: String, desc: 'The name of the tag'
- requires :ref, type: String, desc: 'The commit sha or branch name'
- optional :message, type: String, desc: 'Specifying a message creates an annotated tag'
+ requires :tag_name, type: String, desc: 'The name of the tag', documentation: { example: 'v.1.0.0' }
+ requires :ref, type: String, desc: 'The commit sha or branch name', documentation: { example: '2695effb5807a22ff3d138d593fd856244e155e7' }
+ optional :message, type: String, desc: 'Specifying a message creates an annotated tag', documentation: { example: 'Release 1.0.0' }
end
post ':id/repository/tags', :release_orchestration do
authorize_admin_tag
@@ -81,7 +100,15 @@ module API
end
end
- desc 'Delete a repository tag'
+ desc 'Delete a repository tag' do
+ success code: 204
+ failure [
+ { code: 403, message: 'Unauthenticated' },
+ { code: 404, message: 'Not found' },
+ { code: 412, message: 'Precondition failed' }
+ ]
+ tags %w[tags]
+ end
params do
requires :tag_name, type: String, desc: 'The name of the tag'
end
diff --git a/lib/api/terraform/modules/v1/packages.rb b/lib/api/terraform/modules/v1/packages.rb
index 267d41e5fb9..5624784228e 100644
--- a/lib/api/terraform/modules/v1/packages.rb
+++ b/lib/api/terraform/modules/v1/packages.rb
@@ -21,7 +21,7 @@ module API
module_version: SEMVER_REGEX
}.freeze
- feature_category :infrastructure_as_code
+ feature_category :package_registry
urgency :low
after_validation do
@@ -92,11 +92,29 @@ module API
authorize_read_package!(package || module_namespace)
end
+ desc 'List versions for a module' do
+ detail 'List versions for a module'
+ success code: 200, model: Entities::Terraform::ModuleVersions
+ failure [
+ { code: 403, message: 'Forbidden' }
+ ]
+ is_array true
+ tags %w[terraform_registry]
+ end
get 'versions' do
presenter = ::Terraform::ModulesPresenter.new(packages, params[:module_system])
present presenter, with: ::API::Entities::Terraform::ModuleVersions
end
+ desc 'Get download location for the latest version of a module' do
+ detail 'Download the latest version of a module'
+ success code: 302
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[terraform_registry]
+ end
get 'download' do
latest_version = packages.order_version.last&.version
@@ -115,6 +133,15 @@ module API
redirect(download_path)
end
+ desc 'Get details about the latest version of a module' do
+ detail 'Get details about the latest version of a module'
+ success code: 200, model: Entities::Terraform::ModuleVersion
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[terraform_registry]
+ end
get do
latest_package = packages.order_version.last
@@ -133,6 +160,15 @@ module API
not_found! unless package && package_file
end
+ desc 'Get download location for specific version of a module' do
+ detail 'Download specific version of a module'
+ success code: 204
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[terraform_registry]
+ end
get 'download' do
module_file_path = api_v4_packages_terraform_modules_v1_module_version_file_path(
module_namespace: params[:module_namespace],
@@ -154,6 +190,15 @@ module API
accept.token_types(:deploy_token_from_jwt, :job_token_from_jwt, :personal_access_token_from_jwt).sent_through(:token_param)
end
+ desc 'Download specific version of a module' do
+ detail 'Download specific version of a module'
+ success File
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[terraform_registry]
+ end
get do
track_package_event('pull_package', :terraform_module, project: package.project, namespace: module_namespace, user: current_user)
@@ -166,6 +211,15 @@ module API
# format: false is required, otherwise grape splits the semver version into 2 params:
# params[:module_version] and params[:format],
# thus leading to an invalid/not found module version
+ desc 'Get details about specific version of a module' do
+ detail 'Get details about specific version of a module'
+ success code: 200, model: Entities::Terraform::ModuleVersion
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[terraform_registry]
+ end
get format: false do
presenter = ::Terraform::ModuleVersionPresenter.new(package, params[:module_system])
present presenter, with: ::API::Entities::Terraform::ModuleVersion
@@ -189,6 +243,11 @@ module API
desc 'Workhorse authorize Terraform Module package file' do
detail 'This feature was introduced in GitLab 13.11'
+ success code: 200
+ failure [
+ { code: 403, message: 'Forbidden' }
+ ]
+ tags %w[terraform_registry]
end
put 'authorize' do
@@ -200,10 +259,19 @@ module API
desc 'Upload Terraform Module package file' do
detail 'This feature was introduced in GitLab 13.11'
+ success code: 201
+ failure [
+ { code: 400, message: 'Invalid file' },
+ { code: 401, message: 'Unauthorized' },
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ consumes %w[multipart/form-data]
+ tags %w[terraform_registry]
end
params do
- requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)'
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The package file to be published (generated by Multipart middleware)', documentation: { type: 'file' }
end
put do
diff --git a/lib/api/terraform/state.rb b/lib/api/terraform/state.rb
index a19919b5e76..577d011ebad 100644
--- a/lib/api/terraform/state.rb
+++ b/lib/api/terraform/state.rb
@@ -27,13 +27,21 @@ 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', 'p_terraform_state_api_unique_users',
- namespace: user_project&.namespace, user: current_user)
+ 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
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -49,7 +57,19 @@ module API
end
end
- desc 'Get a terraform state by its name'
+ desc 'Get a Terraform state by its name' do
+ detail 'Get a Terraform state by its name'
+ success [
+ { code: 200 },
+ { code: 204, message: 'Empty state' }
+ ]
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Validation failure' }
+ ]
+ tags %w[terraform_state]
+ end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
get do
remote_state_handler.find_with_lock do |state|
@@ -60,7 +80,18 @@ module API
end
end
- desc 'Add a new terraform state or update an existing one'
+ desc 'Add a new Terraform state or update an existing one' do
+ detail 'Add a new Terraform state or update an existing one'
+ success [
+ { code: 200 },
+ { code: 204, message: 'No data provided' }
+ ]
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 422, message: 'Validation failure' }
+ ]
+ tags %w[terraform_state]
+ end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
post do
authorize! :admin_terraform_state, user_project
@@ -76,7 +107,16 @@ module API
status :ok
end
- desc 'Delete a terraform state of a certain name'
+ desc 'Delete a Terraform state of a certain name' do
+ detail 'Delete a Terraform state of a certain name'
+ success code: 200
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Validation failure' }
+ ]
+ tags %w[terraform_state]
+ end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
delete do
authorize! :admin_terraform_state, user_project
@@ -89,7 +129,17 @@ module API
status :ok
end
- desc 'Lock a terraform state of a certain name'
+ desc 'Lock a Terraform state of a certain name' do
+ detail 'Lock a Terraform state of a certain name'
+ success code: 200
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Conflict' },
+ { code: 422, message: 'Validation failure' }
+ ]
+ tags %w[terraform_state]
+ end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
params do
requires :ID, type: String, limit: 255, desc: 'Terraform state lock ID'
@@ -128,7 +178,17 @@ module API
end
end
- desc 'Unlock a terraform state of a certain name'
+ desc 'Unlock a Terraform state of a certain name' do
+ detail 'Unlock a Terraform state of a certain name'
+ success code: 200
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' },
+ { code: 409, message: 'Conflict' },
+ { code: 422, message: 'Validation failure' }
+ ]
+ tags %w[terraform_state]
+ end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
params do
optional :ID, type: String, limit: 255, desc: 'Terraform state lock ID'
diff --git a/lib/api/terraform/state_version.rb b/lib/api/terraform/state_version.rb
index ca37c786666..f98aeb5860e 100644
--- a/lib/api/terraform/state_version.rb
+++ b/lib/api/terraform/state_version.rb
@@ -14,7 +14,7 @@ module API
end
params do
- requires :id, type: String, desc: 'The ID of a project'
+ requires :id, types: [String, Integer], desc: 'The ID or URL-encoded path of the project'
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
@@ -42,7 +42,15 @@ module API
end
end
- desc 'Get a terraform state version'
+ desc 'Get a Terraform state version' do
+ detail 'Get a Terraform state version'
+ success File
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[terraform_state]
+ end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
get do
find_version(params[:serial]) do |version|
@@ -52,7 +60,15 @@ module API
end
end
- desc 'Delete a terraform state version'
+ desc 'Delete a Terraform state version' do
+ detail 'Delete a Terraform state version'
+ success code: 204
+ failure [
+ { code: 403, message: 'Forbidden' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[terraform_state]
+ end
route_setting :authentication, basic_auth_personal_access_token: true, job_token_allowed: :basic_auth
delete do
authorize! :admin_terraform_state, user_project
diff --git a/lib/api/topics.rb b/lib/api/topics.rb
index 38cfdc44021..b16b40244d4 100644
--- a/lib/api/topics.rb
+++ b/lib/api/topics.rb
@@ -11,7 +11,9 @@ module API
success Entities::Projects::Topic
end
params do
- optional :search, type: String, desc: 'Return list of topics matching the search criteria'
+ optional :search, type: String,
+ desc: 'Return list of topics matching the search criteria',
+ documentation: { example: 'search' }
optional :without_projects, type: Boolean, desc: 'Return list of topics without assigned projects'
use :pagination
end
@@ -42,7 +44,8 @@ module API
requires :name, type: String, desc: 'Slug (name)'
requires :title, type: String, desc: 'Title'
optional :description, type: String, desc: 'Description'
- optional :avatar, type: ::API::Validations::Types::WorkhorseFile, desc: 'Avatar image for topic'
+ optional :avatar, type: ::API::Validations::Types::WorkhorseFile, desc: 'Avatar image for topic',
+ documentation: { type: 'file' }
end
post 'topics' do
authenticated_as_admin!
@@ -65,7 +68,8 @@ module API
optional :name, type: String, desc: 'Slug (name)'
optional :title, type: String, desc: 'Title'
optional :description, type: String, desc: 'Description'
- optional :avatar, type: ::API::Validations::Types::WorkhorseFile, desc: 'Avatar image for topic'
+ optional :avatar, type: ::API::Validations::Types::WorkhorseFile, desc: 'Avatar image for topic',
+ documentation: { type: 'file' }
end
put 'topics/:id' do
authenticated_as_admin!
diff --git a/lib/api/unleash.rb b/lib/api/unleash.rb
index 1fbd7cf5afc..38ce4bd7f32 100644
--- a/lib/api/unleash.rb
+++ b/lib/api/unleash.rb
@@ -4,14 +4,16 @@ module API
class Unleash < ::API::Base
include PaginationParams
+ unleash_tags = %w[unleash_api]
+
feature_category :feature_flags
namespace :feature_flags do
resource :unleash, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
params do
requires :project_id, type: String, desc: 'The ID of a project'
- optional :instance_id, type: String, desc: 'The Instance ID of Unleash Client'
- optional :app_name, type: String, desc: 'The Application Name of Unleash Client'
+ optional :instance_id, type: String, desc: 'The instance ID of Unleash Client'
+ optional :app_name, type: String, desc: 'The application name of Unleash Client'
end
route_param :project_id do
before do
@@ -23,26 +25,22 @@ module API
status :ok
end
- desc 'Get a list of features (deprecated, v2 client support)'
- get 'features' do
- if ::Feature.enabled?(:cache_unleash_client_api, project)
- present_feature_flags
- else
- present :version, 1
- present :features, feature_flags, with: ::API::Entities::UnleashFeature
- end
+ desc 'Get a list of features (deprecated, v2 client support)' do
+ is_array true
+ tags unleash_tags
+ end
+ get 'features', urgency: :low do
+ 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'
+ desc 'Get a list of features' do
+ is_array true
+ tags unleash_tags
+ end
get 'client/features', urgency: :low do
- if ::Feature.enabled?(:cache_unleash_client_api, project)
- present_feature_flags
- else
- present :version, 1
- present :features, feature_flags, with: ::API::Entities::UnleashFeature
- end
+ present_feature_flags
end
post 'client/register' do
@@ -50,7 +48,7 @@ module API
status :ok
end
- post 'client/metrics' do
+ post 'client/metrics', urgency: :low do
# not supported yet
status :ok
end
diff --git a/lib/api/user_counts.rb b/lib/api/user_counts.rb
index 388aa5e375c..e9420f1e2b7 100644
--- a/lib/api/user_counts.rb
+++ b/lib/api/user_counts.rb
@@ -8,17 +8,12 @@ module API
resource :user_counts do
desc 'Return the user specific counts' do
detail 'Assigned open issues, assigned MRs and pending todos count'
+ success Entities::UserCounts
end
get do
unauthorized! unless current_user
- {
- merge_requests: current_user.assigned_open_merge_requests_count, # @deprecated
- assigned_issues: current_user.assigned_open_issues_count,
- assigned_merge_requests: current_user.assigned_open_merge_requests_count,
- review_requested_merge_requests: current_user.review_requested_open_merge_requests_count,
- todos: current_user.todos_pending_count
- }
+ present current_user, with: Entities::UserCounts
end
end
end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 7f44e46f1ca..72c121bca03 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -8,9 +8,18 @@ module API
allow_access_with_scope :read_user, if: -> (request) { request.get? || request.head? }
- feature_category :users, ['/users/:id/custom_attributes', '/users/:id/custom_attributes/:key']
-
- urgency :medium, ['/users/:id/custom_attributes', '/users/:id/custom_attributes/:key']
+ feature_category :users,
+ %w[
+ /users/:id/custom_attributes
+ /users/:id/custom_attributes/:key
+ /users/:id/associations_count
+ ]
+
+ urgency :medium,
+ %w[
+ /users/:id/custom_attributes
+ /users/:id/custom_attributes/:key
+ ]
resource :users, requirements: { uid: /[0-9]*/, id: /[0-9]*/ } do
include CustomAttributesEndpoints
@@ -20,16 +29,10 @@ module API
end
helpers Helpers::UsersHelpers
+ helpers Gitlab::Tracking::Helpers::WeakPasswordErrorEvent
helpers do
# rubocop: disable CodeReuse/ActiveRecord
- def find_user_by_id(params)
- id = params[:user_id] || params[:id]
- User.find_by(id: id) || not_found!('User')
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- # rubocop: disable CodeReuse/ActiveRecord
def reorder_users(users)
if params[:order_by] && params[:sort]
users.reorder(order_options_with_tie_breaker)
@@ -75,6 +78,31 @@ module API
end
end
+ resources ':id/associations_count' do
+ helpers do
+ def present_entity(result)
+ present result,
+ with: ::API::Entities::UserAssociationsCount
+ end
+ end
+
+ desc "Returns a list of a specified user's count of projects, groups, issues and merge requests."
+ params do
+ requires :id,
+ type: Integer,
+ desc: 'ID of the user to query.'
+ end
+ get do
+ authenticate!
+
+ user = find_user_by_id(params)
+ forbidden! unless can?(current_user, :get_user_associations_count, user)
+ not_found!('User') unless user
+
+ present_entity(user)
+ end
+ end
+
desc 'Get the list of users' do
success Entities::UserBasic
end
@@ -279,6 +307,8 @@ module API
.by_username(user.username)
.any?
+ track_weak_password_error(user, 'API::Users', 'create')
+
render_validation_error!(user)
end
end
@@ -324,6 +354,7 @@ module API
if result[:status] == :success
present user, with: Entities::UserWithAdmin, current_user: current_user
else
+ track_weak_password_error(user, 'API::Users', 'update')
render_validation_error!(user)
end
end
@@ -402,16 +433,16 @@ module API
success Entities::SSHKey
end
params do
- requires :id, type: Integer, desc: 'The ID of the user'
+ requires :user_id, type: Integer, desc: 'The ID of the user'
requires :key, type: String, desc: 'The new SSH key'
requires :title, type: String, desc: 'The title of the new SSH key'
optional :expires_at, type: DateTime, desc: 'The expiration date of the SSH key in ISO 8601 format (YYYY-MM-DDTHH:MM:SSZ)'
end
# rubocop: disable CodeReuse/ActiveRecord
- post ":id/keys", feature_category: :authentication_and_authorization do
+ post ":user_id/keys", feature_category: :authentication_and_authorization do
authenticated_as_admin!
- user = User.find_by(id: params.delete(:id))
+ user = User.find_by(id: params.delete(:user_id))
not_found!('User') unless user
key = ::Keys::CreateService.new(current_user, declared_params(include_missing: false).merge(user: user)).execute
diff --git a/lib/api/v3/github.rb b/lib/api/v3/github.rb
index c86b7785ce2..e4a26838746 100644
--- a/lib/api/v3/github.rb
+++ b/lib/api/v3/github.rb
@@ -58,7 +58,7 @@ module API
project = find_project!(
::Gitlab::Jira::Dvcs.restore_full_path(**params.slice(:namespace, :project).symbolize_keys)
)
- not_found! unless can?(current_user, :download_code, project)
+ not_found! unless can?(current_user, :read_code, project)
project
end
diff --git a/lib/api/validations/validators/email_or_email_list.rb b/lib/api/validations/validators/email_or_email_list.rb
index da665f39130..715a29c613d 100644
--- a/lib/api/validations/validators/email_or_email_list.rb
+++ b/lib/api/validations/validators/email_or_email_list.rb
@@ -9,7 +9,12 @@ module API
return unless value
- return if value.split(',').map { |v| ValidateEmail.valid?(v) }.all?
+ case value
+ when String
+ return if value.split(',').map { |v| ValidateEmail.valid?(v) }.all?
+ when Array
+ return if value.map { |v| ValidateEmail.valid?(v) }.all?
+ end
raise Grape::Exceptions::Validation.new(
params: [@scope.full_name(attr_name)],
diff --git a/lib/api/wikis.rb b/lib/api/wikis.rb
index bb8ad5c4285..2058f5de706 100644
--- a/lib/api/wikis.rb
+++ b/lib/api/wikis.rb
@@ -28,6 +28,11 @@ module API
desc 'Get a list of wiki pages' do
success Entities::WikiPageBasic
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[wikis]
+ is_array true
end
params do
optional :with_content, type: Boolean, default: false, desc: "Include pages' content"
@@ -47,6 +52,10 @@ module API
desc 'Get a wiki page' do
success Entities::WikiPage
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[wikis]
end
params do
requires :slug, type: String, desc: 'The slug of a wiki page'
@@ -67,6 +76,12 @@ module API
desc 'Create a wiki page' do
success Entities::WikiPage
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[wikis]
end
params do
requires :title, type: String, desc: 'Title of a wiki page'
@@ -88,6 +103,12 @@ module API
desc 'Update a wiki page' do
success Entities::WikiPage
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' },
+ { code: 422, message: 'Unprocessable entity' }
+ ]
+ tags %w[wikis]
end
params do
optional :title, type: String, desc: 'Title of a wiki page'
@@ -110,7 +131,14 @@ module API
end
end
- desc 'Delete a wiki page'
+ desc 'Delete a wiki page' do
+ success code: 204
+ failure [
+ { code: 400, message: 'Validation error' },
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[wikis]
+ end
params do
requires :slug, type: String, desc: 'The slug of a wiki page'
end
@@ -131,6 +159,10 @@ module API
desc 'Upload an attachment to the wiki repository' do
detail 'This feature was introduced in GitLab 11.3.'
success Entities::WikiAttachment
+ failure [
+ { code: 404, message: 'Not found' }
+ ]
+ tags %w[wikis]
end
params do
requires :file, types: [Rack::Multipart::UploadedFile, ::API::Validations::Types::WorkhorseFile], desc: 'The attachment file to be uploaded', documentation: { type: 'file' }
diff --git a/lib/atlassian/jira_connect/jwt/asymmetric.rb b/lib/atlassian/jira_connect/jwt/asymmetric.rb
index 0611a17c005..573a8022752 100644
--- a/lib/atlassian/jira_connect/jwt/asymmetric.rb
+++ b/lib/atlassian/jira_connect/jwt/asymmetric.rb
@@ -12,7 +12,8 @@ module Atlassian
KeyFetchError = Class.new(StandardError)
ALGORITHM = 'RS256'
- PUBLIC_KEY_CDN_URL = 'https://connect-install-keys.atlassian.com/'
+ DEFAULT_PUBLIC_KEY_CDN_URL = 'https://connect-install-keys.atlassian.com'
+ PROXY_PUBLIC_KEY_PATH = '/-/jira_connect/public_keys'
UUID4_REGEX = /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/.freeze
def initialize(token, verification_claims)
@@ -60,7 +61,7 @@ module Atlassian
def retrieve_public_key(key_id)
raise KeyFetchError unless UUID4_REGEX.match?(key_id)
- public_key = Gitlab::HTTP.try_get(PUBLIC_KEY_CDN_URL + key_id).try(:body)
+ public_key = Gitlab::HTTP.try_get("#{public_key_cdn_url}/#{key_id}").try(:body)
raise KeyFetchError if public_key.blank?
@@ -74,6 +75,21 @@ module Atlassian
def verification_qsh
@verification_claims[:qsh]
end
+
+ def public_key_cdn_url
+ if public_key_cdn_url_setting.blank? || Feature.disabled?(:jira_connect_oauth_self_managed)
+ return DEFAULT_PUBLIC_KEY_CDN_URL
+ end
+
+ public_key_cdn_url_setting
+ end
+
+ def public_key_cdn_url_setting
+ @public_key_cdn_url_setting ||=
+ if Gitlab::CurrentSettings.jira_connect_proxy_url
+ Gitlab::Utils.append_path(Gitlab::CurrentSettings.jira_connect_proxy_url, PROXY_PUBLIC_KEY_PATH)
+ end
+ end
end
end
end
diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb
index 902eb8f6659..a8b3c12a2a2 100644
--- a/lib/backup/manager.rb
+++ b/lib/backup/manager.rb
@@ -396,13 +396,13 @@ module Backup
timestamp = matched[1].to_i
- if Time.at(timestamp) < (Time.now - keep_time)
- begin
- FileUtils.rm(file)
- removed += 1
- rescue StandardError => e
- puts_time "Deleting #{file} failed: #{e.message}".color(:red)
- end
+ next unless Time.at(timestamp) < (Time.now - keep_time)
+
+ begin
+ FileUtils.rm(file)
+ removed += 1
+ rescue StandardError => e
+ puts_time "Deleting #{file} failed: #{e.message}".color(:red)
end
end
end
diff --git a/lib/banzai/filter/external_link_filter.rb b/lib/banzai/filter/external_link_filter.rb
index d1a0f8e5859..0a76c84efe5 100644
--- a/lib/banzai/filter/external_link_filter.rb
+++ b/lib/banzai/filter/external_link_filter.rb
@@ -22,12 +22,12 @@ module Banzai
addressable_uri = nil
end
- unless internal_url?(addressable_uri)
- punycode_autolink_node!(addressable_uri, node)
- sanitize_link_text!(node)
- add_malicious_tooltip!(addressable_uri, node)
- add_nofollow!(addressable_uri, node)
- end
+ next if internal_url?(addressable_uri)
+
+ punycode_autolink_node!(addressable_uri, node)
+ sanitize_link_text!(node)
+ add_malicious_tooltip!(addressable_uri, node)
+ add_nofollow!(addressable_uri, node)
end
doc
diff --git a/lib/banzai/filter/footnote_filter.rb b/lib/banzai/filter/footnote_filter.rb
index f5c4b788ad8..f10efdccdf1 100644
--- a/lib/banzai/filter/footnote_filter.rb
+++ b/lib/banzai/filter/footnote_filter.rb
@@ -44,25 +44,25 @@ module Banzai
node_xpath = Gitlab::Utils::Nokogiri.css_to_xpath(css)
footnote_node = doc.at_xpath(node_xpath)
- if footnote_node || modified_footnotes[ref_num]
- link_node[:href] += rand_suffix
- link_node[:id] += rand_suffix
+ next unless footnote_node || modified_footnotes[ref_num]
- # Sanitization stripped off class - add it back in
- link_node.parent.append_class('footnote-ref')
+ link_node[:href] += rand_suffix
+ link_node[:id] += rand_suffix
- unless modified_footnotes[ref_num]
- footnote_node[:id] += rand_suffix
- backref_node = footnote_node.at_css("a[href=\"##{fnref_id(ref_num)}\"]")
+ # Sanitization stripped off class - add it back in
+ link_node.parent.append_class('footnote-ref')
- if backref_node
- backref_node[:href] += rand_suffix
- backref_node.append_class('footnote-backref')
- end
+ next if modified_footnotes[ref_num]
- modified_footnotes[ref_num] = true
- end
+ footnote_node[:id] += rand_suffix
+ backref_node = footnote_node.at_css("a[href=\"##{fnref_id(ref_num)}\"]")
+
+ if backref_node
+ backref_node[:href] += rand_suffix
+ backref_node.append_class('footnote-backref')
end
+
+ modified_footnotes[ref_num] = true
end
doc
diff --git a/lib/banzai/filter/kroki_filter.rb b/lib/banzai/filter/kroki_filter.rb
index 713ff2439fc..26f42c6b194 100644
--- a/lib/banzai/filter/kroki_filter.rb
+++ b/lib/banzai/filter/kroki_filter.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
-require "nokogiri"
-require "asciidoctor/extensions/asciidoctor_kroki/extension"
+require 'nokogiri'
+require 'asciidoctor/extensions/asciidoctor_kroki/version'
+require 'asciidoctor/extensions/asciidoctor_kroki/extension'
module Banzai
module Filter
@@ -31,16 +32,16 @@ module Banzai
img_tag = Nokogiri::HTML::DocumentFragment.parse(%(<img src="#{image_src}" />))
img_tag = img_tag.children.first
- unless img_tag.nil?
- lazy_load = diagram_src.length > MAX_CHARACTER_LIMIT
- img_tag.set_attribute('hidden', '') if lazy_load
- img_tag.set_attribute('class', 'js-render-kroki')
+ next if img_tag.nil?
- img_tag.set_attribute('data-diagram', diagram_type)
- img_tag.set_attribute('data-diagram-src', "data:text/plain;base64,#{Base64.strict_encode64(diagram_src)}")
+ lazy_load = diagram_src.length > MAX_CHARACTER_LIMIT
+ img_tag.set_attribute('hidden', '') if lazy_load
+ img_tag.set_attribute('class', 'js-render-kroki')
- node.parent.replace(img_tag)
- end
+ img_tag.set_attribute('data-diagram', diagram_type)
+ img_tag.set_attribute('data-diagram-src', "data:text/plain;base64,#{Base64.strict_encode64(diagram_src)}")
+
+ node.parent.replace(img_tag)
end
doc
diff --git a/lib/banzai/filter/math_filter.rb b/lib/banzai/filter/math_filter.rb
index 1ca4b2c89db..1d854d6599b 100644
--- a/lib/banzai/filter/math_filter.rb
+++ b/lib/banzai/filter/math_filter.rb
@@ -10,7 +10,7 @@ module Banzai
# HTML filter that implements our math syntax, adding class="code math"
#
class MathFilter < HTML::Pipeline::Filter
- CSS_MATH = 'pre.code.language-math'
+ CSS_MATH = 'pre[lang="math"] > code'
XPATH_MATH = Gitlab::Utils::Nokogiri.css_to_xpath(CSS_MATH).freeze
CSS_CODE = 'code'
XPATH_CODE = Gitlab::Utils::Nokogiri.css_to_xpath(CSS_CODE).freeze
@@ -32,7 +32,7 @@ module Banzai
# Corresponds to the $$\n...\n$$ syntax
DOLLAR_DISPLAY_BLOCK_PATTERN = %r{
^(?<matched>\$\$\ *\n(?<math>.*)\n\$\$\ *)$
- }x.freeze
+ }mx.freeze
# Order dependent. Handle the `$$` syntax before the `$` syntax
DOLLAR_MATH_PIPELINE = [
@@ -107,27 +107,27 @@ module Banzai
# We need a sibling before and after.
# They should end and start with $ respectively.
- if closing && opening &&
- closing.text? && opening.text? &&
- closing.content.first == DOLLAR_SIGN &&
- opening.content.last == DOLLAR_SIGN
-
- code[:class] = MATH_CLASSES
- code[STYLE_ATTRIBUTE] = 'inline'
- closing.content = closing.content[1..]
- opening.content = opening.content[0..-2]
-
- @nodes_count += 1
- break if @nodes_count >= RENDER_NODES_LIMIT
- end
+ next unless closing && opening &&
+ closing.text? && opening.text? &&
+ closing.content.first == DOLLAR_SIGN &&
+ opening.content.last == DOLLAR_SIGN
+
+ code[:class] = MATH_CLASSES
+ code[STYLE_ATTRIBUTE] = 'inline'
+ closing.content = closing.content[1..]
+ opening.content = opening.content[0..-2]
+
+ @nodes_count += 1
+ break if @nodes_count >= RENDER_NODES_LIMIT
end
end
# corresponds to the "```math...```" syntax
def process_math_codeblock
- doc.xpath(XPATH_MATH).each do |el|
- el[STYLE_ATTRIBUTE] = 'display'
- el[:class] += " #{TAG_CLASS}"
+ doc.xpath(XPATH_MATH).each do |node|
+ pre_node = node.parent
+ pre_node[STYLE_ATTRIBUTE] = 'display'
+ pre_node[:class] = TAG_CLASS
end
end
diff --git a/lib/banzai/filter/plantuml_filter.rb b/lib/banzai/filter/plantuml_filter.rb
index 82f6247cf03..6a1fa64fb76 100644
--- a/lib/banzai/filter/plantuml_filter.rb
+++ b/lib/banzai/filter/plantuml_filter.rb
@@ -17,12 +17,12 @@ module Banzai
img_tag = Nokogiri::HTML::DocumentFragment.parse(
Asciidoctor::PlantUml::Processor.plantuml_content(node.content, {})).css('img').first
- unless img_tag.nil?
- img_tag.set_attribute('data-diagram', 'plantuml')
- img_tag.set_attribute('data-diagram-src', "data:text/plain;base64,#{Base64.strict_encode64(node.content)}")
+ next if img_tag.nil?
- node.parent.replace(img_tag)
- end
+ img_tag.set_attribute('data-diagram', 'plantuml')
+ img_tag.set_attribute('data-diagram-src', "data:text/plain;base64,#{Base64.strict_encode64(node.content)}")
+
+ node.parent.replace(img_tag)
end
doc
diff --git a/lib/banzai/filter/repository_link_filter.rb b/lib/banzai/filter/repository_link_filter.rb
index f5cf1833304..e95da735647 100644
--- a/lib/banzai/filter/repository_link_filter.rb
+++ b/lib/banzai/filter/repository_link_filter.rb
@@ -101,6 +101,7 @@ module Banzai
if uri.relative? && uri.path.present?
html_attr.value = rebuild_relative_uri(uri).to_s
+ html_attr.parent.add_class('gfm')
end
rescue URI::Error, Addressable::URI::InvalidURIError
# noop
diff --git a/lib/banzai/filter/syntax_highlight_filter.rb b/lib/banzai/filter/syntax_highlight_filter.rb
index 7175e99f1c7..766715d9e39 100644
--- a/lib/banzai/filter/syntax_highlight_filter.rb
+++ b/lib/banzai/filter/syntax_highlight_filter.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
require 'rouge/plugins/common_mark'
-require "asciidoctor/extensions/asciidoctor_kroki/extension"
+require 'asciidoctor/extensions/asciidoctor_kroki/version'
+require 'asciidoctor/extensions/asciidoctor_kroki/extension'
# Generated HTML is transformed back to GFM by app/assets/javascripts/behaviors/markdown/nodes/code_block.js
module Banzai
@@ -13,8 +14,9 @@ module Banzai
LANG_PARAMS_DELIMITER = ':'
LANG_PARAMS_ATTR = 'data-lang-params'
+ CSS_CLASSES = 'code highlight js-syntax-highlight'
- CSS = 'pre:not([data-math-style]):not([data-mermaid-style]):not([data-kroki-style]) > code:only-child'
+ CSS = 'pre:not([data-kroki-style]) > code:only-child'
XPATH = Gitlab::Utils::Nokogiri.css_to_xpath(CSS).freeze
def call
@@ -26,9 +28,9 @@ module Banzai
end
def highlight_node(node)
- css_classes = +'code highlight js-syntax-highlight'
+ return if node.parent&.parent.nil?
+
lang, lang_params = parse_lang_params(node)
- sourcepos = node.parent.attr('data-sourcepos')
retried = false
if use_rouge?(lang)
@@ -41,7 +43,6 @@ module Banzai
begin
code = Rouge::Formatters::HTMLGitlab.format(lex(lexer, node.text), tag: language)
- css_classes << " language-#{language}" if language
rescue StandardError
# Gracefully handle syntax highlighter bugs/errors to ensure users can
# still access an issue/comment/etc. First, retry with the plain text
@@ -56,16 +57,26 @@ module Banzai
retry
end
- sourcepos_attr = sourcepos ? "data-sourcepos=\"#{escape_once(sourcepos)}\"" : ''
+ # maintain existing attributes already added. e.g math and mermaid nodes
+ node.children = code
+ pre_node = node.parent
+
+ # ensure there are no extra children, such as a text node that might
+ # show up from an XSS attack
+ pre_node.children = node
+
+ pre_node[:lang] = language
+ pre_node.add_class(CSS_CLASSES)
+ pre_node.add_class("language-#{language}") if language
+ pre_node.set_attribute('data-canonical-lang', escape_once(lang)) if lang != language
+ pre_node.set_attribute(LANG_PARAMS_ATTR, escape_once(lang_params)) if lang_params.present?
+ pre_node.set_attribute('v-pre', 'true')
+ pre_node.remove_attribute('data-meta')
- highlighted = %(<div class="gl-relative markdown-code-block js-markdown-code"><pre #{sourcepos_attr} class="#{css_classes}"
- lang="#{language}"
- #{lang != language ? "data-canonical-lang=\"#{escape_once(lang)}\"" : ""}
- #{lang_params}
- v-pre="true"><code>#{code}</code></pre><copy-code></copy-code></div>)
+ highlighted = %(<div class="gl-relative markdown-code-block js-markdown-code">#{pre_node.to_html}<copy-code></copy-code></div>)
# Extracted to a method to measure it
- replace_parent_pre_element(node, highlighted)
+ replace_pre_element(pre_node, highlighted)
end
private
@@ -93,9 +104,8 @@ module Banzai
language, language_params = language.split(LANG_PARAMS_DELIMITER, 2)
language_params = [node.attr('data-meta'), language_params].compact.join(' ')
- formatted_language_params = format_language_params(language_params)
- [language, formatted_language_params]
+ [language, language_params]
end
# Separate method so it can be instrumented.
@@ -107,20 +117,14 @@ module Banzai
(Rouge::Lexer.find(language) || Rouge::Lexers::PlainText).new
end
- # Replace the parent `pre` element with the entire highlighted block
- def replace_parent_pre_element(node, highlighted)
- node.parent.replace(highlighted)
+ # Replace the `pre` element with the entire highlighted block
+ def replace_pre_element(pre_node, highlighted)
+ pre_node.replace(highlighted)
end
def use_rouge?(language)
(%w(math suggestion) + ::AsciidoctorExtensions::Kroki::SUPPORTED_DIAGRAM_NAMES).exclude?(language)
end
-
- def format_language_params(language_params)
- return if language_params.blank?
-
- %(#{LANG_PARAMS_ATTR}="#{escape_once(language_params)}")
- end
end
end
end
diff --git a/lib/banzai/filter/table_of_contents_filter.rb b/lib/banzai/filter/table_of_contents_filter.rb
index 1c794a81d9d..d76009d08e1 100644
--- a/lib/banzai/filter/table_of_contents_filter.rb
+++ b/lib/banzai/filter/table_of_contents_filter.rb
@@ -33,17 +33,17 @@ module Banzai
header_root = current_header = HeaderNode.new
doc.xpath(XPATH).each do |node|
- if header_content = node.children.first
- id = string_to_anchor(node.text[0...255])
+ next unless header_content = node.children.first
- uniq = headers[id] > 0 ? "-#{headers[id]}" : ''
- headers[id] += 1
- href = "#{id}#{uniq}"
+ id = string_to_anchor(node.text[0...255])
- current_header = HeaderNode.new(node: node, href: href, previous_header: current_header)
+ uniq = headers[id] > 0 ? "-#{headers[id]}" : ''
+ headers[id] += 1
+ href = "#{id}#{uniq}"
- header_content.add_previous_sibling(anchor_tag(href))
- end
+ current_header = HeaderNode.new(node: node, href: href, previous_header: current_header)
+
+ header_content.add_previous_sibling(anchor_tag(href))
end
push_toc(header_root.children, root: true)
diff --git a/lib/banzai/pipeline/ascii_doc_pipeline.rb b/lib/banzai/pipeline/ascii_doc_pipeline.rb
index b652d8d89cf..afd5802de22 100644
--- a/lib/banzai/pipeline/ascii_doc_pipeline.rb
+++ b/lib/banzai/pipeline/ascii_doc_pipeline.rb
@@ -7,13 +7,13 @@ module Banzai
FilterArray[
Filter::AsciiDocSanitizationFilter,
Filter::AssetProxyFilter,
- Filter::SyntaxHighlightFilter,
Filter::ExternalLinkFilter,
Filter::PlantumlFilter,
Filter::ColorFilter,
Filter::ImageLazyLoadFilter,
Filter::ImageLinkFilter,
Filter::WikiLinkFilter,
+ Filter::SyntaxHighlightFilter,
Filter::AsciiDocPostProcessingFilter
]
end
diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb
index 5e7c2f64c92..9b73e413d44 100644
--- a/lib/banzai/pipeline/gfm_pipeline.rb
+++ b/lib/banzai/pipeline/gfm_pipeline.rb
@@ -17,7 +17,6 @@ module Banzai
Filter::SanitizationFilter,
Filter::KrokiFilter,
Filter::AssetProxyFilter,
- Filter::SyntaxHighlightFilter,
Filter::MathFilter,
Filter::ColorFilter,
Filter::MermaidFilter,
@@ -37,7 +36,8 @@ module Banzai
Filter::CustomEmojiFilter,
Filter::TaskListFilter,
Filter::InlineDiffFilter,
- Filter::SetDirectionFilter
+ Filter::SetDirectionFilter,
+ Filter::SyntaxHighlightFilter
]
end
diff --git a/lib/banzai/reference_parser/base_parser.rb b/lib/banzai/reference_parser/base_parser.rb
index 831baa9a778..19d91876892 100644
--- a/lib/banzai/reference_parser/base_parser.rb
+++ b/lib/banzai/reference_parser/base_parser.rb
@@ -66,6 +66,8 @@ module Banzai
projects = lazy { projects_for_nodes(nodes) }
project_attr = 'data-project'
+ preload_associations(projects, user)
+
nodes.select do |node|
if node.has_attribute?(project_attr)
can_read_reference?(user, projects[node], node)
@@ -261,6 +263,14 @@ module Banzai
hash[key] = {}
end
end
+
+ # For any preloading of project associations
+ # needed to avoid N+1s.
+ # Note: `projects` param is a hash of { node => project }.
+ # See #projects_for_nodes for more information.
+ def preload_associations(projects, user)
+ ::Preloaders::ProjectPolicyPreloader.new(projects.values, user).execute
+ end
end
end
end
diff --git a/lib/banzai/reference_parser/commit_parser.rb b/lib/banzai/reference_parser/commit_parser.rb
index 88896970bc6..c51f4976c28 100644
--- a/lib/banzai/reference_parser/commit_parser.rb
+++ b/lib/banzai/reference_parser/commit_parser.rb
@@ -32,6 +32,13 @@ 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 fb4a392105f..3d09bc83151 100644
--- a/lib/banzai/reference_parser/commit_range_parser.rb
+++ b/lib/banzai/reference_parser/commit_range_parser.rb
@@ -38,6 +38,13 @@ 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/bulk_imports/clients/http.rb b/lib/bulk_imports/clients/http.rb
index 1d77757c4af..4c36f226006 100644
--- a/lib/bulk_imports/clients/http.rb
+++ b/lib/bulk_imports/clients/http.rb
@@ -56,8 +56,15 @@ module BulkImports
def instance_version
strong_memoize(:instance_version) do
- response = with_error_handling do
- Gitlab::HTTP.get(resource_url(:version), default_options)
+ response = begin
+ with_error_handling do
+ Gitlab::HTTP.get(resource_url(:version), default_options)
+ end
+ rescue BulkImports::NetworkError
+ # `version` endpoint is not available, try `metadata` endpoint instead
+ with_error_handling do
+ Gitlab::HTTP.get(resource_url(:metadata), default_options)
+ end
end
Gitlab::VersionInfo.parse(response.parsed_response['version'])
diff --git a/lib/bulk_imports/common/pipelines/entity_finisher.rb b/lib/bulk_imports/common/pipelines/entity_finisher.rb
index 5066f622d57..a52504d04bc 100644
--- a/lib/bulk_imports/common/pipelines/entity_finisher.rb
+++ b/lib/bulk_imports/common/pipelines/entity_finisher.rb
@@ -24,11 +24,13 @@ module BulkImports
end
logger.info(
- bulk_import_id: context.bulk_import_id,
- bulk_import_entity_id: context.entity.id,
- bulk_import_entity_type: context.entity.source_type,
+ bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_id: entity.id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
pipeline_class: self.class.name,
message: "Entity #{entity.status_name}",
+ source_version: entity.bulk_import.source_version_info.to_s,
importer: 'gitlab_migration'
)
diff --git a/lib/bulk_imports/common/pipelines/wiki_pipeline.rb b/lib/bulk_imports/common/pipelines/wiki_pipeline.rb
index fea550b9f9d..68d511b065f 100644
--- a/lib/bulk_imports/common/pipelines/wiki_pipeline.rb
+++ b/lib/bulk_imports/common/pipelines/wiki_pipeline.rb
@@ -24,7 +24,7 @@ module BulkImports
Gitlab::UrlBlocker.validate!(url, schemes: %w[http https], allow_local_network: allow_local_requests?, allow_localhost: allow_local_requests?)
- wiki.ensure_repository
+ wiki.create_wiki_repository
wiki.repository.fetch_as_mirror(url)
end
diff --git a/lib/bulk_imports/pipeline/runner.rb b/lib/bulk_imports/pipeline/runner.rb
index ef9575d1e96..81f8dee30d9 100644
--- a/lib/bulk_imports/pipeline/runner.rb
+++ b/lib/bulk_imports/pipeline/runner.rb
@@ -99,7 +99,7 @@ module BulkImports
end
def log_import_failure(exception, step)
- attributes = {
+ failure_attributes = {
bulk_import_entity_id: context.entity.id,
pipeline_class: pipeline,
pipeline_step: step,
@@ -108,16 +108,18 @@ module BulkImports
correlation_id_value: Labkit::Correlation::CorrelationId.current_or_new_id
}
- error(
- bulk_import_id: context.bulk_import_id,
- pipeline_step: step,
- exception_class: exception.class.to_s,
- exception_message: exception.message,
- message: "Pipeline failed",
- importer: 'gitlab_migration'
+ log_exception(
+ exception,
+ log_params(
+ {
+ bulk_import_id: context.bulk_import_id,
+ pipeline_step: step,
+ message: 'Pipeline failed'
+ }
+ )
)
- BulkImports::Failure.create(attributes)
+ BulkImports::Failure.create(failure_attributes)
end
def info(extra = {})
@@ -128,17 +130,15 @@ module BulkImports
logger.warn(log_params(extra))
end
- def error(extra = {})
- logger.error(log_params(extra))
- end
-
def log_params(extra)
defaults = {
bulk_import_id: context.bulk_import_id,
bulk_import_entity_id: context.entity.id,
bulk_import_entity_type: context.entity.source_type,
+ source_full_path: context.entity.source_full_path,
pipeline_class: pipeline,
context_extra: context.extra,
+ source_version: context.entity.bulk_import.source_version_info.to_s,
importer: 'gitlab_migration'
}
@@ -150,6 +150,19 @@ module BulkImports
def logger
@logger ||= Gitlab::Import::Logger.build
end
+
+ def log_exception(exception, payload)
+ Gitlab::ExceptionLogFormatter.format!(exception, payload)
+ logger.error(structured_payload(payload))
+ end
+
+ def structured_payload(payload = {})
+ context = Gitlab::ApplicationContext.current.merge(
+ 'class' => self.class.name
+ )
+
+ payload.stringify_keys.merge(context)
+ end
end
end
end
diff --git a/lib/bulk_imports/projects/pipelines/references_pipeline.rb b/lib/bulk_imports/projects/pipelines/references_pipeline.rb
new file mode 100644
index 00000000000..9c76f96c7be
--- /dev/null
+++ b/lib/bulk_imports/projects/pipelines/references_pipeline.rb
@@ -0,0 +1,103 @@
+# frozen_string_literal: true
+
+module BulkImports
+ module Projects
+ module Pipelines
+ class ReferencesPipeline
+ include Pipeline
+
+ BATCH_SIZE = 100
+
+ def extract(_context)
+ data = Enumerator.new do |enum|
+ add_matching_objects(portable.issues, enum)
+ add_matching_objects(portable.merge_requests, enum)
+ end
+
+ BulkImports::Pipeline::ExtractedData.new(data: data)
+ end
+
+ def transform(_context, object)
+ body = object_body(object).dup
+
+ matching_urls(object).each do |old_url, new_url|
+ body.gsub!(old_url, new_url)
+ end
+
+ object.assign_attributes(body_field(object) => body)
+
+ object
+ end
+
+ def load(_context, object)
+ object.save! if object_body_changed?(object)
+ end
+
+ private
+
+ def add_matching_objects(collection, enum)
+ collection.each_batch(of: BATCH_SIZE, column: :iid) do |batch|
+ batch.each do |object|
+ enum << object if object_has_reference?(object)
+
+ object.notes.each_batch(of: BATCH_SIZE) do |notes_batch|
+ notes_batch.each do |note|
+ enum << note if object_has_reference?(note)
+ end
+ end
+ end
+ end
+ end
+
+ def object_has_reference?(object)
+ object_body(object).include?(source_full_path)
+ end
+
+ def object_body(object)
+ call_object_method(object)
+ end
+
+ def object_body_changed?(object)
+ call_object_method(object, suffix: '_changed?')
+ end
+
+ def call_object_method(object, suffix: nil)
+ method = body_field(object)
+ method = "#{method}#{suffix}" if suffix.present?
+
+ object.public_send(method) # rubocop:disable GitlabSecurity/PublicSend
+ end
+
+ def body_field(object)
+ object.is_a?(Note) ? 'note' : 'description'
+ end
+
+ def matching_urls(object)
+ URI.extract(object_body(object), %w[http https]).each_with_object([]) do |url, array|
+ parsed_url = URI.parse(url)
+
+ next unless source_host == parsed_url.host
+ next unless parsed_url.path&.start_with?("/#{source_full_path}")
+
+ array << [url, new_url(parsed_url)]
+ end
+ end
+
+ def new_url(parsed_old_url)
+ parsed_old_url.host = ::Gitlab.config.gitlab.host
+ parsed_old_url.port = ::Gitlab.config.gitlab.port
+ parsed_old_url.scheme = ::Gitlab.config.gitlab.https ? 'https' : 'http'
+ parsed_old_url.to_s.gsub!(source_full_path, portable.full_path)
+ end
+
+ def source_host
+ @source_host ||= URI.parse(context.configuration.url).host
+ end
+
+ def source_full_path
+ context.entity.source_full_path
+ end
+ end
+ end
+ end
+end
diff --git a/lib/bulk_imports/projects/stage.rb b/lib/bulk_imports/projects/stage.rb
index acfa9163eae..2fefdb9055e 100644
--- a/lib/bulk_imports/projects/stage.rb
+++ b/lib/bulk_imports/projects/stage.rb
@@ -129,6 +129,10 @@ module BulkImports
pipeline: BulkImports::Projects::Pipelines::PipelineSchedulesPipeline,
stage: 5
},
+ references: {
+ pipeline: BulkImports::Projects::Pipelines::ReferencesPipeline,
+ stage: 5
+ },
finisher: {
pipeline: BulkImports::Common::Pipelines::EntityFinisher,
stage: 6
diff --git a/lib/error_tracking/sentry_client.rb b/lib/error_tracking/sentry_client.rb
index 713cec7a7d6..dea60fff04c 100644
--- a/lib/error_tracking/sentry_client.rb
+++ b/lib/error_tracking/sentry_client.rb
@@ -17,14 +17,9 @@ module ErrorTracking
attr_accessor :url, :token
- def initialize(api_url, token, validate_size_guarded_by_feature_flag: false)
+ def initialize(api_url, token)
@url = api_url
@token = token
- @validate_size_guarded_by_feature_flag = validate_size_guarded_by_feature_flag
- end
-
- def validate_size_guarded_by_feature_flag?
- @validate_size_guarded_by_feature_flag
end
private
@@ -103,7 +98,7 @@ module ErrorTracking
def handle_response(response)
raise_error "Sentry response status code: #{response.code}" unless response.code.between?(200, 204)
- validate_size(response.parsed_response) if validate_size_guarded_by_feature_flag?
+ validate_size(response.parsed_response)
{ body: response.parsed_response, headers: response.headers }
end
diff --git a/lib/error_tracking/sentry_client/issue.rb b/lib/error_tracking/sentry_client/issue.rb
index 5e2e0787a3f..359617328cb 100644
--- a/lib/error_tracking/sentry_client/issue.rb
+++ b/lib/error_tracking/sentry_client/issue.rb
@@ -18,10 +18,6 @@ module ErrorTracking
issues = response[:issues]
pagination = response[:pagination]
- # We check validate size only with feture flag disabled because when
- # enabled we already check it when parsing the response.
- validate_size(issues) unless validate_size_guarded_by_feature_flag?
-
handle_mapping_exceptions do
{
issues: map_to_errors(issues),
diff --git a/lib/feature.rb b/lib/feature.rb
index f317e8cb2c5..5841828da0e 100644
--- a/lib/feature.rb
+++ b/lib/feature.rb
@@ -301,11 +301,11 @@ module Feature
end
def gate_specified?
- %i(user project group feature_group namespace).any? { |key| params.key?(key) }
+ %i(user project group feature_group namespace repository).any? { |key| params.key?(key) }
end
def targets
- [feature_group, users, projects, groups, namespaces].flatten.compact
+ [feature_group, users, projects, groups, namespaces, repositories].flatten.compact
end
private
@@ -350,6 +350,17 @@ module Feature
Namespace.without_project_namespaces.find_by_full_path(arg) || (raise UnknowTargetError, "#{arg} is not found!")
end
end
+
+ def repositories
+ return unless params.key?(:repository)
+
+ params[:repository].split(',').map do |arg|
+ container, _project, _type, _path = Gitlab::RepoPath.parse(arg)
+ raise UnknowTargetError, "#{arg} is not found!" if container.nil?
+
+ container.repository
+ end
+ end
end
end
diff --git a/lib/feature/gitaly.rb b/lib/feature/gitaly.rb
index 0c6b9dfde7a..fd798862fa8 100644
--- a/lib/feature/gitaly.rb
+++ b/lib/feature/gitaly.rb
@@ -4,26 +4,60 @@ module Feature
class Gitaly
PREFIX = "gitaly_"
+ # Wrapper for feature flag actor to avoid unnecessarily SQL queries
+ class ActorWrapper
+ def initialize(klass, id)
+ @klass = klass
+ @id = id
+ end
+
+ def flipper_id
+ "#{@klass.name}:#{@id}"
+ end
+ end
+
class << self
- def enabled?(feature_flag, project = nil)
+ def enabled_for_any?(feature_flag, *actors)
return false unless Feature::FlipperFeature.table_exists?
- Feature.enabled?("#{PREFIX}#{feature_flag}", project, type: :undefined, default_enabled_if_undefined: false)
+ actors = actors.compact
+ return Feature.enabled?(feature_flag, type: :undefined, default_enabled_if_undefined: false) if actors.empty?
+
+ actors.any? do |actor|
+ Feature.enabled?(feature_flag, actor, type: :undefined, default_enabled_if_undefined: false)
+ end
rescue ActiveRecord::NoDatabaseError, PG::ConnectionBad
false
end
- def server_feature_flags(project = nil)
+ def server_feature_flags(repository: nil, user: nil, project: nil, group: nil)
# We need to check that both the DB connection and table exists
return {} unless FlipperFeature.database.cached_table_exists?
+ # The order of actors here is significant. Percentage-based actor selection may not work as expected if this
+ # order changes. We want repository actor to take highest precedence.
+ actors = [repository, user, project, group].compact
+
Feature.persisted_names
.select { |f| f.start_with?(PREFIX) }
.to_h do |f|
- flag = f.delete_prefix(PREFIX)
+ ["gitaly-feature-#{f.delete_prefix(PREFIX).tr('_', '-')}", enabled_for_any?(f, *actors).to_s]
+ end
+ end
- ["gitaly-feature-#{flag.tr('_', '-')}", enabled?(flag, project).to_s]
- end
+ def user_actor(user = nil)
+ return ::Feature::Gitaly::ActorWrapper.new(::User, user.id) if user.is_a?(::User)
+
+ user_id = Gitlab::ApplicationContext.current_context_attribute(:user_id)
+ ::Feature::Gitaly::ActorWrapper.new(::User, user_id) if user_id
+ end
+
+ def project_actor(container)
+ ::Feature::Gitaly::ActorWrapper.new(::Project, container.id) if container.is_a?(::Project)
+ end
+
+ def group_actor(container)
+ ::Feature::Gitaly::ActorWrapper.new(::Group, container.namespace_id) if container.is_a?(::Project)
end
end
end
diff --git a/lib/gitlab/application_context.rb b/lib/gitlab/application_context.rb
index 1920e1443da..b6ad25e700b 100644
--- a/lib/gitlab/application_context.rb
+++ b/lib/gitlab/application_context.rb
@@ -11,6 +11,7 @@ module Gitlab
LOG_KEY = Labkit::Context::LOG_KEY
KNOWN_KEYS = [
:user,
+ :user_id,
:project,
:root_namespace,
:client_id,
@@ -98,6 +99,7 @@ module Gitlab
assign_hash_if_value(hash, :artifacts_dependencies_count)
hash[:user] = -> { username } if include_user?
+ hash[:user_id] = -> { user_id } if include_user?
hash[:project] = -> { project_path } if include_project?
hash[:root_namespace] = -> { root_namespace_path } if include_namespace?
hash[:client_id] = -> { client } if include_client?
@@ -147,6 +149,11 @@ module Gitlab
associated_user&.username
end
+ def user_id
+ associated_user = user || job_user
+ associated_user&.id
+ end
+
def root_namespace_path
associated_routable = namespace || project || runner_project || runner_group || job_project
associated_routable&.full_path_components&.first
diff --git a/lib/gitlab/application_rate_limiter/increment_per_actioned_resource.rb b/lib/gitlab/application_rate_limiter/increment_per_actioned_resource.rb
index 7a68dd104a8..e8bdddca374 100644
--- a/lib/gitlab/application_rate_limiter/increment_per_actioned_resource.rb
+++ b/lib/gitlab/application_rate_limiter/increment_per_actioned_resource.rb
@@ -10,7 +10,7 @@ module Gitlab
def increment(cache_key, expiry)
with_redis do |redis|
redis.pipelined do |pipeline|
- pipeline.sadd(cache_key, resource_key)
+ pipeline.sadd?(cache_key, resource_key)
pipeline.expire(cache_key, expiry)
pipeline.scard(cache_key)
end.last
diff --git a/lib/gitlab/asciidoc.rb b/lib/gitlab/asciidoc.rb
index a9c2dd001cb..d55f2bc8ac9 100644
--- a/lib/gitlab/asciidoc.rb
+++ b/lib/gitlab/asciidoc.rb
@@ -2,6 +2,7 @@
require 'asciidoctor'
require 'asciidoctor-plantuml'
+require 'asciidoctor/extensions/asciidoctor_kroki/version'
require 'asciidoctor/extensions/asciidoctor_kroki/extension'
require 'asciidoctor/extensions'
require 'gitlab/asciidoc/html5_converter'
diff --git a/lib/gitlab/audit/type/definition.rb b/lib/gitlab/audit/type/definition.rb
index af5dc9f4b44..f64f66f4ca4 100644
--- a/lib/gitlab/audit/type/definition.rb
+++ b/lib/gitlab/audit/type/definition.rb
@@ -5,6 +5,7 @@ module Gitlab
module Type
class Definition
include ActiveModel::Validations
+ include ::Gitlab::Audit::Type::Shared
attr_reader :path
attr_reader :attributes
@@ -17,18 +18,6 @@ module Gitlab
AUDIT_EVENT_TYPE_SCHEMA_PATH = Rails.root.join('config', 'audit_events', 'types', 'type_schema.json')
AUDIT_EVENT_TYPE_SCHEMA = JSONSchemer.schema(AUDIT_EVENT_TYPE_SCHEMA_PATH)
- # The PARAMS in config/audit_events/types/type_schema.json
- PARAMS = %i[
- name
- description
- introduced_by_issue
- introduced_by_mr
- group
- milestone
- saved_to_database
- streamed
- ].freeze
-
PARAMS.each do |param|
define_method(param) do
attributes[param]
diff --git a/lib/gitlab/audit/type/shared.rb b/lib/gitlab/audit/type/shared.rb
new file mode 100644
index 00000000000..999b7de13e2
--- /dev/null
+++ b/lib/gitlab/audit/type/shared.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+# This file can contain only simple constructs as it is shared between:
+# 1. `Pure Ruby`: `bin/audit-event-type`
+# 2. `GitLab Rails`: `lib/gitlab/audit/type/definition.rb`
+
+module Gitlab
+ module Audit
+ module Type
+ module Shared
+ # The PARAMS in config/audit_events/types/type_schema.json
+ PARAMS = %i[
+ name
+ description
+ introduced_by_issue
+ introduced_by_mr
+ group
+ milestone
+ saved_to_database
+ streamed
+ ].freeze
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/backfill_cluster_agents_has_vulnerabilities.rb b/lib/gitlab/background_migration/backfill_cluster_agents_has_vulnerabilities.rb
index 2ee0594d0a6..249c9d7af57 100644
--- a/lib/gitlab/background_migration/backfill_cluster_agents_has_vulnerabilities.rb
+++ b/lib/gitlab/background_migration/backfill_cluster_agents_has_vulnerabilities.rb
@@ -16,11 +16,10 @@ module Gitlab
.where(has_vulnerabilities: false)
end
+ operation_name :update_all
+
def perform
- each_sub_batch(
- operation_name: :update_all,
- batching_scope: RELATION
- ) do |sub_batch|
+ each_sub_batch(batching_scope: RELATION) do |sub_batch|
sub_batch
.joins(VULNERABILITY_READS_JOIN)
.update_all(has_vulnerabilities: true)
diff --git a/lib/gitlab/background_migration/backfill_group_features.rb b/lib/gitlab/background_migration/backfill_group_features.rb
index 35b5282360f..4ea664e2529 100644
--- a/lib/gitlab/background_migration/backfill_group_features.rb
+++ b/lib/gitlab/background_migration/backfill_group_features.rb
@@ -5,10 +5,10 @@ module Gitlab
# Backfill group_features for an array of groups
class BackfillGroupFeatures < ::Gitlab::BackgroundMigration::BatchedMigrationJob
job_arguments :batch_size
+ operation_name :upsert_group_features
def perform
each_sub_batch(
- operation_name: :upsert_group_features,
batching_arguments: { order_hint: :type },
batching_scope: ->(relation) { relation.where(type: 'Group') }
) do |sub_batch|
diff --git a/lib/gitlab/background_migration/backfill_imported_issue_search_data.rb b/lib/gitlab/background_migration/backfill_imported_issue_search_data.rb
index b2d38ce6aa4..c95fed512c9 100644
--- a/lib/gitlab/background_migration/backfill_imported_issue_search_data.rb
+++ b/lib/gitlab/background_migration/backfill_imported_issue_search_data.rb
@@ -9,10 +9,10 @@ module Gitlab
class BackfillImportedIssueSearchData < BatchedMigrationJob
SUB_BATCH_SIZE = 1_000
+ operation_name :update_search_data
+
def perform
- each_sub_batch(
- operation_name: :update_search_data
- ) do |sub_batch|
+ each_sub_batch do |sub_batch|
update_search_data(sub_batch)
rescue ActiveRecord::StatementInvalid => e
raise unless e.cause.is_a?(PG::ProgramLimitExceeded) && e.message.include?('string is too long for tsvector')
diff --git a/lib/gitlab/background_migration/backfill_internal_on_notes.rb b/lib/gitlab/background_migration/backfill_internal_on_notes.rb
index 300f2cff6ca..fe05b4ec3c1 100644
--- a/lib/gitlab/background_migration/backfill_internal_on_notes.rb
+++ b/lib/gitlab/background_migration/backfill_internal_on_notes.rb
@@ -5,9 +5,10 @@ module Gitlab
# This syncs the data to `internal` from `confidential` as we rename the column.
class BackfillInternalOnNotes < BatchedMigrationJob
scope_to -> (relation) { relation.where(confidential: true) }
+ operation_name :update_all
def perform
- each_sub_batch(operation_name: :update_all) do |sub_batch|
+ each_sub_batch do |sub_batch|
sub_batch.update_all(internal: true)
end
end
diff --git a/lib/gitlab/background_migration/backfill_namespace_details.rb b/lib/gitlab/background_migration/backfill_namespace_details.rb
index b8a51b576b6..640d9379351 100644
--- a/lib/gitlab/background_migration/backfill_namespace_details.rb
+++ b/lib/gitlab/background_migration/backfill_namespace_details.rb
@@ -4,8 +4,10 @@ module Gitlab
module BackgroundMigration
# Backfill namespace_details for a range of namespaces
class BackfillNamespaceDetails < ::Gitlab::BackgroundMigration::BatchedMigrationJob
+ operation_name :backfill_namespace_details
+
def perform
- each_sub_batch(operation_name: :backfill_namespace_details) do |sub_batch|
+ each_sub_batch do |sub_batch|
upsert_namespace_details(sub_batch)
end
end
diff --git a/lib/gitlab/background_migration/backfill_namespace_id_of_vulnerability_reads.rb b/lib/gitlab/background_migration/backfill_namespace_id_of_vulnerability_reads.rb
index cd349bf3ae1..dca7f9fa921 100644
--- a/lib/gitlab/background_migration/backfill_namespace_id_of_vulnerability_reads.rb
+++ b/lib/gitlab/background_migration/backfill_namespace_id_of_vulnerability_reads.rb
@@ -4,6 +4,8 @@ module Gitlab
module BackgroundMigration
# Sets the `namespace_id` of the existing `vulnerability_reads` records
class BackfillNamespaceIdOfVulnerabilityReads < BatchedMigrationJob
+ operation_name :set_namespace_id
+
UPDATE_SQL = <<~SQL
UPDATE
vulnerability_reads
@@ -16,7 +18,7 @@ module Gitlab
SQL
def perform
- each_sub_batch(operation_name: :set_namespace_id) do |sub_batch|
+ each_sub_batch do |sub_batch|
update_query = update_query_for(sub_batch)
connection.execute(update_query)
diff --git a/lib/gitlab/background_migration/backfill_project_feature_package_registry_access_level.rb b/lib/gitlab/background_migration/backfill_project_feature_package_registry_access_level.rb
index ce4c4a28b37..6520cd63711 100644
--- a/lib/gitlab/background_migration/backfill_project_feature_package_registry_access_level.rb
+++ b/lib/gitlab/background_migration/backfill_project_feature_package_registry_access_level.rb
@@ -17,8 +17,10 @@ module Gitlab
self.table_name = 'project_features'
end
+ operation_name :update_all
+
def perform
- each_sub_batch(operation_name: :update_all) do |sub_batch|
+ each_sub_batch do |sub_batch|
ProjectFeature.connection.execute(
<<~SQL
UPDATE project_features pf
diff --git a/lib/gitlab/background_migration/backfill_project_import_level.rb b/lib/gitlab/background_migration/backfill_project_import_level.rb
index 06706b729ea..21c239e0070 100644
--- a/lib/gitlab/background_migration/backfill_project_import_level.rb
+++ b/lib/gitlab/background_migration/backfill_project_import_level.rb
@@ -3,6 +3,8 @@
module Gitlab
module BackgroundMigration
class BackfillProjectImportLevel < BatchedMigrationJob
+ operation_name :update_import_level
+
LEVEL = {
Gitlab::Access::NO_ACCESS => [0],
Gitlab::Access::DEVELOPER => [2],
@@ -11,7 +13,7 @@ module Gitlab
}.freeze
def perform
- each_sub_batch(operation_name: :update_import_level) do |sub_batch|
+ each_sub_batch do |sub_batch|
update_import_level(sub_batch)
end
end
diff --git a/lib/gitlab/background_migration/backfill_project_namespace_details.rb b/lib/gitlab/background_migration/backfill_project_namespace_details.rb
new file mode 100644
index 00000000000..9bee3cf21e8
--- /dev/null
+++ b/lib/gitlab/background_migration/backfill_project_namespace_details.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+module Gitlab
+ module BackgroundMigration
+ # Backfill project namespace_details for a range of projects
+ class BackfillProjectNamespaceDetails < ::Gitlab::BackgroundMigration::BatchedMigrationJob
+ operation_name :backfill_project_namespace_details
+
+ def perform
+ each_sub_batch do |sub_batch|
+ upsert_project_namespace_details(sub_batch)
+ end
+ end
+
+ def upsert_project_namespace_details(relation)
+ connection.execute(
+ <<~SQL
+ INSERT INTO namespace_details (description, description_html, cached_markdown_version, created_at, updated_at, namespace_id)
+ SELECT projects.description, projects.description_html, projects.cached_markdown_version, now(), now(), projects.project_namespace_id
+ FROM projects
+ WHERE projects.id IN(#{relation.select(:id).to_sql})
+ ON CONFLICT (namespace_id) DO NOTHING;
+ SQL
+ )
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/backfill_project_namespace_on_issues.rb b/lib/gitlab/background_migration/backfill_project_namespace_on_issues.rb
index 815c346bb39..34dd3321125 100644
--- a/lib/gitlab/background_migration/backfill_project_namespace_on_issues.rb
+++ b/lib/gitlab/background_migration/backfill_project_namespace_on_issues.rb
@@ -4,21 +4,53 @@ module Gitlab
module BackgroundMigration
# Back-fills the `issues.namespace_id` by setting it to corresponding project.project_namespace_id
class BackfillProjectNamespaceOnIssues < BatchedMigrationJob
+ MAX_UPDATE_RETRIES = 3
+
+ operation_name :update_all
+
def perform
each_sub_batch(
- operation_name: :update_all,
batching_scope: -> (relation) {
relation.joins("INNER JOIN projects ON projects.id = issues.project_id")
.select("issues.id AS issue_id, projects.project_namespace_id").where(issues: { namespace_id: nil })
}
) do |sub_batch|
- connection.execute <<~SQL
+ # updating issues table results in failed batches quite a bit,
+ # to prevent that as much as possible we try to update the same sub-batch up to 3 times.
+ update_with_retry(sub_batch)
+ end
+ end
+
+ private
+
+ # rubocop:disable Database/RescueQueryCanceled
+ # rubocop:disable Database/RescueStatementTimeout
+ def update_with_retry(sub_batch)
+ update_attempt = 1
+
+ begin
+ update_batch(sub_batch)
+ rescue ActiveRecord::StatementTimeout, ActiveRecord::QueryCanceled => e
+ update_attempt += 1
+
+ if update_attempt <= MAX_UPDATE_RETRIES
+ sleep(5)
+ retry
+ end
+
+ raise e
+ end
+ end
+ # rubocop:enable Database/RescueQueryCanceled
+ # rubocop:enable Database/RescueStatementTimeout
+
+ def update_batch(sub_batch)
+ connection.execute <<~SQL
UPDATE issues
SET namespace_id = projects.project_namespace_id
FROM (#{sub_batch.to_sql}) AS projects(issue_id, project_namespace_id)
WHERE issues.id = issue_id
- SQL
- end
+ SQL
end
end
end
diff --git a/lib/gitlab/background_migration/backfill_projects_with_coverage.rb b/lib/gitlab/background_migration/backfill_projects_with_coverage.rb
deleted file mode 100644
index ca262c0bd59..00000000000
--- a/lib/gitlab/background_migration/backfill_projects_with_coverage.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module BackgroundMigration
- # Backfill project_ci_feature_usages for a range of projects with coverage
- class BackfillProjectsWithCoverage
- class ProjectCiFeatureUsage < ActiveRecord::Base # rubocop:disable Style/Documentation
- self.table_name = 'project_ci_feature_usages'
- end
-
- COVERAGE_ENUM_VALUE = 1
- INSERT_DELAY_SECONDS = 0.1
-
- def perform(start_id, end_id, sub_batch_size)
- report_results = ActiveRecord::Base.connection.execute <<~SQL
- SELECT DISTINCT project_id, default_branch
- FROM ci_daily_build_group_report_results
- WHERE id BETWEEN #{start_id} AND #{end_id}
- SQL
-
- report_results.to_a.in_groups_of(sub_batch_size, false) do |batch|
- ProjectCiFeatureUsage.insert_all(build_values(batch))
-
- sleep INSERT_DELAY_SECONDS
- end
- end
-
- private
-
- def build_values(batch)
- batch.map do |data|
- {
- project_id: data['project_id'],
- feature: COVERAGE_ENUM_VALUE,
- default_branch: data['default_branch']
- }
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/background_migration/backfill_user_details_fields.rb b/lib/gitlab/background_migration/backfill_user_details_fields.rb
new file mode 100644
index 00000000000..8d8619256b0
--- /dev/null
+++ b/lib/gitlab/background_migration/backfill_user_details_fields.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Class that will backfill the following fields from user to user_details
+ # * linkedin
+ # * twitter
+ # * skype
+ # * website_url
+ # * location
+ # * organization
+ class BackfillUserDetailsFields < BatchedMigrationJob
+ operation_name :backfill_user_details_fields
+
+ def perform
+ query = <<~SQL
+ (COALESCE(linkedin, '') IS DISTINCT FROM '')
+ OR (COALESCE(twitter, '') IS DISTINCT FROM '')
+ OR (COALESCE(skype, '') IS DISTINCT FROM '')
+ OR (COALESCE(website_url, '') IS DISTINCT FROM '')
+ OR (COALESCE(location, '') IS DISTINCT FROM '')
+ OR (COALESCE(organization, '') IS DISTINCT FROM '')
+ SQL
+ field_limit = UserDetail::DEFAULT_FIELD_LENGTH
+
+ each_sub_batch(
+ batching_scope: ->(relation) {
+ relation.where(query).select(
+ 'id AS user_id',
+ "substring(COALESCE(linkedin, '') from 1 for #{field_limit}) AS linkedin",
+ "substring(COALESCE(twitter, '') from 1 for #{field_limit}) AS twitter",
+ "substring(COALESCE(skype, '') from 1 for #{field_limit}) AS skype",
+ "substring(COALESCE(website_url, '') from 1 for #{field_limit}) AS website_url",
+ "substring(COALESCE(location, '') from 1 for #{field_limit}) AS location",
+ "substring(COALESCE(organization, '') from 1 for #{field_limit}) AS organization"
+ )
+ }
+ ) do |sub_batch|
+ upsert_user_details_fields(sub_batch)
+ end
+ end
+
+ def upsert_user_details_fields(relation)
+ connection.execute(
+ <<~SQL
+ INSERT INTO user_details (user_id, linkedin, twitter, skype, website_url, location, organization)
+ #{relation.to_sql}
+ ON CONFLICT (user_id)
+ DO UPDATE SET
+ "linkedin" = EXCLUDED."linkedin",
+ "twitter" = EXCLUDED."twitter",
+ "skype" = EXCLUDED."skype",
+ "website_url" = EXCLUDED."website_url",
+ "location" = EXCLUDED."location",
+ "organization" = EXCLUDED."organization"
+ SQL
+ )
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/backfill_vulnerability_reads_cluster_agent.rb b/lib/gitlab/background_migration/backfill_vulnerability_reads_cluster_agent.rb
index 0c41d6af209..37b1a37569b 100644
--- a/lib/gitlab/background_migration/backfill_vulnerability_reads_cluster_agent.rb
+++ b/lib/gitlab/background_migration/backfill_vulnerability_reads_cluster_agent.rb
@@ -4,6 +4,8 @@ module Gitlab
module BackgroundMigration
# Backfills the `vulnerability_reads.casted_cluster_agent_id` column
class BackfillVulnerabilityReadsClusterAgent < Gitlab::BackgroundMigration::BatchedMigrationJob
+ operation_name :update_all
+
CLUSTER_AGENTS_JOIN = <<~SQL
INNER JOIN cluster_agents
ON CAST(vulnerability_reads.cluster_agent_id AS bigint) = cluster_agents.id AND
@@ -15,7 +17,7 @@ module Gitlab
scope_to ->(relation) { relation.where(report_type: CLUSTER_IMAGE_SCANNING_REPORT_TYPE) }
def perform
- each_sub_batch(operation_name: :update_all) do |sub_batch|
+ each_sub_batch do |sub_batch|
sub_batch
.joins(CLUSTER_AGENTS_JOIN)
.update_all('casted_cluster_agent_id = CAST(vulnerability_reads.cluster_agent_id AS bigint)')
diff --git a/lib/gitlab/background_migration/backfill_work_item_type_id_for_issues.rb b/lib/gitlab/background_migration/backfill_work_item_type_id_for_issues.rb
index 86d53ad798d..a020cabd1f4 100644
--- a/lib/gitlab/background_migration/backfill_work_item_type_id_for_issues.rb
+++ b/lib/gitlab/background_migration/backfill_work_item_type_id_for_issues.rb
@@ -19,10 +19,10 @@ module Gitlab
}
job_arguments :base_type, :base_type_id
+ operation_name :update_all
def perform
each_sub_batch(
- operation_name: :update_all,
batching_scope: -> (relation) { relation.where(work_item_type_id: nil) }
) do |sub_batch|
first, last = sub_batch.pick(Arel.sql('min(id), max(id)'))
diff --git a/lib/gitlab/background_migration/batched_migration_job.rb b/lib/gitlab/background_migration/batched_migration_job.rb
index 11d15804344..64401bc0674 100644
--- a/lib/gitlab/background_migration/batched_migration_job.rb
+++ b/lib/gitlab/background_migration/batched_migration_job.rb
@@ -36,6 +36,12 @@ module Gitlab
0
end
+ def self.operation_name(operation)
+ define_method('operation_name') do
+ operation
+ end
+ end
+
def self.job_arguments(*args)
args.each.with_index do |arg, index|
define_method(arg) do
@@ -70,7 +76,7 @@ module Gitlab
attr_reader :start_id, :end_id, :batch_table, :batch_column, :sub_batch_size, :pause_ms, :connection
- def each_sub_batch(operation_name: :default, batching_arguments: {}, batching_scope: nil)
+ def each_sub_batch(batching_arguments: {}, batching_scope: nil)
all_batching_arguments = { column: batch_column, of: sub_batch_size }.merge(batching_arguments)
relation = filter_batch(base_relation)
@@ -85,7 +91,7 @@ module Gitlab
end
end
- def distinct_each_batch(operation_name: :default, batching_arguments: {})
+ def distinct_each_batch(batching_arguments: {})
if base_relation != filter_batch(base_relation)
raise 'distinct_each_batch can not be used when additional filters are defined with scope_to'
end
@@ -111,6 +117,10 @@ module Gitlab
batching_scope.call(relation)
end
+
+ def operation_name
+ raise('Operation name is required, please define it with `operation_name`')
+ end
end
end
end
diff --git a/lib/gitlab/background_migration/copy_column_using_background_migration_job.rb b/lib/gitlab/background_migration/copy_column_using_background_migration_job.rb
index 15e54431a44..136293242b2 100644
--- a/lib/gitlab/background_migration/copy_column_using_background_migration_job.rb
+++ b/lib/gitlab/background_migration/copy_column_using_background_migration_job.rb
@@ -15,11 +15,12 @@ module Gitlab
# We use the provided primary_key column to perform the update.
class CopyColumnUsingBackgroundMigrationJob < BatchedMigrationJob
job_arguments :copy_from, :copy_to
+ operation_name :update_all
def perform
assignment_clauses = build_assignment_clauses(copy_from, copy_to)
- each_sub_batch(operation_name: :update_all) do |relation|
+ each_sub_batch do |relation|
relation.update_all(assignment_clauses)
end
end
diff --git a/lib/gitlab/background_migration/delete_orphaned_operational_vulnerabilities.rb b/lib/gitlab/background_migration/delete_orphaned_operational_vulnerabilities.rb
index c3e1019b72f..f93dcf83c49 100644
--- a/lib/gitlab/background_migration/delete_orphaned_operational_vulnerabilities.rb
+++ b/lib/gitlab/background_migration/delete_orphaned_operational_vulnerabilities.rb
@@ -16,13 +16,14 @@ module Gitlab
)
SQL
+ operation_name :delete_orphaned_operational_vulnerabilities
scope_to ->(relation) do
relation
.where(report_type: [REPORT_TYPES[:cluster_image_scanning], REPORT_TYPES[:custom]])
end
def perform
- each_sub_batch(operation_name: :delete_orphaned_operational_vulnerabilities) do |sub_batch|
+ each_sub_batch do |sub_batch|
sub_batch
.where(NOT_EXISTS_SQL)
.delete_all
diff --git a/lib/gitlab/background_migration/destroy_invalid_group_members.rb b/lib/gitlab/background_migration/destroy_invalid_group_members.rb
index 35ac42f76ab..9eb0d4489d6 100644
--- a/lib/gitlab/background_migration/destroy_invalid_group_members.rb
+++ b/lib/gitlab/background_migration/destroy_invalid_group_members.rb
@@ -9,8 +9,10 @@ module Gitlab
.where(namespaces: { id: nil })
end
+ operation_name :delete_all
+
def perform
- each_sub_batch(operation_name: :delete_all) do |sub_batch|
+ each_sub_batch do |sub_batch|
invalid_ids = sub_batch.map(&:id)
Gitlab::AppLogger.info({ message: 'Removing invalid group member records',
deleted_count: invalid_ids.size, ids: invalid_ids })
diff --git a/lib/gitlab/background_migration/destroy_invalid_members.rb b/lib/gitlab/background_migration/destroy_invalid_members.rb
index 7d78795bea9..17a141860ec 100644
--- a/lib/gitlab/background_migration/destroy_invalid_members.rb
+++ b/lib/gitlab/background_migration/destroy_invalid_members.rb
@@ -4,9 +4,10 @@ module Gitlab
module BackgroundMigration
class DestroyInvalidMembers < Gitlab::BackgroundMigration::BatchedMigrationJob # rubocop:disable Style/Documentation
scope_to ->(relation) { relation.where(member_namespace_id: nil) }
+ operation_name :delete_all
def perform
- each_sub_batch(operation_name: :delete_all) do |sub_batch|
+ each_sub_batch do |sub_batch|
deleted_members_data = sub_batch.map do |m|
{ id: m.id, source_id: m.source_id, source_type: m.source_type }
end
diff --git a/lib/gitlab/background_migration/destroy_invalid_project_members.rb b/lib/gitlab/background_migration/destroy_invalid_project_members.rb
index 3c60f765c29..53b4712ef6e 100644
--- a/lib/gitlab/background_migration/destroy_invalid_project_members.rb
+++ b/lib/gitlab/background_migration/destroy_invalid_project_members.rb
@@ -4,9 +4,10 @@ module Gitlab
module BackgroundMigration
class DestroyInvalidProjectMembers < Gitlab::BackgroundMigration::BatchedMigrationJob # rubocop:disable Style/Documentation
scope_to ->(relation) { relation.where(source_type: 'Project') }
+ operation_name :delete_all
def perform
- each_sub_batch(operation_name: :delete_all) do |sub_batch|
+ each_sub_batch do |sub_batch|
invalid_project_members = sub_batch
.joins('LEFT OUTER JOIN projects ON members.source_id = projects.id')
.where(projects: { id: nil })
diff --git a/lib/gitlab/background_migration/disable_legacy_open_source_licence_for_recent_public_projects.rb b/lib/gitlab/background_migration/disable_legacy_open_source_licence_for_recent_public_projects.rb
index 824054b31f2..b32e88581dd 100644
--- a/lib/gitlab/background_migration/disable_legacy_open_source_licence_for_recent_public_projects.rb
+++ b/lib/gitlab/background_migration/disable_legacy_open_source_licence_for_recent_public_projects.rb
@@ -7,6 +7,8 @@ module Gitlab
PUBLIC = 20
THRESHOLD_DATE = '2022-02-17 09:00:00'
+ operation_name :disable_legacy_open_source_licence_for_recent_public_projects
+
# Migration only version of `project_settings` table
class ProjectSetting < ApplicationRecord
self.table_name = 'project_settings'
@@ -14,7 +16,6 @@ module Gitlab
def perform
each_sub_batch(
- operation_name: :disable_legacy_open_source_licence_for_recent_public_projects,
batching_scope: ->(relation) {
relation.where(visibility_level: PUBLIC).where('created_at >= ?', THRESHOLD_DATE)
}
diff --git a/lib/gitlab/background_migration/disable_legacy_open_source_license_for_inactive_public_projects.rb b/lib/gitlab/background_migration/disable_legacy_open_source_license_for_inactive_public_projects.rb
index e759d504f8d..5685b782a71 100644
--- a/lib/gitlab/background_migration/disable_legacy_open_source_license_for_inactive_public_projects.rb
+++ b/lib/gitlab/background_migration/disable_legacy_open_source_license_for_inactive_public_projects.rb
@@ -8,6 +8,8 @@ module Gitlab
PUBLIC = 20
LAST_ACTIVITY_DATE = '2021-07-01'
+ operation_name :disable_legacy_open_source_license_available
+
# Migration only version of `project_settings` table
class ProjectSetting < ApplicationRecord
self.table_name = 'project_settings'
@@ -15,7 +17,6 @@ module Gitlab
def perform
each_sub_batch(
- operation_name: :disable_legacy_open_source_license_available,
batching_scope: ->(relation) {
relation.where(visibility_level: PUBLIC).where('last_activity_at < ?', LAST_ACTIVITY_DATE)
}
diff --git a/lib/gitlab/background_migration/disable_legacy_open_source_license_for_no_issues_no_repo_projects.rb b/lib/gitlab/background_migration/disable_legacy_open_source_license_for_no_issues_no_repo_projects.rb
index 019c3d15b3e..b5e5555bd2d 100644
--- a/lib/gitlab/background_migration/disable_legacy_open_source_license_for_no_issues_no_repo_projects.rb
+++ b/lib/gitlab/background_migration/disable_legacy_open_source_license_for_no_issues_no_repo_projects.rb
@@ -6,6 +6,8 @@ module Gitlab
class DisableLegacyOpenSourceLicenseForNoIssuesNoRepoProjects < ::Gitlab::BackgroundMigration::BatchedMigrationJob
PUBLIC = 20
+ operation_name :disable_legacy_open_source_license_for_no_issues_no_repo_projects
+
# Migration only version of `project_settings` table
class ProjectSetting < ApplicationRecord
self.table_name = 'project_settings'
@@ -13,7 +15,6 @@ module Gitlab
def perform
each_sub_batch(
- operation_name: :disable_legacy_open_source_license_for_no_issues_no_repo_projects,
batching_scope: ->(relation) { relation.where(visibility_level: PUBLIC) }
) do |sub_batch|
no_issues_no_repo_projects =
diff --git a/lib/gitlab/background_migration/disable_legacy_open_source_license_for_one_member_no_repo_projects.rb b/lib/gitlab/background_migration/disable_legacy_open_source_license_for_one_member_no_repo_projects.rb
index 3a9049b1f19..89863458676 100644
--- a/lib/gitlab/background_migration/disable_legacy_open_source_license_for_one_member_no_repo_projects.rb
+++ b/lib/gitlab/background_migration/disable_legacy_open_source_license_for_one_member_no_repo_projects.rb
@@ -6,6 +6,8 @@ module Gitlab
class DisableLegacyOpenSourceLicenseForOneMemberNoRepoProjects < ::Gitlab::BackgroundMigration::BatchedMigrationJob
PUBLIC = 20
+ operation_name :disable_legacy_open_source_license_for_one_member_no_repo_projects
+
# Migration only version of `project_settings` table
class ProjectSetting < ApplicationRecord
self.table_name = 'project_settings'
@@ -13,7 +15,6 @@ module Gitlab
def perform
each_sub_batch(
- operation_name: :disable_legacy_open_source_license_for_one_member_no_repo_projects,
batching_scope: ->(relation) { relation.where(visibility_level: PUBLIC) }
) do |sub_batch|
one_member_no_repo_projects =
diff --git a/lib/gitlab/background_migration/disable_legacy_open_source_license_for_projects_less_than_one_mb.rb b/lib/gitlab/background_migration/disable_legacy_open_source_license_for_projects_less_than_one_mb.rb
index 6e4d5d8ddcb..7d93f2d4fda 100644
--- a/lib/gitlab/background_migration/disable_legacy_open_source_license_for_projects_less_than_one_mb.rb
+++ b/lib/gitlab/background_migration/disable_legacy_open_source_license_for_projects_less_than_one_mb.rb
@@ -5,9 +5,10 @@ module Gitlab
# Set `project_settings.legacy_open_source_license_available` to false for projects less than 1 MB
class DisableLegacyOpenSourceLicenseForProjectsLessThanOneMb < ::Gitlab::BackgroundMigration::BatchedMigrationJob
scope_to ->(relation) { relation.where(legacy_open_source_license_available: true) }
+ operation_name :disable_legacy_open_source_license_for_projects_less_than_one_mb
def perform
- each_sub_batch(operation_name: :disable_legacy_open_source_license_for_projects_less_than_one_mb) do |sub_batch|
+ each_sub_batch do |sub_batch|
updates = { legacy_open_source_license_available: false, updated_at: Time.current }
sub_batch
diff --git a/lib/gitlab/background_migration/encrypt_static_object_token.rb b/lib/gitlab/background_migration/encrypt_static_object_token.rb
index e1805d40bab..961dea028c9 100644
--- a/lib/gitlab/background_migration/encrypt_static_object_token.rb
+++ b/lib/gitlab/background_migration/encrypt_static_object_token.rb
@@ -40,8 +40,9 @@ module Gitlab
encrypted_tokens_sql = user_encrypted_tokens.compact.map { |(id, token)| "(#{id}, '#{token}')" }.join(',')
- if user_encrypted_tokens.present?
- User.connection.execute(<<~SQL)
+ next unless user_encrypted_tokens.present?
+
+ User.connection.execute(<<~SQL)
WITH cte(cte_id, cte_token) AS #{::Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
SELECT *
FROM (VALUES #{encrypted_tokens_sql}) AS t (id, token)
@@ -50,8 +51,7 @@ module Gitlab
SET static_object_token_encrypted = cte_token
FROM cte
WHERE cte_id = id
- SQL
- end
+ SQL
end
mark_job_as_succeeded(start_id, end_id)
diff --git a/lib/gitlab/background_migration/expire_o_auth_tokens.rb b/lib/gitlab/background_migration/expire_o_auth_tokens.rb
index 595e4ac9dc8..08bcdb8a789 100644
--- a/lib/gitlab/background_migration/expire_o_auth_tokens.rb
+++ b/lib/gitlab/background_migration/expire_o_auth_tokens.rb
@@ -4,9 +4,10 @@ module Gitlab
module BackgroundMigration
# Add expiry to all OAuth access tokens
class ExpireOAuthTokens < ::Gitlab::BackgroundMigration::BatchedMigrationJob
+ operation_name :update_oauth_tokens
+
def perform
each_sub_batch(
- operation_name: :update_oauth_tokens,
batching_scope: ->(relation) { relation.where(expires_in: nil) }
) do |sub_batch|
update_oauth_tokens(sub_batch)
diff --git a/lib/gitlab/background_migration/populate_operation_visibility_permissions_from_operations.rb b/lib/gitlab/background_migration/populate_operation_visibility_permissions_from_operations.rb
index 3f04e04fc4d..3dd867fa1fe 100644
--- a/lib/gitlab/background_migration/populate_operation_visibility_permissions_from_operations.rb
+++ b/lib/gitlab/background_migration/populate_operation_visibility_permissions_from_operations.rb
@@ -6,8 +6,10 @@ module Gitlab
# monitor_access_level, deployments_access_level, infrastructure_access_level.
# The operations_access_level setting is being split into three seperate toggles.
class PopulateOperationVisibilityPermissionsFromOperations < BatchedMigrationJob
+ operation_name :populate_operations_visibility
+
def perform
- each_sub_batch(operation_name: :populate_operations_visibility) do |batch|
+ each_sub_batch do |batch|
batch.update_all('monitor_access_level=operations_access_level,' \
'infrastructure_access_level=operations_access_level,' \
' feature_flags_access_level=operations_access_level,'\
diff --git a/lib/gitlab/background_migration/populate_projects_star_count.rb b/lib/gitlab/background_migration/populate_projects_star_count.rb
new file mode 100644
index 00000000000..085d576637e
--- /dev/null
+++ b/lib/gitlab/background_migration/populate_projects_star_count.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # The class to populates the star counter of projects
+ class PopulateProjectsStarCount < BatchedMigrationJob
+ MAX_UPDATE_RETRIES = 3
+
+ operation_name :update_all
+
+ def perform
+ each_sub_batch do |sub_batch|
+ update_with_retry(sub_batch)
+ end
+ end
+
+ private
+
+ # rubocop:disable Database/RescueQueryCanceled
+ # rubocop:disable Database/RescueStatementTimeout
+ def update_with_retry(sub_batch)
+ update_attempt = 1
+
+ begin
+ update_batch(sub_batch)
+ rescue ActiveRecord::StatementTimeout, ActiveRecord::QueryCanceled => e
+ update_attempt += 1
+
+ if update_attempt <= MAX_UPDATE_RETRIES
+ sleep(5)
+ retry
+ end
+
+ raise e
+ end
+ end
+ # rubocop:enable Database/RescueQueryCanceled
+ # rubocop:enable Database/RescueStatementTimeout
+
+ def update_batch(sub_batch)
+ ApplicationRecord.connection.execute <<~SQL
+ WITH batched_relation AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (#{sub_batch.select(:id).to_sql})
+ UPDATE projects
+ SET star_count = (
+ SELECT COUNT(*)
+ FROM users_star_projects
+ INNER JOIN users
+ ON users_star_projects.user_id = users.id
+ WHERE users_star_projects.project_id = batched_relation.id
+ AND users.state = 'active'
+ )
+ FROM batched_relation
+ WHERE projects.id = batched_relation.id
+ SQL
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/recount_epic_cache_counts.rb b/lib/gitlab/background_migration/recount_epic_cache_counts.rb
new file mode 100644
index 00000000000..42f84a33a5a
--- /dev/null
+++ b/lib/gitlab/background_migration/recount_epic_cache_counts.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # rubocop: disable Style/Documentation
+ class RecountEpicCacheCounts < Gitlab::BackgroundMigration::BatchedMigrationJob
+ def perform; end
+ end
+ # rubocop: enable Style/Documentation
+ end
+end
+
+# rubocop: disable Layout/LineLength
+# we just want to re-enqueue the previous BackfillEpicCacheCounts migration,
+# because it's a EE-only migation and it's a module, we just prepend new
+# RecountEpicCacheCounts with existing batched migration module (which is same in both cases)
+Gitlab::BackgroundMigration::RecountEpicCacheCounts.prepend_mod_with('Gitlab::BackgroundMigration::BackfillEpicCacheCounts')
+# rubocop: enable Layout/LineLength
diff --git a/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at.rb b/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at.rb
index d30263976e8..dc7c16d7947 100644
--- a/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at.rb
+++ b/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at.rb
@@ -6,6 +6,8 @@ module Gitlab
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/47723.
# These job artifacts will not be deleted and will have their `expire_at` removed.
class RemoveBackfilledJobArtifactsExpireAt < BatchedMigrationJob
+ operation_name :update_all
+
# The migration would have backfilled `expire_at`
# to midnight on the 22nd of the month of the local timezone,
# storing it as UTC time in the database.
@@ -32,9 +34,7 @@ module Gitlab
}
def perform
- each_sub_batch(
- operation_name: :update_all
- ) do |sub_batch|
+ each_sub_batch do |sub_batch|
sub_batch.update_all(expire_at: nil)
end
end
diff --git a/lib/gitlab/background_migration/remove_self_managed_wiki_notes.rb b/lib/gitlab/background_migration/remove_self_managed_wiki_notes.rb
index 5b1d630bb03..a284c04d4f5 100644
--- a/lib/gitlab/background_migration/remove_self_managed_wiki_notes.rb
+++ b/lib/gitlab/background_migration/remove_self_managed_wiki_notes.rb
@@ -4,10 +4,10 @@ module Gitlab
module BackgroundMigration
# Removes obsolete wiki notes
class RemoveSelfManagedWikiNotes < BatchedMigrationJob
+ operation_name :delete_all
+
def perform
- each_sub_batch(
- operation_name: :delete_all
- ) do |sub_batch|
+ each_sub_batch do |sub_batch|
sub_batch.where(noteable_type: 'Wiki').delete_all
end
end
diff --git a/lib/gitlab/background_migration/rename_task_system_note_to_checklist_item.rb b/lib/gitlab/background_migration/rename_task_system_note_to_checklist_item.rb
index 718fb0aaa71..1b13c2ab7ef 100644
--- a/lib/gitlab/background_migration/rename_task_system_note_to_checklist_item.rb
+++ b/lib/gitlab/background_migration/rename_task_system_note_to_checklist_item.rb
@@ -13,8 +13,10 @@ module Gitlab
relation.where(system_note_metadata: { action: :task })
}
+ operation_name :update_all
+
def perform
- each_sub_batch(operation_name: :update_all) do |sub_batch|
+ each_sub_batch do |sub_batch|
ApplicationRecord.connection.execute <<~SQL
UPDATE notes
SET note = REGEXP_REPLACE(notes.note,'#{REPLACE_REGEX}', '#{TEXT_REPLACEMENT}')
diff --git a/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values.rb b/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values.rb
index 952f3b0e3c3..832385fd662 100644
--- a/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values.rb
+++ b/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values.rb
@@ -4,8 +4,10 @@ module Gitlab
module BackgroundMigration
# A job to nullify duplicate token_encrypted values in ci_runners table in batches
class ResetDuplicateCiRunnersTokenEncryptedValues < BatchedMigrationJob
+ operation_name :nullify_duplicate_ci_runner_token_encrypted_values
+
def perform
- each_sub_batch(operation_name: :nullify_duplicate_ci_runner_token_encrypted_values) do |sub_batch|
+ each_sub_batch do |sub_batch|
# Reset duplicate runner encrypted tokens that would prevent creating an unique index.
nullify_duplicate_ci_runner_token_encrypted_values(sub_batch)
end
diff --git a/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values.rb b/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values.rb
index cfd6a4e4091..5f552accd8d 100644
--- a/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values.rb
+++ b/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values.rb
@@ -4,8 +4,10 @@ module Gitlab
module BackgroundMigration
# A job to nullify duplicate token values in ci_runners table in batches
class ResetDuplicateCiRunnersTokenValues < BatchedMigrationJob
+ operation_name :nullify_duplicate_ci_runner_token_values
+
def perform
- each_sub_batch(operation_name: :nullify_duplicate_ci_runner_token_values) do |sub_batch|
+ each_sub_batch do |sub_batch|
# Reset duplicate runner tokens that would prevent creating an unique index.
nullify_duplicate_ci_runner_token_values(sub_batch)
end
diff --git a/lib/gitlab/background_migration/sanitize_confidential_todos.rb b/lib/gitlab/background_migration/sanitize_confidential_todos.rb
new file mode 100644
index 00000000000..d3ef6ac3019
--- /dev/null
+++ b/lib/gitlab/background_migration/sanitize_confidential_todos.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module BackgroundMigration
+ # Iterates through confidential notes and removes any its todos if user can
+ # not read the note
+ #
+ # Warning: This migration is not properly isolated. The reason for this is
+ # that we need to check permission for notes and it would be difficult
+ # to extract all related logic.
+ # Details in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/87908#note_952459215
+ class SanitizeConfidentialTodos < BatchedMigrationJob
+ scope_to ->(relation) { relation.where(confidential: true) }
+
+ operation_name :delete_invalid_todos
+
+ def perform
+ each_sub_batch do |sub_batch|
+ delete_ids = invalid_todo_ids(sub_batch)
+
+ Todo.where(id: delete_ids).delete_all if delete_ids.present?
+ end
+ end
+
+ private
+
+ def invalid_todo_ids(notes_batch)
+ todos = Todo.where(note_id: notes_batch.select(:id)).includes(:note, :user)
+
+ todos.each_with_object([]) do |todo, ids|
+ ids << todo.id if invalid_todo?(todo)
+ end
+ end
+
+ def invalid_todo?(todo)
+ return false unless todo.note
+ return false if Ability.allowed?(todo.user, :read_todo, todo)
+
+ logger.info(
+ message: "#{self.class.name} deleting invalid todo",
+ attributes: todo.attributes
+ )
+
+ true
+ end
+
+ def logger
+ @logger ||= Gitlab::BackgroundMigration::Logger.build
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/set_correct_vulnerability_state.rb b/lib/gitlab/background_migration/set_correct_vulnerability_state.rb
index a0cfeed618a..dfd71bb8b5f 100644
--- a/lib/gitlab/background_migration/set_correct_vulnerability_state.rb
+++ b/lib/gitlab/background_migration/set_correct_vulnerability_state.rb
@@ -7,9 +7,10 @@ module Gitlab
DISMISSED_STATE = 2
scope_to ->(relation) { relation.where.not(dismissed_at: nil) }
+ operation_name :update_vulnerabilities_state
def perform
- each_sub_batch(operation_name: :update_vulnerabilities_state) do |sub_batch|
+ each_sub_batch do |sub_batch|
sub_batch.update_all(state: DISMISSED_STATE)
end
end
diff --git a/lib/gitlab/background_migration/set_legacy_open_source_license_available_for_non_public_projects.rb b/lib/gitlab/background_migration/set_legacy_open_source_license_available_for_non_public_projects.rb
index e85b1bc402a..4ae7ad897cf 100644
--- a/lib/gitlab/background_migration/set_legacy_open_source_license_available_for_non_public_projects.rb
+++ b/lib/gitlab/background_migration/set_legacy_open_source_license_available_for_non_public_projects.rb
@@ -6,6 +6,8 @@ module Gitlab
class SetLegacyOpenSourceLicenseAvailableForNonPublicProjects < ::Gitlab::BackgroundMigration::BatchedMigrationJob
PUBLIC = 20
+ operation_name :set_legacy_open_source_license_available
+
# Migration only version of `project_settings` table
class ProjectSetting < ApplicationRecord
self.table_name = 'project_settings'
@@ -13,7 +15,6 @@ module Gitlab
def perform
each_sub_batch(
- operation_name: :set_legacy_open_source_license_available,
batching_scope: ->(relation) { relation.where.not(visibility_level: PUBLIC) }
) do |sub_batch|
ProjectSetting.where(project_id: sub_batch).update_all(legacy_open_source_license_available: false)
diff --git a/lib/gitlab/background_migration/update_delayed_project_removal_to_null_for_user_namespaces.rb b/lib/gitlab/background_migration/update_delayed_project_removal_to_null_for_user_namespaces.rb
index 04a2ceebef8..b2cf8298e4f 100644
--- a/lib/gitlab/background_migration/update_delayed_project_removal_to_null_for_user_namespaces.rb
+++ b/lib/gitlab/background_migration/update_delayed_project_removal_to_null_for_user_namespaces.rb
@@ -10,10 +10,10 @@ module Gitlab
self.table_name = 'namespace_settings'
end
+ operation_name :set_delayed_project_removal_to_null_for_user_namespace
+
def perform
- each_sub_batch(
- operation_name: :set_delayed_project_removal_to_null_for_user_namespace
- ) do |sub_batch|
+ each_sub_batch do |sub_batch|
set_delayed_project_removal_to_null_for_user_namespace(sub_batch)
end
end
diff --git a/lib/gitlab/cache/ci/project_pipeline_status.rb b/lib/gitlab/cache/ci/project_pipeline_status.rb
index 9209c9b4927..b2630a7ad7a 100644
--- a/lib/gitlab/cache/ci/project_pipeline_status.rb
+++ b/lib/gitlab/cache/ci/project_pipeline_status.rb
@@ -85,7 +85,7 @@ module Gitlab
end
def load_from_cache
- Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
self.sha, self.status, self.ref = redis.hmget(cache_key, :sha, :status, :ref)
self.status = nil if self.status.empty?
@@ -93,13 +93,13 @@ module Gitlab
end
def store_in_cache
- Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.mapped_hmset(cache_key, { sha: sha, status: status, ref: ref })
end
end
def delete_from_cache
- Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.del(cache_key)
end
end
@@ -107,7 +107,7 @@ module Gitlab
def has_cache?
return self.loaded unless self.loaded.nil?
- Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.exists?(cache_key) # rubocop:disable CodeReuse/ActiveRecord
end
end
@@ -125,6 +125,10 @@ module Gitlab
project.commit
end
end
+
+ def with_redis(&block)
+ Gitlab::Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord
+ end
end
end
end
diff --git a/lib/gitlab/cache/import/caching.rb b/lib/gitlab/cache/import/caching.rb
index 4e7a7f326a5..7fec6584ba3 100644
--- a/lib/gitlab/cache/import/caching.rb
+++ b/lib/gitlab/cache/import/caching.rb
@@ -33,7 +33,7 @@ module Gitlab
# timeout - The new timeout of the key if the key is to be refreshed.
def self.read(raw_key, timeout: TIMEOUT)
key = cache_key_for(raw_key)
- value = Redis::Cache.with { |redis| redis.get(key) }
+ value = with_redis { |redis| redis.get(key) }
if value.present?
# We refresh the expiration time so frequently used keys stick
@@ -44,7 +44,7 @@ module Gitlab
# did not find a matching GitLab user. In that case we _don't_ want to
# refresh the TTL so we automatically pick up the right data when said
# user were to register themselves on the GitLab instance.
- Redis::Cache.with { |redis| redis.expire(key, timeout) }
+ with_redis { |redis| redis.expire(key, timeout) }
end
value
@@ -69,7 +69,7 @@ module Gitlab
key = cache_key_for(raw_key)
- Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.set(key, value, ex: timeout)
end
@@ -85,7 +85,7 @@ module Gitlab
def self.increment(raw_key, timeout: TIMEOUT)
key = cache_key_for(raw_key)
- Redis::Cache.with do |redis|
+ with_redis do |redis|
value = redis.incr(key)
redis.expire(key, timeout)
@@ -105,7 +105,7 @@ module Gitlab
key = cache_key_for(raw_key)
- Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.incrby(key, value)
redis.expire(key, timeout)
end
@@ -121,9 +121,9 @@ module Gitlab
key = cache_key_for(raw_key)
- Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.multi do |m|
- m.sadd(key, value)
+ m.sadd?(key, value)
m.expire(key, timeout)
end
end
@@ -149,7 +149,7 @@ module Gitlab
def self.values_from_set(raw_key)
key = cache_key_for(raw_key)
- Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.smembers(key)
end
end
@@ -160,14 +160,16 @@ module Gitlab
# key_prefix - prefix inserted before each key
# timeout - The time after which the cache key should expire.
def self.write_multiple(mapping, key_prefix: nil, timeout: TIMEOUT)
- Redis::Cache.with do |redis|
- redis.pipelined do |multi|
- mapping.each do |raw_key, value|
- key = cache_key_for("#{key_prefix}#{raw_key}")
+ with_redis do |redis|
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ redis.pipelined do |multi|
+ mapping.each do |raw_key, value|
+ key = cache_key_for("#{key_prefix}#{raw_key}")
- validate_redis_value!(value)
+ validate_redis_value!(value)
- multi.set(key, value, ex: timeout)
+ multi.set(key, value, ex: timeout)
+ end
end
end
end
@@ -180,7 +182,7 @@ module Gitlab
def self.expire(raw_key, timeout)
key = cache_key_for(raw_key)
- Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.expire(key, timeout)
end
end
@@ -199,7 +201,7 @@ module Gitlab
validate_redis_value!(value)
key = cache_key_for(raw_key)
- val = Redis::Cache.with do |redis|
+ val = with_redis do |redis|
redis
.eval(WRITE_IF_GREATER_SCRIPT, keys: [key], argv: [value, timeout])
end
@@ -218,7 +220,7 @@ module Gitlab
key = cache_key_for(raw_key)
- Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.multi do |m|
m.hset(key, field, value)
m.expire(key, timeout)
@@ -232,7 +234,7 @@ module Gitlab
def self.values_from_hash(raw_key)
key = cache_key_for(raw_key)
- Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.hgetall(key)
end
end
@@ -241,6 +243,10 @@ module Gitlab
"#{Redis::Cache::CACHE_NAMESPACE}:#{raw_key}"
end
+ def self.with_redis(&block)
+ Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord
+ end
+
def self.validate_redis_value!(value)
value_as_string = value.to_s
return if value_as_string.is_a?(String)
diff --git a/lib/gitlab/cache/metrics.rb b/lib/gitlab/cache/metrics.rb
new file mode 100644
index 00000000000..0143052beb1
--- /dev/null
+++ b/lib/gitlab/cache/metrics.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+# Instrumentation for cache efficiency metrics
+module Gitlab
+ module Cache
+ class Metrics
+ DEFAULT_BUCKETS = [0, 1, 5].freeze
+ VALID_BACKING_RESOURCES = [:cpu, :database, :gitaly, :memory, :unknown].freeze
+ DEFAULT_BACKING_RESOURCE = :unknown
+
+ def initialize(
+ caller_id:,
+ cache_identifier:,
+ feature_category: ::Gitlab::FeatureCategories::FEATURE_CATEGORY_DEFAULT,
+ backing_resource: DEFAULT_BACKING_RESOURCE
+ )
+ @caller_id = caller_id
+ @cache_identifier = cache_identifier
+ @feature_category = Gitlab::FeatureCategories.default.get!(feature_category)
+ @backing_resource = fetch_backing_resource!(backing_resource)
+ end
+
+ # Increase cache hit counter
+ #
+ def increment_cache_hit
+ counter.increment(labels.merge(cache_hit: true))
+ end
+
+ # Increase cache miss counter
+ #
+ def increment_cache_miss
+ counter.increment(labels.merge(cache_hit: false))
+ end
+
+ # Measure the duration of cacheable action
+ #
+ # @example
+ # observe_cache_generation do
+ # cacheable_action
+ # end
+ #
+ def observe_cache_generation(&block)
+ real_start = Gitlab::Metrics::System.monotonic_time
+
+ value = yield
+
+ histogram.observe({}, Gitlab::Metrics::System.monotonic_time - real_start)
+
+ value
+ end
+
+ private
+
+ attr_reader :caller_id, :cache_identifier, :feature_category, :backing_resource
+
+ def counter
+ @counter ||= Gitlab::Metrics.counter(:redis_hit_miss_operations_total, "Hit/miss Redis cache counter")
+ end
+
+ def histogram
+ @histogram ||= Gitlab::Metrics.histogram(
+ :redis_cache_generation_duration_seconds,
+ 'Duration of Redis cache generation',
+ labels,
+ DEFAULT_BUCKETS
+ )
+ end
+
+ def labels
+ @labels ||= {
+ caller_id: caller_id,
+ cache_identifier: cache_identifier,
+ feature_category: feature_category,
+ backing_resource: backing_resource
+ }
+ end
+
+ def fetch_backing_resource!(resource)
+ return resource if VALID_BACKING_RESOURCES.include?(resource)
+
+ raise "Unknown backing resource: #{resource}" if Gitlab.dev_or_test_env?
+
+ DEFAULT_BACKING_RESOURCE
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/ansi2html.rb b/lib/gitlab/ci/ansi2html.rb
index 2ab702aa4f9..19819ff7275 100644
--- a/lib/gitlab/ci/ansi2html.rb
+++ b/lib/gitlab/ci/ansi2html.rb
@@ -312,9 +312,10 @@ module Gitlab
normalized_section = section_to_class_name(section)
- if action == "start"
+ case action
+ when "start"
handle_section_start(normalized_section, timestamp)
- elsif action == "end"
+ when "end"
handle_section_end(normalized_section, timestamp)
end
end
diff --git a/lib/gitlab/ci/ansi2json/converter.rb b/lib/gitlab/ci/ansi2json/converter.rb
index ddf40296809..78f6c5bf0aa 100644
--- a/lib/gitlab/ci/ansi2json/converter.rb
+++ b/lib/gitlab/ci/ansi2json/converter.rb
@@ -107,9 +107,10 @@ module Gitlab
section_name = sanitize_section_name(section)
- if action == 'start'
+ case action
+ when 'start'
handle_section_start(scanner, section_name, timestamp, options)
- elsif action == 'end'
+ when 'end'
handle_section_end(scanner, section_name, timestamp)
else
raise 'unsupported action'
diff --git a/lib/gitlab/ci/build/image.rb b/lib/gitlab/ci/build/image.rb
index 7dc375e05eb..84f8eae8deb 100644
--- a/lib/gitlab/ci/build/image.rb
+++ b/lib/gitlab/ci/build/image.rb
@@ -24,10 +24,11 @@ module Gitlab
end
def initialize(image)
- if image.is_a?(String)
+ case image
+ when String
@name = image
@ports = []
- elsif image.is_a?(Hash)
+ when Hash
@alias = image[:alias]
@command = image[:command]
@entrypoint = image[:entrypoint]
diff --git a/lib/gitlab/ci/build/rules/rule/clause/exists.rb b/lib/gitlab/ci/build/rules/rule/clause/exists.rb
index aebd81e7b07..c55615bb83b 100644
--- a/lib/gitlab/ci/build/rules/rule/clause/exists.rb
+++ b/lib/gitlab/ci/build/rules/rule/clause/exists.rb
@@ -9,20 +9,30 @@ module Gitlab
MAX_PATTERN_COMPARISONS = 10_000
def initialize(globs)
- globs = Array(globs)
-
- @top_level_only = globs.all?(&method(:top_level_glob?))
- @exact_globs, @pattern_globs = globs.partition(&method(:exact_glob?))
+ @globs = Array(globs)
+ @top_level_only = @globs.all?(&method(:top_level_glob?))
end
def satisfied_by?(_pipeline, context)
paths = worktree_paths(context)
+ exact_globs, pattern_globs = separate_globs(context)
- exact_matches?(paths) || pattern_matches?(paths)
+ exact_matches?(paths, exact_globs) || pattern_matches?(paths, pattern_globs)
end
private
+ def separate_globs(context)
+ expanded_globs = expand_globs(context)
+ expanded_globs.partition(&method(:exact_glob?))
+ end
+
+ def expand_globs(context)
+ @globs.map do |glob|
+ ExpandVariables.expand_existing(glob, -> { context.variables_hash })
+ end
+ end
+
def worktree_paths(context)
return [] unless context.project
@@ -33,13 +43,16 @@ module Gitlab
end
end
- def exact_matches?(paths)
- @exact_globs.any? { |glob| paths.bsearch { |path| glob <=> path } }
+ def exact_matches?(paths, exact_globs)
+ exact_globs.any? do |glob|
+ paths.bsearch { |path| glob <=> path }
+ end
end
- def pattern_matches?(paths)
+ def pattern_matches?(paths, pattern_globs)
comparisons = 0
- @pattern_globs.any? do |glob|
+
+ pattern_globs.any? do |glob|
paths.any? do |path|
comparisons += 1
comparisons > MAX_PATTERN_COMPARISONS || pattern_match?(glob, path)
diff --git a/lib/gitlab/ci/config.rb b/lib/gitlab/ci/config.rb
index 661c6fb87e3..ee537f4efe5 100644
--- a/lib/gitlab/ci/config.rb
+++ b/lib/gitlab/ci/config.rb
@@ -73,6 +73,10 @@ module Gitlab
root.variables_entry.value_with_data
end
+ def variables_with_prefill_data
+ root.variables_entry.value_with_prefill_data
+ end
+
def stages
root.stages_value
end
diff --git a/lib/gitlab/ci/config/entry/bridge.rb b/lib/gitlab/ci/config/entry/bridge.rb
index 73742298628..ee99354cb28 100644
--- a/lib/gitlab/ci/config/entry/bridge.rb
+++ b/lib/gitlab/ci/config/entry/bridge.rb
@@ -18,7 +18,7 @@ module Gitlab
validates :config, allowed_keys: ALLOWED_KEYS + PROCESSABLE_ALLOWED_KEYS
with_options allow_nil: true do
- validates :when, inclusion: {
+ validates :when, type: String, inclusion: {
in: ALLOWED_WHEN,
message: "should be one of: #{ALLOWED_WHEN.join(', ')}"
}
diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb
index 7513936a18a..8e7f6ba4326 100644
--- a/lib/gitlab/ci/config/entry/job.rb
+++ b/lib/gitlab/ci/config/entry/job.rb
@@ -21,7 +21,7 @@ module Gitlab
validates :script, presence: true
with_options allow_nil: true do
- validates :when, inclusion: {
+ validates :when, type: String, inclusion: {
in: ALLOWED_WHEN,
message: "should be one of: #{ALLOWED_WHEN.join(', ')}"
}
diff --git a/lib/gitlab/ci/config/entry/processable.rb b/lib/gitlab/ci/config/entry/processable.rb
index 2d2032b1d8c..e0a052ffdfd 100644
--- a/lib/gitlab/ci/config/entry/processable.rb
+++ b/lib/gitlab/ci/config/entry/processable.rb
@@ -60,6 +60,7 @@ module Gitlab
entry :variables, ::Gitlab::Ci::Config::Entry::Variables,
description: 'Environment variables available for this job.',
+ metadata: { allowed_value_data: %i[value expand] },
inherit: false
entry :inherit, ::Gitlab::Ci::Config::Entry::Inherit,
diff --git a/lib/gitlab/ci/config/entry/root.rb b/lib/gitlab/ci/config/entry/root.rb
index 1d7d8617c74..a30e6a0d9c3 100644
--- a/lib/gitlab/ci/config/entry/root.rb
+++ b/lib/gitlab/ci/config/entry/root.rb
@@ -50,7 +50,7 @@ module Gitlab
entry :variables, Entry::Variables,
description: 'Environment variables that will be used.',
- metadata: { allowed_value_data: %i[value description], allow_array_value: true },
+ metadata: { allowed_value_data: %i[value description expand], allow_array_value: true },
reserved: true
entry :stages, Entry::Stages,
diff --git a/lib/gitlab/ci/config/entry/variable.rb b/lib/gitlab/ci/config/entry/variable.rb
index 54c153c8b07..16091758916 100644
--- a/lib/gitlab/ci/config/entry/variable.rb
+++ b/lib/gitlab/ci/config/entry/variable.rb
@@ -33,6 +33,10 @@ module Gitlab
def value_with_data
{ value: @config.to_s }
end
+
+ def value_with_prefill_data
+ value_with_data
+ end
end
class ComplexVariable < ::Gitlab::Config::Entry::Node
@@ -48,6 +52,9 @@ module Gitlab
validates :key, alphanumeric: true
validates :config_value, alphanumeric: true, allow_nil: false, if: :config_value_defined?
validates :config_description, alphanumeric: true, allow_nil: false, if: :config_description_defined?
+ validates :config_expand, boolean: true,
+ allow_nil: false,
+ if: -> { ci_raw_variables_in_yaml_config_enabled? && config_expand_defined? }
validate do
allowed_value_data = Array(opt(:allowed_value_data))
@@ -67,7 +74,22 @@ module Gitlab
end
def value_with_data
- { value: value, description: config_description }.compact
+ if ci_raw_variables_in_yaml_config_enabled?
+ {
+ value: value,
+ raw: (!config_expand if config_expand_defined?)
+ }.compact
+ else
+ {
+ value: value
+ }.compact
+ end
+ end
+
+ def value_with_prefill_data
+ value_with_data.merge(
+ description: config_description
+ ).compact
end
def config_value
@@ -78,6 +100,10 @@ module Gitlab
@config[:description]
end
+ def config_expand
+ @config[:expand]
+ end
+
def config_value_defined?
config.key?(:value)
end
@@ -85,6 +111,14 @@ module Gitlab
def config_description_defined?
config.key?(:description)
end
+
+ def config_expand_defined?
+ config.key?(:expand)
+ end
+
+ def ci_raw_variables_in_yaml_config_enabled?
+ YamlProcessor::FeatureFlags.enabled?(:ci_raw_variables_in_yaml_config)
+ end
end
class ComplexArrayVariable < ComplexVariable
@@ -110,8 +144,10 @@ module Gitlab
config_value.first
end
- def value_with_data
- super.merge(value_options: config_value).compact
+ def value_with_prefill_data
+ super.merge(
+ value_options: config_value
+ ).compact
end
end
diff --git a/lib/gitlab/ci/config/entry/variables.rb b/lib/gitlab/ci/config/entry/variables.rb
index 4430a11dda7..ef4f74b9f56 100644
--- a/lib/gitlab/ci/config/entry/variables.rb
+++ b/lib/gitlab/ci/config/entry/variables.rb
@@ -29,6 +29,12 @@ module Gitlab
end
end
+ def value_with_prefill_data
+ @entries.to_h do |key, entry|
+ [key.to_s, entry.value_with_prefill_data]
+ end
+ end
+
private
def composable_class(_name, _config)
diff --git a/lib/gitlab/ci/config/external/file/artifact.rb b/lib/gitlab/ci/config/external/file/artifact.rb
index 1244c7f7475..21a57640aee 100644
--- a/lib/gitlab/ci/config/external/file/artifact.rb
+++ b/lib/gitlab/ci/config/external/file/artifact.rb
@@ -42,29 +42,20 @@ module Gitlab
context&.parent_pipeline&.project
end
- def validate_content!
- return unless ensure_preconditions_satisfied!
-
- errors.push("File `#{masked_location}` is empty!") unless content.present?
- end
-
- def ensure_preconditions_satisfied!
- unless creating_child_pipeline?
- errors.push('Including configs from artifacts is only allowed when triggering child pipelines')
- return false
- end
-
- unless job_name.present?
- errors.push("Job must be provided when including configs from artifacts")
- return false
- end
-
- unless artifact_job.present?
- errors.push("Job `#{masked_job_name}` not found in parent pipeline or does not have artifacts!")
- return false
+ def validate_context!
+ context.logger.instrument(:config_file_artifact_validate_context) do
+ if !creating_child_pipeline?
+ errors.push('Including configs from artifacts is only allowed when triggering child pipelines')
+ elsif !job_name.present?
+ errors.push("Job must be provided when including configs from artifacts")
+ elsif !artifact_job.present?
+ errors.push("Job `#{masked_job_name}` not found in parent pipeline or does not have artifacts!")
+ end
end
+ end
- true
+ def validate_content!
+ errors.push("File `#{masked_location}` is empty!") unless content.present?
end
def artifact_job
diff --git a/lib/gitlab/ci/config/external/file/base.rb b/lib/gitlab/ci/config/external/file/base.rb
index 89da0796906..57ff606c9ee 100644
--- a/lib/gitlab/ci/config/external/file/base.rb
+++ b/lib/gitlab/ci/config/external/file/base.rb
@@ -47,12 +47,11 @@ module Gitlab
end
def validate!
- context.logger.instrument(:config_file_validation) do
- validate_execution_time!
- validate_location!
- validate_content! if errors.none?
- validate_hash! if errors.none?
- end
+ validate_execution_time!
+ validate_location!
+ validate_context! if valid?
+ fetch_and_validate_content! if valid?
+ load_and_validate_expanded_hash! if valid?
end
def metadata
@@ -100,6 +99,34 @@ module Gitlab
end
end
+ def validate_context!
+ raise NotImplementedError, 'subclass must implement validate_context'
+ end
+
+ def fetch_and_validate_content!
+ context.logger.instrument(:config_file_fetch_content) do
+ content # calling the method fetches then memoizes the result
+ end
+
+ return if errors.any?
+
+ context.logger.instrument(:config_file_validate_content) do
+ validate_content!
+ end
+ end
+
+ def load_and_validate_expanded_hash!
+ context.logger.instrument(:config_file_fetch_content_hash) do
+ content_hash # calling the method loads then memoizes the result
+ end
+
+ context.logger.instrument(:config_file_expand_content_includes) do
+ expanded_content_hash # calling the method expands then memoizes the result
+ end
+
+ validate_hash!
+ end
+
def validate_content!
if content.blank?
errors.push("Included file `#{masked_location}` is empty or does not exist!")
diff --git a/lib/gitlab/ci/config/external/file/local.rb b/lib/gitlab/ci/config/external/file/local.rb
index 36fc5c656fc..0912a732158 100644
--- a/lib/gitlab/ci/config/external/file/local.rb
+++ b/lib/gitlab/ci/config/external/file/local.rb
@@ -31,10 +31,14 @@ module Gitlab
private
+ def validate_context!
+ return if context.project&.repository
+
+ errors.push("Local file `#{masked_location}` does not have project!")
+ end
+
def validate_content!
- if context.project&.repository.nil?
- errors.push("Local file `#{masked_location}` does not have project!")
- elsif content.nil?
+ if content.nil?
errors.push("Local file `#{masked_location}` does not exist!")
elsif content.blank?
errors.push("Local file `#{masked_location}` is empty!")
diff --git a/lib/gitlab/ci/config/external/file/project.rb b/lib/gitlab/ci/config/external/file/project.rb
index 89418bd6a21..553cbd819ad 100644
--- a/lib/gitlab/ci/config/external/file/project.rb
+++ b/lib/gitlab/ci/config/external/file/project.rb
@@ -39,12 +39,16 @@ module Gitlab
private
- def validate_content!
+ 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.")
elsif sha.nil?
errors.push("Project `#{masked_project_name}` reference `#{masked_ref_name}` does not exist!")
- elsif content.nil?
+ end
+ end
+
+ def validate_content!
+ if content.nil?
errors.push("Project `#{masked_project_name}` file `#{masked_location}` does not exist!")
elsif content.blank?
errors.push("Project `#{masked_project_name}` file `#{masked_location}` is empty!")
@@ -58,7 +62,11 @@ module Gitlab
end
def can_access_local_content?
- Ability.allowed?(context.user, :download_code, project)
+ strong_memoize(: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 fetch_local_content
diff --git a/lib/gitlab/ci/config/external/file/remote.rb b/lib/gitlab/ci/config/external/file/remote.rb
index 3984bf9e4f8..b0c540685d4 100644
--- a/lib/gitlab/ci/config/external/file/remote.rb
+++ b/lib/gitlab/ci/config/external/file/remote.rb
@@ -30,6 +30,10 @@ module Gitlab
private
+ def validate_context!
+ # no-op
+ end
+
def validate_location!
super
diff --git a/lib/gitlab/ci/config/external/file/template.rb b/lib/gitlab/ci/config/external/file/template.rb
index 5fcf7c71bdf..53236cb317b 100644
--- a/lib/gitlab/ci/config/external/file/template.rb
+++ b/lib/gitlab/ci/config/external/file/template.rb
@@ -33,6 +33,10 @@ module Gitlab
private
+ def validate_context!
+ # no-op
+ end
+
def validate_location!
super
diff --git a/lib/gitlab/ci/config/external/mapper.rb b/lib/gitlab/ci/config/external/mapper.rb
index 2a1060a6059..fc03ac125fd 100644
--- a/lib/gitlab/ci/config/external/mapper.rb
+++ b/lib/gitlab/ci/config/external/mapper.rb
@@ -8,13 +8,15 @@ module Gitlab
include Gitlab::Utils::StrongMemoize
FILE_CLASSES = [
- External::File::Remote,
- External::File::Template,
External::File::Local,
External::File::Project,
+ External::File::Remote,
+ External::File::Template,
External::File::Artifact
].freeze
+ FILE_SUBKEYS = FILE_CLASSES.map { |f| f.name.demodulize.downcase }.freeze
+
Error = Class.new(StandardError)
AmbigiousSpecificationError = Class.new(Error)
TooManyIncludesError = Class.new(Error)
@@ -120,9 +122,13 @@ module Gitlab
file_class.new(location, context)
end.select(&:matching?)
- raise AmbigiousSpecificationError, "Include `#{masked_location(location.to_json)}` needs to match exactly one accessor!" unless matching.one?
-
- matching.first
+ if matching.one?
+ matching.first
+ elsif matching.empty?
+ raise AmbigiousSpecificationError, "`#{masked_location(location.to_json)}` does not have a valid subkey for include. Valid subkeys are: `#{FILE_SUBKEYS.join('`, `')}`"
+ else
+ raise AmbigiousSpecificationError, "Each include must use only one of: `#{FILE_SUBKEYS.join('`, `')}`"
+ end
end
def verify!(location_object)
diff --git a/lib/gitlab/ci/parsers/codequality/code_climate.rb b/lib/gitlab/ci/parsers/codequality/code_climate.rb
index 628d50b84cb..14ea907edd8 100644
--- a/lib/gitlab/ci/parsers/codequality/code_climate.rb
+++ b/lib/gitlab/ci/parsers/codequality/code_climate.rb
@@ -5,23 +5,36 @@ module Gitlab
module Parsers
module Codequality
class CodeClimate
- def parse!(json_data, codequality_report)
+ def parse!(json_data, codequality_report, metadata = {})
root = Gitlab::Json.parse(json_data)
- parse_all(root, codequality_report)
+ parse_all(root, codequality_report, metadata)
rescue JSON::ParserError => e
codequality_report.set_error_message("JSON parsing failed: #{e}")
end
private
- def parse_all(root, codequality_report)
+ def parse_all(root, codequality_report, metadata)
return unless root.present?
root.each do |degradation|
- break unless codequality_report.add_degradation(degradation)
+ break unless codequality_report.valid_degradation?(degradation)
+
+ degradation['web_url'] = web_url(degradation, metadata)
+ codequality_report.add_degradation(degradation)
end
end
+
+ def web_url(degradation, metadata)
+ return unless metadata[:project].present? && metadata[:commit_sha].present?
+
+ path = degradation.dig('location', 'path')
+ line = degradation.dig('location', 'lines', 'begin') ||
+ degradation.dig('location', 'positions', 'begin', 'line')
+ "#{Routing.url_helpers.project_blob_url(
+ metadata[:project], File.join(metadata[:commit_sha], path))}#L#{line}"
+ end
end
end
end
diff --git a/lib/gitlab/ci/parsers/coverage/sax_document.rb b/lib/gitlab/ci/parsers/coverage/sax_document.rb
index 27cce0e3a3b..ddd9c80f5ea 100644
--- a/lib/gitlab/ci/parsers/coverage/sax_document.rb
+++ b/lib/gitlab/ci/parsers/coverage/sax_document.rb
@@ -76,7 +76,12 @@ module Gitlab
# | /builds/foo/test/something | something |
# | /builds/foo/test/ | nil |
# | /builds/foo/test | nil |
- node.split("#{project_path}/", 2)[1]
+ # | D:\builds\foo\bar\app\ | app\ |
+ unixify(node).split("#{project_path}/", 2)[1]
+ end
+
+ def unixify(path)
+ path.tr('\\', '/')
end
def remove_matched_filenames
diff --git a/lib/gitlab/ci/parsers/sbom/cyclonedx.rb b/lib/gitlab/ci/parsers/sbom/cyclonedx.rb
index aa594ca4049..bc62fbe55ec 100644
--- a/lib/gitlab/ci/parsers/sbom/cyclonedx.rb
+++ b/lib/gitlab/ci/parsers/sbom/cyclonedx.rb
@@ -61,23 +61,19 @@ module Gitlab
end
def parse_components
- data['components']&.each do |component_data|
- type = component_data['type']
- next unless supported_component_type?(type)
-
+ data['components']&.each_with_index do |component_data, index|
component = ::Gitlab::Ci::Reports::Sbom::Component.new(
- type: type,
+ type: component_data['type'],
name: component_data['name'],
+ purl: component_data['purl'],
version: component_data['version']
)
- report.add_component(component)
+ report.add_component(component) if component.ingestible?
+ rescue ::Sbom::PackageUrl::InvalidPackageUrl
+ report.add_error("/components/#{index}/purl is invalid")
end
end
-
- def supported_component_type?(type)
- ::Enums::Sbom.component_types.include?(type.to_sym)
- end
end
end
end
diff --git a/lib/gitlab/ci/parsers/security/common.rb b/lib/gitlab/ci/parsers/security/common.rb
index 0c117d5f214..0ac012b9fd1 100644
--- a/lib/gitlab/ci/parsers/security/common.rb
+++ b/lib/gitlab/ci/parsers/security/common.rb
@@ -41,7 +41,7 @@ module Gitlab
private
- attr_reader :json_data, :report, :validate
+ attr_reader :json_data, :report, :validate, :project
def valid?
return true unless validate
@@ -157,13 +157,7 @@ module Gitlab
signature_value: value
)
- if signature.valid?
- signature
- else
- e = SecurityReportParserError.new("Vulnerability tracking signature is not valid: #{signature}")
- Gitlab::ErrorTracking.track_exception(e)
- nil
- end
+ signature if signature.valid?
end.compact
end
diff --git a/lib/gitlab/ci/parsers/security/validators/schema_validator.rb b/lib/gitlab/ci/parsers/security/validators/schema_validator.rb
index 627a1f58715..ab5203252a2 100644
--- a/lib/gitlab/ci/parsers/security/validators/schema_validator.rb
+++ b/lib/gitlab/ci/parsers/security/validators/schema_validator.rb
@@ -7,14 +7,14 @@ module Gitlab
module Validators
class SchemaValidator
SUPPORTED_VERSIONS = {
- cluster_image_scanning: %w[14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2],
- container_scanning: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2],
- coverage_fuzzing: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2],
- dast: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2],
- api_fuzzing: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2],
- dependency_scanning: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2],
- sast: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2],
- secret_detection: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2]
+ cluster_image_scanning: %w[14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4],
+ container_scanning: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4],
+ coverage_fuzzing: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4],
+ dast: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4],
+ api_fuzzing: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4],
+ dependency_scanning: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4],
+ sast: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4],
+ secret_detection: %w[14.0.0 14.0.1 14.0.2 14.0.3 14.0.4 14.0.5 14.0.6 14.1.0 14.1.1 14.1.2 14.1.3 15.0.0 15.0.1 15.0.2 15.0.4]
}.freeze
VERSIONS_TO_REMOVE_IN_16_0 = [].freeze
diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/cluster-image-scanning-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/cluster-image-scanning-report-format.json
new file mode 100644
index 00000000000..3a859ca8bcf
--- /dev/null
+++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/cluster-image-scanning-report-format.json
@@ -0,0 +1,984 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/cluster-image-scanning-report-format.json",
+ "title": "Report format for GitLab Cluster Image Scanning",
+ "description": "This schema provides the the report format for Cluster Image Scanning (https://docs.gitlab.com/ee/user/application_security/cluster_image_scanning/).",
+ "definitions": {
+ "detail_type": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/named_list"
+ },
+ {
+ "$ref": "#/definitions/list"
+ },
+ {
+ "$ref": "#/definitions/table"
+ },
+ {
+ "$ref": "#/definitions/text"
+ },
+ {
+ "$ref": "#/definitions/url"
+ },
+ {
+ "$ref": "#/definitions/code"
+ },
+ {
+ "$ref": "#/definitions/value"
+ },
+ {
+ "$ref": "#/definitions/diff"
+ },
+ {
+ "$ref": "#/definitions/markdown"
+ },
+ {
+ "$ref": "#/definitions/commit"
+ },
+ {
+ "$ref": "#/definitions/file_location"
+ },
+ {
+ "$ref": "#/definitions/module_location"
+ }
+ ]
+ },
+ "text_value": {
+ "type": "string"
+ },
+ "named_field": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/text_value",
+ "type": "string",
+ "minLength": 1
+ },
+ "description": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "named_list": {
+ "type": "object",
+ "description": "An object with named and typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "named-list"
+ },
+ "items": {
+ "type": "object",
+ "patternProperties": {
+ "^.*$": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/named_field"
+ },
+ {
+ "$ref": "#/definitions/detail_type"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "list": {
+ "type": "object",
+ "description": "A list of typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "list"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ },
+ "table": {
+ "type": "object",
+ "description": "A table of typed fields",
+ "required": [
+ "type",
+ "rows"
+ ],
+ "properties": {
+ "type": {
+ "const": "table"
+ },
+ "header": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ },
+ "rows": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ }
+ },
+ "text": {
+ "type": "object",
+ "description": "Raw text",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "text"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "url": {
+ "type": "object",
+ "description": "A single URL",
+ "required": [
+ "type",
+ "href"
+ ],
+ "properties": {
+ "type": {
+ "const": "url"
+ },
+ "text": {
+ "$ref": "#/definitions/text_value"
+ },
+ "href": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "http://mysite.com"
+ ]
+ }
+ }
+ },
+ "code": {
+ "type": "object",
+ "description": "A codeblock",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "code"
+ },
+ "value": {
+ "type": "string"
+ },
+ "lang": {
+ "type": "string",
+ "description": "A programming language"
+ }
+ }
+ },
+ "value": {
+ "type": "object",
+ "description": "A field that can store a range of types of value",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "value"
+ },
+ "value": {
+ "type": [
+ "number",
+ "string",
+ "boolean"
+ ]
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "description": "A diff",
+ "required": [
+ "type",
+ "before",
+ "after"
+ ],
+ "properties": {
+ "type": {
+ "const": "diff"
+ },
+ "before": {
+ "type": "string"
+ },
+ "after": {
+ "type": "string"
+ }
+ }
+ },
+ "markdown": {
+ "type": "object",
+ "description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "markdown"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value",
+ "examples": [
+ "Here is markdown `inline code` #1 [test](gitlab.com)\n\n![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)"
+ ]
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "description": "A commit/tag/branch within the GitLab project",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "commit"
+ },
+ "value": {
+ "type": "string",
+ "description": "The commit SHA",
+ "minLength": 1
+ }
+ }
+ },
+ "file_location": {
+ "type": "object",
+ "description": "A location within a file in the project",
+ "required": [
+ "type",
+ "file_name",
+ "line_start"
+ ],
+ "properties": {
+ "type": {
+ "const": "file-location"
+ },
+ "file_name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "line_start": {
+ "type": "integer"
+ },
+ "line_end": {
+ "type": "integer"
+ }
+ }
+ },
+ "module_location": {
+ "type": "object",
+ "description": "A location within a binary module of the form module+relative_offset",
+ "required": [
+ "type",
+ "module_name",
+ "offset"
+ ],
+ "properties": {
+ "type": {
+ "const": "module-location"
+ },
+ "module_name": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "compiled_binary"
+ ]
+ },
+ "offset": {
+ "type": "integer",
+ "examples": [
+ 100
+ ]
+ }
+ }
+ }
+ },
+ "self": {
+ "version": "15.0.4"
+ },
+ "type": "object",
+ "required": [
+ "scan",
+ "version",
+ "vulnerabilities"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "scan": {
+ "type": "object",
+ "required": [
+ "analyzer",
+ "end_time",
+ "scanner",
+ "start_time",
+ "status",
+ "type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-01-28T03:26:02"
+ ]
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Communication intended for the initiator of a scan.",
+ "required": [
+ "level",
+ "value"
+ ],
+ "properties": {
+ "level": {
+ "type": "string",
+ "description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
+ "enum": [
+ "info",
+ "warn",
+ "fatal"
+ ],
+ "examples": [
+ "info"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "The message to communicate.",
+ "minLength": 1,
+ "examples": [
+ "Permission denied, scanning aborted"
+ ]
+ }
+ }
+ }
+ },
+ "analyzer": {
+ "type": "object",
+ "description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "gitlab-dast"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the analyzer, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "GitLab DAST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "pattern": "^https?://.+",
+ "description": "A link to more information about the analyzer.",
+ "examples": [
+ "https://docs.gitlab.com/ee/user/application_security/dast"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the analyzer.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ }
+ }
+ },
+ "scanner": {
+ "type": "object",
+ "description": "Object defining the scanner used to perform the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the scanner.",
+ "minLength": 1,
+ "examples": [
+ "my-sast-scanner"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the scanner, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "My SAST Scanner"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "A link to more information about the scanner.",
+ "examples": [
+ "https://scanner.url"
+ ]
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the scanner.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the scanner.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "start_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-02-14T16:01:59"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "description": "Result of the scan.",
+ "enum": [
+ "success",
+ "failure"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of the scan.",
+ "enum": [
+ "cluster_image_scanning"
+ ]
+ },
+ "primary_identifiers": {
+ "type": "array",
+ "description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^https?://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ }
+ }
+ },
+ "schema": {
+ "type": "string",
+ "description": "URI pointing to the validating security report schema.",
+ "pattern": "^https?://.+"
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the schema to which the JSON report conforms.",
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
+ },
+ "vulnerabilities": {
+ "type": "array",
+ "description": "Array of vulnerability objects.",
+ "items": {
+ "type": "object",
+ "description": "Describes the vulnerability using GitLab Flavored Markdown",
+ "required": [
+ "id",
+ "identifiers",
+ "location"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the vulnerability. This must not include the finding's specific information."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1048576,
+ "description": "A long text section describing the vulnerability more fully."
+ },
+ "severity": {
+ "type": "string",
+ "description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
+ "enum": [
+ "Info",
+ "Unknown",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+ },
+ "solution": {
+ "type": "string",
+ "maxLength": 7000,
+ "description": "Explanation of how to fix the vulnerability."
+ },
+ "identifiers": {
+ "type": "array",
+ "minItems": 1,
+ "description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^https?://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "links": {
+ "type": "array",
+ "description": "An array of references to external documentation or articles that describe the vulnerability.",
+ "items": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the vulnerability details link."
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the vulnerability details document.",
+ "pattern": "^https?://.+"
+ }
+ }
+ }
+ },
+ "details": {
+ "$ref": "#/definitions/named_list/properties/items"
+ },
+ "tracking": {
+ "type": "object",
+ "description": "Describes how this vulnerability should be tracked as the project changes.",
+ "oneOf": [
+ {
+ "description": "Declares that a series of items should be tracked using source-specific tracking methods.",
+ "required": [
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "source"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "description": "An item that should be tracked using source-specific tracking methods.",
+ "type": "object",
+ "required": [
+ "signatures"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the file that includes the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the file that includes the vulnerability."
+ },
+ "signatures": {
+ "type": "array",
+ "description": "An array of calculated tracking signatures for this tracking item.",
+ "minItems": 1,
+ "items": {
+ "description": "A calculated tracking signature value and metadata.",
+ "type": "object",
+ "required": [
+ "algorithm",
+ "value"
+ ],
+ "properties": {
+ "algorithm": {
+ "type": "string",
+ "description": "The algorithm used to generate the signature."
+ },
+ "value": {
+ "type": "string",
+ "description": "The result of this signature algorithm."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Each tracking type must declare its own type."
+ }
+ }
+ },
+ "flags": {
+ "description": "Flags that can be attached to vulnerabilities.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Informational flags identified and assigned to a vulnerability.",
+ "required": [
+ "type",
+ "origin",
+ "description"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Result of the scan.",
+ "enum": [
+ "flagged-as-likely-false-positive"
+ ]
+ },
+ "origin": {
+ "minLength": 1,
+ "description": "Tool that issued the flag.",
+ "type": "string"
+ },
+ "description": {
+ "minLength": 1,
+ "description": "What the flag is about.",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "location": {
+ "type": "object",
+ "description": "Identifies the vulnerability's location.",
+ "required": [
+ "dependency",
+ "image",
+ "kubernetes_resource"
+ ],
+ "properties": {
+ "dependency": {
+ "type": "object",
+ "description": "Describes the dependency of a project where the vulnerability is located.",
+ "required": [
+ "package",
+ "version"
+ ],
+ "properties": {
+ "package": {
+ "type": "object",
+ "description": "Provides information on the package where the vulnerability is located.",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the package where the vulnerability is located."
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "Version of the vulnerable package."
+ },
+ "iid": {
+ "description": "ID that identifies the dependency in the scope of a dependency file.",
+ "type": "number"
+ },
+ "direct": {
+ "type": "boolean",
+ "description": "Tells whether this is a direct, top-level dependency of the scanned project."
+ },
+ "dependency_path": {
+ "type": "array",
+ "description": "Ancestors of the dependency, starting from a direct project dependency, and ending with an immediate parent of the dependency. The dependency itself is excluded from the path. Direct dependencies have no path.",
+ "items": {
+ "type": "object",
+ "required": [
+ "iid"
+ ],
+ "properties": {
+ "iid": {
+ "type": "number",
+ "description": "ID that is unique in the scope of a parent object, and specific to the resource type."
+ }
+ }
+ }
+ }
+ }
+ },
+ "operating_system": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "description": "The operating system that contains the vulnerable package."
+ },
+ "image": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The analyzed Docker image.",
+ "examples": [
+ "index.docker.io/library/nginx:1.21"
+ ]
+ },
+ "kubernetes_resource": {
+ "type": "object",
+ "description": "The specific Kubernetes resource that was scanned.",
+ "required": [
+ "namespace",
+ "kind",
+ "name",
+ "container_name"
+ ],
+ "properties": {
+ "namespace": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "description": "The Kubernetes namespace the resource that had its image scanned.",
+ "examples": [
+ "default",
+ "staging",
+ "production"
+ ]
+ },
+ "kind": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "description": "The Kubernetes kind the resource that had its image scanned.",
+ "examples": [
+ "Deployment",
+ "DaemonSet"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "description": "The name of the resource that had its image scanned.",
+ "examples": [
+ "nginx-ingress"
+ ]
+ },
+ "container_name": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "description": "The name of the container that had its image scanned.",
+ "examples": [
+ "nginx"
+ ]
+ },
+ "agent_id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "description": "The GitLab ID of the Kubernetes Agent which performed the scan.",
+ "examples": [
+ "1234"
+ ]
+ },
+ "cluster_id": {
+ "type": "string",
+ "minLength": 1,
+ "maxLength": 255,
+ "description": "The GitLab ID of the Kubernetes cluster when using cluster integration.",
+ "examples": [
+ "1234"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "remediations": {
+ "type": "array",
+ "description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
+ "items": {
+ "type": "object",
+ "required": [
+ "fixes",
+ "summary",
+ "diff"
+ ],
+ "properties": {
+ "fixes": {
+ "type": "array",
+ "description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
+ "items": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ }
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "minLength": 1,
+ "description": "An overview of how the vulnerabilities were fixed."
+ },
+ "diff": {
+ "type": "string",
+ "minLength": 1,
+ "description": "A base64-encoded remediation code diff, compatible with git apply."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/container-scanning-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/container-scanning-report-format.json
new file mode 100644
index 00000000000..95f9ce90af7
--- /dev/null
+++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/container-scanning-report-format.json
@@ -0,0 +1,916 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/container-scanning-report-format.json",
+ "title": "Report format for GitLab Container Scanning",
+ "description": "This schema provides the the report format for Container Scanning (https://docs.gitlab.com/ee/user/application_security/container_scanning).",
+ "definitions": {
+ "detail_type": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/named_list"
+ },
+ {
+ "$ref": "#/definitions/list"
+ },
+ {
+ "$ref": "#/definitions/table"
+ },
+ {
+ "$ref": "#/definitions/text"
+ },
+ {
+ "$ref": "#/definitions/url"
+ },
+ {
+ "$ref": "#/definitions/code"
+ },
+ {
+ "$ref": "#/definitions/value"
+ },
+ {
+ "$ref": "#/definitions/diff"
+ },
+ {
+ "$ref": "#/definitions/markdown"
+ },
+ {
+ "$ref": "#/definitions/commit"
+ },
+ {
+ "$ref": "#/definitions/file_location"
+ },
+ {
+ "$ref": "#/definitions/module_location"
+ }
+ ]
+ },
+ "text_value": {
+ "type": "string"
+ },
+ "named_field": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/text_value",
+ "type": "string",
+ "minLength": 1
+ },
+ "description": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "named_list": {
+ "type": "object",
+ "description": "An object with named and typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "named-list"
+ },
+ "items": {
+ "type": "object",
+ "patternProperties": {
+ "^.*$": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/named_field"
+ },
+ {
+ "$ref": "#/definitions/detail_type"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "list": {
+ "type": "object",
+ "description": "A list of typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "list"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ },
+ "table": {
+ "type": "object",
+ "description": "A table of typed fields",
+ "required": [
+ "type",
+ "rows"
+ ],
+ "properties": {
+ "type": {
+ "const": "table"
+ },
+ "header": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ },
+ "rows": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ }
+ },
+ "text": {
+ "type": "object",
+ "description": "Raw text",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "text"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "url": {
+ "type": "object",
+ "description": "A single URL",
+ "required": [
+ "type",
+ "href"
+ ],
+ "properties": {
+ "type": {
+ "const": "url"
+ },
+ "text": {
+ "$ref": "#/definitions/text_value"
+ },
+ "href": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "http://mysite.com"
+ ]
+ }
+ }
+ },
+ "code": {
+ "type": "object",
+ "description": "A codeblock",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "code"
+ },
+ "value": {
+ "type": "string"
+ },
+ "lang": {
+ "type": "string",
+ "description": "A programming language"
+ }
+ }
+ },
+ "value": {
+ "type": "object",
+ "description": "A field that can store a range of types of value",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "value"
+ },
+ "value": {
+ "type": [
+ "number",
+ "string",
+ "boolean"
+ ]
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "description": "A diff",
+ "required": [
+ "type",
+ "before",
+ "after"
+ ],
+ "properties": {
+ "type": {
+ "const": "diff"
+ },
+ "before": {
+ "type": "string"
+ },
+ "after": {
+ "type": "string"
+ }
+ }
+ },
+ "markdown": {
+ "type": "object",
+ "description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "markdown"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value",
+ "examples": [
+ "Here is markdown `inline code` #1 [test](gitlab.com)\n\n![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)"
+ ]
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "description": "A commit/tag/branch within the GitLab project",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "commit"
+ },
+ "value": {
+ "type": "string",
+ "description": "The commit SHA",
+ "minLength": 1
+ }
+ }
+ },
+ "file_location": {
+ "type": "object",
+ "description": "A location within a file in the project",
+ "required": [
+ "type",
+ "file_name",
+ "line_start"
+ ],
+ "properties": {
+ "type": {
+ "const": "file-location"
+ },
+ "file_name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "line_start": {
+ "type": "integer"
+ },
+ "line_end": {
+ "type": "integer"
+ }
+ }
+ },
+ "module_location": {
+ "type": "object",
+ "description": "A location within a binary module of the form module+relative_offset",
+ "required": [
+ "type",
+ "module_name",
+ "offset"
+ ],
+ "properties": {
+ "type": {
+ "const": "module-location"
+ },
+ "module_name": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "compiled_binary"
+ ]
+ },
+ "offset": {
+ "type": "integer",
+ "examples": [
+ 100
+ ]
+ }
+ }
+ }
+ },
+ "self": {
+ "version": "15.0.4"
+ },
+ "type": "object",
+ "required": [
+ "scan",
+ "version",
+ "vulnerabilities"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "scan": {
+ "type": "object",
+ "required": [
+ "analyzer",
+ "end_time",
+ "scanner",
+ "start_time",
+ "status",
+ "type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-01-28T03:26:02"
+ ]
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Communication intended for the initiator of a scan.",
+ "required": [
+ "level",
+ "value"
+ ],
+ "properties": {
+ "level": {
+ "type": "string",
+ "description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
+ "enum": [
+ "info",
+ "warn",
+ "fatal"
+ ],
+ "examples": [
+ "info"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "The message to communicate.",
+ "minLength": 1,
+ "examples": [
+ "Permission denied, scanning aborted"
+ ]
+ }
+ }
+ }
+ },
+ "analyzer": {
+ "type": "object",
+ "description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "gitlab-dast"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the analyzer, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "GitLab DAST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "pattern": "^https?://.+",
+ "description": "A link to more information about the analyzer.",
+ "examples": [
+ "https://docs.gitlab.com/ee/user/application_security/dast"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the analyzer.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ }
+ }
+ },
+ "scanner": {
+ "type": "object",
+ "description": "Object defining the scanner used to perform the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the scanner.",
+ "minLength": 1,
+ "examples": [
+ "my-sast-scanner"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the scanner, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "My SAST Scanner"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "A link to more information about the scanner.",
+ "examples": [
+ "https://scanner.url"
+ ]
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the scanner.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the scanner.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "start_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-02-14T16:01:59"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "description": "Result of the scan.",
+ "enum": [
+ "success",
+ "failure"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of the scan.",
+ "enum": [
+ "container_scanning"
+ ]
+ },
+ "primary_identifiers": {
+ "type": "array",
+ "description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^https?://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ }
+ }
+ },
+ "schema": {
+ "type": "string",
+ "description": "URI pointing to the validating security report schema.",
+ "pattern": "^https?://.+"
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the schema to which the JSON report conforms.",
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
+ },
+ "vulnerabilities": {
+ "type": "array",
+ "description": "Array of vulnerability objects.",
+ "items": {
+ "type": "object",
+ "description": "Describes the vulnerability using GitLab Flavored Markdown",
+ "required": [
+ "id",
+ "identifiers",
+ "location"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the vulnerability. This must not include the finding's specific information."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1048576,
+ "description": "A long text section describing the vulnerability more fully."
+ },
+ "severity": {
+ "type": "string",
+ "description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
+ "enum": [
+ "Info",
+ "Unknown",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+ },
+ "solution": {
+ "type": "string",
+ "maxLength": 7000,
+ "description": "Explanation of how to fix the vulnerability."
+ },
+ "identifiers": {
+ "type": "array",
+ "minItems": 1,
+ "description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^https?://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "links": {
+ "type": "array",
+ "description": "An array of references to external documentation or articles that describe the vulnerability.",
+ "items": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the vulnerability details link."
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the vulnerability details document.",
+ "pattern": "^https?://.+"
+ }
+ }
+ }
+ },
+ "details": {
+ "$ref": "#/definitions/named_list/properties/items"
+ },
+ "tracking": {
+ "type": "object",
+ "description": "Describes how this vulnerability should be tracked as the project changes.",
+ "oneOf": [
+ {
+ "description": "Declares that a series of items should be tracked using source-specific tracking methods.",
+ "required": [
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "source"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "description": "An item that should be tracked using source-specific tracking methods.",
+ "type": "object",
+ "required": [
+ "signatures"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the file that includes the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the file that includes the vulnerability."
+ },
+ "signatures": {
+ "type": "array",
+ "description": "An array of calculated tracking signatures for this tracking item.",
+ "minItems": 1,
+ "items": {
+ "description": "A calculated tracking signature value and metadata.",
+ "type": "object",
+ "required": [
+ "algorithm",
+ "value"
+ ],
+ "properties": {
+ "algorithm": {
+ "type": "string",
+ "description": "The algorithm used to generate the signature."
+ },
+ "value": {
+ "type": "string",
+ "description": "The result of this signature algorithm."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Each tracking type must declare its own type."
+ }
+ }
+ },
+ "flags": {
+ "description": "Flags that can be attached to vulnerabilities.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Informational flags identified and assigned to a vulnerability.",
+ "required": [
+ "type",
+ "origin",
+ "description"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Result of the scan.",
+ "enum": [
+ "flagged-as-likely-false-positive"
+ ]
+ },
+ "origin": {
+ "minLength": 1,
+ "description": "Tool that issued the flag.",
+ "type": "string"
+ },
+ "description": {
+ "minLength": 1,
+ "description": "What the flag is about.",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "location": {
+ "type": "object",
+ "description": "Identifies the vulnerability's location.",
+ "required": [
+ "dependency",
+ "operating_system",
+ "image"
+ ],
+ "properties": {
+ "dependency": {
+ "type": "object",
+ "description": "Describes the dependency of a project where the vulnerability is located.",
+ "required": [
+ "package",
+ "version"
+ ],
+ "properties": {
+ "package": {
+ "type": "object",
+ "description": "Provides information on the package where the vulnerability is located.",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the package where the vulnerability is located."
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "Version of the vulnerable package."
+ },
+ "iid": {
+ "description": "ID that identifies the dependency in the scope of a dependency file.",
+ "type": "number"
+ },
+ "direct": {
+ "type": "boolean",
+ "description": "Tells whether this is a direct, top-level dependency of the scanned project."
+ },
+ "dependency_path": {
+ "type": "array",
+ "description": "Ancestors of the dependency, starting from a direct project dependency, and ending with an immediate parent of the dependency. The dependency itself is excluded from the path. Direct dependencies have no path.",
+ "items": {
+ "type": "object",
+ "required": [
+ "iid"
+ ],
+ "properties": {
+ "iid": {
+ "type": "number",
+ "description": "ID that is unique in the scope of a parent object, and specific to the resource type."
+ }
+ }
+ }
+ }
+ }
+ },
+ "operating_system": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The operating system that contains the vulnerable package."
+ },
+ "image": {
+ "type": "string",
+ "minLength": 1,
+ "description": "The analyzed Docker image."
+ },
+ "default_branch_image": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the image on the default branch."
+ }
+ }
+ }
+ }
+ }
+ },
+ "remediations": {
+ "type": "array",
+ "description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
+ "items": {
+ "type": "object",
+ "required": [
+ "fixes",
+ "summary",
+ "diff"
+ ],
+ "properties": {
+ "fixes": {
+ "type": "array",
+ "description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
+ "items": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ }
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "minLength": 1,
+ "description": "An overview of how the vulnerabilities were fixed."
+ },
+ "diff": {
+ "type": "string",
+ "minLength": 1,
+ "description": "A base64-encoded remediation code diff, compatible with git apply."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/coverage-fuzzing-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/coverage-fuzzing-report-format.json
new file mode 100644
index 00000000000..b2f39d6f070
--- /dev/null
+++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/coverage-fuzzing-report-format.json
@@ -0,0 +1,874 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/coverage-fuzzing-report-format.json",
+ "title": "Report format for GitLab Fuzz Testing",
+ "description": "This schema provides the report format for Coverage Guided Fuzz Testing (https://docs.gitlab.com/ee/user/application_security/coverage_fuzzing).",
+ "definitions": {
+ "detail_type": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/named_list"
+ },
+ {
+ "$ref": "#/definitions/list"
+ },
+ {
+ "$ref": "#/definitions/table"
+ },
+ {
+ "$ref": "#/definitions/text"
+ },
+ {
+ "$ref": "#/definitions/url"
+ },
+ {
+ "$ref": "#/definitions/code"
+ },
+ {
+ "$ref": "#/definitions/value"
+ },
+ {
+ "$ref": "#/definitions/diff"
+ },
+ {
+ "$ref": "#/definitions/markdown"
+ },
+ {
+ "$ref": "#/definitions/commit"
+ },
+ {
+ "$ref": "#/definitions/file_location"
+ },
+ {
+ "$ref": "#/definitions/module_location"
+ }
+ ]
+ },
+ "text_value": {
+ "type": "string"
+ },
+ "named_field": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/text_value",
+ "type": "string",
+ "minLength": 1
+ },
+ "description": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "named_list": {
+ "type": "object",
+ "description": "An object with named and typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "named-list"
+ },
+ "items": {
+ "type": "object",
+ "patternProperties": {
+ "^.*$": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/named_field"
+ },
+ {
+ "$ref": "#/definitions/detail_type"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "list": {
+ "type": "object",
+ "description": "A list of typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "list"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ },
+ "table": {
+ "type": "object",
+ "description": "A table of typed fields",
+ "required": [
+ "type",
+ "rows"
+ ],
+ "properties": {
+ "type": {
+ "const": "table"
+ },
+ "header": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ },
+ "rows": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ }
+ },
+ "text": {
+ "type": "object",
+ "description": "Raw text",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "text"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "url": {
+ "type": "object",
+ "description": "A single URL",
+ "required": [
+ "type",
+ "href"
+ ],
+ "properties": {
+ "type": {
+ "const": "url"
+ },
+ "text": {
+ "$ref": "#/definitions/text_value"
+ },
+ "href": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "http://mysite.com"
+ ]
+ }
+ }
+ },
+ "code": {
+ "type": "object",
+ "description": "A codeblock",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "code"
+ },
+ "value": {
+ "type": "string"
+ },
+ "lang": {
+ "type": "string",
+ "description": "A programming language"
+ }
+ }
+ },
+ "value": {
+ "type": "object",
+ "description": "A field that can store a range of types of value",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "value"
+ },
+ "value": {
+ "type": [
+ "number",
+ "string",
+ "boolean"
+ ]
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "description": "A diff",
+ "required": [
+ "type",
+ "before",
+ "after"
+ ],
+ "properties": {
+ "type": {
+ "const": "diff"
+ },
+ "before": {
+ "type": "string"
+ },
+ "after": {
+ "type": "string"
+ }
+ }
+ },
+ "markdown": {
+ "type": "object",
+ "description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "markdown"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value",
+ "examples": [
+ "Here is markdown `inline code` #1 [test](gitlab.com)\n\n![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)"
+ ]
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "description": "A commit/tag/branch within the GitLab project",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "commit"
+ },
+ "value": {
+ "type": "string",
+ "description": "The commit SHA",
+ "minLength": 1
+ }
+ }
+ },
+ "file_location": {
+ "type": "object",
+ "description": "A location within a file in the project",
+ "required": [
+ "type",
+ "file_name",
+ "line_start"
+ ],
+ "properties": {
+ "type": {
+ "const": "file-location"
+ },
+ "file_name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "line_start": {
+ "type": "integer"
+ },
+ "line_end": {
+ "type": "integer"
+ }
+ }
+ },
+ "module_location": {
+ "type": "object",
+ "description": "A location within a binary module of the form module+relative_offset",
+ "required": [
+ "type",
+ "module_name",
+ "offset"
+ ],
+ "properties": {
+ "type": {
+ "const": "module-location"
+ },
+ "module_name": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "compiled_binary"
+ ]
+ },
+ "offset": {
+ "type": "integer",
+ "examples": [
+ 100
+ ]
+ }
+ }
+ }
+ },
+ "self": {
+ "version": "15.0.4"
+ },
+ "type": "object",
+ "required": [
+ "scan",
+ "version",
+ "vulnerabilities"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "scan": {
+ "type": "object",
+ "required": [
+ "analyzer",
+ "end_time",
+ "scanner",
+ "start_time",
+ "status",
+ "type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-01-28T03:26:02"
+ ]
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Communication intended for the initiator of a scan.",
+ "required": [
+ "level",
+ "value"
+ ],
+ "properties": {
+ "level": {
+ "type": "string",
+ "description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
+ "enum": [
+ "info",
+ "warn",
+ "fatal"
+ ],
+ "examples": [
+ "info"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "The message to communicate.",
+ "minLength": 1,
+ "examples": [
+ "Permission denied, scanning aborted"
+ ]
+ }
+ }
+ }
+ },
+ "analyzer": {
+ "type": "object",
+ "description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "gitlab-dast"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the analyzer, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "GitLab DAST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "pattern": "^https?://.+",
+ "description": "A link to more information about the analyzer.",
+ "examples": [
+ "https://docs.gitlab.com/ee/user/application_security/dast"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the analyzer.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ }
+ }
+ },
+ "scanner": {
+ "type": "object",
+ "description": "Object defining the scanner used to perform the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the scanner.",
+ "minLength": 1,
+ "examples": [
+ "my-sast-scanner"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the scanner, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "My SAST Scanner"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "A link to more information about the scanner.",
+ "examples": [
+ "https://scanner.url"
+ ]
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the scanner.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the scanner.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "start_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-02-14T16:01:59"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "description": "Result of the scan.",
+ "enum": [
+ "success",
+ "failure"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of the scan.",
+ "enum": [
+ "coverage_fuzzing"
+ ]
+ },
+ "primary_identifiers": {
+ "type": "array",
+ "description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^https?://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ }
+ }
+ },
+ "schema": {
+ "type": "string",
+ "description": "URI pointing to the validating security report schema.",
+ "pattern": "^https?://.+"
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the schema to which the JSON report conforms.",
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
+ },
+ "vulnerabilities": {
+ "type": "array",
+ "description": "Array of vulnerability objects.",
+ "items": {
+ "type": "object",
+ "description": "Describes the vulnerability using GitLab Flavored Markdown",
+ "required": [
+ "id",
+ "identifiers",
+ "location"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the vulnerability. This must not include the finding's specific information."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1048576,
+ "description": "A long text section describing the vulnerability more fully."
+ },
+ "severity": {
+ "type": "string",
+ "description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
+ "enum": [
+ "Info",
+ "Unknown",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+ },
+ "solution": {
+ "type": "string",
+ "maxLength": 7000,
+ "description": "Explanation of how to fix the vulnerability."
+ },
+ "identifiers": {
+ "type": "array",
+ "minItems": 1,
+ "description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^https?://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "links": {
+ "type": "array",
+ "description": "An array of references to external documentation or articles that describe the vulnerability.",
+ "items": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the vulnerability details link."
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the vulnerability details document.",
+ "pattern": "^https?://.+"
+ }
+ }
+ }
+ },
+ "details": {
+ "$ref": "#/definitions/named_list/properties/items"
+ },
+ "tracking": {
+ "type": "object",
+ "description": "Describes how this vulnerability should be tracked as the project changes.",
+ "oneOf": [
+ {
+ "description": "Declares that a series of items should be tracked using source-specific tracking methods.",
+ "required": [
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "source"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "description": "An item that should be tracked using source-specific tracking methods.",
+ "type": "object",
+ "required": [
+ "signatures"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the file that includes the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the file that includes the vulnerability."
+ },
+ "signatures": {
+ "type": "array",
+ "description": "An array of calculated tracking signatures for this tracking item.",
+ "minItems": 1,
+ "items": {
+ "description": "A calculated tracking signature value and metadata.",
+ "type": "object",
+ "required": [
+ "algorithm",
+ "value"
+ ],
+ "properties": {
+ "algorithm": {
+ "type": "string",
+ "description": "The algorithm used to generate the signature."
+ },
+ "value": {
+ "type": "string",
+ "description": "The result of this signature algorithm."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Each tracking type must declare its own type."
+ }
+ }
+ },
+ "flags": {
+ "description": "Flags that can be attached to vulnerabilities.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Informational flags identified and assigned to a vulnerability.",
+ "required": [
+ "type",
+ "origin",
+ "description"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Result of the scan.",
+ "enum": [
+ "flagged-as-likely-false-positive"
+ ]
+ },
+ "origin": {
+ "minLength": 1,
+ "description": "Tool that issued the flag.",
+ "type": "string"
+ },
+ "description": {
+ "minLength": 1,
+ "description": "What the flag is about.",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "location": {
+ "description": "The location of the error",
+ "type": "object",
+ "properties": {
+ "crash_address": {
+ "type": "string",
+ "description": "The relative address in memory were the crash occurred.",
+ "examples": [
+ "0xabababab"
+ ]
+ },
+ "stacktrace_snippet": {
+ "type": "string",
+ "description": "The stack trace recorded during fuzzing resulting the crash.",
+ "examples": [
+ "func_a+0xabcd\nfunc_b+0xabcc"
+ ]
+ },
+ "crash_state": {
+ "type": "string",
+ "description": "Minimised and normalized crash stack-trace (called crash_state).",
+ "examples": [
+ "func_a+0xa\nfunc_b+0xb\nfunc_c+0xc"
+ ]
+ },
+ "crash_type": {
+ "type": "string",
+ "description": "Type of the crash.",
+ "examples": [
+ "Heap-Buffer-overflow",
+ "Division-by-zero"
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "remediations": {
+ "type": "array",
+ "description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
+ "items": {
+ "type": "object",
+ "required": [
+ "fixes",
+ "summary",
+ "diff"
+ ],
+ "properties": {
+ "fixes": {
+ "type": "array",
+ "description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
+ "items": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ }
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "minLength": 1,
+ "description": "An overview of how the vulnerabilities were fixed."
+ },
+ "diff": {
+ "type": "string",
+ "minLength": 1,
+ "description": "A base64-encoded remediation code diff, compatible with git apply."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/dast-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/dast-report-format.json
new file mode 100644
index 00000000000..2b86d7e40c9
--- /dev/null
+++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/dast-report-format.json
@@ -0,0 +1,1279 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/dast-report-format.json",
+ "title": "Report format for GitLab DAST",
+ "description": "This schema provides the the report format for Dynamic Application Security Testing (https://docs.gitlab.com/ee/user/application_security/dast).",
+ "definitions": {
+ "detail_type": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/named_list"
+ },
+ {
+ "$ref": "#/definitions/list"
+ },
+ {
+ "$ref": "#/definitions/table"
+ },
+ {
+ "$ref": "#/definitions/text"
+ },
+ {
+ "$ref": "#/definitions/url"
+ },
+ {
+ "$ref": "#/definitions/code"
+ },
+ {
+ "$ref": "#/definitions/value"
+ },
+ {
+ "$ref": "#/definitions/diff"
+ },
+ {
+ "$ref": "#/definitions/markdown"
+ },
+ {
+ "$ref": "#/definitions/commit"
+ },
+ {
+ "$ref": "#/definitions/file_location"
+ },
+ {
+ "$ref": "#/definitions/module_location"
+ }
+ ]
+ },
+ "text_value": {
+ "type": "string"
+ },
+ "named_field": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/text_value",
+ "type": "string",
+ "minLength": 1
+ },
+ "description": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "named_list": {
+ "type": "object",
+ "description": "An object with named and typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "named-list"
+ },
+ "items": {
+ "type": "object",
+ "patternProperties": {
+ "^.*$": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/named_field"
+ },
+ {
+ "$ref": "#/definitions/detail_type"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "list": {
+ "type": "object",
+ "description": "A list of typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "list"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ },
+ "table": {
+ "type": "object",
+ "description": "A table of typed fields",
+ "required": [
+ "type",
+ "rows"
+ ],
+ "properties": {
+ "type": {
+ "const": "table"
+ },
+ "header": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ },
+ "rows": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ }
+ },
+ "text": {
+ "type": "object",
+ "description": "Raw text",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "text"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "url": {
+ "type": "object",
+ "description": "A single URL",
+ "required": [
+ "type",
+ "href"
+ ],
+ "properties": {
+ "type": {
+ "const": "url"
+ },
+ "text": {
+ "$ref": "#/definitions/text_value"
+ },
+ "href": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "http://mysite.com"
+ ]
+ }
+ }
+ },
+ "code": {
+ "type": "object",
+ "description": "A codeblock",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "code"
+ },
+ "value": {
+ "type": "string"
+ },
+ "lang": {
+ "type": "string",
+ "description": "A programming language"
+ }
+ }
+ },
+ "value": {
+ "type": "object",
+ "description": "A field that can store a range of types of value",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "value"
+ },
+ "value": {
+ "type": [
+ "number",
+ "string",
+ "boolean"
+ ]
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "description": "A diff",
+ "required": [
+ "type",
+ "before",
+ "after"
+ ],
+ "properties": {
+ "type": {
+ "const": "diff"
+ },
+ "before": {
+ "type": "string"
+ },
+ "after": {
+ "type": "string"
+ }
+ }
+ },
+ "markdown": {
+ "type": "object",
+ "description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "markdown"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value",
+ "examples": [
+ "Here is markdown `inline code` #1 [test](gitlab.com)\n\n![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)"
+ ]
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "description": "A commit/tag/branch within the GitLab project",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "commit"
+ },
+ "value": {
+ "type": "string",
+ "description": "The commit SHA",
+ "minLength": 1
+ }
+ }
+ },
+ "file_location": {
+ "type": "object",
+ "description": "A location within a file in the project",
+ "required": [
+ "type",
+ "file_name",
+ "line_start"
+ ],
+ "properties": {
+ "type": {
+ "const": "file-location"
+ },
+ "file_name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "line_start": {
+ "type": "integer"
+ },
+ "line_end": {
+ "type": "integer"
+ }
+ }
+ },
+ "module_location": {
+ "type": "object",
+ "description": "A location within a binary module of the form module+relative_offset",
+ "required": [
+ "type",
+ "module_name",
+ "offset"
+ ],
+ "properties": {
+ "type": {
+ "const": "module-location"
+ },
+ "module_name": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "compiled_binary"
+ ]
+ },
+ "offset": {
+ "type": "integer",
+ "examples": [
+ 100
+ ]
+ }
+ }
+ }
+ },
+ "self": {
+ "version": "15.0.4"
+ },
+ "type": "object",
+ "required": [
+ "scan",
+ "version",
+ "vulnerabilities"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "scan": {
+ "type": "object",
+ "required": [
+ "analyzer",
+ "end_time",
+ "scanned_resources",
+ "scanner",
+ "start_time",
+ "status",
+ "type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-01-28T03:26:02"
+ ]
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Communication intended for the initiator of a scan.",
+ "required": [
+ "level",
+ "value"
+ ],
+ "properties": {
+ "level": {
+ "type": "string",
+ "description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
+ "enum": [
+ "info",
+ "warn",
+ "fatal"
+ ],
+ "examples": [
+ "info"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "The message to communicate.",
+ "minLength": 1,
+ "examples": [
+ "Permission denied, scanning aborted"
+ ]
+ }
+ }
+ }
+ },
+ "analyzer": {
+ "type": "object",
+ "description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "gitlab-dast"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the analyzer, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "GitLab DAST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "pattern": "^https?://.+",
+ "description": "A link to more information about the analyzer.",
+ "examples": [
+ "https://docs.gitlab.com/ee/user/application_security/dast"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the analyzer.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ }
+ }
+ },
+ "scanner": {
+ "type": "object",
+ "description": "Object defining the scanner used to perform the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the scanner.",
+ "minLength": 1,
+ "examples": [
+ "my-sast-scanner"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the scanner, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "My SAST Scanner"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "A link to more information about the scanner.",
+ "examples": [
+ "https://scanner.url"
+ ]
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the scanner.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the scanner.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "start_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-02-14T16:01:59"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "description": "Result of the scan.",
+ "enum": [
+ "success",
+ "failure"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of the scan.",
+ "enum": [
+ "dast",
+ "api_fuzzing"
+ ]
+ },
+ "primary_identifiers": {
+ "type": "array",
+ "description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^https?://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "scanned_resources": {
+ "type": "array",
+ "description": "The attack surface scanned by DAST.",
+ "items": {
+ "type": "object",
+ "required": [
+ "method",
+ "url",
+ "type"
+ ],
+ "properties": {
+ "method": {
+ "type": "string",
+ "minLength": 1,
+ "description": "HTTP method of the scanned resource.",
+ "examples": [
+ "GET",
+ "POST",
+ "HEAD"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "minLength": 1,
+ "description": "URL of the scanned resource.",
+ "examples": [
+ "http://my.site.com/a-page"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Type of the scanned resource, for DAST, this must be 'url'.",
+ "examples": [
+ "url"
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "schema": {
+ "type": "string",
+ "description": "URI pointing to the validating security report schema.",
+ "pattern": "^https?://.+"
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the schema to which the JSON report conforms.",
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
+ },
+ "vulnerabilities": {
+ "type": "array",
+ "description": "Array of vulnerability objects.",
+ "items": {
+ "type": "object",
+ "description": "Describes the vulnerability using GitLab Flavored Markdown",
+ "required": [
+ "id",
+ "identifiers",
+ "location"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the vulnerability. This must not include the finding's specific information."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1048576,
+ "description": "A long text section describing the vulnerability more fully."
+ },
+ "severity": {
+ "type": "string",
+ "description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
+ "enum": [
+ "Info",
+ "Unknown",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+ },
+ "solution": {
+ "type": "string",
+ "maxLength": 7000,
+ "description": "Explanation of how to fix the vulnerability."
+ },
+ "identifiers": {
+ "type": "array",
+ "minItems": 1,
+ "description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^https?://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "links": {
+ "type": "array",
+ "description": "An array of references to external documentation or articles that describe the vulnerability.",
+ "items": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the vulnerability details link."
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the vulnerability details document.",
+ "pattern": "^https?://.+"
+ }
+ }
+ }
+ },
+ "details": {
+ "$ref": "#/definitions/named_list/properties/items"
+ },
+ "tracking": {
+ "type": "object",
+ "description": "Describes how this vulnerability should be tracked as the project changes.",
+ "oneOf": [
+ {
+ "description": "Declares that a series of items should be tracked using source-specific tracking methods.",
+ "required": [
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "source"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "description": "An item that should be tracked using source-specific tracking methods.",
+ "type": "object",
+ "required": [
+ "signatures"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the file that includes the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the file that includes the vulnerability."
+ },
+ "signatures": {
+ "type": "array",
+ "description": "An array of calculated tracking signatures for this tracking item.",
+ "minItems": 1,
+ "items": {
+ "description": "A calculated tracking signature value and metadata.",
+ "type": "object",
+ "required": [
+ "algorithm",
+ "value"
+ ],
+ "properties": {
+ "algorithm": {
+ "type": "string",
+ "description": "The algorithm used to generate the signature."
+ },
+ "value": {
+ "type": "string",
+ "description": "The result of this signature algorithm."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Each tracking type must declare its own type."
+ }
+ }
+ },
+ "flags": {
+ "description": "Flags that can be attached to vulnerabilities.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Informational flags identified and assigned to a vulnerability.",
+ "required": [
+ "type",
+ "origin",
+ "description"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Result of the scan.",
+ "enum": [
+ "flagged-as-likely-false-positive"
+ ]
+ },
+ "origin": {
+ "minLength": 1,
+ "description": "Tool that issued the flag.",
+ "type": "string"
+ },
+ "description": {
+ "minLength": 1,
+ "description": "What the flag is about.",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "evidence": {
+ "type": "object",
+ "properties": {
+ "source": {
+ "type": "object",
+ "description": "Source of evidence",
+ "required": [
+ "id",
+ "name"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique source identifier",
+ "examples": [
+ "assert:LogAnalysis",
+ "assert:StatusCode"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Source display name",
+ "examples": [
+ "Log Analysis",
+ "Status Code"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "Link to additional information",
+ "examples": [
+ "https://docs.gitlab.com/ee/development/integrations/secure.html"
+ ]
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "description": "Human readable string containing evidence of the vulnerability.",
+ "examples": [
+ "Credit card 4111111111111111 found",
+ "Server leaked information nginx/1.17.6"
+ ]
+ },
+ "request": {
+ "type": "object",
+ "description": "An HTTP request.",
+ "required": [
+ "headers",
+ "method",
+ "url"
+ ],
+ "properties": {
+ "headers": {
+ "type": "array",
+ "description": "HTTP headers present on the request.",
+ "items": {
+ "type": "object",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Name of the HTTP header.",
+ "examples": [
+ "Accept",
+ "Content-Length",
+ "Content-Type"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the HTTP header.",
+ "examples": [
+ "*/*",
+ "560",
+ "application/json; charset=utf-8"
+ ]
+ }
+ }
+ }
+ },
+ "method": {
+ "type": "string",
+ "minLength": 1,
+ "description": "HTTP method used in the request.",
+ "examples": [
+ "GET",
+ "POST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "minLength": 1,
+ "description": "URL of the request.",
+ "examples": [
+ "http://my.site.com/vulnerable-endpoint?show-credit-card"
+ ]
+ },
+ "body": {
+ "type": "string",
+ "description": "Body of the request for display purposes. Body must be suitable for display (not binary), and truncated to a reasonable size.",
+ "examples": [
+ "user=jsmith&first=%27&last=smith"
+ ]
+ }
+ }
+ },
+ "response": {
+ "type": "object",
+ "description": "An HTTP response.",
+ "required": [
+ "headers",
+ "reason_phrase",
+ "status_code"
+ ],
+ "properties": {
+ "headers": {
+ "type": "array",
+ "description": "HTTP headers present on the request.",
+ "items": {
+ "type": "object",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Name of the HTTP header.",
+ "examples": [
+ "Accept",
+ "Content-Length",
+ "Content-Type"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the HTTP header.",
+ "examples": [
+ "*/*",
+ "560",
+ "application/json; charset=utf-8"
+ ]
+ }
+ }
+ }
+ },
+ "reason_phrase": {
+ "type": "string",
+ "description": "HTTP reason phrase of the response.",
+ "examples": [
+ "OK",
+ "Internal Server Error"
+ ]
+ },
+ "status_code": {
+ "type": "integer",
+ "description": "HTTP status code of the response.",
+ "examples": [
+ 200,
+ 500
+ ]
+ },
+ "body": {
+ "type": "string",
+ "description": "Body of the response for display purposes. Body must be suitable for display (not binary), and truncated to a reasonable size.",
+ "examples": [
+ "{\"user_id\": 2}"
+ ]
+ }
+ }
+ },
+ "supporting_messages": {
+ "type": "array",
+ "description": "Array of supporting http messages.",
+ "items": {
+ "type": "object",
+ "description": "A supporting http message.",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Message display name.",
+ "examples": [
+ "Unmodified",
+ "Recorded"
+ ]
+ },
+ "request": {
+ "type": "object",
+ "description": "An HTTP request.",
+ "required": [
+ "headers",
+ "method",
+ "url"
+ ],
+ "properties": {
+ "headers": {
+ "type": "array",
+ "description": "HTTP headers present on the request.",
+ "items": {
+ "type": "object",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Name of the HTTP header.",
+ "examples": [
+ "Accept",
+ "Content-Length",
+ "Content-Type"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the HTTP header.",
+ "examples": [
+ "*/*",
+ "560",
+ "application/json; charset=utf-8"
+ ]
+ }
+ }
+ }
+ },
+ "method": {
+ "type": "string",
+ "minLength": 1,
+ "description": "HTTP method used in the request.",
+ "examples": [
+ "GET",
+ "POST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "minLength": 1,
+ "description": "URL of the request.",
+ "examples": [
+ "http://my.site.com/vulnerable-endpoint?show-credit-card"
+ ]
+ },
+ "body": {
+ "type": "string",
+ "description": "Body of the request for display purposes. Body must be suitable for display (not binary), and truncated to a reasonable size.",
+ "examples": [
+ "user=jsmith&first=%27&last=smith"
+ ]
+ }
+ }
+ },
+ "response": {
+ "type": "object",
+ "description": "An HTTP response.",
+ "required": [
+ "headers",
+ "reason_phrase",
+ "status_code"
+ ],
+ "properties": {
+ "headers": {
+ "type": "array",
+ "description": "HTTP headers present on the request.",
+ "items": {
+ "type": "object",
+ "required": [
+ "name",
+ "value"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Name of the HTTP header.",
+ "examples": [
+ "Accept",
+ "Content-Length",
+ "Content-Type"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the HTTP header.",
+ "examples": [
+ "*/*",
+ "560",
+ "application/json; charset=utf-8"
+ ]
+ }
+ }
+ }
+ },
+ "reason_phrase": {
+ "type": "string",
+ "description": "HTTP reason phrase of the response.",
+ "examples": [
+ "OK",
+ "Internal Server Error"
+ ]
+ },
+ "status_code": {
+ "type": "integer",
+ "description": "HTTP status code of the response.",
+ "examples": [
+ 200,
+ 500
+ ]
+ },
+ "body": {
+ "type": "string",
+ "description": "Body of the response for display purposes. Body must be suitable for display (not binary), and truncated to a reasonable size.",
+ "examples": [
+ "{\"user_id\": 2}"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "location": {
+ "type": "object",
+ "description": "Identifies the vulnerability's location.",
+ "properties": {
+ "hostname": {
+ "type": "string",
+ "description": "The protocol, domain, and port of the application where the vulnerability was found."
+ },
+ "method": {
+ "type": "string",
+ "description": "The HTTP method that was used to request the URL where the vulnerability was found."
+ },
+ "param": {
+ "type": "string",
+ "description": "A value provided by a vulnerability rule related to the found vulnerability. Examples include a header value, or a parameter used in a HTTP POST."
+ },
+ "path": {
+ "type": "string",
+ "description": "The path of the URL where the vulnerability was found. Typically, this would start with a forward slash."
+ }
+ }
+ },
+ "assets": {
+ "type": "array",
+ "description": "Array of build assets associated with vulnerability.",
+ "items": {
+ "type": "object",
+ "description": "Describes an asset associated with vulnerability.",
+ "required": [
+ "type",
+ "name",
+ "url"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The type of asset",
+ "enum": [
+ "http_session",
+ "postman"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Display name for asset",
+ "examples": [
+ "HTTP Messages",
+ "Postman Collection"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Link to asset in build artifacts",
+ "examples": [
+ "https://gitlab.com/gitlab-org/security-products/dast/-/jobs/626397001/artifacts/file//output/zap_session.data"
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "remediations": {
+ "type": "array",
+ "description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
+ "items": {
+ "type": "object",
+ "required": [
+ "fixes",
+ "summary",
+ "diff"
+ ],
+ "properties": {
+ "fixes": {
+ "type": "array",
+ "description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
+ "items": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ }
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "minLength": 1,
+ "description": "An overview of how the vulnerabilities were fixed."
+ },
+ "diff": {
+ "type": "string",
+ "minLength": 1,
+ "description": "A base64-encoded remediation code diff, compatible with git apply."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/dependency-scanning-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/dependency-scanning-report-format.json
new file mode 100644
index 00000000000..29ba60b895e
--- /dev/null
+++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/dependency-scanning-report-format.json
@@ -0,0 +1,982 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/dependency-scanning-report-format.json",
+ "title": "Report format for GitLab Dependency Scanning",
+ "description": "This schema provides the the report format for Dependency Scanning analyzers (https://docs.gitlab.com/ee/user/application_security/dependency_scanning).",
+ "definitions": {
+ "detail_type": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/named_list"
+ },
+ {
+ "$ref": "#/definitions/list"
+ },
+ {
+ "$ref": "#/definitions/table"
+ },
+ {
+ "$ref": "#/definitions/text"
+ },
+ {
+ "$ref": "#/definitions/url"
+ },
+ {
+ "$ref": "#/definitions/code"
+ },
+ {
+ "$ref": "#/definitions/value"
+ },
+ {
+ "$ref": "#/definitions/diff"
+ },
+ {
+ "$ref": "#/definitions/markdown"
+ },
+ {
+ "$ref": "#/definitions/commit"
+ },
+ {
+ "$ref": "#/definitions/file_location"
+ },
+ {
+ "$ref": "#/definitions/module_location"
+ }
+ ]
+ },
+ "text_value": {
+ "type": "string"
+ },
+ "named_field": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/text_value",
+ "type": "string",
+ "minLength": 1
+ },
+ "description": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "named_list": {
+ "type": "object",
+ "description": "An object with named and typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "named-list"
+ },
+ "items": {
+ "type": "object",
+ "patternProperties": {
+ "^.*$": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/named_field"
+ },
+ {
+ "$ref": "#/definitions/detail_type"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "list": {
+ "type": "object",
+ "description": "A list of typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "list"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ },
+ "table": {
+ "type": "object",
+ "description": "A table of typed fields",
+ "required": [
+ "type",
+ "rows"
+ ],
+ "properties": {
+ "type": {
+ "const": "table"
+ },
+ "header": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ },
+ "rows": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ }
+ },
+ "text": {
+ "type": "object",
+ "description": "Raw text",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "text"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "url": {
+ "type": "object",
+ "description": "A single URL",
+ "required": [
+ "type",
+ "href"
+ ],
+ "properties": {
+ "type": {
+ "const": "url"
+ },
+ "text": {
+ "$ref": "#/definitions/text_value"
+ },
+ "href": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "http://mysite.com"
+ ]
+ }
+ }
+ },
+ "code": {
+ "type": "object",
+ "description": "A codeblock",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "code"
+ },
+ "value": {
+ "type": "string"
+ },
+ "lang": {
+ "type": "string",
+ "description": "A programming language"
+ }
+ }
+ },
+ "value": {
+ "type": "object",
+ "description": "A field that can store a range of types of value",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "value"
+ },
+ "value": {
+ "type": [
+ "number",
+ "string",
+ "boolean"
+ ]
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "description": "A diff",
+ "required": [
+ "type",
+ "before",
+ "after"
+ ],
+ "properties": {
+ "type": {
+ "const": "diff"
+ },
+ "before": {
+ "type": "string"
+ },
+ "after": {
+ "type": "string"
+ }
+ }
+ },
+ "markdown": {
+ "type": "object",
+ "description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "markdown"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value",
+ "examples": [
+ "Here is markdown `inline code` #1 [test](gitlab.com)\n\n![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)"
+ ]
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "description": "A commit/tag/branch within the GitLab project",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "commit"
+ },
+ "value": {
+ "type": "string",
+ "description": "The commit SHA",
+ "minLength": 1
+ }
+ }
+ },
+ "file_location": {
+ "type": "object",
+ "description": "A location within a file in the project",
+ "required": [
+ "type",
+ "file_name",
+ "line_start"
+ ],
+ "properties": {
+ "type": {
+ "const": "file-location"
+ },
+ "file_name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "line_start": {
+ "type": "integer"
+ },
+ "line_end": {
+ "type": "integer"
+ }
+ }
+ },
+ "module_location": {
+ "type": "object",
+ "description": "A location within a binary module of the form module+relative_offset",
+ "required": [
+ "type",
+ "module_name",
+ "offset"
+ ],
+ "properties": {
+ "type": {
+ "const": "module-location"
+ },
+ "module_name": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "compiled_binary"
+ ]
+ },
+ "offset": {
+ "type": "integer",
+ "examples": [
+ 100
+ ]
+ }
+ }
+ }
+ },
+ "self": {
+ "version": "15.0.4"
+ },
+ "type": "object",
+ "required": [
+ "dependency_files",
+ "scan",
+ "version",
+ "vulnerabilities"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "scan": {
+ "type": "object",
+ "required": [
+ "analyzer",
+ "end_time",
+ "scanner",
+ "start_time",
+ "status",
+ "type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-01-28T03:26:02"
+ ]
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Communication intended for the initiator of a scan.",
+ "required": [
+ "level",
+ "value"
+ ],
+ "properties": {
+ "level": {
+ "type": "string",
+ "description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
+ "enum": [
+ "info",
+ "warn",
+ "fatal"
+ ],
+ "examples": [
+ "info"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "The message to communicate.",
+ "minLength": 1,
+ "examples": [
+ "Permission denied, scanning aborted"
+ ]
+ }
+ }
+ }
+ },
+ "analyzer": {
+ "type": "object",
+ "description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "gitlab-dast"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the analyzer, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "GitLab DAST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "pattern": "^https?://.+",
+ "description": "A link to more information about the analyzer.",
+ "examples": [
+ "https://docs.gitlab.com/ee/user/application_security/dast"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the analyzer.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ }
+ }
+ },
+ "scanner": {
+ "type": "object",
+ "description": "Object defining the scanner used to perform the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the scanner.",
+ "minLength": 1,
+ "examples": [
+ "my-sast-scanner"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the scanner, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "My SAST Scanner"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "A link to more information about the scanner.",
+ "examples": [
+ "https://scanner.url"
+ ]
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the scanner.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the scanner.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "start_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-02-14T16:01:59"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "description": "Result of the scan.",
+ "enum": [
+ "success",
+ "failure"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of the scan.",
+ "enum": [
+ "dependency_scanning"
+ ]
+ },
+ "primary_identifiers": {
+ "type": "array",
+ "description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^https?://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ }
+ }
+ },
+ "schema": {
+ "type": "string",
+ "description": "URI pointing to the validating security report schema.",
+ "pattern": "^https?://.+"
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the schema to which the JSON report conforms.",
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
+ },
+ "vulnerabilities": {
+ "type": "array",
+ "description": "Array of vulnerability objects.",
+ "items": {
+ "type": "object",
+ "description": "Describes the vulnerability using GitLab Flavored Markdown",
+ "required": [
+ "id",
+ "identifiers",
+ "location"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the vulnerability. This must not include the finding's specific information."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1048576,
+ "description": "A long text section describing the vulnerability more fully."
+ },
+ "severity": {
+ "type": "string",
+ "description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
+ "enum": [
+ "Info",
+ "Unknown",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+ },
+ "solution": {
+ "type": "string",
+ "maxLength": 7000,
+ "description": "Explanation of how to fix the vulnerability."
+ },
+ "identifiers": {
+ "type": "array",
+ "minItems": 1,
+ "description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^https?://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "links": {
+ "type": "array",
+ "description": "An array of references to external documentation or articles that describe the vulnerability.",
+ "items": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the vulnerability details link."
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the vulnerability details document.",
+ "pattern": "^https?://.+"
+ }
+ }
+ }
+ },
+ "details": {
+ "$ref": "#/definitions/named_list/properties/items"
+ },
+ "tracking": {
+ "type": "object",
+ "description": "Describes how this vulnerability should be tracked as the project changes.",
+ "oneOf": [
+ {
+ "description": "Declares that a series of items should be tracked using source-specific tracking methods.",
+ "required": [
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "source"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "description": "An item that should be tracked using source-specific tracking methods.",
+ "type": "object",
+ "required": [
+ "signatures"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the file that includes the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the file that includes the vulnerability."
+ },
+ "signatures": {
+ "type": "array",
+ "description": "An array of calculated tracking signatures for this tracking item.",
+ "minItems": 1,
+ "items": {
+ "description": "A calculated tracking signature value and metadata.",
+ "type": "object",
+ "required": [
+ "algorithm",
+ "value"
+ ],
+ "properties": {
+ "algorithm": {
+ "type": "string",
+ "description": "The algorithm used to generate the signature."
+ },
+ "value": {
+ "type": "string",
+ "description": "The result of this signature algorithm."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Each tracking type must declare its own type."
+ }
+ }
+ },
+ "flags": {
+ "description": "Flags that can be attached to vulnerabilities.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Informational flags identified and assigned to a vulnerability.",
+ "required": [
+ "type",
+ "origin",
+ "description"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Result of the scan.",
+ "enum": [
+ "flagged-as-likely-false-positive"
+ ]
+ },
+ "origin": {
+ "minLength": 1,
+ "description": "Tool that issued the flag.",
+ "type": "string"
+ },
+ "description": {
+ "minLength": 1,
+ "description": "What the flag is about.",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "location": {
+ "type": "object",
+ "description": "Identifies the vulnerability's location.",
+ "required": [
+ "file",
+ "dependency"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Path to the manifest or lock file where the dependency is declared (such as yarn.lock)."
+ },
+ "dependency": {
+ "type": "object",
+ "description": "Describes the dependency of a project where the vulnerability is located.",
+ "required": [
+ "package",
+ "version"
+ ],
+ "properties": {
+ "package": {
+ "type": "object",
+ "description": "Provides information on the package where the vulnerability is located.",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the package where the vulnerability is located."
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "Version of the vulnerable package."
+ },
+ "iid": {
+ "description": "ID that identifies the dependency in the scope of a dependency file.",
+ "type": "number"
+ },
+ "direct": {
+ "type": "boolean",
+ "description": "Tells whether this is a direct, top-level dependency of the scanned project."
+ },
+ "dependency_path": {
+ "type": "array",
+ "description": "Ancestors of the dependency, starting from a direct project dependency, and ending with an immediate parent of the dependency. The dependency itself is excluded from the path. Direct dependencies have no path.",
+ "items": {
+ "type": "object",
+ "required": [
+ "iid"
+ ],
+ "properties": {
+ "iid": {
+ "type": "number",
+ "description": "ID that is unique in the scope of a parent object, and specific to the resource type."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "remediations": {
+ "type": "array",
+ "description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
+ "items": {
+ "type": "object",
+ "required": [
+ "fixes",
+ "summary",
+ "diff"
+ ],
+ "properties": {
+ "fixes": {
+ "type": "array",
+ "description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
+ "items": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ }
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "minLength": 1,
+ "description": "An overview of how the vulnerabilities were fixed."
+ },
+ "diff": {
+ "type": "string",
+ "minLength": 1,
+ "description": "A base64-encoded remediation code diff, compatible with git apply."
+ }
+ }
+ }
+ },
+ "dependency_files": {
+ "type": "array",
+ "description": "List of dependency files identified in the project.",
+ "items": {
+ "type": "object",
+ "required": [
+ "path",
+ "package_manager",
+ "dependencies"
+ ],
+ "properties": {
+ "path": {
+ "type": "string",
+ "minLength": 1
+ },
+ "package_manager": {
+ "type": "string",
+ "minLength": 1
+ },
+ "dependencies": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Describes the dependency of a project where the vulnerability is located.",
+ "required": [
+ "package",
+ "version"
+ ],
+ "properties": {
+ "package": {
+ "type": "object",
+ "description": "Provides information on the package where the vulnerability is located.",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the package where the vulnerability is located."
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "Version of the vulnerable package."
+ },
+ "iid": {
+ "description": "ID that identifies the dependency in the scope of a dependency file.",
+ "type": "number"
+ },
+ "direct": {
+ "type": "boolean",
+ "description": "Tells whether this is a direct, top-level dependency of the scanned project."
+ },
+ "dependency_path": {
+ "type": "array",
+ "description": "Ancestors of the dependency, starting from a direct project dependency, and ending with an immediate parent of the dependency. The dependency itself is excluded from the path. Direct dependencies have no path.",
+ "items": {
+ "type": "object",
+ "required": [
+ "iid"
+ ],
+ "properties": {
+ "iid": {
+ "type": "number",
+ "description": "ID that is unique in the scope of a parent object, and specific to the resource type."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/sast-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/sast-report-format.json
new file mode 100644
index 00000000000..238003f8eb2
--- /dev/null
+++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/sast-report-format.json
@@ -0,0 +1,869 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/sast-report-format.json",
+ "title": "Report format for GitLab SAST",
+ "description": "This schema provides the report format for Static Application Security Testing analyzers (https://docs.gitlab.com/ee/user/application_security/sast).",
+ "definitions": {
+ "detail_type": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/named_list"
+ },
+ {
+ "$ref": "#/definitions/list"
+ },
+ {
+ "$ref": "#/definitions/table"
+ },
+ {
+ "$ref": "#/definitions/text"
+ },
+ {
+ "$ref": "#/definitions/url"
+ },
+ {
+ "$ref": "#/definitions/code"
+ },
+ {
+ "$ref": "#/definitions/value"
+ },
+ {
+ "$ref": "#/definitions/diff"
+ },
+ {
+ "$ref": "#/definitions/markdown"
+ },
+ {
+ "$ref": "#/definitions/commit"
+ },
+ {
+ "$ref": "#/definitions/file_location"
+ },
+ {
+ "$ref": "#/definitions/module_location"
+ }
+ ]
+ },
+ "text_value": {
+ "type": "string"
+ },
+ "named_field": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/text_value",
+ "type": "string",
+ "minLength": 1
+ },
+ "description": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "named_list": {
+ "type": "object",
+ "description": "An object with named and typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "named-list"
+ },
+ "items": {
+ "type": "object",
+ "patternProperties": {
+ "^.*$": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/named_field"
+ },
+ {
+ "$ref": "#/definitions/detail_type"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "list": {
+ "type": "object",
+ "description": "A list of typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "list"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ },
+ "table": {
+ "type": "object",
+ "description": "A table of typed fields",
+ "required": [
+ "type",
+ "rows"
+ ],
+ "properties": {
+ "type": {
+ "const": "table"
+ },
+ "header": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ },
+ "rows": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ }
+ },
+ "text": {
+ "type": "object",
+ "description": "Raw text",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "text"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "url": {
+ "type": "object",
+ "description": "A single URL",
+ "required": [
+ "type",
+ "href"
+ ],
+ "properties": {
+ "type": {
+ "const": "url"
+ },
+ "text": {
+ "$ref": "#/definitions/text_value"
+ },
+ "href": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "http://mysite.com"
+ ]
+ }
+ }
+ },
+ "code": {
+ "type": "object",
+ "description": "A codeblock",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "code"
+ },
+ "value": {
+ "type": "string"
+ },
+ "lang": {
+ "type": "string",
+ "description": "A programming language"
+ }
+ }
+ },
+ "value": {
+ "type": "object",
+ "description": "A field that can store a range of types of value",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "value"
+ },
+ "value": {
+ "type": [
+ "number",
+ "string",
+ "boolean"
+ ]
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "description": "A diff",
+ "required": [
+ "type",
+ "before",
+ "after"
+ ],
+ "properties": {
+ "type": {
+ "const": "diff"
+ },
+ "before": {
+ "type": "string"
+ },
+ "after": {
+ "type": "string"
+ }
+ }
+ },
+ "markdown": {
+ "type": "object",
+ "description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "markdown"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value",
+ "examples": [
+ "Here is markdown `inline code` #1 [test](gitlab.com)\n\n![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)"
+ ]
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "description": "A commit/tag/branch within the GitLab project",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "commit"
+ },
+ "value": {
+ "type": "string",
+ "description": "The commit SHA",
+ "minLength": 1
+ }
+ }
+ },
+ "file_location": {
+ "type": "object",
+ "description": "A location within a file in the project",
+ "required": [
+ "type",
+ "file_name",
+ "line_start"
+ ],
+ "properties": {
+ "type": {
+ "const": "file-location"
+ },
+ "file_name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "line_start": {
+ "type": "integer"
+ },
+ "line_end": {
+ "type": "integer"
+ }
+ }
+ },
+ "module_location": {
+ "type": "object",
+ "description": "A location within a binary module of the form module+relative_offset",
+ "required": [
+ "type",
+ "module_name",
+ "offset"
+ ],
+ "properties": {
+ "type": {
+ "const": "module-location"
+ },
+ "module_name": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "compiled_binary"
+ ]
+ },
+ "offset": {
+ "type": "integer",
+ "examples": [
+ 100
+ ]
+ }
+ }
+ }
+ },
+ "self": {
+ "version": "15.0.4"
+ },
+ "type": "object",
+ "required": [
+ "scan",
+ "version",
+ "vulnerabilities"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "scan": {
+ "type": "object",
+ "required": [
+ "analyzer",
+ "end_time",
+ "scanner",
+ "start_time",
+ "status",
+ "type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-01-28T03:26:02"
+ ]
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Communication intended for the initiator of a scan.",
+ "required": [
+ "level",
+ "value"
+ ],
+ "properties": {
+ "level": {
+ "type": "string",
+ "description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
+ "enum": [
+ "info",
+ "warn",
+ "fatal"
+ ],
+ "examples": [
+ "info"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "The message to communicate.",
+ "minLength": 1,
+ "examples": [
+ "Permission denied, scanning aborted"
+ ]
+ }
+ }
+ }
+ },
+ "analyzer": {
+ "type": "object",
+ "description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "gitlab-dast"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the analyzer, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "GitLab DAST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "pattern": "^https?://.+",
+ "description": "A link to more information about the analyzer.",
+ "examples": [
+ "https://docs.gitlab.com/ee/user/application_security/dast"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the analyzer.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ }
+ }
+ },
+ "scanner": {
+ "type": "object",
+ "description": "Object defining the scanner used to perform the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the scanner.",
+ "minLength": 1,
+ "examples": [
+ "my-sast-scanner"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the scanner, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "My SAST Scanner"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "A link to more information about the scanner.",
+ "examples": [
+ "https://scanner.url"
+ ]
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the scanner.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the scanner.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "start_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-02-14T16:01:59"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "description": "Result of the scan.",
+ "enum": [
+ "success",
+ "failure"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of the scan.",
+ "enum": [
+ "sast"
+ ]
+ },
+ "primary_identifiers": {
+ "type": "array",
+ "description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^https?://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ }
+ }
+ },
+ "schema": {
+ "type": "string",
+ "description": "URI pointing to the validating security report schema.",
+ "pattern": "^https?://.+"
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the schema to which the JSON report conforms.",
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
+ },
+ "vulnerabilities": {
+ "type": "array",
+ "description": "Array of vulnerability objects.",
+ "items": {
+ "type": "object",
+ "description": "Describes the vulnerability using GitLab Flavored Markdown",
+ "required": [
+ "id",
+ "identifiers",
+ "location"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the vulnerability. This must not include the finding's specific information."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1048576,
+ "description": "A long text section describing the vulnerability more fully."
+ },
+ "severity": {
+ "type": "string",
+ "description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
+ "enum": [
+ "Info",
+ "Unknown",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+ },
+ "solution": {
+ "type": "string",
+ "maxLength": 7000,
+ "description": "Explanation of how to fix the vulnerability."
+ },
+ "identifiers": {
+ "type": "array",
+ "minItems": 1,
+ "description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^https?://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "links": {
+ "type": "array",
+ "description": "An array of references to external documentation or articles that describe the vulnerability.",
+ "items": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the vulnerability details link."
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the vulnerability details document.",
+ "pattern": "^https?://.+"
+ }
+ }
+ }
+ },
+ "details": {
+ "$ref": "#/definitions/named_list/properties/items"
+ },
+ "tracking": {
+ "type": "object",
+ "description": "Describes how this vulnerability should be tracked as the project changes.",
+ "oneOf": [
+ {
+ "description": "Declares that a series of items should be tracked using source-specific tracking methods.",
+ "required": [
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "source"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "description": "An item that should be tracked using source-specific tracking methods.",
+ "type": "object",
+ "required": [
+ "signatures"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the file that includes the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the file that includes the vulnerability."
+ },
+ "signatures": {
+ "type": "array",
+ "description": "An array of calculated tracking signatures for this tracking item.",
+ "minItems": 1,
+ "items": {
+ "description": "A calculated tracking signature value and metadata.",
+ "type": "object",
+ "required": [
+ "algorithm",
+ "value"
+ ],
+ "properties": {
+ "algorithm": {
+ "type": "string",
+ "description": "The algorithm used to generate the signature."
+ },
+ "value": {
+ "type": "string",
+ "description": "The result of this signature algorithm."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Each tracking type must declare its own type."
+ }
+ }
+ },
+ "flags": {
+ "description": "Flags that can be attached to vulnerabilities.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Informational flags identified and assigned to a vulnerability.",
+ "required": [
+ "type",
+ "origin",
+ "description"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Result of the scan.",
+ "enum": [
+ "flagged-as-likely-false-positive"
+ ]
+ },
+ "origin": {
+ "minLength": 1,
+ "description": "Tool that issued the flag.",
+ "type": "string"
+ },
+ "description": {
+ "minLength": 1,
+ "description": "What the flag is about.",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "location": {
+ "type": "object",
+ "description": "Identifies the vulnerability's location.",
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the code affected by the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the code affected by the vulnerability."
+ },
+ "class": {
+ "type": "string",
+ "description": "Provides the name of the class where the vulnerability is located."
+ },
+ "method": {
+ "type": "string",
+ "description": "Provides the name of the method where the vulnerability is located."
+ }
+ }
+ },
+ "raw_source_code_extract": {
+ "type": "string",
+ "description": "Provides an unsanitized excerpt of the affected source code."
+ }
+ }
+ }
+ },
+ "remediations": {
+ "type": "array",
+ "description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
+ "items": {
+ "type": "object",
+ "required": [
+ "fixes",
+ "summary",
+ "diff"
+ ],
+ "properties": {
+ "fixes": {
+ "type": "array",
+ "description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
+ "items": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ }
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "minLength": 1,
+ "description": "An overview of how the vulnerabilities were fixed."
+ },
+ "diff": {
+ "type": "string",
+ "minLength": 1,
+ "description": "A base64-encoded remediation code diff, compatible with git apply."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/secret-detection-report-format.json b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/secret-detection-report-format.json
new file mode 100644
index 00000000000..5cc55ea6409
--- /dev/null
+++ b/lib/gitlab/ci/parsers/security/validators/schemas/15.0.4/secret-detection-report-format.json
@@ -0,0 +1,893 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "$id": "https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/raw/master/dist/secret-detection-report-format.json",
+ "title": "Report format for GitLab Secret Detection",
+ "description": "This schema provides the the report format for the Secret Detection analyzer (https://docs.gitlab.com/ee/user/application_security/secret_detection)",
+ "definitions": {
+ "detail_type": {
+ "oneOf": [
+ {
+ "$ref": "#/definitions/named_list"
+ },
+ {
+ "$ref": "#/definitions/list"
+ },
+ {
+ "$ref": "#/definitions/table"
+ },
+ {
+ "$ref": "#/definitions/text"
+ },
+ {
+ "$ref": "#/definitions/url"
+ },
+ {
+ "$ref": "#/definitions/code"
+ },
+ {
+ "$ref": "#/definitions/value"
+ },
+ {
+ "$ref": "#/definitions/diff"
+ },
+ {
+ "$ref": "#/definitions/markdown"
+ },
+ {
+ "$ref": "#/definitions/commit"
+ },
+ {
+ "$ref": "#/definitions/file_location"
+ },
+ {
+ "$ref": "#/definitions/module_location"
+ }
+ ]
+ },
+ "text_value": {
+ "type": "string"
+ },
+ "named_field": {
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "$ref": "#/definitions/text_value",
+ "type": "string",
+ "minLength": 1
+ },
+ "description": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "named_list": {
+ "type": "object",
+ "description": "An object with named and typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "named-list"
+ },
+ "items": {
+ "type": "object",
+ "patternProperties": {
+ "^.*$": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/named_field"
+ },
+ {
+ "$ref": "#/definitions/detail_type"
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "list": {
+ "type": "object",
+ "description": "A list of typed fields",
+ "required": [
+ "type",
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "list"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ },
+ "table": {
+ "type": "object",
+ "description": "A table of typed fields",
+ "required": [
+ "type",
+ "rows"
+ ],
+ "properties": {
+ "type": {
+ "const": "table"
+ },
+ "header": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ },
+ "rows": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/detail_type"
+ }
+ }
+ }
+ }
+ },
+ "text": {
+ "type": "object",
+ "description": "Raw text",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "text"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value"
+ }
+ }
+ },
+ "url": {
+ "type": "object",
+ "description": "A single URL",
+ "required": [
+ "type",
+ "href"
+ ],
+ "properties": {
+ "type": {
+ "const": "url"
+ },
+ "text": {
+ "$ref": "#/definitions/text_value"
+ },
+ "href": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "http://mysite.com"
+ ]
+ }
+ }
+ },
+ "code": {
+ "type": "object",
+ "description": "A codeblock",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "code"
+ },
+ "value": {
+ "type": "string"
+ },
+ "lang": {
+ "type": "string",
+ "description": "A programming language"
+ }
+ }
+ },
+ "value": {
+ "type": "object",
+ "description": "A field that can store a range of types of value",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "value"
+ },
+ "value": {
+ "type": [
+ "number",
+ "string",
+ "boolean"
+ ]
+ }
+ }
+ },
+ "diff": {
+ "type": "object",
+ "description": "A diff",
+ "required": [
+ "type",
+ "before",
+ "after"
+ ],
+ "properties": {
+ "type": {
+ "const": "diff"
+ },
+ "before": {
+ "type": "string"
+ },
+ "after": {
+ "type": "string"
+ }
+ }
+ },
+ "markdown": {
+ "type": "object",
+ "description": "GitLab flavoured markdown, see https://docs.gitlab.com/ee/user/markdown.html",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "markdown"
+ },
+ "value": {
+ "$ref": "#/definitions/text_value",
+ "examples": [
+ "Here is markdown `inline code` #1 [test](gitlab.com)\n\n![GitLab Logo](https://about.gitlab.com/images/press/logo/preview/gitlab-logo-white-preview.png)"
+ ]
+ }
+ }
+ },
+ "commit": {
+ "type": "object",
+ "description": "A commit/tag/branch within the GitLab project",
+ "required": [
+ "type",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "const": "commit"
+ },
+ "value": {
+ "type": "string",
+ "description": "The commit SHA",
+ "minLength": 1
+ }
+ }
+ },
+ "file_location": {
+ "type": "object",
+ "description": "A location within a file in the project",
+ "required": [
+ "type",
+ "file_name",
+ "line_start"
+ ],
+ "properties": {
+ "type": {
+ "const": "file-location"
+ },
+ "file_name": {
+ "type": "string",
+ "minLength": 1
+ },
+ "line_start": {
+ "type": "integer"
+ },
+ "line_end": {
+ "type": "integer"
+ }
+ }
+ },
+ "module_location": {
+ "type": "object",
+ "description": "A location within a binary module of the form module+relative_offset",
+ "required": [
+ "type",
+ "module_name",
+ "offset"
+ ],
+ "properties": {
+ "type": {
+ "const": "module-location"
+ },
+ "module_name": {
+ "type": "string",
+ "minLength": 1,
+ "examples": [
+ "compiled_binary"
+ ]
+ },
+ "offset": {
+ "type": "integer",
+ "examples": [
+ 100
+ ]
+ }
+ }
+ }
+ },
+ "self": {
+ "version": "15.0.4"
+ },
+ "type": "object",
+ "required": [
+ "scan",
+ "version",
+ "vulnerabilities"
+ ],
+ "additionalProperties": true,
+ "properties": {
+ "scan": {
+ "type": "object",
+ "required": [
+ "analyzer",
+ "end_time",
+ "scanner",
+ "start_time",
+ "status",
+ "type"
+ ],
+ "properties": {
+ "end_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan finished.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-01-28T03:26:02"
+ ]
+ },
+ "messages": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Communication intended for the initiator of a scan.",
+ "required": [
+ "level",
+ "value"
+ ],
+ "properties": {
+ "level": {
+ "type": "string",
+ "description": "Describes the severity of the communication. Use info to communicate normal scan behaviour; warn to communicate a potentially recoverable problem, or a partial error; fatal to communicate an issue that causes the scan to halt.",
+ "enum": [
+ "info",
+ "warn",
+ "fatal"
+ ],
+ "examples": [
+ "info"
+ ]
+ },
+ "value": {
+ "type": "string",
+ "description": "The message to communicate.",
+ "minLength": 1,
+ "examples": [
+ "Permission denied, scanning aborted"
+ ]
+ }
+ }
+ }
+ },
+ "analyzer": {
+ "type": "object",
+ "description": "Object defining the analyzer used to perform the scan. Analyzers typically delegate to an underlying scanner to run the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "gitlab-dast"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the analyzer, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "GitLab DAST"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "pattern": "^https?://.+",
+ "description": "A link to more information about the analyzer.",
+ "examples": [
+ "https://docs.gitlab.com/ee/user/application_security/dast"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the analyzer.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the analyzer.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ }
+ }
+ },
+ "scanner": {
+ "type": "object",
+ "description": "Object defining the scanner used to perform the scan.",
+ "required": [
+ "id",
+ "name",
+ "version",
+ "vendor"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "description": "Unique id that identifies the scanner.",
+ "minLength": 1,
+ "examples": [
+ "my-sast-scanner"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "description": "A human readable value that identifies the scanner, not required to be unique.",
+ "minLength": 1,
+ "examples": [
+ "My SAST Scanner"
+ ]
+ },
+ "url": {
+ "type": "string",
+ "description": "A link to more information about the scanner.",
+ "examples": [
+ "https://scanner.url"
+ ]
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the scanner.",
+ "minLength": 1,
+ "examples": [
+ "1.0.2"
+ ]
+ },
+ "vendor": {
+ "description": "The vendor/maintainer of the scanner.",
+ "type": "object",
+ "required": [
+ "name"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "The name of the vendor.",
+ "minLength": 1,
+ "examples": [
+ "GitLab"
+ ]
+ }
+ }
+ }
+ }
+ },
+ "start_time": {
+ "type": "string",
+ "description": "ISO8601 UTC value with format yyyy-mm-ddThh:mm:ss, representing when the scan started.",
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$",
+ "examples": [
+ "2020-02-14T16:01:59"
+ ]
+ },
+ "status": {
+ "type": "string",
+ "description": "Result of the scan.",
+ "enum": [
+ "success",
+ "failure"
+ ]
+ },
+ "type": {
+ "type": "string",
+ "description": "Type of the scan.",
+ "enum": [
+ "secret_detection"
+ ]
+ },
+ "primary_identifiers": {
+ "type": "array",
+ "description": "An unordered array containing an exhaustive list of primary identifiers for which the analyzer may return results",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^https?://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ }
+ }
+ },
+ "schema": {
+ "type": "string",
+ "description": "URI pointing to the validating security report schema.",
+ "pattern": "^https?://.+"
+ },
+ "version": {
+ "type": "string",
+ "description": "The version of the schema to which the JSON report conforms.",
+ "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
+ },
+ "vulnerabilities": {
+ "type": "array",
+ "description": "Array of vulnerability objects.",
+ "items": {
+ "type": "object",
+ "description": "Describes the vulnerability using GitLab Flavored Markdown",
+ "required": [
+ "id",
+ "identifiers",
+ "location"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 255,
+ "description": "The name of the vulnerability. This must not include the finding's specific information."
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 1048576,
+ "description": "A long text section describing the vulnerability more fully."
+ },
+ "severity": {
+ "type": "string",
+ "description": "How much the vulnerability impacts the software. Possible values are Info, Unknown, Low, Medium, High, or Critical. Note that some analyzers may not report all these possible values.",
+ "enum": [
+ "Info",
+ "Unknown",
+ "Low",
+ "Medium",
+ "High",
+ "Critical"
+ ]
+ },
+ "solution": {
+ "type": "string",
+ "maxLength": 7000,
+ "description": "Explanation of how to fix the vulnerability."
+ },
+ "identifiers": {
+ "type": "array",
+ "minItems": 1,
+ "description": "An ordered array of references that identify a vulnerability on internal or external databases. The first identifier is the Primary Identifier, which has special meaning.",
+ "items": {
+ "type": "object",
+ "required": [
+ "type",
+ "name",
+ "value"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "for example, cve, cwe, osvdb, usn, or an analyzer-dependent type such as gemnasium).",
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "description": "Human-readable name of the identifier.",
+ "minLength": 1
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the identifier's documentation.",
+ "pattern": "^https?://.+"
+ },
+ "value": {
+ "type": "string",
+ "description": "Value of the identifier, for matching purpose.",
+ "minLength": 1
+ }
+ }
+ }
+ },
+ "links": {
+ "type": "array",
+ "description": "An array of references to external documentation or articles that describe the vulnerability.",
+ "items": {
+ "type": "object",
+ "required": [
+ "url"
+ ],
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the vulnerability details link."
+ },
+ "url": {
+ "type": "string",
+ "description": "URL of the vulnerability details document.",
+ "pattern": "^https?://.+"
+ }
+ }
+ }
+ },
+ "details": {
+ "$ref": "#/definitions/named_list/properties/items"
+ },
+ "tracking": {
+ "type": "object",
+ "description": "Describes how this vulnerability should be tracked as the project changes.",
+ "oneOf": [
+ {
+ "description": "Declares that a series of items should be tracked using source-specific tracking methods.",
+ "required": [
+ "items"
+ ],
+ "properties": {
+ "type": {
+ "const": "source"
+ },
+ "items": {
+ "type": "array",
+ "items": {
+ "description": "An item that should be tracked using source-specific tracking methods.",
+ "type": "object",
+ "required": [
+ "signatures"
+ ],
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located."
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the file that includes the vulnerability."
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the file that includes the vulnerability."
+ },
+ "signatures": {
+ "type": "array",
+ "description": "An array of calculated tracking signatures for this tracking item.",
+ "minItems": 1,
+ "items": {
+ "description": "A calculated tracking signature value and metadata.",
+ "type": "object",
+ "required": [
+ "algorithm",
+ "value"
+ ],
+ "properties": {
+ "algorithm": {
+ "type": "string",
+ "description": "The algorithm used to generate the signature."
+ },
+ "value": {
+ "type": "string",
+ "description": "The result of this signature algorithm."
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "Each tracking type must declare its own type."
+ }
+ }
+ },
+ "flags": {
+ "description": "Flags that can be attached to vulnerabilities.",
+ "type": "array",
+ "items": {
+ "type": "object",
+ "description": "Informational flags identified and assigned to a vulnerability.",
+ "required": [
+ "type",
+ "origin",
+ "description"
+ ],
+ "properties": {
+ "type": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Result of the scan.",
+ "enum": [
+ "flagged-as-likely-false-positive"
+ ]
+ },
+ "origin": {
+ "minLength": 1,
+ "description": "Tool that issued the flag.",
+ "type": "string"
+ },
+ "description": {
+ "minLength": 1,
+ "description": "What the flag is about.",
+ "type": "string"
+ }
+ }
+ }
+ },
+ "location": {
+ "required": [
+ "commit"
+ ],
+ "type": "object",
+ "properties": {
+ "file": {
+ "type": "string",
+ "description": "Path to the file where the vulnerability is located"
+ },
+ "commit": {
+ "type": "object",
+ "description": "Represents the commit in which the vulnerability was detected",
+ "required": [
+ "sha"
+ ],
+ "properties": {
+ "author": {
+ "type": "string"
+ },
+ "date": {
+ "type": "string"
+ },
+ "message": {
+ "type": "string"
+ },
+ "sha": {
+ "type": "string",
+ "minLength": 1
+ }
+ }
+ },
+ "start_line": {
+ "type": "number",
+ "description": "The first line of the code affected by the vulnerability"
+ },
+ "end_line": {
+ "type": "number",
+ "description": "The last line of the code affected by the vulnerability"
+ },
+ "class": {
+ "type": "string",
+ "description": "Provides the name of the class where the vulnerability is located"
+ },
+ "method": {
+ "type": "string",
+ "description": "Provides the name of the method where the vulnerability is located"
+ }
+ }
+ },
+ "raw_source_code_extract": {
+ "type": "string",
+ "description": "Provides an unsanitized excerpt of the affected source code."
+ }
+ }
+ }
+ },
+ "remediations": {
+ "type": "array",
+ "description": "An array of objects containing information on available remediations, along with patch diffs to apply.",
+ "items": {
+ "type": "object",
+ "required": [
+ "fixes",
+ "summary",
+ "diff"
+ ],
+ "properties": {
+ "fixes": {
+ "type": "array",
+ "description": "An array of strings that represent references to vulnerabilities fixed by this remediation.",
+ "items": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "id": {
+ "type": "string",
+ "minLength": 1,
+ "description": "Unique identifier of the vulnerability. This is recommended to be a UUID.",
+ "examples": [
+ "642735a5-1425-428d-8d4e-3c854885a3c9"
+ ]
+ }
+ }
+ }
+ },
+ "summary": {
+ "type": "string",
+ "minLength": 1,
+ "description": "An overview of how the vulnerabilities were fixed."
+ },
+ "diff": {
+ "type": "string",
+ "minLength": 1,
+ "description": "A base64-encoded remediation code diff, compatible with git apply."
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/lib/gitlab/ci/pipeline/chain/command.rb b/lib/gitlab/ci/pipeline/chain/command.rb
index 76d4a05bf30..5ec04b4889e 100644
--- a/lib/gitlab/ci/pipeline/chain/command.rb
+++ b/lib/gitlab/ci/pipeline/chain/command.rb
@@ -117,7 +117,7 @@ module Gitlab
logger.observe(:pipeline_size_count, pipeline.total_size)
metrics.pipeline_size_histogram
- .observe({ source: pipeline.source.to_s }, pipeline.total_size)
+ .observe({ source: pipeline.source.to_s, plan: project.actual_plan_name }, pipeline.total_size)
end
def observe_jobs_count_in_alive_pipelines
diff --git a/lib/gitlab/ci/pipeline/chain/ensure_environments.rb b/lib/gitlab/ci/pipeline/chain/ensure_environments.rb
index 3dd9b85d9b2..1b9dd158733 100644
--- a/lib/gitlab/ci/pipeline/chain/ensure_environments.rb
+++ b/lib/gitlab/ci/pipeline/chain/ensure_environments.rb
@@ -16,18 +16,7 @@ module Gitlab
private
def ensure_environment(build)
- return unless build.instance_of?(::Ci::Build) && build.has_environment?
-
- environment = ::Gitlab::Ci::Pipeline::Seed::Environment
- .new(build, merge_request: @command.merge_request)
- .to_resource
-
- if environment.persisted?
- build.persisted_environment = environment
- build.assign_attributes(metadata_attributes: { expanded_environment_name: environment.name })
- else
- build.assign_attributes(status: :failed, failure_reason: :environment_creation_failure)
- end
+ ::Environments::CreateForBuildService.new.execute(build, merge_request: @command.merge_request)
end
end
end
diff --git a/lib/gitlab/ci/pipeline/chain/limit/active_jobs.rb b/lib/gitlab/ci/pipeline/chain/limit/active_jobs.rb
index 8b26416edf7..2bb32a316be 100644
--- a/lib/gitlab/ci/pipeline/chain/limit/active_jobs.rb
+++ b/lib/gitlab/ci/pipeline/chain/limit/active_jobs.rb
@@ -21,7 +21,10 @@ module Gitlab
class: self.class.name,
message: MESSAGE,
project_id: project.id,
- plan: project.actual_plan_name)
+ plan: project.actual_plan_name,
+ project_path: project.path,
+ jobs_in_alive_pipelines_count: count_jobs_in_alive_pipelines
+ )
end
def break?
diff --git a/lib/gitlab/ci/pipeline/chain/populate.rb b/lib/gitlab/ci/pipeline/chain/populate.rb
index 4bec8355732..654e24be8e1 100644
--- a/lib/gitlab/ci/pipeline/chain/populate.rb
+++ b/lib/gitlab/ci/pipeline/chain/populate.rb
@@ -25,8 +25,6 @@ module Gitlab
return error('Failed to build the pipeline!')
end
- set_pipeline_name
-
raise Populate::PopulateError if pipeline.persisted?
end
@@ -36,15 +34,6 @@ module Gitlab
private
- def set_pipeline_name
- return if Feature.disabled?(:pipeline_name, pipeline.project) ||
- @command.yaml_processor_result.workflow_name.blank?
-
- name = @command.yaml_processor_result.workflow_name
-
- pipeline.build_pipeline_metadata(project: pipeline.project, title: name)
- end
-
def stage_names
# We filter out `.pre/.post` stages, as they alone are not considered
# a complete pipeline:
diff --git a/lib/gitlab/ci/pipeline/chain/populate_metadata.rb b/lib/gitlab/ci/pipeline/chain/populate_metadata.rb
new file mode 100644
index 00000000000..35b907b669c
--- /dev/null
+++ b/lib/gitlab/ci/pipeline/chain/populate_metadata.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Ci
+ module Pipeline
+ module Chain
+ class PopulateMetadata < Chain::Base
+ include Chain::Helpers
+
+ def perform!
+ set_pipeline_name
+ return if pipeline.pipeline_metadata.nil? || pipeline.pipeline_metadata.valid?
+
+ message = pipeline.pipeline_metadata.errors.full_messages.join(', ')
+ error("Failed to build pipeline metadata! #{message}")
+ end
+
+ def break?
+ pipeline.pipeline_metadata&.errors&.any?
+ end
+
+ private
+
+ def set_pipeline_name
+ return if Feature.disabled?(:pipeline_name, pipeline.project) ||
+ @command.yaml_processor_result.workflow_name.blank?
+
+ name = @command.yaml_processor_result.workflow_name
+ name = ExpandVariables.expand(name, -> { global_context.variables.sort_and_expand_all })
+
+ pipeline.build_pipeline_metadata(project: pipeline.project, name: name)
+ end
+
+ def global_context
+ Gitlab::Ci::Build::Context::Global.new(
+ pipeline, yaml_variables: @command.pipeline_seed.root_variables)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/pipeline/seed/deployment.rb b/lib/gitlab/ci/pipeline/seed/deployment.rb
deleted file mode 100644
index 69dfd6be8d5..00000000000
--- a/lib/gitlab/ci/pipeline/seed/deployment.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Ci
- module Pipeline
- module Seed
- class Deployment < Seed::Base
- attr_reader :job, :environment
-
- def initialize(job, environment)
- @job = job
- @environment = environment
- end
-
- def to_resource
- return job.deployment if job.deployment
- return unless job.starts_environment?
-
- deployment = ::Deployment.new(attributes)
-
- # If there is a validation error on environment creation, such as
- # the name contains invalid character, the job will fall back to a
- # non-environment job.
- return unless deployment.valid? && deployment.environment.persisted?
-
- if cluster = deployment.environment.deployment_platform&.cluster
- # double write cluster_id until 12.9: https://gitlab.com/gitlab-org/gitlab/issues/202628
- deployment.cluster_id = cluster.id
- deployment.deployment_cluster = ::DeploymentCluster.new(
- cluster_id: cluster.id,
- kubernetes_namespace: cluster.kubernetes_namespace_for(deployment.environment, deployable: job)
- )
- end
-
- # Allocate IID for deployments.
- # This operation must be outside of transactions of pipeline creations.
- deployment.ensure_project_iid!
-
- deployment
- end
-
- private
-
- def attributes
- {
- project: job.project,
- environment: environment,
- user: job.user,
- ref: job.ref,
- tag: job.tag,
- sha: job.sha,
- on_stop: job.on_stop
- }
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/ci/pipeline/seed/environment.rb b/lib/gitlab/ci/pipeline/seed/environment.rb
deleted file mode 100644
index 8353bc523bf..00000000000
--- a/lib/gitlab/ci/pipeline/seed/environment.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Ci
- module Pipeline
- module Seed
- class Environment < Seed::Base
- attr_reader :job, :merge_request
-
- delegate :simple_variables, to: :job
-
- def initialize(job, merge_request: nil)
- @job = job
- @merge_request = merge_request
- end
-
- def to_resource
- environments.safe_find_or_create_by(name: expanded_environment_name) do |environment|
- # Initialize the attributes at creation
- environment.auto_stop_in = expanded_auto_stop_in
- environment.tier = deployment_tier
- environment.merge_request = merge_request
- end
- end
-
- private
-
- def environments
- job.project.environments
- end
-
- def auto_stop_in
- job.environment_auto_stop_in
- end
-
- def deployment_tier
- job.environment_tier_from_options
- end
-
- def expanded_environment_name
- job.expanded_environment_name
- end
-
- def expanded_auto_stop_in
- return unless auto_stop_in
-
- ExpandVariables.expand(auto_stop_in, -> { simple_variables.sort_and_expand_all })
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/ci/pipeline/seed/pipeline.rb b/lib/gitlab/ci/pipeline/seed/pipeline.rb
index e1a15fb8d5b..9e609debeed 100644
--- a/lib/gitlab/ci/pipeline/seed/pipeline.rb
+++ b/lib/gitlab/ci/pipeline/seed/pipeline.rb
@@ -32,6 +32,10 @@ module Gitlab
end
end
+ def root_variables
+ @context.root_variables
+ end
+
private
def stage_seeds
diff --git a/lib/gitlab/ci/reports/codequality_reports.rb b/lib/gitlab/ci/reports/codequality_reports.rb
index 353d359fde8..3196bf3fc6d 100644
--- a/lib/gitlab/ci/reports/codequality_reports.rb
+++ b/lib/gitlab/ci/reports/codequality_reports.rb
@@ -37,8 +37,6 @@ module Gitlab
end.to_h
end
- private
-
def valid_degradation?(degradation)
JSONSchemer.schema(Pathname.new(CODECLIMATE_SCHEMA_PATH)).valid?(degradation)
rescue StandardError => _
diff --git a/lib/gitlab/ci/reports/sbom/component.rb b/lib/gitlab/ci/reports/sbom/component.rb
index 198b34451b4..5188304f4ed 100644
--- a/lib/gitlab/ci/reports/sbom/component.rb
+++ b/lib/gitlab/ci/reports/sbom/component.rb
@@ -7,11 +7,34 @@ module Gitlab
class Component
attr_reader :component_type, :name, :version
- def initialize(type:, name:, version:)
+ def initialize(type:, name:, purl:, version:)
@component_type = type
@name = name
+ @purl = purl
@version = version
end
+
+ def ingestible?
+ supported_component_type? && supported_purl_type?
+ end
+
+ def purl
+ return unless @purl
+
+ ::Sbom::PackageUrl.parse(@purl)
+ end
+
+ private
+
+ def supported_component_type?
+ ::Enums::Sbom.component_types.include?(component_type.to_sym)
+ end
+
+ def supported_purl_type?
+ return true unless purl
+
+ ::Enums::Sbom.purl_types.include?(purl.type.to_sym)
+ end
end
end
end
diff --git a/lib/gitlab/ci/reports/sbom/report.rb b/lib/gitlab/ci/reports/sbom/report.rb
index 4f84d12f78c..51fa8ce0d2e 100644
--- a/lib/gitlab/ci/reports/sbom/report.rb
+++ b/lib/gitlab/ci/reports/sbom/report.rb
@@ -12,6 +12,10 @@ module Gitlab
@errors = []
end
+ def valid?
+ errors.empty?
+ end
+
def add_error(error)
errors << error
end
diff --git a/lib/gitlab/ci/reports/security/finding.rb b/lib/gitlab/ci/reports/security/finding.rb
index 911a7f5d358..dd9b9cc6d55 100644
--- a/lib/gitlab/ci/reports/security/finding.rb
+++ b/lib/gitlab/ci/reports/security/finding.rb
@@ -156,6 +156,14 @@ module Gitlab
signatures.present?
end
+ def false_positive?
+ flags.any?(&:false_positive?)
+ end
+
+ def remediation_byte_offsets
+ remediations.map(&:byte_offsets).compact
+ end
+
def raw_metadata
@raw_metadata ||= original_data.to_json
end
@@ -176,6 +184,10 @@ module Gitlab
original_data['location']
end
+ def assets
+ original_data['assets'] || []
+ end
+
# Returns either the max priority signature hex
# or the location fingerprint
def location_fingerprint
diff --git a/lib/gitlab/ci/reports/security/flag.rb b/lib/gitlab/ci/reports/security/flag.rb
index 8370dd60418..e1fbd4c0eff 100644
--- a/lib/gitlab/ci/reports/security/flag.rb
+++ b/lib/gitlab/ci/reports/security/flag.rb
@@ -27,6 +27,10 @@ module Gitlab
description: description
}.compact
end
+
+ def false_positive?
+ flag_type == :false_positive
+ end
end
end
end
diff --git a/lib/gitlab/ci/reports/security/reports.rb b/lib/gitlab/ci/reports/security/reports.rb
index b6372349f68..5c08381d5cc 100644
--- a/lib/gitlab/ci/reports/security/reports.rb
+++ b/lib/gitlab/ci/reports/security/reports.rb
@@ -23,6 +23,10 @@ module Gitlab
end
def violates_default_policy_against?(target_reports, vulnerabilities_allowed, severity_levels, vulnerability_states, report_types = [])
+ if Feature.enabled?(:require_approval_on_scan_removal, pipeline.project) && scan_removed?(target_reports)
+ return true
+ end
+
unsafe_findings_count(target_reports, severity_levels, vulnerability_states, report_types) > vulnerabilities_allowed
end
@@ -36,6 +40,10 @@ module Gitlab
new_uuids = unsafe_findings_uuids(severity_levels, report_types) - target_reports&.unsafe_findings_uuids(severity_levels, report_types).to_a
new_uuids.count
end
+
+ def scan_removed?(target_reports)
+ (target_reports&.reports&.keys.to_a - reports.keys).any?
+ end
end
end
end
diff --git a/lib/gitlab/ci/templates/Bash.gitlab-ci.yml b/lib/gitlab/ci/templates/Bash.gitlab-ci.yml
index 004c2897b60..fb062683397 100644
--- a/lib/gitlab/ci/templates/Bash.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Bash.gitlab-ci.yml
@@ -41,3 +41,4 @@ deploy1:
stage: deploy
script:
- echo "Do your deploy here"
+ environment: production
diff --git a/lib/gitlab/ci/templates/Grails.gitlab-ci.yml b/lib/gitlab/ci/templates/Grails.gitlab-ci.yml
index 01697f67b89..2474bc569d5 100644
--- a/lib/gitlab/ci/templates/Grails.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Grails.gitlab-ci.yml
@@ -26,7 +26,7 @@ variables:
before_script:
- apt-get update -qq && apt-get install -y -qq unzip
- curl -sSL https://get.sdkman.io | bash
- - echo sdkman_auto_answer=true > ~/.sdkman/etc/config
+ - echo sdkman_auto_answer=true >> ~/.sdkman/etc/config
- source ~/.sdkman/bin/sdkman-init.sh
- sdk install gradle $GRADLE_VERSION < /dev/null
- sdk use gradle $GRADLE_VERSION
diff --git a/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml
index d1018f1e769..fcf2ac7de7a 100644
--- a/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml
@@ -1,4 +1,4 @@
-# Read more about the feature here: https://docs.gitlab.com/ee/user/project/merge_requests/browser_performance_testing.html
+# Read more about the feature here: https://docs.gitlab.com/ee/ci/testing/browser_performance_testing.html
browser_performance:
stage: performance
diff --git a/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.latest.gitlab-ci.yml
index bb7e020b159..04b7dacf2dd 100644
--- a/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.latest.gitlab-ci.yml
@@ -1,4 +1,4 @@
-# Read more about the feature here: https://docs.gitlab.com/ee/user/project/merge_requests/browser_performance_testing.html
+# Read more about the feature here: https://docs.gitlab.com/ee/ci/testing/browser_performance_testing.html
browser_performance:
stage: performance
diff --git a/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Build.gitlab-ci.yml
index 071eccbab0d..fc1f4f0cce8 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.19.0'
+ AUTO_BUILD_IMAGE_VERSION: 'v1.21.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 071eccbab0d..fc1f4f0cce8 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.19.0'
+ AUTO_BUILD_IMAGE_VERSION: 'v1.21.0'
build:
stage: build
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 d994ed70ea9..7a208584c4c 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.39.0'
+ DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.42.1'
.dast-auto-deploy:
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${DAST_AUTO_DEPLOY_IMAGE_VERSION}"
diff --git a/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
index 7ad71625436..292b0a0036d 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.39.0'
+ AUTO_DEPLOY_IMAGE_VERSION: 'v2.42.1'
.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 10c843f60a6..ba03ad6304f 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.39.0'
+ AUTO_DEPLOY_IMAGE_VERSION: 'v2.42.1'
.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/Load-Performance-Testing.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml
index eea1c397108..936d8751fe1 100644
--- a/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml
@@ -6,7 +6,7 @@ load_performance:
DOCKER_TLS_CERTDIR: ""
K6_IMAGE: loadimpact/k6
K6_VERSION: 0.27.0
- K6_TEST_FILE: github.com/loadimpact/k6/samples/http_get.js
+ K6_TEST_FILE: raw.githubusercontent.com/grafana/k6/master/samples/http_get.js
K6_OPTIONS: ''
K6_DOCKER_OPTIONS: ''
services:
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 0513aae00a8..77048037915 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
@@ -38,7 +38,7 @@ kics-iac-sast:
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /kics/
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_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.
when: never
- if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead.
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 c0ca821ebff..4600468ef30 100644
--- a/lib/gitlab/ci/templates/Jobs/SAST.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Jobs/SAST.latest.gitlab-ci.yml
@@ -200,7 +200,7 @@ nodejs-scan-sast:
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /nodejs-scan/
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_PIPELINE_SOURCE == "merge_request_event" # Add the job to merge request pipelines if there's an open merge request.
exists:
- '**/package.json'
- if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
@@ -221,7 +221,7 @@ phpcs-security-audit-sast:
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /phpcs-security-audit/
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_PIPELINE_SOURCE == "merge_request_event" # Add the job to merge request pipelines if there's an open merge request.
exists:
- '**/*.php'
- if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
@@ -242,7 +242,7 @@ pmd-apex-sast:
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /pmd-apex/
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_PIPELINE_SOURCE == "merge_request_event" # Add the job to merge request pipelines if there's an open merge request.
exists:
- '**/*.cls'
- if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
@@ -263,7 +263,7 @@ security-code-scan-sast:
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /security-code-scan/
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_PIPELINE_SOURCE == "merge_request_event" # Add the job to merge request pipelines if there's an open merge request.
exists:
- '**/*.csproj'
- '**/*.vbproj'
@@ -287,7 +287,7 @@ semgrep-sast:
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /semgrep/
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_PIPELINE_SOURCE == "merge_request_event" # Add the job to merge request pipelines if there's an open merge request.
exists:
- '**/*.py'
- '**/*.js'
@@ -326,7 +326,7 @@ sobelow-sast:
when: never
- if: $SAST_EXCLUDED_ANALYZERS =~ /sobelow/
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_PIPELINE_SOURCE == "merge_request_event" # Add the job to merge request pipelines if there's an open merge request.
exists:
- 'mix.exs'
- if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
@@ -351,7 +351,7 @@ spotbugs-sast:
when: never
- if: $SAST_DISABLED
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_PIPELINE_SOURCE == "merge_request_event" # Add the job to merge request pipelines if there's an open merge request.
exists:
- '**/*.groovy'
- '**/*.scala'
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 e6eba6f6406..6603ee4268e 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
@@ -29,7 +29,7 @@ secret_detection:
rules:
- if: $SECRET_DETECTION_DISABLED
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_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.
when: never
- if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead.
diff --git a/lib/gitlab/ci/templates/Security/DAST-On-Demand-API-Scan.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/DAST-On-Demand-API-Scan.gitlab-ci.yml
index 1bd527a6ec0..5863da142f0 100644
--- a/lib/gitlab/ci/templates/Security/DAST-On-Demand-API-Scan.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/DAST-On-Demand-API-Scan.gitlab-ci.yml
@@ -2,6 +2,9 @@
# 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/DAST-On-Demand-API-Scan.gitlab-ci.yml
+# NOTE: This template is intended for internal GitLab use only and likely will not work properly
+# in any other project. Do not include it in your pipeline configuration.
+# For information on how to set up and use DAST, visit https://docs.gitlab.com/ee/user/application_security/dast/
stages:
- build
diff --git a/lib/gitlab/ci/templates/Security/DAST-On-Demand-Scan.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/DAST-On-Demand-Scan.gitlab-ci.yml
index 701e08ba56d..733ba4e4954 100644
--- a/lib/gitlab/ci/templates/Security/DAST-On-Demand-Scan.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/DAST-On-Demand-Scan.gitlab-ci.yml
@@ -2,6 +2,9 @@
# 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/DAST-On-Demand-Scan.gitlab-ci.yml
+# NOTE: This template is intended for internal GitLab use only and likely will not work properly
+# in any other project. Do not include it in your pipeline configuration.
+# For information on how to set up and use DAST, visit https://docs.gitlab.com/ee/user/application_security/dast/
stages:
- build
diff --git a/lib/gitlab/ci/templates/Security/DAST-Runner-Validation.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/DAST-Runner-Validation.gitlab-ci.yml
index 5b6af37977e..c75ff2e9ff8 100644
--- a/lib/gitlab/ci/templates/Security/DAST-Runner-Validation.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Security/DAST-Runner-Validation.gitlab-ci.yml
@@ -2,6 +2,9 @@
# 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/DAST-Runner-Validation.gitlab-ci.yml
+# NOTE: This template is intended for internal GitLab use only and likely will not work properly
+# in any other project. Do not include it in your pipeline configuration.
+# For information on how to set up and use DAST, visit https://docs.gitlab.com/ee/user/application_security/dast/
stages:
- build
diff --git a/lib/gitlab/ci/templates/Terraform.gitlab-ci.yml b/lib/gitlab/ci/templates/Terraform.gitlab-ci.yml
index 4d0259fe678..51bcbd278d5 100644
--- a/lib/gitlab/ci/templates/Terraform.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Terraform.gitlab-ci.yml
@@ -12,6 +12,7 @@ stages:
- test
- build
- deploy
+ - cleanup
fmt:
extends: .terraform:fmt
diff --git a/lib/gitlab/ci/templates/Terraform.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Terraform.latest.gitlab-ci.yml
index 019b970bc30..0b6c10293fc 100644
--- a/lib/gitlab/ci/templates/Terraform.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Terraform.latest.gitlab-ci.yml
@@ -12,6 +12,7 @@ stages:
- test
- build
- deploy
+ - cleanup
fmt:
extends: .terraform:fmt
diff --git a/lib/gitlab/ci/templates/Terraform/Base.gitlab-ci.yml b/lib/gitlab/ci/templates/Terraform/Base.gitlab-ci.yml
index 9a40a23b276..dd1676f25b6 100644
--- a/lib/gitlab/ci/templates/Terraform/Base.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Terraform/Base.gitlab-ci.yml
@@ -13,7 +13,7 @@ image:
variables:
TF_ROOT: ${CI_PROJECT_DIR} # The relative path to the root directory of the Terraform project
- TF_STATE_NAME: ${TF_STATE_NAME:-default} # The name of the state file used by the GitLab Managed Terraform state backend
+ TF_STATE_NAME: default # The name of the state file used by the GitLab Managed Terraform state backend
cache:
key: "${TF_ROOT}"
diff --git a/lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml
index 4579f31d7ac..9c967d48de1 100644
--- a/lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Terraform/Base.latest.gitlab-ci.yml
@@ -14,7 +14,7 @@ image:
variables:
TF_ROOT: ${CI_PROJECT_DIR} # The relative path to the root directory of the Terraform project
- TF_STATE_NAME: ${TF_STATE_NAME:-default} # The name of the state file used by the GitLab Managed Terraform state backend
+ TF_STATE_NAME: default # The name of the state file used by the GitLab Managed Terraform state backend
cache:
key: "${TF_ROOT}"
@@ -27,12 +27,22 @@ cache:
- cd "${TF_ROOT}"
- gitlab-terraform fmt
allow_failure: true
+ rules:
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+ - if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
+ when: never
+ - if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead.
.terraform:validate: &terraform_validate
stage: validate
script:
- cd "${TF_ROOT}"
- gitlab-terraform validate
+ rules:
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+ - if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
+ when: never
+ - if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead.
.terraform:build: &terraform_build
stage: build
@@ -46,6 +56,11 @@ cache:
- ${TF_ROOT}/plan.cache
reports:
terraform: ${TF_ROOT}/plan.json
+ rules:
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+ - if: $CI_OPEN_MERGE_REQUESTS # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
+ when: never
+ - if: $CI_COMMIT_BRANCH # If there's no open merge request, add it to a *branch* pipeline instead.
.terraform:deploy: &terraform_deploy
stage: deploy
diff --git a/lib/gitlab/ci/templates/ThemeKit.gitlab-ci.yml b/lib/gitlab/ci/templates/ThemeKit.gitlab-ci.yml
index 8a0913e8f66..47329a602b1 100644
--- a/lib/gitlab/ci/templates/ThemeKit.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/ThemeKit.gitlab-ci.yml
@@ -8,6 +8,7 @@ stages:
- deploy:production
staging:
+ environment: staging
image: python:2
stage: deploy:staging
script:
@@ -18,6 +19,7 @@ staging:
- $CI_DEFAULT_BRANCH == $CI_COMMIT_BRANCH
production:
+ environment: production
image: python:2
stage: deploy:production
script:
diff --git a/lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml b/lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml
index 2349c37c130..c3113ffebf3 100644
--- a/lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml
@@ -3,7 +3,7 @@
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Verify/Browser-Performance.gitlab-ci.yml
-# Read more about the feature here: https://docs.gitlab.com/ee/user/project/merge_requests/browser_performance_testing.html
+# Read more about the feature here: https://docs.gitlab.com/ee/ci/testing/browser_performance_testing.html
stages:
- build
diff --git a/lib/gitlab/ci/templates/Verify/Browser-Performance.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Verify/Browser-Performance.latest.gitlab-ci.yml
index 73ab5fcbe44..c9f0c173692 100644
--- a/lib/gitlab/ci/templates/Verify/Browser-Performance.latest.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Verify/Browser-Performance.latest.gitlab-ci.yml
@@ -3,7 +3,7 @@
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Verify/Browser-Performance.latest.gitlab-ci.yml
-# Read more about the feature here: https://docs.gitlab.com/ee/user/project/merge_requests/browser_performance_testing.html
+# Read more about the feature here: https://docs.gitlab.com/ee/ci/testing/browser_performance_testing.html
stages:
- build
diff --git a/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml b/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml
index 53fabcfc721..bf5cfbb519d 100644
--- a/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml
@@ -3,7 +3,7 @@
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml
-# Read more about the feature here: https://docs.gitlab.com/ee/user/project/merge_requests/load_performance_testing.html
+# Read more about the feature here: https://docs.gitlab.com/ee/ci/testing/code_quality.html
stages:
- build
@@ -17,7 +17,7 @@ load_performance:
variables:
K6_IMAGE: loadimpact/k6
K6_VERSION: 0.27.0
- K6_TEST_FILE: github.com/loadimpact/k6/samples/http_get.js
+ K6_TEST_FILE: raw.githubusercontent.com/grafana/k6/master/samples/http_get.js
K6_OPTIONS: ''
K6_DOCKER_OPTIONS: ''
services:
diff --git a/lib/gitlab/ci/templates/dotNET.gitlab-ci.yml b/lib/gitlab/ci/templates/dotNET.gitlab-ci.yml
index 50ce181095e..8dfb6c38b55 100644
--- a/lib/gitlab/ci/templates/dotNET.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/dotNET.gitlab-ci.yml
@@ -89,3 +89,4 @@ deploy_job:
dependencies:
- build_job
- test_job
+ environment: production
diff --git a/lib/gitlab/ci/variables/builder.rb b/lib/gitlab/ci/variables/builder.rb
index cf5f04215ad..8db8ea3a720 100644
--- a/lib/gitlab/ci/variables/builder.rb
+++ b/lib/gitlab/ci/variables/builder.rb
@@ -171,16 +171,6 @@ module Gitlab
end
end
- def strong_memoize_with(name, *args)
- container = strong_memoize(name) { {} }
-
- if container.key?(args)
- container[args]
- else
- container[args] = yield
- end
- end
-
def release
return unless @pipeline.tag?
diff --git a/lib/gitlab/ci/variables/collection.rb b/lib/gitlab/ci/variables/collection.rb
index b6d6e1a3e5f..e9766061072 100644
--- a/lib/gitlab/ci/variables/collection.rb
+++ b/lib/gitlab/ci/variables/collection.rb
@@ -72,7 +72,8 @@ module Gitlab
Collection.new(@variables.reject(&block))
end
- def expand_value(value, keep_undefined: false, expand_file_vars: true, project: nil)
+ # `expand_raw_refs` will be deleted with the FF `ci_raw_variables_in_yaml_config`.
+ def expand_value(value, keep_undefined: false, expand_file_refs: true, expand_raw_refs: true, project: nil)
value.gsub(Item::VARIABLES_REGEXP) do
match = Regexp.last_match # it is either a valid variable definition or a ($$ / %%)
full_match = match[0]
@@ -86,19 +87,26 @@ module Gitlab
variable = self[variable_name]
if variable # VARIABLE_NAME is an existing variable
- next variable.value unless variable.file?
-
- # Will be cleaned up with https://gitlab.com/gitlab-org/gitlab/-/issues/378266
- if project
- # We only log if `project` exists to make sure it is called from `Ci::BuildRunnerPresenter`
- # when the variables are sent to Runner.
- Gitlab::AppJsonLogger.info(
- event: 'file_variable_is_referenced_in_another_variable',
- project_id: project.id
- )
+ if variable.file?
+ # Will be cleaned up with https://gitlab.com/gitlab-org/gitlab/-/issues/378266
+ if project
+ # We only log if `project` exists to make sure it is called from `Ci::BuildRunnerPresenter`
+ # when the variables are sent to Runner.
+ Gitlab::AppJsonLogger.info(event: 'file_variable_is_referenced_in_another_variable',
+ project_id: project.id,
+ variable: variable_name)
+ end
+
+ expand_file_refs ? variable.value : full_match
+ elsif variable.raw?
+ # With `full_match`, we defer the expansion of raw variables to the runner. If we expand them here,
+ # the runner will not know the expanded value is a raw variable and it tries to expand it again.
+ # Discussion: https://gitlab.com/gitlab-org/gitlab/-/issues/353991#note_1103274951
+ expand_raw_refs ? variable.value : full_match
+ else
+ variable.value
end
- expand_file_vars ? variable.value : full_match
elsif keep_undefined
full_match # we do not touch the variable definition
else
@@ -107,7 +115,8 @@ module Gitlab
end
end
- def sort_and_expand_all(keep_undefined: false, expand_file_vars: true, project: nil)
+ # `expand_raw_refs` will be deleted with the FF `ci_raw_variables_in_yaml_config`.
+ def sort_and_expand_all(keep_undefined: false, expand_file_refs: true, expand_raw_refs: true, project: nil)
sorted = Sort.new(self)
return self.class.new(self, sorted.errors) unless sorted.valid?
@@ -122,7 +131,8 @@ module Gitlab
# expand variables as they are added
variable = item.to_runner_variable
variable[:value] = new_collection.expand_value(variable[:value], keep_undefined: keep_undefined,
- expand_file_vars: expand_file_vars,
+ expand_file_refs: expand_file_refs,
+ expand_raw_refs: expand_raw_refs,
project: project)
new_collection.append(variable)
end
diff --git a/lib/gitlab/ci/variables/collection/item.rb b/lib/gitlab/ci/variables/collection/item.rb
index ea2aa8f2db8..0fcf11121fa 100644
--- a/lib/gitlab/ci/variables/collection/item.rb
+++ b/lib/gitlab/ci/variables/collection/item.rb
@@ -21,9 +21,10 @@ module Gitlab
@variable.fetch(:value)
end
- def raw
+ def raw?
@variable.fetch(:raw)
end
+ alias_method :raw, :raw?
def file?
@variable.fetch(:file)
@@ -39,7 +40,7 @@ module Gitlab
def depends_on
strong_memoize(:depends_on) do
- next if raw
+ next if raw?
next unless self.class.possible_var_reference?(value)
@@ -48,9 +49,8 @@ module Gitlab
end
##
- # If `file: true` has been provided we expose it, otherwise we
- # don't expose `file` attribute at all (stems from what the runner
- # expects).
+ # If `file: true` or `raw: true` has been provided we expose it, otherwise we
+ # don't expose `file` and `raw` attributes at all (stems from what the runner expects).
#
def to_runner_variable
@variable.reject do |hash_key, hash_value|
diff --git a/lib/gitlab/ci/yaml_processor/result.rb b/lib/gitlab/ci/yaml_processor/result.rb
index 5c3864362da..ff255543d3b 100644
--- a/lib/gitlab/ci/yaml_processor/result.rb
+++ b/lib/gitlab/ci/yaml_processor/result.rb
@@ -6,12 +6,17 @@ module Gitlab
module Ci
class YamlProcessor
class Result
- attr_reader :errors, :warnings
+ attr_reader :errors, :warnings,
+ :root_variables, :root_variables_with_prefill_data,
+ :stages, :jobs,
+ :workflow_rules, :workflow_name
def initialize(ci_config: nil, errors: [], warnings: [])
@ci_config = ci_config
@errors = errors || []
@warnings = warnings || []
+
+ assign_valid_attributes if valid?
end
def valid?
@@ -32,34 +37,10 @@ module Gitlab
end
end
- def workflow_rules
- @workflow_rules ||= @ci_config.workflow_rules
- end
-
- def workflow_name
- @workflow_name ||= @ci_config.workflow_name&.strip
- end
-
- def root_variables
- @root_variables ||= transform_to_array(@ci_config.variables)
- end
-
- def jobs
- @jobs ||= @ci_config.normalized_jobs
- end
-
- def stages
- @stages ||= @ci_config.stages
- end
-
def included_templates
@included_templates ||= @ci_config.included_templates
end
- def variables_with_data
- @ci_config.variables_with_data
- end
-
def yaml_variables_for(job_name)
job = jobs[job_name]
@@ -82,6 +63,22 @@ module Gitlab
private
+ def assign_valid_attributes
+ @root_variables = if YamlProcessor::FeatureFlags.enabled?(:ci_raw_variables_in_yaml_config)
+ transform_to_array(@ci_config.variables_with_data)
+ else
+ transform_to_array(@ci_config.variables)
+ end
+
+ @root_variables_with_prefill_data = @ci_config.variables_with_prefill_data
+
+ @stages = @ci_config.stages
+ @jobs = @ci_config.normalized_jobs
+
+ @workflow_rules = @ci_config.workflow_rules
+ @workflow_name = @ci_config.workflow_name&.strip
+ end
+
def stage_builds_attributes(stage)
jobs.values
.select { |job| job[:stage] == stage }
@@ -129,14 +126,10 @@ module Gitlab
start_in: job[:start_in],
trigger: job[:trigger],
bridge_needs: job.dig(:needs, :bridge)&.first,
- release: release(job)
+ release: job[:release]
}.compact }.compact
end
- def release(job)
- job[:release]
- end
-
def transform_to_array(variables)
::Gitlab::Ci::Variables::Helpers.transform_to_array(variables)
end
diff --git a/lib/gitlab/cluster/lifecycle_events.rb b/lib/gitlab/cluster/lifecycle_events.rb
index be08ada9d2f..b39d2a02f02 100644
--- a/lib/gitlab/cluster/lifecycle_events.rb
+++ b/lib/gitlab/cluster/lifecycle_events.rb
@@ -63,6 +63,15 @@ module Gitlab
#
# Sidekiq/Puma Single: This is called immediately.
#
+ # - on_worker_stop (on worker process):
+ #
+ # Puma Cluster: Called in the worker process
+ # exactly once after it stops processing requests
+ # but before it shuts down.
+ #
+ # Sidekiq: Called after the scheduler shuts down but
+ # before the worker finishes ongoing jobs.
+ #
# Blocks will be executed in the order in which they are registered.
#
class LifecycleEvents
@@ -113,6 +122,10 @@ module Gitlab
end
end
+ def on_worker_stop(&block)
+ (@worker_stop_hooks ||= []) << block
+ end
+
#
# Lifecycle integration methods (called from puma.rb, etc.)
#
@@ -137,6 +150,10 @@ module Gitlab
call(:master_restart_hooks, @master_restart_hooks)
end
+ def do_worker_stop
+ call(:worker_stop_hooks, @worker_stop_hooks)
+ end
+
# DEPRECATED
alias_method :do_master_restart, :do_before_master_restart
diff --git a/lib/gitlab/cluster/puma_worker_killer_initializer.rb b/lib/gitlab/cluster/puma_worker_killer_initializer.rb
index 5908de68687..957faf797b5 100644
--- a/lib/gitlab/cluster/puma_worker_killer_initializer.rb
+++ b/lib/gitlab/cluster/puma_worker_killer_initializer.rb
@@ -9,6 +9,10 @@ module Gitlab
puma_master_max_memory_mb: 950,
additional_puma_dev_max_memory_mb: 200)
+ # We are replacing PWK with Watchdog by using backward compatible RssMemoryLimit monitor by default.
+ # https://gitlab.com/groups/gitlab-org/-/epics/9119
+ return if Gitlab::Utils.to_boolean(ENV.fetch('GITLAB_MEMORY_WATCHDOG_ENABLED', true))
+
require 'puma_worker_killer'
PumaWorkerKiller.config do |config|
diff --git a/lib/gitlab/config_checker/external_database_checker.rb b/lib/gitlab/config_checker/external_database_checker.rb
index 64950fb4eef..ff20833b5be 100644
--- a/lib/gitlab/config_checker/external_database_checker.rb
+++ b/lib/gitlab/config_checker/external_database_checker.rb
@@ -9,19 +9,23 @@ module Gitlab
'<a href="https://docs.gitlab.com/ee/install/requirements.html#database">database requirements</a>'
def check
- unsupported_database = Gitlab::Database
+ unsupported_databases = Gitlab::Database
.database_base_models
- .map { |_, model| Gitlab::Database::Reflection.new(model) }
- .reject(&:postgresql_minimum_supported_version?)
+ .each_with_object({}) do |(database_name, base_model), databases|
+ database = Gitlab::Database::Reflection.new(base_model)
- unsupported_database.map do |database|
+ databases[database_name] = database unless database.postgresql_minimum_supported_version?
+ end
+
+ unsupported_databases.map do |database_name, database|
{
type: 'warning',
- message: _('You are using PostgreSQL %{pg_version_current}, but PostgreSQL ' \
- '%{pg_version_minimum} is required for this version of GitLab. ' \
+ message: _('Database \'%{database_name}\' is using PostgreSQL %{pg_version_current}, ' \
+ 'but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. ' \
'Please upgrade your environment to a supported PostgreSQL version, ' \
'see %{pg_requirements_url} for details.') % \
{
+ database_name: database_name,
pg_version_current: database.version,
pg_version_minimum: Gitlab::Database::MINIMUM_POSTGRES_VERSION,
pg_requirements_url: PG_REQUIREMENTS_LINK
diff --git a/lib/gitlab/container_repository/tags/cache.rb b/lib/gitlab/container_repository/tags/cache.rb
index 47a6e67a5a1..f9de16f002f 100644
--- a/lib/gitlab/container_repository/tags/cache.rb
+++ b/lib/gitlab/container_repository/tags/cache.rb
@@ -18,7 +18,7 @@ module Gitlab
keys = tags.map(&method(:cache_key))
cached_tags_count = 0
- ::Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
tags.zip(redis.mget(keys)).each do |tag, created_at|
next unless created_at
@@ -45,7 +45,7 @@ module Gitlab
now = Time.zone.now
- ::Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
# we use a pipeline instead of a MSET because each tag has
# a specific ttl
redis.pipelined do |pipeline|
@@ -66,6 +66,10 @@ module Gitlab
def cache_key(tag)
"container_repository:{#{@container_repository.id}}:tag:#{tag.name}:created_at"
end
+
+ def with_redis(&block)
+ ::Gitlab::Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord
+ end
end
end
end
diff --git a/lib/gitlab/content_security_policy/config_loader.rb b/lib/gitlab/content_security_policy/config_loader.rb
index f1faade250e..29e8e631fb7 100644
--- a/lib/gitlab/content_security_policy/config_loader.rb
+++ b/lib/gitlab/content_security_policy/config_loader.rb
@@ -24,7 +24,7 @@ module Gitlab
'frame_src' => ContentSecurityPolicy::Directives.frame_src,
'img_src' => "'self' data: blob: http: https:",
'manifest_src' => "'self'",
- 'media_src' => "'self' data:",
+ 'media_src' => "'self' data: http: https:",
'script_src' => ContentSecurityPolicy::Directives.script_src,
'style_src' => "'self' 'unsafe-inline'",
'worker_src' => "#{Gitlab::Utils.append_path(Gitlab.config.gitlab.url, 'assets/')} blob: data:",
diff --git a/lib/gitlab/data_builder/build.rb b/lib/gitlab/data_builder/build.rb
index 4640f85bb0a..8eda871770b 100644
--- a/lib/gitlab/data_builder/build.rb
+++ b/lib/gitlab/data_builder/build.rb
@@ -12,7 +12,7 @@ module Gitlab
author_url = build_author_url(build.commit, commit)
- {
+ data = {
object_kind: 'build',
ref: build.ref,
@@ -68,6 +68,10 @@ module Gitlab
environment: build_environment(build)
}
+
+ data[:retries_count] = build.retries_count if Feature.enabled?(:job_webhook_retries_count, project)
+
+ data
end
private
@@ -91,7 +95,7 @@ module Gitlab
end
def build_environment(build)
- return unless build.has_environment?
+ return unless build.has_environment_keyword?
{
name: build.expanded_environment_name,
diff --git a/lib/gitlab/data_builder/pipeline.rb b/lib/gitlab/data_builder/pipeline.rb
index a75c7c539ae..939eaa377aa 100644
--- a/lib/gitlab/data_builder/pipeline.rb
+++ b/lib/gitlab/data_builder/pipeline.rb
@@ -105,6 +105,7 @@ module Gitlab
target_project_id: merge_request.target_project_id,
state: merge_request.state,
merge_status: merge_request.public_merge_status,
+ detailed_merge_status: detailed_merge_status(merge_request),
url: Gitlab::UrlBuilder.build(merge_request)
}
end
@@ -146,7 +147,7 @@ module Gitlab
end
def environment_hook_attrs(build)
- return unless build.has_environment?
+ return unless build.has_environment_keyword?
{
name: build.expanded_environment_name,
@@ -154,6 +155,10 @@ module Gitlab
deployment_tier: build.persisted_environment.try(:tier)
}
end
+
+ def detailed_merge_status(merge_request)
+ ::MergeRequests::Mergeability::DetailedMergeStatusService.new(merge_request: merge_request).execute.to_s
+ end
end
end
end
diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb
index dd84127459d..04cf056199c 100644
--- a/lib/gitlab/database.rb
+++ b/lib/gitlab/database.rb
@@ -56,7 +56,7 @@ module Gitlab
# Note that we use ActiveRecord::Base here and not ApplicationRecord.
# This is deliberate, as we also use these classes to apply load
# balancing to, and the load balancer must be enabled for _all_ models
- # that inher from ActiveRecord::Base; not just our own models that
+ # that inherit from ActiveRecord::Base; not just our own models that
# inherit from ApplicationRecord.
main: ::ActiveRecord::Base,
ci: ::Ci::ApplicationRecord.connection_class? ? ::Ci::ApplicationRecord : nil
@@ -217,13 +217,13 @@ module Gitlab
Rails.application.config.paths['db'].each do |db_path|
path = Rails.root.join(db_path, 'post_migrate').to_s
- unless Rails.application.config.paths['db/migrate'].include? path
- Rails.application.config.paths['db/migrate'] << path
+ next if Rails.application.config.paths['db/migrate'].include? path
- # Rails memoizes migrations at certain points where it won't read the above
- # path just yet. As such we must also update the following list of paths.
- ActiveRecord::Migrator.migrations_paths << path
- end
+ Rails.application.config.paths['db/migrate'] << path
+
+ # Rails memoizes migrations at certain points where it won't read the above
+ # path just yet. As such we must also update the following list of paths.
+ ActiveRecord::Migrator.migrations_paths << path
end
end
diff --git a/lib/gitlab/database/background_migration/batched_job.rb b/lib/gitlab/database/background_migration/batched_job.rb
index 81898a59da7..6b7ff308c7e 100644
--- a/lib/gitlab/database/background_migration/batched_job.rb
+++ b/lib/gitlab/database/background_migration/batched_job.rb
@@ -14,7 +14,8 @@ module Gitlab
MAX_ATTEMPTS = 3
STUCK_JOBS_TIMEOUT = 1.hour.freeze
TIMEOUT_EXCEPTIONS = [ActiveRecord::StatementTimeout, ActiveRecord::ConnectionTimeoutError,
- ActiveRecord::AdapterTimeout, ActiveRecord::LockWaitTimeout].freeze
+ ActiveRecord::AdapterTimeout, ActiveRecord::LockWaitTimeout,
+ ActiveRecord::QueryCanceled].freeze
belongs_to :batched_migration, foreign_key: :batched_background_migration_id
has_many :batched_job_transition_logs, foreign_key: :batched_background_migration_job_id
@@ -112,7 +113,10 @@ module Gitlab
end
def can_split?(exception)
- attempts >= MAX_ATTEMPTS && TIMEOUT_EXCEPTIONS.include?(exception&.class) && batch_size > sub_batch_size && batch_size > 1
+ attempts >= MAX_ATTEMPTS &&
+ exception&.class&.in?(TIMEOUT_EXCEPTIONS) &&
+ batch_size > sub_batch_size &&
+ batch_size > 1
end
def split_and_retry!
diff --git a/lib/gitlab/database/background_migration/batched_migration.rb b/lib/gitlab/database/background_migration/batched_migration.rb
index 92cafd1d00e..61a660ad14c 100644
--- a/lib/gitlab/database/background_migration/batched_migration.rb
+++ b/lib/gitlab/database/background_migration/batched_migration.rb
@@ -94,8 +94,21 @@ module Gitlab
end
def self.active_migration(connection:)
+ active_migrations_distinct_on_table(connection: connection, limit: 1).first
+ end
+
+ def self.find_executable(id, connection:)
for_gitlab_schema(Gitlab::Database.gitlab_schemas_for_connection(connection))
- .executable.queue_order.first
+ .executable.find_by_id(id)
+ end
+
+ def self.active_migrations_distinct_on_table(connection:, limit:)
+ distinct_on_table = select('DISTINCT ON (table_name) id')
+ .for_gitlab_schema(Gitlab::Database.gitlab_schemas_for_connection(connection))
+ .executable
+ .order(table_name: :asc, id: :asc)
+
+ where(id: distinct_on_table).queue_order.limit(limit)
end
def self.successful_rows_counts(migrations)
diff --git a/lib/gitlab/database/gitlab_schemas.yml b/lib/gitlab/database/gitlab_schemas.yml
index c4a9cf8b80f..bf6ebb21f7d 100644
--- a/lib/gitlab/database/gitlab_schemas.yml
+++ b/lib/gitlab/database/gitlab_schemas.yml
@@ -40,6 +40,7 @@ atlassian_identities: :gitlab_main
audit_events_external_audit_event_destinations: :gitlab_main
audit_events: :gitlab_main
audit_events_streaming_headers: :gitlab_main
+audit_events_streaming_event_type_filters: :gitlab_main
authentication_events: :gitlab_main
award_emoji: :gitlab_main
aws_roles: :gitlab_main
@@ -167,6 +168,7 @@ dast_site_profiles_pipelines: :gitlab_main
dast_sites: :gitlab_main
dast_site_tokens: :gitlab_main
dast_site_validations: :gitlab_main
+dependency_proxy_blob_states: :gitlab_main
dependency_proxy_blobs: :gitlab_main
dependency_proxy_group_settings: :gitlab_main
dependency_proxy_image_ttl_group_policies: :gitlab_main
@@ -206,7 +208,6 @@ events: :gitlab_main
evidences: :gitlab_main
experiments: :gitlab_main
experiment_subjects: :gitlab_main
-experiment_users: :gitlab_main
external_approval_rules: :gitlab_main
external_approval_rules_protected_branches: :gitlab_main
external_pull_requests: :gitlab_ci
@@ -342,6 +343,7 @@ namespace_limits: :gitlab_main
namespace_package_settings: :gitlab_main
namespace_root_storage_statistics: :gitlab_main
namespace_ci_cd_settings: :gitlab_main
+namespace_commit_emails: :gitlab_main
namespace_settings: :gitlab_main
namespace_details: :gitlab_main
namespaces: :gitlab_main
@@ -363,6 +365,7 @@ operations_scopes: :gitlab_main
operations_strategies: :gitlab_main
operations_strategies_user_lists: :gitlab_main
operations_user_lists: :gitlab_main
+p_ci_builds_metadata: :gitlab_ci
packages_build_infos: :gitlab_main
packages_cleanup_policies: :gitlab_main
packages_composer_cache_files: :gitlab_main
@@ -451,6 +454,7 @@ projects: :gitlab_main
projects_sync_events: :gitlab_main
project_statistics: :gitlab_main
project_topics: :gitlab_main
+project_wiki_repositories: :gitlab_main
project_wiki_repository_states: :gitlab_main
prometheus_alert_events: :gitlab_main
prometheus_alerts: :gitlab_main
diff --git a/lib/gitlab/database/load_balancing/configuration.rb b/lib/gitlab/database/load_balancing/configuration.rb
index 59b08fac7e9..50472bd5780 100644
--- a/lib/gitlab/database/load_balancing/configuration.rb
+++ b/lib/gitlab/database/load_balancing/configuration.rb
@@ -57,7 +57,8 @@ module Gitlab
record_type: 'A',
interval: 60,
disconnect_timeout: 120,
- use_tcp: false
+ use_tcp: false,
+ max_replica_pools: nil
}
end
diff --git a/lib/gitlab/database/load_balancing/load_balancer.rb b/lib/gitlab/database/load_balancing/load_balancer.rb
index 0881025b425..cb3a378ad64 100644
--- a/lib/gitlab/database/load_balancing/load_balancer.rb
+++ b/lib/gitlab/database/load_balancing/load_balancer.rb
@@ -119,6 +119,13 @@ module Gitlab
connection = pool.connection
transaction_open = connection.transaction_open?
+ if attempt && attempt > 1
+ ::Gitlab::Database::LoadBalancing::Logger.warn(
+ event: :read_write_retry,
+ message: 'A read_write block was retried because of connection error'
+ )
+ end
+
yield connection
rescue StandardError => e
# No leaking will happen on the final attempt. Leaks are caused by subsequent retries
diff --git a/lib/gitlab/database/load_balancing/service_discovery.rb b/lib/gitlab/database/load_balancing/service_discovery.rb
index dfd4892371c..52a9e8798d4 100644
--- a/lib/gitlab/database/load_balancing/service_discovery.rb
+++ b/lib/gitlab/database/load_balancing/service_discovery.rb
@@ -48,6 +48,7 @@ module Gitlab
# forcefully disconnected.
# use_tcp - Use TCP instaed of UDP to look up resources
# load_balancer - The load balancer instance to use
+ # rubocop:disable Metrics/ParameterLists
def initialize(
load_balancer,
nameserver:,
@@ -56,7 +57,8 @@ module Gitlab
record_type: 'A',
interval: 60,
disconnect_timeout: 120,
- use_tcp: false
+ use_tcp: false,
+ max_replica_pools: nil
)
@nameserver = nameserver
@port = port
@@ -66,7 +68,9 @@ module Gitlab
@disconnect_timeout = disconnect_timeout
@use_tcp = use_tcp
@load_balancer = load_balancer
+ @max_replica_pools = max_replica_pools
end
+ # rubocop:enable Metrics/ParameterLists
def start
Thread.new do
@@ -170,6 +174,8 @@ module Gitlab
addresses_from_srv_record(response)
end
+ addresses = sampler.sample(addresses)
+
raise EmptyDnsResponse if addresses.empty?
# Addresses are sorted so we can directly compare the old and new
@@ -221,6 +227,11 @@ module Gitlab
def addresses_from_a_record(resources)
resources.map { |r| Address.new(r.address.to_s) }
end
+
+ def sampler
+ @sampler ||= ::Gitlab::Database::LoadBalancing::ServiceDiscovery::Sampler
+ .new(max_replica_pools: @max_replica_pools)
+ end
end
end
end
diff --git a/lib/gitlab/database/load_balancing/service_discovery/sampler.rb b/lib/gitlab/database/load_balancing/service_discovery/sampler.rb
new file mode 100644
index 00000000000..71870214156
--- /dev/null
+++ b/lib/gitlab/database/load_balancing/service_discovery/sampler.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module LoadBalancing
+ class ServiceDiscovery
+ class Sampler
+ def initialize(max_replica_pools:, seed: Random.new_seed)
+ # seed must be set once and consistent
+ # for every invocation of #sample on
+ # the same instance of Sampler
+ @seed = seed
+ @max_replica_pools = max_replica_pools
+ end
+
+ def sample(addresses)
+ return addresses if @max_replica_pools.nil? || addresses.count <= @max_replica_pools
+
+ ::Gitlab::Database::LoadBalancing::Logger.info(
+ event: :host_list_limit_exceeded,
+ message: "Host list length exceeds max_replica_pools so random hosts will be chosen.",
+ max_replica_pools: @max_replica_pools,
+ total_host_list_length: addresses.count,
+ randomization_seed: @seed
+ )
+
+ # First sort them in case the ordering from DNS server changes
+ # then randomly order all addresses using consistent seed so
+ # this process always gives the same set for this instance of
+ # Sampler
+ addresses = addresses.sort
+ addresses = addresses.shuffle(random: Random.new(@seed))
+
+ # Group by hostname so that we can sample evenly across hosts
+ addresses_by_host = addresses.group_by(&:hostname)
+
+ selected_addresses = []
+ while selected_addresses.count < @max_replica_pools
+ # Loop over all hostnames grabbing one address at a time to
+ # evenly distribute across all hostnames
+ addresses_by_host.each do |host, addresses|
+ next if addresses.empty?
+
+ selected_addresses << addresses.pop
+
+ break unless selected_addresses.count < @max_replica_pools
+ end
+ end
+
+ selected_addresses
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb b/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb
index 3180289ec69..737852d5ccb 100644
--- a/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb
+++ b/lib/gitlab/database/load_balancing/sidekiq_server_middleware.rb
@@ -4,7 +4,7 @@ module Gitlab
module Database
module LoadBalancing
class SidekiqServerMiddleware
- JobReplicaNotUpToDate = Class.new(StandardError)
+ JobReplicaNotUpToDate = Class.new(::Gitlab::SidekiqMiddleware::RetryError)
MINIMUM_DELAY_INTERVAL_SECONDS = 0.8
diff --git a/lib/gitlab/database/lock_writes_manager.rb b/lib/gitlab/database/lock_writes_manager.rb
index fe75cd763b4..2594ee04b35 100644
--- a/lib/gitlab/database/lock_writes_manager.rb
+++ b/lib/gitlab/database/lock_writes_manager.rb
@@ -5,6 +5,11 @@ module Gitlab
class LockWritesManager
TRIGGER_FUNCTION_NAME = 'gitlab_schema_prevent_write'
+ # Triggers to block INSERT / UPDATE / DELETE
+ # Triggers on TRUNCATE are not added to the information_schema.triggers
+ # See https://www.postgresql.org/message-id/16934.1568989957%40sss.pgh.pa.us
+ EXPECTED_TRIGGER_RECORD_COUNT = 3
+
def initialize(table_name:, connection:, database_name:, logger: nil, dry_run: false)
@table_name = table_name
@connection = connection
@@ -20,7 +25,7 @@ module Gitlab
AND trigger_name = '#{write_trigger_name(table_name)}'
SQL
- connection.select_value(query) == 3
+ connection.select_value(query) == EXPECTED_TRIGGER_RECORD_COUNT
end
def lock_writes
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index df40e3b3868..16416dd2507 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -6,6 +6,10 @@ module Gitlab
include Migrations::ReestablishedConnectionStack
include Migrations::BackgroundMigrationHelpers
include Migrations::BatchedBackgroundMigrationHelpers
+ include Migrations::LockRetriesHelpers
+ include Migrations::TimeoutHelpers
+ include Migrations::ConstraintsHelpers
+ include Migrations::ExtensionHelpers
include DynamicModelHelpers
include RenameTableHelpers
include AsyncIndexes::MigrationHelpers
@@ -22,8 +26,6 @@ module Gitlab
super(table_name, connection: connection, **kwargs)
end
- # https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
- MAX_IDENTIFIER_NAME_LENGTH = 63
DEFAULT_TIMESTAMP_COLUMNS = %i[created_at updated_at].freeze
# Adds `created_at` and `updated_at` columns with timezone information.
@@ -146,6 +148,12 @@ module Gitlab
'in the body of your migration class'
end
+ if !options.delete(:allow_partition) && partition?(table_name)
+ raise ArgumentError, 'add_concurrent_index can not be used on a partitioned ' \
+ 'table. Please use add_concurrent_partitioned_index on the partitioned table ' \
+ 'as we need to create indexes on each partition and an index on the parent table'
+ end
+
options = options.merge({ algorithm: :concurrently })
if index_exists?(table_name, column_name, **options)
@@ -202,6 +210,12 @@ module Gitlab
'in the body of your migration class'
end
+ if partition?(table_name)
+ raise ArgumentError, 'remove_concurrent_index can not be used on a partitioned ' \
+ 'table. Please use remove_concurrent_partitioned_index_by_name on the partitioned table ' \
+ 'as we need to remove the index on the parent table'
+ end
+
options = options.merge({ algorithm: :concurrently })
unless index_exists?(table_name, column_name, **options)
@@ -231,6 +245,12 @@ module Gitlab
'in the body of your migration class'
end
+ if partition?(table_name)
+ raise ArgumentError, 'remove_concurrent_index_by_name can not be used on a partitioned ' \
+ 'table. Please use remove_concurrent_partitioned_index_by_name on the partitioned table ' \
+ 'as we need to remove the index on the parent table'
+ end
+
index_name = index_name[:name] if index_name.is_a?(Hash)
raise 'remove_concurrent_index_by_name must get an index name as the second argument' if index_name.blank?
@@ -360,97 +380,6 @@ module Gitlab
"#{prefix}#{hashed_identifier}"
end
- # Long-running migrations may take more than the timeout allowed by
- # the database. Disable the session's statement timeout to ensure
- # migrations don't get killed prematurely.
- #
- # There are two possible ways to disable the statement timeout:
- #
- # - Per transaction (this is the preferred and default mode)
- # - Per connection (requires a cleanup after the execution)
- #
- # When using a per connection disable statement, code must be inside
- # a block so we can automatically execute `RESET statement_timeout` after block finishes
- # otherwise the statement will still be disabled until connection is dropped
- # or `RESET statement_timeout` is executed
- def disable_statement_timeout
- if block_given?
- if statement_timeout_disabled?
- # Don't do anything if the statement_timeout is already disabled
- # Allows for nested calls of disable_statement_timeout without
- # resetting the timeout too early (before the outer call ends)
- yield
- else
- begin
- execute('SET statement_timeout TO 0')
-
- yield
- ensure
- execute('RESET statement_timeout')
- end
- end
- else
- unless transaction_open?
- raise <<~ERROR
- Cannot call disable_statement_timeout() without a transaction open or outside of a transaction block.
- If you don't want to use a transaction wrap your code in a block call:
-
- disable_statement_timeout { # code that requires disabled statement here }
-
- This will make sure statement_timeout is disabled before and reset after the block execution is finished.
- ERROR
- end
-
- execute('SET LOCAL statement_timeout TO 0')
- end
- end
-
- # Executes the block with a retry mechanism that alters the +lock_timeout+ and +sleep_time+ between attempts.
- # The timings can be controlled via the +timing_configuration+ parameter.
- # If the lock was not acquired within the retry period, a last attempt is made without using +lock_timeout+.
- #
- # Note this helper uses subtransactions when run inside an already open transaction.
- #
- # ==== Examples
- # # Invoking without parameters
- # with_lock_retries do
- # drop_table :my_table
- # end
- #
- # # Invoking with custom +timing_configuration+
- # t = [
- # [1.second, 1.second],
- # [2.seconds, 2.seconds]
- # ]
- #
- # with_lock_retries(timing_configuration: t) do
- # drop_table :my_table # this will be retried twice
- # end
- #
- # # Disabling the retries using an environment variable
- # > export DISABLE_LOCK_RETRIES=true
- #
- # with_lock_retries do
- # drop_table :my_table # one invocation, it will not retry at all
- # end
- #
- # ==== Parameters
- # * +timing_configuration+ - [[ActiveSupport::Duration, ActiveSupport::Duration], ...] lock timeout for the block, sleep time before the next iteration, defaults to `Gitlab::Database::WithLockRetries::DEFAULT_TIMING_CONFIGURATION`
- # * +logger+ - [Gitlab::JsonLogger]
- # * +env+ - [Hash] custom environment hash, see the example with `DISABLE_LOCK_RETRIES`
- def with_lock_retries(*args, **kwargs, &block)
- raise_on_exhaustion = !!kwargs.delete(:raise_on_exhaustion)
- merged_args = {
- connection: connection,
- klass: self.class,
- logger: Gitlab::BackgroundMigration::Logger,
- allow_savepoints: true
- }.merge(kwargs)
-
- Gitlab::Database::WithLockRetries.new(**merged_args)
- .run(raise_on_exhaustion: raise_on_exhaustion, &block)
- end
-
def true_value
Database.true_value
end
@@ -796,6 +725,10 @@ module Gitlab
install_rename_triggers(table, old, new)
end
+ def convert_to_type_column(column, from_type, to_type)
+ "#{column}_convert_#{from_type}_to_#{to_type}"
+ end
+
def convert_to_bigint_column(column)
"#{column}_convert_to_bigint"
end
@@ -826,7 +759,22 @@ module Gitlab
# columns - The name, or array of names, of the column(s) that we want to convert to bigint.
# primary_key - The name of the primary key column (most often :id)
def initialize_conversion_of_integer_to_bigint(table, columns, primary_key: :id)
- create_temporary_columns_and_triggers(table, columns, primary_key: primary_key, data_type: :bigint)
+ mappings = Array(columns).map do |c|
+ {
+ c => {
+ from_type: :int,
+ to_type: :bigint,
+ default_value: 0
+ }
+ }
+ end.reduce(&:merge)
+
+ create_temporary_columns_and_triggers(
+ table,
+ mappings,
+ primary_key: primary_key,
+ old_bigint_column_naming: true
+ )
end
# Reverts `initialize_conversion_of_integer_to_bigint`
@@ -849,9 +797,23 @@ module Gitlab
# table - The name of the database table containing the columns
# columns - The name, or array of names, of the column(s) that we have converted to bigint.
# primary_key - The name of the primary key column (most often :id)
-
def restore_conversion_of_integer_to_bigint(table, columns, primary_key: :id)
- create_temporary_columns_and_triggers(table, columns, primary_key: primary_key, data_type: :int)
+ mappings = Array(columns).map do |c|
+ {
+ c => {
+ from_type: :bigint,
+ to_type: :int,
+ default_value: 0
+ }
+ }
+ end.reduce(&:merge)
+
+ create_temporary_columns_and_triggers(
+ table,
+ mappings,
+ primary_key: primary_key,
+ old_bigint_column_naming: true
+ )
end
# Backfills the new columns used in an integer-to-bigint conversion using background migrations.
@@ -947,43 +909,6 @@ module Gitlab
execute("DELETE FROM batched_background_migrations WHERE #{conditions}")
end
- 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!
-
- Gitlab::Database::BackgroundMigration::BatchedMigration.reset_column_information
- migration = Gitlab::Database::BackgroundMigration::BatchedMigration.find_for_configuration(
- Gitlab::Database.gitlab_schemas_for_connection(connection),
- job_class_name, table_name, column_name, job_arguments
- )
-
- configuration = {
- job_class_name: job_class_name,
- table_name: table_name,
- column_name: column_name,
- job_arguments: job_arguments
- }
-
- return Gitlab::AppLogger.warn "Could not find batched background migration for the given configuration: #{configuration}" if migration.nil?
-
- return if migration.finished?
-
- finalize_batched_background_migration(job_class_name: job_class_name, table_name: table_name, column_name: column_name, job_arguments: job_arguments) if finalize
-
- unless migration.reload.finished? # rubocop:disable Cop/ActiveRecordAssociationReload
- raise "Expected batched background migration for the given configuration to be marked as 'finished', " \
- "but it is '#{migration.status_name}':" \
- "\t#{configuration}" \
- "\n\n" \
- "Finalize it manually by running the following command in a `bash` or `sh` shell:" \
- "\n\n" \
- "\tsudo gitlab-rake gitlab:background_migrations:finalize[#{job_class_name},#{table_name},#{column_name},'#{job_arguments.to_json.gsub(',', '\,')}']" \
- "\n\n" \
- "For more information, check the documentation" \
- "\n\n" \
- "\thttps://docs.gitlab.com/ee/user/admin_area/monitoring/background_migrations.html#database-migrations-failing-because-of-batched-background-migration-not-finished"
- end
- end
-
# Returns an Array containing the indexes for the given column
def indexes_for(table, column)
column = column.to_s
@@ -1102,6 +1027,24 @@ module Gitlab
rescue ArgumentError
end
+ # Remove any instances of deprecated job classes lingering in queues.
+ #
+ # rubocop:disable Cop/SidekiqApiUsage
+ def sidekiq_remove_jobs(job_klass:)
+ Sidekiq::Queue.new(job_klass.queue).each do |job|
+ job.delete if job.klass == job_klass.to_s
+ end
+
+ Sidekiq::RetrySet.new.each do |retri|
+ retri.delete if retri.klass == job_klass.to_s
+ end
+
+ Sidekiq::ScheduledSet.new.each do |scheduled|
+ scheduled.delete if scheduled.klass == job_klass.to_s
+ end
+ end
+ # rubocop:enable Cop/SidekiqApiUsage
+
def sidekiq_queue_migrate(queue_from, to:)
while sidekiq_queue_length(queue_from) > 0
Sidekiq.redis do |conn|
@@ -1194,320 +1137,6 @@ into similar problems in the future (e.g. when new tables are created).
execute(sql)
end
- # Returns the name for a check constraint
- #
- # type:
- # - Any value, as long as it is unique
- # - Constraint names are unique per table in Postgres, and, additionally,
- # we can have multiple check constraints over a column
- # So we use the (table, column, type) triplet as a unique name
- # - e.g. we use 'max_length' when adding checks for text limits
- # or 'not_null' when adding a NOT NULL constraint
- #
- def check_constraint_name(table, column, type)
- identifier = "#{table}_#{column}_check_#{type}"
- # Check concurrent_foreign_key_name() for info on why we use a hash
- hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
-
- "check_#{hashed_identifier}"
- 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
- end
-
- # Adds a check constraint to a table
- #
- # This method is the generic helper for adding any check constraint
- # More specialized helpers may use it (e.g. add_text_limit or add_not_null)
- #
- # This method only requires minimal locking:
- # - The constraint is added using NOT VALID
- # This allows us to add the check constraint without validating it
- # - The check will be enforced for new data (inserts) coming in
- # - If `validate: true` the constraint is also validated
- # Otherwise, validate_check_constraint() can be used at a later stage
- # - Check comments on add_concurrent_foreign_key for more info
- #
- # table - The table the constraint will be added to
- # check - The check clause to add
- # e.g. 'char_length(name) <= 5' or 'store IS NOT NULL'
- # constraint_name - The name of the check constraint (otherwise auto-generated)
- # Should be unique per table (not per column)
- # validate - Whether to validate the constraint in this call
- #
- def add_check_constraint(table, check, constraint_name, validate: true)
- # Transactions would result in ALTER TABLE locks being held for the
- # duration of the transaction, defeating the purpose of this method.
- validate_not_in_transaction!(:add_check_constraint)
-
- validate_check_constraint_name!(constraint_name)
-
- if check_constraint_exists?(table, constraint_name)
- warning_message = <<~MESSAGE
- Check constraint was not created because it exists already
- (this may be due to an aborted migration or similar)
- table: #{table}, check: #{check}, constraint name: #{constraint_name}
- MESSAGE
-
- Gitlab::AppLogger.warn warning_message
- else
- # Only add the constraint without validating it
- # Even though it is fast, ADD CONSTRAINT requires an EXCLUSIVE lock
- # Use with_lock_retries to make sure that this operation
- # will not timeout on tables accessed by many processes
- with_lock_retries do
- execute <<-EOF.strip_heredoc
- ALTER TABLE #{table}
- ADD CONSTRAINT #{constraint_name}
- CHECK ( #{check} )
- NOT VALID;
- EOF
- end
- end
-
- if validate
- validate_check_constraint(table, constraint_name)
- end
- end
-
- def validate_check_constraint(table, constraint_name)
- validate_check_constraint_name!(constraint_name)
-
- unless check_constraint_exists?(table, constraint_name)
- raise missing_schema_object_message(table, "check constraint", constraint_name)
- end
-
- disable_statement_timeout do
- # VALIDATE CONSTRAINT only requires a SHARE UPDATE EXCLUSIVE LOCK
- # It only conflicts with other validations and creating indexes
- execute("ALTER TABLE #{table} VALIDATE CONSTRAINT #{constraint_name};")
- end
- end
-
- def remove_check_constraint(table, constraint_name)
- # This is technically not necessary, but aligned with add_check_constraint
- # and allows us to continue use with_lock_retries here
- validate_not_in_transaction!(:remove_check_constraint)
-
- validate_check_constraint_name!(constraint_name)
-
- # DROP CONSTRAINT requires an EXCLUSIVE lock
- # Use with_lock_retries to make sure that this will not timeout
- with_lock_retries do
- execute <<-EOF.strip_heredoc
- ALTER TABLE #{table}
- DROP CONSTRAINT IF EXISTS #{constraint_name}
- EOF
- end
- end
-
- # Copies all check constraints for the old column to the new column.
- #
- # table - The table containing the columns.
- # old - The old column.
- # new - The new column.
- # schema - The schema the table is defined for
- # If it is not provided, then the current_schema is used
- def copy_check_constraints(table, old, new, schema: nil)
- if transaction_open?
- raise 'copy_check_constraints can not be run inside a transaction'
- end
-
- unless column_exists?(table, old)
- raise "Column #{old} does not exist on #{table}"
- end
-
- unless column_exists?(table, new)
- raise "Column #{new} does not exist on #{table}"
- end
-
- table_with_schema = schema.present? ? "#{schema}.#{table}" : table
-
- check_constraints_for(table, old, schema: schema).each do |check_c|
- validate = !(check_c["constraint_def"].end_with? "NOT VALID")
-
- # Normalize:
- # - Old constraint definitions:
- # '(char_length(entity_path) <= 5500)'
- # - Definitionss from pg_get_constraintdef(oid):
- # 'CHECK ((char_length(entity_path) <= 5500))'
- # - Definitions from pg_get_constraintdef(oid, pretty_bool):
- # 'CHECK (char_length(entity_path) <= 5500)'
- # - Not valid constraints: 'CHECK (...) NOT VALID'
- # to a single format that we can use:
- # '(char_length(entity_path) <= 5500)'
- check_definition = check_c["constraint_def"]
- .sub(/^\s*(CHECK)?\s*\({0,2}/, '(')
- .sub(/\){0,2}\s*(NOT VALID)?\s*$/, ')')
-
- constraint_name = begin
- if check_definition == "(#{old} IS NOT NULL)"
- not_null_constraint_name(table_with_schema, new)
- elsif check_definition.start_with? "(char_length(#{old}) <="
- text_limit_name(table_with_schema, new)
- else
- check_constraint_name(table_with_schema, new, 'copy_check_constraint')
- end
- end
-
- add_check_constraint(
- table_with_schema,
- check_definition.gsub(old.to_s, new.to_s),
- constraint_name,
- validate: validate
- )
- end
- end
-
- # Migration Helpers for adding limit to text columns
- def add_text_limit(table, column, limit, constraint_name: nil, validate: true)
- add_check_constraint(
- table,
- "char_length(#{column}) <= #{limit}",
- text_limit_name(table, column, name: constraint_name),
- validate: validate
- )
- end
-
- def validate_text_limit(table, column, constraint_name: nil)
- validate_check_constraint(table, text_limit_name(table, column, name: constraint_name))
- end
-
- def remove_text_limit(table, column, constraint_name: nil)
- remove_check_constraint(table, text_limit_name(table, column, name: constraint_name))
- end
-
- def check_text_limit_exists?(table, column, constraint_name: nil)
- check_constraint_exists?(table, text_limit_name(table, column, name: constraint_name))
- end
-
- # Migration Helpers for managing not null constraints
- def add_not_null_constraint(table, column, constraint_name: nil, validate: true)
- if column_is_nullable?(table, column)
- add_check_constraint(
- table,
- "#{column} IS NOT NULL",
- not_null_constraint_name(table, column, name: constraint_name),
- validate: validate
- )
- else
- warning_message = <<~MESSAGE
- NOT NULL check constraint was not created:
- column #{table}.#{column} is already defined as `NOT NULL`
- MESSAGE
-
- Gitlab::AppLogger.warn warning_message
- end
- end
-
- def validate_not_null_constraint(table, column, constraint_name: nil)
- validate_check_constraint(
- table,
- not_null_constraint_name(table, column, name: constraint_name)
- )
- end
-
- def remove_not_null_constraint(table, column, constraint_name: nil)
- remove_check_constraint(
- table,
- not_null_constraint_name(table, column, name: constraint_name)
- )
- end
-
- def check_not_null_constraint_exists?(table, column, constraint_name: nil)
- check_constraint_exists?(
- table,
- not_null_constraint_name(table, column, name: constraint_name)
- )
- end
-
- def create_extension(extension)
- execute('CREATE EXTENSION IF NOT EXISTS %s' % extension)
- rescue ActiveRecord::StatementInvalid => e
- dbname = ApplicationRecord.database.database_name
- user = ApplicationRecord.database.username
-
- warn(<<~MSG) if e.to_s =~ /permission denied/
- GitLab requires the PostgreSQL extension '#{extension}' installed in database '#{dbname}', but
- the database user is not allowed to install the extension.
-
- You can either install the extension manually using a database superuser:
-
- CREATE EXTENSION IF NOT EXISTS #{extension}
-
- Or, you can solve this by logging in to the GitLab
- database (#{dbname}) using a superuser and running:
-
- ALTER #{user} WITH SUPERUSER
-
- This query will grant the user superuser permissions, ensuring any database extensions
- can be installed through migrations.
-
- For more information, refer to https://docs.gitlab.com/ee/install/postgresql_extensions.html.
- MSG
-
- raise
- end
-
- def drop_extension(extension)
- execute('DROP EXTENSION IF EXISTS %s' % extension)
- rescue ActiveRecord::StatementInvalid => e
- dbname = ApplicationRecord.database.database_name
- user = ApplicationRecord.database.username
-
- warn(<<~MSG) if e.to_s =~ /permission denied/
- This migration attempts to drop the PostgreSQL extension '#{extension}'
- installed in database '#{dbname}', but the database user is not allowed
- to drop the extension.
-
- You can either drop the extension manually using a database superuser:
-
- DROP EXTENSION IF EXISTS #{extension}
-
- Or, you can solve this by logging in to the GitLab
- database (#{dbname}) using a superuser and running:
-
- ALTER #{user} WITH SUPERUSER
-
- This query will grant the user superuser permissions, ensuring any database extensions
- can be dropped through migrations.
-
- For more information, refer to https://docs.gitlab.com/ee/install/postgresql_extensions.html.
- MSG
-
- raise
- end
-
- def rename_constraint(table_name, old_name, new_name)
- execute <<~SQL
- ALTER TABLE #{quote_table_name(table_name)}
- RENAME CONSTRAINT #{quote_column_name(old_name)} TO #{quote_column_name(new_name)}
- SQL
- end
-
- def drop_constraint(table_name, constraint_name, cascade: false)
- execute <<~SQL
- ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(constraint_name)} #{cascade_statement(cascade)}
- SQL
- end
-
def add_primary_key_using_index(table_name, pk_name, index_to_use)
execute <<~SQL
ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{quote_table_name(pk_name)} PRIMARY KEY USING INDEX #{quote_table_name(index_to_use)}
@@ -1536,17 +1165,20 @@ into similar problems in the future (e.g. when new tables are created).
SQL
end
- private
+ # rubocop:disable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
+ def create_temporary_columns_and_triggers(table, mappings, primary_key: :id, old_bigint_column_naming: false)
+ raise ArgumentError, "No mappings for column conversion provided" if mappings.blank?
- def multiple_columns(columns, separator: ', ')
- Array.wrap(columns).join(separator)
- end
+ unless mappings.values.all? { |values| mapping_has_required_columns?(values) }
+ raise ArgumentError, "Some mappings don't have required keys provided"
+ end
- def cascade_statement(cascade)
- cascade ? 'CASCADE' : ''
- end
+ neutral_values_for_type = {
+ int: 0,
+ bigint: 0,
+ uuid: '00000000-0000-0000-0000-000000000000'
+ }
- def create_temporary_columns_and_triggers(table, columns, primary_key: :id, data_type: :bigint)
unless table_exists?(table)
raise "Table #{table} does not exist"
end
@@ -1555,7 +1187,7 @@ into similar problems in the future (e.g. when new tables are created).
raise "Column #{primary_key} does not exist on #{table}"
end
- columns = Array.wrap(columns)
+ columns = mappings.keys
columns.each do |column|
next if column_exists?(table, column)
@@ -1564,67 +1196,88 @@ into similar problems in the future (e.g. when new tables are created).
check_trigger_permissions!(table)
- conversions = columns.to_h { |column| [column, convert_to_bigint_column(column)] }
+ if old_bigint_column_naming
+ mappings.each do |column, params|
+ params.merge!(
+ temporary_column_name: convert_to_bigint_column(column)
+ )
+ end
+ else
+ mappings.each do |column, params|
+ params.merge!(
+ temporary_column_name: convert_to_type_column(column, params[:from_type], params[:to_type])
+ )
+ end
+ end
with_lock_retries do
- conversions.each do |(source_column, temporary_name)|
- column = column_for(table, source_column)
+ mappings.each do |(column_name, params)|
+ column = column_for(table, column_name)
+ temporary_name = params[:temporary_column_name]
+ data_type = params[:to_type]
+ default_value = params[:default_value]
if (column.name.to_s == primary_key.to_s) || !column.null
# If the column to be converted is either a PK or is defined as NOT NULL,
# set it to `NOT NULL DEFAULT 0` and we'll copy paste the correct values bellow
# That way, we skip the expensive validation step required to add
# a NOT NULL constraint at the end of the process
- add_column(table, temporary_name, data_type, default: column.default || 0, null: false)
+ add_column(
+ table,
+ temporary_name,
+ data_type,
+ default: column.default || default_value || neutral_values_for_type.fetch(data_type),
+ null: false
+ )
else
- add_column(table, temporary_name, data_type, default: column.default)
+ add_column(
+ table,
+ temporary_name,
+ data_type,
+ default: column.default
+ )
end
end
- install_rename_triggers(table, conversions.keys, conversions.values)
+ old_column_names = mappings.keys
+ temporary_column_names = mappings.values.map { |v| v[:temporary_column_name] }
+ install_rename_triggers(table, old_column_names, temporary_column_names)
end
end
+ # rubocop:enable Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
- def validate_check_constraint_name!(constraint_name)
- if constraint_name.to_s.length > MAX_IDENTIFIER_NAME_LENGTH
- raise "The maximum allowed constraint name is #{MAX_IDENTIFIER_NAME_LENGTH} characters"
+ def partition?(table_name)
+ if view_exists?(:postgres_partitions)
+ Gitlab::Database::PostgresPartition.partition_exists?(table_name)
+ else
+ Gitlab::Database::PostgresPartition.legacy_partition_exists?(table_name)
end
end
- # Returns an ActiveRecord::Result containing the check constraints
- # defined for the given column.
- #
- # If the schema is not provided, then the current_schema is used
- def check_constraints_for(table, column, schema: nil)
- check_sql = <<~SQL
- SELECT
- ccu.table_schema as schema_name,
- ccu.table_name as table_name,
- ccu.column_name as column_name,
- con.conname as constraint_name,
- pg_get_constraintdef(con.oid) as constraint_def
- 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
- INNER JOIN information_schema.constraint_column_usage ccu
- ON con.conname = ccu.constraint_name
- AND nsp.nspname = ccu.constraint_schema
- AND rel.relname = ccu.table_name
- WHERE nsp.nspname = #{connection.quote(schema.presence || current_schema)}
- AND rel.relname = #{connection.quote(table)}
- AND ccu.column_name = #{connection.quote(column)}
- AND con.contype = 'c'
- ORDER BY constraint_name
- SQL
+ private
+
+ def multiple_columns(columns, separator: ', ')
+ Array.wrap(columns).join(separator)
+ end
+
+ def cascade_statement(cascade)
+ cascade ? 'CASCADE' : ''
+ end
- connection.exec_query(check_sql)
+ def validate_check_constraint_name!(constraint_name)
+ if constraint_name.to_s.length > MAX_IDENTIFIER_NAME_LENGTH
+ raise "The maximum allowed constraint name is #{MAX_IDENTIFIER_NAME_LENGTH} characters"
+ end
end
- def statement_timeout_disabled?
- # This is a string of the form "100ms" or "0" when disabled
- connection.select_value('SHOW statement_timeout') == "0"
+ # mappings => {} where keys are column names and values are hashes with the following keys:
+ # from_type - from which type we're migrating
+ # to_type - to which type we're migrating
+ # default_value - custom default value, if not provided will be taken from neutral_values_for_type
+ def mapping_has_required_columns?(mapping)
+ %i[from_type to_type].map do |required_key|
+ mapping.has_key?(required_key)
+ end.all?
end
def column_is_nullable?(table, column)
@@ -1640,14 +1293,6 @@ into similar problems in the future (e.g. when new tables are created).
connection.select_value(check_sql) == 'YES'
end
- def text_limit_name(table, column, name: nil)
- name.presence || check_constraint_name(table, column, 'max_length')
- end
-
- def not_null_constraint_name(table, column, name: nil)
- name.presence || check_constraint_name(table, column, 'not_null')
- end
-
def missing_schema_object_message(table, type, name)
<<~MESSAGE
Could not find #{type} "#{name}" on table "#{table}" which was referenced during the migration.
@@ -1717,17 +1362,6 @@ into similar problems in the future (e.g. when new tables are created).
Must end with `_at`}
MESSAGE
end
-
- def validate_not_in_transaction!(method_name, modifier = nil)
- return unless transaction_open?
-
- raise <<~ERROR
- #{["`#{method_name}`", modifier].compact.join(' ')} cannot be run inside a transaction.
-
- You can disable transactions by calling `disable_ddl_transaction!` in the body of
- your migration class
- ERROR
- end
end
end
end
diff --git a/lib/gitlab/database/migration_helpers/v2.rb b/lib/gitlab/database/migration_helpers/v2.rb
index dd426962033..b5b8b58681c 100644
--- a/lib/gitlab/database/migration_helpers/v2.rb
+++ b/lib/gitlab/database/migration_helpers/v2.rb
@@ -205,8 +205,8 @@ module Gitlab
raise "Column #{old_column} does not exist on #{table}"
end
- if column.default
- raise "#{calling_operation} does not currently support columns with default values"
+ if column.default_function
+ raise "#{calling_operation} does not currently support columns with default functions"
end
unless column_exists?(table, batch_column_name)
@@ -269,17 +269,20 @@ module Gitlab
def create_insert_trigger(trigger_name, quoted_table, quoted_old_column, quoted_new_column)
function_name = function_name_for_trigger(trigger_name)
+ column = columns(quoted_table.delete('"').to_sym).find { |column| column.name == quoted_old_column.delete('"') }
+ quoted_default_value = connection.quote(column.default)
+
execute(<<~SQL)
CREATE OR REPLACE FUNCTION #{function_name}()
RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
- IF NEW.#{quoted_old_column} IS NULL AND NEW.#{quoted_new_column} IS NOT NULL THEN
+ IF NEW.#{quoted_old_column} IS NOT DISTINCT FROM #{quoted_default_value} AND NEW.#{quoted_new_column} IS DISTINCT FROM #{quoted_default_value} THEN
NEW.#{quoted_old_column} = NEW.#{quoted_new_column};
END IF;
- IF NEW.#{quoted_new_column} IS NULL AND NEW.#{quoted_old_column} IS NOT NULL THEN
+ IF NEW.#{quoted_new_column} IS NOT DISTINCT FROM #{quoted_default_value} AND NEW.#{quoted_old_column} IS DISTINCT FROM #{quoted_default_value} THEN
NEW.#{quoted_new_column} = NEW.#{quoted_old_column};
END IF;
diff --git a/lib/gitlab/database/migrations/batched_background_migration_helpers.rb b/lib/gitlab/database/migrations/batched_background_migration_helpers.rb
index 363fd0598f9..e958ce2aba4 100644
--- a/lib/gitlab/database/migrations/batched_background_migration_helpers.rb
+++ b/lib/gitlab/database/migrations/batched_background_migration_helpers.rb
@@ -196,6 +196,43 @@ module Gitlab
:gitlab_main
end
end
+
+ 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!
+
+ Gitlab::Database::BackgroundMigration::BatchedMigration.reset_column_information
+ migration = Gitlab::Database::BackgroundMigration::BatchedMigration.find_for_configuration(
+ Gitlab::Database.gitlab_schemas_for_connection(connection),
+ job_class_name, table_name, column_name, job_arguments
+ )
+
+ configuration = {
+ job_class_name: job_class_name,
+ table_name: table_name,
+ column_name: column_name,
+ job_arguments: job_arguments
+ }
+
+ return Gitlab::AppLogger.warn "Could not find batched background migration for the given configuration: #{configuration}" if migration.nil?
+
+ return if migration.finished?
+
+ finalize_batched_background_migration(job_class_name: job_class_name, table_name: table_name, column_name: column_name, job_arguments: job_arguments) if finalize
+
+ return if migration.reload.finished? # rubocop:disable Cop/ActiveRecordAssociationReload
+
+ raise "Expected batched background migration for the given configuration to be marked as 'finished', " \
+ "but it is '#{migration.status_name}':" \
+ "\t#{configuration}" \
+ "\n\n" \
+ "Finalize it manually by running the following command in a `bash` or `sh` shell:" \
+ "\n\n" \
+ "\tsudo gitlab-rake gitlab:background_migrations:finalize[#{job_class_name},#{table_name},#{column_name},'#{job_arguments.to_json.gsub(',', '\,')}']" \
+ "\n\n" \
+ "For more information, check the documentation" \
+ "\n\n" \
+ "\thttps://docs.gitlab.com/ee/user/admin_area/monitoring/background_migrations.html#database-migrations-failing-because-of-batched-background-migration-not-finished"
+ end
end
end
end
diff --git a/lib/gitlab/database/migrations/constraints_helpers.rb b/lib/gitlab/database/migrations/constraints_helpers.rb
new file mode 100644
index 00000000000..7b849e3137a
--- /dev/null
+++ b/lib/gitlab/database/migrations/constraints_helpers.rb
@@ -0,0 +1,337 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module Migrations
+ module ConstraintsHelpers
+ include LockRetriesHelpers
+ include TimeoutHelpers
+
+ # https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
+ MAX_IDENTIFIER_NAME_LENGTH = 63
+
+ # Returns the name for a check constraint
+ #
+ # type:
+ # - Any value, as long as it is unique
+ # - Constraint names are unique per table in Postgres, and, additionally,
+ # we can have multiple check constraints over a column
+ # So we use the (table, column, type) triplet as a unique name
+ # - e.g. we use 'max_length' when adding checks for text limits
+ # or 'not_null' when adding a NOT NULL constraint
+ #
+ def check_constraint_name(table, column, type)
+ identifier = "#{table}_#{column}_check_#{type}"
+ # Check concurrent_foreign_key_name() for info on why we use a hash
+ hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)
+
+ "check_#{hashed_identifier}"
+ 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
+ end
+
+ # Adds a check constraint to a table
+ #
+ # This method is the generic helper for adding any check constraint
+ # More specialized helpers may use it (e.g. add_text_limit or add_not_null)
+ #
+ # This method only requires minimal locking:
+ # - The constraint is added using NOT VALID
+ # This allows us to add the check constraint without validating it
+ # - The check will be enforced for new data (inserts) coming in
+ # - If `validate: true` the constraint is also validated
+ # Otherwise, validate_check_constraint() can be used at a later stage
+ # - Check comments on add_concurrent_foreign_key for more info
+ #
+ # table - The table the constraint will be added to
+ # check - The check clause to add
+ # e.g. 'char_length(name) <= 5' or 'store IS NOT NULL'
+ # constraint_name - The name of the check constraint (otherwise auto-generated)
+ # Should be unique per table (not per column)
+ # validate - Whether to validate the constraint in this call
+ #
+ def add_check_constraint(table, check, constraint_name, validate: true)
+ # Transactions would result in ALTER TABLE locks being held for the
+ # duration of the transaction, defeating the purpose of this method.
+ validate_not_in_transaction!(:add_check_constraint)
+
+ validate_check_constraint_name!(constraint_name)
+
+ if check_constraint_exists?(table, constraint_name)
+ warning_message = <<~MESSAGE
+ Check constraint was not created because it exists already
+ (this may be due to an aborted migration or similar)
+ table: #{table}, check: #{check}, constraint name: #{constraint_name}
+ MESSAGE
+
+ Gitlab::AppLogger.warn warning_message
+ else
+ # Only add the constraint without validating it
+ # Even though it is fast, ADD CONSTRAINT requires an EXCLUSIVE lock
+ # Use with_lock_retries to make sure that this operation
+ # will not timeout on tables accessed by many processes
+ with_lock_retries do
+ execute <<~SQL
+ ALTER TABLE #{table}
+ ADD CONSTRAINT #{constraint_name}
+ CHECK ( #{check} )
+ NOT VALID;
+ SQL
+ end
+ end
+
+ validate_check_constraint(table, constraint_name) if validate
+ end
+
+ def validate_check_constraint(table, constraint_name)
+ validate_check_constraint_name!(constraint_name)
+
+ unless check_constraint_exists?(table, constraint_name)
+ raise missing_schema_object_message(table, "check constraint", constraint_name)
+ end
+
+ disable_statement_timeout do
+ # VALIDATE CONSTRAINT only requires a SHARE UPDATE EXCLUSIVE LOCK
+ # It only conflicts with other validations and creating indexes
+ execute("ALTER TABLE #{table} VALIDATE CONSTRAINT #{constraint_name};")
+ end
+ end
+
+ def remove_check_constraint(table, constraint_name)
+ # This is technically not necessary, but aligned with add_check_constraint
+ # and allows us to continue use with_lock_retries here
+ validate_not_in_transaction!(:remove_check_constraint)
+
+ validate_check_constraint_name!(constraint_name)
+
+ # DROP CONSTRAINT requires an EXCLUSIVE lock
+ # Use with_lock_retries to make sure that this will not timeout
+ with_lock_retries do
+ execute <<-SQL
+ ALTER TABLE #{table}
+ DROP CONSTRAINT IF EXISTS #{constraint_name}
+ SQL
+ end
+ end
+
+ # Copies all check constraints for the old column to the new column.
+ #
+ # table - The table containing the columns.
+ # old - The old column.
+ # new - The new column.
+ # schema - The schema the table is defined for
+ # If it is not provided, then the current_schema is used
+ def copy_check_constraints(table, old, new, schema: nil)
+ raise 'copy_check_constraints can not be run inside a transaction' if transaction_open?
+
+ raise "Column #{old} does not exist on #{table}" unless column_exists?(table, old)
+
+ raise "Column #{new} does not exist on #{table}" unless column_exists?(table, new)
+
+ table_with_schema = schema.present? ? "#{schema}.#{table}" : table
+
+ check_constraints_for(table, old, schema: schema).each do |check_c|
+ validate = !(check_c["constraint_def"].end_with? "NOT VALID")
+
+ # Normalize:
+ # - Old constraint definitions:
+ # '(char_length(entity_path) <= 5500)'
+ # - Definitionss from pg_get_constraintdef(oid):
+ # 'CHECK ((char_length(entity_path) <= 5500))'
+ # - Definitions from pg_get_constraintdef(oid, pretty_bool):
+ # 'CHECK (char_length(entity_path) <= 5500)'
+ # - Not valid constraints: 'CHECK (...) NOT VALID'
+ # to a single format that we can use:
+ # '(char_length(entity_path) <= 5500)'
+ check_definition = check_c["constraint_def"]
+ .sub(/^\s*(CHECK)?\s*\({0,2}/, '(')
+ .sub(/\){0,2}\s*(NOT VALID)?\s*$/, ')')
+
+ constraint_name = if check_definition == "(#{old} IS NOT NULL)"
+ not_null_constraint_name(table_with_schema, new)
+ elsif check_definition.start_with? "(char_length(#{old}) <="
+ text_limit_name(table_with_schema, new)
+ else
+ check_constraint_name(table_with_schema, new, 'copy_check_constraint')
+ end
+
+ add_check_constraint(
+ table_with_schema,
+ check_definition.gsub(old.to_s, new.to_s),
+ constraint_name,
+ validate: validate
+ )
+ end
+ end
+
+ # Migration Helpers for adding limit to text columns
+ def add_text_limit(table, column, limit, constraint_name: nil, validate: true)
+ add_check_constraint(
+ table,
+ "char_length(#{column}) <= #{limit}",
+ text_limit_name(table, column, name: constraint_name),
+ validate: validate
+ )
+ end
+
+ def validate_text_limit(table, column, constraint_name: nil)
+ validate_check_constraint(table, text_limit_name(table, column, name: constraint_name))
+ end
+
+ def remove_text_limit(table, column, constraint_name: nil)
+ remove_check_constraint(table, text_limit_name(table, column, name: constraint_name))
+ end
+
+ def check_text_limit_exists?(table, column, constraint_name: nil)
+ check_constraint_exists?(table, text_limit_name(table, column, name: constraint_name))
+ end
+
+ # Migration Helpers for managing not null constraints
+ def add_not_null_constraint(table, column, constraint_name: nil, validate: true)
+ if column_is_nullable?(table, column)
+ add_check_constraint(
+ table,
+ "#{column} IS NOT NULL",
+ not_null_constraint_name(table, column, name: constraint_name),
+ validate: validate
+ )
+ else
+ warning_message = <<~MESSAGE
+ NOT NULL check constraint was not created:
+ column #{table}.#{column} is already defined as `NOT NULL`
+ MESSAGE
+
+ Gitlab::AppLogger.warn warning_message
+ end
+ end
+
+ def validate_not_null_constraint(table, column, constraint_name: nil)
+ validate_check_constraint(
+ table,
+ not_null_constraint_name(table, column, name: constraint_name)
+ )
+ end
+
+ def remove_not_null_constraint(table, column, constraint_name: nil)
+ remove_check_constraint(
+ table,
+ not_null_constraint_name(table, column, name: constraint_name)
+ )
+ end
+
+ def check_not_null_constraint_exists?(table, column, constraint_name: nil)
+ check_constraint_exists?(
+ table,
+ not_null_constraint_name(table, column, name: constraint_name)
+ )
+ end
+
+ def rename_constraint(table_name, old_name, new_name)
+ execute <<~SQL
+ ALTER TABLE #{quote_table_name(table_name)}
+ RENAME CONSTRAINT #{quote_column_name(old_name)} TO #{quote_column_name(new_name)}
+ SQL
+ end
+
+ def drop_constraint(table_name, constraint_name, cascade: false)
+ execute <<~SQL
+ ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(constraint_name)} #{cascade_statement(cascade)}
+ SQL
+ end
+
+ def validate_check_constraint_name!(constraint_name)
+ return unless constraint_name.to_s.length > MAX_IDENTIFIER_NAME_LENGTH
+
+ raise "The maximum allowed constraint name is #{MAX_IDENTIFIER_NAME_LENGTH} characters"
+ end
+
+ def text_limit_name(table, column, name: nil)
+ name.presence || check_constraint_name(table, column, 'max_length')
+ end
+
+ private
+
+ def validate_not_in_transaction!(method_name, modifier = nil)
+ return unless transaction_open?
+
+ raise <<~ERROR
+ #{["`#{method_name}`", modifier].compact.join(' ')} cannot be run inside a transaction.
+
+ You can disable transactions by calling `disable_ddl_transaction!` in the body of
+ your migration class
+ ERROR
+ end
+
+ # Returns an ActiveRecord::Result containing the check constraints
+ # defined for the given column.
+ #
+ # If the schema is not provided, then the current_schema is used
+ def check_constraints_for(table, column, schema: nil)
+ check_sql = <<~SQL
+ SELECT
+ ccu.table_schema as schema_name,
+ ccu.table_name as table_name,
+ ccu.column_name as column_name,
+ con.conname as constraint_name,
+ pg_get_constraintdef(con.oid) as constraint_def
+ 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
+ INNER JOIN information_schema.constraint_column_usage ccu
+ ON con.conname = ccu.constraint_name
+ AND nsp.nspname = ccu.constraint_schema
+ AND rel.relname = ccu.table_name
+ WHERE nsp.nspname = #{connection.quote(schema.presence || current_schema)}
+ AND rel.relname = #{connection.quote(table)}
+ AND ccu.column_name = #{connection.quote(column)}
+ AND con.contype = 'c'
+ ORDER BY constraint_name
+ SQL
+
+ connection.exec_query(check_sql)
+ end
+
+ def cascade_statement(cascade)
+ cascade ? 'CASCADE' : ''
+ end
+
+ def not_null_constraint_name(table, column, name: nil)
+ name.presence || check_constraint_name(table, column, 'not_null')
+ end
+
+ def missing_schema_object_message(table, type, name)
+ <<~MESSAGE
+ Could not find #{type} "#{name}" on table "#{table}" which was referenced during the migration.
+ This issue could be caused by the database schema straying from the expected state.
+
+ To resolve this issue, please verify:
+ 1. all previous migrations have completed
+ 2. the database objects used in this migration match the Rails definition in schema.rb or structure.sql
+
+ MESSAGE
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/migrations/extension_helpers.rb b/lib/gitlab/database/migrations/extension_helpers.rb
new file mode 100644
index 00000000000..435e9e0d2dc
--- /dev/null
+++ b/lib/gitlab/database/migrations/extension_helpers.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module Migrations
+ module ExtensionHelpers
+ def create_extension(extension)
+ execute("CREATE EXTENSION IF NOT EXISTS #{extension}")
+ rescue ActiveRecord::StatementInvalid => e
+ dbname = ApplicationRecord.database.database_name
+ user = ApplicationRecord.database.username
+
+ warn(<<~MSG) if e.to_s.include?('permission denied')
+ GitLab requires the PostgreSQL extension '#{extension}' installed in database '#{dbname}', but
+ the database user is not allowed to install the extension.
+
+ You can either install the extension manually using a database superuser:
+
+ CREATE EXTENSION IF NOT EXISTS #{extension}
+
+ Or, you can solve this by logging in to the GitLab
+ database (#{dbname}) using a superuser and running:
+
+ ALTER #{user} WITH SUPERUSER
+
+ This query will grant the user superuser permissions, ensuring any database extensions
+ can be installed through migrations.
+
+ For more information, refer to https://docs.gitlab.com/ee/install/postgresql_extensions.html.
+ MSG
+
+ raise
+ end
+
+ def drop_extension(extension)
+ execute("DROP EXTENSION IF EXISTS #{extension}")
+ rescue ActiveRecord::StatementInvalid => e
+ dbname = ApplicationRecord.database.database_name
+ user = ApplicationRecord.database.username
+
+ warn(<<~MSG) if e.to_s.include?('permission denied')
+ This migration attempts to drop the PostgreSQL extension '#{extension}'
+ installed in database '#{dbname}', but the database user is not allowed
+ to drop the extension.
+
+ You can either drop the extension manually using a database superuser:
+
+ DROP EXTENSION IF EXISTS #{extension}
+
+ Or, you can solve this by logging in to the GitLab
+ database (#{dbname}) using a superuser and running:
+
+ ALTER #{user} WITH SUPERUSER
+
+ This query will grant the user superuser permissions, ensuring any database extensions
+ can be dropped through migrations.
+
+ For more information, refer to https://docs.gitlab.com/ee/install/postgresql_extensions.html.
+ MSG
+
+ raise
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/migrations/lock_retries_helpers.rb b/lib/gitlab/database/migrations/lock_retries_helpers.rb
new file mode 100644
index 00000000000..137ef3ab144
--- /dev/null
+++ b/lib/gitlab/database/migrations/lock_retries_helpers.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module Migrations
+ module LockRetriesHelpers
+ # Executes the block with a retry mechanism that alters the +lock_timeout+ and +sleep_time+ between attempts.
+ # The timings can be controlled via the +timing_configuration+ parameter.
+ # If the lock was not acquired within the retry period, a last attempt is made without using +lock_timeout+.
+ #
+ # Note this helper uses subtransactions when run inside an already open transaction.
+ #
+ # ==== Examples
+ # # Invoking without parameters
+ # with_lock_retries do
+ # drop_table :my_table
+ # end
+ #
+ # # Invoking with custom +timing_configuration+
+ # t = [
+ # [1.second, 1.second],
+ # [2.seconds, 2.seconds]
+ # ]
+ #
+ # with_lock_retries(timing_configuration: t) do
+ # drop_table :my_table # this will be retried twice
+ # end
+ #
+ # # Disabling the retries using an environment variable
+ # > export DISABLE_LOCK_RETRIES=true
+ #
+ # with_lock_retries do
+ # drop_table :my_table # one invocation, it will not retry at all
+ # end
+ #
+ # ==== Parameters
+ # * +timing_configuration+ - [[ActiveSupport::Duration, ActiveSupport::Duration], ...] lock timeout for the
+ # block, sleep time before the next iteration, defaults to
+ # `Gitlab::Database::WithLockRetries::DEFAULT_TIMING_CONFIGURATION`
+ # * +logger+ - [Gitlab::JsonLogger]
+ # * +env+ - [Hash] custom environment hash, see the example with `DISABLE_LOCK_RETRIES`
+ def with_lock_retries(*args, **kwargs, &block)
+ raise_on_exhaustion = !!kwargs.delete(:raise_on_exhaustion)
+ merged_args = {
+ connection: connection,
+ klass: self.class,
+ logger: Gitlab::BackgroundMigration::Logger,
+ allow_savepoints: true
+ }.merge(kwargs)
+
+ Gitlab::Database::WithLockRetries.new(**merged_args)
+ .run(raise_on_exhaustion: raise_on_exhaustion, &block)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/migrations/runner.rb b/lib/gitlab/database/migrations/runner.rb
index 85dc6051c7c..27b161419b2 100644
--- a/lib/gitlab/database/migrations/runner.rb
+++ b/lib/gitlab/database/migrations/runner.rb
@@ -7,6 +7,7 @@ module Gitlab
BASE_RESULT_DIR = Rails.root.join('tmp', 'migration-testing').freeze
METADATA_FILENAME = 'metadata.json'
SCHEMA_VERSION = 4 # Version of the output format produced by the runner
+ POST_MIGRATION_MATCHER = %r{db/post_migrate/}.freeze
class << self
def up(database:, legacy_mode: false)
@@ -116,7 +117,10 @@ module Gitlab
verbose_was = ActiveRecord::Migration.verbose
ActiveRecord::Migration.verbose = true
- sorted_migrations = migrations.sort_by(&:version)
+ sorted_migrations = migrations.sort_by do |m|
+ [m.filename.match?(POST_MIGRATION_MATCHER) ? 1 : 0, m.version]
+ end
+
sorted_migrations.reverse! if direction == :down
instrumentation = Instrumentation.new(result_dir: result_dir)
diff --git a/lib/gitlab/database/migrations/timeout_helpers.rb b/lib/gitlab/database/migrations/timeout_helpers.rb
new file mode 100644
index 00000000000..423c77452b1
--- /dev/null
+++ b/lib/gitlab/database/migrations/timeout_helpers.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module Migrations
+ module TimeoutHelpers
+ # Long-running migrations may take more than the timeout allowed by
+ # the database. Disable the session's statement timeout to ensure
+ # migrations don't get killed prematurely.
+ #
+ # There are two possible ways to disable the statement timeout:
+ #
+ # - Per transaction (this is the preferred and default mode)
+ # - Per connection (requires a cleanup after the execution)
+ #
+ # When using a per connection disable statement, code must be inside
+ # a block so we can automatically execute `RESET statement_timeout` after block finishes
+ # otherwise the statement will still be disabled until connection is dropped
+ # or `RESET statement_timeout` is executed
+ def disable_statement_timeout
+ if block_given?
+ if statement_timeout_disabled?
+ # Don't do anything if the statement_timeout is already disabled
+ # Allows for nested calls of disable_statement_timeout without
+ # resetting the timeout too early (before the outer call ends)
+ yield
+ else
+ begin
+ execute('SET statement_timeout TO 0')
+
+ yield
+ ensure
+ execute('RESET statement_timeout')
+ end
+ end
+ else
+ unless transaction_open?
+ raise <<~ERROR
+ Cannot call disable_statement_timeout() without a transaction open or outside of a transaction block.
+ If you don't want to use a transaction wrap your code in a block call:
+
+ disable_statement_timeout { # code that requires disabled statement here }
+
+ This will make sure statement_timeout is disabled before and reset after the block execution is finished.
+ ERROR
+ end
+
+ execute('SET LOCAL statement_timeout TO 0')
+ end
+ end
+
+ private
+
+ def statement_timeout_disabled?
+ # This is a string of the form "100ms" or "0" when disabled
+ connection.select_value('SHOW statement_timeout') == "0"
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/partitioning/convert_table_to_first_list_partition.rb b/lib/gitlab/database/partitioning/convert_table_to_first_list_partition.rb
index 23a8dc0b44f..58447481e60 100644
--- a/lib/gitlab/database/partitioning/convert_table_to_first_list_partition.rb
+++ b/lib/gitlab/database/partitioning/convert_table_to_first_list_partition.rb
@@ -10,13 +10,17 @@ module Gitlab
attr_reader :partitioning_column, :table_name, :parent_table_name, :zero_partition_value
- def initialize(migration_context:, table_name:, parent_table_name:, partitioning_column:, zero_partition_value:)
+ def initialize(
+ migration_context:, table_name:, parent_table_name:, partitioning_column:,
+ zero_partition_value:, lock_tables: [])
+
@migration_context = migration_context
@connection = migration_context.connection
@table_name = table_name
@parent_table_name = parent_table_name
@partitioning_column = partitioning_column
@zero_partition_value = zero_partition_value
+ @lock_tables = Array.wrap(lock_tables)
end
def prepare_for_partitioning
@@ -35,7 +39,12 @@ module Gitlab
create_parent_table
attach_foreign_keys_to_parent
- migration_context.with_lock_retries(raise_on_exhaustion: true) do
+ lock_args = {
+ raise_on_exhaustion: true,
+ timing_configuration: lock_timing_configuration
+ }
+
+ migration_context.with_lock_retries(**lock_args) do
migration_context.execute(sql_to_convert_table)
end
end
@@ -74,6 +83,7 @@ module Gitlab
# but they acquire the same locks so it's much faster to incude them
# here.
[
+ lock_tables_statement,
attach_table_to_parent_statement,
alter_sequence_statements(old_table: table_name, new_table: parent_table_name),
remove_constraint_statement
@@ -162,6 +172,16 @@ module Gitlab
end
end
+ def lock_tables_statement
+ return if @lock_tables.empty?
+
+ table_names = @lock_tables.map { |name| quote_table_name(name) }.join(', ')
+
+ <<~SQL
+ LOCK #{table_names} IN ACCESS EXCLUSIVE MODE
+ SQL
+ end
+
def attach_table_to_parent_statement
<<~SQL
ALTER TABLE #{quote_table_name(parent_table_name)}
@@ -235,6 +255,13 @@ module Gitlab
ALTER TABLE #{connection.quote_table_name(table_name)} OWNER TO CURRENT_USER
SQL
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
end
end
diff --git a/lib/gitlab/database/partitioning/detached_partition_dropper.rb b/lib/gitlab/database/partitioning/detached_partition_dropper.rb
index 5e32ecad4ca..58c0728b614 100644
--- a/lib/gitlab/database/partitioning/detached_partition_dropper.rb
+++ b/lib/gitlab/database/partitioning/detached_partition_dropper.rb
@@ -7,7 +7,7 @@ module Gitlab
Gitlab::AppLogger.info(message: "Checking for previously detached partitions to drop")
Postgresql::DetachedPartition.ready_to_drop.find_each do |detached_partition|
- if partition_attached?(qualify_partition_name(detached_partition.table_name))
+ if partition_attached?(detached_partition.fully_qualified_table_name)
unmark_partition(detached_partition)
else
drop_partition(detached_partition)
@@ -41,14 +41,14 @@ module Gitlab
# Another process may have already dropped the table and deleted this entry
next unless try_lock_detached_partition(detached_partition.id)
- drop_detached_partition(detached_partition.table_name)
+ drop_detached_partition(detached_partition)
detached_partition.destroy!
end
end
def remove_foreign_keys(detached_partition)
- partition_identifier = qualify_partition_name(detached_partition.table_name)
+ partition_identifier = detached_partition.fully_qualified_table_name
# We want to load all of these into memory at once to get a consistent view to loop over,
# since we'll be deleting from this list as we go
@@ -65,7 +65,7 @@ module Gitlab
# It is important to only drop one foreign key per transaction.
# Dropping a foreign key takes an ACCESS EXCLUSIVE lock on both tables participating in the foreign key.
- partition_identifier = qualify_partition_name(detached_partition.table_name)
+ partition_identifier = detached_partition.fully_qualified_table_name
with_lock_retries do
connection.transaction(requires_new: false) do
next unless try_lock_detached_partition(detached_partition.id)
@@ -83,16 +83,10 @@ module Gitlab
end
end
- def drop_detached_partition(partition_name)
- partition_identifier = qualify_partition_name(partition_name)
+ def drop_detached_partition(detached_partition)
+ connection.drop_table(detached_partition.fully_qualified_table_name, if_exists: true)
- connection.drop_table(partition_identifier, if_exists: true)
-
- Gitlab::AppLogger.info(message: "Dropped previously detached partition", partition_name: partition_name)
- end
-
- def qualify_partition_name(table_name)
- "#{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}.#{table_name}"
+ Gitlab::AppLogger.info(message: "Dropped previously detached partition", partition_name: detached_partition.table_name)
end
def partition_attached?(partition_identifier)
diff --git a/lib/gitlab/database/partitioning_migration_helpers/index_helpers.rb b/lib/gitlab/database/partitioning_migration_helpers/index_helpers.rb
index 15b542cf089..62f33bb56bc 100644
--- a/lib/gitlab/database/partitioning_migration_helpers/index_helpers.rb
+++ b/lib/gitlab/database/partitioning_migration_helpers/index_helpers.rb
@@ -7,6 +7,8 @@ module Gitlab
include Gitlab::Database::MigrationHelpers
include Gitlab::Database::SchemaHelpers
+ DuplicatedIndexesError = Class.new(StandardError)
+
ERROR_SCOPE = 'index'
# Concurrently creates a new index on a partitioned table. In concept this works similarly to
@@ -38,7 +40,7 @@ module Gitlab
partitioned_table.postgres_partitions.order(:name).each do |partition|
partition_index_name = generated_index_name(partition.identifier, options[:name])
- partition_options = options.merge(name: partition_index_name)
+ partition_options = options.merge(name: partition_index_name, allow_partition: true)
add_concurrent_index(partition.identifier, column_names, partition_options)
end
@@ -92,6 +94,42 @@ module Gitlab
.map { |_, indexes| indexes.map { |index| index['index_name'] } }
end
+ # Retrieves a hash of index names for a given table and schema, by index
+ # definition.
+ #
+ # Example:
+ #
+ # indexes_by_definition_for_table('table_name_goes_here')
+ #
+ # Returns:
+ #
+ # {
+ # "CREATE _ btree (created_at)" => "index_on_created_at"
+ # }
+ def indexes_by_definition_for_table(table_name, schema_name: connection.current_schema)
+ duplicate_indexes = find_duplicate_indexes(table_name, schema_name: schema_name)
+
+ unless duplicate_indexes.empty?
+ raise DuplicatedIndexesError, "#{table_name} has duplicate indexes: #{duplicate_indexes}"
+ end
+
+ find_indexes(table_name, schema_name: schema_name)
+ .each_with_object({}) { |row, hash| hash[row['index_id']] = row['index_name'] }
+ end
+
+ # Renames indexes for a given table and schema, mapping by index
+ # definition, to a hash of new index names.
+ #
+ # Example:
+ #
+ # index_names = indexes_by_definition_for_table('source_table_name_goes_here')
+ # drop_table('source_table_name_goes_here')
+ # rename_indexes_for_table('destination_table_name_goes_here', index_names)
+ def rename_indexes_for_table(table_name, new_index_names, schema_name: connection.current_schema)
+ current_index_names = indexes_by_definition_for_table(table_name, schema_name: schema_name)
+ rename_indexes(current_index_names, new_index_names, schema_name: schema_name)
+ end
+
private
def find_indexes(table_name, schema_name: connection.current_schema)
@@ -124,6 +162,18 @@ module Gitlab
def generated_index_name(partition_name, index_name)
object_name("#{partition_name}_#{index_name}", 'index')
end
+
+ def rename_indexes(from, to, schema_name: connection.current_schema)
+ indexes_to_rename = from.select { |index_id, _| to.has_key?(index_id) }
+ statements = indexes_to_rename.map do |index_id, index_name|
+ <<~SQL
+ ALTER INDEX #{connection.quote_table_name("#{schema_name}.#{connection.quote_column_name(index_name)}")}
+ RENAME TO #{connection.quote_column_name(to[index_id])}
+ SQL
+ end
+
+ connection.execute(statements.join(';'))
+ end
end
end
end
diff --git a/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers.rb b/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers.rb
index 695a5d7ec77..f9790bf53b9 100644
--- a/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers.rb
+++ b/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers.rb
@@ -275,7 +275,7 @@ module Gitlab
).revert_preparation_for_partitioning
end
- def convert_table_to_first_list_partition(table_name:, partitioning_column:, parent_table_name:, initial_partitioning_value:)
+ def convert_table_to_first_list_partition(table_name:, partitioning_column:, parent_table_name:, initial_partitioning_value:, lock_tables: [])
validate_not_in_transaction!(:convert_table_to_first_list_partition)
Gitlab::Database::Partitioning::ConvertTableToFirstListPartition
@@ -283,7 +283,8 @@ module Gitlab
table_name: table_name,
parent_table_name: parent_table_name,
partitioning_column: partitioning_column,
- zero_partition_value: initial_partitioning_value
+ zero_partition_value: initial_partitioning_value,
+ lock_tables: lock_tables
).partition
end
diff --git a/lib/gitlab/database/postgres_partition.rb b/lib/gitlab/database/postgres_partition.rb
index eb080904f73..eda11fd8382 100644
--- a/lib/gitlab/database/postgres_partition.rb
+++ b/lib/gitlab/database/postgres_partition.rb
@@ -19,6 +19,20 @@ module Gitlab
scope :for_parent_table, ->(name) { where("parent_identifier = concat(current_schema(), '.', ?)", name).order(:name) }
+ def self.partition_exists?(table_name)
+ where("identifier = concat(current_schema(), '.', ?)", table_name).exists?
+ end
+
+ def self.legacy_partition_exists?(table_name)
+ result = connection.select_value(<<~SQL)
+ SELECT true FROM pg_class
+ WHERE relname = '#{table_name}'
+ AND relispartition = true;
+ SQL
+
+ !!result
+ end
+
def to_s
name
end
diff --git a/lib/gitlab/database/query_analyzer.rb b/lib/gitlab/database/query_analyzer.rb
index 6f64d04270f..1280789b30c 100644
--- a/lib/gitlab/database/query_analyzer.rb
+++ b/lib/gitlab/database/query_analyzer.rb
@@ -86,7 +86,11 @@ module Gitlab
analyzers.each do |analyzer|
next if analyzer.suppressed? && !analyzer.requires_tracking?(parsed)
- analyzer.analyze(parsed)
+ if analyzer.raw?
+ analyzer.analyze(sql)
+ else
+ analyzer.analyze(parsed)
+ end
rescue StandardError, ::Gitlab::Database::QueryAnalyzers::Base::QueryAnalyzerError => e
# We catch all standard errors to prevent validation errors to introduce fatal errors in production
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e)
diff --git a/lib/gitlab/database/query_analyzers/base.rb b/lib/gitlab/database/query_analyzers/base.rb
index 9a52a4f6e23..9c2c228f869 100644
--- a/lib/gitlab/database/query_analyzers/base.rb
+++ b/lib/gitlab/database/query_analyzers/base.rb
@@ -53,6 +53,10 @@ module Gitlab
Thread.current[self.context_key]
end
+ def self.raw?
+ false
+ end
+
def self.enabled?
raise NotImplementedError
end
diff --git a/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer.rb b/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer.rb
deleted file mode 100644
index c2d5dfc1a15..00000000000
--- a/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Database
- module QueryAnalyzers
- module Ci
- # The purpose of this analyzer is to detect queries not going through a partitioning routing table
- class PartitioningAnalyzer < Database::QueryAnalyzers::Base
- RoutingTableNotUsedError = Class.new(QueryAnalyzerError)
-
- ENABLED_TABLES = %w[
- ci_builds_metadata
- ].freeze
-
- class << self
- def enabled?
- ::Feature::FlipperFeature.table_exists? &&
- ::Feature.enabled?(:ci_partitioning_analyze_queries, type: :ops)
- end
-
- def analyze(parsed)
- analyze_legacy_tables_usage(parsed)
- end
-
- private
-
- def analyze_legacy_tables_usage(parsed)
- detected = ENABLED_TABLES & (parsed.pg.dml_tables + parsed.pg.select_tables)
-
- return if detected.none?
-
- ::Gitlab::ErrorTracking.track_and_raise_for_dev_exception(
- RoutingTableNotUsedError.new("Detected non-partitioned table use #{detected.inspect}: #{parsed.sql}")
- )
- end
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer.rb b/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer.rb
new file mode 100644
index 00000000000..47277182d9a
--- /dev/null
+++ b/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module QueryAnalyzers
+ module Ci
+ # The purpose of this analyzer is to detect queries missing partition_id clause
+ # when selecting, inserting, updating or deleting data.
+ class PartitioningIdAnalyzer < Database::QueryAnalyzers::Base
+ PartitionIdMissingError = Class.new(QueryAnalyzerError)
+
+ ROUTING_TABLES = %w[p_ci_builds_metadata].freeze
+
+ class << self
+ def enabled?
+ ::Feature::FlipperFeature.table_exists? &&
+ ::Feature.enabled?(:ci_partitioning_analyze_queries_partition_id_check, type: :ops)
+ end
+
+ def analyze(parsed)
+ analyze_partition_id_presence(parsed)
+ end
+
+ private
+
+ def analyze_partition_id_presence(parsed)
+ detected = ROUTING_TABLES & (parsed.pg.dml_tables + parsed.pg.select_tables)
+ return if detected.none?
+
+ if insert_query?(parsed)
+ return if insert_include_partition_id?(parsed)
+ else
+ detected_with_selected_columns = parsed_detected_tables(parsed, detected)
+ return if partition_id_included?(detected_with_selected_columns)
+ end
+
+ ::Gitlab::ErrorTracking.track_and_raise_for_dev_exception(
+ PartitionIdMissingError.new(
+ "Detected query against a partitioned table without partition id: #{parsed.sql}"
+ )
+ )
+ end
+
+ def parsed_detected_tables(parsed, routing_tables)
+ parsed.pg.filter_columns.each_with_object(Hash.new { |h, k| h[k] = [] }) do |item, hash|
+ table_name = item[0] || routing_tables[0]
+ column_name = item[1]
+
+ hash[table_name] << column_name if routing_tables.include?(table_name)
+ end
+ end
+
+ def partition_id_included?(result)
+ return false if result.empty?
+
+ result.all? { |_routing_table, columns| columns.include?('partition_id') }
+ end
+
+ def insert_query?(parsed)
+ parsed.sql.start_with?('INSERT')
+ end
+
+ def insert_include_partition_id?(parsed)
+ filtered_columns_on_insert(parsed).include?('partition_id')
+ end
+
+ def filtered_columns_on_insert(parsed)
+ result = parsed.pg.tree.to_h.dig(:stmts, 0, :stmt, :insert_stmt, :cols).map do |h|
+ h.dig(:res_target, :name)
+ end
+
+ result || []
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer.rb b/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer.rb
new file mode 100644
index 00000000000..eb55ebc7619
--- /dev/null
+++ b/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module QueryAnalyzers
+ module Ci
+ # The purpose of this analyzer is to detect queries not going through a partitioning routing table
+ class PartitioningRoutingAnalyzer < Database::QueryAnalyzers::Base
+ RoutingTableNotUsedError = Class.new(QueryAnalyzerError)
+
+ ENABLED_TABLES = %w[ci_builds_metadata].freeze
+
+ class << self
+ def enabled?
+ ::Feature::FlipperFeature.table_exists? &&
+ ::Feature.enabled?(:ci_partitioning_analyze_queries, type: :ops)
+ end
+
+ def analyze(parsed)
+ analyze_legacy_tables_usage(parsed)
+ end
+
+ private
+
+ def analyze_legacy_tables_usage(parsed)
+ detected = ENABLED_TABLES & (parsed.pg.dml_tables + parsed.pg.select_tables)
+
+ return if detected.none?
+
+ ::Gitlab::ErrorTracking.track_and_raise_for_dev_exception(
+ RoutingTableNotUsedError.new("Detected non-partitioned table use #{detected.inspect}: #{parsed.sql}")
+ )
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/query_analyzers/query_recorder.rb b/lib/gitlab/database/query_analyzers/query_recorder.rb
new file mode 100644
index 00000000000..88fe829c3d2
--- /dev/null
+++ b/lib/gitlab/database/query_analyzers/query_recorder.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module QueryAnalyzers
+ class QueryRecorder < Base
+ LOG_FILE = 'rspec/query_recorder.ndjson'
+
+ class << self
+ def raw?
+ true
+ end
+
+ def enabled?
+ # Only enable QueryRecorder in CI
+ ENV['CI'].present?
+ end
+
+ def analyze(sql)
+ payload = {
+ sql: sql
+ }
+
+ log_query(payload)
+ end
+
+ private
+
+ def log_query(payload)
+ log_path = Rails.root.join(LOG_FILE)
+ log_dir = File.dirname(log_path)
+
+ # Create log directory if it does not exist since it is only created
+ # ahead of time by certain CI jobs
+ FileUtils.mkdir_p(log_dir) unless Dir.exist?(log_dir)
+
+ log_line = "#{Gitlab::Json.dump(payload)}\n"
+
+ File.write(log_path, log_line, mode: 'a')
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/tables_truncate.rb b/lib/gitlab/database/tables_truncate.rb
index 164520fbab3..8380bf23899 100644
--- a/lib/gitlab/database/tables_truncate.rb
+++ b/lib/gitlab/database/tables_truncate.rb
@@ -14,7 +14,7 @@ module Gitlab
end
def execute
- raise "Cannot truncate legacy tables in single-db setup" unless Gitlab::Database.has_config?(:ci)
+ raise "Cannot truncate legacy tables in single-db setup" if single_database_setup?
raise "database is not supported" unless %w[main ci].include?(database_name)
logger&.info "DRY RUN:" if dry_run
@@ -91,6 +91,13 @@ module Gitlab
end
end
end
+
+ def single_database_setup?
+ return true unless Gitlab::Database.has_config?(:ci)
+
+ ci_base_model = Gitlab::Database.database_base_models[:ci]
+ !!Gitlab::Database.db_config_share_with(ci_base_model.connection_db_config)
+ end
end
end
end
diff --git a/lib/gitlab/database/type/symbolized_jsonb.rb b/lib/gitlab/database/type/symbolized_jsonb.rb
new file mode 100644
index 00000000000..5bec738ec9c
--- /dev/null
+++ b/lib/gitlab/database/type/symbolized_jsonb.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Database
+ module Type
+ # Extends Rails' Jsonb data type to deserialize it into symbolized Hash.
+ #
+ # Example:
+ #
+ # class SomeModel < ApplicationRecord
+ # # some_model.a_field is of type `jsonb`
+ # attribute :a_field, :sym_jsonb
+ # end
+ class SymbolizedJsonb < ::ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Jsonb
+ def type
+ :sym_jsonb
+ end
+
+ def deserialize(value)
+ data = super
+ return unless data
+
+ ::Gitlab::Utils.deep_symbolized_access(data)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database_importers/self_monitoring/project/create_service.rb b/lib/gitlab/database_importers/self_monitoring/project/create_service.rb
index 57d354eb907..be500171bef 100644
--- a/lib/gitlab/database_importers/self_monitoring/project/create_service.rb
+++ b/lib/gitlab/database_importers/self_monitoring/project/create_service.rb
@@ -98,7 +98,7 @@ module Gitlab
if environment.save
success(result)
else
- log_error("Could not create environment for the Self monitoring project. Errors: %{errors}" % { errors: environment.errors.full_messages })
+ log_error("Could not create environment for the Self-monitoring project. Errors: %{errors}" % { errors: environment.errors.full_messages })
error(_('Could not create environment'))
end
end
diff --git a/lib/gitlab/database_importers/self_monitoring/project/delete_service.rb b/lib/gitlab/database_importers/self_monitoring/project/delete_service.rb
index 998977b4000..d5bed94d735 100644
--- a/lib/gitlab/database_importers/self_monitoring/project/delete_service.rb
+++ b/lib/gitlab/database_importers/self_monitoring/project/delete_service.rb
@@ -23,7 +23,7 @@ module Gitlab
def validate_self_monitoring_project_exists(result)
unless project_created? || self_monitoring_project_id.present?
- return error(_('Self monitoring project does not exist'))
+ return error(_('Self-monitoring project does not exist'))
end
success(result)
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index 5583c896803..d5c0b187f92 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -44,10 +44,6 @@ module Gitlab
add_blobs_to_batch_loader
end
- def use_semantic_ipynb_diff?
- strong_memoize(:_use_semantic_ipynb_diff) { Feature.enabled?(:ipynb_semantic_diff, repository.project) }
- end
-
def has_renderable?
rendered&.has_renderable?
end
@@ -372,7 +368,7 @@ module Gitlab
end
def rendered
- return unless use_semantic_ipynb_diff? && ipynb? && modified_file? && !collapsed? && !too_large?
+ return unless ipynb? && modified_file? && !collapsed? && !too_large?
strong_memoize(:rendered) { Rendered::Notebook::DiffFile.new(self) }
end
diff --git a/lib/gitlab/diff/file_collection/base.rb b/lib/gitlab/diff/file_collection/base.rb
index 924de132840..ae55dae1201 100644
--- a/lib/gitlab/diff/file_collection/base.rb
+++ b/lib/gitlab/diff/file_collection/base.rb
@@ -46,7 +46,9 @@ module Gitlab
# This is either the new path, otherwise the old path for the diff_file
def diff_file_paths
- diff_files.map(&:file_path)
+ diffs.map do |diff|
+ diff.new_path.presence || diff.old_path
+ end
end
# This is both the new and old paths for the diff_file
diff --git a/lib/gitlab/diff/highlight_cache.rb b/lib/gitlab/diff/highlight_cache.rb
index d6f5e45c034..5128b09aef4 100644
--- a/lib/gitlab/diff/highlight_cache.rb
+++ b/lib/gitlab/diff/highlight_cache.rb
@@ -62,7 +62,7 @@ module Gitlab
end
def clear
- Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.del(key)
end
end
@@ -124,7 +124,7 @@ module Gitlab
# ...it will write/update a Gitlab::Redis hash (HSET)
#
def write_to_redis_hash(hash)
- Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.pipelined do |pipeline|
hash.each do |diff_file_id, highlighted_diff_lines_hash|
pipeline.hset(
@@ -132,7 +132,7 @@ module Gitlab
diff_file_id,
gzip_compress(highlighted_diff_lines_hash.to_json)
)
- rescue Encoding::UndefinedConversionError
+ rescue Encoding::UndefinedConversionError, EncodingError, JSON::GeneratorError
nil
end
@@ -189,7 +189,7 @@ module Gitlab
results = []
cache_key = key # Moving out redis calls for feature flags out of redis.pipelined
- Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.pipelined do |pipeline|
results = pipeline.hmget(cache_key, file_paths)
pipeline.expire(key, EXPIRATION)
@@ -223,6 +223,10 @@ module Gitlab
::Gitlab::Metrics::WebTransaction.current
end
+ def with_redis(&block)
+ Gitlab::Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord
+ end
+
def record_hit_ratio(results)
current_transaction&.increment(:gitlab_redis_diff_caching_requests_total)
current_transaction&.increment(:gitlab_redis_diff_caching_hits_total) if results.any?(&:present?)
diff --git a/lib/gitlab/discussions_diff/highlight_cache.rb b/lib/gitlab/discussions_diff/highlight_cache.rb
index 3337aeb9262..14cb773251b 100644
--- a/lib/gitlab/discussions_diff/highlight_cache.rb
+++ b/lib/gitlab/discussions_diff/highlight_cache.rb
@@ -14,12 +14,14 @@ module Gitlab
#
# mapping - Write multiple cache values at once
def write_multiple(mapping)
- Redis::Cache.with do |redis|
- redis.multi do |multi|
- mapping.each do |raw_key, value|
- key = cache_key_for(raw_key)
+ with_redis do |redis|
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ redis.multi do |multi|
+ mapping.each do |raw_key, value|
+ key = cache_key_for(raw_key)
- multi.set(key, gzip_compress(value.to_json), ex: EXPIRATION)
+ multi.set(key, gzip_compress(value.to_json), ex: EXPIRATION)
+ end
end
end
end
@@ -37,7 +39,7 @@ module Gitlab
keys = raw_keys.map { |id| cache_key_for(id) }
content =
- Redis::Cache.with do |redis|
+ with_redis do |redis|
Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
redis.mget(keys)
end
@@ -62,7 +64,7 @@ module Gitlab
keys = raw_keys.map { |id| cache_key_for(id) }
- Redis::Cache.with do |redis|
+ with_redis do |redis|
Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
redis.del(keys)
end
@@ -78,6 +80,10 @@ module Gitlab
def cache_key_prefix
"#{Redis::Cache::CACHE_NAMESPACE}:#{VERSION}:discussion-highlight"
end
+
+ def with_redis(&block)
+ Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord
+ end
end
end
end
diff --git a/lib/gitlab/doorkeeper_secret_storing/token/pbkdf2_sha512.rb b/lib/gitlab/doorkeeper_secret_storing/token/pbkdf2_sha512.rb
index f9e6d4076f3..7bb9ac2ffdb 100644
--- a/lib/gitlab/doorkeeper_secret_storing/token/pbkdf2_sha512.rb
+++ b/lib/gitlab/doorkeeper_secret_storing/token/pbkdf2_sha512.rb
@@ -12,8 +12,6 @@ module Gitlab
SALT = ''
def self.transform_secret(plain_secret)
- return plain_secret unless Feature.enabled?(:hash_oauth_tokens)
-
Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512.digest(plain_secret, STRETCHES, SALT)
end
diff --git a/lib/gitlab/email/common.rb b/lib/gitlab/email/common.rb
new file mode 100644
index 00000000000..afee8d9cd3d
--- /dev/null
+++ b/lib/gitlab/email/common.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Email
+ # Contains common methods which must be present in all email classes
+ module Common
+ UNSUBSCRIBE_SUFFIX = '-unsubscribe'
+ UNSUBSCRIBE_SUFFIX_LEGACY = '+unsubscribe'
+ WILDCARD_PLACEHOLDER = '%{key}'
+
+ # This can be overridden for a custom config
+ def config
+ raise NotImplementedError
+ end
+
+ def incoming_email_config
+ Gitlab.config.incoming_email
+ end
+
+ def enabled?
+ !!config&.enabled && config.address.present?
+ end
+
+ def supports_wildcard?
+ config_address = incoming_email_config.address
+
+ config_address.present? && config_address.include?(WILDCARD_PLACEHOLDER)
+ end
+
+ def supports_issue_creation?
+ enabled? && supports_wildcard?
+ end
+
+ def reply_address(key)
+ incoming_email_config.address.sub(WILDCARD_PLACEHOLDER, key)
+ end
+
+ # example: incoming+1234567890abcdef1234567890abcdef-unsubscribe@incoming.gitlab.com
+ def unsubscribe_address(key)
+ incoming_email_config.address.sub(WILDCARD_PLACEHOLDER, "#{key}#{UNSUBSCRIBE_SUFFIX}")
+ end
+
+ def key_from_address(address, wildcard_address: nil)
+ raise NotImplementedError
+ end
+
+ def key_from_fallback_message_id(mail_id)
+ message_id_regexp = /\Areply-(.+)@#{Gitlab.config.gitlab.host}\z/
+
+ mail_id[message_id_regexp, 1]
+ end
+
+ def scan_fallback_references(references)
+ # It's looking for each <...>
+ references.scan(/(?!<)[^<>]+(?=>)/)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/email/handler/create_issue_handler.rb b/lib/gitlab/email/handler/create_issue_handler.rb
index 434893eab82..e21a88c4e0d 100644
--- a/lib/gitlab/email/handler/create_issue_handler.rb
+++ b/lib/gitlab/email/handler/create_issue_handler.rb
@@ -73,7 +73,7 @@ module Gitlab
end
def can_handle_legacy_format?
- project_path && !incoming_email_token.include?('+') && !mail_key.include?(Gitlab::IncomingEmail::UNSUBSCRIBE_SUFFIX_LEGACY)
+ project_path && !incoming_email_token.include?('+') && !mail_key.include?(Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX_LEGACY)
end
end
end
diff --git a/lib/gitlab/email/handler/unsubscribe_handler.rb b/lib/gitlab/email/handler/unsubscribe_handler.rb
index 528857aff14..a4e526d9a24 100644
--- a/lib/gitlab/email/handler/unsubscribe_handler.rb
+++ b/lib/gitlab/email/handler/unsubscribe_handler.rb
@@ -12,8 +12,8 @@ module Gitlab
delegate :project, to: :sent_notification, allow_nil: true
HANDLER_REGEX_FOR = -> (suffix) { /\A(?<reply_token>\w+)#{Regexp.escape(suffix)}\z/ }.freeze
- HANDLER_REGEX = HANDLER_REGEX_FOR.call(Gitlab::IncomingEmail::UNSUBSCRIBE_SUFFIX).freeze
- HANDLER_REGEX_LEGACY = HANDLER_REGEX_FOR.call(Gitlab::IncomingEmail::UNSUBSCRIBE_SUFFIX_LEGACY).freeze
+ HANDLER_REGEX = HANDLER_REGEX_FOR.call(Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX).freeze
+ HANDLER_REGEX_LEGACY = HANDLER_REGEX_FOR.call(Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX_LEGACY).freeze
def initialize(mail, mail_key)
super(mail, mail_key)
diff --git a/lib/gitlab/email/receiver.rb b/lib/gitlab/email/receiver.rb
index ba84be6e8ca..1e03f5d17ee 100644
--- a/lib/gitlab/email/receiver.rb
+++ b/lib/gitlab/email/receiver.rb
@@ -10,6 +10,14 @@ module Gitlab
RECEIVED_HEADER_REGEX = /for\s+\<(.+)\>/.freeze
+ # Errors that are purely from users and not anything we can control
+ USER_ERRORS = [
+ Gitlab::Email::AutoGeneratedEmailError, Gitlab::Email::ProjectNotFound, Gitlab::Email::EmptyEmailError,
+ Gitlab::Email::UserNotFoundError, Gitlab::Email::UserBlockedError, Gitlab::Email::UserNotAuthorizedError,
+ Gitlab::Email::NoteableNotFoundError, Gitlab::Email::InvalidAttachment, Gitlab::Email::InvalidRecordError,
+ Gitlab::Email::EmailTooLarge
+ ].freeze
+
def initialize(raw)
@raw = raw
end
@@ -24,6 +32,9 @@ module Gitlab
handler.execute.tap do
Gitlab::Metrics::BackgroundTransaction.current&.add_event(handler.metrics_event, handler.metrics_params)
end
+ rescue *USER_ERRORS => e
+ # do not send a metric event since these are purely user errors that we can't control
+ raise e
rescue StandardError => e
Gitlab::Metrics::BackgroundTransaction.current&.add_event('email_receiver_error', error: e.class.name)
raise e
diff --git a/lib/gitlab/environment.rb b/lib/gitlab/environment.rb
index 3c6ed696b9d..b1a9603d3a5 100644
--- a/lib/gitlab/environment.rb
+++ b/lib/gitlab/environment.rb
@@ -5,9 +5,5 @@ module Gitlab
def self.hostname
@hostname ||= ENV['HOSTNAME'] || Socket.gethostname
end
-
- def self.qa_user_agent
- ENV['GITLAB_QA_USER_AGENT']
- end
end
end
diff --git a/lib/gitlab/error_tracking.rb b/lib/gitlab/error_tracking.rb
index 83920182da4..582c3380869 100644
--- a/lib/gitlab/error_tracking.rb
+++ b/lib/gitlab/error_tracking.rb
@@ -131,6 +131,9 @@ module Gitlab
end
def before_send(event, hint)
+ # Don't report Sidekiq retry errors to Sentry
+ return if hint[:exception].is_a?(Gitlab::SidekiqMiddleware::RetryError)
+
inject_context_for_exception(event, hint[:exception])
custom_fingerprinting(event, hint[:exception])
diff --git a/lib/gitlab/etag_caching/store.rb b/lib/gitlab/etag_caching/store.rb
index 437d577e70e..bc97c88ce85 100644
--- a/lib/gitlab/etag_caching/store.rb
+++ b/lib/gitlab/etag_caching/store.rb
@@ -15,10 +15,12 @@ module Gitlab
def touch(*keys, only_if_missing: false)
etags = keys.map { generate_etag }
- Gitlab::Redis::SharedState.with do |redis|
- redis.pipelined do |pipeline|
- keys.each_with_index do |key, i|
- pipeline.set(redis_shared_state_key(key), etags[i], ex: EXPIRY_TIME, nx: only_if_missing)
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ Gitlab::Redis::SharedState.with do |redis|
+ redis.pipelined do |pipeline|
+ keys.each_with_index do |key, i|
+ pipeline.set(redis_shared_state_key(key), etags[i], ex: EXPIRY_TIME, nx: only_if_missing)
+ end
end
end
end
diff --git a/lib/gitlab/experimentation/group_types.rb b/lib/gitlab/experimentation/group_types.rb
deleted file mode 100644
index 8e8f7284b99..00000000000
--- a/lib/gitlab/experimentation/group_types.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Experimentation
- module GroupTypes
- GROUP_CONTROL = :control
- GROUP_EXPERIMENTAL = :experimental
- end
- end
-end
diff --git a/lib/gitlab/external_authorization/cache.rb b/lib/gitlab/external_authorization/cache.rb
index c06711d16f8..2ba1a363421 100644
--- a/lib/gitlab/external_authorization/cache.rb
+++ b/lib/gitlab/external_authorization/cache.rb
@@ -11,7 +11,7 @@ module Gitlab
end
def load
- @access, @reason, @refreshed_at = ::Gitlab::Redis::Cache.with do |redis|
+ @access, @reason, @refreshed_at = with_redis do |redis|
redis.hmget(cache_key, :access, :reason, :refreshed_at)
end
@@ -19,7 +19,7 @@ module Gitlab
end
def store(new_access, new_reason, new_refreshed_at)
- ::Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.pipelined do |pipeline|
pipeline.mapped_hmset(
cache_key,
@@ -58,6 +58,10 @@ module Gitlab
def cache_key
"external_authorization:user-#{@user.id}:label-#{@label}"
end
+
+ def with_redis(&block)
+ ::Gitlab::Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord
+ end
end
end
end
diff --git a/lib/gitlab/feature_categories.rb b/lib/gitlab/feature_categories.rb
index d06f3b14fed..17586a94d7e 100644
--- a/lib/gitlab/feature_categories.rb
+++ b/lib/gitlab/feature_categories.rb
@@ -31,6 +31,14 @@ module Gitlab
category
end
+ def get!(feature_category)
+ return feature_category if valid?(feature_category)
+
+ raise "Unknown feature category: #{feature_category}" if Gitlab.dev_or_test_env?
+
+ FEATURE_CATEGORY_DEFAULT
+ end
+
def valid?(category)
categories.include?(category.to_s)
end
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 9bbe17dcad1..b8f4ff0e9c4 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -45,7 +45,7 @@ module Gitlab
# Relative path of repo
attr_reader :relative_path
- attr_reader :storage, :gl_repository, :gl_project_path
+ attr_reader :storage, :gl_repository, :gl_project_path, :container
# This remote name has to be stable for all types of repositories that
# can join an object pool. If it's structure ever changes, a migration
@@ -56,11 +56,12 @@ module Gitlab
# This initializer method is only used on the client side (gitlab-ce).
# Gitaly-ruby uses a different initializer.
- def initialize(storage, relative_path, gl_repository, gl_project_path)
+ def initialize(storage, relative_path, gl_repository, gl_project_path, container: nil)
@storage = storage
@relative_path = relative_path
@gl_repository = gl_repository
@gl_project_path = gl_project_path
+ @container = container
@name = @relative_path.split("/").last
end
@@ -69,6 +70,11 @@ module Gitlab
"<#{self.class.name}: #{self.gl_project_path}>"
end
+ # Support Feature Flag Repository actor
+ def flipper_id
+ "Repository:#{@relative_path}"
+ end
+
def ==(other)
other.is_a?(self.class) && [storage, relative_path] == [other.storage, other.relative_path]
end
@@ -534,9 +540,9 @@ module Gitlab
# Returns matching refs for OID
#
# Limit of 0 means there is no limit.
- def refs_by_oid(oid:, limit: 0)
+ def refs_by_oid(oid:, limit: 0, ref_patterns: nil)
wrapped_gitaly_errors do
- gitaly_ref_client.find_refs_by_oid(oid: oid, limit: limit)
+ gitaly_ref_client.find_refs_by_oid(oid: oid, limit: limit, ref_patterns: ref_patterns)
end
rescue CommandError, TypeError, NoRepository
nil
@@ -1054,19 +1060,19 @@ module Gitlab
end
end
- def search_files_by_name(query, ref)
+ def search_files_by_name(query, ref, limit: 0, offset: 0)
safe_query = query.sub(%r{^/*}, "")
ref ||= root_ref
return [] if empty? || safe_query.blank?
- gitaly_repository_client.search_files_by_name(ref, safe_query).map do |file|
+ gitaly_repository_client.search_files_by_name(ref, safe_query, limit: limit, offset: offset).map do |file|
Gitlab::EncodingHelper.encode_utf8(file)
end
end
- def search_files_by_regexp(filter, ref = 'HEAD')
- gitaly_repository_client.search_files_by_regexp(ref, filter).map do |file|
+ def search_files_by_regexp(filter, ref = 'HEAD', limit: 0, offset: 0)
+ gitaly_repository_client.search_files_by_regexp(ref, filter, limit: limit, offset: offset).map do |file|
Gitlab::EncodingHelper.encode_utf8(file)
end
end
diff --git a/lib/gitlab/git_ref_validator.rb b/lib/gitlab/git_ref_validator.rb
index 1330b06bf9c..f4d4cebc096 100644
--- a/lib/gitlab/git_ref_validator.rb
+++ b/lib/gitlab/git_ref_validator.rb
@@ -13,6 +13,7 @@ module Gitlab
#
# Returns true for a valid reference name, false otherwise
def validate(ref_name)
+ return false if ref_name.to_s.empty? # #blank? raises an ArgumentError for invalid encodings
return false if ref_name.start_with?(*(EXPANDED_PREFIXES + DISALLOWED_PREFIXES))
return false if ref_name == 'HEAD'
@@ -24,6 +25,7 @@ module Gitlab
end
def validate_merge_request_branch(ref_name)
+ return false if ref_name.to_s.empty?
return false if ref_name.start_with?(*DISALLOWED_PREFIXES)
expanded_name = if ref_name.start_with?(*EXPANDED_PREFIXES)
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index 996534f4194..735c7fcf80c 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -204,8 +204,9 @@ module Gitlab
metadata['x-gitlab-correlation-id'] = Labkit::Correlation::CorrelationId.current_id if Labkit::Correlation::CorrelationId.current_id
metadata['gitaly-session-id'] = session_id
metadata['username'] = context_data['meta.user'] if context_data&.fetch('meta.user', nil)
+ metadata['user_id'] = context_data['meta.user_id'].to_s if context_data&.fetch('meta.user_id', nil)
metadata['remote_ip'] = context_data['meta.remote_ip'] if context_data&.fetch('meta.remote_ip', nil)
- metadata.merge!(Feature::Gitaly.server_feature_flags)
+ metadata.merge!(Feature::Gitaly.server_feature_flags(**feature_flag_actors))
metadata.merge!(route_to_primary)
deadline_info = request_deadline(timeout)
@@ -293,7 +294,7 @@ module Gitlab
# check if the limit is being exceeded while testing in those environments
# In that case we can use a feature flag to indicate that we do want to
# enforce request limits.
- return true if Feature::Gitaly.enabled?('enforce_requests_limits')
+ return true if Feature::Gitaly.enabled_for_any?(:gitaly_enforce_requests_limits)
!Rails.env.production?
end
@@ -502,5 +503,24 @@ module Gitlab
end
private_class_method :max_stacks
+
+ def self.with_feature_flag_actors(repository: nil, user: nil, project: nil, group: nil, &block)
+ feature_flag_actors[:repository] = repository
+ feature_flag_actors[:user] = user
+ feature_flag_actors[:project] = project
+ feature_flag_actors[:group] = group
+
+ yield
+ ensure
+ feature_flag_actors.clear
+ end
+
+ def self.feature_flag_actors
+ if Gitlab::SafeRequestStore.active?
+ Gitlab::SafeRequestStore[:gitaly_feature_flag_actors] ||= {}
+ else
+ Thread.current[:gitaly_feature_flag_actors] ||= {}
+ end
+ end
end
end
diff --git a/lib/gitlab/gitaly_client/blob_service.rb b/lib/gitlab/gitaly_client/blob_service.rb
index 3b08a833aeb..6d87c3329d7 100644
--- a/lib/gitlab/gitaly_client/blob_service.rb
+++ b/lib/gitlab/gitaly_client/blob_service.rb
@@ -4,9 +4,12 @@ module Gitlab
module GitalyClient
class BlobService
include Gitlab::EncodingHelper
+ include WithFeatureFlagActors
def initialize(repository)
@gitaly_repo = repository.gitaly_repository
+
+ self.repository_actor = repository
end
def get_blob(oid:, limit:)
@@ -15,7 +18,7 @@ module Gitlab
oid: oid,
limit: limit
)
- response = GitalyClient.call(@gitaly_repo.storage_name, :blob_service, :get_blob, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@gitaly_repo.storage_name, :blob_service, :get_blob, request, timeout: GitalyClient.fast_timeout)
consume_blob_response(response)
end
@@ -35,7 +38,7 @@ module Gitlab
GitalyClient.medium_timeout
end
- response = GitalyClient.call(@gitaly_repo.storage_name, :blob_service, :list_blobs, request, timeout: timeout)
+ response = gitaly_client_call(@gitaly_repo.storage_name, :blob_service, :list_blobs, request, timeout: timeout)
GitalyClient::BlobsStitcher.new(GitalyClient::ListBlobsAdapter.new(response))
end
@@ -47,7 +50,7 @@ module Gitlab
blob_ids: blob_ids
)
- response = GitalyClient.call(@gitaly_repo.storage_name, :blob_service, :get_lfs_pointers, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@gitaly_repo.storage_name, :blob_service, :get_lfs_pointers, request, timeout: GitalyClient.medium_timeout)
map_lfs_pointers(response)
end
@@ -64,7 +67,7 @@ module Gitlab
limit: limit
)
- response = GitalyClient.call(
+ response = gitaly_client_call(
@gitaly_repo.storage_name,
:blob_service,
:get_blobs,
@@ -87,7 +90,7 @@ module Gitlab
limit: limit
)
- response = GitalyClient.call(
+ response = gitaly_client_call(
@gitaly_repo.storage_name,
:blob_service,
:get_blobs,
@@ -107,7 +110,7 @@ module Gitlab
GitalyClient.medium_timeout
end
- response = GitalyClient.call(
+ response = gitaly_client_call(
@gitaly_repo.storage_name,
:blob_service,
rpc,
@@ -123,7 +126,7 @@ module Gitlab
revisions: [encode_binary("--all")]
)
- response = GitalyClient.call(@gitaly_repo.storage_name, :blob_service, :list_lfs_pointers, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@gitaly_repo.storage_name, :blob_service, :list_lfs_pointers, request, timeout: GitalyClient.medium_timeout)
map_lfs_pointers(response)
end
diff --git a/lib/gitlab/gitaly_client/cleanup_service.rb b/lib/gitlab/gitaly_client/cleanup_service.rb
index 649aaa46362..3c2c41a244e 100644
--- a/lib/gitlab/gitaly_client/cleanup_service.rb
+++ b/lib/gitlab/gitaly_client/cleanup_service.rb
@@ -3,6 +3,8 @@
module Gitlab
module GitalyClient
class CleanupService
+ include WithFeatureFlagActors
+
attr_reader :repository, :gitaly_repo, :storage
# 'repository' is a Gitlab::Git::Repository
@@ -10,10 +12,12 @@ module Gitlab
@repository = repository
@gitaly_repo = repository.gitaly_repository
@storage = repository.storage
+
+ self.repository_actor = repository
end
def apply_bfg_object_map_stream(io, &blk)
- response = GitalyClient.call(
+ response = gitaly_client_call(
storage,
:cleanup_service,
:apply_bfg_object_map_stream,
diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb
index 312d1dddff1..6bcf4802fbe 100644
--- a/lib/gitlab/gitaly_client/commit_service.rb
+++ b/lib/gitlab/gitaly_client/commit_service.rb
@@ -4,12 +4,15 @@ module Gitlab
module GitalyClient
class CommitService
include Gitlab::EncodingHelper
+ include WithFeatureFlagActors
TREE_ENTRIES_DEFAULT_LIMIT = 100_000
def initialize(repository)
@gitaly_repo = repository.gitaly_repository
@repository = repository
+
+ self.repository_actor = repository
end
def ls_files(revision)
@@ -18,7 +21,7 @@ module Gitlab
revision: encode_binary(revision)
)
- response = GitalyClient.call(@repository.storage, :commit_service, :list_files, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :list_files, request, timeout: GitalyClient.medium_timeout)
response.flat_map do |msg|
msg.paths.map { |d| EncodingHelper.encode!(d.dup) }
end
@@ -31,7 +34,7 @@ module Gitlab
child_id: child_id
)
- GitalyClient.call(@repository.storage, :commit_service, :commit_is_ancestor, request, timeout: GitalyClient.fast_timeout).value
+ gitaly_client_call(@repository.storage, :commit_service, :commit_is_ancestor, request, timeout: GitalyClient.fast_timeout).value
end
def diff(from, to, options = {})
@@ -74,7 +77,7 @@ module Gitlab
def commit_deltas(commit)
request = Gitaly::CommitDeltaRequest.new(diff_from_parent_request_params(commit))
- response = GitalyClient.call(@repository.storage, :diff_service, :commit_delta, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@repository.storage, :diff_service, :commit_delta, request, timeout: GitalyClient.fast_timeout)
response.flat_map { |msg| msg.deltas }
end
@@ -93,7 +96,7 @@ module Gitlab
limit: limit.to_i
)
- response = GitalyClient.call(@repository.storage, :commit_service, :tree_entry, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :tree_entry, request, timeout: GitalyClient.medium_timeout)
entry = nil
data = []
@@ -127,7 +130,7 @@ module Gitlab
)
request.sort = Gitaly::GetTreeEntriesRequest::SortBy::TREES_FIRST if pagination_params
- response = GitalyClient.call(@repository.storage, :commit_service, :get_tree_entries, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :get_tree_entries, request, timeout: GitalyClient.medium_timeout)
cursor = nil
@@ -163,7 +166,7 @@ module Gitlab
request.path = encode_binary(options[:path]) if options[:path].present?
request.max_count = options[:max_count] if options[:max_count].present?
- GitalyClient.call(@repository.storage, :commit_service, :count_commits, request, timeout: GitalyClient.medium_timeout).count
+ gitaly_client_call(@repository.storage, :commit_service, :count_commits, request, timeout: GitalyClient.medium_timeout).count
end
def diverging_commit_count(from, to, max_count:)
@@ -173,7 +176,7 @@ module Gitlab
to: encode_binary(to),
max_count: max_count
)
- response = GitalyClient.call(@repository.storage, :commit_service, :count_diverging_commits, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :count_diverging_commits, request, timeout: GitalyClient.medium_timeout)
[response.left_count, response.right_count]
end
@@ -187,7 +190,7 @@ module Gitlab
global_options: parse_global_options!(literal_pathspec: literal_pathspec)
)
- response = GitalyClient.call(@repository.storage, :commit_service, :list_last_commits_for_tree, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :list_last_commits_for_tree, request, timeout: GitalyClient.medium_timeout)
response.each_with_object({}) do |gitaly_response, hsh|
gitaly_response.commits.each do |commit_for_tree|
@@ -204,7 +207,7 @@ module Gitlab
global_options: parse_global_options!(literal_pathspec: literal_pathspec)
)
- gitaly_commit = GitalyClient.call(@repository.storage, :commit_service, :last_commit_for_path, request, timeout: GitalyClient.fast_timeout).commit
+ gitaly_commit = gitaly_client_call(@repository.storage, :commit_service, :last_commit_for_path, request, timeout: GitalyClient.fast_timeout).commit
return unless gitaly_commit
Gitlab::Git::Commit.new(@repository, gitaly_commit)
@@ -217,7 +220,7 @@ module Gitlab
right_commit_id: right_commit_sha
)
- response = GitalyClient.call(@repository.storage, :diff_service, :diff_stats, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :diff_service, :diff_stats, request, timeout: GitalyClient.medium_timeout)
response.flat_map { |rsp| rsp.stats.to_a }
end
@@ -227,7 +230,7 @@ module Gitlab
commits: commits
)
- response = GitalyClient.call(@repository.storage, :diff_service, :find_changed_paths, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :diff_service, :find_changed_paths, request, timeout: GitalyClient.medium_timeout)
response.flat_map do |msg|
msg.paths.map do |path|
Gitlab::Git::ChangedPath.new(
@@ -247,7 +250,7 @@ module Gitlab
)
request.order = opts[:order].upcase if opts[:order].present?
- response = GitalyClient.call(@repository.storage, :commit_service, :find_all_commits, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :find_all_commits, request, timeout: GitalyClient.medium_timeout)
consume_commits_response(response)
end
@@ -268,7 +271,7 @@ module Gitlab
request.before = GitalyClient.timestamp(params[:before]) if params[:before]
request.after = GitalyClient.timestamp(params[:after]) if params[:after]
- response = GitalyClient.call(@repository.storage, :commit_service, :list_commits, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :list_commits, request, timeout: GitalyClient.medium_timeout)
consume_commits_response(response)
end
@@ -290,7 +293,7 @@ module Gitlab
repository: quarantined_repo
)
- response = GitalyClient.call(@repository.storage, :commit_service, :list_all_commits, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :list_all_commits, request, timeout: GitalyClient.medium_timeout)
quarantined_commits = consume_commits_response(response)
quarantined_commit_ids = quarantined_commits.map(&:id)
@@ -328,7 +331,7 @@ module Gitlab
request = Gitaly::ListCommitsByOidRequest.new(repository: @gitaly_repo, oid: oids)
- response = GitalyClient.call(@repository.storage, :commit_service, :list_commits_by_oid, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :list_commits_by_oid, request, timeout: GitalyClient.medium_timeout)
consume_commits_response(response)
rescue GRPC::NotFound # If no repository is found, happens mainly during testing
[]
@@ -345,13 +348,13 @@ module Gitlab
global_options: parse_global_options!(literal_pathspec: literal_pathspec)
)
- response = GitalyClient.call(@repository.storage, :commit_service, :commits_by_message, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :commits_by_message, request, timeout: GitalyClient.medium_timeout)
consume_commits_response(response)
end
def languages(ref = nil)
request = Gitaly::CommitLanguagesRequest.new(repository: @gitaly_repo, revision: ref || '')
- response = GitalyClient.call(@repository.storage, :commit_service, :commit_languages, request, timeout: GitalyClient.long_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :commit_languages, request, timeout: GitalyClient.long_timeout)
response.languages.map { |l| { value: l.share.round(2), label: l.name, color: l.color, highlight: l.color } }
end
@@ -364,7 +367,7 @@ module Gitlab
range: (encode_binary(range) if range)
)
- response = GitalyClient.call(@repository.storage, :commit_service, :raw_blame, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :raw_blame, request, timeout: GitalyClient.medium_timeout)
response.reduce([]) { |memo, msg| memo << msg.data }.join
end
@@ -400,7 +403,7 @@ module Gitlab
repository: @gitaly_repo,
revision: encode_binary(revision)
)
- GitalyClient.call(@repository.storage, :commit_service, :commit_stats, request, timeout: GitalyClient.medium_timeout)
+ gitaly_client_call(@repository.storage, :commit_service, :commit_stats, request, timeout: GitalyClient.medium_timeout)
end
def find_commits(options)
@@ -424,7 +427,7 @@ module Gitlab
request.paths = encode_repeated(Array(options[:path])) if options[:path].present?
- response = GitalyClient.call(@repository.storage, :commit_service, :find_commits, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :find_commits, request, timeout: GitalyClient.medium_timeout)
consume_commits_response(response)
end
@@ -443,7 +446,7 @@ module Gitlab
end
end
- response = GitalyClient.call(
+ response = gitaly_client_call(
@repository.storage, :commit_service, :check_objects_exist, enum, timeout: GitalyClient.medium_timeout
)
@@ -470,7 +473,7 @@ module Gitlab
end
end
- response = GitalyClient.call(@repository.storage, :commit_service, :filter_shas_with_signatures, enum, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :filter_shas_with_signatures, enum, timeout: GitalyClient.fast_timeout)
response.flat_map do |msg|
msg.shas.map { |sha| EncodingHelper.encode!(sha) }
end
@@ -478,7 +481,7 @@ module Gitlab
def get_commit_signatures(commit_ids)
request = Gitaly::GetCommitSignaturesRequest.new(repository: @gitaly_repo, commit_ids: commit_ids)
- response = GitalyClient.call(@repository.storage, :commit_service, :get_commit_signatures, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :get_commit_signatures, request, timeout: GitalyClient.fast_timeout)
signatures = Hash.new { |h, k| h[k] = [+''.b, +''.b] }
current_commit_id = nil
@@ -497,7 +500,7 @@ module Gitlab
def get_commit_messages(commit_ids)
request = Gitaly::GetCommitMessagesRequest.new(repository: @gitaly_repo, commit_ids: commit_ids)
- response = GitalyClient.call(@repository.storage, :commit_service, :get_commit_messages, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :get_commit_messages, request, timeout: GitalyClient.fast_timeout)
messages = Hash.new { |h, k| h[k] = +''.b }
current_commit_id = nil
@@ -515,7 +518,7 @@ module Gitlab
request = Gitaly::ListCommitsByRefNameRequest
.new(repository: @gitaly_repo, ref_names: refs.map { |ref| encode_binary(ref) })
- response = GitalyClient.call(@repository.storage, :commit_service, :list_commits_by_ref_name, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :list_commits_by_ref_name, request, timeout: GitalyClient.medium_timeout)
commit_refs = response.flat_map do |message|
message.commit_refs.map do |commit_ref|
@@ -540,7 +543,7 @@ module Gitlab
request_params.merge!(Gitlab::Git::DiffCollection.limits(options))
request = Gitaly::CommitDiffRequest.new(request_params)
- response = GitalyClient.call(@repository.storage, :diff_service, :commit_diff, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :diff_service, :commit_diff, request, timeout: GitalyClient.medium_timeout)
GitalyClient::DiffStitcher.new(response)
end
@@ -577,7 +580,7 @@ module Gitlab
revision: encode_binary(revision)
)
- response = GitalyClient.call(@repository.storage, :commit_service, :find_commit, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :commit_service, :find_commit, request, timeout: GitalyClient.medium_timeout)
response.commit
end
diff --git a/lib/gitlab/gitaly_client/conflicts_service.rb b/lib/gitlab/gitaly_client/conflicts_service.rb
index 982454b117e..38f648ccc31 100644
--- a/lib/gitlab/gitaly_client/conflicts_service.rb
+++ b/lib/gitlab/gitaly_client/conflicts_service.rb
@@ -4,6 +4,7 @@ module Gitlab
module GitalyClient
class ConflictsService
include Gitlab::EncodingHelper
+ include WithFeatureFlagActors
MAX_MSG_SIZE = 128.kilobytes.freeze
@@ -12,6 +13,8 @@ module Gitlab
@repository = repository
@our_commit_oid = our_commit_oid
@their_commit_oid = their_commit_oid
+
+ self.repository_actor = repository
end
def list_conflict_files(allow_tree_conflicts: false)
@@ -21,7 +24,7 @@ module Gitlab
their_commit_oid: @their_commit_oid,
allow_tree_conflicts: allow_tree_conflicts
)
- response = GitalyClient.call(@repository.storage, :conflicts_service, :list_conflict_files, request, timeout: GitalyClient.long_timeout)
+ response = gitaly_client_call(@repository.storage, :conflicts_service, :list_conflict_files, request, timeout: GitalyClient.long_timeout)
GitalyClient::ConflictFilesStitcher.new(response, @gitaly_repo)
end
@@ -50,7 +53,7 @@ module Gitlab
end
end
- response = GitalyClient.call(@repository.storage, :conflicts_service, :resolve_conflicts, req_enum, remote_storage: target_repository.storage, timeout: GitalyClient.long_timeout)
+ response = gitaly_client_call(@repository.storage, :conflicts_service, :resolve_conflicts, req_enum, remote_storage: target_repository.storage, timeout: GitalyClient.long_timeout)
if response.resolution_error.present?
raise Gitlab::Git::Conflict::Resolver::ResolutionError, response.resolution_error
diff --git a/lib/gitlab/gitaly_client/object_pool_service.rb b/lib/gitlab/gitaly_client/object_pool_service.rb
index 786ef0ebebe..e07bf3fbccc 100644
--- a/lib/gitlab/gitaly_client/object_pool_service.rb
+++ b/lib/gitlab/gitaly_client/object_pool_service.rb
@@ -3,6 +3,8 @@
module Gitlab
module GitalyClient
class ObjectPoolService
+ include WithFeatureFlagActors
+
attr_reader :object_pool, :storage
def initialize(object_pool)
@@ -15,8 +17,10 @@ module Gitlab
object_pool: object_pool,
origin: repository.gitaly_repository)
- GitalyClient.call(storage, :object_pool_service, :create_object_pool,
- request, timeout: GitalyClient.medium_timeout)
+ GitalyClient.with_feature_flag_actors(**gitaly_feature_flag_actors(repository)) do
+ GitalyClient.call(storage, :object_pool_service, :create_object_pool,
+ request, timeout: GitalyClient.medium_timeout)
+ end
end
def delete
@@ -32,8 +36,10 @@ module Gitlab
repository: repository.gitaly_repository
)
- GitalyClient.call(storage, :object_pool_service, :link_repository_to_object_pool,
- request, timeout: GitalyClient.fast_timeout)
+ GitalyClient.with_feature_flag_actors(**gitaly_feature_flag_actors(repository)) do
+ GitalyClient.call(storage, :object_pool_service, :link_repository_to_object_pool,
+ request, timeout: GitalyClient.fast_timeout)
+ end
end
def fetch(repository)
@@ -42,8 +48,10 @@ module Gitlab
origin: repository.gitaly_repository
)
- GitalyClient.call(storage, :object_pool_service, :fetch_into_object_pool,
- request, timeout: GitalyClient.long_timeout)
+ GitalyClient.with_feature_flag_actors(**gitaly_feature_flag_actors(repository)) do
+ GitalyClient.call(storage, :object_pool_service, :fetch_into_object_pool,
+ request, timeout: GitalyClient.long_timeout)
+ end
end
end
end
diff --git a/lib/gitlab/gitaly_client/operation_service.rb b/lib/gitlab/gitaly_client/operation_service.rb
index 7835fb32f59..2312def5efc 100644
--- a/lib/gitlab/gitaly_client/operation_service.rb
+++ b/lib/gitlab/gitaly_client/operation_service.rb
@@ -4,12 +4,15 @@ module Gitlab
module GitalyClient
class OperationService
include Gitlab::EncodingHelper
+ include WithFeatureFlagActors
MAX_MSG_SIZE = 128.kilobytes.freeze
def initialize(repository)
@gitaly_repo = repository.gitaly_repository
@repository = repository
+
+ self.repository_actor = repository
end
def rm_tag(tag_name, user)
@@ -19,7 +22,7 @@ module Gitlab
user: Gitlab::Git::User.from_gitlab(user).to_gitaly
)
- response = GitalyClient.call(@repository.storage, :operation_service, :user_delete_tag, request, timeout: GitalyClient.long_timeout)
+ response = gitaly_client_call(@repository.storage, :operation_service, :user_delete_tag, request, timeout: GitalyClient.long_timeout)
if pre_receive_error = response.pre_receive_error.presence
raise Gitlab::Git::PreReceiveError, pre_receive_error
@@ -36,7 +39,7 @@ module Gitlab
timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
- response = GitalyClient.call(@repository.storage, :operation_service, :user_create_tag, request, timeout: GitalyClient.long_timeout)
+ response = gitaly_client_call(@repository.storage, :operation_service, :user_create_tag, request, timeout: GitalyClient.long_timeout)
if pre_receive_error = response.pre_receive_error.presence
raise Gitlab::Git::PreReceiveError, pre_receive_error
elsif response.exists
@@ -73,7 +76,7 @@ module Gitlab
user: Gitlab::Git::User.from_gitlab(user).to_gitaly,
start_point: encode_binary(start_point)
)
- response = GitalyClient.call(@repository.storage, :operation_service,
+ response = gitaly_client_call(@repository.storage, :operation_service,
:user_create_branch, request, timeout: GitalyClient.long_timeout)
if response.pre_receive_error.present?
@@ -110,7 +113,7 @@ module Gitlab
oldrev: encode_binary(oldrev)
)
- response = GitalyClient.call(@repository.storage, :operation_service,
+ response = gitaly_client_call(@repository.storage, :operation_service,
:user_update_branch, request, timeout: GitalyClient.long_timeout)
if pre_receive_error = response.pre_receive_error.presence
@@ -125,7 +128,7 @@ module Gitlab
user: Gitlab::Git::User.from_gitlab(user).to_gitaly
)
- response = GitalyClient.call(@repository.storage, :operation_service,
+ response = gitaly_client_call(@repository.storage, :operation_service,
:user_delete_branch, request, timeout: GitalyClient.long_timeout)
if pre_receive_error = response.pre_receive_error.presence
@@ -156,7 +159,7 @@ module Gitlab
timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
- response = GitalyClient.call(@repository.storage, :operation_service,
+ response = gitaly_client_call(@repository.storage, :operation_service,
:user_merge_to_ref, request, timeout: GitalyClient.long_timeout)
response.commit_id
@@ -164,7 +167,7 @@ module Gitlab
def user_merge_branch(user, source_sha, target_branch, message)
request_enum = QueueEnumerator.new
- response_enum = GitalyClient.call(
+ response_enum = gitaly_client_call(
@repository.storage,
:operation_service,
:user_merge_branch,
@@ -225,7 +228,7 @@ module Gitlab
branch: encode_binary(target_branch)
)
- response = GitalyClient.call(
+ response = gitaly_client_call(
@repository.storage,
:operation_service,
:user_ff_branch,
@@ -268,7 +271,7 @@ module Gitlab
request_enum = QueueEnumerator.new
rebase_sha = nil
- response_enum = GitalyClient.call(
+ response_enum = gitaly_client_call(
@repository.storage,
:operation_service,
:user_rebase_confirmable,
@@ -334,7 +337,7 @@ module Gitlab
timestamp: Google::Protobuf::Timestamp.new(seconds: time.to_i)
)
- response = GitalyClient.call(
+ response = gitaly_client_call(
@repository.storage,
:operation_service,
:user_squash,
@@ -376,7 +379,7 @@ module Gitlab
timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.utc.to_i)
)
- response = GitalyClient.call(
+ response = gitaly_client_call(
@repository.storage,
:operation_service,
:user_update_submodule,
@@ -422,7 +425,7 @@ module Gitlab
end
end
- response = GitalyClient.call(
+ response = gitaly_client_call(
@repository.storage, :operation_service, :user_commit_files, req_enum,
timeout: GitalyClient.long_timeout, remote_storage: start_repository&.storage)
@@ -435,9 +438,25 @@ module Gitlab
end
Gitlab::Git::OperationService::BranchUpdate.from_gitaly(response.branch_update)
+ rescue GRPC::BadStatus => e
+ detailed_error = GitalyClient.decode_detailed_error(e)
+
+ case detailed_error&.error
+ when :access_check
+ access_check_error = detailed_error.access_check
+ # These messages were returned from internal/allowed API calls
+ raise Gitlab::Git::PreReceiveError.new(fallback_message: access_check_error.error_message)
+ when :custom_hook
+ raise Gitlab::Git::PreReceiveError.new(custom_hook_error_message(detailed_error.custom_hook),
+ fallback_message: e.details)
+ when :index_update
+ raise Gitlab::Git::Index::IndexError, index_error_message(detailed_error.index_update)
+ else
+ raise e
+ end
end
- # rubocop:enable Metrics/ParameterLists
+ # rubocop:enable Metrics/ParameterLists
def user_commit_patches(user, branch_name, patches)
header = Gitaly::UserApplyPatchRequest::Header.new(
repository: @gitaly_repo,
@@ -457,7 +476,7 @@ module Gitlab
end
end
- response = GitalyClient.call(@repository.storage, :operation_service,
+ response = gitaly_client_call(@repository.storage, :operation_service,
:user_apply_patch, chunks, timeout: GitalyClient.long_timeout)
Gitlab::Git::OperationService::BranchUpdate.from_gitaly(response.branch_update)
@@ -493,7 +512,7 @@ module Gitlab
dry_run: dry_run
)
- response = GitalyClient.call(
+ response = gitaly_client_call(
@repository.storage,
:operation_service,
:"user_#{rpc}",
@@ -575,6 +594,27 @@ module Gitlab
custom_hook_output = custom_hook_error.stderr.presence || custom_hook_error.stdout
EncodingHelper.encode!(custom_hook_output)
end
+
+ def index_error_message(index_error)
+ encoded_path = EncodingHelper.encode!(index_error.path)
+
+ case index_error.error_type
+ when :ERROR_TYPE_EMPTY_PATH
+ "Received empty path"
+ when :ERROR_TYPE_INVALID_PATH
+ "Invalid path: #{encoded_path}"
+ when :ERROR_TYPE_DIRECTORY_EXISTS
+ "Directory already exists: #{encoded_path}"
+ when :ERROR_TYPE_DIRECTORY_TRAVERSAL
+ "Directory traversal in path escapes repository: #{encoded_path}"
+ when :ERROR_TYPE_FILE_EXISTS
+ "File already exists: #{encoded_path}"
+ when :ERROR_TYPE_FILE_NOT_FOUND
+ "File not found: #{encoded_path}"
+ else
+ "Unknown error performing git operation"
+ end
+ end
end
end
end
diff --git a/lib/gitlab/gitaly_client/praefect_info_service.rb b/lib/gitlab/gitaly_client/praefect_info_service.rb
index 127f8cfbdf6..b565898acf8 100644
--- a/lib/gitlab/gitaly_client/praefect_info_service.rb
+++ b/lib/gitlab/gitaly_client/praefect_info_service.rb
@@ -3,16 +3,20 @@
module Gitlab
module GitalyClient
class PraefectInfoService
+ include WithFeatureFlagActors
+
def initialize(repository)
@repository = repository
@gitaly_repo = repository.gitaly_repository
@storage = repository.storage
+
+ self.repository_actor = repository
end
def replicas
request = Gitaly::RepositoryReplicasRequest.new(repository: @gitaly_repo)
- GitalyClient.call(@storage, :praefect_info_service, :repository_replicas, request, timeout: GitalyClient.fast_timeout)
+ gitaly_client_call(@storage, :praefect_info_service, :repository_replicas, request, timeout: GitalyClient.fast_timeout)
end
end
end
diff --git a/lib/gitlab/gitaly_client/ref_service.rb b/lib/gitlab/gitaly_client/ref_service.rb
index d2b702f3a6d..de76ade76cb 100644
--- a/lib/gitlab/gitaly_client/ref_service.rb
+++ b/lib/gitlab/gitaly_client/ref_service.rb
@@ -4,6 +4,7 @@ module Gitlab
module GitalyClient
class RefService
include Gitlab::EncodingHelper
+ include WithFeatureFlagActors
TAGS_SORT_KEY = {
'name' => Gitaly::FindAllTagsRequest::SortBy::Key::REFNAME,
@@ -21,17 +22,19 @@ module Gitlab
@repository = repository
@gitaly_repo = repository.gitaly_repository
@storage = repository.storage
+
+ self.repository_actor = repository
end
def branches
request = Gitaly::FindAllBranchesRequest.new(repository: @gitaly_repo)
- response = GitalyClient.call(@storage, :ref_service, :find_all_branches, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@storage, :ref_service, :find_all_branches, request, timeout: GitalyClient.fast_timeout)
consume_find_all_branches_response(response)
end
def remote_branches(remote_name)
request = Gitaly::FindAllRemoteBranchesRequest.new(repository: @gitaly_repo, remote_name: remote_name)
- response = GitalyClient.call(@storage, :ref_service, :find_all_remote_branches, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@storage, :ref_service, :find_all_remote_branches, request, timeout: GitalyClient.medium_timeout)
consume_find_all_remote_branches_response(remote_name, response)
end
@@ -41,25 +44,25 @@ module Gitlab
merged_only: true,
merged_branches: branch_names.map { |s| encode_binary(s) }
)
- response = GitalyClient.call(@storage, :ref_service, :find_all_branches, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@storage, :ref_service, :find_all_branches, request, timeout: GitalyClient.fast_timeout)
consume_find_all_branches_response(response)
end
def default_branch_name
request = Gitaly::FindDefaultBranchNameRequest.new(repository: @gitaly_repo)
- response = GitalyClient.call(@storage, :ref_service, :find_default_branch_name, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@storage, :ref_service, :find_default_branch_name, request, timeout: GitalyClient.fast_timeout)
Gitlab::Git.branch_name(response.name)
end
def branch_names
request = Gitaly::FindAllBranchNamesRequest.new(repository: @gitaly_repo)
- response = GitalyClient.call(@storage, :ref_service, :find_all_branch_names, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@storage, :ref_service, :find_all_branch_names, request, timeout: GitalyClient.fast_timeout)
consume_refs_response(response) { |name| Gitlab::Git.branch_name(name) }
end
def tag_names
request = Gitaly::FindAllTagNamesRequest.new(repository: @gitaly_repo)
- response = GitalyClient.call(@storage, :ref_service, :find_all_tag_names, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@storage, :ref_service, :find_all_tag_names, request, timeout: GitalyClient.fast_timeout)
consume_refs_response(response) { |name| Gitlab::Git.tag_name(name) }
end
@@ -74,7 +77,7 @@ module Gitlab
def local_branches(sort_by: nil, pagination_params: nil)
request = Gitaly::FindLocalBranchesRequest.new(repository: @gitaly_repo, pagination_params: pagination_params)
request.sort_by = sort_local_branches_by_param(sort_by) if sort_by
- response = GitalyClient.call(@storage, :ref_service, :find_local_branches, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@storage, :ref_service, :find_local_branches, request, timeout: GitalyClient.fast_timeout)
consume_find_local_branches_response(response)
end
@@ -82,13 +85,13 @@ module Gitlab
request = Gitaly::FindAllTagsRequest.new(repository: @gitaly_repo, pagination_params: pagination_params)
request.sort_by = sort_tags_by_param(sort_by) if sort_by
- response = GitalyClient.call(@storage, :ref_service, :find_all_tags, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@storage, :ref_service, :find_all_tags, request, timeout: GitalyClient.medium_timeout)
consume_tags_response(response)
end
def ref_exists?(ref_name)
request = Gitaly::RefExistsRequest.new(repository: @gitaly_repo, ref: encode_binary(ref_name))
- response = GitalyClient.call(@storage, :ref_service, :ref_exists, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@storage, :ref_service, :ref_exists, request, timeout: GitalyClient.fast_timeout)
response.value
rescue GRPC::InvalidArgument => e
raise ArgumentError, e.message
@@ -100,7 +103,7 @@ module Gitlab
name: encode_binary(branch_name)
)
- response = GitalyClient.call(@repository.storage, :ref_service, :find_branch, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :ref_service, :find_branch, request, timeout: GitalyClient.medium_timeout)
branch = response.branch
return unless branch
@@ -116,7 +119,7 @@ module Gitlab
tag_name: encode_binary(tag_name)
)
- response = GitalyClient.call(@repository.storage, :ref_service, :find_tag, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :ref_service, :find_tag, request, timeout: GitalyClient.medium_timeout)
tag = response.tag
return unless tag
@@ -140,7 +143,7 @@ module Gitlab
except_with_prefix: except_with_prefixes.map { |r| encode_binary(r) }
)
- response = GitalyClient.call(@repository.storage, :ref_service, :delete_refs, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@repository.storage, :ref_service, :delete_refs, request, timeout: GitalyClient.medium_timeout)
raise Gitlab::Git::Repository::GitError, response.git_error if response.git_error.present?
rescue GRPC::BadStatus => e
@@ -164,7 +167,7 @@ module Gitlab
limit: limit
)
- response = GitalyClient.call(@storage, :ref_service, :list_tag_names_containing_commit, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@storage, :ref_service, :list_tag_names_containing_commit, request, timeout: GitalyClient.medium_timeout)
consume_ref_contains_sha_response(response, :tag_names)
end
@@ -176,7 +179,7 @@ module Gitlab
limit: limit
)
- response = GitalyClient.call(@storage, :ref_service, :list_branch_names_containing_commit, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@storage, :ref_service, :list_branch_names_containing_commit, request, timeout: GitalyClient.medium_timeout)
consume_ref_contains_sha_response(response, :branch_names)
end
@@ -185,7 +188,7 @@ module Gitlab
messages = Hash.new { |h, k| h[k] = +''.b }
current_tag_id = nil
- response = GitalyClient.call(@storage, :ref_service, :get_tag_messages, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@storage, :ref_service, :get_tag_messages, request, timeout: GitalyClient.fast_timeout)
response.each do |rpc_message|
current_tag_id = rpc_message.tag_id if rpc_message.tag_id.present?
@@ -197,7 +200,7 @@ module Gitlab
def get_tag_signatures(tag_ids)
request = Gitaly::GetTagSignaturesRequest.new(repository: @gitaly_repo, tag_revisions: tag_ids)
- response = GitalyClient.call(@repository.storage, :ref_service, :get_tag_signatures, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@repository.storage, :ref_service, :get_tag_signatures, request, timeout: GitalyClient.fast_timeout)
signatures = Hash.new { |h, k| h[k] = [+''.b, +''.b] }
current_tag_id = nil
@@ -222,20 +225,20 @@ module Gitlab
patterns: patterns
)
- response = GitalyClient.call(@storage, :ref_service, :list_refs, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@storage, :ref_service, :list_refs, request, timeout: GitalyClient.fast_timeout)
consume_list_refs_response(response)
end
def pack_refs
request = Gitaly::PackRefsRequest.new(repository: @gitaly_repo)
- GitalyClient.call(@storage, :ref_service, :pack_refs, request, timeout: GitalyClient.long_timeout)
+ gitaly_client_call(@storage, :ref_service, :pack_refs, request, timeout: GitalyClient.long_timeout)
end
- def find_refs_by_oid(oid:, limit:)
- request = Gitaly::FindRefsByOIDRequest.new(repository: @gitaly_repo, sort_field: :refname, oid: oid, limit: limit)
+ def find_refs_by_oid(oid:, limit:, ref_patterns: nil)
+ request = Gitaly::FindRefsByOIDRequest.new(repository: @gitaly_repo, sort_field: :refname, oid: oid, limit: limit, ref_patterns: ref_patterns)
- response = GitalyClient.call(@storage, :ref_service, :find_refs_by_oid, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@storage, :ref_service, :find_refs_by_oid, request, timeout: GitalyClient.medium_timeout)
response&.refs&.to_a
end
diff --git a/lib/gitlab/gitaly_client/remote_service.rb b/lib/gitlab/gitaly_client/remote_service.rb
index 535b987f91c..9647cfad76e 100644
--- a/lib/gitlab/gitaly_client/remote_service.rb
+++ b/lib/gitlab/gitaly_client/remote_service.rb
@@ -4,6 +4,7 @@ module Gitlab
module GitalyClient
class RemoteService
include Gitlab::EncodingHelper
+ include WithFeatureFlagActors
MAX_MSG_SIZE = 128.kilobytes.freeze
@@ -24,6 +25,8 @@ module Gitlab
@repository = repository
@gitaly_repo = repository.gitaly_repository
@storage = repository.storage
+
+ self.repository_actor = repository
end
def find_remote_root_ref(remote_url, authorization)
@@ -31,7 +34,7 @@ module Gitlab
remote_url: remote_url,
http_authorization_header: authorization)
- response = GitalyClient.call(@storage, :remote_service,
+ response = gitaly_client_call(@storage, :remote_service,
:find_remote_root_ref, request, timeout: GitalyClient.medium_timeout)
encode_utf8(response.ref)
diff --git a/lib/gitlab/gitaly_client/repository_service.rb b/lib/gitlab/gitaly_client/repository_service.rb
index f11437552e1..e6565bd33c2 100644
--- a/lib/gitlab/gitaly_client/repository_service.rb
+++ b/lib/gitlab/gitaly_client/repository_service.rb
@@ -4,6 +4,7 @@ module Gitlab
module GitalyClient
class RepositoryService
include Gitlab::EncodingHelper
+ include WithFeatureFlagActors
MAX_MSG_SIZE = 128.kilobytes
@@ -11,57 +12,59 @@ module Gitlab
@repository = repository
@gitaly_repo = repository.gitaly_repository
@storage = repository.storage
+
+ self.repository_actor = repository
end
def exists?
request = Gitaly::RepositoryExistsRequest.new(repository: @gitaly_repo)
- response = GitalyClient.call(@storage, :repository_service, :repository_exists, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@storage, :repository_service, :repository_exists, request, timeout: GitalyClient.fast_timeout)
response.exists
end
def optimize_repository
request = Gitaly::OptimizeRepositoryRequest.new(repository: @gitaly_repo)
- GitalyClient.call(@storage, :repository_service, :optimize_repository, request, timeout: GitalyClient.long_timeout)
+ gitaly_client_call(@storage, :repository_service, :optimize_repository, request, timeout: GitalyClient.long_timeout)
end
def prune_unreachable_objects
request = Gitaly::PruneUnreachableObjectsRequest.new(repository: @gitaly_repo)
- GitalyClient.call(@storage, :repository_service, :prune_unreachable_objects, request, timeout: GitalyClient.long_timeout)
+ gitaly_client_call(@storage, :repository_service, :prune_unreachable_objects, request, timeout: GitalyClient.long_timeout)
end
def garbage_collect(create_bitmap, prune:)
request = Gitaly::GarbageCollectRequest.new(repository: @gitaly_repo, create_bitmap: create_bitmap, prune: prune)
- GitalyClient.call(@storage, :repository_service, :garbage_collect, request, timeout: GitalyClient.long_timeout)
+ gitaly_client_call(@storage, :repository_service, :garbage_collect, request, timeout: GitalyClient.long_timeout)
end
def repack_full(create_bitmap)
request = Gitaly::RepackFullRequest.new(repository: @gitaly_repo, create_bitmap: create_bitmap)
- GitalyClient.call(@storage, :repository_service, :repack_full, request, timeout: GitalyClient.long_timeout)
+ gitaly_client_call(@storage, :repository_service, :repack_full, request, timeout: GitalyClient.long_timeout)
end
def repack_incremental
request = Gitaly::RepackIncrementalRequest.new(repository: @gitaly_repo)
- GitalyClient.call(@storage, :repository_service, :repack_incremental, request, timeout: GitalyClient.long_timeout)
+ gitaly_client_call(@storage, :repository_service, :repack_incremental, request, timeout: GitalyClient.long_timeout)
end
def repository_size
request = Gitaly::RepositorySizeRequest.new(repository: @gitaly_repo)
- response = GitalyClient.call(@storage, :repository_service, :repository_size, request, timeout: GitalyClient.long_timeout)
+ response = gitaly_client_call(@storage, :repository_service, :repository_size, request, timeout: GitalyClient.long_timeout)
response.size
end
def get_object_directory_size
request = Gitaly::GetObjectDirectorySizeRequest.new(repository: @gitaly_repo)
- response = GitalyClient.call(@storage, :repository_service, :get_object_directory_size, request, timeout: GitalyClient.medium_timeout)
+ response = gitaly_client_call(@storage, :repository_service, :get_object_directory_size, request, timeout: GitalyClient.medium_timeout)
response.size
end
def apply_gitattributes(revision)
request = Gitaly::ApplyGitattributesRequest.new(repository: @gitaly_repo, revision: encode_binary(revision))
- GitalyClient.call(@storage, :repository_service, :apply_gitattributes, request, timeout: GitalyClient.fast_timeout)
+ gitaly_client_call(@storage, :repository_service, :apply_gitattributes, request, timeout: GitalyClient.fast_timeout)
rescue GRPC::InvalidArgument => ex
raise Gitlab::Git::Repository::InvalidRef, ex
end
@@ -69,7 +72,7 @@ module Gitlab
def info_attributes
request = Gitaly::GetInfoAttributesRequest.new(repository: @gitaly_repo)
- response = GitalyClient.call(@storage, :repository_service, :get_info_attributes, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@storage, :repository_service, :get_info_attributes, request, timeout: GitalyClient.fast_timeout)
response.each_with_object([]) do |message, attributes|
attributes << message.attributes
end.join
@@ -103,18 +106,18 @@ module Gitlab
end
end
- GitalyClient.call(@storage, :repository_service, :fetch_remote, request, timeout: GitalyClient.long_timeout)
+ gitaly_client_call(@storage, :repository_service, :fetch_remote, request, timeout: GitalyClient.long_timeout)
end
# rubocop: enable Metrics/ParameterLists
def create_repository(default_branch = nil)
request = Gitaly::CreateRepositoryRequest.new(repository: @gitaly_repo, default_branch: default_branch)
- GitalyClient.call(@storage, :repository_service, :create_repository, request, timeout: GitalyClient.fast_timeout)
+ gitaly_client_call(@storage, :repository_service, :create_repository, request, timeout: GitalyClient.fast_timeout)
end
def has_local_branches?
request = Gitaly::HasLocalBranchesRequest.new(repository: @gitaly_repo)
- response = GitalyClient.call(@storage, :repository_service, :has_local_branches, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@storage, :repository_service, :has_local_branches, request, timeout: GitalyClient.fast_timeout)
response.value
end
@@ -125,7 +128,7 @@ module Gitlab
revisions: revisions.map { |r| encode_binary(r) }
)
- response = GitalyClient.call(@storage, :repository_service, :find_merge_base, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@storage, :repository_service, :find_merge_base, request, timeout: GitalyClient.fast_timeout)
response.base.presence
end
@@ -135,7 +138,7 @@ module Gitlab
source_repository: source_repository.gitaly_repository
)
- GitalyClient.call(
+ gitaly_client_call(
@storage,
:repository_service,
:create_fork,
@@ -153,7 +156,7 @@ module Gitlab
mirror: mirror
)
- GitalyClient.call(
+ gitaly_client_call(
@storage,
:repository_service,
:create_repository_from_url,
@@ -170,7 +173,7 @@ module Gitlab
target_ref: local_ref.b
)
- response = GitalyClient.call(
+ response = gitaly_client_call(
@storage,
:repository_service,
:fetch_source_branch,
@@ -184,7 +187,7 @@ module Gitlab
def fsck
request = Gitaly::FsckRequest.new(repository: @gitaly_repo)
- response = GitalyClient.call(@storage, :repository_service, :fsck, request, timeout: GitalyClient.long_timeout)
+ response = gitaly_client_call(@storage, :repository_service, :fsck, request, timeout: GitalyClient.long_timeout)
if response.error.empty?
["", 0]
@@ -236,7 +239,7 @@ module Gitlab
http_auth: http_auth
)
- GitalyClient.call(
+ gitaly_client_call(
@storage,
:repository_service,
:create_repository_from_snapshot,
@@ -253,11 +256,11 @@ module Gitlab
)
request.old_revision = old_ref.b unless old_ref.nil?
- GitalyClient.call(@storage, :repository_service, :write_ref, request, timeout: GitalyClient.fast_timeout)
+ gitaly_client_call(@storage, :repository_service, :write_ref, request, timeout: GitalyClient.fast_timeout)
end
def set_full_path(path)
- GitalyClient.call(
+ gitaly_client_call(
@storage,
:repository_service,
:set_full_path,
@@ -272,7 +275,7 @@ module Gitlab
end
def full_path
- response = GitalyClient.call(
+ response = gitaly_client_call(
@storage,
:repository_service,
:full_path,
@@ -286,12 +289,12 @@ module Gitlab
def find_license
request = Gitaly::FindLicenseRequest.new(repository: @gitaly_repo)
- GitalyClient.call(@storage, :repository_service, :find_license, request, timeout: GitalyClient.medium_timeout)
+ gitaly_client_call(@storage, :repository_service, :find_license, request, timeout: GitalyClient.medium_timeout)
end
def calculate_checksum
request = Gitaly::CalculateChecksumRequest.new(repository: @gitaly_repo)
- response = GitalyClient.call(@storage, :repository_service, :calculate_checksum, request, timeout: GitalyClient.fast_timeout)
+ response = gitaly_client_call(@storage, :repository_service, :calculate_checksum, request, timeout: GitalyClient.fast_timeout)
response.checksum.presence
rescue GRPC::DataLoss => e
raise Gitlab::Git::Repository::InvalidRepository, e
@@ -300,23 +303,23 @@ module Gitlab
def raw_changes_between(from, to)
request = Gitaly::GetRawChangesRequest.new(repository: @gitaly_repo, from_revision: from, to_revision: to)
- GitalyClient.call(@storage, :repository_service, :get_raw_changes, request, timeout: GitalyClient.fast_timeout)
+ gitaly_client_call(@storage, :repository_service, :get_raw_changes, request, timeout: GitalyClient.fast_timeout)
end
- def search_files_by_name(ref, query)
- request = Gitaly::SearchFilesByNameRequest.new(repository: @gitaly_repo, ref: ref, query: query)
- GitalyClient.call(@storage, :repository_service, :search_files_by_name, request, timeout: GitalyClient.fast_timeout).flat_map(&:files)
+ 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)
+ 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)
- response = GitalyClient.call(@storage, :repository_service, :search_files_by_content, request, timeout: GitalyClient.default_timeout)
+ 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)
- request = Gitaly::SearchFilesByNameRequest.new(repository: @gitaly_repo, ref: ref, query: '.', filter: filter)
- GitalyClient.call(@storage, :repository_service, :search_files_by_name, request, timeout: GitalyClient.fast_timeout).flat_map(&:files)
+ 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)
+ gitaly_client_call(@storage, :repository_service, :search_files_by_name, request, timeout: GitalyClient.fast_timeout).flat_map(&:files)
end
def disconnect_alternates
@@ -324,19 +327,19 @@ module Gitlab
repository: @gitaly_repo
)
- GitalyClient.call(@storage, :object_pool_service, :disconnect_git_alternates, request, timeout: GitalyClient.long_timeout)
+ gitaly_client_call(@storage, :object_pool_service, :disconnect_git_alternates, request, timeout: GitalyClient.long_timeout)
end
def rename(relative_path)
request = Gitaly::RenameRepositoryRequest.new(repository: @gitaly_repo, relative_path: relative_path)
- GitalyClient.call(@storage, :repository_service, :rename_repository, request, timeout: GitalyClient.fast_timeout)
+ gitaly_client_call(@storage, :repository_service, :rename_repository, request, timeout: GitalyClient.fast_timeout)
end
def remove
request = Gitaly::RemoveRepositoryRequest.new(repository: @gitaly_repo)
- GitalyClient.call(@storage, :repository_service, :remove_repository, request, timeout: GitalyClient.long_timeout)
+ gitaly_client_call(@storage, :repository_service, :remove_repository, request, timeout: GitalyClient.long_timeout)
end
def replicate(source_repository)
@@ -345,7 +348,7 @@ module Gitlab
source: source_repository.gitaly_repository
)
- GitalyClient.call(
+ gitaly_client_call(
@storage,
:repository_service,
:replicate_repository,
@@ -371,11 +374,11 @@ module Gitlab
current_match << message.match_data
- if message.end_of_match
- matches << current_match
- current_match = +""
- matches_count += 1
- end
+ next unless message.end_of_match
+
+ matches << current_match
+ current_match = +""
+ matches_count += 1
end
matches
@@ -383,7 +386,7 @@ module Gitlab
def gitaly_fetch_stream_to_file(save_path, rpc_name, request_class, timeout)
request = request_class.new(repository: @gitaly_repo)
- response = GitalyClient.call(
+ response = gitaly_client_call(
@storage,
:repository_service,
rpc_name,
@@ -416,7 +419,7 @@ module Gitlab
end
end
- GitalyClient.call(
+ gitaly_client_call(
@storage,
:repository_service,
rpc_name,
diff --git a/lib/gitlab/gitaly_client/with_feature_flag_actors.rb b/lib/gitlab/gitaly_client/with_feature_flag_actors.rb
new file mode 100644
index 00000000000..92fc524b724
--- /dev/null
+++ b/lib/gitlab/gitaly_client/with_feature_flag_actors.rb
@@ -0,0 +1,103 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module GitalyClient
+ # This module is responsible for collecting feature flag actors in Gitaly Client. Unlike normal feature flags used
+ # in Gitlab development, feature flags passed to Gitaly are pre-evaluated at Rails side before being passed to
+ # Gitaly. As a result, we need to collect all possible actors for the evaluation before issue any RPC. At this
+ # layer, the only parameter we have is raw repository. We need to infer other actors from the repository. Adding
+ # extra SQL queries before any RPC are not good for the performance. We applied some quirky optimizations here to
+ # avoid issuing SQL queries. However, in some less common code paths, a couple of queries are expected.
+ module WithFeatureFlagActors
+ include Gitlab::Utils::StrongMemoize
+
+ attr_accessor :repository_actor
+
+ # gitaly_client_call performs Gitaly calls including collected feature flag actors. The actors are retrieved
+ # from repository actor and memoized. The service must set `self.repository_actor = a_repository` beforehand.
+ def gitaly_client_call(*args, **kargs)
+ return GitalyClient.call(*args, **kargs) unless actors_aware_gitaly_calls?
+
+ unless repository_actor
+ Gitlab::ErrorTracking.track_and_raise_for_dev_exception(
+ Feature::InvalidFeatureFlagError.new("gitaly_client_call called without setting repository_actor")
+ )
+ end
+
+ GitalyClient.with_feature_flag_actors(
+ repository: repository_actor,
+ user: user_actor,
+ project: project_actor,
+ group: group_actor
+ ) do
+ GitalyClient.call(*args, **kargs)
+ end
+ end
+
+ # gitaly_feature_flag_actors returns a hash of actors implied from input repository. If actors_aware_gitaly_calls
+ # flag is not on, this method returns an empty hash.
+ def gitaly_feature_flag_actors(repository)
+ return {} unless actors_aware_gitaly_calls?
+
+ container = find_repository_container(repository)
+ {
+ repository: repository,
+ user: Feature::Gitaly.user_actor,
+ project: Feature::Gitaly.project_actor(container),
+ group: Feature::Gitaly.group_actor(container)
+ }
+ end
+
+ # Use actor here means the user who originally perform the action. It is collected from ApplicationContext. As
+ # this information is widely propagated in all entry points, User actor should be available everywhere, even in
+ # background jobs.
+ def user_actor
+ strong_memoize(:user_actor) do
+ Feature::Gitaly.user_actor
+ end
+ end
+
+ # TODO: replace this project actor by Repo actor
+ def project_actor
+ strong_memoize(:project_actor) do
+ Feature::Gitaly.project_actor(repository_container)
+ end
+ end
+
+ def group_actor
+ strong_memoize(:group_actor) do
+ Feature::Gitaly.group_actor(repository_container)
+ end
+ end
+
+ private
+
+ def repository_container
+ strong_memoize(:repository_container) do
+ find_repository_container(repository_actor)
+ end
+ end
+
+ def find_repository_container(repository)
+ return if repository&.gl_repository.blank?
+
+ if repository.container.nil?
+ begin
+ identifier = Gitlab::GlRepository::Identifier.parse(repository.gl_repository)
+ identifier.container
+ rescue Gitlab::GlRepository::Identifier::InvalidIdentifier
+ nil
+ end
+ else
+ repository.container
+ end
+ end
+
+ def actors_aware_gitaly_calls?
+ Feature.enabled?(:actors_aware_gitaly_calls)
+ end
+ end
+ end
+end
+
+Gitlab::GitalyClient::WithFeatureFlagActors.prepend_mod_with('Gitlab::GitalyClient::WithFeatureFlagActors')
diff --git a/lib/gitlab/github_import/client.rb b/lib/gitlab/github_import/client.rb
index 0f89a7b6575..d6060141bce 100644
--- a/lib/gitlab/github_import/client.rb
+++ b/lib/gitlab/github_import/client.rb
@@ -76,6 +76,10 @@ module Gitlab
each_object(:pull_request_reviews, repo_name, iid)
end
+ def pull_request_review_requests(repo_name, iid)
+ with_rate_limit { octokit.pull_request_review_requests(repo_name, iid).to_h }
+ end
+
def repos(options = {})
octokit.repos(nil, options).map(&:to_h)
end
diff --git a/lib/gitlab/github_import/importer/events/changed_assignee.rb b/lib/gitlab/github_import/importer/events/changed_assignee.rb
index b75d41f40de..bcf9cd94ad9 100644
--- a/lib/gitlab/github_import/importer/events/changed_assignee.rb
+++ b/lib/gitlab/github_import/importer/events/changed_assignee.rb
@@ -39,12 +39,10 @@ module Gitlab
def parse_body(issue_event, assignee_id)
assignee = User.find(assignee_id).to_reference
- Gitlab::I18n.with_default_locale do
- if issue_event.event == "unassigned"
- "unassigned #{assignee}"
- else
- "assigned to #{assignee}"
- end
+ if issue_event.event == 'unassigned'
+ "#{SystemNotes::IssuablesService.issuable_events[:unassigned]} #{assignee}"
+ else
+ "#{SystemNotes::IssuablesService.issuable_events[:assigned]} #{assignee}"
end
end
end
diff --git a/lib/gitlab/github_import/importer/events/changed_label.rb b/lib/gitlab/github_import/importer/events/changed_label.rb
index 83130d18db9..553ef0886e8 100644
--- a/lib/gitlab/github_import/importer/events/changed_label.rb
+++ b/lib/gitlab/github_import/importer/events/changed_label.rb
@@ -13,6 +13,7 @@ module Gitlab
def create_event(issue_event)
attrs = {
+ importing: true,
user_id: author_id(issue_event),
label_id: label_finder.id_for(issue_event.label_title),
action: action(issue_event.event),
diff --git a/lib/gitlab/github_import/importer/protected_branch_importer.rb b/lib/gitlab/github_import/importer/protected_branch_importer.rb
index 21075e21e1d..801a0840c52 100644
--- a/lib/gitlab/github_import/importer/protected_branch_importer.rb
+++ b/lib/gitlab/github_import/importer/protected_branch_importer.rb
@@ -37,18 +37,36 @@ module Gitlab
name: protected_branch.id,
push_access_levels_attributes: [{ access_level: push_access_level }],
merge_access_levels_attributes: [{ access_level: merge_access_level }],
- allow_force_push: allow_force_push?
+ allow_force_push: allow_force_push?,
+ code_owner_approval_required: code_owner_approval_required?
}
end
def allow_force_push?
- if ProtectedBranch.protected?(project, protected_branch.id)
- ProtectedBranch.allow_force_push?(project, protected_branch.id) && protected_branch.allow_force_pushes
+ return false unless protected_branch.allow_force_pushes
+
+ if protected_on_gitlab?
+ ProtectedBranch.allow_force_push?(project, protected_branch.id)
+ elsif default_branch?
+ !default_branch_protection.any?
else
- protected_branch.allow_force_pushes
+ true
end
end
+ def code_owner_approval_required?
+ return false unless project.licensed_feature_available?(:code_owner_approval_required)
+
+ return protected_branch.require_code_owner_reviews unless protected_on_gitlab?
+
+ # Gets the strictest require_code_owner rule between GitHub and GitLab
+ protected_branch.require_code_owner_reviews ||
+ ProtectedBranch.branch_requires_code_owner_approval?(
+ project,
+ protected_branch.id
+ )
+ end
+
def default_branch?
protected_branch.id == project.default_branch
end
diff --git a/lib/gitlab/github_import/importer/protected_branches_importer.rb b/lib/gitlab/github_import/importer/protected_branches_importer.rb
index 4372477f55d..ff425528aec 100644
--- a/lib/gitlab/github_import/importer/protected_branches_importer.rb
+++ b/lib/gitlab/github_import/importer/protected_branches_importer.rb
@@ -13,13 +13,15 @@ module Gitlab
protected_branches = client.branches(repo).select { |branch| branch.dig(:protection, :enabled) }
protected_branches.each do |protected_branch|
+ next if already_imported?(protected_branch)
+
object = client.branch_protection(repo, protected_branch[:name])
- next if object.nil? || already_imported?(object)
+ next if object.nil?
yield object
Gitlab::GithubImport::ObjectCounter.increment(project, object_type, :fetched)
- mark_as_imported(object)
+ mark_as_imported(protected_branch)
end
end
diff --git a/lib/gitlab/github_import/importer/pull_request_review_importer.rb b/lib/gitlab/github_import/importer/pull_request_review_importer.rb
index dd5b7c93ced..b11af90aa6f 100644
--- a/lib/gitlab/github_import/importer/pull_request_review_importer.rb
+++ b/lib/gitlab/github_import/importer/pull_request_review_importer.rb
@@ -18,6 +18,7 @@ module Gitlab
if gitlab_user_id
add_review_note!(gitlab_user_id)
add_approval!(gitlab_user_id)
+ add_reviewer!(gitlab_user_id)
else
add_complementary_review_note!(project.creator_id)
end
@@ -95,6 +96,24 @@ module Gitlab
end
end
+ def add_reviewer!(user_id)
+ return if review_re_requested?(user_id)
+
+ ::MergeRequestReviewer.create!(
+ merge_request_id: merge_request.id,
+ user_id: user_id,
+ state: ::MergeRequestReviewer.states['reviewed'],
+ created_at: submitted_at
+ )
+ end
+
+ # rubocop:disable CodeReuse/ActiveRecord
+ def review_re_requested?(user_id)
+ # records that were imported on previous stage with "unreviewed" status
+ MergeRequestReviewer.where(merge_request_id: merge_request.id, user_id: user_id).exists?
+ end
+ # rubocop:enable CodeReuse/ActiveRecord
+
def add_approval_system_note!(user_id)
attributes = note_attributes(
user_id,
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
new file mode 100644
index 00000000000..bb51d856d9b
--- /dev/null
+++ b/lib/gitlab/github_import/importer/pull_requests/review_request_importer.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module GithubImport
+ module Importer
+ module PullRequests
+ class ReviewRequestImporter
+ def initialize(review_request, project, client)
+ @review_request = review_request
+ @user_finder = UserFinder.new(project, client)
+ @issue_finder = IssuableFinder.new(project, client)
+ end
+
+ def execute
+ MergeRequestReviewer.bulk_insert!(build_reviewers)
+ end
+
+ private
+
+ 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.map do |reviewer_id|
+ MergeRequestReviewer.new(
+ merge_request_id: review_request.merge_request_id,
+ user_id: reviewer_id,
+ state: MergeRequestReviewer.states['unreviewed'],
+ created_at: Time.zone.now
+ )
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/github_import/importer/pull_requests/review_requests_importer.rb b/lib/gitlab/github_import/importer/pull_requests/review_requests_importer.rb
new file mode 100644
index 00000000000..c5d8da3be1c
--- /dev/null
+++ b/lib/gitlab/github_import/importer/pull_requests/review_requests_importer.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module GithubImport
+ module Importer
+ module PullRequests
+ class ReviewRequestsImporter
+ include ParallelScheduling
+
+ BATCH_SIZE = 100
+
+ private
+
+ def each_object_to_import(&block)
+ merge_request_collection.each_batch(of: BATCH_SIZE, column: :iid) do |batch|
+ batch.each do |merge_request|
+ repo = project.import_source
+
+ review_requests = client.pull_request_review_requests(repo, merge_request.iid)
+ review_requests[:merge_request_id] = merge_request.id
+ yield review_requests
+
+ mark_merge_request_imported(merge_request)
+ end
+ end
+ end
+
+ def importer_class
+ ReviewRequestImporter
+ end
+
+ def representation_class
+ Gitlab::GithubImport::Representation::PullRequests::ReviewRequests
+ end
+
+ def sidekiq_worker_class
+ Gitlab::GithubImport::PullRequests::ImportReviewRequestWorker
+ end
+
+ def collection_method
+ :pull_request_review_requests
+ end
+
+ # rubocop:disable CodeReuse/ActiveRecord
+ def merge_request_collection
+ project.merge_requests
+ .where.not(iid: already_imported_merge_requests)
+ .select(:id, :iid)
+ end
+ # rubocop:enable CodeReuse/ActiveRecord
+
+ def merge_request_imported_cache_key
+ "github-importer/pull_requests/#{collection_method}/already-imported/#{project.id}"
+ end
+
+ def already_imported_merge_requests
+ Gitlab::Cache::Import::Caching.values_from_set(merge_request_imported_cache_key)
+ end
+
+ def mark_merge_request_imported(merge_request)
+ Gitlab::Cache::Import::Caching.set_add(
+ merge_request_imported_cache_key,
+ merge_request.iid
+ )
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/github_import/importer/pull_requests_importer.rb b/lib/gitlab/github_import/importer/pull_requests_importer.rb
index 16541c90002..62863ba67fd 100644
--- a/lib/gitlab/github_import/importer/pull_requests_importer.rb
+++ b/lib/gitlab/github_import/importer/pull_requests_importer.rb
@@ -38,7 +38,7 @@ module Gitlab
# deliberate. If we were to update this column after the fetch we may
# miss out on changes pushed during the fetch or between the fetch and
# updating the timestamp.
- project.touch(:last_repository_updated_at) # rubocop: disable Rails/SkipsModelValidations
+ project.touch(:last_repository_updated_at)
project.repository.fetch_remote(project.import_url, refmap: Gitlab::GithubImport.refmap, forced: true)
diff --git a/lib/gitlab/github_import/importer/repository_importer.rb b/lib/gitlab/github_import/importer/repository_importer.rb
index 708768a60cf..d7fe01e90f8 100644
--- a/lib/gitlab/github_import/importer/repository_importer.rb
+++ b/lib/gitlab/github_import/importer/repository_importer.rb
@@ -80,7 +80,7 @@ module Gitlab
end
def update_clone_time
- project.touch(:last_repository_updated_at) # rubocop: disable Rails/SkipsModelValidations
+ project.touch(:last_repository_updated_at)
end
private
diff --git a/lib/gitlab/github_import/representation/protected_branch.rb b/lib/gitlab/github_import/representation/protected_branch.rb
index 07a607ae70d..d2a52b64bbf 100644
--- a/lib/gitlab/github_import/representation/protected_branch.rb
+++ b/lib/gitlab/github_import/representation/protected_branch.rb
@@ -10,7 +10,7 @@ module Gitlab
attr_reader :attributes
expose_attribute :id, :allow_force_pushes, :required_conversation_resolution, :required_signatures,
- :required_pull_request_reviews
+ :required_pull_request_reviews, :require_code_owner_reviews
# Builds a Branch Protection info from a GitHub API response.
# Resource structure details:
@@ -24,7 +24,9 @@ module Gitlab
allow_force_pushes: branch_protection.dig(:allow_force_pushes, :enabled),
required_conversation_resolution: branch_protection.dig(:required_conversation_resolution, :enabled),
required_signatures: branch_protection.dig(:required_signatures, :enabled),
- required_pull_request_reviews: branch_protection[:required_pull_request_reviews].present?
+ required_pull_request_reviews: branch_protection[:required_pull_request_reviews].present?,
+ require_code_owner_reviews: branch_protection.dig(:required_pull_request_reviews,
+ :require_code_owner_reviews).present?
}
new(hash)
diff --git a/lib/gitlab/github_import/representation/pull_requests/review_requests.rb b/lib/gitlab/github_import/representation/pull_requests/review_requests.rb
new file mode 100644
index 00000000000..692004c4460
--- /dev/null
+++ b/lib/gitlab/github_import/representation/pull_requests/review_requests.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module GithubImport
+ module Representation
+ module PullRequests
+ class ReviewRequests
+ include ToHash
+ include ExposeAttribute
+
+ attr_reader :attributes
+
+ expose_attribute :merge_request_id, :users
+
+ class << self
+ # Builds a list of requested reviewers from a GitHub API response.
+ #
+ # review_requests - An instance of `Hash` containing the review requests details.
+ def from_api_response(review_requests, _additional_data = {})
+ review_requests = Representation.symbolize_hash(review_requests)
+ users = review_requests[:users].map do |user_data|
+ Representation::User.from_api_response(user_data)
+ end
+
+ new(
+ merge_request_id: review_requests[:merge_request_id],
+ users: users
+ )
+ end
+ alias_method :from_json_hash, :from_api_response
+ end
+
+ # attributes - A Hash containing the review details. The keys of this
+ # Hash (and any nested hashes) must be symbols.
+ def initialize(attributes)
+ @attributes = attributes
+ end
+
+ def github_identifiers
+ { merge_request_id: merge_request_id }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index bdb7484f3d6..ecb57bfc1a2 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -18,8 +18,16 @@ module Gitlab
gon.markdown_automatic_lists = current_user&.markdown_automatic_lists
if Gitlab.config.sentry.enabled
- gon.sentry_dsn = Gitlab.config.sentry.clientside_dsn
- gon.sentry_environment = Gitlab.config.sentry.environment
+ gon.sentry_dsn = Gitlab.config.sentry.clientside_dsn
+ gon.sentry_environment = Gitlab.config.sentry.environment
+ end
+
+ # Support for Sentry setup via configuration files will be removed in 16.0
+ # in favor of Gitlab::CurrentSettings.
+ if Feature.enabled?(:enable_new_sentry_clientside_integration,
+ current_user) && Gitlab::CurrentSettings.sentry_enabled
+ gon.sentry_dsn = Gitlab::CurrentSettings.sentry_clientside_dsn
+ gon.sentry_environment = Gitlab::CurrentSettings.sentry_environment
end
gon.recaptcha_api_server_url = ::Recaptcha.configuration.api_server_url
@@ -58,6 +66,7 @@ module Gitlab
push_frontend_feature_flag(:new_header_search)
push_frontend_feature_flag(:source_editor_toolbar)
push_frontend_feature_flag(:integration_slack_app_notifications)
+ push_frontend_feature_flag(:vue_group_select)
end
# Exposes the state of a feature flag to the frontend code.
diff --git a/lib/gitlab/grape_logging/loggers/filter_parameters.rb b/lib/gitlab/grape_logging/loggers/filter_parameters.rb
new file mode 100644
index 00000000000..ae9df203544
--- /dev/null
+++ b/lib/gitlab/grape_logging/loggers/filter_parameters.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module GrapeLogging
+ module Loggers
+ # In the CI variables APIs, the POST or PUT parameters will always be
+ # literally 'key' and 'value'. Rails' default filters_parameters will
+ # always incorrectly mask the value of param 'key' when it should mask the
+ # value of the param 'value'.
+ # See: https://gitlab.com/gitlab-org/gitlab/-/issues/353857
+ class FilterParameters < ::GrapeLogging::Loggers::FilterParameters
+ private
+
+ def safe_parameters(request)
+ loggable_params = super
+ settings = request.env[Grape::Env::API_ENDPOINT]&.route&.settings
+
+ return loggable_params unless settings&.key?(:log_safety)
+
+ settings[:log_safety][:safe].each do |key|
+ loggable_params[key] = request.params[key] if loggable_params.key?(key)
+ end
+
+ settings[:log_safety][:unsafe].each do |key|
+ loggable_params[key] = @replacement if loggable_params.key?(key)
+ end
+
+ loggable_params
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/highlight.rb b/lib/gitlab/highlight.rb
index b71abe5c052..1a85c57e6b1 100644
--- a/lib/gitlab/highlight.rb
+++ b/lib/gitlab/highlight.rb
@@ -2,9 +2,9 @@
module Gitlab
class Highlight
- def self.highlight(blob_name, blob_content, language: nil, plain: false)
+ def self.highlight(blob_name, blob_content, language: nil, plain: false, context: {})
new(blob_name, blob_content, language: language)
- .highlight(blob_content, continue: false, plain: plain)
+ .highlight(blob_content, continue: false, plain: plain, context: context)
end
def self.too_large?(size)
diff --git a/lib/gitlab/hook_data/merge_request_builder.rb b/lib/gitlab/hook_data/merge_request_builder.rb
index 65c623c5d7d..96128f432c5 100644
--- a/lib/gitlab/hook_data/merge_request_builder.rb
+++ b/lib/gitlab/hook_data/merge_request_builder.rb
@@ -66,12 +66,19 @@ module Gitlab
labels: merge_request.labels_hook_attrs,
state: merge_request.state, # This key is deprecated
blocking_discussions_resolved: merge_request.mergeable_discussions_state?,
- first_contribution: merge_request.first_contribution?
+ first_contribution: merge_request.first_contribution?,
+ detailed_merge_status: detailed_merge_status
}
merge_request.attributes.with_indifferent_access.slice(*self.class.safe_hook_attributes)
.merge!(attrs)
end
+
+ private
+
+ def detailed_merge_status
+ ::MergeRequests::Mergeability::DetailedMergeStatusService.new(merge_request: merge_request).execute.to_s
+ end
end
end
end
diff --git a/lib/gitlab/i18n.rb b/lib/gitlab/i18n.rb
index a2d06b7f5b3..a42cac61a55 100644
--- a/lib/gitlab/i18n.rb
+++ b/lib/gitlab/i18n.rb
@@ -44,30 +44,30 @@ module Gitlab
TRANSLATION_LEVELS = {
'bg' => 0,
'cs_CZ' => 0,
- 'da_DK' => 37,
+ 'da_DK' => 36,
'de' => 17,
'en' => 100,
'eo' => 0,
- 'es' => 36,
+ 'es' => 35,
'fil_PH' => 0,
- 'fr' => 72,
+ 'fr' => 85,
'gl_ES' => 0,
'id_ID' => 0,
'it' => 1,
- 'ja' => 31,
- 'ko' => 20,
+ 'ja' => 30,
+ 'ko' => 21,
'nb_NO' => 25,
'nl_NL' => 0,
'pl_PL' => 3,
- 'pt_BR' => 57,
- 'ro_RO' => 99,
- 'ru' => 26,
+ 'pt_BR' => 58,
+ 'ro_RO' => 98,
+ 'ru' => 25,
'si_LK' => 11,
'tr_TR' => 11,
- 'uk' => 49,
+ 'uk' => 52,
'zh_CN' => 98,
'zh_HK' => 1,
- 'zh_TW' => 99
+ 'zh_TW' => 100
}.freeze
private_constant :TRANSLATION_LEVELS
diff --git a/lib/gitlab/identifier.rb b/lib/gitlab/identifier.rb
index d5f94ad04f1..08d44184bb6 100644
--- a/lib/gitlab/identifier.rb
+++ b/lib/gitlab/identifier.rb
@@ -5,10 +5,11 @@
module Gitlab
module Identifier
def identify(identifier)
- if identifier =~ /\Auser-\d+\Z/
+ case identifier
+ when /\Auser-\d+\Z/
# git push over http
identify_using_user(identifier)
- elsif identifier =~ /\Akey-\d+\Z/
+ when /\Akey-\d+\Z/
# git push over ssh
identify_using_ssh_key(identifier)
end
diff --git a/lib/gitlab/import_export/attributes_permitter.rb b/lib/gitlab/import_export/attributes_permitter.rb
index f6f65f85599..8c7a6c13246 100644
--- a/lib/gitlab/import_export/attributes_permitter.rb
+++ b/lib/gitlab/import_export/attributes_permitter.rb
@@ -85,11 +85,11 @@ module Gitlab
while stack.any?
model_name, relations = stack.pop
- if relations.is_a?(Hash)
- add_permitted_attributes(model_name, relations.keys)
+ next unless relations.is_a?(Hash)
- stack.concat(relations.to_a)
- end
+ add_permitted_attributes(model_name, relations.keys)
+
+ stack.concat(relations.to_a)
end
@permitted_attributes
diff --git a/lib/gitlab/import_export/base/relation_object_saver.rb b/lib/gitlab/import_export/base/relation_object_saver.rb
index 3c473449ec0..ed3858d0bf4 100644
--- a/lib/gitlab/import_export/base/relation_object_saver.rb
+++ b/lib/gitlab/import_export/base/relation_object_saver.rb
@@ -81,11 +81,11 @@ module Gitlab
subrelation = relation_object.public_send(definition)
association = relation_object.class.reflect_on_association(definition)
- if association&.collection? && subrelation.size > MIN_RECORDS_SIZE
- collection_subrelations[definition] = subrelation.records
+ next unless association&.collection? && subrelation.size > MIN_RECORDS_SIZE
- subrelation.clear
- end
+ collection_subrelations[definition] = subrelation.records
+
+ subrelation.clear
end
end
end
diff --git a/lib/gitlab/import_export/decompressed_archive_size_validator.rb b/lib/gitlab/import_export/decompressed_archive_size_validator.rb
index c98dcf7b848..aa66fe8a5ae 100644
--- a/lib/gitlab/import_export/decompressed_archive_size_validator.rb
+++ b/lib/gitlab/import_export/decompressed_archive_size_validator.rb
@@ -87,7 +87,6 @@ module Gitlab
def validate_archive_path
Gitlab::Utils.check_path_traversal!(@archive_path)
- raise(ServiceError, 'Archive path is not a string') unless @archive_path.is_a?(String)
raise(ServiceError, 'Archive path is a symlink') if File.lstat(@archive_path).symlink?
raise(ServiceError, 'Archive path is not a file') unless File.file?(@archive_path)
end
diff --git a/lib/gitlab/import_export/project/exported_relations_merger.rb b/lib/gitlab/import_export/project/exported_relations_merger.rb
new file mode 100644
index 00000000000..dda3d00d608
--- /dev/null
+++ b/lib/gitlab/import_export/project/exported_relations_merger.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module ImportExport
+ module Project
+ class ExportedRelationsMerger
+ include Gitlab::ImportExport::CommandLineUtil
+
+ def initialize(export_job:, shared:)
+ @export_job = export_job
+ @shared = shared
+ end
+
+ def save
+ Dir.mktmpdir do |dirpath|
+ export_job.relation_exports.each do |relation_export|
+ relation = relation_export.relation
+ upload = relation_export.upload
+ filename = upload.export_file.filename
+
+ tar_gz_full_path = File.join(dirpath, filename)
+ decompress_path = File.join(dirpath, relation)
+ Gitlab::Utils.check_path_traversal!(tar_gz_full_path)
+ Gitlab::Utils.check_path_traversal!(decompress_path)
+
+ # Download tar.gz
+ download_or_copy_upload(
+ upload.export_file, tar_gz_full_path, size_limit: relation_export.upload.export_file.size
+ )
+
+ # Decompress tar.gz
+ mkdir_p(decompress_path)
+ untar_zxf(dir: decompress_path, archive: tar_gz_full_path)
+ File.delete(tar_gz_full_path)
+
+ # Merge decompressed files into export_path
+ RecursiveMergeFolders.merge(decompress_path, shared.export_path)
+ FileUtils.rm_r(decompress_path)
+ rescue StandardError => e
+ shared.error(e)
+ false
+ end
+ end
+
+ shared.errors.empty?
+ end
+
+ private
+
+ attr_reader :shared, :export_job
+
+ delegate :project, to: :export_job
+ 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 fb44aaf094e..2d9c8d1108e 100644
--- a/lib/gitlab/import_export/project/import_export.yml
+++ b/lib/gitlab/import_export/project/import_export.yml
@@ -302,6 +302,7 @@ included_attributes:
- :environments_access_level
- :feature_flags_access_level
- :releases_access_level
+ - :infrastructure_access_level
prometheus_metrics:
- :created_at
- :updated_at
@@ -585,7 +586,7 @@ included_attributes:
- :target_sha
pipeline_metadata:
- :project_id
- - :title
+ - :name
stages:
- :name
- :status
@@ -717,6 +718,7 @@ included_attributes:
- :environments_access_level
- :feature_flags_access_level
- :releases_access_level
+ - :infrastructure_access_level
- :allow_merge_on_skipped_pipeline
- :auto_devops_deploy_strategy
- :auto_devops_enabled
diff --git a/lib/gitlab/import_export/project/relation_saver.rb b/lib/gitlab/import_export/project/relation_saver.rb
index 8e91adac196..967239e17c1 100644
--- a/lib/gitlab/import_export/project/relation_saver.rb
+++ b/lib/gitlab/import_export/project/relation_saver.rb
@@ -32,7 +32,7 @@ module Gitlab
project,
reader.project_tree,
json_writer,
- exportable_path: 'project',
+ exportable_path: 'tree/project',
current_user: nil
)
end
diff --git a/lib/gitlab/import_export/recursive_merge_folders.rb b/lib/gitlab/import_export/recursive_merge_folders.rb
new file mode 100644
index 00000000000..982358699bd
--- /dev/null
+++ b/lib/gitlab/import_export/recursive_merge_folders.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+#
+# This class is used by Import/Export to move files and folders from a source folders into a target folders
+# that can already have the same folders in it, resolving in a merged folder.
+#
+# Example:
+#
+# source path
+# |-- tree
+# | |-- project
+# | |-- labels.ndjson
+# |-- uploads
+# | |-- folder1
+# | | |-- image1.png
+# | |-- folder2
+# | | |-- image2.png
+#
+# target path
+# |-- tree
+# | |-- project
+# | |-- issues.ndjson
+# |-- uploads
+# | |-- folder1
+# | | |-- image3.png
+# | |-- folder3
+# | | |-- image4.png
+#
+# target path after merge
+# |-- tree
+# | |-- project
+# | | |-- issues.ndjson
+# | | |-- labels.ndjson
+# |-- uploads
+# | |-- folder1
+# | | |-- image1.png
+# | | |-- image3.png
+# | |-- folder2
+# | | |-- image2.png
+# | |-- folder3
+# | | |-- image4.png
+
+module Gitlab
+ module ImportExport
+ class RecursiveMergeFolders
+ DEFAULT_DIR_MODE = 0o700
+
+ def self.merge(source_path, target_path)
+ Gitlab::Utils.check_path_traversal!(source_path)
+ Gitlab::Utils.check_path_traversal!(target_path)
+ Gitlab::Utils.check_allowed_absolute_path!(source_path, [Dir.tmpdir])
+
+ recursive_merge(source_path, target_path)
+ end
+
+ def self.recursive_merge(source_path, target_path)
+ Dir.children(source_path).each do |child|
+ source_child = File.join(source_path, child)
+ target_child = File.join(target_path, child)
+
+ next if File.lstat(source_child).symlink?
+
+ if File.directory?(source_child)
+ FileUtils.mkdir_p(target_child, mode: DEFAULT_DIR_MODE) unless File.exist?(target_child)
+ recursive_merge(source_child, target_child)
+ else
+ FileUtils.mv(source_child, target_child)
+ end
+ end
+ end
+
+ private_class_method :recursive_merge
+ end
+ end
+end
diff --git a/lib/gitlab/incoming_email.rb b/lib/gitlab/incoming_email.rb
index d55906083ff..d34c19bc9fc 100644
--- a/lib/gitlab/incoming_email.rb
+++ b/lib/gitlab/incoming_email.rb
@@ -2,30 +2,11 @@
module Gitlab
module IncomingEmail
- UNSUBSCRIBE_SUFFIX = '-unsubscribe'
- UNSUBSCRIBE_SUFFIX_LEGACY = '+unsubscribe'
- WILDCARD_PLACEHOLDER = '%{key}'
-
class << self
- def enabled?
- config.enabled && config.address.present?
- end
+ include Gitlab::Email::Common
- def supports_wildcard?
- config.address.present? && config.address.include?(WILDCARD_PLACEHOLDER)
- end
-
- def supports_issue_creation?
- enabled? && supports_wildcard?
- end
-
- def reply_address(key)
- config.address.sub(WILDCARD_PLACEHOLDER, key)
- end
-
- # example: incoming+1234567890abcdef1234567890abcdef-unsubscribe@incoming.gitlab.com
- def unsubscribe_address(key)
- config.address.sub(WILDCARD_PLACEHOLDER, "#{key}#{UNSUBSCRIBE_SUFFIX}")
+ def config
+ incoming_email_config
end
def key_from_address(address, wildcard_address: nil)
@@ -39,21 +20,6 @@ module Gitlab
match[1]
end
- def key_from_fallback_message_id(mail_id)
- message_id_regexp = /\Areply\-(.+)@#{Gitlab.config.gitlab.host}\z/
-
- mail_id[message_id_regexp, 1]
- end
-
- def scan_fallback_references(references)
- # It's looking for each <...>
- references.scan(/(?!<)[^<>]+(?=>)/)
- end
-
- def config
- Gitlab.config.incoming_email
- end
-
private
def address_regex(wildcard_address)
diff --git a/lib/gitlab/instrumentation/redis_base.rb b/lib/gitlab/instrumentation/redis_base.rb
index 0bd10597f24..268c6cdf459 100644
--- a/lib/gitlab/instrumentation/redis_base.rb
+++ b/lib/gitlab/instrumentation/redis_base.rb
@@ -66,8 +66,8 @@ module Gitlab
query_time.round(::Gitlab::InstrumentationHelper::DURATION_PRECISION)
end
- def redis_cluster_validate!(command)
- ::Gitlab::Instrumentation::RedisClusterValidator.validate!(command) if @redis_cluster_validation
+ def redis_cluster_validate!(commands)
+ ::Gitlab::Instrumentation::RedisClusterValidator.validate!(commands) if @redis_cluster_validation
end
def enable_redis_cluster_validation
diff --git a/lib/gitlab/instrumentation/redis_cluster_validator.rb b/lib/gitlab/instrumentation/redis_cluster_validator.rb
index 005751fb0db..36d3e088956 100644
--- a/lib/gitlab/instrumentation/redis_cluster_validator.rb
+++ b/lib/gitlab/instrumentation/redis_cluster_validator.rb
@@ -10,57 +10,189 @@ module Gitlab
#
# Gitlab::Redis::Cache
# .with { |redis| redis.call('COMMAND') }
- # .select { |command| command[3] != command[4] }
- # .map { |command| [command[0].upcase, { first: command[3], last: command[4], step: command[5] }] }
+ # .select { |cmd| cmd[3] != 0 }
+ # .map { |cmd| [
+ # cmd[0].upcase,
+ # { first: cmd[3], last: cmd[4], step: cmd[5], single_key: cmd[3] == cmd[4] }
+ # ]
+ # }
# .sort_by(&:first)
# .to_h
- #
- MULTI_KEY_COMMANDS = {
- "BITOP" => { first: 2, last: -1, step: 1 },
- "BLPOP" => { first: 1, last: -2, step: 1 },
- "BRPOP" => { first: 1, last: -2, step: 1 },
- "BRPOPLPUSH" => { first: 1, last: 2, step: 1 },
- "BZPOPMAX" => { first: 1, last: -2, step: 1 },
- "BZPOPMIN" => { first: 1, last: -2, step: 1 },
- "DEL" => { first: 1, last: -1, step: 1 },
- "EXISTS" => { first: 1, last: -1, step: 1 },
- "MGET" => { first: 1, last: -1, step: 1 },
- "MSET" => { first: 1, last: -1, step: 2 },
- "MSETNX" => { first: 1, last: -1, step: 2 },
- "PFCOUNT" => { first: 1, last: -1, step: 1 },
- "PFMERGE" => { first: 1, last: -1, step: 1 },
- "RENAME" => { first: 1, last: 2, step: 1 },
- "RENAMENX" => { first: 1, last: 2, step: 1 },
- "RPOPLPUSH" => { first: 1, last: 2, step: 1 },
- "SDIFF" => { first: 1, last: -1, step: 1 },
- "SDIFFSTORE" => { first: 1, last: -1, step: 1 },
- "SINTER" => { first: 1, last: -1, step: 1 },
- "SINTERSTORE" => { first: 1, last: -1, step: 1 },
- "SMOVE" => { first: 1, last: 2, step: 1 },
- "SUNION" => { first: 1, last: -1, step: 1 },
- "SUNIONSTORE" => { first: 1, last: -1, step: 1 },
- "UNLINK" => { first: 1, last: -1, step: 1 },
- "WATCH" => { first: 1, last: -1, step: 1 }
+ REDIS_COMMANDS = {
+ "APPEND" => { first: 1, last: 1, step: 1, single_key: true },
+ "BITCOUNT" => { first: 1, last: 1, step: 1, single_key: true },
+ "BITFIELD" => { first: 1, last: 1, step: 1, single_key: true },
+ "BITFIELD_RO" => { first: 1, last: 1, step: 1, single_key: true },
+ "BITOP" => { first: 2, last: -1, step: 1, single_key: false },
+ "BITPOS" => { first: 1, last: 1, step: 1, single_key: true },
+ "BLMOVE" => { first: 1, last: 2, step: 1, single_key: false },
+ "BLPOP" => { first: 1, last: -2, step: 1, single_key: false },
+ "BRPOP" => { first: 1, last: -2, step: 1, single_key: false },
+ "BRPOPLPUSH" => { first: 1, last: 2, step: 1, single_key: false },
+ "BZPOPMAX" => { first: 1, last: -2, step: 1, single_key: false },
+ "BZPOPMIN" => { first: 1, last: -2, step: 1, single_key: false },
+ "COPY" => { first: 1, last: 2, step: 1, single_key: false },
+ "DECR" => { first: 1, last: 1, step: 1, single_key: true },
+ "DECRBY" => { first: 1, last: 1, step: 1, single_key: true },
+ "DEL" => { first: 1, last: -1, step: 1, single_key: false },
+ "DUMP" => { first: 1, last: 1, step: 1, single_key: true },
+ "EXISTS" => { first: 1, last: -1, step: 1, single_key: false },
+ "EXPIRE" => { first: 1, last: 1, step: 1, single_key: true },
+ "EXPIREAT" => { first: 1, last: 1, step: 1, single_key: true },
+ "GEOADD" => { first: 1, last: 1, step: 1, single_key: true },
+ "GEODIST" => { first: 1, last: 1, step: 1, single_key: true },
+ "GEOHASH" => { first: 1, last: 1, step: 1, single_key: true },
+ "GEOPOS" => { first: 1, last: 1, step: 1, single_key: true },
+ "GEORADIUS" => { first: 1, last: 1, step: 1, single_key: true },
+ "GEORADIUSBYMEMBER" => { first: 1, last: 1, step: 1, single_key: true },
+ "GEORADIUSBYMEMBER_RO" => { first: 1, last: 1, step: 1, single_key: true },
+ "GEORADIUS_RO" => { first: 1, last: 1, step: 1, single_key: true },
+ "GEOSEARCH" => { first: 1, last: 1, step: 1, single_key: true },
+ "GEOSEARCHSTORE" => { first: 1, last: 2, step: 1, single_key: false },
+ "GET" => { first: 1, last: 1, step: 1, single_key: true },
+ "GETBIT" => { first: 1, last: 1, step: 1, single_key: true },
+ "GETDEL" => { first: 1, last: 1, step: 1, single_key: true },
+ "GETEX" => { first: 1, last: 1, step: 1, single_key: true },
+ "GETRANGE" => { first: 1, last: 1, step: 1, single_key: true },
+ "GETSET" => { first: 1, last: 1, step: 1, single_key: true },
+ "HDEL" => { first: 1, last: 1, step: 1, single_key: true },
+ "HEXISTS" => { first: 1, last: 1, step: 1, single_key: true },
+ "HGET" => { first: 1, last: 1, step: 1, single_key: true },
+ "HGETALL" => { first: 1, last: 1, step: 1, single_key: true },
+ "HINCRBY" => { first: 1, last: 1, step: 1, single_key: true },
+ "HINCRBYFLOAT" => { first: 1, last: 1, step: 1, single_key: true },
+ "HKEYS" => { first: 1, last: 1, step: 1, single_key: true },
+ "HLEN" => { first: 1, last: 1, step: 1, single_key: true },
+ "HMGET" => { first: 1, last: 1, step: 1, single_key: true },
+ "HMSET" => { first: 1, last: 1, step: 1, single_key: true },
+ "HRANDFIELD" => { first: 1, last: 1, step: 1, single_key: true },
+ "HSCAN" => { first: 1, last: 1, step: 1, single_key: true },
+ "HSET" => { first: 1, last: 1, step: 1, single_key: true },
+ "HSETNX" => { first: 1, last: 1, step: 1, single_key: true },
+ "HSTRLEN" => { first: 1, last: 1, step: 1, single_key: true },
+ "HVALS" => { first: 1, last: 1, step: 1, single_key: true },
+ "INCR" => { first: 1, last: 1, step: 1, single_key: true },
+ "INCRBY" => { first: 1, last: 1, step: 1, single_key: true },
+ "INCRBYFLOAT" => { first: 1, last: 1, step: 1, single_key: true },
+ "LINDEX" => { first: 1, last: 1, step: 1, single_key: true },
+ "LINSERT" => { first: 1, last: 1, step: 1, single_key: true },
+ "LLEN" => { first: 1, last: 1, step: 1, single_key: true },
+ "LMOVE" => { first: 1, last: 2, step: 1, single_key: false },
+ "LPOP" => { first: 1, last: 1, step: 1, single_key: true },
+ "LPOS" => { first: 1, last: 1, step: 1, single_key: true },
+ "LPUSH" => { first: 1, last: 1, step: 1, single_key: true },
+ "LPUSHX" => { first: 1, last: 1, step: 1, single_key: true },
+ "LRANGE" => { first: 1, last: 1, step: 1, single_key: true },
+ "LREM" => { first: 1, last: 1, step: 1, single_key: true },
+ "LSET" => { first: 1, last: 1, step: 1, single_key: true },
+ "LTRIM" => { first: 1, last: 1, step: 1, single_key: true },
+ "MGET" => { first: 1, last: -1, step: 1, single_key: false },
+ "MIGRATE" => { first: 3, last: 3, step: 1, single_key: true },
+ "MOVE" => { first: 1, last: 1, step: 1, single_key: true },
+ "MSET" => { first: 1, last: -1, step: 2, single_key: false },
+ "MSETNX" => { first: 1, last: -1, step: 2, single_key: false },
+ "OBJECT" => { first: 2, last: 2, step: 1, single_key: true },
+ "PERSIST" => { first: 1, last: 1, step: 1, single_key: true },
+ "PEXPIRE" => { first: 1, last: 1, step: 1, single_key: true },
+ "PEXPIREAT" => { first: 1, last: 1, step: 1, single_key: true },
+ "PFADD" => { first: 1, last: 1, step: 1, single_key: true },
+ "PFCOUNT" => { first: 1, last: -1, step: 1, single_key: false },
+ "PFDEBUG" => { first: 2, last: 2, step: 1, single_key: true },
+ "PFMERGE" => { first: 1, last: -1, step: 1, single_key: false },
+ "PSETEX" => { first: 1, last: 1, step: 1, single_key: true },
+ "PTTL" => { first: 1, last: 1, step: 1, single_key: true },
+ "RENAME" => { first: 1, last: 2, step: 1, single_key: false },
+ "RENAMENX" => { first: 1, last: 2, step: 1, single_key: false },
+ "RESTORE" => { first: 1, last: 1, step: 1, single_key: true },
+ "RESTORE-ASKING" => { first: 1, last: 1, step: 1, single_key: true },
+ "RPOP" => { first: 1, last: 1, step: 1, single_key: true },
+ "RPOPLPUSH" => { first: 1, last: 2, step: 1, single_key: false },
+ "RPUSH" => { first: 1, last: 1, step: 1, single_key: true },
+ "RPUSHX" => { first: 1, last: 1, step: 1, single_key: true },
+ "SADD" => { first: 1, last: 1, step: 1, single_key: true },
+ "SCARD" => { first: 1, last: 1, step: 1, single_key: true },
+ "SDIFF" => { first: 1, last: -1, step: 1, single_key: false },
+ "SDIFFSTORE" => { first: 1, last: -1, step: 1, single_key: false },
+ "SET" => { first: 1, last: 1, step: 1, single_key: true },
+ "SETBIT" => { first: 1, last: 1, step: 1, single_key: true },
+ "SETEX" => { first: 1, last: 1, step: 1, single_key: true },
+ "SETNX" => { first: 1, last: 1, step: 1, single_key: true },
+ "SETRANGE" => { first: 1, last: 1, step: 1, single_key: true },
+ "SINTER" => { first: 1, last: -1, step: 1, single_key: false },
+ "SINTERSTORE" => { first: 1, last: -1, step: 1, single_key: false },
+ "SISMEMBER" => { first: 1, last: 1, step: 1, single_key: true },
+ "SMEMBERS" => { first: 1, last: 1, step: 1, single_key: true },
+ "SMISMEMBER" => { first: 1, last: 1, step: 1, single_key: true },
+ "SMOVE" => { first: 1, last: 2, step: 1, single_key: false },
+ "SORT" => { first: 1, last: 1, step: 1, single_key: true },
+ "SPOP" => { first: 1, last: 1, step: 1, single_key: true },
+ "SRANDMEMBER" => { first: 1, last: 1, step: 1, single_key: true },
+ "SREM" => { first: 1, last: 1, step: 1, single_key: true },
+ "SSCAN" => { first: 1, last: 1, step: 1, single_key: true },
+ "STRLEN" => { first: 1, last: 1, step: 1, single_key: true },
+ "SUBSTR" => { first: 1, last: 1, step: 1, single_key: true },
+ "SUNION" => { first: 1, last: -1, step: 1, single_key: false },
+ "SUNIONSTORE" => { first: 1, last: -1, step: 1, single_key: false },
+ "TOUCH" => { first: 1, last: -1, step: 1, single_key: false },
+ "TTL" => { first: 1, last: 1, step: 1, single_key: true },
+ "TYPE" => { first: 1, last: 1, step: 1, single_key: true },
+ "UNLINK" => { first: 1, last: -1, step: 1, single_key: false },
+ "WATCH" => { first: 1, last: -1, step: 1, single_key: false },
+ "XACK" => { first: 1, last: 1, step: 1, single_key: true },
+ "XADD" => { first: 1, last: 1, step: 1, single_key: true },
+ "XAUTOCLAIM" => { first: 1, last: 1, step: 1, single_key: true },
+ "XCLAIM" => { first: 1, last: 1, step: 1, single_key: true },
+ "XDEL" => { first: 1, last: 1, step: 1, single_key: true },
+ "XGROUP" => { first: 2, last: 2, step: 1, single_key: true },
+ "XINFO" => { first: 2, last: 2, step: 1, single_key: true },
+ "XLEN" => { first: 1, last: 1, step: 1, single_key: true },
+ "XPENDING" => { first: 1, last: 1, step: 1, single_key: true },
+ "XRANGE" => { first: 1, last: 1, step: 1, single_key: true },
+ "XREVRANGE" => { first: 1, last: 1, step: 1, single_key: true },
+ "XSETID" => { first: 1, last: 1, step: 1, single_key: true },
+ "XTRIM" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZADD" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZCARD" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZCOUNT" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZDIFFSTORE" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZINCRBY" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZINTERSTORE" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZLEXCOUNT" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZMSCORE" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZPOPMAX" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZPOPMIN" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZRANDMEMBER" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZRANGE" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZRANGEBYLEX" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZRANGEBYSCORE" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZRANGESTORE" => { first: 1, last: 2, step: 1, single_key: false },
+ "ZRANK" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZREM" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZREMRANGEBYLEX" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZREMRANGEBYRANK" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZREMRANGEBYSCORE" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZREVRANGE" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZREVRANGEBYLEX" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZREVRANGEBYSCORE" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZREVRANK" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZSCAN" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZSCORE" => { first: 1, last: 1, step: 1, single_key: true },
+ "ZUNIONSTORE" => { first: 1, last: 1, step: 1, single_key: true }
}.freeze
CrossSlotError = Class.new(StandardError)
class << self
- def validate!(command)
+ def validate!(commands)
return unless Rails.env.development? || Rails.env.test?
return if allow_cross_slot_commands?
+ return if commands.empty?
- command_name = command.first.to_s.upcase
- argument_positions = MULTI_KEY_COMMANDS[command_name]
-
- return unless argument_positions
-
- arguments = command.flatten[argument_positions[:first]..argument_positions[:last]]
-
- key_slots = arguments.each_slice(argument_positions[:step]).map do |args|
- key_slot(args.first)
- end
+ # early exit for single-command (non-pipelined) if it is a single-key-command
+ command_name = commands.size > 1 ? "PIPELINE/MULTI" : commands.first.first.to_s.upcase
+ return if commands.size == 1 && REDIS_COMMANDS.dig(command_name, :single_key)
+ key_slots = commands.map { |command| key_slots(command) }.flatten
if key_slots.uniq.many? # rubocop: disable CodeReuse/ActiveRecord
raise CrossSlotError, "Redis command #{command_name} arguments hash to different slots. See https://docs.gitlab.com/ee/development/redis.html#multi-key-commands"
end
@@ -78,6 +210,17 @@ module Gitlab
private
+ def key_slots(command)
+ argument_positions = REDIS_COMMANDS[command.first.to_s.upcase]
+
+ return [] unless argument_positions
+
+ arguments = command.flatten[argument_positions[:first]..argument_positions[:last]]
+ arguments.each_slice(argument_positions[:step]).map do |args|
+ key_slot(args.first)
+ end
+ end
+
def allow_cross_slot_commands?
Thread.current[:allow_cross_slot_commands].to_i > 0
end
diff --git a/lib/gitlab/instrumentation/redis_interceptor.rb b/lib/gitlab/instrumentation/redis_interceptor.rb
index 7e2acb91b94..f19279df2fe 100644
--- a/lib/gitlab/instrumentation/redis_interceptor.rb
+++ b/lib/gitlab/instrumentation/redis_interceptor.rb
@@ -5,14 +5,6 @@ module Gitlab
module RedisInterceptor
APDEX_EXCLUDE = %w[brpop blpop brpoplpush bzpopmin bzpopmax xread xreadgroup].freeze
- class MysteryRedisDurationError < StandardError
- attr_reader :backtrace
-
- def initialize(backtrace)
- @backtrace = backtrace
- end
- end
-
def call(command)
instrument_call([command]) do
super
@@ -41,8 +33,7 @@ module Gitlab
def instrument_call(commands)
start = Gitlab::Metrics::System.monotonic_time # must come first so that 'start' is always defined
instrumentation_class.instance_count_request(commands.size)
-
- commands.each { |c| instrumentation_class.redis_cluster_validate!(c) }
+ instrumentation_class.redis_cluster_validate!(commands)
yield
rescue ::Redis::BaseError => ex
diff --git a/lib/gitlab/issues/rebalancing/state.rb b/lib/gitlab/issues/rebalancing/state.rb
index abb50281f7a..36346564b39 100644
--- a/lib/gitlab/issues/rebalancing/state.rb
+++ b/lib/gitlab/issues/rebalancing/state.rb
@@ -25,7 +25,7 @@ module Gitlab
redis.multi do |multi|
# we trigger re-balance for namespaces(groups) or specific user project
value = "#{rebalanced_container_type}/#{rebalanced_container_id}"
- multi.sadd(CONCURRENT_RUNNING_REBALANCES_KEY, value)
+ multi.sadd?(CONCURRENT_RUNNING_REBALANCES_KEY, value)
multi.expire(CONCURRENT_RUNNING_REBALANCES_KEY, REDIS_EXPIRY_TIME)
end
end
@@ -99,11 +99,13 @@ module Gitlab
def refresh_keys_expiration
with_redis do |redis|
- redis.multi do |multi|
- multi.expire(issue_ids_key, REDIS_EXPIRY_TIME)
- multi.expire(current_index_key, REDIS_EXPIRY_TIME)
- multi.expire(current_project_key, REDIS_EXPIRY_TIME)
- multi.expire(CONCURRENT_RUNNING_REBALANCES_KEY, REDIS_EXPIRY_TIME)
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ redis.multi do |multi|
+ multi.expire(issue_ids_key, REDIS_EXPIRY_TIME)
+ multi.expire(current_index_key, REDIS_EXPIRY_TIME)
+ multi.expire(current_project_key, REDIS_EXPIRY_TIME)
+ multi.expire(CONCURRENT_RUNNING_REBALANCES_KEY, REDIS_EXPIRY_TIME)
+ end
end
end
end
@@ -112,12 +114,14 @@ module Gitlab
value = "#{rebalanced_container_type}/#{rebalanced_container_id}"
with_redis do |redis|
- redis.multi do |multi|
- multi.del(issue_ids_key)
- multi.del(current_index_key)
- multi.del(current_project_key)
- multi.srem(CONCURRENT_RUNNING_REBALANCES_KEY, value)
- multi.set(self.class.recently_finished_key(rebalanced_container_type, rebalanced_container_id), true, ex: 1.hour)
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ redis.multi do |multi|
+ multi.del(issue_ids_key)
+ multi.del(current_index_key)
+ multi.del(current_project_key)
+ multi.srem?(CONCURRENT_RUNNING_REBALANCES_KEY, value)
+ multi.set(self.class.recently_finished_key(rebalanced_container_type, rebalanced_container_id), true, ex: 1.hour)
+ end
end
end
end
@@ -136,9 +140,10 @@ module Gitlab
current_rebalancing_containers.each do |string|
container_type, container_id = string.split('/', 2).map(&:to_i)
- if container_type == NAMESPACE
+ case container_type
+ when NAMESPACE
namespace_ids << container_id
- elsif container_type == PROJECT
+ when PROJECT
project_ids << container_id
end
end
diff --git a/lib/gitlab/json.rb b/lib/gitlab/json.rb
index 823d6202b1e..8332e4f6d56 100644
--- a/lib/gitlab/json.rb
+++ b/lib/gitlab/json.rb
@@ -41,6 +41,11 @@ module Gitlab
# as the underlying implementation of this varies wildly based on
# the adapter in use.
#
+ # This method does, in some situations, differ in the data it returns
+ # compared to .generate. Counter-intuitively, this is closest in
+ # terms of response to JSON.generate and to the default ActiveSupport
+ # .to_json method.
+ #
# @param object [Object] the object to convert to JSON
# @return [String]
def dump(object)
@@ -162,23 +167,11 @@ module Gitlab
# @return [Boolean, String, Array, Hash, Object]
# @raise [JSON::ParserError]
def handle_legacy_mode!(data)
- return data unless feature_table_exists?
+ return data unless Feature.feature_flags_available?
return data unless Feature.enabled?(:json_wrapper_legacy_mode)
raise parser_error if INVALID_LEGACY_TYPES.any? { |type| data.is_a?(type) }
end
-
- # There are a variety of database errors possible when checking the feature
- # flags at the wrong time during boot, e.g. during migrations. We don't care
- # about these errors, we just need to ensure that we skip feature detection
- # if they will fail.
- #
- # @return [Boolean]
- def feature_table_exists?
- Feature::FlipperFeature.table_exists?
- rescue StandardError
- false
- end
end
# GrapeFormatter is a JSON formatter for the Grape API.
@@ -263,5 +256,19 @@ module Gitlab
buffer.string
end
end
+
+ class RailsEncoder < ActiveSupport::JSON::Encoding::JSONGemEncoder
+ # Rails doesn't provide a way of changing the JSON adapter for
+ # render calls in controllers, so here we're overriding the parent
+ # class method to use our generator, and it's monkey-patched in
+ # config/initializers/active_support_json.rb
+ def stringify(jsonified)
+ Gitlab::Json.dump(jsonified)
+ rescue EncodingError => ex
+ # Raise the same error as the default implementation if we encounter
+ # an error. These are usually related to invalid UTF-8 errors.
+ raise JSON::GeneratorError, ex
+ end
+ end
end
end
diff --git a/lib/gitlab/json_logger.rb b/lib/gitlab/json_logger.rb
index d0dcd232ecc..7dbedef44ee 100644
--- a/lib/gitlab/json_logger.rb
+++ b/lib/gitlab/json_logger.rb
@@ -1,31 +1,52 @@
# frozen_string_literal: true
+require 'labkit/logging'
module Gitlab
- class JsonLogger < ::Gitlab::Logger
- def self.file_name_noext
- raise NotImplementedError
- end
+ class JsonLogger < ::Labkit::Logging::JsonLogger
+ class << self
+ def file_name_noext
+ raise NotImplementedError, "JsonLogger implementations must provide file_name_noext implementation"
+ end
+
+ def file_name
+ file_name_noext + ".log"
+ end
+
+ def debug(message)
+ build.debug(message)
+ end
+
+ def error(message)
+ build.error(message)
+ end
+
+ def warn(message)
+ build.warn(message)
+ end
- def format_message(severity, timestamp, progname, message)
- data = default_attributes
- data[:severity] = severity
- data[:time] = timestamp.utc.iso8601(3)
- data[Labkit::Correlation::CorrelationId::LOG_KEY] = Labkit::Correlation::CorrelationId.current_id
+ def info(message)
+ build.info(message)
+ end
- case message
- when String
- data[:message] = message
- when Hash
- data.merge!(message)
+ def build
+ Gitlab::SafeRequestStore[cache_key] ||=
+ new(full_log_path, level: log_level)
end
- Gitlab::Json.dump(data) + "\n"
+ def cache_key
+ "logger:" + full_log_path.to_s
+ end
+
+ def full_log_path
+ Rails.root.join("log", file_name)
+ end
end
- protected
+ private
- def default_attributes
- {}
+ # Override Labkit's default impl, which uses the default Ruby platform json module.
+ def dump_json(data)
+ Gitlab::Json.dump(data)
end
end
end
diff --git a/lib/gitlab/kas.rb b/lib/gitlab/kas.rb
index bf7b7f2d089..a1e290a54e6 100644
--- a/lib/gitlab/kas.rb
+++ b/lib/gitlab/kas.rb
@@ -34,7 +34,7 @@ module Gitlab
end
def version_info
- Gitlab::VersionInfo.parse(version)
+ Gitlab::VersionInfo.parse(version, parse_suffix: true)
end
# Return GitLab KAS external_url
diff --git a/lib/gitlab/kroki.rb b/lib/gitlab/kroki.rb
index 6799be8e279..5fa77c1f1ba 100644
--- a/lib/gitlab/kroki.rb
+++ b/lib/gitlab/kroki.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
+require 'asciidoctor/extensions/asciidoctor_kroki/version'
require 'asciidoctor/extensions/asciidoctor_kroki/extension'
module Gitlab
diff --git a/lib/gitlab/manifest_import/metadata.rb b/lib/gitlab/manifest_import/metadata.rb
index 6fe9bb10cdf..3747431c6a7 100644
--- a/lib/gitlab/manifest_import/metadata.rb
+++ b/lib/gitlab/manifest_import/metadata.rb
@@ -14,9 +14,11 @@ module Gitlab
def save(repositories, group_id)
Gitlab::Redis::SharedState.with do |redis|
- redis.multi do |multi|
- multi.set(key_for('repositories'), Gitlab::Json.dump(repositories), ex: EXPIRY_TIME)
- multi.set(key_for('group_id'), group_id, ex: EXPIRY_TIME)
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ redis.multi do |multi|
+ multi.set(key_for('repositories'), Gitlab::Json.dump(repositories), ex: EXPIRY_TIME)
+ multi.set(key_for('group_id'), group_id, ex: EXPIRY_TIME)
+ end
end
end
end
diff --git a/lib/gitlab/marginalia/comment.rb b/lib/gitlab/marginalia/comment.rb
index aab58bfa211..1997ebb952b 100644
--- a/lib/gitlab/marginalia/comment.rb
+++ b/lib/gitlab/marginalia/comment.rb
@@ -45,6 +45,18 @@ module Gitlab
def db_config_name
::Gitlab::Database.db_config_name(marginalia_adapter)
end
+
+ def console_hostname
+ return unless ::Gitlab::Runtime.console?
+
+ @cached_console_hostname ||= Socket.gethostname # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ end
+
+ def console_username
+ return unless ::Gitlab::Runtime.console?
+
+ ENV['SUDO_USER'] || ENV['USER']
+ end
end
end
end
diff --git a/lib/gitlab/markdown_cache/redis/store.rb b/lib/gitlab/markdown_cache/redis/store.rb
index 752ab153f37..8cab069e1bf 100644
--- a/lib/gitlab/markdown_cache/redis/store.rb
+++ b/lib/gitlab/markdown_cache/redis/store.rb
@@ -10,9 +10,11 @@ module Gitlab
results = {}
Gitlab::Redis::Cache.with do |r|
- r.pipelined do |pipeline|
- subjects.each do |subject|
- results[subject.cache_key] = new(subject).read(pipeline)
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ r.pipelined do |pipeline|
+ subjects.each do |subject|
+ results[subject.cache_key] = new(subject).read(pipeline)
+ end
end
end
end
@@ -28,7 +30,7 @@ module Gitlab
def save(updates)
@loaded = false
- Gitlab::Redis::Cache.with do |r|
+ with_redis do |r|
r.mapped_hmset(markdown_cache_key, updates)
r.expire(markdown_cache_key, EXPIRES_IN)
end
@@ -40,7 +42,7 @@ module Gitlab
if pipeline
pipeline.mapped_hmget(markdown_cache_key, *fields)
else
- Gitlab::Redis::Cache.with do |r|
+ with_redis do |r|
r.mapped_hmget(markdown_cache_key, *fields)
end
end
@@ -64,6 +66,10 @@ module Gitlab
"markdown_cache:#{@subject.cache_key}"
end
+
+ def with_redis(&block)
+ Gitlab::Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord
+ end
end
end
end
diff --git a/lib/gitlab/memory/watchdog.rb b/lib/gitlab/memory/watchdog.rb
index 7007fdfe386..19dfc640b5d 100644
--- a/lib/gitlab/memory/watchdog.rb
+++ b/lib/gitlab/memory/watchdog.rb
@@ -54,6 +54,17 @@ module Gitlab
init_prometheus_metrics
end
+ ##
+ # Configuration for Watchdog, use like:
+ #
+ # watchdog.configure do |config|
+ # config.handler = Gitlab::Memory::Watchdog::TermProcessHandler
+ # config.sleep_time_seconds = 60
+ # config.logger = Gitlab::AppLogger
+ # config.monitors do |stack|
+ # stack.push MyMonitorClass, args*, max_strikes:, kwargs**, &block
+ # end
+ # end
def configure
yield @configuration
end
@@ -125,7 +136,7 @@ module Gitlab
end
def process_rss_bytes
- Gitlab::Metrics::System.memory_usage_rss
+ Gitlab::Metrics::System.memory_usage_rss[:total]
end
def worker_id
diff --git a/lib/gitlab/memory/watchdog/configuration.rb b/lib/gitlab/memory/watchdog/configuration.rb
index 2d84b083f55..793f75adf59 100644
--- a/lib/gitlab/memory/watchdog/configuration.rb
+++ b/lib/gitlab/memory/watchdog/configuration.rb
@@ -9,7 +9,7 @@ module Gitlab
@monitors = []
end
- def use(monitor_class, *args, **kwargs, &block)
+ def push(monitor_class, *args, **kwargs, &block)
remove(monitor_class)
@monitors.push(build_monitor_state(monitor_class, *args, **kwargs, &block))
end
@@ -39,11 +39,12 @@ module Gitlab
DEFAULT_SLEEP_TIME_SECONDS = 60
- attr_reader :monitors
attr_writer :logger, :handler, :sleep_time_seconds
- def initialize
- @monitors = MonitorStack.new
+ def monitors
+ @monitor_stack ||= MonitorStack.new
+ yield @monitor_stack if block_given?
+ @monitor_stack
end
def handler
diff --git a/lib/gitlab/memory/watchdog/configurator.rb b/lib/gitlab/memory/watchdog/configurator.rb
new file mode 100644
index 00000000000..6d6f97dc8ba
--- /dev/null
+++ b/lib/gitlab/memory/watchdog/configurator.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Memory
+ class Watchdog
+ class Configurator
+ class << self
+ def configure_for_puma
+ lambda do |config|
+ sleep_time_seconds = ENV.fetch('GITLAB_MEMWD_SLEEP_TIME_SEC', 60).to_i
+ config.logger = Gitlab::AppLogger
+ config.handler = Gitlab::Memory::Watchdog::PumaHandler.new
+ config.sleep_time_seconds = sleep_time_seconds
+ config.monitors(&configure_monitors_for_puma)
+ end
+ end
+
+ def configure_for_sidekiq
+ lambda do |config|
+ sleep_time_seconds = [ENV.fetch('SIDEKIQ_MEMORY_KILLER_CHECK_INTERVAL', 3).to_i, 2].max
+ config.logger = Sidekiq.logger
+ config.handler = Gitlab::Memory::Watchdog::TermProcessHandler.new
+ config.sleep_time_seconds = sleep_time_seconds
+ config.monitors(&configure_monitors_for_sidekiq)
+ end
+ end
+
+ private
+
+ def configure_monitors_for_puma
+ lambda do |stack|
+ max_strikes = ENV.fetch('GITLAB_MEMWD_MAX_STRIKES', 5).to_i
+
+ if Gitlab::Utils.to_boolean(ENV['DISABLE_PUMA_WORKER_KILLER'])
+ max_heap_frag = ENV.fetch('GITLAB_MEMWD_MAX_HEAP_FRAG', 0.5).to_f
+ max_mem_growth = ENV.fetch('GITLAB_MEMWD_MAX_MEM_GROWTH', 3.0).to_f
+
+ # stack.push MonitorClass, args*, max_strikes:, kwargs**, &block
+ stack.push Gitlab::Memory::Watchdog::Monitor::HeapFragmentation,
+ max_heap_fragmentation: max_heap_frag,
+ max_strikes: max_strikes
+
+ stack.push Gitlab::Memory::Watchdog::Monitor::UniqueMemoryGrowth,
+ max_mem_growth: max_mem_growth,
+ max_strikes: max_strikes
+ else
+ memory_limit = ENV.fetch('PUMA_WORKER_MAX_MEMORY', 1200).to_i
+
+ stack.push Gitlab::Memory::Watchdog::Monitor::RssMemoryLimit,
+ memory_limit: memory_limit,
+ max_strikes: max_strikes
+ end
+ end
+ end
+
+ def configure_monitors_for_sidekiq
+ # NOP - At the moment we don't run watchdog for Sidekiq
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/memory/watchdog/monitor/heap_fragmentation.rb b/lib/gitlab/memory/watchdog/monitor/heap_fragmentation.rb
index 7748c19c6d8..8f230980eac 100644
--- a/lib/gitlab/memory/watchdog/monitor/heap_fragmentation.rb
+++ b/lib/gitlab/memory/watchdog/monitor/heap_fragmentation.rb
@@ -22,7 +22,7 @@ module Gitlab
def call
heap_fragmentation = Gitlab::Metrics::Memory.gc_heap_fragmentation
- return { threshold_violated: false, payload: {} } unless heap_fragmentation > max_heap_fragmentation
+ return { threshold_violated: false, payload: {} } if heap_fragmentation <= max_heap_fragmentation
{ threshold_violated: true, payload: payload(heap_fragmentation) }
end
diff --git a/lib/gitlab/memory/watchdog/monitor/rss_memory_limit.rb b/lib/gitlab/memory/watchdog/monitor/rss_memory_limit.rb
new file mode 100644
index 00000000000..3e7de024630
--- /dev/null
+++ b/lib/gitlab/memory/watchdog/monitor/rss_memory_limit.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Memory
+ class Watchdog
+ module Monitor
+ class RssMemoryLimit
+ attr_reader :memory_limit
+
+ def initialize(memory_limit:)
+ @memory_limit = memory_limit
+ end
+
+ def call
+ worker_rss = Gitlab::Metrics::System.memory_usage_rss[:total]
+
+ return { threshold_violated: false, payload: {} } if worker_rss <= memory_limit
+
+ { threshold_violated: true, payload: payload(worker_rss, memory_limit) }
+ end
+
+ private
+
+ def payload(worker_rss, memory_limit)
+ {
+ message: 'rss memory limit exceeded',
+ memwd_rss_bytes: worker_rss,
+ memwd_max_rss_bytes: memory_limit
+ }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/memory/watchdog/monitor/unique_memory_growth.rb b/lib/gitlab/memory/watchdog/monitor/unique_memory_growth.rb
index 2a1512c4cff..ce3477e6227 100644
--- a/lib/gitlab/memory/watchdog/monitor/unique_memory_growth.rb
+++ b/lib/gitlab/memory/watchdog/monitor/unique_memory_growth.rb
@@ -16,7 +16,7 @@ module Gitlab
reference_uss = reference_mem[:uss]
memory_limit = max_mem_growth * reference_uss
- return { threshold_violated: false, payload: {} } unless worker_uss > memory_limit
+ return { threshold_violated: false, payload: {} } if worker_uss <= memory_limit
{ threshold_violated: true, payload: payload(worker_uss, reference_uss, memory_limit) }
end
diff --git a/lib/gitlab/merge_requests/mergeability/check_result.rb b/lib/gitlab/merge_requests/mergeability/check_result.rb
index a25156661af..fae4b721e1a 100644
--- a/lib/gitlab/merge_requests/mergeability/check_result.rb
+++ b/lib/gitlab/merge_requests/mergeability/check_result.rb
@@ -22,8 +22,8 @@ module Gitlab
def self.from_hash(data)
new(
- status: data.fetch('status').to_sym,
- payload: data.fetch('payload'))
+ status: data.fetch(:status).to_sym,
+ payload: data.fetch(:payload))
end
def initialize(status:, payload: {})
diff --git a/lib/gitlab/merge_requests/mergeability/redis_interface.rb b/lib/gitlab/merge_requests/mergeability/redis_interface.rb
index b0e739f91ff..1129fa639d8 100644
--- a/lib/gitlab/merge_requests/mergeability/redis_interface.rb
+++ b/lib/gitlab/merge_requests/mergeability/redis_interface.rb
@@ -7,16 +7,20 @@ module Gitlab
VERSION = 1
def save_check(merge_check:, result_hash:)
- Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.set(merge_check.cache_key + ":#{VERSION}", result_hash.to_json, ex: EXPIRATION)
end
end
def retrieve_check(merge_check:)
- Gitlab::Redis::Cache.with do |redis|
- Gitlab::Json.parse(redis.get(merge_check.cache_key + ":#{VERSION}"))
+ with_redis do |redis|
+ Gitlab::Json.parse(redis.get(merge_check.cache_key + ":#{VERSION}"), symbolize_keys: true)
end
end
+
+ def with_redis(&block)
+ Gitlab::Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord
+ end
end
end
end
diff --git a/lib/gitlab/metrics/dashboard/finder.rb b/lib/gitlab/metrics/dashboard/finder.rb
index c8591a81a05..a4964ae0ebc 100644
--- a/lib/gitlab/metrics/dashboard/finder.rb
+++ b/lib/gitlab/metrics/dashboard/finder.rb
@@ -78,7 +78,7 @@ module Gitlab
end
def predefined_dashboard_services_for(project)
- # Only list the self monitoring dashboard on the self monitoring project,
+ # Only list the self-monitoring dashboard on the self-monitoring project,
# since it is the only dashboard (at time of writing) that shows data
# about GitLab itself.
if project.self_monitoring?
diff --git a/lib/gitlab/metrics/global_search_slis.rb b/lib/gitlab/metrics/global_search_slis.rb
index 3400a6c78ef..200c6eb4043 100644
--- a/lib/gitlab/metrics/global_search_slis.rb
+++ b/lib/gitlab/metrics/global_search_slis.rb
@@ -5,12 +5,12 @@ module Gitlab
module GlobalSearchSlis
class << self
# The following targets are the 99.95th percentile of code searches
- # gathered on 24-08-2022
+ # gathered on 25-10-2022
# from https://log.gprd.gitlab.net/goto/0c89cd80-23af-11ed-8656-f5f2137823ba (internal only)
- BASIC_CONTENT_TARGET_S = 7.031
- BASIC_CODE_TARGET_S = 21.903
- ADVANCED_CONTENT_TARGET_S = 4.865
- ADVANCED_CODE_TARGET_S = 13.546
+ BASIC_CONTENT_TARGET_S = 8.812
+ BASIC_CODE_TARGET_S = 27.538
+ ADVANCED_CONTENT_TARGET_S = 2.452
+ ADVANCED_CODE_TARGET_S = 15.52
def initialize_slis!
Gitlab::Metrics::Sli::Apdex.initialize_sli(:global_search, possible_labels)
diff --git a/lib/gitlab/metrics/loose_foreign_keys_slis.rb b/lib/gitlab/metrics/loose_foreign_keys_slis.rb
new file mode 100644
index 00000000000..5d8245aa609
--- /dev/null
+++ b/lib/gitlab/metrics/loose_foreign_keys_slis.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Metrics
+ module LooseForeignKeysSlis
+ class << self
+ def initialize_slis!
+ Gitlab::Metrics::Sli::Apdex.initialize_sli(:loose_foreign_key_clean_ups, possible_labels)
+ Gitlab::Metrics::Sli::ErrorRate.initialize_sli(:loose_foreign_key_clean_ups, possible_labels)
+ end
+
+ def record_apdex(success:, db_config_name:)
+ Gitlab::Metrics::Sli::Apdex[:loose_foreign_key_clean_ups].increment(
+ labels: labels(db_config_name),
+ success: success
+ )
+ end
+
+ def record_error_rate(error:, db_config_name:)
+ Gitlab::Metrics::Sli::ErrorRate[:loose_foreign_key_clean_ups].increment(
+ labels: labels(db_config_name),
+ error: error
+ )
+ end
+
+ private
+
+ def possible_labels
+ ::Gitlab::Database.db_config_names.map do |db_config_name|
+ {
+ db_config_name: db_config_name,
+ feature_category: :database
+ }
+ end
+ end
+
+ def labels(db_config_name)
+ {
+ db_config_name: db_config_name,
+ feature_category: :database
+ }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/metrics/method_call.rb b/lib/gitlab/metrics/method_call.rb
index c6b0a0c5e76..f39ec9cc8ab 100644
--- a/lib/gitlab/metrics/method_call.rb
+++ b/lib/gitlab/metrics/method_call.rb
@@ -39,7 +39,6 @@ module Gitlab
docstring 'Method calls real duration'
label_keys label_keys
buckets [0.01, 0.05, 0.1, 0.5, 1]
- with_feature :prometheus_metrics_method_instrumentation
end
end
diff --git a/lib/gitlab/metrics/samplers/base_sampler.rb b/lib/gitlab/metrics/samplers/base_sampler.rb
index b2a9de21145..e62a62a935e 100644
--- a/lib/gitlab/metrics/samplers/base_sampler.rb
+++ b/lib/gitlab/metrics/samplers/base_sampler.rb
@@ -46,11 +46,11 @@ module Gitlab
# 2. Don't sample data at the same interval two times in a row.
def sleep_interval
while step = @interval_steps.sample
- if step != @last_step
- @last_step = step
+ next if step == @last_step
- return @interval + @last_step
- end
+ @last_step = step
+
+ return @interval + @last_step
end
end
diff --git a/lib/gitlab/metrics/samplers/ruby_sampler.rb b/lib/gitlab/metrics/samplers/ruby_sampler.rb
index 4fe338ffc7f..5a7ca6b6c04 100644
--- a/lib/gitlab/metrics/samplers/ruby_sampler.rb
+++ b/lib/gitlab/metrics/samplers/ruby_sampler.rb
@@ -35,6 +35,8 @@ module Gitlab
process_cpu_seconds_total: ::Gitlab::Metrics.gauge(metric_name(:process, :cpu_seconds_total), 'Process CPU seconds total'),
process_max_fds: ::Gitlab::Metrics.gauge(metric_name(:process, :max_fds), 'Process max fds'),
process_resident_memory_bytes: ::Gitlab::Metrics.gauge(metric_name(:process, :resident_memory_bytes), 'Memory used (RSS)', labels),
+ process_resident_anon_memory_bytes: ::Gitlab::Metrics.gauge(metric_name(:process, :resident_anon_memory_bytes), 'Anonymous memory used (RSS)', labels),
+ process_resident_file_memory_bytes: ::Gitlab::Metrics.gauge(metric_name(:process, :resident_file_memory_bytes), 'File backed memory used (RSS)', labels),
process_unique_memory_bytes: ::Gitlab::Metrics.gauge(metric_name(:process, :unique_memory_bytes), 'Memory used (USS)', labels),
process_proportional_memory_bytes: ::Gitlab::Metrics.gauge(metric_name(:process, :proportional_memory_bytes), 'Memory used (PSS)', labels),
process_start_time_seconds: ::Gitlab::Metrics.gauge(metric_name(:process, :start_time_seconds), 'Process start time seconds'),
@@ -95,7 +97,10 @@ module Gitlab
end
def set_memory_usage_metrics
- metrics[:process_resident_memory_bytes].set(labels, System.memory_usage_rss)
+ rss = System.memory_usage_rss
+ metrics[:process_resident_memory_bytes].set(labels, rss[:total])
+ metrics[:process_resident_anon_memory_bytes].set(labels, rss[:anon])
+ metrics[:process_resident_file_memory_bytes].set(labels, rss[:file])
if Gitlab::Utils.to_boolean(ENV['enable_memory_uss_pss'] || '1')
memory_uss_pss = System.memory_usage_uss_pss
diff --git a/lib/gitlab/metrics/system.rb b/lib/gitlab/metrics/system.rb
index affadc4274c..9b0ae84dec2 100644
--- a/lib/gitlab/metrics/system.rb
+++ b/lib/gitlab/metrics/system.rb
@@ -18,7 +18,9 @@ module Gitlab
PRIVATE_PAGES_PATTERN = /^(Private_Clean|Private_Dirty|Private_Hugetlb):\s+(?<value>\d+)/.freeze
PSS_PATTERN = /^Pss:\s+(?<value>\d+)/.freeze
- RSS_PATTERN = /VmRSS:\s+(?<value>\d+)/.freeze
+ RSS_TOTAL_PATTERN = /^VmRSS:\s+(?<value>\d+)/.freeze
+ RSS_ANON_PATTERN = /^RssAnon:\s+(?<value>\d+)/.freeze
+ RSS_FILE_PATTERN = /^RssFile:\s+(?<value>\d+)/.freeze
MAX_OPEN_FILES_PATTERN = /Max open files\s*(?<value>\d+)/.freeze
MEM_TOTAL_PATTERN = /^MemTotal:\s+(?<value>\d+) (.+)/.freeze
@@ -27,7 +29,7 @@ module Gitlab
{
version: RUBY_DESCRIPTION,
gc_stat: GC.stat,
- memory_rss: memory_usage_rss,
+ memory_rss: memory_usage_rss[:total],
memory_uss: proportional_mem[:uss],
memory_pss: proportional_mem[:pss],
time_cputime: cpu_time,
@@ -38,7 +40,21 @@ module Gitlab
# Returns the given process' RSS (resident set size) in bytes.
def memory_usage_rss(pid: 'self')
- sum_matches(PROC_STATUS_PATH % pid, rss: RSS_PATTERN)[:rss].kilobytes
+ results = { total: 0, anon: 0, file: 0 }
+
+ safe_yield_procfile(PROC_STATUS_PATH % pid) do |io|
+ io.each_line do |line|
+ if (value = parse_metric_value(line, RSS_TOTAL_PATTERN)) > 0
+ results[:total] = value.kilobytes
+ elsif (value = parse_metric_value(line, RSS_ANON_PATTERN)) > 0
+ results[:anon] = value.kilobytes
+ elsif (value = parse_metric_value(line, RSS_FILE_PATTERN)) > 0
+ results[:file] = value.kilobytes
+ end
+ end
+ end
+
+ results
end
# Returns the given process' USS/PSS (unique/proportional set size) in bytes.
@@ -115,9 +131,7 @@ module Gitlab
safe_yield_procfile(proc_file) do |io|
io.each_line do |line|
patterns.each do |metric, pattern|
- match = line.match(pattern)
- value = match&.named_captures&.fetch('value', 0)
- results[metric] += value.to_i
+ results[metric] += parse_metric_value(line, pattern)
end
end
end
@@ -125,6 +139,13 @@ module Gitlab
results
end
+ def parse_metric_value(line, pattern)
+ match = line.match(pattern)
+ return 0 unless match
+
+ match.named_captures.fetch('value', 0).to_i
+ end
+
def proc_stat_entries
safe_yield_procfile(PROC_STAT_PATH) do |io|
io.read.split(' ')
diff --git a/lib/gitlab/nav/top_nav_view_model_builder.rb b/lib/gitlab/nav/top_nav_view_model_builder.rb
index a8e25708107..8cb2729ff61 100644
--- a/lib/gitlab/nav/top_nav_view_model_builder.rb
+++ b/lib/gitlab/nav/top_nav_view_model_builder.rb
@@ -42,13 +42,10 @@ module Gitlab
def build
menu = @menu_builder.build
- hide_menu_text = Feature.enabled?(:new_navbar_layout)
-
menu.merge({
views: @views,
shortcuts: @shortcuts,
- menuTitle: (_('Menu') unless hide_menu_text),
- menuTooltip: (_('Main menu') if hide_menu_text)
+ menuTooltip: _('Main menu')
}.compact)
end
end
diff --git a/lib/gitlab/observability.rb b/lib/gitlab/observability.rb
new file mode 100644
index 00000000000..8dde60a73be
--- /dev/null
+++ b/lib/gitlab/observability.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Observability
+ module_function
+
+ 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
+ return 'https://observe.staging.gitlab.com' if Gitlab.staging?
+
+ 'https://observe.gitlab.com'
+ end
+ end
+end
diff --git a/lib/gitlab/octokit/middleware.rb b/lib/gitlab/octokit/middleware.rb
index a3c0fdcf467..a92860f7eb8 100644
--- a/lib/gitlab/octokit/middleware.rb
+++ b/lib/gitlab/octokit/middleware.rb
@@ -8,7 +8,11 @@ module Gitlab
end
def call(env)
- Gitlab::UrlBlocker.validate!(env[:url], allow_localhost: allow_local_requests?, allow_local_network: allow_local_requests?)
+ Gitlab::UrlBlocker.validate!(env[:url],
+ schemes: %w[http https],
+ allow_localhost: allow_local_requests?,
+ allow_local_network: allow_local_requests?
+ )
@app.call(env)
end
diff --git a/lib/gitlab/pagination/gitaly_keyset_pager.rb b/lib/gitlab/pagination/gitaly_keyset_pager.rb
index d4de2791195..6235874132f 100644
--- a/lib/gitlab/pagination/gitaly_keyset_pager.rb
+++ b/lib/gitlab/pagination/gitaly_keyset_pager.rb
@@ -35,11 +35,12 @@ module Gitlab
def keyset_pagination_enabled?(finder)
return false unless params[:pagination] == "keyset"
- if finder.is_a?(BranchesFinder)
+ case finder
+ when BranchesFinder
Feature.enabled?(:branch_list_keyset_pagination, project)
- elsif finder.is_a?(TagsFinder)
+ when TagsFinder
true
- elsif finder.is_a?(::Repositories::TreeFinder)
+ when ::Repositories::TreeFinder
Feature.enabled?(:repository_tree_gitaly_pagination, project)
else
false
@@ -49,11 +50,12 @@ module Gitlab
def paginate_first_page?(finder)
return false unless params[:page].blank? || params[:page].to_i == 1
- if finder.is_a?(BranchesFinder)
+ case finder
+ when BranchesFinder
Feature.enabled?(:branch_list_keyset_pagination, project)
- elsif finder.is_a?(TagsFinder)
+ when TagsFinder
true
- elsif finder.is_a?(::Repositories::TreeFinder)
+ when ::Repositories::TreeFinder
Feature.enabled?(:repository_tree_gitaly_pagination, project)
else
false
diff --git a/lib/gitlab/pagination/keyset/in_operator_optimization/strategies/record_loader_strategy.rb b/lib/gitlab/pagination/keyset/in_operator_optimization/strategies/record_loader_strategy.rb
index 51f38c1da58..4f79a3593f4 100644
--- a/lib/gitlab/pagination/keyset/in_operator_optimization/strategies/record_loader_strategy.rb
+++ b/lib/gitlab/pagination/keyset/in_operator_optimization/strategies/record_loader_strategy.rb
@@ -39,15 +39,15 @@ module Gitlab
def verify_order_by_attributes_on_model!(model, order_by_columns)
order_by_columns.map(&:column).each do |column|
- unless model.columns_hash[column.attribute_name.to_s]
- text = <<~TEXT
+ next if model.columns_hash[column.attribute_name.to_s]
+
+ text = <<~TEXT
The "RecordLoaderStrategy" does not support the following ORDER BY column because
it's not available on the \"#{model.table_name}\" table: #{column.attribute_name}
Omit the "finder_query" parameter to use the "OrderValuesLoaderStrategy".
- TEXT
- raise text
- end
+ TEXT
+ raise text
end
end
end
diff --git a/lib/gitlab/pagination_delegate.rb b/lib/gitlab/pagination_delegate.rb
new file mode 100644
index 00000000000..05aaff5bbfc
--- /dev/null
+++ b/lib/gitlab/pagination_delegate.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+module Gitlab
+ class PaginationDelegate # rubocop:disable Gitlab/NamespacedClass
+ DEFAULT_PER_PAGE = Kaminari.config.default_per_page
+ MAX_PER_PAGE = Kaminari.config.max_per_page
+
+ def initialize(page:, per_page:, count:, options: {})
+ @count = count
+ @options = { default_per_page: DEFAULT_PER_PAGE,
+ max_per_page: MAX_PER_PAGE }.merge(options)
+
+ @per_page = sanitize_per_page(per_page)
+ @page = sanitize_page(page)
+ end
+
+ def total_count
+ @count
+ end
+
+ def total_pages
+ (total_count.to_f / @per_page).ceil
+ end
+
+ def next_page
+ current_page + 1 unless last_page?
+ end
+
+ def prev_page
+ current_page - 1 unless first_page?
+ end
+
+ def current_page
+ @page
+ end
+
+ def limit_value
+ @per_page
+ end
+
+ def first_page?
+ current_page == 1
+ end
+
+ def last_page?
+ current_page >= total_pages
+ end
+
+ def offset
+ (current_page - 1) * limit_value
+ end
+
+ private
+
+ def sanitize_per_page(per_page)
+ return @options[:default_per_page] unless per_page && per_page > 0
+
+ [@options[:max_per_page], per_page].min
+ end
+
+ def sanitize_page(page)
+ return 1 unless page && page > 1
+
+ [total_pages, page].min
+ end
+ end
+end
diff --git a/lib/gitlab/patch/sidekiq_cron_poller.rb b/lib/gitlab/patch/sidekiq_cron_poller.rb
new file mode 100644
index 00000000000..c9eae2f899f
--- /dev/null
+++ b/lib/gitlab/patch/sidekiq_cron_poller.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+# Patch to address https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1932
+# It restores the behavior of `poll_internal_average` to the one from Sidekiq 6.5.7
+# when the cron poll interval is not configured.
+# (see https://github.com/mperham/sidekiq/blob/v6.5.7/lib/sidekiq/scheduled.rb#L176-L178)
+require 'sidekiq/version'
+require 'sidekiq/cron/version'
+
+if Gem::Version.new(Sidekiq::VERSION) != Gem::Version.new('6.5.7')
+ raise 'New version of sidekiq detected, please remove or update this patch'
+end
+
+if Gem::Version.new(Sidekiq::Cron::VERSION) != Gem::Version.new('1.8.0')
+ raise 'New version of sidekiq-cron detected, please remove or update this patch'
+end
+
+module Gitlab
+ module Patch
+ module SidekiqCronPoller
+ def poll_interval_average(count)
+ Gitlab.config.cron_jobs.poll_interval || @config[:poll_interval_average] || scaled_poll_interval(count) # rubocop:disable Gitlab/ModuleWithInstanceVariables
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled.rb b/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled.rb
index fbc77113875..79c00a48336 100644
--- a/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled.rb
+++ b/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled.rb
@@ -19,7 +19,7 @@ module Gitlab
def enqueue_stats_job(request_id)
return unless Feature.enabled?(:performance_bar_stats, type: :ops)
- @client.sadd(GitlabPerformanceBarStatsWorker::STATS_KEY, request_id)
+ @client.sadd?(GitlabPerformanceBarStatsWorker::STATS_KEY, request_id)
return unless uuid = Gitlab::ExclusiveLease.new(
GitlabPerformanceBarStatsWorker::LEASE_KEY,
diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb
index fb9447f9665..8cc96970ebd 100644
--- a/lib/gitlab/project_search_results.rb
+++ b/lib/gitlab/project_search_results.rb
@@ -117,7 +117,7 @@ module Gitlab
end
def blobs(limit: count_limit)
- return [] unless Ability.allowed?(@current_user, :download_code, @project)
+ return [] unless Ability.allowed?(@current_user, :read_code, @project)
@blobs ||= Gitlab::FileFinder.new(project, repository_project_ref).find(query, content_match_cutoff: limit)
end
@@ -153,7 +153,7 @@ module Gitlab
end
def find_commits(query, limit:)
- return [] unless Ability.allowed?(@current_user, :download_code, @project)
+ return [] unless Ability.allowed?(@current_user, :read_code, @project)
commits = find_commits_by_message(query, limit: limit)
commit_by_sha = find_commit_by_sha(query)
diff --git a/lib/gitlab/project_template.rb b/lib/gitlab/project_template.rb
index 6673940ccf3..51a5bedc44b 100644
--- a/lib/gitlab/project_template.rb
+++ b/lib/gitlab/project_template.rb
@@ -28,6 +28,14 @@ module Gitlab
"#{preview}.git"
end
+ def project_host
+ return unless preview
+
+ uri = URI.parse(preview)
+ uri.path = ""
+ uri.to_s
+ end
+
def project_path
URI.parse(preview).path.delete_prefix('/')
end
diff --git a/lib/gitlab/qa.rb b/lib/gitlab/qa.rb
new file mode 100644
index 00000000000..c47a8982901
--- /dev/null
+++ b/lib/gitlab/qa.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Qa
+ def self.user_agent
+ ENV['GITLAB_QA_USER_AGENT']
+ end
+
+ def self.request?(request_user_agent)
+ return false unless Gitlab.com?
+ return false unless request_user_agent.present?
+ return false unless user_agent.present?
+
+ ActiveSupport::SecurityUtils.secure_compare(request_user_agent, user_agent)
+ end
+ end
+end
diff --git a/lib/gitlab/query_limiting/transaction.rb b/lib/gitlab/query_limiting/transaction.rb
index 46c0a0ddf7a..498da38e268 100644
--- a/lib/gitlab/query_limiting/transaction.rb
+++ b/lib/gitlab/query_limiting/transaction.rb
@@ -68,14 +68,14 @@ module Gitlab
GEO_NODES_LOAD = 'SELECT 1 AS one FROM "geo_nodes" LIMIT 1'
LICENSES_LOAD = 'SELECT "licenses".* FROM "licenses" ORDER BY "licenses"."id"'
- ATTR_INTROSPECTION = %r/SELECT .*\ba.attname\b.* (FROM|JOIN) pg_attribute a/m.freeze
+ SCHEMA_INTROSPECTION = %r/SELECT.*(FROM|JOIN) (pg_attribute|pg_class)/m.freeze
# queries can be safely ignored if they are amoritized in regular usage
# (i.e. only requested occasionally and otherwise cached).
def ignorable?(sql)
return true if sql&.include?(GEO_NODES_LOAD)
return true if sql&.include?(LICENSES_LOAD)
- return true if ATTR_INTROSPECTION =~ sql
+ return true if SCHEMA_INTROSPECTION.match?(sql)
false
end
diff --git a/lib/gitlab/quick_actions/issuable_actions.rb b/lib/gitlab/quick_actions/issuable_actions.rb
index 3b85d6952a1..0b37c80dc5f 100644
--- a/lib/gitlab/quick_actions/issuable_actions.rb
+++ b/lib/gitlab/quick_actions/issuable_actions.rb
@@ -12,16 +12,13 @@ module Gitlab
included do
# Issue, MergeRequest, Epic: quick actions definitions
desc do
- _('Close this %{quick_action_target}') %
- { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
+ _('Close this %{quick_action_target}') % { quick_action_target: target_issuable_name }
end
explanation do
- _('Closes this %{quick_action_target}.') %
- { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
+ _('Closes this %{quick_action_target}.') % { quick_action_target: target_issuable_name }
end
execution_message do
- _('Closed this %{quick_action_target}.') %
- { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
+ _('Closed this %{quick_action_target}.') % { quick_action_target: target_issuable_name }
end
types ::Issuable
condition do
@@ -35,15 +32,15 @@ module Gitlab
desc do
_('Reopen this %{quick_action_target}') %
- { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
+ { quick_action_target: target_issuable_name }
end
explanation do
_('Reopens this %{quick_action_target}.') %
- { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
+ { quick_action_target: target_issuable_name }
end
execution_message do
_('Reopened this %{quick_action_target}.') %
- { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
+ { quick_action_target: target_issuable_name }
end
types ::Issuable
condition do
@@ -170,12 +167,10 @@ module Gitlab
desc { _('Subscribe') }
explanation do
- _('Subscribes to this %{quick_action_target}.') %
- { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
+ _('Subscribes to this %{quick_action_target}.') % { quick_action_target: target_issuable_name }
end
execution_message do
- _('Subscribed to this %{quick_action_target}.') %
- { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
+ _('Subscribed to this %{quick_action_target}.') % { quick_action_target: target_issuable_name }
end
types ::Issuable
condition do
@@ -188,12 +183,10 @@ module Gitlab
desc { _('Unsubscribe') }
explanation do
- _('Unsubscribes from this %{quick_action_target}.') %
- { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
+ _('Unsubscribes from this %{quick_action_target}.') % { quick_action_target: target_issuable_name }
end
execution_message do
- _('Unsubscribed from this %{quick_action_target}.') %
- { quick_action_target: quick_action_target.to_ability_name.humanize(capitalize: false) }
+ _('Unsubscribed from this %{quick_action_target}.') % { quick_action_target: target_issuable_name }
end
types ::Issuable
condition do
@@ -266,6 +259,16 @@ module Gitlab
end
end
+ desc { _("Make %{type} confidential") % { type: target_issuable_name } }
+ explanation { _("Makes this %{type} confidential.") % { type: target_issuable_name } }
+ types ::Issuable
+ condition { quick_action_target.supports_confidentiality? && can_make_confidential? }
+ command :confidential do
+ @updates[:confidential] = true
+
+ @execution_message[:confidential] = confidential_execution_message
+ end
+
private
def find_severity(severity_param)
@@ -315,6 +318,29 @@ module Gitlab
_('Removed all labels.')
end
end
+
+ def target_issuable_name
+ quick_action_target.to_ability_name.humanize(capitalize: false)
+ end
+
+ def can_make_confidential?
+ confidentiality_not_supported = quick_action_target.respond_to?(:issue_type_supports?) &&
+ !quick_action_target.issue_type_supports?(:confidentiality)
+
+ return false if confidentiality_not_supported
+
+ !quick_action_target.confidential? && current_user.can?(:set_confidentiality, quick_action_target)
+ end
+
+ def confidential_execution_message
+ confidential_error_message.presence || _("Made this %{type} confidential.") % { type: target_issuable_name }
+ end
+
+ def confidential_error_message
+ return unless quick_action_target.respond_to?(:confidentiality_errors)
+
+ quick_action_target.confidentiality_errors.join("\n")
+ end
end
end
end
diff --git a/lib/gitlab/quick_actions/issue_actions.rb b/lib/gitlab/quick_actions/issue_actions.rb
index 4883c649a62..e74c58e45b1 100644
--- a/lib/gitlab/quick_actions/issue_actions.rb
+++ b/lib/gitlab/quick_actions/issue_actions.rb
@@ -161,23 +161,6 @@ module Gitlab
@execution_message[:move] = message
end
- desc { _('Make issue confidential') }
- explanation do
- _('Makes this issue confidential.')
- end
- execution_message do
- _('Made this issue confidential.')
- end
- types Issue
- condition do
- quick_action_target.issue_type_supports?(:confidentiality) &&
- !quick_action_target.confidential? &&
- current_user.can?(:set_confidentiality, quick_action_target)
- end
- command :confidential do
- @updates[:confidential] = true
- end
-
desc { _('Create a merge request') }
explanation do |branch_name = nil|
if branch_name
diff --git a/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb b/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb
index a0faf8dd460..8b1ff5d298a 100644
--- a/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb
+++ b/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb
@@ -161,7 +161,7 @@ module Gitlab
parse_params do |raw_duration|
Gitlab::TimeTrackingFormatter.parse(raw_duration)
end
- command :estimate do |time_estimate|
+ command :estimate, :estimate_time do |time_estimate|
if time_estimate
@updates[:time_estimate] = time_estimate
end
@@ -184,7 +184,7 @@ module Gitlab
parse_params do |raw_time_date|
Gitlab::QuickActions::SpendTimeAndDateSeparator.new(raw_time_date).execute
end
- command :spend, :spent do |time_spent, time_spent_date|
+ command :spend, :spent, :spend_time do |time_spent, time_spent_date|
if time_spent
@updates[:spend_time] = {
duration: time_spent,
@@ -202,7 +202,7 @@ module Gitlab
quick_action_target.persisted? &&
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
end
- command :remove_estimate do
+ command :remove_estimate, :remove_time_estimate do
@updates[:time_estimate] = 0
end
diff --git a/lib/gitlab/redis/multi_store.rb b/lib/gitlab/redis/multi_store.rb
index a7c36786d2d..12cb1fc6153 100644
--- a/lib/gitlab/redis/multi_store.rb
+++ b/lib/gitlab/redis/multi_store.rb
@@ -52,6 +52,7 @@ module Gitlab
del
flushdb
rpush
+ eval
).freeze
PIPELINED_COMMANDS = %i(
diff --git a/lib/gitlab/reference_extractor.rb b/lib/gitlab/reference_extractor.rb
index f914123a94d..c5798bec0d7 100644
--- a/lib/gitlab/reference_extractor.rb
+++ b/lib/gitlab/reference_extractor.rb
@@ -42,10 +42,10 @@ module Gitlab
@references[type] ||= references(type)
end
- if %w(mentioned_user mentioned_group mentioned_project).include?(type.to_s)
- define_method("#{type}_ids") do
- @references[type] ||= references(type, ids_only: true)
- end
+ next unless %w(mentioned_user mentioned_group mentioned_project).include?(type.to_s)
+
+ define_method("#{type}_ids") do
+ @references[type] ||= references(type, ids_only: true)
end
end
diff --git a/lib/gitlab/request_forgery_protection.rb b/lib/gitlab/request_forgery_protection.rb
index 258c904290d..d5e80053772 100644
--- a/lib/gitlab/request_forgery_protection.rb
+++ b/lib/gitlab/request_forgery_protection.rb
@@ -10,6 +10,14 @@ module Gitlab
class Controller < ActionController::Base
protect_from_forgery with: :exception, prepend: true
+ def initialize
+ super
+
+ # Squelch noisy and unnecessary "Can't verify CSRF token authenticity." messages.
+ # X-Csrf-Token is only one authentication mechanism for API helpers.
+ self.logger = ActiveSupport::Logger.new(File::NULL)
+ end
+
def index
head :ok
end
diff --git a/lib/gitlab/runtime.rb b/lib/gitlab/runtime.rb
index 6d95cb9a87b..7e9fb82fb8b 100644
--- a/lib/gitlab/runtime.rb
+++ b/lib/gitlab/runtime.rb
@@ -42,7 +42,7 @@ module Gitlab
end
def sidekiq?
- !!(defined?(::Sidekiq) && Sidekiq.server?)
+ !!(defined?(::Sidekiq) && Sidekiq.try(:server?))
end
def rake?
@@ -94,7 +94,7 @@ module Gitlab
#
# These threads execute Sidekiq client middleware when jobs
# are enqueued and those can access DB / Redis.
- threads += Sidekiq.options[:concurrency] + 2
+ threads += Sidekiq[:concurrency] + 2
end
if puma?
diff --git a/lib/gitlab/search/recent_items.rb b/lib/gitlab/search/recent_items.rb
index 593148025e1..7a16b5dfc87 100644
--- a/lib/gitlab/search/recent_items.rb
+++ b/lib/gitlab/search/recent_items.rb
@@ -33,7 +33,7 @@ module Gitlab
end
def search(term)
- finder.new(user, search: term, in: 'title')
+ finder.new(user, search: term, in: 'title', skip_full_text_search_project_condition: true)
.execute
.limit(SEARCH_LIMIT).reorder(nil).id_in_ordered(latest_ids) # rubocop: disable CodeReuse/ActiveRecord
end
diff --git a/lib/gitlab/service_desk_email.rb b/lib/gitlab/service_desk_email.rb
index 14f07140825..bc49efafdda 100644
--- a/lib/gitlab/service_desk_email.rb
+++ b/lib/gitlab/service_desk_email.rb
@@ -3,8 +3,10 @@
module Gitlab
module ServiceDeskEmail
class << self
- def enabled?
- !!config&.enabled && config&.address.present?
+ include Gitlab::Email::Common
+
+ def config
+ Gitlab.config.service_desk_email
end
def key_from_address(address)
@@ -14,20 +16,10 @@ module Gitlab
Gitlab::IncomingEmail.key_from_address(address, wildcard_address: wildcard_address)
end
- def config
- Gitlab.config.service_desk_email
- end
-
def address_for_key(key)
return if config.address.blank?
- config.address.sub(Gitlab::IncomingEmail::WILDCARD_PLACEHOLDER, key)
- end
-
- def key_from_fallback_message_id(mail_id)
- message_id_regexp = /\Areply\-(.+)@#{Gitlab.config.gitlab.host}\z/
-
- mail_id[message_id_regexp, 1]
+ config.address.sub(WILDCARD_PLACEHOLDER, key)
end
end
end
diff --git a/lib/gitlab/set_cache.rb b/lib/gitlab/set_cache.rb
index c7818cb3418..3d2ff5a68d2 100644
--- a/lib/gitlab/set_cache.rb
+++ b/lib/gitlab/set_cache.rb
@@ -34,7 +34,7 @@ module Gitlab
def write(key, value)
with do |redis|
redis.pipelined do |pipeline|
- pipeline.sadd(cache_key(key), value)
+ pipeline.sadd?(cache_key(key), value)
pipeline.expire(cache_key(key), expires_in)
end
diff --git a/lib/gitlab/shard_health_cache.rb b/lib/gitlab/shard_health_cache.rb
index eeb0cc75ef9..a34e4e9c8d1 100644
--- a/lib/gitlab/shard_health_cache.rb
+++ b/lib/gitlab/shard_health_cache.rb
@@ -7,17 +7,17 @@ module Gitlab
# Clears the Redis set storing the list of healthy shards
def self.clear
- Gitlab::Redis::Cache.with { |redis| redis.del(HEALTHY_SHARDS_KEY) }
+ with_redis { |redis| redis.del(HEALTHY_SHARDS_KEY) }
end
# Updates the list of healthy shards using a Redis set
#
# shards - An array of shard names to store
def self.update(shards)
- Gitlab::Redis::Cache.with do |redis|
+ with_redis do |redis|
redis.multi do |m|
m.del(HEALTHY_SHARDS_KEY)
- shards.each { |shard_name| m.sadd(HEALTHY_SHARDS_KEY, shard_name) }
+ m.sadd(HEALTHY_SHARDS_KEY, shards) unless shards.blank?
m.expire(HEALTHY_SHARDS_KEY, HEALTHY_SHARDS_TIMEOUT)
end
end
@@ -25,19 +25,23 @@ module Gitlab
# Returns an array of strings of healthy shards
def self.cached_healthy_shards
- Gitlab::Redis::Cache.with { |redis| redis.smembers(HEALTHY_SHARDS_KEY) }
+ with_redis { |redis| redis.smembers(HEALTHY_SHARDS_KEY) }
end
# Checks whether the given shard name is in the list of healthy shards.
#
# shard_name - The string to check
def self.healthy_shard?(shard_name)
- Gitlab::Redis::Cache.with { |redis| redis.sismember(HEALTHY_SHARDS_KEY, shard_name) }
+ with_redis { |redis| redis.sismember(HEALTHY_SHARDS_KEY, shard_name) }
end
# Returns the number of healthy shards in the Redis set
def self.healthy_shard_count
- Gitlab::Redis::Cache.with { |redis| redis.scard(HEALTHY_SHARDS_KEY) }
+ with_redis { |redis| redis.scard(HEALTHY_SHARDS_KEY) }
+ end
+
+ def self.with_redis(&block)
+ Gitlab::Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord
end
end
end
diff --git a/lib/gitlab/shell.rb b/lib/gitlab/shell.rb
index b167afe589a..bc59d4ce943 100644
--- a/lib/gitlab/shell.rb
+++ b/lib/gitlab/shell.rb
@@ -14,6 +14,11 @@ module Gitlab
class Shell
Error = Class.new(StandardError)
+ PERMITTED_ACTIONS = %w[
+ mv_repository remove_repository add_namespace rm_namespace mv_namespace
+ repository_exists?
+ ].freeze
+
class << self
# Retrieve GitLab Shell secret token
#
diff --git a/lib/gitlab/sidekiq_config.rb b/lib/gitlab/sidekiq_config.rb
index 3e7bdfbe89a..7e2a934b3dd 100644
--- a/lib/gitlab/sidekiq_config.rb
+++ b/lib/gitlab/sidekiq_config.rb
@@ -162,7 +162,7 @@ module Gitlab
# the current Sidekiq process
def current_worker_queue_mappings
worker_queue_mappings
- .select { |worker, queue| Sidekiq.options[:queues].include?(queue) }
+ .select { |worker, queue| Sidekiq[:queues].include?(queue) }
.to_h
end
diff --git a/lib/gitlab/sidekiq_daemon/memory_killer.rb b/lib/gitlab/sidekiq_daemon/memory_killer.rb
index b8f86b92844..d5227e7a007 100644
--- a/lib/gitlab/sidekiq_daemon/memory_killer.rb
+++ b/lib/gitlab/sidekiq_daemon/memory_killer.rb
@@ -118,9 +118,9 @@ module Gitlab
return unless enabled?
# Tell sidekiq to restart itself
- # Keep extra safe to wait `Sidekiq.options[:timeout] + 2` seconds before SIGKILL
+ # Keep extra safe to wait `Sidekiq[:timeout] + 2` seconds before SIGKILL
refresh_state(:shutting_down)
- signal_and_wait(Sidekiq.options[:timeout] + 2, 'SIGTERM', 'gracefully shut down')
+ signal_and_wait(Sidekiq[:timeout] + 2, 'SIGTERM', 'gracefully shut down')
return unless enabled?
# Ideally we should never reach this condition
@@ -221,7 +221,7 @@ module Gitlab
end
def get_rss_kb
- Gitlab::Metrics::System.memory_usage_rss / 1.kilobytes
+ Gitlab::Metrics::System.memory_usage_rss[:total] / 1.kilobytes
end
def get_soft_limit_rss_kb
diff --git a/lib/gitlab/sidekiq_middleware/arguments_logger.rb b/lib/gitlab/sidekiq_middleware/arguments_logger.rb
index fe5213fc5d7..2c506786d83 100644
--- a/lib/gitlab/sidekiq_middleware/arguments_logger.rb
+++ b/lib/gitlab/sidekiq_middleware/arguments_logger.rb
@@ -3,8 +3,10 @@
module Gitlab
module SidekiqMiddleware
class ArgumentsLogger
+ include Sidekiq::ServerMiddleware
+
def call(worker, job, queue)
- Sidekiq.logger.info "arguments: #{Gitlab::Json.dump(job['args'])}"
+ logger.info "arguments: #{Gitlab::Json.dump(job['args'])}"
yield
end
end
diff --git a/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb b/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb
index d42bd672bac..357e9d41187 100644
--- a/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb
+++ b/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'digest'
+require 'msgpack'
module Gitlab
module SidekiqMiddleware
@@ -20,23 +21,8 @@ module Gitlab
include Gitlab::Utils::StrongMemoize
DEFAULT_DUPLICATE_KEY_TTL = 6.hours
- WAL_LOCATION_TTL = 60.seconds
- MAX_REDIS_RETRIES = 5
DEFAULT_STRATEGY = :until_executing
STRATEGY_NONE = :none
- DEDUPLICATED_FLAG_VALUE = 1
-
- LUA_SET_WAL_SCRIPT = <<~EOS
- local key, wal, offset, ttl = KEYS[1], ARGV[1], tonumber(ARGV[2]), ARGV[3]
- local existing_offset = redis.call("LINDEX", key, -1)
- if existing_offset == false then
- redis.call("RPUSH", key, wal, offset)
- redis.call("EXPIRE", key, ttl)
- elseif offset > tonumber(existing_offset) then
- redis.call("LSET", key, 0, wal)
- redis.call("LSET", key, -1, offset)
- end
- EOS
attr_reader :existing_jid
@@ -60,66 +46,76 @@ module Gitlab
# This method will return the jid that was set in redis
def check!(expiry = duplicate_key_ttl)
- read_jid = nil
- read_wal_locations = {}
-
- with_redis do |redis|
- redis.multi do |multi|
- multi.set(idempotency_key, jid, ex: expiry, nx: true)
- read_wal_locations = check_existing_wal_locations!(multi, expiry)
- read_jid = multi.get(idempotency_key)
- end
+ my_cookie = {
+ 'jid' => jid,
+ 'offsets' => {},
+ 'wal_locations' => {},
+ 'existing_wal_locations' => job_wal_locations
+ }
+
+ # There are 3 possible scenarios. In order of decreasing likelyhood:
+ # 1. SET NX succeeds.
+ # 2. SET NX fails, GET succeeds.
+ # 3. SET NX fails, the key expires and GET fails. In this case we must retry.
+ actual_cookie = {}
+ while actual_cookie.empty?
+ set_succeeded = with_redis { |r| r.set(cookie_key, my_cookie.to_msgpack, nx: true, ex: expiry) }
+ actual_cookie = set_succeeded ? my_cookie : get_cookie
end
job['idempotency_key'] = idempotency_key
- # We need to fetch values since the read_wal_locations and read_jid were obtained inside transaction, under redis.multi command.
- self.existing_wal_locations = read_wal_locations.transform_values(&:value)
- self.existing_jid = read_jid.value
+ self.existing_wal_locations = actual_cookie['existing_wal_locations']
+ self.existing_jid = actual_cookie['jid']
end
def update_latest_wal_location!
return unless job_wal_locations.present?
- with_redis do |redis|
- redis.multi do |multi|
- job_wal_locations.each do |connection_name, location|
- multi.eval(
- LUA_SET_WAL_SCRIPT,
- keys: [wal_location_key(connection_name)],
- argv: [location, pg_wal_lsn_diff(connection_name).to_i, WAL_LOCATION_TTL]
- )
- end
- end
+ argv = []
+ job_wal_locations.each do |connection_name, location|
+ argv += [connection_name, pg_wal_lsn_diff(connection_name), location]
end
+
+ with_redis { |r| r.eval(UPDATE_WAL_COOKIE_SCRIPT, keys: [cookie_key], argv: argv) }
end
+ # Generally speaking, updating a Redis key by deserializing and
+ # serializing it on the Redis server is bad for performance. However in
+ # the case of DuplicateJobs we know that key updates are rare, and the
+ # most common operations are setting, getting and deleting the key. The
+ # aim of this design is to make the common operations as fast as
+ # possible.
+ UPDATE_WAL_COOKIE_SCRIPT = <<~LUA
+ local cookie_msgpack = redis.call("get", KEYS[1])
+ if not cookie_msgpack then
+ return
+ end
+ local cookie = cmsgpack.unpack(cookie_msgpack)
+
+ for i = 1, #ARGV, 3 do
+ local connection = ARGV[i]
+ local current_offset = cookie.offsets[connection]
+ local new_offset = tonumber(ARGV[i+1])
+ if not current_offset or current_offset < new_offset then
+ cookie.offsets[connection] = new_offset
+ cookie.wal_locations[connection] = ARGV[i+2]
+ end
+ end
+
+ redis.call("set", KEYS[1], cmsgpack.pack(cookie), "ex", redis.call("ttl", KEYS[1]))
+ LUA
+
def latest_wal_locations
return {} unless job_wal_locations.present?
strong_memoize(:latest_wal_locations) do
- read_wal_locations = {}
-
- with_redis do |redis|
- redis.multi do |multi|
- job_wal_locations.keys.each do |connection_name|
- read_wal_locations[connection_name] = multi.lindex(wal_location_key(connection_name), 0)
- end
- end
- end
- read_wal_locations.transform_values(&:value).compact
+ get_cookie.fetch('wal_locations', {})
end
end
def delete!
- Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
- with_redis do |redis|
- redis.multi do |multi|
- multi.del(idempotency_key, deduplicated_flag_key)
- delete_wal_locations!(multi)
- end
- end
- end
+ with_redis { |redis| redis.del(cookie_key) }
end
def reschedule
@@ -141,17 +137,21 @@ module Gitlab
def set_deduplicated_flag!(expiry = duplicate_key_ttl)
return unless reschedulable?
- with_redis do |redis|
- redis.set(deduplicated_flag_key, DEDUPLICATED_FLAG_VALUE, ex: expiry, nx: true)
- end
+ with_redis { |redis| redis.eval(DEDUPLICATED_SCRIPT, keys: [cookie_key]) }
end
- def should_reschedule?
- return false unless reschedulable?
-
- with_redis do |redis|
- redis.get(deduplicated_flag_key).present?
+ DEDUPLICATED_SCRIPT = <<~LUA
+ local cookie_msgpack = redis.call("get", KEYS[1])
+ if not cookie_msgpack then
+ return
end
+ local cookie = cmsgpack.unpack(cookie_msgpack)
+ cookie.deduplicated = "1"
+ redis.call("set", KEYS[1], cmsgpack.pack(cookie), "ex", redis.call("ttl", KEYS[1]))
+ LUA
+
+ def should_reschedule?
+ reschedulable? && get_cookie['deduplicated'].present?
end
def scheduled_at
@@ -186,31 +186,12 @@ module Gitlab
@worker_klass ||= worker_class_name.to_s.safe_constantize
end
- def delete_wal_locations!(redis)
- job_wal_locations.keys.each do |connection_name|
- redis.del(wal_location_key(connection_name))
- redis.del(existing_wal_location_key(connection_name))
- end
- end
-
- def check_existing_wal_locations!(redis, expiry)
- read_wal_locations = {}
-
- job_wal_locations.each do |connection_name, location|
- key = existing_wal_location_key(connection_name)
- redis.set(key, location, ex: expiry, nx: true)
- read_wal_locations[connection_name] = redis.get(key)
- end
-
- read_wal_locations
- end
-
def job_wal_locations
job['wal_locations'] || {}
end
def pg_wal_lsn_diff(connection_name)
- model = Gitlab::Database.database_base_models[connection_name]
+ model = Gitlab::Database.database_base_models[connection_name.to_sym]
model.connection.load_balancer.wal_diff(
job_wal_locations[connection_name],
@@ -238,22 +219,18 @@ module Gitlab
job['jid']
end
- def existing_wal_location_key(connection_name)
- "#{idempotency_key}:#{connection_name}:existing_wal_location"
+ def cookie_key
+ "#{idempotency_key}:cookie:v2"
end
- def wal_location_key(connection_name)
- "#{idempotency_key}:#{connection_name}:wal_location"
+ def get_cookie
+ with_redis { |redis| MessagePack.unpack(redis.get(cookie_key) || "\x80") }
end
def idempotency_key
@idempotency_key ||= job['idempotency_key'] || "#{namespace}:#{idempotency_hash}"
end
- def deduplicated_flag_key
- "#{idempotency_key}:deduplicate_flag"
- end
-
def idempotency_hash
Digest::SHA256.hexdigest(idempotency_string)
end
diff --git a/lib/gitlab/sidekiq_middleware/retry_error.rb b/lib/gitlab/sidekiq_middleware/retry_error.rb
new file mode 100644
index 00000000000..372213a8e6a
--- /dev/null
+++ b/lib/gitlab/sidekiq_middleware/retry_error.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module SidekiqMiddleware
+ # Sidekiq retry error that won't be reported to Sentry
+ # Use it when a job retry is an expected behavior
+ RetryError = Class.new(StandardError)
+ end
+end
diff --git a/lib/gitlab/sidekiq_middleware/server_metrics.rb b/lib/gitlab/sidekiq_middleware/server_metrics.rb
index 3dd5355d3a3..e36f61be3b3 100644
--- a/lib/gitlab/sidekiq_middleware/server_metrics.rb
+++ b/lib/gitlab/sidekiq_middleware/server_metrics.rb
@@ -43,7 +43,7 @@ module Gitlab
def initialize_process_metrics
metrics = self.metrics
- metrics[:sidekiq_concurrency].set({}, Sidekiq.options[:concurrency].to_i)
+ metrics[:sidekiq_concurrency].set({}, Sidekiq[:concurrency].to_i)
return unless ::Feature.enabled?(:sidekiq_job_completion_metric_initialize)
diff --git a/lib/gitlab/sidekiq_middleware/size_limiter/compressor.rb b/lib/gitlab/sidekiq_middleware/size_limiter/compressor.rb
index bce295d8ba5..f7e0553e536 100644
--- a/lib/gitlab/sidekiq_middleware/size_limiter/compressor.rb
+++ b/lib/gitlab/sidekiq_middleware/size_limiter/compressor.rb
@@ -33,7 +33,7 @@ module Gitlab
validate_args!(job)
job.except!(ORIGINAL_SIZE_KEY, COMPRESSED_KEY)
- job['args'] = Sidekiq.load_json(Zlib::Inflate.inflate(Base64.strict_decode64(job['args'].first)))
+ job['args'] = Gitlab::Json.load(Zlib::Inflate.inflate(Base64.strict_decode64(job['args'].first)))
rescue Zlib::Error
raise PayloadDecompressionError, 'Fail to decompress Sidekiq job payload'
end
diff --git a/lib/gitlab/sidekiq_migrate_jobs.rb b/lib/gitlab/sidekiq_migrate_jobs.rb
index 62d62bf82c4..2467dd7ca43 100644
--- a/lib/gitlab/sidekiq_migrate_jobs.rb
+++ b/lib/gitlab/sidekiq_migrate_jobs.rb
@@ -3,16 +3,18 @@
module Gitlab
class SidekiqMigrateJobs
LOG_FREQUENCY = 1_000
+ LOG_FREQUENCY_QUEUES = 10
- attr_reader :sidekiq_set, :logger
+ attr_reader :logger, :mappings
- def initialize(sidekiq_set, logger: nil)
- @sidekiq_set = sidekiq_set
+ # mappings is a hash of WorkerClassName => target_queue_name
+ def initialize(mappings, logger: nil)
+ @mappings = mappings
@logger = logger
end
- # mappings is a hash of WorkerClassName => target_queue_name
- def execute(mappings)
+ # Migrate jobs in SortedSets, i.e. scheduled and retry sets.
+ def migrate_set(sidekiq_set)
source_queues_regex = Regexp.union(mappings.keys)
cursor = 0
scanned = 0
@@ -33,7 +35,7 @@ module Gitlab
next unless job.match?(source_queues_regex)
- job_hash = Sidekiq.load_json(job)
+ job_hash = Gitlab::Json.load(job)
destination_queue = mappings[job_hash['class']]
next unless mappings.has_key?(job_hash['class'])
@@ -41,7 +43,7 @@ module Gitlab
job_hash['queue'] = destination_queue
- migrated += migrate_job(job, score, job_hash)
+ migrated += migrate_job_in_set(sidekiq_set, job, score, job_hash)
end
end while cursor.to_i != 0
@@ -53,14 +55,54 @@ module Gitlab
}
end
+ # Migrates jobs from queues that are outside the mappings
+ def migrate_queues
+ routing_rules_queues = mappings.values.uniq
+ logger&.info("List of queues based on routing rules: #{routing_rules_queues}")
+ Sidekiq.redis do |conn|
+ # Redis 6 supports conn.scan_each(match: "queue:*", type: 'list')
+ conn.scan_each(match: "queue:*") do |key|
+ # Redis 5 compatibility
+ next unless conn.type(key) == 'list'
+
+ queue_from = key.split(':', 2).last
+ next if routing_rules_queues.include?(queue_from)
+
+ logger&.info("Migrating #{queue_from} queue")
+
+ migrated = 0
+ while queue_length(queue_from) > 0
+ begin
+ if migrated >= 0 && migrated % LOG_FREQUENCY_QUEUES == 0
+ logger&.info("Migrating from #{queue_from}. Total: #{queue_length(queue_from)}. Migrated: #{migrated}.")
+ end
+
+ job = conn.rpop "queue:#{queue_from}"
+ job_hash = Gitlab::Json.load(job)
+ next unless mappings.has_key?(job_hash['class'])
+
+ destination_queue = mappings[job_hash['class']]
+ job_hash['queue'] = destination_queue
+ conn.lpush("queue:#{destination_queue}", Gitlab::Json.dump(job_hash))
+ migrated += 1
+ rescue JSON::ParserError
+ logger&.error("Unmarshal JSON payload from SidekiqMigrateJobs failed. Job: #{job}")
+ next
+ end
+ end
+ logger&.info("Finished migrating #{queue_from} queue")
+ end
+ end
+ end
+
private
- def migrate_job(job, score, job_hash)
+ def migrate_job_in_set(sidekiq_set, job, score, job_hash)
Sidekiq.redis do |connection|
removed = connection.zrem(sidekiq_set, job)
if removed
- connection.zadd(sidekiq_set, score, Sidekiq.dump_json(job_hash))
+ connection.zadd(sidekiq_set, score, Gitlab::Json.dump(job_hash))
1
else
@@ -68,5 +110,11 @@ module Gitlab
end
end
end
+
+ def queue_length(queue_name)
+ Sidekiq.redis do |conn|
+ conn.llen("queue:#{queue_name}")
+ end
+ end
end
end
diff --git a/lib/gitlab/slash_commands/application_help.rb b/lib/gitlab/slash_commands/application_help.rb
index 1a92346be15..bfdb65a816d 100644
--- a/lib/gitlab/slash_commands/application_help.rb
+++ b/lib/gitlab/slash_commands/application_help.rb
@@ -3,14 +3,9 @@
module Gitlab
module SlashCommands
class ApplicationHelp < BaseCommand
- def initialize(project, params)
- @project = project
- @params = params
- end
-
def execute
Gitlab::SlashCommands::Presenters::Help
- .new(project, commands)
+ .new(project, commands, params)
.present(trigger, params[:text])
end
@@ -21,7 +16,11 @@ module Gitlab
end
def commands
- Gitlab::SlashCommands::Command.commands
+ Gitlab::SlashCommands::Command.new(
+ project,
+ chat_name,
+ params
+ ).commands
end
end
end
diff --git a/lib/gitlab/slash_commands/command.rb b/lib/gitlab/slash_commands/command.rb
index 239479f99d2..265eda46489 100644
--- a/lib/gitlab/slash_commands/command.rb
+++ b/lib/gitlab/slash_commands/command.rb
@@ -3,8 +3,8 @@
module Gitlab
module SlashCommands
class Command < BaseCommand
- def self.commands
- [
+ def commands
+ commands = [
Gitlab::SlashCommands::IssueShow,
Gitlab::SlashCommands::IssueNew,
Gitlab::SlashCommands::IssueSearch,
@@ -14,6 +14,12 @@ module Gitlab
Gitlab::SlashCommands::Deploy,
Gitlab::SlashCommands::Run
]
+
+ if Feature.enabled?(:incident_declare_slash_command, current_user)
+ commands << Gitlab::SlashCommands::IncidentManagement::IncidentNew
+ end
+
+ commands
end
def execute
@@ -44,7 +50,7 @@ module Gitlab
private
def available_commands
- self.class.commands.keep_if do |klass|
+ commands.keep_if do |klass|
klass.available?(project)
end
end
diff --git a/lib/gitlab/slash_commands/incident_management/incident_command.rb b/lib/gitlab/slash_commands/incident_management/incident_command.rb
new file mode 100644
index 00000000000..3fa08621777
--- /dev/null
+++ b/lib/gitlab/slash_commands/incident_management/incident_command.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module SlashCommands
+ module IncidentManagement
+ class IncidentCommand < BaseCommand
+ def self.available?(project)
+ true
+ end
+
+ def collection
+ IssuesFinder.new(current_user, project_id: project.id, issue_types: :incident).execute
+ end
+ end
+ end
+ end
+end
+
+Gitlab::SlashCommands::IncidentManagement::IncidentCommand.prepend_mod
diff --git a/lib/gitlab/slash_commands/incident_management/incident_new.rb b/lib/gitlab/slash_commands/incident_management/incident_new.rb
new file mode 100644
index 00000000000..722fcff151d
--- /dev/null
+++ b/lib/gitlab/slash_commands/incident_management/incident_new.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module SlashCommands
+ module IncidentManagement
+ class IncidentNew < IncidentCommand
+ def self.help_message
+ 'incident declare'
+ end
+
+ def self.allowed?(project, user)
+ Feature.enabled?(:incident_declare_slash_command, user) && can?(user, :create_incident, project)
+ end
+
+ def self.match(text)
+ text == 'incident declare'
+ end
+
+ private
+
+ def presenter
+ Gitlab::SlashCommands::Presenters::IncidentManagement::IncidentNew.new
+ end
+ end
+ end
+ end
+end
+
+Gitlab::SlashCommands::IncidentManagement::IncidentNew.prepend_mod
diff --git a/lib/gitlab/slash_commands/presenters/help.rb b/lib/gitlab/slash_commands/presenters/help.rb
index 71bc0dc0123..61b36308d20 100644
--- a/lib/gitlab/slash_commands/presenters/help.rb
+++ b/lib/gitlab/slash_commands/presenters/help.rb
@@ -4,9 +4,10 @@ module Gitlab
module SlashCommands
module Presenters
class Help < Presenters::Base
- def initialize(project, commands)
+ def initialize(project, commands, params = {})
@project = project
@commands = commands
+ @params = params
end
def present(trigger, text)
@@ -66,7 +67,13 @@ module Gitlab
def full_commands_message(trigger)
list = @commands
- .map { |command| "#{trigger} #{command.help_message}" }
+ .map do |command|
+ if command < Gitlab::SlashCommands::IncidentManagement::IncidentCommand
+ "#{@params[:command]} #{command.help_message}"
+ else
+ "#{trigger} #{command.help_message}"
+ end
+ end
.join("\n")
<<~MESSAGE
diff --git a/lib/gitlab/slash_commands/presenters/incident_management/incident_new.rb b/lib/gitlab/slash_commands/presenters/incident_management/incident_new.rb
new file mode 100644
index 00000000000..5030c8282db
--- /dev/null
+++ b/lib/gitlab/slash_commands/presenters/incident_management/incident_new.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module SlashCommands
+ module Presenters
+ module IncidentManagement
+ class IncidentNew < Presenters::Base
+ def present(message)
+ ephemeral_response(text: message)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/sql/pattern.rb b/lib/gitlab/sql/pattern.rb
index ca7ae429986..d13ccde8576 100644
--- a/lib/gitlab/sql/pattern.rb
+++ b/lib/gitlab/sql/pattern.rb
@@ -6,7 +6,7 @@ module Gitlab
extend ActiveSupport::Concern
MIN_CHARS_FOR_PARTIAL_MATCHING = 3
- REGEX_QUOTED_WORD = /(?<=\A| )"[^"]+"(?= |\z)/.freeze
+ REGEX_QUOTED_TERM = /(?<=\A| )"[^"]+"(?= |\z)/.freeze
class_methods do
def fuzzy_search(query, columns, use_minimum_char_limit: true)
@@ -40,12 +40,14 @@ module Gitlab
# lower_exact_match - When set to `true` we'll fall back to using
# `LOWER(column) = query` instead of using `ILIKE`.
def fuzzy_arel_match(column, query, lower_exact_match: false, use_minimum_char_limit: true)
+ return unless query.is_a?(String)
+
query = query.squish
return unless query.present?
arel_column = column.is_a?(Arel::Attributes::Attribute) ? column : arel_table[column]
- words = select_fuzzy_words(query, use_minimum_char_limit: use_minimum_char_limit)
+ words = select_fuzzy_terms(query, use_minimum_char_limit: use_minimum_char_limit)
if words.any?
words.map { |word| arel_column.matches(to_pattern(word, use_minimum_char_limit: use_minimum_char_limit)) }.reduce(:and)
@@ -62,19 +64,21 @@ module Gitlab
end
end
- def select_fuzzy_words(query, use_minimum_char_limit: true)
- quoted_words = query.scan(REGEX_QUOTED_WORD)
-
- query = quoted_words.reduce(query) { |q, quoted_word| q.sub(quoted_word, '') }
-
- words = query.split
-
- quoted_words.map! { |quoted_word| quoted_word[1..-2] }
+ def select_fuzzy_terms(query, use_minimum_char_limit: true)
+ terms = Gitlab::SQL::Pattern.split_query_to_search_terms(query)
+ terms.select { |term| partial_matching?(term, use_minimum_char_limit: use_minimum_char_limit) }
+ end
+ end
- words.concat(quoted_words)
+ def self.split_query_to_search_terms(query)
+ quoted_terms = []
- words.select { |word| partial_matching?(word, use_minimum_char_limit: use_minimum_char_limit) }
+ query = query.gsub(REGEX_QUOTED_TERM) do |quoted_term|
+ quoted_terms << quoted_term
+ ""
end
+
+ query.split + quoted_terms.map { |quoted_term| quoted_term[1..-2] }
end
end
end
diff --git a/lib/gitlab/template/base_template.rb b/lib/gitlab/template/base_template.rb
index 31e11f73fe7..ededc3db18e 100644
--- a/lib/gitlab/template/base_template.rb
+++ b/lib/gitlab/template/base_template.rb
@@ -47,6 +47,8 @@ module Gitlab
{ key: key, name: name, content: content }
end
+ alias_method :as_json, :to_json
+
def <=>(other)
name <=> other.name
end
diff --git a/lib/gitlab/tracking/helpers/weak_password_error_event.rb b/lib/gitlab/tracking/helpers/weak_password_error_event.rb
new file mode 100644
index 00000000000..beb6119e3f7
--- /dev/null
+++ b/lib/gitlab/tracking/helpers/weak_password_error_event.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Tracking
+ module Helpers
+ module WeakPasswordErrorEvent
+ # Tracks information if a user record has a weak password.
+ # No-op unless the error is present.
+ #
+ # Captures a minimal set of information, so that GitLab
+ # remains unaware of which users / demographics are attempting
+ # to choose weak passwords.
+ def track_weak_password_error(user, controller, method_name)
+ return unless user.errors[:password].grep(/must not contain commonly used combinations.*/).any?
+
+ Gitlab::Tracking.event(
+ 'Gitlab::Tracking::Helpers::WeakPasswordErrorEvent',
+ 'track_weak_password_error',
+ controller: controller,
+ method: method_name
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/url_builder.rb b/lib/gitlab/url_builder.rb
index a6d6cffec17..e203fb486e7 100644
--- a/lib/gitlab/url_builder.rb
+++ b/lib/gitlab/url_builder.rb
@@ -52,6 +52,8 @@ module Gitlab
wiki_page_url(object.wiki, object, **options)
when ::DesignManagement::Design
design_url(object, **options)
+ when ::Packages::Package
+ package_url(object, **options)
else
raise NotImplementedError, "No URL builder defined for #{object.inspect}"
end
@@ -133,6 +135,17 @@ module Gitlab
instance.project_design_management_designs_raw_image_url(design.project, design, ref, **options)
end
end
+
+ def package_url(package, **options)
+ project = package.project
+
+ if package.infrastructure_package?
+ return instance.project_infrastructure_registry_url(project, package,
+**options)
+ end
+
+ instance.project_package_url(project, package, **options)
+ end
end
end
end
diff --git a/lib/gitlab/usage/metric_definition.rb b/lib/gitlab/usage/metric_definition.rb
index d6b1e62c84f..065ede75c60 100644
--- a/lib/gitlab/usage/metric_definition.rb
+++ b/lib/gitlab/usage/metric_definition.rb
@@ -4,9 +4,9 @@ module Gitlab
module Usage
class MetricDefinition
METRIC_SCHEMA_PATH = Rails.root.join('config', 'metrics', 'schema.json')
- SKIP_VALIDATION_STATUSES = %w[deprecated removed].to_set.freeze
- AVAILABLE_STATUSES = %w[active data_available implemented deprecated broken].to_set.freeze
- VALID_SERVICE_PING_STATUSES = %w[active data_available implemented deprecated broken].to_set.freeze
+ SKIP_VALIDATION_STATUS = 'removed'
+ AVAILABLE_STATUSES = %w[active broken].to_set.freeze
+ VALID_SERVICE_PING_STATUSES = %w[active broken].to_set.freeze
InvalidError = Class.new(RuntimeError)
@@ -144,7 +144,7 @@ module Gitlab
end
def skip_validation?
- !!attributes[:skip_validation] || @skip_validation || SKIP_VALIDATION_STATUSES.include?(attributes[:status])
+ !!attributes[:skip_validation] || @skip_validation || attributes[:status] == SKIP_VALIDATION_STATUS
end
end
end
diff --git a/lib/gitlab/usage/metrics/aggregates.rb b/lib/gitlab/usage/metrics/aggregates.rb
index a32c413dba8..02d9fa74289 100644
--- a/lib/gitlab/usage/metrics/aggregates.rb
+++ b/lib/gitlab/usage/metrics/aggregates.rb
@@ -7,14 +7,13 @@ module Gitlab
UNION_OF_AGGREGATED_METRICS = 'OR'
INTERSECTION_OF_AGGREGATED_METRICS = 'AND'
ALLOWED_METRICS_AGGREGATIONS = [UNION_OF_AGGREGATED_METRICS, INTERSECTION_OF_AGGREGATED_METRICS].freeze
- AGGREGATED_METRICS_PATH = Rails.root.join('config/metrics/aggregates/*.yml')
AggregatedMetricError = Class.new(StandardError)
UnknownAggregationOperator = Class.new(AggregatedMetricError)
UnknownAggregationSource = Class.new(AggregatedMetricError)
DisallowedAggregationTimeFrame = Class.new(AggregatedMetricError)
DATABASE_SOURCE = 'database'
- REDIS_SOURCE = 'redis'
+ REDIS_SOURCE = 'redis_hll'
SOURCES = {
DATABASE_SOURCE => Sources::PostgresHll,
diff --git a/lib/gitlab/usage/metrics/aggregates/aggregate.rb b/lib/gitlab/usage/metrics/aggregates/aggregate.rb
index cd72f16d46d..78f1ddc8a29 100644
--- a/lib/gitlab/usage/metrics/aggregates/aggregate.rb
+++ b/lib/gitlab/usage/metrics/aggregates/aggregate.rb
@@ -8,22 +8,9 @@ module Gitlab
include Gitlab::Usage::TimeFrame
def initialize(recorded_at)
- @aggregated_metrics = load_metrics(AGGREGATED_METRICS_PATH)
@recorded_at = recorded_at
end
- def all_time_data
- aggregated_metrics_data(Gitlab::Usage::TimeFrame::ALL_TIME_TIME_FRAME_NAME)
- end
-
- def monthly_data
- aggregated_metrics_data(Gitlab::Usage::TimeFrame::TWENTY_EIGHT_DAYS_TIME_FRAME_NAME)
- end
-
- def weekly_data
- aggregated_metrics_data(Gitlab::Usage::TimeFrame::SEVEN_DAYS_TIME_FRAME_NAME)
- end
-
def calculate_count_for_aggregation(aggregation:, time_frame:)
with_validate_configuration(aggregation, time_frame) do
source = SOURCES[aggregation[:source]]
@@ -40,16 +27,7 @@ module Gitlab
private
- attr_accessor :aggregated_metrics, :recorded_at
-
- def aggregated_metrics_data(time_frame)
- aggregated_metrics.each_with_object({}) do |aggregation, data|
- next if aggregation[:feature_flag] && Feature.disabled?(aggregation[:feature_flag], type: :development)
- next unless aggregation[:time_frame].include?(time_frame)
-
- data[aggregation[:name]] = calculate_count_for_aggregation(aggregation: aggregation, time_frame: time_frame)
- end
- end
+ attr_accessor :recorded_at
def with_validate_configuration(aggregation, time_frame)
source = aggregation[:source]
@@ -83,16 +61,6 @@ module Gitlab
Gitlab::Utils::UsageData::FALLBACK
end
- def load_metrics(wildcard)
- Dir[wildcard].each_with_object([]) do |path, metrics|
- metrics.push(*load_yaml_from_path(path))
- end
- end
-
- def load_yaml_from_path(path)
- YAML.safe_load(File.read(path), aliases: true)&.map(&:with_indifferent_access)
- end
-
def time_constraints(time_frame)
case time_frame
when Gitlab::Usage::TimeFrame::TWENTY_EIGHT_DAYS_TIME_FRAME_NAME
@@ -108,5 +76,3 @@ module Gitlab
end
end
end
-
-Gitlab::Usage::Metrics::Aggregates::Aggregate.prepend_mod_with('Gitlab::Usage::Metrics::Aggregates::Aggregate')
diff --git a/lib/gitlab/usage/metrics/instrumentations/aggregated_metric.rb b/lib/gitlab/usage/metrics/instrumentations/aggregated_metric.rb
index 63ead5a8cb0..66be7a7b64e 100644
--- a/lib/gitlab/usage/metrics/instrumentations/aggregated_metric.rb
+++ b/lib/gitlab/usage/metrics/instrumentations/aggregated_metric.rb
@@ -25,7 +25,7 @@ module Gitlab
def initialize(metric_definition)
super
- @source = parse_data_source_to_legacy_value(metric_definition)
+ @source = metric_definition[:data_source]
@aggregate = options.fetch(:aggregate, {})
end
@@ -48,15 +48,6 @@ module Gitlab
attr_accessor :source, :aggregate
- # TODO: This method is a temporary measure that
- # handles backwards compatibility until
- # point 5 from is resolved https://gitlab.com/gitlab-org/gitlab/-/issues/370963#implementation
- def parse_data_source_to_legacy_value(metric_definition)
- return 'redis' if metric_definition[:data_source] == 'redis_hll'
-
- metric_definition[:data_source]
- end
-
def aggregate_config
{
source: source,
diff --git a/lib/gitlab/usage/metrics/instrumentations/count_merge_request_authors_metric.rb b/lib/gitlab/usage/metrics/instrumentations/count_merge_request_authors_metric.rb
new file mode 100644
index 00000000000..a7f8bca8e08
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/count_merge_request_authors_metric.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class CountMergeRequestAuthorsMetric < DatabaseMetric
+ operation :distinct_count, column: :author_id
+
+ relation { MergeRequest }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage/metrics/instrumentations/database_metric.rb b/lib/gitlab/usage/metrics/instrumentations/database_metric.rb
index 6dec0349a38..f0d5298870c 100644
--- a/lib/gitlab/usage/metrics/instrumentations/database_metric.rb
+++ b/lib/gitlab/usage/metrics/instrumentations/database_metric.rb
@@ -34,10 +34,10 @@ module Gitlab
@metric_finish = block
end
- def relation(&block)
- return @metric_relation&.call unless block
+ def relation(relation_proc = nil, &block)
+ return unless relation_proc || block
- @metric_relation = block
+ @metric_relation = (relation_proc || block)
end
def metric_options(&block)
@@ -106,7 +106,11 @@ module Gitlab
end
def relation
- self.class.metric_relation.call.where(time_constraints)
+ if self.class.metric_relation.arity == 1
+ self.class.metric_relation.call(options)
+ else
+ self.class.metric_relation.call
+ end.where(time_constraints)
end
def time_constraints
diff --git a/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_disabled_metric.rb b/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_disabled_metric.rb
deleted file mode 100644
index 0c421dc3311..00000000000
--- a/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_disabled_metric.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Usage
- module Metrics
- module Instrumentations
- class DistinctCountProjectsWithExpirationPolicyDisabledMetric < DatabaseMetric
- operation :distinct_count, column: :project_id
-
- start { Project.minimum(:id) }
- finish { Project.maximum(:id) }
-
- cache_start_and_finish_as :project_id
-
- relation { ::ContainerExpirationPolicy.where(enabled: false) }
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_metric.rb b/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_metric.rb
new file mode 100644
index 00000000000..c7cf6c57059
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_metric.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class DistinctCountProjectsWithExpirationPolicyMetric < DatabaseMetric
+ operation :distinct_count, column: :project_id
+
+ start { Project.minimum(:id) }
+ finish { Project.maximum(:id) }
+
+ cache_start_and_finish_as :project_id
+
+ relation ->(options) do
+ options.each_with_object(::ContainerExpirationPolicy.all) do |(key, value), ar_relation|
+ ar_relation.where!(key => value)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage/metrics/instrumentations/dormant_user_period_setting_metric.rb b/lib/gitlab/usage/metrics/instrumentations/dormant_user_period_setting_metric.rb
new file mode 100644
index 00000000000..c05664aa9c8
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/dormant_user_period_setting_metric.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class DormantUserPeriodSettingMetric < GenericMetric
+ value do
+ ::Gitlab::CurrentSettings.deactivate_dormant_users_period
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage/metrics/instrumentations/dormant_user_setting_enabled_metric.rb b/lib/gitlab/usage/metrics/instrumentations/dormant_user_setting_enabled_metric.rb
new file mode 100644
index 00000000000..82d8570276a
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/dormant_user_setting_enabled_metric.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class DormantUserSettingEnabledMetric < GenericMetric
+ value do
+ ::Gitlab::CurrentSettings.deactivate_dormant_users
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_cta_clicked_metric.rb b/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_cta_clicked_metric.rb
new file mode 100644
index 00000000000..b1a2de29fd7
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_cta_clicked_metric.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class InProductMarketingEmailCtaClickedMetric < DatabaseMetric
+ operation :count
+
+ def initialize(metric_definition)
+ super
+
+ unless track.in?(allowed_track)
+ raise ArgumentError, "track '#{track}' must be one of: #{allowed_track.join(', ')}"
+ end
+
+ return if series.in?(allowed_series)
+
+ raise ArgumentError, "series '#{series}' must be one of: #{allowed_series.join(', ')}"
+ end
+
+ relation { Users::InProductMarketingEmail }
+
+ private
+
+ def relation
+ scope = super.where.not(cta_clicked_at: nil)
+ scope = scope.where(series: series)
+ scope.where(track: track)
+ end
+
+ def track
+ options[:track]
+ end
+
+ def series
+ options[:series]
+ end
+
+ def allowed_track
+ Users::InProductMarketingEmail::ACTIVE_TRACKS.keys
+ end
+
+ def allowed_series
+ @allowed_series ||= begin
+ series_amount = Namespaces::InProductMarketingEmailsService.email_count_for_track(track)
+ 0.upto(series_amount - 1).to_a
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_sent_metric.rb b/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_sent_metric.rb
new file mode 100644
index 00000000000..50dec606d9b
--- /dev/null
+++ b/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_sent_metric.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module Instrumentations
+ class InProductMarketingEmailSentMetric < DatabaseMetric
+ operation :count
+
+ def initialize(metric_definition)
+ super
+
+ unless track.in?(allowed_track)
+ raise ArgumentError, "track '#{track}' must be one of: #{allowed_track.join(', ')}"
+ end
+
+ return if series.in?(allowed_series)
+
+ raise ArgumentError, "series '#{series}' must be one of: #{allowed_series.join(', ')}"
+ end
+
+ relation { Users::InProductMarketingEmail }
+
+ private
+
+ def relation
+ scope = super
+ scope = scope.where(series: series)
+ scope.where(track: track)
+ end
+
+ def track
+ options[:track]
+ end
+
+ def series
+ options[:series]
+ end
+
+ def allowed_track
+ Users::InProductMarketingEmail::ACTIVE_TRACKS.keys
+ end
+
+ def allowed_series
+ @allowed_series ||= begin
+ series_amount = Namespaces::InProductMarketingEmailsService.email_count_for_track(track)
+ 0.upto(series_amount - 1).to_a
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage/metrics/name_suggestion.rb b/lib/gitlab/usage/metrics/name_suggestion.rb
index 238a7a51a20..44723b6f3d4 100644
--- a/lib/gitlab/usage/metrics/name_suggestion.rb
+++ b/lib/gitlab/usage/metrics/name_suggestion.rb
@@ -7,6 +7,7 @@ module Gitlab
FREE_TEXT_METRIC_NAME = "<please fill metric name>"
REDIS_EVENT_METRIC_NAME = "<please fill metric name, suggested format is: {subject}_{verb}{ing|ed}_{object} eg: users_creating_epics or merge_requests_viewed_in_single_file_mode>"
CONSTRAINTS_PROMPT_TEMPLATE = "<adjective describing: '%{constraints}'>"
+ EMPTY_CONSTRAINT = "()"
class << self
def for(operation, relation: nil, column: nil)
@@ -52,7 +53,8 @@ module Gitlab
end
arel = arel_query(relation: relation, column: arel_column, distinct: distinct)
- constraints = parse_constraints(relation: relation, arel: arel)
+ where_constraints = parse_where_constraints(relation: relation, arel: arel)
+ having_constraints = parse_having_constraints(relation: relation, arel: arel)
# In some cases due to performance reasons metrics are instrumented with joined relations
# where relation listed in FROM statement is not the one that includes counted attribute
@@ -66,23 +68,35 @@ module Gitlab
# count_environment_id_from_clusters_with_deployments
actual_source = parse_source(relation, arel_column)
- append_constraints_prompt(actual_source, [constraints], parts)
+ append_constraints_prompt(actual_source, [where_constraints], [having_constraints], parts)
parts << actual_source
- parts += process_joined_relations(actual_source, arel, relation, constraints)
+ parts += process_joined_relations(actual_source, arel, relation, where_constraints)
parts.compact.join('_').delete('"')
end
- def append_constraints_prompt(target, constraints, parts)
- applicable_constraints = constraints.select { |constraint| constraint.include?(target) }
+ def append_constraints_prompt(target, where_constraints, having_constraints, parts)
+ where_constraints.select! do |constraint|
+ constraint.include?(target)
+ end
+ having_constraints.delete(EMPTY_CONSTRAINT)
+ applicable_constraints = where_constraints + having_constraints
return unless applicable_constraints.any?
parts << CONSTRAINTS_PROMPT_TEMPLATE % { constraints: applicable_constraints.join(' AND ') }
end
- def parse_constraints(relation:, arel:)
+ def parse_where_constraints(relation:, arel:)
+ connection = relation.connection
+ ::Gitlab::Usage::Metrics::NamesSuggestions::RelationParsers::WhereConstraints
+ .new(connection)
+ .accept(arel, collector(connection))
+ .value
+ end
+
+ def parse_having_constraints(relation:, arel:)
connection = relation.connection
- ::Gitlab::Usage::Metrics::NamesSuggestions::RelationParsers::Constraints
+ ::Gitlab::Usage::Metrics::NamesSuggestions::RelationParsers::HavingConstraints
.new(connection)
.accept(arel, collector(connection))
.value
@@ -152,7 +166,7 @@ module Gitlab
subtree.each do |parent, children|
parts << "<#{conjunction}>"
join_constraints = joins.find { |join| join[:source] == parent }&.dig(:constraints)
- append_constraints_prompt(parent, [wheres, join_constraints].compact, parts)
+ append_constraints_prompt(parent, [wheres, join_constraints].compact, [], parts)
parts << parent
collect_join_parts(relations: children, joins: joins, wheres: wheres, parts: parts, conjunctions: conjunctions)
end
diff --git a/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/constraints.rb b/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/constraints.rb
deleted file mode 100644
index 199395e4b20..00000000000
--- a/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/constraints.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Usage
- module Metrics
- module NamesSuggestions
- module RelationParsers
- class Constraints < ::Arel::Visitors::PostgreSQL
- # rubocop:disable Naming/MethodName
- def visit_Arel_Nodes_SelectCore(object, collector)
- collect_nodes_for(object.wheres, collector, "") || collector
- end
- # rubocop:enable Naming/MethodName
-
- def quote(value)
- "#{value}"
- end
-
- def quote_table_name(name)
- "#{name}"
- end
-
- def quote_column_name(name)
- "#{name}"
- end
- end
- end
- end
- end
- end
-end
diff --git a/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/having_constraints.rb b/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/having_constraints.rb
new file mode 100644
index 00000000000..8dd3b1ff5c6
--- /dev/null
+++ b/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/having_constraints.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module NamesSuggestions
+ module RelationParsers
+ class HavingConstraints < ::Arel::Visitors::PostgreSQL
+ # rubocop:disable Naming/MethodName
+ def visit_Arel_Nodes_SelectCore(object, collector)
+ collect_nodes_for(object.havings, collector, "") || collector
+ end
+ # rubocop:enable Naming/MethodName
+
+ def quote(value)
+ value.to_s
+ end
+
+ def quote_table_name(name)
+ name.to_s
+ end
+
+ def quote_column_name(name)
+ name.to_s
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/where_constraints.rb b/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/where_constraints.rb
new file mode 100644
index 00000000000..9f829067214
--- /dev/null
+++ b/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/where_constraints.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Usage
+ module Metrics
+ module NamesSuggestions
+ module RelationParsers
+ class WhereConstraints < ::Arel::Visitors::PostgreSQL
+ # rubocop:disable Naming/MethodName
+ def visit_Arel_Nodes_SelectCore(object, collector)
+ collect_nodes_for(object.wheres, collector, "") || collector
+ end
+ # rubocop:enable Naming/MethodName
+
+ def quote(value)
+ value.to_s
+ end
+
+ def quote_table_name(name)
+ name.to_s
+ end
+
+ def quote_column_name(name)
+ name.to_s
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index 87ccb9a31da..5021dac453f 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -30,7 +30,6 @@ module Gitlab
deployment_minimum_id
deployment_maximum_id
auth_providers
- aggregated_metrics
recorded_at
).freeze
@@ -157,11 +156,9 @@ module Gitlab
}.merge(
runners_usage,
integrations_usage,
- usage_counters,
user_preferences_usage,
container_expiration_policies_usage,
- service_desk_counts,
- email_campaign_counts
+ service_desk_counts
).tap do |data|
data[:snippets] = add(data[:personal_snippets], data[:project_snippets])
end
@@ -261,16 +258,6 @@ module Gitlab
}
end
- # @return [Hash<Symbol, Integer>]
- def usage_counters
- usage_data_counters.map { |counter| redis_usage_data(counter) }.reduce({}, :merge)
- end
-
- # @return [Array<#totals>] An array of objects that respond to `#totals`
- def usage_data_counters
- Gitlab::UsageDataCounters.unmigrated_counters
- end
-
def components_usage_data
{
git: { version: alt_usage_data(fallback: { major: -1 }) { Gitlab::Git.version } },
@@ -349,17 +336,13 @@ module Gitlab
# rubocop: disable UsageData/LargeTable
base = ::ContainerExpirationPolicy.active
# rubocop: enable UsageData/LargeTable
- results[:projects_with_expiration_policy_enabled] = distinct_count(base, :project_id, start: start, finish: finish)
# rubocop: disable UsageData/LargeTable
- %i[keep_n cadence older_than].each do |option|
- ::ContainerExpirationPolicy.public_send("#{option}_options").keys.each do |value| # rubocop: disable GitlabSecurity/PublicSend
- results["projects_with_expiration_policy_enabled_with_#{option}_set_to_#{value}".to_sym] = distinct_count(base.where(option => value), :project_id, start: start, finish: finish)
- end
+ ::ContainerExpirationPolicy.older_than_options.keys.each do |value|
+ results["projects_with_expiration_policy_enabled_with_older_than_set_to_#{value}".to_sym] = distinct_count(base.where(older_than: value), :project_id, start: start, finish: finish)
end
# rubocop: enable UsageData/LargeTable
- results[:projects_with_expiration_policy_enabled_with_keep_n_unset] = distinct_count(base.where(keep_n: nil), :project_id, start: start, finish: finish)
results[:projects_with_expiration_policy_enabled_with_older_than_unset] = distinct_count(base.where(older_than: nil), :project_id, start: start, finish: finish)
results
@@ -632,21 +615,16 @@ module Gitlab
{ redis_hll_counters: ::Gitlab::UsageDataCounters::HLLRedisCounter.unique_events_data }
end
- def aggregated_metrics_data
- {
- counts_weekly: { aggregated_metrics: aggregated_metrics.weekly_data },
- counts_monthly: { aggregated_metrics: aggregated_metrics.monthly_data },
- counts: aggregated_metrics
- .all_time_data
- .to_h { |key, value| ["aggregate_#{key}".to_sym, value.round] }
- }
- 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 }
- event_monthly_active_users(date_range)
- .merge!(ide_monthly_active_users(date_range))
+ {
+ 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) },
+ action_monthly_active_users_ide_edit: redis_usage_data { counter.count_edit_using_editor(**date_range) }
+ }
end
def with_duration
@@ -688,7 +666,6 @@ module Gitlab
.merge(usage_activity_by_stage)
.merge(usage_activity_by_stage(:usage_activity_by_stage_monthly, monthly_time_range_db_params))
.merge(redis_hll_counters)
- .deep_merge(aggregated_metrics_data)
end
def metric_time_period(time_period)
@@ -705,34 +682,6 @@ module Gitlab
end
end
- def aggregated_metrics
- @aggregated_metrics ||= ::Gitlab::Usage::Metrics::Aggregates::Aggregate.new(recorded_at)
- end
-
- def event_monthly_active_users(date_range)
- data = {
- action_monthly_active_users_project_repo: Gitlab::UsageDataCounters::TrackUniqueEvents::PUSH_ACTION,
- action_monthly_active_users_design_management: Gitlab::UsageDataCounters::TrackUniqueEvents::DESIGN_ACTION,
- action_monthly_active_users_wiki_repo: Gitlab::UsageDataCounters::TrackUniqueEvents::WIKI_ACTION,
- action_monthly_active_users_git_write: Gitlab::UsageDataCounters::TrackUniqueEvents::GIT_WRITE_ACTION
- }
-
- data.each do |key, event|
- data[key] = redis_usage_data { Gitlab::UsageDataCounters::TrackUniqueEvents.count_unique_events(event_action: event, **date_range) }
- end
- end
-
- def ide_monthly_active_users(date_range)
- counter = Gitlab::UsageDataCounters::EditorUniqueCounter
-
- {
- 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) },
- action_monthly_active_users_ide_edit: redis_usage_data { counter.count_edit_using_editor(**date_range) }
- }
- end
-
def distinct_count_service_desk_enabled_projects(time_period)
project_creator_id_start = minimum_id(User)
project_creator_id_finish = maximum_id(User)
@@ -758,37 +707,6 @@ module Gitlab
end
# rubocop: enable CodeReuse/ActiveRecord
- # rubocop: disable CodeReuse/ActiveRecord
- def email_campaign_counts
- # rubocop:disable UsageData/LargeTable
- sent_emails = count(Users::InProductMarketingEmail.group(:track, :series))
- clicked_emails = count(Users::InProductMarketingEmail.where.not(cta_clicked_at: nil).group(:track, :series))
-
- Users::InProductMarketingEmail::ACTIVE_TRACKS.keys.each_with_object({}) do |track, result|
- series_amount = Namespaces::InProductMarketingEmailsService.email_count_for_track(track)
- # rubocop: enable UsageData/LargeTable:
-
- 0.upto(series_amount - 1).map do |series|
- sent_count = sent_in_product_marketing_email_count(sent_emails, track, series)
- clicked_count = clicked_in_product_marketing_email_count(clicked_emails, track, series)
-
- result["in_product_marketing_email_#{track}_#{series}_sent"] = sent_count
- result["in_product_marketing_email_#{track}_#{series}_cta_clicked"] = clicked_count unless track == 'experience'
- end
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- def sent_in_product_marketing_email_count(sent_emails, track, series)
- # When there is an error with the query and it's not the Hash we expect, we return what we got from `count`.
- sent_emails.is_a?(Hash) ? sent_emails.fetch([track, series], 0) : sent_emails
- end
-
- def clicked_in_product_marketing_email_count(clicked_emails, track, series)
- # When there is an error with the query and it's not the Hash we expect, we return what we got from `count`.
- clicked_emails.is_a?(Hash) ? clicked_emails.fetch([track, series], 0) : clicked_emails
- end
-
def total_alert_issues
# Remove prometheus table queries once they are deprecated
# To be removed with https://gitlab.com/gitlab-org/gitlab/-/issues/217407.
diff --git a/lib/gitlab/usage_data_counters.rb b/lib/gitlab/usage_data_counters.rb
index 37c6e1af7c0..c2961de0eb9 100644
--- a/lib/gitlab/usage_data_counters.rb
+++ b/lib/gitlab/usage_data_counters.rb
@@ -2,9 +2,7 @@
module Gitlab
module UsageDataCounters
- COUNTERS = [].freeze
-
- COUNTERS_MIGRATED_TO_INSTRUMENTATION_CLASSES = [
+ COUNTERS = [
PackageEventCounter,
MergeRequestCounter,
DesignsCounter,
@@ -26,12 +24,8 @@ module Gitlab
UnknownEvent = Class.new(UsageDataCounterError)
class << self
- def unmigrated_counters
- self::COUNTERS
- end
-
def counters
- unmigrated_counters + migrated_counters
+ COUNTERS
end
def count(event_name)
@@ -43,12 +37,6 @@ module Gitlab
raise UnknownEvent, "Cannot find counter for event #{event_name}"
end
-
- private
-
- def migrated_counters
- COUNTERS_MIGRATED_TO_INSTRUMENTATION_CLASSES
- end
end
end
end
diff --git a/lib/gitlab/usage_data_counters/ci_template_unique_counter.rb b/lib/gitlab/usage_data_counters/ci_template_unique_counter.rb
index 1e8918c7c96..eb040e9e819 100644
--- a/lib/gitlab/usage_data_counters/ci_template_unique_counter.rb
+++ b/lib/gitlab/usage_data_counters/ci_template_unique_counter.rb
@@ -10,13 +10,17 @@ module Gitlab::UsageDataCounters
expanded_template_name = expand_template_name(template)
return unless expanded_template_name
- Gitlab::UsageDataCounters::HLLRedisCounter.track_event(
- ci_template_event_name(expanded_template_name, config_source), values: project.id
- )
+ event_name = ci_template_event_name(expanded_template_name, config_source)
+ Gitlab::UsageDataCounters::HLLRedisCounter.track_event(event_name, values: project.id)
namespace = project.namespace
if Feature.enabled?(:route_hll_to_snowplow, namespace)
- Gitlab::Tracking.event(name, 'ci_templates_unique', namespace: namespace, user: user, project: project)
+ context = Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll,
+ event: event_name).to_context
+ label = 'redis_hll_counters.ci_templates.ci_templates_total_unique_counts_monthly'
+ Gitlab::Tracking.event(name, 'ci_templates_unique', namespace: namespace,
+ project: project, context: [context], user: user,
+ label: label)
end
end
diff --git a/lib/gitlab/usage_data_counters/counter_events/package_events.yml b/lib/gitlab/usage_data_counters/counter_events/package_events.yml
index a64d0ff7e24..f7ddc53f50d 100644
--- a/lib/gitlab/usage_data_counters/counter_events/package_events.yml
+++ b/lib/gitlab/usage_data_counters/counter_events/package_events.yml
@@ -55,3 +55,5 @@
- i_package_terraform_module_delete_package
- i_package_terraform_module_pull_package
- i_package_terraform_module_push_package
+- i_package_rpm_push_package
+- i_package_rpm_pull_package
diff --git a/lib/gitlab/usage_data_counters/known_events/common.yml b/lib/gitlab/usage_data_counters/known_events/common.yml
index c13c7657576..c1720b26a22 100644
--- a/lib/gitlab/usage_data_counters/known_events/common.yml
+++ b/lib/gitlab/usage_data_counters/known_events/common.yml
@@ -127,6 +127,11 @@
category: testing
redis_slot: testing
aggregation: weekly
+- name: i_testing_coverage_report_uploaded
+ category: testing
+ redis_slot: testing
+ aggregation: weekly
+ feature_flag: usage_data_ci_i_testing_coverage_report_uploaded
# Project Management group
- name: g_project_management_issue_title_changed
category: issues_edit
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 debdbd8614f..ef8d02fa365 100644
--- a/lib/gitlab/usage_data_counters/known_events/package_events.yml
+++ b/lib/gitlab/usage_data_counters/known_events/package_events.yml
@@ -79,3 +79,11 @@
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/work_items.yml b/lib/gitlab/usage_data_counters/known_events/work_items.yml
index ee828fc0f72..d088b6d7e5a 100644
--- a/lib/gitlab/usage_data_counters/known_events/work_items.yml
+++ b/lib/gitlab/usage_data_counters/known_events/work_items.yml
@@ -19,6 +19,11 @@
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.
@@ -27,3 +32,11 @@
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/kubernetes_agent_counter.rb b/lib/gitlab/usage_data_counters/kubernetes_agent_counter.rb
index 8b9ca0fc220..d6e05f30a0d 100644
--- a/lib/gitlab/usage_data_counters/kubernetes_agent_counter.rb
+++ b/lib/gitlab/usage_data_counters/kubernetes_agent_counter.rb
@@ -8,6 +8,8 @@ module Gitlab
class << self
def increment_event_counts(events)
+ return unless events.present?
+
validate!(events)
events.each do |event, incr|
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 a0fd04596fc..b99c9ebb24f 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
@@ -7,6 +7,7 @@ module Gitlab
WORK_ITEM_TITLE_CHANGED = 'users_updating_work_item_title'
WORK_ITEM_DATE_CHANGED = 'users_updating_work_item_dates'
WORK_ITEM_LABELS_CHANGED = 'users_updating_work_item_labels'
+ WORK_ITEM_MILESTONE_CHANGED = 'users_updating_work_item_milestone'
class << self
def track_work_item_created_action(author:)
@@ -25,6 +26,10 @@ module Gitlab
track_unique_action(WORK_ITEM_LABELS_CHANGED, author)
end
+ def track_work_item_milestone_changed_action(author:)
+ track_unique_action(WORK_ITEM_MILESTONE_CHANGED, author)
+ end
+
private
def track_unique_action(action, author)
diff --git a/lib/gitlab/utils.rb b/lib/gitlab/utils.rb
index a67a0758257..d3055569ece 100644
--- a/lib/gitlab/utils.rb
+++ b/lib/gitlab/utils.rb
@@ -14,7 +14,10 @@ module Gitlab
# Also see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24223#note_284122580
# It also checks for ALT_SEPARATOR aka '\' (forward slash)
def check_path_traversal!(path)
- return unless path.is_a?(String)
+ return unless path
+
+ path = path.to_s if path.is_a?(Gitlab::HashedPath)
+ raise PathTraversalAttackError, 'Invalid path' unless path.is_a?(String)
path = decode_path(path)
path_regex = %r{(\A(\.{1,2})\z|\A\.\.[/\\]|[/\\]\.\.\z|[/\\]\.\.[/\\]|\n)}
@@ -164,9 +167,10 @@ module Gitlab
end
def deep_indifferent_access(data)
- if data.is_a?(Array)
+ case data
+ when Array
data.map(&method(:deep_indifferent_access))
- elsif data.is_a?(Hash)
+ when Hash
data.with_indifferent_access
else
data
@@ -174,9 +178,10 @@ module Gitlab
end
def deep_symbolized_access(data)
- if data.is_a?(Array)
+ case data
+ when Array
data.map(&method(:deep_symbolized_access))
- elsif data.is_a?(Hash)
+ when Hash
data.deep_symbolize_keys
else
data
diff --git a/lib/gitlab/utils/measuring.rb b/lib/gitlab/utils/measuring.rb
index dc43d977a62..cfa09804b98 100644
--- a/lib/gitlab/utils/measuring.rb
+++ b/lib/gitlab/utils/measuring.rb
@@ -31,7 +31,7 @@ module Gitlab
gc_stats: gc_stats,
time_to_finish: time_to_finish,
number_of_sql_calls: sql_calls_count,
- memory_usage: "#{Gitlab::Metrics::System.memory_usage_rss.to_f / 1024 / 1024} MiB",
+ memory_usage: "#{Gitlab::Metrics::System.memory_usage_rss[:total].to_f / 1024 / 1024} MiB",
label: ::Prometheus::PidProvider.worker_id
)
diff --git a/lib/gitlab/utils/strong_memoize.rb b/lib/gitlab/utils/strong_memoize.rb
index 50b8428113d..6456ad08924 100644
--- a/lib/gitlab/utils/strong_memoize.rb
+++ b/lib/gitlab/utils/strong_memoize.rb
@@ -30,10 +30,10 @@ module Gitlab
# end
# strong_memoize_attr :trigger_from_token
#
- # strong_memoize_attr :enabled?, :enabled
# def enabled?
# Feature.enabled?(:some_feature)
# end
+ # strong_memoize_attr :enabled?, :enabled
#
def strong_memoize(name)
key = ivar(name)
@@ -45,6 +45,16 @@ module Gitlab
end
end
+ def strong_memoize_with(name, *args)
+ container = strong_memoize(name) { {} }
+
+ if container.key?(args)
+ container[args]
+ else
+ container[args] = yield
+ end
+ end
+
def strong_memoized?(name)
instance_variable_defined?(ivar(name))
end
@@ -58,23 +68,8 @@ module Gitlab
def strong_memoize_attr(method_name, member_name = nil)
member_name ||= method_name
- if method_defined?(method_name) || private_method_defined?(method_name)
- StrongMemoize.send( # rubocop:disable GitlabSecurity/PublicSend
- :do_strong_memoize, self, method_name, member_name)
- else
- StrongMemoize.send( # rubocop:disable GitlabSecurity/PublicSend
- :queue_strong_memoize, self, method_name, member_name)
- end
- end
-
- def method_added(method_name)
- super
-
- if member_name = StrongMemoize
- .send(:strong_memoize_queue, self).delete(method_name) # rubocop:disable GitlabSecurity/PublicSend
- StrongMemoize.send( # rubocop:disable GitlabSecurity/PublicSend
- :do_strong_memoize, self, method_name, member_name)
- end
+ StrongMemoize.send( # rubocop:disable GitlabSecurity/PublicSend
+ :do_strong_memoize, self, method_name, member_name)
end
end
@@ -88,9 +83,10 @@ module Gitlab
#
# Depending on a type ensure that there's a single memory allocation
def ivar(name)
- if name.is_a?(Symbol)
+ case name
+ when Symbol
name.to_s.prepend("@").to_sym
- elsif name.is_a?(String)
+ when String
:"@#{name}"
else
raise ArgumentError, "Invalid type of '#{name}'"
@@ -100,14 +96,6 @@ module Gitlab
class <<self
private
- def strong_memoize_queue(klass)
- klass.instance_variable_get(:@strong_memoize_queue) || klass.instance_variable_set(:@strong_memoize_queue, {})
- end
-
- def queue_strong_memoize(klass, method_name, member_name)
- strong_memoize_queue(klass)[method_name] = member_name
- end
-
def do_strong_memoize(klass, method_name, member_name)
method = klass.instance_method(method_name)
diff --git a/lib/gitlab/web_hooks/recursion_detection.rb b/lib/gitlab/web_hooks/recursion_detection.rb
index 031d9ec6ec4..7e79283757f 100644
--- a/lib/gitlab/web_hooks/recursion_detection.rb
+++ b/lib/gitlab/web_hooks/recursion_detection.rb
@@ -41,7 +41,7 @@ module Gitlab
::Gitlab::Redis::SharedState.with do |redis|
redis.multi do |multi|
- multi.sadd(cache_key, hook.id)
+ multi.sadd?(cache_key, hook.id)
multi.expire(cache_key, TOUCH_CACHE_TTL)
end
end
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index 906439d5e71..0d5daeefe90 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -33,7 +33,12 @@ module Gitlab
GitalyServer: {
address: Gitlab::GitalyClient.address(repository.storage),
token: Gitlab::GitalyClient.token(repository.storage),
- features: Feature::Gitaly.server_feature_flags(repository.project)
+ features: Feature::Gitaly.server_feature_flags(
+ user: ::Feature::Gitaly.user_actor(user),
+ repository: repository,
+ project: ::Feature::Gitaly.project_actor(repository.container),
+ group: ::Feature::Gitaly.group_actor(repository.container)
+ )
}
}
@@ -252,7 +257,12 @@ module Gitlab
{
address: Gitlab::GitalyClient.address(repository.shard),
token: Gitlab::GitalyClient.token(repository.shard),
- features: Feature::Gitaly.server_feature_flags(repository.project)
+ features: Feature::Gitaly.server_feature_flags(
+ user: ::Feature::Gitaly.user_actor,
+ repository: repository,
+ project: ::Feature::Gitaly.project_actor(repository.container),
+ group: ::Feature::Gitaly.group_actor(repository.container)
+ )
}
end
diff --git a/lib/object_storage/direct_upload.rb b/lib/object_storage/direct_upload.rb
index d092cd56e46..9449e51b053 100644
--- a/lib/object_storage/direct_upload.rb
+++ b/lib/object_storage/direct_upload.rb
@@ -66,6 +66,8 @@ module ObjectStorage
workhorse_aws_hash
elsif config.azure?
workhorse_azure_hash
+ elsif Feature.enabled?(:workhorse_google_client) && config.google?
+ workhorse_google_hash
else
{}
end
@@ -111,6 +113,23 @@ module ObjectStorage
url
end
+ def workhorse_google_hash
+ {
+ UseWorkhorseClient: use_workhorse_google_client?,
+ RemoteTempObjectID: object_name,
+ ObjectStorage: {
+ Provider: 'Google',
+ GoCloudConfig: {
+ URL: google_gocloud_url
+ }
+ }
+ }
+ end
+
+ def google_gocloud_url
+ "gs://#{bucket_name}"
+ end
+
def use_workhorse_s3_client?
return false unless config.use_iam_profile? || config.consolidated_settings?
# The Golang AWS SDK does not support V2 signatures
@@ -119,6 +138,15 @@ module ObjectStorage
true
end
+ def use_workhorse_google_client?
+ return false unless config.consolidated_settings?
+ return true if credentials[:google_application_default]
+ return true if credentials[:google_json_key_location]
+ return true if credentials[:google_json_key_string]
+
+ false
+ end
+
def provider
credentials[:provider].to_s
end
diff --git a/lib/product_analytics/collector_app.rb b/lib/product_analytics/collector_app.rb
deleted file mode 100644
index 1008d2f264c..00000000000
--- a/lib/product_analytics/collector_app.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-# frozen_string_literal: true
-
-module ProductAnalytics
- class CollectorApp
- def call(env)
- request = Rack::Request.new(env)
- params = request.params
-
- return not_found unless EventParams.has_required_params?(params)
-
- # Product analytics feature is behind a flag and is disabled by default.
- # We expect limited amount of projects with this feature enabled in first release.
- # Since collector has no authentication we temporary prevent recording of events
- # for project without the feature enabled. During increase of feature adoption, this
- # check will be removed for better performance.
- project = Project.find(params['aid'].to_i)
- return not_found unless Feature.enabled?(:product_analytics, project)
-
- # Snowplow tracker has own format of events.
- # We need to convert them to match the schema of our database.
- event_params = EventParams.parse_event_params(params)
-
- if ProductAnalyticsEvent.create(event_params)
- ok
- else
- not_found
- end
- rescue ActiveRecord::InvalidForeignKey, ActiveRecord::RecordNotFound
- not_found
- end
-
- def ok
- [200, {}, []]
- end
-
- def not_found
- [404, {}, []]
- end
- end
-end
diff --git a/lib/rouge/formatters/html_gitlab.rb b/lib/rouge/formatters/html_gitlab.rb
index 9e76225fc54..436739bed12 100644
--- a/lib/rouge/formatters/html_gitlab.rb
+++ b/lib/rouge/formatters/html_gitlab.rb
@@ -12,6 +12,8 @@ module Rouge
def initialize(options = {})
@tag = options[:tag]
@line_number = options[:line_number] || 1
+ @ellipsis_indexes = options[:ellipsis_indexes] || []
+ @ellipsis_svg = options[:ellipsis_svg]
end
def stream(tokens)
@@ -26,6 +28,8 @@ module Rouge
yield highlight_unicode_control_characters(span(token, value.chomp! || value))
end
+ yield ellipsis if @ellipsis_indexes.include?(@line_number - 1) && @ellipsis_svg.present?
+
yield %(</span>)
@line_number += 1
@@ -34,6 +38,10 @@ module Rouge
private
+ def ellipsis
+ %(<span class="gl-px-2 gl-rounded-base gl-mx-2 gl-bg-gray-100 gl-cursor-help has-tooltip" title="Content has been trimmed">#{@ellipsis_svg}</span>)
+ end
+
def highlight_unicode_control_characters(text)
text.gsub(Gitlab::Unicode::BIDI_REGEXP) do |char|
%(<span class="unicode-bidi has-tooltip" data-toggle="tooltip" title="#{Gitlab::Unicode.bidi_warning}">#{char}</span>)
diff --git a/lib/sbom/package_url.rb b/lib/sbom/package_url.rb
new file mode 100644
index 00000000000..d8f4e876b82
--- /dev/null
+++ b/lib/sbom/package_url.rb
@@ -0,0 +1,122 @@
+# frozen_string_literal: true
+
+# MIT License
+#
+# Copyright (c) 2021 package-url
+# Portions Copyright 2022 Gitlab B.V.
+#
+# 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.
+
+module Sbom
+ # A package URL, or _purl_, is a URL string used to
+ # identify and locate a software package in a mostly universal and uniform way
+ # across programing languages, package managers, packaging conventions, tools,
+ # APIs and databases.
+ #
+ # A purl is a URL composed of seven components:
+ #
+ # ```
+ # scheme:type/namespace/name@version?qualifiers#subpath
+ # ```
+ #
+ # For example,
+ # the package URL for this Ruby package at version 0.1.0 is
+ # `pkg:ruby/mattt/packageurl-ruby@0.1.0`.
+ #
+ # More details on the package URL format can be found in the purl specification:
+ # https://github.com/package-url/purl-spec/blob/0b1559f76b79829e789c4f20e6d832c7314762c5/PURL-SPECIFICATION.rst
+ class PackageUrl
+ # Raised when attempting to parse an invalid package URL string.
+ # @see #parse
+ InvalidPackageUrl = Class.new(ArgumentError)
+
+ # The URL scheme, which has a constant value of `"pkg"`.
+ def scheme
+ 'pkg'
+ end
+
+ # The package type or protocol, such as `"gem"`, `"npm"`, and `"github"`.
+ attr_reader :type
+
+ # A name prefix, specific to the type of package.
+ # For example, an npm scope, a Docker image owner, or a GitHub user.
+ attr_reader :namespace
+
+ # The name of the package.
+ attr_reader :name
+
+ # The version of the package.
+ attr_reader :version
+
+ # Extra qualifying data for a package, specific to the type of package.
+ # For example, the operating system or architecture.
+ attr_reader :qualifiers
+
+ # An extra subpath within a package, relative to the package root.
+ attr_reader :subpath
+
+ # Constructs a package URL from its components
+ # @param type [String] The package type or protocol.
+ # @param namespace [String] A name prefix, specific to the type of package.
+ # @param name [String] The name of the package.
+ # @param version [String] The version of the package.
+ # @param qualifiers [Hash] Extra qualifying data for a package, specific to the type of package.
+ # @param subpath [String] An extra subpath within a package, relative to the package root.
+ def initialize(type:, name:, namespace: nil, version: nil, qualifiers: nil, subpath: nil)
+ @type = type&.downcase
+ @namespace = namespace
+ @name = name
+ @version = version
+ @qualifiers = qualifiers
+ @subpath = subpath
+
+ ArgumentValidator.new(self).validate!
+ end
+
+ # Creates a new PackageUrl from a string.
+ # @param [String] string The package URL string.
+ # @raise [InvalidPackageUrl] If the string is not a valid package URL.
+ # @return [PackageUrl]
+ def self.parse(string)
+ Decoder.new(string).decode!
+ end
+
+ # Returns a hash containing the
+ # scheme, type, namespace, name, version, qualifiers, and subpath components
+ # of the package URL.
+ def to_h
+ {
+ scheme: scheme,
+ type: @type,
+ namespace: @namespace,
+ name: @name,
+ version: @version,
+ qualifiers: @qualifiers,
+ subpath: @subpath
+ }
+ end
+
+ # Returns a string representation of the package URL.
+ # Package URL representations are created according to the instructions from
+ # https://github.com/package-url/purl-spec/blob/0b1559f76b79829e789c4f20e6d832c7314762c5/PURL-SPECIFICATION.rst#how-to-build-purl-string-from-its-components.
+ def to_s
+ Encoder.new(self).encode
+ end
+ end
+end
diff --git a/lib/sbom/package_url/argument_validator.rb b/lib/sbom/package_url/argument_validator.rb
new file mode 100644
index 00000000000..639ee9f89b6
--- /dev/null
+++ b/lib/sbom/package_url/argument_validator.rb
@@ -0,0 +1,90 @@
+# frozen_string_literal: true
+
+module Sbom
+ class PackageUrl
+ class ArgumentValidator
+ QUALIFIER_KEY_REGEXP = /^[A-Za-z\d._-]+$/.freeze
+ START_WITH_NUMBER_REGEXP = /^\d/.freeze
+
+ def initialize(package)
+ @type = package.type
+ @namespace = package.namespace
+ @name = package.name
+ @version = package.version
+ @qualifiers = package.qualifiers
+ @errors = []
+ end
+
+ def validate!
+ validate_type
+ validate_name
+ validate_qualifiers
+ validate_by_type
+
+ raise ArgumentError, formatted_errors if invalid?
+ end
+
+ private
+
+ def invalid?
+ errors.present?
+ end
+
+ attr_reader :type, :namespace, :name, :version, :qualifiers, :errors
+
+ def formatted_errors
+ errors.join(', ')
+ end
+
+ def validate_type
+ errors.push('Type is required') if type.blank?
+ end
+
+ def validate_name
+ errors.push('Name is required') if name.blank?
+ end
+
+ def validate_qualifiers
+ return if qualifiers.nil?
+
+ keys = qualifiers.keys
+ errors.push('Qualifier keys must be unique') unless keys.uniq.size == keys.size
+
+ keys.each do |key|
+ errors.push(key_error(key, 'contains illegal characters')) unless key.match?(QUALIFIER_KEY_REGEXP)
+ errors.push(key_error(key, 'may not start with a number')) if key.match?(START_WITH_NUMBER_REGEXP)
+ end
+ end
+
+ def key_error(key, text)
+ "Qualifier key `#{key}` #{text}"
+ end
+
+ def validate_by_type
+ case type
+ when 'conan'
+ validate_conan
+ when 'cran'
+ validate_cran
+ when 'swift'
+ validate_swift
+ end
+ end
+
+ def validate_conan
+ return unless namespace.blank? ^ (qualifiers.nil? || qualifiers.exclude?('channel'))
+
+ errors.push('Conan packages require the channel be present if published in a namespace and vice-versa')
+ end
+
+ def validate_cran
+ errors.push('Cran packages require a version') if version.blank?
+ end
+
+ def validate_swift
+ errors.push('Swift packages require a namespace') if namespace.blank?
+ errors.push('Swift packages require a version') if version.blank?
+ end
+ end
+ end
+end
diff --git a/lib/sbom/package_url/decoder.rb b/lib/sbom/package_url/decoder.rb
new file mode 100644
index 00000000000..ceadc36660c
--- /dev/null
+++ b/lib/sbom/package_url/decoder.rb
@@ -0,0 +1,181 @@
+# frozen_string_literal: true
+
+# MIT License
+#
+# Copyright (c) 2021 package-url
+# Portions Copyright 2022 Gitlab B.V.
+#
+# 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.
+
+module Sbom
+ class PackageUrl
+ class Decoder
+ include StringUtils
+
+ def initialize(string)
+ @string = string
+ end
+
+ def decode!
+ raise ArgumentError, "expected String but given #{@string.class}" unless @string.is_a?(::String)
+
+ decode_subpath!
+ decode_qualifiers!
+ decode_scheme!
+ decode_type!
+ decode_version!
+ decode_name!
+ decode_namespace!
+
+ begin
+ PackageUrl.new(
+ type: @type,
+ name: @name,
+ namespace: @namespace,
+ version: @version,
+ qualifiers: @qualifiers,
+ subpath: @subpath
+ )
+ rescue ArgumentError => e
+ raise InvalidPackageUrl, e.message
+ end
+ end
+
+ private
+
+ def decode_subpath!
+ # Split the purl string once from right on '#'
+ # Given the string: `scheme:type/namespace/name@version?qualifiers#subpath`
+ # - The left side is the remainder: `scheme:type/namespace/name@version?qualifiers`
+ # - The right side will be parsed as the subpath: `subpath`
+ @subpath, @string = partition(@string, '#', from: :right) do |subpath|
+ decode_segments(subpath) do |segment|
+ # Discard segments which are blank, `.`, or `..`
+ segment.empty? || segment == '.' || segment == '..'
+ end
+ end
+ end
+
+ def decode_qualifiers!
+ # Split the remainder once from right on '?'
+ # Given string: `scheme:type/namespace/name@version?qualifiers`
+ # - The left side is the remainder: `scheme:type/namespace/name@version`
+ # - The right side is the qualifiers string: `qualifiers`
+ @qualifiers, @string = partition(@string, '?', from: :right) do |qualifiers|
+ parse_qualifiers(qualifiers)
+ end
+ end
+
+ def decode_scheme!
+ # Split the remainder once from left on ':'
+ # Given the string: `scheme:type/namespace/name@version`
+ # - The left side lowercased is the scheme: `scheme`
+ # - The right side is the remainder: `type/namespace/name@version`
+ @scheme, @string = partition(@string, ':', from: :left)
+ raise InvalidPackageUrl, 'invalid or missing "pkg:" URL scheme' unless @scheme == 'pkg'
+ end
+
+ def decode_type!
+ # Strip the remainder from leading and trailing '/'
+ @string = strip(@string, '/')
+ # Split this once from left on '/'
+ # Given the string: `type/namespace/name@version`
+ # - The left side lowercased is the type: `type`
+ # - The right side is the remainder: `namespace/name@version`
+ @type, @string = partition(@string, '/', from: :left, &:downcase)
+ end
+
+ def decode_version!
+ # Split the remainder once from right on '@'
+ # Given the string: `namespace/name@version`
+ # - The left side is the remainder: `namespace/name`
+ # - The right side is the version: `version`
+ # - The version must be URI decoded
+ @version, @string = partition(@string, '@', from: :right) do |version|
+ URI.decode_www_form_component(version)
+ end
+ end
+
+ def decode_name!
+ # Split the remainder once from right on '/'
+ # Given the string: `namespace/name`
+ # - The left side is the remainder: `namespace`
+ # - The right size is the name: `name`
+ # - The name must be URI decoded
+ @name, @string = partition(@string, '/', from: :right, require_separator: false) do |name|
+ decoded_name = URI.decode_www_form_component(name)
+ Normalizer.new(type: @type, text: decoded_name).normalize_name
+ end
+ end
+
+ def decode_namespace!
+ # If there is anything remaining, this is the namespace.
+ # The namespace may contain multiple segments delimited by `/`.
+ return if @string.blank?
+
+ @namespace = decode_segments(@string, &:empty?)
+ @namespace = Normalizer.new(type: @type, text: @namespace).normalize_namespace
+ end
+
+ def decode_segment(segment)
+ decoded = URI.decode_www_form_component(segment)
+
+ raise InvalidPackageUrl, 'slash-separated segments may not contain `/`' if decoded.include?('/')
+
+ decoded
+ end
+
+ def decode_segments(string)
+ string.split('/').filter_map do |segment|
+ next if block_given? && yield(segment)
+
+ decode_segment(segment)
+ end.join('/')
+ end
+
+ def parse_qualifiers(raw_qualifiers)
+ # - Split the qualifiers on '&'. Each part is a key=value pair
+ # - For each pair, split the key=value once from left on '=':
+ # - The key is the lowercase left side
+ # - The value is the percent-decoded right side
+ # - Discard any key/value pairs where the value is empty
+ # - If the key is checksums,
+ # split the value on ',' to create a list of checksums
+ # - This list of key/value is the qualifiers object
+ raw_qualifiers.split('&').each_with_object({}) do |pair, memo|
+ key, separator, value = pair.partition('=')
+
+ next if separator.empty?
+
+ key = key.downcase
+ value = URI.decode_www_form_component(value)
+
+ next if value.empty?
+
+ memo[key] = case key
+ when 'checksums'
+ value.split(',')
+ else
+ value
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sbom/package_url/encoder.rb b/lib/sbom/package_url/encoder.rb
new file mode 100644
index 00000000000..9cf05095571
--- /dev/null
+++ b/lib/sbom/package_url/encoder.rb
@@ -0,0 +1,137 @@
+# frozen_string_literal: true
+
+# MIT License
+#
+# Copyright (c) 2021 package-url
+# Portions Copyright 2022 Gitlab B.V.
+#
+# 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.
+
+module Sbom
+ class PackageUrl
+ class Encoder
+ include StringUtils
+
+ def initialize(package)
+ @type = package.type
+ @namespace = package.namespace
+ @name = package.name
+ @version = package.version
+ @qualifiers = package.qualifiers
+ @subpath = package.subpath
+ @io = StringIO.new
+ end
+
+ def encode
+ encode_scheme!
+ encode_type!
+ encode_name!
+ encode_version!
+ encode_qualifiers!
+ encode_subpath!
+
+ io.string
+ end
+
+ private
+
+ attr_reader :io
+
+ def encode_scheme!
+ io.write('pkg:')
+ end
+
+ def encode_type!
+ # Append the type string to the purl as a lowercase ASCII string
+ # Append '/' to the purl
+ io.write(@type)
+ io.write('/')
+ end
+
+ def encode_name!
+ # If the namespace is empty:
+ # - Apply type-specific normalization to the name if needed
+ # - UTF-8-encode the name if needed in your programming language
+ # - Append the percent-encoded name to the purl
+ #
+ # If the namespace is not empty:
+ # - Strip the namespace from leading and trailing '/'
+ # - Split on '/' as segments
+ # - Apply type-specific normalization to each segment if needed
+ # - UTF-8-encode each segment if needed in your programming language
+ # - Percent-encode each segment
+ # - Join the segments with '/'
+ # - Append this to the purl
+ # - Append '/' to the purl
+ # - Strip the name from leading and trailing '/'
+ # - Apply type-specific normalization to the name if needed
+ # - UTF-8-encode the name if needed in your programming language
+ # - Append the percent-encoded name to the purl
+ if @namespace.nil?
+ io.write(URI.encode_www_form_component(@name, Encoding::UTF_8))
+ else
+ io.write(encode_segments(@namespace, &:empty?))
+ io.write('/')
+ io.write(URI.encode_www_form_component(strip(@name, '/'), Encoding::UTF_8))
+ end
+ end
+
+ def encode_version!
+ return if @version.nil?
+
+ # - Append '@' to the purl
+ # - UTF-8-encode the version if needed in your programming language
+ # - Append the percent-encoded version to the purl
+ io.write('@')
+ io.write(URI.encode_www_form_component(@version, Encoding::UTF_8))
+ end
+
+ def encode_qualifiers!
+ return if @qualifiers.nil? || encoded_qualifiers.empty?
+
+ io.write('?')
+ io.write(encoded_qualifiers)
+ end
+
+ def encoded_qualifiers
+ @encoded_qualifiers ||= @qualifiers.filter_map do |key, value|
+ next if value.empty?
+
+ next "#{key.downcase}=#{value.join(',')}" if key == 'checksums' && value.is_a?(::Array)
+
+ "#{key.downcase}=#{URI.encode_www_form_component(value, Encoding::UTF_8)}"
+ end.sort.join('&')
+ end
+
+ def encode_subpath!
+ return if @subpath.nil? || encoded_subpath.empty?
+
+ io.write('#')
+ io.write(encoded_subpath)
+ end
+
+ def encoded_subpath
+ @encoded_subpath ||= encode_segments(@subpath) do |segment|
+ # Discard segments which are blank, `.`, or `..`
+ segment.empty? || segment == '.' || segment == '..'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sbom/package_url/normalizer.rb b/lib/sbom/package_url/normalizer.rb
new file mode 100644
index 00000000000..663df6f72a5
--- /dev/null
+++ b/lib/sbom/package_url/normalizer.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+module Sbom
+ class PackageUrl
+ class Normalizer
+ def initialize(type:, text:)
+ @type = type
+ @text = text
+ end
+
+ def normalize_namespace
+ return if text.nil?
+
+ normalize
+ end
+
+ def normalize_name
+ raise ArgumentError, 'Name is required' if text.nil?
+
+ normalize
+ end
+
+ private
+
+ def normalize
+ case type
+ when 'bitbucket', 'github'
+ downcase
+ when 'pypi'
+ normalize_pypi
+ else
+ text
+ end
+ end
+
+ attr_reader :type, :text
+
+ def downcase
+ text.downcase
+ end
+
+ def normalize_pypi
+ downcase.tr('_', '-')
+ end
+ end
+ end
+end
diff --git a/lib/sbom/package_url/string_utils.rb b/lib/sbom/package_url/string_utils.rb
new file mode 100644
index 00000000000..c1ea8de95b2
--- /dev/null
+++ b/lib/sbom/package_url/string_utils.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+# MIT License
+#
+# Copyright (c) 2021 package-url
+# Portions Copyright 2022 Gitlab B.V.
+#
+# 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.
+
+module Sbom
+ class PackageUrl
+ module StringUtils
+ private
+
+ def strip(string, char)
+ string = string.delete_prefix(char) while string.start_with?(char)
+ string = string.delete_suffix(char) while string.end_with?(char)
+ string
+ end
+
+ def split_segments(string)
+ strip(string, '/').split('/')
+ end
+
+ def encode_segments(string)
+ return '' if string.nil?
+
+ split_segments(string).map do |segment|
+ next if block_given? && yield(segment)
+
+ URI.encode_www_form_component(segment)
+ end.join('/')
+ end
+
+ # Partition the given string on the separator.
+ # The side being partitioned from is returned as the value,
+ # with the opposing side being returned as the remainder.
+ #
+ # If a block is given, then the (value, remainder) are given
+ # to the block, and the return value of the block is used as the value.
+ #
+ # If `require_separator` is true, then a nil value will be returned
+ # if the separator is not present.
+ def partition(string, sep, from: :left, require_separator: true)
+ value, separator, remainder = if from == :left
+ left, separator, right = string.partition(sep)
+ [left, separator, right]
+ else
+ left, separator, right = string.rpartition(sep)
+ [right, separator, left]
+ end
+
+ return [nil, value] if separator.empty? && require_separator
+
+ value = yield(value) if block_given?
+
+ [value, remainder]
+ end
+ end
+ end
+end
diff --git a/lib/serializers/symbolized_json.rb b/lib/serializers/symbolized_json.rb
deleted file mode 100644
index 78192ce3132..00000000000
--- a/lib/serializers/symbolized_json.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-module Serializers
- # Make the resulting hash have deep symbolized keys
- class SymbolizedJson
- class << self
- def dump(obj)
- obj
- end
-
- def load(data)
- return if data.nil?
-
- Gitlab::Utils.deep_symbolized_access(data)
- end
- end
- end
-end
diff --git a/lib/sidebars/groups/menus/observability_menu.rb b/lib/sidebars/groups/menus/observability_menu.rb
index b479ff3c492..656142375af 100644
--- a/lib/sidebars/groups/menus/observability_menu.rb
+++ b/lib/sidebars/groups/menus/observability_menu.rb
@@ -4,9 +4,11 @@ module Sidebars
module Groups
module Menus
class ObservabilityMenu < ::Sidebars::Menu
- override :link
- def link
- group_observability_index_path(context.group)
+ override :configure_menu_items
+ def configure_menu_items
+ add_item(dashboards_menu_item)
+ add_item(explore_menu_item)
+ add_item(manage_menu_item)
end
override :title
@@ -24,9 +26,33 @@ module Sidebars
can?(context.current_user, :read_observability, context.group)
end
- override :active_routes
- def active_routes
- { controller: :observability, path: 'groups#observability' }
+ private
+
+ def dashboards_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Dashboards'),
+ link: group_observability_dashboards_path(context.group),
+ active_routes: { path: 'groups/observability#dashboards' },
+ item_id: :dashboards
+ )
+ end
+
+ def explore_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Explore'),
+ link: group_observability_explore_path(context.group),
+ active_routes: { path: 'groups/observability#explore' },
+ item_id: :explore
+ )
+ end
+
+ def manage_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Manage Dashboards'),
+ link: group_observability_manage_path(context.group),
+ active_routes: { path: 'groups/observability#manage' },
+ item_id: :manage
+ )
end
end
end
diff --git a/lib/sidebars/groups/menus/settings_menu.rb b/lib/sidebars/groups/menus/settings_menu.rb
index df170670aab..ede195a8e59 100644
--- a/lib/sidebars/groups/menus/settings_menu.rb
+++ b/lib/sidebars/groups/menus/settings_menu.rb
@@ -20,6 +20,10 @@ module Sidebars
# Push Rules are the only group setting that can also be edited by maintainers.
# Create an empty sub-menu here and EE adds Repository menu item (with only Push Rules).
return true
+ elsif Gitlab.ee? && can?(context.current_user, :read_billing, context.group)
+ # Billing is the only group setting that is visible to auditors.
+ # Create an empty sub-menu here and EE adds Settings menu item (with only Billing).
+ return true
end
false
diff --git a/lib/sidebars/projects/menus/deployments_menu.rb b/lib/sidebars/projects/menus/deployments_menu.rb
index 24e58e71023..9904d533f47 100644
--- a/lib/sidebars/projects/menus/deployments_menu.rb
+++ b/lib/sidebars/projects/menus/deployments_menu.rb
@@ -6,8 +6,8 @@ module Sidebars
class DeploymentsMenu < ::Sidebars::Menu
override :configure_menu_items
def configure_menu_items
- add_item(feature_flags_menu_item)
add_item(environments_menu_item)
+ add_item(feature_flags_menu_item)
add_item(releases_menu_item)
true
diff --git a/lib/sidebars/projects/menus/infrastructure_menu.rb b/lib/sidebars/projects/menus/infrastructure_menu.rb
index 2181d89262b..a8ac3d10f83 100644
--- a/lib/sidebars/projects/menus/infrastructure_menu.rb
+++ b/lib/sidebars/projects/menus/infrastructure_menu.rb
@@ -6,7 +6,7 @@ module Sidebars
class InfrastructureMenu < ::Sidebars::Menu
override :configure_menu_items
def configure_menu_items
- return false unless context.project.feature_available?(:operations, context.current_user)
+ return false unless feature_enabled?
add_item(kubernetes_menu_item)
add_item(terraform_menu_item)
@@ -34,6 +34,14 @@ module Sidebars
private
+ def feature_enabled?
+ if ::Feature.enabled?(:split_operations_visibility_permissions, context.project)
+ context.project.feature_available?(:infrastructure, context.current_user)
+ else
+ context.project.feature_available?(:operations, context.current_user)
+ end
+ end
+
def kubernetes_menu_item
unless can?(context.current_user, :read_cluster, context.project)
return ::Sidebars::NilMenuItem.new(item_id: :kubernetes)
diff --git a/lib/sidebars/projects/menus/monitor_menu.rb b/lib/sidebars/projects/menus/monitor_menu.rb
index ecd062f333e..035634702db 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(product_analytics_menu_item)
true
end
@@ -101,20 +100,6 @@ module Sidebars
item_id: :incidents
)
end
-
- def product_analytics_menu_item
- if Feature.disabled?(:product_analytics, context.project) ||
- !can?(context.current_user, :read_product_analytics, context.project)
- return ::Sidebars::NilMenuItem.new(item_id: :product_analytics)
- end
-
- ::Sidebars::MenuItem.new(
- title: _('Product Analytics'),
- link: project_product_analytics_path(context.project),
- active_routes: { controller: :product_analytics },
- item_id: :product_analytics
- )
- end
end
end
end
diff --git a/lib/tasks/contracts/pipelines.rake b/lib/tasks/contracts/pipelines.rake
index 3163791460f..5a8d7791233 100644
--- a/lib/tasks/contracts/pipelines.rake
+++ b/lib/tasks/contracts/pipelines.rake
@@ -24,9 +24,13 @@ namespace :contracts do
end
Pact::VerificationTask.new(:get_pipeline_header_data) do |pact|
+ # pact.uri(
+ # "http://localhost:9292/pacts/provider/GET%20pipeline%20header%20data/consumer/Pipelines%23show/latest",
+ # pact_helper: "#{provider}/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb"
+ # )
pact.uri(
"#{contracts}/show/pipelines#show-get_pipeline_header_data.json",
- pact_helper: "#{provider}/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb"
+ pact_helper: "#{provider}/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb"
)
end
diff --git a/lib/tasks/gitlab/assets.rake b/lib/tasks/gitlab/assets.rake
index b58d9473794..12a8cb01e9e 100644
--- a/lib/tasks/gitlab/assets.rake
+++ b/lib/tasks/gitlab/assets.rake
@@ -84,7 +84,7 @@ namespace :gitlab do
puts "Assets SHA256 for `HEAD`: #{Tasks::Gitlab::Assets.head_assets_sha256.inspect}"
if Tasks::Gitlab::Assets.head_assets_sha256 != Tasks::Gitlab::Assets.master_assets_sha256
- FileUtils.rm_r(Tasks::Gitlab::Assets::PUBLIC_ASSETS_DIR) if Dir.exist?(Tasks::Gitlab::Assets::PUBLIC_ASSETS_DIR)
+ FileUtils.rm_rf([Tasks::Gitlab::Assets::PUBLIC_ASSETS_DIR] + Dir.glob('app/assets/javascripts/locale/**/app.js'))
# gettext:po_to_json needs to run before rake:assets:precompile because
# app/assets/javascripts/locale/**/app.js are pre-compiled by Sprockets
@@ -127,20 +127,20 @@ namespace :gitlab do
# rewrite the corresponding gzip file (if it exists)
gzip = "#{file}.gz"
- if File.exist?(gzip)
- puts "Fixing #{gzip}"
+ next unless File.exist?(gzip)
- FileUtils.rm(gzip)
- mtime = File.stat(file).mtime
+ puts "Fixing #{gzip}"
- File.open(gzip, 'wb+') do |f|
- gz = Zlib::GzipWriter.new(f, Zlib::BEST_COMPRESSION)
- gz.mtime = mtime
- gz.write IO.binread(file)
- gz.close
+ FileUtils.rm(gzip)
+ mtime = File.stat(file).mtime
- File.utime(mtime, mtime, f.path)
- end
+ File.open(gzip, 'wb+') do |f|
+ gz = Zlib::GzipWriter.new(f, Zlib::BEST_COMPRESSION)
+ gz.mtime = mtime
+ gz.write IO.binread(file)
+ gz.close
+
+ File.utime(mtime, mtime, f.path)
end
end
end
diff --git a/lib/tasks/gitlab/db/validate_config.rake b/lib/tasks/gitlab/db/validate_config.rake
index bf9ebc56486..b3c98e91d17 100644
--- a/lib/tasks/gitlab/db/validate_config.rake
+++ b/lib/tasks/gitlab/db/validate_config.rake
@@ -64,15 +64,15 @@ namespace :gitlab do
next unless identifier
connections_with_tasks = connections.select { |connection| connection[:database_tasks?] }
- if connections_with_tasks.many?
- names = connections_with_tasks.pluck(:name)
-
- warnings << "- Many configurations (#{names.join(', ')}) " \
- "share the same database (#{identifier}). " \
- "This will result in failures provisioning or migrating this database. " \
- "Ensure that additional databases are configured " \
- "with 'database_tasks: false' or are pointing to a dedicated database host."
- end
+ next unless connections_with_tasks.many?
+
+ names = connections_with_tasks.pluck(:name)
+
+ warnings << "- Many configurations (#{names.join(', ')}) " \
+ "share the same database (#{identifier}). " \
+ "This will result in failures provisioning or migrating this database. " \
+ "Ensure that additional databases are configured " \
+ "with 'database_tasks: false' or are pointing to a dedicated database host."
end
# Each configuration with `database_tasks: false` should share the database with `main:`
diff --git a/lib/tasks/gitlab/openapi.rake b/lib/tasks/gitlab/openapi.rake
index fd067a1bf0b..dee365de11c 100644
--- a/lib/tasks/gitlab/openapi.rake
+++ b/lib/tasks/gitlab/openapi.rake
@@ -9,6 +9,13 @@ end
namespace :gitlab do
namespace :openapi do
+ task :validate do
+ raise 'This task can only be run in the development environment' unless Rails.env.development?
+
+ success = system('yarn swagger:validate doc/api/openapi/openapi_v2.yaml')
+ abort('Validation of swagger document failed') unless success
+ end
+
task :generate do
raise 'This task can only be run in the development environment' unless Rails.env.development?
@@ -19,5 +26,7 @@ namespace :gitlab do
File.write("doc/api/openapi/openapi_v2.yaml", yaml_content)
end
+
+ task generate_and_check: [:generate, :validate]
end
end
diff --git a/lib/tasks/gitlab/seed.rake b/lib/tasks/gitlab/seed.rake
index 7b9c57b1876..8437ae0a31e 100644
--- a/lib/tasks/gitlab/seed.rake
+++ b/lib/tasks/gitlab/seed.rake
@@ -2,31 +2,37 @@
namespace :gitlab do
namespace :seed do
- desc "GitLab | Seed | Seeds issues"
- task :issues, [:project_full_path, :backfill_weeks, :average_issues_per_week] => :environment do |t, args|
- args.with_defaults(backfill_weeks: 5, average_issues_per_week: 2)
+ def projects_from_args(args)
+ full_path = args.project_full_path
- projects =
- if args.project_full_path
- project = Project.find_by_full_path(args.project_full_path)
+ if full_path
+ project = Project.find_by_full_path(full_path)
- unless project
- error_message = "Project '#{args.project_full_path}' does not exist!"
- potential_projects = Project.search(args.project_full_path)
+ unless project
+ error_message = "Project '#{full_path}' does not exist!"
+ potential_projects = Project.search(full_path)
- if potential_projects.present?
- error_message += " Did you mean '#{potential_projects.first.full_path}'?"
- end
-
- puts error_message.color(:red)
- exit 1
+ if potential_projects.present?
+ error_message += " Did you mean '#{potential_projects.first.full_path}'?"
end
- [project]
- else
- Project.not_mass_generated.find_each
+ puts error_message.color(:red)
+ exit 1
end
+ [project]
+ else
+ scope = Project.respond_to?(:not_mass_generated) ? Project.not_mass_generated : Project
+ scope.find_each
+ end
+ end
+
+ desc "GitLab | Seed | Seeds issues"
+ task :issues, [:project_full_path, :backfill_weeks, :average_issues_per_week] => :environment do |t, args|
+ args.with_defaults(backfill_weeks: 5, average_issues_per_week: 2)
+
+ projects = projects_from_args(args)
+
projects.each do |project|
puts "\nSeeding issues for the '#{project.full_path}' project"
seeder = Quality::Seeders::Issues.new(project: project)
@@ -70,5 +76,17 @@ namespace :gitlab do
puts "\n#{epics} epics created!"
end
end
+
+ desc "GitLab | Seed | Seed a project with vulnerabilities"
+ task :vulnerabilities, [:project_full_path] => :environment do |t, args|
+ projects = projects_from_args(args)
+
+ projects.each do |project|
+ puts "\nSeeding vulnerabilities for the '#{project.full_path}' project"
+ seeder = Quality::Seeders::Vulnerabilities.new(project)
+ seeder.seed!
+ puts "\nDone."
+ end
+ end
end
end
diff --git a/lib/tasks/gitlab/sidekiq.rake b/lib/tasks/gitlab/sidekiq.rake
index 10492e183c5..dc472305304 100644
--- a/lib/tasks/gitlab/sidekiq.rake
+++ b/lib/tasks/gitlab/sidekiq.rake
@@ -10,15 +10,22 @@ namespace :gitlab do
desc 'GitLab | Sidekiq | Migrate jobs in the scheduled set to new queue names'
task schedule: :environment do
::Gitlab::SidekiqMigrateJobs
- .new('schedule', logger: Logger.new($stdout))
- .execute(::Gitlab::SidekiqConfig.worker_queue_mappings)
+ .new(::Gitlab::SidekiqConfig.worker_queue_mappings, logger: Logger.new($stdout) )
+ .migrate_set('schedule')
end
desc 'GitLab | Sidekiq | Migrate jobs in the retry set to new queue names'
task retry: :environment do
::Gitlab::SidekiqMigrateJobs
- .new('retry', logger: Logger.new($stdout))
- .execute(::Gitlab::SidekiqConfig.worker_queue_mappings)
+ .new(::Gitlab::SidekiqConfig.worker_queue_mappings, logger: Logger.new($stdout) )
+ .migrate_set('retry')
+ end
+
+ desc 'GitLab | Sidekiq | Migrate jobs in queues outside of routing rules'
+ task queued: :environment do
+ ::Gitlab::SidekiqMigrateJobs
+ .new(::Gitlab::SidekiqConfig.worker_queue_mappings, logger: Logger.new($stdout) )
+ .migrate_queues
end
end
diff --git a/lib/tasks/gitlab/tw/codeowners.rake b/lib/tasks/gitlab/tw/codeowners.rake
index fd9c7114979..7a2dee3e2e4 100644
--- a/lib/tasks/gitlab/tw/codeowners.rake
+++ b/lib/tasks/gitlab/tw/codeowners.rake
@@ -28,6 +28,7 @@ namespace :tw do
CodeOwnerRule.new('Compliance', '@eread'),
CodeOwnerRule.new('Composition Analysis', '@rdickenson'),
CodeOwnerRule.new('Configure', '@phillipwells'),
+ CodeOwnerRule.new('Container Registry', '@claytoncornell'),
CodeOwnerRule.new('Contributor Experience', '@eread'),
CodeOwnerRule.new('Conversion', '@kpaizee'),
CodeOwnerRule.new('Database', '@aqualls'),
@@ -37,7 +38,6 @@ namespace :tw do
CodeOwnerRule.new('Distribution (Omnibus)', '@axil'),
CodeOwnerRule.new('Documentation Guidelines', '@sselhorn'),
CodeOwnerRule.new('Dynamic Analysis', '@rdickenson'),
- CodeOwnerRule.new('Ecosystem', '@kpaizee'),
CodeOwnerRule.new('Editor', '@ashrafkhamis'),
CodeOwnerRule.new('Foundations', '@rdickenson'),
CodeOwnerRule.new('Fuzz Testing', '@rdickenson'),
@@ -48,11 +48,11 @@ namespace :tw do
CodeOwnerRule.new('Infrastructure', '@sselhorn'),
CodeOwnerRule.new('Integrations', '@ashrafkhamis'),
CodeOwnerRule.new('Knowledge', '@aqualls'),
- CodeOwnerRule.new('Application Performance', '@sselhorn'),
+ CodeOwnerRule.new('Application Performance', '@jglassman1'),
CodeOwnerRule.new('Monitor', '@msedlakjakubowski'),
- CodeOwnerRule.new('Observability', 'msedlakjakubowski'),
- CodeOwnerRule.new('Optimize', '@fneill'),
- CodeOwnerRule.new('Package', '@claytoncornell'),
+ CodeOwnerRule.new('Observability', '@msedlakjakubowski'),
+ CodeOwnerRule.new('Optimize', '@lciutacu'),
+ CodeOwnerRule.new('Package Registry', '@claytoncornell'),
CodeOwnerRule.new('Pipeline Authoring', '@marcel.amirault'),
CodeOwnerRule.new('Pipeline Execution', '@marcel.amirault'),
CodeOwnerRule.new('Pipeline Insights', '@marcel.amirault'),
@@ -66,19 +66,24 @@ namespace :tw do
CodeOwnerRule.new('Redirect', 'Redirect'),
CodeOwnerRule.new('Release', '@rdickenson'),
CodeOwnerRule.new('Respond', '@msedlakjakubowski'),
- CodeOwnerRule.new('Runner', '@sselhorn'),
- CodeOwnerRule.new('Pods', '@sselhorn'),
+ CodeOwnerRule.new('Runner', '@fneill'),
+ CodeOwnerRule.new('Runner SaaS', '@fneill'),
+ CodeOwnerRule.new('Pods', '@jglassman1'),
CodeOwnerRule.new('Security Policies', '@claytoncornell'),
CodeOwnerRule.new('Source Code', '@aqualls'),
CodeOwnerRule.new('Static Analysis', '@rdickenson'),
CodeOwnerRule.new('Style Guide', '@sselhorn'),
CodeOwnerRule.new('Testing', '@eread'),
CodeOwnerRule.new('Threat Insights', '@claytoncornell'),
+ CodeOwnerRule.new('Tutorials', '@kpaizee'),
CodeOwnerRule.new('Utilization', '@fneill'),
CodeOwnerRule.new('Vulnerability Research', '@claytoncornell'),
- CodeOwnerRule.new('Workspace', '@fneill')
+ CodeOwnerRule.new('Workspace', '@lciutacu')
].freeze
+ CODEOWNERS_BLOCK_BEGIN = "# Begin rake-managed-docs-block"
+ CODEOWNERS_BLOCK_END = "# End rake-managed-docs-block"
+
Document = Struct.new(:group, :redirect) do
def has_a_valid_group?
group && !redirect
@@ -122,7 +127,17 @@ namespace :tw do
end
end
- deduplicated_mappings.sort.each { |mapping| puts mapping }
+ new_docs_owners = deduplicated_mappings.sort.join("\n")
+
+ codeowners_path = Rails.root.join('.gitlab/CODEOWNERS')
+ current_codeowners_content = File.read(codeowners_path)
+
+ docs_replace_regex = Regexp.new("#{CODEOWNERS_BLOCK_BEGIN}\n[\\s\\S]*?\n#{CODEOWNERS_BLOCK_END}")
+
+ new_codeowners_content = current_codeowners_content
+ .gsub(docs_replace_regex, "#{CODEOWNERS_BLOCK_BEGIN}\n#{new_docs_owners}\n#{CODEOWNERS_BLOCK_END}")
+
+ File.write(codeowners_path, new_codeowners_content)
if errors.present?
puts "-----"
diff --git a/lib/tasks/gitlab/update_templates.rake b/lib/tasks/gitlab/update_templates.rake
index 07dd5ebeacb..d67ad340007 100644
--- a/lib/tasks/gitlab/update_templates.rake
+++ b/lib/tasks/gitlab/update_templates.rake
@@ -58,14 +58,14 @@ namespace :gitlab do
# extract a concrete commit for signing off what we actually downloaded
# this way we do the right thing even if the repository gets updated in the meantime
- get_commits_response = Gitlab::HTTP.get("https://gitlab.com/api/v4/projects/#{uri_encoded_project_path}/repository/commits",
+ get_commits_response = Gitlab::HTTP.get("#{template.project_host}/api/v4/projects/#{uri_encoded_project_path}/repository/commits",
query: { page: 1, per_page: 1 }
)
raise "Failed to retrieve latest commit for template '#{template.name}'" unless get_commits_response.success?
commit_sha = get_commits_response.parsed_response.dig(0, 'id')
- project_archive_uri = "https://gitlab.com/api/v4/projects/#{uri_encoded_project_path}/repository/archive.tar.gz?sha=#{commit_sha}"
+ project_archive_uri = "#{template.project_host}/api/v4/projects/#{uri_encoded_project_path}/repository/archive.tar.gz?sha=#{commit_sha}"
commit_message = <<~MSG
Initialized from '#{template.title}' project template
diff --git a/lib/unnested_in_filters/rewriter.rb b/lib/unnested_in_filters/rewriter.rb
index bf7be177a0d..ed1e4ce2d9f 100644
--- a/lib/unnested_in_filters/rewriter.rb
+++ b/lib/unnested_in_filters/rewriter.rb
@@ -120,15 +120,47 @@ module UnnestedInFilters
# "vulnerability_reads"."vulnerability_id" DESC
# LIMIT 20
#
+ # If one of the columns being used for filtering or ordering is the primary key,
+ # then the query will be further optimized to use an index-only scan for initial filtering
+ # before selecting all columns using the primary key.
+ #
+ # Using the prior query as an example, where `vulnerability_id` is the primary key,
+ # This will be rewritten to:
+ #
+ # SELECT
+ # "vulnerability_reads".*
+ # FROM
+ # "vulnerability_reads"
+ # WHERE
+ # "vulnerability_reads"."vulnerability_id"
+ # IN (
+ # SELECT
+ # "vulnerability_reads"."vulnerability_id"
+ # FROM
+ # unnest('{1, 4}'::smallint[]) AS "states" ("state"),
+ # LATERAL (
+ # SELECT
+ # "vulnerability_reads"."vulnerability_id"
+ # FROM
+ # "vulnerability_reads"
+ # WHERE
+ # (vulnerability_reads."state" = "states"."state")
+ # ORDER BY
+ # "vulnerability_reads"."severity" DESC,
+ # "vulnerability_reads"."vulnerability_id" DESC
+ # LIMIT 20
+ # ) AS vulnerability_reads
+ # )
+ # ORDER BY
+ # "vulnerability_reads"."severity" DESC,
+ # "vulnerability_reads"."vulnerability_id" DESC
+ # LIMIT 20
def rewrite
log_rewrite
- model.from(from)
- .limit(limit_value)
- .order(order_values)
- .includes(relation.includes_values)
- .preload(relation.preload_values)
- .eager_load(relation.eager_load_values)
+ return filter_query unless primary_key_present?
+
+ index_only_filter_query
end
def rewrite?
@@ -147,6 +179,23 @@ module UnnestedInFilters
::Gitlab::AppLogger.info(message: 'Query is being rewritten by `UnnestedInFilters`', model: model.name)
end
+ def filter_query
+ model.from(from).then { add_relation_defaults(_1) }
+ end
+
+ def index_only_filter_query
+ model.where(model.primary_key => filter_query.select(model.primary_key))
+ .then { add_relation_defaults(_1) }
+ end
+
+ def add_relation_defaults(new_relation)
+ new_relation.limit(limit_value)
+ .order(order_values)
+ .includes(relation.includes_values)
+ .preload(relation.preload_values)
+ .eager_load(relation.eager_load_values)
+ end
+
def from
[value_tables.map(&:to_sql) + [lateral]].join(', ')
end
@@ -156,9 +205,13 @@ module UnnestedInFilters
end
def join_relation
- value_tables.reduce(unscoped_relation) do |memo, tmp_table|
+ join_relation = value_tables.reduce(unscoped_relation) do |memo, tmp_table|
memo.where(tmp_table.as_predicate)
end
+
+ join_relation = join_relation.select(combined_attributes) if primary_key_present?
+
+ join_relation
end
def unscoped_relation
@@ -169,8 +222,14 @@ module UnnestedInFilters
@in_filters ||= arel_in_nodes.each_with_object({}) { |node, memo| memo[node.left.name] = node.right }
end
+ def model_column_names
+ @model_column_names ||= model.columns.map(&:name)
+ end
+
+ # Actively filter any nodes that don't belong to the primary queried table to prevent sql type resolution issues
+ # Context: https://gitlab.com/gitlab-org/gitlab/-/issues/370271#note_1151019824
def arel_in_nodes
- where_clause_arel_nodes.select(&method(:in_predicate?))
+ where_clause_arel_nodes.select(&method(:in_predicate?)).select { model_column_names.include?(_1.left.name) }
end
# `ActiveRecord::WhereClause#ast` is returning a single node when there is only one
@@ -194,12 +253,20 @@ module UnnestedInFilters
indices.any? do |index|
(filter_attributes - Array(index.columns)).empty? && # all the filter attributes are indexed
index.columns.last(order_attributes.length) == order_attributes && # index can be used in sorting
- (index.columns - (filter_attributes + order_attributes)).empty? # there is no other columns in the index
+ (index.columns - combined_attributes).empty? # there is no other columns in the index
end
end
+ def primary_key_present?
+ combined_attributes.include?(model.primary_key)
+ end
+
+ def combined_attributes
+ filter_attributes + order_attributes
+ end
+
def filter_attributes
- @filter_attributes ||= where_values_hash.keys
+ @filter_attributes ||= where_clause.to_h.keys
end
def order_attributes
diff --git a/locale/am_ET/gitlab.po b/locale/am_ET/gitlab.po
index bd2cf29a94d..f222ced9e73 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: 2022-10-10 14:06\n"
+"PO-Revision-Date: 2022-11-13 09:24\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d ላኪ"
msgstr[1] "%d ላኪዎች"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d የተስተካከለ የáተሻ á‹áŒ¤á‰µ"
-msgstr[1] "%d የተስተካከሉ የáተሻ á‹áŒ¤á‰¶á‰½"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr "%{count} á‹á‹­áˆŽá‰½ ተáŠáŠ­á‰°á‹‹áˆ"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr "%{count} ተጨማሪ"
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} ተሳታáŠ"
msgstr[1] "%{count} ተሳታáŠá‹Žá‰½"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} ተዛማጅ %{pluralized_subject}: %{links}"
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr "%{duration}ሚ"
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} %{resultsString} á‹­á‹­á‹›áˆ"
-
-msgid "%{name} found %{resultsString}"
-msgstr "በ%{name} á‹áˆµáŒ¥ %{resultsString} ተገáŠá‰·áˆ"
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Using a static site?"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/ar_SA/gitlab.po b/locale/ar_SA/gitlab.po
index 8801f84e816..097f8d01003 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: 2022-10-10 14:02\n"
+"PO-Revision-Date: 2022-11-13 09:22\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -199,6 +199,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -379,15 +388,6 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
@@ -397,15 +397,6 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -424,15 +415,6 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -841,6 +823,9 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -907,6 +892,24 @@ msgstr[5] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -919,6 +922,15 @@ msgstr[5] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%{count} more"
msgstr ""
@@ -949,6 +961,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -988,9 +1009,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -1201,12 +1219,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1420,6 +1432,9 @@ msgstr[5] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1594,9 +1609,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1654,6 +1666,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1696,6 +1711,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -2089,6 +2107,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -2152,9 +2173,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -2233,9 +2251,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -2443,6 +2458,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2554,15 +2572,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2632,9 +2644,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -3007,6 +3016,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -3190,6 +3205,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -3226,15 +3259,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -3283,6 +3328,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -3328,6 +3376,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -3466,9 +3526,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -3493,6 +3562,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3595,6 +3673,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3787,7 +3868,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3832,7 +3913,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3895,7 +3976,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3943,6 +4024,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -4453,7 +4537,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -4468,6 +4552,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -4504,9 +4591,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4753,6 +4837,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4942,9 +5029,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -5044,9 +5128,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -5149,9 +5230,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -5170,7 +5248,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -5221,6 +5299,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -5239,9 +5320,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -5269,6 +5359,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5629,9 +5722,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5737,7 +5827,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5788,6 +5878,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5839,9 +5953,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -6247,9 +6358,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6613,6 +6721,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -7357,6 +7471,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -7366,6 +7483,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -7387,6 +7507,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -7405,6 +7528,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -7414,6 +7540,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -7432,9 +7561,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -7453,12 +7588,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7618,6 +7762,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7627,9 +7774,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7675,9 +7819,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7708,6 +7849,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7723,6 +7867,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7747,9 +7894,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -8167,9 +8311,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -8185,6 +8326,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8932,6 +9076,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -10255,10 +10402,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -10444,6 +10597,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -11251,10 +11407,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -11287,6 +11443,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -11335,9 +11500,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -11422,9 +11584,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -11587,9 +11746,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11809,9 +11965,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -12079,9 +12232,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -12097,7 +12247,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -12199,9 +12349,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -12532,6 +12679,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -12559,6 +12709,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -12616,6 +12769,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12850,6 +13006,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -13072,6 +13231,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -13159,6 +13321,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -13192,6 +13357,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -13303,6 +13471,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -13324,9 +13495,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -13393,7 +13561,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13894,6 +14062,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13981,6 +14152,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -14329,6 +14515,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -14575,6 +14764,12 @@ msgstr[5] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -14590,6 +14785,9 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
@@ -14599,6 +14797,9 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -15208,6 +15409,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -15538,22 +15745,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15781,6 +16006,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15961,10 +16189,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15979,18 +16207,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -16003,18 +16222,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -16144,9 +16357,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -16210,9 +16420,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -16453,6 +16660,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -16576,6 +16834,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -16633,9 +16894,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16864,6 +17131,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16915,9 +17185,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -17113,9 +17380,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -17377,6 +17641,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17482,9 +17749,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -17692,6 +17956,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -18541,9 +18808,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -18670,6 +18934,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18721,6 +18991,9 @@ 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 ""
@@ -18769,9 +19042,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19327,9 +19597,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -19339,6 +19606,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -20101,12 +20371,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -20176,6 +20440,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -20362,9 +20629,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20827,7 +21091,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20914,12 +21184,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -22687,6 +22951,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -22705,9 +22972,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22765,7 +23029,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22849,19 +23113,16 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22999,12 +23260,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -23026,6 +23293,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -23251,6 +23530,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -23545,6 +23839,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23875,6 +24172,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23914,9 +24214,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -24301,9 +24607,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -24457,6 +24760,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24607,9 +24919,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24880,6 +25189,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -25150,9 +25465,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -25165,6 +25477,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25201,7 +25516,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -25216,9 +25537,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -25228,9 +25555,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -25240,7 +25564,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -25297,6 +25621,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -25321,6 +25648,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -25372,6 +25702,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -25384,6 +25717,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -26020,6 +26356,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -26245,6 +26584,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -26644,6 +26986,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26803,6 +27148,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26875,6 +27223,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -27061,6 +27412,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -27529,6 +27883,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -27658,9 +28015,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -27688,9 +28042,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -27706,9 +28057,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27946,7 +28294,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -28297,6 +28645,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -28306,6 +28657,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -28327,6 +28681,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -28420,9 +28777,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -28447,9 +28801,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -28687,12 +29038,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28738,12 +29083,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28765,12 +29104,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28813,15 +29146,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28852,12 +29176,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28876,9 +29194,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -29056,9 +29371,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -29431,12 +29743,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -29482,6 +29803,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -29632,6 +29959,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -30019,12 +30349,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -30073,7 +30397,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -30292,6 +30616,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -30307,6 +30634,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -30319,12 +30649,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -30334,9 +30670,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -31096,9 +31438,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -31207,6 +31546,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -31348,6 +31750,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -31441,12 +31846,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -32023,6 +32434,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -32035,6 +32449,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -32317,12 +32734,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -32335,12 +32758,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -32362,6 +32791,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -32461,6 +32893,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -32599,6 +33034,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -32629,6 +33067,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -32680,6 +33121,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -33319,6 +33763,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -33355,15 +33802,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -33379,12 +33838,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -33694,6 +34162,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33826,12 +34297,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33925,9 +34390,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -34099,6 +34561,9 @@ msgstr[5] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -34108,6 +34573,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -34564,6 +35032,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -34582,15 +35053,6 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -34624,18 +35086,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34654,12 +35110,6 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -34702,21 +35152,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34732,9 +35173,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -35122,6 +35560,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -35359,6 +35800,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -35401,6 +35845,9 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -35437,7 +35884,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -35650,6 +36097,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -35782,9 +36232,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -35833,6 +36289,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -35872,6 +36331,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -35911,12 +36373,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35971,16 +36427,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr ""
+
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -36088,10 +36550,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -36112,9 +36574,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -36124,9 +36592,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -36277,9 +36751,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -36730,10 +37201,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -36853,6 +37327,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36955,10 +37432,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -37048,7 +37525,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -37066,6 +37543,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -37084,12 +37564,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -37111,6 +37600,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -37240,6 +37732,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -37297,6 +37792,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -37414,9 +37912,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -37429,6 +37933,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -37492,9 +37999,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -37633,10 +38137,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -37648,28 +38152,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37888,9 +38392,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -38044,9 +38545,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -38305,10 +38803,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -38362,7 +38857,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -38377,7 +38872,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -38500,9 +38995,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -38725,6 +39217,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38836,9 +39331,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -39412,9 +39904,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -39427,9 +39916,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -39451,9 +39937,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39973,9 +40456,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -40237,6 +40726,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -40327,6 +40819,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -40411,6 +40906,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -40432,15 +40930,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -40462,9 +40954,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -40483,6 +40972,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -40594,24 +41086,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -40639,12 +41113,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -40732,12 +41200,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -41212,6 +41674,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -41407,9 +41872,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -41440,7 +41902,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -41497,9 +41959,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -41851,9 +42310,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -41887,6 +42343,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -42055,9 +42514,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -42118,6 +42574,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -42334,13 +42793,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -42469,9 +42931,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -42490,6 +42949,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42868,9 +43330,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42976,6 +43435,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -43042,9 +43504,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -43066,18 +43552,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -43090,6 +43597,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -43240,9 +43765,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -43567,6 +44089,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -44071,6 +44599,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -44173,6 +44707,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -44203,6 +44740,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -45265,9 +45805,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -45733,6 +46270,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -45751,6 +46291,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -45886,7 +46429,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45928,6 +46471,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -45943,12 +46489,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45988,6 +46546,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -46102,6 +46663,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -46129,9 +46696,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -46144,7 +46708,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -46156,12 +46720,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -46240,6 +46813,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -46249,7 +46825,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -46573,6 +47149,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -46627,9 +47209,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -46660,10 +47257,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -46675,6 +47275,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -46696,6 +47299,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -46714,6 +47320,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -46813,6 +47422,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -46849,6 +47461,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46894,9 +47512,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -47002,6 +47617,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -47074,7 +47692,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -47098,6 +47716,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -47245,6 +47866,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -47308,7 +47932,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -47476,9 +48100,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -47590,6 +48211,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -47716,16 +48340,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47818,6 +48439,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47887,9 +48511,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -47905,9 +48526,6 @@ msgstr[5] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -47971,6 +48589,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -47980,9 +48604,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -48067,6 +48688,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -48316,12 +48943,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -48400,6 +49042,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -48430,6 +49075,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -48445,6 +49093,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -48523,6 +49174,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -48586,6 +49240,9 @@ msgstr[5] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -48754,6 +49411,9 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -48862,12 +49522,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -48889,6 +49555,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -48913,12 +49582,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -49087,9 +49762,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -49246,6 +49918,9 @@ 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 ""
@@ -49342,9 +50017,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -49408,6 +50080,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -49420,9 +50095,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -49441,9 +50122,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -49492,9 +50170,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -49513,21 +50188,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -49669,9 +50338,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -49696,12 +50362,24 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -49861,6 +50539,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -50005,6 +50686,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/as_IN/gitlab.po b/locale/as_IN/gitlab.po
index 49882c2db1a..a1df2dbdd04 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: 2022-10-10 14:05\n"
+"PO-Revision-Date: 2022-11-13 09:24\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/az_AZ/gitlab.po b/locale/az_AZ/gitlab.po
index d5eb7b9dc6c..9e1e857d819 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: 2022-10-10 14:01\n"
+"PO-Revision-Date: 2022-11-13 09:22\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/ba_RU/gitlab.po b/locale/ba_RU/gitlab.po
index 10746716218..de0d110a7c5 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: 2022-10-10 14:06\n"
+"PO-Revision-Date: 2022-11-13 09:24\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -129,6 +129,10 @@ msgid "%d additional user"
msgid_plural "%d additional users"
msgstr[0] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -209,18 +213,10 @@ msgid "%d epic"
msgid_plural "%d epics"
msgstr[0] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -229,10 +225,6 @@ msgid "%d file"
msgid_plural "%d files"
msgstr[0] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -431,6 +423,9 @@ msgid "%{bold_start}%{count}%{bold_end} opened merge request"
msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -482,6 +477,14 @@ msgstr[0] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -489,6 +492,10 @@ msgstr[0] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+
msgid "%{count} more"
msgstr ""
@@ -509,6 +516,10 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -548,9 +559,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -761,12 +769,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -945,6 +947,9 @@ msgstr[0] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1079,9 +1084,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1139,6 +1141,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1176,6 +1181,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1434,6 +1442,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1497,9 +1508,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1578,9 +1586,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1788,6 +1793,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -1899,15 +1907,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -1977,9 +1979,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2352,6 +2351,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2535,6 +2540,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2571,15 +2594,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2628,6 +2663,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2673,6 +2711,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2811,9 +2861,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2838,6 +2897,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -2940,6 +3008,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3132,7 +3203,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3177,7 +3248,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3240,7 +3311,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3288,6 +3359,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3798,7 +3872,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3813,6 +3887,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3849,9 +3926,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4098,6 +4172,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4282,9 +4359,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4384,9 +4458,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4489,9 +4560,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4510,7 +4578,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4551,6 +4619,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4569,9 +4640,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4599,6 +4679,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -4934,9 +5017,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5037,7 +5117,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5088,6 +5168,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5139,9 +5243,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5532,9 +5633,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -5898,6 +5996,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6622,6 +6726,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6631,6 +6738,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6652,6 +6762,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6670,6 +6783,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6679,6 +6795,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6697,9 +6816,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6718,12 +6843,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -6883,6 +7017,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -6892,9 +7029,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -6940,9 +7074,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -6973,6 +7104,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -6988,6 +7122,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7012,9 +7149,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7427,9 +7561,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7445,6 +7576,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8182,6 +8316,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9495,10 +9632,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9679,6 +9822,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10471,10 +10617,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10507,6 +10653,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10555,9 +10710,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10642,9 +10794,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10807,9 +10956,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11029,9 +11175,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11299,9 +11442,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11317,7 +11457,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11419,9 +11559,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11747,6 +11884,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11774,6 +11914,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11831,6 +11974,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12065,6 +12211,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12282,6 +12431,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12369,6 +12521,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12402,6 +12557,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12513,6 +12671,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12534,9 +12695,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12603,7 +12761,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13074,6 +13232,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13161,6 +13322,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13499,6 +13675,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13735,6 +13914,12 @@ msgstr[0] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13750,10 +13935,16 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14358,6 +14549,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14688,22 +14885,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -14931,6 +15146,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15111,10 +15329,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15129,18 +15347,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15153,18 +15362,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15294,9 +15497,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15360,9 +15560,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15603,6 +15800,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15721,6 +15969,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15778,9 +16029,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16004,6 +16261,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16050,9 +16310,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16248,9 +16505,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16507,6 +16761,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16612,9 +16869,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16822,6 +17076,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17651,9 +17908,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17780,6 +18034,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -17831,6 +18091,9 @@ 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 ""
@@ -17879,9 +18142,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18437,9 +18697,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18449,6 +18706,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19211,12 +19471,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19286,6 +19540,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19462,9 +19719,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -19917,7 +20171,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20004,12 +20264,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21757,6 +22011,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21775,9 +22032,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -21835,7 +22089,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -21914,19 +22168,16 @@ msgid "InviteMembersModal|The following member couldn't be invited"
msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22064,12 +22315,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22091,6 +22348,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22316,6 +22585,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22610,6 +22894,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -22940,6 +23227,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -22979,9 +23269,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23356,9 +23652,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23512,6 +23805,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23662,9 +23964,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -23905,6 +24204,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24175,9 +24480,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24190,6 +24492,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24226,7 +24531,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24241,9 +24552,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24253,9 +24570,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24265,7 +24579,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24322,6 +24636,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24346,6 +24663,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24397,6 +24717,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24409,6 +24732,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25035,6 +25361,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25260,6 +25589,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25649,6 +25981,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -25808,6 +26143,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -25880,6 +26218,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26066,6 +26407,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26524,6 +26868,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26653,9 +27000,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26683,9 +27027,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26701,9 +27042,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -26936,7 +27274,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27267,6 +27605,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27276,6 +27617,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27297,6 +27641,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27390,9 +27737,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27417,9 +27761,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27652,12 +27993,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27703,12 +28038,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27730,12 +28059,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27778,15 +28101,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -27817,12 +28131,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -27841,9 +28149,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28016,9 +28321,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28386,12 +28688,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28437,6 +28748,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28582,6 +28899,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -28964,12 +29284,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29018,7 +29332,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29237,6 +29551,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29252,6 +29569,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29264,12 +29584,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29279,9 +29605,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30041,9 +30373,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30152,6 +30481,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30293,6 +30685,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30386,12 +30781,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -30968,6 +31369,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -30980,6 +31384,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31262,12 +31669,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31280,12 +31693,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31307,6 +31726,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31406,6 +31828,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31544,6 +31969,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31574,6 +32002,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31625,6 +32056,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32264,6 +32698,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32300,15 +32737,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32324,12 +32773,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32639,6 +33097,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32771,12 +33232,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -32870,9 +33325,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33034,6 +33486,9 @@ msgstr[0] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33043,6 +33498,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33499,6 +33957,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33512,10 +33973,6 @@ msgid "Reports|%{recentlyFailed} out of %{failed} failed tests has failed more t
msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days"
msgstr[0] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33544,18 +34001,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33564,12 +34015,6 @@ msgid "Reports|Failed %{count} time in %{base_branch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 days"
msgstr[0] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33612,21 +34057,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33642,9 +34078,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34012,6 +34445,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34239,6 +34675,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34276,6 +34715,9 @@ msgid "Runners|%d selected runner deleted"
msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34302,7 +34744,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34510,6 +34952,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34637,9 +35082,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34688,6 +35139,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34722,6 +35176,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34761,12 +35218,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -34821,16 +35272,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -34938,10 +35395,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -34962,9 +35419,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -34974,9 +35437,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35127,9 +35596,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35525,10 +35991,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35648,6 +36117,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35750,10 +36222,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -35843,7 +36315,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -35861,6 +36333,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -35879,12 +36354,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -35906,6 +36390,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36035,6 +36522,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36092,6 +36582,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36209,9 +36702,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36224,6 +36723,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36287,9 +36789,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36428,10 +36927,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36443,28 +36942,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36683,9 +37182,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -36834,9 +37330,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37090,10 +37583,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37147,7 +37637,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37162,7 +37652,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37285,9 +37775,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37510,6 +37997,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37621,9 +38111,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38197,9 +38684,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38212,9 +38696,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38236,9 +38717,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -38758,9 +39236,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39017,6 +39501,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39107,6 +39594,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39191,6 +39681,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39212,15 +39705,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39242,9 +39729,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39263,6 +39747,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39374,14 +39861,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39399,12 +39878,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39492,12 +39965,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -39947,6 +40414,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40142,9 +40612,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40175,7 +40642,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40232,9 +40699,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40586,9 +41050,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40622,6 +41083,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -40790,9 +41254,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -40853,6 +41314,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41069,13 +41533,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41204,9 +41671,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41225,6 +41689,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41593,9 +42060,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41701,6 +42165,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -41767,9 +42234,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -41791,18 +42282,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -41815,6 +42327,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -41965,9 +42495,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42287,6 +42814,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -42791,6 +43324,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -42893,6 +43432,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -42923,6 +43465,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -43970,9 +44515,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44433,6 +44975,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44451,6 +44996,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44586,7 +45134,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44628,6 +45176,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44643,12 +45194,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44688,6 +45251,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -44802,6 +45368,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -44829,9 +45401,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -44844,7 +45413,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -44856,12 +45425,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -44940,6 +45518,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -44949,7 +45530,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45263,6 +45844,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45312,9 +45899,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45345,10 +45947,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45360,6 +45965,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45381,6 +45989,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45399,6 +46010,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45493,6 +46107,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45529,6 +46146,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45574,9 +46197,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45677,6 +46297,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -45749,7 +46372,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -45773,6 +46396,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -45915,6 +46541,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -45978,7 +46607,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46146,9 +46775,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46260,6 +46886,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46376,16 +47005,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46473,6 +47099,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46542,9 +47171,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46555,9 +47181,6 @@ msgstr[0] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46616,6 +47239,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46625,9 +47254,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46707,6 +47333,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -46936,12 +47568,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47015,6 +47662,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47045,6 +47695,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47060,6 +47713,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47133,6 +47789,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47191,6 +47850,9 @@ msgstr[0] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47344,6 +48006,9 @@ msgid "from %d job"
msgid_plural "from %d jobs"
msgstr[0] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47442,12 +48107,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47469,6 +48140,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47493,12 +48167,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47652,9 +48332,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -47801,6 +48478,9 @@ 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 ""
@@ -47897,9 +48577,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -47963,6 +48640,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -47975,9 +48655,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -47996,9 +48682,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48047,9 +48730,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48068,16 +48748,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48204,9 +48883,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48226,12 +48902,19 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48386,6 +49069,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48520,6 +49206,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/bg/gitlab.po b/locale/bg/gitlab.po
index 72f6db364e4..0489c2facdd 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: 2022-10-10 14:02\n"
+"PO-Revision-Date: 2022-11-13 09:22\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr "Ðктивно"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "Преглед на папката"
@@ -7039,9 +7178,6 @@ msgstr "Преглед на файла"
msgid "Browse Files"
msgstr "Преглед на файловете"
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr "Разглеждане на файловете"
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr "Изтриване"
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Using a static site?"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr "ÐапуÑкане на проекта"
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr "Филтър"
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr "Ðктивно"
msgid "PipelineSchedules|All"
msgstr "Ð’Ñички"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr "Ðеактивно"
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr "Следващо изпълнение"
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "Въведете кратко опиÑание за тази Ñхема"
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr "Поемане на ÑобÑтвеноÑтта"
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr "Цел"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr "Променливи"
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr "Прочетете повече"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr "Изберете чаÑова зона"
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "Преминаване към клон/етикет"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr "Целеви клон"
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr "Вашето име"
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] "дни"
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "родител"
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/bn_BD/gitlab.po b/locale/bn_BD/gitlab.po
index 6029606ab6a..16cc8a5598c 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: 2022-10-10 14:00\n"
+"PO-Revision-Date: 2022-11-13 09:21\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/bn_IN/gitlab.po b/locale/bn_IN/gitlab.po
index 56580402a80..040b870aac8 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: 2022-10-10 14:06\n"
+"PO-Revision-Date: 2022-11-13 09:24\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/br_FR/gitlab.po b/locale/br_FR/gitlab.po
index 6fa207a2359..56634d5dde3 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: 2022-10-10 14:05\n"
+"PO-Revision-Date: 2022-11-13 09:25\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -185,6 +185,14 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -345,14 +353,6 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
@@ -361,14 +361,6 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -385,14 +377,6 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -759,6 +743,9 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -822,6 +809,22 @@ msgstr[4] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -833,6 +836,14 @@ msgstr[4] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
msgid "%{count} more"
msgstr ""
@@ -861,6 +872,14 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -900,9 +919,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -1113,12 +1129,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1325,6 +1335,9 @@ msgstr[4] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1491,9 +1504,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1551,6 +1561,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1592,6 +1605,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1958,6 +1974,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -2021,9 +2040,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -2102,9 +2118,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -2312,6 +2325,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2423,15 +2439,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2501,9 +2511,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2876,6 +2883,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -3059,6 +3072,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -3095,15 +3126,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -3152,6 +3195,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -3197,6 +3243,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -3335,9 +3393,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -3362,6 +3429,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3464,6 +3540,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3656,7 +3735,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3701,7 +3780,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3764,7 +3843,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3812,6 +3891,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -4322,7 +4404,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -4337,6 +4419,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -4373,9 +4458,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4622,6 +4704,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4810,9 +4895,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4912,9 +4994,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -5017,9 +5096,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -5038,7 +5114,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -5087,6 +5163,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -5105,9 +5184,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -5135,6 +5223,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5490,9 +5581,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5597,7 +5685,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5648,6 +5736,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5699,9 +5811,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -6104,9 +6213,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6470,6 +6576,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -7210,6 +7322,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -7219,6 +7334,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -7240,6 +7358,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -7258,6 +7379,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -7267,6 +7391,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -7285,9 +7412,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -7306,12 +7439,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7471,6 +7613,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7480,9 +7625,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7528,9 +7670,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7561,6 +7700,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7576,6 +7718,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7600,9 +7745,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -8019,9 +8161,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -8037,6 +8176,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8782,6 +8924,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -10103,10 +10248,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -10291,6 +10442,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -11095,10 +11249,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -11131,6 +11285,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -11179,9 +11342,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -11266,9 +11426,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -11431,9 +11588,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11653,9 +11807,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11923,9 +12074,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11941,7 +12089,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -12043,9 +12191,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -12375,6 +12520,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -12402,6 +12550,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -12459,6 +12610,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12693,6 +12847,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12914,6 +13071,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -13001,6 +13161,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -13034,6 +13197,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -13145,6 +13311,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -13166,9 +13335,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -13235,7 +13401,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13730,6 +13896,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13817,6 +13986,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -14163,6 +14347,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -14407,6 +14594,12 @@ msgstr[4] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -14422,6 +14615,9 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
@@ -14430,6 +14626,9 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -15038,6 +15237,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -15368,22 +15573,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Using a static site?"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15611,6 +15834,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15791,10 +16017,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15809,18 +16035,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15833,18 +16050,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15974,9 +16185,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -16040,9 +16248,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -16283,6 +16488,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -16405,6 +16661,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -16462,9 +16721,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16692,6 +16957,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16742,9 +17010,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16940,9 +17205,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -17203,6 +17465,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17308,9 +17573,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -17518,6 +17780,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -18363,9 +18628,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -18492,6 +18754,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18543,6 +18811,9 @@ 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 ""
@@ -18591,9 +18862,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19149,9 +19417,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -19161,6 +19426,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19923,12 +20191,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19998,6 +20260,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -20182,9 +20447,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20645,7 +20907,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20732,12 +21000,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -22501,6 +22763,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -22519,9 +22784,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22579,7 +22841,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22662,19 +22924,16 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22812,12 +23071,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22839,6 +23104,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -23064,6 +23341,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -23358,6 +23650,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23688,6 +23983,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23727,9 +24025,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -24112,9 +24416,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -24268,6 +24569,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24418,9 +24728,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24685,6 +24992,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24955,9 +25268,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24970,6 +25280,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25006,7 +25319,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -25021,9 +25340,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -25033,9 +25358,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -25045,7 +25367,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -25102,6 +25424,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -25126,6 +25451,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -25177,6 +25505,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -25189,6 +25520,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25823,6 +26157,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -26048,6 +26385,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -26445,6 +26785,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26604,6 +26947,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26676,6 +27022,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26862,6 +27211,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -27328,6 +27680,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -27457,9 +27812,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -27487,9 +27839,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -27505,9 +27854,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27744,7 +28090,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -28091,6 +28437,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -28100,6 +28449,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -28121,6 +28473,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -28214,9 +28569,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -28241,9 +28593,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -28480,12 +28829,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28531,12 +28874,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28558,12 +28895,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28606,15 +28937,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28645,12 +28967,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28669,9 +28985,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28848,9 +29161,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -29222,12 +29532,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -29273,6 +29592,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -29422,6 +29747,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29808,12 +30136,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29862,7 +30184,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -30081,6 +30403,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -30096,6 +30421,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -30108,12 +30436,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -30123,9 +30457,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30885,9 +31225,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30996,6 +31333,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -31137,6 +31537,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -31230,12 +31633,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31812,6 +32221,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31824,6 +32236,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -32106,12 +32521,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -32124,12 +32545,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -32151,6 +32578,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -32250,6 +32680,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -32388,6 +32821,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -32418,6 +32854,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -32469,6 +32908,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -33108,6 +33550,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -33144,15 +33589,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -33168,12 +33625,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -33483,6 +33949,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33615,12 +34084,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33714,9 +34177,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33886,6 +34346,9 @@ msgstr[4] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33895,6 +34358,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -34351,6 +34817,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -34368,14 +34837,6 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -34408,18 +34869,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34436,12 +34891,6 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -34484,21 +34933,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34514,9 +34954,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34900,6 +35337,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -35135,6 +35575,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -35176,6 +35619,9 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -35210,7 +35656,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -35422,6 +35868,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -35553,9 +36002,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -35604,6 +36059,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -35642,6 +36100,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -35681,12 +36142,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35741,16 +36196,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr ""
+
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35858,10 +36319,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35882,9 +36343,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35894,9 +36361,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -36047,9 +36520,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -36489,10 +36959,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -36612,6 +37085,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36714,10 +37190,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36807,7 +37283,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36825,6 +37301,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36843,12 +37322,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36870,6 +37358,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36999,6 +37490,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -37056,6 +37550,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -37173,9 +37670,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -37188,6 +37691,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -37251,9 +37757,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -37392,10 +37895,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -37407,28 +37910,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37647,9 +38150,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37802,9 +38302,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -38062,10 +38559,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -38119,7 +38613,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -38134,7 +38628,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -38257,9 +38751,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -38482,6 +38973,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38593,9 +39087,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -39169,9 +39660,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -39184,9 +39672,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -39208,9 +39693,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39730,9 +40212,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39993,6 +40481,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -40083,6 +40574,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -40167,6 +40661,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -40188,15 +40685,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -40218,9 +40709,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -40239,6 +40727,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -40350,22 +40841,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -40391,12 +40866,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -40484,12 +40953,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40959,6 +41422,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -41154,9 +41620,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -41187,7 +41650,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -41244,9 +41707,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -41598,9 +42058,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -41634,6 +42091,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41802,9 +42262,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41865,6 +42322,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -42081,13 +42541,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -42216,9 +42679,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -42237,6 +42697,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42613,9 +43076,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42721,6 +43181,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42787,9 +43250,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42811,18 +43298,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42835,6 +43343,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42985,9 +43511,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -43311,6 +43834,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43815,6 +44344,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43917,6 +44452,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43947,6 +44485,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -45006,9 +45547,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -45473,6 +46011,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -45491,6 +46032,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -45626,7 +46170,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45668,6 +46212,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -45683,12 +46230,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45728,6 +46287,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45842,6 +46404,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45869,9 +46437,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45884,7 +46449,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45896,12 +46461,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45980,6 +46554,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45989,7 +46566,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -46311,6 +46888,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -46364,9 +46947,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -46397,10 +46995,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -46412,6 +47013,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -46433,6 +47037,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -46451,6 +47058,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -46549,6 +47159,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -46585,6 +47198,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46630,9 +47249,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -46737,6 +47353,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46809,7 +47428,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46833,6 +47452,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46979,6 +47601,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -47042,7 +47667,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -47210,9 +47835,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -47324,6 +47946,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -47448,16 +48073,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47549,6 +48171,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47618,9 +48243,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -47635,9 +48257,6 @@ msgstr[4] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -47700,6 +48319,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -47709,9 +48334,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -47795,6 +48417,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -48040,12 +48668,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -48123,6 +48766,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -48153,6 +48799,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -48168,6 +48817,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -48245,6 +48897,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -48307,6 +48962,9 @@ msgstr[4] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -48472,6 +49130,9 @@ msgstr[2] ""
msgstr[3] ""
msgstr[4] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -48578,12 +49239,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -48605,6 +49272,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -48629,12 +49299,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -48800,9 +49476,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48957,6 +49630,9 @@ 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 ""
@@ -49053,9 +49729,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -49119,6 +49792,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -49131,9 +49807,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -49152,9 +49834,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -49203,9 +49882,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -49224,20 +49900,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -49376,9 +50047,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -49402,12 +50070,23 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -49566,6 +50245,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -49708,6 +50390,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/bs_BA/gitlab.po b/locale/bs_BA/gitlab.po
index 337041e880f..3c545ed44ca 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: 2022-10-10 14:04\n"
+"PO-Revision-Date: 2022-11-13 09:24\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -157,6 +157,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d odobravatelj"
@@ -277,24 +283,12 @@ msgstr[0] "%d epik"
msgstr[1] "%d epika"
msgstr[2] "%d epika"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d greška"
-msgstr[1] "%d greške"
-msgstr[2] "%d grešaka"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -307,12 +301,6 @@ msgstr[0] "%d fajl"
msgstr[1] "%d fajla"
msgstr[2] "%d fajlova"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -595,6 +583,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -652,6 +643,18 @@ msgstr[2] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -661,6 +664,12 @@ msgstr[2] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%{count} more"
msgstr ""
@@ -685,6 +694,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -724,9 +739,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -937,12 +949,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1135,6 +1141,9 @@ msgstr[2] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1285,9 +1294,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1345,6 +1351,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1384,6 +1393,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1696,6 +1708,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1759,9 +1774,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1840,9 +1852,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -2050,6 +2059,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2161,15 +2173,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2239,9 +2245,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2614,6 +2617,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2797,6 +2806,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2833,15 +2860,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2890,6 +2929,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2935,6 +2977,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -3073,9 +3127,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -3100,6 +3163,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3202,6 +3274,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3394,7 +3469,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3439,7 +3514,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3502,7 +3577,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3550,6 +3625,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -4060,7 +4138,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -4075,6 +4153,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -4111,9 +4192,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4360,6 +4438,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4546,9 +4627,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4648,9 +4726,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4753,9 +4828,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4774,7 +4846,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4819,6 +4891,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4837,9 +4912,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4867,6 +4951,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5212,9 +5299,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5317,7 +5401,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5368,6 +5452,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5419,9 +5527,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5818,9 +5923,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6184,6 +6286,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6916,6 +7024,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6925,6 +7036,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6946,6 +7060,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6964,6 +7081,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6973,6 +7093,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6991,9 +7114,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -7012,12 +7141,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7177,6 +7315,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7186,9 +7327,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7234,9 +7372,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7267,6 +7402,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7282,6 +7420,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7306,9 +7447,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7723,9 +7861,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7741,6 +7876,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8482,6 +8620,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9799,10 +9940,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9985,6 +10132,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10783,10 +10933,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10819,6 +10969,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10867,9 +11026,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10954,9 +11110,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -11119,9 +11272,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11341,9 +11491,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11611,9 +11758,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11629,7 +11773,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11731,9 +11875,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -12061,6 +12202,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -12088,6 +12232,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -12145,6 +12292,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12379,6 +12529,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12598,6 +12751,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12685,6 +12841,9 @@ msgstr "S"
msgid "Days"
msgstr "Dani"
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12718,6 +12877,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12829,6 +12991,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12850,9 +13015,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12919,7 +13081,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13402,6 +13564,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13489,6 +13654,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13831,6 +14011,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -14071,6 +14254,12 @@ msgstr[2] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -14086,12 +14275,18 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14698,6 +14893,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -15028,22 +15229,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Using a static site?"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15271,6 +15490,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15451,12 +15673,12 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgstr ""
+
msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr "Jesi li siguran da želiš ukloniti %{bStart}%{targetIssueTitle}%{bEnd} iz %{bStart}%{parentEpicTitle}%{bEnd}?"
-msgid "Epics|Assign Epic"
-msgstr ""
-
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr ""
@@ -15469,18 +15691,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr "Ukloni zadatak"
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr "Problem pri dodavanju zadatka epiku."
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15493,18 +15706,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr "Problem pri uklanjanju zadatka iz epika."
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15634,9 +15841,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15700,9 +15904,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15943,6 +16144,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -16063,6 +16315,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -16120,9 +16375,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16348,6 +16609,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16396,9 +16660,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16594,9 +16855,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16855,6 +17113,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16960,9 +17221,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -17170,6 +17428,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -18007,9 +18268,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -18136,6 +18394,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18187,6 +18451,9 @@ 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 ""
@@ -18235,9 +18502,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18793,9 +19057,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18805,6 +19066,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19567,12 +19831,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19642,6 +19900,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19822,9 +20083,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20281,7 +20539,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20368,12 +20632,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -22129,6 +22387,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -22147,9 +22408,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22207,7 +22465,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22288,19 +22546,16 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22438,12 +22693,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22465,6 +22726,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr "Zadatak"
@@ -22690,6 +22963,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22984,6 +23272,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23314,6 +23605,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23353,9 +23647,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23734,9 +24034,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23890,6 +24187,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24040,9 +24346,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24295,6 +24598,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24565,9 +24874,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24580,6 +24886,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24616,8 +24925,14 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
-msgstr "Ovaj zadatak je oznaÄen kao povjerljiv."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
+msgstr ""
msgid "Mailgun"
msgstr ""
@@ -24631,9 +24946,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24643,9 +24964,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr "OznaÄi zadatak kao povjerljiv."
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24655,8 +24973,8 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
-msgstr "OznaÄava ovaj zadatak kao povjerljiv."
+msgid "Makes this %{type} confidential."
+msgstr ""
msgid "Manage %{workspace} labels"
msgstr ""
@@ -24712,6 +25030,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24736,6 +25057,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24787,6 +25111,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24799,6 +25126,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25429,6 +25759,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25654,6 +25987,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -26047,6 +26383,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26206,6 +26545,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26278,6 +26620,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26464,6 +26809,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26926,6 +27274,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -27055,9 +27406,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -27085,9 +27433,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -27103,9 +27448,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27340,7 +27682,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27679,6 +28021,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27688,6 +28033,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27709,6 +28057,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27802,9 +28153,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27829,9 +28177,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -28066,12 +28411,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28117,12 +28456,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28144,12 +28477,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28192,15 +28519,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28231,12 +28549,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28255,9 +28567,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28432,9 +28741,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28804,12 +29110,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28855,6 +29170,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -29002,6 +29323,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29386,12 +29710,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29440,7 +29758,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29659,6 +29977,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29674,6 +29995,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29686,12 +30010,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29701,9 +30031,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30463,9 +30799,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30574,6 +30907,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30715,6 +31111,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30808,12 +31207,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31390,6 +31795,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31402,6 +31810,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31684,12 +32095,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31702,12 +32119,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31729,6 +32152,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31828,6 +32254,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31966,6 +32395,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31996,6 +32428,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -32047,6 +32482,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32686,6 +33124,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32722,15 +33163,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32746,12 +33199,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -33061,6 +33523,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33193,12 +33658,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33292,9 +33751,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33460,6 +33916,9 @@ msgstr[2] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33469,6 +33928,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33925,6 +34387,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33940,12 +34405,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33976,18 +34435,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34000,12 +34453,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -34048,21 +34495,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34078,9 +34516,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34456,6 +34891,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34687,6 +35125,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34726,6 +35167,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34756,7 +35200,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34966,6 +35410,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -35095,9 +35542,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -35146,6 +35599,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -35182,6 +35638,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -35221,12 +35680,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35281,16 +35734,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35398,10 +35857,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35422,9 +35881,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35434,9 +35899,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35587,9 +36058,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -36007,10 +36475,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -36130,6 +36601,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36232,10 +36706,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36325,7 +36799,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36343,6 +36817,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36361,12 +36838,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36388,6 +36874,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36517,6 +37006,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36574,6 +37066,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36691,9 +37186,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36706,6 +37207,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36769,9 +37273,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36910,10 +37411,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36925,28 +37426,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37165,9 +37666,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37318,9 +37816,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37576,10 +38071,7 @@ msgstr ""
msgid "Showing all issues"
msgstr "Svi zadaci prikazani"
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37633,7 +38125,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37648,7 +38140,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37771,9 +38263,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37996,6 +38485,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38107,9 +38599,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38683,9 +39172,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38698,9 +39184,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38722,9 +39205,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39244,9 +39724,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39505,6 +39991,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39595,6 +40084,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39679,6 +40171,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39700,15 +40195,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39730,9 +40219,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39751,6 +40237,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39862,18 +40351,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39895,12 +40372,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39988,12 +40459,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40453,6 +40918,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40648,9 +41116,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40681,7 +41146,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40738,9 +41203,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -41092,9 +41554,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -41128,6 +41587,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41296,9 +41758,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41359,6 +41818,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41575,13 +42037,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41710,9 +42175,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41731,6 +42193,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42103,9 +42568,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42211,6 +42673,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42277,9 +42742,33 @@ msgstr "Danas"
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42301,18 +42790,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42325,6 +42835,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42475,9 +43003,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42799,6 +43324,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43303,6 +43834,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43405,6 +43942,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43435,6 +43975,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44488,9 +45031,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44953,6 +45493,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44971,6 +45514,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -45106,7 +45652,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45148,6 +45694,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -45163,12 +45712,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45208,6 +45769,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45322,6 +45886,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45349,9 +45919,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45364,7 +45931,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45376,12 +45943,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45460,6 +46036,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45469,7 +46048,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45787,6 +46366,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45838,9 +46423,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45871,10 +46471,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45886,6 +46489,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45907,6 +46513,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45925,6 +46534,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -46021,6 +46633,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -46057,6 +46672,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46102,9 +46723,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -46207,6 +46825,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46279,7 +46900,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46303,6 +46924,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46447,6 +47071,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46510,7 +47137,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46678,9 +47305,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46792,6 +47416,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46912,16 +47539,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47011,6 +47635,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47080,9 +47707,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -47095,9 +47719,6 @@ msgstr[2] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -47158,6 +47779,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -47167,9 +47794,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -47251,6 +47875,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47488,12 +48118,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47569,6 +48214,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47599,6 +48247,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47614,6 +48265,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47689,6 +48343,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47749,6 +48406,9 @@ msgstr[2] "dana"
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47908,6 +48568,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -48010,12 +48673,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr "je već povezan s GitLab zadatkom. Novi zadatak neće biti povezan."
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -48037,6 +48706,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -48061,12 +48733,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -48226,9 +48904,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48379,6 +49054,9 @@ 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 ""
@@ -48475,9 +49153,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48541,6 +49216,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48553,9 +49231,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48574,9 +49258,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48625,9 +49306,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48646,18 +49324,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48790,9 +49465,6 @@ msgstr ""
msgid "remove weight"
msgstr "ukloni težinu"
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48814,12 +49486,21 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48976,6 +49657,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -49114,6 +49798,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/ca_ES/gitlab.po b/locale/ca_ES/gitlab.po
index 35d5f017595..7ff88c91f7a 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: 2022-10-10 14:02\n"
+"PO-Revision-Date: 2022-11-13 09:22\n"
msgid " %{start} to %{end}"
msgstr " Des de %{start} fins %{end}"
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d aprovador"
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr "%{count} més"
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} participant"
msgstr[1] "%{count} participants"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr "Actiu"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr "Sessions actives"
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr "Analítiques"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr "Artefactes"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr "Nom de la branca"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr "Crea un fitxer o directori nou"
msgid "Create new label"
msgstr "Crea una etiqueta nova"
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr "Branca actual"
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr "Suprimeix"
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr "feb."
msgid "February"
msgstr "febrer"
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr "Grup"
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/cs_CZ/gitlab.po b/locale/cs_CZ/gitlab.po
index 8de7929c3e9..fc0cddd408f 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: 2022-10-10 14:02\n"
+"PO-Revision-Date: 2022-11-13 09:22\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -171,6 +171,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -311,13 +318,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
@@ -325,13 +325,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -346,13 +339,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -677,6 +663,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -737,6 +726,20 @@ msgstr[3] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -747,6 +750,13 @@ msgstr[3] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} more"
msgstr ""
@@ -773,6 +783,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -812,9 +829,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -1025,12 +1039,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1230,6 +1238,9 @@ msgstr[3] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1388,9 +1399,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1448,6 +1456,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1488,6 +1499,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1827,6 +1841,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1890,9 +1907,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1971,9 +1985,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -2181,6 +2192,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2292,15 +2306,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2370,9 +2378,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2745,6 +2750,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2928,6 +2939,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2964,15 +2993,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -3021,6 +3062,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -3066,6 +3110,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -3204,9 +3260,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -3231,6 +3296,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3333,6 +3407,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3525,7 +3602,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3570,7 +3647,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3633,7 +3710,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3681,6 +3758,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -4191,7 +4271,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -4206,6 +4286,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -4242,9 +4325,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4491,6 +4571,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4678,9 +4761,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4780,9 +4860,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4885,9 +4962,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4906,7 +4980,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4953,6 +5027,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4971,9 +5048,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -5001,6 +5087,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5351,9 +5440,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5457,7 +5543,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5508,6 +5594,30 @@ msgstr ""
msgid "Artifacts"
msgstr "Artefakty"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5559,9 +5669,6 @@ msgstr "PÅ™iÅ™aÄte vlastní barvu jako například #FF0000"
msgid "Assign labels"
msgstr "Přiřadit štítky"
-msgid "Assign milestone"
-msgstr "Přiřadit milník"
-
msgid "Assign myself"
msgstr ""
@@ -5961,9 +6068,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6327,6 +6431,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -7063,6 +7173,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -7072,6 +7185,9 @@ msgstr "Tato větev již existuje"
msgid "Branch name"
msgstr "Název větve"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -7093,6 +7209,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -7111,6 +7230,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -7120,6 +7242,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -7138,9 +7263,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -7159,12 +7290,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7324,6 +7464,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7333,9 +7476,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7381,9 +7521,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7414,6 +7551,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7429,6 +7569,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7453,9 +7596,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7871,9 +8011,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7889,6 +8026,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8632,6 +8772,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9951,10 +10094,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -10138,6 +10287,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10939,10 +11091,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10975,6 +11127,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -11023,9 +11184,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -11110,9 +11268,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -11275,9 +11430,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11497,9 +11649,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11767,9 +11916,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11785,7 +11931,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11887,9 +12033,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -12218,6 +12361,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -12245,6 +12391,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -12302,6 +12451,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12536,6 +12688,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12756,6 +12911,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12843,6 +13001,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12876,6 +13037,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12987,6 +13151,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -13008,9 +13175,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -13077,7 +13241,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13566,6 +13730,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13653,6 +13820,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13997,6 +14179,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -14239,6 +14424,12 @@ msgstr[3] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -14254,6 +14445,9 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
@@ -14261,6 +14455,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14868,6 +15065,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -15198,22 +15401,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr ""
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr ""
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15441,6 +15662,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15621,10 +15845,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15639,18 +15863,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15663,18 +15878,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15804,9 +16013,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15870,9 +16076,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -16113,6 +16316,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -16234,6 +16488,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -16291,9 +16548,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16520,6 +16783,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16569,9 +16835,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16767,9 +17030,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -17029,6 +17289,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17134,9 +17397,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -17344,6 +17604,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -18185,9 +18448,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -18314,6 +18574,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18365,6 +18631,9 @@ 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 ""
@@ -18413,9 +18682,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18971,9 +19237,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18983,6 +19246,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19745,12 +20011,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19820,6 +20080,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -20002,9 +20265,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20463,7 +20723,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20550,12 +20816,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -22315,6 +22575,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -22333,9 +22596,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22393,7 +22653,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22475,19 +22735,16 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22625,12 +22882,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22652,6 +22915,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22877,6 +23152,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -23171,6 +23461,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23501,6 +23794,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23540,9 +23836,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23923,9 +24225,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -24079,6 +24378,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24229,9 +24537,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24490,6 +24795,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24760,9 +25071,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24775,6 +25083,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24811,7 +25122,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24826,9 +25143,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24838,9 +25161,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24850,7 +25170,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24907,6 +25227,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24931,6 +25254,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24982,6 +25308,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24994,6 +25323,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25626,6 +25958,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25851,6 +26186,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -26246,6 +26584,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26405,6 +26746,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26477,6 +26821,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26663,6 +27010,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -27127,6 +27477,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -27256,9 +27609,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -27286,9 +27636,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -27304,9 +27651,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27542,7 +27886,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27885,6 +28229,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27894,6 +28241,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27915,6 +28265,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -28008,9 +28361,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -28035,9 +28385,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -28273,12 +28620,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28324,12 +28665,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28351,12 +28686,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28399,15 +28728,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28438,12 +28758,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28462,9 +28776,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28640,9 +28951,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -29013,12 +29321,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -29064,6 +29381,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -29212,6 +29535,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29597,12 +29923,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29651,7 +29971,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29870,6 +30190,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29885,6 +30208,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29897,12 +30223,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29912,9 +30244,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30674,9 +31012,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30785,6 +31120,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30926,6 +31324,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -31019,12 +31420,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31601,6 +32008,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31613,6 +32023,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31895,12 +32308,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31913,12 +32332,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31940,6 +32365,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -32039,6 +32467,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -32177,6 +32608,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -32207,6 +32641,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -32258,6 +32695,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32897,6 +33337,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32933,15 +33376,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32957,12 +33412,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -33272,6 +33736,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33404,12 +33871,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33503,9 +33964,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33673,6 +34131,9 @@ msgstr[3] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33682,6 +34143,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -34138,6 +34602,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -34154,13 +34621,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -34192,18 +34652,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34218,12 +34672,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -34266,21 +34714,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34296,9 +34735,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34678,6 +35114,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34911,6 +35350,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34951,6 +35393,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34983,7 +35428,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -35194,6 +35639,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -35324,9 +35772,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -35375,6 +35829,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -35412,6 +35869,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -35451,12 +35911,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35511,16 +35965,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35628,10 +36088,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35652,9 +36112,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35664,9 +36130,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35817,9 +36289,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -36248,10 +36717,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -36371,6 +36843,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36473,10 +36948,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36566,7 +37041,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36584,6 +37059,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36602,12 +37080,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36629,6 +37116,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36758,6 +37248,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36815,6 +37308,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36932,9 +37428,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36947,6 +37449,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -37010,9 +37515,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -37151,10 +37653,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -37166,28 +37668,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37406,9 +37908,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37560,9 +38059,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37819,10 +38315,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37876,7 +38369,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37891,7 +38384,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -38014,9 +38507,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -38239,6 +38729,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38350,9 +38843,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38926,9 +39416,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38941,9 +39428,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38965,9 +39449,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39487,9 +39968,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39749,6 +40236,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39839,6 +40329,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39923,6 +40416,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39944,15 +40440,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39974,9 +40464,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39995,6 +40482,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -40106,20 +40596,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -40143,12 +40619,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -40236,12 +40706,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40706,6 +41170,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40901,9 +41368,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40934,7 +41398,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40991,9 +41455,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -41345,9 +41806,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -41381,6 +41839,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41549,9 +42010,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41612,6 +42070,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41828,13 +42289,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41963,9 +42427,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41984,6 +42445,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42358,9 +42822,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42466,6 +42927,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42532,9 +42996,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42556,18 +43044,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42580,6 +43089,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42730,9 +43257,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -43055,6 +43579,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43559,6 +44089,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43661,6 +44197,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43691,6 +44230,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44747,9 +45289,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -45213,6 +45752,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -45231,6 +45773,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -45366,7 +45911,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45408,6 +45953,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -45423,12 +45971,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45468,6 +46028,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45582,6 +46145,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45609,9 +46178,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45624,7 +46190,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45636,12 +46202,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45720,6 +46295,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45729,7 +46307,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -46049,6 +46627,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -46101,9 +46685,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -46134,10 +46733,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -46149,6 +46751,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -46170,6 +46775,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -46188,6 +46796,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -46285,6 +46896,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -46321,6 +46935,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46366,9 +46986,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -46472,6 +47089,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46544,7 +47164,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46568,6 +47188,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46713,6 +47336,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46776,7 +47402,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46944,9 +47570,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -47058,6 +47681,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -47180,16 +47806,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47280,6 +47903,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47349,9 +47975,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -47365,9 +47988,6 @@ msgstr[3] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -47429,6 +48049,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -47438,9 +48064,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -47523,6 +48146,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47764,12 +48393,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47846,6 +48490,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47876,6 +48523,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47891,6 +48541,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47967,6 +48620,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -48028,6 +48684,9 @@ msgstr[3] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -48190,6 +48849,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -48294,12 +48956,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -48321,6 +48989,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -48345,12 +49016,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -48513,9 +49190,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48668,6 +49342,9 @@ 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 ""
@@ -48764,9 +49441,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48830,6 +49504,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48842,9 +49519,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48863,9 +49546,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48914,9 +49594,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48935,19 +49612,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -49083,9 +49756,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -49108,12 +49778,22 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -49271,6 +49951,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -49411,6 +50094,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/cy_GB/gitlab.po b/locale/cy_GB/gitlab.po
index 44983b73f0a..4f0319894d6 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: 2022-10-10 14:05\n"
+"PO-Revision-Date: 2022-11-13 09:25\n"
msgid " %{start} to %{end}"
msgstr " %{start} i %{end}"
@@ -199,6 +199,15 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -379,15 +388,6 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
@@ -397,15 +397,6 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -424,15 +415,6 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -841,6 +823,9 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -907,6 +892,24 @@ msgstr[5] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -919,6 +922,15 @@ msgstr[5] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%{count} more"
msgstr ""
@@ -949,6 +961,15 @@ msgstr[3] "%{count} cyfranogwr"
msgstr[4] "%{count} chyfranogwr"
msgstr[5] "%{count} cyfranogwr"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} %{pluralized_subject} cysylltiedig: %{links}"
@@ -988,9 +1009,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr "%{duration}ms"
@@ -1201,12 +1219,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1420,6 +1432,9 @@ msgstr[5] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1594,9 +1609,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1654,6 +1666,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1696,6 +1711,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -2089,6 +2107,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -2152,9 +2173,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -2233,9 +2251,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -2443,6 +2458,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2554,15 +2572,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2632,9 +2644,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -3007,6 +3016,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -3190,6 +3205,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -3226,15 +3259,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -3283,6 +3328,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -3328,6 +3376,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -3466,9 +3526,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -3493,6 +3562,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3595,6 +3673,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3787,7 +3868,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3832,7 +3913,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3895,7 +3976,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3943,6 +4024,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -4453,7 +4537,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -4468,6 +4552,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -4504,9 +4591,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4753,6 +4837,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4942,9 +5029,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -5044,9 +5128,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -5149,9 +5230,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -5170,7 +5248,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -5221,6 +5299,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -5239,9 +5320,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -5269,6 +5359,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5629,9 +5722,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5737,7 +5827,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5788,6 +5878,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5839,9 +5953,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -6247,9 +6358,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6613,6 +6721,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -7357,6 +7471,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -7366,6 +7483,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -7387,6 +7507,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -7405,6 +7528,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -7414,6 +7540,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -7432,9 +7561,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -7453,12 +7588,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7618,6 +7762,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7627,9 +7774,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7675,9 +7819,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7708,6 +7849,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7723,6 +7867,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7747,9 +7894,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -8167,9 +8311,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -8185,6 +8326,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8932,6 +9076,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -10255,10 +10402,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -10444,6 +10597,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -11251,10 +11407,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -11287,6 +11443,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -11335,9 +11500,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -11422,9 +11584,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -11587,9 +11746,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11809,9 +11965,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -12079,9 +12232,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -12097,7 +12247,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -12199,9 +12349,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -12532,6 +12679,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -12559,6 +12709,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -12616,6 +12769,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12850,6 +13006,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -13072,6 +13231,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -13159,6 +13321,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -13192,6 +13357,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -13303,6 +13471,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -13324,9 +13495,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -13393,7 +13561,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13894,6 +14062,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13981,6 +14152,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -14329,6 +14515,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -14575,6 +14764,12 @@ msgstr[5] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -14590,6 +14785,9 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
@@ -14599,6 +14797,9 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -15208,6 +15409,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -15538,22 +15745,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15781,6 +16006,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15961,10 +16189,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15979,18 +16207,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -16003,18 +16222,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -16144,9 +16357,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -16210,9 +16420,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -16453,6 +16660,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -16576,6 +16834,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -16633,9 +16894,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16864,6 +17131,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16915,9 +17185,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -17113,9 +17380,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -17377,6 +17641,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17482,9 +17749,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -17692,6 +17956,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -18541,9 +18808,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -18670,6 +18934,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18721,6 +18991,9 @@ 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 ""
@@ -18769,9 +19042,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -19327,9 +19597,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -19339,6 +19606,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -20101,12 +20371,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -20176,6 +20440,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -20362,9 +20629,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20827,7 +21091,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20914,12 +21184,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -22687,6 +22951,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -22705,9 +22972,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22765,7 +23029,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22849,19 +23113,16 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22999,12 +23260,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -23026,6 +23293,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -23251,6 +23530,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -23545,6 +23839,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23875,6 +24172,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23914,9 +24214,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -24301,9 +24607,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -24457,6 +24760,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24607,9 +24919,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24880,6 +25189,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -25150,9 +25465,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -25165,6 +25477,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -25201,7 +25516,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -25216,9 +25537,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -25228,9 +25555,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -25240,7 +25564,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -25297,6 +25621,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -25321,6 +25648,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -25372,6 +25702,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -25384,6 +25717,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -26020,6 +26356,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -26245,6 +26584,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -26644,6 +26986,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26803,6 +27148,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26875,6 +27223,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -27061,6 +27412,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -27529,6 +27883,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -27658,9 +28015,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -27688,9 +28042,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -27706,9 +28057,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27946,7 +28294,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -28297,6 +28645,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -28306,6 +28657,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -28327,6 +28681,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -28420,9 +28777,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -28447,9 +28801,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -28687,12 +29038,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28738,12 +29083,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28765,12 +29104,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28813,15 +29146,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28852,12 +29176,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28876,9 +29194,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -29056,9 +29371,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -29431,12 +29743,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -29482,6 +29803,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -29632,6 +29959,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -30019,12 +30349,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -30073,7 +30397,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -30292,6 +30616,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -30307,6 +30634,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -30319,12 +30649,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -30334,9 +30670,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -31096,9 +31438,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -31207,6 +31546,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -31348,6 +31750,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -31441,12 +31846,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -32023,6 +32434,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -32035,6 +32449,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -32317,12 +32734,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -32335,12 +32758,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -32362,6 +32791,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -32461,6 +32893,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -32599,6 +33034,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -32629,6 +33067,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -32680,6 +33121,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -33319,6 +33763,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -33355,15 +33802,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -33379,12 +33838,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -33694,6 +34162,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33826,12 +34297,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33925,9 +34390,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -34099,6 +34561,9 @@ msgstr[5] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -34108,6 +34573,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -34564,6 +35032,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -34582,15 +35053,6 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -34624,18 +35086,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34654,12 +35110,6 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -34702,21 +35152,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34732,9 +35173,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -35122,6 +35560,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -35359,6 +35800,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -35401,6 +35845,9 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -35437,7 +35884,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -35650,6 +36097,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -35782,9 +36232,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -35833,6 +36289,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -35872,6 +36331,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -35911,12 +36373,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35971,16 +36427,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr ""
+
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -36088,10 +36550,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -36112,9 +36574,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -36124,9 +36592,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -36277,9 +36751,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -36730,10 +37201,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -36853,6 +37327,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36955,10 +37432,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -37048,7 +37525,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -37066,6 +37543,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -37084,12 +37564,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -37111,6 +37600,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -37240,6 +37732,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -37297,6 +37792,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -37414,9 +37912,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -37429,6 +37933,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -37492,9 +37999,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -37633,10 +38137,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -37648,28 +38152,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37888,9 +38392,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -38044,9 +38545,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -38305,10 +38803,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -38362,7 +38857,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -38377,7 +38872,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -38500,9 +38995,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -38725,6 +39217,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38836,9 +39331,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -39412,9 +39904,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -39427,9 +39916,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -39451,9 +39937,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39973,9 +40456,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -40237,6 +40726,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -40327,6 +40819,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -40411,6 +40906,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -40432,15 +40930,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -40462,9 +40954,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -40483,6 +40972,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -40594,24 +41086,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -40639,12 +41113,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -40732,12 +41200,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -41212,6 +41674,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -41407,9 +41872,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -41440,7 +41902,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -41497,9 +41959,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -41851,9 +42310,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -41887,6 +42343,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -42055,9 +42514,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -42118,6 +42574,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -42334,13 +42793,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -42469,9 +42931,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -42490,6 +42949,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42868,9 +43330,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42976,6 +43435,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -43042,9 +43504,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -43066,18 +43552,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -43090,6 +43597,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -43240,9 +43765,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -43567,6 +44089,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -44071,6 +44599,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -44173,6 +44707,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -44203,6 +44740,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -45265,9 +45805,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -45733,6 +46270,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -45751,6 +46291,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -45886,7 +46429,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45928,6 +46471,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -45943,12 +46489,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45988,6 +46546,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -46102,6 +46663,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -46129,9 +46696,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -46144,7 +46708,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -46156,12 +46720,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -46240,6 +46813,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -46249,7 +46825,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -46573,6 +47149,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -46627,9 +47209,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -46660,10 +47257,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -46675,6 +47275,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -46696,6 +47299,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -46714,6 +47320,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -46813,6 +47422,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -46849,6 +47461,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46894,9 +47512,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -47002,6 +47617,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -47074,7 +47692,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -47098,6 +47716,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -47245,6 +47866,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -47308,7 +47932,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -47476,9 +48100,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -47590,6 +48211,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -47716,16 +48340,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47818,6 +48439,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47887,9 +48511,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -47905,9 +48526,6 @@ msgstr[5] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -47971,6 +48589,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -47980,9 +48604,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -48067,6 +48688,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -48316,12 +48943,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -48400,6 +49042,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -48430,6 +49075,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -48445,6 +49093,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -48523,6 +49174,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -48586,6 +49240,9 @@ msgstr[5] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -48754,6 +49411,9 @@ msgstr[3] ""
msgstr[4] ""
msgstr[5] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -48862,12 +49522,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -48889,6 +49555,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -48913,12 +49582,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -49087,9 +49762,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -49246,6 +49918,9 @@ 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 ""
@@ -49342,9 +50017,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -49408,6 +50080,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -49420,9 +50095,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -49441,9 +50122,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -49492,9 +50170,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -49513,21 +50188,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-msgstr[4] ""
-msgstr[5] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -49669,9 +50338,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -49696,12 +50362,24 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+msgstr[4] ""
+msgstr[5] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -49861,6 +50539,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -50005,6 +50686,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/da_DK/gitlab.po b/locale/da_DK/gitlab.po
index 30a8586c79c..2dbe3f728bc 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: 2022-10-10 14:02\n"
+"PO-Revision-Date: 2022-11-13 09:22\n"
msgid " %{start} to %{end}"
msgstr " %{start} til %{end}"
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d godkender"
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] "%d epic"
msgstr[1] "%d epics"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d fejl"
-msgstr[1] "%d fejl"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d eksportør"
msgstr[1] "%d eksportører"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%d mislykket"
-msgstr[1] "%d mislykkedes"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] "%d mislykket sikkerhedsjob"
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] "%d fil"
msgstr[1] "%d filer"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d rettet testresultat"
-msgstr[1] "%d rettede testresultater"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] "%{bold_start}%{count}%{bold_end} åbnet sammenlægningsanmodning"
msgstr[1] "%{bold_start}%{count}%{bold_end} åbnede sammenlægningsanmodninger"
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr "%{code_open}Maskeret:%{code_close} Skjult i joblogge. Skal matche maskeringskrav."
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr "%{count} filer berørt"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "%{count} element"
@@ -575,6 +578,11 @@ msgstr[1] "%{count} elementer"
msgid "%{count} items per page"
msgstr "%{count} elementer pr. side"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr "%{count} mere"
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} deltager"
msgstr[1] "%{count} deltagere"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} relaterede %{pluralized_subject}: %{links}"
@@ -636,9 +649,6 @@ msgstr "%{docs_link_start}Hvad er Large File Storage?%{docs_link_end}"
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr "%{docs_link_start}Hvad er totrinsgodkendelse?%{docs_link_end}"
-msgid "%{due_date} (Past due)"
-msgstr "%{due_date} (overskredet)"
-
msgid "%{duration}ms"
msgstr "%{duration} ms"
@@ -849,12 +859,6 @@ msgstr "Navnerummet %{name_with_link} er løbet tør for pipeline-minutter for d
msgid "%{name} (Busy)"
msgstr "%{name} (optaget)"
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} indeholdte %{resultsString}"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} fandt %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr "%{name} bruges allerede af en anden emoji"
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "%{strong_start}%{branch_count}%{strong_end} gren"
@@ -1182,9 +1189,6 @@ msgstr "%{user} oprettede en problemstilling: %{issue_link}"
msgid "%{value} is not included in the list"
msgstr "%{value} er ikke med på listen"
-msgid "%{value} s"
-msgstr "%{value} s"
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} %{time_spent_value} brugt tid."
@@ -1242,6 +1246,9 @@ msgstr "'%{source}' er ikke en importkilde"
msgid "'%{template_name}' is unknown or invalid"
msgstr "'%{template_name}' er ukendt eller ugyldigt"
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d lukket)"
@@ -1280,6 +1287,9 @@ msgstr "(lad den være tom hvis du ikke vil ændre den)"
msgid "(max size 15 MB)"
msgstr "(maks. størrelse 15 MB)"
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr "Du har ikke tilladelse til at tilgå siden."
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "Sørg for at adressen er korrekt og at siden ikke er flyttet."
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr "Siden blev ikke fundet"
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "En standardgren kan ikke vælges til et tomt projekt."
-
msgid "A deleted user"
msgstr "En slettet bruger"
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr "Et ren HTML-websted som bruger Netlify til CI/CD frem for GitLab, men stadigvæk med alle de andre gode GitLab-funktioner"
-msgid "A platform value can be web, mob or app."
-msgstr "En platformværdi kan være web, mob eller app."
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr "Accepter vilkår"
msgid "Acceptable for use in this project"
msgstr "Acceptabelt til brug i projektet"
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr "Tilgå Git-depoter eller API'et."
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr "Lær mere"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "Meddelelse: %{message}"
-msgid "AccessibilityReport|New"
-msgstr "Ny"
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr "Tilgængeligsskanningen fandt en fejl med følgende type: %{code}"
@@ -2108,9 +2112,6 @@ msgstr "Aktive"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr "Aktive %{type} (%{token_length})"
-
msgid "Active Sessions"
msgstr "Aktive sessioner"
@@ -2483,6 +2484,12 @@ msgstr "Tilføjer %{labels} %{label_text}."
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr "Du er ved at stoppe alle job. Det standser alle nuværende job som køre
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr "Fejl ved indlæsning af statistikken. Prøv venligst igen"
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr "Auto DevOps-domæne"
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr "Konfigurer Let's Encrypt"
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr "Aktivér delte runnere til nye projekter"
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr "Indstillinger for størrelse og domæne for statiske Pages-websteder."
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr "De seneste artefakter for alle job i de nyeste pipelines som er lykkedes i hvert projekt gemmes og udløber ikke."
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr "Administratorer"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr "Godkend"
@@ -3263,8 +3336,8 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr "Gendan brugeradgang til kontoen, herunder web, Git og API."
-msgid "AdminUsers|Search by name, email or username"
-msgstr "Søg efter navn, e-mail eller brugernavn"
+msgid "AdminUsers|Search by name, email, or username"
+msgstr ""
msgid "AdminUsers|Search users"
msgstr "Søg efter brugere"
@@ -3308,8 +3381,8 @@ msgstr "Brugeren modtager ingen underretninger"
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "Skriv %{projectName} for at bekræfte"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "Skriv %{username} for at bekræfte"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr ""
msgid "AdminUsers|Unban user"
msgstr "Fjern udelukkelse af bruger"
@@ -3371,8 +3444,8 @@ msgstr "Uden projekter"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr "Du er ved at slette brugeren %{username} permanent. Problemstillinger, sammenlægningsanmodninger og grupper som er linket til dem vil blive overført til en systembred \"spøgelsesbruger\". Overvej i stedet at bruge funktionen %{strongStart}blokér bruger%{strongEnd} for at forhindre tab af data. Når du %{strongStart}sletter brugeren%{strongEnd}, så kan det ikke fortrydes eller gendannes."
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
-msgstr "Du er ved at slette brugeren %{username} permanent. Det vil slette alle de problemstillinger, sammenlægningsanmodninger og grupper som er linket til dem. Overvej i stedet at bruge funktionen %{strongStart}blokér bruger%{strongEnd} for at forhindre tab af data. Når du har %{strongStart}slettet brugeren%{strongEnd}, så kan det ikke fortrydes eller gendannes."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
+msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
msgstr "Du kan altid blokere deres konto igen hvis det bliver nødvendigt."
@@ -3419,6 +3492,9 @@ msgstr "Administration"
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr "Yderligere brugere skal kontrolleres og godkendes af en systemadministrator. Lær mere om %{help_link_start}forbrugsloft%{help_link_end}."
@@ -3929,8 +4005,8 @@ msgstr "Alle brugere skal have et navn."
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
-msgstr "Tillad \"%{group_name}\" at logge dig ind"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr ""
msgid "Allow access to members of the following group"
msgstr "Tillad adgang for medlemmer af følgende gruppe"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr "Tillad gruppeejere at håndtere LDAP-relaterede indstillinger"
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr "Tillad nøglen at bruge push til depotet"
msgid "Allow use of licensed EE features"
msgstr "Tillad brug af licenserede EE-funktioner"
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr "Tillad brugere at afskedig broadcastmeddelelsen"
@@ -4229,6 +4305,9 @@ msgstr "Der opstod en fejl under hentning af mærkater. Prøv søgningen igen."
msgid "An error occurred while fetching terraform reports."
msgstr "Der opstod en fejl under hentning af terraform-rapporter."
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr "Der opstod en fejl under hentning af jobloggen."
@@ -4414,9 +4493,6 @@ msgstr "Der opstod en fejl under udløsning af jobbet."
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr "Der opstod en fejl under forsøg på at generere rapporten. Prøv venligst igen senere."
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr "Der opstod en ukendt fejl."
msgid "Analytics"
msgstr "Analyse"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "Analyser dine afhængigheder for kendte sårbarheder."
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr "Opdatering af programindstillinger mislykkedes"
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr "Program afinstalleret men kunne ikke ødelægge: %{error_message}"
-
msgid "Application was successfully destroyed."
msgstr "Programmet blev ødelagt."
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr "Restriktioner for e-mail"
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr "Gem ændringer"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr "Send bekræftelses e-mail ved tilmelding"
@@ -5073,9 +5158,6 @@ 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 these artifacts?"
-msgstr "Er du sikker på, at du vil slette artefakterne?"
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,8 +5259,8 @@ msgstr "Er du sikker på, at du vil prøve migreringen igen?"
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
-msgstr "Er du sikker på, at du vil tilbagekalde denne %{type}? Handlingen kan ikke fortrydes."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr "Er du sikker på, at du vil tilbagekalde den personlige adgangstoken? Handlingen kan ikke fortrydes."
@@ -5228,6 +5310,30 @@ msgstr "Artefaktet blev slettet."
msgid "Artifacts"
msgstr "Artefakter"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr "Tildel tilpasset farve såsom #FF0000"
msgid "Assign labels"
msgstr "Tildel etiketter"
-msgid "Assign milestone"
-msgstr "Tildel milepæl"
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr "Automatisk stop annulleret."
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ 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 enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr "Grenen findes allerede"
msgid "Branch changed"
msgstr "Gren ændret"
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr "Grenen er allerede taget"
msgid "Branch name"
msgstr "Grennavn"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr "Broadcastmeddelelse blev opdateret."
msgid "Broadcast Messages"
msgstr "Broadcastmeddelelser"
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "Gennemse mappe"
@@ -7039,9 +7178,6 @@ msgstr "Gennemse fil"
msgid "Browse Files"
msgstr "Gennemse filer"
-msgid "Browse artifacts"
-msgstr "Gennemse artefakter"
-
msgid "Browse files"
msgstr "Gennemse filer"
@@ -7087,9 +7223,6 @@ msgstr "Filtrér efter kildegruppe"
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr "Fra kildegruppe"
-
msgid "BulkImport|Group import history"
msgstr "Historik for gruppeimport"
@@ -7120,6 +7253,9 @@ msgstr "Navnet findes allerede."
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr "Ingen forælder"
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr "Kildegruppe"
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr "Til ny gruppe"
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr "Annullerer forhåndsvisning"
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr "Kan ikke sammenlægges automatisk"
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr "Kan ikke slette %{profile_name} som er refereret til i sikkerhedsregelsæt"
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr "Kan ikke have flere Jira-importer kørende på samme tid"
@@ -8332,6 +8468,9 @@ msgstr "Nøgle"
msgid "CiVariables|Masked"
msgstr "Maskeret"
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr "Beskyttede"
@@ -9647,10 +9786,16 @@ msgstr "Kommentér på linjerne %{startLine} til %{endLine}"
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr "Fuldført"
@@ -10627,11 +10775,11 @@ msgstr "Bidrag"
msgid "Contribution Analytics"
msgstr "Bidragsanalyse"
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
-msgstr "%{created_count} oprettet, %{closed_count} lukket."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
+msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
-msgstr "%{created_count} oprettet, %{merged_count} sammenlagt, %{closed_count} lukket."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
+msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -10663,6 +10811,15 @@ msgstr "Ingen sammenlægningsanmodninger for den valgte tidsperiode."
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr "Kopiér %{name}"
msgid "Copy %{protocol} clone URL"
msgstr "Kopiér klonings-URL for %{protocol}"
-msgid "Copy %{type}"
-msgstr "Kopiér %{type}"
-
msgid "Copy ID"
msgstr "Kopiér id"
@@ -10798,9 +10952,6 @@ msgstr "Kopiér hemmelighed"
msgid "Copy source branch name"
msgstr "Kopiér kildegrennavn"
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr "Kopiér registreringstokenen."
@@ -10963,9 +11114,6 @@ msgstr "Kunne ikke indlæse forbrugstællinger. Opdater venligst siden for at pr
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr "Kunne ikke fjerne %{user} fra %{group}. Kan ikke fjerne sidste gruppeejer."
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr "Kunne ikke fjerne %{user} fra %{group}. Brugeren er ikke et gruppemedlem."
-
msgid "Could not remove the trigger."
msgstr "Kunne ikke fjerne udløseren."
@@ -11185,9 +11333,6 @@ msgstr "Opret ny fil eller mappe"
msgid "Create new label"
msgstr "Opret ny etiket"
-msgid "Create new project"
-msgstr "Opret nyt projekt"
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr "Opretter epic"
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr "Oprettelsesdato"
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr "Ingen loginoplysninger fundet"
msgid "CredentialsInventory|Personal Access Tokens"
msgstr "Personlige adgangstokens"
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr "Nuværende gren"
msgid "Current Project"
msgstr "Nuværende projekt"
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr "Dato"
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr "Personlige"
msgid "DashboardProjects|Trending"
msgstr "Trending"
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr "%{firstProject} og %{secondProject}"
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr "Gem profil"
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr "Datatype"
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr "Opdatering af database mislykkedes"
@@ -12527,6 +12681,9 @@ msgstr "O"
msgid "Days"
msgstr "Dage"
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr "Slet"
msgid "Delete %{issuableType}"
msgstr "Slet %{issuableType}"
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr "Slet %{name}"
@@ -12692,9 +12855,6 @@ msgstr "Slet Value Stream"
msgid "Delete account"
msgstr "Slet konto"
-msgid "Delete artifacts"
-msgstr "Slet artefakter"
-
msgid "Delete asset"
msgstr ""
@@ -12761,8 +12921,8 @@ msgstr ""
msgid "Delete row"
msgstr "Slet række"
-msgid "Delete self monitoring project"
-msgstr "Slet selvovervågningsprojekt"
+msgid "Delete self-monitoring project"
+msgstr ""
msgid "Delete snippet"
msgstr "Slet udklip"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr "Udløber"
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr "Gruppeudsendelsestokens giver mulighed for at tilgå pakkerne, depoterne og registeraftrykkene i gruppen."
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr "Udsendelseshyppighed"
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] "%d sletninger"
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr "Vis %{unfoldCount} linjer"
msgid "Diffs|Show all unchanged lines"
msgstr "Vis alle uændrede linjer"
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Noget gik galt under hentning af diff-linjer."
@@ -14528,6 +14721,12 @@ msgstr "Redigeret"
msgid "Edited %{timeago}"
msgstr "Redigeret %{timeago}"
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr "Redigering"
@@ -14858,22 +15057,40 @@ msgstr "Aktivér brugerdeaktiverings e-mails"
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Copy snippet"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|Close"
-msgstr "Luk"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr ""
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr ""
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr "Stopper automatisk %{autoStopAt}"
msgid "Environments|Commit"
msgstr "Commit"
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr "Slet"
@@ -15281,12 +15501,12 @@ msgstr "Tilføj en ny epic"
msgid "Epics|Add an existing epic"
msgstr "Tilføj en eksisterende epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgstr ""
+
msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr "Er du sikker på, at du vil fjerne %{bStart}%{targetIssueTitle}%{bEnd} fra %{bStart}%{parentEpicTitle}%{bEnd}?"
-msgid "Epics|Assign Epic"
-msgstr "Tildel epic"
-
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr "Lad den være tom for at nedarve fra milepælsdatoer"
@@ -15299,18 +15519,9 @@ msgstr "Fjern epic"
msgid "Epics|Remove issue"
msgstr "Fjern problemstilling"
-msgid "Epics|Search epics"
-msgstr "Søg efter epics"
-
-msgid "Epics|Select epic"
-msgstr "Vælg epic"
-
msgid "Epics|Show more"
msgstr "Vis mere"
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr "Noget gik galt under tildeling af problemstilling til epic."
-
msgid "Epics|Something went wrong while creating child epics."
msgstr "Noget gik galt under oprettelse af underepics."
@@ -15323,18 +15534,12 @@ msgstr "Noget gik galt under hentning af underepics."
msgid "Epics|Something went wrong while fetching epics list."
msgstr "Noget gik galt under hentning af epicliste."
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr "Noget gik galt under hentning af gruppeepics."
-
msgid "Epics|Something went wrong while moving item."
msgstr "Noget gik galt under flytning af element."
msgid "Epics|Something went wrong while ordering item."
msgstr "Noget gik galt under flytning af organisering af element."
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr "Noget gik galt under fjernelse af problemstilling fra epic."
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr "Der opstod en fejl ved gemning af tildelere"
msgid "Error occurred when saving reviewers"
msgstr "Der opstod en fejl under gemning af kontrollanter"
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr "Fejl ved upload af fil"
msgid "Error uploading file. Please try again."
msgstr "Fejl ved upload af fil. Prøv venligst igen."
-msgid "Error uploading file: %{stripped}"
-msgstr "Fejl ved upload af fil: %{stripped}"
-
msgid "Error while loading the merge request. Please try again."
msgstr "Fejl ved indlæsning af sammenlægningsanmodningen. Prøv venligst igen."
@@ -15773,6 +15972,57 @@ msgstr "Begivenheder"
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr "Alle forsøg på %{action} mislykkedes: %{job_error_message}. Prøv venligst igen."
@@ -15892,6 +16142,9 @@ msgstr "Uden sammenlægningscommits. Begrænset til 6.000 commits."
msgid "Execution time"
msgstr "Udførelsestid"
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr "Eksisterende grennavn, mærkat eller commit-SHA"
@@ -15949,9 +16202,15 @@ msgstr "Udfold sidebjælke"
msgid "Expected documents: %{expected_documents}"
msgstr "Forventede dokumenter: %{expected_documents}"
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr "Udløb"
@@ -16176,6 +16435,9 @@ msgstr "Mislykket"
msgid "Failed to add a Zoom meeting"
msgstr "Kunne ikke tilføje et Zoom-møde"
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr "Kunne ikke anvende kommandoer."
@@ -16223,9 +16485,6 @@ msgstr "Kunne ikke oprette framework"
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr "Kunne ikke oprette depot"
@@ -16421,9 +16680,6 @@ msgstr "Kunne ikke opdatere problemstillingsstatus"
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr "Kunne ikke opdatere."
-
msgid "Failed to upgrade."
msgstr "Kunne ikke opgradere."
@@ -16681,6 +16937,9 @@ msgstr "Feb."
msgid "February"
msgstr "Februar"
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr "Filtrér efter sammenlægningsanmodninger som i øjeblikket er lukket el
msgid "Filter by merge requests that are currently merged."
msgstr "Filtrér efter sammenlægningsanmodninger som i øjeblikket er sammenlagt."
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr "Filtrér efter milepælsnavn"
@@ -16996,6 +17252,9 @@ msgstr "For mere information, gå til "
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr "Glemt din adgangskode?"
@@ -17829,9 +18088,6 @@ msgstr "sekundær"
msgid "Get a free instance review"
msgstr "FÃ¥ en gratis instanskontrol"
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr "FÃ¥ et abonnement med support"
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr "GitLab-opkrævningsteam."
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr "GitLab-version"
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr "GitLab.com"
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr "Stadie"
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr "Gravatar"
@@ -18627,6 +18886,9 @@ msgstr "Gravatar aktiveret"
msgid "Group"
msgstr "Gruppe"
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr "Gruppen %{group_name} kunne ikke eksporteres."
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr "Indlæser grupper"
-msgid "GroupsTree|No groups matched your search"
-msgstr "Ingen grupper matchede din søgning"
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr "Retningslinje"
@@ -19642,9 +19901,6 @@ msgstr "Sunhedsinformation kan indhentes fra følgende slutpunkter. Mere informa
msgid "Health status"
msgstr "Helbredsstatus"
-msgid "Health status cannot be edited because this issue is closed"
-msgstr "Helbredsstatussen kan ikke redigeres da problemstillingen er lukket"
-
msgid "HealthCheck|Access token is"
msgstr "Adgangstoken er"
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr "Hvis e-mailen blev tilføjet ved en fejl, så kan du fjerne den her:"
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr "Hvis det var en fejltagelse, så kan du %{leave_link_start}forlade %{source_type}%{link_end}."
@@ -21943,6 +22199,9 @@ msgstr "Ugyldig totrinskode."
msgid "Invalid yaml"
msgstr "Ugyldig yaml"
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr "Invitation afvist"
msgid "Invite \"%{email}\" by email"
msgstr "Inviter \"%{email}\" via e-mail"
-msgid "Invite \"%{trimmed}\" by email"
-msgstr "Inviter \"%{trimmed}\" via e-mail"
-
msgid "Invite Members"
msgstr "Inviter medlemmer"
@@ -22021,7 +22277,7 @@ msgstr "Inviter dine kollegaer"
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr "Vi har bemærket at du ikke har inviteret nogen til gruppen. Invitér dine kollegaer, så du kan debattere problemstillinger, samarbejde på sammenlægningsanmodninger og dele din viden."
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr "Bruger licenssæde:"
msgid "Is using seat"
msgstr "Bruger sæde"
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr "flyttet"
msgid "IssuableStatus|promoted"
msgstr "forfremmet"
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr "Problemstilling"
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr "I alt:"
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr "Titel"
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr "Download"
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr "Sidst ændret"
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr "Forlad projekt"
msgid "Leave zen mode"
msgstr "Forlad zen-tilstand"
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr "Linjeændringer"
msgid "Link"
msgstr "Link"
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr "Logo fjernes. Er du sikker?"
msgid "Logs"
msgstr "Logge"
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr "MD5"
msgid "MERGED"
msgstr "SAMMENLAGT"
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,8 +24728,14 @@ msgstr "Vis kun ændringer"
msgid "MRDiff|Show full file"
msgstr "Vis hele filen"
-msgid "Made this issue confidential."
-msgstr "Gjorde problemstillingen fortrolig."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
+msgstr ""
msgid "Mailgun"
msgstr "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr "Mailgun-begivenheder"
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr "Vedligeholdelsestilstand"
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr "Gør problemstilling fortrolig"
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,8 +24776,8 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
-msgstr "Gør problemstillingen fortrolig."
+msgid "Makes this %{type} confidential."
+msgstr ""
msgid "Manage %{workspace} labels"
msgstr ""
@@ -24517,6 +24833,9 @@ msgstr "HÃ¥ndteret konto"
msgid "Manifest"
msgstr "Manifest"
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr "Mar."
msgid "March"
msgstr "Marts"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr "Mærk som færdig"
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr "Metode"
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr "Forfaldsdato for milepæl"
msgid "Milestone lists not available with your current license"
msgstr "Milepælslister er ikke tilgængelige med din nuværende licens"
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr "Der opstod en fejl under søgning efter milepæle"
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr "Du vil ikke være i stand til at bruge pull eller push på depoter via SSH før du tilføjer en SSH-nøgle til din profil"
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr "Tilføj projekter"
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr "Ingen omfang"
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr "Ingen gennemløb at vise"
msgid "No job log"
msgstr "Ingen joblog"
-msgid "No jobs to show"
-msgstr "Ingen job at vise"
-
msgid "No label"
msgstr "Ingen etiket"
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr "Ingen medlemmer fundet"
@@ -26902,9 +27245,6 @@ msgstr "Ingen meddelelser blev logget"
msgid "No milestone"
msgstr "Ingen milepæl"
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr "Sammenfold svar"
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr "Antal begivenheder"
-msgid "Number of events for this project: %{total_count}."
-msgstr "Antal begivenheder for projektet: %{total_count}."
-
msgid "Number of files touched"
msgstr "Antal filer berørt"
@@ -27623,9 +27969,6 @@ msgstr "Okt."
msgid "October"
msgstr "Oktober"
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr "Fra"
@@ -27859,12 +28202,6 @@ msgstr "Kunne ikke hente webstedsprofiler. Opdater venligst siden eller prøv ig
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr "Kunne ikke køre skanningen. Prøv venligst igen."
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr "Opret ny webstedsprofil"
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr "HÃ¥ndter skannerprofiler"
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr "Skannerprofil"
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr "Brug eksisterende skannerprofil"
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr "Når den er fjernet kan forgreningsrelationen ikke gendannes. Projektet vil ikke længere være i stand til at modtage eller sende sammenlægningsanmodninger til kildeprojektet eller andre forgreninger."
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr "Når du bekræfter og trykker på \"Reducer projektets synlighed\":"
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] "Et element mere"
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr "Slet pakke"
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr "Hvis du ikke allerede har gjort det, så skal du tilføje det nedenunder til din %{codeStart}.pypirc%{codeEnd}-fil."
@@ -28792,6 +29111,9 @@ msgstr "Beklager, dit filter gav ingen resultater"
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr "MÃ¥l-SHA: %{sha}"
@@ -29175,12 +29497,6 @@ msgstr "væg"
msgid "Period in seconds"
msgstr "Periode i sekunder"
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,8 +29545,8 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr "URL for Phabricator-server"
-msgid "Phabricator Tasks"
-msgstr "Phabricator-opgaver"
+msgid "Phabricator tasks"
+msgstr ""
msgid "Phone"
msgstr ""
@@ -29448,6 +29764,9 @@ msgstr "Aktiv"
msgid "PipelineSchedules|All"
msgstr "Alle"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr "Inaktiv"
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr "Næste kørsel"
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "Angiv en kort beskrivelse til pipelinen"
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr "Tag ejerskab"
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr "MÃ¥l"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr "Variabler"
@@ -30252,9 +30586,6 @@ msgstr "Vælg venligst et Jira-projekt"
msgid "Please select a country"
msgstr "Vælg venligst et land"
-msgid "Please select a file"
-msgstr "Vælg venligst en fil"
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr "Præferencer"
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr "Forhindr automatisk stop af miljø"
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr "Fortsæt"
-msgid "Product Analytics"
-msgstr "Produktanalyse"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
+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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr "Produktivitet"
@@ -31179,6 +31582,9 @@ msgstr "Projektnavn"
msgid "Project navigation"
msgstr "Projektnavigation"
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr "Projektslug"
@@ -31473,12 +31882,18 @@ msgstr "%{link_start}Hvad er beskrivelsesskabeloner?%{link_end}"
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr "Yderligere indstillinger der påvirker hvordan og hvornår sammenlægninger foretages."
+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 ""
@@ -31491,12 +31906,18 @@ msgstr "Vis altid belønningsemojiknapper med tommelfinger-op og tommelfinger-ne
msgid "ProjectSettings|Analytics"
msgstr "Analyse"
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr "Badges"
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr "Byg, test og udsend dine ændringer."
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr "Konfigurer dine projektressourcer og overvåg deres helbred."
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr "Internt"
@@ -31755,6 +32182,9 @@ msgstr "Sikkerhed og overholdelse"
msgid "ProjectSettings|Security & Compliance for this project"
msgstr "Sikkerhed og overholdelse for projektet"
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr "Squashing udføres altid. Afkrydsningsboksen er synlig og tilvalgt, og b
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr "Squashing udføres aldrig og afkrydsningsboksen er skjult."
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr "Indsend ændringer som skal sammenlægges upstream."
@@ -31836,6 +32269,9 @@ msgstr "Brugere kan kopiere depotet til et nyt projekt."
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr "Brugere kan anmode om adgang"
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr "Hold stabile grene sikre og tving udviklere til at bruge sammenlægningsanmodninger."
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr "Lær mere."
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr "Beskyt"
@@ -32535,12 +32986,21 @@ msgstr "Beskyttede grene"
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr "Push-regler"
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr "Læs mere"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr "Læs mere om GitLab på %{link_to_promo}."
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr "Læs mere om relaterede problemstillinger"
-
msgid "Read their documentation."
msgstr "Læs deres dokumentation."
@@ -33081,9 +33538,6 @@ msgstr "Reducer projektets synlighed"
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr "Reducer projektets synlighed?"
-
msgid "Reference"
msgstr "Reference"
@@ -33247,6 +33701,9 @@ msgstr[1] "Udgivelser"
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr "Udgivelsesmaterialer"
@@ -33256,6 +33713,9 @@ msgstr "Dokumentation for udgivelsesmaterialer"
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr "Rapporteret af"
msgid "Reported by %{reporter}"
msgstr "Rapporteret af %{reporter}"
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr "Rapporterer"
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr "Der opstod en fejl under indlæsning af rapport"
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr "Klassenavn"
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr "Mislykkedes"
-
-msgid "Reports|Filename"
-msgstr "Filnavn"
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr "Skanner"
msgid "Reports|Severity"
msgstr "Alvorlighed"
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr "Testopsummering"
-msgid "Reports|Test summary failed loading results"
-msgstr "Testopsummering kunne ikke indlæse resultater"
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr "Testopsummeringsresultater er ved at blive fortolket"
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr "Depoter"
@@ -34234,6 +34668,9 @@ msgstr "Løst af"
msgid "Resolved by %{name}"
msgstr "Løst af %{name}"
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr "Svar"
@@ -34463,6 +34900,9 @@ msgstr "Kør CI-/CD-pipelines med Jenkins."
msgid "Run housekeeping"
msgstr "Kør husarbejde"
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr "Kør manuelle eller forsinkede job"
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr "Aktiv"
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr "Online"
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr "Vis installationsinstruktioner"
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr "SAML-opdagelsestokens"
msgid "SAML for %{group_name}"
msgstr "SAML for %{group_name}"
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr ""
+
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr "Gemmer"
msgid "Saving project."
msgstr "Gemmer projekt."
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr "Søg efter en LDAP-gruppe"
msgid "Search for a group"
msgstr "Søg efter en gruppe"
-msgid "Search for a user"
-msgstr "Søg efter en bruger"
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,11 +36233,14 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
-msgstr "%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
-msgstr "%{branches} og %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
+msgstr ""
msgid "SecurityOrchestration|%{scanners}"
msgstr ""
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr "Tilføj projekter"
msgid "SecurityReports|All activity"
msgstr "Al aktivitet"
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr "Overvågede projekter"
msgid "SecurityReports|More info"
msgstr "Mere information"
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr "Ingen aktivitet"
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr "Sikkerhedsskanninger har kørt"
@@ -36450,9 +36944,15 @@ msgstr "Din feedback er vigtig for os! Vi spørger igen om en uge."
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr "Se målinger"
msgid "See our website for help"
msgstr "Se vores websted for hjælp"
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr "Vælg et skabelondepot"
msgid "Select a template type"
msgstr "Vælg en skabelontype"
-msgid "Select a timezone"
-msgstr "Vælg en tidszone"
-
msgid "Select all"
msgstr "Vælg alle"
@@ -36669,11 +37169,11 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr "Valg af en GitLab-bruger vil tilføje et link til GitLab-brugeren i beskrivelserne af problemstillinger og kommentarer (f.eks. \"Af %{link_open}@ronnierev%{link_close}\"). Det vil også tilknytte og/eller tildele problemstillingerne og kommentarerne med den valgte bruger."
-msgid "Self monitoring"
-msgstr "Selvovervågning"
+msgid "Self-monitoring"
+msgstr ""
-msgid "Self monitoring project does not exist"
-msgstr "Selvovervågningsprojekt findes ikke"
+msgid "Self-monitoring project does not exist"
+msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
msgstr "Selvovervågningsprojekt findes ikke. Tjek venligst loggene for fejlmeddelelser"
@@ -36684,29 +37184,29 @@ 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 "SelfMonitoring|Activate or deactivate instance self monitoring."
-msgstr "Aktivér eller deaktivér selvovervågning af instans."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
+msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
-msgstr "Aktivér selvovervågning for at oprette et projekt som skal bruges til at overvåge helbredet på din instans."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
+msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
-msgstr "Deaktivér selvovervågning?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
+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 "Deaktivering af selvovervågning sletter selvovervågningsprojektet. Er du sikker på, at du vil deaktivere selvovervågning og slette projektet?"
+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|Self monitoring"
-msgstr "Selvovervågning"
+msgid "SelfMonitoring|Self-monitoring"
+msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
-msgstr "Selvovervågning er aktiv. Brug %{projectLinkStart}selvovervågningsprojektet%{projectLinkEnd} til at overvåge helbredet på din instans."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
-msgstr "Selvovervågningsprojekt oprettet."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
+msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
-msgstr "Selvovervågningsprojekt slettet."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
+msgstr ""
msgid "Send"
msgstr "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr "Indstillinger"
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr "Opsætning"
-
msgid "Severity"
msgstr "Alvorlighed"
@@ -37333,10 +37827,7 @@ msgstr "Viser alle epics"
msgid "Showing all issues"
msgstr "Viser alle problemstillinger"
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr "Log ind via 2FA-kode"
msgid "Sign in with"
msgstr "Log ind med"
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr "Størrelsesgrænser"
msgid "Size limit per repository (MB)"
msgstr "Størrelsesgrænse pr. depot (MB)"
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr "Sprunget over"
@@ -37753,6 +38241,9 @@ msgstr "Nogen redigerede sammenlægningsanmodningen på samme tid som dig. Opdat
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr "Nogen redigerede testsagen på samme tid som dig. Beskrivelsen er blevet opdateret og du skal foretage dine ændringer igen."
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr "Noget gik galt under hentning af miljøerne for sammenlægningsanmodning
msgid "Something went wrong while fetching the packages list."
msgstr "Noget gik galt under hentning af pakkelisten."
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr "Noget gik galt under hentning af initiering af OpenAPI-fremviseren"
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr "Noget gik galt under indhentelse af Let's Encrypt-certifikatet."
@@ -38440,9 +38928,6 @@ msgstr "Status:"
msgid "Status: %{title}"
msgstr "Status: %{title}"
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr "Tilføj statustjek"
-msgid "StatusCheck|All passed"
-msgstr "Alle bestået"
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr "Kunne ikke indlæse statustjek."
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr "Skift gren"
msgid "Switch branch/tag"
msgstr "Skift gren/mærkat"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr "Skift til GitLab Next"
@@ -39351,6 +39839,9 @@ msgstr "Indholdsfortegnelse"
msgid "Tag"
msgstr "Mærkat"
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr "Mærkatliste:"
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr "Udgivelsesnoter"
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "Skriv dine udgivelsesnoter eller træk filer hertil …"
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr "beskyttet"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr "MÃ¥lgren"
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr "%{name} fjernet"
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] "%{number} Terraform-rapport blev genereret i dine pipelines"
-msgstr[1] "%{number} Terraform-rapporter blev genereret i dine pipelines"
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr "En rapport kunne ikke genereres."
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr "En rapport blev genereret i dine pipelines."
-
msgid "Terraform|Actions"
msgstr "Handlinger"
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr "Værtsnavnet på din PlantUML-server."
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,8 +40894,8 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr "Det angivne faneblad er ugyldigt. Vælg venligst et andet"
-msgid "The start date must be ealier than the end date."
-msgstr "Startdatoen skal være tidligere end slutdatoen."
+msgid "The start date must be earlier than the end date."
+msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
msgstr "Emnet vil blive brugt som titlen på den nye problemstilling og meddelelsen vil blive beskrivelsen. %{quickActionsLinkStart}Hurtighandlinger%{quickActionsLinkEnd} og styling med %{markdownLinkStart}Markdown%{markdownLinkEnd} understøttes."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr "%{viewer} kunne ikke vises fordi %{reason}. Du kan i stedet %{options}."
msgid "This Cron pattern is invalid"
msgstr "Cron-mønsteret er ugyldigt"
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr "Gruppen er blevet planlagt til permanent sletning %{date}"
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr "Gruppen er linket til et abonnement"
@@ -41322,15 +41785,18 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr "Navnerummet er allerede blevet taget! Vælg venligst et andet."
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
+msgstr ""
+
msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr "Siden er utilgængelig fordi du ikke har tilladelse til at læse information på tværs af flere projekter."
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
-msgstr ""
-
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
msgstr ""
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr "Brugeren har ingen aktive %{type}."
-
msgid "This user has no identities"
msgstr "Brugeren har ingen identiteter"
@@ -41478,6 +41941,9 @@ msgstr "Brugeren er forfatteren af denne %{noteable}."
msgid "This variable can not be masked."
msgstr "Variablen kan ikke maskeres."
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr "Skriv %{phrase_code} for at bekræfte"
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr "Log ind på GitLab på %{gitlab_url} for at genaktivere din konto."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr "I dag"
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr "GitLab Next til/fra"
@@ -42220,9 +42749,6 @@ msgstr "Bidragsydere i alt"
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr "Kerner i alt (CPU'er)"
@@ -42543,6 +43069,12 @@ msgstr "Totrinsgodkendelse er blevet deaktiveret for brugeren"
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr "Totrinsgodkendelse er blevet deaktiveret på din GitLab-konto."
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr "Totrinsgodkendelse er blevet deaktiveret!"
@@ -43047,6 +43579,12 @@ msgstr "Forbrugstrends"
msgid "Usage statistics"
msgstr "Forbrugsstatistik"
+msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
+msgstr ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr "Pakker"
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr "Sæder"
@@ -44229,9 +44773,6 @@ msgstr "Vis fil @ %{commitSha}"
msgid "View full dashboard"
msgstr "Vis hele betjeningspanelet"
-msgid "View full log"
-msgstr "Vis hele loggen"
-
msgid "View group in admin area"
msgstr "Vis gruppe i administratorområde"
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr "Status"
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "Vi vil være sikker på, at det er dig. Bekræft venligst at du ikke er en robot."
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr "WebAuthn-enheder (%{length})"
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr "WebAuthn virker kun med HTTPS-aktiverede websteder. Kontakt din administrator for flere detaljer."
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr "Forgren projekt"
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr "Du kan ikke redigere filer direkte i projektet. Forgren projektet og indsend en sammenlægningsanmodning med dine ændringer."
@@ -44948,6 +45510,9 @@ msgstr "Webhooks"
msgid "Webhooks Help"
msgstr "Hjælp for webhooks"
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr "Hændelser for push"
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr "Hændelser for udgivelser"
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr "Udløser"
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr "Hændelser for wikiside"
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr "Hvad er squashing?"
msgid "What templates can I create?"
msgstr "Hvilke skabeloner kan jeg oprette?"
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr "Hvad vil du bruge gruppen til?"
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr "Nyheder"
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr "Vil du oprette en ny gren?"
@@ -45757,6 +46370,9 @@ msgstr "Du er ved at slette en fil som tidligere er blevet opdateret."
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr "Du har ikke tilladelse til at %{action} en bruger"
msgid "You are not allowed to approve a user"
msgstr "Du har ikke tilladelse til at godkende en bruger"
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr "Du prøver på at uploade noget andet end et billede. Upload venligst en .png, .jpg, .jpeg, .gif, .bmp, .tiff eller .ico."
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr "Du kan %{gitlabLinkStart}løse konflikter på GitLab%{gitlabLinkEnd} eller %{resolveLocallyStart}løse det lokalt%{resolveLocallyEnd}."
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr "Du kan ikke efterligne en blokeret bruger"
msgid "You cannot impersonate a user who cannot log in"
msgstr "Du kan ikke efterligne en bruger som ikke kan logge ind"
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr "Du kan ikke efterligne en intern bruger"
@@ -46181,6 +46806,9 @@ msgstr "Du har ikke tilstrækkelige tilladelser til at oprette en vagtplan for p
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr "YouTube"
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr "Der blev logget ind på din %{host}-konto fra en ny placering"
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr "Din konto er låst."
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr "Din handling lykkedes."
@@ -46644,16 +47272,13 @@ msgstr "Din meddelelse her"
msgid "Your name"
msgstr "Dit navn"
-msgid "Your new %{accessTokenType}"
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new %{type}"
-msgstr "Din nye %{type}"
-
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr "Dit brugernavn er %{username}."
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr "`end_time` skal ikke være mere end en måned efter `start_time`"
msgid "`start_time` should precede `end_time`"
msgstr "`start_time` skal være før `end_time`"
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr "en slettet bruger"
@@ -46825,9 +47450,6 @@ msgstr[1] "cirka %d timer"
msgid "access:"
msgstr "adgang:"
-msgid "added"
-msgstr "tilføjet"
-
msgid "added %{emails}"
msgstr "tilføjede %{emails}"
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr "tildel dig selv"
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr "kl."
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr "vedhæft en ny fil"
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr "må ikke ændres"
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr "Afhængighedsskanning"
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr "Download patchen for at anvende den manuelt"
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr "Ny"
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr "Sikkerhedsskanning"
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr "Løsning"
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr "commit %{commit_id}"
msgid "committed"
msgstr "committed"
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] "dage"
msgid "days"
msgstr "dage"
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr "standardgren"
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] "fra %d job"
msgstr[1] "fra %d job"
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr "frontmatter"
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr "er"
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr "er ikke"
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr "er ikke et gyldigt X509-certifikat."
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr "er ikke gyldig. Gennemløbsgruppen skal matche gennmløbskadencegruppen."
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr "er skrivebeskyttet"
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr "%{mergeError}."
@@ -48090,6 +48766,9 @@ 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."
@@ -48186,9 +48865,6 @@ msgstr "Tilbagefør sammenlægningsanmodningen i en ny sammenlægningsanmodning"
msgid "mrWidget|Revoke approval"
msgstr "Tilbagekald godkendelse"
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr "Indstillet af %{merge_author} til at blive tilføjet til sammenlægningstoget når pipelinen lykkes"
@@ -48252,6 +48928,9 @@ msgstr "skal være efter start"
msgid "must be an email you have verified"
msgstr "skal være en e-mail du har verificeret"
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr "skal være større end startdato"
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr "min-kanal"
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr "behøver opmærksomhed"
-
msgid "needs to be between 10 minutes and 1 month"
msgstr "skal være fra 10 minutter til 1 måned"
@@ -48336,9 +49018,6 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item} og %{lastItem}"
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr "eller"
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] "ud af %d test i alt"
-msgstr[1] "ud af %d tests i alt"
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "forælder"
@@ -48497,9 +49174,6 @@ msgstr "fjern startdato"
msgid "remove weight"
msgstr "fjern vægt"
-msgid "removed"
-msgstr "fjernet"
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr "depot:"
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr "opfyldt"
@@ -48681,6 +49363,9 @@ msgstr "dokumentet"
msgid "time summary"
msgstr "tidsopsummering"
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr "yaml ugyldig"
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/de/gitlab.po b/locale/de/gitlab.po
index ecdde1d6852..8ed95d1bd53 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: 2022-10-10 14:02\n"
+"PO-Revision-Date: 2022-11-13 09:22\n"
msgid " %{start} to %{end}"
msgstr " %{start} bis %{end}"
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] "%d zusätzlicher Benutzer"
msgstr[1] "%d zusätzliche Benutzer"
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] "%d Zustimmung erforderlich"
+msgstr[1] "%d Zustimmungen erforderlich"
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d Genehmigende(r)"
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] "%d Epic"
msgstr[1] "%d Epics"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d Fehler"
-msgstr[1] "%d Fehler"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d Exporter"
msgstr[1] "%d Exporter"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%d fehlgeschlagen"
-msgstr[1] "%d fehlgeschlagen"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] "%d fehlgeschlagener Sicherheitsjob"
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] "%d Datei"
msgstr[1] "%d Dateien"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d korrigiertes Testergebnis"
-msgstr[1] "%d korrigierte Testergebnisse"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] "%d Fork"
@@ -405,8 +395,8 @@ msgstr[1] "%d Sekunden"
msgid "%d stage"
msgid_plural "%d stages"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d Stufe"
+msgstr[1] "%d Stufen"
msgid "%d star"
msgid_plural "%d stars"
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] "%{bold_start}%{count}%{bold_end} offener Merge Request"
msgstr[1] "%{bold_start}%{count}%{bold_end} offene Merge Requests"
+msgid "%{chartTitle} no data series"
+msgstr "%{chartTitle} keine Datenreihe"
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr "%{code_open}Maskiert:%{code_close} In Job-Logs versteckt. Muss Maskier-Bedingungen erfüllen."
@@ -567,6 +560,16 @@ msgstr[1] "%{count} Kontakte"
msgid "%{count} files touched"
msgstr "%{count} Dateien verändert"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] "%{count} Gruppe"
+msgstr[1] "%{count} Gruppen"
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] "%{count} Ticket"
+msgstr[1] "%{count} Tickets"
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "%{count} Element"
@@ -575,6 +578,11 @@ msgstr[1] "%{count} Elemente"
msgid "%{count} items per page"
msgstr "%{count} Einträge pro Seite"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] "%{count} Merge Request"
+msgstr[1] "%{count} Merge Requests"
+
msgid "%{count} more"
msgstr "%{count} weitere"
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} Teilnehmer(in)"
msgstr[1] "%{count} Teilnehmer(innen)"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] "%{count} Projekt"
+msgstr[1] "%{count} Projekte"
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} verwandte %{pluralized_subject}: %{links}"
@@ -636,9 +649,6 @@ msgstr "%{docs_link_start}Was ist \"Large File Storage\"?%{docs_link_end}"
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr "%{docs_link_start}Was ist Zwei-Faktor-Authentifizierung?%{docs_link_end}"
-msgid "%{due_date} (Past due)"
-msgstr "%{due_date} (überfällig)"
-
msgid "%{duration}ms"
msgstr "%{duration}ms"
@@ -849,12 +859,6 @@ msgstr "%{name_with_link} Namespace hat keine Pipeline-Minuten auf geteilten Run
msgid "%{name} (Busy)"
msgstr "%{name} (Beschäftigt)"
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} enthielt %{resultsString}"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} gefunden %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr "%{name} wird bereits für ein anderes Emoji verwendet"
@@ -903,7 +907,7 @@ msgid "%{openedIssues} open, %{closedIssues} closed"
msgstr "%{openedIssues} offen, %{closedIssues} geschlossen"
msgid "%{over_limit_message} To get more members, an owner of the group can start a trial or upgrade to a paid tier."
-msgstr ""
+msgstr "%{over_limit_message} Um mehr Mitglieder zu bekommen, kann ein Eigentümer der Gruppe eine Testversion starten oder ein Upgrade auf eine kostenpflichtige Version durchführen."
msgid "%{over_limit_message} To get more seats, %{link_start}upgrade to a paid tier%{link_end}."
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr "%{strongStart}Tipp:%{strongEnd} Du kannst Merge Requests auch lokal auschecken. %{linkStart}Mehr erfahren. %{linkEnd}"
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "%{strong_start}%{branch_count}%{strong_end} Branch"
@@ -1182,9 +1189,6 @@ msgstr "%{user} hat ein Ticket erstellt: %{issue_link}"
msgid "%{value} is not included in the list"
msgstr "%{value} ist nicht in der Liste enthalten"
-msgid "%{value} s"
-msgstr "%{value} s"
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} %{time_spent_value} verbrachte Zeit."
@@ -1242,6 +1246,9 @@ msgstr "'%{source}' ist keine Import-Quelle"
msgid "'%{template_name}' is unknown or invalid"
msgstr "'%{template_name}' ist unbekannt oder ungültig"
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d geschlossen)"
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr "(kein Benutzer)"
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr "Du hast nicht die Berechtigung auf diese Seite zuzugreifen."
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "Stelle sicher, dass die Adresse korrekt ist und die Seite nicht verschoben wurde."
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr "Seite nicht gefunden"
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "Ein Default-Branch kann nicht für ein leeres Projekt ausgewählt werden."
-
msgid "A deleted user"
msgstr "Ein(e) gelöschte(r) Benutzer(in)"
@@ -1709,9 +1719,6 @@ msgstr "Ein persönliches Zugangstoken, namens %{token_name}, wurde widerrufen."
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr "Eine einfache HTML-Seite, welche Netlify anstatt GitLab für CI/CD nutzt, aber trotzdem von den nützlichen GitLab-Funktionen profitiert"
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr "Eine Projektvorlage für die Salesforce-App-Entwicklung mit Salesforce-Developer-Tools"
@@ -1919,6 +1926,9 @@ msgstr "Bedingungen akzeptieren"
msgid "Acceptable for use in this project"
msgstr "Akzeptabel für die Verwendung in diesem Projekt"
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr "Mehr erfahren"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "Nachricht: %{message}"
-msgid "AccessibilityReport|New"
-msgstr "Neu"
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr "Aktiv"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr "Aktive Sitzungen"
@@ -2483,6 +2484,12 @@ msgstr "Fügt %{labels} %{label_text} hinzu."
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr "Fügt einen Ressourcen-Link hinzu"
+
+msgid "Adds a resource link for this incident."
+msgstr "Fügt einen Ressourcen-Link für diesen Vorfall hinzu."
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr "Fehler beim Laden der Statistik. Bitte versuche es erneut"
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr "Empfängergruppe oder Projekt"
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr "Empfängergruppe oder Projekt ist erforderlich."
+
+msgid "AdminEmail|Subject"
+msgstr "Betreff"
+
+msgid "AdminEmail|Subject is required."
+msgstr "Betreff ist erforderlich."
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr "Auto-DevOps-Domain"
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr "'Geteilte Runner' für neue Projekte aktivieren"
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr "Admins"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,8 +3336,8 @@ msgstr "Reset-Link wird generiert und an den Benutzer gesendet. Der Benutzer wir
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr "Zugriff auf das Konto wiederherstellen, einschließlich Web, Git und API."
-msgid "AdminUsers|Search by name, email or username"
-msgstr "Suche nach Name, E-Mail oder Benutzername"
+msgid "AdminUsers|Search by name, email, or username"
+msgstr ""
msgid "AdminUsers|Search users"
msgstr "Benutzer(innen) suchen"
@@ -3308,8 +3381,8 @@ msgstr "Diese(r) Benutzer(in) erhält keine Benachrichtigungen"
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "Zur Bestätigung %{projectName} eingeben"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "Zur Bestätigung %{username} eingeben"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr "Zur Bestätigung %{username} eingeben."
msgid "AdminUsers|Unban user"
msgstr ""
@@ -3371,7 +3444,7 @@ msgstr "Ohne Projekte"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr "Verwaltung"
msgid "Administrators"
msgstr "Administratoren"
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,8 +4005,8 @@ msgstr "Alle Benutzer(innen) benötigen einen Namen."
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
-msgstr "Erlaube \"%{group_name}\" dich anzumelden"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr ""
msgid "Allow access to members of the following group"
msgstr ""
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr "Gruppenbesitzer erlauben, LDAP-bezogene Einstellungen zu verwalten"
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr "Benutzern das Erstellen von Gruppen auf oberster Ebene erlauben"
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr "Beim Abrufen des Jobprotokolls ist ein Fehler aufgetreten."
@@ -4414,9 +4493,6 @@ msgstr "Beim Starten des Jobs ist ein Fehler aufgetreten."
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr "Analysen"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr "Anwendungseinstellungen erfolgreich gespeichert."
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr "Die Anwendung wurde deinstalliert, konnte jedoch nicht gelöscht werden: %{error_message}"
-
msgid "Application was successfully destroyed."
msgstr "Anwendung wurde erfolgreich gelöscht."
@@ -4642,7 +4712,7 @@ msgstr "Link zu Grafana hinzufügen"
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ 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 must confirm their email address before they can log in."
+msgstr ""
+
msgid "ApplicationSettings|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr "Möchtest du diese Artefakte wirklich löschen?"
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,8 +5259,8 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
-msgstr ""
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
+msgstr "Möchtest du wirklich dieses Gruppen-Zugangstoken löschen? Diese Aktion kann nicht rückgängig gemacht werden."
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr ""
@@ -5228,6 +5310,30 @@ msgstr "Artefakt wurde erfolgreich gelöscht."
msgid "Artifacts"
msgstr "Artefakte"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr "%{name} löschen?"
+
+msgid "Artifacts|Delete artifact"
+msgstr "Artefakt löschen"
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr "Benutzerdefinierte Farbe wie #FF0000 zuweisen"
msgid "Assign labels"
msgstr "Label zuweisen"
-msgid "Assign milestone"
-msgstr "Meilenstein zuweisen"
-
msgid "Assign myself"
msgstr "Selbst zuweisen"
@@ -5675,9 +5778,6 @@ msgstr "Auto-Stop erfolgreich abgebrochen."
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr "Referenzierte Tickets im Standard-Branch automatisch schließen"
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ 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 enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr "Branch existiert bereits"
msgid "Branch name"
msgstr "Branch-Name"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr "Branch nicht geladen - %{branchId}"
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr "Branch"
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr "Details zu den Branch-Regeln"
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr "Gruppen"
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr "Rollen"
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr "Zielbranch"
@@ -7030,6 +7166,9 @@ msgstr "Broadcast-Nachricht wurde erfolgreich aktualisiert."
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "Verzeichnis durchsuchen"
@@ -7039,9 +7178,6 @@ msgstr "Datei durchsuchen"
msgid "Browse Files"
msgstr "Dateien durchsuchen"
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr "Dateien durchsuchen"
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr "Schließe Vorschau"
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr "Kann nicht automatisch zusammengeführt werden"
@@ -7593,6 +7726,9 @@ msgstr "Der Missbrauchsbericht kann nicht erstellt werden. Der/Die Benutzer(in)
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr "Schlüssel"
msgid "CiVariables|Masked"
msgstr "Maskiert"
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,11 +9786,17 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
-msgstr ""
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr "Das Kommentieren von Dateien, die nur verschoben oder umbenannt werden, wird nicht unterstützt"
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
-msgstr ""
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr "Das Kommentieren von Dateien, die symbolische Links ersetzen oder durch diese ersetzt werden, wird nicht unterstützt"
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr "Das Kommentieren von symbolischen Links, die Dateien ersetzen oder durch Dateien ersetzt werden, wird nicht unterstützt"
+
+msgid "Commenting on this line is not supported"
+msgstr "Das Kommentieren dieser Zeile wird nicht unterstützt"
msgid "Comments"
msgstr "Kommentare"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr "Mit Fehlern abgeschlossen"
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr "Beitrag"
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr "Kopiere %{protocol} clone-URL"
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr "ID kopieren"
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr "Erstelle eine neue Datei oder ein neues Verzeichnis"
msgid "Create new label"
msgstr "Neues Label erstellen"
-msgid "Create new project"
-msgstr "Neues Projekt erstellen"
-
msgid "Create new..."
msgstr "Neu erstellen"
@@ -11455,9 +11600,6 @@ msgstr "Epic wird angelegt"
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,8 +11615,8 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
-msgstr ""
+msgid "CredentialsInventory|Project and Group Access Tokens"
+msgstr "Projekt- und Gruppen-Zugriffstoken"
msgid "CredentialsInventory|SSH Keys"
msgstr ""
@@ -11575,9 +11717,6 @@ msgstr "Aktueller Branch"
msgid "Current Project"
msgstr "Aktuelles Projekt"
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr "Der aktuelle Knoten muss der primäre Knoten sein, sonst sperrst Du dich selbst aus"
@@ -11904,6 +12043,9 @@ msgstr "Fehlerrate ändern"
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr "Mediane Zeit, in der ein Incident in einer Produktionsumgebung im angegebenen Zeitraum offen war."
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr "Keine Vorfälle in diesem Zeitraum"
@@ -11988,6 +12133,9 @@ msgstr "Persönliche"
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr "%{firstProject} und %{secondProject}"
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr "M"
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr "Standard - Nie ausführen"
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr "Löschen"
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr "Release %{release} löschen?"
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr "Ablaufdatum (optional)"
msgid "DeployTokens|Expires"
msgstr "Verfällt"
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr "Entwickler"
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr "Leerzeichenänderungen ausblenden"
+
+msgid "Diffs|Inline"
+msgstr "Inline"
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr "Leerzeichenänderungen anzeigen"
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr "Nebeneinander"
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Etwas ging schief, während die Diff-Zeilen abgerufen wurden."
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Using a static site?"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr "Commit"
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr "Ticket löschen"
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr "Beim Erstellen untergeordneter Epics ist etwas schief gelaufen."
@@ -15323,18 +15534,12 @@ msgstr "Beim Abrufen untergeordneter Epics ist etwas schief gelaufen."
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr "Fehler beim Laden des Merge-Requests. Bitte versuche es erneut."
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr "Menüleiste ausklappen"
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr "Ablaufzeitpunkt"
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr "Fehler beim Hinzufügen eines Ressourcen-Links"
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr "Framework konnte nicht erstellt werden"
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr "Konnte Ticket-Status nicht aktualisieren."
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr "Aktualisierung fehlgeschlagen."
-
msgid "Failed to upgrade."
msgstr "Upgrade fehlgeschlagen."
@@ -16681,6 +16937,9 @@ msgstr "Feb"
msgid "February"
msgstr "Februar"
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr "Nach Meilensteinnamen filtern"
@@ -16996,6 +17252,9 @@ msgstr "Für mehr Informationen, gehe zu "
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr "sekundär"
msgid "Get a free instance review"
msgstr "Erhalte eine kostenlose Instanzprüfung"
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,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 eine Merge-Anfrage."
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr "Gruppe"
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr "Lade Gruppen"
-msgid "GroupsTree|No groups matched your search"
-msgstr "Keine Gruppen entsprachen Ihrer Suche"
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr "Keine Gruppen oder Projekte entsprachen deiner Suche"
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr "Gast"
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr "Informationen über den Systemzustand können von folgenden Endpunkten e
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr "Zugriffstoken ist"
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr "Mitglieder einladen"
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] "Das folgende Mitglied konnte nicht eingeladen werden"
msgstr[1] "Das folgenden %d Mitglieder konnten nicht eingeladen werden"
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr "Verwendet eine Lizenz"
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr "hochgestuft"
+msgid "Issuable|epic"
+msgstr "Epic"
+
+msgid "Issuable|escalation policy"
+msgstr "Eskalationsrichtlinien"
+
+msgid "Issuable|iteration"
+msgstr "Iteration"
+
+msgid "Issuable|milestone"
+msgstr "Meilenstein"
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr "Um deine Suche auszuweiten, ändere oder entferne Filter in der Filterle
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr "Titel"
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr "Herunterladen"
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr "Zuletzt bearbeitet von %{link_start}%{avatar} %{name}%{link_end}"
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr "Verlasse das Projekt"
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr "Protokolle"
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr "MD5"
msgid "MERGED"
msgstr "ZUSAMMENGEFÃœHRT"
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr "Betreuer"
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr "Änderungen im Browser mit der Web-IDE vornehmen und überprüfen"
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr "Mache alle in deinem Team unabhängig von ihrem Standort produktiver. GitLab Geo erstellt schreibgeschützte Mirror deiner GitLab-Instanz, sodass du die Zeit zum Klonen und Abrufen großer Repos reduzieren kannst."
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr "Verwaltetes Konto"
msgid "Manifest"
msgstr "Manifest"
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr "Manifestdateiimport"
@@ -24541,6 +24860,9 @@ msgstr "März"
msgid "March"
msgstr "März"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr "Als erledigt markieren"
@@ -24592,6 +24914,9 @@ msgstr "Durchgestrichenen Text hinzufügen (%{modifierKey}⇧X)"
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr "Durchgestrichenen Text hinzufügen (%{modifier_key}⇧X)"
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr "Zeile einrücken (%{modifierKey}])"
@@ -24604,6 +24929,9 @@ msgstr "Zeile ausrücken (%{modifierKey}[)"
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr "Zeile ausrücken (%{modifier_key}[)"
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr "Unterstützt %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr "Merge-Requests dienen dazu, deine Änderungsvorschläge für ein Projekt einzureichen und sie mit anderen zu diskutieren"
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr "Fälligkeitsdatum des Meilensteins"
msgid "Milestone lists not available with your current license"
msgstr "Meilensteinlisten ist mit deiner momentanen Lizenz nicht verfügbar"
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr "%{percentage}%{percent} abgeschlossen"
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr "Minimaler Zugriff"
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr "Kein Workitem-Link gefunden"
+msgid "No access"
+msgstr "Kein Zugriff"
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr "Kein Jobprotokoll"
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr "Es wurden Nachrichten protokolliert"
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr "Keine anderen Tags mit einem solchen Namen oder einer solchen Beschreibung"
@@ -27138,8 +27478,8 @@ msgstr "Antworten reduzieren"
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
-msgstr "Interne Notizen sind nur für den Autor, Beauftragte und Mitglieder mit der Rolle Reporter oder höher sichtbar"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
+msgstr ""
msgid "Notes|Last reply by %{name}"
msgstr ""
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ 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."
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr "Das Projekt befindet sich jetzt unter %{project_full_name_link_start}%{project_full_name}%{link_end}."
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr "Okt"
msgid "October"
msgstr "Oktober"
-msgid "OfSearchInADropdown|Filter"
-msgstr "Filter"
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] "Ein weiteres Element"
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr "Vorgänge"
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr "Leider hat dein Filter keine Ergebnisse geliefert"
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr "Aktiv"
msgid "PipelineSchedules|All"
msgstr "Alle"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr "Inaktiv"
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr "Neuer Zeitplan"
+
msgid "PipelineSchedules|Next Run"
msgstr "Nächste Durchführung"
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "Gib eine kurze Beschreibung für diese Pipeline ein"
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr "Eigentümer(in) werden"
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr "Ziel"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr "Variablen"
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr "Einstellungen"
@@ -30504,6 +30898,9 @@ msgstr "Bearbeiten von Genehmigungsregeln in Projekten und Zusammenführen von A
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr "Veraltete Bereitstellungsjobs verhindern"
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr "Projektname"
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr "Projekt oder Gruppe"
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr "Projekt-Slug"
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr "Badges"
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr "Schützen"
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr "Mehr lesen"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr "Projekt-Sichtbarkeit verringern"
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr "Sichtbarkeit dieses Projekts verringern?"
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr "Release %{deletedRelease} wurde erfolgreich gelöscht."
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr "Melder"
+
msgid "Reporting"
msgstr "Statusbericht"
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr "Namen fehlgeschlagener Tests kopieren, um sie lokal auszuführen"
msgid "Reports|Copy failed tests"
msgstr "Fehlgeschlagene Tests kopieren"
-msgid "Reports|Execution time"
-msgstr "Ausführungszeit"
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr "Fehlschlag"
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr "Schweregrad"
-msgid "Reports|System output"
-msgstr "Systemausgabe"
-
msgid "Reports|Test summary"
msgstr "Testzusammenfassung"
-msgid "Reports|Test summary failed loading results"
-msgstr "Das Laden der Ergebnisse durch die Testzusammenfassung ist fehlgeschlagen"
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr "Ergebnisse der Testzusammenfassung werden analysiert"
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr "Keine geänderten Testergebnisse"
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr "Ressourcen-Link hinzugefügt"
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,8 +34972,8 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
-msgstr ""
+msgid "Runners|Administrator"
+msgstr "Administrator"
msgid "Runners|All"
msgstr ""
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr "Eigentümer(in)"
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr "Aktuell"
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
-msgstr "Wenn du \"Autorisieren\" auswählen, wird die Inhaberschaft deines GitLab-Kontos \"%{username}\" (%{email}) auf deiner Organisation übertragen."
+msgid "SAML single sign-on"
+msgstr "SAML Single Sign-On"
+
+msgid "SAML single sign-on for %{group_name}"
+msgstr "SAML Single Sign-on für %{group_name}"
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr "Vererbt"
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr "Ungültige oder leere Richtlinie"
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr "Projekte hinzufügen"
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr "Alle Schweregrade"
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr "Wähle ein Vorlagen-Repository aus"
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr "Zeitzone auswählen"
-
msgid "Select all"
msgstr ""
@@ -36669,11 +37169,11 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
-msgstr "Selbstüberwachungsprojekt existiert nicht"
+msgid "Self-monitoring project does not exist"
+msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
msgstr ""
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
-msgstr "Selbstüberwachung"
+msgid "SelfMonitoring|Self-monitoring"
+msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr "Einstellungen"
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,8 +37896,8 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
-msgstr "Melde dich mit Single Sign-On an"
+msgid "Sign in with single sign-on"
+msgstr ""
msgid "Sign in with smart card"
msgstr ""
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr "Beim Abrufen der Umgebungen für diesen Merge-Request ist etwas schiefge
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "Zu Branch/Tag wechseln"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr "Release bearbeiten"
@@ -39456,15 +39950,9 @@ msgstr "Nur ein Projektbetreuer oder -besitzer kann ein geschütztes Tag lösche
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr "Versionshinweise"
-
msgid "TagsPage|Repository has no tags yet."
msgstr "Repository hat noch keine Tags."
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr "Verwende den Befehl git tag, um einen neuen Tag hinzuzufügen:"
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "Schreibe deine Versionshinweise oder ziehen Dateien hier hinein…"
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr "geschützt"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr "Zielbranch"
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "Der Import wird nach %{timeout} beendet. Verwende eine Clone/Push-Kombination für Repositorys, die länger brauchen."
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,15 +41785,18 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
+msgstr ""
+
msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr "Diese Seite ist nicht verfügbar, da du nicht Informationen über mehrere Projekte hinweg lesen darfst."
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
-msgstr ""
-
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
msgstr ""
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr "Diese(r) Benutzer(in) hat keine Identitäten"
@@ -41478,6 +41941,9 @@ msgstr "Dieser Benutzer ist der Autor dieses/dieser/diesem %{noteable}."
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr "Heute"
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr "Nichts steht auf Ihrer To-do-Liste. Gute Arbeit!"
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr "Gesamte Beiträge"
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr "Die Zwei-Faktor-Authentifizierung wurde für %{user_email} erfolgreich deaktiviert!"
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr "Die Zwei-Faktor-Authentifizierung wurde für %{username} erfolgreich deaktiviert!"
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
msgstr "Nutzungsstatistiken"
+msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
+msgstr ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr "Scanner:"
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr "Status:"
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "Wir wollen sicher gehen, dass du es bist. Bitte bestätige, dass du kein Roboter bist."
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr "Du kannst Dateien in diesem Projekt nicht direkt bearbeiten. Verzweige dieses Projekt und reiche eine Zusammenführungsanfrage mit deinen Änderungen ein."
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr "Wofür wirst du diese Gruppe verwenden?"
@@ -45209,8 +45789,8 @@ msgstr "Was möchtest du gerne tun?"
msgid "What's new"
msgstr "Was ist neu?"
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
-msgstr ""
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
+msgstr "Wenn ein Bereitstellungsauftrag erfolgreich ist, werden ältere Verteilungsaufträge, die noch ausstehen, verhindert."
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr "Wenn ein Runner gesperrt ist, kann er keinem anderen Projekt zugewiesen werden"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr "Aufgabe hinzufügen"
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr "Aufgaben vorstellen"
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr "Beim Löschen der Aufgabe ist etwas schief gelaufen. Bitteerneut versuchen"
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr "Beim Versuch, ein child hinzuzufügen, ist ein Fehler aufgetreten. Bitte
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr "Du versuchst eine Datei zu löschen, die zuvor aktualisiert wurde."
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr "Du bist bei GitLab angemeldet als:"
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr "Du kannst bis zu 280 Zeichen eingeben"
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr "Du kannst deine .gitlab-ci.yml mit %{linkStart}CI Lint%{linkEnd} testen.
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr "YouTube"
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr "Dein %{host}-Konto wurde von einem neuen Standort aus angemeldet"
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr "Dein Name"
-msgid "Your new %{accessTokenType}"
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{accessTokenType} has been created."
-msgstr ""
-
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr "Deine Aktualisierung ist fehlgeschlagen. Du musst eine Datei mit demselb
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr "Das Feature-Flag `work_items_hierarchy` ist für dieses Projekt deaktiviert"
-
msgid "a deleted user"
msgstr "ein(e) gelöschte(r) Benutzer(in)"
@@ -46825,9 +47450,6 @@ msgstr[1] "etwa %d Stunden"
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr "Die Abhängigkeitsüberprüfung entdeckt bekannte Sicherheitslücken in
msgid "ciReport|Dependency scanning"
msgstr "Abhängigkeitsüberprüfung"
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr "Dynamic Application Security Testing (DAST) entdeckt Schwachstellen in deiner Webanwendung."
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr "Neue Sicherheitslücken sind Sicherheitslücken, die der Sicherheits-Scan im Merge-Request entdeckt, die sich von den vorhandenen Sicherheitslücken im Standard-Branch unterscheiden."
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr "Ergebnisse des Sicherheitsscans"
+
msgid "ciReport|Security scanning"
msgstr "Sicherheitsüberprüfung"
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr "Lösung"
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr "Static Application Security Testing (SAST) entdeckt bekannte Sicherheitslücken in deinem Quellcode."
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] "Tage"
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr "ungültiger Meilensteinstatus `%{state}`"
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr "ist"
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr "ist ein ungültiger IP-Adressbereich"
@@ -47753,6 +48423,9 @@ msgstr "ist nicht"
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr "ist keine gültige URL."
+
msgid "is not a valid X509 certificate."
msgstr "ist kein gültiges X509-Zertifikat."
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr "ist nicht einer von"
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr "ist einer von"
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr "Diesen Merge-Request in einem neuen Merge-Request rückgängig machen"
msgid "mrWidget|Revoke approval"
msgstr "Zustimmung wiederrufen"
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr "muss nach dem Anfangsdatum liegen"
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr "erfordern Beachtung"
-
msgid "needs to be between 10 minutes and 1 month"
msgstr "muss zwischen 10 Minuten und 1 Monat liegen"
@@ -48336,9 +49018,6 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}, und %{lastItem}"
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr "nur %{parent_types} kann der Aufgabe übergeordnet sein."
@@ -48357,17 +49036,15 @@ msgstr "oder"
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] "von insgesamt %d Test"
-msgstr[1] "von insgesamt %d Tests"
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "Ãœbergeordneter"
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr "Gewichtung entfernen"
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr "Die Antwort sollte die gleiche Vertraulichkeit haben wie die Notiz der o
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr "dieses Dokument"
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr "yaml ungültig"
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/el_GR/gitlab.po b/locale/el_GR/gitlab.po
index 8c7c7be8114..518de409ad9 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: 2022-10-10 14:02\n"
+"PO-Revision-Date: 2022-11-13 09:22\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/en_GB/gitlab.po b/locale/en_GB/gitlab.po
index b55d8cfb28a..a5f557c22ce 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: 2022-10-10 14:04\n"
+"PO-Revision-Date: 2022-11-13 09:24\n"
msgid " %{start} to %{end}"
msgstr " %{start} to %{end}"
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d approver"
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] "%d epic"
msgstr[1] "%d epics"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d error"
-msgstr[1] "%d errors"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d exporter"
msgstr[1] "%d exporters"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%d failed"
-msgstr[1] "%d failed"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] "%d failed security job"
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] "%d file"
msgstr[1] "%d files"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d fixed test result"
-msgstr[1] "%d fixed test results"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] "%d fork"
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] "%{bold_start}%{count}%{bold_end} opened merge request"
msgstr[1] "%{bold_start}%{count}%{bold_end} opened merge requests"
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
@@ -567,6 +560,16 @@ msgstr[1] "%{count} contacts"
msgid "%{count} files touched"
msgstr "%{count} files touched"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "%{count} item"
@@ -575,6 +578,11 @@ msgstr[1] "%{count} items"
msgid "%{count} items per page"
msgstr "%{count} items per page"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr "%{count} more"
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} participant"
msgstr[1] "%{count} participants"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} related %{pluralized_subject}: %{links}"
@@ -636,9 +649,6 @@ msgstr "%{docs_link_start}What is Large File Storage?%{docs_link_end}"
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
-msgid "%{due_date} (Past due)"
-msgstr "%{due_date} (Past due)"
-
msgid "%{duration}ms"
msgstr "%{duration}ms"
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr "Reset link will be generated and sent to the user. User will be forced t
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr "Administrators"
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr "Application settings saved successfully."
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr "Assign custom colour like #FF0000"
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr "Assign myself"
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr "Create new..."
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr "Change failure rate"
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr "Median time (last %{days}d)"
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr "Median time an incident was open in a production environment over the given time period."
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr "No incidents during this period"
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Copy snippet"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr ""
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr ""
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr "GitLab Error Tracking"
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] "The following member couldn't be invited"
msgstr[1] "The following %d members couldn't be invited"
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr "No Work Item Link found"
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr "Expand replies"
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr "Pipeline %{pipeline_link} triggered by"
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr "Duplicate packages"
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr "Release date"
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr "Copy failed test names to run locally"
msgid "Reports|Copy failed tests"
msgstr "Copy failed tests"
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr "Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,17 +35503,23 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
-msgstr "Selecting \"Authorise\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organisation."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
+msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr "Sign in to GitLab to connect your organisation's account"
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
-msgstr "The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
-msgstr "To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
+msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "Your organisation's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr "Inherited"
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,8 +36557,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, and Container scanning."
-msgstr "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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
msgstr ""
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr "Set the Ready status"
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr "Titanium yellow"
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,8 +45393,8 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
-msgstr "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
+msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
msgstr ""
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr "Are you sure you want to cancel editing?"
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr "Something went wrong when deleting the task. Please try again."
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr "Something went wrong when trying to add a child. Please try again."
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr "You have insufficient permissions to manage resource links for this incident"
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr "Your update failed. You must upload a file with the same file name when
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr "`work_items_hierarchy` feature flag disabled for this project"
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr "artefacts"
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr "at least the Reporter role"
msgid "at least the Reporter role, the author, and assignees"
msgstr "at least the Reporter role, the author, and assignees"
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr "%{linkStart}Set up now%{linkEnd} to analyse your source code for known security vulnerabilities."
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr "only %{parent_types} can be parent of Task."
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr "organisations can only be added to root groups"
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr "your GitLab instance"
diff --git a/locale/eo/gitlab.po b/locale/eo/gitlab.po
index e233156e745..fc511ade48a 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: 2022-10-10 14:05\n"
+"PO-Revision-Date: 2022-11-13 09:25\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr "Aktiva"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "Foliumi dosierujon"
@@ -7039,9 +7178,6 @@ msgstr "Foliumi dosieron"
msgid "Browse Files"
msgstr "Foliumi dosierojn"
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr "Elekti dosierojn"
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr "Forigi"
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Using a static site?"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr "Forlasi la projekton"
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr "Filtrilo"
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr "Åœaltitaj"
msgid "PipelineSchedules|All"
msgstr "Ĉiuj"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr "MalÅaltitaj"
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr "Sekvanta plenumo"
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "Entajpu mallongan priskribon pri ĉi tiu ĉenstablo"
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr "Akiri posedon"
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr "Celo"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr "Variabloj"
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr "Legu pli"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr "Elektu horzonon"
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "Iri al branĉo/etikedo"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr "Cela branĉo"
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr "Via nomo"
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] "tagoj"
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "patro"
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/es/gitlab.po b/locale/es/gitlab.po
index 6ba80989cc7..ba03c5c0c09 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: 2022-10-10 14:02\n"
+"PO-Revision-Date: 2022-11-13 09:22\n"
msgid " %{start} to %{end}"
msgstr " %{start} hasta %{end}"
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d aprobador"
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] "%d épica"
msgstr[1] "%d épicas"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d error"
-msgstr[1] "%d errores"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d exportador"
msgstr[1] "%d exportadores"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%d fallido"
-msgstr[1] "%d fallidos"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] "%d trabajo de seguridad fallido"
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] "%d archivo"
msgstr[1] "%d archivos"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d resultado de la prueba solucionado"
-msgstr[1] "%d resultados de las pruebas solucionados"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr "%{code_open}Enmascarado:%{code_close} Oculto en los registros de los trabajos. Debe coincidir con los requisitos de enmascaramiento."
@@ -567,6 +560,16 @@ msgstr[1] "%{count} contactos"
msgid "%{count} files touched"
msgstr "%{count} archivos modificados"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "%{count} elemento"
@@ -575,6 +578,11 @@ msgstr[1] "%{count} elementos"
msgid "%{count} items per page"
msgstr "%{count} elementos por página"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr "%{count} más"
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} participante"
msgstr[1] "%{count} participantes"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} %{pluralized_subject} relacionados: %{links}"
@@ -636,9 +649,6 @@ msgstr "%{docs_link_start}¿Qué es el almacenamiento para grandes ficheros?%{do
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr "%{docs_link_start}¿Qué es la autenticación de dos factores?%{docs_link_end}"
-msgid "%{due_date} (Past due)"
-msgstr "%{due_date} (vencido)"
-
msgid "%{duration}ms"
msgstr "%{duration}ms"
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr "%{name} (Ocupado)"
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} contenido en %{resultsString}"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} encontrado %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr "%{name} ya está siendo utilizado para otro emoji"
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "%{strong_start}%{branch_count}%{strong_end} Branch"
@@ -1182,9 +1189,6 @@ msgstr "%{user} creó una incidencia: %{issue_link}"
msgid "%{value} is not included in the list"
msgstr "%{value} no está incluido en la lista"
-msgid "%{value} s"
-msgstr "%{value} s"
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} %{time_spent_value} tiempo gastado."
@@ -1242,6 +1246,9 @@ msgstr "'%{source}' no es una fuente valida para importar"
msgid "'%{template_name}' is unknown or invalid"
msgstr "'%{template_name}' es desconocido o no es válido"
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d cerrado)"
@@ -1280,6 +1287,9 @@ msgstr "(Déjelo en blanco si no quiere cambiarlo)"
msgid "(max size 15 MB)"
msgstr "(tamaño máximo 15 MB)"
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr "(opcional)"
@@ -1565,6 +1575,9 @@ msgstr "No tiene permisos para acceder a esta página."
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "Asegúrese de que la dirección sea correcta y que la página no se haya movido."
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr "Página no encontrada"
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "No se puede elegir una rama por defecto para un proyecto vacío."
-
msgid "A deleted user"
msgstr "Un usuario eliminado"
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr "Un sitio HTML simple que utiliza Netlify para CI/CD en lugar de GitLab, pero que mantiene todas las otras excelentes características de GitLab"
-msgid "A platform value can be web, mob or app."
-msgstr "Un valor de plataforma puede ser web, mob o aplicación."
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr "Una plantilla de proyecto para el desarrollo de aplicaciones de Salesforce con las herramientas de desarrollo de Salesforce"
@@ -1919,6 +1926,9 @@ msgstr "Aceptar los términos"
msgid "Acceptable for use in this project"
msgstr "Aceptable para su utilización en este proyecto"
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr "Acceder a los repositorios Git o a la API."
@@ -2030,15 +2040,9 @@ msgstr "Su token de correo electrónico entrante lo autentica cuando crea una nu
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr "Obtener más información"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "Mensaje: %{message}"
-msgid "AccessibilityReport|New"
-msgstr "Nuevo"
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr "Activo"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr "Activo %{type} (%{token_length})"
-
msgid "Active Sessions"
msgstr "Sesiones activas"
@@ -2483,6 +2484,12 @@ msgstr "Agrega %{labels} %{label_text}."
msgid "Adds a Zoom meeting."
msgstr "Añadir una reunión de Zoom."
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr "Se ha producido un error al cargar las estadísticas. Por favor, inténtalo de nuevo"
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr "Dominio Auto DevOps"
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr "Configurar Let's Encrypt"
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr "Eliminar proyectos inactivos"
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr "Habilitar ejecutores compartidos para los nuevos proyectos"
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr "Mantener los últimos artefactos para todos los trabajos en los últimos pipelines ejecutados correctamente"
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr "Administrador"
msgid "AdminUsers|Admins"
msgstr "Administradores"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr "Aprobar"
@@ -3263,8 +3336,8 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr "Restaure el acceso del usuario a la cuenta, esto incluye la web, Git y API."
-msgid "AdminUsers|Search by name, email or username"
-msgstr "Búsqueda por nombre, correo electrónico o nombre de usuario"
+msgid "AdminUsers|Search by name, email, or username"
+msgstr ""
msgid "AdminUsers|Search users"
msgstr "Buscar usuarios"
@@ -3308,8 +3381,8 @@ msgstr "El usuario no recibirá ninguna notificación"
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "Para confirmar, escriba %{projectName}"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "Para confirmar, escriba %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr ""
msgid "AdminUsers|Unban user"
msgstr "Desbloquear usuario"
@@ -3371,7 +3444,7 @@ msgstr "Sin proyectos"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr "‫Administración"
msgid "Administrators"
msgstr "Administradores"
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,8 +4005,8 @@ msgstr "Todos los usuarios deben tener un nombre."
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
-msgstr "Permitir al grupo %{group_name} iniciar sesión"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr ""
msgid "Allow access to members of the following group"
msgstr "Permitir el acceso a los miembros del siguiente grupo"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr "Permitir a los propietarios de los grupos administrar configuraciones relacionadas con LDAP"
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr "Permitir a esta clave hacer push a este repositorio"
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr "Se ha producido un error al recuperar los tags. Por favor, vuelva a inte
msgid "An error occurred while fetching terraform reports."
msgstr "Se ha producido un error al obtener los informes de terraform."
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr "Se ha producido un error al obtener el log del trabajo."
@@ -4414,9 +4493,6 @@ msgstr "Se ha producido un error al ejecutar el trabajo."
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr "Se ha producido un error desconocido."
msgid "Analytics"
msgstr "Analíticas"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "Analizar sus dependencias en busca de vulnerabilidades conocidas."
@@ -4621,9 +4694,6 @@ msgstr "La configuración de la aplicación se guardó correctamente."
msgid "Application settings update failed"
msgstr "Se ha producido un error al actualizar los ajustes de la aplicación"
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr "La aplicación se ha desinstalado correctamente pero no se ha podido destruir: %{error_message}"
-
msgid "Application was successfully destroyed."
msgstr "Se ha destruido correctamente la aplicación."
@@ -4642,7 +4712,7 @@ msgstr "Añadir un enlace a Grafana"
msgid "ApplicationSettings|After sign-up text"
msgstr "Texto posterior al registro"
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr "Restricciones de correo electrónico"
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr "Guardar cambios"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ 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 these artifacts?"
-msgstr "¿Está seguro de que desea eliminar estos artefactos?"
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr "¿Está seguro que quiere eliminar este %{commentType}?"
@@ -5177,8 +5259,8 @@ msgstr "¿Está seguro de que desea volver a intentar esta migración?"
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
-msgstr "¿Está seguro de que desea revocar este token %{type}? Esta acción no se puede deshacer."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr "¿Está seguro de que desea revocar el token de acceso token personal?. Esta acción no se puede deshacer."
@@ -5228,6 +5310,30 @@ msgstr "El artefacto se ha eliminado correctamente."
msgid "Artifacts"
msgstr "Artefactos"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr "A medida que continuamos construyendo más características para SAST, nos gustaría conocer su opinión sobre la función de configuración SAST en %{linkStart}esta incidencia%{linkEnd}."
@@ -5279,9 +5385,6 @@ msgstr "Asigne colores personalizados como #FF0000"
msgid "Assign labels"
msgstr "Asignar etiquetas"
-msgid "Assign milestone"
-msgstr "Asignar milestone"
-
msgid "Assign myself"
msgstr "Asignar a mi mismo"
@@ -5675,9 +5778,6 @@ msgstr "Parada automática cancelada con éxito."
msgid "Auto-cancel redundant pipelines"
msgstr "Cancelar automáticamente los pipelines redundantes"
-msgid "Auto-close referenced issues on default branch"
-msgstr "Cerrar automáticamente las incidencias referenciadas en el branch por defecto"
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ 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 enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr "La rama ya existe"
msgid "Branch name"
msgstr "Nombre de la rama"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr "Branch no cargada - %{branchId}"
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr "El mensaje de difusión se actualizó correctamente."
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "Examinar directorio"
@@ -7039,9 +7178,6 @@ msgstr "Examinar archivo"
msgid "Browse Files"
msgstr "Examinar archivos"
-msgid "Browse artifacts"
-msgstr "Examinar artefactos"
-
msgid "Browse files"
msgstr "Examinar archivos"
@@ -7087,9 +7223,6 @@ msgstr "Filtrar por grupo de origen"
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr "Del grupo de origen"
-
msgid "BulkImport|Group import history"
msgstr "Historial de importación de grupos"
@@ -7120,6 +7253,9 @@ msgstr "El nombre ya existe."
msgid "BulkImport|Name already used as a target for another group."
msgstr "El nombre ya está en uso como destino para otro grupo."
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr "No se proporcionó información adicional."
@@ -7135,6 +7271,9 @@ msgstr "No hay ningún padre"
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr "Historial de importación de proyectos"
@@ -7159,9 +7298,6 @@ msgstr "Grupo de origen"
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr "Para un nuevo grupo"
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr "Cancelando la vista previa"
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr "No se puede hacer merge automáticamente"
@@ -7593,6 +7726,9 @@ msgstr "No se puede crear el informe de abuso. Este usuario ha sido bloqueado."
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr "No se puede eliminar %{profile_name} referenciado en la política de seguridad"
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr "Clave"
msgid "CiVariables|Masked"
msgstr "Máscara"
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr "Protegido"
@@ -9647,10 +9786,16 @@ msgstr "Comentar en las líneas %{startLine} a %{endLine}"
msgid "Comment/Reply (quoting selected text)"
msgstr "Comentar/Responder (citando el texto seleccionado)"
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr "Completado"
@@ -10627,10 +10775,10 @@ msgstr "Colaboración"
msgid "Contribution Analytics"
msgstr "Análisis de colaboración"
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr "Contribuciones para %{calendar_date}"
@@ -10711,9 +10868,6 @@ msgstr "Copiar %{name}"
msgid "Copy %{protocol} clone URL"
msgstr "Copiar la URL de clonado del protocolo %{protocol}"
-msgid "Copy %{type}"
-msgstr "Copiar %{type}"
-
msgid "Copy ID"
msgstr "Copiar el ID"
@@ -10798,9 +10952,6 @@ msgstr "Copiar el secreto"
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr "Copiar este token de registro."
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr "No es posible eliminar el disparador."
@@ -11185,9 +11333,6 @@ msgstr "Crear un nuevo archivo o directorio"
msgid "Create new label"
msgstr "Crear nueva etiqueta"
-msgid "Create new project"
-msgstr "Crear nuevo proyecto"
-
msgid "Create new..."
msgstr "Crear nuevo..."
@@ -11455,9 +11600,6 @@ msgstr "Creando épica"
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr "La creación de los gráficos utiliza los datos del servidor Prometheus. Si esta proceso tarda mucho tiempo, asegúrese de que los datos estén disponibles."
-msgid "Creation date"
-msgstr "Fecha de creación"
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr "No se encontraron credenciales"
msgid "CredentialsInventory|Personal Access Tokens"
msgstr "Tokens de acceso personal"
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr "Rama actual"
msgid "Current Project"
msgstr "Proyecto actual"
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr "Cambiar tasa de fallo"
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr "Fecha"
@@ -11931,6 +12073,9 @@ msgstr "Tiempo medio (últimos %{days} días)"
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr "La mediana de tiempo en el que se abrió un incidente en un entorno de producción a lo largo de un período determinado."
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr "Sin incidencias durante este periodo"
@@ -11988,6 +12133,9 @@ msgstr "Personal"
msgid "DashboardProjects|Trending"
msgstr "Tendencia"
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr "Dashboard|%{firstProject} y %{secondProject}"
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr "Tipo de datos"
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr "Se ha producido un error al actualizar la base de datos"
@@ -12527,6 +12681,9 @@ msgstr "Mi"
msgid "Days"
msgstr "Días"
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr "Días para hacer merge"
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr "Reducir"
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr "Archivo de configuración por defecto de CI/CD"
@@ -12671,6 +12831,9 @@ msgstr "Eliminar"
msgid "Delete %{issuableType}"
msgstr "Eliminar %{issuableType}"
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr "Eliminar %{name}"
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr "Eliminar cuenta"
-msgid "Delete artifacts"
-msgstr "Eliminar artefactos"
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr "¿Eliminar la versión %{release}?"
msgid "Delete row"
msgstr "Eliminar fila"
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr "Expira"
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr "Adopción DevOps"
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Se ha producido un error mientras se obtienen las líneas del diff."
@@ -14528,6 +14721,12 @@ msgstr "Editado"
msgid "Edited %{timeago}"
msgstr "Editado %{timeago}"
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr "Editando"
@@ -14858,23 +15057,41 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Copy snippet"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|Close"
-msgstr "Cerrar"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr ""
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
-msgstr "Copia el fragmento de texto"
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
+msgstr ""
msgid "Enabled"
msgstr "Habilitado"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr "Commit"
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr "Eliminar"
@@ -15281,12 +15501,12 @@ msgstr "Añadir una nueva tarea épica"
msgid "Epics|Add an existing epic"
msgstr ""
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgstr ""
+
msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr "¿Está seguro de que desea eliminar %{bStart}%{targetIssueTitle}%{bEnd} de %{bStart}%{parentEpicTitle}%{bEnd}?"
-msgid "Epics|Assign Epic"
-msgstr ""
-
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr ""
@@ -15299,18 +15519,9 @@ msgstr "Eliminar tarea épica"
msgid "Epics|Remove issue"
msgstr "Eliminar la incidencia"
-msgid "Epics|Search epics"
-msgstr "Buscar tareas épicas"
-
-msgid "Epics|Select epic"
-msgstr "Seleccionar épica"
-
msgid "Epics|Show more"
msgstr "Mostrar más"
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr "Se ha producido un error al asignar la incidencia a la tarea épica."
-
msgid "Epics|Something went wrong while creating child epics."
msgstr "Se ha producido un error al crear las tareas épicas hijas."
@@ -15323,18 +15534,12 @@ msgstr "Se ha producido un error al obtener las tareas épicas hijas."
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr "Se ha producido un error al obtener los grupos de tareas épicas."
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr "Se ha producido un error al ordenar el elemento."
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr "Se ha producido un error al eliminar la incidencia de la tarea épica."
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr "Se ha producido un error mientras se guardaban los asignados"
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr "Se ha producido un error al enviar el fichero"
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr "Se ha producido un error al subir el archivo: %{stripped}"
-
msgid "Error while loading the merge request. Please try again."
msgstr "Se ha producido un error al procesar su merge request. Por favor, inténtelo de nuevo."
@@ -15773,6 +15972,57 @@ msgstr "Eventos"
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr "Cada intento de %{action} ha fallado: %{job_error_message}. Por favor, inténtalo de nuevo."
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr "Tiempo de ejecución"
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr "Expandir barra lateral"
msgid "Expected documents: %{expected_documents}"
msgstr "Documentos esperados: %{expected_documents}"
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr "Vencimiento"
@@ -16176,6 +16435,9 @@ msgstr "Error en"
msgid "Failed to add a Zoom meeting"
msgstr "Se ha producido un error al añadir una reunión de Zoom"
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr "Se ha producido un error al aplicar los comandos."
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr "Se ha producido un error al crear el repositorio"
@@ -16421,9 +16680,6 @@ msgstr "Se ha producido un error al actualizar el estado de la incidencia"
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr "Se ha producido un error al actualizar."
-
msgid "Failed to upgrade."
msgstr "Se ha producido un error al actualizar."
@@ -16681,6 +16937,9 @@ msgstr "Feb"
msgid "February"
msgstr "Febrero"
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr "Filtrar por nombre del hito"
@@ -16996,6 +17252,9 @@ msgstr "Para obtener más información, vaya a "
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr "¿Olvidó su contraseña?"
@@ -17829,9 +18088,6 @@ msgstr "secundario"
msgid "Get a free instance review"
msgstr "Obtenga una revisión de instancia gratuita"
-msgid "Get a free trial"
-msgstr "Obtenga una prueba gratuita"
-
msgid "Get a support subscription"
msgstr "Obtenga una suscripción de soporte"
@@ -17958,6 +18214,12 @@ msgstr "Solicitud de cuenta de GitLab"
msgid "GitLab Billing Team."
msgstr "Equipo de facturación de GitLab."
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr "Seguimiento de errores de GitLab"
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr "GitLab.com"
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr "Mostrar dependencias"
msgid "GraphViewType|Stage"
msgstr "Etapa"
-msgid "Graphs"
-msgstr "Gráficos"
-
msgid "Gravatar"
msgstr "Gravatar"
@@ -18627,6 +18886,9 @@ msgstr "Gravatar habilitado"
msgid "Group"
msgstr "Grupo"
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr "No se puede exportar el grupo %{group_name} ."
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr "Cargando grupos"
-msgid "GroupsTree|No groups matched your search"
-msgstr "Lo sentimos, no existen grupos que coincidan con su búsqueda"
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr "Lo sentimos, no existen grupos ni proyectos que coincidan con su búsqueda"
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr "Slug del subgrupo"
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr "Guía"
@@ -19642,9 +19901,6 @@ msgstr "La información de la verificación del estado del sistema se puede obte
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr "El token de acceso es"
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr "Si esto fue un error puede %{leave_link_start}dejar el %{source_type}%{link_end}."
@@ -21943,6 +22199,9 @@ msgstr "Código de dos factores no válido."
msgid "Invalid yaml"
msgstr "Yaml no válido"
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr "Investigar vulnerabilidad: %{title}"
@@ -21961,9 +22220,6 @@ msgstr "Invitación rechazada"
msgid "Invite \"%{email}\" by email"
msgstr "Invitar a \"%{email}\" por correo electrónico"
-msgid "Invite \"%{trimmed}\" by email"
-msgstr "Invitar a \"%{trimmed}\" por correo electrónico"
-
msgid "Invite Members"
msgstr "Invitar miembros"
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] "No se pudo invitar al siguiente miembro"
msgstr[1] "Los siguientes %d miembros no pudieron ser invitados"
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr "Está usando el asiento de licencia:"
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr "movida"
msgid "IssuableStatus|promoted"
msgstr "promocionado"
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr "Incidencia"
@@ -22503,6 +22774,21 @@ msgstr "Para ampliar su búsqueda, cambie o elimine los filtros en la barra de f
msgid "IssuesAnalytics|Total:"
msgstr "Total:"
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr "Título"
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr "Descargar"
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr "Abandonar proyecto"
msgid "Leave zen mode"
msgstr "Abandonar el modo zen"
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr "Cambios de línea"
msgid "Link"
msgstr "Enlace"
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr "Logs"
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr "Hay vulnerabilidades bajas presentes"
@@ -24385,6 +24689,9 @@ msgstr "MD5"
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,8 +24728,14 @@ msgstr "Mostrar sólo los cambios"
msgid "MRDiff|Show full file"
msgstr "Mostrar el archivo completo"
-msgid "Made this issue confidential."
-msgstr "Convierte este problema en confidencial."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
+msgstr ""
msgid "Mailgun"
msgstr ""
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr "Modo mantenimiento"
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr "Realice y revise los cambios en el navegador con el Web IDE"
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr "Haga que todos en su equipo sean más productivos, independientemente de su ubicación. GitLab Geo crea réplicas de solo lectura de su instancia de GitLab para que pueda reducir el tiempo que lleva clonar y obtener grandes repositorios."
-msgid "Make issue confidential"
-msgstr "Convertir este problema en confidencial"
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,8 +24776,8 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr "Asegúrese de guardarlo, no podrá volver a acceder a él."
-msgid "Makes this issue confidential."
-msgstr "Convierte la incidencia en confidencial."
+msgid "Makes this %{type} confidential."
+msgstr ""
msgid "Manage %{workspace} labels"
msgstr ""
@@ -24517,6 +24833,9 @@ msgstr "Cuenta gestionada"
msgid "Manifest"
msgstr "Manifiesto"
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr "Importar fichero de manifiesto"
@@ -24541,6 +24860,9 @@ msgstr "Marzo"
msgid "March"
msgstr "Marzo"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr "Marcar como completado"
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr "Los merge request son un lugar para proponer los cambios que ha realizado en un proyecto y discutir esos cambios con otros miembros"
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr "Método"
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr "La métrica se añadió correctamente."
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr "Las listas de hitos no están disponibles con tu licencia actual"
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr "Capacidad mínima que debe estar disponible antes de que programemos más mirrors de forma preventiva."
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr "Añadir proyectos"
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr "Sin alcances"
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr "No se ha encontrado ningún usuario administrador activo"
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr "No hay registro de tareas"
-msgid "No jobs to show"
-msgstr "No hay trabajos para mostrar"
-
msgid "No label"
msgstr "Sin etiqueta"
@@ -26884,9 +27230,6 @@ msgstr "No se han encontrado resultados"
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr "No se han encontrado miembros"
@@ -26902,9 +27245,6 @@ msgstr "No se registraron mensajes"
msgid "No milestone"
msgstr "Sin hito"
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr "No hay otras etiquetas con ese nombre o descripción"
@@ -27138,7 +27478,7 @@ msgstr "Contraer respuestas"
msgid "Notes|Expand replies"
msgstr "Notes|Expandir respuestas"
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr "Pipeline %{pipeline_link} activado por"
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr "Número de archivos tocados"
@@ -27623,9 +27969,6 @@ msgstr "Oct"
msgid "October"
msgstr "Octubre"
-msgid "OfSearchInADropdown|Filter"
-msgstr "Filtrar"
-
msgid "Off"
msgstr "Apagado"
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr "Escaneos bajo demanda"
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr "Tipo de análisis"
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr "Seleccione uno de los perfiles existentes"
-
-msgid "OnDemandScans|Site profile"
-msgstr "Perfil del sitio"
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr "No hay ningún análisis programado."
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr "Ver resultados"
@@ -28048,9 +28358,6 @@ msgstr "Una vez importados, los repositorios se pueden replicar vía de SSH. Par
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] "Un elemento más"
@@ -28224,9 +28531,6 @@ msgstr "La operación ha fallado. Por favor, compruebe los registros del pod par
msgid "Operation not allowed"
msgstr "Operación no permitida"
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr "Se ha agotado el tiempo de la operación. Por favor, compruebe los registros del pod para %{pod_name} para obtener más información."
-
msgid "Operations"
msgstr "Operaciones"
@@ -28595,12 +28899,21 @@ msgstr "Eliminar paquete"
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr "Eliminar este paquete"
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr "PackageRegistry|Paquetes duplicados"
@@ -28646,6 +28959,12 @@ msgstr "Comando de instalación de Gradle Kotlin DSL"
msgid "PackageRegistry|Helm"
msgstr "Helm"
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr "Si todavía no lo ha hecho, necesitará añadir lo siguiente a su archivo %{codeStart}.pypirc%{codeEnd}."
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr "Período en segundos"
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr "Enlace permanente"
@@ -29229,8 +29545,8 @@ msgstr "Importar servidor Phabricator"
msgid "Phabricator Server URL"
msgstr "URL del servidor de Phabricator"
-msgid "Phabricator Tasks"
-msgstr "Tareas de Phabricator"
+msgid "Phabricator tasks"
+msgstr ""
msgid "Phone"
msgstr ""
@@ -29448,6 +29764,9 @@ msgstr "Activos"
msgid "PipelineSchedules|All"
msgstr "Todos"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr "Inactivos"
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr "Próxima Ejecución"
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "Proporcione una descripción breve para este pipeline"
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr "Tomar posesión"
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr "Destino"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr "Variables"
@@ -30252,9 +30586,6 @@ msgstr "Por favor, seleccione un proyecto Jira"
msgid "Please select a country"
msgstr "Por favor, seleccione un país"
-msgid "Please select a file"
-msgstr "Por favor, seleccione un archivo"
-
msgid "Please select a group"
msgstr "Por favor, seleccione un grupo"
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr "Preferencias"
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr "Continuar"
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr "Productividad"
@@ -31179,6 +31582,9 @@ msgstr "Nombre del proyecto"
msgid "Project navigation"
msgstr "Navegación del proyecto"
+msgid "Project or Group"
+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."
@@ -31191,6 +31597,9 @@ msgstr "Estado de la seguridad del proyecto"
msgid "Project security status help page"
msgstr "Página de ayuda sobre el estado de la seguridad del proyecto"
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr "Slug del proyecto"
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr "Insignias"
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr "Interno"
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr "Aprobación del propietario del código"
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr "Proteger"
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr "Requerir aprobación de los propietarios del código:"
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr "Actualmente no hay ramas protegidas, proteja una rama con el formulario anterior."
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr "Leer más"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr "Lea más acerca de las incidencias relacionadas"
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr "Reduce la visibilidad del proyecto"
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr "¿Reducir la visibilidad de este proyecto?"
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] "Versiones"
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr "La versión %{deletedRelease} se ha eliminado correctamente."
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr "Fecha de lanzamiento"
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr "Reportado por %{reporter}"
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr "Informes"
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr "Nombre de la clase"
-
msgid "Reports|Copy failed test names to run locally"
msgstr "Copiar los nombres de los pruebas fallidas para ejecutarlos localmente"
msgid "Reports|Copy failed tests"
msgstr "Copiar las pruebas fallidas"
-msgid "Reports|Execution time"
-msgstr "Tiempo de ejecución"
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr "Fallo"
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr "Severidad"
-msgid "Reports|System output"
-msgstr "Salida del sistema"
-
msgid "Reports|Test summary"
msgstr "Resumen de la prueba"
-msgid "Reports|Test summary failed loading results"
-msgstr "Se ha producido un error al cargar los resultados de la prueba"
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr "Se están analizando los resultados de la prueba"
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr "no hay cambios en los resultados de las pruebas"
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr "Resuelto por"
msgid "Resolved by %{name}"
msgstr "Resuelto por %{name}"
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr "Respuesta"
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr "Ejecutar tareas de mantenimiento"
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr "Los ejecutores son los agentes de GitLab que ejecutan sus trabajos de CI/CD. Siga las %{linkStart}instrucciones de instalación y registro%{linkEnd} para configurar un ejecutor."
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr "Hasta la fecha"
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,17 +35503,23 @@ msgstr "Tokens de descubrimiento SAML"
msgid "SAML for %{group_name}"
msgstr "SAML para %{group_name}"
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
-msgstr "Al seleccionar \"Autorizar\" se transferirá la propiedad de su cuenta de GitLab \"%{username}(%{email}) a su organización."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
+msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr "Inicie sesión en GitLab para conectar la cuenta de su organización"
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
-msgstr "El grupo \"%{group_path}\" le permite iniciar sesión con su cuenta de inicio de sesión único."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
-msgstr "Debe iniciar sesión con su cuenta Single Sign-On, a través de una página de inicio de sesión externa para acceder a \"%{group_name}\" ."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
+msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
@@ -35168,10 +35626,10 @@ msgstr "Guardando"
msgid "Saving project."
msgstr "Guardar proyecto."
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr "Buscar un grupo de LDAP"
msgid "Search for a group"
msgstr "Buscar un grupo"
-msgid "Search for a user"
-msgstr "Buscar un usuario"
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr "Heredado"
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr "un"
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr "un"
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr "Añadir proyectos"
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr "Proyectos monitorizados"
msgid "SecurityReports|More info"
msgstr "Más información"
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr "Ver métricas"
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr "Ver los proyectos afectados en el panel de administración de GitLab"
@@ -36528,9 +37031,6 @@ msgstr "Seleccione una plantilla de repositorio"
msgid "Select a template type"
msgstr "Seleccione un tipo de plantilla"
-msgid "Select a timezone"
-msgstr "Selecciona una zona horaria"
-
msgid "Select all"
msgstr "Seleccionar todo"
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
-msgstr "¿Desactivar auto monitorización?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
+msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
-msgstr " Auto monitorización"
+msgid "SelfMonitoring|Self-monitoring"
+msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
-msgstr "Proyecto de auto monitorización creado con correctamente."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
+msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr "Establecer el estado a Preparado"
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr "Configuración"
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr "Configuración"
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr "Mostrar todas las tareas épicas"
msgid "Showing all issues"
msgstr "Mostrar todas las incidencias"
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,8 +37881,8 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
-msgstr "Iniciar sesión en %{group_name}\""
+msgid "Sign in to %{group_name}"
+msgstr ""
msgid "Sign in to GitLab"
msgstr "Iniciar sesión en GitLab"
@@ -37405,8 +37896,8 @@ msgstr "Inicie sesión mediante un código 2FA"
msgid "Sign in with"
msgstr "Iniciar sesión con"
-msgid "Sign in with Single Sign-On"
-msgstr "Inicie sesión mediante inicio de sesión único"
+msgid "Sign in with single sign-on"
+msgstr ""
msgid "Sign in with smart card"
msgstr "Inicie sesión con una tarjeta inteligente"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr "Límite de tamaño por repositorio (MB)"
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr "Omitido"
@@ -37753,6 +38241,9 @@ msgstr "Alguien editó este merge request al mismo tiempo que lo hizo usted. Por
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr "Alguien editó este caso de prueba al mismo tiempo que usted. Se ha actualizado la descripción y deberá hacer sus cambios de nuevo."
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "Alguien, esperemos que usted, ha solicitado restablecer la contraseña de su cuenta de GitLab en %{link_to_gitlab}."
@@ -37864,9 +38355,6 @@ msgstr "Algo salió mal al buscar los entornos para este merge request. ¡Por fa
msgid "Something went wrong while fetching the packages list."
msgstr "Se produjo un error al obtener la lista de paquetes."
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr "Se ha producido un error al inicializar el visor OpenAPI"
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr "Estado:"
msgid "Status: %{title}"
msgstr "Estado: %{title}"
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr "%{failed} fallido y %{pending} pendiente"
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr "API a comprobar"
msgid "StatusCheck|Add status check"
msgstr "Añadir una verificación de estado"
-msgid "StatusCheck|All passed"
-msgstr "Todo superado"
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr "Se ha producido un error al eliminar la comprobación de estado %{name}."
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr "Amarillo titanio"
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr "Cambiar rama"
msgid "Switch branch/tag"
msgstr "Cambiar rama/etiqueta"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr "Cambiar a GitLab Next"
@@ -39351,6 +39839,9 @@ msgstr "Tabla de contenidos"
msgid "Tag"
msgstr "Etiqueta"
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr "Listas de etiquetas:"
@@ -39435,6 +39926,9 @@ msgstr "Eliminar la etiqueta. ¿Está ABSOLUTAMENTE SEGURO?"
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr "Editar versión"
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr "Opcionalmente, agregue un mensaje a la etiqueta. Deje este espacio en blanco para crear una %{link_start}etiqueta ligera.%{link_end}"
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr "Por favor, escriba lo siguiente para confirmar:"
-msgid "TagsPage|Release notes"
-msgstr "Notas de la versión"
-
msgid "TagsPage|Repository has no tags yet."
msgstr "El repositorio todavía no tiene etiquetas."
@@ -39486,9 +39974,6 @@ msgstr "No se pueden cargar las etiquetas"
msgid "TagsPage|Use git tag command to add a new one:"
msgstr "Utilice el comando git tag para añadir una nueva:"
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "Escriba sus notas de la versión o arrastre los archivos aquí…"
-
msgid "TagsPage|Yes, delete protected tag"
msgstr "Sí, eliminar etiqueta protegida"
@@ -39507,6 +39992,9 @@ msgstr "protegido"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr "Rama de destino"
@@ -39618,16 +40106,6 @@ msgstr "¿Utiliza Terraform? Pruebe los estados administrados de Terraform de Gi
msgid "Terraform|%{name} successfully removed"
msgstr "%{name} eliminado correctamente"
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] "%{number} No se puede generar el informe de Terraform"
-msgstr[1] "%{number} No se pueden generar los informes de Terraform"
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr "Se ha producido un error al generar un informe de Terraform."
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr "Se ha generado un informe en sus pipelines."
-
msgid "Terraform|Actions"
msgstr "Acciones"
@@ -39740,12 +40212,6 @@ msgstr "El comando Terraform init"
msgid "Terraform|Terraform reports"
msgstr "Informes de Terraform"
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr "El trabajo %{name} no pudo generar un informe."
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr "El trabajo %{name} generó un informe."
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr "El nombre de servidor de su servidor de PlantUML."
msgid "The hostname of your Snowplow collector."
msgstr "El nombre de su colector de Snowplow"
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "La importación finalizará después de %{timeout}. Para los repositorios que necesiten más tiempo, utilice una combinación de comandos 'clone'/'push'."
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr "El recurso al que está intentando acceder no existe o no tiene permiso para realizar esta acción."
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,8 +40894,8 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr "La pestaña especificada no es válida, por favor seleccione otra"
-msgid "The start date must be ealier than the end date."
-msgstr "La fecha de inicio debe ser anterior a la fecha de finalización."
+msgid "The start date must be earlier than the end date."
+msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
msgstr ""
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr "Tema"
-msgid "There are currently no events."
-msgstr "Actualmente no hay eventos."
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr "Estas incidencias tienen un título similar al de la incidencia que estÃ
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr "Este %{viewer} no se puede mostrar porque %{reason}. En su lugar, puedes
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,15 +41785,18 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr "Este espacio de nombres ya esta en uso. Por favor, elija otro diferente."
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
+msgstr ""
+
msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr "Esta página no está disponible porque no se le permite leer la información a través de múltiples proyectos."
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
-msgstr ""
-
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
msgstr ""
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr "Este usuario no tiene ningún %{type} activo."
-
msgid "This user has no identities"
msgstr "El usuario no tiene ninguna identidad"
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr "Esta variable no se puede enmascarar."
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr "Para confirmar, escriba %{phrase_code}"
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr "Hoy"
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr "Colaboraciones totales"
msgid "Total Score"
msgstr "Puntuación total"
-msgid "Total artifacts size: %{total_size}"
-msgstr "Tamaño total de los artefactos: %{total_size}"
-
msgid "Total cores (CPUs)"
msgstr "Núcleos totales (CPUs)"
@@ -42543,6 +43069,12 @@ msgstr "La autenticación de doble factor ha sido desactivada para este usuario"
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr "La autenticación de doble factor ha sido deshabilitada para su cuenta de GitLab."
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr "La autenticación de doble factor se ha desactivado correctamente"
@@ -43047,6 +43579,12 @@ msgstr "Tendencias de uso"
msgid "Usage statistics"
msgstr "Estadísticas de uso"
+msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
+msgstr ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr "%{help_link_start}Los ejecutores compartidos%{help_link_end} están deshabilitados, por lo que no hay límites establecidos para el uso de los pipelines"
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr "Paquetes"
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr "Repositorio"
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr "Ver archivo @ %{commitSha}"
msgid "View full dashboard"
msgstr "Ver el tablero completo"
-msgid "View full log"
-msgstr "Ver registro completo"
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr "Solicitud/Respuesta"
msgid "Vulnerability|Scanner Provider"
msgstr "Proveedor para el análisis"
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr "Estado"
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,8 +45393,8 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "Queremos asegurarnos de que sea usted, por favor, ayudenos a confirmar que no es un robot."
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
-msgstr "Queremos informarle que el usuario %{username} ha sido baneado de %{scope} debido a que ha descargado más de %{max_project_downloads} repositorios de proyectos en %{within_minutes} minutos."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
+msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
msgstr "Notificaremos a %{inviter} que ha rechazado su invitación para unirse a GitLab. Dejará de recibir recordatorios."
@@ -44888,6 +45435,9 @@ msgstr "Dispositivos WebAuthn (%{length})"
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr "WebAuthn sólo funciona con sitios web habilitados para HTTPS. Póngase en contacto con su administrador para obtener más detalles."
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr "Webhooks"
msgid "Webhooks Help"
msgstr "Ayuda de Webhooks"
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr "Disparador"
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr "Sitio web"
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr "¿Qué plantillas puedo crear?"
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr "¿Para qué va a utilizar este grupo?"
@@ -45209,7 +45789,7 @@ msgstr "¿Qué le gustaría hacer?"
msgid "What's new"
msgstr "¿Qué hay de nuevo?"
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr "Añadir tarea"
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr "¿Está seguro que desea cancelar la edición?"
@@ -45575,9 +46161,24 @@ msgstr "Introducción de tareas"
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr "Se ha producido un error aleliminar una tarea. Por favor, inténtelo de nuevo."
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr "Se ha producido un error al intentar añadir un trabajo hijo. Por favor,
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr "Está intentando eliminar un archivo que ha sido actualizado previamente
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr "Está intentando actualizar un archivo que ha sido modificado desde que comenzó a editarlo."
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr "No tiene permiso para aprobar a un usuario"
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr "Está utilizando PostgreSQL %{pg_version_current}, pero PostgreSQL %{pg_version_minimum} es necesario para esta versión de GitLab. Por favor, actualice su entorno a una versión de PostgreSQL compatible, vea %{pg_requirements_url} para más detalles."
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr "Puede probar su archivo .gitlab-ci.yml en %{linkStart}CI Lint%{linkEnd}.
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr "No puede suplantar a un usuario bloqueado"
msgid "You cannot impersonate a user who cannot log in"
msgstr "No puede suplantar a un usuario que no puede iniciar sesión"
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr "No puede suplantar a un usuario interno"
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr "Debe estar conectado para buscar en todo GitLab"
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr "YouTube"
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr "Su cuenta está bloqueada."
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr "Su cuenta utiliza credenciales dedicadas para el grupo \"%{group_name}\" y sólo puede actualizarse a través de SSO."
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,18 +47272,15 @@ msgstr "Su mensaje aquí"
msgid "Your name"
msgstr "Tu nombre"
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
+msgstr ""
+
msgid "Your new %{accessTokenType}"
msgstr "Su nuevo %{accessTokenType}"
msgid "Your new %{accessTokenType} has been created."
msgstr "Se ha creado un nuevo %{accessTokenType}."
-msgid "Your new %{type}"
-msgstr "Su nuevo %{type}"
-
-msgid "Your new access token has been created."
-msgstr ""
-
msgid "Your new comment"
msgstr ""
@@ -46742,6 +47367,9 @@ msgstr "Su actualización ha fallado. Debe cargar un archivo con el mismo nombre
msgid "Your username is %{username}."
msgstr "Su nombre de usuario es %{username}."
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr "un usuario eliminado"
@@ -46825,9 +47450,6 @@ msgstr[1] "alrededor de %d horas"
msgid "access:"
msgstr "acceso:"
-msgid "added"
-msgstr "añadido"
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr "asignar a ti mismo"
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr "en"
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr "en riesgo"
-
msgid "attach a new file"
msgstr "adjuntar un nuevo archivo"
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr "El análisis de dependencias detecta vulnerabilidades conocidas en las d
msgid "ciReport|Dependency scanning"
msgstr "Escaneo de seguridad"
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr "Descargue el parche para resolver"
msgid "ciReport|Download the patch to apply it manually"
msgstr "Descargue el parche para aplicarlo manualmente"
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr "Dynamic Application Security Testing (DAST) detecta vulnerabilidades conocidas en su código fuente."
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr "Nuevo"
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr "Análisis de seguridad"
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr "Solución"
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr "Static Application Security Testing (SAST) detecta vulnerabilidades conocidas en su código fuente."
@@ -47411,6 +48066,9 @@ msgstr "commit %{commit_id}"
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] "días"
msgid "days"
msgstr "días"
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr "rama por defecto"
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] "de %d trabajo"
msgstr[1] "de %d trabajos"
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr "frontmatter"
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr "estado del hito invalido '%{state}'"
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr "es"
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr "este es un rango de direcciones IP no válido"
@@ -47753,6 +48423,9 @@ msgstr "no es"
msgid "is not a descendant of the Group owning the template"
msgstr "no es un descendiente del grupo que es propietario de la plantilla"
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr "no es un certificado X509 válido."
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr "Revertir esta solicitud de merge en un nuevo merge request"
msgid "mrWidget|Revoke approval"
msgstr "Revocar la aprobación"
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr "debe ser mayor que la fecha de inicio"
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr "necesita atención"
-
msgid "needs to be between 10 minutes and 1 month"
msgstr "el intervalo debe estar comprendido entre 10 minutos y 1 mes"
@@ -48336,9 +49018,6 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}, y %{lastItem}"
-msgid "on track"
-msgstr "a tiempo"
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr "o"
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] "total de %d prueba"
-msgstr[1] "totales de %d pruebas"
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "padre"
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr "eliminar el peso"
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr "repositorio:"
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr "satisfecho"
@@ -48681,6 +49363,9 @@ msgstr "este documento"
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr "con el vencimiento que permanece sin cambios en %{old_expiry}"
msgid "yaml invalid"
msgstr "El fichero yaml no es válido"
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr "su instancia de GitLab"
diff --git a/locale/et_EE/gitlab.po b/locale/et_EE/gitlab.po
index 8ba2aa55b63..eefececf5aa 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: 2022-10-10 14:01\n"
+"PO-Revision-Date: 2022-11-13 09:21\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/fa_IR/gitlab.po b/locale/fa_IR/gitlab.po
index d1dcab0c699..54400b98ac9 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: 2022-10-10 14:00\n"
+"PO-Revision-Date: 2022-11-13 09:21\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/fi_FI/gitlab.po b/locale/fi_FI/gitlab.po
index d0dadef061f..3e0ca3caa63 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: 2022-10-10 14:02\n"
+"PO-Revision-Date: 2022-11-13 09:22\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/fil_PH/gitlab.po b/locale/fil_PH/gitlab.po
index 1f520e7303e..862adcf8340 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: 2022-10-10 14:05\n"
+"PO-Revision-Date: 2022-11-13 09:25\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/fr/gitlab.po b/locale/fr/gitlab.po
index e650c9c1beb..892b4268642 100644
--- a/locale/fr/gitlab.po
+++ b/locale/fr/gitlab.po
@@ -14,7 +14,7 @@ msgstr ""
"X-Crowdin-Language: fr\n"
"X-Crowdin-File: /master/locale/gitlab.pot\n"
"X-Crowdin-File-ID: 16\n"
-"PO-Revision-Date: 2022-10-10 14:01\n"
+"PO-Revision-Date: 2022-11-13 09:22\n"
msgid " %{start} to %{end}"
msgstr " %{start} à %{end}"
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] "%d utilisateur supplémentaire"
msgstr[1] "%d utilisateurs supplémentaires"
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] "%d approbation requise"
+msgstr[1] "%d approbations requises"
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d approbateur"
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] "%d épopée"
msgstr[1] "%d épopées"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d erreur"
-msgstr[1] "%d erreurs"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d exportateur"
msgstr[1] "%d exportateurs"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%d a échoué"
-msgstr[1] "%d ont échoué"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] "%d tâche de sécurité échouée"
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] "%d fichier"
msgstr[1] "%d fichiers"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d résultat du test corrigé"
-msgstr[1] "%d résultats du test corrigés"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] "%d divergence"
@@ -513,11 +503,14 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] "%{bold_start}%{count}%{bold_end} demande de fusion ouverte"
msgstr[1] "%{bold_start}%{count}%{bold_end} demandes de fusion ouvertes"
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr "%{code_open}Masqué :%{code_close} Masqué dans les journaux des logs. Doit correspondre aux exigences de masquage."
msgid "%{code_open}Protected:%{code_close} Only exposed to protected branches or protected tags."
-msgstr ""
+msgstr "%{code_open}Protégées :%{code_close} Exposées uniquement aux branches ou étiquettes protégées."
msgid "%{commit_author_link} authored %{commit_authored_timeago}"
msgstr "%{commit_author_link} a écrit %{commit_authored_timeago}"
@@ -567,6 +560,16 @@ msgstr[1] "%{count} contacts"
msgid "%{count} files touched"
msgstr "%{count} fichiers modifiés"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] "%{count} groupe"
+msgstr[1] "%{count} groupes"
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] "%{count} ticket"
+msgstr[1] "%{count} tickets"
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "%{count} élément"
@@ -575,6 +578,11 @@ msgstr[1] "%{count} éléments"
msgid "%{count} items per page"
msgstr "%{count} éléments par page"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] "%{count} demande de fusion"
+msgstr[1] "%{count} demandes de fusion"
+
msgid "%{count} more"
msgstr "encore %{count}"
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} participant·e"
msgstr[1] "%{count} participant·e·s"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] "%{count} projet"
+msgstr[1] "%{count} projets"
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} lié à %{pluralized_subject}: %{links}"
@@ -636,9 +649,6 @@ msgstr "%{docs_link_start}Qu'est-ce que le stockage de fichiers volumineux ?%{d
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr "%{docs_link_start}Qu'est-ce que l'authentification à deux facteurs ?%{docs_link_end}"
-msgid "%{due_date} (Past due)"
-msgstr "%{due_date} (Échéance)"
-
msgid "%{duration}ms"
msgstr "%{duration}ms"
@@ -742,13 +752,13 @@ msgid "%{labelStart}Crash Address:%{labelEnd} %{crash_address}"
msgstr "%{labelStart}Adresse du plantage :%{labelEnd} %{crash_address}"
msgid "%{labelStart}Crash State:%{labelEnd} %{crash_state}"
-msgstr ""
+msgstr "%{labelStart}État du plantage :%{labelEnd} %{crash_state}"
msgid "%{labelStart}Crash State:%{labelEnd} %{stacktrace_snippet}"
msgstr "%{labelStart}État du plantage :%{labelEnd} %{stacktrace_snippet}"
msgid "%{labelStart}Crash Type:%{labelEnd} %{crash_type}"
-msgstr ""
+msgstr "%{labelStart}Type du plantage :%{labelEnd} %{crash_type}"
msgid "%{labelStart}Evidence:%{labelEnd} %{evidence}"
msgstr "%{labelStart}Preuve :%{labelEnd} %{evidence}"
@@ -849,12 +859,6 @@ msgstr "L’espace de noms %{name_with_link} a épuisé son temps d’exécution
msgid "%{name} (Busy)"
msgstr "%{name} (occupé)"
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} contenait %{resultsString}"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} a trouvé %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr "%{name} est déjà utilisé pour un autre emoji"
@@ -1040,6 +1044,9 @@ msgstr[1] "%{strongStart}%{count}%{strongEnd} commits"
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr "Projets de %{strong_open}%{group_name}%{strong_close} :"
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "%{strong_start}%{branch_count}%{strong_end} branche"
@@ -1071,7 +1078,7 @@ msgstr[0] "%{strong_start}%{errors}%{strong_end} point"
msgstr[1] "%{strong_start}%{errors}%{strong_end} points"
msgid "%{strong_start}%{human_size}%{strong_end} Project Storage"
-msgstr ""
+msgstr "Stockage de projet %{strong_start}%{human_size}%{strong_end}"
msgid "%{strong_start}%{release_count}%{strong_end} Release"
msgid_plural "%{strong_start}%{release_count}%{strong_end} Releases"
@@ -1093,7 +1100,7 @@ msgid "%{tags} tags per image name"
msgstr "%{tags} étiquettes par nom d'image"
msgid "%{tag}-%{evidence}-%{filename}"
-msgstr ""
+msgstr "%{tag}-%{evidence}-%{filename}"
msgid "%{template_project_id} is unknown or invalid"
msgstr "%{template_project_id} est inconnu ou invalide"
@@ -1102,7 +1109,7 @@ msgid "%{text} is available"
msgstr "%{text} est disponible"
msgid "%{timebox_type} does not support burnup charts"
-msgstr ""
+msgstr "%{timebox_type} ne prend pas en charge les graphiques burnup"
msgid "%{timebox_type} must have a start and due date"
msgstr ""
@@ -1182,9 +1189,6 @@ msgstr "%{user} a créé un ticket : %{issue_link}"
msgid "%{value} is not included in the list"
msgstr "%{value} ne fait pas partie de la liste"
-msgid "%{value} s"
-msgstr "%{value} s"
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} %{time_spent_value} temps passé."
@@ -1225,7 +1229,7 @@ msgid "'%{data}' at %{location} is not: %{const}"
msgstr ""
msgid "'%{level}' is not a valid visibility level"
-msgstr ""
+msgstr "« %{level} » n'est pas un niveau de visibilité valide"
msgid "'%{name}' Value Stream created"
msgstr "Chaîne de Valeur « %{name} » créée"
@@ -1237,10 +1241,13 @@ msgid "'%{name}' Value Stream saved"
msgstr "Chaîne de Valeur « %{name} » enregistrée"
msgid "'%{source}' is not a import source"
-msgstr ""
+msgstr "« %{source} » n'est pas une source d'importation"
msgid "'%{template_name}' is unknown or invalid"
-msgstr ""
+msgstr "« %{template_name} » est inconnu ou non valide"
+
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr "« %{value} » jours d'inactivité doit être supérieur ou égal à 90"
msgid "(%d closed)"
msgid_plural "(%d closed)"
@@ -1257,7 +1264,7 @@ msgid "(+%{count}&nbsp;rules)"
msgstr "(+%{count}&nbsp;règles)"
msgid "(Group Managed Account)"
-msgstr ""
+msgstr "(Compte Géré de Groupe)"
msgid "(No changes)"
msgstr "(Aucun changement)"
@@ -1280,6 +1287,9 @@ msgstr "(laissez vide si vous ne souhaitez pas faire de modification)"
msgid "(max size 15 MB)"
msgstr "(taille max 15 Mo)"
+msgid "(no user)"
+msgstr "(aucun utilisateur)"
+
msgid "(optional)"
msgstr "(facultatif)"
@@ -1302,7 +1312,7 @@ msgid "*Required"
msgstr "*Requis"
msgid "+ %{amount} more"
-msgstr ""
+msgstr "+ %{amount} de plus"
msgid "+ %{count} more"
msgstr "+ %{count} de plus"
@@ -1311,7 +1321,7 @@ msgid "+ %{moreCount} more"
msgstr "+ %{moreCount} de plus"
msgid "+ %{numberOfHiddenAssignees} more"
-msgstr ""
+msgstr "+ %{numberOfHiddenAssignees} de plus"
msgid "+%d more"
msgid_plural "+%d more"
@@ -1319,22 +1329,22 @@ msgstr[0] "+%d en plus"
msgstr[1] "+%d en plus"
msgid "+%{more_assignees_count}"
-msgstr ""
+msgstr "+%{more_assignees_count}"
msgid "+%{more_assignees_count} more assignees"
msgstr ""
msgid "+%{more_reviewers_count}"
-msgstr ""
+msgstr "+%{more_reviewers_count}"
msgid "+%{more_reviewers_count} more reviewers"
-msgstr ""
+msgstr "+%{more_reviewers_count} autres relecteurs"
msgid "+%{tags} more"
-msgstr ""
+msgstr "+%{tags} de plus"
msgid ", "
-msgstr ""
+msgstr ", "
msgid ", or "
msgstr ", ou "
@@ -1346,7 +1356,7 @@ msgid "- Add or remove a user."
msgstr "- Ajouter ou supprimer un utilisateur."
msgid "- Available to run jobs."
-msgstr ""
+msgstr "- Disponible pour exécuter des tâches."
msgid "- Create or close an issue."
msgstr "- Créer ou fermer un ticket."
@@ -1366,7 +1376,7 @@ msgid "- List the visible events for %{project_name} using the Events API %{even
msgstr "- Lister les événements visibles pour %{project_name} à l'aide de l'API Events %{events_api_link}."
msgid "- Not available to run jobs."
-msgstr ""
+msgstr "- Non disponible pour exécuter des tâches."
msgid "- Push code to the repository."
msgstr "- Pousser du code vers le dépôt."
@@ -1386,7 +1396,7 @@ msgid "- of - issues closed"
msgstr "- de - tickets fermés"
msgid "- of - weight completed"
-msgstr ""
+msgstr "- sur - poids terminé(s)"
msgid "- show less"
msgstr "- en montrer moins"
@@ -1495,8 +1505,8 @@ msgstr[1] "%{issues} tickets ouverts"
msgid "1 open merge request"
msgid_plural "%{merge_requests} open merge requests"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "1 demande de fusion ouverte"
+msgstr[1] "%{merge_requests} demandes de fusion ouvertes"
msgid "1 pipeline"
msgid_plural "%d pipelines"
@@ -1565,6 +1575,9 @@ msgstr "Vous n’avez pas l’autorisation d’accéder à cette page."
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "Assurezâ€vous que l’adresse est correcte et que la page n’a pas été déplacée."
+msgid "404|Not found"
+msgstr "Introuvable"
+
msgid "404|Page Not Found"
msgstr "Page introuvable"
@@ -1584,31 +1597,31 @@ msgid ":%{startLine} to %{endLine}"
msgstr ""
msgid "A %{incident_docs_start}modified issue%{incident_docs_end} to guide the resolution of incidents."
-msgstr ""
+msgstr "Un %{incident_docs_start}ticket modifié%{incident_docs_end} pour guider la résolution des incidents."
msgid "A .NET Core console application template, customizable for any .NET Core project"
msgstr "Un modèle d’application de console .NET Core, personnalisable pour tout projet .NET Core"
msgid "A CI/CD pipeline must run and be successful before merge."
-msgstr ""
+msgstr "Un pipeline CI/CD doit s'exécuter et avoir réussi avant la fusion."
msgid "A GitBook site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
-msgstr ""
+msgstr "Un site GitBook utilisant Netlify pour la CI/CD à la place de GitLab, mais tout en proposant toutes les autres fonctionnalités de GitLab"
msgid "A Gitpod configured Webapplication in Spring and Java"
-msgstr ""
+msgstr "Une application Web en Spring et Java configurée avec Gitpod"
msgid "A Hexo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
-msgstr ""
+msgstr "Un site Hexo utilisant Netlify pour la CI/CD à la place de GitLab, mais tout en proposant toutes les autres fonctionnalités de GitLab"
msgid "A Hugo site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
-msgstr ""
+msgstr "Un site Hugo utilisant Netlify pour la CI/CD à la place de GitLab, mais tout en proposant toutes les autres fonctionnalités de GitLab"
msgid "A Jekyll site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
-msgstr ""
+msgstr "Un site Jekyll utilisant Netlify pour la CI/CD à la place de GitLab, mais tout en proposant toutes les autres fonctionnalités de GitLab"
msgid "A Let's Encrypt SSL certificate can not be obtained until your domain is verified."
-msgstr ""
+msgstr "Un certificat SSL de Let's Encrypt ne peut pas être obtenu tant que votre domaine n'est pas vérifié."
msgid "A Work Item can be a parent or a child, but not both."
msgstr "Un Élément de Travail peut être un parent ou un enfant, mais pas les deux à la fois."
@@ -1620,7 +1633,7 @@ msgid "A basic template for developing Linux programs using Kotlin Native"
msgstr "Un modèle de base pour développer des programmes Linux à l'aide de Kotlin Native"
msgid "A complete DevOps platform"
-msgstr ""
+msgstr "Une plateforme DevOps complète"
msgid "A confidential issue cannot have a parent that already has non-confidential children."
msgstr "Un ticket confidentiel ne peut pas avoir un parent qui a déjà un enfant non confidentiel."
@@ -1628,14 +1641,11 @@ msgstr "Un ticket confidentiel ne peut pas avoir un parent qui a déjà un enfan
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr "Un élément de travail confidentiel ne peut pas avoir un parent qui a déjà un enfant non confidentiel."
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "Une branche par défaut ne peut pas être choisie pour un projet vide."
-
msgid "A deleted user"
msgstr "Un utilisateur supprimé"
msgid "A different reason"
-msgstr ""
+msgstr "Une raison différente"
msgid "A file has been changed."
msgstr "Un fichier a été modifié."
@@ -1644,7 +1654,7 @@ msgid "A file was not found."
msgstr "Un fichier n'a pas été trouvé."
msgid "A file with '%{file_name}' already exists in %{branch} branch"
-msgstr ""
+msgstr "Un fichier avec « %{file_name} » existe déjà dans la branche %{branch}"
msgid "A file with this name already exists."
msgstr "Un fichier portant ce nom existe déjà."
@@ -1656,7 +1666,7 @@ msgid "A group represents your organization in GitLab. Groups allow you to manag
msgstr "Un groupe représente votre entreprise dans GitLab. Ils vous permettent de gérer les utilisateurs et de collaborer sur plusieurs projets."
msgid "A job artifact is an archive of files and directories saved by a job when it finishes."
-msgstr ""
+msgstr "Un artéfact de tâche est une archive de fichiers et de répertoires enregistrée par une tâche quand elle se termine."
msgid "A limit of %{ci_project_subscriptions_limit} subscriptions to or from a project applies."
msgstr "Une limite de %{ci_project_subscriptions_limit} abonnements depuis ou vers un projet est appliquée."
@@ -1665,7 +1675,7 @@ msgid "A management, operational, or technical control (that is, safeguard or co
msgstr ""
msgid "A member of the abuse team will review your report as soon as possible."
-msgstr ""
+msgstr "Un membre de l’équipe de prévention des abus examinera votre rapport dès que possible."
msgid "A new Auto DevOps pipeline has been created, go to the Pipelines page for details"
msgstr "Un nouveau pipeline Auto DevOps a été créé, allez à la page Pipelines pour plus de détails"
@@ -1709,14 +1719,11 @@ msgstr "Un jeton d'accès personnel, nommé %{token_name}, a été révoqué."
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr "Un site en pur HTML utilisant Netlify pour la CI/CD à la place de GitLab, mais tout en proposant toutes les autres fonctionnalités de GitLab"
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
-msgstr ""
+msgstr "Un modèle de projet pour le développement d'applications Salesforce avec les outils Salesforce Developer"
msgid "A project boilerplate for Tencent Serverless Framework that uses Next.js SSR"
-msgstr ""
+msgstr "Un modèle de projet pour Tencent Serverless Framework qui utilise SSR avec Next.js"
msgid "A project containing issues for each audit inquiry in the HIPAA Audit Protocol published by the U.S. Department of Health & Human Services"
msgstr ""
@@ -1746,22 +1753,22 @@ msgid "A user with write access to the source branch selected this option"
msgstr "Une personne avec un accès en écriture à la branche source a sélectionné cette option"
msgid "ACTION REQUIRED: Something went wrong while obtaining the Let's Encrypt certificate for GitLab Pages domain '%{domain}'"
-msgstr ""
+msgstr "ACTION REQUISE : Une erreur s'est produite lors de l'obtention du certificat Let's Encrypt pour le domaine GitLab Pages « %{domain} »"
msgid "API"
msgstr "API"
msgid "API Fuzzing"
-msgstr ""
+msgstr "API Fuzzing"
msgid "API Fuzzing Configuration"
-msgstr ""
+msgstr "Configuration de l'API Fuzzing"
msgid "API Help"
msgstr ""
msgid "API Token"
-msgstr ""
+msgstr "Jeton d'API"
msgid "API key"
msgstr "Clé de l'API"
@@ -1779,7 +1786,7 @@ msgid "APIFuzzing|API Fuzzing Configuration"
msgstr "Configuration de l'API Fuzzing"
msgid "APIFuzzing|Base URL of API testing target. For example, http://www.example.com."
-msgstr ""
+msgstr "URL de base pour la cible de test de l'API. Par exemple, http://exemple.com."
msgid "APIFuzzing|Choose a method"
msgstr "Choisissez une méthode"
@@ -1869,13 +1876,13 @@ msgid "APIFuzzing|folder/openapi.json"
msgstr "dossier/openapi.json"
msgid "AWS Access Key"
-msgstr ""
+msgstr "Clé d'Accès AWS"
msgid "AWS OpenSearch IAM credentials"
msgstr ""
msgid "AWS Secret Access Key"
-msgstr ""
+msgstr "Clé d'Accès Secrète AWS"
msgid "AWS access key ID (Optional)"
msgstr "ID de la clé d'accès AWS (facultatif)"
@@ -1908,7 +1915,7 @@ msgid "Abuse reports"
msgstr "Rapports d’abus"
msgid "Abuse reports notification email"
-msgstr ""
+msgstr "Adresse de courriel de notification des rapports d'abus"
msgid "Accept invitation"
msgstr "Accepter l’invitation"
@@ -1917,7 +1924,10 @@ msgid "Accept terms"
msgstr "Accepter les conditions"
msgid "Acceptable for use in this project"
-msgstr ""
+msgstr "Acceptable pour l'utilisation dans ce projet"
+
+msgid "Access Denied"
+msgstr "Accès Refusé"
msgid "Access Git repositories or the API."
msgstr "Accéder aux dépôts Git ou à l'API."
@@ -1929,19 +1939,19 @@ msgid "Access Tokens"
msgstr "Jetons d’accès"
msgid "Access denied for your LDAP account."
-msgstr ""
+msgstr "Accès refusé pour votre compte LDAP."
msgid "Access denied: %{error}"
msgstr "Accès refusé : %{error}"
msgid "Access expires"
-msgstr ""
+msgstr "L'accès expire"
msgid "Access forbidden. Check your access level."
-msgstr ""
+msgstr "Accès interdit. Vérifiez votre niveau d'accès."
msgid "Access granted"
-msgstr ""
+msgstr "Accès accordé"
msgid "Access requests"
msgstr "Demandes d'accès"
@@ -1962,16 +1972,16 @@ msgid "AccessDropdown|Users"
msgstr "Utilisateurs"
msgid "AccessTokens|Access Tokens"
-msgstr ""
+msgstr "Jetons d'Accès"
msgid "AccessTokens|Are you sure?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) ?"
msgid "AccessTokens|Are you sure? Any RSS or calendar URLs currently in use will stop working."
-msgstr ""
+msgstr "Êtes-vous sûr(e) ? Toute URL de flux RSS ou de calendrier actuellement utilisée cessera de fonctionner."
msgid "AccessTokens|Are you sure? Any issue email addresses currently in use will stop working."
-msgstr ""
+msgstr "Êtes-vous sûr(e) ? Toutes les adresses de courriel des tickets actuellement utilisées cesseront de fonctionner."
msgid "AccessTokens|Copy feed token"
msgstr "Copier le jeton de flux"
@@ -1986,13 +1996,13 @@ msgid "AccessTokens|Created"
msgstr "Créé"
msgid "AccessTokens|Feed token"
-msgstr ""
+msgstr "Jeton de flux"
msgid "AccessTokens|Incoming email token"
-msgstr ""
+msgstr "Jeton de courriel entrant"
msgid "AccessTokens|It cannot be used to access any other data."
-msgstr ""
+msgstr "Il ne peut pas être utilisé pour accéder à d'autres données."
msgid "AccessTokens|Keep this token secret. Anyone who has it can access repository static objects as if they were you. If that ever happens, %{linkStart}reset this token%{linkEnd}."
msgstr "Gardez ce jeton secret. Quiconque s’en empare peut accéder aux objets statiques du dépôt à votre place. Si jamais cela arrivait, %{linkStart}réinitialisez ce jeton%{linkEnd}."
@@ -2004,10 +2014,10 @@ msgid "AccessTokens|Keep this token secret. Anyone who has it can read activity
msgstr "Gardez ce jeton secret. Quiconque s’en empare peut lire les flux RSS de l'activité et des tickets, ou celui de votre agenda, comme s'il s'agissait de vous. Si cela arrive, %{linkStart}réinitialisez-le%{linkEnd}."
msgid "AccessTokens|Personal Access Tokens"
-msgstr ""
+msgstr "Jetons d'Accès Personnels"
msgid "AccessTokens|Static object token"
-msgstr ""
+msgstr "Jeton d'objet statique"
msgid "AccessTokens|The last time a token was used"
msgstr "La dernière fois qu'un jeton a été utilisé"
@@ -2016,10 +2026,10 @@ msgid "AccessTokens|They are the only accepted password when you have Two-Factor
msgstr ""
msgid "AccessTokens|You can also use personal access tokens to authenticate against Git over HTTP."
-msgstr ""
+msgstr "Vous pouvez également utiliser des jetons d'accès personnels pour vous authentifier auprès de Git via HTTP."
msgid "AccessTokens|You can generate a personal access token for each application you use that needs access to the GitLab API."
-msgstr ""
+msgstr "Vous pouvez générer un jeton d'accès personnel pour chaque application utilisée nécessitant un accès à l'API GitLab."
msgid "AccessTokens|Your feed token authenticates you when your RSS reader loads a personalized RSS feed or when your calendar application loads a personalized calendar. It is visible in those feed URLs."
msgstr "Votre jeton de flux vous authentifie lorsque votre lecteur RSS charge un flux RSS personnalisé ou lorsque votre application de calendrier charge un calendrier personnalisé. Il est visible dans les URL de ces flux."
@@ -2030,17 +2040,11 @@ msgstr "Votre jeton de courriel entrant vous authentifie lorsque vous créez un
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr "Votre jeton d'objet statique vous authentifie lorsque des objets statiques du dépôt (tels que des archives ou des blobs) sont servis depuis un stockage externe."
-msgid "AccessibilityReport|Learn more"
-msgstr "En savoir plus"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "Message : %{message}"
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
-msgstr ""
+msgstr "L'analyse d'accessibilité a trouvé une erreur du type suivant : %{code}"
msgid "Accessible by any user who is logged in."
msgstr "Accessible à tout utilisateur connecté."
@@ -2052,7 +2056,7 @@ msgid "Account"
msgstr "Compte"
msgid "Account ID"
-msgstr ""
+msgstr "ID du compte"
msgid "Account and limit"
msgstr "Limitations du compte"
@@ -2061,7 +2065,7 @@ msgid "Account:"
msgstr "Compte :"
msgid "Account: %{account}"
-msgstr ""
+msgstr "Compte : %{account}"
msgid "AccountValidation|Fix your pipelines by validating your account"
msgstr ""
@@ -2094,10 +2098,10 @@ msgid "Action to take when receiving an alert. %{docsLink}"
msgstr "Action à prendre lors de la réception d'une alerte. %{docsLink}"
msgid "Actions"
-msgstr ""
+msgstr "Actions"
msgid "Activate Service Desk"
-msgstr ""
+msgstr "Activer le Service d'Assistance"
msgid "Activated on"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr "Actif"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr "%{accessTokenTypePlural} actifs (%{totalAccessTokens})"
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr "Sessions actives"
@@ -2142,7 +2143,7 @@ msgid "Add Kubernetes cluster"
msgstr "Ajouter une grappe de serveurs Kubernetes"
msgid "Add LICENSE"
-msgstr ""
+msgstr "Ajouter LICENSE"
msgid "Add License"
msgstr "Ajouter une licence"
@@ -2154,19 +2155,19 @@ msgid "Add README"
msgstr "Ajouter un README"
msgid "Add Zoom meeting"
-msgstr ""
+msgstr "Ajouter une réunion Zoom"
msgid "Add a %{type}"
-msgstr ""
+msgstr "Ajouter un %{type}"
msgid "Add a GCP region"
-msgstr ""
+msgstr "Ajouter une région GCP"
msgid "Add a GPG key"
msgstr "Ajouter une clé GPG"
msgid "Add a GPG key for secure access to GitLab. %{help_link_start}Learn more.%{help_link_end}"
-msgstr ""
+msgstr "Ajouter une clé GPG pour sécuriser l'accès à GitLab. %{help_link_start}En savoir plus.%{help_link_end}"
msgid "Add a Terms of Service agreement and Privacy Policy for users of this GitLab instance."
msgstr "Ajouter des Conditions Générales d'Utilisation et une Politique de Confidentialité pour les utilisateurs de cette instance GitLab."
@@ -2211,7 +2212,7 @@ msgid "Add a related issue"
msgstr "Ajouter un ticket lié"
msgid "Add a suffix to Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
-msgstr ""
+msgstr "Ajouter un suffixe à l'adresse de courriel du Service d'Assistance. %{linkStart}En savoir plus.%{linkEnd}"
msgid "Add a table"
msgstr "Ajouter un tableau"
@@ -2229,28 +2230,28 @@ msgid "Add an SSH key"
msgstr "Ajouter une clé SSH"
msgid "Add an SSH key for secure access to GitLab. %{help_link_start}Learn more.%{help_link_end}"
-msgstr ""
+msgstr "Ajouter une clé SSH pour sécuriser l'accès à GitLab. %{help_link_start}En savoir plus.%{help_link_end}"
msgid "Add an existing issue"
msgstr "Ajouter un ticket existant"
msgid "Add an impersonation token"
-msgstr ""
+msgstr "Ajouter un jeton d'emprunt d'identité"
msgid "Add another link"
-msgstr ""
+msgstr "Ajouter un autre lien"
msgid "Add approval rule"
-msgstr ""
+msgstr "Ajouter une règle d'approbation"
msgid "Add approvers"
-msgstr ""
+msgstr "Ajouter des approbateurs"
msgid "Add broadcast message"
-msgstr ""
+msgstr "Ajouter un message de diffusion"
msgid "Add child epic to an epic"
-msgstr ""
+msgstr "Ajouter l'épopée enfant à une épopée"
msgid "Add comment now"
msgstr "Ajouter un commentaire"
@@ -2271,10 +2272,10 @@ msgid "Add commit messages as comments to Pivotal Tracker stories. %{docs_link}"
msgstr "Ajouter les messages de validation en tant que commentaires sur les histoires de Pivotal Tracker. %{docs_link}"
msgid "Add customer relation contact(s)."
-msgstr ""
+msgstr "Ajoutez un ou des contacts de relation client."
msgid "Add customer relation contacts"
-msgstr ""
+msgstr "Ajouter des contacts de relation client"
msgid "Add deploy freeze"
msgstr "Ajouter un gel de déploiement"
@@ -2286,7 +2287,7 @@ msgid "Add email address"
msgstr "Ajouter une adresse électronique"
msgid "Add email participant(s)"
-msgstr ""
+msgstr "Ajouter un ou plusieurs participants par courriel"
msgid "Add environment"
msgstr ""
@@ -2328,7 +2329,7 @@ msgid "Add new directory"
msgstr "Ajouter un nouveau dossier"
msgid "Add or remove a user."
-msgstr ""
+msgstr "Ajouter ou supprimer un utilisateur."
msgid "Add or remove previously merged commits"
msgstr ""
@@ -2358,10 +2359,10 @@ msgid "Add suggestion to batch"
msgstr ""
msgid "Add system hook"
-msgstr ""
+msgstr "Ajouter un crochet système"
msgid "Add text to the sign-in page. Markdown enabled."
-msgstr ""
+msgstr "Ajouter du texte à la page de connexion. Markdown activé."
msgid "Add to board"
msgstr "Ajouter au tableau"
@@ -2370,10 +2371,10 @@ msgid "Add to epic"
msgstr "Ajouter à l'épopée"
msgid "Add to merge train"
-msgstr ""
+msgstr "Ajouter au train de fusion"
msgid "Add to merge train when pipeline succeeds"
-msgstr ""
+msgstr "Ajouter au train de fusion lorsque le pipeline réussit"
msgid "Add to review"
msgstr "Ajouter à la revue de code"
@@ -2388,16 +2389,16 @@ msgid "Add trigger"
msgstr "Ajouter un déclencheur"
msgid "Add variable"
-msgstr ""
+msgstr "Ajouter une variable"
msgid "Add vulnerability finding"
msgstr ""
msgid "Add webhook"
-msgstr ""
+msgstr "Ajouter un crochet web"
msgid "Add your team members and others to GitLab."
-msgstr ""
+msgstr "Ajoutez les membres de votre équipe et d'autres personnes à GitLab."
msgid "Add/remove"
msgstr "Ajouter/supprimer"
@@ -2430,7 +2431,7 @@ msgid "Added"
msgstr "Ajouté"
msgid "Added %{epic_ref} as a child epic."
-msgstr ""
+msgstr "%{epic_ref} ajoutée comme épopée enfant."
msgid "Added %{label_references} %{label_text}."
msgstr "%{label_references} %{label_text} ajouté."
@@ -2463,7 +2464,7 @@ msgid "Additional text for the sign-in and Help page."
msgstr "Texte supplémentaire pour les pages d'aide et de connexion."
msgid "Additional text to show on the Help page"
-msgstr ""
+msgstr "Texte supplémentaire à afficher sur la page d'aide"
msgid "Additional text to show on the sign-in page"
msgstr "Texte supplémentaire à afficher sur la page de connexion"
@@ -2475,13 +2476,19 @@ msgid "Adds"
msgstr "Ajoute"
msgid "Adds %{epic_ref} as child epic."
-msgstr ""
+msgstr "Ajoute %{epic_ref} comme épopée enfant."
msgid "Adds %{labels} %{label_text}."
msgstr "Ajoute %{labels} %{label_text}."
msgid "Adds a Zoom meeting."
-msgstr ""
+msgstr "Ajoute une réunion Zoom."
+
+msgid "Adds a resource link"
+msgstr "Ajoute un lien de ressource"
+
+msgid "Adds a resource link for this incident."
+msgstr "Ajoute un lien de ressource pour cet incident."
msgid "Adds a timeline event to incident."
msgstr "Ajoute un événement de la chronologie à l'incident."
@@ -2493,7 +2500,7 @@ msgid "Adds an issue to an epic."
msgstr "Ajoute un ticket à une épopée."
msgid "Adds email participant(s)."
-msgstr ""
+msgstr "Ajoute un ou plusieurs participants via leur adresse de courriel."
msgid "Adds this %{issuable_type} as related to the %{issuable_type} it was created from"
msgstr "Ajoute ce %{issuable_type} en relation avec le %{issuable_type} depuis lequel il a été créé"
@@ -2508,7 +2515,7 @@ msgid "Admin Area"
msgstr "Espace d’administration"
msgid "Admin Mode"
-msgstr ""
+msgstr "Mode Admin"
msgid "Admin Note"
msgstr ""
@@ -2523,13 +2530,13 @@ msgid "Admin Section"
msgstr "Section Admin"
msgid "Admin mode already enabled"
-msgstr ""
+msgstr "Mode Admin déjà activé"
msgid "Admin mode disabled"
-msgstr ""
+msgstr "Mode Admin désactivé"
msgid "Admin mode enabled"
-msgstr ""
+msgstr "Mode Admin activé"
msgid "Admin navigation"
msgstr ""
@@ -2577,7 +2584,7 @@ msgid "AdminArea|Included Free in license"
msgstr ""
msgid "AdminArea|Instance OAuth applications"
-msgstr ""
+msgstr "Applications OAuth de l'instance"
msgid "AdminArea|Latest groups"
msgstr "Derniers groupes"
@@ -2592,7 +2599,7 @@ msgid "AdminArea|Maintainer"
msgstr "Mainteneur"
msgid "AdminArea|Manage applications for your instance that can use GitLab as an %{docs_link_start}OAuth provider%{docs_link_end}."
-msgstr ""
+msgstr "Gérer les applications de votre instance qui peuvent utiliser GitLab en tant que %{docs_link_start}fournisseur OAuth%{docs_link_end}."
msgid "AdminArea|Minimal access"
msgstr "Accès minimal"
@@ -2607,7 +2614,7 @@ msgid "AdminArea|New user"
msgstr "Nouvel utilisateur"
msgid "AdminArea|No applications found"
-msgstr ""
+msgstr "Aucune application trouvée"
msgid "AdminArea|Owner"
msgstr "Propriétaire"
@@ -2616,7 +2623,7 @@ msgid "AdminArea|Projects"
msgstr "Projets"
msgid "AdminArea|Reporter"
-msgstr ""
+msgstr "Rapporteur"
msgid "AdminArea|Sign up for the GitLab Security Newsletter to get notified for security updates."
msgstr "Inscrivez-vous à la lettre d'information sur la sécurité de GitLab pour être informé des mises à jour de sécurité."
@@ -2637,28 +2644,28 @@ msgid "AdminArea|Stopping jobs failed"
msgstr "L’arrêt des tâches a échoué"
msgid "AdminArea|Total users"
-msgstr ""
+msgstr "Nombre total d'utilisateurs"
msgid "AdminArea|Users"
msgstr "Utilisateurs"
msgid "AdminArea|Users statistics"
-msgstr ""
+msgstr "Statistiques sur les utilisateurs"
msgid "AdminArea|Users with highest role"
-msgstr ""
+msgstr "Utilisateurs ayant pour rôle le plus élevé"
msgid "AdminArea|Users without a Group and Project"
msgstr "Utilisateurs sans Groupe ni Projet"
msgid "AdminArea|View latest groups"
-msgstr ""
+msgstr "Voir les derniers groupes"
msgid "AdminArea|View latest projects"
-msgstr ""
+msgstr "Voir les derniers projets"
msgid "AdminArea|View latest users"
-msgstr ""
+msgstr "Voir les derniers utilisateurs"
msgid "AdminArea|You’re about to stop all jobs. This will halt all current jobs that are running."
msgstr "Vous êtes sur le point d'arrêter toutes les tâches. Toutes les tâches actuelles qui sont en cours d'exécution seront interrompues."
@@ -2666,6 +2673,24 @@ msgstr "Vous êtes sur le point d'arrêter toutes les tâches. Toutes les tâche
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr "Erreur lors du chargement des statistiques. Veuillez réessayer"
+msgid "AdminEmail|Body"
+msgstr "Corps"
+
+msgid "AdminEmail|Body is required."
+msgstr "Le corps est requis."
+
+msgid "AdminEmail|Recipient group or project"
+msgstr "Groupe ou projet destinataire"
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr "Un groupe ou projet destinataire est requis."
+
+msgid "AdminEmail|Subject"
+msgstr "Sujet"
+
+msgid "AdminEmail|Subject is required."
+msgstr "Le sujet est requis."
+
msgid "AdminLabels|Define your default set of project labels"
msgstr "Définissez votre propre ensemble d'étiquettes de projet"
@@ -2676,7 +2701,7 @@ msgid "AdminLabels|They can be used to categorize issues and merge requests."
msgstr "Elles peuvent servir à classifier les tickets et les demandes de fusion."
msgid "AdminProjects| You’re about to permanently delete the project %{projectName}, its repository, and all related resources, including issues and merge requests. After you confirm and press %{strong_start}Delete project%{strong_end}, it cannot be undone or recovered."
-msgstr ""
+msgstr "Vous êtes sur le point de supprimer définitivement le projet %{projectName}, son dépôt et toutes les ressources qui lui sont associées, y compris les tickets et les demandes de fusion. Après avoir confirmé et appuyé sur %{strong_start}Supprimer le projet%{strong_end}, cela ne pourra être ni annulé ni restauré."
msgid "AdminProjects|Delete"
msgstr "Supprimer"
@@ -2700,17 +2725,29 @@ msgid "AdminSettings|Auto DevOps domain"
msgstr "Domaine de DevOps automatique"
msgid "AdminSettings|CI/CD limits"
-msgstr ""
+msgstr "Limites CI/CD"
+
+msgid "AdminSettings|Clickhouse URL"
+msgstr "URL de Clickhouse"
msgid "AdminSettings|Configure Let's Encrypt"
msgstr "Configurer Let's Encrypt"
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
+msgstr "Configurer les limites du nombre de dépôts que les utilisateurs peuvent télécharger dans un temps donné."
+
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
msgstr ""
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr "Définir quand les projets inactifs doivent être automatiquement supprimés. %{linkStart}Qu'est-ce-qu'un projet inactif ?%{linkEnd}"
+msgid "AdminSettings|Cube API URL"
+msgstr "URL de l'API Cube"
+
+msgid "AdminSettings|Cube API key"
+msgstr "Clé d'API Cube"
+
msgid "AdminSettings|Delete inactive projects"
msgstr "Supprimer les projets inactifs"
@@ -2745,7 +2782,7 @@ msgid "AdminSettings|Enable Registration Features"
msgstr "Activer les fonctionnalités d'inscription"
msgid "AdminSettings|Enable Service Ping"
-msgstr ""
+msgstr "Activer le Ping de Service"
msgid "AdminSettings|Enable collection of application metrics. Restart required. %{link_start}Learn how to export metrics to Prometheus%{link_end}."
msgstr "Activer la collecte des métriques de l'application. Un redémarrage est requis. %{link_start}En savoir plus sur l'export des métriques vers Prometheus%{link_end}. "
@@ -2759,6 +2796,9 @@ msgstr "Activer l'analyseur personnalisé kuromoji : Recherche"
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr "Activer la bannière de suggestion de pipeline"
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr "Activer les exécuteurs partagés pour les nouveaux projets"
@@ -2804,6 +2844,18 @@ msgstr "Suppression de projet inactif"
msgid "AdminSettings|Instance runners expiration"
msgstr "Expiration des exécuteurs d'instance"
+msgid "AdminSettings|Jitsu administrator email"
+msgstr "Courriel de l'administrateur Jitsu"
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr "Mot de passe de l'administrateur Jitsu"
+
+msgid "AdminSettings|Jitsu host"
+msgstr "Hôte Jitsu"
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr "ID projet Jitsu"
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr "Conserver les derniers artéfacts de toutes les tâches des pipelines réussis le plus récemment"
@@ -2832,16 +2884,16 @@ msgid "AdminSettings|Maximum number of jobs in a single pipeline"
msgstr "Nombre maximum de tâches dans un pipeline unique"
msgid "AdminSettings|Maximum number of pipeline schedules"
-msgstr ""
+msgstr "Nombre maximum de planifications de pipelines"
msgid "AdminSettings|Maximum number of pipeline subscriptions to and from a project"
msgstr ""
msgid "AdminSettings|Maximum number of runners registered per group"
-msgstr ""
+msgstr "Nombre maximum d'exécuteurs enregistrés par groupe"
msgid "AdminSettings|Maximum number of runners registered per project"
-msgstr ""
+msgstr "Nombre maximum d'exécuteurs enregistrés par projet"
msgid "AdminSettings|Minimum size must be at least 0."
msgstr "La taille minimale doit être d'au moins 0."
@@ -2892,7 +2944,7 @@ msgid "AdminSettings|Search with Elasticsearch enabled"
msgstr "Recherche avec Elasticsearch activée"
msgid "AdminSettings|Select a CI/CD template"
-msgstr ""
+msgstr "Sélectionnez un modèle de CI/CD"
msgid "AdminSettings|Select a group to use as the source for instance-level project templates."
msgstr "Sélectionnez un groupe à utiliser comme source pour les modèles de projet de niveau instance."
@@ -2916,7 +2968,7 @@ msgid "AdminSettings|Set a CI/CD template as the required pipeline configuration
msgstr "Définir un modèle CI/CD comme configuration requise de pipeline pour tous les projets de l'instance. La configuration CI/CD du projet fusionne avec la configuration requise de pipeline lorsque le pipeline est exécuté. %{link_start}Qu'est-ce-qu'une configuration requise de pipeline ?%{link_end}"
msgid "AdminSettings|Set limit to 0 to disable it."
-msgstr ""
+msgstr "Définir la limite à 0 pour la désactiver."
msgid "AdminSettings|Set the expiration time of authentication tokens of newly registered group runners."
msgstr "Définit la durée avant expiration des jetons d'authentification des exécuteurs de groupe nouvellement enregistrés."
@@ -2928,7 +2980,7 @@ msgid "AdminSettings|Set the expiration time of authentication tokens of newly r
msgstr "Définit la durée avant expiration des jetons d'authentification des exécuteurs de projet nouvellement enregistrés."
msgid "AdminSettings|Set the initial name and protections for the default branch of new repositories created in the instance."
-msgstr ""
+msgstr "Définissez le nom initial et les protections de la branche par défaut des nouveaux dépôts créés dans l'instance."
msgid "AdminSettings|Set the maximum number of GitLab Pages custom domains per project (0 for unlimited). %{link_start}Learn more.%{link_end}"
msgstr "Définir le nombre maximal de domaines Pages GitLab personnalisés par projet (0 pour illimité). %{link_start}En savoir plus.%{link_end}"
@@ -2942,9 +2994,18 @@ msgstr "Le paramètre doit être supérieur à 0."
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr "Paramètres de taille et de domaine pour les sites statiques Pages."
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr "L'URL de votre instance Cube."
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr "L'hôte de votre instance Jitsu."
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr "Les derniers artéfacts de toutes les tâches des pipelines qui ont réussi le plus récemment dans chaque projet sont enregistrés et n'expirent pas."
@@ -2969,6 +3030,15 @@ msgstr "Nombre total de tâches dans les pipelines actuellement actifs"
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
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."
@@ -2985,7 +3055,7 @@ msgid "AdminSettings|You can't delete projects before the warning email is sent.
msgstr "Vous ne pouvez pas supprimer de projets tant que le courriel d'avertissement n'est pas envoyé."
msgid "AdminStatistics|Active Users"
-msgstr ""
+msgstr "Utilisateurs actifs"
msgid "AdminStatistics|Forks"
msgstr ""
@@ -3003,10 +3073,10 @@ msgid "AdminStatistics|Notes"
msgstr ""
msgid "AdminStatistics|SSH Keys"
-msgstr ""
+msgstr "Clés SSH"
msgid "AdminStatistics|Snippets"
-msgstr ""
+msgstr "Extraits"
msgid "AdminUsers|(Admin)"
msgstr "(Admin)"
@@ -3030,10 +3100,10 @@ msgid "AdminUsers|(Pending approval)"
msgstr "(En attente d'approbation)"
msgid "AdminUsers|2FA Disabled"
-msgstr ""
+msgstr "A2F Désactivée"
msgid "AdminUsers|2FA Enabled"
-msgstr ""
+msgstr "A2F Activée"
msgid "AdminUsers|A user can validate themselves by inputting a credit/debit card, or an admin can manually validate a user. Validated users can use free CI minutes on shared runners."
msgstr "Un utilisateur peut se valider lui-même en entrant une carte de crédit/débit, ou alors il peut être validé manuellement par un administrateur. Les utilisateurs validés peuvent utiliser des minutes CI gratuites sur les exécuteurs partagés."
@@ -3060,7 +3130,7 @@ msgid "AdminUsers|Active"
msgstr "Actif"
msgid "AdminUsers|Adjust the user cap setting on your instance"
-msgstr ""
+msgstr "Ajuster le paramètre du plafond d'utilisateurs sur votre instance"
msgid "AdminUsers|Admin"
msgstr "Admin"
@@ -3071,6 +3141,9 @@ msgstr "Administrateur"
msgid "AdminUsers|Admins"
msgstr "Admins"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr "Approuver"
@@ -3096,7 +3169,7 @@ msgid "AdminUsers|Ban user"
msgstr "Bannir un utilisateur"
msgid "AdminUsers|Ban user %{username}?"
-msgstr ""
+msgstr "Bannir l'utilisateur %{username} ?"
msgid "AdminUsers|Banned"
msgstr "Banni"
@@ -3114,10 +3187,10 @@ msgid "AdminUsers|Block user %{username}?"
msgstr "Bloquer l'utilisateur %{username} ?"
msgid "AdminUsers|Blocked"
-msgstr ""
+msgstr "Bloqué"
msgid "AdminUsers|Blocking user has the following effects:"
-msgstr ""
+msgstr "Bloquer un utilisateur aura les conséquences suivantes :"
msgid "AdminUsers|Bot"
msgstr "Bot"
@@ -3138,22 +3211,22 @@ msgid "AdminUsers|Confirm user"
msgstr "Confirmer l'utilisateur"
msgid "AdminUsers|Confirm user %{username}?"
-msgstr ""
+msgstr "Confirmer l'utilisateur %{username}?"
msgid "AdminUsers|Could not load user group counts. Please refresh the page to try again."
-msgstr ""
+msgstr "Impossible de charger le nombre de groupes d’utilisateurs. Veuillez actualiser la page pour réessayer."
msgid "AdminUsers|Deactivate"
-msgstr ""
+msgstr "Désactiver"
msgid "AdminUsers|Deactivate user %{username}?"
msgstr "Désactiver l'utilisateur %{username} ?"
msgid "AdminUsers|Deactivated"
-msgstr ""
+msgstr "Désactivé"
msgid "AdminUsers|Deactivating a user has the following effects:"
-msgstr ""
+msgstr "Désactiver un utilisateur aura les conséquences suivantes :"
msgid "AdminUsers|Delete User %{username} and contributions?"
msgstr "Supprimer le compte %{username} et ses contributions ?"
@@ -3195,13 +3268,13 @@ msgid "AdminUsers|Issues authored by this user are hidden from other users."
msgstr "Les tickets rédigés par cet utilisateur sont cachés aux autres utilisateurs."
msgid "AdminUsers|It's you!"
-msgstr ""
+msgstr "C'est vous !"
msgid "AdminUsers|LDAP Blocked"
msgstr "Bloqué par LDAP"
msgid "AdminUsers|Learn more about %{link_start}banned users.%{link_end}"
-msgstr ""
+msgstr "En savoir plus sur les %{link_start}utilisateurs bannis.%{link_end}"
msgid "AdminUsers|Limits"
msgstr "Limites"
@@ -3219,16 +3292,16 @@ msgid "AdminUsers|Manage (accept/reject) pending user sign ups"
msgstr "Gérer (accepter/refuser) les inscriptions des utilisateurs en attente"
msgid "AdminUsers|New user"
-msgstr ""
+msgstr "Nouvel utilisateur"
msgid "AdminUsers|No users found"
-msgstr ""
+msgstr "Aucun utilisateur trouvé"
msgid "AdminUsers|Owned groups will be left"
msgstr ""
msgid "AdminUsers|Pending approval"
-msgstr ""
+msgstr "En attente d'approbation"
msgid "AdminUsers|Personal projects will be left"
msgstr ""
@@ -3240,7 +3313,7 @@ msgid "AdminUsers|Quota of CI/CD minutes"
msgstr "Quota de minutes CI/CD"
msgid "AdminUsers|Reactivating a user will:"
-msgstr ""
+msgstr "Réactiver un utilisateur va :"
msgid "AdminUsers|Regular"
msgstr "Normal"
@@ -3263,8 +3336,8 @@ msgstr "Le lien de réinitialisation sera généré et envoyé à l'utilisateur.
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
-msgstr ""
+msgid "AdminUsers|Search by name, email, or username"
+msgstr "Rechercher par nom, courriel ou nom d'utilisateur"
msgid "AdminUsers|Search users"
msgstr "Rechercher des utilisateurs"
@@ -3276,7 +3349,7 @@ msgid "AdminUsers|Skype"
msgstr "Skype"
msgid "AdminUsers|Sort by"
-msgstr ""
+msgstr "Trier par"
msgid "AdminUsers|The maximum number of CI/CD minutes on shared runners that a group can use each month. Set 0 for unlimited. Set empty to inherit the global setting of %{minutes}"
msgstr "Le nombre maximum de minutes CI/CD sur les exécuteurs partagés qu'un groupe peut utiliser chaque mois. Définir à 0 pour illimité. Laisser vide pour hériter du paramètre global fixé à %{minutes}"
@@ -3291,31 +3364,31 @@ msgid "AdminUsers|The user has unlimited access to all groups, projects, users,
msgstr "L'utilisateur dispose d'un accès illimité à tous les groupes, projets, utilisateurs et fonctionnalités."
msgid "AdminUsers|The user will be logged out"
-msgstr ""
+msgstr "L'utilisateur sera déconnecté"
msgid "AdminUsers|The user will not be able to access git repositories"
-msgstr ""
+msgstr "L'utilisateur ne pourra pas accéder aux dépôts git"
msgid "AdminUsers|The user will not be able to access the API"
-msgstr ""
+msgstr "L'utilisateur ne pourra pas accéder à l'API"
msgid "AdminUsers|The user will not be able to use slash commands"
-msgstr ""
+msgstr "L'utilisateur ne pourra pas utiliser les commandes barre oblique"
msgid "AdminUsers|The user will not receive any notifications"
-msgstr ""
+msgstr "L'utilisateur ne recevra aucune notification"
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "Pour confirmer, veuillez saisir %{projectName}"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "Pour confirmer, veuillez saisir %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr "Pour confirmer, veuillez saisir %{username}."
msgid "AdminUsers|Unban user"
-msgstr ""
+msgstr "Gracier l'utilisateur"
msgid "AdminUsers|Unban user %{username}?"
-msgstr ""
+msgstr "Gracier l'utilisateur %{username} ?"
msgid "AdminUsers|Unblock"
msgstr "Débloquer"
@@ -3330,10 +3403,10 @@ msgid "AdminUsers|User administration"
msgstr "Administration des utilisateurs"
msgid "AdminUsers|User will not be able to access git repositories"
-msgstr ""
+msgstr "L'utilisateur ne pourra pas accéder aux dépôts git"
msgid "AdminUsers|User will not be able to login"
-msgstr ""
+msgstr "L'utilisateur ne pourra pas se connecter"
msgid "AdminUsers|Users"
msgstr "Utilisateurs"
@@ -3357,7 +3430,7 @@ msgid "AdminUsers|What does this mean?"
msgstr "Qu'est-ce que cela signifie?"
msgid "AdminUsers|When banned:"
-msgstr ""
+msgstr "Quand il est banni :"
msgid "AdminUsers|When the user logs back in, their account will reactivate as a fully active account"
msgstr ""
@@ -3366,31 +3439,31 @@ msgid "AdminUsers|Will be deleted"
msgstr ""
msgid "AdminUsers|Without projects"
-msgstr ""
+msgstr "Sans projets"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr "Vous êtes sur le point de supprimer définitivement l’utilisateur %{username}. Les tickets, les demandes de fusion et les groupes qui lui sont liés seront transférés à un « utilisateur fantôme » global au système. Pour éviter la perte de données, pensez à utiliser à la place la fonctionnalité %{strongStart}bloquer l'utilisateur%{strongEnd}. L'action %{strongStart}Supprimer l'utilisateur%{strongEnd} terminée, elle ne pourra pas être annulée ni récupérée."
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
-msgstr "Vous êtes sur le point de supprimer définitivement l’utilisateur %{username}. Cela supprimera tous les tickets, demandes de fusion et groupes qui lui sont liés. Pour éviter la perte de données, pensez à utiliser à la place la fonctionnalité %{strongStart}bloquer l'utilisateur%{strongEnd} . L'action %{strongStart}Supprimer l'utilisateur%{strongEnd} terminée, elle ne pourra pas être annulée ni récupérée."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
+msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
-msgstr ""
+msgstr "Vous pourrez toujours bloquer son compte de nouveau si besoin."
msgid "AdminUsers|You can always deactivate their account again if needed."
-msgstr ""
+msgstr "Vous pourrez toujours désactiver son compte de nouveau si besoin."
msgid "AdminUsers|You can always re-activate their account, their data will remain intact."
-msgstr ""
+msgstr "Vous pourrez toujours réactiver son compte, ses données resteront intactes."
msgid "AdminUsers|You can always unblock their account, their data will remain intact."
-msgstr ""
+msgstr "Vous pourrez toujours débloquer son compte, ses données resteront intactes."
msgid "AdminUsers|You can ban their account in the future if necessary."
msgstr "Vous pouvez bannir leur compte dans le futur si nécessaire."
msgid "AdminUsers|You can unban their account in the future. Their data remains intact."
-msgstr ""
+msgstr "Vous pourrez toujours le gracier plus tard, ses données resteront intactes."
msgid "AdminUsers|You cannot remove your own administrator access."
msgstr "Vous ne pouvez pas supprimer votre propre accès administrateur."
@@ -3399,7 +3472,7 @@ msgid "AdminUsers|You must transfer ownership or delete the groups owned by this
msgstr "Vous devez faire un transfert de propriété ou supprimer les groupes appartenant à cet utilisateur avant de pouvoir supprimer son compte"
msgid "AdminUsers|Your GitLab instance has reached the maximum allowed %{user_doc_link} set by an instance admin."
-msgstr ""
+msgstr "Votre instance GitLab a atteint son %{user_doc_link} maximum autorisé défini par un administrateur de l'instance."
msgid "AdminUsers|approve them"
msgstr ""
@@ -3411,7 +3484,7 @@ msgid "AdminUsers|docs"
msgstr "docs"
msgid "AdminUsers|user cap"
-msgstr ""
+msgstr "plafond d'utilisateurs"
msgid "Administration"
msgstr "Administration"
@@ -3419,6 +3492,9 @@ msgstr "Administration"
msgid "Administrators"
msgstr "Administrateurs"
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr "Les administrateurs ne sont pas autorisés à connecter des applications avec ces portées : %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close} et %{code_open}sudo%{code_close}. Pour le permettre, modifiez le paramètre %{code_open}disable_admin_oauth_scopes%{code_close} en utilisant l'API."
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr "Les utilisateurs supplémentaires doivent être examinés et approuvés par un administrateur système. En savoir plus sur les %{help_link_start}limites d'utilisation%{help_link_end}."
@@ -3465,22 +3541,22 @@ msgid "AdvancedSearch|Introduced in GitLab 13.1, before using %{reindexing_link_
msgstr ""
msgid "AdvancedSearch|Pause indexing and upgrade Elasticsearch to a supported version."
-msgstr ""
+msgstr "Suspendre l'indexation et mettre à niveau Elasticsearch vers une version prise en charge."
msgid "AdvancedSearch|Reindex recommended"
-msgstr ""
+msgstr "Réindexation recommandée"
msgid "AdvancedSearch|Reindex required"
msgstr "Réindexation requise"
msgid "AdvancedSearch|You are using outdated code search mappings. To improve code search quality, we recommend you use %{reindexing_link_start}zero-downtime reindexing%{link_end} or %{recreate_link_start}re-create your index%{link_end}."
-msgstr ""
+msgstr "Vous utilisez des mappages de recherche de code obsolètes. Pour améliorer la qualité de la recherche de code, nous vous conseillons d'utiliser la %{reindexing_link_start}réindexation sans temps d'arrêt%{link_end} ou de %{recreate_link_start}recréer votre index%{link_end}. "
msgid "After a successful password update you will be redirected to login screen."
msgstr "Après modification de votre mot de passe, vous serez redirigé vers l’écran de connexion."
msgid "After a successful password update, you will be redirected to the login page where you can log in with your new password."
-msgstr ""
+msgstr "Après une mise à jour réussie du mot de passe, vous serez redirigé(e) vers la page de connexion où vous pourrez vous connecter avec votre nouveau mot de passe."
msgid "After it expires, you can't use merge approvals, code quality, or many other features."
msgstr "Après son expiration, vous ne pouvez pas utiliser les approbations de fusion, la qualité de code ou de nombreuses autres fonctionnalités."
@@ -3501,7 +3577,7 @@ msgid "Akismet"
msgstr "Akismet"
msgid "Akismet API Key"
-msgstr ""
+msgstr "Clé d'API Akismet"
msgid "Akismet helps prevent the creation of spam issues in public projects."
msgstr "Akismet contribue à empêcher la création de tickets indésirables dans les projets publics."
@@ -3528,7 +3604,7 @@ msgid "AlertManagement|Alert details"
msgstr ""
msgid "AlertManagement|Alert status: %{status}"
-msgstr ""
+msgstr "État de l'alerte : %{status}"
msgid "AlertManagement|Alerts"
msgstr "Alertes"
@@ -3543,7 +3619,7 @@ msgid "AlertManagement|Assignees"
msgstr ""
msgid "AlertManagement|Authorize external service"
-msgstr ""
+msgstr "Autoriser un service externe"
msgid "AlertManagement|Create incident"
msgstr "Créer un incident"
@@ -3552,7 +3628,7 @@ msgid "AlertManagement|Display alerts from all your monitoring tools directly wi
msgstr ""
msgid "AlertManagement|Edit"
-msgstr ""
+msgstr "Modifier"
msgid "AlertManagement|Environment"
msgstr "Environnement"
@@ -3582,7 +3658,7 @@ msgid "AlertManagement|No alerts available to display. See %{linkStart}enabling
msgstr "Aucune alerte n'est disponible pour affichage. Voir l'%{linkStart}activation de la gestion des alertes%{linkEnd} pour plus d’informations sur l’ajout d’alertes à la liste."
msgid "AlertManagement|No alerts to display."
-msgstr ""
+msgstr "Aucune alerte à afficher."
msgid "AlertManagement|None"
msgstr ""
@@ -3600,31 +3676,31 @@ msgid "AlertManagement|Reported %{when} by %{tool}"
msgstr ""
msgid "AlertManagement|Resolved"
-msgstr ""
+msgstr "Résolue"
msgid "AlertManagement|Runbook"
msgstr "Dossier d'exploitation"
msgid "AlertManagement|Service"
-msgstr ""
+msgstr "Service"
msgid "AlertManagement|Severity"
-msgstr ""
+msgstr "Gravité"
msgid "AlertManagement|Start time"
-msgstr ""
+msgstr "Heure de début"
msgid "AlertManagement|Status"
msgstr "État"
msgid "AlertManagement|Surface alerts in GitLab"
-msgstr ""
+msgstr "Remonter les alertes dans GitLab"
msgid "AlertManagement|There was an error displaying the alert. Please refresh the page to try again."
msgstr "Une erreur s’est produite lors de l’affichage de l’alerte. Veuillez actualiser la page pour réessayer."
msgid "AlertManagement|There was an error displaying the alerts. Confirm your endpoint's configuration details to ensure alerts appear."
-msgstr ""
+msgstr "Une erreur s'est produite lors de l'affichage des alertes. Confirmez les détails de configuration de vos points de terminaison pour vous assurer que des alertes apparaissent."
msgid "AlertManagement|There was an error while updating the assignee(s) list. Please try again."
msgstr "Une erreur s’est produite lors de la mise à jour de la liste des assigné(e)s. Veuillez réessayer."
@@ -3651,7 +3727,7 @@ msgid "AlertManagement|Value"
msgstr "Valeur"
msgid "AlertManagement|View incident"
-msgstr ""
+msgstr "Voir l'incident"
msgid "AlertMappingBuilder|Define fallback"
msgstr "Définir une solution par défaut"
@@ -3681,10 +3757,10 @@ msgid "AlertSettings|Alert settings"
msgstr "Paramètres d’alerte"
msgid "AlertSettings|Authorization key"
-msgstr ""
+msgstr "Clé d'autorisation"
msgid "AlertSettings|Configure details"
-msgstr ""
+msgstr "Configurer les détails"
msgid "AlertSettings|Current integrations"
msgstr "Intégrations actuelles"
@@ -3708,16 +3784,16 @@ msgid "AlertSettings|Enter an example payload from your selected monitoring tool
msgstr "Entrez un exemple de charge utile issu de votre outil de supervision sélectionné. Cela prend en charge l'envoi d'alertes vers un point de terminaison GitLab."
msgid "AlertSettings|Enter integration name"
-msgstr ""
+msgstr "Entrez le nom de l'intégration"
msgid "AlertSettings|Free versions of GitLab are limited to one integration per type. To add more, %{linkStart}upgrade your subscription%{linkEnd}."
-msgstr ""
+msgstr "Les versions gratuites de GitLab sont limitées à une intégration par type. Pour en ajouter, %{linkStart}mettez à niveau votre abonnement%{linkEnd}."
msgid "AlertSettings|GitLab has created a URL and authorization key for your integration. You can use them to set up a webhook and authorize your endpoint to send alerts to GitLab."
msgstr "GitLab a créé une URL et une clé d'autorisation pour votre intégration. Vous pouvez les utiliser pour mettre en place un crochet web et pour autoriser votre point de terminaison à envoyer des alertes vers GitLab."
msgid "AlertSettings|HTTP Endpoint"
-msgstr ""
+msgstr "Point de terminaison HTTP"
msgid "AlertSettings|If you edit the payload, you must re-map the fields again."
msgstr "Si vous modifiez la charge utile, vous devrez refaire l'association avec les champs."
@@ -3729,7 +3805,7 @@ msgid "AlertSettings|Integration successfully saved"
msgstr "Intégration enregistrée avec succès"
msgid "AlertSettings|Name integration"
-msgstr ""
+msgstr "Nommer l'intégration"
msgid "AlertSettings|Parse payload fields"
msgstr "Analyser les champs de la charge utile"
@@ -3738,7 +3814,7 @@ msgid "AlertSettings|Proceed with editing"
msgstr "Procéder à l'édition"
msgid "AlertSettings|Prometheus"
-msgstr ""
+msgstr "Prometheus"
msgid "AlertSettings|Prometheus API base URL"
msgstr "URL de base de l'API Prometheus"
@@ -3747,28 +3823,28 @@ msgid "AlertSettings|Reset Key"
msgstr "Réinitialiser la Clé"
msgid "AlertSettings|Reset the mapping"
-msgstr ""
+msgstr "Réinitialiser les associations"
msgid "AlertSettings|Sample payload has been parsed. You can now map the fields."
msgstr "L'exemple de charge utile a été analysé. Vous pouvez à présent faire l'association des champs."
msgid "AlertSettings|Save & create test alert"
-msgstr ""
+msgstr "Enregistrer et créer une alerte de test"
msgid "AlertSettings|Save integration"
-msgstr ""
+msgstr "Enregistrer l'intégration"
msgid "AlertSettings|Save integration & send"
msgstr "Enregistrer l’intégration et envoyer"
msgid "AlertSettings|Select integration type"
-msgstr ""
+msgstr "Sélectionnez le type d'intégration"
msgid "AlertSettings|Send test alert"
msgstr "Envoyer une alerte de test"
msgid "AlertSettings|Send without saving"
-msgstr ""
+msgstr "Envoyer sans enregistrer"
msgid "AlertSettings|The form has unsaved changes"
msgstr "Le formulaire comporte des modifications non enregistrées"
@@ -3783,10 +3859,10 @@ msgid "AlertSettings|URL cannot be blank and must start with http: or https:."
msgstr "L'URL ne peut pas être vide et doit commencer par http: ou https:."
msgid "AlertSettings|Use the URL and authorization key below to configure how Prometheus sends alerts to GitLab. Review the %{linkStart}GitLab documentation%{linkEnd} to learn how to configure your endpoint."
-msgstr ""
+msgstr "Utilisez l'URL et la clé d'autorisation ci-dessous pour configurer la façon dont Prometheus envoie des alertes à GitLab. Consultez la %{linkStart}documentation de GitLab%{linkEnd} pour apprendre à configurer votre point de terminaison."
msgid "AlertSettings|Use the URL and authorization key below to configure how an external service sends alerts to GitLab. %{linkStart}How do I configure the endpoint?%{linkEnd}"
-msgstr ""
+msgstr "Utilisez l'URL et la clé d'autorisation ci-dessous pour configurer la manière dont un service externe envoie des alertes à GitLab. %{linkStart}Comment configurer le point de terminaison ?%{linkEnd}"
msgid "AlertSettings|View URL and authorization key"
msgstr "Afficher l'URL et la clé d'autorisation"
@@ -3804,7 +3880,7 @@ msgid "AlertSettings|{ \"events\": [{ \"application\": \"Name of application\" }
msgstr "{ \"events\": [{ \"application\": \"Nom de l'application\" }] }"
msgid "Alerts"
-msgstr ""
+msgstr "Alertes"
msgid "AlertsIntegrations|Alerts will be created through this integration"
msgstr "Les alertes seront créées via cette intégration"
@@ -3816,7 +3892,7 @@ msgid "AlertsIntegrations|If you delete the %{integrationName} integration, aler
msgstr "Si vous supprimez l'intégration %{integrationName}, les alertes ne seront plus envoyées depuis ce point de terminaison. Cette action ne peut pas être annulée."
msgid "AlertsIntegrations|Integration Name"
-msgstr ""
+msgstr "Nom de l'intégration"
msgid "AlertsIntegrations|Integration payload is invalid."
msgstr "La charge utile de l’intégration n’est pas valide."
@@ -3849,7 +3925,7 @@ msgid "AlertsIntegrations|The test alert should now be visible in your alerts li
msgstr "L'alerte de test devrait maintenant être visible dans votre liste d'alertes."
msgid "Algorithm"
-msgstr ""
+msgstr "Algorithme"
msgid "All"
msgstr "Tous"
@@ -3867,7 +3943,7 @@ msgid "All Members"
msgstr "Tous les membres"
msgid "All branches"
-msgstr ""
+msgstr "Toutes les branches"
msgid "All changes are committed"
msgstr "Toutes les modifications sont validées"
@@ -3876,13 +3952,13 @@ msgid "All eligible users"
msgstr "Tous les utilisateurs éligibles"
msgid "All email addresses will be used to identify your commits."
-msgstr ""
+msgstr "Toutes les adresses de courriel seront utilisées pour identifier vos commits."
msgid "All environments"
-msgstr ""
+msgstr "Tous les environnements"
msgid "All groups and projects"
-msgstr ""
+msgstr "Tous les groupes et projets"
msgid "All issues"
msgstr "Tous les tickets"
@@ -3894,25 +3970,25 @@ msgid "All issues for this milestone are closed. You may close this milestone no
msgstr "Tous les tickets liés à ce jalon sont fermés. Vous pouvez désormais fermer ce jalon."
msgid "All merge conflicts were resolved. The merge request can now be merged."
-msgstr ""
+msgstr "Tous les conflits de fusion ont été résolus. La demande de fusion peut maintenant être fusionnée."
msgid "All merge request dependencies have been merged"
-msgstr ""
+msgstr "Toutes les dépendances des demandes de fusion ont été fusionnées"
msgid "All paths are relative to the GitLab URL. Do not include %{relative_url_link_start}relative URLs%{relative_url_link_end}."
-msgstr ""
+msgstr "Tous les chemins sont relatifs à l'URL de GitLab. Ne pas inclure les %{relative_url_link_start}URLs relatives%{relative_url_link_end}."
msgid "All project members"
msgstr "Tous les membres du projet"
msgid "All projects"
-msgstr ""
+msgstr "Tous les projets"
msgid "All projects selected"
msgstr "Tous les projets sélectionnés"
msgid "All protected branches"
-msgstr ""
+msgstr "Toutes les branches protégées"
msgid "All threads resolved!"
msgstr "Tous les sujets ont été résolus !"
@@ -3924,13 +4000,13 @@ msgid "All users must accept the Terms of Service and Privacy Policy to access G
msgstr "Tous les utilisateurs doivent accepter les Conditions Générales d'Utilisation et la Politique de Confidentialité pour accéder à GitLab"
msgid "All users must have a name."
-msgstr ""
+msgstr "Tous les utilisateurs doivent avoir un nom."
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
-msgstr ""
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr "Autoriser %{strongOpen}%{group_name}%{strongClose} pour vous connecter ?"
msgid "Allow access to members of the following group"
msgstr "Autoriser l'accès aux membres du groupe suivant"
@@ -3939,28 +4015,31 @@ msgid "Allow access to the following IP addresses"
msgstr "Autoriser l'accès aux adresses IP suivantes"
msgid "Allow commits from members who can merge to the target branch. %{link_start}About this feature.%{link_end}"
-msgstr ""
+msgstr "Autoriser les commits des membres qui peuvent fusionner vers la branche cible. %{link_start}À propos de cette fonctionnalité.%{link_end}"
msgid "Allow group owners to manage LDAP-related settings"
-msgstr ""
+msgstr "Autoriser les propriétaires de groupe à gérer les paramètres liés à LDAP"
+
+msgid "Allow new users to create top-level groups"
+msgstr "Autoriser les nouveaux utilisateurs à créer des groupes de premier niveau"
msgid "Allow non-administrators access to the performance bar"
msgstr "Autoriser les non-administrateurs à accéder à la barre de performance"
msgid "Allow only the selected protocols to be used for Git access."
-msgstr ""
+msgstr "Autoriser uniquement les protocoles sélectionnés pour accéder à Git."
msgid "Allow owners to manage default branch protection per group."
-msgstr ""
+msgstr "Autoriser les propriétaires à gérer la protection de la branche par défaut au niveau du groupe."
msgid "Allow owners to manually add users outside of LDAP"
-msgstr ""
+msgstr "Autoriser les propriétaires à ajouter manuellement des utilisateurs en dehors de LDAP"
msgid "Allow password authentication for Git over HTTP(S)"
-msgstr ""
+msgstr "Autoriser l'authentification par mot de passe pour Git en HTTP(S)"
msgid "Allow password authentication for the web interface"
-msgstr ""
+msgstr "Autoriser l'authentification par mot de passe pour l'interface Web"
msgid "Allow project maintainers to configure repository mirroring"
msgstr "Autoriser les mainteneurs de projet à configurer la mise en miroir de dépôts"
@@ -3980,23 +4059,20 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr "Autoriser les utilisateurs à créer des groupes de niveau supérieur"
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
msgid "Allow users to register any application to use GitLab as an OAuth provider"
-msgstr ""
+msgstr "Autoriser les utilisateurs à enregistrer n'importe quelle application pour utiliser GitLab en tant que fournisseur OAuth"
msgid "Allowed"
msgstr ""
msgid "Allowed email domain restriction only permitted for top-level groups"
-msgstr ""
+msgstr "La restriction de domaines de courriel autorisés est uniquement possible pour les groupes de haut niveau"
msgid "Allowed to create:"
-msgstr ""
+msgstr "Autorisés à créer :"
msgid "Allowed to delete projects"
msgstr "Autorisé à supprimer des projets"
@@ -4005,7 +4081,7 @@ msgid "Allowed to fail"
msgstr ""
msgid "Allows projects or subgroups in this group to override the global setting."
-msgstr ""
+msgstr "Autorise les projets ou les sous-groupes de ce groupe à outrepasser le paramètre global."
msgid "Allows projects to track errors using an Opstrace integration."
msgstr "Permet aux projets de faire un suivi des erreurs grâce à une intégration de Opstrace."
@@ -4014,10 +4090,10 @@ msgid "Allows you to add and manage Kubernetes clusters."
msgstr "Vous permet d’ajouter et de gérer des grappes de serveurs Kubernetes."
msgid "Almost there"
-msgstr ""
+msgstr "Presque fini"
msgid "Almost there..."
-msgstr ""
+msgstr "Presque fini..."
msgid "Already blocked"
msgstr "Déjà bloqué"
@@ -4041,16 +4117,16 @@ msgid "Alternate support URL for Help page and Help dropdown."
msgstr ""
msgid "Alternatively, you can convert your account to a managed account by the %{group_name} group."
-msgstr ""
+msgstr "Vous pouvez également convertir votre compte en un compte géré par le groupe %{group_name}."
msgid "Amazon EKS"
-msgstr ""
+msgstr "Amazon EKS"
msgid "Amazon EKS integration allows you to provision EKS clusters from GitLab."
-msgstr ""
+msgstr "L'intégration d'Amazon EKS vous permet de provisionner des grappes de serveurs EKS depuis GitLab."
msgid "Amazon Web Services Logo"
-msgstr ""
+msgstr "Logo Amazon Web Services"
msgid "An %{link_start}alert%{link_end} with the same fingerprint is already open. To change the status of this alert, resolve the linked alert."
msgstr ""
@@ -4068,7 +4144,7 @@ msgid "An alert has been resolved in %{project_path}."
msgstr ""
msgid "An alert has been triggered in %{project_path}."
-msgstr ""
+msgstr "Une alerte a été déclenchée dans %{project_path}."
msgid "An application called %{link_to_client} is requesting access to your GitLab account."
msgstr "Une application appelée %{link_to_client} demande l’accès à votre compte GitLab."
@@ -4077,7 +4153,7 @@ msgid "An email notification was recently sent from the admin panel. Please wait
msgstr "Une notification par courriel a récemment été envoyée depuis le panneau d'administration. Veuillez patienter %{wait_time_in_words} avant de tenter l'envoi d'un autre message."
msgid "An email will be sent with the report attached after it is generated."
-msgstr ""
+msgstr "Un courriel sera envoyé avec le rapport en pièce jointe une fois celui-ci généré."
msgid "An empty GitLab User field will add the FogBugz user's full name (e.g. \"By John Smith\") in the description of all issues and comments. It will also associate and/or assign these issues and comments with the project creator."
msgstr "Un champ utilisateur Gitlab vide ajoutera le nom complet de l’utilisateur FogBugz (p. ex., « Par John Smith ») dans la description de tous les tickets et commentaires. Il associera ou assignera ces tickets et commentaires au créateur du projet."
@@ -4089,28 +4165,28 @@ msgid "An error in reporting in which a test result incorrectly indicates the pr
msgstr ""
msgid "An error occurred adding a draft to the thread."
-msgstr ""
+msgstr "Une erreur s'est produite lors de l'ajout d'un brouillon au fil de conversation."
msgid "An error occurred adding a new draft."
msgstr "Une erreur est survenue lors de l’ajout d’un nouveau brouillon."
msgid "An error occurred creating the new branch."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la création de la nouvelle branche."
msgid "An error occurred fetching the approval rules."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des règles d'approbation."
msgid "An error occurred fetching the approvers for the new rule."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des approbateurs pour la nouvelle règle."
msgid "An error occurred fetching the dropdown data."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des données de la liste déroulante."
msgid "An error occurred fetching the project authors."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des auteurs du projet."
msgid "An error occurred fetching the public deploy keys. Please try again."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des clés de déploiement publiques. Veuillez réessayer."
msgid "An error occurred previewing the blob"
msgstr "Une erreur s’est produite lors de la prévisualisation du blob"
@@ -4122,7 +4198,7 @@ msgid "An error occurred when updating the title"
msgstr "Une erreur s'est produite lors de la mise à jour du titre"
msgid "An error occurred while acknowledging the notification. Refresh the page and try again."
-msgstr ""
+msgstr "Une erreur s'est produite en accusant réception de la notification. Rafraîchissez la page et réessayez."
msgid "An error occurred while adding approvers"
msgstr "Une erreur s'est produite lors de l'ajout des approbateurs"
@@ -4134,7 +4210,7 @@ msgid "An error occurred while approving, please try again."
msgstr "Une erreur s'est produite lors de l'approbation, veuillez réessayer."
msgid "An error occurred while authorizing your role"
-msgstr ""
+msgstr "Une erreur s'est produite lors de l'autorisation de votre rôle"
msgid "An error occurred while checking group path. Please refresh and try again."
msgstr "Une erreur s'est produite lors de la vérification du chemin d'accès au groupe. Veuillez actualiser et réessayer."
@@ -4143,19 +4219,19 @@ msgid "An error occurred while decoding the file."
msgstr "Une erreur s'est produite lors du décodage du fichier."
msgid "An error occurred while deleting the approvers group"
-msgstr ""
+msgstr "Une erreur s'est produite lors de la suppression du groupe d'approbateurs"
msgid "An error occurred while deleting the comment"
msgstr "Une erreur est survenue lors de la suppression du commentaire"
msgid "An error occurred while deleting the pipeline."
-msgstr ""
+msgstr "Une erreur s’est produite lors de la suppression du pipeline."
msgid "An error occurred while detecting host keys"
msgstr "Une erreur est survenue lors de la détection des clefs de l’hôte"
msgid "An error occurred while disabling Service Desk."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la désactivation du Service d'Assistance."
msgid "An error occurred while dismissing the alert. Refresh the page and try again."
msgstr "Une erreur s’est produite lors de la révocation de l’alerte. Actualisez la page et essayez à nouveau."
@@ -4167,10 +4243,10 @@ msgid "An error occurred while drawing job relationship links."
msgstr ""
msgid "An error occurred while enabling Service Desk."
-msgstr ""
+msgstr "Une erreur s'est produite lors de l'activation du Service d'Assistance."
msgid "An error occurred while fetching Markdown preview"
-msgstr ""
+msgstr "Une erreur s’est produite lors de la récupération de l'aperçu du Markdown"
msgid "An error occurred while fetching ancestors"
msgstr "Une erreur s’est produite lors de la récupération des prédécesseurs"
@@ -4188,22 +4264,22 @@ msgid "An error occurred while fetching commits. Retry the search."
msgstr "Une erreur s'est produite lors de la récupération des commits. Réessayez la recherche."
msgid "An error occurred while fetching coverage reports."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des rapports de couverture."
msgid "An error occurred while fetching environments."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des environnements."
msgid "An error occurred while fetching exposed artifacts."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des artéfacts exposés."
msgid "An error occurred while fetching folder content."
-msgstr ""
+msgstr "Une erreur s’est produite lors de la récupération du contenu du dossier."
msgid "An error occurred while fetching issues."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des tickets."
msgid "An error occurred while fetching label colors."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des couleurs des étiquettes."
msgid "An error occurred while fetching participants"
msgstr "Une erreur s'est produite lors de la récupération des participants"
@@ -4227,7 +4303,10 @@ msgid "An error occurred while fetching tags. Retry the search."
msgstr "Une erreur s'est produite lors de la récupération des étiquettes. Réessayez la recherche."
msgid "An error occurred while fetching terraform reports."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des rapports de terraform."
+
+msgid "An error occurred while fetching the health status."
+msgstr "Une erreur s'est produite lors de la récupération de l'état de santé."
msgid "An error occurred while fetching the job log."
msgstr "Une erreur est survenue pendant la récupération du journal de la tâche."
@@ -4242,16 +4321,16 @@ msgid "An error occurred while fetching the jobs."
msgstr "Une erreur est survenue pendant la récupération des tâches."
msgid "An error occurred while fetching the latest pipeline."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération du dernier pipeline."
msgid "An error occurred while fetching the pipelines jobs."
msgstr "Une erreur s'est produite lors de la récupération des tâches des pipelines."
msgid "An error occurred while fetching the releases. Please try again."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des versions. Veuillez réessayer."
msgid "An error occurred while fetching this tab."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération de cet onglet."
msgid "An error occurred while getting files for - %{branchId}"
msgstr ""
@@ -4269,13 +4348,13 @@ msgid "An error occurred while loading a section of this page."
msgstr "Une erreur s’est produite lors du chargement d'une section de cette page."
msgid "An error occurred while loading all the files."
-msgstr ""
+msgstr "Une erreur s'est produite lors du chargement de l’ensemble des fichiers."
msgid "An error occurred while loading chart data"
msgstr "Une erreur est survenue lors du chargement des données du graphique"
msgid "An error occurred while loading code owners."
-msgstr ""
+msgstr "Une erreur s'est produite lors du chargement des propriétaires de code."
msgid "An error occurred while loading commit signatures"
msgstr "Une erreur s’est produite lors du chargement des signatures du commit"
@@ -4290,13 +4369,13 @@ msgid "An error occurred while loading filenames"
msgstr "Une erreur s’est produite lors du chargement des noms de fichiers"
msgid "An error occurred while loading group members."
-msgstr ""
+msgstr "Une erreur s’est produite lors du chargement des membres du groupe."
msgid "An error occurred while loading issues"
-msgstr ""
+msgstr "Une erreur s'est produite lors du chargement des tickets"
msgid "An error occurred while loading merge requests."
-msgstr ""
+msgstr "Une erreur s'est produite lors du chargement des demandes de fusion."
msgid "An error occurred while loading projects."
msgstr "Une erreur s’est produite lors du chargement des projets."
@@ -4311,19 +4390,19 @@ msgid "An error occurred while loading the Test Reports tab."
msgstr "Une erreur s'est produite lors du chargement de l'onglet des Rapports de Tests."
msgid "An error occurred while loading the blob controls."
-msgstr ""
+msgstr "Une erreur s'est produite lors du chargement du contrôle du BLOB (Binary large object)"
msgid "An error occurred while loading the data. Please try again."
-msgstr ""
+msgstr "Une erreur s'est produite lors du chargement des données. Veuillez réessayer."
msgid "An error occurred while loading the file"
msgstr "Une erreur s’est produite lors du chargement du fichier"
msgid "An error occurred while loading the file content."
-msgstr ""
+msgstr "Une erreur s'est produite lors du chargement du contenu du fichier."
msgid "An error occurred while loading the file."
-msgstr ""
+msgstr "Une erreur s’est produite lors du chargement du fichier."
msgid "An error occurred while loading the file. Please try again later."
msgstr "Une erreur est survenue lors de chargement du fichier. Veuillez réessayer ultérieurement."
@@ -4332,13 +4411,13 @@ msgid "An error occurred while loading the file. Please try again."
msgstr "Une erreur s'est produite lors du chargement du fichier. Veuillez réessayer."
msgid "An error occurred while loading the merge request changes."
-msgstr ""
+msgstr "Une erreur s'est produite lors du chargement des modifications de la demande de fusion."
msgid "An error occurred while loading the merge request version data."
-msgstr ""
+msgstr "Une erreur s'est produite lors du chargement des données de version de la demande de fusion."
msgid "An error occurred while loading the merge request."
-msgstr ""
+msgstr "Une erreur s'est produite lors du chargement de la demande de fusion."
msgid "An error occurred while loading the notification settings. Please try again."
msgstr "Une erreur s'est produite lors du chargement des paramètres de notification. Veuillez réessayer."
@@ -4347,7 +4426,7 @@ msgid "An error occurred while loading the pipeline."
msgstr "Une erreur s’est produite lors du chargement du pipeline."
msgid "An error occurred while loading the pipelines jobs."
-msgstr ""
+msgstr "Une erreur s'est produite lors du chargement des tâches des pipelines."
msgid "An error occurred while making the request."
msgstr "Une erreur s’est produite lors de la requête."
@@ -4356,22 +4435,22 @@ msgid "An error occurred while moving the issue."
msgstr "Une erreur est survenue lors du déplacement du ticket."
msgid "An error occurred while parsing recent searches"
-msgstr ""
+msgstr "Une erreur s'est produite lors de l'analyse des recherches récentes"
msgid "An error occurred while parsing the file."
msgstr "Une erreur s'est produite lors de l'analyse du fichier."
msgid "An error occurred while pasting text in the editor. Please try again."
-msgstr ""
+msgstr "Une erreur s'est produite lors du collage du texte dans l'éditeur. Veuillez réessayer."
msgid "An error occurred while performing this action."
msgstr "Une erreur s'est produite lors de l'exécution de cette action."
msgid "An error occurred while removing epics."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la suppression des épopées."
msgid "An error occurred while removing issues."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la suppression des tickets."
msgid "An error occurred while rendering preview broadcast message"
msgstr "Une erreur s’est produite lors de la prévisualisation de la bannière"
@@ -4380,7 +4459,7 @@ msgid "An error occurred while rendering the editor"
msgstr "Une erreur s'est produite lors de l'affichage de l'éditeur"
msgid "An error occurred while reordering issues."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la réorganisation des tickets."
msgid "An error occurred while retrieving calendar activity"
msgstr "Une erreur s’est produite lors de la récupération de l’activité du calendrier"
@@ -4402,21 +4481,18 @@ msgstr "Une erreur s'est produite lors de l'enregistrement des modifications : %
msgid "An error occurred while saving the setting"
msgid_plural "An error occurred while saving the settings"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Une erreur s'est produite lors de la sauvegarde du paramètre"
+msgstr[1] "Une erreur s'est produite lors de la sauvegarde des paramètres"
msgid "An error occurred while saving your settings. Try saving them again."
msgstr "Une erreur s'est produite lors de la sauvegarde de vos paramètres. Essayez de les sauvegarder de nouveau."
msgid "An error occurred while triggering the job."
-msgstr ""
+msgstr "Une erreur s'est produite lors du déclenchement de la tâche."
msgid "An error occurred while trying to follow this user, please try again."
msgstr "Une erreur s'est produite lors de la tentative pour suivre cet utilisateur, veuillez réessayer."
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr "Une erreur s'est produite lors de la tentative pour générer le rapport. Veuillez réessayer plus tard."
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr "Une erreur s'est produite lors de la tentative pour afficher l'éditeur de contenu. Veuillez réessayer."
@@ -4427,10 +4503,10 @@ msgid "An error occurred while trying to unfollow this user, please try again."
msgstr "Une erreur s'est produite lors de la tentative pour ne plus suivre cet utilisateur, veuillez réessayer."
msgid "An error occurred while updating approvers"
-msgstr ""
+msgstr "Une erreur s'est produite lors de la mise à jour des approbateurs"
msgid "An error occurred while updating assignees."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la mise à jour des assignés."
msgid "An error occurred while updating configuration."
msgstr "Une erreur s'est produite lors de la mise à jour de la configuration."
@@ -4448,10 +4524,10 @@ msgid "An error occurred while updating the notification settings. Please try ag
msgstr "Une erreur s'est produite lors de la mise à jour des paramètres de notification. Veuillez réessayer."
msgid "An error occurred while uploading the file. Please try again."
-msgstr ""
+msgstr "Une erreur s'est produite lors du téléversement du fichier. Veuillez réessayer."
msgid "An error occurred while validating group path"
-msgstr ""
+msgstr "Une erreur s'est produite lors de la validation du chemin du groupe"
msgid "An error occurred while validating username"
msgstr "Une erreur s’est produite lors de la validation du nom d’utilisateur"
@@ -4478,7 +4554,7 @@ msgid "An incident has been triggered in %{project_path}."
msgstr "Un incident a été déclenché dans %{project_path}."
msgid "An integer value is required for seconds"
-msgstr ""
+msgstr "Une valeur entière est requise pour les secondes"
msgid "An issue already exists"
msgstr "Un ticket existe déjà"
@@ -4490,22 +4566,22 @@ msgid "An unexpected error occurred"
msgstr "Une erreur inattendue s'est produite"
msgid "An unexpected error occurred while checking the project environment."
-msgstr ""
+msgstr "Une erreur inattendue s'est produite lors de la vérification de l'environnement du projet."
msgid "An unexpected error occurred while checking the project runners."
-msgstr ""
+msgstr "Une erreur inattendue s'est produite lors de la vérification des exécuteurs du projet."
msgid "An unexpected error occurred while communicating with the Web Terminal."
-msgstr ""
+msgstr "Une erreur inattendue s'est produite lors de la communication avec le Terminal Web."
msgid "An unexpected error occurred while loading the code quality diff."
msgstr "Une erreur inattendue s'est produite lors du chargement du diff de qualité de code."
msgid "An unexpected error occurred while starting the Web Terminal."
-msgstr ""
+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 ""
+msgstr "Une erreur inattendue s'est produite lors de l'arrêt du Terminal Web."
msgid "An unknown error occurred while loading this graph."
msgstr "Une erreur inconnue s'est produite lors du chargement de ce graphe."
@@ -4516,14 +4592,11 @@ msgstr "Une erreur inconnue s'est produite."
msgid "Analytics"
msgstr "Analyse"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
-msgstr ""
+msgstr "Analyser vos dépendances à la recherche de vulnérabilités connues."
msgid "Analyze your infrastructure as code configuration files for known vulnerabilities."
-msgstr ""
+msgstr "Analyser les fichiers de configuration de votre infrastructure en tant que code à la recherche de vulnérabilités connues."
msgid "Analyze your source code and git history for secrets."
msgstr "Analyser votre code source et historique git à la recherche de secrets."
@@ -4538,7 +4611,7 @@ msgid "Ancestors"
msgstr ""
msgid "And this registration token:"
-msgstr ""
+msgstr "Et ce jeton d’inscription :"
msgid "Anonymous"
msgstr "Anonyme"
@@ -4550,7 +4623,7 @@ msgid "Another issue tracker is already in use. Only one issue tracker service c
msgstr "Un autre outil de suivi de tickets est déjà en cours d'utilisation. Un seul peut être actif à la fois"
msgid "Another third-party wiki is already in use. Only one third-party wiki integration can be active at a time"
-msgstr ""
+msgstr "Un autre wiki tiers est déjà utilisé. Une seule intégration de wiki tiers peut être active à la fois"
msgid "Anti-spam verification"
msgstr "Vérification antiâ€pourriel"
@@ -4562,7 +4635,7 @@ msgid "Any %{header}"
msgstr ""
msgid "Any Author"
-msgstr ""
+msgstr "N'importe quel auteur"
msgid "Any Milestone"
msgstr "N'importe quel jalon"
@@ -4592,7 +4665,7 @@ msgid "Appearance"
msgstr "Apparence"
msgid "Appearance was successfully created."
-msgstr ""
+msgstr "L'apparence a été créée avec succès."
msgid "Appearance was successfully updated."
msgstr "L'apparence a bien été mise à jour."
@@ -4613,7 +4686,7 @@ msgid "Application limits saved successfully"
msgstr "Limites d'application enregistrées avec succès"
msgid "Application settings saved successfully"
-msgstr ""
+msgstr "Les paramètres de l'application ont été enregistrés avec succès"
msgid "Application settings saved successfully."
msgstr "Les paramètres de l'application ont été sauvegardés avec succès."
@@ -4621,11 +4694,8 @@ msgstr "Les paramètres de l'application ont été sauvegardés avec succès."
msgid "Application settings update failed"
msgstr "La mise à jour des paramètres de l'application a échoué"
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
-msgstr ""
+msgstr "L'application a été détruite avec succès."
msgid "Application was successfully updated."
msgstr "L'application a été mise à jour avec succès."
@@ -4642,8 +4712,8 @@ msgstr "Ajouter un lien vers Grafana"
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
-msgstr "Après que l'instance ait atteint le nombre maximal d'utilisateurs, tout utilisateur qui est ajouté ou qui demande un accès devra être approuvé par un administrateur. Laissez vide pour qu'il n'y ait pas de limite."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
+msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
msgstr "Domaines autorisés pour les inscriptions"
@@ -4685,6 +4755,9 @@ msgstr "Fichier de liste d'exclusion"
msgid "ApplicationSettings|Domain denylist"
msgstr "Liste d'exclusion de domaines"
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr "Restrictions d'adresses de courriel"
@@ -4703,9 +4776,18 @@ msgstr "Activer les restrictions d'adresses de courriel pour les inscriptions"
msgid "ApplicationSettings|Enter denylist manually"
msgstr "Entrez la liste d'exclusion manuellement"
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr "Longueur minimale du mot de passe (nombre de caractères)"
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr "Les nouveaux utilisateurs peuvent s'inscrire sans confirmer leur adresse de courriel."
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr "Seuls les utilisateurs dont les adresses de courriel correspondent à ce(s) domaine(s ) peuvent s'inscrire. Les jokers sont autorisés. Pour plusieurs entrées, utilisez des lignes séparées. Exemple : domaine.com, *.domaine.com"
@@ -4733,11 +4815,14 @@ 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 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|Send confirmation email on sign-up"
msgstr "Envoyer un courriel de confirmation lors de l'inscription"
msgid "ApplicationSettings|Sign-up enabled"
-msgstr ""
+msgstr "Inscription activée"
msgid "ApplicationSettings|Text shown after a user signs up. Markdown enabled."
msgstr "Texte affiché après l’inscription d’un utilisateur. Markdown activé."
@@ -4755,7 +4840,7 @@ msgid "ApplicationSettings|User cap"
msgstr "Plafonnement utilisateur"
msgid "ApplicationSettings|Users with e-mail addresses that match these domain(s) cannot sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
-msgstr ""
+msgstr "Les utilisateurs dont les adresses de courriel correspondent à ce(s) domaine(s) ne pourront pas s'inscrire. Les jokers sont autorisés. Pour plusieurs entrées, utilisez des lignes séparées. Exemples : domaine.com, *.domaine.com"
msgid "ApplicationSettings|Users with e-mail addresses that match these domain(s) cannot sign up. Wildcards allowed. Use separate lines or commas for multiple entries."
msgstr "Les utilisateurs dont les adresses de courriel correspondent à ce(s) domaine(s) ne peuvent pas s'inscrire. Les jokers sont autorisés. Pour plusieurs entrées, utilisez des lignes séparées ou des virgules."
@@ -4782,7 +4867,7 @@ msgid "Applied"
msgstr ""
msgid "Apply"
-msgstr ""
+msgstr "Appliquer"
msgid "Apply %d suggestion"
msgid_plural "Apply %d suggestions"
@@ -4790,7 +4875,7 @@ msgstr[0] "Appliquer %d suggestion"
msgstr[1] "Appliquer %d suggestions"
msgid "Apply a label"
-msgstr ""
+msgstr "Appliquer une étiquette"
msgid "Apply a template"
msgstr ""
@@ -4808,7 +4893,7 @@ msgid "Applying"
msgstr ""
msgid "Applying a template will replace the existing issue description. Any changes you have made will be lost."
-msgstr ""
+msgstr "L'application d'un modèle remplacera la description existante du ticket. Tout les modifications que vous avez apportées seront perdues."
msgid "Applying command"
msgstr ""
@@ -4826,7 +4911,7 @@ msgid "Applying suggestions..."
msgstr "Application des suggestions..."
msgid "Approval rules"
-msgstr ""
+msgstr "Règles d'approbation"
msgid "Approval rules reset to project defaults"
msgstr "Règles d'approbation réinitialisées aux valeurs par défaut du projet"
@@ -4836,8 +4921,8 @@ msgstr "Paramètres d'approbation"
msgid "ApprovalRuleRemove|%d member"
msgid_plural "ApprovalRuleRemove|%d members"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%d membre"
+msgstr[1] "%d membres"
msgid "ApprovalRuleRemove|You are about to remove the %{name} approver group which has %{strongStart}%{count} member%{strongEnd}. Approvals from this member are not revoked."
msgid_plural "ApprovalRuleRemove|You are about to remove the %{name} approver group which has %{strongStart}%{count} members%{strongEnd}. Approvals from these members are not revoked."
@@ -4891,7 +4976,7 @@ msgid "ApprovalRule|Learn more about merge request approval rules."
msgstr "En savoir plus sur les règles d'approbation des demandes de fusion."
msgid "ApprovalRule|Name"
-msgstr ""
+msgstr "Nom"
msgid "ApprovalRule|Newly detected"
msgstr "Récemment détectée"
@@ -4906,13 +4991,13 @@ msgid "ApprovalRule|Resolved"
msgstr "Résolue"
msgid "ApprovalRule|Rule name"
-msgstr ""
+msgstr "Nom de la règle"
msgid "ApprovalRule|Select eligible approvers by expertise or files changed."
msgstr "Sélectionnez les approbateurs éligibles par expertise ou fichiers modifiés."
msgid "ApprovalRule|Target branch"
-msgstr ""
+msgstr "Branche cible"
msgid "ApprovalRule|Try for free"
msgstr "Essayer gratuitement"
@@ -4954,7 +5039,7 @@ msgid "ApprovalSettings|There was an error updating merge request approval setti
msgstr "Une erreur s'est produite lors de la mise à jour des paramètres d'approbation des demandes de fusion."
msgid "ApprovalSettings|This setting is configured at the instance level and can only be changed by an administrator."
-msgstr ""
+msgstr "Ce paramètre est configuré au niveau de l'instance et ne peut être modifié que par un administrateur."
msgid "ApprovalSettings|This setting is configured in %{groupName} and can only be changed in the group settings by an administrator or group owner."
msgstr "Ce paramètre est configuré dans %{groupName} et ne peut être modifié dans les paramètres du groupe que par un administrateur ou par un propriétaire du groupe."
@@ -4993,10 +5078,10 @@ msgid "Approved-By"
msgstr ""
msgid "Approver"
-msgstr ""
+msgstr "Approbateur"
msgid "Approvers"
-msgstr ""
+msgstr "Approbateurs"
msgid "Approvers from private group(s) not shown"
msgstr ""
@@ -5014,13 +5099,13 @@ msgid "Archive"
msgstr ""
msgid "Archive jobs"
-msgstr ""
+msgstr "Archiver les tâches"
msgid "Archive project"
-msgstr ""
+msgstr "Archiver le projet"
msgid "Archive test case"
-msgstr ""
+msgstr "Archiver le cas de test"
msgid "Archived"
msgstr ""
@@ -5041,25 +5126,25 @@ msgid "Archiving the project makes it entirely read-only. It is hidden from the
msgstr "L'archivage du projet met celui-ci en lecture seule dans sa totalité. Il est masqué sur le tableau de bord et n'est pas affiché dans les recherches. %{strong_start}Aucun commit ne pourra y être fait, et aucun ticket, commentaire ni autre entité ne pourra être créé.%{strong_end} %{link_start}En savoir plus.%{link_end}"
msgid "Are you ABSOLUTELY SURE you wish to remove this group?"
-msgstr ""
+msgstr "Êtes-vous ABSOLUMENT sûr(e) de vouloir supprimer ce groupe ?"
msgid "Are you absolutely sure?"
-msgstr ""
+msgstr "Êtes-vous absolument sûr(e) ?"
msgid "Are you sure that you want to archive this project?"
msgstr "Êtes-vous sûr de vouloir archiver ce projet ?"
msgid "Are you sure that you want to destroy %{application}"
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir détruire %{application}"
msgid "Are you sure that you want to unarchive this project?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir désarchiver ce projet ?"
msgid "Are you sure you want to %{action} %{name}?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir %{action} %{name} ?"
msgid "Are you sure you want to approve %{user}?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir approuver %{user} ?"
msgid "Are you sure you want to attempt to merge?"
msgstr "Êtes-vous sûr de vouloir tenter la fusion ?"
@@ -5068,13 +5153,10 @@ msgid "Are you sure you want to cancel editing this %{commentType}?"
msgstr "Êtes-vous sûr de vouloir annuler la modification de ce %{commentType} ?"
msgid "Are you sure you want to close this blocked issue?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir fermer ce ticket bloqué ?"
msgid "Are you sure you want to delete %{name}?"
-msgstr ""
-
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir supprimer %{name} ?"
msgid "Are you sure you want to delete this %{commentType}?"
msgstr "Êtes-vous sûr de vouloir supprimer ce %{commentType} ?"
@@ -5089,7 +5171,7 @@ msgid "Are you sure you want to delete this deploy key?"
msgstr "Êtes-vous sûr de vouloir supprimer cette clé de déploiement ?"
msgid "Are you sure you want to delete this device? This action cannot be undone."
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir supprimer cet appareil ? Cette action ne peut pas être annulée."
msgid "Are you sure you want to delete this label?"
msgstr "Êtes-vous sûr de vouloir supprimer cette étiquette ?"
@@ -5098,13 +5180,13 @@ msgid "Are you sure you want to delete this pipeline schedule?"
msgstr "Êtesâ€vous sûr·e de vouloir supprimer ce pipeline programmé ?"
msgid "Are you sure you want to delete this pipeline? Doing so will expire all pipeline caches and delete all related objects, such as builds, logs, artifacts, and triggers. This action cannot be undone."
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir supprimer ce pipeline ? Faire ceci fera expirer tous les caches du pipeline et supprimera tous les objets associés, tels que les constructions, les journaux, les artéfacts et les déclencheurs. Cette action ne peut pas être annulée."
msgid "Are you sure you want to deploy this environment?"
-msgstr ""
+msgstr "Voulez-vous vraiment déployer sur cet environnement ?"
msgid "Are you sure you want to discard this comment?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir abandonner ce commentaire ?"
msgid "Are you sure you want to discard your changes?"
msgstr "Êtes-vous sûr(e) de vouloir abandonner vos modifications ?"
@@ -5124,19 +5206,19 @@ msgid "Are you sure you want to lose unsaved changes?"
msgstr "Êtesâ€vous vraiment prêt(e) à perdre les modifications non enregistrées ?"
msgid "Are you sure you want to lose your issue information?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir perdre les informations de votre ticket ?"
msgid "Are you sure you want to merge immediately?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir fusionner immédiatement ?"
msgid "Are you sure you want to re-deploy this environment?"
-msgstr ""
+msgstr "Voulez-vous vraiment redéployer sur cet environnement ?"
msgid "Are you sure you want to reindex?"
msgstr "Êtes-vous sûr de vouloir réindexer ?"
msgid "Are you sure you want to remove %{email}?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir supprimer %{email} ?"
msgid "Are you sure you want to remove %{group_name}?"
msgstr "Voulezâ€vous vraiment supprimer %{group_name} ?"
@@ -5160,7 +5242,7 @@ msgid "Are you sure you want to remove this list?"
msgstr "Êtes-vous sûr(e) de vouloir supprimer cette liste ?"
msgid "Are you sure you want to remove this nickname?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir supprimer ce pseudo ?"
msgid "Are you sure you want to reset the error tracking access token?"
msgstr "Êtes-vous sûr de vouloir réinitialiser le jeton d'accès du suivi des erreurs ?"
@@ -5169,7 +5251,7 @@ msgid "Are you sure you want to reset the health check token?"
msgstr "Êtesâ€vous sûr·e de vouloir réinitialiser le jeton de bilan de santé ?"
msgid "Are you sure you want to reset the registration token?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir réinitialiser le jeton d’inscription ?"
msgid "Are you sure you want to retry this migration?"
msgstr "Êtesâ€vous sûr(e) de vouloir retenter cette migration ?"
@@ -5177,8 +5259,8 @@ msgstr "Êtesâ€vous sûr(e) de vouloir retenter cette migration ?"
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr "Êtes-vous sûr de vouloir révoquer ce %{accessTokenType} ? Cette action ne peut pas être annulée."
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
-msgstr ""
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
+msgstr "Êtes-vous sûr(e) de vouloir révoquer ce jeton d'accès au groupe ? Cette action ne peut pas être annulée."
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr "Êtes-vous sûr de vouloir révoquer ce jeton d'accès personnel ? Cette action ne peut pas être annulée."
@@ -5205,10 +5287,10 @@ msgid "Are you sure?"
msgstr "Êtesâ€vous certain(e) ?"
msgid "Are you sure? All commits that were signed with this GPG key will be unverified."
-msgstr ""
+msgstr "Êtes-vous sûr(e) ? Tous les commits qui ont été signés avec cette clé GPG deviendront non vérifiés."
msgid "Are you sure? Removing this GPG key does not affect already signed commits."
-msgstr ""
+msgstr "Êtes-vous sûr(e) ? La suppression de cette clé GPG n’affecte pas les commits déjà signés."
msgid "Are you sure? The device will be signed out of GitLab and all remember me tokens revoked."
msgstr "Êtes-vous sûr(e) ? L'appareil sera déconnecté de GitLab et tous les jetons « se souvenir de moi » seront révoqués."
@@ -5217,17 +5299,41 @@ msgid "Arrange charts"
msgstr ""
msgid "Artifact"
-msgstr ""
+msgstr "Artéfact"
msgid "Artifact could not be deleted."
-msgstr ""
+msgstr "L'artéfact n'a pas pu être supprimé."
msgid "Artifact was successfully deleted."
-msgstr ""
+msgstr "L'artéfact a été supprimé avec succès."
msgid "Artifacts"
msgstr "Artéfacts"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr "Une erreur s'est produite lors de la suppression de l'artéfact"
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr "Une erreur s'est produite lors de la récupération des artéfacts de la tâche"
+
+msgid "Artifacts|Artifacts"
+msgstr "Artéfacts"
+
+msgid "Artifacts|Browse"
+msgstr "Parcourir"
+
+msgid "Artifacts|Delete %{name}?"
+msgstr "Supprimer %{name} ?"
+
+msgid "Artifacts|Delete artifact"
+msgstr "Supprimer l'artéfact"
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr "Taille totale des artéfacts"
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr "Comme nous développons toujours davantage de fonctions pour SAST, nous souhaiterions connaître votre avis sur la fonctionnalité de configuration SAST via %{linkStart}cet ticket%{linkEnd}."
@@ -5259,19 +5365,19 @@ msgid "Assertion consumer service URL"
msgstr "URL du service consommateur d’assertion"
msgid "Assets"
-msgstr ""
+msgstr "Ressources"
msgid "Assets:"
-msgstr ""
+msgstr "Ressources :"
msgid "Assign"
msgstr ""
msgid "Assign Iteration"
-msgstr ""
+msgstr "Assigner l'Itération"
msgid "Assign To"
-msgstr ""
+msgstr "Assigner à"
msgid "Assign custom color like #FF0000"
msgstr "Attribuer une couleur personnalisée comme #FF0000"
@@ -5279,14 +5385,11 @@ msgstr "Attribuer une couleur personnalisée comme #FF0000"
msgid "Assign labels"
msgstr "Attribuer des étiquettes"
-msgid "Assign milestone"
-msgstr "Attribuer un jalon"
-
msgid "Assign myself"
msgstr "Me l'attribuer"
msgid "Assign reviewer"
-msgstr ""
+msgstr "Assigner un relecteur"
msgid "Assign reviewer(s)"
msgstr ""
@@ -5295,7 +5398,7 @@ msgid "Assign severity"
msgstr "Attribuer la gravité"
msgid "Assign some issues to this milestone."
-msgstr ""
+msgstr "Attribuez des tickets à ce jalon."
msgid "Assign to"
msgstr "Assigner à"
@@ -5386,7 +5489,7 @@ msgstr[0] "Joindre un fichier"
msgstr[1] "Joindre %d fichiers"
msgid "Attaching the file failed."
-msgstr ""
+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 ""
@@ -5395,7 +5498,7 @@ msgid "Audit Events"
msgstr "Événements d’audit"
msgid "Audit events"
-msgstr ""
+msgstr "Événements d'audit"
msgid "AuditLogs|(removed)"
msgstr ""
@@ -5425,7 +5528,7 @@ msgid "AuditLogs|Log"
msgstr "Journaux"
msgid "AuditLogs|Member Events"
-msgstr ""
+msgstr "Événements des Membres"
msgid "AuditLogs|No matching %{type} found."
msgstr "Pas de %{type} qui corresponde."
@@ -5457,13 +5560,13 @@ msgid "AuditStreams|Active"
msgstr ""
msgid "AuditStreams|Add a custom header"
-msgstr ""
+msgstr "Ajouter un en-tête personnalisé"
msgid "AuditStreams|Add a custom value"
-msgstr ""
+msgstr "Ajouter une valeur personnalisée"
msgid "AuditStreams|Add an HTTP endpoint to manage audit logs in third-party systems."
-msgstr ""
+msgstr "Ajouter un point de terminaison HTTP pour gérer les journaux d'audit dans des systèmes tiers."
msgid "AuditStreams|Add another custom header"
msgstr "Ajouter un autre en-tête personnalisé"
@@ -5496,7 +5599,7 @@ msgid "AuditStreams|Custom HTTP headers (optional)"
msgstr "En-têtes HTTP personnalisés (facultatif)"
msgid "AuditStreams|Delete %{link}"
-msgstr ""
+msgstr "Supprimer %{link}"
msgid "AuditStreams|Destination URL"
msgstr "URL de destination"
@@ -5553,13 +5656,13 @@ msgid "August"
msgstr "août"
msgid "Authenticate"
-msgstr ""
+msgstr "S'authentifier"
msgid "Authenticate user SSH keys without requiring additional configuration. Performance of GitLab can be improved by using the GitLab database instead. %{link_start}How do I configure authentication using the GitLab database? %{link_end}"
msgstr ""
msgid "Authenticate with GitHub"
-msgstr ""
+msgstr "S'authentifier avec GitHub"
msgid "Authenticated API rate limit period in seconds"
msgstr "Limitation de fréquence des requêtes d'API authentifiées en secondes"
@@ -5595,7 +5698,7 @@ msgid "Authentication error: enable 2FA in your profile settings to continue usi
msgstr "Erreur d'authentification : activez l'A2F dans les paramètres de votre profil pour continuer à utiliser GitLab : %{mfa_help_page}"
msgid "Authentication failed: %{error_message}"
-msgstr ""
+msgstr "L'authentification a échoué : %{error_message}"
msgid "Authentication log"
msgstr "Journal d’authentification"
@@ -5604,10 +5707,10 @@ msgid "Authentication method"
msgstr "Méthode d’authentification"
msgid "Authentication method updated"
-msgstr ""
+msgstr "Méthode d'authentification mise à jour"
msgid "Authentication via U2F device failed."
-msgstr ""
+msgstr "L'authentification via l'appareil U2F a échoué."
msgid "Authentication via WebAuthn device failed."
msgstr "L'authentification via l'appareil WebAuthn a échoué."
@@ -5622,7 +5725,7 @@ msgid "Authored %{timeago}"
msgstr "Rédigé %{timeago}"
msgid "Authored %{timeago} by %{author}"
-msgstr ""
+msgstr "Rédigé %{timeago} par %{author}"
msgid "Authorization code:"
msgstr "Code d’autorisation :"
@@ -5670,14 +5773,11 @@ msgid "Auto DevOps enabled"
msgstr "Auto DevOps activé"
msgid "Auto stop successfully canceled."
-msgstr ""
+msgstr "Arrêt automatique annulé avec succès."
msgid "Auto-cancel redundant pipelines"
msgstr "Annulation auto des pipelines redondants"
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr "%{auto_devops_start}Automatisez la construction, le test et le déploiement%{auto_devops_end} de vos applications selon votre configuration d'intégration et de livraison continues. %{quickstart_start}Comment commencer ?%{quickstart_end}"
@@ -5700,7 +5800,7 @@ msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr "Apprenezâ€en davantage en consultant la %{link_to_documentation}"
msgid "AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found."
-msgstr ""
+msgstr "Le pipeline Auto DevOps a été activé et sera utilisé si aucun autre fichier de configuration d’intégration continue n’est trouvé."
msgid "AutoDevopsAlert|Security testing tools enabled with %{linkStart}Auto DevOps%{linkEnd}"
msgstr "Outils de test de sécurité activés avec %{linkStart}Auto DevOps%{linkEnd}"
@@ -5745,10 +5845,10 @@ msgid "Autocomplete usage hint"
msgstr ""
msgid "Automatic certificate management using %{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end}"
-msgstr ""
+msgstr "Gestion automatique des certificats à l'aide de %{lets_encrypt_link_start}Let's Encrypt%{lets_encrypt_link_end}"
msgid "Automatic certificate management using Let's Encrypt"
-msgstr ""
+msgstr "Gestion automatique des certificats à l'aide de Let's Encrypt"
msgid "Automatic deployment rollbacks"
msgstr ""
@@ -5778,7 +5878,7 @@ msgid "Available group runners: %{runners}"
msgstr "Exécuteurs de groupe disponibles : %{runners}"
msgid "Available on-demand"
-msgstr ""
+msgstr "Disponible sur demande"
msgid "Available shared runners:"
msgstr "Exécuteurs partagés disponibles :"
@@ -5811,7 +5911,7 @@ msgid "Back"
msgstr "Retour"
msgid "Back to page %{number}"
-msgstr ""
+msgstr "Retour à la page %{number}"
msgid "Background Color"
msgstr "Couleur de fond"
@@ -5820,7 +5920,7 @@ msgid "Background Jobs"
msgstr "Tâches de fond"
msgid "Background Migrations"
-msgstr ""
+msgstr "Migrations en arrière-plan"
msgid "Background color"
msgstr "Couleur d’arrièreâ€plan"
@@ -5871,10 +5971,10 @@ msgid "Badges|Deleting the badge failed, please try again."
msgstr "La suppression du badge a échoué, veuillez réessayer."
msgid "Badges|Enter a valid URL"
-msgstr ""
+msgstr "Entrez une URL valide"
msgid "Badges|Example: %{exampleUrl}"
-msgstr ""
+msgstr "Exemple : %{exampleUrl}"
msgid "Badges|Group Badge"
msgstr "Badge de groupe"
@@ -5883,10 +5983,10 @@ msgid "Badges|Link"
msgstr "Lien"
msgid "Badges|Name"
-msgstr ""
+msgstr "Nom"
msgid "Badges|New badge added."
-msgstr ""
+msgstr "Nouveau badge ajouté."
msgid "Badges|No badge image"
msgstr "Pas d’image de badge"
@@ -5955,10 +6055,10 @@ msgid "Banned"
msgstr "Banni"
msgid "Banner message"
-msgstr ""
+msgstr "Message de bannière"
msgid "Based on"
-msgstr ""
+msgstr "Basé sur"
msgid "Batch size"
msgstr ""
@@ -6036,10 +6136,16 @@ msgid "BatchedJob|Transition logs:"
msgstr ""
msgid "Be careful. Changing the project's namespace can have unintended side effects."
-msgstr ""
+msgstr "Faites attention. Modifier l'espace de noms du projet peut avoir des effets secondaires imprévus."
msgid "Be careful. Renaming a project's repository can have unintended side effects."
-msgstr ""
+msgstr "Faites attention. Renommer le dépôt d'un projet peut avoir des effets secondaires imprévus."
+
+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}."
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr "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 le gracier : %{url}."
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr "Avant d'activer cette intégration, créez un crochet web pour le salon Google Chat dans lequel vous voulez recevoir les notifications de ce projet. %{docs_link}"
@@ -6054,7 +6160,7 @@ msgid "Begin with the selected commit"
msgstr "Commencer avec le commit sélectionné"
msgid "Below are the fingerprints for the current instance SSH host keys."
-msgstr ""
+msgstr "Vous trouverez ci-dessous les empreintes des clés SSH de l’instance actuelle."
msgid "Below are the settings for %{link_to_gitlab_pages}."
msgstr "Les paramètres de %{link_to_gitlab_pages} figurent ci-après."
@@ -6066,7 +6172,7 @@ msgid "Beta"
msgstr "Bêta"
msgid "Bi-weekly code coverage"
-msgstr ""
+msgstr "Couverture de code bihebdomadaire"
msgid "Billable Users"
msgstr ""
@@ -6126,22 +6232,22 @@ msgid "BillingPlans|End of availability for the Bronze Plan"
msgstr "Fin de disponibilité pour le Forfait Bronze"
msgid "BillingPlans|Enhance team productivity and collaboration"
-msgstr ""
+msgstr "Améliorer la productivité et la collaboration de l'équipe"
msgid "BillingPlans|Enterprise agile planning"
-msgstr ""
+msgstr "Planification agile d'entreprise"
msgid "BillingPlans|Faster code reviews"
msgstr "Revues de code plus rapides"
msgid "BillingPlans|Free forever features for individual users"
-msgstr ""
+msgstr "Fonctionnalités gratuites pour toujours pour les utilisateurs individuels"
msgid "BillingPlans|Free guest users"
msgstr "Utilisateurs invités à titre gratuit"
msgid "BillingPlans|Free upgrade!"
-msgstr ""
+msgstr "Mise à niveau gratuite !"
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
msgstr ""
@@ -6156,7 +6262,7 @@ msgid "BillingPlans|Learn more about each plan by reading our %{faq_link}, or st
msgstr "Renseignez-vous sur nos forfaits en lisant notre %{faq_link} ou essayez gratuitement l’édition Ultimate sur GitLab.com pendant 30 jours."
msgid "BillingPlans|Learn more about each plan by visiting our %{pricing_page_link}."
-msgstr ""
+msgstr "En savoir plus sur chacun des forfaits en visitant notre %{pricing_page_link}."
msgid "BillingPlans|Looking to purchase or manage a subscription for your group? Navigate to your %{groups_link} and go to %{strong_open}Settings &gt; Billing.%{strong_close}"
msgstr "Vous cherchez à acheter ou gérer un abonnement pour votre groupe ? Accédez à vos %{groups_link} puis allez sur %{strong_open}Paramètres &gt; Facturation%{strong_close}"
@@ -6201,13 +6307,13 @@ msgid "BillingPlans|See all %{plan_name} features"
msgstr "Afficher toutes les caractéristiques de %{plan_name}"
msgid "BillingPlans|Self-managed reliability"
-msgstr ""
+msgstr "Fiabilité autogérée"
msgid "BillingPlans|Spans the DevOps lifecycle"
msgstr "Couvre le cycle de vie DevOps"
msgid "BillingPlans|Start a free Ultimate trial"
-msgstr ""
+msgstr "Commencer un essai Ultimate gratuit"
msgid "BillingPlans|Still have questions?"
msgstr "D'autres questions ?"
@@ -6228,10 +6334,10 @@ msgid "BillingPlans|Ultimate"
msgstr "Ultimate"
msgid "BillingPlans|Upgrade to Premium"
-msgstr ""
+msgstr "Mettre à niveau vers Premium"
msgid "BillingPlans|Upgrade to Ultimate"
-msgstr ""
+msgstr "Mettre à niveau vers Ultimate"
msgid "BillingPlans|Value stream management"
msgstr "Gestion de la chaîne de valeur"
@@ -6243,7 +6349,7 @@ msgid "BillingPlans|While GitLab is ending availability of the Bronze plan, you
msgstr "Alors que GitLab met fin à la disponibilité du forfait Bronze, il vous est toujours possible de renouveler votre abonnement Bronze une dernière fois avant %{eoa_bronze_plan_end_date}. Nous proposons également pour une durée limitée une mise à niveau gratuite vers notre forfait Premium (jusqu'à 25 utilisateurs) ! En savoir plus sur les modifications et offres sur notre %{announcement_link}."
msgid "BillingPlans|You don't have any groups. You'll need to %{create_group_link_start}create one%{create_group_link_end} and %{move_link_start}move this project to it%{move_link_end}."
-msgstr ""
+msgstr "Vous n'avez aucun groupe. Vous devrez %{create_group_link_start}en créer un%{create_group_link_end} et %{move_link_start}déplacer ce projet dedans%{move_link_end}."
msgid "BillingPlans|You'll have to %{move_link_start}move this project%{move_link_end} to one of your groups."
msgstr "Vous aurez à %{move_link_start}déplacer ce projet%{move_link_end} dans un de vos groupes."
@@ -6258,7 +6364,7 @@ msgid "BillingPlans|Your current plan"
msgstr "Votre forfait actuel"
msgid "BillingPlans|billed annually at %{price_per_year}"
-msgstr ""
+msgstr "facturé annuellement à %{price_per_year}"
msgid "BillingPlans|for the remainder of your subscription"
msgstr "pour le reste de votre abonnement"
@@ -6279,16 +6385,16 @@ msgid "BillingPlans|per user/month"
msgstr "par utilisateur/mois"
msgid "BillingPlan|Upgrade"
-msgstr ""
+msgstr "Mettre à niveau"
msgid "BillingPlan|Upgrade for free"
-msgstr ""
+msgstr "Mettre à niveau gratuitement"
msgid "Billings|%{planName} plan"
msgstr "Forfait %{planName}"
msgid "Billings|An error occurred while extending your trial."
-msgstr ""
+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."
@@ -6300,7 +6406,7 @@ msgid "Billings|By reactivating your trial, you will receive an additional 30 da
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 ""
+msgstr "Erreur lors de la validation des détails de la carte"
msgid "Billings|Extend trial"
msgstr "Prolonger l'essai"
@@ -6348,7 +6454,7 @@ msgid "Billings|Your account has been validated"
msgstr "Votre compte a été validé"
msgid "Billing|%{user} was successfully approved"
-msgstr ""
+msgstr "%{user} a été approuvé avec succès"
msgid "Billing|Add seats"
msgstr "Ajouter des sièges"
@@ -6404,7 +6510,7 @@ msgid "Billing|Members who were invited via a group invitation cannot be removed
msgstr "Les membres qui ont été invités via une invitation de groupe ne peuvent pas être supprimés. Vous pouvez soit supprimer l'ensemble du groupe, soit demander à un Propriétaire du groupe invité d'en supprimer le membre."
msgid "Billing|No users to display."
-msgstr ""
+msgstr "Aucun utilisateur à afficher."
msgid "Billing|Private"
msgstr "Privé"
@@ -6443,7 +6549,7 @@ msgid "Bitbucket Server Import"
msgstr "Importation d’un serveur Bitbucket"
msgid "Bitbucket Server import"
-msgstr ""
+msgstr "Importation d'un serveur Bitbucket"
msgid "Bitbucket import"
msgstr "Importation de Bitbucket"
@@ -6478,7 +6584,7 @@ msgid "Blocking issues"
msgstr "Tickets bloquants"
msgid "Blocks"
-msgstr ""
+msgstr "Bloque"
msgid "Blog"
msgstr "Blog"
@@ -6499,10 +6605,10 @@ msgid "BoardNewEpic|No matching results"
msgstr "Aucun résultat correspondant"
msgid "BoardNewEpic|Search groups"
-msgstr ""
+msgstr "Rechercher des groupes"
msgid "BoardNewEpic|Select a group"
-msgstr ""
+msgstr "Sélectionnez un groupe"
msgid "BoardNewIssue|No matching results"
msgstr "Aucun résultat correspondant"
@@ -6520,7 +6626,7 @@ msgid "BoardScope|%{iterationTitle} iteration in %{iterationCadence}"
msgstr "Itération %{iterationTitle} dans %{iterationCadence}"
msgid "BoardScope|An error occurred while getting iterations. Please try again."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des itérations. Veuillez réessayer."
msgid "BoardScope|An error occurred while getting milestones, please try again."
msgstr "Une erreur s'est produite lors de l'obtention des jalons, veuillez réessayer."
@@ -6538,7 +6644,7 @@ msgid "BoardScope|Any assignee"
msgstr "N'importe quel assigné"
msgid "BoardScope|Any iteration"
-msgstr ""
+msgstr "N'importe quelle itération"
msgid "BoardScope|Any label"
msgstr "N'importe quelle étiquette"
@@ -6550,7 +6656,7 @@ msgid "BoardScope|Choose labels"
msgstr "Choisir les étiquettes"
msgid "BoardScope|Current iteration"
-msgstr ""
+msgstr "Itération actuelle"
msgid "BoardScope|Don't filter milestone"
msgstr "Ne pas filtrer par jalon"
@@ -6559,7 +6665,7 @@ msgid "BoardScope|Edit"
msgstr "Modifier"
msgid "BoardScope|Iteration"
-msgstr ""
+msgstr "Itération"
msgid "BoardScope|Labels"
msgstr "Étiquettes"
@@ -6568,13 +6674,13 @@ msgid "BoardScope|Milestone"
msgstr "Jalon"
msgid "BoardScope|No iteration"
-msgstr ""
+msgstr "Aucune itération"
msgid "BoardScope|No milestone"
msgstr "Aucun jalon"
msgid "BoardScope|Search iterations"
-msgstr ""
+msgstr "Rechercher des itérations"
msgid "BoardScope|Search milestones"
msgstr "Rechercher des jalons"
@@ -6595,7 +6701,7 @@ msgid "BoardScope|Select weight"
msgstr "Sélectionnez le poids"
msgid "BoardScope|Started"
-msgstr ""
+msgstr "Commencé"
msgid "BoardScope|Upcoming"
msgstr "À venir"
@@ -6636,13 +6742,13 @@ msgid "Boards|An error occurred while fetching labels. Please reload the page."
msgstr "Une erreur s'est produite lors de la récupération des étiquettes. Veuillez recharger la page."
msgid "Boards|An error occurred while fetching the board epics. Please reload the page."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des épopées du tableau. Veuillez recharger la page."
msgid "Boards|An error occurred while fetching the board issues. Please reload the page."
msgstr "Une erreur s'est produite lors de la récupération des tickets du tableau. Veuillez recharger la page."
msgid "Boards|An error occurred while fetching the board lists. Please reload the page."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des listes de tableaux. Veuillez recharger la page."
msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
msgstr "Une erreur s'est produite lors de la récupération des lignes de séparation des tableaux. Veuillez recharger la page."
@@ -6651,7 +6757,7 @@ msgid "Boards|An error occurred while fetching the board. Please reload the page
msgstr "Une erreur s'est produite lors de la récupération du tableau. Veuillez recharger la page."
msgid "Boards|An error occurred while generating lists. Please reload the page."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la génération des listes. Veuillez recharger la page."
msgid "Boards|An error occurred while moving the epic. Please try again."
msgstr "Une erreur s'est produite lors du déplacement de l'épopée. Veuillez réessayer."
@@ -6671,13 +6777,13 @@ msgstr[0] "Blocage par %{blockedByCount} %{issuableType}"
msgstr[1] "Blocage par %{blockedByCount} %{issuableType}s"
msgid "Boards|Collapse"
-msgstr ""
+msgstr "Réduire"
msgid "Boards|Edit board"
-msgstr ""
+msgstr "Modifier le tableau"
msgid "Boards|Expand"
-msgstr ""
+msgstr "Étendre"
msgid "Boards|Failed to fetch blocking %{issuableType}s"
msgstr "Échec de la récupération des %{issuableType}s bloquant(e)s"
@@ -6704,28 +6810,28 @@ msgid "Boards|View all blocking %{issuableType}s"
msgstr ""
msgid "Boards|View scope"
-msgstr ""
+msgstr "Voir la portée"
msgid "Board|An error occurred while fetching the board, please try again."
msgstr "Une erreur s'est produite lors de la récupération du tableau, veuillez réessayer."
msgid "Board|Are you sure you want to delete this board?"
-msgstr ""
+msgstr "Êtes-vous sûr de vouloir supprimer ce tableau ?"
msgid "Board|Board scope"
msgstr "Portée du tableau"
msgid "Board|Create board"
-msgstr ""
+msgstr "Créer un tableau"
msgid "Board|Create new board"
msgstr "Créer un nouveau tableau"
msgid "Board|Delete board"
-msgstr ""
+msgstr "Supprimer le tableau"
msgid "Board|Edit board"
-msgstr ""
+msgstr "Modifier le tableau"
msgid "Board|Enter board name"
msgstr "Entrer le nom du tableau"
@@ -6737,7 +6843,7 @@ msgid "Board|Load more epics"
msgstr "Charger plus d'épopées"
msgid "Board|Load more issues"
-msgstr ""
+msgstr "Charger plus de tickets"
msgid "Board|Loading epics"
msgstr "Chargement des épopées"
@@ -6755,7 +6861,7 @@ msgid "Both project and dashboard_path are required"
msgstr "Le projet et dashboard_path sont tous deux requis"
msgid "Branch"
-msgstr ""
+msgstr "Branche"
msgid "Branch %{branchName} was not found in this project's repository."
msgstr "La branche %{branchName} n’a pas été trouvée dans le dépôt de ce projet."
@@ -6764,20 +6870,26 @@ msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab
msgstr "La branche %{branch_name} a été créée. Pour mettre en place le déploiement automatique, choisissez un modèle Yaml GitLab CI puis validez vos modifications. %{link_to_autodeploy_doc}"
msgid "Branch already exists"
-msgstr ""
+msgstr "La branche existe déjà"
msgid "Branch changed"
msgstr "Branche modifiée"
-msgid "Branch has been updated since the merge was requested."
+msgid "Branch defaults"
msgstr ""
+msgid "Branch has been updated since the merge was requested."
+msgstr "La branche a été mise à jour depuis la fusion a été demandée."
+
msgid "Branch is already taken"
msgstr "Ce nom de branche existe déjà"
msgid "Branch name"
msgstr "Nom de la branche"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6785,58 +6897,67 @@ msgid "Branch rules"
msgstr ""
msgid "BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or production/ are supported"
-msgstr ""
+msgstr "Les %{linkStart}caractères génériques%{linkEnd} tels que *-stable ou production/ sont pris en charge"
msgid "BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or production/* are supported."
msgstr "Les %{linkStart}caractères génériques%{linkEnd} tels que *-stable ou production/* sont pris en charge."
msgid "BranchRules|All branches"
-msgstr ""
+msgstr "Toutes les branches"
msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
+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}."
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr "Autorisé à fusionner"
msgid "BranchRules|Allowed to merge (%{total})"
-msgstr ""
+msgstr "Autorisé à fusionner (%{total})"
msgid "BranchRules|Allowed to push"
msgstr "Autorisé à pousser"
msgid "BranchRules|Allowed to push (%{total})"
-msgstr ""
+msgstr "Autorisé à pousser (%{total})"
msgid "BranchRules|An error occurred while fetching branches."
msgstr "Une erreur s'est produite lors de la récupération des branches."
msgid "BranchRules|Approvals"
+msgstr "Approbations"
+
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
msgid "BranchRules|Branch"
msgstr "Branche"
msgid "BranchRules|Branch name or pattern"
-msgstr ""
+msgstr "Motif ou nom de branche"
msgid "BranchRules|Branch rules details"
msgstr "Détails des règles de branche"
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr "Créer un joker : %{searchTerm}"
msgid "BranchRules|Details"
-msgstr ""
+msgstr "Détails"
msgid "BranchRules|Force push"
-msgstr ""
+msgstr "Forcer la poussée"
msgid "BranchRules|Force push is not allowed."
-msgstr ""
+msgstr "Forcer les poussées n'est pas autorisé."
msgid "BranchRules|Groups"
msgstr "Groupes"
@@ -6844,17 +6965,23 @@ msgstr "Groupes"
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr "Conservez les branches stables sécurisées et forcez les développeurs à utiliser des demandes de fusion. %{linkStart}Que sont les branches protégées ?%{linkEnd}"
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr "Gérer dans les Approbations des Demandes de Fusion"
+
msgid "BranchRules|Manage in Protected Branches"
-msgstr ""
+msgstr "Gérer dans les Branches Protégées"
+
+msgid "BranchRules|Manage in Status checks"
+msgstr "Gérer dans les vérifications d'état"
msgid "BranchRules|No data to display"
-msgstr ""
+msgstr "Aucune donnée à afficher"
msgid "BranchRules|No matching results"
msgstr "Aucun résultat correspondant"
msgid "BranchRules|Protect branch"
-msgstr ""
+msgstr "Protéger la branche"
msgid "BranchRules|Protections"
msgstr "Protections"
@@ -6865,11 +6992,20 @@ msgstr "Rejeter les poussées de code qui modifient les fichiers répertoriés d
msgid "BranchRules|Require approval from code owners."
msgstr "Nécessiter l'approbation des propriétaires du code."
+msgid "BranchRules|Required approvals (%{total})"
+msgstr "Approbations requises (%{total})"
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr "Nécessite les approbations de CODEOWNERS"
+
msgid "BranchRules|Roles"
msgstr "Rôles"
msgid "BranchRules|Status checks"
-msgstr ""
+msgstr "Vérifications d'état"
+
+msgid "BranchRules|Status checks (%{total})"
+msgstr "Vérifications d'état (%{total})"
msgid "BranchRules|Target Branch"
msgstr "Branche cible"
@@ -6908,7 +7044,7 @@ msgid "Branches|Cancel, keep branch"
msgstr "Annuler, conserver la branche"
msgid "Branches|Can’t find HEAD commit for this branch"
-msgstr ""
+msgstr "Impossible de trouver le commit HEAD de cette branche"
msgid "Branches|Compare"
msgstr "Comparer"
@@ -7030,6 +7166,9 @@ msgstr "Le message de diffusion a été mis à jour avec succès."
msgid "Broadcast Messages"
msgstr "Messages de diffusion"
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr "Une erreur s'est produite lors de la suppression de ce message, veuillez réessayer plus tard."
+
msgid "Browse Directory"
msgstr "Parcourir le dossier"
@@ -7039,9 +7178,6 @@ msgstr "Parcourir le fichier"
msgid "Browse Files"
msgstr "Parcourir les fichiers"
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr "Parcourir les fichiers"
@@ -7052,7 +7188,7 @@ msgid "Build cannot be erased"
msgstr ""
msgid "BuildArtifacts|An error occurred while fetching the artifacts"
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des artéfacts"
msgid "BuildArtifacts|Loading artifacts"
msgstr ""
@@ -7073,10 +7209,10 @@ msgid "BulkImport|%{feature} (require v%{version})"
msgstr "%{feature} (nécessite la v%{version})"
msgid "BulkImport|Destination"
-msgstr ""
+msgstr "Destination"
msgid "BulkImport|Destination group"
-msgstr ""
+msgstr "Groupe de destination"
msgid "BulkImport|Existing groups"
msgstr "Groupes existants"
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr "Les données suivantes ne seront pas migrées : %{bullets} Contactez l'administrateur système de %{host} pour mettre à jour GitLab si vous avez besoin d'inclure ces données dans votre migration"
-msgid "BulkImport|From source group"
-msgstr "Depuis le groupe source"
-
msgid "BulkImport|Group import history"
msgstr "Historique d'importation de groupe"
@@ -7120,14 +7253,17 @@ msgstr "Le nom existe déjà."
msgid "BulkImport|Name already used as a target for another group."
msgstr "Le nom est déjà utilisé comme cible pour un autre groupe."
+msgid "BulkImport|New group"
+msgstr "Nouveau groupe"
+
msgid "BulkImport|No additional information provided."
-msgstr ""
+msgstr "Aucune information supplémentaire fournie."
msgid "BulkImport|No groups found"
msgstr "Aucun groupe trouvé"
msgid "BulkImport|No history is available"
-msgstr ""
+msgstr "Aucun historique n'est disponible"
msgid "BulkImport|No parent"
msgstr "Aucun parent"
@@ -7135,8 +7271,11 @@ msgstr "Aucun parent"
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr "Seuls les groupes pour lesquels vous avez le rôle %{role} sont listés parmi ceux que vous pouvez importer."
+msgid "BulkImport|Path of the new group."
+msgstr "Chemin du nouveau groupe."
+
msgid "BulkImport|Project import history"
-msgstr ""
+msgstr "Historique d'importation de projets"
msgid "BulkImport|Re-import creates a new group. It does not sync with the existing group."
msgstr "La réimportation crée un nouveau groupe. Elle n'est pas synchronisée avec le groupe existant."
@@ -7151,16 +7290,13 @@ msgid "BulkImport|Showing %{start}-%{end} of %{total} that you own matching filt
msgstr "Affichage de %{start}-%{end} parmi les %{total} que vous possédez et qui correspondent au filtre « %{filter} » sur %{link}"
msgid "BulkImport|Source"
-msgstr ""
+msgstr "Source"
msgid "BulkImport|Source group"
msgstr "Groupe source"
msgid "BulkImport|Template / File-based import / GitLab Migration"
-msgstr ""
-
-msgid "BulkImport|To new group"
-msgstr "Vers un nouveau groupe"
+msgstr "Modèle / Importation de fichier / Migration GitLab"
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7187,10 +7323,10 @@ msgid "Bullet list"
msgstr "Liste à puces"
msgid "Burndown chart"
-msgstr ""
+msgstr "Graphique d'avancement"
msgid "BurndownChartLabel|Remaining"
-msgstr ""
+msgstr "Restants"
msgid "Burnup chart"
msgstr ""
@@ -7208,13 +7344,13 @@ msgid "Busy"
msgstr "Occupé(e)"
msgid "Buy CI Minutes"
-msgstr ""
+msgstr "Acheter des Minutes CI"
msgid "Buy Storage"
msgstr "Acheter du Stockage"
msgid "Buy more Pipeline minutes"
-msgstr ""
+msgstr "Acheter plus de minutes de Pipeline"
msgid "By %{user_name}"
msgstr "Par %{user_name}"
@@ -7259,7 +7395,7 @@ msgid "CI/CD Analytics"
msgstr ""
msgid "CI/CD Settings"
-msgstr ""
+msgstr "Paramètres CI/CD"
msgid "CI/CD configuration"
msgstr "Configuration de l’intégration et de la livraison continues"
@@ -7268,7 +7404,7 @@ msgid "CI/CD configuration file"
msgstr "Fichier de configuration CI/CD"
msgid "CI/CD limits"
-msgstr ""
+msgstr "Limites CI/CD"
msgid "CI/CD minutes"
msgstr ""
@@ -7348,13 +7484,13 @@ msgid "CICD|Default to Auto DevOps pipeline"
msgstr "Pipeline Auto DevOps par défaut"
msgid "CICD|Default to Auto DevOps pipeline for all projects"
-msgstr ""
+msgstr "Utiliser par défaut le pipeline Auto DevOps pour tout les projets"
msgid "CICD|Deployment strategy"
msgstr "Stratégie de déploiement"
msgid "CICD|Enable feature to limit job token access to the following projects."
-msgstr ""
+msgstr "Activez la fonctionnalité pour que l'accès au jeton de tâche soit limité aux projets suivants."
msgid "CICD|Jobs"
msgstr "Tâches"
@@ -7363,7 +7499,7 @@ msgid "CICD|Limit"
msgstr ""
msgid "CICD|Limit CI_JOB_TOKEN access"
-msgstr ""
+msgstr "Limiter l'accès à CI_JOB_TOKEN"
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 "Sélectionner les projets accessibles par les requêtes API authentifiées avec la variable CI/CD CI_JOB_TOKEN de ce projet. Désactiver cette fonctionnalité constitue un risque pour la sécurité, car des projets non autorisés peuvent tenter de récupérer un jeton actif et accéder à l'API. %{linkStart}En savoir plus.%{linkEnd}"
@@ -7375,16 +7511,16 @@ msgid "CICD|The Auto DevOps pipeline runs if no alternative CI configuration fil
msgstr "Le pipeline Auto DevOps s’exécute si aucun autre fichier de configuration CI n’est trouvé."
msgid "CICD|There are several CI/CD limits in place."
-msgstr ""
+msgstr "Plusieurs limites CI/CD sont définies."
msgid "CICD|Unprotected branches will not have access to the cache from protected branches."
-msgstr ""
+msgstr "Les branches non protégées n'auront pas accès au cache des branches protégées."
msgid "CICD|Use separate caches for protected branches"
msgstr "Utiliser des caches distincts pour les branches protégées"
msgid "CICD|group enabled"
-msgstr ""
+msgstr "activé sur le groupe"
msgid "CICD|instance enabled"
msgstr "instance activée"
@@ -7399,10 +7535,10 @@ msgid "CODEOWNERS rule violation"
msgstr "Violation de règle CODEOWNERS"
msgid "CONTRIBUTING"
-msgstr ""
+msgstr "CONTRIBUTING"
msgid "CPU"
-msgstr ""
+msgstr "CPU"
msgid "CSV is being generated and will be emailed to you upon completion."
msgstr "Le CSV est en cours de génération et sera envoyé par courriel une fois celle-ci terminée."
@@ -7465,7 +7601,7 @@ msgid "Can be overridden in each project."
msgstr ""
msgid "Can create groups:"
-msgstr ""
+msgstr "Peut créer des groupes :"
msgid "Can not delete primary training"
msgstr ""
@@ -7495,16 +7631,16 @@ msgid "Can't find HEAD commit for this branch"
msgstr "Impossible de trouver le dernier commit (HEAD) pour cette branche"
msgid "Can't find variable: ZiteReader"
-msgstr ""
+msgstr "Impossible de trouver la variable : ZiteReader"
msgid "Can't scan the code?"
-msgstr ""
+msgstr "Impossible de scanner le code ?"
msgid "Can't update snippet: %{err}"
msgstr "Impossible de mettre à jour l'extrait de code : %{err}"
msgid "Canary"
-msgstr ""
+msgstr "Canari"
msgid "Canary Ingress does not exist in the environment."
msgstr "Le Canari Ingress n'existe pas dans l'environnement."
@@ -7546,13 +7682,13 @@ msgid "Cancel downstream pipeline"
msgstr ""
msgid "Cancel editing"
-msgstr ""
+msgstr "Annuler l'édition"
msgid "Cancel index deletion"
msgstr "Annuler la suppression d'index"
msgid "Cancel running"
-msgstr ""
+msgstr "Annuler l'exécution"
msgid "Cancel this job"
msgstr "Annuler cette tâche"
@@ -7575,32 +7711,32 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr "Impossible d'assigner une épopée confidentielle à un ticket non confidentiel. Rendez le ticket confidentiel et réessayez"
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr "Ne peut être fusionnée automatiquement"
msgid "Cannot create the abuse report. The reported user was invalid. Please try again or contact support."
-msgstr ""
+msgstr "Impossible de créer le rapport d'abus. L'utilisateur signalé n'est pas valide. Veuillez réessayer ou contacter le support."
msgid "Cannot create the abuse report. The user has been deleted."
-msgstr ""
+msgstr "Impossible de créer le rapport d'abus. L'utilisateur a été supprimé."
msgid "Cannot create the abuse report. This user has been blocked."
-msgstr ""
+msgstr "Impossible de créer le rapport d'abus. Cet utilisateur a été bloqué."
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr "Impossible de supprimer %{profile_name} référencé dans la stratégie de sécurité"
-msgid "Cannot have multiple Jira imports running at the same time"
+msgid "Cannot delete the default framework"
msgstr ""
+msgid "Cannot have multiple Jira imports running at the same time"
+msgstr "Impossible d'exécuter plusieurs importations Jira en même temps"
+
msgid "Cannot have multiple unresolved alerts"
msgstr ""
msgid "Cannot import because issues are not available in this project."
-msgstr ""
+msgstr "Impossible d'importer car les tickets ne sont pas disponibles dans ce projet."
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"
@@ -7618,13 +7754,13 @@ msgid "Cannot modify managed Kubernetes cluster"
msgstr "Impossible de modifier la grappe de serveurs gérée par Kubernetes"
msgid "Cannot modify provider during creation"
-msgstr ""
+msgstr "Impossible de modifier le fournisseur pendant la création"
msgid "Cannot promote issue because it does not belong to a group."
msgstr ""
msgid "Cannot promote issue due to insufficient permissions."
-msgstr ""
+msgstr "Impossible de promouvoir le ticket en raison d'autorisations insuffisantes."
msgid "Cannot refer to a group milestone by an internal id!"
msgstr "Impossible de faire référence à un jalon de groupe avec un id interne !"
@@ -7684,10 +7820,10 @@ msgid "Certificate Subject"
msgstr ""
msgid "Change Failure Rate"
-msgstr ""
+msgstr "Taux d’échec des changements"
msgid "Change assignee"
-msgstr ""
+msgstr "Changer d'assigné"
msgid "Change assignee(s)"
msgstr "Changer le(s) assigné(s)"
@@ -7732,7 +7868,7 @@ msgid "Change title"
msgstr "Modifier le titre"
msgid "Change your password"
-msgstr ""
+msgstr "Modifiez votre mot de passe"
msgid "Change your password or recover your current one"
msgstr ""
@@ -7777,7 +7913,7 @@ msgid "ChangeTypeAction|Switch branch"
msgstr "Changer de branche"
msgid "ChangeTypeAction|Switch project"
-msgstr ""
+msgstr "Changer de projet"
msgid "ChangeTypeAction|This will create a new commit in order to revert the existing changes."
msgstr "Cela va créer un nouveau commit afin de défaire les modifications existantes."
@@ -7813,7 +7949,7 @@ msgid "Changes saved."
msgstr "Modifications enregistrées."
msgid "Changes suppressed. Click to show."
-msgstr ""
+msgstr "Modifications supprimées. Cliquez pour afficher."
msgid "Changes the title to \"%{title_param}\"."
msgstr ""
@@ -7834,7 +7970,7 @@ msgid "Characters over limit"
msgstr ""
msgid "Charts can't be displayed as the request for data has timed out. %{documentationLink}"
-msgstr ""
+msgstr "Les graphiques ne peuvent pas être affichés car la requête pour accéder aux données a expiré. %{documentationLink}"
msgid "Chat"
msgstr "Discussion"
@@ -7870,7 +8006,7 @@ msgid "ChatMessage|and [%{count} more](%{pipeline_failed_jobs_url})"
msgstr ""
msgid "ChatMessage|has failed"
-msgstr ""
+msgstr "a échoué"
msgid "ChatMessage|has passed"
msgstr ""
@@ -7906,7 +8042,7 @@ msgid "Check with your administrator."
msgstr "Vérifiez avec votre administrateur."
msgid "Check your Docker images for known vulnerabilities."
-msgstr ""
+msgstr "Vérifier les vulnérabilités connues de vos images Docker."
msgid "Check your Kubernetes cluster images for known vulnerabilities."
msgstr "Vérifiez les vulnérabilités connues des images de votre grappe de serveurs Kubernetes."
@@ -7921,10 +8057,10 @@ msgid "Checking branch availability..."
msgstr "Vérification de la disponibilité du nom de branche…"
msgid "Checking group path availability..."
-msgstr ""
+msgstr "Vérification de la disponibilité du chemin de groupe ..."
msgid "Checking username availability..."
-msgstr ""
+msgstr "Vérification de la disponibilité du nom d'utilisateur..."
msgid "Checkout"
msgstr ""
@@ -7936,7 +8072,7 @@ msgid "Checkout|$%{selectedPlanPrice} per pack of 1,000 minutes"
msgstr "%{selectedPlanPrice}$ par pack de 1000 minutes"
msgid "Checkout|$%{selectedPlanPrice} per user per year"
-msgstr ""
+msgstr "%{selectedPlanPrice} $ par utilisateur et par an"
msgid "Checkout|%d CI minute pack"
msgid_plural "Checkout|%d CI minute packs"
@@ -7950,7 +8086,7 @@ msgid "Checkout|%{name}'s CI minutes"
msgstr "Minutes CI de %{name}"
msgid "Checkout|%{name}'s GitLab subscription"
-msgstr ""
+msgstr "Abonnement GitLab de %{name}"
msgid "Checkout|%{name}'s storage subscription"
msgstr "Abonnement au stockage de %{name}"
@@ -7970,7 +8106,7 @@ msgid "Checkout|%{selectedPlanText} plan"
msgstr ""
msgid "Checkout|%{startDate} - %{endDate}"
-msgstr ""
+msgstr "%{startDate} - %{endDate}"
msgid "Checkout|(may be %{linkStart}charged upon purchase%{linkEnd})"
msgstr ""
@@ -7997,7 +8133,7 @@ msgid "Checkout|CI minutes"
msgstr "Minutes CI"
msgid "Checkout|Calculating your subscription..."
-msgstr ""
+msgstr "Calcul de votre abonnement..."
msgid "Checkout|Checkout"
msgstr ""
@@ -8006,7 +8142,7 @@ msgid "Checkout|City"
msgstr "Ville"
msgid "Checkout|Confirm purchase"
-msgstr ""
+msgstr "Confirmer l'achat"
msgid "Checkout|Confirming..."
msgstr "Confirmation..."
@@ -8024,13 +8160,13 @@ msgid "Checkout|Create a new group"
msgstr "Créer un nouveau groupe"
msgid "Checkout|Credit card form failed to load. Please try again."
-msgstr ""
+msgstr "Le chargement du formulaire de carte de crédit a échoué. Veuillez réessayer."
msgid "Checkout|Credit card form failed to load: %{message}"
-msgstr ""
+msgstr "Le chargement du formulaire de carte de crédit a échoué : %{message}"
msgid "Checkout|Edit"
-msgstr ""
+msgstr "Modifier"
msgid "Checkout|Enter a number greater than 0"
msgstr "Entrez un nombre supérieur à 0"
@@ -8048,7 +8184,7 @@ msgid "Checkout|Failed to load countries. Please try again."
msgstr "Impossible de charger les pays. Veuillez réessayer."
msgid "Checkout|Failed to load states. Please try again."
-msgstr ""
+msgstr "Échec du chargement des états. Veuillez réessayer."
msgid "Checkout|Failed to load the payment form. Please try again."
msgstr "Échec du chargement du formulaire de paiement. Veuillez réessayer."
@@ -8066,7 +8202,7 @@ msgid "Checkout|GitLab plan"
msgstr ""
msgid "Checkout|Group"
-msgstr ""
+msgstr "Groupe"
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."
@@ -8075,16 +8211,16 @@ msgid "Checkout|Must be %{minimumNumberOfUsers} (your seats in use, plus all ove
msgstr "Doit valoir %{minimumNumberOfUsers} (votre nombre de sièges en cours d'utilisation plus tous les membres hors limite) ou plus. Pour acheter moins de sièges, enlevez des membres du groupe."
msgid "Checkout|Name of company or organization using GitLab"
-msgstr ""
+msgstr "Nom de l'entreprise ou de l'organisation utilisant GitLab"
msgid "Checkout|Name: %{errors}"
msgstr "Nom : %{errors}"
msgid "Checkout|Need more users? Purchase GitLab for your %{company}."
-msgstr ""
+msgstr "Besoin de plus d'utilisateurs ? Achetez GitLab pour votre %{company}."
msgid "Checkout|Number of users"
-msgstr ""
+msgstr "Nombre d'utilisateurs"
msgid "Checkout|Payment method"
msgstr "Moyen de paiement"
@@ -8114,10 +8250,10 @@ msgid "Checkout|Submitting the credit card form failed with code %{errorCode}: %
msgstr "L'envoi du formulaire de la carte de crédit a échoué avec le code %{errorCode} : %{errorMessage}"
msgid "Checkout|Subscription details"
-msgstr ""
+msgstr "Détails de l'abonnement"
msgid "Checkout|Subtotal"
-msgstr ""
+msgstr "Sous-total"
msgid "Checkout|Success: subscription"
msgstr "Réussite : abonnement"
@@ -8141,7 +8277,7 @@ msgid "Checkout|You'll create your new group after checkout"
msgstr "Vous créerez votre nouveau groupe après la commande"
msgid "Checkout|Your organization"
-msgstr ""
+msgstr "Votre organisation"
msgid "Checkout|Your storage subscription has the same term as your main subscription, and the price is prorated accordingly."
msgstr "Votre abonnement au stockage possède les mêmes termes que votre abonnement principal, et le tarif est calculé au prorata en conséquence."
@@ -8156,7 +8292,7 @@ msgid "Checkout|a storage subscription"
msgstr "un abonnement au stockage"
msgid "Checkout|company or team"
-msgstr ""
+msgstr "entreprise ou équipe"
msgid "Checkout|minutes"
msgstr "minutes"
@@ -8180,10 +8316,10 @@ msgid "Child epic"
msgstr "Épopée enfant"
msgid "Child epic does not exist."
-msgstr ""
+msgstr "L'épopée enfant n'existe pas."
msgid "Child epic doesn't exist."
-msgstr ""
+msgstr "L'épopée enfant n'existe pas."
msgid "Child issues and epics"
msgstr "Épopées et tickets enfants"
@@ -8213,7 +8349,7 @@ msgid "Choose any color."
msgstr "Choisissez n’importe quelle couleur."
msgid "Choose file…"
-msgstr ""
+msgstr "Choisir un fichier…"
msgid "Choose the preferred Runner and populate the AWS CFT."
msgstr "Choisissez l'Exécuteur préféré et remplissez le CFT AWS."
@@ -8315,10 +8451,10 @@ msgid "CiStatus|running"
msgstr "en cours"
msgid "CiVariables|Cannot use Masked Variable with current value"
-msgstr ""
+msgstr "Impossible d'utiliser une Variable Masquée avec la valeur actuelle"
msgid "CiVariables|Environments"
-msgstr ""
+msgstr "Environnements"
msgid "CiVariables|Input variable key"
msgstr "Nom de la variable"
@@ -8327,13 +8463,16 @@ msgid "CiVariables|Input variable value"
msgstr "Valeur de la variable"
msgid "CiVariables|Key"
-msgstr ""
+msgstr "Clé"
msgid "CiVariables|Masked"
-msgstr ""
+msgstr "Masquée"
+
+msgid "CiVariables|Options"
+msgstr "Options"
msgid "CiVariables|Protected"
-msgstr ""
+msgstr "Protégée"
msgid "CiVariables|Remove variable"
msgstr "Supprimer la variable"
@@ -8342,22 +8481,22 @@ msgid "CiVariables|Remove variable row"
msgstr "Supprimer cette variable"
msgid "CiVariables|Scope"
-msgstr ""
+msgstr "Portée"
msgid "CiVariables|Specify variable values to be used in this run. The values specified in %{linkStart}CI/CD settings%{linkEnd} will be used as default"
-msgstr ""
+msgstr "Spécifiez des valeurs de variables à utiliser pendant cette exécution. Les valeurs spécifiées dans les %{linkStart}paramètres CI/CD%{linkEnd} seront utilisées par défaut"
msgid "CiVariables|State"
-msgstr ""
+msgstr "État"
msgid "CiVariables|Type"
msgstr "Type"
msgid "CiVariables|Value"
-msgstr ""
+msgstr "Valeur"
msgid "CiVariables|Variables"
-msgstr ""
+msgstr "Variables"
msgid "CiVariable|* (All environments)"
msgstr "* (tout environnement)"
@@ -8404,13 +8543,13 @@ msgstr[0] "Supprimer %{count} image du cache ?"
msgstr[1] "Supprimer %{count} images du cache ?"
msgid "Clear all repository checks"
-msgstr ""
+msgstr "Effacer toutes les vérifications de dépôt"
msgid "Clear chart filters"
msgstr ""
msgid "Clear due date"
-msgstr ""
+msgstr "Effacer la date d'échéance"
msgid "Clear health status"
msgstr "Effacer l'état de santé"
@@ -8419,7 +8558,7 @@ msgid "Clear recent searches"
msgstr "Effacer les recherches récentes"
msgid "Clear repository checks"
-msgstr ""
+msgstr "Effacer les vérifications du dépôt"
msgid "Clear search"
msgstr "Effacer la recherche"
@@ -8428,7 +8567,7 @@ msgid "Clear search input"
msgstr "Vider le champ de recherche"
msgid "Clear start date"
-msgstr ""
+msgstr "Effacer la date de début"
msgid "Clear templates search input"
msgstr ""
@@ -8443,19 +8582,19 @@ msgid "Clear this checkbox to use an external authentication provider instead."
msgstr "Décochez cette case pour utiliser un fournisseur d'authentification externe à la place."
msgid "Clear weight"
-msgstr ""
+msgstr "Effacer le poids"
msgid "Cleared health status."
msgstr "État de santé effacé."
msgid "Cleared weight."
-msgstr ""
+msgstr "Poids effacé."
msgid "Clears health status."
msgstr "Efface l'état de santé."
msgid "Clears weight."
-msgstr ""
+msgstr "Efface le poids."
msgid "Click %{link_start}here%{link_end} to view the request."
msgstr "Cliquez %{link_start}ici%{link_end} pour voir la requête."
@@ -8464,10 +8603,10 @@ msgid "Click %{link_to} to view the request."
msgstr "Cliquez %{link_to} pour voir la requête."
msgid "Click the link below to confirm your email address (%{email})"
-msgstr ""
+msgstr "Cliquez sur le lien ci-dessous pour confirmer votre adresse de courriel (%{email})"
msgid "Click the link below to confirm your email address."
-msgstr ""
+msgstr "Cliquez sur le lien ci-dessous pour confirmer votre adresse de courriel."
msgid "Click to expand it."
msgstr "Cliquez pour l’agrandir."
@@ -8476,10 +8615,10 @@ msgid "Click to expand text"
msgstr "Cliquez pour agrandir le texte"
msgid "Click to hide"
-msgstr ""
+msgstr "Cliquer pour masquer"
msgid "Click to reveal"
-msgstr ""
+msgstr "Cliquer pour révéler"
msgid "Client request timeout"
msgstr "Délai d'expiration des requêtes client"
@@ -8491,22 +8630,22 @@ msgid "Clientside DSN"
msgstr "DSN côté client"
msgid "Clone"
-msgstr ""
+msgstr "Cloner"
msgid "Clone repository"
msgstr "Cloner le dépôt"
msgid "Clone this issue"
-msgstr ""
+msgstr "Cloner ce ticket"
msgid "Clone with %{http_label}"
-msgstr ""
+msgstr "Cloner avec %{http_label}"
msgid "Clone with %{protocol}"
-msgstr ""
+msgstr "Cloner avec %{protocol}"
msgid "Clone with KRB5"
-msgstr ""
+msgstr "Cloner avec KRB5"
msgid "Clone with SSH"
msgstr "Cloner avec SSH"
@@ -8548,7 +8687,7 @@ msgid "Close milestone"
msgstr "Fermer le jalon"
msgid "Close sidebar"
-msgstr ""
+msgstr "Fermer la barre latérale"
msgid "Close this %{quick_action_target}"
msgstr ""
@@ -8572,7 +8711,7 @@ msgid "Closed this %{quick_action_target}."
msgstr ""
msgid "Closed: %{closed}"
-msgstr ""
+msgstr "Fermés : %{closed}"
msgid "Closes this %{quick_action_target}."
msgstr ""
@@ -8740,10 +8879,10 @@ msgid "Cluster"
msgstr ""
msgid "Cluster Health"
-msgstr ""
+msgstr "Santé de la grappe de serveurs"
msgid "Cluster cache cleared."
-msgstr ""
+msgstr "Cache de la grappe de serveurs vidé."
msgid "Cluster is required for Stages::ClusterEndpointInserter"
msgstr "Une grappe de serveurs est requise pour Stages::ClusterEndpointInserter"
@@ -8761,7 +8900,7 @@ msgid "ClusterAgents|%{name} successfully deleted"
msgstr "%{name} supprimé avec succès"
msgid "ClusterAgents|%{name} successfully revoked"
-msgstr ""
+msgstr "%{name} a été révoqué avec succès"
msgid "ClusterAgents|%{number} of %{total} agents"
msgstr "%{number} agents sur %{total}"
@@ -8800,7 +8939,7 @@ msgid "ClusterAgents|Agent %{strongStart}disconnected%{strongEnd}"
msgstr "Agent %{strongStart}déconnecté%{strongEnd}"
msgid "ClusterAgents|Agent access token:"
-msgstr ""
+msgstr "Jeton d'accès de l'agent"
msgid "ClusterAgents|Agent might not be connected to GitLab"
msgstr ""
@@ -8848,19 +8987,19 @@ msgid "ClusterAgents|Configuration"
msgstr "Configuration"
msgid "ClusterAgents|Connect a Kubernetes cluster"
-msgstr ""
+msgstr "Connecter une grappe de serveurs Kubernetes"
msgid "ClusterAgents|Connect a cluster"
-msgstr ""
+msgstr "Connecter une grappe de serveurs"
msgid "ClusterAgents|Connect a cluster (agent)"
-msgstr ""
+msgstr "Connecter une grappe de serveurs (agent)"
msgid "ClusterAgents|Connect a cluster (certificate - deprecated)"
-msgstr ""
+msgstr "Connecter une grappe de serveurs (certificat - obsolète)"
msgid "ClusterAgents|Connect a cluster (deprecated)"
-msgstr ""
+msgstr "Connecter une grappe de serveurs (obsolète)"
msgid "ClusterAgents|Connected"
msgstr "Connectés"
@@ -8869,7 +9008,7 @@ msgid "ClusterAgents|Connection status"
msgstr "État de la connexion"
msgid "ClusterAgents|Copy command"
-msgstr ""
+msgstr "Copier la commande"
msgid "ClusterAgents|Copy token"
msgstr "Copier le jeton"
@@ -8878,7 +9017,7 @@ msgid "ClusterAgents|Create a cluster"
msgstr "Créer une grappe de serveurs"
msgid "ClusterAgents|Create agent access token"
-msgstr ""
+msgstr "Créer le jeton d'accès de l'agent"
msgid "ClusterAgents|Create agent: %{searchTerm}"
msgstr ""
@@ -8893,7 +9032,7 @@ msgid "ClusterAgents|Created by %{name} %{time}"
msgstr ""
msgid "ClusterAgents|Date created"
-msgstr ""
+msgstr "Date de création"
msgid "ClusterAgents|Default configuration"
msgstr "Configuration par défaut"
@@ -8917,7 +9056,7 @@ msgid "ClusterAgents|Failed to create a token"
msgstr ""
msgid "ClusterAgents|Failed to register an agent"
-msgstr ""
+msgstr "Échec de l'enregistrement d'un agent"
msgid "ClusterAgents|From a terminal, connect to your cluster and run this command. The token is included in the command."
msgstr "Depuis un terminal, connectez-vous à votre grappe de serveurs puis exécutez cette commande. Cette dernière contient le jeton."
@@ -8959,7 +9098,7 @@ msgid "ClusterAgents|Name"
msgstr "Nom"
msgid "ClusterAgents|Never"
-msgstr ""
+msgstr "Jamais"
msgid "ClusterAgents|Never connected"
msgstr "Jamais connectés"
@@ -8970,7 +9109,7 @@ msgstr[0] "Il n'y a eu aucune activité au cours du dernier jour"
msgstr[1] "Il n'y a eu aucune activité au cours des %d derniers jours"
msgid "ClusterAgents|No agent access token"
-msgstr ""
+msgstr "Aucun jeton d'accès à l'agent"
msgid "ClusterAgents|No agents"
msgstr "Aucun agent"
@@ -9000,7 +9139,7 @@ msgid "ClusterAgents|Requires a Maintainer or greater role to perform these acti
msgstr "Nécessite un rôle Mainteneur ou supérieur pour effectuer ces actions"
msgid "ClusterAgents|Requires a Maintainer or greater role to perform this action"
-msgstr ""
+msgstr "Nécessite un Responsable ou un rôle supérieur pour effectuer cette action"
msgid "ClusterAgents|Revoke access token?"
msgstr "Révoquer le jeton d’accès ?"
@@ -9009,7 +9148,7 @@ msgid "ClusterAgents|Revoke token"
msgstr "Révoquer le jeton"
msgid "ClusterAgents|Security"
-msgstr ""
+msgstr "Sécurité"
msgid "ClusterAgents|See agent activity updates, like tokens created or revoked and clusters connected or not connected."
msgstr ""
@@ -9096,13 +9235,13 @@ msgid "ClusterIntegration|A cluster management project can be used to run deploy
msgstr "Un projet de gestion de grappe de serveurs peut être utilisé pour exécuter des tâches de déploiement avec les privilèges %{code_open}cluster-admin%{code_close} de Kubernetes."
msgid "ClusterIntegration|A service token scoped to %{code}kube-system%{end_code} with %{code}cluster-admin%{end_code} privileges."
-msgstr ""
+msgstr "Un jeton de service avec une portée définie sur %{code}kube-system%{end_code} et avec les privilèges %{code}cluster-admin%{end_code}."
msgid "ClusterIntegration|API URL"
msgstr "URL de l’API"
msgid "ClusterIntegration|API URL should be a valid http/https url."
-msgstr ""
+msgstr "L’URL de l’API doit être une URL http/https valide."
msgid "ClusterIntegration|Add Kubernetes cluster"
msgstr "Ajouter une grappe de serveurs Kubernetes"
@@ -9129,7 +9268,7 @@ msgid "ClusterIntegration|Allows GitLab to query a specifically configured in-cl
msgstr ""
msgid "ClusterIntegration|Amazon EKS"
-msgstr ""
+msgstr "Amazon EKS"
msgid "ClusterIntegration|An unknown error occurred while attempting to connect to Kubernetes."
msgstr "Une erreur inconnue s’est produite lors de la tentative de connexion à Kubernetes."
@@ -9168,7 +9307,7 @@ msgid "ClusterIntegration|Civo Kubernetes"
msgstr "Civo Kubernetes"
msgid "ClusterIntegration|Clear cluster cache"
-msgstr ""
+msgstr "Vider le cache de la grappe de serveurs"
msgid "ClusterIntegration|Clear the local cache of namespace and service accounts."
msgstr "Vider le cache local de l’espace de noms et des comptes de service."
@@ -9177,13 +9316,13 @@ msgid "ClusterIntegration|Cluster management project"
msgstr "Projet de gestion de grappe de serveurs"
msgid "ClusterIntegration|Cluster name is required."
-msgstr ""
+msgstr "Le nom de la grappe de serveurs est requis."
msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters. %{linkStart}More information%{linkEnd}"
msgstr ""
msgid "ClusterIntegration|Connect a Kubernetes cluster"
-msgstr ""
+msgstr "Connecter une grappe de serveurs Kubernetes"
msgid "ClusterIntegration|Connect your cluster to GitLab through %{linkStart}cluster certificates%{linkEnd}."
msgstr "Connectez votre grappe de serveurs à GitLab via des %{linkStart}certificats de grappes de serveurs%{linkEnd}."
@@ -9210,7 +9349,7 @@ msgid "ClusterIntegration|Did you know?"
msgstr "Le saviezâ€vous ?"
msgid "ClusterIntegration|Elastic Kubernetes Service"
-msgstr ""
+msgstr "Elastic Kubernetes Service"
msgid "ClusterIntegration|Enable Prometheus integration"
msgstr "Activer l'intégration Prometheus"
@@ -9222,7 +9361,7 @@ msgid "ClusterIntegration|Enable this setting if using role-based access control
msgstr "Activez ce paramètre si vous utilisez le contrôle d’accès basé sur les rôles (RBAC)."
msgid "ClusterIntegration|Enter details about your cluster. %{linkStart}How do I use a certificate to connect to my cluster?%{linkEnd}"
-msgstr ""
+msgstr "Entrez les détails de votre grappe de serveurs. %{linkStart}Comment puis-je utiliser un certificat pour me connecter à ma grappe de serveurs ?%{linkEnd}"
msgid "ClusterIntegration|Enter new Service Token"
msgstr "Entrez un nouveau Jeton de Service"
@@ -9240,19 +9379,19 @@ msgid "ClusterIntegration|Every new Google Cloud Platform (GCP) account receives
msgstr "Chaque nouveau compte Google Cloud Platform (GCP) reçoit un crédit de 300 US$ sur %{sign_up_link}. En partenariat avec Google, GitLab est en mesure de vous offrir 200 US$ supplémentaires, à la fois pour les nouveaux et les anciens comptes GCP, afin de vous permettre de commencer l’intégration de Google Kubernetes Engine sur GitLab."
msgid "ClusterIntegration|Failed to configure EKS provider: %{message}"
-msgstr ""
+msgstr "Échec de la configuration du fournisseur EKS : %{message}"
msgid "ClusterIntegration|Failed to configure Google Kubernetes Engine Cluster: %{message}"
-msgstr ""
+msgstr "Échec de la configuration de la grappe de serveurs Google Kubernetes Engine : %{message}"
msgid "ClusterIntegration|Failed to fetch CloudFormation stack: %{message}"
-msgstr ""
+msgstr "Échec de la récupération de la pile CloudFormation : %{message}"
msgid "ClusterIntegration|Failed to request to Google Cloud Platform: %{message}"
msgstr ""
msgid "ClusterIntegration|Failed to run Kubeclient: %{message}"
-msgstr ""
+msgstr "Échec de l'exécution de Kubeclient : %{message}"
msgid "ClusterIntegration|GitLab Integration"
msgstr "Intégration GitLab"
@@ -9267,7 +9406,7 @@ msgid "ClusterIntegration|GitLab-managed cluster"
msgstr ""
msgid "ClusterIntegration|Google GKE"
-msgstr ""
+msgstr "Google GKE"
msgid "ClusterIntegration|Google Kubernetes Engine"
msgstr "Google Kubernetes Engine"
@@ -9297,13 +9436,13 @@ msgid "ClusterIntegration|Integrations allow you to use applications installed i
msgstr ""
msgid "ClusterIntegration|Kubernetes cluster is being created..."
-msgstr ""
+msgstr "La grappe de serveurs Kubernetes est en cours de création..."
msgid "ClusterIntegration|Kubernetes cluster name"
msgstr "Nom de la grappe de serveurs Kubernetes"
msgid "ClusterIntegration|Kubernetes cluster was successfully created."
-msgstr ""
+msgstr "La grappe de serveurs Kubernetes a été créée avec succès."
msgid "ClusterIntegration|Learn more about Kubernetes."
msgstr "En savoir plus sur Kubernetes."
@@ -9312,7 +9451,7 @@ msgid "ClusterIntegration|Learn more about group Kubernetes clusters"
msgstr "En savoir plus sur les grappes de serveurs Kubernetes de groupe"
msgid "ClusterIntegration|Learn more about instance Kubernetes clusters"
-msgstr ""
+msgstr "En savoir plus sur les grappes de serveurs Kubernetes de l'instance"
msgid "ClusterIntegration|Make sure your API endpoint is correct"
msgstr "Assurez-vous que votre point de terminaison de l'API est correct"
@@ -9333,7 +9472,7 @@ msgid "ClusterIntegration|Project namespace (optional, unique)"
msgstr "Espace de noms du projet (facultatif, unique)"
msgid "ClusterIntegration|Project namespace prefix (optional, unique)"
-msgstr ""
+msgstr "Préfixe de l'espace de noms du projet (facultatif, unique)"
msgid "ClusterIntegration|Provider details"
msgstr "Détails du fournisseur"
@@ -9366,28 +9505,28 @@ msgid "ClusterIntegration|See and edit the details for your Kubernetes cluster"
msgstr "Voir et modifier les détails de votre grappe de serveurs Kubernetes"
msgid "ClusterIntegration|Service Token"
-msgstr ""
+msgstr "Jeton de Service"
msgid "ClusterIntegration|Service token is required."
-msgstr ""
+msgstr "Le jeton de service est requis."
msgid "ClusterIntegration|Set a prefix for your namespaces. If not set, defaults to your project path. If modified, existing environments will use their current namespaces until the cluster cache is cleared."
-msgstr ""
+msgstr "Définissez un préfixe pour vos espaces de noms. S'il n'est pas défini, le chemin par défaut est celui de votre projet. S'il est modifié, les environnements existants utiliseront leurs espaces de noms actuels jusqu'à ce que le cache de la grappe soit effacé."
msgid "ClusterIntegration|Something went wrong on our end."
msgstr "Un problème est survenu de notre côté."
msgid "ClusterIntegration|Something went wrong while creating your Kubernetes cluster"
-msgstr ""
+msgstr "Une erreur s’est produite lors de la création de votre grappe de serveurs Kubernetes"
msgid "ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{linkStart}Auto DevOps.%{linkEnd} The domain should have a wildcard DNS configured matching the domain. "
msgstr "Spécifier un domaine vous permettra d'utiliser les Applications de Revue Auto et les étapes de Déploiement Auto pour %{linkStart}Auto DevOps.%{linkEnd} Le domaine doit avoir un wildcard DNS configuré correspondant au domaine. "
msgid "ClusterIntegration|The Kubernetes certificate used to authenticate to the cluster."
-msgstr ""
+msgstr "Le certificat Kubernetes utilisé pour s'authentifier auprès de la grappe de serveurs."
msgid "ClusterIntegration|The URL used to access the Kubernetes API."
-msgstr ""
+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."
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."
@@ -9402,7 +9541,7 @@ msgid "ClusterIntegration|The namespace associated with your project. This will
msgstr "L’espace de noms associé à votre projet. Il sera utilisé pour déployer les tableaux de bord et les terminaux Web."
msgid "ClusterIntegration|There was a problem authenticating with your cluster. Please ensure your CA Certificate and Token are valid."
-msgstr ""
+msgstr "Une erreur s'est produite lors de l'authentification avec votre grappe de serveurs. Veuillez vous assurer que votre Certificat CA et votre Jeton sont valides."
msgid "ClusterIntegration|There was an HTTP error when connecting to your cluster."
msgstr "Une erreur HTTP s'est produite lors de la connexion à votre grappe de serveurs."
@@ -9426,7 +9565,7 @@ msgid "ClusterIntegration|To remove your integration and resources, type %{clust
msgstr ""
msgid "ClusterIntegration|To remove your integration, type %{clusterName} to confirm:"
-msgstr ""
+msgstr "Pour supprimer votre intégration, tapez %{clusterName} pour confirmer :"
msgid "ClusterIntegration|Troubleshooting tips:"
msgstr "Conseils de dépannage :"
@@ -9450,16 +9589,16 @@ msgid "ClusterIntegration|Using AutoDevOps with multiple clusters? %{help_link_s
msgstr "Utiliser AutoDevOps avec plusieurs grappes de serveurs ? %{help_link_start}Lisez d'abord ceci.%{help_link_end}"
msgid "ClusterIntegration|Where do you want to create a cluster?"
-msgstr ""
+msgstr "Où souhaitez-vous créer une grappe de serveurs ?"
msgid "ClusterIntegration|You are about to remove your cluster integration and all GitLab-created resources associated with this cluster."
msgstr ""
msgid "ClusterIntegration|You are about to remove your cluster integration."
-msgstr ""
+msgstr "Vous êtes sur le point de retirer l'intégration de votre grappe de serveurs."
msgid "ClusterIntegration|Your cluster API is unreachable. Please ensure your API URL is correct."
-msgstr ""
+msgstr "L'API de votre grappe de serveurs est inaccessible. Veuillez vous assurer que l'URL de votre API est correcte."
msgid "ClusterIntegration|sign up"
msgstr "s’inscrire"
@@ -9468,7 +9607,7 @@ msgid "Clusters|An error occurred while loading clusters"
msgstr "Une erreur s'est produite lors du chargement des grappes de serveurs"
msgid "Code"
-msgstr ""
+msgstr "Code"
msgid "Code Coverage: %{coveragePercentage}%{percentSymbol}"
msgstr "Couverture de code : %{coveragePercentage}%{percentSymbol}"
@@ -9480,22 +9619,22 @@ msgid "Code Coverage|Couldn't fetch the code coverage data"
msgstr "Impossible de récupérer les données de couverture de code"
msgid "Code Owner"
-msgstr ""
+msgstr "Propriétaire du Code"
msgid "Code Owners"
-msgstr ""
+msgstr "Propriétaires du Code"
msgid "Code Quality"
-msgstr ""
+msgstr "Qualité du code"
msgid "Code Review"
-msgstr ""
+msgstr "Revue de Code"
msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
msgstr "Les données analytiques de Revue de Code affichent un tableau des demandes de fusion ouvertes considérées comme étant en revue de code. Il n'y a actuellement aucune demande de fusion en cours de revue pour ce projet et/ou pour ces filtres."
msgid "Code block"
-msgstr ""
+msgstr "Bloc de code"
msgid "Code can be imported from enabled sources during project creation. OmniAuth must be configured for GitHub"
msgstr "Le code peut être importé depuis des sources activées pendant la création du projet. OmniAuth doit être configuré pour GitHub"
@@ -9504,13 +9643,13 @@ msgid "Code coverage statistics for %{ref} %{start_date} - %{end_date}"
msgstr "Statistiques de la couverture de code pour %{ref} de %{start_date} à %{end_date}"
msgid "Code owner approval is required"
-msgstr ""
+msgstr "L'approbation du propriétaire du code est requise"
msgid "Code owners"
msgstr "Propriétaires du code"
msgid "Code review"
-msgstr ""
+msgstr "Revue de code"
msgid "Code snippet"
msgstr "Extrait de code"
@@ -9531,16 +9670,16 @@ msgid "CodeQuality|New code quality degradations on this line"
msgstr "Nouvelles dégradations de la qualité de code sur cette ligne"
msgid "Cohorts|Inactive users"
-msgstr ""
+msgstr "Utilisateurs inactifs"
msgid "Cohorts|Month %{month_index}"
-msgstr ""
+msgstr "Mois %{month_index}"
msgid "Cohorts|New users"
msgstr "Nouveaux utilisateurs"
msgid "Cohorts|Registration month"
-msgstr ""
+msgstr "Mois d'inscription"
msgid "Cohorts|Returning users"
msgstr ""
@@ -9555,13 +9694,13 @@ msgid "Collapse all threads"
msgstr "Réduire tous les fils de conversation"
msgid "Collapse approvers"
-msgstr ""
+msgstr "Réduire les approbateurs"
msgid "Collapse issues"
msgstr "Réduire les tickets"
msgid "Collapse jobs"
-msgstr ""
+msgstr "Réduire les tâches"
msgid "Collapse merge details"
msgstr "Réduire les détails de fusion"
@@ -9582,7 +9721,7 @@ msgid "Collapses this file (only for you) until it’s changed again."
msgstr "Replier ce fichier (pour vous uniquement) jusqu'à ce qu'il soit de nouveau modifié."
msgid "Collector hostname"
-msgstr ""
+msgstr "Nom d'hôte du collecteur"
msgid "Color"
msgstr "Couleur"
@@ -9603,13 +9742,13 @@ msgid "Colorize messages"
msgstr ""
msgid "ComboSearch is not defined"
-msgstr ""
+msgstr "ComboSearch n'est pas défini"
msgid "Comma-separated list of email addresses."
msgstr "Liste d'adresses de courriel, séparées par des virgules."
msgid "Command"
-msgstr ""
+msgstr "Commande"
msgid "Command line instructions"
msgstr ""
@@ -9647,11 +9786,17 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr "Commenter/Répondre (en citant le texte sélectionné)"
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
-msgstr "Mettre des commentaires sur des fichiers qui remplacent, ou sont remplacés par des liens symboliques n'est pas pris en charge."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
-msgstr "Mettre des commentaires sur des liens symboliques qui remplacent, ou sont remplacés par des fichiers n'est pas pris en charge."
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
+msgstr ""
msgid "Comments"
msgstr "Commentaires"
@@ -9683,7 +9828,7 @@ msgid "Commit message"
msgstr "Message de commit"
msgid "Commit message (optional)"
-msgstr ""
+msgstr "Message de validation (facultatif)"
msgid "Commit statistics for %{ref} %{start_time} - %{end_time}"
msgstr "Statistiques des commits pour %{ref} de %{start_time} à %{end_time}"
@@ -9743,7 +9888,7 @@ msgid "Company"
msgstr "Entreprise"
msgid "Company Name"
-msgstr ""
+msgstr "Nom de l'entreprise"
msgid "Compare"
msgstr "Comparer"
@@ -9764,7 +9909,7 @@ msgid "Compare branches and continue"
msgstr "Comparer les branches et continuer"
msgid "Compare changes"
-msgstr ""
+msgstr "Comparer les modifications"
msgid "Compare changes with the last commit"
msgstr "Comparer les changements avec le dernier commit"
@@ -9776,7 +9921,7 @@ msgid "Compare submodule commit revisions"
msgstr "Comparer les révisions des commits de sous-modules"
msgid "Compare with previous version"
-msgstr ""
+msgstr "Comparer avec la version précédente"
msgid "CompareBranches|%{source_branch} and %{target_branch} are the same."
msgstr "%{source_branch} et %{target_branch} sont identiques."
@@ -9832,8 +9977,11 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr "Terminez la vérification pour vous inscrire."
+msgid "Complete with errors"
+msgstr "Terminé avec des erreurs"
+
msgid "Completed"
-msgstr ""
+msgstr "Terminés"
msgid "Completed in %{duration_seconds} seconds (%{relative_time})"
msgstr "Terminé en %{duration_seconds} secondes (%{relative_time})"
@@ -9902,7 +10050,7 @@ msgid "ComplianceFrameworks|No compliance frameworks are set up yet"
msgstr ""
msgid "ComplianceFrameworks|Required format: %{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}. %{linkStart}What is a compliance pipeline configuration?%{linkEnd}"
-msgstr ""
+msgstr "Format requis : %{codeStart}chemin/fichier.y[a]ml@nom-groupe/nom-projet%{codeEnd}. %{linkStart}Qu'est-ce-qu'une configuration de pipeline conforme ?%{linkEnd}"
msgid "ComplianceFrameworks|Unable to save this compliance framework. Please try again"
msgstr "Impossible d'enregistrer ce cadre de conformité. Veuillez réessayer"
@@ -9959,7 +10107,7 @@ msgid "Confidentiality"
msgstr "Confidentialité"
msgid "Configuration"
-msgstr ""
+msgstr "Configuration"
msgid "Configuration help"
msgstr ""
@@ -9995,7 +10143,7 @@ msgid "Configure GitLab"
msgstr "Configurer GitLab"
msgid "Configure GitLab runners to start using the Web Terminal. %{helpStart}Learn more.%{helpEnd}"
-msgstr ""
+msgstr "Configurer les exécuteurs de GitLab pour commencer à utiliser le Terminal Web. %{helpStart}En savoir plus.%{helpEnd}"
msgid "Configure Gitaly timeouts."
msgstr "Configurer les délais d’expiration de Gitaly."
@@ -10004,7 +10152,7 @@ msgid "Configure Integrations"
msgstr "Configurer les intégrations"
msgid "Configure Prometheus"
-msgstr ""
+msgstr "Configurer Prometheus"
msgid "Configure SAST IaC in `.gitlab-ci.yml` using the GitLab managed template. You can [add variable overrides](https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings) to customize SAST IaC settings."
msgstr "Paramétrez SAST pour IaC dans `.gitlab-ci.yml` en utilisant le modèle géré de GitLab. Vous pouvez [modifier des variables](https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings) pour personnaliser les paramètres SAST pour IaC."
@@ -10034,10 +10182,10 @@ msgid "Configure advanced permissions, Large File Storage, two-factor authentica
msgstr "Configurer les autorisations avancées, le Stockage de Fichiers Volumineux (LFS), les paramètres d'authentification à deux facteurs et de CI/CD."
msgid "Configure advanced permissions, Large File Storage, two-factor authentication, and customer relations settings."
-msgstr ""
+msgstr "Configurez les autorisations avancées, le stockage de fichiers volumineux, l'authentification à deux facteurs et les paramètres de relation client."
msgid "Configure existing installation"
-msgstr ""
+msgstr "Configurer l'installation existante"
msgid "Configure pipeline"
msgstr "Configurer le pipeline"
@@ -10046,16 +10194,16 @@ msgid "Configure pipelines to deploy web apps, backend services, APIs and static
msgstr ""
msgid "Configure region"
-msgstr ""
+msgstr "Configurer la région"
msgid "Configure region for environment"
msgstr ""
msgid "Configure regions"
-msgstr ""
+msgstr "Configurer les régions"
msgid "Configure repository mirroring."
-msgstr ""
+msgstr "Configurez la mise en miroir du dépôt."
msgid "Configure repository storage."
msgstr "Configurer le stockage du dépôt."
@@ -10082,7 +10230,7 @@ msgid "Configure the way a user creates a new account."
msgstr "Configurez la manière dont une personne crée un nouveau compte."
msgid "Configure via Merge Request"
-msgstr ""
+msgstr "Configurer via une Demande de Fusion"
msgid "Configure which lists are shown for anyone who visits this board"
msgstr "Configurer les listes qui sont affichées pour toute personne visitant ce tableau"
@@ -10091,7 +10239,7 @@ msgid "Configure with a merge request"
msgstr "Configurer avec une demande de fusion"
msgid "Configure your environments to be deployed to specific geographical regions"
-msgstr ""
+msgstr "Configurez vos environnements à déployer dans des régions géographiques spécifiques"
msgid "Confirm"
msgstr ""
@@ -10103,7 +10251,7 @@ msgid "Confirm destroy application"
msgstr ""
msgid "Confirm new password"
-msgstr ""
+msgstr "Confirmez le nouveau mot de passe"
msgid "Confirm user"
msgstr ""
@@ -10115,37 +10263,37 @@ msgid "Confirm your email address"
msgstr ""
msgid "Confirmation email sent to %{email}"
-msgstr ""
+msgstr "Courriel de confirmation envoyé à %{email}"
msgid "Confirmation required"
-msgstr ""
+msgstr "Confirmation requise"
msgid "Confirmed at:"
-msgstr ""
+msgstr "Confirmé le :"
msgid "Confirmed:"
msgstr ""
msgid "Conflict: This file was added both in the source and target branches, but with different contents."
-msgstr ""
+msgstr "Conflit : Ce fichier a été ajouté à la fois dans les branches source et cible, mais avec différents contenus."
msgid "Conflict: This file was modified in both the source and target branches."
-msgstr ""
+msgstr "Conflit : Ce fichier a été modifié dans les branches source et cible."
msgid "Conflict: This file was modified in the source branch, but removed in the target branch."
-msgstr ""
+msgstr "Conflit : Ce fichier a été modifié dans la branche source, mais supprimé dans la branche cible."
msgid "Conflict: This file was removed in the source branch, but modified in the target branch."
-msgstr ""
+msgstr "Conflit : Ce fichier a été supprimé dans la branche source, mais modifié dans la branche cible."
msgid "Conflict: This file was removed in the source branch, but renamed in the target branch."
-msgstr ""
+msgstr "Conflit : Ce fichier a été supprimé dans la branche source, mais renommé dans la branche cible."
msgid "Conflict: This file was renamed differently in the source and target branches."
-msgstr ""
+msgstr "Conflit : Ce fichier a été renommé différemment dans les branches source et cible."
msgid "Conflict: This file was renamed in the source branch, but removed in the target branch."
-msgstr ""
+msgstr "Conflit : Ce fichier a été renommé dans la branche source, mais supprimé dans la branche cible."
msgid "Confluence"
msgstr "Confluence"
@@ -10172,10 +10320,10 @@ msgid "Connect"
msgstr "Connecter"
msgid "Connect a Kubernetes Cluster"
-msgstr ""
+msgstr "Connecter une grappe de serveurs Kubernetes"
msgid "Connect a cluster"
-msgstr ""
+msgstr "Connecter une grappe de serveurs"
msgid "Connect all repositories"
msgstr "Connecter tous les dépôts"
@@ -10193,19 +10341,19 @@ msgid "Connecting"
msgstr ""
msgid "Connecting to terminal sync service"
-msgstr ""
+msgstr "Connexion au service de synchronisation du terminal"
msgid "Connecting..."
msgstr "Connexion en cours…"
msgid "Connection failed"
-msgstr ""
+msgstr "La connexion a échoué"
msgid "Connection failure"
-msgstr ""
+msgstr "Échec de connexion"
msgid "Connection timed out"
-msgstr ""
+msgstr "La connexion a expiré"
msgid "Consistency guarantee method"
msgstr ""
@@ -10220,19 +10368,19 @@ msgid "Container Registry"
msgstr "Registre de conteneur"
msgid "Container Repository"
-msgstr ""
+msgstr "Dépôt de Conteneurs"
msgid "Container Scanning"
-msgstr ""
+msgstr "Analyse de Conteneurs"
msgid "Container must be a project or a group."
msgstr "Le conteneur doit être un projet ou un groupe."
msgid "Container registry images"
-msgstr ""
+msgstr "Images du registre de conteneurs"
msgid "Container registry is not enabled on this GitLab instance. Ask an administrator to enable it in order for Auto DevOps to work."
-msgstr ""
+msgstr "Le registre de conteneur n'est pas activé sur cette instance GitLab. Demandez à un administrateur de l'activer afin que Auto DevOps puisse fonctionner."
msgid "Container repositories"
msgstr "Dépôts de conteneurs"
@@ -10263,7 +10411,7 @@ msgid "ContainerRegistry|%{title} was successfully scheduled for deletion"
msgstr "La suppression de %{title} a été planifiée avec succès"
msgid "ContainerRegistry|-- tags"
-msgstr ""
+msgstr "-- étiquettes"
msgid "ContainerRegistry|Build an image"
msgstr "Construire une image"
@@ -10314,16 +10462,16 @@ msgid "ContainerRegistry|Configuration digest: %{digest}"
msgstr "Code de hachage de configuration : %{digest}"
msgid "ContainerRegistry|Container Registry"
-msgstr ""
+msgstr "Registre de Conteneurs"
msgid "ContainerRegistry|Copy build command"
-msgstr ""
+msgstr "Copier la commande de construction"
msgid "ContainerRegistry|Copy image path"
msgstr "Copier le chemin de l'image"
msgid "ContainerRegistry|Copy login command"
-msgstr ""
+msgstr "Copier la commande de connexion"
msgid "ContainerRegistry|Copy push command"
msgstr ""
@@ -10344,7 +10492,7 @@ msgid "ContainerRegistry|Digest: %{imageId}"
msgstr "Code de hachage : %{imageId}"
msgid "ContainerRegistry|Docker connection error"
-msgstr ""
+msgstr "Erreur de connexion Docker"
msgid "ContainerRegistry|Edit cleanup rules"
msgstr "Modifier les règles de nettoyage"
@@ -10395,7 +10543,7 @@ msgid "ContainerRegistry|Last updated %{time}"
msgstr "Dernière mise à jour %{time}"
msgid "ContainerRegistry|Login"
-msgstr ""
+msgstr "Connexion"
msgid "ContainerRegistry|Manifest digest: %{digest}"
msgstr "Code de hachage de manifeste : %{digest}"
@@ -10541,10 +10689,10 @@ msgid "ContainerRegistry|The value of this input should be less than 256 charact
msgstr "La valeur de cette entrée doit contenir moins de 256 caractères"
msgid "ContainerRegistry|There are no container images available in this group"
-msgstr ""
+msgstr "Aucune image de conteneur n'est disponible dans ce groupe"
msgid "ContainerRegistry|There are no container images stored for this project"
-msgstr ""
+msgstr "Il n'y a aucune image de conteneur enregistrée pour ce projet"
msgid "ContainerRegistry|There was an error during the deletion of this image repository, please try again."
msgstr "Une erreur s'est produite lors de la suppression de ce dépôt d'images, veuillez réessayer."
@@ -10571,7 +10719,7 @@ msgid "ContainerRegistry|We are having trouble connecting to the Container Regis
msgstr "Nous rencontrons des difficultés pour nous connecter au Registre de Conteneur. Veuillez essayer de rafraîchir la page. Si cette erreur persiste, veuillez consulter %{docLinkStart}la documentation de dépannage%{docLinkEnd}."
msgid "ContainerRegistry|With the Container Registry, every project can have its own space to store its Docker images. %{docLinkStart}More Information%{docLinkEnd}"
-msgstr ""
+msgstr "Avec le Registre de Conteneurs, chaque projet peut avoir son propre espace pour stocker ses images Docker. %{docLinkStart}En savoir plus%{docLinkEnd}"
msgid "ContainerRegistry|With the Container Registry, every project can have its own space to store its Docker images. Push at least one Docker image in one of this group's projects in order to show up here. %{docLinkStart}More Information%{docLinkEnd}"
msgstr ""
@@ -10586,7 +10734,7 @@ msgid "ContainerRegistry|You are about to remove repository %{title}. Once you c
msgstr "Vous êtes sur le point de supprimer le dépôt %{title}. Une fois confirmé, ce dépôt sera définitivement supprimé."
msgid "ContainerRegistry|You can add an image to this registry with the following commands:"
-msgstr ""
+msgstr "Vous pouvez ajouter une image à ce registre avec les commandes suivantes :"
msgid "Content parsed with %{link}."
msgstr "Contenu analysé avec %{link}."
@@ -10595,7 +10743,7 @@ msgid "ContentEditor|You have to provide a renderMarkdown function or a custom s
msgstr "Vous devez fournir une fonction renderMarkdown ou un sérialiseur personnalisé"
msgid "Contents of .gitlab-ci.yml"
-msgstr ""
+msgstr "Contenu de .gitlab-ci.yml"
msgid "ContextCommits|Failed to create context commits. Please try again."
msgstr ""
@@ -10610,7 +10758,7 @@ msgid "Continue"
msgstr "Continuer"
msgid "Continue editing"
-msgstr ""
+msgstr "Poursuivre l'édition"
msgid "Continue to the next step"
msgstr "Passer à l’étape suivante"
@@ -10627,11 +10775,11 @@ msgstr "Contribution"
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
-msgstr "%{created_count} créé(e)s, %{closed_count} fermé(e)s."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
+msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
-msgstr "%{created_count} créé(e)s, %{merged_count} fusionné(e)s, %{closed_count} fermé(e)s."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
+msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -10663,9 +10811,18 @@ msgstr "Aucune demande de fusion pour la période sélectionnée."
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr "Aucune poussée pour la période sélectionnée."
-msgid "Contributions for %{calendar_date}"
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
msgstr ""
+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"
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr "Il y a trop de données à calculer. Essayez de diminuer le paramètre period_limit dans le fichier de configuration insights."
+
+msgid "Contributions for %{calendar_date}"
+msgstr "Contributions du %{calendar_date}"
+
msgid "Contributions per group member"
msgstr "Contributions par membre du groupe"
@@ -10676,7 +10833,7 @@ msgid "Contributors"
msgstr "Contributeurs"
msgid "Control emails linked to your account"
-msgstr ""
+msgstr "Contrôler les courriels liés à votre compte"
msgid "Control how the CI_JOB_TOKEN CI/CD variable is used for API access between projects."
msgstr "Contrôler la façon dont est utilisée la variable CI/CD CI_JOB_TOKEN CI/CD pour l'accès de l'API entre les projets."
@@ -10688,7 +10845,7 @@ msgid "Control whether to display customer experience improvement content and th
msgstr ""
msgid "Cookie domain"
-msgstr ""
+msgstr "Domaine des cookies"
msgid "Copied"
msgstr ""
@@ -10697,13 +10854,13 @@ msgid "Copied labels and milestone from %{source_issuable_reference}."
msgstr ""
msgid "Copy"
-msgstr ""
+msgstr "Copier"
msgid "Copy %{accessTokenType}"
msgstr ""
msgid "Copy %{http_label} clone URL"
-msgstr ""
+msgstr "Copier l’URL %{http_label} de clonage"
msgid "Copy %{name}"
msgstr "Copier %{name}"
@@ -10711,47 +10868,44 @@ msgstr "Copier %{name}"
msgid "Copy %{protocol} clone URL"
msgstr "Copier l’URL %{protocol} de clonage"
-msgid "Copy %{type}"
-msgstr "Copier %{type}"
-
msgid "Copy ID"
-msgstr ""
+msgstr "Copier l'ID"
msgid "Copy KRB5 clone URL"
-msgstr ""
+msgstr "Copier l'URL KRB5 de clonage"
msgid "Copy SSH clone URL"
msgstr "Copier l’URL SSH de clonage"
msgid "Copy SSH public key"
-msgstr ""
+msgstr "Copier la clé publique SSH"
msgid "Copy URL"
-msgstr ""
+msgstr "Copier l'URL"
msgid "Copy audio URL"
msgstr "Copier l'URL de l'audio"
msgid "Copy branch name"
-msgstr ""
+msgstr "Copier le nom de la branche"
msgid "Copy code"
-msgstr ""
+msgstr "Copier le code"
msgid "Copy codes"
msgstr "Copier les codes"
msgid "Copy command"
-msgstr ""
+msgstr "Copier la commande"
msgid "Copy commands"
-msgstr ""
+msgstr "Copier les commandes"
msgid "Copy commit SHA"
msgstr ""
msgid "Copy environment"
-msgstr ""
+msgstr "Copier l'environnement"
msgid "Copy evidence SHA"
msgstr ""
@@ -10760,10 +10914,10 @@ msgid "Copy failed. Please manually copy the value."
msgstr "La copie a échoué. Veuillez copier la valeur manuellement."
msgid "Copy file contents"
-msgstr ""
+msgstr "Copier le contenu du fichier"
msgid "Copy file path"
-msgstr ""
+msgstr "Copier le chemin du fichier"
msgid "Copy image URL"
msgstr "Copier l'URL de l'image"
@@ -10772,7 +10926,7 @@ msgid "Copy issue URL to clipboard"
msgstr "Copier l'URL du ticket dans le presse-papiers"
msgid "Copy key"
-msgstr ""
+msgstr "Copier la clé"
msgid "Copy labels and milestone from %{source_issuable_reference}."
msgstr ""
@@ -10784,37 +10938,34 @@ msgid "Copy link"
msgstr "Copier le lien"
msgid "Copy link URL"
-msgstr ""
+msgstr "Copier l'URL du lien"
msgid "Copy link to chart"
-msgstr ""
+msgstr "Copier le lien du graphique"
msgid "Copy reference"
msgstr "Copier la référence"
msgid "Copy secret"
-msgstr ""
+msgstr "Copier le secret"
msgid "Copy source branch name"
msgstr "Copier le nom de la branche source"
-msgid "Copy the code below to implement tracking in your application:"
-msgstr "Copiez le code ci-dessous pour implémenter le suivi dans votre application :"
-
msgid "Copy this registration token."
-msgstr ""
+msgstr "Copiez ce jeton d'inscription."
msgid "Copy to clipboard"
msgstr "Copier dans le presse-papier"
msgid "Copy token"
-msgstr ""
+msgstr "Copier le jeton"
msgid "Copy trigger token"
-msgstr ""
+msgstr "Copier le jeton de déclenchement"
msgid "Copy value"
-msgstr ""
+msgstr "Copier la valeur"
msgid "Copy video URL"
msgstr "Copier l'URL de la vidéo"
@@ -10835,7 +10986,7 @@ msgid "CorpusManagement|Corpus file"
msgstr "Fichier de corpus"
msgid "CorpusManagement|Corpus files are used in coverage-guided fuzz testing as seed inputs to improve testing."
-msgstr ""
+msgstr "Les fichiers de corpus sont utilisés en tant que source d'entrée dans les tests à données aléatoires guidés par la couverture pour améliorer les tests."
msgid "CorpusManagement|Corpus files must be in *.zip format. Maximum 5 GB"
msgstr "Les fichiers de corpus doivent être au format *.zip. 5 Go maximum"
@@ -10865,7 +11016,7 @@ msgid "CorpusManagement|Latest Job:"
msgstr "Dernière Tâche :"
msgid "CorpusManagement|Manage your fuzz testing corpus files"
-msgstr ""
+msgstr "Gérez vos fichiers de corpus pour les tests à données aléatoires"
msgid "CorpusManagement|New corpus"
msgstr "Nouveau corpus"
@@ -10886,7 +11037,7 @@ msgid "CorpusManagement|Total Size: %{totalSize}"
msgstr "Taille Totale : %{totalSize}"
msgid "Could not add admins as members"
-msgstr ""
+msgstr "Impossible d'ajouter des administrateurs en tant que membres"
msgid "Could not apply %{name} command."
msgstr ""
@@ -10895,16 +11046,16 @@ msgid "Could not apply %{name} command. %{message}."
msgstr "Impossible d'appliquer la commande %{name} . %{message}."
msgid "Could not authorize chat nickname. Try again!"
-msgstr ""
+msgstr "Impossible d'autoriser le pseudo de discussion. Réessayez !"
msgid "Could not change HEAD: branch '%{branch}' does not exist"
-msgstr ""
+msgstr "Impossible de modifier le HEAD : la branche « %{branch} » n'existe pas"
msgid "Could not commit. An unexpected error occurred."
msgstr "Impossible de valider. Une erreur inattendue s'est produite."
msgid "Could not connect to FogBugz, check your URL"
-msgstr ""
+msgstr "Impossible de se connecter à FogBugz, vérifiez votre URL"
msgid "Could not connect to Sentry. Refresh the page to try again."
msgstr "Impossible de se connecter à Sentry. Actualisez la page pour réessayer."
@@ -10913,25 +11064,25 @@ msgid "Could not connect to Web IDE file mirror service."
msgstr ""
msgid "Could not create Wiki Repository at this time. Please try again later."
-msgstr ""
+msgstr "Impossible de créer le Dépôt du Wiki pour le moment. Veuillez réessayer plus tard."
msgid "Could not create environment"
-msgstr ""
+msgstr "Impossible de créer l'environnement"
msgid "Could not create group"
-msgstr ""
+msgstr "Impossible de créer le groupe"
msgid "Could not create issue"
msgstr "Impossible de créer le ticket"
msgid "Could not create project"
-msgstr ""
+msgstr "Impossible de créer le projet"
msgid "Could not create wiki page"
msgstr "Impossible de créer la page wiki"
msgid "Could not delete chat nickname %{chat_name}."
-msgstr ""
+msgstr "Impossible de supprimer le pseudo de discussion %{chat_name}."
msgid "Could not delete wiki page"
msgstr "Impossible de supprimer la page wiki"
@@ -10940,10 +11091,10 @@ msgid "Could not draw the lines for job relationships"
msgstr ""
msgid "Could not fetch policy because existing policy YAML is invalid"
-msgstr ""
+msgstr "Impossible de récupérer la stratégie car le YAML de la stratégie existante n'est pas valide"
msgid "Could not fetch training providers. Please refresh the page, or try again later."
-msgstr ""
+msgstr "Impossible de récupérer les fournisseurs de formation. Veuillez actualiser la page ou réessayer plus tard."
msgid "Could not find design."
msgstr "Impossible de trouver le design."
@@ -10952,10 +11103,10 @@ msgid "Could not find iteration"
msgstr "Itération introuvable"
msgid "Could not get the data properly"
-msgstr ""
+msgstr "Impossible d'obtenir les données correctement"
msgid "Could not load the user chart. Please refresh the page to try again."
-msgstr ""
+msgstr "Impossible de charger le graphique utilisateur. Veuillez actualiser la page pour réessayer."
msgid "Could not load usage counts. Please refresh the page to try again."
msgstr "Impossible de charger les compteurs d'utilisation. Veuillez actualiser la page pour réessayer."
@@ -10963,26 +11114,23 @@ msgstr "Impossible de charger les compteurs d'utilisation. Veuillez actualiser l
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr "Impossible de supprimer %{user} de %{group}. Il n'est pas possible de supprimer le dernier propriétaire du groupe."
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
-msgstr ""
+msgstr "Impossible de supprimer le déclencheur."
msgid "Could not restore the group"
-msgstr ""
+msgstr "Impossible de restaurer le groupe"
msgid "Could not revoke access token %{access_token_name}."
msgstr "Impossible de révoquer le jeton d'accès %{access_token_name}."
msgid "Could not revoke impersonation token %{token_name}."
-msgstr ""
+msgstr "Impossible de révoquer le jeton d'emprunt d'identité %{token_name}."
msgid "Could not revoke personal access token %{personal_access_token_name}."
-msgstr ""
+msgstr "Impossible de révoquer le jeton d'accès personnel %{personal_access_token_name}."
msgid "Could not save configuration. Please refresh the page, or try again later."
-msgstr ""
+msgstr "Impossible d'enregistrer la configuration. Veuillez actualiser la page ou réessayer plus tard."
msgid "Could not save group ID"
msgstr ""
@@ -10991,7 +11139,7 @@ msgid "Could not save project ID"
msgstr ""
msgid "Could not save prometheus manual configuration"
-msgstr ""
+msgstr "Impossible d'enregistrer la configuration manuelle de Prometheus"
msgid "Could not update the LDAP settings"
msgstr "Impossible de mettre à jour les paramètres LDAP"
@@ -11012,7 +11160,7 @@ msgid "Counts reflect children you may not have access to."
msgstr ""
msgid "Coverage"
-msgstr ""
+msgstr "Couverture"
msgid "Coverage Fuzzing"
msgstr "Tests à données aléatoires guidés par la couverture de code"
@@ -11036,16 +11184,16 @@ msgid "Create New Directory"
msgstr "Créer un nouveau dossier"
msgid "Create New Domain"
-msgstr ""
+msgstr "Créer un Nouveau Domaine"
msgid "Create a GitLab account first, and then connect it to your %{label} account."
-msgstr ""
+msgstr "Créez d'abord un compte GitLab, puis connectez-le à votre compte %{label}."
msgid "Create a Kubernetes cluster"
msgstr "Créer une grappe de serveurs Kubernetes"
msgid "Create a Mattermost team for this group"
-msgstr ""
+msgstr "Créer une équipe Mattermost pour ce groupe"
msgid "Create a cluster"
msgstr "Créer une grappe de serveurs"
@@ -11054,7 +11202,7 @@ msgid "Create a group"
msgstr "Créer un groupe"
msgid "Create a merge request"
-msgstr ""
+msgstr "Créer une demande de fusion"
msgid "Create a new %{codeStart}.gitlab-ci.yml%{codeEnd} file at the root of the repository to get started."
msgstr "Créez un nouveau fichier %{codeStart}.gitlab-ci.yml%{codeEnd} à la racine du dépôt pour commencer."
@@ -11063,7 +11211,7 @@ msgid "Create a new branch"
msgstr "Créer une nouvelle branche"
msgid "Create a new file as there are no files yet. Afterwards, you'll be able to commit your changes."
-msgstr ""
+msgstr "Créez un nouveau fichier car il n'y a pas encore de fichier. Ensuite, vous pourrez valider vos modifications."
msgid "Create a new issue"
msgstr "Créer un nouveau ticket"
@@ -11072,7 +11220,7 @@ msgid "Create a new project"
msgstr "Créer un nouveau projet"
msgid "Create a new repository"
-msgstr ""
+msgstr "Créer un nouveau dépôt"
msgid "Create a personal access token on your account to pull or push via %{protocol}."
msgstr "Créer un jeton d’accès personnel pour votre compte afin de récupérer ou pousser par %{protocol}."
@@ -11096,13 +11244,13 @@ msgid "Create commit"
msgstr "Créer un commit"
msgid "Create commit..."
-msgstr ""
+msgstr "Créer un commit..."
msgid "Create common files more quickly, and standardize their format."
msgstr ""
msgid "Create confidential merge request"
-msgstr ""
+msgstr "Créer une demande de fusion confidentielle"
msgid "Create confidential merge request and branch"
msgstr ""
@@ -11123,7 +11271,7 @@ msgid "Create file"
msgstr "Créer un fichier"
msgid "Create from"
-msgstr ""
+msgstr "Créer à partir de"
msgid "Create group"
msgstr "Créer un groupe"
@@ -11144,7 +11292,7 @@ msgid "Create label"
msgstr "Créer une étiquette"
msgid "Create list"
-msgstr ""
+msgstr "Créer une liste"
msgid "Create lists from labels. Issues with that label appear in that list."
msgstr "Créer des listes à partir d’étiquettes. Les tickets avec l’étiquette sélectionnée apparaissent dans cette liste."
@@ -11162,7 +11310,7 @@ msgid "Create new"
msgstr "Créer un nouveau"
msgid "Create new %{name} by email"
-msgstr ""
+msgstr "Création de %{name} par courriel"
msgid "Create new Value Stream"
msgstr "Créer de nouvelles Chaînes de Valeur"
@@ -11185,14 +11333,11 @@ msgstr "Créer un nouveau fichier ou répertoire"
msgid "Create new label"
msgstr "Créer une nouvelle étiquette"
-msgid "Create new project"
-msgstr "Créer un nouveau projet"
-
msgid "Create new..."
msgstr "Créer un nouveau…"
msgid "Create one"
-msgstr ""
+msgstr "Créez-en un"
msgid "Create or close an issue."
msgstr "Créer ou fermer un ticket."
@@ -11207,22 +11352,22 @@ msgid "Create project label"
msgstr "Créer une étiquette de projet"
msgid "Create release"
-msgstr ""
+msgstr "Créer une version"
msgid "Create requirement"
msgstr "Créer une exigence"
msgid "Create service account"
-msgstr ""
+msgstr "Créer un compte de service"
msgid "Create snippet"
msgstr "Créer un extrait de code"
msgid "Create tag %{tagName}"
-msgstr ""
+msgstr "Créer l'étiquette %{tagName}"
msgid "Create topic"
-msgstr ""
+msgstr "Créer le sujet"
msgid "Create user"
msgstr "Créer un utilisateur"
@@ -11249,10 +11394,10 @@ msgid "CreateGitTag|Set tag message"
msgstr "Définir le message de l’étiquette"
msgid "CreateGroup|You don’t have permission to create a subgroup in this group."
-msgstr ""
+msgstr "Vous n'avez pas la permission de créer un sous-groupe dans ce groupe."
msgid "CreateGroup|You don’t have permission to create groups."
-msgstr ""
+msgstr "Vous n'avez pas la permission de créer des groupes."
msgid "CreateTag|Tag"
msgstr "Étiquette"
@@ -11282,7 +11427,7 @@ msgid "CreateValueStreamForm|Create from default template"
msgstr "Créer à partir du modèle par défaut"
msgid "CreateValueStreamForm|Create from no template"
-msgstr ""
+msgstr "Créer à partir d'aucun modèle"
msgid "CreateValueStreamForm|Create new Value Stream"
msgstr "Créer une nouvelle Chaîne de Valeur"
@@ -11441,7 +11586,7 @@ msgid "Created on:"
msgstr "Créé le :"
msgid "Creates a branch and a merge request to resolve this issue."
-msgstr ""
+msgstr "Crée une branche et une demande de fusion pour résoudre ce ticket."
msgid "Creates branch '%{branch_name}' and a merge request to resolve this issue."
msgstr ""
@@ -11455,14 +11600,11 @@ msgstr "Création de l’épopée en cours"
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr "Créateur"
msgid "Credentials"
-msgstr ""
+msgstr "Identifiants"
msgid "CredentialsInventory|GPG Keys"
msgstr "Clés GPG"
@@ -11473,8 +11615,8 @@ msgstr "Aucun identifiant trouvé"
msgid "CredentialsInventory|Personal Access Tokens"
msgstr "Jetons d'Accès Personnels"
-msgid "CredentialsInventory|Project Access Tokens"
-msgstr "Jetons d'accès au projet"
+msgid "CredentialsInventory|Project and Group Access Tokens"
+msgstr "Jetons d'accès au groupe et au projet"
msgid "CredentialsInventory|SSH Keys"
msgstr "Clés SSH"
@@ -11495,16 +11637,16 @@ msgid "Crm|Contact"
msgstr "Contact"
msgid "Crm|Contact has been added."
-msgstr ""
+msgstr "Le contact a été ajouté."
msgid "Crm|Contact has been updated."
-msgstr ""
+msgstr "Le contact a été mis à jour."
msgid "Crm|Customer relations contacts"
-msgstr ""
+msgstr "Contacts de la Relation Client"
msgid "Crm|Customer relations organizations"
-msgstr ""
+msgstr "Entreprises de Relation Client"
msgid "Crm|Default rate"
msgstr ""
@@ -11513,31 +11655,31 @@ msgid "Crm|Edit contact"
msgstr "Modifier le contact"
msgid "Crm|Edit organization"
-msgstr ""
+msgstr "Modifier l'organisation"
msgid "Crm|New contact"
-msgstr ""
+msgstr "Nouveau contact"
msgid "Crm|New organization"
msgstr "Nouvelle organisation"
msgid "Crm|No contacts found"
-msgstr ""
+msgstr "Aucun contact trouvé"
msgid "Crm|No organization"
-msgstr ""
+msgstr "Aucune organisation"
msgid "Crm|No organizations found"
-msgstr ""
+msgstr "Aucune organisation trouvée"
msgid "Crm|Organization"
-msgstr ""
+msgstr "Organisation"
msgid "Crm|Organization has been added."
-msgstr ""
+msgstr "L'organisation a été ajoutée."
msgid "Crm|Organization has been updated."
-msgstr ""
+msgstr "L'organisation a été mise à jour."
msgid "Cron Timezone"
msgstr "Fuseau horaire des tâches planifiées cron"
@@ -11573,16 +11715,13 @@ msgid "Current Branch"
msgstr "Branche actuelle"
msgid "Current Project"
-msgstr ""
-
-msgid "Current forks will keep their visibility level."
-msgstr "Les forks actuels conserveront leur niveau de visibilité."
+msgstr "Projet actuel"
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr "Le nœud actuel doit être le nœud principal sinon vous vous verrouillerez vous-même"
msgid "Current password"
-msgstr ""
+msgstr "Mot de passe actuel"
msgid "Current sign-in IP:"
msgstr "IP de connexion actuelle :"
@@ -11609,10 +11748,10 @@ msgid "CurrentUser|Preferences"
msgstr "Préférences"
msgid "CurrentUser|Start an Ultimate trial"
-msgstr ""
+msgstr "Commencer un essai Ultimate"
msgid "Currently unable to fetch data for this pipeline."
-msgstr ""
+msgstr "Impossible actuellement de récupérer les données pour ce pipeline."
msgid "Custom (%{language})"
msgstr ""
@@ -11621,7 +11760,7 @@ msgid "Custom Attributes"
msgstr ""
msgid "Custom Git clone URL for HTTP(S)"
-msgstr ""
+msgstr "URL de clonage Git personnalisée pour HTTP(S)"
msgid "Custom analyzers: language support"
msgstr ""
@@ -11642,10 +11781,10 @@ msgid "Custom project templates"
msgstr "Modèles de projets personnalisés"
msgid "Custom project templates have not been set up for groups that you are a member of. They are enabled from a group’s settings page. Contact your group’s Owner or Maintainer to setup custom project templates."
-msgstr ""
+msgstr "Aucun modèle de projet personnalisé n'a été configuré pour les groupes dont vous êtes membre. Ils sont activés à partir de la page des paramètres d'un groupe. Contactez le propriétaire ou le responsable de votre groupe pour configurer des modèles de projet personnalisés."
msgid "Custom range"
-msgstr ""
+msgstr "Plage personnalisée"
msgid "Custom range (UTC)"
msgstr "Plage personnalisée (UTC)"
@@ -11657,10 +11796,10 @@ msgid "Customer relations"
msgstr "Relation Client"
msgid "Customer relations contacts"
-msgstr ""
+msgstr "Contacts de la Relation Client"
msgid "Customer relations organizations"
-msgstr ""
+msgstr "Entreprises de Relation Client"
msgid "Customize CI/CD settings, including Auto DevOps, shared runners, and job artifacts."
msgstr "Personnalisez les paramètres CI/CD, dont les exécuteurs partagés, les artéfacts des tâches et Auto DevOps."
@@ -11681,10 +11820,10 @@ msgid "Customize name"
msgstr ""
msgid "Customize your pipeline configuration."
-msgstr ""
+msgstr "Personnalisez la configuration de vos pipelines."
msgid "Cycle Time"
-msgstr ""
+msgstr "Temps de cycle"
msgid "CycleAnalyticsEvent|%{label_reference} label was added to the issue"
msgstr "L'étiquette %{label_reference} a été ajoutée au ticket"
@@ -11699,10 +11838,10 @@ msgid "CycleAnalyticsEvent|%{label_reference} label was removed from the merge r
msgstr "L'étiquette %{label_reference} a été supprimée de la demande de fusion"
msgid "CycleAnalyticsEvent|Issue closed"
-msgstr ""
+msgstr "Ticket fermé"
msgid "CycleAnalyticsEvent|Issue created"
-msgstr ""
+msgstr "Un ticket est créé"
msgid "CycleAnalyticsEvent|Issue first added to a board"
msgstr ""
@@ -11711,10 +11850,10 @@ 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 ""
+msgstr "Un ticket est associé pour la première fois à un jalon ou ajouté dans un tableau"
msgid "CycleAnalyticsEvent|Issue first mentioned in a commit"
-msgstr ""
+msgstr "Un ticket est mentionné pour la première fois dans une validation"
msgid "CycleAnalyticsEvent|Issue label was added"
msgstr "L'étiquette de ticket a été ajoutée"
@@ -11726,7 +11865,7 @@ msgid "CycleAnalyticsEvent|Issue last edited"
msgstr ""
msgid "CycleAnalyticsEvent|Merge request closed"
-msgstr ""
+msgstr "Demande de fusion fermée"
msgid "CycleAnalyticsEvent|Merge request created"
msgstr "Demande de fusion créée"
@@ -11735,7 +11874,7 @@ msgid "CycleAnalyticsEvent|Merge request first commit time"
msgstr "Date du premier commit de la demande de fusion"
msgid "CycleAnalyticsEvent|Merge request first deployed to production"
-msgstr ""
+msgstr "Demande de fusion déployée en production pour la première fois"
msgid "CycleAnalyticsEvent|Merge request label was added"
msgstr ""
@@ -11753,7 +11892,7 @@ msgid "CycleAnalyticsEvent|Merge request last edited"
msgstr ""
msgid "CycleAnalyticsEvent|Merge request merged"
-msgstr ""
+msgstr "Demande de fusion fusionnée"
msgid "CycleAnalyticsStage|Code"
msgstr "Code"
@@ -11777,7 +11916,7 @@ msgid "CycleAnalyticsStage|Total"
msgstr "Total"
msgid "CycleAnalyticsStage|is not available for the selected group"
-msgstr ""
+msgstr "n'est pas disponible pour le groupe sélectionné"
msgid "CycleAnalyticsStage|should be under a group"
msgstr ""
@@ -11807,7 +11946,7 @@ msgid "CycleAnalytics|Custom value streams to measure your DevSecOps lifecycle"
msgstr ""
msgid "CycleAnalytics|Data is collecting and loading."
-msgstr ""
+msgstr "Les données sont en cours de collecte et de chargement."
msgid "CycleAnalytics|Date"
msgstr "Date"
@@ -11816,13 +11955,13 @@ msgid "CycleAnalytics|Display chart filters"
msgstr ""
msgid "CycleAnalytics|If you have recently upgraded to GitLab Premium, it can take up to 30 minutes for data to collect and display."
-msgstr ""
+msgstr "Si vous avez récemment mis à niveau vers GitLab Premium, cela peut prendre jusqu'à 30 minutes pour que les données soient collectées et affichées."
msgid "CycleAnalytics|Lead Time for Changes"
msgstr "Délai de mise à disposition pour les Modifications"
msgid "CycleAnalytics|Number of tasks"
-msgstr ""
+msgstr "Nombre de tâches"
msgid "CycleAnalytics|Only %{maxLabels} labels can be selected at this time"
msgstr ""
@@ -11890,7 +12029,7 @@ msgid "DAST profiles"
msgstr "Profils DAST"
msgid "DNS"
-msgstr ""
+msgstr "DNS"
msgid "DORA4Metrics|%{startDate} - %{endDate}"
msgstr "%{startDate} - %{endDate}"
@@ -11904,6 +12043,9 @@ msgstr "Taux d’échec des changements"
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr "Taux d’échec des changements (pourcentage)"
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr "Métriques DORA du groupe %{groupName}"
+
msgid "DORA4Metrics|Date"
msgstr "Date"
@@ -11931,6 +12073,9 @@ msgstr "Durée médiane (%{days} derniers jours)"
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr "Durée médiane d'ouverture d'un incident dans un environnement de production au cours de la période donnée."
+msgid "DORA4Metrics|Month to date"
+msgstr "Mois en cours"
+
msgid "DORA4Metrics|No incidents during this period"
msgstr "Aucun incident au cours de cette période"
@@ -11977,7 +12122,7 @@ msgid "Dashboard"
msgstr "Tableau de bord"
msgid "Dashboard uid not found"
-msgstr ""
+msgstr "L'uid du tableau de bord est introuvable"
msgid "DashboardProjects|All"
msgstr "Tous"
@@ -11988,8 +12133,11 @@ msgstr "Personnels"
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr "Tableaux de bord"
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
-msgstr ""
+msgstr "%{firstProject} et %{secondProject}"
msgid "Dashboard|%{firstProject}, %{rest}, and %{secondProject}"
msgstr ""
@@ -12010,7 +12158,7 @@ msgid "DastConfig|Enabled"
msgstr "Activé"
msgid "DastConfig|Generate code snippet"
-msgstr ""
+msgstr "Générer un extrait de code"
msgid "DastConfig|Last scan triggered %{runTimeAgo} in pipeline "
msgstr "Dernière analyse déclenchée %{runTimeAgo} dans le pipeline "
@@ -12031,7 +12179,7 @@ msgid "DastProfiles|A site profile defines the attributes and configuration deta
msgstr "Un profil de site définit les informations sur les attributs et la configuration de vos API, applications et sites Web déployés. %{linkStart}En savoir plus%{linkEnd}."
msgid "DastProfiles|AJAX spider"
-msgstr ""
+msgstr "Araignée AJAX"
msgid "DastProfiles|API"
msgstr "API"
@@ -12040,7 +12188,7 @@ msgid "DastProfiles|API endpoint URL"
msgstr "URL du point de terminaison de l'API"
msgid "DastProfiles|Active"
-msgstr ""
+msgstr "Active"
msgid "DastProfiles|Additional request headers (optional)"
msgstr "En-têtes de requête supplémentaires (facultatif)"
@@ -12190,7 +12338,7 @@ msgid "DastProfiles|Not Validated"
msgstr "Non validé"
msgid "DastProfiles|Passive"
-msgstr ""
+msgstr "Passive"
msgid "DastProfiles|Password"
msgstr "Mot de passe"
@@ -12222,6 +12370,9 @@ msgstr "Enregistrez dans des profils les configurations couramment utilisées po
msgid "DastProfiles|Save profile"
msgstr "Enregistrer le profil"
+msgid "DastProfiles|Scan Method"
+msgstr "Méthode d'Analyse"
+
msgid "DastProfiles|Scan method"
msgstr "Méthode d'analyse"
@@ -12268,7 +12419,7 @@ msgid "DastProfiles|Site type"
msgstr "Type de site"
msgid "DastProfiles|Spider timeout"
-msgstr ""
+msgstr "Délai d'attente de l'araignée"
msgid "DastProfiles|Submit button"
msgstr ""
@@ -12298,7 +12449,7 @@ msgid "DastProfiles|This site profile is currently being used by a policy. To ma
msgstr "Ce profil de site est actuellement utilisé par une stratégie. Pour effectuer des modifications, vous devez le supprimer de la stratégie active."
msgid "DastProfiles|Turn on AJAX spider"
-msgstr ""
+msgstr "Activer l'araignée AJAX"
msgid "DastProfiles|URL"
msgstr "URL"
@@ -12343,7 +12494,7 @@ msgid "DastSiteValidation|Copy HTTP header to clipboard"
msgstr "Copier l'en-tête HTTP dans le presse-papiers"
msgid "DastSiteValidation|Copy Meta tag to clipboard"
-msgstr ""
+msgstr "Copier la balise Meta dans le presse-papiers"
msgid "DastSiteValidation|Could not create validation token. Please try again."
msgstr "Impossible de créer le jeton de validation. Veuillez réessayer."
@@ -12432,7 +12583,7 @@ msgid "DastSiteValidation|You will not be able to run active scans against %{url
msgstr "Vous ne serez pas en mesure d’exécuter des analyses actives à destination de %{url}."
msgid "Data is still calculating..."
-msgstr ""
+msgstr "Les données sont toujours en cours de calcul..."
msgid "Data refresh"
msgstr ""
@@ -12440,56 +12591,59 @@ msgstr ""
msgid "Data type"
msgstr "Type de données"
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr "La base de données « %{database_name} » utilise PostgreSQL %{pg_version_current} mais cette version de GitLab nécessite PostgreSQL %{pg_version_minimum}. Veuillez mettre à jour votre environnement vers une version de PostgreSQL prise en charge, voir %{pg_requirements_url} pour plus de détails."
+
msgid "Database update failed"
msgstr "La mise à jour de la base de données a échoué"
msgid "DatadogIntegration|%{linkOpen}API key%{linkClose} used for authentication with Datadog."
-msgstr ""
+msgstr "%{linkOpen}Clé d'API%{linkClose} utilisée pour l'authentification avec Datadog."
msgid "DatadogIntegration|(Advanced) The full URL for your Datadog site."
-msgstr ""
+msgstr "(Avancé) L'URL complète pour votre site Datadog."
msgid "DatadogIntegration|API URL"
-msgstr ""
+msgstr "URL de l’API"
msgid "DatadogIntegration|Custom tags in Datadog. Enter one tag per line in the %{codeOpen}key:value%{codeClose} format. %{linkOpen}How do I use tags?%{linkClose}"
msgstr "Étiquettes personnalisées dans Datadog. Entrez une étiquette par ligne au format %{codeOpen}clé:valeur%{codeClose}. %{linkOpen}Comment utiliser les étiquettes ?%{linkClose}"
msgid "DatadogIntegration|Environment"
-msgstr ""
+msgstr "Environnement"
msgid "DatadogIntegration|For self-managed deployments, set the %{codeOpen}env%{codeClose} tag for all the data sent to Datadog. %{linkOpen}How do I use tags?%{linkClose}"
-msgstr ""
+msgstr "Pour les déploiements auto-gérés, définissez l'étiquette %{codeOpen}env%{codeClose} pour toutes les données envoyées à Datadog. %{linkOpen}Comment puis-je utiliser les étiquettes ?%{linkClose}"
msgid "DatadogIntegration|How do I set up this integration?"
-msgstr ""
+msgstr "Comment puis-je configurer cette intégration ?"
msgid "DatadogIntegration|Send CI/CD pipeline information to Datadog to monitor for job failures and troubleshoot performance issues. %{docs_link}"
-msgstr ""
+msgstr "Envoyer les informations de pipeline CI/CD à Datadog afin de surveiller les échecs des tâches et résoudre les problèmes de performances. %{docs_link}"
msgid "DatadogIntegration|Service"
-msgstr ""
+msgstr "Service"
msgid "DatadogIntegration|Tag all data from this GitLab instance in Datadog. Useful when managing several self-managed deployments."
-msgstr ""
+msgstr "Étiqueter toutes les données de cette instance GitLab dans Datadog. Utile lors de la gestion de plusieurs déploiements auto-gérés."
msgid "DatadogIntegration|Tags"
msgstr "Étiquettes"
msgid "DatadogIntegration|The Datadog site to send data to. To send data to the EU site, use %{codeOpen}datadoghq.eu%{codeClose}."
-msgstr ""
+msgstr "Le site Datadog auquel envoyer les données. Pour envoyer des données au site européen, utilisez %{codeOpen}datadoghq.eu%{codeClose}."
msgid "DatadogIntegration|Trace your GitLab pipelines with Datadog."
-msgstr ""
+msgstr "Tracer vos pipelines GitLab avec Datadog."
msgid "DatadogIntegration|have an invalid format"
msgstr ""
msgid "Datasource name not found"
-msgstr ""
+msgstr "Nom de la source de données introuvable"
msgid "Date"
-msgstr ""
+msgstr "Date"
msgid "Date merged"
msgstr ""
@@ -12501,7 +12655,7 @@ msgid "Date range limited to %{number} days"
msgstr "La plage de dates est limitée à %{number} jours"
msgid "Date range must be shorter than %{max_range} days."
-msgstr ""
+msgstr "La plage de dates doit être inférieure à %{max_range} jours."
msgid "Date to enact enforcement on newly created namespaces"
msgstr "Date de mise en application sur les espaces de noms nouvellement créés"
@@ -12510,13 +12664,13 @@ msgid "DateRange|%{start_date}–%{end_date}"
msgstr "%{start_date}–%{end_date}"
msgid "Day of month"
-msgstr ""
+msgstr "Jour du mois"
msgid "DayTitle|F"
-msgstr ""
+msgstr "V"
msgid "DayTitle|M"
-msgstr ""
+msgstr "L"
msgid "DayTitle|S"
msgstr ""
@@ -12525,7 +12679,10 @@ msgid "DayTitle|W"
msgstr ""
msgid "Days"
-msgstr ""
+msgstr "Jours"
+
+msgid "Days of inactivity before deactivation"
+msgstr "Jours d'inactivité avant désactivation"
msgid "Days to merge"
msgstr ""
@@ -12560,35 +12717,38 @@ msgstr "La validation de la taille de l'archive décompressée a échoué."
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr "Par défaut - Ne jamais exécuter"
+
msgid "Default CI/CD configuration file"
msgstr "Fichier de configuration CI/CD par défaut"
msgid "Default artifacts expiration"
-msgstr ""
+msgstr "Expiration par défaut des artéfacts"
msgid "Default branch"
-msgstr ""
+msgstr "Branche par défaut"
msgid "Default branch and protected branches"
-msgstr ""
+msgstr "Branche par défaut et branches protégées"
msgid "Default description template for issues"
-msgstr ""
+msgstr "Modèle de description par défaut pour les tickets"
msgid "Default description template for merge requests"
-msgstr ""
+msgstr "Modèle de description par défaut pour les demandes de fusion"
msgid "Default first day of the week"
msgstr "Premier jour de la semaine par défaut"
msgid "Default first day of the week in calendars and date pickers."
-msgstr ""
+msgstr "Le premier jour de la semaine par défaut dans les calendriers et les sélecteurs de date."
msgid "Default projects limit"
msgstr ""
msgid "Default timeout"
-msgstr ""
+msgstr "Délai d'expiration par défaut"
msgid "Default: Map a FogBugz account ID to a full name"
msgstr "Par défaut : associer un identifiant de compte FogBugz à un nom complet"
@@ -12633,7 +12793,7 @@ msgid "Define environments in the deploy stage(s) in %{code_open}.gitlab-ci.yml%
msgstr ""
msgid "Define how approval rules are applied to merge requests."
-msgstr ""
+msgstr "Définir comment les règles d'approbation sont appliquées aux demandes de fusion."
msgid "Define rules for who can push, merge, and the required approvals for each branch."
msgstr ""
@@ -12671,11 +12831,14 @@ msgstr "Supprimer"
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr "Supprimer %{name}"
msgid "Delete Comment"
-msgstr ""
+msgstr "Supprimer le commentaire"
msgid "Delete File"
msgstr "Supprimer le fichier"
@@ -12692,9 +12855,6 @@ msgstr "Supprimer les Chaînes de Valeur"
msgid "Delete account"
msgstr "Supprimer le compte"
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr "Supprimer la ressource"
@@ -12702,10 +12862,10 @@ msgid "Delete audio"
msgstr "Supprimer l'audio"
msgid "Delete badge"
-msgstr ""
+msgstr "Supprimer le badge"
msgid "Delete code block"
-msgstr ""
+msgstr "Supprimer le bloc de code"
msgid "Delete column"
msgstr "Supprimer la colonne"
@@ -12761,14 +12921,14 @@ msgstr "Supprimer la version %{release} ?"
msgid "Delete row"
msgstr "Supprimer la ligne"
-msgid "Delete self monitoring project"
-msgstr ""
+msgid "Delete self-monitoring project"
+msgstr "Supprimer le projet d'autosurveillance"
msgid "Delete snippet"
-msgstr ""
+msgstr "Supprimer l’extrait"
msgid "Delete snippet?"
-msgstr ""
+msgstr "Supprimer l’extrait ?"
msgid "Delete source branch"
msgstr ""
@@ -12792,10 +12952,10 @@ msgid "Delete this project"
msgstr "Supprimer ce projet"
msgid "Delete user list"
-msgstr ""
+msgstr "Supprimer la liste d'utilisateurs"
msgid "Delete variable"
-msgstr ""
+msgstr "Supprimer la variable"
msgid "Delete video"
msgstr "Supprimer la vidéo"
@@ -12804,7 +12964,7 @@ msgid "DeleteProject|Failed to remove events. Please try again or contact admini
msgstr "Impossible de supprimer les événements. Veuillez réessayer ou contacter l'administrateur."
msgid "DeleteProject|Failed to remove project repository. Please try again or contact administrator."
-msgstr ""
+msgstr "Échec de la suppression du dépôt du projet. Veuillez réessayer ou contacter l'administrateur."
msgid "DeleteProject|Failed to remove project snippets. Please try again or contact administrator."
msgstr "Impossible de supprimer les extraits du projet. Veuillez réessayer ou contacter l’administrateur."
@@ -12816,7 +12976,7 @@ msgid "DeleteProject|Failed to remove webhooks. Please try again or contact admi
msgstr "Impossible de supprimer les webhooks. Veuillez réessayer ou contacter l'administrateur."
msgid "DeleteProject|Failed to remove wiki repository. Please try again or contact administrator."
-msgstr ""
+msgstr "Échec de la suppression du dépôt du wiki. Veuillez réessayer ou contacter l'administrateur."
msgid "DeleteRelease|Are you sure you want to delete this release?"
msgstr "Êtes-vous sûr de vouloir supprimer cette version ?"
@@ -12840,10 +13000,10 @@ msgid "Deleted"
msgstr "Supprimé"
msgid "Deleted chat nickname: %{chat_name}!"
-msgstr ""
+msgstr "Pseudo de discussion supprimé : %{chat_name} !"
msgid "Deleted commits:"
-msgstr ""
+msgstr "Commits supprimés :"
msgid "Deleted projects cannot be restored!"
msgstr "Les projets supprimés ne peuvent pas être restaurés !"
@@ -12897,7 +13057,7 @@ msgid "Denied"
msgstr ""
msgid "Denied authorization of chat nickname %{user_name}."
-msgstr ""
+msgstr "Autorisation refusée du pseudo de discussion %{user_name}."
msgid "Deny"
msgstr "Refuser"
@@ -12906,7 +13066,7 @@ msgid "Deny access request"
msgstr ""
msgid "Dependencies"
-msgstr ""
+msgstr "Dépendances"
msgid "Dependencies help page link"
msgstr ""
@@ -12927,7 +13087,7 @@ msgstr[0] "%d vulnérabilité détectée"
msgstr[1] "%d vulnérabilités détectées"
msgid "Dependencies|%{remainingLicensesCount} more"
-msgstr ""
+msgstr "%{remainingLicensesCount} de plus"
msgid "Dependencies|(top level)"
msgstr "(premier niveau)"
@@ -12936,16 +13096,16 @@ msgid "Dependencies|All"
msgstr ""
msgid "Dependencies|Component"
-msgstr ""
+msgstr "Composant"
msgid "Dependencies|Component name"
-msgstr ""
+msgstr "Nom du composant"
msgid "Dependencies|Dependency path"
msgstr ""
msgid "Dependencies|Export as JSON"
-msgstr ""
+msgstr "Exporter en JSON"
msgid "Dependencies|Job failed to generate the dependency list"
msgstr ""
@@ -12954,10 +13114,10 @@ msgid "Dependencies|Learn more about dependency paths"
msgstr "En savoir plus sur les chemins de dépendance"
msgid "Dependencies|License"
-msgstr ""
+msgstr "Licence"
msgid "Dependencies|Location"
-msgstr ""
+msgstr "Emplacement"
msgid "Dependencies|Location and dependency path"
msgstr "Emplacement et chemin de dépendance"
@@ -12984,19 +13144,19 @@ msgid "Dependencies|Unsupported file(s) detected"
msgstr ""
msgid "Dependencies|Vulnerable components"
-msgstr ""
+msgstr "Composants vulnérables"
msgid "Dependency List"
-msgstr ""
+msgstr "Liste des dépendances"
msgid "Dependency List has no entries"
msgstr "Aucune entrée dans la liste de dépendances"
msgid "Dependency Proxy"
-msgstr ""
+msgstr "Proxy de Dépendance"
msgid "Dependency Scanning"
-msgstr ""
+msgstr "Analyse des Dépendances"
msgid "Dependency list"
msgstr "Liste des dépendances"
@@ -13008,7 +13168,7 @@ msgid "DependencyProxy|Cached %{time}"
msgstr ""
msgid "DependencyProxy|Clear cache"
-msgstr ""
+msgstr "Vider le cache"
msgid "DependencyProxy|Clear the Dependency Proxy cache automatically"
msgstr "Vider automatiquement le cache du Proxy de Dépendance"
@@ -13077,7 +13237,7 @@ msgid "Deploy freezes"
msgstr "Gels de déploiement"
msgid "Deploy key was successfully updated."
-msgstr ""
+msgstr "La clé de déploiement a été mise à jour avec succès."
msgid "Deploy keys"
msgstr "Clés de déploiement"
@@ -13203,10 +13363,10 @@ msgid "DeployTokens|Allows write access to registry images."
msgstr "Autorise l'accès en écriture aux images de registre."
msgid "DeployTokens|Copy deploy token"
-msgstr ""
+msgstr "Copier le jeton de déploiement"
msgid "DeployTokens|Copy username"
-msgstr ""
+msgstr "Copier le nom d'utilisateur"
msgid "DeployTokens|Create a new deploy token for all projects in this group. %{link_start}What are deploy tokens?%{link_end}"
msgstr "Créer un nouveau jeton de déploiement pour tous les projets de ce groupe. %{link_start}Que sont les jetons de déploiement ?%{link_end}"
@@ -13238,6 +13398,9 @@ msgstr "Date d'expiration (facultatif)"
msgid "DeployTokens|Expires"
msgstr "Expire"
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr "Échec de la création d'un nouveau jeton de déploiement"
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr "Les jetons de déploiement de groupe permettent l’accès aux paquets, dépôts et images de registre dans le groupe."
@@ -13317,7 +13480,7 @@ msgid "Deployment Target|%{linkStart}How to provision or deploy to Kubernetes cl
msgstr "%{linkStart}Comment provisionner ou déployer vers des grappes de serveurs Kubernetes depuis GitLab ?%{linkEnd}"
msgid "Deployment Target|Project deployment target (optional)"
-msgstr ""
+msgstr "Cible du déploiement du projet (facultative)"
msgid "Deployment Target|Select the deployment target"
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr "Fréquence de déploiement"
+msgid "DeploymentApprovals|Approvals"
+msgstr "Approbations"
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr "Approbateurs"
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr "Développeurs + Responsables"
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr "Responsables"
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr "Approbations actuelles : %{current}"
@@ -13359,7 +13537,7 @@ msgid "DeploymentApproval|Rejected by you %{time}"
msgstr "Rejeté par vous %{time}"
msgid "DeploymentTarget|GitLab Pages"
-msgstr ""
+msgstr "GitLab Pages"
msgid "DeploymentTarget|Heroku"
msgstr "Heroku"
@@ -13374,7 +13552,7 @@ msgid "DeploymentTarget|Managed container runtime (Fargate, Cloud Run, DigitalOc
msgstr ""
msgid "DeploymentTarget|Mobile app store"
-msgstr ""
+msgstr "Magasin d'applications mobiles"
msgid "DeploymentTarget|No deployment planned"
msgstr "Aucun déploiement planifié"
@@ -13395,7 +13573,7 @@ msgid "DeploymentTarget|Virtual machine (for example, EC2)"
msgstr "Machine virtuelle (par exemple, EC2)"
msgid "Deployments"
-msgstr ""
+msgstr "Déploiements"
msgid "Deployments|%{deployments} environment impacted."
msgid_plural "Deployments|%{deployments} environments impacted."
@@ -13403,7 +13581,7 @@ msgstr[0] "%{deployments} environnement impacté."
msgstr[1] "%{deployments} environnements impactés."
msgid "Deployment|API"
-msgstr ""
+msgstr "API"
msgid "Deployment|Cancelled"
msgstr "Annulé"
@@ -13433,10 +13611,10 @@ msgid "Deployment|Success"
msgstr "Succès"
msgid "Deployment|This deployment was created using the API"
-msgstr ""
+msgstr "Ce déploiement a été créé à l'aide de l'API"
msgid "Deployment|Triggerer"
-msgstr ""
+msgstr "Déclenché par"
msgid "Deployment|Waiting"
msgstr "En attente"
@@ -13445,22 +13623,22 @@ msgid "Deployment|blocked"
msgstr "bloqué"
msgid "Deployment|canceled"
-msgstr ""
+msgstr "annulé"
msgid "Deployment|created"
msgstr ""
msgid "Deployment|failed"
-msgstr ""
+msgstr "en échec"
msgid "Deployment|running"
-msgstr ""
+msgstr "en cours"
msgid "Deployment|skipped"
msgstr "Ignoré"
msgid "Deployment|success"
-msgstr ""
+msgstr "réussi"
msgid "Deprecated API rate limits"
msgstr ""
@@ -13540,19 +13718,19 @@ msgid "DesignManagement|Are you sure you want to cancel creating this comment?"
msgstr "Êtes-vous sûr de vouloir annuler la création de ce commentaire ?"
msgid "DesignManagement|Are you sure you want to cancel editing this comment?"
-msgstr ""
+msgstr "Êtes-vous sûr de vouloir annuler la modification de ce commentaire ?"
msgid "DesignManagement|Click the image where you'd like to start a new discussion"
-msgstr ""
+msgstr "Cliquez sur l'image où vous souhaitez démarrer une nouvelle discussion"
msgid "DesignManagement|Comment"
msgstr "Commentaire"
msgid "DesignManagement|Continue creating"
-msgstr ""
+msgstr "Poursuivre la création"
msgid "DesignManagement|Continue editing"
-msgstr ""
+msgstr "Poursuivre la modification"
msgid "DesignManagement|Could not add a new comment. Please try again."
msgstr "Impossible d'ajouter un nouveau commentaire. Veuillez réessayer."
@@ -13573,7 +13751,7 @@ msgid "DesignManagement|Designs"
msgstr "Designs"
msgid "DesignManagement|Discard changes"
-msgstr ""
+msgstr "Abandonner les modifications"
msgid "DesignManagement|Discussion"
msgstr "Discussion"
@@ -13588,13 +13766,13 @@ msgid "DesignManagement|Go back to designs"
msgstr ""
msgid "DesignManagement|Go to next design"
-msgstr ""
+msgstr "Aller au design suivant"
msgid "DesignManagement|Go to previous design"
-msgstr ""
+msgstr "Aller au design précédent"
msgid "DesignManagement|Requested design version does not exist. Showing latest version instead"
-msgstr ""
+msgstr "La version du design demandée n'existe pas. Affichage de la dernière version à la place"
msgid "DesignManagement|Resolve thread"
msgstr ""
@@ -13615,7 +13793,7 @@ msgid "DesignManagement|Some of the designs you tried uploading did not change:
msgstr "Certains des designs que vous avez essayé de téléverser n'ont pas changé : %{skippedFiles}."
msgid "DesignManagement|The maximum number of designs allowed to be uploaded is %{upload_limit}. Please try again."
-msgstr ""
+msgstr "Le nombre maximum de designs pouvant être téléversés est de %{upload_limit}. Veuillez réessayer."
msgid "DesignManagement|There was an error moving your designs. Please upload your designs below."
msgstr "Une erreur s’est produite lors du déplacement de vos designs. Veuillez téléverser vos designs ci-dessous."
@@ -13636,7 +13814,7 @@ msgid "DesignManagement|Your designs are being copied and are on their way… Pl
msgstr "Vos designs sont en cours de copie et sont en route… Veuillez actualiser pour mettre à jour."
msgid "Designs"
-msgstr ""
+msgstr "Designs"
msgid "Destroy"
msgstr "Détruire"
@@ -13657,7 +13835,7 @@ msgid "Detect host keys"
msgstr "Détecter les clefs de l’hôte"
msgid "DevOps Adoption"
-msgstr ""
+msgstr "Adoption DevOps"
msgid "DevOps Reports"
msgstr "Rapports DevOps"
@@ -13665,6 +13843,9 @@ msgstr "Rapports DevOps"
msgid "DevOps adoption"
msgstr "Adoption de DevOps"
+msgid "Developer"
+msgstr "Développeur"
+
msgid "Development"
msgstr "Développement"
@@ -13834,16 +14015,16 @@ msgid "DevopsReport|DevOps score metrics are based on usage over the last 30 day
msgstr "Les métriques du score DevOps sont basées sur l’utilisation au cours des 30 derniers jours. Dernière mise à jour : %{timestamp}."
msgid "DevopsReport|High"
-msgstr ""
+msgstr "Élevé"
msgid "DevopsReport|Leader usage"
msgstr ""
msgid "DevopsReport|Low"
-msgstr ""
+msgstr "Faible"
msgid "DevopsReport|Moderate"
-msgstr ""
+msgstr "Modéré"
msgid "DevopsReport|Overview"
msgstr "Vue d'ensemble"
@@ -13861,7 +14042,7 @@ msgid "Diagram (%{language})"
msgstr "Diagramme (%{language})"
msgid "Did not delete the source branch."
-msgstr ""
+msgstr "N'a pas supprimé la branche source."
msgid "Didn't receive a confirmation email?"
msgstr "Vous n'avez pas reçu de courriel de confirmation ?"
@@ -13882,13 +14063,13 @@ msgid "Diff notes"
msgstr ""
msgid "Difference between start date and now"
-msgstr ""
+msgstr "Différence entre la date de début et maintenant"
msgid "DiffsCompareBaseBranch|(HEAD)"
msgstr "(HEAD)"
msgid "DiffsCompareBaseBranch|(base)"
-msgstr ""
+msgstr "(base)"
msgid "Diffs|%d addition"
msgid_plural "Diffs|%d additions"
@@ -13901,7 +14082,13 @@ msgstr[0] "%d suppression"
msgstr[1] "%d suppressions"
msgid "Diffs|Expand all lines"
-msgstr ""
+msgstr "Étendre toutes les lignes"
+
+msgid "Diffs|Hide whitespace changes"
+msgstr "Masquer les modifications d'espaces"
+
+msgid "Diffs|Inline"
+msgstr "En ligne"
msgid "Diffs|Next 20 lines"
msgstr "20 lignes suivantes"
@@ -13918,11 +14105,17 @@ msgstr "Afficher %{unfoldCount} lignes"
msgid "Diffs|Show all unchanged lines"
msgstr "Afficher toutes les lignes inchangées"
+msgid "Diffs|Show whitespace changes"
+msgstr "Afficher les modifications d'espaces"
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] "Affichage de %{dropdownStart}%{count} fichier modifié%{dropdownEnd}"
msgstr[1] "Affichage de %{dropdownStart}%{count} fichiers modifiés%{dropdownEnd}"
+msgid "Diffs|Side-by-side"
+msgstr "Côte à côte"
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Quelque chose s’est mal passé lors de la rapatriement des lignes du diff."
@@ -13933,13 +14126,13 @@ msgid "Direct member"
msgstr "Membre direct"
msgid "Direct members"
-msgstr ""
+msgstr "Membres direct"
msgid "Direct non-authenticated users to this page."
-msgstr ""
+msgstr "Diriger les utilisateurs non authentifiés vers cette page."
msgid "Direct users to this page after they sign out."
-msgstr ""
+msgstr "Diriger les utilisateurs vers cette page après leur déconnexion."
msgid "Direction"
msgstr "Direction"
@@ -13963,7 +14156,7 @@ msgid "Disable group runners"
msgstr "Désactiver les exécuteurs de groupe"
msgid "Disable two-factor authentication"
-msgstr ""
+msgstr "Désactiver l’authentification à deux facteurs"
msgid "Disabled"
msgstr ""
@@ -13981,7 +14174,7 @@ msgid "Discard all changes"
msgstr "Rejeter tous les changements"
msgid "Discard all changes?"
-msgstr ""
+msgstr "Abandonner toutes les modifications ?"
msgid "Discard changes"
msgstr "Abandonner les modifications"
@@ -13993,7 +14186,7 @@ msgid "Discard draft"
msgstr "Abandonner le brouillon"
msgid "DiscordService|Discord Notifications"
-msgstr ""
+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."
@@ -14002,7 +14195,7 @@ msgid "Discover"
msgstr ""
msgid "Discover GitLab Geo"
-msgstr ""
+msgstr "Découvrir GitLab Geo"
msgid "Discover projects, groups and snippets. Share your projects with others"
msgstr "Découvrez des projets, des groupes et des extraits de code. Partagez vos projets avec d’autres personnes"
@@ -14044,7 +14237,7 @@ msgid "Discussion to reply to cannot be found"
msgstr ""
msgid "Disk Usage"
-msgstr ""
+msgstr "Utilisation du disque"
msgid "Dismiss"
msgstr "Rejeter"
@@ -14097,10 +14290,10 @@ msgid "Display progress of child issues"
msgstr "Afficher la progression des tickets enfants"
msgid "Display rendered file"
-msgstr ""
+msgstr "Afficher le rendu du fichier"
msgid "Display source"
-msgstr ""
+msgstr "Afficher la source"
msgid "Display time tracking in issues in total hours only. %{link_start}What is time tracking?%{link_end}"
msgstr ""
@@ -14115,16 +14308,16 @@ msgid "Do you want to remove this deploy key?"
msgstr "Voulez-vous supprimer cette clé de déploiement ?"
msgid "Dockerfile"
-msgstr ""
+msgstr "Dockerfile"
msgid "Documentation"
-msgstr ""
+msgstr "Documentation"
msgid "Documentation for popular identity providers"
msgstr "Documentation des principaux fournisseurs d’identité"
msgid "Documentation pages URL"
-msgstr ""
+msgstr "URL des pages de documentation"
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr "Documents réindexés : %{processed_documents} (%{percentage}%%)"
@@ -14148,16 +14341,16 @@ msgid "DomainVerification|The following domains are configured for projects in t
msgstr "Les domaines suivants sont configurés pour les projets de ce groupe. Les utilisateurs dont les adresses de courriel correspondent à un domaine vérifié n'ont pas besoin de confirmer leur compte."
msgid "Don't have a group?"
-msgstr ""
+msgstr "Vous n'avez pas de groupe ?"
msgid "Don't have an account yet?"
-msgstr ""
+msgstr "Vous n'avez pas encore de compte ?"
msgid "Don't include description in commit message"
msgstr "Ne pas inclure la description dans le message de commit"
msgid "Don't paste the private part of the GPG key. Paste the public part which begins with '-----BEGIN PGP PUBLIC KEY BLOCK-----'."
-msgstr ""
+msgstr "Ne collez pas la partie privée de la clé GPG. Collez la partie publique qui commence par « -----BEGIN PGP PUBLIC KEY BLOCK----- »."
msgid "Don't send service data"
msgstr ""
@@ -14187,13 +14380,13 @@ msgid "Download (%{size})"
msgstr "Télécharger (%{size})"
msgid "Download CSV"
-msgstr ""
+msgstr "Télécharger le CSV"
msgid "Download PDF"
msgstr "Télécharger le PDF"
msgid "Download artifacts"
-msgstr ""
+msgstr "Télécharger les artéfacts"
msgid "Download codes"
msgstr ""
@@ -14205,7 +14398,7 @@ msgid "Download export"
msgstr ""
msgid "Download image"
-msgstr ""
+msgstr "Télécharger l'image"
msgid "Download payload"
msgstr "Télécharger la charge utile"
@@ -14214,10 +14407,10 @@ msgid "Download raw data (.csv)"
msgstr "Télécharger les données brutes (.csv)"
msgid "Download source code"
-msgstr ""
+msgstr "Télécharger le code source"
msgid "Download this directory"
-msgstr ""
+msgstr "Télécharger ce répertoire"
msgid "DownloadCommit|Email Patches"
msgstr "Envoyer les correctifs par courriel"
@@ -14292,7 +14485,7 @@ msgid "DropdownWidget|You don't have permission to view this %{issuableAttribute
msgstr ""
msgid "Due Date"
-msgstr ""
+msgstr "Date d'échéance"
msgid "Due date"
msgstr "Date d’échéance"
@@ -14310,49 +14503,49 @@ msgid "Duplicate page: %{error_message}"
msgstr "Page dupliquée : %{error_message}"
msgid "Duration"
-msgstr ""
+msgstr "Durée"
msgid "Duration (min)"
msgstr "Durée (min)"
msgid "Duration|%s days"
-msgstr ""
+msgstr "%s jours"
msgid "Duration|%s hours"
-msgstr ""
+msgstr "%s heures"
msgid "Duration|%s minutes"
-msgstr ""
+msgstr "%s minutes"
msgid "Duration|%s months"
-msgstr ""
+msgstr "%s mois"
msgid "Duration|%s seconds"
-msgstr ""
+msgstr "%s secondes"
msgid "Duration|%s weeks"
-msgstr ""
+msgstr "%s semaines"
msgid "Duration|%s years"
-msgstr ""
+msgstr "%s ans"
msgid "Duration|1 day"
-msgstr ""
+msgstr "1 jour"
msgid "Duration|1 hour"
-msgstr ""
+msgstr "1 heure"
msgid "Duration|1 minute"
-msgstr ""
+msgstr "1 minute"
msgid "Duration|1 month"
-msgstr ""
+msgstr "1 mois"
msgid "Duration|1 week"
-msgstr ""
+msgstr "1 semaine"
msgid "Duration|1 year"
-msgstr ""
+msgstr "1 an"
msgid "During this process, you’ll be asked for URLs from GitLab’s side. Use the URLs shown below."
msgstr "Au cours de ce processus, il vous sera demandé les URL de GitLab. Utilisez les URL indiquées ciâ€dessous."
@@ -14379,7 +14572,7 @@ msgid "Edit Comment"
msgstr "Modifier le commentaire"
msgid "Edit Deploy Key"
-msgstr ""
+msgstr "Modifier la clé de déploiement"
msgid "Edit Geo Site"
msgstr "Modifier le Site Geo"
@@ -14397,13 +14590,13 @@ msgid "Edit Milestone"
msgstr "Modifier le jalon"
msgid "Edit Password"
-msgstr ""
+msgstr "Modifier le mot de passe"
msgid "Edit Pipeline Schedule"
msgstr "Modifier la Planification de Pipeline"
msgid "Edit Release"
-msgstr ""
+msgstr "Modifier la Version"
msgid "Edit Requirement"
msgstr "Modifier l'Exigence"
@@ -14433,13 +14626,13 @@ msgid "Edit deploy freeze"
msgstr "Modifier le gel de déploiement"
msgid "Edit deploy key"
-msgstr ""
+msgstr "Modifier la clé de déploiement"
msgid "Edit description"
-msgstr ""
+msgstr "Modifier la description"
msgid "Edit environment"
-msgstr ""
+msgstr "Modifier l'environnement"
msgid "Edit epics"
msgstr "Modifier les épopées"
@@ -14481,7 +14674,7 @@ msgid "Edit merge requests"
msgstr "Modifier les demandes de fusion"
msgid "Edit public deploy key"
-msgstr ""
+msgstr "Modifier la clé de déploiement publique"
msgid "Edit sidebar"
msgstr "Modifier la barre latérale"
@@ -14490,10 +14683,10 @@ msgid "Edit table"
msgstr "Modifier le tableau"
msgid "Edit this file only."
-msgstr ""
+msgstr "Modifier ce fichier uniquement."
msgid "Edit this release"
-msgstr ""
+msgstr "Modifier cette version"
msgid "Edit title and description"
msgstr "Modifier le titre et la description"
@@ -14508,7 +14701,7 @@ msgid "Edit video description"
msgstr ""
msgid "Edit wiki page"
-msgstr ""
+msgstr "Modifier la page wiki"
msgid "Edit your most recent comment in a thread (from an empty textarea)"
msgstr ""
@@ -14528,8 +14721,14 @@ msgstr "Édité"
msgid "Edited %{timeago}"
msgstr "Modifié %{timeago}"
+msgid "Edited %{timeago} by %{author}"
+msgstr "Modifié %{timeago} par %{author}"
+
+msgid "Edited by %{author}"
+msgstr "Modifié par %{author}"
+
msgid "Editing"
-msgstr ""
+msgstr "Édition"
msgid "Elapsed time"
msgstr "Temps écoulé"
@@ -14541,7 +14740,7 @@ msgid "Elasticsearch indexing restrictions"
msgstr ""
msgid "Elasticsearch indexing started"
-msgstr ""
+msgstr "L'indexation Elasticsearch a démarré"
msgid "Elasticsearch migration halted"
msgstr ""
@@ -14559,22 +14758,22 @@ msgid "Elasticsearch zero-downtime reindexing"
msgstr "Réindexation Elasticsearch sans temps mort"
msgid "Elastic|None. Select namespaces to index."
-msgstr ""
+msgstr "Aucun. Sélectionnez les espaces de noms à indexer."
msgid "Elastic|None. Select projects to index."
-msgstr ""
+msgstr "Aucun. Sélectionnez les projets à indexer."
msgid "Email"
msgstr "Courriel"
msgid "Email %{number}"
-msgstr ""
+msgstr "Courriel %{number}"
msgid "Email Notification"
msgstr ""
msgid "Email a new %{name} to this project"
-msgstr ""
+msgstr "Cliquez pour une création de %{name} par courriel"
msgid "Email address suffix"
msgstr ""
@@ -14622,25 +14821,25 @@ msgid "EmailError|The thread you are replying to no longer exists, perhaps it wa
msgstr "Le fil de discussion auquel vous répondez n'existe plus, peut-être a-t-il été supprimé ? Si vous pensez que c'est une erreur, contactez un membre du staff."
msgid "EmailError|We couldn't figure out what the email is for. Please create your issue or comment through the web interface."
-msgstr ""
+msgstr "Nous n'avons pas pu déterminer à quoi est destiné ce courriel. Veuillez créer votre ticket ou votre commentaire via l'interface Web."
msgid "EmailError|We couldn't figure out what the email is in reply to. Please create your comment through the web interface."
msgstr "Nous n'avons pas pu déterminer à quoi le courriel répond. Veuillez créer votre commentaire via l'interface Web."
msgid "EmailError|We couldn't figure out what user corresponds to the email. Please create your comment through the web interface."
-msgstr ""
+msgstr "Nous n'avons pas pu déterminer à quel utilisateur correspond ce courriel. Veuillez créer votre commentaire via l'interface Web."
msgid "EmailError|We couldn't find the project. Please check if there's any typo."
-msgstr ""
+msgstr "Nous n'avons pas pu trouver le projet. Veuillez vérifier qu'il n'y a aucune faute de frappe."
msgid "EmailError|We couldn't process your email because it is too large. Please create your issue or comment through the web interface."
msgstr "Nous n'avons pas pu traiter votre courriel car il est trop volulineux. Veuillez créer votre ticket ou votre commentaire via l'interface Web."
msgid "EmailError|You are not allowed to perform this action. If you believe this is in error, contact a staff member."
-msgstr ""
+msgstr "Vous n'êtes pas autorisé(e) à effectuer cette action. Si vous pensez qu'il s'agit d'une erreur, contactez un membre du personnel."
msgid "EmailError|Your account has been blocked. If you believe this is in error, contact a staff member."
-msgstr ""
+msgstr "Votre compte a été bloqué. Si vous pensez qu'il s'agit d'une erreur, contactez un membre du staff."
msgid "EmailParticipantsWarning|%{emails} will be notified of your comment."
msgstr "%{emails} sera informé de votre commentaire."
@@ -14658,13 +14857,13 @@ msgid "Emails sent to %{email} are also supported."
msgstr "Les courriels envoyés à %{email} sont également pris en charge."
msgid "EmailsOnPushService|Disable code diffs"
-msgstr ""
+msgstr "Désactiver les diffs de code"
msgid "EmailsOnPushService|Don't include possibly sensitive code diffs in notification body."
msgstr ""
msgid "EmailsOnPushService|Email the commits and diff of each push to a list of recipients."
-msgstr ""
+msgstr "Envoyer par courriel les commits et les diffs de chaque poussée à une liste de destinataires."
msgid "EmailsOnPushService|Emails on push"
msgstr ""
@@ -14673,7 +14872,7 @@ msgid "EmailsOnPushService|Emails separated by whitespace."
msgstr "Adresses de courriel séparées par des espaces."
msgid "EmailsOnPushService|Send from committer"
-msgstr ""
+msgstr "Envoyer depuis le contributeur"
msgid "EmailsOnPushService|Send notifications from the committer's email address if the domain matches the domain used by your GitLab instance (such as %{domains})."
msgstr "Envoyer les notifications depuis l'adresse de courriel du contributeur si le domaine correspond à celui utilisé par votre instance GitLab (tels que %{domains})."
@@ -14694,7 +14893,7 @@ msgid "Enable Akismet"
msgstr "Activer Akismet"
msgid "Enable Amazon EKS integration"
-msgstr ""
+msgstr "Activer l'intégration d'Amazon EKS"
msgid "Enable Auto DevOps"
msgstr "Activer Auto DevOps"
@@ -14706,13 +14905,13 @@ msgid "Enable GitLab Prometheus metrics endpoint"
msgstr "Activer le point d'arrivée des métriques Prometheus de GitLab"
msgid "Enable Gitpod"
-msgstr ""
+msgstr "Activer Gitpod"
msgid "Enable Gitpod?"
-msgstr ""
+msgstr "Activer Gitpod ?"
msgid "Enable Invisible Captcha during sign up"
-msgstr ""
+msgstr "Activer un Captcha invisible lors de l'inscription"
msgid "Enable Kroki"
msgstr "Activer Kroki"
@@ -14721,19 +14920,19 @@ msgid "Enable Mailgun event receiver"
msgstr "Activer le récepteur d'événements Mailgun"
msgid "Enable PlantUML"
-msgstr ""
+msgstr "Activer PlantUML"
msgid "Enable SSL verification"
msgstr "Activer la vérification SSL"
msgid "Enable Sentry error tracking"
-msgstr ""
+msgstr "Activer le suivi des erreurs Sentry"
msgid "Enable Snowplow tracking"
msgstr "Activer le suivi avec Snowplow"
msgid "Enable Spam Check via external API endpoint"
-msgstr ""
+msgstr "Activer Spam Check via le point de terminaison d'une API externe"
msgid "Enable What's new: All tiers"
msgstr "Activer les Nouveautés : Toutes les éditions"
@@ -14745,7 +14944,7 @@ msgid "Enable access to the performance bar for non-administrators in a given gr
msgstr "Activer l'accès à la barre de performance pour les non-administrateurs d'un groupe donné."
msgid "Enable admin mode"
-msgstr ""
+msgstr "Activer le mode admin"
msgid "Enable and disable Service Desk. Some additional configuration might be required. %{link_start}Learn more%{link_end}."
msgstr "Activer et désactiver le Service d'Assistance. Une configuration supplémentaire peut se révéler nécessaire. %{link_start}En savoir plus%{link_end}."
@@ -14775,10 +14974,10 @@ msgid "Enable dashboard limits on namespaces"
msgstr ""
msgid "Enable email notification"
-msgstr ""
+msgstr "Activer la notification par courriel"
msgid "Enable error tracking"
-msgstr ""
+msgstr "Activer le suivi des erreurs"
msgid "Enable feature to choose access level"
msgstr ""
@@ -14790,7 +14989,7 @@ msgid "Enable group runners"
msgstr "Activer les exécuteurs de groupe"
msgid "Enable header and footer in emails"
-msgstr ""
+msgstr "Activer l'en-tête et le pied de page dans les courriels"
msgid "Enable in-product marketing emails"
msgstr ""
@@ -14802,7 +15001,7 @@ msgid "Enable integration"
msgstr "Activer l'intégration"
msgid "Enable logs collection"
-msgstr ""
+msgstr "Activer la collecte des journaux"
msgid "Enable maintenance mode"
msgstr "Activer le mode maintenance"
@@ -14814,7 +15013,7 @@ msgid "Enable only for confidential applications exclusively used by a trusted b
msgstr "Activer uniquement pour les applications confidentielles utilisées exclusivement par un serveur backend de confiance qui peut stocker en toute sécurité le secret du client. Ne pas activer pour les applications mobiles natives, à page unique ou autres applications JavaScript car elles ne peuvent pas garder le secret du client confidentiel."
msgid "Enable or disable version check and Service Ping."
-msgstr ""
+msgstr "Activer ou désactiver le contrôle de version et le Ping de Service."
msgid "Enable rate limiting for POST requests to the specified paths"
msgstr ""
@@ -14829,7 +15028,7 @@ msgid "Enable repository checks"
msgstr "Activer les vérifications de dépôt"
msgid "Enable security training"
-msgstr ""
+msgstr "Activer la formation à la sécurité"
msgid "Enable security training to help your developers learn how to fix vulnerabilities. Developers can view security training from selected educational providers, relevant to the detected vulnerability."
msgstr ""
@@ -14844,7 +15043,7 @@ msgid "Enable shared runners for this project"
msgstr "Activer les exécuteurs partagés pour ce projet"
msgid "Enable two-factor authentication"
-msgstr ""
+msgstr "Activer l'authentification à deux facteurs"
msgid "Enable unauthenticated API request rate limit"
msgstr "Activer la limite de fréquence des requêtes d'API non authentifiées"
@@ -14853,28 +15052,46 @@ msgid "Enable unauthenticated web request rate limit"
msgstr ""
msgid "Enable user deactivation emails"
-msgstr ""
+msgstr "Activer les courriels de désactivation d'utilisateur"
msgid "Enable version check"
msgstr "Activer le contrôle de version"
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
-msgstr "%{stepStart}Étape 1%{stepEnd}. Assurez-vous d'avoir configuré Kubernetes et de disposer d'un domaine de base pour votre %{linkStart}grappe de serveurs%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr "Ajoutez dans votre configuration CI/CD une tâche qui :"
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
-msgstr "%{stepStart}Étape 2%{stepEnd}. Copiez l'extrait suivant :"
+msgid "EnableReviewApp|Copy snippet"
+msgstr "Copier l'extrait"
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
-msgstr "%{stepStart}Étape 3%{stepEnd}. Ajoutez-le au fichier %{linkStart}gitlab-ci.yml%{linkEnd} du projet."
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr "A accès à l'infrastructure qui peut héberger et déployer les applications de revue."
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
-msgstr "%{stepStart}Étape 4 (facultative)%{stepEnd}. Activez les Revues Visuelles en suivant les %{linkStart}instructions de configuration%{linkEnd}."
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr "Installer et configurer un exécuteur pour effectuer le déploiement."
-msgid "EnableReviewApp|Close"
-msgstr "Fermer"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr "Assurez-vous que le projet dispose d'un environnement configuré avec l'URL cible définie sur l'URL du site web. Si ce n'est pas le cas, créez-en un nouveau avant de continuer."
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr "Ne s'exécute que pour les demandes de fusion ou les branches de fonctionnalité."
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr "Recommandé : Mettre en place une tâche qui arrête manuellement les Applis de Revue."
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr "Les applis de revue sont des environnements dynamiques que vous pouvez utiliser pour fournir un aperçu en direct des modifications effectuées dans une branche de fonctionnalité."
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr "Pour configurer une application de revue dynamique, vous devez :"
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr "Utilise une variable CI/CD prédéfinie comme %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} pour créer dynamiquement des environnements d'application de revue. Par exemple, pour une configuration utilisant des pipelines de demande de fusion :"
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr "Vous utilisez un site statique ?"
-msgid "EnableReviewApp|Copy snippet text"
-msgstr "Copier l'extrait de texte"
+msgid "EnableReviewApp|View more example projects"
+msgstr "Voir plus d'exemples de projets"
msgid "Enabled"
msgstr "activé"
@@ -14883,7 +15100,7 @@ msgid "Enabled Git access protocols"
msgstr ""
msgid "Enabled OAuth authentication sources"
-msgstr ""
+msgstr "Sources d'authentification OAuth activées"
msgid "End Time"
msgstr ""
@@ -14901,7 +15118,7 @@ msgid "Ends: %{endsAt}"
msgstr ""
msgid "Enforce two-factor authentication"
-msgstr ""
+msgstr "Imposer l'authentification à deux facteurs"
msgid "Enforce two-factor authentication for all user sign-ins."
msgstr ""
@@ -14922,13 +15139,13 @@ msgid "Enter 2FA for Admin Mode"
msgstr ""
msgid "Enter Admin Mode"
-msgstr ""
+msgstr "Entrer en Mode Admin"
msgid "Enter a number"
-msgstr ""
+msgstr "Entrez un nombre"
msgid "Enter an integer number between 0 and 100"
-msgstr ""
+msgstr "Entrez un nombre entier compris entre 0 et 100"
msgid "Enter any color or choose one of the suggested colors below."
msgstr "Entrez n'importe quelle couleur ou choisissez-en une parmi celles suggérées ci-dessous."
@@ -14937,13 +15154,13 @@ msgid "Enter any color."
msgstr "Entrez une couleur."
msgid "Enter at least three characters to search"
-msgstr ""
+msgstr "Entrez au moins trois caractères pour effectuer la recherche"
msgid "Enter in your Bitbucket Server URL and personal access token below"
msgstr "Entrez l’URL de votre serveur Bitbucket et votre jeton d’accès personnel ciâ€dessous"
msgid "Enter in your Phabricator Server URL and personal access token below"
-msgstr ""
+msgstr "Entrez l’URL de votre serveur Phabricator et votre jeton d’accès personnel ciâ€dessous"
msgid "Enter license key"
msgstr "Entrez la clé de licence"
@@ -14952,10 +15169,10 @@ msgid "Enter merge request URLs"
msgstr ""
msgid "Enter new AWS Secret Access Key"
-msgstr ""
+msgstr "Entrez la nouvelle Clé d'Accès Secrète AWS"
msgid "Enter number of issues"
-msgstr ""
+msgstr "Entrez le nombre de tickets"
msgid "Enter one or more user ID separated by commas"
msgstr "Entrez un ou plusieurs ID utilisateur séparés par des virgules"
@@ -14967,13 +15184,13 @@ 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 ""
+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 following to confirm:"
msgstr "Entrez ce qui suit pour confirmer :"
msgid "Enter the name of your application, and we'll return a unique %{type}."
-msgstr ""
+msgstr "Entrez le nom de votre application, et nous retournerons un %{type} unique."
msgid "Enter the number of seconds, or other human-readable input, like \"1 hour\". This timeout takes precedence over lower timeouts set for the project."
msgstr "Entrez le nombre de secondes ou toute autre expression lisible telle que « 1 hour ». Ce délai d'expiration a la priorité sur les délais plus courts définis pour le projet."
@@ -14994,7 +15211,7 @@ msgid "Enter your Packagist username."
msgstr "Entrez votre nom d'utilisateur Packagist."
msgid "Enter your password to approve"
-msgstr ""
+msgstr "Entrez votre mot de passe pour approuver"
msgid "Enterprise"
msgstr ""
@@ -15018,10 +15235,10 @@ msgid "Environment variables on this GitLab instance are configured to be %{link
msgstr "Les variables d'environnement de cette instance GitLab sont configurées pour être %{link_start}protégées%{link_end} par défaut."
msgid "Environment:"
-msgstr ""
+msgstr "Environnement :"
msgid "EnvironmentDashboard|API"
-msgstr ""
+msgstr "API"
msgid "EnvironmentDashboard|Created through the Deployment API"
msgstr ""
@@ -15033,7 +15250,7 @@ msgid "Environments"
msgstr "Environnements"
msgid "Environments Dashboard"
-msgstr ""
+msgstr "Tableau de bord des Environnements"
msgid "Environments allow you to track deployments of your application. %{linkStart}More information%{linkEnd}."
msgstr "Les environnements vous permettent de suivre les déploiements de votre application. %{linkStart}Plus d'informations%{linkEnd}."
@@ -15045,22 +15262,22 @@ msgid "EnvironmentsAlert|%{severity} • %{title} %{text}. %{linkStart}View Deta
msgstr "%{severity} • %{title} %{text}. %{linkStart}Voir les Détails%{linkEnd} · %{startedAt} "
msgid "EnvironmentsDashboard|Add a project to the dashboard"
-msgstr ""
+msgstr "Ajouter un projet au tableau de bord"
msgid "EnvironmentsDashboard|Add projects"
-msgstr ""
+msgstr "Ajouter des projets"
msgid "EnvironmentsDashboard|Environments Dashboard"
-msgstr ""
+msgstr "Tableau de bord des Environnements"
msgid "EnvironmentsDashboard|Job: %{job}"
-msgstr ""
+msgstr "Tâche : %{job}"
msgid "EnvironmentsDashboard|More actions"
-msgstr ""
+msgstr "Plus d'actions"
msgid "EnvironmentsDashboard|Remove"
-msgstr ""
+msgstr "Supprimer"
msgid "EnvironmentsDashboard|The environments dashboard provides a summary of each project's environments' status, including pipeline and alert statuses."
msgstr ""
@@ -15096,11 +15313,14 @@ msgid "Environments|Auto stop"
msgstr "Arrêt auto"
msgid "Environments|Auto stops %{autoStopAt}"
-msgstr ""
+msgstr "S'arrête automatiquement %{autoStopAt}"
msgid "Environments|Commit"
msgstr "Commit"
+msgid "Environments|Copy live environment URL"
+msgstr "Copier l'URL de l'environnement de production"
+
msgid "Environments|Delete"
msgstr "Supprimer"
@@ -15138,13 +15358,13 @@ msgid "Environments|Environments are places where code gets deployed, such as st
msgstr "Les environnements sont des endroits où le code est déployé, tel que l’étape ou la production."
msgid "Environments|How do I create an environment?"
-msgstr ""
+msgstr "Comment créer un environnement ?"
msgid "Environments|Job"
msgstr "Tâche"
msgid "Environments|Learn about environments"
-msgstr ""
+msgstr "En savoir plus sur les environnements"
msgid "Environments|Learn more about stopping environments"
msgstr "En savoir plus sur l’arrêt des environnements"
@@ -15165,7 +15385,7 @@ msgid "Environments|Note that this action will stop the environment, but it will
msgstr "Notez que cette action arrêtera l’environnement, mais n’aura %{emphasisStart}aucun%{emphasisEnd} effet sur les déploiements existants en raison de l’absence de directive « arrêter l’action de l’environnement » dans le fichier de configuration %{ciConfigLinkEnd}.gitlab-ci.yml%{ciConfigLinkStart}."
msgid "Environments|Open"
-msgstr ""
+msgstr "Ouvrir"
msgid "Environments|Open live environment"
msgstr "Ouvrir l’environnement en cours"
@@ -15219,10 +15439,10 @@ msgid "Environments|Updated"
msgstr "Mis à jour"
msgid "Environments|You don't have any environments."
-msgstr ""
+msgstr "Vous n'avez aucun environnement."
msgid "Environments|You don't have any stopped environments."
-msgstr ""
+msgstr "Vous n'avez aucun environnement arrêté."
msgid "Environments|by %{avatar}"
msgstr "par %{avatar}"
@@ -15281,12 +15501,12 @@ msgstr "Ajouter une nouvelle épopée"
msgid "Epics|Add an existing epic"
msgstr "Ajouter une épopée existante"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgstr "Êtes-vous sûr de vouloir supprimer %{bStart}%{targetEpicTitle}%{bEnd} de %{bStart}%{parentEpicTitle}%{bEnd} ?"
+
msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr "Êtes-vous sûr de vouloir supprimer %{bStart}%{targetIssueTitle}%{bEnd} de %{bStart}%{parentEpicTitle}%{bEnd} ?"
-msgid "Epics|Assign Epic"
-msgstr "Assigner une Épopée"
-
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr "Laisser vide pour hériter des dates du jalon"
@@ -15294,46 +15514,31 @@ msgid "Epics|No start date – %{dueDate}"
msgstr "Pas de date de début – %{dueDate}"
msgid "Epics|Remove epic"
-msgstr ""
+msgstr "Supprimer l'épopée"
msgid "Epics|Remove issue"
msgstr "Supprimer le ticket"
-msgid "Epics|Search epics"
-msgstr "Rechercher des épopées"
-
-msgid "Epics|Select epic"
-msgstr "Sélectionner une épopée"
-
msgid "Epics|Show more"
-msgstr ""
-
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
+msgstr "Afficher plus"
msgid "Epics|Something went wrong while creating child epics."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la création des épopées enfants."
msgid "Epics|Something went wrong while creating issue."
msgstr "Une erreur s'est produite lors de la création du ticket."
msgid "Epics|Something went wrong while fetching child epics."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des épopées enfants."
msgid "Epics|Something went wrong while fetching epics list."
msgstr "Une erreur s'est produite lors de la récupération de la liste des épopées."
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr "Une erreur s'est produite lors du déplacement de l'élément."
msgid "Epics|Something went wrong while ordering item."
-msgstr ""
-
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
+msgstr "Une erreur s'est produite lors du classement de l'élément."
msgid "Epics|Something went wrong while updating epics."
msgstr "Une erreur s'est produite lors de la mise à jour des épopées."
@@ -15360,7 +15565,7 @@ msgid "Error Details"
msgstr ""
msgid "Error Tracking"
-msgstr ""
+msgstr "Suivi des erreurs"
msgid "Error creating epic"
msgstr "Erreur lors de la création de l’épopée"
@@ -15372,7 +15577,7 @@ msgid "Error creating new directory. Please try again."
msgstr "Erreur lors de la création du nouveau répertoire. Veuillez réessayer."
msgid "Error creating new iteration"
-msgstr ""
+msgstr "Erreur lors de la création d'une nouvelle itération"
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}"
@@ -15384,7 +15589,7 @@ msgid "Error creating vulnerability finding: %{errors}"
msgstr "Erreur lors de la création de la découverte de vulnérabilité : %{errors}"
msgid "Error deleting project. Check logs for error details."
-msgstr ""
+msgstr "Erreur lors de la suppression du projet. Consultez les journaux pour plus de détails sur l'erreur."
msgid "Error fetching branches"
msgstr "Erreur lors de la récupération des branches"
@@ -15411,7 +15616,7 @@ msgid "Error fetching refs"
msgstr "Erreur lors de la récupération des refs"
msgid "Error fetching the dependency list. Please check your network connection and try again."
-msgstr ""
+msgstr "Erreur lors de la récupération de la liste de dépendances. Veuillez vérifier votre connexion réseau et réessayer."
msgid "Error loading branch data. Please try again."
msgstr "Erreur lors du chargement des données de branche. Veuillez réessayer."
@@ -15420,10 +15625,10 @@ msgid "Error loading branches."
msgstr "Erreur lors du chargement des branches."
msgid "Error loading burndown chart data"
-msgstr ""
+msgstr "Erreur lors du chargement des données du graphique d'avancement"
msgid "Error loading file viewer."
-msgstr ""
+msgstr "Erreur lors du chargement du visualiseur de fichiers."
msgid "Error loading issues"
msgstr "Erreur lors du chargement des tickets"
@@ -15453,46 +15658,43 @@ msgid "Error loading template."
msgstr "Erreur lors du chargement du modèle."
msgid "Error loading viewer"
-msgstr ""
+msgstr "Erreur lors du chargement du visualiseur"
msgid "Error occurred when fetching sidebar data"
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des données de la barre latérale"
msgid "Error occurred when saving assignees"
-msgstr ""
+msgstr "Erreur lors de l'enregistrement des assignés"
msgid "Error occurred when saving reviewers"
msgstr "Une erreur s'est produite lors de l'enregistrement des relecteurs"
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr "Une erreur s'est produite lors de la mise à jour de l'état de %{issuableType}"
-
msgid "Error occurred while updating the issue status"
msgstr "Une erreur s'est produite lors de la mise à jour de l'état du ticket"
msgid "Error occurred. A blocked user cannot be deactivated"
-msgstr ""
+msgstr "Une erreur s'est produite. Un utilisateur bloqué ne peut pas être désactivé"
msgid "Error occurred. A blocked user must be unblocked to be activated"
-msgstr ""
+msgstr "Une erreur s'est produite. Un utilisateur bloqué doit être débloqué pour être activé"
msgid "Error occurred. User was not banned"
-msgstr ""
+msgstr "Une erreur s'est produite. L'utilisateur n'a pas été banni"
msgid "Error occurred. User was not blocked"
-msgstr ""
+msgstr "Une erreur s'est produite. L'utilisateur n'a pas été bloqué"
msgid "Error occurred. User was not confirmed"
-msgstr ""
+msgstr "Une erreur s'est produite. L'utilisateur n'a pas été confirmé"
msgid "Error occurred. User was not unbanned"
msgstr "Une erreur s'est produite. L'utilisateur n'a pas été gracié"
msgid "Error occurred. User was not unblocked"
-msgstr ""
+msgstr "Une erreur s'est produite. L'utilisateur n'a pas été débloqué"
msgid "Error occurred. User was not unlocked"
-msgstr ""
+msgstr "Une erreur s'est produite. L'utilisateur n'a pas été déverrouillé"
msgid "Error parsing CSV file. Please make sure it has"
msgstr "Erreur lors de l'analyse du fichier CSV. Veuillez vous assurer qu'il a"
@@ -15501,13 +15703,13 @@ msgid "Error promoting the note to timeline event: %{error}"
msgstr "Erreur lors de la promotion de la note en événement de chronologie : %{error}"
msgid "Error rendering Markdown preview"
-msgstr ""
+msgstr "Erreur lors du rendu de l'aperçu du Markdown"
msgid "Error saving label update."
msgstr "Erreur lors de la mise à jour de l’étiquette."
msgid "Error setting up editor. Please try again."
-msgstr ""
+msgstr "Erreur lors de la configuration de l'éditeur. Veuillez réessayer."
msgid "Error tracking"
msgstr "Suivi des erreurs"
@@ -15525,14 +15727,11 @@ msgid "Error updating the snippet"
msgstr "Erreur lors de la mise à jour de l'extrait de code"
msgid "Error uploading file"
-msgstr ""
+msgstr "Erreur lors du téléversement du fichier"
msgid "Error uploading file. Please try again."
msgstr "Erreur lors du téléversement du fichier. Veuillez réessayer."
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr "Erreur lors du chargement de la demande de fusion. Veuillez réessayer."
@@ -15540,7 +15739,7 @@ msgid "Error while migrating %{upload_id}: %{error_message}"
msgstr ""
msgid "Error with Akismet. Please check the logs for more info."
-msgstr ""
+msgstr "Erreur avec Akismet. Veuillez vérifier les journaux pour plus d'informations."
msgid "Error: %{error_message}"
msgstr "Erreur : %{error_message}"
@@ -15549,7 +15748,7 @@ msgid "Error: %{error}"
msgstr "Erreur : %{error}"
msgid "Error: Couldn't load some or all of the changes."
-msgstr ""
+msgstr "Erreur : Impossible de charger la totalité ou une partie des modifications."
msgid "Error: No AWS credentials were supplied"
msgstr "Erreur : Aucun identifiant AWS n'a été fourni"
@@ -15570,13 +15769,13 @@ msgid "ErrorTracking|Access token is %{token_in_code_tag}"
msgstr "Le jeton d'accès est %{token_in_code_tag}"
msgid "ErrorTracking|Active"
-msgstr ""
+msgstr "Actif"
msgid "ErrorTracking|After adding your Auth Token, select the Connect button to load projects."
msgstr "Après l'ajout de votre Jeton d'Authentification, sélectionnez le bouton Connecter pour charger les projets."
msgid "ErrorTracking|Auth Token"
-msgstr ""
+msgstr "Jeton d'Authentification"
msgid "ErrorTracking|Click Connect to reestablish the connection to Sentry and activate the dropdown."
msgstr ""
@@ -15588,7 +15787,7 @@ msgid "ErrorTracking|Enable error tracking"
msgstr "Activer le suivi des erreurs"
msgid "ErrorTracking|Error tracking backend"
-msgstr ""
+msgstr "Backend du suivi des erreurs"
msgid "ErrorTracking|If you self-host Sentry, enter your Sentry instance's full URL. If you use Sentry's hosted solution, enter https://sentry.io"
msgstr "Si vous auto-hébergez Sentry, entrez l'URL complète de votre instance Sentry. Si vous utilisez la solution d'hébergement de Sentry, entrez https://sentry.io"
@@ -15600,19 +15799,19 @@ msgid "ErrorTracking|Integrated error tracking is %{epicLinkStart}turned off by
msgstr ""
msgid "ErrorTracking|No projects available"
-msgstr ""
+msgstr "Aucun projet disponible"
msgid "ErrorTracking|Select project"
-msgstr ""
+msgstr "Sélectionner un projet"
msgid "ErrorTracking|To enable project selection, enter a valid Auth Token."
msgstr "Pour activer la sélection de projet, entrez un Jeton d'Authentification valide."
msgid "ErrorTracking|View project settings"
-msgstr ""
+msgstr "Voir les paramètres du projet"
msgid "Errors"
-msgstr ""
+msgstr "Erreurs"
msgid "Errors found on line %{line_number}: %{error_lines}. Please check if these lines have a requirement title."
msgstr "Erreurs trouvées sur la ligne %{line_number} : %{error_lines}. Veuillez vérifier si ces lignes ont un titre d'exigence."
@@ -15663,7 +15862,7 @@ msgid "EscalationPolicies|Add escalation policy"
msgstr "Ajouter une politique d'escalade"
msgid "EscalationPolicies|Add policy"
-msgstr ""
+msgstr "Ajouter une politique"
msgid "EscalationPolicies|Are you sure you want to delete the \"%{escalationPolicy}\" escalation policy? This action cannot be undone."
msgstr "Êtes-vous sûr(e) de vouloir supprimer la politique d'escalade « %{escalationPolicy} » ? Cette action ne peut pas être annulée."
@@ -15750,7 +15949,7 @@ msgid "EventFilterBy|Filter by designs"
msgstr "Filtrer par design"
msgid "EventFilterBy|Filter by epic events"
-msgstr ""
+msgstr "Filtrer par événements d'épopées"
msgid "EventFilterBy|Filter by issue events"
msgstr "Filtrer par événements de ticket"
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15780,13 +16030,13 @@ msgid "Every 3 months"
msgstr "Tous les 3 mois"
msgid "Every 3 months on the %{day} at %{time} %{timezone}"
-msgstr ""
+msgstr "Tous les 3 mois le %{day} à %{time} %{timezone}"
msgid "Every 6 months"
msgstr "Tous les 6 mois"
msgid "Every 6 months on the %{day} at %{time} %{timezone}"
-msgstr ""
+msgstr "Tous les 6 mois le %{day} à %{time} %{timezone}"
msgid "Every day"
msgstr ""
@@ -15798,19 +16048,19 @@ msgid "Every day at %{time} %{timezone}"
msgstr "Tous les jours à %{time} %{timezone}"
msgid "Every month"
-msgstr ""
+msgstr "Tous les mois"
msgid "Every month (Day %{day} at %{time})"
-msgstr ""
+msgstr "Chaque mois (le %{day} à %{time})"
msgid "Every month on the %{day} at %{time} %{timezone}"
-msgstr ""
+msgstr "Tous les mois le %{day} à %{time} %{timezone}"
msgid "Every three months"
-msgstr ""
+msgstr "Tous les trois mois"
msgid "Every two weeks"
-msgstr ""
+msgstr "Toutes les deux semaines"
msgid "Every week"
msgid_plural "Every %d weeks"
@@ -15818,7 +16068,7 @@ msgstr[0] "Toutes les semaines"
msgstr[1] "Toutes les %d semaines"
msgid "Every week (%{weekday} at %{time})"
-msgstr ""
+msgstr "Toutes les semaines (%{weekday} à %{time})"
msgid "Every week on %{day} at %{time} %{timezone}"
msgstr ""
@@ -15842,22 +16092,22 @@ msgid "Everything on your to-do list is marked as done."
msgstr ""
msgid "Everything you need to create a GitLab Pages site using Gatsby"
-msgstr ""
+msgstr "Tout ce dont vous avez besoin pour créer un site GitLab Pages avec Gatsby"
msgid "Everything you need to create a GitLab Pages site using GitBook"
-msgstr ""
+msgstr "Tout ce dont vous avez besoin pour créer un site GitLab Pages avec GitBook"
msgid "Everything you need to create a GitLab Pages site using Hexo"
-msgstr ""
+msgstr "Tout ce dont vous avez besoin pour créer un site GitLab Pages avec Hexo"
msgid "Everything you need to create a GitLab Pages site using Hugo"
-msgstr ""
+msgstr "Tout ce dont vous avez besoin pour créer un site GitLab Pages avec Hugo"
msgid "Everything you need to create a GitLab Pages site using Jekyll"
-msgstr ""
+msgstr "Tout ce dont vous avez besoin pour créer un site GitLab Pages avec Jekyll"
msgid "Everything you need to create a GitLab Pages site using Middleman"
-msgstr ""
+msgstr "Tout ce dont vous avez besoin pour créer un site GitLab Pages avec Middleman"
msgid "Everything you need to create a GitLab Pages site using Pelican"
msgstr "Tout ce dont vous avez besoin pour créer un site GitLab Pages avec Pelican"
@@ -15875,7 +16125,7 @@ msgid "Example: @sub\\.company\\.com$"
msgstr ""
msgid "Examples"
-msgstr ""
+msgstr "Exemples"
msgid "Except policy:"
msgstr ""
@@ -15890,7 +16140,10 @@ msgid "Excluding merge commits. Limited to 6,000 commits."
msgstr ""
msgid "Execution time"
-msgstr ""
+msgstr "Durée d’exécution"
+
+msgid "Executive Dashboard"
+msgstr "Tableau de bord Exécutif"
msgid "Existing branch name, tag, or commit SHA"
msgstr "Nom de branche, étiquette ou SHA de commit existant"
@@ -15920,16 +16173,16 @@ msgid "Expand all threads"
msgstr "Étendre tous les fils de conversation"
msgid "Expand approvers"
-msgstr ""
+msgstr "Étendre les approbateurs"
msgid "Expand file"
-msgstr ""
+msgstr "Étendre le fichier"
msgid "Expand issues"
msgstr "Étendre les tickets"
msgid "Expand jobs"
-msgstr ""
+msgstr "Étendre les tâches"
msgid "Expand merge details"
msgstr "Étendre les détails de fusion"
@@ -15938,10 +16191,10 @@ msgid "Expand milestones"
msgstr "Étendre les jalons"
msgid "Expand panel"
-msgstr ""
+msgstr "Étendre le panneau"
msgid "Expand settings section"
-msgstr ""
+msgstr "Étendre la section des paramètres"
msgid "Expand sidebar"
msgstr "Étendre la barre latérale"
@@ -15949,12 +16202,18 @@ msgstr "Étendre la barre latérale"
msgid "Expected documents: %{expected_documents}"
msgstr "Documents attendus : %{expected_documents}"
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr "Doit être un choix unique entre Utilisateur, Espace de noms et Projet."
-msgid "Expiration"
+msgid "Experiments"
msgstr ""
+msgid "Expiration"
+msgstr "Expiration"
+
msgid "Expiration date"
msgstr "Date d’expiration"
@@ -16013,7 +16272,7 @@ msgid "Explore public projects"
msgstr "Explorer les projets publics"
msgid "Explore snippets"
-msgstr ""
+msgstr "Explorer les extraits"
msgid "Explore topics"
msgstr "Explorer les sujets"
@@ -16031,7 +16290,7 @@ msgid "Export commit custody report"
msgstr "Exporter le rapport des consignations du commit"
msgid "Export group"
-msgstr ""
+msgstr "Exporter le groupe"
msgid "Export issues"
msgstr "Exporter les tickets"
@@ -16052,13 +16311,13 @@ msgid "Export this project with all its related data in order to move it to a ne
msgstr "Exportez ce projet avec toutes ses données associées afin de le déplacer vers une nouvelle instance de GitLab. Lorsque le fichier exporté est prêt, vous pouvez le télécharger à partir de cette page ou du lien de téléchargement présent dans le courriel de notification que vous recevrez. Vous pouvez ensuite l'importer lors de la création d'un nouveau projet. %{link_start}En savoir plus.%{link_end}"
msgid "Export variable to pipelines running on protected branches and tags only."
-msgstr ""
+msgstr "Exporter la variable vers les pipelines qui s'exécutent uniquement sur des branches et des étiquettes protégées."
msgid "Exported requirements"
msgstr "Exigences exportées"
msgid "External URL"
-msgstr ""
+msgstr "URL externe"
msgid "External User:"
msgstr "Utilisateur Externe :"
@@ -16067,10 +16326,10 @@ msgid "External authorization denied access to this project"
msgstr "L’autorisation externe a refusé l’accès à ce projet"
msgid "External storage URL"
-msgstr ""
+msgstr "URL du stockage externe"
msgid "External storage authentication token"
-msgstr ""
+msgstr "Jeton d'authentification du stockage externe"
msgid "External storage for repository static objects"
msgstr "Stockage externe pour les objets statiques du dépôt"
@@ -16174,7 +16433,10 @@ msgid "Failed on"
msgstr ""
msgid "Failed to add a Zoom meeting"
-msgstr ""
+msgstr "Échec de l'ajout d'une réunion Zoom"
+
+msgid "Failed to add a resource link"
+msgstr "Échec de l'ajout d'un lien de ressource"
msgid "Failed to apply commands."
msgstr ""
@@ -16194,7 +16456,7 @@ msgid "Failed to cancel auto stop because failed to update the environment."
msgstr "Échec de l'annulation de l'arrêt automatique car la mise à jour de l'environnement a échoué."
msgid "Failed to cancel auto stop because the environment is not set as auto stop."
-msgstr ""
+msgstr "Échec de l'annulation de l'arrêt automatique car l'environnement n'est pas configuré pour s'arrêter automatiquement."
msgid "Failed to cancel auto stop because you do not have permission to update the environment."
msgstr "Échec de l'annulation de l'arrêt automatique car vous n'êtes pas autorisé à mettre à jour l'environnement."
@@ -16212,7 +16474,7 @@ msgid "Failed to clone this issue: wrong parameters."
msgstr "Impossible de cloner ce ticket : paramètres incorrects."
msgid "Failed to create a branch for this issue. Please try again."
-msgstr ""
+msgstr "Échec de la création d'une branche pour ce ticket. Veuillez réessayer."
msgid "Failed to create a to-do item for the design."
msgstr ""
@@ -16223,14 +16485,11 @@ msgstr "Échec de la création du framework"
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr "Échec de la création d'un nouveau jeton d'accès : %{token_response_message}"
-
msgid "Failed to create repository"
-msgstr ""
+msgstr "Échec de la création du dépôt"
msgid "Failed to create resources"
-msgstr ""
+msgstr "Échec de la création de ressources"
msgid "Failed to create wiki"
msgstr "Échec de la création du wiki"
@@ -16254,19 +16513,19 @@ msgid "Failed to find users for %{missing}"
msgstr ""
msgid "Failed to generate export, please try again later."
-msgstr ""
+msgstr "Échec de la génération de l'export, veuillez réessayer plus tard."
msgid "Failed to generate report, please try again after sometime"
-msgstr ""
+msgstr "Échec de la génération du rapport, veuillez réessayer après quelque temps"
msgid "Failed to get ref."
-msgstr ""
+msgstr "Échec d'obtention de la réf."
msgid "Failed to install."
-msgstr ""
+msgstr "Échec de l'installation."
msgid "Failed to load"
-msgstr ""
+msgstr "Échec du chargement"
msgid "Failed to load Roadmap"
msgstr "Échec du chargement de la Feuille de route"
@@ -16278,7 +16537,7 @@ msgid "Failed to load assignees. Please try again."
msgstr "Impossible de charger les assigné(e)s. Veuillez réessayer."
msgid "Failed to load authors. Please try again."
-msgstr ""
+msgstr "Échec du chargement des auteurs. Veuillez réessayer."
msgid "Failed to load branches. Please try again."
msgstr "Échec du chargement des branches. Veuillez réessayer."
@@ -16287,7 +16546,7 @@ msgid "Failed to load deploy keys."
msgstr "Échec du chargement des clés de déploiement."
msgid "Failed to load error details from Sentry."
-msgstr ""
+msgstr "Échec du chargement des détails de l'erreur de Sentry."
msgid "Failed to load errors from Sentry."
msgstr "Impossible de charger les erreurs depuis Sentry."
@@ -16302,7 +16561,7 @@ msgid "Failed to load groups."
msgstr "Échec du chargement des groupes."
msgid "Failed to load iteration cadences."
-msgstr ""
+msgstr "Échec du chargement des cadences d'itération."
msgid "Failed to load iterations."
msgstr "Échec du chargement des itérations."
@@ -16317,13 +16576,13 @@ msgid "Failed to load milestones. Please try again."
msgstr "Échec du chargement des jalons. Veuillez réessayer."
msgid "Failed to load projects"
-msgstr ""
+msgstr "Échec du chargement des projets"
msgid "Failed to load related branches"
-msgstr ""
+msgstr "Échec du chargement des branches associées"
msgid "Failed to load stacktrace."
-msgstr ""
+msgstr "Échec du chargement de la trace de pile."
msgid "Failed to make repository read-only. %{reason}"
msgstr "Impossible de rendre le dépôt en lecture seule. %{reason}"
@@ -16332,31 +16591,31 @@ msgid "Failed to mark this issue as a duplicate because referenced issue was not
msgstr ""
msgid "Failed to move this issue because label was not found."
-msgstr ""
+msgstr "Échec du déplacement de ce ticket car l'étiquette est introuvable."
msgid "Failed to move this issue because only a single label can be provided."
-msgstr ""
+msgstr "Échec du déplacement de ce ticket car une seule étiquette peut être fournie."
msgid "Failed to move this issue because target project doesn't exist."
-msgstr ""
+msgstr "Échec du déplacement de ce ticket car le projet cible n'existe pas."
msgid "Failed to promote issue to incident"
msgstr "La promotion du ticket en incident a échoué"
msgid "Failed to promote label due to internal error. Please contact administrators."
-msgstr ""
+msgstr "Échec de la promotion de l'étiquette en raison d'une erreur interne. Veuillez contacter les administrateurs."
msgid "Failed to protect the branch"
-msgstr ""
+msgstr "Échec de la protection de la branche"
msgid "Failed to protect the environment"
-msgstr ""
+msgstr "Échec de la protection de l'environnement"
msgid "Failed to publish issue on status page."
-msgstr ""
+msgstr "Échec de la publication du ticket sur la page d'état."
msgid "Failed to remove a Zoom meeting"
-msgstr ""
+msgstr "Échec de la suppression d'une réunion Zoom"
msgid "Failed to remove a to-do item for the design."
msgstr ""
@@ -16371,10 +16630,10 @@ msgid "Failed to remove timelog"
msgstr "Échec de la suppression d'une entrée de temps passé"
msgid "Failed to remove user identity."
-msgstr ""
+msgstr "Échec de la suppression de l'identité de l'utilisateur."
msgid "Failed to remove user key."
-msgstr ""
+msgstr "Échec de la suppression de la clé d'utilisateur."
msgid "Failed to retrieve page"
msgstr "Échec de la récupération de la page"
@@ -16383,19 +16642,19 @@ msgid "Failed to save merge conflicts resolutions. Please try again!"
msgstr ""
msgid "Failed to save new settings"
-msgstr ""
+msgstr "Échec de l'enregistrement des nouveaux paramètres"
msgid "Failed to save preferences (%{error_message})."
msgstr "Impossible d'enregistrer les préférences (%{error_message})."
msgid "Failed to save preferences."
-msgstr ""
+msgstr "Échec de l'enregistrement des préférences."
msgid "Failed to save timelog"
msgstr "Échec de la sauvegarde d'une entrée de temps passé"
msgid "Failed to set due date because the date format is invalid."
-msgstr ""
+msgstr "Échec de la définition de la date d'échéance car le format de date n'est pas valide."
msgid "Failed to set iteration on this issue. Please try again."
msgstr ""
@@ -16407,25 +16666,22 @@ msgid "Failed to toggle the to-do status for the design."
msgstr ""
msgid "Failed to update branch!"
-msgstr ""
+msgstr "Échec de la mise à jour de la branche !"
msgid "Failed to update environment!"
-msgstr ""
+msgstr "Échec de la mise à jour de l'environnement !"
msgid "Failed to update framework"
msgstr "Échec de la mise à jour du framework"
msgid "Failed to update issue status"
-msgstr ""
+msgstr "Échec de la mise à jour de l'état du ticket"
msgid "Failed to update the Canary Ingress."
msgstr "Échec de la mise à jour du Canari Ingress."
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
-msgstr ""
+msgstr "Échec de la mise à niveau."
msgid "Failed to upload object map file"
msgstr ""
@@ -16446,7 +16702,7 @@ msgid "Favicon"
msgstr "Favicon"
msgid "Favicon was successfully removed."
-msgstr ""
+msgstr "La favicon a été supprimée avec succès."
msgid "Favicon will be removed. Are you sure?"
msgstr "La favicon sera supprimée. Êtesâ€vous sûr(e) ?"
@@ -16461,10 +16717,10 @@ msgid "Feature flag status"
msgstr "État de l'indicateur de fonctionnalité"
msgid "Feature flag was not removed."
-msgstr ""
+msgstr "L'Indicateur de fonctionnalité n'a pas été supprimé."
msgid "Feature flag was successfully removed."
-msgstr ""
+msgstr "L'indicateur de fonctionnalité a été supprimé avec succès."
msgid "FeatureFlags|%d user"
msgid_plural "FeatureFlags|%d users"
@@ -16484,7 +16740,7 @@ msgid "FeatureFlags|%{percent} randomly"
msgstr ""
msgid "FeatureFlags|* (All Environments)"
-msgstr ""
+msgstr "* (Tous les Environnements)"
msgid "FeatureFlags|API URL"
msgstr "URL de l’API"
@@ -16502,7 +16758,7 @@ msgid "FeatureFlags|All Users"
msgstr "Tous les utilisateurs"
msgid "FeatureFlags|All users"
-msgstr ""
+msgstr "Tous les utilisateurs"
msgid "FeatureFlags|Configure"
msgstr "Configurer"
@@ -16517,10 +16773,10 @@ msgid "FeatureFlags|Create feature flag"
msgstr "Créer un indicateur de fonctionnalité"
msgid "FeatureFlags|Delete %{name}?"
-msgstr ""
+msgstr "Supprimer %{name} ?"
msgid "FeatureFlags|Delete feature flag"
-msgstr ""
+msgstr "Supprimer l'indicateur de fonctionnalité"
msgid "FeatureFlags|Description"
msgstr "Description"
@@ -16553,22 +16809,22 @@ msgid "FeatureFlags|Feature Flag has no strategies"
msgstr "L'indicateur de fonctionnalité ne possède pas de stratégie"
msgid "FeatureFlags|Feature Flags"
-msgstr ""
+msgstr "Indicateurs de Fonctionnalités"
msgid "FeatureFlags|Feature flag %{name} will be removed. Are you sure?"
-msgstr ""
+msgstr "L’indicateur de fonctionnalité %{name} va être supprimé. Êtesâ€vous sûr(e) ?"
msgid "FeatureFlags|Feature flags allow you to configure your code into different flavors by dynamically toggling certain functionality."
msgstr ""
msgid "FeatureFlags|Feature flags limit reached (%{featureFlagsLimit}). Delete one or more feature flags before adding new ones."
-msgstr ""
+msgstr "Limite des indicateurs de fonctionnalité atteinte (%{featureFlagsLimit}). Supprimez un ou plusieurs indicateurs de fonctionnalité avant d'en ajouter de nouveaux."
msgid "FeatureFlags|Get started with feature flags"
-msgstr ""
+msgstr "Premiers pas avec les indicateurs de fonctionnalité"
msgid "FeatureFlags|ID"
-msgstr ""
+msgstr "ID"
msgid "FeatureFlags|Inactive"
msgstr "Inactif"
@@ -16583,13 +16839,13 @@ msgid "FeatureFlags|Instance ID"
msgstr "Identifiant d’instance"
msgid "FeatureFlags|List details"
-msgstr ""
+msgstr "Détails de la liste"
msgid "FeatureFlags|Loading feature flags"
msgstr ""
msgid "FeatureFlags|More information"
-msgstr ""
+msgstr "Plus d'informations"
msgid "FeatureFlags|Name"
msgstr "Nom"
@@ -16604,7 +16860,7 @@ msgid "FeatureFlags|New User List"
msgstr "Nouvelle Liste d'Utilisateurs"
msgid "FeatureFlags|New feature flag"
-msgstr ""
+msgstr "Nouvel indicateur de fonctionnalité"
msgid "FeatureFlags|No user list selected"
msgstr "Aucune liste d'utilisateurs sélectionnée"
@@ -16619,7 +16875,7 @@ msgid "FeatureFlags|Percent rollout must be an integer number between 0 and 100"
msgstr "Le pourcentage de déploiement doit être un nombre entier compris entre 0 et 100"
msgid "FeatureFlags|Remove"
-msgstr ""
+msgstr "Supprimer"
msgid "FeatureFlags|Search code references"
msgstr "Rechercher des références de code"
@@ -16634,16 +16890,16 @@ msgid "FeatureFlags|Strategies"
msgstr "Stratégies"
msgid "FeatureFlags|There was an error fetching the feature flags."
-msgstr ""
+msgstr "Une erreur s’est produite lors de la récupération des indicateurs de fonctionnalité."
msgid "FeatureFlags|To prevent accidental actions we ask you to confirm your intention. Please type %{projectName} to proceed or close this modal to cancel."
msgstr "Pour empêcher des actions accidentelles, nous vous demandons de confirmer votre intention. Veuillez taper %{projectName} pour continuer ou fermer ce dialogue pour annuler."
msgid "FeatureFlags|Try again in a few moments or contact your support team."
-msgstr ""
+msgstr "Réessayez dans quelques instants ou contactez votre équipe d'assistance."
msgid "FeatureFlags|User IDs"
-msgstr ""
+msgstr "IDs utilisateur"
msgid "FeatureFlags|User List"
msgstr "Liste d'Utilisateurs"
@@ -16658,7 +16914,7 @@ msgid "FeatureFlag|Percentage"
msgstr "Pourcentage"
msgid "FeatureFlag|Select a user list"
-msgstr ""
+msgstr "Sélectionner une liste d'utilisateurs"
msgid "FeatureFlag|Select the environment scope for this feature flag"
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr "févr."
msgid "February"
msgstr "février"
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16688,7 +16947,7 @@ msgid "Fetching incoming email"
msgstr ""
msgid "File"
-msgstr ""
+msgstr "Fichier"
msgid "File %{current} of %{total}"
msgstr "Fichier %{current} sur %{total}"
@@ -16703,13 +16962,13 @@ msgid "File Tree"
msgstr ""
msgid "File added"
-msgstr ""
+msgstr "Fichier ajouté"
msgid "File browser"
-msgstr ""
+msgstr "Navigateur de fichiers"
msgid "File deleted"
-msgstr ""
+msgstr "Fichier supprimé"
msgid "File hooks are similar to system hooks but are executed as files instead of sending data to a URL."
msgstr "Les fichiers « hooks » sont similaires aux « hooks » système mais sont exécutés sous forme de fichiers plutôt que par l'envoi de données vers une URL."
@@ -16718,7 +16977,7 @@ msgid "File mode changed from %{a_mode} to %{b_mode}"
msgstr ""
msgid "File moved"
-msgstr ""
+msgstr "Fichier déplacé"
msgid "File name"
msgstr ""
@@ -16736,7 +16995,7 @@ msgid "File too large. Secure Files must be less than %{limit} MB."
msgstr "Fichier trop volumineux. Les Fichiers Sécurisés doivent faire moins de %{limit} Mo."
msgid "File upload error."
-msgstr ""
+msgstr "Erreur du téléversement du fichier."
msgid "Filename"
msgstr "Nom du fichier"
@@ -16751,7 +17010,7 @@ msgid "Files breadcrumb"
msgstr ""
msgid "Files with large changes are collapsed by default."
-msgstr ""
+msgstr "Les fichiers avec des modifications importantes sont réduits par défaut."
msgid "Files, directories, and submodules in the path %{path} for commit reference %{ref}"
msgstr ""
@@ -16769,10 +17028,10 @@ msgid "Filter by %{page_context_word} that are currently open."
msgstr "Filtrer sur les %{page_context_word} qui sont actuellement ouvert(e)s."
msgid "Filter by Git revision"
-msgstr ""
+msgstr "Filtrer par révision Git"
msgid "Filter by issues that are currently closed."
-msgstr ""
+msgstr "Filtrer sur les tickets qui sont actuellement fermés."
msgid "Filter by issues that are currently opened."
msgstr "Filtrer sur les tickets qui sont actuellement ouverts."
@@ -16784,10 +17043,7 @@ msgid "Filter by merge requests that are currently closed and unmerged."
msgstr "Filtrer par demandes de fusion qui sont actuellement fermées et non fusionnées."
msgid "Filter by merge requests that are currently merged."
-msgstr ""
-
-msgid "Filter by milestone"
-msgstr "Filtrer par jalon"
+msgstr "Filtrer sur les demandes de fusion actuellement fusionnées."
msgid "Filter by milestone name"
msgstr "Filtrer par nom de jalon"
@@ -16808,22 +17064,22 @@ msgid "Filter parameters are not valid. Make sure that the end date is after the
msgstr "Les paramètres du filtre ne sont pas valides. Assurez-vous que la date de fin est postérieure à la date de début."
msgid "Filter pipelines"
-msgstr ""
+msgstr "Filtrer les pipelines"
msgid "Filter results"
-msgstr ""
+msgstr "Filtrer les résultats"
msgid "Filter results by group"
-msgstr ""
+msgstr "Filtrer les résultats par groupe"
msgid "Filter results by project"
-msgstr ""
+msgstr "Filtrer les résultats par projet"
msgid "Filter results..."
-msgstr ""
+msgstr "Filtrer les résultats..."
msgid "Filter users"
-msgstr ""
+msgstr "Filtrer les utilisateurs"
msgid "Filter..."
msgstr "Filtrer…"
@@ -16832,7 +17088,7 @@ msgid "Find File"
msgstr "Rechercher un fichier"
msgid "Find bugs in your code with API fuzzing."
-msgstr ""
+msgstr "Trouvez des bogues dans votre code avec des tests d'API par injection de données aléatoires."
msgid "Find bugs in your code with coverage-guided fuzzing."
msgstr "Trouvez les bogues de votre code avec des tests à données aléatoires guidés par la couverture."
@@ -16853,10 +17109,10 @@ msgid "Fingerprints"
msgstr "Empreintes"
msgid "Finish editing this message first!"
-msgstr ""
+msgstr "Terminez d'abord l'édition de ce message !"
msgid "Finish review"
-msgstr ""
+msgstr "Terminer la revue de code"
msgid "Finish setting up your dedicated account for %{group_name}."
msgstr "Terminer la configuration de votre compte dédié pour %{group_name}."
@@ -16874,7 +17130,7 @@ msgid "First day of the week"
msgstr "Premier jour de la semaine"
msgid "First name"
-msgstr ""
+msgstr "Prénom"
msgid "First seen"
msgstr ""
@@ -16961,7 +17217,7 @@ msgid "For additional information, review your group membership: %{link_to} or c
msgstr "Pour des informations supplémentaires, examinez votre adhésion au groupe : %{link_to} ou contactez le propriétaire de votre groupe."
msgid "For each job, clone the repository."
-msgstr ""
+msgstr "Pour chaque tâche, cloner le dépôt."
msgid "For each job, re-use the project workspace. If the workspace doesn't exist, use %{code_open}git clone%{code_close}."
msgstr "Pour chaque tâche, réutiliser l'espace de travail du projet. S'il n'en existe pas, utiliser %{code_open}git clone%{code_close}."
@@ -16985,7 +17241,7 @@ msgid "For investigating IT service disruptions or outages"
msgstr "Pour enquêter sur les perturbations ou les pannes des services informatiques"
msgid "For more info, read the documentation."
-msgstr ""
+msgstr "Pour en savoir plus, lisez la documentation."
msgid "For more information on how the number of active users is calculated, see the %{self_managed_subscriptions_doc_link} documentation."
msgstr "Pour plus d'informations sur la façon dont le nombre d'utilisateurs actifs est calculé, consultez la %{self_managed_subscriptions_doc_link}documentation."
@@ -16996,9 +17252,12 @@ msgstr "Pour plus d’informations, consultez "
msgid "For more information, see the File Hooks documentation."
msgstr "Pour plus d'informations, reportez-vous à la documentation sur les fichiers « Hooks »."
-msgid "Forgot your password?"
+msgid "Forbidden"
msgstr ""
+msgid "Forgot your password?"
+msgstr "Mot de passe oublié ?"
+
msgid "Fork"
msgstr ""
@@ -17087,13 +17346,13 @@ msgid "Forks"
msgstr ""
msgid "Format: %{dateFormat}"
-msgstr ""
+msgstr "Format : %{dateFormat}"
msgid "Forward %{package_type} package requests to the %{registry_type} Registry if the packages are not found in the GitLab Package Registry"
msgstr "Transférer les demandes de paquets %{package_type} au Registre %{registry_type} dans le cas où les paquets ne sont pas trouvés dans le Registre de Paquets de GitLab"
msgid "Found errors in your %{gitlab_ci_yml}:"
-msgstr ""
+msgstr "Erreurs trouvées dans votre %{gitlab_ci_yml} :"
msgid "Found errors in your .gitlab-ci.yml:"
msgstr "Erreurs trouvées dans votre fichier .gitlab-ci.yml :"
@@ -17102,7 +17361,7 @@ msgid "Framework successfully deleted"
msgstr "Framework supprimé avec succès"
msgid "Free"
-msgstr ""
+msgstr "Gratuit"
msgid "Free Trial of GitLab.com Ultimate"
msgstr "Essai Gratuit de GitLab.com Ultimate"
@@ -17158,7 +17417,7 @@ msgid "Fri"
msgstr "Ven"
msgid "Friday"
-msgstr ""
+msgstr "Vendredi"
msgid "From"
msgstr ""
@@ -17187,19 +17446,19 @@ msgid "Full log"
msgstr "Journaux complets"
msgid "Full name"
-msgstr ""
+msgstr "Nom complet"
msgid "GCP region configured"
-msgstr ""
+msgstr "Région GCP configurée"
msgid "GPG Key ID:"
-msgstr ""
+msgstr "ID de la clé GPG :"
msgid "GPG Keys"
msgstr "Clefs GPG"
msgid "GPG keys allow you to verify signed commits."
-msgstr ""
+msgstr "Les clés GPG vous permettent de vérifier les commits signés."
msgid "GPG signature (loading...)"
msgstr ""
@@ -17223,7 +17482,7 @@ msgid "Generate group access tokens scoped to this group for your applications t
msgstr "Générer des jetons d'accès au groupe, de portée limitée à celui-ci, pour vos applications qui ont besoin de l'API GitLab."
msgid "Generate new export"
-msgstr ""
+msgstr "Générer un nouvel export"
msgid "Generate project access tokens scoped to this project for your applications that need access to the GitLab API."
msgstr "Générer des jetons d'accès au projet, de portée limitée au projet, pour vos applications qui ont besoin de l'API GitLab."
@@ -17287,10 +17546,10 @@ msgid "Geo|%{label} %{timeAgo}"
msgstr "%{label} %{timeAgo}"
msgid "Geo|%{label} can't be blank"
-msgstr ""
+msgstr "%{label} ne peut pas être vide"
msgid "Geo|%{label} should be between 1-999"
-msgstr ""
+msgstr "%{label} doit être compris entre 1 et 999"
msgid "Geo|%{name} is scheduled for forced re-download"
msgstr "%{name} est programmé pour le reâ€téléchargement forcé"
@@ -17383,10 +17642,10 @@ msgid "Geo|Data type"
msgstr "Type de données"
msgid "Geo|Disabled"
-msgstr ""
+msgstr "Désactivé"
msgid "Geo|Discover GitLab Geo"
-msgstr ""
+msgstr "Découvrez GitLab Geo"
msgid "Geo|Does not match the primary storage configuration"
msgstr ""
@@ -17404,7 +17663,7 @@ msgid "Geo|Errors:"
msgstr "Erreurs :"
msgid "Geo|External URL"
-msgstr ""
+msgstr "URL externe"
msgid "Geo|Failed"
msgstr "En échec"
@@ -17413,7 +17672,7 @@ msgid "Geo|File synchronization concurrency limit"
msgstr "Limite de synchronisations de fichiers simultanées"
msgid "Geo|Filter Geo sites"
-msgstr ""
+msgstr "Filtrer les sites Geo"
msgid "Geo|Filter by name"
msgstr "Filtrer par nom"
@@ -17425,7 +17684,7 @@ msgid "Geo|Full details"
msgstr "Détails complets"
msgid "Geo|Geo Settings"
-msgstr ""
+msgstr "Paramètres de Geo"
msgid "Geo|Geo Status"
msgstr "État de Geo"
@@ -17467,10 +17726,10 @@ msgid "Geo|Internal URL (optional)"
msgstr "URL interne (facultatif)"
msgid "Geo|Last event ID from primary"
-msgstr ""
+msgstr "ID du dernier événement du nœud principal"
msgid "Geo|Last event ID processed by cursor"
-msgstr ""
+msgstr "ID du dernier événement traité par le curseur"
msgid "Geo|Last repository check run"
msgstr ""
@@ -17632,7 +17891,7 @@ msgid "Geo|Retry count"
msgstr "Nombre de tentatives"
msgid "Geo|Reverify"
-msgstr ""
+msgstr "Revérifier"
msgid "Geo|Reverify all"
msgstr "Tout revérifier"
@@ -17722,7 +17981,7 @@ msgid "Geo|The site is currently %{minutes_behind} behind the primary site."
msgstr "Le site est actuellement %{minutes_behind} derrière le site principal."
msgid "Geo|There are no %{replicable_type} to show"
-msgstr ""
+msgstr "Il n’y a pas de %{replicable_type} à afficher"
msgid "Geo|There are no %{replicable} to show"
msgstr "Il n'y a pas de %{replicable} à afficher"
@@ -17746,7 +18005,7 @@ msgid "Geo|There was an error updating the Geo Settings"
msgstr "Une erreur s'est produite lors de la mise à jour des paramètres de Geo"
msgid "Geo|This GitLab instance is subscribed to the %{insufficient_license} tier. Geo is only available for users who have at least a Premium subscription."
-msgstr ""
+msgstr "Cette instance GitLab dispose d'un abonnement au forfait %{insufficient_license}. Geo n'est disponible que pour les utilisateurs qui possèdent au minimum un abonnement Premium."
msgid "Geo|This will resync all %{replicableType}. It may take some time to complete. Are you sure you want to continue?"
msgstr "Cette action resynchronisera la totalité des %{replicableType}. Cela peut prendre un certain temps pour s'exécuter. Êtes-vous sûr(e) de vouloir continuer ?"
@@ -17829,9 +18088,6 @@ msgstr "secondaire"
msgid "Get a free instance review"
msgstr "Obtenez une revue d’instance gratuite"
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr "Obtenir un abonnement au support"
@@ -17842,7 +18098,7 @@ msgid "Get started with GitLab"
msgstr ""
msgid "Get started with error tracking"
-msgstr ""
+msgstr "Premiers pas avec le suivi des erreurs"
msgid "Get started with performance monitoring"
msgstr ""
@@ -17851,7 +18107,7 @@ msgid "Get started!"
msgstr ""
msgid "Getting started with releases"
-msgstr ""
+msgstr "Premiers pas avec les versions"
msgid "Git"
msgstr "Git"
@@ -17863,7 +18119,7 @@ msgid "Git LFS Rate Limits"
msgstr "Limitations de Fréquence Git LFS"
msgid "Git LFS is not enabled on this GitLab server, contact your admin."
-msgstr ""
+msgstr "Git LFS n'est pas activé sur ce serveur GitLab, contactez votre administrateur."
msgid "Git LFS objects will be synced if LFS is %{docs_link_start}enabled for the project%{docs_link_end}. Push mirrors will %{strong_open}not%{strong_close} sync LFS objects over SSH."
msgstr "Les objets Git LFS seront synchronisés si LFS est %{docs_link_start}activé sur le projet%{docs_link_end}. Les miroirs push ne synchroniseront %{strong_open}pas%{strong_close} les objets LFS via SSH."
@@ -17944,7 +18200,7 @@ msgid "GitLab"
msgstr "GitLab"
msgid "GitLab (self-managed)"
-msgstr ""
+msgstr "GitLab (autogéré)"
msgid "GitLab / Unsubscribe"
msgstr "GitLab / Se désabonner"
@@ -17958,6 +18214,12 @@ msgstr "Demande de Compte GitLab"
msgid "GitLab Billing Team."
msgstr "Équipe de facturation GitLab."
+msgid "GitLab Community Edition"
+msgstr "GitLab Édition Communautaire"
+
+msgid "GitLab Enterprise Edition"
+msgstr "GitLab Édition Entreprise"
+
msgid "GitLab Error Tracking"
msgstr "Suivi d'Erreurs de GitLab"
@@ -17971,7 +18233,7 @@ msgid "GitLab KAS"
msgstr "GitLab KAS"
msgid "GitLab Pages"
-msgstr ""
+msgstr "GitLab Pages"
msgid "GitLab Shell"
msgstr "GitLab Shell"
@@ -18001,16 +18263,19 @@ msgid "GitLab events trigger webhooks. Use the request details of a webhook to h
msgstr ""
msgid "GitLab export"
-msgstr ""
+msgstr "Export GitLab"
msgid "GitLab for Jira Cloud"
msgstr ""
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 ""
msgid "GitLab informs you if a new version is available. %{link_start}What information does GitLab Inc. collect?%{link_end}"
-msgstr ""
+msgstr "GitLab vous informe si une nouvelle version est disponible. %{link_start}Quelles sont les informations collectées par GitLab Inc. ?%{link_end}"
msgid "GitLab is a complete DevOps platform, delivered as a single application, fundamentally changing the way Development, Security, and Ops teams collaborate"
msgstr ""
@@ -18025,13 +18290,13 @@ msgid "GitLab is free to use. Many features for larger teams are part of our %{l
msgstr "L'utilisation de GitLab est gratuite. De nombreuses fonctionnalités à destination de grandes équipes font parties de nos %{link_start}produits payants%{link_end}. Vous pouvez essayer Ultimate gratuitement sans aucune obligation ni information de paiement."
msgid "GitLab is obtaining a Let's Encrypt SSL certificate for this domain. This process can take some time. Please try again later."
-msgstr ""
+msgstr "GitLab est en train d'obtenir un certificat SSL Let's Encrypt pour ce domaine. Ce processus peut prendre du temps. Veuillez réessayer plus tard."
msgid "GitLab is open source software to collaborate on code."
msgstr "GitLab est un logiciel libre pour collaborer sur du code."
msgid "GitLab is undergoing maintenance"
-msgstr ""
+msgstr "GitLab est actuellement en maintenance"
msgid "GitLab logo"
msgstr "Logo GitLab"
@@ -18052,14 +18317,11 @@ msgid "GitLab uses %{linkStart}Sidekiq%{linkEnd} to process background jobs"
msgstr "GitLab utilise %{linkStart}Sidekiq%{linkEnd} pour traiter les tâches en arrière-plan"
msgid "GitLab version"
-msgstr ""
+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.com"
-msgstr "GitLab.com"
-
msgid "GitLab.com (SaaS)"
msgstr "GitLab.com (SaaS)"
@@ -18070,22 +18332,22 @@ msgid "GitLabPagesDomains|Retry"
msgstr "Réessayer"
msgid "GitLabPages|%{domain} is not verified. To learn how to verify ownership, visit your %{link_start}domain details%{link_end}."
-msgstr ""
+msgstr "%{domain} n'est pas vérifié. Pour savoir comment en vérifier la propriété, consultez les %{link_start}détails de votre domaine%{link_end}."
msgid "GitLabPages|Access Control is enabled for this Pages website; only authorized users will be able to access it. To make your website publicly available, navigate to your project's %{strong_start}Settings &gt; General &gt; Visibility%{strong_end} and select %{strong_start}Everyone%{strong_end} in pages section. Read the %{link_start}documentation%{link_end} for more information."
msgstr "Le Contrôle d’Accès est activé pour ce site web Pages ; seuls les utilisateurs autorisés seront en mesure d’y accéder. Pour rendre votre site web accessible au public, accédez à %{strong_start}Paramètres &gt; Général &gt; Visibilité%{strong_end} dans votre projet et sélectionnez %{strong_start}Tout le monde%{strong_end} dans la section des pages. Lisez la %{link_start}documentation%{link_end} pour plus d'informations."
msgid "GitLabPages|Access pages"
-msgstr ""
+msgstr "Accéder aux pages"
msgid "GitLabPages|Are you sure?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) ?"
msgid "GitLabPages|Can be overridden per project. For no limit, enter 0. To inherit the value, leave empty."
msgstr "Peut être outrepassé au niveau du projet. Pour supprimer la limite, entrez 0. Pour hériter de la valeur, laissez vide."
msgid "GitLabPages|Certificate: %{subject}"
-msgstr ""
+msgstr "Certificat : %{subject}"
msgid "GitLabPages|Check the Pipeline Status"
msgstr "Vérifier l'État du Pipeline"
@@ -18094,7 +18356,7 @@ msgid "GitLabPages|Configure pages"
msgstr ""
msgid "GitLabPages|Domains"
-msgstr ""
+msgstr "Domaines"
msgid "GitLabPages|Edit"
msgstr "Éditer"
@@ -18103,7 +18365,7 @@ msgid "GitLabPages|Expired"
msgstr ""
msgid "GitLabPages|Force HTTPS (requires valid certificates)"
-msgstr ""
+msgstr "Forcer le HTTPS (nécessite des certificats valides)"
msgid "GitLabPages|GitLab Pages are disabled for this project. You can enable them on your project's %{strong_start}Settings &gt; General &gt; Visibility%{strong_end} page."
msgstr "Les Pages GitLab de ce projet sont désactivées. Vous pouvez les activer sur la page %{strong_start}Paramètres &gt; Général &gt; Visibilité%{strong_end} de votre projet."
@@ -18112,16 +18374,16 @@ msgid "GitLabPages|Maximum size (MB)"
msgstr "Taille maximale (Mo)"
msgid "GitLabPages|New Domain"
-msgstr ""
+msgstr "Nouveau Domaine"
msgid "GitLabPages|Only project maintainers can remove pages"
-msgstr ""
+msgstr "Seuls les responsables de projet peuvent supprimer des pages"
msgid "GitLabPages|Pages"
-msgstr ""
+msgstr "Pages"
msgid "GitLabPages|Remove"
-msgstr ""
+msgstr "Supprimer"
msgid "GitLabPages|Remove certificate"
msgstr "Supprimer le certificat"
@@ -18130,7 +18392,7 @@ msgid "GitLabPages|Remove domain"
msgstr "Supprimer le domaine"
msgid "GitLabPages|Remove pages"
-msgstr ""
+msgstr "Supprimer les pages"
msgid "GitLabPages|Removing pages will prevent them from being exposed to the outside world."
msgstr ""
@@ -18229,7 +18491,7 @@ msgid "GithubIntegration|This requires mirroring your GitHub repository to this
msgstr "Cela nécessite de faire un miroir de votre dépôt GitHub vers ce projet. %{docs_link}"
msgid "Gitpod"
-msgstr ""
+msgstr "Gitpod"
msgid "Gitpod|Enable Gitpod integration"
msgstr "Activer l’intégration de Gitpod"
@@ -18253,13 +18515,13 @@ msgid "Given access %{time_ago}"
msgstr "Accès donné %{time_ago}"
msgid "Given epic is already related to this epic."
-msgstr ""
+msgstr "L'épopée donnée est déjà liée à cette épopée."
msgid "Global Search is disabled for this scope"
msgstr "La Recherche Globale est désactivée pour cette portée"
msgid "Global Shortcuts"
-msgstr ""
+msgstr "Raccourcis globaux"
msgid "Global notification level"
msgstr "Niveau de notification global"
@@ -18388,7 +18650,7 @@ msgid "Go to definition"
msgstr "Aller à la définition"
msgid "Go to environments"
-msgstr ""
+msgstr "Aller aux environnements"
msgid "Go to environments page to approve or reject"
msgstr "Aller à la page des environnements pour approuver ou rejeter"
@@ -18397,16 +18659,16 @@ msgid "Go to epic"
msgstr "Aller à l'épopée"
msgid "Go to file"
-msgstr ""
+msgstr "Aller au fichier"
msgid "Go to file permalink (while viewing a file)"
msgstr ""
msgid "Go to files"
-msgstr ""
+msgstr "Aller aux fichiers"
msgid "Go to find file"
-msgstr ""
+msgstr "Aller à la recherche de fichier"
msgid "Go to issue boards"
msgstr "Aller aux tableaux des tickets"
@@ -18415,16 +18677,16 @@ msgid "Go to issues"
msgstr "Aller aux tickets"
msgid "Go to jobs"
-msgstr ""
+msgstr "Aller aux tâches"
msgid "Go to kubernetes"
-msgstr ""
+msgstr "Aller à kubernetes"
msgid "Go to merge requests"
-msgstr ""
+msgstr "Aller aux demandes de fusion"
msgid "Go to metrics"
-msgstr ""
+msgstr "Aller aux métriques"
msgid "Go to next page"
msgstr "Aller à la page suivante"
@@ -18451,19 +18713,19 @@ msgid "Go to primary site"
msgstr "Aller au site principal"
msgid "Go to project"
-msgstr ""
+msgstr "Aller au projet"
msgid "Go to releases"
-msgstr ""
+msgstr "Aller aux versions"
msgid "Go to repository charts"
-msgstr ""
+msgstr "Aller aux graphiques du dépôt"
msgid "Go to repository graph"
-msgstr ""
+msgstr "Aller au graphe du dépôt"
msgid "Go to snippets"
-msgstr ""
+msgstr "Aller aux extraits de code"
msgid "Go to the %{b_open}Activity%{b_close} page for %{project_link}."
msgstr "Aller à la page %{b_open}Activité%{b_close} de %{project_link}."
@@ -18478,7 +18740,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 "Aller au flux d'activité"
msgid "Go to the group’s 'Settings &gt; General' page, and check 'Restrict membership by email domain'."
msgstr ""
@@ -18487,13 +18749,13 @@ msgid "Go to the milestone list"
msgstr "Aller à la liste des jalons"
msgid "Go to the project's activity feed"
-msgstr ""
+msgstr "Aller au flux d'activité du projet"
msgid "Go to the project's overview page"
-msgstr ""
+msgstr "Aller à la vue d'ensemble du projet"
msgid "Go to wiki"
-msgstr ""
+msgstr "Aller au wiki"
msgid "Go to your To-Do list"
msgstr "Aller à votre liste de tâches"
@@ -18502,19 +18764,19 @@ msgid "Go to your fork"
msgstr ""
msgid "Go to your groups"
-msgstr ""
+msgstr "Aller à vos groupes"
msgid "Go to your issues"
msgstr "Aller à vos tickets"
msgid "Go to your merge requests"
-msgstr ""
+msgstr "Aller à vos demandes de fusion"
msgid "Go to your projects"
-msgstr ""
+msgstr "Aller à vos projets"
msgid "Go to your snippets"
-msgstr ""
+msgstr "Aller à vos extraits"
msgid "Google Cloud"
msgstr "Google Cloud"
@@ -18523,7 +18785,7 @@ msgid "Google Cloud Error - %{error}"
msgstr "Erreur Google Cloud - %{error}"
msgid "Google Cloud Project"
-msgstr ""
+msgstr "Projet Google Cloud"
msgid "Google Cloud authorizations required"
msgstr "Autorisations Google Cloud requises"
@@ -18547,7 +18809,7 @@ msgid "GoogleCloud|Google OAuth2 token revocation request failed"
msgstr "La demande de révocation du jeton Google OAuth2 a échoué"
msgid "GoogleCloud|Google OAuth2 token revocation requested"
-msgstr ""
+msgstr "Révocation du jeton Google OAuth2 demandée"
msgid "GoogleCloud|I understand the responsibilities involved with managing service account keys"
msgstr ""
@@ -18571,7 +18833,7 @@ msgid "Got it!"
msgstr "Compris !"
msgid "Grafana URL"
-msgstr ""
+msgstr "URL de Grafana"
msgid "Grafana response contains invalid json"
msgstr ""
@@ -18586,10 +18848,10 @@ msgid "GrafanaIntegration|Enter the %{docLinkStart}Grafana API token%{docLinkEnd
msgstr "Entrez le %{docLinkStart}jeton d'API Grafana%{docLinkEnd}."
msgid "GrafanaIntegration|Enter the base URL of the Grafana instance."
-msgstr ""
+msgstr "Entrez l'URL de base de l'instance Grafana."
msgid "GrafanaIntegration|Grafana URL"
-msgstr ""
+msgstr "URL de Grafana"
msgid "GrafanaIntegration|Grafana authentication"
msgstr "Authentification Grafana"
@@ -18615,18 +18877,18 @@ msgstr "Afficher les dépendances"
msgid "GraphViewType|Stage"
msgstr "Étape"
-msgid "Graphs"
-msgstr "graphiques"
-
msgid "Gravatar"
-msgstr ""
+msgstr "Gravatar"
msgid "Gravatar enabled"
-msgstr ""
+msgstr "Gravatar activé"
msgid "Group"
msgstr "Groupe"
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr "Le groupe %{group_name} et son équipe Mattermost ont été créés avec succès."
+
msgid "Group %{group_name} couldn't be exported."
msgstr "Le groupe %{group_name} n'a pas pu être exporté."
@@ -18634,10 +18896,10 @@ msgid "Group %{group_name} was exported successfully."
msgstr "Le groupe %{group_name} a été exporté avec succès."
msgid "Group %{group_name} was scheduled for deletion."
-msgstr ""
+msgstr "Le groupe %{group_name} a été planifié pour suppression."
msgid "Group %{group_name} was successfully created."
-msgstr ""
+msgstr "Le groupe %{group_name} a été créé avec succès."
msgid "Group Access Tokens"
msgstr "Jetons d'Accès de Groupe"
@@ -18682,7 +18944,7 @@ msgid "Group export could not be started."
msgstr "L'exportation de groupe n'a pas pu être démarrée."
msgid "Group export download requests"
-msgstr ""
+msgstr "Demandes de téléchargement d'export de groupe"
msgid "Group export error"
msgstr "Erreur d'exportation de groupe"
@@ -18700,7 +18962,7 @@ msgid "Group has been already marked for deletion"
msgstr "Le groupe a déjà été marqué pour suppression"
msgid "Group has not been marked for deletion"
-msgstr ""
+msgstr "Le groupe n'a pas été marqué pour suppression"
msgid "Group import could not be scheduled"
msgstr "L'importation de groupe n'a pas pu être planifiée"
@@ -18721,7 +18983,7 @@ msgid "Group jobs by"
msgstr "Grouper les tâches par"
msgid "Group members"
-msgstr ""
+msgstr "Membres du groupe"
msgid "Group membership expiration date changed"
msgstr "La date d'expiration de l'adhésion au groupe a été modifiée"
@@ -18748,10 +19010,10 @@ msgid "Group path is already taken. We've suggested one that is available."
msgstr "Le chemin du groupe est déjà pris. Nous en avons suggéré un qui est disponible."
msgid "Group path is available."
-msgstr ""
+msgstr "Le chemin de groupe est disponible."
msgid "Group pipeline minutes were successfully reset."
-msgstr ""
+msgstr "Les minutes du pipeline du groupe ont été réinitialisées avec succès."
msgid "Group project URLs are prefixed with the group namespace"
msgstr ""
@@ -18766,13 +19028,13 @@ msgid "Group runners can be managed with the %{link}."
msgstr "Les exécuteurs de groupe peuvent être gérés avec l'%{link}."
msgid "Group variables (inherited)"
-msgstr ""
+msgstr "Variables du groupe (héritées)"
msgid "Group was exported"
msgstr "Le groupe a été exporté"
msgid "Group was successfully updated."
-msgstr ""
+msgstr "Le groupe a été mis à jour avec succès."
msgid "Group wikis"
msgstr ""
@@ -18784,7 +19046,7 @@ msgid "Group: %{group_name}"
msgstr "Groupe : %{group_name}"
msgid "Group: %{name}"
-msgstr ""
+msgstr "Groupe : %{name}"
msgid "GroupActivityMetrics|Issues created"
msgstr "Tickets créés"
@@ -18826,7 +19088,7 @@ msgid "GroupPage|Group ID: %{group_id}"
msgstr "ID de groupe : %{group_id}"
msgid "GroupRoadmap|%{dateWord} – No end date"
-msgstr ""
+msgstr "%{dateWord} – Pas de date de fin"
msgid "GroupRoadmap|%{startDateInWords} – %{endDateInWords}"
msgstr "%{startDateInWords} – %{endDateInWords}"
@@ -18841,7 +19103,7 @@ msgid "GroupRoadmap|No start and end date"
msgstr "Pas de date de début ni de fin"
msgid "GroupRoadmap|No start date – %{dateWord}"
-msgstr ""
+msgstr "Pas de date de début – %{dateWord}"
msgid "GroupRoadmap|Something went wrong while fetching epics"
msgstr "Une erreur s’est produite lors de la récupération des épopées"
@@ -18865,7 +19127,7 @@ msgid "GroupRoadmap|To make your epics appear in the roadmap, add start or due d
msgstr "Pour que les épopées apparaissent sur la feuille de route, ajoutez-leur des dates de début ou d'échéance."
msgid "GroupRoadmap|To view the roadmap, add a start or due date to one of the %{linkStart}child epics%{linkEnd}."
-msgstr ""
+msgstr "Pour afficher la feuille de route, ajoutez une date de début ou une date d'échéance à l'une des %{linkStart}épopées enfants%{linkEnd}."
msgid "GroupRoadmap|To view the roadmap, add a start or due date to one of your epics in this group or its subgroups; from %{startDate} to %{endDate}."
msgstr ""
@@ -18877,7 +19139,7 @@ msgid "GroupRoadmap|View epics list"
msgstr "Afficher la liste des épopées"
msgid "GroupRoadmap|Within 3 years"
-msgstr ""
+msgstr "Dans les 3 ans"
msgid "GroupSAML|\"persistent\" recommended"
msgstr "\"persistant\" recommandé"
@@ -18886,7 +19148,7 @@ msgid "GroupSAML|%{strongOpen}Warning%{strongClose} - Enable %{linkStart}SSO enf
msgstr "%{strongOpen}Avertissement%{strongClose} - Activer la %{linkStart}mise en œuvre de SSO%{linkEnd} pour réduire les risques de sécurité."
msgid "GroupSAML|Active SAML Group Links (%{count})"
-msgstr ""
+msgstr "Liens de groupe SAML actifs (%{count})"
msgid "GroupSAML|An error occurred generating your SCIM token. Please try again."
msgstr "Une erreur s'est produite lors de la génération de votre jeton SCIM. Veuillez réessayer."
@@ -18895,7 +19157,7 @@ msgid "GroupSAML|An error occurred resetting your SCIM token. Please try again."
msgstr "Une erreur s'est produite lors de la réinitialisation de votre jeton SCIM. Veuillez réessayer."
msgid "GroupSAML|Are you sure you want to remove the SAML group link?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir supprimer le lien du groupe SAML ?"
msgid "GroupSAML|Are you sure you want to reset the SCIM token? SCIM provisioning will stop working until the new token is updated."
msgstr "Êtes-vous sûr de vouloir réinitialiser le jeton SCIM ? Le provisionnement SCIM cessera de fonctionner jusqu'à ce que le nouveau jeton soit mis à jour."
@@ -18907,16 +19169,16 @@ msgid "GroupSAML|Before enforcing SSO-only authentication for Git activity of al
msgstr "Avant de mettre en œuvre l'authentification unique avec SSO pour l'activité Git de tous les utilisateurs, activez-la pour l'activité web."
msgid "GroupSAML|Certificate fingerprint"
-msgstr ""
+msgstr "Empreinte du certificat"
msgid "GroupSAML|Configuration"
-msgstr ""
+msgstr "Configuration"
msgid "GroupSAML|Copy SAML Response XML"
msgstr "Copier le XML de la réponse SAML"
msgid "GroupSAML|Could not create SAML group link: %{errors}."
-msgstr ""
+msgstr "Impossible de créer le lien de groupe SAML : %{errors}."
msgid "GroupSAML|Default membership role"
msgstr ""
@@ -18934,10 +19196,10 @@ msgid "GroupSAML|Enforce users to have dedicated group-managed accounts for this
msgstr "Forcer les utilisateurs à avoir des comptes dédiés gérés par le groupe pour ce groupe"
msgid "GroupSAML|Generate a SCIM token"
-msgstr ""
+msgstr "Générer un jeton SCIM"
msgid "GroupSAML|Generate a SCIM token to set up your System for Cross-Domain Identity Management."
-msgstr ""
+msgstr "Générez un jeton SCIM pour mettre en place votre Système de Gestion des Identités Inter-Domaines."
msgid "GroupSAML|Identifier"
msgstr "Identifiant"
@@ -18964,10 +19226,10 @@ msgid "GroupSAML|NameID Format"
msgstr "Format NameID"
msgid "GroupSAML|New SAML group link saved."
-msgstr ""
+msgstr "Nouveau lien de groupe SAML enregistré."
msgid "GroupSAML|No active SAML group links"
-msgstr ""
+msgstr "Aucun lien de groupe SAML actif"
msgid "GroupSAML|Prohibit outer forks for this group"
msgstr "Interdire les projets divergents externes pour ce groupe"
@@ -18979,13 +19241,13 @@ msgid "GroupSAML|Role to assign members of this SAML group."
msgstr ""
msgid "GroupSAML|SAML Group Links"
-msgstr ""
+msgstr "Liens de groupe SAML"
msgid "GroupSAML|SAML Group Name"
-msgstr ""
+msgstr "Nom du Groupe SAML"
msgid "GroupSAML|SAML Group Name: %{saml_group_name}"
-msgstr ""
+msgstr "Nom du Groupe SAML : %{saml_group_name}"
msgid "GroupSAML|SAML Response Output"
msgstr "Sortie de la réponse SAML"
@@ -18994,25 +19256,25 @@ msgid "GroupSAML|SAML Response XML"
msgstr "XML de la réponse SAML"
msgid "GroupSAML|SAML Single Sign On"
-msgstr ""
+msgstr "Authentification unique SAML"
msgid "GroupSAML|SAML Single Sign On Settings"
-msgstr ""
+msgstr "Paramètres de l'authentification unique SAML"
msgid "GroupSAML|SAML group link was successfully removed."
-msgstr ""
+msgstr "Le lien de groupe SAML a été supprimé avec succès."
msgid "GroupSAML|SCIM Token"
-msgstr ""
+msgstr "Jeton SCIM"
msgid "GroupSAML|SHA1 fingerprint of the SAML token signing certificate. Get this from your identity provider, where it can also be called \"Thumbprint\"."
-msgstr ""
+msgstr "Empreinte SHA1 du certificat de signature du jeton SAML. Obtenez-la auprès de votre fournisseur d’identité, où elle peut également être appelée « fingerprint » ou « thumbprint »."
msgid "GroupSAML|The SCIM token is now hidden. To see the value of the token again, you need to %{linkStart}reset it%{linkEnd}."
msgstr "Le jeton SCIM est maintenant masqué. Pour voir à nouveau sa valeur, vous devez %{linkStart}le réinitialiser%{linkEnd}."
msgid "GroupSAML|The case-sensitive group name that will be sent by the SAML identity provider."
-msgstr ""
+msgstr "Le nom de groupe sensible à la casse qui sera envoyé par le fournisseur d'identité SAML."
msgid "GroupSAML|This will be set as the access level of users added to the group."
msgstr ""
@@ -19066,7 +19328,7 @@ msgid "GroupSettings|Applied to all subgroups unless overridden by a group owner
msgstr ""
msgid "GroupSettings|Auto DevOps pipeline was updated for the group"
-msgstr ""
+msgstr "Le pipeline Auto DevOps a été mis à jour pour le groupe"
msgid "GroupSettings|Available only on the top-level group. Applies to all subgroups. Groups already shared with a group outside %{group} are still shared unless removed manually."
msgstr "Disponible uniquement sur le groupe de niveau supérieur. S'applique à tous les sous-groupes. Les groupes déjà partagés avec un groupe en dehors de %{group} sont toujours partagés à moins de les supprimer manuellement."
@@ -19093,7 +19355,7 @@ msgid "GroupSettings|Compliance frameworks"
msgstr "Cadres de conformité"
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
-msgstr ""
+msgstr "Configurer les cadres de conformité pour les mettre à disposition des projets de ce groupe. %{linkStart}Que sont les cadres de conformité ?%{linkEnd}"
msgid "GroupSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
@@ -19108,7 +19370,7 @@ msgid "GroupSettings|Customize this group's badges."
msgstr "Personnaliser les badges de ce groupe."
msgid "GroupSettings|Default to Auto DevOps pipeline for all projects within this group"
-msgstr ""
+msgstr "Utiliser par défaut le pipeline Auto DevOps pour tous les projets de ce groupe"
msgid "GroupSettings|Email notifications are disabled"
msgstr "Les notifications par courriel sont désactivées"
@@ -19141,7 +19403,7 @@ msgid "GroupSettings|Overrides user notification preferences for all members of
msgstr "Outrepasse les préférences de notification des utilisateurs pour tous les membres du groupe, sous-groupes et projets."
msgid "GroupSettings|Pipeline settings was updated for the group"
-msgstr ""
+msgstr "Les paramètres du pipeline ont été mis à jour pour le groupe"
msgid "GroupSettings|Please choose a group URL with no special characters or spaces."
msgstr "Veuillez choisir une URL de groupe sans caractères spéciaux ni espaces."
@@ -19183,10 +19445,10 @@ msgid "GroupSettings|The projects in this subgroup can be selected as templates
msgstr "Les projets de ce sous-groupe peuvent être sélectionnés comme modèles pour les nouveaux projets créés dans le groupe. %{link_start}En savoir plus.%{link_end}"
msgid "GroupSettings|There was a problem updating Auto DevOps pipeline: %{error_messages}."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la mise à jour du pipeline Auto DevOps : %{error_messages}."
msgid "GroupSettings|There was a problem updating the pipeline settings: %{error_messages}."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la mise à jour des paramètres du pipeline : %{error_messages}."
msgid "GroupSettings|This setting is applied on %{ancestor_group} and has been overridden on this subgroup."
msgstr "Ce paramètre s’applique au groupe %{ancestor_group} et a été forcé pour ce sousâ€groupe."
@@ -19198,7 +19460,7 @@ msgid "GroupSettings|This setting is applied on %{ancestor_group}. You can overr
msgstr "Ce paramètre s’applique au groupe %{ancestor_group}. Vous pouvez écraser le paramètre ou le %{remove_ancestor_share_with_group_lock}."
msgid "GroupSettings|Transfer group"
-msgstr ""
+msgstr "Transférer le groupe"
msgid "GroupSettings|Users can create %{link_start_project}project access tokens%{link_end} and %{link_start_group}group access tokens%{link_end} in this group"
msgstr "Les utilisateurs peuvent créer des %{link_start_project}jetons d'accès au projet%{link_end} et des %{link_start_group}jetons d'accès au groupe%{link_end} dans ce groupe"
@@ -19213,7 +19475,7 @@ msgid "GroupSettings|When the number of active users exceeds this number, additi
msgstr "Lorsque le nombre d'utilisateurs actifs dépasse ce nombre, les utilisateurs supplémentaires doivent être %{user_cap_docs_link_start}approuvés par un propriétaire%{user_cap_docs_link_end}. Laissez vide si vous ne voulez pas imposer ces approbations. Augmenter le nombre maximal d'utilisateurs n'approuvera pas automatiquement les utilisateurs en attente."
msgid "GroupSettings|You can only transfer the group to a group you manage."
-msgstr ""
+msgstr "Vous ne pouvez transférer le groupe que dans un groupe que vous gérez."
msgid "GroupSettings|You will need to update your local repositories to point to the new location."
msgstr ""
@@ -19234,7 +19496,7 @@ msgid "Groups"
msgstr "Groupes"
msgid "Groups (%{count})"
-msgstr ""
+msgstr "Groupes (%{count})"
msgid "Groups and projects"
msgstr "Groupes et projets"
@@ -19276,7 +19538,7 @@ msgid "GroupsEmptyState|Create new subgroup"
msgstr "Créer un nouveau sous-groupe"
msgid "GroupsEmptyState|Groups are the best way to manage multiple projects and members."
-msgstr ""
+msgstr "Les groupes sont la manière la plus efficace de gérer plusieurs projets et membres."
msgid "GroupsEmptyState|If you organize your projects under a group, it works like a folder."
msgstr "Si vous organisez vos projets au sein d’un groupe, cela fonctionne comme un dossier."
@@ -19306,7 +19568,7 @@ msgid "GroupsNew|Assemble related projects together and grant members access to
msgstr "Réunit des groupes apparentés et accorde aux membres l'accès à plusieurs projets à la fois."
msgid "GroupsNew|Connect instance"
-msgstr ""
+msgstr "Se connecter à l'instance"
msgid "GroupsNew|Contact an administrator to enable options for importing your group."
msgstr "Contactez un administrateur pour activer les options pour importer votre groupe."
@@ -19321,7 +19583,7 @@ msgid "GroupsNew|Create subgroup"
msgstr "Créer un sous-groupe"
msgid "GroupsNew|Create this in the %{pat_link_start}user settings%{pat_link_end} of the source GitLab instance. For %{short_living_link_start}security reasons%{short_living_link_end}, use a short expiration date when creating the token."
-msgstr ""
+msgstr "Créez-le dans les %{pat_link_start}paramètres de l'utilisateur%{pat_link_end} de l'instance GitLab source. Pour %{short_living_link_start}des raisons de sécurité%{short_living_link_end}, utilisez une date d'expiration proche lors de sa création."
msgid "GroupsNew|GitLab source URL"
msgstr ""
@@ -19339,7 +19601,7 @@ msgid "GroupsNew|Import groups from another instance of GitLab"
msgstr "Importer des groupes depuis une autre instance de GitLab"
msgid "GroupsNew|No import options available"
-msgstr ""
+msgstr "Aucune option d'importation n'est disponible"
msgid "GroupsNew|Not all related objects are migrated. %{docs_link_start}More info%{docs_link_end}."
msgstr "Tous les objets associés ne sont pas migrés. %{docs_link_start}Plus d'infos%{docs_link_end}."
@@ -19389,12 +19651,6 @@ msgstr "Quitter le groupe"
msgid "GroupsTree|Loading groups"
msgstr "Chargement des groupes"
-msgid "GroupsTree|No groups matched your search"
-msgstr "Aucun groupe ne correspond à votre recherche"
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr "Aucun groupe ni projet ne correspond à votre recherche"
-
msgid "GroupsTree|Options"
msgstr "Options"
@@ -19441,7 +19697,7 @@ msgid "Groups|Learn more about subgroups"
msgstr "En savoir plus sur les sous-groupes"
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 "Les membres, projets, essais et abonnements payants sont liés à un groupe de premier niveau spécifique. Si vous êtes déjà membre d'un groupe de premier niveau, vous pouvez créer un sous-groupe afin que votre nouveau travail fasse partie de votre groupe de premier niveau existant. Voulez-vous créer un sous-groupe à la place ?"
msgid "Groups|Must start with letter, digit, emoji, or underscore. Can also contain periods, dashes, spaces, and parentheses."
msgstr "Doit commencer par une lettre, un chiffre, un emoji ou un trait de soulignement. Peut également contenir des points, des tirets, des espaces et des parenthèses."
@@ -19462,7 +19718,10 @@ msgid "Groups|Subgroup slug"
msgstr "Slug du sous-groupe"
msgid "Groups|You're creating a new top-level group"
-msgstr ""
+msgstr "Vous êtes en train de créer un nouveau groupe de premier niveau"
+
+msgid "Guest"
+msgstr "Invité"
msgid "Guideline"
msgstr ""
@@ -19486,7 +19745,7 @@ msgid "Harbor Registry"
msgstr "Registre Harbor"
msgid "HarborIntegration|After the Harbor integration is activated, global variables `$HARBOR_USERNAME`, `$HARBOR_HOST`, `$HARBOR_OCI`, `$HARBOR_PASSWORD`, `$HARBOR_URL` and `$HARBOR_PROJECT` will be created for CI/CD use."
-msgstr ""
+msgstr "Une fois l'intégration Harbor activée, les variables globales `$HARBOR_USERNAME`, `$HARBOR_HOST`, `$HARBOR_OCI`, `$HARBOR_PASSWORD`, `$HARBOR_URL` et `$HARBOR_PROJECT` seront créées pour être utilisées avec CI/CD."
msgid "HarborIntegration|Base URL of the Harbor instance."
msgstr "URL de base de l'instance Harbor."
@@ -19532,7 +19791,7 @@ msgid "HarborRegistry|-- artifacts"
msgstr "-- artéfacts"
msgid "HarborRegistry|-- tags"
-msgstr ""
+msgstr "-- étiquettes"
msgid "HarborRegistry|Digest: %{imageId}"
msgstr ""
@@ -19601,7 +19860,7 @@ msgid "Header logo"
msgstr "Logo d'en-tête"
msgid "Header logo was successfully removed."
-msgstr ""
+msgstr "Le logo de l'en-tête a été supprimé avec succès."
msgid "Header logo will be removed. Are you sure?"
msgstr "Le logo d'en-tête sera supprimé. Êtesâ€vous sûr(e) ?"
@@ -19642,9 +19901,6 @@ msgstr "L’état des services peut être récupéré depuis les emplacements su
msgid "Health status"
msgstr "État de santé"
-msgid "Health status cannot be edited because this issue is closed"
-msgstr "L'état de santé ne peut pas être modifié car ce ticket est fermé"
-
msgid "HealthCheck|Access token is"
msgstr "Le jeton d’accès est"
@@ -19688,13 +19944,13 @@ msgid "Help translate GitLab into your language"
msgstr "Aidez-nous à traduire GitLab dans votre langue"
msgid "Helps prevent bots from brute-force attacks."
-msgstr ""
+msgstr "Contribue à empêcher les attaques par force brute lancées par des bots."
msgid "Helps prevent bots from creating accounts."
-msgstr ""
+msgstr "Contribue à empêcher la création de comptes par des bots."
msgid "Helps prevent bots from creating accounts. %{link_start}How do I configure it?%{link_end}"
-msgstr ""
+msgstr "Contribue à empêcher la création de comptes par des bots. %{link_start}Comment puis-je le configurer ?%{link_end}"
msgid "Helps prevent bots from creating issues."
msgstr "Contribue à empêcher la création de tickets par des bots."
@@ -19721,15 +19977,15 @@ msgid "Hide"
msgstr "Masquer"
msgid "Hide Live Preview"
-msgstr ""
+msgstr "Masquer l'aperçu en direct"
msgid "Hide archived projects"
msgstr "Masquer les projets archivés"
msgid "Hide chart"
msgid_plural "Hide charts"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Masquer le graphique"
+msgstr[1] "Masquer les graphiques"
msgid "Hide comments"
msgstr "Masquer les commentaires"
@@ -19738,19 +19994,19 @@ msgid "Hide comments on this file"
msgstr "Masquer les commentaires de ce fichier"
msgid "Hide details"
-msgstr ""
+msgstr "Masquer les détails"
msgid "Hide file browser"
-msgstr ""
+msgstr "Masquer le navigateur de fichiers"
msgid "Hide group projects"
-msgstr ""
+msgstr "Masquer les projets de groupe"
msgid "Hide host keys manual input"
msgstr "Masquer la saisie manuelle des clefs d’hôtes"
msgid "Hide list"
-msgstr ""
+msgstr "Masquer la liste"
msgid "Hide marketing-related entries from the Help page"
msgstr "Masquer les entrées liées au marketing de la page d'Aide"
@@ -19759,7 +20015,7 @@ msgid "Hide payload"
msgstr "Masquer la charge utile"
msgid "Hide shared projects"
-msgstr ""
+msgstr "Masquer les projets partagés"
msgid "Hide thread"
msgstr ""
@@ -19773,7 +20029,7 @@ msgstr[0] "Masquer la valeur"
msgstr[1] "Masquer les valeurs"
msgid "Hide values"
-msgstr ""
+msgstr "Masquer les valeurs"
msgid "Hierarchy|Current structure"
msgstr "Structure actuelle"
@@ -19806,7 +20062,7 @@ msgid "High or unknown vulnerabilities present"
msgstr ""
msgid "Highest role:"
-msgstr ""
+msgstr "Rôle le plus élevé :"
msgid "HighlightBar|Alert events:"
msgstr "Événements d’alerte :"
@@ -19827,7 +20083,7 @@ msgid "History"
msgstr "Historique"
msgid "History of authentications"
-msgstr ""
+msgstr "Historique des authentifications"
msgid "Holder name:"
msgstr "Nom du titulaire :"
@@ -19839,13 +20095,13 @@ msgid "Homepage"
msgstr "Page d'accueil"
msgid "Hook execution failed. Ensure the group has a project with commits."
-msgstr ""
+msgstr "L'exécution du crochet a échoué. Assurez-vous que le groupe a un projet avec des commits."
msgid "Hook was successfully updated."
-msgstr ""
+msgstr "Le crochet a été mis à jour avec succès."
msgid "Horizontal rule"
-msgstr ""
+msgstr "Ligne horizontale"
msgid "Hostname"
msgstr "Nom d’hôte"
@@ -19857,7 +20113,7 @@ msgid "Hour (UTC)"
msgstr "Heure (UTC)"
msgid "Housekeeping"
-msgstr ""
+msgstr "Maintenance"
msgid "Housekeeping successfully started"
msgstr "Maintenance démarrée avec succès"
@@ -19866,7 +20122,7 @@ msgid "How do I configure Akismet?"
msgstr "Comment configurer Akismet ?"
msgid "How do I configure this integration?"
-msgstr ""
+msgstr "Comment configurer cette intégration ?"
msgid "How do I generate it?"
msgstr ""
@@ -19905,7 +20161,7 @@ msgid "I accept the %{terms_link}"
msgstr "J’accepte les %{terms_link}"
msgid "I forgot my password"
-msgstr ""
+msgstr "J'ai oublié mon mot de passe"
msgid "I want to explore GitLab to see if it’s worth switching to"
msgstr "Je souhaite découvrir GitLab pour voir s'il est intéressant d'y passer"
@@ -19914,13 +20170,13 @@ msgid "I want to learn the basics of Git"
msgstr "Je souhaite apprendre les bases de Git"
msgid "I want to move my repository to GitLab from somewhere else"
-msgstr ""
+msgstr "Je souhaite déplacer mon dépôt vers GitLab depuis un autre endroit"
msgid "I want to store my code"
-msgstr ""
+msgstr "Je souhaite stocker mon code"
msgid "I want to use GitLab CI with my existing repository"
-msgstr ""
+msgstr "Je souhaite utiliser GitLab CI avec mon dépôt existant"
msgid "I'd like to receive updates about GitLab via email"
msgstr ""
@@ -19932,7 +20188,7 @@ msgid "ID"
msgstr "Identifiant"
msgid "ID:"
-msgstr ""
+msgstr "ID :"
msgid "IDE"
msgstr "IDE"
@@ -20001,7 +20257,7 @@ msgid "IP subnet restriction only allowed for top-level groups"
msgstr ""
msgid "Id"
-msgstr ""
+msgstr "Id"
msgid "Identifier"
msgstr "Identifiant"
@@ -20099,8 +20355,14 @@ msgstr "Envoyer un code"
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr "Une erreur s'est produite. Veuillez réessayer."
-msgid "IdentityVerification|Step 1: Verify phone number"
-msgstr "Étape 1 : Vérifier le numéro de téléphone"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr "Étape %{stepNumber} : Vérifier un moyen de paiement"
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr "Étape %{stepNumber} : Vérifier l'adresse de courriel"
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
+msgstr "Étape %{stepNumber} : Vérifier le numéro de téléphone"
msgid "IdentityVerification|The code has expired. Send a new code and try again."
msgstr "Le code a expiré. Envoyez un nouveau code et réessayez."
@@ -20127,7 +20389,7 @@ msgid "IdentityVerification|Verify your identity"
msgstr "Vérifiez votre identité"
msgid "IdentityVerification|You can always verify your account at a later time to create a group."
-msgstr ""
+msgstr "Vous pouvez toujours vérifier votre compte plus tard pour créer un groupe."
msgid "IdentityVerification|You will receive a text containing a code. Standard charges may apply."
msgstr ""
@@ -20186,12 +20448,6 @@ msgstr "Si ce courriel a été ajouté par erreur, vous pouvez le supprimer ici
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr "Si ce courriel a été ajouté par erreur, vous pouvez le supprimer ici : %{profile_emails_url}"
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -20205,7 +20461,7 @@ msgid "If you add %{codeStart}needs%{codeEnd} to jobs in your pipeline you'll be
msgstr "Si vous ajoutez des %{codeStart}nécessités%{codeEnd} aux tâches de votre pipeline, vous serez en mesure de voir les relations des %{codeStart}nécessités%{codeEnd} entre tâches dans cet onglet en tant que %{linkStart}Graphe orienté acyclique (DAG)%{linkEnd}."
msgid "If you did not initiate these sign-in attempts, please reach out to your administrator or enable two-factor authentication (2FA) on your account."
-msgstr ""
+msgstr "Si vous n'avez pas initié ces tentatives de connexion, veuillez contacter votre administrateur ou activer l'authentification à deux facteurs (2FA) sur votre compte."
msgid "If you did not initiate this change, please contact your administrator immediately."
msgstr "Si vous n'êtes pas à l'origine de cette modification, veuillez contacter votre administrateur immédiatement."
@@ -20220,22 +20476,22 @@ msgid "If you did not recently sign in, you should immediately change your passw
msgstr "Si vous ne vous êtes pas connecté récemment, vous devriez immédiatement modifier votre mot de passe : %{password_link}."
msgid "If you did not recently try to sign in, you should immediately %{password_link_start}change your password%{password_link_end}."
-msgstr ""
+msgstr "Si vous n'avez pas récemment essayé de vous connecter, vous devriez immédiatement %{password_link_start}changer votre mot de passe%{password_link_end}."
msgid "If you did not recently try to sign in, you should immediately change your password: %{password_link}."
-msgstr ""
+msgstr "Si vous n'avez pas récemment essayé de vous connecter, vous devriez immédiatement changer votre mot de passe : %{password_link}."
msgid "If you get a lot of false alarms from repository checks, you can clear all repository check information from the database."
msgstr "Si les vérifications de dépôt vous renvoient de nombreuses fausses alertes, vous pouvez supprimer de la base de données toutes les informations de vérification de dépôt."
msgid "If you lose your recovery codes you can generate new ones, invalidating all previous codes."
-msgstr ""
+msgstr "Si vous perdez vos codes de récupération, vous pouvez en générer de nouveaux, ce qui invalidera tous les codes précédents."
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 ""
+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 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}"
@@ -20253,7 +20509,7 @@ msgid "If you've purchased or renewed your subscription and have an activation c
msgstr "Si vous avez acheté ou renouvelé votre abonnement et que vous disposez d'un code d'activation, veuillez le saisir ci-dessous pour lancer le processus d'activation."
msgid "If your HTTP repository is not publicly accessible, add your credentials."
-msgstr ""
+msgstr "Si votre dépôt HTTP n'est pas accessible publiquement, ajoutez vos identifiants."
msgid "Ignore"
msgstr ""
@@ -20274,10 +20530,10 @@ msgid "ImageDiffViewer|Swipe"
msgstr "par balayage"
msgid "ImageViewerDimensions|H"
-msgstr ""
+msgstr "H"
msgid "ImageViewerDimensions|W"
-msgstr ""
+msgstr "L"
msgid "Images with incorrect dimensions are not resized automatically, and may result in unexpected behavior."
msgstr "Les images dont les dimensions sont incorrectes ne sont pas redimensionnées automatiquement et peuvent provoquer des effets inattendus."
@@ -20289,7 +20545,7 @@ msgid "Impersonation Tokens"
msgstr "Jetons d'emprunt d'identité"
msgid "Impersonation has been disabled"
-msgstr ""
+msgstr "L'emprunt d'identité a été désactivé"
msgid "Import"
msgstr "Importer"
@@ -20317,7 +20573,7 @@ msgid "Import and export rate limits"
msgstr ""
msgid "Import failed due to a GitHub error: %{original} (HTTP %{code})"
-msgstr ""
+msgstr "L'importation a échoué en raison d'une erreur GitHub : %{original} (HTTP %{code})"
msgid "Import from"
msgstr ""
@@ -20326,7 +20582,7 @@ msgid "Import from Jira"
msgstr "Importer depuis Jira"
msgid "Import group"
-msgstr ""
+msgstr "Importer un groupe"
msgid "Import group from file"
msgstr "Importer un groupe depuis un fichier"
@@ -20335,7 +20591,7 @@ msgid "Import groups"
msgstr "Importer des groupes"
msgid "Import history"
-msgstr ""
+msgstr "Historique d'importation"
msgid "Import in progress"
msgstr "Importation en cours"
@@ -20344,7 +20600,7 @@ msgid "Import in progress. Refresh page to see newly added issues."
msgstr "Importation en cours. Rafraîchir la page pour voir les tickets nouvellement ajoutés."
msgid "Import issues"
-msgstr ""
+msgstr "Importer des tickets"
msgid "Import multiple repositories by uploading a manifest file."
msgstr "Importez plusieurs dépôts en téléversant un fichier manifeste."
@@ -20353,7 +20609,7 @@ msgid "Import project"
msgstr "Importer un projet"
msgid "Import project from"
-msgstr ""
+msgstr "Importer un projet depuis"
msgid "Import projects from Bitbucket"
msgstr "Importer des projets depuis Bitbucket"
@@ -20398,13 +20654,13 @@ msgid "ImportAProjectModal|Import members from another project"
msgstr "Importer des membres depuis un autre projet"
msgid "ImportAProjectModal|Import project members"
-msgstr ""
+msgstr "Importer les membres du projet"
msgid "ImportAProjectModal|Only project members (not group members) are imported, and they get the same permissions as the project you import from."
msgstr ""
msgid "ImportAProjectModal|Successfully imported"
-msgstr ""
+msgstr "Importé avec succès"
msgid "ImportAProjectModal|Unable to import project members"
msgstr "Impossible d’importer les membres du projet"
@@ -20419,19 +20675,19 @@ msgid "ImportProjects|%{provider} rate limit exceeded. Try again later"
msgstr "La limite de débit de %{provider} a été dépassée. Réessayez plus tard"
msgid "ImportProjects|Advanced import settings"
-msgstr ""
+msgstr "Paramètres avancés d'importation"
msgid "ImportProjects|Blocked import URL: %{message}"
-msgstr ""
+msgstr "URL d'importation bloquée : %{message}"
msgid "ImportProjects|Error importing repository %{project_safe_import_url} into %{project_full_path} - %{message}"
-msgstr ""
+msgstr "Erreur lors de l'importation du dépôt %{project_safe_import_url} vers %{project_full_path} - %{message}"
msgid "ImportProjects|Import repositories"
msgstr "Importer des dépôts"
msgid "ImportProjects|Importing the project failed"
-msgstr ""
+msgstr "L'importation du projet a échoué"
msgid "ImportProjects|Importing the project failed: %{reason}"
msgstr "L'importation du projet a échoué : %{reason}"
@@ -20446,13 +20702,13 @@ msgid "ImportProjects|Select the repositories you want to import"
msgstr "Sélectionnez les dépôts que vous souhaitez importer"
msgid "ImportProjects|The more information you select, the longer it will take to import"
-msgstr ""
+msgstr "Plus vous sélectionnez d'informations, plus l'importation prendra de temps"
msgid "ImportProjects|The remote data could not be imported."
-msgstr ""
+msgstr "Les données distantes n'ont pas pu être importées."
msgid "ImportProjects|The repository could not be created."
-msgstr ""
+msgstr "Le dépôt n'a pas pu être créé."
msgid "ImportProjects|Update of imported projects with realtime changes failed"
msgstr ""
@@ -20466,7 +20722,7 @@ msgstr[0] "Importation de %d dépôt"
msgstr[1] "Importation de %d dépôts"
msgid "Importing..."
-msgstr ""
+msgstr "Importation en cours..."
msgid "Import|The repository could not be imported."
msgstr "Le dépôt n'a pas pu être importé."
@@ -20487,7 +20743,7 @@ msgid "In progress"
msgstr "En cours"
msgid "In the background, we're attempting to connect you again."
-msgstr ""
+msgstr "En arrière-plan, nous essayons de vous reconnecter."
msgid "In this page you will find information about the settings that are used in your current instance."
msgstr "Sur cette page, vous trouverez des informations sur les paramètres utilisés par votre instance actuelle."
@@ -20592,7 +20848,7 @@ msgid "InProductMarketing|Create a custom runner"
msgstr "Créer un exécuteur personnalisé"
msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
-msgstr ""
+msgstr "Créez un projet dans GitLab en 5 minutes"
msgid "InProductMarketing|Create well-defined workflows by using scoped labels on issues, merge requests, and epics. Labels with the same scope cannot be used together, which prevents conflicts."
msgstr ""
@@ -20658,7 +20914,7 @@ msgid "InProductMarketing|Find out if your external libraries are safe. Run depe
msgstr "Découvrez si vos bibliothèques externes sont sûres. Exécutez des tâches d'analyse de dépendances qui vérifient la présence de vulnérabilités connues dans vos bibliothèques externes."
msgid "InProductMarketing|Follow our steps"
-msgstr ""
+msgstr "Suivez nos étapes"
msgid "InProductMarketing|Free 30-day trial"
msgstr "Essai gratuit de 30 jours"
@@ -20679,7 +20935,7 @@ msgid "InProductMarketing|Get started today with a 30-day GitLab Ultimate trial,
msgstr "Débutez dès aujourd'hui avec un essai GitLab Ultimate de 30 jours, aucune carte de crédit n'est requise."
msgid "InProductMarketing|Get started with GitLab CI/CD"
-msgstr ""
+msgstr "Premiers pas avec GitLab CI/CD"
msgid "InProductMarketing|Get to know GitLab CI/CD"
msgstr ""
@@ -20709,7 +20965,7 @@ msgid "InProductMarketing|Give us one minute..."
msgstr ""
msgid "InProductMarketing|Go farther with GitLab"
-msgstr ""
+msgstr "Allez plus loin avec GitLab"
msgid "InProductMarketing|Goldman Sachs went from 1 build every two weeks to thousands of builds a day"
msgstr "Goldman Sachs est passé de 1 construction toutes les deux semaines à des milliers par jour"
@@ -20811,7 +21067,7 @@ msgid "InProductMarketing|Multiple required approvers"
msgstr "Plusieurs approbateurs requis"
msgid "InProductMarketing|Need an alternative to importing?"
-msgstr ""
+msgstr "Besoin d'une alternative à l'importation ?"
msgid "InProductMarketing|No credit card required."
msgstr "Aucune carte de crédit requise."
@@ -20868,7 +21124,7 @@ msgid "InProductMarketing|Start by %{performance_link}"
msgstr ""
msgid "InProductMarketing|Start by importing your projects"
-msgstr ""
+msgstr "Commencez par importer vos projets"
msgid "InProductMarketing|Start with a GitLab Ultimate free trial"
msgstr "Commencez avec un essai gratuit de GitLab Ultimate"
@@ -20886,7 +21142,7 @@ msgid "InProductMarketing|Streamline code review, know at a glance who's unavail
msgstr "Rationalisez la revue de code, voyez en un clin d'œil qui n'est pas disponible, communiquez via les commentaires ou par courriel et intégrez Slack afin que tout le monde soit sur la même page."
msgid "InProductMarketing|Take your first steps with GitLab"
-msgstr ""
+msgstr "Faites vos premiers pas avec GitLab"
msgid "InProductMarketing|Take your source code management to the next level"
msgstr ""
@@ -20988,7 +21244,7 @@ msgid "InProductMarketing|Your software, deployed your way"
msgstr "Votre logiciel, déployé à votre façon"
msgid "InProductMarketing|Your teams can be more efficient"
-msgstr ""
+msgstr "Vos équipes peuvent être plus efficaces"
msgid "InProductMarketing|comprehensive guide"
msgstr "guide complet"
@@ -21048,7 +21304,7 @@ msgid "Incident details"
msgstr "Détails de l'incident"
msgid "Incident template (optional)."
-msgstr ""
+msgstr "Modèle d'incident (facultatif)."
msgid "IncidentManagement|%{hours} hours, %{minutes} minutes remaining"
msgstr "%{hours} heures, %{minutes} minutes restantes"
@@ -21093,7 +21349,7 @@ msgid "IncidentManagement|Critical - S1"
msgstr "Critique - S1"
msgid "IncidentManagement|Date created"
-msgstr ""
+msgstr "Date de création"
msgid "IncidentManagement|Display your incidents in a dedicated view"
msgstr "Afficher vos incidents dans une vue dédiée"
@@ -21129,7 +21385,7 @@ msgid "IncidentManagement|Open"
msgstr "Ouvert(s)"
msgid "IncidentManagement|Page your team with escalation policies"
-msgstr ""
+msgstr "Notifiez votre équipe avec des politiques d'escalade"
msgid "IncidentManagement|Paged"
msgstr ""
@@ -21141,7 +21397,7 @@ msgid "IncidentManagement|Published to status page"
msgstr "Publié(s) sur la page d'état"
msgid "IncidentManagement|Resolved"
-msgstr ""
+msgstr "Résolu"
msgid "IncidentManagement|Setting the status to Acknowledged or Resolved stops paging when escalation policies are selected for the incident."
msgstr ""
@@ -21162,7 +21418,7 @@ msgid "IncidentManagement|Time to SLA"
msgstr "Durée avant SLA"
msgid "IncidentManagement|Triggered"
-msgstr ""
+msgstr "Déclenché"
msgid "IncidentManagement|Unassigned"
msgstr "Non assigné(s)"
@@ -21219,7 +21475,7 @@ msgid "IncidentSettings|minutes"
msgstr "minutes"
msgid "Incidents"
-msgstr ""
+msgstr "Incidents"
msgid "Incidents|Add image details"
msgstr ""
@@ -21234,7 +21490,7 @@ msgid "Incidents|Must start with http or https"
msgstr "Doit commencer par http ou https"
msgid "Incident|Add new timeline event"
-msgstr ""
+msgstr "Ajouter un nouvel événement à la chronologie"
msgid "Incident|Alert details"
msgstr "Détails de l'alerte"
@@ -21273,7 +21529,7 @@ msgid "Incident|Metrics"
msgstr "Métriques"
msgid "Incident|No timeline items have been added yet."
-msgstr ""
+msgstr "Aucun élément de chronologie n’a encore été ajouté."
msgid "Incident|Save and add another event"
msgstr "Sauvegarder et ajouter un autre événement"
@@ -21300,7 +21556,7 @@ msgid "Incident|There was an issue loading incident data. Please try again."
msgstr "Une erreur s'est produite lors du chargement des données de l'incident. Veuillez réessayer."
msgid "Incident|Timeline"
-msgstr ""
+msgstr "Chronologie"
msgid "Incident|Timeline text"
msgstr "Texte de la chronologie"
@@ -21309,7 +21565,7 @@ msgid "Incident|Timeline text..."
msgstr "Texte de la chronologie..."
msgid "Include author name in notification email body"
-msgstr ""
+msgstr "Inclure le nom de l'auteur dans le corps du courriel de notification"
msgid "Include description in commit message"
msgstr "Inclure la description dans le message du commit"
@@ -21342,13 +21598,13 @@ msgid "Incoming!"
msgstr ""
msgid "Incompatible options set!"
-msgstr ""
+msgstr "Des options incompatibles sont définies !"
msgid "Incompatible project"
msgstr "Projet incompatible"
msgid "Incomplete"
-msgstr ""
+msgstr "Non terminés"
msgid "Increase"
msgstr "Augmenter"
@@ -21369,7 +21625,7 @@ msgid "Indicates whether this runner can pick jobs without tags"
msgstr "Indique si l’exécuteur peut choisir des tâches sans étiquettes (tags)"
msgid "Inform users without uploaded SSH keys that they can't push over SSH until one is added"
-msgstr ""
+msgstr "Informer les utilisateurs qui n'ont pas téléversé de clés SSH qu'ils ne peuvent pas pousser sur SSH tant qu'ils n'en ont pas ajouté une"
msgid "Infrastructure"
msgstr "Infrastructure"
@@ -21417,10 +21673,10 @@ msgid "Inherited:"
msgstr ""
msgid "Initial default branch name"
-msgstr ""
+msgstr "Nom initial de la branche par défaut"
msgid "Initial default branch protection"
-msgstr ""
+msgstr "Protection initiale de la branche par défaut"
msgid "Inline"
msgstr "En ligne"
@@ -21441,7 +21697,7 @@ msgid "Insert a %{rows}x%{cols} table."
msgstr "Insérer un tableau %{rows}x%{cols}."
msgid "Insert a quote"
-msgstr ""
+msgstr "Insérer une citation"
msgid "Insert code"
msgstr "Insérer du code"
@@ -21486,7 +21742,7 @@ msgid "Install GitLab Runner and ensure it's running."
msgstr "Installez GitLab Runner et assurez-vous qu'il est en cours d'exécution."
msgid "Install on clusters"
-msgstr ""
+msgstr "Installer sur des grappes de serveurs"
msgid "Installation"
msgstr "Installation"
@@ -21497,7 +21753,7 @@ msgstr[0] "Instance"
msgstr[1] "Instances"
msgid "Instance Configuration"
-msgstr ""
+msgstr "Configuration de l'instance"
msgid "Instance access request"
msgstr "Demande d'accès à l'instance"
@@ -21596,13 +21852,13 @@ msgid "Integrations|Branches for which notifications are to be sent"
msgstr "Branches pour lesquelles des notifications doivent être envoyées"
msgid "Integrations|Clear if using a self-signed certificate."
-msgstr ""
+msgstr "Décochez si un certificat auto-signé est utilisé."
msgid "Integrations|Comment detail:"
msgstr ""
msgid "Integrations|Comment settings:"
-msgstr ""
+msgstr "Paramètres des commentaires :"
msgid "Integrations|Configure the scope of notifications."
msgstr "Configurer la portée des notifications."
@@ -21638,7 +21894,7 @@ msgid "Integrations|Enable SSL verification"
msgstr "Activer la vérification SSL"
msgid "Integrations|Enable comments"
-msgstr ""
+msgstr "Activer les commentaires"
msgid "Integrations|Ensure your instance URL is correct and your instance is configured correctly. %{linkStart}Learn more%{linkEnd}."
msgstr ""
@@ -21680,7 +21936,7 @@ msgid "Integrations|Includes Standard, plus the entire commit message, commit ha
msgstr "Inclus Standard, plus le message de commit, le hash de commit et les IDs des tickets"
msgid "Integrations|Includes commit title and branch."
-msgstr ""
+msgstr "Inclut le titre et la branche du commit."
msgid "Integrations|Instance-level integration management"
msgstr "Gestion d'intégration au niveau de l'instance"
@@ -21755,7 +22011,7 @@ msgid "Integrations|Send notifications about project events to Unify Circuit."
msgstr "Envoie des notifications sur les événements du projet vers Unify Circuit."
msgid "Integrations|Send notifications about project events to a Unify Circuit conversation. %{docs_link}"
-msgstr ""
+msgstr "Envoyer des notifications sur les événements du projet vers une conversation Unify Circuit. %{docs_link}"
msgid "Integrations|Sign in to %{url}"
msgstr "Se connecter à %{url}"
@@ -21767,7 +22023,7 @@ msgid "Integrations|Sign in to add namespaces"
msgstr "Connectez-vous pour ajouter des espaces de noms"
msgid "Integrations|Standard"
-msgstr ""
+msgstr "Standard"
msgid "Integrations|There are no projects using custom settings"
msgstr "Aucun projet n'utilise de paramètres personnalisés"
@@ -21833,13 +22089,13 @@ msgid "Interested parties can even contribute by pushing commits if they want to
msgstr "Les personnes intéressées peuvent même contribuer en poussant des commits si elles le souhaitent."
msgid "Internal"
-msgstr ""
+msgstr "Interne"
msgid "Internal - The group and any internal projects can be viewed by any logged in user except external users."
msgstr "Interne - Le groupe et tous les projets internes peuvent être vus par tout utilisateur connecté, à l'exception des utilisateurs externes."
msgid "Internal - The project can be accessed by any logged in user except external users."
-msgstr ""
+msgstr "Interne - Le projet est accessible par tout utilisateur connecté, à l'exception des utilisateurs externes."
msgid "Internal error occurred while delivering this webhook."
msgstr "Une erreur interne est survenue lors de l'exécution de ce webhook."
@@ -21851,7 +22107,7 @@ msgid "Internal users"
msgstr "Utilisateurs internes"
msgid "Internal users cannot be deactivated"
-msgstr ""
+msgstr "Les utilisateurs internes ne peuvent pas être désactivés"
msgid "Interval"
msgstr ""
@@ -21866,13 +22122,13 @@ msgid "Invalid"
msgstr "Non valide"
msgid "Invalid Insights config file detected"
-msgstr ""
+msgstr "Fichier de configuration Insights non valide détecté"
msgid "Invalid OS"
msgstr "OS non valide"
msgid "Invalid URL"
-msgstr ""
+msgstr "URL non valide"
msgid "Invalid URL: %{url}"
msgstr "URL non valide : %{url}"
@@ -21896,7 +22152,7 @@ msgid "Invalid file format with specified file type"
msgstr "Format de fichier non valide avec le type de fichier spécifié"
msgid "Invalid file."
-msgstr ""
+msgstr "Fichier non valide."
msgid "Invalid format selected"
msgstr ""
@@ -21938,22 +22194,25 @@ msgid "Invalid status"
msgstr "État non valide"
msgid "Invalid two-factor code."
-msgstr ""
+msgstr "Code à deux facteurs invalide."
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr "Enquête sur la vulnérabilité : %{title}"
msgid "Invisible Captcha"
-msgstr ""
+msgstr "Captcha invisible"
msgid "Invisible Captcha helps prevent the creation of spam accounts. It adds a honeypot field and time-sensitive form submission to the account signup form."
-msgstr ""
+msgstr "Un Captcha invisible empêche la création de comptes poubelles. Il ajoute un champ pour servir de piège dans le formulaire de création de compte et tient compte du délai d'envoi."
msgid "Invitation"
-msgstr ""
+msgstr "Invitation"
msgid "Invitation declined"
msgstr "Invitation refusée"
@@ -21961,9 +22220,6 @@ msgstr "Invitation refusée"
msgid "Invite \"%{email}\" by email"
msgstr "Inviter « %{email} » par courriel"
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr "Inviter des membres"
@@ -22001,13 +22257,13 @@ msgid "InviteEmail|What's it about?"
msgstr "De quoi s'agit-il ?"
msgid "InviteEmail|You are invited to join the %{strong_start}%{project_or_group_name}%{strong_end}%{br_tag}%{project_or_group} as a %{role}"
-msgstr ""
+msgstr "Vous êtes invité à rejoindre le %{strong_start}%{project_or_group_name}%{strong_end}%{br_tag}%{project_or_group} en tant que %{role}"
msgid "InviteEmail|You have been invited to join the %{project_or_group_name} %{project_or_group} as a %{role}"
msgstr "Vous avez été invité(e) à rejoindre le %{project_or_group} %{project_or_group_name} en tant que %{role}"
msgid "InviteEmail|You were assigned the following tasks:"
-msgstr ""
+msgstr "Les tâches suivantes vous ont été assignées :"
msgid "InviteEmail|and has assigned you the following tasks:"
msgstr "et vous a assigné les tâches suivantes :"
@@ -22021,8 +22277,8 @@ msgstr "Invitez vos collègues"
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr "Nous avons remarqué que vous n’avez invité personne dans ce groupe. Invitez vos collègues afin de pouvoir discuter des tickets, collaborer sur les demandes de fusion et partager vos connaissances."
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
-msgstr "Pour bénéficier de plus de membres et accéder à des fonctionnalités payantes supplémentaires, un propriétaire de ce groupe peut commencer une période d'essai ou faire une mise à niveau vers une offre payante."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
+msgstr "Pour pouvoir avoir davantage de membres, le propriétaire de cet espace de noms peut %{trialLinkStart}commencer un essai%{trialLinkEnd} ou %{upgradeLinkStart}effectuer une mise à niveau%{upgradeLinkEnd} vers une édition payante."
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
msgstr "%{linkStart}En savoir plus%{linkEnd} sur les permissions des rôles"
@@ -22101,21 +22357,18 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] "Le membre suivant n'a pas pu être invité"
msgstr[1] "Les %d membres suivants n'ont pas pu être invités"
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr "Cette fonctionnalité est désactivée jusqu'à ce que ce groupe ait suffisamment d'espace pour plus de membres."
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr "Pour assigner des tickets à un nouveau membre de l'équipe, vous avez besoin d'un projet pour ceux-ci. %{linkStart}Créez un projet pour commencer.%{linkEnd}"
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr "Pour pouvoir avoir davantage de membres, un propriétaire de ce groupe peut %{trialLinkStart}commencer une période d'essai%{trialLinkEnd} ou %{upgradeLinkStart}effectuer une mise à niveau%{upgradeLinkEnd} vers une offre payante."
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
+msgstr ""
+
msgid "InviteMembersModal|Username or email address"
msgstr "Nom d’utilisateur ou adresse de messagerie"
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
-msgstr "Vous ne pouvez pas ajouter plus de membres, mais vous pouvez supprimer ceux qui n’ont plus besoin d’accès."
-
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
msgstr "Vous n'avez de place que pour %{count} %{members} de plus sur %{name}"
@@ -22162,7 +22415,7 @@ msgid "InviteReminderEmail|%{inviter} is still waiting for you to join GitLab"
msgstr "%{inviter} attend toujours que vous rejoigniez GitLab"
msgid "InviteReminderEmail|%{inviter} is waiting for you to join GitLab"
-msgstr ""
+msgstr "%{inviter} attend que vous rejoigniez GitLab"
msgid "InviteReminderEmail|%{inviter} is waiting for you to join the %{strong_start}%{project_or_group_name}%{strong_end} %{project_or_group} as a %{role}."
msgstr "%{inviter} attend que vous rejoigniez le %{project_or_group} %{strong_start}%{project_or_group_name}%{strong_end} en tant que %{role}."
@@ -22228,7 +22481,7 @@ msgid "IrkerService|Server host (optional)"
msgstr "Hôte du serveur (facultatif)"
msgid "IrkerService|Server port (optional)"
-msgstr ""
+msgstr "Port du serveur (facultatif)"
msgid "IrkerService|URI to add before each recipient."
msgstr "URI à ajouter avant chaque destinataire."
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr "%{wi_type} créé(e) %{created_at} par "
@@ -22267,7 +22526,7 @@ msgid "IssuableStatus|Closed (%{link})"
msgstr "Fermé (%{link})"
msgid "IssuableStatus|Created %{created_at} by"
-msgstr ""
+msgstr "Créé %{created_at} par"
msgid "IssuableStatus|duplicated"
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr "épopée"
+
+msgid "Issuable|escalation policy"
+msgstr "politique d'escalade"
+
+msgid "Issuable|iteration"
+msgstr "itération"
+
+msgid "Issuable|milestone"
+msgstr "jalon"
+
msgid "Issue"
msgstr "Ticket"
@@ -22297,7 +22568,7 @@ msgid "Issue already promoted to epic."
msgstr "Le ticket a déjà été promu en épopée."
msgid "Issue cannot be found."
-msgstr ""
+msgstr "Le ticket est introuvable."
msgid "Issue created from vulnerability %{vulnerability_link}"
msgstr "Ticket créé à partir de la vulnérabilité %{vulnerability_link}"
@@ -22330,7 +22601,7 @@ msgid "Issue types"
msgstr "Types de ticket"
msgid "Issue update failed"
-msgstr ""
+msgstr "La mise à jour du ticket a échoué"
msgid "Issue was closed by %{name} %{reason}"
msgstr "Le ticket a été fermé par %{name} %{reason}"
@@ -22393,7 +22664,7 @@ msgid "IssueList|created %{timeAgoString} by %{user}"
msgstr "créé %{timeAgoString} par %{user}"
msgid "IssueTracker|Custom issue tracker"
-msgstr ""
+msgstr "Gestionnaire de tickets personnalisé"
msgid "IssueTracker|Issue URL"
msgstr "URL du ticket"
@@ -22474,7 +22745,7 @@ msgid "Issues with no epic assigned"
msgstr "Tickets sans épopée attribuée"
msgid "Issues, merge requests, pushes, and comments."
-msgstr ""
+msgstr "Tickets, demandes de fusion, poussées et commentaires."
msgid "IssuesAnalytics|After you begin creating issues for your projects, we can start tracking and displaying metrics for them"
msgstr "Une fois que vous aurez commencé à créer des tickets d’incident en relation avec vos projets, nous pourrons commencer à en effectuer le suivi et afficher des statistiques les concernant"
@@ -22503,6 +22774,21 @@ msgstr "Afin d’élargir votre recherche, modifiez ou supprimez des critères d
msgid "IssuesAnalytics|Total:"
msgstr "Total :"
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr "Les tâches et les scénarios de test ne peuvent pas être déplacés."
+
+msgid "Issues|Tasks can not be moved."
+msgstr "Les tâches ne peuvent pas être déplacées."
+
+msgid "Issues|Test cases can not be moved."
+msgstr "Les scénarios de test ne peuvent pas être déplacés."
+
+msgid "Issues|There was an error while moving the issues."
+msgstr "Une erreur s'est produite lors du déplacement des tickets."
+
msgid "Issue|Title"
msgstr "Titre"
@@ -22513,13 +22799,13 @@ msgid "It looks like you have some draft commits in this branch."
msgstr "Il semble que vous ayez des brouillons de commits dans cette branche."
msgid "It looks like you're attempting to activate your subscription. Use %{a_start}the Subscription page%{a_end} instead."
-msgstr ""
+msgstr "Il semble que vous essayez d'activer votre abonnement. Utilisez %{a_start}la page d'abonnement%{a_end} à la place."
msgid "It may be several days before you see feature usage data."
msgstr "Il peut s'écouler plusieurs jours avant de voir les données d'utilisation des fonctionnalités."
msgid "It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected."
-msgstr ""
+msgstr "Il doit comporter une ligne d'en-tête et au moins deux colonnes : la première correspond au titre du ticket et la seconde à sa description. Le séparateur est détecté automatiquement."
msgid "It seems like the Dependency Scanning job ran successfully, but no dependencies have been detected in your project."
msgstr "Il semble que la tâche d'analyse des dépendances ait été exécutée avec succès, mais aucune dépendance n'a été détectée dans votre projet."
@@ -22528,13 +22814,13 @@ msgid "It seems that there is currently no available data for code coverage"
msgstr "Il semble n'y avoir actuellement aucune donnée disponible pour la couverture du code"
msgid "It's you"
-msgstr ""
+msgstr "C'est vous"
msgid "Italic text"
msgstr "Texte en italique"
msgid "Iteration"
-msgstr ""
+msgstr "Itération"
msgid "Iteration cannot be created for cadence"
msgstr "L'itération ne peut pas être créée pour la cadence"
@@ -22549,7 +22835,7 @@ msgid "Iteration removed"
msgstr "Itération supprimée"
msgid "Iteration updated"
-msgstr ""
+msgstr "Itération mise à jour"
msgid "Iterations"
msgstr "Itérations"
@@ -22573,7 +22859,7 @@ msgid "Iterations|Add iteration"
msgstr "Ajouter une itération"
msgid "Iterations|All"
-msgstr ""
+msgstr "Toutes"
msgid "Iterations|All scheduled iterations will remain scheduled even if you use a smaller number."
msgstr "Toutes les itérations planifiées resteront planifiées même si vous utilisez un nombre plus petit."
@@ -22591,7 +22877,7 @@ msgid "Iterations|Cadence name"
msgstr "Nom de la cadence"
msgid "Iterations|Cancel"
-msgstr ""
+msgstr "Annuler"
msgid "Iterations|Couldn't find iteration cadence"
msgstr "Impossible de trouver la cadence d'itération"
@@ -22600,7 +22886,7 @@ msgid "Iterations|Create cadence"
msgstr "Créer une cadence"
msgid "Iterations|Create iteration"
-msgstr ""
+msgstr "Créer une itération"
msgid "Iterations|Create iterations automatically on a regular schedule."
msgstr "Créer automatiquement des itérations selon une planification périodique."
@@ -22615,7 +22901,7 @@ msgid "Iterations|Delete iteration?"
msgstr "Supprimer l'itération ?"
msgid "Iterations|Description"
-msgstr ""
+msgstr "Description"
msgid "Iterations|Done"
msgstr ""
@@ -22636,7 +22922,7 @@ msgid "Iterations|Edit iteration cadence"
msgstr "Modifier la cadence d'itération"
msgid "Iterations|Enable automatic scheduling"
-msgstr ""
+msgstr "Activer la planification automatique"
msgid "Iterations|Enable roll over"
msgstr "Activer la reconduction"
@@ -22669,7 +22955,7 @@ msgid "Iterations|No iteration cadences to show."
msgstr "Aucune cadence d'itération à afficher."
msgid "Iterations|No iterations found"
-msgstr ""
+msgstr "Aucune itération trouvée"
msgid "Iterations|No iterations in cadence."
msgstr "Aucune itération dans la cadence."
@@ -22684,10 +22970,10 @@ msgid "Iterations|Open"
msgstr ""
msgid "Iterations|Roll over issues"
-msgstr ""
+msgstr "Reporter les tickets"
msgid "Iterations|Save changes"
-msgstr ""
+msgstr "Enregistrer les modifications"
msgid "Iterations|Select duration"
msgstr "Sélectionnez une durée"
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr "ID de l'Application Jira Connect"
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr "La nouvelle branche a été créée avec succès."
@@ -22909,7 +23198,7 @@ msgid "JiraService|Issues created from vulnerabilities in this project will be J
msgstr "Les tickets créés à partir des vulnérabilités de ce projet seront des tickets Jira, même si les tickets GitLab sont activés."
msgid "JiraService|Jira API URL"
-msgstr ""
+msgstr "URL de l'API Jira"
msgid "JiraService|Jira comments are created when an issue is referenced in a commit."
msgstr "Les commentaires Jira sont créés lorsqu'un ticket est référencé dans un commit."
@@ -22933,7 +23222,7 @@ msgid "JiraService|Open Jira"
msgstr "Ouvrir Jira"
msgid "JiraService|Password or API token"
-msgstr ""
+msgstr "Mot de passe ou jeton d'API"
msgid "JiraService|Project key changed, refresh list"
msgstr "Clé de projet modifiée, actualiser la liste"
@@ -22984,7 +23273,7 @@ msgid "JiraService|Web URL"
msgstr "URL Web"
msgid "JiraService|Welcome to GitLab for Jira"
-msgstr ""
+msgstr "Bienvenue sur GitLab pour Jira"
msgid "JiraService|What version of GitLab are you using?"
msgstr "Quelle version de GitLab utilisez-vous ?"
@@ -23026,7 +23315,7 @@ msgid "Job is stuck. Check runners."
msgstr ""
msgid "Job logs and artifacts"
-msgstr ""
+msgstr "Artéfacts et journaux des tâches"
msgid "Job to create self-monitoring project is in progress"
msgstr "La tâche de création d'un projet d'auto-surveillance est en cours"
@@ -23047,7 +23336,7 @@ msgid "Jobs older than the configured time are considered expired and are archiv
msgstr "Les tâches antérieures à la durée configurée sont considérées expirées et sont archivées. Les tâches archivées ne peuvent plus être retentées. Laissez vide pour ne jamais archiver les tâches automatiquement. L'unité par défaut est en jours, mais vous pouvez en utiliser d'autres, par exemple %{code_open}15 days%{code_close}, %{code_open}1 month%{code_close}, %{code_open}2 years%{code_close}. La valeur minimale est de 1 jour."
msgid "Jobs|All"
-msgstr ""
+msgstr "Toutes"
msgid "Jobs|An error occurred while loading the Failed Jobs tab."
msgstr "Une erreur s'est produite lors du chargement de l'onglet des Tâches ayant échoué."
@@ -23065,7 +23354,7 @@ msgid "Jobs|Filter jobs"
msgstr "Filtrer les tâches"
msgid "Jobs|Finished"
-msgstr ""
+msgstr "Terminées"
msgid "Jobs|Job is stuck. Check runners."
msgstr "La tâche est bloquée. Vérifiez les exécuteurs."
@@ -23127,6 +23416,9 @@ msgstr "Créée"
msgid "Job|Download"
msgstr "Télécharger"
+msgid "Job|Duration"
+msgstr "Durée"
+
msgid "Job|Erase job log and artifacts"
msgstr "Effacer le journal des tâches et les artéfacts"
@@ -23166,9 +23458,15 @@ msgstr "En attente"
msgid "Job|Preparing"
msgstr "En préparation"
+msgid "Job|Queued"
+msgstr "En file d'attente"
+
msgid "Job|Retry"
msgstr "Réessayer"
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr "En cours"
@@ -23203,7 +23501,7 @@ msgid "Job|The artifacts were removed"
msgstr "Les artefacts ont été supprimés"
msgid "Job|The artifacts will be removed"
-msgstr ""
+msgstr "Les artéfacts seront supprimés"
msgid "Job|There was a problem retrying the failed job."
msgstr ""
@@ -23275,7 +23573,7 @@ msgid "June"
msgstr "juin"
msgid "Just me"
-msgstr ""
+msgstr "Moi uniquement"
msgid "K8s pod health"
msgstr ""
@@ -23299,10 +23597,10 @@ msgid "Kerberos access denied"
msgstr "Accès Kerberos refusé"
msgid "Key"
-msgstr ""
+msgstr "Clé"
msgid "Key (PEM)"
-msgstr ""
+msgstr "Clé (PEM)"
msgid "Key:"
msgstr "Clé :"
@@ -23326,7 +23624,7 @@ msgid "KeyboardKey|Esc"
msgstr "Échap"
msgid "KeyboardKey|Shift"
-msgstr ""
+msgstr "Shift"
msgid "KeyboardShortcuts|No shortcuts matched your search"
msgstr "Aucun raccourci ne correspond à votre recherche"
@@ -23338,7 +23636,7 @@ msgid "Keys"
msgstr "Clés"
msgid "Ki"
-msgstr ""
+msgstr "Ki"
msgid "Kroki"
msgstr "Kroki"
@@ -23350,7 +23648,7 @@ msgid "Kubernetes Cluster"
msgstr "Grappe de serveurs Kubernetes"
msgid "Kubernetes Clusters"
-msgstr ""
+msgstr "Grappe de serveurs Kubernetes"
msgid "Kubernetes cluster"
msgstr "Grappe de serveurs Kubernetes"
@@ -23371,13 +23669,13 @@ msgid "Kubernetes clusters"
msgstr "Grappes de serveurs Kubernetes"
msgid "Kubernetes deployment not found"
-msgstr ""
+msgstr "Déploiement de Kubernetes introuvable"
msgid "Kubernetes error: %{error_code}"
-msgstr ""
+msgstr "Erreur Kubernetes : %{error_code}"
msgid "LDAP"
-msgstr ""
+msgstr "LDAP"
msgid "LDAP Synchronization"
msgstr "Synchronisation LDAP"
@@ -23386,13 +23684,13 @@ msgid "LDAP group settings"
msgstr "Paramètres de groupe LDAP"
msgid "LDAP settings"
-msgstr ""
+msgstr "Paramètres LDAP"
msgid "LDAP settings updated"
msgstr "Paramètres LDAP mis à jour"
msgid "LDAP sync in progress. This could take a few minutes. Refresh the page to see the changes."
-msgstr ""
+msgstr "Synchro LDAP en cours. Cela peut prendre quelques minutes. Actualiser la page pour voir les modifications."
msgid "LDAP synchronizations"
msgstr "Synchronisations LDAP"
@@ -23404,7 +23702,7 @@ msgid "LFS"
msgstr "LFS"
msgid "LFS objects"
-msgstr ""
+msgstr "Objets LFS"
msgid "LFSStatus|Disabled"
msgstr "Désactivé"
@@ -23413,7 +23711,7 @@ msgid "LFSStatus|Enabled"
msgstr "Activé"
msgid "LICENSE"
-msgstr ""
+msgstr "LICENSE"
msgid "Label"
msgstr "Étiquette"
@@ -23430,13 +23728,13 @@ msgid "Label priority"
msgstr "Priorité de l'étiquette"
msgid "Label was created"
-msgstr ""
+msgstr "L'étiquette a été créée"
msgid "Label was removed"
msgstr "L'étiquette a été supprimée"
msgid "Label was successfully updated."
-msgstr ""
+msgstr "L'étiquette a été mise à jour avec succès."
msgid "LabelSelect|%{firstLabelName} +%{remainingLabelCount} more"
msgstr "%{firstLabelName} +%{remainingLabelCount} de plus"
@@ -23522,13 +23820,13 @@ msgid "Last Sync"
msgstr "Dernière Synchro"
msgid "Last Used"
-msgstr ""
+msgstr "Dernière Utilisation"
msgid "Last accessed on"
-msgstr ""
+msgstr "Dernier accès le"
msgid "Last activity"
-msgstr ""
+msgstr "Dernière activité"
msgid "Last commit"
msgstr "Dernier commit"
@@ -23545,9 +23843,6 @@ msgstr "Dernière modification par %{link_start}%{avatar} %{name}%{link_end}"
msgid "Last event"
msgstr "Dernier événement"
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr "Dernière modification"
@@ -23624,22 +23919,22 @@ msgid "Latest changes"
msgstr "Derniers changements"
msgid "Latest pipeline for the most recent commit on this branch"
-msgstr ""
+msgstr "Dernier pipeline pour la validation la plus récente sur cette branche"
msgid "Launch a ready-to-code development environment for your project."
msgstr "Lancer un environnement de développement prêt-à-coder pour votre projet."
msgid "Layout|Fixed"
-msgstr ""
+msgstr "Fixe"
msgid "Layout|Fluid"
-msgstr ""
+msgstr "Fluide"
msgid "Lead Time"
-msgstr ""
+msgstr "Délai de mise à disposition"
msgid "Lead Time for Changes"
-msgstr ""
+msgstr "Délai d'Exécution des Changements"
msgid "Lead time"
msgstr "Délai de mise à disposition"
@@ -23654,10 +23949,10 @@ msgid "Learn More."
msgstr "En savoir plus."
msgid "Learn how to %{link_start}contribute to the built-in templates%{link_end}"
-msgstr ""
+msgstr "Apprenez comment %{link_start}contribuer aux modèles intégrés%{link_end}"
msgid "Learn how to %{no_packages_link_start}publish and share your packages%{no_packages_link_end} with GitLab."
-msgstr ""
+msgstr "Apprenez comment %{no_packages_link_start}publier et partager vos paquets%{no_packages_link_end} avec GitLab."
msgid "Learn more"
msgstr "En savoir plus"
@@ -23666,7 +23961,7 @@ msgid "Learn more about %{name}"
msgstr "En savoir plus sur %{name}"
msgid "Learn more about Auto DevOps"
-msgstr ""
+msgstr "En savoir plus sur Auto DevOps"
msgid "Learn more about GitLab"
msgstr "En savoir plus sur GitLab"
@@ -23675,25 +23970,25 @@ msgid "Learn more about Needs relationships"
msgstr "En savoir plus sur les relations de Besoins"
msgid "Learn more about Web Terminal"
-msgstr ""
+msgstr "En savoir plus sur le Terminal Web"
msgid "Learn more about X.509 signed commits"
msgstr ""
msgid "Learn more about adding certificates to your project by following the %{docs_link_start}documentation on GitLab Pages%{docs_link_end}."
-msgstr ""
+msgstr "En savoir plus sur l'ajout de certificats à votre projet en suivant la %{docs_link_start}documentation de GitLab Pages%{docs_link_end}."
msgid "Learn more about custom project templates"
-msgstr ""
+msgstr "En savoir plus sur les modèles de projet personnalisés"
msgid "Learn more about deploying to AWS"
msgstr "En savoir plus sur le déploiement vers AWS"
msgid "Learn more about deploying to a cluster"
-msgstr ""
+msgstr "En savoir plus sur le déploiement vers une grappe de serveurs"
msgid "Learn more about group-level project templates"
-msgstr ""
+msgstr "En savoir plus sur les modèles de projet de niveau groupe"
msgid "Learn more about groups."
msgstr "En savoir plus sur les groupes."
@@ -23701,6 +23996,15 @@ msgstr "En savoir plus sur les groupes."
msgid "Learn more about issues."
msgstr "En savoir plus sur les tickets."
+msgid "Learn more about linking epics"
+msgstr "En savoir plus sur la liaison d'épopées"
+
+msgid "Learn more about linking issues"
+msgstr "En savoir plus sur la liaison de tickets"
+
+msgid "Learn more about linking issues and incidents"
+msgstr "En savoir plus sur la liaison de tickets et d'incidents"
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23711,7 +24015,7 @@ msgid "Learn more about shards and replicas in the %{configuration_link_start}Ad
msgstr "En savoir plus sur les fragments et les réplicas grâce à la documentation sur la %{configuration_link_start}configuration de Recherche Avancée%{configuration_link_end}. Les changements ne seront pas effectifs tant que vous n'aurez pas %{recreated_link_start}recréé%{recreated_link_end} l'index."
msgid "Learn more about signing commits"
-msgstr ""
+msgstr "En savoir plus sur la signature des validations"
msgid "Learn more in the"
msgstr "Apprenezâ€en plus dans la"
@@ -23720,7 +24024,7 @@ msgid "Learn more."
msgstr "En savoir plus."
msgid "LearnGitLab|%{percentage}%{percentSymbol} completed"
-msgstr ""
+msgstr "Terminé à %{percentage}%{percentSymbol}"
msgid "LearnGitLab|Add code owners"
msgstr "Ajouter des propriétaires de code"
@@ -23738,7 +24042,7 @@ msgid "LearnGitLab|Create a workflow for your new workspace, and learn how GitLa
msgstr "Créez un flux de travail pour votre nouvel environnement et découvrez la façon dont les fonctionnalités de GitLab fonctionnent ensemble :"
msgid "LearnGitLab|Create an issue"
-msgstr "Créer un ticket"
+msgstr "Créez un ticket"
msgid "LearnGitLab|Create or import your first repository into your new project."
msgstr "Créez ou importez votre premier dépôt dans votre nouveau projet."
@@ -23762,13 +24066,13 @@ msgid "LearnGitLab|Learn GitLab"
msgstr ""
msgid "LearnGitLab|Plan and execute"
-msgstr ""
+msgstr "Planifier et exécuter"
msgid "LearnGitLab|Prevent unexpected changes to important assets by assigning ownership of files and paths."
msgstr ""
msgid "LearnGitLab|Ready to get started with GitLab? Follow these steps to set up your workspace, plan and commit changes, and deploy your project."
-msgstr ""
+msgstr "Prêt à démarrer avec GitLab? Suivez ces étapes pour configurer votre espace de travail, planifier et valider des modifications et déployer votre projet."
msgid "LearnGitLab|Review and edit proposed changes to source code."
msgstr "Examiner et modifier les modifications proposées au code source."
@@ -23777,7 +24081,7 @@ msgid "LearnGitLab|Route code reviews to the right reviewers, every time."
msgstr "Attribuer les revues de code aux bons relecteurs, à chaque fois."
msgid "LearnGitLab|Run a Security scan using CI/CD"
-msgstr "Exécuter une analyse de Sécurité avec CI/CD"
+msgstr "Exécutez une analyse de Sécurité avec CI/CD"
msgid "LearnGitLab|Save time by automating your integration and deployment tasks."
msgstr "Gagnez du temps en automatisant vos tâches d'intégration et de déploiement."
@@ -23798,7 +24102,7 @@ msgid "LearnGitLab|Set up your first project's CI/CD"
msgstr "Configurez CI/CD pour votre premier projet"
msgid "LearnGitLab|Set up your workspace"
-msgstr ""
+msgstr "Configurer votre espace de travail"
msgid "LearnGitLab|Start a free trial of GitLab Ultimate"
msgstr "Commencez un essai gratuit de GitLab Ultimate"
@@ -23837,10 +24141,10 @@ msgid "Leave"
msgstr "Quitter"
msgid "Leave Admin Mode"
-msgstr ""
+msgstr "Quitter le Mode Admin"
msgid "Leave edit mode? All unsaved changes will be lost."
-msgstr ""
+msgstr "Quitter le mode édition ? Toutes les modifications non enregistrées seront perdues."
msgid "Leave group"
msgstr "Quitter le groupe"
@@ -23851,9 +24155,6 @@ msgstr "Quitter le projet"
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr "Laisser ce paramètre activé est recommandé."
-
msgid "Legacy burndown chart"
msgstr "Ancien graphique d'avancement"
@@ -23870,10 +24171,10 @@ msgid "Let's Encrypt does not accept emails on example.com"
msgstr ""
msgid "Let's Encrypt is a free, automated, and open certificate authority (CA) that gives digital certificates in order to enable HTTPS (SSL/TLS) for websites. Learn more about Let's Encrypt configuration by following the %{docs_link_start}documentation on GitLab Pages%{docs_link_end}."
-msgstr ""
+msgstr "Let's Encrypt est une autorité de certification (CA) gratuite, automatisée et ouverte, qui fournit des certificats numériques afin d'activer HTTPS (SSL/TLS) pour les sites Web. En savoir plus sur la configuration de Let's Encrypt en suivant la %{docs_link_start}documentation de GitLab Pages%{docs_link_end}."
msgid "License Compliance"
-msgstr ""
+msgstr "Conformité de Licence"
msgid "License Compliance| Used by %{dependencies}"
msgstr "Utilisée par %{dependencies}"
@@ -23903,19 +24204,19 @@ msgid "LicenseCompliance|Add license and related policy"
msgstr "Ajouter une licence et sa stratégie associée"
msgid "LicenseCompliance|Add license policy"
-msgstr ""
+msgstr "Ajouter une stratégie de licences"
msgid "LicenseCompliance|Allow"
-msgstr ""
+msgstr "Autoriser"
msgid "LicenseCompliance|Allowed"
-msgstr ""
+msgstr "Autorisée"
msgid "LicenseCompliance|Denied"
-msgstr ""
+msgstr "Refusée"
msgid "LicenseCompliance|Deny"
-msgstr ""
+msgstr "Refuser"
msgid "LicenseCompliance|Disallow merge request if detected and will instruct developer to remove"
msgstr "Interdire la demande de fusion si détectée puis ordonner au développeur de supprimer"
@@ -23940,8 +24241,8 @@ msgstr[1] ""
msgid "LicenseCompliance|License Compliance detected %d new license"
msgid_plural "LicenseCompliance|License Compliance detected %d new licenses"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "La Conformité de Licence a détecté %d nouvelle licence"
+msgstr[1] "La Conformité de Licence a détecté %d nouvelles licences"
msgid "LicenseCompliance|License Compliance detected %d new license and policy violation"
msgid_plural "LicenseCompliance|License Compliance detected %d new licenses and policy violations"
@@ -23957,10 +24258,10 @@ msgid "LicenseCompliance|License Compliance detected no licenses for the source
msgstr ""
msgid "LicenseCompliance|License Compliance detected no new licenses"
-msgstr ""
+msgstr "La Conformité de Licence n'a détecté aucune nouvelle licence"
msgid "LicenseCompliance|License name"
-msgstr ""
+msgstr "Nom de la licence"
msgid "LicenseCompliance|No policy matches this license"
msgstr "Aucune politique ne correspond à cette licence"
@@ -23969,10 +24270,10 @@ msgid "LicenseCompliance|Out-of-compliance with the project's policies and shoul
msgstr "Non conforme(s) aux stratégies du projet et à supprimer"
msgid "LicenseCompliance|Remove license"
-msgstr ""
+msgstr "Supprimer la licence"
msgid "LicenseCompliance|Remove license?"
-msgstr ""
+msgstr "Supprimer la licence ?"
msgid "LicenseCompliance|There are currently no policies in this project."
msgstr "Il n'y a actuellement aucune stratégie dans ce projet."
@@ -23981,7 +24282,7 @@ msgid "LicenseCompliance|There are currently no policies that match in this proj
msgstr ""
msgid "LicenseCompliance|This license already exists in this project."
-msgstr ""
+msgstr "Cette licence existe déjà dans ce projet."
msgid "LicenseCompliance|Uncategorized"
msgstr ""
@@ -23993,10 +24294,10 @@ msgid "LicenseCompliance|You are about to remove the license, %{name}, from this
msgstr ""
msgid "LicenseManagement|Allowed"
-msgstr ""
+msgstr "Autorisée"
msgid "LicenseManagement|Denied"
-msgstr ""
+msgstr "Refusée"
msgid "LicenseManagement|Uncategorized"
msgstr ""
@@ -24020,13 +24321,13 @@ msgid "Licenses|Acceptable license to be used in the project"
msgstr "Licence acceptable pouvant être utilisée dans le projet"
msgid "Licenses|Component"
-msgstr ""
+msgstr "Composant"
msgid "Licenses|Components"
-msgstr ""
+msgstr "Composants"
msgid "Licenses|Detected in Project"
-msgstr ""
+msgstr "Détectées dans le Projet"
msgid "Licenses|Displays licenses detected in the project that are out of compliance with the project's policies, based on the %{linkStart}latest successful%{linkEnd} scan"
msgstr "Affiche les licences détectées dans le projet qui ne sont pas conformes aux stratégies du projet, en se basant sur la%{linkStart}dernière analyse réussie%{linkEnd}"
@@ -24074,7 +24375,7 @@ msgid "Licenses|View license details for your project"
msgstr "Voir les détails de la licence de votre projet"
msgid "Limit display of time tracking units to hours."
-msgstr ""
+msgstr "Limiter l'affichage des unités de suivi du temps aux heures."
msgid "Limit sign in from multiple IP addresses"
msgstr ""
@@ -24089,7 +24390,7 @@ msgid "Limit the number of pipeline creation requests per minute. This limit inc
msgstr "Limiter le nombre de requêtes de création de pipelines par minute. Cette limite inclut les pipelines créés via l'interface utilisateur, l'API et les traitements en arrière-plan."
msgid "Limit the size of Sidekiq jobs stored in Redis."
-msgstr ""
+msgstr "Limiter la taille des tâches Sidekiq stockées dans Redis."
msgid "Limiting mode"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr "Lignes changées"
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr "Lien (facultatif)"
@@ -24107,7 +24414,7 @@ msgid "Link Sentry to GitLab to discover and view the errors your application ge
msgstr "Associer Sentry à GitLab pour découvrir et afficher les erreurs générées par votre application."
msgid "Link URL"
-msgstr ""
+msgstr "URL du lien"
msgid "Link an external wiki from the project's sidebar. %{docs_link}"
msgstr "Lier un wiki externe à la barre latérale du projet. %{docs_link}"
@@ -24119,16 +24426,16 @@ msgid "Link text"
msgstr "Texte de lien"
msgid "Link title"
-msgstr ""
+msgstr "Titre du lien"
msgid "Link title is required"
-msgstr ""
+msgstr "Le titre du lien est requis"
msgid "Link to go to GitLab pipeline documentation"
msgstr "Lien vers la documentation des pipelines GitLab"
msgid "Link to your Grafana instance."
-msgstr ""
+msgstr "Créer un lien vers votre instance Grafana."
msgid "Linked emails (%{email_count})"
msgstr ""
@@ -24269,7 +24576,7 @@ msgid "Loading..."
msgstr "Chargement…"
msgid "Loading…"
-msgstr ""
+msgstr "Chargement en cours…"
msgid "Localization"
msgstr "Localisation"
@@ -24323,7 +24630,7 @@ msgid "Locks give the ability to lock specific file or folder."
msgstr "Les verrous permettent de verrouiller un fichier ou un dossier spécifique."
msgid "Locks the discussion."
-msgstr ""
+msgstr "Verrouille la discussion."
msgid "LoggedOutMarketingHeader|About GitLab"
msgstr "À propos de GitLab"
@@ -24362,7 +24669,7 @@ msgid "Login with smartcard"
msgstr "Se connecter avec une carte à puce"
msgid "Logo was successfully removed."
-msgstr ""
+msgstr "Le logo a été supprimé avec succès."
msgid "Logo will be removed. Are you sure?"
msgstr "Le logo sera supprimé. Êtesâ€vous sûr(e) ?"
@@ -24370,9 +24677,6 @@ msgstr "Le logo sera supprimé. Êtesâ€vous sûr(e) ?"
msgid "Logs"
msgstr "Journaux"
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr "Vulnérabilités faibles présentes"
@@ -24380,11 +24684,14 @@ msgid "MB"
msgstr "Mo"
msgid "MD5"
-msgstr ""
+msgstr "MD5"
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr "Revenir à la demande de fusion"
@@ -24404,7 +24711,7 @@ msgid "MRApprovals|Approved by"
msgstr ""
msgid "MRApprovals|Approvers"
-msgstr ""
+msgstr "Approbateurs"
msgid "MRApprovals|Commented by"
msgstr "Mise en commentaire par"
@@ -24421,8 +24728,14 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
-msgstr "Ce ticket est désormais confidentiel."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
+msgstr ""
msgid "Mailgun"
msgstr "Mailgun"
@@ -24436,23 +24749,26 @@ msgstr "Événements Mailgun"
msgid "Main menu"
msgstr "Menu principal"
+msgid "Maintainer"
+msgstr "Responsable"
+
msgid "Maintenance mode"
msgstr "Mode maintenance"
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
msgid "Make and review changes in the browser with the Web IDE"
-msgstr ""
+msgstr "Effectuer et examiner les modifications dans le navigateur avec l'EDI Web"
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr "Rendez chaque membre de votre équipe plus productif, quel que soit l’endroit où il se situe. GitLab Geo crée des miroirs en lecture seule de votre instance GitLab afin que vous puissiez réduire le temps nécessaire pour cloner et récupérer de gros dépôts."
-msgid "Make issue confidential"
-msgstr "Rendre le ticket confidentiel"
-
msgid "Make sure you choose a strong, unique password."
-msgstr ""
+msgstr "Assurez-vous de choisir un mot de passe fort et unique."
msgid "Make sure you have the correct permissions to link your project."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24503,13 +24819,13 @@ msgid "Manage projects."
msgstr "Gérer les projets."
msgid "Manage two-factor authentication"
-msgstr ""
+msgstr "Gérer l'authentification à deux facteurs"
msgid "Manage your project's triggers"
msgstr "Gérez les déclencheurs de votre projet"
msgid "Manage your subscription"
-msgstr ""
+msgstr "Gérer votre abonnement"
msgid "Managed Account"
msgstr ""
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr "Manifeste"
+msgid "Manifest file"
+msgstr "Fichier manifeste"
+
msgid "Manifest file import"
msgstr "Importation de fichier manifeste"
@@ -24541,6 +24860,9 @@ msgstr "mars"
msgid "March"
msgstr "mars"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr "Impossible de récupérer le contenu de l'aide."
+
msgid "Mark as done"
msgstr "Marquer comme terminé"
@@ -24551,7 +24873,7 @@ msgid "Mark as ready"
msgstr "Marquer comme prêt"
msgid "Mark this issue as a duplicate of another issue"
-msgstr ""
+msgstr "Marquer ce ticket comme un doublon d'un autre ticket"
msgid "Mark this issue as related to another issue"
msgstr "Marquer ce ticket comme lié à un autre ticket"
@@ -24563,7 +24885,7 @@ msgid "Markdown Help"
msgstr "Aide sur Markdown"
msgid "Markdown enabled."
-msgstr ""
+msgstr "Markdown activé."
msgid "Markdown supported."
msgstr "Markdown pris en charge."
@@ -24592,6 +24914,9 @@ msgstr "Ajouter un texte barré (%{modifierKey}⇧X)"
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr "Ajouter un texte barré (%{modifier_key}⇧X)"
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr "Désindenter une ligne (%{modifierKey}[)"
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr "Désindenter une ligne (%{modifier_key}[)"
+msgid "MarkdownEditor|header"
+msgstr "en-tête"
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr "Prend en charge le %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
@@ -24623,7 +24951,7 @@ msgid "Marked this %{noun} as ready."
msgstr ""
msgid "Marked this issue as a duplicate of %{duplicate_param}."
-msgstr ""
+msgstr "Ce ticket a été marqué comme un doublon de %{duplicate_param}."
msgid "Marked this issue as related to %{issue_ref}."
msgstr "a lié ce ticket au %{issue_ref}."
@@ -24638,7 +24966,7 @@ msgid "Marks this %{noun} as ready."
msgstr ""
msgid "Marks this issue as a duplicate of %{duplicate_reference}."
-msgstr ""
+msgstr "Marque ce ticket comme un doublon de %{duplicate_reference}."
msgid "Marks this issue as related to %{issue_ref}."
msgstr "Marque ce ticket comme lié à %{issue_ref}."
@@ -24647,10 +24975,10 @@ msgid "Marks to do as done."
msgstr "Marque comme fait."
msgid "Mask variable"
-msgstr ""
+msgstr "Masquer la variable"
msgid "Match not found; try refining your search query."
-msgstr ""
+msgstr "Aucune correspondance trouvée ; essayez d'affiner votre demande de recherche."
msgid "Mattermost"
msgstr "Mattermost"
@@ -24662,7 +24990,7 @@ msgid "Mattermost notifications"
msgstr "Notifications Mattermost"
msgid "MattermostService|Add to Mattermost"
-msgstr ""
+msgstr "Ajouter à Mattermost"
msgid "MattermostService|After you configure the integration, view your new Mattermost commands by entering"
msgstr "Après avoir configuré l’intégration, affichez vos nouvelles commandes Mattermost en entrant"
@@ -24674,10 +25002,10 @@ msgid "MattermostService|Fill in the word that works best for your team."
msgstr ""
msgid "MattermostService|Request URL"
-msgstr ""
+msgstr "URL de requête"
msgid "MattermostService|Request method"
-msgstr ""
+msgstr "Méthode de requête"
msgid "MattermostService|Response icon"
msgstr ""
@@ -24686,7 +25014,7 @@ msgid "MattermostService|Response username"
msgstr ""
msgid "MattermostService|Suggestions:"
-msgstr ""
+msgstr "Suggestions :"
msgid "MattermostService|Use this service to perform common tasks in your project by entering slash commands in Mattermost."
msgstr "Utilisez ce service pour effectuer des tâches courantes dans votre projet en entrant des commandes barre oblique dans Mattermost."
@@ -24743,16 +25071,16 @@ msgid "Maximum allowed lifetime for SSH keys (days)"
msgstr "Durée de vie maximale autorisée pour les clés SSH (jours)"
msgid "Maximum artifacts size"
-msgstr ""
+msgstr "Taille maximale des artéfacts"
msgid "Maximum artifacts size (MB)"
-msgstr ""
+msgstr "Taille maximale des artéfacts (Mo)"
msgid "Maximum attachment size"
msgstr "Taille maximale des pièces jointes"
msgid "Maximum attachment size (MB)"
-msgstr ""
+msgstr "Taille maximale des pièces jointes (Mo)"
msgid "Maximum authenticated API requests per rate limit period per user"
msgstr ""
@@ -24785,13 +25113,13 @@ msgid "Maximum duration of a session."
msgstr "Durée maximale d'une session."
msgid "Maximum export size"
-msgstr ""
+msgstr "Taille maximale de l'exportation"
msgid "Maximum export size (MB)"
-msgstr ""
+msgstr "Taille maximale de l'exportation (Mo)"
msgid "Maximum field length"
-msgstr ""
+msgstr "Longueur maximale de champ"
msgid "Maximum file size indexed (KiB)"
msgstr "Taille maximale de fichier à indexer (KiB)"
@@ -24800,7 +25128,7 @@ msgid "Maximum file size is 1 MB. Image size must be 32 x 32 pixels. Allowed ima
msgstr "La taille maximale du fichier est de 1 Mo. Les dimensions de l'image doivent être de 32×32 pixels. Les formats d'image autorisés sont %{favicon_extension_allowlist}."
msgid "Maximum file size is 1MB. Pages are optimized for a 24px tall header logo"
-msgstr ""
+msgstr "La taille maximale du fichier est de 1 Mo. Les pages sont optimisées pour un logo d'en-tête de 24 px de haut"
msgid "Maximum file size is 1MB. Pages are optimized for a 640x360 px logo."
msgstr "La taille maximale du fichier est de 1 Mo. Les pages sont optimisées pour un logo de 640x360 px."
@@ -24809,19 +25137,19 @@ msgid "Maximum files in a diff"
msgstr "Nombre maximum de fichiers dans un diff"
msgid "Maximum group export download requests per minute"
-msgstr ""
+msgstr "Nombre maximum de requêtes de téléchargement d'export de groupes par minute"
msgid "Maximum group export requests per minute"
-msgstr ""
+msgstr "Nombre maximum de requêtes d'exportation de groupes par minute"
msgid "Maximum group import requests per minute"
-msgstr ""
+msgstr "Nombre maximum de requêtes d'importation de groupes par minute"
msgid "Maximum import size"
msgstr "Taille maximale de l'importation"
msgid "Maximum import size (MB)"
-msgstr ""
+msgstr "Taille maximale de l'importation (Mo)"
msgid "Maximum job artifact size"
msgstr "Taille maximale des artéfacts des tâches"
@@ -24830,7 +25158,7 @@ msgid "Maximum job timeout"
msgstr "Durée maximale d’exécution de la tâche"
msgid "Maximum job timeout has a value which could not be accepted"
-msgstr ""
+msgstr "Le délai d'attente maximal pour les tâches a une valeur qui ne peut pas être acceptée"
msgid "Maximum lines in a diff"
msgstr "Nombre maximum de lignes dans un diff"
@@ -24848,19 +25176,19 @@ msgid "Maximum number of comments exceeded"
msgstr ""
msgid "Maximum number of mirrors that can be synchronizing at the same time."
-msgstr ""
+msgstr "Nombre maximum de miroirs pouvant être synchronisés en même temps."
msgid "Maximum number of projects."
-msgstr ""
+msgstr "Nombre maximum de projets."
msgid "Maximum number of requests per minute"
-msgstr ""
+msgstr "Nombre maximum de requêtes par minute"
msgid "Maximum number of requests per minute for an authenticated user"
-msgstr ""
+msgstr "Nombre maximum de requêtes par minute pour un utilisateur authentifié"
msgid "Maximum number of requests per minute for an unauthenticated IP address"
-msgstr ""
+msgstr "Nombre maximum de requêtes par minute pour une adresse IP non authentifiée"
msgid "Maximum number of requests per minute for each raw path (default is 300). Set to 0 to disable throttling."
msgstr ""
@@ -24872,7 +25200,7 @@ msgid "Maximum number of variables loaded (2000)"
msgstr "Nombre maximum de variables chargées (2000)"
msgid "Maximum of 255 characters"
-msgstr ""
+msgstr "Maximum de 255 caractères"
msgid "Maximum page reached"
msgstr "Page maximale atteinte"
@@ -24881,13 +25209,13 @@ msgid "Maximum page size"
msgstr "Taille maximale de page"
msgid "Maximum project export download requests per minute"
-msgstr ""
+msgstr "Nombre maximum de requêtes de téléchargement d'export de projets par minute"
msgid "Maximum project export requests per minute"
-msgstr ""
+msgstr "Nombre maximum de requêtes d'exportation de projets par minute"
msgid "Maximum project import requests per minute"
-msgstr ""
+msgstr "Nombre maximum de requêtes d'importation de projets par minute"
msgid "Maximum push size"
msgstr "Taille maximale de poussée"
@@ -24935,7 +25263,7 @@ msgid "Maximum time that users are allowed to skip the setup of two-factor authe
msgstr "Durée maximale pendant laquelle les utilisateurs sont autorisés à ignorer la configuration de l'authentification à deux facteurs (en heures). Définir sur 0 (zéro) pour l'imposer à la prochaine connexion."
msgid "Maximum time, in seconds, for a web terminal websocket connection. 0 for unlimited."
-msgstr ""
+msgstr "Durée maximale, en secondes, pour une connexion websocket du terminal web. 0 pour illimitée."
msgid "Maximum unauthenticated API requests per rate limit period per IP"
msgstr ""
@@ -24980,7 +25308,7 @@ msgid "Members can be added by project %{i_open}Maintainers%{i_close} or %{i_ope
msgstr "Les membres peuvent être ajoutés par les %{i_open}Mainteneurs%{i_close} ou %{i_open}Propriétaires%{i_close} du projet"
msgid "Members listed as CODEOWNERS of affected files."
-msgstr ""
+msgstr "Membres répertoriés comme propriétaires du code des fichiers concernés dans le fichier CODEOWNERS."
msgid "Members of %{group} can also merge into this branch: %{branch}"
msgstr "Les membres de %{group} peuvent aussi fusionner vers cette branche : %{branch}"
@@ -25068,7 +25396,7 @@ msgid "Members|Expiration date updated successfully."
msgstr "La date d'expiration a été mise à jour avec succès."
msgid "Members|Filter groups"
-msgstr ""
+msgstr "Filtrer les groupes"
msgid "Members|Filter members"
msgstr "Filtrer les membres"
@@ -25113,7 +25441,7 @@ msgid "Member|Revoke invite"
msgstr "Révoquer l'invitation"
msgid "Memory Usage"
-msgstr ""
+msgstr "Utilisation de la mémoire"
msgid "Menu"
msgstr "Menu"
@@ -25182,7 +25510,7 @@ msgid "Merge locally"
msgstr ""
msgid "Merge options"
-msgstr ""
+msgstr "Options de fusion"
msgid "Merge request"
msgstr "Demande de fusion"
@@ -25232,6 +25560,9 @@ msgstr "Les paramètres des approbations et des demandes de fusion ont changé d
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr "Les demandes de fusion permettent de proposer les modifications que vous avez apportées à un projet et de discuter de ces modifications avec les autres"
+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 the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25239,10 +25570,10 @@ 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 ""
+msgstr "Fusionner les modifications non vérifiées"
msgid "Merge unverified changes?"
-msgstr ""
+msgstr "Fusionner les modifications non vérifiées ?"
msgid "Merge when pipeline succeeds"
msgstr ""
@@ -25254,7 +25585,7 @@ msgid "MergeConflict|Commit to source branch"
msgstr ""
msgid "MergeConflict|Committing..."
-msgstr ""
+msgstr "Validation en cours..."
msgid "MergeConflict|HEAD//our changes"
msgstr ""
@@ -25425,7 +25756,7 @@ msgid "Merged MRs"
msgstr ""
msgid "Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes."
-msgstr ""
+msgstr "Les branches fusionnées sont en cours de suppression. Cela peut prendre un certain temps en fonction du nombre de branches. Veuillez actualiser la page pour suivre l'évolution."
msgid "Merged by"
msgstr "Fusionné par"
@@ -25452,22 +25783,25 @@ msgid "Messages"
msgstr "Messages"
msgid "Method"
-msgstr ""
+msgstr "Méthode"
msgid "Method call threshold (ms)"
msgstr "Seuil d'appel de méthode (ms)"
+msgid "Metric"
+msgstr "Métrique"
+
msgid "Metric was successfully added."
-msgstr ""
+msgstr "La métrique a été ajoutée avec succès."
msgid "Metric was successfully updated."
-msgstr ""
+msgstr "La métrique a été mise à jour avec succès."
msgid "Metric:"
msgstr "Métrique :"
msgid "MetricChart|Please select a metric"
-msgstr ""
+msgstr "Veuillez sélectionner une métrique"
msgid "MetricChart|Selected"
msgstr ""
@@ -25494,13 +25828,13 @@ msgid "Metrics"
msgstr "Métriques"
msgid "Metrics - Grafana"
-msgstr ""
+msgstr "Métriques - Grafana"
msgid "Metrics - Prometheus"
msgstr "Métriques — Prometheus"
msgid "Metrics Dashboard"
-msgstr ""
+msgstr "Tableau de bord des Métriques"
msgid "Metrics Dashboard YAML definition"
msgstr "Définition YAML du tableau de bord des métriques"
@@ -25578,10 +25912,10 @@ msgid "Metrics|2. Paste panel YAML into dashboard"
msgstr "2. Collez le code YAML du panneau dans le tableau de bord"
msgid "Metrics|Add metric"
-msgstr ""
+msgstr "Ajouter une métrique"
msgid "Metrics|Add panel"
-msgstr ""
+msgstr "Ajouter un panneau"
msgid "Metrics|Avg"
msgstr ""
@@ -25629,10 +25963,10 @@ msgid "Metrics|Define panel YAML below to preview panel."
msgstr "Définissez le YAML du panneau ci-dessous pour prévisualiser le panneau."
msgid "Metrics|Delete metric"
-msgstr ""
+msgstr "Supprimer une métrique"
msgid "Metrics|Delete metric?"
-msgstr ""
+msgstr "Supprimer la métrique ?"
msgid "Metrics|Duplicate"
msgstr "Dupliquer"
@@ -25641,21 +25975,21 @@ msgid "Metrics|Duplicate current dashboard"
msgstr "Dupliquer le tableau de bord actuel"
msgid "Metrics|Duplicate dashboard"
-msgstr ""
+msgstr "Dupliquer le tableau de bord"
msgid "Metrics|Duplicate this dashboard to add panel or edit dashboard YAML."
msgstr ""
msgid "Metrics|Duplicating..."
-msgstr ""
+msgstr "Duplication en cours..."
msgid "Metrics|Edit dashboard YAML"
msgstr "Modifier le YAML du tableau de bord"
msgid "Metrics|Edit metric"
msgid_plural "Metrics|Edit metrics"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Modifier la métrique"
+msgstr[1] "Modifier les métriques"
msgid "Metrics|Expand panel"
msgstr "Étendre le panneau"
@@ -25667,7 +26001,7 @@ msgid "Metrics|Invalid time range, please verify."
msgstr "Intervalle de temps invalide, veuillez vérifier."
msgid "Metrics|Label of the y-axis (usually the unit). The x-axis always represents time."
-msgstr ""
+msgstr "Libellé de l'axe des Y (généralement l'unité). L'axe des X représente toujours le temps."
msgid "Metrics|Legend label (optional)"
msgstr "Libellé de légende (facultatif)"
@@ -25682,13 +26016,13 @@ msgid "Metrics|Manage chart links"
msgstr ""
msgid "Metrics|Max"
-msgstr ""
+msgstr "Max"
msgid "Metrics|Metrics Settings"
msgstr "Paramètres des métriques"
msgid "Metrics|Min"
-msgstr ""
+msgstr "Min"
msgid "Metrics|More actions"
msgstr "Plus d'actions"
@@ -25700,7 +26034,7 @@ msgid "Metrics|New metric"
msgstr "Nouvelle métrique"
msgid "Metrics|Open repository"
-msgstr ""
+msgstr "Ouvrir le dépôt"
msgid "Metrics|Panel YAML"
msgstr "YAML du panneau"
@@ -25709,10 +26043,10 @@ msgid "Metrics|Panel YAML copied"
msgstr "YAML du panneau copié"
msgid "Metrics|Preview panel"
-msgstr ""
+msgstr "Aperçu du panneau"
msgid "Metrics|PromQL query is valid"
-msgstr ""
+msgstr "La requête PromQL est valide"
msgid "Metrics|Prometheus Query Documentation"
msgstr "Documentation des requêtes Prometheus"
@@ -25802,16 +26136,16 @@ msgid "Metrics|You can save a copy of this dashboard to your repository so it ca
msgstr ""
msgid "Metrics|You're about to permanently delete this metric. This cannot be undone."
-msgstr ""
+msgstr "Vous êtes sur le point de supprimer définitivement cette métrique. Cette opération est irréversible."
msgid "Metrics|Your dashboard schema is invalid. Edit the dashboard to correct the YAML schema."
msgstr "Le schéma de votre tableau de bord n’est pas valide. Modifiez le tableau de bord pour corriger le schéma YAML."
msgid "Metrics|e.g. HTTP requests"
-msgstr ""
+msgstr "p. ex. Requêtes HTTP"
msgid "Metrics|e.g. Requests/second"
-msgstr ""
+msgstr "p. ex. Requêtes/seconde"
msgid "Metrics|e.g. Throughput"
msgstr "p. ex., débit"
@@ -25820,10 +26154,10 @@ msgid "Metrics|e.g. rate(http_requests_total[5m])"
msgstr ""
msgid "Metrics|e.g. req/sec"
-msgstr ""
+msgstr "p. ex. req/sec"
msgid "Mi"
-msgstr ""
+msgstr "Mi"
msgid "Migrated %{success_count}/%{total_count} files."
msgstr ""
@@ -25835,7 +26169,7 @@ msgid "Migration has been scheduled to be retried"
msgstr "Une nouvelle tentative de migration a été planifiée"
msgid "Migration successful."
-msgstr ""
+msgstr "Migration réussie."
msgid "Milestone"
msgid_plural "Milestones"
@@ -25848,6 +26182,9 @@ msgstr "Date d'échéance du jalon"
msgid "Milestone lists not available with your current license"
msgstr "La liste des jalons n’est pas disponible avec votre licence actuelle"
+msgid "Milestone(s) not found: %{milestones}"
+msgstr "Jalon(s) introuvable(s) : %{milestones}"
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr "Une erreur s’est produite lors de la recherche de jalons"
@@ -25858,7 +26195,7 @@ msgid "MilestoneCombobox|Milestone"
msgstr "Jalon"
msgid "MilestoneCombobox|No matching results"
-msgstr ""
+msgstr "Aucun résultat correspondant"
msgid "MilestoneCombobox|No milestone"
msgstr "Aucun jalon"
@@ -25921,7 +26258,7 @@ msgid "MilestoneSidebar|Start date"
msgstr "Date de début"
msgid "MilestoneSidebar|Toggle sidebar"
-msgstr ""
+msgstr "Afficher/masquer la barre latérale"
msgid "MilestoneSidebar|Until"
msgstr "Jusqu'à"
@@ -25945,7 +26282,7 @@ msgid "Milestones|Completed Issues (closed)"
msgstr "Tickets terminés (fermés)"
msgid "Milestones|Create a milestone to better track your issues and merge requests. %{learn_more_link}"
-msgstr ""
+msgstr "Créez un jalon pour mieux suivre vos tickets et vos demandes de fusions. %{learn_more_link}"
msgid "Milestones|Delete milestone"
msgstr "Supprimer le jalon"
@@ -25966,7 +26303,7 @@ msgid "Milestones|Ongoing Issues (open and assigned)"
msgstr "Tickets en cours (ouverts et attribués)"
msgid "Milestones|Organize issues and merge requests into a cohesive group, and set optional start and due dates. %{learn_more_link}"
-msgstr ""
+msgstr "Organisez les tickets et les demandes de fusions dans un ensemble cohérent, et définissez des dates de début et de fin facultatives. %{learn_more_link}"
msgid "Milestones|Project Milestone"
msgstr "Jalon du projet"
@@ -26007,11 +26344,14 @@ msgstr "terminé à %{percentage}%{percent}"
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
msgid "Minutes"
-msgstr ""
+msgstr "Minutes"
msgid "Mirror direction"
msgstr "Sens du miroir"
@@ -26038,13 +26378,13 @@ msgid "Mirroring repositories"
msgstr "Dépôts miroir"
msgid "Mirroring settings were successfully updated."
-msgstr ""
+msgstr "Les paramètres de mise en miroir ont été mis à jour avec succès."
msgid "Mirroring settings were successfully updated. The project is being updated."
msgstr ""
msgid "Mirroring was successfully disabled."
-msgstr ""
+msgstr "La mise en miroir a été désactivée avec succès."
msgid "Mirroring will only be available if the feature is included in the plan of the selected group or user."
msgstr ""
@@ -26079,9 +26419,12 @@ msgstr "Vous ne pouvez ni pousser ni récupérer de dépôt tant que vous n'avez
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr "Vous ne pourrez ni récupérer ni pousser vers des dépôts via SSH tant que vous n'aurez pas ajouté une clé SSH à votre profil"
-msgid "ModalButton|Add projects"
+msgid "MlExperimentsEmptyState|No Experiments to Show"
msgstr ""
+msgid "ModalButton|Add projects"
+msgstr "Ajouter des projets"
+
msgid "Modal|Close"
msgstr "Fermer"
@@ -26104,7 +26447,7 @@ msgid "Mon"
msgstr "Lun"
msgid "Monday"
-msgstr ""
+msgstr "Lundi"
msgid "Monitor"
msgstr "Supervision"
@@ -26134,13 +26477,13 @@ msgid "More Details"
msgstr "Plus de détails"
msgid "More Information"
-msgstr ""
+msgstr "En savoir plus"
msgid "More actions"
msgstr "Autres actions"
msgid "More details"
-msgstr ""
+msgstr "Plus de détails"
msgid "More info"
msgstr "En savoir plus"
@@ -26161,7 +26504,7 @@ msgid "More than %{number_commits_distance} commits different with %{default_bra
msgstr ""
msgid "More topics"
-msgstr ""
+msgstr "Plus de sujets"
msgid "Most common"
msgstr ""
@@ -26194,13 +26537,13 @@ msgid "Move test case"
msgstr "Déplacer le cas de test"
msgid "Move this issue to another project."
-msgstr ""
+msgstr "Déplacer ce ticket vers un autre projet."
msgid "Move up"
msgstr "Déplacer vers le haut"
msgid "MoveIssue|Cannot move issue due to insufficient permissions!"
-msgstr ""
+msgstr "Impossible de déplacer le ticket en raison de permissions insuffisantes !"
msgid "MoveIssue|Cannot move issue to project it originates from!"
msgstr ""
@@ -26218,7 +26561,7 @@ msgid "Moves issue to %{label} column in the board."
msgstr ""
msgid "Moves this issue to %{path_to_project}."
-msgstr ""
+msgstr "Déplace ce ticket vers %{path_to_project}."
msgid "MrDeploymentActions|Deploy"
msgstr "Déployer"
@@ -26265,8 +26608,11 @@ msgstr "Les intégrations multiples de Prometheus ne sont pas prises en charge"
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr "Multiplicateur à appliquer aux intervalles d'interrogation. Les valeurs décimales sont prises en charge. La valeur par défaut est 1."
+msgid "Must be 90 days or more."
+msgstr "Doit être de 90 jours ou plus."
+
msgid "My awesome group"
-msgstr ""
+msgstr "Mon super groupe"
msgid "My company or team"
msgstr "Mon entreprise ou mon équipe"
@@ -26287,7 +26633,7 @@ msgid "Name can't be blank"
msgstr "Le nom ne peut pas être vide"
msgid "Name has already been taken"
-msgstr ""
+msgstr "Le nom a déjà été pris"
msgid "Name is already taken."
msgstr "Le nom est déjà pris."
@@ -26379,7 +26725,7 @@ msgid "Namespaces to index"
msgstr ""
msgid "Naming, topics, avatar"
-msgstr ""
+msgstr "Nommage, sujets, avatar"
msgid "Naming, visibility"
msgstr "Nommage, visibilité"
@@ -26436,7 +26782,7 @@ msgid "Nav|Sign out and sign in with a different account"
msgstr "Se déconnecter et se reconnecter avec un autre compte"
msgid "Need help?"
-msgstr ""
+msgstr "Besoin d'aide ?"
msgid "Needs"
msgstr ""
@@ -26469,7 +26815,7 @@ msgid "New Deploy Key"
msgstr "Nouvelle clé de déploiement"
msgid "New Environment"
-msgstr ""
+msgstr "Nouvel Environnement"
msgid "New Epic"
msgstr "Nouvelle Épopée"
@@ -26481,7 +26827,7 @@ msgid "New Group"
msgstr "Nouveau groupe"
msgid "New Group Name"
-msgstr ""
+msgstr "Nom du nouveau groupe"
msgid "New Identity"
msgstr "Nouvelle identité"
@@ -26504,13 +26850,13 @@ msgid "New Pages Domain"
msgstr ""
msgid "New Password"
-msgstr ""
+msgstr "Nouveau Mot de passe"
msgid "New Pipeline Schedule"
msgstr "Nouvelle planification de pipeline"
msgid "New Project"
-msgstr ""
+msgstr "Nouveau projet"
msgid "New Protected Branch"
msgstr "Nouvelle Branche Protégée"
@@ -26543,7 +26889,7 @@ msgid "New confidential issue title"
msgstr "Nouveau titre de ticket confidentiel"
msgid "New deploy key"
-msgstr ""
+msgstr "Nouvelle clé de déploiement"
msgid "New directory"
msgstr "Nouveau dossier"
@@ -26552,10 +26898,10 @@ msgid "New discussion"
msgstr "Nouvelle discussion"
msgid "New email address added"
-msgstr ""
+msgstr "Nouvelle adresse de courriel ajoutée"
msgid "New environment"
-msgstr ""
+msgstr "Nouvel environnement"
msgid "New epic"
msgstr "Nouvelle épopée"
@@ -26573,7 +26919,7 @@ msgid "New group"
msgstr "Nouveau groupe"
msgid "New health check access token has been generated!"
-msgstr ""
+msgstr "Un nouveau jeton d'accès au bilan de santé a été généré !"
msgid "New identity"
msgstr "Nouvelle identité"
@@ -26606,7 +26952,7 @@ msgid "New name"
msgstr "Nouveau Nom"
msgid "New password"
-msgstr ""
+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."
@@ -26630,7 +26976,7 @@ msgid "New related %{issueType}"
msgstr "Nouveau %{issueType} lié"
msgid "New release"
-msgstr ""
+msgstr "Nouvelle version"
msgid "New requirement"
msgstr "Nouvelle exigence"
@@ -26639,7 +26985,7 @@ msgid "New response for issue #%{issue_iid}:"
msgstr "Nouvelle réponse pour le ticket #%{issue_iid} :"
msgid "New runners registration token has been generated!"
-msgstr ""
+msgstr "Un nouveau jeton d'inscription d'exécuteurs a été généré !"
msgid "New schedule"
msgstr "Nouvelle planification"
@@ -26693,7 +27039,7 @@ msgid "Next update"
msgstr "Prochaine mise à jour"
msgid "Nickname"
-msgstr ""
+msgstr "Pseudo"
msgid "No"
msgstr "Non"
@@ -26725,17 +27071,20 @@ msgstr ""
msgid "No Work Item Link found"
msgstr "Aucun Lien d'Élément de Travail trouvé"
-msgid "No active admin user found"
+msgid "No access"
msgstr ""
+msgid "No active admin user found"
+msgstr "Aucun administrateur actif n'a été trouvé"
+
msgid "No activities found"
-msgstr ""
+msgstr "Aucune activité trouvée"
msgid "No application_settings found"
msgstr ""
msgid "No approvers"
-msgstr ""
+msgstr "Aucun approbateur"
msgid "No artifacts found"
msgstr "Aucun artéfact trouvé"
@@ -26744,7 +27093,7 @@ msgid "No assignee"
msgstr "Aucune personne assignée"
msgid "No authentication methods configured."
-msgstr ""
+msgstr "Aucune méthode d'authentification configurée."
msgid "No available branches"
msgstr "Aucune branche disponible"
@@ -26780,7 +27129,7 @@ msgid "No connection could be made to a Gitaly Server, please check your logs!"
msgstr "Aucune connexion n’a pu être établie avec un serveur Gitaly, veuillez vérifier votre journal !"
msgid "No contributions"
-msgstr ""
+msgstr "Aucune contribution"
msgid "No contributions were found"
msgstr "Aucune contribution n’a été trouvée"
@@ -26795,16 +27144,16 @@ msgid "No data available"
msgstr "Aucune donnée disponible"
msgid "No data found"
-msgstr ""
+msgstr "Aucune donnée trouvée"
msgid "No data to display"
-msgstr ""
+msgstr "Aucune donnée à afficher"
msgid "No deployments detected. Use environments to control your software's continuous deployment. %{linkStart}Learn more about deployment jobs.%{linkEnd}"
msgstr "Aucun déploiement détecté. Utilisez des environnements pour contrôler le déploiement continu de votre logiciel. %{linkStart}En savoir plus sur les tâches de déploiement.%{linkEnd}"
msgid "No deployments found"
-msgstr ""
+msgstr "Aucun déploiement trouvé"
msgid "No email participants were added. Either none were provided, or they already exist."
msgstr "Aucun participant n'a été ajouté par courriel. Soit aucun n'a été fourni, soit ils existent déjà."
@@ -26813,7 +27162,7 @@ msgid "No endpoint provided"
msgstr "Aucun point de terminaison fourni"
msgid "No errors to display."
-msgstr ""
+msgstr "Aucune erreur à afficher."
msgid "No estimate or time spent"
msgstr "Aucune estimation ou temps passé"
@@ -26825,10 +27174,10 @@ msgid "No file hooks found."
msgstr "Aucun fichier « Hook » trouvé."
msgid "No file selected"
-msgstr ""
+msgstr "Aucun fichier sélectionné"
msgid "No files"
-msgstr ""
+msgstr "Aucun fichier"
msgid "No files found."
msgstr "Aucun fichier trouvé."
@@ -26849,14 +27198,11 @@ msgid "No iteration"
msgstr "Aucune itération"
msgid "No iterations to show"
-msgstr ""
+msgstr "Aucune itération à afficher"
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr "Aucun étiquette"
@@ -26879,14 +27225,11 @@ msgid "No matching labels"
msgstr "Aucune étiquette correspondante"
msgid "No matching results"
-msgstr ""
+msgstr "Aucun résultat correspondant"
msgid "No matching results for \"%{query}\""
msgstr "Aucun résultat correspondant pour « %{query} »"
-msgid "No matching results..."
-msgstr "Aucun résultat correspondant..."
-
msgid "No members found"
msgstr "Aucun membre trouvé"
@@ -26902,9 +27245,6 @@ msgstr "Aucun message n’a été enregistré"
msgid "No milestone"
msgstr "Aucun jalon"
-msgid "No namespace"
-msgstr "Aucun espace de noms"
-
msgid "No other labels with such name or description"
msgstr "Aucune autre étiquette avec un tel nom ou une telle description"
@@ -26912,7 +27252,7 @@ msgid "No panels matching properties %{opts}"
msgstr ""
msgid "No parent group"
-msgstr ""
+msgstr "Pas de groupe parent"
msgid "No plan"
msgstr ""
@@ -26921,7 +27261,7 @@ msgid "No policy matches this license"
msgstr "Aucune stratégie ne correspond à cette licence"
msgid "No preview for this file type"
-msgstr ""
+msgstr "Aucun aperçu pour ce type de fichier"
msgid "No prioritized labels with such name or description"
msgstr ""
@@ -26936,7 +27276,7 @@ msgid "No projects found"
msgstr "Aucun projet trouvé"
msgid "No public deploy keys"
-msgstr ""
+msgstr "Aucune clé de déploiement publique"
msgid "No public groups"
msgstr "Aucun groupe public"
@@ -26945,7 +27285,7 @@ msgid "No ref selected"
msgstr "Pas de réf sélectionnée"
msgid "No regions configured"
-msgstr ""
+msgstr "Aucune région configurée"
msgid "No related merge requests found."
msgstr "Aucune demande de fusion associée n'a été trouvée."
@@ -26966,7 +27306,7 @@ msgid "No schedules"
msgstr "Aucune planification"
msgid "No service accounts"
-msgstr ""
+msgstr "Aucun compte de service"
msgid "No severity matches the provided parameter"
msgstr "Aucune gravité ne correspond au paramètre fourni"
@@ -27002,13 +27342,13 @@ msgid "No user provided"
msgstr "Aucun utilisateur spécifié"
msgid "No vulnerabilities present"
-msgstr ""
+msgstr "Aucune vulnérabilité présente"
msgid "No webhook events"
msgstr "Aucun événement de crochet web"
msgid "No webhooks enabled. Select trigger events above."
-msgstr ""
+msgstr "Aucun crochet web n'est activé. Sélectionnez les événements déclencheurs ci-dessus."
msgid "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} day to renew your subscription."
msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{strong_close} features for now. You have %{remaining_days} days to renew your subscription."
@@ -27016,7 +27356,7 @@ msgstr[0] ""
msgstr[1] ""
msgid "No wrap"
-msgstr ""
+msgstr "Pas de retour à la ligne"
msgid "No. of commits"
msgstr "Nb de commits"
@@ -27025,10 +27365,10 @@ msgid "Nobody has starred this repository yet"
msgstr ""
msgid "Node was successfully created."
-msgstr ""
+msgstr "Le nœud a été créé avec succès."
msgid "Node was successfully updated."
-msgstr ""
+msgstr "Le nœud a été mis à jour avec succès."
msgid "Nodes"
msgstr "NÅ“uds"
@@ -27052,7 +27392,7 @@ msgid "Not all browsers support WebAuthn. Therefore, we require that you set up
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 data has been processed yet, the accuracy of the chart for the selected timeframe is limited."
-msgstr ""
+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."
msgid "Not applicable."
msgstr "Non applicable."
@@ -27073,13 +27413,13 @@ msgid "Not found"
msgstr "Non trouvé"
msgid "Not found."
-msgstr ""
+msgstr "Introuvable."
msgid "Not permitted to destroy framework"
msgstr "Pas d'autorisation pour détruire le framework"
msgid "Not ready yet. Try again later."
-msgstr ""
+msgstr "Pas encore prêt. Réessayez plus tard."
msgid "Not started"
msgstr ""
@@ -27138,8 +27478,8 @@ msgstr "Réduire les réponses"
msgid "Notes|Expand replies"
msgstr "Afficher les réponses"
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
-msgstr ""
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
+msgstr "Les notes internes ne sont visibles que pour les membres ayant le rôle de Rapporteur ou supérieur"
msgid "Notes|Last reply by %{name}"
msgstr "Dernière réponse apportée par %{name}"
@@ -27181,7 +27521,7 @@ msgid "Notification setting - %{notification_title}"
msgstr ""
msgid "Notification settings saved"
-msgstr ""
+msgstr "Paramètres de notification enregistrés"
msgid "NotificationEmail|Assignee"
msgid_plural "NotificationEmail|Assignees"
@@ -27243,7 +27583,7 @@ msgid "NotificationEvent|New note"
msgstr "Nouvelle note"
msgid "NotificationEvent|New release"
-msgstr ""
+msgstr "Nouvelle version"
msgid "NotificationEvent|Push to merge request"
msgstr ""
@@ -27342,7 +27682,7 @@ msgid "Notify|%{name} requested a new review on %{mr_link}."
msgstr "%{name} a demandé une nouvelle relecture sur %{mr_link}."
msgid "Notify|%{p_start}To update the remote url in your local repository run (for ssh):%{p_end} %{ssh_url_to_repo} %{p_start}or for http(s):%{p_end} %{http_url_to_repo}"
-msgstr ""
+msgstr "%{p_start}Pour mettre à jour l'URL distante dans votre dépôt local, exécutez (pour SSH) :%{p_end} %{ssh_url_to_repo} %{p_start}ou pour HTTP(S) :%{p_end} %{http_url_to_repo}"
msgid "Notify|%{paragraph_start}Hi %{name}!%{paragraph_end} %{paragraph_start}A new public key was added to your account:%{paragraph_end} %{paragraph_start}title: %{key_title}%{paragraph_end} %{paragraph_start}If this key was added in error, you can remove it under %{removal_link}%{paragraph_end}"
msgstr "%{paragraph_start}Bonjour %{name}!%{paragraph_end} %{paragraph_start}Une nouvelle clé publique a été ajoutée à votre compte:%{paragraph_end} %{paragraph_start}titre: %{key_title}%{paragraph_end} %{paragraph_start}Si cette clé a été ajoutée par erreur, vous pouvez la supprimer sous %{removal_link}%{paragraph_end}"
@@ -27473,6 +27813,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|Pipeline #%{pipeline_id} has failed!"
+msgstr "Le pipeline #%{pipeline_id} a échoué !"
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr "Pipeline %{pipeline_link} déclenché par"
@@ -27482,6 +27825,9 @@ msgstr "Le pipeline a été corrigé et #%{pipeline_id} est passé !"
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."
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr "Le projet %{project_name} n'a pas pu être exporté."
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr "Le projet %{project_name} a été exporté avec succès."
@@ -27503,8 +27849,11 @@ msgstr "Le diff n'a pas été inclus car il est trop volumineux."
msgid "Notify|The download link will expire in 24 hours."
msgstr "Le lien de téléchargement expirera dans 24 heures."
+msgid "Notify|The errors we encountered were:"
+msgstr "Voici les erreurs que nous avons rencontrées :"
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
-msgstr ""
+msgstr "Le projet se trouve désormais sous %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgid "Notify|The push did not contain any new commits, but force pushed to delete the commits and changes below."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr "Nombre d'employés"
msgid "Number of events"
msgstr "Nombre d'événements"
-msgid "Number of events for this project: %{total_count}."
-msgstr "Nombre d'événements pour ce projet : %{total_count}."
-
msgid "Number of files touched"
msgstr ""
@@ -27623,11 +27969,8 @@ msgstr "oct."
msgid "October"
msgstr "octobre"
-msgid "OfSearchInADropdown|Filter"
-msgstr "Filtre"
-
msgid "Off"
-msgstr ""
+msgstr "Désactivé"
msgid "Offline"
msgstr ""
@@ -27836,13 +28179,13 @@ msgid "OnDemandScans|Add a schedule to run this scan at a specified date and tim
msgstr "Établir une planification pour exécuter cette analyse à une date et une heure spécifiées ou sur une base récurrente. Les analyses planifiées sont automatiquement enregistrées dans la bibliothèque d'analyses."
msgid "OnDemandScans|Analyze a deployed version of your web application for known vulnerabilities by examining it from the outside in. DAST works by simulating external attacks on your application while it is running."
-msgstr ""
+msgstr "Analyser une version déployée de votre application web à la recherche de vulnérabilités connues en l’examinant de l’extérieur. DAST fonctionne en simulant des attaques externes sur votre application pendant son exécution."
msgid "OnDemandScans|Are you sure you want to delete this scan?"
msgstr "Êtes-vous sûr de vouloir supprimer cette analyse ?"
msgid "OnDemandScans|Cancel"
-msgstr ""
+msgstr "Annuler"
msgid "OnDemandScans|Could not delete saved scan. Please refresh the page, or try again later."
msgstr "Impossible de supprimer l'analyse enregistrée. Veuillez actualiser la page ou réessayer plus tard."
@@ -27859,12 +28202,6 @@ msgstr "Impossible de récupérer les profils de site. Veuillez actualiser la pa
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr "Impossible d’exécuter l’analyse. Veuillez réessayer."
-msgid "OnDemandScans|Create new scanner profile"
-msgstr "Créer un nouveau profil de scanner"
-
-msgid "OnDemandScans|Create new site profile"
-msgstr "Créer un nouveau profil de site"
-
msgid "OnDemandScans|DAST configuration"
msgstr "Configuration DAST"
@@ -27910,12 +28247,6 @@ msgstr "Par exemple : Teste la page de connexion contre les injections SQL"
msgid "OnDemandScans|Keep editing"
msgstr "Poursuivre la modification"
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr "Gérer les profils de scanner"
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr "Gérer les profils de site"
-
msgid "OnDemandScans|My daily scan"
msgstr "Mon analyse quotidienne"
@@ -27937,12 +28268,6 @@ msgstr "Nouvelle analyse"
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr "Actuellement aucun profil . Pour créer une nouvelle analyse, vous devez avoir rempli entièrement au moins un profil de scanner."
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr "Il n'y a aucun profil pour l'instant. Afin de créer une nouvelle analyse, vous devez avoir terminé au moins un profil de site."
-
msgid "OnDemandScans|On-demand Scans"
msgstr "Analyses à la demande"
@@ -27985,15 +28310,6 @@ msgstr "Planification d'analyse"
msgid "OnDemandScans|Scan type"
msgstr "Type d'analyse"
-msgid "OnDemandScans|Scanner profile"
-msgstr "Profil de scanner"
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr "Sélectionnez l'un des profils existants"
-
-msgid "OnDemandScans|Site profile"
-msgstr "Profil de site"
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr "Commencez par la création d'un nouveau profil. Les profils facilitent l'enregistrement et la réutilisation des informations de configuration des outils de sécurité de GitLab."
@@ -28024,12 +28340,6 @@ msgstr "Il n'y a aucune analyse planifiée."
msgid "OnDemandScans|Timezone"
msgstr "Fuseau horaire"
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr "Utiliser un profil de scanner existant"
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr "Utiliser un profil de site existant"
-
msgid "OnDemandScans|View results"
msgstr "Voir les résultats"
@@ -28043,14 +28353,11 @@ msgid "OnDemandScans|at"
msgstr "le"
msgid "Once imported, repositories can be mirrored over SSH. Read more %{link_start}here%{link_end}."
-msgstr ""
+msgstr "Une fois importés, les dépôts peuvent être mis en miroir via SSH. Plus d'informations %{link_start}ici%{link_end}."
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr "Une fois supprimée, la relation du fork ne pourra plus être restaurée. Ce projet ne sera plus en mesure de recevoir ni d'envoyer des demandes de fusion vers le projet source ni vers d'autres forks."
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] "Un élément de plus"
@@ -28069,7 +28376,7 @@ msgid "One or more groups that you don't have access to."
msgstr ""
msgid "One or more of you personal access tokens were revoked"
-msgstr ""
+msgstr "Un ou plusieurs de vos jetons d'accès personnels ont été révoqués"
msgid "One or more of your %{provider} projects cannot be imported into GitLab directly because they use Subversion or Mercurial for version control, rather than Git."
msgstr "Un ou plusieurs de vos projets %{provider} ne peuvent pas être importés directement dans GitLab car ils utilisent Subversion ou Mercurial plutôt que Git pour le contrôle de versions."
@@ -28114,7 +28421,7 @@ msgid "Only allow anyone to register for accounts on GitLab instances that you i
msgstr ""
msgid "Only effective when remote storage is enabled. Set to 0 for no size limit."
-msgstr ""
+msgstr "Effectif uniquement lorsque le stockage distant est activé. Définir à 0 pour aucune limite de taille."
msgid "Only group members with at least the Reporter role can view or be notified about this epic"
msgstr "Seuls les membres du groupe ayant au moins le rôle de Rapporteur peuvent voir cette épopée ou recevoir des notifications la concernant"
@@ -28159,7 +28466,7 @@ msgid "Open"
msgstr "Ouvert"
msgid "Open Selection"
-msgstr ""
+msgstr "Ouvrir la Sélection"
msgid "Open errors"
msgstr ""
@@ -28180,7 +28487,7 @@ msgid "Open new window"
msgstr "Ouvrir une nouvelle fenêtre"
msgid "Open raw"
-msgstr ""
+msgstr "Ouvrir la version brute"
msgid "Open sidebar"
msgstr "Ouvrir la barre latérale"
@@ -28219,14 +28526,11 @@ msgid "Opens new window"
msgstr "Ouvre une nouvelle fenêtre"
msgid "Operation failed. Check pod logs for %{pod_name} for more details."
-msgstr ""
+msgstr "L'opération a échoué. Vérifiez les journaux du pod %{pod_name} pour plus de détails."
msgid "Operation not allowed"
msgstr "Opération non autorisée"
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr "Opérations"
@@ -28237,13 +28541,13 @@ msgid "OperationsDashboard|Add a project to the dashboard"
msgstr "Ajouter un projet au tableau de bord"
msgid "OperationsDashboard|Add projects"
-msgstr ""
+msgstr "Ajouter des projets"
msgid "OperationsDashboard|More information"
-msgstr ""
+msgstr "En savoir plus"
msgid "OperationsDashboard|Operations Dashboard"
-msgstr ""
+msgstr "Tableau de bord des Opérations"
msgid "OperationsDashboard|The Operations and Environments dashboards share the same list of projects. When you add or remove a project from one, GitLab adds or removes the project from the other. %{linkStart}More information%{linkEnd}"
msgstr "Le tableau de bord des Opérations et celui des Environnements partagent la même liste de projets. Lorsque vous ajoutez ou supprimez un projet de l'un d'eux, GitLab l'ajoute ou le supprime de l’autre. %{linkStart}Plus d'informations%{linkEnd}"
@@ -28372,10 +28676,10 @@ msgid "Owners and administrators"
msgstr "Propriétaires et administrateurs"
msgid "Owners can modify this selection."
-msgstr ""
+msgstr "Les propriétaires peuvent modifier cette sélection."
msgid "PQL|An error occurred while sending hand raise lead."
-msgstr ""
+msgstr "Une erreur s'est produite lors de l'envoi du prospect."
msgid "PQL|By providing my contact information, I agree GitLab may contact me via email about its product, services and events. You may opt-out at any time by unsubscribing in emails or visiting our communication preference center."
msgstr "En fournissant mes informations de contact, j'accepte que GitLab puisse me contacter par courriel à propos de ses produits, services et événements. Vous pouvez vous rétracter à tout moment en vous désinscrivant depuis les courriels ou en vous rendant dans notre centre de préférence de communication."
@@ -28387,7 +28691,7 @@ msgid "PQL|Contact our Sales team"
msgstr "Contacter notre équipe commerciale"
msgid "PQL|Contact sales"
-msgstr ""
+msgstr "Contacter le service commercial"
msgid "PQL|Hello %{userName}. Before putting you in touch with our sales team, we would like you to verify and complete the information below."
msgstr "Bonjour %{userName}. Avant de vous mettre en contact avec notre équipe commerciale, nous souhaiterions vérifier et compléter les informations ci-dessous."
@@ -28420,7 +28724,7 @@ msgid "Package and registry settings"
msgstr "Paramètres des paquets et registres"
msgid "Package deleted successfully"
-msgstr ""
+msgstr "Le paquet a été supprimé avec succès"
msgid "Package file size limits"
msgstr "Limites de taille de fichier des paquets"
@@ -28447,7 +28751,7 @@ msgid "Package type must be Maven"
msgstr "Le type de paquet doit être Maven"
msgid "Package type must be NPM"
-msgstr ""
+msgstr "Le type de paquet doit être NPM"
msgid "Package type must be NuGet"
msgstr "Le type de paquet doit être NuGet"
@@ -28555,7 +28859,7 @@ msgid "PackageRegistry|Copy and paste this inside your %{codeStart}pom.xml%{code
msgstr "Copiez et collez ceci à l'intérieur du bloc de %{codeStart}dépendances%{codeEnd} de votre %{codeStart}pom.xml%{codeEnd}."
msgid "PackageRegistry|Copy npm command"
-msgstr ""
+msgstr "Copier la commande npm"
msgid "PackageRegistry|Copy npm setup command"
msgstr ""
@@ -28570,7 +28874,7 @@ msgid "PackageRegistry|Copy target SHA"
msgstr ""
msgid "PackageRegistry|Copy yarn command"
-msgstr ""
+msgstr "Copier la commande yarn"
msgid "PackageRegistry|Copy yarn setup command"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr "Supprimer la ressource du paquet"
+msgid "PackageRegistry|Delete package version"
+msgstr "Supprimer la version du paquet"
+
msgid "PackageRegistry|Delete selected"
msgstr "Supprimer la sélection"
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr "La suppression de toutes les ressources du paquet supprimera la version %{version} de %{name}. Êtes-vous sûr(e) ?"
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr "La suppression de la dernière ressource du paquet supprimera la version %{version} de %{name}. Êtes-vous sûr(e) ?"
+
msgid "PackageRegistry|Duplicate packages"
msgstr "Paquets dupliqués"
@@ -28646,6 +28959,12 @@ msgstr "Commande d'installation du DSL Kotlin pour Gradle"
msgid "PackageRegistry|Helm"
msgstr "Helm"
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr "Aidez-nous à en savoir plus sur vos besoins en matière de migration de registre"
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr "Si vous êtes intéressé par la migration des paquets depuis votre registre privé vers le Registre de Paquets GitLab, répondez à notre enquête et dites-en nous plus sur vos besoins."
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr "Si vous ne l'avez pas déjà fait, vous devrez ajouter ce qui suit à votre fichier %{codeStart}.pypirc%{codeEnd}."
@@ -28665,7 +28984,7 @@ msgid "PackageRegistry|Last downloaded %{dateTime}"
msgstr "Dernier téléchargement %{dateTime}"
msgid "PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab."
-msgstr ""
+msgstr "Apprenez comment %{noPackagesLinkStart}publier et partager vos paquets%{noPackagesLinkEnd} avec GitLab."
msgid "PackageRegistry|License information located at %{link}"
msgstr ""
@@ -28718,7 +29037,7 @@ msgid "PackageRegistry|Package updated by commit %{link} on branch %{branch}, bu
msgstr "Paquet mis à jour par le commit %{link} sur la branche %{branch}, construit par le pipeline %{pipeline} et publié dans le registre %{datetime}"
msgid "PackageRegistry|Permanently delete"
-msgstr ""
+msgstr "Supprimer définitivement"
msgid "PackageRegistry|Permanently delete assets"
msgstr "Supprimer définitivement les ressources"
@@ -28733,7 +29052,7 @@ msgid "PackageRegistry|Publish packages if their name or version matches this re
msgstr "Publier les paquets si leur nom ou leur version correspond à cette expression rationnelle."
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
-msgstr ""
+msgstr "Publié dans le Registre de Paquets %{project} %{datetime}"
msgid "PackageRegistry|PyPI"
msgstr "PyPI"
@@ -28792,6 +29111,9 @@ msgstr "Désolé, aucun résultat ne correspond à vos critères de recherche."
msgid "PackageRegistry|Source project located at %{link}"
msgstr "Projet source situé à %{link}"
+msgid "PackageRegistry|Take survey"
+msgstr "Répondre à l'enquête"
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr "SHA cible : %{sha}"
@@ -28799,10 +29121,10 @@ msgid "PackageRegistry|There are no other versions of this package."
msgstr "Il n’y a pas d'autre version de ce paquet."
msgid "PackageRegistry|There are no packages yet"
-msgstr ""
+msgstr "Il n'y a pas encore de paquets"
msgid "PackageRegistry|There was a problem fetching the details for this package."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des détails de ce paquet."
msgid "PackageRegistry|There was a timeout and the package was not published. Delete this package and try again."
msgstr "Un délai d'attente a expiré et le paquet n'a pas été publié. Supprimez ce paquet et réessayez."
@@ -28823,7 +29145,7 @@ msgid "PackageRegistry|Unable to fetch package version information."
msgstr "Impossible de récupérer les informations de version du paquet."
msgid "PackageRegistry|Unable to load package"
-msgstr ""
+msgstr "Impossible de charger le paquet"
msgid "PackageRegistry|When a package with same name and version is uploaded to the registry, more assets are added to the package. To save storage space, keep only the most recent assets."
msgstr "Lorsqu’un paquet ayant le même nom et la même version est téléversé dans le registre, des ressources supplémentaires sont ajoutées au paquet. Pour économiser de l'espace de stockage, ne conservez que les ressources les plus récentes."
@@ -28832,7 +29154,7 @@ msgid "PackageRegistry|You are about to delete %{filename}. This is a destructiv
msgstr "Vous êtes sur le point de supprimer %{filename}. Il s'agit d'une action destructrice qui peut rendre votre paquet inutilisable. Êtes-vous sûr(e) ?"
msgid "PackageRegistry|You are about to delete %{name}, are you sure?"
-msgstr ""
+msgstr "Vous êtes sur le point de supprimer %{name}, êtes-vous sûr(e) ?"
msgid "PackageRegistry|You are about to delete 1 asset. This operation is irreversible."
msgid_plural "PackageRegistry|You are about to delete %d assets. This operation is irreversible."
@@ -28858,10 +29180,10 @@ msgid "Packages and registries"
msgstr "Paquets & registres"
msgid "Page not found"
-msgstr ""
+msgstr "Page introuvable"
msgid "PagerDutySettings|Active"
-msgstr ""
+msgstr "Actif"
msgid "PagerDutySettings|Create a GitLab incident for each PagerDuty incident by %{linkStart}configuring a webhook in PagerDuty%{linkEnd}"
msgstr "Créer un incident GitLab pour chaque incident PagerDuty en %{linkStart}configurant un webhook dans PagerDuty%{linkEnd}"
@@ -28942,7 +29264,7 @@ msgid "Partial import"
msgstr ""
msgid "Participants"
-msgstr ""
+msgstr "Participants"
msgid "Pass job variables"
msgstr "Transmettre des variables de tâche"
@@ -28957,16 +29279,16 @@ msgid "Password"
msgstr "Mot de Passe"
msgid "Password (optional)"
-msgstr ""
+msgstr "Mot de passe (facultatif)"
msgid "Password authentication is unavailable."
-msgstr ""
+msgstr "L'authentification par mot de passe n'est pas disponible."
msgid "Password confirmation"
-msgstr ""
+msgstr "Confirmation du mot de passe"
msgid "Password successfully changed"
-msgstr ""
+msgstr "Mot de passe modifié avec succès"
msgid "Password was successfully updated. Please sign in again."
msgstr "Le mot de passe a été mis à jour avec succès. Veuillez vous reconnecter."
@@ -29014,10 +29336,10 @@ msgid "Paste confidential issue link"
msgstr "Coller le lien du ticket confidentiel"
msgid "Paste epic link"
-msgstr ""
+msgstr "Coller le lien de l'épopée"
msgid "Paste issue link"
-msgstr ""
+msgstr "Coller le lien du ticket"
msgid "Paste link"
msgstr "Coller le lien"
@@ -29032,7 +29354,7 @@ msgid "Patch to apply"
msgstr "Correctif à appliquer"
msgid "Path"
-msgstr ""
+msgstr "Chemin"
msgid "Path:"
msgstr "Chemin d’accès :"
@@ -29095,7 +29417,7 @@ msgid "Perform advanced options such as changing path, transferring, exporting,
msgstr "Effectuer des opérations avancées telles que changer de chemin, transférer, exporter ou supprimer le groupe."
msgid "Perform code reviews and enhance collaboration with merge requests."
-msgstr ""
+msgstr "Effectuez des revue de code et améliorez la collaboration avec des demandes de fusion."
msgid "Perform common operations on GitLab project"
msgstr ""
@@ -29113,7 +29435,7 @@ msgid "PerformanceBar|DOM Content Loaded"
msgstr "DOM Content Loaded"
msgid "PerformanceBar|Download"
-msgstr ""
+msgstr "Télécharger"
msgid "PerformanceBar|Elasticsearch calls"
msgstr "Appels Elasticsearch"
@@ -29131,7 +29453,7 @@ msgid "PerformanceBar|Frontend resources"
msgstr ""
msgid "PerformanceBar|Gitaly calls"
-msgstr ""
+msgstr "Appels Gitaly"
msgid "PerformanceBar|Memory"
msgstr "Mémoire"
@@ -29140,13 +29462,13 @@ msgid "PerformanceBar|Memory report"
msgstr ""
msgid "PerformanceBar|Redis calls"
-msgstr ""
+msgstr "Appels Redis"
msgid "PerformanceBar|Rugged calls"
-msgstr ""
+msgstr "Appels Rugged"
msgid "PerformanceBar|SQL queries"
-msgstr ""
+msgstr "Requêtes SQL"
msgid "PerformanceBar|Sort by duration"
msgstr "Trier par durée"
@@ -29175,12 +29497,6 @@ msgstr "mur"
msgid "Period in seconds"
msgstr "Période en secondes"
-msgid "Period of inactivity (days)"
-msgstr "Période d'inactivité (jours)"
-
-msgid "Period of inactivity before deactivation."
-msgstr "Période d'inactivité avant désactivation."
-
msgid "Permalink"
msgstr "Lien permanent"
@@ -29203,7 +29519,7 @@ msgid "Personal Access Token prefix"
msgstr "Préfixe du Jeton d'Accès Personnel"
msgid "Personal project creation is not allowed. Please contact your administrator with questions"
-msgstr ""
+msgstr "La création de projet personnel n'est pas autorisée. Veuillez contacter votre administrateur pour toute question"
msgid "Personal projects"
msgstr "Projets personnels"
@@ -29224,22 +29540,22 @@ msgid "PersonalProject|Your project %{projectName} is not in a group"
msgstr "Votre projet %{projectName} n'est pas dans un groupe"
msgid "Phabricator Server Import"
-msgstr ""
+msgstr "Importation depuis un Serveur Phabricator"
msgid "Phabricator Server URL"
-msgstr ""
+msgstr "URL du serveur Phabricator"
-msgid "Phabricator Tasks"
-msgstr ""
+msgid "Phabricator tasks"
+msgstr "Tâches Phabricator"
msgid "Phone"
-msgstr ""
+msgstr "Téléphone"
msgid "Pick a name"
msgstr ""
msgid "Pin code"
-msgstr ""
+msgstr "Code Pin"
msgid "Pipeline"
msgstr "Pipeline"
@@ -29254,7 +29570,7 @@ msgid "Pipeline Editor|Are you sure you want to reset the file to its last commi
msgstr "Êtes-vous sûr de vouloir réinitialiser le fichier à sa dernière version validée ?"
msgid "Pipeline ID"
-msgstr ""
+msgstr "ID du pipeline"
msgid "Pipeline IID"
msgstr "IID de pipeline"
@@ -29272,7 +29588,7 @@ msgid "Pipeline creation rate limits"
msgstr ""
msgid "Pipeline durations for the last 30 commits"
-msgstr ""
+msgstr "Durée des pipelines pour les 30 dernières validations"
msgid "Pipeline ran in fork of project"
msgstr "Pipeline exécuté dans un fork du projet"
@@ -29290,7 +29606,7 @@ msgid "Pipeline triggers"
msgstr "Déclencheurs de pipeline"
msgid "Pipeline: %{status}"
-msgstr ""
+msgstr "Pipeline : %{status}"
msgid "PipelineCharts|An error has occurred when retrieving the analytics data"
msgstr "Une erreur s’est produite lors de la récupération des données analytiques"
@@ -29448,20 +29764,26 @@ msgstr "Actif"
msgid "PipelineSchedules|All"
msgstr "Tous"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr "Êtes-vous sûr de vouloir supprimer cette planification de pipeline ?"
+
msgid "PipelineSchedules|Delete pipeline schedule"
-msgstr ""
+msgstr "Supprimer la planification du pipeline"
msgid "PipelineSchedules|Description"
-msgstr ""
+msgstr "Description"
msgid "PipelineSchedules|Edit pipeline schedule"
-msgstr ""
+msgstr "Modifier la planification du pipeline"
msgid "PipelineSchedules|Inactive"
msgstr "Inactif"
msgid "PipelineSchedules|Last Pipeline"
-msgstr ""
+msgstr "Dernier pipeline"
+
+msgid "PipelineSchedules|New schedule"
+msgstr "Nouvelle planification"
msgid "PipelineSchedules|Next Run"
msgstr "Prochaine exécution"
@@ -29473,24 +29795,36 @@ msgid "PipelineSchedules|Only the owner of a pipeline schedule can make changes
msgstr "Seul le propriétaire d’une planification de pipeline peut y apporter des modifications. Voulez-vous prendre possession de cette planification ?"
msgid "PipelineSchedules|Owner"
-msgstr ""
+msgstr "Propriétaire"
+
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr "Planification de pipeline supprimée avec succès."
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "Indiquez une courte description"
msgid "PipelineSchedules|Run pipeline schedule"
+msgstr "Exécuter la planification du pipeline"
+
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
msgstr ""
msgid "PipelineSchedules|Take ownership"
msgstr "S’approprier"
msgid "PipelineSchedules|Take ownership of pipeline schedule"
-msgstr ""
+msgstr "Prendre possession de la planification du pipeline"
msgid "PipelineSchedules|Target"
msgstr "Cible"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr "Une erreur est survenue lors de la suppression de la planification du pipeline."
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
+msgstr "Une erreur est survenue lors de la récupération des planifications de pipelines."
+
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
msgid "PipelineSchedules|Variables"
@@ -29542,10 +29876,10 @@ msgid "PipelineSource|Web IDE"
msgstr "EDI Web"
msgid "PipelineStatusTooltip|Pipeline: %{ciStatus}"
-msgstr ""
+msgstr "Pipeline : %{ciStatus}"
msgid "PipelineStatusTooltip|Pipeline: %{ci_status}"
-msgstr ""
+msgstr "Pipeline : %{ci_status}"
msgid "PipelineWizardDefaultCommitMessage|Add %{filename}"
msgstr "Ajouter %{filename}"
@@ -29602,7 +29936,7 @@ msgid "Pipelines charts"
msgstr "Graphiques des pipelines"
msgid "Pipelines settings for '%{project_name}' were successfully updated."
-msgstr ""
+msgstr "Les paramètres des pipelines pour « %{project_name} » ont été mis à jour avec succès."
msgid "Pipelines|\"Hello world\" with GitLab CI"
msgstr ""
@@ -29623,7 +29957,7 @@ msgid "Pipelines|A GitLab Runner is an application that works with GitLab CI/CD
msgstr ""
msgid "Pipelines|API"
-msgstr ""
+msgstr "API"
msgid "Pipelines|Are you sure you want to run this pipeline?"
msgstr "Êtes-vous sûr(e) de vouloir exécuter ce pipeline ?"
@@ -29689,7 +30023,7 @@ msgid "Pipelines|Get familiar with GitLab CI syntax by setting up a simple pipe
msgstr ""
msgid "Pipelines|Get started with GitLab CI/CD"
-msgstr ""
+msgstr "Premiers pas avec GitLab CI/CD"
msgid "Pipelines|GitLab CI/CD can automatically build, test, and deploy your code. Let GitLab take care of time consuming tasks, so you can spend more time creating."
msgstr "GitLab CI/CD peut automatiquement construire, tester et déployer votre code. Laissez GitLab se charger des tâches chronophages afin de pouvoir consacrer davantage de temps à la création."
@@ -29899,7 +30233,7 @@ msgid "Pipeline|Canceled"
msgstr "Annulé"
msgid "Pipeline|Checking pipeline status"
-msgstr ""
+msgstr "Vérification de l'état du pipeline"
msgid "Pipeline|Checking pipeline status."
msgstr "Vérification de l'état du pipeline."
@@ -30031,7 +30365,7 @@ msgid "Pipeline|View commit"
msgstr "Afficher le commit"
msgid "Pipeline|View pipeline"
-msgstr ""
+msgstr "Voir le pipeline"
msgid "Pipeline|We are currently unable to fetch pipeline data"
msgstr "Il n'est pas possible actuellement de récupérer les données de pipeline"
@@ -30094,10 +30428,10 @@ msgid "Play"
msgstr "Lancer"
msgid "Play all manual"
-msgstr ""
+msgstr "Tout lancer en manuel"
msgid "Please %{link_to_register} or %{link_to_sign_in} to comment"
-msgstr ""
+msgstr "Veuillez vous %{link_to_register} ou vous %{link_to_sign_in} pour commenter"
msgid "Please %{registerLinkStart}register%{registerLinkEnd} or %{signInLinkStart}sign in%{signInLinkEnd} to reply."
msgstr ""
@@ -30112,7 +30446,7 @@ msgid "Please accept the Terms of Service before continuing."
msgstr "Veuillez accepter les conditions générales d’utilisation avant de continuer."
msgid "Please add a comment in the text area above"
-msgstr ""
+msgstr "Veuillez ajouter un commentaire dans la zone de texte ci-dessus"
msgid "Please check the configuration file for this chart"
msgstr ""
@@ -30121,19 +30455,19 @@ msgid "Please check the configuration file to ensure that a collection of charts
msgstr ""
msgid "Please check the configuration file to ensure that it is available and the YAML is valid"
-msgstr ""
+msgstr "Veuillez vérifier le fichier de configuration pour vous assurer qu'il est disponible et que le YAML est valide"
msgid "Please check your email %{email} to confirm your account"
msgstr "Veuillez vérifier votre courriel %{email} pour valider votre compte"
msgid "Please check your email (%{email}) to verify that you own this address and unlock the power of CI/CD. Didn't receive it? %{resend_link}. Wrong email address? %{update_link}."
-msgstr ""
+msgstr "Veuillez vérifier votre courriel (%{email}) pour être sûr que vous êtes bien propriétaire de cette adresse et libérer toute la puissance de la CI/CD. Vous ne l'avez pas reçu ? %{resend_link}. L'adresse de courriel est incorrecte ? %{update_link}."
msgid "Please click the link in the confirmation email before continuing. It was sent to %{html_tag_strong_start}%{email}%{html_tag_strong_end}."
msgstr "Veuillez cliquer sur le lien présent dans le courriel de confirmation avant de continuer. Il a été envoyé à %{html_tag_strong_start}%{email}%{html_tag_strong_end}."
msgid "Please complete your profile with email address"
-msgstr ""
+msgstr "Veuillez compléter votre profil avec une adresse de courriel"
msgid "Please confirm your email address"
msgstr "Veuillez confirmer votre adresse de courriel"
@@ -30157,10 +30491,10 @@ msgid "Please copy, download, or print your recovery codes before proceeding."
msgstr "Veuillez copier, télécharger ou imprimer vos codes de récupération avant de poursuivre."
msgid "Please create a password for your new account."
-msgstr ""
+msgstr "Veuillez créer un mot de passe pour votre nouveau compte."
msgid "Please create a username with only alphanumeric characters."
-msgstr ""
+msgstr "Veuillez créer un nom d'utilisateur avec uniquement des caractères alphanumériques."
msgid "Please create an index before enabling indexing"
msgstr "Veuillez créer un index avant d'activer l'indexation"
@@ -30169,10 +30503,10 @@ msgid "Please delete your current license if you want to downgrade to the free p
msgstr "Veuillez supprimer votre licence actuelle si vous souhaitez revenir au forfait gratuit."
msgid "Please enable and migrate to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
-msgstr ""
+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 non-negative number"
-msgstr ""
+msgstr "Veuillez entrer un nombre non négatif"
msgid "Please enter a number greater than %{number} (from the project settings)"
msgstr ""
@@ -30184,7 +30518,7 @@ msgid "Please enter a valid hex (#RRGGBB or #RGB) color value"
msgstr "Veuillez entrer une valeur de couleur hexadécimale valide (#RRVVBB ou #RVB)"
msgid "Please enter a valid number"
-msgstr ""
+msgstr "Veuillez entrer un nombre valide"
msgid "Please enter a valid time interval"
msgstr "Veuillez entrer un intervalle de temps valide"
@@ -30202,7 +30536,7 @@ msgid "Please fill in a title for your topic."
msgstr "Veuillez saisir un titre pour votre sujet."
msgid "Please fill out this field."
-msgstr ""
+msgstr "Veuillez remplir ce champ."
msgid "Please follow the %{link_start}Let's Encrypt troubleshooting instructions%{link_end} to re-obtain your Let's Encrypt certificate."
msgstr "Veuillez suivre les %{link_start}instructions de dépannage de Let's Encrypt%{link_end} pour obtenir à nouveau votre certificat Let's Encrypt."
@@ -30211,13 +30545,13 @@ msgid "Please follow the Let's Encrypt troubleshooting instructions to re-obtain
msgstr "Veuillez suivre les instructions de dépannage de Let's Encrypt pour obtenir de nouveau votre certificat Let's Encrypt : %{docs_url}."
msgid "Please migrate all existing projects to hashed storage to avoid security issues and ensure data integrity. %{migrate_link}"
-msgstr ""
+msgstr "Veuillez migrer tous les projets existants vers un stockage haché pour éviter les problèmes de sécurité et assurer l'intégrité des données. %{migrate_link}"
msgid "Please note that this application is not provided by GitLab and you should verify its authenticity before allowing access."
msgstr "Veuillez noter que cette application n’est pas fournie par GitLab, vous devriez vérifier son authenticité avant d’autoriser son accès."
msgid "Please provide a name"
-msgstr ""
+msgstr "Veuillez fournir un nom"
msgid "Please provide a name."
msgstr "Veuillez fournir un nom."
@@ -30226,7 +30560,7 @@ msgid "Please provide a valid URL."
msgstr "Veuillez fournir une URL valide."
msgid "Please provide a valid email address."
-msgstr ""
+msgstr "Veuillez fournir une adresse de courriel valide."
msgid "Please provide attributes to update"
msgstr ""
@@ -30250,10 +30584,7 @@ msgid "Please select a Jira project"
msgstr "Veuillez sélectionner un projet Jira"
msgid "Please select a country"
-msgstr ""
-
-msgid "Please select a file"
-msgstr ""
+msgstr "Veuillez sélectionner un pays"
msgid "Please select a group"
msgstr "Veuillez sélectionner un groupe"
@@ -30265,7 +30596,7 @@ msgid "Please select a valid target branch."
msgstr "Veuillez sélectionner une branche cible valide."
msgid "Please select and add a member"
-msgstr ""
+msgstr "Veuillez sélectionner et ajouter un membre"
msgid "Please select at least one filter to see results"
msgstr "Veuillez sélectionner au moins un filtre pour voir les résultats"
@@ -30277,7 +30608,7 @@ msgid "Please select..."
msgstr ""
msgid "Please set a new password before proceeding."
-msgstr ""
+msgstr "Veuillez définir un nouveau mot de passe avant de continuer."
msgid "Please solve the captcha"
msgstr "Veuillez résoudre le captcha"
@@ -30295,10 +30626,10 @@ msgid "Please use this form to report to the admin users who create spam issues,
msgstr ""
msgid "Please wait a few moments while we load the file history for this line."
-msgstr ""
+msgstr "Veuillez patienter quelques instants pendant que nous chargeons l'historique des fichiers pour cette ligne."
msgid "Please wait a moment, this page will automatically refresh when ready."
-msgstr ""
+msgstr "Veuillez patienter quelques instants, cette page s'actualisera automatiquement lorsqu'elle sera prête."
msgid "Please wait while we connect to your repository. Refresh at will."
msgstr "Veuillez patienter pendant la connexion à votre dépôt. Actualisez à votre guise."
@@ -30363,6 +30694,69 @@ msgstr "Caractère potentiellement indésirable détecté : Contrôle Unicode Bi
msgid "Pre-defined push rules"
msgstr "Règles de poussée prédéfinies"
+msgid "PreScanVerification|(optional)"
+msgstr "(facultatif)"
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr "Authentification"
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr "Connexion"
+
+msgid "PreScanVerification|Download results"
+msgstr "Télécharger les résultats"
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr "Dernière exécution %{timeAgo} en pipeline"
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr "Vérification de préanalyse"
+
+msgid "PreScanVerification|Save and run verification"
+msgstr "Enregistrer et exécuter la vérification"
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr "A démarré %{timeAgo} en pipeline"
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr "Testez votre configuration et identifiez les erreurs potentielles avant de lancer une analyse complète."
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr "Vérifier la configuration"
+
+msgid "PreScanVerification|View results"
+msgstr "Voir les résultats"
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr "Préférences"
@@ -30370,19 +30764,19 @@ msgid "Preferences saved."
msgstr "Préférences enregistrées."
msgid "Preferences|Automatically add new list items"
-msgstr ""
+msgstr "Ajouter automatiquement de nouveaux éléments de liste"
msgid "Preferences|Behavior"
msgstr "Comportement"
msgid "Preferences|Choose between fixed (max. 1280px) and fluid (%{percentage}) application layout."
-msgstr ""
+msgstr "Choisissez entre une disposition d'application fixe (max. 1280px) et fluide (%{percentage})."
msgid "Preferences|Choose what content you want to see by default on your dashboard."
msgstr "Choisissez le contenu par défaut que vous souhaitez voir sur votre tableau de bord."
msgid "Preferences|Choose what content you want to see on a project’s overview page."
-msgstr ""
+msgstr "Choisissez le contenu que vous souhaitez voir sur la vue d'ensemble d'un projet."
msgid "Preferences|Color for added lines"
msgstr "Couleur des lignes ajoutées"
@@ -30445,7 +30839,7 @@ msgid "Preferences|Preview"
msgstr "Aperçu"
msgid "Preferences|Project overview content"
-msgstr ""
+msgstr "Contenu de la vue d'ensemble du projet"
msgid "Preferences|Render whitespace characters in the Web IDE"
msgstr "Afficher les caractères non imprimables dans l'EDI Web"
@@ -30475,7 +30869,7 @@ msgid "Preferences|This setting allows you to customize the appearance of the sy
msgstr "Ce paramètre vous permet de personnaliser l'apparence de la syntaxe."
msgid "Preferences|This setting allows you to customize the behavior of the system layout and default views."
-msgstr ""
+msgstr "Ces paramètres vous permettent de personnaliser le comportement de la mise en page du système et des vues par défaut."
msgid "Preferences|Time preferences"
msgstr "Préférences de l’heure"
@@ -30484,7 +30878,7 @@ msgid "Preferences|Use relative times"
msgstr ""
msgid "Preferences|When you type in a description or comment box, pressing %{kbdOpen}Enter%{kbdClose} in a list adds a new item below."
-msgstr ""
+msgstr "Lorsque vous saisissez du texte dans une zone de commentaire ou de description, l'appui sur %{kbdOpen}Entrée%{kbdClose} dans une liste ajoute dessous un nouvel élément."
msgid "Preferences|When you type in a description or comment box, selected text is surrounded by the corresponding character after typing one of the following characters: %{supported_characters}."
msgstr "Lorsque vous saisissez du texte dans un champ de commentaire ou de description, la sélection est encadrée par le caractère correspondant après avoir tapé l'un des caractères suivants : %{supported_characters}."
@@ -30493,7 +30887,7 @@ msgid "Preparing the report for the scan."
msgstr "Préparation du rapport pour l'analyse."
msgid "Prev"
-msgstr ""
+msgstr "Précédent"
msgid "Prevent auto-stopping"
msgstr "Empêcher l'arrêt automatique"
@@ -30504,6 +30898,9 @@ msgstr "Empêcher la modification des règles d'approbation dans les projets et
msgid "Prevent environment from auto-stopping"
msgstr "Empêcher l'environnement de s'arrêter automatiquement"
+msgid "Prevent outdated deployment jobs"
+msgstr "Empêcher les tâches de déploiement dépassées"
+
msgid "Prevent project forking outside current group"
msgstr "Empêcher le fork de projet en dehors du groupe actuel"
@@ -30520,7 +30917,7 @@ msgid "Preview JavaScript projects in the Web IDE with CodeSandbox Live Preview.
msgstr "Prévisualisez les projets JavaScript dans l'EDI Web avec CodeSandbox Live Preview. %{link_start}En savoir plus.%{link_end} "
msgid "Preview Markdown"
-msgstr ""
+msgstr "Aperçu du Markdown"
msgid "Preview changes"
msgstr ""
@@ -30532,7 +30929,7 @@ msgid "Preview payload"
msgstr "Aperçu de la charge utile"
msgid "Previous Artifacts"
-msgstr ""
+msgstr "Artéfacts précédents"
msgid "Previous commit"
msgstr "Commit précédent"
@@ -30583,7 +30980,7 @@ msgid "Private group(s)"
msgstr ""
msgid "Private profile"
-msgstr ""
+msgstr "Profil privé"
msgid "Private projects Minutes cost factor"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr "Problème avec la commande %{name} : %{message}."
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
-msgstr "Données analytiques de produit"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
+msgstr "Audience"
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|Widgets content"
+msgstr "Contenu des widgets"
+
msgid "Productivity"
msgstr "Productivité"
@@ -30613,7 +31016,7 @@ msgid "Productivity analytics can help identify the problems that are delaying y
msgstr ""
msgid "ProductivityAanalytics|Merge requests"
-msgstr ""
+msgstr "Demandes de fusion"
msgid "ProductivityAanalytics|is earlier than the allowed minimum date"
msgstr "est plus tôt que la date minimale autorisée"
@@ -30622,7 +31025,7 @@ msgid "ProductivityAnalytics|Ascending"
msgstr ""
msgid "ProductivityAnalytics|Days"
-msgstr ""
+msgstr "Jours"
msgid "ProductivityAnalytics|Days to merge"
msgstr ""
@@ -30631,19 +31034,19 @@ msgid "ProductivityAnalytics|Descending"
msgstr ""
msgid "ProductivityAnalytics|Hours"
-msgstr ""
+msgstr "Heures"
msgid "ProductivityAnalytics|List"
-msgstr ""
+msgstr "Liste"
msgid "ProductivityAnalytics|Merge Requests"
-msgstr ""
+msgstr "Demandes de Fusion"
msgid "ProductivityAnalytics|Merge date"
-msgstr ""
+msgstr "Date de fusion"
msgid "ProductivityAnalytics|Merge requests"
-msgstr ""
+msgstr "Demandes de fusion"
msgid "ProductivityAnalytics|Time to merge"
msgstr ""
@@ -30685,7 +31088,7 @@ msgid "Profiles|%{provider} Active"
msgstr ""
msgid "Profiles|@username"
-msgstr ""
+msgstr "@nom_d_utilisateur"
msgid "Profiles|Account could not be deleted. GitLab was unable to verify your identity."
msgstr "Le compte n'a pas pu être supprimé. GitLab n'a pas réussi à vérifier votre identité."
@@ -30718,7 +31121,7 @@ msgid "Profiles|Change username"
msgstr "Changer le nom d’utilisateur·rice"
msgid "Profiles|Changing your username can have unintended side effects."
-msgstr ""
+msgstr "Changer votre nom d'utilisateur peut avoir des effets secondaires inattendus."
msgid "Profiles|Choose file..."
msgstr "Choisir un fichier…"
@@ -30727,10 +31130,10 @@ msgid "Profiles|Choose to show contributions of private projects on your public
msgstr "Choisir d'afficher les contributions des projets privés sur votre profil public mais sans les informations relatives aux projet, dépôt ni organisation."
msgid "Profiles|City, country"
-msgstr ""
+msgstr "Ville, pays"
msgid "Profiles|Commit email"
-msgstr ""
+msgstr "Courriel pour les validations"
msgid "Profiles|Connect %{provider}"
msgstr "Connecter %{provider}"
@@ -30739,7 +31142,7 @@ msgid "Profiles|Connect a service for sign-in."
msgstr "Sélectionner un service avec lequel vous connecter."
msgid "Profiles|Connected Accounts"
-msgstr ""
+msgstr "Comptes connectés"
msgid "Profiles|Created%{time_ago}"
msgstr "Crée %{time_ago}"
@@ -30751,7 +31154,7 @@ msgid "Profiles|Current status"
msgstr "État actuel"
msgid "Profiles|Default notification email"
-msgstr ""
+msgstr "Courriel de notification par défaut"
msgid "Profiles|Delete account"
msgstr "Supprimer le compte"
@@ -30760,7 +31163,7 @@ msgid "Profiles|Deleting an account has the following effects:"
msgstr "Supprimer un compte aura les conséquences suivantes :"
msgid "Profiles|Disconnect"
-msgstr ""
+msgstr "Déconnecter"
msgid "Profiles|Disconnect %{provider}"
msgstr "Déconnecter %{provider}"
@@ -30790,7 +31193,7 @@ msgid "Profiles|Enter your pronouns to let people know how to refer to you."
msgstr "Entrez les pronoms qui vous correspondent pour que l'on sache comment faire référence à vous."
msgid "Profiles|Example: MacBook key"
-msgstr ""
+msgstr "Exemple : clé MacBook"
msgid "Profiles|Expiration date"
msgstr "Date d'expiration"
@@ -30802,10 +31205,10 @@ msgid "Profiles|Expires:"
msgstr ""
msgid "Profiles|Feed token was successfully reset"
-msgstr ""
+msgstr "Le jeton de flux a été réinitialisé avec succès"
msgid "Profiles|Full name"
-msgstr ""
+msgstr "Nom complet"
msgid "Profiles|GitLab is unable to verify your identity automatically. For security purposes, you must set a password by %{openingTag}resetting your password%{closingTag} to delete your account."
msgstr "GitLab ne peut pas vérifier votre identité automatiquement. Pour des raisons de sécurité, vous devez définir un mot de passe en %{openingTag}réinitialisant votre mot de passe%{closingTag} pour supprimer votre compte."
@@ -30814,10 +31217,10 @@ msgid "Profiles|If after setting a password, the option to delete your account i
msgstr "Si, après avoir défini un mot de passe, l'option pour supprimer votre compte n'est toujours pas disponible, veuillez %{link_start}soumettre une requête%{link_end} pour commencer le processus de suppression."
msgid "Profiles|Include private contributions on my profile"
-msgstr ""
+msgstr "Inclure les contributions privées sur mon profil"
msgid "Profiles|Incoming email token was successfully reset"
-msgstr ""
+msgstr "Le jeton de courriel entrant a été réinitialisé avec succès"
msgid "Profiles|Increase your account's security by enabling two-factor authentication (2FA)."
msgstr "Augmenter la sécurité de votre compte en activant l'authentification à deux facteurs (A2F)."
@@ -30832,13 +31235,13 @@ msgid "Profiles|Job title"
msgstr "Intitulé de poste"
msgid "Profiles|Key"
-msgstr ""
+msgstr "Clé"
msgid "Profiles|Key becomes invalid on this date. Maximum lifetime for SSH keys is %{max_ssh_key_lifetime} days"
msgstr "La clé devient invalide à cette date. La durée de vie maximale des clés SSH est de %{max_ssh_key_lifetime} jours"
msgid "Profiles|Key titles are publicly visible."
-msgstr ""
+msgstr "Le titre des clés est visible publiquement."
msgid "Profiles|Last used:"
msgstr ""
@@ -30847,7 +31250,7 @@ msgid "Profiles|Learn more"
msgstr "En savoir plus"
msgid "Profiles|Location"
-msgstr ""
+msgstr "Emplacement"
msgid "Profiles|Made a private contribution"
msgstr "a fait une contribution privée"
@@ -30862,13 +31265,13 @@ msgid "Profiles|No file chosen."
msgstr "Aucun fichier choisi."
msgid "Profiles|Notification email"
-msgstr ""
+msgstr "Courriel de notification"
msgid "Profiles|Optional but recommended. If set, key becomes invalid on the specified date."
msgstr "Facultatif mais recommandé. Si définie, la clé devient invalide à la date spécifiée."
msgid "Profiles|Organization"
-msgstr ""
+msgstr "Organisation"
msgid "Profiles|Path"
msgstr "Chemin d’accès"
@@ -30877,7 +31280,7 @@ msgid "Profiles|Position and size your new avatar"
msgstr "Position et taille de votre nouvel avatar"
msgid "Profiles|Primary email"
-msgstr ""
+msgstr "Courriel principal"
msgid "Profiles|Private contributions"
msgstr "Contributions privées"
@@ -30895,7 +31298,7 @@ msgid "Profiles|Public avatar"
msgstr "Avatar public"
msgid "Profiles|Public email"
-msgstr ""
+msgstr "Courriel public"
msgid "Profiles|Publicly visible private SSH keys can compromise your system."
msgstr "Les clés SSH privées visibles publiquement peuvent compromettre votre système."
@@ -30919,7 +31322,7 @@ msgid "Profiles|Some options are unavailable for LDAP accounts"
msgstr "Certaines options ne sont pas disponibles pour les comptes LDAP"
msgid "Profiles|Static object token was successfully reset"
-msgstr ""
+msgstr "Le jeton d'objet statique a été réinitialisé avec succès"
msgid "Profiles|Tell us about yourself in fewer than 250 characters."
msgstr "Parlez-nous de vous en moins de 250 caractères."
@@ -30943,7 +31346,7 @@ msgid "Profiles|This information will appear on your profile."
msgstr "Cette information apparaîtra sur votre profil."
msgid "Profiles|Time settings"
-msgstr ""
+msgstr "Paramètres de l'heure"
msgid "Profiles|Title"
msgstr "Titre"
@@ -30967,7 +31370,7 @@ msgid "Profiles|Use a private email - %{email}"
msgstr "Utiliser une adresse de courriel privée — %{email}"
msgid "Profiles|User ID"
-msgstr ""
+msgstr "ID utilisateur"
msgid "Profiles|Username change failed - %{message}"
msgstr "Le changement de nom d’utilisateur a échoué : %{message}"
@@ -30976,7 +31379,7 @@ msgid "Profiles|Username successfully changed"
msgstr "Changement de nom d’utilisateur effectué"
msgid "Profiles|Using emojis in names seems fun, but please try to set a status message instead"
-msgstr ""
+msgstr "Utiliser des émojis dans les noms est amusant, mais essayez plutôt de définir un message d'état à la place"
msgid "Profiles|Website url"
msgstr "URL du site Web"
@@ -31009,19 +31412,19 @@ msgid "Profiles|You must transfer ownership or delete these groups before you ca
msgstr "Vous devez transférer la propriété ou supprimer ces groupes avant de pouvoir supprimer votre compte."
msgid "Profiles|Your LinkedIn profile name from linkedin.com/in/profilename"
-msgstr ""
+msgstr "Votre nom de profil LinkedIn accessible à partir de linkedin.com/in/nom_profil"
msgid "Profiles|Your account is currently an owner in these groups:"
msgstr "Votre compte est actuellement propriétaire des groupes suivants :"
msgid "Profiles|Your email address was automatically set based on your %{provider_label} account"
-msgstr ""
+msgstr "Votre adresse de courriel a été automatiquement définie en fonction de votre compte %{provider_label}"
msgid "Profiles|Your location was automatically set based on your %{provider_label} account"
-msgstr ""
+msgstr "Votre emplacement a été automatiquement défini en fonction de votre compte %{provider_label}"
msgid "Profiles|Your name was automatically set based on your %{provider_label} account, so people you know can recognize you"
-msgstr ""
+msgstr "Votre nom a été automatiquement défini en fonction de votre compte %{provider_label}, afin que les personnes que vous connaissez puissent vous reconnaitre"
msgid "Profiles|Your name was automatically set based on your %{provider_label} account, so people you know can recognize you."
msgstr "Votre nom sera automatiquement défini d'après votre compte %{provider_label} afin qu'il soit possible de vous reconnaître."
@@ -31030,7 +31433,7 @@ msgid "Profiles|https://website.com"
msgstr "https://siteweb.com"
msgid "Profiles|username"
-msgstr ""
+msgstr "nom_d_utilisateur"
msgid "Profiles|your account"
msgstr "votre compte"
@@ -31054,16 +31457,16 @@ msgid "Project"
msgstr "Projet"
msgid "Project \"%{name}\" is no longer available. Select another project to continue."
-msgstr ""
+msgstr "Le projet « %{name} » n'est plus disponible. Sélectionnez un autre projet pour continuer."
msgid "Project %{project_repo} could not be found"
-msgstr ""
+msgstr "Le projet %{project_repo} n'a pas pu être trouvé"
msgid "Project & Group can not be assigned at the same time"
msgstr "Le projet et le groupe ne peuvent pas être assignés en même temps"
msgid "Project '%{project_name}' is being imported."
-msgstr ""
+msgstr "Le projet « %{project_name} » est en cours d'importation."
msgid "Project '%{project_name}' is in the process of being deleted."
msgstr "Le projet « %{project_name} » est en cours de suppression."
@@ -31090,10 +31493,10 @@ msgid "Project Badges"
msgstr "Badges numériques du projet"
msgid "Project Files"
-msgstr ""
+msgstr "Fichiers du projet"
msgid "Project ID"
-msgstr ""
+msgstr "ID du projet"
msgid "Project Templates"
msgstr "Modèles de Projet"
@@ -31111,7 +31514,7 @@ msgid "Project already deleted"
msgstr "Projet déjà supprimé"
msgid "Project and wiki repositories"
-msgstr ""
+msgstr "Dépôts du projet et du wiki"
msgid "Project audit events"
msgstr "Événements d'audit de projet"
@@ -31126,10 +31529,10 @@ msgid "Project configuration, excluding integrations"
msgstr "La configuration du projet, à l'exclusion des intégrations"
msgid "Project description (optional)"
-msgstr ""
+msgstr "Description du projet (facultative)"
msgid "Project does not exist or you don't have permission to perform this action"
-msgstr ""
+msgstr "Le projet n'existe pas ou vous n'avez pas la permission d'effectuer cette action"
msgid "Project does not have a policy configuration"
msgstr "Le projet ne dispose d'aucune configuration de politique"
@@ -31138,7 +31541,7 @@ msgid "Project export could not be deleted."
msgstr "L’exportation du projet n’a pas pu être supprimée."
msgid "Project export download requests"
-msgstr ""
+msgstr "Demandes de téléchargement d'export de projet"
msgid "Project export has been deleted."
msgstr "L’exportation du projet a été supprimée."
@@ -31153,7 +31556,7 @@ msgid "Project export started. A download link will be sent by email and made av
msgstr "L'exportation du projet a commencé. Un lien de téléchargement sera envoyé par courriel et sera disponible sur cette page."
msgid "Project has too many %{label_for_message} to search"
-msgstr ""
+msgstr "Le projet a trop de %{label_for_message} à rechercher"
msgid "Project import requests"
msgstr "Demandes d'importation de projet"
@@ -31179,11 +31582,14 @@ msgstr "Nom du projet"
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr "Projet ou Groupe"
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
msgid "Project path"
-msgstr ""
+msgstr "Chemin du projet"
msgid "Project security status"
msgstr ""
@@ -31191,23 +31597,26 @@ msgstr ""
msgid "Project security status help page"
msgstr "Page d'aide sur l'état de la sécurité du projet"
+msgid "Project settings were successfully updated."
+msgstr "Les paramètres du projet ont été mis à jour avec succès."
+
msgid "Project slug"
msgstr "Identifiant « slug » du projet"
msgid "Project uploads"
-msgstr ""
+msgstr "Téléversements du projet"
msgid "Project visibility level is less restrictive than the group settings."
msgstr "Le niveau de visibilité du projet est moins restrictif que celui défini par les paramètres du groupe."
msgid "Project visibility level will be changed to match namespace rules when transferring to a group."
-msgstr ""
+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 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é."
msgid "Project: %{name}"
-msgstr ""
+msgstr "Projet : %{name}"
msgid "Project:Branches: %{source_project_path}:%{source_branch} to %{target_project_path}:%{target_branch}"
msgstr "Projet:Branches : %{source_project_path}:%{source_branch} vers %{target_project_path}:%{target_branch}"
@@ -31342,13 +31751,13 @@ msgid "ProjectQualitySummary|This page helps you understand the code testing tre
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 ""
+msgstr " ou un groupe"
msgid "ProjectSelect|No matching results"
msgstr "Aucun résultat correspondant"
msgid "ProjectSelect|Search for project"
-msgstr ""
+msgstr "Rechercher un projet"
msgid "ProjectSelect|Search projects"
msgstr "Rechercher des projets"
@@ -31473,12 +31882,18 @@ msgstr "%{link_start}Que sont les modèles de description ?%{link_end}"
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr "%{link_start}Quelles variables puis-je utiliser ?%{link_end}"
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr "Une branche par défaut ne peut pas être choisie pour un projet vide."
+
msgid "ProjectSettings|Additional options"
msgstr "Options supplémentaires"
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr "Paramètres supplémentaires qui agissent sur comment et quand les fusions sont effectuées."
+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 "Tous les fil de conversation doivent être résolus"
@@ -31491,12 +31906,18 @@ msgstr "Toujours afficher les boutons des émojis de récompense « pouce vers l
msgid "ProjectSettings|Analytics"
msgstr "Analytiques"
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr "Fermer automatiquement les tickets référencés sur la branche par défaut"
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr "Résoudre automatiquement les discussions des diff de demande de fusion lorsqu'elles ne sont plus d'actualité"
msgid "ProjectSettings|Badges"
msgstr "Badges numériques"
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr "Construisez, testez et déployez vos modifications."
@@ -31510,7 +31931,7 @@ msgid "ProjectSettings|Choose the method, options, checks, and squash options fo
msgstr "Choisir la méthode, les options, les vérifications et les options d'écrasement pour les demandes de fusion. Vous pouvez également configurer des modèles de demande de fusion pour différentes actions."
msgid "ProjectSettings|Choose your merge method, merge options, merge checks, and merge suggestions."
-msgstr ""
+msgstr "Choisissez votre méthode de fusion, les options de fusion, les vérifications de fusion et les suggestions de fusion."
msgid "ProjectSettings|Choose your merge method, options, checks, and squash options."
msgstr "Choisissez votre méthode de fusion, vos options, vos vérifications et vos options d'écrasement."
@@ -31518,6 +31939,9 @@ msgstr "Choisissez votre méthode de fusion, vos options, vos vérifications et
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr "Configurer les ressources de votre projet et surveiller leur état de santé."
@@ -31528,7 +31952,7 @@ msgid "ProjectSettings|Container registry"
msgstr ""
msgid "ProjectSettings|Customize this project's badges."
-msgstr ""
+msgstr "Personnaliser les badges de ce groupe."
msgid "ProjectSettings|Determine what happens to the commit history when you merge a merge request."
msgstr "Déterminer ce qu'il advient de l'historique des commits lors de la fusion d'une demande de fusion."
@@ -31552,7 +31976,7 @@ msgid "ProjectSettings|Enable suggested reviewers"
msgstr "Activer les relecteurs suggérés"
msgid "ProjectSettings|Encourage"
-msgstr ""
+msgstr "Inciter"
msgid "ProjectSettings|Environments"
msgstr "Environnements"
@@ -31617,14 +32041,17 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr "Si les trains de fusion sont activés, la fusion n'est possible que si la branche peut être rebasée sans conflits."
+msgid "ProjectSettings|Infrastructure"
+msgstr "Infrastructure"
+
msgid "ProjectSettings|Internal"
-msgstr ""
+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 ""
+msgstr "Tickets"
msgid "ProjectSettings|LFS objects from this repository are available to forks. %{linkStart}How do I remove them?%{linkEnd}"
msgstr "Les objets LFS de ce dépôt sont disponibles pour les forks. %{linkStart}Comment puis-je les supprimer ?%{linkEnd}"
@@ -31642,7 +32069,7 @@ msgid "ProjectSettings|Maximum %{maxLength} characters."
msgstr "%{maxLength} caractères maximum."
msgid "ProjectSettings|Merge checks"
-msgstr ""
+msgstr "Vérifications de fusion"
msgid "ProjectSettings|Merge commit"
msgstr ""
@@ -31654,13 +32081,13 @@ msgid "ProjectSettings|Merge commit with semi-linear history"
msgstr ""
msgid "ProjectSettings|Merge method"
-msgstr ""
+msgstr "Méthode de fusion"
msgid "ProjectSettings|Merge options"
-msgstr ""
+msgstr "Options de fusion"
msgid "ProjectSettings|Merge requests"
-msgstr ""
+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 ""
@@ -31678,13 +32105,13 @@ msgid "ProjectSettings|Monitor"
msgstr "Supervision"
msgid "ProjectSettings|No merge commits are created."
-msgstr ""
+msgstr "Aucun commit de fusion n'est créé."
msgid "ProjectSettings|Note: The container registry is always visible when a project is public and the container registry is set to '%{access_level_description}'"
msgstr "Remarque : Le registre de conteneurs est toujours visible lorsqu'un projet est public et que le registre de conteneurs est défini sur « %{access_level_description} »"
msgid "ProjectSettings|Only commits that include a %{code_block_start}Signed-off-by:%{code_block_end} element can be pushed to this repository."
-msgstr ""
+msgstr "Seuls les commits qui contiennent un élément %{code_block_start}Signed-off-by:%{code_block_end} peuvent être poussés vers ce dépôt."
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr "Seuls les commits signés peuvent être poussés sur ce dépôt Git."
@@ -31699,37 +32126,37 @@ msgid "ProjectSettings|Package registry"
msgstr "Registre de paquets"
msgid "ProjectSettings|Packages"
-msgstr ""
+msgstr "Paquets"
msgid "ProjectSettings|Pages"
-msgstr ""
+msgstr "Pages"
msgid "ProjectSettings|Pages for project documentation."
-msgstr ""
+msgstr "Pages pour la documentation du projet."
msgid "ProjectSettings|Pipelines must succeed"
-msgstr ""
+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"
msgid "ProjectSettings|Private"
-msgstr ""
+msgstr "Privée"
msgid "ProjectSettings|Project visibility"
-msgstr ""
+msgstr "Visibilité du projet"
msgid "ProjectSettings|Public"
-msgstr ""
+msgstr "Publique"
msgid "ProjectSettings|Releases"
msgstr "Versions"
msgid "ProjectSettings|Repository"
-msgstr ""
+msgstr "Dépôt"
msgid "ProjectSettings|Require"
-msgstr ""
+msgstr "Exiger"
msgid "ProjectSettings|Require an associated issue from Jira"
msgstr ""
@@ -31755,11 +32182,14 @@ msgstr "Sécurité & Conformité"
msgid "ProjectSettings|Security & Compliance for this project"
msgstr "Sécurité & Conformité de ce projet"
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
msgid "ProjectSettings|Share code with others outside the project."
-msgstr ""
+msgstr "Partagez du code avec d'autres personnes en dehors du projet."
msgid "ProjectSettings|Show default award emojis"
msgstr ""
@@ -31771,7 +32201,7 @@ msgid "ProjectSettings|Skipped pipelines are considered successful"
msgstr "Les pipelines ignorés sont considérés comme réussis"
msgid "ProjectSettings|Snippets"
-msgstr ""
+msgstr "Extraits"
msgid "ProjectSettings|Squash commit message template"
msgstr "Modèle de message pour les squash de validation"
@@ -31785,6 +32215,9 @@ msgstr "Le squashing est toujours effectué. La case à cocher est visible et sÃ
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr "Le squashing n’est jamais effectué et la case à cocher est cachée."
+msgid "ProjectSettings|Status checks must succeed"
+msgstr "Les vérifications d'état doivent réussir"
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr "Soumettre les modifications à fusionner en amont."
@@ -31822,7 +32255,7 @@ msgid "ProjectSettings|This setting will be applied to all projects unless overr
msgstr "Ce paramètre s’appliquera à tous les projets à moins qu’un administrateur ou une administratrice ne l’outrepasse sur certains projets."
msgid "ProjectSettings|Transfer project"
-msgstr ""
+msgstr "Transférer le projet"
msgid "ProjectSettings|Upstream project"
msgstr "Projet amont"
@@ -31836,9 +32269,12 @@ msgstr "Les utilisateurs peuvent copier le dépôt vers un nouveau projet."
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
-msgid "ProjectSettings|Users can request access"
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
msgstr ""
+msgid "ProjectSettings|Users can request access"
+msgstr "Les utilisateurs peuvent demander l'accès"
+
msgid "ProjectSettings|View and edit files in this project."
msgstr "Afficher et modifier des fichiers dans ce projet."
@@ -31876,16 +32312,16 @@ msgid "ProjectSettings|When there is a merge conflict, the user is given the opt
msgstr "En cas de conflit de fusion, l’utilisateur a la possibilité de rebaser."
msgid "ProjectSettings|Wiki"
-msgstr ""
+msgstr "Wiki"
msgid "ProjectSettings|With GitLab Pages you can host your static websites on GitLab. GitLab Pages uses a caching mechanism for efficiency. Your changes may not take effect until that cache is invalidated, which usually takes less than a minute."
msgstr "Grâce aux Pages GitLab, vous pouvez héberger vos sites web statiques sur GitLab. Les Pages GitLab utilisent un mécanisme de cache pour plus d'efficacité. Vos modifications ne seront effectives que lorsque le cache sera invalidé, ce qui prend en général moins d'une minute."
msgid "ProjectTemplates|.NET Core"
-msgstr ""
+msgstr ".NET Core"
msgid "ProjectTemplates|Android"
-msgstr ""
+msgstr "Android"
msgid "ProjectTemplates|GitLab Cluster Management"
msgstr ""
@@ -31894,7 +32330,7 @@ msgid "ProjectTemplates|Gitpod/Spring Petclinic"
msgstr "Gitpod/Spring Petclinic"
msgid "ProjectTemplates|Go Micro"
-msgstr ""
+msgstr "Go Micro"
msgid "ProjectTemplates|HIPAA Audit Protocol"
msgstr "Protocole d'audit HIPAA"
@@ -31903,19 +32339,19 @@ msgid "ProjectTemplates|Jsonnet for Dynamic Child Pipelines"
msgstr "Jsonnet pour les Pipelines Enfants Dynamiques"
msgid "ProjectTemplates|Kotlin Native for Linux"
-msgstr ""
+msgstr "Kotlin Native pour Linux"
msgid "ProjectTemplates|Netlify/GitBook"
-msgstr ""
+msgstr "Netlify/GitBook"
msgid "ProjectTemplates|Netlify/Hexo"
-msgstr ""
+msgstr "Netlify/Hexo"
msgid "ProjectTemplates|Netlify/Hugo"
-msgstr ""
+msgstr "Netlify/Hugo"
msgid "ProjectTemplates|Netlify/Jekyll"
-msgstr ""
+msgstr "Netlify/Jekyll"
msgid "ProjectTemplates|Netlify/Plain HTML"
msgstr ""
@@ -31927,19 +32363,19 @@ msgid "ProjectTemplates|Pages/Gatsby"
msgstr "Pages/Gatsby"
msgid "ProjectTemplates|Pages/GitBook"
-msgstr ""
+msgstr "Pages/GitBook"
msgid "ProjectTemplates|Pages/Hexo"
-msgstr ""
+msgstr "Pages/Hexo"
msgid "ProjectTemplates|Pages/Hugo"
-msgstr ""
+msgstr "Pages/Hugo"
msgid "ProjectTemplates|Pages/Jekyll"
-msgstr ""
+msgstr "Pages/Jekyll"
msgid "ProjectTemplates|Pages/Middleman"
-msgstr ""
+msgstr "Pages/Middleman"
msgid "ProjectTemplates|Pages/Pelican"
msgstr "Pages/Pelican"
@@ -31948,7 +32384,7 @@ msgid "ProjectTemplates|Pages/Plain HTML"
msgstr ""
msgid "ProjectTemplates|Ruby on Rails"
-msgstr ""
+msgstr "Ruby on Rails"
msgid "ProjectTemplates|SalesforceDX"
msgstr "SalesforceDX"
@@ -31960,13 +32396,13 @@ msgid "ProjectTemplates|Serverless Framework/JS"
msgstr "Serverless Framework/JS"
msgid "ProjectTemplates|Spring"
-msgstr ""
+msgstr "Spring"
msgid "ProjectTemplates|Tencent Serverless Framework/NextjsSSR"
msgstr "Tencent Serverless Framework/NextjsSSR"
msgid "ProjectTemplates|iOS (Swift)"
-msgstr ""
+msgstr "iOS (Swift)"
msgid "ProjectTransfer|An error occurred fetching the transfer locations, please refresh the page and try again."
msgstr "Une erreur s’est produite lors de la récupération des emplacements des transferts, veuillez actualiser la page et réessayer."
@@ -31984,13 +32420,13 @@ msgid "Projects"
msgstr "Projets"
msgid "Projects (%{count})"
-msgstr ""
+msgstr "Projets (%{count})"
msgid "Projects API"
msgstr ""
msgid "Projects Successfully Retrieved"
-msgstr ""
+msgstr "Projets Récupérés avec Succès"
msgid "Projects are graded based on the highest severity vulnerability present"
msgstr "Les projets sont classés selon la gravité la plus élevée des vulnérabilités présentes"
@@ -32014,7 +32450,7 @@ msgid "Projects shared with %{group_name}"
msgstr "Projets partagés avec %{group_name}"
msgid "Projects that can be accessed"
-msgstr ""
+msgstr "Projets accessibles"
msgid "Projects to index"
msgstr ""
@@ -32083,13 +32519,13 @@ msgid "ProjectsNew|Create a project pre-populated with the necessary files to ge
msgstr "Créer un projet pré-rempli avec les fichiers nécessaires pour vous permettre de démarrer rapidement."
msgid "ProjectsNew|Create blank project"
-msgstr ""
+msgstr "Créer un projet vierge"
msgid "ProjectsNew|Create from template"
msgstr "Créer à partir d’un modèle"
msgid "ProjectsNew|Create new project"
-msgstr ""
+msgstr "Créer un nouveau projet"
msgid "ProjectsNew|Description format"
msgstr ""
@@ -32107,13 +32543,13 @@ msgid "ProjectsNew|Include a Getting Started README"
msgstr ""
msgid "ProjectsNew|Initialize repository with a README"
-msgstr ""
+msgstr "Initialiser le dépôt avec un README"
msgid "ProjectsNew|Migrate your data from an external source like GitHub, Bitbucket, or another instance of GitLab."
msgstr "Migrez vos données depuis une source externe comme GitHub, Bitbucket ou une autre instance de GitLab."
msgid "ProjectsNew|No import options available"
-msgstr ""
+msgstr "Aucune option d'importation n'est disponible"
msgid "ProjectsNew|Pick a group or namespace"
msgstr ""
@@ -32125,7 +32561,7 @@ msgid "ProjectsNew|Project Configuration"
msgstr "Configuration du Projet"
msgid "ProjectsNew|Project description %{tag_start}(optional)%{tag_end}"
-msgstr ""
+msgstr "Description du projet %{tag_start}(facultative)%{tag_end}"
msgid "ProjectsNew|Recommended if you're new to GitLab"
msgstr ""
@@ -32134,7 +32570,7 @@ msgid "ProjectsNew|Run CI/CD for external repository"
msgstr ""
msgid "ProjectsNew|Visibility Level"
-msgstr ""
+msgstr "Niveau de visibilité"
msgid "ProjectsNew|Want to organize several dependent projects under the same namespace? %{link_start}Create a group.%{link_end}"
msgstr "Vous souhaitez organiser plusieurs projets interdépendants sous un même espace de noms ? %{link_start}Créez un groupe.%{link_end}"
@@ -32173,7 +32609,7 @@ msgid "PrometheusService|Custom metrics require Prometheus installed on a cluste
msgstr ""
msgid "PrometheusService|Enable Prometheus to define custom metrics, using either option above"
-msgstr ""
+msgstr "Activez Prometheus pour définir des métriques personnalisées, en utilisant l'une des options ci-dessus"
msgid "PrometheusService|Finding and configuring metrics..."
msgstr "Recherche et configuration des métriques en cours…"
@@ -32209,7 +32645,7 @@ msgid "PrometheusService|No %{docsUrlStart}common metrics%{docsUrlEnd} were foun
msgstr "Aucune %{docsUrlStart}métrique commune%{docsUrlEnd} n’a été trouvée"
msgid "PrometheusService|No custom metrics have been created. Create one using the button above"
-msgstr ""
+msgstr "Aucune métrique personnalisée n'a été créée. Créez-en une en utilisant le bouton ci-dessus"
msgid "PrometheusService|Prometheus cluster integration"
msgstr "Intégration de grappe de serveurs Prometheus"
@@ -32251,7 +32687,7 @@ msgid "Promote issue to an epic"
msgstr ""
msgid "Promote issue to incident"
-msgstr ""
+msgstr "Promouvoir le ticket en incident"
msgid "Promote to epic"
msgstr "Promouvoir en épopée"
@@ -32344,7 +32780,7 @@ msgid "Promotions|Keep track of events in your project"
msgstr "Gardez une trace des événements de votre projet"
msgid "Promotions|Learn more"
-msgstr ""
+msgstr "En savoir plus"
msgid "Promotions|Merge request approvals"
msgstr "Approbations de demande de fusion"
@@ -32413,7 +32849,7 @@ msgid "Promotions|Weighting your issue"
msgstr ""
msgid "Promotions|When you have a lot of issues, it can be hard to get an overview. By adding a weight to your issues, you can get a better idea of the effort, cost, required time, or value of each, and so better manage them."
-msgstr ""
+msgstr "Lorsque vous avez de nombreux tickets, il peut être difficile d'en avoir une vue d'ensemble. En leur ajoutant un poids, vous pouvez avoir une meilleure idée de l'effort, du coût, du temps nécessaire ou de la valeur de chacun, et ainsi mieux les gérer."
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."
@@ -32425,7 +32861,7 @@ msgid "Promotions|to help your contributors communicate effectively!"
msgstr "pour aider vos contributeurs à communiquer efficacement !"
msgid "Prompt users to upload SSH keys"
-msgstr ""
+msgstr "Inviter les utilisateurs à téléverser des clés SSH"
msgid "Protect"
msgstr "Protéger"
@@ -32434,7 +32870,7 @@ msgid "Protect a tag"
msgstr "Protéger une étiquette"
msgid "Protect variable"
-msgstr ""
+msgstr "Protéger la variable"
msgid "Protected"
msgstr "Protégé"
@@ -32446,7 +32882,7 @@ msgid "Protected Branches"
msgstr "Branches protégées"
msgid "Protected Environment"
-msgstr ""
+msgstr "Environnement protégé"
msgid "Protected Paths: requests"
msgstr "Chemins protégés : demandes"
@@ -32458,7 +32894,7 @@ msgid "Protected Tags"
msgstr "Étiquettes protégées"
msgid "Protected branches"
-msgstr ""
+msgstr "Branches protégées"
msgid "Protected environments"
msgstr "Environnements protégés"
@@ -32475,6 +32911,9 @@ msgstr "Autoriser tous les utilisateurs ayant un accès pour pousser à %{tag_st
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr "Autoriser tous les utilisateurs ayant un accès pour pousser à forcer les poussées."
+msgid "ProtectedBranch|Allowed to create"
+msgstr "Autorisé à créer"
+
msgid "ProtectedBranch|Allowed to force push"
msgstr "Autoriser à forcer les poussées"
@@ -32482,22 +32921,22 @@ msgid "ProtectedBranch|Allowed to force push:"
msgstr "Autoriser à forcer les poussées :"
msgid "ProtectedBranch|Allowed to merge"
-msgstr ""
+msgstr "Autorisés à fusionner"
msgid "ProtectedBranch|Allowed to merge:"
-msgstr ""
+msgstr "Autorisés à fusionner :"
msgid "ProtectedBranch|Allowed to push"
-msgstr ""
+msgstr "Autorisés à pousser"
msgid "ProtectedBranch|Allowed to push:"
-msgstr ""
+msgstr "Autorisés à pousser :"
msgid "ProtectedBranch|An error occurred while loading branch rules. Please try again."
msgstr "Une erreur s'est produite lors du chargement des règles de branche. Veuillez réessayer."
msgid "ProtectedBranch|Branch"
-msgstr ""
+msgstr "Branche"
msgid "ProtectedBranch|Branch will be writable for developers. Are you sure?"
msgstr "La branche sera accessible en écriture pour les développeurs. Êtes-vous sûr de vouloir cela ?"
@@ -32511,38 +32950,59 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr "Créer un joker"
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr "Ne s'applique pas aux utilisateurs autorisés à pousser. Les sections facultatives ne sont pas appliquées."
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr "Gardez les branches stables sécurisées et forcez les développeurs à utiliser des demandes de fusion."
+msgid "ProtectedBranch|Last commit"
+msgstr "Dernier commit"
+
msgid "ProtectedBranch|Learn more."
msgstr "En savoir plus."
+msgid "ProtectedBranch|New Protected Tag"
+msgstr "Nouvelle Étiquette Protégée"
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr "Aucune étiquette n’est protégée."
+
msgid "ProtectedBranch|Protect"
-msgstr ""
+msgstr "Protéger"
msgid "ProtectedBranch|Protect a branch"
-msgstr ""
+msgstr "Protéger une branche"
msgid "ProtectedBranch|Protected branch (%{protected_branches_count})"
-msgstr ""
+msgstr "Branche protégée (%{protected_branches_count})"
msgid "ProtectedBranch|Protected branches"
-msgstr ""
+msgstr "Branches protégées"
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr "Une fois configurées, les branches protégées, les approbations de demandes de fusion et les vérifications d'état apparaîtront ici."
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr "Étiquettes protégées (%{tags_count})"
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr "Rejeter les poussées de code qui modifient les fichiers répertoriés dans le fichier CODEOWNERS."
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr "Rechercher des étiquettes protégées"
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr "Sélectionner une étiquette ou créer un joker"
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
-msgstr ""
+msgstr "Il n'y a actuellement aucune branche protégée, protégez une branche avec le formulaire ci-dessus."
msgid "ProtectedBranch|Toggle allowed to force push"
msgstr "Inverser l'autorisation de forcer les poussées"
@@ -32614,7 +33074,7 @@ msgid "ProtectedEnvironment|Select an environment"
msgstr "Sélectionner un environnement"
msgid "ProtectedEnvironment|Select groups"
-msgstr ""
+msgstr "Sélectionner des groupes"
msgid "ProtectedEnvironment|Select users"
msgstr ""
@@ -32734,10 +33194,10 @@ msgid "PumbleIntegration|Send notifications about project events to Pumble. %{do
msgstr "Envoyer à Pumble des notifications concernant les évènements du projet. %{docs_link}"
msgid "Purchase more minutes"
-msgstr ""
+msgstr "Acheter plus de minutes"
msgid "Purchase more storage"
-msgstr ""
+msgstr "Acheter plus de stockage"
msgid "PurchaseStep|An error occurred in the purchase step. If the problem persists please contact support at https://support.gitlab.com."
msgstr "Une erreur s'est produite lors de l'étape d'achat. Si le problème persiste, veuillez contacter le support sur https://support.gitlab.com."
@@ -32752,7 +33212,7 @@ msgid "Push Rules"
msgstr "Règles de poussage Git"
msgid "Push Rules updated successfully."
-msgstr ""
+msgstr "Règles de Poussée mises à jour avec succès."
msgid "Push an existing Git repository"
msgstr ""
@@ -32818,7 +33278,7 @@ msgid "PushRules|Reject any files likely to contain secrets. %{secret_files_link
msgstr "Rejeter tout fichier susceptible de contenir des secrets. %{secret_files_link_start}Quels sont les fichiers secrets rejetés ?%{secret_files_link_end}"
msgid "PushRules|Reject commits that aren't DCO certified"
-msgstr ""
+msgstr "Rejeter les commits qui ne sont pas certifiés avec un DCO"
msgid "PushRules|Reject expression in commit messages"
msgstr "Rejeter les expressions dans les messages de commit"
@@ -32850,6 +33310,9 @@ msgstr "Les utilisateurs peuvent toujours supprimer des étiquettes par l'interm
msgid "PushRule|Push rules"
msgstr "Règles de poussée"
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr "Rejeter les utilisateurs non vérifiés"
@@ -32860,13 +33323,13 @@ msgid "Pushes"
msgstr "Poussées Git"
msgid "PushoverService|%{user_name} deleted branch \"%{ref}\"."
-msgstr ""
+msgstr "%{user_name} a supprimé la branche « %{ref} »."
msgid "PushoverService|%{user_name} push to branch \"%{ref}\"."
msgstr ""
msgid "PushoverService|%{user_name} pushed new branch \"%{ref}\"."
-msgstr ""
+msgstr "%{user_name} a poussé une nouvelle branche « %{ref} »."
msgid "PushoverService|Enter new user key"
msgstr "Entrez la nouvelle clé d'utilisateur"
@@ -32875,7 +33338,7 @@ msgid "PushoverService|Enter your application key."
msgstr ""
msgid "PushoverService|Enter your user key."
-msgstr ""
+msgstr "Entrez votre clé d’utilisateur."
msgid "PushoverService|Get real-time notifications on your device."
msgstr "Recevez des notifications en temps réel sur votre appareil."
@@ -32923,7 +33386,7 @@ msgid "Quick help"
msgstr "Aide rapide"
msgid "Quick range"
-msgstr ""
+msgstr "Plage prédéfinie"
msgid "Quota of CI/CD minutes"
msgstr "Quota de minutes CI/CD"
@@ -32932,7 +33395,7 @@ msgid "Quota of CI/CD minutes:"
msgstr "Quota de minutes CI/CD :"
msgid "README"
-msgstr ""
+msgstr "README"
msgid "Rails"
msgstr "Rails"
@@ -32982,12 +33445,6 @@ msgstr "Lire plus"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr "En savoir plus sur GitLab sur %{link_to_promo}."
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr "Lisez leur documentation."
@@ -33010,7 +33467,7 @@ msgid "Rebase completed"
msgstr "Rebasage terminé"
msgid "Rebase in progress"
-msgstr ""
+msgstr "Rebasage en cours"
msgid "Rebase source branch"
msgstr "Rebaser la branche source"
@@ -33031,13 +33488,13 @@ msgid "Receive notification of abuse reports by email."
msgstr "Recevoir une notification de rapports d'abus par courriel."
msgid "Receive notifications about your own activity"
-msgstr ""
+msgstr "Recevoir des notifications sur votre propre activité"
msgid "Receive product marketing emails"
msgstr ""
msgid "Recent"
-msgstr ""
+msgstr "Récent"
msgid "Recent Project Activity"
msgstr ""
@@ -33061,7 +33518,7 @@ msgid "Recover password"
msgstr "Récupérer le mot de passe"
msgid "Recovery Codes"
-msgstr ""
+msgstr "Codes de Récupération"
msgid "Redirect to SAML provider to test configuration"
msgstr "Rediriger vers le fournisseur SAML pour tester la configuration"
@@ -33081,9 +33538,6 @@ msgstr "Réduire la visibilité du projet"
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr "Réduire la visibilité de ce projet ?"
-
msgid "Reference"
msgstr "Référence"
@@ -33094,7 +33548,7 @@ msgid "Refine your search criteria (select a %{strong_open}group%{strong_close}
msgstr "Affinez vos critères de recherche (sélectionnez un %{strong_open}groupe%{strong_close} et un %{strong_open}projet%{strong_close} si possible)"
msgid "Refresh the page and try again."
-msgstr ""
+msgstr "Actualiser la page et réessayer."
msgid "Refreshing in a second to show the updated status..."
msgid_plural "Refreshing in %d seconds to show the updated status..."
@@ -33105,10 +33559,10 @@ msgid "Regenerate export"
msgstr ""
msgid "Regenerate instance ID"
-msgstr ""
+msgstr "Régénérer l'ID d'instance"
msgid "Regenerate recovery codes"
-msgstr ""
+msgstr "Régénérer les codes de récupération"
msgid "Regenerating the instance ID can break integration depending on the client you are using."
msgstr ""
@@ -33117,10 +33571,10 @@ msgid "Regex pattern"
msgstr "Expression rationnelle"
msgid "Region"
-msgstr ""
+msgstr "Région"
msgid "Regions"
-msgstr ""
+msgstr "Régions"
msgid "Register"
msgstr ""
@@ -33132,7 +33586,7 @@ msgid "Register Two-Factor Authenticator"
msgstr ""
msgid "Register Universal Two-Factor (U2F) Device"
-msgstr ""
+msgstr "Enregistrer un Appareil Universel à Deux Facteurs (U2F)"
msgid "Register WebAuthn Device"
msgstr "Enregistrer un Appareil WebAuthn"
@@ -33222,7 +33676,7 @@ msgid "Reject"
msgstr ""
msgid "Rejected (closed)"
-msgstr ""
+msgstr "Rejetées (fermées)"
msgid "Relate to %{issuable_type} %{add_related_issue_link}"
msgstr "Est lié au %{issuable_type} %{add_related_issue_link}"
@@ -33237,16 +33691,19 @@ msgid "Related merge requests"
msgstr "Demandes de fusion liées"
msgid "Relates to"
-msgstr ""
+msgstr "A un lien avec"
msgid "Release"
msgid_plural "Releases"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Version"
+msgstr[1] "Versions"
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr "La version %{deletedRelease} a été supprimée avec succès."
+msgid "Release already exists"
+msgstr "La version existe déjà"
+
msgid "Release assets"
msgstr "Ressources de version"
@@ -33256,17 +33713,20 @@ msgstr "Documentation des ressources de version"
msgid "Release date"
msgstr "Date de publication"
+msgid "Release does not exist"
+msgstr "La version n'existe pas"
+
msgid "Release does not have the same project as the milestone"
msgstr ""
msgid "Release notes"
-msgstr ""
+msgstr "Notes de version"
msgid "Release notes:"
-msgstr ""
+msgstr "Notes de version :"
msgid "Release title"
-msgstr ""
+msgstr "Titre de version"
msgid "Release with tag \"%{tag}\" was not found"
msgstr "La version avec l'étiquette « %{tag} » est introuvable"
@@ -33347,7 +33807,7 @@ msgid "Remind later"
msgstr "Me le rappeler ultérieurement"
msgid "Remote object has no absolute path."
-msgstr ""
+msgstr "L'objet distant n'a pas de chemin absolu."
msgid "Remove"
msgstr "Supprimer"
@@ -33374,10 +33834,10 @@ msgid "Remove all or specific reviewer(s)"
msgstr ""
msgid "Remove approvers"
-msgstr ""
+msgstr "Supprimer les approbateurs"
msgid "Remove approvers?"
-msgstr ""
+msgstr "Supprimer les approbateurs ?"
msgid "Remove asset link"
msgstr "Supprimer le lien des ressources"
@@ -33392,13 +33852,13 @@ msgid "Remove card"
msgstr ""
msgid "Remove child epic from an epic"
-msgstr ""
+msgstr "Supprimer l'épopée enfant d'une épopée"
msgid "Remove customer relation contact(s)."
-msgstr ""
+msgstr "Supprimer le(s) contact(s) de la relation client."
msgid "Remove customer relation contacts"
-msgstr ""
+msgstr "Supprimer des contacts de la relation client"
msgid "Remove deploy key"
msgstr "Supprimer la clé de déploiement"
@@ -33407,7 +33867,7 @@ msgid "Remove description history"
msgstr ""
msgid "Remove due date"
-msgstr ""
+msgstr "Supprimer la date d'échéance"
msgid "Remove favicon"
msgstr "Supprimer la favicon"
@@ -33467,7 +33927,7 @@ msgid "Remove report"
msgstr "Supprimer le rapport"
msgid "Remove reviewer"
-msgstr ""
+msgstr "Supprimer le relecteur"
msgid "Remove runner"
msgstr "Supprimer l'exécuteur"
@@ -33482,7 +33942,7 @@ msgid "Remove time estimate"
msgstr ""
msgid "Remove topic avatar"
-msgstr ""
+msgstr "Supprimer l'avatar du sujet"
msgid "Remove user"
msgstr "Supprimer l'utilisateur"
@@ -33506,7 +33966,7 @@ msgid "Removed %{assignee_text} %{assignee_references}."
msgstr "%{assignee_text} %{assignee_references} a été retiré ."
msgid "Removed %{epic_ref} from child epics."
-msgstr ""
+msgstr "%{epic_ref} supprimée des épopées enfants."
msgid "Removed %{iteration_reference} iteration."
msgstr "Itération %{iteration_reference} supprimée."
@@ -33536,7 +33996,7 @@ msgid "Removed spent time."
msgstr ""
msgid "Removed the due date."
-msgstr ""
+msgstr "Date d'échéance supprimée."
msgid "Removed time estimate."
msgstr ""
@@ -33554,7 +34014,7 @@ msgid "Removes %{assignee_text} %{assignee_references}."
msgstr ""
msgid "Removes %{epic_ref} from child epics."
-msgstr ""
+msgstr "Supprime %{epic_ref} des épopées enfants."
msgid "Removes %{iteration_reference} iteration."
msgstr "Supprime l'itération %{iteration_reference}."
@@ -33581,7 +34041,7 @@ msgid "Removes spent time."
msgstr ""
msgid "Removes the due date."
-msgstr ""
+msgstr "Supprime la date d'échéance."
msgid "Removes time estimate."
msgstr ""
@@ -33608,7 +34068,7 @@ msgid "Renews"
msgstr ""
msgid "Reopen"
-msgstr ""
+msgstr "Rouvrir"
msgid "Reopen %{issueType}"
msgstr "Rouvrir %{issueType}"
@@ -33635,10 +34095,10 @@ msgid "Reopens this %{quick_action_target}."
msgstr ""
msgid "Replace"
-msgstr ""
+msgstr "Remplacer"
msgid "Replace %{name}"
-msgstr ""
+msgstr "Remplacer %{name}"
msgid "Replace all label(s)"
msgstr ""
@@ -33647,7 +34107,7 @@ msgid "Replace audio"
msgstr ""
msgid "Replace file"
-msgstr ""
+msgstr "Remplacer le fichier"
msgid "Replace image"
msgstr ""
@@ -33659,7 +34119,7 @@ msgid "Replaced all labels with %{label_references} %{label_text}."
msgstr ""
msgid "Replaces the clone URL root."
-msgstr ""
+msgstr "Remplace la racine de l'URL de clonage."
msgid "Replication"
msgstr "Réplication"
@@ -33692,7 +34152,7 @@ msgid "Report abuse to admin"
msgstr "Signaler un abus à l'administrateur"
msgid "Report couldn't be prepared."
-msgstr ""
+msgstr "Le rapport n'a pas pu être préparé."
msgid "Report for the scan has been removed from the database."
msgstr "Le rapport de cette analyse a été supprimé de la base de données."
@@ -33712,6 +34172,9 @@ msgstr "Signalé par"
msgid "Reported by %{reporter}"
msgstr "Signalé par %{reporter}"
+msgid "Reporter"
+msgstr "Rapporteur"
+
msgid "Reporting"
msgstr "Rapports"
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] "%{recentlyFailed} test en échec sur %{failed} a échoué plus d'une fois au cours des 14 derniers jours"
msgstr[1] "%{recentlyFailed} tests en échec sur %{failed} ont échoué plus d'une fois au cours des 14 derniers jours"
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] "L’analyse d’accessibilité a détecté %{strong_start}%{number}%{strong_end} problème pour la branche source uniquement"
@@ -33760,18 +34218,12 @@ msgstr "Une erreur s'est produite lors du chargement du rapport"
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr "Copier les noms des tests échoués pour les exécuter en local"
msgid "Reports|Copy failed tests"
msgstr "Copier les tests échoués"
-msgid "Reports|Execution time"
-msgstr "Durée d’exécution"
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] "Échec %{count} fois dans %{baseBranch} au cours des 14 derniers jours"
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] "Échec %{count} fois dans %{base_branch} au cours des 14 derniers jours"
msgstr[1] "Échec %{count} fois dans %{base_branch} au cours des 14 derniers jours"
-msgid "Reports|Failure"
-msgstr "Échec"
-
-msgid "Reports|Filename"
-msgstr "Nom de fichier"
-
msgid "Reports|Fixed"
msgstr ""
@@ -33822,7 +34268,7 @@ msgid "Reports|Metrics reports: %{strong_start}%{numberOfChanges}%{strong_end} %
msgstr ""
msgid "Reports|New"
-msgstr ""
+msgstr "Nouveau"
msgid "Reports|Scanner"
msgstr "Scanner"
@@ -33830,21 +34276,12 @@ msgstr "Scanner"
msgid "Reports|Severity"
msgstr "Sévérité"
-msgid "Reports|System output"
-msgstr "Sortie du système"
-
msgid "Reports|Test summary"
msgstr "Synthèse des tests"
-msgid "Reports|Test summary failed loading results"
-msgstr "Échec du chargement des résultats de la synthèse des tests"
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr "Les résultats de la synthèse des tests sont en cours d’analyse"
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr "Nom de vulnérabilité"
msgid "Reports|metrics report"
msgstr "rapport des métriques"
-msgid "Reports|no changed test results"
-msgstr "aucun résultat de test modifié"
-
msgid "Repositories"
msgstr "Dépôts"
@@ -33885,7 +34319,7 @@ msgid "RepositoriesAnalytics|Code Coverage: %{averageCoverage}"
msgstr "Couverture de Code : %{averageCoverage}"
msgid "RepositoriesAnalytics|Coverage"
-msgstr ""
+msgstr "Couverture"
msgid "RepositoriesAnalytics|Coverage Jobs"
msgstr ""
@@ -33964,10 +34398,10 @@ msgid "Repository"
msgstr "Dépôt"
msgid "Repository Analytics"
-msgstr ""
+msgstr "Analyses du dépôt"
msgid "Repository Graph"
-msgstr ""
+msgstr "Graphe du dépôt"
msgid "Repository Settings"
msgstr "Paramètres du dépôt"
@@ -33979,19 +34413,19 @@ msgid "Repository by URL"
msgstr "Dépôt par URL"
msgid "Repository check"
-msgstr ""
+msgstr "Vérification du dépôt"
msgid "Repository check was triggered."
-msgstr ""
+msgstr "La vérification du dépôt a été déclenchée."
msgid "Repository checks"
msgstr "Vérifications de dépôt"
msgid "Repository cleanup"
-msgstr ""
+msgstr "Nettoyage du dépôt"
msgid "Repository cleanup has started. You will receive an email once the cleanup operation is complete."
-msgstr ""
+msgstr "Le nettoyage du dépôt a commencé. Vous recevrez un courriel une fois cette opération terminée."
msgid "Repository clone URL"
msgstr "URL de clonage du dépôt"
@@ -34015,13 +34449,13 @@ msgid "Repository maintenance"
msgstr "Maintenance du dépôt"
msgid "Repository mirroring"
-msgstr ""
+msgstr "Mise en miroir du dépôt"
msgid "Repository mirroring configuration"
msgstr "Configuration de la mise en miroir du dépôt"
msgid "Repository mirroring has been paused due to too many failed attempts. It can be resumed by a project maintainer or owner."
-msgstr ""
+msgstr "La mise en miroir du dépôt a été interrompue en raison d'un trop grand nombre de tentatives infructueuses. Elle peut être reprise par un responsable ou propriétaire du projet."
msgid "Repository must contain at least 1 file."
msgstr "Le dépôt doit contenir au moins 1 fichier."
@@ -34030,7 +34464,7 @@ msgid "Repository size is above the limit."
msgstr "La taille du dépôt est supérieure à la limite."
msgid "Repository size limit (MB)"
-msgstr ""
+msgstr "Limite de taille du dépôt (Mo)"
msgid "Repository storage"
msgstr "Stockage du dépôt"
@@ -34169,10 +34603,10 @@ msgid "Resend confirmation email"
msgstr ""
msgid "Resend invite"
-msgstr ""
+msgstr "Renvoyer l'invitation"
msgid "Resend it"
-msgstr ""
+msgstr "Renvoyez-le"
msgid "Resend unlock instructions"
msgstr "Renvoyer les instructions de déverrouillage"
@@ -34234,6 +34668,9 @@ msgstr "Résolu par"
msgid "Resolved by %{name}"
msgstr "Résolu par %{name}"
+msgid "Resource link added"
+msgstr "Lien de ressource ajouté"
+
msgid "Response"
msgstr ""
@@ -34265,7 +34702,7 @@ msgid "Restart GitLab to apply changes."
msgstr "Redémarrez GitLab pour appliquer les modifications."
msgid "Restart Terminal"
-msgstr ""
+msgstr "Redémarrer le Terminal"
msgid "Restore"
msgstr "Restaurer"
@@ -34336,7 +34773,7 @@ msgstr[0] "Révéler la valeur"
msgstr[1] "Révéler les valeurs"
msgid "Reveal values"
-msgstr ""
+msgstr "Révéler les valeurs"
msgid "Revert this commit"
msgstr "Défaire ce commit"
@@ -34401,16 +34838,16 @@ msgid "Revoked"
msgstr ""
msgid "Revoked access token %{access_token_name}!"
-msgstr ""
+msgstr "Jeton d'accès %{access_token_name} révoqué !"
msgid "Revoked impersonation token %{token_name}!"
-msgstr ""
+msgstr "Jeton d'emprunt d'identité %{token_name} révoqué !"
msgid "Revoked personal access token %{personal_access_token_name}!"
-msgstr ""
+msgstr "Jeton d'accès personnel %{personal_access_token_name} révoqué !"
msgid "Rich text"
-msgstr ""
+msgstr "Texte enrichi"
msgid "RightSidebar|Copy email address"
msgstr "Copier l'adresse de courriel"
@@ -34422,13 +34859,13 @@ msgid "Roadmap"
msgstr "Feuille de route"
msgid "Roadmap settings"
-msgstr ""
+msgstr "Paramètres de la feuille de route"
msgid "Roadmap view"
-msgstr ""
+msgstr "Vue de la feuille de route"
msgid "Role"
-msgstr ""
+msgstr "Rôle"
msgid "Rollback"
msgstr ""
@@ -34449,7 +34886,7 @@ msgid "Rules that define what git pushes are accepted for a project. All newly c
msgstr "Règles qui définissent quelles poussées git sont acceptées pour un projet. Tous les projets nouvellement créés utiliseront ces paramètres."
msgid "Run %{code_start}git fsck%{code_end} periodically in all project and wiki repositories to look for silent disk corruption issues."
-msgstr ""
+msgstr "Exécute %{code_start}git fsck%{code_end} périodiquement dans tous les dépôts de projet et de wiki pour rechercher des problèmes de corruption de données silencieuse."
msgid "Run CI/CD pipelines for external repositories"
msgstr "Exécuter des pipelines CI / CD pour les dépôts externes"
@@ -34461,13 +34898,16 @@ msgid "Run CI/CD pipelines with Jenkins."
msgstr "Exécuter des pipelines CI/CD avec Jenkins."
msgid "Run housekeeping"
-msgstr ""
+msgstr "Démarrer la maintenance"
+
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr "Exécuter des tâches de maintenance pour optimiser automatiquement les dépôts Git. Désactiver cette option fera que les performances vont se dégrader au fil du temps."
msgid "Run manual or delayed jobs"
msgstr "Exécuter des tâches manuelles ou différées"
msgid "Run tests against your code live using the Web Terminal"
-msgstr ""
+msgstr "Exécutez des tests sur votre code en direct avec le Terminal Web"
msgid "Run untagged jobs"
msgstr "Exécuter les tâches non étiquetées"
@@ -34482,10 +34922,10 @@ msgid "Runner tokens"
msgstr "Jetons d’exécuteur"
msgid "Runner was not updated."
-msgstr ""
+msgstr "L'exécuteur n'a pas été mis à jour."
msgid "Runner was successfully updated."
-msgstr ""
+msgstr "L'éxécuteur a été mis à jour avec succès."
msgid "Runners"
msgstr "Exécuteurs"
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] "%d exécuteur sélectionné supprimé"
msgstr[1] "%d exécuteurs sélectionnés supprimés"
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr "%{link_start}Ces exécuteurs%{link_end} sont disponibles pour tous les groupes et tous les projets."
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34511,8 +34954,8 @@ msgstr[1] "%{strongStart}%{count}%{strongEnd} exécuteurs sélectionnés"
msgid "Runners|%{strongStart}%{count}%{strongEnd} runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgid_plural "Runners|%{strongStart}%{count}%{strongEnd} runners will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "%{strongStart}%{count}%{strongEnd} exécuteur sera définitivement supprimé et ne sera plus disponible pour les projets ou les groupes de l'instance. Êtes-vous sûr de vouloir continuer ?"
+msgstr[1] "%{strongStart}%{count}%{strongEnd} exécuteurs seront définitivement supprimés et ne seront plus disponibles pour les projets ou les groupes de l'instance. Êtes-vous sûr de vouloir continuer ?"
msgid "Runners|A capacity of 1 enables warm HA through Auto Scaling group re-spawn. A capacity of 2 enables hot HA because the service is available even when a node is lost. A capacity of 3 or more enables hot HA and manual scaling of runner fleet."
msgstr ""
@@ -34529,8 +34972,8 @@ msgstr "Actif"
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr "Ajouter des notes, comme à qui appartient l'exécuteur ou à quoi il doit servir."
-msgid "Runners|Add your feedback in the issue"
-msgstr ""
+msgid "Runners|Administrator"
+msgstr "Administrateur"
msgid "Runners|All"
msgstr "Tous"
@@ -34581,13 +35024,13 @@ msgid "Runners|Capacity of 1 enables warm HA through Auto Scaling group re-spawn
msgstr ""
msgid "Runners|Checkbox"
-msgstr ""
+msgstr "Case à cocher de sélection"
msgid "Runners|Choose your preferred GitLab Runner"
msgstr ""
msgid "Runners|Clear selection"
-msgstr ""
+msgstr "Désélectionner"
msgid "Runners|Command to register runner"
msgstr "Commande pour enregistrer l'exécuteur"
@@ -34606,8 +35049,8 @@ msgstr "Créé %{timeAgo}"
msgid "Runners|Delete %d runner"
msgid_plural "Runners|Delete %d runners"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Supprimer %d exécuteur"
+msgstr[1] "Supprimer %d exécuteurs"
msgid "Runners|Delete runner"
msgstr "Supprimer l’exécuteur"
@@ -34616,7 +35059,7 @@ msgid "Runners|Delete runner %{name}?"
msgstr "Supprimer l'exécuteur %{name} ?"
msgid "Runners|Delete selected"
-msgstr ""
+msgstr "Supprimer la sélection"
msgid "Runners|Deploy GitLab Runner in AWS"
msgstr "Déployer GitLab Runner sur AWS"
@@ -34661,7 +35104,7 @@ msgid "Runners|Group"
msgstr "Groupe"
msgid "Runners|How do runners pick up jobs?"
-msgstr ""
+msgstr "Comment les exécuteurs sélectionnent-ils les tâches ?"
msgid "Runners|How do we upgrade GitLab runner?"
msgstr "Comment mettons-nous à jour GitLab Runner ?"
@@ -34709,7 +35152,7 @@ msgid "Runners|Never expires"
msgstr "N'expire jamais"
msgid "Runners|New group runners view"
-msgstr ""
+msgstr "Nouvelle vue des exécuteurs de groupe"
msgid "Runners|New registration token generated!"
msgstr "Nouveau jeton d’inscription généré !"
@@ -34730,13 +35173,16 @@ msgid "Runners|Offline"
msgstr "Hors ligne"
msgid "Runners|Offline:"
-msgstr ""
+msgstr "Hors ligne :"
msgid "Runners|Online"
msgstr "En ligne"
msgid "Runners|Online:"
-msgstr ""
+msgstr "En ligne :"
+
+msgid "Runners|Owner"
+msgstr "Propriétaire"
msgid "Runners|Pause from accepting jobs"
msgstr "Acceptation de tâches suspendue"
@@ -34777,7 +35223,7 @@ msgid "Runners|Register an instance runner"
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 ""
+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|Registration token"
msgstr "Jeton d'inscription"
@@ -34816,7 +35262,7 @@ msgid "Runners|Runner has contacted GitLab within the last %{elapsedTime}"
msgstr ""
msgid "Runners|Runner has never contacted GitLab (when you register a runner, use %{codeStart}gitlab-runner run%{codeEnd} to bring it online)"
-msgstr ""
+msgstr "L'exécuteur n'a jamais contacté GitLab (lorsque vous enregistrez un exécuteur, utilisez %{codeStart}gitlab-runner run%{codeEnd} pour le mettre en ligne)"
msgid "Runners|Runner has never contacted this instance"
msgstr "L'exécuteur n'a jamais contacté cette instance"
@@ -34861,14 +35307,20 @@ msgid "Runners|Runners"
msgstr "Exécuteurs"
msgid "Runners|Runners are either:"
-msgstr ""
+msgstr "Les exécuteurs sont soit :"
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr "Les exécuteurs sont les agents qui exécutent vos tâches CI/CD. Suivez les %{linkStart}instructions d'installation et d'enregistrement%{linkEnd} pour mettre en place un exécuteur."
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr "Les exécuteurs sont les agents qui exécutent vos tâches CI/CD. Pour enregistrer de nouveaux exécuteurs, veuillez contacter votre administrateur."
+
msgid "Runners|Runs untagged jobs"
msgstr "Exécute des tâches non marquées"
+msgid "Runners|Select all"
+msgstr "Tout sélectionner"
+
msgid "Runners|Select projects to assign to this runner"
msgstr "Sélectionnez les projets à attribuer à cet exécuteur"
@@ -34876,7 +35328,7 @@ msgid "Runners|Select your preferred option here. In the next step, you can choo
msgstr ""
msgid "Runners|Show only inherited"
-msgstr ""
+msgstr "N'afficher que ceux hérités"
msgid "Runners|Show runner installation and registration instructions"
msgstr "Afficher les instructions d'installation et d'enregistrement d'exécuteur"
@@ -34909,14 +35361,17 @@ msgid "Runners|Tags"
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 ""
+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|Take me there!"
-msgstr ""
+msgstr "Emmenez-moi là-bas !"
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr "La nouvelle vue vous donne plus d'espace et une meilleure visibilité sur votre flotte d'exécuteurs."
+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."
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr "L'exécuteur sera définitivement supprimé et ne sera plus disponible pour les projets ou les groupes de l'instance. Êtes-vous sûr de vouloir continuer ?"
@@ -34952,6 +35407,9 @@ msgstr "Pour les enregistrer, allez sur la %{link_start}page des Exécuteurs du
msgid "Runners|Token expiry"
msgstr "Expiration du jeton"
+msgid "Runners|Unselect all"
+msgstr "Tout désélectionner"
+
msgid "Runners|Up to date"
msgstr "À jour"
@@ -34991,12 +35449,6 @@ msgstr "Version %{version}"
msgid "Runners|View installation instructions"
msgstr "Afficher les instructions d'installation"
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr "Nous voulons que vous puissiez gérer vos exécuteurs facilement et efficacement à partir de cette page, et nous apportons des modifications pour atteindre ce but. Donnez-nous votre avis sur ce que nous faisons !"
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr "Nous avons apporté quelques modifications et souhaitons avoir votre avis"
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr "Shell Windows 2019 avec mise à l'échelle manuelle et planification facultative. Spot %{percentage}."
@@ -35034,7 +35486,7 @@ msgid "Running"
msgstr "En cours d’exécution"
msgid "Runs a number of housekeeping tasks within the current repository, such as compressing file revisions and removing unreachable objects."
-msgstr ""
+msgstr "Exécute un certain nombre de tâches de maintenance dans le dépôt actuel, telles que la compression des révisions de fichiers et la suppression d'objets inaccessibles."
msgid "SAML"
msgstr "SAML"
@@ -35051,17 +35503,23 @@ msgstr "Jetons de découverte SAML"
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
-msgstr "Sélectionner « Autoriser » va transférer la propriété de votre compte GitLab « %{username} » (%{email}) à votre organisation."
+msgid "SAML single sign-on"
+msgstr "Authentification unique SAML"
+
+msgid "SAML single sign-on for %{group_name}"
+msgstr "Authentification unique SAML pour %{group_name}"
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr "Connectez-vous à GitLab pour connecter le compte de votre organisation"
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
-msgstr "Le groupe « %{group_path} » vous autorise à vous connecter avec votre compte SSO."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr "Le groupe %{strongOpen}%{group_path}%{strongClose} vous autorise à vous connecter en utilisant l'authentification unique."
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr "Pour accéder à %{strongOpen}%{group_name}%{strongClose}, vous devez vous connecter en utilisant l'authentification unique via une page de connexion externe."
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
-msgstr "Pour accéder à « %{group_name} », vous devez vous connecter avec votre compte SSO via une page de connexion externe."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
+msgstr "Pour autoriser %{strongOpen}%{group_name}%{strongClose} à gérer votre compte GitLab %{strongOpen}%{username}%{strongClose} (%{email}) après vous être connecté avec succès en utilisant l'authentification unique, sélectionnez %{strongOpen}Autoriser%{strongClose}."
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"
@@ -35070,13 +35528,13 @@ msgid "SAST Configuration"
msgstr "Configuration SAST"
msgid "SHA256"
-msgstr ""
+msgstr "SHA256"
msgid "SSH Fingerprints"
msgstr "Empreintes SSH"
msgid "SSH Key"
-msgstr ""
+msgstr "Clé SSH"
msgid "SSH Keys"
msgstr "Clefs SSH"
@@ -35088,7 +35546,7 @@ msgid "SSH fingerprints verify that the client is connecting to the correct host
msgstr "Les empreintes SSH garantissent que le client se connecte au bon hôte. Vérifiez la %{config_link_start}configuration de l'instance actuelle%{config_link_end}."
msgid "SSH host key fingerprints"
-msgstr ""
+msgstr "Empreintes de la clé SSH de l'hôte"
msgid "SSH host keys"
msgstr "Clefs SSH de l’hôte"
@@ -35103,7 +35561,7 @@ msgid "SSH keys"
msgstr "Clés SSH"
msgid "SSH keys allow you to establish a secure connection between your computer and GitLab."
-msgstr ""
+msgstr "Les clés SSH vous permettent d’établir une connexion sécurisée entre votre ordinateur et GitLab."
msgid "SSH keys with the following fingerprints are scheduled to expire soon. Expired SSH keys can not be used:"
msgstr "Les clés SSH avec les empreintes suivantes vont bientôt arriver à expiration. Les clés SSH expirées ne peuvent pas être utilisées :"
@@ -35127,7 +35585,7 @@ msgid "Satisfied"
msgstr ""
msgid "Saturday"
-msgstr ""
+msgstr "Samedi"
msgid "Save"
msgstr "Enregistrer"
@@ -35136,7 +35594,7 @@ msgid "Save %{name} size limits"
msgstr ""
msgid "Save Changes"
-msgstr ""
+msgstr "Enregistrer les modifications"
msgid "Save application"
msgstr "Enregistrer l’application"
@@ -35157,7 +35615,7 @@ msgid "Save internal note"
msgstr "Enregistrer la note interne"
msgid "Save password"
-msgstr ""
+msgstr "Enregistrer le mot de passe"
msgid "Save pipeline schedule"
msgstr "Sauvegarder la planification du pipeline"
@@ -35168,12 +35626,12 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
-msgstr "%{ifLabelStart}if%{ifLabelEnd} %{rules} actions pour les %{scopes} %{branches}"
-
msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr "%{period} %{days} à %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
+msgstr ""
+
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
msgstr "%{thenLabelStart}Then%{thenLabelEnd} Nécessite une analyse %{scan} pour s'exécuter"
@@ -35192,9 +35650,15 @@ msgstr "Planification"
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr "Composant de règle de planification"
+msgid "ScanExecutionPolicy|Select agent"
+msgstr "Sélectionner un agent"
+
msgid "ScanExecutionPolicy|Select branches"
msgstr "Sélectionnez des branches"
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr "Sélectionner des espaces de noms"
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr "Sélectionner un profil de scanner"
@@ -35204,9 +35668,15 @@ msgstr "Sélectionner un profil de site"
msgid "ScanExecutionPolicy|Site profile"
msgstr "Profil de site"
+msgid "ScanExecutionPolicy|agent"
+msgstr "agent"
+
msgid "ScanExecutionPolicy|branch"
msgstr "branche"
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr "dans les espaces de noms"
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35271,7 +35741,7 @@ msgid "Scope board to current iteration"
msgstr "Limiter la portée du tableau à l'itération actuelle"
msgid "Scopes"
-msgstr ""
+msgstr "Portées"
msgid "Scopes (select at least one)"
msgstr "Portées (sélectionnez-en au moins une)"
@@ -35316,10 +35786,10 @@ msgid "Search assignees"
msgstr "Rechercher des assigné(e)s"
msgid "Search authors"
-msgstr ""
+msgstr "Rechercher des auteurs"
msgid "Search branch"
-msgstr ""
+msgstr "Rechercher une branche"
msgid "Search branches"
msgstr "Rechercher des branches"
@@ -35352,14 +35822,11 @@ msgid "Search for Namespace"
msgstr "Rechercher un Espace de noms"
msgid "Search for a LDAP group"
-msgstr ""
+msgstr "Rechercher un groupe LDAP"
msgid "Search for a group"
msgstr "Rechercher un groupe"
-msgid "Search for a user"
-msgstr "Rechercher un utilisateur"
-
msgid "Search for an emoji"
msgstr "Rechercher un emoji"
@@ -35394,7 +35861,7 @@ msgid "Search or filter results..."
msgstr "Rechercher ou filtrer les résultats…"
msgid "Search or filter results…"
-msgstr ""
+msgstr "Rechercher ou filtrer les résultats…"
msgid "Search page"
msgstr "Rechercher dans la page"
@@ -35427,7 +35894,7 @@ msgid "Search users"
msgstr "Rechercher des utilisateurs et utilisatrices"
msgid "Search users or groups"
-msgstr ""
+msgstr "Rechercher des utilisateurs ou des groupes"
msgid "Search your project dependencies for their licenses and apply policies."
msgstr "Rechercher les licences dans les dépendances de votre projet et appliquer les stratégies."
@@ -35451,7 +35918,7 @@ msgid "SearchAutocomplete|Merge requests assigned to me"
msgstr "Demandes de fusion qui me sont assignées"
msgid "SearchAutocomplete|Merge requests that I'm a reviewer"
-msgstr ""
+msgstr "Demandes de fusion dont je suis un relecteur"
msgid "SearchAutocomplete|in all GitLab"
msgstr "Dans tout GitLab"
@@ -35460,7 +35927,7 @@ msgid "SearchAutocomplete|in group %{groupName}"
msgstr ""
msgid "SearchAutocomplete|in project %{projectName}"
-msgstr ""
+msgstr "dans le projet %{projectName}"
msgid "SearchCodeResults|of %{link_to_project}"
msgstr ""
@@ -35484,8 +35951,8 @@ msgstr[1] ""
msgid "SearchResults|comment"
msgid_plural "SearchResults|comments"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "commentaire"
+msgstr[1] "commentaires"
msgid "SearchResults|commit"
msgid_plural "SearchResults|commits"
@@ -35499,13 +35966,13 @@ msgstr[1] "épopées"
msgid "SearchResults|issue"
msgid_plural "SearchResults|issues"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "ticket"
+msgstr[1] "tickets"
msgid "SearchResults|merge request"
msgid_plural "SearchResults|merge requests"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "demande de fusion"
+msgstr[1] "demandes de fusion"
msgid "SearchResults|milestone"
msgid_plural "SearchResults|milestones"
@@ -35514,18 +35981,18 @@ msgstr[1] "jalons"
msgid "SearchResults|project"
msgid_plural "SearchResults|projects"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "projet"
+msgstr[1] "projets"
msgid "SearchResults|snippet"
msgid_plural "SearchResults|snippets"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "extrait"
+msgstr[1] "extraits"
msgid "SearchResults|user"
msgid_plural "SearchResults|users"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "utilisateur"
+msgstr[1] "utilisateurs"
msgid "SearchResults|wiki result"
msgid_plural "SearchResults|wiki results"
@@ -35572,7 +36039,7 @@ msgid "Secure Code Warrior"
msgstr "Secure Code Warrior"
msgid "Secure Files"
-msgstr ""
+msgstr "Fichiers sécurisés"
msgid "Secure token that identifies an external storage request."
msgstr "Jeton sécurisé qui identifie une requête de stockage externe."
@@ -35590,7 +36057,7 @@ msgid "Security"
msgstr "Sécurité"
msgid "Security & Compliance"
-msgstr ""
+msgstr "Sécurité et Conformité"
msgid "Security Configuration"
msgstr "Configuration de la sécurité"
@@ -35602,7 +36069,7 @@ msgid "Security Finding not found"
msgstr "Découverte de Sécurité introuvable"
msgid "Security dashboard"
-msgstr ""
+msgstr "Tableau de bord de sécurité"
msgid "Security navigation"
msgstr ""
@@ -35668,7 +36135,7 @@ msgid "SecurityConfiguration|Configure with a merge request"
msgstr "Configurer avec une demande de fusion"
msgid "SecurityConfiguration|Copy code and open .gitlab-ci.yml file"
-msgstr ""
+msgstr "Copier le code et ouvrir le fichier .gitlab-ci.yml"
msgid "SecurityConfiguration|Copy code only"
msgstr ""
@@ -35701,13 +36168,13 @@ msgid "SecurityConfiguration|Immediately begin risk analysis and remediation wit
msgstr "Démarrez immédiatement l'analyse et la résolution des risques avec les fonctionnalités de sécurité des applications. Commencez avec SAST et la Détection de Secrets, disponibles dans tous les forfaits. Passez à Ultimate pour obtenir l'ensemble des fonctionnalités, notamment :"
msgid "SecurityConfiguration|Learn more about vulnerability training"
-msgstr ""
+msgstr "En savoir plus sur la formation concernant les vulnérabilités"
msgid "SecurityConfiguration|Manage corpus"
msgstr "Gestion de corpus"
msgid "SecurityConfiguration|Manage corpus files used as seed inputs with coverage-guided fuzzing."
-msgstr ""
+msgstr "Gérez les fichiers de corpus utilisés en tant que source de données entrantes pour les tests à données aléatoires guidés par la couverture de code."
msgid "SecurityConfiguration|Manage profiles"
msgstr "Gérer les profils"
@@ -35716,13 +36183,13 @@ msgid "SecurityConfiguration|Manage profiles for use by DAST scans."
msgstr "Gérer les profils utilisés par les analyses DAST."
msgid "SecurityConfiguration|More scan types, including DAST, Dependency Scanning, Fuzzing, and Licence Compliance"
-msgstr ""
+msgstr "Davantage de types d'analyse, incluant DAST, Analyse de Dépendances, Tests à données aléatoires et Conformité de Licences"
msgid "SecurityConfiguration|Not enabled"
-msgstr ""
+msgstr "Non activé"
msgid "SecurityConfiguration|Once you've enabled a scan for the default branch, any subsequent feature branch you create will include the scan. An enabled scanner will not be reflected as such until the pipeline has been successfully executed and it has generated valid artifacts."
-msgstr ""
+msgstr "Une fois que vous avez activé une analyse de la branche par défaut, toute branche de fonctionnalité ultérieure que vous créerez l'inclura. Un scanner activé n'apparaîtra pas en tant que tel tant que le pipeline n'aura pas été exécuté avec succès et qu'il n'aura pas généré d'artéfacts valides."
msgid "SecurityConfiguration|Quickly enable all continuous testing and compliance tools by enabling %{linkStart}Auto DevOps%{linkEnd}"
msgstr "Activer rapidement tous les outils de test continu et de conformité en activant %{linkStart}Auto DevOps%{linkEnd}"
@@ -35749,7 +36216,7 @@ msgid "SecurityConfiguration|The status of the tools only applies to the default
msgstr "L'état des outils ne s'applique qu'à la branche par défaut et se base sur le %{linkStart}dernier pipeline%{linkEnd}."
msgid "SecurityConfiguration|Upgrade or start a free trial"
-msgstr ""
+msgstr "Mettre à niveau ou commencer un essai gratuit"
msgid "SecurityConfiguration|Using custom settings. You won't receive automatic updates on this variable. %{anchorStart}Restore to default%{anchorEnd}"
msgstr "Utilisation de paramètres personnalisés. Vous ne recevrez pas de mises à jour automatiques sur cette variable. %{anchorStart}Restaurer la valeur par défaut%{anchorEnd}"
@@ -35766,11 +36233,14 @@ msgstr "et "
msgid "SecurityOrchestration| or "
msgstr " ou "
-msgid "SecurityOrchestration|%{branches} %{plural}"
-msgstr "Les %{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
-msgstr "Les %{branches} et %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
+msgstr ""
msgid "SecurityOrchestration|%{scanners}"
msgstr "%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr "Hérité"
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr "Héritée de %{namespace}"
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr "Type de politique non valide"
@@ -35965,7 +36438,7 @@ msgid "SecurityOrchestration|Runs a %{action} scan"
msgstr ""
msgid "SecurityOrchestration|Save changes"
-msgstr ""
+msgstr "Enregistrer les modifications"
msgid "SecurityOrchestration|Scan Execution"
msgstr ""
@@ -35991,17 +36464,17 @@ msgstr "Les stratégies de résultats d'analyse ne peuvent être créées que pa
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
-msgstr "Analyse à effectuer %{cadence}"
-
msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr "Analyse à effectuer %{cadence} sur les %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
+msgstr ""
+
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
msgstr "Analyse à effectuer sur chaque pipeline des %{branches}"
msgid "SecurityOrchestration|Security Approvals"
-msgstr ""
+msgstr "Approbations de sécurité"
msgid "SecurityOrchestration|Security policy project was linked successfully"
msgstr "Le projet de politique de sécurité a été lié avec succès"
@@ -36031,10 +36504,10 @@ msgid "SecurityOrchestration|Status"
msgstr "État"
msgid "SecurityOrchestration|Step 1: Choose a policy type"
-msgstr ""
+msgstr "Étape 1 : Choisir un type de politique"
msgid "SecurityOrchestration|Step 2: Policy details"
-msgstr ""
+msgstr "Étape 2 : Détails de la politique"
msgid "SecurityOrchestration|Summary"
msgstr "Résumé"
@@ -36084,8 +36557,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, and Container 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 et analyse de Conteneur."
+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 ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
msgstr "Utilisez une stratégie de résultats d'analyse pour créer des règles qui garantissent que les problèmes de sécurité sont vérifiés avant de fusionner une demande de fusion."
@@ -36102,6 +36575,9 @@ msgstr "un(e)"
msgid "SecurityOrchestration|all branches"
msgstr "toutes les branches"
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr "un(e)"
@@ -36112,20 +36588,29 @@ msgid "SecurityOrchestration|branches"
msgstr "branches"
msgid "SecurityOrchestration|scanner finds"
-msgstr ""
+msgstr "scanner trouve"
msgid "SecurityOrchestration|scanners find"
-msgstr ""
+msgstr "scanners trouvent"
msgid "SecurityOrchestration|the %{branches}"
msgstr "les %{branches}"
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr "vulnérabilités"
msgid "SecurityOrchestration|vulnerability"
msgstr "vulnérabilité"
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr "%{count} sélectionnés"
@@ -36147,6 +36632,9 @@ msgstr "Ajouter des projets"
msgid "SecurityReports|All activity"
msgstr "Toute l'activité"
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr "Bien qu'il soit rare de ne pas avoir de vulnérabilités, cela peut arriver. Vérifiez vos paramètres afin de vous assurer que vous avez configuré votre tableau de bord correctement."
@@ -36276,6 +36764,9 @@ msgstr "Projets surveillés"
msgid "SecurityReports|More info"
msgstr "Plus d’informations"
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr "Aucune activité"
@@ -36313,7 +36804,7 @@ msgid "SecurityReports|Projects added"
msgstr "Projets ajoutés"
msgid "SecurityReports|Remove project from dashboard"
-msgstr ""
+msgstr "Supprimer le projet du tableau de bord"
msgid "SecurityReports|Report has expired"
msgstr "Le rapport a expiré"
@@ -36333,6 +36824,9 @@ msgstr "Les rapports de sécurité ne peuvent être consultés que par les utili
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36358,7 +36852,7 @@ msgid "SecurityReports|Status"
msgstr "État"
msgid "SecurityReports|Still detected"
-msgstr ""
+msgstr "Toujours détecté"
msgid "SecurityReports|Submit vulnerability"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr "Votre avis est important pour nous ! Nous vous le demanderons de nouveau
msgid "SecurityReports|scanned resources"
msgstr "ressources analysées"
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr "Activer la formation sur la sécurité pour apprendre comment corriger les vulnérabilités. Voir la formation de sécurité depuis des centres de formation sélectionnés en fonction de la vulnérabilité détectée."
+
msgid "SecurityTraining|Primary Training"
msgstr "Formation primaire"
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr "La formation provenant de ce partenaire est prioritaire lorsqu'il y a plus d'un partenaire de formation activé."
@@ -36460,11 +36960,14 @@ msgid "See example DevOps Score page in our documentation."
msgstr "Voir l'exemple de page Score DevOps dans notre documentation."
msgid "See metrics"
-msgstr ""
+msgstr "Voir les métriques"
msgid "See our website for help"
msgstr "Consultez notre site Web pour obtenir de l'aide"
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr "Consultez la documentation de dépannage Geo pour en savoir plus : %{docs_url}"
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36490,7 +36993,7 @@ msgid "Select a branch"
msgstr "Sélectionner une branche"
msgid "Select a branch to compare"
-msgstr ""
+msgstr "Sélectionnez une branche à comparer"
msgid "Select a color"
msgstr "Sélectionnez une couleur"
@@ -36499,7 +37002,7 @@ msgid "Select a compliance framework to apply to this project. %{linkStart}How a
msgstr ""
msgid "Select a file from the left sidebar to begin editing. Afterwards, you'll be able to commit your changes."
-msgstr ""
+msgstr "Sélectionnez un fichier dans la barre latérale de gauche pour commencer l'édition. Ensuite, vous pourrez valider vos modifications."
msgid "Select a label"
msgstr "Sélectionnez une étiquette"
@@ -36508,7 +37011,7 @@ msgid "Select a milestone"
msgstr "Sélectionner un jalon"
msgid "Select a new namespace"
-msgstr ""
+msgstr "Sélectionnez un nouvel espace de noms"
msgid "Select a project"
msgstr ""
@@ -36520,7 +37023,7 @@ msgid "Select a repository containing templates for common files."
msgstr "Sélectionnez un dépôt contenant les modèles des fichiers ordinaires."
msgid "Select a role"
-msgstr ""
+msgstr "Sélectionner un rôle"
msgid "Select a template repository"
msgstr "Sélectionner un modèle de dépôt"
@@ -36528,9 +37031,6 @@ msgstr "Sélectionner un modèle de dépôt"
msgid "Select a template type"
msgstr "Sélectionner un type de modèle"
-msgid "Select a timezone"
-msgstr "Sélectionnez un fuseau horaire"
-
msgid "Select all"
msgstr "Tout sélectionner"
@@ -36556,7 +37056,7 @@ msgid "Select branches"
msgstr ""
msgid "Select default branch"
-msgstr ""
+msgstr "Sélectionner la branche par défaut"
msgid "Select due date"
msgstr "Sélectionner la date d'échéance"
@@ -36604,10 +37104,10 @@ msgid "Select projects"
msgstr ""
msgid "Select report"
-msgstr ""
+msgstr "Sélectionner un rapport"
msgid "Select reviewer(s)"
-msgstr ""
+msgstr "Sélectionnez un ou plusieurs relecteurs"
msgid "Select source"
msgstr "Sélectionner la source"
@@ -36619,13 +37119,13 @@ msgid "Select source project"
msgstr "Sélectionner le projet source"
msgid "Select start date"
-msgstr ""
+msgstr "Sélectionnez la date de début"
msgid "Select status"
-msgstr ""
+msgstr "Sélectionnez l'état"
msgid "Select strategy activation method"
-msgstr ""
+msgstr "Sélectionnez la méthode d'activation de la stratégie"
msgid "Select subgroup"
msgstr "Sélectionner un sous-groupe"
@@ -36669,11 +37169,11 @@ msgstr "L'étiquette sélectionnée est déjà utilisée. Faites un autre choix.
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr "Sélectionner un utilisateur GitLab ajoutera un lien vers celui-ci dans la description et les commentaires des tickets (p. ex. « Par %{link_open}@johnsmith%{link_close} »). Cela associera également et/ou assignera ces tickets et ces commentaires à l'utilisateur sélectionné."
-msgid "Self monitoring"
-msgstr "Auto-surveillance"
+msgid "Self-monitoring"
+msgstr "Autosurveillance"
-msgid "Self monitoring project does not exist"
-msgstr "Le projet d'auto-surveillance n'existe pas"
+msgid "Self-monitoring project does not exist"
+msgstr "Le projet d'autosurveillance n'existe pas"
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
msgstr "Le projet d'auto-surveillance n'existe pas. Veuillez vérifier les messages d'erreur dans les journaux"
@@ -36684,29 +37184,29 @@ 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 "SelfMonitoring|Activate or deactivate instance self monitoring."
-msgstr "Activer ou désactiver l'auto-surveillance de l'instance."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
+msgstr "Activer ou désactiver l'autosurveillance de l'instance."
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
-msgstr "Activez l'auto-surveillance pour créer un projet à utiliser pour surveiller la santé de votre instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
+msgstr "Activez l'autosurveillance pour créer un projet à utiliser pour surveiller la santé de votre instance."
-msgid "SelfMonitoring|Deactivate self monitoring?"
-msgstr "Désactiver l'auto-surveillance ?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
+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'auto-surveillance supprime le projet d'auto-surveillance. Voulez-vous vraiment désactiver l'auto-surveillance et supprimer le projet ?"
+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. Êtes-vous sûr de vouloir désactiver l’autosurveillance et de supprimer le projet ?"
-msgid "SelfMonitoring|Self monitoring"
-msgstr "Auto-surveillance"
+msgid "SelfMonitoring|Self-monitoring"
+msgstr "Autosurveillance"
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
-msgstr "L'auto-surveillance est active. Utilisez le %{projectLinkStart}projet d'auto-surveillance%{projectLinkEnd} pour surveiller la santé de votre instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgstr "L’autosurveillance est active. Utilisez le %{projectLinkStart}projet d’autosurveillance%{projectLinkEnd} pour surveiller la santé de votre instance."
-msgid "SelfMonitoring|Self monitoring project successfully created."
-msgstr "Le projet d'auto-surveillance a été créé avec succès."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
+msgstr "Le projet d’autosurveillance a été créé avec succès."
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
-msgstr "Le projet d’auto-surveillance a été supprimé avec succès."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
+msgstr "Le projet d’autosurveillance a été supprimé avec succès."
msgid "Send"
msgstr "Envoyer"
@@ -36754,7 +37254,7 @@ msgid "Sentry"
msgstr "Sentry"
msgid "Sentry API URL"
-msgstr ""
+msgstr "URL de l'API Sentry"
msgid "Sentry event"
msgstr ""
@@ -36766,7 +37266,7 @@ msgid "September"
msgstr "septembre"
msgid "SeriesFinalConjunction|and"
-msgstr ""
+msgstr "et"
msgid "Serve repository static objects (for example, archives and blobs) from external storage."
msgstr "Desservir les objets statiques du dépôt (archives et blobs par exemple) depuis un stockage externe."
@@ -36808,7 +37308,7 @@ msgid "Service accounts"
msgstr "Comptes de service"
msgid "Service usage data"
-msgstr ""
+msgstr "Données d'utilisation du service"
msgid "ServiceDesk|Enable Service Desk"
msgstr "Activer le Service d'Assistance"
@@ -36850,7 +37350,7 @@ msgid "Session ID"
msgstr "ID de session"
msgid "Session duration (minutes)"
-msgstr ""
+msgstr "Durée de session (minutes)"
msgid "Set %{epic_ref} as the parent epic."
msgstr ""
@@ -36924,9 +37424,6 @@ msgstr "Définir à l'état Brouillon"
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr "Définissez la branche par défaut de ce projet. Tous les commits et demandes de fusion seront effectués sur cette branche à moins que vous n'en spécifiez une autre."
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr "Définir le délai d'expiration par défaut des artéfacts des tâches dans tous les projets. Mettre à %{code_open}0%{code_close} pour que les artéfacts n'expirent jamais par défaut. Si aucune unité n'est précisée, ce sera la seconde par défaut. Ces exemples sont tous équivalents : %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close} et %{code_open}une heure%{code_close}."
@@ -36991,10 +37488,10 @@ msgid "Set visibility of project contents. Configure import sources and Git acce
msgstr "Définir la visibilité du contenu du projet. Configurer les sources d'importation et les protocoles d'accès à Git."
msgid "Set weight"
-msgstr ""
+msgstr "Définir le poids"
msgid "Set weight to %{weight}."
-msgstr ""
+msgstr "Définir le poids à %{weight}."
msgid "SetStatusModal|Clear status"
msgstr "Effacer l’état"
@@ -37057,10 +37554,10 @@ msgid "Sets time estimate to %{time_estimate}."
msgstr ""
msgid "Sets weight to %{weight}."
-msgstr ""
+msgstr "Définit le poids à %{weight}."
msgid "Setting"
-msgstr ""
+msgstr "Paramètre"
msgid "Setting enforced"
msgstr "Paramètre imposé"
@@ -37076,9 +37573,6 @@ msgstr "Paramètres"
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr "Impossible de charger les paramètres des options de demande de fusion. Essayez de recharger la page."
-msgid "Setup"
-msgstr "Configuration"
-
msgid "Severity"
msgstr "Gravité"
@@ -37119,7 +37613,7 @@ msgid "Shared runners details"
msgstr "Détails des exécuteurs partagés"
msgid "Shared runners enabled cannot be enabled until a valid credit card is on file"
-msgstr ""
+msgstr "Les exécuteurs partagés ne peuvent pas être activés tant qu'aucune carte de crédit valide n'est enregistrée"
msgid "Shared runners help link"
msgstr ""
@@ -37155,10 +37649,10 @@ msgid "Shimo|You've enabled the Shimo Workspace integration. You can view your w
msgstr "Vous avez activé l'intégration de l'Espace de travail Shimo. Vous pouvez voir votre wiki directement dans Shimo."
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 ""
+msgstr "En cas de perte de votre téléphone ou de l'accès à votre mot de passe secret unique, chacun de ces codes de récupération pourra être utilisé une fois pour regagner l'accès à votre compte. Veuillez les enregistrer dans un lieu sûr, sinon vous %{boldStart}allez%{boldEnd} perdre l'accès à votre compte."
msgid "Show Pipeline ID"
-msgstr ""
+msgstr "Afficher l'ID de Pipeline"
msgid "Show Pipeline IID"
msgstr "Afficher l'IID de Pipeline"
@@ -37167,7 +37661,7 @@ msgid "Show all %{issuable_type}."
msgstr ""
msgid "Show all activity"
-msgstr ""
+msgstr "Afficher toute l'activité"
msgid "Show all breadcrumbs"
msgstr "Afficher tous les fils d'Ariane"
@@ -37212,7 +37706,7 @@ msgid "Show details"
msgstr "Afficher les détails"
msgid "Show file browser"
-msgstr ""
+msgstr "Afficher le navigateur de fichiers"
msgid "Show file contents"
msgstr "Afficher le contenu du fichier"
@@ -37331,13 +37825,10 @@ msgid "Showing all epics"
msgstr "Affichage de toutes les épopées"
msgid "Showing all issues"
-msgstr ""
-
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr "Affichage des données des éléments du flux de travail sur cette plage de dates. Celle-ci est limitée à %{maxDateRange} jours."
+msgstr "Affichage de tous les tickets"
-msgid "Showing graphs based on events of the last %{timerange} days."
-msgstr "Affichage des graphiques en fonction des événements des %{timerange} derniers jours."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
+msgstr ""
msgid "Showing last %{size} of log -"
msgstr ""
@@ -37390,8 +37881,8 @@ msgstr "Connectez-vous comme utilisateur avec l'adresse de courriel correspondan
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
-msgstr ""
+msgid "Sign in to %{group_name}"
+msgstr "Se connecter à %{group_name}"
msgid "Sign in to GitLab"
msgstr "Se connecter à GitLab"
@@ -37405,8 +37896,8 @@ msgstr ""
msgid "Sign in with"
msgstr "Connexion avec"
-msgid "Sign in with Single Sign-On"
-msgstr "Se connecter avec une authentification unique"
+msgid "Sign in with single sign-on"
+msgstr "Se connecter avec l'authentification unique"
msgid "Sign in with smart card"
msgstr ""
@@ -37427,7 +37918,7 @@ msgid "Sign up now"
msgstr "S'inscrire maintenant"
msgid "Sign up was successful! Please confirm your email to sign in."
-msgstr ""
+msgstr "L'inscription a réussi ! Veuillez confirmer votre adresse de courriel pour vous connecter."
msgid "Sign-in and Help page"
msgstr "Pages d'aide et de connexion"
@@ -37481,7 +37972,7 @@ msgid "SignUp|Minimum length is %{minimum_password_length} characters."
msgstr "La longueur minimale est de %{minimum_password_length} caractères."
msgid "SignUp|Username is too long (maximum is %{max_length} characters)."
-msgstr ""
+msgstr "Le nom d'utilisateur est trop long (le maximum est de %{max_length} caractères)."
msgid "SignUp|Username is too short (minimum is %{min_length} characters)."
msgstr "Le nom d'utilisateur est trop court (le minimum est de %{min_length} caractères)."
@@ -37496,7 +37987,7 @@ msgid "Signed in to GitLab as %{user_link}"
msgstr ""
msgid "Signed in with %{authentication} authentication"
-msgstr ""
+msgstr "Connexion avec l'authentification %{authentication}"
msgid "Signing in using %{label} has been disabled"
msgstr ""
@@ -37526,10 +38017,7 @@ msgid "Size Limits"
msgstr "Limitations des Tailles"
msgid "Size limit per repository (MB)"
-msgstr ""
-
-msgid "Skip outdated deployment jobs"
-msgstr "Ignorer les tâches de déploiement dépassées"
+msgstr "Limite de taille par dépôt (Mo)"
msgid "Skipped"
msgstr ""
@@ -37679,16 +38167,16 @@ msgid "SnippetsEmptyState|Documentation"
msgstr "Documentation"
msgid "SnippetsEmptyState|New snippet"
-msgstr ""
+msgstr "Nouvel extrait"
msgid "SnippetsEmptyState|No snippets found"
-msgstr ""
+msgstr "Aucun extrait trouvé"
msgid "SnippetsEmptyState|Store, share, and embed small pieces of code and text."
msgstr "Stocker, partager et intégrer des petites portions de code et de texte."
msgid "SnippetsEmptyState|There are no snippets to show."
-msgstr ""
+msgstr "Il n'y a aucun extrait à afficher."
msgid "Snippets|%{spammable_titlecase} was submitted to Akismet successfully."
msgstr "%{spammable_titlecase} a été soumis à Akismet avec succès."
@@ -37718,10 +38206,10 @@ msgid "Snippets|Snippets can't contain empty files. Ensure all files have conten
msgstr "Les extraits ne peuvent pas contenir de fichiers vides. Assurez-vous que tous les fichiers ont du contenu, ou supprimez-les."
msgid "Snowplow"
-msgstr ""
+msgstr "Snowplow"
msgid "Soft wrap"
-msgstr ""
+msgstr "Retour à la ligne"
msgid "Solid"
msgstr "Solide"
@@ -37748,11 +38236,14 @@ msgid "Someone edited this %{issueType} at the same time you did. The descriptio
msgstr ""
msgid "Someone edited this merge request at the same time you did. Please refresh the page to see changes."
-msgstr ""
+msgstr "Quelqu'un a modifié cette demande de fusion en même temps que vous. Veuillez actualiser la page pour voir les modifications."
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr "Quelqu'un a modifié ce cas de test en même temps que vous. La description a été mise à jour et vous allez devoir refaire vos modifications."
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr "Quelqu'un s'est connecté à votre compte %{host} à partir d'un nouvel emplacement"
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "Quelqu'un, en espérant qu'il s'agit de vous, a demandé la réinitialisation du mot de passe de votre compte GitLab sur %{link_to_gitlab}."
@@ -37769,7 +38260,7 @@ msgid "Something went wrong on our end. Please try again!"
msgstr "Quelque chose s’est mal passé de notre côté. Veuillez réessayer."
msgid "Something went wrong on our end. Please try again."
-msgstr ""
+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}"
@@ -37790,7 +38281,7 @@ msgid "Something went wrong while applying the batch of suggestions. Please try
msgstr ""
msgid "Something went wrong while applying the suggestion. Please try again."
-msgstr ""
+msgstr "Une erreur s'est produite lors de l'application de la suggestion. Veuillez réessayer."
msgid "Something went wrong while archiving a requirement."
msgstr "Une erreur s'est produite lors de l'archivage d'une exigence."
@@ -37805,10 +38296,10 @@ msgid "Something went wrong while creating a requirement."
msgstr "Une erreur s'est produite lors de la création d'une exigence."
msgid "Something went wrong while deleting description changes. Please try again."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la suppression des modifications de la description. Veuillez réessayer."
msgid "Something went wrong while deleting the source branch. Please try again."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la suppression de la branche source. Veuillez réessayer."
msgid "Something went wrong while deleting your note. Please try again."
msgstr ""
@@ -37817,7 +38308,7 @@ msgid "Something went wrong while deploying this environment. Please try again."
msgstr "Une erreur s'est produite lors du déploiement de cet environnement. Veuillez réessayer."
msgid "Something went wrong while editing your comment. Please try again."
-msgstr ""
+msgstr "Une erreur s'est produite lors de l'édition de votre commentaire. Veuillez réessayer."
msgid "Something went wrong while exporting requirements"
msgstr "Une erreur s'est produite lors de l'export des exigences."
@@ -37829,7 +38320,7 @@ msgid "Something went wrong while fetching comments. Please try again."
msgstr "Une erreur est survenue lors de la récupération des commentaires. Veuillez réessayer."
msgid "Something went wrong while fetching description changes. Please try again."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des modifications de la description. Veuillez réessayer."
msgid "Something went wrong while fetching details"
msgstr "Une erreur s'est produite lors de la récupération des détails"
@@ -37841,13 +38332,13 @@ msgid "Something went wrong while fetching latest comments."
msgstr "Quelque chose s'est mal passé lors de la récupération des derniers commentaires."
msgid "Something went wrong while fetching projects"
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des projets"
msgid "Something went wrong while fetching projects."
msgstr "Une erreur s'est produite lors de la récupération des projets."
msgid "Something went wrong while fetching related merge requests."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des demandes de fusion associées."
msgid "Something went wrong while fetching requirements count."
msgstr "Une erreur s'est produite lors de la récupération du nombre d'exigences."
@@ -37862,10 +38353,7 @@ msgid "Something went wrong while fetching the environments for this merge reque
msgstr "Une erreur est survenue lors de la récupération des environnements pour cette demande de fusion. Veuillez réessayer."
msgid "Something went wrong while fetching the packages list."
-msgstr ""
-
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération de la liste des paquets."
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr "Une erreur s'est produite lors de l'obtention du certificat Let's Encrypt."
@@ -37907,7 +38395,7 @@ msgid "Something went wrong while setting %{issuableType} weight."
msgstr "Une erreur s'est produite lors du réglage du poids de %{issuableType}."
msgid "Something went wrong while stopping this environment. Please try again."
-msgstr ""
+msgstr "Une erreur s'est produite lors de l'arrêt de cet environnement. Veuillez réessayer."
msgid "Something went wrong while updating a requirement."
msgstr "Une erreur s'est produite lors de la mise à jour d'une exigence."
@@ -37916,7 +38404,7 @@ msgid "Something went wrong while updating assignees"
msgstr "Une erreur s'est produite lors de la mise à jour des assigné(e)s"
msgid "Something went wrong while updating your list settings"
-msgstr ""
+msgstr "Une erreur s'est produite lors de la mise à jour des paramètres de votre liste"
msgid "Something went wrong with your automatic subscription renewal."
msgstr "Une erreur s'est produite lors du renouvellement automatique de votre abonnement."
@@ -37928,10 +38416,10 @@ msgid "Something went wrong, unable to delete project"
msgstr "Une erreur s'est produite, impossible de supprimer le projet"
msgid "Something went wrong, unable to get projects"
-msgstr ""
+msgstr "Une erreur s'est produite, impossible d'obtenir les projets"
msgid "Something went wrong, unable to search projects"
-msgstr ""
+msgstr "Une erreur s'est produite, impossible de rechercher des projets"
msgid "Something went wrong. Please try again later"
msgstr "Une erreur s'est produite. Veuillez réessayer plus tard"
@@ -37940,7 +38428,7 @@ msgid "Something went wrong. Please try again."
msgstr "Quelque chose s’est mal passé. Veuillez réessayer."
msgid "Something went wrong. Try again later."
-msgstr ""
+msgstr "Une erreur s'est produite. Réessayez plus tard."
msgid "Sorry, no projects matched your search"
msgstr "Désolé, aucun projet ne correspond à votre recherche"
@@ -38141,10 +38629,10 @@ msgid "Source branch"
msgstr "Branche source"
msgid "Source branch will be deleted."
-msgstr ""
+msgstr "La branche source sera supprimée."
msgid "Source branch will not be deleted."
-msgstr ""
+msgstr "La branche source ne sera pas supprimée."
msgid "Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}"
msgstr "Branche Source : %{source_branch_open}%{source_branch}%{source_branch_close}"
@@ -38156,7 +38644,7 @@ msgid "Source is not available"
msgstr "La source n’est pas disponible"
msgid "Source project cannot be found."
-msgstr ""
+msgstr "Le projet source est introuvable."
msgid "SourceEditor|\"el\" parameter is required for createInstance()"
msgstr "Le paramètre « el » est requis pour createInstance()"
@@ -38273,7 +38761,7 @@ msgid "Squash commits when merge request is accepted."
msgstr "Écraser les commits lorsque la demande de fusion est acceptée."
msgid "Stack trace"
-msgstr ""
+msgstr "Trace de pile"
msgid "Stacktrace snippet"
msgstr "Extrait de la trace de pile"
@@ -38285,7 +38773,7 @@ msgid "Stage:"
msgstr "Étape :"
msgid "Standard"
-msgstr ""
+msgstr "Standard"
msgid "Star labels to start sorting by priority"
msgstr "Mettez des étoiles sur les étiquettes pour les classer par priorité"
@@ -38315,16 +38803,16 @@ msgid "Starrers"
msgstr ""
msgid "Stars"
-msgstr ""
+msgstr "Étoiles"
msgid "Start Date"
-msgstr ""
+msgstr "Date de début"
msgid "Start Time"
msgstr ""
msgid "Start Web Terminal"
-msgstr ""
+msgstr "Démarrer le Terminal Web"
msgid "Start a %{new_merge_request} with these changes"
msgstr "Créer une %{new_merge_request} avec ces changements"
@@ -38363,13 +38851,13 @@ msgid "Start merge train"
msgstr ""
msgid "Start merge train when pipeline succeeds"
-msgstr ""
+msgstr "Démarrer un train de fusion lorsque le pipeline réussit"
msgid "Start merge train..."
msgstr ""
msgid "Start search"
-msgstr ""
+msgstr "Commencer une recherche"
msgid "Start thread"
msgstr ""
@@ -38378,7 +38866,7 @@ msgid "Start your Free Ultimate Trial"
msgstr "Commencez votre Essai Ultimate Gratuit"
msgid "Start your free trial"
-msgstr ""
+msgstr "Commencez votre essai gratuit"
msgid "Started"
msgstr "Démarré"
@@ -38393,7 +38881,7 @@ msgid "Started escalation for this incident."
msgstr ""
msgid "Starting..."
-msgstr ""
+msgstr "Démarrage en cours..."
msgid "Starts"
msgstr "Commence"
@@ -38426,23 +38914,20 @@ msgid "Static Application Security Testing (SAST)"
msgstr "Test statique de la sécurité des applications (SAST)"
msgid "Statistics"
-msgstr ""
+msgstr "Statistiques"
msgid "Status"
-msgstr ""
+msgstr "État"
msgid "Status was retried."
msgstr ""
msgid "Status:"
-msgstr ""
+msgstr "État :"
msgid "Status: %{title}"
msgstr "État : %{title}"
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr " %{failed} en échec, et %{pending} en attente"
-
msgid "StatusCheck|%{failed} failed"
msgstr "%{failed} a échoué"
@@ -38455,9 +38940,6 @@ msgstr "API à vérifier"
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr "Toutes passées"
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr "Une erreur s'est produite lors de la suppression de la vérification d'état %{name}."
@@ -38479,9 +38961,6 @@ msgstr "L'API externe est déjà utilisée par une autre vérification d'état."
msgid "StatusCheck|Failed to load status checks"
msgstr "Échec du chargement des vérifications d'état"
-msgid "StatusCheck|Failed to load status checks."
-msgstr "Impossible de charger les vérifications d'état."
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr "Invoquer une API externe dans le cadre du processus de pipeline."
@@ -38561,25 +39040,25 @@ msgid "StatusPage|your status page frontend."
msgstr "votre page frontale d'état."
msgid "Stay updated about the performance and health of your environment by configuring Prometheus to monitor your deployments."
-msgstr ""
+msgstr "Restez informé des performances et de l'état de santé de votre environnement en configurant Prometheus pour surveiller vos déploiements."
msgid "Step %{currentStep} of %{stepCount}"
msgstr "Étape %{currentStep} sur %{stepCount}"
msgid "Step 1."
-msgstr ""
+msgstr "Étape 1."
msgid "Step 2."
-msgstr ""
+msgstr "Étape 2."
msgid "Step 3."
-msgstr ""
+msgstr "Étape 3."
msgid "Step 4."
-msgstr ""
+msgstr "Étape 4."
msgid "Stop Terminal"
-msgstr ""
+msgstr "Arrêter le Terminal"
msgid "Stop impersonation"
msgstr "Arrêter l’emprunt d’identité"
@@ -38591,7 +39070,7 @@ msgid "Stopped"
msgstr "Arrêté"
msgid "Stopping..."
-msgstr ""
+msgstr "Arrêt en cours..."
msgid "Storage"
msgstr "Stockage"
@@ -38639,7 +39118,7 @@ msgid "SubgroupCreationlevel|Maintainers"
msgstr ""
msgid "SubgroupCreationlevel|Owners"
-msgstr ""
+msgstr "Propriétaires"
msgid "Subgroups"
msgstr "Sousâ€groupes"
@@ -38660,7 +39139,7 @@ msgid "Submit"
msgstr "Envoyer"
msgid "Submit a review"
-msgstr ""
+msgstr "Envoyer une revue de code"
msgid "Submit as ham"
msgstr "Soumettre comme acceptable"
@@ -38678,7 +39157,7 @@ msgid "Submit search"
msgstr "Soumettre la recherche"
msgid "Submit the current review."
-msgstr ""
+msgstr "Envoyez la revue de code actuelle."
msgid "Submitted as ham"
msgstr "Soumis comme acceptable"
@@ -38696,10 +39175,10 @@ msgid "Subscribe at project level"
msgstr "S’abonner au niveau du projet"
msgid "Subscribe to RSS feed"
-msgstr ""
+msgstr "S'abonner au flux RSS"
msgid "Subscribe to calendar"
-msgstr ""
+msgstr "S'abonner au calendrier"
msgid "Subscribed"
msgstr "Abonné"
@@ -38717,13 +39196,13 @@ msgid "Subscript"
msgstr "Indice"
msgid "Subscription"
-msgstr ""
+msgstr "Abonnement"
msgid "Subscription History"
msgstr "Historique d'Abonnement"
msgid "Subscription deletion failed."
-msgstr ""
+msgstr "La suppression de l'abonnement a échoué."
msgid "Subscription service outage"
msgstr "Panne du service abonnement"
@@ -38732,10 +39211,10 @@ msgid "Subscription successfully applied to \"%{group_name}\""
msgstr "Abonnement appliqué avec succès à \"%{group_name}\""
msgid "Subscription successfully created."
-msgstr ""
+msgstr "Abonnement créé avec succès."
msgid "Subscription successfully deleted."
-msgstr ""
+msgstr "Abonnement supprimé avec succès."
msgid "SubscriptionBanner|Add new license"
msgstr "Ajouter une nouvelle licence"
@@ -38753,7 +39232,7 @@ msgid "SubscriptionTable|An error occurred while loading the subscription detail
msgstr "Une erreur s'est produite lors du chargement des détails de l'abonnement."
msgid "SubscriptionTable|Billing"
-msgstr ""
+msgstr "Facturation"
msgid "SubscriptionTable|Free"
msgstr ""
@@ -38762,13 +39241,13 @@ msgid "SubscriptionTable|GitLab allows you to continue using your subscription e
msgstr ""
msgid "SubscriptionTable|Last invoice"
-msgstr ""
+msgstr "Dernière facture"
msgid "SubscriptionTable|Loading subscriptions"
-msgstr ""
+msgstr "Chargement des abonnements"
msgid "SubscriptionTable|Manage"
-msgstr ""
+msgstr "Gérer"
msgid "SubscriptionTable|Max seats used"
msgstr ""
@@ -38798,10 +39277,10 @@ msgid "SubscriptionTable|Something went wrong trying to refresh seats"
msgstr "Une erreur s'est produite lors de la tentative d'actualisation des sièges"
msgid "SubscriptionTable|Subscription end date"
-msgstr ""
+msgstr "Date de fin de l'abonnement"
msgid "SubscriptionTable|Subscription start date"
-msgstr ""
+msgstr "Date de début de l'abonnement"
msgid "SubscriptionTable|This is the last time the GitLab.com team was in contact with you to settle any outstanding balances."
msgstr ""
@@ -38825,13 +39304,13 @@ msgid "SubscriptionTable|Trial start date"
msgstr ""
msgid "SubscriptionTable|Usage"
-msgstr ""
+msgstr "Utilisation"
msgid "SubscriptionTable|Usage count is performed once a day at 12:00 PM."
msgstr ""
msgid "Subscriptions"
-msgstr ""
+msgstr "Abonnements"
msgid "Subscriptions|Chat with sales"
msgstr "Discuter avec le service commercial"
@@ -38861,7 +39340,7 @@ msgid "Succeeded"
msgstr ""
msgid "Successfully activated"
-msgstr ""
+msgstr "Activé avec succès"
msgid "Successfully approved"
msgstr "Approuvé avec succès"
@@ -38870,25 +39349,25 @@ msgid "Successfully banned"
msgstr "Banni avec succès"
msgid "Successfully blocked"
-msgstr ""
+msgstr "Bloqué avec succès"
msgid "Successfully confirmed"
-msgstr ""
+msgstr "Confirmé avec succès"
msgid "Successfully deactivated"
-msgstr ""
+msgstr "Désactivé avec succès"
msgid "Successfully deleted U2F device."
-msgstr ""
+msgstr "Appareil U2F supprimé avec succès."
msgid "Successfully deleted WebAuthn device."
msgstr "L'appareil WebAuthn a été supprimé avec succès."
msgid "Successfully removed email."
-msgstr ""
+msgstr "Courriel supprimé avec succès."
msgid "Successfully scheduled a pipeline to run. Go to the %{pipelines_link_start}Pipelines page%{pipelines_link_end} for details."
-msgstr ""
+msgstr "L’exécution d’un pipeline a été planifiée avec succès. Accédez à la %{pipelines_link_start}page des Pipelines%{pipelines_link_end} pour plus de détails."
msgid "Successfully synced %{synced_timeago}."
msgstr "Synchronisation réussie %{synced_timeago}."
@@ -38897,10 +39376,10 @@ msgid "Successfully unbanned"
msgstr "Gracié avec succès"
msgid "Successfully unblocked"
-msgstr ""
+msgstr "Débloqué avec succès"
msgid "Successfully unlocked"
-msgstr ""
+msgstr "Déverrouillé avec succès"
msgid "Successfully updated %{last_updated_timeago}."
msgstr "Mise à jour réussie %{last_updated_timeago}."
@@ -38969,7 +39448,7 @@ msgid "SuggestedColors|Green"
msgstr "Vert"
msgid "SuggestedColors|Green screen"
-msgstr ""
+msgstr "Écran vert"
msgid "SuggestedColors|Green-cyan"
msgstr "Turquoise foncé"
@@ -38984,16 +39463,16 @@ msgid "SuggestedColors|Medium sea green"
msgstr "Vert océan moyen"
msgid "SuggestedColors|Orange"
-msgstr ""
+msgstr "Orange"
msgid "SuggestedColors|Purple"
-msgstr ""
+msgstr "Violet"
msgid "SuggestedColors|Red"
msgstr "Rouge"
msgid "SuggestedColors|Rose red"
-msgstr ""
+msgstr "Rouge rose"
msgid "SuggestedColors|Titanium yellow"
msgstr "Jaune titane"
@@ -39001,9 +39480,15 @@ msgstr "Jaune titane"
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr "Obtenir des suggestions pour les relecteurs grâce à l'outil d'apprentissage automatique de GitLab."
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr "En savoir plus sur les relecteurs suggérés"
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr "Relecteurs suggérés"
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr "Les suggestions apparaissent dans la section Relecteur de la barre latérale droite"
@@ -39011,7 +39496,7 @@ msgid "Suggestion is not applicable as the suggestion was not found."
msgstr "La suggestion n'est pas applicable car elle n'a pas été trouvée."
msgid "Suggestion(s)"
-msgstr ""
+msgstr "Suggestion(s)"
msgid "Suggestions are not applicable as one or more suggestions were not found."
msgstr ""
@@ -39023,10 +39508,10 @@ msgid "Suggestions must all be on the same branch."
msgstr "Les suggestions doivent toutes être sur la même branche."
msgid "Suggestions:"
-msgstr ""
+msgstr "Suggestions :"
msgid "Suite"
-msgstr ""
+msgstr "Suite"
msgid "Summary"
msgstr ""
@@ -39035,13 +39520,13 @@ msgid "Summary / note"
msgstr "Résumé / note"
msgid "Summary comment (optional)"
-msgstr ""
+msgstr "Commentaire récapitulatif (facultatif)"
msgid "Sun"
msgstr "Dim"
msgid "Sunday"
-msgstr ""
+msgstr "Dimanche"
msgid "SuperSonics|Activate subscription"
msgstr "Activer l'abonnement"
@@ -39232,10 +39717,10 @@ msgid "Support"
msgstr ""
msgid "Support for custom certificates is disabled. Ask your system's administrator to enable it."
-msgstr ""
+msgstr "La prise en charge des certificats personnalisés est désactivée. Demandez à l'administrateur de votre système de l'activer."
msgid "Support page URL"
-msgstr ""
+msgstr "URL de la page de support"
msgid "Surveys|Delighted"
msgstr "Très satisfait"
@@ -39256,11 +39741,14 @@ msgid "Switch Branches"
msgstr ""
msgid "Switch branch"
-msgstr ""
+msgstr "Changer de branche"
msgid "Switch branch/tag"
msgstr "Changer de branche ou d’étiquette"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr "Passer à GitLab Next"
@@ -39322,10 +39810,10 @@ msgid "System Info"
msgstr "Informations système"
msgid "System default (%{default})"
-msgstr ""
+msgstr "Valeur par défaut du système (%{default})"
msgid "System header and footer"
-msgstr ""
+msgstr "Enâ€tête et pied de page du système"
msgid "System hooks are triggered on sets of events like creating a project or adding an SSH key. You can also enable extra triggers, such as push events."
msgstr "Les crochets systèmes sont déclenchés selon un ensemble d'événements, tels que la création d'un projet ou l'ajout d'une clé SSH. Vous pouvez également activer des déclencheurs supplémentaires comme des événements de poussée."
@@ -39343,7 +39831,7 @@ msgid "System started"
msgstr "Système démarré"
msgid "Table of Contents"
-msgstr ""
+msgstr "Table des Matières"
msgid "Table of contents"
msgstr "Table des matières"
@@ -39351,11 +39839,14 @@ msgstr "Table des matières"
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr "L'étiquette n'existe pas"
+
msgid "Tag list:"
msgstr ""
msgid "Tag name"
-msgstr ""
+msgstr "Nom de l'étiquette"
msgid "Tag name is required."
msgstr "Le nom de l'étiquette est requis."
@@ -39435,6 +39926,9 @@ msgstr "Supprimer l'étiquette. Êtes-vous ABSOLUMENT SÛR ?"
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr "La suppression de l’étiquette %{strongStart}%{tagName}%{strongEnd} ne peut être annulée. Êtes-vous sûr(e) ?"
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr "Voulez-vous créer une version avec la nouvelle étiquette ? Vous pouvez le faire dans la %{link_start}page de Nouvelle version%{link_end}."
+
msgid "TagsPage|Edit release"
msgstr "Modifier la version"
@@ -39456,15 +39950,9 @@ msgstr "Seul un propriétaire ou un mainteneur du projet peut supprimer une éti
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr "Éventuellement, créez une Version publique de votre projet, basée sur cette étiquette. Les notes de version sont affichées sur la page des %{releases_page_link_start}Versions%{link_end} . %{docs_link_start}Plus d'informations%{link_end}"
-
msgid "TagsPage|Please type the following to confirm:"
msgstr "Veuillez taper ce qui suit pour confirmer :"
-msgid "TagsPage|Release notes"
-msgstr "Notes de version"
-
msgid "TagsPage|Repository has no tags yet."
msgstr "Le dépôt n’a pour le moment aucune étiquette."
@@ -39486,9 +39974,6 @@ msgstr "Impossible de charger les étiquettes"
msgid "TagsPage|Use git tag command to add a new one:"
msgstr "Utilisez la commande « git tag » pour en rajouter :"
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "Rédigez vos notes de version ou faites glisser des fichiers ici…"
-
msgid "TagsPage|Yes, delete protected tag"
msgstr "Oui, supprimer l’étiquette protégée"
@@ -39505,7 +39990,10 @@ msgid "TagsPage|protected"
msgstr "protégé"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
-msgstr ""
+msgstr "Jetez un œil à la documentation pour découvrir toutes les fonctionnalités de GitLab."
+
+msgid "Target"
+msgstr "Cible"
msgid "Target Branch"
msgstr "Branche cible"
@@ -39520,7 +40008,7 @@ msgid "Target branch or tag"
msgstr ""
msgid "Target roles"
-msgstr ""
+msgstr "Rôles cibles"
msgid "Target-Branch"
msgstr "Branche-cible"
@@ -39568,7 +40056,7 @@ msgid "TemplateRepository|Create common files more quickly, and standardize thei
msgstr "Créer des fichiers ordinaires plus rapidement, et uniformiser leur format."
msgid "Templates"
-msgstr ""
+msgstr "Modèles"
msgid "TemporaryStorageIncrease|can only be set once"
msgstr "ne peut être défini qu'une seule fois"
@@ -39586,13 +40074,13 @@ msgid "TemporaryStorage|Temporarily increase storage now?"
msgstr "Augmenter temporairement le stockage maintenant ?"
msgid "Terminal"
-msgstr ""
+msgstr "Terminal"
msgid "Terminal for environment"
msgstr ""
msgid "Terminal sync service is running"
-msgstr ""
+msgstr "Le service de synchronisation du terminal est en cours d'exécution"
msgid "Terms of Service Agreement and Privacy Policy"
msgstr "Conditions générales d’utilisation et politique de confidentialité"
@@ -39604,7 +40092,7 @@ msgid "Terms of service"
msgstr "Conditions d’Utilisation"
msgid "Terraform"
-msgstr ""
+msgstr "Terraform"
msgid "TerraformBanner|Learn more about GitLab's Backend State"
msgstr "En savoir plus sur le Backend État de GitLab"
@@ -39618,16 +40106,6 @@ msgstr "Terraform est utilisé ? Essayez l'État Terraform Géré par GitLab"
msgid "Terraform|%{name} successfully removed"
msgstr "%{name} supprimé avec succès"
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] "%{number} rapport Terraform a été généré dans vos pipelines"
-msgstr[1] "%{number} rapports Terraform ont été générés dans vos pipelines"
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr "La génération d'un rapport Terraform a échoué."
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr "Un rapport Terraform a été généré dans vos pipelines."
-msgid "Terraform|A report failed to generate."
-msgstr "La génération d'un rapport a échoué."
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr "Un rapport a été généré dans vos pipelines."
-
msgid "Terraform|Actions"
msgstr "Actions"
@@ -39681,7 +40153,7 @@ msgid "Terraform|Details"
msgstr ""
msgid "Terraform|Download JSON"
-msgstr ""
+msgstr "Télécharger le JSON"
msgid "Terraform|Failed to load Terraform reports"
msgstr "Échec du chargement des rapports Terraform"
@@ -39690,7 +40162,7 @@ msgid "Terraform|Generating the report caused an error."
msgstr "La génération du rapport a provoqué une erreur."
msgid "Terraform|How to use GitLab-managed Terraform state?"
-msgstr ""
+msgstr "Comment utiliser un état Terraform géré par GitLab ?"
msgid "Terraform|Job status"
msgstr "État de la tâche"
@@ -39702,7 +40174,7 @@ msgid "Terraform|Lock"
msgstr "Verrouiller"
msgid "Terraform|Locked"
-msgstr ""
+msgstr "Verrouillé"
msgid "Terraform|Locked by %{user} %{timeAgo}"
msgstr "Verrouillage par %{user} %{timeAgo}"
@@ -39720,7 +40192,7 @@ msgid "Terraform|Remove"
msgstr "Supprimer"
msgid "Terraform|Remove state file and versions"
-msgstr ""
+msgstr "Supprimer le fichier d'état et ses versions"
msgid "Terraform|Removed"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr "Commande Terraform init"
msgid "Terraform|Terraform reports"
msgstr "Rapports Terraform"
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr "La tâche %{name} n'a pas pu générer de rapport."
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr "La tâche %{name} a généré un rapport."
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr "La tâche %{strong_start}%{name}%{strong_end} n'a pas réussi à générer un rapport."
@@ -39756,7 +40222,7 @@ msgid "Terraform|To get access to this terraform state from your local computer,
msgstr "Pour obtenir l'accès à cet état terraform depuis votre ordinateur local, exécutez la commande suivante sur la ligne de commande. La première ligne nécessite un jeton d'accès personnel avec accès en lecture et en écriture à l'API. %{linkStart}Comment créer un jeton d'accès personnel ?%{linkEnd}."
msgid "Terraform|To remove the State file and its versions, type %{name} to confirm:"
-msgstr ""
+msgstr "Pour supprimer le fichier d'État et ses versions, tapez %{name} pour confirmer :"
msgid "Terraform|Unknown User"
msgstr "Utilisateur Inconnu"
@@ -39820,7 +40286,7 @@ msgid "TestCases|Something went wrong while creating a test case."
msgstr "Une erreur s'est produite lors de la création d'un cas de test."
msgid "TestCases|Something went wrong while fetching test case."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération du cas de test."
msgid "TestCases|Something went wrong while fetching test cases list."
msgstr "Une erreur s'est produite lors de la récupération de la liste des cas de test."
@@ -39868,10 +40334,10 @@ msgid "TestHooks|Ensure the wiki is enabled and has pages."
msgstr ""
msgid "TestReports|%{count} errors"
-msgstr ""
+msgstr "%{count} erreurs"
msgid "TestReports|%{count} failures"
-msgstr ""
+msgstr "%{count} échecs"
msgid "TestReports|%{count} tests"
msgstr "%{count} tests"
@@ -39904,16 +40370,16 @@ msgid "TestReports|Test reports require job artifacts but all artifacts are expi
msgstr "Les rapports de tests nécessitent des artéfacts de tâche mais tous ces derniers ont expiré. %{linkStart}En savoir plus%{linkEnd}"
msgid "TestReports|Tests"
-msgstr ""
+msgstr "Tests"
msgid "TestReports|There are no test cases to display."
-msgstr ""
+msgstr "Il n’y a aucun cas de test à afficher."
msgid "TestReports|There are no test reports for this pipeline"
msgstr "Il n’y a aucun rapport de tests pour ce pipeline"
msgid "TestReports|There are no test suites to show."
-msgstr ""
+msgstr "Il n'y a aucune suite de tests à afficher."
msgid "TestReports|There are no tests to display"
msgstr "Il n'y a aucun test à afficher"
@@ -39928,7 +40394,7 @@ msgid "TestReports|You can configure your job to use unit test reports, and GitL
msgstr "Vous pouvez configurer votre tâche pour utiliser des rapports de tests unitaires, et GitLab affichera un rapport ici ainsi que dans la demande de fusion associée."
msgid "Tests"
-msgstr ""
+msgstr "Tests"
msgid "Text (optional)"
msgstr "Texte (facultatif)"
@@ -39968,8 +40434,8 @@ msgstr "Le %{plan_name} n'est plus disponible à l'achat. Pour plus d'informatio
msgid "The %{type} contains the following error:"
msgid_plural "The %{type} contains the following errors:"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Le %{type} contient l'erreur suivante :"
+msgstr[1] "Le %{type} contient les erreurs suivantes :"
msgid "The API key used by GitLab for accessing the Spam Check service endpoint."
msgstr "La clé d'API utilisée par GitLab pour accéder au point de terminaison du service Spam Check."
@@ -40017,7 +40483,7 @@ msgid "The associated issue #%{issueId} has been closed as the error is now reso
msgstr "Le ticket #%{issueId} associé a été fermé car l'erreur est maintenant résolue."
msgid "The branch for this project has no active pipeline configuration."
-msgstr ""
+msgstr "La branche de ce projet n'a pas de configuration de pipeline active."
msgid "The branch or tag does not exist"
msgstr "La branche ou le tag n'existe pas"
@@ -40053,13 +40519,13 @@ msgid "The content editor may change the markdown formatting style of the docume
msgstr "L'éditeur de contenu peut modifier le style de mise en forme markdown du document, qui peut ne pas correspondre à votre style markdown d'origine."
msgid "The content for this wiki page failed to load. To fix this error, reload the page."
-msgstr ""
+msgstr "Le contenu de cette page wiki n'a pas pu être chargé. Pour corriger cette erreur, rechargez la page."
msgid "The content for this wiki page failed to render."
-msgstr ""
+msgstr "Le rendu du contenu de cette page wiki a échoué."
msgid "The content of this page is not encoded in UTF-8. Edits can only be made via the Git repository."
-msgstr ""
+msgstr "Le contenu de cette page n'est pas codé en UTF-8. Les modifications ne peuvent être effectuées que via le dépôt Git."
msgid "The contents of this group, its subgroups and projects will be permanently removed after %{deletion_adjourned_period} days on %{date}. After this point, your data cannot be recovered."
msgstr ""
@@ -40092,19 +40558,19 @@ msgid "The default branch for this project has been changed. Please update your
msgstr "La branche par défaut de ce projet a été modifiée. Veuillez mettre à jour vos favoris."
msgid "The dependency list details information about the components used within your project."
-msgstr ""
+msgstr "La liste des dépendances détaille les informations sur les composants utilisés dans votre projet."
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 directory has been successfully created."
-msgstr ""
+msgstr "Le répertoire a été créé avec succès."
msgid "The domain you entered is misformatted."
-msgstr ""
+msgstr "Le domaine que vous avez saisi est mal formaté."
msgid "The domain you entered is not allowed."
-msgstr ""
+msgstr "Le domaine que vous avez saisi n'est pas autorisé."
msgid "The download link will expire in 24 hours."
msgstr "Le lien de téléchargement expirera dans 24 heures."
@@ -40122,10 +40588,10 @@ msgid "The file could not be displayed because it is empty or larger than the ma
msgstr "Le fichier ne peut pas être affiché car il est vide ou de taille supérieure à celle maximale indexée (%{size})."
msgid "The file has been successfully created."
-msgstr ""
+msgstr "Le fichier a été créé avec succès."
msgid "The file has been successfully deleted."
-msgstr ""
+msgstr "Le fichier a été supprimé avec succès."
msgid "The file name should have a .yml extension"
msgstr "Le nom du fichier doit avoir une extension .yml"
@@ -40140,16 +40606,16 @@ msgid "The following %{user} can also push to this branch: %{branch}"
msgstr ""
msgid "The following Personal Access Token was revoked by an administrator, %{username}."
-msgstr ""
+msgstr "Le Jeton d'Accès Personnel suivant a été révoqué par un administrateur, %{username}."
msgid "The following SSH key was deleted by an administrator, %{username}."
msgstr "La clé SSH suivante a été supprimée par un administrateur, %{username}."
msgid "The following items will NOT be exported:"
-msgstr ""
+msgstr "Les éléments suivants ne seront PAS exportés :"
msgid "The following items will be exported:"
-msgstr ""
+msgstr "Les éléments suivants seront exportés :"
msgid "The following personal access token: %{token_names} was revoked, because a new policy to expire personal access tokens were set."
msgid_plural "The following personal access tokens: %{token_names} were revoked, because a new policy to expire personal access tokens were set."
@@ -40177,7 +40643,7 @@ msgid "The group and any internal projects can be viewed by any logged in user e
msgstr ""
msgid "The group and any public projects can be viewed without any authentication."
-msgstr ""
+msgstr "Le groupe et tous les projets publics peuvent être visualisés sans aucune authentification."
msgid "The group and its projects can only be viewed by members."
msgstr ""
@@ -40186,7 +40652,7 @@ msgid "The group export can be downloaded from:"
msgstr "L'export du groupe peut être téléchargé à partir de :"
msgid "The group has already been shared with this group"
-msgstr ""
+msgstr "Le groupe a déjà été partagé avec ce groupe"
msgid "The group settings for %{group_links} require you to enable Two-Factor Authentication for your account. You can %{leave_group_links}."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr "Le nom d'hôte de votre serveur PlantUML."
msgid "The hostname of your Snowplow collector."
msgstr "Le nom d'hôte de votre collecteur Snowplow."
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "L’importation expirera après %{timeout}. Pour les dépôts qui prennent plus de temps, utilisez une combinaison de clone et push."
@@ -40216,10 +40685,10 @@ msgid "The invitation could not be declined."
msgstr ""
msgid "The invitation has already been accepted."
-msgstr ""
+msgstr "L'invitation a déjà été acceptée."
msgid "The invitation was successfully resent."
-msgstr ""
+msgstr "L'invitation a été renvoyée avec succès."
msgid "The issue was successfully promoted to an epic. Redirecting to epic..."
msgstr "Le ticket a été promu en épopée avec succès. Redirection vers l'épopée..."
@@ -40243,13 +40712,13 @@ msgid "The license key is invalid. Make sure it is exactly as you received it fr
msgstr "La clé de licence n’est pas valide. Assurez-vous qu'elle est exactement telle que vous l'avez reçue de GitLab Inc."
msgid "The license was removed. GitLab has fallen back on the previous license."
-msgstr ""
+msgstr "La licence a été supprimée. GitLab a été remis sous la licence précédente."
msgid "The license was removed. GitLab now no longer has a valid license."
-msgstr ""
+msgstr "La licence a été supprimée. GitLab n'a plus de licence valide."
msgid "The license was successfully uploaded and is now active. You can see the details below."
-msgstr ""
+msgstr "La licence a été téléversée avec succès et est maintenant active. Vous pouvez voir les détails ci-dessous."
msgid "The license was successfully uploaded and will be active from %{starts_at}. You can see the details below."
msgstr "La licence a été téléversée avec succès et sera active à partir du %{starts_at}. Vous pouvez voir les détails ci-dessous."
@@ -40264,7 +40733,7 @@ msgid "The maximum amount of time users have to set up two-factor authentication
msgstr "La durée maximale avant que l'authentification à deux facteurs ne soit imposée pour les utilisateurs qui l'ont activée."
msgid "The maximum file size allowed is %{size}."
-msgstr ""
+msgstr "La taille de fichier maximale autorisée est de %{size}."
msgid "The maximum file size for job artifacts."
msgstr "La taille maximale de fichier pour les artéfacts des tâches."
@@ -40285,7 +40754,7 @@ msgid "The merge conflicts for this merge request cannot be resolved through Git
msgstr ""
msgid "The merge conflicts for this merge request have already been resolved."
-msgstr ""
+msgstr "Les conflits de fusion de cette demande de fusion ont déjà été résolus."
msgid "The merge conflicts for this merge request have already been resolved. Please return to the merge request."
msgstr ""
@@ -40336,7 +40805,7 @@ msgid "The pipelines schedule runs pipelines in the future, repeatedly, for spec
msgstr "La planification des pipelines permet l’exécution de pipelines programmés, de manière récurrente, pour des branches ou des étiquettes spécifiques. Ces pipelines programmés hériteront d’un accès limité aux projets en fonction de l’utilisateur qui leur est associé."
msgid "The project can be accessed by any logged in user except external users."
-msgstr ""
+msgstr "Le projet est accessible à tout utilisateur connecté, à l'exception des utilisateurs externes."
msgid "The project can be accessed without any authentication."
msgstr "Votre projet est accessible sans aucune authentification."
@@ -40345,7 +40814,7 @@ msgid "The project has already been added to your dashboard."
msgstr "Le projet a déjà été ajouté à votre tableau de bord."
msgid "The project is still being deleted. Please try again later."
-msgstr ""
+msgstr "Le projet est toujours en cours de suppression. Veuillez réessayer plus tard."
msgid "The project size exceeds the export limit."
msgstr "La taille du projet dépasse la limite d'exportation."
@@ -40354,7 +40823,7 @@ msgid "The project was successfully forked."
msgstr ""
msgid "The project was successfully imported."
-msgstr ""
+msgstr "Le projet a été importé avec succès."
msgid "The related CI build failed."
msgstr ""
@@ -40366,7 +40835,7 @@ msgid "The remote mirror took to long to complete."
msgstr ""
msgid "The remote repository is being updated..."
-msgstr ""
+msgstr "Le dépôt distant est en cours de mise à jour …"
msgid "The report artifact provided by the CI build couldn't be parsed."
msgstr ""
@@ -40384,7 +40853,7 @@ msgid "The repository for this project is empty"
msgstr "Le dépôt de ce projet est vide"
msgid "The repository is being updated..."
-msgstr ""
+msgstr "Le dépôt est en cours de mise à jour..."
msgid "The repository must be accessible over %{code_open}http://%{code_close}, %{code_open}https://%{code_close} or %{code_open}git://%{code_close}."
msgstr "Le dépôt doit être accessible avec %{code_open}http://%{code_close}, %{code_open}https://%{code_close} ou %{code_open}git://%{code_close}."
@@ -40395,9 +40864,6 @@ msgstr "Le dépôt doit être accessible avec %{code_open}http://%{code_close},
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr "La ressource à laquelle vous essayez d'accéder n'existe pas ou vous n'avez pas la permission d'effectuer cette action."
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr "Le même exécuteur partagé exécute du code à partir de plusieurs projets, sauf si vous configurez le dimensionnement automatique avec %{link} à 1 (ce qui est le cas sur GitLab.com)."
-
msgid "The scan has been created."
msgstr "L'analyse a été créée."
@@ -40405,10 +40871,10 @@ msgid "The secret is only available when you first create the application."
msgstr ""
msgid "The snippet can be accessed without any authentication."
-msgstr ""
+msgstr "L'extrait de code peut être consulté sans aucune authentification."
msgid "The snippet is visible only to me."
-msgstr ""
+msgstr "L'extrait de code est visible seulement pour moi."
msgid "The snippet is visible only to project members."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr "Le sujet source n'est pas un sujet."
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr "La date de début doit être antérieure à la date de fin."
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40450,7 +40916,7 @@ msgid "The uploaded file was invalid. Supported file extensions are %{extensions
msgstr "Le fichier téléversé n'était pas valide. Les extensions de fichier prises en charge sont %{extensions}."
msgid "The user is being deleted."
-msgstr ""
+msgstr "L'utilisateur est en cours de suppression."
msgid "The user map has been saved. Continue by selecting the projects you want to import."
msgstr ""
@@ -40462,7 +40928,7 @@ msgid "The user you are trying to approve is not pending approval"
msgstr "L'utilisateur que vous essayez d'approuver n'est pas en attente d'approbation"
msgid "The user you are trying to deactivate has been active in the past %{minimum_inactive_days} days and cannot be deactivated"
-msgstr ""
+msgstr "L'utilisateur que vous essayez de désactiver a été actif au cours des %{minimum_inactive_days} derniers jours et ne peut pas être désactivé"
msgid "The username for the Jenkins server."
msgstr "Le nom d'utilisateur du serveur Jenkins."
@@ -40483,10 +40949,7 @@ msgid "The vulnerability is no longer detected. Verify the vulnerability has bee
msgstr "La vulnérabilité n'est plus détectée. Vérifiez qu'elle a été corrigée avant de changer son état."
msgid "Theme"
-msgstr ""
-
-msgid "There are currently no events."
-msgstr "Il n'y a actuellement aucun événement."
+msgstr "Thème"
msgid "There are currently no mirrored repositories."
msgstr "Il n'y a actuellement aucun dépôt mis en miroir."
@@ -40495,16 +40958,16 @@ msgid "There are merge conflicts"
msgstr "Il y a des conflits de fusion"
msgid "There are no GPG keys associated with this account."
-msgstr ""
+msgstr "Il n'y a pas de clé GPG associée à ce compte."
msgid "There are no GPG keys with access to your account."
-msgstr ""
+msgstr "Il n'y a pas de clé GPG avec accès à votre compte."
msgid "There are no SSH keys associated with this account."
-msgstr ""
+msgstr "Il n'y a pas de clé SSH associée à ce compte."
msgid "There are no SSH keys with access to your account."
-msgstr ""
+msgstr "Il n'y a pas de clé SSH avec accès à votre compte."
msgid "There are no Spam Logs"
msgstr "Il n'y a pas de Journaux d'Indésirables"
@@ -40528,16 +40991,16 @@ msgid "There are no changes"
msgstr "Il n'y a aucun changement"
msgid "There are no charts configured for this page"
-msgstr ""
+msgstr "Il n'y a aucun graphique configuré pour cette page"
msgid "There are no closed epics"
msgstr "Il n'y a pas d'épopée fermée"
msgid "There are no closed issues"
-msgstr ""
+msgstr "Il n'y a aucun ticket fermé"
msgid "There are no closed merge requests"
-msgstr ""
+msgstr "Il n'y a aucune demande de fusion fermée"
msgid "There are no commits yet."
msgstr "Il n'y a pas encore de commit."
@@ -40552,16 +41015,16 @@ msgid "There are no issues with the selected labels"
msgstr "Il n'y a aucun ticket avec les étiquettes sélectionnées"
msgid "There are no matching files"
-msgstr ""
+msgstr "Il n'y a aucun fichier correspondant"
msgid "There are no open epics"
msgstr "Il n'y a pas d'épopée ouverte"
msgid "There are no open issues"
-msgstr ""
+msgstr "Il n'y a pas de ticket ouvert"
msgid "There are no open merge requests"
-msgstr ""
+msgstr "Il n'y a aucune demande de fusion ouverte"
msgid "There are no open requirements"
msgstr "Il n'y a aucune exigence ouverte"
@@ -40570,7 +41033,7 @@ msgid "There are no open test cases"
msgstr "Il n'y a aucun cas de test ouvert"
msgid "There are no packages yet"
-msgstr ""
+msgstr "Il n'y a pas encore de paquets"
msgid "There are no projects shared with this group yet"
msgstr "Il n’y a pas encore de projets partagés avec ce groupe"
@@ -40597,7 +41060,7 @@ msgid "There are several size limits in place."
msgstr "Plusieurs limitations de tailles sont définies."
msgid "There is already a repository with that name on disk"
-msgstr ""
+msgstr "Il existe déjà un dépôt avec ce nom sur le disque"
msgid "There is already a to-do item for this design."
msgstr "Il y a déjà un élément « À faire » pour ce design."
@@ -40609,7 +41072,7 @@ msgid "There is no data available."
msgstr "Il n'y a aucune donnée disponible."
msgid "There is no data available. Please change your selection."
-msgstr ""
+msgstr "Aucune donnée n'est disponible. Veuillez modifier votre sélection."
msgid "There is no table data available."
msgstr "Il n'y a aucune donnée de tableau disponible."
@@ -40618,7 +41081,7 @@ msgid "There is too much data to calculate. Please change your selection."
msgstr "Il y a trop de données à calculer. Veuillez modifier votre sélection."
msgid "There was a problem communicating with your device."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la communication avec votre appareil."
msgid "There was a problem fetching CRM contacts."
msgstr "Une erreur s'est produite lors de la récupération des contacts du CRM."
@@ -40666,7 +41129,7 @@ msgid "There was a problem fetching recent projects."
msgstr "Une erreur s'est produite lors de la récupération des projets récents."
msgid "There was a problem fetching releases."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des versions."
msgid "There was a problem fetching the job token scope value"
msgstr "Un problème est survenu lors de la récupération de la valeur de la portée du jeton de tâche"
@@ -40690,7 +41153,7 @@ msgid "There was a problem handling the pipeline data."
msgstr "Une erreur s'est produite lors de la gestion des données du pipeline."
msgid "There was a problem sending the confirmation email"
-msgstr ""
+msgstr "Une erreur s'est produite lors de l'envoi du courriel de confirmation"
msgid "There was a problem updating the keep latest artifacts setting."
msgstr "Une erreur s'est produite lors de la mise à jour du paramètre de conservation des derniers artéfacts."
@@ -40705,16 +41168,16 @@ msgid "There was an error creating the dashboard, branch named: %{branch} alread
msgstr "Une erreur s'est produite lors de la création du tableau de bord, la branche nommée : %{branch} existe déjà."
msgid "There was an error creating the issue"
-msgstr ""
+msgstr "Une erreur s'est produite lors de la création du ticket"
msgid "There was an error deleting the To Do."
msgstr ""
msgid "There was an error fetching configuration for charts"
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération de la configuration des graphiques"
msgid "There was an error fetching data for the selected stage"
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des données de l'étape sélectionnée"
msgid "There was an error fetching data for the tasks by type chart"
msgstr ""
@@ -40753,7 +41216,7 @@ msgid "There was an error fetching value stream analytics stages."
msgstr "Une erreur s'est produite lors de la récupération des étapes de l'analyse des chaînes de valeur."
msgid "There was an error gathering the chart data"
-msgstr ""
+msgstr "Une erreur s'est produite lors de la collecte des données du graphique"
msgid "There was an error getting the epic participants."
msgstr "Une erreur s'est produite lors de l'obtention des participants à l'épopée."
@@ -40780,7 +41243,7 @@ msgid "There was an error retrieving the Jira users."
msgstr "Une erreur s'est produite lors de la récupération des utilisateurs Jira."
msgid "There was an error saving your changes."
-msgstr ""
+msgstr "Une erreur s'est produite lors de l'enregistrement de vos modifications."
msgid "There was an error subscribing to this label."
msgstr "Une erreur s’est produite lors de l’abonnement à cette étiquette."
@@ -40792,7 +41255,7 @@ msgid "There was an error syncing the %{replicableType}"
msgstr ""
msgid "There was an error trying to validate your query"
-msgstr ""
+msgstr "Une erreur s'est produite en essayant de valider votre requête"
msgid "There was an error updating the Maintenance Mode Settings"
msgstr "Une erreur s'est produite lors de la mise à jour des Paramètres du Mode Maintenance"
@@ -40825,7 +41288,7 @@ msgid "There was an error while fetching value stream analytics duration data."
msgstr "Une erreur s'est produite lors de la récupération des données de durée de l'analyse des chaînes de valeur."
msgid "There was an error with the reCAPTCHA. Please solve the reCAPTCHA again."
-msgstr ""
+msgstr "Une erreur s'est produite avec le reCAPTCHA. Veuillez le résoudre à nouveau."
msgid "These dates affect how your epics appear in the roadmap. Set a fixed date or one inherited from the milestones assigned to issues in this epic."
msgstr "Ces dates affectent la façon dont vos épopées apparaissent sur la feuille de route. Définissez une date fixe ou une date héritée des jalons attribués aux tickets de cette épopée."
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr "Ces exécuteurs sont partagés par tous les projets de ce groupe."
-msgid "These runners are shared across this GitLab instance."
-msgstr "Ces exécuteurs sont partagés sur cette instance de GitLab."
-
msgid "These runners are specific to this project."
msgstr "Ces exécuteurs sont spécifiques à ce projet."
@@ -40852,7 +41312,7 @@ msgid "These will be sent to %{email} in an attachment once finished."
msgstr ""
msgid "Things to be aware of before transferring:"
-msgstr ""
+msgstr "Les choses à savoir avant de transférer :"
msgid "Third Party Advisory Link"
msgstr "Liens des Annonces d'Offres Tierces"
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr "Ce motif Cron n'est pas valide"
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr "Cette instance de GitLab ne fournit aucun exécuteur partagé pour le moment. Les administrateurs de l’instance peuvent en enregistrer dans l'espace d’administration."
@@ -40948,7 +41411,7 @@ msgid "This change will remove %{strongOpen}ALL%{strongClose} Premium and Ultima
msgstr "Cette modification va supprimer %{strongOpen}TOUTES%{strongClose} les fonctionnalités Premium et Ultimate pour %{strongOpen}TOUS%{strongClose} les clients SaaS et faire échouer le démarrage des tests."
msgid "This chart could not be displayed"
-msgstr ""
+msgstr "Ce graphique n'a pas pu être affiché"
msgid "This clears repository check states for all projects in the database and cannot be undone. Are you sure?"
msgstr "Ceci efface les états de vérification du dépôt pour tous les projets de la base de données et cela ne peut pas être annulé. Êtes-vous sûr(e) ?"
@@ -40969,10 +41432,10 @@ msgid "This commit was signed with a %{strong_open}verified%{strong_close} signa
msgstr "Ce commit a été signé avec une signature %{strong_open}vérifiée%{strong_close} et le courriel du contributeur a bien été vérifié comme correspondant au même utilisateur."
msgid "This commit was signed with a different user's verified signature."
-msgstr ""
+msgstr "Ce commit a été signé avec la signature vérifiée d'un utilisateur différent."
msgid "This commit was signed with a verified signature, but the committer email is not associated with the GPG Key."
-msgstr ""
+msgstr "Ce commit a été signé avec une signature vérifiée, mais l'adresse de courriel du contributeur n'est pas associée à la Clé GPG."
msgid "This commit was signed with an %{strong_open}unverified%{strong_close} signature."
msgstr "Ce commit a été signé avec une signature %{strong_open}non vérifiée%{strong_close}."
@@ -40987,7 +41450,7 @@ msgid "This credential has expired"
msgstr "Ces identifiants ont expiré"
msgid "This deployment is not waiting for approvals."
-msgstr ""
+msgstr "Ce déploiement n'est pas en attente d'approbations."
msgid "This deployment job does not run automatically and must be started manually, but it's older than the latest deployment, and therefore can't run."
msgstr "Cette tâche de déploiement ne s'exécute pas automatiquement et doit être démarrée manuellement, mais elle est antérieure au déploiement le plus récent et ne peut donc pas s'exécuter."
@@ -40996,10 +41459,10 @@ msgid "This deployment job does not run automatically and must be started manual
msgstr ""
msgid "This device has already been registered with us."
-msgstr ""
+msgstr "Cet appareil a déjà été enregistré auprès de nous."
msgid "This device has not been registered with us."
-msgstr ""
+msgstr "Cet appareil n'a pas été enregistré auprès de nous."
msgid "This diff is collapsed."
msgstr "Ce diff est replié."
@@ -41041,31 +41504,28 @@ msgid "This epic already has the maximum number of child epics."
msgstr "Cette épopée a déjà le nombre maximum d'épopées enfants."
msgid "This epic cannot be added. An epic cannot be added to itself."
-msgstr ""
-
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
+msgstr "Cette épopée ne peut pas être ajoutée. Une épopée ne peut pas être ajoutée à elle-même."
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
-msgstr ""
+msgstr "Cette épopée ne peut pas être ajoutée. Une épopée doit appartenir au même groupe ou sous-groupe que son épopée parente."
msgid "This epic cannot be added. It is already an ancestor of the parent epic."
-msgstr ""
+msgstr "Cette épopée ne peut pas être ajoutée. Elle est déjà un ancêtre de l'épopée parente."
msgid "This epic cannot be added. It is already assigned to the parent epic."
-msgstr ""
+msgstr "Cette épopée ne peut pas être ajoutée. Elle est déjà assignée à l'épopée parente."
msgid "This epic cannot be added. One or more epics would exceed the maximum depth (%{max_depth}) from its most distant ancestor."
-msgstr ""
+msgstr "Cette épopée ne peut pas être ajoutée. Une ou plusieurs épopées dépasseraient la profondeur maximale (%{max_depth}) jusqu'à son ancêtre le plus éloigné."
msgid "This epic cannot be added. You don't have access to perform this action."
-msgstr ""
+msgstr "Cette épopée ne peut pas être ajoutée. Vous n'avez pas les droits suffisants pour effectuer cette action."
msgid "This epic does not exist or you don't have sufficient permission."
-msgstr ""
+msgstr "Cette épopée n'existe pas ou vous n'avez pas les permissions suffisantes."
msgid "This epic would exceed maximum number of related epics."
-msgstr ""
+msgstr "Cette épopée dépasserait le nombre maximum d'épopées associées."
msgid "This feature requires local storage to be enabled"
msgstr ""
@@ -41074,7 +41534,7 @@ msgid "This field is required"
msgstr "Ce champ est requis"
msgid "This field is required."
-msgstr ""
+msgstr "Ce champ est requis."
msgid "This file was modified for readability, and can't accept suggestions. Edit it directly."
msgstr "Ce fichier a été modifié pour être plus lisible, et ne peut pas accepter de suggestions. Modifiez-le directement."
@@ -41106,6 +41566,9 @@ msgstr "La suppression de ce groupe a été programmée pour le %{date}"
msgid "This group has no active access tokens."
msgstr "Ce groupe n'a aucun jeton d'accès actif."
+msgid "This group has no projects yet"
+msgstr "Ce groupe n'a pas encore de projets"
+
msgid "This group is linked to a subscription"
msgstr "Ce groupe est lié à un abonnement"
@@ -41122,10 +41585,10 @@ msgid "This incident is already escalated with '%{escalation_policy_name}'."
msgstr "Cet incident est déjà escaladé avec « %{escalation_policy_name} »."
msgid "This invitation was sent to %{mail_to_invite_email}, but you are signed in as %{link_to_current_user} with email %{mail_to_current_user}."
-msgstr ""
+msgstr "Cette invitation a été envoyée à %{mail_to_invite_email}, mais vous êtes connecté en tant que %{link_to_current_user} avec l'adresse de courriel %{mail_to_current_user}."
msgid "This is a \"Ghost User\", created to hold all issues authored by users that have since been deleted. This user cannot be removed."
-msgstr ""
+msgstr "Il s'agit d'un « Utilisateur Fantôme », créé pour conserver tous les tickets rédigés par des utilisateurs qui ont été supprimés depuis. Cet utilisateur ne peut pas être supprimé."
msgid "This is a Jira user."
msgstr "C'est un utilisateur de Jira."
@@ -41137,7 +41600,7 @@ msgid "This is a delayed job to run in %{remainingTime}"
msgstr "Il s’agit d’une tâche différée devant être exécutée dans %{remainingTime}"
msgid "This is a list of devices that have logged into your account. Revoke any sessions that you do not recognize."
-msgstr ""
+msgstr "Il s'agit d'une liste d'appareils qui se sont connectés à votre compte. Révoquez toutes les sessions que vous ne reconnaissez pas."
msgid "This is a private email address %{helpIcon} generated just for you. Anyone who has it can create issues or merge requests as if they were you. If that happens, %{resetLinkStart}reset this token%{resetLinkEnd}."
msgstr "Il s'agit d'une adresse de courriel privée %{helpIcon} générée uniquement pour vous. Quiconque la connait peut créer des tickets ou des demandes de fusion comme s'il s'agissait de vous. Si cela arrive, %{resetLinkStart}réinitialisez ce jeton%{resetLinkEnd}."
@@ -41161,7 +41624,7 @@ msgid "This is the only time the secret is accessible. Copy the secret and store
msgstr "C'est la seule fois où le secret est accessible. Copiez-le et stockez-le en sécurité."
msgid "This is your current session"
-msgstr ""
+msgstr "Ceci est votre session en cours"
msgid "This issue cannot be assigned to a confidential epic because it is public."
msgstr "Ce ticket ne peut pas être assigné à une épopée confidentielle car il est public."
@@ -41194,7 +41657,7 @@ msgid "This job does not have a trace."
msgstr "Cette tâche n’a pas de trace."
msgid "This job does not run automatically and must be started manually, but you do not have access to it."
-msgstr ""
+msgstr "Cette tâche ne s'exécute pas automatiquement et doit être démarrée manuellement, mais vous n'y avez pas accès."
msgid "This job has been canceled"
msgstr "Cette tâche a été annulée"
@@ -41272,7 +41735,7 @@ msgid "This job requires a manual action"
msgstr "Cette tâche nécessite une action manuelle"
msgid "This job requires manual intervention to start. Before starting this job, you can add variables below for last-minute configuration changes."
-msgstr ""
+msgstr "Cette tâche nécessite une intervention manuelle pour démarrer. Avant de la lancer, vous pouvez ajouter des variables ci-dessous pour faire des modifications de configuration de dernière minute."
msgid "This job will automatically run after its timer finishes. Often they are used for incremental roll-out deploys to production environments. When unscheduled it converts into a manual action."
msgstr ""
@@ -41320,22 +41783,25 @@ msgid "This merge request was merged. To apply this suggestion, edit this file d
msgstr "Cette demande de fusion a été fusionnée. Pour appliquer cette suggestion, modifiez ce fichier directement."
msgid "This namespace has already been taken! Please choose another one."
-msgstr ""
+msgstr "Cet espace de noms a déjà été pris ! Veuillez en choisir un autre."
+
+msgid "This namespace has already been taken. Choose a different one."
+msgstr "Cet espace de noms a déjà été pris. Choisissez-en un différent."
msgid "This only applies to repository indexing operations."
msgstr "Cela ne s'applique qu'aux opérations d'indexation des dépôts."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
+msgstr ""
+
msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr "Cette page n’est pas disponible car vous n’êtes pas autorisé à lire des informations à travers de multiples projets."
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
-msgstr "Cette page envoie une charge utile. Retournez à la page des événements pour voir un événement nouvellement créé."
-
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
msgstr "Ce pipeline utilise une configuration CI/CD prédéfinie activée par %{b_open}Auto DevOps.%{b_close}"
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{strongStart}Auto DevOps.%{strongEnd}"
-msgstr ""
+msgstr "Ce pipeline fait usage d'une configuration CI/CD prédéfinie activée par %{strongStart}Auto DevOps.%{strongEnd}"
msgid "This pipeline was triggered by a schedule."
msgstr "Ce pipeline a été déclenché par une planification."
@@ -41380,10 +41846,10 @@ msgid "This project is mirrored from %{link}."
msgstr ""
msgid "This project is not subscribed to any project pipelines."
-msgstr ""
+msgstr "Ce projet n'est abonné à aucun pipeline de projets."
msgid "This project is public. Non-members can guess the Service Desk email address, because it contains the group and project name. %{linkStart}How do I create a custom email address?%{linkEnd}"
-msgstr ""
+msgstr "Ce projet est public. Les personnes n'étant pas membres peuvent deviner l'adresse de courriel du Service d'Assistance car elle contient les noms du groupe et du projet. %{linkStart}Comment puis-je créer une adresse de courriel personnalisée ?%{linkEnd}"
msgid "This project manages its dependencies using %{strong_start}%{manager_name}%{strong_end}"
msgstr "Les dépendances de ce projet sont gérées grâce à %{strong_start}%{manager_name}%{strong_end}"
@@ -41401,7 +41867,7 @@ msgid "This project will be deleted on %{date} since its parent group '%{parent_
msgstr "Ce projet sera supprimé le %{date} car la suppression de son groupe parent « %{parent_group_name} » a été programmée."
msgid "This project's pipeline configuration is located outside this repository"
-msgstr ""
+msgstr "La configuration du pipeline de ce projet est située en dehors de ce dépôt"
msgid "This release was created with a date in the past. Evidence collection at the moment of the release is unavailable."
msgstr "Cette version a été créée avec une date dans le passé. La collecte de preuves au moment de la publication n'est pas disponible."
@@ -41416,7 +41882,7 @@ msgid "This repository has never been checked."
msgstr "Ce dépôt n'a jamais été vérifié."
msgid "This repository is currently empty. A new Auto DevOps pipeline will be created after a new file has been pushed to a branch."
-msgstr ""
+msgstr "Ce dépôt est actuellement vide. Un nouveau pipeline Auto DevOps sera créé lorsqu'un nouveau fichier sera poussé sur une branche."
msgid "This repository was last checked %{last_check_timestamp}. The check %{strong_start}failed.%{strong_end} See the 'repocheck.log' file for error messages."
msgstr "Ce dépôt a été vérifié pour la dernière fois %{last_check_timestamp}. La vérification %{strong_start}a échoué.%{strong_end} Voir le fichier « repocheck.log » pour les messages d'erreur."
@@ -41431,7 +41897,7 @@ msgid "This setting can be overridden in each project."
msgstr "Ce paramètre peut être outrepassé pour chacun des projets."
msgid "This setting has been configured at the instance level and cannot be overridden per group"
-msgstr ""
+msgstr "Ce paramètre a été configuré au niveau de l'instance et ne peut pas être outrepassé par le groupe "
msgid "This setting is allowed for forked projects only"
msgstr "Ce paramètre n'est autorisé que pour les projets divergents"
@@ -41446,7 +41912,7 @@ msgid "This title already exists."
msgstr "Ce titre existe déjà."
msgid "This user cannot be unlocked manually from GitLab"
-msgstr ""
+msgstr "Cet utilisateur ne peut pas être déverrouillé manuellement depuis GitLab"
msgid "This user has an unconfirmed email address (%{email}). You may force a confirmation."
msgstr "Cet utilisateur possède une adresse de courriel (%{email}) non confirmée. Vous pouvez forcer une confirmation."
@@ -41457,9 +41923,6 @@ msgstr "L'adresse de messagerie de cet utilisateur n'est pas confirmée. Vous po
msgid "This user has no active %{accessTokenTypePlural}."
msgstr "Cet utilisateur n'a pas de %{accessTokenTypePlural} actifs."
-msgid "This user has no active %{type}."
-msgstr "Cet utilisateur n'a aucun(e) %{type} actif(ve)."
-
msgid "This user has no identities"
msgstr "Cet utilisateur ou cette utilisatrice n’a aucune identité"
@@ -41476,13 +41939,16 @@ msgid "This user is the author of this %{noteable}."
msgstr "Cet utilisateur est l'auteur de ce(tte) %{noteable}."
msgid "This variable can not be masked."
+msgstr "Cette variable ne peut pas être masquée."
+
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
msgstr ""
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
-msgstr ""
+msgstr "Cela va invalider vos applications enregistrées et vos appareils U2F/WebAuthn."
msgid "This will invalidate your registered applications and U2F devices."
-msgstr ""
+msgstr "Cela va invalider vos applications enregistrées et vos appareils U2F."
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}."
@@ -41491,7 +41957,7 @@ msgid "This will remove the fork relationship between this project and other pro
msgstr ""
msgid "Thread options"
-msgstr ""
+msgstr "Options du fil de discussion"
msgid "Thread to reply to cannot be found"
msgstr ""
@@ -41512,10 +41978,10 @@ msgid "Thu"
msgstr "Jeu"
msgid "Thursday"
-msgstr ""
+msgstr "Jeudi"
msgid "Time"
-msgstr ""
+msgstr "Heure"
msgid "Time (in hours) that users are allowed to skip forced configuration of two-factor authentication."
msgstr "Durée (en heures) pendant laquelle les utilisateurs sont autorisés à ignorer la configuration obligatoire de l’authentification à deux facteurs."
@@ -41596,7 +42062,7 @@ msgid "TimeTracking|Spent"
msgstr "Passé"
msgid "TimeTracking|Time remaining: %{timeRemainingHumanReadable}"
-msgstr ""
+msgstr "Temps restant : %{timeRemainingHumanReadable}"
msgid "Timeago|%s days ago"
msgstr "il y a %s jours"
@@ -41801,7 +42267,7 @@ msgid "Title (required)"
msgstr "Titre (obligatoire)"
msgid "Title:"
-msgstr ""
+msgstr "Titre :"
msgid "Titles and Descriptions"
msgstr "Titres et descriptions"
@@ -41837,7 +42303,7 @@ msgid "To add a custom suffix, set up a Service Desk email address. %{linkStart}
msgstr "Pour ajouter un suffixe personnalisé, configurez une adresse électronique pour le Service d'Assistance. %{linkStart}En savoir plus.%{linkEnd}"
msgid "To add display name, set up a Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
-msgstr ""
+msgstr "Pour ajouter le nom à afficher, configurez l'adresse de courriel du Service d'Assistance. %{linkStart}En savoir plus.%{linkEnd}"
msgid "To add the entry manually, provide the following details to the application on your phone."
msgstr ""
@@ -41848,14 +42314,11 @@ msgstr "Pour approuver cette demande de fusion, veuillez saisir votre mot de pas
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr "Pour confirmer, tapez %{phrase_code}"
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr "Pour connecter des dépôts GitHub, vous pouvez utiliser un %{personal_access_token_link}. Lorsque vous créez votre Jeton d'Accès Personnel, vous devez sélectionner la portée %{code_open}repo%{code_close} pour que nous puissions afficher une liste de vos dépôts publics et privés qui sont disponibles pour connexion."
msgid "To connect GitHub repositories, you first need to authorize GitLab to access the list of your GitHub repositories."
-msgstr ""
+msgstr "Pour connecter les dépôts GitHub, vous devez d'abord autoriser GitLab à accéder à la liste de vos dépôts GitHub."
msgid "To connect GitHub repositories, you first need to authorize GitLab to access the list of your GitHub repositories:"
msgstr "Afin de connecter des dépôts GitHub, vous devez d’abord autoriser GitLab à accéder à la liste de vos dépôts GitHub :"
@@ -41873,7 +42336,7 @@ msgid "To define internal users, first enable new users set to external"
msgstr "Afin de définir les utilisateurs internes, veuillez d’abord activer les nouveaux utilisateurs définis comme externes"
msgid "To edit the pipeline configuration, you must go to the project or external site that hosts the file."
-msgstr ""
+msgstr "Pour modifier la configuration du pipeline, vous devez vous rendre sur le site externe ou sur le projet qui héberge le fichier."
msgid "To enable Registration Features, first enable Service Ping."
msgstr "Pour activer les Fonctionnalités d'Inscription, activez d'abord le Ping de Service."
@@ -41956,6 +42419,9 @@ msgstr "Pour réactiver votre compte, %{gitlab_link_start}connectez-vous à GitL
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr "Pour réactiver votre compte, connectez-vous à GitLab sur %{gitlab_url}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr "Pour résoudre cela, essayez de :"
@@ -41963,7 +42429,7 @@ msgid "To run CI/CD pipelines with JetBrains TeamCity, input the GitLab project
msgstr "Pour exécuter des pipelines CI/CD avec JetBrains TeamCity, entrez les détails du projet GitLab dans les Paramètres de Contrôle de Version du projet TeamCity."
msgid "To see all the user's personal access tokens you must impersonate them first."
-msgstr ""
+msgstr "Pour voir tous les jetons d'accès personnel d'un utilisateur, vous devez d'abord emprunter son identité."
msgid "To see this project's operational details, %{linkStart}upgrade its group plan to Premium%{linkEnd}. You can also remove the project from the dashboard."
msgstr ""
@@ -42002,7 +42468,7 @@ msgid "To view all %{scannedResourcesCount} scanned URLs, %{linkStart}please dow
msgstr "Pour voir toutes les %{scannedResourcesCount} URLs analysées, %{linkStart}veuillez télécharger le fichier CSV%{linkEnd}"
msgid "To view usage, refresh this page in a few minutes."
-msgstr ""
+msgstr "Pour afficher l'utilisation, actualisez cette page dans quelques minutes."
msgid "To widen your search, change or remove filters above"
msgstr "Pour élargir votre recherche, modifiez ou supprimez les filtres ci-dessus"
@@ -42022,9 +42488,33 @@ msgstr "Aujourd’hui"
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr "A ajouté"
+
+msgid "Todos|Alert"
+msgstr "Alerte"
+
+msgid "Todos|Any Action"
+msgstr "Toute Action"
+
+msgid "Todos|Any Type"
+msgstr "Tout Type"
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr "Cherchez-vous des choses à faire ? Jetez un coup d'œil aux %{strongStart}%{openIssuesLinkStart}tickets ouverts%{openIssuesLinkEnd}%{strongEnd}, contribuez à %{strongStart}%{mergeRequestLinkStart}une demande de fusion%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd} ou mentionnez quelqu'un dans un commentaire pour lui assigner automatiquement une nouvelle tâche."
+msgid "Todos|Assigned"
+msgstr "A assigné"
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr "Design"
+
+msgid "Todos|Epic"
+msgstr "Épopée"
+
msgid "Todos|Filter by author"
msgstr "Filtrer par auteur"
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr "Une Liste de Tâches vide, n'est-ce-pas magnifique ?"
+msgid "Todos|Issue"
+msgstr "Ticket"
+
msgid "Todos|It's how you always know what to work on next."
msgstr "C'est ainsi que vous savez toujours sur quoi travailler ensuite."
msgid "Todos|Mark all as done"
msgstr "Tout marquer comme terminé"
+msgid "Todos|Mentioned"
+msgstr "A mentionné"
+
+msgid "Todos|Merge request"
+msgstr "Demande de fusion"
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr "Il n'y a rien sur votre liste de tâches. Beau travail !"
msgid "Todos|Nothing left to do. High five!"
msgstr "Plus rien à faire. Tope là !"
+msgid "Todos|Pipelines"
+msgstr "Pipelines"
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr "Revue demandée"
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr "Annuler Tout marquer comme terminé"
@@ -42070,11 +42581,29 @@ msgstr "Vous avez terminé !"
msgid "Todos|Your To-Do List shows what to work on next"
msgstr "Votre Liste de Tâches montre sur quoi travailler ensuite"
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr "vous-même"
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr "Activer/désactiver GitLab Next"
msgid "Toggle Markdown preview"
-msgstr ""
+msgstr "Afficher/masquer l'aperçu du Markdown"
msgid "Toggle Sidebar"
msgstr "Afficher/masquer la barre latérale"
@@ -42110,13 +42639,13 @@ msgid "Toggle project select"
msgstr ""
msgid "Toggle shortcuts"
-msgstr ""
+msgstr "Activer/désactiver les raccourcis"
msgid "Toggle sidebar"
msgstr "Afficher/masquer la barre latérale"
msgid "Toggle the Performance Bar"
-msgstr ""
+msgstr "Afficher/masquer la Barre de Performance"
msgid "Toggled :%{name}: emoji award."
msgstr ""
@@ -42131,7 +42660,7 @@ msgid "Token Access"
msgstr "Accès au Jeton"
msgid "Token name"
-msgstr ""
+msgstr "Nom du jeton"
msgid "Token valid until revoked"
msgstr "Jeton valide jusqu'à sa révocation"
@@ -42164,7 +42693,7 @@ msgid "TopNav|Explore"
msgstr "Explorer"
msgid "TopNav|Go back"
-msgstr ""
+msgstr "Retour"
msgid "TopNav|Switch to"
msgstr "Basculer vers"
@@ -42173,7 +42702,7 @@ msgid "TopNav|Your dashboards"
msgstr "Vos tableaux de bord"
msgid "Topic %{source_topic} was successfully merged into topic %{target_topic}."
-msgstr ""
+msgstr "Le sujet %{source_topic} a été fusionné avec succès avec le sujet %{target_topic}."
msgid "Topic %{topic_name} was successfully created."
msgstr "Le sujet %{topic_name} a été créé avec succès."
@@ -42185,10 +42714,10 @@ msgid "Topic avatar"
msgstr "Avatar du sujet"
msgid "Topic avatar for %{name} will be removed. This cannot be undone."
-msgstr ""
+msgstr "L'avatar du sujet pour %{name} sera supprimé. Cela ne peut pas être annulé."
msgid "Topic slug (name)"
-msgstr ""
+msgstr "Identifiant « slug » du sujet (nom)"
msgid "Topic title"
msgstr "Titre du sujet"
@@ -42212,7 +42741,7 @@ msgid "Topics could not be merged!"
msgstr "Les sujets n'ont pas pu être fusionnés !"
msgid "Total"
-msgstr ""
+msgstr "Total"
msgid "Total Contributions"
msgstr "Total des contributions"
@@ -42220,9 +42749,6 @@ msgstr "Total des contributions"
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr "Nombre de cœurs (CPUs)"
@@ -42239,7 +42765,7 @@ msgid "Total users"
msgstr "Nombre total d'utilisateurs"
msgid "Total weight"
-msgstr ""
+msgstr "Poids total"
msgid "Total: %{total}"
msgstr "Total : %{total}"
@@ -42269,7 +42795,7 @@ msgid "Training mode"
msgstr "Mode formation"
msgid "Transfer"
-msgstr ""
+msgstr "Transférer"
msgid "Transfer group to another parent group."
msgstr "Transférer le groupe à un autre groupe parent."
@@ -42278,7 +42804,7 @@ msgid "Transfer ownership"
msgstr "Transfert de propriété"
msgid "Transfer project"
-msgstr ""
+msgstr "Transférer le projet"
msgid "Transfer your project into another namespace. %{link_start}Learn more.%{link_end}"
msgstr "Transférer votre projet dans un autre espace de noms. %{link_start}En savoir plus.%{link_end}"
@@ -42287,49 +42813,49 @@ msgid "TransferGroup|Cannot transfer group to one of its subgroup."
msgstr "Impossible de transférer le groupe vers un de ses sous-groupes."
msgid "TransferGroup|Cannot update the path because there are projects under this group that contain Docker images in their Container Registry. Please remove the images from your projects first and try again."
-msgstr ""
+msgstr "Impossible de mettre à jour le chemin d'accès car il y a des projets sous ce groupe qui contiennent des images Docker dans leurs Registres de Conteneurs. Veuillez d'abord supprimer les images de vos projets et réessayer."
msgid "TransferGroup|Database is not supported."
-msgstr ""
+msgstr "La base de données n'est pas prise en charge."
msgid "TransferGroup|Group contains contacts/organizations and you don't have enough permissions to move them to the new root group."
msgstr "Le groupe contient des contacts/organisations et vous n'avez pas les permissions suffisantes pour les déplacer vers le nouveau groupe racine."
msgid "TransferGroup|Group contains projects with NPM packages."
-msgstr ""
+msgstr "Le groupe contient des projets avec des paquets NPM."
msgid "TransferGroup|Group is already a root group."
-msgstr ""
+msgstr "Le groupe est déjà un groupe racine."
msgid "TransferGroup|Group is already associated to the parent group."
-msgstr ""
+msgstr "Le groupe est déjà associé au groupe parent."
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."
msgid "TransferGroup|Transfer failed: %{error_message}"
-msgstr ""
+msgstr "Le transfert a échoué : %{error_message}"
msgid "TransferGroup|You don't have enough permissions."
-msgstr ""
+msgstr "Vous n'avez pas les autorisations suffisantes."
msgid "TransferProject|Cannot move project"
-msgstr ""
+msgstr "Impossible de déplacer le projet"
msgid "TransferProject|Please select a new namespace for your project."
-msgstr ""
+msgstr "Veuillez sélectionner un nouvel espace de noms pour votre projet."
msgid "TransferProject|Project cannot be transferred, because tags are present in its container registry"
-msgstr ""
+msgstr "Le projet ne peut pas être transféré car des étiquettes sont présentes dans son registre de conteneur"
msgid "TransferProject|Project is already in this namespace."
msgstr "Le projet est déjà dans cet espace de noms."
msgid "TransferProject|Project with same name or path in target namespace already exists"
-msgstr ""
+msgstr "Un projet avec le même nom ou le même chemin dans l'espace de noms cible existe déjà"
msgid "TransferProject|Root namespace can't be updated if project has NPM packages"
-msgstr ""
+msgstr "L'espace de noms racine ne peut pas être mis à jour si le projet a des paquets NPM"
msgid "TransferProject|You don't have permission to transfer projects into that namespace."
msgstr "Vous n'avez pas la permission de transférer des projets dans cet espace de noms."
@@ -42385,7 +42911,7 @@ msgid "Trial|Allowed characters: +, 0-9, -, and spaces."
msgstr "Caractères autorisés : +, 0-9, - et espaces."
msgid "Trial|Continue"
-msgstr ""
+msgstr "Continuez"
msgid "Trial|Dismiss"
msgstr ""
@@ -42394,7 +42920,7 @@ msgid "Trial|Your GitLab Ultimate trial lasts for 30 days, but you can keep your
msgstr "Votre essai de Gitlab Ultimate a une durée de 30 jours mais vous pouvez conserver votre compte gratuit Gitlab sans limite de temps. Nous avons seulement besoin de quelques informations supplémentaires pour activer votre période d'essai."
msgid "Trigger"
-msgstr ""
+msgstr "Déclencheur"
msgid "Trigger a pipeline for a branch or tag by generating a trigger token and using it with an API call. The token impersonates a user's project access and permissions."
msgstr "Déclencher un pipeline pour une branche ou une étiquette en générant un jeton de déclenchement et en l'utilisant avec un appel d'API. Un emprunt d'identité donnera au jeton les permissions et l'accès au projet de l'utilisateur."
@@ -42418,7 +42944,7 @@ msgid "Trigger pipelines when branches or tags are updated in the upstream repos
msgstr "Déclencher les pipelines lorsque les branches ou les étiquettes sont mises à jour sur le dépôt amont. Selon l’activité qu'il y a sur ce dernier, cela peut considérablement augmenter la charge de vos exécuteurs CI. N’activez cette option que si vous savez qu’ils peuvent la supporter. %{strong_start}La CI sera lancée avec les identifiants ci-dessus.%{strong_end} %{link_start}En savoir plus.%{link_end}"
msgid "Trigger removed."
-msgstr ""
+msgstr "Déclencheur supprimé."
msgid "Trigger repository check"
msgstr "Déclencher la vérification du dépôt"
@@ -42427,16 +42953,16 @@ msgid "Trigger this manual action"
msgstr "Déclencher cette action manuelle"
msgid "Trigger token:"
-msgstr ""
+msgstr "Jeton de déclenchement :"
msgid "Trigger variables:"
msgstr ""
msgid "Trigger was created successfully."
-msgstr ""
+msgstr "Le déclencheur a été créé avec succès."
msgid "Trigger was successfully updated."
-msgstr ""
+msgstr "Le déclencheur a été mis à jour avec succès."
msgid "Triggerer"
msgstr ""
@@ -42451,13 +42977,13 @@ 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 "Les applications de confiance sont automatiquement autorisées sur le flux GitLab OAuth. Il est fortement recommandé pour la sécurité des utilisateurs que les applications approuvées aient le paramètre confidentiel défini sur vrai."
msgid "Try again"
msgstr "Veuillez réessayer"
msgid "Try again?"
-msgstr ""
+msgstr "Réessayer ?"
msgid "Try all GitLab features for free for 30 days. No credit card required."
msgstr "Essayez toutes les fonctionnalités de GitLab gratuitement pendant 30 jours. Aucune carte de crédit n'est requise."
@@ -42493,13 +43019,13 @@ msgid "Trying to communicate with your device. Plug it in (if needed) and press
msgstr "Tentative de communication avec votre appareil. Branchez-le (si nécessaire) et appuyez sur le bouton de l'appareil maintenant."
msgid "Trying to communicate with your device. Plug it in (if you haven't already) and press the button on the device now."
-msgstr ""
+msgstr "Tentative en cours pour communiquer avec votre appareil. Branchez-le (si vous ne l'avez pas déjà fait) et appuyez sur le bouton de l'appareil maintenant."
msgid "Tue"
msgstr "Mar"
msgid "Tuesday"
-msgstr ""
+msgstr "Mardi"
msgid "Turn off"
msgstr "Désactiver"
@@ -42514,16 +43040,16 @@ msgid "Twitter:"
msgstr "Twitter :"
msgid "Two-Factor Authentication"
-msgstr ""
+msgstr "Authentification à Deux Facteurs"
msgid "Two-Factor Authentication code"
msgstr "Code d'authentification à deux facteurs"
msgid "Two-factor Authentication"
-msgstr ""
+msgstr "Authentification à Deux Facteurs"
msgid "Two-factor Authentication Recovery codes"
-msgstr ""
+msgstr "Codes de Récupération pour l'Authentification à Deux Facteurs"
msgid "Two-factor Authentication:"
msgstr "Authentification à deux facteurs :"
@@ -42543,6 +43069,12 @@ msgstr "L'authentification à deux facteurs a été désactivée pour cet utilis
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr "L'authentification à deux facteurs a été désactivée pour votre compte GitLab."
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr "L'authentification à deux facteurs a été désactivée avec succès pour %{user_email} !"
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr "L'authentification à deux facteurs a été désactivée avec succès pour %{username} !"
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr "L'authentification à deux facteurs a été désactivée avec succès !"
@@ -42559,13 +43091,13 @@ msgid "Type to search"
msgstr "Tapez pour rechercher"
msgid "U2F Devices (%{length})"
-msgstr ""
+msgstr "Appareils U2F (%{length})"
msgid "U2F only works with HTTPS-enabled websites. Contact your administrator for more details."
-msgstr ""
+msgstr "U2F ne fonctionne qu'avec les sites Web ayant activé HTTPS. Contactez votre administrateur pour plus de détails."
msgid "URL"
-msgstr ""
+msgstr "URL"
msgid "URL cannot be blank"
msgstr "L'URL ne peut pas être vide"
@@ -42619,22 +43151,22 @@ msgid "UTC"
msgstr "UTC"
msgid "Unable to apply suggestions to a deleted line."
-msgstr ""
+msgstr "Impossible d'appliquer les suggestions à une ligne supprimée."
msgid "Unable to build Slack link."
msgstr ""
msgid "Unable to collect CPU info"
-msgstr ""
+msgstr "Impossible de collecter les informations sur le CPU"
msgid "Unable to collect memory info"
-msgstr ""
+msgstr "Impossible de collecter les informations sur la mémoire"
msgid "Unable to connect to Prometheus server"
-msgstr ""
+msgstr "Impossible de se connecter au serveur Prometheus"
msgid "Unable to connect to server: %{error}"
-msgstr ""
+msgstr "Impossible de se connecter au serveur : %{error}"
msgid "Unable to connect to the Jira instance. Please check your Jira integration configuration."
msgstr "Impossible de se connecter à l'instance Jira. Veuillez vérifier votre configuration d'intégration Jira."
@@ -42658,7 +43190,7 @@ msgid "Unable to fully load the default commit message. You can still apply this
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é."
msgid "Unable to generate new instance ID"
-msgstr ""
+msgstr "Impossible de générer un nouvel ID d'instance"
msgid "Unable to load commits. Try again later."
msgstr "Impossible de charger les commits. Réessayez plus tard."
@@ -42667,7 +43199,7 @@ msgid "Unable to load file contents. Try again later."
msgstr "Impossible de charger le contenu du fichier. Réessayez plus tard."
msgid "Unable to load refs"
-msgstr ""
+msgstr "Impossible de charger les références"
msgid "Unable to load the diff"
msgstr "Impossible de charger le diff"
@@ -42688,10 +43220,10 @@ msgid "Unable to save iteration. Please try again"
msgstr "Impossible d'enregistrer l'itération. Veuillez réessayer"
msgid "Unable to save your changes. Please try again."
-msgstr ""
+msgstr "Impossible d'enregistrer vos modifications. Veuillez réessayer."
msgid "Unable to save your preference"
-msgstr ""
+msgstr "Impossible d'enregistrer vos préférences."
msgid "Unable to schedule a pipeline to run immediately"
msgstr ""
@@ -42709,10 +43241,10 @@ msgid "Unable to update this epic at this time."
msgstr "Impossible de mettre à jour cette épopée pour le moment."
msgid "Unable to update this issue at this time."
-msgstr ""
+msgstr "Impossible de mettre à jour ce ticket pour le moment."
msgid "Unable to verify the user"
-msgstr ""
+msgstr "Impossible de vérifier l'utilisateur"
msgid "Unapprove a merge request"
msgstr "Désapprouver une demande de fusion"
@@ -42745,7 +43277,7 @@ msgid "Unauthenticated web rate limit period in seconds"
msgstr "Durée de la limitation de fréquence des requêtes Web non authentifiées en secondes"
msgid "Unban"
-msgstr ""
+msgstr "Gracier"
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 ?"
@@ -42784,7 +43316,7 @@ msgid "Unknown Error"
msgstr ""
msgid "Unknown encryption strategy: %{encrypted_strategy}!"
-msgstr ""
+msgstr "Stratégie de chiffrement inconnue : %{encrypted_strategy} !"
msgid "Unknown format"
msgstr ""
@@ -42799,7 +43331,7 @@ msgid "Unless otherwise agreed to in writing with GitLab, by clicking \"Upload L
msgstr "Sauf accord contraire écrit avec GitLab, en cliquant sur « Téléverser la licence », vous acceptez que votre utilisation du logiciel GitLab soit soumise aux %{eula_link_start}Conditions Générales d'Utilisation%{eula_link_end}."
msgid "Unlimited"
-msgstr ""
+msgstr "Illimité"
msgid "Unlink"
msgstr "Dissocier"
@@ -42817,7 +43349,7 @@ msgid "Unlock more features with GitLab Ultimate"
msgstr ""
msgid "Unlock the discussion"
-msgstr ""
+msgstr "Déverrouiller la discussion"
msgid "Unlock this %{issuableDisplayName}? %{strongStart}Everyone%{strongEnd} will be able to comment."
msgstr "Déverrouiller ce %{issuableDisplayName} ? %{strongStart}Tout le monde%{strongEnd} sera en mesure de mettre un commentaire."
@@ -42829,7 +43361,7 @@ msgid "Unlocked the discussion."
msgstr ""
msgid "Unlocks the discussion."
-msgstr ""
+msgstr "Déverrouille la discussion."
msgid "Unreachable"
msgstr "Injoignable"
@@ -42856,7 +43388,7 @@ msgid "Unstar"
msgstr "Supprimer des favoris"
msgid "Unstarted"
-msgstr ""
+msgstr "Non commencés"
msgid "Unsubscribe"
msgstr "Se désabonner"
@@ -42877,7 +43409,7 @@ msgid "Unsubscribes from this %{quick_action_target}."
msgstr ""
msgid "Unsupported sort value."
-msgstr ""
+msgstr "Valeur de tri non prise en charge."
msgid "Unsupported todo type passed. Supported todo types are: %{todo_types}"
msgstr "Type « À faire » non pris en charge. Les types « À faire » supportés sont : %{todo_types}"
@@ -42898,7 +43430,7 @@ msgid "Upcoming"
msgstr "À venir"
msgid "Upcoming Release"
-msgstr ""
+msgstr "Version à venir"
msgid "Update"
msgstr "Mettre à jour"
@@ -42919,10 +43451,10 @@ msgid "Update appearance settings"
msgstr "Mettre à jour les paramètres d'apparence"
msgid "Update approval rule"
-msgstr ""
+msgstr "Mettre à jour la règle d'approbation"
msgid "Update approvers"
-msgstr ""
+msgstr "Mettre à jour les approbateurs"
msgid "Update broadcast message"
msgstr "Mettre à jour le message de diffusion"
@@ -42931,7 +43463,7 @@ msgid "Update failed"
msgstr ""
msgid "Update it"
-msgstr ""
+msgstr "Mettez-la à jour"
msgid "Update milestone"
msgstr "Mettre à jour le jalon"
@@ -42940,10 +43472,10 @@ msgid "Update now"
msgstr "Mettre à jour maintenant"
msgid "Update username"
-msgstr ""
+msgstr "Mettre à jour le nom d'utilisateur"
msgid "Update variable"
-msgstr ""
+msgstr "Mettre à jour la variable"
msgid "Update your bookmarked URLs as filtered/sorted branches URL has been changed."
msgstr ""
@@ -42952,16 +43484,16 @@ 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, topics, description, and avatar."
-msgstr ""
+msgstr "Mettre à jour le nom, les sujets, la description et l'avatar de votre projet."
msgid "UpdateProject|Cannot rename project because it contains container registry tags!"
msgstr ""
msgid "UpdateProject|Could not set the default branch"
-msgstr ""
+msgstr "Impossible de définir la branche par défaut"
msgid "UpdateProject|New visibility level not allowed!"
-msgstr ""
+msgstr "Nouveau niveau de visibilité non autorisé !"
msgid "UpdateProject|Project could not be updated!"
msgstr "Le projet n'a pas pu être mis à jour!"
@@ -42997,7 +43529,7 @@ msgid "Upload %{file_name} file"
msgstr "Téléversez le fichier %{file_name}"
msgid "Upload CSV file"
-msgstr ""
+msgstr "Téléverser un fichier CSV"
msgid "Upload File"
msgstr "Téléverser un Fichier"
@@ -43030,7 +43562,7 @@ msgid "Uploaded date"
msgstr "Date de téléversement"
msgid "Uploading changes to terminal"
-msgstr ""
+msgstr "Téléversement des modifications vers le terminal"
msgid "Uploading..."
msgstr "Téléversement en cours..."
@@ -43047,8 +43579,14 @@ msgstr "Tendances d'Utilisation"
msgid "Usage statistics"
msgstr "Statistiques d’utilisation"
+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."
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr "Cette statistique de stockage au niveau du projet n'inclut pas les économies réalisées par la déduplication à l'échelle du site et n'est pas utilisée pour calculer le stockage total de l'espace de noms."
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
-msgstr ""
+msgstr "Les %{help_link_start}exécuteurs partagés%{help_link_end} sont désactivés. Aucune limite d'utilisation du pipeline n'est donc définie"
msgid "UsageQuota|%{linkStart}Shared runners%{linkEnd} are disabled, so there are no limits set on pipeline usage"
msgstr "Les %{linkStart}Exécuteurs Partagés%{linkEnd} sont désactivés. Aucune limite d'utilisation du pipeline n'est donc définie"
@@ -43063,7 +43601,7 @@ msgid "UsageQuota|%{storage_limit_link_start}A namespace storage limit%{link_end
msgstr "%{storage_limit_link_start}Une limite de stockage d'espace de noms%{link_end} sera bientôt imposée pour l'espace de noms %{strong_start}%{namespace_name}%{strong_end}. %{extra_message}"
msgid "UsageQuota|Artifacts"
-msgstr ""
+msgstr "Artéfacts"
msgid "UsageQuota|Artifacts is a sum of build and pipeline artifacts."
msgstr ""
@@ -43072,7 +43610,7 @@ msgid "UsageQuota|Audio samples, videos, datasets, and graphics."
msgstr "Échantillons sonores, vidéos, jeux de données et graphismes."
msgid "UsageQuota|Buy additional minutes"
-msgstr ""
+msgstr "Acheter des minutes supplémentaires"
msgid "UsageQuota|Buy storage"
msgstr "Acheter du stockage"
@@ -43084,10 +43622,10 @@ msgid "UsageQuota|CI minutes usage by project"
msgstr "Utilisation des minutes CI par projet"
msgid "UsageQuota|CI/CD minutes usage"
-msgstr ""
+msgstr "Utilisation des minutes CI/CD"
msgid "UsageQuota|CI/CD minutes usage since %{timeElapsed}"
-msgstr ""
+msgstr "Utilisation des minutes CI/CD depuis le %{timeElapsed}"
msgid "UsageQuota|CI/CD minutes usage since %{usageSince}"
msgstr "Utilisation des minutes CI/CD depuis %{usageSince}"
@@ -43117,7 +43655,7 @@ msgid "UsageQuota|Gitlab-integrated Docker Container Registry for storing Docker
msgstr "Registre de Conteneurs Docker intégré à GitLab pour le stockage d'Images Docker."
msgid "UsageQuota|Gitlab-integrated Docker Container Registry for storing Docker Images. %{linkStart}More information%{linkEnd}"
-msgstr ""
+msgstr "Registre de Conteneurs Docker intégré à GitLab pour le stockage d'Images Docker. %{linkStart}En savoir plus%{linkEnd}"
msgid "UsageQuota|Group settings &gt; Usage quotas"
msgstr "Paramètres de groupe &gt; Quotas d'utilisation"
@@ -43141,7 +43679,7 @@ msgid "UsageQuota|Learn more about usage quotas."
msgstr "En savoir plus sur les quotas d'utilisation."
msgid "UsageQuota|Local proxy used for frequently-accessed upstream Docker images. %{linkStart}More information%{linkEnd}"
-msgstr ""
+msgstr "Proxy local utilisé pour les images Docker en amont auxquelles les accès sont fréquents. %{linkStart}En savoir plus%{linkEnd}"
msgid "UsageQuota|Namespace storage used"
msgstr ""
@@ -43149,8 +43687,11 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr "Aucune donnée d'utilisation des minutes CI disponible."
+msgid "UsageQuota|No projects to display."
+msgstr "Aucun projet à afficher."
+
msgid "UsageQuota|Packages"
-msgstr ""
+msgstr "Paquets"
msgid "UsageQuota|Pending Members"
msgstr "Membres en attente"
@@ -43159,7 +43700,7 @@ msgid "UsageQuota|Pipeline artifacts and job artifacts, created with CI/CD."
msgstr "Artéfacts de pipeline et de tâches créés par CI/CD."
msgid "UsageQuota|Pipelines"
-msgstr ""
+msgstr "Pipelines"
msgid "UsageQuota|Purchase more storage"
msgstr "Acheter plus de stockage"
@@ -43168,16 +43709,19 @@ msgid "UsageQuota|Purchased storage"
msgstr "Stockage acheté"
msgid "UsageQuota|Purchased storage available"
-msgstr ""
+msgstr "Stockage acheté disponible"
msgid "UsageQuota|Purchased storage used"
msgstr "Stockage acheté utilisé"
msgid "UsageQuota|Recalculate repository usage"
-msgstr ""
+msgstr "Recalculer l'utilisation du dépôt"
msgid "UsageQuota|Repository"
-msgstr ""
+msgstr "Dépôt"
+
+msgid "UsageQuota|Search"
+msgstr "Rechercher"
msgid "UsageQuota|Seats"
msgstr "Sièges"
@@ -43201,7 +43745,7 @@ msgid "UsageQuota|Something went wrong while loading usage details"
msgstr "Une erreur s'est produite lors du chargement des détails d'utilisation"
msgid "UsageQuota|Storage"
-msgstr ""
+msgstr "Stockage"
msgid "UsageQuota|Storage type"
msgstr "Type de stockage"
@@ -43237,7 +43781,7 @@ msgid "UsageQuota|This namespace contains locked projects"
msgstr "Cet espace de noms contient des projets verrouillés"
msgid "UsageQuota|This namespace has no projects which use shared runners"
-msgstr ""
+msgstr "Cet espace de noms n'a aucun projet utilisant des exécuteurs partagés"
msgid "UsageQuota|This namespace has no projects which used shared runners in the current period"
msgstr "Aucun projet de cet espace de noms n'a utilisé d'exécuteurs partagés sur la période actuelle"
@@ -43252,25 +43796,25 @@ msgid "UsageQuota|Total namespace storage used"
msgstr "Quantité totale de stockage utilisé pour l'espace de noms"
msgid "UsageQuota|Unlimited"
-msgstr ""
+msgstr "Illimité"
msgid "UsageQuota|Uploads"
msgstr "Téléversements"
msgid "UsageQuota|Usage"
-msgstr ""
+msgstr "Utilisation"
msgid "UsageQuota|Usage Quotas"
-msgstr ""
+msgstr "Quotas d'utilisation"
msgid "UsageQuota|Usage breakdown"
msgstr "Répartition de l'utilisation"
msgid "UsageQuota|Usage by month"
-msgstr ""
+msgstr "Utilisation par mois"
msgid "UsageQuota|Usage by project"
-msgstr ""
+msgstr "Utilisation par projet"
msgid "UsageQuota|Usage of group resources across the projects in the %{strong_start}%{group_name}%{strong_end} group"
msgstr ""
@@ -43291,7 +43835,7 @@ msgid "UsageQuota|When you purchase additional storage, we automatically unlock
msgstr "Dès le moment où vous achetez de l'espace de stockage supplémentaire, nous débloquons automatiquement les projets qui ont été verrouillés lorsque vous avez atteint la limite de %{actualRepositorySizeLimit}."
msgid "UsageQuota|Wiki"
-msgstr ""
+msgstr "Wiki"
msgid "UsageQuota|Wiki content."
msgstr "Contenu Wiki."
@@ -43357,7 +43901,7 @@ msgid "UsageTrends|Pipelines succeeded"
msgstr "Pipelines ayant réussi"
msgid "UsageTrends|Pipelines total"
-msgstr ""
+msgstr "Nombre total de pipelines"
msgid "UsageTrends|Projects"
msgstr "Projets"
@@ -43387,13 +43931,13 @@ msgid "UsageTrends|There was an error fetching the successful pipelines. Please
msgstr "Une erreur s'est produite lors de la récupération des pipelines réussis. Veuillez réessayer."
msgid "UsageTrends|There was an error fetching the total pipelines. Please try again."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération de la totalité des pipelines. Veuillez réessayer."
msgid "UsageTrends|Total groups"
-msgstr ""
+msgstr "Nombre total de groupes"
msgid "UsageTrends|Total projects"
-msgstr ""
+msgstr "Nombre total de projets"
msgid "UsageTrends|Total projects & groups"
msgstr "Nombre total de groupes et projets"
@@ -43405,13 +43949,13 @@ msgid "Use %{code_start}::%{code_end} to create a %{link_start}scoped label set%
msgstr ""
msgid "Use .gitlab-ci.yml"
-msgstr ""
+msgstr "Utiliser .gitlab-ci.yml"
msgid "Use GitLab Runner in AWS"
msgstr "Utiliser GitLab Runner sur AWS"
msgid "Use Secure Files to store files used by your pipelines such as Android keystores, or Apple provisioning profiles and signing certificates."
-msgstr ""
+msgstr "Utilisez des Fichiers Sécurisés pour stocker les fichiers utilisés par vos pipelines, tels que les magasins de clés Android, ou les profils d'approvisionnement Apple et les certificats de signature."
msgid "Use a one-time password authenticator on your mobile device or computer to enable two-factor authentication (2FA)."
msgstr "Utilisez un générateur de mot de passe à usage unique sur votre appareil mobile ou votre ordinateur pour activer l'authentification à deux facteurs (A2F)."
@@ -43426,7 +43970,7 @@ msgid "Use banners and notifications to notify your users about scheduled mainte
msgstr "Utilisez des bannières et des notifications pour informer vos utilisateurs des maintenances planifiées, des mises à jour récentes, etc."
msgid "Use cURL"
-msgstr ""
+msgstr "Utiliser cURL"
msgid "Use custom color #FF0000"
msgstr ""
@@ -43435,7 +43979,7 @@ msgid "Use double quotes for multiple keywords, such as %{code_open}\"your searc
msgstr "Utilisez des guillemets doubles s'il y a plusieurs mots-clés, comme %{code_open}\"votre recherche\"%{code_close}"
msgid "Use hashed storage"
-msgstr ""
+msgstr "Utiliser le stockage haché"
msgid "Use hashed storage paths for newly created and renamed repositories. Always enabled since 13.0. %{link_start}Learn more.%{link_end}"
msgstr "Utiliser des chemins de stockage hachés pour les dépôts renommés ou nouvellement créés. Toujours activé depuis la version 13.0. %{link_start}En savoir plus.%{link_end}"
@@ -43509,7 +44053,7 @@ msgid "Used programming language"
msgstr "Langage de programmation utilisé"
msgid "Used to help configure your identity provider"
-msgstr ""
+msgstr "Utilisé pour vous aider à configurer votre fournisseur d'identité"
msgid "User"
msgstr "Utilisateur"
@@ -43527,7 +44071,7 @@ msgid "User ID"
msgstr "ID utilisateur"
msgid "User OAuth applications"
-msgstr ""
+msgstr "Applications OAuth de l'utilisateur"
msgid "User Settings"
msgstr "Paramètres de l’utilisateur"
@@ -43548,13 +44092,13 @@ msgid "User does not have a pending request"
msgstr "L'utilisateur n'a pas de requête en attente"
msgid "User identity was successfully created."
-msgstr ""
+msgstr "L'identité de l'utilisateur a été créée avec succès."
msgid "User identity was successfully removed."
-msgstr ""
+msgstr "L'identité de l'utilisateur a été supprimée avec succès."
msgid "User identity was successfully updated."
-msgstr ""
+msgstr "L'identité de l'utilisateur a été mise à jour avec succès."
msgid "User is blocked"
msgstr "L'utilisateur est bloqué"
@@ -43563,19 +44107,19 @@ msgid "User is not allowed to resolve thread"
msgstr ""
msgid "User key"
-msgstr ""
+msgstr "Clé d'utilisateur"
msgid "User key was successfully removed."
-msgstr ""
+msgstr "La clé d'utilisateur a été supprimée avec succès."
msgid "User list %{name} will be removed. Are you sure?"
-msgstr ""
+msgstr "La liste d'utilisateurs %{name} sera supprimée. Êtes-vous sûr(e) ?"
msgid "User map"
msgstr "Correspondance entre utilisateurs"
msgid "User pipeline minutes were successfully reset."
-msgstr ""
+msgstr "Les minutes de pipeline de l'utilisateur ont été réinitialisées avec succès."
msgid "User restrictions"
msgstr ""
@@ -43584,7 +44128,7 @@ msgid "User settings"
msgstr "Paramètres utilisateur"
msgid "User was successfully created."
-msgstr ""
+msgstr "L’utilisateur a été créé avec succès."
msgid "User was successfully removed from group and any subgroups and projects."
msgstr "L'utilisateur a été supprimé du groupe et de ses sous-groupes et projets avec succès."
@@ -43593,13 +44137,13 @@ msgid "User was successfully removed from group."
msgstr "L'utilisateur a été supprimé du groupe avec succès."
msgid "User was successfully removed from project."
-msgstr ""
+msgstr "L'utilisateur a été supprimé du projet avec succès."
msgid "User was successfully unbanned."
-msgstr ""
+msgstr "L'utilisateur a été gracié avec succès."
msgid "User was successfully updated."
-msgstr ""
+msgstr "L’utilisateur a été mis à jour avec succès."
msgid "User-based escalation rules must have a user with access to the project"
msgstr "Les règles d'escalade basées sur l'utilisateur doivent avoir un utilisateur ayant un accès au projet"
@@ -43686,7 +44230,7 @@ msgid "UserList|Delete %{name}?"
msgstr "Supprimer %{name} ?"
msgid "UserList|created %{timeago}"
-msgstr ""
+msgstr "créée %{timeago}"
msgid "UserProfile|(Busy)"
msgstr "(Occupé)"
@@ -43725,16 +44269,16 @@ msgid "UserProfile|Groups"
msgstr "Groupes"
msgid "UserProfile|Groups are the best way to manage projects and members."
-msgstr ""
+msgstr "Les groupes sont le meilleur moyen de gérer des projets et des membres."
msgid "UserProfile|Join or create a group to start contributing by commenting on issues or submitting merge requests!"
-msgstr ""
+msgstr "Rejoignez ou créez un groupe pour commencer à contribuer en commentant des tickets ou en soumettant des demandes de fusion !"
msgid "UserProfile|Most Recent Activity"
msgstr "Activité la plus récente"
msgid "UserProfile|No snippets found."
-msgstr ""
+msgstr "Aucun extrait trouvé."
msgid "UserProfile|Overview"
msgstr "Vue d’ensemble"
@@ -43755,13 +44299,13 @@ msgid "UserProfile|Snippets"
msgstr "Fragments de code"
msgid "UserProfile|Snippets in GitLab can either be private, internal, or public."
-msgstr ""
+msgstr "Les extraits dans GitLab peuvent être soit privés, internes ou publics."
msgid "UserProfile|Star projects to track their progress and show your appreciation."
msgstr ""
msgid "UserProfile|Starred projects"
-msgstr ""
+msgstr "Projets favoris"
msgid "UserProfile|Subscribe"
msgstr "S’abonner"
@@ -43776,13 +44320,13 @@ msgid "UserProfile|This user has a private profile"
msgstr "Cet utilisateur a un profil privé"
msgid "UserProfile|This user hasn't contributed to any projects"
-msgstr ""
+msgstr "Cet utilisateur n’a contribué à aucun projet"
msgid "UserProfile|This user hasn't starred any projects"
-msgstr ""
+msgstr "Cet utilisateur n'a mis aucun projet en favoris"
msgid "UserProfile|This user is blocked"
-msgstr ""
+msgstr "Cet utilisateur est bloqué"
msgid "UserProfile|This user isn't following other users."
msgstr "Cet utilisateur ne suit pas d'autres utilisateurs."
@@ -43809,13 +44353,13 @@ msgid "UserProfile|You do not have any followers."
msgstr "Vous n'avez aucun abonné."
msgid "UserProfile|You haven't created any personal projects."
-msgstr ""
+msgstr "Vous n'avez créé aucun projet personnel."
msgid "UserProfile|You haven't created any snippets."
-msgstr ""
+msgstr "Vous n'avez pas créé d'extrait."
msgid "UserProfile|Your projects can be available publicly, internally, or privately, at your choice."
-msgstr ""
+msgstr "Vos projets peuvent être disponibles publiquement, en interne ou en privé, selon votre choix."
msgid "UserProfile|at"
msgstr "chez"
@@ -43827,16 +44371,16 @@ msgid "Username"
msgstr "Nom d’utilisateur"
msgid "Username (optional)"
-msgstr ""
+msgstr "Nom d'utilisateur (facultatif)"
msgid "Username is already taken."
-msgstr ""
+msgstr "Le nom d'utilisateur est déjà pris."
msgid "Username is available."
-msgstr ""
+msgstr "Le nom d'utilisateur est disponible."
msgid "Username or email"
-msgstr ""
+msgstr "Nom d'utilisateur ou adresse de courriel"
msgid "Username:"
msgstr "Nom d’utilisateur :"
@@ -43875,7 +44419,7 @@ msgid "Users over License"
msgstr "Utilisateurs hors Licence"
msgid "Users requesting access to"
-msgstr ""
+msgstr "Utilisateurs demandant l'accès à"
msgid "Users to exclude from the rate limit"
msgstr "Utilisateurs à exclure de la limitation de fréquence"
@@ -43899,10 +44443,10 @@ msgid "UsersSelect|Unassigned"
msgstr "Non assigné"
msgid "User|Data Analyst"
-msgstr ""
+msgstr "Analyste de Données"
msgid "User|Development Team Lead"
-msgstr ""
+msgstr "Chef d'Équipe Développement"
msgid "User|Devops Engineer"
msgstr "Ingénieur Devops"
@@ -43911,16 +44455,16 @@ msgid "User|Other"
msgstr "Autre"
msgid "User|Product Designer"
-msgstr ""
+msgstr "Concepteur de Produit"
msgid "User|Product Manager"
-msgstr ""
+msgstr "Chef de Produit"
msgid "User|Security Analyst"
-msgstr ""
+msgstr "Analyste Sécurité"
msgid "User|Software Developer"
-msgstr ""
+msgstr "Développeur Logiciel"
msgid "User|Systems Administrator"
msgstr "Administrateur Système"
@@ -43941,7 +44485,7 @@ msgid "Valid From"
msgstr ""
msgid "Validate"
-msgstr ""
+msgstr "Valider"
msgid "Validate your GitLab CI configuration"
msgstr "Valider votre configuration GitLab CI"
@@ -43959,10 +44503,10 @@ msgid "Validated:"
msgstr ""
msgid "Validations failed."
-msgstr ""
+msgstr "Les validations ont échoué."
msgid "Value"
-msgstr ""
+msgstr "Valeur"
msgid "Value Stream Analytics"
msgstr "Analyse des chaînes de valeur"
@@ -44082,10 +44626,10 @@ msgid "Variable"
msgstr "Variable"
msgid "Variable will be masked in job logs."
-msgstr ""
+msgstr "La variable sera masquée dans les journaux des tâches."
msgid "Variables"
-msgstr ""
+msgstr "Variables"
msgid "Variables can be:"
msgstr "Les variables peuvent être :"
@@ -44175,7 +44719,7 @@ msgid "View all groups"
msgstr "Voir tous les groupes"
msgid "View all issues"
-msgstr ""
+msgstr "Voir tous les tickets"
msgid "View all projects"
msgstr "Voir tous les projets"
@@ -44191,26 +44735,26 @@ msgstr ""
msgid "View chart"
msgid_plural "View charts"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Voir le graphique"
+msgstr[1] "Voir les graphiques"
msgid "View dependency details for your project"
-msgstr ""
+msgstr "Voir les détails des dépendances de votre projet"
msgid "View deployment"
-msgstr ""
+msgstr "Voir le déploiement"
msgid "View details"
-msgstr ""
+msgstr "Voir les détails"
msgid "View details: %{details_url}"
-msgstr ""
+msgstr "Voir les détails : %{details_url}"
msgid "View documentation"
msgstr "Voir la documentation"
msgid "View eligible approvers"
-msgstr ""
+msgstr "Voir les approbateurs éligibles"
msgid "View entire blame"
msgstr ""
@@ -44227,13 +44771,10 @@ msgid "View file @ %{commitSha}"
msgstr ""
msgid "View full dashboard"
-msgstr ""
-
-msgid "View full log"
-msgstr ""
+msgstr "Voir le tableau de bord complet"
msgid "View group in admin area"
-msgstr ""
+msgstr "Voir le groupe dans l'espace d’administration"
msgid "View group labels"
msgstr "Afficher les labels de groupe"
@@ -44263,7 +44804,7 @@ msgid "View job"
msgstr ""
msgid "View job log"
-msgstr ""
+msgstr "Voir le journal des tâches"
msgid "View jobs"
msgstr "Afficher les tâches"
@@ -44346,7 +44887,7 @@ msgid "Violation"
msgstr ""
msgid "Visibility"
-msgstr ""
+msgstr "Visibilité"
msgid "Visibility and access controls"
msgstr "Contrôles de visibilité et d’accès"
@@ -44358,10 +44899,10 @@ msgid "Visibility level:"
msgstr "Niveau de visibilité :"
msgid "Visibility settings have been disabled by the administrator."
-msgstr ""
+msgstr "Les paramètres de visibilité ont été désactivés par l'administrateur."
msgid "Visibility, project features, permissions"
-msgstr ""
+msgstr "Visibilité, fonctionnalités du projet, permissions"
msgid "Visibility:"
msgstr "Visibilité :"
@@ -44382,10 +44923,10 @@ msgid "Visual Studio Code (HTTPS)"
msgstr "Visual Studio Code (HTTPS)"
msgid "Visual Studio Code (SSH)"
-msgstr ""
+msgstr "Visual Studio Code (SSH)"
msgid "Vulnerabilities"
-msgstr ""
+msgstr "Vulnérabilités"
msgid "Vulnerabilities over time"
msgstr ""
@@ -44409,10 +44950,10 @@ msgid "Vulnerability resolved in the default branch"
msgstr "Vulnérabilité résolue dans la branche par défaut"
msgid "VulnerabilityChart|%{formattedStartDate} to today"
-msgstr ""
+msgstr "%{formattedStartDate} à aujourd'hui"
msgid "VulnerabilityChart|Severity"
-msgstr ""
+msgstr "Gravité"
msgid "VulnerabilityManagement|%{statusStart}Confirmed%{statusEnd} %{timeago} by %{user}"
msgstr "%{statusStart}Confirmée%{statusEnd} %{timeago} par %{user}"
@@ -44493,7 +45034,7 @@ msgid "VulnerabilityManagement|Select a severity level"
msgstr "Sélectionnez un niveau de gravité"
msgid "VulnerabilityManagement|Select a status"
-msgstr ""
+msgstr "Sélectionnez un état"
msgid "VulnerabilityManagement|Severity is a required field"
msgstr "La gravité est un champ requis"
@@ -44526,7 +45067,7 @@ msgid "VulnerabilityManagement|Something went wrong, could not update vulnerabil
msgstr "Une erreur s’est produite, impossible de mettre à jour l’état de la vulnérabilité."
msgid "VulnerabilityManagement|Status is a required field"
-msgstr ""
+msgstr "L'état est un champ requis"
msgid "VulnerabilityManagement|Submit vulnerability"
msgstr ""
@@ -44655,7 +45196,7 @@ msgid "Vulnerability|Identifiers"
msgstr "Identifiants"
msgid "Vulnerability|Image"
-msgstr ""
+msgstr "Image"
msgid "Vulnerability|Information related to how the vulnerability was discovered and its impact on the system."
msgstr "Informations relatives à la manière dont la vulnérabilité a été découverte et à son impact sur le système."
@@ -44693,6 +45234,9 @@ msgstr "Requête/Réponse"
msgid "Vulnerability|Scanner Provider"
msgstr "Fournisseur de scanner"
+msgid "Vulnerability|Scanner:"
+msgstr "Scanner :"
+
msgid "Vulnerability|Security Audit"
msgstr "Audit de Sécurité"
@@ -44711,6 +45255,9 @@ msgstr "Gravité :"
msgid "Vulnerability|Status"
msgstr "État"
+msgid "Vulnerability|Status:"
+msgstr "État :"
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr "Le scanner a déterminé que cette vulnérabilité est un faux positif. Vérifiez cette évaluation avant d'en modifier l'état. %{linkStart}En savoir plus sur la détection des faux positifs.%{linkEnd}"
@@ -44721,7 +45268,7 @@ msgid "Vulnerability|Tool"
msgstr "Outil"
msgid "Vulnerability|Tool:"
-msgstr ""
+msgstr "Outil :"
msgid "Vulnerability|Training"
msgstr "Formation"
@@ -44739,7 +45286,7 @@ msgid "WARNING:"
msgstr "AVERTISSEMENT :"
msgid "WARNING: This snippet contains hidden files which might be used to mask malicious behavior. Exercise caution if cloning and executing code from this snippet."
-msgstr ""
+msgstr "AVERTISSEMENT : cet extrait contient des fichiers cachés qui pourraient être utilisés pour masquer un comportement malveillant. Soyez prudent si vous clonez et exécutez du code à partir de cet extrait."
msgid "Wait for the file to load to copy its contents"
msgstr ""
@@ -44748,7 +45295,7 @@ msgid "Waiting for approval"
msgstr "En attente d’approbation"
msgid "Waiting for merge (open and assigned)"
-msgstr ""
+msgstr "En attente de fusion (ouvertes et assignées)"
msgid "Waiting for performance data"
msgstr ""
@@ -44781,13 +45328,13 @@ msgid "We are currently unable to fetch data for this graph."
msgstr "Nous sommes actuellement dans l'impossibilité de récupérer les données de ce graphe."
msgid "We could not determine the path to remove the epic"
-msgstr ""
+msgstr "Nous n'avons pas pu déterminer le chemin pour supprimer l'épopée"
msgid "We could not determine the path to remove the issue"
-msgstr ""
+msgstr "Nous n'avons pas pu déterminer le chemin pour supprimer le ticket"
msgid "We couldn't find any %{scope} matching %{term}"
-msgstr ""
+msgstr "Nous n'avons pas trouvé de %{scope} correspondant à %{term}"
msgid "We couldn't find any %{scope} matching %{term} in group %{group}"
msgstr ""
@@ -44802,10 +45349,10 @@ msgid "We created a sandbox project that will help you learn the basics of GitLa
msgstr "Nous avons créé un projet bac à sable pour vous aider à apprendre les bases de GitLab. Vous serez guidé(e) par des tickets dans un tableau de tickets. Vous pouvez les suivre à votre propre rythme."
msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
+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 ""
+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."
@@ -44814,7 +45361,7 @@ msgid "We don't have enough data to show this stage."
msgstr "Nous n’avons pas suffisamment de données pour afficher cette étape."
msgid "We have found the following errors:"
-msgstr ""
+msgstr "Nous avons trouvé les erreurs suivantes :"
msgid "We heard back from your device. You have been authenticated."
msgstr "Nous avons un retour de votre appareil. Vous avez été authentifié."
@@ -44838,7 +45385,7 @@ msgid "We recommend using cloud-based authenticator applications that can restor
msgstr "Nous vous recommandons d'utiliser des applications d'authentification basées sur le cloud qui peuvent restaurer l'accès si vous perdez votre périphérique matériel."
msgid "We sent you an email with reset password instructions"
-msgstr ""
+msgstr "Nous vous avons envoyé un courriel avec les instructions pour réinitialiser le mot de passe"
msgid "We tried to automatically renew your subscription for %{strong}%{namespace_name}%{strong_close} on %{expires_on} but something went wrong so your subscription was downgraded to the free plan. Don't worry, your data is safe. We suggest you check your payment method and get in touch with our support team (%{support_link}). They'll gladly help with your subscription renewal."
msgstr "Nous avons essayé de renouveler automatiquement votre abonnement pour %{strong}%{namespace_name}%{strong_close} le %{expires_on} mais une erreur s'est produite et il a donc été rétrogradé vers le forfait gratuit. Ne vous inquiétez pas, vos données sont en sécurité. Nous vous suggérons de vérifier votre mode de paiement et de contacter notre équipe d'assistance (%{support_link}). Ils se feront un plaisir de vous accompagner pour le renouvellement de votre abonnement."
@@ -44846,8 +45393,8 @@ msgstr "Nous avons essayé de renouveler automatiquement votre abonnement pour %
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "Nous voulons nous assurer qu’il s’agit bien de vous, merci de confirmer que vous n’êtes pas un robot."
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
-msgstr "Nous voulons vous informer que %{username} a été banni de %{scope} car il a téléchargé plus de %{max_project_downloads} dépôts de projets en l'espace de %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
+msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
msgstr "Nous informerons %{inviter} que vous avez refusé leur invitation à rejoindre GitLab. Vous ne recevrez plus de rappels."
@@ -44862,10 +45409,10 @@ 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."
msgid "We're experiencing difficulties and this tab content is currently unavailable."
-msgstr ""
+msgstr "Nous rencontrons des difficultés et le contenu de cet onglet est actuellement indisponible."
msgid "We've detected some unusual activity"
-msgstr ""
+msgstr "Nous avons détecté une activité inhabituelle"
msgid "We've detected unusual activity"
msgstr "Nous avons détecté une activité inhabituelle"
@@ -44877,7 +45424,7 @@ msgid "Web IDE"
msgstr "EDI Web"
msgid "Web Terminal"
-msgstr ""
+msgstr "Terminal Web"
msgid "Web terminal"
msgstr "Terminal Web"
@@ -44888,6 +45435,9 @@ msgstr "Appareils WebAuthn (%{length})"
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr "WebAuthn ne fonctionne qu'avec les sites Web accessibles en HTTPS. Contactez votre administrateur pour plus de détails."
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr "Créer un projet divergent"
@@ -44903,12 +45453,24 @@ msgstr "Modifier rapidement et facilement plusieurs fichiers de votre projet."
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr "Modifier rapidement et facilement plusieurs fichiers de votre projet. Appuyez sur . pour ouvrir\n"
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr "Une erreur s’est produite lors de la mise à jour des préférences de l’utilisateur. Veuillez consulter la console développeur pour plus de détails."
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr "Ce projet n’accepte pas les commits non signés."
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr "Ce projet n'accepte pas les commits non signés. Vous ne pouvez pas valider de modifications dans l'EDI Web."
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr "Vous ne pouvez pas directement modifier les fichiers de ce projet. Créez une divergence, puis proposez une demande de fusion avec vos modifications."
@@ -44943,16 +45505,19 @@ msgid "Webhook:"
msgstr "Point d'ancrage web :"
msgid "Webhooks"
-msgstr ""
+msgstr "Crochets web"
msgid "Webhooks Help"
msgstr "Aide sur les Webhooks"
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr "+ Masquer une autre partie de l'URL"
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr "Un commentaire est ajouté à un ticket confidentiel."
msgid "Webhooks|A comment is added to an issue or merge request."
-msgstr ""
+msgstr "Un commentaire est ajouté à un ticket ou à une demande de fusion."
msgid "Webhooks|A confidential issue is created, updated, closed, or reopened."
msgstr "Un ticket confidentiel est créé, mis à jour, fermé ou rouvert."
@@ -44994,10 +45559,10 @@ msgid "Webhooks|An issue is created, updated, closed, or reopened."
msgstr "Un ticket est créé, mis à jour, fermé ou rouvert."
msgid "Webhooks|Are you sure you want to delete this group hook?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir supprimer ce crochet de groupe ?"
msgid "Webhooks|Are you sure you want to delete this project hook?"
-msgstr ""
+msgstr "Êtes-vous sûr(e) de vouloir supprimer ce crochet de projet ?"
msgid "Webhooks|Are you sure you want to delete this webhook?"
msgstr "Êtes-vous sûr(e) de vouloir supprimer ce webhook ?"
@@ -45018,13 +45583,13 @@ msgid "Webhooks|Deployment events"
msgstr "Événements de déploiement"
msgid "Webhooks|Do not show sensitive data such as tokens in the UI."
-msgstr ""
+msgstr "Ne pas afficher de données sensibles comme les jetons dans l'interface graphique."
msgid "Webhooks|Enable SSL verification"
msgstr "Activer la vérification SSL"
msgid "Webhooks|Failed to connect"
-msgstr ""
+msgstr "Échec de la connexion"
msgid "Webhooks|Fails to connect"
msgstr ""
@@ -45036,7 +45601,7 @@ msgid "Webhooks|Go to webhooks"
msgstr "Aller aux webhooks"
msgid "Webhooks|How it looks in the UI"
-msgstr ""
+msgstr "À quoi elle ressemble dans l'interface graphique"
msgid "Webhooks|Issues events"
msgstr "Événements des tickets"
@@ -45045,7 +45610,7 @@ msgid "Webhooks|Job events"
msgstr "Événements des tâches"
msgid "Webhooks|Mask portions of URL"
-msgstr ""
+msgstr "Masquer des parties de l'URL"
msgid "Webhooks|Member events"
msgstr "Événements des membres"
@@ -45062,6 +45627,12 @@ msgstr "Événements de poussées"
msgid "Webhooks|Push to the repository."
msgstr "Poussée vers le dépôt."
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr "Les expressions rationnelles telles que %{REGEX_CODE} sont prises en charge."
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr "Événements de Versions"
@@ -45072,10 +45643,10 @@ msgid "Webhooks|Secret token"
msgstr "Jeton secret"
msgid "Webhooks|Sensitive portion of URL"
-msgstr ""
+msgstr "Partie sensible de l'URL"
msgid "Webhooks|Show full URL"
-msgstr ""
+msgstr "Afficher l'URL complète"
msgid "Webhooks|Subgroup events"
msgstr "Événements de sous-groupe"
@@ -45089,9 +45660,6 @@ msgstr "Le point d'ancrage Wab %{help_link_start}n'a pas réussi à se connecter
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr "Le point d'ancrage Web n'a pas réussi à se connecter et est désactivé. Pour le réactiver, vérifiez les détails de l'erreur dans les %{strong_start}Événements récents%{strong_end} puis testez vos paramètres ci-dessous."
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr "Le point d'ancrage Web a été déclenché plus de %{limit} fois par minute et est maintenant désactivé. Pour le réactiver, corrigez les problèmes affichés dans les %{strong_start}Événements récents%{strong_end} puis retestez vos paramètres. %{support_link_start}Contactez le Support%{support_link_end} si vous avez besoin d'aide pour réactiver votre point d'ancrage Web."
-
msgid "Webhooks|Trigger"
msgstr "Déclencheur"
@@ -45102,10 +45670,10 @@ msgid "Webhooks|URL must be percent-encoded if it contains one or more special c
msgstr "L'URL doit être en encodage-pourcent si elle contient un ou plusieurs caractères spéciaux."
msgid "Webhooks|URL preview"
-msgstr ""
+msgstr "Aperçu de l'URL"
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
-msgstr "Utilisé pour valider les charges utiles reçues. Envoyé avec la requête dans l'en-tête %{code_start}HTTP X-Gitlab-Token%{code_end}."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
+msgstr "Utilisé pour valider les charges utiles reçues. Envoyé avec la requête dans l'en-tête HTTP %{code_start}X-Gitlab-Token%{code_end}."
msgid "Webhooks|Webhook disabled"
msgstr "Webhook désactivé"
@@ -45116,12 +45684,21 @@ msgstr "Le point d'ancrage Web n'a pas réussi à se connecter"
msgid "Webhooks|Webhook fails to connect"
msgstr "Le point d'ancrage Web n'arrive pas à se connecter"
-msgid "Webhooks|Webhook was automatically disabled"
-msgstr "Le point d'ancrage Web a été automatiquement désactivé"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
+msgstr "Les webhooks de %{root_namespace} sont maintenant désactivés car ils ont été déclenchés plus de %{limit} fois par minute. Ils seront automatiquement réactivés la minute suivante."
msgid "Webhooks|Wiki page events"
msgstr "Événements des Pages Wiki"
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr "Site Web"
@@ -45132,7 +45709,7 @@ msgid "Wed"
msgstr "Mer"
msgid "Wednesday"
-msgstr ""
+msgstr "Mercredi"
msgid "Weekday"
msgstr "Jour de la semaine"
@@ -45147,10 +45724,10 @@ msgid "Weight %{weight}"
msgstr "Poids %{weight}"
msgid "Welcome back! Your account had been deactivated due to inactivity but is now reactivated."
-msgstr ""
+msgstr "Bon retour ! Votre compte avait été désactivé en raison de son inactivité mais il est maintenant réactivé."
msgid "Welcome to GitLab"
-msgstr ""
+msgstr "Bienvenue sur GitLab"
msgid "Welcome to GitLab, %{first_name}!"
msgstr "Bienvenue sur GitLab, %{first_name} !"
@@ -45183,13 +45760,13 @@ msgid "What does this command do?"
msgstr "Que fait cette commande ?"
msgid "What is GitLab Runner?"
-msgstr ""
+msgstr "Qu'est-ce que GitLab Runner ?"
msgid "What is Markdown?"
msgstr "Qu'est-ce que Markdown ?"
msgid "What is listed here?"
-msgstr ""
+msgstr "Qu'est-ce qui est listé ici ?"
msgid "What is repository mirroring?"
msgstr "Qu'est-ce que la mise en miroir de dépôt ?"
@@ -45200,6 +45777,9 @@ msgstr "Que signifie « squasher » ?"
msgid "What templates can I create?"
msgstr "Quels modèles puis-je créer ?"
+msgid "What variables can I use?"
+msgstr "Quelles variables puis-je utiliser ?"
+
msgid "What will you use this group for?"
msgstr "À quoi vous servira ce groupe ?"
@@ -45209,8 +45789,8 @@ msgstr "Que souhaitez-vous faire ?"
msgid "What's new"
msgstr "Nouveautés"
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
-msgstr "Quand une tâche de déploiement réussit, ignorer celles plus anciennes qui sont toujours en attente."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
+msgstr "Lorsqu'une tâche de déploiement a réussi, empêcher celles plus anciennes qui sont toujours en attente"
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr "Lorsqu’un exécuteur est verrouillé, il ne peut pas être affecté à d’autres projets"
@@ -45222,10 +45802,10 @@ msgid "When enabled, cleanup polices execute faster but put more load on Redis."
msgstr ""
msgid "When enabled, existing access tokens may be revoked. Leave blank for no limit."
-msgstr ""
+msgstr "Lorsque cette option est activée, les jetons d'accès existants peuvent être révoqués. Laissez vide pour aucune limite."
msgid "When enabled, job logs are collected by Datadog and displayed along with pipeline execution traces."
-msgstr ""
+msgstr "Lorsque cette option est activée, les journaux de tâches sont collectés par Datadog et affichés avec les traces d'exécution des pipelines."
msgid "When merge requests and commits in the default branch close, any issues they reference also close."
msgstr "Quand des demandes de fusion et des commits sont fermés sur la branche par défaut, tous les tickets auxquels ils font référence sont également clôturés."
@@ -45277,13 +45857,13 @@ msgid "Who will be using this group?"
msgstr "Qui utilisera ce groupe ?"
msgid "Why are you signing up? (optional)"
-msgstr ""
+msgstr "Pourquoi vous inscrivez-vous ? (facultatif)"
msgid "Wiki"
msgstr "Wiki"
msgid "Wiki page"
-msgstr ""
+msgstr "Page wiki"
msgid "Wiki page was successfully created."
msgstr "La page wiki a été créée avec succès."
@@ -45313,7 +45893,7 @@ msgid "WikiEmptyIssueMessage|Suggest wiki improvement"
msgstr "Suggérer une amélioration du wiki"
msgid "WikiEmptyIssueMessage|You must be a group member in order to add wiki pages. If you have suggestions for how to improve the wiki for this group, consider opening an issue in the %{issues_link}."
-msgstr ""
+msgstr "Vous devez être un membre du groupe pour ajouter des pages au wiki. Si vous avez des suggestions pour améliorer le wiki pour ce groupe, envisagez d'ouvrir un ticket dans le %{issues_link}."
msgid "WikiEmptyIssueMessage|You must be a project member in order to add wiki pages. If you have suggestions for how to improve the wiki for this project, consider opening an issue in the %{issues_link}."
msgstr "Vous devez être un membre du projet pour ajouter des pages wiki. Si vous avez des suggestions sur la manière d’améliorer le wiki pour ce projet, veuillez envisager l’ouverture d’un ticket sur %{issues_link}."
@@ -45439,7 +46019,7 @@ msgid "Wikis"
msgstr "Wikis"
msgid "Wiki|Create New Page"
-msgstr ""
+msgstr "Créer une Nouvelle Page"
msgid "Wiki|Created date"
msgstr "Date de création"
@@ -45463,7 +46043,7 @@ msgid "Wiki|The sidebar failed to load. You can reload the page to try again."
msgstr "Le chargement de la barre latérale a échoué. Vous pouvez recharger la page pour réessayer."
msgid "Wiki|Title"
-msgstr ""
+msgstr "Titre"
msgid "Wiki|View All Pages"
msgstr "Voir toutes les pages"
@@ -45496,10 +46076,10 @@ msgid "Won't fix / Accept risk"
msgstr "Ne sera pas corrigé / Accepter le risque"
msgid "Work in progress (open and unassigned)"
-msgstr ""
+msgstr "Travaux en cours (ouverts et non assignés)"
msgid "Work in progress Limit"
-msgstr ""
+msgstr "Limite des travaux en cours"
msgid "WorkItem|%{workItemType} deleted"
msgstr "%{workItemType} supprimé"
@@ -45525,6 +46105,12 @@ msgstr "Ajouter une date de début"
msgid "WorkItem|Add task"
msgstr "Ajouter une tâche"
+msgid "WorkItem|Add to iteration"
+msgstr "Ajouter à l'itération"
+
+msgid "WorkItem|Add to milestone"
+msgstr "Ajouter au jalon"
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr "Êtes-vous sûr de vouloir annuler la modification ?"
@@ -45575,8 +46161,23 @@ msgstr "Introduction aux tâches"
msgid "WorkItem|Issue"
msgstr "Ticket"
+msgid "WorkItem|Iteration"
+msgstr "Itération"
+
msgid "WorkItem|Learn about tasks."
-msgstr ""
+msgstr "En savoir plus sur les tâches."
+
+msgid "WorkItem|Milestone"
+msgstr "Jalon"
+
+msgid "WorkItem|No iteration"
+msgstr "Aucune itération"
+
+msgid "WorkItem|No matching results"
+msgstr "Aucun résultat correspondant"
+
+msgid "WorkItem|No milestone"
+msgstr "Aucun jalon"
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr "Aucune tâche n’est actuellement assignée. Utilisez des tâches pour scinder ce ticket en parties plus petites."
@@ -45608,14 +46209,17 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr "Une erreur s’est produite lors de la suppression de la tâche. Veuillez réessayer."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr "Une erreur s’est produite lors de la récupération des itérations. Veuillez réessayer."
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr "Une erreur s’est produite lors de la récupération des étiquettes. Veuillez réessayer."
+
msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr "Une erreur s’est produite lors de la récupération des tâches. Veuillez actualiser cette page."
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
-msgstr ""
-
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
-msgstr ""
+msgstr "Une erreur s’est produite lors de la récupération des types d’éléments de travail. Veuillez réessayer"
msgid "WorkItem|Something went wrong when trying to add a child. Please try again."
msgstr "Une erreur s’est produite lors de la tentative d’ajout d’un enfant. Veuillez réessayer."
@@ -45623,11 +46227,14 @@ msgstr "Une erreur s’est produite lors de la tentative d’ajout d’un enfant
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr "Une erreur s’est produite lors de la création d’un enfant. Veuillez réessayer."
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr "Une erreur s’est produite lors de la récupération des jalons. Veuillez réessayer."
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
msgid "WorkItem|Something went wrong while updating the work item. Please try again."
-msgstr ""
+msgstr "Une erreur s’est produite lors de la mise à jour de l’élément de travail. Veuillez réessayer."
msgid "WorkItem|Start date"
msgstr "Date de début"
@@ -45644,6 +46251,9 @@ msgstr "Tâches"
msgid "WorkItem|Test case"
msgstr "Cas de test"
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr "Cet élément de travail n'est pas disponible. Soit il n'existe pas, soit vous n'avez pas la permission de le voir."
+
msgid "WorkItem|Turn off confidentiality"
msgstr "Désactiver la confidentialité"
@@ -45654,7 +46264,7 @@ msgid "WorkItem|Undo"
msgstr "Annuler"
msgid "WorkItem|Use tasks to break down your work in an issue into smaller pieces. %{learnMoreLink}"
-msgstr ""
+msgstr "Utiliser des tâches pour scinder votre travail sur un ticket en parties plus petites. %{learnMoreLink}"
msgid "WorkItem|Work Items"
msgstr "Éléments de Travail"
@@ -45662,6 +46272,9 @@ msgstr "Éléments de Travail"
msgid "WorkItem|Work item"
msgstr "Élément de travail"
+msgid "WorkItem|Work item not found"
+msgstr "Élément de travail introuvable"
+
msgid "Would you like to create a new branch?"
msgstr "Voulez-vous créer une nouvelle branche ?"
@@ -45690,10 +46303,10 @@ msgid "Write milestone description..."
msgstr "Ecrire une description du jalon ..."
msgid "Write your release notes or drag your files here…"
-msgstr ""
+msgstr "Rédigez vos notes de version ou faites glisser vos fichiers ici…"
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
-msgstr ""
+msgstr "Un UID externe incorrect a été fourni. Assurez-vous que Auth0 est configuré correctement."
msgid "Xcode"
msgstr "Xcode"
@@ -45705,7 +46318,7 @@ msgid "Yes"
msgstr "Oui"
msgid "Yes or No"
-msgstr ""
+msgstr "Oui ou Non"
msgid "Yes, add it"
msgstr "Oui, l’ajouter"
@@ -45720,7 +46333,7 @@ msgid "Yesterday"
msgstr "Hier"
msgid "You"
-msgstr ""
+msgstr "Vous"
msgid "You already have pending todo for this alert"
msgstr "Vous avez déjà une tâche « À faire » en attente pour cette alerte"
@@ -45737,13 +46350,13 @@ msgid "You are about to delete this forked project containing:"
msgstr "Vous êtes sur le point de supprimer ce projet divergent qui contient :"
msgid "You are about to delete this project containing:"
-msgstr ""
+msgstr "Vous êtes sur le point de supprimer ce projet contenant :"
msgid "You are about to transfer the control of your account to %{group_name} group. This action is NOT reversible, you won't be able to access any of your groups and projects outside of %{group_name} once this transfer is complete."
msgstr "Vous êtes sur le point de transférer le contrôle de votre compte au groupe %{group_name}. Cette action n'est PAS réversible, vous ne pourrez plus accéder à aucun de vos groupes et projets en dehors de %{group_name} une fois ce transfert terminé."
msgid "You are already a member of this %{member_source}."
-msgstr ""
+msgstr "Vous êtes déjà membre de ce %{member_source}."
msgid "You are already impersonating another user"
msgstr "Vous empruntez déjà l'identité d'un autre utilisateur"
@@ -45752,16 +46365,19 @@ msgid "You are an admin, which means granting access to %{client_name} will allo
msgstr "Vous êtes un administrateur, ce qui signifie qu’accorder l’accès à %{client_name} leur permettra d’interagir avec GitLab en tant qu’administrateur. Procédez avec précaution."
msgid "You are attempting to delete a file that has been previously updated."
-msgstr ""
+msgstr "Vous essayez de supprimer un fichier qui a été précédemment mis à jour."
msgid "You are attempting to update a file that has changed since you started editing it."
+msgstr "Vous tentez de mettre à jour un fichier qui a changé depuis que vous avez commencé à le modifier."
+
+msgid "You are being redirected away from GitLab"
msgstr ""
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr "Vous serez facturé si ce nombre est dépassé. %{qsrOverageLinkStart}Comment fonctionne la facturation ?%{qsrOverageLinkEnd}"
msgid "You are connected to the Prometheus server, but there is currently no data to display."
-msgstr ""
+msgstr "Vous êtes connecté au serveur Prometheus, mais il n'y a actuellement aucune donnée à afficher."
msgid "You are currently offline, or the GitLab instance is not reachable."
msgstr "Vous êtes actuellement hors ligne, ou l'instance GitLab n'est pas joignable."
@@ -45770,7 +46386,7 @@ msgid "You are going to delete %{project_full_name}. Deleted projects CANNOT be
msgstr "Vous êtes sur le point de supprimer %{project_full_name}. Les projets supprimés NE PEUVENT PAS être restaurés ! Êtes-vous ABSOLUMENT sûr(e) ?"
msgid "You are going to remove %{group_name}. This will also delete all of its subgroups and projects. Removed groups CANNOT be restored! Are you ABSOLUTELY sure?"
-msgstr ""
+msgstr "Vous êtes sur le point de supprimer %{group_name}. Cela supprimera également tous ses sous-groupes et projets. Les groupes supprimés NE PEUVENT PAS être restaurés ! Êtes-vous ABSOLUMENT sûr(e) ?"
msgid "You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?"
msgstr "Vous êtes sur le point de supprimer la relation de fork du projet %{project_full_name}. Êtesâ€vous ABSOLUMENT sûr ?"
@@ -45793,6 +46409,12 @@ msgstr "Vous n'avez pas le droit de %{action} un utilisateur"
msgid "You are not allowed to approve a user"
msgstr "Vous n'êtes pas autorisé(e) à approuver un utilisateur"
+msgid "You are not allowed to create this tag as it is protected."
+msgstr "Il ne vous est pas permis de créer cette étiquette car elle est protégée."
+
+msgid "You are not allowed to download code from this project."
+msgstr "Vous n'êtes pas autorisé à télécharger du code à partir de ce projet."
+
msgid "You are not allowed to log in using password"
msgstr "Vous n'êtes pas autorisé à vous connecter avec un mot de passe"
@@ -45833,14 +46455,11 @@ msgid "You are receiving this message because you are a GitLab administrator for
msgstr ""
msgid "You are signed in to GitLab as:"
-msgstr ""
+msgstr "Vous êtes connecté à GitLab en tant que :"
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr "Vous essayez de téléverser autre chose qu'une image. Veuillez envoyer un .png, .jpg, .jpeg, .gif, .bmp, .tiff ou .ico."
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr "Vous utilisez PostgreSQL %{pg_version_current}, mais cette version de GitLab nécessite au minimum PostgreSQL %{pg_version_minimum}. Veuillez mettre à jour votre environnement vers une version de PostgreSQL prise en charge, voir %{pg_requirements_url} pour plus de détails."
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr "Vous pouvez %{gitlabLinkStart}résoudre les conflits sur GitLab%{gitlabLinkEnd} ou %{resolveLocallyStart}le faire localement%{resolveLocallyEnd}."
@@ -45857,7 +46476,7 @@ msgid "You can also create a project from the command line."
msgstr "Vous pouvez également créer un projet en ligne de commande."
msgid "You can also press Ctrl-Enter"
-msgstr ""
+msgstr "Vous pouvez également appuyer sur Ctrl-Entrée"
msgid "You can also press ⌘-Enter"
msgstr "Vous pouvez aussi appuyer sur ⌘-Entrée"
@@ -45866,10 +46485,10 @@ 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."
msgid "You can also test your %{gitlab_ci_yml} in %{lint_link_start}CI Lint%{lint_link_end}"
-msgstr ""
+msgstr "Vous pouvez également tester votre %{gitlab_ci_yml} dans %{lint_link_start}CI Lint%{lint_link_end}"
msgid "You can also upload existing files from your computer using the instructions below."
-msgstr ""
+msgstr "Vous pouvez également téléverser des fichiers existants depuis votre ordinateur en suivant les instructions ci-dessous."
msgid "You can also use group access tokens with Git to authenticate over HTTP(S). %{link_start}Learn more.%{link_end}"
msgstr "Vous pouvez également utiliser des jetons d'accès de groupe avec Git pour vous authentifier via HTTP(S). %{link_start}En savoir plus.%{link_end}"
@@ -45942,6 +46561,9 @@ msgstr "Vous pouvez activer la création de jetons d'accès de groupe dans les %
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr "Vous pouvez activer la création de jetons d'accès au projet dans les %{link_start}paramètres de groupe%{link_end}."
+msgid "You can enter up to 280 characters"
+msgstr "Vous pouvez entrer jusqu'à 280 caractères"
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -45994,13 +46616,13 @@ msgid "You can only merge once the items above are resolved."
msgstr ""
msgid "You can only transfer the project to namespaces you manage."
-msgstr ""
+msgstr "Vous ne pouvez transférer le projet que vers des espaces de noms que vous gérez."
msgid "You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}"
msgstr "Vous pouvez résoudre le conflit de fusion Git soit en mode interactif, en cliquant sur les boutons « %{use_ours} » ou « %{use_theirs} », soit en modifiant directement les fichiers. Valider ces modifications dans la branche « %{branch_name} »"
msgid "You can see your chat accounts."
-msgstr ""
+msgstr "Vous pouvez voir vos comptes de discussion."
msgid "You can set up jobs to only use runners with specific tags. Separate tags with commas."
msgstr "Vous pouvez configurer des tâches pour utiliser uniquement des exécuteurs qui possèdent des étiquettes spécifiques. Utilisez des virgules pour séparer les étiquettes."
@@ -46014,35 +46636,38 @@ msgstr "Vous pouvez tester votre fichier « .gitlab-ci.yml » avec %{linkStart
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr "Vous pouvez afficher la source ou %{linkStart}%{cloneIcon} cloner le dépot%{linkEnd}"
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
-msgstr "Vous ne pouvez pas en ajouter davantage mais vous pouvez gérer les membres existants, par exemple, en supprimant ceux inactifs pour les remplacer par de nouveaux. Pour obtenir plus de membres, un propriétaire du groupe peut démarrer une période d'essai ou faire une mise à niveau vers une édition payante."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
+msgstr "Vous ne pouvez pas suivre plus de %{limit} utilisateurs. Pour en suivre d'autres, désabonnez-vous de certains d'entre eux."
msgid "You cannot %{action} %{state} users."
msgstr "Vous ne pouvez pas %{action} les utilisateurs %{state}."
msgid "You cannot access the raw file. Please wait a minute."
-msgstr ""
+msgstr "Vous ne pouvez pas accéder au fichier brut. Veuillez patienter une minute."
msgid "You cannot add any more epics. This epic already has maximum number of child epics."
msgstr "Vous ne pouvez pas ajouter davantage d'épopées. Cette épopée contient déjà le nombre maximal d'épopées enfants."
msgid "You cannot approve your own deployment."
-msgstr ""
+msgstr "Vous ne pouvez pas approuver votre propre déploiement."
msgid "You cannot combine replace_ids with add_ids or remove_ids"
msgstr "Vous ne pouvez pas combiner replace_ids avec add_ids ou remove_ids"
msgid "You cannot impersonate a blocked user"
-msgstr ""
+msgstr "Vous ne pouvez pas emprunter l'identité d'un utilisateur bloqué"
msgid "You cannot impersonate a user who cannot log in"
-msgstr ""
+msgstr "Vous ne pouvez pas emprunter l'identité d'un utilisateur qui ne peut pas se connecter"
+
+msgid "You cannot impersonate a user with an expired password"
+msgstr "Vous ne pouvez pas emprunter l'identité d'un utilisateur dont le mot de passe a expiré"
msgid "You cannot impersonate an internal user"
-msgstr ""
+msgstr "Vous ne pouvez pas emprunter l'identité d'un utilisateur interne"
msgid "You cannot play this scheduled pipeline at the moment. Please wait a minute."
-msgstr ""
+msgstr "Vous ne pouvez pas lancer ce pipeline planifié pour le moment. Veuillez patienter une minute."
msgid "You cannot rename an environment after it's created."
msgstr "Vous ne pouvez pas renommer un environnement après sa création."
@@ -46060,7 +46685,7 @@ msgid "You can’t edit files directly in this project. Fork this project and su
msgstr "Vous ne pouvez pas modifier directement des fichiers dans ce projet. Créez un projet divergent, puis proposez une demande de fusion avec vos modifications."
msgid "You could not create a new trigger."
-msgstr ""
+msgstr "Vous ne pouvez pas créer un nouveau déclencheur."
msgid "You do not have any subscriptions yet"
msgstr "Vous n’avez souscrit à aucun abonnement pour le moment"
@@ -46078,7 +46703,7 @@ msgid "You do not have permission to run a pipeline on this branch."
msgstr "Vous n'avez pas la permission d'exécuter un pipeline sur cette branche."
msgid "You do not have permission to run the Web Terminal. Please contact a project administrator."
-msgstr ""
+msgstr "Vous n'êtes pas autorisé à exécuter le Terminal Web. Veuillez contacter un administrateur du projet."
msgid "You do not have permission to set a member awaiting"
msgstr "Vous n'avez pas la permission de mettre un membre en attente"
@@ -46090,13 +46715,13 @@ 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 ""
+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é."
msgid "You don't have any active chat names."
-msgstr ""
+msgstr "Vous n'avez aucun nom de discussion actif."
msgid "You don't have any applications"
msgstr "Vous ne disposez d’aucune application"
@@ -46117,10 +46742,10 @@ msgid "You don't have permission to review this deployment. Contact the project
msgstr "Vous n'avez pas la permission d'examiner ce déploiement. Contactez le propriétaire du projet ou du groupe pour obtenir de l'aide."
msgid "You don't have permissions to create this project"
-msgstr ""
+msgstr "Vous n'avez pas la permission de créer ce projet"
msgid "You don't have sufficient permission to perform this action."
-msgstr ""
+msgstr "Vous n'avez pas les permissions suffisantes pour effectuer cette action."
msgid "You don't have the %{role} role for any groups in this instance."
msgstr "Vous n'avez le rôle %{role} dans aucun groupe dans cette instance."
@@ -46140,10 +46765,10 @@ msgstr[0] ""
msgstr[1] ""
msgid "You have been granted %{access_level} access to the %{source_link} %{source_type}."
-msgstr ""
+msgstr "Un accès %{access_level} vous a été accordé sur le %{source_type} %{source_link}."
msgid "You have been granted %{access_level} access to the %{source_name} %{source_type}."
-msgstr ""
+msgstr "Un accès %{access_level} vous a été accordé sur le %{source_type} %{source_name}."
msgid "You have been granted %{member_human_access} access to group %{name}."
msgstr "Vous avez obtenu un accès %{member_human_access} au groupe %{name}."
@@ -46179,10 +46804,13 @@ msgid "You have insufficient permissions to create an on-call schedule for this
msgstr "Vous n'avez pas les permissions suffisantes pour créer un calendrier des astreintes pour ce projet"
msgid "You have insufficient permissions to manage resource links for this incident"
-msgstr ""
+msgstr "Vous n'avez pas les permissions suffisantes pour gérer les liens de ressources pour cet incident"
+
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr "Vous n'avez pas les permissions suffisantes pour gérer les étiquettes des événements de la chronologie de ce projet"
msgid "You have insufficient permissions to manage timeline events for this incident"
-msgstr ""
+msgstr "Vous n'avez pas les permissions suffisantes pour gérer les événements de la chronologie de cet incident"
msgid "You have insufficient permissions to remove an on-call rotation from this project"
msgstr "Vous n'avez pas les permissions suffisantes pour supprimer un cycle de travail pour ce projet"
@@ -46218,7 +46846,7 @@ msgid "You have no permissions"
msgstr "Vous n’avez pas les autorisations"
msgid "You have not added any approvers. Start by adding users or groups."
-msgstr ""
+msgstr "Vous n'avez pas ajouté d'approbateurs. Commencez par ajouter des utilisateurs ou des groupes."
msgid "You have set up 2FA for your account! If you lose access to your 2FA device, you can use your recovery codes to access your account. Alternatively, if you upload an SSH key, you can %{anchorOpen}use that key to generate additional recovery codes%{anchorClose}."
msgstr "Vous avez configuré l'A2F sur votre compte ! Si vous perdez l'accès à votre périphérique A2F, vous pouvez utiliser vos codes de récupération pour accéder à votre compte. Sinon, en envoyant une clé SSH, vous pourrez %{anchorOpen}utiliser celle-ci pour générer des codes de récupération supplémentaires%{anchorClose}."
@@ -46236,7 +46864,7 @@ msgid "You left the \"%{membershipable_human_name}\" %{source_type}."
msgstr ""
msgid "You may close the milestone now."
-msgstr ""
+msgstr "Vous pouvez maintenant fermer le jalon."
msgid "You must be authenticated to access this path."
msgstr "Vous devez être authentifié pour accéder à ce chemin."
@@ -46244,17 +46872,17 @@ msgstr "Vous devez être authentifié pour accéder à ce chemin."
msgid "You must be logged in to search across all of GitLab"
msgstr "Vous devez être connecté(e) pour rechercher dans tout GitLab"
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
msgstr "Seul un responsable peut forcer la suppression d’un verrou"
msgid "You must provide a valid current password"
-msgstr ""
+msgstr "Vous devez fournir le mot de passe actuel correct"
msgid "You must provide your current password in order to change it."
-msgstr ""
+msgstr "Vous devez fournir votre mot de passe actuel pour le changer."
msgid "You must sign in to search for specific projects."
msgstr "Vous devez vous connecter pour rechercher des projets spécifiques."
@@ -46281,10 +46909,10 @@ msgid "You need to set terms to be enforced"
msgstr ""
msgid "You need to specify both an Access Token and a Host URL."
-msgstr ""
+msgstr "Vous devez spécifier à la fois un Jeton d'Accès et une URL d'Hôte."
msgid "You need to upload a GitLab project export archive (ending in .gz)."
-msgstr ""
+msgstr "Vous devez téléverser une archive d’exportation de projet GitLab (se terminant par .gz)."
msgid "You need to verify your primary email first before enabling Two-Factor Authentication."
msgstr "Vous devez vérifier votre adresse de courriel principale avant de pouvoir activer l'Authentification à Deux Facteurs."
@@ -46308,13 +46936,13 @@ msgid "You will first need to set up Jira Integration to use this feature."
msgstr "Vous devrez au préalable configurer l'intégration de Jira pour utiliser cette fonctionnalité."
msgid "You will lose all changes you've made to this file. This action cannot be undone."
-msgstr ""
+msgstr "Vous perdrez toutes les modifications que vous avez apportées à ce fichier. Cette action ne peut pas être annulée."
msgid "You will lose all uncommitted changes you've made in this project. This action cannot be undone."
msgstr "Vous allez perdre toutes les modifications non validées que vous avez apportées à ce projet. Cette action ne peut pas être annulée."
msgid "You will need to update your local repositories to point to the new location."
-msgstr ""
+msgstr "Vous devrez mettre à jour vos dépôts locaux pour qu'ils pointent vers le nouvel emplacement."
msgid "You will not get any notifications via email"
msgstr "Vous ne recevrez aucune notification par courriel"
@@ -46338,7 +46966,7 @@ msgid "You'll be charged for %{true_up_link_start}users over license%{link_end}
msgstr "La facturation des %{true_up_link_start}utilisateurs hors licence%{link_end} se fera sur une base trimestrielle ou annuelle, en fonction des termes de votre contrat."
msgid "You'll be signed out from your current account automatically."
-msgstr ""
+msgstr "Vous serez automatiquement déconnecté de votre compte actuel."
msgid "You'll need to use different branch names to get a valid comparison."
msgstr "Vous devrez utiliser différents noms de branches pour obtenir une comparaison valide."
@@ -46412,14 +47040,11 @@ msgstr "YouTube"
msgid "Your %{group} membership will now expire in %{days}."
msgstr "Votre adhésion à %{group} va désormais expirer dans %{days}."
-msgid "Your %{host} account was signed in to from a new location"
-msgstr "Une connexion à votre compte %{host} a eu lieu depuis un nouvel emplacement"
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
-msgstr ""
+msgstr "Votre %{spammable_entity_type} a été reconnu comme du pourriel et a été rejeté."
msgid "Your %{spammable_entity_type} has been recognized as spam. Please, change the content or solve the reCAPTCHA to proceed."
-msgstr ""
+msgstr "Votre %{spammable_entity_type} a été reconnu comme du pourriel. Veuillez modifier le contenu ou résoudre le reCAPTCHA pour continuer."
msgid "Your %{strong}%{plan_name}%{strong_close} subscription expires on %{strong}%{expires_on}%{strong_close}. If you do not renew, you will lose access to your paid features on %{strong}%{downgrades_on}%{strong_close}. After that date, you can't create issues or merge requests, or use many other features."
msgstr "Votre abonnement %{strong}%{plan_name}%{strong_close} arrive à échéance le %{strong}%{expires_on}%{strong_close}. Si vous ne le renouvelez pas, vous perdrez l'accès à vos fonctionnalités payantes le %{strong}%{downgrades_on}%{strong_close}. Après cette date, vous ne pourrez plus créer de tickets ni de demandes de fusion, ni utiliser d'autres fonctionnalités."
@@ -46452,7 +47077,7 @@ msgid "Your DevOps Reports give an overview of how you are using GitLab from a f
msgstr "Vos Rapports DevOps apportent une vue d'ensemble de la façon dont vous utilisez GitLab du point de vue des fonctionnalités. Utilisez-les pour voir comment vous vous situez vis-à-vis d'autres organisations, et pour que vos équipes se comparent entre elles."
msgid "Your GPG keys (%{count})"
-msgstr ""
+msgstr "Vos clés GPG (%{count})"
msgid "Your GitLab account has been locked due to an excessive number of unsuccessful sign in attempts. You can wait for your account to automatically unlock in %{duration} or you can click the link below to unlock now."
msgstr "Votre compte GitLab a été verrouillé en raison d'un nombre excessif de tentatives de connexion infructueuses. Vous pouvez attendre que votre compte soit déverrouillé automatiquement dans %{duration} ou vous pouvez cliquer sur le lien ci-dessous pour le déverrouiller maintenant."
@@ -46485,16 +47110,16 @@ msgid "Your SSH key was deleted"
msgstr "Votre clé SSH a été supprimée"
msgid "Your SSH keys (%{count})"
-msgstr ""
+msgstr "Vos clés SSH (%{count})"
msgid "Your To-Do List"
msgstr "Votre liste de tâches"
msgid "Your U2F device did not send a valid JSON response."
-msgstr ""
+msgstr "Votre appareil U2F n'a pas envoyé de réponse JSON valide."
msgid "Your U2F device was registered!"
-msgstr ""
+msgstr "Votre appareil U2F a été enregistré !"
msgid "Your WebAuthn device did not send a valid JSON response."
msgstr "Votre appareil WebAuthn n'a pas envoyé de réponse JSON valide."
@@ -46503,13 +47128,13 @@ msgid "Your WebAuthn device was registered!"
msgstr "Votre appareil WebAuthn a été enregistré !"
msgid "Your access request to the %{source_type} has been withdrawn."
-msgstr ""
+msgstr "Votre demande d'accès au %{source_type} a été retirée."
msgid "Your account has been deactivated"
msgstr "Votre compte a été désactivé"
msgid "Your account has been deactivated by your administrator. Please log back in to reactivate your account."
-msgstr ""
+msgstr "Votre compte a été désactivé par votre administrateur. Veuillez vous reconnecter pour le réactiver."
msgid "Your account has been deactivated. You will not be able to: "
msgstr "Votre compte a été désactivé. Vous ne pourrez pas : "
@@ -46526,6 +47151,9 @@ msgstr "Votre compte est verrouillé."
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr "Votre action a été rejetée car la limite de stockage de l'espace de noms a été atteinte. Pour plus d'informations, consultez %{doc_url}."
+
msgid "Your action succeeded."
msgstr "Votre action a réussi."
@@ -46539,7 +47167,7 @@ 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 ""
+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+)."
@@ -46554,19 +47182,19 @@ msgid "Your changes have been saved"
msgstr "Vos modifications ont été enregistrées"
msgid "Your changes have been successfully committed."
-msgstr ""
+msgstr "Vos modifications ont été validées avec succès."
msgid "Your comment could not be submitted because %{error}"
msgstr "Votre commentaire n'a pas pu être soumis car %{error}"
msgid "Your comment could not be submitted! Please check your network connection and try again."
-msgstr ""
+msgstr "Votre commentaire n'a pas pu être soumis ! Veuillez vérifier votre connexion réseau et réessayer."
msgid "Your comment could not be updated! Please check your network connection and try again."
-msgstr ""
+msgstr "Votre commentaire n'a pas pu être mis à jour ! Veuillez vérifier votre connexion réseau et réessayer."
msgid "Your comment will be discarded."
-msgstr ""
+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."
@@ -46584,7 +47212,7 @@ msgid "Your default notification email is used for account notifications if a %{
msgstr "Votre courriel de notification par défaut est utilisé pour les notifications liées au compte dans le cas où aucune %{openingTag}adresse de courriel spécifique au groupe%{closingTag} n'est définie."
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
-msgstr ""
+msgstr "Vos services de déploiement seront cassés, vous devrez les réparer manuellement après le renommage."
msgid "Your device is not compatible with GitLab. Please try another device"
msgstr "Votre appareil n'est pas compatible avec GitLab. Veuillez essayer un autre appareil"
@@ -46593,7 +47221,7 @@ msgid "Your device needs to be set up. Plug it in (if needed) and click the butt
msgstr "Votre appareil doit être configuré. Branchez-le (si nécessaire) et cliquez sur le bouton à gauche."
msgid "Your device was successfully set up! Give it a name and register it with the GitLab server."
-msgstr ""
+msgstr "Votre appareil a été configuré avec succès ! Donnez-lui un nom et enregistrez-le auprès du serveur GitLab."
msgid "Your file must contain a column named %{codeStart}title%{codeEnd}. A %{codeStart}description%{codeEnd} column is optional. The maximum file size allowed is 10 MB."
msgstr "Votre fichier doit contenir une colonne nommée %{codeStart}title%{codeEnd}. Une colonne %{codeStart}description%{codeEnd} est optionnelle. La taille de fichier maximale autorisée est de 10 Mo."
@@ -46615,16 +47243,16 @@ msgid "Your instance has %{remaining_user_count} users remaining of the %{total_
msgstr "Votre instance dispose de %{remaining_user_count} utilisateurs restants sur les %{total_user_count} inclus dans votre abonnement. Vous pouvez en ajouter plus que le nombre inclus dans votre licence, et nous intégrerons le surplus à votre prochaine facture."
msgid "Your instance has exceeded your subscription's licensed user count."
-msgstr ""
+msgstr "Votre instance a dépassé le nombre d'utilisateurs sous licence de votre abonnement."
msgid "Your instance is approaching its licensed user count"
-msgstr ""
+msgstr "Votre instance approche du nombre d'utilisateurs sous licence"
msgid "Your issues are being imported. Once finished, you'll get a confirmation email."
-msgstr ""
+msgstr "Vos tickets sont en cours d'importation. Une fois terminé, vous recevrez un courriel de confirmation."
msgid "Your issues will be imported in the background. Once finished, you'll get a confirmation email."
-msgstr ""
+msgstr "Vos tickets seront importés en arrière-plan. Une fois terminé, vous recevrez un courriel de confirmation."
msgid "Your license does not support on-call rotations"
msgstr "Votre licence ne prend pas en charge les cycles de travail"
@@ -46633,7 +47261,7 @@ msgid "Your license does not support on-call schedules"
msgstr "Votre licence n'intègre pas les calendriers d'astreintes"
msgid "Your license is valid from"
-msgstr ""
+msgstr "Votre licence est valide du"
msgid "Your membership in %{group} no longer expires."
msgstr "Votre adhésion à %{group} ne va plus expirer."
@@ -46644,18 +47272,15 @@ msgstr "Votre message ici"
msgid "Your name"
msgstr "Votre nom"
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
+msgstr "Votre espace de noms %{namespace_name} dépasse la limite de %{free_limit} utilisateurs et a été placé en lecture seule."
+
msgid "Your new %{accessTokenType}"
msgstr "Votre nouveau %{accessTokenType}"
msgid "Your new %{accessTokenType} has been created."
msgstr "Votre nouveau %{accessTokenType} a été créé."
-msgid "Your new %{type}"
-msgstr ""
-
-msgid "Your new access token has been created."
-msgstr "Votre nouveau jeton d'accès a été créé."
-
msgid "Your new comment"
msgstr "Votre nouveau commentaire"
@@ -46663,7 +47288,7 @@ msgid "Your password"
msgstr "Votre mot de passe"
msgid "Your password reset token has expired."
-msgstr ""
+msgstr "Le jeton de réinitialisation de votre mot de passe a expiré."
msgid "Your personal access token has expired"
msgstr "Votre jeton d'accès personnel a expiré"
@@ -46681,7 +47306,7 @@ msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-0
msgstr "Votre projet ne bénéficie plus des avantages de GitLab Ultimate depuis le 01/07/2022. Comme précédemment notifié dans l'appli, les projets open source publics de l'édition Gratuite peuvent postuler au programme GitLab for Open Source pour profiter de ces avantages. Veuillez vous référer à la %{faq_link_start}FAQ%{link_end} pour plus d'informations."
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
-msgstr ""
+msgstr "Votre limite de projets est de %{limit} projets ! Veuillez contacter votre administrateur pour l'augmenter"
msgid "Your project will be created at:"
msgstr "Votre projet sera créé à :"
@@ -46696,7 +47321,7 @@ msgid "Your request for access could not be processed: %{error_message}"
msgstr "Votre demande d'accès n'a pas pu être traitée : %{error_message}"
msgid "Your request for access has been queued for review."
-msgstr ""
+msgstr "Votre demande d'accès a été mise en file d'attente pour examen."
msgid "Your request to join %{host} has been rejected."
msgstr "Votre demande pour rejoindre %{host} a été rejetée."
@@ -46742,6 +47367,9 @@ msgstr "Votre mise à jour a échoué. Vous devez téléverser un fichier de mê
msgid "Your username is %{username}."
msgstr "Votre nom d'utilisateur est %{username}."
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr "Échec du chargement du ticket ZenTao. Affichez le ticket dans ZenTao ou rechargez la page."
@@ -46791,10 +47419,10 @@ msgid "ZentaoIntegration|ZenTao issues"
msgstr "Tickets ZenTao"
msgid "Zoom meeting added"
-msgstr ""
+msgstr "Réunion Zoom ajoutée"
msgid "Zoom meeting removed"
-msgstr ""
+msgstr "Réunion Zoom supprimée"
msgid "[No reason]"
msgstr "[Sans raison]"
@@ -46811,9 +47439,6 @@ msgstr "« end_time » ne devrait pas dépasser « start_time » de plus d'un mo
msgid "`start_time` should precede `end_time`"
msgstr "L'heure de début « start_time » doit être antérieure à celle de fin « end_time »"
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr "L'indicateur de fonctionnalité « work_items_hierarchy » est désactivé sur ce projet"
-
msgid "a deleted user"
msgstr "un utilisateur supprimé"
@@ -46825,9 +47450,6 @@ msgstr[1] "environ %d heures"
msgid "access:"
msgstr "accès :"
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46876,7 +47498,7 @@ msgstr[0] "approbation"
msgstr[1] "approbations"
msgid "archived"
-msgstr ""
+msgstr "archivé"
msgid "archived:"
msgstr ""
@@ -46887,16 +47509,19 @@ msgstr "artéfacts"
msgid "assign yourself"
msgstr ""
-msgid "at"
+msgid "assigned"
msgstr ""
-msgid "at least the Reporter role"
+msgid "assigned you"
msgstr ""
-msgid "at least the Reporter role, the author, and assignees"
+msgid "at"
msgstr ""
-msgid "at risk"
+msgid "at least the Reporter role"
+msgstr "au moins le rôle de Rapporteur"
+
+msgid "at least the Reporter role, the author, and assignees"
msgstr ""
msgid "attach a new file"
@@ -46909,7 +47534,7 @@ msgid "banned user already exists"
msgstr "l’utilisateur banni existe déjà"
msgid "blocks"
-msgstr ""
+msgstr "bloque"
msgid "branch"
msgid_plural "branches"
@@ -46929,7 +47554,7 @@ msgid "cURL:"
msgstr "cURL :"
msgid "can contain only digits"
-msgstr ""
+msgstr "ne peut contenir que des chiffres"
msgid "can contain only letters of the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'"
msgstr "ne peut contenir que les lettres de l'alphabet Base64 (RFC4648) ainsi que « @ » et « . »"
@@ -46974,10 +47599,16 @@ msgid "cannot assign a non-confidential work item to a confidential parent. Make
msgstr "ne peut pas assigner un élément de travail non confidentiel à un parent confidentiel. Rendez cet élément de travail confidentiel et réessayez."
msgid "cannot be a date in the past"
-msgstr ""
+msgstr "ne peut pas être une date dans le passé"
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
-msgstr ""
+msgstr "ne peut pas être ajouté car vous avez atteint votre limite de %{free_limit} membres pour %{namespace_name}"
+
+msgid "cannot be associated with a subgroup"
+msgstr "ne peut pas être associé à un sous-groupe"
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr "ne peut pas être associé simultanément à un Groupe et à un Projet"
msgid "cannot be changed"
msgstr ""
@@ -47111,7 +47742,7 @@ msgid "ciReport|All images"
msgstr "Toutes les images"
msgid "ciReport|All projects"
-msgstr ""
+msgstr "Tous les projets"
msgid "ciReport|All severities"
msgstr ""
@@ -47129,10 +47760,10 @@ msgid "ciReport|Base pipeline codequality artifact not found"
msgstr "Artéfact de qualité de code du pipeline de base introuvable"
msgid "ciReport|Browser Performance"
-msgstr ""
+msgstr "Performances du navigateur"
msgid "ciReport|Browser performance test metrics results are being parsed"
-msgstr ""
+msgstr "Les résultats des métriques des tests de performance du navigateur sont en cours d’analyse"
msgid "ciReport|Browser performance test metrics: "
msgstr "Métriques du test de performances du navigateur : "
@@ -47174,7 +47805,7 @@ msgid "ciReport|Code quality scanning detected %{issueCount} changes in merged r
msgstr "L'analyse de la qualité du code a détecté %{issueCount} changements dans les résultats fusionnés"
msgid "ciReport|Container Scanning"
-msgstr ""
+msgstr "Analyse de Conteneurs"
msgid "ciReport|Container scanning"
msgstr "Analyse du conteneur"
@@ -47204,7 +47835,7 @@ msgid "ciReport|DAST"
msgstr "DAST"
msgid "ciReport|Dependency Scanning"
-msgstr ""
+msgstr "Analyse des Dépendances"
msgid "ciReport|Dependency Scanning detects known vulnerabilities in your source code's dependencies."
msgstr "L’analyse des dépendances a détecté une vulnérabilité connue dans les dépendances de votre code source."
@@ -47212,12 +47843,27 @@ msgstr "L’analyse des dépendances a détecté une vulnérabilité connue dans
msgid "ciReport|Dependency scanning"
msgstr "Analyse des dépendances"
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr "Test dynamique de la sécurité des applications (DAST)"
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr "Le test de sécurité d’applications dynamique (Dynamic Application Security Testing — DAST) a détecté une vulnérabilité connue dans votre application Web."
@@ -47240,7 +47886,7 @@ msgid "ciReport|Full Report"
msgstr "Rapport complet"
msgid "ciReport|Generic Report"
-msgstr ""
+msgstr "Rapport Générique"
msgid "ciReport|IaC Scanning"
msgstr "Analyse IaC"
@@ -47249,7 +47895,7 @@ msgid "ciReport|Investigate this vulnerability by creating an issue"
msgstr ""
msgid "ciReport|License Compliance"
-msgstr ""
+msgstr "Conformité de Licence"
msgid "ciReport|License Compliance failed loading results"
msgstr ""
@@ -47292,8 +47938,11 @@ msgstr ""
msgid "ciReport|New"
msgstr "Nouveau"
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr "Les nouvelles vulnérabilités sont des vulnérabilités que l’analyse de sécurité a détectées dans la demande de fusion mais qui sont différentes des vulnérabilités existantes dans la branche par défaut."
+
msgid "ciReport|No changes to Code Quality."
-msgstr ""
+msgstr "Aucun changement dans la qualité du code."
msgid "ciReport|No changes to code quality"
msgstr "Aucun changement dans la qualité du code"
@@ -47322,6 +47971,9 @@ msgstr "Détection de Secret"
msgid "ciReport|Security reports failed loading results"
msgstr "Les rapports de sécurité ont échoué à charger les résultats"
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr "Analyse de sécurité"
@@ -47337,6 +47989,9 @@ msgstr "Affichage de %{fetchedItems} éléments sur %{totalItems}"
msgid "ciReport|Solution"
msgstr "Solution"
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr "Test statique de la sécurité des applications (SAST)"
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr "Le test de sécurité d’applications statique (Static Application Security Testing — SAST) a détecté une vulnérabilité connue dans votre application Web."
@@ -47350,7 +48005,7 @@ msgid "ciReport|There was an error creating the issue. Please try again."
msgstr "Une erreur s’est produite lors de la création du ticket. Veuillez réessayer."
msgid "ciReport|There was an error creating the merge request. Please try again."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la création de la demande de fusion. Veuillez réessayer."
msgid "ciReport|There was an error dismissing the vulnerability. Please try again."
msgstr "Une erreur s’est produite lors du rejet de la vulnérabilité. Veuillez réessayer."
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47418,7 +48076,7 @@ msgid "contacts can only be added to root groups"
msgstr ""
msgid "container registry images"
-msgstr ""
+msgstr "images du registre de conteneurs"
msgid "contains URLs that exceed the 1024 character limit (%{urls})"
msgstr "contient des URL qui dépassent la limite de 1024 caractères (%{urls})"
@@ -47470,6 +48128,9 @@ msgstr[1] "jours"
msgid "days"
msgstr "jours"
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr "branche par défaut"
@@ -47509,7 +48170,7 @@ msgstr[0] "brouillon"
msgstr[1] "brouillons"
msgid "e.g. %{token}"
-msgstr ""
+msgstr "p. ex. %{token}"
msgid "element is not a hierarchy"
msgstr ""
@@ -47545,7 +48206,7 @@ msgid "epic"
msgstr "épopée"
msgid "error"
-msgstr ""
+msgstr "erreur"
msgid "estimateCommand|%{slash_command} overwrites the total estimated time."
msgstr "%{slash_command} écrase le temps passé total."
@@ -47588,14 +48249,14 @@ msgstr ""
msgid "file"
msgid_plural "files"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "fichier"
+msgstr[1] "fichiers"
msgid "finding is not found or is already attached to a vulnerability"
msgstr ""
msgid "following"
-msgstr ""
+msgstr "suivi(s)"
msgid "for"
msgstr "pendant"
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] "à partir de %d tâche"
msgstr[1] "à partir de %d tâches"
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr "frontmatter"
@@ -47639,7 +48303,7 @@ msgid "group access tokens"
msgstr "jetons d'accès de groupe"
msgid "group members"
-msgstr ""
+msgstr "membres du groupe"
msgid "groups"
msgstr "groupes"
@@ -47659,13 +48323,13 @@ msgid "has already been linked to another vulnerability"
msgstr "dispose déjà d'un lien vers une autre vulnérabilité"
msgid "has already been taken"
-msgstr ""
+msgstr "a déjà été pris"
msgid "has already been taken as Codename"
msgstr ""
msgid "has already been taken as Suite"
-msgstr ""
+msgstr "a déjà été pris comme Suite"
msgid "has been completed."
msgstr "a fini."
@@ -47677,7 +48341,7 @@ msgid "help"
msgstr "aide"
msgid "http:"
-msgstr ""
+msgstr "http:"
msgid "http://www.example.com"
msgstr "http://www.exemple.com"
@@ -47726,15 +48390,21 @@ msgstr "note interne"
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
-msgid "is an invalid IP address range"
+msgid "is already linked to this vulnerability"
msgstr ""
+msgid "is an invalid IP address range"
+msgstr "est une plage d'adresses IP non valide"
+
msgid "is blocked by"
msgstr "est bloqué par"
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr "n’est pas une URL valide."
+
msgid "is not a valid X509 certificate."
msgstr "n’est pas un certificat X.509 valide."
@@ -47777,12 +48450,18 @@ msgstr "n'est pas dans le groupe qui impose le Compte Géré de Groupe"
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr "est en lecture seule"
@@ -47879,7 +48558,7 @@ msgid "main_database"
msgstr "main_database"
msgid "manual"
-msgstr ""
+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"
@@ -47916,10 +48595,10 @@ msgid "most recent deployment"
msgstr ""
msgid "mrWidgetCommitsAdded|%{commitCount} and %{mergeCommitCount} will be added to %{targetBranch}%{squashedCommits}."
-msgstr ""
+msgstr "%{commitCount} et %{mergeCommitCount} seront ajoutés à %{targetBranch}%{squashedCommits}."
msgid "mrWidgetCommitsAdded|%{commitCount} will be added to %{targetBranch}."
-msgstr ""
+msgstr "%{commitCount} seront ajoutés à %{targetBranch}."
msgid "mrWidgetCommitsAdded|%{strongStart}1%{strongEnd} merge commit"
msgstr "%{strongStart}1%{strongEnd} commit de fusion"
@@ -47939,9 +48618,6 @@ 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|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr "%{linkStart}Configurer maintenant%{linkEnd} pour analyser votre code source à la recherche de failles de sécurité connues."
-
msgid "mrWidget|%{mergeError}."
msgstr "%{mergeError}."
@@ -47970,10 +48646,10 @@ msgid "mrWidget|Added to the merge train. There are %{mergeTrainPosition} merge
msgstr "Ajoutée au train de fusion. Il y a %{mergeTrainPosition} demandes de fusion en attente de fusion"
msgid "mrWidget|An error occurred while removing your approval."
-msgstr ""
+msgstr "Une erreur s'est produite lors du retrait de votre approbation."
msgid "mrWidget|An error occurred while retrieving approval data for this merge request."
-msgstr ""
+msgstr "Une erreur s'est produite lors de la récupération des données d’approbation pour cette demande de fusion."
msgid "mrWidget|An error occurred while submitting your approval."
msgstr "Une erreur est survenue lors de l’envoi de votre approbation."
@@ -47982,7 +48658,7 @@ msgid "mrWidget|Approval is optional"
msgstr "L'approbation est facultative"
msgid "mrWidget|Approval password is invalid."
-msgstr ""
+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}"
@@ -48038,7 +48714,7 @@ msgid "mrWidget|Create issue to resolve all threads"
msgstr "Créer un ticket pour résoudre tous les fils de conversation"
msgid "mrWidget|Delete source branch"
-msgstr ""
+msgstr "Supprimer la branche source"
msgid "mrWidget|Deployment statistics are not available currently"
msgstr "Les statistiques de déploiement ne sont pas disponibles pour le moment"
@@ -48090,6 +48766,9 @@ msgstr "Fusion bloquée : une clé de ticket Jira doit être citée dans le titr
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."
@@ -48169,7 +48848,7 @@ msgid "mrWidget|Refreshing now"
msgstr "Actualisation en cours"
msgid "mrWidget|Remove from merge train"
-msgstr ""
+msgstr "Supprimer du train de fusion"
msgid "mrWidget|Resolve conflicts"
msgstr "Résoudre les conflits"
@@ -48184,10 +48863,7 @@ msgid "mrWidget|Revert this merge request in a new merge request"
msgstr "Défaire cette demande de fusion dans une nouvelle demande de fusion"
msgid "mrWidget|Revoke approval"
-msgstr ""
-
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr "SAST et la Détection de Secrets ne sont pas activés."
+msgstr "Révoquer l'approbation"
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr "Configuré par %{merge_author} pour être ajouté au train de fusion lorsque le pipeline réussit"
@@ -48211,7 +48887,7 @@ msgid "mrWidget|This merge request failed to be merged automatically"
msgstr "Cette demande de fusion n’a pas pu être fusionnée automatiquement"
msgid "mrWidget|To approve this merge request, please enter your password. This project requires all approvals to be authenticated."
-msgstr ""
+msgstr "Pour approuver cette demande de fusion, veuillez saisir votre mot de passe. Ce projet nécessite que toutes les approbations soient authentifiées."
msgid "mrWidget|To change these default messages, edit the templates for both the merge and squash commit messages. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
@@ -48247,11 +48923,14 @@ msgid "must be a valid json schema"
msgstr "doit être un schéma json valide"
msgid "must be after start"
-msgstr ""
+msgstr "doit être après le début"
msgid "must be an email you have verified"
msgstr "doit être un courriel que vous avez vérifié"
+msgid "must be associated with a Group or a Project"
+msgstr "doit être associé à un Groupe ou à un Projet"
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr "doit être inférieur à la limite de %{tag_limit} étiquettes"
msgid "must be set for a project namespace"
msgstr "doit être défini pour un espace de noms de projet"
+msgid "must be top-level namespace"
+msgstr "doit être un espace de noms de niveau supérieur"
+
msgid "must be unique by status and elapsed time within a policy"
msgstr "doit être unique au niveau état et temps écoulé dans une politique"
+msgid "must belong to same project of the work item."
+msgstr "doit appartenir au même projet que l'élément de travail."
+
msgid "must have a repository"
msgstr "doit avoir un dépôt"
@@ -48285,9 +48970,6 @@ msgstr "mon-canal"
msgid "my-topic"
msgstr "mon-sujet"
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48325,19 +49007,16 @@ msgid "not found"
msgstr ""
msgid "nounSeries|%{firstItem} and %{lastItem}"
-msgstr ""
+msgstr "%{firstItem} et %{lastItem}"
msgid "nounSeries|%{item}"
msgstr "%{item}"
msgid "nounSeries|%{item}, %{nextItem}"
-msgstr ""
+msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
-msgstr ""
-
-msgid "on track"
-msgstr ""
+msgstr "%{item}, et %{lastItem}"
msgid "only %{parent_types} can be parent of Task."
msgstr "seuls des %{parent_types} peuvent être parents d'une Tâche."
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] "sur un total de %d test"
-msgstr[1] "sur un total de %d tests"
-
msgid "packages"
msgstr "paquets"
msgid "pages"
msgstr "pages"
+msgid "params is empty"
+msgstr "params est vide"
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "parent"
@@ -48395,7 +49072,7 @@ msgid "personal access tokens"
msgstr "jetons d'accès personnels"
msgid "pipeline"
-msgstr ""
+msgstr "pipeline"
msgid "pipeline schedules documentation"
msgstr "documentation des planifications de pipeline"
@@ -48477,10 +49154,10 @@ msgid "recent activity"
msgstr "activité récente"
msgid "register"
-msgstr ""
+msgstr "inscrire"
msgid "relates to"
-msgstr ""
+msgstr "a un lien avec"
msgid "remaining"
msgstr "restant"
@@ -48497,9 +49174,6 @@ msgstr "supprimer la date de début"
msgid "remove weight"
msgstr "supprimer le poids"
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr "dépôts"
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] "dépôt"
+msgstr[1] "dépôts"
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48541,7 +49223,7 @@ msgstr[0] "siège"
msgstr[1] "sièges"
msgid "security Reports|There was an error creating the merge request"
-msgstr ""
+msgstr "Une erreur s’est produite lors de la création de la demande de fusion"
msgid "selective_code_owner_removals can only be enabled when retain_approvals_on_push is enabled"
msgstr "selective_code_owner_removals ne peut être activé que si retain_approvals_on_push est activé"
@@ -48595,7 +49277,7 @@ msgid "show less"
msgstr "afficher moins"
msgid "sign in"
-msgstr ""
+msgstr "connecter"
msgid "smartcn custom analyzer"
msgstr "analyseur personnalisé smartcn"
@@ -48613,7 +49295,7 @@ msgid "spendCommand|%{slash_command} adds or subtracts time already spent."
msgstr "%{slash_command} ajoute ou soustrait du temps déjà passé."
msgid "ssh:"
-msgstr ""
+msgstr "ssh:"
msgid "started a discussion on %{design_link}"
msgstr ""
@@ -48631,13 +49313,13 @@ msgid "stuck"
msgstr ""
msgid "success"
-msgstr ""
+msgstr "réussi"
msgid "suggestPipeline|1/2: Choose a template"
-msgstr ""
+msgstr "1/2 : Choisissez un modèle"
msgid "suggestPipeline|2/2: Commit your changes"
-msgstr ""
+msgstr "2/2 : Validez vos modifications"
msgid "suggestPipeline|Choose %{boldStart}Code Quality%{boldEnd} to add a pipeline that tests the quality of your code."
msgstr "Choisissez %{boldStart}Qualité de Code%{boldEnd} pour ajouter un pipeline qui teste la qualité de votre code."
@@ -48649,7 +49331,7 @@ msgid "suggestPipeline|We’re adding a GitLab CI configuration file to add a pi
msgstr "Nous ajoutons un fichier de configuration GitLab CI pour ajouter un pipeline au projet. Vous pouvez le créer manuellement, mais nous vous recommandons de commencer avec un modèle GitLab qui fonctionnera aussitôt."
msgid "supported SSH public key."
-msgstr ""
+msgstr "clé publique SSH prise en charge."
msgid "tag name"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr "ce document"
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr "à vous-même"
+
msgid "today"
msgstr "aujourd'hui"
@@ -48744,13 +49429,13 @@ msgid "verify ownership"
msgstr ""
msgid "version %{versionIndex}"
-msgstr ""
+msgstr "version %{versionIndex}"
msgid "via %{closed_via}"
-msgstr ""
+msgstr "via %{closed_via}"
msgid "via merge request %{link}"
-msgstr ""
+msgstr "via la demande de fusion %{link}"
msgid "view it on GitLab"
msgstr "voir sur GitLab"
@@ -48773,25 +49458,25 @@ msgid "vulnerability|Add a comment"
msgstr "Ajouter un commentaire"
msgid "vulnerability|Add a comment or reason for dismissal"
-msgstr ""
+msgstr "Ajouter un commentaire ou une raison de rejet"
msgid "vulnerability|Add comment"
msgstr "Ajouter un commentaire"
msgid "vulnerability|Add comment & dismiss"
-msgstr ""
+msgstr "Ajouter un commentaire et rejeter"
msgid "vulnerability|Add comment and dismiss"
msgstr "Ajouter un commentaire et rejeter"
msgid "vulnerability|Dismiss vulnerability"
-msgstr ""
+msgstr "Rejeter la vulnérabilité"
msgid "vulnerability|Save comment"
msgstr "vulnerability|Enregistrer le commentaire"
msgid "vulnerability|Undo dismiss"
-msgstr ""
+msgstr "Annuler le rejet"
msgid "vulnerability|dismissed"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr "vous"
+
msgid "your GitLab instance"
msgstr "votre instance GitLab"
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 8160d48fd95..64f787b32f3 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -248,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -273,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -358,6 +343,11 @@ msgid_plural "%d more comments"
msgstr[0] ""
msgstr[1] ""
+msgid "%d package"
+msgid_plural "%d packages"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d pending comment"
msgid_plural "%d pending comments"
msgstr[0] ""
@@ -575,6 +565,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -583,6 +583,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -605,6 +610,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -644,9 +654,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -857,12 +864,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -963,7 +964,7 @@ msgstr ""
msgid "%{reportType} detected %{totalStart}%{total}%{totalEnd} potential %{vulnMessage}"
msgstr ""
-msgid "%{reportType} detected no %{totalStart}new%{totalEnd} vulnerabilities."
+msgid "%{reportType} detected no new vulnerabilities."
msgstr ""
msgid "%{retryButtonStart}Try again%{retryButtonEnd} or %{newFileButtonStart}attach a new file%{newFileButtonEnd}."
@@ -1112,6 +1113,11 @@ msgstr ""
msgid "%{text} is available"
msgstr ""
+msgid "%{thenLabelStart}Then%{thenLabelEnd} Require %{approvalsRequired} approval from %{approverType}%{approvers}"
+msgid_plural "%{thenLabelStart}Then%{thenLabelEnd} Require %{approvalsRequired} approvals from %{approverType}%{approvers}"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{timebox_type} does not support burnup charts"
msgstr ""
@@ -1151,6 +1157,9 @@ msgstr ""
msgid "%{type} only supports %{name} name"
msgstr ""
+msgid "%{url} (optional)"
+msgstr ""
+
msgid "%{userName} (cannot merge)"
msgstr ""
@@ -1193,9 +1202,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1648,9 +1654,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1729,9 +1732,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -2125,9 +2125,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2662,6 +2659,9 @@ msgstr ""
msgid "AdminArea|Total users"
msgstr ""
+msgid "AdminArea|Updated %{last_update_time}"
+msgstr ""
+
msgid "AdminArea|Users"
msgstr ""
@@ -2689,6 +2689,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2725,15 +2743,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2782,6 +2812,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2827,6 +2860,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2917,7 +2962,7 @@ msgstr ""
msgid "AdminSettings|Select a CI/CD template"
msgstr ""
-msgid "AdminSettings|Select a group to use as the source for instance-level project templates."
+msgid "AdminSettings|Select a group to use as a source of custom templates for new projects. %{link_start}Learn more%{link_end}."
msgstr ""
msgid "AdminSettings|Select to disable public access for Pages sites, which requires users to sign in for access to the Pages sites in your instance. %{link_start}Learn more.%{link_end}"
@@ -2965,13 +3010,19 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
-msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
+msgid "AdminSettings|The host of your Jitsu instance."
msgstr ""
-msgid "AdminSettings|The projects in this group can be selected as templates for new projects created on the instance. %{link_start}Learn more.%{link_end} "
+msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
msgid "AdminSettings|The template for the required pipeline configuration can be one of the GitLab-provided templates, or a custom template added to an instance template repository. %{link_start}How do I create an instance template repository?%{link_end}"
@@ -2992,6 +3043,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3094,6 +3154,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3286,7 +3349,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3331,7 +3394,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3394,7 +3457,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3442,6 +3505,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3967,6 +4033,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -4003,9 +4072,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4440,9 +4506,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4542,9 +4605,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4647,9 +4707,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4668,7 +4725,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4711,6 +4768,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4729,9 +4789,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4759,6 +4828,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5099,9 +5171,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5203,7 +5272,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5254,6 +5323,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5305,9 +5398,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5701,9 +5791,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6067,6 +6154,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6795,6 +6888,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6804,6 +6900,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6816,6 +6915,12 @@ msgstr ""
msgid "BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or production/* are supported."
msgstr ""
+msgid "BranchRules|%{total} approval %{subject}"
+msgstr ""
+
+msgid "BranchRules|%{total} status %{subject}"
+msgstr ""
+
msgid "BranchRules|All branches"
msgstr ""
@@ -6825,6 +6930,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6843,7 +6951,7 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
-msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Lean more.%{linkEnd}"
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
msgid "BranchRules|Branch"
@@ -6855,6 +6963,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6879,6 +6990,9 @@ msgstr ""
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6900,12 +7014,18 @@ msgstr ""
msgid "BranchRules|Required approvals (%{total})"
msgstr ""
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -6915,9 +7035,6 @@ msgstr ""
msgid "BranchRules|default"
msgstr ""
-msgid "BranchRules|protected"
-msgstr ""
-
msgid "Branches"
msgstr ""
@@ -6927,6 +7044,9 @@ msgstr ""
msgid "Branches: %{source_branch} → %{target_branch}"
msgstr ""
+msgid "Branches|A branch won't be deleted if it is protected or associated with an open merge request."
+msgstr ""
+
msgid "Branches|Active"
msgstr ""
@@ -6948,7 +7068,10 @@ msgstr ""
msgid "Branches|Compare"
msgstr ""
-msgid "Branches|Delete all branches that are merged into '%{default_branch}'"
+msgid "Branches|Delete all branches that are merged into '%{defaultBranch}'"
+msgstr ""
+
+msgid "Branches|Delete all merged branches?"
msgstr ""
msgid "Branches|Delete branch"
@@ -6969,9 +7092,6 @@ msgstr ""
msgid "Branches|Deleting the %{strongStart}%{branchName}%{strongEnd} branch cannot be undone. Are you sure?"
msgstr ""
-msgid "Branches|Deleting the merged branches cannot be undone. Are you sure?"
-msgstr ""
-
msgid "Branches|Filter by branch name"
msgstr ""
@@ -6993,6 +7113,9 @@ msgstr ""
msgid "Branches|Please type the following to confirm:"
msgstr ""
+msgid "Branches|Plese type the following to confirm: %{codeStart}delete%{codeEnd}."
+msgstr ""
+
msgid "Branches|Show active branches"
msgstr ""
@@ -7026,6 +7149,12 @@ msgstr ""
msgid "Branches|This branch hasn't been merged into %{defaultBranchName}. To avoid data loss, consider merging this branch before deleting it."
msgstr ""
+msgid "Branches|This bulk action is %{strongStart}permanent and cannot be undone or recovered%{strongEnd}."
+msgstr ""
+
+msgid "Branches|This may include merged branches that are not visible on the current screen."
+msgstr ""
+
msgid "Branches|To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above."
msgstr ""
@@ -7038,6 +7167,9 @@ msgstr ""
msgid "Branches|Yes, delete protected branch"
msgstr ""
+msgid "Branches|You are about to %{strongStart}delete all branches%{strongEnd} that were merged into %{codeStart}%{defaultBranch}%{codeEnd}."
+msgstr ""
+
msgid "Branches|You're about to permanently delete the branch %{branchName}."
msgstr ""
@@ -7077,9 +7209,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7095,6 +7224,9 @@ msgstr ""
msgid "BuildArtifacts|Loading artifacts"
msgstr ""
+msgid "Building your merge request. Wait a few moments, then refresh this page."
+msgstr ""
+
msgid "Built-in"
msgstr ""
@@ -7125,9 +7257,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7158,6 +7287,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7173,6 +7305,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7197,9 +7332,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7613,9 +7745,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7631,6 +7760,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -7901,6 +8033,9 @@ msgstr ""
msgid "ChatMessage|Pipeline %{pipeline_link} of %{ref_type} %{ref_link} by %{user_combined_name} %{humanized_status}"
msgstr ""
+msgid "ChatMessage|Pipeline name"
+msgstr ""
+
msgid "ChatMessage|Tag"
msgstr ""
@@ -8370,6 +8505,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9685,10 +9823,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -10668,10 +10812,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10704,6 +10848,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10722,9 +10875,6 @@ msgstr ""
msgid "Control how the CI_JOB_TOKEN CI/CD variable is used for API access between projects."
msgstr ""
-msgid "Control how the GitLab Package Registry functions."
-msgstr ""
-
msgid "Control whether to display customer experience improvement content and third-party offers in GitLab."
msgstr ""
@@ -10752,9 +10902,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10839,9 +10986,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -11004,9 +11148,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11226,9 +11367,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11496,9 +11634,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11514,7 +11649,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11526,6 +11661,9 @@ msgstr ""
msgid "Credit card:"
msgstr ""
+msgid "Critical - S1"
+msgstr ""
+
msgid "Critical vulnerabilities present"
msgstr ""
@@ -11616,9 +11754,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11939,12 +12074,18 @@ msgstr ""
msgid "DORA4Metrics|Average (last %{days}d)"
msgstr ""
+msgid "DORA4Metrics|Change Failure Rate"
+msgstr ""
+
msgid "DORA4Metrics|Change failure rate"
msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11954,9 +12095,15 @@ msgstr ""
msgid "DORA4Metrics|Days from merge to deploy"
msgstr ""
+msgid "DORA4Metrics|Deployment Frequency"
+msgstr ""
+
msgid "DORA4Metrics|Deployment frequency"
msgstr ""
+msgid "DORA4Metrics|Lead Time for Changes"
+msgstr ""
+
msgid "DORA4Metrics|Lead time for changes"
msgstr ""
@@ -11972,6 +12119,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -12005,6 +12155,9 @@ msgstr ""
msgid "DORA4Metrics|The chart displays the median time between a merge request being merged and deployed to production environment(s) that are based on the %{linkStart}deployment_tier%{linkEnd} value."
msgstr ""
+msgid "DORA4Metrics|Time to Restore Service"
+msgstr ""
+
msgid "DORA4Metrics|Time to restore service"
msgstr ""
@@ -12487,6 +12640,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12724,6 +12880,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12745,9 +12904,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12814,7 +12970,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13291,6 +13447,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13378,6 +13537,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13959,6 +14133,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13974,11 +14154,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14167,9 +14353,6 @@ msgstr ""
msgid "Do not force push over diverged refs. After the mirror is created, this setting can only be modified using the API. %{mirroring_docs_link_start}Learn more about this option%{link_closing_tag} and %{mirroring_api_docs_link_start}the API.%{link_closing_tag}"
msgstr ""
-msgid "Do not show again"
-msgstr ""
-
msgid "Do you want to remove this deploy key?"
msgstr ""
@@ -15022,6 +15205,9 @@ msgstr ""
msgid "Enter at least three characters to search"
msgstr ""
+msgid "Enter at least three characters to search."
+msgstr ""
+
msgid "Enter in your Bitbucket Server URL and personal access token below"
msgstr ""
@@ -15373,9 +15559,6 @@ msgstr ""
msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
-msgstr ""
-
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr ""
@@ -15388,18 +15571,6 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
-msgid "Epics|Show more"
-msgstr ""
-
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15412,18 +15583,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15616,9 +15781,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -16029,6 +16191,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -16086,7 +16251,10 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
-msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
+msgid "Experiment Candidates"
+msgstr ""
+
+msgid "Experiments"
msgstr ""
msgid "Expiration"
@@ -16558,9 +16726,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16818,6 +16983,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16923,9 +17091,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -17082,6 +17247,9 @@ msgstr ""
msgid "Followed users"
msgstr ""
+msgid "Following tags don't exist"
+msgstr ""
+
msgid "Font Color"
msgstr ""
@@ -17133,6 +17301,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17226,9 +17397,6 @@ msgstr ""
msgid "Format: %{dateFormat}"
msgstr ""
-msgid "Forward %{package_type} package requests to the %{registry_type} Registry if the packages are not found in the GitLab Package Registry"
-msgstr ""
-
msgid "Found errors in your %{gitlab_ci_yml}:"
msgstr ""
@@ -17966,9 +18134,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -18095,6 +18260,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18146,6 +18317,9 @@ 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 ""
@@ -18194,9 +18368,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18650,6 +18821,9 @@ msgstr ""
msgid "Go to your projects"
msgstr ""
+msgid "Go to your review requests"
+msgstr ""
+
msgid "Go to your snippets"
msgstr ""
@@ -18752,9 +18926,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -19298,7 +19469,7 @@ msgstr ""
msgid "GroupSettings|Reporting"
msgstr ""
-msgid "GroupSettings|Select a subgroup to use as the source for custom project templates for this group."
+msgid "GroupSettings|Select a subgroup to use as a source of custom templates for new projects in this group. %{link_start}Learn more%{link_end}."
msgstr ""
msgid "GroupSettings|Select parent group"
@@ -19319,9 +19490,6 @@ msgstr ""
msgid "GroupSettings|The Auto DevOps pipeline runs if no alternative CI configuration file is found."
msgstr ""
-msgid "GroupSettings|The projects in this subgroup can be selected as templates for new projects created in the group. %{link_start}Learn more.%{link_end}"
-msgstr ""
-
msgid "GroupSettings|There was a problem updating Auto DevOps pipeline: %{error_messages}."
msgstr ""
@@ -19936,12 +20104,18 @@ msgstr ""
msgid "Hierarchy|You can start using these items now."
msgstr ""
+msgid "High - S2"
+msgstr ""
+
msgid "High or unknown vulnerabilities present"
msgstr ""
msgid "Highest role:"
msgstr ""
+msgid "Highlight"
+msgstr ""
+
msgid "HighlightBar|Alert events:"
msgstr ""
@@ -20242,9 +20416,6 @@ msgstr ""
msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
-msgstr ""
-
msgid "IdentityVerification|The code has expired. Send a new code and try again."
msgstr ""
@@ -20329,12 +20500,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21187,12 +21352,18 @@ msgstr ""
msgid "Incident Management Limits"
msgstr ""
+msgid "Incident creation cancelled."
+msgstr ""
+
msgid "Incident details"
msgstr ""
msgid "Incident template (optional)."
msgstr ""
+msgid "Incident title"
+msgstr ""
+
msgid "IncidentManagement|%{hours} hours, %{minutes} minutes remaining"
msgstr ""
@@ -22107,9 +22278,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22167,7 +22335,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22247,19 +22415,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22397,12 +22562,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22661,10 +22832,22 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
-msgid "Issue|Title"
+msgid "Issues|Move selected"
msgstr ""
-msgid "It is not possible to %{action} files that are stored in LFS using the web interface"
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
+msgid "Issue|Title"
msgstr ""
msgid "It looks like you have some draft commits in this branch."
@@ -22955,6 +23138,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23285,6 +23471,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23324,9 +23513,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23703,9 +23898,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23859,6 +24051,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24009,9 +24210,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24258,6 +24456,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24474,10 +24678,10 @@ msgstr ""
msgid "Locked by %{fileLockUserName}"
msgstr ""
-msgid "Locked the discussion."
+msgid "Locked files"
msgstr ""
-msgid "Locks give the ability to lock specific file or folder."
+msgid "Locked the discussion."
msgstr ""
msgid "Locks the discussion."
@@ -24528,7 +24732,7 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
+msgid "Low - S4"
msgstr ""
msgid "Low vulnerabilities present"
@@ -24543,6 +24747,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24579,7 +24786,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24600,6 +24813,9 @@ msgstr ""
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24609,9 +24825,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24621,12 +24834,15 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
msgstr ""
+msgid "Manage Dashboards"
+msgstr ""
+
msgid "Manage Web IDE features."
msgstr ""
@@ -24678,6 +24894,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24702,6 +24921,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -25119,6 +25341,9 @@ msgstr ""
msgid "Measured in bytes of code. Excludes generated and vendored code."
msgstr ""
+msgid "Medium - S3"
+msgstr ""
+
msgid "Medium timeout"
msgstr ""
@@ -25399,6 +25624,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25624,6 +25852,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -26252,6 +26483,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26754,6 +26988,9 @@ msgstr ""
msgid "New identity"
msgstr ""
+msgid "New incident"
+msgstr ""
+
msgid "New issue"
msgstr ""
@@ -27033,9 +27270,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -27063,9 +27297,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -27081,9 +27312,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,6 +27366,9 @@ msgstr ""
msgid "No results found"
msgstr ""
+msgid "No results found."
+msgstr ""
+
msgid "No runner executable"
msgstr ""
@@ -27652,6 +27883,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27781,9 +28015,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27808,9 +28039,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -28044,12 +28272,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28095,12 +28317,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28122,12 +28338,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28170,15 +28380,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28209,12 +28410,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28233,9 +28428,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28409,9 +28601,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28694,6 +28883,9 @@ msgstr ""
msgid "PackageRegistry|Conan Command"
msgstr ""
+msgid "PackageRegistry|Configure package forwarding and package file size limits."
+msgstr ""
+
msgid "PackageRegistry|Copy .pypirc content"
msgstr ""
@@ -28783,6 +28975,9 @@ msgstr ""
msgid "PackageRegistry|Delete package version"
msgstr ""
+msgid "PackageRegistry|Delete packages"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
@@ -28798,6 +28993,12 @@ msgstr ""
msgid "PackageRegistry|Duplicate packages"
msgstr ""
+msgid "PackageRegistry|Enforce %{packageType} setting for all subgroups"
+msgstr ""
+
+msgid "PackageRegistry|Enforce %{package_type} setting for all subgroups"
+msgstr ""
+
msgid "PackageRegistry|Error publishing"
msgstr ""
@@ -28822,6 +29023,18 @@ msgstr ""
msgid "PackageRegistry|For more information on the PyPi registry, %{linkStart}see the documentation%{linkEnd}."
msgstr ""
+msgid "PackageRegistry|Forward %{packageType} package requests"
+msgstr ""
+
+msgid "PackageRegistry|Forward %{package_type} package requests"
+msgstr ""
+
+msgid "PackageRegistry|Forward package requests"
+msgstr ""
+
+msgid "PackageRegistry|Forward package requests to a public registry if the packages are not found in the GitLab package registry."
+msgstr ""
+
msgid "PackageRegistry|Generic"
msgstr ""
@@ -28840,6 +29053,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28903,6 +29122,9 @@ msgstr ""
msgid "PackageRegistry|Package formats"
msgstr ""
+msgid "PackageRegistry|Package forwarding"
+msgstr ""
+
msgid "PackageRegistry|Package has %{updatesCount} archived update"
msgid_plural "PackageRegistry|Package has %{updatesCount} archived updates"
msgstr[0] ""
@@ -28911,6 +29133,9 @@ msgstr[1] ""
msgid "PackageRegistry|Package updated by commit %{link} on branch %{branch}, built by pipeline %{pipeline}, and published to the registry %{datetime}"
msgstr ""
+msgid "PackageRegistry|Packages deleted successfully"
+msgstr ""
+
msgid "PackageRegistry|Permanently delete"
msgstr ""
@@ -28965,6 +29190,9 @@ msgstr ""
msgid "PackageRegistry|Show Yarn commands"
msgstr ""
+msgid "PackageRegistry|Something went wrong while deleting packages."
+msgstr ""
+
msgid "PackageRegistry|Something went wrong while deleting the package asset."
msgstr ""
@@ -28986,6 +29214,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29033,6 +29264,11 @@ msgid_plural "PackageRegistry|You are about to delete %d assets. This operation
msgstr[0] ""
msgstr[1] ""
+msgid "PackageRegistry|You are about to delete 1 package. This operation is irreversible."
+msgid_plural "PackageRegistry|You are about to delete %d packages. This operation is irreversible."
+msgstr[0] ""
+msgstr[1] ""
+
msgid "PackageRegistry|You are about to delete version %{version} of %{name}. Are you sure?"
msgstr ""
@@ -29417,12 +29653,30 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
msgstr ""
+msgid "PhoneVerification|Enter a valid code."
+msgstr ""
+
+msgid "PhoneVerification|Something went wrong. Please try again."
+msgstr ""
+
+msgid "PhoneVerification|The code has expired. Request a new code and try again."
+msgstr ""
+
+msgid "PhoneVerification|There was a problem with the phone number you entered. Enter a different phone number and try again."
+msgstr ""
+
+msgid "PhoneVerification|There was a problem with the phone number you entered. Enter a valid phone number."
+msgstr ""
+
+msgid "PhoneVerification|You've reached the maximum number of tries. Request a new code and try again."
+msgstr ""
+
msgid "Pick a name"
msgstr ""
@@ -29654,6 +29908,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29666,12 +29923,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29687,6 +29950,9 @@ msgstr ""
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30326,6 +30592,9 @@ msgstr ""
msgid "Please click the link in the confirmation email before continuing. It was sent to %{html_tag_strong_start}%{email}%{html_tag_strong_end}."
msgstr ""
+msgid "Please complete the incident creation form."
+msgstr ""
+
msgid "Please complete your profile with email address"
msgstr ""
@@ -30446,9 +30715,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30560,24 +30826,66 @@ msgstr ""
msgid "PreScanVerification|(optional)"
msgstr ""
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
msgstr ""
msgid "PreScanVerification|Pre-scan verification"
msgstr ""
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
msgid "PreScanVerification|Started %{timeAgo} in pipeline"
msgstr ""
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
msgstr ""
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
msgid "PreScanVerification|Verify configuration"
msgstr ""
msgid "PreScanVerification|View results"
msgstr ""
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30719,6 +31027,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30812,7 +31123,7 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
msgstr ""
msgid "ProductAnalytics|Audience"
@@ -31400,6 +31711,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31412,6 +31726,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31694,12 +32011,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31712,12 +32035,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31739,6 +32068,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31838,6 +32170,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31976,6 +32311,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -32006,6 +32344,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -32057,6 +32398,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32696,6 +33040,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32732,15 +33079,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32756,12 +33115,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -33071,6 +33439,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33203,12 +33574,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33302,9 +33667,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33985,18 +34347,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34007,12 +34363,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -34055,21 +34405,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34085,9 +34426,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34599,7 +34937,7 @@ msgstr ""
msgid "Review time"
msgstr ""
-msgid "Review time is defined as the time it takes from first comment until merged."
+msgid "Review time is the amount of time since the first comment in a merge request."
msgstr ""
msgid "ReviewApp|Enable Review App"
@@ -34691,6 +35029,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34760,9 +35101,6 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
-msgstr ""
-
msgid "Runners|Administrator"
msgstr ""
@@ -34781,6 +35119,9 @@ msgstr ""
msgid "Runners|An error has occurred fetching instructions"
msgstr ""
+msgid "Runners|An error occurred while deleting. Some runners may not have been deleted."
+msgstr ""
+
msgid "Runners|An upgrade is available for this runner"
msgstr ""
@@ -35240,12 +35581,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35279,6 +35614,9 @@ msgstr ""
msgid "Runner|Owner"
msgstr ""
+msgid "Runner|Runner %{runnerName} failed to delete"
+msgstr ""
+
msgid "Running"
msgstr ""
@@ -35624,9 +35962,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -36033,10 +36368,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -36090,6 +36428,9 @@ msgstr ""
msgid "SecurityOrchestration|Choose a project"
msgstr ""
+msgid "SecurityOrchestration|Choose approver type"
+msgstr ""
+
msgid "SecurityOrchestration|Create more robust vulnerability rules and apply them to all your projects."
msgstr ""
@@ -36147,15 +36488,24 @@ msgstr ""
msgid "SecurityOrchestration|Failed to load vulnerability scanners."
msgstr ""
+msgid "SecurityOrchestration|Groups"
+msgstr ""
+
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
msgstr ""
+msgid "SecurityOrchestration|Individual users"
+msgstr ""
+
msgid "SecurityOrchestration|Inherited"
msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36258,10 +36608,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36285,6 +36635,9 @@ msgstr ""
msgid "SecurityOrchestration|Select security project"
msgstr ""
+msgid "SecurityOrchestration|Select users"
+msgstr ""
+
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@@ -36351,7 +36704,10 @@ 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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+msgstr ""
+
+msgid "SecurityOrchestration|Use a scan result policy to create rules that check for security vulnerabilities and license compliance before merging a merge request."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36369,6 +36725,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36387,12 +36746,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36405,6 +36773,9 @@ msgstr ""
msgid "SecurityReports|%{firstProject}, %{secondProject}, and %{rest}"
msgstr ""
+msgid "SecurityReports|Activity"
+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 ""
@@ -36414,6 +36785,12 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
+msgid "SecurityReports|All statuses"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36543,6 +36920,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36600,6 +36980,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36738,6 +37121,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36774,6 +37160,9 @@ msgstr ""
msgid "Select a file from the left sidebar to begin editing. Afterwards, you'll be able to commit your changes."
msgstr ""
+msgid "Select a group"
+msgstr ""
+
msgid "Select a label"
msgstr ""
@@ -36801,9 +37190,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36882,6 +37268,9 @@ msgstr ""
msgid "Select reviewer(s)"
msgstr ""
+msgid "Select severity (optional)"
+msgstr ""
+
msgid "Select source"
msgstr ""
@@ -36942,10 +37331,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36957,28 +37346,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37197,9 +37586,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37349,9 +37735,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37502,6 +37885,9 @@ msgstr ""
msgid "Show list"
msgstr ""
+msgid "Show more"
+msgstr ""
+
msgid "Show one file at a time"
msgstr ""
@@ -37606,10 +37992,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37801,9 +38184,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37840,6 +38220,9 @@ msgstr ""
msgid "SlackIntegration|Install Slack app"
msgstr ""
+msgid "SlackIntegration|Notifications only work if you're on the latest version of the GitLab for Slack app"
+msgstr ""
+
msgid "SlackIntegration|Project alias"
msgstr ""
@@ -37867,6 +38250,9 @@ msgstr ""
msgid "SlackIntegration|This integration allows users to perform common operations on this project by entering slash commands in Slack."
msgstr ""
+msgid "SlackIntegration|Update to the latest version"
+msgstr ""
+
msgid "SlackIntegration|Verification token"
msgstr ""
@@ -38026,6 +38412,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38071,6 +38460,9 @@ msgstr ""
msgid "Something went wrong while closing the epic. Please try again later."
msgstr ""
+msgid "Something went wrong while closing the incident form."
+msgstr ""
+
msgid "Something went wrong while closing the merge request. Please try again later."
msgstr ""
@@ -38140,6 +38532,9 @@ msgstr ""
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
+msgid "Something went wrong while opening the incident form."
+msgstr ""
+
msgid "Something went wrong while promoting the issue to an epic. Please try again."
msgstr ""
@@ -39262,9 +39657,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39522,6 +39923,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39765,6 +40169,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -40381,6 +40788,9 @@ msgstr ""
msgid "The following SSH key was deleted by an administrator, %{username}."
msgstr ""
+msgid "The following files or directories can only be modified by the user who locked them."
+msgstr ""
+
msgid "The following items will NOT be exported:"
msgstr ""
@@ -40664,7 +41074,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40721,9 +41131,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40748,9 +41155,6 @@ msgstr ""
msgid "There are no abuse reports!"
msgstr ""
-msgid "There are no archived projects yet"
-msgstr ""
-
msgid "There are no archived requirements"
msgstr ""
@@ -40808,9 +41212,6 @@ msgstr ""
msgid "There are no packages yet"
msgstr ""
-msgid "There are no projects shared with this group yet"
-msgstr ""
-
msgid "There are no secure files yet."
msgstr ""
@@ -41108,6 +41509,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41315,7 +41719,7 @@ msgstr ""
msgid "This group"
msgstr ""
-msgid "This group and its subgroups and projects will be placed in a 'pending deletion' state for %{deletion_adjourned_period} days, then permanently deleted on %{date}. The group can be fully restored before that date."
+msgid "This group and its subgroups and projects will be placed in a 'pending deletion' state for %{deletion_delayed_period} days, then permanently deleted on %{date}. The group can be fully restored before that date."
msgstr ""
msgid "This group can't be removed because it is linked to a subscription. To remove this group, %{linkStart}link the subscription%{linkEnd} with a different group."
@@ -41567,9 +41971,6 @@ msgstr ""
msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
-msgstr ""
-
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
msgstr ""
@@ -41696,9 +42097,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41717,6 +42115,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42075,9 +42476,6 @@ msgstr ""
msgid "To add a custom suffix, set up a Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
-msgid "To add display name, set up a Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
-msgstr ""
-
msgid "To add the entry manually, provide the following details to the application on your phone."
msgstr ""
@@ -42087,9 +42485,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42195,6 +42590,12 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, ask your namespace owner to reduce the number of users in your namespace to %{free_limit} users or less, or to upgrade to a paid tier which do not have user limits."
+msgstr ""
+
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42279,6 +42680,9 @@ msgstr ""
msgid "Todos|Assigned"
msgstr ""
+msgid "Todos|Could not merge"
+msgstr ""
+
msgid "Todos|Design"
msgstr ""
@@ -42330,9 +42734,15 @@ msgstr ""
msgid "Todos|Pipelines"
msgstr ""
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
msgid "Todos|Review requested"
msgstr ""
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42345,6 +42755,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42495,9 +42923,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42818,6 +43243,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -42923,6 +43354,12 @@ msgstr ""
msgid "Unable to fetch branches list, please close the form and try again"
msgstr ""
+msgid "Unable to fetch group. Reload the page to try again."
+msgstr ""
+
+msgid "Unable to fetch groups. Reload the page to try again."
+msgstr ""
+
msgid "Unable to fetch upstream and downstream pipelines."
msgstr ""
@@ -43046,6 +43483,9 @@ msgstr ""
msgid "Unhappy?"
msgstr ""
+msgid "Units|d"
+msgstr ""
+
msgid "Units|ms"
msgstr ""
@@ -43430,6 +43870,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43460,6 +43903,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -43508,6 +43954,9 @@ msgstr ""
msgid "UsageQuota|The table below shows usage since %{timeElapsed}"
msgstr ""
+msgid "UsageQuota|The table below shows usage since %{usageSince}"
+msgstr ""
+
msgid "UsageQuota|This is the total amount of storage used across your projects within this namespace."
msgstr ""
@@ -43517,9 +43966,6 @@ msgstr ""
msgid "UsageQuota|This namespace contains locked projects"
msgstr ""
-msgid "UsageQuota|This namespace has no projects which use shared runners"
-msgstr ""
-
msgid "UsageQuota|This namespace has no projects which used shared runners in the current period"
msgstr ""
@@ -44971,6 +45417,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -45127,7 +45576,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45169,6 +45618,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -45184,12 +45636,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45337,6 +45801,9 @@ msgstr ""
msgid "Webhooks|Merge request events"
msgstr ""
+msgid "Webhooks|Must match part of URL"
+msgstr ""
+
msgid "Webhooks|Pipeline events"
msgstr ""
@@ -45346,6 +45813,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45385,7 +45858,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45406,6 +45879,12 @@ msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45484,6 +45963,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45493,7 +45975,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45809,6 +46291,9 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add tasks"
+msgstr ""
+
msgid "WorkItem|Add to iteration"
msgstr ""
@@ -45853,6 +46338,9 @@ msgstr ""
msgid "WorkItem|Due date"
msgstr ""
+msgid "WorkItem|Existing task"
+msgstr ""
+
msgid "WorkItem|Expand tasks"
msgstr ""
@@ -45874,6 +46362,9 @@ msgstr ""
msgid "WorkItem|Milestone"
msgstr ""
+msgid "WorkItem|New task"
+msgstr ""
+
msgid "WorkItem|No iteration"
msgstr ""
@@ -45901,6 +46392,9 @@ msgstr ""
msgid "WorkItem|Requirements"
msgstr ""
+msgid "WorkItem|Search existing tasks"
+msgstr ""
+
msgid "WorkItem|Select type"
msgstr ""
@@ -45997,6 +46491,9 @@ msgstr ""
msgid "Write a description or drag your files here…"
msgstr ""
+msgid "Write a description..."
+msgstr ""
+
msgid "Write a description…"
msgstr ""
@@ -46116,6 +46613,9 @@ msgstr ""
msgid "You are not allowed to create this tag as it is protected."
msgstr ""
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46161,13 +46661,10 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve them locally%{resolveLocallyEnd}."
msgstr ""
-msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
-msgstr ""
-
-msgid "You can %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
+msgid "You can %{resolveLocallyStart}resolve them locally%{resolveLocallyEnd}."
msgstr ""
msgid "You can adjust rules on auto-banning %{link_start}here%{link_end}."
@@ -46206,11 +46703,6 @@ msgstr ""
msgid "You can always edit this later"
msgstr ""
-msgid "You can begin moving members in %{namespace_name} now. A member loses access to the group when you turn off %{strong_start}In a seat%{strong_end}. If over %{free_user_limit} member has %{strong_start}In a seat%{strong_end} enabled after October 19, 2022, we'll select the %{free_user_limit} member who maintains access. We'll first count members that have Owner and Maintainer roles, then the most recently active members until we reach %{free_user_limit} member. The remaining members will get a status of Over limit and lose access to the group."
-msgid_plural "You can begin moving members in %{namespace_name} now. A member loses access to the group when you turn off %{strong_start}In a seat%{strong_end}. If over %{free_user_limit} members have %{strong_start}In a seat%{strong_end} enabled after October 19, 2022, we'll select the %{free_user_limit} members who maintain access. We'll first count members that have Owner and Maintainer roles, then the most recently active members until we reach %{free_user_limit} members. The remaining members will get a status of Over limit and lose access to the group."
-msgstr[0] ""
-msgstr[1] ""
-
msgid "You can check it in your %{pat_link_start}personal access tokens%{pat_link_end} settings."
msgstr ""
@@ -46265,6 +46757,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46304,9 +46799,6 @@ msgstr ""
msgid "You can now submit a merge request to get this change into the original project."
msgstr ""
-msgid "You can only %{action} files when you are on a branch"
-msgstr ""
-
msgid "You can only add up to %{max_contacts} contacts at one time"
msgstr ""
@@ -46337,9 +46829,6 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
-msgstr ""
-
msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
@@ -46364,6 +46853,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46388,6 +46880,9 @@ msgstr ""
msgid "You could not create a new trigger."
msgstr ""
+msgid "You do not have access to any projects for creating incidents."
+msgstr ""
+
msgid "You do not have any subscriptions yet"
msgstr ""
@@ -46507,6 +47002,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46552,9 +47050,6 @@ msgstr ""
msgid "You have successfully purchased %{product}. You'll receive a receipt by email. Your purchase may take a minute to sync, so refresh the page if you don't see it yet."
msgstr ""
-msgid "You have successfully purchased a %{plan} plan subscription for %{seats}. You’ll receive a receipt via email. Your purchase may take a minute to sync, so refresh the page if you don't see it yet."
-msgstr ""
-
msgid "You have unsaved changes"
msgstr ""
@@ -46570,7 +47065,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46732,13 +47227,13 @@ msgstr ""
msgid "You've rejected %{user}"
msgstr ""
-msgid "YouTube"
+msgid "You've successfully purchased the %{plan} plan subscription for %{seats} and you'll receive a receipt by email. Your purchase may take a minute to sync, refresh the page if your subscription details haven't displayed yet."
msgstr ""
-msgid "Your %{group} membership will now expire in %{days}."
+msgid "YouTube"
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
+msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
@@ -46852,6 +47347,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46970,13 +47468,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47065,6 +47563,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47113,6 +47614,9 @@ msgstr ""
msgid "ZentaoIntegration|ZenTao issues"
msgstr ""
+msgid "Zoom"
+msgstr ""
+
msgid "Zoom meeting added"
msgstr ""
@@ -47128,13 +47632,13 @@ msgstr ""
msgid "[Redacted]"
msgstr ""
-msgid "`end_time` should not exceed one month after `start_time`"
+msgid "[Supports GitLab-flavored markdown, including quick actions]"
msgstr ""
-msgid "`start_time` should precede `end_time`"
+msgid "`end_time` should not exceed one month after `start_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
+msgid "`start_time` should precede `end_time`"
msgstr ""
msgid "a deleted user"
@@ -47207,6 +47711,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -47296,6 +47806,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47349,6 +47865,11 @@ msgid_plural "changes"
msgstr[0] ""
msgstr[1] ""
+msgid "check"
+msgid_plural "checks"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "ciReport|%{criticalStart}critical%{criticalEnd}, %{highStart}high%{highEnd} and %{otherStart}others%{otherEnd}"
msgstr ""
@@ -47406,10 +47927,10 @@ msgstr ""
msgid "ciReport|%{scanner} detected %{strong_start}%{number}%{strong_end} new potential %{vulnStr}"
msgstr ""
-msgid "ciReport|%{scanner} detected no %{boldStart}new%{boldEnd} potential vulnerabilities"
+msgid "ciReport|%{scanner} detected no new %{vulnStr}"
msgstr ""
-msgid "ciReport|%{scanner} detected no %{strong_start}new%{strong_end} %{vulnStr}"
+msgid "ciReport|%{scanner} detected no new potential vulnerabilities"
msgstr ""
msgid "ciReport|: Loading resulted in an error"
@@ -47529,12 +48050,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47609,6 +48145,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47639,6 +48178,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47654,6 +48196,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47728,6 +48273,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47787,6 +48335,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47943,6 +48494,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -48043,12 +48597,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -48097,12 +48657,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -48259,9 +48825,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48410,6 +48973,9 @@ 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 ""
@@ -48506,9 +49072,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48572,6 +49135,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48590,6 +49156,12 @@ msgstr ""
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of its requirement object."
+msgstr ""
+
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48674,11 +49246,6 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
@@ -48837,12 +49404,25 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "rule"
+msgid_plural "rules"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48998,6 +49578,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -49134,6 +49717,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/gl_ES/gitlab.po b/locale/gl_ES/gitlab.po
index 1537c004781..245ebe51631 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: 2022-10-10 14:00\n"
+"PO-Revision-Date: 2022-11-13 09:21\n"
msgid " %{start} to %{end}"
msgstr " %{start} a %{end}"
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d exportador"
msgstr[1] "%d exportadores"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/he_IL/gitlab.po b/locale/he_IL/gitlab.po
index 9374a4148ac..815163032a0 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: 2022-10-10 14:03\n"
+"PO-Revision-Date: 2022-11-13 09:23\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -171,6 +171,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -311,13 +318,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
@@ -325,13 +325,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -346,13 +339,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -677,6 +663,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -737,6 +726,20 @@ msgstr[3] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -747,6 +750,13 @@ msgstr[3] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} more"
msgstr ""
@@ -773,6 +783,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -812,9 +829,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -1025,12 +1039,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1230,6 +1238,9 @@ msgstr[3] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1388,9 +1399,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1448,6 +1456,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1488,6 +1499,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1827,6 +1841,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr "העמוד ×œ× × ×ž×¦×"
@@ -1890,9 +1907,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1971,9 +1985,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -2181,6 +2192,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2292,15 +2306,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2370,9 +2378,6 @@ msgstr "פעיל"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr "הפעלות פעילות"
@@ -2745,6 +2750,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2928,6 +2939,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2964,15 +2993,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -3021,6 +3062,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -3066,6 +3110,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -3204,9 +3260,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -3231,6 +3296,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3333,6 +3407,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3525,7 +3602,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3570,7 +3647,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3633,7 +3710,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3681,6 +3758,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -4191,7 +4271,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -4206,6 +4286,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -4242,9 +4325,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4491,6 +4571,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4678,9 +4761,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4780,9 +4860,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4885,9 +4962,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4906,7 +4980,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4953,6 +5027,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4971,9 +5048,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -5001,6 +5087,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5351,9 +5440,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5457,7 +5543,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5508,6 +5594,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5559,9 +5669,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5961,9 +6068,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6327,6 +6431,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -7063,6 +7173,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -7072,6 +7185,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -7093,6 +7209,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -7111,6 +7230,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -7120,6 +7242,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -7138,9 +7263,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -7159,12 +7290,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7324,6 +7464,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7333,9 +7476,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7381,9 +7521,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7414,6 +7551,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7429,6 +7569,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7453,9 +7596,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7871,9 +8011,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7889,6 +8026,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8632,6 +8772,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9951,10 +10094,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -10138,6 +10287,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10939,10 +11091,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10975,6 +11127,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -11023,9 +11184,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -11110,9 +11268,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -11275,9 +11430,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11497,9 +11649,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11767,9 +11916,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11785,7 +11931,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11887,9 +12033,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -12218,6 +12361,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -12245,6 +12391,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -12302,6 +12451,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12536,6 +12688,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12756,6 +12911,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12843,6 +13001,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12876,6 +13037,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12987,6 +13151,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -13008,9 +13175,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -13077,7 +13241,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13566,6 +13730,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13653,6 +13820,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13997,6 +14179,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -14239,6 +14424,12 @@ msgstr[3] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -14254,6 +14445,9 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
@@ -14261,6 +14455,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14868,6 +15065,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -15198,22 +15401,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Copy snippet"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr ""
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr ""
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15441,6 +15662,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15621,10 +15845,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15639,18 +15863,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15663,18 +15878,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15804,9 +16013,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15870,9 +16076,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -16113,6 +16316,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -16234,6 +16488,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -16291,9 +16548,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16520,6 +16783,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16569,9 +16835,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16767,9 +17030,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -17029,6 +17289,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17134,9 +17397,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -17344,6 +17604,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -18185,9 +18448,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -18314,6 +18574,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18365,6 +18631,9 @@ 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 ""
@@ -18413,9 +18682,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18971,9 +19237,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18983,6 +19246,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19745,12 +20011,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19820,6 +20080,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -20002,9 +20265,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20463,7 +20723,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20550,12 +20816,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -22315,6 +22575,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -22333,9 +22596,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22393,7 +22653,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22475,19 +22735,16 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22625,12 +22882,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22652,6 +22915,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22877,6 +23152,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -23171,6 +23461,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23501,6 +23794,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23540,9 +23836,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23923,9 +24225,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -24079,6 +24378,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24229,9 +24537,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24490,6 +24795,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24760,9 +25071,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24775,6 +25083,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24811,7 +25122,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24826,9 +25143,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24838,9 +25161,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24850,7 +25170,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24907,6 +25227,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24931,6 +25254,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24982,6 +25308,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24994,6 +25323,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25626,6 +25958,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25851,6 +26186,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -26246,6 +26584,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26405,6 +26746,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26477,6 +26821,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26663,6 +27010,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -27127,6 +27477,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -27256,9 +27609,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -27286,9 +27636,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -27304,9 +27651,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27542,7 +27886,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27885,6 +28229,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27894,6 +28241,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27915,6 +28265,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -28008,9 +28361,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -28035,9 +28385,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -28273,12 +28620,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28324,12 +28665,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28351,12 +28686,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28399,15 +28728,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28438,12 +28758,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28462,9 +28776,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28640,9 +28951,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -29013,12 +29321,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -29064,6 +29381,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -29212,6 +29535,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29597,12 +29923,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29651,7 +29971,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29870,6 +30190,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29885,6 +30208,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29897,12 +30223,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29912,9 +30244,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30674,9 +31012,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30785,6 +31120,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30926,6 +31324,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -31019,12 +31420,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31601,6 +32008,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31613,6 +32023,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31895,12 +32308,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31913,12 +32332,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31940,6 +32365,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -32039,6 +32467,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -32177,6 +32608,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -32207,6 +32641,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -32258,6 +32695,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32897,6 +33337,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32933,15 +33376,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32957,12 +33412,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -33272,6 +33736,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33404,12 +33871,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33503,9 +33964,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33673,6 +34131,9 @@ msgstr[3] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33682,6 +34143,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -34138,6 +34602,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -34154,13 +34621,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -34192,18 +34652,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34218,12 +34672,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -34266,21 +34714,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34296,9 +34735,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34678,6 +35114,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34911,6 +35350,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34951,6 +35393,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34983,7 +35428,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -35194,6 +35639,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -35324,9 +35772,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -35375,6 +35829,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -35412,6 +35869,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -35451,12 +35911,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35511,16 +35965,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35628,10 +36088,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35652,9 +36112,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35664,9 +36130,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35817,9 +36289,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -36248,10 +36717,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -36371,6 +36843,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36473,10 +36948,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36566,7 +37041,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36584,6 +37059,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36602,12 +37080,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36629,6 +37116,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36758,6 +37248,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36815,6 +37308,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36932,9 +37428,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36947,6 +37449,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -37010,9 +37515,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -37151,10 +37653,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -37166,28 +37668,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37406,9 +37908,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37560,9 +38059,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37819,10 +38315,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37876,7 +38369,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37891,7 +38384,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -38014,9 +38507,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -38239,6 +38729,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38350,9 +38843,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38926,9 +39416,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38941,9 +39428,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38965,9 +39449,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39487,9 +39968,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39749,6 +40236,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39839,6 +40329,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39923,6 +40416,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39944,15 +40440,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39974,9 +40464,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39995,6 +40482,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -40106,20 +40596,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -40143,12 +40619,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -40236,12 +40706,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40706,6 +41170,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40901,9 +41368,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40934,7 +41398,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40991,9 +41455,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -41345,9 +41806,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -41381,6 +41839,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41549,9 +42010,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41612,6 +42070,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41828,13 +42289,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41963,9 +42427,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41984,6 +42445,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42358,9 +42822,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42466,6 +42927,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42532,9 +42996,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42556,18 +43044,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42580,6 +43089,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42730,9 +43257,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -43055,6 +43579,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43559,6 +44089,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43661,6 +44197,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43691,6 +44230,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44747,9 +45289,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -45213,6 +45752,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -45231,6 +45773,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -45366,7 +45911,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45408,6 +45953,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -45423,12 +45971,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45468,6 +46028,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45582,6 +46145,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45609,9 +46178,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45624,7 +46190,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45636,12 +46202,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45720,6 +46295,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45729,7 +46307,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -46049,6 +46627,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -46101,9 +46685,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -46134,10 +46733,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -46149,6 +46751,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -46170,6 +46775,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -46188,6 +46796,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -46285,6 +46896,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -46321,6 +46935,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46366,9 +46986,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -46472,6 +47089,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46544,7 +47164,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46568,6 +47188,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46713,6 +47336,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46776,7 +47402,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46944,9 +47570,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -47058,6 +47681,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -47180,16 +47806,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47280,6 +47903,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47349,9 +47975,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -47365,9 +47988,6 @@ msgstr[3] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -47429,6 +48049,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -47438,9 +48064,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -47523,6 +48146,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47764,12 +48393,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47846,6 +48490,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47876,6 +48523,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47891,6 +48541,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47967,6 +48620,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -48028,6 +48684,9 @@ msgstr[3] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -48190,6 +48849,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -48294,12 +48956,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -48321,6 +48989,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -48345,12 +49016,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -48513,9 +49190,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48668,6 +49342,9 @@ 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 ""
@@ -48764,9 +49441,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48830,6 +49504,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48842,9 +49519,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48863,9 +49546,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48914,9 +49594,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48935,19 +49612,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -49083,9 +49756,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -49108,12 +49778,22 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -49271,6 +49951,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -49411,6 +50094,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/hi_IN/gitlab.po b/locale/hi_IN/gitlab.po
index 74cf39192c0..118b32160e5 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: 2022-10-10 14:04\n"
+"PO-Revision-Date: 2022-11-13 09:23\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/hr_HR/gitlab.po b/locale/hr_HR/gitlab.po
index 0404a32cc8a..73d481002f7 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: 2022-10-10 14:01\n"
+"PO-Revision-Date: 2022-11-13 09:21\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -157,6 +157,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -277,24 +283,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -307,12 +301,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -595,6 +583,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -652,6 +643,18 @@ msgstr[2] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -661,6 +664,12 @@ msgstr[2] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%{count} more"
msgstr ""
@@ -685,6 +694,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -724,9 +739,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -937,12 +949,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1135,6 +1141,9 @@ msgstr[2] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1285,9 +1294,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1345,6 +1351,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1384,6 +1393,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1696,6 +1708,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1759,9 +1774,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1840,9 +1852,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -2050,6 +2059,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2161,15 +2173,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2239,9 +2245,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2614,6 +2617,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2797,6 +2806,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2833,15 +2860,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2890,6 +2929,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2935,6 +2977,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -3073,9 +3127,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -3100,6 +3163,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3202,6 +3274,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3394,7 +3469,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3439,7 +3514,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3502,7 +3577,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3550,6 +3625,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -4060,7 +4138,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -4075,6 +4153,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -4111,9 +4192,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4360,6 +4438,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4546,9 +4627,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4648,9 +4726,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4753,9 +4828,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4774,7 +4846,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4819,6 +4891,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4837,9 +4912,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4867,6 +4951,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5212,9 +5299,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5317,7 +5401,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5368,6 +5452,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5419,9 +5527,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5818,9 +5923,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6184,6 +6286,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6916,6 +7024,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6925,6 +7036,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6946,6 +7060,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6964,6 +7081,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6973,6 +7093,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6991,9 +7114,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -7012,12 +7141,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7177,6 +7315,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7186,9 +7327,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7234,9 +7372,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7267,6 +7402,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7282,6 +7420,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7306,9 +7447,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7723,9 +7861,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7741,6 +7876,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8482,6 +8620,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9799,10 +9940,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9985,6 +10132,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10783,10 +10933,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10819,6 +10969,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10867,9 +11026,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10954,9 +11110,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -11119,9 +11272,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11341,9 +11491,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11611,9 +11758,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11629,7 +11773,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11731,9 +11875,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -12061,6 +12202,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -12088,6 +12232,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -12145,6 +12292,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12379,6 +12529,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12598,6 +12751,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12685,6 +12841,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12718,6 +12877,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12829,6 +12991,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12850,9 +13015,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12919,7 +13081,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13402,6 +13564,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13489,6 +13654,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13831,6 +14011,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -14071,6 +14254,12 @@ msgstr[2] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -14086,12 +14275,18 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14698,6 +14893,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -15028,22 +15229,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Using a static site?"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15271,6 +15490,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15451,10 +15673,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15469,18 +15691,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15493,18 +15706,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15634,9 +15841,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15700,9 +15904,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15943,6 +16144,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -16063,6 +16315,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -16120,9 +16375,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16348,6 +16609,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16396,9 +16660,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16594,9 +16855,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16855,6 +17113,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16960,9 +17221,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -17170,6 +17428,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -18007,9 +18268,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -18136,6 +18394,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18187,6 +18451,9 @@ 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 ""
@@ -18235,9 +18502,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18793,9 +19057,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18805,6 +19066,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19567,12 +19831,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19642,6 +19900,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19822,9 +20083,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20281,7 +20539,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20368,12 +20632,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -22129,6 +22387,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -22147,9 +22408,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22207,7 +22465,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22288,19 +22546,16 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22438,12 +22693,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22465,6 +22726,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22690,6 +22963,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22984,6 +23272,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23314,6 +23605,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23353,9 +23647,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23734,9 +24034,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23890,6 +24187,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24040,9 +24346,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24295,6 +24598,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24565,9 +24874,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24580,6 +24886,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24616,7 +24925,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24631,9 +24946,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24643,9 +24964,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24655,7 +24973,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24712,6 +25030,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24736,6 +25057,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24787,6 +25111,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24799,6 +25126,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25429,6 +25759,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25654,6 +25987,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -26047,6 +26383,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26206,6 +26545,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26278,6 +26620,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26464,6 +26809,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26926,6 +27274,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -27055,9 +27406,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -27085,9 +27433,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -27103,9 +27448,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27340,7 +27682,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27679,6 +28021,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27688,6 +28033,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27709,6 +28057,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27802,9 +28153,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27829,9 +28177,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -28066,12 +28411,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28117,12 +28456,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28144,12 +28477,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28192,15 +28519,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28231,12 +28549,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28255,9 +28567,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28432,9 +28741,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28804,12 +29110,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28855,6 +29170,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -29002,6 +29323,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29386,12 +29710,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29440,7 +29758,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29659,6 +29977,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29674,6 +29995,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29686,12 +30010,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29701,9 +30031,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30463,9 +30799,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30574,6 +30907,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30715,6 +31111,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30808,12 +31207,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31390,6 +31795,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31402,6 +31810,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31684,12 +32095,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31702,12 +32119,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31729,6 +32152,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31828,6 +32254,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31966,6 +32395,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31996,6 +32428,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -32047,6 +32482,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32686,6 +33124,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32722,15 +33163,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32746,12 +33199,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -33061,6 +33523,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33193,12 +33658,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33292,9 +33751,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33460,6 +33916,9 @@ msgstr[2] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33469,6 +33928,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33925,6 +34387,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33940,12 +34405,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33976,18 +34435,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34000,12 +34453,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -34048,21 +34495,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34078,9 +34516,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34456,6 +34891,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34687,6 +35125,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34726,6 +35167,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34756,7 +35200,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34966,6 +35410,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -35095,9 +35542,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -35146,6 +35599,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -35182,6 +35638,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -35221,12 +35680,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35281,16 +35734,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35398,10 +35857,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35422,9 +35881,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35434,9 +35899,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35587,9 +36058,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -36007,10 +36475,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -36130,6 +36601,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36232,10 +36706,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36325,7 +36799,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36343,6 +36817,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36361,12 +36838,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36388,6 +36874,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36517,6 +37006,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36574,6 +37066,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36691,9 +37186,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36706,6 +37207,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36769,9 +37273,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36910,10 +37411,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36925,28 +37426,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37165,9 +37666,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37318,9 +37816,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37576,10 +38071,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37633,7 +38125,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37648,7 +38140,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37771,9 +38263,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37996,6 +38485,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38107,9 +38599,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38683,9 +39172,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38698,9 +39184,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38722,9 +39205,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39244,9 +39724,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39505,6 +39991,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39595,6 +40084,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39679,6 +40171,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39700,15 +40195,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39730,9 +40219,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39751,6 +40237,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39862,18 +40351,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39895,12 +40372,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39988,12 +40459,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40453,6 +40918,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40648,9 +41116,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40681,7 +41146,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40738,9 +41203,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -41092,9 +41554,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -41128,6 +41587,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41296,9 +41758,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41359,6 +41818,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41575,13 +42037,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41710,9 +42175,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41731,6 +42193,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42103,9 +42568,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42211,6 +42673,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42277,9 +42742,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42301,18 +42790,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42325,6 +42835,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42475,9 +43003,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42799,6 +43324,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43303,6 +43834,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43405,6 +43942,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43435,6 +43975,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44488,9 +45031,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44953,6 +45493,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44971,6 +45514,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -45106,7 +45652,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45148,6 +45694,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -45163,12 +45712,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45208,6 +45769,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45322,6 +45886,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45349,9 +45919,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45364,7 +45931,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45376,12 +45943,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45460,6 +46036,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45469,7 +46048,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45787,6 +46366,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45838,9 +46423,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45871,10 +46471,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45886,6 +46489,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45907,6 +46513,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45925,6 +46534,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -46021,6 +46633,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -46057,6 +46672,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46102,9 +46723,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -46207,6 +46825,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46279,7 +46900,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46303,6 +46924,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46447,6 +47071,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46510,7 +47137,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46678,9 +47305,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46792,6 +47416,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46912,16 +47539,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47011,6 +47635,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47080,9 +47707,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -47095,9 +47719,6 @@ msgstr[2] "približno %d sati"
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -47158,6 +47779,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -47167,9 +47794,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -47251,6 +47875,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47488,12 +48118,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47569,6 +48214,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47599,6 +48247,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47614,6 +48265,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47689,6 +48343,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47749,6 +48406,9 @@ msgstr[2] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47908,6 +48568,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -48010,12 +48673,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -48037,6 +48706,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -48061,12 +48733,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -48226,9 +48904,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48379,6 +49054,9 @@ 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 ""
@@ -48475,9 +49153,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48541,6 +49216,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48553,9 +49231,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48574,9 +49258,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48625,9 +49306,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48646,18 +49324,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48790,9 +49465,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48814,12 +49486,21 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48976,6 +49657,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -49114,6 +49798,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/hu_HU/gitlab.po b/locale/hu_HU/gitlab.po
index b3731b7b9eb..ccb247daedf 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: 2022-10-10 14:01\n"
+"PO-Revision-Date: 2022-11-13 09:22\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/hy_AM/gitlab.po b/locale/hy_AM/gitlab.po
index bbd604854fd..d5bebf0567f 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: 2022-10-10 14:03\n"
+"PO-Revision-Date: 2022-11-13 09:23\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/id_ID/gitlab.po b/locale/id_ID/gitlab.po
index 09c641e1958..f687bce2bee 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: 2022-10-10 14:00\n"
+"PO-Revision-Date: 2022-11-13 09:21\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -129,6 +129,10 @@ msgid "%d additional user"
msgid_plural "%d additional users"
msgstr[0] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -209,18 +213,10 @@ msgid "%d epic"
msgid_plural "%d epics"
msgstr[0] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -229,10 +225,6 @@ msgid "%d file"
msgid_plural "%d files"
msgstr[0] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -431,6 +423,9 @@ msgid "%{bold_start}%{count}%{bold_end} opened merge request"
msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -482,6 +477,14 @@ msgstr[0] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -489,6 +492,10 @@ msgstr[0] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+
msgid "%{count} more"
msgstr ""
@@ -509,6 +516,10 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -548,9 +559,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -761,12 +769,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -945,6 +947,9 @@ msgstr[0] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1079,9 +1084,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1139,6 +1141,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1176,6 +1181,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1434,6 +1442,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1497,9 +1508,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1578,9 +1586,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1788,6 +1793,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -1899,15 +1907,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -1977,9 +1979,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2352,6 +2351,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2535,6 +2540,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2571,15 +2594,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2628,6 +2663,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2673,6 +2711,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2811,9 +2861,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2838,6 +2897,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -2940,6 +3008,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3132,7 +3203,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3177,7 +3248,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3240,7 +3311,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3288,6 +3359,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3798,7 +3872,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3813,6 +3887,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3849,9 +3926,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4098,6 +4172,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4282,9 +4359,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4384,9 +4458,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4489,9 +4560,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4510,7 +4578,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4551,6 +4619,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4569,9 +4640,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4599,6 +4679,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -4934,9 +5017,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5037,7 +5117,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5088,6 +5168,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5139,9 +5243,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5532,9 +5633,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -5898,6 +5996,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6622,6 +6726,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6631,6 +6738,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6652,6 +6762,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6670,6 +6783,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6679,6 +6795,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6697,9 +6816,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6718,12 +6843,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -6883,6 +7017,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -6892,9 +7029,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -6940,9 +7074,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -6973,6 +7104,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -6988,6 +7122,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7012,9 +7149,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7427,9 +7561,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7445,6 +7576,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8182,6 +8316,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9495,10 +9632,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9679,6 +9822,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10471,10 +10617,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10507,6 +10653,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10555,9 +10710,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10642,9 +10794,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10807,9 +10956,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11029,9 +11175,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11299,9 +11442,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11317,7 +11457,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11419,9 +11559,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11747,6 +11884,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11774,6 +11914,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11831,6 +11974,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12065,6 +12211,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12282,6 +12431,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12369,6 +12521,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12402,6 +12557,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12513,6 +12671,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12534,9 +12695,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12603,7 +12761,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13074,6 +13232,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13161,6 +13322,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13499,6 +13675,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13735,6 +13914,12 @@ msgstr[0] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13750,10 +13935,16 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14358,6 +14549,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14688,22 +14885,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -14931,6 +15146,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15111,10 +15329,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15129,18 +15347,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15153,18 +15362,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15294,9 +15497,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15360,9 +15560,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15603,6 +15800,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15721,6 +15969,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15778,9 +16029,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16004,6 +16261,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16050,9 +16310,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16248,9 +16505,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16507,6 +16761,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16612,9 +16869,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16822,6 +17076,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17651,9 +17908,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17780,6 +18034,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -17831,6 +18091,9 @@ 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 ""
@@ -17879,9 +18142,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18437,9 +18697,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18449,6 +18706,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19211,12 +19471,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19286,6 +19540,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19462,9 +19719,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -19917,7 +20171,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20004,12 +20264,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21757,6 +22011,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21775,9 +22032,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -21835,7 +22089,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -21914,19 +22168,16 @@ msgid "InviteMembersModal|The following member couldn't be invited"
msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22064,12 +22315,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22091,6 +22348,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22316,6 +22585,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22610,6 +22894,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -22940,6 +23227,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -22979,9 +23269,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23356,9 +23652,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23512,6 +23805,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23662,9 +23964,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -23905,6 +24204,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24175,9 +24480,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24190,6 +24492,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24226,7 +24531,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24241,9 +24552,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24253,9 +24570,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24265,7 +24579,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24322,6 +24636,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24346,6 +24663,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24397,6 +24717,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24409,6 +24732,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25035,6 +25361,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25260,6 +25589,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25649,6 +25981,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -25808,6 +26143,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -25880,6 +26218,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26066,6 +26407,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26524,6 +26868,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26653,9 +27000,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26683,9 +27027,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26701,9 +27042,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -26936,7 +27274,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27267,6 +27605,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27276,6 +27617,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27297,6 +27641,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27390,9 +27737,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27417,9 +27761,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27652,12 +27993,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27703,12 +28038,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27730,12 +28059,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27778,15 +28101,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -27817,12 +28131,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -27841,9 +28149,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28016,9 +28321,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28386,12 +28688,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28437,6 +28748,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28582,6 +28899,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -28964,12 +29284,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29018,7 +29332,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29237,6 +29551,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29252,6 +29569,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29264,12 +29584,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29279,9 +29605,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30041,9 +30373,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30152,6 +30481,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30293,6 +30685,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30386,12 +30781,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -30968,6 +31369,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -30980,6 +31384,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31262,12 +31669,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31280,12 +31693,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31307,6 +31726,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31406,6 +31828,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31544,6 +31969,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31574,6 +32002,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31625,6 +32056,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32264,6 +32698,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32300,15 +32737,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32324,12 +32773,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32639,6 +33097,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32771,12 +33232,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -32870,9 +33325,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33034,6 +33486,9 @@ msgstr[0] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33043,6 +33498,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33499,6 +33957,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33512,10 +33973,6 @@ msgid "Reports|%{recentlyFailed} out of %{failed} failed tests has failed more t
msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days"
msgstr[0] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33544,18 +34001,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33564,12 +34015,6 @@ msgid "Reports|Failed %{count} time in %{base_branch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 days"
msgstr[0] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33612,21 +34057,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33642,9 +34078,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34012,6 +34445,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34239,6 +34675,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34276,6 +34715,9 @@ msgid "Runners|%d selected runner deleted"
msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34302,7 +34744,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34510,6 +34952,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34637,9 +35082,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34688,6 +35139,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34722,6 +35176,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34761,12 +35218,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -34821,16 +35272,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -34938,10 +35395,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -34962,9 +35419,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -34974,9 +35437,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35127,9 +35596,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35525,10 +35991,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35648,6 +36117,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35750,10 +36222,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -35843,7 +36315,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -35861,6 +36333,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -35879,12 +36354,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -35906,6 +36390,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36035,6 +36522,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36092,6 +36582,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36209,9 +36702,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36224,6 +36723,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36287,9 +36789,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36428,10 +36927,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36443,28 +36942,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36683,9 +37182,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -36834,9 +37330,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37090,10 +37583,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37147,7 +37637,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37162,7 +37652,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37285,9 +37775,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37510,6 +37997,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37621,9 +38111,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38197,9 +38684,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38212,9 +38696,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38236,9 +38717,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -38758,9 +39236,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39017,6 +39501,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39107,6 +39594,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39191,6 +39681,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39212,15 +39705,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39242,9 +39729,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39263,6 +39747,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39374,14 +39861,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39399,12 +39878,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39492,12 +39965,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -39947,6 +40414,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40142,9 +40612,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40175,7 +40642,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40232,9 +40699,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40586,9 +41050,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40622,6 +41083,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -40790,9 +41254,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -40853,6 +41314,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41069,13 +41533,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41204,9 +41671,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41225,6 +41689,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41593,9 +42060,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41701,6 +42165,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -41767,9 +42234,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -41791,18 +42282,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -41815,6 +42327,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -41965,9 +42495,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42287,6 +42814,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -42791,6 +43324,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -42893,6 +43432,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -42923,6 +43465,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -43970,9 +44515,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44433,6 +44975,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44451,6 +44996,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44586,7 +45134,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44628,6 +45176,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44643,12 +45194,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44688,6 +45251,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -44802,6 +45368,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -44829,9 +45401,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -44844,7 +45413,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -44856,12 +45425,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -44940,6 +45518,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -44949,7 +45530,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45263,6 +45844,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45312,9 +45899,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45345,10 +45947,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45360,6 +45965,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45381,6 +45989,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45399,6 +46010,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45493,6 +46107,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45529,6 +46146,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45574,9 +46197,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45677,6 +46297,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -45749,7 +46372,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -45773,6 +46396,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -45915,6 +46541,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -45978,7 +46607,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46146,9 +46775,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46260,6 +46886,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46376,16 +47005,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46473,6 +47099,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46542,9 +47171,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46555,9 +47181,6 @@ msgstr[0] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46616,6 +47239,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46625,9 +47254,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46707,6 +47333,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -46936,12 +47568,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47015,6 +47662,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47045,6 +47695,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47060,6 +47713,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47133,6 +47789,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47191,6 +47850,9 @@ msgstr[0] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47344,6 +48006,9 @@ msgid "from %d job"
msgid_plural "from %d jobs"
msgstr[0] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47442,12 +48107,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47469,6 +48140,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47493,12 +48167,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47652,9 +48332,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -47801,6 +48478,9 @@ 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 ""
@@ -47897,9 +48577,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -47963,6 +48640,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -47975,9 +48655,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -47996,9 +48682,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48047,9 +48730,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48068,16 +48748,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48204,9 +48883,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48226,12 +48902,19 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48386,6 +49069,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48520,6 +49206,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/ig_NG/gitlab.po b/locale/ig_NG/gitlab.po
index f87fa7cea88..85bda778a68 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: 2022-10-10 14:06\n"
+"PO-Revision-Date: 2022-11-13 09:24\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -129,6 +129,10 @@ msgid "%d additional user"
msgid_plural "%d additional users"
msgstr[0] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -209,18 +213,10 @@ msgid "%d epic"
msgid_plural "%d epics"
msgstr[0] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -229,10 +225,6 @@ msgid "%d file"
msgid_plural "%d files"
msgstr[0] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -431,6 +423,9 @@ msgid "%{bold_start}%{count}%{bold_end} opened merge request"
msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -482,6 +477,14 @@ msgstr[0] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -489,6 +492,10 @@ msgstr[0] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+
msgid "%{count} more"
msgstr ""
@@ -509,6 +516,10 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -548,9 +559,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -761,12 +769,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -945,6 +947,9 @@ msgstr[0] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1079,9 +1084,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1139,6 +1141,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1176,6 +1181,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1434,6 +1442,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1497,9 +1508,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1578,9 +1586,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1788,6 +1793,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -1899,15 +1907,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -1977,9 +1979,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2352,6 +2351,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2535,6 +2540,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2571,15 +2594,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2628,6 +2663,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2673,6 +2711,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2811,9 +2861,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2838,6 +2897,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -2940,6 +3008,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3132,7 +3203,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3177,7 +3248,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3240,7 +3311,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3288,6 +3359,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3798,7 +3872,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3813,6 +3887,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3849,9 +3926,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4098,6 +4172,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4282,9 +4359,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4384,9 +4458,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4489,9 +4560,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4510,7 +4578,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4551,6 +4619,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4569,9 +4640,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4599,6 +4679,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -4934,9 +5017,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5037,7 +5117,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5088,6 +5168,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5139,9 +5243,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5532,9 +5633,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -5898,6 +5996,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6622,6 +6726,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6631,6 +6738,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6652,6 +6762,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6670,6 +6783,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6679,6 +6795,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6697,9 +6816,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6718,12 +6843,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -6883,6 +7017,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -6892,9 +7029,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -6940,9 +7074,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -6973,6 +7104,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -6988,6 +7122,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7012,9 +7149,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7427,9 +7561,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7445,6 +7576,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8182,6 +8316,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9495,10 +9632,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9679,6 +9822,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10471,10 +10617,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10507,6 +10653,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10555,9 +10710,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10642,9 +10794,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10807,9 +10956,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11029,9 +11175,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11299,9 +11442,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11317,7 +11457,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11419,9 +11559,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11747,6 +11884,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11774,6 +11914,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11831,6 +11974,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12065,6 +12211,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12282,6 +12431,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12369,6 +12521,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12402,6 +12557,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12513,6 +12671,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12534,9 +12695,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12603,7 +12761,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13074,6 +13232,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13161,6 +13322,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13499,6 +13675,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13735,6 +13914,12 @@ msgstr[0] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13750,10 +13935,16 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14358,6 +14549,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14688,22 +14885,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -14931,6 +15146,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15111,10 +15329,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15129,18 +15347,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15153,18 +15362,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15294,9 +15497,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15360,9 +15560,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15603,6 +15800,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15721,6 +15969,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15778,9 +16029,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16004,6 +16261,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16050,9 +16310,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16248,9 +16505,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16507,6 +16761,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16612,9 +16869,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16822,6 +17076,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17651,9 +17908,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17780,6 +18034,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -17831,6 +18091,9 @@ 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 ""
@@ -17879,9 +18142,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18437,9 +18697,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18449,6 +18706,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19211,12 +19471,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19286,6 +19540,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19462,9 +19719,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -19917,7 +20171,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20004,12 +20264,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21757,6 +22011,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21775,9 +22032,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -21835,7 +22089,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -21914,19 +22168,16 @@ msgid "InviteMembersModal|The following member couldn't be invited"
msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22064,12 +22315,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22091,6 +22348,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22316,6 +22585,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22610,6 +22894,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -22940,6 +23227,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -22979,9 +23269,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23356,9 +23652,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23512,6 +23805,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23662,9 +23964,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -23905,6 +24204,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24175,9 +24480,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24190,6 +24492,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24226,7 +24531,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24241,9 +24552,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24253,9 +24570,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24265,7 +24579,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24322,6 +24636,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24346,6 +24663,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24397,6 +24717,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24409,6 +24732,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25035,6 +25361,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25260,6 +25589,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25649,6 +25981,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -25808,6 +26143,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -25880,6 +26218,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26066,6 +26407,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26524,6 +26868,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26653,9 +27000,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26683,9 +27027,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26701,9 +27042,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -26936,7 +27274,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27267,6 +27605,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27276,6 +27617,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27297,6 +27641,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27390,9 +27737,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27417,9 +27761,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27652,12 +27993,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27703,12 +28038,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27730,12 +28059,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27778,15 +28101,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -27817,12 +28131,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -27841,9 +28149,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28016,9 +28321,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28386,12 +28688,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28437,6 +28748,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28582,6 +28899,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -28964,12 +29284,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29018,7 +29332,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29237,6 +29551,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29252,6 +29569,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29264,12 +29584,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29279,9 +29605,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30041,9 +30373,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30152,6 +30481,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30293,6 +30685,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30386,12 +30781,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -30968,6 +31369,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -30980,6 +31384,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31262,12 +31669,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31280,12 +31693,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31307,6 +31726,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31406,6 +31828,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31544,6 +31969,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31574,6 +32002,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31625,6 +32056,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32264,6 +32698,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32300,15 +32737,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32324,12 +32773,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32639,6 +33097,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32771,12 +33232,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -32870,9 +33325,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33034,6 +33486,9 @@ msgstr[0] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33043,6 +33498,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33499,6 +33957,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33512,10 +33973,6 @@ msgid "Reports|%{recentlyFailed} out of %{failed} failed tests has failed more t
msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days"
msgstr[0] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33544,18 +34001,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33564,12 +34015,6 @@ msgid "Reports|Failed %{count} time in %{base_branch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 days"
msgstr[0] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33612,21 +34057,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33642,9 +34078,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34012,6 +34445,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34239,6 +34675,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34276,6 +34715,9 @@ msgid "Runners|%d selected runner deleted"
msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34302,7 +34744,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34510,6 +34952,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34637,9 +35082,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34688,6 +35139,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34722,6 +35176,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34761,12 +35218,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -34821,16 +35272,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -34938,10 +35395,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -34962,9 +35419,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -34974,9 +35437,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35127,9 +35596,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35525,10 +35991,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35648,6 +36117,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35750,10 +36222,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -35843,7 +36315,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -35861,6 +36333,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -35879,12 +36354,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -35906,6 +36390,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36035,6 +36522,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36092,6 +36582,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36209,9 +36702,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36224,6 +36723,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36287,9 +36789,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36428,10 +36927,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36443,28 +36942,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36683,9 +37182,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -36834,9 +37330,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37090,10 +37583,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37147,7 +37637,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37162,7 +37652,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37285,9 +37775,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37510,6 +37997,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37621,9 +38111,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38197,9 +38684,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38212,9 +38696,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38236,9 +38717,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -38758,9 +39236,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39017,6 +39501,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39107,6 +39594,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39191,6 +39681,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39212,15 +39705,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39242,9 +39729,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39263,6 +39747,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39374,14 +39861,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39399,12 +39878,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39492,12 +39965,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -39947,6 +40414,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40142,9 +40612,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40175,7 +40642,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40232,9 +40699,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40586,9 +41050,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40622,6 +41083,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -40790,9 +41254,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -40853,6 +41314,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41069,13 +41533,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41204,9 +41671,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41225,6 +41689,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41593,9 +42060,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41701,6 +42165,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -41767,9 +42234,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -41791,18 +42282,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -41815,6 +42327,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -41965,9 +42495,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42287,6 +42814,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -42791,6 +43324,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -42893,6 +43432,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -42923,6 +43465,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -43970,9 +44515,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44433,6 +44975,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44451,6 +44996,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44586,7 +45134,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44628,6 +45176,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44643,12 +45194,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44688,6 +45251,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -44802,6 +45368,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -44829,9 +45401,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -44844,7 +45413,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -44856,12 +45425,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -44940,6 +45518,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -44949,7 +45530,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45263,6 +45844,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45312,9 +45899,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45345,10 +45947,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45360,6 +45965,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45381,6 +45989,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45399,6 +46010,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45493,6 +46107,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45529,6 +46146,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45574,9 +46197,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45677,6 +46297,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -45749,7 +46372,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -45773,6 +46396,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -45915,6 +46541,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -45978,7 +46607,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46146,9 +46775,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46260,6 +46886,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46376,16 +47005,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46473,6 +47099,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46542,9 +47171,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46555,9 +47181,6 @@ msgstr[0] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46616,6 +47239,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46625,9 +47254,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46707,6 +47333,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -46936,12 +47568,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47015,6 +47662,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47045,6 +47695,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47060,6 +47713,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47133,6 +47789,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47191,6 +47850,9 @@ msgstr[0] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47344,6 +48006,9 @@ msgid "from %d job"
msgid_plural "from %d jobs"
msgstr[0] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47442,12 +48107,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47469,6 +48140,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47493,12 +48167,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47652,9 +48332,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -47801,6 +48478,9 @@ 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 ""
@@ -47897,9 +48577,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -47963,6 +48640,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -47975,9 +48655,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -47996,9 +48682,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48047,9 +48730,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48068,16 +48748,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48204,9 +48883,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48226,12 +48902,19 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48386,6 +49069,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48520,6 +49206,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/is_IS/gitlab.po b/locale/is_IS/gitlab.po
index 64be7974357..d62a0263f40 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: 2022-10-10 14:00\n"
+"PO-Revision-Date: 2022-11-13 09:21\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/it/gitlab.po b/locale/it/gitlab.po
index 250f15c17b2..f41760b8066 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: 2022-10-10 14:03\n"
+"PO-Revision-Date: 2022-11-13 09:23\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d exporter"
msgstr[1] "%d exporter"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d risultato del test risolto"
-msgstr[1] "%d risultati dei test risolti"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr "%{count} altro"
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} partecipante"
msgstr[1] "%{count} partecipanti"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "%{strong_start}%{branch_count}%{strong_end} branch"
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr "'%{source}' non è una sorgente di importazione"
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "Un ramo predefinito non può essere scelto per un progetto vuoto."
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr "Attivo"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr "Artefatti"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr "La Branch esiste già"
msgid "Branch name"
msgstr "Nome Branch"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "Naviga direttori"
@@ -7039,9 +7178,6 @@ msgstr "Esplora File"
msgid "Browse Files"
msgstr "Esplora Files"
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr "Guarda i files"
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr "Personale"
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr "Elimina"
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Using a static site?"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr "Commit"
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr "Feb"
msgid "February"
msgstr "Febbraio"
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr "Abbandona il progetto"
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr "Mar"
msgid "March"
msgstr "Marzo"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr "Ott"
msgid "October"
msgstr "Ottobre"
-msgid "OfSearchInADropdown|Filter"
-msgstr "Filtra"
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr "Attiva"
msgid "PipelineSchedules|All"
msgstr "Tutto"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr "Inattiva"
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr "Prossima esecuzione"
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "Fornisci una breve descrizione per questa pipeline"
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr "Prendi possesso"
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr "Target"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr "Variabili"
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr "Preferenze"
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr "Vedi altro"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr "Seleziona una timezone"
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr "Impostazioni"
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "Cambia branch/tag"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr "Branch di destinazione"
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr "Il tuo nome"
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] "giorni"
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/ja/gitlab.po b/locale/ja/gitlab.po
index a2ea5dc6717..3f5ba8e628e 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: 2022-10-10 14:03\n"
+"PO-Revision-Date: 2022-11-13 09:23\n"
msgid " %{start} to %{end}"
msgstr " %{start} ã‹ã‚‰ %{end} ã¾ã§"
@@ -119,7 +119,7 @@ msgstr[0] "%d 人ã®è¿½åŠ æ‹…当者"
msgid "%d additional commenter"
msgid_plural "%d additional commenters"
-msgstr[0] ""
+msgstr[0] "%d 人ã®è¿½åŠ ã‚³ãƒ¡ãƒ³ãƒˆæŠ•ç¨¿è€…"
msgid "%d additional committer"
msgid_plural "%d additional committers"
@@ -129,6 +129,10 @@ msgid "%d additional user"
msgid_plural "%d additional users"
msgstr[0] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d 人ã®æ‰¿èªè€…"
@@ -209,18 +213,10 @@ msgid "%d epic"
msgid_plural "%d epics"
msgstr[0] "%d 件ã®ã‚¨ãƒ”ック"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d 件ã®ã‚¨ãƒ©ãƒ¼"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d exporter"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%d 件ã®å¤±æ•—"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] "%d 件ã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ã‚¸ãƒ§ãƒ–ãŒå¤±æ•—ã—ã¾ã—ãŸ"
@@ -229,10 +225,6 @@ msgid "%d file"
msgid_plural "%d files"
msgstr[0] "%d 個ã®ãƒ•ã‚¡ã‚¤ãƒ«"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d 件ã®ãƒ†ã‚¹ãƒˆã§ä¿®æ­£ã•ã‚Œã¾ã—ãŸ"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] "%d 件ã®ãƒ•ã‚©ãƒ¼ã‚¯"
@@ -327,7 +319,7 @@ msgstr[0] ""
msgid "%d remaining"
msgid_plural "%d remaining"
-msgstr[0] ""
+msgstr[0] "残り%d"
msgid "%d reply"
msgid_plural "%d replies"
@@ -367,19 +359,19 @@ msgstr[0] "%d 件ã®è„†å¼±æ€§ãŒç„¡è¦–ã•ã‚Œã¾ã—ãŸ"
msgid "%d vulnerability set to confirmed"
msgid_plural "%d vulnerabilities set to confirmed"
-msgstr[0] ""
+msgstr[0] "確èªæ¸ˆã¿ã«è¨­å®šã•ã‚ŒãŸ %d 件ã®è„†å¼±æ€§"
msgid "%d vulnerability set to dismissed"
msgid_plural "%d vulnerabilities set to dismissed"
-msgstr[0] ""
+msgstr[0] "無視ã«è¨­å®šã•ã‚ŒãŸ %d 件ã®è„†å¼±æ€§"
msgid "%d vulnerability set to needs triage"
msgid_plural "%d vulnerabilities set to needs triage"
-msgstr[0] ""
+msgstr[0] "è¦ãƒˆãƒªã‚¢ãƒ¼ã‚¸ã«è¨­å®šã•ã‚ŒãŸ %d 件ã®è„†å¼±æ€§"
msgid "%d vulnerability set to resolved"
msgid_plural "%d vulnerabilities set to resolved"
-msgstr[0] ""
+msgstr[0] "解決ã«è¨­å®šã•ã‚ŒãŸ %d 件ã®è„†å¼±æ€§"
msgid "%d warning found:"
msgid_plural "%d warnings found:"
@@ -393,7 +385,7 @@ msgid "%{actionText} & %{openOrClose} %{noteable}"
msgstr "%{actionText} 㨠%{openOrClose} %{noteable}"
msgid "%{actionText} & close %{noteable}"
-msgstr ""
+msgstr "%{actionText} & %{noteable}をクローズ"
msgid "%{actionText} & reopen %{noteable}"
msgstr "%{actionText} ãã—㦠%{noteable} ã‚’å†ã³é–‹ã"
@@ -414,7 +406,7 @@ msgid "%{authorsName}'s thread"
msgstr "%{authorsName}ã®ã‚¹ãƒ¬ãƒƒãƒ‰"
msgid "%{author} requested to merge %{source_branch} %{copy_button} into %{target_branch} %{created_at}"
-msgstr ""
+msgstr "%{author}ãŒ%{source_branch} %{copy_button}ã‹ã‚‰%{target_branch} %{created_at}ã¸ã®ãƒžãƒ¼ã‚¸ã‚’リクエストã—ã¾ã—ãŸ"
msgid "%{board_target} not found"
msgstr "%{board_target} ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
@@ -431,6 +423,9 @@ msgid "%{bold_start}%{count}%{bold_end} opened merge request"
msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] "%{bold_start}%{count}%{bold_end} 件ã®ã‚ªãƒ¼ãƒ—ンã—ã¦ã„るマージリクエスト"
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr "%{code_open}マスク:%{code_close} ジョブログã§éžè¡¨ç¤ºã«ã—ã¾ã™ã€‚マスキングã®è¦ä»¶ã‚’満ãŸã™å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
@@ -454,10 +449,10 @@ msgid "%{completedWeight} of %{totalWeight} weight completed"
msgstr "%{completedWeight}/%{totalWeight} ウェイトãŒå®Œäº†ã—ã¾ã—ãŸ"
msgid "%{completed} of %{total} issues closed"
-msgstr ""
+msgstr "å…¨ %{total} 件中ã®%{completed} 件ã®ã‚¯ãƒ­ãƒ¼ã‚ºã—ãŸã‚¤ã‚·ãƒ¥ãƒ¼"
msgid "%{completed} of %{total} weight completed"
-msgstr ""
+msgstr "å…¨%{total}個中%{completed}個ã®ã‚¦ã‚§ã‚¤ãƒˆãŒå®Œäº†ã—ã¾ã—ãŸ"
msgid "%{cores} cores"
msgstr "%{cores} コア"
@@ -482,6 +477,14 @@ msgstr[0] "%{count}件ã®é€£çµ¡å…ˆ"
msgid "%{count} files touched"
msgstr "%{count} ファイルãŒå¤‰æ›´ã•ã‚Œã¾ã—ãŸ"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "%{count} 件ã®ã‚¢ã‚¤ãƒ†ãƒ "
@@ -489,6 +492,10 @@ msgstr[0] "%{count} 件ã®ã‚¢ã‚¤ãƒ†ãƒ "
msgid "%{count} items per page"
msgstr "1ページã‚ãŸã‚Š%{count} 件"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+
msgid "%{count} more"
msgstr "他 %{count} 件"
@@ -509,6 +516,10 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] "%{count} 人ã®å‚加者"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} 件ã®é–¢é€£ã—㟠%{pluralized_subject}: %{links}"
@@ -534,7 +545,7 @@ msgid "%{description}- Sentry event: %{errorUrl}- First seen: %{firstSeen}- Last
msgstr "%{description}- Sentry イベント: %{errorUrl}- 最åˆã«æ¤œå‡ºã•ã‚ŒãŸã‚¤ãƒ™ãƒ³ãƒˆ: %{firstSeen}- 最後ã«æ¤œå‡ºã•ã‚ŒãŸã‚¤ãƒ™ãƒ³ãƒˆ: %{lastSeen} %{countLabel}: %{count}%{userCountLabel}: %{userCount}"
msgid "%{doc_link_start}Advanced search%{doc_link_end} is disabled since %{ref_elem} is not the default branch. %{docs_link}"
-msgstr ""
+msgstr "%{doc_link_start}高度ãªæ¤œç´¢%{doc_link_end} ã¯ã€ç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™ã€‚ %{ref_elem} ãŒãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®ãƒ–ランãƒã§ã¯ãªã„ãŸã‚ã§ã™ã€‚ %{docs_link}"
msgid "%{doc_link_start}Advanced search%{doc_link_end} is enabled."
msgstr "%{doc_link_start}高度ãªæ¤œç´¢%{doc_link_end} ãŒæœ‰åŠ¹ã§ã™ã€‚"
@@ -548,9 +559,6 @@ msgstr "%{docs_link_start} Large File Storage ã¨ã¯ä½•ã§ã™ã‹? %{docs_link_en
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr "%{docs_link_start}二è¦ç´ èªè¨¼ã¨ã¯ä½•ã§ã™ã‹ï¼Ÿ%{docs_link_end}"
-msgid "%{due_date} (Past due)"
-msgstr "%{due_date} (期é™åˆ‡ã‚Œ)"
-
msgid "%{duration}ms"
msgstr "%{duration}ms"
@@ -570,7 +578,7 @@ msgid "%{emailPrefix}@company.com"
msgstr "%{emailPrefix}@company.com"
msgid "%{enable_service_ping_link_start}Enable%{link_end} or %{generate_manually_link_start}generate%{link_end} Service Ping to preview and download service usage data payload."
-msgstr ""
+msgstr "Service Ping ã‚’%{enable_service_ping_link_start}有効化%{link_end} ã¾ãŸã¯ %{generate_manually_link_start}生æˆ%{link_end} ã—ã¦ã€ã‚µãƒ¼ãƒ“ス利用データペイロードをプレビューãŠã‚ˆã³ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰ã—ã¾ã™ã€‚"
msgid "%{extra} more downstream pipelines"
msgstr "%{extra} 個ã®ãƒ€ã‚¦ãƒ³ã‚¹ãƒˆãƒªãƒ¼ãƒ ãƒ‘イプライン"
@@ -600,7 +608,7 @@ msgid "%{group_name} group members"
msgstr "%{group_name} グループã®ãƒ¡ãƒ³ãƒãƒ¼"
msgid "%{group_name} is approaching the limit of available seats"
-msgstr ""
+msgstr "%{group_name} ã®åˆ©ç”¨å¯èƒ½ãªã‚·ãƒ¼ãƒˆæ•°ãŒä¸Šé™ã«è¿‘ã¥ã„ã¦ã„ã¾ã™"
msgid "%{group_name} uses group managed accounts. You need to create a new GitLab account which will be managed by %{group_name}."
msgstr "%{group_name} ã¯ã‚°ãƒ«ãƒ¼ãƒ—管ç†ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’使用ã—ã¾ã™ã€‚ %{group_name} ã«ã‚ˆã£ã¦ç®¡ç†ã•ã‚Œã‚‹æ–°ã—ã„GitLabアカウントを作æˆã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
@@ -627,7 +635,7 @@ msgid "%{issuable_class_name} doesn't exist or you don't have permission to add
msgstr ""
msgid "%{issuable}(s) already assigned"
-msgstr ""
+msgstr "%{issuable}ã¯ã™ã§ã«å‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¦ã„ã¾ã™"
msgid "%{issueType} actions"
msgstr "%{issueType} アクション"
@@ -744,7 +752,7 @@ msgid "%{milliseconds}ms"
msgstr "%{milliseconds} ミリ秒"
msgid "%{minutesUsed} minutes"
-msgstr ""
+msgstr "%{minutesUsed} 分"
msgid "%{model_name} not found"
msgstr "%{model_name} ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
@@ -761,12 +769,6 @@ msgstr "åå‰ç©ºé–“ã® %{name_with_link} ã«ã¯ 共有ランナーパイプラã
msgid "%{name} (Busy)"
msgstr "%{name} (ビジー)"
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} ã«ã¯ %{resultsString} ãŒå«ã¾ã‚Œã¦ã„ã¾ã™"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} ã« %{resultsString} ãŒè¦‹ã¤ã‹ã‚Šã¾ã—ãŸ"
-
msgid "%{name} is already being used for another emoji"
msgstr "%{name} ã¯æ—¢ã«åˆ¥ã®çµµæ–‡å­—ã«ä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã™"
@@ -789,7 +791,7 @@ msgid "%{name}, confirm your email address now!"
msgstr "%{name}ã•ã‚“ã€ä»Šã™ãメールアドレスを確èªã—ã¦ãã ã•ã„ï¼"
msgid "%{name}: %{resultsString}"
-msgstr ""
+msgstr "%{name}: %{resultsString}"
msgid "%{no_of_days} day"
msgid_plural "%{no_of_days} days"
@@ -820,10 +822,10 @@ msgid "%{over_limit_message} To get more seats, %{link_start}upgrade to a paid t
msgstr ""
msgid "%{percentageUsed}%% used"
-msgstr ""
+msgstr "%{percentageUsed}%% 使用済"
msgid "%{percentage}%% issues closed"
-msgstr ""
+msgstr "%{percentage}%% ã®ã‚¤ã‚·ãƒ¥ãƒ¼ãŒã‚¯ãƒ­ãƒ¼ã‚ºã•ã‚Œã¾ã—ãŸ"
msgid "%{percentage}%% weight completed"
msgstr "ウェイト㮠%{percentage}%% ãŒå®Œäº†ã—ã¾ã—ãŸ"
@@ -841,10 +843,10 @@ msgid "%{placeholder} is not a valid theme"
msgstr "%{placeholder} 㯠有効ãªãƒ†ãƒ¼ãƒžã§ã¯ã‚ã‚Šã¾ã›ã‚“。"
msgid "%{policy_link} (notifying after %{elapsed_time} minutes unless %{status})"
-msgstr ""
+msgstr "%{policy_link} (%{status}を除ã„㦠%{elapsed_time} 分後ã«é€šçŸ¥ï¼‰"
msgid "%{project_name}"
-msgstr ""
+msgstr "%{project_name}"
msgid "%{project_path} is a project that you can use to add a README to your GitLab profile. Create a public project and initialize the repository with a README to get started. %{help_link_start}Learn more.%{help_link_end}"
msgstr "%{project_path} ã¯ã€GitLab プロファイルã«READMEを追加ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã™ã‚‹ãƒ—ロジェクトã§ã™ã€‚開始ã™ã‚‹ã«ã¯ã€ãƒ‘ブリックプロジェクトを作æˆã—ã€README ãŒå«ã¾ã‚ŒãŸçŠ¶æ…‹ã§ãƒªãƒã‚¸ãƒˆãƒªã‚’åˆæœŸåŒ–ã—ã¾ã™ã€‚ %{help_link_start}詳細ã¯ã“ã¡ã‚‰%{help_link_end}"
@@ -878,7 +880,7 @@ msgid "%{rotation} has been recalculated with the remaining participants. Please
msgstr "残りã®å‚加者ã‹ã‚‰ %{rotation} ã‚’å†è¨ˆç®—ã—ã¾ã—ãŸã€‚ %{rotation}ã®æ–°ã—ã„設定を確èªã—ã¦ãã ã•ã„。 オンコールã®ã‚«ãƒãƒ¬ãƒƒã‚¸ã‚’確èªã™ã‚‹ãŸã‚ã«ã€ç¾åœ¨ã®ã‚ªãƒ³ã‚³ãƒ¼ãƒ«ã®å¯¾å¿œè€…ã«é€£çµ¡ã™ã‚‹ã“ã¨ã‚’ãŠå‹§ã‚ã—ã¾ã™ã€‚"
msgid "%{runner} created %{timeago}"
-msgstr ""
+msgstr "%{runner} ã¯%{timeago} ã«ä½œæˆã•ã‚Œã¾ã—ãŸ"
msgid "%{scope} results for term '%{term}'"
msgstr "期間'%{term}' ã®%{scope} 件ã®çµæžœ"
@@ -943,6 +945,9 @@ msgid_plural "%{strongStart}%{count}%{strongEnd} commits"
msgstr[0] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
+msgstr "%{strongStart}ヒント:%{strongEnd} %{linkStart}ã“れらã®ã‚¬ã‚¤ãƒ‰ãƒ©ã‚¤ãƒ³%{linkEnd}ã«å¾“ã£ã¦ãƒ­ãƒ¼ã‚«ãƒ«ã§ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’ãƒã‚§ãƒƒã‚¯ã‚¢ã‚¦ãƒˆã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚"
+
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
msgstr ""
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
@@ -1035,7 +1040,7 @@ msgid "%{type} must be a %{help_link}"
msgstr ""
msgid "%{type} only supports %{name} name"
-msgstr ""
+msgstr "%{type} %{name} åå‰ã®ã¿ã‚’サãƒãƒ¼ãƒˆã—ã¾ã™"
msgid "%{userName} (cannot merge)"
msgstr "%{userName} (マージã§ãã¾ã›ã‚“)"
@@ -1047,10 +1052,10 @@ msgid "%{user_name} (%{user_username}) was removed from %{rotation} in %{schedul
msgstr "%{user_name} (%{user_username}) 㯠%{project} プロジェクト㮠%{schedule}ã®%{rotation} ã‹ã‚‰å‰Šé™¤ã•ã‚Œã¾ã—ãŸã€‚ "
msgid "%{user_name} (%{user_username}) was removed from the following escalation policies in %{project_link}: "
-msgstr ""
+msgstr "%{user_name} (%{user_username}) 㯠%{project_link}ã«ã‚る次ã®ã‚¨ã‚¹ã‚«ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ãƒãƒªã‚·ãƒ¼ã®ãŸã‚削除ã•ã‚Œã¾ã—ãŸ: "
msgid "%{user_name} (%{user_username}) was removed from the following escalation policies in %{project}:"
-msgstr ""
+msgstr "%{user_name} (%{user_username}) 㯠%{project}ã«ã‚る次ã®ã‚¨ã‚¹ã‚«ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ãƒãƒªã‚·ãƒ¼ã®ãŸã‚削除ã•ã‚Œã¾ã—ãŸ:"
msgid "%{user_name} profile page"
msgstr "%{user_name} プロフィールページ"
@@ -1079,9 +1084,6 @@ msgstr "%{user} ãŒã‚¤ã‚·ãƒ¥ãƒ¼ã‚’作æˆã—ã¾ã—ãŸ: %{issue_link}"
msgid "%{value} is not included in the list"
msgstr "%{value} ã¯ãƒªã‚¹ãƒˆã«å«ã¾ã‚Œã¦ã„ã¾ã›ã‚“。"
-msgid "%{value} s"
-msgstr "%{value} 秒"
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} ã—㦠%{time_spent_value} ãŒçµŒéŽã—ã¾ã—ãŸã€‚"
@@ -1139,6 +1141,9 @@ msgstr "'%{source}' ã¯ã‚¤ãƒ³ãƒãƒ¼ãƒˆã‚½ãƒ¼ã‚¹ã§ã¯ã‚ã‚Šã¾ã›ã‚“。"
msgid "'%{template_name}' is unknown or invalid"
msgstr "'%{template_name}' ã¯ä¸æ˜Žã€ã¾ãŸã¯ç„¡åŠ¹ã§ã™"
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d 個ã®ã‚¯ãƒ­ãƒ¼ã‚º)"
@@ -1176,6 +1181,9 @@ msgstr "(変更ã—ãŸããªã„å ´åˆã€ç©ºç™½ã®ã¾ã¾ã«ã—ã¦ãã ã•ã„)"
msgid "(max size 15 MB)"
msgstr "(最大サイズ 15MB)"
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr "(オプション)"
@@ -1235,10 +1243,10 @@ msgid ", or "
msgstr "ã€ã¾ãŸã¯"
msgid "- %{policy_name} (notifying after %{elapsed_time} minutes unless %{status})"
-msgstr ""
+msgstr "- %{policy_name} (%{status}を除ã„㦠%{elapsed_time} 分後ã«é€šçŸ¥ï¼‰"
msgid "- Add or remove a user."
-msgstr ""
+msgstr "- ユーザーを追加ã¾ãŸã¯å‰Šé™¤ã—ã¾ã™ã€‚"
msgid "- Available to run jobs."
msgstr "- ジョブを実行ã§ãã¾ã™ã€‚"
@@ -1247,23 +1255,23 @@ msgid "- Create or close an issue."
msgstr ""
msgid "- Create, update, or delete a merge request."
-msgstr ""
+msgstr "- マージリクエストを作æˆã€æ›´æ–°ã€ã¾ãŸã¯å‰Šé™¤ã—ã¾ã™ã€‚"
msgid "- Event"
msgid_plural "- Events"
msgstr[0] "- イベント"
msgid "- Go to the Activity page for %{project_name}."
-msgstr ""
+msgstr "- %{project_name} ã®ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティページã«ç§»å‹•ã—ã¾ã™ã€‚"
msgid "- List the visible events for %{project_name} using the Events API %{events_api_link}."
-msgstr ""
+msgstr "- Events API %{events_api_link}を使用ã—ã¦ã€ %{project_name} ã®è¡¨ç¤ºå¯èƒ½ãªã‚¤ãƒ™ãƒ³ãƒˆã‚’一覧表示ã—ã¾ã™ã€‚"
msgid "- Not available to run jobs."
msgstr "- ジョブを実行ã§ãã¾ã›ã‚“。"
msgid "- Push code to the repository."
-msgstr ""
+msgstr "- リãƒã‚¸ãƒˆãƒªã«ã‚³ãƒ¼ãƒ‰ã‚’プッシュã—ã¾ã™ã€‚"
msgid "- Select -"
msgstr "- é¸æŠž -"
@@ -1273,7 +1281,7 @@ msgid_plural "- Users"
msgstr[0] "- ユーザー"
msgid "- View the last_activity_at attribute for %{project_name} using the Project API %{projects_api_link}."
-msgstr ""
+msgstr "- Project API %{projects_api_link} を使用ã—㦠%{project_name} ã® last_activity_at 属性を表示ã—ã¾ã™ã€‚"
msgid "- of - issues closed"
msgstr ""
@@ -1402,7 +1410,7 @@ msgid "1000+"
msgstr "1000 以上"
msgid "192.168.0.0/24 or 2001:0DB8:1234::/48"
-msgstr ""
+msgstr "192.168.0.0/24 ã¾ãŸã¯ 2001:0DB8:1234::/48"
msgid "1st contribution!"
msgstr "最åˆã®è²¢çŒ®!"
@@ -1434,6 +1442,9 @@ msgstr "ã“ã®ãƒšãƒ¼ã‚¸ã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹æ¨©é™ãŒã‚ã‚Šã¾ã›ã‚“。"
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "URLãŒæ­£ã—ããªã„ã‹ã€ãƒšãƒ¼ã‚¸ãŒç§»å‹•ã•ã‚ŒãŸå¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚"
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr "ページãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
@@ -1441,10 +1452,10 @@ msgid "404|Please contact your GitLab administrator if you think this is a mista
msgstr "ã“ã®ãƒšãƒ¼ã‚¸ãŒæ­£ã—ããªã„å ´åˆã€GitLab 管ç†è€…ã«é€£çµ¡ã—ã¦ãã ã•ã„。"
msgid "409|Please contact your GitLab administrator if you think this is a mistake."
-msgstr ""
+msgstr "ã“ã‚ŒãŒæ­£ã—ããªã„å ´åˆã€GitLab管ç†è€…ã«é€£çµ¡ã—ã¦ãã ã•ã„。"
msgid "409|There was a conflict with your request."
-msgstr ""
+msgstr "リクエストã¨ã‚³ãƒ³ãƒ•ãƒªã‚¯ãƒˆãŒã‚ã‚Šã¾ã—ãŸã€‚"
msgid "8 hours"
msgstr "8 時間"
@@ -1497,9 +1508,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "プロジェクトãŒç©ºã®å ´åˆã¯ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®ãƒ–ランãƒã‚’é¸æŠžã§ãã¾ã›ã‚“。"
-
msgid "A deleted user"
msgstr "削除ã•ã‚ŒãŸãƒ¦ãƒ¼ã‚¶ãƒ¼"
@@ -1516,7 +1524,7 @@ msgid "A file with '%{file_name}' already exists in %{branch} branch"
msgstr "ファイル '%{file_name}' ã¯æ—¢ã« %{branch} ブランãƒã«å­˜åœ¨ã—ã¾ã™"
msgid "A file with this name already exists."
-msgstr ""
+msgstr "ã“ã®åå‰ã®ãƒ•ã‚¡ã‚¤ãƒ«ã¯æ—¢ã«å­˜åœ¨ã—ã¦ã„ã¾ã™ã€‚"
msgid "A group is a collection of several projects"
msgstr "グループã§è¤‡æ•°ã®ãƒ—ロジェクトをã¾ã¨ã‚ã‚‹ã“ã¨ãŒå‡ºæ¥ã¾ã™ã€‚"
@@ -1546,13 +1554,13 @@ msgid "A new Release %{tag} for %{name} was published. Visit the Releases page t
msgstr "%{name} ã®æ–°ã—ã„リリース %{tag} ãŒå…¬é–‹ã•ã‚Œã¾ã—ãŸã€‚ リリースページã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¦è©³ç´°ã‚’確èªã—ã¦ãã ã•ã„:"
msgid "A new email address has been added to your GitLab account: %{email}"
-msgstr ""
+msgstr "GitLab アカウントã«æ–°ã—ã„メールアドレスãŒè¿½åŠ ã•ã‚Œã¾ã—ãŸ: %{email}"
msgid "A new personal access token has been created"
-msgstr ""
+msgstr "æ–°ã—ã„パーソナルアクセストークンãŒä½œæˆã•ã‚Œã¾ã—ãŸ"
msgid "A new personal access token, named %{token_name}, has been created."
-msgstr ""
+msgstr "%{token_name} ã¨ã„ã†åå‰ã®æ–°ã—ã„パーソナルアクセストークンãŒä½œæˆã•ã‚Œã¾ã—ãŸã€‚"
msgid "A non-confidential epic cannot be assigned to a confidential parent epic"
msgstr "公開エピックã®è¦ªã‚¨ãƒ”ックã«éžå…¬é–‹ã‚¨ãƒ”ックã«å‰²ã‚Šå½“ã¦ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
@@ -1564,7 +1572,7 @@ msgid "A non-confidential work item cannot have a confidential parent."
msgstr ""
msgid "A page with that title already exists"
-msgstr ""
+msgstr "ã“ã®ã‚¿ã‚¤ãƒˆãƒ«ã®ãƒšãƒ¼ã‚¸ã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™"
msgid "A personal access token has been revoked"
msgstr ""
@@ -1578,9 +1586,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr "プレーンHTMLã®ã‚µã‚¤ãƒˆã§GitLabã®ä»£ã‚ã‚Šã«Netlifyã‚’CI/CDã§ä½¿ç”¨ã—ã¦ã„ãŸã¨ã—ã¦ã‚‚ã€GitLabã«ã¯ã»ã‹ã«ã‚‚素晴らã—ã„機能ãŒãŸãã•ã‚“ã‚ã‚Šã¾ã™ã€‚"
-msgid "A platform value can be web, mob or app."
-msgstr "プラットフォームã®å€¤ã¯ã€ã‚¦ã‚§ãƒ–ã€ãƒ¢ãƒã‚¤ãƒ«ã€ã¾ãŸã¯ã‚¢ãƒ—リã§ã™ã€‚"
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr "Salesforce Developerツールを使用ã—ãŸSalesforceアプリケーション開発用ã®ãƒ—ロジェクトテンプレート"
@@ -1594,7 +1599,7 @@ msgid "A project’s repository name defines its URL (the one you use to access
msgstr "プロジェクトã®ãƒªãƒã‚¸ãƒˆãƒªåã¯ã€ãã®URL(ブラウザーを介ã—ã¦ãƒ—ロジェクトã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã™ã‚‹ã‚‚ã®ï¼‰ã¨GitLabãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚Œã¦ã„るファイルディスク上ã®å ´æ‰€ã‚’定義ã—ã¾ã™ã€‚ %{link_start}詳細ã¯ã“ã¡ã‚‰ã€‚%{link_end}"
msgid "A quarterly reconciliation is due on %{date}"
-msgstr ""
+msgstr "%{date} ã«å››åŠæœŸæ¯Žã®èª¿æ•´ã‚’è¡Œã„ã¾ã™"
msgid "A ready-to-go template for use with Android apps"
msgstr "Android アプリã§ã™ãã«ä½¿ãˆã‚‹ãƒ†ãƒ³ãƒ—レート。"
@@ -1750,7 +1755,7 @@ msgid "AWS access key ID (Optional)"
msgstr "AWS アクセスキー ID (オプション)"
msgid "AWS secret access key (Optional)"
-msgstr ""
+msgstr "AWS シークレットアクセスキー (オプション)"
msgid "AWS service error: %{error}"
msgstr "AWS サービスエラー: %{error}"
@@ -1788,6 +1793,9 @@ msgstr "利用è¦ç´„ã«åŒæ„ã™ã‚‹"
msgid "Acceptable for use in this project"
msgstr "ã“ã®ãƒ—ロジェクトã¯ä½¿ç”¨å¯èƒ½"
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr "Git リãƒã‚¸ãƒˆãƒªã¾ãŸã¯ API ã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¾ã™ã€‚"
@@ -1843,7 +1851,7 @@ msgid "AccessTokens|Are you sure? Any issue email addresses currently in use wil
msgstr "本当ã«ã‚ˆã‚ã—ã„ã§ã™ã‹ï¼Ÿç¾åœ¨ä½¿ç”¨ã—ã¦ã„るメールアドレスã¯æ©Ÿèƒ½ã—ãªããªã‚Šã¾ã™ã€‚"
msgid "AccessTokens|Copy feed token"
-msgstr ""
+msgstr "フィードトークンをコピー"
msgid "AccessTokens|Copy incoming email token"
msgstr "å—信メールトークンをコピー"
@@ -1864,13 +1872,13 @@ msgid "AccessTokens|It cannot be used to access any other data."
msgstr "ä»–ã®ãƒ‡ãƒ¼ã‚¿ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã«ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“。"
msgid "AccessTokens|Keep this token secret. Anyone who has it can access repository static objects as if they were you. If that ever happens, %{linkStart}reset this token%{linkEnd}."
-msgstr ""
+msgstr "ã“ã®ãƒˆãƒ¼ã‚¯ãƒ³ã‚’外部ã«æ¼ã‚‰ã•ãªã„ã§ãã ã•ã„。ã“れをæŒã£ã¦ã„る人ã¯èª°ã§ã‚‚ã‚ãªãŸã«ãªã‚Šã™ã¾ã—ã¦ãƒªãƒã‚¸ãƒˆãƒªã®é™çš„オブジェクトã«ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã™ã€‚ã‚‚ã—ã‚‚æ¼æ´©ã—ãŸå ´åˆã€ %{linkStart} ã“ã®ãƒˆãƒ¼ã‚¯ãƒ³ã‚’リセット %{linkEnd}ã™ã¹ãã§ã™ã€‚"
msgid "AccessTokens|Keep this token secret. Anyone who has it can create issues as if they were you. If that happens, %{linkStart}reset this token%{linkEnd}."
-msgstr ""
+msgstr "ã“ã®ãƒˆãƒ¼ã‚¯ãƒ³ã¯ç§˜å¯†ã«ã—ã¦ãŠã„ã¦ãã ã•ã„。ã“れをæŒã£ã¦ã„る人ã¯èª°ã§ã‚‚ã‚ãªãŸã¨åŒã˜ã‚ˆã†ã«ã‚¤ã‚·ãƒ¥ãƒ¼ã‚’作æˆã§ãã¾ã™ã€‚ã‚‚ã—æ¼æ´©ã—ãŸå ´åˆã€%{linkStart}ã“ã®ãƒˆãƒ¼ã‚¯ãƒ³ã‚’リセットã—ã¦ãã ã•ã„%{linkEnd}。"
msgid "AccessTokens|Keep this token secret. Anyone who has it can read activity and issue RSS feeds or your calendar feed as if they were you. If that happens, %{linkStart}reset this token%{linkEnd}."
-msgstr ""
+msgstr "ã“ã®ãƒˆãƒ¼ã‚¯ãƒ³ã‚’外部ã«æ¼ã‚‰ã•ãªã„ã§ãã ã•ã„。ã“れをæŒã£ã¦ã„る人ã¯èª°ã§ã‚‚ã‚ãªãŸã®ã‚ˆã†ã«ã‚¢ã‚¯ãƒ†ã‚£ãƒ“ティを読ã‚ã€ã‚ãªãŸã¨ã—ã¦RSSフィードやカレンダーã®ãƒ•ã‚£ãƒ¼ãƒ‰ã‚’発行ã§ãã¾ã™ã€‚æ¼æ´©ã—ãŸå ´åˆã¯ã€%{linkStart}ã“ã®ãƒˆãƒ¼ã‚¯ãƒ³ã‚’リセットã—ã¦ãã ã•ã„%{linkEnd}。"
msgid "AccessTokens|Personal Access Tokens"
msgstr "パーソナルアクセストークン"
@@ -1899,15 +1907,9 @@ msgstr "ã‚ãªãŸãŒãƒ¡ãƒ¼ãƒ«ã§æ–°ã—ã„イシューを作æˆã™ã‚‹ã¨ãã€ã‚
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr "(アーカイブã€ãƒ–ロブãªã©ã®) リãƒã‚¸ãƒˆãƒªã®é™çš„オブジェクトãŒå¤–部ストレージã‹ã‚‰æä¾›ã•ã‚Œã¦ã„ã‚‹å ´åˆã€é™çš„オブジェクトトークンã§ã‚ãªãŸã‚’èªè¨¼ã—ã¾ã™ã€‚"
-msgid "AccessibilityReport|Learn more"
-msgstr "詳細を表示"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "メッセージ: %{message}"
-msgid "AccessibilityReport|New"
-msgstr " æ–°ã—ã„"
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr "アクセシビリティã®ã‚¹ã‚­ãƒ£ãƒ³ã§æ¬¡ã®ã‚¿ã‚¤ãƒ—ã®ã‚¨ãƒ©ãƒ¼ãŒè¦‹ã¤ã‹ã‚Šã¾ã—ãŸ: %{code}"
@@ -1933,28 +1935,28 @@ msgid "Account: %{account}"
msgstr "アカウント: %{account}"
msgid "AccountValidation|Fix your pipelines by validating your account"
-msgstr ""
+msgstr "アカウントを検証ã—ã¦ãƒ‘イプラインを修正ã™ã‚‹"
msgid "AccountValidation|I'll bring my own runners"
-msgstr ""
+msgstr "自分㮠Runner ã‚’æŒã¡è¾¼ã¿ã¾ã™"
msgid "AccountValidation|In order to use free CI/CD minutes on shared runners, you'll need to validate your account using one of our verification options. If you prefer not to, you can run pipelines by bringing your own runners and disabling shared runners for your project."
-msgstr ""
+msgstr "共有Runner ã§ç„¡æ–™ã®CI/CDを使用ã™ã‚‹ã«ã¯ã€ç§é”ãŒæŒ‡å®šã™ã‚‹æ–¹æ³•ã‚’使ã£ã¦ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’検証ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ æä¾›ã—ãŸããªã„å ´åˆã¯ã€è‡ªåˆ†ã®Runnerã‚’æŒå‚ã—ã€ãƒ—ロジェクトã§å…±æœ‰Runnerを無効ã«ã™ã‚‹ã“ã¨ã§ãƒ‘イプラインを実行ã§ãã¾ã™ã€‚"
msgid "AccountValidation|Learn more."
msgstr "詳ã—ã見る"
msgid "AccountValidation|Looks like you’ll need to validate your account to use free CI/CD minutes"
-msgstr ""
+msgstr "無料㮠CI/CDを使用ã™ã‚‹ã«ã¯ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’検証ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
msgid "AccountValidation|Validate your account"
-msgstr ""
+msgstr "アカウントã®æ¤œè¨¼"
msgid "AccountValidation|Verification is required to discourage and reduce the abuse on GitLab infrastructure. If you verify with a credit or debit card, %{strong_start}GitLab will not charge your card, it will only be used for validation.%{strong_end} %{learn_more_link}"
-msgstr ""
+msgstr "アカウントã®æ¤œè¨¼ã¯ã€GitLab インフラストラクãƒãƒ£ã®ä¸æ­£åˆ©ç”¨ã‚’阻止ã—ã€è»½æ¸›ã™ã‚‹ãŸã‚ã«å¿…è¦ã§ã™ã€‚ クレジットカードã¾ãŸã¯ãƒ‡ãƒ“ットカードã§æ¤œè¨¼ã—ãŸå ´åˆã€%{strong_start}GitLab ã¯ã‚«ãƒ¼ãƒ‰ã®ãƒãƒ£ãƒ¼ã‚¸ã‚„ä¿ç®¡ã‚’è¡Œã‚ãšã€æ¤œè¨¼ã«ã®ã¿ä½¿ç”¨ã—ã¦ã„ã¾ã™ã€‚%{strong_end} %{learn_more_link}"
msgid "Acknowledge"
-msgstr ""
+msgstr "承èªã™ã‚‹"
msgid "Action"
msgstr "アクション"
@@ -1977,9 +1979,6 @@ msgstr "有効"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr "有効 %{type} (%{token_length})"
-
msgid "Active Sessions"
msgstr "アクティブ セッション"
@@ -2352,6 +2351,12 @@ msgstr "%{labels} %{label_text} を追加。"
msgid "Adds a Zoom meeting."
msgstr "Zoom ミーティングを追加。"
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2535,6 +2540,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr "統計ã®èª­ã¿è¾¼ã¿ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2571,15 +2594,27 @@ msgstr "Auto DevOps ドメイン"
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2628,6 +2663,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr "æ–°ã—ã„プロジェクトã§å…±æœ‰ Runner を有効ã«ã™ã‚‹"
@@ -2673,6 +2711,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2811,9 +2861,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2838,6 +2897,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -2940,6 +3008,9 @@ msgstr "管ç†è€…"
msgid "AdminUsers|Admins"
msgstr "管ç†è€…"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr "承èªã™ã‚‹"
@@ -3132,8 +3203,8 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr "Web, Git, APIã‚’å«ã‚€ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¸ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚¢ã‚¯ã‚»ã‚¹ã‚’復元ã—ã¾ã™ã€‚"
-msgid "AdminUsers|Search by name, email or username"
-msgstr "åå‰ã€ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼åã§æ¤œç´¢"
+msgid "AdminUsers|Search by name, email, or username"
+msgstr ""
msgid "AdminUsers|Search users"
msgstr "ユーザーを検索"
@@ -3177,8 +3248,8 @@ msgstr "ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯é€šçŸ¥ã‚’å—ã‘å–ã‚Œãªããªã‚Šã¾ã™"
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "確èªã®ãŸã‚ã€%{projectName} を入力ã—ã¦ãã ã•ã„"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "確èªã®ãŸã‚ã€%{username} を入力ã—ã¦ãã ã•ã„"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr ""
msgid "AdminUsers|Unban user"
msgstr "ユーザーã®ãƒ–ロック解除"
@@ -3240,8 +3311,8 @@ msgstr "プロジェクトãªã—"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr "ã‚ãªãŸã¯ãƒ¦ãƒ¼ã‚¶ãƒ¼ %{username} を完全ã«å‰Šé™¤ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚ユーザーã«ãƒªãƒ³ã‚¯ã—ã¦ã„ã‚‹ã€ã‚¤ã‚·ãƒ¥ãƒ¼ã€ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã€ãŠã‚ˆã³ã‚°ãƒ«ãƒ¼ãƒ—ã¯ã€ã‚·ã‚¹ãƒ†ãƒ å…¨ä½“ã®ã€ŒGhost ユーザーã€ã«è»¢é€ã•ã‚Œã¾ã™ã€‚データã®æ失をé¿ã‘ã‚‹ãŸã‚ã«ã¯ã€ä»£ã‚ã‚Šã«%{strongStart}ユーザーã®ãƒ–ロック機能%{strongEnd}を使用ã™ã‚‹ã“ã¨ã‚’検討ã—ã¦ãã ã•ã„。%{strongStart}ユーザーã®å‰Šé™¤%{strongEnd}ã™ã‚‹ã¨ã€å…ƒã«æˆ»ã™ã“ã¨ã¯ã§ãã¾ã›ã‚“ã—復元もã§ãã¾ã›ã‚“。"
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
-msgstr "ã‚ãªãŸã¯ãƒ¦ãƒ¼ã‚¶ãƒ¼ %{username}を完全ã«å‰Šé™¤ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚ユーザーã«ãƒªãƒ³ã‚¯ã—ã¦ã„ã‚‹ã€èª²é¡Œã€ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã€ãŠã‚ˆã³ã‚°ãƒ«ãƒ¼ãƒ—ã¯å‰Šé™¤ã•ã‚Œã¾ã™ã€‚データã®æ失をé¿ã‘ã‚‹ãŸã‚ã«ã¯ã€ä»£ã‚ã‚Šã«%{strongStart}ユーザーã®ãƒ–ロック機能%{strongEnd}を使用ã™ã‚‹ã“ã¨ã‚’検討ã—ã¦ãã ã•ã„。%{strongStart}ユーザーã®å‰Šé™¤%{strongEnd}ã™ã‚‹ã¨ã€å…ƒã«æˆ»ã™ã“ã¨ã¯ã§ãã¾ã›ã‚“ã—復元もã§ãã¾ã›ã‚“。"
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
+msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
msgstr "å¿…è¦ãªã¨ãã¯ã„ã¤ã§ã‚‚ã“れらã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’ブロックã§ãã¾ã™ã€‚"
@@ -3288,6 +3359,9 @@ msgstr "管ç†"
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr "追加ã•ã‚ŒãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯ã‚·ã‚¹ãƒ†ãƒ ç®¡ç†è€…ã«ã‚ˆã£ã¦ç¢ºèªã•ã‚Œã€æ‰¿èªã•ã‚Œãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。 使用状æ³ã®ä¸Šé™è©³ç´°ã«ã¤ã„ã¦ã¯ã€%{help_link_start} ã“ã¡ã‚‰%{help_link_end} ã‚’ã”覧ãã ã•ã„。"
@@ -3798,8 +3872,8 @@ msgstr "ã™ã¹ã¦ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«åå‰ãŒå¿…è¦ã§ã™ã€‚"
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
-msgstr "%{group_name} ã«ã‚µã‚¤ãƒ³ã‚¤ãƒ³ã‚’許å¯"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr ""
msgid "Allow access to members of the following group"
msgstr ""
@@ -3813,6 +3887,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr "グループオーナー㌠LDAP 関連ã®è¨­å®šã‚’管ç†ã§ãるよã†ã«ã™ã‚‹"
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3849,9 +3926,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4098,6 +4172,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr "ã“ã®ã‚¸ãƒ§ãƒ–ã®ãƒ­ã‚°ã‚’フェッãƒã™ã‚‹é–“ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
@@ -4282,9 +4359,6 @@ msgstr "ジョブã®ãƒˆãƒªã‚¬ãƒ¼ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4384,9 +4458,6 @@ msgstr ""
msgid "Analytics"
msgstr "分æž"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "ä¾å­˜é–¢ä¿‚ã«å«ã¾ã‚Œã¦ã„る既知ã®è„†å¼±æ€§ã‚’分æžã—ã¾ã™ã€‚"
@@ -4489,9 +4560,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr "アプリケーションã®è¨­å®šæ›´æ–°ã«å¤±æ•—ã—ã¾ã—ãŸ"
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr "アプリケーションã¯ã‚¢ãƒ³ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã—ã¾ã—ãŸãŒã€ç ´æ£„ã«å¤±æ•—ã—ã¾ã—ãŸ: %{error_message}"
-
msgid "Application was successfully destroyed."
msgstr "アプリケーションã¯æ­£å¸¸ã«ç ´æ£„ã•ã‚Œã¾ã—ãŸã€‚"
@@ -4510,7 +4578,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4551,6 +4619,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4569,9 +4640,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4599,6 +4679,9 @@ msgstr "変更をä¿å­˜"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -4934,9 +5017,6 @@ msgstr "ã“ã®ãƒ–ロックã•ã‚Œã¦ã„るイシューをクローズã—ã¦ã‚‚よ
msgid "Are you sure you want to delete %{name}?"
msgstr "%{name} を削除ã—ã¾ã™ã‹ï¼Ÿ"
-msgid "Are you sure you want to delete these artifacts?"
-msgstr "ã“れらã®ã‚¢ãƒ¼ãƒ†ã‚£ãƒ•ã‚¡ã‚¯ãƒˆã‚’削除ã—ã¦ã‚‚よã‚ã—ã„ã§ã™ã‹ï¼Ÿ"
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5037,7 +5117,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5088,6 +5168,30 @@ msgstr "アーティファクトã¯æ­£å¸¸ã«å‰Šé™¤ã•ã‚Œã¾ã—ãŸã€‚"
msgid "Artifacts"
msgstr "アーティファクト"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr "SASTã®æ©Ÿèƒ½ã‚’ã•ã‚‰ã«æ§‹ç¯‰ã—ã¦ã„ã中ã§ã€%{linkStart}ã“ã®ã‚¤ã‚·ãƒ¥ãƒ¼%{linkEnd}ã®SAST設定機能ã«é–¢ã™ã‚‹ãƒ•ã‚£ãƒ¼ãƒ‰ãƒãƒƒã‚¯ã‚’ãŠå¾…ã¡ã—ã¦ã„ã¾ã™ã€‚"
@@ -5139,9 +5243,6 @@ msgstr "#FF0000ã®ã‚ˆã†ãªã‚«ã‚¹ã‚¿ãƒ ã‚«ãƒ©ãƒ¼ã‚’割り当ã¦ã‚‹"
msgid "Assign labels"
msgstr "ラベルを割り当ã¦ã‚‹"
-msgid "Assign milestone"
-msgstr "マイルストーンを割り当ã¦ã‚‹"
-
msgid "Assign myself"
msgstr ""
@@ -5532,9 +5633,6 @@ msgstr "自動åœæ­¢æ©Ÿèƒ½ã‚’正常ã«ã‚­ãƒ£ãƒ³ã‚»ãƒ«ã—ã¾ã—ãŸã€‚"
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr "デフォルトã®ãƒ–ランãƒã§å‚ç…§ã•ã‚Œã¦ã„るイシューを自動的ã«çµ‚了ã—ã¾ã™ã€‚"
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -5898,6 +5996,12 @@ msgstr "ã”注æ„ãã ã•ã„。プロジェクトã®åå‰ç©ºé–“を変更ã™ã‚‹
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "ã”注æ„ãã ã•ã„。プロジェクトã®ãƒªãƒã‚¸ãƒˆãƒªã®åå‰ã‚’変更ã™ã‚‹ã¨ã€æ„図ã—ãªã„副作用ãŒç™ºç”Ÿã™ã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚"
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6622,6 +6726,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6631,6 +6738,9 @@ msgstr "ブランãƒã¯æ—¢ã«ä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã™"
msgid "Branch name"
msgstr "ブランãƒå"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr "%{branchId} ブランãƒã¯ãƒ­ãƒ¼ãƒ‰ã•ã‚Œã¦ã„ã¾ã›ã‚“。"
@@ -6652,6 +6762,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6670,6 +6783,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6679,6 +6795,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6697,9 +6816,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6718,12 +6843,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -6883,6 +7017,9 @@ msgstr "ブロードキャストメッセージã¯æ­£å¸¸ã«æ›´æ–°ã•ã‚Œã¾ã—ãŸ
msgid "Broadcast Messages"
msgstr "ブロードキャストメッセージ"
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "ディレクトリを表示"
@@ -6892,9 +7029,6 @@ msgstr "ファイルを表示"
msgid "Browse Files"
msgstr "ファイルを表示"
-msgid "Browse artifacts"
-msgstr "アーティファクトをブラウズã™ã‚‹"
-
msgid "Browse files"
msgstr "ファイルを表示"
@@ -6940,9 +7074,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -6973,6 +7104,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -6988,6 +7122,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7012,9 +7149,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7427,9 +7561,6 @@ msgstr "プレビューをキャンセル"
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr "エピックã¨åŒã˜ã‚°ãƒ«ãƒ¼ãƒ—(ã¾ãŸã¯å­å­«ï¼‰ã®ä¸‹ã«å±žã•ãªã„イシューを割り当ã¦ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。"
-
msgid "Cannot be merged automatically"
msgstr "自動的ã«ãƒžãƒ¼ã‚¸ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
@@ -7445,6 +7576,9 @@ msgstr "ä¸æ­£åˆ©ç”¨ãƒ¬ãƒãƒ¼ãƒˆã‚’作æˆã§ãã¾ã›ã‚“。ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr "複数ã®Jiraインãƒãƒ¼ãƒˆã‚’åŒæ™‚ã«å®Ÿè¡Œã§ãã¾ã›ã‚“"
@@ -8182,6 +8316,9 @@ msgstr "キー"
msgid "CiVariables|Masked"
msgstr "マスク"
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9495,10 +9632,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr "コメント/返信 (é¸æŠžã—ãŸãƒ†ã‚­ã‚¹ãƒˆã‚’引用ã—ã¾ã™)"
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9679,6 +9822,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10471,10 +10617,10 @@ msgstr "貢献度"
msgid "Contribution Analytics"
msgstr "貢献度分æž"
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10507,6 +10653,15 @@ msgstr "é¸æŠžã•ã‚ŒãŸæœŸé–“内ã«ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¯ã‚ã‚Šã¾ã›ã‚“。
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr "é¸æŠžã•ã‚ŒãŸæœŸé–“内ã«ãƒ—ッシュã¯ã‚ã‚Šã¾ã›ã‚“"
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10555,9 +10710,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr "%{protocol} クローン URL をコピー"
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr "IDをコピー"
@@ -10642,9 +10794,6 @@ msgstr "秘密情報をコピー"
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10807,9 +10956,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr "トリガーを除去ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"
@@ -11029,9 +11175,6 @@ msgstr "æ–°ã—ã„ファイルやディレクトリを作æˆã—ã¾ã™"
msgid "Create new label"
msgstr "ラベルã®æ–°è¦ä½œæˆ"
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11299,9 +11442,6 @@ msgstr "エピックを作æˆã—ã¦ã„ã¾ã™"
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr "グラフを作æˆã™ã‚‹ã«ã¯ã€Prometheusサーãƒãƒ¼ã‹ã‚‰ã®ãƒ‡ãƒ¼ã‚¿ã‚’使用ã—ã¾ã™ã€‚ã“ã‚Œã«æ™‚é–“ãŒã‹ã‹ã‚‹å ´åˆã¯ã€ãƒ‡ãƒ¼ã‚¿ãŒåˆ©ç”¨ã§ãã‚‹ã‹ã©ã†ã‹ã‚’確èªã—ã¦ãã ã•ã„。"
-msgid "Creation date"
-msgstr "作æˆæ—¥æ™‚"
-
msgid "Creator"
msgstr ""
@@ -11317,7 +11457,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11419,9 +11559,6 @@ msgstr "ç¾åœ¨ã®ãƒ–ランãƒ"
msgid "Current Project"
msgstr "ç¾åœ¨ã®ãƒ—ロジェクト"
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11747,6 +11884,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11774,6 +11914,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11831,6 +11974,9 @@ msgstr "個人"
msgid "DashboardProjects|Trending"
msgstr "トレンド"
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr "%{firstProject} 㨠%{secondProject}"
@@ -12065,6 +12211,9 @@ msgstr "ターゲットサイトãŠã‚ˆã³ã‚¹ã‚­ãƒ£ãƒ³ä»•æ§˜ã§ä¸€èˆ¬çš„ã«ä½¿ç”¨
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12282,6 +12431,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12369,6 +12521,9 @@ msgstr "æ°´"
msgid "Days"
msgstr "æ—¥"
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr "マージã¾ã§ã®æ—¥æ•°"
@@ -12402,6 +12557,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12513,6 +12671,9 @@ msgstr "削除"
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12534,9 +12695,6 @@ msgstr "ãƒãƒªãƒ¥ãƒ¼ã‚¹ãƒˆãƒªãƒ¼ãƒ ã‚’削除"
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr "アーãƒãƒ•ã‚¡ã‚¯ãƒˆã‚’削除"
-
msgid "Delete asset"
msgstr ""
@@ -12603,7 +12761,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13074,6 +13232,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr "有効期é™"
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr "グループデプロイトークンã¯ã€ã‚°ãƒ«ãƒ¼ãƒ—内ã®ãƒ‘ッケージã€ãƒªãƒã‚¸ãƒˆãƒªã¨ãƒ¬ã‚¸ã‚¹ãƒˆãƒªã‚¤ãƒ¡ãƒ¼ã‚¸ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’å¯èƒ½ã«ã—ã¾ã™ã€‚"
@@ -13161,6 +13322,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13499,6 +13675,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13735,6 +13914,12 @@ msgstr[0] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13750,10 +13935,16 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "差分行をå–得中ã«ä½•ã‹å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
@@ -14358,6 +14549,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr "編集中"
@@ -14688,23 +14885,41 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
-msgstr "%{stepStart} ステップ1 %{stepEnd}: KubernetesãŒè¨­å®šã•ã‚Œã¦ãŠã‚Šã€ %{linkStart}クラスター%{linkEnd} ã®ãƒ™ãƒ¼ã‚¹ãƒ‰ãƒ¡ã‚¤ãƒ³ãŒã‚ã‚‹ã“ã¨ã‚’確èªã—ã¾ã™ã€‚"
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
-msgstr "%{stepStart}ステップ2%{stepEnd}: 次ã®ã‚¹ãƒ‹ãƒšãƒƒãƒˆã‚’コピーã—ã¾ã™:"
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
-msgstr "%{stepStart}ステップ3%{stepEnd}: ãれをプロジェクト㮠%{linkStart}gitlab-ci.yml%{linkEnd} ファイルã«è¿½åŠ ã—ã¾ã™ã€‚"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|Close"
-msgstr "é–‰ã˜ã‚‹"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr ""
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr ""
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
-msgstr "スニペットをコピー"
+msgid "EnableReviewApp|View more example projects"
+msgstr ""
msgid "Enabled"
msgstr "有効"
@@ -14931,6 +15146,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr "コミット"
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr "削除"
@@ -15111,12 +15329,12 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgstr ""
+
msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr "本当㫠%{bStart}%{parentEpicTitle}%{bEnd} ã‹ã‚‰ %{bStart}%{targetIssueTitle}%{bEnd} を削除ã—ã¾ã™ã‹ï¼Ÿ"
-msgid "Epics|Assign Epic"
-msgstr ""
-
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr "空ã®ã¾ã¾ã«ã—ãŸå ´åˆã€ãƒžã‚¤ãƒ«ã‚¹ãƒˆãƒ¼ãƒ³ã®æ—¥ä»˜ã‚’継承ã—ã¾ã™"
@@ -15129,18 +15347,9 @@ msgstr "エピックを削除"
msgid "Epics|Remove issue"
msgstr "イシューã®å‰Šé™¤"
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr "詳細を見る"
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr "イシューをエピックã«å‰²ã‚Šå½“ã¦ä¸­ã«ä½•ã‹å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-
msgid "Epics|Something went wrong while creating child epics."
msgstr "å­ã‚¨ãƒ”ック作æˆä¸­ã«ä½•ã‹å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
@@ -15153,18 +15362,12 @@ msgstr "å­ã‚¨ãƒ”ックå–得中ã«ä½•ã‹å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr "グループエピックã®å–得中ã«ä½•ã‹å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr "アイテムを並ã¹ã¦ã„ã‚‹é–“ã«ä½•ã‹å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr "エピックã‹ã‚‰ã‚¤ã‚·ãƒ¥ãƒ¼ã‚’削除ã—ã¦ã‚‹é–“ã«ä½•ã‹å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15294,9 +15497,6 @@ msgstr "担当者ã®ä¿å­˜ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15360,9 +15560,6 @@ msgstr "ファイルアップロードエラー"
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr "ファイルã®ã‚¢ãƒƒãƒ—ロードã«å¤±æ•—ã—ã¾ã—ãŸ: %{stripped} "
-
msgid "Error while loading the merge request. Please try again."
msgstr "マージリクエストã®èª­ã¿è¾¼ã¿ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
@@ -15603,6 +15800,57 @@ msgstr "イベント"
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr "ã™ã¹ã¦ã® %{action} ãŒå¤±æ•—ã—ã¾ã—ãŸï¼š %{job_error_message}。もã†ä¸€åº¦ã‚„ã‚Šç›´ã—ã¦ãã ã•ã„。"
@@ -15721,6 +15969,9 @@ msgstr "マージコミットを除外ã—ã¦ã„ã¾ã™ã€‚ 6,000件ã®ã‚³ãƒŸãƒƒãƒˆ
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15778,9 +16029,15 @@ msgstr "サイドãƒãƒ¼ã‚’é–‹ã"
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr "有効期é™"
@@ -16004,6 +16261,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr "Zoom ミーティングã®è¿½åŠ ã«å¤±æ•—ã—ã¾ã—ãŸ"
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr "コマンドã®é©ç”¨ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
@@ -16050,9 +16310,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr "Jira インãƒãƒ¼ãƒˆã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆãƒ©ãƒ™ãƒ«ãŒä½œæˆã§ãã¾ã›ã‚“ã§ã—ãŸã€‚"
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16248,9 +16505,6 @@ msgstr "イシューã®ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹ã®æ›´æ–°ã«å¤±æ•—ã—ã¾ã—ãŸ"
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr "æ›´æ–°ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
-
msgid "Failed to upgrade."
msgstr "アップグレードã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
@@ -16507,6 +16761,9 @@ msgstr "2月"
msgid "February"
msgstr "2月"
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16612,9 +16869,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr "マイルストーンåã§çµžã‚Šè¾¼ã‚€"
@@ -16822,6 +17076,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr "詳ã—ã„情報ã¯ã€ãƒ•ã‚¡ã‚¤ãƒ«ãƒ•ãƒƒã‚¯ã®æ–‡æ›¸ã‚’ã”覧ãã ã•ã„"
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr "パスワードを忘れã¾ã—ãŸã‹ï¼Ÿ"
@@ -17651,9 +17908,6 @@ msgstr "セカンダリー"
msgid "Get a free instance review"
msgstr "ç„¡æ–™ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãƒ¬ãƒ“ューã®å–å¾—"
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17780,6 +18034,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -17831,6 +18091,9 @@ 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 ""
@@ -17879,9 +18142,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18437,9 +18697,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr "Gravatar"
@@ -18449,6 +18706,9 @@ msgstr "Gravatar を有効化"
msgid "Group"
msgstr "グループ"
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19211,12 +19471,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr "グループã®èª­ã¿è¾¼ã¿ä¸­"
-msgid "GroupsTree|No groups matched your search"
-msgstr "検索ã«é©åˆã™ã‚‹ã‚°ãƒ«ãƒ¼ãƒ—ã¯ã‚ã‚Šã¾ã›ã‚“"
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr "検索ã«é©åˆã™ã‚‹ãƒ—ロジェクトã€ã‚°ãƒ«ãƒ¼ãƒ—ãŒã‚ã‚Šã¾ã›ã‚“"
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19286,6 +19540,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr "ガイドライン"
@@ -19462,9 +19719,6 @@ msgstr "正常性情報ã¯æ¬¡ã®ã‚¨ãƒ³ãƒ‰ãƒã‚¤ãƒ³ãƒˆã‹ã‚‰å–å¾—ã§ãã¾ã™ã€‚
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr "アクセストークンã¯"
@@ -19917,7 +20171,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20004,12 +20264,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr "ã“ã‚ŒãŒé–“é•ã„ã ã£ãŸå ´åˆã¯ã€ %{leave_link_start} %{source_type} ã‚’ãã®ã¾ã¾ã« %{link_end} ã§ãã¾ã™ã€‚"
@@ -21757,6 +22011,9 @@ msgstr "無効ãª2è¦ç´ èªè¨¼ã‚³ãƒ¼ãƒ‰ã§ã™ã€‚"
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21775,9 +22032,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr "メール㧠\"%{email}\" を招待"
-msgid "Invite \"%{trimmed}\" by email"
-msgstr "メール㧠\"%{trimmed}\" を招待"
-
msgid "Invite Members"
msgstr ""
@@ -21835,7 +22089,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -21914,19 +22168,16 @@ msgid "InviteMembersModal|The following member couldn't be invited"
msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22064,12 +22315,18 @@ msgstr "ライセンスシートã®ä½¿ç”¨:"
msgid "Is using seat"
msgstr "シート利用中"
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22091,6 +22348,18 @@ msgstr "移動済ã¿"
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr "イシュー"
@@ -22316,6 +22585,21 @@ msgstr "検索を拡大ã™ã‚‹ã«ã¯ã€ä¸Šè¨˜ã®ãƒ•ã‚£ãƒ«ã‚¿ãƒãƒ¼ã§ãƒ•ã‚£ãƒ«ã‚¿
msgid "IssuesAnalytics|Total:"
msgstr "åˆè¨ˆ:"
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr "タイトル"
@@ -22610,6 +22894,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -22940,6 +23227,9 @@ msgstr ""
msgid "Job|Download"
msgstr "ダウンロード"
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -22979,9 +23269,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23356,9 +23652,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23512,6 +23805,15 @@ msgstr "グループã«ã¤ã„ã¦è©³ã—ã知る"
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23662,9 +23964,6 @@ msgstr "プロジェクトを離脱"
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -23905,6 +24204,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24175,9 +24480,6 @@ msgstr ""
msgid "Logs"
msgstr "ログ"
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr "å¼±ã„脆弱性ã®å­˜åœ¨"
@@ -24190,6 +24492,9 @@ msgstr "MD5"
msgid "MERGED"
msgstr "マージ済ã¿"
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24226,8 +24531,14 @@ msgstr "変更ã®ã¿è¡¨ç¤º"
msgid "MRDiff|Show full file"
msgstr "ã™ã¹ã¦ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‚’表示"
-msgid "Made this issue confidential."
-msgstr "ã“ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã‚’éžå…¬é–‹ã«ã—ã¾ã—ãŸã€‚"
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
+msgstr ""
msgid "Mailgun"
msgstr ""
@@ -24241,9 +24552,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24253,9 +24570,6 @@ msgstr "Web IDEを使用ã—ã¦ãƒ–ラウザ内ã§å¤‰æ›´ã—レビューã™ã‚‹"
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr "ãƒãƒ¼ãƒ å…¨å“¡ãŒå ´æ‰€ã«é–¢ä¿‚ãªãより生産的ã«æ´»å‹•ã§ãã¾ã™ã€‚GitLab Geo ã¯ã€å¤§ããªã‚µã‚¤ã‚ºã®ãƒªãƒã‚¸ãƒˆãƒªã®å–得やクローンã«ã‹ã‹ã‚‹æ™‚間を削減ã™ã‚‹ãŸã‚ã«ã€èª­ã¿è¾¼ã¿å°‚用ã®ãƒŸãƒ©ãƒ¼ã‚’ GitLab インスタンス上ã«ä½œæˆã—ã¾ã™ã€‚"
-msgid "Make issue confidential"
-msgstr "イシューをéžå…¬é–‹ã«ã™ã‚‹"
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24265,8 +24579,8 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr "ã“ã‚Œã¯å¿…ãšä¿å­˜ã—ã¦ãã ã•ã„。二度ã¨ã‚¢ã‚¯ã‚»ã‚¹ã§ãã¾ã›ã‚“。"
-msgid "Makes this issue confidential."
-msgstr "イシューをéžå…¬é–‹ã«ã™ã‚‹ã€‚"
+msgid "Makes this %{type} confidential."
+msgstr ""
msgid "Manage %{workspace} labels"
msgstr ""
@@ -24322,6 +24636,9 @@ msgstr ""
msgid "Manifest"
msgstr "マニフェスト"
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr "マニフェストファイルã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆ"
@@ -24346,6 +24663,9 @@ msgstr "3月"
msgid "March"
msgstr "3月"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr "完了ã«ã™ã‚‹"
@@ -24397,6 +24717,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24409,6 +24732,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25035,6 +25361,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr "マージリクエストã¨ã¯ã€ãƒ—ロジェクトã«åŠ ãˆãŸå¤‰æ›´ã‚’æ示ã—ã€ãã®å¤‰æ›´ã«ã¤ã„ã¦ä»–ã®ãƒ¡ãƒ³ãƒãƒ¼ã¨è©±ã—åˆã†ãŸã‚ã®å ´æ‰€ã§ã™"
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25260,6 +25589,9 @@ msgstr "メソッド"
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr "メトリクスã¯æ­£å¸¸ã«è¿½åŠ ã•ã‚Œã¾ã—ãŸã€‚"
@@ -25649,6 +25981,9 @@ msgstr "マイルストーンã®æœŸæ—¥"
msgid "Milestone lists not available with your current license"
msgstr "ç¾åœ¨ã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ã§ã¯ マイルストーンリストを利用ã§ãã¾ã›ã‚“"
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr "マイルストーンã®æ¤œç´¢ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
@@ -25808,6 +26143,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr "より多ãã®ãƒŸãƒ©ãƒ¼ã‚’優先的ã«ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã™ã‚‹å‰ã«ä½¿ç”¨å¯èƒ½ã«ãªã‚‹ãŸã‚ã®æœ€å°å®¹é‡ã€‚"
@@ -25880,6 +26218,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26066,6 +26407,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26524,6 +26868,9 @@ msgstr "スコープãªã—"
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr "アクティブãªç®¡ç†ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“"
@@ -26653,9 +27000,6 @@ msgstr "表示ã™ã‚‹ã‚¤ãƒ†ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ãŒã‚ã‚Šã¾ã›ã‚“"
msgid "No job log"
msgstr "ジョブログãŒã‚ã‚Šã¾ã›ã‚“"
-msgid "No jobs to show"
-msgstr "表示ã™ã‚‹ã‚¸ãƒ§ãƒ–ãŒã‚ã‚Šã¾ã›ã‚“"
-
msgid "No label"
msgstr ""
@@ -26683,9 +27027,6 @@ msgstr "一致ã™ã‚‹çµæžœãŒã‚ã‚Šã¾ã›ã‚“"
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26701,9 +27042,6 @@ msgstr "メッセージã¯è¨˜éŒ²ã•ã‚Œã¦ã„ã¾ã›ã‚“"
msgid "No milestone"
msgstr "マイルストーンãªã—"
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr "ãã®ä»–ã«ã€ãã®åå‰ã¾ãŸã¯èª¬æ˜Žã®ãƒ©ãƒ™ãƒ«ãŒã‚ã‚Šã¾ã›ã‚“"
@@ -26936,7 +27274,7 @@ msgstr "返信を折りãŸãŸã‚€"
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27267,6 +27605,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27276,6 +27617,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27297,6 +27641,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27390,9 +27737,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr "æ“作ã—ãŸãƒ•ã‚¡ã‚¤ãƒ«æ•°"
@@ -27417,9 +27761,6 @@ msgstr "10月"
msgid "October"
msgstr "10月"
-msgid "OfSearchInADropdown|Filter"
-msgstr "フィルター"
-
msgid "Off"
msgstr ""
@@ -27652,12 +27993,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27703,12 +28038,6 @@ msgstr "例:ログインページã§SQLインジェクションã®ãƒ†ã‚¹ãƒˆã‚’
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27730,12 +28059,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr "オンデマンドスキャン"
@@ -27778,15 +28101,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -27817,12 +28131,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -27841,9 +28149,6 @@ msgstr "インãƒãƒ¼ãƒˆã™ã‚‹ã¨ã€ãƒªãƒã‚¸ãƒˆãƒªã¯SSHã«ã‚ˆã‚ŠãƒŸãƒ©ãƒ¼ãƒªãƒ³
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] "ãã®ä»–ã®ã‚¢ã‚¤ãƒ†ãƒ ã®ä»¶æ•° %d"
@@ -28016,9 +28321,6 @@ msgstr "æ“作ã«å¤±æ•—ã—ã¾ã—ãŸã€‚ pod log ã® %{pod_name} ã§è©³ç´°ã‚’確èª
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr "æ“作ãŒã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã—ã¾ã—ãŸã€‚ pod log ã® %{pod_name} ã§è©³ç´°ã‚’確èªã—ã¦ãã ã•ã„。"
-
msgid "Operations"
msgstr ""
@@ -28386,12 +28688,21 @@ msgstr "パッケージã®å‰Šé™¤"
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28437,6 +28748,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28582,6 +28899,9 @@ msgstr "申ã—訳ã‚ã‚Šã¾ã›ã‚“。ã‚ãªãŸã®ãƒ•ã‚£ãƒ«ã‚¿ãƒ¼ã§ã¯è©²å½“ã™ã‚‹
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -28964,12 +29284,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29018,8 +29332,8 @@ msgstr "Phabricator サーãƒãƒ¼ã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆ"
msgid "Phabricator Server URL"
msgstr "Phabricator サーãƒãƒ¼URL"
-msgid "Phabricator Tasks"
-msgstr "Phabricatorタスク"
+msgid "Phabricator tasks"
+msgstr ""
msgid "Phone"
msgstr ""
@@ -29237,6 +29551,9 @@ msgstr "アクティブ"
msgid "PipelineSchedules|All"
msgstr "全件"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29252,6 +29569,9 @@ msgstr "無効"
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr "次ã®å®Ÿè¡Œ"
@@ -29264,12 +29584,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "ã“ã®ãƒ‘イプラインã«ã¤ã„ã¦ç°¡å˜ã«è¨˜è¿°ã—ã¦ãã ã•ã„。"
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr "権é™ã‚’å–å¾—ã™ã‚‹"
@@ -29279,9 +29605,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr "ターゲット"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr "変数"
@@ -30041,9 +30373,6 @@ msgstr ""
msgid "Please select a country"
msgstr "国をé¸æŠžã—ã¦ãã ã•ã„"
-msgid "Please select a file"
-msgstr "ファイルをé¸æŠžã—ã¦ãã ã•ã„"
-
msgid "Please select a group"
msgstr ""
@@ -30152,6 +30481,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr "基本設定"
@@ -30293,6 +30685,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr "環境ãŒè‡ªå‹•åœæ­¢ã—ãªã„よã†ã«ã™ã‚‹"
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr "ç¾åœ¨ã®ã‚°ãƒ«ãƒ¼ãƒ—外ã¸ãƒ—ロジェクトã®ãƒ•ã‚©ãƒ¼ã‚¯ã‚’防止"
@@ -30386,12 +30781,18 @@ msgstr ""
msgid "Proceed"
msgstr "続行"
-msgid "Product Analytics"
-msgstr "プロダクト分æž"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
+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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -30968,6 +31369,9 @@ msgstr "プロジェクトå"
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr "ローカルストレージãŒåˆ©ç”¨ã§ããªã„ãŸã‚ã€ãƒ—ロジェクトã®é †åºã¯ä¿å­˜ã•ã‚Œã¾ã›ã‚“。"
@@ -30980,6 +31384,9 @@ msgstr "プロジェクトã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£çŠ¶æ…‹"
msgid "Project security status help page"
msgstr "プロジェクトã®ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£çŠ¶æ…‹ã®ãƒ˜ãƒ«ãƒ—ページ"
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr "プロジェクトslug"
@@ -31262,12 +31669,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31280,12 +31693,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr "ãƒãƒƒã‚¸"
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31307,6 +31726,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31406,6 +31828,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr "内部"
@@ -31544,6 +31969,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31574,6 +32002,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31625,6 +32056,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32264,6 +32698,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32300,15 +32737,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr "コードオーナーã®æ‰¿èª"
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr "詳細ã«ã¤ã„ã¦"
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr "ä¿è­·"
@@ -32324,12 +32773,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr "コード所有者ã®æ‰¿èªãŒå¿…è¦ï¼š"
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr "ç¾åœ¨ä¿è­·ãƒ–ランãƒãŒã‚ã‚Šã¾ã›ã‚“。上ã®ãƒ•ã‚©ãƒ¼ãƒ ã§ãƒ–ランãƒã‚’ä¿è­·ã—ã¦ãã ã•ã„。"
@@ -32639,6 +33097,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32771,12 +33232,6 @@ msgstr "続ãを読む"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr "関連ã™ã‚‹ã‚¤ã‚·ãƒ¥ãƒ¼ã«ã¤ã„ã¦ã‚‚ã£ã¨èª­ã‚€"
-
msgid "Read their documentation."
msgstr ""
@@ -32870,9 +33325,6 @@ msgstr "プロジェクトã®å…¬é–‹ç¯„囲を狭ã‚ã‚‹"
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr "ã“ã®ãƒ—ロジェクトã®å…¬é–‹ç¯„囲を狭ã‚ã¾ã™ã‹?"
-
msgid "Reference"
msgstr ""
@@ -33034,6 +33486,9 @@ msgstr[0] "リリース"
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr "アセットをリリース"
@@ -33043,6 +33498,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr "リリースã«ã¯ãƒžã‚¤ãƒ«ã‚¹ãƒˆãƒ¼ãƒ³ã¨åŒã˜ãƒ—ロジェクトãŒã‚ã‚Šã¾ã›ã‚“"
@@ -33499,6 +33957,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr "レãƒãƒ¼ãƒˆ"
@@ -33512,10 +33973,6 @@ msgid "Reports|%{recentlyFailed} out of %{failed} failed tests has failed more t
msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days"
msgstr[0] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33544,18 +34001,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr "クラスå"
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr "実行時間"
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33564,12 +34015,6 @@ msgid "Reports|Failed %{count} time in %{base_branch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 days"
msgstr[0] ""
-msgid "Reports|Failure"
-msgstr "失敗"
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33612,21 +34057,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr "é‡è¦åº¦"
-msgid "Reports|System output"
-msgstr "システム出力"
-
msgid "Reports|Test summary"
msgstr "テストã®è¦ç´„"
-msgid "Reports|Test summary failed loading results"
-msgstr "テストè¦ç´„ã®çµæžœã®ãƒ­ãƒ¼ãƒ‰ã«å¤±æ•—"
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr "テストè¦ç´„ã®çµæžœã¯ãƒ‘ースã•ã‚Œã¦ã„ã¾ã™"
-
msgid "Reports|Test summary results are loading"
msgstr "テストサマリーã®çµæžœã‚’読ã¿è¾¼ã‚“ã§ã„ã¾ã™ã€‚"
@@ -33642,9 +34078,6 @@ msgstr "脆弱性å"
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr "テストçµæžœã«å¤‰æ›´ã‚ã‚Šã¾ã›ã‚“。"
-
msgid "Repositories"
msgstr ""
@@ -34012,6 +34445,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr "%{name} ã«ã‚ˆã£ã¦è§£æ±º"
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr "レスãƒãƒ³ã‚¹"
@@ -34239,6 +34675,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr "ãƒã‚¦ã‚¹ã‚­ãƒ¼ãƒ”ングを実行"
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34276,6 +34715,9 @@ msgid "Runners|%d selected runner deleted"
msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34302,7 +34744,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34510,6 +34952,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34637,9 +35082,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34688,6 +35139,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34722,6 +35176,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34761,12 +35218,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -34821,16 +35272,22 @@ msgstr "SAML ディスカãƒãƒªãƒ¼ãƒˆãƒ¼ã‚¯ãƒ³"
msgid "SAML for %{group_name}"
msgstr "%{group_name} 用ã®SAML"
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -34938,10 +35395,10 @@ msgstr "ä¿å­˜ä¸­"
msgid "Saving project."
msgstr "プロジェクトをä¿å­˜"
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -34962,9 +35419,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -34974,9 +35437,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35127,9 +35596,6 @@ msgstr "LDAP グループを検索"
msgid "Search for a group"
msgstr "グループを検索"
-msgid "Search for a user"
-msgstr "ユーザーを検索"
-
msgid "Search for an emoji"
msgstr ""
@@ -35525,10 +35991,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35648,6 +36117,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35750,10 +36222,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -35843,7 +36315,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -35861,6 +36333,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -35879,12 +36354,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -35906,6 +36390,9 @@ msgstr "プロジェクトを追加"
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36035,6 +36522,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36092,6 +36582,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36209,9 +36702,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36224,6 +36723,9 @@ msgstr "メトリクスをå‚ç…§"
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr "GitLab管ç†ç”»é¢ã§å½±éŸ¿ã‚’å—ã‘るプロジェクトをå‚ç…§"
@@ -36287,9 +36789,6 @@ msgstr "テンプレートリãƒã‚¸ãƒˆãƒªã‚’é¸æŠž"
msgid "Select a template type"
msgstr "テンプレートタイプをé¸æŠž"
-msgid "Select a timezone"
-msgstr "タイムゾーンをé¸æŠž"
-
msgid "Select all"
msgstr "ã™ã¹ã¦é¸æŠž"
@@ -36428,11 +36927,11 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
-msgstr "自己監視プロジェクトã¯ã‚ã‚Šã¾ã›ã‚“"
+msgid "Self-monitoring project does not exist"
+msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
msgstr "自己監視プロジェクトã¯å­˜åœ¨ã—ã¾ã›ã‚“。ログを調ã¹ã‚¨ãƒ©ãƒ¼ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’確èªã—ã¦ãã ã•ã„"
@@ -36443,28 +36942,28 @@ msgstr "自己監視プロジェクトãŒæ­£å¸¸ã«å‰Šé™¤ã•ã‚Œã¾ã—ãŸ"
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr "自己監視プロジェクトã¯å‰Šé™¤ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸã€‚ログを調ã¹ã‚¨ãƒ©ãƒ¼ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’確èªã—ã¦ãã ã•ã„"
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
-msgstr "自己監視"
+msgid "SelfMonitoring|Self-monitoring"
+msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36683,9 +37182,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -36834,9 +37330,6 @@ msgstr "設定"
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37090,10 +37583,7 @@ msgstr ""
msgid "Showing all issues"
msgstr "ã™ã¹ã¦ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã‚’表示"
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37147,8 +37637,8 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
-msgstr "\"%{group_name}\" ã«ã‚µã‚¤ãƒ³ã‚¤ãƒ³ã—ã¾ã™"
+msgid "Sign in to %{group_name}"
+msgstr ""
msgid "Sign in to GitLab"
msgstr ""
@@ -37162,8 +37652,8 @@ msgstr "2FAコードã§ã‚µã‚¤ãƒ³ã‚¤ãƒ³"
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
-msgstr "シングルサインオンã§ã‚µã‚¤ãƒ³ã‚¤ãƒ³ã™ã‚‹"
+msgid "Sign in with single sign-on"
+msgstr ""
msgid "Sign in with smart card"
msgstr "スマートカードã§ã‚µã‚¤ãƒ³ã‚¤ãƒ³"
@@ -37285,9 +37775,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr "リãƒã‚¸ãƒˆãƒªæ¯Žã®ã‚µã‚¤ã‚ºåˆ¶é™ (MB)"
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr "スキップã—ã¾ã—ãŸ"
@@ -37510,6 +37997,9 @@ msgstr "ã‚ãªãŸã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã®ç·¨é›†ã¨åŒæ™‚ã«èª°ã‹ãŒç·¨é›†
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37621,9 +38111,6 @@ msgstr "ã“ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã®ç’°å¢ƒã‚’å–得中ã«å•é¡ŒãŒç™ºç”Ÿã—
msgid "Something went wrong while fetching the packages list."
msgstr "パッケージリストをå–å¾—ã™ã‚‹éš›ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr "OpenAPI ビューアã®åˆæœŸåŒ–中ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸ"
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr "Let's Encrypt ã®è¨¼æ˜Žæ›¸ã‚’å–å¾—ã™ã‚‹éš›ã«å•é¡ŒãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚"
@@ -38197,9 +38684,6 @@ msgstr "ステータス:"
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38212,9 +38696,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38236,9 +38717,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -38758,9 +39236,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39017,6 +39501,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "ブランãƒãƒ»ã‚¿ã‚°åˆ‡ã‚Šæ›¿ãˆ"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr "GitLab Nextã«åˆ‡ã‚Šæ›¿ãˆã‚‹"
@@ -39107,6 +39594,9 @@ msgstr ""
msgid "Tag"
msgstr "ã‚¿ã‚°"
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr "タグ一覧:"
@@ -39191,6 +39681,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39212,15 +39705,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr "オプションã¨ã—ã¦ã€ã‚¿ã‚°ã«ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’追加ã—ã¾ã™ã€‚空白ã®ã¾ã¾ã«ã™ã‚‹ã¨ã€%{link_start}軽é‡ã‚¿ã‚°%{link_end}ãŒä½œæˆã•ã‚Œã¾ã™ã€‚"
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr "リリースノート"
-
msgid "TagsPage|Repository has no tags yet."
msgstr "リãƒã‚¸ãƒˆãƒªã«ã¯ã¾ã ã‚¿ã‚°ãŒã‚ã‚Šã¾ã›ã‚“。"
@@ -39242,9 +39729,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr "æ–°ã—ã„タグを追加ã™ã‚‹ã«ã¯ git tag コマンドを使用ã—ã¾ã™:"
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "リリースノートを書ãã‹ã€ã“ã“ã«ãƒ•ã‚¡ã‚¤ãƒ«ã‚’ドラッグ…"
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39263,6 +39747,9 @@ msgstr "ä¿è­·"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr "ターゲットブランãƒ"
@@ -39374,14 +39861,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39399,12 +39878,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39492,12 +39965,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -39947,6 +40414,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "インãƒãƒ¼ãƒˆã¯ %{timeout} ã§ã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã—ã¾ã™ã€‚タイムアウトã™ã‚‹ãƒªãƒã‚¸ãƒˆãƒªã§ã¯ã€clone/push を組ã¿åˆã‚ã›ã¦ä½¿ç”¨ã—ã¦ãã ã•ã„。"
@@ -40142,9 +40612,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40175,7 +40642,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr "指定ã—ãŸã‚¿ãƒ–ã¯ç„¡åŠ¹ã§ã™ã€‚別ã®ã‚¿ãƒ–ã‚’é¸æŠžã—ã¦ãã ã•ã„"
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40232,9 +40699,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40586,9 +41050,6 @@ msgstr "既存ã®ã‚¤ã‚·ãƒ¥ãƒ¼ã«åŒæ§˜ã®ã‚¿ã‚¤ãƒˆãƒ«ãŒã‚ã‚Šã¾ã™ã€‚別ã®ä¼¼
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40622,6 +41083,9 @@ msgstr "%{reason} ã®ãŸã‚ã€ã“ã® %{viewer} ã¯è¡¨ç¤ºã§ãã¾ã›ã‚“ã§ã—ãŸ
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -40790,9 +41254,6 @@ msgstr "ã“ã®ã‚¨ãƒ”ックã«ã¯ã€æ—¢ã«æœ€å¤§æ•°ã®å­ã‚¨ãƒ”ックãŒã‚ã‚Šã¾
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -40853,6 +41314,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41069,15 +41533,18 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr "ã“ã®åå‰ç©ºé–“ã¯æ—¢ã«ä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã™ã€‚別ã®åå‰ã«ã—ã¦ãã ã•ã„。"
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
+msgstr ""
+
msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr "複数ã®ãƒ—ロジェクト間ã§èª­ã¿è¾¼ã¿ãŒè¨±å¯ã•ã‚Œã¦ã„ãªã„ãŸã‚ã€ã“ã®ãƒšãƒ¼ã‚¸ã¯åˆ©ç”¨ã§ãã¾ã›ã‚“。"
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
-msgstr ""
-
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
msgstr ""
@@ -41204,9 +41671,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr "ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ã¯ ID ãŒã‚ã‚Šã¾ã›ã‚“"
@@ -41225,6 +41689,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr "ã“ã®å¤‰æ•°ã¯ãƒžã‚¹ã‚¯ã§ãã¾ã›ã‚“."
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41593,9 +42060,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41701,6 +42165,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -41767,9 +42234,33 @@ msgstr "今日"
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -41791,18 +42282,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -41815,6 +42327,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -41965,9 +42495,6 @@ msgstr "ç·è²¢çŒ®åº¦"
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr "アーティファクトã®ã‚µã‚¤ã‚º(åˆè¨ˆ): %{total_size}"
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42287,6 +42814,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -42791,6 +43324,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr "%{help_link_start}共有 Runner%{help_link_end} ã¯ç„¡åŠ¹ã«ãªã£ã¦ã„ã‚‹ãŸã‚ã€ãƒ‘イプラインã®ä½¿ç”¨ã«åˆ¶é™ã¯ã‚ã‚Šã¾ã›ã‚“"
@@ -42893,6 +43432,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr "パッケージ"
@@ -42923,6 +43465,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr "リãƒã‚¸ãƒˆãƒª"
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -43970,9 +44515,6 @@ msgstr ""
msgid "View full dashboard"
msgstr "ダッシュボードã®ãƒ•ãƒ«è¡¨ç¤º"
-msgid "View full log"
-msgstr " ログã®å…¨ä½“表示"
-
msgid "View group in admin area"
msgstr "管ç†ã‚¨ãƒªã‚¢ã§ã‚°ãƒ«ãƒ¼ãƒ—を表示"
@@ -44433,6 +44975,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr "スキャナープロãƒã‚¤ãƒ€ãƒ¼"
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44451,6 +44996,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr "状態"
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44586,7 +45134,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "本人確èªã®ãŸã‚ã€ã‚ãªãŸãŒãƒ­ãƒœãƒƒãƒˆã§ãªã„ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。"
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44628,6 +45176,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44643,12 +45194,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44688,6 +45251,9 @@ msgstr "Webhooks"
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -44802,6 +45368,12 @@ msgstr "プッシュイベント"
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -44829,9 +45401,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr "トリガー"
@@ -44844,7 +45413,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -44856,12 +45425,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr "ウェブサイト"
@@ -44940,6 +45518,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -44949,7 +45530,7 @@ msgstr ""
msgid "What's new"
msgstr "What's new"
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45263,6 +45844,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45312,9 +45899,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45345,10 +45947,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45360,6 +45965,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45381,6 +45989,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45399,6 +46010,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45493,6 +46107,9 @@ msgstr "ã‚ãªãŸã¯ã€ä»¥å‰ã«æ›´æ–°ã—ãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚’削除ã—よã†ã¨ã—
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr "編集ã—ãŸãƒ•ã‚¡ã‚¤ãƒ«ã‚’æ›´æ–°ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚"
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45529,6 +46146,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45574,9 +46197,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45677,6 +46297,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr "グラフã®åˆ—をクリックã—ã¦ã€ãƒžãƒ¼ã‚¸æ—¥ã§ãƒ•ã‚£ãƒ«ã‚¿ãƒªãƒ³ã‚°ã§ãã¾ã™ã€‚"
@@ -45749,7 +46372,7 @@ msgstr "%{linkStart} CI Lint %{linkEnd} ã§.gitlab-ci.ymlをテストã™ã‚‹ã“ã
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -45773,6 +46396,9 @@ msgstr "ブロックã•ã‚ŒãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ãªã‚Šã™ã¾ã™ã“ã¨ã¯ã§ãã¾ã›
msgid "You cannot impersonate a user who cannot log in"
msgstr "ログインã§ããªã„ユーザーを代用ã§ãã¾ã›ã‚“"
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr "内部ユーザーを代用ã§ãã¾ã›ã‚“"
@@ -45915,6 +46541,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -45978,7 +46607,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46146,9 +46775,6 @@ msgstr "YouTube"
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46260,6 +46886,9 @@ msgstr "ã‚ãªãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãŒãƒ­ãƒƒã‚¯ã•ã‚Œã¾ã—ãŸã€‚"
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr "ã‚ãªãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¯ \"%{group_name}\"グループã«å°‚用ã®èªè¨¼æƒ…報を使用ã—ã¦ãŠã‚Šã€SSOを通ã˜ã¦ã®ã¿æ›´æ–°ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚"
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46376,16 +47005,13 @@ msgstr "メッセージを入力ã—ã¦ãã ã•ã„。"
msgid "Your name"
msgstr "åå‰"
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46473,6 +47099,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46542,9 +47171,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr "削除ã•ã‚ŒãŸãƒ¦ãƒ¼ã‚¶ãƒ¼"
@@ -46555,9 +47181,6 @@ msgstr[0] "約 %d 時間"
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46616,6 +47239,12 @@ msgstr ""
msgid "assign yourself"
msgstr "自分ã«å‰²ã‚Šå½“ã¦"
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46625,9 +47254,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr "リスクã‚ã‚Š"
-
msgid "attach a new file"
msgstr "æ–°ã—ã„ファイルを添付"
@@ -46707,6 +47333,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -46936,12 +47568,27 @@ msgstr "ä¾å­˜é–¢ä¿‚スキャンã¯ã€ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ã®ä¾å­˜é–¢ä¿‚ã®ä¸­ã®
msgid "ciReport|Dependency scanning"
msgstr "ä¾å­˜é–¢ä¿‚スキャン"
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr "解決ã™ã‚‹ãŸã‚ã®ãƒ‘ッãƒã®ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰"
msgid "ciReport|Download the patch to apply it manually"
msgstr "パッãƒã‚’ダウンロードã—ã¦æ‰‹å‹•ã§é©ç”¨ã™ã‚‹"
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr "動的アプリケーションセキュリティテスト (DAST) ã¯ã€ã‚¦ã‚§ãƒ–アプリケーションã®æ—¢çŸ¥ã®è„†å¼±æ€§ã‚’検出ã—ã¾ã™ã€‚"
@@ -47015,6 +47662,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47045,6 +47695,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr "セキュリティスキャン"
@@ -47060,6 +47713,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr "ソリューション"
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr "é™çš„アプリケーションセキュリティテスト(SAST)ã¯ã€ã‚½ãƒ¼ã‚¹ã‚³ãƒ¼ãƒ‰ä¸­ã®æ—¢çŸ¥ã®è„†å¼±æ€§ã‚’検出ã—ã¾ã™ã€‚"
@@ -47133,6 +47789,9 @@ msgstr "コミット %{commit_id}"
msgid "committed"
msgstr "コミット済ã¿"
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47191,6 +47850,9 @@ msgstr[0] "æ—¥"
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr "デフォルトブランãƒ"
@@ -47344,6 +48006,9 @@ msgid "from %d job"
msgid_plural "from %d jobs"
msgstr[0] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47442,12 +48107,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr "無効ãªãƒžã‚¤ãƒ«ã‚¹ãƒˆãƒ¼ãƒ³çŠ¶æ…‹ `%{state}`"
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr "無効ãªIPアドレスã®ç¯„囲"
@@ -47469,6 +48140,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr "ã¯ãƒ†ãƒ³ãƒ—レートを利用ã§ãるグループã«æ‰€å±žã—ã¦ã„ã¾ã›ã‚“。"
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr "ã¯æœ‰åŠ¹ãª X509 証明書ã§ã¯ã‚ã‚Šã¾ã›ã‚“。"
@@ -47493,12 +48167,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47652,9 +48332,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -47801,6 +48478,9 @@ 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 "マージã¯ãƒ–ロックã•ã‚Œã¾ã—ãŸ: ã™ã¹ã¦ã®ã‚¹ãƒ¬ãƒƒãƒ‰ã‚’解決ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
@@ -47897,9 +48577,6 @@ msgstr "æ–°ã—ã„マージリクエストã§ã“ã®ãƒžãƒ¼ã‚¸ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’リ
msgid "mrWidget|Revoke approval"
msgstr "承èªã‚’å–り消ã™"
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -47963,6 +48640,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr "開始日より後ã«ã—ã¦ãã ã•ã„。"
@@ -47975,9 +48655,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -47996,9 +48682,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr "è¦æ³¨æ„"
-
msgid "needs to be between 10 minutes and 1 month"
msgstr "10分ã‹ã‚‰1ヶ月ã¾ã§ã®é–“ã«ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™"
@@ -48047,9 +48730,6 @@ msgstr "%{item} 〠%{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item} ãれ㫠%{lastItem}"
-msgid "on track"
-msgstr "順調"
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48068,16 +48748,15 @@ msgstr "ã¾ãŸã¯"
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] "テスト全件数 %d ã®ã†ã¡"
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "親"
@@ -48204,9 +48883,6 @@ msgstr ""
msgid "remove weight"
msgstr "ウェイトを削除"
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48226,12 +48902,19 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48386,6 +49069,9 @@ msgstr "ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆ"
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48520,6 +49206,9 @@ msgstr ""
msgid "yaml invalid"
msgstr "yaml ãŒç„¡åŠ¹ã§ã™"
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/ka_GE/gitlab.po b/locale/ka_GE/gitlab.po
index c172dd781a0..cddeca773cc 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: 2022-10-10 14:03\n"
+"PO-Revision-Date: 2022-11-13 09:23\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/kab/gitlab.po b/locale/kab/gitlab.po
index 2e4799fe41c..a10d66a0d72 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: 2022-10-10 14:06\n"
+"PO-Revision-Date: 2022-11-13 09:25\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/ko/gitlab.po b/locale/ko/gitlab.po
index 4d869b92867..0a167e7e0ce 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: 2022-10-10 15:01\n"
+"PO-Revision-Date: 2022-11-13 09:23\n"
msgid " %{start} to %{end}"
msgstr " %{start}부터 %{end}까지"
@@ -129,6 +129,10 @@ msgid "%d additional user"
msgid_plural "%d additional users"
msgstr[0] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] "%d ìŠ¹ì¸ í•„ìš”"
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%dëª…ì˜ ìŠ¹ì¸ìž"
@@ -209,18 +213,10 @@ msgid "%d epic"
msgid_plural "%d epics"
msgstr[0] "%dê°œì˜ ì—픽"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%dê°œì˜ ì˜¤ë¥˜"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d 내보내기"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%dê°œì˜ ì‹¤íŒ¨"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] "실패한 보안 작업 %d 개"
@@ -229,10 +225,6 @@ msgid "%d file"
msgid_plural "%d files"
msgstr[0] "%dê°œì˜ íŒŒì¼"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%dê±´ì˜ í…ŒìŠ¤íŠ¸ 결과를 고쳤습니다."
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] "%d번 í¬í¬ ë¨"
@@ -431,6 +423,9 @@ msgid "%{bold_start}%{count}%{bold_end} opened merge request"
msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
+msgid "%{chartTitle} no data series"
+msgstr "%{chartTitle} ë°ì´í„° 시리즈 ì—†ìŒ"
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -482,6 +477,14 @@ msgstr[0] "%{count}ê°œì˜ ì—°ë½ì²˜"
msgid "%{count} files touched"
msgstr "%{count} 파ì¼ì´ 변경ë˜ì—ˆìŠµë‹ˆë‹¤"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "%{count}ê°œì˜ í•­ëª©"
@@ -489,6 +492,10 @@ msgstr[0] "%{count}ê°œì˜ í•­ëª©"
msgid "%{count} items per page"
msgstr "페ì´ì§€ 당 %{count}ê°œì˜ ì•„ì´í…œ"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+
msgid "%{count} more"
msgstr "%{count} ê°œ ë”보기"
@@ -509,6 +516,10 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] "%{count} ëª…ì˜ ì°¸ì—¬ìž"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} ê±´ê³¼ ê´€ë ¨ëœ %{pluralized_subject}: %{links}"
@@ -548,9 +559,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr "%{due_date} (기한 지남)"
-
msgid "%{duration}ms"
msgstr "%{duration}ms"
@@ -612,7 +620,7 @@ msgid "%{hook_type} was deleted"
msgstr "%{hook_type} ì‚­ì œë¨"
msgid "%{hook_type} was scheduled for deletion"
-msgstr ""
+msgstr "%{hook_type} 삭제 예정"
msgid "%{host} sign-in from new location"
msgstr "새로운 위치ì—ì„œ %{host}ì— ë¡œê·¸ì¸ë˜ì—ˆìŠµë‹ˆë‹¤."
@@ -761,12 +769,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr "%{name} (ë°”ì¨)"
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} í¬í•¨ë¨ %{resultsString}"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} 찾았습니다 %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -869,7 +871,7 @@ msgid "%{reportType} detected no %{totalStart}new%{totalEnd} vulnerabilities."
msgstr ""
msgid "%{retryButtonStart}Try again%{retryButtonEnd} or %{newFileButtonStart}attach a new file%{newFileButtonEnd}."
-msgstr ""
+msgstr "%{retryButtonStart}다시 ì‹œë„%{retryButtonEnd} ë˜ëŠ” %{newFileButtonStart}새 íŒŒì¼ ì²¨ë¶€%{newFileButtonEnd}."
msgid "%{rotation} has been recalculated with the remaining participants. Please review the new setup for %{rotation_link}. It is recommended that you reach out to the current on-call responder to ensure continuity of on-call coverage."
msgstr ""
@@ -945,6 +947,9 @@ msgstr[0] "%{strongStart}%{count}%{strongEnd} 커밋"
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr "%{strong_open}%{group_name}%{strong_close} 프로ì íŠ¸:"
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "%{strong_start}%{branch_count}%{strong_end} 브랜치"
@@ -1032,7 +1037,7 @@ msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr ""
msgid "%{type} must be a %{help_link}"
-msgstr ""
+msgstr "%{type} ì€ %{help_link} ì´ì–´ì•¼ 합니다."
msgid "%{type} only supports %{name} name"
msgstr "%{type} ì€ %{name} ì´ë¦„만 지ì›í•©ë‹ˆë‹¤."
@@ -1079,9 +1084,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr "%{value} ì€(는) 목ë¡ì— í¬í•¨ë˜ì§€ 않습니다"
-msgid "%{value} s"
-msgstr "%{value}ì´ˆ"
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} %{time_spent_value} ì‹œê°„ì´ ì§€ë‚¬ìŠµë‹ˆë‹¤."
@@ -1139,6 +1141,9 @@ msgstr "'%{source}' 는 ìž„í¬íŠ¸ 소스가 아닙니다."
msgid "'%{template_name}' is unknown or invalid"
msgstr "'%{template_name}'ì„ ì•Œ 수 없거나 유효하지 않습니다"
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d 마ê°)"
@@ -1176,6 +1181,9 @@ msgstr "(변경하지 않으려면 비워 둡니다)"
msgid "(max size 15 MB)"
msgstr "(최대 사ì´ì¦ˆ 15MB)"
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr "(ì„ íƒì‚¬í•­)"
@@ -1434,6 +1442,9 @@ msgstr "ì´ íŽ˜ì´ì§€ì— 대한 액세스 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤."
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "주소가 정확하고 페ì´ì§€ê°€ ì´ë™í•˜ì§€ 않았는지 확ì¸í•˜ì‹­ì‹œì˜¤."
+msgid "404|Not found"
+msgstr "ì°¾ì„ ìˆ˜ ì—†ìŒ"
+
msgid "404|Page Not Found"
msgstr "페ì´ì§€ë¥¼ ì°¾ì„ ìˆ˜ 없습니다"
@@ -1497,9 +1508,6 @@ msgstr "기밀 ì´ìŠˆëŠ” ì´ë¯¸ ê¸°ë°€ì´ ì•„ë‹Œ ìžì‹ì´ 있는 부모를 ê°€ì
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr "기밀 ìž‘ì—… í•­ëª©ì€ ì´ë¯¸ ê¸°ë°€ì´ ì•„ë‹Œ ìžì‹ í•­ëª©ì´ ìžˆëŠ” 부모 í•­ëª©ì„ ê°€ì§ˆ 수 없습니다."
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "빈 프로ì íŠ¸ì—서는 기본 브랜치를 ì„ íƒí•  수 없습니다."
-
msgid "A deleted user"
msgstr "ì‚­ì œëœ ì‚¬ìš©ìž"
@@ -1578,9 +1586,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1788,6 +1793,9 @@ msgstr "약관ë™ì˜"
msgid "Acceptable for use in this project"
msgstr "ì´ í”„ë¡œì íŠ¸ì—ì„œ 사용 가능"
+msgid "Access Denied"
+msgstr "ì ‘ê·¼ì´ ê±°ë¶€ë˜ì—ˆìŠµë‹ˆë‹¤"
+
msgid "Access Git repositories or the API."
msgstr "Git 저장소 ë˜ëŠ” APIì— ì•¡ì„¸ìŠ¤í•©ë‹ˆë‹¤."
@@ -1899,15 +1907,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr "ë” ì•Œì•„ë³´ê¸°"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "메시지: %{message}"
-msgid "AccessibilityReport|New"
-msgstr "새로 만들기"
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr "접근성 검사ì—ì„œ ë‹¤ìŒ ìœ í˜•ì˜ ì˜¤ë¥˜ë¥¼ 발견했습니다: %{code}"
@@ -1977,9 +1979,6 @@ msgstr "활성"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr "%{type} 활성화 (%{token_length})"
-
msgid "Active Sessions"
msgstr "í™œì„±í™”ëœ ì„¸ì…˜"
@@ -2352,6 +2351,12 @@ msgstr "%{labels} %{label_text} 추가"
msgid "Adds a Zoom meeting."
msgstr "Zoom íšŒì˜ ì¶”ê°€í•˜ê¸°"
+msgid "Adds a resource link"
+msgstr "리소스 ë§í¬ë¥¼ 추가합니다."
+
+msgid "Adds a resource link for this incident."
+msgstr "ì´ ì‚¬ê±´ì— ëŒ€í•œ 리소스 ë§í¬ë¥¼ 추가합니다."
+
msgid "Adds a timeline event to incident."
msgstr "ì¸ì‹œë˜íŠ¸ì— 타임ë¼ì¸ ì´ë²¤íŠ¸ 추가."
@@ -2535,6 +2540,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2571,15 +2594,27 @@ msgstr "Auto DevOps ë„ë©”ì¸"
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr "Let's Encrypt 설정"
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr "비활성 프로ì íŠ¸ê°€ ìžë™ìœ¼ë¡œ ì‚­ì œë˜ëŠ” ì‹œê°„ì„ ì„¤ì •í•©ë‹ˆë‹¤. %{linkStart}비활성 프로ì íŠ¸ëž€ 무엇입니까?%{linkEnd}"
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr "비활성 프로ì íŠ¸ ì‚­ì œ"
@@ -2628,6 +2663,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr "새 프로ì íŠ¸ì— 공유 러너 활성화"
@@ -2673,6 +2711,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr "ì¸ìŠ¤í„´ìŠ¤ 러너 만료"
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2811,9 +2861,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2838,6 +2897,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr "AdminSettings|IAM ìžê²© ì¦ëª…으로 AWS OpenSearch Service 사용"
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr "ì‚¬ìš©ìž ë° ê·¸ë£¹ì€ ê·¸ë£¹ ë˜ëŠ” 프로ì íŠ¸ì— 추가ë˜ê¸° ì „ì— ì´ˆëŒ€ë¥¼ 수ë½í•´ì•¼ 합니다."
@@ -2890,13 +2958,13 @@ msgid "AdminUsers|(Deactivated)"
msgstr "(비활성화ë¨)"
msgid "AdminUsers|(Internal)"
-msgstr ""
+msgstr "(내부)"
msgid "AdminUsers|(Locked)"
msgstr ""
msgid "AdminUsers|(Pending approval)"
-msgstr ""
+msgstr "(ìŠ¹ì¸ ëŒ€ê¸°)"
msgid "AdminUsers|2FA Disabled"
msgstr "2FA 사용 중지"
@@ -2911,19 +2979,19 @@ msgid "AdminUsers|Access"
msgstr ""
msgid "AdminUsers|Access Git repositories"
-msgstr ""
+msgstr "Git ì €ìž¥ì†Œì— ì ‘ê·¼"
msgid "AdminUsers|Access level"
msgstr "액세스 레벨"
msgid "AdminUsers|Access the API"
-msgstr ""
+msgstr "APIì— ì ‘ê·¼"
msgid "AdminUsers|Activate"
-msgstr ""
+msgstr "활성화"
msgid "AdminUsers|Activate user %{username}?"
-msgstr ""
+msgstr "%{username} 사용ìžë¥¼ 활성화 할까요?"
msgid "AdminUsers|Active"
msgstr "활성"
@@ -2940,6 +3008,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr "관리ìžë“¤"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr "승ì¸"
@@ -2947,7 +3018,7 @@ msgid "AdminUsers|Approve user %{username}?"
msgstr "%{username} 사용ìžë¥¼ 승ì¸í• ê¹Œìš”?"
msgid "AdminUsers|Approved users can:"
-msgstr ""
+msgstr "승ì¸ëœ 사용ìžëŠ” 다ìŒì„ 수행할 수 있어요."
msgid "AdminUsers|Auditor"
msgstr ""
@@ -2971,7 +3042,7 @@ msgid "AdminUsers|Banned"
msgstr ""
msgid "AdminUsers|Be added to groups and projects"
-msgstr ""
+msgstr "그룹과 프로ì íŠ¸ì— 추가ë¨"
msgid "AdminUsers|Block"
msgstr "차단"
@@ -3097,7 +3168,7 @@ msgid "AdminUsers|Owned groups will be left"
msgstr ""
msgid "AdminUsers|Pending approval"
-msgstr ""
+msgstr "승ì¸ëŒ€ê¸°ì¤‘"
msgid "AdminUsers|Personal projects will be left"
msgstr ""
@@ -3132,8 +3203,8 @@ msgstr "리셋 ë§í¬ê°€ ìƒì„±ë˜ì–´ 사용ìžì—게 전송ë©ë‹ˆë‹¤. 사용ìž
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
-msgstr "ì´ë¦„, ì´ë©”ì¼, ì‚¬ìš©ìž ì´ë¦„으로 검색"
+msgid "AdminUsers|Search by name, email, or username"
+msgstr ""
msgid "AdminUsers|Search users"
msgstr "유저 검색"
@@ -3177,8 +3248,8 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "확ì¸ì„ 위해 %{projectName} 를 입력해주세요."
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "확ì¸ì„ 위해 %{username} ì„ ìž…ë ¥í•˜ì„¸ìš”"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr ""
msgid "AdminUsers|Unban user"
msgstr "ì‚¬ìš©ìž ì°¨ë‹¨ í•´ì œ"
@@ -3240,20 +3311,20 @@ msgstr "프로ì íŠ¸ ì—†ì´"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr "%{username}ì„ ì˜êµ¬ì ìœ¼ë¡œ 삭제하려고 합니다. 해당 사용ìžì™€ ì—°ê´€ëœ ì´ìŠˆ, 머지 리퀘스트(MR) ë° ê·¸ë£¹ì´ ì „ì—­ì ìœ¼ë¡œ \"Ghost-user\"으로 변경ë©ë‹ˆë‹¤. ë°ì´í„° ì†ì‹¤ì„ 방지하기 위해 %{strongStart}ì‚¬ìš©ìž ì°¨ë‹¨%{strongEnd} ê¸°ëŠ¥ì„ ëŒ€ì‹  사용해보세요. %{strongStart}ì‚¬ìš©ìž ì‚­ì œ%{strongEnd}ì‹œ ë˜ëŒë¦¬ê±°ë‚˜, 복구할 수 없습니다."
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
msgstr ""
msgid "AdminUsers|You can always deactivate their account again if needed."
-msgstr ""
+msgstr "AdminUsers|필요한 경우 언제든지 ê³„ì •ì„ ë‹¤ì‹œ 비활성화할 수 있습니다."
msgid "AdminUsers|You can always re-activate their account, their data will remain intact."
msgstr ""
msgid "AdminUsers|You can always unblock their account, their data will remain intact."
-msgstr ""
+msgstr "AdminUsers|언제나 계정 ì°¨ë‹¨ì„ í•´ì œí•  수 있으며 ë°ì´í„°ëŠ” 그대로 유지ë©ë‹ˆë‹¤."
msgid "AdminUsers|You can ban their account in the future if necessary."
msgstr ""
@@ -3288,6 +3359,9 @@ msgstr "관리"
msgid "Administrators"
msgstr "관리ìž"
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3331,19 +3405,19 @@ msgid "AdvancedSearch|Elasticsearch version not compatible"
msgstr ""
msgid "AdvancedSearch|Introduced in GitLab 13.1, before using %{reindexing_link_start}zero-downtime reindexing%{link_end} and %{migrations_link_start}Advanced Search migrations%{link_end}, you need to %{recreate_link_start}recreate your index%{link_end}."
-msgstr ""
+msgstr "GitLab 13.1ì— ì¶”ê°€ë˜ì—ˆìŠµë‹ˆë‹¤. %{reindexing_link_start}제로 다운타임 재ì¸ë±ì‹±%{link_end} ë° %{migrations_link_start}Advanced Search 마ì´ê·¸ë ˆì´ì…˜%{link_end}ì„ ì‚¬ìš©í•˜ê¸° ì „ì— %{recreate_link_start}ì¸ë±ìŠ¤ë¥¼ 다시 ìƒì„±í•´ì•¼ 합니다%{link_end}."
msgid "AdvancedSearch|Pause indexing and upgrade Elasticsearch to a supported version."
-msgstr ""
+msgstr "ì¸ë±ì‹±ì„ ì¼ì‹œ 중지하고 Elasticsearch를 지ì›ë˜ëŠ” 버전으로 업그레ì´ë“œí•©ë‹ˆë‹¤."
msgid "AdvancedSearch|Reindex recommended"
-msgstr ""
+msgstr "재색ì¸ì„ 권장함"
msgid "AdvancedSearch|Reindex required"
msgstr ""
msgid "AdvancedSearch|You are using outdated code search mappings. To improve code search quality, we recommend you use %{reindexing_link_start}zero-downtime reindexing%{link_end} or %{recreate_link_start}re-create your index%{link_end}."
-msgstr ""
+msgstr "ì˜¤ëž˜ëœ ì½”ë“œ 검색 ë§¤í•‘ì„ ì‚¬ìš©í•˜ê³  있습니다. 코드 검색 í’ˆì§ˆì„ í–¥ìƒì‹œí‚¤ë ¤ë©´ %{reindexing_link_start}제로 다운타임 재ì¸ë±ì‹±%{link_end} ë˜ëŠ” %{recreate_link_start}재작성 ì¸ë±ìŠ¤%{link_end}ì„ ì‚¬ìš©í•˜ëŠ” ê²ƒì´ ì¢‹ìŠµë‹ˆë‹¤."
msgid "After a successful password update you will be redirected to login screen."
msgstr "비밀번호가 성공ì ìœ¼ë¡œ ë³€ê²½ëœ ë’¤ì— ë¡œê·¸ì¸ í™”ë©´ìœ¼ë¡œ ì´ë™ 합니다."
@@ -3430,7 +3504,7 @@ msgid "AlertManagement|Events"
msgstr "ì´ë²¤íŠ¸"
msgid "AlertManagement|Incident"
-msgstr ""
+msgstr "ì¸ì‹œë˜íŠ¸"
msgid "AlertManagement|Key"
msgstr "키"
@@ -3577,7 +3651,7 @@ msgid "AlertSettings|Enter an example payload from your selected monitoring tool
msgstr ""
msgid "AlertSettings|Enter integration name"
-msgstr ""
+msgstr "AlertSettings|통합 ì´ë¦„ ìž…ë ¥"
msgid "AlertSettings|Free versions of GitLab are limited to one integration per type. To add more, %{linkStart}upgrade your subscription%{linkEnd}."
msgstr ""
@@ -3586,7 +3660,7 @@ msgid "AlertSettings|GitLab has created a URL and authorization key for your int
msgstr ""
msgid "AlertSettings|HTTP Endpoint"
-msgstr ""
+msgstr "AlertSettings|HTTP 엔드í¬ì¸íŠ¸"
msgid "AlertSettings|If you edit the payload, you must re-map the fields again."
msgstr ""
@@ -3625,13 +3699,13 @@ msgid "AlertSettings|Save & create test alert"
msgstr "저장 & 테스트 알람 ìƒì„±"
msgid "AlertSettings|Save integration"
-msgstr ""
+msgstr "통합 저장"
msgid "AlertSettings|Save integration & send"
msgstr ""
msgid "AlertSettings|Select integration type"
-msgstr ""
+msgstr "통합 유형 ì„ íƒ"
msgid "AlertSettings|Send test alert"
msgstr ""
@@ -3676,16 +3750,16 @@ msgid "Alerts"
msgstr "알림"
msgid "AlertsIntegrations|Alerts will be created through this integration"
-msgstr ""
+msgstr "ì´ í†µí•©ì„ í†µí•´ 경고가 ìƒì„±ë©ë‹ˆë‹¤."
msgid "AlertsIntegrations|Alerts will not be created through this integration"
-msgstr ""
+msgstr "ì´ í†µí•©ì„ í†µí•´ 경고가 ìƒì„±ë˜ì§€ 않습니다."
msgid "AlertsIntegrations|If you delete the %{integrationName} integration, alerts are no longer sent from this endpoint. This action cannot be undone."
msgstr ""
msgid "AlertsIntegrations|Integration Name"
-msgstr ""
+msgstr "통합 ì´ë¦„"
msgid "AlertsIntegrations|Integration payload is invalid."
msgstr ""
@@ -3798,8 +3872,8 @@ msgstr "모든 사용ìžëŠ” ì´ë¦„ì´ ìžˆì–´ì•¼í•©ë‹ˆë‹¤."
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
-msgstr "\"%{group_name}\"ì„ ìž…ë ¥í•˜ë©´ ë¡œê·¸ì¸ í•  수 있습니다."
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr ""
msgid "Allow access to members of the following group"
msgstr "ë‹¤ìŒ ê·¸ë£¹ì˜ êµ¬ì„±ì›ì— 대한 액세스 허용"
@@ -3813,6 +3887,9 @@ msgstr "ëŒ€ìƒ ë¸Œëžœì¹˜ì— ë¨¸ì§€í•  수 있는 구성ì›ì˜ ì»¤ë°‹ì„ í—ˆìš©í•
msgid "Allow group owners to manage LDAP-related settings"
msgstr "그룹 소유ìžê°€ LDAP 관련 ì„¤ì •ì„ ê´€ë¦¬í•˜ë„ë¡ í—ˆìš©"
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr "관리ìžê°€ ì•„ë‹Œ ìžê°€ 성능 í‘œì‹œì¤„ì— ì•¡ì„¸ìŠ¤í•  수 있ë„ë¡ í—ˆìš©"
@@ -3835,7 +3912,7 @@ msgid "Allow project maintainers to configure repository mirroring"
msgstr ""
msgid "Allow projects and subgroups to override the group setting"
-msgstr ""
+msgstr "프로ì íŠ¸ ë° í•˜ìœ„ ê·¸ë£¹ì´ ê·¸ë£¹ ì„¤ì •ì„ ìž¬ì •ì˜í•˜ë„ë¡ í—ˆìš©"
msgid "Allow projects within this group to use Git LFS"
msgstr "ì´ ê·¸ë£¹ì˜ í”„ë¡œì íŠ¸ë“¤ì´ Git LFS를 사용하ë„ë¡ í—ˆìš©"
@@ -3849,9 +3926,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr "ë¼ì´ì„ ìŠ¤ëœ EE 기능 사용 허용"
-msgid "Allow users to create top-level groups"
-msgstr "사용ìžê°€ 최ìƒìœ„ ê·¸ë£¹ì„ ë§Œë“¤ 수 있ë„ë¡ í—ˆìš©"
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4098,6 +4172,9 @@ msgstr "태그를 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 다시 ê²€ìƒ
msgid "An error occurred while fetching terraform reports."
msgstr "Terraform 보고서를 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr "ìž‘ì—… 로그를 가져 오는 ì¤‘ì— ì˜¤ë¥˜ê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤."
@@ -4282,9 +4359,6 @@ msgstr "ìž‘ì—…ì„ íŠ¸ë¦¬ê±°í•˜ëŠ” 중 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr "콘í…츠 편집기를 ë Œë”ë§í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 다시 ì‹œë„í•´ 주세요."
@@ -4301,7 +4375,7 @@ msgid "An error occurred while updating assignees."
msgstr ""
msgid "An error occurred while updating configuration."
-msgstr ""
+msgstr "ì„¤ì •ì„ ì—…ë°ì´íŠ¸í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "An error occurred while updating labels."
msgstr "ë¼ë²¨ì„ ì—…ë°ì´íŠ¸í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
@@ -4384,9 +4458,6 @@ msgstr "ì•Œ 수 없는 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "Analytics"
msgstr "분ì„"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4489,9 +4560,6 @@ msgstr "어플리케ì´ì…˜ ì„¤ì •ì´ ì„±ê³µì ìœ¼ë¡œ 저장ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr "어플리케ì´ì…˜ì´ 제거ë˜ì—ˆì§€ë§Œ, 파괴하지 못했습니다: %{error_message}"
-
msgid "Application was successfully destroyed."
msgstr "어플리케ì´ì…˜ì´ 성공ì ìœ¼ë¡œ ì‚­ì œë˜ì—ˆìŠµë‹ˆë‹¤."
@@ -4510,7 +4578,7 @@ msgstr "Grafanaì— ëŒ€í•œ ë§í¬ 추가"
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4551,6 +4619,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4569,9 +4640,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4599,6 +4679,9 @@ msgstr "변경 사항 저장"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -4881,7 +4964,7 @@ msgid "Archive project"
msgstr ""
msgid "Archive test case"
-msgstr ""
+msgstr "ì•„ì¹´ì´ë¸Œ 테스트 ì¼€ì´ìŠ¤"
msgid "Archived"
msgstr "ë³´ê´€ë¨"
@@ -4934,9 +5017,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr "ì •ë§ë¡œ ì´ ì•„í‹°íŒ©íŠ¸ë¥¼ 삭제하시겠습니까?"
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr "ì´ %{commentType}ì„ ì‚­ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?"
@@ -5037,8 +5117,8 @@ msgstr "ì´ ë§ˆì´ê·¸ë ˆì´ì…˜ì„ 다시 ì‹œë„하시겠습니까?"
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
-msgstr "ì´ %{type}ì„ ì·¨ì†Œí•˜ì‹œê² ìŠµë‹ˆê¹Œ? ì´ ìž‘ì—…ì€ ë˜ëŒë¦´ 수 없습니다."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr ""
@@ -5088,6 +5168,30 @@ msgstr ""
msgid "Artifacts"
msgstr "결과물"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5139,9 +5243,6 @@ msgstr "#FF0000ê³¼ ê°™ì´ ë§žì¶¤ ìƒ‰ìƒ ì§€ì •"
msgid "Assign labels"
msgstr "ë¼ë²¨ 지정"
-msgid "Assign milestone"
-msgstr "마ì¼ìŠ¤í†¤ 지정"
-
msgid "Assign myself"
msgstr "나ì—게 할당하기"
@@ -5532,9 +5633,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -5557,7 +5655,7 @@ msgid "AutoDevOps|Learn more in the %{link_to_documentation}"
msgstr "ë” ì•Œì•„ë³´ê¸° %{link_to_documentation}"
msgid "AutoDevOps|The Auto DevOps pipeline has been enabled and will be used if no alternative CI configuration file is found."
-msgstr ""
+msgstr "AutoDevOps|ìžë™ DevOps 파ì´í”„ë¼ì¸ì´ 활성화ë˜ì—ˆìœ¼ë©° 대체 CI 설정 파ì¼ì´ 없는 경우 사용ë©ë‹ˆë‹¤."
msgid "AutoDevopsAlert|Security testing tools enabled with %{linkStart}Auto DevOps%{linkEnd}"
msgstr ""
@@ -5566,28 +5664,28 @@ msgid "AutoRemediation| 1 Merge Request"
msgstr ""
msgid "AutoRemediation|%{mrsCount} ready for review"
-msgstr ""
+msgstr "AutoRemediation|%{mrsCount} 검토 준비"
msgid "AutoRemediation|Auto-fix"
msgstr ""
msgid "AutoRemediation|Auto-fix solutions"
-msgstr ""
+msgstr "ìžë™ 수정 솔루션"
msgid "AutoRemediation|If you're using dependency and/or container scanning, and auto-fix is enabled, auto-fix automatically creates merge requests with fixes to vulnerabilities."
-msgstr ""
+msgstr "종ì†ì„± ë°/ë˜ëŠ” 컨테ì´ë„ˆ ìŠ¤ìº”ì„ ì‚¬ìš© 중ì´ê³  ìžë™ ìˆ˜ì •ì´ í™œì„±í™”ëœ ê²½ìš° ìžë™ ìˆ˜ì •ì€ ì·¨ì•½ì  ìˆ˜ì •ì´ í¬í•¨ëœ 머지 리퀘스트를 ìžë™ìœ¼ë¡œ ìƒì„±í•©ë‹ˆë‹¤."
msgid "AutoRemediation|Introducing GitLab auto-fix"
-msgstr ""
+msgstr "GitLab ìžë™ 수정 소개"
msgid "AutoRollback|Automatic rollbacks start when a critical alert is triggered. If the last successful deployment fails to roll back automatically, it can still be done manually."
-msgstr ""
+msgstr "중요 경보가 트리거ë˜ë©´ ìžë™ ë¡¤ë°±ì´ ì‹œìž‘ë©ë‹ˆë‹¤. 마지막으로 성공한 ë°°í¬ê°€ ìžë™ìœ¼ë¡œ 롤백ë˜ì§€ 않는 경우ì—ë„ ìˆ˜ë™ìœ¼ë¡œ 수행 í•  수 있습니다."
msgid "AutoRollback|Automatically roll back to the last successful deployment when a critical problem is detected."
-msgstr ""
+msgstr "중대한 문제가 ê°ì§€ë˜ë©´ 마지막으로 성공한 ë°°í¬ë¡œ ìžë™ 롤백합니다."
msgid "AutoRollback|Enable automatic rollbacks"
-msgstr ""
+msgstr "ìžë™ 롤백 활성화"
msgid "Autocomplete"
msgstr "ìžë™ 완성"
@@ -5608,7 +5706,7 @@ msgid "Automatic certificate management using Let's Encrypt"
msgstr "Let's Encrypt를 사용하여 ì¸ì¦ì„œë¥¼ ìžë™ìœ¼ë¡œ 관리"
msgid "Automatic deployment rollbacks"
-msgstr ""
+msgstr "ìžë™ ë°°í¬ ë¡¤ë°±"
msgid "Automatic event tracking provides a traceable history for audits."
msgstr ""
@@ -5815,7 +5913,7 @@ msgid "Banner message"
msgstr "배너 메시지"
msgid "Based on"
-msgstr ""
+msgstr "기반으로"
msgid "Batch size"
msgstr "배치 í¬ê¸°"
@@ -5898,6 +5996,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6260,7 +6364,7 @@ msgid "Billing|Members who were invited via a group invitation cannot be removed
msgstr ""
msgid "Billing|No users to display."
-msgstr ""
+msgstr "Billing|표시할 사용ìžê°€ 없습니다."
msgid "Billing|Private"
msgstr ""
@@ -6496,7 +6600,7 @@ msgid "Boards|An error occurred while fetching the board issues. Please reload t
msgstr ""
msgid "Boards|An error occurred while fetching the board lists. Please reload the page."
-msgstr ""
+msgstr "ë³´ë“œ 목ë¡ì„ 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 페ì´ì§€ë¥¼ 새로고침하세요."
msgid "Boards|An error occurred while fetching the board swimlanes. Please reload the page."
msgstr ""
@@ -6505,7 +6609,7 @@ msgid "Boards|An error occurred while fetching the board. Please reload the page
msgstr ""
msgid "Boards|An error occurred while generating lists. Please reload the page."
-msgstr ""
+msgstr "목ë¡ì„ ìƒì„±í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 페ì´ì§€ë¥¼ 새로고침하세요."
msgid "Boards|An error occurred while moving the epic. Please try again."
msgstr ""
@@ -6617,11 +6721,14 @@ msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab
msgstr ""
msgid "Branch already exists"
-msgstr ""
+msgstr "브랜치가 ì´ë¯¸ 있습니다."
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6631,6 +6738,9 @@ msgstr "해당 브랜치는 ì´ë¯¸ 사용중입니다"
msgid "Branch name"
msgstr "브랜치 ì´ë¦„"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6638,58 +6748,67 @@ msgid "Branch rules"
msgstr "브랜치 규칙"
msgid "BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or production/ are supported"
-msgstr ""
+msgstr "*-stable ë˜ëŠ” production/ 와 ê°™ì€ %{linkStart}와ì¼ë“œì¹´ë“œ%{linkEnd}ê°€ 지ì›ë©ë‹ˆë‹¤."
msgid "BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or production/* are supported."
msgstr "*-stable ë˜ëŠ” production/*ê³¼ ê°™ì€ %{linkStart}와ì¼ë“œì¹´ë“œ%{linkEnd}ê°€ 지ì›ë©ë‹ˆë‹¤."
msgid "BranchRules|All branches"
-msgstr ""
+msgstr "모든 브랜치"
msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
+msgstr "푸시 액세스 ê¶Œí•œì´ ìžˆëŠ” 모든 사용ìžëŠ” 강제로 푸시할 수 있습니다."
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr "푸시 액세스 ê¶Œí•œì´ ìžˆëŠ” 모든 사용ìžì—게 %{linkStart}ê°•ì œ 푸시%{linkEnd}를 허용합니다."
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr "머지 허용"
msgid "BranchRules|Allowed to merge (%{total})"
-msgstr ""
+msgstr "ë³‘í•©ì´ í—ˆìš©ë¨(%{total})"
msgid "BranchRules|Allowed to push"
msgstr "푸시 허용"
msgid "BranchRules|Allowed to push (%{total})"
-msgstr ""
+msgstr "푸시 í—ˆìš©ë¨ (%{total})"
msgid "BranchRules|An error occurred while fetching branches."
msgstr "브랜치를 가져오는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "BranchRules|Approvals"
+msgstr "승ì¸"
+
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
msgid "BranchRules|Branch"
msgstr "브랜치"
msgid "BranchRules|Branch name or pattern"
-msgstr ""
+msgstr "브랜치 ì´ë¦„ ë˜ëŠ” 패턴"
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr "와ì¼ë“œì¹´ë“œ ìƒì„±: %{searchTerm}"
msgid "BranchRules|Details"
-msgstr ""
+msgstr "세부정보"
msgid "BranchRules|Force push"
-msgstr ""
+msgstr "강제 푸시"
msgid "BranchRules|Force push is not allowed."
-msgstr ""
+msgstr "ê°•ì œ 푸시는 허용ë˜ì§€ 않습니다."
msgid "BranchRules|Groups"
msgstr ""
@@ -6697,17 +6816,23 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr "머지 레퀘스트 승ì¸ì—ì„œ 관리"
+
msgid "BranchRules|Manage in Protected Branches"
+msgstr "ë³´í˜¸ëœ ë¸Œëžœì¹˜ì—ì„œ 관리"
+
+msgid "BranchRules|Manage in Status checks"
msgstr ""
msgid "BranchRules|No data to display"
-msgstr ""
+msgstr "표시할 ë°ì´í„°ê°€ 없습니다"
msgid "BranchRules|No matching results"
msgstr "ì¼ì¹˜í•˜ëŠ” 결과가 없습니다"
msgid "BranchRules|Protect branch"
-msgstr ""
+msgstr "브랜치 보호"
msgid "BranchRules|Protections"
msgstr ""
@@ -6718,10 +6843,19 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr "코드 소유ìžì˜ 승ì¸ì´ 필요합니다."
+msgid "BranchRules|Required approvals (%{total})"
+msgstr "ìŠ¹ì¸ í•„ìš” (%{total})"
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
+msgstr "ìƒíƒœ 확ì¸"
+
+msgid "BranchRules|Status checks (%{total})"
msgstr ""
msgid "BranchRules|Target Branch"
@@ -6883,6 +7017,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "디렉토리 찾아보기"
@@ -6892,9 +7029,6 @@ msgstr "íŒŒì¼ ì°¾ì•„ë³´ê¸°"
msgid "Browse Files"
msgstr "íŒŒì¼ ì°¾ì•„ë³´ê¸°"
-msgid "Browse artifacts"
-msgstr "아티팩트 찾아보기"
-
msgid "Browse files"
msgstr "íŒŒì¼ ì°¾ì•„ë³´ê¸°"
@@ -6940,9 +7074,6 @@ msgstr "소스 그룹으로 í•„í„°ë§"
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -6973,6 +7104,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -6988,6 +7122,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7012,9 +7149,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7025,16 +7159,16 @@ msgid "BulkImport|Your imported projects will appear here."
msgstr ""
msgid "BulkImport|expected an associated Group but has an associated Project"
-msgstr ""
+msgstr "BulkImport|ì—°ê²°ëœ ê·¸ë£¹ì´ í•„ìš”í•˜ì§€ë§Œ ì—°ê²°ëœ í”„ë¡œì íŠ¸ê°€ 있습니다."
msgid "BulkImport|expected an associated Project but has an associated Group"
-msgstr ""
+msgstr "BulkImport|ì—°ê²°ëœ í”„ë¡œì íŠ¸ê°€ 필요하지만 ì—°ê²°ëœ ê·¸ë£¹ì´ ìžˆìŠµë‹ˆë‹¤."
msgid "BulkImport|invalid entity source type"
msgstr ""
msgid "BulkImport|must be a group"
-msgstr ""
+msgstr "BulkImport|그룹ì´ì–´ì•¼ 합니다."
msgid "Bullet list"
msgstr "글머리 기호 목ë¡"
@@ -7427,9 +7561,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr "대외비가 ì•„ë‹Œ ì´ìŠˆì— 대외비 ì—í”½ì„ í• ë‹¹í•  수 없습니다. ì´ìŠˆë¥¼ 대외비로 설정하고 다시 ì‹œë„하세요."
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr "ìžë™ìœ¼ë¡œ 머지할 수 없습니다."
@@ -7445,6 +7576,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8039,7 +8173,7 @@ msgid "Child issues and epics"
msgstr ""
msgid "Chinese language support using"
-msgstr ""
+msgstr "중국어 지ì›"
msgid "Choose File..."
msgstr "íŒŒì¼ ì„ íƒ..."
@@ -8182,6 +8316,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9495,10 +9632,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9679,6 +9822,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr "ê°€ìž…ì„ ìœ„í•´ ì¸ì¦ì„ 완료하세요."
+msgid "Complete with errors"
+msgstr "오류가 있는 완료"
+
msgid "Completed"
msgstr ""
@@ -9749,7 +9895,7 @@ msgid "ComplianceFrameworks|No compliance frameworks are set up yet"
msgstr ""
msgid "ComplianceFrameworks|Required format: %{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}. %{linkStart}What is a compliance pipeline configuration?%{linkEnd}"
-msgstr ""
+msgstr "요구 형ì‹: %{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}. %{linkStart}규정 준수 파ì´í”„ë¼ì¸ 구성ì´ëž€ 무엇입니까?%{linkEnd}"
msgid "ComplianceFrameworks|Unable to save this compliance framework. Please try again"
msgstr ""
@@ -10055,7 +10201,7 @@ msgid "Connection timed out"
msgstr "ì—°ê²° ì‹œê°„ì´ ì´ˆê³¼ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "Consistency guarantee method"
-msgstr ""
+msgstr "ì¼ê´€ì„± 보장 방법"
msgid "Contact support"
msgstr "ê³ ê° ì§€ì› ë¬¸ì˜"
@@ -10067,7 +10213,7 @@ msgid "Container Registry"
msgstr "컨테ì´ë„ˆ 레지스트리"
msgid "Container Repository"
-msgstr ""
+msgstr "컨테ì´ë„ˆ 저장소"
msgid "Container Scanning"
msgstr ""
@@ -10471,10 +10617,10 @@ msgstr "기여"
msgid "Contribution Analytics"
msgstr "ê¸°ì—¬ë„ ë¶„ì„"
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10507,6 +10653,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10555,9 +10710,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr "%{protocol} í´ë¡  URL 복사"
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr "ID 복사"
@@ -10642,9 +10794,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr "소스 브랜치 ì´ë¦„ 복사"
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10781,7 +10930,7 @@ msgid "Could not delete wiki page"
msgstr ""
msgid "Could not draw the lines for job relationships"
-msgstr ""
+msgstr "ì§ì—… ê´€ê³„ì— ëŒ€í•œ ì„ ì„ ê·¸ë¦´ 수 없습니다"
msgid "Could not fetch policy because existing policy YAML is invalid"
msgstr ""
@@ -10799,7 +10948,7 @@ msgid "Could not get the data properly"
msgstr ""
msgid "Could not load the user chart. Please refresh the page to try again."
-msgstr ""
+msgstr "ì‚¬ìš©ìž ì°¨íŠ¸ë¥¼ 로드할 수 없습니다. 다시 ì‹œë„하려면 페ì´ì§€ë¥¼ 새로고침하세요."
msgid "Could not load usage counts. Please refresh the page to try again."
msgstr ""
@@ -10807,9 +10956,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11029,9 +11175,6 @@ msgstr "새 íŒŒì¼ ë˜ëŠ” 디렉토리 만들기"
msgid "Create new label"
msgstr "새 ë¼ë²¨ 만들기"
-msgid "Create new project"
-msgstr "새 프로ì íŠ¸ 만들기"
-
msgid "Create new..."
msgstr ""
@@ -11279,7 +11422,7 @@ msgid "Created on"
msgstr "ìƒì„±ì¼"
msgid "Created on %{created_at}"
-msgstr ""
+msgstr "%{created_at}ì— ìƒì„±ë¨"
msgid "Created on:"
msgstr "ìƒì„±ì¼:"
@@ -11299,9 +11442,6 @@ msgstr "ì—픽 ìƒì„± 중"
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr "ìƒì„± 날짜"
-
msgid "Creator"
msgstr ""
@@ -11317,7 +11457,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11419,9 +11559,6 @@ msgstr "현재 브랜치"
msgid "Current Project"
msgstr "현재 프로잭트"
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11468,7 +11605,7 @@ msgid "Custom Git clone URL for HTTP(S)"
msgstr ""
msgid "Custom analyzers: language support"
-msgstr ""
+msgstr "ì‚¬ìš©ìž ì§€ì • 분ì„기: 언어 지ì›"
msgid "Custom hostname (for private commit emails)"
msgstr "ì‚¬ìš©ìž ì§€ì • 호스트네임 (ê°œì¸ ì»¤ë°‹ ì´ë©”ì¼ìš©)"
@@ -11747,6 +11884,9 @@ msgstr "DORA4Metrics|실패율 변경"
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr "DORA4Metrics|실패율(í¼ì„¼íŠ¸) 변경"
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11774,6 +11914,9 @@ msgstr "DORA4Metrics|중간값 시간(지난 %{days}ì¼)"
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr "DORA4Metrics|주어진 기간 ë™ì•ˆ 프로ë•ì…˜ 환경ì—ì„œ ì¸ì‹œë˜íŠ¸ê°€ ì—´ë ¤ìžˆì—ˆë˜ ì‹œê°„ì˜ ì¤‘ê°„ê°’ìž…ë‹ˆë‹¤."
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr "DORA4Metrics|ì´ ê¸°ê°„ ë™ì•ˆ ì¸ì‹œë˜íŠ¸ ì—†ìŒ"
@@ -11831,6 +11974,9 @@ msgstr "ê°œì¸"
msgid "DashboardProjects|Trending"
msgstr "ì¸ê¸°"
+msgid "Dashboards"
+msgstr "대시보드"
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -11874,7 +12020,7 @@ msgid "DastProfiles|A site profile defines the attributes and configuration deta
msgstr "사ì´íŠ¸ í”„ë¡œí•„ì€ ë°°í¬ëœ 애플리케ì´ì…˜, 웹 사ì´íŠ¸ ë˜ëŠ” APIì˜ ì†ì„± ë° êµ¬ì„± 세부 정보를 ì •ì˜í•©ë‹ˆë‹¤. %{linkStart}ìžì„¸ížˆ 알아보기%{linkEnd}."
msgid "DastProfiles|AJAX spider"
-msgstr ""
+msgstr "AJAX 스파ì´ë”"
msgid "DastProfiles|API"
msgstr ""
@@ -11883,7 +12029,7 @@ msgid "DastProfiles|API endpoint URL"
msgstr ""
msgid "DastProfiles|Active"
-msgstr ""
+msgstr "활성"
msgid "DastProfiles|Additional request headers (optional)"
msgstr ""
@@ -11946,10 +12092,10 @@ msgid "DastProfiles|DAST profile library"
msgstr ""
msgid "DastProfiles|Debug messages"
-msgstr ""
+msgstr "디버그 메시지"
msgid "DastProfiles|Delete profile"
-msgstr ""
+msgstr "프로필 삭제"
msgid "DastProfiles|Edit profile"
msgstr ""
@@ -12065,6 +12211,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12282,9 +12431,12 @@ msgstr ""
msgid "Data type"
msgstr ""
-msgid "Database update failed"
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
msgstr ""
+msgid "Database update failed"
+msgstr "ë°ì´í„°ë² ì´ìŠ¤ ì—…ë°ì´íŠ¸ 실패"
+
msgid "DatadogIntegration|%{linkOpen}API key%{linkClose} used for authentication with Datadog."
msgstr ""
@@ -12369,6 +12521,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12402,6 +12557,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr "기본값 - 실행ë˜ì§€ ì•ŠìŒ"
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12513,6 +12671,9 @@ msgstr "삭제 "
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12534,9 +12695,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr "아티팩트 삭제"
-
msgid "Delete asset"
msgstr ""
@@ -12544,7 +12702,7 @@ msgid "Delete audio"
msgstr ""
msgid "Delete badge"
-msgstr ""
+msgstr "배지 삭제"
msgid "Delete code block"
msgstr ""
@@ -12603,7 +12761,7 @@ msgstr "릴리스 %{release}ì„ ì‚­ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?"
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -12619,7 +12777,7 @@ msgid "Delete source branch when merge request is accepted."
msgstr ""
msgid "Delete subscription"
-msgstr ""
+msgstr "êµ¬ë… ì‚­ì œ"
msgid "Delete table"
msgstr ""
@@ -12790,7 +12948,7 @@ msgid "Dependencies|Job failed to generate the dependency list"
msgstr "ì˜ì¡´ì„± 목ë¡ì„ 만들어내는 ìž‘ì—…ì„ ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤"
msgid "Dependencies|Learn more about dependency paths"
-msgstr ""
+msgstr "종ì†ì„± ê²½ë¡œì— ëŒ€í•´ ìžì„¸ížˆ 알아보기"
msgid "Dependencies|License"
msgstr ""
@@ -12799,7 +12957,7 @@ msgid "Dependencies|Location"
msgstr ""
msgid "Dependencies|Location and dependency path"
-msgstr ""
+msgstr "위치 ë° ì¢…ì†ì„± 경로"
msgid "Dependencies|Packager"
msgstr ""
@@ -13074,6 +13232,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr "만료"
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13161,6 +13322,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr "ë°°í¬ ë¹ˆë„"
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13374,7 +13550,7 @@ msgid "DesignManagement|Are you sure you want to cancel creating this comment?"
msgstr "ì´ ëŒ“ê¸€ ìž‘ì„±ì„ ì·¨ì†Œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?"
msgid "DesignManagement|Are you sure you want to cancel editing this comment?"
-msgstr ""
+msgstr "ì´ ëŒ“ê¸€ íŽ¸ì§‘ì„ ì·¨ì†Œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?"
msgid "DesignManagement|Click the image where you'd like to start a new discussion"
msgstr ""
@@ -13383,10 +13559,10 @@ msgid "DesignManagement|Comment"
msgstr "댓글"
msgid "DesignManagement|Continue creating"
-msgstr ""
+msgstr "ê³„ì† ìƒì„±"
msgid "DesignManagement|Continue editing"
-msgstr ""
+msgstr "ê³„ì† íŽ¸ì§‘ "
msgid "DesignManagement|Could not add a new comment. Please try again."
msgstr ""
@@ -13407,7 +13583,7 @@ msgid "DesignManagement|Designs"
msgstr ""
msgid "DesignManagement|Discard changes"
-msgstr ""
+msgstr "변경 사항 취소"
msgid "DesignManagement|Discussion"
msgstr "토론"
@@ -13499,6 +13675,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr "개발ìž"
+
msgid "Development"
msgstr "개발"
@@ -13735,6 +13914,12 @@ msgstr[0] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13750,10 +13935,16 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -13954,7 +14145,7 @@ msgid "Documentation for popular identity providers"
msgstr "ì¸ê¸°ìžˆëŠ” ID 제공 ì—…ì²´ì— ëŒ€í•œ 문서"
msgid "Documentation pages URL"
-msgstr ""
+msgstr "문서 페ì´ì§€ URL"
msgid "Documents reindexed: %{processed_documents} (%{percentage}%%)"
msgstr ""
@@ -14320,13 +14511,13 @@ msgid "Edit table"
msgstr ""
msgid "Edit this file only."
-msgstr ""
+msgstr "해당 íŒŒì¼ íŽ¸ì§‘"
msgid "Edit this release"
msgstr "ì´ ë¦´ë¦¬ìŠ¤ 편집"
msgid "Edit title and description"
-msgstr ""
+msgstr "제목 ë° ì„¤ëª… 수정"
msgid "Edit topic: %{topic_name}"
msgstr ""
@@ -14353,11 +14544,17 @@ msgid "Edit, lint, and visualize your pipeline."
msgstr ""
msgid "Edited"
-msgstr ""
+msgstr "수정ë¨"
msgid "Edited %{timeago}"
msgstr "%{timeago} ì „ 수정ë¨"
+msgid "Edited %{timeago} by %{author}"
+msgstr "%{timeago}ì— %{author}ê°€ 수정"
+
+msgid "Edited by %{author}"
+msgstr "%{author}ì— ì˜í•´ 수정ë¨"
+
msgid "Editing"
msgstr ""
@@ -14665,10 +14862,10 @@ msgid "Enable security training to help your developers learn how to fix vulnera
msgstr ""
msgid "Enable shared runners for all projects and subgroups in this group."
-msgstr ""
+msgstr "ì´ ê·¸ë£¹ì˜ ëª¨ë“  프로ì íŠ¸ ë° í•˜ìœ„ ê·¸ë£¹ì— ëŒ€í•´ 공유 러너를 활성화합니다."
msgid "Enable shared runners for this group"
-msgstr ""
+msgstr "ì´ ê·¸ë£¹ì— ëŒ€í•´ 공유 러너 활성화"
msgid "Enable shared runners for this project"
msgstr ""
@@ -14688,23 +14885,41 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
-msgstr ""
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr "CI/CD 구성ì—ì„œ ë‹¤ìŒ ìž‘ì—…ì„ ì¶”ê°€í•©ë‹ˆë‹¤."
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
-msgstr ""
+msgid "EnableReviewApp|Copy snippet"
+msgstr "스니펫 복사"
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
-msgstr ""
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr "검토 ì•±ì„ í˜¸ìŠ¤íŒ…í•˜ê³  ë°°í¬í•  수 있는 ì¸í”„ë¼ì— 액세스할 수 있습니다."
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
-msgstr ""
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr "ë°°í¬ë¥¼ 수행할 실행기를 설치 ë° êµ¬ì„±í•©ë‹ˆë‹¤."
-msgid "EnableReviewApp|Close"
-msgstr ""
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr "프로ì íŠ¸ì— 웹사ì´íŠ¸ URLë¡œ ì„¤ì •ëœ ëŒ€ìƒ URLë¡œ êµ¬ì„±ëœ í™˜ê²½ì´ ìžˆëŠ”ì§€ 확ì¸í•˜ì‹­ì‹œì˜¤. 그렇지 ì•Šì€ ê²½ìš° 계ì†í•˜ê¸° ì „ì— ìƒˆ í•­ëª©ì„ ë§Œë“œì‹­ì‹œì˜¤."
-msgid "EnableReviewApp|Copy snippet text"
-msgstr ""
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr "기능 브랜치 ë˜ëŠ” 머지 ë¦¬í€˜ìŠ¤íŠ¸ì— ëŒ€í•´ì„œë§Œ 실행ë©ë‹ˆë‹¤."
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr "권장: 리뷰 ì•±ì„ ìˆ˜ë™ìœ¼ë¡œ 중지하ë„ë¡ ìž‘ì—…ì„ ì„¤ì •í•©ë‹ˆë‹¤."
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr "검토 ì•±ì€ ê¸°ëŠ¥ 분기ì—ì„œ ìˆ˜í–‰ëœ ë³€ê²½ ì‚¬í•­ì˜ ì‹¤ì‹œê°„ 미리 보기를 제공하는 ë° ì‚¬ìš©í•  수 있는 ë™ì  환경입니다."
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr "ë™ì  검토 ì•±ì„ êµ¬ì„±í•˜ë ¤ë©´ 다ìŒì„ 수행해야 합니다."
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr "%{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} 와 ê°™ì€ ë¯¸ë¦¬ ì •ì˜ëœ CI/CD 변수를 사용하여 리뷰 앱 í™˜ê²½ì„ ë™ì ìœ¼ë¡œ ìƒì„±í•©ë‹ˆë‹¤. 예를 들어, 머지 리퀘스트 파ì´í”„ë¼ì¸ì„ 사용하는 êµ¬ì„±ì˜ ê²½ìš°:"
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr "ì •ì  ì‚¬ì´íŠ¸ë¥¼ 사용 중ì´ì‹ ê°€ìš”?"
+
+msgid "EnableReviewApp|View more example projects"
+msgstr "ë” ë§Žì€ ì˜ˆì œ 프로ì íŠ¸ 보기"
msgid "Enabled"
msgstr "활성화ë¨"
@@ -14716,7 +14931,7 @@ msgid "Enabled OAuth authentication sources"
msgstr ""
msgid "End Time"
-msgstr ""
+msgstr "종료 시간"
msgid "Ends"
msgstr ""
@@ -14931,6 +15146,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr "커밋"
+msgid "Environments|Copy live environment URL"
+msgstr "ë¼ì´ë¸Œ 환경 URL 복사"
+
msgid "Environments|Delete"
msgstr ""
@@ -15111,10 +15329,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
-msgstr ""
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgstr "%{bStart}%{parentEpicTitle}%{bEnd}ì—ì„œ %{bStart}%{targetEpicTitle}%{bEnd} 를 삭제하시겠습니까?"
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15129,18 +15347,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15153,18 +15362,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15294,9 +15497,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr "리뷰어를 저장하는 ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15360,9 +15560,6 @@ msgstr "íŒŒì¼ ì—…ë¡œë“œ 오류"
msgid "Error uploading file. Please try again."
msgstr "íŒŒì¼ ì—…ë¡œë“œì— ì‹¤íŒ¨í•˜ì˜€ìŠµë‹ˆë‹¤. 다시 ì‹œë„í•´ 주세요."
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr "머지 리퀘스트(MR) 요청 중 오류 ë°œìƒ. 다시 ì‹œë„하십시오."
@@ -15603,6 +15800,57 @@ msgstr "ì´ë²¤íŠ¸"
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr "수ë½ë¨"
+
+msgid "Event|added"
+msgstr "추가ë¨"
+
+msgid "Event|approved"
+msgstr "승ì¸ë¨"
+
+msgid "Event|closed"
+msgstr "종료ë¨"
+
+msgid "Event|commented on"
+msgstr "ëŒ“ê¸€ì´ ë‹¬ë¦¼"
+
+msgid "Event|created"
+msgstr "ìƒì„±ë¨"
+
+msgid "Event|deleted"
+msgstr "ì‚­ì œë¨"
+
+msgid "Event|destroyed"
+msgstr "파괴ë¨"
+
+msgid "Event|imported"
+msgstr "가져옴"
+
+msgid "Event|joined"
+msgstr "참가ë¨"
+
+msgid "Event|left"
+msgstr "남겨ì§"
+
+msgid "Event|opened"
+msgstr "열림"
+
+msgid "Event|pushed new"
+msgstr "새로 푸시ë¨"
+
+msgid "Event|pushed to"
+msgstr "푸시ë¨"
+
+msgid "Event|removed"
+msgstr "ì‚­ì œë¨"
+
+msgid "Event|removed due to membership expiration from"
+msgstr "멤버십 만료로 ì¸í•´ ì‚­ì œë¨"
+
+msgid "Event|updated"
+msgstr "ì—…ë°ì´íŠ¸ë¨"
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr "매번 %{action}ì´ ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤: %{job_error_message}. 다시 ì‹œë„해주세요."
@@ -15721,6 +15969,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15778,9 +16029,15 @@ msgstr "사ì´ë“œë°” 확장"
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr "만료"
@@ -16004,6 +16261,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr "리소스 ë§í¬ë¥¼ 추가하지 못했습니다."
+
msgid "Failed to apply commands."
msgstr ""
@@ -16050,9 +16310,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16153,7 +16410,7 @@ msgid "Failed to load stacktrace."
msgstr ""
msgid "Failed to make repository read-only. %{reason}"
-msgstr ""
+msgstr "저장소를 ì½ê¸° 전용으로 만들지 못했습니다. %{reason}"
msgid "Failed to mark this issue as a duplicate because referenced issue was not found."
msgstr ""
@@ -16248,9 +16505,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16499,7 +16753,7 @@ msgid "FeatureFlag|User IDs"
msgstr ""
msgid "FeatureFlag|User List"
-msgstr ""
+msgstr "ì‚¬ìš©ìž ëª©ë¡"
msgid "Feb"
msgstr "2ì›”"
@@ -16507,6 +16761,9 @@ msgstr "2ì›”"
msgid "February"
msgstr "2ì›”"
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16612,9 +16869,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr "마ì¼ìŠ¤í†¤ìœ¼ë¡œ í•„í„°ë§"
-
msgid "Filter by milestone name"
msgstr "마ì¼ìŠ¤í†¤ ì´ë¦„으로 í•„í„°ë§"
@@ -16822,6 +17076,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -16928,7 +17185,7 @@ msgid "Framework successfully deleted"
msgstr ""
msgid "Free"
-msgstr ""
+msgstr "무료"
msgid "Free Trial of GitLab.com Ultimate"
msgstr ""
@@ -17226,7 +17483,7 @@ msgid "Geo|Errors:"
msgstr ""
msgid "Geo|External URL"
-msgstr ""
+msgstr "외부 URL"
msgid "Geo|Failed"
msgstr "실패"
@@ -17568,7 +17825,7 @@ msgid "Geo|There was an error updating the Geo Settings"
msgstr ""
msgid "Geo|This GitLab instance is subscribed to the %{insufficient_license} tier. Geo is only available for users who have at least a Premium subscription."
-msgstr ""
+msgstr "ì´ GitLab ì¸ìŠ¤í„´ìŠ¤ëŠ” %{insufficient_license} ìš”ê¸ˆì œì— ê°€ìž…ë˜ì–´ 있습니다. Geo는 최소한 Premium 구ë…ì´ ìžˆëŠ” 사용ìžë§Œ 사용할 수 있습니다."
msgid "Geo|This will resync all %{replicableType}. It may take some time to complete. Are you sure you want to continue?"
msgstr ""
@@ -17651,9 +17908,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17780,6 +18034,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr "GitLab 오류 추ì "
@@ -17831,6 +18091,9 @@ 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 ""
@@ -17879,9 +18142,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18437,9 +18697,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18449,6 +18706,9 @@ msgstr ""
msgid "Group"
msgstr "그룹"
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr "그룹 %{group_name} ê³¼ Mattermost íŒ€ì´ ì„±ê³µì ìœ¼ë¡œ ìƒì„±ë˜ì—ˆìŠµë‹ˆë‹¤."
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -18915,7 +19175,7 @@ msgid "GroupSettings|Compliance frameworks"
msgstr ""
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
-msgstr ""
+msgstr "GroupSettings|ì´ ê·¸ë£¹ì˜ í”„ë¡œì íŠ¸ì—ì„œ 사용할 수 있ë„ë¡ ì¸ì¦ëœ 프레임워í¬ë¥¼ 구성합니다. %{linkStart}ì¸ì¦ëœ 프레임워í¬ëž€ 무엇입니까?%{linkEnd}"
msgid "GroupSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
@@ -19211,12 +19471,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr "그룹 로딩중입니다"
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19286,6 +19540,9 @@ msgstr "하위 그룹 슬러그"
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr "ì†ë‹˜"
+
msgid "Guideline"
msgstr "ê°€ì´ë“œë¼ì¸"
@@ -19308,7 +19565,7 @@ msgid "Harbor Registry"
msgstr ""
msgid "HarborIntegration|After the Harbor integration is activated, global variables `$HARBOR_USERNAME`, `$HARBOR_HOST`, `$HARBOR_OCI`, `$HARBOR_PASSWORD`, `$HARBOR_URL` and `$HARBOR_PROJECT` will be created for CI/CD use."
-msgstr ""
+msgstr "하버 í†µí•©ì´ í™œì„±í™”ë˜ë©´ CI/CDìš© ì „ì—­ 변수 `$HARBOR_USERNAME`, `$HARBOR_HOST`, `$HARBOR_OCI`, `$HARBOR_PASSWORD`, `$HARBOR_URL` ë° `$HARBOR_PROJECT`ì´ ìƒì„±ë©ë‹ˆë‹¤."
msgid "HarborIntegration|Base URL of the Harbor instance."
msgstr ""
@@ -19462,9 +19719,6 @@ msgstr "헬스 정보는 다ìŒì˜ 경로를 통해 조회할 수 있습니다.
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr "ì´ ì´ìŠˆê°€ 닫혀있으므로 ìƒíƒœë¥¼ 수정할 수 없습니다."
-
msgid "HealthCheck|Access token is"
msgstr "엑세스 토í°: "
@@ -19917,8 +20171,14 @@ msgstr "코드 보내기"
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
-msgstr "1단계: 전화번호 확ì¸"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr "%{stepNumber}단계 : ê²°ì œ 수단 확ì¸"
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr "%{stepNumber}단계 : ì´ë©”ì¼ ì£¼ì†Œ 확ì¸"
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
+msgstr "%{stepNumber}단계 : 전화번호 확ì¸"
msgid "IdentityVerification|The code has expired. Send a new code and try again."
msgstr ""
@@ -20004,12 +20264,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -20235,7 +20489,7 @@ msgid "ImportProjects|%{provider} rate limit exceeded. Try again later"
msgstr ""
msgid "ImportProjects|Advanced import settings"
-msgstr ""
+msgstr "고급 가져오기 설정"
msgid "ImportProjects|Blocked import URL: %{message}"
msgstr ""
@@ -20262,7 +20516,7 @@ msgid "ImportProjects|Select the repositories you want to import"
msgstr ""
msgid "ImportProjects|The more information you select, the longer it will take to import"
-msgstr ""
+msgstr "ì„ íƒí•˜ëŠ” ì •ë³´ê°€ 많ì„ìˆ˜ë¡ ê°€ì ¸ì˜¤ëŠ” ë° ì‹œê°„ì´ ì˜¤ëž˜ 걸립니다."
msgid "ImportProjects|The remote data could not be imported."
msgstr ""
@@ -20866,10 +21120,10 @@ msgid "Incident template (optional)."
msgstr ""
msgid "IncidentManagement|%{hours} hours, %{minutes} minutes remaining"
-msgstr ""
+msgstr "IncidentManagement|%{hours} 시간 %{minutes} 분 남ìŒ"
msgid "IncidentManagement|%{minutes} minutes remaining"
-msgstr ""
+msgstr "사고관리|%{minutes} 분 남ìŒ"
msgid "IncidentManagement|Achieved SLA"
msgstr ""
@@ -21031,7 +21285,7 @@ msgid "IncidentSettings|hours"
msgstr ""
msgid "IncidentSettings|minutes"
-msgstr ""
+msgstr "IncidentSettings|분"
msgid "Incidents"
msgstr ""
@@ -21268,7 +21522,7 @@ msgid "Insert column before"
msgstr ""
msgid "Insert image"
-msgstr ""
+msgstr "ì´ë¯¸ì§€ 삽입"
msgid "Insert link"
msgstr ""
@@ -21500,7 +21754,7 @@ msgid "Integrations|Instance-level integration management"
msgstr ""
msgid "Integrations|Issues created in Jira are shown here once you have created the issues in project setup in Jira."
-msgstr ""
+msgstr "Jiraì—ì„œ ìƒì„±ëœ ì´ìŠˆëŠ” Jiraì˜ í”„ë¡œì íŠ¸ 설정ì—ì„œ ì´ìŠˆë¥¼ ìƒì„±í•˜ë©´ ì—¬ê¸°ì— í‘œì‹œë©ë‹ˆë‹¤."
msgid "Integrations|Keep your PHP dependencies updated on Packagist."
msgstr ""
@@ -21757,6 +22011,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr "무효화ë¨"
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21775,9 +22032,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -21835,8 +22089,8 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
-msgstr "ë” ë§Žì€ íšŒì›ì„ 확보하고 추가 유료 ê¸°ëŠ¥ì— ì•¡ì„¸ìŠ¤í•˜ê¸° 위해 그룹 소유ìžëŠ” í‰ê°€íŒì„ 시작하거나 유료 요금제로 업그레ì´ë“œ 해야 합니다."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
+msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
msgstr ""
@@ -21914,19 +22168,16 @@ msgid "InviteMembersModal|The following member couldn't be invited"
msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] "ë‹¤ìŒ %d ëª…ì˜ íšŒì›ì€ 초대할 수 없습니다"
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr "ë” ë§Žì€ íšŒì›ì„ 가입시키기 위해서는 그룹 소유ìžê°€ %{trialLinkStart}í‰ê°€íŒì„ 시작하거나%{trialLinkEnd} ë˜ëŠ” %{upgradeLinkStart}유료 요금제로 업그레ì´ë“œ%{upgradeLinkEnd} 해야 합니다."
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22064,12 +22315,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr "ì œê±°ëœ ê²€í†  요청 "
msgid "IssuableEvents|requested review from"
msgstr "검토 요청 보낸사람"
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr "%{wi_type}ì´ %{created_at}ì— ìƒì„±ë¨. ìž‘ì„±ìž "
@@ -22091,6 +22348,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr "ì´ìŠˆ"
@@ -22316,6 +22585,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22610,6 +22894,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -22940,6 +23227,9 @@ msgstr ""
msgid "Job|Download"
msgstr "다운로드"
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -22979,9 +23269,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23356,9 +23652,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23512,6 +23805,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr "ì´ìŠˆì— 대해 ìžì„¸ížˆ 알아보세요."
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23662,9 +23964,6 @@ msgstr "프로ì íŠ¸ì—ì„œ 나가기"
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -23905,6 +24204,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24175,9 +24480,6 @@ msgstr ""
msgid "Logs"
msgstr "로그"
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24190,6 +24492,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24226,8 +24531,14 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
-msgstr "ì´ ì´ìŠˆë¥¼ 비공개로 설정하였습니다."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
+msgstr ""
msgid "Mailgun"
msgstr ""
@@ -24241,9 +24552,15 @@ msgstr ""
msgid "Main menu"
msgstr "ë©”ì¸ ë©”ë‰´"
+msgid "Maintainer"
+msgstr "관리ìž"
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24253,9 +24570,6 @@ msgstr "웹 IDE를 사용하여 브ë¼ìš°ì €ì—ì„œ 변경 ì‚¬í•­ì„ ìž‘ì„±í•˜ê³ 
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr "ì´ìŠˆë¥¼ 비공개로 설정"
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24265,8 +24579,8 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
-msgstr "ì´ ì´ìŠˆë¥¼ 비공개로 설정하기"
+msgid "Makes this %{type} confidential."
+msgstr ""
msgid "Manage %{workspace} labels"
msgstr ""
@@ -24314,7 +24628,7 @@ msgid "Manage your project's triggers"
msgstr ""
msgid "Manage your subscription"
-msgstr ""
+msgstr "êµ¬ë… ê´€ë¦¬"
msgid "Managed Account"
msgstr ""
@@ -24322,6 +24636,9 @@ msgstr ""
msgid "Manifest"
msgstr "Manifest"
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr "Manifest íŒŒì¼ ê°€ì ¸ì˜¤ê¸°"
@@ -24346,6 +24663,9 @@ msgstr "3ì›”"
msgid "March"
msgstr "3ì›”"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr "완료로 표시"
@@ -24397,6 +24717,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr "í´ë¦­í•˜ì—¬ 확장"
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24409,6 +24732,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr "í—¤ë”"
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr "%{markdownDocsLinkStart}마í¬ë‹¤ìš´%{markdownDocsLinkEnd} 지ì›"
@@ -25035,6 +25361,9 @@ msgstr "머지 리퀘스트 ë° ìŠ¹ì¸ ì„¤ì •ì´ ì´ë™ë˜ì—ˆìŠµë‹ˆë‹¤."
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr "머지 리퀘스트(MR)는 프로ì íŠ¸ì˜ 변경 ì‚¬í•­ì„ ì œì•ˆí•˜ê³  변경 ì‚¬í•­ì„ ë‹¤ë¥¸ 사람들과 ë…¼ì˜ í•˜ëŠ” 곳입니다."
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25260,6 +25589,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25649,29 +25981,32 @@ msgstr "마ì¼ìŠ¤í†¤ 마ê°ì¼"
msgid "Milestone lists not available with your current license"
msgstr "현재 ë¼ì´ì„¼ìŠ¤ì—서는 마ì¼ìŠ¤í†¤ 목ë¡ì„ 사용할 수 없습니다."
+msgid "Milestone(s) not found: %{milestones}"
+msgstr "마ì¼ìŠ¤í†¤ì„ ì°¾ì„ ìˆ˜ ì—†ìŒ: %{milestones}"
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
-msgstr ""
+msgstr "MilestoneCombobox|마ì¼ìŠ¤í†¤ 검색 중 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
msgid "MilestoneCombobox|Group milestones"
msgstr ""
msgid "MilestoneCombobox|Milestone"
-msgstr ""
+msgstr "MilestoneCombobox|마ì¼ìŠ¤í†¤"
msgid "MilestoneCombobox|No matching results"
-msgstr ""
+msgstr "MilestoneCombobox|ì¼ì¹˜í•˜ëŠ” 결과가 없습니다"
msgid "MilestoneCombobox|No milestone"
-msgstr ""
+msgstr "MilestoneCombobox|마ì¼ìŠ¤í†¤ ì—†ìŒ"
msgid "MilestoneCombobox|Project milestones"
-msgstr ""
+msgstr "MilestoneCombobox|프로ì íŠ¸ 마ì¼ìŠ¤í†¤"
msgid "MilestoneCombobox|Search Milestones"
-msgstr ""
+msgstr "MilestoneCombobox|마ì¼ìŠ¤í†¤ 검색"
msgid "MilestoneCombobox|Select milestone"
-msgstr ""
+msgstr "MilestoneCombobox|마ì¼ìŠ¤í†¤ ì„ íƒ"
msgid "MilestoneSidebar|Closed:"
msgstr ""
@@ -25808,6 +26143,9 @@ msgstr "%{percentage}%{percent} 완료"
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr "ìµœì†Œí•œì˜ ì•¡ì„¸ìŠ¤"
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -25880,6 +26218,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr "프로ì íŠ¸ 추가"
@@ -26066,6 +26407,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26134,7 +26478,7 @@ msgid "NamespaceStorageSize|You have reached the free storage limit of %{free_si
msgstr ""
msgid "NamespaceStorageSize|push to your repository, create pipelines, create issues or add comments. To reduce storage capacity, delete unused repositories, artifacts, wikis, issues, and pipelines."
-msgstr ""
+msgstr "ì €ìž¥ì†Œì— í‘¸ì‹œí•˜ê³ , 파ì´í”„ë¼ì¸ì„ 만들고, ì´ìŠˆë¥¼ ìƒì„±í•˜ê±°ë‚˜, ì˜ê²¬ì„ 추가합니다. 저장 ìš©ëŸ‰ì„ ì¤„ì´ë ¤ë©´ 사용하지 않는 리í¬ì§€í† ë¦¬, 아티팩트, Wiki, ì´ìŠˆ ë° íŒŒì´í”„ë¼ì¸ì„ 삭제합니다."
msgid "NamespaceStorage|%{name_with_link} namespace has approximately %{percent} (%{size}) namespace storage space remaining."
msgstr ""
@@ -26524,6 +26868,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr "접근 불가"
+
msgid "No active admin user found"
msgstr ""
@@ -26653,9 +27000,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr "표시할 ìž‘ì—…ì´ ì—†ìŠµë‹ˆë‹¤."
-
msgid "No label"
msgstr "ë¼ë²¨ ì—†ìŒ"
@@ -26683,9 +27027,6 @@ msgstr "ì¼ì¹˜í•˜ëŠ” 결과가 없습니다."
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26701,9 +27042,6 @@ msgstr "메시지가 기ë¡ë˜ì§€ 않았습니다."
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr "그런 ì´ë¦„ ë˜ëŠ” 설명ì´ìžˆëŠ” 다른 ë ˆì´ë¸”ì´ ì—†ìŠµë‹ˆë‹¤."
@@ -26814,7 +27152,7 @@ msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{stron
msgstr[0] ""
msgid "No wrap"
-msgstr ""
+msgstr "ëž© ì—†ìŒ"
msgid "No. of commits"
msgstr ""
@@ -26936,8 +27274,8 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
-msgstr "내부 메모는 작성ìž, ë‹´ë‹¹ìž ë° ë¦¬í¬í„° ì´ìƒì˜ ì—­í• ì„ ê°€ì§„ 구성ì›ë§Œ ë³¼ 수 있습니다."
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
+msgstr "내부 메모는 리í¬í„° ì´ìƒì˜ ì—­í• ì„ ê°€ì§„ 구성ì›ë§Œ ë³¼ 수 있습니다."
msgid "Notes|Last reply by %{name}"
msgstr "%{name}ì˜ ë§ˆì§€ë§‰ ì‘답"
@@ -27040,7 +27378,7 @@ msgid "NotificationEvent|New release"
msgstr "새 릴리스"
msgid "NotificationEvent|Push to merge request"
-msgstr ""
+msgstr "머지 ë¦¬í€˜ìŠ¤íŠ¸ì— í‘¸ì‹œ"
msgid "NotificationEvent|Reassign issue"
msgstr "ì´ìŠˆ 재지정"
@@ -27052,7 +27390,7 @@ msgid "NotificationEvent|Reopen issue"
msgstr "ì´ìŠˆ 다시 열기"
msgid "NotificationEvent|Reopen merge request"
-msgstr ""
+msgstr "머지 리퀘스트 다시 열기"
msgid "NotificationEvent|Successful pipeline"
msgstr "성공ì ì¸ 파ì´í”„ë¼ì¸"
@@ -27267,6 +27605,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr "ì´ íŒŒì¼ í˜•ì‹ì— 대한 미리보기가 없습니다."
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr "다ìŒì— ì˜í•´ íŠ¸ë¦¬ê±°ëœ íŒŒì´í”„ë¼ì¸ %{pipeline_link}"
@@ -27276,6 +27617,9 @@ msgstr "파ì´í”„ë¼ì¸ì´ 수정ë˜ì—ˆìœ¼ë©° #%{pipeline_id} ì´ í†µê³¼ë˜ì—ˆìŠ
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr "%{project_name} 프로ì íŠ¸ë¥¼ 내보낼 수 없습니다."
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27297,6 +27641,9 @@ msgstr "ì´ íŒŒì¼ì— 대한 diff는 너무 커서 í¬í•¨ë˜ì§€ 않았습니다.
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr "ë°œìƒí•œ 오류는 다ìŒê³¼ 같습니다."
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27390,9 +27737,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27417,9 +27761,6 @@ msgstr "10ì›”"
msgid "October"
msgstr "10ì›”"
-msgid "OfSearchInADropdown|Filter"
-msgstr "í•„í„°"
-
msgid "Off"
msgstr ""
@@ -27442,7 +27783,7 @@ msgid "OmniAuth"
msgstr ""
msgid "On"
-msgstr ""
+msgstr "켜ì§"
msgid "On %{end_date}, your trial will end and %{namespace_name} will be limited to %{free_user_limit} member"
msgid_plural "On %{end_date}, your trial will end and %{namespace_name} will be limited to %{free_user_limit} members"
@@ -27652,12 +27993,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27703,12 +28038,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr "OnDemandScans|ê³„ì† íŽ¸ì§‘"
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27730,12 +28059,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27778,15 +28101,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -27817,12 +28131,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -27841,9 +28149,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] "%dê°œì˜ ì¶”ê°€ ì•„ì´í…œ"
@@ -28016,9 +28321,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr "ìš´ì˜"
@@ -28386,12 +28688,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr "패키지 버전 삭제"
+
msgid "PackageRegistry|Delete selected"
msgstr "ì„ íƒí•œ 항목 ì‚­ì œ"
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr "모든 패키지 ìžì‚°ì„ 삭제하면 %{name}ì˜ ë²„ì „%{version}ì´ ì œê±°ë©ë‹ˆë‹¤. 확실합니까?"
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr "마지막 패키지 ìžì‚°ì„ 삭제하면 %{name}ì˜ ë²„ì „ %{version} ì´ ì œê±°ë©ë‹ˆë‹¤. 확실합니까?"
+
msgid "PackageRegistry|Duplicate packages"
msgstr "중복 패키지"
@@ -28437,6 +28748,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28508,7 +28825,7 @@ msgid "PackageRegistry|Package updated by commit %{link} on branch %{branch}, bu
msgstr ""
msgid "PackageRegistry|Permanently delete"
-msgstr ""
+msgstr "ì˜êµ¬ì ìœ¼ë¡œ ì‚­ì œ"
msgid "PackageRegistry|Permanently delete assets"
msgstr "ìžì‚°ì„ ì˜êµ¬ì ìœ¼ë¡œ ì‚­ì œ"
@@ -28582,6 +28899,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -28622,7 +28942,7 @@ msgid "PackageRegistry|You are about to delete %{filename}. This is a destructiv
msgstr ""
msgid "PackageRegistry|You are about to delete %{name}, are you sure?"
-msgstr ""
+msgstr "%{name}ì„ ì‚­ì œí•˜ë ¤ê³  합니다, ì •ë§ìž…니까?"
msgid "PackageRegistry|You are about to delete 1 asset. This operation is irreversible."
msgid_plural "PackageRegistry|You are about to delete %d assets. This operation is irreversible."
@@ -28964,12 +29284,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr "비활성화 전 비활성 기간입니다."
-
msgid "Permalink"
msgstr ""
@@ -29018,7 +29332,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29237,19 +29551,25 @@ msgstr "활성"
msgid "PipelineSchedules|All"
msgstr "모ë‘"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr "ì´ íŒŒì´í”„ë¼ì¸ ì¼ì •ì„ 삭제하시겠습니까?"
+
msgid "PipelineSchedules|Delete pipeline schedule"
-msgstr ""
+msgstr "파ì´í”„ë¼ì¸ ì¼ì • ì‚­ì œ"
msgid "PipelineSchedules|Description"
-msgstr ""
+msgstr "설명"
msgid "PipelineSchedules|Edit pipeline schedule"
-msgstr ""
+msgstr "파ì´í”„ë¼ì¸ ì¼ì • 편집"
msgid "PipelineSchedules|Inactive"
msgstr "비활성"
msgid "PipelineSchedules|Last Pipeline"
+msgstr "마지막 파ì´í”„ë¼ì¸"
+
+msgid "PipelineSchedules|New schedule"
msgstr ""
msgid "PipelineSchedules|Next Run"
@@ -29262,24 +29582,36 @@ msgid "PipelineSchedules|Only the owner of a pipeline schedule can make changes
msgstr ""
msgid "PipelineSchedules|Owner"
+msgstr "소유ìž"
+
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
msgstr ""
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "ì´ íŒŒì´í”„ë¼ì¸ì— 대한 간단한 설명 제공"
msgid "PipelineSchedules|Run pipeline schedule"
+msgstr "파ì´í”„ë¼ì¸ ì¼ì • 실행"
+
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
msgstr ""
msgid "PipelineSchedules|Take ownership"
msgstr "소유권 가져 오기"
msgid "PipelineSchedules|Take ownership of pipeline schedule"
-msgstr ""
+msgstr "파ì´í”„ë¼ì¸ ì¼ì •ì— 대한 소유권 가져오기"
msgid "PipelineSchedules|Target"
msgstr "대ìƒ"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr "파ì´í”„ë¼ì¸ ì¼ì •ì„ 삭제하는 ë™ì•ˆ 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
+msgstr "파ì´í”„ë¼ì¸ ì¼ì •ì„ 가져오는 ë™ì•ˆ 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤."
+
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
msgid "PipelineSchedules|Variables"
@@ -29640,7 +29972,7 @@ msgid "Pipelines|View merged YAML"
msgstr "ë¨¸ì§€ëœ YAML 보기"
msgid "Pipelines|Visualize"
-msgstr ""
+msgstr "ì‹œê°í™”"
msgid "Pipelines|We'll guide you through a simple pipeline set-up."
msgstr ""
@@ -29991,7 +30323,7 @@ msgid "Please fill in a title for your topic."
msgstr ""
msgid "Please fill out this field."
-msgstr ""
+msgstr "ì´ í•­ëª©ì„ ì±„ì›Œì£¼ì‹­ì‹œì˜¤."
msgid "Please follow the %{link_start}Let's Encrypt troubleshooting instructions%{link_end} to re-obtain your Let's Encrypt certificate."
msgstr ""
@@ -30041,9 +30373,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30152,6 +30481,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr "(ì„ íƒ ì‚¬í•­)"
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr "파ì´í”„ë¼ì¸ì˜ 마지막 실행 %{timeAgo}"
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr "사전 스캔 확ì¸"
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr "파ì´í”„ë¼ì¸ì—ì„œ %{timeAgo} 시작ë¨"
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr "ì „ì²´ ìŠ¤ìº”ì„ ì‹¤í–‰í•˜ê¸° ì „ì— êµ¬ì„±ì„ í…ŒìŠ¤íŠ¸í•˜ê³  ìž ìž¬ì  ì˜¤ë¥˜ë¥¼ 확ì¸í•˜ì‹­ì‹œì˜¤."
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr "구성 확ì¸"
+
+msgid "PreScanVerification|View results"
+msgstr "결과 보기"
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr "환경설정"
@@ -30159,7 +30551,7 @@ msgid "Preferences saved."
msgstr "ì„¤ì •ì„ ì €ìž¥í–ˆìŠµë‹ˆë‹¤."
msgid "Preferences|Automatically add new list items"
-msgstr ""
+msgstr "ìžë™ìœ¼ë¡œ 새 ëª©ë¡ í•­ëª© 추가"
msgid "Preferences|Behavior"
msgstr ""
@@ -30273,7 +30665,7 @@ msgid "Preferences|Use relative times"
msgstr ""
msgid "Preferences|When you type in a description or comment box, pressing %{kbdOpen}Enter%{kbdClose} in a list adds a new item below."
-msgstr ""
+msgstr "설명ì´ë‚˜ 설명 ìƒìžì— 입력할 ë•Œ 목ë¡ì—ì„œ %{kbdOpen}Enter%{kbdClose} ì„ ëˆ„ë¥´ë©´ ì•„ëž˜ì— ìƒˆ í•­ëª©ì´ ì¶”ê°€ë©ë‹ˆë‹¤."
msgid "Preferences|When you type in a description or comment box, selected text is surrounded by the corresponding character after typing one of the following characters: %{supported_characters}."
msgstr ""
@@ -30293,6 +30685,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30386,12 +30781,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -30968,6 +31369,9 @@ msgstr "프로ì íŠ¸ ì´ë¦„"
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -30980,6 +31384,9 @@ msgstr "프로ì íŠ¸ 보안 ìƒíƒœ"
msgid "Project security status help page"
msgstr "프로ì íŠ¸ 보안 ìƒíƒœ ë„ì›€ë§ íŽ˜ì´ì§€"
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr "프로ì íŠ¸ 슬러그"
@@ -31262,12 +31669,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31280,12 +31693,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr "뱃지"
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31307,6 +31726,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr "git 태그를 릴리스 ì •ë³´, 릴리스 ì¦ê±° ë° ìžì‚°ê³¼ 결합하여 릴리스를 만듭니다."
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr "프로ì íŠ¸ 리소스를 설정하고 ìƒíƒœë¥¼ 모니터ë§í•©ë‹ˆë‹¤."
@@ -31406,6 +31828,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31473,7 +31898,7 @@ msgid "ProjectSettings|Note: The container registry is always visible when a pro
msgstr ""
msgid "ProjectSettings|Only commits that include a %{code_block_start}Signed-off-by:%{code_block_end} element can be pushed to this repository."
-msgstr ""
+msgstr "%{code_block_start}Signed-off-by:%{code_block_end} 요소를 í¬í•¨í•˜ëŠ” 커밋만 ì´ ì €ìž¥ì†Œë¡œ 푸시할 수 있습니다."
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr "ì´ ì €ìž¥ì†Œì—는 ì„œëª…ëœ ì»¤ë°‹ë§Œ 푸쉬할 수 있습니다."
@@ -31544,6 +31969,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31574,6 +32002,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31625,6 +32056,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32264,6 +32698,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32300,15 +32737,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr "ë” ì•Œì•„ë³´ê¸°."
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32324,12 +32773,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32607,7 +33065,7 @@ msgid "PushRules|Reject any files likely to contain secrets. %{secret_files_link
msgstr ""
msgid "PushRules|Reject commits that aren't DCO certified"
-msgstr ""
+msgstr "DCO ì¸ì¦ì„ 받지 ì•Šì€ ì»¤ë°‹ 거부"
msgid "PushRules|Reject expression in commit messages"
msgstr ""
@@ -32639,6 +33097,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32771,12 +33232,6 @@ msgstr "ë” ì½ê¸°"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -32870,9 +33325,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33034,6 +33486,9 @@ msgstr[0] "릴리스"
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr "릴리스 %{deletedRelease} ì´ ì„±ê³µì ìœ¼ë¡œ ì‚­ì œë˜ì—ˆìŠµë‹ˆë‹¤."
+msgid "Release already exists"
+msgstr "릴리스가 ì´ë¯¸ 존재합니다."
+
msgid "Release assets"
msgstr ""
@@ -33043,6 +33498,9 @@ msgstr ""
msgid "Release date"
msgstr "릴리스 날짜"
+msgid "Release does not exist"
+msgstr "릴리스가 존재하지 않습니다"
+
msgid "Release does not have the same project as the milestone"
msgstr "ë¦´ë¦¬ìŠ¤ì— ë§ˆì¼ìŠ¤í†¤ê³¼ ë™ì¼í•œ 프로ì íŠ¸ê°€ 없습니다."
@@ -33230,7 +33688,7 @@ msgid "Remove link"
msgstr ""
msgid "Remove list"
-msgstr ""
+msgstr "ëª©ë¡ ì œê±°"
msgid "Remove log"
msgstr ""
@@ -33499,6 +33957,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr "%{reporter}ì— ì˜í•´ ë³´ê³ ë¨"
+msgid "Reporter"
+msgstr "리í¬í„°"
+
msgid "Reporting"
msgstr "ë³´ê³ "
@@ -33512,10 +33973,6 @@ msgid "Reports|%{recentlyFailed} out of %{failed} failed tests has failed more t
msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days"
msgstr[0] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33544,18 +34001,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr "실행 시간"
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33564,12 +34015,6 @@ msgid "Reports|Failed %{count} time in %{base_branch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 days"
msgstr[0] ""
-msgid "Reports|Failure"
-msgstr "실패"
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33612,21 +34057,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr "시스템 출력"
-
msgid "Reports|Test summary"
msgstr "테스트 요약"
-msgid "Reports|Test summary failed loading results"
-msgstr "테스트 요약 로드 실패"
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr "테스트 요약 ê²°ê³¼ 분ì„중"
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33642,9 +34078,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr "Reports|메트릭 보고서"
-msgid "Reports|no changed test results"
-msgstr "ë³€ê²½ëœ í…ŒìŠ¤íŠ¸ ê²°ê³¼ ì—†ìŒ"
-
msgid "Repositories"
msgstr ""
@@ -33801,7 +34234,7 @@ msgid "Repository mirroring configuration"
msgstr ""
msgid "Repository mirroring has been paused due to too many failed attempts. It can be resumed by a project maintainer or owner."
-msgstr ""
+msgstr "너무 ë§Žì€ ì‹œë„ ì‹¤íŒ¨ë¡œ ì¸í•´ 리í¬ì§€í† ë¦¬ 미러ë§ì´ ì¼ì‹œ 중지ë˜ì—ˆìŠµë‹ˆë‹¤. 프로ì íŠ¸ ê´€ë¦¬ìž ë˜ëŠ” 소유ìžê°€ 재개할 수 있습니다."
msgid "Repository must contain at least 1 file."
msgstr ""
@@ -34012,6 +34445,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr "리소스 ë§í¬ 추가ë¨"
+
msgid "Response"
msgstr ""
@@ -34239,6 +34675,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr "정리 실행"
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34276,6 +34715,9 @@ msgid "Runners|%d selected runner deleted"
msgid_plural "Runners|%d selected runners deleted"
msgstr[0] "%d ê°œì˜ ì„ íƒëœ 러너 ì‚­ì œë¨"
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr "%{link_start}ì´ ëŸ¬ë„ˆ%{link_end} ì€ ëª¨ë“  그룹 ë° í”„ë¡œì íŠ¸ì—ì„œ 사용할 수 있습니다."
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34302,8 +34744,8 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
-msgstr "ì´ìŠˆì— ë‹¹ì‹ ì˜ ì˜ê²¬ 추가"
+msgid "Runners|Administrator"
+msgstr "관리ìž"
msgid "Runners|All"
msgstr ""
@@ -34433,7 +34875,7 @@ msgid "Runners|Group"
msgstr ""
msgid "Runners|How do runners pick up jobs?"
-msgstr ""
+msgstr "러너는 ìž‘ì—…ì„ ì–´ë–»ê²Œ ì„ íƒí•˜ë‚˜ìš”?"
msgid "Runners|How do we upgrade GitLab runner?"
msgstr "GitLab 러너를 어떻게 업그레ì´ë“œí•©ë‹ˆê¹Œ?"
@@ -34510,6 +34952,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr "소유ìž"
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34548,7 +34993,7 @@ msgid "Runners|Register an instance runner"
msgstr ""
msgid "Runners|Register as many runners as you want. You can register runners as separate users, on separate servers, and on your local machine."
-msgstr ""
+msgstr "ì›í•˜ëŠ” ë§Œí¼ ëŸ¬ë„ˆë¥¼ 등ë¡í•˜ì„¸ìš”. 러너를 별ë„ì˜ ì‚¬ìš©ìž, 별ë„ì˜ ì„œë²„ ë° ë¡œì»¬ ì»´í“¨í„°ì— ë“±ë¡í•  수 있습니다."
msgid "Runners|Registration token"
msgstr ""
@@ -34632,14 +35077,20 @@ msgid "Runners|Runners"
msgstr ""
msgid "Runners|Runners are either:"
-msgstr ""
+msgstr "러너는 ë‹¤ìŒ ì¤‘ 하나입니다."
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr "Runners|러너는 CI/CD ìž‘ì—…ì„ ì‹¤í–‰í•˜ëŠ” ì—ì´ì „트입니다. %{linkStart}설치 ë° ë“±ë¡ ë°©ë²•%{linkEnd} ì„ ë”°ë¼ ëŸ¬ë„ˆë¥¼ 설정하십시오."
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr "러너는 CI/CD ìž‘ì—…ì„ ì‹¤í–‰í•˜ëŠ” ì—ì´ì „트입니다. 새 러너를 등ë¡í•˜ë ¤ë©´ 관리ìžì—게 문ì˜í•˜ì„¸ìš”."
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr "ëª¨ë‘ ì„ íƒ"
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34647,7 +35098,7 @@ msgid "Runners|Select your preferred option here. In the next step, you can choo
msgstr ""
msgid "Runners|Show only inherited"
-msgstr ""
+msgstr "ìƒì†ëœ 항목만 표시"
msgid "Runners|Show runner installation and registration instructions"
msgstr ""
@@ -34680,7 +35131,7 @@ msgid "Runners|Tags"
msgstr ""
msgid "Runners|Tags control which type of jobs a runner can handle. By tagging a runner, you make sure shared runners only handle the jobs they are equipped to run."
-msgstr ""
+msgstr "태그는 러너가 처리할 수 있는 ìž‘ì—… ìœ í˜•ì„ ì œì–´í•©ë‹ˆë‹¤. ëŸ¬ë„ˆì— íƒœê·¸ë¥¼ 지정하면 공유 러너가 실행할 수 있는 작업만 처리하ë„ë¡ í•  수 있습니다."
msgid "Runners|Take me there!"
msgstr ""
@@ -34688,6 +35139,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr "러너가 등ë¡ëœ 프로ì íŠ¸, 그룹 ë˜ëŠ” ì¸ìŠ¤í„´ìŠ¤. ì¸ìŠ¤í„´ìŠ¤ 실행기는 í•­ìƒ ê´€ë¦¬ìžê°€ 소유합니다."
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr "러너는 ì˜êµ¬ì ìœ¼ë¡œ ì‚­ì œë˜ë©° ì¸ìŠ¤í„´ìŠ¤ì˜ 프로ì íŠ¸ ë˜ëŠ” 그룹ì—ì„œ ë” ì´ìƒ 사용할 수 없습니다. ê³„ì† ì§„í–‰í•˜ì‹œê² ìŠµë‹ˆê¹Œ?"
@@ -34722,6 +35176,9 @@ msgstr "Runners|등ë¡í•˜ë ¤ë©´ %{link_start}ê·¸ë£¹ì˜ ëŸ¬ë„ˆ 페ì´ì§€%{link_en
msgid "Runners|Token expiry"
msgstr "í† í° ë§Œë£Œ"
+msgid "Runners|Unselect all"
+msgstr "ëª¨ë‘ ì„ íƒ ì·¨ì†Œ"
+
msgid "Runners|Up to date"
msgstr ""
@@ -34761,12 +35218,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr "ì´ íŽ˜ì´ì§€ì—ì„œ 러너를 쉽고 효율ì ìœ¼ë¡œ 관리할 수 있기를 ë°”ëžë‹ˆë‹¤. 우리가 하고 있는 ê²ƒì— ëŒ€í•´ ì˜ê²¬ì„ 주세요!"
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr "우리는 ì¼ë¶€ 변경 ì‚¬í•­ì„ ì ìš©í–ˆìœ¼ë©° ì—¬ëŸ¬ë¶„ì˜ ì˜ê²¬ì„ 듣고 싶습니다."
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -34821,17 +35272,23 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
-msgstr "\"승ì¸\"ì„ ì„ íƒí•˜ë©´ GitLab 계정 \"%{username}\"(%{email})ì˜ ì†Œìœ ê¶Œì´ ë³¸ì¸ì´ ì†í•œ ì¡°ì§ìœ¼ë¡œ ì´ì „ë©ë‹ˆë‹¤."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
+msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr "GitLabì— ë¡œê·¸ì¸í•˜ì—¬ ì¡°ì§ì˜ ê³„ì •ì— ì—°ê²°"
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
-msgstr "\"%{group_path}\" ê·¸ë£¹ì„ ì‚¬ìš©í•˜ë©´ Single Sign-On 계정으로 로그ì¸í•  수 있습니다."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
-msgstr "\"%{group_name}\"ì— ì•¡ì„¸ìŠ¤í•˜ë ¤ë©´ 외부 ë¡œê·¸ì¸ íŽ˜ì´ì§€ë¥¼ 통해 Single Sign-On 계정으로 로그ì¸í•´ì•¼ 합니다."
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr ""
+
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
+msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "ì¡°ì§ì˜ SSOê°€ GitLab ê³„ì •ì— ì—°ê²°ë˜ì—ˆìŠµë‹ˆë‹¤."
@@ -34938,12 +35395,12 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
-msgstr "ScanExecutionPolicy|%{ifLabelStart}ì´ë©´%{ifLabelEnd} %{rules} %{scopes} %{branches}ì— ëŒ€í•œ ìž‘ì—…"
-
msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
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"
msgstr "%{thenLabelStart}다ìŒ%{thenLabelEnd} 실행하려면 %{scan} 스캔 í•„ìš”"
@@ -34962,9 +35419,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr "ì—ì´ì „트 ì„ íƒ"
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr "네임스페ì´ìŠ¤ ì„ íƒ"
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr "스ìºë„ˆ 프로필 ì„ íƒ"
@@ -34974,9 +35437,15 @@ msgstr "사ì´íŠ¸ 프로필 ì„ íƒ"
msgid "ScanExecutionPolicy|Site profile"
msgstr "사ì´íŠ¸ 프로필"
+msgid "ScanExecutionPolicy|agent"
+msgstr "ì—ì´ì „트"
+
msgid "ScanExecutionPolicy|branch"
msgstr "ScanExecutionPolicy|브랜치"
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr "네임스페ì´ìŠ¤ ë‚´"
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35089,7 +35558,7 @@ msgid "Search authors"
msgstr "ìž‘ì„±ìž ê²€ìƒ‰"
msgid "Search branch"
-msgstr ""
+msgstr "브랜치 검색"
msgid "Search branches"
msgstr "브랜치 검색"
@@ -35127,9 +35596,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35307,7 +35773,7 @@ msgid "Seats owed"
msgstr ""
msgid "Seats usage data as of %{last_enqueue_time} (Updated daily)"
-msgstr ""
+msgstr "%{last_enqueue_time}ì˜ ì¢Œì„ ì‚¬ìš© ë°ì´í„°(ë§¤ì¼ ì—…ë°ì´íŠ¸ë¨)"
msgid "Seats usage data is updated every day at 12:00pm UTC"
msgstr ""
@@ -35475,13 +35941,13 @@ msgid "SecurityConfiguration|Manage profiles for use by DAST scans."
msgstr ""
msgid "SecurityConfiguration|More scan types, including DAST, Dependency Scanning, Fuzzing, and Licence Compliance"
-msgstr ""
+msgstr "DAST, 종ì†ì„± 검색, í¼ì§• ë° ë¼ì´ì„ ìŠ¤ ì¸ì¦ì„ í¬í•¨í•œ ë” ë§Žì€ ê²€ìƒ‰ 유형"
msgid "SecurityConfiguration|Not enabled"
msgstr ""
msgid "SecurityConfiguration|Once you've enabled a scan for the default branch, any subsequent feature branch you create will include the scan. An enabled scanner will not be reflected as such until the pipeline has been successfully executed and it has generated valid artifacts."
-msgstr ""
+msgstr "ì¼ë‹¨ 기본 ë¸Œëžœì¹˜ì— ëŒ€í•œ ìŠ¤ìº”ì„ í™œì„±í™”í•˜ë©´ ìƒì„±í•˜ëŠ” 모든 í›„ì† ê¸°ëŠ¥ë¸Œëžœì¹˜ì— ìŠ¤ìº”ì´ í¬í•¨ë©ë‹ˆë‹¤. í™œì„±í™”ëœ ìŠ¤ìºë„ˆëŠ” 파ì´í”„ë¼ì¸ì´ 성공ì ìœ¼ë¡œ 실행ë˜ê³  유효한 아티팩트가 ìƒì„±ë  때까지 그대로 ë°˜ì˜ë˜ì§€ 않습니다."
msgid "SecurityConfiguration|Quickly enable all continuous testing and compliance tools by enabling %{linkStart}Auto DevOps%{linkEnd}"
msgstr ""
@@ -35525,10 +35991,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35648,6 +36117,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35750,10 +36222,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -35843,8 +36315,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, and Container scanning."
-msgstr "검사 실행 ì •ì±…ì„ ì‚¬ìš©í•˜ì—¬ 특정 ì‹œê°„ì— íŠ¹ì • ë¸Œëžœì¹˜ì— ëŒ€í•œ 보안 검사를 시행하는 ê·œì¹™ì„ ë§Œë“­ë‹ˆë‹¤. 지ì›ë˜ëŠ” ìœ í˜•ì€ SAST, DAST, 비밀 검출 ë° ì»¨í…Œì´ë„ˆ 스ìºë‹ìž…니다."
+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 ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
msgstr ""
@@ -35861,6 +36333,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -35879,12 +36354,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -35906,6 +36390,9 @@ msgstr "프로ì íŠ¸ 추가"
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr "취약ì ì´ 없는 경우는 드물지만 ë°œìƒí•  수 있습니다. ì„¤ì •ì„ í™•ì¸í•˜ì—¬ 대시보드를 올바르게 설정했는지 확ì¸í•˜ì„¸ìš”."
@@ -36035,6 +36522,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36092,6 +36582,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36117,7 +36610,7 @@ msgid "SecurityReports|Status"
msgstr ""
msgid "SecurityReports|Still detected"
-msgstr ""
+msgstr "ì•„ì§ ê°ì§€ë¨"
msgid "SecurityReports|Submit vulnerability"
msgstr ""
@@ -36209,9 +36702,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr "보안 êµìœ¡ì„ 활성화하여 취약ì ì„ 수정하는 ë°©ë²•ì„ ë°°ìš°ì‹­ì‹œì˜¤. íƒì§€ëœ 취약ì ê³¼ 관련하여 ì„ íƒëœ êµìœ¡ 제공ìžì˜ 보안 êµìœ¡ì„ 봅니다."
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr "보안 êµìœ¡ìœ¼ë¡œ í•´ê²°"
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36224,6 +36723,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36287,9 +36789,6 @@ msgstr "저장소 템플릿 ì„ íƒ"
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr "시간대 ì„ íƒ"
-
msgid "Select all"
msgstr "ëª¨ë‘ ì„ íƒ"
@@ -36315,7 +36814,7 @@ msgid "Select branches"
msgstr ""
msgid "Select default branch"
-msgstr ""
+msgstr "기본 브랜치 ì„ íƒ"
msgid "Select due date"
msgstr ""
@@ -36363,7 +36862,7 @@ msgid "Select projects"
msgstr "프로ì íŠ¸ ì„ íƒ"
msgid "Select report"
-msgstr ""
+msgstr "ë³´ê³ ì„œ ì„ íƒ"
msgid "Select reviewer(s)"
msgstr "리뷰어 ì„ íƒí•˜ê¸°"
@@ -36428,10 +36927,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36443,29 +36942,29 @@ msgstr "셀프 ëª¨ë‹ˆí„°ë§ í”„ë¡œì íŠ¸ê°€ 성공ì ìœ¼ë¡œ ì‚­ì œë˜ì—ˆìŠµë‹ˆë‹
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr "셀프 ëª¨ë‹ˆí„°ë§ í”„ë¡œì íŠ¸ê°€ ì‚­ì œë˜ì§€ 않았습니다. 오류 메시지가 있는지 로그를 확ì¸í•˜ì‹­ì‹œì˜¤."
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
-msgstr "셀프 ëª¨ë‹ˆí„°ë§ í”„ë¡œì íŠ¸ê°€ 성공ì ìœ¼ë¡œ ì‚­ì œë˜ì—ˆìŠµë‹ˆë‹¤."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
+msgstr ""
msgid "Send"
msgstr ""
@@ -36683,9 +37182,6 @@ msgstr "초안 ìƒíƒœë¡œ 설정"
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -36834,9 +37330,6 @@ msgstr "설정"
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37090,10 +37583,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37147,7 +37637,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37162,8 +37652,8 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
-msgstr "Single Sign-On으로 로그ì¸"
+msgid "Sign in with single sign-on"
+msgstr ""
msgid "Sign in with smart card"
msgstr ""
@@ -37202,7 +37692,7 @@ msgid "Sign-in restrictions"
msgstr "ë¡œê·¸ì¸ ì œí•œ"
msgid "Sign-in text"
-msgstr ""
+msgstr "ë¡œê·¸ì¸ í…스트"
msgid "Sign-in using %{provider} auth failed"
msgstr ""
@@ -37285,9 +37775,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37478,7 +37965,7 @@ msgid "Snowplow"
msgstr ""
msgid "Soft wrap"
-msgstr ""
+msgstr "소프트 랩"
msgid "Solid"
msgstr ""
@@ -37510,6 +37997,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37621,9 +38111,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38197,9 +38684,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38212,9 +38696,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38236,9 +38717,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -38758,9 +39236,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr "SuggestedReviewers|GitLabì˜ ë¨¸ì‹  ëŸ¬ë‹ ë„구를 기반으로 검토ìžì— 대한 제안 ì‚¬í•­ì„ ê°€ì ¸ì˜µë‹ˆë‹¤."
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr "SuggestedReviewers|ì œì•ˆëœ ê²€í† ìž"
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr "SuggestedReviewers|오른쪽 사ì´ë“œë°”ì˜ Reviewer ì„¹ì…˜ì— ì œì•ˆ ì‚¬í•­ì´ ë‚˜íƒ€ë‚©ë‹ˆë‹¤."
@@ -39017,6 +39501,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "스위치 브랜치/태그"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr "GitLab Next로 전환"
@@ -39093,7 +39580,7 @@ msgid "System metrics (Kubernetes)"
msgstr ""
msgid "System output"
-msgstr ""
+msgstr "시스템 출력"
msgid "System started"
msgstr "시스템 시작ë¨"
@@ -39107,6 +39594,9 @@ msgstr "목차"
msgid "Tag"
msgstr "태그"
+msgid "Tag does not exist"
+msgstr "태그가 존재하지 않습니다"
+
msgid "Tag list:"
msgstr "태그 목ë¡:"
@@ -39191,6 +39681,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr "새 태그로 릴리스를 ìƒì„±í•˜ì‹œê² ìŠµë‹ˆê¹Œ? %{link_start}새 릴리스 페ì´ì§€%{link_end}ì—ì„œ í•  수 있습니다."
+
msgid "TagsPage|Edit release"
msgstr "TagsPage|릴리즈 수정"
@@ -39212,15 +39705,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr "릴리스 노트"
-
msgid "TagsPage|Repository has no tags yet."
msgstr "ì €ìž¥ì†Œì— ì•„ì§ íƒœê·¸ê°€ 없습니다."
@@ -39242,9 +39729,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr "git tag ëª…ë ¹ì„ ì‚¬ìš©í•˜ì—¬ 새 태그를 추가하십시오:"
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "릴리스 노트를 작성하거나 여기로 파ì¼ì„ ëŒì–´ë‹¤ 놓으십시오…"
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39263,6 +39747,9 @@ msgstr "보호ë¨"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr "ëŒ€ìƒ ë¸Œëžœì¹˜"
@@ -39374,14 +39861,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39399,12 +39878,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39492,12 +39965,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -39708,7 +40175,7 @@ msgid "That's OK, I don't want to renew"
msgstr "괜찮습니다, 갱신하지 않겠습니다."
msgid "That's it, well done!"
-msgstr ""
+msgstr "잘했습니다!"
msgid "The %{link_start}true-up model%{link_end} allows having more users, and additional users will incur a retroactive charge on renewal."
msgstr ""
@@ -39947,6 +40414,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr "%{project_status}ì´ë¯€ë¡œ 가져오기를 취소할 수 없습니다."
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "%{timeout} ì´í›„ 가져오기 ì‹œê°„ì´ ì´ˆê³¼ë˜ì—ˆìŠµë‹ˆë‹¤. 저장소가 ëŠë¦° 경우 복제/푸시 ì¡°í•©ì„ ì‚¬ìš©í•©ì‹œì˜¤."
@@ -40142,9 +40612,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40175,7 +40642,7 @@ msgstr "ì›ë³¸ 주제는 주제가 아닙니다."
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40232,9 +40699,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr "현재 미러ë§ëœ 저장소가 없습니다."
@@ -40586,9 +41050,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40622,6 +41083,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -40788,25 +41252,22 @@ msgid "This epic already has the maximum number of child epics."
msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
-msgstr ""
-
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
+msgstr "ì´ ì—í”½ì€ ì¶”ê°€í•  수 없습니다. ì—픽 ìžì²´ì— 추가할 수 없습니다."
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
-msgstr ""
+msgstr "ì´ ì—í”½ì€ ì¶”ê°€í•  수 없습니다. ì—í”½ì€ ìƒìœ„ ì—픽과 ë™ì¼í•œ 그룹 ë˜ëŠ” 하위 ê·¸ë£¹ì— ì†í•´ì•¼ 합니다."
msgid "This epic cannot be added. It is already an ancestor of the parent epic."
-msgstr ""
+msgstr "ì´ ì—í”½ì€ ì¶”ê°€í•  수 없습니다. ì´ë¯¸ 부모 ì—í”½ì˜ ì¡°ìƒìž…니다."
msgid "This epic cannot be added. It is already assigned to the parent epic."
-msgstr ""
+msgstr "ì´ ì—í”½ì€ ì¶”ê°€í•  수 없습니다. ì´ë¯¸ ìƒìœ„ ì—í”½ì— í• ë‹¹ë˜ì–´ 있습니다."
msgid "This epic cannot be added. One or more epics would exceed the maximum depth (%{max_depth}) from its most distant ancestor."
-msgstr ""
+msgstr "ì´ ì—í”½ì€ ì¶”ê°€í•  수 없습니다. 하나 ì´ìƒì˜ ì—í”½ì´ ê°€ìž¥ 먼 ì¡°ìƒì˜ 최대 깊ì´(%{max_depth})를 초과합니다."
msgid "This epic cannot be added. You don't have access to perform this action."
-msgstr ""
+msgstr "ì´ ì—í”½ì€ ì¶”ê°€í•  수 없습니다. ì´ ìž‘ì—…ì„ ìˆ˜í–‰í•  수 있는 액세스 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤."
msgid "This epic does not exist or you don't have sufficient permission."
msgstr ""
@@ -40853,6 +41314,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr "ì´ ê·¸ë£¹ì—는 ì•„ì§ í”„ë¡œì íŠ¸ê°€ 없습니다."
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -40920,7 +41384,7 @@ msgid "This issue is confidential and should only be visible to team members wit
msgstr "ì´ ì´ìŠˆëŠ” 비공개ì´ë©°, ì ì–´ë„ 리í¬í„° ì´ìƒì˜ ê¶Œí•œì´ ìžˆëŠ” 팀 구성ì›ë“¤ì—게만 보여집니다."
msgid "This issue is currently blocked by the following issues:"
-msgstr ""
+msgstr "ì´ ì´ìŠˆëŠ” 현재 ë‹¤ìŒ ë¬¸ì œë¡œ ì¸í•´ 차단ë©ë‹ˆë‹¤:"
msgid "This issue is hidden because its author has been banned"
msgstr "작성ìžê°€ 차단ë˜ì—ˆê¸° ë•Œë¬¸ì— ì´ ì´ìŠˆëŠ” 숨겨졌습니다."
@@ -41069,15 +41533,18 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr "ì´ ë„¤ìž„ìŠ¤íŽ˜ì´ìŠ¤ëŠ” ì´ë¯¸ 사용 중입니다. 다른 ê²ƒì„ ì„ íƒí•˜ì‹­ì‹œì˜¤."
+
msgid "This only applies to repository indexing operations."
msgstr ""
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
+msgstr ""
+
msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr "여러 프로ì íŠ¸ì—ì„œ 정보를 ì½ì„ 수 없으므로 ì´ íŽ˜ì´ì§€ë¥¼ 사용할 수 없습니다."
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
-msgstr ""
-
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
msgstr ""
@@ -41148,7 +41615,7 @@ msgid "This project will be deleted on %{date} since its parent group '%{parent_
msgstr ""
msgid "This project's pipeline configuration is located outside this repository"
-msgstr ""
+msgstr "ì´ í”„ë¡œì íŠ¸ì˜ 파ì´í”„ë¼ì¸ ì„¤ì •ì´ ì´ ì €ìž¥ì†Œ ì™¸ë¶€ì— ìžˆìŠµë‹ˆë‹¤."
msgid "This release was created with a date in the past. Evidence collection at the moment of the release is unavailable."
msgstr ""
@@ -41204,9 +41671,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr "ì´ ì‚¬ìš©ìžëŠ” ì‹ ì›ì´ 없습니다."
@@ -41225,6 +41689,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41238,7 +41705,7 @@ msgid "This will remove the fork relationship between this project and other pro
msgstr ""
msgid "Thread options"
-msgstr ""
+msgstr "스레드 옵션"
msgid "Thread to reply to cannot be found"
msgstr ""
@@ -41555,7 +42022,7 @@ msgid "To"
msgstr ""
msgid "To %{link_to_help} of your domain, add the above key to a TXT record within your DNS configuration."
-msgstr ""
+msgstr "ë„ë©”ì¸ì˜ %{link_to_help} ì— ìœ„ì˜ í‚¤ë¥¼ DNS 설정 ë‚´ì˜ TXT ë ˆì½”ë“œì— ì¶”ê°€í•˜ì‹­ì‹œì˜¤."
msgid "To Do"
msgstr "í•  ì¼ ëª©ë¡"
@@ -41593,9 +42060,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41618,7 +42082,7 @@ msgid "To define internal users, first enable new users set to external"
msgstr ""
msgid "To edit the pipeline configuration, you must go to the project or external site that hosts the file."
-msgstr ""
+msgstr "파ì´í”„ë¼ì¸ êµ¬ì„±ì„ íŽ¸ì§‘í•˜ë ¤ë©´ 파ì¼ì„ 호스팅하는 프로ì íŠ¸ ë˜ëŠ” 외부 사ì´íŠ¸ë¡œ ì´ë™í•´ì•¼ 합니다."
msgid "To enable Registration Features, first enable Service Ping."
msgstr ""
@@ -41701,6 +42165,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -41767,9 +42234,33 @@ msgstr "오늘"
msgid "Todos count"
msgstr "í•  ì¼ì˜ìˆ˜"
+msgid "Todos|Added"
+msgstr "추가ë¨"
+
+msgid "Todos|Alert"
+msgstr "경고"
+
+msgid "Todos|Any Action"
+msgstr "모든 작업"
+
+msgid "Todos|Any Type"
+msgstr "모든 유형"
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr "할당ë¨"
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr "ë””ìžì¸"
+
+msgid "Todos|Epic"
+msgstr "ì—픽"
+
msgid "Todos|Filter by author"
msgstr "작성ìžë¡œ í•„í„°ë§"
@@ -41791,18 +42282,39 @@ msgstr "ë‹¹ì‹ ì€ \"í• ì¼ ëª©ë¡ íŒŒê´´ìž\"ë¡œ 칭하겠습니다."
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr "비어 있는 í• ì¼ ë¦¬ìŠ¤íŠ¸ê°€ 아름답지 않나요?"
+msgid "Todos|Issue"
+msgstr "ì´ìŠˆ"
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr "ëª¨ë‘ ì™„ë£Œë¡œ 표시"
+msgid "Todos|Mentioned"
+msgstr "언급함"
+
+msgid "Todos|Merge request"
+msgstr "머지 리퀘스트"
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr "í•  ì¼ ëª©ë¡ì— ì•„ë¬´ê²ƒë„ ì—†ìŠµë‹ˆë‹¤. 잘 하셨어요!"
msgid "Todos|Nothing left to do. High five!"
msgstr "ë” ì´ìƒ í•  ì¼ì´ 없습니다. í•˜ì´ íŒŒì´ë¸Œ!"
+msgid "Todos|Pipelines"
+msgstr "파ì´í”„ë¼ì¸"
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr "검토 요청"
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr "ëª¨ë‘ ì™„ë£Œë¡œ 표시한 ê²ƒì„ ì·¨ì†Œ"
@@ -41815,6 +42327,24 @@ msgstr "ëª¨ë‘ ì™„ë£Œí•˜ì˜€ìŠµë‹ˆë‹¤!"
msgid "Todos|Your To-Do List shows what to work on next"
msgstr "ë‹¹ì‹ ì˜ í•  ì¼ ëª©ë¡ì€ 다ìŒì— 해야 í•  ì¼ì„ ë³´ì—¬ì¤ë‹ˆë‹¤."
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -41965,9 +42495,6 @@ msgstr "ì´ ê¸°ì—¬ë„"
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -41981,7 +42508,7 @@ msgid "Total test time for all commits/merges"
msgstr "모든 커밋 / ë¨¸ì§€ì˜ ì´ í…ŒìŠ¤íŠ¸ 시간"
msgid "Total users"
-msgstr ""
+msgstr "ì´ ì‚¬ìš©ìž"
msgid "Total weight"
msgstr "ì´ ê°€ì¤‘ì¹˜"
@@ -42287,6 +42814,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -42684,7 +43217,7 @@ msgid "Update now"
msgstr "지금 ì—…ë°ì´íŠ¸"
msgid "Update username"
-msgstr ""
+msgstr "ì‚¬ìš©ìž ì´ë¦„ ì—…ë°ì´íŠ¸"
msgid "Update variable"
msgstr "변수 ì—…ë°ì´íŠ¸"
@@ -42791,6 +43324,12 @@ msgstr ""
msgid "Usage statistics"
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ì— ëŒ€í•œ 프로ì íŠ¸ 수준 스토리지 통계는 방향성만 제공ë˜ë©° ì¸ìŠ¤í„´ìŠ¤ ì „ì²´ 중복 ì œê±°ì— ëŒ€í•œ ì ˆê° íš¨ê³¼ëŠ” í¬í•¨ë˜ì§€ 않습니다."
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr "ì´ í”„ë¡œì íŠ¸ 수준 저장소 통계ì—는 사ì´íŠ¸ ì „ì²´ 중복 ì œê±°ì— ëŒ€í•œ ì ˆê°ì•¡ì´ í¬í•¨ë˜ì§€ 않으며 네임스페ì´ìŠ¤ 저장소를 합계를 계산하는 ë° ì‚¬ìš©ë˜ì§€ 않습니다."
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr "%{help_link_start}공유 러너%{help_link_end}ê°€ 비활성화ë˜ì—ˆê¸° 때문ì—, 파ì´í”„ë¼ì¸ ì‚¬ìš©ì— ëŒ€í•œ ì œí•œì´ ì„¤ì •ë˜ì§€ 않았습니다."
@@ -42893,6 +43432,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr "패키지"
@@ -42923,6 +43465,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr "저장소"
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -43906,10 +44451,10 @@ msgid "View Stage: %{title}"
msgstr ""
msgid "View alert details at"
-msgstr ""
+msgstr "경고 세부 정보보기"
msgid "View alert details."
-msgstr ""
+msgstr "경고 세부 정보를 봅니다."
msgid "View all environments."
msgstr ""
@@ -43930,7 +44475,7 @@ msgid "View blame prior to this change"
msgstr ""
msgid "View card matches"
-msgstr ""
+msgstr "매칭ë˜ëŠ” ì¹´ë“œ 보기"
msgid "View chart"
msgid_plural "View charts"
@@ -43970,9 +44515,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44433,6 +44975,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44451,6 +44996,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr "ìƒíƒœ"
+msgid "Vulnerability|Status:"
+msgstr "ìƒíƒœ:"
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44461,7 +45009,7 @@ msgid "Vulnerability|Tool"
msgstr ""
msgid "Vulnerability|Tool:"
-msgstr ""
+msgstr "ë„구:"
msgid "Vulnerability|Training"
msgstr ""
@@ -44527,13 +45075,13 @@ msgid "We could not determine the path to remove the issue"
msgstr ""
msgid "We couldn't find any %{scope} matching %{term}"
-msgstr ""
+msgstr "ì¼ì¹˜í•˜ëŠ” %{scope}를 ì°¾ì„ ìˆ˜ 없습니다. %{term}"
msgid "We couldn't find any %{scope} matching %{term} in group %{group}"
-msgstr ""
+msgstr "그룹 %{group}ì—ì„œ %{term} ê³¼ ì¼ì¹˜í•˜ëŠ” %{scope}를 ì°¾ì„ ìˆ˜ 없습니다."
msgid "We couldn't find any %{scope} matching %{term} in project %{project}"
-msgstr ""
+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 ì„œë²„ì— ì—°ê²°í•  수 없습니다. 서버가 ë” ì´ìƒ 존재하지 않거나 설정 세부 정보를 ì—…ë°ì´íŠ¸í•´ì•¼ 합니다."
@@ -44586,7 +45134,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "ì •ë§ ë‹¹ì‹ ì´ ë§žëŠ”ì§€ 확ì¸í•˜ê³  싶습니다, ë‹¹ì‹ ì´ ë¡œë´‡ì´ ì•„ë‹ˆë¼ëŠ” ê²ƒì„ í™•ì¸í•´ì£¼ì‹­ì‹œì˜¤."
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44628,6 +45176,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44643,12 +45194,24 @@ msgstr "프로ì íŠ¸ì˜ 여러 파ì¼ì„ 빠르고 쉽게 편집합니다."
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr "프로ì íŠ¸ì˜ 여러 파ì¼ì„ 빠르고 쉽게 편집합니다. . ì„ ëˆŒëŸ¬ì„œ 열어보세요."
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44688,6 +45251,9 @@ msgstr "웹훅"
msgid "Webhooks Help"
msgstr "웹훅 ë„움ë§"
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -44758,7 +45324,7 @@ msgid "Webhooks|Deployment events"
msgstr ""
msgid "Webhooks|Do not show sensitive data such as tokens in the UI."
-msgstr ""
+msgstr "UIì— í† í°ê³¼ ê°™ì€ ë¯¼ê°í•œ ë°ì´í„°ë¥¼ 표시하지 마십시오."
msgid "Webhooks|Enable SSL verification"
msgstr ""
@@ -44776,7 +45342,7 @@ msgid "Webhooks|Go to webhooks"
msgstr ""
msgid "Webhooks|How it looks in the UI"
-msgstr ""
+msgstr "UIì—ì„œ ë³´ì´ëŠ” ë°©ì‹"
msgid "Webhooks|Issues events"
msgstr ""
@@ -44785,7 +45351,7 @@ msgid "Webhooks|Job events"
msgstr "ìž‘ì—… ì´ë²¤íŠ¸"
msgid "Webhooks|Mask portions of URL"
-msgstr ""
+msgstr "URLì˜ ë§ˆìŠ¤í¬ ë¶€ë¶„"
msgid "Webhooks|Member events"
msgstr ""
@@ -44802,6 +45368,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr "릴리스 ì´ë²¤íŠ¸"
@@ -44812,10 +45384,10 @@ msgid "Webhooks|Secret token"
msgstr ""
msgid "Webhooks|Sensitive portion of URL"
-msgstr ""
+msgstr "URLì˜ ë¯¼ê°í•œ 부분"
msgid "Webhooks|Show full URL"
-msgstr ""
+msgstr "전체 URL 표시"
msgid "Webhooks|Subgroup events"
msgstr ""
@@ -44829,9 +45401,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -44842,9 +45411,9 @@ msgid "Webhooks|URL must be percent-encoded if it contains one or more special c
msgstr ""
msgid "Webhooks|URL preview"
-msgstr ""
+msgstr "URL 미리보기"
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -44856,12 +45425,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
-msgstr ""
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr "Webhook ì†ë„ ì œí•œì— ë„달했습니다."
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
+msgstr "%{root_namespace} ì— ëŒ€í•œ Webhookì€ ë¶„ë‹¹ %{limit} 회 ì´ìƒ 트리거ë˜ì—ˆê¸° ë•Œë¬¸ì— ë¹„í™œì„±í™”ë˜ì—ˆìŠµë‹ˆë‹¤. 1분후 ìžë™ìœ¼ë¡œ 다시 활성화ë©ë‹ˆë‹¤."
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -44940,6 +45518,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr "ì–´ë–¤ í…œí”Œë¦¿ì„ ë§Œë“¤ 수 있습니까?"
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -44949,7 +45530,7 @@ msgstr ""
msgid "What's new"
msgstr "새로운 기능"
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45263,6 +45844,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr "ë°˜ë³µì— ì¶”ê°€"
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr "ì •ë§ íŽ¸ì§‘ì„ ì·¨ì†Œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?"
@@ -45312,9 +45899,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr "ì´ìŠˆ"
+msgid "WorkItem|Iteration"
+msgstr "반복"
+
msgid "WorkItem|Learn about tasks."
msgstr "태스í¬ì— 대해 알아보기"
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr "반복 ì—†ìŒ"
+
+msgid "WorkItem|No matching results"
+msgstr "ì¼ì¹˜í•˜ëŠ” 결과가 없습니다"
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr "현재 í• ë‹¹ëœ ìž‘ì—…ì´ ì—†ìŠµë‹ˆë‹¤. ìž‘ì—…ì„ ì‚¬ìš©í•˜ì—¬ ì´ ë¬¸ì œë¥¼ ë” ìž‘ì€ ë¶€ë¶„ìœ¼ë¡œ 나눕니다."
@@ -45345,12 +45947,15 @@ msgstr "%{workItemType}ì„ ì‚­ì œí•  ë•Œ 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 다시 ì‹
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr "ë°˜ë³µì„ ê°€ì ¸ì˜¬ ë•Œ 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 다시 ì‹œë„í•´ 주세요."
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr "ë ˆì´ë¸”ì„ ê°€ì ¸ì˜¬ ë•Œ 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. 다시 ì‹œë„í•´ 주세요."
+
msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr "ìž‘ì—…ì„ ê°€ì ¸ì˜¬ ë•Œ 문제가 ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì´ íŽ˜ì´ì§€ë¥¼ 새로고침하세요."
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
-msgstr ""
-
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
msgstr ""
@@ -45360,6 +45965,9 @@ msgstr "WorkItem|하위 ìž‘ì—…ì„ ì¶”ê°€í•˜ëŠ” ë™ì•ˆ 문제가 ë°œìƒí–ˆìŠµë‹ˆë
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45381,6 +45989,9 @@ msgstr "태스í¬"
msgid "WorkItem|Test case"
msgstr "테스트 ì¼€ì´ìŠ¤"
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr "ì´ ìž‘ì—… í•­ëª©ì€ ì‚¬ìš©í•  수 없습니다. 존재하지 않거나 ë³¼ 수 있는 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤."
+
msgid "WorkItem|Turn off confidentiality"
msgstr "WorkItem|기밀성 해제"
@@ -45399,6 +46010,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr "ìž‘ì—… í•­ëª©ì„ ì°¾ì„ ìˆ˜ ì—†ìŒ"
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45493,6 +46107,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45529,6 +46146,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr "사용ìžë¥¼ 승ì¸í•  ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤."
+msgid "You are not allowed to create this tag as it is protected."
+msgstr "ì´ íƒœê·¸ëŠ” 보호ë˜ì–´ 있으므로 ìƒì„±í•  수 없습니다."
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45574,9 +46197,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45677,6 +46297,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -45749,8 +46372,8 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
-msgstr "ë” ì´ìƒ 추가할 수 없지만 비활성 구성ì›ì„ 제거하고 새 구성ì›ìœ¼ë¡œ êµì²´í•˜ëŠ” 등 기존 구성ì›ì„ 관리할 수 있습니다. ë” ë§Žì€ íšŒì›ì„ 가입시키려면 그룹 소유ìžëŠ” í‰ê°€íŒì„ 시작하거나 유료 계층으로 업그레ì´ë“œí•´ì•¼ 합니다."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
+msgstr "%{limit} 명 ì´ìƒì˜ 사용ìžë¥¼ 팔로우할 수 없습니다. ë” ë§Žì€ ì‚¬ìš©ìžë¥¼ 팔로우하려면 다른 사용ìžë¥¼ 팔로우 해제하세요."
msgid "You cannot %{action} %{state} users."
msgstr ""
@@ -45773,6 +46396,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -45915,6 +46541,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -45925,7 +46554,7 @@ msgid "You have insufficient permissions to remove an on-call schedule from this
msgstr ""
msgid "You have insufficient permissions to remove this HTTP integration"
-msgstr ""
+msgstr "ì´ HTTP í†µí•©ì„ ì œê±° í•  수있는 ê¶Œí•œì´ ì—†ìŠµë‹ˆë‹¤."
msgid "You have insufficient permissions to remove this Namespace Ban"
msgstr ""
@@ -45978,7 +46607,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46146,9 +46775,6 @@ msgstr "YouTube"
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46260,6 +46886,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46376,16 +47005,13 @@ msgstr ""
msgid "Your name"
msgstr "ê·€í•˜ì˜ ì´ë¦„"
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46473,6 +47099,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46542,9 +47171,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr "ì‚­ì œëœ ì‚¬ìš©ìž"
@@ -46555,9 +47181,6 @@ msgstr[0] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46616,6 +47239,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46625,9 +47254,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr "최소한 리í¬í„° ì—­í• , ì €ìž‘ìž ë° ë‹´ë‹¹ìž"
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46657,7 +47283,7 @@ msgid "cURL:"
msgstr "cURL:"
msgid "can contain only digits"
-msgstr ""
+msgstr "숫ìžë§Œ í¬í•¨í•  수 있ìŒ"
msgid "can contain only letters of the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'"
msgstr ""
@@ -46705,6 +47331,12 @@ msgid "cannot be a date in the past"
msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
+msgstr "%{namespace_name}ëª…ì— ëŒ€í•œ %{free_limit} ëª…ì˜ íšŒì› ì œí•œì— ë„달했기 ë•Œë¬¸ì— ì¶”ê°€í•  수 없습니다."
+
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
msgstr ""
msgid "cannot be changed"
@@ -46936,12 +47568,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -46964,7 +47611,7 @@ msgid "ciReport|Full Report"
msgstr ""
msgid "ciReport|Generic Report"
-msgstr ""
+msgstr "ì¼ë°˜ ë³´ê³ "
msgid "ciReport|IaC Scanning"
msgstr ""
@@ -47015,6 +47662,9 @@ msgstr "ciReport|수ë™ìœ¼ë¡œ 추가ë¨"
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47045,6 +47695,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47060,6 +47713,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47116,7 +47772,7 @@ msgid "closed issue"
msgstr "닫힌 ì´ìŠˆ"
msgid "collect usage information"
-msgstr ""
+msgstr "사용정보 수집"
msgid "comment"
msgstr "댓글"
@@ -47133,6 +47789,9 @@ msgstr ""
msgid "committed"
msgstr "커밋ë¨"
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47191,6 +47850,9 @@ msgstr[0] "ì¼"
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr "기본 브랜치"
@@ -47344,6 +48006,9 @@ msgid "from %d job"
msgid_plural "from %d jobs"
msgstr[0] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47442,12 +48107,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47469,6 +48140,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr "유효한 URLì´ ì•„ë‹™ë‹ˆë‹¤."
+
msgid "is not a valid X509 certificate."
msgstr "올바른 X509 ì¸ì¦ì„œê°€ 아닙니다."
@@ -47493,12 +48167,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47652,9 +48332,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -47801,6 +48478,9 @@ 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 "머지 차단ë¨: 모든 스레드를 해결해야 합니다."
@@ -47897,9 +48577,6 @@ msgstr "새로운 머지 리퀘스트(MR)ì—ì„œ ì´ ë¨¸ì§€ 리퀘스트(MR)ë¡œ ë
msgid "mrWidget|Revoke approval"
msgstr "ìŠ¹ì¸ ì·¨ì†Œ"
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr "파ì´í”„ë¼ì¸ì´ 성공하면 머지 트레ì¸ì— 추가ë˜ë„ë¡ %{merge_author}ì— ì˜í•´ 설정ë©ë‹ˆë‹¤"
@@ -47963,6 +48640,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -47975,9 +48655,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr "최ìƒìœ„ 네임스페ì´ìŠ¤ì—¬ì•¼ 합니다."
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -47996,9 +48682,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48047,9 +48730,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48068,16 +48748,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] "전체 테스트 중 %d"
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr "매개변수가 비어 있습니다."
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "부모"
@@ -48204,9 +48883,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr "%{link_type} ë§í¬ë¥¼ 제거했습니다"
@@ -48226,12 +48902,19 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+
msgid "repository:"
msgstr "저장소:"
msgid "role's base access level does not match the access level of the membership"
msgstr "ì—­í• ì˜ ê¸°ë³¸ 액세스 ìˆ˜ì¤€ì´ ë©¤ë²„ì‹­ì˜ ì•¡ì„¸ìŠ¤ 수준과 ì¼ì¹˜í•˜ì§€ 않습니다."
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48354,7 +49037,7 @@ msgid "suggestPipeline|We’re adding a GitLab CI configuration file to add a pi
msgstr "프로ì íŠ¸ì— 파ì´í”„ë¼ì¸ì„ 추가하기 위해 GitLab CI 구성 파ì¼ì„ 추가하고 있습니다. 수ë™ìœ¼ë¡œ ìƒì„±í•  ìˆ˜ë„ ìžˆì§€ë§Œ 기본ì ìœ¼ë¡œ ìž‘ë™í•˜ëŠ” GitLab 템플릿으로 시작하는 ê²ƒì´ ì¢‹ìŠµë‹ˆë‹¤."
msgid "supported SSH public key."
-msgstr ""
+msgstr "지ì›ë˜ëŠ” SSH 공개 키."
msgid "tag name"
msgstr ""
@@ -48386,6 +49069,9 @@ msgstr "ì´ ë¬¸ì„œ"
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48520,6 +49206,9 @@ msgstr ""
msgid "yaml invalid"
msgstr "유효하지 ì•Šì€ yaml"
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr "ë‹¹ì‹ ì˜ GitLab ì¸ìŠ¤í„´ìŠ¤"
diff --git a/locale/ku_TR/gitlab.po b/locale/ku_TR/gitlab.po
index ca67694f76a..8ec30aab0db 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: 2022-10-10 14:03\n"
+"PO-Revision-Date: 2022-11-13 09:23\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/ky_KG/gitlab.po b/locale/ky_KG/gitlab.po
index 294541b6d87..56c9ad12bc8 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: 2022-10-10 14:04\n"
+"PO-Revision-Date: 2022-11-13 09:23\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/lt_LT/gitlab.po b/locale/lt_LT/gitlab.po
index e66368e856f..ef0f793bf9d 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: 2022-10-10 14:03\n"
+"PO-Revision-Date: 2022-11-13 09:23\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -171,6 +171,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -311,13 +318,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
@@ -325,13 +325,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -346,13 +339,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -677,6 +663,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -737,6 +726,20 @@ msgstr[3] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -747,6 +750,13 @@ msgstr[3] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} more"
msgstr ""
@@ -773,6 +783,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -812,9 +829,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -1025,12 +1039,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1230,6 +1238,9 @@ msgstr[3] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1388,9 +1399,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1448,6 +1456,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1488,6 +1499,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1827,6 +1841,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1890,9 +1907,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1971,9 +1985,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -2181,6 +2192,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2292,15 +2306,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2370,9 +2378,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2745,6 +2750,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2928,6 +2939,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2964,15 +2993,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -3021,6 +3062,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -3066,6 +3110,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -3204,9 +3260,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -3231,6 +3296,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3333,6 +3407,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3525,7 +3602,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3570,7 +3647,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3633,7 +3710,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3681,6 +3758,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -4191,7 +4271,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -4206,6 +4286,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -4242,9 +4325,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4491,6 +4571,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4678,9 +4761,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4780,9 +4860,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4885,9 +4962,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4906,7 +4980,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4953,6 +5027,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4971,9 +5048,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -5001,6 +5087,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5351,9 +5440,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5457,7 +5543,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5508,6 +5594,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5559,9 +5669,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5961,9 +6068,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6327,6 +6431,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -7063,6 +7173,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -7072,6 +7185,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -7093,6 +7209,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -7111,6 +7230,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -7120,6 +7242,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -7138,9 +7263,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -7159,12 +7290,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7324,6 +7464,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7333,9 +7476,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7381,9 +7521,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7414,6 +7551,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7429,6 +7569,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7453,9 +7596,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7871,9 +8011,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7889,6 +8026,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8632,6 +8772,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9951,10 +10094,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -10138,6 +10287,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10939,10 +11091,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10975,6 +11127,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -11023,9 +11184,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -11110,9 +11268,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -11275,9 +11430,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11497,9 +11649,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11767,9 +11916,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11785,7 +11931,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11887,9 +12033,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -12218,6 +12361,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -12245,6 +12391,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -12302,6 +12451,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12536,6 +12688,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12756,6 +12911,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12843,6 +13001,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12876,6 +13037,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12987,6 +13151,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -13008,9 +13175,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -13077,7 +13241,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13566,6 +13730,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13653,6 +13820,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13997,6 +14179,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -14239,6 +14424,12 @@ msgstr[3] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -14254,6 +14445,9 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
@@ -14261,6 +14455,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14868,6 +15065,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -15198,22 +15401,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Copy snippet"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr ""
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr ""
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15441,6 +15662,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15621,10 +15845,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15639,18 +15863,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15663,18 +15878,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15804,9 +16013,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15870,9 +16076,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -16113,6 +16316,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -16234,6 +16488,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -16291,9 +16548,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16520,6 +16783,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16569,9 +16835,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16767,9 +17030,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -17029,6 +17289,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17134,9 +17397,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -17344,6 +17604,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -18185,9 +18448,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -18314,6 +18574,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18365,6 +18631,9 @@ 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 ""
@@ -18413,9 +18682,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18971,9 +19237,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18983,6 +19246,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19745,12 +20011,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19820,6 +20080,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -20002,9 +20265,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20463,7 +20723,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20550,12 +20816,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -22315,6 +22575,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -22333,9 +22596,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22393,7 +22653,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22475,19 +22735,16 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22625,12 +22882,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22652,6 +22915,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22877,6 +23152,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -23171,6 +23461,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23501,6 +23794,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23540,9 +23836,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23923,9 +24225,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -24079,6 +24378,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24229,9 +24537,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24490,6 +24795,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24760,9 +25071,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24775,6 +25083,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24811,7 +25122,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24826,9 +25143,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24838,9 +25161,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24850,7 +25170,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24907,6 +25227,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24931,6 +25254,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24982,6 +25308,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24994,6 +25323,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25626,6 +25958,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25851,6 +26186,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -26246,6 +26584,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26405,6 +26746,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26477,6 +26821,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26663,6 +27010,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -27127,6 +27477,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -27256,9 +27609,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -27286,9 +27636,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -27304,9 +27651,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27542,7 +27886,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27885,6 +28229,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27894,6 +28241,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27915,6 +28265,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -28008,9 +28361,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -28035,9 +28385,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -28273,12 +28620,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28324,12 +28665,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28351,12 +28686,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28399,15 +28728,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28438,12 +28758,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28462,9 +28776,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28640,9 +28951,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -29013,12 +29321,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -29064,6 +29381,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -29212,6 +29535,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29597,12 +29923,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29651,7 +29971,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29870,6 +30190,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29885,6 +30208,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29897,12 +30223,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29912,9 +30244,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30674,9 +31012,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30785,6 +31120,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30926,6 +31324,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -31019,12 +31420,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31601,6 +32008,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31613,6 +32023,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31895,12 +32308,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31913,12 +32332,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31940,6 +32365,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -32039,6 +32467,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -32177,6 +32608,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -32207,6 +32641,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -32258,6 +32695,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32897,6 +33337,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32933,15 +33376,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32957,12 +33412,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -33272,6 +33736,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33404,12 +33871,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33503,9 +33964,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33673,6 +34131,9 @@ msgstr[3] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33682,6 +34143,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -34138,6 +34602,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -34154,13 +34621,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -34192,18 +34652,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34218,12 +34672,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -34266,21 +34714,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34296,9 +34735,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34678,6 +35114,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34911,6 +35350,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34951,6 +35393,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34983,7 +35428,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -35194,6 +35639,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -35324,9 +35772,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -35375,6 +35829,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -35412,6 +35869,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -35451,12 +35911,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35511,16 +35965,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35628,10 +36088,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35652,9 +36112,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35664,9 +36130,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35817,9 +36289,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -36248,10 +36717,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -36371,6 +36843,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36473,10 +36948,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36566,7 +37041,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36584,6 +37059,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36602,12 +37080,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36629,6 +37116,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36758,6 +37248,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36815,6 +37308,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36932,9 +37428,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36947,6 +37449,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -37010,9 +37515,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -37151,10 +37653,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -37166,28 +37668,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37406,9 +37908,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37560,9 +38059,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37819,10 +38315,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37876,7 +38369,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37891,7 +38384,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -38014,9 +38507,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -38239,6 +38729,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38350,9 +38843,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38926,9 +39416,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38941,9 +39428,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38965,9 +39449,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39487,9 +39968,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39749,6 +40236,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39839,6 +40329,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39923,6 +40416,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39944,15 +40440,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39974,9 +40464,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39995,6 +40482,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -40106,20 +40596,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -40143,12 +40619,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -40236,12 +40706,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40706,6 +41170,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40901,9 +41368,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40934,7 +41398,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40991,9 +41455,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -41345,9 +41806,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -41381,6 +41839,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41549,9 +42010,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41612,6 +42070,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41828,13 +42289,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41963,9 +42427,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41984,6 +42445,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42358,9 +42822,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42466,6 +42927,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42532,9 +42996,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42556,18 +43044,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42580,6 +43089,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42730,9 +43257,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -43055,6 +43579,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43559,6 +44089,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43661,6 +44197,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43691,6 +44230,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44747,9 +45289,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -45213,6 +45752,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -45231,6 +45773,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -45366,7 +45911,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45408,6 +45953,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -45423,12 +45971,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45468,6 +46028,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45582,6 +46145,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45609,9 +46178,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45624,7 +46190,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45636,12 +46202,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45720,6 +46295,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45729,7 +46307,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -46049,6 +46627,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -46101,9 +46685,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -46134,10 +46733,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -46149,6 +46751,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -46170,6 +46775,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -46188,6 +46796,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -46285,6 +46896,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -46321,6 +46935,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46366,9 +46986,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -46472,6 +47089,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46544,7 +47164,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46568,6 +47188,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46713,6 +47336,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46776,7 +47402,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46944,9 +47570,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -47058,6 +47681,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -47180,16 +47806,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47280,6 +47903,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47349,9 +47975,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -47365,9 +47988,6 @@ msgstr[3] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -47429,6 +48049,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -47438,9 +48064,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -47523,6 +48146,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47764,12 +48393,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47846,6 +48490,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47876,6 +48523,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47891,6 +48541,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47967,6 +48620,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -48028,6 +48684,9 @@ msgstr[3] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -48190,6 +48849,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -48294,12 +48956,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -48321,6 +48989,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -48345,12 +49016,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -48513,9 +49190,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48668,6 +49342,9 @@ 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 ""
@@ -48764,9 +49441,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48830,6 +49504,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48842,9 +49519,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48863,9 +49546,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48914,9 +49594,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48935,19 +49612,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -49083,9 +49756,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -49108,12 +49778,22 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -49271,6 +49951,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -49411,6 +50094,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/mk_MK/gitlab.po b/locale/mk_MK/gitlab.po
index ca9cf1d01a5..6505cd62af3 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: 2022-10-10 14:04\n"
+"PO-Revision-Date: 2022-11-13 09:23\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/ml_IN/gitlab.po b/locale/ml_IN/gitlab.po
index cfa2339e1cc..c191d76d2ab 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: 2022-10-10 14:05\n"
+"PO-Revision-Date: 2022-11-13 09:25\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/mn_MN/gitlab.po b/locale/mn_MN/gitlab.po
index 5f9cb63fea4..5f25cea5f66 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: 2022-10-10 14:04\n"
+"PO-Revision-Date: 2022-11-13 09:23\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/nb_NO/gitlab.po b/locale/nb_NO/gitlab.po
index fcad820e52d..0ee100f3d99 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: 2022-10-10 14:06\n"
+"PO-Revision-Date: 2022-11-13 09:24\n"
msgid " %{start} to %{end}"
msgstr " %{start} til %{end}"
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d godkjenner"
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] "%d epos"
msgstr[1] "%d eposer"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d feil"
-msgstr[1] "%d feil"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d exporter"
msgstr[1] "%d exporters"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%d mislyktes"
-msgstr[1] "%d mislyktes"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] "%d mislykket sikkerhetsjobb"
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] "%d fil"
msgstr[1] "%d filer"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d fikset testresultat"
-msgstr[1] "%d fiksede testresultater"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] "%{bold_start}%{count}%{bold_end} åpnet fletteforespørsel"
msgstr[1] "%{bold_start}%{count}%{bold_end} åpnede fletteforespørsler"
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr "%{code_open}Maskert:%{code_close} Skjult i jobblogger. MÃ¥ oppfylle kravene til maskering."
@@ -567,6 +560,16 @@ msgstr[1] "%{count} kontakter"
msgid "%{count} files touched"
msgstr "%{count} filer berørt"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "%{count} gjenstand"
@@ -575,6 +578,11 @@ msgstr[1] "%{count} gjenstander"
msgid "%{count} items per page"
msgstr "%{count} gjenstander per side"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr "%{count} mer"
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} deltaker"
msgstr[1] "%{count} deltakere"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} relatert(e) %{pluralized_subject}: %{links}"
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr "%{docs_link_start}Hva er 2-trinnsautentisering?%{docs_link_end}"
-msgid "%{due_date} (Past due)"
-msgstr "%{due_date} (Forbi måldatoen)"
-
msgid "%{duration}ms"
msgstr "%{duration}ms"
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr "%{name} (opptatt)"
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} inneholdt %{resultsString}"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} fant %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr "%{name} brukes allerede for en annen emoji"
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "%{strong_start}%{branch_count}%{strong_end} gren"
@@ -1182,9 +1189,6 @@ msgstr "%{user} opprettet en sak: %{issue_link}"
msgid "%{value} is not included in the list"
msgstr "%{value} er ikke inkludert i listen"
-msgid "%{value} s"
-msgstr "%{value} sek"
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} %{time_spent_value} brukt tid."
@@ -1242,6 +1246,9 @@ msgstr "'%{source}' er ikke en importkilde"
msgid "'%{template_name}' is unknown or invalid"
msgstr "'%{template_name}' er ukjent eller ugyldig"
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d lukket)"
@@ -1280,6 +1287,9 @@ msgstr "(la stå tomt hvis du ikke vil endre det)"
msgid "(max size 15 MB)"
msgstr "(maks størrelse 15 MB)"
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr "(valgfritt)"
@@ -1565,6 +1575,9 @@ msgstr "Du har ikke tilgang til å nå denne siden."
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "Kontroller at adressen er riktig og at siden ikke er flyttet."
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr "Siden ble ikke funnet"
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "En standardgren kan ikke velges for et tomt prosjekt."
-
msgid "A deleted user"
msgstr "En slettet bruker"
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr "En plattformverdi kan være web, mob, eller app."
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr "Godta vilkår"
msgid "Acceptable for use in this project"
msgstr "Akseptabelt for bruk i dette prosjektet"
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr "Lær mer"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "Melding: %{message}"
-msgid "AccessibilityReport|New"
-msgstr "Ny"
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr "Aktiv"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr "Aktiv %{type} (%{token_length})"
-
msgid "Active Sessions"
msgstr "Aktive økter"
@@ -2483,6 +2484,12 @@ msgstr "Legger til %{labels} %{label_text}."
msgid "Adds a Zoom meeting."
msgstr "Legger til et Zoom-møte."
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr "Feil under innlasting av statistikken. Vennligst prøv igjen"
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr "Auto DevOps-domene"
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr "Konfigurer «Let's Encrypt»"
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr "Administratorer"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr "Godkjenn"
@@ -3263,8 +3336,8 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr "Gjenopprett brukertilgang til kontoen, inkludert nett, Git og API."
-msgid "AdminUsers|Search by name, email or username"
-msgstr "Søk etter navn, e-postadresse eller brukernavn"
+msgid "AdminUsers|Search by name, email, or username"
+msgstr ""
msgid "AdminUsers|Search users"
msgstr "Søk etter brukere"
@@ -3308,8 +3381,8 @@ msgstr "Brukeren vil ikke motta noen varsler"
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "For å bekrefte, skriv %{projectName}"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "For å bekrefte, skriv %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr ""
msgid "AdminUsers|Unban user"
msgstr "Opphev bannlysning av bruker"
@@ -3371,8 +3444,8 @@ msgstr "Uten prosjekter"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr "Du er i ferd med å slette brukeren %{username} permanent. Saker, fletteforespørsler og grupper knyttet til dem vil bli overført til en systemomfattende \"Spøkelsesbruker\". For å unngå tap av data, bør du vurdere å bruke «%{strongStart}Blokker bruker%{strongEnd}»-funksjonen i stedet. Når du har benyttet «%{strongStart}Slett bruker%{strongEnd}», kan det ikke angres på eller gjenopprettes."
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
-msgstr "Du er i ferd med å slette brukeren %{username} permanent. Dette vil slette alle saker, fletteforespørsler og grupper knyttet til dem. For å unngå tap av data, bør du vurdere å bruke «%{strongStart}Blokker bruker%{strongEnd}»-funksjonen i stedet. Når du har benyttet «%{strongStart}Slett bruker%{strongEnd}», kan det ikke angres på eller gjenopprettes."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
+msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
msgstr ""
@@ -3419,6 +3492,9 @@ msgstr "Administrasjon"
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,8 +4005,8 @@ msgstr "Alle brukere må ha et navn."
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
-msgstr "Tillat \"%{group_name}\" å logge deg på"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr ""
msgid "Allow access to members of the following group"
msgstr ""
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr "Tillat gruppeeiere å behandle LDAP-relaterte innstillinger"
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr "Tillat brukere å avvise utsendingsmeldingen"
@@ -4229,6 +4305,9 @@ msgstr "Det oppstod en feil under innhenting av etiketter. Prøv søket på nytt
msgid "An error occurred while fetching terraform reports."
msgstr "Det oppstod en feil under innhenting av terraformingsrapporter."
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr "En feil oppstod under innhenting av jobbloggføringen."
@@ -4414,9 +4493,6 @@ msgstr "En feil oppstod under trigging av jobben."
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr "En ukjent feil har oppstått."
msgid "Analytics"
msgstr "Analyser"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "Analyser avhengighetene dine for kjente sårbarheter."
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr "Oppdatering av programinnstillinger mislyktes"
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr "Appen ble vellykket søndersmadret."
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr "E-postbegrensninger"
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr "Lagre endringer"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ 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 these artifacts?"
-msgstr "Er du sikker på at du vil slette disse artefaktene?"
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,8 +5259,8 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
-msgstr "Er du sikker på at du vil trekke tilbake denne %{type}? Denne handlingen kan ikke angres på."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr ""
@@ -5228,6 +5310,30 @@ msgstr "Artifakten ble vellykket slettet."
msgid "Artifacts"
msgstr "Artefakter"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr "Tilordne en tilpasset farge som #FF0000"
msgid "Assign labels"
msgstr "Tilordne stempler"
-msgid "Assign milestone"
-msgstr "Tilordne milepæl"
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr "Grenen finnes allerede"
msgid "Branch changed"
msgstr "Grenen ble endret"
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr "Grenen er allerede i bruk"
msgid "Branch name"
msgstr "Grennavn"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr "Grenen ble ikke lastet inn - %{branchId}"
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr "Meldinger"
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "Bla gjennom katalog"
@@ -7039,9 +7178,6 @@ msgstr "Bla gjennom fil"
msgid "Browse Files"
msgstr "Bla gjennom filer"
-msgid "Browse artifacts"
-msgstr "Bla gjennom artefakter"
-
msgid "Browse files"
msgstr "Bla gjennom filer"
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr "Fra kildegruppe"
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr "Navnet finnes allerede."
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr "Til ny gruppe"
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr "Avbryter forhåndsvisningen"
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr "Kan ikke flettes automatisk"
@@ -7593,6 +7726,9 @@ msgstr "Kan ikke opprette misbruksrapporten. Brukeren har blitt blokkert."
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr "Kan ikke ha flere Jira-importeringer som kjører samtidig"
@@ -8332,6 +8468,9 @@ msgstr "Nøkkel"
msgid "CiVariables|Masked"
msgstr "Maskert"
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr "Beskyttet"
@@ -9647,10 +9786,16 @@ msgstr "Kommenter på linjene fra %{startLine} til %{endLine}"
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr "Fullført"
@@ -10627,10 +10775,10 @@ msgstr "Bidrag"
msgid "Contribution Analytics"
msgstr "Bidragsanalyse"
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
-msgstr "%{created_count} opprettet, %{closed_count} lukket."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
+msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr "Bidrag på %{calendar_date}"
@@ -10711,9 +10868,6 @@ msgstr "Kopier %{name}"
msgid "Copy %{protocol} clone URL"
msgstr "Kopier %{protocol}-klone-URL"
-msgid "Copy %{type}"
-msgstr "Kopier %{type}"
-
msgid "Copy ID"
msgstr "Kopier ID"
@@ -10798,9 +10952,6 @@ msgstr "Kopier hemmelighet"
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr "Klarte ikke å fjerne trigger."
@@ -11185,9 +11333,6 @@ msgstr "Opprett ny fil eller katalog"
msgid "Create new label"
msgstr "Opprett ny stempel"
-msgid "Create new project"
-msgstr "Opprett et nytt prosjekt"
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr "Oppretter epos"
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr "Opprettelsesdato"
-
msgid "Creator"
msgstr "Opprettet av"
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr "Personlige tilgangssjetonger"
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr "Nåværende gren"
msgid "Current Project"
msgstr "Gjeldende prosjekt"
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr "Dato"
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr "Personlig"
msgid "DashboardProjects|Trending"
msgstr "Trendende"
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr "%{firstProject} og %{secondProject}"
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr "Lagre profil"
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr "Datatype"
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr "O"
msgid "Days"
msgstr "Dager"
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr "Dager igjen til sammenslåing"
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr "Minsk"
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr "Standard CI/CD-oppsettsfil"
@@ -12671,6 +12831,9 @@ msgstr "Slett"
msgid "Delete %{issuableType}"
msgstr "Slett %{issuableType}"
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr "Slett %{name}"
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr "Slett konto"
-msgid "Delete artifacts"
-msgstr "Slett artefakter"
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr "Slett rad"
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr "Utløper"
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr "DevOps-adopsjon"
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr "Vis %{unfoldCount} linjer"
msgid "Diffs|Show all unchanged lines"
msgstr "Vis alle uendrede linjer"
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr "Redigert"
msgid "Edited %{timeago}"
msgstr "Redigert %{timeago}"
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr "Redigerer"
@@ -14858,23 +15057,41 @@ msgstr ""
msgid "Enable version check"
msgstr "Skru på versjonssjekk"
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
-msgstr "%{stepStart}Trinn 2%{stepEnd}. Kopier det følgende utdraget:"
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|Close"
-msgstr "Lukk"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr ""
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr ""
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
-msgstr "Kopier utdragstekst"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
+msgstr ""
msgid "Enabled"
msgstr "Skrudd på"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr "Commit"
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr "Slett"
@@ -15281,11 +15501,11 @@ msgstr "Legg til et nytt epos"
msgid "Epics|Add an existing epic"
msgstr "Legg til et eksisterende epos"
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
-msgstr "Tilordne epos"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr ""
@@ -15299,18 +15519,9 @@ msgstr "Fjern epos"
msgid "Epics|Remove issue"
msgstr "Fjern saker"
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr "Velg epos"
-
msgid "Epics|Show more"
msgstr "Vis mer"
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr "Noe gikk galt under flytting av gjenstand."
msgid "Epics|Something went wrong while ordering item."
msgstr "Noe gikk galt under sortering av gjenstand."
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr "En feil oppstod under oppdatering av sakens status"
@@ -15530,9 +15732,6 @@ msgstr "Feil ved opplasting av fil"
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr "Feil under opplasting av fil: %{stripped}"
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr "Hendelser"
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr "Ekskludert innflettings-commiter. Begrenset til 6 000 commiter."
msgid "Execution time"
msgstr "Iverksettelsestid"
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr "Eksisterende greinnavn, etikett, eller commit-SHA"
@@ -15949,9 +16202,15 @@ msgstr "Utvid sidepanelet"
msgid "Expected documents: %{expected_documents}"
msgstr "Forventede dokumenter: %{expected_documents}"
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr "Utløp"
@@ -16176,6 +16435,9 @@ msgstr "Mislyktes den"
msgid "Failed to add a Zoom meeting"
msgstr "Mislyktes i å legge til et Zoom-møte"
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr "Mislyktes i å benytte kommandoer."
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr "Mislyktes i å opprette kodelager"
@@ -16421,9 +16680,6 @@ msgstr "Mislyktes i å oppdatere-sakerstatus"
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr "Mislyktes i å oppdatere."
-
msgid "Failed to upgrade."
msgstr "Mislyktes i å upgrade."
@@ -16681,6 +16937,9 @@ msgstr "Feb"
msgid "February"
msgstr "Februar"
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr "Filtrer etter milepælnavn"
@@ -16996,6 +17252,9 @@ msgstr "For mer informasjon, gå til "
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr "Glemt passordet ditt?"
@@ -17829,9 +18088,6 @@ msgstr "sekundær"
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr "GitLab-kontoforespørsel"
msgid "GitLab Billing Team."
msgstr "GitLab-faktureringsteamet."
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr "GitLab-versjon"
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr "GitLab.com"
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr "Vis avhengigheter"
msgid "GraphViewType|Stage"
msgstr "Trinn"
-msgid "Graphs"
-msgstr "Grafer"
-
msgid "Gravatar"
msgstr "Gravatar"
@@ -18627,6 +18886,9 @@ msgstr "Gravatar er skrudd på"
msgid "Group"
msgstr "Gruppe"
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr "Laster inn grupper"
-msgid "GroupsTree|No groups matched your search"
-msgstr "Ingen grupper samsvarte med søket ditt"
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr "Ingen grupper eller prosjekter samsvarte med søket ditt"
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr "Retningslinje"
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr "Helsestatus"
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr "Tilgangssjetongen er"
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr "Hvis dette var en feil, kan du %{leave_link_start}forlate %{source_type}%{link_end}."
@@ -21943,6 +22199,9 @@ msgstr "Ugyldig 2-trinnskode."
msgid "Invalid yaml"
msgstr "Ugyldig yaml"
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr "Invitasjonen ble avslått"
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr "Inviter «%{trimmed}» via e-post"
-
msgid "Invite Members"
msgstr "Inviter medlemmer"
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr "Bruker lisenssetet:"
msgid "Is using seat"
msgstr "Benytter sete"
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr "flyttet"
msgid "IssuableStatus|promoted"
msgstr "forfremmet"
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr "Sak"
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr "Totalt:"
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr "Tittel"
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr "Last ned"
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr "Senest redigert av %{link_start}%{avatar} %{name}%{link_end}"
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr "Senest endret"
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr "Forlat prosjektet"
msgid "Leave zen mode"
msgstr "Forlat zenmodus"
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr "Linjeendringer"
msgid "Link"
msgstr "Lenke"
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr "Logger"
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr "MD5"
msgid "MERGED"
msgstr "INNFLETTET"
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,8 +24728,14 @@ msgstr "Vis kun endringer"
msgid "MRDiff|Show full file"
msgstr "Vis hele filen"
-msgid "Made this issue confidential."
-msgstr "Gjorde denne saken konfidensiell."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
+msgstr ""
msgid "Mailgun"
msgstr "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr "Mailgun-hendelser"
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr "Vedlikeholdsmodus"
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr "Gjør alle på teamet ditt mer produktive, uansett hvor de befinner seg. GitLab Geo oppretter skrivebeskyttede speilinger av din GitLab-instans, slik at du kan redusere tiden det tar å klone og hente store kodelagre."
-msgid "Make issue confidential"
-msgstr "Gjør saken konfidensiell"
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,8 +24776,8 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
-msgstr "Gjør denne saken konfidensiell."
+msgid "Makes this %{type} confidential."
+msgstr ""
msgid "Manage %{workspace} labels"
msgstr ""
@@ -24517,6 +24833,9 @@ msgstr "Behandlet konto"
msgid "Manifest"
msgstr "Manifest"
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr "Manifest-filimport"
@@ -24541,6 +24860,9 @@ msgstr "Mar"
msgid "March"
msgstr "Mars"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr "Marker som ferdig"
@@ -24592,6 +24914,9 @@ msgstr "Legg til gjennomstreket tekst (%{modifierKey}⇧X)"
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr "Legg til gjennomstreket tekst (%{modifier_key}⇧X)"
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr "Støtter %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr "Metode"
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr "Milepælens forfallsdato"
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr "Legg til prosjekter"
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr "Ingen iterasjoner å vise"
msgid "No job log"
msgstr "Ingen jobblogg"
-msgid "No jobs to show"
-msgstr "Ingen jobber å vise"
-
msgid "No label"
msgstr "Ingen etikett"
@@ -26884,9 +27230,6 @@ msgstr "Ingen samsvarende resultater"
msgid "No matching results for \"%{query}\""
msgstr "Ingen samsvarende resultater for \"%{query}\""
-msgid "No matching results..."
-msgstr "Ingen samsvarende resultater …"
-
msgid "No members found"
msgstr "Ingen medlemmer ble funnet"
@@ -26902,9 +27245,6 @@ msgstr "Ingen meldinger ble loggført"
msgid "No milestone"
msgstr "Ingen milepæl"
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr "Ingen andre stempler med sådan navn eller beskrivelse"
@@ -27138,7 +27478,7 @@ msgstr "Klapp sammen svar"
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr "Antall ansatte"
msgid "Number of events"
msgstr "Antall hendelser"
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr "Antall berørte filer"
@@ -27623,9 +27969,6 @@ msgstr "Okt"
msgid "October"
msgstr "Oktober"
-msgid "OfSearchInADropdown|Filter"
-msgstr "Filter"
-
msgid "Off"
msgstr "Av"
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr "Skannerprofil"
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr "Velg en av de eksisterende profilene"
-
-msgid "OnDemandScans|Site profile"
-msgstr "Nettstedsprofil"
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr "Bruk eksisterende sideprofil"
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] "Én gjenstand til"
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr "Handlingen er ikke tillatt"
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr "Handlinger"
@@ -28595,12 +28899,21 @@ msgstr "Slett pakke"
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr "Helm"
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr "Beklager, filteret ditt ga ingen resultater"
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr "Periode i sekunder"
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr "Permalenke"
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr "Aktiv"
msgid "PipelineSchedules|All"
msgstr "Alle"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr "Inaktive"
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr "Neste kjøring"
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr "MÃ¥l"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr "Variabler"
@@ -30252,9 +30586,6 @@ msgstr "Vennligst velg et Jira-prosjekt"
msgid "Please select a country"
msgstr "Vennligst velg et land"
-msgid "Please select a file"
-msgstr "Vennligst velg en fil"
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr "Innstillinger"
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr "Fortsett"
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr "Produktivitet"
@@ -31179,6 +31582,9 @@ msgstr "Prosjektets navn"
msgid "Project navigation"
msgstr "Prosjektnavigering"
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr "Prosjekt-sikkerhetsstatus"
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr "Analyser"
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr "Merker"
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr "Internt"
@@ -31755,6 +32182,9 @@ msgstr "Sikkerhet og standarder"
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr "Lær mer."
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr "Beskytt"
@@ -32535,12 +32986,21 @@ msgstr "Beskyttede grener"
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr "Push-regler"
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr "Les mer"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr "Les mer om GitLab på %{link_to_promo}."
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr "Referanse"
@@ -33247,6 +33701,9 @@ msgstr[1] "Utgivelser"
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr "Rapportert av"
msgid "Reported by %{reporter}"
msgstr "Rapportert av %{reporter}"
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr "Rapportering"
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr "Klassenavn"
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr "Kjøretid"
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr "Feilede"
-
-msgid "Reports|Filename"
-msgstr "Filnavn"
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr "Skanner"
msgid "Reports|Severity"
msgstr "Alvorlighetsgrad"
-msgid "Reports|System output"
-msgstr "Systemutdata"
-
msgid "Reports|Test summary"
msgstr "Testoversikt"
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr "SÃ¥rbarhetsnavn"
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr "Ingen endrede testresultater"
-
msgid "Repositories"
msgstr "Kodelagre"
@@ -34234,6 +34668,9 @@ msgstr "Løst av"
msgid "Resolved by %{name}"
msgstr "Løst av %{name}"
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr "Svar"
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr "Aktiv"
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr "PÃ¥ nett"
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr "SAML-oppdagelsessjetonger"
msgid "SAML for %{group_name}"
msgstr "SAML for %{group_name}"
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr ""
+
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr "Lagrer"
msgid "Saving project."
msgstr "Lagrer prosjekt."
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr "Søk etter en LDAP-gruppe"
msgid "Search for a group"
msgstr "Søk etter en gruppe"
-msgid "Search for a user"
-msgstr "Søk etter en bruker"
-
msgid "Search for an emoji"
msgstr "Søk etter en emoji"
@@ -35766,11 +36233,14 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
-msgstr "%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
-msgstr "%{branches} og %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
+msgstr ""
msgid "SecurityOrchestration|%{scanners}"
msgstr ""
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr "Legg til prosjekter"
msgid "SecurityReports|All activity"
msgstr "All aktivitet"
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr "Prosjekter som holdes øye med"
msgid "SecurityReports|More info"
msgstr "Mere info"
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr "Ingen aktivitet"
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr "Se målinger"
msgid "See our website for help"
msgstr "Se nettstedet vårt for hjelp"
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr "Velg et mal-kodelager"
msgid "Select a template type"
msgstr "Velg en maltype"
-msgid "Select a timezone"
-msgstr "Velg en tidssone"
-
msgid "Select all"
msgstr "Velg alt"
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr "Å velge en GitLab-bruker vil legge til en lenke til GitLab-brukeren i beskrivelsene av saker og kommentarer (f.eks. \"Av %{link_open}@johnsmith%{link_close}\"). Det vil også knytte og/eller tildele disse sakene og kommentarene til den valgte brukeren."
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr "Alternativer"
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr "Oppsett"
-
msgid "Severity"
msgstr "Alvorlighetsgrad"
@@ -37333,10 +37827,7 @@ msgstr "Viser alle eposer"
msgid "Showing all issues"
msgstr "Viser alle saker"
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,8 +37881,8 @@ msgstr ""
msgid "Sign in preview"
msgstr "Forhåndsvisning av pålogging"
-msgid "Sign in to \"%{group_name}\""
-msgstr "Logg inn hos «%{group_name}»"
+msgid "Sign in to %{group_name}"
+msgstr ""
msgid "Sign in to GitLab"
msgstr "Logg på GitLab"
@@ -37405,8 +37896,8 @@ msgstr "Logg på med 2FA-kode"
msgid "Sign in with"
msgstr "Logg på med"
-msgid "Sign in with Single Sign-On"
-msgstr "Logg på med enkelt pålogging"
+msgid "Sign in with single sign-on"
+msgstr ""
msgid "Sign in with smart card"
msgstr "Logg på med smartkort"
@@ -37528,9 +38019,6 @@ msgstr "Størrelsesgrenser"
msgid "Size limit per repository (MB)"
msgstr "Størrelsesgrense per kodelager (MB)"
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr "Hoppet over"
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr "Noe gikk galt ved henting av miljøer for denne fletteforespørselen. Ve
msgid "Something went wrong while fetching the packages list."
msgstr "Noe gikk galt under innhenting av pakkelisten."
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr "Noe gikk galt under oppstart av OpenAPI-visningen"
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr "Status:"
msgid "Status: %{title}"
msgstr "Status: %{title}"
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr "API som skal sjekkes"
msgid "StatusCheck|Add status check"
msgstr "Legg til statussjekk"
-msgid "StatusCheck|All passed"
-msgstr "Alle ble bestått"
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr "Mislyktes i å laste inn statussjekker."
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr "Titanium-gul"
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr "Bytt gren"
msgid "Switch branch/tag"
msgstr "Bytt gren/etikett"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr "Innholdsfortegnelse"
msgid "Tag"
msgstr "Etikett"
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr "Etikettliste:"
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr "Eventuelt kan du opprette en offentlig utgivelse av prosjektet ditt, basert på denne etiketten. Utgivelsesbeskrivelser vises på %{releases_page_link_start}Utgivelser%{link_end}-siden. %{docs_link_start}Mer informasjon%{link_end}"
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr "Utgivelsesbeskrivelser"
-
msgid "TagsPage|Repository has no tags yet."
msgstr "Kodelageret har ingen etiketter enda."
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "Skriv inn dine utgivelsesbeskrivelser eller dra filer hit …"
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr "beskyttet"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr "MÃ¥lgren"
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr "%{name} ble vellykket fjernet"
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr "Handlinger"
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr "Vertsnavnet til PlantUML-tjeneren din."
msgid "The hostname of your Snowplow collector."
msgstr "Vertsnavnet til din Snowplow-innsamler."
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr "Kodelageret må være tilgjengelig over %{code_open}http://%{code_close}
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr "Det er ingen hendelser for øyeblikket."
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr "Dette Cron-mønsteret er ugyldig"
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr "Denne gruppen er knyttet til et abonnement"
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr "Denne brukeren har en ubekreftet E-postadresse. Du kan tvinge den til å
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr "Denne brukeren har ingen aktive %{type}."
-
msgid "This user has no identities"
msgstr "Denne brukeren har ingen identiteter"
@@ -41478,6 +41941,9 @@ msgstr "Denne brukeren er forfatteren av denne %{noteable}."
msgid "This variable can not be masked."
msgstr "Denne variabelen kan ikke maskeres."
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr "For å bekrefte, skriv %{phrase_code}"
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr "For å koble til GitHub-kodelagre, kan du bruke en %{personal_access_token_link}. Når du oppretter din personlige tilgangsnøkkel, må du velge %{code_open}kodelager%{code_close}-omfang, så vi kan vise en liste over dine offentlige og private kodelagre som er tilgjengelige for å koble til."
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr "For å aktivere kontoen din på nytt, logg på GitLab på %{gitlab_url}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr "For å oppklare dette, forsøk å:"
@@ -42022,9 +42488,33 @@ msgstr "I dag"
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr "Totalt antall bidrag"
msgid "Total Score"
msgstr "Totalscore"
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr "Totalt antall kjerner (CPU-er)"
@@ -42543,6 +43069,12 @@ msgstr "2-trinnautentisering har blitt skrudd av for denne brukeren"
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr "2-trinnautentisering har blitt skrudd av vellykket!"
@@ -43047,6 +43579,12 @@ msgstr "Brukstrender"
msgid "Usage statistics"
msgstr "Bruksstatistikk"
+msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
+msgstr ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr "Pakker"
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr "Kodelager"
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr "Seter"
@@ -44229,9 +44773,6 @@ msgstr "Vis fil @ %{commitSha}"
msgid "View full dashboard"
msgstr "Vis full kontrollpanel"
-msgid "View full log"
-msgstr "Vis full logg"
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr "Skannerleverandør"
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr "Status"
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr "Vi prøvde å fornye abonnementet ditt automatisk for %{strong}%{namespa
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr "Avgrein prosjekt"
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr "Webhooks"
msgid "Webhooks Help"
msgstr "Webhook-hjelp"
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr "Pushhendelser"
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr "Trigger"
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr "Wiki-sidehendelser"
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr "Nettsted"
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr "Hva vil du gjøre?"
msgid "What's new"
msgstr "Hva er nytt"
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr "Sak"
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr "Du bruker PostgreSQL %{pg_version_current}, men PostgreSQL %{pg_version_minimum} er påkrevd for denne versjonen av GitLab. Vennligst oppgrader ditt miljø til en støttet PostgreSQL-versjon, se %{pg_requirements_url} for detaljer."
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr "YouTube"
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr "Kontoen din er låst."
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr "Handlingen din lyktes."
@@ -46644,16 +47272,13 @@ msgstr "Din melding her"
msgid "Your name"
msgstr "Navnet ditt"
-msgid "Your new %{accessTokenType}"
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new %{type}"
-msgstr "Din nye %{type}"
-
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr "en slettet bruker"
@@ -46825,9 +47450,6 @@ msgstr[1] "omkring %d timer"
msgid "access:"
msgstr "tilgang:"
-msgid "added"
-msgstr "lagt til"
-
msgid "added %{emails}"
msgstr "la til %{emails}"
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr "tildel deg selv"
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr "kl."
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr "i faresonen"
-
msgid "attach a new file"
msgstr "legg ved en ny fil"
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr "kan ikke endres"
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr "Avhengighetsskanning"
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr "Ny"
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr "Sikkerhetsskanning"
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr "Løsning"
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr "commit %{commit_id}"
msgid "committed"
msgstr "forpliktet"
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] "dager"
msgid "days"
msgstr "dager"
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr "standardgren"
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] "fra %d jobb"
msgstr[1] "fra %d jobber"
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr "ugyldig milepælstilstand `%{state}`"
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr "er"
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr "er et ugyldig IP-adresseområde"
@@ -47753,6 +48423,9 @@ msgstr "er ikke"
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr "er ikke et gyldig X509-sertifikat."
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr "er skrivebeskyttet"
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr "%{mergeError}."
@@ -48090,6 +48766,9 @@ 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."
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr "Trekk tilbake godkjennelse"
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr "må være etter starten"
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr "må være høyere enn startdatoen"
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr "min-kanal"
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr "trenger oppmerksomhet"
-
msgid "needs to be between 10 minutes and 1 month"
msgstr "må være mellom 10 minutter og 1 måned"
@@ -48336,9 +49018,6 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}, og %{lastItem}"
-msgid "on track"
-msgstr "på sporet"
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr "eller"
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "overkategori"
@@ -48497,9 +49174,6 @@ msgstr "fjern startdato"
msgid "remove weight"
msgstr "fjern vektlegging"
-msgid "removed"
-msgstr "fjernet"
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr "kodelagre"
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr "kodelager:"
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr "tilfredsstilt"
@@ -48681,6 +49363,9 @@ msgstr "dette dokumentet"
msgid "time summary"
msgstr "tidsoppsummering"
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr "yaml er ugyldig"
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/nl_NL/gitlab.po b/locale/nl_NL/gitlab.po
index 92e99e1b842..2be1fb9ff49 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: 2022-10-10 14:04\n"
+"PO-Revision-Date: 2022-11-13 09:23\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d exporter"
msgstr[1] "%d exporters"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d opgelost testresultaat"
-msgstr[1] "%d opgeloste testresultaten"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} deelnemer"
msgstr[1] "%{count} deelnemers"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr "Voorwaarden accepteren"
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr "Actief"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "Bladeren in map"
@@ -7039,9 +7178,6 @@ msgstr "Bekijk bestand"
msgid "Browse Files"
msgstr "Door bestanden bladeren"
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr "Door bestanden bladeren"
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Using a static site?"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/or_IN/gitlab.po b/locale/or_IN/gitlab.po
index c45da23d6c7..4f68008552f 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: 2022-10-10 14:04\n"
+"PO-Revision-Date: 2022-11-13 09:24\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/pa_IN/gitlab.po b/locale/pa_IN/gitlab.po
index 663cd9071ff..594954e89de 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: 2022-10-10 14:04\n"
+"PO-Revision-Date: 2022-11-13 09:23\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/pa_PK/gitlab.po b/locale/pa_PK/gitlab.po
index d5c98b786df..36b8bd4ca03 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: 2022-10-10 14:06\n"
+"PO-Revision-Date: 2022-11-13 09:24\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/pl_PL/gitlab.po b/locale/pl_PL/gitlab.po
index b4a58f577da..413a80f75d8 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: 2022-10-10 14:03\n"
+"PO-Revision-Date: 2022-11-13 09:23\n"
msgid " %{start} to %{end}"
msgstr " %{start} do %{end}"
@@ -171,6 +171,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d zatwierdzajÄ…cy"
@@ -311,13 +318,6 @@ msgstr[1] "%d epiki"
msgstr[2] "%d epików"
msgstr[3] "%d epiku"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d błąd"
-msgstr[1] "%d błędy"
-msgstr[2] "%d błędów"
-msgstr[3] "%d błędu"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d eksporter"
@@ -325,13 +325,6 @@ msgstr[1] "%d eksportery"
msgstr[2] "%d eksporterów"
msgstr[3] "%d eksporteru"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] "%d nieudane zadanie bezpieczeństwa"
@@ -346,13 +339,6 @@ msgstr[1] "%d pliki"
msgstr[2] "%d plików"
msgstr[3] "%d pliku"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d poprawiony wynik testu"
-msgstr[1] "%d poprawione wyniki testu"
-msgstr[2] "%d poprawionych wyników testu"
-msgstr[3] "%d poprawionego wyniku testu"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -677,6 +663,9 @@ msgstr[1] "%{bold_start}%{count}%{bold_end} otwarte merge requesty"
msgstr[2] "%{bold_start}%{count}%{bold_end} otwartych merge requestów"
msgstr[3] "%{bold_start}%{count}%{bold_end} otwartego merge requesta"
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr "%{code_open} Maskowanie:%{code_close} Ukryte w logu zadań. Musi spełnić wymagania maskowania."
@@ -737,6 +726,20 @@ msgstr[3] ""
msgid "%{count} files touched"
msgstr "%{count} plików zmieniono"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "%{count} element"
@@ -747,6 +750,13 @@ msgstr[3] "%{count} elementu"
msgid "%{count} items per page"
msgstr "%{count} elementy na stronie"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} more"
msgstr "%{count} więcej"
@@ -773,6 +783,13 @@ msgstr[1] "%{count} uczestnicy"
msgstr[2] "%{count} uczestników"
msgstr[3] "%{count} uczestnika"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} powiÄ…zanych %{pluralized_subject}: %{links}"
@@ -812,9 +829,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr "%{due_date} (zaległe)"
-
msgid "%{duration}ms"
msgstr "%{duration}ms"
@@ -1025,12 +1039,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr "%{name} (Zajęte)"
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} zawierało %{resultsString}"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} znalazło %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr "%{name} jest już używane w innym emoji"
@@ -1230,6 +1238,9 @@ msgstr[3] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1388,9 +1399,6 @@ msgstr "%{user} utworzył(a) zgłoszenie: %{issue_link}"
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr "%{value} s"
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} %{time_spent_value} wykorzystanego czasu."
@@ -1448,6 +1456,9 @@ msgstr "'%{source}' nie jest źródłem importu"
msgid "'%{template_name}' is unknown or invalid"
msgstr "'%{template_name}' jest nieznany lub nieprawidłowy"
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d zamknięte)"
@@ -1488,6 +1499,9 @@ msgstr "(pozostaw puste, jeśli nie chcesz tego zmieniać)"
msgid "(max size 15 MB)"
msgstr "(maksymalny rozmiar 15 MB)"
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1827,6 +1841,9 @@ msgstr "Nie posiadasz uprawnień dostępu do tej strony."
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1890,9 +1907,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "Domyślny branch nie może być wybrany dla pustego projektu."
-
msgid "A deleted user"
msgstr "Usunięty użytkownik"
@@ -1971,9 +1985,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr "Zwykła strona HTML, która używa Netlify dla CI/CD zamiast GitLab'a, ale nadal ze wszystkimi innymi wspaniałymi funkcjami GitLab"
-msgid "A platform value can be web, mob or app."
-msgstr "Wartością platformy może być internet, mob lub aplikacja."
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr "Projekt standardowy dla rozwoju aplikacji Salesforce z narzędziami Salesforce Developer"
@@ -2181,6 +2192,9 @@ msgstr "Zaakceptuj warunki"
msgid "Acceptable for use in this project"
msgstr "Akceptowalne do użycia w tym projekcie"
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2292,15 +2306,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr "Dowiedz się więcej"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "Wiadomość: %{message}"
-msgid "AccessibilityReport|New"
-msgstr "Nowy"
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr "Skanowanie dostępności znalazło błąd następującego typu: %{code}"
@@ -2370,9 +2378,6 @@ msgstr "Aktywne"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr "Aktywne %{type} (%{token_length})"
-
msgid "Active Sessions"
msgstr "Aktywne Sesje"
@@ -2745,6 +2750,12 @@ msgstr "Dodaje %{labels} %{label_text}."
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2928,6 +2939,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2964,15 +2993,27 @@ msgstr "Automatyczna domena DevOps"
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -3021,6 +3062,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -3066,6 +3110,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr "Zachowaj ostatnie artefakty dla wszystkich zadań w ostatnich udanych potokach"
@@ -3204,9 +3260,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -3231,6 +3296,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3333,6 +3407,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr "Zatwierdź"
@@ -3525,8 +3602,8 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr "Przywróć dostęp użytkownika do konta, w tym strony internetowej, Git i API."
-msgid "AdminUsers|Search by name, email or username"
-msgstr "Wyszukaj według nazwy, adresu e-mail lub nazwy użytkownika"
+msgid "AdminUsers|Search by name, email, or username"
+msgstr ""
msgid "AdminUsers|Search users"
msgstr "Wyszukaj użytkowników"
@@ -3570,8 +3647,8 @@ msgstr "Użytkownik nie otrzyma żadnych powiadomień"
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "Aby potwierdzić, wpisz %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr ""
msgid "AdminUsers|Unban user"
msgstr ""
@@ -3633,7 +3710,7 @@ msgstr "Bez projektów"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3681,6 +3758,9 @@ msgstr "Administracja"
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -4191,7 +4271,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -4206,6 +4286,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr "Pozwól właścicielom grupy na zarządzanie ustawieniami związanymi z LDAP"
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -4242,9 +4325,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4491,6 +4571,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4678,9 +4761,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4780,9 +4860,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4885,9 +4962,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr "Aktualizacja ustawień aplikacji nie powiodła się"
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4906,7 +4980,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4953,6 +5027,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4971,9 +5048,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -5001,6 +5087,9 @@ msgstr "Zapisz zmiany"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5351,9 +5440,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5457,7 +5543,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5508,6 +5594,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5559,9 +5669,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5961,9 +6068,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6327,6 +6431,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -7063,6 +7173,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -7072,6 +7185,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -7093,6 +7209,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -7111,6 +7230,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -7120,6 +7242,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -7138,9 +7263,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -7159,12 +7290,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7324,6 +7464,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7333,9 +7476,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7381,9 +7521,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7414,6 +7551,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7429,6 +7569,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7453,9 +7596,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7871,9 +8011,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7889,6 +8026,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8632,6 +8772,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9951,10 +10094,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -10138,6 +10287,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10939,10 +11091,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10975,6 +11127,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -11023,9 +11184,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -11110,9 +11268,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -11275,9 +11430,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11497,9 +11649,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11767,9 +11916,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11785,7 +11931,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11887,9 +12033,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -12218,6 +12361,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -12245,6 +12391,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -12302,6 +12451,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12536,6 +12688,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12756,6 +12911,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12843,6 +13001,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12876,6 +13037,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12987,6 +13151,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -13008,9 +13175,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -13077,7 +13241,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13566,6 +13730,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13653,6 +13820,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13997,6 +14179,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -14239,6 +14424,12 @@ msgstr[3] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -14254,6 +14445,9 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
@@ -14261,6 +14455,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14868,6 +15065,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -15198,22 +15401,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Using a static site?"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15441,6 +15662,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15621,10 +15845,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15639,18 +15863,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15663,18 +15878,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15804,9 +16013,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15870,9 +16076,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -16113,6 +16316,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -16234,6 +16488,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -16291,9 +16548,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16520,6 +16783,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16569,9 +16835,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16767,9 +17030,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -17029,6 +17289,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17134,9 +17397,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -17344,6 +17604,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -18185,9 +18448,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -18314,6 +18574,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18365,6 +18631,9 @@ 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 ""
@@ -18413,9 +18682,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18971,9 +19237,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18983,6 +19246,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19745,12 +20011,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19820,6 +20080,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -20002,9 +20265,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20463,7 +20723,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20550,12 +20816,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -22315,6 +22575,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -22333,9 +22596,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22393,7 +22653,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22475,19 +22735,16 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22625,12 +22882,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22652,6 +22915,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22877,6 +23152,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -23171,6 +23461,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23501,6 +23794,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23540,9 +23836,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23923,9 +24225,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -24079,6 +24378,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24229,9 +24537,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24490,6 +24795,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24760,9 +25071,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24775,6 +25083,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24811,7 +25122,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24826,9 +25143,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24838,9 +25161,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24850,7 +25170,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24907,6 +25227,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24931,6 +25254,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24982,6 +25308,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24994,6 +25323,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25626,6 +25958,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25851,6 +26186,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -26246,6 +26584,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26405,6 +26746,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26477,6 +26821,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26663,6 +27010,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -27127,6 +27477,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -27256,9 +27609,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -27286,9 +27636,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -27304,9 +27651,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27542,7 +27886,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27885,6 +28229,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27894,6 +28241,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27915,6 +28265,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -28008,9 +28361,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -28035,9 +28385,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -28273,12 +28620,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28324,12 +28665,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28351,12 +28686,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28399,15 +28728,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28438,12 +28758,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28462,9 +28776,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28640,9 +28951,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -29013,12 +29321,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -29064,6 +29381,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -29212,6 +29535,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29597,12 +29923,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29651,7 +29971,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29870,6 +30190,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29885,6 +30208,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29897,12 +30223,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29912,9 +30244,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30674,9 +31012,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30785,6 +31120,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30926,6 +31324,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -31019,12 +31420,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31601,6 +32008,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31613,6 +32023,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31895,12 +32308,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31913,12 +32332,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31940,6 +32365,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -32039,6 +32467,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -32177,6 +32608,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -32207,6 +32641,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -32258,6 +32695,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32897,6 +33337,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32933,15 +33376,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32957,12 +33412,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -33272,6 +33736,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33404,12 +33871,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33503,9 +33964,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33673,6 +34131,9 @@ msgstr[3] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33682,6 +34143,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -34138,6 +34602,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -34154,13 +34621,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -34192,18 +34652,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34218,12 +34672,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -34266,21 +34714,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr "Wyniki podsumowania testu sÄ… analizowane"
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34296,9 +34735,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr "brak zmienionych wyników testów"
-
msgid "Repositories"
msgstr ""
@@ -34678,6 +35114,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34911,6 +35350,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34951,6 +35393,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34983,7 +35428,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -35194,6 +35639,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -35324,9 +35772,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -35375,6 +35829,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -35412,6 +35869,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -35451,12 +35911,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35511,16 +35965,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35628,10 +36088,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35652,9 +36112,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35664,9 +36130,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35817,9 +36289,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -36248,10 +36717,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -36371,6 +36843,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36473,10 +36948,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36566,7 +37041,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36584,6 +37059,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36602,12 +37080,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36629,6 +37116,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36758,6 +37248,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36815,6 +37308,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36932,9 +37428,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36947,6 +37449,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -37010,9 +37515,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -37151,10 +37653,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -37166,28 +37668,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37406,9 +37908,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37560,9 +38059,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37819,10 +38315,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37876,7 +38369,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37891,7 +38384,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -38014,9 +38507,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -38239,6 +38729,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38350,9 +38843,6 @@ msgstr "Coś poszło nie tak podczas pobierania środowisk dla tego żądania sc
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38926,9 +39416,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38941,9 +39428,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38965,9 +39449,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39487,9 +39968,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39749,6 +40236,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39839,6 +40329,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39923,6 +40416,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39944,15 +40440,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39974,9 +40464,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "Napisz swoje uwagi do wydania lub przeciągnij pliki tutaj…"
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39995,6 +40482,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -40106,20 +40596,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -40143,12 +40619,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -40236,12 +40706,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40706,6 +41170,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40901,9 +41368,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40934,7 +41398,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40991,9 +41455,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -41345,9 +41806,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -41381,6 +41839,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41549,9 +42010,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41612,6 +42070,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41828,13 +42289,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41963,9 +42427,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41984,6 +42445,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42358,9 +42822,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42466,6 +42927,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42532,9 +42996,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42556,18 +43044,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42580,6 +43089,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42730,9 +43257,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -43055,6 +43579,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43559,6 +44089,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43661,6 +44197,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43691,6 +44230,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44747,9 +45289,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -45213,6 +45752,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -45231,6 +45773,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -45366,7 +45911,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45408,6 +45953,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -45423,12 +45971,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45468,6 +46028,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45582,6 +46145,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45609,9 +46178,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45624,7 +46190,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45636,12 +46202,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45720,6 +46295,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45729,7 +46307,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -46049,6 +46627,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -46101,9 +46685,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -46134,10 +46733,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -46149,6 +46751,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -46170,6 +46775,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -46188,6 +46796,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -46285,6 +46896,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -46321,6 +46935,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46366,9 +46986,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -46472,6 +47089,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46544,7 +47164,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46568,6 +47188,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46713,6 +47336,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46776,7 +47402,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46944,9 +47570,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -47058,6 +47681,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -47180,16 +47806,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47280,6 +47903,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47349,9 +47975,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -47365,9 +47988,6 @@ msgstr[3] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -47429,6 +48049,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -47438,9 +48064,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -47523,6 +48146,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47764,12 +48393,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47846,6 +48490,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47876,6 +48523,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47891,6 +48541,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47967,6 +48620,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -48028,6 +48684,9 @@ msgstr[3] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -48190,6 +48849,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -48294,12 +48956,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -48321,6 +48989,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -48345,12 +49016,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -48513,9 +49190,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48668,6 +49342,9 @@ 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 ""
@@ -48764,9 +49441,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48830,6 +49504,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48842,9 +49519,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48863,9 +49546,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48914,9 +49594,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48935,19 +49612,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -49083,9 +49756,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -49108,12 +49778,22 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -49271,6 +49951,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -49411,6 +50094,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/pt_BR/gitlab.po b/locale/pt_BR/gitlab.po
index 5ce8bc30ef9..503484c3701 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: 2022-10-10 14:00\n"
+"PO-Revision-Date: 2022-11-13 09:21\n"
msgid " %{start} to %{end}"
msgstr " %{start} até %{end}"
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] "%d usuário adicional"
msgstr[1] "%d usuários adicionais"
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] "%d aprovação necessária"
+msgstr[1] "%d aprovações necessárias"
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d aprovador"
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] "%d épico"
msgstr[1] "%d épicos"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d: erro"
-msgstr[1] "%d: erros"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d exporter"
msgstr[1] "%d exporters"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%d falha"
-msgstr[1] "%d falhas"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] "%d tarefa de segurança com falha"
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] "%d arquivo"
msgstr[1] "%d arquivos"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d resultado do teste corrigido"
-msgstr[1] "%d resultados do teste corrigidos"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] "%{bold_start}%{count}%{bold_end} solicitação de mesclagem aberta"
msgstr[1] "%{bold_start}%{count}%{bold_end} solicitações de mesclagem abertas"
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr "%{code_open}Mascarado:%{code_close} Escondidos nos logs de tarefas. Deve corresponder a requisitos de mascaramento."
@@ -567,6 +560,16 @@ msgstr[1] "%{count} contatos"
msgid "%{count} files touched"
msgstr "%{count} arquivos modificados"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] "%{count} grupo"
+msgstr[1] "%{count} grupos"
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] "%{count} issue"
+msgstr[1] "%{count} issues"
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "%{count} item"
@@ -575,6 +578,11 @@ msgstr[1] "%{count} itens"
msgid "%{count} items per page"
msgstr "%{count} itens por página"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] "%{count} solicitação de mesclagem"
+msgstr[1] "%{count} solicitações de mesclagem"
+
msgid "%{count} more"
msgstr "mais %{count}"
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} participante"
msgstr[1] "%{count} participantes"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] "%{count} projeto"
+msgstr[1] "%{count} projetos"
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} %{pluralized_subject} relacionados: %{links}"
@@ -636,9 +649,6 @@ msgstr "%{docs_link_start}O que é armazenamento de arquivos grandes?%{docs_link
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr "%{docs_link_start}O que é autenticação de dois fatores?%{docs_link_end}"
-msgid "%{due_date} (Past due)"
-msgstr "%{due_date} (vencido)"
-
msgid "%{duration}ms"
msgstr "%{duration}ms"
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr "%{name} (Ocupado)"
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} continha %{resultsString}"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} encontrou %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr "%{name} já está sendo usado para outro emoji"
@@ -962,10 +966,10 @@ msgid "%{retryButtonStart}Try again%{retryButtonEnd} or %{newFileButtonStart}att
msgstr "%{retryButtonStart}Tente novamente%{retryButtonEnd} ou %{newFileButtonStart}anexe um novo arquivo%{newFileButtonEnd}."
msgid "%{rotation} has been recalculated with the remaining participants. Please review the new setup for %{rotation_link}. It is recommended that you reach out to the current on-call responder to ensure continuity of on-call coverage."
-msgstr ""
+msgstr "%{rotation} foi recalculado com os participantes restantes. Por favor, revise a nova configuração para %{rotation_link}. É recomendável que você entre em contato com um plantonista para garantir a continuidade do chamado."
msgid "%{rotation} has been recalculated with the remaining participants. Please review the new setup for %{rotation}. It is recommended that you reach out to the current on-call responder to ensure continuity of on-call coverage."
-msgstr ""
+msgstr "%{rotation} foi recalculado com os participantes restantes. Por favor, revise a nova configuração para %{rotation}. É recomendável que você entre em contato com o plantonista para garantir continuidade do chamado."
msgid "%{runner} created %{timeago}"
msgstr "%{runner} criou %{timeago}"
@@ -983,8 +987,8 @@ msgstr[1] "%{securityScanner} não estão ativados para este projeto. %{linkStar
msgid "%{securityScanner} result is not available because a pipeline has not been run since it was enabled. %{linkStart}Run a pipeline%{linkEnd}"
msgid_plural "%{securityScanner} results are not available because a pipeline has not been run since it was enabled. %{linkStart}Run a pipeline%{linkEnd}"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "O resultado %{securityScanner} não está disponível pois um pipeline não foi executado desde que foi ativado. %{linkStart}Executar um pipeline%{linkEnd}"
+msgstr[1] "Os resultados %{securityScanner} não estão disponíveis porque um pipeline não foi executado desde que foi ativado. %{linkStart}Executar um pipeline%{linkEnd}"
msgid "%{selectedLabelsCount} label"
msgid_plural "%{selectedLabelsCount} labels"
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "%{strong_start}%{branch_count}%{strong_end} Branch"
@@ -1182,9 +1189,6 @@ msgstr "%{user} criou uma issue: %{issue_link}"
msgid "%{value} is not included in the list"
msgstr "%{value} não está incluído na lista"
-msgid "%{value} s"
-msgstr "%{value} s"
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} %{time_spent_value} tempo gasto."
@@ -1242,6 +1246,9 @@ msgstr "'%{source}' não é uma fonte de importação"
msgid "'%{template_name}' is unknown or invalid"
msgstr "'%{template_name}' é desconhecido ou inválido"
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d fechado)"
@@ -1280,6 +1287,9 @@ msgstr "(Deixe em branco se não quiser alterá-lo)"
msgid "(max size 15 MB)"
msgstr "(tamanho máximo de 15MB)"
+msgid "(no user)"
+msgstr "(sem usuário)"
+
msgid "(optional)"
msgstr "(opcional)"
@@ -1565,6 +1575,9 @@ msgstr "Você não tem permissão para acessar essa página."
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "Certifique-se de que o endereço está correto e a página não foi movida."
+msgid "404|Not found"
+msgstr "Não encontrado"
+
msgid "404|Page Not Found"
msgstr "Página não encontrada"
@@ -1628,9 +1641,6 @@ msgstr "Uma issue confidencial não pode ter um pai que já tenha filhos não co
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "Um branch padrão não pode ser escolhido para um projeto vazio."
-
msgid "A deleted user"
msgstr "Um usuário excluído"
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr "Um projeto modelo para desenvolvimento de aplicativos Salesforce com as ferramentas de desenvolvedor Salesforce"
@@ -1919,6 +1926,9 @@ msgstr "Aceitar os temos"
msgid "Acceptable for use in this project"
msgstr "Aceitável para uso neste projeto"
+msgid "Access Denied"
+msgstr "Acesso negado"
+
msgid "Access Git repositories or the API."
msgstr "Acessar repositórios Git ou a API."
@@ -1992,7 +2002,7 @@ msgid "AccessTokens|Incoming email token"
msgstr "Token de e-mail recebido"
msgid "AccessTokens|It cannot be used to access any other data."
-msgstr "Ele não pode ser usado para acessar outros dados."
+msgstr "Não pode ser usado para acessar outros dados."
msgid "AccessTokens|Keep this token secret. Anyone who has it can access repository static objects as if they were you. If that ever happens, %{linkStart}reset this token%{linkEnd}."
msgstr "Mantenha este token em segredo. Qualquer pessoa que o tiver poderá acessar objetos estáticos do repositório como se fosse você. Se isso acontecer,%{linkStart} reinicie este token%{linkEnd}."
@@ -2030,15 +2040,9 @@ msgstr "Seu token de e-mail de entrada autentica você quando você cria um novo
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr "Saiba mais"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "Mensagem: %{message}"
-msgid "AccessibilityReport|New"
-msgstr "Novo"
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr "A verificação de acessibilidade encontrou um erro do seguinte tipo: %{code}"
@@ -2108,9 +2112,6 @@ msgstr "Ativo"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr "Ativo %{accessTokenTypePlural} (%{totalAccessTokens})"
-msgid "Active %{type} (%{token_length})"
-msgstr "Ativo %{type} (%{token_length})"
-
msgid "Active Sessions"
msgstr "Sessões ativas"
@@ -2130,7 +2131,7 @@ msgid "Add \"%{value}\""
msgstr "Adicionar \"%{value}\""
msgid "Add %{linkStart}assets%{linkEnd} to your Release. GitLab automatically includes read-only assets, like source code and release evidence."
-msgstr ""
+msgstr "Adicionar %{linkStart}ativos%{linkEnd} para sua versão. GitLab inclui automaticamente ativos somente leitura, como evidência de código-fonte e lançamento."
msgid "Add CHANGELOG"
msgstr "Adicionar CHANGELOG"
@@ -2483,6 +2484,12 @@ msgstr "Adiciona %{labels} %{label_text}."
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr "Adiciona um link de recurso"
+
+msgid "Adds a resource link for this incident."
+msgstr "Adiciona um link de recurso para este incidente."
+
msgid "Adds a timeline event to incident."
msgstr "Adiciona um evento de linha do tempo ao incidente."
@@ -2666,6 +2673,24 @@ msgstr "Você parará todas as tarefas. Os processos em execução serão abrupt
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr "Erro ao carregar as estatísticas. Por favor, tente novamente"
+msgid "AdminEmail|Body"
+msgstr "Corpo"
+
+msgid "AdminEmail|Body is required."
+msgstr "O corpo é obrigatório."
+
+msgid "AdminEmail|Recipient group or project"
+msgstr "Grupo ou projeto de destinatários"
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr "Grupo de destinatários ou projeto é obrigatório."
+
+msgid "AdminEmail|Subject"
+msgstr "Assunto"
+
+msgid "AdminEmail|Subject is required."
+msgstr "Assunto é obrigatório."
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr "Domínio de Auto DevOps"
msgid "AdminSettings|CI/CD limits"
msgstr "Limites de CI/CD"
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr "Configurar Let's Encrypt"
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr "Configure limites no número de repositórios que os usuários podem baixar em um determinado momento."
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr "Configure análises de produtos para acompanhar eventos em seus aplicativos de projeto."
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr "Configurar quando projetos inativos devem ser excluídos automaticamente. %{linkStart}O que são projetos inativos?%{linkEnd}"
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr "Excluir projetos Inativos"
@@ -2759,6 +2796,9 @@ msgstr "Ativar analisador personalizado de kuromoji: Pesquisa"
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr "Ativar banner de sugestão de pipeline"
+msgid "AdminSettings|Enable product analytics"
+msgstr "Ativar análise de produtos"
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr "Ativar executores compartilhados para novos projetos"
@@ -2804,6 +2844,18 @@ msgstr "Exclusão de projeto inativo"
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr "Manter os artefatos mais recentes para todas as tarefas nos pipelines de sucesso mais recentes"
@@ -2919,7 +2971,7 @@ msgid "AdminSettings|Set limit to 0 to disable it."
msgstr "Defina o limite como 0 para desativá-lo."
msgid "AdminSettings|Set the expiration time of authentication tokens of newly registered group runners."
-msgstr ""
+msgstr "Defina o tempo de expiração dos tokens de autenticação de executores de grupo recém-registrados."
msgid "AdminSettings|Set the expiration time of authentication tokens of newly registered instance runners. Authentication tokens are automatically reset at these intervals."
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr "A configuração deve ser maior que 0."
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr "Configurações de tamanho e domínio para sites estáticos do Pages."
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr "O domínio padrão a ser usado para os estágios de Auto Review Apps e Auto Deploy em todos os projetos."
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr "Os artefatos mais recentes de todas as tarefas dos pipelines mais recentes em cada projeto são armazenados e não expiram."
@@ -2969,6 +3030,15 @@ msgstr "Número total de tarefas em pipelines ativos no momento"
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr "Usar o AWS OpenSearch Service com credenciais do IAM"
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr "Usuários e grupos devem aceitar o convite antes de serem adicionados a um grupo ou projeto."
@@ -3071,6 +3141,9 @@ msgstr "Administrador"
msgid "AdminUsers|Admins"
msgstr "Administradores"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr "Aprovar"
@@ -3120,7 +3193,7 @@ msgid "AdminUsers|Blocking user has the following effects:"
msgstr "Bloquear o usuário tem os seguintes efeitos:"
msgid "AdminUsers|Bot"
-msgstr ""
+msgstr "Robô"
msgid "AdminUsers|Can create group"
msgstr "Pode criar grupo"
@@ -3263,8 +3336,8 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr "Restaurar o acesso do usuário para a conta, incluindo a web, o Git e a API."
-msgid "AdminUsers|Search by name, email or username"
-msgstr "Procure por nome, e-mail ou nome de usuário"
+msgid "AdminUsers|Search by name, email, or username"
+msgstr "Procurar por nome, e-mail ou nome de usuário"
msgid "AdminUsers|Search users"
msgstr "Procurar usuários"
@@ -3308,8 +3381,8 @@ msgstr "O usuário não receberá nenhuma notificações"
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "Para confirmar, digite %{projectName}"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "Para confirmar, digite %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr "Para confirmar, digite %{username}."
msgid "AdminUsers|Unban user"
msgstr "Desbanir usuário"
@@ -3371,8 +3444,8 @@ msgstr "Sem projetos"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr "Você está prestes a apagar permanentemente o usuário %{username}. Issues, merge requests e grupos vinculados a eles serão transferidos para um \"usuário fantasma\" em todo o sistema. Para evitar a perda de dados, considere usar o recurso %{strongStart}bloquear usuário%{strongEnd}. Assim que %{strongStart}Apagar usuário%{strongEnd}, não poderá ser desfeito ou recuperado."
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
-msgstr "Você está prestes a apagar o usuário permanentemente %{username}. Isto irá deletar todas as issues, merge requests e grupos ligados a eles. Para evitar a perda de dados, considere utilizar o recurso %{strongStart}bloqueio de usuário%{strongEnd}. Uma vez que você %{strongStart}Deletar o usuário%{strongEnd}, o mesmo não poderá ser desfeito ou recuperado."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
+msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
msgstr "Você sempre pode bloquear suas contas novamente, se necessário."
@@ -3419,6 +3492,9 @@ msgstr "Administração"
msgid "Administrators"
msgstr "Administradores"
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr "Usuários adicionais devem ser revisados e aprovados por um administrador do sistema. Saiba mais sobre %{help_link_start}limites de uso%{help_link_end}."
@@ -3468,7 +3544,7 @@ msgid "AdvancedSearch|Pause indexing and upgrade Elasticsearch to a supported ve
msgstr ""
msgid "AdvancedSearch|Reindex recommended"
-msgstr ""
+msgstr "Reindexação recomendada"
msgid "AdvancedSearch|Reindex required"
msgstr ""
@@ -3711,7 +3787,7 @@ msgid "AlertSettings|Enter integration name"
msgstr "Insira o nome da integração"
msgid "AlertSettings|Free versions of GitLab are limited to one integration per type. To add more, %{linkStart}upgrade your subscription%{linkEnd}."
-msgstr ""
+msgstr "Versões gratuitas do GitLab são limitadas a uma integração por tipo. Para adicionar mais, %{linkStart}atualize sua assinatura%{linkEnd}."
msgid "AlertSettings|GitLab has created a URL and authorization key for your integration. You can use them to set up a webhook and authorize your endpoint to send alerts to GitLab."
msgstr "O GitLab criou um URL e uma chave de autorização para sua integração. Você pode usá-los para configurar um webhook e autorizar o seu endpoint para enviar alertas para o GitLab."
@@ -3929,8 +4005,8 @@ msgstr "Todos os usuários devem ter um nome."
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
-msgstr "Permitir que \"%{group_name}\" adicione você"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr ""
msgid "Allow access to members of the following group"
msgstr "Permitir o acesoaos membros do seguinte grupo"
@@ -3944,6 +4020,9 @@ msgstr "Permitir commits de membros que podem mesclar na ramificação de destin
msgid "Allow group owners to manage LDAP-related settings"
msgstr "Permitir que proprietários de grupos gerenciem configurações relacionadas ao LDAP"
+msgid "Allow new users to create top-level groups"
+msgstr "Permitir que novos usuários criem grupos de nível superior"
+
msgid "Allow non-administrators access to the performance bar"
msgstr "Permitir que não administradores acessem a barra de desempenho"
@@ -3980,9 +4059,6 @@ msgstr "Permitir que esta chave faça push para este repositório"
msgid "Allow use of licensed EE features"
msgstr "Permitir o uso de funcionalidades da licença EE"
-msgid "Allow users to create top-level groups"
-msgstr "Permitir que os usuários criem grupos de nível superior"
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4005,7 +4081,7 @@ msgid "Allowed to fail"
msgstr "Permitido falhar"
msgid "Allows projects or subgroups in this group to override the global setting."
-msgstr ""
+msgstr "Permite que projetos ou subgrupos neste grupo substituam a configuração global."
msgid "Allows projects to track errors using an Opstrace integration."
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr "Ocorreu um erro ao obter as tags. Tente novamente a pesquisa."
msgid "An error occurred while fetching terraform reports."
msgstr "Ocorreu um erro ao obter os relatórios de terraform."
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr "Ocorreu um erro na recuperação de registros da tarefa."
@@ -4414,9 +4493,6 @@ msgstr "Ocorreu um erro ao disparar a tarefa."
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr "Ocorreu um erro ao tentar gerar o relatório. Por favor, tente novamente mais tarde."
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr "Ocorreu um erro desconhecido."
msgid "Analytics"
msgstr "Telemetria"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "Analise suas dependências em busca de vulnerabilidades conhecidas."
@@ -4621,9 +4694,6 @@ msgstr "As configurações do aplicativo foram salvas com sucesso."
msgid "Application settings update failed"
msgstr "Falha na atualização de configurações da aplicação"
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr "Aplicativo desinstalado, mas falhou em destruir: %{error_message}"
-
msgid "Application was successfully destroyed."
msgstr "Aplicação foi destruída com sucesso."
@@ -4642,8 +4712,8 @@ msgstr "Adicionar um link para o Grafana"
msgid "ApplicationSettings|After sign-up text"
msgstr "Após o texto de inscrição"
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
-msgstr "Depois que a instância atinge o limite de usuários, qualquer usuário adicionado ou solicita acesso deve ser aprovado por um administrador. Deixe em branco para ilimitado."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
+msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
msgstr "Domínios permitidos para inscrições"
@@ -4685,6 +4755,9 @@ msgstr "Arquivo de lista de restrição"
msgid "ApplicationSettings|Domain denylist"
msgstr "Lista de restrição de domínio"
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr "Configurações de confirmação de e-mail"
+
msgid "ApplicationSettings|Email restrictions"
msgstr "Restrições de e-mail"
@@ -4703,9 +4776,18 @@ msgstr "Ativar restrições de e-mail para cadastro"
msgid "ApplicationSettings|Enter denylist manually"
msgstr "Inserir lista de restrição manualmente"
+msgid "ApplicationSettings|Hard"
+msgstr "Difícil"
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr "Comprimento mínimo de senha (número de caracteres)"
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr "ConfiguDesativado"
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr "Somente usuários com endereços de e-mail que correspondam a esses domínios podem se inscrever. Caracteres curinga permitidos. Use linhas separadas para várias entradas. Exemplo: domínio.com, *.domínio.com"
@@ -4733,6 +4815,9 @@ msgstr "Salvar mudanças"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr "Enviar e-mail de confirmação no cadastro"
@@ -5073,9 +5158,6 @@ 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 these artifacts?"
-msgstr "Você tem certeza que deseja excluir estes artefatos?"
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,8 +5259,8 @@ msgstr "Tem certeza de que deseja repetir esta migração?"
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr "Tem certeza de que deseja revogar este %{accessTokenType}? Essa ação não pode ser desfeita."
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
-msgstr "Tem certeza de que deseja revogar este %{type}? Essa ação não pode ser desfeita."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
+msgstr "Tem certeza de que deseja revogar este token de acesso ao grupo? Esta ação não pode ser desfeita."
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr "Tem certeza de que deseja revogar este token de acesso pessoal? Esta ação não pode ser desfeita."
@@ -5228,6 +5310,30 @@ msgstr "O artefato foi excluído com sucesso."
msgid "Artifacts"
msgstr "Artefatos"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr "Artefatos"
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr "Excluir %{name}?"
+
+msgid "Artifacts|Delete artifact"
+msgstr "Excluir artefato"
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr "Este artefato será excluído permanentemente. Quaisquer relatórios gerados a partir deste artefato estarão vazios."
+
+msgid "Artifacts|Total artifacts size"
+msgstr "Tamanho total dos artefatos"
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr "À medida que continuamos a construir mais recursos para SAST, adoraríamos seu feedback sobre o recurso de configuração SAST %{linkStart}nessa issue%{linkEnd}."
@@ -5279,9 +5385,6 @@ msgstr "Coloque uma cor personalizada, como #FF0000"
msgid "Assign labels"
msgstr "Atribuir etiquetas"
-msgid "Assign milestone"
-msgstr "Atribuir marco"
-
msgid "Assign myself"
msgstr "Atribuir a mim"
@@ -5675,9 +5778,6 @@ msgstr "Parada automática cancelada com sucesso."
msgid "Auto-cancel redundant pipelines"
msgstr "Cancelar automaticamente os pipelines redundantes"
-msgid "Auto-close referenced issues on default branch"
-msgstr "Fechar automaticamente as issues referenciadas na ramificação padrão"
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr "%{auto_devops_start}Automatiza a construção, testes e implantação de%{auto_devops_end} seus aplicativos com base na sua integração contínua e configuração de entrega. %{quickstart_start}Como eu começo?%{quickstart_end}"
@@ -5718,7 +5818,7 @@ msgid "AutoRemediation|Auto-fix solutions"
msgstr ""
msgid "AutoRemediation|If you're using dependency and/or container scanning, and auto-fix is enabled, auto-fix automatically creates merge requests with fixes to vulnerabilities."
-msgstr ""
+msgstr "Se você está usando dependência e/ou escaneamento de contêiner, e a correção automática estiver habilitada, a correção automática cria solicitações de mesclagem com correções para vulnerabilidades."
msgid "AutoRemediation|Introducing GitLab auto-fix"
msgstr ""
@@ -6041,6 +6141,12 @@ 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 enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr "Antes de ativar esta integração, crie um webhook para a sala no Google Chat onde você deseja receber notificações deste projeto. %{docs_link}"
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr "Branch já utilizada"
msgid "Branch name"
msgstr "Nome da ramificação"
+msgid "Branch name template"
+msgstr "Modelo de nome de ramificação"
+
msgid "Branch not loaded - %{branchId}"
msgstr "Branch não carregado - %{branchId}"
@@ -6791,52 +6903,61 @@ msgid "BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or productio
msgstr ""
msgid "BranchRules|All branches"
-msgstr ""
+msgstr "Todas as ramificações"
msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
+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}."
+msgid "BranchRules|Allowed to force push"
+msgstr "Permitido forçar push"
+
msgid "BranchRules|Allowed to merge"
msgstr "Permitido para mesclar"
msgid "BranchRules|Allowed to merge (%{total})"
-msgstr ""
+msgstr "Permitido para mesclar (%{total})"
msgid "BranchRules|Allowed to push"
msgstr "Permitido push"
msgid "BranchRules|Allowed to push (%{total})"
-msgstr ""
+msgstr "Permitido push (%{total})"
msgid "BranchRules|An error occurred while fetching branches."
msgstr ""
msgid "BranchRules|Approvals"
+msgstr "Aprovações"
+
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
msgid "BranchRules|Branch"
-msgstr ""
+msgstr "Ramificação"
msgid "BranchRules|Branch name or pattern"
msgstr ""
msgid "BranchRules|Branch rules details"
+msgstr "Detalhes das regras de ramificação"
+
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
msgid "BranchRules|Create wildcard: %{searchTerm}"
-msgstr ""
+msgstr "Criar curinga: %{searchTerm}"
msgid "BranchRules|Details"
msgstr "Detalhes"
msgid "BranchRules|Force push"
-msgstr ""
+msgstr "Forçar push"
msgid "BranchRules|Force push is not allowed."
-msgstr ""
+msgstr "Forçar push não é permitido."
msgid "BranchRules|Groups"
msgstr "Grupos"
@@ -6844,17 +6965,23 @@ msgstr "Grupos"
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
+msgstr "Gerenciar em ramificações protegidos"
+
+msgid "BranchRules|Manage in Status checks"
msgstr ""
msgid "BranchRules|No data to display"
-msgstr ""
+msgstr "Nenhum dado para exibir"
msgid "BranchRules|No matching results"
-msgstr ""
+msgstr "Nenhum resultado correspondente"
msgid "BranchRules|Protect branch"
-msgstr ""
+msgstr "Proteger ramificação"
msgid "BranchRules|Protections"
msgstr "Proteções"
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr "Aprovações necessárias (%{total})"
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr "Requer aprovação de CODEOWNERS"
+
msgid "BranchRules|Roles"
msgstr "Cargos"
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr "Transmissão de messagem foi atualizada com sucesso."
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "Navegar no Diretório"
@@ -7039,9 +7178,6 @@ msgstr "Acessar arquivo"
msgid "Browse Files"
msgstr "Acessar arquivos"
-msgid "Browse artifacts"
-msgstr "Navegar pelos artefatos"
-
msgid "Browse files"
msgstr "Navegar pelos arquivos"
@@ -7087,9 +7223,6 @@ msgstr "Filtrar por grupo de fonte"
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr "Do grupo de origem"
-
msgid "BulkImport|Group import history"
msgstr "Histórico de importação de grupo"
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr "Novo grupo"
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr "Caminho do novo grupo."
+
msgid "BulkImport|Project import history"
msgstr "Histórico de importação do projeto"
@@ -7159,9 +7298,6 @@ msgstr "Grupo de fonte"
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr "Para um novo grupo"
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7366,7 +7502,7 @@ msgid "CICD|Limit CI_JOB_TOKEN access"
msgstr "Limite de acesso de CI_JOB_TOKEN"
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 ""
+msgstr "Selecione os projetos que podem ser acessados por solicitações de API autenticadas com a variável CI_JOB_TOKEN CI/CD deste projeto. É um risco de segurança desabilitar esse recurso, pois projetos não autorizados podem tentar recuperar um token ativo e acessar a API. %{linkStart}Saiba mais.%{linkEnd}"
msgid "CICD|The Auto DevOps pipeline runs by default in all projects with no CI/CD configuration file. %{link_start}What is Auto DevOps?%{link_end}"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr "Cancelando pré-visualização"
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr "Não é possível atribuir um épico confidencial a uma issue não confidencial. Torne a issue confidencial e tente novamente"
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr "Não pode ser mesclado automaticamente"
@@ -7593,6 +7726,9 @@ msgstr "Não é possível criar o relatório de abuso. Este usuário foi bloquea
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr "Chave"
msgid "CiVariables|Masked"
msgstr "Mascarada"
+msgid "CiVariables|Options"
+msgstr "Opções"
+
msgid "CiVariables|Protected"
msgstr "Protegido"
@@ -9647,10 +9786,16 @@ msgstr "Comentar nas linhas %{startLine} a %{endLine}"
msgid "Comment/Reply (quoting selected text)"
msgstr "Comentar/Responder (citando o texto selecionado)"
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr "Conclua a verificação para cadastrar."
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr "Completo"
@@ -9974,7 +10122,7 @@ msgid "Configure %{repository_checks_link_start}repository checks%{link_end} and
msgstr ""
msgid "Configure CAPTCHAs, IP address limits, and other anti-spam measures."
-msgstr ""
+msgstr "Configurar CAPTCHAs, limites de endereço IP e outras medidas anti-spam."
msgid "Configure Container Scanning in `.gitlab-ci.yml` using the GitLab managed template. You can [add variable overrides](https://docs.gitlab.com/ee/user/application_security/container_scanning/#customizing-the-container-scanning-settings) to customize Container Scanning settings."
msgstr "Configure a varredura de contêiner no `.gitlab-ci.yml` usando o modelo gerenciado pelo GitLab. Você pode [adicionar sobreposições de variáveis](https://docs.gitlab.com/ee/user/application_security/container_scanning/#customizing-the-container-scanning-settings) para personalizar as configurações de varredura de contêiner."
@@ -10627,11 +10775,11 @@ msgstr "Contribuições"
msgid "Contribution Analytics"
msgstr "Análise de contribuição"
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
-msgstr ""
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
+msgstr "%{created} criado, %{closed} fechado."
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
-msgstr ""
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
+msgstr "%{created} criado, %{merged} mesclado, %{closed} fechado."
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr ""
@@ -10663,6 +10811,15 @@ msgstr "Nenhuma solicitação de mesclagem para o período selecionado."
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr "Nenhum push para o período selecionado."
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr "O intervalo de datas fornecido é maior que 31 dias"
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr "A data final é anterior à data inicial fornecida"
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr "Há muitos dados para calcular. Tente diminuir a configuração period_limit no arquivo de configuração de insights."
+
msgid "Contributions for %{calendar_date}"
msgstr "Contribuições para %{calendar_date}"
@@ -10679,7 +10836,7 @@ msgid "Control emails linked to your account"
msgstr "Controle e-mails vinculados à sua conta"
msgid "Control how the CI_JOB_TOKEN CI/CD variable is used for API access between projects."
-msgstr ""
+msgstr "Controle como a variável CI_JOB_TOKEN CI/CD é usada para acesso à API entre projetos."
msgid "Control how the GitLab Package Registry functions."
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr "Copiar %{name}"
msgid "Copy %{protocol} clone URL"
msgstr "Copiar URL de Clone do %{protocol}"
-msgid "Copy %{type}"
-msgstr "Copiar %{type}"
-
msgid "Copy ID"
msgstr "Copiar ID"
@@ -10798,9 +10952,6 @@ msgstr "Copiar senha"
msgid "Copy source branch name"
msgstr "Copiar o nome da origem do branch"
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr "Copiar esse token de registro"
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr "Não foi possível remover %{user} de %{group}. Não é possível remover o último proprietário do grupo."
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr "Não foi possível remover %{user} de %{group}. Usuário não é um membro do grupo."
-
msgid "Could not remove the trigger."
msgstr "Não foi possível remover o gatilho."
@@ -11185,9 +11333,6 @@ msgstr "Criar novo arquivo ou diretório"
msgid "Create new label"
msgstr "Criar nova etiqueta"
-msgid "Create new project"
-msgstr "Criar novo projeto"
-
msgid "Create new..."
msgstr "Criar novo..."
@@ -11455,9 +11600,6 @@ msgstr "Criando épico"
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr "A criação de gráficos usa os dados do servidor Prometheus. Se isso levar muito tempo, verifique se os dados estão disponíveis."
-msgid "Creation date"
-msgstr "Data de criação"
-
msgid "Creator"
msgstr "Criador"
@@ -11473,8 +11615,8 @@ msgstr "Nenhuma credencial encontrada"
msgid "CredentialsInventory|Personal Access Tokens"
msgstr "Tokens de acesso pessoal"
-msgid "CredentialsInventory|Project Access Tokens"
-msgstr "Tokens de acesso pessoal"
+msgid "CredentialsInventory|Project and Group Access Tokens"
+msgstr "Tokens de acesso a projetos e grupos"
msgid "CredentialsInventory|SSH Keys"
msgstr "Chaves SSH"
@@ -11575,9 +11717,6 @@ msgstr "Ramificação atual"
msgid "Current Project"
msgstr "Projeto atual"
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr "Taxa de falha de mudança"
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr "Taxa de falha de mudança (porcentagem)"
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr "Data"
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr "Tempo médio em que um incidente foi aberto em um ambiente de produção durante o período de tempo determinado."
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr "Nenhum incidente durante este período"
@@ -11988,6 +12133,9 @@ msgstr "Pessoal"
msgid "DashboardProjects|Trending"
msgstr "Tendências"
+msgid "Dashboards"
+msgstr "Painéis"
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr "%{firstProject} e %{secondProject}"
@@ -11998,7 +12146,7 @@ msgid "Dashboard|Unable to add %{invalidProjects}. This dashboard is available f
msgstr ""
msgid "DastConfig|Customize DAST settings to suit your requirements. Configuration changes made here override those provided by GitLab and are excluded from updates. For details of more advanced configuration options, see the %{docsLinkStart}GitLab DAST documentation%{docsLinkEnd}."
-msgstr ""
+msgstr "Personalizar as configurações DAST para atender às suas necessidades. As alterações de configurações realizadas aqui substituem aquelas fornecidas pelo GitLab e são excluídas das atualizações. Para mais detalhes sobre opções avançadas de configuração, ver a %{docsLinkStart}documentação DAST do GitLab%{docsLinkEnd}."
msgid "DastConfig|DAST CI/CD configuration"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr "Salvar configurações comumente usadas para sites de destino e especifi
msgid "DastProfiles|Save profile"
msgstr "Salvar perfil"
+msgid "DastProfiles|Scan Method"
+msgstr "Método de verificação"
+
msgid "DastProfiles|Scan method"
msgstr "Método de verificação"
@@ -12440,6 +12591,9 @@ msgstr "Atualização de dados"
msgid "Data type"
msgstr "Tipo de dados"
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr "Falha na atualização do banco de dados"
@@ -12462,7 +12616,7 @@ msgid "DatadogIntegration|For self-managed deployments, set the %{codeOpen}env%{
msgstr ""
msgid "DatadogIntegration|How do I set up this integration?"
-msgstr ""
+msgstr "Como faço para configurar essa integração?"
msgid "DatadogIntegration|Send CI/CD pipeline information to Datadog to monitor for job failures and troubleshoot performance issues. %{docs_link}"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr "Dias"
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr "Dias para mesclar"
@@ -12560,6 +12717,9 @@ msgstr "Falha ao validar tamanho do arquivo descompactado."
msgid "Decrease"
msgstr "Diminuir"
+msgid "Default - Never run"
+msgstr "Padrão - Nunca executar"
+
msgid "Default CI/CD configuration file"
msgstr "Arquivo de configuração padrão de CI/CD"
@@ -12671,6 +12831,9 @@ msgstr "Excluir"
msgid "Delete %{issuableType}"
msgstr "Excluir %{issuableType}"
+msgid "Delete %{issuableType}?"
+msgstr "Excluir %{issuableType}?"
+
msgid "Delete %{name}"
msgstr "Excluir %{name}"
@@ -12692,9 +12855,6 @@ msgstr "Excluir fluxo de valor"
msgid "Delete account"
msgstr "Excluir conta"
-msgid "Delete artifacts"
-msgstr "Excluir artefatos"
-
msgid "Delete asset"
msgstr "Excluir ativos"
@@ -12761,8 +12921,8 @@ msgstr ""
msgid "Delete row"
msgstr "Excluir linha"
-msgid "Delete self monitoring project"
-msgstr "Excluir projeto de automonitoramento"
+msgid "Delete self-monitoring project"
+msgstr ""
msgid "Delete snippet"
msgstr "Excluir snippet"
@@ -12891,7 +13051,7 @@ msgid "DeletionSettings|Owners and administrators can delete projects."
msgstr ""
msgid "DeletionSettings|Retention period that deleted groups and projects will remain restorable. Personal projects are always deleted immediately. Some groups can opt-out their projects."
-msgstr ""
+msgstr "Período de retenção que grupos e projetos excluídos permanecerão restauráveis. Projetos pessoais são sempre excluídos imediatamente. Alguns grupos podem desativar seus projetos."
msgid "Denied"
msgstr "Negado"
@@ -13101,7 +13261,7 @@ msgid "DeployBoard|Kubernetes Pods"
msgstr ""
msgid "DeployFreeze|Add a freeze period to prevent unintended releases during a period of time for a given environment. You must update the deployment jobs in %{filename} according to the deploy freezes added here. %{freeze_period_link_start}Learn more.%{freeze_period_link_end}"
-msgstr ""
+msgstr "Adicione um período de congelamento para evitar lançamentos não intencionais durante um período de tempo para um determinado ambiente. Você pode atualizar as tarefas de deploy em %{filename} de acordo com os períodos de congelamento adicionados aqui. %{freeze_period_link_start}Saiba mais.%{freeze_period_link_end}"
msgid "DeployFreeze|Add deploy freeze"
msgstr ""
@@ -13238,6 +13398,9 @@ msgstr "Data de expiração (opcional)"
msgid "DeployTokens|Expires"
msgstr "Expira"
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr "Os tokens de implantação do grupo permitem acesso aos pacotes, repositórios e imagens de registro dentro do grupo."
@@ -13325,9 +13488,24 @@ msgstr "Selecione o alvo de implantação"
msgid "Deployment frequency"
msgstr "Frequência de implantação"
-msgid "DeploymentApproval| Current approvals: %{current}"
+msgid "DeploymentApprovals|Approvals"
msgstr ""
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
+msgid "DeploymentApproval| Current approvals: %{current}"
+msgstr "Aprovações atuais: %{current}"
+
msgid "DeploymentApproval|Approval options"
msgstr "Opções de aprovação"
@@ -13338,10 +13516,10 @@ msgid "DeploymentApproval|Approved %{time}"
msgstr ""
msgid "DeploymentApproval|Approved by you %{time}"
-msgstr ""
+msgstr "Aprovado por você %{time}"
msgid "DeploymentApproval|Approving will run the manual job from deployment #%{deploymentIid}. Rejecting will fail the manual job."
-msgstr ""
+msgstr "A aprovação irá executar a tarefa manual a partir da implantação #%{deploymentIid}. Rejeitar irá falhar na tarefa manual."
msgid "DeploymentApproval|Deployment tier: %{tier}"
msgstr "Nível de implantação: %{tier}"
@@ -13540,7 +13718,7 @@ msgid "DesignManagement|Are you sure you want to cancel creating this comment?"
msgstr "Você tem certeza que quer cancelar a criação deste comentário?"
msgid "DesignManagement|Are you sure you want to cancel editing this comment?"
-msgstr ""
+msgstr "Tem certeza de que deseja cancelar a edição deste comentário?"
msgid "DesignManagement|Click the image where you'd like to start a new discussion"
msgstr ""
@@ -13549,10 +13727,10 @@ msgid "DesignManagement|Comment"
msgstr "Comentário"
msgid "DesignManagement|Continue creating"
-msgstr ""
+msgstr "Continuar criando"
msgid "DesignManagement|Continue editing"
-msgstr ""
+msgstr "Continuar editando"
msgid "DesignManagement|Could not add a new comment. Please try again."
msgstr "Não foi possível adicionar um novo comentário. Por favor, tente novamente."
@@ -13573,7 +13751,7 @@ msgid "DesignManagement|Designs"
msgstr "Designs"
msgid "DesignManagement|Discard changes"
-msgstr ""
+msgstr "Descartar alterações"
msgid "DesignManagement|Discussion"
msgstr "Discussão"
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr "Adoção de DevOps"
+msgid "Developer"
+msgstr "Desenvolvedor"
+
msgid "Development"
msgstr "Desenvolvimento"
@@ -13747,7 +13928,7 @@ msgid "DevopsAdoption|Dev"
msgstr "Dev"
msgid "DevopsAdoption|DevOps adoption tracks the use of key features across your favorite groups. Add a group to the table to begin."
-msgstr ""
+msgstr "A adoção de DevOps rastreia o uso das principais características entre seus grupos favoritos. Adicione um grupo à tabela para começar."
msgid "DevopsAdoption|Edit groups"
msgstr "Editar grupos"
@@ -13903,6 +14084,12 @@ msgstr[1] "%d exclusões"
msgid "Diffs|Expand all lines"
msgstr "Expandir todas as linhas"
+msgid "Diffs|Hide whitespace changes"
+msgstr "Ocultar alterações de espaço em branco"
+
+msgid "Diffs|Inline"
+msgstr "Em linha"
+
msgid "Diffs|Next 20 lines"
msgstr "Próximas 20 linhas"
@@ -13918,11 +14105,17 @@ msgstr "Mostrar %{unfoldCount} linhas"
msgid "Diffs|Show all unchanged lines"
msgstr "Mostrar todas as linhas sem alterações"
+msgid "Diffs|Show whitespace changes"
+msgstr "Mostrar alterações de espaço em branco"
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] "Mostrando %{dropdownStart}%{count} arquivo alterado%{dropdownEnd}"
msgstr[1] "Mostrando %{dropdownStart}%{count} arquivos alterados%{dropdownEnd}"
+msgid "Diffs|Side-by-side"
+msgstr "Lado a lado"
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Algo errado aconteceu ao buscar linhas de comparação."
@@ -14528,6 +14721,12 @@ msgstr "Editado"
msgid "Edited %{timeago}"
msgstr "Editado em %{timeago}"
+msgid "Edited %{timeago} by %{author}"
+msgstr "Editado %{timeago} por %{author}"
+
+msgid "Edited by %{author}"
+msgstr "Editado por %{author}"
+
msgid "Editing"
msgstr "Editando"
@@ -14858,23 +15057,41 @@ msgstr "Ativar e-mails de desativação do usuário"
msgid "Enable version check"
msgstr "Ativar verificação de versão"
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
-msgstr "%{stepStart}Etapa 1%{stepEnd}. Certifique-se de ter o Kubernetes configurado e ter um domínio base para seus %{linkStart}clusters%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
-msgstr "%{stepStart}Etapa 2%{stepEnd}. Copie o seguinte trecho:"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
-msgstr "%{stepStart}Etapa 3%{stepEnd}. Adicione-o ao arquivo %{linkStart}gitlab-ci.yml%{linkEnd} do projeto."
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
-msgstr "%{stepStart}Etapa 4 (opcional)%{stepEnd}. Ative as revisões visuais seguindo as %{linkStart}instruções de configuração%{linkEnd}."
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr ""
-msgid "EnableReviewApp|Close"
-msgstr "Fechar"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
-msgstr "Copiar texto do snippet"
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr "Usando um site estático?"
+
+msgid "EnableReviewApp|View more example projects"
+msgstr "Ver mais projetos de exemplo"
msgid "Enabled"
msgstr "Habilitado"
@@ -15015,7 +15232,7 @@ msgid "Environment variables are configured by your administrator to be %{link_s
msgstr "As variáveis de ambiente são configuradas pelo seu administrador para serem %{link_start}protegidas%{link_end} por padrão."
msgid "Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default."
-msgstr ""
+msgstr "As variáveis de ambiente nesta instância do GitLab são configuradas para serem %{link_start}protegidas%{link_end} por padrão."
msgid "Environment:"
msgstr "Ambiente:"
@@ -15101,6 +15318,9 @@ msgstr "Paradas automáticas %{autoStopAt}"
msgid "Environments|Commit"
msgstr "Commit"
+msgid "Environments|Copy live environment URL"
+msgstr "Copiar URL do ambiente ao vivo"
+
msgid "Environments|Delete"
msgstr "Excluir"
@@ -15201,7 +15421,7 @@ msgid "Environments|Stopping %{environmentName}"
msgstr "Parar %{environmentName}"
msgid "Environments|There are no deployments for this environment yet. %{linkStart}Learn more about setting up deployments.%{linkEnd}"
-msgstr ""
+msgstr "Não há implantações para este ambiente ainda. %{linkStart}Saiba mais sobre como configurar implantações.%{linkEnd}"
msgid "Environments|This action will %{docsStart}retry the latest deployment%{docsEnd} with the commit %{commitId}, for this environment. Are you sure you want to continue?"
msgstr ""
@@ -15281,12 +15501,12 @@ msgstr "Adicionar um novo épico"
msgid "Epics|Add an existing epic"
msgstr "Adicionar um épico existente"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgstr ""
+
msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr "Você tem certeza de que quer remover %{bStart}%{targetIssueTitle}%{bEnd} de %{bStart}%{parentEpicTitle}%{bEnd}?"
-msgid "Epics|Assign Epic"
-msgstr "Atribuir épico"
-
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr "Deixe em branco para herdar as datas do marco"
@@ -15299,18 +15519,9 @@ msgstr "Remover épico"
msgid "Epics|Remove issue"
msgstr "Remover issue"
-msgid "Epics|Search epics"
-msgstr "Pesquisar épico"
-
-msgid "Epics|Select epic"
-msgstr "Selecionar épico"
-
msgid "Epics|Show more"
msgstr "Mostrar mais"
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr "Algo deu errado ao atribuir a issue para épico."
-
msgid "Epics|Something went wrong while creating child epics."
msgstr "Algo deu errado ao criar épicos filhos."
@@ -15323,18 +15534,12 @@ msgstr "Algo deu errado ao buscar épicos filhos."
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr "Algo deu errado ao buscar épicas do grupo."
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr "Algo deu errado ao fazer o pedido do item."
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr "Algo deu errado ao remover a issue de épico."
-
msgid "Epics|Something went wrong while updating epics."
msgstr "Algo deu errado ao atualizar épicos filhos."
@@ -15464,9 +15669,6 @@ msgstr "Ocorreu um erro ao salvar os responsáveis"
msgid "Error occurred when saving reviewers"
msgstr "Ocorreu um erro ao salvar os revisores"
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr "Ocorreu um erro ao atualizar o status da issue"
@@ -15530,9 +15732,6 @@ msgstr "Erro ao enviar o arquivo"
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr "Erro ao enviar o arquivo: %{stripped}"
-
msgid "Error while loading the merge request. Please try again."
msgstr "Erro ao carregar a solicitação de mesclagem. Por favor, tente novamente."
@@ -15773,6 +15972,57 @@ msgstr "Eventos"
msgid "Events API"
msgstr "API de eventos"
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr "Cada tentativa de %{action} falhou: %{job_error_message}. Por favor, tente novamente."
@@ -15892,6 +16142,9 @@ msgstr "Excluindo commits de mesclar. Limitado a 6.000 commits."
msgid "Execution time"
msgstr "Tempo de execução"
+msgid "Executive Dashboard"
+msgstr "Painel executivo"
+
msgid "Existing branch name, tag, or commit SHA"
msgstr "Nome de ramificação, tag ou SHA do commit existente"
@@ -15949,9 +16202,15 @@ msgstr "Expandir barra lateral"
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr "Expiração"
@@ -16176,6 +16435,9 @@ msgstr "Falhou em"
msgid "Failed to add a Zoom meeting"
msgstr "Falha ao adicionar uma reunião do Zoom"
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr "Falha ao aplicar comandos."
@@ -16223,9 +16485,6 @@ msgstr "alha ao criar o framework"
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr "Falha ao criar novo token de acesso: %{token_response_message}"
-
msgid "Failed to create repository"
msgstr "Falha ao criar o repositório"
@@ -16421,9 +16680,6 @@ msgstr "Erro em atualizar o status da issue"
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr "Falha ao atualizar."
-
msgid "Failed to upgrade."
msgstr "Falha ao atualizar."
@@ -16681,6 +16937,9 @@ msgstr "Fev"
msgid "February"
msgstr "Fevereiro"
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr "Filtrar por solicitações de mesclagem que estão atualmente fechadas e
msgid "Filter by merge requests that are currently merged."
msgstr "Filtrar por solicitações de mesclagem atualmente mescladas."
-msgid "Filter by milestone"
-msgstr "Filtrar por marco"
-
msgid "Filter by milestone name"
msgstr "Filtrar por nome de marco"
@@ -16859,7 +17115,7 @@ msgid "Finish review"
msgstr ""
msgid "Finish setting up your dedicated account for %{group_name}."
-msgstr ""
+msgstr "Termine de configurar sua conta dedicada para %{group_name}."
msgid "Finished"
msgstr "Finalizado"
@@ -16996,6 +17252,9 @@ msgstr "Para mais informações, vá para o "
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr "Não permitido"
+
msgid "Forgot your password?"
msgstr "Esqueceu sua senha?"
@@ -17102,7 +17361,7 @@ msgid "Framework successfully deleted"
msgstr ""
msgid "Free"
-msgstr ""
+msgstr "Grátis"
msgid "Free Trial of GitLab.com Ultimate"
msgstr "Avaliação gratuita do GitLab.com Ultimate"
@@ -17623,7 +17882,7 @@ msgid "Geo|Resync all %{projects_count} projects"
msgstr ""
msgid "Geo|Resync all %{total}%{replicableType}"
-msgstr ""
+msgstr "Ressincronizar todos os %{total}%{replicableType}"
msgid "Geo|Resync project"
msgstr ""
@@ -17812,7 +18071,7 @@ msgid "Geo|With GitLab Geo, you can install a special read-only and replicated i
msgstr ""
msgid "Geo|You are on a secondary, %{b_open}read-only%{b_close} Geo site."
-msgstr ""
+msgstr "Você está em um site Geo secundário, %{b_open}somente leitura%{b_close}."
msgid "Geo|You may be able to make a limited amount of changes or perform a limited amount of actions on this page."
msgstr "Você pode ser capaz de fazer um número limitado de mudanças ou executar uma quantidade limitada de ações nessa página."
@@ -17829,9 +18088,6 @@ msgstr "secundário"
msgid "Get a free instance review"
msgstr "Obter gratuitamente uma instância de revisão"
-msgid "Get a free trial"
-msgstr "Obtenha um teste gratuito"
-
msgid "Get a support subscription"
msgstr "Obtenha uma assinatura de suporte"
@@ -17896,7 +18152,7 @@ msgid "GitAbuse|Automatically ban users from this %{scope} when they exceed the
msgstr "Banir automaticamente os usuários deste %{scope} quando eles excederem os limites especificados"
msgid "GitAbuse|Excluded users"
-msgstr ""
+msgstr "Usuários excluídos"
msgid "GitAbuse|Number of repositories"
msgstr ""
@@ -17923,13 +18179,13 @@ msgid "GitAbuse|Reporting time period should be between %{minTimePeriod}-%{maxTi
msgstr ""
msgid "GitAbuse|The maximum number of unique repositories a user can download in the specified time period before they're banned."
-msgstr ""
+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 excluded from the Git abuse rate limit."
msgstr ""
msgid "GitAbuse|You cannot specify more than %{maxExcludedUsers} excluded users."
-msgstr ""
+msgstr "Você não pode especificar mais de %{maxExcludedUsers} usuários excluídos."
msgid "GitHub API rate limit exceeded. Try again after %{reset_time}"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr "Solicitação de conta do GitLab"
msgid "GitLab Billing Team."
msgstr "Equipe de cobrança do GitLab."
+msgid "GitLab Community Edition"
+msgstr "GitLab Community Edition"
+
+msgid "GitLab Enterprise Edition"
+msgstr "GitLab Enterprise Edition"
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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}"
@@ -18057,9 +18322,6 @@ msgstr "Versão do GitLab"
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr "GitLab.com"
-
msgid "GitLab.com (SaaS)"
msgstr "GitLab.com (SaaS)"
@@ -18073,7 +18335,7 @@ msgid "GitLabPages|%{domain} is not verified. To learn how to verify ownership,
msgstr "%{domain} não está verificado. Para saber como verificar sua propriedade, visite os %{link_start}detalhes do seu domínio%{link_end}."
msgid "GitLabPages|Access Control is enabled for this Pages website; only authorized users will be able to access it. To make your website publicly available, navigate to your project's %{strong_start}Settings &gt; General &gt; Visibility%{strong_end} and select %{strong_start}Everyone%{strong_end} in pages section. Read the %{link_start}documentation%{link_end} for more information."
-msgstr ""
+msgstr "Controle de acesso está ativado para este site de Páginas; somente usuários autorizados poderão acessá-lo. Para tornar seu site disponível publicamente, navegue até a seção %{strong_start}Configurações &gt; Geral &gt; Visibilidade%{strong_end} do seu projeto e selecione %{strong_start}Todos%{strong_end} nas páginas. Leia a %{link_start}documentação%{link_end} para obter mais informações."
msgid "GitLabPages|Access pages"
msgstr "Páginas de aceso"
@@ -18615,9 +18877,6 @@ msgstr "Mostrar dependências"
msgid "GraphViewType|Stage"
msgstr "Estágio"
-msgid "Graphs"
-msgstr "Gráficos"
-
msgid "Gravatar"
msgstr "Gravatar"
@@ -18627,6 +18886,9 @@ msgstr "Gravatar habilitado"
msgid "Group"
msgstr "Grupo"
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr "Deixar grupo"
msgid "GroupsTree|Loading groups"
msgstr "Carregando grupos"
-msgid "GroupsTree|No groups matched your search"
-msgstr "Nenhum grupo corresponde à sua pesquisa"
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr "Desculpe, nenhum grupo ou projeto correspondem à sua pesquisa"
-
msgid "GroupsTree|Options"
msgstr "Opções"
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr "Você está criando um novo grupo de nível superior"
+msgid "Guest"
+msgstr "Visitante"
+
msgid "Guideline"
msgstr "Diretriz"
@@ -19642,9 +19901,6 @@ msgstr "Informações do status de saúde podem ser obtidas nos seguintes locais
msgid "Health status"
msgstr "Status de saúde"
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr "O token de acesso é"
@@ -20099,8 +20355,14 @@ msgstr "Enviar código"
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
-msgstr "Etapa 1: verificar o número de telefone"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
+msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
msgstr "O código expirou. Envie um novo código e tente novamente."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr "Se isso foi um erro, você pode %{leave_link_start}deixar o %{source_type}%{link_end}."
@@ -20419,7 +20675,7 @@ msgid "ImportProjects|%{provider} rate limit exceeded. Try again later"
msgstr ""
msgid "ImportProjects|Advanced import settings"
-msgstr ""
+msgstr "Configurações avançadas de importação"
msgid "ImportProjects|Blocked import URL: %{message}"
msgstr "URL de importação bloqueada: %{message}"
@@ -20446,7 +20702,7 @@ msgid "ImportProjects|Select the repositories you want to import"
msgstr "Selecione os repositórios que você deseja importar"
msgid "ImportProjects|The more information you select, the longer it will take to import"
-msgstr ""
+msgstr "Quanto mais informações você selecionar, mais tempo levará para importar"
msgid "ImportProjects|The remote data could not be imported."
msgstr ""
@@ -20985,7 +21241,7 @@ msgid "InProductMarketing|YouTube"
msgstr "YouTube"
msgid "InProductMarketing|Your software, deployed your way"
-msgstr ""
+msgstr "Seu software, implantado do seu jeito"
msgid "InProductMarketing|Your teams can be more efficient"
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr "Código de dois fatores inválido."
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr "Convite recusado"
msgid "Invite \"%{email}\" by email"
msgstr "Convidar \"%{email}\" por e-mail"
-msgid "Invite \"%{trimmed}\" by email"
-msgstr "Convidar \"%{trimmed}\" por e-mail"
-
msgid "Invite Members"
msgstr "Convidar membros"
@@ -22021,8 +22277,8 @@ msgstr "Convide seus colegas"
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr "Percebemos que você não convidou ninguém para este grupo. Convide seus colegas para que você possa discutir problemas, colaborar em solicitações de mesclagem e compartilhar seu conhecimento."
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
-msgstr "Para obter mais membros e acesso a recursos pagos adicionais, o proprietário do grupo pode iniciar uma avaliação ou atualizar para um nível pago."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
+msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
msgstr "%{linkStart}Leia mais%{linkEnd} sobre as permissões de cargos"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] "O seguinte membro não pôde ser convidado"
msgstr[1] "Os seguintes %d membros não puderam ser convidados"
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr "Para obter mais membros, um proprietário do grupo pode %{trialLinkStart}iniciar uma avaliação%{trialLinkEnd} ou %{upgradeLinkStart}atualizar%{upgradeLinkEnd} para um nível pago."
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22210,10 +22463,10 @@ msgid "IrkerService|Channels and users separated by whitespaces. %{recipients_do
msgstr "Canais e usuários separados por espaços em branco. %{recipients_docs_link}"
msgid "IrkerService|Default IRC URI (optional)"
-msgstr ""
+msgstr "URI de IRC padrão (opcional)"
msgid "IrkerService|How to enter channels or users?"
-msgstr ""
+msgstr "Como inserir canais ou usuários?"
msgid "IrkerService|Recipients"
msgstr "Destinatários"
@@ -22251,12 +22504,18 @@ msgstr "Está usando o assento de licença:"
msgid "Is using seat"
msgstr "Está usando licença"
+msgid "IssuableEvents|assigned to"
+msgstr "atribuído a"
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr "não atribuído"
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr "%{wi_type} criado %{created_at} por "
@@ -22278,6 +22537,18 @@ msgstr "movida"
msgid "IssuableStatus|promoted"
msgstr "promovida"
+msgid "Issuable|epic"
+msgstr "épico"
+
+msgid "Issuable|escalation policy"
+msgstr "política de escalonamento"
+
+msgid "Issuable|iteration"
+msgstr "iteração"
+
+msgid "Issuable|milestone"
+msgstr "marco"
+
msgid "Issue"
msgstr "Issue"
@@ -22503,6 +22774,21 @@ msgstr "Para ampliar sua pesquisa, altere ou remova filtros na barra de filtros
msgid "IssuesAnalytics|Total:"
msgstr "Total:"
+msgid "Issues|Move selected"
+msgstr "Mover selecionado"
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr "Título"
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr "URL do proxy do Jira Connect"
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -22807,7 +23096,7 @@ msgid "JiraConnect|You can now close this window and return to Jira."
msgstr ""
msgid "JiraConnect|You don't have permission to create branches for this project. Select a different project or contact the project owner for access. %{linkStart}Learn more.%{linkEnd}"
-msgstr ""
+msgstr "Você não tem permissão para criar uma ramificação nesse projeto. Selecione um projeto diferente ou solicite permissões ao proprietário do projeto. %{linkStart}Saiba mais.%{linkEnd}"
msgid "JiraRequest|A connection error occurred while connecting to Jira. Try your request again."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr "Criado"
msgid "Job|Download"
msgstr "Baixar"
+msgid "Job|Duration"
+msgstr "Duração"
+
msgid "Job|Erase job log and artifacts"
msgstr "Apagar registro de tarefa e artefatos"
@@ -23166,9 +23458,15 @@ msgstr "Pendente"
msgid "Job|Preparing"
msgstr "Preparando"
+msgid "Job|Queued"
+msgstr "Em fila"
+
msgid "Job|Retry"
msgstr "Repetir"
+msgid "Job|Run again"
+msgstr "Executar novamente"
+
msgid "Job|Running"
msgstr "Executando"
@@ -23545,9 +23843,6 @@ msgstr "Última edição por %{link_start}%{avatar} %{name}%{link_end}"
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr "Última modificação"
@@ -23701,6 +23996,15 @@ msgstr "Saiba mais sobre os grupos."
msgid "Learn more about issues."
msgstr "Saiba mais sobre as issues."
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr "Saiba mais sobre o máximo de assentos usados"
@@ -23720,10 +24024,10 @@ msgid "Learn more."
msgstr "Saiba mais."
msgid "LearnGitLab|%{percentage}%{percentSymbol} completed"
-msgstr ""
+msgstr "%{percentage}%{percentSymbol} concluído"
msgid "LearnGitLab|Add code owners"
-msgstr ""
+msgstr "Adicionar proprietários de códigos"
msgid "LearnGitLab|Analyze your application for vulnerabilities with DAST"
msgstr "Analise seu aplicativo em busca de vulnerabilidades com o DAST"
@@ -23750,10 +24054,10 @@ msgid "LearnGitLab|Deploy"
msgstr "Implantar"
msgid "LearnGitLab|Enable require merge approvals"
-msgstr ""
+msgstr "Habilitar a necessidade de aprovações de merge"
msgid "LearnGitLab|GitLab works best as a team. Invite your colleague to enjoy all features."
-msgstr ""
+msgstr "GitLab funciona melhor em equipe. Convide seu colega para desfrutar de todos os recursos."
msgid "LearnGitLab|Invite your colleagues"
msgstr "Convide seus colegas"
@@ -23762,7 +24066,7 @@ msgid "LearnGitLab|Learn GitLab"
msgstr ""
msgid "LearnGitLab|Plan and execute"
-msgstr ""
+msgstr "Planejar e executar"
msgid "LearnGitLab|Prevent unexpected changes to important assets by assigning ownership of files and paths."
msgstr "Previne mudanças inesperadas em arquivos importantes atribuindo a propriedade de arquivos e caminhos."
@@ -23771,10 +24075,10 @@ msgid "LearnGitLab|Ready to get started with GitLab? Follow these steps to set u
msgstr "Pronto para começar com o GitLab? Siga estas etapas para configurar sua área de trabalho, planejar e comprometer as alterações e publicar seu projeto."
msgid "LearnGitLab|Review and edit proposed changes to source code."
-msgstr ""
+msgstr "Aprenda e edite as alterações propostas no código-fonte."
msgid "LearnGitLab|Route code reviews to the right reviewers, every time."
-msgstr ""
+msgstr "Encaminhe revisões de código para os revisores certos, sempre."
msgid "LearnGitLab|Run a Security scan using CI/CD"
msgstr "Execute uma verificação de segurança usando CI/CD"
@@ -23789,16 +24093,16 @@ msgid "LearnGitLab|Scan dependencies for vulnerabilities"
msgstr ""
msgid "LearnGitLab|Scan your code to uncover vulnerabilities before deploying."
-msgstr ""
+msgstr "Escaneie seu código para descobrir vulnerabilidades antes de implantar."
msgid "LearnGitLab|Set up CI/CD"
-msgstr ""
+msgstr "Configurar CI/CD"
msgid "LearnGitLab|Set up your first project's CI/CD"
msgstr "Configure o CI/CD do seu primeiro projeto"
msgid "LearnGitLab|Set up your workspace"
-msgstr ""
+msgstr "Configure sua área de trabalho"
msgid "LearnGitLab|Start a free trial of GitLab Ultimate"
msgstr "Comece uma avaliação gratuita do GitLab Ultimate"
@@ -23807,16 +24111,16 @@ msgid "LearnGitLab|Submit a merge request (MR)"
msgstr "Enviar uma solicitação de mesclagem (MR)"
msgid "LearnGitLab|Try GitLab Ultimate for free"
-msgstr ""
+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 your new GitLab workflow to deploy your application, monitor its health, and keep it secure:"
-msgstr ""
+msgstr "Use o seu novo fluxo de trabalho do GitLab para publicar seu aplicativo, monitorar sua saúde e mantê-lo seguro:"
msgid "LearnGitLab|Your team is growing! You've successfully invited new team members to the %{projectName} project."
-msgstr ""
+msgstr "Sua equipe está crescendo! Você convidou novos membros da equipe para o projeto %{projectName}."
msgid "LearnGitlab|- Included in trial"
msgstr "- Incluído na avaliação"
@@ -23825,13 +24129,13 @@ 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 ""
+msgstr "Criando sua experiência de integração..."
msgid "LearnGitlab|Ok, let's go"
msgstr "Ok, vamos lá"
msgid "LearnGitlab|View administrator list"
-msgstr ""
+msgstr "Ver lista de administradores"
msgid "Leave"
msgstr "Sair"
@@ -23851,9 +24155,6 @@ msgstr "Sair do projeto"
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr "Gráfico de burndown legado"
@@ -23945,8 +24246,8 @@ msgstr[1] "Conformidade de licença detectou %d novas licenças"
msgid "LicenseCompliance|License Compliance detected %d new license and policy violation"
msgid_plural "LicenseCompliance|License Compliance detected %d new licenses and policy violations"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "Conformidade de licença detectou %d nova licença e violação de política"
+msgstr[1] "Conformidade de licença detectou %d novas licenças e violações de política"
msgid "LicenseCompliance|License Compliance detected %d new license and policy violation; approval required"
msgid_plural "LicenseCompliance|License Compliance detected %d new licenses and policy violations; approval required"
@@ -23966,7 +24267,7 @@ msgid "LicenseCompliance|No policy matches this license"
msgstr "Nenhuma política corresponde a esta licença"
msgid "LicenseCompliance|Out-of-compliance with the project's policies and should be removed"
-msgstr ""
+msgstr "Fora de conformidade com as políticas do projeto e deve ser removido"
msgid "LicenseCompliance|Remove license"
msgstr "Remover licença"
@@ -23993,10 +24294,10 @@ msgid "LicenseCompliance|You are about to remove the license, %{name}, from this
msgstr "Você está prestes a remover a licença %{name} deste projeto."
msgid "LicenseManagement|Allowed"
-msgstr ""
+msgstr "Permitido"
msgid "LicenseManagement|Denied"
-msgstr ""
+msgstr "Negado"
msgid "LicenseManagement|Uncategorized"
msgstr "Não categorizado"
@@ -24014,10 +24315,10 @@ msgid "Licenses"
msgstr "Licenças"
msgid "Licenses|%{remainingComponentsCount} more"
-msgstr ""
+msgstr "%{remainingComponentsCount} mais"
msgid "Licenses|Acceptable license to be used in the project"
-msgstr ""
+msgstr "Licença aceitável para ser usada no projeto"
msgid "Licenses|Component"
msgstr "Componente"
@@ -24059,7 +24360,7 @@ msgid "Licenses|Policy violation: denied"
msgstr "Violação da política: negada"
msgid "Licenses|Specified policies in this project"
-msgstr ""
+msgstr "Políticas especificadas neste projeto"
msgid "Licenses|The file could not be uploaded."
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr "Alterações de linha"
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr "Link (opcional)"
@@ -24209,7 +24516,7 @@ msgid "List of all merge commits"
msgstr "Lista de todos commits de mesclagem"
msgid "List of suitable GCP locations"
-msgstr ""
+msgstr "Lista de localizações adequadas do GCP"
msgid "List of users who are allowed to exceed the rate limit. Example: username1, username2"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr "Registros"
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr "MD5"
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,8 +24728,14 @@ msgstr "Mostrar apenas alterações"
msgid "MRDiff|Show full file"
msgstr "Mostrar arquivo completo"
-msgid "Made this issue confidential."
-msgstr "Tornou esta issue confidencial."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
+msgstr "Tornou este %{type} confidencial."
msgid "Mailgun"
msgstr ""
@@ -24436,7 +24749,13 @@ msgstr ""
msgid "Main menu"
msgstr "Menu principal"
+msgid "Maintainer"
+msgstr "Mantenedor"
+
msgid "Maintenance mode"
+msgstr "Modo de manutenção"
+
+msgid "Make %{type} confidential"
msgstr ""
msgid "Make adjustments to how your GitLab instance is set up."
@@ -24448,20 +24767,17 @@ msgstr "Faça e revise alterações no navegador com o IDE Web"
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr "Faça com que todos em sua equipe sejam mais produtivos, independentemente da localização deles. O GitLab Geo cria espelhos somente leitura de sua instância do GitLab para que você possa reduzir o tempo necessário para clonar e buscar grandes repositórios."
-msgid "Make issue confidential"
-msgstr "Tornar essa issue confidencial"
-
msgid "Make sure you choose a strong, unique password."
msgstr "Certifique-se de escolher uma senha forte e única."
msgid "Make sure you have the correct permissions to link your project."
-msgstr ""
+msgstr "Verifique se você tem as permissões corretas para vincular seu projeto."
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
-msgstr "Torna esta issue confidencial."
+msgid "Makes this %{type} confidential."
+msgstr ""
msgid "Manage %{workspace} labels"
msgstr "Gerenciar etiquetas de %{workspace}"
@@ -24517,6 +24833,9 @@ msgstr "Conta gerenciada"
msgid "Manifest"
msgstr "Manifest"
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr "Importação de arquivo de manifest"
@@ -24541,6 +24860,9 @@ msgstr "Mar"
msgid "March"
msgstr "Março"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr "Marcar como pronto"
@@ -24592,11 +24914,14 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr "Clique para expandir"
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
-msgstr ""
+msgstr "Recuar linha (%{modifierKey}])"
msgid "MarkdownEditor|Indent line (%{modifier_key}])"
-msgstr ""
+msgstr "Recuar linha (%{modifier_key}])"
msgid "MarkdownEditor|Outdent line (%{modifierKey}[)"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr "Cabeçalho"
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr "Suporta %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
@@ -24800,10 +25128,10 @@ msgid "Maximum file size is 1 MB. Image size must be 32 x 32 pixels. Allowed ima
msgstr "O tamanho máximo do arquivo é 1 MB. O tamanho da imagem deve ser 32 x 32 pixels. Os formatos de imagem permitidos são %{favicon_extension_allowlist}."
msgid "Maximum file size is 1MB. Pages are optimized for a 24px tall header logo"
-msgstr ""
+msgstr "O tamanho máximo do arquivo é 1 MB. As páginas são otimizadas para um logotipo de cabeçalho de 24px de altura"
msgid "Maximum file size is 1MB. Pages are optimized for a 640x360 px logo."
-msgstr ""
+msgstr "O tamanho máximo do arquivo é 1 MB. As páginas são otimizadas para um logotipo de 640x360 px."
msgid "Maximum files in a diff"
msgstr ""
@@ -24959,7 +25287,7 @@ msgid "Medium vulnerabilities present"
msgstr ""
msgid "Member since"
-msgstr ""
+msgstr "Membro desde"
msgid "Member since %{date}"
msgstr "Membro desde %{date}"
@@ -25232,6 +25560,9 @@ msgstr "As configurações de solicitações e aprovações de mesclagem foram m
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr "A tela de solicitação de mesclagem é um lugar para propor mudanças em um projeto e discutir essas mudanças com outros"
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25305,7 +25636,7 @@ msgid "MergeRequestApprovals|Enforce %{separationLinkStart}separation of duties%
msgstr "Aplicar %{separationLinkStart}separação de tarefas%{separationLinkEnd} para todos os projetos. %{learnLinkStart}Saiba mais.%{learnLinkEnd}"
msgid "MergeRequestDiffs|Commenting on lines %{selectStart}start%{selectEnd} to %{end}"
-msgstr ""
+msgstr "Comentando nas linhas %{selectStart}iniciam%{selectEnd} a %{end}"
msgid "MergeRequestDiffs|Select comment starting line"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr "Método"
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr "Métrica"
+
msgid "Metric was successfully added."
msgstr "A métrica foi adicionada com sucesso."
@@ -25572,10 +25906,10 @@ msgid "MetricsUsersStarredDashboards|You are not authorized to add star to this
msgstr ""
msgid "Metrics|1. Define and preview panel"
-msgstr ""
+msgstr "1. Definir e visualizar o painel"
msgid "Metrics|2. Paste panel YAML into dashboard"
-msgstr ""
+msgstr "2. Colar YAML do painel no painel"
msgid "Metrics|Add metric"
msgstr "Adicionar métrica"
@@ -25730,7 +26064,7 @@ msgid "Metrics|Set refresh rate"
msgstr ""
msgid "Metrics|Star dashboard"
-msgstr ""
+msgstr "Favorirtar painel"
msgid "Metrics|There was an error creating the dashboard."
msgstr ""
@@ -25778,7 +26112,7 @@ msgid "Metrics|Unit label"
msgstr "Rótulo de unidade"
msgid "Metrics|Unstar dashboard"
-msgstr ""
+msgstr "Desfavoritar painel"
msgid "Metrics|Used as a title for the chart"
msgstr "Usado como um título para o gráfico"
@@ -25787,7 +26121,7 @@ msgid "Metrics|Used if the query returns a single series. If it returns multiple
msgstr "Usado se a consulta retornar uma única série. Se ele retornar várias séries, seus rótulos de legenda serão retirados da resposta."
msgid "Metrics|Validating query"
-msgstr ""
+msgstr "Validando consulta"
msgid "Metrics|Values"
msgstr "Valores"
@@ -25848,6 +26182,9 @@ msgstr "Validade do marco"
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"
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr "%{percentage}%{percent} completo"
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr "Acesso mínimo"
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr "Capacidade mínima para estar disponível antes de agendar mais espelhos preventivamente."
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr "Adicionar projetos"
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr "Meu grupo incrível"
@@ -26296,7 +26642,7 @@ msgid "Name new label"
msgstr "Nome da nova etiqueta"
msgid "Name to be used as the sender for emails from Service Desk."
-msgstr ""
+msgstr "Nome a ser usado como remetente para e-mails da Central de serviços"
msgid "Name:"
msgstr "Nome:"
@@ -26725,6 +27071,9 @@ msgstr "Nenhum escopo"
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr "Sem acesso"
+
msgid "No active admin user found"
msgstr "Nenhum usuário administrador ativo encontrado"
@@ -26854,9 +27203,6 @@ msgstr "Nenhuma iteração para mostrar"
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr "Nenhuma tarefa para mostrar"
-
msgid "No label"
msgstr "Nenhuma etiqueta"
@@ -26884,9 +27230,6 @@ msgstr "Nenhum resultado correspondente"
msgid "No matching results for \"%{query}\""
msgstr "Nenhum resultado correspondente para \"%{query}\""
-msgid "No matching results..."
-msgstr "Nenhum resultado correspondente..."
-
msgid "No members found"
msgstr "Nenhum membro encontrado"
@@ -26902,9 +27245,6 @@ msgstr "Nenhuma mensagem foi registrada"
msgid "No milestone"
msgstr "Nenhum marco"
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr "Sem outras etiquetas com esse nome ou descrição"
@@ -26945,7 +27285,7 @@ msgid "No ref selected"
msgstr ""
msgid "No regions configured"
-msgstr ""
+msgstr "Nenhuma região configurada"
msgid "No related merge requests found."
msgstr "Nenhuma solicitação de mesclagem relacionada foi encontrada."
@@ -27034,7 +27374,7 @@ msgid "Nodes"
msgstr "Nós"
msgid "Non-admin users are restricted to read-only access, in both GitLab UI and API."
-msgstr ""
+msgstr "Os usuários não administradores estão restritos ao acesso somente leitura, tanto na interface do usuário do GitLab quanto na API."
msgid "None"
msgstr "Nenhum"
@@ -27138,8 +27478,8 @@ msgstr "Recolher respostas"
msgid "Notes|Expand replies"
msgstr "Expandir respostas"
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
-msgstr "As notas internas são visíveis apenas para o autor, cessionários e membros com a função de Repórter ou superior"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
+msgstr "As notas internas são visíveis apenas para membros com a função de Repórter ou superior"
msgid "Notes|Last reply by %{name}"
msgstr "Última resposta por %{name}"
@@ -27306,7 +27646,7 @@ msgid "Notify|%{author_link}'s issue %{issue_reference_link} is due soon."
msgstr ""
msgid "Notify|%{author_name} %{action_name} %{ref_type} %{ref_name} at %{project_link}"
-msgstr ""
+msgstr "%{author_name} %{action_name} %{ref_type} %{ref_name} em %{project_link}"
msgid "Notify|%{changed_files}:"
msgstr ""
@@ -27315,10 +27655,10 @@ msgid "Notify|%{commit_link} in %{mr_link}"
msgstr "%{commit_link} em %{mr_link}"
msgid "Notify|%{commits_text} from branch `%{target_branch}`"
-msgstr ""
+msgstr "%{commits_text} da ramificação `%{target_branch}`"
msgid "Notify|%{committed_by_start} by %{author_name} %{committed_by_end} %{committed_at_start} at %{committed_date} %{committed_at_end}"
-msgstr ""
+msgstr "%{committed_by_start} por %{author_name} %{committed_by_end} %{committed_at_start} em %{committed_date} %{committed_at_end}"
msgid "Notify|%{invite_email}, now known as %{user_name}, has accepted your invitation to join the %{target_name} %{target_model_name}."
msgstr "%{invite_email}, agora conhecido como %{user_name}, aceitou seu convite para se juntar ao %{target_name} %{target_model_name}."
@@ -27327,7 +27667,7 @@ msgid "Notify|%{invited_user} has %{highlight_start}declined%{highlight_end} you
msgstr "%{invited_user} %{highlight_start}recusou%{highlight_end} seu convite para participar do %{target_link} %{target_name}."
msgid "Notify|%{issues} imported."
-msgstr ""
+msgstr "%{issues} importada."
msgid "Notify|%{member_link} requested %{member_role} access to the %{target_source_link} %{target_type}."
msgstr "%{member_link} solicitou %{member_role} acesso ao %{target_source_link} %{target_type}."
@@ -27473,6 +27813,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|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr "Pipeline %{pipeline_link} acionado por"
@@ -27482,6 +27825,9 @@ msgstr "Pipeline foi corrigido e #%{pipeline_id} foi aprovado!"
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr "Projeto %{project_name} não pôde ser exportado."
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr "O projeto %{project_name} foi exportado com sucesso."
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr "O link de download expirará em 24 horas."
+msgid "Notify|The errors we encountered were:"
+msgstr "Os erros que encontramos foram:"
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr "Número de funcionários"
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr "Número de arquivos tocados"
@@ -27623,9 +27969,6 @@ msgstr "Out"
msgid "October"
msgstr "Outubro"
-msgid "OfSearchInADropdown|Filter"
-msgstr "Filtrar"
-
msgid "Off"
msgstr ""
@@ -27716,13 +28059,13 @@ msgid "OnCallSchedules|Delete schedule"
msgstr "Excluir agendamento"
msgid "OnCallSchedules|Edit rotation"
-msgstr ""
+msgstr "Editar rotação"
msgid "OnCallSchedules|Edit schedule"
msgstr "Editar agendamento"
msgid "OnCallSchedules|Enable end date"
-msgstr ""
+msgstr "Ativar data de término"
msgid "OnCallSchedules|Expand schedule"
msgstr "Expandir agendamento"
@@ -27740,7 +28083,7 @@ msgid "OnCallSchedules|For this rotation, on-call will be:"
msgstr ""
msgid "OnCallSchedules|On-call schedule %{obstacle} in project %{project}"
-msgstr ""
+msgstr "Agendamento de plantão %{obstacle} no projeto %{project}"
msgid "OnCallSchedules|On-call schedules"
msgstr ""
@@ -27749,7 +28092,7 @@ msgid "OnCallSchedules|Please note, rotations with shifts that are less than fou
msgstr ""
msgid "OnCallSchedules|Removing this user may put their on-call team at risk of missing a notification."
-msgstr ""
+msgstr "Remover este usuário pode colocar sua equipe de plantão em risco de perder uma notificação."
msgid "OnCallSchedules|Removing yourself may put your on-call team at risk of missing a notification."
msgstr ""
@@ -27809,10 +28152,10 @@ msgid "OnCallSchedules|The schedule could not be updated. Please try again."
msgstr ""
msgid "OnCallSchedules|Try adding a rotation"
-msgstr ""
+msgstr "Tente adicionar uma rotação"
msgid "OnCallSchedules|User %{name} is currently part of:"
-msgstr ""
+msgstr "O usuário %{name} atualmente faz parte de:"
msgid "OnCallSchedules|View next timeframe"
msgstr "Ver próximo período de tempo"
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr "Criar novo perfil de verificação"
-
-msgid "OnDemandScans|Create new site profile"
-msgstr "Criar novo perfil de site"
-
msgid "OnDemandScans|DAST configuration"
msgstr "Configuração de DAST"
@@ -27910,12 +28247,6 @@ msgstr "Por exemplo: testa a página de login para injeções de SQL"
msgid "OnDemandScans|Keep editing"
msgstr "Continuar editando"
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr "Gerenciar perfis de verificação"
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr "Gerenciar perfis de sites"
-
msgid "OnDemandScans|My daily scan"
msgstr "Minha verificação diária"
@@ -27937,12 +28268,6 @@ msgstr "Nova verificação"
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr "Não há nenhum perfil ainda. Para criar uma nova verificação, você precisa ter pelo menos um perfil completo de verificação."
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr "Não há nenhum perfil ainda. Para criar uma nova verificação, você precisa ter pelo menos um perfil completo de site."
-
msgid "OnDemandScans|On-demand Scans"
msgstr "Verificação sob demanda"
@@ -27985,15 +28310,6 @@ msgstr "Agendamento de verificação"
msgid "OnDemandScans|Scan type"
msgstr "Tipo de verificação"
-msgid "OnDemandScans|Scanner profile"
-msgstr "Perfil de verificação"
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr "Perfil de site"
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr "Fuso horário"
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr "Ver resultados"
@@ -28048,9 +28358,6 @@ msgstr "Uma vez importados, os repositórios podem ser espelhados por SSH. Leia
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr "Uma vez removido. o relacionamento do fork não pode ser restaurado. Esse projeto não poderá mais receber ou enviar solicitações de mesclagem para o projeto original ou outros forks."
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] "Mais um item"
@@ -28224,9 +28531,6 @@ msgstr "A operação falhou. Verifique os registros do pod para %{pod_name} para
msgid "Operation not allowed"
msgstr "Operação não permitida"
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr "A operação expirou. Verifique os registros do pod para %{pod_name} para mais detalhes."
-
msgid "Operations"
msgstr "Operações"
@@ -28595,12 +28899,21 @@ msgstr "Excluir pacote"
msgid "PackageRegistry|Delete package asset"
msgstr "Excluir ativos do pacote"
+msgid "PackageRegistry|Delete package version"
+msgstr "Excluir versão do pacote"
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr "Excluir esse pacote"
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr "Pacotes duplicados"
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr "Helm"
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr "Ajude-nos a conhecer suas necessidades de migração de registro"
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr "Se você estiver interessado em migrar pacotes do seu registro privado para o GitLab Package Registry, responda à nossa pesquisa e conte-nos mais sobre suas necessidades."
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28718,7 +29037,7 @@ msgid "PackageRegistry|Package updated by commit %{link} on branch %{branch}, bu
msgstr ""
msgid "PackageRegistry|Permanently delete"
-msgstr ""
+msgstr "Excluir permanentemente"
msgid "PackageRegistry|Permanently delete assets"
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr "Realizar pesquisa"
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr "SHA de destino: %{sha}"
@@ -28832,7 +29154,7 @@ msgid "PackageRegistry|You are about to delete %{filename}. This is a destructiv
msgstr ""
msgid "PackageRegistry|You are about to delete %{name}, are you sure?"
-msgstr ""
+msgstr "Você está prestes a excluir %{name}, tem certeza?"
msgid "PackageRegistry|You are about to delete 1 asset. This operation is irreversible."
msgid_plural "PackageRegistry|You are about to delete %d assets. This operation is irreversible."
@@ -29175,12 +29497,6 @@ msgstr "parede"
msgid "Period in seconds"
msgstr "Período em segundos"
-msgid "Period of inactivity (days)"
-msgstr "Período de inatividade (dias)"
-
-msgid "Period of inactivity before deactivation."
-msgstr "Período de inatividade antes da desativação."
-
msgid "Permalink"
msgstr "Link permanente"
@@ -29229,8 +29545,8 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
-msgstr "Tarefas de Phabricator"
+msgid "Phabricator tasks"
+msgstr ""
msgid "Phone"
msgstr "Telefone"
@@ -29448,20 +29764,26 @@ msgstr "Ativo"
msgid "PipelineSchedules|All"
msgstr "Todos"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr "Tem certeza de que deseja excluir este agendamento de pipeline?"
+
msgid "PipelineSchedules|Delete pipeline schedule"
-msgstr ""
+msgstr "Excluir agendamento de pipeline"
msgid "PipelineSchedules|Description"
msgstr "Descrição"
msgid "PipelineSchedules|Edit pipeline schedule"
-msgstr ""
+msgstr "Editar agendamento de pipeline"
msgid "PipelineSchedules|Inactive"
msgstr "Inativo"
msgid "PipelineSchedules|Last Pipeline"
-msgstr ""
+msgstr "Último pipeline"
+
+msgid "PipelineSchedules|New schedule"
+msgstr "Novo agendamento"
msgid "PipelineSchedules|Next Run"
msgstr "Próxima Execução"
@@ -29473,12 +29795,18 @@ msgid "PipelineSchedules|Only the owner of a pipeline schedule can make changes
msgstr ""
msgid "PipelineSchedules|Owner"
+msgstr "Proprietário"
+
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
msgstr ""
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "Digite uma descrição curta para esta pipeline"
msgid "PipelineSchedules|Run pipeline schedule"
+msgstr "Executar agendamento de pipeline"
+
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
msgstr ""
msgid "PipelineSchedules|Take ownership"
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr "Destino"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr "Ocorreu um problema ao excluir o agendamento do pipeline."
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr "Variáveis"
@@ -30252,9 +30586,6 @@ msgstr "Selecione um projeto Jira"
msgid "Please select a country"
msgstr "Por favor selecione um país"
-msgid "Please select a file"
-msgstr "Por favor, selecione um arquivo"
-
msgid "Please select a group"
msgstr "Por favor, selecione um grupo"
@@ -30313,7 +30644,7 @@ msgid "Pods in use"
msgstr "Pods em uso"
msgid "Point to any links you like: documentation, built binaries, or other related materials. These can be internal or external links from your GitLab instance. Each URL and link title must be unique."
-msgstr ""
+msgstr "Aponte para quaisquer links que desejar: documentação, binários construídos ou outros materiais relacionados. Eles podem ser links internos ou externos da sua instância do GitLab. Cada URL e título de link deve ser exclusivo."
msgid "Policies"
msgstr "Políticas"
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr "(opcional)"
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr "Autenticação"
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr "Conexão"
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr "Última execução %{timeAgo} no pipeline"
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr "Verificação de pré-verificação"
+
+msgid "PreScanVerification|Save and run verification"
+msgstr "Salvar e executar a verificação"
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr "Iniciado %{timeAgo} no pipeline"
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr "Verificações de verificação"
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr "Verificar configuração"
+
+msgid "PreScanVerification|View results"
+msgstr "Ver resultados"
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr "Preferências"
@@ -30370,7 +30764,7 @@ msgid "Preferences saved."
msgstr "Preferências salvas."
msgid "Preferences|Automatically add new list items"
-msgstr ""
+msgstr "Adicionar automaticamente novos itens de lista"
msgid "Preferences|Behavior"
msgstr "Comportamento"
@@ -30484,7 +30878,7 @@ msgid "Preferences|Use relative times"
msgstr "Usar tempos relativos"
msgid "Preferences|When you type in a description or comment box, pressing %{kbdOpen}Enter%{kbdClose} in a list adds a new item below."
-msgstr ""
+msgstr "Quando você digita em uma descrição ou caixa de comentário, pressionar %{kbdOpen}Enter%{kbdClose} em uma lista adiciona um novo item abaixo."
msgid "Preferences|When you type in a description or comment box, selected text is surrounded by the corresponding character after typing one of the following characters: %{supported_characters}."
msgstr "Quando você digita em uma descrição ou caixa de comentário, o texto selecionado é cercado pelo caractere correspondente após digitar um dos seguintes caracteres: %{supported_characters}."
@@ -30504,6 +30898,9 @@ msgstr "Impedir a edição de regras de aprovação em projetos e solicitações
msgid "Prevent environment from auto-stopping"
msgstr "Evitar que o ambiente pare automaticamente"
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr "Evitar o fork do projeto fora do grupo atual"
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr "Prosseguir"
-msgid "Product Analytics"
-msgstr "Análises de produto"
+msgid "Product analytics"
+msgstr "Análise de produtos"
+
+msgid "ProductAnalytics|Audience"
+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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr "Produtividade"
@@ -31179,6 +31582,9 @@ msgstr "Nome do projeto"
msgid "Project navigation"
msgstr "Navegação do projeto"
+msgid "Project or Group"
+msgstr "Projeto ou grupo"
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr "Status de segurança do projeto"
msgid "Project security status help page"
msgstr "Página de ajuda do status de segurança do projeto"
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr "Slug do projeto"
@@ -31473,12 +31882,18 @@ msgstr "%{link_start}O que são modelos de descrição?%{link_end}"
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr "%{link_start}Que variáveis posso usar?%{link_end}"
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr "Uma ramificação padrão não pode ser escolhida para um projeto vazio."
+
msgid "ProjectSettings|Additional options"
msgstr "Opções adicionais"
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr "Configurações adicionais que influenciam como e onde as mesclagem são feitas."
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr "ProjectSettings|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"
@@ -31491,12 +31906,18 @@ msgstr "Sempre mostrar os emojis de aprovação e desaprovação com polegar em
msgid "ProjectSettings|Analytics"
msgstr "Análises"
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr "Fechar automaticamente as issues referenciadas na ramificação padrão"
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr "Resolva automaticamente os encadeamentos de diferenças de solicitação de mesclagem quando eles se tornarem desatualizados"
msgid "ProjectSettings|Badges"
msgstr "Selos"
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr "Ramificações criadas a partir de issues seguem este padrão."
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr "Construir, testar e implantar suas mudanças."
@@ -31518,6 +31939,9 @@ msgstr "Escolha seu método de mesclagem, opções, verificações e opções de
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr "Configure sua infraestrutura."
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr "Configure os recursos do projeto e monitore a saúde deles."
@@ -31617,6 +32041,9 @@ msgstr "Como eles diferem?"
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr "Se os merge trains estiverem ativados, a mesclagem só será possível se a ramificação puder ser rebaseada sem conflitos."
+msgid "ProjectSettings|Infrastructure"
+msgstr "Infraestrutura"
+
msgid "ProjectSettings|Internal"
msgstr "Interno"
@@ -31684,7 +32111,7 @@ msgid "ProjectSettings|Note: The container registry is always visible when a pro
msgstr "Observação: o container registry está sempre visível quando um projeto é público e o container registry está definido como '%{access_level_description}'"
msgid "ProjectSettings|Only commits that include a %{code_block_start}Signed-off-by:%{code_block_end} element can be pushed to this repository."
-msgstr ""
+msgstr "Somente commits que incluem um elemento %{code_block_start}Signed-off-by:%{code_block_end} podem ser enviados para este repositório."
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr "Apenas para commits assinados pode-se fazer push para este repositório."
@@ -31755,6 +32182,9 @@ msgstr "Segurança e conformidade"
msgid "ProjectSettings|Security & 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."
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing 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."
@@ -31785,6 +32215,9 @@ msgstr "Squashing é sempre executado. A caixa de seleção está visível e sel
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr "Squashing nunca é executado e a caixa de seleção está oculta."
+msgid "ProjectSettings|Status checks must succeed"
+msgstr "As verificações de status devem ser bem-sucedidas"
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr "Enviar alterações para serem mescladas no upstream."
@@ -31836,6 +32269,9 @@ msgstr "Usuários podem copiar o repositório para um novo projeto."
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr "Os usuários só podem enviar commits para este repositório se o e-mail do committer for um de seus próprios e-mails verificados."
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr "Usuários podem solicitar acesso"
@@ -32475,6 +32911,9 @@ msgstr "Permitir que todos os usuários com acesso %{tag_start}forcem o push%{ta
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr "Permitir que todos os usuários com acesso push forcem o push."
+msgid "ProtectedBranch|Allowed to create"
+msgstr "Permitido criar"
+
msgid "ProtectedBranch|Allowed to force push"
msgstr "Permitido forçar um push"
@@ -32511,15 +32950,27 @@ msgstr "Proteção de ramificações protegidas por padrão restringem quem pode
msgid "ProtectedBranch|Code owner approval"
msgstr "Aprovação do proprietário do código"
+msgid "ProtectedBranch|Create wildcard"
+msgstr "Criar curinga"
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr "Não se aplica a usuários com permissão para fazer push. Seções opcionais não são aplicadas."
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr "Mantenha ramificações estáveis seguras e força os desenvolvedores a usar as solicitações de mesclagem"
+msgid "ProtectedBranch|Last commit"
+msgstr "Último commit"
+
msgid "ProtectedBranch|Learn more."
msgstr "Saiba mais."
+msgid "ProtectedBranch|New Protected Tag"
+msgstr "Nova tag protegida"
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr "Nenhuma tag está protegida."
+
msgid "ProtectedBranch|Protect"
msgstr "Proteger"
@@ -32535,12 +32986,21 @@ msgstr "Ramificações protegidas"
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr "Ramificações protegidas, aprovações de solicitações de mesclagem e verificações de status aparecerão aqui depois de configurados."
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr "Tags protegidas (%{tags_count})"
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr "Rejeitar o código envia os arquivos de alteração listados no arquivo CODEOWNERS."
msgid "ProtectedBranch|Require approval from code owners:"
msgstr "Exigir aprovação dos proprietários do código:"
+msgid "ProtectedBranch|Search protected tags"
+msgstr "Pesquisar tags protegidas"
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr "Selecione a tag ou crie um curinga"
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32608,7 +33068,7 @@ msgid "ProtectedEnvironment|Protected Environment (%{protected_environments_coun
msgstr "Ambiente Protegido (%{protected_environments_count})"
msgid "ProtectedEnvironment|Required approvals"
-msgstr ""
+msgstr "Aprovações necessárias"
msgid "ProtectedEnvironment|Select an environment"
msgstr "Selecione um ambiente"
@@ -32818,7 +33278,7 @@ msgid "PushRules|Reject any files likely to contain secrets. %{secret_files_link
msgstr "Rejeita quaisquer arquivos que provavelmente contenham segredos. %{secret_files_link_start}Quais arquivos secretos são rejeitados?%{secret_files_link_end}"
msgid "PushRules|Reject commits that aren't DCO certified"
-msgstr ""
+msgstr "Rejeitar commits que não são certificados pelo DCO"
msgid "PushRules|Reject expression in commit messages"
msgstr "Rejeitar expressão em mensagens de confirmação"
@@ -32850,6 +33310,9 @@ msgstr "Os usuários ainda podem excluir tags por meio da interface de usuário
msgid "PushRule|Push rules"
msgstr "Regras de push"
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr "Rejeitar usuários não verificados"
@@ -32982,12 +33445,6 @@ msgstr "Leia mais"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr "Leia mais sobre épicos relacionados"
-
-msgid "Read more about related issues"
-msgstr "Leia mais sobre issues relacionadas"
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr "Referência"
@@ -33247,13 +33701,19 @@ msgstr[1] "Versões"
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
-msgid "Release assets"
+msgid "Release already exists"
msgstr ""
+msgid "Release assets"
+msgstr "Ativos de versões"
+
msgid "Release assets documentation"
msgstr ""
msgid "Release date"
+msgstr "Data de lançamento"
+
+msgid "Release does not exist"
msgstr ""
msgid "Release does not have the same project as the milestone"
@@ -33314,7 +33774,7 @@ msgid "Releases|Tag message"
msgstr ""
msgid "Release|Include message from the annotated tag."
-msgstr ""
+msgstr "Incluir mensagem da tag anotada."
msgid "Release|Something went wrong while creating a new release."
msgstr ""
@@ -33332,7 +33792,7 @@ msgid "Release|Unable to fetch the tag notes."
msgstr ""
msgid "Release|You can edit the content later by editing the release. %{linkStart}How do I edit a release?%{linkEnd}"
-msgstr ""
+msgstr "Você pode editar o conteúdo posteriormente editando a versão. %{linkStart}Como edito uma versão?%{linkEnd}"
msgid "Reload page"
msgstr "Atualizar a página"
@@ -33712,6 +34172,9 @@ msgstr "Reportado por"
msgid "Reported by %{reporter}"
msgstr "Reportado por %{reporter}"
+msgid "Reporter"
+msgstr "Relator"
+
msgid "Reporting"
msgstr "Reportando"
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr "Noma da classe"
-
msgid "Reports|Copy failed test names to run locally"
msgstr "Copie nomes de teste com falha para executar localmente"
msgid "Reports|Copy failed tests"
msgstr "Copie testes com falha"
-msgid "Reports|Execution time"
-msgstr "Tempo de execução"
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr "Falha"
-
-msgid "Reports|Filename"
-msgstr "Nome do arquivo"
-
msgid "Reports|Fixed"
msgstr "Corrigido"
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr "Gravidade"
-msgid "Reports|System output"
-msgstr "Saída do sistema"
-
msgid "Reports|Test summary"
msgstr "Resumo do teste"
-msgid "Reports|Test summary failed loading results"
-msgstr "Resumo do teste falhou ao carregar os resultados"
-
msgid "Reports|Test summary failed to load results"
msgstr "Resumo do teste falhou ao carregar os resultados"
-msgid "Reports|Test summary results are being parsed"
-msgstr "Os resultados do resumo de teste estão sendo analisados"
-
msgid "Reports|Test summary results are loading"
msgstr "Os resultados do resumo de teste estão sendo carregados"
@@ -33860,9 +34297,6 @@ msgstr "Nome da vulnerabilidade"
msgid "Reports|metrics report"
msgstr "relatório de métricas"
-msgid "Reports|no changed test results"
-msgstr "sem resultados de teste alterados"
-
msgid "Repositories"
msgstr "Repositórios"
@@ -34066,7 +34500,7 @@ msgid "Request parameter %{param} is missing."
msgstr ""
msgid "Request review from"
-msgstr ""
+msgstr "Solicitar revisão de"
msgid "Request time"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr "Resolvido por"
msgid "Resolved by %{name}"
msgstr "Resolvido por %{name}"
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr "Resposta"
@@ -34463,6 +34900,9 @@ msgstr "Execute pipelines de CI/CD com Jenkins."
msgid "Run housekeeping"
msgstr "Executar manutenção"
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34491,7 +34931,7 @@ msgid "Runners"
msgstr "Executores"
msgid "Runners are processes that pick up and execute CI/CD jobs for GitLab."
-msgstr "Executores são processos que selecionam e executam Tarefas de CI /CD para o GitLab."
+msgstr "Executores são processos que selecionam e executam tarefas de CI/CD para o GitLab."
msgid "Runners page."
msgstr "Página de executores."
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] "%d executor selecionado excluído"
msgstr[1] "%d executores selecionados excluídos"
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr "%{link_start}Esses executores%{link_end} estão disponíveis para todos os grupos e projetos."
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,8 +34972,8 @@ msgstr "Ativo"
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
-msgstr ""
+msgid "Runners|Administrator"
+msgstr "Administrador"
msgid "Runners|All"
msgstr "Todos"
@@ -34610,7 +35053,7 @@ msgstr[0] ""
msgstr[1] ""
msgid "Runners|Delete runner"
-msgstr ""
+msgstr "Excluir executor"
msgid "Runners|Delete runner %{name}?"
msgstr ""
@@ -34661,7 +35104,7 @@ msgid "Runners|Group"
msgstr "Grupo"
msgid "Runners|How do runners pick up jobs?"
-msgstr ""
+msgstr "Como os executor conseguem tarefas?"
msgid "Runners|How do we upgrade GitLab runner?"
msgstr ""
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr "Proprietário"
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34777,7 +35223,7 @@ msgid "Runners|Register an instance runner"
msgstr ""
msgid "Runners|Register as many runners as you want. You can register runners as separate users, on separate servers, and on your local machine."
-msgstr ""
+msgstr "Registre quantos executores quiser. Você pode registrar executores como usuários separados, em servidores separados e em sua máquina local."
msgid "Runners|Registration token"
msgstr "Token de registro"
@@ -34861,14 +35307,20 @@ msgid "Runners|Runners"
msgstr "Executores"
msgid "Runners|Runners are either:"
-msgstr ""
+msgstr "Executores são:"
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr "Executores são os agentes que executam seus trabalhos de CI/CD. Siga as %{linkStart}instruções de instalação e registro%{linkEnd} para configurar um runner."
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr "Selecionar todos"
+
msgid "Runners|Select projects to assign to this runner"
msgstr "Selecione projetos para atribuir a este executor"
@@ -34909,7 +35361,7 @@ msgid "Runners|Tags"
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 ""
+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|Take me there!"
msgstr "Leve-me lá!"
@@ -34917,6 +35369,9 @@ msgstr "Leve-me lá!"
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr "A nova visualização oferece mais espaço e melhor visibilidade da sua frota de executores."
+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."
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr "Expiração do token"
+msgid "Runners|Unselect all"
+msgstr "Desmarcar tudo"
+
msgid "Runners|Up to date"
msgstr "Atualizado"
@@ -34991,12 +35449,6 @@ msgstr "Versão %{version}"
msgid "Runners|View installation instructions"
msgstr "Ver instruções de instalação do executor"
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,17 +35503,23 @@ msgstr "Tokens de descoberta de SAML"
msgid "SAML for %{group_name}"
msgstr "SAML para %{group_name}"
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
-msgstr "Selecionar \"Autorizar\" transferirá a propriedade de sua conta do GitLab \"%{username}\" (%{email}) para sua organização."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
+msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr "Entrar no GitLab para conectar a conta da sua organização"
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
-msgstr "O grupo \"%{group_path}\" permite que você entre com sua conta de entrada única."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
-msgstr "Para acessar \"%{group_name}\" você deve entrar com sua conta Single Sign-On, através de uma página de entrada externa."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
+msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "O SSO da sua organização foi conectado à sua conta do GitLab"
@@ -35168,17 +35626,17 @@ msgstr "Salvando"
msgid "Saving project."
msgstr "Salvando projeto."
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
-msgstr "%{ifLabelStart}se%{ifLabelEnd} %{rules} ações para os %{scopes} %{branches}"
-
msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
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"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run with site profile %{siteProfile} and scanner profile %{scannerProfile}"
-msgstr ""
+msgstr "%{thenLabelStart}Então%{thenLabelEnd} Exigir uma %{scan} verificação para executar com perfil do site %{siteProfile} e verificação de perfil %{scannerProfile}"
msgid "ScanExecutionPolicy|A pipeline is run"
msgstr ""
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr "Selecionar agente"
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr "Selecionar espaços de nome"
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr "agente"
+
msgid "ScanExecutionPolicy|branch"
msgstr "ramificação"
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr "%{ifLabelStart}se%{ifLabelEnd} %{scanners} encontrar mais de %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilidades em uma solicitação de mesclagem aberta visando %{branches}"
@@ -35319,7 +35789,7 @@ msgid "Search authors"
msgstr "Pesquisar autores"
msgid "Search branch"
-msgstr ""
+msgstr "Pesquisar ramificação"
msgid "Search branches"
msgstr "Pesquisar ramificações"
@@ -35357,9 +35827,6 @@ msgstr "Pesquisar por um grupo LDAP"
msgid "Search for a group"
msgstr "Pesquisar por um grupo"
-msgid "Search for a user"
-msgstr "Pesquisar por um usuário"
-
msgid "Search for an emoji"
msgstr "Pesquisar por um emoji"
@@ -35716,13 +36183,13 @@ msgid "SecurityConfiguration|Manage profiles for use by DAST scans."
msgstr "Gerenciar perfis para uso pelas verificações de DAST."
msgid "SecurityConfiguration|More scan types, including DAST, Dependency Scanning, Fuzzing, and Licence Compliance"
-msgstr ""
+msgstr "Mais tipos de verificação, incluindo DAST, verificação de dependência, fuzzing e conformidade de licença"
msgid "SecurityConfiguration|Not enabled"
msgstr "Não ativado"
msgid "SecurityConfiguration|Once you've enabled a scan for the default branch, any subsequent feature branch you create will include the scan. An enabled scanner will not be reflected as such until the pipeline has been successfully executed and it has generated valid artifacts."
-msgstr ""
+msgstr "Após ativar uma verificação para a ramificação padrão, qualquer ramificação de recurso subsequente que você criar incluirá a varredura. Uma verificação ativada não será refletida como tal até que o pipeline tenha sido executado com sucesso e tenha gerado artefatos válidos."
msgid "SecurityConfiguration|Quickly enable all continuous testing and compliance tools by enabling %{linkStart}Auto DevOps%{linkEnd}"
msgstr "Ative rapidamente todos os testes contínuos e ferramentas de conformidade ativando %{linkStart}Auto DevOps%{linkEnd}"
@@ -35766,10 +36233,13 @@ msgstr "e "
msgid "SecurityOrchestration| or "
msgstr "ou "
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr "Política inválida"
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr "Política de resultados de verificação"
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,17 +36596,26 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr "Política inválida ou vazia"
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
msgid "SecurityReports|%{count}+ projects"
-msgstr ""
+msgstr "%{count}+ projetos"
msgid "SecurityReports|%{firstProject} and %{secondProject}"
msgstr "%{firstProject} e %{secondProject}"
@@ -36147,6 +36632,9 @@ msgstr "Adicionar projetos"
msgid "SecurityReports|All activity"
msgstr "Todas as atividades"
+msgid "SecurityReports|All severities"
+msgstr "Todas as severidades"
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr "Projetos monitorados"
msgid "SecurityReports|More info"
msgstr "Mais informações"
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr "Nenhuma atividade"
@@ -36292,7 +36783,7 @@ msgid "SecurityReports|Oops, something doesn't seem right."
msgstr ""
msgid "SecurityReports|Operational vulnerabilities"
-msgstr ""
+msgstr "Vulnerabilidades operacionais"
msgid "SecurityReports|Parsing errors and warnings in pipeline"
msgstr ""
@@ -36316,13 +36807,13 @@ msgid "SecurityReports|Remove project from dashboard"
msgstr ""
msgid "SecurityReports|Report has expired"
-msgstr ""
+msgstr "O relatório expirou"
msgid "SecurityReports|Results show vulnerabilities introduced by the merge request, in addition to existing vulnerabilities from the latest successful pipeline in your project's default branch."
msgstr ""
msgid "SecurityReports|Scan details"
-msgstr ""
+msgstr "Detalhes da verificação"
msgid "SecurityReports|Security Dashboard"
msgstr "Painel de segurança"
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr "Resultados da verificação de segurança"
+
msgid "SecurityReports|Security scans have run"
msgstr "As análises de segurança foram executadas"
@@ -36361,13 +36855,13 @@ msgid "SecurityReports|Still detected"
msgstr ""
msgid "SecurityReports|Submit vulnerability"
-msgstr ""
+msgstr "Enviar vulnerabilidade"
msgid "SecurityReports|Take survey"
msgstr "Responder pesquisa"
msgid "SecurityReports|The Vulnerability Report shows results of successful scans on your project's default branch, manually added vulnerability records, and vulnerabilities found from scanning operational environments. %{linkStart}Learn more.%{linkEnd}"
-msgstr ""
+msgstr "O relatório de vulnerabilidade mostra resultados de verificações bem-sucedidas na ramificação padrão do seu projeto, registros de vulnerabilidade adicionados manualmente e vulnerabilidades encontradas na verificação de ambientes operacionais. %{linkStart}Saiba mais.%{linkEnd}"
msgid "SecurityReports|The following security reports contain one or more vulnerability findings that could not be parsed and were not recorded. To investigate a report, download the artifacts in the job output. Ensure the security report conforms to the relevant %{helpPageLinkStart}JSON schema%{helpPageLinkEnd}."
msgstr ""
@@ -36403,7 +36897,7 @@ msgid "SecurityReports|There was an error while generating the report."
msgstr ""
msgid "SecurityReports|These vulnerabilities were detected in external sources. They are not necessarily tied to your GitLab project. For example, running containers, URLs, and so on."
-msgstr ""
+msgstr "Estas vulnerabilidades foram detectadas em fontes externas. Não estão necessariamente vinculados ao seu projeto GitLab. Por exemplo, executando contêineres, URLs e assim por diante."
msgid "SecurityReports|To widen your search, change or remove filters above"
msgstr "Para ampliar sua pesquisa, altere ou remova os filtros acima"
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr "Treinamento primário"
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr "O treinamento deste parceiro tem precedência quando mais de um parceiro de treinamento está ativado."
@@ -36465,6 +36965,9 @@ msgstr "Ver métricas"
msgid "See our website for help"
msgstr "Consulte nosso site para obter ajuda"
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr "Veja os projetos afetados no painel de administração do GitLab"
@@ -36528,9 +37031,6 @@ msgstr "Selecione um repositório de modelos"
msgid "Select a template type"
msgstr "Selecione um tipo de modelo"
-msgid "Select a timezone"
-msgstr "Selecionar fuso horário"
-
msgid "Select all"
msgstr "Selecionar todos"
@@ -36556,7 +37056,7 @@ msgid "Select branches"
msgstr ""
msgid "Select default branch"
-msgstr ""
+msgstr "Selecionar a ramificação padrão"
msgid "Select due date"
msgstr "Selecionar validade"
@@ -36625,7 +37125,7 @@ msgid "Select status"
msgstr "Selecionar status"
msgid "Select strategy activation method"
-msgstr ""
+msgstr "Selecione o método de ativação da estratégia"
msgid "Select subgroup"
msgstr "Selecionar subgrupo"
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
-msgstr "Automonitoramento"
+msgid "Self-monitoring"
+msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
-msgstr "Automonitoramento"
+msgid "SelfMonitoring|Self-monitoring"
+msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr "Defina a ramificação padrão para este projeto. Todas as merge requests e commits são feitos nessa ramificação, a menos que você especifique um diferente."
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -36970,7 +37467,7 @@ msgid "Set up Jira Integration"
msgstr "Configurar integração do Jira"
msgid "Set up a %{type} runner for a project"
-msgstr ""
+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."
@@ -37076,9 +37573,6 @@ msgstr "Configurações"
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr "Severidade"
@@ -37333,11 +37827,8 @@ msgstr "Mostrando todos os épicos"
msgid "Showing all issues"
msgstr "Mostrando todas as issues"
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr "Mostrando dados para itens de fluxo de trabalho criados neste intervalo de datas. Período limitado a %{maxDateRange} dias."
-
-msgid "Showing graphs based on events of the last %{timerange} days."
-msgstr ""
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
+msgstr "Mostrando dados para itens de fluxo de trabalho completados neste intervalo de datas. Período limitado a %{maxDateRange} dias."
msgid "Showing last %{size} of log -"
msgstr "Mostrando os últimos %{size} de log -"
@@ -37390,8 +37881,8 @@ msgstr ""
msgid "Sign in preview"
msgstr "Prévia de entrada"
-msgid "Sign in to \"%{group_name}\""
-msgstr "Entrar em \"%{group_name}\""
+msgid "Sign in to %{group_name}"
+msgstr "Entre em %{group_name}"
msgid "Sign in to GitLab"
msgstr "Entrar no Gitlab"
@@ -37405,8 +37896,8 @@ msgstr "Entrar via código da A2F"
msgid "Sign in with"
msgstr "Entrar com"
-msgid "Sign in with Single Sign-On"
-msgstr "Entre com logon único"
+msgid "Sign in with single sign-on"
+msgstr "Entrar com entrada única"
msgid "Sign in with smart card"
msgstr "Entrar com cartão inteligente"
@@ -37528,9 +38019,6 @@ msgstr "Limite de tamanho"
msgid "Size limit per repository (MB)"
msgstr "Limite de tamanho por repositório (MB)"
-msgid "Skip outdated deployment jobs"
-msgstr "Pular tarefas de implantação desatualizados"
-
msgid "Skipped"
msgstr "Ignorado"
@@ -37721,7 +38209,7 @@ msgid "Snowplow"
msgstr "Snowplow"
msgid "Soft wrap"
-msgstr ""
+msgstr "Com quebra automática"
msgid "Solid"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr "Alguém editou essa solicitação de mesclagem ao mesmo tempo que você.
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr "Alguém entrou na sua conta %{host} de um novo local"
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "Alguém, esperamos que você, solicitou a redefinição da senha da sua conta do GitLab em %{link_to_gitlab}."
@@ -37864,9 +38355,6 @@ msgstr "Algo deu errado ao buscar os ambientes para essa solicitação de mescla
msgid "Something went wrong while fetching the packages list."
msgstr "Algo deu errado ao recuperar a lista de pacotes."
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr "Ocorreu um erro ao obter o certificado Let's Encrypt."
@@ -38440,9 +38928,6 @@ msgstr "Status:"
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr "Adicionar verificação de status"
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr "Amarelo titânio"
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr "Obter sugestões para revisores com base na ferramenta de aprendizado de máquina do GitLab."
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr "Saiba mais sobre revisores sugeridos"
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr "Revisores sugeridos"
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr "Link de ajuda dos revisores sugeridos"
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr "Sugestões aparecem na seção Revisor da barra lateral direita"
@@ -39261,6 +39746,9 @@ msgstr "Trocar ramificação"
msgid "Switch branch/tag"
msgstr "Trocar ramificação/tag"
+msgid "Switch editors"
+msgstr "Alternar editores"
+
msgid "Switch to GitLab Next"
msgstr "Mudar para GitLab Next"
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr "Tag"
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr "Lista de tags:"
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr "Editar versão"
@@ -39456,15 +39950,9 @@ msgstr "Somente um mantenedor ou proprietário do projeto pode excluir uma tag p
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr "Opcionalmente, crie uma versão pública do seu projeto, baseado nesta tag. As notas de versão são exibidas na página de %{releases_page_link_start}versões%{link_end} . %{docs_link_start}Mais informações%{link_end}"
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr "Release notes"
-
msgid "TagsPage|Repository has no tags yet."
msgstr "Repositório ainda não tem tags."
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr "Use o comando \"git tag\" para adiciona uma nova tag:"
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "Escreva suas notas de lançamento ou arraste arquivos aqui…"
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr "protegido"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr "Dê uma olhada na documentação para descobrir todos os recursos do GitLab."
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr "Ramificação de destino"
@@ -39541,7 +40029,7 @@ msgid "TasksToBeDone|Create/import issues (tickets) to collaborate on ideas and
msgstr ""
msgid "TasksToBeDone|Set up CI/CD pipelines to build, test, deploy, and monitor code"
-msgstr ""
+msgstr "Configure pipelines de CI/CD para construir, testar, implantar e monitorar código"
msgid "Team"
msgstr "Equipe"
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr "Ações"
@@ -39740,12 +40212,6 @@ msgstr "Comando init do Terraform"
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40083,7 +40549,7 @@ msgid "The data source is connected, but there is no data to display. %{document
msgstr ""
msgid "The date when the release is ready. A release with a date in the future is labeled as an %{linkStart}Upcoming Release%{linkEnd}."
-msgstr ""
+msgstr "A data em que o lançamento está pronto. Uma versão com uma data no futuro é rotulada como %{linkStart}Próxima versão%{linkEnd}."
msgid "The default CI/CD configuration file and path for new projects."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "A importação expirará após %{timeout}. Para repositórios que demoram mais tempo, use a combinação clone/push."
@@ -40395,9 +40864,6 @@ msgstr "O repositório deve ser acessível em %{code_open}http://%{code_close},
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr "O recurso que você está tentando acessar não existe ou você não tem permissão para realizar esta ação."
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,8 +40894,8 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
-msgstr ""
+msgid "The start date must be earlier than the end date."
+msgstr "A data de início deve ser anterior à data de término."
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
msgstr ""
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr "Tema"
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr "Atualmente, não há repositórios espelhados."
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr "Esses executores são compartilhados entre projetos neste grupo."
-msgid "These runners are shared across this GitLab instance."
-msgstr "Esses executores são compartilhados nesta instância do GitLab."
-
msgid "These runners are specific to this project."
msgstr "Esses executores são específicos para este projeto."
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr "Este grupo ainda não tem projetos"
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,15 +41785,18 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr "Este espaço de nome já foi usado. Escolha um diferente."
+
msgid "This only applies to repository indexing operations."
msgstr ""
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
+msgstr "Esta página está hospedada nas páginas do GitLab, mas contém conteúdo gerado pelo usuário e pode conter código malicioso. Não aceite a menos que você confie no autor e na fonte."
+
msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr "Esta página não está disponível porque você não tem permissão para ler informações de vários projetos."
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
-msgstr "Esta página envia uma carga útil. Volte para a página de eventos para ver um evento recém-criado."
-
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
msgstr ""
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr "Este usuário não tem %{type} ativo."
-
msgid "This user has no identities"
msgstr "Esse usuário não tem identidades"
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr "Isso invalidará seus aplicativos registrados e dispositivos U2F / WebAuthn."
@@ -41491,7 +41957,7 @@ msgid "This will remove the fork relationship between this project and other pro
msgstr ""
msgid "Thread options"
-msgstr ""
+msgstr "Opções de tópicos"
msgid "Thread to reply to cannot be found"
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr "Para conectar repositórios do GitHub, você pode usar um %{personal_access_token_link}. Ao criar seu token de acesso pessoal, você precisará selecionar o escopo %{code_open}repo%{code_close}, para que possamos exibir uma lista de seus repositórios públicos e privados que estão disponíveis para importação."
@@ -41873,7 +42336,7 @@ msgid "To define internal users, first enable new users set to external"
msgstr "Para definir usuários internos, primeiro ative os novos usuários definidos como externos"
msgid "To edit the pipeline configuration, you must go to the project or external site that hosts the file."
-msgstr ""
+msgstr "Para editar a configuração do pipeline, você deve acessar o projeto ou site externo que hospeda o arquivo."
msgid "To enable Registration Features, first enable Service Ping."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr "Hoje"
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr "Adicionado"
+
+msgid "Todos|Alert"
+msgstr "Alerta"
+
+msgid "Todos|Any Action"
+msgstr "Qualquer Ação"
+
+msgid "Todos|Any Type"
+msgstr "Qualquer tipo"
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr "Você está procurando coisas para fazer? Dê uma olhada em %{strongStart}%{openIssuesLinkStart}issues abertas%{openIssuesLinkEnd}%{strongEnd}, contribua para %{strongStart}%{mergeRequestLinkStart}uma solicitação de mesclagem%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd} ou mencione alguém em um comentário para atribuir automaticamente uma nova tarefa."
+msgid "Todos|Assigned"
+msgstr "Atribuído"
+
+msgid "Todos|Could not merge"
+msgstr "Não foi possível mesclar"
+
+msgid "Todos|Design"
+msgstr "Design"
+
+msgid "Todos|Epic"
+msgstr "Épico"
+
msgid "Todos|Filter by author"
msgstr "Filtrar por autor"
@@ -42046,18 +42536,39 @@ msgstr "De agora em diante, você será conhecido como \"Destruidor de tarefas\"
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr "Uma lista de tarefas vazia não é linda?"
+msgid "Todos|Issue"
+msgstr "Issue"
+
msgid "Todos|It's how you always know what to work on next."
msgstr "É assim que você sempre sabe no que trabalhar a seguir."
msgid "Todos|Mark all as done"
msgstr "Marcar tudo como concluído"
+msgid "Todos|Mentioned"
+msgstr "Mencionado"
+
+msgid "Todos|Merge request"
+msgstr "Solicitação de mesclagem"
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
-msgstr ""
+msgstr "Nada está na sua lista de tarefas. Bom trabalho!"
msgid "Todos|Nothing left to do. High five!"
msgstr "Nada a fazer. Toca aqui!"
+msgid "Todos|Pipelines"
+msgstr "Pipelines"
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr "Revisão solicitada"
+
+msgid "Todos|The pipeline failed in"
+msgstr "O pipeline falhou em"
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr "Sua lista de tarefas mostra o que fazer a seguir"
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr "mencionados %{who} em"
+
+msgid "Todos|requested a review of"
+msgstr "solicitou uma revisão de"
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr "você mesmo"
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr "Alternar para o GitLab Next"
@@ -42220,9 +42749,6 @@ msgstr "Contribuições totais"
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr "Tamanho total de artefatos: %{total_size}"
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr "A autenticação de dois fatores foi desativada para este usuário"
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr "A autenticação de dois fatores foi desativada para sua conta do GitLab."
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr "A autenticação de dois fatores foi desativada com sucesso %{user_email}!"
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr "A autenticação de dois fatores foi desativada com sucesso %{username}!"
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr "A autenticação de dois fatores foi desativada com sucesso!"
@@ -43047,6 +43579,12 @@ msgstr "Tendências de uso"
msgid "Usage statistics"
msgstr "Estatísticas de uso"
+msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
+msgstr ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr "%{help_link_start}Executores compartilhados%{help_link_end} estão desativados, então não há limites definidos no uso de pipeline"
@@ -43149,6 +43687,9 @@ msgstr "Armazenamento de espaço de nome usado"
msgid "UsageQuota|No CI minutes usage data available."
msgstr "Não há dados de uso de minutos de CI disponíveis."
+msgid "UsageQuota|No projects to display."
+msgstr "Nenhum projeto para exibir."
+
msgid "UsageQuota|Packages"
msgstr "Pacotes"
@@ -43179,6 +43720,9 @@ msgstr "Recalcular o uso do repositório"
msgid "UsageQuota|Repository"
msgstr "Repositório"
+msgid "UsageQuota|Search"
+msgstr "Pesquisar"
+
msgid "UsageQuota|Seats"
msgstr "Assentos"
@@ -43869,7 +44413,7 @@ msgid "Users in License"
msgstr "Usuários com licença"
msgid "Users or groups set as approvers in the project's or merge request's settings."
-msgstr ""
+msgstr "Usuários ou grupos definidos como aprovadores nas configurações do projeto ou da solicitação de mesclagem."
msgid "Users over License"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr "Visualizar arquivo @ %{commitSha}"
msgid "View full dashboard"
msgstr "Ver painel completo"
-msgid "View full log"
-msgstr "Ver log completo"
-
msgid "View group in admin area"
msgstr "Ver grupo na área do administrador"
@@ -44529,7 +45070,7 @@ msgid "VulnerabilityManagement|Status is a required field"
msgstr ""
msgid "VulnerabilityManagement|Submit vulnerability"
-msgstr ""
+msgstr "Enviar vulnerabilidade"
msgid "VulnerabilityManagement|Summary, detailed description, steps to reproduce, etc."
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr "Provedor de verificação"
+msgid "Vulnerability|Scanner:"
+msgstr "Verificador:"
+
msgid "Vulnerability|Security Audit"
msgstr "Auditoria de segurança"
@@ -44711,6 +45255,9 @@ msgstr "Severidade:"
msgid "Vulnerability|Status"
msgstr "Status"
+msgid "Vulnerability|Status:"
+msgstr "Status:"
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "Queremos ter certeza de que é você, confirme que você não é um robô."
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr "Dispositivos WebAuthn (%{length})"
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr "O WebAuthn só funciona com sites habilitados para HTTPS. Entre em contato com seu administrador para mais detalhes."
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr "Tem certeza de que deseja trocar de editor? Você perderá todas as alterações não salvas."
+
msgid "WebIDE|Fork project"
msgstr "Fork projeto"
@@ -44903,12 +45453,24 @@ msgstr "Edite rapidamente e facilmente vários arquivos em seu projeto."
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr "Edite de forma rápida e fácil vários arquivos em seu projeto. Imprensa . abrir"
+msgid "WebIDE|Ready for something new?"
+msgstr "Pronto para algo novo?"
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr "Mudar para o novo IDE Web"
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr "Você está convidado a experimentar o novo IDE Web."
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr "Você não pode editar arquivos diretamente nesse projeto. Faça um fork nesse projeto e envie uma solicitação de mesclagem com suas alterações."
@@ -44948,6 +45510,9 @@ msgstr "Webhooks"
msgid "Webhooks Help"
msgstr "Ajuda do Webhooks"
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr "Um comentário é adicionado a uma issue confidencial."
@@ -45018,7 +45583,7 @@ msgid "Webhooks|Deployment events"
msgstr "Eventos de implantação"
msgid "Webhooks|Do not show sensitive data such as tokens in the UI."
-msgstr ""
+msgstr "Não mostrar dados confidenciais, como tokens na interface do usuário."
msgid "Webhooks|Enable SSL verification"
msgstr "Ativar verificação SSL"
@@ -45062,6 +45627,12 @@ msgstr "Eventos de push"
msgid "Webhooks|Push to the repository."
msgstr "Push para o repositório."
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr "Expressão regular"
+
msgid "Webhooks|Releases events"
msgstr "Eventos de versões"
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr "Gatilho"
@@ -45102,10 +45670,10 @@ msgid "Webhooks|URL must be percent-encoded if it contains one or more special c
msgstr "URL deve ser codificado por porcentagem se contiver um ou mais caracteres especiais."
msgid "Webhooks|URL preview"
-msgstr ""
+msgstr "Pré-visualização de URL"
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
-msgstr "Usado para validar as cargas recebidas. Enviado com a solicitação no cabeçalho %{code_start}X-Gitlab-Token HTTP%{code_end}."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
+msgstr ""
msgid "Webhooks|Webhook disabled"
msgstr "Webhook desativado"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr "O limite de taxa de webhook foi atingido"
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr "Eventos da página Wiki"
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr "Site"
@@ -45200,6 +45777,9 @@ msgstr "O que é o esmagamento?"
msgid "What templates can I create?"
msgstr "Quais modelos posso criar?"
+msgid "What variables can I use?"
+msgstr "Quais variáveis posso usar?"
+
msgid "What will you use this group for?"
msgstr "Para que você usará este grupo?"
@@ -45209,8 +45789,8 @@ msgstr "O que você gostaria de fazer?"
msgid "What's new"
msgstr "Novidades"
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
-msgstr "Quando uma tarefa de implantação é bem-sucedida, pule as tarefas de implantação mais antigos que ainda estão pendentes."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
+msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr "Quando um executor está bloqueado, não pode ser atribuído a outros projetos"
@@ -45525,6 +46105,12 @@ msgstr "Adicionar data de início"
msgid "WorkItem|Add task"
msgstr "Adicionar tarefa"
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr "Adicionar ao marco"
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr "Introdução de tarefas"
msgid "WorkItem|Issue"
msgstr "Issue"
+msgid "WorkItem|Iteration"
+msgstr "Iteração"
+
msgid "WorkItem|Learn about tasks."
msgstr "Saiba mais sobre tarefas."
+msgid "WorkItem|Milestone"
+msgstr "Marco"
+
+msgid "WorkItem|No iteration"
+msgstr "Sem iteração"
+
+msgid "WorkItem|No matching results"
+msgstr "Nenhum resultado correspondente"
+
+msgid "WorkItem|No milestone"
+msgstr "Nenhum marco"
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr "Nenhuma tarefa está atribuída no momento. Use tarefas para dividir esse problema em partes menores."
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr "Tarefas"
msgid "WorkItem|Test case"
msgstr "Caso de teste"
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr "Desativar confidencialidade"
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr "Item de trabalho"
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45690,7 +46303,7 @@ msgid "Write milestone description..."
msgstr "Escreva a descrição do marco..."
msgid "Write your release notes or drag your files here…"
-msgstr ""
+msgstr "Escreva suas notas de lançamento ou arraste seus arquivos aqui…"
msgid "Wrong extern UID provided. Make sure Auth0 is configured correctly."
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr "Você está tentando excluir um arquivo que foi atualizado anteriormente
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr "Você está tentando atualizar um arquivo que foi alterado desde que você começou a editá-lo."
+msgid "You are being redirected away from GitLab"
+msgstr "Você está sendo redirecionado para fora do GitLab"
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr "Você será cobrado se exceder esse número. %{qsrOverageLinkStart}Como funciona o faturamento?%{qsrOverageLinkEnd}"
@@ -45793,6 +46409,12 @@ msgstr "Você não tem permissão para %{action} um usuário"
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr "Você não tem permissão para criar esta tag, pois ela está protegida."
+
+msgid "You are not allowed to download code from this project."
+msgstr "Você não tem permissão para baixar o código deste projeto."
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr "Você pode testar o seu .gitlab-ci.yml no %{linkStart}CI Lint%{linkEnd}.
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr "Você pode ver a fonte ou %{linkStart}%{cloneIcon} clonar o repositório%{linkEnd}"
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr "Você não pode se passar por um usuário bloqueado"
msgid "You cannot impersonate a user who cannot log in"
msgstr "Você não pode se passar por um usuário que não pode fazer login"
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr "Você não pode se passar por um usuário interno"
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr "Você não tem permissões suficientes para gerenciar as tags de evento da linha do tempo para este projeto"
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr "Você deve estar conectado para pesquisar em todo o GitLab"
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr "YouTube"
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr "Sua conta %{host} foi conectada a partir de um novo local"
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr "A sua conta está bloqueada."
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr "Sua mensagem aqui"
msgid "Your name"
msgstr "Seu nome"
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr "Seu nome de usuário é %{username}."
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr "um usuário excluído"
@@ -46825,9 +47450,6 @@ msgstr[1] "há cerca de %d horas"
msgid "access:"
msgstr ""
-msgid "added"
-msgstr "adicionado"
-
msgid "added %{emails}"
msgstr "adicionou %{emails}"
@@ -46887,6 +47509,12 @@ msgstr "artefatos"
msgid "assign yourself"
msgstr "atribuir a si mesmo"
+msgid "assigned"
+msgstr "atribuído"
+
+msgid "assigned you"
+msgstr "atribuídos a você"
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr "não pode ser alterado"
@@ -47212,12 +47843,27 @@ msgstr "A verificação de dependência detecta vulnerabilidades conhecidas nas
msgid "ciReport|Dependency scanning"
msgstr "Verificação de dependência"
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr "Baixe o patch para resolver"
msgid "ciReport|Download the patch to apply it manually"
msgstr "Baixe o patch para aplicá-lo manualmente"
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr "O Teste de Segurança de Aplicativos Dinâmicos (DAST) detecta vulnerabilidades conhecidas em seu aplicativo da web."
@@ -47240,7 +47886,7 @@ msgid "ciReport|Full Report"
msgstr "Relatório completo"
msgid "ciReport|Generic Report"
-msgstr ""
+msgstr "Relatório genérico"
msgid "ciReport|IaC Scanning"
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr "Adicionado manualmente"
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr "Verificação de segurança"
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr "Solução"
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr "O Teste de Segurança de Aplicativos Estáticos (SAST) detecta vulnerabilidades conhecidas em seu código-fonte."
@@ -47411,6 +48066,9 @@ msgstr "commit %{commit_id}"
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr "completo"
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] "dias"
msgid "days"
msgstr "dias"
+msgid "default"
+msgstr "padrão"
+
msgid "default branch"
msgstr "ramificação padrão"
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] "de %d tarefa"
msgstr[1] "de %d tarefas"
+msgid "from yourself"
+msgstr "de você mesmo"
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr "nota interna"
msgid "invalid milestone state `%{state}`"
msgstr "estado de marco invalido '%{state}'"
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr "já está vinculado a esta vulnerabilidade"
+
msgid "is an invalid IP address range"
msgstr "é um intervalo de endereços IP inválido"
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr "não é um URL válido."
+
msgid "is not a valid X509 certificate."
msgstr "não é um certificado X509 válido."
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr "não é membro do grupo"
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr "não é membro do projeto"
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr "é somente leitura"
@@ -47939,9 +48618,6 @@ 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|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr "%{mergeError}."
@@ -48090,6 +48766,9 @@ 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 ""
+
msgid "mrWidget|Merge blocked: all threads must be resolved."
msgstr "Mesclagem bloqueada: todos os tópicos devem ser resolvidos."
@@ -48186,9 +48865,6 @@ msgstr "Reverter essa solicitação de mesclagem com um nova solicitação de me
msgid "mrWidget|Revoke approval"
msgstr "Revogar aprovação"
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr "deve ser depois do início"
msgid "must be an email you have verified"
msgstr "deve ser um email verificado"
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr "deve ser maior que a data de início"
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr "deve ser um espaço de nome de nível superior"
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr "deve ter um repositório"
@@ -48285,9 +48970,6 @@ msgstr "meu-canal"
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr "precisa ser entre 10 minutos e 1 mês"
@@ -48336,9 +49018,6 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}, e %{lastItem}"
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr "ou"
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] "de um total de %d teste"
-msgstr[1] "de um total de %d testes"
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr "páginas"
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "pai"
@@ -48497,9 +49174,6 @@ msgstr "remover data de início"
msgid "remove weight"
msgstr "remover peso"
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr "repositórios"
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] "repositório"
+msgstr[1] "repositórios"
+
msgid "repository:"
msgstr "repositório:"
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr "executando"
+
msgid "satisfied"
msgstr "satisfeito"
@@ -48681,6 +49363,9 @@ msgstr "este documento"
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr "para você mesmo"
+
msgid "today"
msgstr "hoje"
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr "você"
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/pt_PT/gitlab.po b/locale/pt_PT/gitlab.po
index be0f5131021..6a93ec2275d 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: 2022-10-10 14:01\n"
+"PO-Revision-Date: 2022-11-13 09:22\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d exportador"
msgstr[1] "%d exportadores"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d resultado do teste fixo"
-msgstr[1] "%d resultados do teste fixos"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr "mais %{count}"
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} participante"
msgstr[1] "%{count} participantes"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} continha %{resultsString}"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} encontrou %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "%{strong_start}%{branch_count}%{strong_end} Ramo"
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} %{time_spent_value} tempo passado."
@@ -1242,6 +1246,9 @@ msgstr "'%{source}' não é uma fonte de importação"
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d fechado)"
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr "Não tens permissão para acessar esta página."
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "Certifica-te de que o endereço está correto e a página não foi movida."
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr "Página Não Encontrada"
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "Um ramo padrão não pode ser escolhido para um projeto vazio."
-
msgid "A deleted user"
msgstr "Um utilizador apagado"
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr "Aceitar os termos"
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr "Ativo"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr "Sessões Ativas"
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr "Domínio Auto DevOps"
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr "Ativar executadores compartilhados aos novos projetos"
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr "Administradores"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,8 +3336,8 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
-msgstr "Pesquisar por nome, email ou nome de utilizador"
+msgid "AdminUsers|Search by name, email, or username"
+msgstr ""
msgid "AdminUsers|Search users"
msgstr "Pesquisar utilizadores"
@@ -3308,8 +3381,8 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "Para confirmar, digita %{projectName}"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "Para confirmar, digita %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr ""
msgid "AdminUsers|Unban user"
msgstr ""
@@ -3371,7 +3444,7 @@ msgstr "Sem projetos"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,8 +4005,8 @@ msgstr "Todos os utilizadores devem ter um nome."
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
-msgstr "Permitir que \"%{group_name}\" adicione-te"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr ""
msgid "Allow access to members of the following group"
msgstr ""
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr "Permitir que proprietários de grupos gerenciem as definições relacionadas ao LDAP"
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr "Ocorreu um erro ao buscar o registo do trabalho."
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr "Estatísticas"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr "Aplicação desinstalada mas falhou ao destruir: %{error_message}"
-
msgid "Application was successfully destroyed."
msgstr "A aplicação foi destruída com sucesso."
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr "Artefactos"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr "Atribui uma cor personalizada, como #FF0000"
msgid "Assign labels"
msgstr "Atribuir etiquetas"
-msgid "Assign milestone"
-msgstr "Atribuir objetivo"
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ 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 enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr "Ramo já está a ser usado"
msgid "Branch name"
msgstr "Nome do ramo"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr "Ramo não carregado - %{branchId}"
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr "Mensagem de transmissão atualizada com sucesso."
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "Procurar Diretório"
@@ -7039,9 +7178,6 @@ msgstr "Procurar Ficheiro"
msgid "Browse Files"
msgstr "Procurar Ficheiros"
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr "Procurar ficheiros"
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr "Não pode ser mesclado automaticamente"
@@ -7593,6 +7726,9 @@ msgstr "Não foi possível criar o relatório de abuso. Este utilizador foi bloq
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr "Chave"
msgid "CiVariables|Masked"
msgstr "Mascarado"
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Using a static site?"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr "Filtrar por nome de objetivo"
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ 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"
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr "Nenhumas outras etiquetas com tal nome ou descrição"
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr "Pesquisar por um grupo LDAP"
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr "um utilizador apagado"
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/ro_RO/gitlab.po b/locale/ro_RO/gitlab.po
index 8a5440b288c..9328769bce1 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: 2022-10-10 13:58\n"
+"PO-Revision-Date: 2022-11-13 09:20\n"
msgid " %{start} to %{end}"
msgstr " de la %{start} până la %{end}"
@@ -157,6 +157,12 @@ msgstr[0] "%d utilizator suplimentar"
msgstr[1] "%d utilizatori suplimentari"
msgstr[2] "%d de utilizatori suplimentari"
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] "%d aprobare necesară"
+msgstr[1] "%d aprobări necesare"
+msgstr[2] "%d de aprobări necesare"
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d aprobator"
@@ -277,24 +283,12 @@ msgstr[0] "%d epică"
msgstr[1] "%d epice"
msgstr[2] "%d de epice"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d eroare"
-msgstr[1] "%d erori"
-msgstr[2] "%d de erori"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d exportator"
msgstr[1] "%d exportatori"
msgstr[2] "%d de exportatori"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%d eșuare"
-msgstr[1] "%d eșuări"
-msgstr[2] "%d de eșuări"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] "%d job de securitate nereușit"
@@ -307,12 +301,6 @@ msgstr[0] "%d fișier"
msgstr[1] "%d fișiere"
msgstr[2] "%d de fișiere"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d rezultat de test rezolvat"
-msgstr[1] "%d rezultate de test rezolvate"
-msgstr[2] "%d de rezultate de test rezolvate"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] "%d fork"
@@ -595,6 +583,9 @@ msgstr[0] "%{bold_start}%{count}%{bold_end} merge request deschis"
msgstr[1] "%{bold_start}%{count}%{bold_end} merge request-uri deschise"
msgstr[2] "%{bold_start}%{count}%{bold_end} de merge request-uri deschise"
+msgid "%{chartTitle} no data series"
+msgstr "%{chartTitle} fără nicio serie de date"
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr "%{code_open}Mascate:%{code_close} Ascunse în jurnalele jobului. Trebuie să se potrivească cerințelor de mascare."
@@ -652,6 +643,18 @@ msgstr[2] "%{count} de contacte"
msgid "%{count} files touched"
msgstr "%{count} (de) fișiere atinse"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "%{count} element"
@@ -661,6 +664,12 @@ msgstr[2] "%{count} de elemente"
msgid "%{count} items per page"
msgstr "%{count} articole pe pagină"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%{count} more"
msgstr "%{count} mai mult"
@@ -685,6 +694,12 @@ msgstr[0] "%{count} participant"
msgstr[1] "%{count} participanți"
msgstr[2] "%{count} de participanți"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} de %{pluralized_subject} conexe: %{links}"
@@ -724,9 +739,6 @@ msgstr "%{docs_link_start}Ce este Large File Storage?%{docs_link_end}"
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr "%{docs_link_start}Ce este autentificarea cu doi factori?%{docs_link_end}"
-msgid "%{due_date} (Past due)"
-msgstr "%{due_date} (Depășit)"
-
msgid "%{duration}ms"
msgstr "%{duration}ms"
@@ -937,12 +949,6 @@ msgstr "Spațiul de nume %{name_with_link} a rămas fără minute de Pipeline pe
msgid "%{name} (Busy)"
msgstr "%{name} (Ocupat)"
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} conținea %{resultsString}"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} a găsit %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr "%{name} este deja folosit pentru un alt emoji"
@@ -1135,6 +1141,9 @@ msgstr[2] "%{strongStart}%{count}%{strongEnd} de commit-uri"
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr "%{strongStart}Sfat:%{strongEnd} De asemenea, puteți verifica merge request-urile la nivel local. %{linkStart}Aflați mai multe.%{linkEnd}"
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr "proiectele grupului %{strong_open}%{group_name}%{strong_close}:"
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "%{strong_start}%{branch_count}%{strong_end} Ramură"
@@ -1238,7 +1247,7 @@ msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr "%{total} (de) avertismente găsite: se afișează primul %{warningsDisplayed}"
msgid "%{type} must be a %{help_link}"
-msgstr ""
+msgstr "%{type} trebuie să fie un/o %{help_link}"
msgid "%{type} only supports %{name} name"
msgstr "%{type} acceptă numai numele %{name}"
@@ -1285,9 +1294,6 @@ msgstr "%{user} a creat o problemă: %{issue_link}"
msgid "%{value} is not included in the list"
msgstr "%{value} nu face parte din listă"
-msgid "%{value} s"
-msgstr "%{value} s"
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} %{time_spent_value} de timp petrecut."
@@ -1345,6 +1351,9 @@ msgstr "„%{source}†nu este o sursă de import"
msgid "'%{template_name}' is unknown or invalid"
msgstr "'%{template_name}' este necunoscut sau invalid"
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr "'%{value}' de zile de inactivitate trebuie să fie mai mare sau egală cu 90"
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d închis)"
@@ -1384,6 +1393,9 @@ msgstr "(lăsați necompletat dacă nu doriți să o modificați)"
msgid "(max size 15 MB)"
msgstr "(mărime maximă 15 MB)"
+msgid "(no user)"
+msgstr "(fără utilizator)"
+
msgid "(optional)"
msgstr "(opțional)"
@@ -1696,6 +1708,9 @@ msgstr "Nu aveți permisiunea de a accesa această pagină."
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "Asigurați-vă că adresa este corectă și pagina nu s-a mutat."
+msgid "404|Not found"
+msgstr "Nu s-a găsit"
+
msgid "404|Page Not Found"
msgstr "Pagina nu a fost găsită"
@@ -1759,9 +1774,6 @@ msgstr "O problemă confidențială nu poate avea un părinte care are deja copi
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr "Un element de lucru confidențial nu poate avea un părinte care are deja copii neconfidențiali."
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "O ramură implicită nu poate fi aleasă pentru un proiect gol."
-
msgid "A deleted user"
msgstr "Un utilizator șters"
@@ -1840,9 +1852,6 @@ msgstr "Un token de acces personal, numit %{token_name}, a fost revocat."
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr "Un site HTML simplu care folosește Netlify pentru CI/CD în loc de GitLab, dar totuși cu toate celelalte caracteristici grozave ale GitLab."
-msgid "A platform value can be web, mob or app."
-msgstr "O valoare a platformei poate fi web, mob sau aplicație."
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr "Un proiect cazan pentru dezvoltarea de aplicații Salesforce cu instrumente de dezvoltatori Salesforce"
@@ -2050,6 +2059,9 @@ msgstr "Acceptați termenii"
msgid "Acceptable for use in this project"
msgstr "Acceptabil pentru utilizare în acest proiect"
+msgid "Access Denied"
+msgstr "Acces refuzat"
+
msgid "Access Git repositories or the API."
msgstr "Accesați repozitoriile Git sau API."
@@ -2063,7 +2075,7 @@ msgid "Access denied for your LDAP account."
msgstr "Acces refuzat pentru contul dvs. LDAP."
msgid "Access denied: %{error}"
-msgstr "Acces interzis: %{error}"
+msgstr "Acces refuzat: %{error}"
msgid "Access expires"
msgstr "Accesul expiră"
@@ -2161,15 +2173,9 @@ msgstr "Tokenul dvs. de e-mail primit vă autentifică atunci când creați o no
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr "Tokenul dvs. pentru obiecte statice vă autentifică atunci când obiectele statice din repozitoriu (cum ar fi arhivele sau blob-urile) sunt servite dintr-o stocare externă."
-msgid "AccessibilityReport|Learn more"
-msgstr "Aflați mai multe"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "Mesaj: %{message}"
-msgid "AccessibilityReport|New"
-msgstr "Nou"
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr "Scanarea de accesibilitate a găsit o eroare de tipul următor: %{code}"
@@ -2239,9 +2245,6 @@ msgstr "Activ"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr "%{accessTokenTypePlural} active (%{totalAccessTokens})"
-msgid "Active %{type} (%{token_length})"
-msgstr "%{type} activ (%{token_length})"
-
msgid "Active Sessions"
msgstr "Sesiuni active"
@@ -2614,6 +2617,12 @@ msgstr "Adaugă %{labels} %{label_text}."
msgid "Adds a Zoom meeting."
msgstr "Adaugă o reuniune Zoom."
+msgid "Adds a resource link"
+msgstr "Adaugă un link de resurse"
+
+msgid "Adds a resource link for this incident."
+msgstr "Adaugă un link de resurse pentru acest incident."
+
msgid "Adds a timeline event to incident."
msgstr "Adaugă un eveniment de cronologie la incident."
@@ -2797,6 +2806,24 @@ msgstr "Sunteți pe cale să opriți toate joburile. Acest lucru va opri toate j
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr "Eroare la încărcarea statisticilor. Vă rugăm să încercați din nou"
+msgid "AdminEmail|Body"
+msgstr "Corp"
+
+msgid "AdminEmail|Body is required."
+msgstr "Corpul este necesar."
+
+msgid "AdminEmail|Recipient group or project"
+msgstr "Destinatar de grup sau proiect"
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr "Destinatarul grupului sau proiectului este obligatoriu."
+
+msgid "AdminEmail|Subject"
+msgstr "Subiect"
+
+msgid "AdminEmail|Subject is required."
+msgstr "Subiectul este obligatoriu."
+
msgid "AdminLabels|Define your default set of project labels"
msgstr "Definiți setul dvs. implicit de etichete de proiect"
@@ -2833,15 +2860,27 @@ msgstr "Domeniul Auto DevOps"
msgid "AdminSettings|CI/CD limits"
msgstr "Limitele CI/CD"
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr "Configurați Let's Encrypt"
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr "Configurați limitele numărului de repozitorii care pot fi descărcate de utilizatori într-un anumit interval de timp."
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr "Configurați când proiectele inactive trebuie să fie șterse automat. %{linkStart}Ce sunt proiectele inactive?%{linkEnd}"
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr "Ștergeți proiectele inactive"
@@ -2890,6 +2929,9 @@ msgstr "Activați analizatorul personalizat kuromoji: Căutare"
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr "Activați bannerul de sugestie pentru pipeline"
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr "Activați executorii partajați pentru proiecte noi"
@@ -2935,6 +2977,18 @@ msgstr "Ștergerea proiectelor inactive"
msgid "AdminSettings|Instance runners expiration"
msgstr "Expirarea executanților de instanță"
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr "Păstrați cele mai recente artefacte pentru toate joburile din cele mai recente pipeline-uri de succes"
@@ -3073,9 +3127,18 @@ msgstr "Setarea trebuie să fie mai mare de 0."
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr "Setările de mărime și domeniu pentru site-urile statice Pages."
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr "Domeniul implicit de utilizat pentru etapele Auto Review Apps și Auto Deploy în toate proiectele."
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr "Cele mai recente artefacte pentru toate joburile din cele mai recente pipeline-uri reușite din fiecare proiect sunt stocate și nu expiră."
@@ -3100,6 +3163,15 @@ msgstr "Numărul total de joburi în pipeline-urile active în prezent"
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr "Utilizați serviciul AWS OpenSearch cu acreditările IAM"
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr "Atât utilizatorii, cât și grupurile trebuie să accepte invitația înainte de a fi adăugați la un grup sau la un proiect."
@@ -3202,6 +3274,9 @@ msgstr "Administrator"
msgid "AdminUsers|Admins"
msgstr "Administratori"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr "Aprobare"
@@ -3394,8 +3469,8 @@ msgstr "Va fi generat și trimis utilizatorului un link de resetare. Utilizatoru
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr "Restabiliți accesul utilizatorului la cont, inclusiv la web, Git și API."
-msgid "AdminUsers|Search by name, email or username"
-msgstr "Căutați după nume, e-mail sau nume de utilizator"
+msgid "AdminUsers|Search by name, email, or username"
+msgstr "Căutare după nume, e-mail sau nume de utilizator"
msgid "AdminUsers|Search users"
msgstr "Căutați utilizatori"
@@ -3439,8 +3514,8 @@ msgstr "Utilizatorul nu va primi nicio notificare"
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "Pentru a confirma, tastați %{projectName}"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "Pentru a confirma, tastați %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr ""
msgid "AdminUsers|Unban user"
msgstr "Anulați interdicția utilizatorului"
@@ -3502,8 +3577,8 @@ msgstr "Fără proiecte"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr "Sunteți pe cale să ștergeți definitiv utilizatorul %{username}. Problemele, merge request-urile și grupurile legate de acestea vor fi transferate către un „Utilizator-fantomă†la nivel de sistem. Pentru a evita pierderea de date, luați în considerare utilizarea în schimb a funcției %{strongStart}blocare utilizator%{strongEnd}. Odată ce %{strongStart}Ștergeți utilizatorul%{strongEnd}, această operațiune nu mai poate fi anulată, nici contul recuperat."
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
-msgstr "Sunteți pe cale să ștergeți definitiv utilizatorul %{username}. Aceasta va șterge toate problemele, merge request-urile și grupurile legate de acesta. Pentru a evita pierderea de date, luați în considerare posibilitatea de a utiliza în schimb funcția %{strongStart}blocare utilizator%{strongEnd}. Odată ce ați folosit %{strongStart}Ștergeți utilizator%{strongEnd}, aceasta operațiune nu mai poate fi anulată sau contul recuperat."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
+msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
msgstr "Puteți oricând să le blocați din nou contul, dacă este necesar."
@@ -3550,6 +3625,9 @@ msgstr "Administrație"
msgid "Administrators"
msgstr "Administratori"
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr "Utilizatorii suplimentari trebuie să fie verificați și aprobați de un administrator de sistem. Aflați mai multe despre %{help_link_start}plafoanele de utilizare%{help_link_end}."
@@ -3593,19 +3671,19 @@ msgid "AdvancedSearch|Elasticsearch version not compatible"
msgstr "Versiunea Elasticsearch nu este compatibilă"
msgid "AdvancedSearch|Introduced in GitLab 13.1, before using %{reindexing_link_start}zero-downtime reindexing%{link_end} and %{migrations_link_start}Advanced Search migrations%{link_end}, you need to %{recreate_link_start}recreate your index%{link_end}."
-msgstr ""
+msgstr "Introdus în GitLab 13.1, înainte de a utiliza %{reindexing_link_start}reindexarea cu zero-downtime%{link_end} și %{migrations_link_start}migrările de Căutare avansată%{link_end}, trebuie să %{recreate_link_start}recreați indexul%{link_end}."
msgid "AdvancedSearch|Pause indexing and upgrade Elasticsearch to a supported version."
-msgstr ""
+msgstr "Întrerupeți indexarea și actualizați Elasticsearch la o versiune acceptată."
msgid "AdvancedSearch|Reindex recommended"
-msgstr ""
+msgstr "Reindexare recomandată"
msgid "AdvancedSearch|Reindex required"
msgstr "Reindexare necesară"
msgid "AdvancedSearch|You are using outdated code search mappings. To improve code search quality, we recommend you use %{reindexing_link_start}zero-downtime reindexing%{link_end} or %{recreate_link_start}re-create your index%{link_end}."
-msgstr ""
+msgstr "Folosiți mapări de căutare a codurilor învechite. Pentru a îmbunătăți calitatea căutării codului, vă recomandăm să utilizați o %{reindexing_link_start}reindexare cu zero-downtime%{link_end} sau %{recreate_link_start}să creați din nou indexul%{link_end}."
msgid "After a successful password update you will be redirected to login screen."
msgstr "După o actualizare reușită a parolei, veți fi redirecționat către ecranul de conectare."
@@ -4060,8 +4138,8 @@ msgstr "Toți utilizatorii trebuie să aibă un nume."
msgid "All users with matching cards"
msgstr "Toți utilizatorii cu carduri care se potrivesc"
-msgid "Allow \"%{group_name}\" to sign you in"
-msgstr "Permiteți \"%{group_name}\" să vă conecteze"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr "Permiteți ca %{strongOpen}%{group_name}%{strongClose} să vă conecteze?"
msgid "Allow access to members of the following group"
msgstr "Permiteți accesul membrilor din următorul grup"
@@ -4075,6 +4153,9 @@ msgstr "Permiteți commit-uri de la membrii care pot îmbina cu ramura țintă.
msgid "Allow group owners to manage LDAP-related settings"
msgstr "Permiteți proprietarilor de grup să gestioneze setările legate de LDAP"
+msgid "Allow new users to create top-level groups"
+msgstr "Permiteți ca noii utilizatori să creeze grupuri de nivel superior"
+
msgid "Allow non-administrators access to the performance bar"
msgstr "Permiteți accesul non-administratorilor la bara de performanță"
@@ -4111,9 +4192,6 @@ msgstr "Permiteți acestei chei să facă push către acest repozitoriu"
msgid "Allow use of licensed EE features"
msgstr "Permiteți utilizarea funcțiilor EE licențiate"
-msgid "Allow users to create top-level groups"
-msgstr "Permiteți utilizatorilor să creeze grupuri de nivel superior"
-
msgid "Allow users to dismiss the broadcast message"
msgstr "Permiteți utilizatorilor să respingă mesajul difuzat"
@@ -4360,6 +4438,9 @@ msgstr "A apărut o eroare în timpul căutării etichetelor. Reîncercați cău
msgid "An error occurred while fetching terraform reports."
msgstr "A apărut o eroare în timpul preluării rapoartelor terraform."
+msgid "An error occurred while fetching the health status."
+msgstr "S-a produs o eroare la preluarea stării de sănătate."
+
msgid "An error occurred while fetching the job log."
msgstr "A apărut o eroare în timpul preluării jurnalului de lucru."
@@ -4546,9 +4627,6 @@ msgstr "S-a produs o eroare la declanșarea jobului."
msgid "An error occurred while trying to follow this user, please try again."
msgstr "A apărut o eroare la încercarea de a urmări acest utilizator, vă rugăm să încercați din nou."
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr "A apărut o eroare în timpul încercării de generare a raportului. Vă rugăm să încercați din nou mai târziu."
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr "A survenit o eroare în timpul încercării de a afișa editorul de conținut. Încercați din nou."
@@ -4648,9 +4726,6 @@ msgstr "A apărut o eroare necunoscută."
msgid "Analytics"
msgstr "Analize"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "Analizați-vă dependențele pentru vulnerabilități cunoscute."
@@ -4753,9 +4828,6 @@ msgstr "Setările aplicației au fost salvate cu succes."
msgid "Application settings update failed"
msgstr "Actualizarea setărilor aplicației a eșuat"
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr "Aplicația a fost dezinstalată, dar nu a reușit să fie ștearsă: %{error_message}"
-
msgid "Application was successfully destroyed."
msgstr "Aplicația a fost distrusă cu succes."
@@ -4774,8 +4846,8 @@ msgstr "Adăugați un link la Grafana"
msgid "ApplicationSettings|After sign-up text"
msgstr "După textul de înregistrare"
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
-msgstr "După ce instanța atinge plafonul de utilizatori, orice utilizator care este adăugat sau solicită acces trebuie să fie aprobat de un administrator. Lăsați necompletat pentru nelimitat."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
+msgstr "După ce instanța atinge plafonul de utilizatori, orice utilizator adăugat sau care solicită acces trebuie să fie aprobat de un administrator. Lăsați gol pentru un plafon nelimitat de utilizatori. Dacă modificați plafonul de utilizatori la nelimitat, trebuie să reactivați %{projectSharingLinkStart}partajarea proiectelor%{projectSharingLinkEnd} și %{groupSharingLinkStart}partajarea grupurilor%{groupSharingLinkEnd}."
msgid "ApplicationSettings|Allowed domains for sign-ups"
msgstr "Domenii permise pentru înscrieri"
@@ -4819,6 +4891,9 @@ msgstr "Fișier cu lista de refuzări"
msgid "ApplicationSettings|Domain denylist"
msgstr "Lista de domenii refuzate"
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr "Setări de confirmare prin e-mail"
+
msgid "ApplicationSettings|Email restrictions"
msgstr "Restricții de e-mail"
@@ -4837,9 +4912,18 @@ msgstr "Activați restricțiile de e-mail pentru înscrieri"
msgid "ApplicationSettings|Enter denylist manually"
msgstr "Completați manual lista de refuzări"
+msgid "ApplicationSettings|Hard"
+msgstr "Dură"
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr "Lungimea minimă a parolei (număr de caractere)"
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr "Utilizatorii noi se pot înregistra fără a-și confirma adresa de e-mail."
+
+msgid "ApplicationSettings|Off"
+msgstr "Oprită"
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr "Numai utilizatorii cu adrese de e-mail care corespund acestor domenii se pot înscrie. Sunt permise caractere wildcard. Folosiți linii separate pentru intrări multiple. Exemplu: domain.com, *.domain.com"
@@ -4867,6 +4951,9 @@ 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 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|Send confirmation email on sign-up"
msgstr "Trimiteți un e-mail de confirmare la înscriere"
@@ -5212,9 +5299,6 @@ 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 these artifacts?"
-msgstr "Sunteți sigur că doriți să ștergeți aceste artefacte?"
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr "Sunteți sigur că doriți să ștergeți acest %{commentType}?"
@@ -5317,8 +5401,8 @@ msgstr "Sunteți sigur că doriți să reîncercați această migrare?"
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr "Sunteți sigur că doriți să revocați acest %{accessTokenType}? Această acțiune nu poate fi anulată."
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
-msgstr "Sunteți sigur că doriți să revocați acest %{type}? Această acțiune nu poate fi anulată."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr "Sunteți sigur că doriți să revocați acest token de acces personal? Această acțiune nu poate fi anulată."
@@ -5368,6 +5452,30 @@ msgstr "Artefactul a fost șters cu succes."
msgid "Artifacts"
msgstr "Artefacte"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr "A apărut o eroare la ștergerea artefactului"
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr "A apărut o eroare în timpul recuperării artefactelor jobului"
+
+msgid "Artifacts|Artifacts"
+msgstr "Artefacte"
+
+msgid "Artifacts|Browse"
+msgstr "Răsfoiți"
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr "Mărimea totală a artefactelor"
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr "Pe măsură ce continuăm să dezvoltăm mai multe funcții pentru SAST, ne-ar plăcea să primim feedback-ul dvs. cu privire la funcția de configurare SAST în %{linkStart}această problemă%{linkEnd}."
@@ -5419,9 +5527,6 @@ msgstr "Atribuire de culoare personalizată, cum ar fi # FF0000"
msgid "Assign labels"
msgstr "Atribuire etichete"
-msgid "Assign milestone"
-msgstr "Atribuiți un obiectiv"
-
msgid "Assign myself"
msgstr "Atribuire personală"
@@ -5818,9 +5923,6 @@ msgstr "Oprirea automată a fost anulată cu succes."
msgid "Auto-cancel redundant pipelines"
msgstr "Auto-anulare de pipeline-uri redundante"
-msgid "Auto-close referenced issues on default branch"
-msgstr "Închiderea automată a problemelor referite pe ramura implicită"
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr "%{auto_devops_start}Automatizați construirea, testarea și implementarea%{auto_devops_end} propriilor aplicații pe baza configurației de integrare și livrare continuă. %{quickstart_start}Cum pot începe?%{quickstart_end}"
@@ -6184,6 +6286,12 @@ 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 enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr "Înainte de a activa această integrare, creați un webhook pentru camera din Google Chat în care doriți să primiți notificări de la acest proiect. %{docs_link}"
@@ -6916,6 +7024,9 @@ msgstr "Ramura există deja"
msgid "Branch changed"
msgstr "Ramura schimbată"
+msgid "Branch defaults"
+msgstr "Valorile implicite ale ramurii"
+
msgid "Branch has been updated since the merge was requested."
msgstr "Ramura a fost actualizată de când a fost solicitată îmbinarea."
@@ -6925,6 +7036,9 @@ msgstr "Ramura este deja luată"
msgid "Branch name"
msgstr "Numele ramurii"
+msgid "Branch name template"
+msgstr "Șablonul numelui ramurii"
+
msgid "Branch not loaded - %{branchId}"
msgstr "Ramura nu a fost încărcată - %{branchId}"
@@ -6932,58 +7046,67 @@ msgid "Branch rules"
msgstr "Reguli pentru ramură"
msgid "BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or production/ are supported"
-msgstr ""
+msgstr "%{linkStart}Caracterele wildcard%{linkEnd}, cum ar fi *-stable sau production/, sunt acceptate."
msgid "BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or production/* are supported."
msgstr "Sunt acceptate wildcard-uri %{linkStart}%{linkEnd}, cum ar fi *-stable sau production/*."
msgid "BranchRules|All branches"
-msgstr ""
+msgstr "Toate ramurile"
msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
+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}."
+msgid "BranchRules|Allowed to force push"
+msgstr "Permise pentru push forțat"
+
msgid "BranchRules|Allowed to merge"
msgstr "Permise pentru îmbinare"
msgid "BranchRules|Allowed to merge (%{total})"
-msgstr ""
+msgstr "Permise să îmbine (%{total})"
msgid "BranchRules|Allowed to push"
msgstr "Permise pentru push"
msgid "BranchRules|Allowed to push (%{total})"
-msgstr ""
+msgstr "Permise să facă push (%{total})"
msgid "BranchRules|An error occurred while fetching branches."
msgstr "A apărut o eroare în timpul preluării ramurilor."
msgid "BranchRules|Approvals"
+msgstr "Aprobări"
+
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
msgid "BranchRules|Branch"
msgstr "Ramura"
msgid "BranchRules|Branch name or pattern"
-msgstr ""
+msgstr "Numele sau modelul ramurii"
msgid "BranchRules|Branch rules details"
msgstr "Detaliile regulilor ramurii"
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr "Creați un wildcard: %{searchTerm}"
msgid "BranchRules|Details"
-msgstr ""
+msgstr "Detalii"
msgid "BranchRules|Force push"
-msgstr ""
+msgstr "Push forțat"
msgid "BranchRules|Force push is not allowed."
-msgstr ""
+msgstr "Nu este permis push forțat."
msgid "BranchRules|Groups"
msgstr "Grupuri"
@@ -6991,17 +7114,23 @@ msgstr "Grupuri"
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr "Păstrați ramurile stabile în siguranță și forțați dezvoltatorii să folosească merge request-uri. %{linkStart}Ce sunt ramurile protejate?%{linkEnd}"
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr "Gestionați în Aprobările merge request-urilor"
+
msgid "BranchRules|Manage in Protected Branches"
+msgstr "Gestionați în ramuri protejate"
+
+msgid "BranchRules|Manage in Status checks"
msgstr ""
msgid "BranchRules|No data to display"
-msgstr ""
+msgstr "Nu există date de afișat"
msgid "BranchRules|No matching results"
msgstr "Nu există rezultate care să corespundă"
msgid "BranchRules|Protect branch"
-msgstr ""
+msgstr "Protejați ramura"
msgid "BranchRules|Protections"
msgstr "Protecții"
@@ -7012,10 +7141,19 @@ msgstr "Refuzați împingerile de cod care modifică fișierele enumerate în fi
msgid "BranchRules|Require approval from code owners."
msgstr "Necesită aprobarea proprietarilor de coduri."
+msgid "BranchRules|Required approvals (%{total})"
+msgstr "Aprobări necesare (%{total})"
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr "Este necesară aprobarea CODEOWNERS"
+
msgid "BranchRules|Roles"
msgstr "Roluri"
msgid "BranchRules|Status checks"
+msgstr "Verificări de stare"
+
+msgid "BranchRules|Status checks (%{total})"
msgstr ""
msgid "BranchRules|Target Branch"
@@ -7177,6 +7315,9 @@ msgstr "Mesajul de difuzare a fost actualizat cu succes."
msgid "Broadcast Messages"
msgstr "Mesaje de difuzare"
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr "A apărut o problemă la ștergerea acestui mesaj, vă rugăm să încercați din nou mai târziu."
+
msgid "Browse Directory"
msgstr "Răsfoiți directorul"
@@ -7186,9 +7327,6 @@ msgstr "Răsfoiți fișierul"
msgid "Browse Files"
msgstr "Răsfoiți fișierele"
-msgid "Browse artifacts"
-msgstr "Răsfoiți artefactele"
-
msgid "Browse files"
msgstr "Răsfoiți fișierele"
@@ -7234,9 +7372,6 @@ msgstr "Filtrați după grupul sursă"
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr "Următoarele date nu vor fi migrate: %{bullets} Contactați administratorul de sistem al %{host} pentru a actualiza GitLab dacă aveți nevoie de aceste date în migrația dumneavoastră"
-msgid "BulkImport|From source group"
-msgstr "Din grupul sursă"
-
msgid "BulkImport|Group import history"
msgstr "Istoricul importului grupului"
@@ -7267,6 +7402,9 @@ msgstr "Numele există deja."
msgid "BulkImport|Name already used as a target for another group."
msgstr "Nume deja utilizat ca țintă pentru un alt grup."
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr "Nu sunt furnizate informații suplimentare."
@@ -7282,6 +7420,9 @@ msgstr "Fără părinte"
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr "Numai grupurile pentru care aveți rolul de %{role} sunt listate ca grupuri pe care le puteți importa."
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr "Istoricul importului proiectului"
@@ -7306,9 +7447,6 @@ msgstr "Grupul sursă"
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr "Șablon / Import bazat pe fișiere / Migrație GitLab"
-msgid "BulkImport|To new group"
-msgstr "La un grup nou"
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr "Actualizarea statusurilor de import cu modificările în timp real a eșuat"
@@ -7723,9 +7861,6 @@ msgstr "Anulare previzualizare"
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr "Nu se poate atribui o epocă de tip confidențial unei probleme neconfidențiale. Faceți problema confidențială și încercați din nou."
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr "Nu se poate atribui o problemă care nu aparține aceluiași grup (sau descendent) ca și epica."
-
msgid "Cannot be merged automatically"
msgstr "Nu poate fi îmbinat automat"
@@ -7741,6 +7876,9 @@ msgstr "Nu se poate crea raportul de abuz. Acest utilizator a fost blocat."
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr "Nu se poate șterge %{profile_name} la care se face referire în politica de securitate"
+msgid "Cannot delete the default framework"
+msgstr "Nu se poate șterge framework-ul implicit"
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr "Nu se pot executa mai multe importuri Jira în același timp"
@@ -8482,6 +8620,9 @@ msgstr "Cheie"
msgid "CiVariables|Masked"
msgstr "Mascată"
+msgid "CiVariables|Options"
+msgstr "Opțiuni"
+
msgid "CiVariables|Protected"
msgstr "Protejat"
@@ -9799,11 +9940,17 @@ msgstr "Comentariu pe liniile de la %{startLine} la %{endLine}"
msgid "Comment/Reply (quoting selected text)"
msgstr "Comentariu/Răspuns (citând textul selectat)"
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
-msgstr "Comentarea fișierelor care înlocuiesc sau sunt înlocuite de legături simbolice nu este acceptată în prezent."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
-msgstr "Comentarea legăturilor simbolice care înlocuiesc sau sunt înlocuite de fișiere nu este acceptată în prezent."
+msgid "Commenting on this line is not supported"
+msgstr ""
msgid "Comments"
msgstr "Comentarii"
@@ -9985,6 +10132,9 @@ msgstr "Completați verificarea pentru a vă autentifica."
msgid "Complete verification to sign up."
msgstr "Completați verificarea pentru a vă înscrie."
+msgid "Complete with errors"
+msgstr "Completat cu erori"
+
msgid "Completed"
msgstr "Completat"
@@ -10055,7 +10205,7 @@ msgid "ComplianceFrameworks|No compliance frameworks are set up yet"
msgstr "Încă nu sunt configurate framework-uri de conformitate"
msgid "ComplianceFrameworks|Required format: %{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}. %{linkStart}What is a compliance pipeline configuration?%{linkEnd}"
-msgstr ""
+msgstr "Format obligatoriu: %{codeStart}cale/fișier.y[a]ml@nume-grup/nume-proiect%{codeEnd}. %{linkStart}Ce este o configurație pipeline de conformitate?%{linkEnd}"
msgid "ComplianceFrameworks|Unable to save this compliance framework. Please try again"
msgstr "Nu se poate salva acest framework de conformitate. Vă rugăm să încercați din nou"
@@ -10373,7 +10523,7 @@ msgid "Container Registry"
msgstr "Registrul de containere"
msgid "Container Repository"
-msgstr ""
+msgstr "Repozitoriul de containere"
msgid "Container Scanning"
msgstr "Scanarea containerelor"
@@ -10783,11 +10933,11 @@ msgstr "Contribuție"
msgid "Contribution Analytics"
msgstr "Analize de contribuții"
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
-msgstr "%{created_count} create, %{closed_count} închise."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
+msgstr "%{created} create, %{closed} închise."
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
-msgstr "%{created_count} create, %{merged_count} îmbinate, %{closed_count} închise."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
+msgstr "%{created} create, %{merged} îmbinate, %{closed} închise."
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr "%{pushes}, mai mult de %{commits} făcute de %{contributors}."
@@ -10819,6 +10969,15 @@ msgstr "Nu există merge request-uri pentru perioada de timp selectată."
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr "Nu există împingeri pentru perioada de timp selectată."
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr "Contribuții pentru %{calendar_date}"
@@ -10867,9 +11026,6 @@ msgstr "Copiați %{name}"
msgid "Copy %{protocol} clone URL"
msgstr "Copiați URL-ul clonei %{protocol}"
-msgid "Copy %{type}"
-msgstr "Copiați %{type}"
-
msgid "Copy ID"
msgstr "Copiați ID-ul"
@@ -10954,9 +11110,6 @@ msgstr "Copiați secretul"
msgid "Copy source branch name"
msgstr "Copiați numele ramurii sursă"
-msgid "Copy the code below to implement tracking in your application:"
-msgstr "Copiați codul de mai jos pentru a implementa urmărirea în aplicația d-voastră:"
-
msgid "Copy this registration token."
msgstr "Copiați acest token de înregistrare."
@@ -11119,9 +11272,6 @@ msgstr "Nu se poate încărca numărul de utilizări. Vă rugăm să reîmprospÄ
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr "Nu s-a putut înlătura %{user} din %{group}. Nu se poate elimina ultimul proprietar de grup."
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr "Nu s-a putut înlătura %{user} din %{group}. Utilizatorul nu este membru al grupului."
-
msgid "Could not remove the trigger."
msgstr "Nu s-a putut înlătura declanșatorul."
@@ -11341,9 +11491,6 @@ msgstr "Creați un nou fișier sau un director"
msgid "Create new label"
msgstr "Creați o nouă etichetă"
-msgid "Create new project"
-msgstr "Creați un nou proiect"
-
msgid "Create new..."
msgstr "Creare de nou(ă)..."
@@ -11611,9 +11758,6 @@ msgstr "Se creează epica"
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr "Crearea graficelor utilizează datele de pe serverul Prometheus. Dacă durează mult, asigurați-vă că datele sunt disponibile."
-msgid "Creation date"
-msgstr "Data creării"
-
msgid "Creator"
msgstr "Creator"
@@ -11629,8 +11773,8 @@ msgstr "Nu s-au găsit acreditări"
msgid "CredentialsInventory|Personal Access Tokens"
msgstr "Tokenuri de acces personal"
-msgid "CredentialsInventory|Project Access Tokens"
-msgstr "Tokenuri de acces la proiect"
+msgid "CredentialsInventory|Project and Group Access Tokens"
+msgstr ""
msgid "CredentialsInventory|SSH Keys"
msgstr "Chei SSH"
@@ -11731,9 +11875,6 @@ msgstr "Ramura actuală"
msgid "Current Project"
msgstr "Proiectul actual"
-msgid "Current forks will keep their visibility level."
-msgstr "Forkurile actuale își vor păstra nivelul de vizibilitate."
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr "Nodul actual trebuie să fie nodul primar, altfel vă blocați singur."
@@ -12061,6 +12202,9 @@ msgstr "Rata de eșec a modificărilor"
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr "Rata de eșec a modificării (procentaj)"
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr "Metrici DORA pentru grupul %{groupName}"
+
msgid "DORA4Metrics|Date"
msgstr "Data"
@@ -12088,6 +12232,9 @@ msgstr "Timpul mediu (ultimele %{days}d)"
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr "Timpul mediu în care un incident a fost deschis într-un mediu de producție în perioada de timp dată."
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr "Niciun incident în această perioadă"
@@ -12145,6 +12292,9 @@ msgstr "Personal"
msgid "DashboardProjects|Trending"
msgstr "Tendințe"
+msgid "Dashboards"
+msgstr "Tablouri de bord"
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr "%{firstProject} și %{secondProject}"
@@ -12379,6 +12529,9 @@ msgstr "SalvaÈ›i configuraÈ›iile utilizate în mod obiÈ™nuit pentru site-urile È
msgid "DastProfiles|Save profile"
msgstr "Salvați profilul"
+msgid "DastProfiles|Scan Method"
+msgstr "Metoda de scanare"
+
msgid "DastProfiles|Scan method"
msgstr "Metoda de scanare"
@@ -12598,6 +12751,9 @@ msgstr "Reîmprospătarea datelor"
msgid "Data type"
msgstr "Tipul de date"
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr "Actualizarea bazei de date a eșuat"
@@ -12685,6 +12841,9 @@ msgstr "Mi"
msgid "Days"
msgstr "Zile"
+msgid "Days of inactivity before deactivation"
+msgstr "Zile de inactivitate înainte de dezactivare"
+
msgid "Days to merge"
msgstr "Zile până la îmbinare"
@@ -12718,6 +12877,9 @@ msgstr "Validarea mărimii arhivei decomprimate a eșuat."
msgid "Decrease"
msgstr "Descreștere"
+msgid "Default - Never run"
+msgstr "Implicit - Nu se execută niciodată"
+
msgid "Default CI/CD configuration file"
msgstr "Fișier implicit de configurare CI/CD"
@@ -12829,6 +12991,9 @@ msgstr "Șterge"
msgid "Delete %{issuableType}"
msgstr "Ștergeți %{issuableType}"
+msgid "Delete %{issuableType}?"
+msgstr "Ștergeți %{issuableType}?"
+
msgid "Delete %{name}"
msgstr "Ștergeți %{name}"
@@ -12850,9 +13015,6 @@ msgstr "Ștergeți Fluxul de valori"
msgid "Delete account"
msgstr "Ștergeți contul"
-msgid "Delete artifacts"
-msgstr "Ștergeți artefactele"
-
msgid "Delete asset"
msgstr "Ștergeți activul"
@@ -12919,7 +13081,7 @@ msgstr "Ștergeți versiunea %{release}?"
msgid "Delete row"
msgstr "Ștergeți rândul"
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr "Ștergeți proiectul de automonitorizare"
msgid "Delete snippet"
@@ -13402,6 +13564,9 @@ msgstr "Data expirării (opțional)"
msgid "DeployTokens|Expires"
msgstr "Expiră"
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr "Nu s-a reușit crearea unui nou token de implementare"
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr "Tokenurile de implementare de grup permit accesul la pachetele, depozitele și imaginile de registru din cadrul grupului."
@@ -13489,6 +13654,21 @@ msgstr "Selectați ținta de implementare"
msgid "Deployment frequency"
msgstr "Frecvența de implementare"
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr " Aprobări actuale: %{current}"
@@ -13706,7 +13886,7 @@ msgid "DesignManagement|Are you sure you want to cancel creating this comment?"
msgstr "Sunteți sigur că doriți să anulați crearea acestui comentariu?"
msgid "DesignManagement|Are you sure you want to cancel editing this comment?"
-msgstr ""
+msgstr "Sigur doriți să anulați editarea acestui comentariu?"
msgid "DesignManagement|Click the image where you'd like to start a new discussion"
msgstr "Faceți clic pe imagine acolo unde doriți să începeți o nouă discuție"
@@ -13715,10 +13895,10 @@ msgid "DesignManagement|Comment"
msgstr "Comentariu"
msgid "DesignManagement|Continue creating"
-msgstr ""
+msgstr "Continuați crearea"
msgid "DesignManagement|Continue editing"
-msgstr ""
+msgstr "Continuați editarea"
msgid "DesignManagement|Could not add a new comment. Please try again."
msgstr "Nu s-a putut adăuga un comentariu nou. Vă rugăm să încercați din nou."
@@ -13739,7 +13919,7 @@ msgid "DesignManagement|Designs"
msgstr "Design"
msgid "DesignManagement|Discard changes"
-msgstr ""
+msgstr "Renunțați la modificări"
msgid "DesignManagement|Discussion"
msgstr "Discuție"
@@ -13831,6 +14011,9 @@ msgstr "Rapoarte DevOps"
msgid "DevOps adoption"
msgstr "Adoptarea DevOps"
+msgid "Developer"
+msgstr "Dezvoltator"
+
msgid "Development"
msgstr "Dezvoltare"
@@ -14071,6 +14254,12 @@ msgstr[2] "%d de ștergeri"
msgid "Diffs|Expand all lines"
msgstr "Extindeți toate liniile"
+msgid "Diffs|Hide whitespace changes"
+msgstr "Ascundeți modificările spațiilor albe"
+
+msgid "Diffs|Inline"
+msgstr "Inline"
+
msgid "Diffs|Next 20 lines"
msgstr "Următoarele 20 de linii"
@@ -14086,12 +14275,18 @@ msgstr "Afișați %{unfoldCount} linii"
msgid "Diffs|Show all unchanged lines"
msgstr "Afișați toate liniile neschimbate"
+msgid "Diffs|Show whitespace changes"
+msgstr "Afișați modificările spațiilor albe"
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] "Se afișează %{dropdownStart}%{count} fișier modificat%{dropdownEnd}"
msgstr[1] "Se afișează %{dropdownStart}%{count} fișiere modificate%{dropdownEnd}"
msgstr[2] "Se afișează %{dropdownStart}%{count} de fișiere modificate%{dropdownEnd}"
+msgid "Diffs|Side-by-side"
+msgstr "Una lângă alta"
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Ceva nu a mers bine în timpul preluării liniilor diff."
@@ -14698,6 +14893,12 @@ msgstr "Editat"
msgid "Edited %{timeago}"
msgstr "Editat(ă) %{timeago}"
+msgid "Edited %{timeago} by %{author}"
+msgstr "Editat %{timeago} de %{author}"
+
+msgid "Edited by %{author}"
+msgstr "Editat de %{author}"
+
msgid "Editing"
msgstr "Editare"
@@ -15028,23 +15229,41 @@ msgstr "Activați e-mailurile de dezactivare a utilizatorilor"
msgid "Enable version check"
msgstr "Activați verificarea versiunii"
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
-msgstr "%{stepStart}Etapa 1%{stepEnd}. Asigurați-vă că ați configurat Kubernetes și că aveți un domeniu de bază pentru %{linkStart}clusterul%{linkEnd} dumneavoastră."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr "Adăugați un job în configurația CI/CD care:"
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
-msgstr "%{stepStart}Etapa 2%{stepEnd}. Copiați următorul fragment de cod:"
+msgid "EnableReviewApp|Copy snippet"
+msgstr "Copiați fragmentul"
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
-msgstr "%{stepStart}Etapa 3%{stepEnd}. Adăugați-l în fișierul %{linkStart}gitlab-ci.yml al proiectului%{linkEnd}."
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr "Aveți acces la infrastructura care poate găzdui și implementa aplicațiile de revizuire."
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
-msgstr "%{stepStart}Etapa 4 (opțională)%{stepEnd}. Activați „Recenzii vizuale†urmând %{linkStart}instrucțiunile de configurare%{linkEnd}."
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr "Instalați și configurați un executor pentru a efectua implementarea."
-msgid "EnableReviewApp|Close"
-msgstr "Închideți"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr "Asigurați-vă că proiectul are un mediu configurat cu URL-ul țintă setat la URL-ul website-ului dvs. În caz contrar, creați unul nou înainte de a continua."
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr "Se execută numai pentru ramuri de caracteristici sau merge request-uri."
-msgid "EnableReviewApp|Copy snippet text"
-msgstr "Copiați textul fragmentului de cod"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr "Recomandat: Configurați un job care să oprească manual aplicațiile de revizuire."
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr "Aplicațiile de revizuire sunt medii dinamice pe care le puteți utiliza pentru a oferi o previzualizare în timp real a modificărilor efectuate într-o ramură de caracteristică."
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr "Pentru a configura o aplicație de revizuire dinamică, trebuie:"
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr "Folosește o variabilă CI/CD predefinită, cum ar fi %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} pentru a crea în mod dinamic mediile aplicațiilor de revizuire. De exemplu, pentru o configurație care utilizează pipeline-uri de merge request:"
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr "Utilizați un site static?"
+
+msgid "EnableReviewApp|View more example projects"
+msgstr "Vizualizați mai multe exemple de proiecte"
msgid "Enabled"
msgstr "Activat"
@@ -15271,6 +15490,9 @@ msgstr "Oprire automată %{autoStopAt}"
msgid "Environments|Commit"
msgstr "Commit"
+msgid "Environments|Copy live environment URL"
+msgstr "Copiați URL-ul mediului live"
+
msgid "Environments|Delete"
msgstr "Ștergeți"
@@ -15356,7 +15578,7 @@ msgid "Environments|Rollback environment %{name}?"
msgstr "Mediul de revenire %{name}?"
msgid "Environments|Search by environment name"
-msgstr "Căutați după numele mediului"
+msgstr "Căutare după numele mediului"
msgid "Environments|Show all"
msgstr "Afișați toate"
@@ -15425,7 +15647,7 @@ msgid "Epic events"
msgstr "Evenimente epice"
msgid "Epic not found for given params"
-msgstr "Epica nu a fost găsită pentru parametrii dați"
+msgstr "Epica nu a fost găsită pentru params dat"
msgid "Epics"
msgstr "Epice"
@@ -15451,12 +15673,12 @@ msgstr "Adăugați o nouă epică"
msgid "Epics|Add an existing epic"
msgstr "Adăugați o epică existentă"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgstr "Sunteți sigur că vreți să înlăturați %{bStart}%{targetEpicTitle}%{bEnd} din %{bStart}%{parentEpicTitle}%{bEnd}?"
+
msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr "Sunteți sigur că doriți să înlăturați %{bStart}%{targetIssueTitle}%{bEnd} din %{bStart}%{parentEpicTitle}%{bEnd}?"
-msgid "Epics|Assign Epic"
-msgstr "Atribuiți epica"
-
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr "Lăsați necomplet pentru a moșteni din datele obiectivului"
@@ -15469,18 +15691,9 @@ msgstr "Înlăturați epica"
msgid "Epics|Remove issue"
msgstr "Înlăturați problema"
-msgid "Epics|Search epics"
-msgstr "Căutați epice"
-
-msgid "Epics|Select epic"
-msgstr "Selectați epica"
-
msgid "Epics|Show more"
msgstr "Afișați mai multe"
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr "Ceva nu a mers bine la atribuirea problemei la epică."
-
msgid "Epics|Something went wrong while creating child epics."
msgstr "Ceva nu a mers bine în timpul creării epicelor copil."
@@ -15493,18 +15706,12 @@ msgstr "Ceva nu a mers bine în timpul preluării epicelor copil."
msgid "Epics|Something went wrong while fetching epics list."
msgstr "Ceva nu a mers bine în timpul preluării listei de epice."
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr "Ceva nu a mers bine în timpul preluării epicelor de grup."
-
msgid "Epics|Something went wrong while moving item."
msgstr "Ceva nu a mers bine în timpul mutării elementului."
msgid "Epics|Something went wrong while ordering item."
msgstr "Ceva nu a mers bine în timpul sortării elementului."
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr "Ceva nu a mers bine în timpul înlăturării problemei din epică."
-
msgid "Epics|Something went wrong while updating epics."
msgstr "Ceva nu a mers bine în timp ce se actualizau epicele."
@@ -15634,9 +15841,6 @@ msgstr "A apărut o eroare la salvarea responsabililor"
msgid "Error occurred when saving reviewers"
msgstr "A apărut o eroare la salvarea recenzenților"
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr "A apărut o eroare la actualizarea statusului %{issuableType}"
-
msgid "Error occurred while updating the issue status"
msgstr "A apărut o eroare la actualizarea stării problemei"
@@ -15700,9 +15904,6 @@ msgstr "Eroare la încărcarea fișierului"
msgid "Error uploading file. Please try again."
msgstr "Eroare la încărcarea fișierului. Vă rugăm să încercați din nou."
-msgid "Error uploading file: %{stripped}"
-msgstr "Eroare la încărcarea fișierului: %{stripped}"
-
msgid "Error while loading the merge request. Please try again."
msgstr "Eroare la încărcarea merge request-ului. Vă rugăm să încercați din nou."
@@ -15943,6 +16144,57 @@ msgstr "Evenimente"
msgid "Events API"
msgstr "API de evenimente"
+msgid "Event|accepted"
+msgstr "a acceptat"
+
+msgid "Event|added"
+msgstr " a adăugat"
+
+msgid "Event|approved"
+msgstr "a aprobat"
+
+msgid "Event|closed"
+msgstr "a închis"
+
+msgid "Event|commented on"
+msgstr "a comentat pe"
+
+msgid "Event|created"
+msgstr "a creat"
+
+msgid "Event|deleted"
+msgstr "a șters"
+
+msgid "Event|destroyed"
+msgstr "a distrus"
+
+msgid "Event|imported"
+msgstr "a importat"
+
+msgid "Event|joined"
+msgstr "s-a alăturat"
+
+msgid "Event|left"
+msgstr "a părăsit"
+
+msgid "Event|opened"
+msgstr "a deschis"
+
+msgid "Event|pushed new"
+msgstr "a împins un/o nou(ă)"
+
+msgid "Event|pushed to"
+msgstr "a împins la"
+
+msgid "Event|removed"
+msgstr "a înlăturat"
+
+msgid "Event|removed due to membership expiration from"
+msgstr "a fost înlăturat din cauza expirării calității de membru din"
+
+msgid "Event|updated"
+msgstr "a actualizat"
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr "Toate încercările de %{action} au eșuat: %{job_error_message}. Vă rugăm să încercați din nou."
@@ -16063,6 +16315,9 @@ msgstr "Se exclud commit-urile de îmbinare. Limitat la 6000 de commit-uri."
msgid "Execution time"
msgstr "Durata de execuție"
+msgid "Executive Dashboard"
+msgstr "Tablou de bord executiv"
+
msgid "Existing branch name, tag, or commit SHA"
msgstr "Numele ramurii, eticheta sau SHA de commit existente"
@@ -16120,9 +16375,15 @@ msgstr "Extindeți bara laterală"
msgid "Expected documents: %{expected_documents}"
msgstr "Documente așteptate: %{expected_documents}"
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr "Trebuie să aibă exact una dintre următoarele: Utilizator, Spațiu de nume sau Proiect."
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr "Expirare"
@@ -16348,6 +16609,9 @@ msgstr "Eșuat pe"
msgid "Failed to add a Zoom meeting"
msgstr "Nu s-a reușit adăugarea unei reuniuni Zoom"
+msgid "Failed to add a resource link"
+msgstr "Nu s-a putut adăuga un link de resurse"
+
msgid "Failed to apply commands."
msgstr "Nu s-a reușit aplicarea comenzilor."
@@ -16396,9 +16660,6 @@ msgstr "Nu s-a reușit crearea framework-ului"
msgid "Failed to create import label for jira import."
msgstr "Nu s-a reușit crearea etichetei de import pentru importul jira."
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr "Nu s-a reușit crearea unui nou token de acces: %{token_response_message}"
-
msgid "Failed to create repository"
msgstr "Nu s-a reușit crearea repozitoriului"
@@ -16594,9 +16855,6 @@ msgstr "Nu s-a reușit actualizarea stării problemei"
msgid "Failed to update the Canary Ingress."
msgstr "Nu s-a reușit actualizarea Canary Ingress."
-msgid "Failed to update."
-msgstr "Nu s-a reușit actualizarea."
-
msgid "Failed to upgrade."
msgstr "Nu s-a reușit upgrade-ul."
@@ -16855,6 +17113,9 @@ 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:"
@@ -16960,9 +17221,6 @@ msgstr "FiltraÈ›i după merge request-uri care sunt în prezent închise È™i neÃ
msgid "Filter by merge requests that are currently merged."
msgstr "Filtrează după merge request-urile care sunt în prezent îmbinate."
-msgid "Filter by milestone"
-msgstr "Filtrați în funcție de obiectiv"
-
msgid "Filter by milestone name"
msgstr "Filtrează după numele obiectivului"
@@ -17170,6 +17428,9 @@ msgstr "Pentru mai multe informații, accesați "
msgid "For more information, see the File Hooks documentation."
msgstr "Pentru mai multe informații, consultați documentația Hook-urilor de fișiere"
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr "Ați uitat parola?"
@@ -17276,7 +17537,7 @@ msgid "Framework successfully deleted"
msgstr "Framework-ul a fost eliminat cu succes"
msgid "Free"
-msgstr ""
+msgstr "Gratuit"
msgid "Free Trial of GitLab.com Ultimate"
msgstr "Versiune de încercare gratuită a GitLab.com Ultimate"
@@ -17582,7 +17843,7 @@ msgid "Geo|Errors:"
msgstr "Erori:"
msgid "Geo|External URL"
-msgstr ""
+msgstr "URL extern"
msgid "Geo|Failed"
msgstr "Eșuat"
@@ -17924,7 +18185,7 @@ msgid "Geo|There was an error updating the Geo Settings"
msgstr "A apărut o eroare la actualizarea setărilor Geo"
msgid "Geo|This GitLab instance is subscribed to the %{insufficient_license} tier. Geo is only available for users who have at least a Premium subscription."
-msgstr ""
+msgstr "Această instanță GitLab este abonată la nivelul %{insufficient_license}. Geo este disponibil numai utilizatorilor care au cel puțin un abonament Premium."
msgid "Geo|This will resync all %{replicableType}. It may take some time to complete. Are you sure you want to continue?"
msgstr "Aceasta va resincroniza toate %{replicableType}. S-ar putea să dureze ceva timp până la finalizare. Sunteți sigur că doriți să continuați?"
@@ -18007,9 +18268,6 @@ msgstr "secundar"
msgid "Get a free instance review"
msgstr "Obțineți o revizuire gratuită a instanței"
-msgid "Get a free trial"
-msgstr "Obțineți o încercare gratuită"
-
msgid "Get a support subscription"
msgstr "Obțineți un abonament de asistență"
@@ -18136,6 +18394,12 @@ msgstr "Solicitare de cont GitLab"
msgid "GitLab Billing Team."
msgstr "Echipa de facturare GitLab."
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr "Urmărirea erorilor GitLab"
@@ -18187,6 +18451,9 @@ 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}"
@@ -18235,9 +18502,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.com"
-msgstr "GitLab.com"
-
msgid "GitLab.com (SaaS)"
msgstr "GitLab.com (SaaS)"
@@ -18793,9 +19057,6 @@ msgstr "Afișați dependențele"
msgid "GraphViewType|Stage"
msgstr "Etapa"
-msgid "Graphs"
-msgstr "Grafice"
-
msgid "Gravatar"
msgstr "Gravatar"
@@ -18805,6 +19066,9 @@ msgstr "Gravatar activat"
msgid "Group"
msgstr "Grup"
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr "Grupul %{group_name} și echipa sa Mattermost au fost create cu succes."
+
msgid "Group %{group_name} couldn't be exported."
msgstr "Grupul %{group_name} nu a putut fi exportat."
@@ -19271,7 +19535,7 @@ msgid "GroupSettings|Compliance frameworks"
msgstr "Framework-uri de conformitate"
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
-msgstr ""
+msgstr "Configurați framework-urile de conformitate pentru a le pune la dispoziția proiectelor din acest grup. %{linkStart}Ce sunt framework-urile de conformitate?%{linkEnd}"
msgid "GroupSettings|Configure limits on the number of repositories users can download in a given time."
msgstr "Configurați limitele numărului de repozitorii care pot fi descărcate de utilizatori într-un anumit interval de timp."
@@ -19567,17 +19831,11 @@ msgstr "Părăsirea grupului"
msgid "GroupsTree|Loading groups"
msgstr "Se încarcă grupurile"
-msgid "GroupsTree|No groups matched your search"
-msgstr "Niciun grup nu corespunde căutării d-voastră"
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr "Niciun grup sau proiect nu corespunde căutării d-voastră"
-
msgid "GroupsTree|Options"
msgstr "Opțiuni"
msgid "GroupsTree|Search by name"
-msgstr "Căutați după nume"
+msgstr "Căutare după nume"
msgid "Groups|Avatar will be removed. Are you sure?"
msgstr "Avatarul va fi eliminat. Sunteți sigur?"
@@ -19642,6 +19900,9 @@ msgstr "Slug-ul subgrupului"
msgid "Groups|You're creating a new top-level group"
msgstr "Creați un nou grup de nivel superior"
+msgid "Guest"
+msgstr "Invitat"
+
msgid "Guideline"
msgstr "Ghid"
@@ -19664,7 +19925,7 @@ msgid "Harbor Registry"
msgstr "Registrul Harbor"
msgid "HarborIntegration|After the Harbor integration is activated, global variables `$HARBOR_USERNAME`, `$HARBOR_HOST`, `$HARBOR_OCI`, `$HARBOR_PASSWORD`, `$HARBOR_URL` and `$HARBOR_PROJECT` will be created for CI/CD use."
-msgstr ""
+msgstr "După ce integrarea Harbor este activată, variabilele globale `$HARBOR_USERNAME`, `$HARBOR_HOST`, `$HARBOR_OCI`, `$HARBOR_PASSWORD`, `$HARBOR_URL` și `$HARBOR_PROJECT` vor fi create pentru utilizarea CI/CD."
msgid "HarborIntegration|Base URL of the Harbor instance."
msgstr "URL-ul de bază al instanței Harbor."
@@ -19822,9 +20083,6 @@ msgstr "Informațiile despre sănătate pot fi preluate din următoarele puncte
msgid "Health status"
msgstr "Stare de sănătate"
-msgid "Health status cannot be edited because this issue is closed"
-msgstr "Starea de sănătate nu poate fi editată deoarece această problemă este închisă"
-
msgid "HealthCheck|Access token is"
msgstr "Tokenul de acces este"
@@ -20281,8 +20539,14 @@ msgstr "Trimiteți codul"
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr "Ceva nu a mers bine. Vă rugăm să încercați din nou."
-msgid "IdentityVerification|Step 1: Verify phone number"
-msgstr "Etapa 1: Verificarea numărului de telefon"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr "Etapa %{stepNumber}: Verificarea unei metode de plată"
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr "Etapa %{stepNumber}: Verificarea adresei de e-mail"
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
+msgstr "Etapa %{stepNumber}: Verificarea numărului de telefon"
msgid "IdentityVerification|The code has expired. Send a new code and try again."
msgstr "Codul a expirat. Trimiteți-mi un nou cod și încercați din nou."
@@ -20368,12 +20632,6 @@ msgstr "Dacă acest e-mail a fost adăugat din greșeală, îl puteți elimina a
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr "Dacă acest e-mail a fost adăugat din greșeală, îl puteți înlătura aici: %{profile_emails_url}"
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr "Dacă este vorba de o greșeală, puteți să %{link_start}îi deblocați%{link_end}."
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr "Dacă aceasta este o greșeală, îi puteți debloca: %{url}."
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr "Dacă aceasta a fost o greșeală, puteți %{leave_link_start} părăsi %{source_type} %{link_end}."
@@ -20603,7 +20861,7 @@ msgid "ImportProjects|%{provider} rate limit exceeded. Try again later"
msgstr "Limita de rată %{provider} a fost depășită. Încercați din nou mai târziu"
msgid "ImportProjects|Advanced import settings"
-msgstr ""
+msgstr "Setări avansate de import"
msgid "ImportProjects|Blocked import URL: %{message}"
msgstr "URL de import blocat: %{message}"
@@ -20630,7 +20888,7 @@ msgid "ImportProjects|Select the repositories you want to import"
msgstr "Selectați repozitoriile pe care doriți să le importați"
msgid "ImportProjects|The more information you select, the longer it will take to import"
-msgstr ""
+msgstr "Cu cât selectați mai multe informații, cu atât va dura mai mult să importați"
msgid "ImportProjects|The remote data could not be imported."
msgstr "Datele remote nu au putut fi importate."
@@ -22091,7 +22349,7 @@ msgid "Invalid hash"
msgstr "Hash nevalid"
msgid "Invalid import params"
-msgstr "Parametri de import nevalizi"
+msgstr "Invalid params de import"
msgid "Invalid input, please avoid emojis"
msgstr "Intrare invalidă, vă rugăm să evitați emojiurile"
@@ -22129,6 +22387,9 @@ msgstr "Cod cu doi factori invalid."
msgid "Invalid yaml"
msgstr "Yaml nevalid"
+msgid "Invalidated"
+msgstr "Invalidat"
+
msgid "Investigate vulnerability: %{title}"
msgstr "Investigați vulnerabilitatea: %{title}"
@@ -22147,9 +22408,6 @@ msgstr "Invitația a fost refuzată"
msgid "Invite \"%{email}\" by email"
msgstr "Invitați „%{email}†prin e-mail"
-msgid "Invite \"%{trimmed}\" by email"
-msgstr "Invitați \"%{trimmed}\" prin e-mail"
-
msgid "Invite Members"
msgstr "Invitați membri"
@@ -22207,8 +22465,8 @@ msgstr "Invitați-vă colegii"
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr "Am observat că nu ați invitat pe nimeni în acest grup. Invitați-vă colegii pentru a putea discuta probleme, colabora la merge request-uri și pentru a vă împărtăși cunoștințele."
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
-msgstr " Se pot obține mai mulți membri și acces la funcții suplimentare plătite dacă proprietarul grupului începe o perioadă de probă sau trece la un nivel plătit."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
+msgstr "Pentru a avea mai mulți membri, proprietarul acestui spațiu de nume poate %{trialLinkStart}începe o perioadă de probă%{trialLinkEnd} sau poate %{upgradeLinkStart}face upgrade%{upgradeLinkEnd} la un nivel plătit."
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
msgstr "%{linkStart}Citiți mai multe%{linkEnd} despre permisiunile rolurilor"
@@ -22288,21 +22546,18 @@ msgstr[0] "Următorul membru nu a putut fi invitat"
msgstr[1] "Următorii %d membri nu au putut fi invitați"
msgstr[2] "Următorii %d de membri nu au putut fi invitați"
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr "Această caracteristică este dezactivată până când acest grup are loc pentru mai mulți membri."
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr "Pentru a atribui probleme unui nou membru al echipei, aveți nevoie de un proiect pentru problemele respective. %{linkStart}Creați un proiect pentru a începe.%{linkEnd}"
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr "Se pot obține mai mulți membri dacă un proprietar al grupului %{trialLinkStart}începe o perioadă de probă%{trialLinkEnd} sau %{upgradeLinkStart}actualizează%{upgradeLinkEnd} la un nivel plătit."
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
+msgstr "Pentru a invita noi utilizatori în acest spațiu de nume, trebuie să înlăturați utilizatorii existenți. Puteți adăuga în continuare utilizatori existenți ai spațiului de nume."
+
msgid "InviteMembersModal|Username or email address"
msgstr "Nume de utilizator sau adresă de e-mail"
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
-msgstr "Nu puteți adăuga alți membri, dar puteți înlătura membrii care nu mai au nevoie de acces."
-
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
msgstr "Mai aveți loc doar pentru încă %{count} %{members} în %{name}"
@@ -22438,12 +22693,18 @@ msgstr "Folosește seat de licență:"
msgid "Is using seat"
msgstr "Folosește seat"
+msgid "IssuableEvents|assigned to"
+msgstr "atribuit la"
+
msgid "IssuableEvents|removed review request for"
msgstr "a înlăturat solicitarea de revizuire pentru"
msgid "IssuableEvents|requested review from"
msgstr "a solicitat revizuirea de la"
+msgid "IssuableEvents|unassigned"
+msgstr "neatribuit"
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr "%{wi_type} creat(ă) la %{created_at} de "
@@ -22465,6 +22726,18 @@ msgstr "mutat(ă)"
msgid "IssuableStatus|promoted"
msgstr "promovat(ă)"
+msgid "Issuable|epic"
+msgstr "epică"
+
+msgid "Issuable|escalation policy"
+msgstr "politica de escaladare"
+
+msgid "Issuable|iteration"
+msgstr "Iterație"
+
+msgid "Issuable|milestone"
+msgstr "obiectiv"
+
msgid "Issue"
msgstr "Problema"
@@ -22690,6 +22963,21 @@ msgstr "Pentru a vă lărgi căutarea, modificați sau înlăturați filtrele di
msgid "IssuesAnalytics|Total:"
msgstr "Total:"
+msgid "Issues|Move selected"
+msgstr "Mutați cele selectate"
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr "Sarcinile și cazurile de testare nu pot fi mutate."
+
+msgid "Issues|Tasks can not be moved."
+msgstr "Sarcinile nu pot fi mutate."
+
+msgid "Issues|Test cases can not be moved."
+msgstr "Cazurile de testare nu pot fi mutate."
+
+msgid "Issues|There was an error while moving the issues."
+msgstr "S-a produs o eroare în timpul mutării problemelor."
+
msgid "Issue|Title"
msgstr "Titlu"
@@ -22984,6 +23272,9 @@ msgstr "Aplicația GitLab pentru Jira"
msgid "JiraConnect|Jira Connect Application ID"
msgstr "ID-ul aplicației Jira Connect"
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr "URL-ul Proxy Jira Connect"
+
msgid "JiraConnect|New branch was successfully created."
msgstr "Noua ramură a fost creată cu succes."
@@ -23314,6 +23605,9 @@ msgstr "Creat"
msgid "Job|Download"
msgstr "Descărcare"
+msgid "Job|Duration"
+msgstr "Durata"
+
msgid "Job|Erase job log and artifacts"
msgstr "Ștergeți jurnalul jobului și artefactele"
@@ -23353,9 +23647,15 @@ msgstr "În așteptare"
msgid "Job|Preparing"
msgstr "În pregătire"
+msgid "Job|Queued"
+msgstr "În coadă"
+
msgid "Job|Retry"
msgstr "Reîncercați"
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr "Rulează"
@@ -23734,9 +24034,6 @@ msgstr "Ultima editare de %{link_start}%{avatar} %{name}%{link_end}"
msgid "Last event"
msgstr "Ultimul eveniment"
-msgid "Last item before this page loaded in your browser:"
-msgstr "Ultimul element înainte ca această pagină să fie încărcată în browser:"
-
msgid "Last modified"
msgstr "Ultima modificare"
@@ -23890,6 +24187,15 @@ msgstr "Aflați mai multe despre grupuri."
msgid "Learn more about issues."
msgstr "Aflați mai multe despre probleme."
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr "Aflați mai multe despre numărul maxim de seat-uri utilizate"
@@ -24040,9 +24346,6 @@ msgstr "Părăsiți proiectul"
msgid "Leave zen mode"
msgstr "Părăsiți modul zen"
-msgid "Leaving this setting enabled is recommended."
-msgstr "Se recomandă să lăsați această setare activată."
-
msgid "Legacy burndown chart"
msgstr "Graficul burndown legacy"
@@ -24295,6 +24598,12 @@ msgstr "Modificări de linie"
msgid "Link"
msgstr "Linkul"
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr "Linkul (opțional)"
@@ -24565,9 +24874,6 @@ msgstr "Logoul va fi înlăturat. Sunteți sigur?"
msgid "Logs"
msgstr "Jurnale"
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr "Se pare că ați atins limita de %{free_limit} (de) membri pentru %{strong_start}%{namespace_name}%{strong_end}"
-
msgid "Low vulnerabilities present"
msgstr "Prezintă vulnerabilități scăzute"
@@ -24580,6 +24886,9 @@ msgstr "MD5"
msgid "MERGED"
msgstr "ÃŽMBINAT"
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr "ÃŽnapoi la merge request"
@@ -24616,8 +24925,14 @@ msgstr "Afișați numai modificările"
msgid "MRDiff|Show full file"
msgstr "Afișați întregul fișier"
-msgid "Made this issue confidential."
-msgstr "Această problemă a devenit confidențială."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
+msgstr "A făcut acest %{type} confidențial."
msgid "Mailgun"
msgstr "Mailgun"
@@ -24631,9 +24946,15 @@ msgstr "Evenimente Mailgun"
msgid "Main menu"
msgstr "Meniul principal"
+msgid "Maintainer"
+msgstr "Întreținător"
+
msgid "Maintenance mode"
msgstr "Modul de întreținere"
+msgid "Make %{type} confidential"
+msgstr "Faceți %{type} confidențial"
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr "Efectuați modificări la modul în care este configurată instanța dvs. GitLab."
@@ -24643,9 +24964,6 @@ msgstr "Efectuați și revizuiți modificările în browser cu ajutorul IDE Web"
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr "Faceți ca toți membrii echipei dvs. să fie mai productivi, indiferent de locația lor. GitLab Geo creează replici doar în citire ale instanței dvs. GitLab, astfel încât să puteți reduce timpul necesar pentru a clona și a prelua repozitoriile mari."
-msgid "Make issue confidential"
-msgstr "Faceți problema confidențială"
-
msgid "Make sure you choose a strong, unique password."
msgstr "Asigurați-vă că alegeți o parolă puternică și unică."
@@ -24655,8 +24973,8 @@ msgstr "Asigurați-vă că aveți permisiunile adecvate pentru a vă conecta pro
msgid "Make sure you save it - you won't be able to access it again."
msgstr "Asigurați-vă că îl salvați - nu îl veți mai putea accesa din nou."
-msgid "Makes this issue confidential."
-msgstr "Face această problemă confidențială."
+msgid "Makes this %{type} confidential."
+msgstr "Face ca acest/această %{type} să fie confidențial(ă)."
msgid "Manage %{workspace} labels"
msgstr "Gestionați etichetele pentru %{workspace}"
@@ -24704,7 +25022,7 @@ msgid "Manage your project's triggers"
msgstr "Gestionați declanșatoarele proiectului dumneavoastră"
msgid "Manage your subscription"
-msgstr ""
+msgstr "Gestionați-vă abonamentul"
msgid "Managed Account"
msgstr "Cont gestionat"
@@ -24712,6 +25030,9 @@ msgstr "Cont gestionat"
msgid "Manifest"
msgstr "Manifest"
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr "Importul cu un fișier manifest"
@@ -24736,6 +25057,9 @@ msgstr "Mar"
msgid "March"
msgstr "Martie"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr "Marcați ca terminat"
@@ -24787,6 +25111,9 @@ msgstr "Adăugați text tăiat cu o linie (%{modifierKey}⇧X)"
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr "Adăugați text tăiat cu o linie (%{modifier_key}⇧X)"
+msgid "MarkdownEditor|Click to expand"
+msgstr "Faceți clic pentru a extinde"
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr "Linie de indentare (%{modifierKey}])"
@@ -24799,6 +25126,9 @@ msgstr "Linie de indentare negativă (%{modifierKey}[)"
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr "Linie de indentare negativă (%{modifier_key}[)"
+msgid "MarkdownEditor|header"
+msgstr "antet"
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr "Acceptă %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
@@ -25429,6 +25759,9 @@ msgstr "Setările merge request-urilor și aprobărilor au fost mutate."
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr "Merge request-urile sunt un loc în care puteți propune modificările pe care le-ați făcut la un proiect și să discutați aceste modificări cu alții."
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr "Îmbinați ramura de caracteristică în ramura țintă și rezolvați orice conflict. %{linkStart}Cum pot să le rezolv?%{linkEnd}"
@@ -25654,6 +25987,9 @@ msgstr "Metodă"
msgid "Method call threshold (ms)"
msgstr "Pragul metodei de apel (ms)"
+msgid "Metric"
+msgstr "Metrică"
+
msgid "Metric was successfully added."
msgstr "Metrica a fost adăugată cu succes."
@@ -26047,6 +26383,9 @@ msgstr "Data scadentă a obiectivului"
msgid "Milestone lists not available with your current license"
msgstr "Listele de obiective nu sunt disponibile cu licența dvs. actuală"
+msgid "Milestone(s) not found: %{milestones}"
+msgstr "Obiectivul (obiectivele) nu a(u) fost găsit(e): %{milestones}"
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr "S-a produs o eroare în timpul căutării pentru obiective"
@@ -26206,6 +26545,9 @@ msgstr "%{percentage}%{percent} finalizat"
msgid "Min Value"
msgstr "Valoare minimă"
+msgid "Minimal Access"
+msgstr "Acces minim"
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr "Capacitatea minimă care trebuie să fie disponibilă înainte de a programa mai multe replici în mod preventiv."
@@ -26278,6 +26620,9 @@ msgstr "Nu puteți să faceți push sau pull de repozitorii folosind SSH până
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr "Nu veți putea face pull sau push de repozitorii prin SSH până când nu adăugați o cheie SSH la profilul dvs."
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr "Adăugare proiecte"
@@ -26464,6 +26809,9 @@ msgstr "Integrările multiple Prometheus nu sunt acceptate"
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr "Multiplicator aplicabil intervalelor de sondare. Sunt acceptate valorile zecimale. Valoarea implicită este 1."
+msgid "Must be 90 days or more."
+msgstr "Trebuie să fie de 90 de zile sau mai mult."
+
msgid "My awesome group"
msgstr "Grupul meu formidabil"
@@ -26926,6 +27274,9 @@ msgstr "Fără domenii"
msgid "No Work Item Link found"
msgstr "Nu s-a găsit niciun link cu elementul de lucru"
+msgid "No access"
+msgstr "Fără acces"
+
msgid "No active admin user found"
msgstr "Nu s-a găsit niciun utilizator administrator activ"
@@ -27055,9 +27406,6 @@ msgstr "Nicio iterație de afișat"
msgid "No job log"
msgstr "Niciun jurnal de job"
-msgid "No jobs to show"
-msgstr "Niciun job de afișat"
-
msgid "No label"
msgstr "Nicio etichetă"
@@ -27085,9 +27433,6 @@ msgstr "Nicio potrivire de rezultate"
msgid "No matching results for \"%{query}\""
msgstr "Nicio potrivire de rezultate pentru „%{query}â€"
-msgid "No matching results..."
-msgstr "Nicio potrivire de rezultate..."
-
msgid "No members found"
msgstr "Nu s-au găsit membri"
@@ -27103,9 +27448,6 @@ msgstr "Nu s-au înregistrat mesaje"
msgid "No milestone"
msgstr "Niciun obiectiv"
-msgid "No namespace"
-msgstr "Niciun spațiu de nume"
-
msgid "No other labels with such name or description"
msgstr "Nicio altă etichetă cu un astfel de nume sau descriere"
@@ -27218,7 +27560,7 @@ msgstr[1] "Nu vă faceți griji, puteți utiliza în continuare toate caracteris
msgstr[2] "Nu vă faceți griji, puteți utiliza în continuare toate caracteristicile %{strong}%{plan_name}%{strong_close} pentru acum. Aveți la dispoziție %{remaining_days} de zile pentru a vă reînnoi abonamentul."
msgid "No wrap"
-msgstr ""
+msgstr "Fără încadrare"
msgid "No. of commits"
msgstr "Nr. de commit-uri"
@@ -27340,8 +27682,8 @@ msgstr "Restrângeți răspunsurile"
msgid "Notes|Expand replies"
msgstr "Extindeți răspunsurile"
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
-msgstr "Notele interne sunt vizibile doar pentru autor, responsabili și membrii cu rol de Reporter sau mai mare"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
+msgstr "Notele interne sunt vizibile numai membrilor cu rol de Reporter sau mai mare."
msgid "Notes|Last reply by %{name}"
msgstr "Ultimul răspuns de %{name}"
@@ -27679,6 +28021,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|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr "Pipeline-ul %{pipeline_link} declanșat de"
@@ -27688,6 +28033,9 @@ msgstr "Pipeline-ul a fost reparat și #%{pipeline_id} a trecut!"
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."
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr "Proiectul %{project_name} nu a putut fi exportat."
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr "Exportul proiectului %{project_name} s-a finalizat."
@@ -27709,6 +28057,9 @@ msgstr "Diff-ul nu a fost inclus pentru că este prea mare."
msgid "Notify|The download link will expire in 24 hours."
msgstr "Linkul de descărcare va expira în 24 de ore."
+msgid "Notify|The errors we encountered were:"
+msgstr "Erorile întâlnite au fost:"
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr "Proiectul este acum localizat sub %{project_full_name_link_start}%{project_full_name}%{link_end}."
@@ -27802,9 +28153,6 @@ msgstr "Numărul de angajați"
msgid "Number of events"
msgstr "Numărul de evenimente"
-msgid "Number of events for this project: %{total_count}."
-msgstr "Numărul de evenimente pentru acest proiect: %{total_count}."
-
msgid "Number of files touched"
msgstr "Numărul de fișiere atinse"
@@ -27829,9 +28177,6 @@ msgstr "Oct"
msgid "October"
msgstr "Octombrie"
-msgid "OfSearchInADropdown|Filter"
-msgstr "Filtru"
-
msgid "Off"
msgstr "Oprit"
@@ -28066,12 +28411,6 @@ msgstr "Nu se pot prelua profilurile site-ului. Vă rugăm să reîmprospătați
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr "Nu s-a putut rula scanarea. Vă rugăm să încercați din nou."
-msgid "OnDemandScans|Create new scanner profile"
-msgstr "Creați un nou profil de scaner"
-
-msgid "OnDemandScans|Create new site profile"
-msgstr "Creați un nou profil de site"
-
msgid "OnDemandScans|DAST configuration"
msgstr "Configurația DAST"
@@ -28117,12 +28456,6 @@ msgstr "De exemplu: Testarea unei pagini de autentificare pentru injecții SQL"
msgid "OnDemandScans|Keep editing"
msgstr "Continuați să editați"
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr "Gestionați profilurile de scanare"
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr "Gestionați profilurile site-ului"
-
msgid "OnDemandScans|My daily scan"
msgstr "Scanarea mea zilnică"
@@ -28144,12 +28477,6 @@ msgstr "Scanare nouă"
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr "Nu s-au găsit profiluri %{profileType} pentru DAST"
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr "Nu aveți niciun profil configurat. Pentru a crea o nouă scanare, trebuie să aveți cel puțin un profil de scanare finalizat."
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr "Nu aveți niciun profil configurat. Pentru a crea o nouă scanare, trebuie să aveți cel puțin un profil de site completat."
-
msgid "OnDemandScans|On-demand Scans"
msgstr "Scanări la cerere"
@@ -28192,15 +28519,6 @@ msgstr "Program de scanare"
msgid "OnDemandScans|Scan type"
msgstr "Tipul de scanare"
-msgid "OnDemandScans|Scanner profile"
-msgstr "Profilul scanerului"
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr "Selectați unul dintre profilurile existente"
-
-msgid "OnDemandScans|Site profile"
-msgstr "Profilul site-ului"
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr "Începeți prin crearea unui profil nou. Profilurile facilitează salvarea și reutilizarea detaliilor de configurare pentru instrumentele de securitate GitLab."
@@ -28231,12 +28549,6 @@ msgstr "Nu există scanări programate."
msgid "OnDemandScans|Timezone"
msgstr "Fusul orar"
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr "Utilizați profilul scanerului existent"
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr "Utilizați profilul site-ului existent"
-
msgid "OnDemandScans|View results"
msgstr "Vizualizați rezultatul"
@@ -28255,9 +28567,6 @@ msgstr "Odată importate, repozitoriile pot fi replicate prin SSH. Aflați mai m
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr "Odată eliminată, relația de fork nu mai poate fi restabilită. Acest proiect nu va mai putea să primească sau să trimită merge request-uri către proiectul sursă sau către alte forkuri."
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr "După ce confirmaÈ›i È™i apăsaÈ›i „ReduceÈ›i vizibilitatea proiectuluiâ€:"
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] "Un element mai mult"
@@ -28432,9 +28741,6 @@ msgstr "Operația a eșuat. Verificați jurnalele pod pentru %{pod_name} pentru
msgid "Operation not allowed"
msgstr "Operațiunea nu este permisă"
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr "Operația a expirat. Verificați jurnalele pod pentru %{pod_name} pentru mai multe detalii."
-
msgid "Operations"
msgstr "Operațiuni"
@@ -28804,12 +29110,21 @@ msgstr "Ștergeți pachetul"
msgid "PackageRegistry|Delete package asset"
msgstr "Ștergeți activul pachetului"
+msgid "PackageRegistry|Delete package version"
+msgstr "Ștergeți versiunea pachetului"
+
msgid "PackageRegistry|Delete selected"
msgstr "Ștergeți selectat"
msgid "PackageRegistry|Delete this package"
msgstr "Ștergeți acest pachet"
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr "Ștergerea tuturor activelor pachetului va înlătura versiunea %{version} a %{name}. Sunteți sigur?"
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr "Ștergerea ultimului activ al pachetului va înlătura versiunea %{version} a %{name}. Sunteți sigur?"
+
msgid "PackageRegistry|Duplicate packages"
msgstr "Pachete duplicate"
@@ -28855,6 +29170,12 @@ msgstr "Comanda de instalare Gradle Kotlin DSL"
msgid "PackageRegistry|Helm"
msgstr "Helm"
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr "Ajutați-ne să aflăm despre nevoile dvs. de migrare a registrului"
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr "Dacă sunteți interesat în migrarea pachetelor din registrul privat în registrul de pachete GitLab, răspundeți la sondajul nostru și spuneți-ne mai multe despre nevoile dvs."
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr "Dacă nu ați făcut-o deja, va trebui să adăugați următoarele la fișierul d-voastră %{codeStart}.pypirc%{codeEnd}."
@@ -28928,7 +29249,7 @@ msgid "PackageRegistry|Package updated by commit %{link} on branch %{branch}, bu
msgstr "Pachet actualizat de commit-ul %{link} pe ramura %{branch}, construit de pipeline-ul %{pipeline} și publicat în registru la %{datetime}"
msgid "PackageRegistry|Permanently delete"
-msgstr ""
+msgstr "Ștergeți permanent"
msgid "PackageRegistry|Permanently delete assets"
msgstr "Ștergeți permanent activele"
@@ -29002,6 +29323,9 @@ msgstr "Ne pare rău, filtrul dvs. nu a produs rezultate"
msgid "PackageRegistry|Source project located at %{link}"
msgstr "Proiectul sursă se află la %{link}"
+msgid "PackageRegistry|Take survey"
+msgstr "Răspundeți la sondaj"
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr "SHA țintă: %{sha}"
@@ -29042,7 +29366,7 @@ msgid "PackageRegistry|You are about to delete %{filename}. This is a destructiv
msgstr "Sunteți pe cale să ștergeți %{filename}. Aceasta este o acțiune distructivă care poate face pachetul dvs. inutilizabil. Sunteți sigur?"
msgid "PackageRegistry|You are about to delete %{name}, are you sure?"
-msgstr ""
+msgstr "Sunteți pe cale să ștergeți %{name}, sunteți sigur?"
msgid "PackageRegistry|You are about to delete 1 asset. This operation is irreversible."
msgid_plural "PackageRegistry|You are about to delete %d assets. This operation is irreversible."
@@ -29386,12 +29710,6 @@ msgstr "perete"
msgid "Period in seconds"
msgstr "Perioada în secunde"
-msgid "Period of inactivity (days)"
-msgstr "Perioada de inactivitate (zile)"
-
-msgid "Period of inactivity before deactivation."
-msgstr "Perioada de inactivitate înainte de dezactivare."
-
msgid "Permalink"
msgstr "Permalink"
@@ -29440,8 +29758,8 @@ msgstr "Import de pe serverul Phabricator"
msgid "Phabricator Server URL"
msgstr "URL-ul serverului Phabricator"
-msgid "Phabricator Tasks"
-msgstr "Sarcini Phabricator"
+msgid "Phabricator tasks"
+msgstr ""
msgid "Phone"
msgstr "Telefon"
@@ -29659,20 +29977,26 @@ msgstr "Activ"
msgid "PipelineSchedules|All"
msgstr "Toate"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr "Sigur doriți să ștergeți acest program de pipeline?"
+
msgid "PipelineSchedules|Delete pipeline schedule"
-msgstr ""
+msgstr "Ștergeți programul de pipeline"
msgid "PipelineSchedules|Description"
-msgstr ""
+msgstr "Descriere"
msgid "PipelineSchedules|Edit pipeline schedule"
-msgstr ""
+msgstr "Editați programul de pipeline"
msgid "PipelineSchedules|Inactive"
msgstr "Inactiv"
msgid "PipelineSchedules|Last Pipeline"
-msgstr ""
+msgstr "Ultimul pipeline"
+
+msgid "PipelineSchedules|New schedule"
+msgstr "Program nou"
msgid "PipelineSchedules|Next Run"
msgstr "Următoarea execuție"
@@ -29684,24 +30008,36 @@ msgid "PipelineSchedules|Only the owner of a pipeline schedule can make changes
msgstr "Proprietarul unui program de pipeline este singurul care poate să-l modifice. Doriți să vă asumați proprietatea asupra acestui program?"
msgid "PipelineSchedules|Owner"
+msgstr "Proprietar"
+
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
msgstr ""
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "Furnizați o scurtă descriere pentru acest pipeline"
msgid "PipelineSchedules|Run pipeline schedule"
+msgstr "Executați programul de pipeline"
+
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
msgstr ""
msgid "PipelineSchedules|Take ownership"
msgstr "Asumați-vă proprietatea"
msgid "PipelineSchedules|Take ownership of pipeline schedule"
-msgstr ""
+msgstr "Asumați-vă proprietatea asupra programului de pipeline"
msgid "PipelineSchedules|Target"
msgstr "Țintă"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr "A apărut o problemă la ștergerea programului de pipeline."
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
+msgstr "A apărut o problemă la preluarea programelor de pipeline."
+
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
msgid "PipelineSchedules|Variables"
@@ -30463,9 +30799,6 @@ 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 file"
-msgstr "Vă rugăm să selectați un fișier"
-
msgid "Please select a group"
msgstr "Vă rugăm să selectați un grup"
@@ -30574,6 +30907,69 @@ msgstr "Caracter potențial nedorit detectat: Control Unicode pentru text BiDi"
msgid "Pre-defined push rules"
msgstr "Reguli push predefinite"
+msgid "PreScanVerification|(optional)"
+msgstr "(opțional)"
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr "Ultima execuție %{timeAgo} în pipeline"
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr "Verificare pre-scanare"
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr "A început %{timeAgo} în pipeline"
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr "Testați-vă configurația și identificați erori potențiale înainte de a rula o scanare completă."
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr "Verificați configurația"
+
+msgid "PreScanVerification|View results"
+msgstr "Vizualizați rezultatele"
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr "Preferințe"
@@ -30581,7 +30977,7 @@ msgid "Preferences saved."
msgstr "Preferințe salvate."
msgid "Preferences|Automatically add new list items"
-msgstr ""
+msgstr "Adăugați automat elemente noi din listă"
msgid "Preferences|Behavior"
msgstr "Comportament"
@@ -30695,7 +31091,7 @@ msgid "Preferences|Use relative times"
msgstr "Utilizați timpi relativi"
msgid "Preferences|When you type in a description or comment box, pressing %{kbdOpen}Enter%{kbdClose} in a list adds a new item below."
-msgstr ""
+msgstr "Când introduceți o descriere sau un comentariu într-o casetă, apăsarea tastei %{kbdOpen}Enter%{kbdClose} într-o listă adaugă un nou element mai jos."
msgid "Preferences|When you type in a description or comment box, selected text is surrounded by the corresponding character after typing one of the following characters: %{supported_characters}."
msgstr "Atunci când introduceți text într-o casetă de descriere sau de comentariu, textul selectat este înconjurat de caracterul corespunzător după ce ați introdus unul dintre caracterele următoare: %{supported_characters}."
@@ -30715,6 +31111,9 @@ msgstr "Preveniți modificarea regulilor de aprobare în proiecte și merge requ
msgid "Prevent environment from auto-stopping"
msgstr "Împiedicați oprirea automată a mediului"
+msgid "Prevent outdated deployment jobs"
+msgstr "Împiedicați joburile de implementare învechite"
+
msgid "Prevent project forking outside current group"
msgstr "Împiedicați forkingul proiectului în afara grupului curent"
@@ -30808,12 +31207,18 @@ msgstr "Problemă cu comanda %{name}: %{message}."
msgid "Proceed"
msgstr "Continuați"
-msgid "Product Analytics"
-msgstr "Analize de produs"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
+msgstr "Audiență"
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|Widgets content"
+msgstr "Conținut widget-uri"
+
msgid "Productivity"
msgstr "Productivitate"
@@ -31390,6 +31795,9 @@ msgstr "Numele proiectului"
msgid "Project navigation"
msgstr "Navigarea în proiect"
+msgid "Project or Group"
+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ă."
@@ -31402,6 +31810,9 @@ msgstr "Starea securității proiectului"
msgid "Project security status help page"
msgstr "Pagina de ajutor privind starea de securitate a proiectului"
+msgid "Project settings were successfully updated."
+msgstr "Setările proiectului au fost actualizate cu succes."
+
msgid "Project slug"
msgstr "Slug de proiect"
@@ -31684,12 +32095,18 @@ msgstr "%{link_start}Ce sunt șabloanele de descriere?%{link_end}"
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr "%{link_start}Ce variabile pot folosi?%{link_end}"
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr "Nu se poate alege o ramură implicită pentru un proiect gol."
+
msgid "ProjectSettings|Additional options"
msgstr "Opțiuni suplimentare"
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr "Setări suplimentare care influențează modul și momentul în care se realizează îmbinările."
+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"
@@ -31702,12 +32119,18 @@ msgstr "Afișați întotdeauna butoanele emoji de recompensă cu degetul mare î
msgid "ProjectSettings|Analytics"
msgstr "Analize"
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr "Închiderea automată a problemelor referite pe ramura implicită"
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr "Rezolvați automat subiectele legate de diff-uri de merge request atunci când acestea devin depășite"
msgid "ProjectSettings|Badges"
msgstr "Insigne"
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr "Ramurile create din probleme urmează acest model."
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr "Creați, testați și implementați modificările."
@@ -31729,6 +32152,9 @@ msgstr "Alegeți metoda de îmbinare, opțiunile, verificările și opțiunile d
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr "Combinați etichetele git cu notele de lansare, dovezile de lansare și activele pentru a crea o versiune."
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr "Configurați resursele proiectului și monitorizați starea lor de sănătate."
@@ -31828,6 +32254,9 @@ msgstr "Care sunt diferențele dintre ele?"
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr "În cazul în care merge train-urile sunt activate, îmbinarea este posibilă numai dacă un rebase al ramurii poate fi făcut fără conflicte."
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr "Intern"
@@ -31895,7 +32324,7 @@ msgid "ProjectSettings|Note: The container registry is always visible when a pro
msgstr "Notă: Registrul containerului este întotdeauna vizibil când un proiect este public È™i registrul containerului este setat la „%{access_level_description}â€"
msgid "ProjectSettings|Only commits that include a %{code_block_start}Signed-off-by:%{code_block_end} element can be pushed to this repository."
-msgstr ""
+msgstr "Numai la commit-urile care includ un element %{code_block_start}Semnat-de:%{code_block_end} se poate face push către acest repozitoriu."
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr "Numai la commit-urile semnate se poate face push către acest repozitoriu."
@@ -31966,6 +32395,9 @@ msgstr "Securitate & Conformitate"
msgid "ProjectSettings|Security & Compliance for this project"
msgstr "Securitate și conformitate pentru acest proiect"
+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."
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr "Stabiliți comportamentul implicit al acestei opțiuni în merge request-uri. Modificările aduse acestei opțiuni se aplică, de asemenea, merge request-urilor existente."
@@ -31996,6 +32428,9 @@ msgstr "Squashing-ul se efectuează întotdeauna. Caseta de selectare este vizib
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr "Squashing-ul nu se efectuează niciodată, iar caseta de selectare este ascunsă."
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr "Trimiteți modificările pentru a fi îmbinate în amonte."
@@ -32047,6 +32482,9 @@ msgstr "Utilizatorii pot copia repozitoriul într-un nou proiect."
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr "Utilizatorii pot face push de commit-uri în acest repozitoriu doar dacă adresa de e-mail a comitentului este una dintre adresele lor de e-mail verificate."
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr "Utilizatorii pot solicita acces"
@@ -32686,6 +33124,9 @@ msgstr "Permiteți tuturor utilizatorilor cu acces push să execute %{tag_start}
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr "Permiteți tuturor utilizatorilor cu acces push să execute push forțat."
+msgid "ProtectedBranch|Allowed to create"
+msgstr "Autorizat să creeze"
+
msgid "ProtectedBranch|Allowed to force push"
msgstr "Autorizați să facă push forțat"
@@ -32722,15 +33163,27 @@ msgstr "În mod implicit, ramurile protejate limitează cine poate modifica ramu
msgid "ProtectedBranch|Code owner approval"
msgstr "Aprobarea proprietarului de cod"
+msgid "ProtectedBranch|Create wildcard"
+msgstr "Creați wildcard"
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr "Nu se aplică utilizatorilor autorizați să facă push. Secțiunile opționale nu sunt aplicate."
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr "Păstrați ramurile stabile în siguranță și forțați dezvoltatorii să folosească merge request-uri."
+msgid "ProtectedBranch|Last commit"
+msgstr "Ultimul commit"
+
msgid "ProtectedBranch|Learn more."
msgstr "Aflați mai multe."
+msgid "ProtectedBranch|New Protected Tag"
+msgstr "Nouă etichetă protejată"
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr "Nu există etichete protejate."
+
msgid "ProtectedBranch|Protect"
msgstr "Protejați"
@@ -32746,12 +33199,21 @@ msgstr "Ramuri protejate"
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr "Ramurile protejate, aprobările de merge request și verificările de stare vor apărea aici odată configurate."
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr "Etichete protejate (%{tags_count})"
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr "Refuzați împingerile de cod care modifică fișierele enumerate în fișierul CODEOWNERS."
msgid "ProtectedBranch|Require approval from code owners:"
msgstr "Necesită aprobarea proprietarilor de coduri:"
+msgid "ProtectedBranch|Search protected tags"
+msgstr "Căutare etichete protejate"
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr "Selectați eticheta sau creați un wildcard"
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr "În prezent nu există ramuri protejate, protejați o ramură cu ajutorul formularului de mai sus."
@@ -33029,7 +33491,7 @@ msgid "PushRules|Reject any files likely to contain secrets. %{secret_files_link
msgstr "Respingeți orice fișier care ar putea conține secrete. %{secret_files_link_start}Ce fișiere secrete sunt respinse?%{secret_files_link_end}"
msgid "PushRules|Reject commits that aren't DCO certified"
-msgstr ""
+msgstr "Respingeți commit-urile care nu sunt certificate DCO"
msgid "PushRules|Reject expression in commit messages"
msgstr "Respingeți mesajele de commit bazate pe această expresie"
@@ -33061,6 +33523,9 @@ msgstr "Utilizatorii pot șterge în continuare etichetele prin interfața GitLa
msgid "PushRule|Push rules"
msgstr "Reguli push"
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr "Respingeți utilizatorii neverificați"
@@ -33125,7 +33590,7 @@ msgid "Query cannot be processed"
msgstr "Interogarea nu poate fi procesată"
msgid "Queued"
-msgstr "În așteptare"
+msgstr "În coadă"
msgid "Quick actions can be used in description and comment boxes."
msgstr "Acțiunile rapide pot fi utilizate în casetele de descriere și de comentarii."
@@ -33193,12 +33658,6 @@ msgstr "Citiți mai mult"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr "Citiți mai multe despre GitLab la %{link_to_promo}."
-msgid "Read more about related epics"
-msgstr "Citiți mai multe despre epicele conexe"
-
-msgid "Read more about related issues"
-msgstr "Citiți mai multe despre problemele conexe"
-
msgid "Read their documentation."
msgstr "Citiți documentația acestora."
@@ -33292,9 +33751,6 @@ msgstr "Reduceți vizibilitatea proiectului"
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr "Reduceți riscurile și triați mai puține vulnerabilități cu ajutorul formării de securitate"
-msgid "Reduce this project’s visibility?"
-msgstr "Reduceți vizibilitatea acestui proiect?"
-
msgid "Reference"
msgstr "Referință"
@@ -33460,6 +33916,9 @@ msgstr[2] "Lansări"
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr "Versiunea %{deletedRelease} a fost ștearsă cu succes."
+msgid "Release already exists"
+msgstr "Versiunea există deja"
+
msgid "Release assets"
msgstr "Resursele versiunii"
@@ -33469,6 +33928,9 @@ msgstr "Documentația resurselor versiunii"
msgid "Release date"
msgstr "Data lansării"
+msgid "Release does not exist"
+msgstr "Versiunea nu există"
+
msgid "Release does not have the same project as the milestone"
msgstr "Lansarea nu are același proiect ca și obiectivul"
@@ -33925,6 +34387,9 @@ msgstr "Raportat de"
msgid "Reported by %{reporter}"
msgstr "Raportat de %{reporter}"
+msgid "Reporter"
+msgstr "Reporter"
+
msgid "Reporting"
msgstr "Raportare"
@@ -33940,12 +34405,6 @@ msgstr[0] "%{recentlyFailed} din %{failed} teste eșuate a eșuat mai mult de o
msgstr[1] "%{recentlyFailed} din %{failed} teste eșuate au eșuat mai mult de o dată în ultimele 14 zile"
msgstr[2] "%{recentlyFailed} din %{failed} de teste eșuate au eșuat mai mult de o dată în ultimele 14 zile"
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] "Scanarea accesibilității a detectat %d problemă numai pentru ramura sursă"
-msgstr[1] "Scanarea accesibilității a detectat %d probleme numai pentru ramura sursă"
-msgstr[2] "Scanarea accesibilității a detectat %d de probleme numai pentru ramura sursă"
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] "Scanarea accesibilității a detectat %{strong_start}%{number}%{strong_end} problemă numai pentru ramura sursă"
@@ -33976,18 +34435,12 @@ msgstr "A apărut o eroare în timpul încărcării raportului"
msgid "Reports|Base report parsing error:"
msgstr "Eroare de analiză a raportului de bază:"
-msgid "Reports|Classname"
-msgstr "Numele clasei"
-
msgid "Reports|Copy failed test names to run locally"
msgstr "Copiați numele testelor eșuate pentru a le rula local"
msgid "Reports|Copy failed tests"
msgstr "Copiați testele eșuate"
-msgid "Reports|Execution time"
-msgstr "Timp de execuție"
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] "A eșuat %{count} dată în %{baseBranch} în ultimele 14 zile"
@@ -34000,12 +34453,6 @@ msgstr[0] "A eșuat %{count} dată în %{base_branch} în ultimele 14 zile"
msgstr[1] "A eșuat de %{count} ori în %{base_branch} în ultimele 14 zile"
msgstr[2] "A eșuat de %{count} de ori în %{base_branch} în ultimele 14 zile"
-msgid "Reports|Failure"
-msgstr "Eșec"
-
-msgid "Reports|Filename"
-msgstr "Numele fișierului"
-
msgid "Reports|Fixed"
msgstr "Corectat"
@@ -34048,21 +34495,12 @@ msgstr "Scaner"
msgid "Reports|Severity"
msgstr "Severitatea"
-msgid "Reports|System output"
-msgstr "Ieșire de sistem"
-
msgid "Reports|Test summary"
msgstr "Rezumatul testului"
-msgid "Reports|Test summary failed loading results"
-msgstr "Rezumatul testului nu a reușit încărcarea rezultatelor"
-
msgid "Reports|Test summary failed to load results"
msgstr "Rezumatul testului nu a reușit să încarce rezultatele"
-msgid "Reports|Test summary results are being parsed"
-msgstr "Rezultatele rezumatului testului sunt analizate"
-
msgid "Reports|Test summary results are loading"
msgstr "Rezultatele rezumatului testului se încarcă"
@@ -34078,9 +34516,6 @@ msgstr "Numele vulnerabilității"
msgid "Reports|metrics report"
msgstr "raport de metrice"
-msgid "Reports|no changed test results"
-msgstr "nu s-au modificat rezultatele testelor"
-
msgid "Repositories"
msgstr "Repozitorii"
@@ -34241,7 +34676,7 @@ msgid "Repository mirroring configuration"
msgstr "Configurația replicării repozitoriului"
msgid "Repository mirroring has been paused due to too many failed attempts. It can be resumed by a project maintainer or owner."
-msgstr ""
+msgstr "Replicarea repozitoriului s-a întrerupt datorită prea multor încercări eșuate. Poate fi reluată de un întreținător sau proprietar de proiect."
msgid "Repository must contain at least 1 file."
msgstr "Repozitoriul trebuie să conțină cel puțin 1 fișier."
@@ -34456,6 +34891,9 @@ msgstr "Rezolvat de"
msgid "Resolved by %{name}"
msgstr "Rezolvat de %{name}"
+msgid "Resource link added"
+msgstr "Link de resurse adăugat"
+
msgid "Response"
msgstr "Răspuns"
@@ -34687,6 +35125,9 @@ msgstr "Executați pipeline-uri CI/CD cu Jenkins."
msgid "Run housekeeping"
msgstr "Executați menajul"
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr "Executați sarcini de menaj pentru a optimiza automat repozitoriile Git. Dezactivarea acestei opțiuni va duce la degradarea performanțelor în timp."
+
msgid "Run manual or delayed jobs"
msgstr "Executați joburi manuale sau întârziate"
@@ -34726,6 +35167,9 @@ msgstr[0] "%d executor selectat șters"
msgstr[1] "%d executori selectați șterși"
msgstr[2] "%d de executori selectați șterși"
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr "%{link_start}Acești executori%{link_end} sunt disponibili pentru toate grupurile și proiectele."
+
msgid "Runners|%{percentage} spot."
msgstr "%{percentage} spot."
@@ -34756,8 +35200,8 @@ msgstr "Activ"
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr "Adăugați note, cum ar fi cine este proprietarul executorului sau la ce ar trebui să fie folosit."
-msgid "Runners|Add your feedback in the issue"
-msgstr "Adăugați un feedback la problemă"
+msgid "Runners|Administrator"
+msgstr "Administrator"
msgid "Runners|All"
msgstr "Toți"
@@ -34889,7 +35333,7 @@ msgid "Runners|Group"
msgstr "Grup"
msgid "Runners|How do runners pick up jobs?"
-msgstr ""
+msgstr "Cum își aleg executorii joburile?"
msgid "Runners|How do we upgrade GitLab runner?"
msgstr "Cum actualizăm executorul GitLab?"
@@ -34966,6 +35410,9 @@ msgstr "Online"
msgid "Runners|Online:"
msgstr "Online:"
+msgid "Runners|Owner"
+msgstr "Proprietar"
+
msgid "Runners|Pause from accepting jobs"
msgstr "Întrerupeți acceptarea de joburi"
@@ -35006,7 +35453,7 @@ msgid "Runners|Register an instance runner"
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 ""
+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|Registration token"
msgstr "Tokenul de înregistrare"
@@ -35090,14 +35537,20 @@ msgid "Runners|Runners"
msgstr "Executori"
msgid "Runners|Runners are either:"
-msgstr ""
+msgstr "Executorii sunt fie:"
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr "Executorii sunt agenții care execută joburile CI/CD. Urmați %{linkStart}instrucțiunile de instalare și înregistrare%{linkEnd} pentru a configura un executor."
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr "Executorii sunt agenții care execută sarcinile CI/CD. Pentru a înregistra noi executori, contactați-vă administratorul."
+
msgid "Runners|Runs untagged jobs"
msgstr "Rulează joburi neetichetate"
+msgid "Runners|Select all"
+msgstr "Selectați-i pe toți"
+
msgid "Runners|Select projects to assign to this runner"
msgstr "Selectați proiectele pe care să le atribuiți acestui executor"
@@ -35105,7 +35558,7 @@ msgid "Runners|Select your preferred option here. In the next step, you can choo
msgstr "Selectați opțiunea preferată aici. În etapa următoare, puteți alege capacitatea executorului dvs. în consola AWS CloudFormation."
msgid "Runners|Show only inherited"
-msgstr ""
+msgstr "Afișați numai cele moștenite"
msgid "Runners|Show runner installation and registration instructions"
msgstr "Afișați instrucțiunile de instalare și înregistrare a executorului"
@@ -35138,7 +35591,7 @@ msgid "Runners|Tags"
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 ""
+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|Take me there!"
msgstr "Duceți-mă acolo!"
@@ -35146,6 +35599,9 @@ msgstr "Duceți-mă acolo!"
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr "Noua vizualizare vă oferă mai mult spațiu și o mai bună vizibilitate asupra flotei de executori."
+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."
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr "Executorul va fi șters permanent și nu va mai fi disponibil pentru proiectele sau grupurile din instanță. Sunteți sigur că doriți să continuați?"
@@ -35182,6 +35638,9 @@ msgstr "Pentru a-i înscrie, mergeți la %{link_start}pagina executorilor grupul
msgid "Runners|Token expiry"
msgstr "Expirarea tokenului"
+msgid "Runners|Unselect all"
+msgstr "Deselectați-i pe toți"
+
msgid "Runners|Up to date"
msgstr "La zi"
@@ -35221,12 +35680,6 @@ msgstr "Versiune %{version}"
msgid "Runners|View installation instructions"
msgstr "Vizualizați instrucțiunile de instalare"
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr "Dorim să vă puteți gestiona executorii ușor și eficient de pe această pagină și facem schimbări pentru a atinge acest obiectiv. Dați-ne feedback cu privire la modul în care ne descurcăm!"
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr "Am efectuat câteva modificări și am dori să avem feedbackul d-voastră"
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr "Windows 2019 Shell cu scalare manuală și programare opțională. Spot %{percentage}."
@@ -35281,17 +35734,23 @@ msgstr "Tokenuri de descoperire SAML"
msgid "SAML for %{group_name}"
msgstr "SAML pentru %{group_name}"
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
-msgstr "Selectând „Autorizați†veți transfera proprietatea contului GitLab „%{username}†(%{email}) către organizația dumneavoastră."
+msgid "SAML single sign-on"
+msgstr "Autentificare unică SAML"
+
+msgid "SAML single sign-on for %{group_name}"
+msgstr "Autentificare unică SAML pentru %{group_name}"
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr "Conectați-vă la GitLab pentru a conecta contul organizației dumneavoastră"
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
-msgstr "Grupul „%{group_path}†vă permite să vă conectați cu contul dvs. de autentificare unică (SSO)."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr "Grupul %{strongOpen}%{group_path}%{strongClose} vă permite să vă conectați folosind autentificarea unică."
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
-msgstr "Pentru a accesa „%{group_name}†trebuie să vă conectați cu contul dvs. de autentificare unică (SSO), prin intermediul unei pagini externe de autentificare."
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr "Pentru a accesa %{strongOpen}%{group_name}%{strongClose}, trebuie să vă autentificați folosind autentificarea unică printr-o pagină de autentificare externă."
+
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
+msgstr "Pentru a permite ca %{strongOpen}%{group_name}%{strongClose} să vă administreze contul GitLab %{strongOpen}%{username}%{strongClose} (%{email}) după ce vă autentificați folosind autentificarea unică, selectați %{strongOpen}Autorizați%{strongClose}."
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"
@@ -35398,12 +35857,12 @@ msgstr "Se salvează"
msgid "Saving project."
msgstr "Se salvează proiectul."
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
-msgstr "%{ifLabelStart}dacă%{ifLabelEnd} acțiunile %{rules} pentru %{scopes} %{branches}"
-
msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
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"
msgstr "%{thenLabelStart}Atunci%{thenLabelEnd} necesită executarea unei scanări %{scan}"
@@ -35422,9 +35881,15 @@ msgstr "Programare"
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr "Elementul regulii de programare"
+msgid "ScanExecutionPolicy|Select agent"
+msgstr "Selectați un agent"
+
msgid "ScanExecutionPolicy|Select branches"
msgstr "Selectați ramurile"
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr "Selectați spațiile de nume"
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr "Selectați profilul scanerului"
@@ -35434,9 +35899,15 @@ msgstr "Selectați profilul site-ului"
msgid "ScanExecutionPolicy|Site profile"
msgstr "Profil de site"
+msgid "ScanExecutionPolicy|agent"
+msgstr "agent"
+
msgid "ScanExecutionPolicy|branch"
msgstr "ramura"
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr "în spațiile de nume"
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr "%{ifLabelStart}dacă%{ifLabelEnd} %{scanners} găsește mai mult de %{vulnerabilitiesAllowed} (de) vulnerabilitate/vulnerabilități %{severities} %{vulnerabilityStates} într-un merge request deschis care vizează %{branches}"
@@ -35549,7 +36020,7 @@ msgid "Search authors"
msgstr "Căutați autorii"
msgid "Search branch"
-msgstr ""
+msgstr "Căutare ramură"
msgid "Search branches"
msgstr "Căutați ramuri"
@@ -35573,7 +36044,7 @@ msgid "Search by message"
msgstr "Căutați după mesaj"
msgid "Search by name"
-msgstr "Căutați după nume"
+msgstr "Căutare după nume"
msgid "Search files"
msgstr "Căutați fișiere"
@@ -35587,9 +36058,6 @@ msgstr "Căutați un grup LDAP"
msgid "Search for a group"
msgstr "Căutați un grup"
-msgid "Search for a user"
-msgstr "Căutați un utilizator"
-
msgid "Search for an emoji"
msgstr "Căutați un emoji"
@@ -35957,13 +36425,13 @@ msgid "SecurityConfiguration|Manage profiles for use by DAST scans."
msgstr "Gestionați profilurile de utilizat de către scanările DAST."
msgid "SecurityConfiguration|More scan types, including DAST, Dependency Scanning, Fuzzing, and Licence Compliance"
-msgstr ""
+msgstr "Mai multe tipuri de scanare, inclusiv DAST, Scanarea dependențelor, Fuzzing și Conformitatea licențelor"
msgid "SecurityConfiguration|Not enabled"
msgstr "Neactivat"
msgid "SecurityConfiguration|Once you've enabled a scan for the default branch, any subsequent feature branch you create will include the scan. An enabled scanner will not be reflected as such until the pipeline has been successfully executed and it has generated valid artifacts."
-msgstr ""
+msgstr "Odată ce ați activat o scanare pentru ramura implicită, orice ramură de caracteristică ulterioară pe care o creați va include scanarea. O scanare activată nu va fi reflectată ca atare până când pipeline-ul nu a fost executat cu succes și nu a generat artefacte valide."
msgid "SecurityConfiguration|Quickly enable all continuous testing and compliance tools by enabling %{linkStart}Auto DevOps%{linkEnd}"
msgstr "Activați rapid toate instrumentele de testare continuă și de conformitate prin activarea %{linkStart}Auto DevOps%{linkEnd}"
@@ -36007,11 +36475,14 @@ msgstr " și "
msgid "SecurityOrchestration| or "
msgstr " sau "
-msgid "SecurityOrchestration|%{branches} %{plural}"
-msgstr "%{branches}%{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr "%{agent} pentru %{namespaces}"
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
-msgstr "%{branches} și %{lastBranch}%{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
+msgstr ""
msgid "SecurityOrchestration|%{scanners}"
msgstr "%{scanners}"
@@ -36130,6 +36601,9 @@ msgstr "Moștenit"
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr "Moștenit din %{namespace}"
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr "Tip de politică invalid"
@@ -36232,12 +36706,12 @@ msgstr "Politicile privind rezultatele scanării pot fi create numai de către p
msgid "SecurityOrchestration|Scan result policy"
msgstr "Politica privind rezultatele scanării"
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
-msgstr "Scanarea trebuie efectuată %{cadence}"
-
msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr "Scanarea trebuie efectuată %{cadence} pe %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
+msgstr "Scanare care urmează să fie efectuată de agentul numit %{agents} %{cadence}"
+
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
msgstr "Scanare care trebuie efectuată pe fiecare pipeline de pe %{branches}"
@@ -36275,7 +36749,7 @@ msgid "SecurityOrchestration|Step 1: Choose a policy type"
msgstr "Etapa 1: Alegeți un tip de politică"
msgid "SecurityOrchestration|Step 2: Policy details"
-msgstr "Pasul 2: Detaliile politicii"
+msgstr "Etapa 2: Detaliile politicii"
msgid "SecurityOrchestration|Summary"
msgstr "Rezumat"
@@ -36325,8 +36799,8 @@ 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, and Container scanning."
-msgstr "Utilizați o politică de execuție a scanării pentru crearea de reguli care să impună scanări de securitate pentru anumite ramuri la un anumit moment. Tipurile acceptate sunt SAST, DAST, Detectarea secretelor și Scanarea containerelor."
+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 ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
msgstr "Utilizați o politică de rezultate ale scanării pentru a crea reguli care asigură verificarea problemelor de securitate înainte de îmbinarea unui merge request."
@@ -36343,6 +36817,9 @@ msgstr "a"
msgid "SecurityOrchestration|all branches"
msgstr "toate ramurile"
+msgid "SecurityOrchestration|all namespaces"
+msgstr "toate spațiile de nume"
+
msgid "SecurityOrchestration|an"
msgstr "un"
@@ -36361,12 +36838,21 @@ msgstr "scanerele găsesc"
msgid "SecurityOrchestration|the %{branches}"
msgstr "%{branches}"
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr "vulnerabilități"
msgid "SecurityOrchestration|vulnerability"
msgstr "vulnerabilitate"
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr "%{count} Selectat(e)"
@@ -36388,6 +36874,9 @@ msgstr "Adăugare proiecte"
msgid "SecurityReports|All activity"
msgstr "Toată activitatea"
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr "Deși este rar să nu existe vulnerabilități, acest lucru se poate întâmpla. Verificați setările pentru a vă asigura că v-ați configurat corect tabloul de bord."
@@ -36517,6 +37006,9 @@ msgstr "Proiecte monitorizate"
msgid "SecurityReports|More info"
msgstr "Mai multe informații"
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr "Vulnerabilitățile noi sunt vulnerabilitățile pe care scanarea de securitate le detectează în merge-request și care sunt diferite de vulnerabilitățile existente în ramura implicită."
+
msgid "SecurityReports|No activity"
msgstr "Nicio activitate"
@@ -36574,6 +37066,9 @@ msgstr "Rapoartele de securitate pot fi accesate numai de către utilizatorii au
msgid "SecurityReports|Security reports help page link"
msgstr "Linkul paginii de ajutor pentru rapoartele de securitate"
+msgid "SecurityReports|Security scan results"
+msgstr "Rezultatele scanării de securitate"
+
msgid "SecurityReports|Security scans have run"
msgstr "S-au executat scanările de securitate"
@@ -36599,7 +37094,7 @@ msgid "SecurityReports|Status"
msgstr "Status"
msgid "SecurityReports|Still detected"
-msgstr ""
+msgstr "Încă se detectează"
msgid "SecurityReports|Submit vulnerability"
msgstr "Trimiteți vulnerabilitatea"
@@ -36691,9 +37186,15 @@ msgstr "Feedbackul dvs. este important pentru noi! Vom întreba din nou peste o
msgid "SecurityReports|scanned resources"
msgstr "resurse scanate"
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr "Activați formarea de securitate pentru a afla cum să remediați vulnerabilitățile. Vizualizați formarea de securitate de la furnizorii educaționali selectați, relevantă pentru vulnerabilitatea detectată."
+
msgid "SecurityTraining|Primary Training"
msgstr "Formare primară"
+msgid "SecurityTraining|Resolve with security training"
+msgstr "Rezolvați cu formare de securitate"
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr "Formarea de la acest partener are prioritate atunci când sunt activați mai mulți parteneri de formare."
@@ -36706,6 +37207,9 @@ msgstr "Consultați metricile"
msgid "See our website for help"
msgstr "Consultați site-ul nostru pentru ajutor"
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr "Vedeți proiectele afectate în panoul de administrare GitLab"
@@ -36769,9 +37273,6 @@ msgstr "Selectați un repozitoriu de șabloane"
msgid "Select a template type"
msgstr "Selectați un tip de șablon"
-msgid "Select a timezone"
-msgstr "Selectați un fus orar"
-
msgid "Select all"
msgstr "Selectați tot"
@@ -36797,7 +37298,7 @@ msgid "Select branches"
msgstr "Selectați ramura"
msgid "Select default branch"
-msgstr ""
+msgstr "Selectați ramura implicită"
msgid "Select due date"
msgstr "Selectați data scadentă"
@@ -36845,7 +37346,7 @@ msgid "Select projects"
msgstr "Selectați proiecte"
msgid "Select report"
-msgstr ""
+msgstr "Selectați raportul"
msgid "Select reviewer(s)"
msgstr "Selectare recenzent(i)"
@@ -36910,10 +37411,10 @@ msgstr "Eticheta selectată este deja în uz. Alegeți o altă opțiune."
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr "Selectarea unui utilizator GitLab va adăuga un link către utilizatorul GitLab în descrierile problemelor È™i comentariilor (de exemplu, „de %{link_open}@johnsmith%{link_close}â€). De asemenea, va asocia È™i/sau atribui aceste probleme È™i comentarii cu creatorul proiectului."
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr "Automonitorizare"
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr "Proiectul de automonitorizare nu există"
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36925,29 +37426,29 @@ 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 "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr "Activați sau dezactivați automonitorizarea instanței."
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
-msgstr "Activați automonitorizarea pentru a crea un proiect pe care să-l utilizați pentru a monitoriza starea de sănătate a instanței dumneavoastră."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
+msgstr "Activați automonitorizarea pentru a crea un proiect de utilizat pentru monitorizarea sănătății instanței."
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
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?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr "Automonitorizare"
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
-msgstr "Automonitorizarea este activă. Utilizați %{projectLinkStart}proiectul de automonitorizare%{projectLinkEnd} pentru a monitoriza starea de sănătate a instanței dumneavoastră."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgstr "Automonitorizarea este activă. Utilizați %{projectLinkStart}proiectul de automonitorizare%{projectLinkEnd} pentru a monitoriza sănătatea instanței."
-msgid "SelfMonitoring|Self monitoring project successfully created."
-msgstr "Proiectul de automonitorizare a fost creat cu succes."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
+msgstr "Crearea proiectului de automonitorizare s-a finalizat."
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
-msgstr "Proiectul de automonitorizare a fost șters cu succes."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
+msgstr "Ștergerea proiectului de automonitorizare s-a finalizat."
msgid "Send"
msgstr "Trimite"
@@ -37165,9 +37666,6 @@ msgstr "Setați starea de Draft"
msgid "Set the Ready status"
msgstr "Setați starea Gata"
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr "Setați ramura implicită pentru acest proiect. Toate merge request-urile și editările sunt efectuate către această ramură, cu excepția cazului în care specificați o ramură diferită."
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr "Stabiliți timpul de expirare implicit pentru artefactele de job din toate proiectele. Setați la %{code_open}0%{code_close} pentru a nu expira niciodată artefactele în mod implicit. Dacă nu este scrisă nicio unitate, aceasta revine implicit la secunde. De exemplu, toate acestea sunt echivalente: %{code_open}3600%{code_close}, %{code_open}60 de minute%{code_close} sau %{code_open}o oră%{code_close}."
@@ -37318,9 +37816,6 @@ msgstr "Setări"
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr "Nu se pot încărca setările opțiunilor merge request-urilor. Încercați să reîncărcați pagina."
-msgid "Setup"
-msgstr "Configurare"
-
msgid "Severity"
msgstr "Severitate"
@@ -37576,11 +38071,8 @@ msgstr "Afișarea tuturor epicelor"
msgid "Showing all issues"
msgstr "Afișarea tuturor problemelor"
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr "Afișarea datelor pentru elementele fluxului de lucru create în acest interval de date. Interval de date limitat la %{maxDateRange} (de) zile."
-
-msgid "Showing graphs based on events of the last %{timerange} days."
-msgstr "Afișarea graficelor bazate pe evenimentele din ultimele %{timerange} zile."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
+msgstr "Afișarea datelor pentru elementele fluxului de lucru finalizate în acest interval de date. Interval de date limitat la %{maxDateRange} de zile."
msgid "Showing last %{size} of log -"
msgstr "Se afișează ultimii %{size} de jurnal -"
@@ -37633,8 +38125,8 @@ msgstr "Conectați-vă ca utilizator cu adresa de e-mail potrivită, adăugați
msgid "Sign in preview"
msgstr "Previzualizare autentificare"
-msgid "Sign in to \"%{group_name}\""
-msgstr "ConectaÈ›i-vă la „%{group_name}â€"
+msgid "Sign in to %{group_name}"
+msgstr "Conectați-vă la %{group_name}"
msgid "Sign in to GitLab"
msgstr "Conectați-vă la GitLab"
@@ -37648,8 +38140,8 @@ msgstr "Conectați-vă prin codul 2FA"
msgid "Sign in with"
msgstr "Conectați-vă cu"
-msgid "Sign in with Single Sign-On"
-msgstr "Conectați-vă cu autentificarea unică (SSO)"
+msgid "Sign in with single sign-on"
+msgstr "Conectați-vă cu autentificarea unică"
msgid "Sign in with smart card"
msgstr "Conectați-vă cu cardul inteligent"
@@ -37771,9 +38263,6 @@ msgstr "Limite de mărime"
msgid "Size limit per repository (MB)"
msgstr "Limita de dimensiune pe depozit (MB)"
-msgid "Skip outdated deployment jobs"
-msgstr "Săriți peste joburile de implementare învechite"
-
msgid "Skipped"
msgstr "Sărit"
@@ -37964,7 +38453,7 @@ msgid "Snowplow"
msgstr "Snowplow"
msgid "Soft wrap"
-msgstr ""
+msgstr "Încadrare suplă"
msgid "Solid"
msgstr "Solid"
@@ -37996,6 +38485,9 @@ msgstr "Cineva a editat acest merge request în același timp cu dumneavoastră.
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr "Cineva a editat acest caz de testare în același timp cu dumneavoastră. Descrierea a fost actualizată și va trebui să efectuați din nou modificările."
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "Cineva, sperăm că dvs., a solicitat resetarea parolei pentru contul dvs. GitLab pe %{link_to_gitlab}."
@@ -38107,9 +38599,6 @@ msgstr "Ceva nu a mers bine în timpul preluării mediilor pentru acest merge re
msgid "Something went wrong while fetching the packages list."
msgstr "Ceva nu a mers bine în timpul preluării listei de pachete."
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr "Ceva nu a mers bine în timpul inițializării vizualizatorului OpenAPI"
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr "Ceva nu a mers bine la obținerea certificatului Let's Encrypt."
@@ -38683,9 +39172,6 @@ msgstr "Stare:"
msgid "Status: %{title}"
msgstr "Stare: %{title}"
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr "%{failed} a(u) eșuat și %{pending} în așteptare"
-
msgid "StatusCheck|%{failed} failed"
msgstr "%{failed} a(u) eșuat"
@@ -38698,9 +39184,6 @@ msgstr "API de verificat"
msgid "StatusCheck|Add status check"
msgstr "Adăugați verificarea stării"
-msgid "StatusCheck|All passed"
-msgstr "Toate au trecut"
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr "S-a produs o eroare la ștergerea verificării stării %{name}."
@@ -38722,9 +39205,6 @@ msgstr "API-ul extern este deja utilizat de o altă verificare de stare."
msgid "StatusCheck|Failed to load status checks"
msgstr "Nu s-a reușit încărcarea verificărilor de stare"
-msgid "StatusCheck|Failed to load status checks."
-msgstr "Nu s-a reușit încărcarea verificărilor de stare."
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr "Invocați un API extern ca parte a procesului pipeline."
@@ -39244,9 +39724,15 @@ msgstr "Galben titan"
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr "Obțineți recomandări pentru recenzenți bazate pe instrumentul de învățare automată al GitLab."
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr "Aflați mai multe despre recenzenții recomandați"
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr "Recenzenți recomandați"
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr "Link de ajutor pentru recenzenții recomandați"
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr "Recomandările apar în secțiunea Recenzent din bara laterală din dreapta."
@@ -39505,6 +39991,9 @@ msgstr "Schimbați branșa"
msgid "Switch branch/tag"
msgstr "Schimbați ramura/eticheta"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr "Treceți la GitLab Next"
@@ -39595,6 +40084,9 @@ msgstr "Cuprins"
msgid "Tag"
msgstr "Etichetă"
+msgid "Tag does not exist"
+msgstr "Eticheta nu există"
+
msgid "Tag list:"
msgstr "Lista de etichete:"
@@ -39679,6 +40171,9 @@ msgstr "Ștergeți eticheta. Sunteți ABSOLUT SIGUR?"
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr "Ștergerea etichetei %{strongStart}%{tagName}%{strongEnd} nu poate fi anulată. Sunteți sigur?"
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr "DoriÈ›i să creaÈ›i o versiune cu noua etichetă? PuteÈ›i face acest lucru în pagina %{link_start}„New releaseâ€%{link_end}."
+
msgid "TagsPage|Edit release"
msgstr "Editarea versiunii"
@@ -39700,15 +40195,9 @@ msgstr "Numai un întreținător sau un proprietar de proiect poate șterge o et
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr "Opțional, adăugați un mesaj la etichetă. Lăsând acest spațiu necompletat, se creează o %{link_start}etichetă ușoară.%{link_end}"
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr "Opțional, creați o Lansare publică a proiectului dumneavoastră, bazată pe această etichetă. Notele de lansare sunt afișate pe pagina %{releases_page_link_start}Lansări%{link_end}. %{docs_link_start}Mai multe informații%{link_end}"
-
msgid "TagsPage|Please type the following to confirm:"
msgstr "Vă rugăm să introduceți următoarele date pentru a confirma:"
-msgid "TagsPage|Release notes"
-msgstr "Note de lansare"
-
msgid "TagsPage|Repository has no tags yet."
msgstr "Repozitoriul nu are încă etichete."
@@ -39730,9 +40219,6 @@ msgstr "Nu se pot încărca etichetele"
msgid "TagsPage|Use git tag command to add a new one:"
msgstr "Utilizați comanda „git tag†pentru a adăuga una nouă:"
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "Scrieți-vă notele de lansare sau trageți fișierele aici..."
-
msgid "TagsPage|Yes, delete protected tag"
msgstr "Da, ștergeți eticheta protejată"
@@ -39751,6 +40237,9 @@ msgstr "protejate"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr "Consultați documentația pentru a descoperi toate capacitățile GitLab."
+msgid "Target"
+msgstr "Țintă"
+
msgid "Target Branch"
msgstr "Ramura țintă"
@@ -39862,18 +40351,6 @@ msgstr "Folosiți Terraform? Încercați Starea Terraform administrată de GitLa
msgid "Terraform|%{name} successfully removed"
msgstr "%{name} a fost înlăturat cu succes"
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] "%{number} raport Terraform nu a putut fi generat"
-msgstr[1] "%{number} rapoarte Terraform nu au putut fi generate"
-msgstr[2] "%{number} de rapoarte Terraform nu au putut fi generate"
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] "%{number} raport Terraform a fost generat în pipeline-urile dumneavoastră"
-msgstr[1] "%{number} rapoarte Terraform au fost generate în pipeline-urile dumneavoastră"
-msgstr[2] "%{number} de rapoarte Terraform au fost generate în pipeline-urile dumneavoastră"
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] "%{strong_start}%{number}%{strong_end} raport Terraform nu a putut fi generat"
@@ -39895,12 +40372,6 @@ msgstr "Un raport Terraform nu a putut fi generat."
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr "Un raport Terraform a fost generat în pipeline-urile dumneavoastră."
-msgid "Terraform|A report failed to generate."
-msgstr "Nu s-a reușit generarea unui raport."
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr "A fost generat un raport în pipeline-urile dumneavoastră."
-
msgid "Terraform|Actions"
msgstr "Acțiuni"
@@ -39988,12 +40459,6 @@ msgstr "Comanda Terraform init"
msgid "Terraform|Terraform reports"
msgstr "Rapoarte Terraform"
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr "Jobul %{name} nu a reușit să genereze un raport."
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr "Jobul %{name} a generat un raport."
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr "Jobul %{strong_start}%{name}%{strong_end} nu a reușit să genereze un raport."
@@ -40453,6 +40918,9 @@ msgstr "Numele de gazdă al serverului PlantUML."
msgid "The hostname of your Snowplow collector."
msgstr "Numele de gazdă al colectorului Snowplow."
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr "Importul nu poate fi anulat deoarece este %{project_status}"
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "Importul va expira după %{timeout}. Pentru repozitoriile care necesită mai mult timp, utilizați o combinație clonă/push."
@@ -40648,9 +41116,6 @@ msgstr "Repozitoriul trebuie să fie accesibil prin %{code_open}http://%{code_cl
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr "Resursa pe care încercați să o accesați nu există sau nu aveți permisiunea de a efectua această acțiune."
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr "Același executor partajat execută cod din mai multe proiecte, numai dacă nu configurați scalarea automată cu %{link} setat la 1 (care este pe GitLab.com)."
-
msgid "The scan has been created."
msgstr "Scanarea a fost creată."
@@ -40681,8 +41146,8 @@ msgstr "Subiectul sursă nu este un subiect."
msgid "The specified tab is invalid, please select another"
msgstr "Fila specificată nu este validă, vă rugăm să selectați alta"
-msgid "The start date must be ealier than the end date."
-msgstr "Data de început trebuie să fie mai devreme decât data de sfârșit."
+msgid "The start date must be earlier than the end date."
+msgstr "Data de început trebuie să fie anterioară datei de sfârșit."
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
msgstr "Subiectul va fi folosit ca titlu al noii probleme, iar mesajul va fi descrierea. Sunt acceptate %{quickActionsLinkStart}acțiunile rapide%{quickActionsLinkEnd} și formatarea cu %{markdownLinkStart}Markdown%{markdownLinkEnd}."
@@ -40738,9 +41203,6 @@ msgstr "Vulnerabilitatea nu mai este detectată. Verificați dacă vulnerabilita
msgid "Theme"
msgstr "Tema"
-msgid "There are currently no events."
-msgstr "În prezent nu există evenimente."
-
msgid "There are currently no mirrored repositories."
msgstr "În prezent, nu există repozitorii replicate."
@@ -41092,9 +41554,6 @@ msgstr "Aceste probleme existente au un titlu similar. Ar fi mai bine să coment
msgid "These runners are shared across projects in this group."
msgstr "Acești executori sunt partajați între proiectele din acest grup."
-msgid "These runners are shared across this GitLab instance."
-msgstr "Acești executori sunt partajați pe această instanță GitLab."
-
msgid "These runners are specific to this project."
msgstr "Acești executori sunt specifici pentru acest proiect."
@@ -41128,6 +41587,9 @@ msgstr "Acest %{viewer} nu a putut fi afișat deoarece %{reason}. Puteți %{opti
msgid "This Cron pattern is invalid"
msgstr "Acest model Cron nu este valid"
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr "Această instanță GitLab nu oferă încă niciun executor partajat. Administratorii instanței pot înregistra executorii partajați în zona admin."
@@ -41294,25 +41756,22 @@ msgid "This epic already has the maximum number of child epics."
msgstr "Această epică are deja numărul maxim de epice copil."
msgid "This epic cannot be added. An epic cannot be added to itself."
-msgstr ""
-
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
+msgstr "Această epică nu poate fi adăugată. O epică nu se poate adăuga la ea însăși."
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
-msgstr ""
+msgstr "Această epică nu poate fi adăugată. O epică trebuie să aparțină aceluiași grup sau subgrup ca și epica părinte."
msgid "This epic cannot be added. It is already an ancestor of the parent epic."
-msgstr ""
+msgstr "Această epică nu poate fi adăugată. Este deja un strămoș al epicei părinte."
msgid "This epic cannot be added. It is already assigned to the parent epic."
-msgstr ""
+msgstr "Această epică nu poate fi adăugată. Ea este deja atribuită epicei părinte."
msgid "This epic cannot be added. One or more epics would exceed the maximum depth (%{max_depth}) from its most distant ancestor."
-msgstr ""
+msgstr "Această epică nu poate fi adăugată. Una sau mai multe epice ar depăși adâncimea maximă (%{max_depth}) de la strămoșul cel mai îndepărtat."
msgid "This epic cannot be added. You don't have access to perform this action."
-msgstr ""
+msgstr "Această epică nu poate fi adăugată. Nu aveți acces pentru a efectua această acțiune."
msgid "This epic does not exist or you don't have sufficient permission."
msgstr "Această epică nu există sau nu aveți permisiunea suficientă."
@@ -41359,6 +41818,9 @@ msgstr "Acest grup a fost programat pentru înlăturare permanentă la %{date}."
msgid "This group has no active access tokens."
msgstr "Acest grup nu are tokenuri de acces active."
+msgid "This group has no projects yet"
+msgstr "Acest grup nu are încă proiecte"
+
msgid "This group is linked to a subscription"
msgstr "Acest grup este legat de un abonament"
@@ -41575,15 +42037,18 @@ msgstr "Acest merge request a fost îmbinat. Pentru a aplica această sugestie,
msgid "This namespace has already been taken! Please choose another one."
msgstr "Acest spațiu de nume a fost deja luat! Vă rugăm să alegeți altul."
+msgid "This namespace has already been taken. Choose a different one."
+msgstr "Acest spațiu de nume a fost deja luat. Alegeți altul."
+
msgid "This only applies to repository indexing operations."
msgstr "Acest lucru se aplică numai la operațiunile de indexare a repozitoriilor."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
+msgstr ""
+
msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr "Această pagină nu este disponibilă deoarece nu aveți permisiunea de a citi informații în mai multe proiecte."
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
-msgstr "Această pagină trimite o sarcină. Întoarceți-vă la pagina evenimentelor pentru a vedea un eveniment nou creat."
-
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
msgstr "Acest pipeline utilizează o configurație predefinită CI/CD activată de %{b_open}Auto DevOps.%{b_close}"
@@ -41654,7 +42119,7 @@ msgid "This project will be deleted on %{date} since its parent group '%{parent_
msgstr "Acest proiect va fi șters la %{date}, deoarece grupul său părinte „%{parent_group_name}†a fost programat pentru ștergere."
msgid "This project's pipeline configuration is located outside this repository"
-msgstr ""
+msgstr "Configurația pipeline-ului proiectului se află în afara acestui repozitoriu"
msgid "This release was created with a date in the past. Evidence collection at the moment of the release is unavailable."
msgstr "Această versiune a fost creată cu o dată din trecut. Colectarea probelor la momentul lansării nu este disponibilă."
@@ -41710,9 +42175,6 @@ msgstr "Acest utilizator are o adresă de e-mail neconfirmată. Puteți forța o
msgid "This user has no active %{accessTokenTypePlural}."
msgstr "Acest utilizator nu are %{accessTokenTypePlural} active."
-msgid "This user has no active %{type}."
-msgstr "Acest utilizator nu are niciun %{type} activ."
-
msgid "This user has no identities"
msgstr "Acest utilizator nu are identități"
@@ -41731,6 +42193,9 @@ msgstr "Acest utilizator este autorul acestui/acestei %{noteable}."
msgid "This variable can not be masked."
msgstr "Această variabilă nu poate fi mascată."
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr "Aceasta va invalida aplicațiile înregistrate și dispozitivele U2F / WebAuthn."
@@ -41744,7 +42209,7 @@ msgid "This will remove the fork relationship between this project and other pro
msgstr "Aceasta va elimina relația fork dintre acest proiect și alte proiecte din rețeaua fork."
msgid "Thread options"
-msgstr ""
+msgstr "Opțiunile subiectului"
msgid "Thread to reply to cannot be found"
msgstr "Nu se poate găsi subiectul la care să răspundeți"
@@ -42103,9 +42568,6 @@ msgstr "Pentru a aproba acest merge request, introduceți parola. Acest proiect
msgid "To complete registration, we need additional details from you."
msgstr "Pentru a finaliza înregistrarea, avem nevoie de detalii suplimentare de la dumneavoastră."
-msgid "To confirm, type %{phrase_code}"
-msgstr "Pentru confirmare, tastați %{phrase_code}"
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr "Pentru a conecta repozitoriile GitHub, puteți utiliza un %{personal_access_token_link}. Atunci când vă creați Tokenul de acces personal, va trebui să selectați domeniul %{code_open}repo%{code_close}, astfel încât să putem afișa o listă a repozitoriilor dvs. publice și private care sunt disponibile pentru conectare."
@@ -42128,7 +42590,7 @@ msgid "To define internal users, first enable new users set to external"
msgstr "Pentru a defini utilizatorii interni, activați mai întâi setarea ca noii utilizatori să fie externi"
msgid "To edit the pipeline configuration, you must go to the project or external site that hosts the file."
-msgstr ""
+msgstr "Pentru a edita configurația pipeline-ului, trebuie să accesați proiectul sau site-ul extern care găzduiește fișierul."
msgid "To enable Registration Features, first enable Service Ping."
msgstr "Pentru a activa Funcțiile de înregistrare, activați mai întâi Serviciul Ping."
@@ -42211,6 +42673,9 @@ msgstr "Pentru a vă reactiva contul, %{gitlab_link_start}conectați-vă la GitL
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr "Pentru a vă reactiva contul, conectați-vă la GitLab la %{gitlab_url}."
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr "Pentru a rezolva această, încercați să:"
@@ -42277,9 +42742,33 @@ msgstr "Astăzi"
msgid "Todos count"
msgstr "Număr de todos"
+msgid "Todos|Added"
+msgstr "Adăugate"
+
+msgid "Todos|Alert"
+msgstr "Alertă"
+
+msgid "Todos|Any Action"
+msgstr "Orice acțiune"
+
+msgid "Todos|Any Type"
+msgstr "Orice tip"
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr "Căutați lucruri de făcut? Aruncați o privire la %{strongStart}%{openIssuesLinkStart}problemele deschise%{openIssuesLinkEnd}%{strongEnd}, contribuiți la %{strongStart}%{mergeRequestLinkStart}un merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd} sau menționați pe cineva într-un comentariu pentru a-i atribui automat un nou element de-făcut."
+msgid "Todos|Assigned"
+msgstr "Atribuite"
+
+msgid "Todos|Could not merge"
+msgstr "Nu s-a putut îmbina"
+
+msgid "Todos|Design"
+msgstr "Design"
+
+msgid "Todos|Epic"
+msgstr "Epică"
+
msgid "Todos|Filter by author"
msgstr "Filtrați după autor"
@@ -42299,7 +42788,10 @@ msgid "Todos|Henceforth, you shall be known as \"To-Do Destroyer\""
msgstr "De acum înainte, veÈ›i fi cunoscut ca „Distrugătorul de sarcini De-Făcutâ€."
msgid "Todos|Isn't an empty To-Do List beautiful?"
-msgstr "Nu-i așa că o listă De-Făcut este frumoasă?"
+msgstr "Nu-i așa că o listă De-Făcut goală este frumoasă?"
+
+msgid "Todos|Issue"
+msgstr "Problemă"
msgid "Todos|It's how you always know what to work on next."
msgstr "În acest fel știți totdeauna la ce să lucrați în continuare."
@@ -42307,12 +42799,30 @@ msgstr "În acest fel știți totdeauna la ce să lucrați în continuare."
msgid "Todos|Mark all as done"
msgstr "Marcați totul ca terminat"
+msgid "Todos|Mentioned"
+msgstr "Menționate"
+
+msgid "Todos|Merge request"
+msgstr "Merge request"
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr "Nu aveți nimic pe lista lucrurilor de-făcut. Bine lucrat!"
msgid "Todos|Nothing left to do. High five!"
msgstr "Nu mai e nimic de făcut. Bate palma!"
+msgid "Todos|Pipelines"
+msgstr "Pipeline-uri"
+
+msgid "Todos|Removed from Merge Train:"
+msgstr "Înlăturat din Merge Train:"
+
+msgid "Todos|Review requested"
+msgstr "Solicitări de revizuire"
+
+msgid "Todos|The pipeline failed in"
+msgstr "Pipeline-ul a eșuat în"
+
msgid "Todos|Undo mark all as done"
msgstr "Anulați marcarea tuturor ca fiind făcute"
@@ -42325,6 +42835,24 @@ msgstr "Ați terminat totul!"
msgid "Todos|Your To-Do List shows what to work on next"
msgstr "Lista de sarcini De-Făcut arată la ce să lucrați în continuare"
+msgid "Todos|added a todo for"
+msgstr "a adăugat o sarcină de făcut pentru"
+
+msgid "Todos|mentioned %{who} on"
+msgstr "a menționat pe %{who} pe"
+
+msgid "Todos|requested a review of"
+msgstr "a solicitat o revizuire a"
+
+msgid "Todos|set %{who} as an approver for"
+msgstr "setați %{who} ca aprobator pentru"
+
+msgid "Todos|yourself"
+msgstr "înșivă"
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr "la %{todo_parent_path}"
+
msgid "Toggle GitLab Next"
msgstr "Comutați la GitLab Next"
@@ -42475,9 +43003,6 @@ msgstr "Contribuții totale"
msgid "Total Score"
msgstr "Scor total"
-msgid "Total artifacts size: %{total_size}"
-msgstr "Mărimea totală a artefactelor: %{total_size}"
-
msgid "Total cores (CPUs)"
msgstr "Total nuclee (CPU)"
@@ -42799,6 +43324,12 @@ msgstr "Autentificarea cu doi factori a fost dezactivată pentru acest utilizato
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr "Autentificarea cu doi factori a fost dezactivată pentru contul dvs. GitLab."
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr "Dezactivarea autentificării cu doi factori pentru %{user_email} s-a finalizat!"
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr "Dezactivarea autentificării cu doi factori pentru %{username} s-a finalizat!"
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr "Autentificarea cu doi factori a fost dezactivată cu succes!"
@@ -43303,6 +43834,12 @@ msgstr "Tendințe de utilizare"
msgid "Usage statistics"
msgstr "Statistici de utilizare"
+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ță."
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr "Această statistică de stocare la nivel de proiect nu include economiile pentru deduplicarea la nivel de site și nu este utilizată pentru a calcula stocarea totală a spațiului de nume."
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr "%{help_link_start}Executorii partajați%{help_link_end} sunt dezactivați, așa că nu există limite stabilite pentru utilizarea de pipeline-uri."
@@ -43405,6 +43942,9 @@ msgstr "Stocarea spațiului de nume utilizată"
msgid "UsageQuota|No CI minutes usage data available."
msgstr "Nu sunt disponibile date privind utilizarea minutelor CI."
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr "Pachete"
@@ -43435,6 +43975,9 @@ msgstr "Recalculați utilizarea repozitorului"
msgid "UsageQuota|Repository"
msgstr "Repozitoriu"
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr "Seat-uri"
@@ -44444,7 +44987,7 @@ msgid "View blame prior to this change"
msgstr "Consultați blame înainte de această modificare"
msgid "View card matches"
-msgstr ""
+msgstr "Vizualizați potriviri card"
msgid "View chart"
msgid_plural "View charts"
@@ -44488,9 +45031,6 @@ msgstr "Vizualizați fișierul @ %{commitSha}"
msgid "View full dashboard"
msgstr "Vizualizați dashboard-ul complet"
-msgid "View full log"
-msgstr "Vizualizați jurnalul complet"
-
msgid "View group in admin area"
msgstr "Vizualizați grupul în Zona Admin"
@@ -44953,6 +45493,9 @@ msgstr "Solicitare/Răspuns"
msgid "Vulnerability|Scanner Provider"
msgstr "Furnizorul scanerului"
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr "Audit de securitate"
@@ -44971,6 +45514,9 @@ msgstr "Severitate:"
msgid "Vulnerability|Status"
msgstr "Status"
+msgid "Vulnerability|Status:"
+msgstr "Status:"
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr "Scanerul a determinat că această vulnerabilitate este un fals pozitiv. Verificați evaluarea înainte de a-i schimba statutul. %{linkStart}Aflați mai multe despre detectarea falsurilor pozitive.%{linkEnd}"
@@ -44981,7 +45527,7 @@ msgid "Vulnerability|Tool"
msgstr "Instrument"
msgid "Vulnerability|Tool:"
-msgstr ""
+msgstr "Instrument:"
msgid "Vulnerability|Training"
msgstr "Formare"
@@ -45106,8 +45652,8 @@ msgstr "Am încercat să vă reînnoim automat abonamentul pentru %{strong}%{nam
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "Vrem să fim siguri că sunteți dvs., vă rugăm să confirmați că nu sunteți un robot."
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
-msgstr "Dorim să vă informăm că %{username} a fost interzis din %{scope} deoarece a descărcat mai mult de %{max_project_downloads} (de) repozitorii de proiecte în decurs de %{within_minutes} (de) minute."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
+msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
msgstr "Vom notifica %{inviter} că ați refuzat invitația de a vă alătura GitLab. Nu veți mai primi mementouri."
@@ -45148,6 +45694,9 @@ msgstr "Dispozitive WebAuthn (%{length})"
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr "WebAuthn funcționează numai cu site-uri web compatibile HTTPS. Contactați administratorul dumneavoastră pentru mai multe detalii."
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr "Creați fork de proiect"
@@ -45163,12 +45712,24 @@ msgstr "Editați cu rapiditate și ușurință mai multe fișiere din proiect."
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr "Editați cu rapiditate și ușurință mai multe fișiere din proiect. Apăsați . pentru a deschide"
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr "Acest proiect nu acceptă commit-uri nesemnate."
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr "Acest proiect nu acceptă commit-uri nesemnate. Nu puteți comite modificări prin intermediul Web IDE."
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr "Nu puteți edita fișiere direct în acest proiect. Creați un fork pentru acest proiect și trimiteți un merge request cu modificările dumneavoastră."
@@ -45208,6 +45769,9 @@ msgstr "Webhook-uri"
msgid "Webhooks Help"
msgstr "Ajutor Webhook-uri"
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr "+ Mascați o altă porțiune din URL"
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr "Se adaugă un comentariu la o problemă confidențială."
@@ -45278,7 +45842,7 @@ msgid "Webhooks|Deployment events"
msgstr "Evenimente de desfășurare"
msgid "Webhooks|Do not show sensitive data such as tokens in the UI."
-msgstr ""
+msgstr "Nu afișați date sensibile, cum ar fi tokenurile, în UI."
msgid "Webhooks|Enable SSL verification"
msgstr "Activați verificarea SSL"
@@ -45296,7 +45860,7 @@ msgid "Webhooks|Go to webhooks"
msgstr "Mergeți la webhook-uri"
msgid "Webhooks|How it looks in the UI"
-msgstr ""
+msgstr "Cum arată în UI"
msgid "Webhooks|Issues events"
msgstr "Evenimente de probleme"
@@ -45305,7 +45869,7 @@ msgid "Webhooks|Job events"
msgstr "Evenimente de job"
msgid "Webhooks|Mask portions of URL"
-msgstr ""
+msgstr "Mascați porțiuni din URL"
msgid "Webhooks|Member events"
msgstr "Evenimente de membri"
@@ -45322,6 +45886,12 @@ msgstr "Evenimente de push"
msgid "Webhooks|Push to the repository."
msgstr "Push către repozitoriu."
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr "Regex precum %{REGEX_CODE} este acceptat."
+
+msgid "Webhooks|Regular expression"
+msgstr "Expresie regulată"
+
msgid "Webhooks|Releases events"
msgstr "Evenimente de lansări"
@@ -45332,10 +45902,10 @@ msgid "Webhooks|Secret token"
msgstr "Token secret"
msgid "Webhooks|Sensitive portion of URL"
-msgstr ""
+msgstr "Părți sensibile din URL"
msgid "Webhooks|Show full URL"
-msgstr ""
+msgstr "Afișare URL complet"
msgid "Webhooks|Subgroup events"
msgstr "Evenimente de subgrup"
@@ -45349,9 +45919,6 @@ msgstr "Webhook-ul %{help_link_start}nu a reușit să se conecteze%{help_link_en
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr "Webhook-ul nu a reușit să se conecteze și este dezactivat. Pentru a-l reactiva, verificați %{strong_start}Evenimentele recente%{strong_end} pentru detalii despre eroare, apoi testați setările dvs. mai jos."
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr "Webhook-ul a fost declanșat de mai mult de %{limit} (de) ori pe minut și este acum dezactivat. Pentru a reactiva acest webhook, rezolvați problemele afișate în %{strong_start}Evenimentele recente%{strong_end}, apoi retestați-vă setările. %{support_link_start}Contactați serviciul de asistență%{support_link_end} dacă aveți nevoie de ajutor pentru a vă reactiva webhook-ul."
-
msgid "Webhooks|Trigger"
msgstr "Declanșator"
@@ -45362,10 +45929,10 @@ msgid "Webhooks|URL must be percent-encoded if it contains one or more special c
msgstr "URL-ul trebuie să fie codificat-procentual atunci când conține unul sau mai multe caractere speciale."
msgid "Webhooks|URL preview"
-msgstr ""
+msgstr "Previzualizare URL"
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
-msgstr "Utilizat pentru a valida payload-urile primite. Trimis împreună cu cererea în antetul %{code_start}X-Gitlab-Token HTTP%{code_end}."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
+msgstr "Utilizat pentru a valida payload-urile primite. Trimis cu solicitarea în antetul HTTP %{code_start}X-Gitlab-Token%{code_end}."
msgid "Webhooks|Webhook disabled"
msgstr "Webhook dezactivat"
@@ -45376,12 +45943,21 @@ msgstr "Webhook-ul nu a reușit să se conecteze"
msgid "Webhooks|Webhook fails to connect"
msgstr "Webhook-ul nu reușește să se conecteze"
-msgid "Webhooks|Webhook was automatically disabled"
-msgstr "Webhook-ul a fost dezactivat automat"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr "Limita ratei webhook-ului a fost atinsă"
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
+msgstr "Webhook-urile pentru %{root_namespace} sunt acum dezactivate deoarece au fost declanșate mai mult de %{limit} de ori pe minut. Acestea vor fi reactivate automat în următorul minut."
msgid "Webhooks|Wiki page events"
msgstr "Evenimente de pagină Wiki"
+msgid "Webhooks|Wildcard pattern"
+msgstr "Model wildcard"
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr "Sunt acceptate caractere wildcard precum %{WILDCARD_CODE_STABLE} sau %{WILDCARD_CODE_PRODUCTION}."
+
msgid "Website"
msgstr "Site web"
@@ -45460,6 +46036,9 @@ msgstr "Ce este squashing-ul?"
msgid "What templates can I create?"
msgstr "Ce șabloane pot crea?"
+msgid "What variables can I use?"
+msgstr "Ce variabile pot folosi?"
+
msgid "What will you use this group for?"
msgstr "Pentru ce veți folosi acest grup?"
@@ -45469,8 +46048,8 @@ msgstr "Ce ați dori să faceți?"
msgid "What's new"
msgstr "Ce este nou"
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
-msgstr "Atunci când un job de implementare are succes, săriți joburile de implementare mai vechi încă în așteptare."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
+msgstr "Când un job de implementare reușește, se previn joburile de implementare mai vechi care sunt încă în așteptare."
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr "Atunci când un executor este blocat, acesta nu poate fi desemnat pentru alte proiecte."
@@ -45787,6 +46366,12 @@ msgstr "Adăugați data de început"
msgid "WorkItem|Add task"
msgstr "Adăugați sarcina"
+msgid "WorkItem|Add to iteration"
+msgstr "Adăugați la iterație"
+
+msgid "WorkItem|Add to milestone"
+msgstr "Adăugați un obiectiv"
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr "Sunteți sigur că doriți să anulați editarea?"
@@ -45838,9 +46423,24 @@ msgstr "Introducerea sarcinilor"
msgid "WorkItem|Issue"
msgstr "Problemă"
+msgid "WorkItem|Iteration"
+msgstr "Iterație"
+
msgid "WorkItem|Learn about tasks."
msgstr "Învățați despre sarcini."
+msgid "WorkItem|Milestone"
+msgstr "Obiectiv"
+
+msgid "WorkItem|No iteration"
+msgstr "Nicio iterație"
+
+msgid "WorkItem|No matching results"
+msgstr "Nicio potrivire de rezultate"
+
+msgid "WorkItem|No milestone"
+msgstr "Niciun obiectiv"
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr "În prezent, nu sunt alocate sarcini. Utilizați sarcinile pentru a împărți această problemă în părți mai mici."
@@ -45871,12 +46471,15 @@ msgstr "Ceva nu a mers bine la ștergerea %{workItemType}. Vă rugăm să încer
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr "Ceva nu a mers bine la ștergerea sarcinii. Vă rugăm să încercați din nou."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr "Ceva nu a mers bine la preluarea iterațiilor. Vă rugăm să încercați din nou."
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr "Ceva nu a mers bine la preluarea etichetelor. Vă rugăm să încercați din nou."
+
msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr "Ceva nu a mers bine la preluarea sarcinilor. Vă rugăm să reîmprospătați această pagină."
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
-msgstr "Ceva nu a mers bine la preluarea elementului de lucru. Vă rugăm să încercați din nou."
-
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
msgstr "Ceva nu a mers bine la preluarea tipurilor de elemente de lucru. Vă rugăm să încercați din nou"
@@ -45886,6 +46489,9 @@ msgstr "Ceva nu a mers bine atunci când s-a încercat adăugarea unui copil. VÄ
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr "Ceva nu a mers bine atunci când ați încercat să creați un copil. Încercați din nou."
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr "Ceva nu a mers bine în timpul recuperării obiectivelor. Încercați din nou."
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr "Ceva nu a mers bine în timp ce se actualiza %{workItemType}. Vă rugăm să încercați din nou."
@@ -45907,6 +46513,9 @@ msgstr "Sarcini"
msgid "WorkItem|Test case"
msgstr "Caz de testare"
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr "Acest element de lucru este indisponibil. Fie nu există, fie nu aveți permisiunea de a-l vizualiza."
+
msgid "WorkItem|Turn off confidentiality"
msgstr "Opriți confidențialitatea"
@@ -45925,6 +46534,9 @@ msgstr "Elemente de lucru"
msgid "WorkItem|Work item"
msgstr "Element de lucru"
+msgid "WorkItem|Work item not found"
+msgstr "Elementul de lucru nu a fost găsit"
+
msgid "Would you like to create a new branch?"
msgstr "Doriți să creați o nouă ramură?"
@@ -46021,6 +46633,9 @@ msgstr "Încercați să ștergeți un fișier care a fost actualizat anterior."
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr "Încercați să actualizați un fișier care s-a modificat de când ați început să-l editați."
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr "Dacă depășiți acest număr, veți fi facturat. %{qsrOverageLinkStart}Cum funcționează facturarea?%{qsrOverageLinkEnd}"
@@ -46057,6 +46672,12 @@ msgstr "Nu aveți permisiunea să %{action} un utilizator"
msgid "You are not allowed to approve a user"
msgstr "Nu aveți voie să aprobați un utilizator"
+msgid "You are not allowed to create this tag as it is protected."
+msgstr "Nu aveți permisiunea să creați această etichetă, deoarece este protejată."
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr "Nu aveți voie să vă conectați folosind parola"
@@ -46102,9 +46723,6 @@ msgstr "Sunteți conectat la GitLab ca:"
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr "Încercați să încărcați altceva decât o imagine. Vă rugăm să încărcați un fișier .png, .jpg, .jpeg, .gif, .bmp, .tiff sau .ico."
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr "Folosiți %{pg_version_current}, dar pentru această versiune de GitLab este necesar %{pg_version_minimum}. Vă rugăm să vă actualizați mediul la o versiune PostgreSQL acceptată, consultați %{pg_requirements_url} pentru detalii."
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr "Puteți să %{gitlabLinkStart}rezolvați conflictele pe GitLab%{gitlabLinkEnd} sau %{resolveLocallyStart}să le rezolvați local%{resolveLocallyEnd}."
@@ -46207,6 +46825,9 @@ msgstr "Puteți activa crearea de tokenuri de acces de grup în %{link_start}set
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr "Puteți activa crearea de tokenuri de acces la proiect în %{link_start}setările grupului%{link_end}."
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr "Puteți filtra în funcție de „zile până la îmbinare†făcând clic pe coloanele din grafic."
@@ -46279,8 +46900,8 @@ msgstr "Vă puteți testa fișierul .gitlab-ci.yml în %{linkStart}CI Lint%{link
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr "Puteți vizualiza sursa sau %{linkStart}%{cloneIcon} clona repozitoriul%{linkEnd}"
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
-msgstr "Nu puteți să mai adăugați membri, dar puteți să-i gestionați pe cei existenți, de exemplu, înlăturând membrii inactivi și înlocuindu-i cu alții noi. În vederea obținerii mai multor membri, un proprietar al grupului poate începe o perioadă de probă sau poate trece la un nivel plătit."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
+msgstr "Nu puteți urmări mai mult de %{limit} de utilizatori. Pentru a urmări mai mulți utilizatori, renunțați la urmărirea unora."
msgid "You cannot %{action} %{state} users."
msgstr "Nu puteți %{action} utilizatorii %{state}."
@@ -46303,6 +46924,9 @@ msgstr "Nu puteți impersona un utilizator blocat"
msgid "You cannot impersonate a user who cannot log in"
msgstr "Nu puteți impersona un utilizator care nu se poate conecta"
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr "Nu puteți impersona un utilizator intern"
@@ -46447,6 +47071,9 @@ msgstr "Nu aveți permisiuni suficiente pentru a crea un program de gardă pentr
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr "Nu aveți permisiuni suficiente pentru a gestiona linkurile resurselor acestui incident"
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr "Nu aveți permisiuni suficiente pentru a gestiona evenimentele cronologice pentru acest incident"
@@ -46510,7 +47137,7 @@ msgstr "Trebuie să fiți autentificat pentru a accesa această cale."
msgid "You must be logged in to search across all of GitLab"
msgstr "Trebuie să fiți autentificat pentru a căuta peste tot în GitLab"
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46678,9 +47305,6 @@ msgstr "YouTube"
msgid "Your %{group} membership will now expire in %{days}."
msgstr "Abonamentul dvs. %{group} va expira acum în %{days}."
-msgid "Your %{host} account was signed in to from a new location"
-msgstr "Contul dvs. %{host} a fost conectat dintr-o locație nouă"
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr "%{spammable_entity_type} dvs. a fost recunoscut ca spam și a fost înlăturat."
@@ -46792,6 +47416,9 @@ msgstr "Contul dvs. este blocat."
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr "Contul dvs. utilizează acreditări dedicate pentru grupul \"%{group_name}\" și poate fi actualizat numai prin SSO."
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr "Acțiunea a fost respinsă deoarece ați atins limita de stocare a spațiului de nume. Pentru mai multe informații, vizitați %{doc_url}."
+
msgid "Your action succeeded."
msgstr "Acțiunea dvs. a reușit."
@@ -46912,18 +47539,15 @@ msgstr "Mesajul dvs. aici"
msgid "Your name"
msgstr "Numele dvs."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
+msgstr ""
+
msgid "Your new %{accessTokenType}"
msgstr "Noul dvs. %{accessTokenType}"
msgid "Your new %{accessTokenType} has been created."
msgstr "Noul dvs. %{accessTokenType} a fost creat."
-msgid "Your new %{type}"
-msgstr "Noul dvs. %{type}"
-
-msgid "Your new access token has been created."
-msgstr "Noul dvs. token de acces a fost creat."
-
msgid "Your new comment"
msgstr "Noul dvs. comentariu"
@@ -47011,6 +47635,9 @@ msgstr "Actualizarea a eșuat. Trebuie să încărcați un fișier cu același n
msgid "Your username is %{username}."
msgstr "Numele dvs. de utilizator este %{username}."
+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 "SunteÈ›i pe cale să È™tergeÈ›i definitiv %{issuableType} „%{strongOpen}%{issuableTitle}%{strongClose}â€. Pentru a evita pierderea de date, consideraÈ›i mai degrabă %{strongOpen}închiderea acestui/acestei %{issuableType}%{strongClose}. După È™tergere, nu se mai poate anula sau recupera."
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr "Nu s-a reușit încărcarea problemei ZenTao. Vizualizați problema în ZenTao sau reîncărcați pagina."
@@ -47080,9 +47707,6 @@ msgstr "„end_time†nu trebuie să depășească o lună după „start_timeâ
msgid "`start_time` should precede `end_time`"
msgstr "„start_time†ar trebui să preceadă „end_timeâ€"
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr "Pentru acest proiect, Feature Flag „work_items_hierarchy†a fost dezactivat"
-
msgid "a deleted user"
msgstr "un utilizator șters"
@@ -47095,9 +47719,6 @@ msgstr[2] "aproximativ %d de ore"
msgid "access:"
msgstr "acces:"
-msgid "added"
-msgstr "adăugat(ă)"
-
msgid "added %{emails}"
msgstr "adăugat %{emails}"
@@ -47158,6 +47779,12 @@ msgstr "artefacte"
msgid "assign yourself"
msgstr "atribuiți-vă singur"
+msgid "assigned"
+msgstr "atribuit"
+
+msgid "assigned you"
+msgstr "v-a desemnat"
+
msgid "at"
msgstr "la"
@@ -47167,9 +47794,6 @@ msgstr "cel puțin rolul de Reporter"
msgid "at least the Reporter role, the author, and assignees"
msgstr "cel puțin rolul de Reporter, autorul și responsabilii"
-msgid "at risk"
-msgstr "la risc"
-
msgid "attach a new file"
msgstr "atașați un fișier nou"
@@ -47201,7 +47825,7 @@ msgid "cURL:"
msgstr "cURL:"
msgid "can contain only digits"
-msgstr ""
+msgstr "poate conține numai cifre"
msgid "can contain only letters of the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'"
msgstr "poate conÈ›ine numai litere din alfabetul Base64 (RFC4648), la care se adaugă „@â€, „:†și „.â€."
@@ -47249,7 +47873,13 @@ msgid "cannot be a date in the past"
msgstr "nu poate fi o dată în trecut"
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
-msgstr ""
+msgstr "nu poate fi adăugat deoarece ați atins limita de %{free_limit} membri pentru %{namespace_name}"
+
+msgid "cannot be associated with a subgroup"
+msgstr "nu poate fi asociat cu un subgrup"
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr "nu poate fi asociat atât cu un Grup, cât și cu un Proiect"
msgid "cannot be changed"
msgstr "nu se poate modifica"
@@ -47488,12 +48118,27 @@ msgstr "Scanarea dependențelor detectează vulnerabilitățile cunoscute în de
msgid "ciReport|Dependency scanning"
msgstr "Scanarea dependențelor"
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr "Descărcați patch-ul pentru a rezolva"
msgid "ciReport|Download the patch to apply it manually"
msgstr "Descărcați patch-ul pentru a-l aplica manual"
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr "Testarea dinamică a securității aplicațiilor (DAST) detectează vulnerabilitățile cunoscute din aplicația dvs. web."
@@ -47516,7 +48161,7 @@ msgid "ciReport|Full Report"
msgstr "Raportul complet"
msgid "ciReport|Generic Report"
-msgstr ""
+msgstr "Raport generic"
msgid "ciReport|IaC Scanning"
msgstr "Scanarea IaC"
@@ -47569,6 +48214,9 @@ msgstr "Adăugat manual"
msgid "ciReport|New"
msgstr "Nou"
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr "Nicio modificare în Code Quality."
@@ -47599,6 +48247,9 @@ msgstr "Detectarea secretelor"
msgid "ciReport|Security reports failed loading results"
msgstr "Rapoartele de securitate nu au reușit să încarce rezultatele"
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr "Scanare de securitate"
@@ -47614,6 +48265,9 @@ msgstr "Se afișează %{fetchedItems} din %{totalItems} elemente"
msgid "ciReport|Solution"
msgstr "Soluție"
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr "Testarea statică a securității aplicațiilor (SAST) detectează vulnerabilitățile cunoscute în codul dvs. sursă."
@@ -47689,6 +48343,9 @@ msgstr "commit %{commit_id}"
msgid "committed"
msgstr "comis"
+msgid "complete"
+msgstr "complet"
+
msgid "compliance violation has already been recorded"
msgstr "încălcarea conformității a fost deja înregistrată"
@@ -47749,6 +48406,9 @@ msgstr[2] "de zile"
msgid "days"
msgstr "zile"
+msgid "default"
+msgstr "implicit"
+
msgid "default branch"
msgstr "ramura implicită"
@@ -47908,6 +48568,9 @@ msgstr[0] "din %d job"
msgstr[1] "din %d joburi"
msgstr[2] "din %d de joburi"
+msgid "from yourself"
+msgstr "de la dvs."
+
msgid "frontmatter"
msgstr "frontmatter"
@@ -48010,12 +48673,18 @@ msgstr "notă internă"
msgid "invalid milestone state `%{state}`"
msgstr "stare invalidă a obiectivului `%{state}`"
+msgid "invalidated"
+msgstr "invalidat"
+
msgid "is"
msgstr "este"
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr "este deja asociat cu o problemă GitLab. Noua problemă nu va fi asociată."
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr "este un interval de adrese IP invalid"
@@ -48037,6 +48706,9 @@ msgstr "nu este"
msgid "is not a descendant of the Group owning the template"
msgstr "nu este descendent al grupului care deține șablonul"
+msgid "is not a valid URL."
+msgstr "nu este un URL valid."
+
msgid "is not a valid X509 certificate."
msgstr "nu este un certificat X509 valid."
@@ -48061,12 +48733,18 @@ msgstr "nu face parte din grupul care impune Contul gestionat de grup"
msgid "is not in the member group"
msgstr "nu face parte din membrii grupului"
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr "nu este membru al proiectului"
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr "nu este validă. Grupul de iterații trebuie să se potrivească grupului de cadență de iterații."
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr "este numai în citire"
@@ -48226,9 +48904,6 @@ 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|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr "%{linkStart}Configurați acum%{linkEnd} pentru a vă analiza codul sursă pentru vulnerabilitățile de securitate cunoscute."
-
msgid "mrWidget|%{mergeError}."
msgstr "%{mergeError}."
@@ -48379,6 +49054,9 @@ msgstr "Fuziune blocată: în titlu sau în descriere trebuie să se menționeze
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."
@@ -48475,9 +49153,6 @@ msgstr "Reveniți acest merge request într-un nou merge request"
msgid "mrWidget|Revoke approval"
msgstr "Revocați aprobarea"
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr "SAST și Detecția secretelor nu sunt activate."
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr "Setat de %{merge_author} pentru a fi adăugat la merge train atunci când pipeline-ul reușește"
@@ -48541,6 +49216,9 @@ msgstr "trebuie să fie după start"
msgid "must be an email you have verified"
msgstr "trebuie să fie un e-mail pe care l-ați verificat"
+msgid "must be associated with a Group or a Project"
+msgstr "trebuie să fie asociat cu un Grup sau un Proiect"
+
msgid "must be greater than start date"
msgstr "trebuie să fie mai mare decât data de început"
@@ -48553,9 +49231,15 @@ msgstr "trebuie să fie mai mic(ă) decât limita de %{tag_limit} (de) etichete"
msgid "must be set for a project namespace"
msgstr "trebuie să fie setat pentru un spațiu de nume de proiect"
+msgid "must be top-level namespace"
+msgstr "trebuie să fie un spațiu de nume de nivel superior"
+
msgid "must be unique by status and elapsed time within a policy"
msgstr "trebuie să fie unic(ă) prin statut și timp scurs în cadrul unei politici"
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr "trebuie să aibă un repozitoriu"
@@ -48574,9 +49258,6 @@ msgstr "canalul-meu"
msgid "my-topic"
msgstr "subiectul meu"
-msgid "need attention"
-msgstr "necesită atenție"
-
msgid "needs to be between 10 minutes and 1 month"
msgstr "trebuie să fie între 10 minute și 1 lună"
@@ -48625,9 +49306,6 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item} și %{lastItem}"
-msgid "on track"
-msgstr "conform planului"
-
msgid "only %{parent_types} can be parent of Task."
msgstr "numai %{parent_types} poate fi părintele Sarcinii."
@@ -48646,18 +49324,15 @@ msgstr "sau"
msgid "organizations can only be added to root groups"
msgstr "organizațiile pot fi adăugate numai la grupurile rădăcină"
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] "din %d test total"
-msgstr[1] "din %d teste totale"
-msgstr[2] "din %d de teste totale"
-
msgid "packages"
msgstr "pachete"
msgid "pages"
msgstr "pagini"
+msgid "params is empty"
+msgstr "params este gol"
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "părinte"
@@ -48790,9 +49465,6 @@ msgstr "înlăturați data de începere"
msgid "remove weight"
msgstr "înlăturați greutatea"
-msgid "removed"
-msgstr "înlăturat"
-
msgid "removed a %{link_type} link"
msgstr "a înlăturat un link %{link_type}"
@@ -48814,12 +49486,21 @@ msgstr "răspunsul ar trebui să aibă aceeași confidențialitate ca și nota d
msgid "repositories"
msgstr "repozitorii"
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "repository:"
msgstr "repozitoriu:"
msgid "role's base access level does not match the access level of the membership"
msgstr "nivelul de acces de bază al rolului nu corespunde nivelului de acces al calității de membru"
+msgid "running"
+msgstr "rulează"
+
msgid "satisfied"
msgstr "satisfăcut"
@@ -48944,7 +49625,7 @@ msgid "suggestPipeline|We’re adding a GitLab CI configuration file to add a pi
msgstr "Adăugăm un fișier de configurare GitLab CI pentru a adăuga un pipeline la proiect. Ați putea să-l creați manual, dar vă recomandăm să începeți cu un șablon GitLab care funcționează din start."
msgid "supported SSH public key."
-msgstr ""
+msgstr "cheia publică SSH acceptată."
msgid "tag name"
msgstr "numele etichetei"
@@ -48976,6 +49657,9 @@ msgstr "acest document"
msgid "time summary"
msgstr "rezumat de timp"
+msgid "to yourself"
+msgstr "pentru dvs."
+
msgid "today"
msgstr "astăzi"
@@ -49114,6 +49798,9 @@ msgstr "cu expirarea rămasă neschimbată la %{old_expiry}"
msgid "yaml invalid"
msgstr "yaml invalid"
+msgid "you"
+msgstr "dvs."
+
msgid "your GitLab instance"
msgstr "instanța dvs. GitLab"
diff --git a/locale/ru/gitlab.po b/locale/ru/gitlab.po
index a34471e3e34..f6c77617e22 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: 2022-10-10 14:00\n"
+"PO-Revision-Date: 2022-11-13 09:21\n"
msgid " %{start} to %{end}"
msgstr " %{start} по %{end}"
@@ -171,6 +171,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d утверждающий"
@@ -311,13 +318,6 @@ msgstr[1] "%d цели"
msgstr[2] "%d целей"
msgstr[3] "%d целей"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d ошибка"
-msgstr[1] "%d ошибки"
-msgstr[2] "%d ошибок"
-msgstr[3] "%d ошибок"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d ÑкÑпортер"
@@ -325,13 +325,6 @@ msgstr[1] "%d ÑкÑпортера"
msgstr[2] "%d ÑкÑпортеров"
msgstr[3] "%d ÑкÑпортеров"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%d провален"
-msgstr[1] "%d провалено"
-msgstr[2] "%d провалено"
-msgstr[3] "%d провалено"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -346,13 +339,6 @@ msgstr[1] "%d файла"
msgstr[2] "%d файлов"
msgstr[3] "%d файлов"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d иÑправленный результат теÑта"
-msgstr[1] "%d иÑправленных результатов теÑта"
-msgstr[2] "%d иÑправленных результатов теÑта"
-msgstr[3] "%d иÑправленные результаты теÑта"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] "%d ответвление"
@@ -677,6 +663,9 @@ msgstr[1] "%{bold_start}%{count}%{bold_end} открытых запроÑа на
msgstr[2] "%{bold_start}%{count}%{bold_end} открытых запроÑов на ÑлиÑние"
msgstr[3] "%{bold_start}%{count}%{bold_end} открытых запроÑов на ÑлиÑние"
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -737,6 +726,20 @@ msgstr[3] "%{count} контактов"
msgid "%{count} files touched"
msgstr "затронуто %{count} файлов"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "%{count} Ñлемент"
@@ -747,6 +750,13 @@ msgstr[3] "%{count} Ñлементов"
msgid "%{count} items per page"
msgstr "%{count} Ñлементов на Ñтранице"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} more"
msgstr "ещё %{count}"
@@ -773,6 +783,13 @@ msgstr[1] "%{count} учаÑтника"
msgstr[2] "%{count} учаÑтников"
msgstr[3] "%{count} учаÑтников"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} ÑвÑзанный %{pluralized_subject}: %{links}"
@@ -812,9 +829,6 @@ msgstr "%{docs_link_start}Что такое хранилище больших ф
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr "%{docs_link_start}Что такое Ð´Ð²ÑƒÑ…Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð°Ñ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ?%{docs_link_end}"
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr "%{duration}мÑ"
@@ -1025,12 +1039,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} Ñодержал %{resultsString}"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} нашел %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1230,6 +1238,9 @@ msgstr[3] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "%{strong_start}%{branch_count}%{strong_end} Ветка"
@@ -1388,9 +1399,6 @@ msgstr "%{user} Ñоздал обÑуждение: %{issue_link}"
msgid "%{value} is not included in the list"
msgstr "%{value} не ÑодержитÑÑ Ð² ÑпиÑке"
-msgid "%{value} s"
-msgstr "%{value} Ñ"
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} %{time_spent_value} потраченного времени."
@@ -1448,6 +1456,9 @@ msgstr "'%{source}' не ÑвлÑетÑÑ Ð¸Ñточником импорта"
msgid "'%{template_name}' is unknown or invalid"
msgstr "'%{template_name}' неизвеÑтен или указан неверно"
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d закрыт)"
@@ -1488,6 +1499,9 @@ msgstr "(не заполнÑйте, еÑли хотите оÑтавить беÐ
msgid "(max size 15 MB)"
msgstr "(макÑ. размер 15 Мбайт)"
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1827,6 +1841,9 @@ msgstr "У Ð’Ð°Ñ Ð½ÐµÑ‚ права доÑтупа к Ñтой Ñтранице.
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "ПожалуйÑта убедитеÑÑŒ что Ð°Ð´Ñ€ÐµÑ Ñтраницы верный и то что Ñтраница не была перемещена."
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr "Страница Ðе Ðайдена"
@@ -1890,9 +1907,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "Ð”Ð»Ñ Ð¿ÑƒÑтого проекта Ð½ÐµÐ»ÑŒÐ·Ñ Ð²Ñ‹Ð±Ñ€Ð°Ñ‚ÑŒ ветку по умолчанию."
-
msgid "A deleted user"
msgstr "Удаленный пользователь"
@@ -1971,9 +1985,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr "Сайт на проÑтом HTML иÑпользует Netlify Ð´Ð»Ñ CI/CD вмеÑто GitLab, но вÑÑ‘ же пользуетÑÑ Ð²Ñеми другими замечательными возможноÑÑ‚Ñми GitLab"
-msgid "A platform value can be web, mob or app."
-msgstr "Параметр платформы может принимать Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ web, mob или app."
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr "Шаблон проекта Ð´Ð»Ñ Ñ€Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ¸ приложений Salesforce Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ инÑтрументов разработчика Salesforce."
@@ -2181,6 +2192,9 @@ msgstr "ПринÑÑ‚ÑŒ уÑловиÑ"
msgid "Acceptable for use in this project"
msgstr "Разрешены к иÑпользованию в Ñтом проекте"
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr "ДоÑтуп к репозиториÑм Git или API."
@@ -2292,15 +2306,9 @@ msgstr "Токен входÑщей Ñлектронной почты аутен
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr "Токен ÑтатичеÑких объектов идентифицирует ваÑ, когда ÑтатичеÑкие объекты Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ð¸Ñ (например, архивы или большие двоичные объекты (blobs)) обÑлуживаютÑÑ Ð²Ð½ÐµÑˆÐ½Ð¸Ð¼ хранилищем."
-msgid "AccessibilityReport|Learn more"
-msgstr "Узнать больше"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "Сообщение: %{message}"
-msgid "AccessibilityReport|New"
-msgstr "Ðовый"
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr "При Ñканировании доÑтупноÑти обнаружена ошибка типа %{code}"
@@ -2370,9 +2378,6 @@ msgstr "Ðктивный"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr "Ðктивный %{type} (%{token_length})"
-
msgid "Active Sessions"
msgstr "Ðктивные ÑеÑÑии"
@@ -2745,6 +2750,12 @@ msgstr "ДобавлÑетÑÑ %{labels}%{label_text}."
msgid "Adds a Zoom meeting."
msgstr "ДобавлÑет вÑтречу в Zoom."
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2928,6 +2939,24 @@ msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ оÑтановить вÑе заданиÑ.
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr "Ошибка загрузки ÑтатиÑтики. ПожалуйÑта, попробуйте еще раз"
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2964,15 +2993,27 @@ msgstr "Домен Auto DevOps"
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr "ÐаÑтроить Let's Encrypt"
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -3021,6 +3062,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr "Включить баннер, рекомендующий добавить Ñборочную линию"
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr "ИÑпользовать общие Runner'Ñ‹ в новых проектах"
@@ -3066,6 +3110,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr "СохранÑÑ‚ÑŒ поÑледние артефакты Ð´Ð»Ñ Ð²Ñех заданий в поÑледних уÑпешных Ñборочных линиÑÑ…"
@@ -3204,9 +3260,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr "ÐаÑтройки размера и домена Ð´Ð»Ñ ÑтатичеÑких Ñайтов Pages."
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr "ПоÑледние артефакты Ð´Ð»Ñ Ð²Ñех заданий в недавних уÑпешных Ñборочных линиÑÑ… каждого проекта ÑохранÑÑŽÑ‚ÑÑ Ð±ÐµÑÑрочно."
@@ -3231,6 +3296,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3333,6 +3407,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr "ÐдминиÑтраторы"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr "Одобрить"
@@ -3525,8 +3602,8 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr "ВоÑÑтановить доÑтуп Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ðº учетной запиÑи, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ð²ÐµÐ±, Git и API."
-msgid "AdminUsers|Search by name, email or username"
-msgstr "ПоиÑк по имени, Ñлектронной почте или по имени пользователÑ"
+msgid "AdminUsers|Search by name, email, or username"
+msgstr ""
msgid "AdminUsers|Search users"
msgstr "ПоиÑк пользователей"
@@ -3570,8 +3647,8 @@ msgstr "Пользователь не будет получать никаких
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "Ð”Ð»Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ, введите %{projectName}"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "Ð”Ð»Ñ Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ, введите %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr ""
msgid "AdminUsers|Unban user"
msgstr "Разбанить пользователÑ"
@@ -3633,8 +3710,8 @@ msgstr "Без проектов"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
-msgstr "Ð’Ñ‹ ÑобираетеÑÑŒ окончательно удалить Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ %{username}. Это удалит вÑе его обÑуждениÑ, запроÑÑ‹ ÑлиÑÐ½Ð¸Ñ Ð¸ ÑвÑзанные Ñ Ð½Ð¸Ð¼Ð¸ группы. Чтобы избежать потери данных, раÑÑмотрите возможноÑÑ‚ÑŒ иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ %{strongStart}блокировки пользователÑ%{strongEnd}. ПоÑле %{strongStart}ÑƒÐ´Ð°Ð»ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ%{strongEnd}, Ð½ÐµÐ»ÑŒÐ·Ñ Ð±ÑƒÐ´ÐµÑ‚ его воÑÑтановить или отменить удаление."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
+msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
msgstr ""
@@ -3681,6 +3758,9 @@ msgstr "ÐдминиÑтрирование"
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -4191,8 +4271,8 @@ msgstr "У вÑех пользователей должно быть имÑ."
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
-msgstr "Разрешить %{group_name} Ð²Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸Ñать"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr ""
msgid "Allow access to members of the following group"
msgstr "Разрешить доÑтуп учаÑтникам Ñледующей группы"
@@ -4206,6 +4286,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr "Разрешить владельцам групп управлÑÑ‚ÑŒ наÑтройками, ÑвÑзанными Ñ LDAP"
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr "Разрешить пользователÑм без прав админиÑтратора доÑтуп к панели производительноÑти"
@@ -4242,9 +4325,6 @@ msgstr "Разрешить Ñтому ключу выполнÑÑ‚ÑŒ push в да
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr "Разрешить пользователÑм закрыть Ñообщение"
@@ -4491,6 +4571,9 @@ msgstr "Произошла ошибка при получении тегов. П
msgid "An error occurred while fetching terraform reports."
msgstr "Произошла ошибка при получении отчётов Terraform."
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr "Произошла ошибка при получении журнала заданий."
@@ -4678,9 +4761,6 @@ msgstr "Произошла ошибка при запуÑке заданиÑ."
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr "Произошла ошибка при попытке Ñоздать отчёт. ПожалуйÑта, повторите попытку позже."
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4780,9 +4860,6 @@ msgstr "Произошла неизвеÑÑ‚Ð½Ð°Ñ Ð¾ÑˆÐ¸Ð±ÐºÐ°."
msgid "Analytics"
msgstr "Ðналитика"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "Ðнализируйте ваши завиÑимоÑти на предмет извеÑтных уÑзвимоÑтей."
@@ -4885,9 +4962,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr "Ðе удалоÑÑŒ обновить наÑтройки приложениÑ"
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr "Приложение было уÑпешно удалено."
@@ -4906,7 +4980,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4953,6 +5027,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4971,9 +5048,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -5001,6 +5087,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5351,9 +5440,6 @@ msgstr "Вы уверены, что хотите закрыть заблокир
msgid "Are you sure you want to delete %{name}?"
msgstr "Вы точно хотите удалить %{name}?"
-msgid "Are you sure you want to delete these artifacts?"
-msgstr "Ð’Ñ‹ уверены, что хотите удалить Ñти артефакты?"
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5457,8 +5543,8 @@ msgstr "Вы уверены, что хотите попробовать повт
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
-msgstr "Ð’Ñ‹ уверены, что хотите отозвать %{type}? Это дейÑтвие Ð½ÐµÐ»ÑŒÐ·Ñ Ð¾Ñ‚Ð¼ÐµÐ½Ð¸Ñ‚ÑŒ."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr "Ð’Ñ‹ уверены, что хотите отозвать Ñтот перÑональный токен доÑтупа? Это дейÑтвие не может быть отменено."
@@ -5508,6 +5594,30 @@ msgstr "Ðртефакт был уÑпешно удален."
msgid "Artifacts"
msgstr "Ðртефакты"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr "ПоÑкольку мы продолжаем Ñоздавать больше возможноÑтей Ð´Ð»Ñ SAST, мы будем рады вашему отзыву о функции наÑтройки SAST в %{linkStart}Ñтом обÑуждении%{linkEnd}."
@@ -5559,9 +5669,6 @@ msgstr "Ðазначьте пользовательÑкий цвет, напри
msgid "Assign labels"
msgstr "Ðазначить метки"
-msgid "Assign milestone"
-msgstr "Ðазначить Ñтап"
-
msgid "Assign myself"
msgstr ""
@@ -5961,9 +6068,6 @@ msgstr "ÐвтоматичеÑÐºÐ°Ñ Ð¾Ñтановка уÑпешно отмеÐ
msgid "Auto-cancel redundant pipelines"
msgstr "ÐвтоматичеÑÐºÐ°Ñ Ð¾Ñ‚Ð¼ÐµÐ½Ð° избыточных Ñборочных линий"
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr "%{auto_devops_start}Ðвтоматизируйте Ñоздание, теÑтирование и развертывание%{auto_devops_end} Ñвоих приложений на оÑнове наÑтроек непрерывной интеграции и доÑтавки. %{quickstart_start}С чего мне начать?%{quickstart_end}"
@@ -6327,6 +6431,12 @@ msgstr "Будьте оÑторожны. Изменение пути проекÑ
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "Будьте оÑторожны. Переименование Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ð¸Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ð° может вызвать нежелательные побочные Ñффекты."
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr "Перед включением данной интеграции Ñоздайте веб-обработчик Ð´Ð»Ñ ÐºÐ¾Ð¼Ð½Ð°Ñ‚Ñ‹ Google Chat, в которой вы хотите получать ÑƒÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ Ð¾Ñ‚ Ñтого проекта. %{docs_link}"
@@ -7063,6 +7173,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -7072,6 +7185,9 @@ msgstr "Ветвь уже ÑущеÑтвует"
msgid "Branch name"
msgstr "Ð˜Ð¼Ñ Ð²ÐµÑ‚Ð²Ð¸"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr "Ветка не загружена - %{branchId}"
@@ -7093,6 +7209,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -7111,6 +7230,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -7120,6 +7242,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -7138,9 +7263,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -7159,12 +7290,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7324,6 +7464,9 @@ msgstr "Широковещательное Ñообщение уÑпешно оÐ
msgid "Broadcast Messages"
msgstr "Широковещательные СообщениÑ"
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "ПроÑмотр каталога"
@@ -7333,9 +7476,6 @@ msgstr "ПроÑмотр файла"
msgid "Browse Files"
msgstr "ПроÑмотр файлов"
-msgid "Browse artifacts"
-msgstr "ПроÑмотр артефактов"
-
msgid "Browse files"
msgstr "ПроÑмотр файлов"
@@ -7381,9 +7521,6 @@ msgstr "Фильтр по иÑходной группе"
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr "Из иÑходной группы"
-
msgid "BulkImport|Group import history"
msgstr "ИÑÑ‚Ð¾Ñ€Ð¸Ñ Ð¸Ð¼Ð¿Ð¾Ñ€Ñ‚Ð° групп"
@@ -7414,6 +7551,9 @@ msgstr "Ð˜Ð¼Ñ ÑƒÐ¶Ðµ ÑущеÑтвует."
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7429,6 +7569,9 @@ msgstr "Без родителÑ"
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7453,9 +7596,6 @@ msgstr "ИÑÑ…Ð¾Ð´Ð½Ð°Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð°"
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr "В новую группу"
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7871,9 +8011,6 @@ msgstr "Отмена предварительного проÑмотра"
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr "Ðет возможноÑти объединить автоматичеÑки"
@@ -7889,6 +8026,9 @@ msgstr "Ðевозможно Ñоздать Ñообщение о нарушен
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr "Ðе удаетÑÑ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ÑŒ %{profile_name}, упомÑнутый в политике безопаÑноÑти"
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr "Ðевозможно проводить одновременно неÑколько импортов из Jira"
@@ -8632,6 +8772,9 @@ msgstr "Ключ"
msgid "CiVariables|Masked"
msgstr "МаÑкируемаÑ"
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr "ЗащищеннаÑ"
@@ -9951,10 +10094,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr "Комментарий/Ответ (цитирование выделенного текÑта)"
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -10138,6 +10287,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10939,10 +11091,10 @@ msgstr "УчаÑтие"
msgid "Contribution Analytics"
msgstr "Ðналитика вкладов"
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10975,6 +11127,15 @@ msgstr "Ðет запроÑов на ÑлиÑние в выбранном пер
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -11023,9 +11184,6 @@ msgstr "Копировать %{name}"
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr "Копировать ID"
@@ -11110,9 +11268,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr "Скопировать Ð¸Ð¼Ñ Ð¸Ñходной ветки"
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -11275,9 +11430,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11497,9 +11649,6 @@ msgstr "Создать новый файл или каталог"
msgid "Create new label"
msgstr "Создать новую метку"
-msgid "Create new project"
-msgstr "Создать новый проект"
-
msgid "Create new..."
msgstr ""
@@ -11767,9 +11916,6 @@ msgstr "Цель ÑоздаетÑÑ"
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr "Дата ÑозданиÑ"
-
msgid "Creator"
msgstr ""
@@ -11785,7 +11931,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11887,9 +12033,6 @@ msgstr "Ð¢ÐµÐºÑƒÑ‰Ð°Ñ Ð’ÐµÑ‚ÐºÐ°"
msgid "Current Project"
msgstr "Текущий проект"
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -12218,6 +12361,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -12245,6 +12391,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -12302,6 +12451,9 @@ msgstr "Личные"
msgid "DashboardProjects|Trending"
msgstr "ПопулÑрные"
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr "%{firstProject} и %{secondProject}"
@@ -12536,6 +12688,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12756,6 +12911,9 @@ msgstr ""
msgid "Data type"
msgstr "Тип данных"
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr "Ошибка Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð±Ð°Ð·Ñ‹ данных"
@@ -12843,6 +13001,9 @@ msgstr "Ср"
msgid "Days"
msgstr "Дней"
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr "Дней до ÑлиÑниÑ"
@@ -12876,6 +13037,9 @@ msgstr "Ошибка проверки размера раÑпакованногÐ
msgid "Decrease"
msgstr "Уменьшить"
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr "Файл конфигурации CI/CD по умолчанию"
@@ -12987,6 +13151,9 @@ msgstr "Удалить"
msgid "Delete %{issuableType}"
msgstr "Удалить %{issuableType}"
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr "Удалить %{name}"
@@ -13008,9 +13175,6 @@ msgstr "Удалить Поток ценноÑти"
msgid "Delete account"
msgstr "Удалить аккаунт"
-msgid "Delete artifacts"
-msgstr "Удалить артефакты"
-
msgid "Delete asset"
msgstr ""
@@ -13077,7 +13241,7 @@ msgstr ""
msgid "Delete row"
msgstr "Удалить Ñтроку"
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13566,6 +13730,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr "ИÑтекает"
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13653,6 +13820,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13997,6 +14179,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -14239,6 +14424,12 @@ msgstr[3] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -14254,6 +14445,9 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
@@ -14261,6 +14455,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Что-то пошло не так при извлечении отличий."
@@ -14868,6 +15065,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr "Редактирование"
@@ -15198,23 +15401,41 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
-msgstr "%{stepStart}Шаг 1%{stepEnd}. УбедитеÑÑŒ, что Kubernetes наÑтроен и имеет базовый домен Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ %{linkStart}клаÑтера%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
-msgstr "%{stepStart}Шаг 2%{stepEnd}. Скопируйте Ñледующий Ñниппет:"
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
-msgstr "%{stepStart}Шаг 3%{stepEnd}. Добавьте его в файл %{linkStart}gitlab-ci.yml%{linkEnd} проекта."
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|Close"
-msgstr "Закрыть"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr ""
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr ""
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
-msgstr "Скопировать текÑÑ‚ Ñниппета"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
+msgstr ""
msgid "Enabled"
msgstr "Включено"
@@ -15441,6 +15662,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr "Коммит"
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15621,12 +15845,12 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgstr ""
+
msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr "Ð’Ñ‹ дейÑтвительно хотите удалить %{bStart}%{targetIssueTitle}%{bEnd} из %{bStart}%{parentEpicTitle}%{bEnd}?"
-msgid "Epics|Assign Epic"
-msgstr ""
-
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr ""
@@ -15639,18 +15863,9 @@ msgstr "Удалить цель"
msgid "Epics|Remove issue"
msgstr "Удалить обÑуждение"
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr "Показать еще"
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr "Что-то пошло не так при назначении обÑÑƒÐ¶Ð´ÐµÐ½Ð¸Ñ Ð² цель."
-
msgid "Epics|Something went wrong while creating child epics."
msgstr "Что-то пошло не так при Ñоздании дочерней цели."
@@ -15663,18 +15878,12 @@ msgstr "Что-то пошло не так при получении дочерÐ
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr "Что-то пошло не так при получении целей группы."
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr "Что-то пошло не так при заказе товара."
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr "Что-то пошло не так при удалении обÑÑƒÐ¶Ð´ÐµÐ½Ð¸Ñ Ð¸Ð· цели."
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15804,9 +16013,6 @@ msgstr "Произошла ошибка при Ñохранении ответÑ
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr "Произошла ошибка при обновлении ÑтатуÑа обÑуждениÑ"
@@ -15870,9 +16076,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr "Ошибка при загрузке файла: %{stripped}"
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -16113,6 +16316,57 @@ msgstr "СобытиÑ"
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -16234,6 +16488,9 @@ msgstr "ИÑÐºÐ»ÑŽÑ‡Ð°Ñ ÐºÐ¾Ð¼Ð¼Ð¸Ñ‚Ñ‹-ÑлиÑниÑ. Ограничено дÐ
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -16291,9 +16548,15 @@ msgstr "Развернуть боковую панель"
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16520,6 +16783,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16569,9 +16835,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16767,9 +17030,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -17029,6 +17289,9 @@ msgstr "Фев."
msgid "February"
msgstr "Февраль"
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17134,9 +17397,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr "Фильтр по названию Ñтапа"
@@ -17344,6 +17604,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr "Забыли пароль?"
@@ -18185,9 +18448,6 @@ msgstr "вторичный"
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -18314,6 +18574,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18365,6 +18631,9 @@ 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 ""
@@ -18413,9 +18682,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18971,9 +19237,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr "Gravatar"
@@ -18983,6 +19246,9 @@ msgstr "Gravatar включён"
msgid "Group"
msgstr "Группа"
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19745,12 +20011,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr "Загрузка групп"
-msgid "GroupsTree|No groups matched your search"
-msgstr "ПоиÑк групп не дал результатов"
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr "ПоиÑк групп или проектов не дал результатов"
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19820,6 +20080,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr "РуководÑтво"
@@ -20002,9 +20265,6 @@ msgstr "Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ работоÑпоÑобноÑти может б
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20463,7 +20723,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20550,12 +20816,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -22315,6 +22575,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -22333,9 +22596,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr "ПриглаÑить \"%{trimmed}\" по Ñлектронной почте"
-
msgid "Invite Members"
msgstr "ПриглаÑить УчаÑтников"
@@ -22393,7 +22653,7 @@ msgstr "Приглашайте коллег"
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr "Мы заметили, что вы никого не приглаÑили в Ñту группу. ПриглаÑите коллег, чтобы вы могли учаÑтвовать в обÑуждениÑÑ…, вмеÑте работать над запроÑами на ÑлиÑние и делитьÑÑ Ð·Ð½Ð°Ð½Ð¸Ñми."
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22475,19 +22735,16 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr "Чтобы назначить обÑÑƒÐ¶Ð´ÐµÐ½Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð¼Ñƒ учаÑтнику команды, нужен проект Ð´Ð»Ñ Ñтих обÑуждений. %{linkStart}Создайте проект.%{linkEnd}"
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22625,12 +22882,18 @@ msgstr "ИÑпользует лицензионное меÑто:"
msgid "Is using seat"
msgstr "ИÑпользует меÑто"
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22652,6 +22915,18 @@ msgstr "перемещено"
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr "ОбÑуждение"
@@ -22877,6 +23152,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -23171,6 +23461,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23501,6 +23794,9 @@ msgstr ""
msgid "Job|Download"
msgstr "Скачать"
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23540,9 +23836,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23923,9 +24225,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -24079,6 +24378,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24229,9 +24537,6 @@ msgstr "Покинуть проект"
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24490,6 +24795,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24760,9 +25071,6 @@ msgstr ""
msgid "Logs"
msgstr "Журналы"
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24775,6 +25083,9 @@ msgstr "MD5"
msgid "MERGED"
msgstr "СЛИТО"
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24811,7 +25122,13 @@ msgstr "Показать только изменениÑ"
msgid "MRDiff|Show full file"
msgstr "Показать веÑÑŒ файл"
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24826,9 +25143,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr "Режим обÑлуживаниÑ"
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24838,9 +25161,6 @@ msgstr "ВнеÑите и проÑмотрите Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² брауÐ
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr "Сделайте вÑех в Ñвоей команде более производительными незавиÑимо от меÑтоположениÑ. GitLab Geo Ñоздаёт доÑтупные только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ Ð·ÐµÑ€ÐºÐ°Ð»Ð° вашего ÑкземплÑра GitLab так, чтобы Ñократить времÑ, необходимое Ð´Ð»Ñ ÐºÐ»Ð¾Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸ ÑÐºÐ°Ñ‡Ð¸Ð²Ð°Ð½Ð¸Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ñ… репозиториев."
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24850,7 +25170,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24907,6 +25227,9 @@ msgstr ""
msgid "Manifest"
msgstr "МанифеÑÑ‚"
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr "Импорт файла манифеÑта"
@@ -24931,6 +25254,9 @@ msgstr "Мар."
msgid "March"
msgstr "Март"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr "Отметить как выполнено"
@@ -24982,6 +25308,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24994,6 +25323,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25626,6 +25958,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr "ЗапроÑÑ‹ на ÑлиÑние- Ñто меÑто, где можно предлагать Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð²Ð½Ð¾Ñимые в проект, и обÑуждать Ñти Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ Ð´Ñ€ÑƒÐ³Ð¸Ð¼Ð¸"
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25851,6 +26186,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr "Метрика была уÑпешно добавлена."
@@ -26246,6 +26584,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26405,6 +26746,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26477,6 +26821,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26663,6 +27010,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -27127,6 +27477,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -27256,9 +27609,6 @@ msgstr "Ðет итераций Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ"
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr "Ðет заданий Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ"
-
msgid "No label"
msgstr ""
@@ -27286,9 +27636,6 @@ msgstr "Ðет результатов"
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -27304,9 +27651,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr "Ðет других меток Ñ Ñ‚Ð°ÐºÐ¸Ð¼ наименованием или опиÑанием"
@@ -27542,7 +27886,7 @@ msgstr "Свернуть ответы"
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27885,6 +28229,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27894,6 +28241,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27915,6 +28265,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -28008,9 +28361,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -28035,9 +28385,6 @@ msgstr "Окт."
msgid "October"
msgstr "ОктÑбрь"
-msgid "OfSearchInADropdown|Filter"
-msgstr "Фильтр"
-
msgid "Off"
msgstr ""
@@ -28273,12 +28620,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28324,12 +28665,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28351,12 +28686,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28399,15 +28728,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28438,12 +28758,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28462,9 +28776,6 @@ msgstr "ПоÑле импорта, репозитории могут зеркаÐ
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] "Еще один Ñлемент"
@@ -28640,9 +28951,6 @@ msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð½Ðµ удалаÑÑŒ. Проверьте журналы
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr "Ð’Ñ€ÐµÐ¼Ñ Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ð¸ иÑтекло. Проверьте журналы пода %{pod_name} Ð´Ð»Ñ Ð±Ð¾Ð»ÐµÐµ подробной информации."
-
msgid "Operations"
msgstr ""
@@ -29013,12 +29321,21 @@ msgstr "Удалить пакет"
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -29064,6 +29381,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr "ЕÑли вы еще не Ñделали Ñтого, вам нужно будет добавить нижераÑположенное в Ñвой файл %{codeStart}.pypirc%{codeEnd}."
@@ -29212,6 +29535,9 @@ msgstr "Извините, ваш фильтр иÑключил вÑе резул
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29597,12 +29923,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29651,7 +29971,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29870,6 +30190,9 @@ msgstr "Ðктивно"
msgid "PipelineSchedules|All"
msgstr "Ð’Ñе"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29885,6 +30208,9 @@ msgstr "Ðеактивно"
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr "Следующий запуÑк"
@@ -29897,12 +30223,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "ПредоÑтавьте краткое опиÑание Ñтой Ñборочной линии"
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr "Стать владельцем"
@@ -29912,9 +30244,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr "Цель"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr "Переменные"
@@ -30674,9 +31012,6 @@ msgstr "ПожалуйÑта, выберите проект Jira"
msgid "Please select a country"
msgstr "ПожалуйÑта, выберите Ñтрану"
-msgid "Please select a file"
-msgstr "ПожалуйÑта, выберите файл"
-
msgid "Please select a group"
msgstr ""
@@ -30785,6 +31120,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr "ПредпочтениÑ"
@@ -30926,6 +31324,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -31019,12 +31420,18 @@ msgstr ""
msgid "Proceed"
msgstr "Продолжить"
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr "ПродуктивноÑÑ‚ÑŒ"
@@ -31601,6 +32008,9 @@ msgstr "Ð˜Ð¼Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ð°"
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31613,6 +32023,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr "URL проекта"
@@ -31895,12 +32308,18 @@ msgstr "%{link_start}Что такое шаблоны опиÑаниÑ?%{link_en
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr "Дополнительные параметры, влиÑющие на то, как и когда проиÑходит ÑлиÑние,"
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31913,12 +32332,18 @@ msgstr "Ð’Ñегда показывать большой палец вверх Ð
msgid "ProjectSettings|Analytics"
msgstr "Ðналитика"
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr "Значки"
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr "Сборка, теÑтирование и разворачивание изменений."
@@ -31940,6 +32365,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr "ÐаÑтройка реÑурÑов проекта и мониторинг их здоровьÑ."
@@ -32039,6 +32467,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr "ВнутреннÑÑ"
@@ -32177,6 +32608,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr "Задайте поведение по умолчанию в запроÑах на ÑлиÑние. Изменение Ñтого параметра также затронет ÑущеÑтвующие запроÑÑ‹ на ÑлиÑние."
@@ -32207,6 +32641,9 @@ msgstr "Сжатие выполнÑетÑÑ Ð²Ñегда. Флажок отобÑ
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr "Сжатие никогда не выполнÑетÑÑ, а флажок Ñкрыт."
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr "Отправка изменений Ð´Ð»Ñ ÑлиÑÐ½Ð¸Ñ Ð² upstream."
@@ -32258,6 +32695,9 @@ msgstr "Пользователи могут копировать репозитÐ
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr "Пользователи могут запрашивать доÑтуп"
@@ -32897,6 +33337,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32933,15 +33376,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr "Одобрение владельцем кода"
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr "Защитить"
@@ -32957,12 +33412,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr "ТребуетÑÑ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ðµ от владельцев кода:"
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr "Ðа данный момент нет защищённых веток, защитите ветку Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ формы Ñверху."
@@ -33272,6 +33736,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33404,12 +33871,6 @@ msgstr "Подробнее"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33503,9 +33964,6 @@ msgstr "Уменьшить облаÑÑ‚ÑŒ видимоÑти проекта"
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr "Уменьшить облаÑÑ‚ÑŒ видимоÑти Ñтого проекта?"
-
msgid "Reference"
msgstr ""
@@ -33673,6 +34131,9 @@ msgstr[3] "Релизов"
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33682,6 +34143,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -34138,6 +34602,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -34154,13 +34621,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -34192,18 +34652,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34218,12 +34672,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Failure"
-msgstr "Отказ"
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -34266,21 +34714,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34296,9 +34735,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34678,6 +35114,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr "Ответ"
@@ -34911,6 +35350,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr "ЗапуÑтить очиÑтку"
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34951,6 +35393,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34983,7 +35428,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -35194,6 +35639,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -35324,9 +35772,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -35375,6 +35829,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -35412,6 +35869,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -35451,12 +35911,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35511,16 +35965,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr "SAML Ð´Ð»Ñ %{group_name}"
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35628,10 +36088,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35652,9 +36112,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35664,9 +36130,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35817,9 +36289,6 @@ msgstr "ПоиÑк LDAP группы"
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr "ПоиÑк пользователÑ"
-
msgid "Search for an emoji"
msgstr ""
@@ -36248,10 +36717,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -36371,6 +36843,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36473,10 +36948,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36566,7 +37041,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36584,6 +37059,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36602,12 +37080,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36629,6 +37116,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36758,6 +37248,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36815,6 +37308,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36932,9 +37428,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36947,6 +37449,9 @@ msgstr "ПоÑмотреть метрики"
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr "ПоÑмотреть затрагиваемые проекты в панели админиÑтратора GitLab"
@@ -37010,9 +37515,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr "Выбор временной зоны"
-
msgid "Select all"
msgstr "Выбрать вÑе"
@@ -37151,10 +37653,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -37166,28 +37668,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
-msgstr "Включение и отключение автомониторинга ÑкземплÑра."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
+msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
-msgstr "Отключить автомониторинг?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
+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|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
+msgstr ""
-msgid "SelfMonitoring|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37406,9 +37908,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37560,9 +38059,6 @@ msgstr "ÐаÑтройки"
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37819,10 +38315,7 @@ msgstr ""
msgid "Showing all issues"
msgstr "Показаны вÑе обÑуждениÑ"
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37876,8 +38369,8 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
-msgstr "Ð’Ñтупить в \"%{group_name}\""
+msgid "Sign in to %{group_name}"
+msgstr ""
msgid "Sign in to GitLab"
msgstr ""
@@ -37891,7 +38384,7 @@ msgstr "Войти Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ 2FA"
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -38014,9 +38507,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr "Лимит размера на репозиторий (Мбайт)"
-msgid "Skip outdated deployment jobs"
-msgstr "ПропуÑтить уÑтаревшие Ð·Ð°Ð´Ð°Ð½Ð¸Ñ Ñ€Ð°Ð·Ð²Ñ‘Ñ€Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ"
-
msgid "Skipped"
msgstr ""
@@ -38239,6 +38729,9 @@ msgstr "Кто-то отредактировал Ñтот Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° Ñл
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38350,9 +38843,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38926,9 +39416,6 @@ msgstr "СтатуÑ:"
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38941,9 +39428,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38965,9 +39449,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39487,9 +39968,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39749,6 +40236,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "Переключить ветка/тег"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39839,6 +40329,9 @@ msgstr ""
msgid "Tag"
msgstr "Тег"
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr "СпиÑок тегов:"
@@ -39923,6 +40416,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39944,15 +40440,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr "При желании, добавьте Ñообщение к метке. ЕÑли оÑтавить его пуÑтым, будет Ñоздана %{link_start}легковеÑÐ½Ð°Ñ Ð¼ÐµÑ‚ÐºÐ°.%{link_end}"
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr "По желанию Ñоздайте публичный Релиз вашего проекта на оÑнове Ñтого тега. ÐŸÑ€Ð¸Ð¼ÐµÑ‡Ð°Ð½Ð¸Ñ Ðº релизу отображаютÑÑ Ð½Ð° Ñтранице %{releases_page_link_start}Релизов%{link_end}. %{docs_link_start}Ð”Ð¾Ð¿Ð¾Ð»Ð½Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ%{link_end}"
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr "Заметки к релизу"
-
msgid "TagsPage|Repository has no tags yet."
msgstr "Репозитарий не Ñодержит тегов."
@@ -39974,9 +40464,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr "ИÑпользуйте команду git tag, чтобы добавить новый тег:"
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "Ðапишите заметки к релизу или перетащите Ñюда файлы…"
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39995,6 +40482,9 @@ msgstr "защищенный"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr "Ветка"
@@ -40106,20 +40596,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -40143,12 +40619,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -40236,12 +40706,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40706,6 +41170,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "Импорт будет отключен поÑле %{timeout}. Ð”Ð»Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ð¸ÐµÐ², которые импортируютÑÑ Ð·Ð° большее времÑ, иÑпользуйте комбинацию команд clone/push."
@@ -40901,9 +41368,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40934,7 +41398,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40991,9 +41455,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -41345,9 +41806,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -41381,6 +41839,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41549,9 +42010,6 @@ msgstr "Эта цель уже имеет макÑимально возможнÐ
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41612,6 +42070,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41828,13 +42289,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41963,9 +42427,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41984,6 +42445,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42358,9 +42822,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42466,6 +42927,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42532,9 +42996,33 @@ msgstr "СегоднÑ"
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42556,18 +43044,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42580,6 +43089,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42730,9 +43257,6 @@ msgstr "Общий вклад"
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr "Общий размер артефактов: %{total_size}"
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -43055,6 +43579,12 @@ msgstr "Ð”Ð²ÑƒÑ…Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð°Ñ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr "Ð”Ð²ÑƒÑ…Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð°Ñ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð¾Ñ‚ÐºÐ»ÑŽÑ‡ÐµÐ½Ð° Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ¹ учётной запиÑи GitLab."
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr "Ð”Ð²ÑƒÑ…Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð°Ñ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ ÑƒÑпешно отключена!"
@@ -43559,6 +44089,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr "%{help_link_start}Общие Runner'Ñ‹%{help_link_end} отключены, поÑтому нет наÑтроенных ограничений в иÑпользовании Ñборочных линий"
@@ -43661,6 +44197,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr "Пакеты"
@@ -43691,6 +44230,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr "Репозиторий"
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr "МеÑта"
@@ -44747,9 +45289,6 @@ msgstr ""
msgid "View full dashboard"
msgstr "Показать вÑÑŽ панель"
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -45213,6 +45752,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -45231,6 +45773,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -45366,7 +45911,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "Мы хотим быть уверены, что Ñто вы, пожалуйÑта, подтвердите, что вы не робот."
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45408,6 +45953,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -45423,12 +45971,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45468,6 +46028,9 @@ msgstr "Веб-обработчики"
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45582,6 +46145,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45609,9 +46178,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45624,7 +46190,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45636,12 +46202,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45720,6 +46295,9 @@ msgstr "Что такое Ñжатие?"
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45729,7 +46307,7 @@ msgstr ""
msgid "What's new"
msgstr "Что нового?"
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -46049,6 +46627,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -46101,9 +46685,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -46134,10 +46733,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -46149,6 +46751,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -46170,6 +46775,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -46188,6 +46796,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -46285,6 +46896,9 @@ msgstr "Ð’Ñ‹ пытаетеÑÑŒ удалить файл, который был Ñ
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr "Ð’Ñ‹ пытаетеÑÑŒ обновить файл, который изменилÑÑ Ñ Ñ‚ÐµÑ… пор, как вы начали его редактировать."
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -46321,6 +46935,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46366,9 +46986,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -46472,6 +47089,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46544,7 +47164,7 @@ msgstr "Ð’Ñ‹ можете протеÑтировать Ñвой файл .gitlab
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46568,6 +47188,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr "Ð’Ñ‹ не можете выдать ÑÐµÐ±Ñ Ð·Ð° внутреннего пользователÑ"
@@ -46713,6 +47336,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46776,7 +47402,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46944,9 +47570,6 @@ msgstr "YouTube"
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -47058,6 +47681,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr "Ваш аккаунт иÑпользует Ñпециальные учетные данные Ð´Ð»Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ñ‹ \"%{group_name}\" и может быть обновлен только через SSO."
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -47180,16 +47806,13 @@ msgstr "Ваше Ñообщение здеÑÑŒ"
msgid "Your name"
msgstr "Ваше имÑ"
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47280,6 +47903,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47349,9 +47975,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -47365,9 +47988,6 @@ msgstr[3] "примерно %d чаÑов"
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -47429,6 +48049,12 @@ msgstr ""
msgid "assign yourself"
msgstr "назначить ÑебÑ"
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -47438,9 +48064,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr "под угрозой"
-
msgid "attach a new file"
msgstr ""
@@ -47523,6 +48146,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47764,12 +48393,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr "Скачать патч Ð´Ð»Ñ Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ"
msgid "ciReport|Download the patch to apply it manually"
msgstr "Скачайте патч, чтобы применить его вручную"
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47846,6 +48490,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47876,6 +48523,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47891,6 +48541,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47967,6 +48620,9 @@ msgstr "коммит %{commit_id}"
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -48028,6 +48684,9 @@ msgstr[3] "дней"
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -48190,6 +48849,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -48294,12 +48956,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr "неверное ÑоÑтоÑние Ñтапа `%{state}`"
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr "ÑвлÑетÑÑ"
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr "диапазон недопуÑтимых IP адреÑов"
@@ -48321,6 +48989,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -48345,12 +49016,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -48513,9 +49190,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48668,6 +49342,9 @@ 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 ""
@@ -48764,9 +49441,6 @@ msgstr "Откатить Ñтот Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑлиÑние в новом
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48830,6 +49504,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48842,9 +49519,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48863,9 +49546,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr "требуют вниманиÑ"
-
msgid "needs to be between 10 minutes and 1 month"
msgstr "должно быть от 10 минут до 1 меÑÑца"
@@ -48914,9 +49594,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}, и %{lastItem}"
-msgid "on track"
-msgstr "по плану"
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48935,19 +49612,15 @@ msgstr "или"
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "владелец"
@@ -49083,9 +49756,6 @@ msgstr ""
msgid "remove weight"
msgstr "удалить приоритет"
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -49108,12 +49778,22 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "repository:"
msgstr "репозиторий:"
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -49271,6 +49951,9 @@ msgstr "Ñтот документ"
msgid "time summary"
msgstr "Ñводка по времени"
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -49411,6 +50094,9 @@ msgstr "Ñ Ð¾ÑтавшимÑÑ Ð¸Ñтечением, неизменным на
msgid "yaml invalid"
msgstr "неверный YAML"
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/si_LK/gitlab.po b/locale/si_LK/gitlab.po
index 37539f6c29a..56b02abbb11 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: 2022-10-10 14:05\n"
+"PO-Revision-Date: 2022-11-13 09:24\n"
msgid " %{start} to %{end}"
msgstr " %{start} සිට %{end}"
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "අනුමතකරුවන් %d"
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "දà·à·‚ %d"
-msgstr[1] "දà·à·‚ %d"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "නිර්යà·à¶­à¶šà¶»à·”වන් %d"
msgstr[1] "නිර්යà·à¶­à¶šà¶»à·”වන් %d"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%d අසමත් විය"
-msgstr[1] "%d අසමත් විය"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] "ගොනු %d"
msgstr[1] "ගොනු %d"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] "විවෘත සංයුක්ත ඉල්ලීම් %{bold_start}%{count}%{bold_end}"
msgstr[1] "විවෘත සංයුක්ත ඉල්ලීම් %{bold_start}%{count}%{bold_end}"
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] "සබඳත෠%{count}"
msgid "%{count} files touched"
msgstr "ගොනු %{count}ක් ස්පර්à·à¶ºà·’"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "අථක %{count}"
@@ -575,6 +578,11 @@ msgstr[1] "අථක %{count}"
msgid "%{count} items per page"
msgstr "පිටුවකට අංග %{count}"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr "තවත් %{count}"
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] "සහභà·à¶œà·“න් %{count}"
msgstr[1] "සහභà·à¶œà·“න් %{count}"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr "%{docs_link_start}විà·à·à¶½ ගොනු ආචයනය යනු
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr "%{docs_link_start}ද්වි à·ƒà·à¶°à¶š සත්â€à¶ºà·à¶´à¶±à¶º යනු කුමක්ද?%{docs_link_end}"
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr "මිලි ත. %{duration}"
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr "%{name} (කà·à¶»à·Šà¶ºà¶¶à·„ුලයි)"
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} හමුවිය %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "à·à·à¶›à· %{strong_start}%{branch_count}%{strong_end}"
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d වස෠ඇත)"
@@ -1280,6 +1287,9 @@ msgstr "(වෙනස් නොකළ යුතු නම් හිස්ව ත
msgid "(max size 15 MB)"
msgstr "(උ. ප්â€à¶»à¶¸à·à¶«à¶º මෙ.බ. 15)"
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr "(වෛකල්පිතයි)"
@@ -1565,6 +1575,9 @@ msgstr "මෙම පිටුවට ප්â€à¶»à·€à·šà· වීමට ඔබà¶
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "ලිපිනය නිවà·à¶»à¶¯à·’ බවත් පිටුව ගෙනගොස් නà·à¶­à·’ බවත් සහතික කර ගන්න."
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr "පිටුව හමු නොවිණි"
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "හිස් ව්â€à¶ºà·à¶´à·˜à¶­à·’යක් සඳහ෠පෙරනිමි à·à·à¶›à·à·€à¶šà·Š තේරීමට නොහà·à¶šà·’ය."
-
msgid "A deleted user"
msgstr "මකà·à¶¯à·à¶¸à·– පරිà·à·“ලකයෙකි"
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr "නියම පිළිගන්න"
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr "තව දà·à¶±à¶œà¶±à·Šà¶±"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "පණිවිඩය: %{message}"
-msgid "AccessibilityReport|New"
-msgstr "නව"
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr "සක්â€à¶»à·’යයි"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr "සක්â€à¶»à·’ය %{type} (%{token_length})"
-
msgid "Active Sessions"
msgstr "සක්â€à¶»à·’ය à·€à·à¶»"
@@ -2483,6 +2484,12 @@ msgstr "%{labels} %{label_text} එක් කරයි."
msgid "Adds a Zoom meeting."
msgstr "සූම් රà·à·ƒà·Šà·€à·“මක් එක් කරයි"
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr "CI/CD සීමà·"
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr "ලෙට්'ස් එන්ක්â€à¶»à·’ප්ට් වින්â€à¶ºà·à·ƒà¶œà¶­ කරන්න"
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr "අක්â€à¶»à·’ය ව්â€à¶ºà·à¶´à·˜à¶­à·’ මකන්න"
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr "අක්â€à¶»à·’ය ව්â€à¶ºà·à¶´à·˜à¶­à·’ මකà·à¶¯à·à¶¸à·“à
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr "à·ƒà·à¶šà·ƒà·”ම් 0 ට වඩ෠වà·à¶©à·’ විය යුතà·
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr "පරිපà·à¶½à¶š"
msgid "AdminUsers|Admins"
msgstr "පරිපà·à¶½à¶šà¶ºà·’න්"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr "අනුමත"
@@ -3263,7 +3336,7 @@ msgstr "යළි à·ƒà·à¶šà·ƒà·“මේ සබà·à¶³à·’ය උත්පà·à¶¯à¶±
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,8 +3381,8 @@ msgstr "පරිà·à·“ලකයà·à¶§ කිසිදු දà·à¶±à·”ම්දà
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "තහවුරු කිරීමට, %{projectName} ලියන්න"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "තහවුරු කිරීමට, %{username} ලියන්න"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr ""
msgid "AdminUsers|Unban user"
msgstr ""
@@ -3371,7 +3444,7 @@ msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’ නà·à¶­à·’à·€"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr "පරිපà·à¶½à¶±à¶º"
msgid "Administrators"
msgstr "පරිපà·à¶½à¶šà¶ºà·’න්"
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr "සියළුම පරිà·à·“ලකයින්ට නමක් ත
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr "නොදන්න෠දà·à·‚යක් සිදුවිය."
msgid "Analytics"
msgstr "විà·à·Šà¶½à·šà·‚ණ"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr "යෙදුම් à·ƒà·à¶šà·ƒà·”ම් à·ƒà·à¶»à·Šà¶®à¶šà·€ සුර
msgid "Application settings update failed"
msgstr "යෙදුමේ à·ƒà·à¶šà·ƒà·”ම් යà·à·€à¶­à·Šà¶šà·à¶½à¶ºà¶§ අසමත්!"
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr "යෙදුම අස්ථà·à¶´à·’තයි නමුත් විනà·à·à¶ºà¶§ අසමත් විය: %{error_message}"
-
msgid "Application was successfully destroyed."
msgstr "යෙදුම à·ƒà·à¶»à·Šà¶®à¶šà·€ විනà·à· විය."
@@ -4642,7 +4712,7 @@ msgstr "ග්â€à¶»à·à·†à·à¶±à· වෙත සබà·à¶³à·’යක් යොද
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr "ඔබට %{name} මà·à¶šà·“මට වුවමන෠ද?"
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr "ඔබට මෙම %{commentType} මà·à¶šà·“මට වුවමන෠ද?"
@@ -5177,8 +5259,8 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr "ඔබට මෙම %{accessTokenType} අහà·à·ƒà·’ කිරීමට වුවමන෠ද? මෙම ක්â€à¶»à·’යà·à¶¸à·à¶»à·Šà¶œà¶º අප්â€à¶»à¶­à·’වර්ත්â€à¶ºà¶ºà·’."
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
-msgstr "ඔබට මෙම %{type} අහà·à·ƒà·’ කිරීමට වුවමන෠ද? මෙම ක්â€à¶»à·’යà·à¶¸à·à¶»à·Šà¶œà¶º අප්â€à¶»à¶­à·’වර්ත්â€à¶ºà¶ºà·’."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr ""
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr "නම්පත් පà·à·€à¶»à·“ම"
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr "මටම පවරන්න"
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr "à·à·à¶›à·à·€ පවතී"
msgid "Branch changed"
msgstr "à·à·à¶›à·à·€ වෙනස් විය"
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr "à·à·à¶›à·à·€ ගෙන ඇත"
msgid "Branch name"
msgstr "à·à·à¶›à·à·€à·š නම"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "නà·à¶¸à·à·€à¶½à·’ය පිරික්සන්න"
@@ -7039,9 +7178,6 @@ msgstr "ගොනුව පිරික්සන්න"
msgid "Browse Files"
msgstr "ගොනු පිරික්සන්න"
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr "ගොනු පිරික්සන්න"
@@ -7087,9 +7223,6 @@ msgstr "මූලà·à·à·Šâ€à¶» සමූහයට අනුව පෙරන්
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr "නම දà·à¶±à¶§à¶¸à¶­à·Š පවතී."
msgid "BulkImport|Name already used as a target for another group."
msgstr "අන් සමූහකට ඉලක්කයක් ලෙස නම භà·à·€à·’ත෠කර ඇත."
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr "අතිරේක තොරතුරු සපය෠නà·à¶­."
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’ය ආයà·à¶­ ඉතිහà·à·ƒà¶º"
@@ -7159,9 +7298,6 @@ msgstr "මූලà·à·à·Šâ€à¶» සමූහය"
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr "නව සමූහයකට"
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr "පෙරදසුන අවලංගු වෙමින්"
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr "ස්වයංක්â€à¶»à·“යව සංයුක්ත කළ නොහà·à¶šà·’ය"
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr "යතුර"
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr "පිවිසීමට තහවුරුව නිම කරන්න
msgid "Complete verification to sign up."
msgstr "පිවිසීමට සත්â€à¶ºà·à¶´à¶±à¶º නිම කරන්න."
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr "සම්පූර්ණයි"
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13362,7 +13540,7 @@ msgid "DeploymentTarget|GitLab Pages"
msgstr ""
msgid "DeploymentTarget|Heroku"
-msgstr ""
+msgstr "හිරà·à¶šà·”"
msgid "DeploymentTarget|Infrastructure provider (Terraform, Cloudformation, and so on)"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13744,7 +13925,7 @@ msgid "DevopsAdoption|Deploys"
msgstr ""
msgid "DevopsAdoption|Dev"
-msgstr ""
+msgstr "සංව."
msgid "DevopsAdoption|DevOps adoption tracks the use of key features across your favorite groups. Add a group to the table to begin."
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr "සිදුවීම් යෙ.ක්â€à¶».මු."
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr "නවම්"
msgid "February"
msgstr "නවම්"
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr "මුරපදය අමතක වුනà·à¶¯?"
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr "ගිට්ලà·à¶¶à·Š දà·à·‚ ලුහුබà·à¶³à·“ම"
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr "GitLab.com (SaaS)"
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr "MD5"
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr "මà·à¶¯à·’න්"
msgid "March"
msgstr "මà·à¶¯à·’න්"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr "ප්â€à¶»à·à¶¸à·’තියස් අනුකලන කිහිපà
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr "වප්"
msgid "October"
msgstr "වප්"
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr "ඇසුරුම් අනුපිටපත්"
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr "හෙල්ම්"
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr "අභිප්â€à¶»à·šà¶­"
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] "නිකුතු"
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr "තීව්â€à¶»à¶­à·à·€"
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr ""
+
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr "උදව් සඳහ෠අපගේ අඩවිය බලන්න"
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr "වේල෠කලà·à¶´à¶ºà¶šà·Š තà·à¶»à¶±à·Šà¶±"
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr "සූදà·à¶±à¶¸à·Š තත්â€à·€à¶º සකසන්න"
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr "තීව්â€à¶»à¶­à·à·€"
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,8 +37881,8 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
-msgstr "“%{group_name}†වෙත පිවිසෙන්න"
+msgid "Sign in to %{group_name}"
+msgstr ""
msgid "Sign in to GitLab"
msgstr "ගිට්ලà·à¶¶à·Š වෙත පිවිසෙන්න"
@@ -37405,7 +37896,7 @@ msgstr "2FA කේතය මගින් පිවිසෙන්න"
msgid "Sign in with"
msgstr "මෙමගින් පිවිසෙන්න"
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "යමෙක්, බොහà·à·€à·’ට ඔබ, %{link_to_gitlab} à·„à·’ ඔබගේ ගිට්ලà·à¶¶à·Š ගිණුමේ මුරපදය යළි පිහිටුවීමට ඉල්ල෠ඇත."
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr "තත්â€à·€à¶º:"
msgid "Status: %{title}"
msgstr "තත්â€à·€à¶º: %{title}"
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr "පරීක්â€à·‚à·à·€à¶§ යෙ.ක්â€à¶».මු."
msgid "StatusCheck|Add status check"
msgstr "තත්â€à·€ පරීක්â€à·‚à·à·€ එක්කරන්න"
-msgid "StatusCheck|All passed"
-msgstr "සියල්ල සමත්!"
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr "බà·à·„ිර යෙ.ක්â€à¶».මු. දà·à¶±à¶§à¶¸à¶­à·Š වෙ
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr "තත්â€à·€ පරීක්â€à·‚෠පූරණයට අසමත් විය."
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr "à·à·à¶›à·à·€ මà·à¶»à·”à·€"
msgid "Switch branch/tag"
msgstr "à·à·à¶›à·à·€/අනන්â€à¶ºà¶±à¶º මà·à¶»à·”à·€"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr "ගිට්ලà·à¶¶à·Š නෙක්â€à·ƒà·Šà¶§à·Š මà·à¶»à·”à·€"
@@ -39351,6 +39839,9 @@ msgstr "පටුන"
msgid "Tag"
msgstr "අනන්â€à¶ºà¶±à¶º"
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr "අනන්â€à¶ºà¶±à¶º මකන්න. ඔබට විà·à·Šà·€à·à·
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr "%{strongStart}%{tagName}%{strongEnd} අනන්â€à¶ºà¶±à¶º මක෠දà·à¶¸à·“ම අප්â€à¶»à¶­à·’වර්ත්â€à¶ºà¶ºà·’. ඔබට විà·à·Šà·€à·à·ƒà¶¯?"
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr "ව්â€à¶ºà·à¶´à·˜à¶­à·’ නඩත්තුකරුවෙකුට à
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr "තහවුරු කිරීමට පහත දෙය ලියන්න:"
-msgid "TagsPage|Release notes"
-msgstr "නිකුතු සටහන්"
-
msgid "TagsPage|Repository has no tags yet."
msgstr "කà·à·‚්ඨයෙහි තවම අනන්â€à¶ºà¶± නà·à¶­."
@@ -39486,9 +39974,6 @@ msgstr "අනන්â€à¶ºà¶± පූරණය කිරීමට නොහà·à¶š
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "ඔබගේ නිකුතු සටහන් ලියන්න හ෠ගොනු මෙතà·à¶±à¶§ අදින්න…"
-
msgid "TagsPage|Yes, delete protected tag"
msgstr "ඔව්, රක්â€à·‚ිත අනන්â€à¶ºà¶±à¶º මකන්න"
@@ -39507,6 +39992,9 @@ msgstr "රක්â€à·‚ිතයි"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr "ඉලක්කගත à·à·à¶›à·à·€"
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr "%{name} à·ƒà·à¶»à·Šà¶®à¶šà·€ ඉවත් කෙරිණි"
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr "ටෙරà·à·†à·à¶¸à·Š à·€à·à¶»à·Šà¶­à·à·€ උත්පà·à¶¯à¶±à¶ºà
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr "à·€à·à¶»à·Šà¶­à·à·€à¶šà·Š උත්පà·à¶¯à¶±à¶ºà¶§ අසමත් විය."
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr "ක්â€à¶»à·’යà·à¶¸à·à¶»à·Šà¶œ"
@@ -39740,12 +40212,6 @@ msgstr "ටෙරà·à·†à·à¶¸à·Š init විධà·à¶±à¶º"
msgid "Terraform|Terraform reports"
msgstr "ටෙරà·à·†à·à¶¸à·Š à·€à·à¶»à·Šà¶­à·"
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr "සුපිරික්සීම à·ƒà·à¶¯à· ඇත."
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr "තේමà·à·€"
-msgid "There are currently no events."
-msgstr "දà·à¶±à¶§ සිදුවීම් නà·à¶­."
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,15 +41785,18 @@ msgstr "සංයුක්ත ඉල්ලීම ඒකà·à¶¶à¶¯à·Šà¶°à¶ºà·’. à¶
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
+msgstr ""
+
msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr "ඔබට ව්â€à¶ºà·à¶´à·˜à¶­à·’ කිහිපයක් හරහ෠තොරතුරු කියවීමට ඉඩ නà·à¶­à·’ නිස෠මෙම පිටුව නොතිබේ."
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
-msgstr ""
-
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
msgstr ""
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr "මෙම පුද්ගලයà·à¶§ අනන්â€à¶ºà¶­à·à·€à¶šà·Š නà·à¶­"
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr "අද"
msgid "Todos count"
msgstr "කළ-යුතු ගණන"
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr "කතෘට අනුව පෙරන්න"
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr "සියල්ල අහවර බව යොදන්න"
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr "සියල්ල අහවරයි!"
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr "මුළු දà·à¶ºà¶šà¶­à·Šâ€à·€"
msgid "Total Score"
msgstr "මුළු ලකුණු"
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr "මෙම පුද්ගලය෠සඳහ෠ද්වි-à·ƒà·à¶°à¶
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr "ඔබගේ ගිට්ලà·à¶¶à·Š ගිණුම සඳහ෠ද්වි-à·ƒà·à¶°à¶š සත්â€à¶ºà·à¶´à¶±à¶º අබල කර ඇත."
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr "ද්වි-à·ƒà·à¶°à¶š සත්â€à¶ºà·à¶´à¶±à¶º à·ƒà·à¶»à·Šà¶®à¶šà·€ අබල කර ඇත!"
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr "ඇසුරුම්"
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr "කà·à·‚්ඨය"
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr "ආසන"
@@ -44229,9 +44773,6 @@ msgstr "ගොනුව බලන්න @ %{commitSha}"
msgid "View full dashboard"
msgstr "උපකරණ පුවරුව බලන්න"
-msgid "View full log"
-msgstr "පූර්ණ සටහන බලන්න"
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr "ඉල්ලීම/ප්â€à¶»à¶­à·’චà·à¶»à¶º"
msgid "Vulnerability|Scanner Provider"
msgstr "සුපිරික්සන à·ƒà·à¶´à¶ºà·”ම්කරු"
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr "ආරක්â€à·‚ණ විගණනය"
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr "තත්â€à·€à¶º"
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "ඔබ ස්වයංක්â€à¶»à¶¸à¶½à·šà¶›à¶ºà¶šà·Š නොවන බව තහවුරු කරන්න."
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr "නිකුතු සිදුවීම්"
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr "වියමන අඩවිය"
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr "ඔබ මෙම සමූහය භà·à·€à·’ත෠කරන්නේ කුමක් සඳහà·à¶¯?"
@@ -45209,7 +45789,7 @@ msgstr "ඔබ කිරීමට කà·à¶¸à¶­à·’ කුමක්ද?"
msgid "What's new"
msgstr "මොනවà·à¶¯ අළුත්"
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr "ඔබ නව à·à·à¶›à·à·€à¶šà·Š සෑදීමට කà·à¶¸à¶­à·’ද?"
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr "මෙලෙස ගිට්ලà·à¶¶à·Š වෙත ඇතුළු à·€à·
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr "ගිට්ලà·à¶¶à·Š à·„à·’ à·ƒà·à¶¸à¶­à·à¶± සෙවීමට ඇතුළු වී සිටිය යුතුය"
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr "යූටියුබ්"
msgid "Your %{group} membership will now expire in %{days}."
msgstr "ඔබගේ %{group} à·ƒà·à¶¸à·à¶¢à·’කත්වය දà·à¶±à·Š %{days} කින් ඉකුත් වේ."
-msgid "Your %{host} account was signed in to from a new location"
-msgstr "ඔබගේ %{host} ගිණුමට නව ස්ථà·à¶±à¶ºà¶šà·’න් ඇතුළු වී ඇත"
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr "ඔබගේ %{spammable_entity_type} අයà·à¶ à·’ත ලෙස හඳුන෠ගෙන ඉවත දම෠ඇත."
@@ -46526,6 +47151,9 @@ msgstr "ඔබගේ ගිණුමට අගුළු ල෠ඇත."
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr "ඔබගේ ක්â€à¶»à·’යà·à¶¸à·à¶»à·Šà¶œà¶º à·ƒà·à¶»à·Šà¶®à¶šà¶ºà·’."
@@ -46644,18 +47272,15 @@ msgstr "ඔබගේ පණිවිඩය මෙතà·à¶±"
msgid "Your name"
msgstr "ඔබගේ නම"
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
+msgstr ""
+
msgid "Your new %{accessTokenType}"
msgstr "ඔබගේ නව %{accessTokenType}"
msgid "Your new %{accessTokenType} has been created."
msgstr ""
-msgid "Your new %{type}"
-msgstr "ඔබගේ නව %{type}"
-
-msgid "Your new access token has been created."
-msgstr ""
-
msgid "Your new comment"
msgstr "ඔබගේ නව අදහස"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr "ඔබගේ පරිà·à·“ලක නà·à¶¸à¶º %{username}."
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr "මක෠දà·à¶¸à·– පුද්ගලයෙකි"
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr "ප්â€à¶»à·€à·šà·à¶º:"
-msgid "added"
-msgstr "එකතු කෙරිණි"
-
msgid "added %{emails}"
msgstr "%{emails} එක් කළà·"
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr "නව ගොනුවක් අමුණන්න"
@@ -46979,6 +47604,12 @@ msgstr "අතීත දිනයක් විය නොහà·à¶šà·’ය"
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr "වෙනස් කළ නොහà·à¶šà·’ය"
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr "පරà·à¶ºà¶­à·Šà¶­ සුපිරික්සමින්"
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr "නව"
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr "කේත ගුණත්â€à·€à¶ºà¶§ වෙනසක් නà·à¶­."
@@ -47322,6 +47971,9 @@ msgstr "රහස් අනà·à·€à¶»à¶«à¶º"
msgid "ciReport|Security reports failed loading results"
msgstr "ආරක්â€à·‚ණ à·€à·à¶»à·Šà¶­à· ප්â€à¶»à¶­à·’ඵල පූරණයට අසමත් විය"
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr "ආරක්â€à·‚ණ සුපිරික්සීම"
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr "විසඳුම"
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] "දවස්"
msgid "days"
msgstr "දවස්"
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr "පෙරනිමි à·à·à¶›à·à·€"
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr "අභ්â€à¶ºà¶±à·Šà¶­à¶» සටහන"
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr "වලංගු නොවන අ.ජà·.කෙ. ලිපින පරà·à·ƒà¶ºà¶šà·’"
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr "වලංගු X509 සහතිකයක් නොවේ."
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr "à·ƒà·à¶¸à·à¶¢à·’ක කණ්ඩà·à¶ºà¶¸ තුළ නà·à¶­"
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr "කියවීමට පමණි"
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr "%{mergeError}."
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr "අනුමà·à¶­à·’ය අහà·à·ƒà·’ කරන්න"
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr "ආරම්භයෙන් පසු විය යුතුය"
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr "ආරම්භක දිනයට පසු විය යුතුය"
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr "කà·à·‚්ඨයක් තිබිය යුතුය"
@@ -48285,9 +48970,6 @@ msgstr "මà·à¶œà·š-නà·à¶½à·’කà·à·€"
msgid "my-topic"
msgstr "මà·à¶œà·š-මà·à¶­à·˜à¶šà·à·€"
-msgid "need attention"
-msgstr "අවධà·à¶±à¶º අවà·à·Šâ€à¶ºà¶ºà·’"
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}, සහ %{lastItem}"
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr "à·„à·"
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr "ඇසුරුම් "
msgid "pages"
msgstr "පිටු"
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr "ආරම්භක දිනය ඉවත් කරන්න"
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr "ඉවත් කර ඇත"
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr "කà·à·‚්ඨ"
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr "කà·à·‚්ඨය:"
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr "මෙම ලේඛනය"
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr "yaml වලංගු නොවේ"
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/sk_SK/gitlab.po b/locale/sk_SK/gitlab.po
index 7ec8eab02b6..c23c35973cd 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: 2022-10-10 14:01\n"
+"PO-Revision-Date: 2022-11-13 09:22\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -171,6 +171,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -311,13 +318,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
@@ -325,13 +325,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -346,13 +339,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -677,6 +663,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -737,6 +726,20 @@ msgstr[3] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -747,6 +750,13 @@ msgstr[3] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} more"
msgstr ""
@@ -773,6 +783,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -812,9 +829,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -1025,12 +1039,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1230,6 +1238,9 @@ msgstr[3] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1388,9 +1399,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1448,6 +1456,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1488,6 +1499,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1827,6 +1841,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1890,9 +1907,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1971,9 +1985,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -2181,6 +2192,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2292,15 +2306,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2370,9 +2378,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2745,6 +2750,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2928,6 +2939,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2964,15 +2993,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -3021,6 +3062,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -3066,6 +3110,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -3204,9 +3260,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -3231,6 +3296,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3333,6 +3407,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3525,7 +3602,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3570,7 +3647,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3633,7 +3710,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3681,6 +3758,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -4191,7 +4271,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -4206,6 +4286,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -4242,9 +4325,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4491,6 +4571,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4678,9 +4761,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4780,9 +4860,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4885,9 +4962,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4906,7 +4980,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4953,6 +5027,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4971,9 +5048,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -5001,6 +5087,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5351,9 +5440,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5457,7 +5543,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5508,6 +5594,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5559,9 +5669,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5961,9 +6068,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6327,6 +6431,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -7063,6 +7173,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -7072,6 +7185,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -7093,6 +7209,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -7111,6 +7230,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -7120,6 +7242,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -7138,9 +7263,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -7159,12 +7290,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7324,6 +7464,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7333,9 +7476,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7381,9 +7521,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7414,6 +7551,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7429,6 +7569,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7453,9 +7596,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7871,9 +8011,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7889,6 +8026,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8632,6 +8772,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9951,10 +10094,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -10138,6 +10287,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10939,10 +11091,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10975,6 +11127,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -11023,9 +11184,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -11110,9 +11268,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -11275,9 +11430,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11497,9 +11649,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11767,9 +11916,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11785,7 +11931,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11887,9 +12033,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -12218,6 +12361,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -12245,6 +12391,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -12302,6 +12451,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12536,6 +12688,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12756,6 +12911,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12843,6 +13001,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12876,6 +13037,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12987,6 +13151,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -13008,9 +13175,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -13077,7 +13241,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13566,6 +13730,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13653,6 +13820,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13997,6 +14179,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -14239,6 +14424,12 @@ msgstr[3] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -14254,6 +14445,9 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
@@ -14261,6 +14455,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14868,6 +15065,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -15198,22 +15401,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Copy snippet"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr ""
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr ""
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15441,6 +15662,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15621,10 +15845,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15639,18 +15863,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15663,18 +15878,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15804,9 +16013,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15870,9 +16076,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -16113,6 +16316,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -16234,6 +16488,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -16291,9 +16548,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16520,6 +16783,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16569,9 +16835,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16767,9 +17030,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -17029,6 +17289,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17134,9 +17397,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -17344,6 +17604,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -18185,9 +18448,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -18314,6 +18574,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18365,6 +18631,9 @@ 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 ""
@@ -18413,9 +18682,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18971,9 +19237,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18983,6 +19246,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19745,12 +20011,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19820,6 +20080,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -20002,9 +20265,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20463,7 +20723,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20550,12 +20816,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -22315,6 +22575,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -22333,9 +22596,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22393,7 +22653,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22475,19 +22735,16 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22625,12 +22882,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22652,6 +22915,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22877,6 +23152,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -23171,6 +23461,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23501,6 +23794,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23540,9 +23836,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23923,9 +24225,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -24079,6 +24378,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24229,9 +24537,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24490,6 +24795,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24760,9 +25071,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24775,6 +25083,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24811,7 +25122,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24826,9 +25143,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24838,9 +25161,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24850,7 +25170,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24907,6 +25227,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24931,6 +25254,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24982,6 +25308,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24994,6 +25323,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25626,6 +25958,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25851,6 +26186,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -26246,6 +26584,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26405,6 +26746,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26477,6 +26821,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26663,6 +27010,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -27127,6 +27477,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -27256,9 +27609,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -27286,9 +27636,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -27304,9 +27651,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27542,7 +27886,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27885,6 +28229,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27894,6 +28241,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27915,6 +28265,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -28008,9 +28361,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -28035,9 +28385,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -28273,12 +28620,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28324,12 +28665,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28351,12 +28686,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28399,15 +28728,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28438,12 +28758,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28462,9 +28776,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28640,9 +28951,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -29013,12 +29321,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -29064,6 +29381,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -29212,6 +29535,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29597,12 +29923,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29651,7 +29971,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29870,6 +30190,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29885,6 +30208,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29897,12 +30223,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29912,9 +30244,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30674,9 +31012,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30785,6 +31120,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30926,6 +31324,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -31019,12 +31420,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31601,6 +32008,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31613,6 +32023,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31895,12 +32308,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31913,12 +32332,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31940,6 +32365,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -32039,6 +32467,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -32177,6 +32608,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -32207,6 +32641,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -32258,6 +32695,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32897,6 +33337,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32933,15 +33376,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32957,12 +33412,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -33272,6 +33736,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33404,12 +33871,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33503,9 +33964,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33673,6 +34131,9 @@ msgstr[3] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33682,6 +34143,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -34138,6 +34602,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -34154,13 +34621,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -34192,18 +34652,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34218,12 +34672,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -34266,21 +34714,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34296,9 +34735,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34678,6 +35114,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34911,6 +35350,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34951,6 +35393,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34983,7 +35428,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -35194,6 +35639,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -35324,9 +35772,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -35375,6 +35829,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -35412,6 +35869,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -35451,12 +35911,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35511,16 +35965,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35628,10 +36088,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35652,9 +36112,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35664,9 +36130,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35817,9 +36289,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -36248,10 +36717,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -36371,6 +36843,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36473,10 +36948,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36566,7 +37041,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36584,6 +37059,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36602,12 +37080,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36629,6 +37116,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36758,6 +37248,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36815,6 +37308,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36932,9 +37428,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36947,6 +37449,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -37010,9 +37515,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -37151,10 +37653,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -37166,28 +37668,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37406,9 +37908,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37560,9 +38059,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37819,10 +38315,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37876,7 +38369,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37891,7 +38384,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -38014,9 +38507,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -38239,6 +38729,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38350,9 +38843,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38926,9 +39416,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38941,9 +39428,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38965,9 +39449,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39487,9 +39968,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39749,6 +40236,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39839,6 +40329,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39923,6 +40416,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39944,15 +40440,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39974,9 +40464,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39995,6 +40482,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -40106,20 +40596,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -40143,12 +40619,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -40236,12 +40706,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40706,6 +41170,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40901,9 +41368,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40934,7 +41398,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40991,9 +41455,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -41345,9 +41806,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -41381,6 +41839,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41549,9 +42010,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41612,6 +42070,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41828,13 +42289,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41963,9 +42427,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41984,6 +42445,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42358,9 +42822,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42466,6 +42927,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42532,9 +42996,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42556,18 +43044,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42580,6 +43089,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42730,9 +43257,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -43055,6 +43579,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43559,6 +44089,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43661,6 +44197,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43691,6 +44230,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44747,9 +45289,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -45213,6 +45752,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -45231,6 +45773,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -45366,7 +45911,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45408,6 +45953,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -45423,12 +45971,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45468,6 +46028,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45582,6 +46145,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45609,9 +46178,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45624,7 +46190,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45636,12 +46202,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45720,6 +46295,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45729,7 +46307,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -46049,6 +46627,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -46101,9 +46685,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -46134,10 +46733,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -46149,6 +46751,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -46170,6 +46775,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -46188,6 +46796,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -46285,6 +46896,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -46321,6 +46935,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46366,9 +46986,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -46472,6 +47089,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46544,7 +47164,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46568,6 +47188,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46713,6 +47336,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46776,7 +47402,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46944,9 +47570,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -47058,6 +47681,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -47180,16 +47806,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47280,6 +47903,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47349,9 +47975,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -47365,9 +47988,6 @@ msgstr[3] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -47429,6 +48049,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -47438,9 +48064,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -47523,6 +48146,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47764,12 +48393,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47846,6 +48490,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47876,6 +48523,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47891,6 +48541,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47967,6 +48620,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -48028,6 +48684,9 @@ msgstr[3] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -48190,6 +48849,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -48294,12 +48956,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -48321,6 +48989,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -48345,12 +49016,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -48513,9 +49190,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48668,6 +49342,9 @@ 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 ""
@@ -48764,9 +49441,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48830,6 +49504,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48842,9 +49519,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48863,9 +49546,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48914,9 +49594,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48935,19 +49612,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -49083,9 +49756,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -49108,12 +49778,22 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -49271,6 +49951,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -49411,6 +50094,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/sl_SI/gitlab.po b/locale/sl_SI/gitlab.po
index 642dd8a06d1..8193dd0b596 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: 2022-10-10 13:59\n"
+"PO-Revision-Date: 2022-11-13 09:20\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -171,6 +171,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -311,13 +318,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
@@ -325,13 +325,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -346,13 +339,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -677,6 +663,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -737,6 +726,20 @@ msgstr[3] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -747,6 +750,13 @@ msgstr[3] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} more"
msgstr ""
@@ -773,6 +783,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -812,9 +829,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -1025,12 +1039,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1230,6 +1238,9 @@ msgstr[3] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1388,9 +1399,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1448,6 +1456,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1488,6 +1499,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1827,6 +1841,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1890,9 +1907,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1971,9 +1985,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -2181,6 +2192,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2292,15 +2306,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2370,9 +2378,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2745,6 +2750,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2928,6 +2939,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2964,15 +2993,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -3021,6 +3062,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -3066,6 +3110,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -3204,9 +3260,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -3231,6 +3296,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3333,6 +3407,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3525,7 +3602,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3570,7 +3647,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3633,7 +3710,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3681,6 +3758,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -4191,7 +4271,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -4206,6 +4286,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -4242,9 +4325,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4491,6 +4571,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4678,9 +4761,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4780,9 +4860,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4885,9 +4962,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4906,7 +4980,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4953,6 +5027,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4971,9 +5048,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -5001,6 +5087,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5351,9 +5440,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5457,7 +5543,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5508,6 +5594,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5559,9 +5669,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5961,9 +6068,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6327,6 +6431,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -7063,6 +7173,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -7072,6 +7185,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -7093,6 +7209,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -7111,6 +7230,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -7120,6 +7242,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -7138,9 +7263,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -7159,12 +7290,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7324,6 +7464,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7333,9 +7476,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7381,9 +7521,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7414,6 +7551,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7429,6 +7569,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7453,9 +7596,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7871,9 +8011,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7889,6 +8026,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8632,6 +8772,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9951,10 +10094,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -10138,6 +10287,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10939,10 +11091,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10975,6 +11127,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -11023,9 +11184,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -11110,9 +11268,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -11275,9 +11430,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11497,9 +11649,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11767,9 +11916,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11785,7 +11931,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11887,9 +12033,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -12218,6 +12361,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -12245,6 +12391,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -12302,6 +12451,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12536,6 +12688,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12756,6 +12911,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12843,6 +13001,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12876,6 +13037,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12987,6 +13151,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -13008,9 +13175,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -13077,7 +13241,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13566,6 +13730,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13653,6 +13820,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13997,6 +14179,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -14239,6 +14424,12 @@ msgstr[3] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -14254,6 +14445,9 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
@@ -14261,6 +14455,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14868,6 +15065,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -15198,22 +15401,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Copy snippet"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr ""
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr ""
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15441,6 +15662,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15621,10 +15845,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15639,18 +15863,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15663,18 +15878,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15804,9 +16013,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15870,9 +16076,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -16113,6 +16316,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -16234,6 +16488,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -16291,9 +16548,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16520,6 +16783,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16569,9 +16835,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16767,9 +17030,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -17029,6 +17289,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17134,9 +17397,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -17344,6 +17604,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -18185,9 +18448,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -18314,6 +18574,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18365,6 +18631,9 @@ 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 ""
@@ -18413,9 +18682,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18971,9 +19237,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18983,6 +19246,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19745,12 +20011,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19820,6 +20080,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -20002,9 +20265,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20463,7 +20723,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20550,12 +20816,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -22315,6 +22575,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -22333,9 +22596,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22393,7 +22653,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22475,19 +22735,16 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22625,12 +22882,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22652,6 +22915,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22877,6 +23152,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -23171,6 +23461,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23501,6 +23794,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23540,9 +23836,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23923,9 +24225,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -24079,6 +24378,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24229,9 +24537,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24490,6 +24795,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24760,9 +25071,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24775,6 +25083,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24811,7 +25122,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24826,9 +25143,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24838,9 +25161,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24850,7 +25170,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24907,6 +25227,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24931,6 +25254,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24982,6 +25308,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24994,6 +25323,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25626,6 +25958,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25851,6 +26186,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -26246,6 +26584,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26405,6 +26746,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26477,6 +26821,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26663,6 +27010,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -27127,6 +27477,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -27256,9 +27609,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -27286,9 +27636,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -27304,9 +27651,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27542,7 +27886,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27885,6 +28229,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27894,6 +28241,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27915,6 +28265,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -28008,9 +28361,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -28035,9 +28385,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -28273,12 +28620,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28324,12 +28665,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28351,12 +28686,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28399,15 +28728,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28438,12 +28758,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28462,9 +28776,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28640,9 +28951,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -29013,12 +29321,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -29064,6 +29381,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -29212,6 +29535,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29597,12 +29923,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29651,7 +29971,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29870,6 +30190,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29885,6 +30208,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29897,12 +30223,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29912,9 +30244,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30674,9 +31012,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30785,6 +31120,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30926,6 +31324,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -31019,12 +31420,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31601,6 +32008,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31613,6 +32023,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31895,12 +32308,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31913,12 +32332,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31940,6 +32365,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -32039,6 +32467,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -32177,6 +32608,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -32207,6 +32641,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -32258,6 +32695,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32897,6 +33337,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32933,15 +33376,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32957,12 +33412,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -33272,6 +33736,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33404,12 +33871,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33503,9 +33964,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33673,6 +34131,9 @@ msgstr[3] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33682,6 +34143,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -34138,6 +34602,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -34154,13 +34621,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -34192,18 +34652,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34218,12 +34672,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -34266,21 +34714,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34296,9 +34735,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34678,6 +35114,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34911,6 +35350,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34951,6 +35393,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34983,7 +35428,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -35194,6 +35639,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -35324,9 +35772,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -35375,6 +35829,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -35412,6 +35869,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -35451,12 +35911,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35511,16 +35965,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35628,10 +36088,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35652,9 +36112,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35664,9 +36130,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35817,9 +36289,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -36248,10 +36717,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -36371,6 +36843,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36473,10 +36948,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36566,7 +37041,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36584,6 +37059,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36602,12 +37080,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36629,6 +37116,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36758,6 +37248,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36815,6 +37308,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36932,9 +37428,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36947,6 +37449,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -37010,9 +37515,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -37151,10 +37653,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -37166,28 +37668,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37406,9 +37908,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37560,9 +38059,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37819,10 +38315,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37876,7 +38369,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37891,7 +38384,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -38014,9 +38507,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -38239,6 +38729,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38350,9 +38843,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38926,9 +39416,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38941,9 +39428,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38965,9 +39449,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39487,9 +39968,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39749,6 +40236,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39839,6 +40329,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39923,6 +40416,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39944,15 +40440,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39974,9 +40464,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39995,6 +40482,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -40106,20 +40596,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -40143,12 +40619,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -40236,12 +40706,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40706,6 +41170,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40901,9 +41368,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40934,7 +41398,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40991,9 +41455,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -41345,9 +41806,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -41381,6 +41839,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41549,9 +42010,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41612,6 +42070,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41828,13 +42289,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41963,9 +42427,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41984,6 +42445,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42358,9 +42822,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42466,6 +42927,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42532,9 +42996,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42556,18 +43044,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42580,6 +43089,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42730,9 +43257,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -43055,6 +43579,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43559,6 +44089,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43661,6 +44197,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43691,6 +44230,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44747,9 +45289,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -45213,6 +45752,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -45231,6 +45773,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -45366,7 +45911,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45408,6 +45953,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -45423,12 +45971,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45468,6 +46028,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45582,6 +46145,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45609,9 +46178,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45624,7 +46190,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45636,12 +46202,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45720,6 +46295,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45729,7 +46307,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -46049,6 +46627,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -46101,9 +46685,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -46134,10 +46733,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -46149,6 +46751,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -46170,6 +46775,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -46188,6 +46796,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -46285,6 +46896,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -46321,6 +46935,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46366,9 +46986,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -46472,6 +47089,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46544,7 +47164,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46568,6 +47188,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46713,6 +47336,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46776,7 +47402,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46944,9 +47570,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -47058,6 +47681,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -47180,16 +47806,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47280,6 +47903,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47349,9 +47975,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -47365,9 +47988,6 @@ msgstr[3] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -47429,6 +48049,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -47438,9 +48064,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -47523,6 +48146,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47764,12 +48393,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47846,6 +48490,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47876,6 +48523,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47891,6 +48541,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47967,6 +48620,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -48028,6 +48684,9 @@ msgstr[3] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -48190,6 +48849,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -48294,12 +48956,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -48321,6 +48989,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -48345,12 +49016,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -48513,9 +49190,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48668,6 +49342,9 @@ 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 ""
@@ -48764,9 +49441,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48830,6 +49504,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48842,9 +49519,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48863,9 +49546,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48914,9 +49594,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48935,19 +49612,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -49083,9 +49756,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -49108,12 +49778,22 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -49271,6 +49951,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -49411,6 +50094,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/sq_AL/gitlab.po b/locale/sq_AL/gitlab.po
index f44da24dc42..2f240a42aa8 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: 2022-10-10 13:59\n"
+"PO-Revision-Date: 2022-11-13 09:20\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/sr_CS/gitlab.po b/locale/sr_CS/gitlab.po
index d05e2e90d0e..f4e29b1a805 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: 2022-10-10 14:06\n"
+"PO-Revision-Date: 2022-11-13 09:24\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -157,6 +157,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -277,24 +283,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d greška"
-msgstr[1] "%d greške"
-msgstr[2] "%d grešaka"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -307,12 +301,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -595,6 +583,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -652,6 +643,18 @@ msgstr[2] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -661,6 +664,12 @@ msgstr[2] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%{count} more"
msgstr ""
@@ -685,6 +694,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -724,9 +739,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -937,12 +949,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1135,6 +1141,9 @@ msgstr[2] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1285,9 +1294,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1345,6 +1351,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1384,6 +1393,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1696,6 +1708,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1759,9 +1774,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1840,9 +1852,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -2050,6 +2059,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2161,15 +2173,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2239,9 +2245,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2614,6 +2617,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2797,6 +2806,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2833,15 +2860,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2890,6 +2929,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2935,6 +2977,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -3073,9 +3127,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -3100,6 +3163,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3202,6 +3274,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3394,7 +3469,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3439,7 +3514,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3502,7 +3577,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3550,6 +3625,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -4060,7 +4138,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -4075,6 +4153,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -4111,9 +4192,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4360,6 +4438,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4546,9 +4627,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4648,9 +4726,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4753,9 +4828,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4774,7 +4846,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4819,6 +4891,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4837,9 +4912,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4867,6 +4951,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5212,9 +5299,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5317,7 +5401,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5368,6 +5452,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5419,9 +5527,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5818,9 +5923,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6184,6 +6286,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6916,6 +7024,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6925,6 +7036,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6946,6 +7060,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6964,6 +7081,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6973,6 +7093,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6991,9 +7114,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -7012,12 +7141,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7177,6 +7315,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7186,9 +7327,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7234,9 +7372,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7267,6 +7402,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7282,6 +7420,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7306,9 +7447,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7723,9 +7861,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7741,6 +7876,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8482,6 +8620,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9799,10 +9940,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9985,6 +10132,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10783,10 +10933,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10819,6 +10969,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10867,9 +11026,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10954,9 +11110,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -11119,9 +11272,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11341,9 +11491,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11611,9 +11758,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11629,7 +11773,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11731,9 +11875,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -12061,6 +12202,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -12088,6 +12232,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -12145,6 +12292,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12379,6 +12529,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12598,6 +12751,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12685,6 +12841,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12718,6 +12877,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12829,6 +12991,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12850,9 +13015,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12919,7 +13081,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13402,6 +13564,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13489,6 +13654,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13831,6 +14011,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -14071,6 +14254,12 @@ msgstr[2] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -14086,12 +14275,18 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14698,6 +14893,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -15028,22 +15229,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Using a static site?"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15271,6 +15490,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15451,10 +15673,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15469,18 +15691,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15493,18 +15706,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15634,9 +15841,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15700,9 +15904,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15943,6 +16144,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -16063,6 +16315,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -16120,9 +16375,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16348,6 +16609,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16396,9 +16660,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16594,9 +16855,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16855,6 +17113,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16960,9 +17221,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -17170,6 +17428,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -18007,9 +18268,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -18136,6 +18394,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18187,6 +18451,9 @@ 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 ""
@@ -18235,9 +18502,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18793,9 +19057,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18805,6 +19066,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19567,12 +19831,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19642,6 +19900,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19822,9 +20083,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20281,7 +20539,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20368,12 +20632,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -22129,6 +22387,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -22147,9 +22408,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22207,7 +22465,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22288,19 +22546,16 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22438,12 +22693,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22465,6 +22726,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22690,6 +22963,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22984,6 +23272,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23314,6 +23605,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23353,9 +23647,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23734,9 +24034,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23890,6 +24187,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24040,9 +24346,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24295,6 +24598,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24565,9 +24874,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24580,6 +24886,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24616,7 +24925,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24631,9 +24946,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24643,9 +24964,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24655,7 +24973,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24712,6 +25030,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24736,6 +25057,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24787,6 +25111,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24799,6 +25126,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25429,6 +25759,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25654,6 +25987,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -26047,6 +26383,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26206,6 +26545,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26278,6 +26620,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26464,6 +26809,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26926,6 +27274,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -27055,9 +27406,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -27085,9 +27433,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -27103,9 +27448,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27340,7 +27682,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27679,6 +28021,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27688,6 +28033,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27709,6 +28057,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27802,9 +28153,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27829,9 +28177,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -28066,12 +28411,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28117,12 +28456,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28144,12 +28477,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28192,15 +28519,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28231,12 +28549,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28255,9 +28567,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28432,9 +28741,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28804,12 +29110,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28855,6 +29170,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -29002,6 +29323,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29386,12 +29710,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29440,7 +29758,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29659,6 +29977,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29674,6 +29995,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29686,12 +30010,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29701,9 +30031,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30463,9 +30799,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30574,6 +30907,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30715,6 +31111,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30808,12 +31207,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31390,6 +31795,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31402,6 +31810,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31684,12 +32095,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31702,12 +32119,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31729,6 +32152,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31828,6 +32254,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31966,6 +32395,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31996,6 +32428,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -32047,6 +32482,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32686,6 +33124,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32722,15 +33163,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32746,12 +33199,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -33061,6 +33523,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33193,12 +33658,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33292,9 +33751,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33460,6 +33916,9 @@ msgstr[2] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33469,6 +33928,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33925,6 +34387,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33940,12 +34405,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33976,18 +34435,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34000,12 +34453,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -34048,21 +34495,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34078,9 +34516,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34456,6 +34891,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34687,6 +35125,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34726,6 +35167,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34756,7 +35200,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34966,6 +35410,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -35095,9 +35542,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -35146,6 +35599,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -35182,6 +35638,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -35221,12 +35680,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35281,16 +35734,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35398,10 +35857,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35422,9 +35881,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35434,9 +35899,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35587,9 +36058,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -36007,10 +36475,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -36130,6 +36601,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36232,10 +36706,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36325,7 +36799,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36343,6 +36817,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36361,12 +36838,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36388,6 +36874,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36517,6 +37006,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36574,6 +37066,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36691,9 +37186,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36706,6 +37207,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36769,9 +37273,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36910,10 +37411,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36925,28 +37426,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37165,9 +37666,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37318,9 +37816,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37576,10 +38071,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37633,7 +38125,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37648,7 +38140,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37771,9 +38263,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37996,6 +38485,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38107,9 +38599,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38683,9 +39172,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38698,9 +39184,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38722,9 +39205,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39244,9 +39724,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39505,6 +39991,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39595,6 +40084,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39679,6 +40171,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39700,15 +40195,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39730,9 +40219,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39751,6 +40237,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39862,18 +40351,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39895,12 +40372,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39988,12 +40459,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40453,6 +40918,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40648,9 +41116,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40681,7 +41146,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40738,9 +41203,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -41092,9 +41554,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -41128,6 +41587,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41296,9 +41758,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41359,6 +41818,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41575,13 +42037,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41710,9 +42175,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41731,6 +42193,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42103,9 +42568,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42211,6 +42673,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42277,9 +42742,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42301,18 +42790,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42325,6 +42835,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42475,9 +43003,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42799,6 +43324,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43303,6 +43834,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43405,6 +43942,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43435,6 +43975,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44488,9 +45031,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44953,6 +45493,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44971,6 +45514,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -45106,7 +45652,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45148,6 +45694,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -45163,12 +45712,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45208,6 +45769,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45322,6 +45886,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45349,9 +45919,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45364,7 +45931,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45376,12 +45943,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45460,6 +46036,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45469,7 +46048,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45787,6 +46366,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45838,9 +46423,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45871,10 +46471,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45886,6 +46489,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45907,6 +46513,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45925,6 +46534,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -46021,6 +46633,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -46057,6 +46672,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46102,9 +46723,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -46207,6 +46825,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46279,7 +46900,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46303,6 +46924,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46447,6 +47071,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46510,7 +47137,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46678,9 +47305,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46792,6 +47416,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46912,16 +47539,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47011,6 +47635,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47080,9 +47707,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -47095,9 +47719,6 @@ msgstr[2] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -47158,6 +47779,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -47167,9 +47794,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -47251,6 +47875,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47488,12 +48118,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47569,6 +48214,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47599,6 +48247,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47614,6 +48265,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47689,6 +48343,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47749,6 +48406,9 @@ msgstr[2] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47908,6 +48568,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -48010,12 +48673,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -48037,6 +48706,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -48061,12 +48733,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -48226,9 +48904,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48379,6 +49054,9 @@ 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 ""
@@ -48475,9 +49153,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48541,6 +49216,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48553,9 +49231,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48574,9 +49258,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48625,9 +49306,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48646,18 +49324,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48790,9 +49465,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48814,12 +49486,21 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48976,6 +49657,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -49114,6 +49798,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/sr_SP/gitlab.po b/locale/sr_SP/gitlab.po
index e70bc29509a..8ede4d795dd 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: 2022-10-10 13:59\n"
+"PO-Revision-Date: 2022-11-13 09:20\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -157,6 +157,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -277,24 +283,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -307,12 +301,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -595,6 +583,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -652,6 +643,18 @@ msgstr[2] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -661,6 +664,12 @@ msgstr[2] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%{count} more"
msgstr ""
@@ -685,6 +694,12 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -724,9 +739,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -937,12 +949,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1135,6 +1141,9 @@ msgstr[2] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1285,9 +1294,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1345,6 +1351,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1384,6 +1393,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1696,6 +1708,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1759,9 +1774,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1840,9 +1852,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -2050,6 +2059,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2161,15 +2173,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2239,9 +2245,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2614,6 +2617,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2797,6 +2806,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2833,15 +2860,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2890,6 +2929,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2935,6 +2977,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -3073,9 +3127,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -3100,6 +3163,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3202,6 +3274,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3394,7 +3469,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3439,7 +3514,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3502,7 +3577,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3550,6 +3625,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -4060,7 +4138,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -4075,6 +4153,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -4111,9 +4192,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4360,6 +4438,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4546,9 +4627,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4648,9 +4726,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4753,9 +4828,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4774,7 +4846,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4819,6 +4891,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4837,9 +4912,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4867,6 +4951,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5212,9 +5299,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5317,7 +5401,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5368,6 +5452,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5419,9 +5527,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5818,9 +5923,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6184,6 +6286,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6916,6 +7024,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6925,6 +7036,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6946,6 +7060,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6964,6 +7081,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6973,6 +7093,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6991,9 +7114,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -7012,12 +7141,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7177,6 +7315,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7186,9 +7327,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7234,9 +7372,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7267,6 +7402,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7282,6 +7420,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7306,9 +7447,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7723,9 +7861,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7741,6 +7876,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8482,6 +8620,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9799,10 +9940,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9985,6 +10132,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10783,10 +10933,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10819,6 +10969,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10867,9 +11026,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10954,9 +11110,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -11119,9 +11272,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11341,9 +11491,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11611,9 +11758,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11629,7 +11773,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11731,9 +11875,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -12061,6 +12202,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -12088,6 +12232,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -12145,6 +12292,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12379,6 +12529,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12598,6 +12751,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12685,6 +12841,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12718,6 +12877,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12829,6 +12991,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12850,9 +13015,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12919,7 +13081,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13402,6 +13564,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13489,6 +13654,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13831,6 +14011,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -14071,6 +14254,12 @@ msgstr[2] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -14086,12 +14275,18 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14698,6 +14893,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -15028,22 +15229,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Using a static site?"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15271,6 +15490,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15451,10 +15673,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15469,18 +15691,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15493,18 +15706,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15634,9 +15841,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15700,9 +15904,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15943,6 +16144,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -16063,6 +16315,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -16120,9 +16375,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16348,6 +16609,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16396,9 +16660,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16594,9 +16855,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16855,6 +17113,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16960,9 +17221,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -17170,6 +17428,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -18007,9 +18268,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -18136,6 +18394,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18187,6 +18451,9 @@ 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 ""
@@ -18235,9 +18502,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18793,9 +19057,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18805,6 +19066,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19567,12 +19831,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19642,6 +19900,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19822,9 +20083,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20281,7 +20539,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20368,12 +20632,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -22129,6 +22387,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -22147,9 +22408,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22207,7 +22465,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22288,19 +22546,16 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22438,12 +22693,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22465,6 +22726,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22690,6 +22963,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22984,6 +23272,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23314,6 +23605,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23353,9 +23647,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23734,9 +24034,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23890,6 +24187,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24040,9 +24346,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24295,6 +24598,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24565,9 +24874,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24580,6 +24886,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24616,7 +24925,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24631,9 +24946,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24643,9 +24964,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24655,7 +24973,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24712,6 +25030,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24736,6 +25057,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24787,6 +25111,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24799,6 +25126,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25429,6 +25759,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25654,6 +25987,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -26047,6 +26383,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26206,6 +26545,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26278,6 +26620,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26464,6 +26809,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26926,6 +27274,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -27055,9 +27406,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -27085,9 +27433,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -27103,9 +27448,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27340,7 +27682,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27679,6 +28021,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27688,6 +28033,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27709,6 +28057,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27802,9 +28153,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27829,9 +28177,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -28066,12 +28411,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28117,12 +28456,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28144,12 +28477,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28192,15 +28519,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28231,12 +28549,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28255,9 +28567,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28432,9 +28741,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28804,12 +29110,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28855,6 +29170,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -29002,6 +29323,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29386,12 +29710,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29440,7 +29758,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29659,6 +29977,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29674,6 +29995,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29686,12 +30010,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29701,9 +30031,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30463,9 +30799,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30574,6 +30907,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30715,6 +31111,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30808,12 +31207,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31390,6 +31795,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31402,6 +31810,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31684,12 +32095,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31702,12 +32119,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31729,6 +32152,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31828,6 +32254,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31966,6 +32395,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31996,6 +32428,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -32047,6 +32482,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32686,6 +33124,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32722,15 +33163,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32746,12 +33199,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -33061,6 +33523,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33193,12 +33658,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33292,9 +33751,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33460,6 +33916,9 @@ msgstr[2] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33469,6 +33928,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33925,6 +34387,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33940,12 +34405,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33976,18 +34435,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34000,12 +34453,6 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -34048,21 +34495,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34078,9 +34516,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34456,6 +34891,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34687,6 +35125,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34726,6 +35167,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34756,7 +35200,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34966,6 +35410,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -35095,9 +35542,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -35146,6 +35599,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -35182,6 +35638,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -35221,12 +35680,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35281,16 +35734,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35398,10 +35857,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35422,9 +35881,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35434,9 +35899,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35587,9 +36058,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -36007,10 +36475,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -36130,6 +36601,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36232,10 +36706,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36325,7 +36799,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36343,6 +36817,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36361,12 +36838,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36388,6 +36874,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36517,6 +37006,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36574,6 +37066,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36691,9 +37186,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36706,6 +37207,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36769,9 +37273,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36910,10 +37411,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36925,28 +37426,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37165,9 +37666,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37318,9 +37816,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37576,10 +38071,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37633,7 +38125,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37648,7 +38140,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37771,9 +38263,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37996,6 +38485,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38107,9 +38599,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38683,9 +39172,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38698,9 +39184,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38722,9 +39205,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39244,9 +39724,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39505,6 +39991,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39595,6 +40084,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39679,6 +40171,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39700,15 +40195,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39730,9 +40219,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39751,6 +40237,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39862,18 +40351,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39895,12 +40372,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39988,12 +40459,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40453,6 +40918,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40648,9 +41116,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40681,7 +41146,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40738,9 +41203,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -41092,9 +41554,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -41128,6 +41587,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41296,9 +41758,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41359,6 +41818,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41575,13 +42037,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41710,9 +42175,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41731,6 +42193,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42103,9 +42568,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42211,6 +42673,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42277,9 +42742,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42301,18 +42790,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42325,6 +42835,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42475,9 +43003,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42799,6 +43324,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43303,6 +43834,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43405,6 +43942,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43435,6 +43975,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44488,9 +45031,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44953,6 +45493,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44971,6 +45514,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -45106,7 +45652,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45148,6 +45694,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -45163,12 +45712,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45208,6 +45769,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45322,6 +45886,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45349,9 +45919,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45364,7 +45931,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45376,12 +45943,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45460,6 +46036,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45469,7 +46048,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45787,6 +46366,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45838,9 +46423,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45871,10 +46471,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45886,6 +46489,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45907,6 +46513,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45925,6 +46534,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -46021,6 +46633,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -46057,6 +46672,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46102,9 +46723,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -46207,6 +46825,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46279,7 +46900,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46303,6 +46924,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46447,6 +47071,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46510,7 +47137,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46678,9 +47305,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46792,6 +47416,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46912,16 +47539,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47011,6 +47635,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47080,9 +47707,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -47095,9 +47719,6 @@ msgstr[2] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -47158,6 +47779,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -47167,9 +47794,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -47251,6 +47875,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47488,12 +48118,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47569,6 +48214,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47599,6 +48247,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47614,6 +48265,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47689,6 +48343,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47749,6 +48406,9 @@ msgstr[2] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47908,6 +48568,9 @@ msgstr[0] ""
msgstr[1] ""
msgstr[2] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -48010,12 +48673,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -48037,6 +48706,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -48061,12 +48733,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -48226,9 +48904,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48379,6 +49054,9 @@ 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 ""
@@ -48475,9 +49153,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48541,6 +49216,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48553,9 +49231,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48574,9 +49258,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48625,9 +49306,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48646,18 +49324,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48790,9 +49465,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48814,12 +49486,21 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48976,6 +49657,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -49114,6 +49798,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/sv_SE/gitlab.po b/locale/sv_SE/gitlab.po
index a25bd260db4..076a7df4700 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: 2022-10-10 13:59\n"
+"PO-Revision-Date: 2022-11-13 09:20\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d godkännare"
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] "%d epic"
msgstr[1] "%d epics"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d fel"
-msgstr[1] "%d fel"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] "%d misslyckat säkerhetsjobb"
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] "%d fil"
msgstr[1] "%d filer"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr "%{count} fler"
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} deltagare"
msgstr[1] "%{count} deltagare"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} relaterade %{pluralized_subject}: %{links}"
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr "%{due_date} (förfallen)"
-
msgid "%{duration}ms"
msgstr "%{duration}ms"
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr "%{name} (Upptagen)"
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} innehöll %{resultsString}"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} hittade %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr "%{name} används redan för en annan emoji"
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr "(max storlek 15 MB)"
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr "En raderad användare"
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr "Skapa ny fil eller katalog"
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Using a static site?"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr "Gravatar"
@@ -18627,6 +18886,9 @@ msgstr "Gravatar aktiverat"
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/sw_KE/gitlab.po b/locale/sw_KE/gitlab.po
index 5986a004f5d..3e905fac9a6 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: 2022-10-10 14:04\n"
+"PO-Revision-Date: 2022-11-13 09:24\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/ta_IN/gitlab.po b/locale/ta_IN/gitlab.po
index 5d225586e07..b59208a7626 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: 2022-10-10 14:00\n"
+"PO-Revision-Date: 2022-11-13 09:21\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/th_TH/gitlab.po b/locale/th_TH/gitlab.po
index 565627b2b95..971845cdf03 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: 2022-10-10 14:01\n"
+"PO-Revision-Date: 2022-11-13 09:21\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -129,6 +129,10 @@ msgid "%d additional user"
msgid_plural "%d additional users"
msgstr[0] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -209,18 +213,10 @@ msgid "%d epic"
msgid_plural "%d epics"
msgstr[0] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -229,10 +225,6 @@ msgid "%d file"
msgid_plural "%d files"
msgstr[0] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -431,6 +423,9 @@ msgid "%{bold_start}%{count}%{bold_end} opened merge request"
msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -482,6 +477,14 @@ msgstr[0] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -489,6 +492,10 @@ msgstr[0] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+
msgid "%{count} more"
msgstr ""
@@ -509,6 +516,10 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -548,9 +559,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -761,12 +769,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -945,6 +947,9 @@ msgstr[0] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1079,9 +1084,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1139,6 +1141,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1176,6 +1181,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1434,6 +1442,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1497,9 +1508,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1578,9 +1586,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1788,6 +1793,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -1899,15 +1907,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -1977,9 +1979,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2352,6 +2351,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2535,6 +2540,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2571,15 +2594,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2628,6 +2663,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2673,6 +2711,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2811,9 +2861,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2838,6 +2897,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -2940,6 +3008,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3132,7 +3203,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3177,7 +3248,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3240,7 +3311,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3288,6 +3359,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3798,7 +3872,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3813,6 +3887,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3849,9 +3926,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4098,6 +4172,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4282,9 +4359,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4384,9 +4458,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4489,9 +4560,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4510,7 +4578,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4551,6 +4619,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4569,9 +4640,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4599,6 +4679,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -4934,9 +5017,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5037,7 +5117,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5088,6 +5168,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5139,9 +5243,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5532,9 +5633,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -5898,6 +5996,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6622,6 +6726,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6631,6 +6738,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6652,6 +6762,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6670,6 +6783,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6679,6 +6795,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6697,9 +6816,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6718,12 +6843,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -6883,6 +7017,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -6892,9 +7029,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -6940,9 +7074,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -6973,6 +7104,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -6988,6 +7122,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7012,9 +7149,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7427,9 +7561,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7445,6 +7576,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8182,6 +8316,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9495,10 +9632,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9679,6 +9822,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10471,10 +10617,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10507,6 +10653,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10555,9 +10710,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10642,9 +10794,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10807,9 +10956,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11029,9 +11175,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11299,9 +11442,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11317,7 +11457,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11419,9 +11559,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11747,6 +11884,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11774,6 +11914,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11831,6 +11974,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12065,6 +12211,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12282,6 +12431,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12369,6 +12521,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12402,6 +12557,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12513,6 +12671,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12534,9 +12695,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12603,7 +12761,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13074,6 +13232,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13161,6 +13322,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13499,6 +13675,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13735,6 +13914,12 @@ msgstr[0] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13750,10 +13935,16 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14358,6 +14549,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14688,22 +14885,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -14931,6 +15146,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15111,10 +15329,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15129,18 +15347,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15153,18 +15362,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15294,9 +15497,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15360,9 +15560,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15603,6 +15800,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15721,6 +15969,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15778,9 +16029,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16004,6 +16261,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16050,9 +16310,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16248,9 +16505,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16507,6 +16761,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16612,9 +16869,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16822,6 +17076,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17651,9 +17908,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17780,6 +18034,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -17831,6 +18091,9 @@ 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 ""
@@ -17879,9 +18142,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18437,9 +18697,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18449,6 +18706,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19211,12 +19471,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19286,6 +19540,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19462,9 +19719,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -19917,7 +20171,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20004,12 +20264,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21757,6 +22011,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21775,9 +22032,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -21835,7 +22089,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -21914,19 +22168,16 @@ msgid "InviteMembersModal|The following member couldn't be invited"
msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22064,12 +22315,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22091,6 +22348,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22316,6 +22585,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22610,6 +22894,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -22940,6 +23227,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -22979,9 +23269,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23356,9 +23652,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23512,6 +23805,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23662,9 +23964,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -23905,6 +24204,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24175,9 +24480,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24190,6 +24492,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24226,7 +24531,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24241,9 +24552,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24253,9 +24570,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24265,7 +24579,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24322,6 +24636,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24346,6 +24663,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24397,6 +24717,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24409,6 +24732,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25035,6 +25361,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25260,6 +25589,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25649,6 +25981,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -25808,6 +26143,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -25880,6 +26218,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26066,6 +26407,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26524,6 +26868,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26653,9 +27000,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26683,9 +27027,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26701,9 +27042,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -26936,7 +27274,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27267,6 +27605,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27276,6 +27617,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27297,6 +27641,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27390,9 +27737,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27417,9 +27761,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27652,12 +27993,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27703,12 +28038,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27730,12 +28059,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27778,15 +28101,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -27817,12 +28131,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -27841,9 +28149,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28016,9 +28321,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28386,12 +28688,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28437,6 +28748,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28582,6 +28899,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -28964,12 +29284,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29018,7 +29332,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29237,6 +29551,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29252,6 +29569,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29264,12 +29584,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29279,9 +29605,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30041,9 +30373,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30152,6 +30481,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30293,6 +30685,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30386,12 +30781,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -30968,6 +31369,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -30980,6 +31384,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31262,12 +31669,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31280,12 +31693,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31307,6 +31726,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31406,6 +31828,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31544,6 +31969,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31574,6 +32002,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31625,6 +32056,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32264,6 +32698,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32300,15 +32737,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32324,12 +32773,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32639,6 +33097,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32771,12 +33232,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -32870,9 +33325,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33034,6 +33486,9 @@ msgstr[0] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33043,6 +33498,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33499,6 +33957,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33512,10 +33973,6 @@ msgid "Reports|%{recentlyFailed} out of %{failed} failed tests has failed more t
msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days"
msgstr[0] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33544,18 +34001,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33564,12 +34015,6 @@ msgid "Reports|Failed %{count} time in %{base_branch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 days"
msgstr[0] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33612,21 +34057,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33642,9 +34078,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34012,6 +34445,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34239,6 +34675,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34276,6 +34715,9 @@ msgid "Runners|%d selected runner deleted"
msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34302,7 +34744,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34510,6 +34952,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34637,9 +35082,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34688,6 +35139,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34722,6 +35176,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34761,12 +35218,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -34821,16 +35272,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -34938,10 +35395,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -34962,9 +35419,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -34974,9 +35437,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35127,9 +35596,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35525,10 +35991,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35648,6 +36117,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35750,10 +36222,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -35843,7 +36315,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -35861,6 +36333,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -35879,12 +36354,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -35906,6 +36390,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36035,6 +36522,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36092,6 +36582,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36209,9 +36702,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36224,6 +36723,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36287,9 +36789,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36428,10 +36927,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36443,28 +36942,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36683,9 +37182,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -36834,9 +37330,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37090,10 +37583,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37147,7 +37637,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37162,7 +37652,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37285,9 +37775,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37510,6 +37997,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37621,9 +38111,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38197,9 +38684,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38212,9 +38696,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38236,9 +38717,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -38758,9 +39236,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39017,6 +39501,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39107,6 +39594,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39191,6 +39681,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39212,15 +39705,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39242,9 +39729,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39263,6 +39747,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39374,14 +39861,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39399,12 +39878,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39492,12 +39965,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -39947,6 +40414,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40142,9 +40612,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40175,7 +40642,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40232,9 +40699,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40586,9 +41050,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40622,6 +41083,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -40790,9 +41254,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -40853,6 +41314,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41069,13 +41533,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41204,9 +41671,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41225,6 +41689,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41593,9 +42060,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41701,6 +42165,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -41767,9 +42234,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -41791,18 +42282,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -41815,6 +42327,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -41965,9 +42495,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42287,6 +42814,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -42791,6 +43324,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -42893,6 +43432,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -42923,6 +43465,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -43970,9 +44515,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44433,6 +44975,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44451,6 +44996,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44586,7 +45134,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44628,6 +45176,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44643,12 +45194,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44688,6 +45251,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -44802,6 +45368,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -44829,9 +45401,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -44844,7 +45413,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -44856,12 +45425,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -44940,6 +45518,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -44949,7 +45530,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45263,6 +45844,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45312,9 +45899,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45345,10 +45947,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45360,6 +45965,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45381,6 +45989,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45399,6 +46010,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45493,6 +46107,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45529,6 +46146,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45574,9 +46197,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45677,6 +46297,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -45749,7 +46372,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -45773,6 +46396,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -45915,6 +46541,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -45978,7 +46607,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46146,9 +46775,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46260,6 +46886,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46376,16 +47005,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46473,6 +47099,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46542,9 +47171,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46555,9 +47181,6 @@ msgstr[0] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46616,6 +47239,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46625,9 +47254,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46707,6 +47333,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -46936,12 +47568,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47015,6 +47662,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47045,6 +47695,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47060,6 +47713,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47133,6 +47789,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47191,6 +47850,9 @@ msgstr[0] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47344,6 +48006,9 @@ msgid "from %d job"
msgid_plural "from %d jobs"
msgstr[0] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47442,12 +48107,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47469,6 +48140,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47493,12 +48167,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47652,9 +48332,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -47801,6 +48478,9 @@ 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 ""
@@ -47897,9 +48577,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -47963,6 +48640,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -47975,9 +48655,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -47996,9 +48682,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48047,9 +48730,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48068,16 +48748,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48204,9 +48883,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48226,12 +48902,19 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48386,6 +49069,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48520,6 +49206,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/tr_TR/gitlab.po b/locale/tr_TR/gitlab.po
index 21930809973..cf8c0d4e562 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: 2022-10-10 13:59\n"
+"PO-Revision-Date: 2022-11-13 09:20\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d onaylayan"
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d hata"
-msgstr[1] "%d hata"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d dışa aktaran"
msgstr[1] "%d dışa aktaran"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%d başarısız"
-msgstr[1] "%d başarısız"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] "%d güvenlik işi başarısız oldu"
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] "%d dosya"
msgstr[1] "%d dosya"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d sabit test sonucu"
-msgstr[1] "%d sabit test sonucu"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr "%{count} dosyaya dokunuldu"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr "sayfa başına %{count} öğe"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr "%{count} daha"
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] "%{count} katılımcı"
msgstr[1] "%{count} katılımcı"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr "%{duration}ms"
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr "%{name} (MeÅŸgul)"
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} %{resultsString} ifadesini içeriyor"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} bulundu %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr "%{name} zaten başka bir ifade için kullanılıyor"
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "%{strong_start}%{branch_count}%{strong_end} Dal"
@@ -1182,9 +1189,6 @@ msgstr "%{user} bir sorun oluÅŸturdu: %{issue_link}"
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr "%{value} s"
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} %{time_spent_value} zaman harcandı."
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d kapandı)"
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr "(en yüksek boyut 15 MB)"
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr "Bu sayfaya eriÅŸim izniniz yok."
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "Adresin doğru olduğundan ve sayfanın taşınmadığından emin olun."
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr "Sayfa Bulunamadı"
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "Boş bir proje için bir varsayılan dal seçilemez."
-
msgid "A deleted user"
msgstr "Silinmiş kullanıcı"
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr "Bir platform deÄŸeri web, mobil veya uygulama olabilir."
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr "Şartları kabul et"
msgid "Acceptable for use in this project"
msgstr "Bu projede kullanım için kabul edilebilir"
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr "Daha fazlasını öğren"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "Mesaj: %{message}"
-msgid "AccessibilityReport|New"
-msgstr "Yeni"
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr "Etkin"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr "Etkin Oturumlar"
@@ -2483,6 +2484,12 @@ msgstr "%{labels} %{label_text} ekler."
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr "İstatistikler yüklenirken hata oluştu. Lütfen tekrar deneyin"
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr "Otomatik DevOps etki alanı"
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr "Yeni projeler için paylaşılan çalıştırıcıları etkinleştir"
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr "Yöneticiler"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr "Onayla"
@@ -3263,8 +3336,8 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
-msgstr "İsme, e-postaya veya kullanıcı adına göre ara"
+msgid "AdminUsers|Search by name, email, or username"
+msgstr ""
msgid "AdminUsers|Search users"
msgstr "Kullanıcıları ara"
@@ -3308,8 +3381,8 @@ msgstr "Kullanıcı herhangi bir bildirim almayacak"
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "Onaylamak için, %{projectName} yazın"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "Onaylamak için, %{username} yazın"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr ""
msgid "AdminUsers|Unban user"
msgstr ""
@@ -3371,7 +3444,7 @@ msgstr "Projeler olmadan"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr "Yönetim"
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,8 +4005,8 @@ msgstr "Tüm kullanıcıların bir adı olmalıdır."
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
-msgstr "\"%{group_name}\" grubunun oturum açmasına izin ver"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr ""
msgid "Allow access to members of the following group"
msgstr ""
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr "Grup sahiplerinin LDAP ile ilgili ayarları yönetmesine izin ver"
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr "Kullanıcıların yayın mesajını kapatmalarına izin ver"
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr "Terraform raporu alınırken bir hata oluştu."
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr "İş kayıtları alınırken bir hata oluştu."
@@ -4414,9 +4493,6 @@ msgstr "Ä°ÅŸ tetiklenirken bir hata oluÅŸtu."
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr "Analizler"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr "Uygulama ayarları güncellemesi başarısız oldu"
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr "Uygulama başarıyla imha edildi."
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ 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 these artifacts?"
-msgstr "Bu artifact'ları silmek istediğinize emin misiniz?"
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr "Artifact başarıyla silindi."
msgid "Artifacts"
msgstr "Yapılar"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr "#FF0000 gibi özel renk ata"
msgid "Assign labels"
msgstr "Etiket tanımla"
-msgid "Assign milestone"
-msgstr "Kilometre taşı ata"
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ 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 enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr "Dal zaten alınmış"
msgid "Branch name"
msgstr "Dal adı"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr "Dal yüklü değil - %{branchId}"
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr "Yayın Mesajı başarıyla güncellendi."
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "Dizine Gözat"
@@ -7039,9 +7178,6 @@ msgstr "Dosyaya Gözat"
msgid "Browse Files"
msgstr "Dosyalara Gözat"
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr "Dosyalara gözat"
@@ -7087,9 +7223,6 @@ msgstr "Kaynak gruba göre filtrele"
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr "Otomatik olarak birleÅŸtirilemez"
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr "Yorumla/Yanıtla (seçilen metinden alıntıyla)"
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr "Katkı"
msgid "Contribution Analytics"
msgstr "Katkı Analizi"
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr "%{protocol} klon URL'sini kopyala"
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr "KimliÄŸi kopyala"
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr "Yeni dosya veya dizin oluÅŸtur"
msgid "Create new label"
msgstr "Yeni etiket oluÅŸtur"
-msgid "Create new project"
-msgstr "Yeni proje oluÅŸtur"
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr "Epik oluÅŸturuluyor"
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr "Mevcut Proje"
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr "KiÅŸisel"
msgid "DashboardProjects|Trending"
msgstr "Öne Çıkanlar"
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr "Sil"
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr "Sona Eriyor"
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Değişiklik çizgileri alırken bir şeyler ters gitti."
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr "%{timeago} düzenlendi"
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr "Düzenleme"
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Copy snippet"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|Close"
-msgstr "Kapat"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr ""
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr ""
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr "Ä°ÅŸlem"
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr "Sil"
@@ -15281,10 +15501,10 @@ msgstr "Yeni epik ekle"
msgid "Epics|Add an existing epic"
msgstr "Mevcut bir epiÄŸi ekle"
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr "EpiÄŸi sil"
msgid "Epics|Remove issue"
msgstr "Sorunu sil"
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr "Daha fazlasını göster"
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr "Epiğe sorun atama sırasında bir şeyler ters gitti."
-
msgid "Epics|Something went wrong while creating child epics."
msgstr "Alt epikler oluÅŸturulurken bir ÅŸeyler ters gitti."
@@ -15323,18 +15534,12 @@ msgstr "Alt epikler alınırken bir şeyler ters gitti."
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr "Grup epikleri alınırken bir şeyler ters gitti."
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr "Öge sıralanırken bir şeyler ters gitti."
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr "Epikten sorun kaldırılırken bir şeyler ters gitti."
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr "Vekiller kaydedilirken bir hata oluÅŸtu"
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr "Birleştirme isteğini yüklerken hata oluştu. Lütfen tekrar deneyin."
@@ -15773,6 +15972,57 @@ msgstr "Etkinlikler"
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr "Birleştirme işlemleri hariç tutuluyor. 6,000 işlem ile sınırlı."
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr "Mevcut dal adı, etiketi veya işlem SHA"
@@ -15949,9 +16202,15 @@ msgstr "Kenar çubuğunu genişlet"
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr "Süre sonu"
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr "Jira içe aktarımı için içe aktarma etiketi oluşturulamadı."
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr "Depo oluşturulamadı"
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr "Åžub"
msgid "February"
msgstr "Åžubat"
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr "Dönüm noktası adına göre filtrele"
@@ -16996,6 +17252,9 @@ msgstr "Daha fazla bilgi için şu adrese gidin: "
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr "Åžifrenizi mi unuttunuz?"
@@ -17829,9 +18088,6 @@ msgstr "ikincil"
msgid "Get a free instance review"
msgstr "Ücretsiz bir örnek incelemesi alın"
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr "Gravatar"
@@ -18627,6 +18886,9 @@ msgstr "Gravatar etkinleÅŸtirildi"
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr "Aramanızla eşleşen grup yok"
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr "Aramanız ile eşleşen grup veya proje yok"
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr "Sistem durumu bilgileri aşağıdaki uç noktalardan alınabilir. Daha f
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr "Geçersiz iki adımlı doğrulama kodu."
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr "Konu"
@@ -22503,6 +22774,21 @@ msgstr "Aramanızı genişletmek için yukarıdaki süzgeç çubuğundaki süzge
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr "Başlık"
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr "Ä°ndir"
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr "Projeden ayrıl"
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr "BÄ°RLEÅžTÄ°RÄ°LDÄ°"
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr "Mar"
msgid "March"
msgstr "Mart"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr "Bitti olarak iÅŸaretle"
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr "Gösterilecek yineleme yok"
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr "Eki"
msgid "October"
msgstr "Ekim"
-msgid "OfSearchInADropdown|Filter"
-msgstr "Süzgeç"
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr "Üzgünüz, filtreniz sonuç vermedi"
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr "Etkin"
msgid "PipelineSchedules|All"
msgstr "Tümü"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr "Etkin deÄŸil"
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr "Sonraki çalışma"
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "Bu iş hattı için kısa bir açıklama girin"
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr "SahipliÄŸi al"
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr "Hedef"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr "Lütfen bir ülke seçin"
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr "Tercihler"
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr "Proje adı"
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr "Proje kullanıcı adı"
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr "Rozetler"
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr "Daha fazlasını öğrenin."
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr "Devamını oku"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr "İlgili sorunlar hakkında daha fazla bilgi edinin"
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr "Sistem çıkışı"
-
msgid "Reports|Test summary"
msgstr "Test özeti"
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr "deÄŸiÅŸtirilmiÅŸ test sonucu yok"
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr "%{name} tarafından çözüldü"
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr "Temizlik hizmetini çalıştır"
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr ""
+
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr "Metrikleri gör"
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr "Zaman dilimini seçin"
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr "Ayarlar"
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr "Önem"
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr "Tüm sorunlar gösteriliyor"
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr "2FA kodu ile oturum açın"
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr "Durum:"
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "Dal/etiketi deÄŸiÅŸtir"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr "GitLab Next'e geçin"
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr "Sürüm notları"
-
msgid "TagsPage|Repository has no tags yet."
msgstr "Depo için henüz etiket eklenmemiş."
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "Sürüm notlarınızı yazın veya dosyaları buraya sürükleyin…"
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr "korumalı"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr "Hedef Dal"
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr "Bu kullanıcının kimliği yok"
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr "Bugün"
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr "Toplam Katkı"
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
msgstr "Kullanım istatistikleri"
+msgid "UsageQuotas|The project-level storage statistics for the Container Registry are directional only and do not include savings for instance-wide deduplication."
+msgstr ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr "Paketler"
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr "Depo"
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr "Yenilikler"
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr "YouTube"
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr "%{host} hesabınıza yeni bir konumdan giriş yapıldı"
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr "Hesabınız kilitlendi."
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr "Adınız"
-msgid "Your new %{accessTokenType}"
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{accessTokenType} has been created."
-msgstr ""
-
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr "silinmiş bir kullanıcı"
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr "kendinizi atayın"
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr "yeni bir dosya ekle"
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr "Çözmek için yama indirin"
msgid "ciReport|Download the patch to apply it manually"
msgstr "Elle uygulamak için yamayı indirin"
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr "Güvenlik taraması"
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr "Çözüm"
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] "gün"
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr "varsayılan dal"
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr "Onayı iptal et"
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr "dikkat gerekli"
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr "veya"
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "ebeveyn"
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr "ağırlığı kaldır"
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr "bu belge"
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr "yaml geçersiz"
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/uk/gitlab.po b/locale/uk/gitlab.po
index d70773216ae..ba4a6611f00 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: 2022-10-10 13:59\n"
+"PO-Revision-Date: 2022-11-13 09:20\n"
msgid " %{start} to %{end}"
msgstr " %{start} до %{end}"
@@ -171,6 +171,13 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+msgstr[2] ""
+msgstr[3] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d затверджуюча оÑоба"
@@ -311,13 +318,6 @@ msgstr[1] "%d епіка"
msgstr[2] "%d епіки"
msgstr[3] "%d епіків"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d помилка"
-msgstr[1] "%d помилки"
-msgstr[2] "%d помилок"
-msgstr[3] "%d помилок"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d екÑпортер"
@@ -325,13 +325,6 @@ msgstr[1] "%d екÑпортера"
msgstr[2] "%d екÑпортерів"
msgstr[3] "%d екÑпортерів"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%d невдало"
-msgstr[1] "%d невдалих"
-msgstr[2] "%d невдалих"
-msgstr[3] "%d невдалих"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -346,13 +339,6 @@ msgstr[1] "%d файла"
msgstr[2] "%d файлів"
msgstr[3] "%d файлів"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d виправлений результат теÑту"
-msgstr[1] "%d виправлені результати теÑту"
-msgstr[2] "%d виправлених результатів теÑту"
-msgstr[3] "%d виправлених результатів теÑту"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] "%d форк"
@@ -537,10 +523,10 @@ msgstr[3] "%d Ñекунд"
msgid "%d stage"
msgid_plural "%d stages"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "%d ÑтадіÑ"
+msgstr[1] "%d Ñтадії"
+msgstr[2] "%d Ñтадій"
+msgstr[3] "%d Ñтадій"
msgid "%d star"
msgid_plural "%d stars"
@@ -677,6 +663,9 @@ msgstr[1] "%{bold_start}%{count}%{bold_end} відкритих запитів н
msgstr[2] "%{bold_start}%{count}%{bold_end} відкритих запитів на злиттÑ"
msgstr[3] "%{bold_start}%{count}%{bold_end} відкритих запитів на злиттÑ"
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr "%{code_open}ЗамаÑковано:%{code_close} Сховано в журналах завдань. Повинні відповідати вимогам до маÑкуваннÑ."
@@ -737,6 +726,20 @@ msgstr[3] "%{count} контактів"
msgid "%{count} files touched"
msgstr "%{count} файлів змінено"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] "%{count} група"
+msgstr[1] "%{count} групи"
+msgstr[2] "%{count} груп"
+msgstr[3] "%{count} груп"
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] "%{count} задача"
+msgstr[1] "%{count} задачі"
+msgstr[2] "%{count} задач"
+msgstr[3] "%{count} задач"
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "%{count} елемент"
@@ -747,6 +750,13 @@ msgstr[3] "%{count} елементів"
msgid "%{count} items per page"
msgstr "%{count} елементів на Ñторінці"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] "%{count} запит на злиттÑ"
+msgstr[1] "%{count} запити на злиттÑ"
+msgstr[2] "%{count} запитів на злиттÑ"
+msgstr[3] "%{count} запитів на злиттÑ"
+
msgid "%{count} more"
msgstr "%{count} більше"
@@ -773,6 +783,13 @@ msgstr[1] "%{count} учаÑтника"
msgstr[2] "%{count} учаÑтників"
msgstr[3] "%{count} учаÑтників"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] "%{count} проєкт"
+msgstr[1] "%{count} проєкти"
+msgstr[2] "%{count} проєктів"
+msgstr[3] "%{count} проєктів"
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} пов’Ñзаних %{pluralized_subject}: %{links}"
@@ -812,9 +829,6 @@ msgstr "%{docs_link_start}Що таке Ñховище великих файлі
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr "%{docs_link_start} Що таке Двофакторна автентифікаціÑ?%{docs_link_end}"
-msgid "%{due_date} (Past due)"
-msgstr "%{due_date} (з проÑтроченнÑм)"
-
msgid "%{duration}ms"
msgstr "%{duration}мÑ"
@@ -1017,20 +1031,14 @@ msgid "%{mrText}, this issue will be closed automatically."
msgstr "%{mrText}, Ñ†Ñ Ð·Ð°Ð´Ð°Ñ‡Ð° буде закрита автоматично."
msgid "%{name_with_link} namespace has %{percent} or less Shared Runner Pipeline minutes remaining. Once it runs out, no new jobs or pipelines in its projects will run."
-msgstr "%{name_with_link} проÑÑ‚Ñ–Ñ€ імен %{percent} або менше хвилин загальних ранерів. ПіÑÐ»Ñ Ñ‚Ð¾Ð³Ð¾, Ñк він закінчитьÑÑ, нові Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð°Ð±Ð¾ конвеєри в його проєктах не працюватимуть."
+msgstr "%{name_with_link} проÑÑ‚Ñ–Ñ€ імен %{percent} або менше хвилин загальних раннерів. ПіÑÐ»Ñ Ñ‚Ð¾Ð³Ð¾, Ñк він закінчитьÑÑ, нові Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð°Ð±Ð¾ конвеєри в його проєктах не працюватимуть."
msgid "%{name_with_link} namespace has run out of Shared Runner Pipeline minutes. No new jobs or pipelines in its projects will run."
-msgstr "%{name_with_link} у проÑторі імен вичерпано хвилин загальних ранерів конвеєра. Ðових завдань у проєктах не буде."
+msgstr "%{name_with_link} у проÑторі імен вичерпано хвилин загальних раннерів конвеєра. Ðових завдань у проєктах не буде."
msgid "%{name} (Busy)"
msgstr "%{name} (зайнÑто)"
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} міÑтить %{resultsString}"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} знайдено %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr "%{name} вже викориÑтовуєтьÑÑ Ð´Ð»Ñ Ñ–Ð½ÑˆÐ¾Ð³Ð¾ емодзі"
@@ -1044,10 +1052,10 @@ msgid "%{name}'s avatar"
msgstr "Ðватар %{name}"
msgid "%{name}(%{url}) namespace has %{percent} or less Shared Runner Pipeline minutes remaining. After it runs out, no new jobs or pipelines in its projects will run."
-msgstr ""
+msgstr "%{name}(%{url}) ПроÑÑ‚Ñ–Ñ€ імен має %{percent}або менше хвилин, що залишилиÑÑ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ð° Ñпільних раннерів. ПіÑÐ»Ñ Ñ‚Ð¾Ð³Ð¾, Ñк він закінчитьÑÑ, нові Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð°Ð±Ð¾ конвеєри в його проєктах не будуть запущені."
msgid "%{name}(%{url}) namespace has run out of Shared Runner Pipeline minutes so no new jobs or pipelines in its projects will run."
-msgstr "%{name}(%{url}) проÑÑ‚Ñ–Ñ€ імен вичерпавÑÑ Ñƒ хвилинах конвеєра загальних ранерів, тому нові Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð½Ðµ запуÑкатимутьÑÑ Ð² Ñвоїх проєктах."
+msgstr "%{name}(%{url}) проÑÑ‚Ñ–Ñ€ імен вичерпавÑÑ Ñƒ хвилинах конвеєра загальних раннерів, тому нові Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð½Ðµ запуÑкатимутьÑÑ Ð² Ñвоїх проєктах."
msgid "%{name}, confirm your email address now!"
msgstr "%{name}, підтвердіть Ñвою адреÑу електронної пошти зараз!"
@@ -1230,6 +1238,9 @@ msgstr[3] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr "%{strongStart}Порада:%{strongEnd}Ви також можете перевірÑти запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¾, %{linkStart}ДізнатиÑÑŒ більше%{linkEnd}"
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr "%{strong_open}%{group_name}%{strong_close} проєкти:"
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "%{strong_start}%{branch_count}%{strong_end} Гілка"
@@ -1267,10 +1278,10 @@ msgstr[3] ""
msgid "%{strong_start}%{errors}%{strong_end} point"
msgid_plural "%{strong_start}%{errors}%{strong_end} points"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "%{strong_start}%{errors}%{strong_end} бал"
+msgstr[1] "%{strong_start}%{errors}%{strong_end} бали"
+msgstr[2] "%{strong_start}%{errors}%{strong_end} балів"
+msgstr[3] "%{strong_start}%{errors}%{strong_end} балів"
msgid "%{strong_start}%{human_size}%{strong_end} Project Storage"
msgstr "%{strong_start}%{human_size}%{strong_end} Сховище проєкту"
@@ -1341,7 +1352,7 @@ msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr "%{total}знайдено Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ : показано перше%{warningsDisplayed}"
msgid "%{type} must be a %{help_link}"
-msgstr ""
+msgstr "%{type} має бути %{help_link}"
msgid "%{type} only supports %{name} name"
msgstr "%{type} підтримує лише %{name} ім'Ñ"
@@ -1388,9 +1399,6 @@ msgstr "%{user} Ñтворив задачу: %{issue_link}"
msgid "%{value} is not included in the list"
msgstr "%{value} не включено до ÑпиÑку"
-msgid "%{value} s"
-msgstr "%{value} Ñ"
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} %{time_spent_value} витрачено чаÑу."
@@ -1448,6 +1456,9 @@ msgstr "\"%{source}\" не є джерелом імпорту"
msgid "'%{template_name}' is unknown or invalid"
msgstr "\"%{template_name}\" невідомий або неправильний"
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d закрита)"
@@ -1488,6 +1499,9 @@ msgstr "(залишіть порожнім, Ñкщо ви не хочете зм
msgid "(max size 15 MB)"
msgstr "(макÑимальний розмір 15 Мб)"
+msgid "(no user)"
+msgstr "(нема кориÑтувача)"
+
msgid "(optional)"
msgstr "(необов'Ñзково)"
@@ -1827,6 +1841,9 @@ msgstr "У Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” доÑтупу до цієї Ñторінки."
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "Перевірте, що адреÑа правильна Ñ– те, що Ñторінка не переміщувалаÑÑ."
+msgid "404|Not found"
+msgstr "Ðе знайдено"
+
msgid "404|Page Not Found"
msgstr "Сторінка не знайдена"
@@ -1885,13 +1902,10 @@ msgid "A complete DevOps platform"
msgstr "Повноцінна DevOps платформа"
msgid "A confidential issue cannot have a parent that already has non-confidential children."
-msgstr ""
+msgstr "Конфіденційна задача не може мати батька, Ñкий вже має неконфіденційних дітей."
msgid "A confidential work item cannot have a parent that already has non-confidential children."
-msgstr ""
-
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "Ðе можна обирати уÑтавну гілку Ð´Ð»Ñ Ð¿Ð¾Ñ€Ð¾Ð¶Ð½ÑŒÐ¾Ð³Ð¾ проєкту."
+msgstr "Конфіденційний робочий елемент не може мати батьківÑького елемента, Ñкий уже має неконфіденційні дочірні елементи."
msgid "A deleted user"
msgstr "Видалений кориÑтувач"
@@ -1963,17 +1977,14 @@ msgid "A personal access token has been revoked"
msgstr "ПерÑональний токен було відкликано"
msgid "A personal access token, named %{code_start}%{token_name}%{code_end}, has been revoked."
-msgstr ""
+msgstr "ПерÑональний токен доÑтупу, %{code_start}%{token_name}%{code_end}було відкликано."
msgid "A personal access token, named %{token_name}, has been revoked."
-msgstr ""
+msgstr "ПерÑональний токен доÑтупу, з ім'Ñм %{token_name}було відкликано."
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr "Сайт на HTML, Ñкий викориÑтовує Netlify Ð´Ð»Ñ CI/CD заміÑÑ‚ÑŒ GitLab, але вÑе ще з уÑіма іншими чудовими функціÑми GitLab"
-msgid "A platform value can be web, mob or app."
-msgstr "Ð—Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ð»Ð°Ñ‚Ñ„Ð¾Ñ€Ð¼Ð¸ може бути веб, моб або заÑтоÑунок."
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr "Проєкт boilerplate Ð´Ð»Ñ Ñ€Ð¾Ð·Ñ€Ð¾Ð±ÐºÐ¸ заÑтоÑунку Salesforce з інÑтрументами розробника Salesforce"
@@ -2181,6 +2192,9 @@ msgstr "ПрийнÑти умови"
msgid "Acceptable for use in this project"
msgstr "Дозволений Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Ð² цьому проєкті"
+msgid "Access Denied"
+msgstr "ДоÑтуп Заборонено"
+
msgid "Access Git repositories or the API."
msgstr "ДоÑтуп до Git репозиторіїв або API."
@@ -2292,15 +2306,9 @@ msgstr "Ваш токен Ð´Ð»Ñ Ð²Ñ…Ñ–Ð´Ð½Ð¸Ñ… повідомлень елекÑ
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr "Ваш токен Ñтатичного об'єкта аутентифікує ваÑ, коли Ñтатичні об'єкти репозиторію (наприклад, архіви або великі об'єкти) обÑлуговуютьÑÑ Ñ–Ð· зовнішнього Ñховища."
-msgid "AccessibilityReport|Learn more"
-msgstr "ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "ПовідомленнÑ: %{message}"
-msgid "AccessibilityReport|New"
-msgstr "Ðовий"
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr "Перевірка доÑтупноÑÑ‚Ñ– виÑвила помилку такого типу: %{code}"
@@ -2329,10 +2337,10 @@ msgid "AccountValidation|Fix your pipelines by validating your account"
msgstr "Виправте Ñвої конвеєри, підтвердивши Ñвій обліковий запиÑ"
msgid "AccountValidation|I'll bring my own runners"
-msgstr "Я зареєÑтрую мої влаÑні ранери"
+msgstr "Я зареєÑтрую мої влаÑні раннери"
msgid "AccountValidation|In order to use free CI/CD minutes on shared runners, you'll need to validate your account using one of our verification options. If you prefer not to, you can run pipelines by bringing your own runners and disabling shared runners for your project."
-msgstr "Щоб викориÑтовувати безкоштовні хвилини CI/CD на Ñпільних ранер'ах, вам потрібно підтвердити Ñвій обліковий Ð·Ð°Ð¿Ð¸Ñ Ð·Ð° допомогою одного з наших варіантів підтвердженнÑ. Якщо ви віддаєте перевагу цьому не робити, ви можете запуÑкати конвеєри, додавши влаÑні ранери та вимкнувши Ñпільні ранери Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ проєкту."
+msgstr "Щоб викориÑтовувати безкоштовні хвилини CI/CD на Ñпільних раннер'ах, вам потрібно підтвердити Ñвій обліковий Ð·Ð°Ð¿Ð¸Ñ Ð·Ð° допомогою одного з наших варіантів підтвердженнÑ. Якщо ви віддаєте перевагу цьому не робити, ви можете запуÑкати конвеєри, додавши влаÑні раннери та вимкнувши Ñпільні раннери Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ проєкту."
msgid "AccountValidation|Learn more."
msgstr "ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ."
@@ -2370,9 +2378,6 @@ msgstr "Ðктивний"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr "Ðктивні %{accessTokenTypePlural} (%{totalAccessTokens})"
-msgid "Active %{type} (%{token_length})"
-msgstr "Ðктивні %{type} (%{token_length})"
-
msgid "Active Sessions"
msgstr "Ðктивні ÑеÑÑ–Ñ—"
@@ -2452,7 +2457,7 @@ msgid "Add a confidential internal note to this %{noteableDisplayName}."
msgstr ""
msgid "Add a custom message with details about the instance's shared runners. The message is visible when you view runners for projects and groups. Markdown is supported."
-msgstr ""
+msgstr "Додайте Ñпеціальне Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð· детальними відомоÑÑ‚Ñми про Ñпільні раннери. ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð²Ð¸Ð´Ð¸Ð¼Ðµ, коли ви переглÑдаєте раннери проєктів та групи. ПідтримуєтьÑÑ Markdown."
msgid "Add a general comment to this %{noteableDisplayName}."
msgstr "Додайте загальний коментар до цього %{noteableDisplayName}."
@@ -2745,6 +2750,12 @@ msgstr "Додає %{labels} %{label_text}."
msgid "Adds a Zoom meeting."
msgstr "Додає Zoom-зуÑтріч."
+msgid "Adds a resource link"
+msgstr "Додає поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° реÑурÑ"
+
+msgid "Adds a resource link for this incident."
+msgstr "Додає поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° реÑÑƒÑ€Ñ Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ інциденту."
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2928,6 +2939,24 @@ msgstr "Ви збираєтеÑÑ Ð·ÑƒÐ¿Ð¸Ð½Ð¸Ñ‚Ð¸ вÑÑ– завданнÑ. Ви
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr "Помилка при завантаженні ÑтатиÑтики. Будь лаÑка, Ñпробуйте знову"
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr "Тема"
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr "Визначте ваш набір проєктних міток за замовчуваннÑм"
@@ -2956,7 +2985,7 @@ msgid "AdminSettings|Affects all new and existing groups."
msgstr "Впливає на вÑÑ– нові та Ñ–Ñнуючі групи."
msgid "AdminSettings|All new projects can use the instance's shared runners by default."
-msgstr "Ð’ÑÑ– нові проєкти за замовчуваннÑм можуть викориÑтовувати загальні ранери (ранери) інÑтанÑа."
+msgstr "Ð’ÑÑ– нові проєкти за замовчуваннÑм можуть викориÑтовувати загальні раннери (раннери) інÑтанÑа."
msgid "AdminSettings|Auto DevOps domain"
msgstr "Домен Auto DevOps"
@@ -2964,20 +2993,32 @@ msgstr "Домен Auto DevOps"
msgid "AdminSettings|CI/CD limits"
msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ CI/CD"
+msgid "AdminSettings|Clickhouse URL"
+msgstr "URL-адреÑа Clickhouse"
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr "Ðалаштувати Let's Encrypt"
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr "URL-адреÑа Cube API"
+
+msgid "AdminSettings|Cube API key"
+msgstr "Ключ API Cube"
+
msgid "AdminSettings|Delete inactive projects"
msgstr "Видалити неактивні проєкти"
msgid "AdminSettings|Delete inactive projects that exceed"
-msgstr ""
+msgstr "Видалити неактивні проєкти, що перевищують"
msgid "AdminSettings|Delete project after"
msgstr ""
@@ -3021,8 +3062,11 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr "Увімкнути банер пропозицій конвеєра"
+msgid "AdminSettings|Enable product analytics"
+msgstr "Увімкнути аналітику продуктів"
+
msgid "AdminSettings|Enable shared runners for new projects"
-msgstr "Увімкнути загальні ранери Ð´Ð»Ñ Ð½Ð¾Ð²Ð¸Ñ… проєктів"
+msgstr "Увімкнути загальні раннери Ð´Ð»Ñ Ð½Ð¾Ð²Ð¸Ñ… проєктів"
msgid "AdminSettings|Enable smartcn custom analyzer: Indexing"
msgstr ""
@@ -3034,7 +3078,7 @@ msgid "AdminSettings|Enabled"
msgstr "Увімкнено"
msgid "AdminSettings|Enforce invitation flow for groups and projects"
-msgstr ""
+msgstr "ПримуÑове Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð´Ð»Ñ Ð³Ñ€ÑƒÐ¿ та проєктів"
msgid "AdminSettings|Feed token"
msgstr "Токен доÑтупу до каналів"
@@ -3043,7 +3087,7 @@ msgid "AdminSettings|Git abuse rate limit"
msgstr "Ліміт кількоÑÑ‚Ñ– порушень Git"
msgid "AdminSettings|Group runners expiration"
-msgstr "Термін дії групових ранерів"
+msgstr "Термін дії групових раннерів"
msgid "AdminSettings|I have read and agree to the Let's Encrypt %{link_start}Terms of Service%{link_end} (PDF)."
msgstr "Я прочитав Ñ– погоджуюÑÑŒ %{link_start}умовами викориÑтаннÑ%{link_end} (PDF)."
@@ -3064,7 +3108,19 @@ msgid "AdminSettings|Inactive project deletion"
msgstr ""
msgid "AdminSettings|Instance runners expiration"
-msgstr "Термін дії групових ранерів"
+msgstr "Термін дії групових раннерів"
+
+msgid "AdminSettings|Jitsu administrator email"
+msgstr "Електронна пошта адмініÑтратора Jitsu"
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr "Пароль адмініÑтратора Jitsu"
+
+msgid "AdminSettings|Jitsu host"
+msgstr "ХоÑÑ‚ Jitsu"
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr "Зберегти оÑтанні артефакти Ð´Ð»Ñ Ð²ÑÑ–Ñ… завдань в оÑтанніх уÑпішних конвеєрах"
@@ -3088,7 +3144,7 @@ msgid "AdminSettings|Maximum number of active pipelines per project"
msgstr ""
msgid "AdminSettings|Maximum number of custom domains per project"
-msgstr ""
+msgstr "МакÑимальна кількіÑÑ‚ÑŒ кориÑтувацьких доменів на проєкт"
msgid "AdminSettings|Maximum number of jobs in a single pipeline"
msgstr ""
@@ -3127,7 +3183,7 @@ msgid "AdminSettings|Project export"
msgstr "ЕкÑпорт проєкту"
msgid "AdminSettings|Project runners expiration"
-msgstr ""
+msgstr "Термін дії раннерів проєкту"
msgid "AdminSettings|Protect CI/CD variables by default"
msgstr "ЗахиÑтити змінні CI/CD за замовчуваннÑм"
@@ -3157,7 +3213,7 @@ msgid "AdminSettings|Select a CI/CD template"
msgstr "Виберіть шаблон CI/CD"
msgid "AdminSettings|Select a group to use as the source for instance-level project templates."
-msgstr ""
+msgstr "Виберіть групу Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Ñк джерело Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ð½Ð¸Ñ… шаблонів на рівні інÑтанÑа."
msgid "AdminSettings|Select to disable public access for Pages sites, which requires users to sign in for access to the Pages sites in your instance. %{link_start}Learn more.%{link_end}"
msgstr ""
@@ -3166,7 +3222,7 @@ msgid "AdminSettings|Send email to maintainers after project is inactive for"
msgstr ""
msgid "AdminSettings|Send warning email"
-msgstr ""
+msgstr "ÐадіÑлати Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾ÑŽ поштою"
msgid "AdminSettings|Service ping is disabled in your configuration file, and cannot be enabled through this form. For more information, see the documentation on %{link_start}deactivating service ping%{link_end}."
msgstr ""
@@ -3181,7 +3237,7 @@ msgid "AdminSettings|Set limit to 0 to disable it."
msgstr ""
msgid "AdminSettings|Set the expiration time of authentication tokens of newly registered group runners."
-msgstr "Ð’Ñтановити термін дії токенів автентифікації щойно зареєÑтрованих групових ранерів."
+msgstr "Ð’Ñтановити термін дії токенів автентифікації щойно зареєÑтрованих групових раннерів."
msgid "AdminSettings|Set the expiration time of authentication tokens of newly registered instance runners. Authentication tokens are automatically reset at these intervals."
msgstr ""
@@ -3193,7 +3249,7 @@ msgid "AdminSettings|Set the initial name and protections for the default branch
msgstr ""
msgid "AdminSettings|Set the maximum number of GitLab Pages custom domains per project (0 for unlimited). %{link_start}Learn more.%{link_end}"
-msgstr ""
+msgstr "Ð’Ñтановіть макÑимальну кількіÑÑ‚ÑŒ кориÑтувацьких доменів на проєкт на GitLab Pages (0 - без обмежень). %{link_start}Докладніше%{link_end}"
msgid "AdminSettings|Set the maximum size of GitLab Pages per project (0 for unlimited). %{link_start}Learn more.%{link_end}"
msgstr "Ð’Ñтановіть макÑимальний розмір GitLab Pages Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ проєкту (0 Ð´Ð»Ñ Ð½ÐµÐ¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð¾Ñ— кількоÑÑ‚Ñ–). %{link_start}ДовідайтеÑÑŒ більше.%{link_end}"
@@ -3204,9 +3260,18 @@ msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð°Ñ” бути більше 0."
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr "Розмір Ñ– параметри Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ð¼ÐµÐ½Ñƒ Ð´Ð»Ñ Ñтатичних Ñайтів Сторінок."
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr "ОÑтанні артефакти Ð´Ð»Ñ Ð²ÑÑ–Ñ… завдань у оÑтанніх уÑпішних конвеєрах у кожному проєкті зберігаютьÑÑ Ñ‚Ð° не мають терміну дії."
@@ -3231,9 +3296,18 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr "ВикориÑтовуйте Ñлужбу AWS OpenSearch з обліковими даними IAM"
-msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
msgstr ""
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
+msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
+msgstr "КориÑтувачі та групи повинні прийнÑти Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð´Ð¾ того, Ñк вони додадутьÑÑ Ð´Ð¾ групи або проєкту."
+
msgid "AdminSettings|When paused, GitLab still tracks the changes. This is useful for cluster/index migrations."
msgstr ""
@@ -3298,7 +3372,7 @@ msgid "AdminUsers|2FA Enabled"
msgstr "2FA увімкнено"
msgid "AdminUsers|A user can validate themselves by inputting a credit/debit card, or an admin can manually validate a user. Validated users can use free CI minutes on shared runners."
-msgstr "КориÑтувач може підтвердити Ñебе, ввівши кредитну/дебетову картку, або адмініÑтратор може вручну підтвердити кориÑтувача. Перевірені кориÑтувачі можуть викориÑтовувати безкоштовні CI хвилини у Ñпільних ранерах."
+msgstr "КориÑтувач може підтвердити Ñебе, ввівши кредитну/дебетову картку, або адмініÑтратор може вручну підтвердити кориÑтувача. Перевірені кориÑтувачі можуть викориÑтовувати безкоштовні CI хвилини у Ñпільних раннерах."
msgid "AdminUsers|Access"
msgstr "ДоÑтуп"
@@ -3333,6 +3407,9 @@ msgstr "ÐдмініÑтратор"
msgid "AdminUsers|Admins"
msgstr "ÐдмініÑтратори"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr "Затвердити"
@@ -3382,7 +3459,7 @@ msgid "AdminUsers|Blocking user has the following effects:"
msgstr "Ð‘Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача має наÑтупні наÑлідки:"
msgid "AdminUsers|Bot"
-msgstr ""
+msgstr "Бот"
msgid "AdminUsers|Can create group"
msgstr "Може Ñтворювати групи"
@@ -3520,13 +3597,13 @@ msgid "AdminUsers|Rejected users:"
msgstr "Відхилені кориÑтувачі:"
msgid "AdminUsers|Reset link will be generated and sent to the user. User will be forced to set the password on first sign in."
-msgstr ""
+msgstr "ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð´Ð»Ñ ÑÐºÐ¸Ð´Ð°Ð½Ð½Ñ Ð±ÑƒÐ´Ðµ Ñтворено та надіÑлано кориÑтувачеві. При першому вході кориÑтувачу буде необхідно вÑтановити пароль."
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr "Відновити доÑтуп кориÑтувача до облікового запиÑу, включаючи веб, Git та API."
-msgid "AdminUsers|Search by name, email or username"
-msgstr "Шукати за іменем, електронною поштою або іменем кориÑтувача"
+msgid "AdminUsers|Search by name, email, or username"
+msgstr ""
msgid "AdminUsers|Search users"
msgstr "Пошук кориÑтувачів"
@@ -3541,7 +3618,7 @@ msgid "AdminUsers|Sort by"
msgstr "Сортувати за"
msgid "AdminUsers|The maximum number of CI/CD minutes on shared runners that a group can use each month. Set 0 for unlimited. Set empty to inherit the global setting of %{minutes}"
-msgstr "МакÑимальна кількіÑÑ‚ÑŒ CI/CD хвилин на Ñпільних ранерах, Ñкі група може викориÑтовувати щоміÑÑцÑ. Ð’Ñтановіть 0 Ð´Ð»Ñ Ð½ÐµÐ¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð¾Ñ— кількоÑÑ‚Ñ–. Ð’Ñтановіть пуÑтим, щоб уÑпадкувати глобальне Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ %{minutes}"
+msgstr "МакÑимальна кількіÑÑ‚ÑŒ CI/CD хвилин на Ñпільних раннерах, Ñкі група може викориÑтовувати щоміÑÑцÑ. Ð’Ñтановіть 0 Ð´Ð»Ñ Ð½ÐµÐ¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð¾Ñ— кількоÑÑ‚Ñ–. Ð’Ñтановіть пуÑтим, щоб уÑпадкувати глобальне Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ %{minutes}"
msgid "AdminUsers|The user can't access git repositories."
msgstr "КориÑтувач не може отримати доÑтуп до репозиторіїв git."
@@ -3570,8 +3647,8 @@ msgstr "КориÑтувач не отримуватиме Ñповіщень"
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "Ð”Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð²Ð²ÐµÐ´Ñ–Ñ‚ÑŒ %{projectName}"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "Ð”Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð²Ð²ÐµÐ´Ñ–Ñ‚ÑŒ %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr "Ð”Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð²Ð²ÐµÐ´Ñ–Ñ‚ÑŒ %{username}."
msgid "AdminUsers|Unban user"
msgstr "Розбанити кориÑтувача"
@@ -3633,8 +3710,8 @@ msgstr "Без проєктів"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr "Ви збираєтеÑÑ Ð¾Ñтаточно видалити кориÑтувача %{username}. Пов'Ñзані з ним задачі, запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ– групи будуть передані загальноÑиÑтемному кориÑтувачеві \"Ghost User\". Щоб уникнути втрати даних, розглÑньте можливіÑÑ‚ÑŒ %{strongStart}Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача%{strongEnd} заміÑÑ‚ÑŒ видаленнÑ. ПіÑÐ»Ñ %{strongStart}Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача%{strongEnd}, його неможливо буде відновити."
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
-msgstr "Ви збираєтеÑÑ Ð¾Ñтаточно видалити кориÑтувача %{username}. Ð’ÑÑ– пов'Ñзані з ним задачі, запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ– групи будуть видалені. Щоб уникнути втрати даних, розглÑньте можливіÑÑ‚ÑŒ %{strongStart}Ð±Ð»Ð¾ÐºÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача%{strongEnd} заміÑÑ‚ÑŒ видаленнÑ. ПіÑÐ»Ñ %{strongStart}Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ ÐºÐ¾Ñ€Ð¸Ñтувача%{strongEnd}, його неможливо буде відновити."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
+msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
msgstr "Ви завжди можете заблокувати Ñ—Ñ… обліковий запиÑ, Ñкщо це необхідно."
@@ -3681,6 +3758,9 @@ msgstr "ÐдмініÑтруваннÑ"
msgid "Administrators"
msgstr "ÐдмініÑтратори"
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr "Додаткові кориÑтувачі повинні бути перевірені та затверджені ÑиÑтемним адмініÑтратором. Докладніше про %{help_link_start} Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑтаннÑ%{help_link_end}."
@@ -3727,16 +3807,16 @@ msgid "AdvancedSearch|Introduced in GitLab 13.1, before using %{reindexing_link_
msgstr ""
msgid "AdvancedSearch|Pause indexing and upgrade Elasticsearch to a supported version."
-msgstr ""
+msgstr "Призупинити індекÑÑƒÐ²Ð°Ð½Ð½Ñ Ñ‚Ð° оновити Elasticsearch до підтримуваної верÑÑ–Ñ—."
msgid "AdvancedSearch|Reindex recommended"
-msgstr ""
+msgstr "Рекомендовано переіндекÑувати"
msgid "AdvancedSearch|Reindex required"
msgstr "Потрібна повторна індекÑаціÑ"
msgid "AdvancedSearch|You are using outdated code search mappings. To improve code search quality, we recommend you use %{reindexing_link_start}zero-downtime reindexing%{link_end} or %{recreate_link_start}re-create your index%{link_end}."
-msgstr ""
+msgstr "Ви викориÑтовуєте заÑтарілі Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ коду. Щоб покращити ÑкіÑÑ‚ÑŒ пошуку коду, ми рекомендуємо викориÑтовувати %{reindexing_link_start}повторне індекÑÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÐµÐ· проÑтою%{link_end} або %{recreate_link_start}повторно Ñтворити Ñвій індекÑ%{link_end}."
msgid "After a successful password update you will be redirected to login screen."
msgstr "ПіÑÐ»Ñ ÑƒÑпішного Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð²Ð¸ перейдете на екран входу."
@@ -3745,7 +3825,7 @@ msgid "After a successful password update, you will be redirected to the login p
msgstr "ПіÑÐ»Ñ ÑƒÑпішного Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð¿Ð°Ñ€Ð¾Ð»ÑŽ ви будете перенаправлені на Ñторінку входу, де ви зможете увійти з новим паролем."
msgid "After it expires, you can't use merge approvals, code quality, or many other features."
-msgstr ""
+msgstr "ПіÑÐ»Ñ Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñтроку дії ви не можете викориÑтовувати Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ, ÑкіÑÑ‚ÑŒ коду чи багато інших функцій."
msgid "After it expires, you can't use merge approvals, epics, or many other features."
msgstr "ПіÑÐ»Ñ Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ його дії ви не зможете викориÑтовувати Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð·Ð»Ð¸Ñ‚Ñ‚Ñ, епіків або багато інших функцій."
@@ -3865,7 +3945,7 @@ msgid "AlertManagement|Resolved"
msgstr "Вирішено"
msgid "AlertManagement|Runbook"
-msgstr ""
+msgstr "Runbook"
msgid "AlertManagement|Service"
msgstr "СервіÑ"
@@ -3994,7 +4074,7 @@ msgid "AlertSettings|Name integration"
msgstr "Ð†Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ Ð· іменем"
msgid "AlertSettings|Parse payload fields"
-msgstr ""
+msgstr "Ðналіз полів кориÑного навантаженнÑ"
msgid "AlertSettings|Proceed with editing"
msgstr "Продовжити редагуваннÑ"
@@ -4165,7 +4245,7 @@ msgid "All paths are relative to the GitLab URL. Do not include %{relative_url_l
msgstr "Ð’ÑÑ– шлÑхи Ñ” відноÑними до URL-адреÑи GitLab. Ðе включайте %{relative_url_link_start}відноÑні URL-адреÑи%{relative_url_link_end}."
msgid "All project members"
-msgstr ""
+msgstr "Ð’ÑÑ– учаÑники проєкту"
msgid "All projects"
msgstr "Ð’ÑÑ– проєкти"
@@ -4191,8 +4271,8 @@ msgstr "Ð’ÑÑ– кориÑтувачі повинні мати імена."
msgid "All users with matching cards"
msgstr "Ð’ÑÑ– кориÑтувачі з картами, що збігаютьÑÑ"
-msgid "Allow \"%{group_name}\" to sign you in"
-msgstr "Дозволити вхід через \"%{group_name}\""
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr "Дозволити %{strongOpen}%{group_name}%{strongClose} щоб увійти?"
msgid "Allow access to members of the following group"
msgstr "Дозволити доÑтуп учаÑникам цієї групи"
@@ -4206,6 +4286,9 @@ msgstr "Дозволити коміти від учаÑників, Ñкі мож
msgid "Allow group owners to manage LDAP-related settings"
msgstr "Дозволити влаÑникам груп керувати налаштуваннÑми LDAP"
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr "Дозволити кориÑтувачам без прав адмініÑтратора доÑтуп до панелі продуктивноÑÑ‚Ñ–"
@@ -4242,9 +4325,6 @@ msgstr "Дозволити відправлÑти ключ до цього реÐ
msgid "Allow use of licensed EE features"
msgstr "Дозволити викориÑÑ‚Ð°Ð½Ð½Ñ Ð»Ñ–Ñ†ÐµÐ½Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ… функцій EE"
-msgid "Allow users to create top-level groups"
-msgstr "Дозволити кориÑтувачам Ñтворювати групи верхнього рівнÑ"
-
msgid "Allow users to dismiss the broadcast message"
msgstr "Дозволити кориÑтувачам відхилÑти повідомленнÑ"
@@ -4270,7 +4350,7 @@ msgid "Allows projects or subgroups in this group to override the global setting
msgstr "ДозволÑÑ” проєктам або підгрупам у цій групі перевизначати глобальне налаштуваннÑ."
msgid "Allows projects to track errors using an Opstrace integration."
-msgstr ""
+msgstr "ДозволÑÑ” проєктам відÑтежувати помилки за допомогою Opstrace інтеграції."
msgid "Allows you to add and manage Kubernetes clusters."
msgstr "ДозволÑÑ” додавати та керувати клаÑтерами Kubernetes."
@@ -4444,7 +4524,7 @@ msgid "An error occurred while fetching codequality mr diff reports."
msgstr "ВідбулаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð·Ð²Ñ–Ñ‚Ñ–Ð² про відмінноÑÑ‚Ñ– запиту на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð· ÑкіÑÑ‚ÑŽ коду."
msgid "An error occurred while fetching commit data."
-msgstr ""
+msgstr "Помилка при отриманні даних коміту."
msgid "An error occurred while fetching commits. Retry the search."
msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼Ð¼Ñ–Ñ‚Ñ–Ð². Повторіть пошук."
@@ -4491,6 +4571,9 @@ msgstr "Під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ñ‚ÐµÐ³Ñ–Ð² ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ
msgid "An error occurred while fetching terraform reports."
msgstr "Під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð·Ð²Ñ–Ñ‚Ñ–Ð² terraform ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°."
+msgid "An error occurred while fetching the health status."
+msgstr "Помилка при отриманні ÑтатуÑу здоров'Ñ."
+
msgid "An error occurred while fetching the job log."
msgstr "Помилка при отриманні логів завданнÑ."
@@ -4678,9 +4761,6 @@ msgstr "Помилка при запуÑку завданнÑ."
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr "Під Ñ‡Ð°Ñ Ñпроби Ñтворити звіт ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°. Будь лаÑка, Ñпробуйте пізніше."
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4757,7 +4837,7 @@ msgid "An unexpected error occurred while checking the project environment."
msgstr "Ðеочікувана помилка при перевірці Ñередовища проєкту."
msgid "An unexpected error occurred while checking the project runners."
-msgstr "Ðеочікувана помилка при перевірці ранерів проєкту."
+msgstr "Ðеочікувана помилка при перевірці раннерів проєкту."
msgid "An unexpected error occurred while communicating with the Web Terminal."
msgstr "Ðеочікувана помилка з'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ñ–Ð· Веб-терміналом."
@@ -4780,9 +4860,6 @@ msgstr "СталаÑÑ Ð½ÐµÐ²Ñ–Ð´Ð¾Ð¼Ð° помилка."
msgid "Analytics"
msgstr "Ðналітика"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "Проаналізуйте ваші залежноÑÑ‚Ñ– на предмет відомих вразливоÑтей."
@@ -4811,7 +4888,7 @@ msgid "Another action is currently in progress"
msgstr "Ð’ даний момент виконуєтьÑÑ Ñ‰Ðµ одна діÑ"
msgid "Another issue tracker is already in use. Only one issue tracker service can be active at a time"
-msgstr ""
+msgstr "Інший трекер задач вже викориÑтовуєтьÑÑ. Можна активувати лише одну Ñлужбу відÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ð·Ð°Ð´Ð°Ñ‡"
msgid "Another third-party wiki is already in use. Only one third-party wiki integration can be active at a time"
msgstr ""
@@ -4885,9 +4962,6 @@ msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°ÑтоÑунку уÑпішно збереÐ
msgid "Application settings update failed"
msgstr "ÐžÐ½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½ÑŒ програми не вдалоÑÑ"
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr "ЗаÑтоÑунок видалено, але не вдалоÑÑ Ð·Ð½Ð¸Ñ‰Ð¸Ñ‚Ð¸: %{error_message}"
-
msgid "Application was successfully destroyed."
msgstr "ЗаÑтоÑунок було уÑпішно знищено."
@@ -4906,7 +4980,7 @@ msgstr "Додати поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° Grafana"
msgid "ApplicationSettings|After sign-up text"
msgstr "ТекÑÑ‚ піÑÐ»Ñ Ñ€ÐµÑ”Ñтрації"
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4953,6 +5027,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr "СпиÑок заборонених доменів"
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾ÑŽ поштою"
@@ -4960,7 +5037,7 @@ msgid "ApplicationSettings|Email restrictions for sign-ups"
msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾Ñ— пошти Ð´Ð»Ñ Ñ€ÐµÑ”Ñтрації"
msgid "ApplicationSettings|Enable Slack application"
-msgstr ""
+msgstr "Увімкнути заÑтоÑунок Slack"
msgid "ApplicationSettings|Enable domain denylist for sign-ups"
msgstr ""
@@ -4971,9 +5048,18 @@ msgstr "Увімкнути Ð¾Ð±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾Ñ— пошти
msgid "ApplicationSettings|Enter denylist manually"
msgstr "Введіть ÑпиÑок заборони вручну"
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr "Мінімальна довжина Ð¿Ð°Ñ€Ð¾Ð»Ñ (кількіÑÑ‚ÑŒ Ñимволів)"
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -5001,6 +5087,9 @@ msgstr "Зберегти зміни"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
msgstr "Див. %{linkStart}правила політики паролів%{linkEnd}."
+msgid "ApplicationSettings|Send a confirmation email during sign up. New users must confirm their email address before they can log in."
+msgstr ""
+
msgid "ApplicationSettings|Send confirmation email on sign-up"
msgstr "ÐадіÑлати лиÑта на пошту з підтвердженнÑм під Ñ‡Ð°Ñ Ñ€ÐµÑ”Ñтрації"
@@ -5351,9 +5440,6 @@ msgstr "Ви впевнені, що хочете закрити цю заблоÐ
msgid "Are you sure you want to delete %{name}?"
msgstr "Ви впевнені, що хочете видалити %{name}?"
-msgid "Are you sure you want to delete these artifacts?"
-msgstr "Ви впевнені, що бажаєте видалити ці артефакти?"
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr "Ви певні, що хочете видалити цей %{commentType}?"
@@ -5457,8 +5543,8 @@ msgstr "Ви впевнені, що хочете повторити перене
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr "Ви впевнені, що бажаєте видалити цей %{accessTokenType}? Ð¦Ñ Ð´Ñ–Ñ Ð½Ðµ може бути ÑкаÑована."
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
-msgstr "Ви впевнені, що бажаєте видалити цей %{type}? Ð¦Ñ Ð´Ñ–Ñ Ð½Ðµ може бути ÑкаÑована."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr "Ви впевнені, що хочете відкликати цей перÑональний токен доÑтупу? Ð¦Ñ Ð´Ñ–Ñ Ð½Ðµ може бути ÑкаÑована."
@@ -5508,6 +5594,30 @@ msgstr "Ðртефакт було уÑпішно видалено."
msgid "Artifacts"
msgstr "Ðртефакти"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr "ОÑкільки ми продовжуємо Ñтворювати більше функцій Ð´Ð»Ñ SAST, ми хотіли б отримати ваші відгуки про функцію конфігурації SAST у %{linkStart}цій задачі%{linkEnd}."
@@ -5533,7 +5643,7 @@ msgid "Ask someone with write access to resolve it."
msgstr "ПопроÑÑ–Ñ‚ÑŒ когоÑÑŒ із правом запиÑу вирішити цю проблему."
msgid "Ask your group owner to set up a group runner."
-msgstr "ПопроÑÑ–Ñ‚ÑŒ керівника групи налаштувати груповий ранер."
+msgstr "ПопроÑÑ–Ñ‚ÑŒ керівника групи налаштувати груповий раннер."
msgid "Assertion consumer service URL"
msgstr "URL-адреÑа Ñлужби обробника тверджень"
@@ -5559,9 +5669,6 @@ msgstr "Призначити влаÑний колір типу #FF0000"
msgid "Assign labels"
msgstr "Призначити мітку"
-msgid "Assign milestone"
-msgstr "Призначити етап"
-
msgid "Assign myself"
msgstr "Призначити Ñебе"
@@ -5621,7 +5728,7 @@ msgstr[2] "%d Виконавців"
msgstr[3] "%d Виконавців"
msgid "Assignee has no permissions"
-msgstr ""
+msgstr "Виконавець не має прав"
msgid "Assignee lists not available with your current license"
msgstr "СпиÑки виконавців не доÑтупні з вашою поточною ліцензією"
@@ -5642,7 +5749,7 @@ msgid "At least one approval from a code owner is required to change files match
msgstr "Потрібне щонайменше одне Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ влаÑника коду Ð´Ð»Ñ Ð·Ð¼Ñ–Ð½Ð¸ файлів, що задовільнÑÑŽÑ‚ÑŒ відповідним правилам CODEOWNER."
msgid "At least one field of %{one_of_required_fields} must be present"
-msgstr ""
+msgstr "Принаймні одне поле %{one_of_required_fields} має бути приÑутнім"
msgid "At least one of group_id or project_id must be specified"
msgstr "Треба зазначити принаймні group_id або project_id"
@@ -5944,7 +6051,7 @@ msgid "AuthorizedApplication|Are you sure you want to revoke this application?"
msgstr ""
msgid "AuthorizedApplication|Revoke application"
-msgstr ""
+msgstr "Відкликати заÑтоÑунок"
msgid "Authors: %{authors}"
msgstr "Ðвтори: %{authors}"
@@ -5961,9 +6068,6 @@ msgstr "Ðвтозупинка уÑпішно ÑкаÑована."
msgid "Auto-cancel redundant pipelines"
msgstr "Ðвтоматичне ÑкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð½Ð°Ð´Ð»Ð¸ÑˆÐºÐ¾Ð²Ð¸Ñ… конвеєрів"
-msgid "Auto-close referenced issues on default branch"
-msgstr "Пов'Ñзані задачі в гілці за замовчуваннÑм автоматично закриті"
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr "%{auto_devops_start}Ðвтоматизуйте ÑтвореннÑ, теÑÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ‚Ð° розгортаннÑ%{auto_devops_end} ваших заÑтоÑунків на оÑнові вашої безперервної інтеграції та конфігурації розгортаннÑ. %{quickstart_start}Як розпочати роботу?%{quickstart_end}"
@@ -6001,7 +6105,7 @@ msgid "AutoRemediation|Auto-fix"
msgstr "ÐвтовиправленнÑ"
msgid "AutoRemediation|Auto-fix solutions"
-msgstr ""
+msgstr "Ðвто-Ð²Ð¸Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ñ€Ñ–ÑˆÐµÐ½ÑŒ"
msgid "AutoRemediation|If you're using dependency and/or container scanning, and auto-fix is enabled, auto-fix automatically creates merge requests with fixes to vulnerabilities."
msgstr "Якщо ви викориÑтовуєте ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð»ÐµÐ¶Ð½Ð¾Ñтей та/або контейнерів, Ñ– Ñкщо Ð°Ð²Ñ‚Ð¾Ð²Ð¸Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ ÑƒÐ²Ñ–Ð¼ÐºÐ½ÐµÐ½Ð¾, Ñ„ÑƒÐ½ÐºÑ†Ñ–Ñ Ð°Ð²Ñ‚Ð¾Ð²Ð¸Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ñ Ð°Ð²Ñ‚Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡Ð½Ð¾ Ñтворює запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð· виправленнÑм вразливоÑÑ‚Ñ–."
@@ -6049,7 +6153,7 @@ msgid "Automatically resolved"
msgstr "Вирішено автоматично"
msgid "Automatically update this project's branches and tags from the upstream repository."
-msgstr ""
+msgstr "Ðвтоматично оновлювати гілки та теги цього проєкту із репозиторію upstream."
msgid "Autosave|Note"
msgstr "Примітка"
@@ -6061,16 +6165,16 @@ msgid "Available ID"
msgstr "ДоÑтупний ідентифікатор"
msgid "Available group runners: %{runners}"
-msgstr "ДоÑтупна група ранерів: %{runners}"
+msgstr "ДоÑтупна група раннерів: %{runners}"
msgid "Available on-demand"
msgstr ""
msgid "Available shared runners:"
-msgstr "ДоÑтупні Ñпільні ранери:"
+msgstr "ДоÑтупні Ñпільні раннери:"
msgid "Available specific runners"
-msgstr "ДоÑтупні Ñпеціальні ранери"
+msgstr "ДоÑтупні Ñпеціальні раннери"
msgid "Avatar for %{assigneeName}"
msgstr "Ðватар Ð´Ð»Ñ %{assigneeName}"
@@ -6085,7 +6189,7 @@ msgid "Awaiting user signup"
msgstr "ÐžÑ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÑ”Ñтрації кориÑтувача"
msgid "Award added"
-msgstr ""
+msgstr "Ðагороду додано"
msgid "Award removed"
msgstr "Ðагороду видалено"
@@ -6247,7 +6351,7 @@ msgid "Based on"
msgstr "Ðа оÑнові"
msgid "Batch size"
-msgstr ""
+msgstr "Розмір групи"
msgid "Batched Job|Background Migrations"
msgstr "Міграції у фоновому режимі"
@@ -6256,7 +6360,7 @@ msgid "Batched Job|Batched Job (Id: %{id})"
msgstr ""
msgid "BatchedJob|Attempts"
-msgstr ""
+msgstr "Спроби"
msgid "BatchedJob|Batch size"
msgstr ""
@@ -6268,7 +6372,7 @@ msgid "BatchedJob|Created At"
msgstr ""
msgid "BatchedJob|Created at"
-msgstr ""
+msgstr "Створено о"
msgid "BatchedJob|Exception Class"
msgstr ""
@@ -6327,6 +6431,12 @@ msgstr "Будьте обережні. Зміна проÑтору імен пр
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "Будьте обережні. ÐŸÐµÑ€ÐµÐ¹Ð¼ÐµÐ½ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ñ–ÑŽ проєкту може мати небажані побічні ефекти."
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr "Перш ніж увімкнути цю інтеграцію, Ñтворіть вебхук Ð´Ð»Ñ ÐºÑ–Ð¼Ð½Ð°Ñ‚Ð¸ в Google Chat де ви хочете отримувати ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ цього проєкту. %{docs_link}"
@@ -6610,13 +6720,13 @@ msgid "Billings|Seats in use / Seats in subscription"
msgstr ""
msgid "Billings|Shared runners cannot be enabled until a valid credit card is on file."
-msgstr "ДоÑтупні ранери будуть ввімкнені піÑÐ»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð´Ñ–Ð¹Ñної кредитної картки."
+msgstr "ДоÑтупні раннери будуть ввімкнені піÑÐ»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð´Ñ–Ð¹Ñної кредитної картки."
msgid "Billings|To use free CI/CD minutes on shared runners, you’ll need to validate your account with a credit card. If you prefer not to provide one, you can run pipelines by bringing your own runners and disabling shared runners for your project. This is required to discourage and reduce abuse on GitLab infrastructure. %{strongStart}GitLab will not charge your card, it will only be used for validation.%{strongEnd} %{linkStart}Learn more%{linkEnd}."
-msgstr "Ð”Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Ð²Ñ–Ð»ÑŒÐ½Ð¸Ñ… хвилин CI/CD на Ñпільних ранерах, вам необхідно підтвердити ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð·Ð° допомогою кредитної картки. Якщо ви не бажаєте Ñ—Ñ— надавати, ви можете запуÑкати конвеєри, додаючи ваші влаÑні ранери та вимикаючи Ñпільні ранери Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ проєкту. Це необхідно Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð±Ñ–Ð³Ð°Ð½Ð½Ñ Ñ‚Ð° Ð·Ð¼ÐµÐ½ÑˆÐµÐ½Ð½Ñ Ð·Ð»Ð¾Ð²Ð¶Ð¸Ð²Ð°Ð½Ð½Ñ Ñ–Ð½Ñ„Ñ€Ð°Ñтруктурою GitLab. %{strongStart} Gitlab не буде ÑÑ‚Ñгувати кошти з вашої картки, вона необхідна лише Ð´Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¾Ð³Ð¾ запиÑу. %{strongEnd}%{linkStart}ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ%{linkEnd}."
+msgstr "Ð”Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Ð²Ñ–Ð»ÑŒÐ½Ð¸Ñ… хвилин CI/CD на Ñпільних раннерах, вам необхідно підтвердити ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð·Ð° допомогою кредитної картки. Якщо ви не бажаєте Ñ—Ñ— надавати, ви можете запуÑкати конвеєри, додаючи ваші влаÑні раннери та вимикаючи Ñпільні раннери Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ проєкту. Це необхідно Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð±Ñ–Ð³Ð°Ð½Ð½Ñ Ñ‚Ð° Ð·Ð¼ÐµÐ½ÑˆÐµÐ½Ð½Ñ Ð·Ð»Ð¾Ð²Ð¶Ð¸Ð²Ð°Ð½Ð½Ñ Ñ–Ð½Ñ„Ñ€Ð°Ñтруктурою GitLab. %{strongStart} Gitlab не буде ÑÑ‚Ñгувати кошти з вашої картки, вона необхідна лише Ð´Ð»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¾Ð³Ð¾ запиÑу. %{strongEnd}%{linkStart}ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ%{linkEnd}."
msgid "Billings|To use free CI/CD minutes on shared runners, you’ll need to validate your account with a credit card. This is required to discourage and reduce abuse on GitLab infrastructure. %{strongStart}GitLab will not charge your card, it will only be used for validation.%{strongEnd}"
-msgstr "Ð”Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Ð²Ñ–Ð»ÑŒÐ½Ð¸Ñ… хвилин CI/CD на Ñпільних ранерах, вам необхідно перевірити ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð·Ð° допомогою кредитної картки. Це необхідно Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð±Ñ–Ð³Ð°Ð½Ð½Ñ Ñ‚Ð° Ð·Ð¼ÐµÐ½ÑˆÐµÐ½Ð½Ñ Ð·Ð»Ð¾Ð²Ð¶Ð¸Ð²Ð°Ð½Ð½Ñ Ñ–Ð½Ñ„Ñ€Ð°Ñтруктурою GitLab. %{strongStart} Gitlab не буде ÑÑ‚Ñгувати кошти з вашої картки, вона необхідна лише Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸ облікового запиÑу. %{strongEnd}"
+msgstr "Ð”Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑÑ‚Ð°Ð½Ð½Ñ Ð²Ñ–Ð»ÑŒÐ½Ð¸Ñ… хвилин CI/CD на Ñпільних раннерах, вам необхідно перевірити ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð·Ð° допомогою кредитної картки. Це необхідно Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð±Ñ–Ð³Ð°Ð½Ð½Ñ Ñ‚Ð° Ð·Ð¼ÐµÐ½ÑˆÐµÐ½Ð½Ñ Ð·Ð»Ð¾Ð²Ð¶Ð¸Ð²Ð°Ð½Ð½Ñ Ñ–Ð½Ñ„Ñ€Ð°Ñтруктурою GitLab. %{strongStart} Gitlab не буде ÑÑ‚Ñгувати кошти з вашої картки, вона необхідна лише Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸ облікового запиÑу. %{strongEnd}"
msgid "Billings|User validation required"
msgstr "Ðеобхідна перевірка кориÑтувача."
@@ -6628,7 +6738,7 @@ msgid "Billings|Validate user account"
msgstr "Перевірити обліковий Ð·Ð°Ð¿Ð¸Ñ ÐºÐ¾Ñ€Ð¸Ñтувача"
msgid "Billings|You'll now be able to take advantage of free CI/CD minutes on shared runners."
-msgstr "Тепер ви зможете ÑкориÑтатиÑÑ Ð²Ñ–Ð»ÑŒÐ½Ð¸Ð¼Ð¸ хвилинами CI/CD на Ñпільних ранерах."
+msgstr "Тепер ви зможете ÑкориÑтатиÑÑ Ð²Ñ–Ð»ÑŒÐ½Ð¸Ð¼Ð¸ хвилинами CI/CD на Ñпільних раннерах."
msgid "Billings|Your account has been validated"
msgstr "Ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð±ÑƒÐ»Ð¾ перевірено"
@@ -6713,7 +6823,7 @@ msgid "Billing|Type %{username} to confirm"
msgstr "Введіть %{username} щоб підтвердити"
msgid "Billing|Unlimited members during your trial"
-msgstr ""
+msgstr "Ðеобмежена кількіÑÑ‚ÑŒ учаÑників протÑгом вашої пробної верÑÑ–Ñ—"
msgid "Billing|User was successfully removed"
msgstr "КориÑтувача уÑпішно видалено"
@@ -6750,10 +6860,10 @@ msgstr "Заблокований"
msgid "Blocked by %d issue"
msgid_plural "Blocked by %d issues"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "Заблоковано %d задачею"
+msgstr[1] "Заблоковано %d задачами"
+msgstr[2] "Заблоковано %d задачами"
+msgstr[3] "Заблоковано %d задачами"
msgid "Blocked issue"
msgstr "Заблокована задача"
@@ -6843,7 +6953,7 @@ msgid "BoardScope|Current iteration"
msgstr "Поточна ітераціÑ"
msgid "BoardScope|Don't filter milestone"
-msgstr ""
+msgstr "Ðе фільтруйте етап"
msgid "BoardScope|Edit"
msgstr "Редагувати"
@@ -7040,7 +7150,7 @@ msgid "Bold text"
msgstr "Жирний текÑÑ‚"
msgid "Bot"
-msgstr ""
+msgstr "Бот"
msgid "Both SSH and HTTP(S)"
msgstr "SSH Ñ– HTTP(S)"
@@ -7063,6 +7173,9 @@ msgstr "Гілка вже Ñ–Ñнує"
msgid "Branch changed"
msgstr "Гілку змінено"
+msgid "Branch defaults"
+msgstr "Типові Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð³Ñ–Ð»ÐºÐ¸"
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -7072,6 +7185,9 @@ msgstr "Гілка вже Ñ–Ñнує"
msgid "Branch name"
msgstr "Ðазва гілки"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr "Гілку не завантажено: %{branchId}"
@@ -7085,30 +7201,36 @@ msgid "BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or productio
msgstr "ПідтримуютьÑÑ%{linkStart}шаблони%{linkEnd}, такі Ñк *-stable або production/*."
msgid "BranchRules|All branches"
-msgstr ""
+msgstr "Ð’ÑÑ– гілки"
msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
+msgstr "УÑім кориÑтувачам з доÑтупом push дозволено примуÑовий push."
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr "Дозволити вÑім кориÑтувачам з push-доÑтупом %{linkStart}примуÑово push%{linkEnd}."
+msgid "BranchRules|Allowed to force push"
+msgstr "Дозволено примуÑово виконувати push"
+
msgid "BranchRules|Allowed to merge"
msgstr "Дозволено злиттÑ"
msgid "BranchRules|Allowed to merge (%{total})"
-msgstr ""
+msgstr "Дозволене Ð·Ð»Ð¸Ñ‚Ñ‚Ñ (%{total})"
msgid "BranchRules|Allowed to push"
msgstr "Дозволено здійÑнити push"
msgid "BranchRules|Allowed to push (%{total})"
-msgstr ""
+msgstr "Дозволено push (%{total})"
msgid "BranchRules|An error occurred while fetching branches."
msgstr "Під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð³Ñ–Ð»Ð¾Ðº ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°."
msgid "BranchRules|Approvals"
+msgstr "ЗатвердженнÑ"
+
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
msgid "BranchRules|Branch"
@@ -7120,14 +7242,17 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr "Деталі правил гілки"
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr "Створити шаблон: %{searchTerm}"
msgid "BranchRules|Details"
-msgstr ""
+msgstr "Деталі"
msgid "BranchRules|Force push"
-msgstr ""
+msgstr "ПримуÑове надÑиланнÑ"
msgid "BranchRules|Force push is not allowed."
msgstr ""
@@ -7138,17 +7263,23 @@ msgstr "Групи"
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr "Захищайте Ñтабільні гілки та змушуйте розробників викориÑтовувати запити на злиттÑ. %{linkStart}Що таке захищені гілки?%{linkEnd}"
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
-msgid "BranchRules|No data to display"
+msgid "BranchRules|Manage in Status checks"
msgstr ""
+msgid "BranchRules|No data to display"
+msgstr "Ðемає даних Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ"
+
msgid "BranchRules|No matching results"
msgstr "Ðемає відповідних результатів"
msgid "BranchRules|Protect branch"
-msgstr ""
+msgstr "ЗахиÑтити гілку"
msgid "BranchRules|Protections"
msgstr "ЗахиÑÑ‚"
@@ -7159,11 +7290,20 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr "Вимагати Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ влаÑників коду."
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr "Ролі"
msgid "BranchRules|Status checks"
-msgstr ""
+msgstr "Перевірка ÑтатуÑу"
+
+msgid "BranchRules|Status checks (%{total})"
+msgstr "Перевірка ÑтатуÑу (%{total})"
msgid "BranchRules|Target Branch"
msgstr "Цільова гілка"
@@ -7324,6 +7464,9 @@ msgstr "ÐžÐ³Ð¾Ð»Ð¾ÑˆÐµÐ½Ð½Ñ ÑƒÑпішно оновлено."
msgid "Broadcast Messages"
msgstr "ПовідомленнÑ"
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr "Під Ñ‡Ð°Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð²Ð¸Ð½Ð¸ÐºÐ»Ð° проблема, Ñпробуйте пізніше."
+
msgid "Browse Directory"
msgstr "ПереглÑнути каталог"
@@ -7333,9 +7476,6 @@ msgstr "ПереглÑнути файл"
msgid "Browse Files"
msgstr "ПереглÑд файлів"
-msgid "Browse artifacts"
-msgstr "ПереглÑнути артефакти"
-
msgid "Browse files"
msgstr "ПереглÑд файлів"
@@ -7367,7 +7507,7 @@ msgid "BulkImport|%{feature} (require v%{version})"
msgstr "%{feature} (потрібна v%{version})"
msgid "BulkImport|Destination"
-msgstr ""
+msgstr "ПризначеннÑ"
msgid "BulkImport|Destination group"
msgstr "Група призначеннÑ"
@@ -7381,9 +7521,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr "Такі дані не будуть перенеÑені: %{bullets} ЗвернітьÑÑ Ð´Ð¾ ÑиÑтемного адмініÑтратора %{host} Ð´Ð»Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ GitLab, Ñкщо вам необхідно перенеÑти ці дані"
-msgid "BulkImport|From source group"
-msgstr "З групи джерел"
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7414,11 +7551,14 @@ msgstr "Ім'Ñ Ð²Ð¶Ðµ Ñ–Ñнує."
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr "Ðова група"
+
msgid "BulkImport|No additional information provided."
-msgstr ""
+msgstr "Ðемає додаткової інформації."
msgid "BulkImport|No groups found"
-msgstr ""
+msgstr "Групи не знайдені"
msgid "BulkImport|No history is available"
msgstr "ІÑÑ‚Ð¾Ñ€Ñ–Ñ Ð½ÐµÐ´Ð¾Ñтупна"
@@ -7429,6 +7569,9 @@ msgstr "Ðемає батьківÑького елемента"
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr "ШлÑÑ… до нової групи."
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7453,9 +7596,6 @@ msgstr "Група джерел"
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr "Ð”Ð»Ñ Ð½Ð¾Ð²Ð¾Ñ— групи"
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr "Помилка Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ð¾Ð²Ð°Ð½Ð¸Ñ… проєктів із змінами в реальному чаÑÑ–."
@@ -7538,7 +7678,7 @@ msgid "CI Lint"
msgstr "Перевірка CI конфігурації"
msgid "CI configuration validated, including all configuration added with the %{codeStart}include%{codeEnd} keyword. %{link}"
-msgstr ""
+msgstr "ÐšÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ CI перевірена, включаючи вÑÑŽ конфігурацію, додану за допомогою ключового Ñлова %{codeStart}, включаючи %{codeEnd}. ключове Ñлово %{link}"
msgid "CI settings"
msgstr "Параметри CI"
@@ -7562,10 +7702,10 @@ msgid "CI/CD configuration file"
msgstr "Файл конфігурації CI/CD"
msgid "CI/CD limits"
-msgstr ""
+msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ CI/CD"
msgid "CI/CD minutes"
-msgstr ""
+msgstr "CI/CD хвилини"
msgid "CI/CD|No projects have been added to the scope"
msgstr "Ðемає проєктів в облаÑÑ‚ÑŒ видимоÑÑ‚Ñ–"
@@ -7586,7 +7726,7 @@ msgid "CICDAnalytics|Lead time"
msgstr "Ð§Ð°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ"
msgid "CICDAnalytics|No shared runner minute usage data available"
-msgstr ""
+msgstr "Ðемає даних про викориÑÑ‚Ð°Ð½Ð½Ñ Ñ…Ð²Ð¸Ð»Ð¸Ð½ Ñпільного раннера"
msgid "CICDAnalytics|Projects with releases"
msgstr "Проєкти з релізами"
@@ -7605,10 +7745,10 @@ msgid "CICDAnalytics|Releases"
msgstr "Релізів"
msgid "CICDAnalytics|Shared runner duration is the total runtime of all jobs that ran on shared runners"
-msgstr ""
+msgstr "ТриваліÑÑ‚ÑŒ Ñпільного раннера – це загальний Ñ‡Ð°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð²ÑÑ–Ñ… завдань, Ñкі працювали на Ñпільних раннерах"
msgid "CICDAnalytics|Shared runner pipeline minute duration by month"
-msgstr ""
+msgstr "ТриваліÑÑ‚ÑŒ Ñпільного раннера в хвилинах по міÑÑцÑÑ…"
msgid "CICDAnalytics|Something went wrong while fetching release statistics"
msgstr ""
@@ -7617,7 +7757,7 @@ msgid "CICDAnalytics|Time to restore service"
msgstr "Ð§Ð°Ñ Ð²Ñ–Ð´Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÑервіÑу"
msgid "CICDAnalytics|What is shared runner duration?"
-msgstr ""
+msgstr "Що таке триваліÑÑ‚ÑŒ Ñпільного раннера?"
msgid "CICD|Add a %{base_domain_link_start}base domain%{link_end} to your %{kubernetes_cluster_link_start}Kubernetes cluster%{link_end} for your deployment strategy to work."
msgstr "Додайти %{base_domain_link_start}базовий домен%{link_end} у Ñвій %{kubernetes_cluster_link_start} клаÑтер Kubernetes%{link_end}, щоб ваша ÑÑ‚Ñ€Ð°Ñ‚ÐµÐ³Ñ–Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð¿Ñ€Ð°Ñ†ÑŽÐ²Ð°Ð»Ð°."
@@ -7665,19 +7805,19 @@ msgid "CICD|Select the projects that can be accessed by API requests authenticat
msgstr ""
msgid "CICD|The Auto DevOps pipeline runs by default in all projects with no CI/CD configuration file. %{link_start}What is Auto DevOps?%{link_end}"
-msgstr ""
+msgstr "Конвеєр Auto DevOps запуÑкаєтьÑÑ Ð·Ð° замовчуваннÑм у вÑÑ–Ñ… проєктах без файлу конфігурації CI/CD. %{link_start}Що таке Auto DevOps?%{link_end}"
msgid "CICD|The Auto DevOps pipeline runs if no alternative CI configuration file is found."
msgstr "Конвеєр Auto DevOps запуÑкаєтьÑÑ, Ñкщо не знайдено альтернативного файлу конфігурації CI."
msgid "CICD|There are several CI/CD limits in place."
-msgstr ""
+msgstr "ІÑнує кілька обмежень CI/CD."
msgid "CICD|Unprotected branches will not have access to the cache from protected branches."
-msgstr ""
+msgstr "Ðезахищені гілки не матимуть доÑтупу до кешу із захищених гілок."
msgid "CICD|Use separate caches for protected branches"
-msgstr ""
+msgstr "ВикориÑтовуйте окремі кеші Ð´Ð»Ñ Ð·Ð°Ñ…Ð¸Ñ‰ÐµÐ½Ð¸Ñ… гілок"
msgid "CICD|group enabled"
msgstr "група увімкнена"
@@ -7740,7 +7880,7 @@ msgid "Campfire subdomain (optional)"
msgstr ""
msgid "Campfire token"
-msgstr ""
+msgstr "Campfire токен"
msgid "CampfireService|API authentication token from Campfire."
msgstr "API Токен автентифікації від Campfire"
@@ -7830,7 +7970,7 @@ msgid "CanaryIngress|Stable"
msgstr "Стабільний"
msgid "CanaryIngress|You are changing the ratio of the canary rollout for %{environment} compared to the stable deployment to:"
-msgstr "Ви змінюєте ÑÐ¿Ñ–Ð²Ð²Ñ–Ð´Ð½Ð¾ÑˆÐµÐ½Ð½Ñ canary Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð½Ð° %{environment} у порівнÑнні зі Ñтабільним розгортаннÑм на:"
+msgstr "Ви змінюєте ÑÐ¿Ñ–Ð²Ð²Ñ–Ð´Ð½Ð¾ÑˆÐµÐ½Ð½Ñ canary Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð½Ð° %{environment} у порівнÑнні з Ñтабільним розгортаннÑм на :"
msgid "Cancel"
msgstr "СкаÑувати"
@@ -7871,9 +8011,6 @@ msgstr "СкаÑÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð½ÑŒÐ¾Ð³Ð¾ переглÑду"
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr "Ðеможливо призначати конфіденційний епік до неконфіденційної задачі. Зробіть задачу конфіденційною та Ñпробуйте ще раз"
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr "Ðеможливо злити автоматично"
@@ -7889,6 +8026,9 @@ msgstr "Ðеможливо Ñтворити звіт про зловживанн
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr "Ðе можна видалити %{profile_name} Ñк поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð² політиці безпеки"
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr "Ðеможливо мати декілька імпортів Jira одночаÑно"
@@ -7965,7 +8105,7 @@ msgid "CascadingSettings|cannot be nil when locking the attribute"
msgstr ""
msgid "Certain user content will be moved to a system-wide \"Ghost User\" in order to maintain content for posterity. For further information, please refer to the %{link_start}user account deletion documentation.%{link_end}"
-msgstr ""
+msgstr "Певний контент кориÑтувача буде переміщений в загальноÑиÑтемний «КориÑтувач-привид», щоб зберегти контент Ð´Ð»Ñ Ð½Ð°Ñ‰Ð°Ð´ÐºÑ–Ð². Додаткову інформацію див. у документації з Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¾Ð³Ð¾ запиÑу кориÑтувача %{link_start}.%{link_end}"
msgid "Certificate"
msgstr "Сертифікат"
@@ -8118,7 +8258,7 @@ msgid "Changes to the title have not been saved"
msgstr "Зміни в заголовку не збережені"
msgid "Changes:"
-msgstr ""
+msgstr "Зміни:"
msgid "Changing any setting here requires an application restart"
msgstr ""
@@ -8187,7 +8327,7 @@ msgid "Check feature availability on namespace plan"
msgstr "Перевірити наÑвніÑÑ‚ÑŒ функціональноÑÑ‚Ñ– в плані Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñтору імен"
msgid "Check out branch"
-msgstr ""
+msgstr "Перевірити гілку"
msgid "Check out, review, and merge locally"
msgstr "Перевірте, переглÑньте та об’єднайте локально"
@@ -8516,7 +8656,7 @@ msgid "Choose file…"
msgstr "Виберіть файл…"
msgid "Choose the preferred Runner and populate the AWS CFT."
-msgstr "Виберіть потрібний ранер і заповніть AWS CFT."
+msgstr "Виберіть потрібний раннер і заповніть AWS CFT."
msgid "Choose the top-level group for your repository imports."
msgstr "Оберіть групу найвищого Ñ€Ñ–Ð²Ð½Ñ Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ репозиторіїв."
@@ -8632,6 +8772,9 @@ msgstr "Ключ"
msgid "CiVariables|Masked"
msgstr "Приховано"
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr "Захищений"
@@ -8913,7 +9056,7 @@ msgid "CloudSeed|Cloud SQL for Postgres"
msgstr ""
msgid "CloudSeed|Cloud SQL for SQL Server"
-msgstr ""
+msgstr "Cloud SQL Ð´Ð»Ñ SQL Server"
msgid "CloudSeed|Cloud SQL instance creation request successful. Expected resolution time is ~5 minutes."
msgstr ""
@@ -9141,7 +9284,7 @@ msgid "ClusterAgents|Are you sure you want to revoke this token? You cannot undo
msgstr "Ви впевнені, що хочете відкликати цей токен? Цю дію не можна відмінити."
msgid "ClusterAgents|CI/CD workflow with restricted access"
-msgstr ""
+msgstr "Робочий Ð¿Ñ€Ð¾Ñ†ÐµÑ CI/CD з обмеженим доÑтупом"
msgid "ClusterAgents|Certificate"
msgstr "Сертифікат"
@@ -9694,10 +9837,10 @@ 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."
-msgstr ""
+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}."
-msgstr ""
+msgstr "Ð†Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ Kubernetes на оÑнові Ñертифікатів заÑтаріла та буде вимкнена наприкінці лютого 2023 року. Будь лаÑка, %{linkStart}мігруйте на агент GitLab Ð´Ð»Ñ Kubernetes%{linkEnd}."
msgid "ClusterIntegration|The certificate-based method to connect clusters to GitLab was %{linkStart}deprecated%{linkEnd} in GitLab 14.5."
msgstr "СпоÑіб Ð¿Ñ–Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð½Ñ ÐºÐ»Ð°Ñтерів до GitLab через Ñертифікати %{linkStart}заÑтарілий%{linkEnd} у GitLab 14.5."
@@ -9951,11 +10094,17 @@ msgstr "Коментувати Ñ€Ñдки з %{startLine} по %{endLine}"
msgid "Comment/Reply (quoting selected text)"
msgstr "Коментувати/відповіÑти (цитуючи виділений текÑÑ‚)"
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
-msgstr "ÐšÐ¾Ð¼ÐµÐ½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñ–Ð², Ñкі замінюють або замінюютьÑÑ Ñимволічними поÑиланнÑми, наразі не підтримуєтьÑÑ."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
-msgstr "ÐšÐ¾Ð¼ÐµÐ½Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñимволічних поÑилань, Ñкі замінюють або замінюютьÑÑ Ñ„Ð°Ð¹Ð»Ð°Ð¼Ð¸, наразі не підтримуєтьÑÑ."
+msgid "Commenting on this line is not supported"
+msgstr ""
msgid "Comments"
msgstr "Коментарі"
@@ -10028,7 +10177,7 @@ msgid "Commits you select appear here. Go to the first tab and select commits to
msgstr "Тут з’ÑвлÑÑ‚ÑŒÑÑ Ð¾Ð±Ñ€Ð°Ð½Ñ– вами коміти. Перейдіть до першої вкладки та оберіть коміти, щоб додати Ñ—Ñ… до цього запиту на злиттÑ."
msgid "Commits:"
-msgstr ""
+msgstr "Коміти:"
msgid "Commits|An error occurred while fetching merge requests data."
msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ… запиту на злиттÑ."
@@ -10138,6 +10287,9 @@ msgstr "Пройдіть верифікацію, щоб зареєÑтруват
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr "Завершено"
@@ -10295,13 +10447,13 @@ msgid "Configure Dependency Scanning in `.gitlab-ci.yml`, creating this file if
msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð»ÐµÐ¶Ð½Ð¾Ñтей в `.gitlab-ci.yml`, ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ†ÑŒÐ¾Ð³Ð¾ файлу, Ñкщо він ще не Ñ–Ñнує"
msgid "Configure Error Tracking"
-msgstr ""
+msgstr "Ðалаштувати відÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ð¿Ð¾Ð¼Ð¸Ð»Ð¾Ðº"
msgid "Configure GitLab"
msgstr "Ðалаштувати GitLab"
msgid "Configure GitLab runners to start using the Web Terminal. %{helpStart}Learn more.%{helpEnd}"
-msgstr "Ðалаштувати ранерів GitLab Ð´Ð»Ñ Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÑƒ викориÑÑ‚Ð°Ð½Ð½Ñ Ð’ÐµÐ±-терміналу. %{helpStart}Докладніше.%{helpEnd}"
+msgstr "Ðалаштувати раннерів GitLab Ð´Ð»Ñ Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÑƒ викориÑÑ‚Ð°Ð½Ð½Ñ Ð’ÐµÐ±-терміналу. %{helpStart}Докладніше.%{helpEnd}"
msgid "Configure Gitaly timeouts."
msgstr "Ðалаштувати таймаути Gitaly."
@@ -10526,7 +10678,7 @@ msgid "Container Registry"
msgstr "РеєÑÑ‚Ñ€ Контейнерів"
msgid "Container Repository"
-msgstr ""
+msgstr "Репозиторій контейнера"
msgid "Container Scanning"
msgstr "Ð¡ÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð½Ñ‚ÐµÐ¹Ð½ÐµÑ€Ð°"
@@ -10657,7 +10809,7 @@ msgid "ContainerRegistry|Docker connection error"
msgstr "Помилка Ð·â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Docker"
msgid "ContainerRegistry|Edit cleanup rules"
-msgstr ""
+msgstr "Редагувати правила очищеннÑ"
msgid "ContainerRegistry|Enable expiration policy"
msgstr "Увімкнути політику Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії"
@@ -10939,11 +11091,11 @@ msgstr "ВнеÑок"
msgid "Contribution Analytics"
msgstr "Ðналітика внеÑків"
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
-msgstr "%{created_count} Ñтворено, %{closed_count} закрито."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
+msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
-msgstr "%{created_count} Ñтворено, %{merged_count} об’єднано, %{closed_count} закрито."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
+msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr "%{pushes}, більш ніж %{commits} від %{contributors}."
@@ -10975,6 +11127,15 @@ msgstr "Ðемає запитів на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð° обраний пері
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr "Ðемає відправлень за обраний період."
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr "ВнеÑки за %{calendar_date}"
@@ -11023,9 +11184,6 @@ msgstr "Скопіювати %{name}"
msgid "Copy %{protocol} clone URL"
msgstr "Скопіювати URL Ð´Ð»Ñ ÐºÐ»Ð¾Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ñ‡ÐµÑ€ÐµÐ· %{protocol}"
-msgid "Copy %{type}"
-msgstr "Скопіювати %{type}"
-
msgid "Copy ID"
msgstr "Скопіювати ID"
@@ -11110,9 +11268,6 @@ msgstr "Скопіювати Ñекрет"
msgid "Copy source branch name"
msgstr "Копіювати назву гілки-джерела"
-msgid "Copy the code below to implement tracking in your application:"
-msgstr "Скопіюйте наведений нижче код Ð´Ð»Ñ Ñ€ÐµÐ°Ð»Ñ–Ð·Ð°Ñ†Ñ–Ñ— відÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ñƒ вашому заÑтоÑунку:"
-
msgid "Copy this registration token."
msgstr "Скопіювати цей токен реєÑтрації."
@@ -11275,9 +11430,6 @@ msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ дані про викориÑ
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ %{user} з %{group}. Ðеможливо видалити оÑтаннього влаÑника групи."
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ %{user} з %{group}. КориÑтувач не Ñ” учаÑником групи."
-
msgid "Could not remove the trigger."
msgstr "Ðе вдалоÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ тригер."
@@ -11321,7 +11473,7 @@ msgid "Country"
msgstr "Країна"
msgid "Counts reflect children you may not have access to."
-msgstr ""
+msgstr "Підрахунок показує дочірні елементи, до Ñких ви можете не мати доÑтупу."
msgid "Coverage"
msgstr "ПокриттÑ"
@@ -11497,9 +11649,6 @@ msgstr "Створити новий файл чи папку"
msgid "Create new label"
msgstr "Створити нову мітку"
-msgid "Create new project"
-msgstr "Створити новий проєкт"
-
msgid "Create new..."
msgstr "Створити новий..."
@@ -11767,9 +11916,6 @@ msgstr "Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ ÐµÐ¿Ñ–ÐºÑƒ"
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr "Ð¡Ñ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð³Ñ€Ð°Ñ„Ñ–ÐºÑ–Ð² викориÑтовує дані з Ñервера Prometheus. Якщо це займає багато чаÑу, переконайтеÑÑ, що дані доÑтупні."
-msgid "Creation date"
-msgstr "Дата ÑтвореннÑ"
-
msgid "Creator"
msgstr ""
@@ -11785,8 +11931,8 @@ msgstr "Облікові дані не знайдено"
msgid "CredentialsInventory|Personal Access Tokens"
msgstr "ОÑобиÑÑ‚Ñ– токени доÑтупу"
-msgid "CredentialsInventory|Project Access Tokens"
-msgstr ""
+msgid "CredentialsInventory|Project and Group Access Tokens"
+msgstr "Токени доÑтупу до проєкту та групи"
msgid "CredentialsInventory|SSH Keys"
msgstr "Ключі SSH"
@@ -11858,7 +12004,7 @@ msgid "Cron time zone"
msgstr "ЧаÑовий поÑÑ Cron"
msgid "Crowd"
-msgstr ""
+msgstr "Crowd"
msgid "CsvParser|Failed to render the CSV file for the following reasons:"
msgstr "Помилка при отриманні CSV файлу з наÑтупних причин:"
@@ -11887,9 +12033,6 @@ msgstr "Поточна гілка"
msgid "Current Project"
msgstr "Поточний проєкт"
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr "Поточний вузол повинен бути оÑновним, інакше ви будете заблоковані"
@@ -11975,7 +12118,7 @@ msgid "Customer relations organizations"
msgstr ""
msgid "Customize CI/CD settings, including Auto DevOps, shared runners, and job artifacts."
-msgstr "Ðалаштуйте параметри CI/CD, зокрема Auto DevOps, Ñпільні ранери та артефакти завдань."
+msgstr "Ðалаштуйте параметри CI/CD, зокрема Auto DevOps, Ñпільні раннери та артефакти завдань."
msgid "Customize colors"
msgstr "Параметри кольорів"
@@ -12216,13 +12359,16 @@ msgid "DORA4Metrics|Change failure rate"
msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
+msgstr "Змінити відÑоток невдач (відÑотків)"
+
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
msgstr ""
msgid "DORA4Metrics|Date"
msgstr "Дата"
msgid "DORA4Metrics|Days for an open incident"
-msgstr ""
+msgstr "Дні Ð´Ð»Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¾Ð³Ð¾ інциденту"
msgid "DORA4Metrics|Days from merge to deploy"
msgstr "Днів від Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð´Ð¾ розгортаннÑ"
@@ -12234,17 +12380,20 @@ msgid "DORA4Metrics|Lead time for changes"
msgstr "Ð§Ð°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð·Ð¼Ñ–Ð½"
msgid "DORA4Metrics|Lead time for changes (median days)"
-msgstr ""
+msgstr "Ð§Ð°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð·Ð¼Ñ–Ð½ (Ñереднє чиÑло днів)"
msgid "DORA4Metrics|Median (last %{days}d)"
msgstr "Ð’ Ñередньому (оÑтанні %{days}d)"
msgid "DORA4Metrics|Median time (last %{days}d)"
-msgstr ""
+msgstr "Середній Ñ‡Ð°Ñ (за оÑтанні %{days}ів)"
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr "Жодних інцидентів за цей період"
@@ -12302,6 +12451,9 @@ msgstr "ОÑобиÑÑ‚Ñ–"
msgid "DashboardProjects|Trending"
msgstr "ПопулÑрні"
+msgid "Dashboards"
+msgstr "Панелі керуваннÑ"
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr "%{firstProject} Ñ– %{secondProject}"
@@ -12536,6 +12688,9 @@ msgstr "Зберегти чаÑто викориÑтовувані конфігÑ
msgid "DastProfiles|Save profile"
msgstr "Зберегти профіль"
+msgid "DastProfiles|Scan Method"
+msgstr "Метод ÑкануваннÑ"
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12573,10 +12728,10 @@ msgid "DastProfiles|Site name"
msgstr "Ім'Ñ Ñайту"
msgid "DastProfiles|Site profile"
-msgstr ""
+msgstr "Профіль Ñайту"
msgid "DastProfiles|Site profiles"
-msgstr ""
+msgstr "Профілі Ñайту"
msgid "DastProfiles|Site type"
msgstr "Тип Ñайту"
@@ -12657,10 +12812,10 @@ msgid "DastSiteValidation|Copy HTTP header to clipboard"
msgstr "Скопіюйте заголовок HTTP в буфер обміну"
msgid "DastSiteValidation|Copy Meta tag to clipboard"
-msgstr ""
+msgstr "Копіювати мета-тег у буфер обміну"
msgid "DastSiteValidation|Could not create validation token. Please try again."
-msgstr ""
+msgstr "Ðе вдалоÑÑ Ñтворити токен перевірки. Будь лаÑка, Ñпробуйте ще раз."
msgid "DastSiteValidation|Could not revoke validation. Please try again."
msgstr "Ðе вдалоÑÑ ÑкаÑувати перевірку. Будь лаÑка, Ñпробуйте ще раз."
@@ -12756,6 +12911,9 @@ msgstr ""
msgid "Data type"
msgstr "Тип даних"
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr "База даних «%{database_name}» викориÑтовує PostgreSQL %{pg_version_current}, але Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— верÑÑ–Ñ— GitLab потрібен PostgreSQL %{pg_version_minimum} . Будь лаÑка, оновіть Ñвоє Ñередовище до підтримуваної верÑÑ–Ñ— PostgreSQL, подробиці див. %{pg_requirements_url}."
+
msgid "Database update failed"
msgstr "Помилка Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð±Ð°Ð·Ð¸ даних"
@@ -12763,7 +12921,7 @@ msgid "DatadogIntegration|%{linkOpen}API key%{linkClose} used for authentication
msgstr "%{linkOpen}Ключ API%{linkClose} викориÑтовуєтьÑÑ Ð´Ð»Ñ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ— за допомогою Datadog."
msgid "DatadogIntegration|(Advanced) The full URL for your Datadog site."
-msgstr ""
+msgstr "(Додатково) Повна URL-адреÑа вашого Ñайту Datadog."
msgid "DatadogIntegration|API URL"
msgstr "URL API"
@@ -12843,6 +13001,9 @@ msgstr "Ср"
msgid "Days"
msgstr "Днів"
+msgid "Days of inactivity before deactivation"
+msgstr "Днів бездіÑльноÑÑ‚Ñ– перед деактивацією"
+
msgid "Days to merge"
msgstr "Днів до злиттÑ"
@@ -12871,11 +13032,14 @@ msgid "Decline and sign out"
msgstr "Відхити та вийти"
msgid "Decompressed archive size validation failed."
-msgstr ""
+msgstr "Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€Ð¸Ñ‚Ð¸ розмір розпакованого архіву."
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr "Типовий файл конфігурації CI/CD"
@@ -12913,7 +13077,7 @@ msgid "DefaultBranchLabel|default"
msgstr "За замовчуваннÑм"
msgid "DefaultBranchProtection|Both developers and maintainers can push new commits, but cannot force push."
-msgstr ""
+msgstr "Як розробники та керівники можуть відправити нові коміти, але не можуть примуÑово відправити."
msgid "DefaultBranchProtection|Both developers and maintainers can push new commits, force push, or delete the branch."
msgstr ""
@@ -12987,6 +13151,9 @@ msgstr "Видалити"
msgid "Delete %{issuableType}"
msgstr "Видалити %{issuableType}"
+msgid "Delete %{issuableType}?"
+msgstr "Видалити %{issuableType}?"
+
msgid "Delete %{name}"
msgstr "Видалити %{name}"
@@ -13008,11 +13175,8 @@ msgstr "Видалити потік значень"
msgid "Delete account"
msgstr "Видалити обліковий запиÑ"
-msgid "Delete artifacts"
-msgstr "Видалити артефакти"
-
msgid "Delete asset"
-msgstr ""
+msgstr "Видалити реÑурÑ"
msgid "Delete audio"
msgstr ""
@@ -13077,7 +13241,7 @@ msgstr "Видалити реліз %{release}?"
msgid "Delete row"
msgstr "Видалити Ñ€Ñдок"
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13141,7 +13305,7 @@ msgid "DeleteRelease|For more details, see %{docsPathStart}Deleting a release%{d
msgstr "Ð”Ð»Ñ Ð±Ñ–Ð»ÑŒÑˆ детальної інформації дивітьÑÑ %{docsPathStart}Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñ€ÐµÐ»Ñ–Ð·Ñƒ%{docsPathEnd}."
msgid "DeleteRelease|You are about to delete release %{release} and its assets. The Git tag %{tag} will not be deleted."
-msgstr ""
+msgstr "Ви збираєтеÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ реліз %{release} та його медіафайли. Git тег %{tag} не буде видалено."
msgid "DeleteValueStream|'%{name}' Value Stream deleted"
msgstr "'%{name}' Потік значень видалено"
@@ -13159,7 +13323,7 @@ msgid "Deleted chat nickname: %{chat_name}!"
msgstr "Видалено пÑевдонім Ð´Ð»Ñ Ñ‡Ð°Ñ‚Ñƒ: %{chat_name}!"
msgid "Deleted commits:"
-msgstr ""
+msgstr "Видалені коміти:"
msgid "Deleted projects cannot be restored!"
msgstr "Видалені проєкти неможливо відновити!"
@@ -13528,7 +13692,7 @@ msgid "DeployTokens|Allows read-only access to the repository."
msgstr "ДозволÑÑ” доÑтуп лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ Ð´Ð¾ репозиторію."
msgid "DeployTokens|Allows write access to registry images."
-msgstr ""
+msgstr "ДозволÑÑ” запиÑувати образи реєÑтру."
msgid "DeployTokens|Copy deploy token"
msgstr "Скопіювати токен розгортаннÑ"
@@ -13566,6 +13730,9 @@ msgstr "Дата Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ (необов’Ñзково)"
msgid "DeployTokens|Expires"
msgstr "Термін дії"
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr "Токени групового Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð½Ð°Ð´Ð°ÑŽÑ‚ÑŒ доÑтуп до пакетів, репозиторіїв та образів реєÑтру."
@@ -13585,7 +13752,7 @@ msgid "DeployTokens|Scopes"
msgstr "ОблаÑÑ‚ÑŒ дії"
msgid "DeployTokens|Scopes (select at least one)"
-msgstr ""
+msgstr "Межі (вибрати хоча б одну)"
msgid "DeployTokens|This %{entity_type} has no active Deploy Tokens."
msgstr ""
@@ -13597,7 +13764,7 @@ msgid "DeployTokens|This username supports access. %{link_start}What kind of acc
msgstr ""
msgid "DeployTokens|Use this token as a password. Save it. This password can %{i_start}not%{i_end} be recovered."
-msgstr ""
+msgstr "ВикориÑтовуйте цей токен Ñк пароль. Ðе забудьте зберегти. Цей пароль %{i_start}не може%{i_end} бути відновлений."
msgid "DeployTokens|Username"
msgstr "Ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача"
@@ -13633,7 +13800,7 @@ msgid "Deploying to"
msgstr "Ð Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð´Ð¾"
msgid "Deploying to AWS is easy with GitLab"
-msgstr ""
+msgstr "За допомогою GitLab легко розгорнути в AWS"
msgid "Deployment"
msgstr "РозгортаннÑ"
@@ -13653,6 +13820,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr "ЧаÑтота розгортаннÑ"
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr "Затверджено "
+
+msgid "DeploymentApprovals|Approvers"
+msgstr "Затверджуючі оÑоби"
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr "Розробники + Керівники"
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr "Керівники"
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13905,10 +14087,10 @@ msgid "DesignManagement|Designs"
msgstr "Дизайни"
msgid "DesignManagement|Discard changes"
-msgstr ""
+msgstr "СкаÑувати зміни"
msgid "DesignManagement|Discussion"
-msgstr ""
+msgstr "ОбговореннÑ"
msgid "DesignManagement|Download design"
msgstr ""
@@ -13932,7 +14114,7 @@ msgid "DesignManagement|Resolve thread"
msgstr "Завершити обговореннÑ"
msgid "DesignManagement|Resolved Comments"
-msgstr ""
+msgstr "Вирішені коментарі"
msgid "DesignManagement|Save comment"
msgstr "Зберегти коментар"
@@ -13997,8 +14179,11 @@ msgstr "Звіти DevOps"
msgid "DevOps adoption"
msgstr "ÐŸÑ€Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ DevOps"
+msgid "Developer"
+msgstr "Розробник"
+
msgid "Development"
-msgstr ""
+msgstr "Розробка"
msgid "Devices (optional)"
msgstr "ПриÑтрої (необов’Ñзково)"
@@ -14127,10 +14312,10 @@ msgid "DevopsAdoption|Remove Group from the table."
msgstr "Видалити групу з таблиці."
msgid "DevopsAdoption|Runner configured for project/group"
-msgstr "Ранер, налаштований Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ/групи"
+msgstr "Раннер, налаштований Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ/групи"
msgid "DevopsAdoption|Runners"
-msgstr "Ранери"
+msgstr "Раннери"
msgid "DevopsAdoption|SAST"
msgstr "SAST"
@@ -14239,6 +14424,12 @@ msgstr[3] "%d видалено"
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -14254,6 +14445,9 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] "Показано %{dropdownStart}%{count} змінений файл%{dropdownEnd}"
@@ -14261,6 +14455,9 @@ msgstr[1] "Показано %{dropdownStart}%{count} зміненого файл
msgstr[2] "Показано %{dropdownStart}%{count} змінених файлів%{dropdownEnd}"
msgstr[3] "Показано %{dropdownStart}%{count} змінених файлів%{dropdownEnd}"
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "Проблема при отриманні Ñ€Ñдків відмінноÑтей."
@@ -14277,7 +14474,7 @@ msgid "Direct non-authenticated users to this page."
msgstr "СпрÑмуйте неавтентифікованих кориÑтувачів на цю Ñторінку."
msgid "Direct users to this page after they sign out."
-msgstr ""
+msgstr "Перенаправити кориÑтувачів на цю Ñторінку піÑÐ»Ñ Ñ€ÐµÑ”Ñтрації."
msgid "Direction"
msgstr "ÐапрÑмок"
@@ -14292,13 +14489,13 @@ msgid "Disable Two-factor Authentication"
msgstr "Вимкнути двофакторну автентифікацію"
msgid "Disable What's new"
-msgstr ""
+msgstr "Вимкнути Що нового"
msgid "Disable for this project"
msgstr "Вимкнути Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту"
msgid "Disable group runners"
-msgstr "Вимкнути групові ранери"
+msgstr "Вимкнути групові раннери"
msgid "Disable two-factor authentication"
msgstr "Вимкнути двофакторну автентифікацію"
@@ -14358,7 +14555,7 @@ msgid "Discover|Security capabilities, integrated into your development lifecycl
msgstr ""
msgid "Discover|See the other features of the %{linkStart}ultimate plan%{linkEnd}"
-msgstr ""
+msgstr "ПереглÑньте інші функції %{linkStart}ultimate плану%{linkEnd}"
msgid "Discover|Start a free trial"
msgstr "Розпочати безкоштовну пробну верÑÑ–ÑŽ"
@@ -14476,10 +14673,10 @@ msgid "Domain Name"
msgstr "Доменне ім'Ñ"
msgid "Domain Verification"
-msgstr ""
+msgstr "Перевірка домену"
msgid "DomainVerification|How do I configure a domain?"
-msgstr ""
+msgstr "Як мені налаштувати домен?"
msgid "DomainVerification|No domains configured. Create a domain in a project in this group hierarchy."
msgstr ""
@@ -14590,7 +14787,7 @@ msgid "Drop or %{linkStart}upload%{linkEnd} file to attach"
msgstr "Перекиньте або %{linkStart}завантажте%{linkEnd} файл, щоб прикріпити"
msgid "Drop or %{linkStart}upload%{linkEnd} files to attach"
-msgstr ""
+msgstr "Перекиньте або %{linkStart}завантажте%{linkEnd} файли, щоб прикріпити"
msgid "Drop your designs to start your upload."
msgstr ""
@@ -14868,6 +15065,12 @@ msgstr "Відредаговано"
msgid "Edited %{timeago}"
msgstr "Відредаговано %{timeago}"
+msgid "Edited %{timeago} by %{author}"
+msgstr "Відредаговано %{timeago} %{author}"
+
+msgid "Edited by %{author}"
+msgstr "Відредаговано %{author}"
+
msgid "Editing"
msgstr "РедагуваннÑ"
@@ -15076,7 +15279,7 @@ msgid "Enable Spam Check via external API endpoint"
msgstr ""
msgid "Enable What's new: All tiers"
-msgstr ""
+msgstr "Увімкнути Що нового: вÑÑ– рівні"
msgid "Enable What's new: Current tier only"
msgstr "Увімкнути Що нового: тільки поточний рівень"
@@ -15127,7 +15330,7 @@ msgid "Enable for this project"
msgstr "Увімкнути Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту"
msgid "Enable group runners"
-msgstr "Увімкнути групові ранери"
+msgstr "Увімкнути групові раннери"
msgid "Enable header and footer in emails"
msgstr "Увімкнути заголовок та футер в електронних лиÑтах"
@@ -15163,7 +15366,7 @@ msgid "Enable reCAPTCHA"
msgstr "Увімкнути reCAPTCHA"
msgid "Enable reCAPTCHA for login."
-msgstr ""
+msgstr "Увімкнути reCAPTCHA Ð´Ð»Ñ Ð²Ñ…Ð¾Ð´Ñƒ."
msgid "Enable repository checks"
msgstr ""
@@ -15175,13 +15378,13 @@ msgid "Enable security training to help your developers learn how to fix vulnera
msgstr "Увімкніть Ñ‚Ñ€ÐµÐ½ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸, щоб допомогти вашим розробникам навчитиÑÑ Ð²Ð¸Ð¿Ñ€Ð°Ð²Ð»Ñти вразливоÑÑ‚Ñ–. Розробники можуть переглÑдати Ñ‚Ñ€ÐµÐ½ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸ вибраних оÑвітніх провайдерів, що ÑтоÑуютьÑÑ Ð²Ð¸Ñвленої вразливоÑÑ‚Ñ–."
msgid "Enable shared runners for all projects and subgroups in this group."
-msgstr "Увімкнути загальні ранери Ð´Ð»Ñ Ð²ÑÑ–Ñ… проєктів Ñ– підгруп у цій групі."
+msgstr "Увімкнути загальні раннери Ð´Ð»Ñ Ð²ÑÑ–Ñ… проєктів Ñ– підгруп у цій групі."
msgid "Enable shared runners for this group"
-msgstr "Увімкнути загальні ранери Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— групи"
+msgstr "Увімкнути загальні раннери Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— групи"
msgid "Enable shared runners for this project"
-msgstr "Увімкнути загальні ранери Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту"
+msgstr "Увімкнути загальні раннери Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту"
msgid "Enable two-factor authentication"
msgstr "Увімкнути двофакторну автентифікацію"
@@ -15198,23 +15401,41 @@ msgstr ""
msgid "Enable version check"
msgstr "Увімкнути перевірку верÑÑ–Ñ—"
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
-msgstr "%{stepStart}Крок 1%{stepEnd}. ПереконайтеÑÑ, що у Ð²Ð°Ñ Ð½Ð°Ð»Ð°ÑˆÑ‚Ð¾Ð²Ð°Ð½Ð¾ Kubernetes Ñ– Ñ” базовий домен Ð´Ð»Ñ Ð²Ð°ÑˆÐ¾Ð³Ð¾ %{linkStart}клаÑтера%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr "Скопіювати Ñніпет"
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
-msgstr "%{stepStart}Крок 3%{stepEnd}. Додайте його до проєкту %{linkStart}gitlab-ci.yml%{linkEnd} файлу."
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
msgstr ""
-msgid "EnableReviewApp|Close"
-msgstr "Закрити"
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
-msgstr "Скопіювати текÑÑ‚ Ñніпета"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr ""
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr ""
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
+msgstr ""
msgid "Enabled"
msgstr "Увімкнено"
@@ -15441,6 +15662,9 @@ msgstr "Ðвтоматичні зупинки %{autoStopAt}"
msgid "Environments|Commit"
msgstr "Коміт"
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr "Видалити"
@@ -15589,13 +15813,13 @@ msgid "Epic cannot be found."
msgstr "Ðе вдалоÑÑ Ð·Ð½Ð°Ð¹Ñ‚Ð¸ епік."
msgid "Epic details"
-msgstr ""
+msgstr "Деталі епіку"
msgid "Epic events"
msgstr "Події епіків"
msgid "Epic not found for given params"
-msgstr ""
+msgstr "Епіку не знайдено Ð´Ð»Ñ Ð·Ð°Ð´Ð°Ð½Ð¸Ñ… параметрів"
msgid "Epics"
msgstr "Епіки"
@@ -15621,12 +15845,12 @@ msgstr "Додати новий епік"
msgid "Epics|Add an existing epic"
msgstr "Додати Ñ–Ñнуючий епік"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgstr "Ви впевнені, що хочете видалити %{bStart}%{targetEpicTitle}%{bEnd} із %{bStart}%{parentEpicTitle}%{bEnd}?"
+
msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr "Ви впевнені, що хочете видалити %{bStart}%{targetIssueTitle}%{bEnd} із %{bStart}%{parentEpicTitle}%{bEnd}?"
-msgid "Epics|Assign Epic"
-msgstr ""
-
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr ""
@@ -15639,18 +15863,9 @@ msgstr "Видалити епік"
msgid "Epics|Remove issue"
msgstr "Видалити задачу"
-msgid "Epics|Search epics"
-msgstr "Пошук епіків"
-
-msgid "Epics|Select epic"
-msgstr "Вибрати епік"
-
msgid "Epics|Show more"
msgstr "Показати більше"
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr "ЩоÑÑŒ пішло не так при призначенні задачі до епіку."
-
msgid "Epics|Something went wrong while creating child epics."
msgstr "ЩоÑÑŒ пішло не так при Ñтворенні дочірніх епіків."
@@ -15663,18 +15878,12 @@ msgstr "ЩоÑÑŒ пішло не так при отриманні дочірні
msgid "Epics|Something went wrong while fetching epics list."
msgstr "ЩоÑÑŒ пішло не так під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ ÑпиÑку eпіків."
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr "Помилка при отриманні епіків групи."
-
msgid "Epics|Something went wrong while moving item."
msgstr "ЩоÑÑŒ пішло не так при переміщенні завданнÑ."
msgid "Epics|Something went wrong while ordering item."
msgstr "Помилка при вÑтановленні порÑдку елементу."
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr "Помилка при видаленні задачі із епіка."
-
msgid "Epics|Something went wrong while updating epics."
msgstr "ЩоÑÑŒ пішло не так під Ñ‡Ð°Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÐµÐ¿Ñ–ÐºÑ–Ð²."
@@ -15718,7 +15927,7 @@ msgid "Error creating repository for snippet with id %{snippet_id}"
msgstr ""
msgid "Error creating the snippet"
-msgstr ""
+msgstr "Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñніпета"
msgid "Error creating vulnerability finding: %{errors}"
msgstr "Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ð¾ÑˆÑƒÐºÑƒ вразливоÑÑ‚Ñ–: %{errors}"
@@ -15727,7 +15936,7 @@ msgid "Error deleting project. Check logs for error details."
msgstr "Помилка при видаленні проєкту. Перевірте журнали Ð´Ð»Ñ Ð¿Ð¾Ð´Ñ€Ð¾Ð±Ð¸Ñ†ÑŒ про помилку."
msgid "Error fetching branches"
-msgstr ""
+msgstr "Помилка при завантаженні гілок"
msgid "Error fetching burnup chart data"
msgstr ""
@@ -15804,9 +16013,6 @@ msgstr "Помилка при збереженні виконавців"
msgid "Error occurred when saving reviewers"
msgstr "Під Ñ‡Ð°Ñ Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð¾Ð³Ð»Ñдачів ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°"
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr "СталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ° під Ñ‡Ð°Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ ÑтатуÑу задачі"
@@ -15870,9 +16076,6 @@ msgstr "Помилка Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ"
msgid "Error uploading file. Please try again."
msgstr "Помилка Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ. Будь лаÑка, Ñпробуйте ще раз."
-msgid "Error uploading file: %{stripped}"
-msgstr "Помилка Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ: %{stripped}"
-
msgid "Error while loading the merge request. Please try again."
msgstr "Помилка при завантаженні запита на злиттÑ. Будь лаÑка, Ñпробуйте знову."
@@ -16113,6 +16316,57 @@ msgstr "Події"
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr "прийнÑто"
+
+msgid "Event|added"
+msgstr "додано"
+
+msgid "Event|approved"
+msgstr "затверджено"
+
+msgid "Event|closed"
+msgstr "закрито"
+
+msgid "Event|commented on"
+msgstr "прокоментована"
+
+msgid "Event|created"
+msgstr "Ñтворено"
+
+msgid "Event|deleted"
+msgstr "видалено"
+
+msgid "Event|destroyed"
+msgstr "знищено"
+
+msgid "Event|imported"
+msgstr "імпортовано"
+
+msgid "Event|joined"
+msgstr "приєднано"
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr "відкрито"
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr "УÑÑ– Ñпроби %{action} закінчилиÑÑ Ð½ÐµÐ²Ð´Ð°Ñ‡ÐµÑŽ: %{job_error_message}. Будь лаÑка, Ñпробуйте знову."
@@ -16126,7 +16380,7 @@ msgid "Every 6 months"
msgstr "Кожні 6 міÑÑцÑ"
msgid "Every 6 months on the %{day} at %{time} %{timezone}"
-msgstr ""
+msgstr "Кожні 6 міÑÑців на %{day} в %{time} %{timezone}"
msgid "Every day"
msgstr "ЩоднÑ"
@@ -16141,10 +16395,10 @@ msgid "Every month"
msgstr "ЩоміÑÑцÑ"
msgid "Every month (Day %{day} at %{time})"
-msgstr ""
+msgstr "Кожен міÑÑць (день %{day} в %{time})"
msgid "Every month on the %{day} at %{time} %{timezone}"
-msgstr ""
+msgstr "ЩоміÑÑÑ†Ñ Ð½Ð° %{day} в %{time} %{timezone}"
msgid "Every three months"
msgstr "Кожні 3 міÑÑці"
@@ -16234,6 +16488,9 @@ msgstr "Без комітів злиттÑ. Обмежено 6000 комітів
msgid "Execution time"
msgstr "Ð§Ð°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ"
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr "Ім'Ñ Ñ–Ñнуючої гілки, тега або SHA коміта"
@@ -16268,7 +16525,7 @@ msgid "Expand file"
msgstr "Розгорнути файл"
msgid "Expand issues"
-msgstr ""
+msgstr "Розгорнути задачі"
msgid "Expand jobs"
msgstr ""
@@ -16277,7 +16534,7 @@ msgid "Expand merge details"
msgstr "Показати деталі злиттÑ"
msgid "Expand milestones"
-msgstr ""
+msgstr "Розгорнути етапи"
msgid "Expand panel"
msgstr "Розгорнути панель"
@@ -16291,9 +16548,15 @@ msgstr "Розгорніть бічну панель"
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr "Повинен мати точно один із таких параметрів: КориÑтувач, проÑÑ‚Ñ–Ñ€ імен або проєкт."
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr "Термін дії"
@@ -16469,7 +16732,7 @@ msgid "ExternalAuthorization|Service URL"
msgstr "URL-адреÑа Ñлужби"
msgid "ExternalAuthorization|URL to which the projects make authorization requests. If the URL is blank, cross-project features are available and can still specify classification labels for projects."
-msgstr ""
+msgstr "URL-адреÑа, на Ñку проєкти надÑилають запити на авторизацію. Якщо URL-адреÑа пуÑта, між проєктні функції доÑтупні та вÑе ж можуть вказати мітки клаÑифікації Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñ–Ð²."
msgid "ExternalIssueIntegration|Another issue tracker is already in use"
msgstr ""
@@ -16487,10 +16750,10 @@ msgid "ExternalWikiService|Enter the URL to the external wiki."
msgstr ""
msgid "ExternalWikiService|External wiki"
-msgstr ""
+msgstr "Ð—Ð¾Ð²Ð½Ñ–ÑˆÐ½Ñ Ð²Ñ–ÐºÑ–"
msgid "ExternalWikiService|External wiki URL"
-msgstr ""
+msgstr "URL-адреÑа зовнішньої вікі"
msgid "ExternalWikiService|Link to an external wiki from the sidebar."
msgstr "ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° зовнішню вікі з бічної панелі."
@@ -16520,6 +16783,9 @@ msgstr "Помилка на"
msgid "Failed to add a Zoom meeting"
msgstr "Ðе вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ Zoom-зуÑтріч"
+msgid "Failed to add a resource link"
+msgstr "Ðе вдалоÑÑ Ð´Ð¾Ð´Ð°Ñ‚Ð¸ поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° реÑурÑ"
+
msgid "Failed to apply commands."
msgstr "Ðе вдалоÑÑ Ð·Ð°ÑтоÑувати команди."
@@ -16569,9 +16835,6 @@ msgstr "Ðе вдалоÑÑ Ñтворити фреймворк"
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr "Ðе вдалоÑÑ Ñтворити новий токен доÑтупу: %{token_response_message}"
-
msgid "Failed to create repository"
msgstr "Ðе вдалоÑÑ Ñтворити репозиторій"
@@ -16687,7 +16950,7 @@ msgid "Failed to move this issue because target project doesn't exist."
msgstr "Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ¼Ñ–Ñтити цю задачу, тому що цільовий проєкт не Ñ–Ñнує."
msgid "Failed to promote issue to incident"
-msgstr ""
+msgstr "Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ½ÐµÑти задачу до інциденту"
msgid "Failed to promote label due to internal error. Please contact administrators."
msgstr "Ðе вдалоÑÑ Ð¿ÐµÑ€ÐµÐ½ÐµÑти мітку через внутрішню проблему. Будь лаÑка, звернітьÑÑ Ð´Ð¾ адмініÑтраторів."
@@ -16767,9 +17030,6 @@ msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ ÑÑ‚Ð°Ñ‚ÑƒÑ Ð·Ð°Ð´Ð°Ñ‡Ñ–"
msgid "Failed to update the Canary Ingress."
msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ Canary Ingress."
-msgid "Failed to update."
-msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸."
-
msgid "Failed to upgrade."
msgstr "Ðе вдалоÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸."
@@ -16925,7 +17185,7 @@ msgid "FeatureFlags|Inactive flag for %{scope}"
msgstr "Ðеактивний перемикач функції Ð´Ð»Ñ %{scope}"
msgid "FeatureFlags|Install a %{docsLinkAnchoredStart}compatible client library%{docsLinkAnchoredEnd} and specify the API URL, application name, and instance ID during the configuration setup. %{docsLinkStart}More Information%{docsLinkEnd}"
-msgstr ""
+msgstr "Ð’Ñтановіть %{docsLinkAnchoredStart}ÑуміÑну клієнтÑьку бібліотеку%{docsLinkAnchoredEnd} Ñ– вкажіть URL адреÑу API, назву заÑтоÑунку та ідентифікатор інÑтанÑа під Ñ‡Ð°Ñ Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ. %{docsLinkStart}Більше інформації%{docsLinkEnd}"
msgid "FeatureFlags|Instance ID"
msgstr "Ідентифікатор ІнÑтанÑу"
@@ -17029,6 +17289,9 @@ msgstr "лют."
msgid "February"
msgstr "лютий"
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -17075,7 +17338,7 @@ msgid "File renamed with no changes."
msgstr ""
msgid "File suppressed by a .gitattributes entry or the file's encoding is unsupported."
-msgstr ""
+msgstr "Файл, заблокований запиÑом .gitattributes, або ÐºÐ¾Ð´ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñƒ не підтримуєтьÑÑ."
msgid "File templates"
msgstr "Шаблони файлів"
@@ -17120,10 +17383,10 @@ msgid "Filter by Git revision"
msgstr "Фільтр за верÑією Git"
msgid "Filter by issues that are currently closed."
-msgstr ""
+msgstr "Фільтр за закритими задачами."
msgid "Filter by issues that are currently opened."
-msgstr ""
+msgstr "Відфільтруйте за задачами, Ñкі зараз відкриті."
msgid "Filter by label"
msgstr "Фільтр за мітками"
@@ -17134,9 +17397,6 @@ msgstr "Фільтрувати за запитами на злиттÑ, Ñкі Ð
msgid "Filter by merge requests that are currently merged."
msgstr "Фільтрувати за запитами на злиттÑ, Ñкі наразі об’єднані."
-msgid "Filter by milestone"
-msgstr "Фільтр по етапу"
-
msgid "Filter by milestone name"
msgstr "Фільтрувати за назвою етапу"
@@ -17228,7 +17488,7 @@ msgid "First seen"
msgstr "Перший раз знайдено"
msgid "Fixed"
-msgstr ""
+msgstr "Виправлено"
msgid "Fixed burndown chart"
msgstr ""
@@ -17344,6 +17604,9 @@ msgstr "Ð”Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð¾Ñ— інформації, вÑ
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr "Заборонено"
+
msgid "Forgot your password?"
msgstr "Забули ваш пароль?"
@@ -17411,7 +17674,7 @@ msgid "ForkProject|Visibility level"
msgstr "Рівень видимоÑÑ‚Ñ–"
msgid "ForkProject|Want to organize several dependent projects under the same namespace?"
-msgstr ""
+msgstr "Бажаєте організувати кілька залежних проєктів в одному проÑторі імен?"
msgid "ForkSuggestion|Cancel"
msgstr "СкаÑувати"
@@ -17450,7 +17713,7 @@ msgid "Framework successfully deleted"
msgstr "Фреймворк уÑпішно видалено"
msgid "Free"
-msgstr ""
+msgstr "Безоплатно"
msgid "Free Trial of GitLab.com Ultimate"
msgstr "Безкоштовна пробна верÑÑ–Ñ GitLab.com Ultimate"
@@ -17466,31 +17729,31 @@ msgstr[2] ""
msgstr[3] ""
msgid "FreeUserCap|Alternatively you can upgrade to GitLab Premium or GitLab Ultimate:"
-msgstr ""
+msgstr "Крім того, ви можете перейти на GitLab Premium або GitLab Ultimate:"
msgid "FreeUserCap|Explore paid plans"
-msgstr ""
+msgstr "ОглÑд платних планів"
msgid "FreeUserCap|Explore paid plans:"
-msgstr ""
+msgstr "ОглÑд платних планів:"
msgid "FreeUserCap|Looks like you've reached your limit of %{free_user_limit} members for \"%{namespace_name}\". You can't add any more, but you can manage your existing members, for example, by removing inactive members and replacing them with new members."
msgstr ""
msgid "FreeUserCap|Manage members"
-msgstr ""
+msgstr "Ð£Ð¿Ñ€Ð°Ð²Ð»Ñ–Ð½Ð½Ñ ÑƒÑ‡Ð°Ñниками"
msgid "FreeUserCap|Manage members:"
-msgstr ""
+msgstr "Ð£Ð¿Ñ€Ð°Ð²Ð»Ñ–Ð½Ð½Ñ ÑƒÑ‡Ð°Ñниками:"
msgid "FreeUserCap|To get more members %{trial_link_start}start a trial %{trial_link_end} or %{upgrade_link_start}upgrade%{upgrade_link_end} to GitLab Premium or GitLab Ultimate."
msgstr ""
msgid "FreeUserCap|To get more members start a trial:"
-msgstr ""
+msgstr "Щоб отримати більше учаÑників пробної верÑÑ–Ñ—:"
msgid "FreeUserCap|You've reached your member limit!"
-msgstr ""
+msgstr "Ви доÑÑгли ліміту учаÑників!"
msgid "Freeze end"
msgstr ""
@@ -17748,7 +18011,7 @@ msgid "Geo|Does not match the primary storage configuration"
msgstr ""
msgid "Geo|Edit %{nodeType} site"
-msgstr ""
+msgstr "Редагувати %{nodeType} Ñайт"
msgid "Geo|Edit Geo Site"
msgstr ""
@@ -17760,7 +18023,7 @@ msgid "Geo|Errors:"
msgstr ""
msgid "Geo|External URL"
-msgstr ""
+msgstr "Зовнішній URL"
msgid "Geo|Failed"
msgstr "Ðевдало"
@@ -17850,7 +18113,7 @@ msgid "Geo|Limit the number of concurrent operations this secondary site can run
msgstr ""
msgid "Geo|Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
-msgstr ""
+msgstr "Зробіть кожного учаÑника команди більш продуктивним незалежно від його міÑцезнаходженнÑ. GitLab Geo Ñтворює копії \"тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ\" вашого GitLab Ñервера, щоб Ñкоротити Ñ‡Ð°Ñ Ð´Ð»Ñ ÐºÐ»Ð¾Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ñ– Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ ÐºÐ¾Ð´Ñƒ з великих репозиторіїв."
msgid "Geo|Minimum interval in days"
msgstr ""
@@ -17931,7 +18194,7 @@ msgid "Geo|Remove"
msgstr "Видалити"
msgid "Geo|Remove %{nodeType} site"
-msgstr ""
+msgstr "Видалити %{nodeType} Ñайт"
msgid "Geo|Remove entry"
msgstr "Видалити запиÑ"
@@ -18033,7 +18296,7 @@ msgid "Geo|Shards to synchronize"
msgstr ""
msgid "Geo|Show more"
-msgstr ""
+msgstr "Показати більше"
msgid "Geo|Site name can't be blank"
msgstr ""
@@ -18185,9 +18448,6 @@ msgstr "вторинний"
msgid "Get a free instance review"
msgstr "Отримайте безкоштовну оцінку інÑтанÑа"
-msgid "Get a free trial"
-msgstr "Спробувати безкоштовну пробну верÑÑ–ÑŽ"
-
msgid "Get a support subscription"
msgstr ""
@@ -18270,10 +18530,10 @@ msgid "GitAbuse|Reporting time period (seconds)"
msgstr ""
msgid "GitAbuse|Reporting time period can't be blank. Set to 0 for no limit."
-msgstr ""
+msgstr "КількіÑÑ‚ÑŒ репозиторіїв не може бути пуÑтою. Ð’Ñтановіть 0 Ð´Ð»Ñ Ð±ÐµÐ·Ð»Ñ–Ð¼Ñ–Ñ‚Ñƒ."
msgid "GitAbuse|Reporting time period must be a number."
-msgstr ""
+msgstr "Проміжок чаÑу Ð·Ð²Ñ–Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð°Ñ” бути чиÑлом."
msgid "GitAbuse|Reporting time period should be between %{minTimePeriod}-%{maxTimePeriod} seconds."
msgstr ""
@@ -18314,6 +18574,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr "Команда оплати GitLab."
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr "Корпоративна верÑÑ–Ñ GitLab"
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18365,6 +18631,9 @@ msgstr ""
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 ""
@@ -18413,9 +18682,6 @@ msgstr "ВерÑÑ–Ñ GitLab"
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr "GitLab Ñтворить гілку у вашому форку та розпочне запит на злиттÑ."
-msgid "GitLab.com"
-msgstr "GitLab.com"
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18543,7 +18809,7 @@ msgid "Gitaly storage name:"
msgstr "Ðазва Ñховища Gitaly:"
msgid "Gitaly timeouts"
-msgstr ""
+msgstr "Ð§Ð°Ñ Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Gitaly"
msgid "Gitaly|Address"
msgstr "ÐдреÑа"
@@ -18633,7 +18899,7 @@ msgid "GlobalSearch|Groups"
msgstr "Групи"
msgid "GlobalSearch|Help"
-msgstr ""
+msgstr "Допомога"
msgid "GlobalSearch|In this project"
msgstr ""
@@ -18660,10 +18926,10 @@ msgid "GlobalSearch|Recent epics"
msgstr ""
msgid "GlobalSearch|Recent issues"
-msgstr ""
+msgstr "Свіжі задачі"
msgid "GlobalSearch|Recent merge requests"
-msgstr ""
+msgstr "ОÑтанні запити на злиттÑ"
msgid "GlobalSearch|Results updated. %{count} results available. Use the up and down arrow keys to navigate search results list, or ENTER to submit."
msgstr ""
@@ -18678,7 +18944,7 @@ msgid "GlobalSearch|Search results are loading"
msgstr "Результати пошуку завантажуютьÑÑ"
msgid "GlobalSearch|Settings"
-msgstr ""
+msgstr "Параметри"
msgid "GlobalSearch|There was an error fetching search autocomplete suggestions."
msgstr ""
@@ -18690,7 +18956,7 @@ msgid "GlobalSearch|Type for new suggestions to appear below."
msgstr "Введіть, щоб нижче з'ÑвилиÑÑ Ð½Ð¾Ð²Ñ– пропозиції."
msgid "GlobalSearch|Use the shortcut key %{kbdOpen}/%{kbdClose} to start a search"
-msgstr ""
+msgstr "ВикориÑтовуйте клавішу швидкого доÑтупу %{kbdOpen}/%{kbdClose}, щоб почати пошук"
msgid "GlobalSearch|What are you searching for?"
msgstr ""
@@ -18971,9 +19237,6 @@ msgstr "Показати залежноÑÑ‚Ñ–"
msgid "GraphViewType|Stage"
msgstr "СтадіÑ"
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr "Gravatar"
@@ -18983,6 +19246,9 @@ msgstr "Gravatar увімкнено"
msgid "Group"
msgstr "Група"
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr "Групу %{group_name} та Ñ—Ñ— команду Mattermost було уÑпішно Ñтворено."
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19116,7 +19382,7 @@ msgid "Group requires separate account"
msgstr "Група вимагає окремий обліковий запиÑ"
msgid "Group runners"
-msgstr "Групові ранери"
+msgstr "Групові раннери"
msgid "Group runners can be managed with the %{link}."
msgstr ""
@@ -19218,7 +19484,7 @@ msgid "GroupRoadmap|This year"
msgstr "Цього року"
msgid "GroupRoadmap|To make your epics appear in the roadmap, add start or due dates to them."
-msgstr ""
+msgstr "Щоб ваші епіки відображалиÑÑ Ð² дорожній карті, додайте до них дату початку або заплановану дату завершеннÑ."
msgid "GroupRoadmap|To view the roadmap, add a start or due date to one of the %{linkStart}child epics%{linkEnd}."
msgstr "Ð”Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду плану-графіку додайте дату початку або Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ Ð´Ð¾ одного із %{linkStart}епіків-дітей%{linkEnd}."
@@ -19425,7 +19691,7 @@ msgid "GroupSettings|Auto DevOps pipeline was updated for the group"
msgstr "Конвеєр Auto DevOps оновлено Ð´Ð»Ñ Ñ†Ñ–Ñ”Ñ— групи"
msgid "GroupSettings|Available only on the top-level group. Applies to all subgroups. Groups already shared with a group outside %{group} are still shared unless removed manually."
-msgstr ""
+msgstr "ДоÑтупно тільки Ð´Ð»Ñ Ð³Ñ€ÑƒÐ¿Ð¸ верхнього рівнÑ. ЗаÑтоÑовуєтьÑÑ Ð´Ð¾ вÑÑ–Ñ… підгруп. Групи, до Ñких вже надано Ñпільний доÑтуп з групою за межами %{group}, залишаютьÑÑ Ñпільними, Ñкщо Ñ—Ñ… не видалено вручну."
msgid "GroupSettings|Badges"
msgstr "Значки"
@@ -19692,7 +19958,7 @@ msgid "GroupsNew|Import group"
msgstr "Імпортувати групу"
msgid "GroupsNew|Import groups from another instance of GitLab"
-msgstr ""
+msgstr "Імпорт груп з іншого інÑтанÑа GitLab"
msgid "GroupsNew|No import options available"
msgstr "Ðемає доÑтупних параметрів імпорту"
@@ -19745,12 +20011,6 @@ msgstr "Залишити групу"
msgid "GroupsTree|Loading groups"
msgstr "Ð—Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð³Ñ€ÑƒÐ¿"
-msgid "GroupsTree|No groups matched your search"
-msgstr "Жодна группа не задовольнÑÑ” параметрам вашого запиту"
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr "Жодна группа чи проєкт не задовольнÑÑ” параметрам вашого запиту"
-
msgid "GroupsTree|Options"
msgstr "Параметри"
@@ -19800,7 +20060,7 @@ msgid "Groups|Members, projects, trials, and paid subscriptions are tied to a sp
msgstr ""
msgid "Groups|Must start with letter, digit, emoji, or underscore. Can also contain periods, dashes, spaces, and parentheses."
-msgstr ""
+msgstr "Має починатиÑÑ Ð· літери, цифри, емодзі або Ñимволу підкреÑленнÑ. Може також міÑтити крапки, тире, пробіли та круглі дужки."
msgid "Groups|Remove avatar"
msgstr "Видалити аватар"
@@ -19820,6 +20080,9 @@ msgstr "ШлÑÑ… підгрупи"
msgid "Groups|You're creating a new top-level group"
msgstr "Ви Ñтворюєте нову групу верхнього рівнÑ"
+msgid "Guest"
+msgstr "ГіÑÑ‚ÑŒ"
+
msgid "Guideline"
msgstr "Керівництво"
@@ -20002,9 +20265,6 @@ msgstr "Інформацію про працездатніÑÑ‚ÑŒ можна от
msgid "Health status"
msgstr "Стан здоров’Ñ"
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr "Токен доÑтупу"
@@ -20081,7 +20341,7 @@ msgid "Hide"
msgstr "Приховати"
msgid "Hide Live Preview"
-msgstr ""
+msgstr "Приховати попередній переглÑд"
msgid "Hide archived projects"
msgstr "Сховати архівовані проєкти"
@@ -20173,19 +20433,19 @@ msgid "Highest role:"
msgstr "Ðайвища роль:"
msgid "HighlightBar|Alert events:"
-msgstr ""
+msgstr "Події попереджень:"
msgid "HighlightBar|Alert start time:"
-msgstr ""
+msgstr "Ð§Ð°Ñ Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÑƒ попередженнÑ:"
msgid "HighlightBar|Original alert:"
-msgstr ""
+msgstr "Оригінальне попередженнÑ:"
msgid "HighlightBar|Time to SLA:"
msgstr ""
msgid "Historical release"
-msgstr ""
+msgstr "ІÑторичний реліз"
msgid "History"
msgstr "ІÑторіÑ"
@@ -20239,10 +20499,10 @@ msgid "How do I mirror repositories?"
msgstr "Як дзеркально відобразити репозиторії?"
msgid "How do I rename an environment?"
-msgstr ""
+msgstr "Як перейменувати Ñередовище?"
msgid "How do I set up a Google Chat webhook?"
-msgstr ""
+msgstr "Як налаштувати вебхук Google Chat?"
msgid "How do I set up this service?"
msgstr "Як налаштувати цей ÑервіÑ?"
@@ -20263,7 +20523,7 @@ msgid "How the job limiter handles jobs exceeding the thresholds specified below
msgstr ""
msgid "How to track time"
-msgstr ""
+msgstr "Як відÑтежувати чаÑ"
msgid "I accept the %{terms_link}"
msgstr "Я приймаю %{terms_link}"
@@ -20437,16 +20697,16 @@ msgid "IdentityVerification|Maximum login attempts exceeded. Wait %{interval} an
msgstr ""
msgid "IdentityVerification|Phone number"
-msgstr ""
+msgstr "Ðомер телефону"
msgid "IdentityVerification|Phone number can't be blank."
-msgstr ""
+msgstr "Ðомер телефону не може бути порожнім."
msgid "IdentityVerification|Phone number must be %{maxLength} digits or fewer."
-msgstr ""
+msgstr "Ðомер телефону має бути %{maxLength} цифр або менше."
msgid "IdentityVerification|Phone number must contain only digits."
-msgstr ""
+msgstr "Ðомер телефону повинен міÑтити лише цифри."
msgid "IdentityVerification|Please enter a valid code"
msgstr ""
@@ -20458,13 +20718,19 @@ msgid "IdentityVerification|Send a new code"
msgstr "ÐадіÑлати новий код"
msgid "IdentityVerification|Send code"
-msgstr ""
+msgstr "ÐадіÑлати код"
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr "ЩоÑÑŒ пішло не так. Будь лаÑка, Ñпробуйте ще раз."
-msgid "IdentityVerification|Step 1: Verify phone number"
-msgstr ""
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr "Крок %{stepNumber}: Перевірити ÑпоÑіб оплати"
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr "Крок %{stepNumber}: Перевірка адреÑи електронної пошти"
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
+msgstr "Крок %{stepNumber}: Перевірка номера телефону"
msgid "IdentityVerification|The code has expired. Send a new code and try again."
msgstr "Термін дії коду закінчивÑÑ. Ðадішліть новий код Ñ– повторіть Ñпробу."
@@ -20485,7 +20751,7 @@ msgid "IdentityVerification|Verify email address"
msgstr "Підтвердити адреÑу електронної пошти"
msgid "IdentityVerification|Verify payment method"
-msgstr ""
+msgstr "Підтвердьте ÑпоÑіб оплати"
msgid "IdentityVerification|Verify your identity"
msgstr "Підтвердити Ñвою оÑобу"
@@ -20494,7 +20760,7 @@ msgid "IdentityVerification|You can always verify your account at a later time t
msgstr ""
msgid "IdentityVerification|You will receive a text containing a code. Standard charges may apply."
-msgstr ""
+msgstr "Ви отримаєте текÑÑ‚ із кодом. Може ÑÑ‚ÑгуватиÑÑ Ñтандартна плата."
msgid "IdentityVerification|You've reached the maximum amount of resends. Wait %{interval} and try again."
msgstr "Ви доÑÑгли макÑимальної кількоÑÑ‚Ñ– повторних відправлень. Зачекайте %{interval} Ñ– повторіть Ñпробу."
@@ -20550,12 +20816,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr "Якщо не була помилка, ви можете %{leave_link_start}залишити %{source_type}%{link_end}."
@@ -20587,7 +20847,7 @@ msgid "If you did not recently try to sign in, you should immediately %{password
msgstr ""
msgid "If you did not recently try to sign in, you should immediately change your password: %{password_link}."
-msgstr ""
+msgstr "Якщо ви нещодавно не входили в ÑиÑтему, вам Ñлід негайно змінити Ñвій пароль: %{password_link}."
msgid "If you get a lot of false alarms from repository checks, you can clear all repository check information from the database."
msgstr ""
@@ -20787,7 +21047,7 @@ msgid "ImportProjects|%{provider} rate limit exceeded. Try again later"
msgstr "%{provider} перевищено ліміт чаÑтоти. Спробуйте знову пізніше"
msgid "ImportProjects|Advanced import settings"
-msgstr ""
+msgstr "Розширені Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ"
msgid "ImportProjects|Blocked import URL: %{message}"
msgstr "Заблокований URL Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ: %{message}"
@@ -20814,7 +21074,7 @@ msgid "ImportProjects|Select the repositories you want to import"
msgstr "Виберіть репозиторії, Ñкі ви хочете імпортувати"
msgid "ImportProjects|The more information you select, the longer it will take to import"
-msgstr ""
+msgstr "Що більше інформації ви виберете, то більше чаÑу знадобитьÑÑ Ð´Ð»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ"
msgid "ImportProjects|The remote data could not be imported."
msgstr "Віддалені дані не можуть бути імпортовані."
@@ -20911,7 +21171,7 @@ msgid "InProductMarketing|And many more..."
msgstr "І багато іншого..."
msgid "InProductMarketing|Are your runners ready?"
-msgstr "Чи готові ваші ранери?"
+msgstr "Чи готові ваші раннери?"
msgid "InProductMarketing|Automated security scans directly within GitLab"
msgstr "Ðвтоматичні ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸ безпоÑередньо в GitLab"
@@ -20959,7 +21219,7 @@ msgid "InProductMarketing|Create a custom CI runner with just a few clicks"
msgstr ""
msgid "InProductMarketing|Create a custom runner"
-msgstr "Створити влаÑного runner"
+msgstr "Створити влаÑного раннер"
msgid "InProductMarketing|Create a project in GitLab in 5 minutes"
msgstr "Створити проєкт у GitLab за 5 хвилин"
@@ -21034,7 +21294,7 @@ msgid "InProductMarketing|Free 30-day trial"
msgstr ""
msgid "InProductMarketing|Get going with CI/CD quickly using our %{quick_start_link}. Start with an available runner and then create a CI .yml file – it's really that easy."
-msgstr "Швидко розпочніть роботу з CI/CD, викориÑтовуючи наш %{quick_start_link}. Почніть з доÑтупного runner'а, а потім Ñтворіть файл CI .yml – це дійÑно так проÑто."
+msgstr "Швидко розпочніть роботу з CI/CD, викориÑтовуючи наш %{quick_start_link}. Почніть з доÑтупного раннера, а потім Ñтворіть файл CI .yml – це дійÑно так проÑто."
msgid "InProductMarketing|Get our import guides"
msgstr "Отримайте наші поÑібники з імпорту"
@@ -21322,7 +21582,7 @@ msgid "InProductMarketing|Use GitLab CI/CD"
msgstr "ВикориÑтовувати GitLab CI/CD"
msgid "InProductMarketing|Use our AWS cloudformation template to spin up your runners in just a few clicks!"
-msgstr ""
+msgstr "СкориÑтайтеÑÑ Ð½Ð°ÑˆÐ¸Ð¼ шаблоном AWS cloudformation Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку ваших раннерів лише кількома кліками!"
msgid "InProductMarketing|Used by more than 100,000 organizations from around the globe:"
msgstr "ВикориÑтовуєтьÑÑ Ð¿Ð¾Ð½Ð°Ð´ 100 000 організаціÑми з уÑього Ñвіту:"
@@ -21577,10 +21837,10 @@ msgid "IncidentSettings|Time limit must be a valid number."
msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ‡Ð°Ñу має бути дійÑним чиÑлом."
msgid "IncidentSettings|Time limit must be greater than 0."
-msgstr ""
+msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ‡Ð°Ñу має бути більшим за 0."
msgid "IncidentSettings|When activated, this applies to all new incidents in the project."
-msgstr ""
+msgstr "Коли таймер активовано, він Ñпрацьовує Ð´Ð»Ñ Ð²ÑÑ–Ñ… нових інцидентів у проєкті."
msgid "IncidentSettings|hours"
msgstr "години"
@@ -21631,7 +21891,7 @@ msgid "Incident|Editing %{filename}"
msgstr ""
msgid "Incident|Error creating incident timeline event: %{error}"
-msgstr ""
+msgstr "Помилка ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¿Ð¾Ð´Ñ–Ñ— чаÑової шкали інциденту: %{error}"
msgid "Incident|Error deleting incident timeline event: %{error}"
msgstr ""
@@ -21673,10 +21933,10 @@ msgid "Incident|Timeline"
msgstr ""
msgid "Incident|Timeline text"
-msgstr ""
+msgstr "ТекÑÑ‚ шкали чаÑу"
msgid "Incident|Timeline text..."
-msgstr ""
+msgstr "ТекÑÑ‚ шкали чаÑу..."
msgid "Include author name in notification email body"
msgstr "Вказати ім'Ñ Ð°Ð²Ñ‚Ð¾Ñ€Ð° в тілі ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð¿Ð¾ електронній пошті"
@@ -21694,7 +21954,7 @@ msgid "Include the username in the URL if required: %{code_open}https://username
msgstr ""
msgid "Includes LFS objects. It can be overridden per group, or per project. Set to 0 for no limit."
-msgstr ""
+msgstr "Включає об'єкти LFS. Може бути перевизначено в групі або проєкті. 0 — необмежено."
msgid "Includes an MVC structure to help you get started"
msgstr "Включає Ñтруктуру MVC, щоб допомогти вам розпочати роботу"
@@ -21736,7 +21996,7 @@ msgid "Index deletion is canceled"
msgstr "Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñ–Ð½Ð´ÐµÐºÑу ÑкаÑовуєтьÑÑ"
msgid "Indicates whether this runner can pick jobs without tags"
-msgstr "Вказує на те, чи може даний runner виконувати Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð±ÐµÐ· тегів"
+msgstr "Вказує на те, чи може даний раннер виконувати Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð±ÐµÐ· тегів"
msgid "Inform users without uploaded SSH keys that they can't push over SSH until one is added"
msgstr "ПовідомлÑти кориÑтувачам без клічів SSH, що без них вони не зможуть відправлÑти код через SSH"
@@ -22049,10 +22309,10 @@ msgid "Integrations|Group-level integration management"
msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñ–Ð½Ñ‚ÐµÐ³Ñ€Ð°Ñ†Ñ–Ñ”ÑŽ на рівні групи"
msgid "Integrations|Includes Standard, plus the entire commit message, commit hash, and issue IDs"
-msgstr ""
+msgstr "Включає Стандарт, а також уÑе Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ коміт, хеш коміту та ідентифікатори задач."
msgid "Integrations|Includes commit title and branch."
-msgstr ""
+msgstr "Включає назву коміту та гілки."
msgid "Integrations|Instance-level integration management"
msgstr ""
@@ -22070,7 +22330,7 @@ msgid "Integrations|Link namespaces"
msgstr ""
msgid "Integrations|Linked namespaces"
-msgstr ""
+msgstr "Пов'Ñзані проÑтори імен"
msgid "Integrations|Namespace successfully linked"
msgstr ""
@@ -22130,13 +22390,13 @@ msgid "Integrations|Send notifications about project events to a Unify Circuit c
msgstr ""
msgid "Integrations|Sign in to %{url}"
-msgstr ""
+msgstr "Увійти до %{url}"
msgid "Integrations|Sign in to GitLab"
msgstr "Увійти до GitLab"
msgid "Integrations|Sign in to add namespaces"
-msgstr ""
+msgstr "Увійти, щоб додати проÑтори імен"
msgid "Integrations|Standard"
msgstr ""
@@ -22157,7 +22417,7 @@ msgid "Integrations|Trigger"
msgstr ""
msgid "Integrations|Use custom settings"
-msgstr ""
+msgstr "ВикориÑтовувати влаÑні налаштуваннÑ"
msgid "Integrations|Use default settings"
msgstr "ВикориÑтовувати Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð° замовчуваннÑм"
@@ -22166,7 +22426,7 @@ msgid "Integrations|You can close this window."
msgstr ""
msgid "Integrations|You can use this alias in your Slack commands"
-msgstr ""
+msgstr "Ви можете викориÑтовувати цей пÑевдонім у командах Slack"
msgid "Integrations|You haven't activated any integrations yet."
msgstr "Ви ще не активували жодної інтеграції."
@@ -22187,7 +22447,7 @@ msgid "Integrations|Your browser is not supported"
msgstr ""
msgid "Integrations|ZenTao issues display here when you create issues in your project in ZenTao."
-msgstr ""
+msgstr "Задачі ZenTao відображаютьÑÑ Ñ‚ÑƒÑ‚, коли ви Ñтворюєте задачі у вашому проєкті в ZenTao."
msgid "Integrations|can't exceed %{recipients_limit}"
msgstr "Ðе може перевищувати %{recipients_limit}"
@@ -22208,7 +22468,7 @@ msgid "Internal"
msgstr "Внутрішній"
msgid "Internal - The group and any internal projects can be viewed by any logged in user except external users."
-msgstr ""
+msgstr "Внутрішній – групу та будь-Ñкі внутрішні проєкти можуть переглÑдати будь-Ñкі кориÑтувачі, Ñкі ввійшли в ÑиÑтему, крім зовнішніх кориÑтувачів."
msgid "Internal - The project can be accessed by any logged in user except external users."
msgstr "Внутрішній - будь-Ñкий зареєÑтрований кориÑтувач має доÑтуп до цього проєкту."
@@ -22315,6 +22575,9 @@ msgstr "ÐедійÑний двофакторний код підтверджеÐ
msgid "Invalid yaml"
msgstr "ÐедійÑний yaml"
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr "ДоÑлідити вразливіÑÑ‚ÑŒ: %{title}"
@@ -22333,9 +22596,6 @@ msgstr "Ð—Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð²Ñ–Ð´Ñ…Ð¸Ð»ÐµÐ½Ð¾"
msgid "Invite \"%{email}\" by email"
msgstr "ЗапроÑити \"%{email}\" за електронною поштою"
-msgid "Invite \"%{trimmed}\" by email"
-msgstr "ЗапроÑити \"%{trimmed}\" за електронною поштою"
-
msgid "Invite Members"
msgstr "ЗапроÑити учаÑників"
@@ -22385,15 +22645,15 @@ msgid "InviteEmail|and has assigned you the following tasks:"
msgstr "та призначив вам такі завданнÑ:"
msgid "InviteMembersBanner|Collaborate with your team"
-msgstr ""
+msgstr "Співпрацюйте зі Ñвоєю командою"
msgid "InviteMembersBanner|Invite your colleagues"
-msgstr ""
+msgstr "ЗапроÑити Ñвоїх колег"
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr "Ми помітили, що ви нікого не запроÑили до цієї групи. ЗапроÑÑ–Ñ‚ÑŒ Ñвоїх колег, щоб ви могли обговорювати задачі, Ñпівпрацювати над запитами на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ‚Ð° ділитиÑÑ Ñвоїми знаннÑми."
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22475,19 +22735,16 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr "Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾, щоб призначити задачі новому учаÑнику команди, вам потрібен проєкт Ð´Ð»Ñ Ð·Ð°Ð´Ð°Ñ‡. %{linkStart}Створити проєкт, щоб почати.%{linkEnd}"
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22625,12 +22882,18 @@ msgstr "ВикориÑтовує міÑце в ліцензії:"
msgid "Is using seat"
msgstr "ВикориÑтовує міÑце"
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22652,6 +22915,18 @@ msgstr "переміщено"
msgid "IssuableStatus|promoted"
msgstr "перенеÑено"
+msgid "Issuable|epic"
+msgstr "епік"
+
+msgid "Issuable|escalation policy"
+msgstr "політика еÑкалації"
+
+msgid "Issuable|iteration"
+msgstr "ітераціÑ"
+
+msgid "Issuable|milestone"
+msgstr "етап"
+
msgid "Issue"
msgstr "Задача"
@@ -22877,6 +23152,21 @@ msgstr "Щоб розширити пошук, будь лаÑка, змінітÑ
msgid "IssuesAnalytics|Total:"
msgstr "Ð’Ñього:"
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr "Ðазва"
@@ -22935,10 +23225,10 @@ msgid "Iterations cannot be manually added to cadences that use automatic schedu
msgstr ""
msgid "IterationsCadence|The automation start date must come after the active iteration %{iteration_dates}."
-msgstr ""
+msgstr "Дата початку автоматизації повинна бути піÑÐ»Ñ Ð°ÐºÑ‚Ð¸Ð²Ð½Ð¾Ñ— ітерації %{iteration_dates}."
msgid "IterationsCadence|The automation start date must come after the past iteration %{iteration_dates}."
-msgstr ""
+msgstr "Дата початку автоматизації повинна бути піÑÐ»Ñ Ð¼Ð¸Ð½ÑƒÐ»Ð¾Ñ— ітерації %{iteration_dates}."
msgid "IterationsCadence|The automation start date would retroactively create a past iteration. %{start_date} is the earliest possible start date."
msgstr ""
@@ -23171,6 +23461,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr "Ðова гілка була уÑпішно Ñтворена."
@@ -23397,7 +23690,7 @@ msgid "Job has wrong arguments format."
msgstr "Ð—Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð¼Ð°Ñ” неправильний формат аргументів."
msgid "Job is stuck. Check runners."
-msgstr "Ð—Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ðµ. Перевірте ранери."
+msgstr "Ð—Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ðµ. Перевірте раннери."
msgid "Job logs and artifacts"
msgstr "Журнали завдань та артефакти"
@@ -23478,7 +23771,7 @@ msgid "Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{ref}"
msgstr ""
msgid "Job|%{searchLength} results found for %{searchTerm}"
-msgstr ""
+msgstr "%{searchLength} результатів знайдено Ð´Ð»Ñ %{searchTerm}"
msgid "Job|Are you sure you want to erase this job log and artifacts?"
msgstr ""
@@ -23501,6 +23794,9 @@ msgstr "Створено"
msgid "Job|Download"
msgstr "Завантажити"
+msgid "Job|Duration"
+msgstr "ТриваліÑÑ‚ÑŒ"
+
msgid "Job|Erase job log and artifacts"
msgstr "Стерти лог завдань та артефакти"
@@ -23540,9 +23836,15 @@ msgstr "В очікуванні"
msgid "Job|Preparing"
msgstr "Підготовка"
+msgid "Job|Queued"
+msgstr "У черзі"
+
msgid "Job|Retry"
msgstr "Повторити"
+msgid "Job|Run again"
+msgstr "ЗапуÑтити знову"
+
msgid "Job|Running"
msgstr "ВиконуєтьÑÑ"
@@ -23553,7 +23855,7 @@ msgid "Job|Scroll to bottom"
msgstr "Прокрутити вниз"
msgid "Job|Scroll to next failure"
-msgstr ""
+msgstr "Прокрутити до наÑтупної невдачі"
msgid "Job|Scroll to top"
msgstr "Прокрутити вгору"
@@ -23562,7 +23864,7 @@ msgid "Job|Search for substrings in your job log output. Currently search is onl
msgstr ""
msgid "Job|Search job log"
-msgstr ""
+msgstr "Пошук журналу завдань"
msgid "Job|Show complete raw"
msgstr "Показати повний неформатований"
@@ -23592,7 +23894,7 @@ msgid "Job|This job is stuck because of one of the following problems. There are
msgstr ""
msgid "Job|This job is stuck because the project doesn't have any runners online assigned to it."
-msgstr "Це Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ðµ, тому що цей проєкт не має жодних ранерів призначених Ð´Ð»Ñ Ð½ÑŒÐ¾Ð³Ð¾."
+msgstr "Це Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð·Ð°Ð±Ð»Ð¾ÐºÐ¾Ð²Ð°Ð½Ðµ, тому що цей проєкт не має жодних раннерів призначених Ð´Ð»Ñ Ð½ÑŒÐ¾Ð³Ð¾."
msgid "Job|This job is stuck because you don't have any active runners that can run this job."
msgstr ""
@@ -23923,9 +24225,6 @@ msgstr "ВоÑтаннє редаговано %{link_start}%{avatar} %{name}%{li
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr "ОÑÑ‚Ð°Ð½Ð½Ñ Ð·Ð¼Ñ–Ð½Ð°"
@@ -24079,6 +24378,15 @@ msgstr "ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про групи."
msgid "Learn more about issues."
msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про задачі."
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° задачі та інциденти"
+
msgid "Learn more about max seats used"
msgstr ""
@@ -24131,16 +24439,16 @@ msgid "LearnGitLab|Enable require merge approvals"
msgstr ""
msgid "LearnGitLab|GitLab works best as a team. Invite your colleague to enjoy all features."
-msgstr ""
+msgstr "GitLab діє ефективніше у команді. ЗапроÑÑ–Ñ‚ÑŒ ваших колег, аби наÑолодитиÑÑ ÑƒÑіма функціÑми."
msgid "LearnGitLab|Invite your colleagues"
-msgstr ""
+msgstr "ЗапроÑÑ–Ñ‚ÑŒ ваших колег"
msgid "LearnGitLab|Learn GitLab"
msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про GitLab"
msgid "LearnGitLab|Plan and execute"
-msgstr ""
+msgstr "Плануйте та виконуйте"
msgid "LearnGitLab|Prevent unexpected changes to important assets by assigning ownership of files and paths."
msgstr ""
@@ -24229,9 +24537,6 @@ msgstr "Залишити проєкт"
msgid "Leave zen mode"
msgstr "Залишити режим дзен"
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24242,7 +24547,7 @@ msgid "Less Details"
msgstr ""
msgid "Less restrictive visibility"
-msgstr ""
+msgstr "Менш обмежена видиміÑÑ‚ÑŒ"
msgid "Let's Encrypt does not accept emails on example.com"
msgstr "Let's Encrypt не приймає Ð°Ð´Ñ€ÐµÑ ÐµÐ»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð¾Ñ— пошти з example.com"
@@ -24490,6 +24795,12 @@ msgstr "Зміни Ñ€Ñдка"
msgid "Link"
msgstr "ПоÑиланнÑ"
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr "ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ (необов'Ñзково)"
@@ -24760,9 +25071,6 @@ msgstr ""
msgid "Logs"
msgstr "Логи"
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr "ПриÑутні вразливоÑÑ‚Ñ– низького рівнÑ"
@@ -24775,6 +25083,9 @@ msgstr "MD5"
msgid "MERGED"
msgstr "ЗЛИТО"
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr "ПовернутиÑÑ Ð´Ð¾ запиту на злиттÑ"
@@ -24811,8 +25122,14 @@ msgstr "Показувати лише зміни"
msgid "MRDiff|Show full file"
msgstr "Показувати файл повніÑÑ‚ÑŽ"
-msgid "Made this issue confidential."
-msgstr "Цю задачу зроблено конфіденційною."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
+msgstr ""
msgid "Mailgun"
msgstr "Mailgun"
@@ -24826,9 +25143,15 @@ msgstr ""
msgid "Main menu"
msgstr "Головне меню"
+msgid "Maintainer"
+msgstr "Керівник"
+
msgid "Maintenance mode"
msgstr "Режим обÑлуговуваннÑ"
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24838,9 +25161,6 @@ msgstr "ЗдійÑнити та переглÑнути зміни в браузÐ
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr "Зробіть кожного учаÑника команди більш продуктивним незалежно від його міÑцезнаходженнÑ. GitLab Geo Ñтворює копії \"тільки Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ\" вашого GitLab Ñервера, щоб Ñкоротити Ñ‡Ð°Ñ Ð´Ð»Ñ ÐºÐ»Ð¾Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ñ– Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ ÐºÐ¾Ð´Ñƒ з великих репозиторіїв."
-msgid "Make issue confidential"
-msgstr "Зробити задачу конфіденційною"
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24850,8 +25170,8 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr "ПереконайтеÑÑ, що ви його зберегли, бо ви не зможете отримати доÑтуп до нього знову."
-msgid "Makes this issue confidential."
-msgstr "Робить цю задачу конфіденційною."
+msgid "Makes this %{type} confidential."
+msgstr ""
msgid "Manage %{workspace} labels"
msgstr ""
@@ -24899,7 +25219,7 @@ msgid "Manage your project's triggers"
msgstr ""
msgid "Manage your subscription"
-msgstr ""
+msgstr "Керувати вашою підпиÑкою"
msgid "Managed Account"
msgstr "Керований обліковий запиÑ"
@@ -24907,6 +25227,9 @@ msgstr "Керований обліковий запиÑ"
msgid "Manifest"
msgstr "МаніфеÑÑ‚"
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr "Імпортувати файл маніфеÑту"
@@ -24931,6 +25254,9 @@ msgstr "бер."
msgid "March"
msgstr "березень"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr "Відмітити Ñк виконано"
@@ -24982,6 +25308,9 @@ msgstr "Додати закреÑлений текÑÑ‚ (%{modifierKey}⇧X)"
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr "Додати закреÑлений текÑÑ‚ (%{modifier_key}⇧X)"
+msgid "MarkdownEditor|Click to expand"
+msgstr "ÐатиÑніть, щоб розгорнути"
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr "ВідÑтуп Ñ€Ñдка (%{modifierKey}])"
@@ -24994,11 +25323,14 @@ msgstr "ВиÑтуп Ñ€Ñдка (%{modifierKey}[)"
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr "ВиÑтуп Ñ€Ñдка (%{modifier_key}[)"
+msgid "MarkdownEditor|header"
+msgstr "заголовок"
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr "ПідтримуєтьÑÑ %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgid "Marked"
-msgstr ""
+msgstr "Позначено"
msgid "Marked For Deletion At - %{deletion_time}"
msgstr ""
@@ -25130,7 +25462,7 @@ msgid "Maximum allowable lifetime for access token (days)"
msgstr ""
msgid "Maximum allowed lifetime for SSH keys (days)"
-msgstr ""
+msgstr "МакÑимально дозволений термін екÑплуатації ключів SSH (днів)"
msgid "Maximum artifacts size"
msgstr "МакÑимальний розмір артефактів"
@@ -25626,6 +25958,9 @@ msgstr "Запити на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ñ– Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð±ÑƒÐ»Ð¸ пе
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ â€” це ÑпоÑіб запропонувати Ñвої зміни до проєкту Ñ– обговорити Ñ—Ñ… із іншими"
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25669,7 +26004,7 @@ msgid "MergeConflict|origin//their changes"
msgstr "Зміни між origin та їхнім"
msgid "MergeRequestAnalytics|Assignees"
-msgstr ""
+msgstr "Виконавець"
msgid "MergeRequestAnalytics|Date Merged"
msgstr ""
@@ -25792,7 +26127,7 @@ msgid "MergeTopics|%{sourceTopic} will be removed"
msgstr "%{sourceTopic} буде видалено"
msgid "MergeTopics|All assigned projects will be moved to %{targetTopic}"
-msgstr ""
+msgstr "Ð’ÑÑ– призначені проєкти будуть переміщені в %{targetTopic}"
msgid "MergeTopics|Merge topics"
msgstr "Об’єднати теми"
@@ -25801,7 +26136,7 @@ msgid "MergeTopics|Merging topics will cause the following:"
msgstr "ÐžÐ±â€™Ñ”Ð´Ð½Ð°Ð½Ð½Ñ Ñ‚ÐµÐ¼ може викликати наÑтупне:"
msgid "MergeTopics|Move all assigned projects from the source topic to the target topic and remove the source topic."
-msgstr ""
+msgstr "ПереміÑтити вÑÑ– призначені проєкти з вихідної теми в цільову тему Ñ– видалити початкову тему."
msgid "MergeTopics|Source topic"
msgstr "Вихідна тема"
@@ -25851,6 +26186,9 @@ msgstr "Метод"
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr "Метрику уÑпішно додано."
@@ -26246,6 +26584,9 @@ msgstr "Дата Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð½Ñ ÐµÑ‚Ð°Ð¿Ñƒ"
msgid "Milestone lists not available with your current license"
msgstr "СпиÑки етапів не доÑтупні з вашою поточною ліцензією"
+msgid "Milestone(s) not found: %{milestones}"
+msgstr "Етап(и) не знайдено: %{milestones}"
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26364,7 +26705,7 @@ msgid "Milestones|Ongoing Issues (open and assigned)"
msgstr "Поточні задачі (відкриті та призначені)"
msgid "Milestones|Organize issues and merge requests into a cohesive group, and set optional start and due dates. %{learn_more_link}"
-msgstr ""
+msgstr "ВпорÑдкувати задачі та об'єднати запити в ціліÑну групу, а також вÑтановити необов'Ñзкові дати початку та заплановану дату завершеннÑ. %{learn_more_link}"
msgid "Milestones|Project Milestone"
msgstr "Етап проєкту"
@@ -26405,6 +26746,9 @@ msgstr "%{percentage}%{percent} завершено"
msgid "Min Value"
msgstr "Мінімальне значеннÑ"
+msgid "Minimal Access"
+msgstr "Мінімальний ДоÑтуп"
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr "Мінімальна доÑтупна пропуÑкна здатніÑÑ‚ÑŒ необхідна Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку попередньої Ñинхронізації дзеркал."
@@ -26477,6 +26821,9 @@ msgstr "Ви не можете відправлÑти або отримуватÐ
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr "Ви не зможете відправлÑти або отримувати репозиторії через SSH, поки не додаÑте ключ SSH до Ñвого профілю."
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr "Додати проєкти"
@@ -26508,7 +26855,7 @@ msgid "Monitor"
msgstr "Моніторинг"
msgid "Monitor GitLab with Prometheus."
-msgstr ""
+msgstr "Моніторинг GitLab за допомогою Prometheus."
msgid "Monitor Settings"
msgstr ""
@@ -26663,6 +27010,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr "Має бути 90 днів і більше."
+
msgid "My awesome group"
msgstr ""
@@ -26966,7 +27316,7 @@ msgid "New epic title"
msgstr "Заголовок нового епіка"
msgid "New error tracking access token has been generated!"
-msgstr ""
+msgstr "Згенеровано новий токен доÑтупу відÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ð¿Ð¾Ð¼Ð¸Ð»Ð¾Ðº!"
msgid "New file"
msgstr "Ðовий файл"
@@ -27041,7 +27391,7 @@ msgid "New response for issue #%{issue_iid}:"
msgstr ""
msgid "New runners registration token has been generated!"
-msgstr "Згенеровано новий реєÑтраційний токен runner-ів!"
+msgstr "Згенеровано новий реєÑтраційний токен раннерів!"
msgid "New schedule"
msgstr "Ðовий Розклад"
@@ -27125,7 +27475,10 @@ msgid "No Scopes"
msgstr ""
msgid "No Work Item Link found"
-msgstr ""
+msgstr "ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° робочий елемент не знайдено"
+
+msgid "No access"
+msgstr "Ðемає доÑтупу"
msgid "No active admin user found"
msgstr "Ðе знайдено активного адмініÑтратора"
@@ -27194,7 +27547,7 @@ msgid "No credit card required."
msgstr "Ðе потрібна кредитна картка."
msgid "No data available"
-msgstr ""
+msgstr "Ðемає даних"
msgid "No data found"
msgstr "Даних не знайдено"
@@ -27256,9 +27609,6 @@ msgstr "Ðемає ітерацій Ð´Ð»Ñ Ð¿Ð¾ÐºÐ°Ð·Ñƒ"
msgid "No job log"
msgstr "Ðемає журналу завданнÑ"
-msgid "No jobs to show"
-msgstr "Ðемає завдань Ð´Ð»Ñ Ð²Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ"
-
msgid "No label"
msgstr "Без мітки"
@@ -27286,9 +27636,6 @@ msgstr "Ðемає відповідних результатів"
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr "Ðемає відповідних результатів..."
-
msgid "No members found"
msgstr ""
@@ -27304,9 +27651,6 @@ msgstr "Ðемає повідомлень у журналі"
msgid "No milestone"
msgstr "Етап відÑутній"
-msgid "No namespace"
-msgstr "Ðемає проÑтору імен"
-
msgid "No other labels with such name or description"
msgstr "Ðемає інших міток з таким іменем або опиÑом"
@@ -27542,8 +27886,8 @@ msgstr "Згорнути відповіді"
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
-msgstr ""
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
+msgstr "Внутрішні нотатки видимі лише Ð´Ð»Ñ ÑƒÑ‡Ð°Ñників, що мають роль репортера або вище"
msgid "Notes|Last reply by %{name}"
msgstr ""
@@ -27570,13 +27914,13 @@ msgid "Notes|You're only seeing %{boldStart}other activity%{boldEnd} in the feed
msgstr "Ви бачите лише %{boldStart}іншу активніÑÑ‚ÑŒ%{boldEnd} в каналі. Ð”Ð»Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ ÐºÐ¾Ð¼ÐµÐ½Ñ‚Ð°Ñ€Ñ, виберіть одну з наÑтупних опцій."
msgid "Note|The created date provided is too far in the past."
-msgstr ""
+msgstr "Вказана дата занадто далеко в минулому."
msgid "Nothing to preview."
msgstr "Дані Ð´Ð»Ñ Ð¿ÐµÑ€ÐµÐ³Ð»Ñду відÑутні."
msgid "Notification Email"
-msgstr ""
+msgstr "Електронна пошта Ð´Ð»Ñ Ñповіщень"
msgid "Notification events"
msgstr "ÐŸÐ¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ події"
@@ -27718,19 +28062,19 @@ msgid "Notify|%{author_link}'s issue %{issue_reference_link} is due soon."
msgstr ""
msgid "Notify|%{author_name} %{action_name} %{ref_type} %{ref_name} at %{project_link}"
-msgstr ""
+msgstr "%{author_name} %{action_name} %{ref_type} %{ref_name} о %{project_link}"
msgid "Notify|%{changed_files}:"
-msgstr ""
+msgstr "%{changed_files}:"
msgid "Notify|%{commit_link} in %{mr_link}"
msgstr "%{commit_link} в %{mr_link}"
msgid "Notify|%{commits_text} from branch `%{target_branch}`"
-msgstr ""
+msgstr "%{commits_text} з гілки `%{target_branch}`"
msgid "Notify|%{committed_by_start} by %{author_name} %{committed_by_end} %{committed_at_start} at %{committed_date} %{committed_at_end}"
-msgstr ""
+msgstr "%{committed_by_start} від %{author_name} %{committed_by_end} %{committed_at_start} о %{committed_date} %{committed_at_end}"
msgid "Notify|%{invite_email}, now known as %{user_name}, has accepted your invitation to join the %{target_name} %{target_model_name}."
msgstr "%{invite_email}, тепер відомий Ñк %{user_name}, прийнÑв ваше Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð¿Ñ€Ð¸Ñ”Ð´Ð½Ð°Ñ‚Ð¸ÑÑ Ð´Ð¾ %{target_name} %{target_model_name}."
@@ -27745,55 +28089,55 @@ msgid "Notify|%{member_link} requested %{member_role} access to the %{target_sou
msgstr "%{member_link} запроÑив %{member_role} доÑтуп до %{target_source_link} %{target_type}."
msgid "Notify|%{mr_highlight}Merge request%{highlight_end} %{mr_link} %{reviewer_highlight}was approved by%{highlight_end} %{reviewer_avatar} %{reviewer_link}"
-msgstr ""
+msgstr "%{mr_highlight}Запит на злиттÑ%{highlight_end} %{mr_link} %{reviewer_highlight}було Ñхвалено%{highlight_end} %{reviewer_avatar} %{reviewer_link}"
msgid "Notify|%{mr_highlight}Merge request%{highlight_end} %{mr_link} %{reviewer_highlight}was unapproved by%{highlight_end} %{reviewer_avatar} %{reviewer_link}"
-msgstr ""
+msgstr "%{mr_highlight}Запит на злиттÑ%{highlight_end} %{mr_link} %{reviewer_highlight}було відхилено%{highlight_end} %{reviewer_avatar} %{reviewer_link}"
msgid "Notify|%{name} requested a new review on %{mr_link}."
msgstr ""
msgid "Notify|%{p_start}To update the remote url in your local repository run (for ssh):%{p_end} %{ssh_url_to_repo} %{p_start}or for http(s):%{p_end} %{http_url_to_repo}"
-msgstr ""
+msgstr "%{p_start}Щоб оновити віддалений URL у вашому локальному репозиторію виконайте (Ð´Ð»Ñ ssh):%{p_end} %{ssh_url_to_repo} %{p_start}або Ð´Ð»Ñ http(s):%{p_end} %{http_url_to_repo}"
msgid "Notify|%{paragraph_start}Hi %{name}!%{paragraph_end} %{paragraph_start}A new public key was added to your account:%{paragraph_end} %{paragraph_start}title: %{key_title}%{paragraph_end} %{paragraph_start}If this key was added in error, you can remove it under %{removal_link}%{paragraph_end}"
-msgstr ""
+msgstr "%{paragraph_start}Привіт %{name}!%{paragraph_end} %{paragraph_start}До вашого облікового запиÑу додано новий публічний ключ:%{paragraph_end} %{paragraph_start}назва: %{key_title}%{paragraph_end} %{paragraph_start}Якщо цей ключ додано помилково, ви можете видалити його в розділі %{removal_link}%{paragraph_end}"
msgid "Notify|%{project_link_start}Download%{project_link_end} the project export."
-msgstr ""
+msgstr "%{project_link_start}Завантажте%{project_link_end} екÑпорт проєкту."
msgid "Notify|%{update_at_start} Last update at %{update_at_mid} %{last_update_at} %{update_at_end}"
-msgstr ""
+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 ""
+msgstr "%{updated_by_user_name} надіÑлав нові коміти Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ %{mr_link}"
msgid "Notify|A new GPG key was added to your account:"
-msgstr ""
+msgstr "Ðовий ключ GPG додано до вашого облікового запиÑу:"
msgid "Notify|A remote mirror update has failed."
-msgstr ""
+msgstr "Помилка Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð²Ñ–Ð´Ð´Ð°Ð»ÐµÐ½Ð¾Ð³Ð¾ дзеркала."
msgid "Notify|After it expires, you can %{a_start} request a new one %{a_end}."
msgstr "ПіÑÐ»Ñ Ð·Ð°ÐºÑ–Ð½Ñ‡ÐµÐ½Ð½Ñ Ñ‚ÐµÑ€Ð¼Ñ–Ð½Ñƒ дії ви можете %{a_start} подати запит на новий %{a_end}."
msgid "Notify|All discussions on merge request %{mr_link} were resolved by %{name}"
-msgstr ""
+msgstr "Ð’ÑÑ– Ð¾Ð±Ð³Ð¾Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ñ‰Ð¾Ð´Ð¾ запиту на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ %{mr_link} були вирішені %{name}"
msgid "Notify|And %{total_stripped_new_commits_count} more"
-msgstr ""
+msgstr "Та ще %{total_stripped_new_commits_count}"
msgid "Notify|Assignee changed from %{fromNames} to %{toNames}"
-msgstr ""
+msgstr "Ð’Ð¸ÐºÐ¾Ð½Ð°Ð²Ñ†Ñ Ð·Ð¼Ñ–Ð½ÐµÐ½Ð¾ з %{fromNames} на %{toNames}"
msgid "Notify|Assignee changed to %{toNames}"
-msgstr ""
+msgstr "Ð’Ð¸ÐºÐ¾Ð½Ð°Ð²Ñ†Ñ Ð·Ð¼Ñ–Ð½ÐµÐ½Ð¾ на %{toNames}"
msgid "Notify|Author: %{author_name}"
msgstr "Ðвтор: %{author_name}"
msgid "Notify|Auto DevOps pipeline was disabled for %{project}"
-msgstr ""
+msgstr "Конвеєр Auto DevOps було вимкнено Ð´Ð»Ñ %{project}"
msgid "Notify|CI/CD project settings"
msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ CI/CD"
@@ -27802,16 +28146,16 @@ msgid "Notify|Click here to set your password"
msgstr "ÐатиÑніть тут, щоб уÑтановити пароль"
msgid "Notify|Commit Author"
-msgstr ""
+msgstr "Ðвтор коміту"
msgid "Notify|Committed by"
msgstr "Закомічено"
msgid "Notify|Don't want to receive updates from GitLab administrators?"
-msgstr ""
+msgstr "Ðе хочете отримувати Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ адмініÑтраторів GitLab?"
msgid "Notify|Error parsing CSV file. Please make sure it has the correct format: a delimited text file that uses a comma to separate values."
-msgstr ""
+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}. Будь лаÑка, перевірте, чи ці Ñ€Ñдки мають заголовок проблеми."
@@ -27826,40 +28170,40 @@ msgid "Notify|Hi %{user}!"
msgstr "Привіт %{user}!"
msgid "Notify|If this key was added in error, you can remove it under %{removal_link}"
-msgstr ""
+msgstr "Якщо цей ключ був доданий з помилкою, ви можете видалити його під %{removal_link}"
msgid "Notify|If you no longer wish to use this domain with GitLab Pages, please remove it from your GitLab project and delete any related DNS records."
msgstr ""
msgid "Notify|Issue was %{issue_status} by %{updated_by}"
-msgstr ""
+msgstr "Задача була %{issue_status} від %{updated_by}"
msgid "Notify|Issue was moved to another project."
-msgstr ""
+msgstr "Задача була перенеÑена до іншого проєкту."
msgid "Notify|Learn more about Auto DevOps"
msgstr "ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про Auto DevOps"
msgid "Notify|Logs may contain sensitive data. Please consider before forwarding this email."
-msgstr ""
+msgstr "Логи можуть міÑтити конфіденційні дані. Будь лаÑка, подумайте, перш ніж переÑилати цей електронний лиÑÑ‚."
msgid "Notify|Merge request %{merge_request} can no longer be merged due to conflict."
-msgstr ""
+msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ %{merge_request} більше не може бути злитий через конфлікт."
msgid "Notify|Merge request %{merge_request} was %{mr_status}"
-msgstr ""
+msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ %{merge_request} був %{mr_status}"
msgid "Notify|Merge request %{merge_request} was %{mr_status} by %{updated_by}"
-msgstr ""
+msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ %{merge_request} був %{mr_status} кориÑтувачем %{updated_by}"
msgid "Notify|Merge request %{merge_request} was merged"
-msgstr ""
+msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ %{merge_request} було об’єднано"
msgid "Notify|Merge request %{mr_link} was closed by %{closed_by}"
-msgstr ""
+msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ %{mr_link} був закритий %{closed_by}"
msgid "Notify|Merge request URL: %{merge_request_url}"
-msgstr ""
+msgstr "URL-адреÑа запиту на злиттÑ: %{merge_request_url}"
msgid "Notify|Merge request was approved"
msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð±ÑƒÐ² Ñхвалений"
@@ -27868,10 +28212,10 @@ msgid "Notify|Merge request was approved (%{approvals}/%{required_approvals})"
msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð±ÑƒÐ² затверджений (%{approvals}/%{required_approvals})"
msgid "Notify|Merge request was unapproved"
-msgstr ""
+msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð½Ðµ Ñхвалено"
msgid "Notify|Merge request was unapproved (%{approvals_count}/%{approvals_required})"
-msgstr ""
+msgstr "Запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð½Ðµ Ñхвалено (%{approvals_count}/%{approvals_required})"
msgid "Notify|Milestone changed to %{milestone}"
msgstr "Етап змінено на %{milestone}"
@@ -27880,55 +28224,64 @@ msgid "Notify|Milestone removed"
msgstr "Етап видалено"
msgid "Notify|New issue: %{project_issue_url}"
-msgstr ""
+msgstr "Ðова задача: %{project_issue_url}"
msgid "Notify|No preview for this file type"
-msgstr ""
+msgstr "Ðемає попереднього переглÑду Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ типу файлу"
+
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr "Конвеєр #%{pipeline_id} вийшов з ладу!"
msgid "Notify|Pipeline %{pipeline_link} triggered by"
-msgstr ""
+msgstr "Конвеєр %{pipeline_link} запущено"
msgid "Notify|Pipeline has been fixed and #%{pipeline_id} has passed!"
-msgstr ""
+msgstr "Конвеєр виправлено, і #%{pipeline_id} виконано!"
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
-msgstr ""
+msgstr "Проєкт %{old_path_with_namespace} переміщено в інше міÑце."
+
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr "Проєкт %{project_name} не вдалоÑÑ ÐµÐºÑпортувати."
msgid "Notify|Project %{project_name} was exported successfully."
-msgstr ""
+msgstr "Проєкт %{project_name} уÑпішно екÑпортовано."
msgid "Notify|Remote mirror"
-msgstr ""
+msgstr "Віддалене дзеркало"
msgid "Notify|The Administrator created an account for you. Now you are a member of the company GitLab application."
-msgstr ""
+msgstr "ÐдмініÑтратор Ñтворив Ð´Ð»Ñ Ð²Ð°Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¸Ð¹ запиÑ. Тепер ви Ñ” учаÑником компанії GitLab заÑтоÑунку."
msgid "Notify|The Auto DevOps pipeline failed for pipeline %{pipeline_link} and has been disabled for %{project_link}. In order to use the Auto DevOps pipeline with your project, please review the %{supported_langs_link}, adjust your project accordingly, and turn on the Auto DevOps pipeline within your %{settings_link}."
msgstr ""
msgid "Notify|The diff for this file was not included because it is too large."
-msgstr ""
+msgstr "Ð Ñ–Ð·Ð½Ð¸Ñ†Ñ Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ файлу не була включена, тому що він завеликий."
msgid "Notify|The diff was not included because it is too large."
-msgstr ""
+msgstr "Ð Ñ–Ð·Ð½Ð¸Ñ†Ñ Ð½Ðµ була включена тому, що вона завелика."
msgid "Notify|The download link will expire in 24 hours."
msgstr "Термін дії поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶ÐµÐ½Ð½Ñ Ð·Ð°ÐºÑ–Ð½Ñ‡Ð¸Ñ‚ÑŒÑÑ Ñ‡ÐµÑ€ÐµÐ· 24 години."
+msgid "Notify|The errors we encountered were:"
+msgstr "Помилки, з Ñкими ми зіткнулиÑÑ, були:"
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
-msgstr ""
+msgstr "Проєкт зараз знаходитьÑÑ Ð¿Ñ–Ð´ %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgid "Notify|The push did not contain any new commits, but force pushed to delete the commits and changes below."
msgstr ""
msgid "Notify|This issue is due on: %{issue_due_date}"
-msgstr ""
+msgstr "Ð¦Ñ Ð·Ð°Ð´Ð°Ñ‡Ð° запланована: %{issue_due_date}"
msgid "Notify|This link is valid for %{password_reset_token_valid_time}."
msgstr "Це поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð´Ñ–Ð¹Ñне Ð´Ð»Ñ %{password_reset_token_valid_time}."
msgid "Notify|Unless you verify your domain by %{time_start}%{time}%{time_end} it will be removed from your GitLab project."
-msgstr ""
+msgstr "Якщо ви не підтвердите ваш домен на %{time_start}%{time}%{time_end} його буде видалено із вашого проєкту GitLab."
msgid "Notify|You don't have access to the project."
msgstr "Ви не маєте доÑтупу до цього проєкту"
@@ -27940,10 +28293,10 @@ msgid "Notify|You have been mentioned in merge request %{mr_link}"
msgstr "Ð’Ð°Ñ Ð·Ð³Ð°Ð´Ð°Ð»Ð¸ у запиті на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ %{mr_link}"
msgid "Notify|You have been unsubscribed from receiving GitLab administrator notifications."
-msgstr ""
+msgstr "Вашу підпиÑку на ÑÐ¿Ð¾Ð²Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð°Ð´Ð¼Ñ–Ð½Ñ–Ñтратора GitLab ÑкаÑовано."
msgid "Notify|Your CSV import for project %{project_link} has been completed."
-msgstr ""
+msgstr "Ваш імпорт CSV Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ %{project_link} завершено."
msgid "Notify|Your account has been created successfully."
msgstr "Ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð±ÑƒÐ² уÑпішно Ñтворений"
@@ -27955,7 +28308,7 @@ msgid "Notify|currently supported languages"
msgstr "Ðаразі підтримуютьÑÑ Ð¼Ð¾Ð²Ð¸"
msgid "Notify|deleted"
-msgstr ""
+msgstr "Видалено"
msgid "Notify|login.........................................."
msgstr "увійти................................................."
@@ -28008,9 +28361,6 @@ msgstr "КількіÑÑ‚ÑŒ працівників"
msgid "Number of events"
msgstr "КількіÑÑ‚ÑŒ подій"
-msgid "Number of events for this project: %{total_count}."
-msgstr "КількіÑÑ‚ÑŒ подій в цьому проєкті: %{total_count}."
-
msgid "Number of files touched"
msgstr "КількіÑÑ‚ÑŒ змінених файлів"
@@ -28035,9 +28385,6 @@ msgstr "жовт."
msgid "October"
msgstr "жовтень"
-msgid "OfSearchInADropdown|Filter"
-msgstr "Фільтр"
-
msgid "Off"
msgstr "Вимк."
@@ -28060,7 +28407,7 @@ msgid "OmniAuth"
msgstr "OmniAuth"
msgid "On"
-msgstr ""
+msgstr "Увімкнути"
msgid "On %{end_date}, your trial will end and %{namespace_name} will be limited to %{free_user_limit} member"
msgid_plural "On %{end_date}, your trial will end and %{namespace_name} will be limited to %{free_user_limit} members"
@@ -28190,7 +28537,7 @@ msgid "OnCallSchedules|Rotations"
msgstr ""
msgid "OnCallSchedules|Route alerts directly to specific members of your team"
-msgstr ""
+msgstr "Ðаправити Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ Ð±ÐµÐ·Ð¿Ð¾Ñередньо певним учаÑникам вашої команди"
msgid "OnCallSchedules|Route alerts directly to specific members of your team. To access this feature, ask %{linkStart}a project Owner%{linkEnd} to grant you at least the Maintainer role."
msgstr ""
@@ -28273,12 +28620,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -28324,12 +28665,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr "Продовжити редагуваннÑ"
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -28351,12 +28686,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -28399,15 +28728,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28438,12 +28758,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28462,9 +28776,6 @@ msgstr "ПіÑÐ»Ñ Ñ–Ð¼Ð¿Ð¾Ñ€Ñ‚Ñƒ, репозиторії можуть бути
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr "ПіÑÐ»Ñ Ð¿Ñ–Ð´Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ñ‚Ð° натиÑÐ½ÐµÐ½Ð½Ñ \"Зменшити видиміÑÑ‚ÑŒ проєкту\":"
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] "Ще один елемент"
@@ -28640,9 +28951,6 @@ msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð·Ð°Ð²ÐµÑ€ÑˆÐ¸Ð»Ð°ÑÑ Ð½ÐµÐ²Ð´Ð°Ð»Ð¾. Перевірт
msgid "Operation not allowed"
msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð·Ð°Ð±Ð¾Ñ€Ð¾Ð½ÐµÐ½Ð°"
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr "ÐžÐ¿ÐµÑ€Ð°Ñ†Ñ–Ñ Ð¿ÐµÑ€ÐµÐ²Ð¸Ñ‰Ð¸Ð»Ð° ліміт очікуваннÑ. Перевірте журнал pod'а %{pod_name} Ð´Ð»Ñ Ð±Ñ–Ð»ÑŒÑˆ детальної інформації."
-
msgid "Operations"
msgstr "Операції"
@@ -28872,7 +29180,7 @@ msgid "Package type must be PyPi"
msgstr ""
msgid "Package type must be RPM"
-msgstr ""
+msgstr "Тип пакета має бути RPM"
msgid "Package type must be RubyGems"
msgstr ""
@@ -29013,12 +29321,21 @@ msgstr "Видалити пакет"
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr "Видалити верÑÑ–ÑŽ пакету"
+
msgid "PackageRegistry|Delete selected"
msgstr "Видалити вибране"
msgid "PackageRegistry|Delete this package"
msgstr "Видалити цей пакет"
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr "Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð²ÑÑ–Ñ… реÑурÑів пакета призведе до Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð²ÐµÑ€ÑÑ–Ñ— %{version} з %{name}. Ви впевнені?"
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr "Ð’Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð¾Ñтаннього пакета призведе до Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð²ÐµÑ€ÑÑ–Ñ— %{version} з %{name}. Ви впевнені?"
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -29026,7 +29343,7 @@ msgid "PackageRegistry|Error publishing"
msgstr ""
msgid "PackageRegistry|Examples of assets include .pom & .jar files"
-msgstr ""
+msgstr "Приклади активів включають файли .pom і .jar"
msgid "PackageRegistry|Failed to load the package data"
msgstr ""
@@ -29064,6 +29381,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr "Helm"
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr "Якщо ви ще не зробили цього, вам потрібно буде додати розміщене нижче в Ñвій файл %{codeStart}.pypirc%{codeEnd}."
@@ -29089,7 +29412,7 @@ msgid "PackageRegistry|License information located at %{link}"
msgstr ""
msgid "PackageRegistry|Manage storage used by package assets"
-msgstr ""
+msgstr "ÐšÐµÑ€ÑƒÐ²Ð°Ð½Ð½Ñ Ñховищем, Ñке викориÑтовуєтьÑÑ Ñ€ÐµÑурÑами пакета"
msgid "PackageRegistry|Manually Published"
msgstr "Опубліковано вручну"
@@ -29119,7 +29442,7 @@ msgid "PackageRegistry|Package asset deleted successfully"
msgstr ""
msgid "PackageRegistry|Package assets deleted successfully"
-msgstr ""
+msgstr "РеÑурÑи пакета уÑпішно видалено"
msgid "PackageRegistry|Package deleted successfully"
msgstr "Пакет уÑпішно видалено"
@@ -29138,10 +29461,10 @@ msgid "PackageRegistry|Package updated by commit %{link} on branch %{branch}, bu
msgstr "Пакет оновлено через коміт %{link} в гілці %{branch}, побудований через конвеєр %{pipeline}та опублікований в реєÑÑ‚Ñ€ %{datetime}"
msgid "PackageRegistry|Permanently delete"
-msgstr ""
+msgstr "Видалити назавжди"
msgid "PackageRegistry|Permanently delete assets"
-msgstr ""
+msgstr "ОÑтаточно видалити реÑурÑи"
msgid "PackageRegistry|Pip Command"
msgstr "Команда pip"
@@ -29195,7 +29518,7 @@ msgid "PackageRegistry|Something went wrong while deleting the package asset."
msgstr ""
msgid "PackageRegistry|Something went wrong while deleting the package assets."
-msgstr ""
+msgstr "ЩоÑÑŒ пішло не так під Ñ‡Ð°Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñ€ÐµÑурÑів пакета."
msgid "PackageRegistry|Something went wrong while deleting the package."
msgstr "ЩоÑÑŒ пішло не так під Ñ‡Ð°Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð¿Ð°ÐºÐµÑ‚Ð°."
@@ -29212,6 +29535,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr "Пройдіть опитуваннÑ"
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29252,7 +29578,7 @@ msgid "PackageRegistry|You are about to delete %{filename}. This is a destructiv
msgstr ""
msgid "PackageRegistry|You are about to delete %{name}, are you sure?"
-msgstr ""
+msgstr "Ви збираєтеÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ %{name}, ви впевнені?"
msgid "PackageRegistry|You are about to delete 1 asset. This operation is irreversible."
msgid_plural "PackageRegistry|You are about to delete %d assets. This operation is irreversible."
@@ -29597,12 +29923,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29634,7 +29954,7 @@ msgid "Personal projects limit:"
msgstr ""
msgid "PersonalProject|Learn to move a project to a group"
-msgstr ""
+msgstr "ÐавчітьÑÑ Ð¿ÐµÑ€ÐµÐ¼Ñ–Ñ‰ÑƒÐ²Ð°Ñ‚Ð¸ проєкт до групи"
msgid "PersonalProject|Some GitLab features, including the ability to upgrade to a paid plan or start a free trial, are only available for groups and projects inside groups. %{projectName} is a personal project, so none of this is available. We recommend you move your project to a group to unlock GitLab's full potential."
msgstr ""
@@ -29651,8 +29971,8 @@ msgstr "Ð†Ð¼Ð¿Ð¾Ñ€Ñ‚ÑƒÐ²Ð°Ñ‚Ñ‚Ñ Ñ–Ð· Ñерверу Phabricator"
msgid "Phabricator Server URL"
msgstr "URL-адреÑа Ñерверу Phabricator"
-msgid "Phabricator Tasks"
-msgstr "Задачі Phabricator"
+msgid "Phabricator tasks"
+msgstr ""
msgid "Phone"
msgstr "Телефон"
@@ -29814,7 +30134,7 @@ msgid "PipelineEditor|Other pipeline sources are not available yet."
msgstr ""
msgid "PipelineEditor|Pipeline Source"
-msgstr ""
+msgstr "Джерело конвеєра"
msgid "PipelineEditor|Pipeline behavior will be simulated including the %{codeStart}rules%{codeEnd} %{codeStart}only%{codeEnd} %{codeStart}except%{codeEnd} and %{codeStart}needs%{codeEnd} job dependencies."
msgstr ""
@@ -29853,7 +30173,7 @@ msgid "PipelineEditor|Validate pipeline under simulated conditions"
msgstr ""
msgid "PipelineEditor|Validating pipeline... It can take up to a minute."
-msgstr ""
+msgstr "Перевірка конвеєра... Це може зайнÑти до хвилини."
msgid "PipelineEditor|Waiting for CI content to load..."
msgstr ""
@@ -29870,19 +30190,25 @@ msgstr "Ðктивні"
msgid "PipelineSchedules|All"
msgstr "Ð’ÑÑ–"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr "Ви впевнені, що хочете видалити цей розклад Ð´Ð»Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ð°?"
+
msgid "PipelineSchedules|Delete pipeline schedule"
-msgstr ""
+msgstr "Видалити розклад конвеєра"
msgid "PipelineSchedules|Description"
-msgstr ""
+msgstr "ОпиÑ"
msgid "PipelineSchedules|Edit pipeline schedule"
-msgstr ""
+msgstr "Редагувати розклад конвеєра"
msgid "PipelineSchedules|Inactive"
msgstr "Ðеактивні"
msgid "PipelineSchedules|Last Pipeline"
+msgstr "ОÑтанній Конвеєр"
+
+msgid "PipelineSchedules|New schedule"
msgstr ""
msgid "PipelineSchedules|Next Run"
@@ -29895,24 +30221,36 @@ msgid "PipelineSchedules|Only the owner of a pipeline schedule can make changes
msgstr "Лише влаÑник розкладу конвеєрів може внеÑти до нього зміни. Ви хочете взÑти право влаÑноÑÑ‚Ñ– на цей розклад?"
msgid "PipelineSchedules|Owner"
+msgstr "ВлаÑник"
+
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
msgstr ""
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "Задайте короткий Ð¾Ð¿Ð¸Ñ Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ конвеєру"
msgid "PipelineSchedules|Run pipeline schedule"
+msgstr "ЗапуÑтити розклад конвеєра"
+
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
msgstr ""
msgid "PipelineSchedules|Take ownership"
msgstr "Стати влаÑником"
msgid "PipelineSchedules|Take ownership of pipeline schedule"
-msgstr ""
+msgstr "Стати влаÑником розкладу конвеєрів"
msgid "PipelineSchedules|Target"
msgstr "Ціль"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr "Під Ñ‡Ð°Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ñ€Ð¾Ð·ÐºÐ»Ð°Ð´Ñƒ конвеєра виникла проблема."
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
+msgstr "Виникла проблема під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·ÐºÐ»Ð°Ð´Ñ–Ð² конвеєрів."
+
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
msgstr ""
msgid "PipelineSchedules|Variables"
@@ -30042,7 +30380,7 @@ msgid "Pipelines|2. Configure deployment pipeline"
msgstr ""
msgid "Pipelines|A GitLab Runner is an application that works with GitLab CI/CD to run jobs in a pipeline. Install GitLab Runner and register your own runners to get started with CI/CD."
-msgstr "GitLab ранер — це заÑтоÑунок, Ñкий працює з GitLab CI/CD Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð·Ð°Ð²Ð´Ð°Ð½ÑŒ у конвеєрі. Ð’Ñтановіть GitLab ранер та зареєÑтруйте влаÑні ранери Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку з CI/CD."
+msgstr "GitLab раннер — це заÑтоÑунок, Ñкий працює з GitLab CI/CD Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ð·Ð°Ð²Ð´Ð°Ð½ÑŒ у конвеєрі. Ð’Ñтановіть GitLab раннер та зареєÑтруйте влаÑні раннери Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑку з CI/CD."
msgid "Pipelines|API"
msgstr "API"
@@ -30072,7 +30410,7 @@ msgid "Pipelines|Child pipeline (%{link_start}parent%{link_end})"
msgstr ""
msgid "Pipelines|Clear runner caches"
-msgstr "ОчиÑтити кеш runner"
+msgstr "ОчиÑтити кеш раннер"
msgid "Pipelines|Configuration validation currently not available."
msgstr ""
@@ -30192,7 +30530,7 @@ msgid "Pipelines|Set up a runner"
msgstr ""
msgid "Pipelines|Something went wrong while cleaning runners cache."
-msgstr "Помилка при очищенні кеша ранерів."
+msgstr "Помилка при очищенні кеша раннерів."
msgid "Pipelines|The %{namespace_name} namespace has %{percentage}%% or less Shared Runner Pipeline minutes remaining. After it runs out, no new jobs or pipelines in its projects will run."
msgstr ""
@@ -30674,9 +31012,6 @@ msgstr ""
msgid "Please select a country"
msgstr "Будь лаÑка, виберіть країну"
-msgid "Please select a file"
-msgstr "Будь лаÑка, виберіть файл"
-
msgid "Please select a group"
msgstr ""
@@ -30785,6 +31120,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr "ÐвтентифікаціÑ"
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr "ПідключеннÑ"
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr "ОÑтаннє Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÐ²Ñ–Ñ€ÐºÐ¸ попереднього ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð±Ñ–Ð»ÑŒÑˆ не дійÑне, тому що ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð¼Ñ–Ð½Ð¸Ð»Ð°ÑÑ."
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr "Параметри"
@@ -30792,7 +31190,7 @@ msgid "Preferences saved."
msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð¾."
msgid "Preferences|Automatically add new list items"
-msgstr ""
+msgstr "Ðвтоматично додавати нові елементи ÑпиÑку"
msgid "Preferences|Behavior"
msgstr "Поведінка"
@@ -30828,7 +31226,7 @@ msgid "Preferences|Customize the colors of removed and added lines in diffs."
msgstr "Ðалаштувати кольори вилучених Ñ– доданих Ñ€Ñдків у відмінноÑÑ‚ÑÑ…."
msgid "Preferences|Dashboard"
-msgstr ""
+msgstr "Панель керуваннÑ"
msgid "Preferences|Diff colors"
msgstr "Колір різниці"
@@ -30906,7 +31304,7 @@ msgid "Preferences|Use relative times"
msgstr "ВикориÑтовувати відноÑний чаÑ"
msgid "Preferences|When you type in a description or comment box, pressing %{kbdOpen}Enter%{kbdClose} in a list adds a new item below."
-msgstr ""
+msgstr "Коли ви вводите Ð¾Ð¿Ð¸Ñ Ð°Ð±Ð¾ коментар, натиÑÐºÐ°Ð½Ð½Ñ ÐºÐ»Ð°Ð²Ñ–Ñˆ %{kbdOpen}Enter%{kbdClose} у ÑпиÑку додає новий елемент нижче."
msgid "Preferences|When you type in a description or comment box, selected text is surrounded by the corresponding character after typing one of the following characters: %{supported_characters}."
msgstr "Коли ви вводите Ð¾Ð¿Ð¸Ñ Ð°Ð±Ð¾ поле коментарÑ, виділений текÑÑ‚ оточуєтьÑÑ Ð²Ñ–Ð´Ð¿Ð¾Ð²Ñ–Ð´Ð½Ð¸Ð¼ Ñимволом піÑÐ»Ñ Ð²Ð²ÐµÐ´ÐµÐ½Ð½Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ з таких Ñимволів: %{supported_characters}."
@@ -30926,6 +31324,9 @@ msgstr "Заборонити редагувати правила ÑхваленÐ
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -31019,12 +31420,18 @@ msgstr ""
msgid "Proceed"
msgstr "Продовжити"
-msgid "Product Analytics"
-msgstr ""
+msgid "Product analytics"
+msgstr "Ðналітика продукту"
+
+msgid "ProductAnalytics|Audience"
+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|Widgets content"
+msgstr "ВміÑÑ‚ віджетів"
+
msgid "Productivity"
msgstr "ПродуктивніÑÑ‚ÑŒ"
@@ -31287,7 +31694,7 @@ msgid "Profiles|Notification email"
msgstr "ÐдреÑа електронної пошти Ð´Ð»Ñ Ñповіщень"
msgid "Profiles|Optional but recommended. If set, key becomes invalid on the specified date."
-msgstr ""
+msgstr "Ðеобов'Ñзково, але рекомендовано. Якщо задано, ключ Ñтає недійÑним у вказаній даті."
msgid "Profiles|Organization"
msgstr "ОрганізаціÑ"
@@ -31368,7 +31775,7 @@ msgid "Profiles|Time settings"
msgstr "Параметри чаÑу"
msgid "Profiles|Title"
-msgstr ""
+msgstr "Заголовок"
msgid "Profiles|Two-factor authentication"
msgstr "Двофакторна автентифікаціÑ"
@@ -31524,7 +31931,7 @@ msgid "Project URL"
msgstr "URL-адреÑа проєкту"
msgid "Project access must be granted explicitly to each user. If this project is part of a group, access is granted to members of the group."
-msgstr ""
+msgstr "ДоÑтуп до проєкту повинен надаватиÑÑ ÐºÐ¾Ð¶Ð½Ð¾Ð¼Ñƒ кориÑтувачеві. Якщо цей проєкт Ñ” чаÑтиною групи, доÑтуп буде надано учаÑникам групи."
msgid "Project access token creation is disabled in this group. You can still use and manage existing tokens. %{link_start}Learn more.%{link_end}"
msgstr ""
@@ -31601,6 +32008,9 @@ msgstr "Ðазва проєкту"
msgid "Project navigation"
msgstr "ÐÐ°Ð²Ñ–Ð³Ð°Ñ†Ñ–Ñ Ð¿Ð¾ проєкту"
+msgid "Project or Group"
+msgstr "Проєкт або Група"
+
msgid "Project order will not be saved as local storage is not available."
msgstr "ПорÑдок проєктів не буде збережено, тому що локальне Ñховище недоÑтупне."
@@ -31613,6 +32023,9 @@ msgstr "Стан безпеки проєкту"
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr "ШлÑÑ… проєкту"
@@ -31895,12 +32308,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr "Додаткові параметри"
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr "Додаткові налаштуваннÑ, Ñкі впливають на те, Ñк Ñ– коли виконуютьÑÑ Ð·Ð»Ð¸Ñ‚Ñ‚Ñ."
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31913,12 +32332,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr "Ðналітика"
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr "Значки"
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr "Збирайте, теÑтуйте та розгортайте Ñвої зміни."
@@ -31940,6 +32365,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr "Ðалаштуйте реÑурÑи вашого проєкту Ñ– відÑтежуйте Ñ—Ñ… здоров'Ñ."
@@ -32034,11 +32462,14 @@ msgid "ProjectSettings|Housekeeping, export, archive, change path, transfer, and
msgstr ""
msgid "ProjectSettings|How do they differ?"
-msgstr ""
+msgstr "Чим вони відрізнÑÑŽÑ‚ÑŒÑÑ?"
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr "Внутрішній"
@@ -32061,7 +32492,7 @@ msgid "ProjectSettings|Manages large files such as audio, video, and graphics fi
msgstr "Керує великими файлами такими Ñк аудіо, відео та графіка."
msgid "ProjectSettings|Maximum %{maxLength} characters."
-msgstr ""
+msgstr "МакÑимум %{maxLength} Ñимволів."
msgid "ProjectSettings|Merge checks"
msgstr "Перевірки злиттÑ"
@@ -32091,7 +32522,7 @@ msgid "ProjectSettings|Merge requests can't be merged if the latest pipeline did
msgstr ""
msgid "ProjectSettings|Merge suggestions"
-msgstr ""
+msgstr "Пропозиції щодо злиттÑ"
msgid "ProjectSettings|Merging is only allowed when the source branch is up-to-date with its target."
msgstr ""
@@ -32106,7 +32537,7 @@ msgid "ProjectSettings|Note: The container registry is always visible when a pro
msgstr ""
msgid "ProjectSettings|Only commits that include a %{code_block_start}Signed-off-by:%{code_block_end} element can be pushed to this repository."
-msgstr ""
+msgstr "До цього репозиторію можуть бути переміщені лише Ñ‚Ñ– коміти, Ñкі міÑÑ‚ÑÑ‚ÑŒ елемент %{code_block_start}Signed-off-by:%{code_block_end}."
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr "Тільки підпиÑані коміти можуть бути надіÑлані в цей репозиторій."
@@ -32118,7 +32549,7 @@ msgid "ProjectSettings|Override user notification preferences for all project me
msgstr ""
msgid "ProjectSettings|Package registry"
-msgstr ""
+msgstr "РеєÑÑ‚Ñ€ пакетів"
msgid "ProjectSettings|Packages"
msgstr "Пакети"
@@ -32145,13 +32576,13 @@ msgid "ProjectSettings|Public"
msgstr "Публічний"
msgid "ProjectSettings|Releases"
-msgstr ""
+msgstr "Релізи"
msgid "ProjectSettings|Repository"
msgstr "Репозиторій"
msgid "ProjectSettings|Require"
-msgstr ""
+msgstr "Вимагати"
msgid "ProjectSettings|Require an associated issue from Jira"
msgstr ""
@@ -32177,6 +32608,9 @@ msgstr "Безпека та відповідніÑÑ‚ÑŒ"
msgid "ProjectSettings|Security & Compliance for this project"
msgstr "Безпека та відповідніÑÑ‚ÑŒ Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проєкту"
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -32207,6 +32641,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr "Відправити зміни Ð´Ð»Ñ Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð² батьківÑькі репозиторії."
@@ -32258,6 +32695,9 @@ msgstr "КориÑтувачі можуть копіювати репозитоÑ
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr "КориÑтувачі можуть відправлÑти в цей репозиторій лише Ñ‚Ñ– коміти, Ñкщо ім'Ñ ÐºÐ¾Ð¼Ñ–Ñ‚ÐµÑ€Ð° відповідає Ñ—Ñ… імені кориÑтувача git в конфігурації."
+
msgid "ProjectSettings|Users can request access"
msgstr "КориÑтувачі можуть запитувати доÑтуп"
@@ -32265,7 +32705,7 @@ msgid "ProjectSettings|View and edit files in this project."
msgstr "ПереглÑдати та редагувати файли в цьому проєкті."
msgid "ProjectSettings|View and edit files in this project. Non-project members have only read access."
-msgstr ""
+msgstr "ПереглÑд Ñ– Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ Ñ„Ð°Ð¹Ð»Ñ–Ð² у цьому проєкті. Ðе учаÑники проєкту мають доÑтуп лише Ð´Ð»Ñ Ñ‡Ð¸Ñ‚Ð°Ð½Ð½Ñ."
msgid "ProjectSettings|View project analytics."
msgstr "ПереглÑнути аналітику проєкту."
@@ -32397,10 +32837,10 @@ msgid "ProjectView|Activity"
msgstr "ÐктивніÑÑ‚ÑŒ"
msgid "ProjectView|Files and Readme (default)"
-msgstr ""
+msgstr "Файли та інÑÑ‚Ñ€ÑƒÐºÑ†Ñ–Ñ (за замовчуваннÑм)"
msgid "ProjectView|Readme"
-msgstr ""
+msgstr "інÑтрукціÑ"
msgid "Projects"
msgstr "Проєкти"
@@ -32499,7 +32939,7 @@ msgid "ProjectsNew|Create"
msgstr "Створити"
msgid "ProjectsNew|Create a blank project to store your files, plan your work, and collaborate on code, among other things."
-msgstr ""
+msgstr "Створіть порожній проєкт, щоб зберігати Ñвої файли, планувати Ñвою роботу та Ñпільно працювати над кодом, Ñеред іншого."
msgid "ProjectsNew|Create a project pre-populated with the necessary files to get you started quickly."
msgstr "Створити проєкт попередньо заповнений необхідними файлами Ð´Ð»Ñ ÑˆÐ²Ð¸Ð´ÐºÐ¾Ð³Ð¾ Ñтарту."
@@ -32559,7 +32999,7 @@ msgid "ProjectsNew|Visibility Level"
msgstr "Рівень видимоÑÑ‚Ñ–"
msgid "ProjectsNew|Want to organize several dependent projects under the same namespace? %{link_start}Create a group.%{link_end}"
-msgstr ""
+msgstr "Бажаєте організувати кілька залежних проєктів в одному проÑторі імен? %{link_start}Створіть групу.%{link_end}"
msgid "PrometheusAlerts|exceeded"
msgstr ""
@@ -32897,6 +33337,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32933,15 +33376,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr "Ð—Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð²Ð»Ð°Ñника коду"
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr "ОÑтанній коміт"
+
msgid "ProtectedBranch|Learn more."
msgstr "ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ."
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr "ЗахиÑтити"
@@ -32957,12 +33412,21 @@ msgstr "Захищені гілки"
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr "Вимагати Ð·Ð°Ñ‚Ð²ÐµÑ€Ð´Ð¶ÐµÐ½Ð½Ñ Ð²Ñ–Ð´ влаÑників коду:"
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr "Ðаразі немає захищених гілок, захиÑÑ‚Ñ–Ñ‚ÑŒ гілку за допомогою форми вище."
@@ -33006,10 +33470,10 @@ msgid "ProtectedEnvironment|Environments protected upstream"
msgstr ""
msgid "ProtectedEnvironment|Failed to load details for this group."
-msgstr ""
+msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ деталі цієї групи."
msgid "ProtectedEnvironment|No environments in this project are protected."
-msgstr ""
+msgstr "Жодне Ñередовище в цьому проєкті не Ñ” захищеним."
msgid "ProtectedEnvironment|Only specified groups can execute deployments in protected environments."
msgstr ""
@@ -33213,13 +33677,13 @@ msgid "PushRules|All committed filenames cannot match this %{wiki_syntax_link_st
msgstr ""
msgid "PushRules|Branch name"
-msgstr ""
+msgstr "Ðазва гілки"
msgid "PushRules|Check whether the commit author is a GitLab user"
msgstr ""
msgid "PushRules|Commit author's email"
-msgstr ""
+msgstr "ÐдреÑа електронної пошти автора коміту"
msgid "PushRules|Commit messages cannot match this %{wiki_syntax_link_start}regular expression%{wiki_syntax_link_end}. If empty, commit messages are not rejected based on any expression."
msgstr ""
@@ -33228,7 +33692,7 @@ msgid "PushRules|Do not allow users to remove Git tags with %{code_block_start}g
msgstr ""
msgid "PushRules|Maximum file size (MB)"
-msgstr ""
+msgstr "МакÑимальний розмір файлу (МБ)"
msgid "PushRules|Prevent pushing secret files"
msgstr ""
@@ -33240,7 +33704,7 @@ msgid "PushRules|Reject any files likely to contain secrets. %{secret_files_link
msgstr ""
msgid "PushRules|Reject commits that aren't DCO certified"
-msgstr ""
+msgstr "ВідхилÑти коміти, Ñкі не Ñертифіковані DCO"
msgid "PushRules|Reject expression in commit messages"
msgstr ""
@@ -33249,7 +33713,7 @@ msgid "PushRules|Reject file sizes equal to or greater than this size. If set to
msgstr ""
msgid "PushRules|Reject unsigned commits"
-msgstr ""
+msgstr "Відхилити непідпиÑані коміти"
msgid "PushRules|Require expression in commit messages"
msgstr ""
@@ -33272,6 +33736,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr "Відхилити неузгоджене ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача"
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -33390,7 +33857,7 @@ msgid "Re-authentication required"
msgstr "Ðеобхідна повторна автентифікаціÑ"
msgid "Re-import"
-msgstr ""
+msgstr "Повторне імпортуваннÑ"
msgid "Re-request review"
msgstr ""
@@ -33404,12 +33871,6 @@ msgstr "Докладніше"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr "ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ про пов’Ñзані задачі"
-
msgid "Read their documentation."
msgstr ""
@@ -33474,7 +33935,7 @@ msgid "Recent searches"
msgstr "ОÑтанні пошукові запити"
msgid "Recently used"
-msgstr ""
+msgstr "Ðещодавно викориÑтане"
msgid "Reconfigure"
msgstr "Переналаштувати"
@@ -33503,9 +33964,6 @@ msgstr "Знизити видиміÑÑ‚ÑŒ проєкту"
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr "Знизити видиміÑÑ‚ÑŒ проєкту?"
-
msgid "Reference"
msgstr "ПоÑиланнÑ"
@@ -33673,6 +34131,9 @@ msgstr[3] "Релізів"
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr "Реліз вже Ñ–Ñнує"
+
msgid "Release assets"
msgstr "РеÑурÑи релізу"
@@ -33682,6 +34143,9 @@ msgstr "Ð”Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°Ñ†Ñ–Ñ Ð¿Ð¾ реÑурÑам релізу"
msgid "Release date"
msgstr "Дата релізу"
+msgid "Release does not exist"
+msgstr "Реліз не Ñ–Ñнує"
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -34138,6 +34602,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr "Репортер"
+
msgid "Reporting"
msgstr "ЗвітуваннÑ"
@@ -34154,13 +34621,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -34192,18 +34652,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr "Ðазва клаÑу"
-
msgid "Reports|Copy failed test names to run locally"
msgstr "Копіюйте назви невдалих теÑтів Ð´Ð»Ñ Ð»Ð¾ÐºÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ запуÑку"
msgid "Reports|Copy failed tests"
msgstr "Копіювати невдалі теÑти"
-msgid "Reports|Execution time"
-msgstr "Ð§Ð°Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ"
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -34218,12 +34672,6 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
-msgid "Reports|Failure"
-msgstr "Помилка"
-
-msgid "Reports|Filename"
-msgstr "Ім'Ñ Ñ„Ð°Ð¹Ð»Ñƒ"
-
msgid "Reports|Fixed"
msgstr ""
@@ -34266,21 +34714,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr "Рівень"
-msgid "Reports|System output"
-msgstr "СиÑтемний вивід"
-
msgid "Reports|Test summary"
msgstr "ТеÑтовий звіт"
-msgid "Reports|Test summary failed loading results"
-msgstr "Помилка при завантаженні результатів Ð´Ð»Ñ Ñ‚ÐµÑтового звіту"
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr "Результати Ð´Ð»Ñ Ñ‚ÐµÑтового звіту оброблÑÑŽÑ‚ÑŒÑÑ"
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -34294,10 +34733,7 @@ msgid "Reports|Vulnerability Name"
msgstr "Ім'Ñ Ð²Ñ€Ð°Ð·Ð»Ð¸Ð²Ð¾ÑÑ‚Ñ–"
msgid "Reports|metrics report"
-msgstr ""
-
-msgid "Reports|no changed test results"
-msgstr "результати теÑтів не змінилиÑÑ"
+msgstr "звіт про метрики"
msgid "Repositories"
msgstr "Репозиторії"
@@ -34461,7 +34897,7 @@ msgid "Repository mirroring configuration"
msgstr ""
msgid "Repository mirroring has been paused due to too many failed attempts. It can be resumed by a project maintainer or owner."
-msgstr ""
+msgstr "Ð’Ñ–Ð´Ð´Ð·ÐµÑ€ÐºÐ°Ð»ÐµÐ½Ð½Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ñ–ÑŽ призупинено через надто велику кількіÑÑ‚ÑŒ невдалих Ñпроб. Його може відновити керівник або влаÑник проєкту."
msgid "Repository must contain at least 1 file."
msgstr ""
@@ -34509,13 +34945,13 @@ msgid "Request review from"
msgstr ""
msgid "Request time"
-msgstr ""
+msgstr "Ð§Ð°Ñ Ð·Ð°Ð¿Ð¸Ñ‚Ñƒ"
msgid "Request to link SAML account must be authorized"
msgstr "Запит на зв’ÑÐ·ÑƒÐ²Ð°Ð½Ð½Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¾Ð³Ð¾ запиÑу SAML повинен бути авторизований"
msgid "Requested"
-msgstr ""
+msgstr "Запитано"
msgid "Requested %{time_ago}"
msgstr "Відправлено запит %{time_ago}"
@@ -34625,7 +35061,7 @@ msgid "Reset"
msgstr "Скинути"
msgid "Reset error tracking access token"
-msgstr ""
+msgstr "Скинути токен доÑтупу відÑÑ‚ÐµÐ¶ÐµÐ½Ð½Ñ Ð¿Ð¾Ð¼Ð¸Ð»Ð¾Ðº"
msgid "Reset file"
msgstr ""
@@ -34678,6 +35114,9 @@ msgstr "Вирішено"
msgid "Resolved by %{name}"
msgstr "Вирішено %{name}"
+msgid "Resource link added"
+msgstr "ПоÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð½Ð° реÑÑƒÑ€Ñ Ð´Ð¾Ð´Ð°Ð½Ð¾"
+
msgid "Response"
msgstr "Відповідь"
@@ -34911,6 +35350,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr "ЗапуÑтити очищеннÑ"
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34930,19 +35372,19 @@ msgid "Runner tokens"
msgstr ""
msgid "Runner was not updated."
-msgstr "Ранер не було оновлено."
+msgstr "Раннер не було оновлено."
msgid "Runner was successfully updated."
-msgstr "Ранер оновлено уÑпішно."
+msgstr "Раннер оновлено уÑпішно."
msgid "Runners"
-msgstr "Ранери"
+msgstr "Раннери"
msgid "Runners are processes that pick up and execute CI/CD jobs for GitLab."
msgstr ""
msgid "Runners page."
-msgstr "Сторінка ранерів."
+msgstr "Сторінка раннерів."
msgid "Runners|%d selected runner deleted"
msgid_plural "Runners|%d selected runners deleted"
@@ -34951,6 +35393,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr "%{link_start}Ці раннери%{link_end} доÑтупні Ð´Ð»Ñ Ð²ÑÑ–Ñ… груп Ñ– проєктів."
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34983,8 +35428,8 @@ msgstr "Ðктивні"
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
-msgstr ""
+msgid "Runners|Administrator"
+msgstr "ÐдмініÑтратор"
msgid "Runners|All"
msgstr "Ð’ÑÑ–"
@@ -35044,7 +35489,7 @@ msgid "Runners|Clear selection"
msgstr "ОчиÑтити вибір"
msgid "Runners|Command to register runner"
-msgstr "Команда Ð´Ð»Ñ Ñ€ÐµÑ”Ñтрації runner"
+msgstr "Команда Ð´Ð»Ñ Ñ€ÐµÑ”Ñтрації раннер"
msgid "Runners|Configuration"
msgstr "КонфігураціÑ"
@@ -35060,22 +35505,22 @@ msgstr "Створено %{timeAgo}"
msgid "Runners|Delete %d runner"
msgid_plural "Runners|Delete %d runners"
-msgstr[0] "Видалити %d runner"
-msgstr[1] "Видалити %d runner`а"
-msgstr[2] "Видалити %d runner`ів"
-msgstr[3] "Видалити %d runner`ів"
+msgstr[0] "Видалити %d раннер"
+msgstr[1] "Видалити %d раннера"
+msgstr[2] "Видалити %d раннерів"
+msgstr[3] "Видалити %d раннерів"
msgid "Runners|Delete runner"
-msgstr "Видалити runner"
+msgstr "Видалити раннер"
msgid "Runners|Delete runner %{name}?"
-msgstr "Видалити runner %{name}?"
+msgstr "Видалити раннер %{name}?"
msgid "Runners|Delete selected"
msgstr "Видалити вибрані"
msgid "Runners|Deploy GitLab Runner in AWS"
-msgstr "Розгортати ранер GitLab в AWS"
+msgstr "Розгортати раннер GitLab в AWS"
msgid "Runners|Description"
msgstr "ОпиÑ"
@@ -35096,7 +35541,7 @@ msgid "Runners|Edit your search and try again"
msgstr "Відредагуйте ваш пошук Ñ– Ñпробуйте знову"
msgid "Runners|Enable stale runner cleanup"
-msgstr "Увімкнути Ð¾Ñ‡Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð·Ð°Ñтарілого runner"
+msgstr "Увімкнути Ð¾Ñ‡Ð¸Ñ‰ÐµÐ½Ð½Ñ Ð·Ð°Ñтарілого раннер"
msgid "Runners|Enable stale runner cleanup?"
msgstr ""
@@ -35108,25 +35553,25 @@ msgid "Runners|Executor"
msgstr ""
msgid "Runners|Filter projects"
-msgstr ""
+msgstr "Фільтр проєктів"
msgid "Runners|Get started with runners"
-msgstr "Розпочати роботу з runner'ами"
+msgstr "Розпочати роботу з раннерами"
msgid "Runners|Group"
msgstr "Група"
msgid "Runners|How do runners pick up jobs?"
-msgstr ""
+msgstr "Як раннери можуть приймати задачі?"
msgid "Runners|How do we upgrade GitLab runner?"
-msgstr ""
+msgstr "Як оновити GitLab раннер?"
msgid "Runners|IP Address"
msgstr "IP-адреÑа"
msgid "Runners|Install a runner"
-msgstr "Ð’Ñтановити runner"
+msgstr "Ð’Ñтановити раннер"
msgid "Runners|Instance"
msgstr "ІнÑтанÑ"
@@ -35194,6 +35639,9 @@ msgstr "Онлайн"
msgid "Runners|Online:"
msgstr "Онлайн:"
+msgid "Runners|Owner"
+msgstr "ВлаÑник"
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -35223,7 +35671,7 @@ msgid "Runners|Recommended"
msgstr "Рекомендовано"
msgid "Runners|Register a group runner"
-msgstr "ЗареєÑтрувати груповий runner"
+msgstr "ЗареєÑтрувати груповий раннер"
msgid "Runners|Register a project runner"
msgstr ""
@@ -35232,7 +35680,7 @@ msgid "Runners|Register a runner"
msgstr ""
msgid "Runners|Register an instance runner"
-msgstr "ЗареєÑтрувати runner інÑтанÑа"
+msgstr "ЗареєÑтрувати раннер інÑтанÑа"
msgid "Runners|Register as many runners as you want. You can register runners as separate users, on separate servers, and on your local machine."
msgstr ""
@@ -35253,16 +35701,16 @@ msgid "Runners|Revision"
msgstr "ВерÑÑ–Ñ"
msgid "Runners|Runner"
-msgstr "Ранер"
+msgstr "Раннер"
msgid "Runners|Runner #%{runner_id}"
-msgstr "Ранер #%{runner_id}"
+msgstr "Раннер #%{runner_id}"
msgid "Runners|Runner %{name} was deleted"
-msgstr "Ранер %{name} було видалено"
+msgstr "Раннер %{name} було видалено"
msgid "Runners|Runner assigned to project."
-msgstr "Ранер призначено Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ."
+msgstr "Раннер призначено Ð´Ð»Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ."
msgid "Runners|Runner authentication token expiration"
msgstr ""
@@ -35310,23 +35758,29 @@ msgid "Runners|Runner registration"
msgstr ""
msgid "Runners|Runner statuses"
-msgstr "СтатуÑи ранер"
+msgstr "СтатуÑи раннер"
msgid "Runners|Runner unassigned from project."
msgstr ""
msgid "Runners|Runners"
-msgstr "Ранери"
+msgstr "Раннери"
msgid "Runners|Runners are either:"
-msgstr ""
+msgstr "Раннери теж такі:"
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
-msgstr ""
+msgstr "Раннери — це агенти, Ñкі виконують ваші Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ CI/CD. ДотримуйтеÑÑŒ інÑтрукцій %{linkStart} зі вÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ‚Ð° реєÑтрації %{linkEnd}, щоб налаштувати раннер."
+
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr "Раннери — це агенти, Ñкі керують вашою роботою CI/CD. Щоб зареєÑтрувати нові раннери, будь лаÑка, звернітьÑÑ Ð´Ð¾ адмініÑтратора."
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr "Вибрати вÑÑ–"
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -35334,10 +35788,10 @@ msgid "Runners|Select your preferred option here. In the next step, you can choo
msgstr ""
msgid "Runners|Show only inherited"
-msgstr ""
+msgstr "Показати тільки уÑпадковані"
msgid "Runners|Show runner installation and registration instructions"
-msgstr "Показати інÑтрукції Ð´Ð»Ñ Ð²ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ‚Ð° реєÑтрації runner"
+msgstr "Показати інÑтрукції Ð´Ð»Ñ Ð²ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ Ñ‚Ð° реєÑтрації раннер"
msgid "Runners|Show runner installation instructions"
msgstr ""
@@ -35367,7 +35821,7 @@ msgid "Runners|Tags"
msgstr "Теги"
msgid "Runners|Tags control which type of jobs a runner can handle. By tagging a runner, you make sure shared runners only handle the jobs they are equipped to run."
-msgstr ""
+msgstr "Теги визначають, Ñкі типи завдань може виконати раннер. Позначаючи раннер, ви гарантуєте, що Ñпільні раннери виконують лише Ñ‚Ñ– завданнÑ, Ð´Ð»Ñ Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ Ñких вони обладнані."
msgid "Runners|Take me there!"
msgstr ""
@@ -35375,6 +35829,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr "Проєкт, група або інÑтанÑ, де зареєÑтровано раннер. ІнÑÑ‚Ð°Ð½Ñ Ñ€Ð°Ð½Ð½ÐµÑ€Ð¸ завжди належать адмініÑтратору."
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -35398,7 +35855,7 @@ msgid "Runners|This runner is available to all projects and subgroups in a group
msgstr ""
msgid "Runners|This runner is outdated, an upgrade is recommended"
-msgstr ""
+msgstr "Цей раннер заÑтарів, рекомендуєтьÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ його"
msgid "Runners|To install Runner in Kubernetes follow the instructions described in the GitLab documentation."
msgstr ""
@@ -35407,11 +35864,14 @@ msgid "Runners|To install Runner in a container follow the instructions describe
msgstr ""
msgid "Runners|To register them, go to the %{link_start}group's Runners page%{link_end}."
-msgstr ""
+msgstr "Щоб зареєÑтрувати Ñ—Ñ…, перейдіть на Ñторінку раннерів групи %{link_start}%{link_end}."
msgid "Runners|Token expiry"
msgstr "Термін дії токену"
+msgid "Runners|Unselect all"
+msgstr "СкаÑувати вибір вÑÑ–Ñ…"
+
msgid "Runners|Up to date"
msgstr "Ð’ актуальному Ñтані"
@@ -35419,13 +35879,13 @@ msgid "Runners|Upgrade GitLab Runner to match the version of GitLab you're runni
msgstr ""
msgid "Runners|Upgrade Status"
-msgstr ""
+msgstr "Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ"
msgid "Runners|Upgrade available"
-msgstr ""
+msgstr "ДоÑтупне оновленнÑ"
msgid "Runners|Upgrade recommended"
-msgstr ""
+msgstr "РекомендуєтьÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸"
msgid "Runners|Use Group runners when you want all projects in a group to have access to a set of runners."
msgstr ""
@@ -35451,12 +35911,6 @@ msgstr "ВерÑÑ–Ñ %{version}"
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35470,7 +35924,7 @@ msgid "Runners|You can set up a specific runner to be used by multiple projects
msgstr ""
msgid "Runners|You have used %{quotaUsed} out of %{quotaLimit} of your shared Runners pipeline minutes."
-msgstr "Ви викориÑтали %{quotaUsed} із ваших %{quotaLimit} хвилин Ð´Ð»Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ñ–Ð² загальних ранерів."
+msgstr "Ви викориÑтали %{quotaUsed} із ваших %{quotaLimit} хвилин Ð´Ð»Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ñ–Ð² загальних раннерів."
msgid "Runners|active"
msgstr "активні"
@@ -35511,17 +35965,23 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr "SAML Ð´Ð»Ñ %{group_name}"
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
-msgstr ""
+msgid "SAML single sign-on"
+msgstr "Єдиний вхід SAML"
+
+msgid "SAML single sign-on for %{group_name}"
+msgstr "Єдиний вхід SAML Ð´Ð»Ñ %{group_name}"
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
-msgstr "Група \"%{group_path}\" дозволÑÑ” увійти за допомогою облікового запиÑу єдиного входу."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr "Група %{strongOpen}%{group_path}%{strongClose} дозволÑÑ” входити за допомогою єдиного входу."
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
-msgstr ""
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr "Щоб отримати доÑтуп до %{strongOpen}%{group_name}%{strongClose}, ви повинні ввійти за допомогою ÑиÑтеми єдиного входу через зовнішню Ñторінку входу."
+
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
+msgstr "Щоб дозволити %{strongOpen}%{group_name}%{strongClose} керувати вашим обліковим запиÑом GitLab %{strongOpen}%{username}%{strongClose} (%{email}) піÑÐ»Ñ ÑƒÑпішного входу за допомогою єдиного входу, виберіть %{strongOpen}Ðвторизувати%{strongClose}."
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr ""
@@ -35628,12 +36088,12 @@ msgstr "ЗбереженнÑ"
msgid "Saving project."
msgstr "Ð—Ð±ÐµÑ€ÐµÐ¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ”ÐºÑ‚Ñƒ."
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
-msgstr "%{ifLabelStart}Ñкщо%{ifLabelEnd} %{rules} дії Ð´Ð»Ñ %{scopes} %{branches}"
-
msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
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"
msgstr ""
@@ -35644,7 +36104,7 @@ msgid "ScanExecutionPolicy|A pipeline is run"
msgstr "Конвеєр запущений"
msgid "ScanExecutionPolicy|Scanner profile"
-msgstr ""
+msgstr "Профіль Ñканера"
msgid "ScanExecutionPolicy|Schedule"
msgstr ""
@@ -35652,21 +36112,33 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr "Вибрати агента"
+
msgid "ScanExecutionPolicy|Select branches"
msgstr "Виберіть гілки"
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr "Вибрати проÑтори імен"
+
msgid "ScanExecutionPolicy|Select scanner profile"
-msgstr ""
+msgstr "Виберіть профіль Ñканера"
msgid "ScanExecutionPolicy|Select site profile"
-msgstr ""
+msgstr "Вибрати профіль Ñайту"
msgid "ScanExecutionPolicy|Site profile"
-msgstr ""
+msgstr "Профіль Ñайту"
+
+msgid "ScanExecutionPolicy|agent"
+msgstr "агент"
msgid "ScanExecutionPolicy|branch"
msgstr "гілка"
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr "у проÑторі імен"
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35817,9 +36289,6 @@ msgstr "Пошук LDAP-групи"
msgid "Search for a group"
msgstr "Шукати групу"
-msgid "Search for a user"
-msgstr "Пошук кориÑтувача"
-
msgid "Search for an emoji"
msgstr ""
@@ -36198,7 +36667,7 @@ msgid "SecurityConfiguration|Manage profiles for use by DAST scans."
msgstr ""
msgid "SecurityConfiguration|More scan types, including DAST, Dependency Scanning, Fuzzing, and Licence Compliance"
-msgstr ""
+msgstr "Більше типів ÑкануваннÑ, включаючи DAST, ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð»ÐµÐ¶Ð½Ð¾Ñтей, збіг та відповідніÑÑ‚ÑŒ ліцензіÑм"
msgid "SecurityConfiguration|Not enabled"
msgstr "Ðе увімкнено"
@@ -36248,11 +36717,14 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
-msgstr ""
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr "%{branches} і %{lastBranch} гілки"
+
+msgid "SecurityOrchestration|%{branches} branch"
+msgstr "гілка%{branches}"
msgid "SecurityOrchestration|%{scanners}"
msgstr ""
@@ -36371,6 +36843,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -36473,10 +36948,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36566,7 +37041,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36584,6 +37059,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr "уÑÑ– гілки"
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36602,12 +37080,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr "ПроÑтори імен %{namespaces} та %{lastNamespace}"
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr "ПроÑÑ‚Ñ–Ñ€ імен %{namespaces}"
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36629,6 +37116,9 @@ msgstr "Додати проєкти"
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr "Ð’ÑÑ– рівні"
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36758,6 +37248,9 @@ msgstr "Моніторингові проєкти Ñкі моніторÑÑ‚ÑŒÑÑ
msgid "SecurityReports|More info"
msgstr "Детальніше"
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36815,6 +37308,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr "Перевірка безпеки виконана"
@@ -36840,7 +37336,7 @@ msgid "SecurityReports|Status"
msgstr "СтатуÑ"
msgid "SecurityReports|Still detected"
-msgstr ""
+msgstr "Ð’Ñе ще виÑвлено"
msgid "SecurityReports|Submit vulnerability"
msgstr ""
@@ -36932,9 +37428,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr "Увімкніть Ð½Ð°Ð²Ñ‡Ð°Ð½Ð½Ñ Ð· безпеки, щоб навчитиÑÑ Ð²Ð¸Ð¿Ñ€Ð°Ð²Ð»Ñти вразливоÑÑ‚Ñ–. ПереглÑнути тренінги з безпеки від обраних поÑтачальників оÑвітніх поÑлуг, що мають Ð²Ñ–Ð´Ð½Ð¾ÑˆÐµÐ½Ð½Ñ Ð´Ð¾ виÑвленої вразливоÑÑ‚Ñ–."
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr "Вирішити проблему за допомогою тренінгів з безпеки"
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36947,6 +37449,9 @@ msgstr "ПереглÑнути метрики"
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr "ПереглÑнути уÑÑ– уражені проєкти на панелі адмініÑтратора GitLab"
@@ -37010,9 +37515,6 @@ msgstr "Вибрати шаблон репозиторію"
msgid "Select a template type"
msgstr "Вибрати тип шаблону"
-msgid "Select a timezone"
-msgstr "Вибрати чаÑовий поÑÑ"
-
msgid "Select all"
msgstr "Вибрати вÑе"
@@ -37038,7 +37540,7 @@ msgid "Select branches"
msgstr ""
msgid "Select default branch"
-msgstr ""
+msgstr "Виберіть гілку за замовчуваннÑм"
msgid "Select due date"
msgstr "Виберіть заплановану дату завершеннÑ"
@@ -37086,7 +37588,7 @@ msgid "Select projects"
msgstr "Вибрати проєкти"
msgid "Select report"
-msgstr ""
+msgstr "Виберіть звіт"
msgid "Select reviewer(s)"
msgstr "Вибрати оглÑдача(ів)"
@@ -37122,7 +37624,7 @@ msgid "Select target branch or tag"
msgstr "Виберіть цільову гілку або тег"
msgid "Select target project"
-msgstr ""
+msgstr "Вибрати цільовий проєкт"
msgid "Select timezone"
msgstr "Обрати чаÑовий поÑÑ"
@@ -37151,10 +37653,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -37166,28 +37668,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -37404,10 +37906,7 @@ msgid "Set the Draft status"
msgstr "Ð’Ñтановити ÑÑ‚Ð°Ñ‚ÑƒÑ Ñ‡ÐµÑ€Ð½ÐµÑ‚ÐºÐ¸"
msgid "Set the Ready status"
-msgstr ""
-
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
+msgstr "Ð’Ñтановити ÑÑ‚Ð°Ñ‚ÑƒÑ Ð“Ð¾Ñ‚Ð¾Ð²Ð¾"
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37485,7 +37984,7 @@ msgid "SetStatusModal|Clear status after"
msgstr "ОчиÑтити ÑÑ‚Ð°Ñ‚ÑƒÑ Ð¿Ñ–ÑлÑ"
msgid "SetStatusModal|Displays that you are busy or not able to respond"
-msgstr ""
+msgstr "Відображає, що ви зайнÑÑ‚Ñ– або не можете відповідати"
msgid "SetStatusModal|Edit status"
msgstr "Змінити ÑтатуÑ"
@@ -37560,9 +38059,6 @@ msgstr "Параметри"
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr "Параметри"
-
msgid "Severity"
msgstr "СерйозніÑÑ‚ÑŒ"
@@ -37585,7 +38081,7 @@ msgid "Share the %{strong_open}GitLab single sign-on URL%{strong_close} with mem
msgstr ""
msgid "Shared Runners"
-msgstr "Загальні ранери"
+msgstr "Загальні раннери"
msgid "Shared projects"
msgstr "Спільні проєкти"
@@ -37606,7 +38102,7 @@ msgid "Shared runners enabled cannot be enabled until a valid credit card is on
msgstr ""
msgid "Shared runners help link"
-msgstr "Допомога по загальним runner'ам"
+msgstr "Допомога по загальним раннерам"
msgid "SharedRunnersMinutesSettings|By resetting the pipeline minutes for this namespace, the currently used minutes will be set to zero."
msgstr "При обнуленні хвилин конвеєрів Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ проÑтору імен, кількіÑÑ‚ÑŒ вже викориÑтаних хвилин буде дорівнювати 0."
@@ -37819,10 +38315,7 @@ msgstr "Показати вÑÑ– епіки"
msgid "Showing all issues"
msgstr "Ð’Ñ–Ð´Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð½Ñ ÑƒÑÑ–Ñ… задач"
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37876,8 +38369,8 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
-msgstr "Увійти до \"%{group_name}\""
+msgid "Sign in to %{group_name}"
+msgstr "Увійти в %{group_name}"
msgid "Sign in to GitLab"
msgstr ""
@@ -37891,7 +38384,7 @@ msgstr "Увійти за допомогою коду двофакторної Ð
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr "Увійти за допомогою єдиного входу"
msgid "Sign in with smart card"
@@ -37934,7 +38427,7 @@ msgid "Sign-in text"
msgstr ""
msgid "Sign-in using %{provider} auth failed"
-msgstr ""
+msgstr "Помилка входу за допомогою автентифікації %{provider}"
msgid "Sign-out page URL"
msgstr ""
@@ -38014,9 +38507,6 @@ msgstr "ÐžÐ±Ð¼ÐµÐ¶ÐµÐ½Ð½Ñ Ñ€Ð¾Ð·Ð¼Ñ–Ñ€Ñƒ"
msgid "Size limit per repository (MB)"
msgstr "МакÑимальний розмір Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ репозиторію (МБ)"
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr "Пропущені"
@@ -38108,37 +38598,37 @@ msgid "SlackService|Perform common operations in this project by entering slash
msgstr ""
msgid "Slack|%{asterisk}Step 1.%{asterisk} Connect your GitLab account to get started."
-msgstr ""
+msgstr "%{asterisk}Крок 1.%{asterisk} під'єднає ваш обліковий Ð·Ð°Ð¿Ð¸Ñ GitLab, щоб розпочати роботу."
msgid "Slack|%{asterisk}Step 2.%{asterisk} Try it out!"
-msgstr ""
+msgstr "%{asterisk}Крок 2.%{asterisk} Спробуйте!"
msgid "Slack|%{emoji}Connected to GitLab account %{account}"
-msgstr ""
+msgstr "%{emoji}Підключено до облікового запиÑу GitLab %{account}"
msgid "Slack|%{emoji}Welcome to GitLab for Slack!"
-msgstr ""
+msgstr "%{emoji}ЛаÑкаво проÑимо до GitLab Ð´Ð»Ñ Slack!"
msgid "Slack|Connect your GitLab account"
-msgstr ""
+msgstr "Підключіть Ñвій обліковий Ð·Ð°Ð¿Ð¸Ñ GitLab"
msgid "Slack|Create a new issue"
-msgstr ""
+msgstr "Створити нову задачу"
msgid "Slack|Create new issues from Slack: %{command}"
-msgstr ""
+msgstr "Створити нові задачі із Slack: %{command}"
msgid "Slack|Run a CI/CD job"
-msgstr ""
+msgstr "ЗапуÑтити Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ CI/CD"
msgid "Slack|See a list of available commands: %{command})"
-msgstr ""
+msgstr "ПереглÑньте ÑпиÑок доÑтупних команд: %{command})"
msgid "Slack|Streamline your GitLab deployments with ChatOps. Once you've configured your %{startMarkup}CI/CD pipelines%{endMarkup}, try: %{command}"
-msgstr ""
+msgstr "Оптимізуйте Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ GitLab за допомогою ChatOps. ПіÑÐ»Ñ Ñ‚Ð¾Ð³Ð¾ Ñк ви налаштували конвеєри %{startMarkup}CI/CD%{endMarkup}, Ñпробуйте: %{command}"
msgid "Slack|View and control GitLab content while you're working in Slack. Type the command as a message in your chat client to activate it. %{startMarkup}Learn more%{endMarkup}."
-msgstr ""
+msgstr "ПереглÑдайте вміÑÑ‚ GitLab Ñ– керуйте ним під Ñ‡Ð°Ñ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸ в Slack. Введіть команду Ñк Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñƒ Ñвоєму клієнті чату, щоб активувати Ñ—Ñ—. %{startMarkup}ДізнайтеÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ%{endMarkup}."
msgid "Slice multiplier"
msgstr ""
@@ -38239,6 +38729,9 @@ msgstr "ХтоÑÑŒ відредагував цей запит на злиттÑ
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr "ХтоÑÑŒ увійшов у ваш обліковий Ð·Ð°Ð¿Ð¸Ñ %{host} з нового міÑцÑ"
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -38350,9 +38843,6 @@ msgstr "Проблема при отриманні Ñередовищ Ð´Ð»Ñ Ñ†Ñ
msgid "Something went wrong while fetching the packages list."
msgstr "Помилка при отриманні ÑпиÑку пакетів."
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38444,10 +38934,10 @@ msgid "Sort direction"
msgstr "ПорÑдок ÑортуваннÑ"
msgid "Sort direction: Ascending"
-msgstr ""
+msgstr "ÐапрÑмок ÑортуваннÑ: за зроÑтаннÑм"
msgid "Sort direction: Descending"
-msgstr ""
+msgstr "ÐапрÑмок ÑортуваннÑ: за ÑпаданнÑм"
msgid "Sort or filter"
msgstr ""
@@ -38495,7 +38985,7 @@ msgid "SortOptions|Last created"
msgstr "ОÑтанній Ñтворений"
msgid "SortOptions|Latest version"
-msgstr ""
+msgstr "ОÑÑ‚Ð°Ð½Ð½Ñ Ð²ÐµÑ€ÑÑ–Ñ"
msgid "SortOptions|Least popular"
msgstr "Ðайменш популÑрний"
@@ -38558,7 +39048,7 @@ msgid "SortOptions|Oldest updated"
msgstr "Оновлений найраніше"
msgid "SortOptions|Oldest version"
-msgstr ""
+msgstr "ÐайÑтаріша верÑÑ–Ñ"
msgid "SortOptions|Popularity"
msgstr "ПопулÑрніÑÑ‚ÑŒ"
@@ -38600,7 +39090,7 @@ msgid "SortOptions|Start soon"
msgstr "Розпочатий нещодавно"
msgid "SortOptions|Title"
-msgstr ""
+msgstr "Заголовок"
msgid "SortOptions|Type"
msgstr "Тип"
@@ -38926,9 +39416,6 @@ msgstr "СтатуÑ:"
msgid "Status: %{title}"
msgstr "СтатуÑ: %{title}"
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38941,9 +39428,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38965,9 +39449,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39487,9 +39968,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39497,7 +39984,7 @@ msgid "Suggestion is not applicable as the suggestion was not found."
msgstr ""
msgid "Suggestion(s)"
-msgstr ""
+msgstr "ПропозиціÑ(Ñ—)"
msgid "Suggestions are not applicable as one or more suggestions were not found."
msgstr ""
@@ -39699,7 +40186,7 @@ msgid "SuperSonics|Your subscription details will sync shortly."
msgstr ""
msgid "SuperSonics|Your subscription is expired"
-msgstr ""
+msgstr "Термін дії вашої підпиÑки закінчивÑÑ"
msgid "SuperSonics|Your subscription was successfully activated. You can see the details below."
msgstr ""
@@ -39749,6 +40236,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "Перейти в гілку/тег"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr "Перейти на GitLab Next"
@@ -39839,6 +40329,9 @@ msgstr ""
msgid "Tag"
msgstr "Тег"
+msgid "Tag does not exist"
+msgstr "Тег не Ñ–Ñнує"
+
msgid "Tag list:"
msgstr "СпиÑок тегів:"
@@ -39903,7 +40396,7 @@ msgid "TagsPage|Cancel, keep tag"
msgstr ""
msgid "TagsPage|Create release"
-msgstr ""
+msgstr "Створити реліз"
msgid "TagsPage|Create tag"
msgstr "Створити тег"
@@ -39923,8 +40416,11 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr "Ви хочете Ñтворити реліз з новим тегом? Ви можете зробити це на Ñторінці %{link_start}Ðовий реліз%{link_end}."
+
msgid "TagsPage|Edit release"
-msgstr ""
+msgstr "Редагувати реліз"
msgid "TagsPage|Existing branch name, tag, or commit SHA"
msgstr "Ім'Ñ Ñ–Ñнуючої гілки, тега або SHA коміта"
@@ -39944,15 +40440,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr "За бажаннÑм додайте Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ð´Ð¾ цього тегу. Залишивши це поле порожнім, ÑтворюєтьÑÑ %{link_start}легкий (lightweight) тег.%{link_end}"
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr "ÐžÐ¿Ð¸Ñ Ñ€ÐµÐ»Ñ–Ð·Ñƒ"
-
msgid "TagsPage|Repository has no tags yet."
msgstr "Репозиторій не міÑтить тегів."
@@ -39974,9 +40464,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr "ВикориÑтовуйте команду git tag, щоб додати новий тег:"
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "Створити Ð¾Ð¿Ð¸Ñ Ñ€ÐµÐ»Ñ–Ð·Ñƒ або перетÑгніть файли Ñюди…"
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39995,6 +40482,9 @@ msgstr "захищений"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr "Цільова гілка"
@@ -40106,20 +40596,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr "%{name} уÑпішно видалено"
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -40143,12 +40619,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr "Ðе вдалоÑÑ Ñтворити звіт."
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr "Дії"
@@ -40236,12 +40706,6 @@ msgstr "Команда Terraform init"
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40270,7 +40734,7 @@ msgid "Terraform|You have insufficient permissions to delete this state"
msgstr ""
msgid "Terraform|Your project doesn't have any Terraform state files"
-msgstr ""
+msgstr "Ваш проєкт не має файлів Ñтану Terraform"
msgid "Test"
msgstr "ТеÑÑ‚"
@@ -40706,6 +41170,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr "Імпорт не можна ÑкаÑувати, тому що він %{project_status}"
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "Імпорт буде припинено піÑÐ»Ñ %{timeout}. Ð”Ð»Ñ Ñ€ÐµÐ¿Ð¾Ð·Ð¸Ñ‚Ð¾Ñ€Ñ–Ñ—Ð², Ñким потрібно більше чаÑу, викориÑтовуйте комбінацію clone/push."
@@ -40782,7 +41249,7 @@ msgid "The maximum file size is %{size}."
msgstr "МакÑимальний розмір файлу це %{size}."
msgid "The maximum number of CI/CD minutes on shared runners that a group can use each month. 0 for unlimited."
-msgstr "МакÑимальна кількіÑÑ‚ÑŒ CI/CD хвилин Ð´Ð»Ñ Ñпільних ранерів, Ñкі можна викориÑтовувати щоміÑÑцÑ. 0 - без обмежень."
+msgstr "МакÑимальна кількіÑÑ‚ÑŒ CI/CD хвилин Ð´Ð»Ñ Ñпільних раннерів, Ñкі можна викориÑтовувати щоміÑÑцÑ. 0 - без обмежень."
msgid "The maximum number of tags that a single worker accepts for cleanup. If the number of tags goes above this limit, the list of tags to delete is truncated to this number. To remove this limit, set it to 0."
msgstr ""
@@ -40901,9 +41368,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40929,12 +41393,12 @@ msgid "The source topic and the target topic are identical."
msgstr ""
msgid "The source topic is not a topic."
-msgstr ""
+msgstr "Вихідна тема не є темою."
msgid "The specified tab is invalid, please select another"
msgstr "Вказана вкладка недійÑна. Будь лаÑка, виберіть іншу"
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40944,7 +41408,7 @@ msgid "The tag name can't be changed for an existing release."
msgstr ""
msgid "The target topic is not a topic."
-msgstr ""
+msgstr "Цільова тема не є темою."
msgid "The time period in seconds that the maximum requests per project limit applies to."
msgstr ""
@@ -40991,9 +41455,6 @@ msgstr "ВразливіÑÑ‚ÑŒ більше не виÑвлÑєтьÑÑ. ПерÐ
msgid "Theme"
msgstr "Тема"
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr "Ðаразі немає віддзеркалених репозиторіїв."
@@ -41016,7 +41477,7 @@ msgid "There are no Spam Logs"
msgstr ""
msgid "There are no abuse reports!"
-msgstr ""
+msgstr "Повідомлень про Ð·Ð»Ð¾Ð²Ð¶Ð¸Ð²Ð°Ð½Ð½Ñ Ð½ÐµÐ¼Ð°Ñ”!"
msgid "There are no archived projects yet"
msgstr "Ðаразі немає жодного архівованого проєкту"
@@ -41345,9 +41806,6 @@ msgstr "Ці Ñ–Ñнуючі проблеми мають подібні загоÐ
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -41381,6 +41839,9 @@ msgstr "Цей %{viewer} не може бути відображено череÐ
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41547,25 +42008,22 @@ msgid "This epic already has the maximum number of child epics."
msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
-msgstr ""
-
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
+msgstr "Цей епік не можна додати. Ðе можна додати до Ñамого епіка."
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
-msgstr ""
+msgstr "Цей епік не можна додати. Цей епік повинен належати тій же групі або підгрупі, Ñк Ñ– батьківÑький епік."
msgid "This epic cannot be added. It is already an ancestor of the parent epic."
-msgstr ""
+msgstr "Цей епік не можна додати. Він уже Ñ” предком батьківÑького епіка."
msgid "This epic cannot be added. It is already assigned to the parent epic."
-msgstr ""
+msgstr "Цей епік не може бути доданий. Він вже закріплений за батьківÑьким епіком."
msgid "This epic cannot be added. One or more epics would exceed the maximum depth (%{max_depth}) from its most distant ancestor."
-msgstr ""
+msgstr "Цей епік не може бути доданий. Один або більше епіків перевищують макÑимальну глибину (%{max_depth}) від Ñвого найвіддаленішого предка."
msgid "This epic cannot be added. You don't have access to perform this action."
-msgstr ""
+msgstr "Цей епік не можна додати. Ви не маєте доÑтупу до цієї дії."
msgid "This epic does not exist or you don't have sufficient permission."
msgstr "Цей епік не Ñ–Ñнує або у Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” доÑтатніх дозволів."
@@ -41612,6 +42070,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr "Ð¦Ñ Ð³Ñ€ÑƒÐ¿Ð° ще не має проєктів"
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41763,7 +42224,7 @@ msgid "This job is deployed to %{environmentLink}."
msgstr "Це Ð·Ð°Ð´Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·Ð³Ð¾Ñ€Ð½ÑƒÑ‚Ð¾ на %{environmentLink}."
msgid "This job is in pending state and is waiting to be picked by a runner"
-msgstr "Це Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÐ±ÑƒÐ²Ð°Ñ” в Ñтані Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ– чекає на запуÑк ранер"
+msgstr "Це Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð¿ÐµÑ€ÐµÐ±ÑƒÐ²Ð°Ñ” в Ñтані Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ– чекає на запуÑк раннер"
msgid "This job is performing tasks that must complete before it can start"
msgstr "Це Ð·Ð°Ð²Ð´Ð°Ð½Ð½Ñ Ð²Ð¸ÐºÐ¾Ð½ÑƒÑ” кроки, Ñкі повинні бути завершені перед його початком"
@@ -41828,15 +42289,18 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr "Такий проÑÑ‚Ñ–Ñ€ імен вже викориÑтовуєтьÑÑ! Будь лаÑка, виберіть інший."
+msgid "This namespace has already been taken. Choose a different one."
+msgstr "Цей проÑÑ‚Ñ–Ñ€ імен уже зайнÑто. Виберіть інший."
+
msgid "This only applies to repository indexing operations."
msgstr ""
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
+msgstr ""
+
msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr "Ð¦Ñ Ñторінка недоÑтупна, тому що ви не можете переглÑдати інформацію по кількох проєктах."
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
-msgstr ""
-
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
msgstr "Цей конвеєр викориÑтовує попередньо визначену конфігурацію CI / CD, увімкнену за допомогою %{b_open}Auto DevOps.%{b_close}"
@@ -41898,7 +42362,7 @@ msgid "This project path either does not exist or you do not have access."
msgstr ""
msgid "This project reached the limit of custom domains. (Max %d)"
-msgstr ""
+msgstr "Цей проєкт доÑÑг межі влаÑних доменів. (МакÑ. %d)"
msgid "This project will be deleted on %{date}"
msgstr ""
@@ -41907,7 +42371,7 @@ msgid "This project will be deleted on %{date} since its parent group '%{parent_
msgstr ""
msgid "This project's pipeline configuration is located outside this repository"
-msgstr ""
+msgstr "ÐšÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ð° цього проєкту знаходитьÑÑ Ð¿Ð¾Ð·Ð° межами цього репозиторію"
msgid "This release was created with a date in the past. Evidence collection at the moment of the release is unavailable."
msgstr ""
@@ -41931,7 +42395,7 @@ msgid "This repository was last checked %{last_check_timestamp}. The check passe
msgstr ""
msgid "This runner will only run on pipelines triggered on protected branches"
-msgstr "Цей runner буде виконуватиÑÑ Ñ‚Ñ–Ð»ÑŒÐºÐ¸ на тих конвеєрах, Ñкі Ñпрацьовують на захищених гілках"
+msgstr "Цей раннер буде виконуватиÑÑ Ñ‚Ñ–Ð»ÑŒÐºÐ¸ на тих конвеєрах, Ñкі Ñпрацьовують на захищених гілках"
msgid "This setting can be overridden in each project."
msgstr "Цей параметр можна перевизначати Ð´Ð»Ñ ÐºÐ¾Ð¶Ð½Ð¾Ð³Ð¾ проєкту."
@@ -41963,9 +42427,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr "Цей кориÑтувач не має ідентифікацій"
@@ -41984,6 +42445,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr "Цю змінну не можна замаÑкувати."
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr "Цей тип вразливоÑÑ‚Ñ– був заÑтарілий із Ñтандартного правила GitLab за замовчуваннÑм Ñ– автоматично вирішений."
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -42228,7 +42692,7 @@ msgid "Timeago|right now"
msgstr "зараз"
msgid "Timeline event added successfully."
-msgstr ""
+msgstr "ÐŸÐ¾Ð´Ñ–Ñ Ð½Ð° чаÑовій шкалі додана уÑпішно."
msgid "Timeline|Turn recent updates view off"
msgstr ""
@@ -42347,7 +42811,7 @@ msgid "To add a custom suffix, set up a Service Desk email address. %{linkStart}
msgstr ""
msgid "To add display name, set up a Service Desk email address. %{linkStart}Learn more.%{linkEnd}"
-msgstr ""
+msgstr "Щоб додати відображуване ім'Ñ, налаштуйте адреÑу електронної пошти Service Desk. %{linkStart}Докладніше%{linkEnd}."
msgid "To add the entry manually, provide the following details to the application on your phone."
msgstr "Щоб додати Ð·Ð°Ð¿Ð¸Ñ Ð²Ñ€ÑƒÑ‡Ð½Ñƒ, надайте наÑтупні відомоÑÑ‚Ñ– заÑтоÑунку у вашому телефоні."
@@ -42358,9 +42822,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -42383,7 +42844,7 @@ msgid "To define internal users, first enable new users set to external"
msgstr "Ð”Ð»Ñ Ð²Ð¸Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð²Ð½ÑƒÑ‚Ñ€Ñ–ÑˆÐ½Ñ–Ñ… кориÑтувачів, Ñпочатку вÑтановіть Ð´Ð»Ñ Ð½Ð¾Ð²Ð¸Ñ… кориÑтувачів \"зовнішній по замовчанню\""
msgid "To edit the pipeline configuration, you must go to the project or external site that hosts the file."
-msgstr ""
+msgstr "Ð”Ð»Ñ Ñ€ÐµÐ´Ð°Ð³ÑƒÐ²Ð°Ð½Ð½Ñ ÐºÐ¾Ð½Ñ„Ñ–Ð³ÑƒÑ€Ð°Ñ†Ñ–Ñ— конвеєра необхідно перейти на проєкт або зовнішній Ñайт, на Ñкому розміщений файл."
msgid "To enable Registration Features, first enable Service Ping."
msgstr ""
@@ -42466,6 +42927,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42532,9 +42996,33 @@ msgstr "Сьогодні"
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr "Додано"
+
+msgid "Todos|Alert"
+msgstr "ПопередженнÑ"
+
+msgid "Todos|Any Action"
+msgstr "Будь-Ñка діÑ"
+
+msgid "Todos|Any Type"
+msgstr "Будь-Ñкий тип"
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr "Призначено"
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr "Дизайн"
+
+msgid "Todos|Epic"
+msgstr "Епік"
+
msgid "Todos|Filter by author"
msgstr "Фільтрувати за автором"
@@ -42545,16 +43033,19 @@ msgid "Todos|Filter by project"
msgstr "Фільтрувати за проєктом"
msgid "Todos|Give yourself a pat on the back!"
-msgstr ""
+msgstr "ПоплеÑкайте Ñебе по плечу!"
msgid "Todos|Good job! Looks like you don't have anything left on your To-Do List"
-msgstr ""
+msgstr "Гарна робота! Схоже, у вашому ÑпиÑку Ñправ нічого не залишилоÑÑ"
msgid "Todos|Henceforth, you shall be known as \"To-Do Destroyer\""
-msgstr ""
+msgstr "Відтепер ви будете відомі Ñк \"Руйнівник Ñправ\""
msgid "Todos|Isn't an empty To-Do List beautiful?"
-msgstr ""
+msgstr "Хіба порожній ÑпиÑок Ñправ не прекраÑний?"
+
+msgid "Todos|Issue"
+msgstr "Задача"
msgid "Todos|It's how you always know what to work on next."
msgstr ""
@@ -42562,10 +43053,28 @@ msgstr ""
msgid "Todos|Mark all as done"
msgstr "Позначити вÑе Ñк виконане"
+msgid "Todos|Mentioned"
+msgstr "Згадувано"
+
+msgid "Todos|Merge request"
+msgstr "Запит на злиттÑ"
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
+msgstr "Ðе залишилоÑÑ Ñ€Ð¾Ð±Ð¾Ñ‚Ð¸. Дай п'ÑÑ‚ÑŒ!"
+
+msgid "Todos|Pipelines"
+msgstr "Конвеєр"
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
msgstr ""
msgid "Todos|Undo mark all as done"
@@ -42580,6 +43089,24 @@ msgstr "Ð’Ñе готово!"
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr "Ñебе"
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr "о %{todo_parent_path}"
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42680,7 +43207,7 @@ msgid "TopNav|Switch to"
msgstr "Перейти до"
msgid "TopNav|Your dashboards"
-msgstr ""
+msgstr "Ваші панелі керуваннÑ"
msgid "Topic %{source_topic} was successfully merged into topic %{target_topic}."
msgstr ""
@@ -42719,7 +43246,7 @@ msgid "Topics"
msgstr "Теми"
msgid "Topics could not be merged!"
-msgstr ""
+msgstr "Ðе вдалоÑÑ Ð¾Ð±'єднати теми!"
msgid "Total"
msgstr "Ð’Ñього"
@@ -42730,9 +43257,6 @@ msgstr "Загальна кількіÑÑ‚ÑŒ внеÑків"
msgid "Total Score"
msgstr "Загальний рахунок"
-msgid "Total artifacts size: %{total_size}"
-msgstr "Загальний розмір артефактів: %{total_size}"
-
msgid "Total cores (CPUs)"
msgstr "Ð’Ñього Ñдер (ЦП)"
@@ -43055,6 +43579,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43194,7 +43724,7 @@ msgid "Unable to parse JSON"
msgstr ""
msgid "Unable to parse the vulnerability report's options."
-msgstr ""
+msgstr "Ðе вдалоÑÑ Ð¿Ñ€Ð¾Ð°Ð½Ð°Ð»Ñ–Ð·ÑƒÐ²Ð°Ñ‚Ð¸ параметри звіту про вразливіÑÑ‚ÑŒ."
msgid "Unable to save iteration. Please try again"
msgstr "Ðе вдалоÑÑ Ð·Ð±ÐµÑ€ÐµÐ³Ñ‚Ð¸ ітерацію. Будь лаÑка, Ñпробуйте ще раз"
@@ -43559,8 +44089,14 @@ msgstr "Тенденції викориÑтаннÑ"
msgid "Usage statistics"
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 "СтатиÑтичні дані щодо Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Ð ÐµÑ”Ñтру контейнерів на рівні проєкту Ñ” лише орієнтовними Ñ– не включають економію коштів за рахунок дедуплікації в маÑштабах інÑтанÑів."
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr "Ð¦Ñ ÑтатиÑтика Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Ð½Ð° рівні проєкту не включає економію за рахунок дедуплікації на рівні вÑього Ñайту Ñ– не викориÑтовуєтьÑÑ Ð´Ð»Ñ Ñ€Ð¾Ð·Ñ€Ð°Ñ…ÑƒÐ½ÐºÑƒ загального обÑÑгу Ð·Ð±ÐµÑ€Ñ–Ð³Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñтору імен."
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
-msgstr "%{help_link_start}Загальні ранери%{help_link_end} вимкнено, тому ліміти на викориÑÑ‚Ð°Ð½Ð½Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ñ–Ð² відÑутні"
+msgstr "%{help_link_start}Загальні раннери%{help_link_end} вимкнено, тому ліміти на викориÑÑ‚Ð°Ð½Ð½Ñ ÐºÐ¾Ð½Ð²ÐµÑ”Ñ€Ñ–Ð² відÑутні"
msgid "UsageQuota|%{linkStart}Shared runners%{linkEnd} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43661,6 +44197,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr "Пакети"
@@ -43691,6 +44230,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr "Репозиторій"
+msgid "UsageQuota|Search"
+msgstr "Пошук"
+
msgid "UsageQuota|Seats"
msgstr "МіÑцÑ"
@@ -43749,7 +44291,7 @@ msgid "UsageQuota|This namespace contains locked projects"
msgstr ""
msgid "UsageQuota|This namespace has no projects which use shared runners"
-msgstr "Цей проÑÑ‚Ñ–Ñ€ імен не міÑтить проєктів, що викориÑтовують загальні ранери"
+msgstr "Цей проÑÑ‚Ñ–Ñ€ імен не міÑтить проєктів, що викориÑтовують загальні раннери"
msgid "UsageQuota|This namespace has no projects which used shared runners in the current period"
msgstr ""
@@ -44173,7 +44715,7 @@ msgid "UserLists|New list"
msgstr "Ðовий ÑпиÑок"
msgid "UserLists|New user list"
-msgstr ""
+msgstr "Ðовий ÑпиÑок кориÑтувачів"
msgid "UserLists|Save"
msgstr "Зберегти"
@@ -44368,7 +44910,7 @@ msgid "Users can launch a development environment from a GitLab browser tab when
msgstr ""
msgid "Users can reactivate their account by signing in. %{link_start}Learn more.%{link_end}"
-msgstr ""
+msgstr "КориÑтувачі можуть повторно активувати Ñвій обліковий запиÑ, увійшовши в ÑиÑтему. %{link_start}ДізнатиÑÑ Ð±Ñ–Ð»ÑŒÑˆÐµ.%{link_end}"
msgid "Users can render diagrams in AsciiDoc, Markdown, reStructuredText, and Textile documents using Kroki."
msgstr ""
@@ -44419,25 +44961,25 @@ msgid "User|Development Team Lead"
msgstr ""
msgid "User|Devops Engineer"
-msgstr ""
+msgstr "Devops Інженер"
msgid "User|Other"
-msgstr ""
+msgstr "Інший"
msgid "User|Product Designer"
-msgstr ""
+msgstr "Дизайнер Продукту"
msgid "User|Product Manager"
-msgstr ""
+msgstr "Менеджер Продукту"
msgid "User|Security Analyst"
msgstr ""
msgid "User|Software Developer"
-msgstr ""
+msgstr "Розробник ПЗ"
msgid "User|Systems Administrator"
-msgstr ""
+msgstr "СиÑтемний ÐдмініÑтратор"
msgid "Uses GitLab as an alternative to Sentry."
msgstr "ВикориÑтовувати GitLab Ñк альтернативу Sentry."
@@ -44653,7 +45195,7 @@ msgid "Version %{report_version} for report type %{report_type} has been depreca
msgstr ""
msgid "Version %{report_version} for report type %{report_type} is unsupported, supported versions for this report type are: %{supported_schema_versions}. GitLab will attempt to validate this report against the earliest supported versions of this report type, to show all the errors but will not ingest the report"
-msgstr ""
+msgstr "ВерÑÑ–Ñ %{report_version} Ð´Ð»Ñ Ñ‚Ð¸Ð¿Ñƒ звіту %{report_type} не підтримуєтьÑÑ, підтримувані верÑÑ–Ñ— цього типу звіту: %{supported_schema_versions}. GitLab Ñпробує перевірити цей звіт відноÑно ранніх підтримуваних верÑій цього типу, щоб показати вÑÑ– помилки, але не буде імпортувати звіт"
msgid "Version %{versionNumber}"
msgstr "ВерÑÑ–Ñ %{versionNumber}"
@@ -44701,7 +45243,7 @@ msgid "View blame prior to this change"
msgstr ""
msgid "View card matches"
-msgstr ""
+msgstr "ПереглÑнути відповідноÑÑ‚Ñ– картці"
msgid "View chart"
msgid_plural "View charts"
@@ -44747,9 +45289,6 @@ msgstr "ПереглÑнути файл @ %{commitSha}"
msgid "View full dashboard"
msgstr "ПереглÑнути повну панель керуваннÑ"
-msgid "View full log"
-msgstr "ПереглÑнути веÑÑŒ журнал"
-
msgid "View group in admin area"
msgstr ""
@@ -45157,7 +45696,7 @@ msgid "Vulnerability|File"
msgstr "Файл"
msgid "Vulnerability|File:"
-msgstr ""
+msgstr "Файл:"
msgid "Vulnerability|GitLab Security Report"
msgstr ""
@@ -45184,7 +45723,7 @@ msgid "Vulnerability|Links"
msgstr "ПоÑиланнÑ"
msgid "Vulnerability|Location"
-msgstr ""
+msgstr "РозташуваннÑ"
msgid "Vulnerability|Method"
msgstr "Метод"
@@ -45196,7 +45735,7 @@ msgid "Vulnerability|Project"
msgstr "Проєкт"
msgid "Vulnerability|Project:"
-msgstr ""
+msgstr "Проєкт:"
msgid "Vulnerability|Remove identifier row"
msgstr ""
@@ -45213,6 +45752,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -45226,11 +45768,14 @@ msgid "Vulnerability|Severity"
msgstr "Рівень"
msgid "Vulnerability|Severity:"
-msgstr ""
+msgstr "Рівень:"
msgid "Vulnerability|Status"
msgstr "СтатуÑ"
+msgid "Vulnerability|Status:"
+msgstr "СтатуÑ:"
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -45241,7 +45786,7 @@ msgid "Vulnerability|Tool"
msgstr ""
msgid "Vulnerability|Tool:"
-msgstr ""
+msgstr "ІнÑтрумент:"
msgid "Vulnerability|Training"
msgstr ""
@@ -45256,7 +45801,7 @@ msgid "Vulnerability|View training"
msgstr ""
msgid "WARNING:"
-msgstr ""
+msgstr "ПОПЕРЕДЖЕÐÐЯ:"
msgid "WARNING: This snippet contains hidden files which might be used to mask malicious behavior. Exercise caution if cloning and executing code from this snippet."
msgstr ""
@@ -45322,7 +45867,7 @@ msgid "We created a sandbox project that will help you learn the basics of GitLa
msgstr ""
msgid "We detected an attempt to sign in to your %{host} account using a wrong two-factor authentication code"
-msgstr ""
+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 ""
@@ -45366,7 +45911,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "Ми хочемо бути впевнені, що це ви, будь лаÑка, підтвердіть, що ви не робот."
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -45408,6 +45953,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr "Форк проєкту"
@@ -45423,12 +45971,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -45468,6 +46028,9 @@ msgstr "Веб-хуки"
msgid "Webhooks Help"
msgstr "Допомога по веб-хукам"
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45538,7 +46101,7 @@ msgid "Webhooks|Deployment events"
msgstr ""
msgid "Webhooks|Do not show sensitive data such as tokens in the UI."
-msgstr ""
+msgstr "Ðе відображати конфіденційні дані, такі Ñк токени в інтерфейÑÑ–."
msgid "Webhooks|Enable SSL verification"
msgstr "Увімкнути перевірку SSL"
@@ -45553,10 +46116,10 @@ msgid "Webhooks|Feature flag events"
msgstr ""
msgid "Webhooks|Go to webhooks"
-msgstr ""
+msgstr "Перейти до вебхуків"
msgid "Webhooks|How it looks in the UI"
-msgstr ""
+msgstr "Як це виглÑдає в інтерфейÑÑ–"
msgid "Webhooks|Issues events"
msgstr ""
@@ -45565,7 +46128,7 @@ msgid "Webhooks|Job events"
msgstr ""
msgid "Webhooks|Mask portions of URL"
-msgstr ""
+msgstr "МаÑкувати чаÑтини URL-адреÑи"
msgid "Webhooks|Member events"
msgstr ""
@@ -45582,6 +46145,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr "РегулÑрний вираз, такий Ñк %{REGEX_CODE}."
+
+msgid "Webhooks|Regular expression"
+msgstr "РегулÑрний вираз"
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45592,10 +46161,10 @@ msgid "Webhooks|Secret token"
msgstr ""
msgid "Webhooks|Sensitive portion of URL"
-msgstr ""
+msgstr "Чутлива чаÑтина URL"
msgid "Webhooks|Show full URL"
-msgstr ""
+msgstr "Показати повний URL"
msgid "Webhooks|Subgroup events"
msgstr ""
@@ -45609,9 +46178,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45622,13 +46188,13 @@ msgid "Webhooks|URL must be percent-encoded if it contains one or more special c
msgstr ""
msgid "Webhooks|URL preview"
-msgstr ""
+msgstr "ПереглÑд URL"
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
-msgstr ""
+msgstr "Вебхук вимкнено"
msgid "Webhooks|Webhook failed to connect"
msgstr ""
@@ -45636,12 +46202,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr "ПідтримуютьÑÑ ÑˆÐ°Ð±Ð»Ð¾Ð½Ð¸, такі Ñк %{WILDCARD_CODE_STABLE} або %{WILDCARD_CODE_PRODUCTION}."
+
msgid "Website"
msgstr ""
@@ -45694,7 +46269,7 @@ msgid "What are project audit events?"
msgstr ""
msgid "What are some examples?"
-msgstr ""
+msgstr "Які є приклади?"
msgid "What does the setting affect?"
msgstr "Ðа що впливає налаштуваннÑ?"
@@ -45703,7 +46278,7 @@ msgid "What does this command do?"
msgstr "Що робить Ñ†Ñ ÐºÐ¾Ð¼Ð°Ð½Ð´Ð°?"
msgid "What is GitLab Runner?"
-msgstr "Що таке GitLab ранер?"
+msgstr "Що таке GitLab раннер?"
msgid "What is Markdown?"
msgstr ""
@@ -45720,6 +46295,9 @@ msgstr "Що таке об'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ (squash) комітів?"
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr "Ð”Ð»Ñ Ñ‡Ð¾Ð³Ð¾ ви будете викориÑтовувати цю групу?"
@@ -45729,11 +46307,11 @@ msgstr ""
msgid "What's new"
msgstr "Що нового"
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
-msgstr "Коли runner закріплений (за проєктами), його не можна викориÑтовувати в інших проєктах"
+msgstr "Коли раннер закріплений (за проєктами), його не можна викориÑтовувати в інших проєктах"
msgid "When enabled, SSH keys with no expiry date or an invalid expiration date are no longer accepted. Leave blank for no limit."
msgstr ""
@@ -45948,7 +46526,7 @@ msgid "WikiPage|Tip: You can specify the full path for the new file. We will aut
msgstr ""
msgid "WikiPage|Title"
-msgstr ""
+msgstr "Заголовок"
msgid "WikiPage|To link to a (new) page, simply type %{linkExample}. More examples are in the %{linkStart}documentation%{linkEnd}."
msgstr ""
@@ -46049,6 +46627,12 @@ msgstr "Додати дату початку"
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr "Додати до ітерації"
+
+msgid "WorkItem|Add to milestone"
+msgstr "Додати в етап"
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -46101,9 +46685,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr "Задача"
+msgid "WorkItem|Iteration"
+msgstr "ІтераціÑ"
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr "Етап"
+
+msgid "WorkItem|No iteration"
+msgstr "Ðемає ітерації"
+
+msgid "WorkItem|No matching results"
+msgstr "Ðемає відповідних результатів"
+
+msgid "WorkItem|No milestone"
+msgstr "Ðемає етапу"
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -46129,17 +46728,20 @@ msgid "WorkItem|Something went wrong when creating %{workItemType}. Please try a
msgstr "ЩоÑÑŒ пішло не так під Ñ‡Ð°Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ %{workItemType}. Будь лаÑка Ñпробуйте ще раз."
msgid "WorkItem|Something went wrong when deleting the %{workItemType}. Please try again."
-msgstr ""
+msgstr "ЩоÑÑŒ пішло не так під Ñ‡Ð°Ñ Ð²Ð¸Ð´Ð°Ð»ÐµÐ½Ð½Ñ %{workItemType}. Будь лаÑка, Ñпробуйте ще раз."
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr "Під Ñ‡Ð°Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð¼Ñ–Ñ‚Ð¾Ðº ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°. Будь лаÑка, Ñпробуйте ще раз."
+
msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr "ЩоÑÑŒ пішло не так при отриманні ÑпиÑку елементів. Будь лаÑка, оновіть цю Ñторінку."
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
-msgstr ""
-
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
msgstr ""
@@ -46149,8 +46751,11 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr "Під Ñ‡Ð°Ñ Ñпроби Ñтворити дочірній елемент ÑталаÑÑ Ð¿Ð¾Ð¼Ð¸Ð»ÐºÐ°. Будь лаÑка, Ñпробуйте ще раз."
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr "ЩоÑÑŒ пішло не так під Ñ‡Ð°Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ. Будь лаÑка, Ñпробуйте ще раз."
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
-msgstr ""
+msgstr "ЩоÑÑŒ пішло не так під Ñ‡Ð°Ñ Ð¾Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ %{workItemType}. Будь лаÑка, Ñпробуйте ще раз."
msgid "WorkItem|Something went wrong while updating the work item. Please try again."
msgstr ""
@@ -46170,8 +46775,11 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr "Робочий елемент недоÑтупний. Він не Ñ–Ñнує, або у Ð²Ð°Ñ Ð½ÐµÐ¼Ð°Ñ” дозволу на його переглÑд."
+
msgid "WorkItem|Turn off confidentiality"
-msgstr ""
+msgstr "Вимкнути конфіденційніÑÑ‚ÑŒ"
msgid "WorkItem|Turn on confidentiality"
msgstr "Увімкнути конфіденційніÑÑ‚ÑŒ"
@@ -46188,6 +46796,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr "Робочий елемент"
+msgid "WorkItem|Work item not found"
+msgstr "Робочий елемент не знайдено"
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -46285,6 +46896,9 @@ msgstr "Ви намагаєтеÑÑ Ð²Ð¸Ð´Ð°Ð»Ð¸Ñ‚Ð¸ файл, Ñкий рані
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr "Ви намагаєтеÑÑ Ð¾Ð½Ð¾Ð²Ð¸Ñ‚Ð¸ файл, Ñкий було змінено піÑÐ»Ñ Ð¿Ð¾Ñ‡Ð°Ñ‚ÐºÑƒ редагуваннÑ."
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -46321,6 +46935,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr "Вам заборонено Ñтворювати цей тег, оÑкільки він захищений."
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -46366,9 +46986,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr "Ви намагаєтеÑÑŒ завантажити щоÑÑŒ, що не Ñ” зображеннÑм. Будь лаÑка, завантажте файл .png, .jpg, .jpeg, .gif, .bmp, .tiff або .ico."
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -46425,10 +47042,10 @@ msgid "You can check it in your in your personal access tokens settings %{pat_li
msgstr ""
msgid "You can check your tokens or create a new one in your %{pat_link_start}personal access tokens settings%{pat_link_end}."
-msgstr ""
+msgstr "Ви можете перевірити Ñвої токени або Ñтворити новий у ваших %{pat_link_start}перÑональних налаштуваннÑÑ… доÑтупу%{pat_link_end}."
msgid "You can check your tokens or create a new one in your personal access tokens settings %{pat_link}."
-msgstr ""
+msgstr "Ви можете перевірити Ñвої токени або Ñтворити новий в налаштуваннÑÑ… ваших оÑобиÑтих токенів доÑтупу %{pat_link}."
msgid "You can create a new %{link}."
msgstr ""
@@ -46472,6 +47089,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr "Ви можете ввеÑти до 280 Ñимволів"
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr "Ви можете фільтрувати за \"днÑми до злиттÑ\", натиÑнувши на колонки в таблиці."
@@ -46544,8 +47164,8 @@ msgstr "Ви можете перевірити Ñвій .gitlab-ci.yml у %{link
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
-msgstr ""
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
+msgstr "Ви не можете підпиÑатиÑÑ Ð½Ð° більше ніж %{limit} кориÑтувачів. Щоб підпиÑатиÑÑ Ð½Ð° більше кориÑтувачів, ÑкаÑуйте підпиÑку на деÑких інших."
msgid "You cannot %{action} %{state} users."
msgstr ""
@@ -46554,7 +47174,7 @@ msgid "You cannot access the raw file. Please wait a minute."
msgstr "Ви не можете отримати доÑтуп до неформатованого файлу. Будь лаÑка, зачекайте хвилину."
msgid "You cannot add any more epics. This epic already has maximum number of child epics."
-msgstr ""
+msgstr "Ви не можете додати більше епіків. Цей епік вже має макÑимальну кількіÑÑ‚ÑŒ дочірніх епіків."
msgid "You cannot approve your own deployment."
msgstr ""
@@ -46568,6 +47188,9 @@ msgstr "Ви не можете імітувати заблокованого кÐ
msgid "You cannot impersonate a user who cannot log in"
msgstr "Ви не можете імітувати кориÑтувача, Ñкий не може увійти"
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr "Ви не можете імітувати внутрішнього кориÑтувача"
@@ -46713,6 +47336,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46759,7 +47385,7 @@ msgid "You have successfully purchased %{product}. You'll receive a receipt by e
msgstr ""
msgid "You have successfully purchased a %{plan} plan subscription for %{seats}. You’ll receive a receipt via email. Your purchase may take a minute to sync, so refresh the page if you don't see it yet."
-msgstr ""
+msgstr "Ви уÑпішно придбали тарифний план %{plan} Ð´Ð»Ñ %{seats}. Ви отримаєте чек на електронну пошту. Ваша покупка може зайнÑти хвилину Ð´Ð»Ñ Ñинхронізації, тому оновіть Ñторінку, Ñкщо ви ще цього не бачили."
msgid "You have unsaved changes"
msgstr ""
@@ -46776,7 +47402,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46822,7 +47448,7 @@ msgid "You need to verify your primary email first before enabling Two-Factor Au
msgstr ""
msgid "You see projects here when you're added to a group or project."
-msgstr ""
+msgstr "Ви бачите тут проєкти під Ñ‡Ð°Ñ Ð´Ð¾Ð´Ð°Ð²Ð°Ð½Ð½Ñ Ð´Ð¾ групи або проєкту."
msgid "You successfully declined the invitation"
msgstr ""
@@ -46930,7 +47556,7 @@ msgid "You're receiving this email because you have been mentioned on %{host}. %
msgstr ""
msgid "You're viewing members of %{strong_start}%{group_name}%{strong_end}."
-msgstr ""
+msgstr "Ви переглÑдаєте учаÑників %{strong_start}%{group_name}%{strong_end}."
msgid "You've already enabled two-factor authentication using one time password authenticators. In order to register a different device, you must first disable two-factor authentication."
msgstr "Ви уже увімкнули двофакторну автентифікацію за допомогою автентифікаторів одноразових паролів. Ð”Ð»Ñ Ñ€ÐµÑ”Ñтрації іншого приÑтрою ви повинні Ñпочатку вимкнути двофакторну автентифікацію."
@@ -46944,9 +47570,6 @@ msgstr "YouTube"
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46975,10 +47598,10 @@ msgid "Your CSV import for project"
msgstr ""
msgid "Your Chain of Custody CSV export for the group %{group_link} has been added to this email as an attachment."
-msgstr ""
+msgstr "Ваш ланцюг CSV Custody Ð´Ð»Ñ Ð³Ñ€ÑƒÐ¿Ð¸ %{group_link} було додано на цей електронний лиÑÑ‚ Ñк вкладеннÑ."
msgid "Your Chain of Custody CSV export for the group %{group_name} has been added to this email as an attachment."
-msgstr ""
+msgstr "Ваш ланцюг CSV Custody Ð´Ð»Ñ Ð³Ñ€ÑƒÐ¿Ð¸ %{group_name} було додано на цей електронний лиÑÑ‚ Ñк вкладеннÑ."
msgid "Your DevOps Reports give an overview of how you are using GitLab from a feature perspective. Use them to view how you compare with other organizations, and how your teams compare against each other."
msgstr ""
@@ -47058,6 +47681,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr "Ваш обліковий Ð·Ð°Ð¿Ð¸Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸Ñтовує окремі параметри входу Ð´Ð»Ñ Ð³Ñ€ÑƒÐ¿Ð¸ \"%{group_name}\" Ñ– можу бути оновлений тільки через SSO."
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr "Вашу дію було відхилено, оÑкільки доÑÑгнуто ліміту проÑтору імен. Ð”Ð»Ñ Ð¾Ñ‚Ñ€Ð¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð¾Ñ— інформації, відвідайте %{doc_url}."
+
msgid "Your action succeeded."
msgstr ""
@@ -47132,10 +47758,10 @@ msgstr ""
msgid "Your free group is now limited to %d member"
msgid_plural "Your free group is now limited to %d members"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "Ваша безкоштовна група тепер обмежена %d учаÑником"
+msgstr[1] "Ваша безкоштовна група тепер обмежена %d учаÑниками"
+msgstr[2] "Ваша безкоштовна група тепер обмежена %d учаÑниками"
+msgstr[3] "Ваша безкоштовна група тепер обмежена %d учаÑниками"
msgid "Your group, %{strong_start}%{namespace_name}%{strong_end} has more than %{free_user_limit} member. From October 19, 2022, the %{free_user_limit} most recently active member will remain active, and the remaining members will have the %{link_start}Over limit status%{link_end} and lose access to the group. You can go to the Usage Quotas page to manage which %{free_user_limit} member will remain in your group."
msgid_plural "Your group, %{strong_start}%{namespace_name}%{strong_end} has more than %{free_user_limit} members. From October 19, 2022, the %{free_user_limit} most recently active members will remain active, and the remaining members will have the %{link_start}Over limit status%{link_end} and lose access to the group. You can go to the Usage Quotas page to manage which %{free_user_limit} members will remain in your group."
@@ -47180,16 +47806,13 @@ msgstr "Ваше Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ Ñ‚ÑƒÑ‚"
msgid "Your name"
msgstr "Ваше ім'Ñ"
-msgid "Your new %{accessTokenType}"
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new %{type}"
-msgstr "Ваш новий %{type}"
-
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -47214,7 +47837,7 @@ msgid "Your profile"
msgstr "Ваш профіль"
msgid "Your project is no longer receiving GitLab Ultimate benefits as of 2022-07-01. As notified in-app previously, public open source projects on the Free tier can apply to the GitLab for Open Source Program to receive GitLab Ultimate benefits. Please refer to the %{faq_link_start}FAQ%{link_end} for more details."
-msgstr ""
+msgstr "Ваш проєкт більше не отримує переваги GitLab Ultimate з 2022-07-01. Як повідомлÑлоÑÑ Ñ€Ð°Ð½Ñ–ÑˆÐµ в заÑтоÑунку, публічні проєкти з відкритим вихідним кодом на безкоштовному рівні можуть подати заÑвку на учаÑÑ‚ÑŒ у програмі GitLab Ð´Ð»Ñ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¾Ð³Ð¾ вихідного коду, щоб отримати переваги GitLab Ultimate. Будь лаÑка, звернітьÑÑ Ð´Ð¾ %{faq_link_start}FAQ%{link_end} Ð´Ð»Ñ Ð±Ñ–Ð»ÑŒÑˆ детальної інформації."
msgid "Your project limit is %{limit} projects! Please contact your administrator to increase it"
msgstr "Ваш ліміт проєктів Ñкладає %{limit}! Будь лаÑка, звернітьÑÑ Ð´Ð¾ адмініÑтратора, щоб його збільшити"
@@ -47280,6 +47903,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -47349,9 +47975,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr "видалений кориÑтувач"
@@ -47365,14 +47988,11 @@ msgstr[3] "близько %d годин"
msgid "access:"
msgstr "доÑтуп:"
-msgid "added"
-msgstr "додано"
-
msgid "added %{emails}"
msgstr "додано %{emails}"
msgid "added a %{link_type} link"
-msgstr ""
+msgstr "додано поÑÐ¸Ð»Ð°Ð½Ð½Ñ %{link_type}"
msgid "added a Zoom call to this issue"
msgstr "додано дзвінок Zoom до цієї задачі"
@@ -47429,6 +48049,12 @@ msgstr ""
msgid "assign yourself"
msgstr "призначити Ñамому Ñобі"
+msgid "assigned"
+msgstr "призначено"
+
+msgid "assigned you"
+msgstr "назначено вам"
+
msgid "at"
msgstr ""
@@ -47438,9 +48064,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr "під загрозою"
-
msgid "attach a new file"
msgstr "прикріпити новий файл"
@@ -47473,7 +48096,7 @@ msgid "cURL:"
msgstr ""
msgid "can contain only digits"
-msgstr ""
+msgstr "може міÑтити лише цифри"
msgid "can contain only letters of the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'"
msgstr ""
@@ -47515,12 +48138,18 @@ msgid "can't reference a branch that does not exist"
msgstr ""
msgid "cannot assign a non-confidential work item to a confidential parent. Make the work item confidential and try again."
-msgstr ""
+msgstr "не може призначити неконфіденційний робочий елемент конфіденційному батькові. Зробіть робочий елемент конфіденційним Ñ– повторіть Ñпробу."
msgid "cannot be a date in the past"
msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
+msgstr "не можна додати оÑкільки ви доÑÑгли ліміту учаÑників %{free_limit} Ð´Ð»Ñ %{namespace_name}"
+
+msgid "cannot be associated with a subgroup"
+msgstr "не можна аÑоціювати з підгрупою"
+
+msgid "cannot be associated with both a Group and a Project"
msgstr ""
msgid "cannot be changed"
@@ -47533,7 +48162,7 @@ msgid "cannot be changed if shared runners are enabled"
msgstr ""
msgid "cannot be changed since member is associated with a custom role"
-msgstr ""
+msgstr "не можна змінити, оÑкільки учаÑник пов’Ñзаний зі Ñпеціальною роллю"
msgid "cannot be enabled"
msgstr ""
@@ -47764,12 +48393,27 @@ msgstr "Ð¡ÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð»ÐµÐ¶Ð½Ð¾Ñтей виÑвлÑÑ” відомі
msgid "ciReport|Dependency scanning"
msgstr "Ð¡ÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð·Ð°Ð»ÐµÐ¶Ð½Ð¾Ñтей"
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr "ВиÑвлÑÑ” відомі вразливоÑÑ‚Ñ– в залежноÑÑ‚ÑÑ… вашого коду."
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr "ВиÑвлÑÑ” відомі вразливоÑÑ‚Ñ– у вашому вихідному коді."
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr "ВиÑвлÑÑ” відомі вразливоÑÑ‚Ñ– у вашому веб-заÑтоÑунку."
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr "ВиÑвлÑÑ” Ñекрети та вразливоÑÑ‚Ñ– облікових даних у вашому вихідному коді."
+
msgid "ciReport|Download patch to resolve"
msgstr "завантажити патч Ð´Ð»Ñ Ð²Ð¸Ñ€Ñ–ÑˆÐµÐ½Ð½Ñ"
msgid "ciReport|Download the patch to apply it manually"
msgstr "Завантажити патч Ñ– заÑтоÑувати його вручну"
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr "Динамічне теÑÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸ заÑтоÑунків (DAST) виÑвлÑÑ” відомі вразливоÑÑ‚Ñ– у вашому веб-заÑтоÑунку."
@@ -47792,7 +48436,7 @@ msgid "ciReport|Full Report"
msgstr "Повний звіт"
msgid "ciReport|Generic Report"
-msgstr ""
+msgstr "Загальний звіт"
msgid "ciReport|IaC Scanning"
msgstr ""
@@ -47846,6 +48490,9 @@ msgstr "Додано вручну"
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr "Ðові вразливоÑÑ‚Ñ– - це вразливоÑÑ‚Ñ–, Ñкі виÑвлÑÑ” аналіз безпеки у запиті на злиттÑ, відмінні від Ñ–Ñнуючих вразливоÑтей у гілці за замовчуваннÑм."
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47876,6 +48523,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr "Результати ÑÐºÐ°Ð½ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸"
+
msgid "ciReport|Security scanning"
msgstr "Перевірка безпеки"
@@ -47891,6 +48541,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr "РішеннÑ"
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr "Статичне теÑÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð±ÐµÐ·Ð¿ÐµÐºÐ¸ заÑтоÑунків (SAST) виÑвлÑÑ” відомі вразливоÑÑ‚Ñ– у вашому коді."
@@ -47967,6 +48620,9 @@ msgstr "коміт %{commit_id}"
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47998,13 +48654,13 @@ msgid "created %{timeAgoString} by %{email} via %{user}"
msgstr ""
msgid "created %{timeAgo}"
-msgstr ""
+msgstr "Ñтворено %{timeAgo}"
msgid "created %{timeAgo} by %{author}"
msgstr ""
msgid "created %{timeAgo} by %{author} in %{project_link}"
-msgstr ""
+msgstr "Ñтворено %{timeAgo} %{author} в %{project_link}"
msgid "created by"
msgstr ""
@@ -48028,6 +48684,9 @@ msgstr[3] "днів"
msgid "days"
msgstr "дні"
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr "гілка за замовчуваннÑм"
@@ -48035,7 +48694,7 @@ msgid "deleted"
msgstr "видалено"
msgid "denied"
-msgstr ""
+msgstr "відмовлено"
msgid "deploy"
msgstr "розгортаннÑ"
@@ -48141,7 +48800,7 @@ msgid "failed to dismiss finding: %{message}"
msgstr ""
msgid "failed to dismiss security finding: %{message}"
-msgstr ""
+msgstr "не зміг відхилити виÑновок про безпеку: %{message}"
msgid "failed to revert associated finding(id=%{finding_id}) to detected"
msgstr ""
@@ -48190,6 +48849,9 @@ msgstr[1] ""
msgstr[2] ""
msgstr[3] ""
+msgid "from yourself"
+msgstr "від ваÑ"
+
msgid "frontmatter"
msgstr ""
@@ -48294,12 +48956,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr "некоректний Ñтан етапу '%{state}'"
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr "Ñ”"
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr "вже пов'Ñзана з цією вразливіÑÑ‚ÑŽ"
+
msgid "is an invalid IP address range"
msgstr "Ñ” недопуÑтимим діапазоном IP-адреÑ"
@@ -48321,6 +48989,9 @@ msgstr "не є"
msgid "is not a descendant of the Group owning the template"
msgstr "не Ñ” нащадком групи, Ñкій належить шаблон"
+msgid "is not a valid URL."
+msgstr "не Ñ” дійÑною URL-адреÑою."
+
msgid "is not a valid X509 certificate."
msgstr "не відповідний Ñертифікат X509."
@@ -48345,12 +49016,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr "не є одним з"
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr "є одним з"
+
msgid "is read-only"
msgstr ""
@@ -48358,7 +49035,7 @@ msgid "is too long (%{current_value}). The maximum size is %{max_size}."
msgstr "Ñ” занадто довгим (%{current_value}). МакÑимальний розмір Ñкладає %{max_size}."
msgid "is too long (%{size}). The maximum size is %{max_size}."
-msgstr ""
+msgstr "занадто довгий (%{size}). МакÑимальний розмір – %{max_size}."
msgid "is too long (maximum is %{count} characters)"
msgstr ""
@@ -48431,10 +49108,10 @@ msgstr "доÑÑгнуто ліміт %{project_limit}"
msgid "line"
msgid_plural "lines"
-msgstr[0] ""
-msgstr[1] ""
-msgstr[2] ""
-msgstr[3] ""
+msgstr[0] "Ñ€Ñдок"
+msgstr[1] "Ñ€Ñдки"
+msgstr[2] "Ñ€Ñдків"
+msgstr[3] "Ñ€Ñдків"
msgid "load it anyway"
msgstr "вÑе одно завантажити"
@@ -48472,13 +49149,13 @@ msgstr[2] "запитів на злиттÑ"
msgstr[3] "запитів на злиттÑ"
msgid "mergedCommitsAdded| (commits were squashed)"
-msgstr ""
+msgstr " (коміти були об'єднані)"
msgid "metric_id must be unique across a project"
msgstr ""
msgid "milestone should belong either to a project or a group."
-msgstr ""
+msgstr "етап повинен належати до проєкту або до групи."
msgid "missing"
msgstr "відÑутні"
@@ -48496,7 +49173,7 @@ msgid "mrWidgetCommitsAdded|%{commitCount} will be added to %{targetBranch}."
msgstr "%{commitCount} буде додано в %{targetBranch}."
msgid "mrWidgetCommitsAdded|%{strongStart}1%{strongEnd} merge commit"
-msgstr ""
+msgstr "%{strongStart}1%{strongEnd} коміт-злиттÑ"
msgid "mrWidgetCommitsAdded|Changes merged into %{targetBranch} with %{mergeCommitSha}%{squashedCommits}."
msgstr "Зміни злиті в %{targetBranch} з %{mergeCommitSha}%{squashedCommits}."
@@ -48513,9 +49190,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr "%{boldHeaderStart}Схоже, що конвеєр тут відÑутній%{boldHeaderEnd}"
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr "%{mergeError}."
@@ -48663,11 +49337,14 @@ msgstr[2] "Задач зі згадками"
msgstr[3] "Задач зі згадками"
msgid "mrWidget|Merge blocked: a Jira issue key must be mentioned in the title or description."
-msgstr ""
+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 ""
@@ -48764,9 +49441,6 @@ msgstr "Ðнулювати цей запит на Ð·Ð»Ð¸Ñ‚Ñ‚Ñ Ð·Ð° допомо
msgid "mrWidget|Revoke approval"
msgstr "СкаÑувати затвердженнÑ"
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48830,6 +49504,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr "повинна бути пізніша за дату початку"
@@ -48842,9 +49519,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr "має бути проÑÑ‚Ñ–Ñ€ імен верхнього рівнÑ"
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48863,9 +49546,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr "потребує уваги"
-
msgid "needs to be between 10 minutes and 1 month"
msgstr "має бути між 10 хвилинами та 1 міÑÑцем"
@@ -48914,9 +49594,6 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item}, Ñ– %{lastItem}"
-msgid "on track"
-msgstr "по плану"
-
msgid "only %{parent_types} can be parent of Task."
msgstr "лише %{parent_types} може бути батьківÑьким завданнÑм."
@@ -48935,19 +49612,15 @@ msgstr "або"
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] "із %d теÑту"
-msgstr[1] "із %d теÑтів"
-msgstr[2] "із %d теÑтів"
-msgstr[3] "із %d теÑтів"
-
msgid "packages"
msgstr "пакети"
msgid "pages"
msgstr "Ñторінки"
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "батьківÑький об’єкт"
@@ -48956,10 +49629,10 @@ msgstr[2] "батьківÑький об’єктів"
msgstr[3] "батьківÑький об’єктів"
msgid "parent already has maximum number of children."
-msgstr ""
+msgstr "у батька вже Ñ” макÑимальна кількіÑÑ‚ÑŒ дітей."
msgid "parent must be in the same project as child."
-msgstr ""
+msgstr "батько має бути в тому ж проєкті, що й дитина."
msgid "password"
msgstr "пароль"
@@ -49083,11 +49756,8 @@ msgstr ""
msgid "remove weight"
msgstr "видалити вагу"
-msgid "removed"
-msgstr "видалено"
-
msgid "removed a %{link_type} link"
-msgstr ""
+msgstr "видалено поÑÐ¸Ð»Ð°Ð½Ð½Ñ %{link_type}"
msgid "removed a Zoom call from this issue"
msgstr "видалено дзвінок Zoom із цієї задачі"
@@ -49108,12 +49778,22 @@ msgstr ""
msgid "repositories"
msgstr "репозиторії"
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] "репозиторій"
+msgstr[1] "репозиторіÑ"
+msgstr[2] "репозиторіїв"
+msgstr[3] "репозиторіїв"
+
msgid "repository:"
msgstr "репозиторій:"
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr "задоволено"
@@ -49239,7 +49919,7 @@ msgid "suggestPipeline|We’re adding a GitLab CI configuration file to add a pi
msgstr ""
msgid "supported SSH public key."
-msgstr ""
+msgstr "підтримує відкритий ключ SSH."
msgid "tag name"
msgstr "назва тегу"
@@ -49254,7 +49934,7 @@ msgid "the following epics"
msgstr "наÑтупні епіки"
msgid "the following incidents or issues"
-msgstr ""
+msgstr "наÑтупні інциденти або задачі"
msgid "the following issues"
msgstr "наÑтупні задачі"
@@ -49271,6 +49951,9 @@ msgstr "цей документ"
msgid "time summary"
msgstr "підÑумок чаÑу"
+msgid "to yourself"
+msgstr "Ñамому Ñобі"
+
msgid "today"
msgstr ""
@@ -49411,11 +50094,14 @@ msgstr ""
msgid "yaml invalid"
msgstr "yaml недійÑний"
+msgid "you"
+msgstr "ви"
+
msgid "your GitLab instance"
-msgstr ""
+msgstr "ваш інÑÑ‚Ð°Ð½Ñ GitLab"
msgid "your group (%{group_name})"
-msgstr ""
+msgstr "ваша група (%{group_name})"
msgid "your settings"
msgstr "ваші налаштуваннÑ"
diff --git a/locale/ur_PK/gitlab.po b/locale/ur_PK/gitlab.po
index 984a7761bc6..b7ae00cd0e7 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: 2022-10-10 14:00\n"
+"PO-Revision-Date: 2022-11-13 09:21\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/uz_UZ/gitlab.po b/locale/uz_UZ/gitlab.po
index 3e7ecfe06a7..f236b145e88 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: 2022-10-10 14:05\n"
+"PO-Revision-Date: 2022-11-13 09:24\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -143,6 +143,11 @@ msgid_plural "%d additional users"
msgstr[0] ""
msgstr[1] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -243,21 +248,11 @@ msgid_plural "%d epics"
msgstr[0] ""
msgstr[1] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
msgstr[1] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -268,11 +263,6 @@ msgid_plural "%d files"
msgstr[0] ""
msgstr[1] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -513,6 +503,9 @@ msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
msgstr[1] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -567,6 +560,16 @@ msgstr[1] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+msgstr[1] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -575,6 +578,11 @@ msgstr[1] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} more"
msgstr ""
@@ -597,6 +605,11 @@ msgid_plural "%{count} participants"
msgstr[0] ""
msgstr[1] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -636,9 +649,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -849,12 +859,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -1040,6 +1044,9 @@ msgstr[1] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1182,9 +1189,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1242,6 +1246,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1280,6 +1287,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1565,6 +1575,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1628,9 +1641,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1709,9 +1719,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1919,6 +1926,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -2030,15 +2040,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -2108,9 +2112,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2483,6 +2484,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2666,6 +2673,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2702,15 +2727,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2759,6 +2796,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2804,6 +2844,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2942,9 +2994,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2969,6 +3030,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -3071,6 +3141,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3263,7 +3336,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3308,7 +3381,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3371,7 +3444,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3419,6 +3492,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3929,7 +4005,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3944,6 +4020,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3980,9 +4059,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4229,6 +4305,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4414,9 +4493,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4516,9 +4592,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4621,9 +4694,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4642,7 +4712,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4685,6 +4755,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4703,9 +4776,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4733,6 +4815,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -5073,9 +5158,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5177,7 +5259,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5228,6 +5310,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5279,9 +5385,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5675,9 +5778,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -6041,6 +6141,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6769,6 +6875,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6778,6 +6887,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6799,6 +6911,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6817,6 +6932,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6826,6 +6944,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6844,9 +6965,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6865,12 +6992,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -7030,6 +7166,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -7039,9 +7178,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -7087,9 +7223,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -7120,6 +7253,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -7135,6 +7271,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7159,9 +7298,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7575,9 +7711,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7593,6 +7726,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8332,6 +8468,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9647,10 +9786,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9832,6 +9977,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10627,10 +10775,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10663,6 +10811,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10711,9 +10868,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10798,9 +10952,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10963,9 +11114,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11185,9 +11333,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11455,9 +11600,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11473,7 +11615,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11575,9 +11717,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11904,6 +12043,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11931,6 +12073,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11988,6 +12133,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12222,6 +12370,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12440,6 +12591,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12527,6 +12681,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12560,6 +12717,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12671,6 +12831,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12692,9 +12855,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12761,7 +12921,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13238,6 +13398,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13325,6 +13488,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13665,6 +13843,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13903,6 +14084,12 @@ msgstr[1] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13918,11 +14105,17 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
msgstr[1] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14528,6 +14721,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14858,22 +15057,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -15101,6 +15318,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15281,10 +15501,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15299,18 +15519,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15323,18 +15534,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15464,9 +15669,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15530,9 +15732,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15773,6 +15972,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15892,6 +16142,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15949,9 +16202,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16176,6 +16435,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16223,9 +16485,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16421,9 +16680,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16681,6 +16937,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16786,9 +17045,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16996,6 +17252,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17829,9 +18088,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17958,6 +18214,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -18009,6 +18271,9 @@ 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 ""
@@ -18057,9 +18322,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18615,9 +18877,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18627,6 +18886,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19389,12 +19651,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19464,6 +19720,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19642,9 +19901,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -20099,7 +20355,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20186,12 +20448,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21943,6 +22199,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21961,9 +22220,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -22021,7 +22277,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -22101,19 +22357,16 @@ msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
msgstr[1] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22251,12 +22504,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22278,6 +22537,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22503,6 +22774,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22797,6 +23083,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -23127,6 +23416,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -23166,9 +23458,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23545,9 +23843,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23701,6 +23996,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23851,9 +24155,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -24100,6 +24401,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24370,9 +24677,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24385,6 +24689,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24421,7 +24728,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24436,9 +24749,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24448,9 +24767,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24460,7 +24776,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24517,6 +24833,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24541,6 +24860,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24592,6 +24914,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24604,6 +24929,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25232,6 +25560,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25457,6 +25788,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25848,6 +26182,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -26007,6 +26344,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -26079,6 +26419,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26265,6 +26608,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26725,6 +27071,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26854,9 +27203,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26884,9 +27230,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26902,9 +27245,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -27138,7 +27478,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27473,6 +27813,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27482,6 +27825,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27503,6 +27849,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27596,9 +27945,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27623,9 +27969,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27859,12 +28202,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27910,12 +28247,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27937,12 +28268,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27985,15 +28310,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -28024,12 +28340,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -28048,9 +28358,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28224,9 +28531,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28595,12 +28899,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28646,6 +28959,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28792,6 +29111,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -29175,12 +29497,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29229,7 +29545,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29448,6 +29764,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29463,6 +29782,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29475,12 +29797,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29490,9 +29818,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30252,9 +30586,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30363,6 +30694,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30504,6 +30898,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30597,12 +30994,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -31179,6 +31582,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -31191,6 +31597,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31473,12 +31882,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31491,12 +31906,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31518,6 +31939,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31617,6 +32041,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31755,6 +32182,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31785,6 +32215,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31836,6 +32269,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32475,6 +32911,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32511,15 +32950,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32535,12 +32986,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32850,6 +33310,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32982,12 +33445,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -33081,9 +33538,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33247,6 +33701,9 @@ msgstr[1] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33256,6 +33713,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33712,6 +34172,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33726,11 +34189,6 @@ msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have faile
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33760,18 +34218,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33782,12 +34234,6 @@ msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 day
msgstr[0] ""
msgstr[1] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33830,21 +34276,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33860,9 +34297,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34234,6 +34668,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34463,6 +34900,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34501,6 +34941,9 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34529,7 +34972,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34738,6 +35181,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34866,9 +35312,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34917,6 +35369,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34952,6 +35407,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34991,12 +35449,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -35051,16 +35503,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -35168,10 +35626,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -35192,9 +35650,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -35204,9 +35668,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35357,9 +35827,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35766,10 +36233,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35889,6 +36359,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35991,10 +36464,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -36084,7 +36557,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -36102,6 +36575,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -36120,12 +36596,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -36147,6 +36632,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36276,6 +36764,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36333,6 +36824,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36450,9 +36944,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36465,6 +36965,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36528,9 +37031,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36669,10 +37169,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36684,28 +37184,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36924,9 +37424,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -37076,9 +37573,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37333,10 +37827,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37390,7 +37881,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37405,7 +37896,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37528,9 +38019,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37753,6 +38241,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37864,9 +38355,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38440,9 +38928,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38455,9 +38940,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38479,9 +38961,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -39001,9 +39480,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39261,6 +39746,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39351,6 +39839,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39435,6 +39926,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39456,15 +39950,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39486,9 +39974,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39507,6 +39992,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39618,16 +40106,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-msgstr[1] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39647,12 +40125,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39740,12 +40212,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -40200,6 +40666,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40395,9 +40864,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40428,7 +40894,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40485,9 +40951,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40839,9 +41302,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40875,6 +41335,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -41043,9 +41506,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -41106,6 +41566,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41322,13 +41785,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41457,9 +41923,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41478,6 +41941,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41848,9 +42314,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41956,6 +42419,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -42022,9 +42488,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -42046,18 +42536,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -42070,6 +42581,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -42220,9 +42749,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42543,6 +43069,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -43047,6 +43579,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -43149,6 +43687,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -43179,6 +43720,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -44229,9 +44773,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44693,6 +45234,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44711,6 +45255,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44846,7 +45393,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44888,6 +45435,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44903,12 +45453,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44948,6 +45510,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -45062,6 +45627,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -45089,9 +45660,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -45104,7 +45672,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -45116,12 +45684,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -45200,6 +45777,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -45209,7 +45789,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45525,6 +46105,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45575,9 +46161,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45608,10 +46209,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45623,6 +46227,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45644,6 +46251,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45662,6 +46272,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45757,6 +46370,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45793,6 +46409,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45838,9 +46460,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45942,6 +46561,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -46014,7 +46636,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -46038,6 +46660,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -46181,6 +46806,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -46244,7 +46872,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46412,9 +47040,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46526,6 +47151,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46644,16 +47272,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46742,6 +47367,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46811,9 +47439,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46825,9 +47450,6 @@ msgstr[1] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46887,6 +47509,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46896,9 +47524,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46979,6 +47604,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -47212,12 +47843,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47292,6 +47938,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47322,6 +47971,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47337,6 +47989,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47411,6 +48066,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47470,6 +48128,9 @@ msgstr[1] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47626,6 +48287,9 @@ msgid_plural "from %d jobs"
msgstr[0] ""
msgstr[1] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47726,12 +48390,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47753,6 +48423,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47777,12 +48450,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47939,9 +48618,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -48090,6 +48766,9 @@ 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 ""
@@ -48186,9 +48865,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -48252,6 +48928,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -48264,9 +48943,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -48285,9 +48970,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48336,9 +49018,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48357,17 +49036,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-msgstr[1] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48497,9 +49174,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48520,12 +49194,20 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+msgstr[1] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48681,6 +49363,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48817,6 +49502,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/vi_VN/gitlab.po b/locale/vi_VN/gitlab.po
index fa8acc10867..6f0d31d5c05 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: 2022-10-10 13:59\n"
+"PO-Revision-Date: 2022-11-13 09:20\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -129,6 +129,10 @@ msgid "%d additional user"
msgid_plural "%d additional users"
msgstr[0] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -209,18 +213,10 @@ msgid "%d epic"
msgid_plural "%d epics"
msgstr[0] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] ""
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -229,10 +225,6 @@ msgid "%d file"
msgid_plural "%d files"
msgstr[0] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] ""
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -431,6 +423,9 @@ msgid "%{bold_start}%{count}%{bold_end} opened merge request"
msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -482,6 +477,14 @@ msgstr[0] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -489,6 +492,10 @@ msgstr[0] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+
msgid "%{count} more"
msgstr ""
@@ -509,6 +516,10 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] ""
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -548,9 +559,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -761,12 +769,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -945,6 +947,9 @@ msgstr[0] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1079,9 +1084,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1139,6 +1141,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1176,6 +1181,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1434,6 +1442,9 @@ msgstr ""
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr ""
@@ -1497,9 +1508,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1578,9 +1586,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1788,6 +1793,9 @@ msgstr ""
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -1899,15 +1907,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -1977,9 +1979,6 @@ msgstr ""
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2352,6 +2351,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2535,6 +2540,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2571,15 +2594,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2628,6 +2663,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2673,6 +2711,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2811,9 +2861,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2838,6 +2897,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -2940,6 +3008,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr ""
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3132,7 +3203,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3177,7 +3248,7 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr ""
-msgid "AdminUsers|To confirm, type %{username}"
+msgid "AdminUsers|To confirm, type %{username}."
msgstr ""
msgid "AdminUsers|Unban user"
@@ -3240,7 +3311,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3288,6 +3359,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3798,7 +3872,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3813,6 +3887,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3849,9 +3926,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4098,6 +4172,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4282,9 +4359,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4384,9 +4458,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4489,9 +4560,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4510,7 +4578,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4551,6 +4619,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4569,9 +4640,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4599,6 +4679,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -4934,9 +5017,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5037,7 +5117,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5088,6 +5168,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5139,9 +5243,6 @@ msgstr ""
msgid "Assign labels"
msgstr ""
-msgid "Assign milestone"
-msgstr ""
-
msgid "Assign myself"
msgstr ""
@@ -5532,9 +5633,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -5898,6 +5996,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6622,6 +6726,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6631,6 +6738,9 @@ msgstr ""
msgid "Branch name"
msgstr ""
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6652,6 +6762,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6670,6 +6783,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6679,6 +6795,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6697,9 +6816,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6718,12 +6843,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -6883,6 +7017,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr ""
@@ -6892,9 +7029,6 @@ msgstr ""
msgid "Browse Files"
msgstr ""
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr ""
@@ -6940,9 +7074,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -6973,6 +7104,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -6988,6 +7122,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7012,9 +7149,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7427,9 +7561,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7445,6 +7576,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8182,6 +8316,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9495,10 +9632,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9679,6 +9822,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10471,10 +10617,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10507,6 +10653,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10555,9 +10710,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10642,9 +10794,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10807,9 +10956,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11029,9 +11175,6 @@ msgstr ""
msgid "Create new label"
msgstr ""
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11299,9 +11442,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11317,7 +11457,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11419,9 +11559,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11747,6 +11884,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11774,6 +11914,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11831,6 +11974,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12065,6 +12211,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12282,6 +12431,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12369,6 +12521,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12402,6 +12557,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12513,6 +12671,9 @@ msgstr ""
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12534,9 +12695,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12603,7 +12761,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13074,6 +13232,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13161,6 +13322,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13499,6 +13675,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13735,6 +13914,12 @@ msgstr[0] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13750,10 +13935,16 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14358,6 +14549,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14688,22 +14885,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr ""
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr ""
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr ""
+
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -14931,6 +15146,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15111,10 +15329,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15129,18 +15347,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15153,18 +15362,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15294,9 +15497,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15360,9 +15560,6 @@ msgstr ""
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15603,6 +15800,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15721,6 +15969,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15778,9 +16029,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16004,6 +16261,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16050,9 +16310,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16248,9 +16505,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16507,6 +16761,9 @@ msgstr ""
msgid "February"
msgstr ""
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16612,9 +16869,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr ""
@@ -16822,6 +17076,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17651,9 +17908,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17780,6 +18034,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -17831,6 +18091,9 @@ 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 ""
@@ -17879,9 +18142,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18437,9 +18697,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18449,6 +18706,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19211,12 +19471,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19286,6 +19540,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19462,9 +19719,6 @@ msgstr ""
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr ""
@@ -19917,7 +20171,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20004,12 +20264,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21757,6 +22011,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21775,9 +22032,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -21835,7 +22089,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -21914,19 +22168,16 @@ msgid "InviteMembersModal|The following member couldn't be invited"
msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22064,12 +22315,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22091,6 +22348,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22316,6 +22585,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22610,6 +22894,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -22940,6 +23227,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -22979,9 +23269,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23356,9 +23652,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23512,6 +23805,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23662,9 +23964,6 @@ msgstr ""
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -23905,6 +24204,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24175,9 +24480,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24190,6 +24492,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24226,7 +24531,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24241,9 +24552,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24253,9 +24570,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24265,7 +24579,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24322,6 +24636,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24346,6 +24663,9 @@ msgstr ""
msgid "March"
msgstr ""
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24397,6 +24717,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24409,6 +24732,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25035,6 +25361,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25260,6 +25589,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25649,6 +25981,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr ""
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -25808,6 +26143,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -25880,6 +26218,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26066,6 +26407,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26524,6 +26868,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26653,9 +27000,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26683,9 +27027,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26701,9 +27042,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -26936,7 +27274,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27267,6 +27605,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27276,6 +27617,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27297,6 +27641,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27390,9 +27737,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27417,9 +27761,6 @@ msgstr ""
msgid "October"
msgstr ""
-msgid "OfSearchInADropdown|Filter"
-msgstr ""
-
msgid "Off"
msgstr ""
@@ -27652,12 +27993,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27703,12 +28038,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27730,12 +28059,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27778,15 +28101,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -27817,12 +28131,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -27841,9 +28149,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28016,9 +28321,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28386,12 +28688,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28437,6 +28748,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28582,6 +28899,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -28964,12 +29284,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29018,7 +29332,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29237,6 +29551,9 @@ msgstr ""
msgid "PipelineSchedules|All"
msgstr ""
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29252,6 +29569,9 @@ msgstr ""
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr ""
@@ -29264,12 +29584,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr ""
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr ""
@@ -29279,9 +29605,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr ""
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr ""
@@ -30041,9 +30373,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30152,6 +30481,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30293,6 +30685,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30386,12 +30781,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -30968,6 +31369,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -30980,6 +31384,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31262,12 +31669,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31280,12 +31693,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31307,6 +31726,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31406,6 +31828,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31544,6 +31969,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31574,6 +32002,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31625,6 +32056,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32264,6 +32698,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32300,15 +32737,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32324,12 +32773,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32639,6 +33097,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32771,12 +33232,6 @@ msgstr ""
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -32870,9 +33325,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33034,6 +33486,9 @@ msgstr[0] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33043,6 +33498,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33499,6 +33957,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33512,10 +33973,6 @@ msgid "Reports|%{recentlyFailed} out of %{failed} failed tests has failed more t
msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days"
msgstr[0] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33544,18 +34001,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33564,12 +34015,6 @@ msgid "Reports|Failed %{count} time in %{base_branch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 days"
msgstr[0] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33612,21 +34057,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33642,9 +34078,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34012,6 +34445,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34239,6 +34675,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34276,6 +34715,9 @@ msgid "Runners|%d selected runner deleted"
msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34302,7 +34744,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34510,6 +34952,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34637,9 +35082,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34688,6 +35139,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34722,6 +35176,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34761,12 +35218,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -34821,16 +35272,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -34938,10 +35395,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -34962,9 +35419,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -34974,9 +35437,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35127,9 +35596,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35525,10 +35991,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35648,6 +36117,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35750,10 +36222,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -35843,7 +36315,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -35861,6 +36333,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -35879,12 +36354,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -35906,6 +36390,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36035,6 +36522,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36092,6 +36582,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36209,9 +36702,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36224,6 +36723,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36287,9 +36789,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr ""
-
msgid "Select all"
msgstr ""
@@ -36428,10 +36927,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36443,28 +36942,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36683,9 +37182,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -36834,9 +37330,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37090,10 +37583,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37147,7 +37637,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37162,7 +37652,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37285,9 +37775,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37510,6 +37997,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37621,9 +38111,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38197,9 +38684,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38212,9 +38696,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38236,9 +38717,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -38758,9 +39236,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39017,6 +39501,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr ""
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39107,6 +39594,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39191,6 +39681,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39212,15 +39705,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39242,9 +39729,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39263,6 +39747,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr ""
@@ -39374,14 +39861,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39399,12 +39878,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39492,12 +39965,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -39947,6 +40414,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40142,9 +40612,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40175,7 +40642,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40232,9 +40699,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40586,9 +41050,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40622,6 +41083,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -40790,9 +41254,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -40853,6 +41314,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41069,13 +41533,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41204,9 +41671,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41225,6 +41689,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41593,9 +42060,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41701,6 +42165,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -41767,9 +42234,33 @@ msgstr ""
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -41791,18 +42282,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -41815,6 +42327,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -41965,9 +42495,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42287,6 +42814,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -42791,6 +43324,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -42893,6 +43432,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -42923,6 +43465,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -43970,9 +44515,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44433,6 +44975,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44451,6 +44996,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44586,7 +45134,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44628,6 +45176,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44643,12 +45194,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44688,6 +45251,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -44802,6 +45368,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -44829,9 +45401,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -44844,7 +45413,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -44856,12 +45425,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -44940,6 +45518,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -44949,7 +45530,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45263,6 +45844,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45312,9 +45899,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45345,10 +45947,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45360,6 +45965,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45381,6 +45989,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45399,6 +46010,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45493,6 +46107,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45529,6 +46146,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45574,9 +46197,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45677,6 +46297,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -45749,7 +46372,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -45773,6 +46396,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -45915,6 +46541,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -45978,7 +46607,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46146,9 +46775,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46260,6 +46886,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46376,16 +47005,13 @@ msgstr ""
msgid "Your name"
msgstr ""
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46473,6 +47099,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46542,9 +47171,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46555,9 +47181,6 @@ msgstr[0] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46616,6 +47239,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46625,9 +47254,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46707,6 +47333,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -46936,12 +47568,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47015,6 +47662,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47045,6 +47695,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47060,6 +47713,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47133,6 +47789,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47191,6 +47850,9 @@ msgstr[0] ""
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47344,6 +48006,9 @@ msgid "from %d job"
msgid_plural "from %d jobs"
msgstr[0] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47442,12 +48107,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47469,6 +48140,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47493,12 +48167,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47652,9 +48332,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -47801,6 +48478,9 @@ 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 ""
@@ -47897,9 +48577,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -47963,6 +48640,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -47975,9 +48655,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -47996,9 +48682,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48047,9 +48730,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48068,16 +48748,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] ""
@@ -48204,9 +48883,6 @@ msgstr ""
msgid "remove weight"
msgstr ""
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48226,12 +48902,19 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48386,6 +49069,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48520,6 +49206,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/zh_CN/gitlab.po b/locale/zh_CN/gitlab.po
index 219649df2e3..3edcd3fe207 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: 2022-10-10 13:59\n"
+"PO-Revision-Date: 2022-11-13 09:21\n"
msgid " %{start} to %{end}"
msgstr "从%{start}到%{end}"
@@ -129,6 +129,10 @@ msgid "%d additional user"
msgid_plural "%d additional users"
msgstr[0] "%d 个其他用户"
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] "éœ€è¦ %d 个批准"
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%dä½æ ¸å‡†äºº"
@@ -209,18 +213,10 @@ msgid "%d epic"
msgid_plural "%d epics"
msgstr[0] "%d 个å²è¯—"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d个错误"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d 导出器"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%d个失败"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] "%d个失败的安全扫æ作业"
@@ -229,10 +225,6 @@ msgid "%d file"
msgid_plural "%d files"
msgstr[0] "%d 个文件"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d个修å¤çš„测试结果"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] "%d 个派生"
@@ -431,6 +423,9 @@ msgid "%{bold_start}%{count}%{bold_end} opened merge request"
msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] "%{bold_start}%{count}%{bold_end} 个开放中的åˆå¹¶è¯·æ±‚"
+msgid "%{chartTitle} no data series"
+msgstr "%{chartTitle} 没有数æ®ï¼"
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr "%{code_open}éšè—:%{code_close} éšè—在作业日志中。必须符åˆéšè—è¦æ±‚。"
@@ -482,6 +477,14 @@ msgstr[0] "%{count} 个è”系人"
msgid "%{count} files touched"
msgstr "已选择 %{count} 个文件"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] "%{count} 个群组"
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] "%{count} 个议题"
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "%{count} 个事项"
@@ -489,6 +492,10 @@ msgstr[0] "%{count} 个事项"
msgid "%{count} items per page"
msgstr "æ¯é¡µ%{count}æ¡"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] "%{count} 个åˆå¹¶è¯·æ±‚"
+
msgid "%{count} more"
msgstr "其余%{count}项"
@@ -509,6 +516,10 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] "%{count}ä½å‚与者"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] "%{count} 个项目"
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count}个相关的%{pluralized_subject}: %{links}"
@@ -548,9 +559,6 @@ msgstr "%{docs_link_start}什么是大文件存储?%{docs_link_end}"
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr "%{docs_link_start}什么是åŒé‡èº«ä»½éªŒè¯ï¼Ÿ%{docs_link_end}"
-msgid "%{due_date} (Past due)"
-msgstr "%{due_date} (已过期)"
-
msgid "%{duration}ms"
msgstr "%{duration}毫秒"
@@ -761,12 +769,6 @@ msgstr "%{name_with_link}的共享 Runner æµæ°´çº¿åˆ†é’Ÿæ•°å·²ç”¨å®Œï¼Œå…¶ä¸‹é¡
msgid "%{name} (Busy)"
msgstr "%{name} (忙碌中)"
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} åŒ…å« %{resultsString}"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} 找到了 %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr "%{name}已用于å¦ä¸€ä¸ªè¡¨æƒ…符å·"
@@ -945,6 +947,9 @@ msgstr[0] "%{strongStart}%{count}%{strongEnd} æ交"
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr "%{strongStart}æ示:%{strongEnd} 您也å¯ä»¥åœ¨æœ¬åœ°æ£€å‡ºåˆå¹¶è¯·æ±‚。%{linkStart}了解更多。%{linkEnd}"
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr "%{strong_open}%{group_name}%{strong_close} 的项目:"
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "%{strong_start}%{branch_count}%{strong_end} 个分支"
@@ -1032,7 +1037,7 @@ msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr "找到%{total}个警告: æ˜¾ç¤ºå‰ %{warningsDisplayed}"
msgid "%{type} must be a %{help_link}"
-msgstr ""
+msgstr "%{type} 必须是一个%{help_link}"
msgid "%{type} only supports %{name} name"
msgstr "%{type} åªæ”¯æŒ %{name} å称"
@@ -1079,9 +1084,6 @@ msgstr "%{user} 创建了一个议题:%{issue_link}"
msgid "%{value} is not included in the list"
msgstr "列表中ä¸åŒ…å«%{value}"
-msgid "%{value} s"
-msgstr "%{value}秒"
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} 耗时 %{time_spent_value}"
@@ -1139,6 +1141,9 @@ msgstr "'%{source}'ä¸æ˜¯ä¸€ä¸ªå¯¼å…¥æº"
msgid "'%{template_name}' is unknown or invalid"
msgstr "未知或无效的'%{template_name}' "
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr "'%{value}' ä¸æ´»åŠ¨çš„天数必须大于或等于 90"
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d 已关闭)"
@@ -1176,6 +1181,9 @@ msgstr "(如果您ä¸æƒ³æ›´æ”¹ï¼Œè¯·ç•™ç©º)"
msgid "(max size 15 MB)"
msgstr "(最大 15 MB)"
+msgid "(no user)"
+msgstr "(无用户)"
+
msgid "(optional)"
msgstr "(å¯é€‰)"
@@ -1434,6 +1442,9 @@ msgstr "您没有æƒé™è®¿é—®æ­¤é¡µé¢ã€‚"
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "请确认您访问的地å€æ­£ç¡®å¹¶ä¸”页é¢æœªè¢«ç§»åŠ¨ã€‚"
+msgid "404|Not found"
+msgstr "页é¢æœªæ‰¾åˆ°"
+
msgid "404|Page Not Found"
msgstr "页é¢æœªæ‰¾åˆ°"
@@ -1497,9 +1508,6 @@ msgstr "ç§å¯†è®®é¢˜ä¸èƒ½è¢«åŒ…å«åœ¨å·²å«æœ‰éžç§å¯†å­é¡¹çš„父项中。"
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr "ç§å¯†å·¥ä½œé¡¹ä¸èƒ½è¢«åŒ…å«åœ¨å·²å«æœ‰éžç§å¯†å­é¡¹çš„父项中。"
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "无法为空项目选择默认分支。"
-
msgid "A deleted user"
msgstr "已删除的用户"
@@ -1578,9 +1586,6 @@ msgstr "å为 %{token_name}的个人访问令牌已被撤销。"
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr "一个纯HTML站点,它使用NetLifyæ¥ä»£æ›¿Gitlabçš„CI/CD,但ä»ç„¶å…·æœ‰æ‰€æœ‰å…¶ä»–主è¦çš„Gitlab功能。"
-msgid "A platform value can be web, mob or app."
-msgstr "å¹³å°å€¼å¯ä»¥æ˜¯web, mob或app。"
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr "使用 Salesforce Developer å·¥å…·å¼€å‘ Salesforce App 的项目样æ¿"
@@ -1788,6 +1793,9 @@ msgstr "接å—æ¡æ¬¾"
msgid "Acceptable for use in this project"
msgstr "å¯æŽ¥å—用于此项目"
+msgid "Access Denied"
+msgstr "æ‹’ç»è®¿é—®"
+
msgid "Access Git repositories or the API."
msgstr "访问 Git 仓库或 API。"
@@ -1899,15 +1907,9 @@ msgstr "当您通过电å­é‚®ä»¶åˆ›å»ºä¸€ä¸ªæ–°è®®é¢˜æ—¶ï¼Œæ‚¨çš„接收电å­é‚®
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr "当仓库é™æ€å¯¹è±¡(例如归档或åšå®¢)从外部存储æœåŠ¡æ—¶ï¼Œæ‚¨çš„é™æ€å¯¹è±¡ä»¤ç‰Œä¼šéªŒè¯æ‚¨ã€‚"
-msgid "AccessibilityReport|Learn more"
-msgstr "了解更多"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "消æ¯ï¼š %{message}"
-msgid "AccessibilityReport|New"
-msgstr "新增"
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr "æ— éšœç¢æ€§æ‰«æå‘现以下类型的错误: %{code}"
@@ -1977,9 +1979,6 @@ msgstr "å¯ç”¨"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr "å¯ç”¨%{accessTokenTypePlural} (%{totalAccessTokens})"
-msgid "Active %{type} (%{token_length})"
-msgstr "有效的%{type}(%{token_length})"
-
msgid "Active Sessions"
msgstr "活动会è¯"
@@ -2352,6 +2351,12 @@ msgstr "添加%{labels}%{label_text}。"
msgid "Adds a Zoom meeting."
msgstr "添加 Zoom 会议。"
+msgid "Adds a resource link"
+msgstr "添加一个资æºé“¾æŽ¥"
+
+msgid "Adds a resource link for this incident."
+msgstr "为此事件添加一个资æºé“¾æŽ¥ã€‚"
+
msgid "Adds a timeline event to incident."
msgstr "添加时间线事件。"
@@ -2535,6 +2540,24 @@ msgstr "您å³å°†åœæ­¢æ‰€æœ‰ä½œä¸šï¼Œè¿™ä¼šä¸­æ–­å¹¶ç»“æŸæ‰€æœ‰æ­£åœ¨è¿è¡Œçš„
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr "加载统计数æ®æ—¶å‡ºé”™ã€‚请å†è¯•ä¸€æ¬¡"
+msgid "AdminEmail|Body"
+msgstr "正文"
+
+msgid "AdminEmail|Body is required."
+msgstr "必须有正文。"
+
+msgid "AdminEmail|Recipient group or project"
+msgstr "收件群组或项目"
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr "必须有收件群组或项目。"
+
+msgid "AdminEmail|Subject"
+msgstr "主题"
+
+msgid "AdminEmail|Subject is required."
+msgstr "必须有主题"
+
msgid "AdminLabels|Define your default set of project labels"
msgstr "定义项目标记的默认集"
@@ -2571,15 +2594,27 @@ msgstr "Auto DevOps 域"
msgid "AdminSettings|CI/CD limits"
msgstr "CI/CD é™åˆ¶"
+msgid "AdminSettings|Clickhouse URL"
+msgstr "Clickhouse URL"
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr "é…ç½® Let's Encrypt"
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr "é…置用户在给定时间内å¯ä»¥ä¸‹è½½çš„仓库数é‡é™åˆ¶ã€‚"
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr "é…置何时自动删除ä¸æ´»è·ƒçš„项目。%{linkStart}什么是ä¸æ´»è·ƒçš„项目?%{linkEnd}"
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr "删除ä¸æ´»è·ƒçš„项目"
@@ -2628,6 +2663,9 @@ msgstr "å¯ç”¨ kuromoji 自定义分æžå™¨ï¼šæœç´¢"
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr "å¯ç”¨æµæ°´çº¿å»ºè®®æ示"
+msgid "AdminSettings|Enable product analytics"
+msgstr "å¯ç”¨äº§å“分æž"
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr "为新项目å¯ç”¨å…±äº«Runner"
@@ -2673,6 +2711,18 @@ msgstr "删除ä¸æ´»è·ƒçš„项目"
msgid "AdminSettings|Instance runners expiration"
msgstr "实例 runners 过期"
+msgid "AdminSettings|Jitsu administrator email"
+msgstr "Jitsu管ç†å‘˜ç”µå­é‚®ä»¶"
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr "Jitsu管ç†å‘˜å¯†ç "
+
+msgid "AdminSettings|Jitsu host"
+msgstr "Jitsu主机"
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr "Jitsu项目 ID"
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr "在最新æˆåŠŸçš„æµæ°´çº¿ä¸­ï¼Œä¿ç•™æ‰€æœ‰ä½œä¸šçš„最新产物"
@@ -2811,9 +2861,18 @@ msgstr "设置必须大于 0。"
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr "Pages é™æ€ç«™ç‚¹çš„大å°å’ŒåŸŸå设置。"
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr "Jitsu中的项目ID,此项目包å«æ‰€æœ‰åˆ†æžå®žä¾‹ã€‚"
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr "在所有项目中,自动评审应用和自动部署阶段使用的默认域å。"
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr "存储了æ¯ä¸ªé¡¹ç›®ä¸­æœ€è¿‘æˆåŠŸå®Œæˆçš„æµæ°´çº¿ä¸­æ‰€æœ‰ä½œä¸šçš„最新产物,并且ä¸ä¼šè¿‡æœŸã€‚"
@@ -2838,6 +2897,15 @@ msgstr "当å‰æ´»åŠ¨æµæ°´çº¿ä¸­çš„作业总数"
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr "以 IMA 凭æ®ä½¿ç”¨ AWS çš„ OpenSearch æœåŠ¡"
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr "用户和群组在被添加到群组或项目之å‰å¿…须确认接å—邀请。"
@@ -2940,6 +3008,9 @@ msgstr "管ç†å‘˜"
msgid "AdminUsers|Admins"
msgstr "管ç†å‘˜"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr "批准"
@@ -3132,8 +3203,8 @@ msgstr "将生æˆé‡ç½®é“¾æŽ¥å¹¶å‘é€ç»™ç”¨æˆ·ã€‚用户将被迫在首次登录
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr "æ¢å¤ç”¨æˆ·è®¿é—®è´¦æˆ·ï¼ŒåŒ…括网页ã€Gitå’ŒAPI。"
-msgid "AdminUsers|Search by name, email or username"
-msgstr "按åå­—ã€ç”µå­é‚®ä»¶æˆ–用户åæœç´¢"
+msgid "AdminUsers|Search by name, email, or username"
+msgstr "通过å称ã€ç”µå­é‚®ä»¶æˆ–用户åæœç´¢"
msgid "AdminUsers|Search users"
msgstr "æœç´¢ç”¨æˆ·"
@@ -3177,8 +3248,8 @@ msgstr "此用户将ä¸ä¼šæ”¶åˆ°ä»»ä½•é€šçŸ¥"
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "请输入 %{projectName} æ¥ç¡®è®¤"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "请输入 %{username} æ¥ç¡®è®¤"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr "è¦ç¡®è®¤ï¼Œè¯·è¾“å…¥ %{username}."
msgid "AdminUsers|Unban user"
msgstr "解ç¦ç”¨æˆ·"
@@ -3240,8 +3311,8 @@ msgstr "无项目"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr "您å³å°†æ°¸ä¹…删除用户 %{username}。该用户的议题ã€åˆå¹¶è¯·æ±‚以åŠç›¸å…³çš„群组将被转移到系统的“Ghost用户â€ã€‚为é¿å…æ•°æ®ä¸¢å¤±ï¼Œå»ºè®®æ‚¨ä½¿ç”¨ %{strongStart}ç¦ç”¨ç”¨æˆ·%{strongEnd} 功能。一旦您 %{strongStart}删除用户%{strongEnd},将无法撤消或æ¢å¤ã€‚"
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
-msgstr "您å³å°†æ°¸ä¹…删除用户 %{username}。此æ“作会删除该用户的所有议题ã€åˆå¹¶è¯·æ±‚以åŠç›¸å…³çš„群组。为é¿å…æ•°æ®ä¸¢å¤±ï¼Œå»ºè®®æ‚¨ä½¿ç”¨ %{strongStart}ç¦ç”¨ç”¨æˆ·%{strongEnd} 功能。一旦您 %{strongStart}删除用户%{strongEnd},将无法撤消或æ¢å¤ã€‚"
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
+msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
msgstr "如果需è¦ï¼Œæ‚¨éšæ—¶å¯ä»¥ç¦ç”¨ä»–们的å¸æˆ·ã€‚"
@@ -3288,6 +3359,9 @@ msgstr "管ç†"
msgid "Administrators"
msgstr "管ç†å‘˜"
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr "新加入的用户必须ç»è¿‡ç³»ç»Ÿç®¡ç†å‘˜å®¡æ ¸ä¸Žæ‰¹å‡†ã€‚了解更多关于%{help_link_start}用户数å°é¡¶%{help_link_end}çš„ä¿¡æ¯ã€‚"
@@ -3331,19 +3405,19 @@ msgid "AdvancedSearch|Elasticsearch version not compatible"
msgstr "Elasticsearch 版本ä¸å…¼å®¹"
msgid "AdvancedSearch|Introduced in GitLab 13.1, before using %{reindexing_link_start}zero-downtime reindexing%{link_end} and %{migrations_link_start}Advanced Search migrations%{link_end}, you need to %{recreate_link_start}recreate your index%{link_end}."
-msgstr ""
+msgstr "从 13.1 版本起,您需è¦å…ˆ%{recreate_link_start}é‡å»ºç´¢å¼•%{link_end}æ‰èƒ½æ‰§è¡Œ%{reindexing_link_start}ä¸åœæœºé‡ç´¢å¼•%{link_end}å’Œ%{migrations_link_start}高级æœç´¢è¿ç§»%{link_end}。"
msgid "AdvancedSearch|Pause indexing and upgrade Elasticsearch to a supported version."
-msgstr ""
+msgstr "æš‚åœç´¢å¼•å¹¶å°† Elasticsearch å‡çº§åˆ°å—支æŒçš„版本。"
msgid "AdvancedSearch|Reindex recommended"
-msgstr ""
+msgstr "推èé‡æ–°ç´¢å¼•"
msgid "AdvancedSearch|Reindex required"
msgstr "需è¦é‡æ–°ç´¢å¼•"
msgid "AdvancedSearch|You are using outdated code search mappings. To improve code search quality, we recommend you use %{reindexing_link_start}zero-downtime reindexing%{link_end} or %{recreate_link_start}re-create your index%{link_end}."
-msgstr ""
+msgstr "您正在使用过时的代ç æœç´¢æ˜ å°„。 为了æ高代ç æœç´¢è´¨é‡ï¼Œæˆ‘们建议您使用%{reindexing_link_start}ä¸åœæœºé‡ç´¢å¼•%{link_end},或%{recreate_link_start}é‡æ–°åˆ›å»ºæ‚¨çš„索引%{link_end}。"
msgid "After a successful password update you will be redirected to login screen."
msgstr "密ç æ›´æ–°æˆåŠŸåŽï¼Œæ‚¨å°†è¢«é‡å®šå‘到登录页é¢ã€‚"
@@ -3798,8 +3872,8 @@ msgstr "所有的用户都必须具有å称。"
msgid "All users with matching cards"
msgstr "所有具有匹é…å¡ç‰‡çš„用户"
-msgid "Allow \"%{group_name}\" to sign you in"
-msgstr "å…许“%{group_name}â€ä»¥æ‚¨çš„身份登录"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr "å…许登录到 %{strongOpen}%{group_name}%{strongClose} å—?"
msgid "Allow access to members of the following group"
msgstr "å…许访问以下群组的æˆå‘˜"
@@ -3813,6 +3887,9 @@ msgstr "å…许å¯ä»¥åˆå¹¶åˆ°ç›®æ ‡åˆ†æ”¯çš„æˆå‘˜æ交。%{link_start}关于æ­
msgid "Allow group owners to manage LDAP-related settings"
msgstr "å…许群组所有者管ç†LDAP相关的设置"
+msgid "Allow new users to create top-level groups"
+msgstr "å…许新用户创建顶级群组"
+
msgid "Allow non-administrators access to the performance bar"
msgstr "å…许éžç®¡ç†å‘˜è®¿é—®æ€§èƒ½æ "
@@ -3849,9 +3926,6 @@ msgstr "å…许此密钥推é€åˆ°è¿™ä¸ªä»“库"
msgid "Allow use of licensed EE features"
msgstr "å…许使用许å¯çš„EE功能"
-msgid "Allow users to create top-level groups"
-msgstr "å…许用户创建顶级群组"
-
msgid "Allow users to dismiss the broadcast message"
msgstr "å…许用户关闭广播消æ¯"
@@ -4098,6 +4172,9 @@ msgstr "获å–标签时å‘生错误,请é‡è¯•æœç´¢ã€‚"
msgid "An error occurred while fetching terraform reports."
msgstr "获å–terraform报告时å‘生错误。"
+msgid "An error occurred while fetching the health status."
+msgstr "获å–å¥åº·çŠ¶æ€æ—¶å‡ºé”™ã€‚"
+
msgid "An error occurred while fetching the job log."
msgstr "获å–作业日志时å‘生错误。"
@@ -4282,9 +4359,6 @@ msgstr "触å‘作业时å‘生错误。"
msgid "An error occurred while trying to follow this user, please try again."
msgstr "试图关注这个用户时出错,请é‡è¯•ã€‚"
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr "å°è¯•ç”ŸæˆæŠ¥å‘Šæ—¶å‡ºé”™ã€‚请ç¨åŽå†è¯•ã€‚"
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr "å°è¯•æ¸²æŸ“内容编辑器时å‘生错误,请é‡è¯•ã€‚"
@@ -4384,9 +4458,6 @@ msgstr "å‘生未知错误。"
msgid "Analytics"
msgstr "分æž"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "分æžä¾èµ–项查找已知æ¼æ´ž."
@@ -4489,9 +4560,6 @@ msgstr "应用程åºè®¾ç½®å·²æˆåŠŸä¿å­˜ã€‚"
msgid "Application settings update failed"
msgstr "应用程åºè®¾ç½®æ›´æ–°å¤±è´¥"
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr "应用已å¸è½½ä½†æœªèƒ½æ¸…除: %{error_message}"
-
msgid "Application was successfully destroyed."
msgstr "应用程åºå·²æˆåŠŸåˆ é™¤ã€‚"
@@ -4510,8 +4578,8 @@ msgstr "添加链接到Grafana"
msgid "ApplicationSettings|After sign-up text"
msgstr "注册åŽæ–‡æœ¬"
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
-msgstr "一旦实例达到用户上é™ï¼Œä»»ä½•æ·»åŠ æˆ–请求访问的用户都必须得到管ç†å‘˜çš„批准。将该字段留空以表示无é™åˆ¶ã€‚"
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
+msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
msgstr "å…许注册的域"
@@ -4551,6 +4619,9 @@ msgstr "æ‹’ç»åå•æ–‡ä»¶"
msgid "ApplicationSettings|Domain denylist"
msgstr "域å黑åå•"
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr "电å­é‚®ä»¶ç¡®è®¤è®¾ç½®"
+
msgid "ApplicationSettings|Email restrictions"
msgstr "邮箱黑åå•"
@@ -4569,9 +4640,18 @@ msgstr "为注册å¯ç”¨ç”µå­é‚®ä»¶é™åˆ¶"
msgid "ApplicationSettings|Enter denylist manually"
msgstr "手动输入拒ç»åˆ—表"
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr "最å°å¯†ç é•¿åº¦ï¼ˆå­—符数)"
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr "关闭"
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr "åªæœ‰ç”µå­é‚®ä»¶åœ°å€ä¸Žè¿™äº›åŸŸå匹é…的用户æ‰èƒ½æ³¨å†Œã€‚å…许使用通é…符。对多个æ¡ç›®ä½¿ç”¨å•ç‹¬çš„行。例如:domain.com, *.domain.com"
@@ -4599,6 +4679,9 @@ msgstr "ä¿å­˜æ›´æ”¹"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
msgstr "请å‚阅%{linkStart}密ç ç­–略指å—%{linkEnd}。"
+msgid "ApplicationSettings|Send a confirmation email during sign up. New users must confirm their email address before they can log in."
+msgstr "注册时å‘é€ä¸€å°ç¡®è®¤é‚®ä»¶ã€‚新用户在登录å‰å¿…须确认他们的电å­é‚®ä»¶åœ°å€ã€‚"
+
msgid "ApplicationSettings|Send confirmation email on sign-up"
msgstr "注册时å‘é€ç¡®è®¤é‚®ä»¶"
@@ -4934,9 +5017,6 @@ msgstr "您确定è¦å…³é—­æ­¤è¢«å—阻的议题å—?"
msgid "Are you sure you want to delete %{name}?"
msgstr "您确定è¦åˆ é™¤%{name}å—?"
-msgid "Are you sure you want to delete these artifacts?"
-msgstr "确定è¦åˆ é™¤è¿™äº›äº§ç‰©å—?"
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr "您确定è¦åˆ é™¤%{commentType}å—?"
@@ -5037,8 +5117,8 @@ msgstr "确定è¦é‡è¯•æ­¤è¿ç§»å—?"
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr "您确定è¦æ’¤é”€%{accessTokenType}嘛?此æ“作ä¸èƒ½æ’¤é”€ã€‚"
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
-msgstr "您确定è¦æ’¤é”€æ­¤%{type}å—?此æ“作ä¸å¯é€†ã€‚"
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
+msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr "您确定è¦æ’¤æ¶ˆæ­¤ä¸ªäººè®¿é—®ä»¤ç‰Œå—?此æ“作无法撤消。"
@@ -5088,6 +5168,30 @@ msgstr "产物已æˆåŠŸåˆ é™¤ã€‚"
msgid "Artifacts"
msgstr "产物"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr "删除产物时出错"
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr "检索作业产物时出错"
+
+msgid "Artifacts|Artifacts"
+msgstr "产物"
+
+msgid "Artifacts|Browse"
+msgstr "æµè§ˆ"
+
+msgid "Artifacts|Delete %{name}?"
+msgstr "删除 %{name} å—?"
+
+msgid "Artifacts|Delete artifact"
+msgstr "删除产物"
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr "此产物将被永久删除。任何从由此产物所生æˆçš„报告都将被清空。"
+
+msgid "Artifacts|Total artifacts size"
+msgstr "产物总大å°"
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr "éšç€æˆ‘们继续为SAST添加更多的功能,我们éžå¸¸æ¬¢è¿Žæ‚¨é€šè¿‡%{linkStart}此议题%{linkEnd}为SASTé…置功能æä¾›å馈。"
@@ -5139,9 +5243,6 @@ msgstr "分é…自定义颜色,如FF0000"
msgid "Assign labels"
msgstr "添加标记"
-msgid "Assign milestone"
-msgstr "分é…里程碑"
-
msgid "Assign myself"
msgstr "指派给自己"
@@ -5532,9 +5633,6 @@ msgstr "自动åœæ­¢å·²æˆåŠŸå–消。"
msgid "Auto-cancel redundant pipelines"
msgstr "自动å–消多余的æµæ°´çº¿"
-msgid "Auto-close referenced issues on default branch"
-msgstr "自动关闭默认分支上的引用议题"
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr "æ ¹æ®æŒç»­çš„集æˆå’Œäº¤ä»˜é…置,%{auto_devops_start}自动构建,测试和部署%{auto_devops_end}您的应用程åºã€‚%{quickstart_start}我该如何开始?%{quickstart_end}"
@@ -5898,6 +5996,12 @@ msgstr "请注æ„,更改项目的命å空间å¯èƒ½ä¼šäº§ç”Ÿéžé¢„期的副作
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "请注æ„,é‡å‘½å项目的仓库å¯èƒ½ä¼šäº§ç”Ÿéžé¢„期的副作用。"
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr "在å¯ç”¨æ­¤é›†æˆä¹‹å‰ï¼Œè¯·åœ¨ Google Chat 中为您希望从该项目接收通知的房间创建一个 webhook。 %{docs_link}"
@@ -6539,10 +6643,10 @@ msgid "Boards|Move card"
msgstr "移动å¡ç‰‡"
msgid "Boards|Move to end of list"
-msgstr "移动至列表末尾"
+msgstr "移动至列表底部"
msgid "Boards|Move to start of list"
-msgstr "移动至列表开头"
+msgstr "移动至列表顶部"
msgid "Boards|New board"
msgstr "新建看æ¿"
@@ -6622,6 +6726,9 @@ msgstr "分支已ç»å­˜åœ¨"
msgid "Branch changed"
msgstr "分支已更改"
+msgid "Branch defaults"
+msgstr "分支默认值"
+
msgid "Branch has been updated since the merge was requested."
msgstr "自请求åˆå¹¶ä»¥æ¥ï¼Œåˆ†æ”¯å·²æ›´æ–°ã€‚"
@@ -6631,6 +6738,9 @@ msgstr "分支已被采用"
msgid "Branch name"
msgstr "分支å称"
+msgid "Branch name template"
+msgstr "分支å称模æ¿"
+
msgid "Branch not loaded - %{branchId}"
msgstr "分支未载入 - %{branchId}"
@@ -6638,58 +6748,67 @@ msgid "Branch rules"
msgstr "分支规则"
msgid "BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or production/ are supported"
-msgstr ""
+msgstr "%{linkStart}支æŒé€šé…符%{linkEnd} ,例如 *-stable 或 production/"
msgid "BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or production/* are supported."
msgstr "%{linkStart}支æŒé€šé…符%{linkEnd} ,例如 *-stable 或 production/*。"
msgid "BranchRules|All branches"
-msgstr ""
+msgstr "所有分支"
msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
+msgstr "å…许所有具有推é€è®¿é—®æƒé™çš„用户强制推é€ã€‚"
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr "å…许所有具有推é€è®¿é—®æƒé™çš„用户%{linkStart}强制推é€%{linkEnd}。"
+msgid "BranchRules|Allowed to force push"
+msgstr "å…许强制推é€"
+
msgid "BranchRules|Allowed to merge"
msgstr "å…许åˆå¹¶"
msgid "BranchRules|Allowed to merge (%{total})"
-msgstr ""
+msgstr "å…许åˆå¹¶ (%{total})"
msgid "BranchRules|Allowed to push"
msgstr "å…许推é€"
msgid "BranchRules|Allowed to push (%{total})"
-msgstr ""
+msgstr "å…许推é€(%{total})"
msgid "BranchRules|An error occurred while fetching branches."
msgstr "获å–分支时å‘生错误。"
msgid "BranchRules|Approvals"
+msgstr "批准"
+
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
msgid "BranchRules|Branch"
msgstr "分支"
msgid "BranchRules|Branch name or pattern"
-msgstr ""
+msgstr "分支å称或样å¼"
msgid "BranchRules|Branch rules details"
msgstr "分支规则详情"
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr "创建通é…符:%{searchTerm}"
msgid "BranchRules|Details"
-msgstr ""
+msgstr "详情"
msgid "BranchRules|Force push"
-msgstr ""
+msgstr "强制推é€"
msgid "BranchRules|Force push is not allowed."
-msgstr ""
+msgstr "ä¸å…许强制推é€ã€‚"
msgid "BranchRules|Groups"
msgstr "群组"
@@ -6697,17 +6816,23 @@ msgstr "群组"
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr "ä¿æŒç¨³å®šåˆ†æ”¯çš„安全并强制开å‘者使用åˆå¹¶è¯·æ±‚。%{linkStart}什么是å—ä¿æŠ¤çš„分支?%{linkEnd}"
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr "在åˆå¹¶è¯·æ±‚批准中管ç†"
+
msgid "BranchRules|Manage in Protected Branches"
-msgstr ""
+msgstr "在å—ä¿æŠ¤çš„分支中管ç†"
+
+msgid "BranchRules|Manage in Status checks"
+msgstr "在状æ€æ£€æŸ¥ä¸­ç®¡ç†"
msgid "BranchRules|No data to display"
-msgstr ""
+msgstr "没有è¦æ˜¾ç¤ºçš„æ•°æ®"
msgid "BranchRules|No matching results"
msgstr "没有匹é…的结果"
msgid "BranchRules|Protect branch"
-msgstr ""
+msgstr "ä¿æŠ¤åˆ†æ”¯"
msgid "BranchRules|Protections"
msgstr "ä¿æŠ¤"
@@ -6718,11 +6843,20 @@ msgstr "æ‹’ç»ä»£ç æŽ¨é€æ›´æ”¹ CODEOWNERS 文件中列出的文件。"
msgid "BranchRules|Require approval from code owners."
msgstr "需è¦ä»£ç æ‰€æœ‰è€…的核准。"
+msgid "BranchRules|Required approvals (%{total})"
+msgstr "需è¦æ‰¹å‡†ï¼ˆ%{total} 个)"
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr "éœ€è¦ CODEOWNERS 批准"
+
msgid "BranchRules|Roles"
msgstr "角色"
msgid "BranchRules|Status checks"
-msgstr ""
+msgstr "状æ€æ£€æŸ¥"
+
+msgid "BranchRules|Status checks (%{total})"
+msgstr "状æ€æ£€æŸ¥ (%{total})"
msgid "BranchRules|Target Branch"
msgstr "目标分支"
@@ -6883,6 +7017,9 @@ msgstr "广播消æ¯å·²æˆåŠŸæ›´æ–°ã€‚"
msgid "Broadcast Messages"
msgstr "广播消æ¯"
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr "删除此消æ¯æ—¶å‡ºçŽ°é—®é¢˜ï¼Œè¯·ç¨åŽå†è¯•ã€‚"
+
msgid "Browse Directory"
msgstr "æµè§ˆç›®å½•"
@@ -6892,9 +7029,6 @@ msgstr "æµè§ˆæ–‡ä»¶"
msgid "Browse Files"
msgstr "æµè§ˆæ–‡ä»¶"
-msgid "Browse artifacts"
-msgstr "æµè§ˆäº§ç‰©"
-
msgid "Browse files"
msgstr "æµè§ˆæ–‡ä»¶"
@@ -6940,9 +7074,6 @@ msgstr "按æºç¾¤ç»„过滤"
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr "以下数æ®å°†ä¸ä¼šè¢«è¿ç§»ï¼š%{bullets} 如果您在è¿ç§»ä¸­éœ€è¦æ­¤æ•°æ®ï¼Œè¯· %{host} 系统管ç†å‘˜å‡çº§ GitLab"
-msgid "BulkImport|From source group"
-msgstr "从æºç¾¤ç»„"
-
msgid "BulkImport|Group import history"
msgstr "群组导入历å²"
@@ -6973,6 +7104,9 @@ msgstr "å称已存在。"
msgid "BulkImport|Name already used as a target for another group."
msgstr "å称已用作å¦ä¸€ç»„的目标。"
+msgid "BulkImport|New group"
+msgstr "新建群组"
+
msgid "BulkImport|No additional information provided."
msgstr "未æ供其它信æ¯ã€‚"
@@ -6988,6 +7122,9 @@ msgstr "没有父级"
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr "åªæœ‰æ‚¨æœ‰ %{role} 角色的群组æ‰è¢«åˆ—为您å¯ä»¥å¯¼å…¥çš„群组。"
+msgid "BulkImport|Path of the new group."
+msgstr "新群组的路径。"
+
msgid "BulkImport|Project import history"
msgstr "项目导入历å²"
@@ -7012,9 +7149,6 @@ msgstr "æºç¾¤ç»„"
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr "模版/基于文件导入/GitLab è¿ç§»"
-msgid "BulkImport|To new group"
-msgstr "到新群组"
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr "更新具有实时å˜æ›´çš„导入状æ€å¤±è´¥"
@@ -7427,9 +7561,6 @@ msgstr "å–消预览"
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr "无法将机密å²è¯—分é…ç»™éžæœºå¯†è®®é¢˜ã€‚请将此议题设置机密并é‡è¯•"
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr "无法指派与å²è¯—ä¸å±žäºŽåŒä¸€ç¾¤ç»„(或下级)的议题。"
-
msgid "Cannot be merged automatically"
msgstr "无法自动åˆå¹¶"
@@ -7445,6 +7576,9 @@ msgstr "无法创建滥用报告。此用户已被ç¦ç”¨ã€‚"
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr "ä¸èƒ½åˆ é™¤å®‰å…¨ç­–略中引用的 %{profile_name}"
+msgid "Cannot delete the default framework"
+msgstr "无法删除默认框架"
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr "ä¸èƒ½åŒæ—¶è¿è¡Œå¤šä¸ªJira导入"
@@ -8182,6 +8316,9 @@ msgstr "é”®"
msgid "CiVariables|Masked"
msgstr "éšè—"
+msgid "CiVariables|Options"
+msgstr "选项"
+
msgid "CiVariables|Protected"
msgstr "å—ä¿æŠ¤"
@@ -8382,7 +8519,7 @@ msgid "Close %{issueType}"
msgstr "关闭%{issueType}"
msgid "Close %{noteable}"
-msgstr "关闭 %{noteable}"
+msgstr "关闭%{noteable}"
msgid "Close %{tabname}"
msgstr "关闭%{tabname}"
@@ -9495,11 +9632,17 @@ msgstr "对%{startLine}到%{endLine}行的评论"
msgid "Comment/Reply (quoting selected text)"
msgstr "评论/å›žå¤ (引用选定的文本)"
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
-msgstr "ç›®å‰ä¸æ”¯æŒè¯„论替æ¢ç¬¦å·é“¾æŽ¥çš„文件或被符å·é“¾æŽ¥çš„文件替æ¢çš„文件。"
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
-msgstr "ç›®å‰ä¸æ”¯æŒè¯„论符å·é“¾æŽ¥ï¼Œè¿™äº›é“¾æŽ¥æ›¿æ¢æ–‡ä»¶æˆ–被文件替æ¢ã€‚"
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr ""
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
+msgstr "ä¸æ”¯æŒè¯„论此行"
msgid "Comments"
msgstr "评论"
@@ -9679,6 +9822,9 @@ msgstr "完æˆéªŒè¯æ–¹å¯ç™»å½•ã€‚"
msgid "Complete verification to sign up."
msgstr "完æˆéªŒè¯æ–¹å¯æ³¨å†Œã€‚"
+msgid "Complete with errors"
+msgstr "已完æˆï¼Œä½†æ˜¯æœ‰é”™è¯¯"
+
msgid "Completed"
msgstr "已完æˆ"
@@ -9749,7 +9895,7 @@ msgid "ComplianceFrameworks|No compliance frameworks are set up yet"
msgstr "尚未设置åˆè§„框架"
msgid "ComplianceFrameworks|Required format: %{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}. %{linkStart}What is a compliance pipeline configuration?%{linkEnd}"
-msgstr ""
+msgstr "所需格å¼ï¼š%{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}。%{linkStart}什么是åˆè§„æµæ°´çº¿é…置?%{linkEnd}"
msgid "ComplianceFrameworks|Unable to save this compliance framework. Please try again"
msgstr "无法ä¿å­˜æ­¤åˆè§„性框架。请é‡è¯•"
@@ -10067,7 +10213,7 @@ msgid "Container Registry"
msgstr "容器镜åƒåº“"
msgid "Container Repository"
-msgstr ""
+msgstr "容器仓库"
msgid "Container Scanning"
msgstr "容器扫æ"
@@ -10471,11 +10617,11 @@ msgstr "贡献"
msgid "Contribution Analytics"
msgstr "贡献度分æž"
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
-msgstr "创建%{created_count}个,关闭%{closed_count}个。"
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
+msgstr "%{created} 个已创建,%{closed} 个已关闭。"
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
-msgstr "已创建%{created_count}个,已åˆå¹¶%{merged_count}个,已关闭%{closed_count}个。"
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
+msgstr "%{created} 个已创建, %{merged} 个已åˆå¹¶ï¼Œ%{closed} 个已关闭。"
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr "%{pushes} 个推é€ï¼Œè¶…过 %{contributors} 个贡献者的 %{commits} 次æ交"
@@ -10507,6 +10653,15 @@ msgstr "在选定的时间段内没有åˆå¹¶è¯·æ±‚。"
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr "在选定的时间段内没有推é€ã€‚"
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr "给定的日期范围大于 31 天"
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr "%{calendar_date}的贡献"
@@ -10555,9 +10710,6 @@ msgstr "å¤åˆ¶ %{name}"
msgid "Copy %{protocol} clone URL"
msgstr "å¤åˆ¶ %{protocol} 克隆URL"
-msgid "Copy %{type}"
-msgstr "å¤åˆ¶%{type}"
-
msgid "Copy ID"
msgstr "å¤åˆ¶ID"
@@ -10642,9 +10794,6 @@ msgstr "å¤åˆ¶å¯†ç "
msgid "Copy source branch name"
msgstr "å¤åˆ¶æºåˆ†æ”¯å称"
-msgid "Copy the code below to implement tracking in your application:"
-msgstr "å¤åˆ¶ä¸‹é¢çš„代ç æ¥å®žçŽ°æ‚¨çš„应用程åºä¸­çš„跟踪:"
-
msgid "Copy this registration token."
msgstr "å¤åˆ¶æ­¤æ³¨å†Œä»¤ç‰Œ."
@@ -10807,9 +10956,6 @@ msgstr "无法加载使用计数。请刷新页é¢é‡è¯•ã€‚"
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr "无法将 %{user} 从 %{group}中移除。无法移除最åŽä¸€ä¸ªç¾¤ç»„所有者。"
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr "无法从%{group}中移除%{user}。用户ä¸æ˜¯ç¾¤ç»„æˆå‘˜ã€‚"
-
msgid "Could not remove the trigger."
msgstr "无法删除触å‘器。"
@@ -11029,9 +11175,6 @@ msgstr "创建新文件或目录"
msgid "Create new label"
msgstr "创建新标记"
-msgid "Create new project"
-msgstr "新建项目"
-
msgid "Create new..."
msgstr "创建新的..."
@@ -11299,9 +11442,6 @@ msgstr "创建å²è¯—中"
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr "正在使用PrometheusæœåŠ¡å™¨ä¸­çš„æ•°æ®åˆ›å»ºå›¾è¡¨ã€‚如果这需è¦å¾ˆé•¿æ—¶é—´ï¼Œè¯·ç¡®ä¿æ•°æ®å¯ç”¨ã€‚"
-msgid "Creation date"
-msgstr "创建日期"
-
msgid "Creator"
msgstr "创建者"
@@ -11317,8 +11457,8 @@ msgstr "找ä¸åˆ°å‡­è¯"
msgid "CredentialsInventory|Personal Access Tokens"
msgstr "个人访问令牌"
-msgid "CredentialsInventory|Project Access Tokens"
-msgstr "项目访问令牌"
+msgid "CredentialsInventory|Project and Group Access Tokens"
+msgstr ""
msgid "CredentialsInventory|SSH Keys"
msgstr "SSH密钥"
@@ -11419,9 +11559,6 @@ msgstr "当å‰åˆ†æ”¯"
msgid "Current Project"
msgstr "当å‰é¡¹ç›®"
-msgid "Current forks will keep their visibility level."
-msgstr "当å‰æ´¾ç”Ÿï¼ˆfork)将ä¿æŒå…¶å¯è§ç­‰çº§ã€‚"
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr "当å‰èŠ‚点必须是主节点,å¦åˆ™æ‚¨å°†ä¼šé”定自己。"
@@ -11747,6 +11884,9 @@ msgstr "更改失败率"
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr "å˜æ›´å¤±è´¥çŽ‡ï¼ˆç™¾åˆ†æ¯”)"
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr "%{groupName} 群组的 DORA指标"
+
msgid "DORA4Metrics|Date"
msgstr "日期"
@@ -11774,6 +11914,9 @@ msgstr "中ä½æ—¶é—´ï¼ˆæœ€è¿‘ %{days} 天)"
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr "在给定时间段内,事件在生产环境中的中ä½æ—¶é—´ã€‚"
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr "在此期间没有事件"
@@ -11831,6 +11974,9 @@ msgstr "个人"
msgid "DashboardProjects|Trending"
msgstr "热门"
+msgid "Dashboards"
+msgstr "仪表盘"
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr "%{firstProject} 和 %{secondProject}"
@@ -12065,6 +12211,9 @@ msgstr "将目标站点和扫æ设置的常用设定ä¿å­˜ä¸ºé…置。使用这
msgid "DastProfiles|Save profile"
msgstr "ä¿å­˜é…ç½®"
+msgid "DastProfiles|Scan Method"
+msgstr "扫æ方法"
+
msgid "DastProfiles|Scan method"
msgstr "扫æ方法"
@@ -12282,6 +12431,9 @@ msgstr "æ•°æ®åˆ·æ–°"
msgid "Data type"
msgstr "æ•°æ®ç±»åž‹"
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr "æ•°æ®åº“更新失败"
@@ -12369,6 +12521,9 @@ msgstr "三"
msgid "Days"
msgstr "天"
+msgid "Days of inactivity before deactivation"
+msgstr "åœç”¨å‰çš„ä¸æ´»åŠ¨å¤©æ•°"
+
msgid "Days to merge"
msgstr "åˆå¹¶æ‰€éœ€å¤©æ•°"
@@ -12402,6 +12557,9 @@ msgstr "解压归档大å°éªŒè¯å¤±è´¥ã€‚"
msgid "Decrease"
msgstr "å‡å°‘"
+msgid "Default - Never run"
+msgstr "默认 - 从ä¸è¿è¡Œ"
+
msgid "Default CI/CD configuration file"
msgstr "默认 CI/CD é…置文件"
@@ -12513,6 +12671,9 @@ msgstr "删除"
msgid "Delete %{issuableType}"
msgstr "删除 %{issuableType}"
+msgid "Delete %{issuableType}?"
+msgstr "删除 %{issuableType}?"
+
msgid "Delete %{name}"
msgstr "删除%{name}"
@@ -12534,9 +12695,6 @@ msgstr "删除值æµ"
msgid "Delete account"
msgstr "删除账户"
-msgid "Delete artifacts"
-msgstr "删除产物"
-
msgid "Delete asset"
msgstr "删除 asset"
@@ -12603,7 +12761,7 @@ msgstr "删除å‘布 %{release}?"
msgid "Delete row"
msgstr "删除行"
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr "删除自监控项目"
msgid "Delete snippet"
@@ -13074,6 +13232,9 @@ msgstr "到期日期(å¯é€‰ï¼‰"
msgid "DeployTokens|Expires"
msgstr "到期"
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr "创建新的部署令牌失败"
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr "群组部署令牌å…许访问群组内的软件包,代ç ä»“库和容器镜åƒåº“中的镜åƒã€‚"
@@ -13161,6 +13322,21 @@ msgstr "选择部署目标"
msgid "Deployment frequency"
msgstr "部署频率"
+msgid "DeploymentApprovals|Approvals"
+msgstr "批准"
+
+msgid "DeploymentApprovals|Approved By"
+msgstr "核准人"
+
+msgid "DeploymentApprovals|Approvers"
+msgstr "核准人"
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr "å¼€å‘者 + 维护者"
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr "维护者"
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr "当å‰æ‰¹å‡†ï¼š %{current}"
@@ -13374,7 +13550,7 @@ msgid "DesignManagement|Are you sure you want to cancel creating this comment?"
msgstr "确定è¦å–消创建此评论å—?"
msgid "DesignManagement|Are you sure you want to cancel editing this comment?"
-msgstr ""
+msgstr "您确定è¦å–消编辑此评论å—?"
msgid "DesignManagement|Click the image where you'd like to start a new discussion"
msgstr "å•å‡»æ‚¨è¦å¼€å§‹æ–°è®¨è®ºçš„图åƒ"
@@ -13383,10 +13559,10 @@ msgid "DesignManagement|Comment"
msgstr "评论"
msgid "DesignManagement|Continue creating"
-msgstr ""
+msgstr "继续创建"
msgid "DesignManagement|Continue editing"
-msgstr ""
+msgstr "继续编辑"
msgid "DesignManagement|Could not add a new comment. Please try again."
msgstr "无法添加新评论。请å†è¯•ä¸€æ¬¡."
@@ -13407,7 +13583,7 @@ msgid "DesignManagement|Designs"
msgstr "设计"
msgid "DesignManagement|Discard changes"
-msgstr ""
+msgstr "放弃更改"
msgid "DesignManagement|Discussion"
msgstr "讨论"
@@ -13499,6 +13675,9 @@ msgstr "DevOps 报告"
msgid "DevOps adoption"
msgstr "DevOps adoption"
+msgid "Developer"
+msgstr "å¼€å‘者"
+
msgid "Development"
msgstr "å¼€å‘"
@@ -13735,6 +13914,12 @@ msgstr[0] "%d 个删除"
msgid "Diffs|Expand all lines"
msgstr "展开所有行"
+msgid "Diffs|Hide whitespace changes"
+msgstr "éšè—空白å˜æ›´å†…容"
+
+msgid "Diffs|Inline"
+msgstr "行内"
+
msgid "Diffs|Next 20 lines"
msgstr "åŽ 20 è¡Œ"
@@ -13750,10 +13935,16 @@ msgstr "显示%{unfoldCount}行"
msgid "Diffs|Show all unchanged lines"
msgstr "显示所有未改å˜çš„è¡Œ"
+msgid "Diffs|Show whitespace changes"
+msgstr "显示空白å˜æ›´å†…容"
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] "显示 %{dropdownStart}%{count} 个更改的文件%{dropdownEnd}"
+msgid "Diffs|Side-by-side"
+msgstr "å·¦å³å¹¶æŽ’"
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "获å–差异线时å‘生错误。"
@@ -14358,6 +14549,12 @@ msgstr "已编辑"
msgid "Edited %{timeago}"
msgstr "编辑于%{timeago}"
+msgid "Edited %{timeago} by %{author}"
+msgstr "由 %{author} 编辑于 %{timeago}"
+
+msgid "Edited by %{author}"
+msgstr "由 %{author} 编辑"
+
msgid "Editing"
msgstr "编辑中"
@@ -14688,23 +14885,41 @@ msgstr "å¯ç”¨ç”¨æˆ·åœç”¨ç”µå­é‚®ä»¶"
msgid "Enable version check"
msgstr "å¯ç”¨ç‰ˆæœ¬æ£€æŸ¥"
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
-msgstr "%{stepStart}第一步%{stepEnd}: ç¡®ä¿æ‚¨å·²è®¾ç½®Kubernetes并为您的%{linkStart}集群%{linkEnd}æ供了基本域。"
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr "在您的 CI/CD é…置中添加一个作业:"
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr "å¤åˆ¶ä»£ç ç‰‡æ®µ"
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
-msgstr "%{stepStart}第2æ­¥%{stepEnd}: å¤åˆ¶ä»¥ä¸‹è„šæœ¬ï¼š"
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr "具有访问å¯ä»¥æ‰˜ç®¡å’Œéƒ¨ç½² review apps 的基础架构的æƒé™ã€‚"
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
-msgstr "%{stepStart}第3步%{stepEnd}: 将其添加到项目的%{linkStart}gitlab-ci.yml%{linkEnd}文件。"
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr "安装并é…ç½® runner æ¥è¿›è¡Œéƒ¨ç½²ã€‚"
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
-msgstr "%{stepStart}第 4 步(å¯é€‰ï¼‰%{stepEnd}。%{linkStart}æ ¹æ®è®¾ç½®è¯´æ˜Žå¯ç”¨å¯è§†åŒ–评审%{linkEnd}。"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr "ç¡®ä¿æ‚¨çš„项目é…置了一个环境,其中目标 URL 设置为您的网站 URL。如果没有,请在继续之å‰åˆ›å»ºä¸€ä¸ªæ–°çš„。"
-msgid "EnableReviewApp|Close"
-msgstr "关闭"
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr "仅针对功能分支或åˆå¹¶è¯·æ±‚è¿è¡Œã€‚"
-msgid "EnableReviewApp|Copy snippet text"
-msgstr "å¤åˆ¶ä»£ç ç‰‡æ®µ"
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr "推è:设置手动åœæ­¢ Review Apps 的作业。"
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr "Review apps 是动æ€çŽ¯å¢ƒï¼Œæ‚¨å¯ä»¥ç”¨æ¥ä¸ºåŠŸèƒ½åˆ†æ”¯ä¸­çš„更改æ供实时预览。"
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr "è¦é…ç½® review app,您必须:"
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr "使用预定义的 CI/CD å˜é‡ï¼Œä¾‹å¦‚ %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} æ¥åŠ¨æ€åˆ›å»º review app 环境。例如,使用åˆå¹¶è¯·æ±‚æµæ°´çº¿çš„é…置:"
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr "使用é™æ€ç«™ç‚¹ï¼Ÿ"
+
+msgid "EnableReviewApp|View more example projects"
+msgstr "查看更多示例项目"
msgid "Enabled"
msgstr "å·²å¯ç”¨"
@@ -14931,6 +15146,9 @@ msgstr "自动åœæ­¢äºŽ %{autoStopAt}"
msgid "Environments|Commit"
msgstr "æ交"
+msgid "Environments|Copy live environment URL"
+msgstr "å¤åˆ¶å®žæ—¶çŽ¯å¢ƒ URL"
+
msgid "Environments|Delete"
msgstr "删除"
@@ -15111,12 +15329,12 @@ msgstr "添加一个新的å²è¯—。"
msgid "Epics|Add an existing epic"
msgstr "添加一个现有的å²è¯—。"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgstr "您确定è¦ä»Ž %{bStart}%{parentEpicTitle}%{bEnd} 中删除 %{bStart}%{targetEpicTitle}%{bEnd} å—?"
+
msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr "确定è¦ä»Ž%{bStart}%{parentEpicTitle}%{bEnd}删除%{bStart}%{targetIssueTitle}%{bEnd}å—?"
-msgid "Epics|Assign Epic"
-msgstr "指派å²è¯—"
-
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr "留空以继承里程碑日期"
@@ -15129,18 +15347,9 @@ msgstr "删除å²è¯—"
msgid "Epics|Remove issue"
msgstr "删除议题"
-msgid "Epics|Search epics"
-msgstr "æœç´¢å²è¯—"
-
-msgid "Epics|Select epic"
-msgstr "选择å²è¯—"
-
msgid "Epics|Show more"
msgstr "显示更多"
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr "分é…议题到å²è¯—时出错。"
-
msgid "Epics|Something went wrong while creating child epics."
msgstr "创建å­å²è¯—时出错。"
@@ -15153,18 +15362,12 @@ msgstr "获å–å­å²è¯—时出错。"
msgid "Epics|Something went wrong while fetching epics list."
msgstr "获å–å²è¯—列表时出错。"
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr "获å–群组å²è¯—时出错。"
-
msgid "Epics|Something went wrong while moving item."
msgstr "移动项目时出了错。"
msgid "Epics|Something went wrong while ordering item."
msgstr "排åºæ—¶å‡ºé”™ã€‚"
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr "从å²è¯—中删除议题时出错。"
-
msgid "Epics|Something went wrong while updating epics."
msgstr "æ›´æ–°å²è¯—时出错。"
@@ -15294,9 +15497,6 @@ msgstr "ä¿å­˜è¢«æŒ‡æ´¾äººæ—¶å‡ºçŽ°é”™è¯¯ã€‚"
msgid "Error occurred when saving reviewers"
msgstr "ä¿å­˜å®¡æ ¸è€…时出错"
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr "æ›´æ–° %{issuableType} 状æ€æ—¶å‡ºé”™"
-
msgid "Error occurred while updating the issue status"
msgstr "更新议题状æ€æ—¶å‡ºé”™"
@@ -15360,9 +15560,6 @@ msgstr "上传文件时出错"
msgid "Error uploading file. Please try again."
msgstr "上传文件时出错。请é‡è¯•ã€‚"
-msgid "Error uploading file: %{stripped}"
-msgstr "上传文件时出错: %{stripped}"
-
msgid "Error while loading the merge request. Please try again."
msgstr "加载åˆå¹¶è¯·æ±‚时出错。请å†è¯•ä¸€æ¬¡ã€‚"
@@ -15603,6 +15800,57 @@ msgstr "事件"
msgid "Events API"
msgstr "事件 API"
+msgid "Event|accepted"
+msgstr "已接å—"
+
+msgid "Event|added"
+msgstr "已添加"
+
+msgid "Event|approved"
+msgstr "已批准"
+
+msgid "Event|closed"
+msgstr "已关闭"
+
+msgid "Event|commented on"
+msgstr "评论于"
+
+msgid "Event|created"
+msgstr "已创建"
+
+msgid "Event|deleted"
+msgstr "已删除"
+
+msgid "Event|destroyed"
+msgstr "已销æ¯"
+
+msgid "Event|imported"
+msgstr "已导入"
+
+msgid "Event|joined"
+msgstr "已加入"
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr "已打开"
+
+msgid "Event|pushed new"
+msgstr "推é€æ–°çš„"
+
+msgid "Event|pushed to"
+msgstr "推é€åˆ°"
+
+msgid "Event|removed"
+msgstr "已删除"
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr "已更新"
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr "所有 %{action} å°è¯•éƒ½å·²å¤±è´¥ï¼š %{job_error_message}。请å†è¯•ä¸€æ¬¡ã€‚"
@@ -15721,6 +15969,9 @@ msgstr "ä¸åŒ…括åˆå¹¶æ交。仅é™6,000次æ交。"
msgid "Execution time"
msgstr "执行时间"
+msgid "Executive Dashboard"
+msgstr "管ç†å±•ç¤ºä»ªè¡¨ç›˜"
+
msgid "Existing branch name, tag, or commit SHA"
msgstr "已存在分支å称,标记或æ交SHA"
@@ -15778,9 +16029,15 @@ msgstr "展开侧边æ "
msgid "Expected documents: %{expected_documents}"
msgstr "需è¦çš„文档: %{expected_documents}"
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr "必须有一个用户ã€å‘½å空间或项目。"
+msgid "Experiments"
+msgstr "实验"
+
msgid "Expiration"
msgstr "过期时间"
@@ -16004,6 +16261,9 @@ msgstr "失败于"
msgid "Failed to add a Zoom meeting"
msgstr "无法添加Zoom会议"
+msgid "Failed to add a resource link"
+msgstr "添加资æºé“¾æŽ¥å¤±è´¥"
+
msgid "Failed to apply commands."
msgstr "应用命令失败。"
@@ -16050,9 +16310,6 @@ msgstr "创建框架失败"
msgid "Failed to create import label for jira import."
msgstr "为jira导入创建导入标签失败。"
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr "创建新访问令牌失败:%{token_response_message}"
-
msgid "Failed to create repository"
msgstr "创建仓库失败"
@@ -16248,9 +16505,6 @@ msgstr "更新议题状æ€å¤±è´¥"
msgid "Failed to update the Canary Ingress."
msgstr "无法更新Canary Ingress。"
-msgid "Failed to update."
-msgstr "更新失败。"
-
msgid "Failed to upgrade."
msgstr "å‡çº§å¤±è´¥ã€‚"
@@ -16507,6 +16761,9 @@ msgstr "2月"
msgid "February"
msgstr "2月"
+msgid "Feedback and Updates"
+msgstr "å馈和更新"
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr "获å–并检出这个åˆå¹¶è¯·æ±‚的功能分支:"
@@ -16612,9 +16869,6 @@ msgstr "按当å‰å·²å…³é—­å’Œæœªåˆå¹¶çš„åˆå¹¶è¯·æ±‚筛选。"
msgid "Filter by merge requests that are currently merged."
msgstr "按当å‰å·²åˆå¹¶çš„åˆå¹¶è¯·æ±‚筛选。"
-msgid "Filter by milestone"
-msgstr "按里程碑筛选"
-
msgid "Filter by milestone name"
msgstr "按里程碑å称筛选"
@@ -16822,6 +17076,9 @@ msgstr "如需了解详细信æ¯ï¼Œè¯·å‚阅"
msgid "For more information, see the File Hooks documentation."
msgstr "欲了解更多信æ¯ï¼Œè¯·å‚阅文件钩å­æ–‡æ¡£ã€‚"
+msgid "Forbidden"
+msgstr "ç¦æ­¢"
+
msgid "Forgot your password?"
msgstr "忘记密ç ï¼Ÿ"
@@ -16928,7 +17185,7 @@ msgid "Framework successfully deleted"
msgstr "框架删除æˆåŠŸ"
msgid "Free"
-msgstr ""
+msgstr "å…è´¹"
msgid "Free Trial of GitLab.com Ultimate"
msgstr "å…费试用"
@@ -17226,7 +17483,7 @@ msgid "Geo|Errors:"
msgstr "错误:"
msgid "Geo|External URL"
-msgstr ""
+msgstr "外部 URL"
msgid "Geo|Failed"
msgstr "失败"
@@ -17568,7 +17825,7 @@ msgid "Geo|There was an error updating the Geo Settings"
msgstr "更新Geo设置时出错"
msgid "Geo|This GitLab instance is subscribed to the %{insufficient_license} tier. Geo is only available for users who have at least a Premium subscription."
-msgstr ""
+msgstr "此实例已订阅到 %{insufficient_license} 级别。Geo 仅适用于至少有专业版订阅的用户。"
msgid "Geo|This will resync all %{replicableType}. It may take some time to complete. Are you sure you want to continue?"
msgstr "å°†è¦é‡æ–°åŒæ­¥æ‰€æœ‰%{replicableType}。å¯èƒ½éœ€è¦ä¸€äº›æ—¶é—´å®Œæˆã€‚确定继续å—?"
@@ -17651,9 +17908,6 @@ msgstr "次è¦èŠ‚点"
msgid "Get a free instance review"
msgstr "获得å…费的实例评估"
-msgid "Get a free trial"
-msgstr "获得å…费试用"
-
msgid "Get a support subscription"
msgstr "获å–支æŒè®¢é˜…"
@@ -17780,6 +18034,12 @@ msgstr "GitLabå¸æˆ·åˆ›å»ºè¯·æ±‚"
msgid "GitLab Billing Team."
msgstr "GitLab计费团队。"
+msgid "GitLab Community Edition"
+msgstr "GitLab 社区版"
+
+msgid "GitLab Enterprise Edition"
+msgstr "GitLab ä¼ä¸šç‰ˆ"
+
msgid "GitLab Error Tracking"
msgstr "GitLab 错误跟踪"
@@ -17831,6 +18091,9 @@ 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}"
@@ -17879,9 +18142,6 @@ msgstr "GitLab 版本"
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr "GitLab 将在你的派生项目中创建分支并开始åˆå¹¶è¯·æ±‚。"
-msgid "GitLab.com"
-msgstr "GitLab.com"
-
msgid "GitLab.com (SaaS)"
msgstr "GitLab.com (SaaS)"
@@ -18437,9 +18697,6 @@ msgstr "查看ä¾èµ–项"
msgid "GraphViewType|Stage"
msgstr "阶段"
-msgid "Graphs"
-msgstr "图表"
-
msgid "Gravatar"
msgstr "Gravatar"
@@ -18449,6 +18706,9 @@ msgstr "å¯ç”¨ Gravatar"
msgid "Group"
msgstr "群组"
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr "群组%{group_name}无法导出。"
@@ -18915,7 +19175,7 @@ msgid "GroupSettings|Compliance frameworks"
msgstr "åˆè§„框架"
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
-msgstr ""
+msgstr "é…ç½®åˆè§„框架以æ供给此群组中的项目。%{linkStart}什么是åˆè§„框架?%{linkEnd}"
msgid "GroupSettings|Configure limits on the number of repositories users can download in a given time."
msgstr "é…置用户在给定时间内å¯ä»¥ä¸‹è½½çš„仓库数é‡é™åˆ¶ã€‚"
@@ -19211,12 +19471,6 @@ msgstr "离开群组"
msgid "GroupsTree|Loading groups"
msgstr "加载群组中"
-msgid "GroupsTree|No groups matched your search"
-msgstr "没有æœç´¢åˆ°ä»»ä½•ç¬¦åˆçš„群组"
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr "没有任何群组或项目符åˆæ‚¨çš„æœç´¢"
-
msgid "GroupsTree|Options"
msgstr "选项"
@@ -19286,6 +19540,9 @@ msgstr "å­ç»„标识串"
msgid "Groups|You're creating a new top-level group"
msgstr "您正在创建一个新的顶级群组"
+msgid "Guest"
+msgstr "访客"
+
msgid "Guideline"
msgstr "å‚考"
@@ -19308,7 +19565,7 @@ msgid "Harbor Registry"
msgstr "Harbor é•œåƒåº“"
msgid "HarborIntegration|After the Harbor integration is activated, global variables `$HARBOR_USERNAME`, `$HARBOR_HOST`, `$HARBOR_OCI`, `$HARBOR_PASSWORD`, `$HARBOR_URL` and `$HARBOR_PROJECT` will be created for CI/CD use."
-msgstr ""
+msgstr "激活 Harbor 集æˆåŽï¼Œå…¨å±€å˜é‡ `$HARBOR_USERNAME`,$HARBOR_HOST`ã€`$HARBOR_OCI`ã€`$HARBOR_PASSWORD`ã€`$HARBOR_URL` å’Œ `$HARBOR_PROJECT` 将被创建,供 CI/CD 使用。"
msgid "HarborIntegration|Base URL of the Harbor instance."
msgstr "Harbor 实例的基础 URL。"
@@ -19462,9 +19719,6 @@ msgstr "è¿è¡ŒçŠ¶å†µä¿¡æ¯å¯ä»¥ä»Žä»¥ä¸‹API路径获å–。如需了解更多信
msgid "Health status"
msgstr "å¥åº·çŠ¶æ€"
-msgid "Health status cannot be edited because this issue is closed"
-msgstr "由于此议题已关闭,因此无法编辑å¥åº·çŠ¶æ€"
-
msgid "HealthCheck|Access token is"
msgstr "访问令牌为"
@@ -19917,8 +20171,14 @@ msgstr "å‘é€éªŒè¯ç "
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr "出错了,请å†è¯•ä¸€æ¬¡ã€‚"
-msgid "IdentityVerification|Step 1: Verify phone number"
-msgstr "步骤1:验è¯ç”µè¯å·ç "
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr "步骤 %{stepNumber}:验è¯ä»˜æ¬¾æ–¹å¼"
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr "步骤 %{stepNumber}:验è¯ç”µå­é‚®ä»¶åœ°å€"
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
+msgstr "步骤 %{stepNumber}:验è¯ç”µè¯å·ç "
msgid "IdentityVerification|The code has expired. Send a new code and try again."
msgstr "验è¯ç å·²è¿‡æœŸã€‚é‡æ–°å‘é€æ–°éªŒè¯ç ç„¶åŽé‡è¯•ã€‚"
@@ -20004,12 +20264,6 @@ msgstr "如果此电å­é‚®ä»¶è¢«é”™è¯¯æ·»åŠ ï¼Œæ‚¨å¯ä»¥åœ¨è¿™é‡Œåˆ é™¤ï¼š"
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr "如果此电å­é‚®ä»¶è¢«é”™è¯¯æ·»åŠ ï¼Œæ‚¨å¯ä»¥åœ¨è¿™é‡Œåˆ é™¤å®ƒï¼š %{profile_emails_url}"
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr "如果这是一个错误,您å¯ä»¥%{link_start}解除对他们的å°ç¦%{link_end}。"
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr "如果这是一个错误,你å¯ä»¥è§£é™¤å¯¹ä»–们的å°ç¦ï¼š%{url}。"
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr "如果这是一个错误,你å¯ä»¥%{leave_link_start}退出%{source_type}%{link_end}。"
@@ -20235,7 +20489,7 @@ msgid "ImportProjects|%{provider} rate limit exceeded. Try again later"
msgstr "超过%{provider}的速率é™åˆ¶ã€‚请ç¨åŽå†è¯•"
msgid "ImportProjects|Advanced import settings"
-msgstr ""
+msgstr "高级导入设置"
msgid "ImportProjects|Blocked import URL: %{message}"
msgstr "ç¦æ­¢çš„导入URL: %{message}"
@@ -20262,7 +20516,7 @@ msgid "ImportProjects|Select the repositories you want to import"
msgstr "选择您想è¦å¯¼å…¥çš„仓库"
msgid "ImportProjects|The more information you select, the longer it will take to import"
-msgstr ""
+msgstr "您选择的信æ¯è¶Šå¤šï¼Œå¯¼å…¥æ‰€éœ€çš„时间越长"
msgid "ImportProjects|The remote data could not be imported."
msgstr "无法导入远程数æ®ã€‚"
@@ -21757,6 +22011,9 @@ msgstr "无效的åŒé‡è®¤è¯ç ã€‚"
msgid "Invalid yaml"
msgstr "无效的yaml"
+msgid "Invalidated"
+msgstr "无效"
+
msgid "Investigate vulnerability: %{title}"
msgstr "调查æ¼æ´ž: %{title}"
@@ -21775,9 +22032,6 @@ msgstr "邀请被拒ç»"
msgid "Invite \"%{email}\" by email"
msgstr "通过电å­é‚®ä»¶é‚€è¯·â€œ%{email}â€"
-msgid "Invite \"%{trimmed}\" by email"
-msgstr "通过电å­é‚®ä»¶é‚€è¯·â€œ%{trimmed}â€"
-
msgid "Invite Members"
msgstr "邀请æˆå‘˜"
@@ -21835,8 +22089,8 @@ msgstr "邀请您的åŒäº‹"
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr "ç›®å‰æ‚¨è¿˜æ²¡æœ‰é‚€è¯·ä»»ä½•äººåŠ å…¥è¿™ä¸ªç¾¤ç»„。 您å¯ä»¥é‚€è¯·æ‚¨çš„åŒäº‹åˆ°ç¾¤ç»„ç§ï¼Œä»¥æ–¹ä¾¿è®¨è®ºé—®é¢˜ï¼Œåœ¨åˆå¹¶è¯·æ±‚中进行å作,以åŠåˆ†äº«æ‚¨çš„知识。"
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
-msgstr "è¦èŽ·å¾—更多æˆå‘˜å¹¶è®¿é—®å…¶ä»–付费功能,群组的所有者å¯ä»¥å¼€å§‹è¯•ç”¨æˆ–å‡çº§åˆ°ä»˜è´¹ç­‰çº§ã€‚"
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
+msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
msgstr "%{linkStart}了解更多%{linkEnd}关于角色æƒé™çš„ä¿¡æ¯"
@@ -21914,21 +22168,18 @@ msgid "InviteMembersModal|The following member couldn't be invited"
msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] "以下 %d 个æˆå‘˜æ— æ³•è¢«é‚€è¯·"
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr "此功能被ç¦ç”¨ï¼Œç›´åˆ°è¯¥ç¾¤ç»„有更多æˆå‘˜çš„空间。"
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr "è¦å‘新团队æˆå‘˜åˆ†é…议题,您需è¦ä¸€ä¸ªè®®é¢˜æ‰€å±žçš„项目。 %{linkStart}从创建一个项目开始。%{linkEnd}"
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr "è¦èŽ·å¾—更多æˆå‘˜ï¼Œç¾¤ç»„的所有者å¯ä»¥ %{trialLinkStart}开始试用%{trialLinkEnd} 或 %{upgradeLinkStart}å‡çº§%{upgradeLinkEnd} 到付费等级。"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
+msgstr ""
+
msgid "InviteMembersModal|Username or email address"
msgstr "用户å或电å­é‚®ä»¶åœ°å€"
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
-msgstr "您ä¸èƒ½æ·»åŠ æ›´å¤šæˆå‘˜ï¼Œä½†æ‚¨å¯ä»¥åˆ é™¤ä¸å†éœ€è¦è®¿é—®çš„æˆå‘˜ã€‚"
-
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
msgstr "在 %{name},您åªæœ‰ %{count} 个更多的 %{members} 的空间"
@@ -22064,12 +22315,18 @@ msgstr "正在使用许å¯è¯ï¼š"
msgid "Is using seat"
msgstr "正在使用许å¯å¸­ä½"
+msgid "IssuableEvents|assigned to"
+msgstr "分é…ç»™"
+
msgid "IssuableEvents|removed review request for"
msgstr "已删除审核请求"
msgid "IssuableEvents|requested review from"
msgstr "请求审核"
+msgid "IssuableEvents|unassigned"
+msgstr "未分é…"
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr "%{wi_type} 由 %{created_at} 创建"
@@ -22091,6 +22348,18 @@ msgstr "已移动"
msgid "IssuableStatus|promoted"
msgstr "å·²å‡çº§"
+msgid "Issuable|epic"
+msgstr "å²è¯—"
+
+msgid "Issuable|escalation policy"
+msgstr "å‡çº§ç­–ç•¥"
+
+msgid "Issuable|iteration"
+msgstr "迭代"
+
+msgid "Issuable|milestone"
+msgstr "里程碑"
+
msgid "Issue"
msgstr "议题"
@@ -22316,6 +22585,21 @@ msgstr "è¦æ‰©å¤§æœç´¢èŒƒå›´ï¼Œè¯·æ›´æ”¹æˆ–删除上é¢çš„筛选æ¡ä»¶"
msgid "IssuesAnalytics|Total:"
msgstr "总计:"
+msgid "Issues|Move selected"
+msgstr "移动所选"
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr "任务和测试用例ä¸èƒ½è¢«ç§»åŠ¨ã€‚"
+
+msgid "Issues|Tasks can not be moved."
+msgstr "任务ä¸èƒ½è¢«ç§»åŠ¨ã€‚"
+
+msgid "Issues|Test cases can not be moved."
+msgstr "测试用例ä¸èƒ½è¢«ç§»åŠ¨ã€‚"
+
+msgid "Issues|There was an error while moving the issues."
+msgstr "移动议题时出错。"
+
msgid "Issue|Title"
msgstr "标题"
@@ -22610,6 +22894,9 @@ msgstr "GitLab for Jira App"
msgid "JiraConnect|Jira Connect Application ID"
msgstr "Jira Connect Application ID"
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr "Jira Connect Proxy URL"
+
msgid "JiraConnect|New branch was successfully created."
msgstr "æˆåŠŸåˆ›å»ºæ–°åˆ†æ”¯ã€‚"
@@ -22940,6 +23227,9 @@ msgstr "已创建"
msgid "Job|Download"
msgstr "下载"
+msgid "Job|Duration"
+msgstr "时长"
+
msgid "Job|Erase job log and artifacts"
msgstr "擦除作业日志和产物"
@@ -22979,9 +23269,15 @@ msgstr "等待中"
msgid "Job|Preparing"
msgstr "正在准备"
+msgid "Job|Queued"
+msgstr "队列中"
+
msgid "Job|Retry"
msgstr "é‡è¯•"
+msgid "Job|Run again"
+msgstr "å†æ¬¡è¿è¡Œ"
+
msgid "Job|Running"
msgstr "正在è¿è¡Œ"
@@ -23356,9 +23652,6 @@ msgstr "最åŽä¸€æ¬¡ç”± %{link_start}%{avatar} %{name}%{link_end} 编辑"
msgid "Last event"
msgstr "最近活动"
-msgid "Last item before this page loaded in your browser:"
-msgstr "此页é¢åœ¨æ‚¨çš„æµè§ˆå™¨ä¸­è½½å…¥å‰çš„最åŽä¸€ä¸ªé¡¹ç›®ï¼š"
-
msgid "Last modified"
msgstr "最近修改"
@@ -23512,6 +23805,15 @@ msgstr "了解关于群组的更多信æ¯ã€‚"
msgid "Learn more about issues."
msgstr "了解有关议题的更多信æ¯ã€‚"
+msgid "Learn more about linking epics"
+msgstr "了解更多关于关è”å²è¯—çš„ä¿¡æ¯"
+
+msgid "Learn more about linking issues"
+msgstr "了解更多关于关è”议题的信æ¯"
+
+msgid "Learn more about linking issues and incidents"
+msgstr "了解更多关于关è”议题和事件的信æ¯"
+
msgid "Learn more about max seats used"
msgstr "了解更多关于最大席ä½æ•°çš„ä¿¡æ¯"
@@ -23662,9 +23964,6 @@ msgstr "退出项目"
msgid "Leave zen mode"
msgstr "离开禅模å¼"
-msgid "Leaving this setting enabled is recommended."
-msgstr "建议å¯ç”¨æ­¤è®¾ç½®ã€‚"
-
msgid "Legacy burndown chart"
msgstr "旧版燃尽图"
@@ -23905,6 +24204,12 @@ msgstr "è¡Œå˜æ›´"
msgid "Link"
msgstr "链接"
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr "链接(å¯é€‰ï¼‰"
@@ -24089,7 +24394,7 @@ msgid "Lock"
msgstr "é”定"
msgid "Lock %{issuableDisplayName}"
-msgstr "é”定 %{issuableDisplayName}"
+msgstr "é”定%{issuableDisplayName}"
msgid "Lock File?"
msgstr "é”定文件?"
@@ -24175,9 +24480,6 @@ msgstr "Logo 将被删除,您确定å—?"
msgid "Logs"
msgstr "日志"
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr "似乎您已ç»è¾¾åˆ°äº† %{free_limit} %{strong_start}%{namespace_name}çš„%{strong_end} æˆå‘˜ä¸Šé™"
-
msgid "Low vulnerabilities present"
msgstr "存在低å±æ¼æ´ž"
@@ -24190,6 +24492,9 @@ msgstr "MD5"
msgid "MERGED"
msgstr "å·²åˆå¹¶"
+msgid "ML Experiments"
+msgstr "机器学习实验"
+
msgid "MR widget|Back to the merge request"
msgstr "返回åˆå¹¶è¯·æ±‚"
@@ -24226,8 +24531,14 @@ msgstr "åªæŸ¥çœ‹å˜æ›´å†…容"
msgid "MRDiff|Show full file"
msgstr "显示全部文件"
-msgid "Made this issue confidential."
-msgstr "将此议题设置为ç§å¯†."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr "机器学习实验跟踪处于孵化阶段"
+
+msgid "Machine Learning Experiments"
+msgstr "机器学习实验"
+
+msgid "Made this %{type} confidential."
+msgstr "已将此 %{type} 设置为ç§å¯†ã€‚"
msgid "Mailgun"
msgstr "Mailgun"
@@ -24241,9 +24552,15 @@ msgstr "Mailgun事件"
msgid "Main menu"
msgstr "主èœå•"
+msgid "Maintainer"
+msgstr "维护者"
+
msgid "Maintenance mode"
msgstr "维护模å¼"
+msgid "Make %{type} confidential"
+msgstr "å°† %{type} 设置为ç§å¯†ã€‚"
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr "调整您 GitLab 实例的设置方å¼ã€‚"
@@ -24253,9 +24570,6 @@ msgstr "使用Web IDE在æµè§ˆå™¨ä¸­åˆ›å»ºå’ŒæŸ¥çœ‹æ›´æ”¹"
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr "GitLab Geoå¯ä»¥åˆ›å»ºGitLab实例的åªè¯»é•œåƒ, 使得从远端克隆和拉å–大型代ç ä»“库的时间大大缩短,从而æ高团队æˆå‘˜çš„工作效率。"
-msgid "Make issue confidential"
-msgstr "将议题设置为ç§å¯†ã€‚"
-
msgid "Make sure you choose a strong, unique password."
msgstr "ç¡®ä¿é€‰æ‹©ä¸€ä¸ªå¼ºå¤§ä¸”唯一的密ç ã€‚"
@@ -24265,8 +24579,8 @@ msgstr "请确ä¿æ‚¨æœ‰æ­£ç¡®çš„æƒé™å…³è”您的项目。"
msgid "Make sure you save it - you won't be able to access it again."
msgstr "请确ä¿å¦¥å–„ä¿å­˜å®ƒ - 您无法å†æ¬¡è®¿é—®å®ƒçš„内容。"
-msgid "Makes this issue confidential."
-msgstr "将此议题设置为ç§å¯†."
+msgid "Makes this %{type} confidential."
+msgstr "将此 %{type} 设置为ç§å¯†ã€‚"
msgid "Manage %{workspace} labels"
msgstr "ç®¡ç† %{workspace} 标记"
@@ -24314,7 +24628,7 @@ msgid "Manage your project's triggers"
msgstr "管ç†æ‚¨çš„项目触å‘器"
msgid "Manage your subscription"
-msgstr ""
+msgstr "管ç†æ‚¨çš„订阅"
msgid "Managed Account"
msgstr "托管账户"
@@ -24322,6 +24636,9 @@ msgstr "托管账户"
msgid "Manifest"
msgstr "Manifest"
+msgid "Manifest file"
+msgstr "Manifest 文件"
+
msgid "Manifest file import"
msgstr "Manifest文件导入"
@@ -24346,6 +24663,9 @@ msgstr "3月"
msgid "March"
msgstr "3月"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr "无法获å–帮助内容。"
+
msgid "Mark as done"
msgstr "标记为已完æˆ"
@@ -24397,6 +24717,9 @@ msgstr "添加删除线文本 (%{modifierKey}⇧X)"
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr "添加带删除线的文本(%{modifier_key}⇧X)"
+msgid "MarkdownEditor|Click to expand"
+msgstr "点击展开"
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr "缩进行(%{modifierKey})"
@@ -24409,6 +24732,9 @@ msgstr "å‡å°‘缩进行 (%{modifierKey}[)"
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr "å‡å°‘缩进行(%{modifier_key}[)"
+msgid "MarkdownEditor|header"
+msgstr "标题"
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr "æ”¯æŒ %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
@@ -25035,6 +25361,9 @@ msgstr "åˆå¹¶è¯·æ±‚和批准设置已移动。"
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr "åˆå¹¶è¯·æ±‚用于æ出对项目的更改并与他人进行讨论"
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr "如果状æ€æ£€æŸ¥æœªæˆåŠŸæˆ–ä»åœ¨è¿è¡Œï¼Œåˆ™æ— æ³•åˆå¹¶åˆå¹¶è¯·æ±‚。"
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr "将功能分支åˆå¹¶åˆ°ç›®æ ‡åˆ†æ”¯å¹¶ä¿®å¤ä»»ä½•å†²çªã€‚ %{linkStart}我该如何修å¤å®ƒä»¬ï¼Ÿ%{linkEnd}"
@@ -25260,6 +25589,9 @@ msgstr "方法"
msgid "Method call threshold (ms)"
msgstr "方法调用阈值(毫秒)"
+msgid "Metric"
+msgstr "指标"
+
msgid "Metric was successfully added."
msgstr "指标已æˆåŠŸæ·»åŠ ã€‚"
@@ -25649,6 +25981,9 @@ msgstr "里程碑截止日期"
msgid "Milestone lists not available with your current license"
msgstr "当å‰è®¸å¯è¯æ— æ³•ä½¿ç”¨é‡Œç¨‹ç¢‘列表"
+msgid "Milestone(s) not found: %{milestones}"
+msgstr "未找到里程碑:%{milestones}"
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr "æœç´¢é‡Œç¨‹ç¢‘时出错"
@@ -25808,6 +26143,9 @@ msgstr "%{percentage}%{percent} 完æˆ"
msgid "Min Value"
msgstr "最å°å€¼"
+msgid "Minimal Access"
+msgstr "最å°è®¿é—®æƒé™"
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr "在我们预先安排更多镜åƒä¹‹å‰å¯ç”¨çš„最å°å®¹é‡ã€‚"
@@ -25880,6 +26218,9 @@ msgstr "在您的个人资料中添加SSH密钥之å‰ï¼Œæ‚¨ä¸èƒ½é€šè¿‡SSHæ¥æ‹‰
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr "在您的个人资料中添加SSH密钥之å‰ï¼Œæ‚¨ä¸èƒ½é€šè¿‡SSHæ¥æ‹‰å–或推é€ä»“库。"
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr "没有è¦æ˜¾ç¤ºçš„实验"
+
msgid "ModalButton|Add projects"
msgstr "添加项目"
@@ -26066,6 +26407,9 @@ msgstr "ä¸æ”¯æŒå¤šä¸ªPrometheus集æˆ"
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr "应用于轮询间隔的乘数。支æŒå进制值。默认为 1。"
+msgid "Must be 90 days or more."
+msgstr "必须是 90 天或更长时间。"
+
msgid "My awesome group"
msgstr "我最棒的团队"
@@ -26524,6 +26868,9 @@ msgstr "无范围"
msgid "No Work Item Link found"
msgstr "未找到工作项链接"
+msgid "No access"
+msgstr "无访问æƒé™"
+
msgid "No active admin user found"
msgstr "没有找到活动的管ç†å‘˜ç”¨æˆ·"
@@ -26653,9 +27000,6 @@ msgstr "没有å¯æ˜¾ç¤ºè¿­ä»£"
msgid "No job log"
msgstr "没有作业日志"
-msgid "No jobs to show"
-msgstr "没有è¦æ˜¾ç¤ºçš„作业"
-
msgid "No label"
msgstr "无标记"
@@ -26683,9 +27027,6 @@ msgstr "没有匹é…的结果"
msgid "No matching results for \"%{query}\""
msgstr "没有与“%{query}â€åŒ¹é…的结果"
-msgid "No matching results..."
-msgstr "无匹é…结果..."
-
msgid "No members found"
msgstr "未找到æˆå‘˜"
@@ -26701,9 +27042,6 @@ msgstr "未记录任何消æ¯"
msgid "No milestone"
msgstr "无里程碑"
-msgid "No namespace"
-msgstr "没有命å空间"
-
msgid "No other labels with such name or description"
msgstr "没有其他具有此类å称或æ述的标记"
@@ -26814,7 +27152,7 @@ msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{stron
msgstr[0] "ä¸ç”¨æ‹…心,您现在ä»ç„¶å¯ä»¥ä½¿ç”¨æ‰€æœ‰ %{strong}%{plan_name}%{strong_close} 功能。您有 %{remaining_days} 天æ¥ç»­è®¢æ‚¨çš„订阅。"
msgid "No wrap"
-msgstr ""
+msgstr "æ— æ¢è¡Œ"
msgid "No. of commits"
msgstr "æ交次数"
@@ -26936,8 +27274,8 @@ msgstr "收起回å¤"
msgid "Notes|Expand replies"
msgstr "展开回å¤"
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
-msgstr "内部备注åªå¯¹ä½œè€…ã€æŒ‡æ´¾äººå’Œå…·æœ‰æŠ¥å‘Šäººæˆ–更高角色的æˆå‘˜å¯è§"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
+msgstr "内部备注åªå¯¹å…·æœ‰æŠ¥å‘Šè€…或更高角色的æˆå‘˜å¯è§"
msgid "Notes|Last reply by %{name}"
msgstr "最åŽå›žå¤è€…为 %{name}"
@@ -27267,6 +27605,9 @@ msgstr "新建议题:%{project_issue_url}"
msgid "Notify|No preview for this file type"
msgstr "无法预览此类型文件"
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr "æµæ°´çº¿ #%{pipeline_id} 失败ï¼"
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr "æµæ°´çº¿ %{pipeline_link} 的触å‘者为"
@@ -27276,6 +27617,9 @@ msgstr "æµæ°´çº¿å·²ä¿®å¤ï¼Œ#%{pipeline_id} 已通过ï¼"
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr "项目 %{old_path_with_namespace} 被移动到å¦ä¸€ä¸ªä½ç½®ã€‚"
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr "项目 %{project_name} 无法导出。"
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr "项目 %{project_name} å·²æˆåŠŸå¯¼å‡ºã€‚"
@@ -27297,6 +27641,9 @@ msgstr "未包å«å·®å¼‚,因为它太大。"
msgid "Notify|The download link will expire in 24 hours."
msgstr "下载链接将于24å°æ—¶åŽè¿‡æœŸã€‚"
+msgid "Notify|The errors we encountered were:"
+msgstr "我们é‡åˆ°çš„错误是:"
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr "该项目现在ä½äºŽ %{project_full_name_link_start}%{project_full_name}%{link_end}下。"
@@ -27390,9 +27737,6 @@ msgstr "员工人数"
msgid "Number of events"
msgstr "事件数é‡"
-msgid "Number of events for this project: %{total_count}."
-msgstr "此项目的事件数é‡: %{total_count}。"
-
msgid "Number of files touched"
msgstr "改动的文件数"
@@ -27417,9 +27761,6 @@ msgstr "10月"
msgid "October"
msgstr "10月"
-msgid "OfSearchInADropdown|Filter"
-msgstr "过滤"
-
msgid "Off"
msgstr "关闭"
@@ -27652,12 +27993,6 @@ msgstr "无法获å–站点é…置文件。请刷新页é¢æˆ–ç¨åŽå†è¯•ã€‚"
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr "无法è¿è¡Œæ‰«æ。请é‡è¯•ã€‚"
-msgid "OnDemandScans|Create new scanner profile"
-msgstr "创建新的扫æ工具é…置文件"
-
-msgid "OnDemandScans|Create new site profile"
-msgstr "创建新的站点é…置文件"
-
msgid "OnDemandScans|DAST configuration"
msgstr "DAST é…ç½®"
@@ -27703,12 +28038,6 @@ msgstr "例如:测试SQL注入的登录页é¢"
msgid "OnDemandScans|Keep editing"
msgstr "继续编辑"
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr "管ç†æ‰«æ工具é…置文件"
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr "管ç†ç«™ç‚¹é…置文件"
-
msgid "OnDemandScans|My daily scan"
msgstr "我的æ¯æ—¥æ‰«æ"
@@ -27730,12 +28059,6 @@ msgstr "新建扫æ"
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr "未找到 DAST çš„ %{profileType} é…置文件"
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr "å°šæ— é…置文件。如需创建新扫æ,需è¦è‡³å°‘有一个完整的扫æ工具é…置文件。"
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr "å°šæ— é…置文件。如需创建新扫æ,需è¦è‡³å°‘有一个完整的站点é…置文件。"
-
msgid "OnDemandScans|On-demand Scans"
msgstr "按需扫æ"
@@ -27778,15 +28101,6 @@ msgstr "扫æ计划"
msgid "OnDemandScans|Scan type"
msgstr "扫æ类型"
-msgid "OnDemandScans|Scanner profile"
-msgstr "扫æ工具é…ç½®"
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr "选择一个现有的é…置文件"
-
-msgid "OnDemandScans|Site profile"
-msgstr "站点é…ç½®"
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr "开始创建一个新的é…置文件。é…置文件å¯ä»¥æ–¹ä¾¿ä¿å­˜å’Œé‡ç”¨å®‰å…¨å·¥å…·çš„é…置细节。"
@@ -27817,12 +28131,6 @@ msgstr "没有计划中的扫æ。"
msgid "OnDemandScans|Timezone"
msgstr "时区"
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr "使用现有的站点é…ç½®"
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr "使用现有的站点é…置文件"
-
msgid "OnDemandScans|View results"
msgstr "查看结果"
@@ -27841,9 +28149,6 @@ msgstr "仓库导入åŽï¼Œå¯ä»¥é€šè¿‡SSH进行镜åƒã€‚点击%{link_start}æ­¤å¤
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr "删除åŽå°†æ— æ³•æ¢å¤æ´¾ç”Ÿå…³ç³»ã€‚此项目将无法å†å‘æºé¡¹ç›®æˆ–其他派生å‘é€æˆ–接收åˆå¹¶è¯·æ±‚。"
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr "一旦您确认并点击\"é™ä½Žé¡¹ç›®å¯è§æ€§\":"
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] "其余%d项"
@@ -28016,9 +28321,6 @@ msgstr "æ“作失败。请检查 Pod 日志 %{pod_name} 了解更多信æ¯ã€‚"
msgid "Operation not allowed"
msgstr "ä¸å…许此æ“作"
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr "æ“作超时。请检查 Pod 日志 %{pod_name} 了解更多信æ¯ã€‚"
-
msgid "Operations"
msgstr "è¿ç»´"
@@ -28386,12 +28688,21 @@ msgstr "删除软件包"
msgid "PackageRegistry|Delete package asset"
msgstr "删除软件包 asset"
+msgid "PackageRegistry|Delete package version"
+msgstr "删除软件包版本"
+
msgid "PackageRegistry|Delete selected"
msgstr "删除选中"
msgid "PackageRegistry|Delete this package"
msgstr "删除此软件包"
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr "删除所有软件包 assets 将删除 %{name} çš„ %{version} 版本。您确定å—?"
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr "删除最åŽä¸€ä¸ªè½¯ä»¶åŒ… assets 将删除 %{name} çš„ %{version} 版本。您确定å—?"
+
msgid "PackageRegistry|Duplicate packages"
msgstr "é‡å¤çš„软件包"
@@ -28437,6 +28748,12 @@ msgstr "Gradle Kotlin DSL安装命令"
msgid "PackageRegistry|Helm"
msgstr "Helm"
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr "帮助我们了解您的仓库è¿ç§»éœ€æ±‚"
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr "如果您有兴趣将软件包从您的ç§äººåº“è¿ç§»åˆ° GitLab 软件包库,å‚加我们的调查并告诉我们您的更多需求。"
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr "如果尚未é…置,需è¦å°†ä»¥ä¸‹å†…容添加到%{codeStart}.pypirc%{codeEnd}文件中。"
@@ -28508,7 +28825,7 @@ msgid "PackageRegistry|Package updated by commit %{link} on branch %{branch}, bu
msgstr "软件包由分支%{branch}上的%{link}æ交所更新,由æµæ°´çº¿%{pipeline}构建并于%{datetime}å‘布到库"
msgid "PackageRegistry|Permanently delete"
-msgstr ""
+msgstr "永久删除"
msgid "PackageRegistry|Permanently delete assets"
msgstr "永久删除 assets"
@@ -28582,6 +28899,9 @@ msgstr "对ä¸èµ·ï¼Œæ²¡æœ‰ç¬¦åˆç­›é€‰å™¨çš„任何结果"
msgid "PackageRegistry|Source project located at %{link}"
msgstr "æºé¡¹ç›®ä½äºŽ%{link}"
+msgid "PackageRegistry|Take survey"
+msgstr "å‚加调查"
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr "目标 SHA:%{sha}"
@@ -28622,7 +28942,7 @@ msgid "PackageRegistry|You are about to delete %{filename}. This is a destructiv
msgstr "您将è¦åˆ é™¤ %{filename}。这是一ç§ç ´å性æ“作,å¯èƒ½ä¼šä½¿æ‚¨çš„包无法使用。您确定å—?"
msgid "PackageRegistry|You are about to delete %{name}, are you sure?"
-msgstr ""
+msgstr "您将è¦åˆ é™¤ %{name},您确定å—?"
msgid "PackageRegistry|You are about to delete 1 asset. This operation is irreversible."
msgid_plural "PackageRegistry|You are about to delete %d assets. This operation is irreversible."
@@ -28964,12 +29284,6 @@ msgstr "墙"
msgid "Period in seconds"
msgstr "周期(秒)"
-msgid "Period of inactivity (days)"
-msgstr "ä¸æ´»åŠ¨æ—¶é•¿ï¼ˆå¤©æ•°ï¼‰"
-
-msgid "Period of inactivity before deactivation."
-msgstr "åœç”¨å‰çš„ä¸æ´»åŠ¨æ—¶é—´ã€‚"
-
msgid "Permalink"
msgstr "永久链接"
@@ -29018,8 +29332,8 @@ msgstr "PhabricatoræœåŠ¡å™¨å¯¼å…¥"
msgid "Phabricator Server URL"
msgstr "PharibatoræœåŠ¡å™¨URL"
-msgid "Phabricator Tasks"
-msgstr "Phabricator任务"
+msgid "Phabricator tasks"
+msgstr "Phabricator 任务"
msgid "Phone"
msgstr "电è¯"
@@ -29237,20 +29551,26 @@ msgstr "å·²å¯ç”¨"
msgid "PipelineSchedules|All"
msgstr "所有"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr "确定è¦åˆ é™¤æ­¤æµæ°´çº¿è®¡åˆ’å—?"
+
msgid "PipelineSchedules|Delete pipeline schedule"
-msgstr ""
+msgstr "删除æµæ°´çº¿è®¡åˆ’"
msgid "PipelineSchedules|Description"
-msgstr ""
+msgstr "æè¿°"
msgid "PipelineSchedules|Edit pipeline schedule"
-msgstr ""
+msgstr "编辑æµæ°´çº¿è®¡åˆ’"
msgid "PipelineSchedules|Inactive"
msgstr "未å¯ç”¨"
msgid "PipelineSchedules|Last Pipeline"
-msgstr ""
+msgstr "最近的æµæ°´çº¿"
+
+msgid "PipelineSchedules|New schedule"
+msgstr "新建计划"
msgid "PipelineSchedules|Next Run"
msgstr "下次è¿è¡Œæ—¶é—´"
@@ -29262,25 +29582,37 @@ msgid "PipelineSchedules|Only the owner of a pipeline schedule can make changes
msgstr "åªæœ‰æµæ°´çº¿è®¡åˆ’的所有者å¯ä»¥å¯¹å…¶è¿›è¡Œæ›´æ”¹ã€‚你想è¦èŽ·å¾—计划的所有æƒå—?"
msgid "PipelineSchedules|Owner"
-msgstr ""
+msgstr "所有者"
+
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr "æµæ°´çº¿è®¡åˆ’å·²æˆåŠŸåˆ é™¤ã€‚"
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "为此æµæ°´çº¿æ供简短æè¿°"
msgid "PipelineSchedules|Run pipeline schedule"
-msgstr ""
+msgstr "è¿è¡Œæµæ°´çº¿è®¡åˆ’"
+
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr "æˆåŠŸä»Ž %{owner} å–得所有æƒã€‚"
msgid "PipelineSchedules|Take ownership"
msgstr "å–得所有æƒ"
msgid "PipelineSchedules|Take ownership of pipeline schedule"
-msgstr ""
+msgstr "å–å¾—æµæ°´çº¿è®¡åˆ’的所有æƒ"
msgid "PipelineSchedules|Target"
msgstr "目标"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr "删除æµæ°´çº¿è®¡åˆ’时出错。"
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
-msgstr ""
+msgstr "获å–æµæ°´çº¿è®¡åˆ’时出错。"
+
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr "获å–æµæ°´çº¿è®¡åˆ’的所有æƒæ—¶å‡ºé”™ã€‚"
msgid "PipelineSchedules|Variables"
msgstr "å˜é‡"
@@ -29397,7 +29729,7 @@ msgid "Pipelines|\"Hello world\" with GitLab CI"
msgstr "使用 GitLab CI 实现 \"Hello world\""
msgid "Pipelines|%{jobs} %{ref_text} in %{duration}"
-msgstr ""
+msgstr "%{jobs} %{ref_text} 用时 %{duration}"
msgid "Pipelines|(queued for %{queued_duration})"
msgstr "(已排队 %{queued_duration})"
@@ -30041,9 +30373,6 @@ msgstr "请选择一个Jira项目"
msgid "Please select a country"
msgstr "请选择国家/地区"
-msgid "Please select a file"
-msgstr "请选择一个文件"
-
msgid "Please select a group"
msgstr "请选择一个群组"
@@ -30152,6 +30481,69 @@ msgstr "检测到å¯èƒ½ä¸éœ€è¦çš„字符:Unicode BiDi Control"
msgid "Pre-defined push rules"
msgstr "预定义推é€è§„则"
+msgid "PreScanVerification|(optional)"
+msgstr "(å¯é€‰ï¼‰"
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr "å°è¯•å¯¹æ‰«æ目标进行身份验è¯"
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr "å°è¯•æŸ¥æ‰¾å¹¶è¿žæŽ¥åˆ°æ‰«æ目标"
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr "å°è¯•è·Ÿè¸ªå†…部链接并抓å–3个无错误页é¢"
+
+msgid "PreScanVerification|Authentication"
+msgstr "身份验è¯"
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr "å–消预扫æ验è¯"
+
+msgid "PreScanVerification|Connection"
+msgstr "连接"
+
+msgid "PreScanVerification|Download results"
+msgstr "下载结果"
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr "在æµæ°´çº¿ä¸­æœ€åŽè¿è¡ŒäºŽ %{timeAgo} "
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr "预扫æ验è¯"
+
+msgid "PreScanVerification|Save and run verification"
+msgstr "ä¿å­˜å¹¶è¿è¡ŒéªŒè¯"
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr "在æµæ°´çº¿ä¸­å¼€å§‹äºŽ %{timeAgo}"
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr "在è¿è¡Œå®Œæ•´æ‰«æå‰æµ‹è¯•æ‚¨çš„é…置并识别潜在错误。"
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr "验è¯æ£€æŸ¥"
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr "验è¯æ£€æŸ¥ç”±æ‰«æçš„é…置细节决定。更改é…置细节å¯èƒ½æ›´æ”¹æˆ–é‡ç½®éªŒè¯æ£€æŸ¥åŠå…¶çŠ¶æ€ã€‚"
+
+msgid "PreScanVerification|Verify configuration"
+msgstr "验è¯é…ç½®"
+
+msgid "PreScanVerification|View results"
+msgstr "查看结果"
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr "在开始预扫æ验è¯ä¹‹å‰ï¼Œæ‚¨å¿…须先填写扫æé…ç½®"
+
msgid "Preferences"
msgstr "å好设置"
@@ -30159,7 +30551,7 @@ msgid "Preferences saved."
msgstr "å好设置已ä¿å­˜ã€‚"
msgid "Preferences|Automatically add new list items"
-msgstr ""
+msgstr "自动添加新列表项"
msgid "Preferences|Behavior"
msgstr "个性化"
@@ -30273,7 +30665,7 @@ msgid "Preferences|Use relative times"
msgstr "使用相对时间"
msgid "Preferences|When you type in a description or comment box, pressing %{kbdOpen}Enter%{kbdClose} in a list adds a new item below."
-msgstr ""
+msgstr "当您在æ述或评论框中键入时,按列表中的 %{kbdOpen}Enter%{kbdClose},会在下é¢æ·»åŠ ä¸€ä¸ªæ–°é¡¹ã€‚"
msgid "Preferences|When you type in a description or comment box, selected text is surrounded by the corresponding character after typing one of the following characters: %{supported_characters}."
msgstr "当您在æ述或评论框中键入时,在键入以下字符之一åŽï¼Œé€‰å®šçš„文本将被相应的字符包围:%{supported_characters}。"
@@ -30293,6 +30685,9 @@ msgstr "ç¦æ­¢åœ¨é¡¹ç›®å’Œåˆå¹¶è¯·æ±‚中编辑批准规则。"
msgid "Prevent environment from auto-stopping"
msgstr "防止环境自动终止"
+msgid "Prevent outdated deployment jobs"
+msgstr "阻止已过时的部署作业"
+
msgid "Prevent project forking outside current group"
msgstr "阻止项目派生到当å‰ç¾¤ç»„以外"
@@ -30386,12 +30781,18 @@ msgstr "%{name} 命令出错: %{message}。"
msgid "Proceed"
msgstr "继续"
-msgid "Product Analytics"
-msgstr "产å“分æž"
+msgid "Product analytics"
+msgstr "生产力分æž"
+
+msgid "ProductAnalytics|Audience"
+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|Widgets content"
+msgstr "部件内容"
+
msgid "Productivity"
msgstr "效率"
@@ -30968,6 +31369,9 @@ msgstr "项目å称"
msgid "Project navigation"
msgstr "项目导航"
+msgid "Project or Group"
+msgstr "项目或群组"
+
msgid "Project order will not be saved as local storage is not available."
msgstr "由于本地存储ä¸å¯ç”¨ï¼Œå› æ­¤ä¸ä¼šä¿å­˜é¡¹ç›®é¡ºåºã€‚"
@@ -30980,6 +31384,9 @@ msgstr "项目安全状æ€"
msgid "Project security status help page"
msgstr "项目安全状æ€å¸®åŠ©é¡µé¢"
+msgid "Project settings were successfully updated."
+msgstr "项目设置已æˆåŠŸæ›´æ–°ã€‚"
+
msgid "Project slug"
msgstr "项目标识串"
@@ -31262,12 +31669,18 @@ msgstr "%{link_start}什么是æ述模æ¿ï¼Ÿ%{link_end}"
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr "%{link_start}我å¯ä»¥ä½¿ç”¨å“ªäº›å˜é‡ï¼Ÿ%{link_end}"
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr "ä¸èƒ½ä¸ºç©ºé¡¹ç›®é€‰æ‹©é»˜è®¤åˆ†æ”¯ã€‚"
+
msgid "ProjectSettings|Additional options"
msgstr "其他选项"
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr "å½±å“åˆå¹¶å®Œæˆçš„æ–¹å¼å’Œæ—¶é—´çš„其他设置。"
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr "除éžæ‚¨æŒ‡å®šä¸åŒçš„分支,å¦åˆ™æ‰€æœ‰åˆå¹¶è¯·æ±‚å’Œæ交都是针对此分支进行的。"
+
msgid "ProjectSettings|All threads must be resolved"
msgstr "必须解决所有主题"
@@ -31280,12 +31693,18 @@ msgstr "始终在议题ã€åˆå¹¶è¯·æ±‚和代ç ç‰‡æ®µä¸Šæ˜¾ç¤ºèµžè®¸å’Œä¸èµžè®¸
msgid "ProjectSettings|Analytics"
msgstr "分æž"
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr "自动关闭默认分支上的引用议题"
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr "自动解决åˆå¹¶è¯·æ±‚差异主题过期时的åˆå¹¶è¯·æ±‚"
msgid "ProjectSettings|Badges"
msgstr "徽章"
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr "从议题创建的分支éµå¾ªæ­¤æ ·å¼ã€‚"
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr "构建ã€æµ‹è¯•å’Œéƒ¨ç½²æ‚¨çš„更改。"
@@ -31307,6 +31726,9 @@ msgstr "选择您的åˆå¹¶æ–¹æ³•ã€é€‰é¡¹ã€æ£€æŸ¥å’ŒåŽ‹ç¼©é€‰é¡¹ã€‚"
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr "å°† git 标签与å‘布说明ã€å‘布 evidence å’Œ assets 相结åˆæ¥åˆ›å»ºå‘布。"
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr "é…置您的基础设施。"
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr "é…置您的项目资æºå¹¶ç›‘控它们的è¿è¡ŒçŠ¶å†µã€‚"
@@ -31406,6 +31828,9 @@ msgstr "它们之间有何差异?"
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr "如果å¯ç”¨äº†åˆå¹¶é˜Ÿåˆ—,则åªæœ‰åœ¨å¯ä»¥é‡æ–°è®¾ç½®åˆ†æ”¯è€Œä¸å‘生冲çªçš„情况下æ‰èƒ½è¿›è¡Œåˆå¹¶ã€‚"
+msgid "ProjectSettings|Infrastructure"
+msgstr "基础设施"
+
msgid "ProjectSettings|Internal"
msgstr "内部"
@@ -31473,7 +31898,7 @@ msgid "ProjectSettings|Note: The container registry is always visible when a pro
msgstr "注æ„:当项目是公共的并且容器镜åƒåº“设置为“%{access_level_description}â€æ—¶ï¼Œå®¹å™¨é•œåƒåº“始终å¯è§"
msgid "ProjectSettings|Only commits that include a %{code_block_start}Signed-off-by:%{code_block_end} element can be pushed to this repository."
-msgstr ""
+msgstr "åªæœ‰åŒ…å« %{code_block_start}Signed-off-by:%{code_block_end} 元素的æ交æ‰èƒ½æŽ¨é€åˆ°æ­¤ä»“库。"
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr "åªæœ‰å·²ç­¾ç½²æ交æ‰å¯ä»¥æŽ¨é€åˆ°æ­¤ä»“库。"
@@ -31544,6 +31969,9 @@ msgstr "安全与åˆè§„"
msgid "ProjectSettings|Security & Compliance for this project"
msgstr "此项目的安全与åˆè§„"
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr "选择此项目的默认分支并é…置分支å称模æ¿ã€‚"
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr "在åˆå¹¶è¯·æ±‚中设置此选项的默认行为。对此的更改也适用于现有的åˆå¹¶è¯·æ±‚。"
@@ -31574,6 +32002,9 @@ msgstr "始终执行压缩。å¤é€‰æ¡†æ˜¯å¯è§çš„并处于选中状æ€ï¼Œç”¨æˆ·
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr "永远ä¸ä¼šæ‰§è¡ŒåŽ‹ç¼©ï¼Œå¹¶ä¸”该å¤é€‰æ¡†æ˜¯éšè—的。"
+msgid "ProjectSettings|Status checks must succeed"
+msgstr "状æ€æ£€æŸ¥å¿…é¡»æˆåŠŸ"
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr "æ交è¦åˆå¹¶åˆ°ä¸Šæ¸¸çš„更改。"
@@ -31625,6 +32056,9 @@ msgstr "用户å¯ä»¥å°†ä»“库å¤åˆ¶åˆ°æ–°é¡¹ç›®ã€‚"
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr "如果æ交者电å­é‚®ä»¶æ˜¯ä»–们自己的已验è¯ç”µå­é‚®ä»¶ä¹‹ä¸€ï¼Œç”¨æˆ·åªèƒ½å°†æ交推é€åˆ°æ­¤ä»“库。"
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr "用户å¯ä»¥è¯·æ±‚访问"
@@ -32264,6 +32698,9 @@ msgstr "å…许所有具有推é€è®¿é—®æƒé™çš„用户%{tag_start}强制推é€%{t
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr "å…许所有具有推é€è®¿é—®æƒé™çš„用户强制推é€ã€‚"
+msgid "ProtectedBranch|Allowed to create"
+msgstr "å…许创建"
+
msgid "ProtectedBranch|Allowed to force push"
msgstr "å…许强制推é€"
@@ -32300,15 +32737,27 @@ msgstr "默认情况下,å—ä¿æŠ¤åˆ†æ”¯é™åˆ¶è°å¯ä»¥ä¿®æ”¹åˆ†æ”¯ã€‚"
msgid "ProtectedBranch|Code owner approval"
msgstr "代ç æ‰€æœ‰è€…批准"
+msgid "ProtectedBranch|Create wildcard"
+msgstr "创建通é…符"
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr "ä¸é€‚用于å…许推é€çš„用户。ä¸å¼ºåˆ¶æ‰§è¡Œå¯é€‰éƒ¨åˆ†ã€‚"
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr "ä¿æŒç¨³å®šçš„分支安全并强制开å‘人员使用åˆå¹¶è¯·æ±‚。"
+msgid "ProtectedBranch|Last commit"
+msgstr "最åŽæ交"
+
msgid "ProtectedBranch|Learn more."
msgstr "了解更多。"
+msgid "ProtectedBranch|New Protected Tag"
+msgstr "新建å—ä¿æŠ¤æ ‡ç­¾"
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr "没有标签å—到ä¿æŠ¤ã€‚"
+
msgid "ProtectedBranch|Protect"
msgstr "ä¿æŠ¤"
@@ -32324,12 +32773,21 @@ msgstr "å—ä¿æŠ¤åˆ†æ”¯"
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr "å—ä¿æŠ¤åˆ†æ”¯ã€åˆå¹¶è¯·æ±‚批准以åŠçŠ¶æ€æ£€æŸ¥å°†åœ¨é…ç½®åŽæ˜¾ç¤ºã€‚"
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr "å—ä¿æŠ¤æ ‡ç­¾ï¼ˆ%{tags_count})"
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr "æ‹’ç»ä»£ç æŽ¨é€æ›´æ”¹ CODEOWNERS 文件中列出的文件。"
msgid "ProtectedBranch|Require approval from code owners:"
msgstr "需è¦ä»£ç æ‰€æœ‰è€…的批准:"
+msgid "ProtectedBranch|Search protected tags"
+msgstr "æœç´¢å—ä¿æŠ¤æ ‡ç­¾"
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr "选择标签或创建通é…符"
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr "当å‰æ²¡æœ‰å—ä¿æŠ¤çš„分支,请使用上述表å•æ¥ä¿æŠ¤åˆ†æ”¯ã€‚"
@@ -32607,7 +33065,7 @@ msgid "PushRules|Reject any files likely to contain secrets. %{secret_files_link
msgstr "æ‹’ç»ä»»ä½•å¯èƒ½åŒ…å« secret 的文件。 %{secret_files_link_start}哪些 secret 文件会被拒ç»ï¼Ÿ%{secret_files_link_end}"
msgid "PushRules|Reject commits that aren't DCO certified"
-msgstr ""
+msgstr "æ‹’ç»ä¸æ˜¯ DCO 认è¯çš„æ交"
msgid "PushRules|Reject expression in commit messages"
msgstr "æ交消æ¯ä¸­çš„æ‹’ç»è¡¨è¾¾å¼"
@@ -32639,6 +33097,9 @@ msgstr "用户ä»ç„¶å¯ä»¥é€šè¿‡UI删除标签。"
msgid "PushRule|Push rules"
msgstr "推é€è§„则"
+msgid "PushRule|Reject inconsistent user name"
+msgstr "æ‹’ç»ä¸ä¸€è‡´çš„用户å"
+
msgid "PushRule|Reject unverified users"
msgstr "æ‹’ç»æœªç»éªŒè¯çš„用户"
@@ -32771,12 +33232,6 @@ msgstr "进一步了解"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr "在%{link_to_promo}上阅读更多关于 GitLab çš„ä¿¡æ¯ã€‚"
-msgid "Read more about related epics"
-msgstr "阅读更多关于相关å²è¯—çš„ä¿¡æ¯"
-
-msgid "Read more about related issues"
-msgstr "了解更多关于相关议题的信æ¯"
-
msgid "Read their documentation."
msgstr "阅读他们的文档。"
@@ -32870,9 +33325,6 @@ msgstr "é™ä½Žé¡¹ç›®å¯è§æ€§"
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr "通过安全培训é™ä½Žé£Žé™©å¹¶å‡å°‘æ¼æ´žç±»åž‹"
-msgid "Reduce this project’s visibility?"
-msgstr "é™ä½Žæ­¤é¡¹ç›®å¯è§æ€§å—?"
-
msgid "Reference"
msgstr "å‚考"
@@ -33034,6 +33486,9 @@ msgstr[0] "å‘è¡Œ"
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr "å‘布 %{deletedRelease} å·²æˆåŠŸåˆ é™¤ã€‚"
+msgid "Release already exists"
+msgstr "å‘布已存在"
+
msgid "Release assets"
msgstr "å‘布资æº"
@@ -33043,6 +33498,9 @@ msgstr "å‘布资æºæ–‡æ¡£"
msgid "Release date"
msgstr "å‘布日期"
+msgid "Release does not exist"
+msgstr "å‘布ä¸å­˜åœ¨"
+
msgid "Release does not have the same project as the milestone"
msgstr "å‘布与里程碑的项目ä¸åŒ"
@@ -33499,6 +33957,9 @@ msgstr "报告人"
msgid "Reported by %{reporter}"
msgstr "由%{reporter}报告"
+msgid "Reporter"
+msgstr "报告者"
+
msgid "Reporting"
msgstr "报告"
@@ -33512,10 +33973,6 @@ msgid "Reports|%{recentlyFailed} out of %{failed} failed tests has failed more t
msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days"
msgstr[0] "在过去的14天中,在%{failed}个测试中有%{recentlyFailed}个失败了一次以上"
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] "æ— éšœç¢æ€§æ‰«æ检测到%d个仅存在于æºåˆ†æ”¯çš„问题"
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] "æ— éšœç¢æ€§æ‰«æ检测到 %{strong_start}%{number}%{strong_end} 个仅针对æºåˆ†æ”¯çš„问题"
@@ -33544,18 +34001,12 @@ msgstr "加载报告时出错"
msgid "Reports|Base report parsing error:"
msgstr "基础报告分æžé”™è¯¯ï¼š"
-msgid "Reports|Classname"
-msgstr "ç±»å"
-
msgid "Reports|Copy failed test names to run locally"
msgstr "å¤åˆ¶å¤±è´¥çš„测试å称到本地è¿è¡Œ"
msgid "Reports|Copy failed tests"
msgstr "å¤åˆ¶å¤±è´¥çš„测试"
-msgid "Reports|Execution time"
-msgstr "执行时间"
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] "过去14天中在%{baseBranch}上,失败了%{count} 次"
@@ -33564,12 +34015,6 @@ msgid "Reports|Failed %{count} time in %{base_branch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 days"
msgstr[0] "过去14天中在%{base_branch}上,失败了%{count} 次"
-msgid "Reports|Failure"
-msgstr "失败"
-
-msgid "Reports|Filename"
-msgstr "文件å"
-
msgid "Reports|Fixed"
msgstr "已修å¤"
@@ -33612,21 +34057,12 @@ msgstr "扫æ工具"
msgid "Reports|Severity"
msgstr "严é‡çº§åˆ«"
-msgid "Reports|System output"
-msgstr "系统输出"
-
msgid "Reports|Test summary"
msgstr "测试总结报告"
-msgid "Reports|Test summary failed loading results"
-msgstr "测试总结报告加载失败"
-
msgid "Reports|Test summary failed to load results"
msgstr "测试摘è¦åŠ è½½ç»“果失败"
-msgid "Reports|Test summary results are being parsed"
-msgstr "测试总结报告解æžä¸­"
-
msgid "Reports|Test summary results are loading"
msgstr "测试摘è¦ç»“果正在加载"
@@ -33642,9 +34078,6 @@ msgstr "æ¼æ´žå称"
msgid "Reports|metrics report"
msgstr "指标报告"
-msgid "Reports|no changed test results"
-msgstr "未å‘生å˜åŒ–的测试结果"
-
msgid "Repositories"
msgstr "仓库"
@@ -33801,7 +34234,7 @@ msgid "Repository mirroring configuration"
msgstr "仓库镜åƒé…ç½®"
msgid "Repository mirroring has been paused due to too many failed attempts. It can be resumed by a project maintainer or owner."
-msgstr ""
+msgstr "由于å°è¯•å¤±è´¥æ¬¡æ•°è¿‡å¤šï¼Œä»“库镜åƒå·²æš‚åœï¼Œå¯ä»¥ç”±é¡¹ç›®ç»´æŠ¤è€…或所有者æ¢å¤ã€‚"
msgid "Repository must contain at least 1 file."
msgstr "仓库必须包å«è‡³å°‘1个文件。"
@@ -34012,6 +34445,9 @@ msgstr "解决者"
msgid "Resolved by %{name}"
msgstr "由%{name}解决"
+msgid "Resource link added"
+msgstr "资æºé“¾æŽ¥å·²æ·»åŠ "
+
msgid "Response"
msgstr "å“应"
@@ -34239,6 +34675,9 @@ msgstr "使用 Jenkins è¿è¡Œ CI/CD æµæ°´çº¿ã€‚"
msgid "Run housekeeping"
msgstr "è¿è¡Œä¾‹è¡Œç»´æŠ¤"
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr "è¿è¡Œä¾‹è¡Œç»´æŠ¤ä»»åŠ¡æ¥è‡ªåŠ¨ä¼˜åŒ– Git 仓库。ç¦ç”¨æ­¤é€‰é¡¹å°†å¯¼è‡´æ€§èƒ½éšç€æ—¶é—´çš„推移而下é™ã€‚"
+
msgid "Run manual or delayed jobs"
msgstr "è¿è¡Œæ‰‹åŠ¨æˆ–延迟的作业"
@@ -34276,6 +34715,9 @@ msgid "Runners|%d selected runner deleted"
msgid_plural "Runners|%d selected runners deleted"
msgstr[0] "%d 个选定的 runners 已删除"
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr "%{link_start}这些 runners%{link_end} 适用于所有群组和项目。"
+
msgid "Runners|%{percentage} spot."
msgstr "%{percentage} 点。"
@@ -34302,8 +34744,8 @@ msgstr "å¯ç”¨"
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr "添加备注,比如è°æ‹¥æœ‰ runner,或者它应该用于什么目的。"
-msgid "Runners|Add your feedback in the issue"
-msgstr "在议题中添加您的å馈"
+msgid "Runners|Administrator"
+msgstr "管ç†å‘˜"
msgid "Runners|All"
msgstr "全部"
@@ -34433,7 +34875,7 @@ msgid "Runners|Group"
msgstr "群组"
msgid "Runners|How do runners pick up jobs?"
-msgstr ""
+msgstr "Runners 如何挑选作业?"
msgid "Runners|How do we upgrade GitLab runner?"
msgstr "我们如何å‡çº§ GitLab runner?"
@@ -34510,6 +34952,9 @@ msgstr "在线"
msgid "Runners|Online:"
msgstr "在线:"
+msgid "Runners|Owner"
+msgstr "所有者"
+
msgid "Runners|Pause from accepting jobs"
msgstr "æš‚åœæŽ¥å—作业"
@@ -34548,7 +34993,7 @@ msgid "Runners|Register an instance runner"
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 ""
+msgstr "注册尽å¯èƒ½å¤šçš„ runner。您å¯ä»¥ç”¨å•ç‹¬çš„用户,或者在ä¸åŒçš„æœåŠ¡å™¨æˆ–者本地计算机上注册 runner。"
msgid "Runners|Registration token"
msgstr "注册令牌"
@@ -34632,14 +35077,20 @@ msgid "Runners|Runners"
msgstr "Runner"
msgid "Runners|Runners are either:"
-msgstr ""
+msgstr "Runners 是:"
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr "Runners 是è¿è¡Œ CI/CD 作业的代ç†ã€‚按照 %{linkStart}安装和注册指å—%{linkEnd} æ¥è®¾ç½®ä¸€ä¸ª runner。"
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr "Runners 是è¿è¡Œ CI/CD 作业的代ç†ã€‚è¦æ³¨å†Œæ–°çš„ runners,请è”系您的管ç†å‘˜ã€‚"
+
msgid "Runners|Runs untagged jobs"
msgstr "è¿è¡Œæœªæ ‡è®°çš„作业"
+msgid "Runners|Select all"
+msgstr "选择所有"
+
msgid "Runners|Select projects to assign to this runner"
msgstr "选择è¦åˆ†é…给此 runner 的项目"
@@ -34647,7 +35098,7 @@ msgid "Runners|Select your preferred option here. In the next step, you can choo
msgstr "在此选择您的首选选项。在下一步中,您å¯ä»¥åœ¨ AWS CloudFormation 控制å°ä¸­é€‰æ‹©æ‚¨çš„ runner 能力。"
msgid "Runners|Show only inherited"
-msgstr ""
+msgstr "åªæ˜¾ç¤ºç»§æ‰¿çš„"
msgid "Runners|Show runner installation and registration instructions"
msgstr "显示runner安装和注册说明"
@@ -34680,7 +35131,7 @@ msgid "Runners|Tags"
msgstr "标签"
msgid "Runners|Tags control which type of jobs a runner can handle. By tagging a runner, you make sure shared runners only handle the jobs they are equipped to run."
-msgstr ""
+msgstr "标签控制 runner å¯ä»¥å¤„ç†çš„作业类型。通过为 runner 打标签,您å¯ä»¥ç¡®ä¿å…±äº« runners åªå¤„ç†ä»–们准备è¿è¡Œçš„工作。"
msgid "Runners|Take me there!"
msgstr "带我去那里ï¼"
@@ -34688,6 +35139,9 @@ msgstr "带我去那里ï¼"
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr "新视图为您æ供更多空间并更好地了解 runner 队ä¼ã€‚"
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr "注册了 runner 的项目ã€ç¾¤ç»„或实例。实例 runners 始终归管ç†å‘˜æ‰€æœ‰ã€‚"
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr "Runner 将被永久删除,ä¸å†é€‚用于项目或群组。您确定è¦ç»§ç»­å—?"
@@ -34722,6 +35176,9 @@ msgstr "è¦æ³¨å†Œå®ƒä»¬ï¼Œè¯·è½¬åˆ°%{link_start}群组的 Runners 页é¢%{link_e
msgid "Runners|Token expiry"
msgstr "令牌过期"
+msgid "Runners|Unselect all"
+msgstr "å–消选择所有"
+
msgid "Runners|Up to date"
msgstr "最新"
@@ -34761,12 +35218,6 @@ msgstr "版本 %{version}"
msgid "Runners|View installation instructions"
msgstr "查看安装说明"
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr "我们希望您能够从此页é¢è½»æ¾æœ‰æ•ˆåœ°ç®¡ç† runners,我们正在åšå‡ºæ”¹å˜ä»¥å®žçŽ°ç›®æ ‡ã€‚就我们的表现给我们å馈ï¼"
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr "我们åšäº†ä¸€äº›æ”¹å˜ï¼Œå¸Œæœ›å¾—到您的å馈"
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr "Windows 2019 Shell,具有手动缩放和å¯é€‰è°ƒåº¦åŠŸèƒ½ã€‚ %{percentage} 点。"
@@ -34821,17 +35272,23 @@ msgstr "SAMLå‘现令牌"
msgid "SAML for %{group_name}"
msgstr "%{group_name} çš„ SAML"
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
-msgstr "选择“授æƒâ€ä¼šå°†æ‚¨çš„ GitLab 账户“%{username}â€(%{email}) 的所有æƒè½¬ç§»ç»™æ‚¨çš„组织。"
+msgid "SAML single sign-on"
+msgstr "SAML å•ç‚¹ç™»å½•"
+
+msgid "SAML single sign-on for %{group_name}"
+msgstr "%{group_name} çš„ SAML å•ç‚¹ç™»å½•"
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr "登录 GitLab 以连接您组织的å¸æˆ·"
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
-msgstr "群组“%{group_path}â€å…许您使用 SSO æ¥ç™»å½•å¸æˆ·ã€‚"
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr "%{strongOpen}%{group_path}%{strongClose} 群组å…许您使用å•ç‚¹ç™»å½•è¿›è¡Œç™»å½•ã€‚"
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr "è¦è®¿é—® %{strongOpen}%{group_name}%{strongClose},您必须通过外部登录页é¢ä½¿ç”¨å•ç‚¹ç™»å½•è¿›è¡Œç™»å½•ã€‚"
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
-msgstr "è¦è®¿é—®â€œ%{group_name}â€ï¼Œæ‚¨å¿…须使用您的å•ç‚¹ç™»å½•å¸æˆ·é€šè¿‡å¤–部登录页é¢ç™»å½•ã€‚"
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
+msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "您的组织的 SSO 已连接到您的 GitLab å¸æˆ·"
@@ -34938,12 +35395,12 @@ msgstr "ä¿å­˜ä¸­"
msgid "Saving project."
msgstr "正在ä¿å­˜é¡¹ç›®ã€‚"
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
-msgstr "%{ifLabelStart}如果%{ifLabelEnd} %{rules} æ“作用于 %{scopes} %{branches}"
-
msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr "%{period}%{days} 在 %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
+msgstr ""
+
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
msgstr "%{thenLabelStart}然åŽ%{thenLabelEnd} éœ€è¦ %{scan} 扫ææ‰èƒ½è¿è¡Œ"
@@ -34962,9 +35419,15 @@ msgstr "计划"
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr "计划规则组件"
+msgid "ScanExecutionPolicy|Select agent"
+msgstr "选择代ç†"
+
msgid "ScanExecutionPolicy|Select branches"
msgstr "选择分支"
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr "选择命å空间"
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr "选择扫æ器é…置文件"
@@ -34974,9 +35437,15 @@ msgstr "选择站点é…置文件"
msgid "ScanExecutionPolicy|Site profile"
msgstr "站点é…置文件"
+msgid "ScanExecutionPolicy|agent"
+msgstr "代ç†"
+
msgid "ScanExecutionPolicy|branch"
msgstr "分支"
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr "在命å空间中"
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr "%{ifLabelStart}如果%{ifLabelEnd} %{scanners} 在针对 %{branches} 的开放åˆå¹¶è¯·æ±‚中å‘现超过 %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} çš„æ¼æ´ž"
@@ -35089,7 +35558,7 @@ msgid "Search authors"
msgstr "æœç´¢ä½œè€…"
msgid "Search branch"
-msgstr ""
+msgstr "æœç´¢åˆ†æ”¯"
msgid "Search branches"
msgstr "æœç´¢åˆ†æ”¯"
@@ -35127,9 +35596,6 @@ msgstr "æœç´¢LDAP组"
msgid "Search for a group"
msgstr "æœç´¢ç¾¤ç»„"
-msgid "Search for a user"
-msgstr "æœç´¢ç”¨æˆ·"
-
msgid "Search for an emoji"
msgstr "æœç´¢ emoji"
@@ -35475,13 +35941,13 @@ msgid "SecurityConfiguration|Manage profiles for use by DAST scans."
msgstr "管ç†ä¾› DAST 扫æ使用的é…置文件。"
msgid "SecurityConfiguration|More scan types, including DAST, Dependency Scanning, Fuzzing, and Licence Compliance"
-msgstr ""
+msgstr "更多扫æ类型,包括 DAST,ä¾èµ–扫æ,模糊测试和许å¯è¯åˆè§„。"
msgid "SecurityConfiguration|Not enabled"
msgstr "未å¯ç”¨"
msgid "SecurityConfiguration|Once you've enabled a scan for the default branch, any subsequent feature branch you create will include the scan. An enabled scanner will not be reflected as such until the pipeline has been successfully executed and it has generated valid artifacts."
-msgstr ""
+msgstr "为默认分支å¯ç”¨æ‰«æåŽï¼Œæ‚¨åˆ›å»ºçš„任何åŽç»­åŠŸèƒ½åˆ†æ”¯éƒ½å°†åŒ…å«è¯¥æ‰«æ。在æµæ°´çº¿æˆåŠŸæ‰§è¡Œå¹¶ç”Ÿæˆæœ‰æ•ˆäº§ç‰©ä¹‹å‰ï¼Œå¯ç”¨çš„扫æ程åºä¸ä¼šè¢«å映。"
msgid "SecurityConfiguration|Quickly enable all continuous testing and compliance tools by enabling %{linkStart}Auto DevOps%{linkEnd}"
msgstr "%{linkStart}Auto DevOps%{linkEnd}快速å¯ç”¨æ‰€æœ‰æŒç»­æµ‹è¯•å’Œåˆè§„性工具"
@@ -35525,11 +35991,14 @@ msgstr "和 "
msgid "SecurityOrchestration| or "
msgstr "或 "
-msgid "SecurityOrchestration|%{branches} %{plural}"
-msgstr "%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
-msgstr "%{branches} 和 %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} branch"
+msgstr ""
msgid "SecurityOrchestration|%{scanners}"
msgstr "%{scanners}"
@@ -35648,6 +36117,9 @@ msgstr "继承"
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr "继承自 %{namespace}"
+msgid "SecurityOrchestration|Invalid policy"
+msgstr "无效策略"
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr "无效的策略类型"
@@ -35750,12 +36222,12 @@ msgstr "扫æ结果策略åªèƒ½ç”±é¡¹ç›®æ‰€æœ‰è€…创建。"
msgid "SecurityOrchestration|Scan result policy"
msgstr "扫æ结果策略"
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
-msgstr "è¦æ‰§è¡Œçš„扫æ %{cadence}"
-
msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr "扫æ %{cadence} 在 %{branches} 上执行"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
+msgstr ""
+
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
msgstr "在%{branches}上扫ææ¯ä¸ªæµæ°´çº¿"
@@ -35843,8 +36315,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
msgstr "使用扫æ结果策略创建规则,确ä¿åœ¨åˆå¹¶åˆå¹¶è¯·æ±‚之å‰æ£€æŸ¥å®‰å…¨é—®é¢˜ã€‚"
@@ -35861,6 +36333,9 @@ msgstr "一个"
msgid "SecurityOrchestration|all branches"
msgstr "所有分支"
+msgid "SecurityOrchestration|all namespaces"
+msgstr "所有命å空间"
+
msgid "SecurityOrchestration|an"
msgstr "一个"
@@ -35879,12 +36354,21 @@ msgstr "扫æ器å‘现"
msgid "SecurityOrchestration|the %{branches}"
msgstr "%{branches}"
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr "æ¼æ´ž"
msgid "SecurityOrchestration|vulnerability"
msgstr "æ¼æ´ž"
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr "策略无效或为空"
+
msgid "SecurityReports|%{count} Selected"
msgstr "已选择 %{count} 个"
@@ -35906,6 +36390,9 @@ msgstr "添加项目"
msgid "SecurityReports|All activity"
msgstr "所有活动"
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr "虽然没有æ¼æ´žçš„情况很少è§ï¼Œä½†å®ƒå¯èƒ½ä¼šå‘生。检查您的设置以确ä¿æ‚¨å·²æ­£ç¡®è®¾ç½®ä»ªè¡¨æ¿ã€‚"
@@ -36035,6 +36522,9 @@ msgstr "监控的项目"
msgid "SecurityReports|More info"
msgstr "更多信æ¯"
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr "无活动"
@@ -36092,6 +36582,9 @@ msgstr "安全报告åªèƒ½ç”±æŽˆæƒçš„用户访问。"
msgid "SecurityReports|Security reports help page link"
msgstr "安全报告帮助页é¢é“¾æŽ¥"
+msgid "SecurityReports|Security scan results"
+msgstr "安全扫æ结果"
+
msgid "SecurityReports|Security scans have run"
msgstr "安全扫æå·²è¿è¡Œ"
@@ -36117,7 +36610,7 @@ msgid "SecurityReports|Status"
msgstr "状æ€"
msgid "SecurityReports|Still detected"
-msgstr ""
+msgstr "ä»ç„¶æ£€æµ‹åˆ°"
msgid "SecurityReports|Submit vulnerability"
msgstr "æ交æ¼æ´ž"
@@ -36209,9 +36702,15 @@ msgstr "您的å馈对我们很é‡è¦ï¼æˆ‘们将在一周内å†æ¬¡è¯¢é—®ã€‚"
msgid "SecurityReports|scanned resources"
msgstr "扫æ资æº"
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr "å¯ç”¨å®‰å…¨åŸ¹è®­æ¥å­¦ä¹ å¦‚何修å¤æ¼æ´žã€‚查看选定的教育æ供者æ供的与å‘现的æ¼æ´žç›¸å…³çš„安全培训。"
+
msgid "SecurityTraining|Primary Training"
msgstr "åˆçº§åŸ¹è®­"
+msgid "SecurityTraining|Resolve with security training"
+msgstr "通过安全培训解决问题"
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr "当多个培训åˆä½œä¼™ä¼´å¯ç”¨æ—¶ï¼Œæ¥è‡ªæ­¤åˆä½œä¼™ä¼´çš„培训将优先进行。"
@@ -36224,6 +36723,9 @@ msgstr "查看指标"
msgid "See our website for help"
msgstr "查看我们的网站以获å–帮助"
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr "查看 GitLab 管ç†é¢æ¿ä¸­çš„å—å½±å“项目"
@@ -36287,9 +36789,6 @@ msgstr "选择模æ¿ä»“库"
msgid "Select a template type"
msgstr "选择模æ¿ç±»åž‹"
-msgid "Select a timezone"
-msgstr "选择时区"
-
msgid "Select all"
msgstr "选择全部"
@@ -36315,7 +36814,7 @@ msgid "Select branches"
msgstr "选择分支"
msgid "Select default branch"
-msgstr ""
+msgstr "选择默认分支"
msgid "Select due date"
msgstr "设置截止日期"
@@ -36363,7 +36862,7 @@ msgid "Select projects"
msgstr "选择项目"
msgid "Select report"
-msgstr ""
+msgstr "选择报告"
msgid "Select reviewer(s)"
msgstr "选择审核者"
@@ -36428,11 +36927,11 @@ msgstr "所选标签已在使用中。选择å¦ä¸€ä¸ªé€‰é¡¹ã€‚"
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr "选择GitLab用户将在议题和评论的æ述中加入指å‘该GitLab用户的链接(例如“由%{link_open}@johnsmith%{link_close}â€)。它还将与所选用户关è”å’Œ/或分é…这些议题和评论。"
-msgid "Self monitoring"
-msgstr "自我监控"
+msgid "Self-monitoring"
+msgstr "自监控"
-msgid "Self monitoring project does not exist"
-msgstr "自我监控项目ä¸å­˜åœ¨"
+msgid "Self-monitoring project does not exist"
+msgstr "自监控项目ä¸å­˜åœ¨"
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
msgstr "自我监控项目ä¸å­˜åœ¨ã€‚请检查日志中是å¦æœ‰ä»»ä½•é”™è¯¯æ¶ˆæ¯"
@@ -36443,29 +36942,29 @@ msgstr "自我监控项目已æˆåŠŸåˆ é™¤"
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr "自我监控项目未被删除。请检查日志中是å¦æœ‰ä»»ä½•é”™è¯¯æ¶ˆæ¯"
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
-msgstr "激活或åœç”¨å®žä¾‹è‡ªæˆ‘监测。"
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
+msgstr "å¯ç”¨æˆ–ç¦ç”¨å®žä¾‹è‡ªç›‘控。"
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
-msgstr "激活自我监控以创建用于监控实例è¿è¡ŒçŠ¶å†µçš„项目。"
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
+msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
-msgstr "åœç”¨è‡ªæˆ‘监控?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
+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|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
+msgstr ""
-msgid "SelfMonitoring|Self monitoring"
-msgstr "自我监控"
+msgid "SelfMonitoring|Self-monitoring"
+msgstr "自监控"
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
-msgstr "自我监控已å¯ç”¨ã€‚使用 %{projectLinkStart}自我监控项目%{projectLinkEnd} æ¥ç›‘控您的实例的è¿è¡ŒçŠ¶å†µã€‚"
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
-msgstr "æˆåŠŸåˆ›å»ºäº†è‡ªæˆ‘监测项目。"
+msgid "SelfMonitoring|Self-monitoring project successfully created."
+msgstr "自监控项目已æˆåŠŸåˆ›å»ºã€‚"
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
-msgstr "æˆåŠŸåˆ é™¤äº†è‡ªæˆ‘监测项目。"
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
+msgstr "自监控项目已æˆåŠŸåˆ é™¤ã€‚"
msgid "Send"
msgstr "å‘é€"
@@ -36683,9 +37182,6 @@ msgstr "设置è‰ç¨¿çŠ¶æ€"
msgid "Set the Ready status"
msgstr "设置就绪状æ€"
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr "设置此项目的默认分支。除éžæ‚¨æŒ‡å®šä¸åŒçš„分支,å¦åˆ™æ‰€æœ‰åˆå¹¶è¯·æ±‚å’Œæ交都是针对此分支进行的。"
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr "为所有项目中的作业产物设置默认到期时间。默认情况下设置为 %{code_open}0%{code_close} 表示永ä¸è¿‡æœŸã€‚如果没有写入å•ä½ï¼Œåˆ™é»˜è®¤ä¸ºç§’。例如,以下都是等价的: %{code_open}3600%{code_close}〠%{code_open}60 minutes%{code_close}或 %{code_open}one hour%{code_close}。"
@@ -36834,9 +37330,6 @@ msgstr "设置"
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr "无法加载åˆå¹¶è¯·æ±‚选项设置。å°è¯•é‡æ–°åŠ è½½é¡µé¢ã€‚"
-msgid "Setup"
-msgstr "设置"
-
msgid "Severity"
msgstr "严é‡ç¨‹åº¦"
@@ -37090,11 +37583,8 @@ msgstr "显示所有å²è¯—"
msgid "Showing all issues"
msgstr "已显示全部议题"
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr "显示在此日期范围内创建的工作æµäº‹é¡¹çš„æ•°æ®ã€‚日期范围最多 %{maxDateRange} 天。"
-
-msgid "Showing graphs based on events of the last %{timerange} days."
-msgstr "显示基于最近%{timerange}天的事件的图表。"
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
+msgstr ""
msgid "Showing last %{size} of log -"
msgstr "显示日志的最åŽ%{size} -"
@@ -37147,8 +37637,8 @@ msgstr "以具有匹é…电å­é‚®ä»¶åœ°å€çš„用户身份登录,将电å­é‚®ä»¶
msgid "Sign in preview"
msgstr "登录预览"
-msgid "Sign in to \"%{group_name}\""
-msgstr "登录到 \"%{group_name}\""
+msgid "Sign in to %{group_name}"
+msgstr "登录到 %{group_name}"
msgid "Sign in to GitLab"
msgstr "登录到GitLab"
@@ -37162,8 +37652,8 @@ msgstr "通过2FA代ç ç™»å½•"
msgid "Sign in with"
msgstr "登录方å¼"
-msgid "Sign in with Single Sign-On"
-msgstr "使用å•ç‚¹ç™»å½•(SSO)进行登录"
+msgid "Sign in with single sign-on"
+msgstr "使用å•ç‚¹ç™»å½•ï¼ˆSSO)进行登录"
msgid "Sign in with smart card"
msgstr "使用智能å¡ç™»å½•"
@@ -37285,9 +37775,6 @@ msgstr "大å°é™åˆ¶"
msgid "Size limit per repository (MB)"
msgstr "æ¯ä¸ªä»“库的大å°é™åˆ¶ (MB)"
-msgid "Skip outdated deployment jobs"
-msgstr "跳过已过时的部署作业"
-
msgid "Skipped"
msgstr "跳过"
@@ -37478,7 +37965,7 @@ msgid "Snowplow"
msgstr "Snowplow"
msgid "Soft wrap"
-msgstr ""
+msgstr "自动æ¢è¡Œ"
msgid "Solid"
msgstr "实心"
@@ -37510,6 +37997,9 @@ msgstr "有人您åŒæ—¶ç¼–辑了这一åˆå¹¶è¯·æ±‚。请刷新页é¢æŸ¥çœ‹æ›´æ”¹
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr "有人在你编辑的åŒæ—¶ç¼–辑了这个测试用例。æ述已更新,您需è¦å†æ¬¡è¿›è¡Œæ›´æ”¹ã€‚"
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr "有人从新ä½ç½®ç™»å½•åˆ°æ‚¨çš„ %{host} å¸æˆ·"
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "有人(希望是您)è¦æ±‚在 %{link_to_gitlab}上é‡ç½®æ‚¨çš„ GitLab è´¦å·çš„密ç ã€‚"
@@ -37621,9 +38111,6 @@ msgstr "获å–æ­¤åˆå¹¶è¯·æ±‚的环境时出错,请ç¨åŽé‡è¯•ã€‚"
msgid "Something went wrong while fetching the packages list."
msgstr "获å–软件包列表时出错。"
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr "åˆå§‹åŒ–OpenAPI查看器时出错"
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr "获å–Let's Encryptè¯ä¹¦æ—¶å‡ºäº†é”™ã€‚"
@@ -38197,9 +38684,6 @@ msgstr "状æ€:"
msgid "Status: %{title}"
msgstr "状æ€: %{title}"
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr "%{failed} 个失败, %{pending} 个待处ç†"
-
msgid "StatusCheck|%{failed} failed"
msgstr "%{failed} 个失败"
@@ -38212,9 +38696,6 @@ msgstr "API检查"
msgid "StatusCheck|Add status check"
msgstr "添加状æ€æ£€æŸ¥"
-msgid "StatusCheck|All passed"
-msgstr "全部通过"
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr "删除 %{name} 状æ€æ£€æŸ¥æ—¶å‡ºé”™ã€‚"
@@ -38236,9 +38717,6 @@ msgstr "外部 API 已被å¦ä¸€ä¸ªçŠ¶æ€æ£€æŸ¥ä½¿ç”¨ã€‚"
msgid "StatusCheck|Failed to load status checks"
msgstr "加载状æ€æ£€æŸ¥å¤±è´¥"
-msgid "StatusCheck|Failed to load status checks."
-msgstr "无法加载状æ€æ£€æŸ¥ã€‚"
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr "调用外部 API 作为æµæ°´çº¿è¿‡ç¨‹çš„一部分。"
@@ -38758,9 +39236,15 @@ msgstr "钛黄色"
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr "基于机器学习工具å‘审核者æ供建议。"
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr "了解推è的审核者"
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr "推è的审核者"
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr "推è的审核者帮助链接"
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr "建议出现在å³ä¾§è¾¹æ çš„审核者部分中"
@@ -39017,6 +39501,9 @@ msgstr "切æ¢åˆ†æ”¯"
msgid "Switch branch/tag"
msgstr "切æ¢åˆ†æ”¯/标签"
+msgid "Switch editors"
+msgstr "切æ¢ç¼–辑器"
+
msgid "Switch to GitLab Next"
msgstr "切æ¢åˆ°GitLab 预览版"
@@ -39107,6 +39594,9 @@ msgstr "目录"
msgid "Tag"
msgstr "标签"
+msgid "Tag does not exist"
+msgstr "标签ä¸å­˜åœ¨"
+
msgid "Tag list:"
msgstr "标签列表:"
@@ -39191,6 +39681,9 @@ msgstr "删除标签。您ç»å¯¹ç¡®å®šå—?"
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr "删除 %{strongStart}%{tagName}%{strongEnd} 标记无法撤消。您确定å—?"
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr "是å¦è¦åˆ›å»ºå¸¦æœ‰æ–°æ ‡ç­¾çš„å‘布?您å¯ä»¥åœ¨%{link_start}新建å‘布页é¢%{link_end}中执行此æ“作。"
+
msgid "TagsPage|Edit release"
msgstr "编辑å‘布"
@@ -39212,15 +39705,9 @@ msgstr "åªæœ‰é¡¹ç›®ç»´æŠ¤è€…或所有者æ‰èƒ½åˆ é™¤å—ä¿æŠ¤çš„标签"
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr "也å¯ä»¥æ·»åŠ æ¶ˆæ¯åˆ°æ ‡ç­¾ã€‚ä¿ç•™ç©ºç™½åˆ™åˆ›å»º %{link_start}è½»é‡æ ‡ç­¾%{link_end}。"
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr "å¯é€‰ï¼ŒåŸºäºŽæ­¤æ ‡ç­¾åˆ›å»ºé¡¹ç›®å…¬å¼€å‘布。 å‘布说明会显示在%{releases_page_link_start}å‘布%{link_end}页é¢ã€‚ %{docs_link_start}更多信æ¯%{link_end}"
-
msgid "TagsPage|Please type the following to confirm:"
msgstr "请输入以下内容进行确认:"
-msgid "TagsPage|Release notes"
-msgstr "å‘行说明"
-
msgid "TagsPage|Repository has no tags yet."
msgstr "版本库还没有标签。"
@@ -39242,9 +39729,6 @@ msgstr "无法加载标签"
msgid "TagsPage|Use git tag command to add a new one:"
msgstr "使用git tag命令添加一个:"
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "编写å‘行说明(Release Notes)或将文件拖动到此处..."
-
msgid "TagsPage|Yes, delete protected tag"
msgstr "是,删除å—ä¿æŠ¤çš„标签"
@@ -39263,6 +39747,9 @@ msgstr "å·²ä¿æŠ¤"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr "查看文档,å‘现 GitLab 的所有功能。"
+msgid "Target"
+msgstr "目标"
+
msgid "Target Branch"
msgstr "目标分支"
@@ -39374,14 +39861,6 @@ msgstr "使用 Terraform?å°è¯• GitLab 托管 Terraform State"
msgid "Terraform|%{name} successfully removed"
msgstr "%{name} å·²æˆåŠŸåˆ é™¤"
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] "%{number}个Terraform报告生æˆå¤±è´¥"
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] "您的æµæ°´çº¿ç”Ÿæˆäº†%{number}个Terraform报告"
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] "%{strong_start}%{number}%{strong_end} 个 Terraform 报告生æˆå¤±è´¥"
@@ -39399,12 +39878,6 @@ msgstr "Terraform 报告生æˆå¤±è´¥ã€‚"
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr "在您的æµæ°´çº¿ä¸­ç”Ÿæˆäº†ä¸€ä¸ª Terraform 报告。"
-msgid "Terraform|A report failed to generate."
-msgstr "无法生æˆæŠ¥å‘Šã€‚"
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr "在您的æµæ°´çº¿ä¸­ç”Ÿæˆäº†ä¸€ä»½æŠ¥å‘Šã€‚"
-
msgid "Terraform|Actions"
msgstr "æ“作"
@@ -39492,12 +39965,6 @@ msgstr "Terraform init 命令"
msgid "Terraform|Terraform reports"
msgstr "Terraform 报告"
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr "作业 %{name} 生æˆæŠ¥å‘Šå¤±è´¥ã€‚"
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr "作业 %{name} 生æˆäº†ä¸€ä¸ªæŠ¥å‘Šã€‚"
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr "作业 %{strong_start}%{name}%{strong_end} 生æˆæŠ¥å‘Šå¤±è´¥ã€‚"
@@ -39947,6 +40414,9 @@ msgstr "您的 PlantUML æœåŠ¡å™¨çš„主机å。"
msgid "The hostname of your Snowplow collector."
msgstr "您的 Snowplow 收集器的主机å。"
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr "导入无法å–消,因为它的状æ€æ˜¯ %{project_status}"
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "该导入过程将在 %{timeout}åŽè¶…时。对于需è¦é•¿äºŽè¯¥æ—¶é—´æ‰èƒ½å¯¼å…¥çš„仓库,请使用克隆/推é€ç»„åˆã€‚"
@@ -40142,9 +40612,6 @@ msgstr "仓库必须能够通过%{code_open}http://%{code_close}, %{code_open}ht
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr "您è¦è®¿é—®çš„资æºä¸å­˜åœ¨æˆ–您没有执行此æ“作的æƒé™ã€‚"
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr "åŒä¸€ä¸ªå…±äº«runnerå¯æ‰§è¡Œå¤šä¸ªé¡¹ç›®çš„代ç ï¼Œé™¤éžæ‚¨é…置了自动伸缩,将%{link}设置为1 (GitLab.com 上的设置)。"
-
msgid "The scan has been created."
msgstr "扫æ已创建。"
@@ -40175,7 +40642,7 @@ msgstr "æºä¸»é¢˜ä¸æ˜¯ä¸»é¢˜ã€‚"
msgid "The specified tab is invalid, please select another"
msgstr "指定标签页无效,请选择å¦ä¸€ä¸ª"
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr "开始日期必须早于结æŸæ—¥æœŸã€‚"
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40232,9 +40699,6 @@ msgstr "æ¼æ´žå·²ä¸å†è¢«æ£€æµ‹åˆ°ã€‚请在更改其状æ€å‰ç¡®ä¿æ¼æ´žå·²ä¿®
msgid "Theme"
msgstr "主题"
-msgid "There are currently no events."
-msgstr "当å‰æ²¡æœ‰äº‹ä»¶ã€‚"
-
msgid "There are currently no mirrored repositories."
msgstr "ç›®å‰æ²¡æœ‰é•œåƒçš„仓库。"
@@ -40586,9 +41050,6 @@ msgstr "这些现有的议题具有类似的标题。在那里评论å¯èƒ½æ›´å¥½
msgid "These runners are shared across projects in this group."
msgstr "这些Runner在该群组中的项目之间共享。"
-msgid "These runners are shared across this GitLab instance."
-msgstr "这些Runner在此 GitLab 实例中共享。"
-
msgid "These runners are specific to this project."
msgstr "这些Runner是该项目所指定的。"
@@ -40622,6 +41083,9 @@ msgstr "因为 %{reason}无法显示 %{viewer} 。您å¯ä»¥æ”¹ä¸º %{options}。"
msgid "This Cron pattern is invalid"
msgstr "æ­¤Cronæ ¼å¼æ— æ•ˆ"
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr "æ­¤ GitLab 实例尚未æ供任何共享 Runner,实例管ç†å‘˜å¯ä»¥åœ¨ç®¡ç†ä¸­å¿ƒæ³¨å†Œå…±äº«Runner。"
@@ -40788,25 +41252,22 @@ msgid "This epic already has the maximum number of child epics."
msgstr "æ­¤å²è¯—çš„å­å²è¯—数目已达最大值。"
msgid "This epic cannot be added. An epic cannot be added to itself."
-msgstr ""
-
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
+msgstr "无法添加此å²è¯—。å²è¯—ä¸èƒ½æ·»åŠ åˆ°è‡ªèº«ã€‚"
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
-msgstr ""
+msgstr "无法添加此å²è¯—。å²è¯—必须与其上级å²è¯—属于åŒä¸€ç¾¤ç»„或å­ç»„。"
msgid "This epic cannot be added. It is already an ancestor of the parent epic."
-msgstr ""
+msgstr "无法添加此å²è¯—。它已ç»æ˜¯çˆ¶å²è¯—的祖先。"
msgid "This epic cannot be added. It is already assigned to the parent epic."
-msgstr ""
+msgstr "无法添加此å²è¯—。它已分é…给上级å²è¯—。"
msgid "This epic cannot be added. One or more epics would exceed the maximum depth (%{max_depth}) from its most distant ancestor."
-msgstr ""
+msgstr "无法添加此å²è¯—。一个或多个å²è¯—将超过其级别的最大深度(%{max_depth})。"
msgid "This epic cannot be added. You don't have access to perform this action."
-msgstr ""
+msgstr "无法添加此å²è¯—。您没有执行此æ“作的æƒé™ã€‚"
msgid "This epic does not exist or you don't have sufficient permission."
msgstr "æ­¤å²è¯—ä¸å­˜åœ¨æˆ–者您没有足够的æƒé™ã€‚"
@@ -40853,6 +41314,9 @@ msgstr "此群组已安排在%{date}永久删除"
msgid "This group has no active access tokens."
msgstr "此群组没有有效的访问令牌。"
+msgid "This group has no projects yet"
+msgstr "此群组还没有项目"
+
msgid "This group is linked to a subscription"
msgstr "此群组已链接到订阅"
@@ -41069,15 +41533,18 @@ msgstr "åˆå¹¶è¯·æ±‚å·²åˆå¹¶ã€‚è¦åº”用此建议,请直接编辑此文件。
msgid "This namespace has already been taken! Please choose another one."
msgstr "此命å空间已被使用ï¼è¯·é€‰æ‹©å…¶ä»–命å空间。"
+msgid "This namespace has already been taken. Choose a different one."
+msgstr "此命å空间已被使用。选择å¦ä¸€ä¸ªã€‚"
+
msgid "This only applies to repository indexing operations."
msgstr "è¿™åªé€‚用于仓库索引æ“作。"
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
+msgstr ""
+
msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr "此页é¢ä¸å¯ç”¨ï¼Œæ‚¨æ— æƒè·¨é¡¹ç›®é˜…读相关信æ¯ã€‚"
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
-msgstr "此页é¢å‘é€äº†ä¸€ä¸ªæœ‰æ•ˆæ•°æ®ã€‚返回事件页é¢æŸ¥çœ‹æ–°åˆ›å»ºçš„事件。"
-
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
msgstr "æ­¤æµæ°´çº¿ä½¿ç”¨äº†åŒ…å«%{b_open}Auto DevOps%{b_close}的预先定义CI/CDé…置。"
@@ -41148,7 +41615,7 @@ msgid "This project will be deleted on %{date} since its parent group '%{parent_
msgstr "此项目将于 %{date} 删除,因为它的父组 '%{parent_group_name}'已计划删除。"
msgid "This project's pipeline configuration is located outside this repository"
-msgstr ""
+msgstr "此项目的æµæ°´çº¿é…ç½®ä½äºŽè¿™ä¸ªä»“库之外。"
msgid "This release was created with a date in the past. Evidence collection at the moment of the release is unavailable."
msgstr "æ­¤å‘布是使用过去的日期创建的,当时 Evidence 收集功能ä¸å¯ç”¨ã€‚"
@@ -41204,9 +41671,6 @@ msgstr "此用户有一个未ç»ç¡®è®¤çš„电å­é‚®ä»¶åœ°å€ã€‚您å¯ä»¥å¼ºåˆ¶ç¡®
msgid "This user has no active %{accessTokenTypePlural}."
msgstr "此用户没有有效的%{accessTokenTypePlural}。"
-msgid "This user has no active %{type}."
-msgstr "此用户没有有效的%{type}。"
-
msgid "This user has no identities"
msgstr "该用户无身份标识"
@@ -41225,6 +41689,9 @@ msgstr "该用户是%{noteable}的作者。"
msgid "This variable can not be masked."
msgstr "æ­¤å˜é‡æ— æ³•è¢«éšè—。"
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr "这会使您注册的应用程åºå’Œ U2F / WebAuthn 设备无效。"
@@ -41238,7 +41705,7 @@ msgid "This will remove the fork relationship between this project and other pro
msgstr "这将删除此项目与派生网络中其他项目之间的派生关系。"
msgid "Thread options"
-msgstr ""
+msgstr "主题选项"
msgid "Thread to reply to cannot be found"
msgstr "找ä¸åˆ°è¦å›žå¤çš„主题"
@@ -41593,9 +42060,6 @@ msgstr "è¦æ‰¹å‡†æ­¤åˆå¹¶è¯·æ±‚,请输入您的密ç ã€‚此项目需è¦æ‰€æœ‰
msgid "To complete registration, we need additional details from you."
msgstr "è¦å®Œæˆæ³¨å†Œï¼Œæˆ‘们需è¦æ‚¨æ供更多信æ¯ã€‚"
-msgid "To confirm, type %{phrase_code}"
-msgstr "è¦ç¡®è®¤ï¼Œè¯·é”®å…¥ %{phrase_code}"
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr "å¯ä»¥ä½¿ç”¨ %{personal_access_token_link}连接GitHub仓库。当创建个人访问令牌时,需è¦é€‰æ‹©%{code_open}repo%{code_close}范围,以显示å¯ä¾›è¿žæŽ¥çš„公共和ç§æœ‰çš„仓库列表。"
@@ -41618,7 +42082,7 @@ msgid "To define internal users, first enable new users set to external"
msgstr "è¦å®šä¹‰å†…部用户,请首先å¯ç”¨è®¾ç½®ä¸ºå¤–部的新用户"
msgid "To edit the pipeline configuration, you must go to the project or external site that hosts the file."
-msgstr ""
+msgstr "è¦ç¼–辑æµæ°´çº¿é…置,您必须转到托管文件的项目或外部站点。"
msgid "To enable Registration Features, first enable Service Ping."
msgstr "è¦å¯ç”¨æ³¨å†ŒåŠŸèƒ½ï¼Œè¯·å…ˆå¯ç”¨Service Ping。"
@@ -41701,6 +42165,9 @@ msgstr "è¦é‡æ–°æ¿€æ´»æ‚¨çš„å¸æˆ·ï¼Œ %{gitlab_link_start}登录到 GitLab。%{
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, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr "è¦è§£å†³æ­¤é—®é¢˜ï¼Œè¯·å°è¯•ï¼š"
@@ -41767,9 +42234,33 @@ msgstr "今日"
msgid "Todos count"
msgstr "待办事项计数"
+msgid "Todos|Added"
+msgstr "已添加"
+
+msgid "Todos|Alert"
+msgstr "警报"
+
+msgid "Todos|Any Action"
+msgstr "任何æ“作"
+
+msgid "Todos|Any Type"
+msgstr "任何类型"
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr "您正在寻找è¦åšçš„事情å—? 查看 %{strongStart}%{openIssuesLinkStart}打开的议题%{openIssuesLinkEnd}%{strongEnd},贡献给 %{strongStart}%{mergeRequestLinkStart}åˆå¹¶è¯·æ±‚%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd},或在评论中æåŠæŸäººï¼Œè‡ªåŠ¨åˆ†é…新的待办事项。"
+msgid "Todos|Assigned"
+msgstr "已分é…"
+
+msgid "Todos|Could not merge"
+msgstr "无法åˆå¹¶"
+
+msgid "Todos|Design"
+msgstr "设计"
+
+msgid "Todos|Epic"
+msgstr "å²è¯—"
+
msgid "Todos|Filter by author"
msgstr "按作者筛选"
@@ -41791,18 +42282,39 @@ msgstr "从此,您将被称为â€å¾…办事项破å者“"
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr "一个空的待办事项列表是ä¸æ˜¯å¾ˆæ¼‚亮?"
+msgid "Todos|Issue"
+msgstr "议题"
+
msgid "Todos|It's how you always know what to work on next."
msgstr "这是您始终知é“下一步该åšä»€ä¹ˆçš„æ–¹å¼ã€‚"
msgid "Todos|Mark all as done"
msgstr "标记全部完æˆ"
+msgid "Todos|Mentioned"
+msgstr "å·²æåŠ"
+
+msgid "Todos|Merge request"
+msgstr "åˆå¹¶è¯·æ±‚"
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr "您的待办事项列表中没有任何事项。"
msgid "Todos|Nothing left to do. High five!"
msgstr "没有需è¦åšçš„事情。真棒ï¼"
+msgid "Todos|Pipelines"
+msgstr "æµæ°´çº¿"
+
+msgid "Todos|Removed from Merge Train:"
+msgstr "已从åˆå¹¶é˜Ÿåˆ—中删除:"
+
+msgid "Todos|Review requested"
+msgstr "已请求审核"
+
+msgid "Todos|The pipeline failed in"
+msgstr "æµæ°´çº¿å¤±è´¥"
+
msgid "Todos|Undo mark all as done"
msgstr "撤销标记全部完æˆ"
@@ -41815,6 +42327,24 @@ msgstr "å·²ç»å…¨éƒ¨å®Œæˆäº†ï¼"
msgid "Todos|Your To-Do List shows what to work on next"
msgstr "您的待办事项列表显示下一步è¦åšä»€ä¹ˆ"
+msgid "Todos|added a todo for"
+msgstr "新增一个待办事项"
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr "请求审核"
+
+msgid "Todos|set %{who} as an approver for"
+msgstr "设置 %{who} 为核准人"
+
+msgid "Todos|yourself"
+msgstr "您自己"
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr "在 %{todo_parent_path}"
+
msgid "Toggle GitLab Next"
msgstr "切æ¢GitLab Next"
@@ -41965,9 +42495,6 @@ msgstr "贡献总计"
msgid "Total Score"
msgstr "总分"
-msgid "Total artifacts size: %{total_size}"
-msgstr "所有产物大å°ï¼š %{total_size}"
-
msgid "Total cores (CPUs)"
msgstr "总核心(CPU)"
@@ -42287,6 +42814,12 @@ msgstr "此用户已ç¦ç”¨åŒé‡è®¤è¯"
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr "您的å¸æˆ·å·²ç¦ç”¨åŒé‡éªŒè¯"
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr "%{user_email} çš„åŒé‡èº«ä»½éªŒè¯å·²è¢«æˆåŠŸç¦ç”¨ï¼"
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr "%{username} çš„åŒé‡éªŒè¯å·²è¢«æˆåŠŸç¦ç”¨ï¼"
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr "åŒé‡éªŒè¯å·²è¢«æˆåŠŸç¦ç”¨ï¼"
@@ -42791,6 +43324,12 @@ msgstr "使用趋势"
msgid "Usage statistics"
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 的项目级存储统计信æ¯ä»…具有方å‘性,ä¸åŒ…括实例范围的é‡å¤æ•°æ®åˆ é™¤ã€‚"
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr "此项目级存储统计ä¸åŒ…括站点范围é‡å¤æ•°æ®çš„删除,ä¸ç”¨äºŽè®¡ç®—总命å空间存储。"
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr "%{help_link_start}共享Runner%{help_link_end}å·²ç¦ç”¨ï¼Œæ‰€ä»¥æµæ°´çº¿ä½¿ç”¨æ²¡æœ‰è®¾ç½®é™åˆ¶"
@@ -42893,6 +43432,9 @@ msgstr "已使用的命å空间存储"
msgid "UsageQuota|No CI minutes usage data available."
msgstr "æ— å¯ç”¨çš„ CI 分钟使用数æ®ã€‚"
+msgid "UsageQuota|No projects to display."
+msgstr "没有è¦æ˜¾ç¤ºçš„项目。"
+
msgid "UsageQuota|Packages"
msgstr "软件包"
@@ -42923,6 +43465,9 @@ msgstr "é‡æ–°è®¡ç®—仓库使用情况"
msgid "UsageQuota|Repository"
msgstr "仓库"
+msgid "UsageQuota|Search"
+msgstr "æœç´¢"
+
msgid "UsageQuota|Seats"
msgstr "席ä½"
@@ -43930,7 +44475,7 @@ msgid "View blame prior to this change"
msgstr "查看此å˜æ›´å‰çš„blame模å¼"
msgid "View card matches"
-msgstr ""
+msgstr "查看å¡ç‰‡åŒ¹é…"
msgid "View chart"
msgid_plural "View charts"
@@ -43970,9 +44515,6 @@ msgstr "查看文件@%{commitSha}"
msgid "View full dashboard"
msgstr "查看完整仪表æ¿"
-msgid "View full log"
-msgstr "查看完整日志"
-
msgid "View group in admin area"
msgstr "在管ç†ä¸­å¿ƒæŸ¥çœ‹ç¾¤ç»„"
@@ -44433,6 +44975,9 @@ msgstr "请求/å“应"
msgid "Vulnerability|Scanner Provider"
msgstr "扫æ工具æ供者"
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr "安全审计"
@@ -44451,6 +44996,9 @@ msgstr "严é‡æ€§ï¼š"
msgid "Vulnerability|Status"
msgstr "状æ€"
+msgid "Vulnerability|Status:"
+msgstr "状æ€ï¼š"
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr "扫æ器确定此æ¼æ´žä¸ºè¯¯æŠ¥ã€‚在更改其状æ€ä¹‹å‰éªŒè¯è¯„估。 %{linkStart}了解有关误报检测的更多信æ¯ã€‚%{linkEnd}"
@@ -44461,7 +45009,7 @@ msgid "Vulnerability|Tool"
msgstr "工具"
msgid "Vulnerability|Tool:"
-msgstr ""
+msgstr "工具:"
msgid "Vulnerability|Training"
msgstr "培训"
@@ -44586,8 +45134,8 @@ msgstr "我们å°è¯•äºŽ%{expires_on}自动将%{strong}%{namespace_name}%{strong_
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "我们è¦ç¡®å®šæ‚¨æ˜¯ä¸æ˜¯æœºå™¨äººã€‚"
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
-msgstr "我们想è¦è®©æ‚¨çŸ¥é“ %{username} 已在%{scope}中被å°ç¦ï¼Œå› ä¸ºå®ƒä»¬åœ¨ %{within_minutes} 分钟内下载了超过 %{max_project_downloads} 个项目仓库。"
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
+msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
msgstr "我们会通知%{inviter} ,您拒ç»äº†æ³¨å†ŒGitLab的邀请。您将ä¸ä¼šç»§ç»­æ”¶åˆ°æ醒。"
@@ -44628,6 +45176,9 @@ msgstr "WebAuthn设备 (%{length})"
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr "WebAuthnåªæ”¯æŒå¯ç”¨äº†HTTPS的网站。您å¯ä»¥è”系管ç†å‘˜èŽ·å¾—更多信æ¯"
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr "您确定è¦åˆ‡æ¢ç¼–辑器å—?您将丢失任何未ä¿å­˜çš„更改。"
+
msgid "WebIDE|Fork project"
msgstr "Fork 项目"
@@ -44643,12 +45194,24 @@ msgstr "快速轻æ¾åœ°ç¼–辑您项目中的多个文件。"
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr "轻快地编辑您项目中的多个文件。按 . 打开"
+msgid "WebIDE|Ready for something new?"
+msgstr "准备好迎接新功能了å—?"
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr "更新用户å好设置时出错。请查看开å‘者控制å°äº†è§£è¯¦æƒ…。"
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr "切æ¢åˆ°æ–°çš„ Web IDE"
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr "此项目ä¸æŽ¥å—未签åçš„æ交。"
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr "此项目ä¸æŽ¥å—未签åçš„æ交,您无法通过 Web IDE æ交更改。"
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr "您被邀请体验新的 Web IDE。"
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr "您ä¸èƒ½åœ¨è¿™ä¸ªé¡¹ç›®ä¸­ç›´æŽ¥ç¼–辑文件,请派生(Fork)这个项目并æ交åˆå¹¶è¯·æ±‚。"
@@ -44688,6 +45251,9 @@ msgstr "Webhooks"
msgid "Webhooks Help"
msgstr "Webhooks帮助"
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr "+ éšè— URL çš„å¦ä¸€éƒ¨åˆ†"
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr "一æ¡è¯„论被添加到机密议题。"
@@ -44758,7 +45324,7 @@ msgid "Webhooks|Deployment events"
msgstr "部署事件"
msgid "Webhooks|Do not show sensitive data such as tokens in the UI."
-msgstr ""
+msgstr "在 UI 中ä¸æ˜¾ç¤ºè¯¸å¦‚令牌之类的æ•æ„Ÿæ•°æ®ã€‚"
msgid "Webhooks|Enable SSL verification"
msgstr "å¯ç”¨SSL验è¯"
@@ -44776,7 +45342,7 @@ msgid "Webhooks|Go to webhooks"
msgstr "跳转到 Webhooks"
msgid "Webhooks|How it looks in the UI"
-msgstr ""
+msgstr "在 UI 中的外观"
msgid "Webhooks|Issues events"
msgstr "议题事件"
@@ -44785,7 +45351,7 @@ msgid "Webhooks|Job events"
msgstr "作业事件"
msgid "Webhooks|Mask portions of URL"
-msgstr ""
+msgstr "URL çš„éšè—部分"
msgid "Webhooks|Member events"
msgstr "æˆå‘˜äº‹ä»¶"
@@ -44802,6 +45368,12 @@ msgstr "推é€äº‹ä»¶"
msgid "Webhooks|Push to the repository."
msgstr "推é€åˆ°ä»“库。"
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr "支æŒä¾‹å¦‚ %{REGEX_CODE} 的正则表达å¼ã€‚"
+
+msgid "Webhooks|Regular expression"
+msgstr "正则表达å¼"
+
msgid "Webhooks|Releases events"
msgstr "å‘布事件"
@@ -44812,10 +45384,10 @@ msgid "Webhooks|Secret token"
msgstr "Secret 令牌"
msgid "Webhooks|Sensitive portion of URL"
-msgstr ""
+msgstr "URL çš„æ•æ„Ÿéƒ¨åˆ†"
msgid "Webhooks|Show full URL"
-msgstr ""
+msgstr "显示完整的 URL"
msgid "Webhooks|Subgroup events"
msgstr "å­ç¾¤ç»„事件"
@@ -44829,9 +45401,6 @@ msgstr "Webhook %{help_link_start}连接失败%{help_link_end},将在 %{retry_
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr "Webhook 连接失败,已ç¦ç”¨ã€‚è¦é‡æ–°å¯ç”¨å®ƒï¼Œè¯·æ£€æŸ¥ %{strong_start}最近的事件%{strong_end} 以获å–错误详细信æ¯ï¼Œç„¶åŽåœ¨ä¸‹é¢æµ‹è¯•æ‚¨çš„设置。"
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr "Webhook æ¯åˆ†é’Ÿå·²è¢«è§¦å‘超过 %{limit} 次,现在已被ç¦ç”¨ã€‚è‹¥è¦é‡æ–°å¯ç”¨æ­¤ Webhook,请修å¤åœ¨ %{strong_start}最近事件%{strong_end} 中显示的问题,然åŽé‡æ–°æµ‹è¯•æ‚¨çš„设置。如果您需è¦å¸®åŠ©é‡æ–°å¯ç”¨æ‚¨çš„ Webhook,%{support_link_start}请è”系技术支æŒ%{support_link_end}。"
-
msgid "Webhooks|Trigger"
msgstr "触å‘æ¥æº"
@@ -44842,10 +45411,10 @@ msgid "Webhooks|URL must be percent-encoded if it contains one or more special c
msgstr "如果 URL 包å«ä¸€ä¸ªæˆ–多个特殊字符,则必须进行百分å·ç¼–ç ã€‚"
msgid "Webhooks|URL preview"
-msgstr ""
+msgstr "URL 预览"
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
-msgstr "用于验è¯æŽ¥æ”¶åˆ°çš„有效载è·ã€‚与 %{code_start}X-Gitlab-Token HTTP%{code_end} 标头中的请求一起å‘é€ã€‚"
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
+msgstr "用于验è¯æŽ¥æ”¶åˆ°çš„有效载è·ã€‚与 %{code_start}X-Gitlab-Token%{code_end} HTTP header 中的请求一起å‘é€ã€‚"
msgid "Webhooks|Webhook disabled"
msgstr "Webhook å·²ç¦ç”¨"
@@ -44856,12 +45425,21 @@ msgstr "Webhook 连接失败"
msgid "Webhooks|Webhook fails to connect"
msgstr "Webhook 连接失败"
-msgid "Webhooks|Webhook was automatically disabled"
-msgstr "Webhook 被自动ç¦ç”¨"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr "已达到 Webhook 速率é™åˆ¶"
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
+msgstr "%{root_namespace} çš„ Webhooks 现在被ç¦ç”¨ï¼Œå› ä¸ºä»–们æ¯åˆ†é’Ÿè§¦å‘超过 %{limit} 次。他们将在下一分钟内自动é‡æ–°å¯ç”¨ã€‚"
msgid "Webhooks|Wiki page events"
msgstr "Wiki页é¢äº‹ä»¶"
+msgid "Webhooks|Wildcard pattern"
+msgstr "通é…符样å¼"
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr "æ”¯æŒ %{WILDCARD_CODE_STABLE} 或 %{WILDCARD_CODE_PRODUCTION} 等通é…符。"
+
msgid "Website"
msgstr "网站"
@@ -44940,6 +45518,9 @@ msgstr "什么是压缩?"
msgid "What templates can I create?"
msgstr "我å¯ä»¥åˆ›å»ºä»€ä¹ˆæ ·çš„模æ¿ï¼Ÿ"
+msgid "What variables can I use?"
+msgstr "我å¯ä»¥ä½¿ç”¨å“ªäº›å˜é‡ï¼Ÿ"
+
msgid "What will you use this group for?"
msgstr "你会用这个群组åšä»€ä¹ˆï¼Ÿ"
@@ -44949,8 +45530,8 @@ msgstr "您想è¦åšä»€ä¹ˆï¼Ÿ"
msgid "What's new"
msgstr "新增功能"
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
-msgstr "部署作业æˆåŠŸæ—¶ï¼Œè·³è¿‡å°šæœªå®Œæˆçš„旧部署任务。"
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
+msgstr "部署作业æˆåŠŸæ—¶ï¼Œé˜»æ­¢å°šæœªå®Œæˆçš„旧部署任务。"
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr "当Runner被é”定时,ä¸èƒ½å°†å…¶åˆ†é…给其他项目"
@@ -45263,6 +45844,12 @@ msgstr "添加起始日期"
msgid "WorkItem|Add task"
msgstr "添加任务"
+msgid "WorkItem|Add to iteration"
+msgstr "添加到迭代"
+
+msgid "WorkItem|Add to milestone"
+msgstr "添加到里程碑"
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr "您确定è¦å–消编辑å—?"
@@ -45312,9 +45899,24 @@ msgstr "介ç»ä»»åŠ¡"
msgid "WorkItem|Issue"
msgstr "议题"
+msgid "WorkItem|Iteration"
+msgstr "迭代"
+
msgid "WorkItem|Learn about tasks."
msgstr "了解任务详情。"
+msgid "WorkItem|Milestone"
+msgstr "里程碑"
+
+msgid "WorkItem|No iteration"
+msgstr "无迭代"
+
+msgid "WorkItem|No matching results"
+msgstr "没有匹é…的结果"
+
+msgid "WorkItem|No milestone"
+msgstr "无里程碑"
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr "当å‰æœªè¢«åˆ†é…任何任务。使用任务功能将这个议题分解æˆæ›´å°çš„部分。"
@@ -45345,12 +45947,15 @@ msgstr "删除 %{workItemType} 时出现问题。请å†è¯•ä¸€æ¬¡ã€‚"
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr "删除任务时出错。请é‡è¯•ã€‚"
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr "获å–迭代时出错。请å†è¯•ä¸€æ¬¡ã€‚"
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr "获å–标记时出错。请é‡è¯•ã€‚"
+
msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr "获å–任务时出错。请刷新此页é¢ã€‚"
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
-msgstr "获å–工作项时出现错误,请å†è¯•ä¸€æ¬¡ã€‚"
-
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
msgstr "获å–工作项类型时出现错误,请å†è¯•ä¸€æ¬¡ã€‚"
@@ -45360,6 +45965,9 @@ msgstr "å°è¯•æ·»åŠ å­é¡¹æ—¶å‡ºé”™ã€‚请é‡è¯•ã€‚"
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr "å°è¯•åˆ›å»ºå­é¡¹æ—¶å‡ºé”™ï¼Œè¯·å†è¯•ä¸€æ¬¡ã€‚"
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr "获å–里程碑时出错。请å†è¯•ä¸€æ¬¡ã€‚"
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr "æ›´æ–° %{workItemType} 时出现问题。请å†è¯•ä¸€æ¬¡ã€‚"
@@ -45381,6 +45989,9 @@ msgstr "任务"
msgid "WorkItem|Test case"
msgstr "测试用例"
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr "此工作项ä¸å¯ç”¨ã€‚它å¯èƒ½ä¸å­˜åœ¨ï¼Œæˆ–者您没有查看它的æƒé™ã€‚"
+
msgid "WorkItem|Turn off confidentiality"
msgstr "关闭ç§å¯†"
@@ -45399,6 +46010,9 @@ msgstr "工作事项"
msgid "WorkItem|Work item"
msgstr "工作项"
+msgid "WorkItem|Work item not found"
+msgstr "未找到工作项"
+
msgid "Would you like to create a new branch?"
msgstr "您è¦åˆ›å»ºä¸€ä¸ªæ–°åˆ†æ”¯å—?"
@@ -45493,6 +46107,9 @@ msgstr "您正在å°è¯•åˆ é™¤å…ˆå‰å·²æ›´æ–°çš„文件。"
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr "您正在å°è¯•æ›´æ–°çš„文件自您开始编辑以æ¥å·²ç»å‘生更改。"
+msgid "You are being redirected away from GitLab"
+msgstr "您正被é‡å®šå‘离开 GitLab"
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr "如果超过此数字,将为您计费。%{qsrOverageLinkStart}计费如何è¿ä½œï¼Ÿ%{qsrOverageLinkEnd}"
@@ -45529,6 +46146,12 @@ msgstr "您无æƒ%{action}一å用户"
msgid "You are not allowed to approve a user"
msgstr "您无æƒæ‰¹å‡†ç”¨æˆ·"
+msgid "You are not allowed to create this tag as it is protected."
+msgstr "ä¸å…许您创建此标签,因为它是å—ä¿æŠ¤æ ‡ç­¾ã€‚"
+
+msgid "You are not allowed to download code from this project."
+msgstr "ä¸å…许您从此项目下载代ç ã€‚"
+
msgid "You are not allowed to log in using password"
msgstr "您ä¸èƒ½ä½¿ç”¨å¯†ç ç™»å½•"
@@ -45574,9 +46197,6 @@ msgstr "您登录的身份:"
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr "您正在å°è¯•ä¸Šä¼ éžå›¾ç‰‡æ–‡ä»¶ã€‚请上传.pngã€.jpgã€.jpegã€.gifã€.bmpã€.tiff或.ico。"
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr "您正在使用PostgreSQL %{pg_version_current},但此版本的GitLab需è¦PostgreSQL %{pg_version_minimum}。请将您的环境å‡çº§åˆ°æ”¯æŒçš„ PostgreSQL版本,详情请è§%{pg_requirements_url}。"
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr "您å¯ä»¥%{gitlabLinkStart}在 GitLab 上解决冲çª%{gitlabLinkEnd} 或 %{resolveLocallyStart}本地解决%{resolveLocallyEnd}。"
@@ -45677,6 +46297,9 @@ msgstr "您å¯ä»¥åœ¨%{link_start}群组设置%{link_end}中å¯ç”¨ç¾¤ç»„访问令
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr "您å¯ä»¥åœ¨ %{link_start}群组设置%{link_end} 中å¯ç”¨é¡¹ç›®è®¿é—®ä»¤ç‰Œåˆ›å»ºã€‚"
+msgid "You can enter up to 280 characters"
+msgstr "您最多å¯ä»¥è¾“å…¥ 280 个字符"
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr "您å¯ä»¥é€šè¿‡å•å‡»å›¾è¡¨ä¸­çš„列æ¥æŒ‰â€œåˆå¹¶å¤©æ•°â€è¿›è¡Œç­›é€‰ã€‚"
@@ -45749,8 +46372,8 @@ msgstr "您也å¯ä»¥é€šè¿‡%{linkStart}Lint%{linkEnd}测试.gitlab-ci.yml."
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr "您å¯ä»¥æŸ¥çœ‹æºä»£ç æˆ–%{linkStart}%{cloneIcon}克隆仓库%{linkEnd}"
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
-msgstr "您无法å†æ·»åŠ ï¼Œä½†å¯ä»¥ç®¡ç†çŽ°æœ‰æˆå‘˜ï¼Œä¾‹å¦‚,通过删除éžæ´»åŠ¨æˆå‘˜å¹¶å°†å…¶æ›¿æ¢ä¸ºæ–°æˆå‘˜ã€‚为了获得更多æˆå‘˜ï¼Œç¾¤ç»„的所有者å¯ä»¥å¼€å§‹è¯•ç”¨æˆ–å‡çº§åˆ°ä»˜è´¹ç‰ˆã€‚"
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
+msgstr "您关注的用户ä¸èƒ½è¶…过 %{limit} 个。è¦å…³æ³¨æ›´å¤šç”¨æˆ·ï¼Œè¯·å–消关注其他用户。"
msgid "You cannot %{action} %{state} users."
msgstr "您ä¸èƒ½ %{action} %{state} 用户。"
@@ -45773,6 +46396,9 @@ msgstr "您无法使用被ç¦ç”¨ç”¨æˆ·çš„身份"
msgid "You cannot impersonate a user who cannot log in"
msgstr "您无法仿使用无法登录用户的身份"
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr "您无法使用内部用户的身份"
@@ -45915,6 +46541,9 @@ msgstr "您没有足够的æƒé™æ¥åˆ›å»ºæ­¤é¡¹ç›®çš„待命计划"
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr "您没有足够的æƒé™æ¥ç®¡ç†æ­¤äº‹ä»¶çš„资æºé“¾æŽ¥"
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr "您没有足够的æƒé™ç®¡ç†æ­¤äº‹ä»¶çš„时间线事件"
@@ -45978,7 +46607,7 @@ msgstr "您必须ç»è¿‡è®¤è¯æ‰èƒ½è®¿é—®æ­¤è·¯å¾„。"
msgid "You must be logged in to search across all of GitLab"
msgstr "您必须登录æ‰èƒ½åœ¨æ•´ä¸ªGitLab中进行æœç´¢"
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46146,9 +46775,6 @@ msgstr "YouTube"
msgid "Your %{group} membership will now expire in %{days}."
msgstr "您的%{group}æˆå‘˜èµ„格将在%{days}天内到期。"
-msgid "Your %{host} account was signed in to from a new location"
-msgstr "您在%{host}上的å¸æˆ·å·²ä»Žä¸€ä¸ªæ–°çš„ä½ç½®ç™»å½•"
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr "您的 %{spammable_entity_type} 涉åŠåžƒåœ¾ä¿¡æ¯ï¼Œå·²è¢«ä¸¢å¼ƒã€‚"
@@ -46260,6 +46886,9 @@ msgstr "您的å¸å·å·²è¢«é”定。"
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr "您的å¸æˆ·ä½¿ç”¨ç¾¤ç»„“%{group_name}â€çš„专用凭æ®ï¼Œå¹¶ä¸”åªèƒ½é€šè¿‡SSO进行更新。"
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr "您的æ“作æˆåŠŸã€‚"
@@ -46376,18 +47005,15 @@ msgstr "您的消æ¯æ˜¾ç¤ºäºŽæ­¤"
msgid "Your name"
msgstr "您的åå­—"
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
+msgstr ""
+
msgid "Your new %{accessTokenType}"
msgstr "您的新 %{accessTokenType}"
msgid "Your new %{accessTokenType} has been created."
msgstr "您的新 %{accessTokenType} 已创建。"
-msgid "Your new %{type}"
-msgstr "您的新%{type}"
-
-msgid "Your new access token has been created."
-msgstr "您的新访问令牌已创建。"
-
msgid "Your new comment"
msgstr "您的新评论"
@@ -46473,6 +47099,9 @@ msgstr "您的更新失败。当拖放到现有设计时,您必须上传具有
msgid "Your username is %{username}."
msgstr "您的用户å是%{username}。"
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr "无法加载禅é“议题。在禅é“中查看议题,或é‡æ–°åŠ è½½é¡µé¢ã€‚"
@@ -46542,9 +47171,6 @@ msgstr "`end_time` ä¸åº”超过 `start_time` åŽçš„一个月"
msgid "`start_time` should precede `end_time`"
msgstr "`start_time` 应该在 `end_time` 之å‰"
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr "此项目ç¦ç”¨ `work_items_rivy` 功能标志"
-
msgid "a deleted user"
msgstr "已删除的用户"
@@ -46555,9 +47181,6 @@ msgstr[0] "约%då°æ—¶"
msgid "access:"
msgstr "访问:"
-msgid "added"
-msgstr "已添加"
-
msgid "added %{emails}"
msgstr "添加了 %{emails}"
@@ -46616,6 +47239,12 @@ msgstr "产物"
msgid "assign yourself"
msgstr "分é…给自己"
+msgid "assigned"
+msgstr "已分é…"
+
+msgid "assigned you"
+msgstr "已分é…给您"
+
msgid "at"
msgstr "于"
@@ -46625,9 +47254,6 @@ msgstr "至少有报告者角色"
msgid "at least the Reporter role, the author, and assignees"
msgstr "至少是报告者角色ã€ä½œè€…或指派人"
-msgid "at risk"
-msgstr "存在风险"
-
msgid "attach a new file"
msgstr "添加新附件"
@@ -46657,7 +47283,7 @@ msgid "cURL:"
msgstr "cURL:"
msgid "can contain only digits"
-msgstr ""
+msgstr "åªèƒ½åŒ…å«æ•°å­—"
msgid "can contain only letters of the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'"
msgstr "åªèƒ½åŒ…å«Base64å­—æ¯è¡¨(RFC4648)中的字æ¯ï¼Œä»¥åŠâ€œ@â€ã€â€œ:â€å’Œâ€œ.â€ã€‚"
@@ -46705,7 +47331,13 @@ msgid "cannot be a date in the past"
msgstr "ä¸èƒ½æ˜¯è¿‡åŽ»çš„日期"
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
-msgstr ""
+msgstr "无法添加,因为您已达到 %{namespace_name} çš„ %{free_limit} æˆå‘˜é™åˆ¶"
+
+msgid "cannot be associated with a subgroup"
+msgstr "ä¸èƒ½ä¸Žå­ç»„å…³è”"
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr "ä¸èƒ½åŒæ—¶ä¸Žç¾¤ç»„和项目相关è”"
msgid "cannot be changed"
msgstr "无法更改"
@@ -46936,12 +47568,27 @@ msgstr "ä¾èµ–项扫æå¯ä»¥æ£€æµ‹æºä»£ç ä¾èµ–项中已知的æ¼æ´žã€‚"
msgid "ciReport|Dependency scanning"
msgstr "ä¾èµ–项扫æ"
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr "检测æºä»£ç ä¾èµ–项中的已知æ¼æ´žã€‚"
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr "检测æºä»£ç ä¸­çš„已知æ¼æ´žã€‚"
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr "检测您的 Web 应用程åºä¸­çš„已知æ¼æ´žã€‚"
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr "检测æºä»£ç ä¸­çš„ secrets 和凭æ®æ¼æ´žã€‚"
+
msgid "ciReport|Download patch to resolve"
msgstr "下载补ä¸ä»¥è§£å†³"
msgid "ciReport|Download the patch to apply it manually"
msgstr "下载补ä¸ä»¥æ‰‹åŠ¨åº”用"
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr "动æ€åº”用程åºå®‰å…¨æ€§æµ‹è¯•ï¼ˆDAST)"
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr "动æ€åº”用程åºå®‰å…¨æµ‹è¯•ï¼ˆDAST)å¯æ£€æµ‹Web应用程åºä¸­çš„已知æ¼æ´žã€‚"
@@ -46964,7 +47611,7 @@ msgid "ciReport|Full Report"
msgstr "完整报告"
msgid "ciReport|Generic Report"
-msgstr ""
+msgstr "通用报告"
msgid "ciReport|IaC Scanning"
msgstr "IaC 扫æ"
@@ -47015,6 +47662,9 @@ msgstr "已手动添加"
msgid "ciReport|New"
msgstr "新增"
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr "Code Quality æ— å˜åŒ–。"
@@ -47045,6 +47695,9 @@ msgstr "密ç æ£€æµ‹"
msgid "ciReport|Security reports failed loading results"
msgstr "安全报告加载结果失败"
+msgid "ciReport|Security scan results"
+msgstr "安全扫æ结果"
+
msgid "ciReport|Security scanning"
msgstr "安全扫æ"
@@ -47060,6 +47713,9 @@ msgstr "显示 %{fetchedItems} 项,共 %{totalItems}项"
msgid "ciReport|Solution"
msgstr "解决方案"
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr "é™æ€åº”用程åºå®‰å…¨æ€§æµ‹è¯•ï¼ˆSAST)"
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr "é™æ€åº”用安全测试(SAST)å¯ä»¥æ£€æµ‹æºä»£ç ä¸­å·²çŸ¥çš„æ¼æ´žã€‚"
@@ -47133,6 +47789,9 @@ msgstr "æ交 %{commit_id}"
msgid "committed"
msgstr "å·²æ交"
+msgid "complete"
+msgstr "完æˆ"
+
msgid "compliance violation has already been recorded"
msgstr "è¿è§„行为已被记录"
@@ -47191,6 +47850,9 @@ msgstr[0] "天"
msgid "days"
msgstr "天"
+msgid "default"
+msgstr "默认"
+
msgid "default branch"
msgstr "默认分支"
@@ -47344,6 +48006,9 @@ msgid "from %d job"
msgid_plural "from %d jobs"
msgstr[0] "æ¥è‡ª%d个作业"
+msgid "from yourself"
+msgstr "æ¥è‡ªæ‚¨è‡ªå·±"
+
msgid "frontmatter"
msgstr "frontmatter"
@@ -47442,12 +48107,18 @@ msgstr "内部备注"
msgid "invalid milestone state `%{state}`"
msgstr "æ— æ•ˆçš„é‡Œç¨‹ç¢‘çŠ¶æ€ `%{state}`"
+msgid "invalidated"
+msgstr "无效"
+
msgid "is"
msgstr "是"
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr "å·²ç»ä¸Žä¸€ä¸ªGitLab议题关è”。新的议题将ä¸ä¼šè¢«å…³è”。"
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr "是无效的 IP 地å€èŒƒå›´"
@@ -47469,6 +48140,9 @@ msgstr "ä¸æ˜¯"
msgid "is not a descendant of the Group owning the template"
msgstr "相关群组ä¸å«æ¨¡ç‰ˆ"
+msgid "is not a valid URL."
+msgstr "ä¸æ˜¯æœ‰æ•ˆçš„ URL。"
+
msgid "is not a valid X509 certificate."
msgstr "ä¸æ˜¯æœ‰æ•ˆçš„X509è¯ä¹¦ã€‚"
@@ -47493,12 +48167,18 @@ msgstr "ä¸åœ¨å¼ºåˆ¶æ‰§è¡Œç¾¤ç»„托管账户的群组"
msgid "is not in the member group"
msgstr "ä¸åœ¨æˆå‘˜ç»„"
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr "ä¸åœ¨æˆå‘˜é¡¹ç›®"
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr "无效。迭代群组必须与迭代周期组匹é…。"
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr "åªè¯»"
@@ -47652,9 +48332,6 @@ msgstr "使用åˆå¹¶è¯·æ±‚å‘您的项目æ出更改建议并与您的团队讨
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr "%{boldHeaderStart}此处没有æµæ°´çº¿ã€‚%{boldHeaderEnd}"
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr "mrWidget|%{linkStart}现在设置%{linkEnd} æ¥åˆ†æžæ‚¨çš„æºä»£ç ä¸­å·²çŸ¥çš„安全æ¼æ´žã€‚"
-
msgid "mrWidget|%{mergeError}."
msgstr "%{mergeError}。"
@@ -47801,6 +48478,9 @@ 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 "åˆå¹¶è¢«é˜»æ­¢ï¼šå¿…须解决所有主题。"
@@ -47897,9 +48577,6 @@ msgstr "通过新的åˆå¹¶è¯·æ±‚中还原此åˆå¹¶è¯·æ±‚"
msgid "mrWidget|Revoke approval"
msgstr "撤销核准"
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr "SASTå’ŒSecret检测未å¯ç”¨ã€‚"
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr "ç”±%{merge_author}设置为在æµæ°´çº¿æˆåŠŸæ—¶æ·»åŠ åˆ°åˆå¹¶é˜Ÿåˆ—中"
@@ -47963,6 +48640,9 @@ msgstr "必须在开始之åŽ"
msgid "must be an email you have verified"
msgstr "必须是您已验è¯çš„电å­é‚®ä»¶"
+msgid "must be associated with a Group or a Project"
+msgstr "必须与群组或项目相关è”"
+
msgid "must be greater than start date"
msgstr "必须大于开始日期"
@@ -47975,9 +48655,15 @@ msgstr "å¿…é¡»å°äºŽ %{tag_limit} 个标签的数é‡é™åˆ¶"
msgid "must be set for a project namespace"
msgstr "必须为项目命å空间设置"
+msgid "must be top-level namespace"
+msgstr "必须是顶级命å空间"
+
msgid "must be unique by status and elapsed time within a policy"
msgstr "必须在策略中的状æ€å’Œç»è¿‡æ—¶é—´ä¸Šæ˜¯å”¯ä¸€çš„"
+msgid "must belong to same project of the work item."
+msgstr "必须属于工作项所在的åŒä¸€é¡¹ç›®ã€‚"
+
msgid "must have a repository"
msgstr "必须有一个仓库"
@@ -47996,9 +48682,6 @@ msgstr "我的频é“"
msgid "my-topic"
msgstr "我的主题"
-msgid "need attention"
-msgstr "需è¦å…³æ³¨"
-
msgid "needs to be between 10 minutes and 1 month"
msgstr "需è¦åœ¨10分钟到1个月之间"
@@ -48047,9 +48730,6 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item},和 %{lastItem}"
-msgid "on track"
-msgstr "按计划进行"
-
msgid "only %{parent_types} can be parent of Task."
msgstr "åªæœ‰ %{parent_types} å¯ä»¥æ˜¯ä»»åŠ¡çš„上级。"
@@ -48068,16 +48748,15 @@ msgstr "或"
msgid "organizations can only be added to root groups"
msgstr "机构组织åªèƒ½æ·»åŠ åˆ° root 群组"
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] "于总计%d个测试中"
-
msgid "packages"
msgstr "软件包"
msgid "pages"
msgstr "Pages"
+msgid "params is empty"
+msgstr "å‚数为空"
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "上级"
@@ -48204,9 +48883,6 @@ msgstr "删除开始日期"
msgid "remove weight"
msgstr "移除æƒé‡"
-msgid "removed"
-msgstr "已删除"
-
msgid "removed a %{link_type} link"
msgstr "删除了一个 %{link_type} 链接"
@@ -48226,12 +48902,19 @@ msgstr "回å¤åº”与顶级备注具有相åŒçš„机密性"
msgid "repositories"
msgstr "仓库"
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] "仓库"
+
msgid "repository:"
msgstr "仓库:"
msgid "role's base access level does not match the access level of the membership"
msgstr "基于角色的访问级别ä¸åŒ¹é…æˆå‘˜çš„访问级别"
+msgid "running"
+msgstr "è¿è¡Œä¸­"
+
msgid "satisfied"
msgstr "满足"
@@ -48354,7 +49037,7 @@ msgid "suggestPipeline|We’re adding a GitLab CI configuration file to add a pi
msgstr "我们正在添加GitLab CIé…置文件,以将æµæ°´çº¿æ·»åŠ åˆ°é¡¹ç›®ä¸­ã€‚您也å¯ä»¥æ‰‹åŠ¨åˆ›å»ºï¼Œä½†æˆ‘们建议您从一个开箱å³ç”¨çš„GitLab模æ¿å¼€å§‹ã€‚"
msgid "supported SSH public key."
-msgstr ""
+msgstr "æ”¯æŒ SSH 公钥。"
msgid "tag name"
msgstr "标签å称"
@@ -48386,6 +49069,9 @@ msgstr "此文档"
msgid "time summary"
msgstr "时间总计"
+msgid "to yourself"
+msgstr "到您自己"
+
msgid "today"
msgstr "今天"
@@ -48520,6 +49206,9 @@ msgstr "过期时间ä¿æŒä¸å˜äºŽ%{old_expiry}"
msgid "yaml invalid"
msgstr "yaml无效"
+msgid "you"
+msgstr "您"
+
msgid "your GitLab instance"
msgstr "您的 GitLab 实例"
diff --git a/locale/zh_HK/gitlab.po b/locale/zh_HK/gitlab.po
index ae77ec6cc4b..d3818eb6001 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: 2022-10-10 14:05\n"
+"PO-Revision-Date: 2022-11-13 09:25\n"
msgid " %{start} to %{end}"
msgstr ""
@@ -129,6 +129,10 @@ msgid "%d additional user"
msgid_plural "%d additional users"
msgstr[0] ""
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] ""
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] ""
@@ -209,18 +213,10 @@ msgid "%d epic"
msgid_plural "%d epics"
msgstr[0] ""
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] ""
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d 導出"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] ""
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] ""
@@ -229,10 +225,6 @@ msgid "%d file"
msgid_plural "%d files"
msgstr[0] ""
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d 個已修復測試çµæžœ"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] ""
@@ -431,6 +423,9 @@ msgid "%{bold_start}%{count}%{bold_end} opened merge request"
msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] ""
+msgid "%{chartTitle} no data series"
+msgstr ""
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr ""
@@ -482,6 +477,14 @@ msgstr[0] ""
msgid "%{count} files touched"
msgstr ""
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] ""
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] ""
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] ""
@@ -489,6 +492,10 @@ msgstr[0] ""
msgid "%{count} items per page"
msgstr ""
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] ""
+
msgid "%{count} more"
msgstr "還有 %{count} 項"
@@ -509,6 +516,10 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] "%{count} ä½åƒèˆ‡è€…"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] ""
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr ""
@@ -548,9 +559,6 @@ msgstr ""
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr ""
-msgid "%{due_date} (Past due)"
-msgstr ""
-
msgid "%{duration}ms"
msgstr ""
@@ -761,12 +769,6 @@ msgstr ""
msgid "%{name} (Busy)"
msgstr ""
-msgid "%{name} contained %{resultsString}"
-msgstr ""
-
-msgid "%{name} found %{resultsString}"
-msgstr ""
-
msgid "%{name} is already being used for another emoji"
msgstr ""
@@ -945,6 +947,9 @@ msgstr[0] ""
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr ""
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr ""
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] ""
@@ -1079,9 +1084,6 @@ msgstr ""
msgid "%{value} is not included in the list"
msgstr ""
-msgid "%{value} s"
-msgstr ""
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr ""
@@ -1139,6 +1141,9 @@ msgstr ""
msgid "'%{template_name}' is unknown or invalid"
msgstr ""
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr ""
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] ""
@@ -1176,6 +1181,9 @@ msgstr ""
msgid "(max size 15 MB)"
msgstr ""
+msgid "(no user)"
+msgstr ""
+
msgid "(optional)"
msgstr ""
@@ -1434,6 +1442,9 @@ msgstr "您無權使用這個é é¢ã€‚"
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr ""
+msgid "404|Not found"
+msgstr ""
+
msgid "404|Page Not Found"
msgstr "無法找到網é "
@@ -1497,9 +1508,6 @@ msgstr ""
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr ""
-msgid "A default branch cannot be chosen for an empty project."
-msgstr ""
-
msgid "A deleted user"
msgstr ""
@@ -1578,9 +1586,6 @@ msgstr ""
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr ""
-msgid "A platform value can be web, mob or app."
-msgstr ""
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr ""
@@ -1788,6 +1793,9 @@ msgstr "接å—æ¢æ¬¾"
msgid "Acceptable for use in this project"
msgstr ""
+msgid "Access Denied"
+msgstr ""
+
msgid "Access Git repositories or the API."
msgstr ""
@@ -1899,15 +1907,9 @@ msgstr ""
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr ""
-msgid "AccessibilityReport|Learn more"
-msgstr ""
-
msgid "AccessibilityReport|Message: %{message}"
msgstr ""
-msgid "AccessibilityReport|New"
-msgstr ""
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr ""
@@ -1977,9 +1979,6 @@ msgstr "啟用"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr ""
-msgid "Active %{type} (%{token_length})"
-msgstr ""
-
msgid "Active Sessions"
msgstr ""
@@ -2352,6 +2351,12 @@ msgstr ""
msgid "Adds a Zoom meeting."
msgstr ""
+msgid "Adds a resource link"
+msgstr ""
+
+msgid "Adds a resource link for this incident."
+msgstr ""
+
msgid "Adds a timeline event to incident."
msgstr ""
@@ -2535,6 +2540,24 @@ msgstr ""
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr ""
+msgid "AdminEmail|Body"
+msgstr ""
+
+msgid "AdminEmail|Body is required."
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project"
+msgstr ""
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr ""
+
+msgid "AdminEmail|Subject"
+msgstr ""
+
+msgid "AdminEmail|Subject is required."
+msgstr ""
+
msgid "AdminLabels|Define your default set of project labels"
msgstr ""
@@ -2571,15 +2594,27 @@ msgstr ""
msgid "AdminSettings|CI/CD limits"
msgstr ""
+msgid "AdminSettings|Clickhouse URL"
+msgstr ""
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr ""
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr ""
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr ""
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr ""
+msgid "AdminSettings|Cube API URL"
+msgstr ""
+
+msgid "AdminSettings|Cube API key"
+msgstr ""
+
msgid "AdminSettings|Delete inactive projects"
msgstr ""
@@ -2628,6 +2663,9 @@ msgstr ""
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr ""
+msgid "AdminSettings|Enable product analytics"
+msgstr ""
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr ""
@@ -2673,6 +2711,18 @@ msgstr ""
msgid "AdminSettings|Instance runners expiration"
msgstr ""
+msgid "AdminSettings|Jitsu administrator email"
+msgstr ""
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr ""
+
+msgid "AdminSettings|Jitsu host"
+msgstr ""
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr ""
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
@@ -2811,9 +2861,18 @@ msgstr ""
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr ""
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr ""
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr ""
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr ""
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr ""
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
@@ -2838,6 +2897,15 @@ msgstr ""
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr ""
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr ""
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr ""
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr ""
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr ""
@@ -2940,6 +3008,9 @@ msgstr ""
msgid "AdminUsers|Admins"
msgstr "管ç†å“¡"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr ""
+
msgid "AdminUsers|Approve"
msgstr ""
@@ -3132,7 +3203,7 @@ msgstr ""
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr ""
-msgid "AdminUsers|Search by name, email or username"
+msgid "AdminUsers|Search by name, email, or username"
msgstr ""
msgid "AdminUsers|Search users"
@@ -3177,8 +3248,8 @@ msgstr ""
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "請輸入 %{projectName} 以進行確èª"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "請輸入 %{username} 以進行確èª"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr ""
msgid "AdminUsers|Unban user"
msgstr ""
@@ -3240,7 +3311,7 @@ msgstr ""
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr ""
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
msgstr ""
msgid "AdminUsers|You can always block their account again if needed."
@@ -3288,6 +3359,9 @@ msgstr ""
msgid "Administrators"
msgstr ""
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr ""
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr ""
@@ -3798,7 +3872,7 @@ msgstr ""
msgid "All users with matching cards"
msgstr ""
-msgid "Allow \"%{group_name}\" to sign you in"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
msgstr ""
msgid "Allow access to members of the following group"
@@ -3813,6 +3887,9 @@ msgstr ""
msgid "Allow group owners to manage LDAP-related settings"
msgstr ""
+msgid "Allow new users to create top-level groups"
+msgstr ""
+
msgid "Allow non-administrators access to the performance bar"
msgstr ""
@@ -3849,9 +3926,6 @@ msgstr ""
msgid "Allow use of licensed EE features"
msgstr ""
-msgid "Allow users to create top-level groups"
-msgstr ""
-
msgid "Allow users to dismiss the broadcast message"
msgstr ""
@@ -4098,6 +4172,9 @@ msgstr ""
msgid "An error occurred while fetching terraform reports."
msgstr ""
+msgid "An error occurred while fetching the health status."
+msgstr ""
+
msgid "An error occurred while fetching the job log."
msgstr ""
@@ -4282,9 +4359,6 @@ msgstr ""
msgid "An error occurred while trying to follow this user, please try again."
msgstr ""
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr ""
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr ""
@@ -4384,9 +4458,6 @@ msgstr ""
msgid "Analytics"
msgstr ""
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr ""
@@ -4489,9 +4560,6 @@ msgstr ""
msgid "Application settings update failed"
msgstr ""
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr ""
-
msgid "Application was successfully destroyed."
msgstr ""
@@ -4510,7 +4578,7 @@ msgstr ""
msgid "ApplicationSettings|After sign-up text"
msgstr ""
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
msgstr ""
msgid "ApplicationSettings|Allowed domains for sign-ups"
@@ -4551,6 +4619,9 @@ msgstr ""
msgid "ApplicationSettings|Domain denylist"
msgstr ""
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr ""
+
msgid "ApplicationSettings|Email restrictions"
msgstr ""
@@ -4569,9 +4640,18 @@ msgstr ""
msgid "ApplicationSettings|Enter denylist manually"
msgstr ""
+msgid "ApplicationSettings|Hard"
+msgstr ""
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr ""
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr ""
+
+msgid "ApplicationSettings|Off"
+msgstr ""
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr ""
@@ -4599,6 +4679,9 @@ msgstr ""
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
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|Send confirmation email on sign-up"
msgstr ""
@@ -4934,9 +5017,6 @@ msgstr ""
msgid "Are you sure you want to delete %{name}?"
msgstr ""
-msgid "Are you sure you want to delete these artifacts?"
-msgstr ""
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr ""
@@ -5037,7 +5117,7 @@ msgstr ""
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr ""
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
@@ -5088,6 +5168,30 @@ msgstr ""
msgid "Artifacts"
msgstr ""
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr ""
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr ""
+
+msgid "Artifacts|Artifacts"
+msgstr ""
+
+msgid "Artifacts|Browse"
+msgstr ""
+
+msgid "Artifacts|Delete %{name}?"
+msgstr ""
+
+msgid "Artifacts|Delete artifact"
+msgstr ""
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr ""
+
+msgid "Artifacts|Total artifacts size"
+msgstr ""
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr ""
@@ -5139,9 +5243,6 @@ msgstr ""
msgid "Assign labels"
msgstr "指派標籤"
-msgid "Assign milestone"
-msgstr "指派里程碑"
-
msgid "Assign myself"
msgstr ""
@@ -5532,9 +5633,6 @@ msgstr ""
msgid "Auto-cancel redundant pipelines"
msgstr ""
-msgid "Auto-close referenced issues on default branch"
-msgstr ""
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr ""
@@ -5898,6 +5996,12 @@ msgstr ""
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr ""
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr ""
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr ""
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr ""
@@ -6622,6 +6726,9 @@ msgstr ""
msgid "Branch changed"
msgstr ""
+msgid "Branch defaults"
+msgstr ""
+
msgid "Branch has been updated since the merge was requested."
msgstr ""
@@ -6631,6 +6738,9 @@ msgstr "分支已被採å–"
msgid "Branch name"
msgstr "分支å稱"
+msgid "Branch name template"
+msgstr ""
+
msgid "Branch not loaded - %{branchId}"
msgstr ""
@@ -6652,6 +6762,9 @@ msgstr ""
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr ""
+msgid "BranchRules|Allowed to force push"
+msgstr ""
+
msgid "BranchRules|Allowed to merge"
msgstr ""
@@ -6670,6 +6783,9 @@ msgstr ""
msgid "BranchRules|Approvals"
msgstr ""
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Branch"
msgstr ""
@@ -6679,6 +6795,9 @@ msgstr ""
msgid "BranchRules|Branch rules details"
msgstr ""
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr ""
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr ""
@@ -6697,9 +6816,15 @@ msgstr ""
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr ""
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr ""
+
msgid "BranchRules|Manage in Protected Branches"
msgstr ""
+msgid "BranchRules|Manage in Status checks"
+msgstr ""
+
msgid "BranchRules|No data to display"
msgstr ""
@@ -6718,12 +6843,21 @@ msgstr ""
msgid "BranchRules|Require approval from code owners."
msgstr ""
+msgid "BranchRules|Required approvals (%{total})"
+msgstr ""
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr ""
+
msgid "BranchRules|Roles"
msgstr ""
msgid "BranchRules|Status checks"
msgstr ""
+msgid "BranchRules|Status checks (%{total})"
+msgstr ""
+
msgid "BranchRules|Target Branch"
msgstr ""
@@ -6883,6 +7017,9 @@ msgstr ""
msgid "Broadcast Messages"
msgstr ""
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr ""
+
msgid "Browse Directory"
msgstr "ç€è¦½ç›®éŒ„"
@@ -6892,9 +7029,6 @@ msgstr "ç€è¦½æ–‡ä»¶"
msgid "Browse Files"
msgstr "ç€è¦½æ–‡ä»¶"
-msgid "Browse artifacts"
-msgstr ""
-
msgid "Browse files"
msgstr "ç€è¦½æ–‡ä»¶"
@@ -6940,9 +7074,6 @@ msgstr ""
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr ""
-msgid "BulkImport|From source group"
-msgstr ""
-
msgid "BulkImport|Group import history"
msgstr ""
@@ -6973,6 +7104,9 @@ msgstr ""
msgid "BulkImport|Name already used as a target for another group."
msgstr ""
+msgid "BulkImport|New group"
+msgstr ""
+
msgid "BulkImport|No additional information provided."
msgstr ""
@@ -6988,6 +7122,9 @@ msgstr ""
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr ""
+msgid "BulkImport|Path of the new group."
+msgstr ""
+
msgid "BulkImport|Project import history"
msgstr ""
@@ -7012,9 +7149,6 @@ msgstr ""
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr ""
-msgid "BulkImport|To new group"
-msgstr ""
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr ""
@@ -7427,9 +7561,6 @@ msgstr ""
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr ""
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr ""
-
msgid "Cannot be merged automatically"
msgstr ""
@@ -7445,6 +7576,9 @@ msgstr ""
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr ""
+msgid "Cannot delete the default framework"
+msgstr ""
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
@@ -8182,6 +8316,9 @@ msgstr ""
msgid "CiVariables|Masked"
msgstr ""
+msgid "CiVariables|Options"
+msgstr ""
+
msgid "CiVariables|Protected"
msgstr ""
@@ -9495,10 +9632,16 @@ msgstr ""
msgid "Comment/Reply (quoting selected text)"
msgstr ""
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr ""
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
msgstr ""
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr ""
+
+msgid "Commenting on this line is not supported"
msgstr ""
msgid "Comments"
@@ -9679,6 +9822,9 @@ msgstr ""
msgid "Complete verification to sign up."
msgstr ""
+msgid "Complete with errors"
+msgstr ""
+
msgid "Completed"
msgstr ""
@@ -10471,10 +10617,10 @@ msgstr ""
msgid "Contribution Analytics"
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
msgstr ""
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
msgstr ""
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
@@ -10507,6 +10653,15 @@ msgstr ""
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr ""
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr ""
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr ""
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr ""
+
msgid "Contributions for %{calendar_date}"
msgstr ""
@@ -10555,9 +10710,6 @@ msgstr ""
msgid "Copy %{protocol} clone URL"
msgstr ""
-msgid "Copy %{type}"
-msgstr ""
-
msgid "Copy ID"
msgstr ""
@@ -10642,9 +10794,6 @@ msgstr ""
msgid "Copy source branch name"
msgstr ""
-msgid "Copy the code below to implement tracking in your application:"
-msgstr ""
-
msgid "Copy this registration token."
msgstr ""
@@ -10807,9 +10956,6 @@ msgstr ""
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr ""
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr ""
-
msgid "Could not remove the trigger."
msgstr ""
@@ -11029,9 +11175,6 @@ msgstr ""
msgid "Create new label"
msgstr "建立新標籤"
-msgid "Create new project"
-msgstr ""
-
msgid "Create new..."
msgstr ""
@@ -11299,9 +11442,6 @@ msgstr ""
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr ""
-msgid "Creation date"
-msgstr ""
-
msgid "Creator"
msgstr ""
@@ -11317,7 +11457,7 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
-msgid "CredentialsInventory|Project Access Tokens"
+msgid "CredentialsInventory|Project and Group Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
@@ -11419,9 +11559,6 @@ msgstr ""
msgid "Current Project"
msgstr ""
-msgid "Current forks will keep their visibility level."
-msgstr ""
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr ""
@@ -11747,6 +11884,9 @@ msgstr ""
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr ""
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr ""
+
msgid "DORA4Metrics|Date"
msgstr ""
@@ -11774,6 +11914,9 @@ msgstr ""
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr ""
+msgid "DORA4Metrics|Month to date"
+msgstr ""
+
msgid "DORA4Metrics|No incidents during this period"
msgstr ""
@@ -11831,6 +11974,9 @@ msgstr ""
msgid "DashboardProjects|Trending"
msgstr ""
+msgid "Dashboards"
+msgstr ""
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr ""
@@ -12065,6 +12211,9 @@ msgstr ""
msgid "DastProfiles|Save profile"
msgstr ""
+msgid "DastProfiles|Scan Method"
+msgstr ""
+
msgid "DastProfiles|Scan method"
msgstr ""
@@ -12282,6 +12431,9 @@ msgstr ""
msgid "Data type"
msgstr ""
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr ""
+
msgid "Database update failed"
msgstr ""
@@ -12369,6 +12521,9 @@ msgstr ""
msgid "Days"
msgstr ""
+msgid "Days of inactivity before deactivation"
+msgstr ""
+
msgid "Days to merge"
msgstr ""
@@ -12402,6 +12557,9 @@ msgstr ""
msgid "Decrease"
msgstr ""
+msgid "Default - Never run"
+msgstr ""
+
msgid "Default CI/CD configuration file"
msgstr ""
@@ -12513,6 +12671,9 @@ msgstr "刪除"
msgid "Delete %{issuableType}"
msgstr ""
+msgid "Delete %{issuableType}?"
+msgstr ""
+
msgid "Delete %{name}"
msgstr ""
@@ -12534,9 +12695,6 @@ msgstr ""
msgid "Delete account"
msgstr ""
-msgid "Delete artifacts"
-msgstr ""
-
msgid "Delete asset"
msgstr ""
@@ -12603,7 +12761,7 @@ msgstr ""
msgid "Delete row"
msgstr ""
-msgid "Delete self monitoring project"
+msgid "Delete self-monitoring project"
msgstr ""
msgid "Delete snippet"
@@ -13074,6 +13232,9 @@ msgstr ""
msgid "DeployTokens|Expires"
msgstr ""
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr ""
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr ""
@@ -13161,6 +13322,21 @@ msgstr ""
msgid "Deployment frequency"
msgstr ""
+msgid "DeploymentApprovals|Approvals"
+msgstr ""
+
+msgid "DeploymentApprovals|Approved By"
+msgstr ""
+
+msgid "DeploymentApprovals|Approvers"
+msgstr ""
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr ""
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr ""
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr ""
@@ -13499,6 +13675,9 @@ msgstr ""
msgid "DevOps adoption"
msgstr ""
+msgid "Developer"
+msgstr ""
+
msgid "Development"
msgstr ""
@@ -13735,6 +13914,12 @@ msgstr[0] ""
msgid "Diffs|Expand all lines"
msgstr ""
+msgid "Diffs|Hide whitespace changes"
+msgstr ""
+
+msgid "Diffs|Inline"
+msgstr ""
+
msgid "Diffs|Next 20 lines"
msgstr ""
@@ -13750,10 +13935,16 @@ msgstr ""
msgid "Diffs|Show all unchanged lines"
msgstr ""
+msgid "Diffs|Show whitespace changes"
+msgstr ""
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] ""
+msgid "Diffs|Side-by-side"
+msgstr ""
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr ""
@@ -14358,6 +14549,12 @@ msgstr ""
msgid "Edited %{timeago}"
msgstr ""
+msgid "Edited %{timeago} by %{author}"
+msgstr ""
+
+msgid "Edited by %{author}"
+msgstr ""
+
msgid "Editing"
msgstr ""
@@ -14688,22 +14885,40 @@ msgstr ""
msgid "Enable version check"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr ""
+
+msgid "EnableReviewApp|Copy snippet"
+msgstr ""
+
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr ""
+
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr ""
+
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr ""
+
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr ""
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
msgstr ""
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
msgstr ""
-msgid "EnableReviewApp|Close"
+msgid "EnableReviewApp|Using a static site?"
msgstr ""
-msgid "EnableReviewApp|Copy snippet text"
+msgid "EnableReviewApp|View more example projects"
msgstr ""
msgid "Enabled"
@@ -14931,6 +15146,9 @@ msgstr ""
msgid "Environments|Commit"
msgstr ""
+msgid "Environments|Copy live environment URL"
+msgstr ""
+
msgid "Environments|Delete"
msgstr ""
@@ -15111,10 +15329,10 @@ msgstr ""
msgid "Epics|Add an existing epic"
msgstr ""
-msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
-msgid "Epics|Assign Epic"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr ""
msgid "Epics|Leave empty to inherit from milestone dates"
@@ -15129,18 +15347,9 @@ msgstr ""
msgid "Epics|Remove issue"
msgstr ""
-msgid "Epics|Search epics"
-msgstr ""
-
-msgid "Epics|Select epic"
-msgstr ""
-
msgid "Epics|Show more"
msgstr ""
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr ""
-
msgid "Epics|Something went wrong while creating child epics."
msgstr ""
@@ -15153,18 +15362,12 @@ msgstr ""
msgid "Epics|Something went wrong while fetching epics list."
msgstr ""
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr ""
-
msgid "Epics|Something went wrong while moving item."
msgstr ""
msgid "Epics|Something went wrong while ordering item."
msgstr ""
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr ""
-
msgid "Epics|Something went wrong while updating epics."
msgstr ""
@@ -15294,9 +15497,6 @@ msgstr ""
msgid "Error occurred when saving reviewers"
msgstr ""
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr ""
-
msgid "Error occurred while updating the issue status"
msgstr ""
@@ -15360,9 +15560,6 @@ msgstr "上傳檔案時出錯"
msgid "Error uploading file. Please try again."
msgstr ""
-msgid "Error uploading file: %{stripped}"
-msgstr ""
-
msgid "Error while loading the merge request. Please try again."
msgstr ""
@@ -15603,6 +15800,57 @@ msgstr ""
msgid "Events API"
msgstr ""
+msgid "Event|accepted"
+msgstr ""
+
+msgid "Event|added"
+msgstr ""
+
+msgid "Event|approved"
+msgstr ""
+
+msgid "Event|closed"
+msgstr ""
+
+msgid "Event|commented on"
+msgstr ""
+
+msgid "Event|created"
+msgstr ""
+
+msgid "Event|deleted"
+msgstr ""
+
+msgid "Event|destroyed"
+msgstr ""
+
+msgid "Event|imported"
+msgstr ""
+
+msgid "Event|joined"
+msgstr ""
+
+msgid "Event|left"
+msgstr ""
+
+msgid "Event|opened"
+msgstr ""
+
+msgid "Event|pushed new"
+msgstr ""
+
+msgid "Event|pushed to"
+msgstr ""
+
+msgid "Event|removed"
+msgstr ""
+
+msgid "Event|removed due to membership expiration from"
+msgstr ""
+
+msgid "Event|updated"
+msgstr ""
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr ""
@@ -15721,6 +15969,9 @@ msgstr ""
msgid "Execution time"
msgstr ""
+msgid "Executive Dashboard"
+msgstr ""
+
msgid "Existing branch name, tag, or commit SHA"
msgstr ""
@@ -15778,9 +16029,15 @@ msgstr ""
msgid "Expected documents: %{expected_documents}"
msgstr ""
+msgid "Experiment Candidates"
+msgstr ""
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr ""
+msgid "Experiments"
+msgstr ""
+
msgid "Expiration"
msgstr ""
@@ -16004,6 +16261,9 @@ msgstr ""
msgid "Failed to add a Zoom meeting"
msgstr ""
+msgid "Failed to add a resource link"
+msgstr ""
+
msgid "Failed to apply commands."
msgstr ""
@@ -16050,9 +16310,6 @@ msgstr ""
msgid "Failed to create import label for jira import."
msgstr ""
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr ""
-
msgid "Failed to create repository"
msgstr ""
@@ -16248,9 +16505,6 @@ msgstr ""
msgid "Failed to update the Canary Ingress."
msgstr ""
-msgid "Failed to update."
-msgstr ""
-
msgid "Failed to upgrade."
msgstr ""
@@ -16507,6 +16761,9 @@ msgstr "二月"
msgid "February"
msgstr "二月"
+msgid "Feedback and Updates"
+msgstr ""
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr ""
@@ -16612,9 +16869,6 @@ msgstr ""
msgid "Filter by merge requests that are currently merged."
msgstr ""
-msgid "Filter by milestone"
-msgstr ""
-
msgid "Filter by milestone name"
msgstr "é€éŽé‡Œç¨‹ç¢‘å稱篩é¸"
@@ -16822,6 +17076,9 @@ msgstr ""
msgid "For more information, see the File Hooks documentation."
msgstr ""
+msgid "Forbidden"
+msgstr ""
+
msgid "Forgot your password?"
msgstr ""
@@ -17651,9 +17908,6 @@ msgstr ""
msgid "Get a free instance review"
msgstr ""
-msgid "Get a free trial"
-msgstr ""
-
msgid "Get a support subscription"
msgstr ""
@@ -17780,6 +18034,12 @@ msgstr ""
msgid "GitLab Billing Team."
msgstr ""
+msgid "GitLab Community Edition"
+msgstr ""
+
+msgid "GitLab Enterprise Edition"
+msgstr ""
+
msgid "GitLab Error Tracking"
msgstr ""
@@ -17831,6 +18091,9 @@ 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 ""
@@ -17879,9 +18142,6 @@ msgstr ""
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr ""
-msgid "GitLab.com"
-msgstr ""
-
msgid "GitLab.com (SaaS)"
msgstr ""
@@ -18437,9 +18697,6 @@ msgstr ""
msgid "GraphViewType|Stage"
msgstr ""
-msgid "Graphs"
-msgstr ""
-
msgid "Gravatar"
msgstr ""
@@ -18449,6 +18706,9 @@ msgstr ""
msgid "Group"
msgstr ""
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr ""
+
msgid "Group %{group_name} couldn't be exported."
msgstr ""
@@ -19211,12 +19471,6 @@ msgstr ""
msgid "GroupsTree|Loading groups"
msgstr ""
-msgid "GroupsTree|No groups matched your search"
-msgstr ""
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr ""
-
msgid "GroupsTree|Options"
msgstr ""
@@ -19286,6 +19540,9 @@ msgstr ""
msgid "Groups|You're creating a new top-level group"
msgstr ""
+msgid "Guest"
+msgstr ""
+
msgid "Guideline"
msgstr ""
@@ -19462,9 +19719,6 @@ msgstr "å¥åº·ä¿¡æ¯å¯ä»¥å¾žä»¥ä¸‹ç«¯é»žæª¢ç´¢ã€‚想了解更多信æ¯è«‹æŸ¥çœ‹
msgid "Health status"
msgstr ""
-msgid "Health status cannot be edited because this issue is closed"
-msgstr ""
-
msgid "HealthCheck|Access token is"
msgstr "訪å•ä»¤ç‰Œæ˜¯"
@@ -19917,7 +20171,13 @@ msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
-msgid "IdentityVerification|Step 1: Verify phone number"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr ""
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Send a new code and try again."
@@ -20004,12 +20264,6 @@ msgstr ""
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr ""
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr ""
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr ""
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr ""
@@ -21757,6 +22011,9 @@ msgstr ""
msgid "Invalid yaml"
msgstr ""
+msgid "Invalidated"
+msgstr ""
+
msgid "Investigate vulnerability: %{title}"
msgstr ""
@@ -21775,9 +22032,6 @@ msgstr ""
msgid "Invite \"%{email}\" by email"
msgstr ""
-msgid "Invite \"%{trimmed}\" by email"
-msgstr ""
-
msgid "Invite Members"
msgstr ""
@@ -21835,7 +22089,7 @@ msgstr ""
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr ""
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
@@ -21914,19 +22168,16 @@ msgid "InviteMembersModal|The following member couldn't be invited"
msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] ""
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr ""
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr ""
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr ""
-msgid "InviteMembersModal|Username or email address"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
msgstr ""
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
+msgid "InviteMembersModal|Username or email address"
msgstr ""
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
@@ -22064,12 +22315,18 @@ msgstr ""
msgid "Is using seat"
msgstr ""
+msgid "IssuableEvents|assigned to"
+msgstr ""
+
msgid "IssuableEvents|removed review request for"
msgstr ""
msgid "IssuableEvents|requested review from"
msgstr ""
+msgid "IssuableEvents|unassigned"
+msgstr ""
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr ""
@@ -22091,6 +22348,18 @@ msgstr ""
msgid "IssuableStatus|promoted"
msgstr ""
+msgid "Issuable|epic"
+msgstr ""
+
+msgid "Issuable|escalation policy"
+msgstr ""
+
+msgid "Issuable|iteration"
+msgstr ""
+
+msgid "Issuable|milestone"
+msgstr ""
+
msgid "Issue"
msgstr ""
@@ -22316,6 +22585,21 @@ msgstr ""
msgid "IssuesAnalytics|Total:"
msgstr ""
+msgid "Issues|Move selected"
+msgstr ""
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr ""
+
+msgid "Issues|Tasks can not be moved."
+msgstr ""
+
+msgid "Issues|Test cases can not be moved."
+msgstr ""
+
+msgid "Issues|There was an error while moving the issues."
+msgstr ""
+
msgid "Issue|Title"
msgstr ""
@@ -22610,6 +22894,9 @@ msgstr ""
msgid "JiraConnect|Jira Connect Application ID"
msgstr ""
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr ""
+
msgid "JiraConnect|New branch was successfully created."
msgstr ""
@@ -22940,6 +23227,9 @@ msgstr ""
msgid "Job|Download"
msgstr ""
+msgid "Job|Duration"
+msgstr ""
+
msgid "Job|Erase job log and artifacts"
msgstr ""
@@ -22979,9 +23269,15 @@ msgstr ""
msgid "Job|Preparing"
msgstr ""
+msgid "Job|Queued"
+msgstr ""
+
msgid "Job|Retry"
msgstr ""
+msgid "Job|Run again"
+msgstr ""
+
msgid "Job|Running"
msgstr ""
@@ -23356,9 +23652,6 @@ msgstr ""
msgid "Last event"
msgstr ""
-msgid "Last item before this page loaded in your browser:"
-msgstr ""
-
msgid "Last modified"
msgstr ""
@@ -23512,6 +23805,15 @@ msgstr ""
msgid "Learn more about issues."
msgstr ""
+msgid "Learn more about linking epics"
+msgstr ""
+
+msgid "Learn more about linking issues"
+msgstr ""
+
+msgid "Learn more about linking issues and incidents"
+msgstr ""
+
msgid "Learn more about max seats used"
msgstr ""
@@ -23662,9 +23964,6 @@ msgstr "退出項目"
msgid "Leave zen mode"
msgstr ""
-msgid "Leaving this setting enabled is recommended."
-msgstr ""
-
msgid "Legacy burndown chart"
msgstr ""
@@ -23905,6 +24204,12 @@ msgstr ""
msgid "Link"
msgstr ""
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr ""
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr ""
+
msgid "Link (optional)"
msgstr ""
@@ -24175,9 +24480,6 @@ msgstr ""
msgid "Logs"
msgstr ""
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr ""
-
msgid "Low vulnerabilities present"
msgstr ""
@@ -24190,6 +24492,9 @@ msgstr ""
msgid "MERGED"
msgstr ""
+msgid "ML Experiments"
+msgstr ""
+
msgid "MR widget|Back to the merge request"
msgstr ""
@@ -24226,7 +24531,13 @@ msgstr ""
msgid "MRDiff|Show full file"
msgstr ""
-msgid "Made this issue confidential."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr ""
+
+msgid "Machine Learning Experiments"
+msgstr ""
+
+msgid "Made this %{type} confidential."
msgstr ""
msgid "Mailgun"
@@ -24241,9 +24552,15 @@ msgstr ""
msgid "Main menu"
msgstr ""
+msgid "Maintainer"
+msgstr ""
+
msgid "Maintenance mode"
msgstr ""
+msgid "Make %{type} confidential"
+msgstr ""
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr ""
@@ -24253,9 +24570,6 @@ msgstr ""
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr ""
-msgid "Make issue confidential"
-msgstr ""
-
msgid "Make sure you choose a strong, unique password."
msgstr ""
@@ -24265,7 +24579,7 @@ msgstr ""
msgid "Make sure you save it - you won't be able to access it again."
msgstr ""
-msgid "Makes this issue confidential."
+msgid "Makes this %{type} confidential."
msgstr ""
msgid "Manage %{workspace} labels"
@@ -24322,6 +24636,9 @@ msgstr ""
msgid "Manifest"
msgstr ""
+msgid "Manifest file"
+msgstr ""
+
msgid "Manifest file import"
msgstr ""
@@ -24346,6 +24663,9 @@ msgstr "三月"
msgid "March"
msgstr "三月"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr ""
+
msgid "Mark as done"
msgstr ""
@@ -24397,6 +24717,9 @@ msgstr ""
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr ""
+msgid "MarkdownEditor|Click to expand"
+msgstr ""
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr ""
@@ -24409,6 +24732,9 @@ msgstr ""
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr ""
+msgid "MarkdownEditor|header"
+msgstr ""
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr ""
@@ -25035,6 +25361,9 @@ msgstr ""
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr ""
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr ""
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr ""
@@ -25260,6 +25589,9 @@ msgstr ""
msgid "Method call threshold (ms)"
msgstr ""
+msgid "Metric"
+msgstr ""
+
msgid "Metric was successfully added."
msgstr ""
@@ -25649,6 +25981,9 @@ msgstr ""
msgid "Milestone lists not available with your current license"
msgstr "ç›®å‰è¨±å¯è­‰ç„¡æ³•ä½¿ç”¨é‡Œç¨‹ç¢‘列表"
+msgid "Milestone(s) not found: %{milestones}"
+msgstr ""
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr ""
@@ -25808,6 +26143,9 @@ msgstr ""
msgid "Min Value"
msgstr ""
+msgid "Minimal Access"
+msgstr ""
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr ""
@@ -25880,6 +26218,9 @@ msgstr ""
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr ""
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr ""
+
msgid "ModalButton|Add projects"
msgstr ""
@@ -26066,6 +26407,9 @@ msgstr ""
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr ""
+msgid "Must be 90 days or more."
+msgstr ""
+
msgid "My awesome group"
msgstr ""
@@ -26524,6 +26868,9 @@ msgstr ""
msgid "No Work Item Link found"
msgstr ""
+msgid "No access"
+msgstr ""
+
msgid "No active admin user found"
msgstr ""
@@ -26653,9 +27000,6 @@ msgstr ""
msgid "No job log"
msgstr ""
-msgid "No jobs to show"
-msgstr ""
-
msgid "No label"
msgstr ""
@@ -26683,9 +27027,6 @@ msgstr ""
msgid "No matching results for \"%{query}\""
msgstr ""
-msgid "No matching results..."
-msgstr ""
-
msgid "No members found"
msgstr ""
@@ -26701,9 +27042,6 @@ msgstr ""
msgid "No milestone"
msgstr ""
-msgid "No namespace"
-msgstr ""
-
msgid "No other labels with such name or description"
msgstr ""
@@ -26936,7 +27274,7 @@ msgstr ""
msgid "Notes|Expand replies"
msgstr ""
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
msgstr ""
msgid "Notes|Last reply by %{name}"
@@ -27267,6 +27605,9 @@ msgstr ""
msgid "Notify|No preview for this file type"
msgstr ""
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr ""
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr ""
@@ -27276,6 +27617,9 @@ msgstr ""
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr ""
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr ""
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr ""
@@ -27297,6 +27641,9 @@ msgstr ""
msgid "Notify|The download link will expire in 24 hours."
msgstr ""
+msgid "Notify|The errors we encountered were:"
+msgstr ""
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr ""
@@ -27390,9 +27737,6 @@ msgstr ""
msgid "Number of events"
msgstr ""
-msgid "Number of events for this project: %{total_count}."
-msgstr ""
-
msgid "Number of files touched"
msgstr ""
@@ -27417,9 +27761,6 @@ msgstr "å月"
msgid "October"
msgstr "å月"
-msgid "OfSearchInADropdown|Filter"
-msgstr "篩é¸"
-
msgid "Off"
msgstr ""
@@ -27652,12 +27993,6 @@ msgstr ""
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr ""
-msgid "OnDemandScans|Create new scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Create new site profile"
-msgstr ""
-
msgid "OnDemandScans|DAST configuration"
msgstr ""
@@ -27703,12 +28038,6 @@ msgstr ""
msgid "OnDemandScans|Keep editing"
msgstr ""
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr ""
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr ""
-
msgid "OnDemandScans|My daily scan"
msgstr ""
@@ -27730,12 +28059,6 @@ msgstr ""
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr ""
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr ""
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr ""
-
msgid "OnDemandScans|On-demand Scans"
msgstr ""
@@ -27778,15 +28101,6 @@ msgstr ""
msgid "OnDemandScans|Scan type"
msgstr ""
-msgid "OnDemandScans|Scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr ""
-
-msgid "OnDemandScans|Site profile"
-msgstr ""
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr ""
@@ -27817,12 +28131,6 @@ msgstr ""
msgid "OnDemandScans|Timezone"
msgstr ""
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr ""
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr ""
-
msgid "OnDemandScans|View results"
msgstr ""
@@ -27841,9 +28149,6 @@ msgstr ""
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr ""
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr ""
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] ""
@@ -28016,9 +28321,6 @@ msgstr ""
msgid "Operation not allowed"
msgstr ""
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr ""
-
msgid "Operations"
msgstr ""
@@ -28386,12 +28688,21 @@ msgstr ""
msgid "PackageRegistry|Delete package asset"
msgstr ""
+msgid "PackageRegistry|Delete package version"
+msgstr ""
+
msgid "PackageRegistry|Delete selected"
msgstr ""
msgid "PackageRegistry|Delete this package"
msgstr ""
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr ""
+
msgid "PackageRegistry|Duplicate packages"
msgstr ""
@@ -28437,6 +28748,12 @@ msgstr ""
msgid "PackageRegistry|Helm"
msgstr ""
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr ""
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr ""
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr ""
@@ -28582,6 +28899,9 @@ msgstr ""
msgid "PackageRegistry|Source project located at %{link}"
msgstr ""
+msgid "PackageRegistry|Take survey"
+msgstr ""
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr ""
@@ -28964,12 +29284,6 @@ msgstr ""
msgid "Period in seconds"
msgstr ""
-msgid "Period of inactivity (days)"
-msgstr ""
-
-msgid "Period of inactivity before deactivation."
-msgstr ""
-
msgid "Permalink"
msgstr ""
@@ -29018,7 +29332,7 @@ msgstr ""
msgid "Phabricator Server URL"
msgstr ""
-msgid "Phabricator Tasks"
+msgid "Phabricator tasks"
msgstr ""
msgid "Phone"
@@ -29237,6 +29551,9 @@ msgstr "已啟用"
msgid "PipelineSchedules|All"
msgstr "所有"
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr ""
+
msgid "PipelineSchedules|Delete pipeline schedule"
msgstr ""
@@ -29252,6 +29569,9 @@ msgstr "未啟用"
msgid "PipelineSchedules|Last Pipeline"
msgstr ""
+msgid "PipelineSchedules|New schedule"
+msgstr ""
+
msgid "PipelineSchedules|Next Run"
msgstr "下次é‹è¡Œæ™‚é–“"
@@ -29264,12 +29584,18 @@ msgstr ""
msgid "PipelineSchedules|Owner"
msgstr ""
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr ""
+
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "為此æµæ°´ç·šæ供簡短æè¿°"
msgid "PipelineSchedules|Run pipeline schedule"
msgstr ""
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr ""
+
msgid "PipelineSchedules|Take ownership"
msgstr "å–得所有權"
@@ -29279,9 +29605,15 @@ msgstr ""
msgid "PipelineSchedules|Target"
msgstr "目標"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
msgstr ""
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr ""
+
msgid "PipelineSchedules|Variables"
msgstr "變é‡"
@@ -30041,9 +30373,6 @@ msgstr ""
msgid "Please select a country"
msgstr ""
-msgid "Please select a file"
-msgstr ""
-
msgid "Please select a group"
msgstr ""
@@ -30152,6 +30481,69 @@ msgstr ""
msgid "Pre-defined push rules"
msgstr ""
+msgid "PreScanVerification|(optional)"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr ""
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr ""
+
+msgid "PreScanVerification|Authentication"
+msgstr ""
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Connection"
+msgstr ""
+
+msgid "PreScanVerification|Download results"
+msgstr ""
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr ""
+
+msgid "PreScanVerification|Save and run verification"
+msgstr ""
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr ""
+
+msgid "PreScanVerification|Target exploration"
+msgstr ""
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr ""
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr ""
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks"
+msgstr ""
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr ""
+
+msgid "PreScanVerification|Verify configuration"
+msgstr ""
+
+msgid "PreScanVerification|View results"
+msgstr ""
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr ""
+
msgid "Preferences"
msgstr ""
@@ -30293,6 +30685,9 @@ msgstr ""
msgid "Prevent environment from auto-stopping"
msgstr ""
+msgid "Prevent outdated deployment jobs"
+msgstr ""
+
msgid "Prevent project forking outside current group"
msgstr ""
@@ -30386,12 +30781,18 @@ msgstr ""
msgid "Proceed"
msgstr ""
-msgid "Product Analytics"
+msgid "Product analytics"
+msgstr ""
+
+msgid "ProductAnalytics|Audience"
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|Widgets content"
+msgstr ""
+
msgid "Productivity"
msgstr ""
@@ -30968,6 +31369,9 @@ msgstr ""
msgid "Project navigation"
msgstr ""
+msgid "Project or Group"
+msgstr ""
+
msgid "Project order will not be saved as local storage is not available."
msgstr ""
@@ -30980,6 +31384,9 @@ msgstr ""
msgid "Project security status help page"
msgstr ""
+msgid "Project settings were successfully updated."
+msgstr ""
+
msgid "Project slug"
msgstr ""
@@ -31262,12 +31669,18 @@ msgstr ""
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr ""
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr ""
+
msgid "ProjectSettings|Additional options"
msgstr ""
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr ""
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr ""
+
msgid "ProjectSettings|All threads must be resolved"
msgstr ""
@@ -31280,12 +31693,18 @@ msgstr ""
msgid "ProjectSettings|Analytics"
msgstr ""
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr ""
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr ""
msgid "ProjectSettings|Badges"
msgstr ""
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr ""
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr ""
@@ -31307,6 +31726,9 @@ msgstr ""
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr ""
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr ""
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr ""
@@ -31406,6 +31828,9 @@ msgstr ""
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr ""
+msgid "ProjectSettings|Infrastructure"
+msgstr ""
+
msgid "ProjectSettings|Internal"
msgstr ""
@@ -31544,6 +31969,9 @@ msgstr ""
msgid "ProjectSettings|Security & Compliance for this project"
msgstr ""
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr ""
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr ""
@@ -31574,6 +32002,9 @@ msgstr ""
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr ""
+msgid "ProjectSettings|Status checks must succeed"
+msgstr ""
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr ""
@@ -31625,6 +32056,9 @@ msgstr ""
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr ""
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr ""
+
msgid "ProjectSettings|Users can request access"
msgstr ""
@@ -32264,6 +32698,9 @@ msgstr ""
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr ""
+msgid "ProtectedBranch|Allowed to create"
+msgstr ""
+
msgid "ProtectedBranch|Allowed to force push"
msgstr ""
@@ -32300,15 +32737,27 @@ msgstr ""
msgid "ProtectedBranch|Code owner approval"
msgstr ""
+msgid "ProtectedBranch|Create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr ""
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr ""
+msgid "ProtectedBranch|Last commit"
+msgstr ""
+
msgid "ProtectedBranch|Learn more."
msgstr ""
+msgid "ProtectedBranch|New Protected Tag"
+msgstr ""
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr ""
+
msgid "ProtectedBranch|Protect"
msgstr ""
@@ -32324,12 +32773,21 @@ msgstr ""
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr ""
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr ""
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr ""
msgid "ProtectedBranch|Require approval from code owners:"
msgstr ""
+msgid "ProtectedBranch|Search protected tags"
+msgstr ""
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr ""
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr ""
@@ -32639,6 +33097,9 @@ msgstr ""
msgid "PushRule|Push rules"
msgstr ""
+msgid "PushRule|Reject inconsistent user name"
+msgstr ""
+
msgid "PushRule|Reject unverified users"
msgstr ""
@@ -32771,12 +33232,6 @@ msgstr "了解更多"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr ""
-msgid "Read more about related epics"
-msgstr ""
-
-msgid "Read more about related issues"
-msgstr ""
-
msgid "Read their documentation."
msgstr ""
@@ -32870,9 +33325,6 @@ msgstr ""
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr ""
-msgid "Reduce this project’s visibility?"
-msgstr ""
-
msgid "Reference"
msgstr ""
@@ -33034,6 +33486,9 @@ msgstr[0] ""
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr ""
+msgid "Release already exists"
+msgstr ""
+
msgid "Release assets"
msgstr ""
@@ -33043,6 +33498,9 @@ msgstr ""
msgid "Release date"
msgstr ""
+msgid "Release does not exist"
+msgstr ""
+
msgid "Release does not have the same project as the milestone"
msgstr ""
@@ -33499,6 +33957,9 @@ msgstr ""
msgid "Reported by %{reporter}"
msgstr ""
+msgid "Reporter"
+msgstr ""
+
msgid "Reporting"
msgstr ""
@@ -33512,10 +33973,6 @@ msgid "Reports|%{recentlyFailed} out of %{failed} failed tests has failed more t
msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days"
msgstr[0] ""
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] ""
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] ""
@@ -33544,18 +34001,12 @@ msgstr ""
msgid "Reports|Base report parsing error:"
msgstr ""
-msgid "Reports|Classname"
-msgstr ""
-
msgid "Reports|Copy failed test names to run locally"
msgstr ""
msgid "Reports|Copy failed tests"
msgstr ""
-msgid "Reports|Execution time"
-msgstr ""
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] ""
@@ -33564,12 +34015,6 @@ msgid "Reports|Failed %{count} time in %{base_branch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 days"
msgstr[0] ""
-msgid "Reports|Failure"
-msgstr ""
-
-msgid "Reports|Filename"
-msgstr ""
-
msgid "Reports|Fixed"
msgstr ""
@@ -33612,21 +34057,12 @@ msgstr ""
msgid "Reports|Severity"
msgstr ""
-msgid "Reports|System output"
-msgstr ""
-
msgid "Reports|Test summary"
msgstr ""
-msgid "Reports|Test summary failed loading results"
-msgstr ""
-
msgid "Reports|Test summary failed to load results"
msgstr ""
-msgid "Reports|Test summary results are being parsed"
-msgstr ""
-
msgid "Reports|Test summary results are loading"
msgstr ""
@@ -33642,9 +34078,6 @@ msgstr ""
msgid "Reports|metrics report"
msgstr ""
-msgid "Reports|no changed test results"
-msgstr ""
-
msgid "Repositories"
msgstr ""
@@ -34012,6 +34445,9 @@ msgstr ""
msgid "Resolved by %{name}"
msgstr ""
+msgid "Resource link added"
+msgstr ""
+
msgid "Response"
msgstr ""
@@ -34239,6 +34675,9 @@ msgstr ""
msgid "Run housekeeping"
msgstr ""
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr ""
+
msgid "Run manual or delayed jobs"
msgstr ""
@@ -34276,6 +34715,9 @@ msgid "Runners|%d selected runner deleted"
msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr ""
+
msgid "Runners|%{percentage} spot."
msgstr ""
@@ -34302,7 +34744,7 @@ msgstr ""
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr ""
-msgid "Runners|Add your feedback in the issue"
+msgid "Runners|Administrator"
msgstr ""
msgid "Runners|All"
@@ -34510,6 +34952,9 @@ msgstr ""
msgid "Runners|Online:"
msgstr ""
+msgid "Runners|Owner"
+msgstr ""
+
msgid "Runners|Pause from accepting jobs"
msgstr ""
@@ -34637,9 +35082,15 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr ""
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr ""
+
msgid "Runners|Runs untagged jobs"
msgstr ""
+msgid "Runners|Select all"
+msgstr ""
+
msgid "Runners|Select projects to assign to this runner"
msgstr ""
@@ -34688,6 +35139,9 @@ msgstr ""
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr ""
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr ""
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr ""
@@ -34722,6 +35176,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
+msgid "Runners|Unselect all"
+msgstr ""
+
msgid "Runners|Up to date"
msgstr ""
@@ -34761,12 +35218,6 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr ""
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr ""
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""
@@ -34821,16 +35272,22 @@ msgstr ""
msgid "SAML for %{group_name}"
msgstr ""
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
+msgid "SAML single sign-on"
+msgstr ""
+
+msgid "SAML single sign-on for %{group_name}"
msgstr ""
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr ""
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr ""
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
msgstr ""
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
msgstr ""
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
@@ -34938,10 +35395,10 @@ msgstr ""
msgid "Saving project."
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
+msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
-msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
+msgid "ScanExecutionPolicy|%{rules} actions for the %{scopes} %{branches} %{agents} %{namespaces}"
msgstr ""
msgid "ScanExecutionPolicy|%{thenLabelStart}Then%{thenLabelEnd} Require a %{scan} scan to run"
@@ -34962,9 +35419,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr ""
+msgid "ScanExecutionPolicy|Select agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select branches"
msgstr ""
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr ""
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr ""
@@ -34974,9 +35437,15 @@ msgstr ""
msgid "ScanExecutionPolicy|Site profile"
msgstr ""
+msgid "ScanExecutionPolicy|agent"
+msgstr ""
+
msgid "ScanExecutionPolicy|branch"
msgstr ""
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr ""
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr ""
@@ -35127,9 +35596,6 @@ msgstr ""
msgid "Search for a group"
msgstr ""
-msgid "Search for a user"
-msgstr ""
-
msgid "Search for an emoji"
msgstr ""
@@ -35525,10 +35991,13 @@ msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
-msgid "SecurityOrchestration|%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
msgstr ""
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr ""
+
+msgid "SecurityOrchestration|%{branches} branch"
msgstr ""
msgid "SecurityOrchestration|%{scanners}"
@@ -35648,6 +36117,9 @@ msgstr ""
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr ""
+msgid "SecurityOrchestration|Invalid policy"
+msgstr ""
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr ""
@@ -35750,10 +36222,10 @@ msgstr ""
msgid "SecurityOrchestration|Scan result policy"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
+msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr ""
-msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
msgstr ""
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
@@ -35843,7 +36315,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
msgstr ""
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
@@ -35861,6 +36333,9 @@ msgstr ""
msgid "SecurityOrchestration|all branches"
msgstr ""
+msgid "SecurityOrchestration|all namespaces"
+msgstr ""
+
msgid "SecurityOrchestration|an"
msgstr ""
@@ -35879,12 +36354,21 @@ msgstr ""
msgid "SecurityOrchestration|the %{branches}"
msgstr ""
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr ""
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr ""
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr ""
+
msgid "SecurityReports|%{count} Selected"
msgstr ""
@@ -35906,6 +36390,9 @@ msgstr ""
msgid "SecurityReports|All activity"
msgstr ""
+msgid "SecurityReports|All severities"
+msgstr ""
+
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr ""
@@ -36035,6 +36522,9 @@ msgstr ""
msgid "SecurityReports|More info"
msgstr ""
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "SecurityReports|No activity"
msgstr ""
@@ -36092,6 +36582,9 @@ msgstr ""
msgid "SecurityReports|Security reports help page link"
msgstr ""
+msgid "SecurityReports|Security scan results"
+msgstr ""
+
msgid "SecurityReports|Security scans have run"
msgstr ""
@@ -36209,9 +36702,15 @@ msgstr ""
msgid "SecurityReports|scanned resources"
msgstr ""
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr ""
+
msgid "SecurityTraining|Primary Training"
msgstr ""
+msgid "SecurityTraining|Resolve with security training"
+msgstr ""
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr ""
@@ -36224,6 +36723,9 @@ msgstr ""
msgid "See our website for help"
msgstr ""
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr ""
+
msgid "See the affected projects in the GitLab admin panel"
msgstr ""
@@ -36287,9 +36789,6 @@ msgstr ""
msgid "Select a template type"
msgstr ""
-msgid "Select a timezone"
-msgstr "é¸æ“‡æ™‚å€"
-
msgid "Select all"
msgstr ""
@@ -36428,10 +36927,10 @@ msgstr ""
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr ""
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr ""
-msgid "Self monitoring project does not exist"
+msgid "Self-monitoring project does not exist"
msgstr ""
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
@@ -36443,28 +36942,28 @@ msgstr ""
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr ""
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
msgstr ""
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
msgstr ""
-msgid "SelfMonitoring|Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?"
+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|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr ""
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully created."
+msgid "SelfMonitoring|Self-monitoring project successfully created."
msgstr ""
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
msgstr ""
msgid "Send"
@@ -36683,9 +37182,6 @@ msgstr ""
msgid "Set the Ready status"
msgstr ""
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr ""
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr ""
@@ -36834,9 +37330,6 @@ msgstr ""
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr ""
-msgid "Setup"
-msgstr ""
-
msgid "Severity"
msgstr ""
@@ -37090,10 +37583,7 @@ msgstr ""
msgid "Showing all issues"
msgstr ""
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr ""
-
-msgid "Showing graphs based on events of the last %{timerange} days."
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
msgstr ""
msgid "Showing last %{size} of log -"
@@ -37147,7 +37637,7 @@ msgstr ""
msgid "Sign in preview"
msgstr ""
-msgid "Sign in to \"%{group_name}\""
+msgid "Sign in to %{group_name}"
msgstr ""
msgid "Sign in to GitLab"
@@ -37162,7 +37652,7 @@ msgstr ""
msgid "Sign in with"
msgstr ""
-msgid "Sign in with Single Sign-On"
+msgid "Sign in with single sign-on"
msgstr ""
msgid "Sign in with smart card"
@@ -37285,9 +37775,6 @@ msgstr ""
msgid "Size limit per repository (MB)"
msgstr ""
-msgid "Skip outdated deployment jobs"
-msgstr ""
-
msgid "Skipped"
msgstr ""
@@ -37510,6 +37997,9 @@ msgstr ""
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr ""
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr ""
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr ""
@@ -37621,9 +38111,6 @@ msgstr ""
msgid "Something went wrong while fetching the packages list."
msgstr ""
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr ""
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr ""
@@ -38197,9 +38684,6 @@ msgstr ""
msgid "Status: %{title}"
msgstr ""
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr ""
-
msgid "StatusCheck|%{failed} failed"
msgstr ""
@@ -38212,9 +38696,6 @@ msgstr ""
msgid "StatusCheck|Add status check"
msgstr ""
-msgid "StatusCheck|All passed"
-msgstr ""
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr ""
@@ -38236,9 +38717,6 @@ msgstr ""
msgid "StatusCheck|Failed to load status checks"
msgstr ""
-msgid "StatusCheck|Failed to load status checks."
-msgstr ""
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr ""
@@ -38758,9 +39236,15 @@ msgstr ""
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr ""
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr ""
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr ""
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr ""
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr ""
@@ -39017,6 +39501,9 @@ msgstr ""
msgid "Switch branch/tag"
msgstr "切æ›åˆ†æ”¯/標籤"
+msgid "Switch editors"
+msgstr ""
+
msgid "Switch to GitLab Next"
msgstr ""
@@ -39107,6 +39594,9 @@ msgstr ""
msgid "Tag"
msgstr ""
+msgid "Tag does not exist"
+msgstr ""
+
msgid "Tag list:"
msgstr ""
@@ -39191,6 +39681,9 @@ msgstr ""
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr ""
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr ""
+
msgid "TagsPage|Edit release"
msgstr ""
@@ -39212,15 +39705,9 @@ msgstr ""
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr ""
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr ""
-
msgid "TagsPage|Please type the following to confirm:"
msgstr ""
-msgid "TagsPage|Release notes"
-msgstr ""
-
msgid "TagsPage|Repository has no tags yet."
msgstr ""
@@ -39242,9 +39729,6 @@ msgstr ""
msgid "TagsPage|Use git tag command to add a new one:"
msgstr ""
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr ""
-
msgid "TagsPage|Yes, delete protected tag"
msgstr ""
@@ -39263,6 +39747,9 @@ msgstr ""
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr ""
+msgid "Target"
+msgstr ""
+
msgid "Target Branch"
msgstr "目標分支"
@@ -39374,14 +39861,6 @@ msgstr ""
msgid "Terraform|%{name} successfully removed"
msgstr ""
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] ""
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] ""
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] ""
@@ -39399,12 +39878,6 @@ msgstr ""
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr ""
-msgid "Terraform|A report failed to generate."
-msgstr ""
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr ""
-
msgid "Terraform|Actions"
msgstr ""
@@ -39492,12 +39965,6 @@ msgstr ""
msgid "Terraform|Terraform reports"
msgstr ""
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr ""
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr ""
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr ""
@@ -39947,6 +40414,9 @@ msgstr ""
msgid "The hostname of your Snowplow collector."
msgstr ""
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr ""
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr ""
@@ -40142,9 +40612,6 @@ msgstr ""
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr ""
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr ""
-
msgid "The scan has been created."
msgstr ""
@@ -40175,7 +40642,7 @@ msgstr ""
msgid "The specified tab is invalid, please select another"
msgstr ""
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr ""
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40232,9 +40699,6 @@ msgstr ""
msgid "Theme"
msgstr ""
-msgid "There are currently no events."
-msgstr ""
-
msgid "There are currently no mirrored repositories."
msgstr ""
@@ -40586,9 +41050,6 @@ msgstr ""
msgid "These runners are shared across projects in this group."
msgstr ""
-msgid "These runners are shared across this GitLab instance."
-msgstr ""
-
msgid "These runners are specific to this project."
msgstr ""
@@ -40622,6 +41083,9 @@ msgstr ""
msgid "This Cron pattern is invalid"
msgstr ""
+msgid "This Experiment has no logged Candidates"
+msgstr ""
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr ""
@@ -40790,9 +41254,6 @@ msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
-
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
@@ -40853,6 +41314,9 @@ msgstr ""
msgid "This group has no active access tokens."
msgstr ""
+msgid "This group has no projects yet"
+msgstr ""
+
msgid "This group is linked to a subscription"
msgstr ""
@@ -41069,13 +41533,16 @@ msgstr ""
msgid "This namespace has already been taken! Please choose another one."
msgstr ""
+msgid "This namespace has already been taken. Choose a different one."
+msgstr ""
+
msgid "This only applies to repository indexing operations."
msgstr ""
-msgid "This page is unavailable because you are not allowed to read information across multiple projects."
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
msgstr ""
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
+msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr ""
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
@@ -41204,9 +41671,6 @@ msgstr ""
msgid "This user has no active %{accessTokenTypePlural}."
msgstr ""
-msgid "This user has no active %{type}."
-msgstr ""
-
msgid "This user has no identities"
msgstr ""
@@ -41225,6 +41689,9 @@ msgstr ""
msgid "This variable can not be masked."
msgstr ""
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr ""
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr ""
@@ -41593,9 +42060,6 @@ msgstr ""
msgid "To complete registration, we need additional details from you."
msgstr ""
-msgid "To confirm, type %{phrase_code}"
-msgstr ""
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr ""
@@ -41701,6 +42165,9 @@ msgstr ""
msgid "To reactivate your account, sign in to GitLab at %{gitlab_url}."
msgstr ""
+msgid "To remove the %{link_start}read-only%{link_end} state and regain write access, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr ""
+
msgid "To resolve this, try to:"
msgstr ""
@@ -41767,9 +42234,33 @@ msgstr "今天"
msgid "Todos count"
msgstr ""
+msgid "Todos|Added"
+msgstr ""
+
+msgid "Todos|Alert"
+msgstr ""
+
+msgid "Todos|Any Action"
+msgstr ""
+
+msgid "Todos|Any Type"
+msgstr ""
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr ""
+msgid "Todos|Assigned"
+msgstr ""
+
+msgid "Todos|Could not merge"
+msgstr ""
+
+msgid "Todos|Design"
+msgstr ""
+
+msgid "Todos|Epic"
+msgstr ""
+
msgid "Todos|Filter by author"
msgstr ""
@@ -41791,18 +42282,39 @@ msgstr ""
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr ""
+msgid "Todos|Issue"
+msgstr ""
+
msgid "Todos|It's how you always know what to work on next."
msgstr ""
msgid "Todos|Mark all as done"
msgstr ""
+msgid "Todos|Mentioned"
+msgstr ""
+
+msgid "Todos|Merge request"
+msgstr ""
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr ""
msgid "Todos|Nothing left to do. High five!"
msgstr ""
+msgid "Todos|Pipelines"
+msgstr ""
+
+msgid "Todos|Removed from Merge Train:"
+msgstr ""
+
+msgid "Todos|Review requested"
+msgstr ""
+
+msgid "Todos|The pipeline failed in"
+msgstr ""
+
msgid "Todos|Undo mark all as done"
msgstr ""
@@ -41815,6 +42327,24 @@ msgstr ""
msgid "Todos|Your To-Do List shows what to work on next"
msgstr ""
+msgid "Todos|added a todo for"
+msgstr ""
+
+msgid "Todos|mentioned %{who} on"
+msgstr ""
+
+msgid "Todos|requested a review of"
+msgstr ""
+
+msgid "Todos|set %{who} as an approver for"
+msgstr ""
+
+msgid "Todos|yourself"
+msgstr ""
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr ""
+
msgid "Toggle GitLab Next"
msgstr ""
@@ -41965,9 +42495,6 @@ msgstr ""
msgid "Total Score"
msgstr ""
-msgid "Total artifacts size: %{total_size}"
-msgstr ""
-
msgid "Total cores (CPUs)"
msgstr ""
@@ -42287,6 +42814,12 @@ msgstr ""
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr ""
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr ""
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr ""
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr ""
@@ -42791,6 +43324,12 @@ msgstr ""
msgid "Usage statistics"
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 ""
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr ""
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr ""
@@ -42893,6 +43432,9 @@ msgstr ""
msgid "UsageQuota|No CI minutes usage data available."
msgstr ""
+msgid "UsageQuota|No projects to display."
+msgstr ""
+
msgid "UsageQuota|Packages"
msgstr ""
@@ -42923,6 +43465,9 @@ msgstr ""
msgid "UsageQuota|Repository"
msgstr ""
+msgid "UsageQuota|Search"
+msgstr ""
+
msgid "UsageQuota|Seats"
msgstr ""
@@ -43970,9 +44515,6 @@ msgstr ""
msgid "View full dashboard"
msgstr ""
-msgid "View full log"
-msgstr ""
-
msgid "View group in admin area"
msgstr ""
@@ -44433,6 +44975,9 @@ msgstr ""
msgid "Vulnerability|Scanner Provider"
msgstr ""
+msgid "Vulnerability|Scanner:"
+msgstr ""
+
msgid "Vulnerability|Security Audit"
msgstr ""
@@ -44451,6 +44996,9 @@ msgstr ""
msgid "Vulnerability|Status"
msgstr ""
+msgid "Vulnerability|Status:"
+msgstr ""
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr ""
@@ -44586,7 +45134,7 @@ msgstr ""
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr ""
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
msgstr ""
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
@@ -44628,6 +45176,9 @@ msgstr ""
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr ""
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr ""
+
msgid "WebIDE|Fork project"
msgstr ""
@@ -44643,12 +45194,24 @@ msgstr ""
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr ""
+msgid "WebIDE|Ready for something new?"
+msgstr ""
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr ""
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr ""
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr ""
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr ""
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr ""
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr ""
@@ -44688,6 +45251,9 @@ msgstr ""
msgid "Webhooks Help"
msgstr ""
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr ""
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr ""
@@ -44802,6 +45368,12 @@ msgstr ""
msgid "Webhooks|Push to the repository."
msgstr ""
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr ""
+
+msgid "Webhooks|Regular expression"
+msgstr ""
+
msgid "Webhooks|Releases events"
msgstr ""
@@ -44829,9 +45401,6 @@ msgstr ""
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr ""
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr ""
-
msgid "Webhooks|Trigger"
msgstr ""
@@ -44844,7 +45413,7 @@ msgstr ""
msgid "Webhooks|URL preview"
msgstr ""
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
msgstr ""
msgid "Webhooks|Webhook disabled"
@@ -44856,12 +45425,21 @@ msgstr ""
msgid "Webhooks|Webhook fails to connect"
msgstr ""
-msgid "Webhooks|Webhook was automatically disabled"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr ""
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
msgstr ""
msgid "Webhooks|Wiki page events"
msgstr ""
+msgid "Webhooks|Wildcard pattern"
+msgstr ""
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr ""
+
msgid "Website"
msgstr ""
@@ -44940,6 +45518,9 @@ msgstr ""
msgid "What templates can I create?"
msgstr ""
+msgid "What variables can I use?"
+msgstr ""
+
msgid "What will you use this group for?"
msgstr ""
@@ -44949,7 +45530,7 @@ msgstr ""
msgid "What's new"
msgstr ""
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
msgstr ""
msgid "When a runner is locked, it cannot be assigned to other projects"
@@ -45263,6 +45844,12 @@ msgstr ""
msgid "WorkItem|Add task"
msgstr ""
+msgid "WorkItem|Add to iteration"
+msgstr ""
+
+msgid "WorkItem|Add to milestone"
+msgstr ""
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr ""
@@ -45312,9 +45899,24 @@ msgstr ""
msgid "WorkItem|Issue"
msgstr ""
+msgid "WorkItem|Iteration"
+msgstr ""
+
msgid "WorkItem|Learn about tasks."
msgstr ""
+msgid "WorkItem|Milestone"
+msgstr ""
+
+msgid "WorkItem|No iteration"
+msgstr ""
+
+msgid "WorkItem|No matching results"
+msgstr ""
+
+msgid "WorkItem|No milestone"
+msgstr ""
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr ""
@@ -45345,10 +45947,13 @@ msgstr ""
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
msgstr ""
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr ""
+
+msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr ""
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
@@ -45360,6 +45965,9 @@ msgstr ""
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr ""
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr ""
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr ""
@@ -45381,6 +45989,9 @@ msgstr ""
msgid "WorkItem|Test case"
msgstr ""
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr ""
+
msgid "WorkItem|Turn off confidentiality"
msgstr ""
@@ -45399,6 +46010,9 @@ msgstr ""
msgid "WorkItem|Work item"
msgstr ""
+msgid "WorkItem|Work item not found"
+msgstr ""
+
msgid "Would you like to create a new branch?"
msgstr ""
@@ -45493,6 +46107,9 @@ msgstr ""
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr ""
+msgid "You are being redirected away from GitLab"
+msgstr ""
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr ""
@@ -45529,6 +46146,12 @@ msgstr ""
msgid "You are not allowed to approve a user"
msgstr ""
+msgid "You are not allowed to create this tag as it is protected."
+msgstr ""
+
+msgid "You are not allowed to download code from this project."
+msgstr ""
+
msgid "You are not allowed to log in using password"
msgstr ""
@@ -45574,9 +46197,6 @@ msgstr ""
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr ""
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr ""
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr ""
@@ -45677,6 +46297,9 @@ msgstr ""
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr ""
+msgid "You can enter up to 280 characters"
+msgstr ""
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr ""
@@ -45749,7 +46372,7 @@ msgstr ""
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr ""
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
msgstr ""
msgid "You cannot %{action} %{state} users."
@@ -45773,6 +46396,9 @@ msgstr ""
msgid "You cannot impersonate a user who cannot log in"
msgstr ""
+msgid "You cannot impersonate a user with an expired password"
+msgstr ""
+
msgid "You cannot impersonate an internal user"
msgstr ""
@@ -45915,6 +46541,9 @@ msgstr ""
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr ""
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr ""
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr ""
@@ -45978,7 +46607,7 @@ msgstr ""
msgid "You must be logged in to search across all of GitLab"
msgstr ""
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
msgstr ""
msgid "You must have maintainer access to force delete a lock"
@@ -46146,9 +46775,6 @@ msgstr ""
msgid "Your %{group} membership will now expire in %{days}."
msgstr ""
-msgid "Your %{host} account was signed in to from a new location"
-msgstr ""
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr ""
@@ -46260,6 +46886,9 @@ msgstr ""
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr ""
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr ""
+
msgid "Your action succeeded."
msgstr ""
@@ -46376,16 +47005,13 @@ msgstr ""
msgid "Your name"
msgstr "您的åå­—"
-msgid "Your new %{accessTokenType}"
-msgstr ""
-
-msgid "Your new %{accessTokenType} has been created."
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
msgstr ""
-msgid "Your new %{type}"
+msgid "Your new %{accessTokenType}"
msgstr ""
-msgid "Your new access token has been created."
+msgid "Your new %{accessTokenType} has been created."
msgstr ""
msgid "Your new comment"
@@ -46473,6 +47099,9 @@ msgstr ""
msgid "Your username is %{username}."
msgstr ""
+msgid "You’re about to permanently delete the %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’. To avoid data loss, consider %{strongOpen}closing this %{issuableType}%{strongClose} instead. Once deleted, it cannot be undone or recovered."
+msgstr ""
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr ""
@@ -46542,9 +47171,6 @@ msgstr ""
msgid "`start_time` should precede `end_time`"
msgstr ""
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr ""
-
msgid "a deleted user"
msgstr ""
@@ -46555,9 +47181,6 @@ msgstr[0] ""
msgid "access:"
msgstr ""
-msgid "added"
-msgstr ""
-
msgid "added %{emails}"
msgstr ""
@@ -46616,6 +47239,12 @@ msgstr ""
msgid "assign yourself"
msgstr ""
+msgid "assigned"
+msgstr ""
+
+msgid "assigned you"
+msgstr ""
+
msgid "at"
msgstr ""
@@ -46625,9 +47254,6 @@ msgstr ""
msgid "at least the Reporter role, the author, and assignees"
msgstr ""
-msgid "at risk"
-msgstr ""
-
msgid "attach a new file"
msgstr ""
@@ -46707,6 +47333,12 @@ msgstr ""
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
msgstr ""
+msgid "cannot be associated with a subgroup"
+msgstr ""
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr ""
+
msgid "cannot be changed"
msgstr ""
@@ -46936,12 +47568,27 @@ msgstr ""
msgid "ciReport|Dependency scanning"
msgstr ""
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr ""
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr ""
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr ""
+
msgid "ciReport|Download patch to resolve"
msgstr ""
msgid "ciReport|Download the patch to apply it manually"
msgstr ""
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr ""
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr ""
@@ -47015,6 +47662,9 @@ msgstr ""
msgid "ciReport|New"
msgstr ""
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr ""
+
msgid "ciReport|No changes to Code Quality."
msgstr ""
@@ -47045,6 +47695,9 @@ msgstr ""
msgid "ciReport|Security reports failed loading results"
msgstr ""
+msgid "ciReport|Security scan results"
+msgstr ""
+
msgid "ciReport|Security scanning"
msgstr ""
@@ -47060,6 +47713,9 @@ msgstr ""
msgid "ciReport|Solution"
msgstr ""
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr ""
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr ""
@@ -47133,6 +47789,9 @@ msgstr ""
msgid "committed"
msgstr ""
+msgid "complete"
+msgstr ""
+
msgid "compliance violation has already been recorded"
msgstr ""
@@ -47191,6 +47850,9 @@ msgstr[0] "天"
msgid "days"
msgstr ""
+msgid "default"
+msgstr ""
+
msgid "default branch"
msgstr ""
@@ -47344,6 +48006,9 @@ msgid "from %d job"
msgid_plural "from %d jobs"
msgstr[0] ""
+msgid "from yourself"
+msgstr ""
+
msgid "frontmatter"
msgstr ""
@@ -47442,12 +48107,18 @@ msgstr ""
msgid "invalid milestone state `%{state}`"
msgstr ""
+msgid "invalidated"
+msgstr ""
+
msgid "is"
msgstr ""
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr ""
+msgid "is already linked to this vulnerability"
+msgstr ""
+
msgid "is an invalid IP address range"
msgstr ""
@@ -47469,6 +48140,9 @@ msgstr ""
msgid "is not a descendant of the Group owning the template"
msgstr ""
+msgid "is not a valid URL."
+msgstr ""
+
msgid "is not a valid X509 certificate."
msgstr ""
@@ -47493,12 +48167,18 @@ msgstr ""
msgid "is not in the member group"
msgstr ""
+msgid "is not one of"
+msgstr ""
+
msgid "is not the member project"
msgstr ""
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr ""
+msgid "is one of"
+msgstr ""
+
msgid "is read-only"
msgstr ""
@@ -47652,9 +48332,6 @@ msgstr ""
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr ""
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr ""
-
msgid "mrWidget|%{mergeError}."
msgstr ""
@@ -47801,6 +48478,9 @@ 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 ""
@@ -47897,9 +48577,6 @@ msgstr ""
msgid "mrWidget|Revoke approval"
msgstr ""
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr ""
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr ""
@@ -47963,6 +48640,9 @@ msgstr ""
msgid "must be an email you have verified"
msgstr ""
+msgid "must be associated with a Group or a Project"
+msgstr ""
+
msgid "must be greater than start date"
msgstr ""
@@ -47975,9 +48655,15 @@ msgstr ""
msgid "must be set for a project namespace"
msgstr ""
+msgid "must be top-level namespace"
+msgstr ""
+
msgid "must be unique by status and elapsed time within a policy"
msgstr ""
+msgid "must belong to same project of the work item."
+msgstr ""
+
msgid "must have a repository"
msgstr ""
@@ -47996,9 +48682,6 @@ msgstr ""
msgid "my-topic"
msgstr ""
-msgid "need attention"
-msgstr ""
-
msgid "needs to be between 10 minutes and 1 month"
msgstr ""
@@ -48047,9 +48730,6 @@ msgstr ""
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr ""
-msgid "on track"
-msgstr ""
-
msgid "only %{parent_types} can be parent of Task."
msgstr ""
@@ -48068,16 +48748,15 @@ msgstr ""
msgid "organizations can only be added to root groups"
msgstr ""
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] ""
-
msgid "packages"
msgstr ""
msgid "pages"
msgstr ""
+msgid "params is empty"
+msgstr ""
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "父級"
@@ -48204,9 +48883,6 @@ msgstr ""
msgid "remove weight"
msgstr "移除權é‡"
-msgid "removed"
-msgstr ""
-
msgid "removed a %{link_type} link"
msgstr ""
@@ -48226,12 +48902,19 @@ msgstr ""
msgid "repositories"
msgstr ""
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] ""
+
msgid "repository:"
msgstr ""
msgid "role's base access level does not match the access level of the membership"
msgstr ""
+msgid "running"
+msgstr ""
+
msgid "satisfied"
msgstr ""
@@ -48386,6 +49069,9 @@ msgstr ""
msgid "time summary"
msgstr ""
+msgid "to yourself"
+msgstr ""
+
msgid "today"
msgstr ""
@@ -48520,6 +49206,9 @@ msgstr ""
msgid "yaml invalid"
msgstr ""
+msgid "you"
+msgstr ""
+
msgid "your GitLab instance"
msgstr ""
diff --git a/locale/zh_TW/gitlab.po b/locale/zh_TW/gitlab.po
index 7b99907ef1a..490493fc116 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: 2022-10-10 13:59\n"
+"PO-Revision-Date: 2022-11-13 09:21\n"
msgid " %{start} to %{end}"
msgstr " %{start} 到 %{end}"
@@ -129,6 +129,10 @@ msgid "%d additional user"
msgid_plural "%d additional users"
msgstr[0] "%d ä½é¡å¤–的使用者"
+msgid "%d approval required"
+msgid_plural "%d approvals required"
+msgstr[0] "éœ€è¦ %d 個核准"
+
msgid "%d approver"
msgid_plural "%d approvers"
msgstr[0] "%d ä½æ ¸å‡†è€…"
@@ -209,18 +213,10 @@ msgid "%d epic"
msgid_plural "%d epics"
msgstr[0] "%d 個å²è©©"
-msgid "%d error"
-msgid_plural "%d errors"
-msgstr[0] "%d 個錯誤"
-
msgid "%d exporter"
msgid_plural "%d exporters"
msgstr[0] "%d 個匯出工具"
-msgid "%d failed"
-msgid_plural "%d failed"
-msgstr[0] "%d 次失敗"
-
msgid "%d failed security job"
msgid_plural "%d failed security jobs"
msgstr[0] "%d 個失敗的安全性作業"
@@ -229,10 +225,6 @@ msgid "%d file"
msgid_plural "%d files"
msgstr[0] "%d 個檔案"
-msgid "%d fixed test result"
-msgid_plural "%d fixed test results"
-msgstr[0] "%d 個確定的測試çµæžœ"
-
msgid "%d fork"
msgid_plural "%d forks"
msgstr[0] "%d 個分支"
@@ -431,6 +423,9 @@ msgid "%{bold_start}%{count}%{bold_end} opened merge request"
msgid_plural "%{bold_start}%{count}%{bold_end} opened merge requests"
msgstr[0] "%{bold_start}%{count}%{bold_end} 個已開啟的åˆä½µè«‹æ±‚"
+msgid "%{chartTitle} no data series"
+msgstr "%{chartTitle} 沒有資料系列"
+
msgid "%{code_open}Masked:%{code_close} Hidden in job logs. Must match masking requirements."
msgstr "%{code_open}éš±è—:%{code_close} éš±è—於作業日誌之中。必須符åˆéš±è—è¦å®šã€‚"
@@ -482,6 +477,14 @@ msgstr[0] "%{count} è¯çµ¡äºº"
msgid "%{count} files touched"
msgstr "å·²é¸æ“‡ %{count} 個檔案"
+msgid "%{count} group"
+msgid_plural "%{count} groups"
+msgstr[0] "%{count} 個群組"
+
+msgid "%{count} issue"
+msgid_plural "%{count} issues"
+msgstr[0] "%{count} 個議題"
+
msgid "%{count} item"
msgid_plural "%{count} items"
msgstr[0] "%{count} 個項目"
@@ -489,6 +492,10 @@ msgstr[0] "%{count} 個項目"
msgid "%{count} items per page"
msgstr "æ¯é %{count} 個項目"
+msgid "%{count} merge request"
+msgid_plural "%{count} merge requests"
+msgstr[0] "%{count} 個åˆä½µè«‹æ±‚"
+
msgid "%{count} more"
msgstr "其餘 %{count} 項"
@@ -509,6 +516,10 @@ msgid "%{count} participant"
msgid_plural "%{count} participants"
msgstr[0] "%{count} ä½åƒèˆ‡è€…"
+msgid "%{count} project"
+msgid_plural "%{count} projects"
+msgstr[0] "%{count} 個專案"
+
msgid "%{count} related %{pluralized_subject}: %{links}"
msgstr "%{count} 個相關的 %{pluralized_subject}:%{links}"
@@ -548,9 +559,6 @@ msgstr "%{docs_link_start}甚麼是大型檔案儲存空間?%{docs_link_end}"
msgid "%{docs_link_start}What is two-factor authentication?%{docs_link_end}"
msgstr "%{docs_link_start}什麼是兩步驟驗證?%{docs_link_end}"
-msgid "%{due_date} (Past due)"
-msgstr "%{due_date} (å·²éŽæœŸ)"
-
msgid "%{duration}ms"
msgstr "%{duration} 毫秒"
@@ -761,12 +769,6 @@ msgstr "%{name_with_link} 命å空間已用盡共用執行器æµæ°´ç·šé¡åº¦ã€‚
msgid "%{name} (Busy)"
msgstr "%{name} (忙碌)"
-msgid "%{name} contained %{resultsString}"
-msgstr "%{name} åŒ…å« %{resultsString}"
-
-msgid "%{name} found %{resultsString}"
-msgstr "%{name} 找到了 %{resultsString}"
-
msgid "%{name} is already being used for another emoji"
msgstr "%{name} 已用於å¦ä¸€å€‹è¡¨æƒ…符號"
@@ -945,6 +947,9 @@ msgstr[0] "%{strongStart}%{count}%{strongEnd} 次æ交"
msgid "%{strongStart}Tip:%{strongEnd} You can also check out merge requests locally. %{linkStart}Learn more.%{linkEnd}"
msgstr "%{strongStart}æ示:%{strongEnd} 您也å¯ä»¥åœ¨æœ¬åœ°ç«¯æŸ¥çœ‹åˆä½µè«‹æ±‚。%{linkStart}了解更多%{linkEnd}"
+msgid "%{strong_open}%{group_name}%{strong_close} projects:"
+msgstr "%{strong_open}%{group_name}%{strong_close} 專案:"
+
msgid "%{strong_start}%{branch_count}%{strong_end} Branch"
msgid_plural "%{strong_start}%{branch_count}%{strong_end} Branches"
msgstr[0] "%{strong_start}%{branch_count}%{strong_end} 個分支"
@@ -1032,7 +1037,7 @@ msgid "%{total} warnings found: showing first %{warningsDisplayed}"
msgstr "ç™¼ç¾ %{total} 個警告訊æ¯ï¼šæ­£åœ¨é¡¯ç¤ºé–‹é ­çš„ %{warningsDisplayed} 個警告訊æ¯"
msgid "%{type} must be a %{help_link}"
-msgstr ""
+msgstr "%{type} 必須為 %{help_link}"
msgid "%{type} only supports %{name} name"
msgstr "%{type} åªæ”¯æŒ %{name} åå­—"
@@ -1079,9 +1084,6 @@ msgstr "%{user} 建立了一個議題: %{issue_link}"
msgid "%{value} is not included in the list"
msgstr "%{value} 未包å«åœ¨åˆ—表中"
-msgid "%{value} s"
-msgstr "%{value} 秒"
-
msgid "%{verb} %{time_spent_value} spent time."
msgstr "%{verb} 耗時 %{time_spent_value}"
@@ -1139,6 +1141,9 @@ msgstr "「%{source}ã€ä¸æ˜¯ä¸€å€‹åŒ¯å…¥ä¾†æº"
msgid "'%{template_name}' is unknown or invalid"
msgstr "「%{template_name}ã€æœªçŸ¥æˆ–無效"
+msgid "'%{value}' days of inactivity must be greater than or equal to 90"
+msgstr "「%{value}ã€å¤©çš„éžæ´»èºå¤©æ•¸å¿…須大於或等於 90"
+
msgid "(%d closed)"
msgid_plural "(%d closed)"
msgstr[0] "(%d 個已關閉)"
@@ -1176,6 +1181,9 @@ msgstr "(如果您ä¸æƒ³æ›´æ”¹ï¼Œè«‹ç•™ç©ºï¼‰"
msgid "(max size 15 MB)"
msgstr "(最大15 MB)"
+msgid "(no user)"
+msgstr "(無使用者)"
+
msgid "(optional)"
msgstr "(é¸é …)"
@@ -1434,6 +1442,9 @@ msgstr "您沒有權é™å­˜å–æ­¤é é¢ã€‚"
msgid "404|Make sure the address is correct and the page hasn't moved."
msgstr "請確ä¿ç¶²å€æ­£ç¢ºä¸”網é æ²’被移動。"
+msgid "404|Not found"
+msgstr "é é¢ä¸å­˜åœ¨"
+
msgid "404|Page Not Found"
msgstr "找ä¸åˆ°ç¶²é "
@@ -1497,9 +1508,6 @@ msgstr "機密性議題ä¸èƒ½æœ‰ä¸€å€‹å·²æœ‰éžæ©Ÿå¯†å­é …的父級。"
msgid "A confidential work item cannot have a parent that already has non-confidential children."
msgstr "機密性工作項ä¸èƒ½æœ‰ä¸€å€‹å·²æœ‰éžæ©Ÿå¯†å­é …的父級。"
-msgid "A default branch cannot be chosen for an empty project."
-msgstr "無法設定空專案的é è¨­åˆ†æ”¯ã€‚"
-
msgid "A deleted user"
msgstr "已刪除的使用者"
@@ -1578,9 +1586,6 @@ msgstr "一個å為 %{token_name} 的個人存å–權æ–已被撤銷。"
msgid "A plain HTML site that uses Netlify for CI/CD instead of GitLab, but still with all the other great GitLab features"
msgstr "ç´” HTML 網站使用 NetLify æ¥å–代 Gitlab çš„ CI/CD,但ä»ä¿±å‚™å®Œæ•´çš„ GitLab 其他優秀功能"
-msgid "A platform value can be web, mob or app."
-msgstr "å¹³å°å¯ä»¥æ˜¯ webã€mob 或 app."
-
msgid "A project boilerplate for Salesforce App development with Salesforce Developer tools"
msgstr "使用 Salesforce Developer 工具開發 Salesforce App 的專案樣æ¿"
@@ -1788,6 +1793,9 @@ msgstr "接å—æœå‹™æ¢æ¬¾"
msgid "Acceptable for use in this project"
msgstr "å¯æŽ¥å—於專案中使用"
+msgid "Access Denied"
+msgstr "拒絕存å–"
+
msgid "Access Git repositories or the API."
msgstr "å­˜å– Git 版本庫或 API。"
@@ -1899,15 +1907,9 @@ msgstr "您的傳入電å­éƒµä»¶ä»¤ç‰Œ(權æ–)在您通éŽé›»å­éƒµä»¶å‰µå»ºæ–°å
msgid "AccessTokens|Your static object token authenticates you when repository static objects (such as archives or blobs) are served from an external storage."
msgstr "當儲存庫éœæ…‹å°è±¡ï¼ˆä¾‹å¦‚檔案或 blob)從外部儲存æ供時,您的éœæ…‹å°è±¡æ¬Šæ–會å°æ‚¨é€²è¡Œèº«ä»½é©—證。"
-msgid "AccessibilityReport|Learn more"
-msgstr "了解更多"
-
msgid "AccessibilityReport|Message: %{message}"
msgstr "消æ¯ï¼š %{message}"
-msgid "AccessibilityReport|New"
-msgstr "最新"
-
msgid "AccessibilityReport|The accessibility scanning found an error of the following type: %{code}"
msgstr "輔助功能掃æ發ç¾ä»¥ä¸‹é¡žåž‹çš„錯誤: %{code}"
@@ -1977,9 +1979,6 @@ msgstr "使用中"
msgid "Active %{accessTokenTypePlural} (%{totalAccessTokens})"
msgstr "使用中 %{accessTokenTypePlural} (%{totalAccessTokens})"
-msgid "Active %{type} (%{token_length})"
-msgstr "使用中 %{type}(%{token_length})"
-
msgid "Active Sessions"
msgstr "使用中的工作階段"
@@ -2185,7 +2184,7 @@ msgid "Add labels"
msgstr "加入標記"
msgid "Add license"
-msgstr "加入授權憑證"
+msgstr "加入授權許å¯"
msgid "Add list"
msgstr "加入列表"
@@ -2352,6 +2351,12 @@ msgstr "加入 %{labels}%{label_text}。"
msgid "Adds a Zoom meeting."
msgstr "加入 Zoom 會議."
+msgid "Adds a resource link"
+msgstr "加入一個資æºéˆçµ"
+
+msgid "Adds a resource link for this incident."
+msgstr "為該事件加入一個資æºéˆçµã€‚"
+
msgid "Adds a timeline event to incident."
msgstr "增加一個時間線事件到事故."
@@ -2479,7 +2484,7 @@ msgid "AdminArea|No applications found"
msgstr "未找到應用程å¼"
msgid "AdminArea|Owner"
-msgstr "所有者"
+msgstr "æ“有者"
msgid "AdminArea|Projects"
msgstr "專案"
@@ -2535,6 +2540,24 @@ msgstr "您打算åœæ­¢æ‰€æœ‰ä»»å‹™ã€‚這將會åœæ­¢æ‰€æœ‰æ­£åœ¨åŸ·è¡Œä¸­çš„ä»»
msgid "AdminDashboard|Error loading the statistics. Please try again"
msgstr "載入統計資料時發生錯誤。請å†è©¦ä¸€æ¬¡"
+msgid "AdminEmail|Body"
+msgstr "郵件正文"
+
+msgid "AdminEmail|Body is required."
+msgstr "郵件正文為必è¦ã€‚"
+
+msgid "AdminEmail|Recipient group or project"
+msgstr "收件人群組或專案"
+
+msgid "AdminEmail|Recipient group or project is required."
+msgstr "收件人群組或專案為必è¦ã€‚"
+
+msgid "AdminEmail|Subject"
+msgstr "郵件標題"
+
+msgid "AdminEmail|Subject is required."
+msgstr "郵件標題為必è¦ã€‚"
+
msgid "AdminLabels|Define your default set of project labels"
msgstr "定義您專案標籤的é è¨­è¨­å®š"
@@ -2571,15 +2594,27 @@ msgstr "Auto DevOps 網域"
msgid "AdminSettings|CI/CD limits"
msgstr "CI/CD é™åˆ¶"
+msgid "AdminSettings|Clickhouse URL"
+msgstr "Clickhouse 網å€"
+
msgid "AdminSettings|Configure Let's Encrypt"
msgstr "é…ç½® Let's Encrypt"
msgid "AdminSettings|Configure limits on the number of repositories users can download in a given time."
msgstr "設定使用者在給定時間內å¯ä»¥ä¸‹è¼‰çš„版本庫數é‡é™åˆ¶ã€‚"
+msgid "AdminSettings|Configure product analytics to track events within your project applications."
+msgstr "設定產å“分æžä»¥è¿½è¸ªæ‚¨å°ˆæ¡ˆæ‡‰ç”¨ç¨‹å¼å…§çš„事件。"
+
msgid "AdminSettings|Configure when inactive projects should be automatically deleted. %{linkStart}What are inactive projects?%{linkEnd}"
msgstr "設定何時應自動刪除ä¸æ´»èºçš„專案。 %{linkStart}什麼是ä¸æ´»èºå°ˆæ¡ˆï¼Ÿ%{linkEnd}"
+msgid "AdminSettings|Cube API URL"
+msgstr "Cube API 網å€"
+
+msgid "AdminSettings|Cube API key"
+msgstr "Cube API 金鑰"
+
msgid "AdminSettings|Delete inactive projects"
msgstr "刪除ä¸æ´»èºå°ˆæ¡ˆ"
@@ -2628,6 +2663,9 @@ msgstr "啟用 kuromoji 自訂分æžå™¨: 查詢"
msgid "AdminSettings|Enable pipeline suggestion banner"
msgstr "啟用æµæ°´ç·šå»ºè­°æ©«å¹…"
+msgid "AdminSettings|Enable product analytics"
+msgstr "啟用產å“分æž"
+
msgid "AdminSettings|Enable shared runners for new projects"
msgstr "啟用新專案的共享執行器"
@@ -2673,6 +2711,18 @@ msgstr "ä¸æ´»èºå°ˆæ¡ˆç§»é™¤"
msgid "AdminSettings|Instance runners expiration"
msgstr "æœå‹™å¯¦é«”執行器éŽæœŸ"
+msgid "AdminSettings|Jitsu administrator email"
+msgstr "Jitsu 管ç†è€…é›»å­éƒµä»¶"
+
+msgid "AdminSettings|Jitsu administrator password"
+msgstr "Jitsu 管ç†è€…密碼"
+
+msgid "AdminSettings|Jitsu host"
+msgstr "Jitsu 主機"
+
+msgid "AdminSettings|Jitsu project ID"
+msgstr "Jitsu 專案 ID"
+
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr "ä¿ç•™æœ€æ–°ä¸”æˆåŠŸçš„æµæ°´ç·šä¸­æ‰€æœ‰ä»»å‹™çš„最新產物"
@@ -2811,9 +2861,18 @@ msgstr "設定值必須大於 0。"
msgid "AdminSettings|Size and domain settings for Pages static sites."
msgstr "é é¢éœæ…‹ç¶²ç«™çš„容é‡åŠç¶²åŸŸè¨­å®šã€‚"
+msgid "AdminSettings|The ID of the project in Jitsu. The project contains all analytics instances."
+msgstr "Jitsu 中專案的 ID,該專案包å«æ‰€æœ‰åˆ†æžå¯¦ä¾‹ã€‚"
+
+msgid "AdminSettings|The URL of your Cube instance."
+msgstr "您 Cube 實例的網å€ã€‚"
+
msgid "AdminSettings|The default domain to use for Auto Review Apps and Auto Deploy stages in all projects."
msgstr "用於所有專案的自動審閱應用程å¼å’Œè‡ªå‹•éƒ¨ç½²éšŽæ®µçš„é è¨­ç¶²åŸŸã€‚"
+msgid "AdminSettings|The host of your Jitsu instance."
+msgstr "您 Jitsu 實例的主機。"
+
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr "æ¯å€‹å°ˆæ¡ˆæœ€æ–°æˆåŠŸçš„æµæ°´ç·šï¼Œå…¶æ‰€æœ‰ä»»å‹™çš„最新產物已被儲存,並且ä¸æœƒéŽæœŸã€‚"
@@ -2838,6 +2897,15 @@ msgstr "ç›®å‰æ´»å‹•ä¸­çš„æµæ°´ç®¡ç·šä½œæ¥­ç¸½æ•¸"
msgid "AdminSettings|Use AWS OpenSearch Service with IAM credentials"
msgstr "使用帶有 IAM 憑證的 AWS OpenSearch æœå‹™"
+msgid "AdminSettings|Used to connect Jitsu to the Clickhouse instance."
+msgstr "用於將 Jitsu 連接到 Clickhouse 實例。"
+
+msgid "AdminSettings|Used to generate short-lived API access tokens."
+msgstr "用於生æˆçŸ­æœŸçš„ API å­˜å–權æ–。"
+
+msgid "AdminSettings|Used to retrieve dashboard data from the Cube instance."
+msgstr "用於從 Cube 實例中å–得儀表æ¿è³‡æ–™ã€‚"
+
msgid "AdminSettings|Users and groups must accept the invitation before they're added to a group or project."
msgstr "使用者和群組在被加入到群組或專案之å‰å¿…須接å—邀請。"
@@ -2940,6 +3008,9 @@ msgstr "系統管ç†å“¡"
msgid "AdminUsers|Admins"
msgstr "管ç†å“¡"
+msgid "AdminUsers|An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted."
+msgstr "æ“·å–此使用者的貢ç»æ™‚發生錯誤,請求無法回傳連çµè‡³æ­¤ä½¿ç”¨è€…的議題數é‡ã€åˆä½µè«‹æ±‚ã€ç¾¤çµ„與專案。若您繼續刪除使用者,他們的所有貢ç»éƒ½ä»æœƒè¢«åˆªé™¤ã€‚"
+
msgid "AdminUsers|Approve"
msgstr "批准"
@@ -3132,8 +3203,8 @@ msgstr "將生æˆé‡è¨­é€£çµä¸¦ç™¼é€çµ¦ä½¿ç”¨è€…。 使用者將被迫在首æ
msgid "AdminUsers|Restore user access to the account, including web, Git and API."
msgstr "還原使用者存å–帳號的權é™ï¼ŒåŒ…括網é ã€Git å’Œ API。"
-msgid "AdminUsers|Search by name, email or username"
-msgstr "ä¾åå­—ã€é›»å­éƒµä»¶æˆ–使用者å稱æœå°‹"
+msgid "AdminUsers|Search by name, email, or username"
+msgstr "根據姓åã€é›»å­éƒµä»¶æˆ–使用者å稱查尋"
msgid "AdminUsers|Search users"
msgstr "æœå°‹ä½¿ç”¨è€…"
@@ -3177,8 +3248,8 @@ msgstr "此使用者將ä¸æœƒæ”¶åˆ°ä»»ä½•é€šçŸ¥"
msgid "AdminUsers|To confirm, type %{projectName}"
msgstr "請輸入 %{projectName} 來確èª"
-msgid "AdminUsers|To confirm, type %{username}"
-msgstr "請輸入 %{username} 來確èª"
+msgid "AdminUsers|To confirm, type %{username}."
+msgstr "輸入 %{username} 以確èªã€‚"
msgid "AdminUsers|Unban user"
msgstr "å–消å°éŽ–"
@@ -3240,8 +3311,8 @@ msgstr "沒有專案"
msgid "AdminUsers|You are about to permanently delete the user %{username}. Issues, merge requests, and groups linked to them will be transferred to a system-wide \"Ghost-user\". To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
msgstr "您å³å°‡æ°¸ä¹…刪除使用者 %{username}。與他相關的議題ã€åˆä½µè«‹æ±‚åŠç¾¤çµ„將被轉移到系統下的「幽éˆä½¿ç”¨è€…ã€ã€‚為é¿å…資料éºå¤±ï¼Œè«‹è€ƒæ…®æ”¹ç”¨%{strongStart}å°éŽ–使用者%{strongEnd}功能。一旦您%{strongStart}刪除使用者%{strongEnd},就無法撤銷或æ¢å¾©ã€‚"
-msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all of the issues, merge requests, and groups linked to them. To avoid data loss, consider using the %{strongStart}block user%{strongEnd} feature instead. Once you %{strongStart}Delete user%{strongEnd}, it cannot be undone or recovered."
-msgstr "您å³å°‡æ°¸ä¹…刪除使用者 %{username}。這會刪除與他相關的所有議題ã€åˆä½µè«‹æ±‚åŠç¾¤çµ„。為é¿å…資料éºå¤±ï¼Œè«‹è€ƒæ…®æ”¹ç”¨%{strongStart}å°éŽ–使用者%{strongEnd}功能。一旦您%{strongStart}刪除使用者%{strongEnd},就無法撤銷或æ¢å¾©ã€‚"
+msgid "AdminUsers|You are about to permanently delete the user %{username}. This will delete all issues, merge requests, groups, and projects linked to them. To avoid data loss, consider using the %{strongStart}Block user%{strongEnd} feature instead. After you %{strongStart}Delete user%{strongEnd}, you cannot undo this action or recover the data."
+msgstr "您å³å°‡æ°¸ä¹…刪除使用者 %{username}。這將會刪除所有連çµè‡³ä»–們的議題ã€åˆä½µè«‹æ±‚ã€ç¾¤çµ„與專案。è¦é¿å…資料éºå¤±ï¼Œè«‹è€ƒæ…®ä½¿ç”¨%{strongStart}å°éŽ–使用者%{strongEnd}功能來代替。在您%{strongStart}刪除使用者%{strongEnd}之後,您就無法撤銷此動作或還原資料。"
msgid "AdminUsers|You can always block their account again if needed."
msgstr "如有需è¦ï¼Œä½ å¯ä»¥éš¨æ™‚å†æ¬¡å°éŽ–他們的帳號。"
@@ -3288,6 +3359,9 @@ msgstr "管ç†ç•Œé¢"
msgid "Administrators"
msgstr "系統管ç†å“¡"
+msgid "Administrators are not permitted to connect applications with these scopes: %{code_open}api%{code_close}, %{code_open}read_api%{code_close}, %{code_open}read_repository%{code_close}, %{code_open}write_repository%{code_close}, %{code_open}write_registry%{code_close}, %{code_open}read_registry%{code_close}, and %{code_open}sudo%{code_close}. To permit this, change the %{code_open}disable_admin_oauth_scopes%{code_close} setting using the API."
+msgstr "ä¸å…許系統管ç†å“¡é€£çµå…·æœ‰ä»¥ä¸‹ç¯„åœçš„應用程å¼ï¼š%{code_open}api%{code_close}ã€%{code_open}read_api%{code_close}ã€%{code_open}read_repository%{code_close}ã€%{code_open}write_repository%{code_close}ã€%{code_open}write_registry%{code_close}ã€%{code_open}read_registry%{code_close} 與 %{code_open}sudo%{code_close}。è¦å…許使用,請利用 API 變更 %{code_open}disable_admin_oauth_scopes%{code_close} 的設定。"
+
msgid "Admin|Additional users must be reviewed and approved by a system administrator. Learn more about %{help_link_start}usage caps%{help_link_end}."
msgstr "其他使用者必須經éŽç³»çµ±ç®¡ç†å“¡çš„審核和批准。詳細了解 %{help_link_start}使用上é™%{help_link_end}。"
@@ -3331,19 +3405,19 @@ msgid "AdvancedSearch|Elasticsearch version not compatible"
msgstr "Elasticsearch 版本ä¸ç›¸å®¹"
msgid "AdvancedSearch|Introduced in GitLab 13.1, before using %{reindexing_link_start}zero-downtime reindexing%{link_end} and %{migrations_link_start}Advanced Search migrations%{link_end}, you need to %{recreate_link_start}recreate your index%{link_end}."
-msgstr ""
+msgstr "在 GitLab 13.1 中引入,在使用 %{reindexing_link_start}zero-downtime reindexing%{link_end} å’Œ %{migrations_link_start}進階查詢é·ç§»%{link_end}之å‰ï¼Œæ‚¨éœ€è¦ %{recreate_link_start}é‡æ–°å»ºç«‹æ‚¨çš„索引%{link_end}。"
msgid "AdvancedSearch|Pause indexing and upgrade Elasticsearch to a supported version."
-msgstr ""
+msgstr "æš«åœç´¢å¼•ä¸¦å°‡ Elasticsearch å‡ç´šåˆ°å—支æ´çš„版本。"
msgid "AdvancedSearch|Reindex recommended"
-msgstr ""
+msgstr "建議é‡å»ºç´¢å¼•"
msgid "AdvancedSearch|Reindex required"
msgstr "需è¦é‡æ–°å»ºç«‹ç´¢å¼•"
msgid "AdvancedSearch|You are using outdated code search mappings. To improve code search quality, we recommend you use %{reindexing_link_start}zero-downtime reindexing%{link_end} or %{recreate_link_start}re-create your index%{link_end}."
-msgstr ""
+msgstr "您正在使用éŽæœŸçš„代碼查詢映射。為了æ高代碼查詢質é‡ï¼Œæˆ‘們建議您使用 %{reindexing_link_start}zero-downtime reindexing%{link_end} 或 %{recreate_link_start}é‡æ–°å»ºç«‹ç´¢å¼•%{link_end}。"
msgid "After a successful password update you will be redirected to login screen."
msgstr "密碼更新æˆåŠŸå¾Œï¼Œæ‚¨å°‡è¢«é‡æ–°å°Žå‘至登入é é¢ã€‚"
@@ -3403,7 +3477,7 @@ msgid "AlertManagement|Alerts"
msgstr "警報"
msgid "AlertManagement|All alerts"
-msgstr "所有警報"
+msgstr "全部警報"
msgid "AlertManagement|Assign status"
msgstr "分é…狀態"
@@ -3730,13 +3804,13 @@ msgid "All (default)"
msgstr "全部 (é è¨­)"
msgid "All GitLab"
-msgstr "所有 GitLab"
+msgstr "全部 GitLab"
msgid "All Members"
-msgstr "所有æˆå“¡"
+msgstr "全部æˆå“¡"
msgid "All branches"
-msgstr "所有分支"
+msgstr "全部分支"
msgid "All changes are committed"
msgstr "所有變更å‡å·²æ交"
@@ -3748,13 +3822,13 @@ msgid "All email addresses will be used to identify your commits."
msgstr "所有電å­éƒµä»¶åœ°å€éƒ½å¯ç”¨æ–¼è­˜åˆ¥æ‚¨çš„æ交。"
msgid "All environments"
-msgstr "所有環境"
+msgstr "全部環境"
msgid "All groups and projects"
-msgstr "所有群組和專案"
+msgstr "全部群組和專案"
msgid "All issues"
-msgstr "所有議題"
+msgstr "全部議題"
msgid "All issues for this milestone are closed."
msgstr "此里程碑的所有議題å‡å·²é—œé–‰ã€‚"
@@ -3775,7 +3849,7 @@ msgid "All project members"
msgstr "專案的所有æˆå“¡"
msgid "All projects"
-msgstr "所有專案"
+msgstr "全部專案"
msgid "All projects selected"
msgstr "所有已é¸å–的專案"
@@ -3798,8 +3872,8 @@ msgstr "所有的使用者都必須具有å稱。"
msgid "All users with matching cards"
msgstr "所有æ“有匹é…å¡çš„使用者"
-msgid "Allow \"%{group_name}\" to sign you in"
-msgstr "å…許「%{group_name}ã€ä»¥æ‚¨çš„身份登入"
+msgid "Allow %{strongOpen}%{group_name}%{strongClose} to sign you in?"
+msgstr "å…許 %{strongOpen}%{group_name}%{strongClose} 登入嗎?"
msgid "Allow access to members of the following group"
msgstr "å…許以下群組的æˆå“¡å­˜å–"
@@ -3813,6 +3887,9 @@ msgstr "å…許具有åˆä½µåˆ°ç›®æ¨™åˆ†æ”¯æ¬Šé™çš„æˆå“¡æ交,%{link_start}é—
msgid "Allow group owners to manage LDAP-related settings"
msgstr "å…è¨±ç¾¤çµ„æ‰€æœ‰è€…ç®¡ç† LDAP 相關的設定"
+msgid "Allow new users to create top-level groups"
+msgstr "å…許新使用者建立最上層群組"
+
msgid "Allow non-administrators access to the performance bar"
msgstr "å…許éžç®¡ç†å“¡å­˜å–效能資訊欄"
@@ -3849,9 +3926,6 @@ msgstr "å…許此金鑰推é€åˆ°æ­¤ç‰ˆæœ¬åº«"
msgid "Allow use of licensed EE features"
msgstr "å…許使用許å¯çš„ EE 功能"
-msgid "Allow users to create top-level groups"
-msgstr "å…許使用者創建最高階群組"
-
msgid "Allow users to dismiss the broadcast message"
msgstr "å…許使用者忽略廣播訊æ¯"
@@ -4098,6 +4172,9 @@ msgstr "在載入標籤時發生錯誤,請é‡è©¦"
msgid "An error occurred while fetching terraform reports."
msgstr "ç²å–é …ç›®(terraform)報告時發生錯誤。"
+msgid "An error occurred while fetching the health status."
+msgstr "讀å–é‹è¡Œç‹€æ…‹æ™‚發生錯誤。"
+
msgid "An error occurred while fetching the job log."
msgstr "抓å–作業日誌時發生錯誤。"
@@ -4282,9 +4359,6 @@ msgstr "觸發作業時發生錯誤。"
msgid "An error occurred while trying to follow this user, please try again."
msgstr "嘗試跟隨此使用者時發生錯誤,請é‡è©¦ã€‚"
-msgid "An error occurred while trying to generate the report. Please try again later."
-msgstr "試圖製作報告時發生錯誤,請ç¨å¾Œé‡è©¦ã€‚"
-
msgid "An error occurred while trying to render the content editor. Please try again."
msgstr "嘗試顯示內容編輯器時發生錯誤,請ç¨å€™å†è©¦ã€‚"
@@ -4384,9 +4458,6 @@ msgstr "發生未知的錯誤"
msgid "Analytics"
msgstr "分æž"
-msgid "AnalyticsDashboards|Dashboards"
-msgstr ""
-
msgid "Analyze your dependencies for known vulnerabilities."
msgstr "分æžå·²çŸ¥æ¼æ´žçš„ä¾è³´é—œä¿‚"
@@ -4489,9 +4560,6 @@ msgstr "應用程å¼è¨­å®šå·²å„²å­˜æˆåŠŸã€‚"
msgid "Application settings update failed"
msgstr "應用程å¼è¨­å®šæ›´æ–°å¤±æ•—"
-msgid "Application uninstalled but failed to destroy: %{error_message}"
-msgstr "應用程å¼å·²ç§»é™¤ä½†æœªèƒ½éŠ·æ¯€: %{error_message}"
-
msgid "Application was successfully destroyed."
msgstr "應用程å¼å·²æˆåŠŸéŠ·æ¯€ã€‚"
@@ -4510,8 +4578,8 @@ msgstr "在 Grafana 加入連çµ"
msgid "ApplicationSettings|After sign-up text"
msgstr "註冊後文字"
-msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for unlimited."
-msgstr "實例é”到使用者上é™å¾Œï¼Œä»»ä½•å¢žåŠ æˆ–請求訪å•çš„使用者都必須得到管ç†å“¡çš„批准。空白表示無é™åˆ¶ã€‚"
+msgid "ApplicationSettings|After the instance reaches the user cap, any user who is added or requests access must be approved by an administrator. Leave blank for an unlimited user cap. If you change the user cap to unlimited, you must re-enable %{projectSharingLinkStart}project sharing%{projectSharingLinkEnd} and %{groupSharingLinkStart}group sharing%{groupSharingLinkEnd}."
+msgstr "一旦伺æœå™¨å¯¦ä¾‹é”到最大使用者數,任何增加或請求存å–的使用者都必須得到管ç†å“¡çš„核准,ä¿ç•™ç©ºç™½è¡¨ç¤ºå°ä½¿ç”¨è€…數é‡æ²’有é™åˆ¶ã€‚ 如果您將上é™æ›´æ”¹åˆ°ç„¡é™åˆ¶ï¼Œæ‚¨å¿…é ˆé‡æ–°å•Ÿç”¨ %{projectSharingLinkStart}專案分享%{projectSharingLinkEnd} å’Œ %{groupSharingLinkStart}群組分享%{groupSharingLinkEnd}。"
msgid "ApplicationSettings|Allowed domains for sign-ups"
msgstr "å…許註冊的網域"
@@ -4551,6 +4619,9 @@ msgstr "拒絕å單文件"
msgid "ApplicationSettings|Domain denylist"
msgstr "å°éŽ–網域清單"
+msgid "ApplicationSettings|Email confirmation settings"
+msgstr "é›»å­éƒµä»¶ç¢ºèªè¨­å®š"
+
msgid "ApplicationSettings|Email restrictions"
msgstr "é›»å­éƒµä»¶å°éŽ–清單"
@@ -4569,9 +4640,18 @@ msgstr "註冊時啟用電å­éƒµä»¶å°éŽ–清單"
msgid "ApplicationSettings|Enter denylist manually"
msgstr "手動輸入拒絕清單"
+msgid "ApplicationSettings|Hard"
+msgstr "硬設置"
+
msgid "ApplicationSettings|Minimum password length (number of characters)"
msgstr "最å°å¯†ç¢¼é•·åº¦ï¼ˆæ–‡å­—ã€æ•¸å­—ã€ç¬¦è™Ÿï¼‰"
+msgid "ApplicationSettings|New users can sign up without confirming their email address."
+msgstr "新使用者無需確èªå…¶é›»å­éƒµä»¶åœ°å€å³å¯è¨»å†Šã€‚"
+
+msgid "ApplicationSettings|Off"
+msgstr "å·²ç¦ç”¨"
+
msgid "ApplicationSettings|Only users with e-mail addresses that match these domain(s) can sign up. Wildcards allowed. Use separate lines for multiple entries. Example: domain.com, *.domain.com"
msgstr "åªæœ‰é›»å­éƒµä»¶åœ°å€ç¬¦åˆé€™äº›ç¶²åŸŸè¨­ç½®çš„使用者æ‰èƒ½è¨»å†Šã€‚ å…許使用通用é…置符號,å°å¤šå€‹é…置使用分行。 例如:domain.com, *.domain.com"
@@ -4599,6 +4679,9 @@ msgstr "ä¿å­˜æ›´æ”¹"
msgid "ApplicationSettings|See %{linkStart}password policy guidelines%{linkEnd}."
msgstr "è«‹åƒé–±%{linkStart}密碼政策指å—%{linkEnd}。"
+msgid "ApplicationSettings|Send a confirmation email during sign up. New users must confirm their email address before they can log in."
+msgstr "在註冊期間寄é€é›»å­éƒµä»¶ç¢ºèªä¿¡ï¼Œæ–°ä½¿ç”¨è€…必須先確èªä»–們的電å­éƒµä»¶åœ°å€ï¼Œç„¶å¾Œæ‰èƒ½ç™»å…¥ã€‚"
+
msgid "ApplicationSettings|Send confirmation email on sign-up"
msgstr "註冊時發é€ç¢ºèªé›»å­éƒµä»¶"
@@ -4934,9 +5017,6 @@ msgstr "您確定è¦é—œé–‰é€™å€‹è¢«å°é˜»çš„å•é¡Œå—Žï¼Ÿ"
msgid "Are you sure you want to delete %{name}?"
msgstr "您確定è¦åˆªé™¤ %{name}嗎?"
-msgid "Are you sure you want to delete these artifacts?"
-msgstr "確定è¦åˆªé™¤é€™äº›ç”¢ç‰©å—Žï¼Ÿ"
-
msgid "Are you sure you want to delete this %{commentType}?"
msgstr "您確定è¦åˆªé™¤æ­¤ %{commentType} 嗎?"
@@ -5037,8 +5117,8 @@ msgstr "您確定è¦é‡è©¦é€™å€‹ç§»è½‰å—Žï¼Ÿ"
msgid "Are you sure you want to revoke this %{accessTokenType}? This action cannot be undone."
msgstr "您確定è¦æ’¤æ¶ˆæ­¤ %{accessTokenType} 嗎?此æ“作無法復原。"
-msgid "Are you sure you want to revoke this %{type}? This action cannot be undone."
-msgstr "您確定è¦æ’¤éŠ·æ­¤ %{type}嗎?此動作無法復原。"
+msgid "Are you sure you want to revoke this group access token? This action cannot be undone."
+msgstr "您確定è¦æ’¤å›žæ­¤ç¾¤çµ„å­˜å–權æ–嗎?此動作無法復原。"
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr "您確定è¦æ’¤å›žæ­¤å€‹äººå­˜å–憑證 (access token)嗎?此動作無法復原。"
@@ -5088,6 +5168,30 @@ msgstr "產物已æˆåŠŸåˆªé™¤ã€‚"
msgid "Artifacts"
msgstr "æˆå“"
+msgid "Artifacts|An error occurred while deleting the artifact"
+msgstr "刪除產物時發生錯誤"
+
+msgid "Artifacts|An error occurred while retrieving job artifacts"
+msgstr "å–得作業產物時發生錯誤"
+
+msgid "Artifacts|Artifacts"
+msgstr "產物"
+
+msgid "Artifacts|Browse"
+msgstr "ç€è¦½"
+
+msgid "Artifacts|Delete %{name}?"
+msgstr "刪除 %{name} 嗎?"
+
+msgid "Artifacts|Delete artifact"
+msgstr "刪除產物"
+
+msgid "Artifacts|This artifact will be permanently deleted. Any reports generated from this artifact will be empty."
+msgstr "該產物將被永久刪除,任何從該產物所生æˆçš„報告都會被清空。"
+
+msgid "Artifacts|Total artifacts size"
+msgstr "總產物大å°"
+
msgid "As we continue to build more features for SAST, we'd love your feedback on the SAST configuration feature in %{linkStart}this issue%{linkEnd}."
msgstr "隨著我們繼續為 SAST å»ºç«‹æ›´å¤šåŠŸèƒ½ï¼Œæˆ‘å€‘å¸Œæœ›æ‚¨å° %{linkStart} 本期 %{linkEnd} 中的 SAST é…置功能æä¾›å饋。"
@@ -5139,9 +5243,6 @@ msgstr "分é…自訂é¡è‰²ï¼Œå¦‚FF0000"
msgid "Assign labels"
msgstr "指派標記 (label)"
-msgid "Assign milestone"
-msgstr "分é…里程碑"
-
msgid "Assign myself"
msgstr "指派給自己"
@@ -5532,9 +5633,6 @@ msgstr "自動åœæ­¢å·²æˆåŠŸå–消。"
msgid "Auto-cancel redundant pipelines"
msgstr "自動å–消多餘的æµæ°´ç·š"
-msgid "Auto-close referenced issues on default branch"
-msgstr "自動關閉é è¨­åˆ†æ”¯çš„åƒè€ƒè­°é¡Œ"
-
msgid "AutoDevOps|%{auto_devops_start}Automate building, testing, and deploying%{auto_devops_end} your applications based on your continuous integration and delivery configuration. %{quickstart_start}How do I get started?%{quickstart_end}"
msgstr "自動 DevOps|根據您的æŒçºŒé›†æˆå’Œäº¤ä»˜é…置,%{auto_devops_start}自動建構ã€æ¸¬è©¦å’Œéƒ¨ç½²%{auto_devops_end}您的應用程å¼ã€‚%{quickstart_start}我該如何開始?%{quickstart_end}"
@@ -5898,6 +5996,12 @@ msgstr "請注æ„,變更項目的命å空間å¯èƒ½æœƒç”¢ç”Ÿéžé æœŸçš„副作
msgid "Be careful. Renaming a project's repository can have unintended side effects."
msgstr "請注æ„,é‡æ–°å‘½å項目的版本庫å¯èƒ½æœƒç”¢ç”Ÿæ„想ä¸åˆ°çš„副作用。"
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can %{link_start}unban them%{link_end}."
+msgstr "因為您啟用了自動ç¦æ­¢ï¼Œæˆ‘們也從 %{scope} 自動ç¦æ­¢è©²ä½¿ç”¨è€…。如果這是一個錯誤,您å¯ä»¥ %{link_start} 解ç¦ä»–們%{link_end}。"
+
+msgid "Because you enabled auto-banning, we have also automatically banned this user from %{scope}. If this is a mistake, you can unban them: %{url}."
+msgstr "因為您啟用了自動ç¦æ­¢ï¼Œæˆ‘們也從 %{scope} 自動ç¦æ­¢è©²ä½¿ç”¨è€…。如果這是一個錯誤,您å¯ä»¥è§£ç¦ä»–們: %{url}。"
+
msgid "Before enabling this integration, create a webhook for the room in Google Chat where you want to receive notifications from this project. %{docs_link}"
msgstr "在啟用此集æˆä¹‹å‰ï¼Œè«‹åœ¨ Google Chat 中為您希望從該項目接收通知的房間創建一個 webhook。 %{docs_link}"
@@ -6622,6 +6726,9 @@ msgstr "分支已經存在"
msgid "Branch changed"
msgstr "分支已變更"
+msgid "Branch defaults"
+msgstr "分支é è¨­"
+
msgid "Branch has been updated since the merge was requested."
msgstr "自請求åˆä½µä»¥ä¾†ï¼Œåˆ†æ”¯å·²æ›´æ–°ã€‚"
@@ -6631,6 +6738,9 @@ msgstr "分支已被採用"
msgid "Branch name"
msgstr "分支å稱"
+msgid "Branch name template"
+msgstr "分支å稱範本"
+
msgid "Branch not loaded - %{branchId}"
msgstr "分支未被載入 - %{branchId}"
@@ -6638,58 +6748,67 @@ msgid "Branch rules"
msgstr "分支è¦å‰‡"
msgid "BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or production/ are supported"
-msgstr ""
+msgstr "%{linkStart}è¬ç”¨å­—å…ƒ%{linkEnd} å¯æ”¯æ´å¦‚ *-stable 或 production/* 。"
msgid "BranchRules|%{linkStart}Wildcards%{linkEnd} such as *-stable or production/* are supported."
msgstr "%{linkStart}è¬ç”¨å­—å…ƒ%{linkEnd} å¯æ”¯æ´å½¢å¦‚ *-stable or production/* 。"
msgid "BranchRules|All branches"
-msgstr ""
+msgstr "全部分支"
msgid "BranchRules|All users with push access are allowed to force push."
-msgstr ""
+msgstr "具有推é€æ¬Šé™çš„全部使用者都å¯ä»¥å¼·åˆ¶æŽ¨é€ã€‚"
msgid "BranchRules|Allow all users with push access to %{linkStart}force push%{linkEnd}."
msgstr "å…許所有具有推é€å­˜å–權é™çš„使用者%{linkStart}強制推é€%{linkEnd}。"
+msgid "BranchRules|Allowed to force push"
+msgstr "å…許強制推é€"
+
msgid "BranchRules|Allowed to merge"
msgstr "å…許åˆä½µ"
msgid "BranchRules|Allowed to merge (%{total})"
-msgstr ""
+msgstr "å·²å…許åˆä½µ (%{total})"
msgid "BranchRules|Allowed to push"
msgstr "å…許推é€"
msgid "BranchRules|Allowed to push (%{total})"
-msgstr ""
+msgstr "å·²å…è¨±æŽ¨é€ (%{total})"
msgid "BranchRules|An error occurred while fetching branches."
msgstr "æ“·å–分支時發生錯誤。"
msgid "BranchRules|Approvals"
-msgstr ""
+msgstr "核准"
+
+msgid "BranchRules|Approvals to ensure separation of duties for new merge requests. %{linkStart}Learn more.%{linkEnd}"
+msgstr "核准以確ä¿æ–°åˆä½µè«‹æ±‚çš„è·è²¬åˆ†é›¢ï¼Œ%{linkStart}å–得更多資訊。%{linkEnd}"
msgid "BranchRules|Branch"
msgstr "分支"
msgid "BranchRules|Branch name or pattern"
-msgstr ""
+msgstr "分支å稱或樣å¼"
msgid "BranchRules|Branch rules details"
msgstr "分支è¦å‰‡è©³ç´°è³‡è¨Š"
+msgid "BranchRules|Check for a status response in merge requests. Failures do not block merges. %{linkStart}Learn more.%{linkEnd}"
+msgstr "在åˆä½µè«‹æ±‚中檢查狀態回應。失敗並ä¸æœƒé˜»æ­¢åˆä½µã€‚%{linkStart}å–得更多資訊。%{linkEnd}"
+
msgid "BranchRules|Create wildcard: %{searchTerm}"
msgstr "建立è¬ç”¨å­—元:%{searchTerm}"
msgid "BranchRules|Details"
-msgstr ""
+msgstr "詳情"
msgid "BranchRules|Force push"
-msgstr ""
+msgstr "強制推é€"
msgid "BranchRules|Force push is not allowed."
-msgstr ""
+msgstr "ä¸å…許強制推é€"
msgid "BranchRules|Groups"
msgstr "群組"
@@ -6697,17 +6816,23 @@ msgstr "群組"
msgid "BranchRules|Keep stable branches secure and force developers to use merge requests. %{linkStart}What are protected branches?%{linkEnd}"
msgstr "維æŒç©©å®šåˆ†æ”¯çš„安全並強制開發者使用åˆä½µè«‹æ±‚。%{linkStart}什麼是å—ä¿è­·çš„分支?%{linkEnd}"
+msgid "BranchRules|Manage in Merge Request Approvals"
+msgstr "在åˆä½µè«‹æ±‚核准中管ç†"
+
msgid "BranchRules|Manage in Protected Branches"
-msgstr ""
+msgstr "管ç†å—ä¿è­·åˆ†æ”¯"
+
+msgid "BranchRules|Manage in Status checks"
+msgstr "管ç†ç‹€æ…‹æª¢æŸ¥"
msgid "BranchRules|No data to display"
-msgstr ""
+msgstr "沒有è¦é¡¯ç¤ºçš„資料"
msgid "BranchRules|No matching results"
msgstr "無符åˆçš„çµæžœ"
msgid "BranchRules|Protect branch"
-msgstr ""
+msgstr "ä¿è­·åˆ†æ”¯"
msgid "BranchRules|Protections"
msgstr "ä¿è­·"
@@ -6718,11 +6843,20 @@ msgstr "拒絕程å¼ç¢¼æŽ¨é€è®Šæ›´åˆ—æ–¼ CODEOWNERS 檔案中的檔案。"
msgid "BranchRules|Require approval from code owners."
msgstr "需è¦ç¨‹å¼ç¢¼æ“有者的批准。"
+msgid "BranchRules|Required approvals (%{total})"
+msgstr "需è¦æ ¸å‡† (%{total})"
+
+msgid "BranchRules|Requires CODEOWNERS approval"
+msgstr "éœ€è¦ CODEOWNERS 核准"
+
msgid "BranchRules|Roles"
msgstr "角色"
msgid "BranchRules|Status checks"
-msgstr ""
+msgstr "狀態檢查"
+
+msgid "BranchRules|Status checks (%{total})"
+msgstr "狀態檢查 (%{total})"
msgid "BranchRules|Target Branch"
msgstr "目標分支"
@@ -6883,6 +7017,9 @@ msgstr "廣播訊æ¯å·²æˆåŠŸæ›´æ–°ã€‚"
msgid "Broadcast Messages"
msgstr "廣播訊æ¯"
+msgid "BroadcastMessages|There was an issue deleting this message, please try again later."
+msgstr "刪除該訊æ¯æ™‚出ç¾å•é¡Œï¼Œç¨å¾Œè«‹é‡è©¦ã€‚"
+
msgid "Browse Directory"
msgstr "ç€è¦½ç›®éŒ„"
@@ -6892,9 +7029,6 @@ msgstr "ç€è¦½æ–‡ä»¶"
msgid "Browse Files"
msgstr "ç€è¦½æ–‡ä»¶"
-msgid "Browse artifacts"
-msgstr "ç€è¦½ç”¢ç‰©"
-
msgid "Browse files"
msgstr "ç€è¦½æ–‡ä»¶"
@@ -6940,9 +7074,6 @@ msgstr "BulkImport|ä¾ç¾¤çµ„來æºç¯©é¸"
msgid "BulkImport|Following data will not be migrated: %{bullets} Contact system administrator of %{host} to upgrade GitLab if you need this data in your migration"
msgstr "以下資料將ä¸æœƒè¢«é·ç§»ï¼š%{bullets} 如果您在é·ç§»ä¸­éœ€è¦æ­¤è³‡æ–™ï¼Œè«‹è¯ç¹« %{host} 系統管ç†å“¡å‡ç´š GitLab"
-msgid "BulkImport|From source group"
-msgstr "BulkImport|來自於æºç¾¤çµ„"
-
msgid "BulkImport|Group import history"
msgstr "BulkImport|群組匯入歷å²"
@@ -6973,6 +7104,9 @@ msgstr "å稱已存在。"
msgid "BulkImport|Name already used as a target for another group."
msgstr "å稱已被其他群組所使用。"
+msgid "BulkImport|New group"
+msgstr "新群組"
+
msgid "BulkImport|No additional information provided."
msgstr "未æ供其它信æ¯ã€‚"
@@ -6988,6 +7122,9 @@ msgstr "沒有父級"
msgid "BulkImport|Only groups that you have the %{role} role for are listed as groups you can import."
msgstr "åªæœ‰æ‚¨æ“有 %{role} 角色的群組æ‰æœƒè¢«åˆ—為您å¯ä»¥å°Žå…¥çš„群組。"
+msgid "BulkImport|Path of the new group."
+msgstr "新群組的路徑。"
+
msgid "BulkImport|Project import history"
msgstr "專案匯入歷å²"
@@ -7012,9 +7149,6 @@ msgstr "來æºç¾¤çµ„"
msgid "BulkImport|Template / File-based import / GitLab Migration"
msgstr "模版 / 基於文件匯入 / GitLab é·ç§»"
-msgid "BulkImport|To new group"
-msgstr "到新群組"
-
msgid "BulkImport|Update of import statuses with realtime changes failed"
msgstr "更新實時變動的匯入狀態失敗"
@@ -7133,7 +7267,7 @@ msgid "CICDAnalytics|%{percent}%{percentSymbol}"
msgstr "%{percent}%{percentSymbol}"
msgid "CICDAnalytics|All time"
-msgstr "所有時間"
+msgstr "全部時間"
msgid "CICDAnalytics|Change failure rate"
msgstr "變更失敗率"
@@ -7427,9 +7561,6 @@ msgstr "å–消é è¦½"
msgid "Cannot assign a confidential epic to a non-confidential issue. Make the issue confidential and try again"
msgstr "無法將機密å²è©©åˆ†é…給éžæ©Ÿå¯†è­°é¡Œã€‚請將此議題設置機密並é‡è©¦"
-msgid "Cannot assign an issue that does not belong under the same group (or descendant) as the epic."
-msgstr "無法分é…與å²è©©ä¸å±¬æ–¼åŒä¸€ç¾¤çµ„(或後代)的議題"
-
msgid "Cannot be merged automatically"
msgstr "無法自動åˆä½µ"
@@ -7445,6 +7576,9 @@ msgstr "無法建立濫用報告。此使用者已被åœç”¨ã€‚"
msgid "Cannot delete %{profile_name} referenced in security policy"
msgstr "ä¸èƒ½åˆªé™¤å®‰å…¨ç­–略中引用的 %{profile_name}"
+msgid "Cannot delete the default framework"
+msgstr "無法刪除é è¨­æ¡†æž¶"
+
msgid "Cannot have multiple Jira imports running at the same time"
msgstr "ä¸èƒ½åŒæ™‚é‹è¡Œå¤šå€‹Jira匯入"
@@ -8182,6 +8316,9 @@ msgstr "éµ"
msgid "CiVariables|Masked"
msgstr "é®ç½©"
+msgid "CiVariables|Options"
+msgstr "é¸é …"
+
msgid "CiVariables|Protected"
msgstr "å—ä¿è­·"
@@ -9331,7 +9468,7 @@ msgid "Code Owner"
msgstr "程å¼ç¢¼æ“有者"
msgid "Code Owners"
-msgstr "程å¼ç¢¼æ‰€æœ‰è€…"
+msgstr "程å¼ç¢¼æ“有者"
msgid "Code Quality"
msgstr "程å¼ç¢¼è³ªé‡"
@@ -9495,11 +9632,17 @@ msgstr "å°%{startLine}到%{endLine}行的留言"
msgid "Comment/Reply (quoting selected text)"
msgstr "留言/回復 (引用é¸å®šçš„文字)"
-msgid "Commenting on files that replace or are replaced by symbolic links is currently not supported."
-msgstr "當å‰ä¸æ”¯æŒç•™è¨€æ›¿æ›æˆ–被符號éˆæŽ¥æ›¿æ›çš„文件。"
+msgid "Commenting on files that are only moved or renamed is not supported"
+msgstr "ä¸æ”¯æ´å°å·²ç§»å‹•æˆ–å·²é‡æ–°å‘½å的文件進行評論"
+
+msgid "Commenting on files that replace or are replaced by symbolic links is not supported"
+msgstr "ä¸æ”¯æ´æ›¿æ›æˆ–被符號éˆçµæ›¿æ›çš„文件進行評論。"
+
+msgid "Commenting on symbolic links that replace or are replaced by files is not supported"
+msgstr "ä¸æ”¯æ´æ›¿æ›æˆ–被文件替æ›çš„符號éˆçµé€²è¡Œè©•è«–。"
-msgid "Commenting on symbolic links that replace or are replaced by files is currently not supported."
-msgstr "當å‰ä¸æ”¯æŒå°æ›¿æ›æˆ–被文件替æ›çš„符號éˆæŽ¥é€²è¡Œç•™è¨€ã€‚"
+msgid "Commenting on this line is not supported"
+msgstr "ä¸æ”¯æ´å°è©²è¡Œç•™è¨€è©•è«–"
msgid "Comments"
msgstr "留言"
@@ -9679,6 +9822,9 @@ msgstr "完æˆé©—證方å¯ç™»éŒ„。"
msgid "Complete verification to sign up."
msgstr "完æˆé©—證方å¯è¨»å†Šã€‚"
+msgid "Complete with errors"
+msgstr "帶有錯誤的完æˆ"
+
msgid "Completed"
msgstr "已完æˆ"
@@ -9749,7 +9895,7 @@ msgid "ComplianceFrameworks|No compliance frameworks are set up yet"
msgstr "尚未設置åˆè¦æ¡†æž¶"
msgid "ComplianceFrameworks|Required format: %{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}. %{linkStart}What is a compliance pipeline configuration?%{linkEnd}"
-msgstr ""
+msgstr "è¦æ±‚çš„æ ¼å¼ï¼š%{codeStart}path/file.y[a]ml@group-name/project-name%{codeEnd}。 %{linkStart}什麼是åˆè¦çš„æµæ°´ç·šé…置?%{linkEnd}"
msgid "ComplianceFrameworks|Unable to save this compliance framework. Please try again"
msgstr "無法ä¿å­˜æ­¤åˆè¦æ€§æ¡†æž¶ï¼Œè«‹é‡è©¦"
@@ -10067,7 +10213,7 @@ msgid "Container Registry"
msgstr "容器映åƒåº«"
msgid "Container Repository"
-msgstr ""
+msgstr "容器映åƒåº«"
msgid "Container Scanning"
msgstr "容器掃æ"
@@ -10471,11 +10617,11 @@ msgstr "è²¢ç»"
msgid "Contribution Analytics"
msgstr "è²¢ç»åº¦åˆ†æž"
-msgid "ContributionAnalytics|%{created_count} created, %{closed_count} closed."
-msgstr "建立%{created_count}個,關閉%{closed_count}個。"
+msgid "ContributionAnalytics|%{created} created, %{closed} closed."
+msgstr "已建立 %{created} ,已關閉 %{closed} 。"
-msgid "ContributionAnalytics|%{created_count} created, %{merged_count} merged, %{closed_count} closed."
-msgstr "已建立%{created_count}個,已åˆä½µ%{merged_count}個,已關閉%{closed_count}個。"
+msgid "ContributionAnalytics|%{created} created, %{merged} merged, %{closed} closed."
+msgstr "已建立 %{created} ,已åˆä½µ %{merged} ,已關閉 %{closed} 。"
msgid "ContributionAnalytics|%{pushes}, more than %{commits} by %{contributors}."
msgstr "%{pushes}ï¼Œè¶…éŽ %{contributors} çš„ %{commits}。"
@@ -10507,6 +10653,15 @@ msgstr "é¸å–的時間範åœæ²’有åˆä½µè«‹æ±‚。"
msgid "ContributionAnalytics|No pushes for the selected time period."
msgstr "é¸å–的時間範åœæ²’有推é€ã€‚"
+msgid "ContributionAnalytics|The given date range is larger than 31 days"
+msgstr "給定的日期範åœå¤§æ–¼ 31 天"
+
+msgid "ContributionAnalytics|The to date is earlier than the given from date"
+msgstr "截止日期早於給定的起始日期"
+
+msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
+msgstr "è¦è¨ˆç®—的資料太多。請嘗試é™ä½Žåœ¨æ´žå¯Ÿå ±å‘Šè¨­å®šæª”中的 period_limit 設定。"
+
msgid "Contributions for %{calendar_date}"
msgstr "%{calendar_date}çš„è²¢ç»"
@@ -10555,9 +10710,6 @@ msgstr "複製 %{name}"
msgid "Copy %{protocol} clone URL"
msgstr "複製 %{protocol} 克隆 (Clone) URL"
-msgid "Copy %{type}"
-msgstr "複製 %{type}"
-
msgid "Copy ID"
msgstr "複製ID"
@@ -10642,9 +10794,6 @@ msgstr "複製密碼"
msgid "Copy source branch name"
msgstr "複製來æºåˆ†æ”¯å稱"
-msgid "Copy the code below to implement tracking in your application:"
-msgstr "複製以下程å¼ç¢¼ä»¥åœ¨æ‚¨çš„應用程å¼ä¸­åŸ·è¡Œè¿½è¹¤ï¼š"
-
msgid "Copy this registration token."
msgstr "複製此註冊憑證。"
@@ -10807,9 +10956,6 @@ msgstr "無法載入使用計數,請é‡æ–°è¼‰å…¥é é¢é‡è©¦ã€‚"
msgid "Could not remove %{user} from %{group}. Cannot remove last group owner."
msgstr "無法從 %{group} 中移除 %{user} ,無法移除最後一個群組的æ“有者。"
-msgid "Could not remove %{user} from %{group}. User is not a group member."
-msgstr "無法從%{group}中移除%{user},使用者ä¸æ˜¯ç¾¤çµ„æˆå“¡ã€‚"
-
msgid "Could not remove the trigger."
msgstr "無法刪除觸發器。"
@@ -11029,9 +11175,6 @@ msgstr "建立新文件或目錄"
msgid "Create new label"
msgstr "建立新標記 (label)"
-msgid "Create new project"
-msgstr "建立新專案"
-
msgid "Create new..."
msgstr "建立新…"
@@ -11299,9 +11442,6 @@ msgstr "建立å²è©©ä¸­"
msgid "Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available."
msgstr "正在使用Prometheus伺æœå™¨ä¸­çš„資料建立圖表。如果這需è¦å¾ˆé•·æ™‚間,請確ä¿è³‡æ–™å¯ç”¨ã€‚"
-msgid "Creation date"
-msgstr "建立日期"
-
msgid "Creator"
msgstr "建立者"
@@ -11317,8 +11457,8 @@ msgstr "找ä¸åˆ°æ†‘è­‰"
msgid "CredentialsInventory|Personal Access Tokens"
msgstr "個人存å–令牌(權æ–)"
-msgid "CredentialsInventory|Project Access Tokens"
-msgstr "專案存å–令牌(權æ–)"
+msgid "CredentialsInventory|Project and Group Access Tokens"
+msgstr "專案與群組存å–權æ–"
msgid "CredentialsInventory|SSH Keys"
msgstr "SSH 金鑰"
@@ -11419,9 +11559,6 @@ msgstr "ç›®å‰åˆ†æ”¯"
msgid "Current Project"
msgstr "ç›®å‰å°ˆæ¡ˆ"
-msgid "Current forks will keep their visibility level."
-msgstr "當å‰å»¶ä¼¸çš„分å‰ï¼ˆFork)將維æŒå…¶å¯è¦‹ç­‰ç´šã€‚"
-
msgid "Current node must be the primary node or you will be locking yourself out"
msgstr "當å‰ç¯€é»žå¿…須是主節點,å¦å‰‡æ‚¨å°‡æœƒéŽ–定自己。"
@@ -11747,6 +11884,9 @@ msgstr "變更失敗率"
msgid "DORA4Metrics|Change failure rate (percentage)"
msgstr "變更失敗率(%%)"
+msgid "DORA4Metrics|DORA metrics for %{groupName} group"
+msgstr "%{groupName} 群組的 DORA 指標"
+
msgid "DORA4Metrics|Date"
msgstr "日期"
@@ -11774,6 +11914,9 @@ msgstr "中ä½æ•¸æ™‚é–“ (最近 %{days} 天)"
msgid "DORA4Metrics|Median time an incident was open in a production environment over the given time period."
msgstr "在給定時間內,於正å¼ç’°å¢ƒä¸­æ‰€é–‹å•Ÿçš„事故中ä½æ•¸æ™‚間。"
+msgid "DORA4Metrics|Month to date"
+msgstr "本月至今"
+
msgid "DORA4Metrics|No incidents during this period"
msgstr "該期間無事故"
@@ -11823,7 +11966,7 @@ msgid "Dashboard uid not found"
msgstr "找ä¸åˆ°å„€è¡¨ç›¤uid"
msgid "DashboardProjects|All"
-msgstr "所有"
+msgstr "全部"
msgid "DashboardProjects|Personal"
msgstr "個人"
@@ -11831,6 +11974,9 @@ msgstr "個人"
msgid "DashboardProjects|Trending"
msgstr "熱門"
+msgid "Dashboards"
+msgstr "儀表æ¿"
+
msgid "Dashboard|%{firstProject} and %{secondProject}"
msgstr "%{firstProject} 和 %{secondProject}"
@@ -11847,7 +11993,7 @@ msgid "DastConfig|DAST CI/CD configuration"
msgstr "DAST CI/CD 設定"
msgid "DastConfig|Enable DAST to automatically test for vulnerabilities in your project's running application, website, or API, in the CI/CD pipeline. Configuration changes must be applied to your .gitlab-ci.yml file to take effect. For details of all configuration options, see the %{linkStart}GitLab DAST documentation%{linkEnd}."
-msgstr "在您的專案啟用 DAST 來自動測試 CI/CD æµæ°´ç·šä¸­æ­£åœ¨é‹è¡Œçš„應用程åºã€ç¶²ç«™æˆ– API çš„æ¼æ´žã€‚é…置的更改必須套用於您的 .gitlab-ci.yml 文件æ‰èƒ½ç”Ÿæ•ˆã€‚有關所有é…ç½®é¸é …的詳細信æ¯ï¼Œè«‹åƒé–± %{linkStart}GitLab DAST 文檔%{linkEnd}。"
+msgstr "在您的專案啟用 DAST 來自動測試 CI/CD æµæ°´ç·šä¸­æ­£åœ¨é‹è¡Œçš„應用程å¼ã€ç¶²ç«™æˆ– API çš„æ¼æ´žã€‚更改設定必須套用於您的 .gitlab-ci.yml 文件æ‰èƒ½å•Ÿå‹•ã€‚有關所有設定é¸é …的詳細信æ¯ï¼Œè«‹åƒé–± %{linkStart}GitLab DAST 文件%{linkEnd}。"
msgid "DastConfig|Enabled"
msgstr "已啟用"
@@ -12065,6 +12211,9 @@ msgstr "將目標站點和掃æ設置的常用設定ä¿å­˜ç‚ºé…置。使用這
msgid "DastProfiles|Save profile"
msgstr "儲存個人資料"
+msgid "DastProfiles|Scan Method"
+msgstr "掃ææ–¹å¼"
+
msgid "DastProfiles|Scan method"
msgstr "掃æ方法"
@@ -12282,6 +12431,9 @@ msgstr "é‡æ–°æ•´ç†è³‡æ–™"
msgid "Data type"
msgstr "資料類型"
+msgid "Database '%{database_name}' is using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
+msgstr "「%{database_name}ã€è³‡æ–™åº«ä½¿ç”¨çš„是 PostgreSQL %{pg_version_current},但這個版本的 GitLab éœ€è¦ PostgreSQL %{pg_version_minimum}。請將您環境中的 PostgreSQL å‡ç´šåˆ°æ”¯æ´ç‰ˆæœ¬ï¼Œè©³ç´°è³‡è¨Šè«‹è¦‹ %{pg_requirements_url}"
+
msgid "Database update failed"
msgstr "數據庫更新失敗"
@@ -12369,6 +12521,9 @@ msgstr "三"
msgid "Days"
msgstr "天"
+msgid "Days of inactivity before deactivation"
+msgstr "åœç”¨å‰çš„未活èºå¤©æ•¸"
+
msgid "Days to merge"
msgstr "åˆä½µæ‰€éœ€å¤©æ•¸"
@@ -12402,6 +12557,9 @@ msgstr "解壓縮檔案大å°é©—證失敗。"
msgid "Decrease"
msgstr "減少"
+msgid "Default - Never run"
+msgstr "é è¨­ - ä¸åŸ·è¡Œ"
+
msgid "Default CI/CD configuration file"
msgstr "é è¨­ CI/CD 組態設定檔"
@@ -12513,6 +12671,9 @@ msgstr "刪除"
msgid "Delete %{issuableType}"
msgstr "刪除 %{issuableType}"
+msgid "Delete %{issuableType}?"
+msgstr "刪除 %{issuableType}?"
+
msgid "Delete %{name}"
msgstr "刪除%{name}"
@@ -12534,9 +12695,6 @@ msgstr "刪除價值æµ"
msgid "Delete account"
msgstr "刪除帳號"
-msgid "Delete artifacts"
-msgstr "刪除產物"
-
msgid "Delete asset"
msgstr "刪除素æ"
@@ -12603,8 +12761,8 @@ msgstr "刪除 %{release} 版本發佈?"
msgid "Delete row"
msgstr "刪除行"
-msgid "Delete self monitoring project"
-msgstr "刪除自我監控專案"
+msgid "Delete self-monitoring project"
+msgstr "刪除自監控專案"
msgid "Delete snippet"
msgstr "刪除程å¼ç¢¼ç‰‡æ®µ"
@@ -12772,7 +12930,7 @@ msgid "Dependencies|(top level)"
msgstr "(頂級)"
msgid "Dependencies|All"
-msgstr "所有"
+msgstr "全部"
msgid "Dependencies|Component"
msgstr "元件"
@@ -13074,6 +13232,9 @@ msgstr "到期日期(å¯é¸)"
msgid "DeployTokens|Expires"
msgstr "éŽæœŸ"
+msgid "DeployTokens|Failed to create a new deployment token"
+msgstr "建立新的部署權æ–(令牌)失敗"
+
msgid "DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group."
msgstr "群組部署令牌(權æ–)å…許存å–群組內的軟體套件ã€ç‰ˆæœ¬åº«å’Œè¨»å†Šåº«æ˜ åƒæª”。"
@@ -13161,6 +13322,21 @@ msgstr "é¸å–部署目標"
msgid "Deployment frequency"
msgstr "部署頻率"
+msgid "DeploymentApprovals|Approvals"
+msgstr "核准"
+
+msgid "DeploymentApprovals|Approved By"
+msgstr "核准者"
+
+msgid "DeploymentApprovals|Approvers"
+msgstr "核准者"
+
+msgid "DeploymentApprovals|Developers + Maintainers"
+msgstr "開發人員 + 維é‹äººå“¡"
+
+msgid "DeploymentApprovals|Maintainers"
+msgstr "維é‹äººå“¡"
+
msgid "DeploymentApproval| Current approvals: %{current}"
msgstr "ç›®å‰æ ¸å‡†ï¼š%{current}"
@@ -13374,7 +13550,7 @@ msgid "DesignManagement|Are you sure you want to cancel creating this comment?"
msgstr "您確定è¦å–消建立此留言評論嗎?"
msgid "DesignManagement|Are you sure you want to cancel editing this comment?"
-msgstr ""
+msgstr "您確定è¦å–消編輯該留言嗎?"
msgid "DesignManagement|Click the image where you'd like to start a new discussion"
msgstr "單擊您è¦é–‹å§‹æ–°è¨Žè«–的圖åƒ"
@@ -13383,10 +13559,10 @@ msgid "DesignManagement|Comment"
msgstr "留言(評論)"
msgid "DesignManagement|Continue creating"
-msgstr ""
+msgstr "繼續建立"
msgid "DesignManagement|Continue editing"
-msgstr ""
+msgstr "繼續編輯"
msgid "DesignManagement|Could not add a new comment. Please try again."
msgstr "無法新增新留言。請é‡è©¦ã€‚"
@@ -13407,7 +13583,7 @@ msgid "DesignManagement|Designs"
msgstr "設計"
msgid "DesignManagement|Discard changes"
-msgstr ""
+msgstr "放棄變更"
msgid "DesignManagement|Discussion"
msgstr "討論"
@@ -13499,6 +13675,9 @@ msgstr "DevOps 報告"
msgid "DevOps adoption"
msgstr "DevOps adoption"
+msgid "Developer"
+msgstr "開發者"
+
msgid "Development"
msgstr "開發"
@@ -13735,6 +13914,12 @@ msgstr[0] "%d 個刪除"
msgid "Diffs|Expand all lines"
msgstr "展開所有行"
+msgid "Diffs|Hide whitespace changes"
+msgstr "éš±è—空白的變更"
+
+msgid "Diffs|Inline"
+msgstr "内嵌"
+
msgid "Diffs|Next 20 lines"
msgstr "下20行"
@@ -13750,10 +13935,16 @@ msgstr "顯示%{unfoldCount}行"
msgid "Diffs|Show all unchanged lines"
msgstr "顯示所有未更改的行"
+msgid "Diffs|Show whitespace changes"
+msgstr "顯示å«ç©ºç™½çš„變更"
+
msgid "Diffs|Showing %{dropdownStart}%{count} changed file%{dropdownEnd}"
msgid_plural "Diffs|Showing %{dropdownStart}%{count} changed files%{dropdownEnd}"
msgstr[0] "顯示 %{dropdownStart}%{count} 個更改的檔案%{dropdownEnd}"
+msgid "Diffs|Side-by-side"
+msgstr "並排"
+
msgid "Diffs|Something went wrong while fetching diff lines."
msgstr "å–得差異行時發生錯誤。"
@@ -14358,6 +14549,12 @@ msgstr "已編輯"
msgid "Edited %{timeago}"
msgstr "編輯於%{timeago}"
+msgid "Edited %{timeago} by %{author}"
+msgstr "由 %{author} 編輯於 %{timeago}"
+
+msgid "Edited by %{author}"
+msgstr "由 %{author} 編輯"
+
msgid "Editing"
msgstr "編輯中"
@@ -14386,7 +14583,7 @@ msgid "Elasticsearch reindexing was not started: %{errors}"
msgstr "Elasticsearch é‡å»ºç´¢å¼•å°šæœªé–‹å§‹ï¼š%{errors}"
msgid "Elasticsearch zero-downtime reindexing"
-msgstr "Elasticsearch ä¸åœæ©Ÿé‡å»ºç´¢å¼•ä¸­"
+msgstr "Elasticsearch zero-downtime reindexing"
msgid "Elastic|None. Select namespaces to index."
msgstr "無。請é¸æ“‡è¦å»ºç«‹ç´¢å¼•çš„命å空間。"
@@ -14688,23 +14885,41 @@ msgstr "啟用使用者åœç”¨é›»å­éƒµä»¶"
msgid "Enable version check"
msgstr "啟用版本檢查"
-msgid "EnableReviewApp|%{stepStart}Step 1%{stepEnd}. Ensure you have Kubernetes set up and have a base domain for your %{linkStart}cluster%{linkEnd}."
-msgstr "%{stepStart}步驟 1%{stepEnd}: 確ä¿æ‚¨å·²è¨­ç½®Kubernetes並為您的%{linkStart}å¢é›†%{linkEnd}æ供了基本域。"
+msgid "EnableReviewApp|Add a job in your CI/CD configuration that:"
+msgstr "在您的 CI/CD 設定中增加一項作業:"
-msgid "EnableReviewApp|%{stepStart}Step 2%{stepEnd}. Copy the following snippet:"
-msgstr "%{stepStart}步驟 2%{stepEnd}: 複製以下腳本:"
+msgid "EnableReviewApp|Copy snippet"
+msgstr "複製代碼片段"
-msgid "EnableReviewApp|%{stepStart}Step 3%{stepEnd}. Add it to the project %{linkStart}gitlab-ci.yml%{linkEnd} file."
-msgstr "%{stepStart}步驟 3%{stepEnd}: 將其加入到專案的%{linkStart}gitlab-ci.yml%{linkEnd}文件。"
+msgid "EnableReviewApp|Have access to infrastructure that can host and deploy the review apps."
+msgstr "有權存å–å¯ä»¥è¨—管和部署審核應用程å¼çš„基礎架構。"
-msgid "EnableReviewApp|%{stepStart}Step 4 (optional)%{stepEnd}. Enable Visual Reviews by following the %{linkStart}setup instructions%{linkEnd}."
-msgstr "%{stepStart}步驟 4(å¯é¸ï¼‰%{stepEnd}。%{linkStart}根據設定說明啟用å¯è¦–化評審%{linkEnd}。"
+msgid "EnableReviewApp|Install and configure a runner to do the deployment."
+msgstr "安è£ä¸¦è¨­å®šä¸€å€‹åŸ·è¡Œå™¨ä¾†é€²è¡Œéƒ¨ç½²ã€‚"
-msgid "EnableReviewApp|Close"
-msgstr "關閉"
+msgid "EnableReviewApp|Make sure your project has an environment configured with the target URL set to your website URL. If not, create a new one before continuing."
+msgstr "確定您的專案有一個設定了目標 URL 的環境,該目標 URL 設置為您的網站 URL。 如果沒有,請在繼續之å‰å»ºç«‹ä¸€å€‹æ–°çš„。"
-msgid "EnableReviewApp|Copy snippet text"
-msgstr "複製代碼片段"
+msgid "EnableReviewApp|Only runs for feature branches or merge requests."
+msgstr "僅é‡å°åŠŸèƒ½åˆ†æ”¯æˆ–åˆä½µè«‹æ±‚執行。"
+
+msgid "EnableReviewApp|Recommended: Set up a job that manually stops the Review Apps."
+msgstr "推薦:設置手動åœæ­¢æ‡‰ç”¨ç¨‹å¼å¯©æ ¸çš„作業。"
+
+msgid "EnableReviewApp|Review apps are dynamic environments that you can use to provide a live preview of changes made in a feature branch."
+msgstr "應用程å¼å¯©æŸ¥æ˜¯ä¸€å€‹å‹•æ…‹ç’°å¢ƒï¼Œæ‚¨å¯ç”¨æ–¼æ供功能分支中所åšæ›´æ”¹çš„實時é è¦½ã€‚"
+
+msgid "EnableReviewApp|To configure a dynamic review app, you must:"
+msgstr "è¦è¨­å®šå‹•æ…‹æ‡‰ç”¨ç¨‹å¼å¯©æŸ¥ï¼Œæ‚¨å¿…須:"
+
+msgid "EnableReviewApp|Uses a predefined CI/CD variable like %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} to dynamically create the review app environments. For example, for a configuration using merge request pipelines:"
+msgstr "使用 %{codeStart}$(CI_COMMIT_REF_SLUG)%{codeEnd} ç­‰é å®šç¾©çš„ CI/CD 變數來動態建立審查應用環境, 例如,å°æ–¼ä½¿ç”¨åˆä½µè«‹æ±‚æµæ°´ç·šçš„é…置:"
+
+msgid "EnableReviewApp|Using a static site?"
+msgstr "使用éœæ…‹ç¶²ç«™ï¼Ÿ"
+
+msgid "EnableReviewApp|View more example projects"
+msgstr "查看更多專案範例"
msgid "Enabled"
msgstr "已啟用"
@@ -14931,6 +15146,9 @@ msgstr "環境|自動åœæ­¢ %{autoStopAt}"
msgid "Environments|Commit"
msgstr "æ交"
+msgid "Environments|Copy live environment URL"
+msgstr "複製實時環境 URL"
+
msgid "Environments|Delete"
msgstr "環境|刪除"
@@ -15111,12 +15329,12 @@ msgstr "加入一個新的å²è©©ã€‚"
msgid "Epics|Add an existing epic"
msgstr "加入一個ç¾æœ‰çš„å²è©©ã€‚"
+msgid "Epics|Are you sure you want to remove %{bStart}%{targetEpicTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
+msgstr "您確定è¦å¾ž %{bStart}%{parentEpicTitle}%{bEnd} 移除 %{bStart}%{targetEpicTitle}%{bEnd} 嗎?"
+
msgid "Epics|Are you sure you want to remove %{bStart}%{targetIssueTitle}%{bEnd} from %{bStart}%{parentEpicTitle}%{bEnd}?"
msgstr "確定è¦å¾ž%{bStart}%{parentEpicTitle}%{bEnd}刪除%{bStart}%{targetIssueTitle}%{bEnd}å—Ž?"
-msgid "Epics|Assign Epic"
-msgstr "指派å²è©©"
-
msgid "Epics|Leave empty to inherit from milestone dates"
msgstr "留空以繼承里程碑日期"
@@ -15129,18 +15347,9 @@ msgstr "刪除å²è©©"
msgid "Epics|Remove issue"
msgstr "刪除議題"
-msgid "Epics|Search epics"
-msgstr "æœå°‹å²è©©"
-
-msgid "Epics|Select epic"
-msgstr "é¸æ“‡å²è©©"
-
msgid "Epics|Show more"
msgstr "顯示更多"
-msgid "Epics|Something went wrong while assigning issue to epic."
-msgstr "分é…議題到å²è©©æ™‚發生錯誤。"
-
msgid "Epics|Something went wrong while creating child epics."
msgstr "建立å­å²è©©æ™‚發生錯誤。"
@@ -15153,18 +15362,12 @@ msgstr "å–å¾—å­å²è©©æ™‚發生錯誤。"
msgid "Epics|Something went wrong while fetching epics list."
msgstr "å–å¾—å²è©©åˆ—表時發生錯誤。"
-msgid "Epics|Something went wrong while fetching group epics."
-msgstr "å–得群組å²è©©æ™‚發生錯誤。"
-
msgid "Epics|Something went wrong while moving item."
msgstr "移動專案時出了錯。"
msgid "Epics|Something went wrong while ordering item."
msgstr "排åºæ™‚發生錯誤。"
-msgid "Epics|Something went wrong while removing issue from epic."
-msgstr "從å²è©©ä¸­åˆªé™¤è­°é¡Œæ™‚發生錯誤。"
-
msgid "Epics|Something went wrong while updating epics."
msgstr "æ›´æ–°å²è©©æ™‚發生錯誤。"
@@ -15294,9 +15497,6 @@ msgstr "ä¿å­˜è¢«æŒ‡æ´¾äººæ™‚出ç¾éŒ¯èª¤ã€‚"
msgid "Error occurred when saving reviewers"
msgstr "ä¿å­˜å¯©æ ¸è€…時發生錯誤"
-msgid "Error occurred while updating the %{issuableType} status"
-msgstr "更新 %{issuableType} 狀態時發生錯誤"
-
msgid "Error occurred while updating the issue status"
msgstr "更新議題狀態時發生錯誤"
@@ -15360,9 +15560,6 @@ msgstr "上傳文件時發生錯誤"
msgid "Error uploading file. Please try again."
msgstr "上傳檔案時出錯。請é‡è©¦ã€‚"
-msgid "Error uploading file: %{stripped}"
-msgstr "上傳文件時發生錯誤: %{stripped}"
-
msgid "Error while loading the merge request. Please try again."
msgstr "載入åˆä½µè«‹æ±‚時出錯。請é‡è©¦ã€‚"
@@ -15603,6 +15800,57 @@ msgstr "事件"
msgid "Events API"
msgstr "事件 API"
+msgid "Event|accepted"
+msgstr "已接å—"
+
+msgid "Event|added"
+msgstr "已加入"
+
+msgid "Event|approved"
+msgstr "已核准"
+
+msgid "Event|closed"
+msgstr "已關閉"
+
+msgid "Event|commented on"
+msgstr "已留言/評論"
+
+msgid "Event|created"
+msgstr "已建立"
+
+msgid "Event|deleted"
+msgstr "已刪除"
+
+msgid "Event|destroyed"
+msgstr "已銷毀"
+
+msgid "Event|imported"
+msgstr "已匯入"
+
+msgid "Event|joined"
+msgstr "已加入"
+
+msgid "Event|left"
+msgstr "剩餘"
+
+msgid "Event|opened"
+msgstr "已開啟"
+
+msgid "Event|pushed new"
+msgstr "新推é€"
+
+msgid "Event|pushed to"
+msgstr "推é€åˆ°"
+
+msgid "Event|removed"
+msgstr "已移除"
+
+msgid "Event|removed due to membership expiration from"
+msgstr "因會員到期而被移除"
+
+msgid "Event|updated"
+msgstr "已更新"
+
msgid "Every %{action} attempt has failed: %{job_error_message}. Please try again."
msgstr "所有 %{action} 嘗試都已失敗: %{job_error_message}。請é‡è©¦ã€‚"
@@ -15721,6 +15969,9 @@ msgstr "ä¸åŒ…括åˆä½µæ交。僅é™6,000次æ交。"
msgid "Execution time"
msgstr "執行時間"
+msgid "Executive Dashboard"
+msgstr "執行儀表æ¿"
+
msgid "Existing branch name, tag, or commit SHA"
msgstr "ç¾æœ‰åˆ†æ”¯å稱ã€æ¨™ç±¤æˆ–æ交 SHA"
@@ -15743,10 +15994,10 @@ msgid "Expand all"
msgstr "展開全部"
msgid "Expand all files"
-msgstr "展開所有檔案"
+msgstr "展開全部檔案"
msgid "Expand all threads"
-msgstr "展開所有話題"
+msgstr "展開全部話題"
msgid "Expand approvers"
msgstr "展開核准者"
@@ -15778,9 +16029,15 @@ msgstr "展開å´é‚Šæ¬„"
msgid "Expected documents: %{expected_documents}"
msgstr "需è¦çš„文件: %{expected_documents}"
+msgid "Experiment Candidates"
+msgstr "實驗候é¸äºº"
+
msgid "ExperimentSubject|Must have exactly one of User, Namespace, or Project."
msgstr "必須有一個使用者ã€å‘½å空間或專案。"
+msgid "Experiments"
+msgstr "實驗"
+
msgid "Expiration"
msgstr "到期"
@@ -16004,6 +16261,9 @@ msgstr "失敗於"
msgid "Failed to add a Zoom meeting"
msgstr "無法加入Zoom會議"
+msgid "Failed to add a resource link"
+msgstr "加入資æºéˆçµå¤±æ•—"
+
msgid "Failed to apply commands."
msgstr "應用指令失敗。"
@@ -16050,9 +16310,6 @@ msgstr "建立框架失敗"
msgid "Failed to create import label for jira import."
msgstr "建立從 jira 匯入的匯入標記失敗。"
-msgid "Failed to create new access token: %{token_response_message}"
-msgstr "建立新訪å•ä»¤ç‰Œå¤±æ•—:%{token_response_message}"
-
msgid "Failed to create repository"
msgstr "建立版本庫失敗"
@@ -16248,9 +16505,6 @@ msgstr "無法更新議題狀態"
msgid "Failed to update the Canary Ingress."
msgstr "無法更新 Canary Ingress。"
-msgid "Failed to update."
-msgstr "更新失敗。"
-
msgid "Failed to upgrade."
msgstr "å‡ç´šå¤±æ•—。"
@@ -16310,7 +16564,7 @@ msgid "FeatureFlags|%{percent} randomly"
msgstr "隨機%{percent}"
msgid "FeatureFlags|* (All Environments)"
-msgstr "*(所有環境)"
+msgstr "*(全部環境)"
msgid "FeatureFlags|API URL"
msgstr "API URL"
@@ -16322,13 +16576,13 @@ msgid "FeatureFlags|Add strategy"
msgstr "加入策略"
msgid "FeatureFlags|All Environments"
-msgstr "所有環境"
+msgstr "全部環境"
msgid "FeatureFlags|All Users"
-msgstr "所有使用者"
+msgstr "全部使用者"
msgid "FeatureFlags|All users"
-msgstr "所有使用者"
+msgstr "全部使用者"
msgid "FeatureFlags|Configure"
msgstr "é…ç½®"
@@ -16507,6 +16761,9 @@ msgstr "2月"
msgid "February"
msgstr "2月"
+msgid "Feedback and Updates"
+msgstr "回饋與更新"
+
msgid "Fetch and check out this merge request's feature branch:"
msgstr "å–得並簽出此åˆä½µè«‹æ±‚的功能分支:"
@@ -16612,9 +16869,6 @@ msgstr "ä¾ç•¶å‰å·²é—œé–‰å’Œæœªåˆä½µçš„åˆä½µè«‹æ±‚éŽæ¿¾ã€‚"
msgid "Filter by merge requests that are currently merged."
msgstr "ä¾ç•¶å‰å·²åˆä½µçš„åˆä½µè«‹æ±‚éŽæ¿¾ã€‚"
-msgid "Filter by milestone"
-msgstr "ä¾é‡Œç¨‹ç¢‘éŽæ¿¾"
-
msgid "Filter by milestone name"
msgstr "ä¾é‡Œç¨‹ç¢‘å稱éŽæ¿¾"
@@ -16822,6 +17076,9 @@ msgstr "如需了解詳細訊æ¯ï¼Œè«‹åƒé–±"
msgid "For more information, see the File Hooks documentation."
msgstr "欲知更多資訊,請檢視檔案掛鉤文件。"
+msgid "Forbidden"
+msgstr "ç¦æ­¢"
+
msgid "Forgot your password?"
msgstr "忘記密碼?"
@@ -16928,7 +17185,7 @@ msgid "Framework successfully deleted"
msgstr "框架刪除æˆåŠŸ"
msgid "Free"
-msgstr ""
+msgstr "å…è²»"
msgid "Free Trial of GitLab.com Ultimate"
msgstr "å…費試用 GitLab.com Ultimate"
@@ -17035,7 +17292,7 @@ msgid "General Settings"
msgstr "一般設定"
msgid "General pipelines"
-msgstr "æµæ°´ç·šé€šç”¨è¨­å®š"
+msgstr "æµæ°´ç·šä¸€èˆ¬è¨­å®š"
msgid "General settings"
msgstr "一般設定"
@@ -17142,7 +17399,7 @@ msgid "Geo|All %{replicable_name}"
msgstr "全部 %{replicable_name}"
msgid "Geo|All projects"
-msgstr "所有專案"
+msgstr "全部專案"
msgid "Geo|All projects are being scheduled for resync"
msgstr "所有專案都已安排é‡æ–°åŒæ­¥"
@@ -17226,7 +17483,7 @@ msgid "Geo|Errors:"
msgstr "錯誤:"
msgid "Geo|External URL"
-msgstr ""
+msgstr "外部 URL"
msgid "Geo|Failed"
msgstr "失敗"
@@ -17568,7 +17825,7 @@ msgid "Geo|There was an error updating the Geo Settings"
msgstr "更新Geo設定時發生錯誤"
msgid "Geo|This GitLab instance is subscribed to the %{insufficient_license} tier. Geo is only available for users who have at least a Premium subscription."
-msgstr ""
+msgstr "這個 GitLab 實例已訂閱為 %{insufficient_license} 層級,Geo 僅é©ç”¨æ–¼è‡³å°‘æ“有進階訂閱的使用者。"
msgid "Geo|This will resync all %{replicableType}. It may take some time to complete. Are you sure you want to continue?"
msgstr "å°‡è¦é‡æ–°åŒæ­¥æ‰€æœ‰%{replicableType}。å¯èƒ½éœ€è¦ä¸€äº›æ™‚間完æˆã€‚確定繼續嗎?"
@@ -17651,9 +17908,6 @@ msgstr "次è¦ç¯€é»ž"
msgid "Get a free instance review"
msgstr "ç²å¾—å…費的實體評估"
-msgid "Get a free trial"
-msgstr "ç²å¾—å…費試用"
-
msgid "Get a support subscription"
msgstr "å–得支æ´è¨‚é–±"
@@ -17780,6 +18034,12 @@ msgstr "請求建立GitLab帳號"
msgid "GitLab Billing Team."
msgstr "GitLab 計費團隊"
+msgid "GitLab Community Edition"
+msgstr "GitLab 社群版本"
+
+msgid "GitLab Enterprise Edition"
+msgstr "GitLab ä¼æ¥­ç‰ˆæœ¬"
+
msgid "GitLab Error Tracking"
msgstr "GitLab 錯誤追踪"
@@ -17831,6 +18091,9 @@ 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}"
@@ -17879,9 +18142,6 @@ msgstr "GitLab版本"
msgid "GitLab will create a branch in your fork and start a merge request."
msgstr "GitLab 將在你的分å‰ï¼ˆFork)中建立一個分支並啟動一個åˆä½µè«‹æ±‚。"
-msgid "GitLab.com"
-msgstr "GitLab.com"
-
msgid "GitLab.com (SaaS)"
msgstr "GitLab.com (SaaS)"
@@ -18437,9 +18697,6 @@ msgstr "GraphViewType|顯示ä¾è³´é …"
msgid "GraphViewType|Stage"
msgstr "GraphViewType|階段"
-msgid "Graphs"
-msgstr "圖表"
-
msgid "Gravatar"
msgstr "Gravatar"
@@ -18449,6 +18706,9 @@ msgstr "啟用 Gravatar"
msgid "Group"
msgstr "群組"
+msgid "Group %{group_name} and its Mattermost team were successfully created."
+msgstr "%{group_name} 群組åŠå…¶æœ€é‡è¦çš„團隊已æˆåŠŸå»ºç«‹ã€‚"
+
msgid "Group %{group_name} couldn't be exported."
msgstr "無法匯出群組 %{group_name}。"
@@ -18915,7 +19175,7 @@ msgid "GroupSettings|Compliance frameworks"
msgstr "åˆè¦æ¡†æž¶"
msgid "GroupSettings|Configure compliance frameworks to make them available to projects in this group. %{linkStart}What are compliance frameworks?%{linkEnd}"
-msgstr ""
+msgstr "é…ç½®åˆè¦æ€§æ¡†æž¶ä»¥ä½¿å…¶å¯ç”¨æ–¼è©²ç¾¤çµ„中的專案。 %{linkStart}什麼是åˆè¦æ¡†æž¶ï¼Ÿ%{linkEnd}"
msgid "GroupSettings|Configure limits on the number of repositories users can download in a given time."
msgstr "設定使用者在給定時間內å¯ä»¥ä¸‹è¼‰çš„版本庫數é‡é™åˆ¶ã€‚"
@@ -19211,12 +19471,6 @@ msgstr "GroupsTree|離開群組"
msgid "GroupsTree|Loading groups"
msgstr "載入群組中"
-msgid "GroupsTree|No groups matched your search"
-msgstr "沒有æœå°‹åˆ°ä»»ä½•ç¬¦åˆçš„群組"
-
-msgid "GroupsTree|No groups or projects matched your search"
-msgstr "沒有任何群組或項目符åˆæ‚¨çš„æœå°‹"
-
msgid "GroupsTree|Options"
msgstr "GroupsTree|é¸é …"
@@ -19286,6 +19540,9 @@ msgstr "å­ç¾¤çµ„ Slug"
msgid "Groups|You're creating a new top-level group"
msgstr "您正在建立一個新的最上層群組"
+msgid "Guest"
+msgstr "訪客"
+
msgid "Guideline"
msgstr "åƒè€ƒ"
@@ -19308,7 +19565,7 @@ msgid "Harbor Registry"
msgstr "Harbor 映åƒåº«"
msgid "HarborIntegration|After the Harbor integration is activated, global variables `$HARBOR_USERNAME`, `$HARBOR_HOST`, `$HARBOR_OCI`, `$HARBOR_PASSWORD`, `$HARBOR_URL` and `$HARBOR_PROJECT` will be created for CI/CD use."
-msgstr ""
+msgstr "啟用 Harbor æ•´åˆå¾Œï¼Œå°‡ç‚º CI/CD å»ºç«‹ä¸‹åˆ—å…¨å±€è®Šé‡ `$HARBOR_USERNAME`ã€`$HARBOR_HOST`ã€`$HARBOR_OCI`ã€`$HARBOR_PASSWORD`ã€`$HARBOR_URL` å’Œ `$HARBOR_PROJECT`。"
msgid "HarborIntegration|Base URL of the Harbor instance."
msgstr "Harbor 實例的基本 URL。"
@@ -19462,9 +19719,6 @@ msgstr "執行狀æ³è¨Šæ¯å¯ä»¥å¾žä»¥ä¸‹API路徑抓å–。如需了解更多資
msgid "Health status"
msgstr "å¥åº·ç‹€æ…‹"
-msgid "Health status cannot be edited because this issue is closed"
-msgstr "無法編輯å¥åº·ç‹€æ…‹ï¼Œå› ç‚ºæ­¤è­°é¡Œå·²é—œé–‰"
-
msgid "HealthCheck|Access token is"
msgstr "å­˜å–權æ–為"
@@ -19917,8 +20171,14 @@ msgstr "發é€é©—證碼"
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr "發生錯誤,請å†è©¦ä¸€æ¬¡ã€‚"
-msgid "IdentityVerification|Step 1: Verify phone number"
-msgstr " 步驟 1:驗證電話號碼"
+msgid "IdentityVerification|Step %{stepNumber}: Verify a payment method"
+msgstr "步驟 %{stepNumber}:驗證付款方å¼"
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify email address"
+msgstr "步驟 %{stepNumber}:驗證電å­éƒµä»¶ä½å€"
+
+msgid "IdentityVerification|Step %{stepNumber}: Verify phone number"
+msgstr "步驟 %{stepNumber}:驗證電話號碼"
msgid "IdentityVerification|The code has expired. Send a new code and try again."
msgstr "驗證碼已éŽæœŸï¼Œç™¼é€æ–°é©—證碼並é‡è©¦ã€‚"
@@ -20004,12 +20264,6 @@ msgstr "如果此電å­éƒµä»¶è¢«éŒ¯èª¤åŠ å…¥ï¼Œæ‚¨å¯ä»¥åœ¨é€™è£¡ç§»é™¤ï¼š"
msgid "If this email was added in error, you can remove it here: %{profile_emails_url}"
msgstr "如果此電å­éƒµä»¶è¢«éŒ¯èª¤åŠ å…¥ï¼Œæ‚¨å¯ä»¥åœ¨é€™è£¡ç§»é™¤å®ƒï¼š %{profile_emails_url}"
-msgid "If this is a mistake, you can %{link_start}unban them%{link_end}."
-msgstr "如果這是一個錯誤,您å¯ä»¥ %{link_start}解ç¦ä»–們%{link_end}。"
-
-msgid "If this is a mistake, you can unban them: %{url}."
-msgstr "如果這是一個錯誤,你å¯ä»¥è§£ç¦ä»–們:%{url}。"
-
msgid "If this was a mistake you can %{leave_link_start}leave the %{source_type}%{link_end}."
msgstr "如果這是一個錯誤,你å¯ä»¥%{leave_link_start}退出%{source_type}%{link_end}。"
@@ -20235,7 +20489,7 @@ msgid "ImportProjects|%{provider} rate limit exceeded. Try again later"
msgstr "超éŽ%{provider}的速率é™åˆ¶ã€‚è«‹ç¨å¾Œå†è©¦"
msgid "ImportProjects|Advanced import settings"
-msgstr ""
+msgstr "進階匯入設定"
msgid "ImportProjects|Blocked import URL: %{message}"
msgstr "ç¦æ­¢çš„匯入URL: %{message}"
@@ -20262,7 +20516,7 @@ msgid "ImportProjects|Select the repositories you want to import"
msgstr "é¸æ“‡æ‚¨æƒ³è¦åŒ¯å…¥çš„版本庫"
msgid "ImportProjects|The more information you select, the longer it will take to import"
-msgstr ""
+msgstr "您é¸æ“‡çš„訊æ¯è¶Šå¤šï¼ŒåŒ¯å…¥æ™‚間就越長"
msgid "ImportProjects|The remote data could not be imported."
msgstr "無法匯入é ç«¯è³‡æ–™ã€‚"
@@ -21757,6 +22011,9 @@ msgstr "無效的雙é‡èªè­‰ç¢¼ã€‚"
msgid "Invalid yaml"
msgstr "無效的yaml"
+msgid "Invalidated"
+msgstr "無效"
+
msgid "Investigate vulnerability: %{title}"
msgstr "調查æ¼æ´ž: %{title}"
@@ -21775,9 +22032,6 @@ msgstr "邀請已被拒絕。"
msgid "Invite \"%{email}\" by email"
msgstr "通éŽé›»å­éƒµä»¶é‚€è«‹ã€Œ%{email}ã€"
-msgid "Invite \"%{trimmed}\" by email"
-msgstr "通éŽé›»å­éƒµä»¶é‚€è«‹ã€Œ%{trimmed}ã€"
-
msgid "Invite Members"
msgstr "邀請æˆå“¡"
@@ -21835,8 +22089,8 @@ msgstr "邀請您的åŒäº‹"
msgid "InviteMembersBanner|We noticed that you haven't invited anyone to this group. Invite your colleagues so you can discuss issues, collaborate on merge requests, and share your knowledge."
msgstr "ç›®å‰æ‚¨é‚„沒有邀請任何人加入這個群組。 您å¯ä»¥é‚€è«‹æ‚¨çš„åŒäº‹åˆ°ç¾¤çµ„,以方便討論å•é¡Œï¼Œåœ¨åˆä½µè«‹æ±‚中進行å”作,以åŠåˆ†äº«æ‚¨çš„知識。"
-msgid "InviteMembersModal| To get more members and access to additional paid features, an owner of the group can start a trial or upgrade to a paid tier."
-msgstr "è¦å–得更多æˆå“¡ä¸¦å­˜å–其他付費功能,群組的æ“有者å¯ä»¥é–‹å§‹è©¦ç”¨æˆ–å‡ç´šåˆ°ä»˜è²»ç­‰ç´šã€‚"
+msgid "InviteMembersModal| To get more members, the owner of this namespace can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
+msgstr "è¦å–得更多æˆå“¡ï¼Œè©²å‘½å空間的æ“有者å¯ä»¥ %{trialLinkStart}開始試用%{trialLinkEnd} 或 %{upgradeLinkStart} å‡ç´š %{upgradeLinkEnd} 到付費等級。"
msgid "InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions"
msgstr "%{linkStart}瞭解更多%{linkEnd}關於角色權é™çš„訊æ¯"
@@ -21914,21 +22168,18 @@ msgid "InviteMembersModal|The following member couldn't be invited"
msgid_plural "InviteMembersModal|The following %d members couldn't be invited"
msgstr[0] "下列 %d 個æˆå“¡ç„¡æ³•è¢«é‚€è«‹"
-msgid "InviteMembersModal|This feature is disabled until this group has space for more members."
-msgstr "在該群組有空間容ç´æ›´å¤šæˆå“¡ä¹‹å‰ï¼Œæ­¤åŠŸèƒ½å°‡è¢«ç¦ç”¨ã€‚"
-
msgid "InviteMembersModal|To assign issues to a new team member, you need a project for the issues. %{linkStart}Create a project to get started.%{linkEnd}"
msgstr "è¦å‘新團隊æˆå“¡åˆ†é…議題,您需è¦ä¸€å€‹è­°é¡Œæ‰€å±¬çš„專案。 %{linkStart}從建立一個專案開始。%{linkEnd}"
msgid "InviteMembersModal|To get more members an owner of the group can %{trialLinkStart}start a trial%{trialLinkEnd} or %{upgradeLinkStart}upgrade%{upgradeLinkEnd} to a paid tier."
msgstr "è¦å–得更多æˆå“¡ï¼Œç¾¤çµ„çš„æ“有者å¯ä»¥ %{trialLinkStart}開始試用%{trialLinkEnd} 或 %{upgradeLinkStart}å‡ç´š%{upgradeLinkEnd} 到付費等級。"
+msgid "InviteMembersModal|To invite new users to this namespace, you must remove existing users. You can still add existing namespace users."
+msgstr "è¦é‚€è«‹æ–°ä½¿ç”¨è€…加入該命å空間,您必須移除ç¾å­˜ä½¿ç”¨è€…。您ä»ç„¶å¯ä»¥å¢žåŠ ç¾å­˜å‘½å空間的使用者。"
+
msgid "InviteMembersModal|Username or email address"
msgstr "使用者å稱或郵箱地å€"
-msgid "InviteMembersModal|You cannot add more members, but you can remove members who no longer need access."
-msgstr "您無法增加更多æˆå“¡ï¼Œä½†å¯ä»¥ç§»é™¤ä¸å†éœ€è¦å­˜å–權é™çš„æˆå“¡ã€‚"
-
msgid "InviteMembersModal|You only have space for %{count} more %{members} in %{name}"
msgstr "在 %{name},您åªæœ‰ %{count} 個更多的 %{members} 的空間"
@@ -22064,12 +22315,18 @@ msgstr "正在使用授權æ¢æ¬¾ï¼š"
msgid "Is using seat"
msgstr "正在使用許å¯å¸­æ¬¡"
+msgid "IssuableEvents|assigned to"
+msgstr "指派給"
+
msgid "IssuableEvents|removed review request for"
msgstr "已移除審查請求"
msgid "IssuableEvents|requested review from"
msgstr "審查è¦æ±‚"
+msgid "IssuableEvents|unassigned"
+msgstr "未指派"
+
msgid "IssuableStatus|%{wi_type} created %{created_at} by "
msgstr "%{wi_type} 創建者 %{created_at}"
@@ -22091,6 +22348,18 @@ msgstr "已移動"
msgid "IssuableStatus|promoted"
msgstr "å·²å‡ç´š"
+msgid "Issuable|epic"
+msgstr "å²è©©"
+
+msgid "Issuable|escalation policy"
+msgstr "å‡ç´šæ”¿ç­–"
+
+msgid "Issuable|iteration"
+msgstr "迭代"
+
+msgid "Issuable|milestone"
+msgstr "里程碑"
+
msgid "Issue"
msgstr "議題"
@@ -22316,6 +22585,21 @@ msgstr "è¦æ“´å¤§æœå°‹ç¯„åœï¼Œè«‹è®Šæ›´æˆ–刪除上é¢çš„éŽæ¿¾æ¢ä»¶"
msgid "IssuesAnalytics|Total:"
msgstr "總計:"
+msgid "Issues|Move selected"
+msgstr "移動已é¸å–çš„"
+
+msgid "Issues|Tasks and test cases can not be moved."
+msgstr "任務和測試案例ä¸èƒ½è¢«ç§»å‹•ã€‚"
+
+msgid "Issues|Tasks can not be moved."
+msgstr "任務ä¸èƒ½è¢«ç§»å‹•ã€‚"
+
+msgid "Issues|Test cases can not be moved."
+msgstr "測試案例ä¸èƒ½è¢«ç§»å‹•ã€‚"
+
+msgid "Issues|There was an error while moving the issues."
+msgstr "移動議題時發生錯誤。"
+
msgid "Issue|Title"
msgstr "標題"
@@ -22610,6 +22894,9 @@ msgstr "é©ç”¨æ–¼ Jira 應用程åºçš„ GitLab"
msgid "JiraConnect|Jira Connect Application ID"
msgstr "Jira Connect æ‡‰ç”¨ç¨‹åº ID"
+msgid "JiraConnect|Jira Connect Proxy URL"
+msgstr "Jira Connect 代ç†ä¼ºæœå™¨ URL"
+
msgid "JiraConnect|New branch was successfully created."
msgstr "æˆåŠŸå»ºç«‹æ–°åˆ†æ”¯ã€‚"
@@ -22940,6 +23227,9 @@ msgstr "已建立"
msgid "Job|Download"
msgstr "下載"
+msgid "Job|Duration"
+msgstr "期間"
+
msgid "Job|Erase job log and artifacts"
msgstr "擦除作業日誌和產物"
@@ -22979,9 +23269,15 @@ msgstr "等待中"
msgid "Job|Preparing"
msgstr "正在準備"
+msgid "Job|Queued"
+msgstr "佇列"
+
msgid "Job|Retry"
msgstr "é‡è©¦"
+msgid "Job|Run again"
+msgstr "å†æ¬¡åŸ·è¡Œ"
+
msgid "Job|Running"
msgstr "執行中"
@@ -23356,9 +23652,6 @@ msgstr "最後一次由 %{link_start}%{avatar} %{name}%{link_end} 編輯"
msgid "Last event"
msgstr "最近一次事件"
-msgid "Last item before this page loaded in your browser:"
-msgstr "在此é é¢è¼‰å…¥ä¹‹å‰çš„最後一個專案:"
-
msgid "Last modified"
msgstr "最近修改"
@@ -23512,6 +23805,15 @@ msgstr "了解關於群組的更多資訊。"
msgid "Learn more about issues."
msgstr "了解更多關於議題的資訊。"
+msgid "Learn more about linking epics"
+msgstr "å–得更多關於連çµå²è©©çš„資訊"
+
+msgid "Learn more about linking issues"
+msgstr "å–得更多關於連çµè­°é¡Œçš„資訊"
+
+msgid "Learn more about linking issues and incidents"
+msgstr "了解更多關於連çµè­°é¡Œèˆ‡äº‹æ•…的資訊"
+
msgid "Learn more about max seats used"
msgstr "了解更多關於最大席ä½æ•¸çš„資訊"
@@ -23662,9 +23964,6 @@ msgstr "退出專案"
msgid "Leave zen mode"
msgstr "離開禪模å¼"
-msgid "Leaving this setting enabled is recommended."
-msgstr "建議啟用此設定。"
-
msgid "Legacy burndown chart"
msgstr "éºç•™çš„燃盡圖"
@@ -23905,6 +24204,12 @@ msgstr "變更的行"
msgid "Link"
msgstr "連çµ"
+msgid "Link %{issuableType}s together to show that they're related or that one is blocking others."
+msgstr "å°‡ %{issuableType} 連çµåœ¨ä¸€èµ·ä»¥è¡¨ç¤ºå®ƒå€‘是相關的,或是其中一個正在阻擋其他的。"
+
+msgid "Link %{issuableType}s together to show that they're related."
+msgstr "å°‡ %{issuableType} 連çµåœ¨ä¸€èµ·ä»¥è¡¨ç¤ºå®ƒå€‘是相關的。"
+
msgid "Link (optional)"
msgstr "連çµï¼ˆå¯é¸ï¼‰"
@@ -24175,9 +24480,6 @@ msgstr "Logo 將被刪除,您確定嗎?"
msgid "Logs"
msgstr "日誌"
-msgid "Looks like you've reached your %{free_limit} member limit for %{strong_start}%{namespace_name}%{strong_end}"
-msgstr "您似乎已é”到 %{strong_start}%{namespace_name}%{strong_end} çš„ %{free_limit} æˆå“¡é™åˆ¶"
-
msgid "Low vulnerabilities present"
msgstr "存在低風險æ¼æ´ž"
@@ -24190,6 +24492,9 @@ msgstr "MD5"
msgid "MERGED"
msgstr "å·²åˆä½µ"
+msgid "ML Experiments"
+msgstr "ML 實驗"
+
msgid "MR widget|Back to the merge request"
msgstr "返回åˆä½µè«‹æ±‚"
@@ -24226,8 +24531,14 @@ msgstr "åªæŸ¥çœ‹è®Šæ›´å…§å®¹"
msgid "MRDiff|Show full file"
msgstr "顯示全部文件"
-msgid "Made this issue confidential."
-msgstr "將此議題設定為ç§å¯†."
+msgid "Machine Learning Experiment Tracking is in Incubating Phase"
+msgstr "機器學習(ML)實驗追踪處於孵化階段"
+
+msgid "Machine Learning Experiments"
+msgstr "機器學習(ML)實驗"
+
+msgid "Made this %{type} confidential."
+msgstr "將該 %{type} 設為機密。"
msgid "Mailgun"
msgstr "Mailgun"
@@ -24241,9 +24552,15 @@ msgstr "Mailgun事件"
msgid "Main menu"
msgstr "主é¸å–®"
+msgid "Maintainer"
+msgstr "維護者"
+
msgid "Maintenance mode"
msgstr "維護模å¼"
+msgid "Make %{type} confidential"
+msgstr "將 %{type} 設為機密"
+
msgid "Make adjustments to how your GitLab instance is set up."
msgstr "調整您 GitLab 實例的設定方å¼ã€‚"
@@ -24253,9 +24570,6 @@ msgstr "使用Web IDE在ç€è¦½å™¨ä¸­å»ºç«‹å’ŒæŸ¥çœ‹æ›´æ”¹"
msgid "Make everyone on your team more productive regardless of their location. GitLab Geo creates read-only mirrors of your GitLab instance so you can reduce the time it takes to clone and fetch large repos."
msgstr "GitLab Geoå¯ä»¥å»ºç«‹GitLab實體的唯讀é¡åƒ, 使得從é ç«¯è¤‡è£½å’Œæ‹‰å–大型程å¼ç¢¼ç‰ˆæœ¬åº«çš„時間大大縮短,從而æ高團隊æˆå“¡çš„工作效率。"
-msgid "Make issue confidential"
-msgstr "將議題設定為機密。"
-
msgid "Make sure you choose a strong, unique password."
msgstr "確定您é¸æ“‡äº†ä¸€å€‹é«˜å¼·åº¦ä¸”唯一的密碼。"
@@ -24265,8 +24579,8 @@ msgstr "確ä¿æ‚¨å…·æœ‰éˆæŽ¥å°ˆæ¡ˆçš„正確權é™ã€‚"
msgid "Make sure you save it - you won't be able to access it again."
msgstr "請確ä¿å¦¥å–„儲存它 - 您無法å†æ¬¡å­˜å–它的內容。"
-msgid "Makes this issue confidential."
-msgstr "將此議題設定為機密."
+msgid "Makes this %{type} confidential."
+msgstr "將該 %{type} 設為機密。"
msgid "Manage %{workspace} labels"
msgstr "ç®¡ç† %{workspace} 標記"
@@ -24314,7 +24628,7 @@ msgid "Manage your project's triggers"
msgstr "管ç†æ‚¨çš„專案觸發器"
msgid "Manage your subscription"
-msgstr ""
+msgstr "管ç†æ‚¨çš„訂閱"
msgid "Managed Account"
msgstr "託管帳號"
@@ -24322,6 +24636,9 @@ msgstr "託管帳號"
msgid "Manifest"
msgstr "Manifest"
+msgid "Manifest file"
+msgstr "Manifest 檔案"
+
msgid "Manifest file import"
msgstr "Manifest文件匯入"
@@ -24346,6 +24663,9 @@ msgstr "3月"
msgid "March"
msgstr "3月"
+msgid "MardownDrawer|Could not fetch help contents."
+msgstr "無法擷å–說明內容。"
+
msgid "Mark as done"
msgstr "標記為已完æˆ"
@@ -24397,6 +24717,9 @@ msgstr "加入刪除線文本 (%{modifierKey}⇧X)"
msgid "MarkdownEditor|Add strikethrough text (%{modifier_key}⇧X)"
msgstr "加入帶刪除線的文本 (%{modifier_key}⇧X)"
+msgid "MarkdownEditor|Click to expand"
+msgstr "點擊展開"
+
msgid "MarkdownEditor|Indent line (%{modifierKey}])"
msgstr "縮排 (%{modifierKey}])"
@@ -24409,6 +24732,9 @@ msgstr "凸排 (%{modifierKey}[)"
msgid "MarkdownEditor|Outdent line (%{modifier_key}[)"
msgstr "凸排 (%{modifier_key}[)"
+msgid "MarkdownEditor|header"
+msgstr "標題"
+
msgid "MarkdownToolbar|Supports %{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
msgstr "支æ´%{markdownDocsLinkStart}Markdown%{markdownDocsLinkEnd}"
@@ -25035,6 +25361,9 @@ msgstr "åˆä½µè«‹æ±‚與核准設定已被移動。"
msgid "Merge requests are a place to propose changes you've made to a project and discuss those changes with others"
msgstr "åˆä½µè«‹æ±‚用於æ出å°å°ˆæ¡ˆçš„變更並與他人進行討論"
+msgid "Merge requests can't be merged if the status checks did not succeed or are still running."
+msgstr "若狀態檢查未æˆåŠŸæˆ–ä»åœ¨åŸ·è¡Œä¸­ï¼Œå‰‡ç„¡æ³•åˆä½µåˆä½µè«‹æ±‚。"
+
msgid "Merge the feature branch into the target branch and fix any conflicts. %{linkStart}How do I fix them?%{linkEnd}"
msgstr "將功能分支åˆä½µåˆ°ç›®æ¨™åˆ†æ”¯ä¸¦ä¿®å¾©ä»»ä½•è¡çªã€‚ %{linkStart}我該如何修復它們?%{linkEnd}"
@@ -25260,6 +25589,9 @@ msgstr "方法"
msgid "Method call threshold (ms)"
msgstr "方法調用閾值(毫秒)"
+msgid "Metric"
+msgstr "指標"
+
msgid "Metric was successfully added."
msgstr "指標已æˆåŠŸåŠ å…¥ã€‚"
@@ -25649,6 +25981,9 @@ msgstr "里程碑截止日期"
msgid "Milestone lists not available with your current license"
msgstr "ç›®å‰æŽˆæ¬Šæ¢æ¬¾ç„¡æ³•ä½¿ç”¨é‡Œç¨‹ç¢‘列表"
+msgid "Milestone(s) not found: %{milestones}"
+msgstr "找ä¸åˆ°é‡Œç¨‹ç¢‘:%{milestones}"
+
msgid "MilestoneCombobox|An error occurred while searching for milestones"
msgstr "æœå°‹é‡Œç¨‹ç¢‘時發生錯誤"
@@ -25808,6 +26143,9 @@ msgstr "%{percentage}%{percent} 完æˆ"
msgid "Min Value"
msgstr "最å°å€¼"
+msgid "Minimal Access"
+msgstr "最å°å­˜å–權é™"
+
msgid "Minimum capacity to be available before we schedule more mirrors preemptively."
msgstr "在我們é å…ˆå®‰æŽ’更多映åƒä¹‹å‰å¯ç”¨çš„最å°å®¹é‡ã€‚"
@@ -25880,6 +26218,9 @@ msgstr "在您個人資料中加入SSH金鑰之å‰ï¼Œæ‚¨ç„¡æ³•é€šéŽSSH來拉å–
msgid "MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile"
msgstr "在您個人資料中加入SSH金鑰之å‰ï¼Œæ‚¨å°‡ä¸èƒ½é€šéŽSSH來拉å–或推é€ç‰ˆæœ¬åº«ã€‚"
+msgid "MlExperimentsEmptyState|No Experiments to Show"
+msgstr "沒有實驗å¯ä»¥å±•ç¤º"
+
msgid "ModalButton|Add projects"
msgstr "加入專案"
@@ -26066,6 +26407,9 @@ msgstr "ä¸æ”¯æ´å¤šå€‹Prometheusæ•´åˆ"
msgid "Multiplier to apply to polling intervals. Decimal values are supported. Defaults to 1."
msgstr "應用於輪詢間隔的乘數。支æ´å進制值。é è¨­ç‚º 1。"
+msgid "Must be 90 days or more."
+msgstr "必須至少90天。"
+
msgid "My awesome group"
msgstr "我最棒的團隊"
@@ -26524,6 +26868,9 @@ msgstr "無範åœ"
msgid "No Work Item Link found"
msgstr "未找到工作項éŠçµ"
+msgid "No access"
+msgstr "沒有存å–權é™"
+
msgid "No active admin user found"
msgstr "沒有找到活動的管ç†å“¡ä½¿ç”¨è€…"
@@ -26653,9 +27000,6 @@ msgstr "沒有å¯é¡¯ç¤ºè¿­ä»£"
msgid "No job log"
msgstr "沒有作業日誌"
-msgid "No jobs to show"
-msgstr "沒有è¦é¡¯ç¤ºçš„作業"
-
msgid "No label"
msgstr "無標記"
@@ -26683,9 +27027,6 @@ msgstr "沒有符åˆçš„çµæžœ"
msgid "No matching results for \"%{query}\""
msgstr "沒有與\"%{query}\"符åˆçš„çµæžœ"
-msgid "No matching results..."
-msgstr "無符åˆçš„çµæžœ..."
-
msgid "No members found"
msgstr "未找到æˆå“¡"
@@ -26701,9 +27042,6 @@ msgstr "未記錄任何消æ¯"
msgid "No milestone"
msgstr "無里程碑"
-msgid "No namespace"
-msgstr "沒有命å空間"
-
msgid "No other labels with such name or description"
msgstr "沒有其他具有此類å稱或æ述的標記"
@@ -26814,7 +27152,7 @@ msgid_plural "No worries, you can still use all the %{strong}%{plan_name}%{stron
msgstr[0] "ä¸ç”¨æ“”心,您ç¾åœ¨ä»ç„¶å¯ä»¥ä½¿ç”¨æ‰€æœ‰ %{strong}%{plan_name}%{strong_close} 功能。您有 %{remaining_days} 天來續訂您的訂閱。"
msgid "No wrap"
-msgstr ""
+msgstr "ä¸æŠ˜è¡Œ"
msgid "No. of commits"
msgstr "æ交次數"
@@ -26936,8 +27274,8 @@ msgstr "收起復原"
msgid "Notes|Expand replies"
msgstr "展開回復"
-msgid "Notes|Internal notes are only visible to the author, assignees, and members with the role of Reporter or higher"
-msgstr "內部註釋僅å°ä½œè€…ã€å—指派人和具有報告者或更高角色的æˆå“¡å¯è¦‹"
+msgid "Notes|Internal notes are only visible to members with the role of Reporter or higher"
+msgstr "內部註釋僅å°å…·æœ‰å ±å‘Šè€…或是更高角色的æˆå“¡å¯è¦‹"
msgid "Notes|Last reply by %{name}"
msgstr "由 %{name} 最後回復"
@@ -27267,6 +27605,9 @@ msgstr "新議題: %{project_issue_url}"
msgid "Notify|No preview for this file type"
msgstr "該文件類型無法é è¦½"
+msgid "Notify|Pipeline #%{pipeline_id} has failed!"
+msgstr "#%{pipeline_id} æµæ°´ç·šå¤±æ•—ï¼"
+
msgid "Notify|Pipeline %{pipeline_link} triggered by"
msgstr "æµæ°´ç·š %{pipeline_link} 的觸發者為"
@@ -27276,6 +27617,9 @@ msgstr "æµæ°´ç·šå·²ä¿®å¾©ï¼Œ#%{pipeline_id} 已通éŽï¼"
msgid "Notify|Project %{old_path_with_namespace} was moved to another location."
msgstr "專案 %{old_path_with_namespace} 已移到其他ä½ç½®ã€‚"
+msgid "Notify|Project %{project_name} couldn't be exported."
+msgstr "無法匯出 %{project_name} 專案。"
+
msgid "Notify|Project %{project_name} was exported successfully."
msgstr "專案 %{project_name} å·²æˆåŠŸåŒ¯å‡ºã€‚"
@@ -27297,6 +27641,9 @@ msgstr "未包å«å·®ç•°ï¼Œå› ç‚ºå®ƒå¤ªå¤§ã€‚"
msgid "Notify|The download link will expire in 24 hours."
msgstr "該下載éˆçµå°‡åœ¨ 24 å°æ™‚後失效。"
+msgid "Notify|The errors we encountered were:"
+msgstr "我們é‡åˆ°çš„錯誤是:"
+
msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}."
msgstr "該專案ç¾åœ¨ä½æ–¼ %{project_full_name_link_start}%{project_full_name}%{link_end} 下。"
@@ -27390,9 +27737,6 @@ msgstr "員工人數"
msgid "Number of events"
msgstr "事件數é‡"
-msgid "Number of events for this project: %{total_count}."
-msgstr "此專案的事件數é‡: %{total_count}。"
-
msgid "Number of files touched"
msgstr "改動的文件數"
@@ -27417,9 +27761,6 @@ msgstr "10月"
msgid "October"
msgstr "10月"
-msgid "OfSearchInADropdown|Filter"
-msgstr "éŽæ¿¾"
-
msgid "Off"
msgstr "關閉"
@@ -27652,12 +27993,6 @@ msgstr "無法å–得站點設定。請é‡æ–°æ•´ç†é é¢æˆ–ç¨å¾Œå†è©¦ã€‚"
msgid "OnDemandScans|Could not run the scan. Please try again."
msgstr "無法執行掃æ。請é‡è©¦ã€‚"
-msgid "OnDemandScans|Create new scanner profile"
-msgstr "建立新的掃æ工具設定"
-
-msgid "OnDemandScans|Create new site profile"
-msgstr "建立新的站點設定"
-
msgid "OnDemandScans|DAST configuration"
msgstr "DAST 組態"
@@ -27703,12 +28038,6 @@ msgstr "例如:測試SQL注入的登入é é¢"
msgid "OnDemandScans|Keep editing"
msgstr "繼續編輯"
-msgid "OnDemandScans|Manage scanner profiles"
-msgstr "管ç†æŽƒæ工具設定"
-
-msgid "OnDemandScans|Manage site profiles"
-msgstr "管ç†ç«™é»žè¨­å®š"
-
msgid "OnDemandScans|My daily scan"
msgstr "我的æ¯æ—¥æŽƒæ"
@@ -27730,12 +28059,6 @@ msgstr "新增掃æ"
msgid "OnDemandScans|No %{profileType} profiles found for DAST"
msgstr "未找到 DAST çš„ %{profileType} é…置文件"
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile."
-msgstr "å°šç„¡é…置文件。如需建立新掃æ,需è¦è‡³å°‘有一個完整的掃æ工具設定。"
-
-msgid "OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile."
-msgstr "尚無設定。如需建立新掃æ,需è¦è‡³å°‘有一個完整的站點設定。"
-
msgid "OnDemandScans|On-demand Scans"
msgstr "On-demand 掃æ"
@@ -27778,15 +28101,6 @@ msgstr "掃æ排程"
msgid "OnDemandScans|Scan type"
msgstr "掃æé¡žåž‹"
-msgid "OnDemandScans|Scanner profile"
-msgstr "掃æ工具設定"
-
-msgid "OnDemandScans|Select one of the existing profiles"
-msgstr "é¸æ“‡ä¸€å€‹ç¾æœ‰çš„設定"
-
-msgid "OnDemandScans|Site profile"
-msgstr "站點設定"
-
msgid "OnDemandScans|Start by creating a new profile. Profiles make it easy to save and reuse configuration details for GitLab’s security tools."
msgstr "首先建立一個新的é…置文件。é…置文件å¯ä»¥è¼•é¬†ä¿å­˜å’Œé‡å¾©ä½¿ç”¨ GitLab 安全工具的組態詳細信æ¯ã€‚"
@@ -27817,12 +28131,6 @@ msgstr "沒有排程中的掃æ。"
msgid "OnDemandScans|Timezone"
msgstr "時å€"
-msgid "OnDemandScans|Use existing scanner profile"
-msgstr "使用ç¾æœ‰çš„站點設定"
-
-msgid "OnDemandScans|Use existing site profile"
-msgstr "使用ç¾æœ‰çš„站點設定"
-
msgid "OnDemandScans|View results"
msgstr "查看çµæžœ"
@@ -27841,9 +28149,6 @@ msgstr "版本庫匯入後,å¯ä»¥é€šéŽSSH進行é¡åƒã€‚點擊%{link_start}æ­
msgid "Once removed, the fork relationship cannot be restored. This project will no longer be able to receive or send merge requests to the source project or other forks."
msgstr "移除後將無法æ¢å¾©åˆ†å‰ï¼ˆFork)關係。此專案將無法å†å‘來æºå°ˆæ¡ˆæˆ–其他分å‰ç™¼é€æˆ–接收åˆä½µè«‹æ±‚。"
-msgid "Once you confirm and press \"Reduce project visibility\":"
-msgstr "一旦您確èªä¸¦æŒ‰ä¸‹\"é™ä½Žå°ˆæ¡ˆå¯è¦‹æ€§\":"
-
msgid "One more item"
msgid_plural "%d more items"
msgstr[0] "其餘%d項"
@@ -28016,9 +28321,6 @@ msgstr "æ“作失敗。請檢查 Pod 日誌 %{pod_name} 了解更多資訊。"
msgid "Operation not allowed"
msgstr "ä¸å…許該æ“作"
-msgid "Operation timed out. Check pod logs for %{pod_name} for more details."
-msgstr "æ“作逾時。請檢查 Pod 日誌 %{pod_name} 了解更多資訊。"
-
msgid "Operations"
msgstr "維é‹"
@@ -28386,12 +28688,21 @@ msgstr "刪除軟體套件"
msgid "PackageRegistry|Delete package asset"
msgstr "刪除軟體套件資產"
+msgid "PackageRegistry|Delete package version"
+msgstr "刪除軟體套件版本"
+
msgid "PackageRegistry|Delete selected"
msgstr "刪除é¸å–"
msgid "PackageRegistry|Delete this package"
msgstr "刪除該軟體套件"
+msgid "PackageRegistry|Deleting all package assets will remove version %{version} of %{name}. Are you sure?"
+msgstr "刪除所有軟體套件資產將åŒæ™‚移除 %{name} çš„ %{version} 版本,您確定嗎?"
+
+msgid "PackageRegistry|Deleting the last package asset will remove version %{version} of %{name}. Are you sure?"
+msgstr "刪除最後一個軟體套件資產將åŒæ™‚移除 %{name} çš„ %{version} 版本,您確定嗎?"
+
msgid "PackageRegistry|Duplicate packages"
msgstr "é‡è¤‡çš„套件"
@@ -28437,6 +28748,12 @@ msgstr "Gradle Kotlin DSL安è£æŒ‡ä»¤"
msgid "PackageRegistry|Helm"
msgstr "Helm"
+msgid "PackageRegistry|Help us learn about your registry migration needs"
+msgstr "幫助我們了解您的註冊表é·ç§»éœ€æ±‚"
+
+msgid "PackageRegistry|If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs."
+msgstr "如果您有興趣將軟體套件從您的ç§æœ‰è¨»å†Šè¡¨é·ç§»åˆ° GitLab 的註冊表,請åƒèˆ‡æˆ‘們的調查並告訴我們更多關於您的需求。"
+
msgid "PackageRegistry|If you haven't already done so, you will need to add the below to your %{codeStart}.pypirc%{codeEnd} file."
msgstr "如果尚未é…置,需è¦å°‡ä»¥ä¸‹å…§å®¹åŠ å…¥åˆ°%{codeStart}.pypirc%{codeEnd}文件中。"
@@ -28508,7 +28825,7 @@ msgid "PackageRegistry|Package updated by commit %{link} on branch %{branch}, bu
msgstr "軟體套件由分支%{branch}上的%{link}æ交所更新,由æµæ°´ç·š%{pipeline}構建並於%{datetime}發布到庫"
msgid "PackageRegistry|Permanently delete"
-msgstr ""
+msgstr "永久刪除"
msgid "PackageRegistry|Permanently delete assets"
msgstr "永久刪除資產"
@@ -28582,6 +28899,9 @@ msgstr "å°ä¸èµ·ï¼Œæ²’有符åˆéŽæ¿¾å™¨çš„任何çµæžœ"
msgid "PackageRegistry|Source project located at %{link}"
msgstr "來æºå°ˆæ¡ˆä½æ–¼%{link}"
+msgid "PackageRegistry|Take survey"
+msgstr "åƒåŠ èª¿æŸ¥"
+
msgid "PackageRegistry|Target SHA: %{sha}"
msgstr "目標 SHA:%{sha}"
@@ -28622,7 +28942,7 @@ msgid "PackageRegistry|You are about to delete %{filename}. This is a destructiv
msgstr "您將è¦åˆªé™¤ %{filename}。這是一種破壞性æ“作,å¯èƒ½æœƒä½¿æ‚¨çš„軟體套件無法使用。您確定嗎?"
msgid "PackageRegistry|You are about to delete %{name}, are you sure?"
-msgstr ""
+msgstr "您å³å°‡åˆªé™¤ %{name},確定嗎?"
msgid "PackageRegistry|You are about to delete 1 asset. This operation is irreversible."
msgid_plural "PackageRegistry|You are about to delete %d assets. This operation is irreversible."
@@ -28964,12 +29284,6 @@ msgstr "牆"
msgid "Period in seconds"
msgstr "週期(秒)"
-msgid "Period of inactivity (days)"
-msgstr "未活動時間(天)"
-
-msgid "Period of inactivity before deactivation."
-msgstr "åœç”¨å‰çš„未活動的時間。"
-
msgid "Permalink"
msgstr "永久連çµ"
@@ -29018,8 +29332,8 @@ msgstr "Phabricator伺æœå™¨åŒ¯å…¥"
msgid "Phabricator Server URL"
msgstr "Pharibator伺æœå™¨URL"
-msgid "Phabricator Tasks"
-msgstr "Phabricator任務"
+msgid "Phabricator tasks"
+msgstr "Phabricator 任務"
msgid "Phone"
msgstr "電話"
@@ -29235,22 +29549,28 @@ msgid "PipelineSchedules|Active"
msgstr "已啟用"
msgid "PipelineSchedules|All"
-msgstr "所有"
+msgstr "全部"
+
+msgid "PipelineSchedules|Are you sure you want to delete this pipeline schedule?"
+msgstr "確定è¦åˆªé™¤æ­¤æµæ°´ç·šæŽ’程嗎?"
msgid "PipelineSchedules|Delete pipeline schedule"
-msgstr ""
+msgstr "刪除æµæ°´ç·šæŽ’程"
msgid "PipelineSchedules|Description"
-msgstr ""
+msgstr "æè¿°"
msgid "PipelineSchedules|Edit pipeline schedule"
-msgstr ""
+msgstr "編輯æµæ°´ç·šæŽ’程"
msgid "PipelineSchedules|Inactive"
msgstr "未啟用"
msgid "PipelineSchedules|Last Pipeline"
-msgstr ""
+msgstr "最近一次æµæ°´ç·š"
+
+msgid "PipelineSchedules|New schedule"
+msgstr "新排程"
msgid "PipelineSchedules|Next Run"
msgstr "下次執行時間"
@@ -29262,25 +29582,37 @@ msgid "PipelineSchedules|Only the owner of a pipeline schedule can make changes
msgstr "åªæœ‰æµæ°´ç·šæŽ’程的所有者,æ‰èƒ½å°å…¶é€²è¡Œè®Šæ›´ã€‚您是å¦è¦å–得這個排程的所有權?"
msgid "PipelineSchedules|Owner"
-msgstr ""
+msgstr "æ“有者"
+
+msgid "PipelineSchedules|Pipeline schedule successfully deleted."
+msgstr "å·²æˆåŠŸåˆªé™¤æµæ°´ç·šæŽ’程。"
msgid "PipelineSchedules|Provide a short description for this pipeline"
msgstr "為此æµæ°´ç·šæ供簡短æè¿°"
msgid "PipelineSchedules|Run pipeline schedule"
-msgstr ""
+msgstr "執行æµæ°´ç·šæŽ’程"
+
+msgid "PipelineSchedules|Successfully taken ownership from %{owner}."
+msgstr "å·²æˆåŠŸå¾ž %{owner} å–得所有權。"
msgid "PipelineSchedules|Take ownership"
msgstr "å–得所有權"
msgid "PipelineSchedules|Take ownership of pipeline schedule"
-msgstr ""
+msgstr "å–å¾—æµæ°´ç·šæŽ’程的所有權"
msgid "PipelineSchedules|Target"
msgstr "目標"
+msgid "PipelineSchedules|There was a problem deleting the pipeline schedule."
+msgstr "刪除æµæ°´ç·šæŽ’程時出ç¾å•é¡Œã€‚"
+
msgid "PipelineSchedules|There was a problem fetching pipeline schedules."
-msgstr ""
+msgstr "æ“·å–æµæ°´ç·šæŽ’程時出ç¾å•é¡Œã€‚"
+
+msgid "PipelineSchedules|There was a problem taking ownership of the pipeline schedule."
+msgstr "å–å¾—æµæ°´ç·šæŽ’程所有權時發生å•é¡Œã€‚"
msgid "PipelineSchedules|Variables"
msgstr "變數"
@@ -30041,9 +30373,6 @@ msgstr "è«‹é¸æ“‡ä¸€å€‹Jira專案"
msgid "Please select a country"
msgstr "è«‹é¸æ“‡åœ‹å®¶/地å€"
-msgid "Please select a file"
-msgstr "è«‹é¸æ“‡ä¸€å€‹æ–‡ä»¶"
-
msgid "Please select a group"
msgstr "è«‹é¸æ“‡ä¸€å€‹ç¾¤çµ„"
@@ -30120,13 +30449,13 @@ msgid "PolicyRuleMultiSelect|%{firstLabel} +%{numberOfAdditionalLabels} more"
msgstr "%{firstLabel} +%{numberOfAdditionalLabels} 更多"
msgid "PolicyRuleMultiSelect|All %{itemTypeName}"
-msgstr "所有 %{itemTypeName}"
+msgstr "全部 %{itemTypeName}"
msgid "PolicyRuleMultiSelect|Select %{itemTypeName}"
msgstr "é¸æ“‡ %{itemTypeName}"
msgid "PolicyRuleMultiSelect|Select all"
-msgstr "é¸æ“‡æ‰€æœ‰"
+msgstr "é¸æ“‡å…¨éƒ¨"
msgid "Polling interval multiplier"
msgstr "輪詢間隔å€æ•¸"
@@ -30152,6 +30481,69 @@ msgstr "檢測到å¯èƒ½ä¸éœ€è¦çš„字符:Unicode BiDi Control"
msgid "Pre-defined push rules"
msgstr "é å…ˆå®šç¾©çš„推é€è¦å‰‡"
+msgid "PreScanVerification|(optional)"
+msgstr "(å¯é¸ï¼‰"
+
+msgid "PreScanVerification|Attempts to authenticate with the scan target"
+msgstr "嘗試å°æŽƒæ目標進行身份驗證"
+
+msgid "PreScanVerification|Attempts to find and connect to the scan target"
+msgstr "嘗試尋找並連çµè‡³æŽƒæ目標"
+
+msgid "PreScanVerification|Attempts to follow internal links and crawl 3 pages without errors"
+msgstr "嘗試追蹤內部連çµä¸¦ç„¡éŒ¯èª¤åœ°æŠ“å–三個é é¢"
+
+msgid "PreScanVerification|Authentication"
+msgstr "é©—è­‰"
+
+msgid "PreScanVerification|Cancel pre-scan verification"
+msgstr "å–消é æŽƒæé©—è­‰"
+
+msgid "PreScanVerification|Connection"
+msgstr "連線"
+
+msgid "PreScanVerification|Download results"
+msgstr "下載çµæžœ"
+
+msgid "PreScanVerification|Last run %{timeAgo} in pipeline"
+msgstr "%{timeAgo} å‰æ–¼æµæ°´ç·šä¸­æœ€å¾ŒåŸ·è¡Œ"
+
+msgid "PreScanVerification|Pre-scan verification"
+msgstr "é æŽƒæé©—è­‰"
+
+msgid "PreScanVerification|Save and run verification"
+msgstr "儲存並執行驗證"
+
+msgid "PreScanVerification|Started %{timeAgo} in pipeline"
+msgstr "%{timeAgo} å‰æ–¼æµæ°´ç·šä¸­é–‹å§‹ "
+
+msgid "PreScanVerification|Target exploration"
+msgstr "目標探索"
+
+msgid "PreScanVerification|Test your configuration and identify potential errors before running a full scan."
+msgstr "在執行完整掃æ之å‰æ¸¬è©¦æ‚¨çš„組態設定並鑑別潛在錯誤。"
+
+msgid "PreScanVerification|The last pre-scan verification job is no longer valid because this scan’s configuration has changed."
+msgstr "最後一次的é æŽƒæ驗證作業ä¸å†æœ‰æ•ˆï¼Œå› ç‚ºè©²æŽƒæ的設定已變更。"
+
+msgid "PreScanVerification|The pre-scan verification status was reset for this scan"
+msgstr "該掃æçš„é æŽƒæ驗證狀態已é‡ç½®"
+
+msgid "PreScanVerification|Verification checks"
+msgstr "驗證檢查"
+
+msgid "PreScanVerification|Verification checks are determined by a scan’s configuration details. Changing configuration details may alter or reset the verification checks and their status."
+msgstr "驗證檢查由掃æ的設定詳細資訊決定。變更設定詳細資訊å¯èƒ½æœƒè®Šæ›´æˆ–é‡è¨­é©—證檢查åŠå…¶ç‹€æ…‹ã€‚"
+
+msgid "PreScanVerification|Verify configuration"
+msgstr "驗證組態é…ç½®"
+
+msgid "PreScanVerification|View results"
+msgstr "檢視çµæžœ"
+
+msgid "PreScanVerification|You must complete the scan configuration form before running pre-scan verification"
+msgstr "您必須在執行é æŽƒæé©—è­‰å‰å¡«å¯«æŽƒæ設定表單"
+
msgid "Preferences"
msgstr "å好設定"
@@ -30159,7 +30551,7 @@ msgid "Preferences saved."
msgstr "å好設定已儲存。"
msgid "Preferences|Automatically add new list items"
-msgstr ""
+msgstr "自動加入新的列表項目"
msgid "Preferences|Behavior"
msgstr "個人化"
@@ -30273,7 +30665,7 @@ msgid "Preferences|Use relative times"
msgstr "使用相å°æ™‚é–“"
msgid "Preferences|When you type in a description or comment box, pressing %{kbdOpen}Enter%{kbdClose} in a list adds a new item below."
-msgstr ""
+msgstr "當您在æ述或留言框中輸入時,在列表中按 %{kbdOpen}Enter%{kbdClose} 會在下é¢å¢žåŠ ä¸€å€‹æ–°é …目。"
msgid "Preferences|When you type in a description or comment box, selected text is surrounded by the corresponding character after typing one of the following characters: %{supported_characters}."
msgstr "當您在æ述或留言框中輸入時,在輸入以下字元之一後,é¸å®šçš„文本將被相應的字元包åœï¼š%{supported_characters}。"
@@ -30293,6 +30685,9 @@ msgstr "防止在專案與åˆä½µè«‹æ±‚中編輯核准è¦å‰‡"
msgid "Prevent environment from auto-stopping"
msgstr "ç¦æ­¢ç’°å¢ƒè‡ªå‹•åœæ­¢"
+msgid "Prevent outdated deployment jobs"
+msgstr "防止éŽæœŸçš„部署作業"
+
msgid "Prevent project forking outside current group"
msgstr "ç¦æ­¢å°ˆæ¡ˆåˆ†å‰ï¼ˆFork)到當å‰ç¾¤çµ„以外"
@@ -30386,12 +30781,18 @@ msgstr "%{name} 指令發生錯誤: %{message}。"
msgid "Proceed"
msgstr "繼續"
-msgid "Product Analytics"
+msgid "Product analytics"
msgstr "產å“分æž"
+msgid "ProductAnalytics|Audience"
+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|Widgets content"
+msgstr "å°çµ„件內容"
+
msgid "Productivity"
msgstr "生產率"
@@ -30968,6 +31369,9 @@ msgstr "專案å稱"
msgid "Project navigation"
msgstr "專案導覽"
+msgid "Project or Group"
+msgstr "專案或群組"
+
msgid "Project order will not be saved as local storage is not available."
msgstr "由於本機儲存ä¸å¯ç”¨ï¼Œå› æ­¤ä¸æœƒå„²å­˜å°ˆæ¡ˆé †åºã€‚"
@@ -30980,6 +31384,9 @@ msgstr "專案安全狀態"
msgid "Project security status help page"
msgstr "專案安全狀態幫助é é¢"
+msgid "Project settings were successfully updated."
+msgstr "專案設定已更新æˆåŠŸã€‚"
+
msgid "Project slug"
msgstr "專案標識"
@@ -31262,12 +31669,18 @@ msgstr "%{link_start}什麼是æ述範本?%{link_end}"
msgid "ProjectSettings|%{link_start}What variables can I use?%{link_end}"
msgstr "%{link_start}我å¯ä»¥ä½¿ç”¨å“ªäº›è®Šæ•¸ï¼Ÿ%{link_end}"
+msgid "ProjectSettings|A default branch cannot be chosen for an empty project."
+msgstr "無法為一個空專案é¸æ“‡é è¨­åˆ†æ”¯ã€‚"
+
msgid "ProjectSettings|Additional options"
msgstr "附加é¸é …"
msgid "ProjectSettings|Additional settings that influence how and when merges are done."
msgstr "影響åˆä½µå®Œæˆçš„æ–¹å¼å’Œæ™‚間的其他設定。"
+msgid "ProjectSettings|All merge requests and commits are made against this branch unless you specify a different one."
+msgstr "除éžæ‚¨æŒ‡å®šä¸åŒçš„分支,å¦å‰‡æ‰€æœ‰åˆä½µè«‹æ±‚å’Œæ交都是é‡å°è©²åˆ†æ”¯é€²è¡Œçš„,。"
+
msgid "ProjectSettings|All threads must be resolved"
msgstr "必須解決所有線程"
@@ -31280,12 +31693,18 @@ msgstr "始終在議題ã€åˆä½µè«‹æ±‚和程å¼ç¢¼ç‰‡æ®µä¸Šé¡¯ç¤ºè®šåŒå’Œä¸è®š
msgid "ProjectSettings|Analytics"
msgstr "分æž"
+msgid "ProjectSettings|Auto-close referenced issues on default branch"
+msgstr "自動關閉é è¨­åˆ†æ”¯ä¸Šæ‰€åƒç…§çš„議題。"
+
msgid "ProjectSettings|Automatically resolve merge request diff threads when they become outdated"
msgstr "當它們變得éŽæ™‚時自動處ç†åˆä½µè«‹æ±‚差異線程"
msgid "ProjectSettings|Badges"
msgstr "徽章"
+msgid "ProjectSettings|Branches created from issues follow this pattern."
+msgstr "éµå¾ªè©²æ¨£å¼å¾žè­°é¡Œå»ºç«‹åˆ†æ”¯ã€‚"
+
msgid "ProjectSettings|Build, test, and deploy your changes."
msgstr "構建ã€æ¸¬è©¦å’Œéƒ¨ç½²æ‚¨çš„更改。"
@@ -31307,6 +31726,9 @@ msgstr "é¸æ“‡æ‚¨çš„åˆä½µæ–¹æ³•ã€é¸é …ã€æª¢æŸ¥å’Œå£“縮 (Squash) é¸é …。"
msgid "ProjectSettings|Combine git tags with release notes, release evidence, and assets to create a release."
msgstr " çµåˆ git 標籤與發布說明ã€ç™¼å¸ƒè­‰æ“šå’Œè³‡ç”¢ä¾†å»ºç«‹ç™¼å¸ƒã€‚"
+msgid "ProjectSettings|Configure your infrastructure."
+msgstr "請設定您的基礎架構。"
+
msgid "ProjectSettings|Configure your project resources and monitor their health."
msgstr "設定您的專案資æºä¸¦ç›£æŽ§å®ƒå€‘的執行狀æ³ã€‚"
@@ -31406,6 +31828,9 @@ msgstr "它們有何ä¸åŒï¼Ÿ"
msgid "ProjectSettings|If merge trains are enabled, merging is only possible if the branch can be rebased without conflicts."
msgstr "如果啟用了åˆä½µä½‡åˆ—,則åªæœ‰åœ¨åˆ†æ”¯å¯ä»¥ä¸ç™¼ç”Ÿè¡çªçš„情æ³ä¸‹è®ŠåŸº (Rebase) æ‰èƒ½é€²è¡Œåˆä½µã€‚"
+msgid "ProjectSettings|Infrastructure"
+msgstr "基礎架構"
+
msgid "ProjectSettings|Internal"
msgstr "內部"
@@ -31473,7 +31898,7 @@ msgid "ProjectSettings|Note: The container registry is always visible when a pro
msgstr "注æ„:當專案是公共的並且容器映åƒåº«è¨­å®šç‚ºã€Œ%{access_level_description}ã€æ™‚,容器映åƒåº«å§‹çµ‚å¯è¦‹"
msgid "ProjectSettings|Only commits that include a %{code_block_start}Signed-off-by:%{code_block_end} element can be pushed to this repository."
-msgstr ""
+msgstr "åªæœ‰ %{code_block_start}Signed-off-by:%{code_block_end} çš„æ交æ‰èƒ½æŽ¨é€åˆ°æ­¤ç‰ˆæœ¬åº«ã€‚"
msgid "ProjectSettings|Only signed commits can be pushed to this repository."
msgstr "åªæœ‰å·²ç°½ç½²æ交æ‰å¯ä»¥æŽ¨é€åˆ°æ­¤ç‰ˆæœ¬åº«ã€‚"
@@ -31544,6 +31969,9 @@ msgstr "安全與åˆè¦"
msgid "ProjectSettings|Security & Compliance for this project"
msgstr "此專案的安全與åˆè¦"
+msgid "ProjectSettings|Select the default branch for this project, and configure the template for branch names."
+msgstr "é¸æ“‡è©²å°ˆæ¡ˆçš„é è¨­åˆ†æ”¯ï¼Œä¸¦è¨­å®šåˆ†æ”¯å稱的範本。"
+
msgid "ProjectSettings|Set the default behavior of this option in merge requests. Changes to this are also applied to existing merge requests."
msgstr "在åˆä½µè«‹æ±‚中設定此é¸é …çš„é è¨­è¡Œç‚ºã€‚å°æ­¤çš„更改也é©ç”¨æ–¼ç¾æœ‰çš„åˆä½µè«‹æ±‚。"
@@ -31574,6 +32002,9 @@ msgstr "總是執行壓縮 (Squash) ,複é¸æ¡†æ˜¯å¯è¦‹çš„並處於é¸å–ç‹€æ…
msgid "ProjectSettings|Squashing is never performed and the checkbox is hidden."
msgstr "æ°¸é ä¸æœƒåŸ·è¡Œå£“縮 (Squash) ,且該複é¸æ¡†æ˜¯éš±è—的。"
+msgid "ProjectSettings|Status checks must succeed"
+msgstr "狀態檢查必須æˆåŠŸ"
+
msgid "ProjectSettings|Submit changes to be merged upstream."
msgstr "æ交è¦åˆä½µåˆ°ä¸Šæ¸¸çš„更改。"
@@ -31625,6 +32056,9 @@ msgstr "使用者å¯ä»¥å°‡ç‰ˆæœ¬åº«è¤‡è£½åˆ°æ–°å°ˆæ¡ˆã€‚"
msgid "ProjectSettings|Users can only push commits to this repository if the committer email is one of their own verified emails."
msgstr "如果æ交者電å­éƒµä»¶æ˜¯ä»–們自己經éŽé©—證的電å­éƒµä»¶ä¹‹ä¸€ï¼Œä½¿ç”¨è€…åªèƒ½å°‡æ交推é€åˆ°æ­¤å­˜å„²åº«ã€‚"
+msgid "ProjectSettings|Users can only push commits to this repository if the committer name is consistent with their git config username."
+msgstr "使用者的æ交者å稱得與 git config 使用者å稱一致,æ‰èƒ½å°‡æ交推é€åˆ°é€™å€‹å„²å­˜åº«ã€‚"
+
msgid "ProjectSettings|Users can request access"
msgstr "使用者å¯ä»¥è«‹æ±‚å­˜å–"
@@ -32264,6 +32698,9 @@ msgstr "å…許所有具有推é€å­˜å–權é™çš„使用者%{tag_start}強制推é€
msgid "ProtectedBranch|Allow all users with push access to force push."
msgstr "å…許所有具有推é€å­˜å–權é™çš„使用者強制推é€ã€‚"
+msgid "ProtectedBranch|Allowed to create"
+msgstr "å·²å…許建立"
+
msgid "ProtectedBranch|Allowed to force push"
msgstr "å…許強制推é€"
@@ -32300,15 +32737,27 @@ msgstr "é è¨­æƒ…æ³ä¸‹ï¼Œå—ä¿è­·åˆ†æ”¯é™åˆ¶èª°å¯ä»¥ä¿®æ”¹åˆ†æ”¯ã€‚"
msgid "ProtectedBranch|Code owner approval"
msgstr "程å¼ç¢¼æ‰€æœ‰è€…核准"
+msgid "ProtectedBranch|Create wildcard"
+msgstr "建立è¬ç”¨å­—å…ƒ"
+
msgid "ProtectedBranch|Does not apply to users allowed to push. Optional sections are not enforced."
msgstr "ä¸é©ç”¨æ–¼å…許推é€çš„使用者。ä¸å¼·åˆ¶åŸ·è¡Œå¯é¸éƒ¨åˆ†ã€‚"
msgid "ProtectedBranch|Keep stable branches secure and force developers to use merge requests."
msgstr "ä¿æŒç©©å®šçš„分支安全並強制開發人員使用åˆä½µè«‹æ±‚。"
+msgid "ProtectedBranch|Last commit"
+msgstr "上次æ交"
+
msgid "ProtectedBranch|Learn more."
msgstr "了解更多。"
+msgid "ProtectedBranch|New Protected Tag"
+msgstr "æ–°çš„å—ä¿è­·æ¨™ç±¤"
+
+msgid "ProtectedBranch|No tags are protected."
+msgstr "沒有å—ä¿è­·çš„標籤。"
+
msgid "ProtectedBranch|Protect"
msgstr "ä¿è­·"
@@ -32324,12 +32773,21 @@ msgstr "å—ä¿è­·åˆ†æ”¯"
msgid "ProtectedBranch|Protected branches, merge request approvals, and status checks will appear here once configured."
msgstr "å—ä¿è­·çš„分支ã€åˆä½µè«‹æ±‚核准和狀態檢查將在組態設定後顯示於此。"
+msgid "ProtectedBranch|Protected tags (%{tags_count})"
+msgstr "å—ä¿è­·çš„標籤 (%{tags_count})"
+
msgid "ProtectedBranch|Reject code pushes that change files listed in the CODEOWNERS file."
msgstr "拒絕程å¼ç¢¼æŽ¨é€æ›´æ”¹ CODEOWNERS 文件中列出的文件。"
msgid "ProtectedBranch|Require approval from code owners:"
msgstr "需è¦ç¨‹å¼ç¢¼æ‰€æœ‰è€…的核准:"
+msgid "ProtectedBranch|Search protected tags"
+msgstr "查詢å—ä¿è­·çš„標籤"
+
+msgid "ProtectedBranch|Select tag or create wildcard"
+msgstr "é¸æ“‡æ¨™ç±¤æˆ–建立è¬ç”¨å­—å…ƒ"
+
msgid "ProtectedBranch|There are currently no protected branches, protect a branch with the form above."
msgstr "ç›®å‰æ²’有å—ä¿è­·çš„分支,請使用上述表單來ä¿è­·åˆ†æ”¯ã€‚"
@@ -32607,7 +33065,7 @@ msgid "PushRules|Reject any files likely to contain secrets. %{secret_files_link
msgstr "拒絕任何å¯èƒ½åŒ…å« secret 的文件。 %{secret_files_link_start}哪些 secret 文件會被拒絕?%{secret_files_link_end}"
msgid "PushRules|Reject commits that aren't DCO certified"
-msgstr ""
+msgstr "拒絕未經 DCO èªè­‰çš„æ交"
msgid "PushRules|Reject expression in commit messages"
msgstr "æ交訊æ¯ä¸­çš„拒絕表é”å¼"
@@ -32639,6 +33097,9 @@ msgstr "使用者ä»ç„¶å¯ä»¥é€šéŽUI刪除標籤。"
msgid "PushRule|Push rules"
msgstr "推é€è¦å‰‡"
+msgid "PushRule|Reject inconsistent user name"
+msgstr "拒絕ä¸ä¸€è‡´çš„使用者å稱"
+
msgid "PushRule|Reject unverified users"
msgstr "拒絕未經驗證的使用者"
@@ -32673,7 +33134,7 @@ msgid "PushoverService|High priority"
msgstr "高優先級"
msgid "PushoverService|Leave blank for all active devices."
-msgstr "留空為所有啟用設備."
+msgstr "為所有啟用設備留空。"
msgid "PushoverService|Leave blank to use your current user key."
msgstr "留空以使用您當å‰çš„使用者金鑰。"
@@ -32771,12 +33232,6 @@ msgstr "進一步了解"
msgid "Read more about GitLab at %{link_to_promo}."
msgstr "在%{link_to_promo}上閱讀更多關於 GitLab 的訊æ¯ã€‚"
-msgid "Read more about related epics"
-msgstr "閱讀更多關於相關å²è©©çš„訊æ¯"
-
-msgid "Read more about related issues"
-msgstr "了解更多關於相關議題的訊æ¯"
-
msgid "Read their documentation."
msgstr "閱讀他們的文件。"
@@ -32870,9 +33325,6 @@ msgstr "é™ä½Žå°ˆæ¡ˆå¯è¦‹æ€§"
msgid "Reduce risk and triage fewer vulnerabilities with security training"
msgstr "通éŽå®‰å…¨åŸ¹è¨“é™ä½Žé¢¨éšªä¸¦æ¸›å°‘æ¼æ´žé¡žåž‹"
-msgid "Reduce this project’s visibility?"
-msgstr "é™ä½Žæ­¤å°ˆæ¡ˆå¯åº¦å—Žï¼Ÿ"
-
msgid "Reference"
msgstr "åƒè€ƒ"
@@ -33034,6 +33486,9 @@ msgstr[0] "發行"
msgid "Release %{deletedRelease} has been successfully deleted."
msgstr "發佈版本 %{deletedRelease} å·²æˆåŠŸåˆªé™¤ã€‚"
+msgid "Release already exists"
+msgstr "版本已存在"
+
msgid "Release assets"
msgstr "發布資產"
@@ -33043,6 +33498,9 @@ msgstr "發布資產文件"
msgid "Release date"
msgstr "發布日期"
+msgid "Release does not exist"
+msgstr "版本ä¸å­˜åœ¨"
+
msgid "Release does not have the same project as the milestone"
msgstr "發布與里程碑沒有相åŒçš„專案"
@@ -33499,6 +33957,9 @@ msgstr "報告人"
msgid "Reported by %{reporter}"
msgstr "由%{reporter}報告"
+msgid "Reporter"
+msgstr "報告者"
+
msgid "Reporting"
msgstr "報告"
@@ -33512,10 +33973,6 @@ msgid "Reports|%{recentlyFailed} out of %{failed} failed tests has failed more t
msgid_plural "Reports|%{recentlyFailed} out of %{failed} failed tests have failed more than once in the last 14 days"
msgstr[0] "在éŽåŽ»çš„14天中,%{failed}個測試中有%{recentlyFailed}個失敗了一次以上"
-msgid "Reports|Accessibility scanning detected %d issue for the source branch only"
-msgid_plural "Reports|Accessibility scanning detected %d issues for the source branch only"
-msgstr[0] "無障礙性掃æ檢測到%d個僅存在於來æºåˆ†æ”¯çš„å•é¡Œ"
-
msgid "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issue for the source branch only"
msgid_plural "Reports|Accessibility scanning detected %{strong_start}%{number}%{strong_end} issues for the source branch only"
msgstr[0] "無障礙性掃æ檢測到 %{strong_start}%{number}%{strong_end} 個僅é‡å°ä¾†æºåˆ†æ”¯çš„å•é¡Œ"
@@ -33544,18 +34001,12 @@ msgstr "載入報告時發生錯誤"
msgid "Reports|Base report parsing error:"
msgstr "基礎報告分æžéŒ¯èª¤ï¼š"
-msgid "Reports|Classname"
-msgstr "é¡žå"
-
msgid "Reports|Copy failed test names to run locally"
msgstr "複製失敗的測試å稱在本地執行"
msgid "Reports|Copy failed tests"
msgstr "複製失敗的測試"
-msgid "Reports|Execution time"
-msgstr "執行時間"
-
msgid "Reports|Failed %{count} time in %{baseBranch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{baseBranch} in the last 14 days"
msgstr[0] "éŽåŽ»14天中在%{baseBranch}上,失敗了%{count} 次"
@@ -33564,12 +34015,6 @@ msgid "Reports|Failed %{count} time in %{base_branch} in the last 14 days"
msgid_plural "Reports|Failed %{count} times in %{base_branch} in the last 14 days"
msgstr[0] "éŽåŽ»14天中在%{base_branch}上,失敗了%{count} 次"
-msgid "Reports|Failure"
-msgstr "失敗"
-
-msgid "Reports|Filename"
-msgstr "文件å"
-
msgid "Reports|Fixed"
msgstr "固定的"
@@ -33612,21 +34057,12 @@ msgstr "掃æ工具"
msgid "Reports|Severity"
msgstr "åš´é‡ç´šåˆ¥"
-msgid "Reports|System output"
-msgstr "系統輸出"
-
msgid "Reports|Test summary"
msgstr "測試總çµå ±å‘Š"
-msgid "Reports|Test summary failed loading results"
-msgstr "測試摘è¦åœ¨è¼‰å…¥çµæžœæ™‚出錯"
-
msgid "Reports|Test summary failed to load results"
msgstr "測試摘è¦è¼‰å…¥çµæžœå¤±æ•—"
-msgid "Reports|Test summary results are being parsed"
-msgstr "測試摘è¦å ±å‘Šè§£æžä¸­"
-
msgid "Reports|Test summary results are loading"
msgstr "測試摘è¦çµæžœæ­£åœ¨è¼‰å…¥"
@@ -33642,9 +34078,6 @@ msgstr "æ¼æ´žå稱"
msgid "Reports|metrics report"
msgstr "指標報告"
-msgid "Reports|no changed test results"
-msgstr "未發生變化的測試çµæžœ"
-
msgid "Repositories"
msgstr "版本庫"
@@ -33801,7 +34234,7 @@ msgid "Repository mirroring configuration"
msgstr "版本庫é¡åƒè¨­å®š"
msgid "Repository mirroring has been paused due to too many failed attempts. It can be resumed by a project maintainer or owner."
-msgstr ""
+msgstr "版本庫é¡åƒå› å˜—試失敗次數éŽå¤šå·²æš«åœï¼Œå®ƒå¯ä»¥ç”±å°ˆæ¡ˆç¶­è­·è€…或æ“有者æ¢å¾©ã€‚"
msgid "Repository must contain at least 1 file."
msgstr "版本庫必須包å«è‡³å°‘1個文件。"
@@ -34012,6 +34445,9 @@ msgstr "處ç†è€…"
msgid "Resolved by %{name}"
msgstr "已由%{name}解決"
+msgid "Resource link added"
+msgstr "資æºéˆçµå·²åŠ å…¥"
+
msgid "Response"
msgstr "響應"
@@ -34239,6 +34675,9 @@ msgstr "使用 Jenkins 執行 CI/CD æµæ°´ç·šã€‚"
msgid "Run housekeeping"
msgstr "執行例行維護"
+msgid "Run housekeeping tasks to automatically optimize Git repositories. Disabling this option will cause performance to degenerate over time."
+msgstr "執行管ç†ä»»å‹™ä¾†è‡ªå‹•å„ªåŒ– Git 版本庫,åœç”¨è©²é¸é …將導致性能隨著時間的推移而下é™ã€‚"
+
msgid "Run manual or delayed jobs"
msgstr "執行手動或延é²çš„作業"
@@ -34276,6 +34715,9 @@ msgid "Runners|%d selected runner deleted"
msgid_plural "Runners|%d selected runners deleted"
msgstr[0] "已刪除 %d 個é¸å®šçš„執行器"
+msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
+msgstr "%{link_start}這些執行器%{link_end} å¯ç”¨æ–¼æ‰€æœ‰ç¾¤çµ„和專案。"
+
msgid "Runners|%{percentage} spot."
msgstr "%{percentage}點。"
@@ -34302,8 +34744,8 @@ msgstr "啟用"
msgid "Runners|Add notes, like who owns the runner or what it should be used for."
msgstr "增加註釋,例如執行器的æ“有者或執行器的用途。"
-msgid "Runners|Add your feedback in the issue"
-msgstr "在議題中加入您的回饋"
+msgid "Runners|Administrator"
+msgstr "管ç†å“¡"
msgid "Runners|All"
msgstr "全部"
@@ -34433,7 +34875,7 @@ msgid "Runners|Group"
msgstr "群組"
msgid "Runners|How do runners pick up jobs?"
-msgstr ""
+msgstr "執行器如何æ€é¸å·¥ä½œ?"
msgid "Runners|How do we upgrade GitLab runner?"
msgstr "如何å‡ç´š GitLab 執行器?"
@@ -34510,6 +34952,9 @@ msgstr "在線"
msgid "Runners|Online:"
msgstr "在線:"
+msgid "Runners|Owner"
+msgstr "æ“有者"
+
msgid "Runners|Pause from accepting jobs"
msgstr "æš«åœæŽ¥å—作業"
@@ -34548,7 +34993,7 @@ msgid "Runners|Register an instance runner"
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 ""
+msgstr "註冊您期望的任æ„數é‡åŸ·è¡Œå™¨ï¼Œ 您å¯ä»¥åœ¨å€‹åˆ¥çš„伺æœå™¨å’Œæœ¬åœ°æ©Ÿå™¨ä¸Šå°‡åŸ·è¡Œå™¨è¨»å†Šç‚ºå–®ç¨çš„使用者。"
msgid "Runners|Registration token"
msgstr "註冊令牌(權æ–)"
@@ -34632,14 +35077,20 @@ msgid "Runners|Runners"
msgstr "執行器(Runners)"
msgid "Runners|Runners are either:"
-msgstr ""
+msgstr "執行器是:"
msgid "Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner."
msgstr "執行器是é‹è¡Œ CI/CD 作業的代ç†ã€‚按照%{linkStart}安è£å’Œè¨»å†Šèªªæ˜Ž%{linkEnd}來設定執行器。"
+msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
+msgstr "執行器(runner)是執行您 CI/CD 作業的代ç†ï¼Œè¦è¨»å†Šæ–°çš„執行器(runner),請è¯ç¹«æ‚¨çš„管ç†å“¡ã€‚"
+
msgid "Runners|Runs untagged jobs"
msgstr "執行未被標籤的作業"
+msgid "Runners|Select all"
+msgstr "全部é¸å–"
+
msgid "Runners|Select projects to assign to this runner"
msgstr "é¸æ“‡è¦æŒ‡æ´¾çµ¦è©²åŸ·è¡Œå™¨(runner)的專案"
@@ -34647,7 +35098,7 @@ msgid "Runners|Select your preferred option here. In the next step, you can choo
msgstr "執行器|在此處é¸æ“‡æ‚¨çš„首è¦é¸é …。在下一步中,您å¯ä»¥åœ¨ AWS CloudFormation 控制å°ä¸­ç‚ºæ‚¨çš„執行器(runner)é¸æ“‡å®¹é‡ã€‚"
msgid "Runners|Show only inherited"
-msgstr ""
+msgstr "僅顯示已繼承的"
msgid "Runners|Show runner installation and registration instructions"
msgstr "顯示執行器(runner)安è£å’Œè¨»å†Šèªªæ˜Ž"
@@ -34680,7 +35131,7 @@ msgid "Runners|Tags"
msgstr "標籤"
msgid "Runners|Tags control which type of jobs a runner can handle. By tagging a runner, you make sure shared runners only handle the jobs they are equipped to run."
-msgstr ""
+msgstr "標籤å¯ä»¥æŽ§åˆ¶åŸ·è¡Œå™¨è™•ç†çš„作業類型, 通éŽæ¨™ç±¤åŸ·è¡Œå™¨ï¼Œæ‚¨å¯ä»¥ç¢ºä¿å…±äº«åŸ·è¡Œå™¨åƒ…處ç†å®ƒå€‘è£é…執行的作業。"
msgid "Runners|Take me there!"
msgstr "帶我到那裡ï¼"
@@ -34688,6 +35139,9 @@ msgstr "帶我到那裡ï¼"
msgid "Runners|The new view gives you more space and better visibility into your fleet of runners."
msgstr "新檢視表為您在執行器佇列æ供更多空間和更好的å¯è¦‹åº¦ã€‚"
+msgid "Runners|The project, group or instance where the runner was registered. Instance runners are always owned by Administrator."
+msgstr "執行器(runner)所註冊的專案ã€ç¾¤çµ„或實例。實例執行器(runner)始終歸管ç†å“¡æ‰€æœ‰ã€‚"
+
msgid "Runners|The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?"
msgstr "執行器(runner)將被永久刪除,ä¸èƒ½å¤ å†ç”¨æ–¼å¯¦ä¾‹ä¸­çš„專案或群組。您確定è¦ç¹¼çºŒå—Žï¼Ÿ"
@@ -34722,6 +35176,9 @@ msgstr "è¦è¨»å†Šä»–們,請到 %{link_start}CI/CD 執行器群組%{link_end} é
msgid "Runners|Token expiry"
msgstr "權æ–(令牌)到期"
+msgid "Runners|Unselect all"
+msgstr "å–消全é¸"
+
msgid "Runners|Up to date"
msgstr "最新的"
@@ -34761,12 +35218,6 @@ msgstr "版本 %{version}"
msgid "Runners|View installation instructions"
msgstr "檢視安è£èªªæ˜Ž"
-msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!"
-msgstr "我們希望您能夠從該é é¢è¼•é¬†æœ‰æ•ˆåœ°ç®¡ç†æ‚¨çš„執行器,我們正在åšå‡ºæ”¹è®Šä»¥å¯¦ç¾ç›®æ¨™ï¼Œå°±æˆ‘們的表ç¾çµ¦æˆ‘們å饋ï¼"
-
-msgid "Runners|We've made some changes and want your feedback"
-msgstr "我們進行了一些更改並希望得到您的å饋"
-
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr "Windows 2019 Shell,具有手動縮放和å¯é¸æŽ’程的功能。 %{percentage} 點。"
@@ -34821,17 +35272,23 @@ msgstr "SAML探索令牌(權æ–)"
msgid "SAML for %{group_name}"
msgstr "%{group_name} çš„ SAML"
-msgid "SAML|Selecting \"Authorize\" will transfer ownership of your GitLab account \"%{username}\" (%{email}) to your organization."
-msgstr "é¸æ“‡â€œæŽˆæ¬Šâ€æœƒå°‡æ‚¨ GitLab 帳號“%{username}â€ï¼ˆ%{email})的所有權轉移到您的組織。"
+msgid "SAML single sign-on"
+msgstr "SAML 單一登入"
+
+msgid "SAML single sign-on for %{group_name}"
+msgstr "%{group_name} 的 SAML 單一登入"
msgid "SAML|Sign in to GitLab to connect your organization's account"
msgstr "登入 GitLab 以連接您組織的帳號"
-msgid "SAML|The \"%{group_path}\" group allows you to sign in with your Single Sign-On Account."
-msgstr "群組 \"%{group_path}\" å…許您使用SSO登入帳號."
+msgid "SAML|The %{strongOpen}%{group_path}%{strongClose} group allows you to sign in using single sign-on."
+msgstr "%{strongOpen}%{group_path}%{strongClose} 群組å…許您使用單點登入進行登入。"
+
+msgid "SAML|To access %{strongOpen}%{group_name}%{strongClose}, you must sign in using single sign-on through an external sign-in page."
+msgstr "è¦å­˜å– %{strongOpen}%{group_name}%{strongClose},您必須從外部登入é é¢ä½¿ç”¨å–®é»žç™»å…¥é€²è¡Œç™»å…¥ã€‚"
-msgid "SAML|To access \"%{group_name}\" you must sign in with your Single Sign-On account, through an external sign-in page."
-msgstr "è¦å­˜å–“%{group_name}â€ï¼Œæ‚¨å¿…須使用單點登入帳號通éŽå¤–部登入é é¢ç™»å…¥ã€‚"
+msgid "SAML|To allow %{strongOpen}%{group_name}%{strongClose} to manage your GitLab account %{strongOpen}%{username}%{strongClose} (%{email}) after you sign in successfully using single sign-on, select %{strongOpen}Authorize%{strongClose}."
+msgstr "è¦åœ¨æ‚¨ä½¿ç”¨å–®é»žç™»å…¥æˆåŠŸç™»å…¥å¾Œå…許 %{strongOpen}%{group_name}%{strongClose} 管ç†æ‚¨çš„ GitLab %{strongOpen}%{username}%{strongClose} 帳號 (%{email}) ,請é¸æ“‡ %{strongOpen}授權 %{strongClose}。"
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
msgstr "您組織的 SSO 已連接到您的 GitLab 帳號"
@@ -34938,12 +35395,12 @@ msgstr "儲存中"
msgid "Saving project."
msgstr "正在儲存專案。"
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
-msgstr "%{ifLabelStart}å‡è¨­%{ifLabelEnd} %{rules} 動作為 %{scopes} %{branches}"
-
msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
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"
msgstr "%{thenLabelStart}然後%{thenLabelEnd} éœ€è¦ %{scan} 掃ææ‰èƒ½é‹è¡Œ"
@@ -34962,9 +35419,15 @@ msgstr "排程"
msgid "ScanExecutionPolicy|Schedule rule component"
msgstr "排程è¦å‰‡å…ƒä»¶"
+msgid "ScanExecutionPolicy|Select agent"
+msgstr "é¸æ“‡ä»£ç†"
+
msgid "ScanExecutionPolicy|Select branches"
msgstr "é¸æ“‡åˆ†æ”¯"
+msgid "ScanExecutionPolicy|Select namespaces"
+msgstr "é¸æ“‡å‘½å空間"
+
msgid "ScanExecutionPolicy|Select scanner profile"
msgstr "é¸æ“‡æŽƒæ器é…ç½®"
@@ -34974,9 +35437,15 @@ msgstr "é¸æ“‡ç«™é»žé…ç½®"
msgid "ScanExecutionPolicy|Site profile"
msgstr "站點é…ç½®"
+msgid "ScanExecutionPolicy|agent"
+msgstr "代ç†"
+
msgid "ScanExecutionPolicy|branch"
msgstr "分支"
+msgid "ScanExecutionPolicy|in namespaces"
+msgstr "在命å空間中"
+
msgid "ScanResultPolicy|%{ifLabelStart}if%{ifLabelEnd} %{scanners} find(s) more than %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} vulnerabilities in an open merge request targeting %{branches}"
msgstr "%{ifLabelStart}如果%{ifLabelEnd} %{scanners} 在é‡å° %{branches} 的開放åˆä½µè«‹æ±‚中發ç¾è¶…éŽ %{vulnerabilitiesAllowed} %{severities} %{vulnerabilityStates} çš„æ¼æ´ž"
@@ -35089,7 +35558,7 @@ msgid "Search authors"
msgstr "æœå°‹ä½œè€…"
msgid "Search branch"
-msgstr ""
+msgstr "查詢分支"
msgid "Search branches"
msgstr "æœå°‹åˆ†æ”¯"
@@ -35127,9 +35596,6 @@ msgstr "æœå°‹LDAP組"
msgid "Search for a group"
msgstr "æœå°‹ç¾¤çµ„"
-msgid "Search for a user"
-msgstr "æœå°‹ä½¿ç”¨è€…"
-
msgid "Search for an emoji"
msgstr "æœå°‹ emoji"
@@ -35475,13 +35941,13 @@ msgid "SecurityConfiguration|Manage profiles for use by DAST scans."
msgstr "管ç†ä¾› DAST 掃æ使用的設定文件。"
msgid "SecurityConfiguration|More scan types, including DAST, Dependency Scanning, Fuzzing, and Licence Compliance"
-msgstr ""
+msgstr "多種掃æ類型,包括 DASTã€ä¾è³´æ€§æŽƒæã€æ¨¡ç³Šæ¸¬è©¦å’Œè¨±å¯è­‰åˆè¦æ€§"
msgid "SecurityConfiguration|Not enabled"
msgstr "未啟用"
msgid "SecurityConfiguration|Once you've enabled a scan for the default branch, any subsequent feature branch you create will include the scan. An enabled scanner will not be reflected as such until the pipeline has been successfully executed and it has generated valid artifacts."
-msgstr ""
+msgstr "為é è¨­åˆ†æ”¯å•Ÿç”¨æŽƒæ後,您建立的任何後續功能分支都將包å«è©²æŽƒæ。 在æµæ°´ç·šæˆåŠŸåŸ·è¡Œä¸¦ç”¢ç”Ÿæœ‰æ•ˆå·¥ä»¶ä¹‹å‰ï¼Œä¸æœƒå映啟用的掃æ。"
msgid "SecurityConfiguration|Quickly enable all continuous testing and compliance tools by enabling %{linkStart}Auto DevOps%{linkEnd}"
msgstr "%{linkStart}Auto DevOps%{linkEnd}快速啟用所有æŒçºŒæ¸¬è©¦å’Œåˆè¦æ€§å·¥å…·"
@@ -35525,11 +35991,14 @@ msgstr "和"
msgid "SecurityOrchestration| or "
msgstr "或 "
-msgid "SecurityOrchestration|%{branches} %{plural}"
-msgstr "%{branches} %{plural}"
+msgid "SecurityOrchestration|%{agent} for %{namespaces}"
+msgstr "%{agent} 用於 %{namespaces}"
-msgid "SecurityOrchestration|%{branches} and %{lastBranch} %{plural}"
-msgstr "%{branches} 和 %{lastBranch} %{plural}"
+msgid "SecurityOrchestration|%{branches} and %{lastBranch} branches"
+msgstr "%{branches} 與 %{lastBranch} 分支"
+
+msgid "SecurityOrchestration|%{branches} branch"
+msgstr "%{branches} 分支"
msgid "SecurityOrchestration|%{scanners}"
msgstr "%{scanners}"
@@ -35562,7 +36031,7 @@ msgid "SecurityOrchestration|After enabling a group-level policy, this policy au
msgstr "啟用群組級別政策後,該政策自動應用於該群組中的所有專案和å­ç¾¤çµ„。"
msgid "SecurityOrchestration|All policies"
-msgstr "所有政策"
+msgstr "全部政策"
msgid "SecurityOrchestration|An error occurred assigning your security policy project"
msgstr "指派您的安全政策專案時發生錯誤"
@@ -35648,6 +36117,9 @@ msgstr "繼承"
msgid "SecurityOrchestration|Inherited from %{namespace}"
msgstr "繼承自 %{namespace}"
+msgid "SecurityOrchestration|Invalid policy"
+msgstr "無效的政策"
+
msgid "SecurityOrchestration|Invalid policy type"
msgstr "無效的政策類型"
@@ -35750,12 +36222,12 @@ msgstr "掃æçµæžœæ”¿ç­–åªèƒ½ç”±å°ˆæ¡ˆæ‰€æœ‰è€…建立。"
msgid "SecurityOrchestration|Scan result policy"
msgstr "掃æçµæžœæ”¿ç­–"
-msgid "SecurityOrchestration|Scan to be performed %{cadence}"
-msgstr "è¦åŸ·è¡Œçš„掃æ %{cadence}"
-
msgid "SecurityOrchestration|Scan to be performed %{cadence} on the %{branches}"
msgstr "掃æ %{cadence} 在 %{branches} 上執行"
+msgid "SecurityOrchestration|Scan to be performed by the agent named %{agents} %{cadence}"
+msgstr "掃æç”±å為 %{agents} %{cadence} 的代ç†åŸ·è¡Œ"
+
msgid "SecurityOrchestration|Scan to be performed on every pipeline on the %{branches}"
msgstr "在%{branches}上掃ææ¯å€‹æµæ°´ç·š"
@@ -35843,8 +36315,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, and Container 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, DAST, Secret detection, Container scanning, and Dependency scanning."
+msgstr "掃æ執行政策å…許建立在特定時間強制å°ç‰¹å®šåˆ†æ”¯é€²è¡Œå®‰å…¨æŽƒæçš„è¦å‰‡ã€‚支æ´çš„類型是 SASTã€DASTã€Secret 檢測ã€å®¹å™¨æŽƒæ與ä¾è³´é—œä¿‚掃æ。"
msgid "SecurityOrchestration|Use a scan result policy to create rules that ensure security issues are checked before merging a merge request."
msgstr "使用掃æçµæžœæ”¿ç­–建立è¦å‰‡ï¼Œç¢ºä¿åœ¨åˆä½µåˆä½µè«‹æ±‚之å‰æª¢æŸ¥å®‰å…¨å•é¡Œã€‚"
@@ -35859,7 +36331,10 @@ msgid "SecurityOrchestration|a"
msgstr "一個"
msgid "SecurityOrchestration|all branches"
-msgstr "所有分支"
+msgstr "全部分支"
+
+msgid "SecurityOrchestration|all namespaces"
+msgstr "全部命å空間"
msgid "SecurityOrchestration|an"
msgstr "一個"
@@ -35879,12 +36354,21 @@ msgstr "掃æ器發ç¾"
msgid "SecurityOrchestration|the %{branches}"
msgstr "%{branches}"
+msgid "SecurityOrchestration|the %{namespaces} and %{lastNamespace} namespaces"
+msgstr "%{namespaces} å’Œ %{lastNamespace} 命å空間"
+
+msgid "SecurityOrchestration|the %{namespaces} namespace"
+msgstr "%{namespaces} 命å空間"
+
msgid "SecurityOrchestration|vulnerabilities"
msgstr "æ¼æ´ž"
msgid "SecurityOrchestration|vulnerability"
msgstr "æ¼æ´ž"
+msgid "SecurityPolicies|Invalid or empty policy"
+msgstr "政策無效或為空"
+
msgid "SecurityReports|%{count} Selected"
msgstr "å·²é¸å– %{count}"
@@ -35904,7 +36388,10 @@ msgid "SecurityReports|Add projects"
msgstr "加入專案"
msgid "SecurityReports|All activity"
-msgstr "所有活動"
+msgstr "全部活動"
+
+msgid "SecurityReports|All severities"
+msgstr "全部嚴é‡ç´šåˆ¥"
msgid "SecurityReports|Although it's rare to have no vulnerabilities, it can happen. Check your settings to make sure you've set up your dashboard correctly."
msgstr "雖然沒有æ¼æ´žçš„情æ³å¾ˆå°‘見,但它å¯èƒ½æœƒç™¼ç”Ÿã€‚檢查您的設定以確ä¿æ‚¨å·²æ­£ç¢ºè¨­å®šå„€è¡¨æ¿ã€‚"
@@ -36035,6 +36522,9 @@ msgstr "監控的專案"
msgid "SecurityReports|More info"
msgstr "更多訊æ¯"
+msgid "SecurityReports|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr "æ–°æ¼æ´žæ˜¯å®‰å…¨æŽƒæ在åˆä½µè«‹æ±‚中檢測到與é è¨­åˆ†æ”¯ç¾æœ‰æ¼æ´žä¸åŒçš„æ¼æ´žã€‚"
+
msgid "SecurityReports|No activity"
msgstr "無活動"
@@ -36092,6 +36582,9 @@ msgstr "安全報告åªèƒ½ç”±æŽˆæ¬Šçš„使用者存å–。"
msgid "SecurityReports|Security reports help page link"
msgstr "安全報告幫助é é¢é€£çµ"
+msgid "SecurityReports|Security scan results"
+msgstr "安全掃æçµæžœ"
+
msgid "SecurityReports|Security scans have run"
msgstr "安全掃æ已執行"
@@ -36117,7 +36610,7 @@ msgid "SecurityReports|Status"
msgstr "狀態"
msgid "SecurityReports|Still detected"
-msgstr ""
+msgstr "ä»ç„¶æª¢æ¸¬åˆ°"
msgid "SecurityReports|Submit vulnerability"
msgstr "æ交æ¼æ´ž"
@@ -36209,9 +36702,15 @@ msgstr "您的回饋å°æˆ‘們很é‡è¦ï¼æˆ‘們將在一周內å†æ¬¡è©¢å•ã€‚"
msgid "SecurityReports|scanned resources"
msgstr "掃æ資æº"
+msgid "SecurityTraining|Enable security training to learn how to fix vulnerabilities. View security training from selected educational providers relevant to the detected vulnerability."
+msgstr "開啟安全培訓以了解如何修補æ¼æ´žï¼Œå¾žæ‰€é¸æ“‡çš„教育供應商來查看æ¼æ´žåµæ¸¬ç›¸é—œçš„安全培訓。"
+
msgid "SecurityTraining|Primary Training"
msgstr "åˆç´šåŸ¹è¨“"
+msgid "SecurityTraining|Resolve with security training"
+msgstr "é€éŽå®‰å…¨åŸ¹è¨“來解決å•é¡Œ"
+
msgid "SecurityTraining|Training from this partner takes precedence when more than one training partner is enabled."
msgstr "當多個培訓åˆä½œå¤¥ä¼´å•Ÿç”¨æ™‚,來自此åˆä½œå¤¥ä¼´çš„培訓將優先進行。"
@@ -36224,6 +36723,9 @@ msgstr "查看指標"
msgid "See our website for help"
msgstr "查看我們的網站以å–得幫助"
+msgid "See the Geo troubleshooting documentation to learn more: %{docs_url}"
+msgstr "è«‹åƒé–± Geo 疑難排解文件以å–得更多資訊:%{docs_url}"
+
msgid "See the affected projects in the GitLab admin panel"
msgstr "查看 GitLab 管ç†é¢æ¿ä¸­çš„å—影響專案"
@@ -36287,9 +36789,6 @@ msgstr "é¸æ“‡ä¸€å€‹ç¯„本版本庫"
msgid "Select a template type"
msgstr "é¸æ“‡ä¸€å€‹ç¯„本類型"
-msgid "Select a timezone"
-msgstr "é¸æ“‡ä¸€å€‹æ™‚å€"
-
msgid "Select all"
msgstr "é¸æ“‡å…¨éƒ¨"
@@ -36315,7 +36814,7 @@ msgid "Select branches"
msgstr "é¸æ“‡åˆ†æ”¯(s)"
msgid "Select default branch"
-msgstr ""
+msgstr "é¸æ“‡é è¨­åˆ†æ”¯"
msgid "Select due date"
msgstr "設定截止日期"
@@ -36363,7 +36862,7 @@ msgid "Select projects"
msgstr "é¸æ“‡å°ˆæ¡ˆ(s)"
msgid "Select report"
-msgstr ""
+msgstr "é¸æ“‡å ±å‘Š"
msgid "Select reviewer(s)"
msgstr "é¸æ“‡å¯©æ ¸è€…(s)"
@@ -36428,11 +36927,11 @@ msgstr "所é¸æ¨™ç±¤å·²åœ¨ä½¿ç”¨ä¸­ã€‚é¸æ“‡å¦ä¸€å€‹é¸é …。"
msgid "Selecting a GitLab user will add a link to the GitLab user in the descriptions of issues and comments (e.g. \"By %{link_open}@johnsmith%{link_close}\"). It will also associate and/or assign these issues and comments with the selected user."
msgstr "é¸æ“‡GitLab使用者將在議題和留言的æ述中加入指å‘該GitLab使用者的連çµ(例如「由%{link_open}@johnsmith%{link_close}ã€)。它還將這些å•é¡Œå’Œè©•è«–與所é¸ä½¿ç”¨è€…é—œè¯å’Œ/或分派。"
-msgid "Self monitoring"
+msgid "Self-monitoring"
msgstr "自監控"
-msgid "Self monitoring project does not exist"
-msgstr "沒有自監控專案"
+msgid "Self-monitoring project does not exist"
+msgstr "自監控專案ä¸å­˜åœ¨"
msgid "Self-monitoring project does not exist. Please check logs for any error messages"
msgstr "沒有自監控專案。請檢查記錄檔是å¦æœ‰éŒ¯èª¤è¨Šæ¯"
@@ -36443,29 +36942,29 @@ msgstr "å·²æˆåŠŸåˆªé™¤è‡ªç›£æŽ§å°ˆæ¡ˆ"
msgid "Self-monitoring project was not deleted. Please check logs for any error messages"
msgstr "未刪除自監控專案。請檢查記錄檔是å¦æœ‰éŒ¯èª¤è¨Šæ¯"
-msgid "SelfMonitoring|Activate or deactivate instance self monitoring."
-msgstr "啟用或åœç”¨å¯¦ä¾‹è‡ªç›£æ¸¬ã€‚"
+msgid "SelfMonitoring|Activate or deactivate instance self-monitoring."
+msgstr "啟用或åœç”¨å¯¦ä¾‹è‡ªç›£æŽ§ã€‚"
-msgid "SelfMonitoring|Activate self monitoring to create a project to use to monitor the health of your instance."
-msgstr "啟用自監控以建立用於監控實例執行狀æ³çš„專案。"
+msgid "SelfMonitoring|Activate self-monitoring to create a project to use to monitor the health of your instance."
+msgstr "啟用自監控來建立用於監控您實例é‹è¡Œç‹€æ³çš„專案。"
-msgid "SelfMonitoring|Deactivate self monitoring?"
+msgid "SelfMonitoring|Deactivate self-monitoring?"
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|Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?"
+msgstr "åœç”¨è‡ªç›£æŽ§æœƒåˆªé™¤è‡ªç›£æŽ§å°ˆæ¡ˆï¼Œæ‚¨ç¢ºå®šè¦åœç”¨è‡ªç›£æŽ§ä¸¦åˆªé™¤è©²å°ˆæ¡ˆå—Žï¼Ÿ"
-msgid "SelfMonitoring|Self monitoring"
+msgid "SelfMonitoring|Self-monitoring"
msgstr "自監控"
-msgid "SelfMonitoring|Self monitoring is active. Use the %{projectLinkStart}self monitoring project%{projectLinkEnd} to monitor the health of your instance."
-msgstr "自監控已啟用。使用 %{projectLinkStart}自監控專案%{projectLinkEnd} 來監控您的實例執行狀æ³ã€‚"
+msgid "SelfMonitoring|Self-monitoring is active. Use the %{projectLinkStart}self-monitoring project%{projectLinkEnd} to monitor the health of your instance."
+msgstr "自監控處於啟用狀態,使用 %{projectLinkStart}自監控專案%{projectLinkEnd} 來監控您實例的é‹è¡Œç‹€æ³ã€‚"
-msgid "SelfMonitoring|Self monitoring project successfully created."
-msgstr "æˆåŠŸå»ºç«‹äº†è‡ªç›£æ¸¬å°ˆæ¡ˆã€‚"
+msgid "SelfMonitoring|Self-monitoring project successfully created."
+msgstr "å·²æˆåŠŸå»ºç«‹è‡ªç›£æŽ§å°ˆæ¡ˆã€‚"
-msgid "SelfMonitoring|Self monitoring project successfully deleted."
-msgstr "æˆåŠŸåˆªé™¤äº†è‡ªç›£æ¸¬å°ˆæ¡ˆã€‚"
+msgid "SelfMonitoring|Self-monitoring project successfully deleted."
+msgstr "å·²æˆåŠŸåˆªé™¤è‡ªç›£æŽ§å°ˆæ¡ˆã€‚"
msgid "Send"
msgstr "發é€"
@@ -36683,9 +37182,6 @@ msgstr "設定è‰ç¨¿ç‹€æ…‹"
msgid "Set the Ready status"
msgstr "設定就緒狀態"
-msgid "Set the default branch for this project. All merge requests and commits are made against this branch unless you specify a different one."
-msgstr "設定此專案的é è¨­åˆ†æ”¯ã€‚除éžæ‚¨æŒ‡å®šä¸åŒçš„分支,å¦å‰‡æ‰€æœ‰åˆä½µè«‹æ±‚å’Œæ交都是é‡å°æ­¤åˆ†æ”¯é€²è¡Œçš„。"
-
msgid "Set the default expiration time for job artifacts in all projects. Set to %{code_open}0%{code_close} to never expire artifacts by default. If no unit is written, it defaults to seconds. For example, these are all equivalent: %{code_open}3600%{code_close}, %{code_open}60 minutes%{code_close}, or %{code_open}one hour%{code_close}."
msgstr "為所有專案中的作業產物設定é è¨­åˆ°æœŸæ™‚間。é è¨­æƒ…æ³ä¸‹è¨­å®šç‚º %{code_open}0%{code_close} 表示永ä¸éŽæœŸã€‚如果沒有寫入單ä½ï¼Œå‰‡é è¨­ç‚ºç§’。例如,以下都是等價的: %{code_open}3600%{code_close}〠%{code_open}60 minutes%{code_close}或 %{code_open}one hour%{code_close}。"
@@ -36834,9 +37330,6 @@ msgstr "設定"
msgid "Settings|Unable to load the merge request options settings. Try reloading the page."
msgstr "無法載入åˆä½µè«‹æ±‚é¸é …設定。嘗試é‡æ–°è¼‰å…¥é é¢ã€‚"
-msgid "Setup"
-msgstr "設定"
-
msgid "Severity"
msgstr "åš´é‡ç¨‹åº¦"
@@ -36922,7 +37415,7 @@ msgid "Show Pipeline IID"
msgstr "顯示æµæ°´ç·šIID"
msgid "Show all %{issuable_type}."
-msgstr "顯示所有 %{issuable_type}。"
+msgstr "顯示全部 %{issuable_type}。"
msgid "Show all activity"
msgstr "顯示所有活動"
@@ -37090,11 +37583,8 @@ msgstr "顯示所有å²è©©"
msgid "Showing all issues"
msgstr "顯示所有議題"
-msgid "Showing data for workflow items created in this date range. Date range limited to %{maxDateRange} days."
-msgstr "顯示在此日期範åœå…§å»ºç«‹çš„工作æµäº‹é …的資料。日期範åœæœ€å¤š %{maxDateRange} 天。"
-
-msgid "Showing graphs based on events of the last %{timerange} days."
-msgstr "顯示基於最近%{timerange}天的事件的圖表。"
+msgid "Showing data for workflow items completed in this date range. Date range limited to %{maxDateRange} days."
+msgstr "顯示在此日期範åœå…§å®Œæˆçš„工作æµç¨‹é …目資訊,日期範åœé™åˆ¶ç‚º %{maxDateRange} 天。"
msgid "Showing last %{size} of log -"
msgstr "顯示日誌的最後%{size} -"
@@ -37147,8 +37637,8 @@ msgstr "以具有符åˆé›»å­éƒµä»¶åœ°å€çš„使用者身份登入,將電å­éƒµ
msgid "Sign in preview"
msgstr "登入é è¦½"
-msgid "Sign in to \"%{group_name}\""
-msgstr "登入到 \"%{group_name}\""
+msgid "Sign in to %{group_name}"
+msgstr "登入至 %{group_name}"
msgid "Sign in to GitLab"
msgstr "登入到GitLab"
@@ -37162,8 +37652,8 @@ msgstr "é€éŽ2FA程å¼ç¢¼ç™»å…¥"
msgid "Sign in with"
msgstr "登入方å¼"
-msgid "Sign in with Single Sign-On"
-msgstr "使用單一登入(SSO)進行登入"
+msgid "Sign in with single sign-on"
+msgstr "使用單一登入進行登入"
msgid "Sign in with smart card"
msgstr "使用智慧å¡ç™»å…¥"
@@ -37285,9 +37775,6 @@ msgstr "大å°é™åˆ¶"
msgid "Size limit per repository (MB)"
msgstr "æ¯å€‹ç‰ˆæœ¬åº«çš„大å°é™åˆ¶ (MB)"
-msgid "Skip outdated deployment jobs"
-msgstr "è·³éŽå·²éŽæ™‚的部署作業"
-
msgid "Skipped"
msgstr "已跳éŽ"
@@ -37478,7 +37965,7 @@ msgid "Snowplow"
msgstr "Snowplow"
msgid "Soft wrap"
-msgstr ""
+msgstr "Soft wrap (ä¸æ’å…¥æ›è¡Œç¬¦è™Ÿ)"
msgid "Solid"
msgstr "實心"
@@ -37510,6 +37997,9 @@ msgstr "有人與您åŒæ™‚編輯了這一åˆä½µè«‹æ±‚。請é‡æ–°æ•´ç†é é¢æŸ¥
msgid "Someone edited this test case at the same time you did. The description has been updated and you will need to make your changes again."
msgstr "有人在您編輯的åŒæ™‚編輯了這個測試案例。æ述已更新,您需è¦å†æ¬¡é€²è¡Œæ›´æ”¹ã€‚"
+msgid "Someone signed in to your %{host} account from a new location"
+msgstr "有人從新ä½ç½®ç™»å…¥åˆ°æ‚¨çš„ %{host} 帳號"
+
msgid "Someone, hopefully you, has requested to reset the password for your GitLab account on %{link_to_gitlab}."
msgstr "有人(希望是您)è¦æ±‚在 %{link_to_gitlab} 上é‡è¨­æ‚¨çš„ GitLab 帳號的密碼。"
@@ -37621,9 +38111,6 @@ msgstr "å–å¾—æ­¤åˆä½µè«‹æ±‚的環境時發生錯誤,請ç¨å¾Œé‡è©¦ã€‚"
msgid "Something went wrong while fetching the packages list."
msgstr "å–得軟體套件列表時發生錯誤。"
-msgid "Something went wrong while initializing the OpenAPI viewer"
-msgstr "åˆå§‹åŒ–OpenAPI查看器時發生錯誤"
-
msgid "Something went wrong while obtaining the Let's Encrypt certificate."
msgstr "å–å¾—Let's Encrypt憑證時發生錯誤。"
@@ -38054,13 +38541,13 @@ msgid "StarProject|Star"
msgstr "收è—(星號)"
msgid "Starred Projects"
-msgstr "收è—(星號)專案"
+msgstr "收è—(星號)的專案"
msgid "Starred Projects' Activity"
-msgstr "收è—(星號)專案的動態"
+msgstr "已收è—(星號)的專案動態"
msgid "Starred projects"
-msgstr "收è—(星號)專案"
+msgstr "收è—(星號)的專案"
msgid "StarredProjectsEmptyState|Visit a project page and press on a star icon. Then, you can find the project on this page."
msgstr "å­˜å–æŸä¸€å°ˆæ¡ˆé é¢ä¸¦é»žæ“Šæ˜Ÿå½¢åœ–標後å¯ä»¥åœ¨æ­¤é é¢ä¸Šæ‰¾åˆ°è©²å°ˆæ¡ˆã€‚"
@@ -38197,9 +38684,6 @@ msgstr "狀態:"
msgid "Status: %{title}"
msgstr "狀態: %{title}"
-msgid "StatusCheck| %{failed} failed, and %{pending} pending"
-msgstr "%{failed} 個失敗, %{pending} 個待處ç†"
-
msgid "StatusCheck|%{failed} failed"
msgstr "%{failed} 個失敗"
@@ -38212,9 +38696,6 @@ msgstr "API檢查"
msgid "StatusCheck|Add status check"
msgstr "加入狀態檢查"
-msgid "StatusCheck|All passed"
-msgstr "全部通éŽ"
-
msgid "StatusCheck|An error occurred deleting the %{name} status check."
msgstr "刪除 %{name} 狀態檢查時發生錯誤。"
@@ -38236,9 +38717,6 @@ msgstr "外部 API 已被å¦ä¸€å€‹ç‹€æ…‹æª¢æŸ¥ä½¿ç”¨ã€‚"
msgid "StatusCheck|Failed to load status checks"
msgstr "載入狀態檢查失敗"
-msgid "StatusCheck|Failed to load status checks."
-msgstr "無法載入狀態檢查。"
-
msgid "StatusCheck|Invoke an external API as part of the pipeline process."
msgstr "調用外部 API 作為æµæ°´ç·šéŽç¨‹çš„一部分。"
@@ -38758,9 +39236,15 @@ msgstr "鈦黃色"
msgid "SuggestedReviewers|Get suggestions for reviewers based on GitLab's machine learning tool."
msgstr "根據 GitLab 的機器學習工具為審查者æ供建議。"
+msgid "SuggestedReviewers|Learn about suggested reviewers"
+msgstr "了解關於推薦的審查員"
+
msgid "SuggestedReviewers|Suggested reviewers"
msgstr "推薦的審查人員"
+msgid "SuggestedReviewers|Suggested reviewers help link"
+msgstr "推薦審查員的幫助éˆæŽ¥"
+
msgid "SuggestedReviewers|Suggestions appear in the Reviewer section of the right sidebar"
msgstr "建議出ç¾åœ¨å³å´é‚Šæ¬„的審查者å€åŸŸ"
@@ -39017,6 +39501,9 @@ msgstr "切æ›åˆ†æ”¯"
msgid "Switch branch/tag"
msgstr "切æ›åˆ†æ”¯/標籤"
+msgid "Switch editors"
+msgstr "切æ›ç·¨è¼¯å™¨"
+
msgid "Switch to GitLab Next"
msgstr "切æ›åˆ°GitLab é è¦½ç‰ˆ"
@@ -39107,6 +39594,9 @@ msgstr "目錄"
msgid "Tag"
msgstr "標籤"
+msgid "Tag does not exist"
+msgstr "標籤ä¸å­˜åœ¨"
+
msgid "Tag list:"
msgstr "標籤列表:"
@@ -39191,6 +39681,9 @@ msgstr "刪除標籤,您å分確定嗎?"
msgid "TagsPage|Deleting the %{strongStart}%{tagName}%{strongEnd} tag cannot be undone. Are you sure?"
msgstr "刪除 %{strongStart}%{tagName}%{strongEnd} 標籤無法撤消,您確定嗎?"
+msgid "TagsPage|Do you want to create a release with the new tag? You can do that in the %{link_start}New release page%{link_end}."
+msgstr "您想建立一個帶有新標籤的版本嗎?您å¯ä»¥åœ¨ %{link_start}新發布é é¢%{link_end} 中執行該æ“作。"
+
msgid "TagsPage|Edit release"
msgstr "編輯發布版本"
@@ -39212,15 +39705,9 @@ msgstr "åªæœ‰å°ˆæ¡ˆç¶­è­·è€…或æ“有者æ‰èƒ½åˆªé™¤å—ä¿è­·çš„標籤"
msgid "TagsPage|Optionally, add a message to the tag. Leaving this blank creates a %{link_start}lightweight tag.%{link_end}"
msgstr "也å¯ä»¥åŠ å…¥æ¶ˆæ¯åˆ°æ¨™ç±¤ã€‚ä¿ç•™ç©ºç™½å‰‡å»ºç«‹ %{link_start}輕é‡æ¨™ç±¤%{link_end}。"
-msgid "TagsPage|Optionally, create a public Release of your project, based on this tag. Release notes are displayed on the %{releases_page_link_start}Releases%{link_end} page. %{docs_link_start}More information%{link_end}"
-msgstr "或者,根據此標籤建立專案的公開版本。 發行說明顯示在 %{releases_page_link_start}Releases%{link_end} é é¢ä¸Šã€‚ %{docs_link_start}更多訊æ¯%{link_end}"
-
msgid "TagsPage|Please type the following to confirm:"
msgstr "請輸入以下內容進行確èªï¼š"
-msgid "TagsPage|Release notes"
-msgstr "發行說明"
-
msgid "TagsPage|Repository has no tags yet."
msgstr "版本庫還沒有標籤。"
@@ -39242,9 +39729,6 @@ msgstr "無法載入標籤"
msgid "TagsPage|Use git tag command to add a new one:"
msgstr "使用git tag指令加入一個:"
-msgid "TagsPage|Write your release notes or drag files here…"
-msgstr "編寫發行說明(Release Notes)或將文件拖動到此處..."
-
msgid "TagsPage|Yes, delete protected tag"
msgstr "是的,刪除å—ä¿è­·çš„標籤"
@@ -39263,6 +39747,9 @@ msgstr "å·²ä¿è­·"
msgid "Take a look at the documentation to discover all of GitLab’s capabilities."
msgstr "查看文件以了解 GitLab 的所有功能。"
+msgid "Target"
+msgstr "目標"
+
msgid "Target Branch"
msgstr "目標分支"
@@ -39374,14 +39861,6 @@ msgstr "使用 Terraform?嘗試 GitLab 託管 Terraform State"
msgid "Terraform|%{name} successfully removed"
msgstr "%{name} å·²æˆåŠŸç§»é™¤"
-msgid "Terraform|%{number} Terraform report failed to generate"
-msgid_plural "Terraform|%{number} Terraform reports failed to generate"
-msgstr[0] "%{number}個Terraform報告產生失敗"
-
-msgid "Terraform|%{number} Terraform report was generated in your pipelines"
-msgid_plural "Terraform|%{number} Terraform reports were generated in your pipelines"
-msgstr[0] "您的æµæ°´ç·šç”¢ç”Ÿäº†%{number}個Terraform報告"
-
msgid "Terraform|%{strong_start}%{number}%{strong_end} Terraform report failed to generate"
msgid_plural "Terraform|%{strong_start}%{number}%{strong_end} Terraform reports failed to generate"
msgstr[0] "%{strong_start}%{number}%{strong_end} 個 Terraform 報告產生失敗"
@@ -39399,12 +39878,6 @@ msgstr "Terraform 報告產生失敗。"
msgid "Terraform|A Terraform report was generated in your pipelines."
msgstr "在您的æµæ°´ç·šä¸­ç”¢ç”Ÿäº†ä¸€å€‹ Terraform 報告。"
-msgid "Terraform|A report failed to generate."
-msgstr "無法產生報告。"
-
-msgid "Terraform|A report was generated in your pipelines."
-msgstr "在您的æµæ°´ç·šä¸­ç”¢ç”Ÿäº†ä¸€ä»½å ±å‘Šã€‚"
-
msgid "Terraform|Actions"
msgstr "動作"
@@ -39492,12 +39965,6 @@ msgstr "Terraform init 指令"
msgid "Terraform|Terraform reports"
msgstr "Terraform 報告"
-msgid "Terraform|The job %{name} failed to generate a report."
-msgstr "作業 %{name} 產生報告失敗。"
-
-msgid "Terraform|The job %{name} generated a report."
-msgstr "作業 %{name} 產生了一個報告。"
-
msgid "Terraform|The job %{strong_start}%{name}%{strong_end} failed to generate a report."
msgstr "作業 %{strong_start}%{name}%{strong_end} 產生報告失敗。"
@@ -39947,6 +40414,9 @@ msgstr "您的 PlantUML 伺æœå™¨çš„主機å。"
msgid "The hostname of your Snowplow collector."
msgstr "您的 Snowplow 收集器的主機å。"
+msgid "The import cannot be canceled because it is %{project_status}"
+msgstr "匯入無法å–消,因為 %{project_status}"
+
msgid "The import will time out after %{timeout}. For repositories that take longer, use a clone/push combination."
msgstr "該匯入éŽç¨‹å°‡åœ¨ %{timeout} 後逾時。å°æ–¼éœ€è¦é•·æ–¼è©²æ™‚é–“æ‰èƒ½åŒ¯å…¥çš„版本庫,請使用克隆 (Clone) /æŽ¨é€ (Push)組åˆã€‚"
@@ -40142,9 +40612,6 @@ msgstr "版本庫必須能夠通éŽ%{code_open}http://%{code_close}, %{code_open
msgid "The resource that you are attempting to access does not exist or you don't have permission to perform this action."
msgstr "您嘗試存å–的資æºä¸å­˜åœ¨æˆ–您沒有執行該動作的權é™ã€‚"
-msgid "The same shared runner executes code from multiple projects, unless you configure autoscaling with %{link} set to 1 (which it is on GitLab.com)."
-msgstr "åŒä¸€å€‹å…±ç”¨åŸ·è¡Œå™¨åŸ·è¡Œä¾†è‡ªå¤šå€‹å°ˆæ¡ˆçš„程å¼ç¢¼ï¼Œé™¤éžæ‚¨å°‡è‡ªå‹•ç¸®æ”¾è¨­å®šç‚º %{link} 設定為 1(在 GitLab.com 上)。"
-
msgid "The scan has been created."
msgstr "掃瞄已建立。"
@@ -40175,7 +40642,7 @@ msgstr "來æºä¸»é¡Œä¸æ˜¯ä¸€å€‹ä¸»é¡Œã€‚"
msgid "The specified tab is invalid, please select another"
msgstr "指定é ç±¤ç„¡æ•ˆï¼Œè«‹é¸æ“‡å¦ä¸€å€‹"
-msgid "The start date must be ealier than the end date."
+msgid "The start date must be earlier than the end date."
msgstr "開始日期必須早於çµæŸæ—¥æœŸã€‚"
msgid "The subject will be used as the title of the new issue, and the message will be the description. %{quickActionsLinkStart}Quick actions%{quickActionsLinkEnd} and styling with %{markdownLinkStart}Markdown%{markdownLinkEnd} are supported."
@@ -40232,9 +40699,6 @@ msgstr "æ¼æ´žå·²ä¸å†è¢«æª¢æ¸¬åˆ°ã€‚請於更改其狀態å‰ç¢ºä¿æ¼æ´žå·²ä¿®
msgid "Theme"
msgstr "主題"
-msgid "There are currently no events."
-msgstr "當å‰æ²’有事件。"
-
msgid "There are currently no mirrored repositories."
msgstr "當å‰æ²’有已é¡åƒçš„版本庫。"
@@ -40586,9 +41050,6 @@ msgstr "這些ç¾æœ‰çš„議題具有類似的標題。在那裡留言å¯èƒ½æ›´å¥½
msgid "These runners are shared across projects in this group."
msgstr "這些執行器(runners)在該群組中的專案之間共用。"
-msgid "These runners are shared across this GitLab instance."
-msgstr "這些執行器(runners)在此 GitLab 實例中共用。"
-
msgid "These runners are specific to this project."
msgstr "以下這些執行器(runners)為該專案特定。"
@@ -40622,6 +41083,9 @@ msgstr "因為 %{reason}無法顯示 %{viewer} 。您å¯ä»¥æ”¹ç‚º %{options}。"
msgid "This Cron pattern is invalid"
msgstr "æ­¤Cronæ ¼å¼ç„¡æ•ˆ"
+msgid "This Experiment has no logged Candidates"
+msgstr "該實驗沒有登記的候é¸äºº"
+
msgid "This GitLab instance does not provide any shared runners yet. Instance administrators can register shared runners in the admin area."
msgstr "æ­¤ GitLab 實例尚未æ供任何共用執行器(runners)。實例管ç†å“¡å¯ä»¥åœ¨ç®¡ç†å€è¨»å†Šå…±ç”¨åŸ·è¡Œå™¨(runners)。"
@@ -40788,25 +41252,22 @@ msgid "This epic already has the maximum number of child epics."
msgstr "æ­¤å²è©©çš„å­å²è©©æ•¸ç›®å·²é”最大值。"
msgid "This epic cannot be added. An epic cannot be added to itself."
-msgstr ""
-
-msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
-msgstr ""
+msgstr "無法增加該å²è©©ï¼Œå²è©©ä¸èƒ½åŠ å…¥åˆ°è‡ªèº«ã€‚"
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
-msgstr ""
+msgstr "無法增加該å²è©©ï¼Œå²è©©å¿…須與其父å²è©©å±¬æ–¼åŒä¸€ç¾¤çµ„或å­ç¾¤çµ„。"
msgid "This epic cannot be added. It is already an ancestor of the parent epic."
-msgstr ""
+msgstr "無法增加該å²è©©ï¼Œå®ƒå·²ç¶“是其父å²è©©çš„上一層。"
msgid "This epic cannot be added. It is already assigned to the parent epic."
-msgstr ""
+msgstr "無法增加該å²è©©ï¼Œå®ƒå·²åˆ†é…給父å²è©©ã€‚"
msgid "This epic cannot be added. One or more epics would exceed the maximum depth (%{max_depth}) from its most distant ancestor."
-msgstr ""
+msgstr "無法增加該å²è©©ï¼Œä¸€å€‹æˆ–多個å²è©©å°‡è¶…éŽå…¶æœ€ä¸Šå±¤ç¥–先的最大深度 (%{max_depth})。"
msgid "This epic cannot be added. You don't have access to perform this action."
-msgstr ""
+msgstr "無法增加該å²è©©ï¼Œæ‚¨ç„¡æ¬ŠåŸ·è¡Œæ­¤å‹•ä½œã€‚"
msgid "This epic does not exist or you don't have sufficient permission."
msgstr "æ­¤å²è©©ä¸å­˜åœ¨æˆ–者您沒有足夠的權é™ã€‚"
@@ -40853,6 +41314,9 @@ msgstr "此群組已安排在%{date}永久移除"
msgid "This group has no active access tokens."
msgstr "此群組沒有有效的存å–令牌。"
+msgid "This group has no projects yet"
+msgstr "此群組還沒有專案"
+
msgid "This group is linked to a subscription"
msgstr "此群組已連çµåˆ°è¨‚é–±"
@@ -41069,15 +41533,18 @@ msgstr "åˆä½µè«‹æ±‚å·²åˆä½µã€‚è¦æ‡‰ç”¨æ­¤å»ºè­°ï¼Œè«‹ç›´æŽ¥ç·¨è¼¯æ­¤æ–‡ä»¶ã€‚
msgid "This namespace has already been taken! Please choose another one."
msgstr "該命å空間已被使用ï¼è«‹é¸æ“‡å…¶ä»–命å空間。"
+msgid "This namespace has already been taken. Choose a different one."
+msgstr "該命å空間已被使用ï¼è«‹é¸æ“‡å…¶ä»–命å空間。"
+
msgid "This only applies to repository indexing operations."
msgstr "這僅é©ç”¨æ–¼ç‰ˆæœ¬åº«ç´¢å¼•æ“作。"
+msgid "This page is hosted on GitLab pages but contains user-generated content and may contain malicious code. Do not accept unless you trust the author and source."
+msgstr "æ­¤é é¢å­˜æ”¾æ–¼ GitLab Pages,但內å«ä½¿ç”¨è€…撰寫的內容,且å¯èƒ½å«æœ‰æƒ¡æ„程å¼ç¢¼ã€‚除éžæ‚¨ä¿¡ä»»ä½œè€…和來æºï¼Œå¦å‰‡è«‹å‹¿æŽ¥å—。"
+
msgid "This page is unavailable because you are not allowed to read information across multiple projects."
msgstr "該é é¢ä¸å¯ç”¨ï¼Œæ‚¨ç„¡æ¬Šè·¨å°ˆæ¡ˆé–±è®€ç›¸é—œè¨Šæ¯ã€‚"
-msgid "This page sends a payload. Go back to the events page to see a newly created event."
-msgstr "該é é¢ç™¼é€äº†ä¸€å€‹æœ‰æ•ˆè³‡æ–™ã€‚返回事件é é¢æŸ¥çœ‹æ–°å»ºç«‹çš„事件。"
-
msgid "This pipeline makes use of a predefined CI/CD configuration enabled by %{b_open}Auto DevOps.%{b_close}"
msgstr "該æµæ°´ç·šä½¿ç”¨äº†åŒ…å«%{b_open}Auto DevOps%{b_close}çš„é å…ˆå®šç¾©çš„CI/CD設定。"
@@ -41148,7 +41615,7 @@ msgid "This project will be deleted on %{date} since its parent group '%{parent_
msgstr "該專案將於 %{date} 刪除,因為它的父群組 '%{parent_group_name}' 已排入刪除排程。"
msgid "This project's pipeline configuration is located outside this repository"
-msgstr ""
+msgstr "該專案的æµæ°´ç·šçµ„æ…‹ä½æ–¼æ­¤ç‰ˆæœ¬åº«ä¹‹å¤–"
msgid "This release was created with a date in the past. Evidence collection at the moment of the release is unavailable."
msgstr "該發布版本是使用éŽåŽ»çš„日期建立的, 無法在發布時收集證據。"
@@ -41204,9 +41671,6 @@ msgstr "此使用者有一個未經確èªçš„é›»å­éƒµä»¶åœ°å€ã€‚您å¯ä»¥å¼·åˆ¶
msgid "This user has no active %{accessTokenTypePlural}."
msgstr "此用戶沒有啟動的 %{accessTokenTypePlural}。"
-msgid "This user has no active %{type}."
-msgstr "此使用者沒有有效的%{type}。"
-
msgid "This user has no identities"
msgstr "該使用者無身份標識"
@@ -41225,6 +41689,9 @@ msgstr "該使用者是%{noteable}的作者。"
msgid "This variable can not be masked."
msgstr "此變數無法被隱è—。"
+msgid "This vulnerability type has been deprecated from GitLab's default ruleset and automatically resolved."
+msgstr "æ­¤æ¼æ´žé¡žåž‹å·²å¾ž GitLab çš„é è¨­è¦å‰‡é›†ä¸­æ£„用並自動解決。"
+
msgid "This will invalidate your registered applications and U2F / WebAuthn devices."
msgstr "這會使您註冊的應用程å¼å’Œ U2F / WebAuthn 設備無效。"
@@ -41238,7 +41705,7 @@ msgid "This will remove the fork relationship between this project and other pro
msgstr "這將移除此專案與分å‰ç¶²è·¯ä¸­å…¶ä»–專案之間的分å‰é—œä¿‚。"
msgid "Thread options"
-msgstr ""
+msgstr "線程é¸é …"
msgid "Thread to reply to cannot be found"
msgstr "找ä¸åˆ°è¦å›žå¾©çš„主題"
@@ -41593,9 +42060,6 @@ msgstr "è¦æ ¸å‡†è©²åˆä½µè«‹æ±‚,請輸入您的密碼,該專案需è¦å°æ‰€
msgid "To complete registration, we need additional details from you."
msgstr "è¦å®Œæˆè¨»å†Šï¼Œæˆ‘們需è¦æ‚¨æ供更多詳細信æ¯ã€‚"
-msgid "To confirm, type %{phrase_code}"
-msgstr "è¦ç¢ºèªï¼Œè«‹è¼¸å…¥ %{phrase_code}"
-
msgid "To connect GitHub repositories, you can use a %{personal_access_token_link}. When you create your Personal Access Token, you will need to select the %{code_open}repo%{code_close} scope, so we can display a list of your public and private repositories which are available to connect."
msgstr "å¯ä»¥ä½¿ç”¨ %{personal_access_token_link} 連接GitHub版本庫。當建立個人存å–令牌時,需è¦é¸æ“‡%{code_open}repo%{code_close}範åœï¼Œä»¥é¡¯ç¤ºå¯ä¾›é€£æŽ¥çš„公開和ç§æœ‰çš„版本庫列表。"
@@ -41618,7 +42082,7 @@ msgid "To define internal users, first enable new users set to external"
msgstr "è¦å®šç¾©å…§éƒ¨ä½¿ç”¨è€…,請首先啟用設定為外部的新使用者"
msgid "To edit the pipeline configuration, you must go to the project or external site that hosts the file."
-msgstr ""
+msgstr "è¦ç·¨è¼¯æµæ°´ç·šçµ„態,您必須到託管文件的專案或外部站點。"
msgid "To enable Registration Features, first enable Service Ping."
msgstr "è¦å•Ÿç”¨è¨»å†ŠåŠŸèƒ½ï¼Œè«‹å…ˆå•Ÿç”¨ Service Ping。"
@@ -41701,6 +42165,9 @@ msgstr "è¦é‡æ–°å•Ÿç”¨æ‚¨çš„帳號, %{gitlab_link_start}登入到 GitLab。%{
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, you can reduce the number of users in your namespace to %{free_limit} users or less. You can also upgrade to a paid tier, which do not have user limits. If you need additional time, you can start a free 30-day trial which includes unlimited users."
+msgstr "è¦ç§»é™¤%{link_start}唯讀%{link_end}狀態並é‡æ–°å–得寫入權é™ï¼Œæ‚¨å¯ä»¥å°‡å‘½å空間中的使用者數é‡æ¸›å°‘到 %{free_limit} 個使用者或更少。您也å¯ä»¥å‡ç´šåˆ°æ²’有使用者é™åˆ¶çš„付費層級。若您需è¦æ›´å¤šæ™‚間,å¯ä»¥é–‹å§‹30天的å…費試用,其中包å«äº†ç„¡é™ä½¿ç”¨è€…。"
+
msgid "To resolve this, try to:"
msgstr "è¦è§£æ±ºæ­¤å•é¡Œï¼Œè«‹å˜—試:"
@@ -41767,9 +42234,33 @@ msgstr "今日"
msgid "Todos count"
msgstr "待辦事項計數"
+msgid "Todos|Added"
+msgstr "已加入"
+
+msgid "Todos|Alert"
+msgstr "警示"
+
+msgid "Todos|Any Action"
+msgstr "任何動作"
+
+msgid "Todos|Any Type"
+msgstr "任何類型"
+
msgid "Todos|Are you looking for things to do? Take a look at %{strongStart}%{openIssuesLinkStart}open issues%{openIssuesLinkEnd}%{strongEnd}, contribute to %{strongStart}%{mergeRequestLinkStart}a merge request%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd}, or mention someone in a comment to automatically assign them a new to-do item."
msgstr "您正在尋找è¦åšçš„事情嗎? 查看 %{strongStart}%{openIssuesLinkStart}é–‹å•Ÿçš„è­°é¡Œ%{openIssuesLinkEnd}%{strongEnd},貢ç»çµ¦ %{strongStart}%{mergeRequestLinkStart}åˆä½µè«‹æ±‚%{mergeRequestLinkEnd}%{mergeRequestLinkEnd}%{strongEnd},或在留言中æåŠæŸäººï¼Œè‡ªå‹•æŒ‡æ´¾æ–°çš„待辦事項。"
+msgid "Todos|Assigned"
+msgstr "已指派"
+
+msgid "Todos|Could not merge"
+msgstr "無法åˆä½µ"
+
+msgid "Todos|Design"
+msgstr "設計"
+
+msgid "Todos|Epic"
+msgstr "å²è©©"
+
msgid "Todos|Filter by author"
msgstr "ä¾ä½œè€…éŽæ¿¾"
@@ -41791,18 +42282,39 @@ msgstr "此後,您將被稱為“待辦事項毀滅者â€"
msgid "Todos|Isn't an empty To-Do List beautiful?"
msgstr "空的待辦事項列表是ä¸æ˜¯å¾ˆæ¼‚亮?"
+msgid "Todos|Issue"
+msgstr "議題"
+
msgid "Todos|It's how you always know what to work on next."
msgstr "這是您總是知é“下一步è¦åšä»€éº¼çš„æ–¹å¼ã€‚"
msgid "Todos|Mark all as done"
msgstr "標示為全部完æˆ"
+msgid "Todos|Mentioned"
+msgstr "æåŠ"
+
+msgid "Todos|Merge request"
+msgstr "åˆä½µè«‹æ±‚"
+
msgid "Todos|Nothing is on your to-do list. Nice work!"
msgstr "您的待辦事項列表中沒有任何事項。"
msgid "Todos|Nothing left to do. High five!"
msgstr "沒有待辦事項,擊掌慶ç¥ï¼"
+msgid "Todos|Pipelines"
+msgstr "æµæ°´ç·š"
+
+msgid "Todos|Removed from Merge Train:"
+msgstr "已從åˆä½µåˆ—隊中移除:"
+
+msgid "Todos|Review requested"
+msgstr "已請求審核"
+
+msgid "Todos|The pipeline failed in"
+msgstr "æµæ°´ç·šå¤±æ•—æ–¼"
+
msgid "Todos|Undo mark all as done"
msgstr "撤銷標示為全部完æˆ"
@@ -41815,6 +42327,24 @@ msgstr "已經全部完æˆäº†ï¼"
msgid "Todos|Your To-Do List shows what to work on next"
msgstr "您的待辦事項列表顯示下一步è¦åšä»€éº¼"
+msgid "Todos|added a todo for"
+msgstr "已加入待辦事項"
+
+msgid "Todos|mentioned %{who} on"
+msgstr "æåŠ %{who} æ–¼"
+
+msgid "Todos|requested a review of"
+msgstr "審查è¦æ±‚"
+
+msgid "Todos|set %{who} as an approver for"
+msgstr "將 %{who} 設置為核准者"
+
+msgid "Todos|yourself"
+msgstr "您自己"
+
+msgid "Todo|at %{todo_parent_path}"
+msgstr "在 %{todo_parent_path}"
+
msgid "Toggle GitLab Next"
msgstr "切æ›GitLabé è¦½ç‰ˆ"
@@ -41965,9 +42495,6 @@ msgstr "è²¢ç»ç¸½è¨ˆ"
msgid "Total Score"
msgstr "總分"
-msgid "Total artifacts size: %{total_size}"
-msgstr "所有產物大å°ï¼š %{total_size}"
-
msgid "Total cores (CPUs)"
msgstr "總核心數目 (CPUs)"
@@ -42092,7 +42619,7 @@ msgid "Trials|%{planName} Trial"
msgstr "%{planName} 試用"
msgid "Trials|Compare all plans"
-msgstr "比較所有方案"
+msgstr "比較全部方案"
msgid "Trials|Create a new group to start your GitLab Ultimate trial."
msgstr "建立一個新群組以開始您的旗艦版試用。"
@@ -42287,6 +42814,12 @@ msgstr "此使用者已åœç”¨é›™å› å­èªè­‰"
msgid "Two-factor authentication has been disabled for your GitLab account."
msgstr "您的帳號已ç¦ç”¨é›™å› å­èªè­‰"
+msgid "Two-factor authentication has been disabled successfully for %{user_email}!"
+msgstr "已為 %{user_email} æˆåŠŸåœç”¨å…©æ­¥é©Ÿé©—è­‰ï¼"
+
+msgid "Two-factor authentication has been disabled successfully for %{username}!"
+msgstr "已為 %{username} æˆåŠŸåœç”¨å…©æ­¥é©Ÿé©—è­‰ï¼"
+
msgid "Two-factor authentication has been disabled successfully!"
msgstr "雙因å­èªè­‰å·²è¢«æˆåŠŸåœç”¨ï¼"
@@ -42791,6 +43324,12 @@ msgstr "使用趨勢"
msgid "Usage statistics"
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 "容器註冊表的專案級儲存統計訊æ¯åƒ…是定å‘的,ä¸åŒ…括實例範åœé‡è¤‡è³‡æ–™åˆªé™¤æ‰€ä¿ç•™çš„。"
+
+msgid "UsageQuotas|This project-level storage statistic does not include savings for site-wide deduplication and is not used to calculate total namespace storage."
+msgstr "這些專案級儲存統計資料ä¸åŒ…括站點範åœé‡è¤‡è³‡æ–™åˆªé™¤æ‰€ä¿ç•™çš„,並且ä¸ç”¨æ–¼ç¸½å‘½å空間儲存。"
+
msgid "UsageQuota|%{help_link_start}Shared runners%{help_link_end} are disabled, so there are no limits set on pipeline usage"
msgstr "%{help_link_start}共用執行器(Runner)%{help_link_end}å·²åœç”¨ï¼Œæ‰€ä»¥æµæ°´ç·šä½¿ç”¨æ²’有設定é™åˆ¶"
@@ -42893,6 +43432,9 @@ msgstr "已使用的命å空間儲存"
msgid "UsageQuota|No CI minutes usage data available."
msgstr "ç„¡å¯ç”¨çš„ CI 分é˜ä½¿ç”¨è³‡æ–™ã€‚"
+msgid "UsageQuota|No projects to display."
+msgstr "ç„¡å¯é¡¯ç¤ºçš„專案。"
+
msgid "UsageQuota|Packages"
msgstr "軟體套件"
@@ -42923,6 +43465,9 @@ msgstr "é‡æ–°è¨ˆç®—版本庫使用情æ³"
msgid "UsageQuota|Repository"
msgstr "版本庫"
+msgid "UsageQuota|Search"
+msgstr "æœå°‹"
+
msgid "UsageQuota|Seats"
msgstr "席次"
@@ -43504,7 +44049,7 @@ msgid "UserProfile|Star projects to track their progress and show your appreciat
msgstr "給專案加星號以追蹤其進度並表é”您的讚賞。"
msgid "UserProfile|Starred projects"
-msgstr "收è—(星號)專案"
+msgstr "收è—(星號)的專案"
msgid "UserProfile|Subscribe"
msgstr "關注"
@@ -43915,13 +44460,13 @@ msgid "View all environments."
msgstr "查看所有環境。"
msgid "View all groups"
-msgstr "檢視所有群組"
+msgstr "檢視全部群組"
msgid "View all issues"
msgstr "查看所有議題"
msgid "View all projects"
-msgstr "檢視所有專案"
+msgstr "檢視全部專案"
msgid "View blame"
msgstr "查看責任歸屬(blame)"
@@ -43930,7 +44475,7 @@ msgid "View blame prior to this change"
msgstr "在該變更之å‰æª¢è¦–責任歸屬(blame)"
msgid "View card matches"
-msgstr ""
+msgstr "查看符åˆçš„å¡ç‰‡"
msgid "View chart"
msgid_plural "View charts"
@@ -43970,9 +44515,6 @@ msgstr "查看文件@%{commitSha}"
msgid "View full dashboard"
msgstr "查看完整儀表æ¿"
-msgid "View full log"
-msgstr "查看完整日誌"
-
msgid "View group in admin area"
msgstr "在管ç†å€æŸ¥çœ‹ç¾¤çµ„"
@@ -44287,7 +44829,7 @@ msgid "VulnerabilityManagement|invalid issue link or ID"
msgstr "無效的議題連çµæˆ–ID"
msgid "VulnerabilityStatusTypes|All statuses"
-msgstr "所有狀態"
+msgstr "全部狀態"
msgid "VulnerabilityStatusTypes|Confirmed"
msgstr "已確èª"
@@ -44433,6 +44975,9 @@ msgstr "請求/回應"
msgid "Vulnerability|Scanner Provider"
msgstr "掃瞄工具æ供者"
+msgid "Vulnerability|Scanner:"
+msgstr "掃æ器:"
+
msgid "Vulnerability|Security Audit"
msgstr "安全審計"
@@ -44451,6 +44996,9 @@ msgstr "åš´é‡æ€§ï¼š"
msgid "Vulnerability|Status"
msgstr "狀態"
+msgid "Vulnerability|Status:"
+msgstr "狀態:"
+
msgid "Vulnerability|The scanner determined this vulnerability to be a false positive. Verify the evaluation before changing its status. %{linkStart}Learn more about false positive detection.%{linkEnd}"
msgstr "掃瞄器確定此æ¼æ´žç‚ºèª¤å ±ã€‚在更改其狀態之å‰é©—證評估。 %{linkStart}了解有關誤報檢測的更多訊æ¯ã€‚%{linkEnd}"
@@ -44461,7 +45009,7 @@ msgid "Vulnerability|Tool"
msgstr "工具"
msgid "Vulnerability|Tool:"
-msgstr ""
+msgstr "工具:"
msgid "Vulnerability|Training"
msgstr "培訓"
@@ -44586,8 +45134,8 @@ msgstr "我們嘗試於%{expires_on}自動將%{strong}%{namespace_name}%{strong_
msgid "We want to be sure it is you, please confirm you are not a robot."
msgstr "我們è¦ç¢ºå®šæ‚¨æ˜¯ä¸æ˜¯æ©Ÿå™¨äººã€‚"
-msgid "We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes."
-msgstr "æˆ‘å€‘æƒ³è®“æ‚¨çŸ¥é“ %{username} 已被 %{scope} å°éŽ–,因為他們在 %{within_minutes} 分é˜å…§ä¸‹è¼‰äº†è¶…éŽ %{max_project_downloads} 個專案版本庫。"
+msgid "We want to let you know %{username} has exceeded the Git rate limit due to them downloading more than %{max_project_downloads} project %{repositories_text} within %{within_text}."
+msgstr "æˆ‘å€‘æƒ³è®“æ‚¨çŸ¥é“ %{username} 已經超éŽäº† Git 速率é™åˆ¶ï¼Œå› ç‚ºä»–們在 %{within_text} 分é˜å…§ä¸‹è¼‰äº†è¶…éŽ %{max_project_downloads} 專案 %{repositories_text}。"
msgid "We will notify %{inviter} that you declined their invitation to join GitLab. You will stop receiving reminders."
msgstr "我們會通知 %{inviter} 您拒絕了他們加入 GitLab 的邀請。您將ä¸æœƒå†æŽ¥æ”¶æ醒。"
@@ -44628,6 +45176,9 @@ msgstr "WebAuthn設備 (%{length})"
msgid "WebAuthn only works with HTTPS-enabled websites. Contact your administrator for more details."
msgstr "WebAuthnåªæ”¯æ´å•Ÿç”¨äº†HTTPS的網站。您å¯ä»¥è¯çµ¡ç®¡ç†å“¡ç²å¾—更多訊æ¯"
+msgid "WebIDE|Are you sure you want to switch editors? You will lose any unsaved changes."
+msgstr "您確定è¦åˆ‡æ›ç·¨è¼¯å™¨å—Žï¼Ÿæ‚¨å°‡æœƒå¤±åŽ»æ‰€æœ‰æœªå„²å­˜çš„變更。"
+
msgid "WebIDE|Fork project"
msgstr "分å‰ï¼ˆFork)專案"
@@ -44643,12 +45194,24 @@ msgstr "快速且輕鬆地編輯專案中的多個文件。"
msgid "WebIDE|Quickly and easily edit multiple files in your project. Press . to open"
msgstr "快速且輕鬆地編輯專案中的多個文件,按 . 來打開"
+msgid "WebIDE|Ready for something new?"
+msgstr "準備好迎接新事物了嗎?"
+
+msgid "WebIDE|Something went wrong while updating the user preferences. Please see developer console for details."
+msgstr "更新使用者å好設定時發生錯誤,詳情請查看開發者主控å°ã€‚"
+
+msgid "WebIDE|Switch to new Web IDE"
+msgstr "切æ›åˆ°æ–°çš„ Web IDE"
+
msgid "WebIDE|This project does not accept unsigned commits."
msgstr "此專案ä¸æŽ¥å—未簽åçš„æ交。"
msgid "WebIDE|This project does not accept unsigned commits. You can’t commit changes through the Web IDE."
msgstr "此專案ä¸æŽ¥å—未簽åçš„æäº¤ï¼Œæ‚¨ç„¡æ³•é€šéŽ Web IDE æ交更改。"
+msgid "WebIDE|You are invited to experience the new Web IDE."
+msgstr "誠摯邀請您體驗新的 Web IDE。"
+
msgid "WebIDE|You can’t edit files directly in this project. Fork this project and submit a merge request with your changes."
msgstr "您ä¸èƒ½åœ¨é€™å€‹å°ˆæ¡ˆä¸­ç›´æŽ¥ç·¨è¼¯æ–‡ä»¶ï¼Œè«‹åˆ†å‰ï¼ˆFork)這個專案並æ交åˆä½µè«‹æ±‚。"
@@ -44688,6 +45251,9 @@ msgstr "Webhooks"
msgid "Webhooks Help"
msgstr "Webhooks幫助"
+msgid "Webhooks|+ Mask another portion of URL"
+msgstr "+ é®è”½ URL çš„å¦ä¸€éƒ¨åˆ†"
+
msgid "Webhooks|A comment is added to a confidential issue."
msgstr "一æ¢ç•™è¨€è¢«åŠ å…¥åˆ°æ©Ÿå¯†è­°é¡Œã€‚"
@@ -44758,7 +45324,7 @@ msgid "Webhooks|Deployment events"
msgstr "部署事件"
msgid "Webhooks|Do not show sensitive data such as tokens in the UI."
-msgstr ""
+msgstr "ä¸è¦åœ¨ UI 中顯示æ•æ„Ÿæ•¸æ“šï¼Œä¾‹å¦‚權æ–令牌。"
msgid "Webhooks|Enable SSL verification"
msgstr "啟用SSL驗證"
@@ -44776,7 +45342,7 @@ msgid "Webhooks|Go to webhooks"
msgstr "到 webhooks"
msgid "Webhooks|How it looks in the UI"
-msgstr ""
+msgstr "在 UI 中的外觀"
msgid "Webhooks|Issues events"
msgstr "議題事件"
@@ -44785,7 +45351,7 @@ msgid "Webhooks|Job events"
msgstr "作業事件"
msgid "Webhooks|Mask portions of URL"
-msgstr ""
+msgstr "URL 的隱蔽部份"
msgid "Webhooks|Member events"
msgstr "æˆå“¡äº‹ä»¶"
@@ -44802,6 +45368,12 @@ msgstr "推é€äº‹ä»¶"
msgid "Webhooks|Push to the repository."
msgstr "推é€åˆ°ç‰ˆæœ¬åº«ã€‚"
+msgid "Webhooks|Regex such as %{REGEX_CODE} is supported."
+msgstr "æ”¯æ´ %{REGEX_CODE} 等正則表é”å¼ã€‚"
+
+msgid "Webhooks|Regular expression"
+msgstr "正則表é”å¼"
+
msgid "Webhooks|Releases events"
msgstr "發布事件"
@@ -44812,10 +45384,10 @@ msgid "Webhooks|Secret token"
msgstr "Secret 令牌"
msgid "Webhooks|Sensitive portion of URL"
-msgstr ""
+msgstr "URL 的機密部分"
msgid "Webhooks|Show full URL"
-msgstr ""
+msgstr "顯示完整的 URL"
msgid "Webhooks|Subgroup events"
msgstr "å­ç¾¤çµ„事件"
@@ -44829,9 +45401,6 @@ msgstr "Webhook %{help_link_start}連接失敗%{help_link_end},將在 %{retry_
msgid "Webhooks|The webhook failed to connect, and is disabled. To re-enable it, check %{strong_start}Recent events%{strong_end} for error details, then test your settings below."
msgstr "Webhook 連接失敗,已åœç”¨ã€‚è¦é‡æ–°å•Ÿç”¨å®ƒï¼Œè«‹æª¢æŸ¥ %{strong_start}最近的事件%{strong_end} 以å–得錯誤詳細訊æ¯ï¼Œç„¶å¾Œåœ¨ä¸‹æ–¹æ¸¬è©¦æ‚¨çš„設定。"
-msgid "Webhooks|The webhook was triggered more than %{limit} times per minute and is now disabled. To re-enable this webhook, fix the problems shown in %{strong_start}Recent events%{strong_end}, then re-test your settings. %{support_link_start}Contact Support%{support_link_end} if you need help re-enabling your webhook."
-msgstr "Webhook æ¯åˆ†é˜å·²è¢«è§¸ç™¼è¶…éŽ %{limit} 次,ç¾åœ¨å·²è¢«åœç”¨ã€‚è‹¥è¦é‡æ–°å•Ÿç”¨æ­¤ Webhook,請修復在 %{strong_start}最近事件%{strong_end} 中顯示的å•é¡Œï¼Œç„¶å¾Œé‡æ–°æ¸¬è©¦æ‚¨çš„設定。如果您需è¦å¹«åŠ©é‡æ–°å•Ÿç”¨æ‚¨çš„ Webhook,%{support_link_start}è«‹è¯çµ¡æŠ€è¡“支æ´%{support_link_end}。"
-
msgid "Webhooks|Trigger"
msgstr "觸發器"
@@ -44842,10 +45411,10 @@ msgid "Webhooks|URL must be percent-encoded if it contains one or more special c
msgstr "如果 URL 包å«ä¸€å€‹æˆ–多個特殊字元,則必須進行百分號編碼。"
msgid "Webhooks|URL preview"
-msgstr ""
+msgstr "é è¦½ URL:"
-msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token HTTP%{code_end} header."
-msgstr "用於驗證接收到的有效資訊。與 %{code_start}X-Gitlab-Token HTTP%{code_end} 標頭中的請求一起發é€ã€‚"
+msgid "Webhooks|Used to validate received payloads. Sent with the request in the %{code_start}X-Gitlab-Token%{code_end} HTTP header."
+msgstr "用於驗證接收到的內容, 與 %{code_start}X-Gitlab-Token%{code_end} HTTP 標頭中的請求一起發é€ã€‚"
msgid "Webhooks|Webhook disabled"
msgstr "Webhook å·²åœç”¨"
@@ -44856,12 +45425,21 @@ msgstr "Webhook 連接失敗"
msgid "Webhooks|Webhook fails to connect"
msgstr "Webhook 連接失敗"
-msgid "Webhooks|Webhook was automatically disabled"
-msgstr "Webhook 被自動åœç”¨"
+msgid "Webhooks|Webhook rate limit has been reached"
+msgstr "å·²é”到 Webhook 速率é™åˆ¶"
+
+msgid "Webhooks|Webhooks for %{root_namespace} are now disabled because they've been triggered more than %{limit} times per minute. They'll be automatically re-enabled in the next minute."
+msgstr "%{root_namespace} çš„ Webhook 已被ç¦ç”¨ï¼Œå› ç‚ºå®ƒæ¯åˆ†é˜è¢«è§¸ç™¼è¶…éŽ %{limit} 次。 它將在 1 分é˜å¾Œè‡ªå‹•é‡æ–°å•Ÿç”¨ã€‚"
msgid "Webhooks|Wiki page events"
msgstr "Wikié é¢äº‹ä»¶"
+msgid "Webhooks|Wildcard pattern"
+msgstr "è¬ç”¨å­—元樣å¼"
+
+msgid "Webhooks|Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+msgstr "支æ´å¦‚ %{WILDCARD_CODE_STABLE} 或 %{WILDCARD_CODE_PRODUCTION} ç­‰è¬ç”¨å­—元。"
+
msgid "Website"
msgstr "網站"
@@ -44940,6 +45518,9 @@ msgstr "什麼是壓縮 (Squashing)?"
msgid "What templates can I create?"
msgstr "我å¯ä»¥å»ºç«‹ä»€éº¼æ¨£çš„範本?"
+msgid "What variables can I use?"
+msgstr "我å¯ä»¥ä½¿ç”¨å“ªäº›è®Šæ•¸ï¼Ÿ"
+
msgid "What will you use this group for?"
msgstr "您會用這個群組åšä»€éº¼ï¼Ÿ"
@@ -44949,8 +45530,8 @@ msgstr "您想è¦åšä»€éº¼ï¼Ÿ"
msgid "What's new"
msgstr "新的功能"
-msgid "When a deployment job is successful, skip older deployment jobs that are still pending."
-msgstr "部署作業æˆåŠŸæ™‚,跳éŽå°šæœªå®Œæˆçš„舊部署任務。"
+msgid "When a deployment job is successful, prevent older deployment jobs that are still pending."
+msgstr "當部署作業æˆåŠŸå¾Œï¼Œè«‹åœæ­¢ä»ç­‰å¾…中的舊部署作業。"
msgid "When a runner is locked, it cannot be assigned to other projects"
msgstr "當Runner被鎖定時,ä¸èƒ½å°‡å…¶åˆ†é…給其他專案"
@@ -45263,6 +45844,12 @@ msgstr "加入開始日期"
msgid "WorkItem|Add task"
msgstr "增加任務"
+msgid "WorkItem|Add to iteration"
+msgstr "加入到迭代"
+
+msgid "WorkItem|Add to milestone"
+msgstr "加入到里程碑"
+
msgid "WorkItem|Are you sure you want to cancel editing?"
msgstr "您確定è¦å–消編輯嗎?"
@@ -45312,9 +45899,24 @@ msgstr "任務介紹"
msgid "WorkItem|Issue"
msgstr "議題"
+msgid "WorkItem|Iteration"
+msgstr "迭代"
+
msgid "WorkItem|Learn about tasks."
msgstr "了解任務。"
+msgid "WorkItem|Milestone"
+msgstr "里程碑"
+
+msgid "WorkItem|No iteration"
+msgstr "沒有迭代"
+
+msgid "WorkItem|No matching results"
+msgstr "沒有符åˆçš„çµæžœ"
+
+msgid "WorkItem|No milestone"
+msgstr "沒有里程碑"
+
msgid "WorkItem|No tasks are currently assigned. Use tasks to break down this issue into smaller parts."
msgstr "ç›®å‰æœªè¢«æŒ‡æ´¾ä»»å‹™ï¼Œä½¿ç”¨ä»»å‹™å°‡è©²è­°é¡Œæ‹†åˆ†æˆæ›´å°çš„部分。"
@@ -45345,12 +45947,15 @@ msgstr "刪除 %{workItemType} 時發生錯誤,請é‡è©¦ã€‚"
msgid "WorkItem|Something went wrong when deleting the task. Please try again."
msgstr "刪除任務時發生錯誤,請é‡è©¦ã€‚"
+msgid "WorkItem|Something went wrong when fetching iterations. Please try again."
+msgstr "導入迭代時發生錯誤, è«‹å†è©¦ä¸€æ¬¡ã€‚"
+
+msgid "WorkItem|Something went wrong when fetching labels. Please try again."
+msgstr "在æå–標籤時發生錯誤,請å†è©¦ä¸€æ¬¡ã€‚"
+
msgid "WorkItem|Something went wrong when fetching tasks. Please refresh this page."
msgstr "å–得任務時發生錯誤,請刷新該é é¢ã€‚"
-msgid "WorkItem|Something went wrong when fetching the work item. Please try again."
-msgstr "å–得工作項時出ç¾éŒ¯èª¤ï¼Œè«‹å†è©¦ä¸€æ¬¡ã€‚"
-
msgid "WorkItem|Something went wrong when fetching work item types. Please try again"
msgstr "å–得工作項類型時出ç¾éŒ¯èª¤ï¼Œè«‹å†è©¦ä¸€æ¬¡ã€‚"
@@ -45360,6 +45965,9 @@ msgstr "嘗試加入å­é …時發生錯誤,請é‡è©¦ã€‚"
msgid "WorkItem|Something went wrong when trying to create a child. Please try again."
msgstr "嘗試建立å­é …時發生錯誤,請å†è©¦ä¸€æ¬¡ã€‚"
+msgid "WorkItem|Something went wrong while fetching milestones. Please try again."
+msgstr "讀å–里程碑時發生錯誤,請å†è©¦ä¸€æ¬¡ã€‚"
+
msgid "WorkItem|Something went wrong while updating the %{workItemType}. Please try again."
msgstr "æ›´æ–° %{workItemType} 時發生錯誤,請é‡è©¦ã€‚"
@@ -45381,6 +45989,9 @@ msgstr "任務"
msgid "WorkItem|Test case"
msgstr "測試案例"
+msgid "WorkItem|This work item is not available. It either doesn't exist or you don't have permission to view it."
+msgstr "該工作項目無法使用,å¯èƒ½ç‚ºä¸å­˜åœ¨æˆ–您無權查看它。"
+
msgid "WorkItem|Turn off confidentiality"
msgstr "關閉機密性"
@@ -45399,6 +46010,9 @@ msgstr "工作事項"
msgid "WorkItem|Work item"
msgstr "工作項目"
+msgid "WorkItem|Work item not found"
+msgstr "未找到工作項目"
+
msgid "Would you like to create a new branch?"
msgstr "您è¦å»ºç«‹ä¸€å€‹æ–°åˆ†æ”¯å—Žï¼Ÿ"
@@ -45493,6 +46107,9 @@ msgstr "您正在嘗試刪除先å‰å·²æ›´æ–°çš„文件。"
msgid "You are attempting to update a file that has changed since you started editing it."
msgstr "您正在嘗試更新的文件自您開始編輯以來已經發生變更。"
+msgid "You are being redirected away from GitLab"
+msgstr "您將離開 GitLab,é‡æ–°å°Žå‘至其他é é¢"
+
msgid "You are billed if you exceed this number. %{qsrOverageLinkStart}How does billing work?%{qsrOverageLinkEnd}"
msgstr "如果超éŽæ­¤æ•¸å­—,將為您計費。%{qsrOverageLinkStart}計費如何é‹ä½œï¼Ÿ%{qsrOverageLinkEnd}"
@@ -45529,6 +46146,12 @@ msgstr "您無權%{action}一å使用者"
msgid "You are not allowed to approve a user"
msgstr "您無權核准使用者"
+msgid "You are not allowed to create this tag as it is protected."
+msgstr "該標籤已å—ä¿è­·ï¼Œæ‚¨ç„¡æ³•å»ºç«‹ã€‚"
+
+msgid "You are not allowed to download code from this project."
+msgstr "您ä¸èƒ½å¾žè©²å°ˆæ¡ˆä¸‹è¼‰ç¨‹å¼ç¢¼ã€‚"
+
msgid "You are not allowed to log in using password"
msgstr "您ä¸èƒ½ä½¿ç”¨å¯†ç¢¼ç™»å…¥"
@@ -45574,9 +46197,6 @@ msgstr "您以該身份æ›å…¥GitLab:"
msgid "You are trying to upload something other than an image. Please upload a .png, .jpg, .jpeg, .gif, .bmp, .tiff or .ico."
msgstr "您正在嘗試上傳éžåœ–片文件。請上傳.pngã€.jpgã€.jpegã€.gifã€.bmpã€.tiff或.ico。"
-msgid "You are using PostgreSQL %{pg_version_current}, but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. Please upgrade your environment to a supported PostgreSQL version, see %{pg_requirements_url} for details."
-msgstr "您正在使用PostgreSQL %{pg_version_current},但此版本的GitLab需è¦PostgreSQL %{pg_version_minimum}。請將您的環境å‡ç´šåˆ°æ”¯æ´çš„ PostgreSQL版本,詳情請見%{pg_requirements_url}。"
-
msgid "You can %{gitlabLinkStart}resolve conflicts on GitLab%{gitlabLinkEnd} or %{resolveLocallyStart}resolve it locally%{resolveLocallyEnd}."
msgstr "您å¯ä»¥%{gitlabLinkStart}在 GitLab 上解決è¡çª%{gitlabLinkEnd} 或 %{resolveLocallyStart}本機解決%{resolveLocallyEnd}。"
@@ -45677,6 +46297,9 @@ msgstr "您å¯ä»¥åœ¨%{link_start}群組設定%{link_end}中啟用群組存å–令
msgid "You can enable project access token creation in %{link_start}group settings%{link_end}."
msgstr "您å¯ä»¥åœ¨ %{link_start}群組設定%{link_end} 中啟用專案存å–令牌建立。"
+msgid "You can enter up to 280 characters"
+msgstr "您最多å¯ä»¥è¼¸å…¥ 280 個字元"
+
msgid "You can filter by 'days to merge' by clicking on the columns in the chart."
msgstr "您å¯ä»¥é€éŽå–®æ“Šåœ–表中的列來按「åˆä½µå¤©æ•¸ã€é€²è¡ŒéŽæ¿¾ã€‚"
@@ -45749,8 +46372,8 @@ msgstr "您也å¯ä»¥é€šéŽ%{linkStart}Lint%{linkEnd}測試.gitlab-ci.yml."
msgid "You can view the source or %{linkStart}%{cloneIcon} clone the repository%{linkEnd}"
msgstr "您å¯ä»¥æŸ¥çœ‹ä¾†æºç¨‹å¼ç¢¼æˆ–%{linkStart}%{cloneIcon}複製 (Clone) 版本庫%{linkEnd}"
-msgid "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. To get more members an owner of the group can start a trial or upgrade to a paid tier."
-msgstr "您無法å†å¢žåŠ ï¼Œä½†å¯ä»¥ç®¡ç†ç¾æœ‰æˆå“¡ï¼Œä¾‹å¦‚,通éŽåˆªé™¤éžæ´»èºçš„æˆå“¡ä¸¦å°‡å…¶æ›¿æ›ç‚ºæ–°æˆå“¡ã€‚為了å–得更多æˆå“¡ï¼Œç¾¤çµ„çš„æ“有者å¯ä»¥é–‹å§‹è©¦ç”¨æˆ–å‡ç´šåˆ°ä»˜è²»å±¤ç´šã€‚"
+msgid "You can't follow more than %{limit} users. To follow more users, unfollow some others."
+msgstr "您最多åªèƒ½é—œæ³¨ %{limit} 個使用者,è¦é—œæ³¨æ›´å¤šä½¿ç”¨è€…,請å–消關注其他使用者。"
msgid "You cannot %{action} %{state} users."
msgstr "您ä¸èƒ½ %{action} %{state} 使用者。"
@@ -45773,6 +46396,9 @@ msgstr "您無法使用被åœç”¨çš„使用者"
msgid "You cannot impersonate a user who cannot log in"
msgstr "您無法摸擬使用無法登入的使用者"
+msgid "You cannot impersonate a user with an expired password"
+msgstr "您無法冒充密碼éŽæœŸçš„使用者"
+
msgid "You cannot impersonate an internal user"
msgstr "您無法摸擬使用內部的使用者"
@@ -45915,6 +46541,9 @@ msgstr "您沒有足夠的權é™ä¾†å»ºç«‹æ­¤å°ˆæ¡ˆçš„ on-call 排程"
msgid "You have insufficient permissions to manage resource links for this incident"
msgstr "您沒有足夠的權é™ç®¡ç†æ­¤äº‹æ•…的資æºéˆçµ"
+msgid "You have insufficient permissions to manage timeline event tags for this project"
+msgstr "您沒有足夠的權é™ç®¡ç†æ­¤å°ˆæ¡ˆçš„時間線事件標籤"
+
msgid "You have insufficient permissions to manage timeline events for this incident"
msgstr "您沒有足夠的權é™ç®¡ç†æ­¤äº‹æ•…的時間線事件"
@@ -45978,8 +46607,8 @@ msgstr "您必須經éŽé©—è­‰æ‰èƒ½å­˜å–此路徑。"
msgid "You must be logged in to search across all of GitLab"
msgstr "您必須登入æ‰èƒ½åœ¨æ•´å€‹GitLab中進行æœå°‹"
-msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' variable to 'false' in your pipeline configuration or CI/CD settings. If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
-msgstr ""
+msgid "You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. To disable debug trace, set the 'CI_DEBUG_TRACE' and 'CI_DEBUG_SERVICES' variables to 'false' in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must add you to the project with developer permissions or higher."
+msgstr "您必須在關è¯å°ˆæ¡ˆä¸­æœ‰é–‹ç™¼è€…或更高等級的權é™ï¼Œæ‰èƒ½åœ¨å•Ÿç”¨ã€Œé™¤éŒ¯è¿½è¹¤ã€æ™‚檢視作業記錄。若è¦åœç”¨é™¤éŒ¯è¿½è¹¤ï¼Œè«‹åœ¨æµæ°´ç·šçµ„態或 CI/CD 設定中將「CI_DEBUG_TRACEã€å’Œã€ŒCI_DEBUG_SERVICESã€è®Šæ•¸è¨­å®šç‚ºã€Œfalseã€ã€‚如果您需è¦æŸ¥çœ‹ä½œæ¥­è¨˜éŒ„,專案維護者或æ“有者得把你以開發者或更高等級的權é™åŠ é€²å°ˆæ¡ˆç•¶ä¸­ã€‚"
msgid "You must have maintainer access to force delete a lock"
msgstr "å¿…é ˆæ“有維護者權é™æ‰èƒ½å¼·åˆ¶åˆªé™¤éŽ–定"
@@ -46146,9 +46775,6 @@ msgstr "YouTube"
msgid "Your %{group} membership will now expire in %{days}."
msgstr "您的%{group}æˆå“¡è³‡æ ¼å°‡åœ¨%{days}天內到期。"
-msgid "Your %{host} account was signed in to from a new location"
-msgstr "您在%{host}上的帳號已從一個新的ä½ç½®ç™»å…¥"
-
msgid "Your %{spammable_entity_type} has been recognized as spam and has been discarded."
msgstr "您的 %{spammable_entity_type} 已被識別為垃圾郵件並已被丟棄。"
@@ -46260,6 +46886,9 @@ msgstr "您的帳號已被鎖定。"
msgid "Your account uses dedicated credentials for the \"%{group_name}\" group and can only be updated through SSO."
msgstr "您帳號使用群組「%{group_name}ã€çš„專用憑證,並且åªèƒ½é€éŽSSO進行更新。"
+msgid "Your action has been rejected because the namespace storage limit has been reached. For more information, visit %{doc_url}."
+msgstr "您的動作已被拒絕,因為已é”到命å空間儲存é™åˆ¶ã€‚如果需è¦æ›´å¤šè³‡è¨Šï¼Œè«‹é€ è¨ª %{doc_url}。"
+
msgid "Your action succeeded."
msgstr "您的æ“作æˆåŠŸã€‚"
@@ -46376,18 +47005,15 @@ msgstr "您的消æ¯é¡¯ç¤ºæ–¼æ­¤"
msgid "Your name"
msgstr "您的åå­—"
+msgid "Your namespace %{namespace_name} is over the %{free_limit} user limit and has been placed in a read-only state."
+msgstr "您的命å空間 %{namespace_name} 超éŽäº† %{free_limit} 個使用者的é™åˆ¶ï¼Œä¸”被置於唯讀狀態。"
+
msgid "Your new %{accessTokenType}"
msgstr "您的新 %{accessTokenType}"
msgid "Your new %{accessTokenType} has been created."
msgstr "您的新 %{accessTokenType} 已建立。"
-msgid "Your new %{type}"
-msgstr "您的新%{type}"
-
-msgid "Your new access token has been created."
-msgstr "您的新存å–令牌已建立。"
-
msgid "Your new comment"
msgstr "您的新留言"
@@ -46473,6 +47099,9 @@ msgstr "您的更新失敗,拖放到ç¾æœ‰è¨­è¨ˆæ™‚,您必須上傳具有相
msgid "Your username is %{username}."
msgstr "您的使用者å是%{username}。"
+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 "您將永久刪除 %{issuableType} ‘%{strongOpen}%{issuableTitle}%{strongClose}’,為é¿å…資料丟失,請考慮以 %{strongOpen} 關閉該 %{issuableType} %{strongClose} 來代替刪除。一旦刪除,就無法撤消或æ¢å¾©ã€‚"
+
msgid "ZenTaoIntegration|Failed to load ZenTao issue. View the issue in ZenTao, or reload the page."
msgstr "無法載入禪é“(ZenTao)議題。在禪é“(ZenTao)中查看議題,或é‡æ–°è¼‰å…¥é é¢ã€‚"
@@ -46542,9 +47171,6 @@ msgstr "`end_time` ä¸æ‡‰è¶…éŽ `start_time` 後的一個月"
msgid "`start_time` should precede `end_time`"
msgstr "`start_time` 應該在 `end_time` 之å‰"
-msgid "`work_items_hierarchy` feature flag disabled for this project"
-msgstr "該專案ç¦ç”¨äº†â€œwork_items_hierarchyâ€çš„功能標誌"
-
msgid "a deleted user"
msgstr "已刪除的使用者"
@@ -46555,9 +47181,6 @@ msgstr[0] "ç´„%då°æ™‚"
msgid "access:"
msgstr "å­˜å–:"
-msgid "added"
-msgstr "已加入"
-
msgid "added %{emails}"
msgstr "加入了 %{emails}"
@@ -46616,6 +47239,12 @@ msgstr "產物"
msgid "assign yourself"
msgstr "指派給自己"
+msgid "assigned"
+msgstr "已指派"
+
+msgid "assigned you"
+msgstr "已指派給您"
+
msgid "at"
msgstr "æ–¼"
@@ -46625,9 +47254,6 @@ msgstr "至少是報告者角色"
msgid "at least the Reporter role, the author, and assignees"
msgstr "至少是報告者角色ã€ä½œè€…和指派者"
-msgid "at risk"
-msgstr "存在風險"
-
msgid "attach a new file"
msgstr "加入新附件"
@@ -46657,7 +47283,7 @@ msgid "cURL:"
msgstr "cURL:"
msgid "can contain only digits"
-msgstr ""
+msgstr "åªèƒ½åŒ…å«æ•¸å­—"
msgid "can contain only letters of the Base64 alphabet (RFC4648) with the addition of '@', ':' and '.'"
msgstr "åªèƒ½åŒ…å«Base64å­—æ¯è¡¨(RFC4648)中的字æ¯ï¼Œä»¥åŠã€Œ@ã€ã€ã€Œ:ã€å’Œã€Œ.ã€ã€‚"
@@ -46705,7 +47331,13 @@ msgid "cannot be a date in the past"
msgstr "ä¸èƒ½æ˜¯éŽåŽ»çš„日期"
msgid "cannot be added since you've reached your %{free_limit} member limit for %{namespace_name}"
-msgstr ""
+msgstr "無法加入,因為您已é”到 %{namespace_name} çš„ %{free_limit} æˆå“¡é™åˆ¶"
+
+msgid "cannot be associated with a subgroup"
+msgstr "ä¸èƒ½èˆ‡å­ç¾¤çµ„é—œè¯"
+
+msgid "cannot be associated with both a Group and a Project"
+msgstr "ä¸èƒ½åŒæ™‚與群組和專案相關è¯"
msgid "cannot be changed"
msgstr "無法被更改"
@@ -46832,19 +47464,19 @@ msgid "ciReport|API fuzzing"
msgstr "API模糊測試"
msgid "ciReport|All clusters"
-msgstr "所有å¢é›†"
+msgstr "全部å¢é›†"
msgid "ciReport|All images"
-msgstr "所有圖åƒ"
+msgstr "全部映åƒ"
msgid "ciReport|All projects"
-msgstr "所有專案"
+msgstr "全部專案"
msgid "ciReport|All severities"
msgstr "全部嚴é‡ç´šåˆ¥"
msgid "ciReport|All tools"
-msgstr "所有工具"
+msgstr "全部工具"
msgid "ciReport|Analyze a deployed version of your web application for known vulnerabilities by examining it from the outside in. DAST works by simulating external attacks on your application while it is running."
msgstr "通éŽç”±å¤–å‘內檢查 Web 應用程å¼çš„已部署版本來分æžå·²çŸ¥æ¼æ´žã€‚DAST 的工作原ç†æ˜¯åœ¨æ‡‰ç”¨ç¨‹å¼é‹è¡Œæ™‚模擬å°æ‡‰ç”¨ç¨‹å¼çš„外部攻擊。"
@@ -46936,12 +47568,27 @@ msgstr "ä¾è³´é …掃æå¯ä»¥æª¢æ¸¬åŽŸå§‹ç¢¼ä¾è³´é …中已知的æ¼æ´žã€‚"
msgid "ciReport|Dependency scanning"
msgstr "ä¾è³´é …掃æ"
+msgid "ciReport|Detects known vulnerabilities in your source code's dependencies."
+msgstr "檢測程å¼ç¢¼ä¾è³´é—œä¿‚中的已知æ¼æ´žã€‚"
+
+msgid "ciReport|Detects known vulnerabilities in your source code."
+msgstr "檢測程å¼ç¢¼ä¸­çš„已知æ¼æ´žã€‚"
+
+msgid "ciReport|Detects known vulnerabilities in your web application."
+msgstr "檢視您的網路應用程å¼ä¸­çš„已知æ¼æ´žã€‚"
+
+msgid "ciReport|Detects secrets and credentials vulnerabilities in your source code."
+msgstr "檢測程å¼ç¢¼ä¸­çš„機密與憑證æ¼æ´žã€‚"
+
msgid "ciReport|Download patch to resolve"
msgstr "下載補ä¸ä»¥è§£æ±º"
msgid "ciReport|Download the patch to apply it manually"
msgstr "下載補ä¸ä»¥æ‰‹å‹•æ‡‰ç”¨"
+msgid "ciReport|Dynamic Application Security Testing (DAST)"
+msgstr "動態應用程å¼å®‰å…¨æ¸¬è©¦ (DAST)"
+
msgid "ciReport|Dynamic Application Security Testing (DAST) detects known vulnerabilities in your web application."
msgstr "動態應用程å¼å®‰å…¨æ¸¬è©¦ï¼ˆDAST)å¯æª¢æ¸¬Web應用程å¼ä¸­çš„已知æ¼æ´žã€‚"
@@ -46964,7 +47611,7 @@ msgid "ciReport|Full Report"
msgstr "完整報告"
msgid "ciReport|Generic Report"
-msgstr ""
+msgstr "一般性報告"
msgid "ciReport|IaC Scanning"
msgstr "IaC 掃æ"
@@ -47015,6 +47662,9 @@ msgstr "已手動增加"
msgid "ciReport|New"
msgstr "新增"
+msgid "ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch."
+msgstr "æ–°æ¼æ´žæ˜¯å®‰å…¨æŽƒæ在åˆä½µè«‹æ±‚中檢測到與é è¨­åˆ†æ”¯ç¾æœ‰æ¼æ´žä¸åŒçš„æ¼æ´žã€‚"
+
msgid "ciReport|No changes to Code Quality."
msgstr "程å¼ç¢¼è³ªé‡(Code Quality)無變化。"
@@ -47045,6 +47695,9 @@ msgstr "Secret 檢測"
msgid "ciReport|Security reports failed loading results"
msgstr "安全報告載入çµæžœå¤±æ•—"
+msgid "ciReport|Security scan results"
+msgstr "安全掃æçµæžœ"
+
msgid "ciReport|Security scanning"
msgstr "安全掃æ"
@@ -47060,6 +47713,9 @@ msgstr "顯示 %{fetchedItems} 項,共 %{totalItems}項"
msgid "ciReport|Solution"
msgstr "解決方案"
+msgid "ciReport|Static Application Security Testing (SAST)"
+msgstr "éœæ…‹æ‡‰ç”¨ç¨‹å¼å®‰å…¨æ¸¬è©¦ (SAST)"
+
msgid "ciReport|Static Application Security Testing (SAST) detects known vulnerabilities in your source code."
msgstr "éœæ…‹æ‡‰ç”¨ç¨‹å¼å®‰å…¨æ¸¬è©¦ï¼ˆSAST)å¯ä»¥æª¢æ¸¬åŽŸå§‹ç¢¼ä¸­å·²çŸ¥çš„æ¼æ´žã€‚"
@@ -47133,6 +47789,9 @@ msgstr "æ交 %{commit_id}"
msgid "committed"
msgstr "å·²æ交"
+msgid "complete"
+msgstr "完æˆ"
+
msgid "compliance violation has already been recorded"
msgstr "é•è¦è¡Œç‚ºå·²è¢«è¨˜éŒ„"
@@ -47191,6 +47850,9 @@ msgstr[0] "天"
msgid "days"
msgstr "天(s) "
+msgid "default"
+msgstr "é è¨­"
+
msgid "default branch"
msgstr "é è¨­åˆ†æ”¯"
@@ -47344,6 +48006,9 @@ msgid "from %d job"
msgid_plural "from %d jobs"
msgstr[0] "來自%d個作業"
+msgid "from yourself"
+msgstr "從您自己"
+
msgid "frontmatter"
msgstr "å‰æ²¿(frontmatter)"
@@ -47442,12 +48107,18 @@ msgstr "內部說明"
msgid "invalid milestone state `%{state}`"
msgstr "無效的里程碑狀態 `%{state}`"
+msgid "invalidated"
+msgstr "無效"
+
msgid "is"
msgstr "是"
msgid "is already associated to a GitLab Issue. New issue will not be associated."
msgstr "已經與一個GitLab議題關è¯ã€‚新的議題將ä¸æœƒè¢«é—œè¯ã€‚"
+msgid "is already linked to this vulnerability"
+msgstr "已與該æ¼æ´žç›¸é—œè¯"
+
msgid "is an invalid IP address range"
msgstr "是無效的 IP ä½å€ç¯„åœ"
@@ -47469,6 +48140,9 @@ msgstr "ä¸æ˜¯"
msgid "is not a descendant of the Group owning the template"
msgstr "ä¸æ˜¯æ“有範本的群組å­æˆå“¡"
+msgid "is not a valid URL."
+msgstr "ä¸æ˜¯ä¸€å€‹æœ‰æ•ˆçš„ URL。"
+
msgid "is not a valid X509 certificate."
msgstr "ä¸æ˜¯æœ‰æ•ˆçš„X509憑證。"
@@ -47493,12 +48167,18 @@ msgstr "ä¸åœ¨å¼·åˆ¶åŸ·è¡Œç¾¤çµ„託管帳號的群組中"
msgid "is not in the member group"
msgstr "ä¸åœ¨æˆå“¡ç¾¤çµ„中"
+msgid "is not one of"
+msgstr "ä¸æ˜¯å…¶ä¸­ä¹‹ä¸€"
+
msgid "is not the member project"
msgstr "ä¸åœ¨æˆå“¡å°ˆæ¡ˆ"
msgid "is not valid. The iteration group has to match the iteration cadence group."
msgstr "無效。迭代群組必須與迭代週期群組符åˆã€‚"
+msgid "is one of"
+msgstr "其中之一"
+
msgid "is read-only"
msgstr "是唯讀"
@@ -47652,9 +48332,6 @@ msgstr "使用åˆä½µè«‹æ±‚å‘您的專案æ出更改建議並與您的團隊討
msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}"
msgstr "%{boldHeaderStart}此處沒有æµæ°´ç·šã€‚%{boldHeaderEnd}"
-msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities."
-msgstr "mrWidget|%{linkStart}ç¾åœ¨è¨­å®š%{linkEnd} 來分æžæ‚¨çš„原始碼中已知的安全æ¼æ´žã€‚"
-
msgid "mrWidget|%{mergeError}."
msgstr "%{mergeError}。"
@@ -47801,6 +48478,9 @@ 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 "åˆä½µå·²å—阻:必須解決所有主題。"
@@ -47897,9 +48577,6 @@ msgstr "在新的åˆä½µè«‹æ±‚中還原 (Revert) 該åˆä½µè«‹æ±‚"
msgid "mrWidget|Revoke approval"
msgstr "撤銷核准"
-msgid "mrWidget|SAST and Secret Detection is not enabled."
-msgstr "SAST和Secret檢測未啟用。"
-
msgid "mrWidget|Set by %{merge_author} to be added to the merge train when the pipeline succeeds"
msgstr "ç”±%{merge_author}設定為在æµæ°´ç·šæˆåŠŸæ™‚加入到åˆä½µä½‡åˆ—中"
@@ -47963,6 +48640,9 @@ msgstr "必須在開始之後"
msgid "must be an email you have verified"
msgstr "必須是您已驗證的電å­éƒµä»¶"
+msgid "must be associated with a Group or a Project"
+msgstr "必須與群組或專案相關è¯"
+
msgid "must be greater than start date"
msgstr "必須大於開始日期"
@@ -47975,9 +48655,15 @@ msgstr "å¿…é ˆå°æ–¼ %{tag_limit} 個標籤的數é‡é™åˆ¶"
msgid "must be set for a project namespace"
msgstr "必須為專案命å空間設定"
+msgid "must be top-level namespace"
+msgstr "必須是最高層級命å空間"
+
msgid "must be unique by status and elapsed time within a policy"
msgstr "必須在政策中的狀態和經éŽæ™‚間上是唯一的"
+msgid "must belong to same project of the work item."
+msgstr "必須屬於該工作項目的åŒä¸€å°ˆæ¡ˆã€‚"
+
msgid "must have a repository"
msgstr "必須有一個版本庫"
@@ -47996,9 +48682,6 @@ msgstr "我的頻é“"
msgid "my-topic"
msgstr "我的主題"
-msgid "need attention"
-msgstr "需è¦é—œæ³¨"
-
msgid "needs to be between 10 minutes and 1 month"
msgstr "需è¦åœ¨10分é˜è‡³1個月之間"
@@ -48047,9 +48730,6 @@ msgstr "%{item}, %{nextItem}"
msgid "nounSeries|%{item}, and %{lastItem}"
msgstr "%{item},和 %{lastItem}"
-msgid "on track"
-msgstr "如期進行"
-
msgid "only %{parent_types} can be parent of Task."
msgstr "åªæœ‰ %{parent_types} å¯ä»¥æ˜¯ Task 的父級。"
@@ -48068,16 +48748,15 @@ msgstr "或"
msgid "organizations can only be added to root groups"
msgstr "組織åªèƒ½è¢«åŠ å…¥åˆ°æ ¹(root)群組"
-msgid "out of %d total test"
-msgid_plural "out of %d total tests"
-msgstr[0] "於總計%d個測試中"
-
msgid "packages"
msgstr "軟體套件"
msgid "pages"
msgstr "Pages"
+msgid "params is empty"
+msgstr "åƒæ•¸ç‚ºç©º"
+
msgid "parent"
msgid_plural "parents"
msgstr[0] "父級"
@@ -48204,9 +48883,6 @@ msgstr "移除開始日期"
msgid "remove weight"
msgstr "移除權é‡"
-msgid "removed"
-msgstr "已移除"
-
msgid "removed a %{link_type} link"
msgstr "移除了一個 %{link_type} éˆçµ"
@@ -48226,12 +48902,19 @@ msgstr "回復應與最上層註釋具有相åŒçš„機密性"
msgid "repositories"
msgstr "版本庫"
+msgid "repository"
+msgid_plural "repositories"
+msgstr[0] "版本庫"
+
msgid "repository:"
msgstr "版本庫:"
msgid "role's base access level does not match the access level of the membership"
msgstr "基於角色的存å–等級ä¸åŒ¹é…æˆå“¡çš„å­˜å–等級"
+msgid "running"
+msgstr "執行中"
+
msgid "satisfied"
msgstr "滿足"
@@ -48354,7 +49037,7 @@ msgid "suggestPipeline|We’re adding a GitLab CI configuration file to add a pi
msgstr "我們正在加入GitLab CI設定文件,以將æµæ°´ç·šåŠ å…¥åˆ°å°ˆæ¡ˆä¸­ã€‚您也å¯ä»¥æ‰‹å‹•å»ºç«‹ï¼Œä½†æˆ‘們建議您從一個立å³å¯ç”¨çš„GitLab範本開始。"
msgid "supported SSH public key."
-msgstr ""
+msgstr "已支æ´çš„ SSH 公鑰。"
msgid "tag name"
msgstr "標籤å稱"
@@ -48386,6 +49069,9 @@ msgstr "此文件"
msgid "time summary"
msgstr "時間總計"
+msgid "to yourself"
+msgstr "給自己"
+
msgid "today"
msgstr "今天"
@@ -48520,6 +49206,9 @@ msgstr "å°‡éŽæœŸæ™‚間維æŒåœ¨ %{old_expiry} ä¸è®Š"
msgid "yaml invalid"
msgstr "yaml 無效"
+msgid "you"
+msgstr "您"
+
msgid "your GitLab instance"
msgstr "您的 GitLab 實例"
diff --git a/package.json b/package.json
index 667b423bad0..7b28a3d557b 100644
--- a/package.json
+++ b/package.json
@@ -38,8 +38,9 @@
"markdownlint:no-trailing-spaces:fix": "yarn run markdownlint:no-trailing-spaces --fix",
"postinstall": "node ./scripts/frontend/postinstall.js",
"storybook:install": "yarn --cwd ./storybook install",
- "storybook:build": "yarn --cwd ./storybook build",
+ "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"
@@ -52,14 +53,14 @@
"@codesandbox/sandpack-client": "^1.2.2",
"@gitlab/at.js": "1.5.7",
"@gitlab/favicon-overlay": "2.0.0",
- "@gitlab/svgs": "3.5.0",
- "@gitlab/ui": "46.1.0",
+ "@gitlab/svgs": "3.8.0",
+ "@gitlab/ui": "49.10.0",
"@gitlab/visual-review-tools": "1.7.3",
- "@gitlab/web-ide": "0.0.1-dev-20220815034418",
+ "@gitlab/web-ide": "0.0.1-dev-20221114183058",
"@rails/actioncable": "6.1.4-7",
"@rails/ujs": "6.1.4-7",
"@sentry/browser": "5.30.0",
- "@sourcegraph/code-host-integration": "0.0.60",
+ "@sourcegraph/code-host-integration": "0.0.84",
"@tiptap/core": "^2.0.0-beta.182",
"@tiptap/extension-blockquote": "^2.0.0-beta.29",
"@tiptap/extension-bold": "^2.0.0-beta.28",
@@ -72,6 +73,7 @@
"@tiptap/extension-gapcursor": "^2.0.0-beta.38",
"@tiptap/extension-hard-break": "^2.0.0-beta.33",
"@tiptap/extension-heading": "^2.0.0-beta.29",
+ "@tiptap/extension-highlight": "^2.0.0-beta.35",
"@tiptap/extension-history": "^2.0.0-beta.25",
"@tiptap/extension-horizontal-rule": "^2.0.0-beta.36",
"@tiptap/extension-image": "^2.0.0-beta.30",
@@ -105,7 +107,7 @@
"codesandbox-api": "0.0.23",
"compression-webpack-plugin": "^5.0.2",
"copy-webpack-plugin": "^6.4.1",
- "core-js": "^3.25.5",
+ "core-js": "^3.26.1",
"cron-validator": "^1.1.1",
"cronstrue": "^1.122.0",
"cropper": "^2.3.0",
@@ -116,7 +118,7 @@
"dateformat": "^5.0.1",
"deckar01-task_list": "^2.3.1",
"diff": "^3.4.0",
- "dompurify": "^2.4.0",
+ "dompurify": "^2.4.1",
"dropzone": "^4.2.0",
"editorconfig": "^0.15.3",
"emoji-regex": "^10.0.0",
@@ -218,7 +220,7 @@
"cheerio": "^1.0.0-rc.9",
"commander": "^2.20.3",
"custom-jquery-matchers": "^2.1.0",
- "eslint": "8.25.0",
+ "eslint": "8.26.0",
"eslint-import-resolver-jest": "3.0.2",
"eslint-import-resolver-webpack": "0.13.2",
"eslint-plugin-import": "^2.26.0",
@@ -236,7 +238,6 @@
"jest-environment-jsdom": "^27.5.1",
"jest-jasmine2": "^27.5.1",
"jest-junit": "^12.0.0",
- "jest-raw-loader": "^1.0.1",
"jest-util": "^27.5.1",
"jsonlint": "^1.6.3",
"markdownlint-cli": "0.32.2",
@@ -251,6 +252,7 @@
"purgecss-from-html": "^4.0.3",
"sass": "^1.49.9",
"stylelint": "^14.9.1",
+ "swagger-cli": "^4.0.4",
"timezone-mock": "^1.0.8",
"webpack-dev-server": "4.11.1",
"xhr-mock": "^2.5.1",
diff --git a/qa/Dockerfile b/qa/Dockerfile
index 341732ab56f..7f236a25288 100644
--- a/qa/Dockerfile
+++ b/qa/Dockerfile
@@ -1,8 +1,9 @@
ARG DOCKER_VERSION=20.10.14
-ARG CHROME_VERSION=103
+ARG CHROME_VERSION=106
ARG QA_BUILD_TARGET=qa
+ARG RUBY_VERSION=2.7
-FROM registry.gitlab.com/gitlab-org/gitlab-build-images/debian-bullseye-ruby-2.7:bundler-2.3-git-2.33-lfs-2.9-chrome-${CHROME_VERSION}-docker-${DOCKER_VERSION}-gcloud-383-kubectl-1.23 AS qa
+FROM registry.gitlab.com/gitlab-org/gitlab-build-images/debian-bullseye-ruby-${RUBY_VERSION}:bundler-2.3-git-2.36-lfs-2.9-chrome-${CHROME_VERSION}-docker-${DOCKER_VERSION}-gcloud-383-kubectl-1.23 AS qa
LABEL maintainer="GitLab Quality Department <quality@gitlab.com>"
ENV DEBIAN_FRONTEND="noninteractive"
diff --git a/qa/Gemfile b/qa/Gemfile
index 12e5d66fc6b..b84a22883d1 100644
--- a/qa/Gemfile
+++ b/qa/Gemfile
@@ -2,31 +2,30 @@
source 'https://rubygems.org'
-gem 'gitlab-qa', '~> 8', '>= 8.8.0', require: 'gitlab/qa'
+gem 'gitlab-qa', '~> 8', '>= 8.11.0', require: 'gitlab/qa'
gem 'activesupport', '~> 6.1.4.7' # This should stay in sync with the root's Gemfile
-gem 'allure-rspec', '~> 2.18.0'
-gem 'capybara', '~> 3.37.1'
+gem 'allure-rspec', '~> 2.19.0'
+gem 'capybara', '~> 3.38.0'
gem 'capybara-screenshot', '~> 1.0.26'
-gem 'rake', '~> 13'
-gem 'rspec', '~> 3.11'
-gem 'selenium-webdriver', '~> 4.5'
+gem 'rake', '~> 13', '>= 13.0.6'
+gem 'rspec', '~> 3.12'
+gem 'selenium-webdriver', '~> 4.6', '>= 4.6.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.1', require: 'rspec/retry'
+gem 'rspec-retry', '~> 0.6.2', require: 'rspec/retry'
gem 'rspec_junit_formatter', '~> 0.6.0'
-gem 'faker', '~> 2.23'
+gem 'faker', '~> 3.0'
gem 'knapsack', '~> 4.0'
-gem 'parallel_tests', '~> 3.13'
-gem 'rotp', '~> 6.2.0'
-gem 'timecop', '~> 0.9.5'
-gem 'parallel', '~> 1.19'
-gem 'rainbow', '~> 3.0.0'
+gem 'parallel_tests', '~> 4.0'
+gem 'rotp', '~> 6.2.1'
+gem 'parallel', '~> 1.22', '>= 1.22.1'
+gem 'rainbow', '~> 3.1.1'
gem 'rspec-parameterized', '~> 0.5.2'
-gem 'octokit', '~> 5.6.1'
+gem 'octokit', '~> 6.0.0'
gem "faraday-retry", "~> 2.0"
gem 'webdrivers', '~> 5.2'
gem 'zeitwerk', '~> 2.4'
-gem 'influxdb-client', '~> 1.17'
+gem 'influxdb-client', '~> 2.8'
gem 'terminal-table', '~> 3.0.2', require: false
gem 'slack-notifier', '~> 2.4', require: false
gem 'fog-google', '~> 1.19', require: false
@@ -36,7 +35,7 @@ gem "warning", "~> 1.3"
gem 'confiner', '~> 0.3'
gem 'chemlab', '~> 0.10'
-gem 'chemlab-library-www-gitlab-com', '~> 0.1'
+gem 'chemlab-library-www-gitlab-com', '~> 0.1', '>= 0.1.1'
# dependencies for jenkins client
gem 'nokogiri', '~> 1.13', '>= 1.13.9'
diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock
index 23f82f553f1..3ccc5fe9be3 100644
--- a/qa/Gemfile.lock
+++ b/qa/Gemfile.lock
@@ -15,10 +15,10 @@ GEM
rack-test (>= 1.1.0, < 2.0)
rest-client (>= 2.0.2, < 3.0)
rspec (~> 3.8)
- allure-rspec (2.18.0)
- allure-ruby-commons (= 2.18.0)
+ allure-rspec (2.19.0)
+ allure-ruby-commons (= 2.19.0)
rspec-core (>= 3.8, < 4)
- allure-ruby-commons (2.18.0)
+ allure-ruby-commons (2.19.0)
mime-types (>= 3.3, < 4)
oj (>= 3.10, < 4)
require_all (>= 2, < 4)
@@ -27,7 +27,7 @@ GEM
binding_ninja (0.2.3)
builder (3.2.4)
byebug (11.1.3)
- capybara (3.37.1)
+ capybara (3.38.0)
addressable
matrix
mini_mime (>= 0.1.3)
@@ -61,7 +61,7 @@ GEM
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
excon (0.92.4)
- faker (2.23.0)
+ faker (3.0.0)
i18n (>= 1.8.11, < 2)
faraday (2.5.2)
faraday-net_http (>= 2.0, < 3.1)
@@ -100,14 +100,13 @@ GEM
gitlab (4.18.0)
httparty (~> 0.18)
terminal-table (>= 1.5.1)
- gitlab-qa (8.8.0)
+ gitlab-qa (8.11.0)
activesupport (~> 6.1)
gitlab (~> 4.18.0)
http (~> 5.0)
nokogiri (~> 1.10)
rainbow (>= 3, < 4)
table_print (= 1.5.7)
- toxiproxy (~> 2.0.2)
zeitwerk (>= 2, < 3)
google-apis-compute_v1 (0.51.0)
google-apis-core (>= 0.7.2, < 2.a)
@@ -156,7 +155,7 @@ GEM
httpclient (2.8.3)
i18n (1.12.0)
concurrent-ruby (~> 1.0)
- influxdb-client (1.17.0)
+ influxdb-client (2.8.0)
jwt (2.5.0)
knapsack (4.0.0)
rake
@@ -182,13 +181,13 @@ GEM
nokogiri (1.13.9)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
- octokit (5.6.1)
+ octokit (6.0.0)
faraday (>= 1, < 3)
sawyer (~> 0.9)
- oj (3.13.21)
+ oj (3.13.23)
os (1.1.4)
- parallel (1.19.2)
- parallel_tests (3.13.0)
+ parallel (1.22.1)
+ parallel_tests (4.0.0)
parallel
parser (3.1.2.1)
ast (~> 2.4.1)
@@ -207,7 +206,7 @@ GEM
rack (2.2.3.1)
rack-test (1.1.0)
rack (>= 1.0, < 3)
- rainbow (3.0.0)
+ rainbow (3.1.1)
rake (13.0.6)
regexp_parser (2.1.1)
representable (3.2.0)
@@ -222,19 +221,19 @@ GEM
netrc (~> 0.8)
retriable (3.1.2)
rexml (3.2.5)
- rotp (6.2.0)
- 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.1)
+ rotp (6.2.1)
+ rspec (3.12.0)
+ rspec-core (~> 3.12.0)
+ rspec-expectations (~> 3.12.0)
+ rspec-mocks (~> 3.12.0)
+ rspec-core (3.12.0)
+ rspec-support (~> 3.12.0)
+ rspec-expectations (3.12.0)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.11.0)
- rspec-mocks (3.11.1)
+ rspec-support (~> 3.12.0)
+ rspec-mocks (3.12.0)
diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.11.0)
+ rspec-support (~> 3.12.0)
rspec-parameterized (0.5.2)
binding_ninja (>= 0.2.3)
parser
@@ -243,7 +242,7 @@ GEM
unparser
rspec-retry (0.6.2)
rspec-core (> 3.3)
- rspec-support (3.11.1)
+ rspec-support (3.12.0)
rspec_junit_formatter (0.6.0)
rspec-core (>= 2, < 4, != 2.12.0)
ruby-debug-ide (0.7.3)
@@ -253,7 +252,7 @@ GEM
sawyer (0.9.2)
addressable (>= 2.3.5)
faraday (>= 0.17.3, < 3)
- selenium-webdriver (4.5.0)
+ selenium-webdriver (4.6.1)
childprocess (>= 0.5, < 5.0)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
@@ -268,8 +267,6 @@ GEM
table_print (1.5.7)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
- timecop (0.9.5)
- toxiproxy (2.0.2)
trailblazer-option (0.1.2)
tzinfo (2.0.5)
concurrent-ruby (~> 1.0)
@@ -303,41 +300,40 @@ PLATFORMS
DEPENDENCIES
activesupport (~> 6.1.4.7)
airborne (~> 0.3.7)
- allure-rspec (~> 2.18.0)
- capybara (~> 3.37.1)
+ allure-rspec (~> 2.19.0)
+ capybara (~> 3.38.0)
capybara-screenshot (~> 1.0.26)
chemlab (~> 0.10)
- chemlab-library-www-gitlab-com (~> 0.1)
+ chemlab-library-www-gitlab-com (~> 0.1, >= 0.1.1)
confiner (~> 0.3)
deprecation_toolkit (~> 2.0.0)
- faker (~> 2.23)
+ faker (~> 3.0)
faraday-retry (~> 2.0)
fog-core (= 2.1.0)
fog-google (~> 1.19)
- gitlab-qa (~> 8, >= 8.8.0)
- influxdb-client (~> 1.17)
+ gitlab-qa (~> 8, >= 8.11.0)
+ influxdb-client (~> 2.8)
knapsack (~> 4.0)
nokogiri (~> 1.13, >= 1.13.9)
- octokit (~> 5.6.1)
- parallel (~> 1.19)
- parallel_tests (~> 3.13)
+ octokit (~> 6.0.0)
+ parallel (~> 1.22, >= 1.22.1)
+ parallel_tests (~> 4.0)
pry-byebug (~> 3.10.1)
- rainbow (~> 3.0.0)
- rake (~> 13)
+ rainbow (~> 3.1.1)
+ rake (~> 13, >= 13.0.6)
rest-client (~> 2.1.0)
- rotp (~> 6.2.0)
- rspec (~> 3.11)
+ rotp (~> 6.2.1)
+ rspec (~> 3.12)
rspec-parameterized (~> 0.5.2)
- rspec-retry (~> 0.6.1)
+ rspec-retry (~> 0.6.2)
rspec_junit_formatter (~> 0.6.0)
ruby-debug-ide (~> 0.7.3)
- selenium-webdriver (~> 4.5)
+ selenium-webdriver (~> 4.6, >= 4.6.1)
slack-notifier (~> 2.4)
terminal-table (~> 3.0.2)
- timecop (~> 0.9.5)
warning (~> 1.3)
webdrivers (~> 5.2)
zeitwerk (~> 2.4)
BUNDLED WITH
- 2.3.24
+ 2.3.25
diff --git a/qa/lib/gitlab/page/group/settings/usage_quota.stub.rb b/qa/lib/gitlab/page/group/settings/usage_quota.stub.rb
deleted file mode 100644
index 2a5d9a6bb5e..00000000000
--- a/qa/lib/gitlab/page/group/settings/usage_quota.stub.rb
+++ /dev/null
@@ -1,515 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Page
- module Group
- module Settings
- module UsageQuota
- # @note Defined as +link :seats_tab+
- # Clicks +seats_tab+
- def seats_tab
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.seats_tab_element).to exist
- # end
- # @return [Watir::Link] The raw +Link+ element
- def seats_tab_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_seats_tab
- # end
- # @return [Boolean] true if the +seats_tab+ element is present on the page
- def seats_tab?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +link :pipelines_tab+
- # Clicks +pipelines_tab+
- def pipelines_tab
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.pipelines_tab_element).to exist
- # end
- # @return [Watir::Link] The raw +Link+ element
- def pipelines_tab_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_pipelines_tab
- # end
- # @return [Boolean] true if the +pipelines_tab+ element is present on the page
- def pipelines_tab?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +link :buy_ci_minutes+
- # Clicks +buy_ci_minutes+
- def buy_ci_minutes
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.buy_ci_minutes_element).to exist
- # end
- # @return [Watir::Link] The raw +Link+ element
- def buy_ci_minutes_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_buy_ci_minutes
- # end
- # @return [Boolean] true if the +buy_ci_minutes+ element is present on the page
- def buy_ci_minutes?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +div :plan_ci_minutes+
- # @return [String] The text content or value of +plan_ci_minutes+
- def plan_ci_minutes
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.plan_ci_minutes_element).to exist
- # end
- # @return [Watir::Div] The raw +Div+ element
- def plan_ci_minutes_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_plan_ci_minutes
- # end
- # @return [Boolean] true if the +plan_ci_minutes+ element is present on the page
- def plan_ci_minutes?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +div :additional_ci_minutes+
- # @return [String] The text content or value of +additional_ci_minutes+
- def additional_ci_minutes
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.additional_ci_minutes_element).to exist
- # end
- # @return [Watir::Div] The raw +Div+ element
- def additional_ci_minutes_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_additional_ci_minutes
- # end
- # @return [Boolean] true if the +additional_ci_minutes+ element is present on the page
- def additional_ci_minutes?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +div :ci_purchase_successful_alert+
- # @return [String] The text content or value of +ci_purchase_successful_alert+
- def ci_purchase_successful_alert
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.ci_purchase_successful_alert_element).to exist
- # end
- # @return [Watir::Div] The raw +Div+ element
- def ci_purchase_successful_alert_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_ci_purchase_successful_alert
- # end
- # @return [Boolean] true if the +ci_purchase_successful_alert+ element is present on the page
- def ci_purchase_successful_alert?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +link :storage_tab+
- # Clicks +storage_tab+
- def storage_tab
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.storage_tab_element).to exist
- # end
- # @return [Watir::Link] The raw +Link+ element
- def storage_tab_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_storage_tab
- # end
- # @return [Boolean] true if the +storage_tab+ element is present on the page
- def storage_tab?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +link :buy_storage+
- # Clicks +buy_storage+
- def buy_storage
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.buy_storage_element).to exist
- # end
- # @return [Watir::Link] The raw +Link+ element
- def buy_storage_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_buy_storage
- # end
- # @return [Boolean] true if the +buy_storage+ element is present on the page
- def buy_storage?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +div :used_storage_message+
- # @return [String] The text content or value of +used_storage_message+
- def used_storage_message
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.used_storage_message_element).to exist
- # end
- # @return [Watir::Div] The raw +Div+ element
- def used_storage_message_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_used_storage_message
- # end
- # @return [Boolean] true if the +used_storage_message+ element is present on the page
- def used_storage_message?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +div :group_usage_message+
- # @return [String] The text content or value of +group_usage_message+
- def group_usage_message
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.group_usage_message_element).to exist
- # end
- # @return [Watir::Div] The raw +Div+ element
- def group_usage_message_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_group_usage_message
- # end
- # @return [Boolean] true if the +group_usage_message+ element is present on the page
- def group_usage_message?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +div :dependency_proxy_usage+
- # @return [String] The text content or value of +dependency_proxy_usage+
- def dependency_proxy_usage
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.dependency_proxy_usage_element).to exist
- # end
- # @return [Watir::Div] The raw +Div+ element
- def dependency_proxy_usage_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_dependency_proxy_usage
- # end
- # @return [Boolean] true if the +dependency_proxy_usage+ element is present on the page
- def dependency_proxy_usage?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +span :dependency_proxy_size+
- # @return [String] The text content or value of +dependency_proxy_size+
- def dependency_proxy_size
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.dependency_proxy_size_element).to exist
- # end
- # @return [Watir::Span] The raw +Span+ element
- def dependency_proxy_size_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_dependency_proxy_size
- # end
- # @return [Boolean] true if the +dependency_proxy_size+ element is present on the page
- def dependency_proxy_size?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +div :container_registry_usage+
- # @return [String] The text content or value of +container_registry_usage+
- def container_registry_usage
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.container_registry_usage_element).to exist
- # end
- # @return [Watir::Div] The raw +Div+ element
- def container_registry_usage_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_container_registry_usage
- # end
- # @return [Boolean] true if the +container_registry_usage+ element is present on the page
- def container_registry_usage?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +div :project_storage_used+
- # @return [String] The text content or value of +project_storage_used+
- def project_storage_used
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.project_storage_used_element).to exist
- # end
- # @return [Watir::Div] The raw +Div+ element
- def project_storage_used_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_project_storage_used
- # end
- # @return [Boolean] true if the +project_storage_used+ element is present on the page
- def project_storage_used?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +div :project+
- # @return [String] The text content or value of +project+
- def project
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.project_element).to exist
- # end
- # @return [Watir::Div] The raw +Div+ element
- def project_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_project
- # end
- # @return [Boolean] true if the +project+ element is present on the page
- def project?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +div :storage_type_legend+
- # @return [String] The text content or value of +storage_type_legend+
- def storage_type_legend
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.storage_type_legend_element).to exist
- # end
- # @return [Watir::Div] The raw +Div+ element
- def storage_type_legend_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_storage_type_legend
- # end
- # @return [Boolean] true if the +storage_type_legend+ element is present on the page
- def storage_type_legend?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +span :container_registry_size+
- # @return [String] The text content or value of +container_registry_size+
- def container_registry_size
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.container_registry_size_element).to exist
- # end
- # @return [Watir::Span] The raw +Span+ element
- def container_registry_size_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_container_registry_size
- # end
- # @return [Boolean] true if the +container_registry_size+ element is present on the page
- def container_registry_size?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +div :purchased_usage_total_free+
- # @return [String] The text content or value of +purchased_usage_total_free+
- def purchased_usage_total_free
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.purchased_usage_total_free_element).to exist
- # end
- # @return [Watir::Div] The raw +Div+ element
- def purchased_usage_total_free_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_purchased_usage_total_free
- # end
- # @return [Boolean] true if the +purchased_usage_total_free+ element is present on the page
- def purchased_usage_total_free?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +span :purchased_usage_total+
- # @return [String] The text content or value of +purchased_usage_total+
- def purchased_usage_total
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.purchased_usage_total_element).to exist
- # end
- # @return [Watir::Span] The raw +Span+ element
- def purchased_usage_total_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_purchased_usage_total
- # end
- # @return [Boolean] true if the +purchased_usage_total+ element is present on the page
- def purchased_usage_total?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +div :storage_purchase_successful_alert+
- # @return [String] The text content or value of +storage_purchase_successful_alert+
- def storage_purchase_successful_alert
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.storage_purchase_successful_alert_element).to exist
- # end
- # @return [Watir::Div] The raw +Div+ element
- def storage_purchase_successful_alert_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_storage_purchase_successful_alert
- # end
- # @return [Boolean] true if the +storage_purchase_successful_alert+ element is present on the page
- def storage_purchase_successful_alert?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @note Defined as +h2 :storage_available_alert+
- # @return [String] The text content or value of +storage_available_alert+
- def storage_available_alert
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota.storage_available_alert_element).to exist
- # end
- # @return [Watir::H2] The raw +H2+ element
- def storage_available_alert_element
- # This is a stub, used for indexing. The method is dynamically generated.
- end
-
- # @example
- # Gitlab::Page::Group::Settings::UsageQuota.perform do |usage_quota|
- # expect(usage_quota).to be_storage_available_alert
- # end
- # @return [Boolean] true if the +storage_available_alert+ element is present on the page
- def storage_available_alert?
- # This is a stub, used for indexing. The method is dynamically generated.
- end
- end
- end
- end
- end
-end
diff --git a/qa/lib/gitlab/page/group/settings/usage_quotas.rb b/qa/lib/gitlab/page/group/settings/usage_quotas.rb
index a1ab345bf1e..8540bce3da8 100644
--- a/qa/lib/gitlab/page/group/settings/usage_quotas.rb
+++ b/qa/lib/gitlab/page/group/settings/usage_quotas.rb
@@ -7,6 +7,11 @@ module Gitlab
class UsageQuotas < Chemlab::Page
# Seats section
link :seats_tab
+ div :seats_in_use
+ p :seats_used
+ p :seats_owed
+ table :subscription_users
+ button :remove_user
# Pipelines section
link :pipelines_tab
diff --git a/qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb b/qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb
new file mode 100644
index 00000000000..6c38625bb3b
--- /dev/null
+++ b/qa/lib/gitlab/page/group/settings/usage_quotas.stub.rb
@@ -0,0 +1,635 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Page
+ module Group
+ module Settings
+ module UsageQuotas
+ # @note Defined as +link :seats_tab+
+ # Clicks +seats_tab+
+ def seats_tab
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.seats_tab_element).to exist
+ # end
+ # @return [Watir::Link] The raw +Link+ element
+ def seats_tab_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_seats_tab
+ # end
+ # @return [Boolean] true if the +seats_tab+ element is present on the page
+ def seats_tab?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +div :seats_in_use+
+ # @return [String] The text content or value of +seats_in_use+
+ def seats_in_use
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.seats_in_use_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def seats_in_use_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_seats_in_use
+ # end
+ # @return [Boolean] true if the +seats_in_use+ element is present on the page
+ def seats_in_use?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +p :seats_used+
+ # @return [String] The text content or value of +seats_used+
+ def seats_used
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.seats_used_element).to exist
+ # end
+ # @return [Watir::P] The raw +P+ element
+ def seats_used_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_seats_used
+ # end
+ # @return [Boolean] true if the +seats_used+ element is present on the page
+ def seats_used?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +p :seats_owed+
+ # @return [String] The text content or value of +seats_owed+
+ def seats_owed
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.seats_owed_element).to exist
+ # end
+ # @return [Watir::P] The raw +P+ element
+ def seats_owed_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_seats_owed
+ # end
+ # @return [Boolean] true if the +seats_owed+ element is present on the page
+ def seats_owed?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +table :subscription_users+
+ # @return [String] The text content or value of +subscription_users+
+ def subscription_users
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.subscription_users_element).to exist
+ # end
+ # @return [Watir::Table] The raw +Table+ element
+ def subscription_users_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_subscription_users
+ # end
+ # @return [Boolean] true if the +subscription_users+ element is present on the page
+ def subscription_users?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +button :remove_user+
+ # Clicks +remove_user+
+ def remove_user
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.remove_user_element).to exist
+ # end
+ # @return [Watir::Button] The raw +Button+ element
+ def remove_user_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_remove_user
+ # end
+ # @return [Boolean] true if the +remove_user+ element is present on the page
+ def remove_user?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +link :pipelines_tab+
+ # Clicks +pipelines_tab+
+ def pipelines_tab
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.pipelines_tab_element).to exist
+ # end
+ # @return [Watir::Link] The raw +Link+ element
+ def pipelines_tab_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_pipelines_tab
+ # end
+ # @return [Boolean] true if the +pipelines_tab+ element is present on the page
+ def pipelines_tab?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +link :buy_ci_minutes+
+ # Clicks +buy_ci_minutes+
+ def buy_ci_minutes
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.buy_ci_minutes_element).to exist
+ # end
+ # @return [Watir::Link] The raw +Link+ element
+ def buy_ci_minutes_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_buy_ci_minutes
+ # end
+ # @return [Boolean] true if the +buy_ci_minutes+ element is present on the page
+ def buy_ci_minutes?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +div :plan_ci_minutes+
+ # @return [String] The text content or value of +plan_ci_minutes+
+ def plan_ci_minutes
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.plan_ci_minutes_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def plan_ci_minutes_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_plan_ci_minutes
+ # end
+ # @return [Boolean] true if the +plan_ci_minutes+ element is present on the page
+ def plan_ci_minutes?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +div :additional_ci_minutes+
+ # @return [String] The text content or value of +additional_ci_minutes+
+ def additional_ci_minutes
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.additional_ci_minutes_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def additional_ci_minutes_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_additional_ci_minutes
+ # end
+ # @return [Boolean] true if the +additional_ci_minutes+ element is present on the page
+ def additional_ci_minutes?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +div :ci_purchase_successful_alert+
+ # @return [String] The text content or value of +ci_purchase_successful_alert+
+ def ci_purchase_successful_alert
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.ci_purchase_successful_alert_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def ci_purchase_successful_alert_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_ci_purchase_successful_alert
+ # end
+ # @return [Boolean] true if the +ci_purchase_successful_alert+ element is present on the page
+ def ci_purchase_successful_alert?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +link :storage_tab+
+ # Clicks +storage_tab+
+ def storage_tab
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.storage_tab_element).to exist
+ # end
+ # @return [Watir::Link] The raw +Link+ element
+ def storage_tab_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_storage_tab
+ # end
+ # @return [Boolean] true if the +storage_tab+ element is present on the page
+ def storage_tab?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +link :purchase_more_storage+
+ # Clicks +purchase_more_storage+
+ def purchase_more_storage
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.purchase_more_storage_element).to exist
+ # end
+ # @return [Watir::Link] The raw +Link+ element
+ def purchase_more_storage_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_purchase_more_storage
+ # end
+ # @return [Boolean] true if the +purchase_more_storage+ element is present on the page
+ def purchase_more_storage?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +div :used_storage_message+
+ # @return [String] The text content or value of +used_storage_message+
+ def used_storage_message
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.used_storage_message_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def used_storage_message_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_used_storage_message
+ # end
+ # @return [Boolean] true if the +used_storage_message+ element is present on the page
+ def used_storage_message?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +div :group_usage_message+
+ # @return [String] The text content or value of +group_usage_message+
+ def group_usage_message
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.group_usage_message_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def group_usage_message_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_group_usage_message
+ # end
+ # @return [Boolean] true if the +group_usage_message+ element is present on the page
+ def group_usage_message?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +div :dependency_proxy_usage+
+ # @return [String] The text content or value of +dependency_proxy_usage+
+ def dependency_proxy_usage
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.dependency_proxy_usage_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def dependency_proxy_usage_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_dependency_proxy_usage
+ # end
+ # @return [Boolean] true if the +dependency_proxy_usage+ element is present on the page
+ def dependency_proxy_usage?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +span :dependency_proxy_size+
+ # @return [String] The text content or value of +dependency_proxy_size+
+ def dependency_proxy_size
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.dependency_proxy_size_element).to exist
+ # end
+ # @return [Watir::Span] The raw +Span+ element
+ def dependency_proxy_size_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_dependency_proxy_size
+ # end
+ # @return [Boolean] true if the +dependency_proxy_size+ element is present on the page
+ def dependency_proxy_size?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +div :container_registry_usage+
+ # @return [String] The text content or value of +container_registry_usage+
+ def container_registry_usage
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.container_registry_usage_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def container_registry_usage_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_container_registry_usage
+ # end
+ # @return [Boolean] true if the +container_registry_usage+ element is present on the page
+ def container_registry_usage?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +div :project_storage_used+
+ # @return [String] The text content or value of +project_storage_used+
+ def project_storage_used
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.project_storage_used_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def project_storage_used_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_project_storage_used
+ # end
+ # @return [Boolean] true if the +project_storage_used+ element is present on the page
+ def project_storage_used?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +div :project+
+ # @return [String] The text content or value of +project+
+ def project
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.project_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def project_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_project
+ # end
+ # @return [Boolean] true if the +project+ element is present on the page
+ def project?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +div :storage_type_legend+
+ # @return [String] The text content or value of +storage_type_legend+
+ def storage_type_legend
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.storage_type_legend_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def storage_type_legend_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_storage_type_legend
+ # end
+ # @return [Boolean] true if the +storage_type_legend+ element is present on the page
+ def storage_type_legend?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +span :container_registry_size+
+ # @return [String] The text content or value of +container_registry_size+
+ def container_registry_size
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.container_registry_size_element).to exist
+ # end
+ # @return [Watir::Span] The raw +Span+ element
+ def container_registry_size_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_container_registry_size
+ # end
+ # @return [Boolean] true if the +container_registry_size+ element is present on the page
+ def container_registry_size?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +div :purchased_usage_total_free+
+ # @return [String] The text content or value of +purchased_usage_total_free+
+ def purchased_usage_total_free
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.purchased_usage_total_free_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def purchased_usage_total_free_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_purchased_usage_total_free
+ # end
+ # @return [Boolean] true if the +purchased_usage_total_free+ element is present on the page
+ def purchased_usage_total_free?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +span :purchased_usage_total+
+ # @return [String] The text content or value of +purchased_usage_total+
+ def purchased_usage_total
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.purchased_usage_total_element).to exist
+ # end
+ # @return [Watir::Span] The raw +Span+ element
+ def purchased_usage_total_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_purchased_usage_total
+ # end
+ # @return [Boolean] true if the +purchased_usage_total+ element is present on the page
+ def purchased_usage_total?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +div :storage_purchase_successful_alert+
+ # @return [String] The text content or value of +storage_purchase_successful_alert+
+ def storage_purchase_successful_alert
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.storage_purchase_successful_alert_element).to exist
+ # end
+ # @return [Watir::Div] The raw +Div+ element
+ def storage_purchase_successful_alert_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_storage_purchase_successful_alert
+ # end
+ # @return [Boolean] true if the +storage_purchase_successful_alert+ element is present on the page
+ def storage_purchase_successful_alert?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @note Defined as +h2 :storage_available_alert+
+ # @return [String] The text content or value of +storage_available_alert+
+ def storage_available_alert
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas.storage_available_alert_element).to exist
+ # end
+ # @return [Watir::H2] The raw +H2+ element
+ def storage_available_alert_element
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+
+ # @example
+ # Gitlab::Page::Group::Settings::UsageQuotas.perform do |usage_quotas|
+ # expect(usage_quotas).to be_storage_available_alert
+ # end
+ # @return [Boolean] true if the +storage_available_alert+ element is present on the page
+ def storage_available_alert?
+ # This is a stub, used for indexing. The method is dynamically generated.
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/fixtures/package_managers/helm/helm_install_package.yaml.erb b/qa/qa/fixtures/package_managers/helm/helm_install_package.yaml.erb
index 786b0592153..590120ce7b2 100644
--- a/qa/qa/fixtures/package_managers/helm/helm_install_package.yaml.erb
+++ b/qa/qa/fixtures/package_managers/helm/helm_install_package.yaml.erb
@@ -1,7 +1,6 @@
pull:
- image: alpine:3
+ image: dtzar/helm-kubectl:latest
script:
- - apk add helm --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing
- helm repo add --username <%= username %> --password <%= access_token %> gitlab_qa ${CI_API_V4_URL}/projects/<%= package_project.id %>/packages/helm/stable
- helm repo update
- helm pull gitlab_qa/<%= package_name %>
diff --git a/qa/qa/fixtures/package_managers/helm/helm_upload_package.yaml.erb b/qa/qa/fixtures/package_managers/helm/helm_upload_package.yaml.erb
index b3e907b50f4..b1c275cd96a 100644
--- a/qa/qa/fixtures/package_managers/helm/helm_upload_package.yaml.erb
+++ b/qa/qa/fixtures/package_managers/helm/helm_upload_package.yaml.erb
@@ -1,7 +1,6 @@
deploy:
- image: alpine:3
+ image: dtzar/helm-kubectl:latest
script:
- - apk add helm --repository=http://dl-cdn.alpinelinux.org/alpine/edge/testing
- apk add curl
- helm create <%= package_name %>
- cp ./Chart.yaml <%= package_name %>
diff --git a/qa/qa/flow/sign_up.rb b/qa/qa/flow/sign_up.rb
index 52c92293bad..abaab064a73 100644
--- a/qa/qa/flow/sign_up.rb
+++ b/qa/qa/flow/sign_up.rb
@@ -37,7 +37,9 @@ module QA
Page::Main::Menu.perform(&:not_signed_in?)
end
- raise "Failed user registration attempt. Registration was expected to #{user.expect_fabrication_success ? 'succeed' : 'fail'} but #{success ? 'succeeded' : 'failed'}." unless success
+ return if success
+
+ raise "Failed user registration attempt. Registration was expected to #{user.expect_fabrication_success ? 'succeed' : 'fail'} but #{success ? 'succeeded' : 'failed'}."
end
def disable_sign_ups
diff --git a/qa/qa/git/repository.rb b/qa/qa/git/repository.rb
index f132d7b7885..35c5262e767 100644
--- a/qa/qa/git/repository.rb
+++ b/qa/qa/git/repository.rb
@@ -305,11 +305,12 @@ module QA
prefix = "-o merge_request"
opts.each_with_object([]) do |(key, value), options|
- if value.is_a?(Array)
+ case value
+ when Array
value.each do |item|
options << "#{prefix}.#{key}=\"#{item}\""
end
- elsif value == true
+ when true
options << "#{prefix}.#{key}"
else
options << "#{prefix}.#{key}=\"#{value}\""
diff --git a/qa/qa/mobile/page/base.rb b/qa/qa/mobile/page/base.rb
new file mode 100644
index 00000000000..8bc7e5f25ab
--- /dev/null
+++ b/qa/qa/mobile/page/base.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module QA
+ module Mobile
+ module Page
+ module Base
+ prepend Support::Page::Logging
+
+ def fill_element(name, content)
+ # We need to bypass click_element_cooridinates as it does not work on mobile devices
+ find_element(name).set(content)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/admin/overview/users/index.rb b/qa/qa/page/admin/overview/users/index.rb
index 2ad45e4a0fa..f46ae30498c 100644
--- a/qa/qa/page/admin/overview/users/index.rb
+++ b/qa/qa/page/admin/overview/users/index.rb
@@ -28,6 +28,10 @@ module QA
click_link(username)
end
end
+
+ def has_username?(username)
+ has_element?(:user_row_content, text: username, wait: 1)
+ end
end
end
end
diff --git a/qa/qa/page/base.rb b/qa/qa/page/base.rb
index 81c518bb4c6..f59b06b4e75 100644
--- a/qa/qa/page/base.rb
+++ b/qa/qa/page/base.rb
@@ -6,6 +6,7 @@ module QA
module Page
class Base
prepend Support::Page::Logging
+ prepend Mobile::Page::Base if QA::Runtime::Env.remote_mobile_device_name
include Capybara::DSL
include Scenario::Actable
@@ -39,7 +40,8 @@ module QA
def inspect
# For prettier failure messages
# Eg.: "expected QA::Page::File::Show not to have file "QA Test - File name"
- # Instead of "expected #<QA::Page::File::Show:0x000055c6511e07b8 @retry_later_backoff=60> not to have file "QA Test - File name"
+ # Instead of "expected #<QA::Page::File::Show:0x000055c6511e07b8 @retry_later_backoff=60>
+ # not to have file "QA Test - File name"
self.class.to_s
end
@@ -158,16 +160,17 @@ module QA
all(element_selector_css(name), **kwargs)
end
- def check_element(name, click_by_js = false, visibility = false)
- if find_element(name, visible: visibility).checked?
+ def check_element(name, click_by_js = false, **kwargs)
+ kwargs[:visible] = false unless kwargs.key?(:visible)
+ if find_element(name, **kwargs).checked?
QA::Runtime::Logger.debug("#{name} is already checked")
return
end
retry_until(sleep_interval: 1) do
- click_checkbox_or_radio(name, click_by_js, visibility)
- checked = find_element(name, visible: visibility).checked?
+ click_checkbox_or_radio(name, click_by_js, **kwargs)
+ checked = find_element(name, **kwargs).checked?
QA::Runtime::Logger.debug(checked ? "#{name} was checked" : "#{name} was not checked")
@@ -175,16 +178,17 @@ module QA
end
end
- def uncheck_element(name, click_by_js = false, visibility = false)
- unless find_element(name, visible: visibility).checked?
+ def uncheck_element(name, click_by_js = false, **kwargs)
+ kwargs[:visible] = false unless kwargs.key?(:visible)
+ unless find_element(name, **kwargs).checked?
QA::Runtime::Logger.debug("#{name} is already unchecked")
return
end
retry_until(sleep_interval: 1) do
- click_checkbox_or_radio(name, click_by_js, visibility)
- unchecked = !find_element(name, visible: visibility).checked?
+ click_checkbox_or_radio(name, click_by_js, **kwargs)
+ unchecked = !find_element(name, **kwargs).checked?
QA::Runtime::Logger.debug(unchecked ? "#{name} was unchecked" : "#{name} was not unchecked")
@@ -193,16 +197,17 @@ module QA
end
# Method for selecting radios
- def choose_element(name, click_by_js = false, visibility = false)
- if find_element(name, visible: visibility).checked?
+ def choose_element(name, click_by_js = false, **kwargs)
+ kwargs[:visible] = false unless kwargs.key?(:visible)
+ if find_element(name, **kwargs).checked?
QA::Runtime::Logger.debug("#{name} is already selected")
return
end
retry_until(sleep_interval: 1) do
- click_checkbox_or_radio(name, click_by_js, visibility)
- selected = find_element(name, visible: visibility).checked?
+ click_checkbox_or_radio(name, click_by_js, **kwargs)
+ selected = find_element(name, **kwargs).checked?
QA::Runtime::Logger.debug(selected ? "#{name} was selected" : "#{name} was not selected")
@@ -368,19 +373,15 @@ module QA
sleep 1
end
- def within_element(name, **kwargs)
+ def within_element(name, **kwargs, &block)
wait_for_requests(skip_finished_loading_check: kwargs.delete(:skip_finished_loading_check))
text = kwargs.delete(:text)
- page.within(element_selector_css(name, kwargs), text: text) do
- yield
- end
+ page.within(element_selector_css(name, kwargs), text: text, &block)
end
- def within_element_by_index(name, index)
- page.within all_elements(name, minimum: index + 1)[index] do
- yield
- end
+ def within_element_by_index(name, index, &block)
+ page.within(all_elements(name, minimum: index + 1)[index], &block)
end
def scroll_to_element(name, *kwargs)
@@ -407,15 +408,14 @@ module QA
def wait_if_retry_later
return if @retry_later_backoff > QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME * 5
+ return unless has_css?('body', text: 'Retry later', wait: 0)
- if has_css?('body', text: 'Retry later', wait: 0)
- QA::Runtime::Logger.warn("`Retry later` error occurred. Sleeping for #{@retry_later_backoff} seconds...")
- sleep @retry_later_backoff
- refresh
- @retry_later_backoff += QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME
+ QA::Runtime::Logger.warn("`Retry later` error occurred. Sleeping for #{@retry_later_backoff} seconds...")
+ sleep @retry_later_backoff
+ refresh
+ @retry_later_backoff += QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME
- wait_if_retry_later
- end
+ wait_if_retry_later
end
def current_host
@@ -458,6 +458,10 @@ module QA
true
end
+ def click_by_javascript(element)
+ page.execute_script("arguments[0].click();", element)
+ end
+
class DSL
attr_reader :views
@@ -474,13 +478,18 @@ module QA
private
- def click_checkbox_or_radio(name, click_by_js, visibility)
- box = find_element(name, visible: visibility)
+ def click_checkbox_or_radio(name, click_by_js, **kwargs)
+ box = find_element(name, **kwargs)
# Some checkboxes and radio buttons are hidden by their labels and cannot be clicked directly
click_by_js ? page.execute_script("arguments[0].click();", box) : box.click
end
- def feature_flag_controlled_element(feature_flag, element_when_flag_enabled, element_when_flag_disabled, visibility = true)
+ def feature_flag_controlled_element(
+ feature_flag,
+ element_when_flag_enabled,
+ element_when_flag_disabled,
+ visibility = true
+ )
# Feature flags can change the UI elements shown, but we need admin access to get feature flag values, which
# prevents us running the tests on production. Instead we detect the UI element that should be shown when the
# feature flag is enabled and otherwise use the element that should be displayed when the feature flag is
diff --git a/qa/qa/page/component/access_tokens.rb b/qa/qa/page/component/access_tokens.rb
index 3c8a608cdc2..586f69b8a64 100644
--- a/qa/qa/page/component/access_tokens.rb
+++ b/qa/qa/page/component/access_tokens.rb
@@ -18,27 +18,24 @@ module QA
element :expiry_date_field
end
- base.view 'app/views/shared/access_tokens/_created_container.html.haml' do
- element :created_access_token_field
- end
-
base.view 'app/views/shared/access_tokens/_form.html.haml' do
element :access_token_name_field
element :create_token_button
end
- base.view 'app/views/shared/access_tokens/_table.html.haml' do
- element :revoke_button
- end
-
base.view 'app/views/shared/tokens/_scopes_form.html.haml' do
element :api_label, '#{scope}_label' # rubocop:disable QA/ElementWithPattern, Lint/InterpolationCheck
end
base.view 'app/assets/javascripts/access_tokens/components/new_access_token_app.vue' do
+ element :access_token_section
element :created_access_token_field
end
+ base.view 'app/assets/javascripts/vue_shared/components/form/input_copy_toggle_visibility.vue' do
+ element :toggle_visibility_button
+ end
+
base.view 'app/assets/javascripts/access_tokens/components/access_token_table_app.vue' do
element :revoke_button
end
@@ -57,7 +54,10 @@ module QA
end
def created_access_token
- find_element(:created_access_token_field, wait: 30).value
+ within_element(:access_token_section) do
+ click_element(:toggle_visibility_button, wait: 30)
+ find_element(:created_access_token_field).value
+ end
end
def fill_expiry_date(date)
diff --git a/qa/qa/page/component/delete_modal.rb b/qa/qa/page/component/delete_modal.rb
new file mode 100644
index 00000000000..18bb2b1bb1b
--- /dev/null
+++ b/qa/qa/page/component/delete_modal.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+module QA
+ module Page
+ module Component
+ module DeleteModal
+ extend QA::Page::PageConcern
+
+ def self.included(base)
+ super
+
+ base.view 'app/assets/javascripts/projects/components/shared/delete_button.vue' do
+ element :confirm_name_field
+ element :confirm_delete_button
+ end
+ end
+
+ def fill_confirmation_path(text)
+ fill_element(:confirm_name_field, text)
+ end
+
+ def wait_for_delete_button_enabled
+ wait_until(reload: false) do
+ !find_element(:confirm_delete_button).disabled?
+ end
+ end
+
+ def confirm_delete
+ wait_for_delete_button_enabled
+ click_element(:confirm_delete_button)
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/page/component/groups_filter.rb b/qa/qa/page/component/groups_filter.rb
index 28b8ece918d..ec59d010718 100644
--- a/qa/qa/page/component/groups_filter.rb
+++ b/qa/qa/page/component/groups_filter.rb
@@ -16,6 +16,10 @@ 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
@@ -28,9 +32,24 @@ module QA
# groups_list_tree_container means we have the complete filtered list
# of groups
has_element?(:groups_list_tree_container, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
-
# If there are no groups we'll know immediately because we filtered the list
- return false if page.has_text?('No groups or projects matched your search', wait: 0)
+ if page.has_text?('No groups or projects matched your search',
+wait: 0) || page.has_text?('No groups matched your search', wait: 0)
+ return false unless has_element?(:public_groups_tab)
+
+ # Try for public groups
+ click_element(:public_groups_tab)
+ # Filter and submit to reload the page and only retrieve the filtered results
+ find_element(:groups_filter_field).set(name).send_keys(:return)
+
+ # Since we submitted after filtering, the presence of
+ # groups_list_tree_container means we have the complete filtered list
+ # of groups
+ has_element?(:groups_list_tree_container, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
+
+ return false if page.has_text?('No groups or projects matched your search',
+wait: 0) || page.has_text?('No groups matched your search', wait: 0)
+ end
# The name will be present as filter input so we check for a link, not text
page.has_link?(name, wait: 0)
diff --git a/qa/qa/page/component/issuable/sidebar.rb b/qa/qa/page/component/issuable/sidebar.rb
index 71a69576c06..fb2e7478684 100644
--- a/qa/qa/page/component/issuable/sidebar.rb
+++ b/qa/qa/page/component/issuable/sidebar.rb
@@ -86,6 +86,24 @@ module QA
end
end
+ def has_reviewer?(username)
+ wait_reviewers_block_finish_loading do
+ has_text?(username)
+ end
+ end
+
+ def has_no_reviewer?(username)
+ wait_reviewers_block_finish_loading do
+ has_no_text?(username)
+ end
+ end
+
+ def has_no_reviewers?
+ wait_reviewers_block_finish_loading do
+ has_text?('None')
+ end
+ end
+
def has_avatar_image_count?(count)
wait_assignees_block_finish_loading do
all_elements(:avatar_image, count: count)
@@ -133,6 +151,53 @@ module QA
click_element(:more_assignees_link)
end
+ def toggle_reviewers_edit
+ click_element(:reviewers_edit_button)
+ end
+
+ def suggested_reviewer_usernames
+ within_element(:reviewers_block_container) do
+ wait_for_requests
+
+ click_element(:reviewers_edit_button)
+ wait_for_requests
+
+ list = find_element(:dropdown_list_content)
+ suggested_reviewers = list.find_all('li[data-user-suggested="true"')
+ raise ElementNotFound, 'No suggested reviewers found' if suggested_reviewers.nil?
+
+ suggested_reviewers.map do |reviewer|
+ info = reviewer.text.split('@')
+ {
+ name: info[0].chomp,
+ username: info[1].chomp
+ }
+ end.compact
+ end
+ end
+
+ def unassign_reviewers
+ within_element(:reviewers_block_container) do
+ wait_for_requests
+
+ click_element(:reviewers_edit_button)
+ wait_for_requests
+ end
+
+ select_reviewer('Unassigned')
+ end
+
+ def select_reviewer(username)
+ within_element(:reviewers_block_container) do
+ within_element(:dropdown_list_content) do
+ click_on username
+ end
+
+ click_element(:reviewers_edit_button)
+ wait_for_requests
+ end
+ end
+
private
def wait_assignees_block_finish_loading
@@ -144,6 +209,15 @@ module QA
end
end
+ def wait_reviewers_block_finish_loading
+ within_element(:reviewers_block_container) do
+ wait_until(reload: false, max_duration: 10, sleep_interval: 1) do
+ finished_loading_block?
+ yield
+ end
+ end
+ end
+
def wait_labels_block_finish_loading
within_element(:labels_block) do
wait_until(reload: false, max_duration: 10, sleep_interval: 1) do
diff --git a/qa/qa/page/component/lazy_loader.rb b/qa/qa/page/component/lazy_loader.rb
index 2123431fc55..1b166efbbff 100644
--- a/qa/qa/page/component/lazy_loader.rb
+++ b/qa/qa/page/component/lazy_loader.rb
@@ -9,8 +9,8 @@ module QA
def self.included(base)
super
- base.view 'app/assets/javascripts/lazy_loader.js' do
- element :js_lazy_loaded
+ base.view 'app/views/layouts/_img_loader.html.haml' do
+ element :js_lazy_loaded_content
end
end
end
diff --git a/qa/qa/page/component/legacy_clone_panel.rb b/qa/qa/page/component/legacy_clone_panel.rb
index ee372a3f9aa..8c3c25f6e41 100644
--- a/qa/qa/page/component/legacy_clone_panel.rb
+++ b/qa/qa/page/component/legacy_clone_panel.rb
@@ -28,7 +28,7 @@ module QA
end
def repository_location
- Git::Location.new(find_element(:clone_url_content).text)
+ Git::Location.new(find_element(:clone_url_content).value)
end
private
diff --git a/qa/qa/page/component/namespace_select.rb b/qa/qa/page/component/namespace_select.rb
index 9b483162f1b..8fb0bb79ab3 100644
--- a/qa/qa/page/component/namespace_select.rb
+++ b/qa/qa/page/component/namespace_select.rb
@@ -9,7 +9,7 @@ module QA
def self.included(base)
super
- base.view "app/assets/javascripts/vue_shared/components/namespace_select/namespace_select_deprecated.vue" do
+ base.view "app/assets/javascripts/groups_projects/components/transfer_locations.vue" do
element :namespaces_list
element :namespaces_list_groups
element :namespaces_list_item
@@ -20,14 +20,15 @@ module QA
def select_namespace(item)
click_element :namespaces_list
- wait_for_requests
-
within_element(:namespaces_list) do
fill_element(:namespaces_list_search, item)
wait_for_requests
- find_element(:namespaces_list_item, text: item).click
+ # Click element by JS in case dropdown changes position mid-click
+ # Workaround for issue https://gitlab.com/gitlab-org/gitlab/-/issues/381376
+ namespace = find_element(:namespaces_list_item, text: item, visible: false)
+ click_by_javascript(namespace)
end
end
end
diff --git a/qa/qa/page/component/users_select.rb b/qa/qa/page/component/users_select.rb
deleted file mode 100644
index f88d6450a33..00000000000
--- a/qa/qa/page/component/users_select.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Page
- module Component
- module UsersSelect
- def select_user(element, username)
- find("#{element_selector_css(element)} input").set(username)
- find('.ajax-users-dropdown .user-username', text: "@#{username}").click
- end
- end
- end
- end
-end
diff --git a/qa/qa/page/component/wiki.rb b/qa/qa/page/component/wiki.rb
index ffd31f8d7b7..ed68052f997 100644
--- a/qa/qa/page/component/wiki.rb
+++ b/qa/qa/page/component/wiki.rb
@@ -38,7 +38,7 @@ module QA
# webdriver to miss the hit so we wait for the svg to load before
# clicking the button.
within_element(:svg_content) do
- has_element?(:js_lazy_loaded)
+ has_element?(:js_lazy_loaded_content)
end
click_element(:create_first_page_link)
diff --git a/qa/qa/page/file/edit.rb b/qa/qa/page/file/edit.rb
index d2b8c8260fd..b9b676ee3c4 100644
--- a/qa/qa/page/file/edit.rb
+++ b/qa/qa/page/file/edit.rb
@@ -12,10 +12,6 @@ module QA
element :editor_toolbar_button
end
- view 'app/views/projects/blob/_editor.html.haml' do
- element :source_editor_preview_container
- end
-
def has_markdown_preview?(component, content)
within_element(:source_editor_preview_container) do
has_css?(component, exact_text: content)
diff --git a/qa/qa/page/file/form.rb b/qa/qa/page/file/form.rb
index bb8934db498..2e0f8c59213 100644
--- a/qa/qa/page/file/form.rb
+++ b/qa/qa/page/file/form.rb
@@ -11,7 +11,7 @@ module QA
include Shared::Editor
view 'app/views/projects/blob/_editor.html.haml' do
- element :file_name, "text_field_tag 'file_name'" # rubocop:disable QA/ElementWithPattern
+ element :file_name_field
end
view 'app/views/projects/blob/_template_selectors.html.haml' do
@@ -23,7 +23,7 @@ module QA
end
def add_name(name)
- fill_in 'file_name', with: name
+ fill_element(:file_name_field, with: name)
end
def select_template(template_type, template)
diff --git a/qa/qa/page/file/shared/editor.rb b/qa/qa/page/file/shared/editor.rb
index dab02c1e34f..f392d52747e 100644
--- a/qa/qa/page/file/shared/editor.rb
+++ b/qa/qa/page/file/shared/editor.rb
@@ -11,7 +11,7 @@ module QA
super
base.view 'app/views/projects/blob/_editor.html.haml' do
- element :editor
+ element :source_editor_preview_container
end
end
@@ -30,7 +30,7 @@ module QA
private
def text_area
- within_element :editor do
+ within_element :source_editor_preview_container do
find('textarea', visible: false)
end
end
diff --git a/qa/qa/page/group/members.rb b/qa/qa/page/group/members.rb
index 58febaddfa0..39003eb03c1 100644
--- a/qa/qa/page/group/members.rb
+++ b/qa/qa/page/group/members.rb
@@ -5,7 +5,6 @@ module QA
module Group
class Members < Page::Base
include Page::Component::InviteMembersModal
- include Page::Component::UsersSelect
include Page::Component::MembersFilter
view 'app/assets/javascripts/members/components/modals/remove_member_modal.vue' do
diff --git a/qa/qa/page/group/new.rb b/qa/qa/page/group/new.rb
index 1f17b470ada..47fda787085 100644
--- a/qa/qa/page/group/new.rb
+++ b/qa/qa/page/group/new.rb
@@ -31,7 +31,7 @@ module QA
end
def create
- click_button 'Create group'
+ click_element(:create_group_button)
end
def create_subgroup
diff --git a/qa/qa/page/issuable/new.rb b/qa/qa/page/issuable/new.rb
index f3e6a84ef54..b74dc705888 100644
--- a/qa/qa/page/issuable/new.rb
+++ b/qa/qa/page/issuable/new.rb
@@ -12,9 +12,8 @@ module QA
element :issuable_form_description_field
end
- view 'app/views/shared/issuable/_milestone_dropdown.html.haml' do
+ view 'app/assets/javascripts/sidebar/components/milestone/milestone_dropdown.vue' do
element :issuable_milestone_dropdown
- element :issuable_milestone_dropdown_content
end
view 'app/views/shared/issuable/_label_dropdown.html.haml' do
@@ -38,9 +37,9 @@ module QA
end
def choose_milestone(milestone)
- click_element :issuable_milestone_dropdown
- within_element(:issuable_milestone_dropdown_content) do
- click_on milestone.title
+ within_element(:issuable_milestone_dropdown) do
+ click_button 'Select milestone'
+ click_button milestone.title
end
end
diff --git a/qa/qa/page/label/index.rb b/qa/qa/page/label/index.rb
index e19bc0838c9..70df2e4dc9e 100644
--- a/qa/qa/page/label/index.rb
+++ b/qa/qa/page/label/index.rb
@@ -23,7 +23,7 @@ module QA
# This can cause webdriver to miss the hit so we wait for the svg to load (implicitly with has_element?)
# before clicking the button.
within_element(:label_svg_content) do
- has_element?(:js_lazy_loaded)
+ has_element?(:js_lazy_loaded_content)
end
click_element :create_new_label_button
diff --git a/qa/qa/page/main/menu.rb b/qa/qa/page/main/menu.rb
index 2f618224a73..ecd71e7c2f4 100644
--- a/qa/qa/page/main/menu.rb
+++ b/qa/qa/page/main/menu.rb
@@ -64,12 +64,7 @@ module QA
def go_to_groups
within_groups_menu do
- # Remove if statement once :remove_extra_primary_submenu_options ff is enabled by default
- if has_element?(:menu_item_link, title: 'Your groups')
- click_element(:menu_item_link, title: 'Your groups')
- else
- click_element(:menu_item_link, title: 'View all groups')
- end
+ click_element(:menu_item_link, title: 'View all groups')
end
end
@@ -80,12 +75,7 @@ module QA
def go_to_projects
within_projects_menu do
- # Remove if statement once :remove_extra_primary_submenu_options ff is enabled by default
- if has_element?(:menu_item_link, title: 'Your projects')
- click_element(:menu_item_link, title: 'Your projects')
- else
- click_element(:menu_item_link, title: 'View all projects')
- end
+ click_element(:menu_item_link, title: 'View all projects')
end
end
diff --git a/qa/qa/page/profile/two_factor_auth.rb b/qa/qa/page/profile/two_factor_auth.rb
index 63593bf0482..16aa60262d8 100644
--- a/qa/qa/page/profile/two_factor_auth.rb
+++ b/qa/qa/page/profile/two_factor_auth.rb
@@ -23,7 +23,14 @@ module QA
end
def click_configure_it_later_button
+ # TO DO: Investigate why button does not appear sometimes:
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/382698
+ return unless has_element?(:configure_it_later_button)
+
click_element :configure_it_later_button
+ wait_until(max_duration: 10, message: "Waiting for create a group page") do
+ has_text?("Welcome to GitLab") && has_text?("Create a group")
+ end
end
def otp_secret_content
diff --git a/qa/qa/page/project/branches/show.rb b/qa/qa/page/project/branches/show.rb
index 4bf8abb555b..7163bc7464d 100644
--- a/qa/qa/page/project/branches/show.rb
+++ b/qa/qa/page/project/branches/show.rb
@@ -5,8 +5,6 @@ module QA
module Project
module Branches
class Show < Page::Base
- include Page::Component::ConfirmModal
-
view 'app/assets/javascripts/branches/components/delete_branch_button.vue' do
element :delete_branch_button
end
@@ -16,22 +14,24 @@ module QA
end
view 'app/views/projects/branches/_branch.html.haml' do
- element :branch_name
+ element :badge_content
+ element :branch_container
+ element :branch_link
end
view 'app/views/projects/branches/_panel.html.haml' do
- element :all_branches
+ element :all_branches_container
end
- view 'app/views/projects/branches/index.html.haml' do
- element :delete_merged_branches
+ view 'app/assets/javascripts/branches/components/delete_merged_branches.vue' do
+ element :delete_merged_branches_button
+ element :delete_merged_branches_input
+ element :delete_merged_branches_confirmation_button
end
def delete_branch(branch_name)
- within_element(:all_branches) do
- within(".js-branch-#{branch_name}") do
- click_element(:delete_branch_button)
- end
+ within_element(:branch_container, name: branch_name) do
+ click_element(:delete_branch_button)
end
click_element(:delete_branch_confirmation_button)
@@ -41,23 +41,23 @@ module QA
def has_no_branch?(branch_name, reload: false)
wait_until(reload: reload) do
- within_element(:all_branches) do
- has_no_element?(:branch_name, text: branch_name)
+ within_element(:all_branches_container) do
+ has_no_element?(:branch_link, text: branch_name)
end
end
end
def has_branch_with_badge?(branch_name, badge)
- within_element(:all_branches) do
- within(".js-branch-#{branch_name} .badge") do
- has_text?(badge)
- end
+ within_element(:branch_container, name: branch_name) do
+ has_element?(:badge_content, text: badge)
end
end
- def delete_merged_branches
- click_element(:delete_merged_branches)
- click_confirmation_ok_button
+ def delete_merged_branches(branches_length)
+ click_element(:delete_merged_branches_button)
+ fill_element(:delete_merged_branches_input, branches_length)
+ click_element(:delete_merged_branches_confirmation_button)
+ finished_loading?
end
end
end
diff --git a/qa/qa/page/project/import/github.rb b/qa/qa/page/project/import/github.rb
index 89d044bac8d..75468c74814 100644
--- a/qa/qa/page/project/import/github.rb
+++ b/qa/qa/page/project/import/github.rb
@@ -85,8 +85,15 @@ module QA
end
end
end
-
alias_method :wait_for_success, :has_imported_project?
+
+ # Select advanced github import option
+ #
+ # @param [Symbol] option_name
+ # @return [void]
+ def select_advanced_option(option_name)
+ check_element(:advanced_settings_checkbox, true, option_name: option_name)
+ end
end
end
end
diff --git a/qa/qa/page/project/new.rb b/qa/qa/page/project/new.rb
index fd650d8ca20..f7434656be3 100644
--- a/qa/qa/page/project/new.rb
+++ b/qa/qa/page/project/new.rb
@@ -64,6 +64,8 @@ module QA
end
def add_description(description)
+ return unless has_element?(:project_description, wait: 1)
+
fill_in 'project_description', with: description
end
diff --git a/qa/qa/page/project/pipeline/show.rb b/qa/qa/page/project/pipeline/show.rb
index 06d154f5178..33ba27a788a 100644
--- a/qa/qa/page/project/pipeline/show.rb
+++ b/qa/qa/page/project/pipeline/show.rb
@@ -35,10 +35,6 @@ module QA
element :status_icon, 'ci-status-icon-${status}' # rubocop:disable QA/ElementWithPattern
end
- view 'app/views/projects/pipelines/_info.html.haml' do
- element :pipeline_badges
- end
-
view 'app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue' do
element :job_dropdown_container
element :jobs_dropdown_menu
@@ -68,12 +64,6 @@ module QA
has_no_element?(:job_link, text: job_name)
end
- def has_tag?(tag_name)
- within_element(:pipeline_badges) do
- has_selector?('.badge', text: tag_name)
- end
- end
-
def linked_pipelines
all_elements(:linked_pipeline_container, minimum: 1)
end
diff --git a/qa/qa/page/project/pipeline_editor/show.rb b/qa/qa/page/project/pipeline_editor/show.rb
index 70c0c5abb52..8fa20aa57cf 100644
--- a/qa/qa/page/project/pipeline_editor/show.rb
+++ b/qa/qa/page/project/pipeline_editor/show.rb
@@ -91,6 +91,8 @@ module QA
def write_to_editor(text)
find_element(:source_editor_container).fill_in(with: text)
+
+ wait_for_requests
end
def submit_changes
@@ -140,6 +142,10 @@ module QA
all_elements(:job_container, minimum: 1).any? { |item| item.text.match(/#{name}/i) }
end
+ def has_no_alert?
+ has_no_css?('.gl-alert-body')
+ end
+
def tab_alert_message
within_element(:file_editor_container) do
find('.gl-alert-body').text
@@ -174,9 +180,13 @@ module QA
within_element(:file_editor_container) do
find('.nav-item', text: name).click
end
+
+ wait_for_requests
end
end
end
end
end
end
+
+QA::Page::Project::PipelineEditor::Show.prepend_mod_with('Page::Project::PipelineEditor::Show', namespace: QA)
diff --git a/qa/qa/page/project/settings/advanced.rb b/qa/qa/page/project/settings/advanced.rb
index 9d8ed132ffd..fcfcecdc183 100644
--- a/qa/qa/page/project/settings/advanced.rb
+++ b/qa/qa/page/project/settings/advanced.rb
@@ -6,10 +6,11 @@ module QA
module Settings
class Advanced < Page::Base
include QA::Page::Component::ConfirmModal
+ include QA::Page::Component::DeleteModal
include Component::NamespaceSelect
- view 'app/assets/javascripts/vue_shared/components/confirm_danger/confirm_danger.vue' do
- element :confirm_danger_button
+ view 'app/assets/javascripts/projects/components/shared/delete_button.vue' do
+ element :delete_button
end
view 'app/views/projects/edit.html.haml' do
@@ -20,7 +21,6 @@ module QA
view 'app/views/projects/settings/_archive.html.haml' do
element :archive_project_link
element :unarchive_project_link
- element :archive_project_content
end
view 'app/views/projects/_export.html.haml' do
@@ -29,6 +29,14 @@ module QA
element :export_project_content
end
+ view 'app/views/projects/_transfer.html.haml' do
+ element :transfer_project_content
+ end
+
+ view 'app/assets/javascripts/projects/settings/components/transfer_project_form.vue' do
+ element :transfer_project_button
+ end
+
def update_project_path_to(path)
fill_project_path(path)
click_change_path_button
@@ -45,13 +53,16 @@ module QA
def transfer_project!(project_name, namespace)
QA::Runtime::Logger.info "Transferring project: #{project_name} to namespace: #{namespace}"
- click_element_coordinates(:archive_project_content)
+ scroll_to_transfer_project_content
# Workaround for a failure to search when there are no spaces around the /
# https://gitlab.com/gitlab-org/gitlab/-/issues/218965
select_namespace(namespace.gsub(%r{([^\s])/([^\s])}, '\1 / \2'))
- click_element(:confirm_danger_button)
+ wait_for_enabled_transfer_project_button
+
+ click_element :transfer_project_button
+
fill_confirmation_text(project_name)
confirm_transfer
end
@@ -77,6 +88,29 @@ module QA
click_element :unarchive_project_link
click_confirmation_ok_button
end
+
+ def delete_project!(project_name)
+ click_element :delete_button
+ fill_confirmation_path(project_name)
+ wait_for_delete_button_enabled
+ confirm_delete
+ end
+
+ private
+
+ def scroll_to_transfer_project_content
+ retry_until(sleep_interval: 1, message: 'Waiting for transfer project content to display') do
+ has_element?(:transfer_project_content, wait: 3)
+ end
+
+ scroll_to_element :transfer_project_content
+ end
+
+ def wait_for_enabled_transfer_project_button
+ retry_until(sleep_interval: 1, message: 'Waiting for transfer project button to be enabled') do
+ has_element?(:transfer_project_button, disabled: false, wait: 3)
+ end
+ end
end
end
end
diff --git a/qa/qa/page/project/settings/ci_variables.rb b/qa/qa/page/project/settings/ci_variables.rb
index 7ee015ceb98..316920ffa90 100644
--- a/qa/qa/page/project/settings/ci_variables.rb
+++ b/qa/qa/page/project/settings/ci_variables.rb
@@ -14,13 +14,6 @@ module QA
element :ci_variable_delete_button
end
- view 'app/assets/javascripts/ci_variable_list/components/legacy_ci_variable_table.vue' do
- element :ci_variable_table_content
- element :add_ci_variable_button
- element :edit_ci_variable_button
- element :reveal_ci_variable_value_button
- end
-
def fill_variable(key, value, masked = false)
within_element(:ci_variable_key_field) { find('input').set key }
fill_element :ci_variable_value_field, value
diff --git a/qa/qa/page/project/settings/default_branch.rb b/qa/qa/page/project/settings/default_branch.rb
index 575f9006c84..69ac45ce72d 100644
--- a/qa/qa/page/project/settings/default_branch.rb
+++ b/qa/qa/page/project/settings/default_branch.rb
@@ -5,7 +5,7 @@ module QA
module Project
module Settings
class DefaultBranch < Page::Base
- view 'app/views/projects/default_branch/_show.html.haml' do
+ view 'app/views/projects/branch_defaults/_show.html.haml' do
element :save_changes_button
end
@@ -18,8 +18,8 @@ module QA
end
def set_default_branch(branch)
- click_button :default_branch_dropdown
- fill_in :ref_selector_searchbox, with: branch
+ find_element(:default_branch_dropdown, visible: false).click
+ find_element(:ref_selector_searchbox, visible: false).fill_in(with: branch)
click_button branch
end
diff --git a/qa/qa/page/project/settings/mirroring_repositories.rb b/qa/qa/page/project/settings/mirroring_repositories.rb
index f55faff19e7..61ee3e4f03c 100644
--- a/qa/qa/page/project/settings/mirroring_repositories.rb
+++ b/qa/qa/page/project/settings/mirroring_repositories.rb
@@ -6,25 +6,25 @@ module QA
module Settings
class MirroringRepositories < Page::Base
view 'app/views/projects/mirrors/_authentication_method.html.haml' do
- element :authentication_method
- element :password
+ element :authentication_method_field
+ element :password_field
end
view 'app/views/projects/mirrors/_mirror_repos.html.haml' do
- element :mirror_repository_url_input
+ element :mirror_repository_url_field
element :mirror_repository_button
end
view 'app/views/projects/mirrors/_mirror_repos_list.html.haml' do
- element :mirror_repository_url_cell
- element :mirror_last_update_at_cell
- element :mirror_error_badge
- element :mirrored_repository_row
+ element :mirror_repository_url_content
+ element :mirror_last_update_at_content
+ element :mirror_error_badge_content
+ element :mirrored_repository_row_container
element :copy_public_key_button
end
view 'app/views/projects/mirrors/_mirror_repos_form.html.haml' do
- element :mirror_direction
+ element :mirror_direction_field
end
view 'app/views/shared/_remote_mirror_update_button.html.haml' do
@@ -37,28 +37,23 @@ module QA
element :fingerprints_list
end
- view 'app/views/projects/mirrors/_authentication_method.html.haml' do
- element :authentication_method
- element :password
- end
-
def repository_url=(value)
- fill_element :mirror_repository_url_input, value
+ fill_element :mirror_repository_url_field, value
end
def password=(value)
- fill_element :password, value
+ fill_element :password_field, value
end
def mirror_direction=(value)
raise ArgumentError, "Mirror direction must be 'Push' or 'Pull'" unless %w[Push Pull].include?(value)
- select_element(:mirror_direction, value)
+ select_element(:mirror_direction_field, value)
# Changing the mirror direction causes the fields below to change,
# and that change is animated, so we need to wait for the animation
# to complete otherwise changes to those fields could fail
- wait_for_animated_element :authentication_method
+ wait_for_animated_element :authentication_method_field
end
def authentication_method=(value)
@@ -66,13 +61,13 @@ module QA
raise ArgumentError, "Authentication method must be 'SSH public key', 'Password', or 'None'"
end
- select_element(:authentication_method, value)
+ select_element(:authentication_method_field, value)
end
def public_key(url)
row_index = find_repository_row_index url
- within_element_by_index(:mirrored_repository_row, row_index) do
+ within_element_by_index(:mirrored_repository_row_container, row_index) do
find_element(:copy_public_key_button)['data-clipboard-text']
end
end
@@ -92,7 +87,7 @@ module QA
def update(url)
row_index = find_repository_row_index(url)
- within_element_by_index(:mirrored_repository_row, row_index) do
+ within_element_by_index(:mirrored_repository_row_container, row_index) do
# When a repository is first mirrored, the update process might
# already be started, so the button is already "clicked"
click_element :update_now_button unless has_element? :updating_button
@@ -105,16 +100,16 @@ module QA
row_index = find_repository_row_index(url)
wait_until(sleep_interval: 1) do
- within_element_by_index(:mirrored_repository_row, row_index) do
- last_update = find_element(:mirror_last_update_at_cell, wait: 0)
+ within_element_by_index(:mirrored_repository_row_container, row_index) do
+ last_update = find_element(:mirror_last_update_at_content, wait: 0)
last_update.has_text?('just now') || last_update.has_text?('seconds')
end
end
# Fail early if the page still shows that there has been no update
- within_element_by_index(:mirrored_repository_row, row_index) do
- find_element(:mirror_last_update_at_cell, wait: 0).assert_no_text('Never')
- assert_no_element(:mirror_error_badge)
+ within_element_by_index(:mirrored_repository_row_container, row_index) do
+ find_element(:mirror_last_update_at_content, wait: 0).assert_no_text('Never')
+ assert_no_element(:mirror_error_badge_content)
end
end
@@ -122,7 +117,7 @@ module QA
def find_repository_row_index(target_url)
wait_until(max_duration: 5, reload: false) do
- all_elements(:mirror_repository_url_cell, minimum: 1).index do |url|
+ all_elements(:mirror_repository_url_content, minimum: 1).index do |url|
# The url might be a sanitized url but the target_url won't be so
# we compare just the paths instead of the full url
URI.parse(url.text).path == target_url.path
diff --git a/qa/qa/page/project/settings/protected_branches.rb b/qa/qa/page/project/settings/protected_branches.rb
index a78d8a6ccf4..4fbf656210f 100644
--- a/qa/qa/page/project/settings/protected_branches.rb
+++ b/qa/qa/page/project/settings/protected_branches.rb
@@ -6,8 +6,8 @@ module QA
module Settings
class ProtectedBranches < Page::Base
view 'app/views/projects/protected_branches/shared/_dropdown.html.haml' do
- element :protected_branch_select
element :protected_branch_dropdown
+ element :protected_branch_dropdown_content
end
view 'app/views/projects/protected_branches/_create_protected_branch.html.haml' do
@@ -22,9 +22,9 @@ module QA
end
def select_branch(branch_name)
- click_element :protected_branch_select
+ click_element :protected_branch_dropdown
- within_element(:protected_branch_dropdown) do
+ within_element(:protected_branch_dropdown_content) do
click_on branch_name
end
end
diff --git a/qa/qa/page/project/settings/repository.rb b/qa/qa/page/project/settings/repository.rb
index de5b4f37076..bf1c3130485 100644
--- a/qa/qa/page/project/settings/repository.rb
+++ b/qa/qa/page/project/settings/repository.rb
@@ -58,7 +58,7 @@ module QA
end
def expand_default_branch(&block)
- within('#default-branch-settings') do
+ within('#branch-defaults-settings') do
find('.btn-default').click do
DefaultBranch.perform(&block)
end
diff --git a/qa/qa/page/project/show.rb b/qa/qa/page/project/show.rb
index 26c2da07b34..a82fa7f5cf3 100644
--- a/qa/qa/page/project/show.rb
+++ b/qa/qa/page/project/show.rb
@@ -32,7 +32,7 @@ module QA
end
view 'app/views/projects/_last_push.html.haml' do
- element :create_merge_request
+ element :create_merge_request_button
end
view 'app/views/projects/_home_panel.html.haml' do
@@ -54,7 +54,7 @@ module QA
end
view 'app/views/projects/empty.html.haml' do
- element :quick_actions
+ element :quick_actions_container
end
view 'app/assets/javascripts/repository/components/breadcrumbs.vue' do
@@ -72,7 +72,7 @@ module QA
end
view 'app/views/projects/blob/viewers/_loading.html.haml' do
- element :spinner
+ element :spinner_placeholder
end
view 'app/views/projects/buttons/_download.html.haml' do
@@ -80,11 +80,11 @@ module QA
end
def wait_for_viewers_to_load
- has_no_element?(:spinner, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
+ has_no_element?(:spinner_placeholder, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
end
def create_first_new_file!
- within_element(:quick_actions) do
+ within_element(:quick_actions_container) do
click_link_with_text 'New file'
end
end
@@ -122,7 +122,7 @@ module QA
end
def has_create_merge_request_button?
- has_css?(element_selector_css(:create_merge_request))
+ has_css?(element_selector_css(:create_merge_request_button))
end
def has_file?(name)
@@ -152,7 +152,7 @@ module QA
has_create_merge_request_button?
end
- click_element :create_merge_request
+ click_element :create_merge_request_button
end
def open_web_ide!
diff --git a/qa/qa/page/project/sub_menus/ci_cd.rb b/qa/qa/page/project/sub_menus/ci_cd.rb
index c8c90df2c1f..4ae51798e54 100644
--- a/qa/qa/page/project/sub_menus/ci_cd.rb
+++ b/qa/qa/page/project/sub_menus/ci_cd.rb
@@ -43,3 +43,5 @@ module QA
end
end
end
+
+QA::Page::Project::SubMenus::CiCd.prepend_mod_with('Page::Project::SubMenus::CiCd', namespace: QA)
diff --git a/qa/qa/page/project/sub_menus/issues.rb b/qa/qa/page/project/sub_menus/issues.rb
index 48cdf9791f8..7fa19063653 100644
--- a/qa/qa/page/project/sub_menus/issues.rb
+++ b/qa/qa/page/project/sub_menus/issues.rb
@@ -74,3 +74,5 @@ module QA
end
end
end
+
+QA::Page::Project::SubMenus::Issues.prepend_mod_with('Page::Project::SubMenus::Issues', namespace: QA)
diff --git a/qa/qa/resource/approval_configuration.rb b/qa/qa/resource/approval_configuration.rb
new file mode 100644
index 00000000000..89b8201d7d2
--- /dev/null
+++ b/qa/qa/resource/approval_configuration.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+module QA
+ module Resource
+ # Helper for approval configuration which exists on project and mr level
+ module ApprovalConfiguration
+ include ApiFabricator
+
+ def api_approval_configuration_path
+ "#{api_get_path}/approvals"
+ end
+
+ def api_approval_rules_path
+ "#{api_get_path}/approval_rules"
+ end
+
+ # Approval configuration
+ #
+ # @return [Hash]
+ def approval_configuration
+ parse_body(api_get_from(api_approval_configuration_path))
+ end
+
+ # Update approvals configuration
+ # MR: https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-approval-configuration
+ # Project: https://docs.gitlab.com/ee/api/merge_request_approvals.html#change-configuration
+ #
+ # @param [Hash] configuration
+ # @return [Hash]
+ def update_approval_configuration(configuration)
+ api_post_to(api_approval_configuration_path, configuration)
+ end
+
+ # Approval rules
+ #
+ # @return [Array<Hash>]
+ def fetch_approval_rules
+ parse_body(api_get_from(api_approval_rules_path))
+ end
+
+ # Create approval rules
+ #
+ # @return [Hash]
+ def create_approval_rules
+ raise("Trying to create approval rules but no rules set!") unless approval_rules
+
+ rule = { approvals_required: 1, name: "Approval rule for mr #{title}" }
+ rule[:user_ids] = approval_rules[:users].map(&:id) if approval_rules[:users]
+ rule[:group_ids] = approval_rules[:group].map(&:full_path) if approval_rules[:groups]
+
+ api_post_to(api_approvals_path, rule)
+ end
+ end
+ end
+end
diff --git a/qa/qa/resource/base.rb b/qa/qa/resource/base.rb
index 6025dd6ec40..4a1a60f4da1 100644
--- a/qa/qa/resource/base.rb
+++ b/qa/qa/resource/base.rb
@@ -22,8 +22,20 @@ module QA
new.tap(&prepare_block)
end
+ def fabricate_via_api_unless_fips!
+ if QA::Support::FIPS.enabled?
+ fabricate!
+ else
+ fabricate_via_api!
+ end
+ end
+
def fabricate!(*args, &prepare_block)
- fabricate_via_api!(*args, &prepare_block)
+ if QA::Support::FIPS.enabled?
+ fabricate_via_browser_ui!(*args, &prepare_block)
+ else
+ fabricate_via_api!(*args, &prepare_block)
+ end
rescue NotImplementedError
fabricate_via_browser_ui!(*args, &prepare_block)
end
@@ -95,7 +107,7 @@ module QA
Support::FabricationTracker.save_fabrication(:"#{fabrication_method}_fabrication", fabrication_time)
- unless resource.retrieved_from_cache
+ unless resource.retrieved_from_cache || QA::Support::FIPS.enabled?
Tools::TestResourceDataProcessor.collect(
resource: resource,
info: resource.identifier,
diff --git a/qa/qa/resource/group.rb b/qa/qa/resource/group.rb
index 84416c0600d..9d1a6868562 100644
--- a/qa/qa/resource/group.rb
+++ b/qa/qa/resource/group.rb
@@ -18,8 +18,14 @@ module QA
end
attribute :sandbox do
- Sandbox.fabricate_via_api! do |sandbox|
- sandbox.api_client = api_client
+ if QA::Support::FIPS.enabled?
+ Resource::Sandbox.fabricate! do |sandbox|
+ sandbox.path = Runtime::Namespace.sandbox_name
+ end
+ else
+ Sandbox.fabricate_via_api! do |sandbox|
+ sandbox.api_client = api_client
+ end
end
end
diff --git a/qa/qa/resource/members.rb b/qa/qa/resource/members.rb
index d9300f80f5d..4bf9c2bed6b 100644
--- a/qa/qa/resource/members.rb
+++ b/qa/qa/resource/members.rb
@@ -10,8 +10,8 @@ module QA
def add_member(user, access_level = AccessLevel::DEVELOPER)
Support::Retrier.retry_until do
QA::Runtime::Logger.info(%(Adding user #{user.username} to #{full_path} #{self.class.name}))
-
- response = post Runtime::API::Request.new(api_client, api_members_path).url, { user_id: user.id, access_level: access_level }
+ response = post Runtime::API::Request.new(api_client, api_members_path).url,
+{ user_id: user.id, access_level: access_level }
break true if response.code == QA::Support::API::HTTP_STATUS_CREATED
break true if response.body.include?('Member already exists')
end
@@ -31,7 +31,8 @@ module QA
Support::Retrier.retry_until do
QA::Runtime::Logger.info(%(Sharing #{self.class.name} with #{group.name}))
- response = post Runtime::API::Request.new(api_client, api_share_path).url, { group_id: group.id, group_access: access_level }
+ response = post Runtime::API::Request.new(api_client, api_share_path).url,
+{ group_id: group.id, group_access: access_level }
response.code == QA::Support::API::HTTP_STATUS_CREATED
end
end
diff --git a/qa/qa/resource/merge_request.rb b/qa/qa/resource/merge_request.rb
index 5d6dc12ac9c..fcfda106523 100644
--- a/qa/qa/resource/merge_request.rb
+++ b/qa/qa/resource/merge_request.rb
@@ -3,6 +3,8 @@
module QA
module Resource
class MergeRequest < Issuable
+ include ApprovalConfiguration
+
attr_accessor :approval_rules,
:source_branch,
:target_new_branch,
@@ -11,7 +13,8 @@ module QA
:milestone,
:labels,
:file_name,
- :file_content
+ :file_content,
+ :reviewer_ids
attr_writer :no_preparation,
:wait_for_merge,
@@ -22,7 +25,8 @@ module QA
:description,
:merge_when_pipeline_succeeds,
:merge_status,
- :state
+ :state,
+ :reviewers
attribute :project do
Project.fabricate_via_api! do |resource|
@@ -121,12 +125,21 @@ module QA
"/projects/#{project.id}/merge_requests"
end
+ def api_reviewers_path
+ "#{api_get_path}/reviewers"
+ end
+
+ def api_approve_path
+ "#{api_get_path}/approve"
+ end
+
def api_post_body
{
description: description,
source_branch: source_branch,
target_branch: target_branch,
- title: title
+ title: title,
+ reviewer_ids: reviewer_ids
}
end
@@ -152,6 +165,17 @@ module QA
end
end
+ # Approve merge request
+ #
+ # Due to internal implementation of api client, project needs to have
+ # setting 'Prevent approval by author' set to false since we use same user that created merge request which
+ # is set through approval configuration
+ #
+ # @return [void]
+ def approve
+ api_post_to(api_approve_path, {})
+ end
+
def fabricate_large_merge_request
@project = Resource::ImportProject.fabricate_via_browser_ui!
# Setting the name here, since otherwise some tests will look for an existing file in
diff --git a/qa/qa/resource/project.rb b/qa/qa/resource/project.rb
index e5df95f1fa5..3cbc002fa86 100644
--- a/qa/qa/resource/project.rb
+++ b/qa/qa/resource/project.rb
@@ -7,6 +7,7 @@ module QA
include Integrations::Project
include Members
include Visibility
+ include ApprovalConfiguration
attr_accessor :initialize_with_readme,
:auto_devops_enabled,
@@ -479,6 +480,16 @@ module QA
end
end
+ def remove_via_browser_ui!
+ Page::Project::Menu.perform(&:go_to_general_settings)
+
+ Page::Project::Settings::Main.perform(&:expand_advanced_settings)
+
+ Page::Project::Settings::Advanced.perform do |advanced|
+ advanced.delete_project!(full_path)
+ end
+ end
+
# Calls the API endpoint that triggers the backend service that performs repository housekeeping (garbage
# collection and similar tasks).
def perform_housekeeping
diff --git a/qa/qa/resource/project_imported_from_github.rb b/qa/qa/resource/project_imported_from_github.rb
index 9ba9723f0cc..1e6b2ff620e 100644
--- a/qa/qa/resource/project_imported_from_github.rb
+++ b/qa/qa/resource/project_imported_from_github.rb
@@ -18,6 +18,11 @@ module QA
Page::Project::Import::Github.perform do |import_page|
import_page.add_personal_access_token(github_personal_access_token)
+
+ import_page.select_advanced_option(:single_endpoint_issue_events_import) if issue_events_import
+ import_page.select_advanced_option(:single_endpoint_notes_import) if full_notes_import
+ import_page.select_advanced_option(:attachments_import) if attachments_import
+
import_page.import!(github_repository_path, group.full_path, name)
import_page.wait_for_success(github_repository_path, wait: 240)
end
diff --git a/qa/qa/resource/sandbox.rb b/qa/qa/resource/sandbox.rb
index 2080e279e99..18526448b00 100644
--- a/qa/qa/resource/sandbox.rb
+++ b/qa/qa/resource/sandbox.rb
@@ -10,7 +10,9 @@ module QA
class << self
# Force top level group creation via UI if test is executed on dot_com environment
def fabricate!(*args, &prepare_block)
- return fabricate_via_browser_ui!(*args, &prepare_block) if Specs::Helpers::ContextSelector.dot_com?
+ if Specs::Helpers::ContextSelector.dot_com? || QA::Support::FIPS.enabled?
+ return fabricate_via_browser_ui!(*args, &prepare_block)
+ end
fabricate_via_api!(*args, &prepare_block)
rescue NotImplementedError
diff --git a/qa/qa/resource/user.rb b/qa/qa/resource/user.rb
index 71a5e1c8930..c8babbc0b16 100644
--- a/qa/qa/resource/user.rb
+++ b/qa/qa/resource/user.rb
@@ -79,11 +79,22 @@ module QA
defined?(@username) && defined?(@password)
end
+ def has_user?(user)
+ Flow::Login.while_signed_in_as_admin do
+ Page::Main::Menu.perform(&:go_to_admin_area)
+ Page::Admin::Menu.perform(&:go_to_users_overview)
+ Page::Admin::Overview::Users::Index.perform do |index|
+ index.search_user(user.username)
+ index.has_username?(user.username)
+ end
+ end
+ end
+
def fabricate!
# Don't try to log-out if we're not logged-in
Page::Main::Menu.perform(&:sign_out) if Page::Main::Menu.perform { |p| p.has_personal_area?(wait: 0) }
- if credentials_given?
+ if credentials_given? || has_user?(self)
Page::Main::Login.perform do |login|
login.sign_in_using_credentials(user: self)
end
@@ -144,7 +155,7 @@ module QA
end
def self.fabricate_or_use(username = nil, password = nil)
- if Runtime::Env.signup_disabled?
+ if Runtime::Env.signup_disabled? || !QA::Support::FIPS.enabled?
fabricate_via_api! do |user|
user.username = username
user.password = password
diff --git a/qa/qa/runtime/allure_report.rb b/qa/qa/runtime/allure_report.rb
index 10f47ca56ba..a9152a5555c 100644
--- a/qa/qa/runtime/allure_report.rb
+++ b/qa/qa/runtime/allure_report.rb
@@ -96,9 +96,14 @@ module QA
return {} unless Env.admin_personal_access_token || Env.personal_access_token
client = Env.admin_personal_access_token ? API::Client.as_admin : API::Client.new
- response = get(API::Request.new(client, '/version').url)
+ response = get(API::Request.new(client, '/metadata').url)
- JSON.parse(response.body, symbolize_names: true)
+ JSON.parse(response.body, symbolize_names: true).then do |metadata|
+ {
+ **metadata.slice(:version, :revision),
+ kas_version: metadata.dig(:kas, :version)
+ }.compact
+ end
rescue StandardError, ArgumentError => e
Logger.error("Failed to attach version info to allure report: #{e}")
{}
diff --git a/qa/qa/runtime/browser.rb b/qa/qa/runtime/browser.rb
index 0dbc3cdf09d..d2ddaf86353 100644
--- a/qa/qa/runtime/browser.rb
+++ b/qa/qa/runtime/browser.rb
@@ -111,6 +111,7 @@ module QA
if QA::Runtime::Env.remote_mobile_device_name
capabilities['platformName'] = 'Android'
+ capabilities['appium:automationName'] = 'UiAutomator2'
capabilities['appium:deviceName'] = QA::Runtime::Env.remote_mobile_device_name
capabilities['appium:platformVersion'] = 'latest'
else
@@ -120,6 +121,7 @@ module QA
when :safari
if QA::Runtime::Env.remote_mobile_device_name
capabilities['platformName'] = 'iOS'
+ capabilities['appium:automationName'] = 'XCUITest'
capabilities['appium:deviceName'] = QA::Runtime::Env.remote_mobile_device_name
capabilities['appium:platformVersion'] = 'latest'
end
diff --git a/qa/qa/runtime/env.rb b/qa/qa/runtime/env.rb
index 782ba1cf2fa..7cb7625118e 100644
--- a/qa/qa/runtime/env.rb
+++ b/qa/qa/runtime/env.rb
@@ -443,7 +443,11 @@ module QA
end
def export_metrics?
- running_in_ci? && enabled?(ENV['QA_EXPORT_TEST_METRICS'], default: true)
+ enabled?(ENV['QA_EXPORT_TEST_METRICS'], default: false)
+ end
+
+ def save_metrics_json?
+ enabled?(ENV['QA_SAVE_TEST_METRICS'], default: false)
end
def ee_activation_code
diff --git a/qa/qa/runtime/key/ed25519.rb b/qa/qa/runtime/key/ed25519.rb
index 3a3567d55da..f59d7b3688d 100644
--- a/qa/qa/runtime/key/ed25519.rb
+++ b/qa/qa/runtime/key/ed25519.rb
@@ -4,8 +4,8 @@ module QA
module Runtime
module Key
class ED25519 < Base
- def initialize
- super('ed25519', 256)
+ def initialize(bits = 256)
+ super('ed25519', bits)
end
end
end
diff --git a/qa/qa/scenario/bootable.rb b/qa/qa/scenario/bootable.rb
index 8eedfab3cff..c6050798e22 100644
--- a/qa/qa/scenario/bootable.rb
+++ b/qa/qa/scenario/bootable.rb
@@ -19,7 +19,8 @@ module QA
options.to_a.each do |opt|
# The argument for the --set-feature-flags option should look something like "flag1=enabled,flag2=disabled"
# Here we translate that string into a hash, e.g.: { 'flag1' => 'enabled', 'flag2' => "disabled" }
- if opt.name == :set_feature_flags
+ case opt.name
+ when :set_feature_flags
parser.on(opt.arg, opt.desc) do |flags|
value = flags.split(',').each_with_object({}) do |pair, hash|
flag_name, flag_value = pair.split('=')
@@ -31,7 +32,7 @@ module QA
end
next
- elsif opt.name == :count_examples_only || opt.name == :test_metadata_only
+ when :count_examples_only, :test_metadata_only
parser.on(opt.arg, opt.desc) do |value|
QA::Runtime::Env.dry_run = true
Runtime::Scenario.define(opt.name, value)
diff --git a/qa/qa/scenario/test/instance/gitlab_pages.rb b/qa/qa/scenario/test/instance/gitlab_pages.rb
new file mode 100644
index 00000000000..487fd739626
--- /dev/null
+++ b/qa/qa/scenario/test/instance/gitlab_pages.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module QA
+ module Scenario
+ module Test
+ module Instance
+ class GitlabPages < All
+ tags :gitlab_pages
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/specs/features/api/12_systems/gitaly/automatic_failover_and_recovery_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/automatic_failover_and_recovery_spec.rb
index 2058d58d5d6..8bbef4ae429 100644
--- a/qa/qa/specs/features/api/12_systems/gitaly/automatic_failover_and_recovery_spec.rb
+++ b/qa/qa/specs/features/api/12_systems/gitaly/automatic_failover_and_recovery_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Systems' do
+ RSpec.describe 'Systems', product_group: :gitaly do
context 'with Gitaly automatic failover and recovery', :orchestrated, :gitaly_cluster do
# Variables shared between contexts. They're used and shared between
# contexts so they can't be `let` variables.
diff --git a/qa/qa/specs/features/api/12_systems/gitaly/backend_node_recovery_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/backend_node_recovery_spec.rb
index 0b4bdf550f8..1abc7b8a912 100644
--- a/qa/qa/specs/features/api/12_systems/gitaly/backend_node_recovery_spec.rb
+++ b/qa/qa/specs/features/api/12_systems/gitaly/backend_node_recovery_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Systems' do
+ RSpec.describe 'Systems', product_group: :gitaly do
describe 'Gitaly backend node recovery', :orchestrated, :gitaly_cluster, :skip_live_env do
let(:praefect_manager) { Service::PraefectManager.new }
let(:project) do
diff --git a/qa/qa/specs/features/api/12_systems/gitaly/changing_repository_storage_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/changing_repository_storage_spec.rb
index 18ec8e0a8b4..01c50c0cd6a 100644
--- a/qa/qa/specs/features/api/12_systems/gitaly/changing_repository_storage_spec.rb
+++ b/qa/qa/specs/features/api/12_systems/gitaly/changing_repository_storage_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Systems' do
+ RSpec.describe 'Systems', product_group: :gitaly do
describe 'Changing Gitaly repository storage', :requires_admin, except: { job: 'review-qa-*' } do
praefect_manager = Service::PraefectManager.new
diff --git a/qa/qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb
index 692297e40ce..397fdb909ac 100644
--- a/qa/qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb
+++ b/qa/qa/specs/features/api/12_systems/gitaly/distributed_reads_spec.rb
@@ -3,7 +3,7 @@
require 'parallel'
module QA
- RSpec.describe 'Systems' do
+ RSpec.describe 'Systems', product_group: :gitaly do
describe 'Gitaly distributed reads', :orchestrated, :gitaly_cluster, :skip_live_env, :requires_admin do
let(:number_of_reads_per_loop) { 9 }
let(:praefect_manager) { Service::PraefectManager.new }
@@ -45,7 +45,11 @@ module QA
end
it 'does not read from the unhealthy node',
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347834' do
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347834',
+ quarantine: {
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/378174',
+ type: :flaky
+ } do
pre_read_data = praefect_manager.query_read_distribution
read_from_project(project, number_of_reads_per_loop * 10)
diff --git a/qa/qa/specs/features/api/12_systems/gitaly/gitaly_mtls_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/gitaly_mtls_spec.rb
index a4b39554453..48d08136d28 100644
--- a/qa/qa/specs/features/api/12_systems/gitaly/gitaly_mtls_spec.rb
+++ b/qa/qa/specs/features/api/12_systems/gitaly/gitaly_mtls_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Systems' do
- describe 'Gitaly using mTLS', :orchestrated, :mtls do
+ describe 'Gitaly using mTLS', :orchestrated, :mtls, product_group: :gitaly do
let(:intial_commit_message) { 'Initial commit' }
let(:first_added_commit_message) { 'commit over git' }
let(:second_added_commit_message) { 'commit over api' }
diff --git a/qa/qa/specs/features/api/12_systems/gitaly/praefect_connectivity_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/praefect_connectivity_spec.rb
index f25b50f584d..bd00b3781f7 100644
--- a/qa/qa/specs/features/api/12_systems/gitaly/praefect_connectivity_spec.rb
+++ b/qa/qa/specs/features/api/12_systems/gitaly/praefect_connectivity_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Systems' do
- describe 'Praefect connectivity commands', :orchestrated, :gitaly_cluster do
+ describe 'Praefect connectivity commands', :orchestrated, :gitaly_cluster, product_group: :gitaly do
praefect_manager = Service::PraefectManager.new
before do
diff --git a/qa/qa/specs/features/api/12_systems/gitaly/praefect_dataloss_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/praefect_dataloss_spec.rb
index 944c58ebc83..6ba192a9dd6 100644
--- a/qa/qa/specs/features/api/12_systems/gitaly/praefect_dataloss_spec.rb
+++ b/qa/qa/specs/features/api/12_systems/gitaly/praefect_dataloss_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Systems' do
- describe 'Praefect dataloss commands', :orchestrated, :gitaly_cluster do
+ describe 'Praefect dataloss commands', :orchestrated, :gitaly_cluster, product_group: :gitaly do
let(:praefect_manager) { Service::PraefectManager.new }
let(:project) do
diff --git a/qa/qa/specs/features/api/12_systems/gitaly/praefect_replication_queue_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/praefect_replication_queue_spec.rb
index f4efcf74956..94bae38c5c8 100644
--- a/qa/qa/specs/features/api/12_systems/gitaly/praefect_replication_queue_spec.rb
+++ b/qa/qa/specs/features/api/12_systems/gitaly/praefect_replication_queue_spec.rb
@@ -3,7 +3,7 @@
require 'parallel'
module QA
- RSpec.describe 'Systems' do
+ RSpec.describe 'Systems', product_group: :gitaly do
describe 'Gitaly Cluster replication queue', :orchestrated, :gitaly_cluster, :skip_live_env do
let(:praefect_manager) { Service::PraefectManager.new }
let(:project) do
diff --git a/qa/qa/specs/features/api/12_systems/gitaly/praefect_repo_sync_spec.rb b/qa/qa/specs/features/api/12_systems/gitaly/praefect_repo_sync_spec.rb
index 064743ae469..40fc6bf2637 100644
--- a/qa/qa/specs/features/api/12_systems/gitaly/praefect_repo_sync_spec.rb
+++ b/qa/qa/specs/features/api/12_systems/gitaly/praefect_repo_sync_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Systems' do
- describe 'Praefect repository commands', :orchestrated, :gitaly_cluster do
+ describe 'Praefect repository commands', :orchestrated, :gitaly_cluster, product_group: :gitaly do
let(:praefect_manager) { Service::PraefectManager.new }
let(:repo1) do
diff --git a/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb b/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb
index bf95a215c8e..e0db758dde3 100644
--- a/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/group_access_token_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Manage' do
- describe 'Group access token' do
+ describe 'Group access token', product_group: :authentication_and_authorization do
let(:group_access_token) { QA::Resource::GroupAccessToken.fabricate_via_api! }
let(:api_client) { Runtime::API::Client.new(:gitlab, personal_access_token: group_access_token.token) }
let(:project) do
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 c3e41e9298b..ab50e02c790 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,165 +1,197 @@
# frozen_string_literal: true
module QA
- # Spec uses real github.com, which means outage of github.com can actually block deployment
- # Keep spec in reliable bucket but don't run in blocking pipelines
- RSpec.describe 'Manage', :github, :reliable, :skip_live_env, :requires_admin, product_group: :import do
- describe 'Project import', issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/353583' do
- let!(:api_client) { Runtime::API::Client.as_admin }
- let!(:group) { Resource::Group.fabricate_via_api! { |resource| resource.api_client = api_client } }
- let!(:user) do
- Resource::User.fabricate_via_api! do |resource|
- resource.api_client = api_client
- resource.hard_delete_on_api_removal = true
+ # https://github.com/gitlab-qa-github/import-test <- project under test
+ #
+ RSpec.describe 'Manage', product_group: :import do
+ describe 'GitHub import', :reliable do
+ include_context 'with github import'
+
+ context 'when imported via api' do
+ it 'imports project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347670' do
+ imported_project.reload! # import the project
+
+ expect { imported_project.project_import_status[:import_status] }.to eventually_eq('finished')
+ .within(max_duration: 240, sleep_interval: 1)
+
+ aggregate_failures do
+ verify_status_data
+ verify_repository_import
+ verify_protected_branches_import
+ verify_commits_import
+ verify_labels_import
+ verify_issues_import
+ verify_milestones_import
+ verify_wikis_import
+ verify_merge_requests_import
+ verify_release_import
+ end
end
- end
- let(:imported_project) do
- Resource::ProjectImportedFromGithub.fabricate_via_api! do |project|
- project.name = 'imported-project'
- project.group = group
- project.github_personal_access_token = Runtime::Env.github_access_token
- project.github_repository_path = 'gitlab-qa-github/import-test'
- project.api_client = Runtime::API::Client.new(user: user)
- project.issue_events_import = true
- project.full_notes_import = true
+ def verify_status_data
+ stats = imported_project.project_import_status.dig(:stats, :imported)
+ expect(stats).to include(
+ issue: 1,
+ label: 9,
+ milestone: 1,
+ note: 3,
+ pull_request: 1,
+ pull_request_review: 1,
+ diff_note: 1,
+ release: 1
+ )
end
- end
-
- before do
- group.add_member(user, Resource::Members::AccessLevel::MAINTAINER)
- end
- after do
- user.remove_via_api!
- end
-
- it 'imports Github repo via api', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347670' do
- imported_project.reload! # import the project
-
- expect { imported_project.project_import_status[:import_status] }.to eventually_eq('finished')
- .within(max_duration: 240, sleep_interval: 1)
-
- aggregate_failures do
- verify_status_data
- verify_repository_import
- verify_protected_branches_import
- verify_commits_import
- verify_labels_import
- verify_issues_import
- verify_milestones_import
- verify_wikis_import
- verify_merge_requests_import
+ def verify_repository_import
+ expect(imported_project.reload!.description).to eq('Project for github import test')
+ expect(imported_project.api_response[:import_error]).to be_nil
end
- end
- def verify_status_data
- stats = imported_project.project_import_status.dig(:stats, :imported)
- expect(stats).to include(
- issue: 1,
- label: 9,
- milestone: 1,
- note: 3,
- pull_request: 1,
- pull_request_review: 1,
- diff_note: 1,
- release: 1
- )
- end
+ def verify_protected_branches_import
+ imported_branches = imported_project.protected_branches.map do |branch|
+ branch.slice(:name, :allow_force_push)
+ end
+ actual_branches = [
+ {
+ name: 'main',
+ allow_force_push: false
+ },
+ {
+ name: 'release',
+ allow_force_push: true
+ }
+ ]
- def verify_repository_import
- expect(imported_project.reload!.description).to eq('Project for github import test')
- expect(imported_project.api_response[:import_error]).to be_nil
- end
+ expect(imported_branches).to match_array(actual_branches)
+ end
- def verify_protected_branches_import
- branches = imported_project.protected_branches.map do |branch|
- branch.slice(:name, :allow_force_push, :code_owner_approval_required)
+ def verify_commits_import
+ expect(imported_project.commits.length).to eq(2)
end
- expect(branches.first).to include(
- {
- name: 'main'
- # TODO: Add validation once https://gitlab.com/groups/gitlab-org/-/epics/8585 is closed
- # At the moment both options are always set to false regardless of state in github
- # allow_force_push: true,
- # code_owner_approval_required: true
- }
- )
- end
- def verify_commits_import
- expect(imported_project.commits.length).to eq(2)
- end
+ def verify_labels_import
+ labels = imported_project.labels.map { |label| label.slice(:name, :color) }
+
+ expect(labels).to include(
+ { name: 'bug', color: '#d73a4a' },
+ { name: 'documentation', color: '#0075ca' },
+ { name: 'duplicate', color: '#cfd3d7' },
+ { name: 'enhancement', color: '#a2eeef' },
+ { name: 'good first issue', color: '#7057ff' },
+ { name: 'help wanted', color: '#008672' },
+ { name: 'invalid', color: '#e4e669' },
+ { name: 'question', color: '#d876e3' },
+ { name: 'wontfix', color: '#ffffff' }
+ )
+ end
- def verify_labels_import
- labels = imported_project.labels.map { |label| label.slice(:name, :color) }
-
- expect(labels).to include(
- { name: 'bug', color: '#d73a4a' },
- { name: 'documentation', color: '#0075ca' },
- { name: 'duplicate', color: '#cfd3d7' },
- { name: 'enhancement', color: '#a2eeef' },
- { name: 'good first issue', color: '#7057ff' },
- { name: 'help wanted', color: '#008672' },
- { name: 'invalid', color: '#e4e669' },
- { name: 'question', color: '#d876e3' },
- { name: 'wontfix', color: '#ffffff' }
- )
- end
+ def verify_milestones_import
+ milestones = imported_project.milestones
- def verify_issues_import
- issues = imported_project.issues
+ expect(milestones.length).to eq(1)
+ expect(milestones.first).to include(title: '0.0.1', description: nil, state: 'active')
+ end
- expect(issues.length).to eq(1)
- expect(issues.first).to include(
- title: 'Test issue',
- description: "*Created by: gitlab-qa-github*\n\nTest issue description",
- labels: ['good first issue', 'help wanted', 'question'],
- user_notes_count: 2
- )
- end
+ def verify_wikis_import
+ wikis = imported_project.wikis
- def verify_milestones_import
- milestones = imported_project.milestones
+ expect(wikis.length).to eq(1)
+ expect(wikis.first).to include(title: 'Home', format: 'markdown')
+ end
- expect(milestones.length).to eq(1)
- expect(milestones.first).to include(title: '0.0.1', description: nil, state: 'active')
- end
+ def verify_issues_import
+ issues = imported_project.issues
+ issue = Resource::Issue.init do |resource|
+ resource.project = imported_project
+ resource.iid = issues.first[:iid]
+ resource.api_client = user_api_client
+ end.reload!
+ comments, events = fetch_events_and_comments(issue)
+
+ expect(issues.length).to eq(1)
+ expect(issue.api_resource).to include(
+ title: 'Test issue',
+ description: "*Created by: gitlab-qa-github*\n\nTest issue description",
+ labels: ['good first issue', 'help wanted', 'question']
+ )
+ expect(comments).to match_array(
+ [
+ "*Created by: gitlab-qa-github*\n\nSome test comment",
+ "*Created by: gitlab-qa-github*\n\nAnother test comment"
+ ]
+ )
+ expect(events).to match_array(
+ [
+ { name: "add_label", label: "question" },
+ { name: "add_label", label: "good first issue" },
+ { name: "add_label", label: "help wanted" },
+ { name: "add_milestone", label: "0.0.1" },
+ { name: "closed" },
+ { name: "reopened" }
+ ]
+ )
+ end
- def verify_wikis_import
- wikis = imported_project.wikis
+ def verify_merge_requests_import
+ merge_requests = imported_project.merge_requests
+ merge_request = Resource::MergeRequest.init do |mr|
+ mr.project = imported_project
+ mr.iid = merge_requests.first[:iid]
+ mr.api_client = user_api_client
+ end.reload!
+ comments, events = fetch_events_and_comments(merge_request)
+
+ expect(merge_requests.length).to eq(1)
+ expect(merge_request.api_resource).to include(
+ title: 'Test pull request',
+ state: 'opened',
+ target_branch: 'main',
+ source_branch: 'gitlab-qa-github-patch-1',
+ labels: %w[documentation],
+ description: "*Created by: gitlab-qa-github*\n\nTest pull request body"
+ )
+ expect(comments).to match_array(
+ [
+ "*Created by: gitlab-qa-github*\n\n**Review:** Commented\n\nGood but needs some improvement",
+ "*Created by: gitlab-qa-github*\n\n```suggestion:-0+0\nProject for GitHub import test to GitLab\r\n```",
+ "*Created by: gitlab-qa-github*\n\nSome test PR comment"
+ ]
+ )
+ expect(events).to match_array(
+ [
+ { name: "add_label", label: "documentation" },
+ { name: "add_milestone", label: "0.0.1" }
+ ]
+ )
+ end
- expect(wikis.length).to eq(1)
- expect(wikis.first).to include(title: 'Home', format: 'markdown')
- end
+ def verify_release_import
+ releases = imported_project.releases
+
+ expect(releases.length).to eq(1)
+ expect(releases.first).to include(
+ tag_name: "0.0.1",
+ name: "0.0.1",
+ description: "Initial release",
+ created_at: "2022-03-07T07:59:22.000Z",
+ released_at: "2022-03-07T08:02:09.000Z"
+ )
+ end
- def verify_merge_requests_import
- merge_requests = imported_project.merge_requests
- merge_request = Resource::MergeRequest.init do |mr|
- mr.project = imported_project
- mr.iid = merge_requests.first[:iid]
- mr.api_client = api_client
- end.reload!
- mr_comments = merge_request.comments.map { |comment| comment[:body] }
-
- expect(merge_requests.length).to eq(1)
- expect(merge_request.api_resource).to include(
- title: 'Test pull request',
- state: 'opened',
- target_branch: 'main',
- source_branch: 'gitlab-qa-github-patch-1',
- labels: %w[documentation],
- description: <<~DSC.strip
- *Created by: gitlab-qa-github*\n\nTest pull request body
- DSC
- )
- expect(mr_comments).to match_array(
- [
- "*Created by: gitlab-qa-github*\n\n**Review:** Commented\n\nGood but needs some improvement",
- "*Created by: gitlab-qa-github*\n\n```suggestion:-0+0\nProject for GitHub import test to GitLab\r\n```",
- "*Created by: gitlab-qa-github*\n\nSome test PR comment"
+ # Fetch events and comments from issue or mr
+ #
+ # @param [QA::Resource::Issuable] issuable
+ # @return [Array]
+ def fetch_events_and_comments(issuable)
+ comments = issuable.comments.map { |comment| comment[:body] }
+ events = [
+ *issuable.label_events.map { |e| { name: "#{e[:action]}_label", label: e.dig(:label, :name) } },
+ *issuable.state_events.map { |e| { name: e[:state] } },
+ *issuable.milestone_events.map { |e| { name: "#{e[:action]}_milestone", label: e.dig(:milestone, :title) } }
]
- )
+
+ [comments, events]
+ end
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 c1f11b15068..887eeda51e3 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
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require_relative 'gitlab_project_migration_common'
-
module QA
RSpec.describe 'Manage' do
describe 'Gitlab migration', product_group: :import do
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb
index 5689fa169ce..116a00f8385 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
@@ -98,12 +98,17 @@ module QA
let(:mrs) { fetch_mrs(imported_project, target_api_client) }
let(:issues) { fetch_issues(imported_project, target_api_client) }
+ let(:import_failures) { imported_group.import_details.sum([]) { |details| details[:failures] } }
+
before do
destination_group.add_member(user, Resource::Members::AccessLevel::MAINTAINER)
end
# rubocop:disable RSpec/InstanceVariable
after do |example|
+ # Log failures for easier debugging
+ Runtime::Logger.error("Import failures: #{import_failures}") if example.exception && !import_failures.empty?
+
next unless defined?(@import_time)
# save data for comparison notification creation
@@ -112,7 +117,7 @@ module QA
{
importer: :gitlab,
import_time: @import_time,
- errors: imported_group.import_details.sum([]) { |details| details[:failures] },
+ errors: import_failures,
source: {
name: "GitLab Source",
project_name: source_project.path_with_namespace,
@@ -154,7 +159,7 @@ module QA
end
# rubocop:enable RSpec/InstanceVariable
- it "migrates large gitlab group via api", testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/358842' do
+ it "migrates large gitlab group via api", testcase: "https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/358842" do
start = Time.now
# trigger import and log imported group path
@@ -165,7 +170,11 @@ module QA
# wait for import to finish and save import time
logger.info("== Waiting for import to be finished ==")
- expect { imported_group.import_status }.to eventually_eq('finished').within(import_wait_duration)
+ expect { imported_group.import_status }.not_to eventually_eq("started").within(import_wait_duration)
+ # finished status actually means success, don't wait for finished status explicitly
+ # because test would wait full duration if returned status is "failed"
+ expect(imported_group.import_status).to eq("finished")
+
@import_time = Time.now - start
aggregate_failures do
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb
index aa4d3becbe7..07e54ead9c8 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_members_spec.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require_relative 'gitlab_project_migration_common'
-
module QA
RSpec.describe 'Manage' do
describe 'Gitlab migration', product_group: :import do
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_mr_spec.rb
index 92cba005832..f44786939dc 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
@@ -1,49 +1,66 @@
# frozen_string_literal: true
-require_relative 'gitlab_project_migration_common'
-
module QA
RSpec.describe 'Manage' do
describe 'Gitlab migration', product_group: :import do
include_context 'with gitlab project migration'
- context 'with merge request' do
- let!(:source_project_with_readme) { true }
-
- let!(:other_user) do
- Resource::User
- .fabricate_via_api! { |usr| usr.api_client = admin_api_client }
- .tap do |usr|
- usr.set_public_email
- source_project.add_member(usr, Resource::Members::AccessLevel::MAINTAINER)
- end
- end
+ let!(:source_project_with_readme) { true }
- let!(:source_mr) do
- Resource::MergeRequest.fabricate_via_api! do |mr|
- mr.project = source_project
- mr.api_client = Runtime::API::Client.new(user: other_user)
+ # We create additional user so that object being migrated is not owned by the user doing migration
+ let!(:other_user) do
+ Resource::User
+ .fabricate_via_api! { |usr| usr.api_client = admin_api_client }
+ .tap do |usr|
+ usr.set_public_email
+ source_project.add_member(usr, Resource::Members::AccessLevel::MAINTAINER)
end
+ end
+
+ let!(:source_mr) do
+ Resource::MergeRequest.fabricate_via_api! do |mr|
+ mr.project = source_project
+ mr.api_client = Runtime::API::Client.new(user: other_user)
+ mr.reviewer_ids = [other_user.id]
end
+ end
- let!(:source_comment) { source_mr.add_comment('This is a test comment!') }
+ let!(:source_comment) { source_mr.add_comment(body: 'This is a test comment!') }
- let(:imported_mrs) { imported_project.merge_requests }
- let(:imported_mr_comments) { imported_mr.comments.map { |note| note.except(:id, :noteable_id) } }
- let(:source_mr_comments) { source_mr.comments.map { |note| note.except(:id, :noteable_id) } }
+ let(:imported_mrs) { imported_project.merge_requests }
+ let(:imported_mr_comments) { imported_mr.comments.map { |note| note.except(:id, :noteable_id) } }
+ let(:source_mr_comments) { source_mr.comments.map { |note| note.except(:id, :noteable_id) } }
- let(:imported_mr) do
- Resource::MergeRequest.init do |mr|
- mr.project = imported_project
- mr.iid = imported_mrs.first[:iid]
- mr.api_client = api_client
- end
+ let(:imported_mr) do
+ Resource::MergeRequest.init do |mr|
+ mr.project = imported_project
+ mr.iid = imported_mrs.first[:iid]
+ mr.api_client = api_client
end
+ end
- after do
- other_user.remove_via_api!
+ let(:imported_mr_reviewers) { imported_mr.reviewers.map { |r| r.slice(:name, :username) } }
+ let(:source_mr_reviewers) { [{ name: other_user.name, username: other_user.username }] }
+
+ let(:imported_mr_approvers) do
+ imported_mr.approval_configuration[:approved_by].map do |usr|
+ { username: usr.dig(:user, :username), name: usr.dig(:user, :name) }
end
+ end
+
+ before do
+ source_project.update_approval_configuration(
+ merge_requests_author_approval: true,
+ approvals_before_merge: 1
+ )
+ source_mr.approve
+ end
+ after do
+ other_user.remove_via_api!
+ end
+
+ context 'with merge request' do
it(
'successfully imports merge request',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348478'
@@ -54,7 +71,9 @@ module QA
aggregate_failures do
expect(imported_mr).to eq(source_mr.reload!)
- expect(imported_mr_comments).to eq(source_mr_comments)
+ expect(imported_mr_comments).to match_array(source_mr_comments)
+ expect(imported_mr_reviewers).to eq(source_mr_reviewers)
+ expect(imported_mr_approvers).to eq([{ username: other_user.username, name: other_user.name }])
end
end
end
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb
index 3db4ff4351e..7b79e6967c7 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_pipeline_spec.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require_relative 'gitlab_project_migration_common'
-
module QA
RSpec.describe 'Manage' do
describe 'Gitlab migration', product_group: :import do
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 3e0df3d1e13..2b7818d1ed2 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
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require_relative 'gitlab_project_migration_common'
-
module QA
RSpec.describe 'Manage' do
describe 'Gitlab migration', product_group: :import do
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb
index 91dcfe6a1a3..36036a2321e 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/migration/gitlab_migration_release_spec.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-require_relative 'gitlab_project_migration_common'
-
module QA
RSpec.describe 'Manage' do
describe 'Gitlab migration', product_group: :import do
diff --git a/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb b/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb
index 756bbe2164a..e210ba882bb 100644
--- a/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/project_access_token_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Manage' do
- describe 'Project access token' do
+ describe 'Project access token', product_group: :authentication_and_authorization do
before(:all) do
@project_access_token = QA::Resource::ProjectAccessToken.fabricate_via_api! do |pat|
pat.project = Resource::ReusableProject.fabricate_via_api!
diff --git a/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb b/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb
index 28c20344b29..b7d0d72297a 100644
--- a/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb
+++ b/qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Manage' do
- describe 'User', :requires_admin, :reliable do
+ describe 'User', :requires_admin, :reliable, product_group: :authentication_and_authorization do
before(:all) do
admin_api_client = Runtime::API::Client.as_admin
diff --git a/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb b/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb
index 073669f033c..6935f9de486 100644
--- a/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb
+++ b/qa/qa/specs/features/api/2_plan/closes_issue_via_pushing_a_commit_spec.rb
@@ -6,7 +6,7 @@ module QA
RSpec.describe 'Plan' do
include Support::API
- describe 'Issue' do
+ describe 'Issue', product_group: :project_management do
let(:issue) do
Resource::Issue.fabricate_via_api!
end
diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb
index ab9af872753..a1060c1d890 100644
--- a/qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_labels_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request push options' do
+ describe 'Merge request push options', product_group: :code_review do
# If run locally on GDK, push options need to be enabled on the host with the following command:
#
# git config --global receive.advertisepushoptions true
diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb
index 6eb3060fb59..0a82c5d6736 100644
--- a/qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_mwps_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request push options' do
+ describe 'Merge request push options', product_group: :code_review do
# If run locally on GDK, push options need to be enabled on the host with the following command:
#
# git config --global receive.advertisepushoptions true
diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb
index 708dd7aa8af..11328c2f517 100644
--- a/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_remove_source_branch_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request push options' do
+ describe 'Merge request push options', product_group: :code_review do
# If run locally on GDK, push options need to be enabled on the host with the following command:
#
# git config --global receive.advertisepushoptions true
diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb
index 97d461c5113..eb7d3da0f97 100644
--- a/qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_target_branch_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request push options' do
+ describe 'Merge request push options', product_group: :code_review do
# If run locally on GDK, push options need to be enabled on the host with the following command:
#
# git config --global receive.advertisepushoptions true
diff --git a/qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb b/qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb
index 9d534e9ea6b..dd297f47975 100644
--- a/qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb
+++ b/qa/qa/specs/features/api/3_create/merge_request/push_options_title_description_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request push options' do
+ describe 'Merge request push options', product_group: :code_review do
# If run locally on GDK, push options need to be enabled on the host with the following command:
#
# git config --global receive.advertisepushoptions true
diff --git a/qa/qa/specs/features/api/3_create/repository/storage_size_spec.rb b/qa/qa/specs/features/api/3_create/repository/storage_size_spec.rb
index df3b5a4e7fb..8c7a58be43a 100644
--- a/qa/qa/specs/features/api/3_create/repository/storage_size_spec.rb
+++ b/qa/qa/specs/features/api/3_create/repository/storage_size_spec.rb
@@ -46,6 +46,7 @@ module QA
local_size = Git::Repository.perform do |repository|
repository.uri = project.repository_http_location.uri
repository.use_default_credentials
+ repository.default_branch = project.default_branch
repository.clone
repository.configure_identity('GitLab QA', 'root@gitlab.com')
# These two commits add a total of 1mb, but half of that is the same as content that has already been added to
diff --git a/qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb b/qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb
index bfa408e1c92..60dace0938e 100644
--- a/qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb
+++ b/qa/qa/specs/features/api/3_create/snippet/snippet_repository_storage_move_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'Snippet repository storage', :requires_admin, :orchestrated, :repository_storage do
let(:source_storage) { { type: :gitaly, name: 'default' } }
let(:destination_storage) { { type: :gitaly, name: QA::Runtime::Env.additional_repository_storage } }
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 8ca0ae1f052..8890b3ff317 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 do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
describe 'Pipeline API defined variable inheritance' do
include_context 'variable inheritance test prep'
diff --git a/qa/qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb b/qa/qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb
index 7c3fb9ebeba..a360c662cf8 100644
--- a/qa/qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb
+++ b/qa/qa/specs/features/api/4_verify/cancel_pipeline_when_block_user_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :requires_admin do
+ RSpec.describe 'Verify', :requires_admin, product_group: :pipeline_execution do
describe 'When user is blocked' do
let!(:admin_api_client) { Runtime::API::Client.as_admin }
let!(:user_api_client) { Runtime::API::Client.new(:gitlab, user: user) }
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 9722f62d5a7..4ae97f589cf 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,10 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, feature_flag: {
- name: 'ci_stop_expanding_file_vars_for_runners',
- scope: :project
- } do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
describe 'Pipeline with project file variables' do
let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
@@ -14,7 +11,7 @@ module QA
end
end
- let(:runner) do
+ let!(:runner) do
Resource::Runner.fabricate! do |runner|
runner.project = project
runner.name = executor
@@ -60,59 +57,30 @@ module QA
end
end
- after do
- runner.remove_via_api!
+ before do
+ add_file_variables
+ add_ci_file
+ trigger_pipeline
+ wait_for_pipeline
end
- shared_examples 'variables are read correctly' do
- it 'shows in job log accordingly' do
- job = Resource::Job.fabricate_via_api! do |job|
- job.project = project
- job.id = project.job_by_name('test')[:id]
- end
-
- aggregate_failures do
- trace = job.trace
- expect(trace).to have_content('run something -f hello, this is test')
- expect(trace).to have_content('docker run --tlscacert="This is secret"')
- expect(trace).to have_content('run --output=This is secret.crt')
- expect(trace).to have_content('Will read private key from hello, this is test')
- end
- end
+ after do
+ runner.remove_via_api!
end
- # FF does not change current behavior
- # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/94198#note_1057609893
- #
- # TODO: Remove when FF is removed
- # TODO: Archive testcase issue when FF is removed
- # Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/369907
- context 'when FF is on', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370787' do
- before do
- Runtime::Feature.enable(:ci_stop_expanding_file_vars_for_runners, project: project)
-
- runner
- add_file_variables
- add_ci_file
- trigger_pipeline
- wait_for_pipeline
+ it 'shows in job log accordingly', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370791' do
+ job = Resource::Job.fabricate_via_api! do |job|
+ job.project = project
+ job.id = project.job_by_name('test')[:id]
end
- it_behaves_like 'variables are read correctly'
- end
-
- # TODO: Refactor when FF is removed
- # TODO: Update testcase issue title and description to not refer to FF status
- context 'when FF is off', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/370791' do
- before do
- runner
- add_file_variables
- add_ci_file
- trigger_pipeline
- wait_for_pipeline
+ aggregate_failures do
+ trace = job.trace
+ expect(trace).to have_content('run something -f hello, this is test')
+ expect(trace).to have_content('docker run --tlscacert="This is secret"')
+ expect(trace).to have_content('run --output=This is secret.crt')
+ expect(trace).to have_content('Will read private key from hello, this is test')
end
-
- it_behaves_like 'variables are read correctly'
end
private
diff --git a/qa/qa/specs/features/api/4_verify/remove_runner_spec.rb b/qa/qa/specs/features/api/4_verify/remove_runner_spec.rb
index 6e6198328e5..eb1b085c35c 100644
--- a/qa/qa/specs/features/api/4_verify/remove_runner_spec.rb
+++ b/qa/qa/specs/features/api/4_verify/remove_runner_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner do
+ RSpec.describe 'Verify', :runner, product_group: :runner do
describe 'Runner removal' do
include Support::API
diff --git a/qa/qa/specs/features/api/5_package/container_registry_spec.rb b/qa/qa/specs/features/api/5_package/container_registry_spec.rb
index 8412c0b2872..0264b8b1ff2 100644
--- a/qa/qa/specs/features/api/5_package/container_registry_spec.rb
+++ b/qa/qa/specs/features/api/5_package/container_registry_spec.rb
@@ -3,7 +3,7 @@
require 'airborne'
module QA
- RSpec.describe 'Package', :reliable, only: { subdomain: %i[staging staging-canary pre] } do
+ RSpec.describe 'Package', :reliable, only: { subdomain: %i[staging staging-canary pre] }, product_group: :container_registry do
include Support::API
include Support::Helpers::MaskToken
diff --git a/qa/qa/specs/features/api/8_monitor/metrics_spec.rb b/qa/qa/specs/features/api/8_monitor/metrics_spec.rb
index 1235b996958..932d2a8e4f4 100644
--- a/qa/qa/specs/features/api/8_monitor/metrics_spec.rb
+++ b/qa/qa/specs/features/api/8_monitor/metrics_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'GitLab Metrics', :aggregate_failures, :orchestrated, :metrics do
+ RSpec.describe 'GitLab Metrics', :aggregate_failures, :orchestrated, :metrics, product_group: :observability do
let(:web_uri) { URI.parse(Runtime::Scenario.gitlab_address) }
let(:endpoint) do
"#{web_uri.scheme}://#{web_uri.host}:#{port}#{path}"
diff --git a/qa/qa/specs/features/browser_ui/14_analytics/performance_bar_spec.rb b/qa/qa/specs/features/browser_ui/14_analytics/performance_bar_spec.rb
index 867c54102ae..6dfc58fbfea 100644
--- a/qa/qa/specs/features/browser_ui/14_analytics/performance_bar_spec.rb
+++ b/qa/qa/specs/features/browser_ui/14_analytics/performance_bar_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Analytics' do
- describe 'Performance bar display', :requires_admin, :skip_live_env do
+ describe 'Performance bar display', :requires_admin, :skip_live_env, product_group: :product_analytics do
context 'when logged in as an admin user' do
# performance metrics: pg, gitaly, redis, rugged (feature flagged), total (not always provided)
let(:minimum_metrics_count) { 3 }
diff --git a/qa/qa/specs/features/browser_ui/14_analytics/service_ping_default_enabled_spec.rb b/qa/qa/specs/features/browser_ui/14_analytics/service_ping_default_enabled_spec.rb
index 7826aca3601..8e4b76cdb7c 100644
--- a/qa/qa/specs/features/browser_ui/14_analytics/service_ping_default_enabled_spec.rb
+++ b/qa/qa/specs/features/browser_ui/14_analytics/service_ping_default_enabled_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Analytics' do
- describe 'Service ping default enabled' do
+ describe 'Service ping default enabled', product_group: :product_intelligence do
context 'when using default enabled from gitlab.yml config', :requires_admin, except: { job: 'review-qa-*' } do
before do
Flow::Login.sign_in_as_admin
diff --git a/qa/qa/specs/features/browser_ui/14_analytics/service_ping_disabled_spec.rb b/qa/qa/specs/features/browser_ui/14_analytics/service_ping_disabled_spec.rb
index 8b30d6a7ad7..e25bba97288 100644
--- a/qa/qa/specs/features/browser_ui/14_analytics/service_ping_disabled_spec.rb
+++ b/qa/qa/specs/features/browser_ui/14_analytics/service_ping_disabled_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Analytics' do
+ RSpec.describe 'Analytics', product_group: :product_intelligence do
describe 'Service ping disabled', :orchestrated, :service_ping_disabled, :requires_admin do
context 'when disabled from gitlab.yml config' do
before do
diff --git a/qa/qa/specs/features/browser_ui/1_manage/group/group_access_token_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/group/group_access_token_spec.rb
index 9f39d376baf..a35cde854a2 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/group/group_access_token_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/group/group_access_token_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Manage' do
- describe 'Group access tokens' do
+ describe 'Group access tokens', product_group: :authentication_and_authorization do
let(:group_access_token) { QA::Resource::GroupAccessToken.fabricate_via_browser_ui! }
it(
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb
index f459c0c71eb..0f3d6a104a7 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_recovery_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Manage', :requires_admin, :skip_live_env, :reliable do
- describe '2FA' do
+ describe '2FA', product_group: :authentication_and_authorization do
let(:owner_user) do
Resource::User.fabricate_via_api! do |usr|
usr.api_client = admin_api_client
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb
index 6c69e4c59d9..9484f15f35d 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/2fa_ssh_recovery_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- context 'Manage', :reliable, :requires_admin, :skip_live_env do
+ context 'Manage', :reliable, :requires_admin, :skip_live_env, product_group: :authentication_and_authorization do
describe '2FA' do
let!(:user) { Resource::User.fabricate_via_api! }
let!(:user_api_client) { Runtime::API::Client.new(:gitlab, user: user) }
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb
index 98b5ecc8f0d..7b91156d926 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Manage', :smoke, :mobile do
+ RSpec.describe 'Manage', :smoke, :mobile, product_group: :authentication_and_authorization do
describe 'basic user login' do
it 'user logs in using basic credentials and logs out', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347880' do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb
index 56883917153..cf9282c1149 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_in_with_2fa_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Manage', :requires_admin, :skip_live_env do
+ RSpec.describe 'Manage', :requires_admin, :skip_live_env, product_group: :authentication_and_authorization do
describe '2FA' do
let(:admin_api_client) { Runtime::API::Client.as_admin }
let(:owner_api_client) { Runtime::API::Client.new(:gitlab, user: owner_user) }
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb
index 7ecad1101c9..3d2e8c13900 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_gitlab_via_ldap_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Manage', :orchestrated, :ldap_no_tls, :ldap_tls do
+ RSpec.describe 'Manage', :orchestrated, :ldap_no_tls, :ldap_tls, product_group: :authentication_and_authorization do
describe 'LDAP login' do
it 'user logs into GitLab using LDAP credentials', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347892' do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb
index 80e660c1c1d..388c9f6b486 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/log_into_mattermost_via_gitlab_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Manage', :orchestrated, :mattermost do
+ RSpec.describe 'Manage', :orchestrated, :mattermost, product_group: :authentication_and_authorization do
describe 'Mattermost login' do
it 'user logs into Mattermost using GitLab OAuth', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347891' do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb
index d6cb65c2788..ca10a3f3d65 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/login_via_instance_wide_saml_sso_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Manage', :orchestrated, :instance_saml do
+ RSpec.describe 'Manage', :orchestrated, :instance_saml, product_group: :authentication_and_authorization do
describe 'Instance wide SAML SSO' do
it(
'user logs in to gitlab with SAML SSO',
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb
index 1d30b915594..dd39b0c8835 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/maintain_log_in_mixed_env_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Manage', only: { subdomain: %i[staging staging-canary] }, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/344213', type: :stale } do
- describe 'basic user' do
+ describe 'basic user', product_group: :authentication_and_authorization do
it 'remains logged in when redirected from canary to non-canary node', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347626' do
Runtime::Browser.visit(:gitlab, Page::Main::Login)
diff --git a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb
index 295702aa328..e0242008785 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/login/register_spec.rb
@@ -13,7 +13,7 @@ module QA
end
end
- RSpec.describe 'Manage', :skip_signup_disabled, :requires_admin do
+ RSpec.describe 'Manage', :skip_signup_disabled, :requires_admin, product_group: :authentication_and_authorization do
describe 'while LDAP is enabled', :orchestrated, :ldap_no_tls, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347934' do
before do
# When LDAP is enabled, a previous test might have created a token for the LDAP 'tanuki' user who is not an admin
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb
index 7c6b0d77219..686cc8fe11e 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_spec.rb
@@ -7,9 +7,6 @@ module QA
it 'creates a new project' do
Page::Project::Show.perform do |project_page|
expect(project_page).to have_content(project_name)
- expect(project_page).to have_content(
- /Project \S?#{project_name}\S+ was successfully created/
- )
expect(project_page).to have_content('The repository for this project is empty')
end
end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb
index 6ac11fea7e1..15563e3aa2a 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/import_github_repo_spec.rb
@@ -4,61 +4,89 @@ module QA
# Spec uses real github.com, which means outage of github can actually block deployment
# Keep spec in reliable bucket but don't run in blocking pipelines
RSpec.describe 'Manage', :github, :reliable, :skip_live_env, :requires_admin, product_group: :import do
- describe 'Project import' do
- let(:github_repo) { 'gitlab-qa-github/import-test' }
- let(:api_client) { Runtime::API::Client.as_admin }
- let(:group) { Resource::Group.fabricate_via_api! { |resource| resource.api_client = api_client } }
- let(:user) do
- Resource::User.fabricate_via_api! do |resource|
- resource.api_client = api_client
- resource.hard_delete_on_api_removal = true
+ describe 'GitHub import' do
+ context 'when imported via UI' do
+ let(:github_repo) { 'gitlab-qa-github/import-test' }
+ let(:api_client) { Runtime::API::Client.as_admin }
+ let(:group) { Resource::Group.fabricate_via_api! { |resource| resource.api_client = api_client } }
+ let(:user) do
+ Resource::User.fabricate_via_api! do |resource|
+ resource.api_client = api_client
+ resource.hard_delete_on_api_removal = true
+ end
end
- end
- let(:imported_project) do
- Resource::ProjectImportedFromGithub.init do |project|
- project.import = true
- project.group = group
- project.github_personal_access_token = Runtime::Env.github_access_token
- project.github_repository_path = github_repo
- project.api_client = api_client
+ let(:imported_project) do
+ Resource::ProjectImportedFromGithub.init do |project|
+ project.import = true
+ project.group = group
+ project.github_personal_access_token = Runtime::Env.github_access_token
+ project.github_repository_path = github_repo
+ project.api_client = api_client
+ end
end
- end
- before do
- group.add_member(user, Resource::Members::AccessLevel::MAINTAINER)
-
- Flow::Login.sign_in(as: user)
- Page::Main::Menu.perform(&:go_to_create_project)
- Page::Project::New.perform do |project_page|
- project_page.click_import_project
- project_page.click_github_link
+ let(:imported_issue) do
+ Resource::Issue.init do |resource|
+ resource.project = imported_project
+ resource.iid = imported_project.issues.first[:iid]
+ resource.api_client = api_client
+ end.reload!
end
- end
- after do
- user.remove_via_api!
- end
+ let(:imported_issue_events) do
+ imported_issue.label_events.map { |e| { name: "#{e[:action]}_label", label: e.dig(:label, :name) } }
+ end
- it 'imports a GitHub repo', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347877' do
- Page::Project::Import::Github.perform do |import_page|
- import_page.add_personal_access_token(Runtime::Env.github_access_token)
- import_page.import!(github_repo, group.full_path, imported_project.name)
+ before do
+ group.add_member(user, Resource::Members::AccessLevel::MAINTAINER)
- aggregate_failures do
- expect(import_page).to have_imported_project(github_repo, wait: 240)
- # validate button is present instead of navigating to avoid dealing with multiple tabs
- # which makes the test more complicated
- expect(import_page).to have_go_to_project_button(github_repo)
+ Flow::Login.sign_in(as: user)
+ Page::Main::Menu.perform(&:go_to_create_project)
+ Page::Project::New.perform do |project_page|
+ project_page.click_import_project
+ project_page.click_github_link
end
end
- imported_project.reload!.visit!
- Page::Project::Show.perform do |project|
- aggregate_failures do
- expect(project).to have_content(imported_project.name)
- expect(project).to have_content('Project for github import test')
+ after do
+ user.remove_via_api!
+ end
+
+ it 'imports a project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347877' do
+ Page::Project::Import::Github.perform do |import_page|
+ import_page.add_personal_access_token(Runtime::Env.github_access_token)
+
+ import_page.select_advanced_option(:single_endpoint_issue_events_import)
+ import_page.select_advanced_option(:single_endpoint_notes_import)
+ import_page.select_advanced_option(:attachments_import)
+
+ import_page.import!(github_repo, group.full_path, imported_project.name)
+
+ aggregate_failures do
+ expect(import_page).to have_imported_project(github_repo, wait: 240)
+ # validate button is present instead of navigating to avoid dealing with multiple tabs
+ # which makes the test more complicated
+ expect(import_page).to have_go_to_project_button(github_repo)
+ end
+ end
+
+ imported_project.reload!.visit!
+ Page::Project::Show.perform do |project|
+ aggregate_failures do
+ expect(project).to have_content(imported_project.name)
+ expect(project).to have_content('Project for github import test')
+ end
end
+
+ # Validate :single_endpoint_issue_events_import option was triggered correctly and imported the events
+ expect(imported_issue_events).to match_array(
+ [
+ { name: "add_label", label: "question" },
+ { name: "add_label", label: "good first issue" },
+ { name: "add_label", label: "help wanted" }
+ ]
+ )
end
end
end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/project_access_token_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/project_access_token_spec.rb
index 63ae90aed9c..55f63845acd 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/project/project_access_token_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/project/project_access_token_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Manage' do
- describe 'Project access tokens', :reliable do
+ describe 'Project access tokens', :reliable, product_group: :authentication_and_authorization do
let(:project_access_token) { QA::Resource::ProjectAccessToken.fabricate_via_browser_ui! }
it(
diff --git a/qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb
index 5bcea1ff094..ce5d9307769 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/user/impersonation_token_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Manage' do
- describe 'Impersonation tokens', :requires_admin do
+ describe 'Impersonation tokens', :requires_admin, product_group: :authentication_and_authorization do
let(:admin_api_client) { Runtime::API::Client.as_admin }
let!(:user) do
diff --git a/qa/qa/specs/features/browser_ui/1_manage/user/parent_group_access_termination_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/user/parent_group_access_termination_spec.rb
index 54f05f84dca..6bc695487ee 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/user/parent_group_access_termination_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/user/parent_group_access_termination_spec.rb
@@ -12,11 +12,9 @@ module QA
end
let!(:group) do
- group = QA::Resource::Group.fabricate_via_api! do |group|
+ QA::Resource::Group.fabricate_via_api! do |group|
group.path = "group-to-test-access-termination-#{SecureRandom.hex(8)}"
end
- group.sandbox.add_member(user)
- group
end
let!(:project) do
@@ -27,24 +25,20 @@ module QA
end
end
- context 'for after parent group membership termination' do
+ context 'when parent group membership is terminated' do
before do
+ group.add_member(user)
+
Flow::Login.while_signed_in_as_admin do
- group.sandbox.visit!
+ group.visit!
- Page::Group::Menu.perform(&:click_group_members_item)
+ Page::Group::Menu.perform(&:click_subgroup_members_item)
Page::Group::Members.perform do |members_page|
members_page.remove_member(user.username)
end
end
end
- after do
- user.remove_via_api!
- project.remove_via_api!
- group.remove_via_api!
- end
-
it 'is not allowed to edit the project files',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347866' do
Flow::Login.sign_in(as: user)
diff --git a/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb
index b815186cd49..b70590e65c8 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/email/trigger_email_notification_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :orchestrated, :smtp, :reliable do
+ RSpec.describe 'Plan', :orchestrated, :smtp, :reliable, product_group: :project_management do
describe 'Email Notification' do
include Support::API
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb
index 1ba110a9602..2f177d12389 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/check_mentions_for_xss_spec.rb
@@ -1,11 +1,11 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable, product_group: :project_management do
let!(:user) do
Resource::User.fabricate_via_api! do |user|
user.name = "QA User <img src=x onerror=alert(2)&lt;img src=x onerror=alert(1)&gt;"
- user.password = "test1234"
+ user.password = "pw_#{SecureRandom.hex(12)}"
user.api_client = Runtime::API::Client.as_admin
end
end
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb
index 8e8112faa48..d446a773809 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/collapse_comments_in_discussions_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable, product_group: :project_management do
describe 'collapse comments in issue discussions' do
let(:my_first_reply) { 'My first reply' }
let(:one_reply) { '1 reply' }
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb
index 3b02093054d..f7dc9157275 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/comment_issue_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable, product_group: :project_management do
describe 'Issue comments' do
before do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
index 7e4a391c390..45c3c264837 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/create_issue_spec.rb
@@ -1,10 +1,19 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :smoke do
+ RSpec.describe 'Plan', :smoke, product_group: :project_management do
describe 'Issue creation' do
- let(:project) { Resource::Project.fabricate_via_api! }
- let(:closed_issue) { Resource::Issue.fabricate_via_api! { |issue| issue.project = project } }
+ let(:project) do
+ Resource::Project.fabricate_via_api_unless_fips! do |project|
+ project.name = "project-create-issue-#{SecureRandom.hex(8)}"
+ project.personal_namespace = Runtime::User.username
+ project.description = nil
+ end
+ end
+
+ let(:closed_issue) do
+ Resource::Issue.fabricate_via_api_unless_fips! { |issue| issue.project = project }
+ end
before do
Flow::Login.sign_in
@@ -55,7 +64,7 @@ module QA
end
before do
- Resource::Issue.fabricate_via_api! { |issue| issue.project = project }.visit!
+ Resource::Issue.fabricate_via_api_unless_fips! { |issue| issue.project = project }.visit!
end
# The following example is excluded from running in `review-qa-smoke` job
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/custom_issue_template_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/custom_issue_template_spec.rb
index b2c612d38fe..bad312bb392 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/custom_issue_template_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/custom_issue_template_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable, product_group: :project_management do
describe 'Custom issue templates' do
let(:template_name) { 'custom_issue_template' }
let(:template_content) { 'This is a custom issue template test' }
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb
index e8c624e9554..61fd743f920 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/export_as_csv_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable, product_group: :project_management do
describe 'Issues list' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb
index d8fa7480f01..8af39cb6a82 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/filter_issue_comments_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable, product_group: :project_management do
describe 'filter issue comments activities' do
before do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb
index 6bb338ae31f..45541939606 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/issue_suggestions_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable, product_group: :project_management do
describe 'issue suggestions' do
let(:issue_title) { 'Issue Lists are awesome' }
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb
index 96f5731ea65..36cfb9dfb6e 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/mentions_spec.rb
@@ -1,11 +1,14 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :smoke do
+ RSpec.describe 'Plan', :smoke, product_group: :project_management do
describe 'mention' do
- let(:user) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
+ let(:user) do
+ Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1)
+ end
+
let(:project) do
- Resource::Project.fabricate_via_api! do |project|
+ Resource::Project.fabricate_via_api_unless_fips! do |project|
project.name = 'project-to-test-mention'
project.visibility = 'private'
end
@@ -14,14 +17,33 @@ module QA
before do
Flow::Login.sign_in
- project.add_member(user)
+ if QA::Support::FIPS.enabled?
+ # Ensure user exists
+ user
+ Flow::Login.sign_in_as_admin
+ project.visit!
+ Page::Project::Menu.perform(&:click_members)
+ Page::Project::Members.perform do |members|
+ members.add_member(user.username)
+ end
+ else
+ project.visit!
+ project.add_member(user)
+ end
- Resource::Issue.fabricate_via_api! do |issue|
- issue.project = project
- end.visit!
+ if QA::Support::FIPS.enabled?
+ Resource::Issue.fabricate_via_browser_ui! do |issue|
+ issue.project = project
+ end.visit!
+ else
+ Resource::Issue.fabricate_via_api! do |issue|
+ issue.project = project
+ end.visit!
+ end
end
- it 'mentions another user in an issue', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347988' do
+ it 'mentions another user in an issue',
+testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347988' do
Page::Project::Issue::Show.perform do |show|
at_username = "@#{user.username}"
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb
index 66e2309e173..060e52276a9 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue/real_time_assignee_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan' do
+ RSpec.describe 'Plan', product_group: :project_management do
describe 'Assignees' do
let(:user1) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
let(:user2) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_2, Runtime::Env.gitlab_qa_password_2) }
diff --git a/qa/qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb
index f116c690eec..83e178ae4c3 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/issue_boards/focus_mode_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable, product_group: :project_management do
describe 'Issue board focus mode' do
let(:project) do
QA::Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb
index d6eab3c8dd0..56e110e6f61 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/milestone/assign_milestone_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable, product_group: :project_management do
describe 'Milestones' do
include Support::Dates
diff --git a/qa/qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb
index 22709e8fbc4..5febb6579df 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/milestone/create_group_milestone_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable, product_group: :project_management do
describe 'Group milestone' do
include Support::Dates
diff --git a/qa/qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb
index 8047f8aea4c..5b580a67f5b 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/milestone/create_project_milestone_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable, product_group: :project_management do
describe 'Project milestone' do
include Support::Dates
diff --git a/qa/qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb
index 85011415177..197e283c93b 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/related_issues/related_issues_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :reliable do
+ RSpec.describe 'Plan', :reliable, product_group: :project_management do
describe 'Related issues' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb b/qa/qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb
index a3fe1d655aa..878c4dea26e 100644
--- a/qa/qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb
+++ b/qa/qa/specs/features/browser_ui/2_plan/transient/comment_on_discussion_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Plan', :transient do
+ RSpec.describe 'Plan', :transient, product_group: :project_management do
describe 'Discussion comments transient bugs' do
let(:user1) do
Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1)
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb
index 413c530116c..8f99644bd24 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_a_merge_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Cherry picking from a merge request' do
+ describe 'Cherry picking from a merge request', product_group: :code_review do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'project'
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb
index d6e9c1a13df..111adf32a69 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Cherry picking a commit' do
+ describe 'Cherry picking a commit', product_group: :code_review do
let(:file_name) { "secret_file.md" }
let(:project) do
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_from_push_notification_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_from_push_notification_spec.rb
index 10d7e0b071f..509714fb5a4 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_from_push_notification_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_from_push_notification_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Create a new merge request from the event notification after a push' do
+ describe 'Create a new merge request from the event notification after a push', product_group: :code_review do
let(:branch_name) { "merge-request-test-#{SecureRandom.hex(8)}" }
let(:title) { "Merge from push event notification test #{SecureRandom.hex(8)}" }
let(:project) do
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
index 25dec82b74c..1e08fc49066 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Create a new merge request' do
+ describe 'Create a new merge request', product_group: :code_review do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'project'
@@ -18,7 +18,7 @@ module QA
it(
'creates a basic merge request',
- :smoke,
+ :smoke, :skip_fips_env,
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347738'
) do
Resource::MergeRequest.fabricate_via_browser_ui! do |merge_request|
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb
index d975e18e962..1ce9430290f 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', :reliable do
+ RSpec.describe 'Create', :reliable, product_group: :code_review do
describe 'Merge request custom templates' do
let(:template_name) { 'custom_merge_request_template' }
let(:template_content) { 'This is a custom merge request template test' }
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb
index 109cf7b73c3..d27ec32fdda 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_merge_request_from_fork_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request creation from fork' do
+ describe 'Merge request creation from fork', product_group: :code_review do
let(:merge_request) do
Resource::MergeRequestFromFork.fabricate_via_browser_ui! do |merge_request|
merge_request.fork_branch = 'feature-branch'
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb
index ac53357a86f..257021b158a 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/merge_when_pipeline_succeeds_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', :runner do
+ RSpec.describe 'Create', :runner, product_group: :code_review do
describe 'Merge requests' do
shared_examples 'merge when pipeline succeeds' do |repeat: 1|
let(:runner_name) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
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 c7296b6eea2..330cae575e4 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
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request rebasing' do
+ describe 'Merge request rebasing', product_group: :code_review do
let(:merge_request) { Resource::MergeRequest.fabricate_via_api! }
before do
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb
index 205ff12ff03..a79c56bd051 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/revert_commit_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', :reliable do
+ RSpec.describe 'Create', :reliable, product_group: :code_review do
describe 'Reverting a commit' do
let(:file_name) { "secret_file.md" }
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb
index 948aedf5aae..82e2136cd22 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/revert/reverting_merge_request_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merged merge request' do
+ describe 'Merged merge request', product_group: :code_review do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'revert'
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb
index fa129f39a4c..a127b846eb9 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/squash_merge_request_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Merge request squashing' do
+ describe 'Merge request squashing', product_group: :code_review do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = "squash-before-merge"
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb
index b20d0929e9c..829b7bab829 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/batch_suggestion_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', :reliable do
+ RSpec.describe 'Create', :reliable, product_group: :code_review do
context 'Add batch suggestions to a Merge Request' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb
index aa637ac4d55..433ef90d9aa 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/suggestions/custom_commit_suggestion_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- context 'Add suggestions to a Merge Request' do
+ context 'Add suggestions to a Merge Request', product_group: :code_review do
let(:commit_message) { 'Applying suggested change for testing purposes.' }
let(:project) do
diff --git a/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
index 18aa6bfe78a..a969b48f0fc 100644
--- a/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/merge_request/view_merge_request_diff_patch_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Download merge request patch and diff' do
+ describe 'Download merge request patch and diff', product_group: :code_review do
let(:merge_request) do
Resource::MergeRequest.fabricate_via_api! do |merge_request|
merge_request.title = 'This is a merge request'
diff --git a/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb b/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb
index 9c912080c5f..c35aa403bfa 100644
--- a/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/pages/new_static_page_spec.rb
@@ -1,8 +1,9 @@
# frozen_string_literal: true
+
module QA
- RSpec.describe 'Create', :runner, only: { subdomain: :staging } do
+ RSpec.describe 'Create', :gitlab_pages, :orchestrated, except: { job: 'review-qa-*', subdomain: :production } do
# TODO: Convert back to :smoke once proved to be stable. Related issue: https://gitlab.com/gitlab-org/gitlab/-/issues/300906
- describe 'Pages' do
+ describe 'Pages', product_group: :editor do
let!(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'jekyll-pages-project'
@@ -21,7 +22,6 @@ module QA
before do
Flow::Login.sign_in
-
Resource::Runner.fabricate_via_api! do |runner|
runner.project = project
runner.executor = :docker
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 37e737a4f84..feb0f28763c 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'Testing wiki content creation inside a project' do
let(:new_wiki_title) { "just_another_wiki_page" }
let(:new_wiki_content) { "this content is changed or added" }
diff --git a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_manipulation_spec.rb b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_manipulation_spec.rb
index a4bdb0193dd..dcac2ad3a9d 100644
--- a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_manipulation_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_content_manipulation_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'Testing wiki content manipulation inside a project' do
let(:new_wiki_title) { "just_another_wiki_page" }
let(:new_wiki_content) { "this content is changed or added" }
diff --git a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_directory_management_spec.rb b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_directory_management_spec.rb
index 0af964fc4bf..7edbb01a522 100644
--- a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_directory_management_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_directory_management_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'A project wiki' do
let(:initial_wiki) { Resource::Wiki::ProjectPage.fabricate_via_api! }
let(:new_path) { "a/new/path-with-spaces" }
diff --git a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_file_upload_spec.rb b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_file_upload_spec.rb
index 361fc459d54..fbe662341c0 100644
--- a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_file_upload_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_file_upload_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', :reliable do
+ RSpec.describe 'Create', :reliable, product_group: :editor do
describe 'Testing project wiki file upload' do
let(:initial_wiki) { Resource::Wiki::ProjectPage.fabricate_via_api! }
let(:page_title) { 'Content Editor Page' }
diff --git a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_list_spec.rb b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_list_spec.rb
index 5c9b97659a7..e0699bccff6 100644
--- a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_list_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_list_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'Project Wiki' do
let(:small_number_of_pages) { 5 }
let(:large_number_of_pages) { 15 }
diff --git a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_page_deletion_spec.rb b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_page_deletion_spec.rb
index 13e04180ab5..626f9a7d593 100644
--- a/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_page_deletion_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/project_wiki/project_based_page_deletion_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'Testing project wiki'
let(:initial_wiki) { Resource::Wiki::ProjectPage.fabricate_via_api! }
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb
index 849022f5a93..866c6a146de 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/add_list_delete_branches_spec.rb
@@ -76,7 +76,7 @@ module QA
expect(branches_page).to have_no_branch(third_branch)
- branches_page.delete_merged_branches
+ branches_page.delete_merged_branches('delete')
expect(branches_page).to have_content(
'Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes.'
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb
index a785e4ae764..0ec231ed66e 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_http_private_token_spec.rb
@@ -2,8 +2,9 @@
module QA
RSpec.describe 'Create' do
- describe 'Git push over HTTP', :smoke, product_group: :source_code do
- it 'user using a personal access token pushes code to the repository', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347749' do
+ describe 'Git push over HTTP', :smoke, :skip_fips_env, product_group: :source_code do
+ it 'user using a personal access token pushes code to the repository',
+testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347749' do
Flow::Login.sign_in
access_token = Resource::PersonalAccessToken.fabricate!.token
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb
index e8f7cb252a0..efa1f9fe2c9 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_http_spec.rb
@@ -3,7 +3,8 @@
module QA
RSpec.describe 'Create' do
describe 'Git push over HTTP', product_group: :source_code do
- it 'user pushes code to the repository', :smoke, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347747' do
+ it 'user pushes code to the repository', :smoke, :skip_fips_env,
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347747' do
Flow::Login.sign_in
Resource::Repository::ProjectPush.fabricate! do |push|
@@ -18,7 +19,8 @@ module QA
end
end
- it 'pushes to a project using a specific Praefect repository storage', :smoke, :requires_admin, :requires_praefect, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347789' do
+ it 'pushes to a project using a specific Praefect repository storage', :smoke, :skip_fips_env, :requires_admin,
+ :requires_praefect, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347789' do
Flow::Login.sign_in_as_admin
project = Resource::Project.fabricate_via_api! do |storage_project|
diff --git a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb
index 4fb52f1e54d..f281f441e8a 100644
--- a/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/repository/push_over_ssh_spec.rb
@@ -26,7 +26,8 @@ module QA
Flow::Login.sign_in
end
- it 'pushes code to the repository via SSH', :smoke, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347825' do
+ it 'pushes code to the repository via SSH', :smoke, :skip_fips_env,
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347825' do
Resource::Repository::ProjectPush.fabricate! do |push|
push.project = project
push.ssh_key = @key
@@ -41,7 +42,8 @@ module QA
end
end
- it 'pushes multiple branches and tags together', :smoke, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347826' do
+ it 'pushes multiple branches and tags together', :smoke, :skip_fips_env,
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347826' do
branches = []
tags = []
Git::Repository.perform do |repository|
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb
index 1a7c64a363f..db180b729c8 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/add_comment_to_snippet_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'Adding comments on snippets' do
let(:comment_author) { Resource::User.fabricate_or_use(Runtime::Env.gitlab_qa_username_1, Runtime::Env.gitlab_qa_password_1) }
let(:comment_content) { 'Comment 123' }
@@ -23,11 +23,6 @@ module QA
Flow::Login.sign_in
end
- after do
- personal_snippet&.remove_via_api!
- project_snippet&.remove_via_api!
- end
-
shared_examples 'comments on snippets' do |snippet_type, testcase|
it "adds, edits, and deletes a comment on a #{snippet_type}", testcase: testcase do
send(snippet_type)
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb
index 8f05446ff70..20a4866baee 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/add_file_to_snippet_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'Multiple file snippet' do
let(:personal_snippet) do
Resource::Snippet.fabricate_via_api! do |snippet|
@@ -23,11 +23,6 @@ module QA
Flow::Login.sign_in
end
- after do
- personal_snippet&.remove_via_api!
- project_snippet&.remove_via_api!
- end
-
shared_examples 'adding file to snippet' do |snippet_type, testcase|
it "adds second file to an existing #{snippet_type} to make it multi-file", testcase: testcase do
send(snippet_type).visit!
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb
index 8f22a28628f..833d3bd6126 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_personal_snippet_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'Version control for personal snippets' do
let(:new_file) { 'new_snippet_file' }
let(:changed_content) { 'changes' }
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb
index 9a5fe44c927..a6bdac8c205 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/clone_push_pull_project_snippet_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'Version control for project snippets' do
let(:new_file) { 'new_snippet_file' }
let(:changed_content) { 'changes' }
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb
index e4204776c46..1a614e538ea 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/copy_snippet_file_contents_spec.rb
@@ -1,7 +1,11 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', :reliable do
+ RSpec.describe 'Create', :reliable, product_group: :editor, quarantine: {
+ only: { subdomain: 'pre' },
+ type: :investigating,
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/378697'
+ } do
describe 'Multiple file snippet' do
let(:first_file_content) { 'First file content' }
let(:second_file_content) { 'Second file content' }
@@ -54,11 +58,6 @@ module QA
Flow::Login.sign_in
end
- after do
- personal_snippet&.remove_via_api!
- project_snippet&.remove_via_api!
- end
-
shared_examples 'copying snippet file contents' do |snippet_type, testcase|
it "copies file contents of a multi-file #{snippet_type} to a comment and verifies them", testcase: testcase do
send(snippet_type).visit!
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb
index 620e6870b26..0e5fcea438d 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', :smoke do
+ RSpec.describe 'Create', :smoke, product_group: :editor do
describe 'Personal snippet creation' do
let(:snippet) do
Resource::Snippet.fabricate_via_browser_ui! do |snippet|
@@ -18,7 +18,12 @@ module QA
end
after do
- snippet.remove_via_api!
+ if QA::Support::FIPS.enabled?
+ snippet.visit!
+ Page::Dashboard::Snippet::Show.perform(&:click_delete_button)
+ else
+ snippet.remove_via_api!
+ end
end
it 'user creates a personal snippet', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347799' do
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_with_multiple_files_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_with_multiple_files_spec.rb
index 0560a5b125c..66376769419 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_with_multiple_files_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/create_personal_snippet_with_multiple_files_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Multiple file snippet', :reliable do
+ describe 'Multiple file snippet', :reliable, product_group: :editor do
let(:snippet) do
Resource::Snippet.fabricate_via_browser_ui! do |snippet|
snippet.title = 'Personal snippet with multiple files'
@@ -22,10 +22,6 @@ module QA
Flow::Login.sign_in
end
- after do
- snippet.remove_via_api!
- end
-
it 'creates a personal snippet with multiple files', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347723' do
snippet
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb
index 0f01a965e7b..0e10a9908f4 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do # to be converted to a smoke test once proved to be stable
+ RSpec.describe 'Create', product_group: :editor do # to be converted to a smoke test once proved to be stable
describe 'Project snippet creation' do
let(:snippet) do
Resource::ProjectSnippet.fabricate_via_browser_ui! do |snippet|
@@ -17,10 +17,6 @@ module QA
Flow::Login.sign_in
end
- after do
- snippet.remove_via_api!
- end
-
it 'user creates a project snippet', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347798' do
snippet
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_with_multiple_files_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_with_multiple_files_spec.rb
index 77b3c4df7e1..3c94107950c 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_with_multiple_files_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/create_project_snippet_with_multiple_files_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', :reliable do
+ RSpec.describe 'Create', :reliable, product_group: :editor do
describe 'Multiple file snippet' do
let(:snippet) do
Resource::ProjectSnippet.fabricate_via_browser_ui! do |snippet|
@@ -24,10 +24,6 @@ module QA
Flow::Login.sign_in
end
- after do
- snippet.remove_via_api!
- end
-
it 'creates a project snippet with multiple files', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347725' do
snippet
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb
index e9339342386..906ac6e09b7 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/delete_file_from_snippet_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Multiple file snippet', :reliable do
+ describe 'Multiple file snippet', :reliable, product_group: :editor do
let(:personal_snippet) do
Resource::Snippet.fabricate_via_api! do |snippet|
snippet.title = 'Personal snippet to delete file from'
@@ -31,11 +31,6 @@ module QA
Flow::Login.sign_in
end
- after do
- personal_snippet&.remove_via_api!
- project_snippet&.remove_via_api!
- end
-
shared_examples 'deleting file from snippet' do |snippet_type, testcase|
it "deletes second file from an existing #{snippet_type} to make it single-file", testcase: testcase do
send(snippet_type).visit!
diff --git a/qa/qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb b/qa/qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb
index 182a21a9377..b58b487531e 100644
--- a/qa/qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/snippet/share_snippet_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Create' do
- describe 'Sharing snippets', :reliable do
+ describe 'Sharing snippets', :reliable, product_group: :editor do
let(:snippet) do
Resource::Snippet.fabricate! do |snippet|
snippet.title = 'Shared snippet'
@@ -16,10 +16,6 @@ module QA
Flow::Login.sign_in
end
- after do
- snippet&.remove_via_api!
- end
-
context 'when the snippet is public' do
it 'can be shared with not signed-in users', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347836' do
snippet.visit!
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 97e42edfd01..63e9fdbb881 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'Snippet index page' do
let(:personal_snippet_with_single_file) do
Resource::Snippet.fabricate_via_api! do |snippet|
@@ -49,13 +49,6 @@ module QA
Flow::Login.sign_in
end
- after do
- personal_snippet_with_single_file.remove_via_api!
- personal_snippet_with_multiple_files.remove_via_api!
- project_snippet_with_single_file.remove_via_api!
- project_snippet_with_multiple_files.remove_via_api!
- end
-
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)
diff --git a/qa/qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb b/qa/qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb
index f95f624d59a..b8617de2e47 100644
--- a/qa/qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/source_editor/source_editor_toolbar_spec.rb
@@ -2,7 +2,7 @@
# tagged transient due to feature-flag caching flakiness. Remove tag along with feature flag removal.
module QA
RSpec.describe 'Create', feature_flag: { name: 'source_editor_toolbar', scope: :global } do
- describe 'Source editor toolbar preview' do
+ describe 'Source editor toolbar preview', product_group: :editor do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'empty-project-with-md'
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 19dd868744f..8ea65e17e13 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,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'Web IDE file templates' do
include Runtime::Fixtures
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 561a5a2cc1c..1da9ed652fe 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,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'Add a directory in Web IDE' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
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 948417458fc..1dfda1608f4 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,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'First file using Web IDE' do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
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 9c1d327f02c..56cf2a08bd9 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,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', 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
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
index 046327f780b..820b47a3175 100644
--- 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'Open a fork in Web IDE',
skip: {
issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/351696",
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 f03c651992c..685cd2d4ad6 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,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'Open Web IDE from Diff Tab' do
files = [
{
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 bd19d70ae5c..e4f29952f99 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,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor, quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/381530', type: :stale } do
describe 'Review a merge request in Web IDE' do
let(:new_file) { 'awesome_new_file.txt' }
let(:original_text) { 'Text' }
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 ac2d374b0ed..0972e4f3e3d 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,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create', :skip_live_env, except: { job: 'review-qa-*' } do
+ RSpec.describe 'Create', :skip_live_env, except: { job: 'review-qa-*' }, product_group: :editor do
describe 'Git Server Hooks' do
let(:file_path) { File.absolute_path(File.join('qa', 'fixtures', 'web_ide', 'README.md')) }
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 3d9d5695d06..c0f65416a1c 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,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Create' do
+ RSpec.describe 'Create', product_group: :editor do
describe 'Upload a file in Web IDE' do
let(:file_path) { File.absolute_path(File.join('qa', 'fixtures', 'web_ide', file_name)) }
diff --git a/qa/qa/specs/features/browser_ui/3_create/web_ide/web_terminal_spec.rb b/qa/qa/specs/features/browser_ui/3_create/web_ide/web_terminal_spec.rb
index 09459057992..f90676ee15a 100644
--- a/qa/qa/specs/features/browser_ui/3_create/web_ide/web_terminal_spec.rb
+++ b/qa/qa/specs/features/browser_ui/3_create/web_ide/web_terminal_spec.rb
@@ -9,7 +9,8 @@ module QA
quarantine: {
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/338179',
type: :bug
- }
+ },
+ product_group: :editor
) do
describe 'Web IDE web terminal' do
before do
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 fa8d0d1501c..aec0da99a5c 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,9 +2,9 @@
module QA
RSpec.describe 'Verify' do
- describe 'Add or Remove CI variable via UI', :smoke do
+ describe 'Add or Remove CI variable via UI', :smoke, product_group: :pipeline_authoring do
let(:project) do
- Resource::Project.fabricate_via_api! do |project|
+ Resource::Project.fabricate_via_api_unless_fips! do |project|
project.name = 'project-with-ci-variables'
project.description = 'project with CI variables'
end
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 63801536c34..4a0a8be3659 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
@@ -2,7 +2,10 @@
module QA
RSpec.describe 'Verify', :runner do
- describe 'Pipeline with customizable variable' do
+ describe 'Pipeline with customizable variable', feature_flag: {
+ name: :run_pipeline_graphql,
+ scope: :project
+ } do
let(:executor) { "qa-runner-#{Time.now.to_i}" }
let(:pipeline_job_name) { 'customizable-variable' }
let(:variable_custom_value) { 'Custom Foo' }
@@ -45,43 +48,74 @@ module QA
end
end
- before do
- Flow::Login.sign_in
- project.visit!
- Page::Project::Menu.perform(&:click_ci_cd_pipelines)
- Page::Project::Pipeline::Index.perform do |index|
- index.click_run_pipeline_button
+ shared_examples 'pipeline with custom variable' do
+ before do
+ Flow::Login.sign_in
+
+ 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
- end
- after do
- [runner, project].each(&:remove_via_api!)
+ after do
+ runner&.remove_via_api!
+ end
+
+ it 'manually creates a pipeline and uses the defined custom variable value' do
+ Page::Project::Pipeline::New.perform do |new|
+ new.configure_variable(value: variable_custom_value)
+ new.click_run_pipeline_button
+ end
+
+ Page::Project::Pipeline::Show.perform do |show|
+ Support::Waiter.wait_until { show.passed? }
+ end
+
+ job = Resource::Job.fabricate_via_api! do |job|
+ job.id = project.job_by_name(pipeline_job_name)[:id]
+ job.name = pipeline_job_name
+ job.project = project
+ end
+
+ job.visit!
+
+ Page::Project::Job::Show.perform do |show|
+ expect(show.output).to have_content(variable_custom_value)
+ end
+ end
end
- it(
- 'manually creates a pipeline and uses the defined custom variable value',
+ # TODO: Clean up tests when run_pipeline_graphql is enabled
+ # Issue https://gitlab.com/gitlab-org/gitlab/-/issues/372310
+ context(
+ 'with feature flag disabled',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/361814'
) do
- Page::Project::Pipeline::New.perform do |new|
- new.configure_variable(value: variable_custom_value)
- new.click_run_pipeline_button
+ before do
+ Runtime::Feature.disable(:run_pipeline_graphql, project: project)
end
- Page::Project::Pipeline::Show.perform do |show|
- Support::Waiter.wait_until { show.passed? }
- end
+ it_behaves_like 'pipeline with custom variable'
+ end
- job = Resource::Job.fabricate_via_api! do |job|
- job.id = project.job_by_name(pipeline_job_name)[:id]
- job.name = pipeline_job_name
- job.project = project
+ context(
+ 'with feature flag enabled',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/378975'
+ ) do
+ before do
+ Runtime::Feature.enable(:run_pipeline_graphql, project: project)
end
- job.visit!
-
- Page::Project::Job::Show.perform do |show|
- expect(show.output).to have_content(variable_custom_value)
+ after do
+ Runtime::Feature.disable(:run_pipeline_graphql, project: project)
end
+
+ it_behaves_like 'pipeline with custom variable'
end
end
end
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 5bb60e64da5..48d6ed8dc49 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,10 +1,10 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
describe 'Pipeline with protected variable' do
- let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(8)}" }
- let(:protected_value) { Faker::Alphanumeric.alphanumeric(8) }
+ let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
+ let(:protected_value) { Faker::Alphanumeric.alphanumeric(number: 8) }
let(:project) do
Resource::Project.fabricate_via_api! do |project|
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 8352ad6aa33..c4ce916d47d 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,10 @@
module QA
RSpec.describe 'Verify' do
- describe 'Pipeline with prefill variables' do
+ describe 'Pipeline with prefill variables', feature_flag: {
+ name: :run_pipeline_graphql,
+ scope: :project
+ } do
let(:prefill_variable_description1) { Faker::Lorem.sentence }
let(:prefill_variable_value1) { Faker::Lorem.word }
let(:prefill_variable_description2) { Faker::Lorem.sentence }
@@ -40,32 +43,62 @@ module QA
end
end
- before do
- Flow::Login.sign_in
- project.visit!
+ shared_examples 'pre-filled variables form' do
+ before do
+ Flow::Login.sign_in
- # Navigate to Run Pipeline page
- Page::Project::Menu.perform(&:click_ci_cd_pipelines)
- Page::Project::Pipeline::Index.perform(&:click_run_pipeline_button)
+ project.visit!
+ # 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' do
+ Page::Project::Pipeline::New.perform do |new|
+ aggregate_failures do
+ expect(new).to have_field('Input variable key', with: 'TEST1')
+ expect(new).to have_field('Input variable value', with: prefill_variable_value1)
+ expect(new).to have_content(prefill_variable_description1)
+
+ expect(new).to have_field('Input variable key', with: 'TEST2')
+ expect(new).to have_content(prefill_variable_description2)
+
+ expect(new).not_to have_field('Input variable key', with: 'TEST3')
+ expect(new).not_to have_field('Input variable key', with: 'TEST4')
+ end
+ end
+ end
end
- it(
- 'shows only variables with description as prefill variables on the run pipeline page',
+ # TODO: Clean up tests when run_pipeline_graphql is enabled
+ # Issue https://gitlab.com/gitlab-org/gitlab/-/issues/372310
+ context(
+ 'with feature flag disabled',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/371204'
) do
- Page::Project::Pipeline::New.perform do |new|
- aggregate_failures do
- expect(new).to have_field('Input variable key', with: 'TEST1')
- expect(new).to have_field('Input variable value', with: prefill_variable_value1)
- expect(new).to have_content(prefill_variable_description1)
+ before do
+ Runtime::Feature.disable(:run_pipeline_graphql, project: project)
+ end
- expect(new).to have_field('Input variable key', with: 'TEST2')
- expect(new).to have_content(prefill_variable_description2)
+ it_behaves_like 'pre-filled variables form'
+ end
- expect(new).not_to have_field('Input variable key', with: 'TEST3')
- expect(new).not_to have_field('Input variable key', with: 'TEST4')
- end
+ context 'with feature flag enabled',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/378977' do
+ before do
+ Runtime::Feature.enable(:run_pipeline_graphql, project: project)
end
+
+ after do
+ Runtime::Feature.disable(:run_pipeline_graphql, project: project)
+ end
+
+ it_behaves_like 'pre-filled variables form'
end
end
end
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
new file mode 100644
index 00000000000..fe934e8c60f
--- /dev/null
+++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/raw_variables_defined_in_yaml_spec.rb
@@ -0,0 +1,148 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.describe 'Verify', :runner do
+ describe 'Pipeline with raw variables in YAML', product_group: :pipeline_authoring, feature_flag: {
+ name: 'ci_raw_variables_in_yaml_config',
+ scope: :project
+ } do
+ let(:executor) { "qa-runner-#{Time.now.to_i}" }
+ let(:pipeline_job_name) { 'rspec' }
+
+ let(:project) do
+ Resource::Project.fabricate_via_api! do |project|
+ project.name = 'project-with-raw-variable-pipeline'
+ end
+ end
+
+ let!(:runner) do
+ Resource::Runner.fabricate! do |runner|
+ runner.project = project
+ runner.name = executor
+ runner.tags = [executor]
+ end
+ end
+
+ let(:commit_ci_file) do
+ Resource::Repository::Commit.fabricate_via_api! do |commit|
+ commit.project = project
+ commit.commit_message = 'Add .gitlab-ci.yml'
+ commit.add_files(
+ [
+ {
+ file_path: '.gitlab-ci.yml',
+ content: <<~YAML
+ variables:
+ VAR7:
+ value: "value 7 $CI_PIPELINE_ID"
+ expand: false
+ VAR8:
+ value: "value 8 $CI_PIPELINE_ID"
+ expand: false
+
+ #{pipeline_job_name}:
+ tags:
+ - #{executor}
+ script:
+ - echo "VAR1 is $VAR1"
+ - echo "VAR2 is $VAR2"
+ - echo "VAR3 is $VAR3"
+ - echo "VAR4 is $VAR4"
+ - echo "VAR5 is $VAR5"
+ - echo "VAR6 is $VAR6"
+ - echo "VAR7 is $VAR7"
+ - echo "VAR8 is $VAR8"
+ variables:
+ VAR1: "JOBID-$CI_JOB_ID"
+ VAR2: "PIPELINEID-$CI_PIPELINE_ID and $VAR1"
+ VAR3:
+ value: "PIPELINEID-$CI_PIPELINE_ID and $VAR1"
+ expand: false
+ VAR4:
+ value: "JOBID-$CI_JOB_ID"
+ expand: false
+ VAR5: "PIPELINEID-$CI_PIPELINE_ID and $VAR4"
+ VAR6:
+ value: "PIPELINEID-$CI_PIPELINE_ID and $VAR4"
+ expand: false
+ VAR7: "overridden value 7 $CI_PIPELINE_ID"
+ YAML
+ }
+ ]
+ )
+ end
+ end
+
+ let(:pipeline_id) { project.pipelines.first[:id] }
+ let(:job_id) { project.job_by_name(pipeline_job_name)[:id] }
+
+ def before_do
+ # TODO: Switch to use `let!` and remove this line when removing FF
+ commit_ci_file
+
+ Flow::Login.sign_in
+ project.visit!
+ Flow::Pipeline.visit_latest_pipeline(status: 'passed')
+ Page::Project::Pipeline::Show.perform do |show|
+ show.click_job(pipeline_job_name)
+ end
+ end
+
+ after do
+ runner&.remove_via_api!
+ end
+
+ context 'when FF is on', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/381487' do
+ before do
+ Runtime::Feature.enable(:ci_raw_variables_in_yaml_config, project: project)
+ sleep 60
+
+ before_do
+ end
+
+ it 'expands variables according to expand: true/false', :aggregate_failures do
+ Page::Project::Job::Show.perform do |show|
+ expect(show.output).to have_content("VAR1 is JOBID-#{job_id}")
+ expect(show.output).to have_content("VAR2 is PIPELINEID-#{pipeline_id} and JOBID-#{job_id}")
+ expect(show.output).to have_content("VAR3 is PIPELINEID-$CI_PIPELINE_ID and $VAR1")
+ expect(show.output).to have_content("VAR4 is JOBID-$CI_JOB_ID")
+ expect(show.output).to have_content("VAR5 is PIPELINEID-#{pipeline_id} and JOBID-$CI_JOB_ID")
+ expect(show.output).to have_content("VAR6 is PIPELINEID-$CI_PIPELINE_ID and $VAR4")
+ expect(show.output).to have_content("VAR7 is overridden value 7 #{pipeline_id}")
+ expect(show.output).to have_content("VAR8 is value 8 $CI_PIPELINE_ID")
+ end
+ end
+ end
+
+ # TODO: Remove this context when FF :ci_raw_variables_in_yaml_config is removed
+ # Also archive testcase and close related issue
+ context 'when FF is off',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/381486',
+ quarantine: {
+ issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/381806',
+ only: { pipeline: %w[staging staging-canary] },
+ type: :waiting_on
+ } do
+ before do
+ Runtime::Feature.disable(:ci_raw_variables_in_yaml_config, project: project)
+ sleep 60
+
+ before_do
+ end
+
+ it 'expands all variables', :aggregate_failures do
+ Page::Project::Job::Show.perform do |show|
+ expect(show.output).to have_content("VAR1 is JOBID-#{job_id}")
+ expect(show.output).to have_content("VAR2 is PIPELINEID-#{pipeline_id} and JOBID-#{job_id}")
+ expect(show.output).to have_content("VAR3 is PIPELINEID-#{pipeline_id} and JOBID-#{job_id}")
+ expect(show.output).to have_content("VAR4 is JOBID-#{job_id}")
+ expect(show.output).to have_content("VAR5 is PIPELINEID-#{pipeline_id} and JOBID-#{job_id}")
+ expect(show.output).to have_content("VAR6 is PIPELINEID-#{pipeline_id} and JOBID-#{job_id}")
+ expect(show.output).to have_content("VAR7 is overridden value 7 #{pipeline_id}")
+ expect(show.output).to have_content("VAR8 is value 8 #{pipeline_id}")
+ end
+ end
+ end
+ end
+ end
+end
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 7782c0240e9..a5ebd4004d2 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 do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring 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 69a99483b38..f53454b801c 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 do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
describe 'UI defined variable' do
include_context 'variable inheritance test prep'
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb
index 1bba5355790..b6270c11ef6 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :smoke, :runner, quarantine: {
+ RSpec.describe 'Verify', :smoke, :runner, product_group: :pipeline_execution, quarantine: {
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/356295',
type: :investigating
} do
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_local_config_file_paths_with_wildcard_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_local_config_file_paths_with_wildcard_spec.rb
index b9b87ed29bb..027383550a7 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_local_config_file_paths_with_wildcard_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_local_config_file_paths_with_wildcard_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Verify' do
- describe 'Include local config file paths with wildcard', :reliable do
+ describe 'Include local config file paths with wildcard', :reliable, product_group: :pipeline_authoring do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'project-with-pipeline'
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb
index 2fa6b9179ef..d773d0f36d0 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/include_multiple_files_from_a_project_spec.rb
@@ -1,9 +1,9 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
describe 'Include multiple files from a project' do
- let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(8)}" }
+ let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:expected_text) { Faker::Lorem.sentence }
let(:unexpected_text) { Faker::Lorem.sentence }
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 3356d1274c8..ba1363d79c5 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 do
+ RSpec.describe 'Verify', :runner, :requires_admin, product_group: :pipeline_insights 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/merge_mr_when_pipline_is_blocked_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb
index d201627218e..34f548a0e69 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/merge_mr_when_pipline_is_blocked_spec.rb
@@ -1,9 +1,9 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do
context 'When pipeline is blocked' do
- let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(8)}" }
+ let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/mr_event_rule_pipeline_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/mr_event_rule_pipeline_spec.rb
index 65561bbba29..e876bf3ab8b 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/mr_event_rule_pipeline_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/mr_event_rule_pipeline_spec.rb
@@ -1,11 +1,11 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
context 'When job is configured to only run on merge_request_events' do
let(:mr_only_job_name) { 'mr_only_job' }
let(:non_mr_only_job_name) { 'non_mr_only_job' }
- let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(8)}" }
+ let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb
index 9e3c29db9e7..a7ca7b82d1e 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/parent_child_pipelines_independent_relationship_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner, :reliable do
+ RSpec.describe 'Verify', :runner, :reliable, product_group: :pipeline_execution do
describe 'Parent-child pipelines independent relationship' do
let!(:project) do
Resource::Project.fabricate_via_api! do |project|
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 bbcc71bade7..fca34fc1f8e 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 do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring 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/pipeline/pipeline_editor_branch_switcher_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb
index ac91a9dd2d3..30c71bc590c 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Verify' do
- describe 'Pipeline editor' do
+ describe 'Pipeline editor', product_group: :pipeline_authoring do
let(:random_test_string) { SecureRandom.hex(10) }
let(:project) do
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb
index 931bb97ba32..1f7871b0900 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Verify' do
- describe 'Pipeline editor' do
+ describe 'Pipeline editor', product_group: :pipeline_authoring do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'pipeline-editor-project'
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb
index bef15b46fcd..dbe24e2a2b2 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_tabs_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Verify' do
- describe 'Pipeline editor', :reliable do
+ describe 'Pipeline editor', :reliable, product_group: :pipeline_authoring do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'pipeline-editor-project'
@@ -36,6 +36,15 @@ module QA
end
end
+ let(:invalid_content) do
+ <<~YAML
+
+ job3:
+ stage: stage_foo
+ script: echo 'Done.'
+ YAML
+ end
+
before do
# Make sure a pipeline is created before visiting pipeline editor page.
# Otherwise, test might timeout before the page finishing fetching pipeline status.
@@ -80,7 +89,7 @@ module QA
invalid_msg = 'syntax is invalid'
Page::Project::PipelineEditor::Show.perform do |show|
- show.write_to_editor(SecureRandom.hex(10))
+ show.write_to_editor(invalid_content)
aggregate_failures do
show.go_to_visualize_tab
@@ -90,8 +99,14 @@ module QA
show.simulate_pipeline
expect(show.tab_alert_title).to have_content('Pipeline simulation completed with errors')
+ expect(show.ci_syntax_validate_message).to have_content('CI configuration is invalid')
+
show.go_to_view_merged_yaml_tab
- expect(show.tab_alert_message).to have_content(invalid_msg)
+
+ # TODO: remove this retry when
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/378536 is resolved
+ show.retry_until(max_attempts: 2, reload: true, sleep_interval: 1) { show.has_no_alert? }
+ expect(show).to have_source_editor
expect(show.ci_syntax_validate_message).to have_content('CI configuration is invalid')
end
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb
index f9113573295..b1ecce297c9 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_with_image_pull_policy_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
describe 'Pipeline with image:pull_policy' do
let(:runner_name) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:job_name) { "test-job-#{pull_policies.join('-')}" }
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_via_web_only_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_via_web_only_spec.rb
index f36593218a9..e8ec01577b1 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_via_web_only_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_via_web_only_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Verify' do
- describe 'Run pipeline', :reliable do
+ describe 'Run pipeline', :reliable, product_group: :pipeline_execution do
context 'with web only rule' do
let(:job_name) { 'test_job' }
let(:project) do
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb
index fb7e3a8437f..4223caaafef 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/run_pipeline_with_manual_jobs_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do
describe 'Run pipeline with manual jobs' do
let(:executor) { "qa-runner-#{SecureRandom.hex(4)}" }
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb
index 1c75beebb48..c1d996df925 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_child_pipeline_with_manual_spec.rb
@@ -1,9 +1,9 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_execution do
describe "Trigger child pipeline with 'when:manual'" do
- let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(8)}" }
+ let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb
index 205b4d1168a..83283c5d8e3 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/trigger_matrix_spec.rb
@@ -1,9 +1,9 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_authoring do
describe 'Trigger matrix' do
- let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(8)}" }
+ let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" }
let(:project) do
Resource::Project.fabricate_via_api! do |project|
diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb
index d34df17c477..1f49c7a3663 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Verify' do
- describe 'Update CI file with pipeline editor' do
+ describe 'Update CI file with pipeline editor', product_group: :pipeline_authoring do
let(:random_test_string) { SecureRandom.hex(10) }
let(:project) do
diff --git a/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb
index f8261bba342..24c49be13bb 100644
--- a/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb
+++ b/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Verify', :runner do
+ RSpec.describe 'Verify', :runner, product_group: :runner do
describe 'Runner registration' do
let(:executor) { "qa-runner-#{Time.now.to_i}" }
let!(:runner) do
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 adcf91a550c..0166c53ffd5 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 do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_insights 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 122fb0fc1a0..2a4852a2b8b 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 do
+ RSpec.describe 'Verify', :runner, product_group: :pipeline_insights 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/container_registry/container_registry_omnibus_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_omnibus_spec.rb
index fca14a55468..c57a5c27dd2 100644
--- a/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_omnibus_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_omnibus_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :skip_live_env do
+ RSpec.describe 'Package', :orchestrated, :skip_live_env, product_group: :container_registry do
describe 'Self-managed Container Registry' do
include Support::Helpers::MaskToken
@@ -174,7 +174,7 @@ module QA
Page::Project::Registry::Show.perform do |registry|
expect(registry).to have_registry_repository(project.name)
- registry.click_on_image(project.path_with_namespace)
+ registry.click_on_image(project.name)
expect(registry).to have_tag('master')
end
end
@@ -232,7 +232,7 @@ module QA
Page::Project::Registry::Show.perform do |registry|
expect(registry).to have_registry_repository(project.name)
- registry.click_on_image(project.path_with_namespace)
+ registry.click_on_image(project.name)
expect(registry).to have_tag('master')
diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb
index 5a29b44e8b3..680b722edb7 100644
--- a/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/container_registry_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Package' do
- describe 'Container Registry', only: { subdomain: %i[staging staging-canary pre] } do
+ describe 'Container Registry', only: { subdomain: %i[staging staging-canary pre] }, product_group: :container_registry do
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'project-with-registry'
diff --git a/qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb b/qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb
index 56e3ec82388..bf328a2bced 100644
--- a/qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/container_registry/online_garbage_collection_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package' do
+ RSpec.describe 'Package', product_group: :container_registry do
describe 'Container Registry Online Garbage Collection', :registry_gc, only: { subdomain: %i[pre] } do
let(:group) { Resource::Group.fabricate_via_api! }
diff --git a/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb b/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb
index ad820977747..978867d5cf1 100644
--- a/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/dependency_proxy/dependency_proxy_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :registry, only: { pipeline: :main } do
+ RSpec.describe 'Package', :orchestrated, :registry, only: { pipeline: :main }, product_group: :container_registry do
describe 'Dependency Proxy' do
using RSpec::Parameterized::TableSyntax
include Support::Helpers::MaskToken
diff --git a/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb
index 6ce395affc7..a80e154a969 100644
--- a/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/infrastructure_registry/terraform_module_registry_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages do
+ RSpec.describe 'Package', :orchestrated, :packages, product_group: :package_registry do
describe 'Terraform Module Registry' do
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb
index d5ef9dce10d..ab4fb21f19a 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/composer_registry_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage do
+ RSpec.describe 'Package', :orchestrated, :packages, :object_storage, product_group: :package_registry do
describe 'Composer Repository' do
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb
index 1840ae4e7f8..687d9f710fb 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/conan_repository_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, quarantine: {
+ RSpec.describe 'Package', :orchestrated, :packages, :object_storage, product_group: :package_registry, quarantine: {
only: { job: 'object_storage' },
issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/335981',
type: :bug
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb
index 677b8970a75..820571593a6 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/generic_repository_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, :reliable do
+ RSpec.describe 'Package', :orchestrated, :packages, :object_storage, :reliable, product_group: :package_registry do
describe 'Generic Repository' do
include Runtime::Fixtures
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 222d1993bf4..4c15b7c7f99 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage do
+ RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, product_group: :package_registry do
describe 'Helm Registry' do
using RSpec::Parameterized::TableSyntax
include Runtime::Fixtures
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 690451f6147..aac8893ff2c 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 do
+ RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, :reliable, product_group: :package_registry do
describe 'Maven group level endpoint' do
include Runtime::Fixtures
include_context 'packages registry qa scenario'
@@ -131,7 +131,7 @@ module QA
Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_disabled)
end
- it 'prevents users from publishing duplicates' do
+ it 'prevents users from publishing duplicates', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/377491' do
create_duplicated_package
push_duplicated_package
@@ -151,7 +151,7 @@ module QA
Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_enabled)
end
- it 'allows users to publish duplicates' do
+ it 'allows users to publish duplicates', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/377492' do
create_duplicated_package
push_duplicated_package
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb
index 324e881f160..8e1b0176f35 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/maven/maven_project_level_spec.rb
@@ -1,12 +1,12 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, :reliable,
+ RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, :reliable,
feature_flag: {
name: 'maven_central_request_forwarding',
scope: :global
} do
- describe 'Maven project level endpoint' do
+ describe 'Maven project level endpoint', product_group: :package_registry do
include Runtime::Fixtures
let(:group_id) { 'com.gitlab.qa' }
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 22052aa4110..a9d66c93fac 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage do
+ RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, product_group: :package_registry do
describe 'Maven Repository with Gradle' do
using RSpec::Parameterized::TableSyntax
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb
index 124e7743728..e209fc55e35 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_instance_level_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Package' do
- describe 'Package Registry', :orchestrated, :reliable, :packages, :object_storage do
+ describe 'Package Registry', :skip_live_env, :orchestrated, :reliable, :packages, :object_storage, product_group: :package_registry do
describe 'npm instance level endpoint' do
using RSpec::Parameterized::TableSyntax
include Runtime::Fixtures
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb
index 59324c7338a..d1aaa05c85a 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/npm/npm_project_level_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Package' do
- describe 'Package Registry', :orchestrated, :reliable, :packages, :object_storage do
+ describe 'Package Registry', :skip_live_env, :orchestrated, :reliable, :packages, :object_storage, product_group: :package_registry do
describe 'npm project level endpoint' do
using RSpec::Parameterized::TableSyntax
include Runtime::Fixtures
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 e2a7006249d..d44bc8fa2ad 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
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage, :reliable do
+ RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, :reliable, product_group: :package_registry do
describe 'NuGet group level endpoint' do
using RSpec::Parameterized::TableSyntax
include Runtime::Fixtures
@@ -133,14 +133,14 @@ module QA
{
file_path: 'otherdotnet.csproj',
content: <<~EOF
- <Project Sdk="Microsoft.NET.Sdk">
+ <Project Sdk="Microsoft.NET.Sdk">
- <PropertyGroup>
- <OutputType>Exe</OutputType>
- <TargetFramework>net5.0</TargetFramework>
- </PropertyGroup>
+ <PropertyGroup>
+ <OutputType>Exe</OutputType>
+ <TargetFramework>net5.0</TargetFramework>
+ </PropertyGroup>
- </Project>
+ </Project>
EOF
}
]
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_project_level_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_project_level_spec.rb
index 620bb7e4988..442deb1eb4e 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_project_level_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/nuget/nuget_project_level_spec.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage do
+ RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage,
+product_group: :package_registry do
describe 'NuGet project level endpoint' do
include Support::Helpers::MaskToken
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb
index 012a03ca115..fddb7fb6ebc 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/pypi_repository_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Package', :orchestrated, :packages, :object_storage do
+ RSpec.describe 'Package', :skip_live_env, :orchestrated, :packages, :object_storage, product_group: :package_registry do
describe 'PyPI Repository' do
include Runtime::Fixtures
include Support::Helpers::MaskToken
diff --git a/qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb b/qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb
index 409a1c10943..63ab826e57b 100644
--- a/qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb
+++ b/qa/qa/specs/features/browser_ui/5_package/package_registry/rubygems_registry_spec.rb
@@ -3,7 +3,7 @@
module QA
RSpec.describe 'Package', :orchestrated, :packages, :object_storage,
feature_flag: { name: 'rubygem_packages', scope: :project } do
- describe 'RubyGems Repository' do
+ describe 'RubyGems Repository', product_group: :package_registry do
include Runtime::Fixtures
let(:project) do
diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb
index 8b7b827de91..05dfc0c572e 100644
--- a/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb
+++ b/qa/qa/specs/features/browser_ui/6_release/deploy_key/add_deploy_key_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Release' do
+ RSpec.describe 'Release', product_group: :release do
describe 'Deploy key creation' do
it 'user adds a deploy key', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348023' do
Flow::Login.sign_in
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 1f5a431938c..3f91d120fdd 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
@@ -3,7 +3,7 @@
require 'digest/sha1'
module QA
- RSpec.describe 'Release', :runner do
+ RSpec.describe 'Release', :runner, product_group: :release do
describe 'Git clone using a deploy key' do
let(:runner_name) { "qa-runner-#{SecureRandom.hex(4)}" }
let(:repository_location) { project.repository_ssh_location }
@@ -35,7 +35,7 @@ module QA
keys = [
['https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348022', Runtime::Key::RSA, 8192, true],
['https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348021', Runtime::Key::ECDSA, 521, true],
- ['https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348020', Runtime::Key::ED25519, false]
+ ['https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348020', Runtime::Key::ED25519, 256, false]
]
supported_keys =
diff --git a/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb b/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb
index 9811453605e..b0b1fa2b68d 100644
--- a/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb
+++ b/qa/qa/specs/features/browser_ui/6_release/deploy_token/add_deploy_token_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Release' do
+ RSpec.describe 'Release', product_group: :release do
describe 'Deploy token creation' do
it 'user adds a deploy token', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/348028' do
Flow::Login.sign_in
diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb
index 608dd7e089f..42a64099a3d 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb
+++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/auto_devops_templates_spec.rb
@@ -2,7 +2,7 @@
module QA
RSpec.describe 'Configure' do
- describe 'AutoDevOps Templates', only: { subdomain: %i[staging staging-canary] } do
+ describe 'AutoDevOps Templates', only: { subdomain: %i[staging staging-canary] }, product_group: :configure do
using RSpec::Parameterized::TableSyntax
# specify jobs to be disabled in the pipeline.
diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
index b839855c500..057b4c15db1 100644
--- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
+++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module QA
- RSpec.describe 'Configure', only: { subdomain: %i[staging staging-canary] } do
+ RSpec.describe 'Configure', only: { subdomain: %i[staging staging-canary] }, product_group: :configure do
describe 'Auto DevOps with a Kubernetes Agent' do
let!(:app_project) do
Resource::Project.fabricate_via_api! do |project|
@@ -98,7 +98,7 @@ module QA
content: <<~YAML
ci_access:
projects:
- - id: #{project.path_with_namespace}
+ - id: #{project.path_with_namespace}
YAML
}
]
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
new file mode 100644
index 00000000000..0a0c2a4a6df
--- /dev/null
+++ b/qa/qa/specs/features/shared_contexts/import/github_import_shared_context.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module QA
+ RSpec.shared_context "with github import", :github, :skip_live_env, :requires_admin, quarantine: {
+ type: :broken,
+ issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/382166"
+ } do
+ let!(:api_client) { Runtime::API::Client.as_admin }
+
+ let!(:group) do
+ Resource::Group.fabricate_via_api! do |resource|
+ resource.api_client = api_client
+ resource.path = "destination-group-for-import-#{SecureRandom.hex(4)}"
+ end
+ end
+
+ let!(:user) do
+ Resource::User.fabricate_via_api! do |resource|
+ resource.api_client = api_client
+ resource.hard_delete_on_api_removal = true
+ end
+ end
+
+ let!(:user_api_client) { Runtime::API::Client.new(user: user) }
+
+ let(:imported_project) do
+ Resource::ProjectImportedFromGithub.fabricate_via_api! do |project|
+ project.name = 'imported-project'
+ project.group = group
+ project.github_personal_access_token = Runtime::Env.github_access_token
+ project.github_repository_path = 'gitlab-qa-github/import-test'
+ project.api_client = user_api_client
+ project.issue_events_import = true
+ project.full_notes_import = true
+ end
+ end
+
+ before do
+ group.add_member(user, Resource::Members::AccessLevel::MAINTAINER)
+ end
+
+ after do
+ user.remove_via_api!
+ end
+ end
+end
diff --git a/qa/qa/specs/features/api/1_manage/migration/gitlab_project_migration_common.rb b/qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb
index 9c80c088917..9c80c088917 100644
--- a/qa/qa/specs/features/api/1_manage/migration/gitlab_project_migration_common.rb
+++ b/qa/qa/specs/features/shared_contexts/import/gitlab_project_migration_common.rb
diff --git a/qa/qa/specs/helpers/context_selector.rb b/qa/qa/specs/helpers/context_selector.rb
index 3608fa7c581..caa5ace430f 100644
--- a/qa/qa/specs/helpers/context_selector.rb
+++ b/qa/qa/specs/helpers/context_selector.rb
@@ -18,6 +18,7 @@ module QA
def context_matches?(*options)
return false unless Runtime::Scenario.attributes[:gitlab_address]
+ return false if Runtime::Scenario.attributes[:test_metadata_only]
opts = {}
opts[:domain] = '.+'
diff --git a/qa/qa/specs/runner.rb b/qa/qa/specs/runner.rb
index c46b6300200..4eb799f34c1 100644
--- a/qa/qa/specs/runner.rb
+++ b/qa/qa/specs/runner.rb
@@ -23,6 +23,8 @@ module QA
def rspec_tags
tags_for_rspec = []
+ return tags_for_rspec if Runtime::Scenario.attributes[:test_metadata_only]
+
if tags.any?
tags.each { |tag| tags_for_rspec.push(['--tag', tag.to_s]) }
else
diff --git a/qa/qa/specs/spec_helper.rb b/qa/qa/specs/spec_helper.rb
index 97901042883..a4721040683 100644
--- a/qa/qa/specs/spec_helper.rb
+++ b/qa/qa/specs/spec_helper.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require_relative '../../qa'
+require 'active_support/testing/time_helpers'
QA::Specs::QaDeprecationToolkitEnv.configure!
@@ -14,20 +15,18 @@ QA::Runtime::Scenario.from_env(QA::Runtime::Env.runtime_scenario_attributes)
# Enable zero monkey patching mode before loading any other RSpec code.
RSpec.configure(&:disable_monkey_patching!)
-Dir[::File.join(__dir__, "features/shared_examples/*.rb")].sort.each { |f| require f }
-Dir[::File.join(__dir__, "features/shared_contexts/*.rb")].sort.each { |f| require f }
-
# For JH additionally process when `jh/` exists
require_relative('../../../jh/qa/qa/specs/spec_helper') if GitlabEdition.jh?
RSpec.configure do |config|
+ config.include ActiveSupport::Testing::TimeHelpers
config.include QA::Support::Matchers::EventuallyMatcher
config.include QA::Support::Matchers::HaveMatcher
config.add_formatter QA::Support::Formatters::ContextFormatter
config.add_formatter QA::Support::Formatters::QuarantineFormatter
config.add_formatter QA::Support::Formatters::FeatureFlagFormatter
- config.add_formatter QA::Support::Formatters::TestStatsFormatter if QA::Runtime::Env.export_metrics?
+ config.add_formatter QA::Support::Formatters::TestMetricsFormatter if QA::Runtime::Env.running_in_ci?
config.before(:suite) do |suite|
QA::Resource::ReusableCollection.register_resource_classes do |collection|
@@ -149,3 +148,6 @@ RSpec.configure do |config|
end
end
end
+
+Dir[::File.join(__dir__, "features/shared_examples/**/*.rb")].sort.each { |f| require f }
+Dir[::File.join(__dir__, "features/shared_contexts/**/*.rb")].sort.each { |f| require f }
diff --git a/qa/qa/support/fips.rb b/qa/qa/support/fips.rb
index f5ebce4fa9c..0fed39e8109 100644
--- a/qa/qa/support/fips.rb
+++ b/qa/qa/support/fips.rb
@@ -5,7 +5,7 @@ module QA
module Support
class FIPS
def self.enabled?
- %(1 true yes).include?(ENV['FIPS'].to_s)
+ %w[1 true yes].include?(ENV['FIPS'].to_s)
end
end
end
diff --git a/qa/qa/support/formatters/allure_metadata_formatter.rb b/qa/qa/support/formatters/allure_metadata_formatter.rb
index d1baf87799a..02719536b17 100644
--- a/qa/qa/support/formatters/allure_metadata_formatter.rb
+++ b/qa/qa/support/formatters/allure_metadata_formatter.rb
@@ -39,6 +39,7 @@ module QA
add_failure_issues_link(example)
add_ci_job_link(example)
set_flaky_status(example)
+ set_behaviour_categories(example)
end
private
@@ -97,6 +98,19 @@ module QA
log(:error, "Failed to add spec pass rate data for example '#{example.description}', error: #{e}")
end
+ # Add behaviour categories to report
+ #
+ # @param [RSpec::Core::Example] example
+ # @return [void]
+ def set_behaviour_categories(example)
+ file_path = example.file_path.gsub('./qa/specs/features', '')
+ devops_stage = file_path.match(%r{\d{1,2}_(\w+)/})&.captures&.first
+ product_group = example.metadata[:product_group]
+
+ example.epic(devops_stage) if devops_stage
+ example.feature(product_group) if product_group
+ end
+
# Flaky specs with pass rate below 98%
#
# @return [Array]
@@ -107,7 +121,7 @@ module QA
runs = records.count
failed = records.count { |r| r.values["status"] == "failed" }
- pass_rate = 100 - ((failed.to_f / runs.to_f) * 100)
+ pass_rate = 100 - ((failed.to_f / runs) * 100)
# Consider spec with a pass rate less than 98% as flaky
result[records.last.values["testcase"]] = pass_rate if pass_rate < 98
diff --git a/qa/qa/support/formatters/context_formatter.rb b/qa/qa/support/formatters/context_formatter.rb
index c8991561f45..11f6a182ebb 100644
--- a/qa/qa/support/formatters/context_formatter.rb
+++ b/qa/qa/support/formatters/context_formatter.rb
@@ -36,6 +36,7 @@ module QA
# @param [<RSpec::Core::ExampleGroup, RSpec::Core::Example>] example
# @return [void]
def set_skip_metadata(example)
+ return if Runtime::Scenario.attributes[:test_metadata_only]
return skip_only(example.metadata) if example.metadata.key?(:only)
return skip_except(example.metadata) if example.metadata.key?(:except)
end
diff --git a/qa/qa/support/formatters/test_metrics_formatter.rb b/qa/qa/support/formatters/test_metrics_formatter.rb
new file mode 100644
index 00000000000..e84373a487d
--- /dev/null
+++ b/qa/qa/support/formatters/test_metrics_formatter.rb
@@ -0,0 +1,242 @@
+# frozen_string_literal: true
+
+require "active_support/core_ext/string/conversions"
+
+module QA
+ module Support
+ module Formatters
+ class TestMetricsFormatter < RSpec::Core::Formatters::BaseFormatter
+ include Support::InfluxdbTools
+
+ RSpec::Core::Formatters.register(self, :stop)
+
+ # Finish test execution
+ #
+ # @param [RSpec::Core::Notifications::ExamplesNotification] notification
+ # @return [void]
+ def stop(notification)
+ return log(:warn, "Missing run_type, skipping metrics export!") unless run_type
+
+ parse_execution_data(notification.examples)
+
+ if Runtime::Env.export_metrics?
+ push_test_metrics
+ push_fabrication_metrics
+ end
+
+ save_test_metrics if Runtime::Env.save_metrics_json?
+ end
+
+ private
+
+ # Save execution data for the run
+ #
+ # @param [Array<RSpec::Core::Example>] examples
+ # @return [Array<Hash>]
+ def execution_data(examples = nil)
+ @execution_metrics ||= examples.map { |example| test_stats(example) }.compact
+ end
+ alias_method :parse_execution_data, :execution_data
+
+ # Push test execution metrics to influxdb
+ #
+ # @return [void]
+ def push_test_metrics
+ write_api.write(data: execution_data)
+ log(:debug, "Pushed #{execution_data.length} test execution entries to influxdb")
+ rescue StandardError => e
+ log(:error, "Failed to push test execution metrics to influxdb, error: #{e}")
+ end
+
+ # Push resource fabrication metrics to influxdb
+ #
+ # @return [void]
+ def push_fabrication_metrics
+ data = Tools::TestResourceDataProcessor.resources.flat_map do |resource, values|
+ values.map { |v| fabrication_stats(resource: resource, **v) }
+ end
+ return if data.empty?
+
+ write_api.write(data: data)
+ log(:debug, "Pushed #{data.length} resource fabrication entries to influxdb")
+ rescue StandardError => e
+ log(:error, "Failed to push fabrication metrics to influxdb, error: #{e}")
+ end
+
+ # Save metrics in json file
+ #
+ # @return [void]
+ def save_test_metrics
+ File.write("tmp/test-metrics-#{env('CI_JOB_NAME_SLUG') || 'local'}.json", execution_data.to_json)
+ rescue StandardError => e
+ log(:error, "Failed to save test execution metrics, error: #{e}")
+ end
+
+ # Transform example to influxdb compatible metrics data
+ # https://github.com/influxdata/influxdb-client-ruby#data-format
+ #
+ # @param [RSpec::Core::Example] example
+ # @return [Hash]
+ def test_stats(example)
+ file_path = example.metadata[:file_path].gsub('./qa/specs/features', '')
+ api_fabrication = ((example.metadata[:api_fabrication] || 0) * 1000).round
+ ui_fabrication = ((example.metadata[:browser_ui_fabrication] || 0) * 1000).round
+
+ # do not export results for tests that are not compatible with environment
+ return if incompatible_env?(example)
+
+ {
+ name: 'test-stats',
+ time: time,
+ tags: {
+ name: example.full_description,
+ file_path: file_path,
+ status: status(example),
+ smoke: example.metadata.key?(:smoke).to_s,
+ reliable: example.metadata.key?(:reliable).to_s,
+ quarantined: quarantined(example.metadata),
+ retried: (retry_attempts(example.metadata) > 0).to_s,
+ job_name: job_name,
+ merge_request: merge_request,
+ run_type: run_type,
+ stage: devops_stage(file_path),
+ product_group: example.metadata[:product_group],
+ testcase: example.metadata[:testcase]
+ },
+ fields: {
+ id: example.id,
+ run_time: (example.execution_result.run_time * 1000).round,
+ api_fabrication: api_fabrication,
+ ui_fabrication: ui_fabrication,
+ total_fabrication: api_fabrication + ui_fabrication,
+ retry_attempts: retry_attempts(example.metadata),
+ job_url: QA::Runtime::Env.ci_job_url,
+ pipeline_url: env('CI_PIPELINE_URL'),
+ pipeline_id: env('CI_PIPELINE_ID'),
+ job_id: env('CI_JOB_ID'),
+ merge_request_iid: merge_request_iid
+ }
+ }
+ rescue StandardError => e
+ log(:error, "Failed to transform example '#{example.id}', error: #{e}")
+ nil
+ end
+
+ # Resource fabrication data point
+ #
+ # @param [String] resource
+ # @param [String] info
+ # @param [Symbol] fabrication_method
+ # @param [Symbol] http_method
+ # @param [Integer] fabrication_time
+ # @param [String] timestamp
+ # @return [Hash]
+ def fabrication_stats(resource:, info:, fabrication_method:, http_method:, fabrication_time:, timestamp:, **)
+ {
+ name: 'fabrication-stats',
+ time: time,
+ tags: {
+ resource: resource,
+ fabrication_method: fabrication_method,
+ http_method: http_method,
+ run_type: env('QA_RUN_TYPE') || run_type,
+ merge_request: merge_request
+ },
+ fields: {
+ fabrication_time: fabrication_time,
+ info: info,
+ job_url: QA::Runtime::Env.ci_job_url,
+ timestamp: timestamp
+ }
+ }
+ end
+
+ # Base ci job name
+ #
+ # @return [String]
+ def job_name
+ @job_name ||= QA::Runtime::Env.ci_job_name&.gsub(%r{ \d{1,2}/\d{1,2}}, '')
+ end
+
+ # Single common timestamp for all exported example metrics to keep data points consistently grouped
+ #
+ # @return [Time]
+ def time
+ @time ||= begin
+ return Time.now unless env('CI_PIPELINE_CREATED_AT')
+
+ env('CI_PIPELINE_CREATED_AT').to_time
+ end
+ end
+
+ # Is a merge request execution
+ #
+ # @return [String]
+ def merge_request
+ (!!merge_request_iid).to_s
+ end
+
+ # Is spec quarantined
+ #
+ # @param [Hash] metadata
+ # @return [String]
+ def quarantined(metadata)
+ return "false" unless metadata.key?(:quarantine)
+ return "true" unless metadata[:quarantine].is_a?(Hash)
+
+ (!Specs::Helpers::Quarantine.quarantined_different_context?(metadata[:quarantine])).to_s
+ end
+
+ # Return a more detailed status
+ #
+ # - if test is failed or pending, return rspec status
+ # - if test passed but had more than 1 attempt, consider test flaky
+ #
+ # @param [RSpec::Core::Example] example
+ # @return [String]
+ def status(example)
+ rspec_status = example.execution_result.status
+ return rspec_status if [:pending, :failed].include?(rspec_status)
+
+ retry_attempts(example.metadata) > 0 ? :flaky : :passed
+ end
+
+ # Check if test was skipped due to context condition
+ #
+ # @param [RSpec::Core::Example] example
+ # @return [Boolean]
+ def incompatible_env?(example)
+ return false unless example.execution_result.status == :pending
+ return false unless example.metadata[:skip]
+
+ !example.metadata[:skip].to_s.include?("quarantine") # rubocop:disable Rails/NegateInclude
+ end
+
+ # Retry attempts
+ #
+ # @param [Hash] metadata
+ # @return [Integer]
+ def retry_attempts(metadata)
+ metadata[:retry_attempts] || 0
+ end
+
+ # Print log message
+ #
+ # @param [Symbol] level
+ # @param [String] message
+ # @return [void]
+ def log(level, message)
+ QA::Runtime::Logger.public_send(level, "[influxdb exporter]: #{message}")
+ end
+
+ # Get spec devops stage
+ #
+ # @param [String] location
+ # @return [String, nil]
+ def devops_stage(file_path)
+ file_path.match(%r{\d{1,2}_(\w+)/})&.captures&.first
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/support/formatters/test_stats_formatter.rb b/qa/qa/support/formatters/test_stats_formatter.rb
deleted file mode 100644
index 2cde2d0928e..00000000000
--- a/qa/qa/support/formatters/test_stats_formatter.rb
+++ /dev/null
@@ -1,179 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Support
- module Formatters
- class TestStatsFormatter < RSpec::Core::Formatters::BaseFormatter
- include Support::InfluxdbTools
-
- RSpec::Core::Formatters.register(self, :stop)
-
- # Finish test execution
- #
- # @param [RSpec::Core::Notifications::ExamplesNotification] notification
- # @return [void]
- def stop(notification)
- push_test_stats(notification.examples)
- push_fabrication_stats
- end
-
- private
-
- # Push test execution stats to influxdb
- #
- # @param [Array<RSpec::Core::Example>] examples
- # @return [void]
- def push_test_stats(examples)
- data = examples.map { |example| test_stats(example) }.compact
-
- write_api.write(data: data)
- log(:debug, "Pushed #{data.length} test execution entries to influxdb")
- rescue StandardError => e
- log(:error, "Failed to push test execution stats to influxdb, error: #{e}")
- end
-
- # Push resource fabrication stats to influxdb
- #
- # @return [void]
- def push_fabrication_stats
- data = Tools::TestResourceDataProcessor.resources.flat_map do |resource, values|
- values.map { |v| fabrication_stats(resource: resource, **v) }
- end
- return if data.empty?
-
- write_api.write(data: data)
- log(:debug, "Pushed #{data.length} resource fabrication entries to influxdb")
- rescue StandardError => e
- log(:error, "Failed to push fabrication stats to influxdb, error: #{e}")
- end
-
- # Transform example to influxdb compatible metrics data
- # https://github.com/influxdata/influxdb-client-ruby#data-format
- #
- # @param [RSpec::Core::Example] example
- # @return [Hash]
- def test_stats(example)
- file_path = example.metadata[:file_path].gsub('./qa/specs/features', '')
- api_fabrication = ((example.metadata[:api_fabrication] || 0) * 1000).round
- ui_fabrication = ((example.metadata[:browser_ui_fabrication] || 0) * 1000).round
-
- {
- name: 'test-stats',
- time: time,
- tags: {
- name: example.full_description,
- file_path: file_path,
- status: example.execution_result.status,
- smoke: example.metadata.key?(:smoke).to_s,
- reliable: example.metadata.key?(:reliable).to_s,
- quarantined: quarantined(example.metadata),
- retried: ((example.metadata[:retry_attempts] || 0) > 0).to_s,
- job_name: job_name,
- merge_request: merge_request,
- run_type: run_type,
- stage: devops_stage(file_path),
- testcase: example.metadata[:testcase]
- },
- fields: {
- id: example.id,
- run_time: (example.execution_result.run_time * 1000).round,
- api_fabrication: api_fabrication,
- ui_fabrication: ui_fabrication,
- total_fabrication: api_fabrication + ui_fabrication,
- retry_attempts: example.metadata[:retry_attempts] || 0,
- job_url: QA::Runtime::Env.ci_job_url,
- pipeline_url: env('CI_PIPELINE_URL'),
- pipeline_id: env('CI_PIPELINE_ID'),
- job_id: env('CI_JOB_ID'),
- merge_request_iid: merge_request_iid
- }
- }
- rescue StandardError => e
- log(:error, "Failed to transform example '#{example.id}', error: #{e}")
- nil
- end
-
- # Resource fabrication data point
- #
- # @param [String] resource
- # @param [String] info
- # @param [Symbol] fabrication_method
- # @param [Symbol] http_method
- # @param [Integer] fabrication_time
- # @return [Hash]
- def fabrication_stats(resource:, info:, fabrication_method:, http_method:, fabrication_time:, timestamp:, **)
- {
- name: 'fabrication-stats',
- time: time,
- tags: {
- resource: resource,
- fabrication_method: fabrication_method,
- http_method: http_method,
- run_type: env('QA_RUN_TYPE') || run_type,
- merge_request: merge_request
- },
- fields: {
- fabrication_time: fabrication_time,
- info: info,
- job_url: QA::Runtime::Env.ci_job_url,
- timestamp: timestamp
- }
- }
- end
-
- # Base ci job name
- #
- # @return [String]
- def job_name
- @job_name ||= QA::Runtime::Env.ci_job_name&.gsub(%r{ \d{1,2}/\d{1,2}}, '')
- end
-
- # Single common timestamp for all exported example metrics to keep data points consistently grouped
- #
- # @return [Time]
- def time
- @time ||= begin
- return Time.now unless env('CI_PIPELINE_CREATED_AT')
-
- DateTime.strptime(env('CI_PIPELINE_CREATED_AT')).to_time
- end
- end
-
- # Is a merge request execution
- #
- # @return [String]
- def merge_request
- (!!merge_request_iid).to_s
- end
-
- # Is spec quarantined
- #
- # @param [Hash] metadata
- # @return [String]
- def quarantined(metadata)
- return "false" unless metadata.key?(:quarantine)
- return "true" unless metadata[:quarantine].is_a?(Hash)
-
- (!Specs::Helpers::Quarantine.quarantined_different_context?(metadata[:quarantine])).to_s
- end
-
- # Print log message
- #
- # @param [Symbol] level
- # @param [String] message
- # @return [void]
- def log(level, message)
- QA::Runtime::Logger.public_send(level, "[influxdb exporter]: #{message}")
- end
-
- # Get spec devops stage
- #
- # @param [String] location
- # @return [String, nil]
- def devops_stage(file_path)
- file_path.match(%r{\d{1,2}_(\w+)/})&.captures&.first
- end
- end
- end
- end
-end
diff --git a/qa/qa/support/influxdb_tools.rb b/qa/qa/support/influxdb_tools.rb
index e53b843ca87..e817b096864 100644
--- a/qa/qa/support/influxdb_tools.rb
+++ b/qa/qa/support/influxdb_tools.rb
@@ -7,7 +7,11 @@ module QA
# Common tools for use with influxdb metrics setup
#
module InfluxdbTools
+ # @return [String] bucket for storing all test run metrics
INFLUX_TEST_METRICS_BUCKET = "e2e-test-stats"
+ # @return [String] bucket for storing metrics from main runs
+ INFLUX_MAIN_TEST_METRICS_BUCKET = "e2e-test-stats-main"
+ # @return [Array] live environment names
LIVE_ENVS = %w[staging staging-canary staging-ref canary preprod production].freeze
private
diff --git a/qa/qa/support/loglinking.rb b/qa/qa/support/loglinking.rb
index ceddd35da17..f24577ff313 100644
--- a/qa/qa/support/loglinking.rb
+++ b/qa/qa/support/loglinking.rb
@@ -9,15 +9,12 @@ module QA
PRE_PROD_ADDRESS = 'https://pre.gitlab.com'
SENTRY_ENVIRONMENTS = {
staging: 'https://sentry.gitlab.net/gitlab/staginggitlabcom/?environment=gstg',
- staging_canary: 'https://sentry.gitlab.net/gitlab/staginggitlabcom/?environment=gstg-cny',
- staging_ref: 'https://sentry.gitlab.net/gitlab/staging-ref/?environment=gstg-ref',
- pre: 'https://sentry.gitlab.net/gitlab/pregitlabcom/?environment=pre',
- canary: 'https://sentry.gitlab.net/gitlab/gitlabcom/?environment=gprd',
- production: 'https://sentry.gitlab.net/gitlab/gitlabcom/?environment=gprd-cny'
+ staging_ref: 'https://sentry.gitlab.net/gitlab/staging-ref/?environment=all',
+ pre: 'https://sentry.gitlab.net/gitlab/pregitlabcom/?environment=all',
+ production: 'https://sentry.gitlab.net/gitlab/gitlabcom/?environment=gprd'
}.freeze
KIBANA_ENVIRONMENTS = {
staging: 'https://nonprod-log.gitlab.net/',
- staging_canary: 'https://nonprod-log.gitlab.net/',
canary: 'https://log.gprd.gitlab.net/',
production: 'https://log.gprd.gitlab.net/'
}.freeze
@@ -30,7 +27,7 @@ module QA
errors = ["Correlation Id: #{correlation_id}"]
errors << "Sentry Url: #{sentry_uri}&query=correlation_id%3A%22#{correlation_id}%22" if sentry_uri
- errors << "Kibana Url: #{kibana_uri}app/discover#/?_a=(query:(language:kuery,query:'json.correlation_id%20:%20#{correlation_id}'))&_g=(time:(from:now-24h%2Fh,to:now))" if kibana_uri
+ errors << "Kibana Url: #{kibana_uri}app/discover#/?_a=%28query%3A%28language%3Akuery%2Cquery%3A%27json.correlation_id%20%3A%20#{correlation_id}%27%29%29&_g=%28time%3A%28from%3Anow-24h%2Cto%3Anow%29%29" if kibana_uri
errors.join("\n")
end
@@ -53,11 +50,11 @@ module QA
case address
when STAGING_ADDRESS
- canary? ? :staging_canary : :staging
+ :staging
when STAGING_REF_ADDRESS
:staging_ref
when PRODUCTION_ADDRESS
- canary? ? :canary : :production
+ :production
when PRE_PROD_ADDRESS
:pre
else
@@ -68,19 +65,6 @@ module QA
def self.logging_environment?
!logging_environment.nil?
end
-
- def self.cookies
- browser_cookies = Capybara.current_session.driver.browser.manage.all_cookies
- # rubocop:disable Rails/IndexBy
- browser_cookies.each_with_object({}) do |cookie, memo|
- memo[cookie[:name]] = cookie
- end
- # rubocop:enable Rails/IndexBy
- end
-
- def self.canary?
- cookies.dig('gitlab_canary', :value) == 'true'
- end
end
end
end
diff --git a/qa/qa/support/page/logging.rb b/qa/qa/support/page/logging.rb
index 6dfb348a347..79ea4a8d001 100644
--- a/qa/qa/support/page/logging.rb
+++ b/qa/qa/support/page/logging.rb
@@ -54,18 +54,25 @@ module QA
elements
end
- def check_element(name, click_by_js = nil)
- log("checking :#{highlight_element(name)}", :info)
+ def check_element(name, click_by_js = false, **kwargs)
+ log_by_js("checking", name, click_by_js, **kwargs)
super
end
- def uncheck_element(name, click_by_js = nil)
- log("unchecking :#{highlight_element(name)}", :info)
+ def uncheck_element(name, click_by_js = false, **kwargs)
+ log_by_js("unchecking", name, click_by_js, **kwargs)
super
end
+ def log_by_js(action, name, click_by_js, **kwargs)
+ msg = action
+ msg += " via JS" if click_by_js
+ msg += " :#{highlight_element(name)} with args #{kwargs}"
+ log(msg, :info)
+ end
+
def click_element_coordinates(name, **kwargs)
log(%(clicking the coordinates of :#{highlight_element(name)}), :info)
diff --git a/qa/qa/tools/ci/qa_changes.rb b/qa/qa/tools/ci/qa_changes.rb
index 784923714d6..1ab93b6dfbf 100644
--- a/qa/qa/tools/ci/qa_changes.rb
+++ b/qa/qa/tools/ci/qa_changes.rb
@@ -10,7 +10,7 @@ module QA
include Helpers
QA_PATTERN = %r{^qa/}.freeze
- SPEC_PATTERN = %r{^qa/qa/specs/features/}.freeze
+ SPEC_PATTERN = %r{^qa/qa/specs/features/\S+_spec\.rb}.freeze
DEPENDENCY_PATTERN = Regexp.union(
/_VERSION/,
/Gemfile\.lock/,
diff --git a/qa/qa/tools/ci/test_metrics.rb b/qa/qa/tools/ci/test_metrics.rb
new file mode 100644
index 00000000000..96df432374a
--- /dev/null
+++ b/qa/qa/tools/ci/test_metrics.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require "active_support/core_ext/string/conversions"
+
+module QA
+ module Tools
+ module Ci
+ class TestMetrics
+ include Helpers
+ include Support::InfluxdbTools
+
+ def initialize(metrics_file_glob)
+ @metrics_file_glob = metrics_file_glob
+ end
+
+ def self.export(metrics_file_glob)
+ new(metrics_file_glob).export
+ end
+
+ # Export metrics to main bucket
+ #
+ # @return [void]
+ def export
+ return logger.warn("No files matched pattern '#{metrics_file_glob}'") if metrics_files.empty?
+
+ logger.info("Exporting #{metrics_data.size} entries to influxdb")
+ influx_client.create_write_api.write(data: metrics_data, bucket: INFLUX_MAIN_TEST_METRICS_BUCKET)
+ end
+
+ private
+
+ attr_reader :metrics_file_glob
+
+ # Metrics data files
+ #
+ # @return [Array]
+ def metrics_files
+ @metrics_files ||= Dir.glob(metrics_file_glob)
+ end
+
+ # Test metrics data
+ #
+ # @return [Array<Hash>]
+ def metrics_data
+ @metrics_data ||= metrics_files
+ .flat_map { |file| JSON.parse(File.read(file), symbolize_names: true) }
+ .map { |entry| entry.merge(time: entry[:time].to_time) }
+ end
+ end
+ end
+ end
+end
diff --git a/qa/qa/tools/delete_subgroups.rb b/qa/qa/tools/delete_subgroups.rb
index 355bd6bf10d..edf2f0ff5f0 100644
--- a/qa/qa/tools/delete_subgroups.rb
+++ b/qa/qa/tools/delete_subgroups.rb
@@ -1,70 +1,149 @@
# frozen_string_literal: true
# This script deletes all subgroups of a group specified by ENV['TOP_LEVEL_GROUP_NAME']
+#
# Required environment variables: GITLAB_QA_ACCESS_TOKEN and GITLAB_ADDRESS
-# Optional environment variable: TOP_LEVEL_GROUP_NAME (defaults to 'gitlab-qa-sandbox-group')
+# Optional environment variable: TOP_LEVEL_GROUP_NAME (defaults to 'gitlab-qa-sandbox-group-<current weekday #>')
+
+# Optional environment variable: PERMANENTLY_DELETE (defaults to false)
+# Set PERMANENTLY_DELETE to true if you would like to permanently delete subgroups on an environment with
+# deletion protection enabled. Otherwise, subgroups will remain available during the retention period specified
+# in admin settings. On environments with deletion protection disabled, subgroups will always be permanently deleted.
+#
# Run `rake delete_subgroups`
module QA
module Tools
class DeleteSubgroups
include Support::API
+ include Ci::Helpers
def initialize
raise ArgumentError, "Please provide GITLAB_ADDRESS" unless ENV['GITLAB_ADDRESS']
raise ArgumentError, "Please provide GITLAB_QA_ACCESS_TOKEN" unless ENV['GITLAB_QA_ACCESS_TOKEN']
@api_client = Runtime::API::Client.new(ENV['GITLAB_ADDRESS'], personal_access_token: ENV['GITLAB_QA_ACCESS_TOKEN'])
+ @failed_deletion_attempts = []
end
def run
- $stdout.puts 'Fetching subgroups for deletion...'
+ group_id = fetch_group_id
+ return logger.info('Top level group not found') if group_id.nil?
- sub_group_ids = fetch_subgroup_ids
- $stdout.puts "\nNumber of Sub Groups not already marked for deletion: #{sub_group_ids.length}"
+ subgroups = fetch_subgroups(group_id)
+ return logger.info('No subgroups available') if subgroups.empty?
- delete_subgroups(sub_group_ids) unless sub_group_ids.empty?
- $stdout.puts "\nDone"
- end
+ subgroups_marked_for_deletion = mark_for_deletion(subgroups)
- private
+ if ENV['PERMANENTLY_DELETE'] && !subgroups_marked_for_deletion.empty?
+ delete_permanently(subgroups_marked_for_deletion)
+ end
- def delete_subgroups(sub_group_ids)
- $stdout.puts "Deleting #{sub_group_ids.length} subgroups..."
- sub_group_ids.each do |subgroup_id|
- request_url = Runtime::API::Request.new(@api_client, "/groups/#{subgroup_id}").url
- path = parse_body(get(request_url))[:full_path]
- $stdout.puts "\nDeleting subgroup #{path}..."
+ print_failed_deletion_attempts
- delete_response = delete(request_url)
- dot_or_f = delete_response.code == 202 ? "\e[32m.\e[0m" : "\e[31mF - #{delete_response}\e[0m"
- print dot_or_f
- end
+ logger.info('Done')
end
+ private
+
def fetch_group_id
+ logger.info("Fetching top level group id...\n")
+
group_name = ENV['TOP_LEVEL_GROUP_NAME'] || "gitlab-qa-sandbox-group-#{Time.now.wday + 1}"
group_search_response = get Runtime::API::Request.new(@api_client, "/groups/#{group_name}" ).url
- JSON.parse(group_search_response.body)["id"]
+ JSON.parse(group_search_response.body)['id']
end
- def fetch_subgroup_ids
- group_id = fetch_group_id
- sub_groups_ids = []
+ def fetch_subgroups(group_id)
+ logger.info("Fetching subgroups...")
+
+ api_path = "/groups/#{group_id}/subgroups"
page_no = '1'
+ subgroups = []
- # When we reach the last page, the x-next-page header is a blank string
while page_no.present?
- $stdout.print '.'
+ subgroups_response = get Runtime::API::Request.new(@api_client, api_path, page: page_no, per_page: '100').url
+ subgroups.concat(JSON.parse(subgroups_response.body))
+
+ page_no = subgroups_response.headers[:x_next_page].to_s
+ end
+
+ subgroups
+ end
+
+ def subgroup_request(subgroup, **options)
+ Runtime::API::Request.new(@api_client, "/groups/#{subgroup['id']}", **options).url
+ end
+
+ def process_response_and_subgroup(response, subgroup, opts = {})
+ if response.code == 202
+ logger.info("Success\n")
+ opts[:save_successes_to] << subgroup if opts[:save_successes_to]
+ else
+ logger.error("Failed - #{response}\n")
+ @failed_deletion_attempts << { path: subgroup['full_path'], response: response }
+ end
+ end
+
+ def mark_for_deletion(subgroups)
+ subgroups_marked_for_deletion = []
+
+ logger.info("Marking #{subgroups.length} subgroups for deletion...\n")
+
+ subgroups.each do |subgroup|
+ path = subgroup['full_path']
+
+ if subgroup['marked_for_deletion_on'].nil?
+ logger.info("Marking subgroup #{path} for deletion...")
+ response = delete(subgroup_request(subgroup))
- sub_groups_response = get Runtime::API::Request.new(@api_client, "/groups/#{group_id}/subgroups", page: page_no, per_page: '100').url
- sub_groups_ids.concat(JSON.parse(sub_groups_response.body)
- .reject { |subgroup| !subgroup["marked_for_deletion_on"].nil? }.map { |subgroup| subgroup['id'] })
+ process_response_and_subgroup(response, subgroup, save_successes_to: subgroups_marked_for_deletion)
+ else
+ logger.info("Subgroup #{path} already marked for deletion\n")
+ subgroups_marked_for_deletion << subgroup
+ end
+ end
+
+ subgroups_marked_for_deletion
+ end
- page_no = sub_groups_response.headers[:x_next_page].to_s
+ def subgroup_exists?(subgroup)
+ response = get(subgroup_request(subgroup))
+
+ if response.code == 404
+ logger.info("Subgroup #{subgroup['full_path']} is no longer available\n")
+ false
+ else
+ true
end
+ end
- sub_groups_ids.uniq
+ def delete_permanently(subgroups)
+ logger.info("Permanently deleting #{subgroups.length} subgroups...\n")
+
+ subgroups.each do |subgroup|
+ path = subgroup['full_path']
+
+ next unless subgroup_exists?(subgroup)
+
+ logger.info("Permanently deleting subgroup #{path}...")
+ delete_subgroup_response = delete(subgroup_request(subgroup, { permanently_remove: true, full_path: path }))
+
+ process_response_and_subgroup(delete_subgroup_response, subgroup)
+ end
+ end
+
+ def print_failed_deletion_attempts
+ if @failed_deletion_attempts.empty?
+ logger.info('No failed deletion attempts to report!')
+ else
+ logger.info("There were #{@failed_deletion_attempts.length} failed deletion attempts:\n")
+
+ @failed_deletion_attempts.each do |attempt|
+ logger.info("Subgroup: #{attempt[:path]}")
+ logger.error("Response: #{attempt[:response]}\n")
+ end
+ end
end
end
end
diff --git a/qa/spec/resource/api_fabricator_spec.rb b/qa/spec/resource/api_fabricator_spec.rb
index 581236e5ac5..4cb6ef3c9b5 100644
--- a/qa/spec/resource/api_fabricator_spec.rb
+++ b/qa/spec/resource/api_fabricator_spec.rb
@@ -155,8 +155,8 @@ RSpec.describe QA::Resource::ApiFabricator do
expect(error.to_s).to eql(<<~ERROR.chomp)
Fabrication of FooBarResource using the API failed (400) with `#{raw_post}`.
Correlation Id: foobar
- Sentry Url: https://sentry.gitlab.net/gitlab/staginggitlabcom/?environment=gstg-cny&query=correlation_id%3A%22foobar%22
- Kibana Url: https://nonprod-log.gitlab.net/app/discover#/?_a=(query:(language:kuery,query:'json.correlation_id%20:%20foobar'))&_g=(time:(from:now-24h%2Fh,to:now))
+ Sentry Url: https://sentry.gitlab.net/gitlab/staginggitlabcom/?environment=gstg&query=correlation_id%3A%22foobar%22
+ Kibana Url: https://nonprod-log.gitlab.net/app/discover#/?_a=%28query%3A%28language%3Akuery%2Cquery%3A%27json.correlation_id%20%3A%20foobar%27%29%29&_g=%28time%3A%28from%3Anow-24h%2Cto%3Anow%29%29
ERROR
end
end
diff --git a/qa/spec/resource/base_spec.rb b/qa/spec/resource/base_spec.rb
index 195e497f290..0ec27da7277 100644
--- a/qa/spec/resource/base_spec.rb
+++ b/qa/spec/resource/base_spec.rb
@@ -87,12 +87,46 @@ RSpec.describe QA::Resource::Base do
end
context 'when resource supports fabrication via the API' do
- it 'calls .fabricate_via_browser_ui!' do
+ it 'calls .fabricate_via_api!!' do
expect(described_class).to receive(:fabricate_via_api!)
described_class.fabricate!
end
end
+
+ context 'when FIPS mode is enabled' do
+ before do
+ stub_env('FIPS', '1')
+ end
+
+ it 'calls .fabricate_via_browser_ui!' do
+ expect(described_class).to receive(:fabricate_via_browser_ui!)
+
+ described_class.fabricate!
+ end
+ end
+ end
+
+ describe '.fabricate_via_api_unless_fips!' do
+ context 'when FIPS mode is not enabled' do
+ it 'calls .fabricate_via_api!!' do
+ expect(described_class).to receive(:fabricate_via_api!)
+
+ described_class.fabricate_via_api_unless_fips!
+ end
+ end
+
+ context 'when FIPS mode is enabled' do
+ before do
+ stub_env('FIPS', '1')
+ end
+
+ it 'calls .fabricate_via_browser_ui!' do
+ expect(described_class).to receive(:fabricate_via_browser_ui!)
+
+ described_class.fabricate_via_api_unless_fips!
+ end
+ end
end
describe '.fabricate_via_api!' do
diff --git a/qa/spec/resource/user_spec.rb b/qa/spec/resource/user_spec.rb
index d82dcc3b21e..d1fc02ff033 100644
--- a/qa/spec/resource/user_spec.rb
+++ b/qa/spec/resource/user_spec.rb
@@ -116,4 +116,31 @@ RSpec.describe QA::Resource::User do
expect(subject).to be_credentials_given
end
end
+
+ describe '#has_user?' do
+ let(:index_mock) do
+ instance_double(QA::Page::Admin::Overview::Users::Index)
+ end
+
+ users = [
+ ['foo', true],
+ ['bar', false]
+ ]
+
+ users.each do |(username, found)|
+ it "returns #{found} when has_username returns #{found}" do
+ subject.username = username
+
+ allow(QA::Flow::Login).to receive(:while_signed_in_as_admin).and_yield
+ allow(QA::Page::Main::Menu).to receive(:perform)
+ allow(QA::Page::Admin::Menu).to receive(:perform)
+ allow(QA::Page::Admin::Overview::Users::Index).to receive(:perform).and_yield(index_mock)
+
+ expect(index_mock).to receive(:search_user).with(username)
+ expect(index_mock).to receive(:has_username?).with(username).and_return(found)
+
+ expect(subject.has_user?(subject)).to eq(found)
+ end
+ end
+ end
end
diff --git a/qa/spec/specs/runner_spec.rb b/qa/spec/specs/runner_spec.rb
index dd013497367..cbe5699a306 100644
--- a/qa/spec/specs/runner_spec.rb
+++ b/qa/spec/specs/runner_spec.rb
@@ -111,7 +111,7 @@ RSpec.describe QA::Specs::Runner do
it 'sets the `--dry-run` flag' do
expect_rspec_runner_arguments(
- ['--dry-run'] + DEFAULT_SKIPPED_TAGS + ['--tag', '~geo', *described_class::DEFAULT_TEST_PATH_ARGS],
+ ['--dry-run', *described_class::DEFAULT_TEST_PATH_ARGS],
[$stderr, anything]
)
diff --git a/qa/spec/support/formatters/test_metrics_formatter_spec.rb b/qa/spec/support/formatters/test_metrics_formatter_spec.rb
new file mode 100644
index 00000000000..76bde98cc33
--- /dev/null
+++ b/qa/spec/support/formatters/test_metrics_formatter_spec.rb
@@ -0,0 +1,336 @@
+# frozen_string_literal: true
+
+require 'rspec/core/sandbox'
+require 'active_support/testing/time_helpers'
+
+describe QA::Support::Formatters::TestMetricsFormatter do
+ include QA::Support::Helpers::StubEnv
+ include QA::Specs::Helpers::RSpec
+ include ActiveSupport::Testing::TimeHelpers
+
+ let(:url) { 'http://influxdb.net' }
+ let(:token) { 'token' }
+ let(:ci_timestamp) { '2021-02-23T20:58:41Z' }
+ let(:ci_job_name) { 'test-job 1/5' }
+ let(:ci_job_url) { 'url' }
+ let(:ci_pipeline_url) { 'url' }
+ let(:ci_pipeline_id) { '123' }
+ let(:ci_job_id) { '321' }
+ let(:run_type) { 'staging-full' }
+ let(:smoke) { 'false' }
+ let(:reliable) { 'false' }
+ let(:quarantined) { 'false' }
+ let(:influx_client) { instance_double('InfluxDB2::Client', create_write_api: influx_write_api) }
+ let(:influx_write_api) { instance_double('InfluxDB2::WriteApi', write: nil) }
+ let(:stage) { '1_manage' }
+ let(:file_path) { "./qa/specs/features/#{stage}/subfolder/some_spec.rb" }
+ let(:ui_fabrication) { 0 }
+ let(:api_fabrication) { 0 }
+ let(:fabrication_resources) { {} }
+ let(:testcase) { 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234' }
+ let(:product_group) { nil }
+
+ let(:influx_client_args) do
+ {
+ bucket: 'e2e-test-stats',
+ org: 'gitlab-qa',
+ precision: InfluxDB2::WritePrecision::NANOSECOND
+ }
+ end
+
+ let(:data) do
+ {
+ name: 'test-stats',
+ time: DateTime.strptime(ci_timestamp).to_time,
+ tags: {
+ name: 'stats export spec',
+ file_path: file_path.gsub('./qa/specs/features', ''),
+ status: :passed,
+ smoke: smoke,
+ reliable: reliable,
+ quarantined: quarantined,
+ retried: 'false',
+ job_name: 'test-job',
+ merge_request: 'false',
+ run_type: run_type,
+ stage: stage.match(%r{\d{1,2}_(\w+)}).captures.first,
+ product_group: product_group,
+ testcase: testcase
+ },
+ fields: {
+ id: './spec/support/formatters/test_metrics_formatter_spec.rb[1:1]',
+ run_time: 0,
+ api_fabrication: api_fabrication * 1000,
+ ui_fabrication: ui_fabrication * 1000,
+ total_fabrication: (api_fabrication + ui_fabrication) * 1000,
+ retry_attempts: 0,
+ job_url: ci_job_url,
+ pipeline_url: ci_pipeline_url,
+ pipeline_id: ci_pipeline_id,
+ job_id: ci_job_id,
+ merge_request_iid: nil
+ }
+ }
+ end
+
+ def run_spec(&spec)
+ spec ||= -> { it('spec', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234') {} }
+
+ describe_successfully('stats export', &spec).tap do |example_group|
+ example_group.examples.each { |ex| ex.metadata[:file_path] = file_path }
+ end
+ send_stop_notification
+ end
+
+ around do |example|
+ RSpec::Core::Sandbox.sandboxed do |config|
+ config.formatter = described_class
+ config.before(:context) { RSpec.current_example = nil }
+
+ example.run
+ end
+ end
+
+ before do
+ allow(InfluxDB2::Client).to receive(:new).with(url, token, **influx_client_args) { influx_client }
+ allow(QA::Tools::TestResourceDataProcessor).to receive(:resources) { fabrication_resources }
+ allow_any_instance_of(RSpec::Core::Example::ExecutionResult).to receive(:run_time).and_return(0) # rubocop:disable RSpec/AnyInstanceOf
+ end
+
+ context 'without influxdb variables configured' do
+ it 'skips export without influxdb url' do
+ stub_env('QA_INFLUXDB_URL', nil)
+ stub_env('QA_INFLUXDB_TOKEN', nil)
+
+ run_spec
+
+ expect(influx_client).not_to have_received(:create_write_api)
+ end
+
+ it 'skips export without influxdb token' do
+ stub_env('QA_INFLUXDB_URL', url)
+ stub_env('QA_INFLUXDB_TOKEN', nil)
+
+ run_spec
+
+ expect(influx_client).not_to have_received(:create_write_api)
+ end
+ end
+
+ context 'with influxdb variables configured' do
+ let(:spec_name) { 'exports data' }
+ let(:run_type) { ci_job_name.gsub(%r{ \d{1,2}/\d{1,2}}, '') }
+
+ before do
+ stub_env('QA_INFLUXDB_URL', url)
+ stub_env('QA_INFLUXDB_TOKEN', token)
+ stub_env('CI_PIPELINE_CREATED_AT', ci_timestamp)
+ stub_env('CI_JOB_URL', ci_job_url)
+ stub_env('CI_JOB_NAME', ci_job_name)
+ stub_env('CI_PIPELINE_URL', ci_pipeline_url)
+ stub_env('CI_PIPELINE_ID', ci_pipeline_id)
+ stub_env('CI_JOB_ID', ci_job_id)
+ stub_env('CI_MERGE_REQUEST_IID', nil)
+ stub_env('TOP_UPSTREAM_MERGE_REQUEST_IID', nil)
+ stub_env('QA_RUN_TYPE', run_type)
+ stub_env('QA_EXPORT_TEST_METRICS', "true")
+ end
+
+ context 'with reliable spec' do
+ let(:reliable) { 'true' }
+
+ it 'exports data to influxdb with correct reliable tag' do
+ run_spec do
+ it('spec', :reliable, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234') {}
+ end
+
+ expect(influx_write_api).to have_received(:write).once
+ expect(influx_write_api).to have_received(:write).with(data: [data])
+ end
+ end
+
+ context 'with product group tag' do
+ let(:product_group) { :import }
+
+ it 'exports data to influxdb with correct reliable tag' do
+ run_spec do
+ it('spec', product_group: :import, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234') {}
+ end
+
+ expect(influx_write_api).to have_received(:write).once
+ expect(influx_write_api).to have_received(:write).with(data: [data])
+ end
+ end
+
+ context 'with smoke spec' do
+ let(:smoke) { 'true' }
+
+ it 'exports data to influxdb with correct smoke tag' do
+ run_spec do
+ it('spec', :smoke, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234') {}
+ end
+
+ expect(influx_write_api).to have_received(:write).once
+ expect(influx_write_api).to have_received(:write).with(data: [data])
+ end
+ end
+
+ context 'with quarantined spec' do
+ let(:quarantined) { 'true' }
+
+ it 'exports data to influxdb with correct quarantine tag' do
+ run_spec do
+ it('spec', :quarantine, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234') {}
+ end
+
+ expect(influx_write_api).to have_received(:write).once
+ expect(influx_write_api).to have_received(:write).with(data: [data])
+ end
+ end
+
+ context 'with context quarantined spec' do
+ let(:quarantined) { 'false' }
+
+ it 'exports data to influxdb with correct qurantine tag' do
+ run_spec do
+ it(
+ 'spec',
+ quarantine: { only: { job: 'praefect' } },
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234'
+ ) {}
+ end
+
+ expect(influx_write_api).to have_received(:write).once
+ expect(influx_write_api).to have_received(:write).with(data: [data])
+ end
+ end
+
+ context 'with skipped spec' do
+ it 'skips export' do
+ run_spec do
+ it(
+ 'spec',
+ skip: 'not compatible',
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234'
+ ) {}
+ end
+
+ expect(influx_write_api).to have_received(:write).with(data: [])
+ end
+ end
+
+ context 'with staging full run' do
+ let(:run_type) { 'staging-full' }
+
+ before do
+ stub_env('CI_PROJECT_NAME', 'staging')
+ stub_env('QA_RUN_TYPE', nil)
+ end
+
+ it 'exports data to influxdb with correct run type' do
+ run_spec
+
+ expect(influx_write_api).to have_received(:write).once
+ expect(influx_write_api).to have_received(:write).with(data: [data])
+ end
+ end
+
+ context 'with staging sanity no admin' do
+ let(:run_type) { 'staging-sanity-no-admin' }
+
+ before do
+ stub_env('CI_PROJECT_NAME', 'staging')
+ stub_env('NO_ADMIN', 'true')
+ stub_env('SMOKE_ONLY', 'true')
+ stub_env('QA_RUN_TYPE', nil)
+ end
+
+ it 'exports data to influxdb with correct run type' do
+ run_spec
+
+ expect(influx_write_api).to have_received(:write).once
+ expect(influx_write_api).to have_received(:write).with(data: [data])
+ end
+ end
+
+ context 'with fabrication runtimes' do
+ let(:api_fabrication) { 4 }
+ let(:ui_fabrication) { 10 }
+ let(:testcase) { nil }
+
+ it 'exports data to influxdb with fabrication times' do
+ run_spec do
+ # Main logic tracks fabrication time in thread local variable and injects it as metadata from
+ # global after hook defined in main spec_helper.
+ #
+ # Inject the values directly since we do not load e2e test spec_helper in unit tests
+ it('spec', api_fabrication: 4, browser_ui_fabrication: 10) {}
+ end
+
+ expect(influx_write_api).to have_received(:write).once
+ expect(influx_write_api).to have_received(:write).with(data: [data])
+ end
+ end
+
+ context 'with fabrication resources' do
+ let(:fabrication_resources) do
+ {
+ 'QA::Resource::Project' => [{
+ info: "with id '1'",
+ api_path: '/project',
+ fabrication_method: :api,
+ fabrication_time: 1,
+ http_method: :post,
+ timestamp: Time.now.to_s
+ }]
+ }
+ end
+
+ let(:fabrication_data) do
+ {
+ name: 'fabrication-stats',
+ time: DateTime.strptime(ci_timestamp).to_time,
+ tags: {
+ resource: 'QA::Resource::Project',
+ fabrication_method: :api,
+ http_method: :post,
+ run_type: run_type,
+ merge_request: "false"
+ },
+ fields: {
+ fabrication_time: 1,
+ info: "with id '1'",
+ job_url: ci_job_url,
+ timestamp: Time.now.to_s
+ }
+ }
+ end
+
+ around do |example|
+ freeze_time { example.run }
+ end
+
+ it 'exports fabrication stats data to influxdb' do
+ run_spec
+
+ expect(influx_write_api).to have_received(:write).with(data: [fabrication_data])
+ end
+ end
+
+ context 'with persisting metrics' do
+ before do
+ stub_env('QA_EXPORT_TEST_METRICS', "false")
+ stub_env('QA_SAVE_TEST_METRICS', "true")
+ stub_env('CI_JOB_NAME_SLUG', "test-job")
+
+ allow(File).to receive(:write)
+ end
+
+ it 'saves test metrics as json files' do
+ run_spec
+
+ expect(File).to have_received(:write).with("tmp/test-metrics-test-job.json", [data].to_json)
+ end
+ end
+ end
+end
diff --git a/qa/spec/support/formatters/test_stats_formatter_spec.rb b/qa/spec/support/formatters/test_stats_formatter_spec.rb
deleted file mode 100644
index d0d89b5ee73..00000000000
--- a/qa/spec/support/formatters/test_stats_formatter_spec.rb
+++ /dev/null
@@ -1,290 +0,0 @@
-# frozen_string_literal: true
-
-require 'rspec/core/sandbox'
-require 'active_support/testing/time_helpers'
-
-describe QA::Support::Formatters::TestStatsFormatter do
- include QA::Support::Helpers::StubEnv
- include QA::Specs::Helpers::RSpec
- include ActiveSupport::Testing::TimeHelpers
-
- let(:url) { 'http://influxdb.net' }
- let(:token) { 'token' }
- let(:ci_timestamp) { '2021-02-23T20:58:41Z' }
- let(:ci_job_name) { 'test-job 1/5' }
- let(:ci_job_url) { 'url' }
- let(:ci_pipeline_url) { 'url' }
- let(:ci_pipeline_id) { '123' }
- let(:ci_job_id) { '321' }
- let(:run_type) { 'staging-full' }
- let(:smoke) { 'false' }
- let(:reliable) { 'false' }
- let(:quarantined) { 'false' }
- let(:influx_client) { instance_double('InfluxDB2::Client', create_write_api: influx_write_api) }
- let(:influx_write_api) { instance_double('InfluxDB2::WriteApi', write: nil) }
- let(:stage) { '1_manage' }
- let(:file_path) { "./qa/specs/features/#{stage}/subfolder/some_spec.rb" }
- let(:ui_fabrication) { 0 }
- let(:api_fabrication) { 0 }
- let(:fabrication_resources) { {} }
- let(:testcase) { 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234' }
-
- let(:influx_client_args) do
- {
- bucket: 'e2e-test-stats',
- org: 'gitlab-qa',
- precision: InfluxDB2::WritePrecision::NANOSECOND
- }
- end
-
- let(:data) do
- {
- name: 'test-stats',
- time: DateTime.strptime(ci_timestamp).to_time,
- tags: {
- name: 'stats export spec',
- file_path: file_path.gsub('./qa/specs/features', ''),
- status: :passed,
- smoke: smoke,
- reliable: reliable,
- quarantined: quarantined,
- retried: 'false',
- job_name: 'test-job',
- merge_request: 'false',
- run_type: run_type,
- stage: stage.match(%r{\d{1,2}_(\w+)}).captures.first,
- testcase: testcase
- },
- fields: {
- id: './spec/support/formatters/test_stats_formatter_spec.rb[1:1]',
- run_time: 0,
- api_fabrication: api_fabrication * 1000,
- ui_fabrication: ui_fabrication * 1000,
- total_fabrication: (api_fabrication + ui_fabrication) * 1000,
- retry_attempts: 0,
- job_url: ci_job_url,
- pipeline_url: ci_pipeline_url,
- pipeline_id: ci_pipeline_id,
- job_id: ci_job_id,
- merge_request_iid: nil
- }
- }
- end
-
- def run_spec(&spec)
- spec ||= -> { it('spec', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234') {} }
-
- describe_successfully('stats export', &spec).tap do |example_group|
- example_group.examples.each { |ex| ex.metadata[:file_path] = file_path }
- end
- send_stop_notification
- end
-
- around do |example|
- RSpec::Core::Sandbox.sandboxed do |config|
- config.formatter = described_class
- config.before(:context) { RSpec.current_example = nil }
-
- example.run
- end
- end
-
- before do
- allow(InfluxDB2::Client).to receive(:new).with(url, token, **influx_client_args) { influx_client }
- allow(QA::Tools::TestResourceDataProcessor).to receive(:resources) { fabrication_resources }
- allow_any_instance_of(RSpec::Core::Example::ExecutionResult).to receive(:run_time).and_return(0) # rubocop:disable RSpec/AnyInstanceOf
- end
-
- context 'without influxdb variables configured' do
- it 'skips export without influxdb url' do
- stub_env('QA_INFLUXDB_URL', nil)
- stub_env('QA_INFLUXDB_TOKEN', nil)
-
- run_spec
-
- expect(influx_client).not_to have_received(:create_write_api)
- end
-
- it 'skips export without influxdb token' do
- stub_env('QA_INFLUXDB_URL', url)
- stub_env('QA_INFLUXDB_TOKEN', nil)
-
- run_spec
-
- expect(influx_client).not_to have_received(:create_write_api)
- end
- end
-
- context 'with influxdb variables configured' do
- let(:spec_name) { 'exports data' }
- let(:run_type) { ci_job_name.gsub(%r{ \d{1,2}/\d{1,2}}, '') }
-
- before do
- stub_env('QA_INFLUXDB_URL', url)
- stub_env('QA_INFLUXDB_TOKEN', token)
- stub_env('CI_PIPELINE_CREATED_AT', ci_timestamp)
- stub_env('CI_JOB_URL', ci_job_url)
- stub_env('CI_JOB_NAME', ci_job_name)
- stub_env('CI_PIPELINE_URL', ci_pipeline_url)
- stub_env('CI_PIPELINE_ID', ci_pipeline_id)
- stub_env('CI_JOB_ID', ci_job_id)
- stub_env('CI_MERGE_REQUEST_IID', nil)
- stub_env('TOP_UPSTREAM_MERGE_REQUEST_IID', nil)
- stub_env('QA_RUN_TYPE', run_type)
- end
-
- context 'with reliable spec' do
- let(:reliable) { 'true' }
-
- it 'exports data to influxdb with correct reliable tag' do
- run_spec do
- it('spec', :reliable, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234') {}
- end
-
- expect(influx_write_api).to have_received(:write).once
- expect(influx_write_api).to have_received(:write).with(data: [data])
- end
- end
-
- context 'with smoke spec' do
- let(:smoke) { 'true' }
-
- it 'exports data to influxdb with correct smoke tag' do
- run_spec do
- it('spec', :smoke, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234') {}
- end
-
- expect(influx_write_api).to have_received(:write).once
- expect(influx_write_api).to have_received(:write).with(data: [data])
- end
- end
-
- context 'with quarantined spec' do
- let(:quarantined) { 'true' }
-
- it 'exports data to influxdb with correct quarantine tag' do
- run_spec do
- it('spec', :quarantine, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234') {}
- end
-
- expect(influx_write_api).to have_received(:write).once
- expect(influx_write_api).to have_received(:write).with(data: [data])
- end
- end
-
- context 'with context quarantined spec' do
- let(:quarantined) { 'false' }
-
- it 'exports data to influxdb with correct qurantine tag' do
- run_spec do
- it(
- 'spec',
- quarantine: { only: { job: 'praefect' } },
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/1234'
- ) {}
- end
-
- expect(influx_write_api).to have_received(:write).once
- expect(influx_write_api).to have_received(:write).with(data: [data])
- end
- end
-
- context 'with staging full run' do
- let(:run_type) { 'staging-full' }
-
- before do
- stub_env('CI_PROJECT_NAME', 'staging')
- stub_env('QA_RUN_TYPE', nil)
- end
-
- it 'exports data to influxdb with correct run type' do
- run_spec
-
- expect(influx_write_api).to have_received(:write).once
- expect(influx_write_api).to have_received(:write).with(data: [data])
- end
- end
-
- context 'with staging sanity no admin' do
- let(:run_type) { 'staging-sanity-no-admin' }
-
- before do
- stub_env('CI_PROJECT_NAME', 'staging')
- stub_env('NO_ADMIN', 'true')
- stub_env('SMOKE_ONLY', 'true')
- stub_env('QA_RUN_TYPE', nil)
- end
-
- it 'exports data to influxdb with correct run type' do
- run_spec
-
- expect(influx_write_api).to have_received(:write).once
- expect(influx_write_api).to have_received(:write).with(data: [data])
- end
- end
-
- context 'with fabrication runtimes' do
- let(:api_fabrication) { 4 }
- let(:ui_fabrication) { 10 }
- let(:testcase) { nil }
-
- it 'exports data to influxdb with fabrication times' do
- run_spec do
- # Main logic tracks fabrication time in thread local variable and injects it as metadata from
- # global after hook defined in main spec_helper.
- #
- # Inject the values directly since we do not load e2e test spec_helper in unit tests
- it('spec', api_fabrication: 4, browser_ui_fabrication: 10) {}
- end
-
- expect(influx_write_api).to have_received(:write).once
- expect(influx_write_api).to have_received(:write).with(data: [data])
- end
- end
-
- context 'with fabrication resources' do
- let(:fabrication_resources) do
- {
- 'QA::Resource::Project' => [{
- info: "with id '1'",
- api_path: '/project',
- fabrication_method: :api,
- fabrication_time: 1,
- http_method: :post,
- timestamp: Time.now.to_s
- }]
- }
- end
-
- let(:fabrication_data) do
- {
- name: 'fabrication-stats',
- time: DateTime.strptime(ci_timestamp).to_time,
- tags: {
- resource: 'QA::Resource::Project',
- fabrication_method: :api,
- http_method: :post,
- run_type: run_type,
- merge_request: "false"
- },
- fields: {
- fabrication_time: 1,
- info: "with id '1'",
- job_url: ci_job_url,
- timestamp: Time.now.to_s
- }
- }
- end
-
- around do |example|
- freeze_time { example.run }
- end
-
- it 'exports fabrication stats data to influxdb' do
- run_spec
-
- expect(influx_write_api).to have_received(:write).with(data: [fabrication_data])
- end
- end
- end
-end
diff --git a/qa/spec/support/loglinking_spec.rb b/qa/spec/support/loglinking_spec.rb
index d1cc76bccc4..10865068e3d 100644
--- a/qa/spec/support/loglinking_spec.rb
+++ b/qa/spec/support/loglinking_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe QA::Support::Loglinking do
expect(QA::Support::Loglinking.failure_metadata('foo123')).to eql(<<~ERROR.chomp)
Correlation Id: foo123
- Kibana Url: https://kibana.address/app/discover#/?_a=(query:(language:kuery,query:'json.correlation_id%20:%20foo123'))&_g=(time:(from:now-24h%2Fh,to:now))
+ Kibana Url: https://kibana.address/app/discover#/?_a=%28query%3A%28language%3Akuery%2Cquery%3A%27json.correlation_id%20%3A%20foo123%27%29%29&_g=%28time%3A%28from%3Anow-24h%2Cto%3Anow%29%29
ERROR
end
end
@@ -39,11 +39,9 @@ RSpec.describe QA::Support::Loglinking do
let(:url_hash) do
{
:staging => 'https://sentry.gitlab.net/gitlab/staginggitlabcom/?environment=gstg',
- :staging_canary => 'https://sentry.gitlab.net/gitlab/staginggitlabcom/?environment=gstg-cny',
- :staging_ref => 'https://sentry.gitlab.net/gitlab/staging-ref/?environment=gstg-ref',
- :pre => 'https://sentry.gitlab.net/gitlab/pregitlabcom/?environment=pre',
- :canary => 'https://sentry.gitlab.net/gitlab/gitlabcom/?environment=gprd',
- :production => 'https://sentry.gitlab.net/gitlab/gitlabcom/?environment=gprd-cny',
+ :staging_ref => 'https://sentry.gitlab.net/gitlab/staging-ref/?environment=all',
+ :pre => 'https://sentry.gitlab.net/gitlab/pregitlabcom/?environment=all',
+ :production => 'https://sentry.gitlab.net/gitlab/gitlabcom/?environment=gprd',
:foo => nil,
nil => nil
}
@@ -62,10 +60,7 @@ RSpec.describe QA::Support::Loglinking do
let(:url_hash) do
{
:staging => 'https://nonprod-log.gitlab.net/',
- :staging_canary => 'https://nonprod-log.gitlab.net/',
:staging_ref => nil,
- :pre => nil,
- :canary => 'https://log.gprd.gitlab.net/',
:production => 'https://log.gprd.gitlab.net/',
:foo => nil,
nil => nil
@@ -90,37 +85,22 @@ RSpec.describe QA::Support::Loglinking do
[
{
address: staging_address,
- canary: false,
expected_env: :staging
},
{
- address: staging_address,
- canary: true,
- expected_env: :staging_canary
- },
- {
address: staging_ref_address,
- canary: true,
expected_env: :staging_ref
},
{
address: production_address,
- canary: false,
expected_env: :production
},
{
- address: production_address,
- canary: true,
- expected_env: :canary
- },
- {
address: pre_prod_address,
- canary: true,
expected_env: :pre
},
{
address: 'https://foo.com',
- canary: true,
expected_env: nil
}
]
@@ -129,7 +109,6 @@ RSpec.describe QA::Support::Loglinking do
it 'returns logging environment if environment found' do
logging_env_array.each do |logging_env_hash|
allow(QA::Runtime::Scenario).to receive(:attributes).and_return({ gitlab_address: logging_env_hash[:address] })
- allow(QA::Support::Loglinking).to receive(:canary?).and_return(logging_env_hash[:canary])
expect(QA::Support::Loglinking.logging_environment).to eq(logging_env_hash[:expected_env])
end
@@ -151,37 +130,4 @@ RSpec.describe QA::Support::Loglinking do
end
end
end
-
- describe '.cookies' do
- let(:cookies) { [{ name: 'Foo', value: 'Bar' }, { name: 'gitlab_canary', value: 'true' }] }
-
- it 'returns browser cookies' do
- allow(Capybara.current_session).to receive_message_chain(:driver, :browser, :manage, :all_cookies).and_return(cookies)
-
- expect(QA::Support::Loglinking.cookies).to eq({ "Foo" => { name: "Foo", value: "Bar" }, "gitlab_canary" => { name: "gitlab_canary", value: "true" } })
- end
- end
-
- describe '.canary?' do
- context 'gitlab_canary cookie is present' do
- it 'and true returns true' do
- allow(QA::Support::Loglinking).to receive(:cookies).and_return({ 'gitlab_canary' => { name: 'gitlab_canary', value: 'true' } })
-
- expect(QA::Support::Loglinking.canary?).to eq(true)
- end
-
- it 'and not true returns false' do
- allow(QA::Support::Loglinking).to receive(:cookies).and_return({ 'gitlab_canary' => { name: 'gitlab_canary', value: 'false' } })
-
- expect(QA::Support::Loglinking.canary?).to eq(false)
- end
- end
- context 'gitlab_canary cookie is not present' do
- it 'returns false' do
- allow(QA::Support::Loglinking).to receive(:cookies).and_return({ 'foo' => { name: 'foo', path: '/pathname' } })
-
- expect(QA::Support::Loglinking.canary?).to eq(false)
- end
- end
- end
end
diff --git a/qa/spec/support/repeater_spec.rb b/qa/spec/support/repeater_spec.rb
index 96e780fc9bd..9810456321e 100644
--- a/qa/spec/support/repeater_spec.rb
+++ b/qa/spec/support/repeater_spec.rb
@@ -1,17 +1,23 @@
# frozen_string_literal: true
require 'active_support/core_ext/integer/time'
+require 'active_support/testing/time_helpers'
RSpec.describe QA::Support::Repeater do
+ include ActiveSupport::Testing::TimeHelpers
+
subject do
Module.new do
extend QA::Support::Repeater
end
end
- let(:time_start) { Time.now }
let(:return_value) { "test passed" }
+ after do
+ travel_back
+ end
+
describe '.repeat_until' do
context 'when raise_on_failure is not provided (default: true)' do
context 'when retry_on_exception is not provided (default: false)' do
@@ -19,12 +25,7 @@ RSpec.describe QA::Support::Repeater do
context 'when max duration is reached' do
it 'raises an exception with default message' do
expect do
- Timecop.freeze do
- subject.repeat_until(max_duration: 1) do
- Timecop.travel(2)
- false
- end
- end
+ subject.repeat_until(max_duration: 1) { travel(2.seconds) && false }
end.to raise_error(QA::Support::Repeater::WaitExceededError, "Wait failed after 1 second")
end
@@ -32,12 +33,7 @@ RSpec.describe QA::Support::Repeater do
message = 'Some custom action'
expect do
- Timecop.freeze do
- subject.repeat_until(max_duration: 1, message: message) do
- Timecop.travel(2)
- false
- end
- end
+ subject.repeat_until(max_duration: 1, message: message) { travel(2.seconds) && false }
end.to raise_error(QA::Support::Repeater::WaitExceededError, "#{message} failed after 1 second")
end
@@ -45,16 +41,14 @@ RSpec.describe QA::Support::Repeater do
loop_counter = 0
expect(
- Timecop.freeze do
- subject.repeat_until(max_duration: 1) do
- loop_counter += 1
-
- if loop_counter > 3
- Timecop.travel(1)
- return_value
- else
- false
- end
+ subject.repeat_until(max_duration: 1) do
+ loop_counter += 1
+
+ if loop_counter > 3
+ travel(1.second)
+ return_value
+ else
+ false
end
end
).to eq(return_value)
@@ -64,13 +58,7 @@ RSpec.describe QA::Support::Repeater do
context 'when max duration is not reached' do
it 'returns value from block' do
- Timecop.freeze(time_start) do
- expect(
- subject.repeat_until(max_duration: 1) do
- return_value
- end
- ).to eq(return_value)
- end
+ expect(subject.repeat_until(max_duration: 10) { return_value }).to eq(return_value)
end
end
end
@@ -78,41 +66,31 @@ RSpec.describe QA::Support::Repeater do
context 'when max_attempts is provided' do
context 'when max_attempts is reached' do
it 'raises an exception with default message' do
- expect do
- Timecop.freeze do
- subject.repeat_until(max_attempts: 1) do
- false
- end
- end
- end.to raise_error(QA::Support::Repeater::RetriesExceededError, "Retry failed after 1 attempt")
+ expect { subject.repeat_until(max_attempts: 1) { false } }.to raise_error(
+ QA::Support::Repeater::RetriesExceededError, "Retry failed after 1 attempt"
+ )
end
it 'raises an exception with custom message' do
message = 'Some custom action'
- expect do
- Timecop.freeze do
- subject.repeat_until(max_attempts: 1, message: message) do
- false
- end
- end
- end.to raise_error(QA::Support::Repeater::RetriesExceededError, "#{message} failed after 1 attempt")
+ expect { subject.repeat_until(max_attempts: 1, message: message) { false } }.to raise_error(
+ QA::Support::Repeater::RetriesExceededError, "#{message} failed after 1 attempt"
+ )
end
it 'ignores duration' do
loop_counter = 0
expect(
- Timecop.freeze do
- subject.repeat_until(max_attempts: 2) do
- loop_counter += 1
- Timecop.travel(1.year)
-
- if loop_counter > 1
- return_value
- else
- false
- end
+ subject.repeat_until(max_attempts: 2) do
+ loop_counter += 1
+ travel(1.year)
+
+ if loop_counter > 1
+ return_value
+ else
+ false
end
end
).to eq(return_value)
@@ -122,13 +100,7 @@ RSpec.describe QA::Support::Repeater do
context 'when max_attempts is not reached' do
it 'returns value from block' do
- expect(
- Timecop.freeze do
- subject.repeat_until(max_attempts: 1) do
- return_value
- end
- end
- ).to eq(return_value)
+ expect(subject.repeat_until(max_attempts: 1) { return_value }).to eq(return_value)
end
end
end
@@ -136,31 +108,17 @@ RSpec.describe QA::Support::Repeater do
context 'when both max_attempts and max_duration are provided' do
context 'when max_attempts is reached first' do
it 'raises an exception' do
- loop_counter = 0
- expect do
- Timecop.freeze do
- subject.repeat_until(max_attempts: 1, max_duration: 2) do
- loop_counter += 1
- Timecop.travel(time_start + loop_counter)
- false
- end
- end
- end.to raise_error(QA::Support::Repeater::RetriesExceededError, "Retry failed after 1 attempt")
+ expect { subject.repeat_until(max_attempts: 1, max_duration: 2) { false } }.to(
+ raise_error(QA::Support::Repeater::RetriesExceededError, "Retry failed after 1 attempt")
+ )
end
end
context 'when max_duration is reached first' do
it 'raises an exception' do
- loop_counter = 0
- expect do
- Timecop.freeze do
- subject.repeat_until(max_attempts: 2, max_duration: 1) do
- loop_counter += 1
- Timecop.travel(time_start + loop_counter)
- false
- end
- end
- end.to raise_error(QA::Support::Repeater::WaitExceededError, "Wait failed after 1 second")
+ expect { subject.repeat_until(max_attempts: 2, max_duration: 1) { travel(10.seconds) && false } }.to(
+ raise_error(QA::Support::Repeater::WaitExceededError, "Wait failed after 1 second")
+ )
end
end
end
@@ -169,30 +127,26 @@ RSpec.describe QA::Support::Repeater do
context 'when retry_on_exception is true' do
context 'when max duration is reached' do
it 'raises an exception' do
- Timecop.freeze do
- expect do
- subject.repeat_until(max_duration: 1, retry_on_exception: true) do
- Timecop.travel(2)
+ expect do
+ subject.repeat_until(max_duration: 1, retry_on_exception: true) do
+ travel(10.seconds)
- raise "this should be raised"
- end
- end.to raise_error(RuntimeError, "this should be raised")
- end
+ raise "this should be raised"
+ end
+ end.to raise_error(RuntimeError, "this should be raised")
end
it 'does not raise an exception until max_duration is reached' do
loop_counter = 0
- Timecop.freeze(time_start) do
- expect do
- subject.repeat_until(max_duration: 2, retry_on_exception: true) do
- loop_counter += 1
- Timecop.travel(time_start + loop_counter)
+ expect do
+ subject.repeat_until(max_duration: 5, retry_on_exception: true) do
+ loop_counter += 1
+ travel(10.seconds) if loop_counter == 2
- raise "this should be raised"
- end
- end.to raise_error(RuntimeError, "this should be raised")
- end
+ raise "this should be raised"
+ end
+ end.to raise_error(RuntimeError, "this should be raised")
expect(loop_counter).to eq(2)
end
end
@@ -201,53 +155,18 @@ RSpec.describe QA::Support::Repeater do
it 'returns value from block' do
loop_counter = 0
- Timecop.freeze(time_start) do
- expect(
- subject.repeat_until(max_duration: 3, retry_on_exception: true) do
- loop_counter += 1
- Timecop.travel(time_start + loop_counter)
+ expect(
+ subject.repeat_until(max_duration: 3, retry_on_exception: true) do
+ loop_counter += 1
- raise "this should not be raised" if loop_counter == 1
+ raise "this should not be raised" if loop_counter == 1
- return_value
- end
- ).to eq(return_value)
- end
+ return_value
+ end
+ ).to eq(return_value)
expect(loop_counter).to eq(2)
end
end
-
- context 'when both max_attempts and max_duration are provided' do
- context 'when max_attempts is reached first' do
- it 'raises an exception' do
- loop_counter = 0
- expect do
- Timecop.freeze do
- subject.repeat_until(max_attempts: 1, max_duration: 2, retry_on_exception: true) do
- loop_counter += 1
- Timecop.travel(time_start + loop_counter)
- false
- end
- end
- end.to raise_error(QA::Support::Repeater::RetriesExceededError, "Retry failed after 1 attempt")
- end
- end
-
- context 'when max_duration is reached first' do
- it 'raises an exception' do
- loop_counter = 0
- expect do
- Timecop.freeze do
- subject.repeat_until(max_attempts: 2, max_duration: 1, retry_on_exception: true) do
- loop_counter += 1
- Timecop.travel(time_start + loop_counter)
- false
- end
- end
- end.to raise_error(QA::Support::Repeater::WaitExceededError, "Wait failed after 1 second")
- end
- end
- end
end
end
@@ -255,11 +174,9 @@ RSpec.describe QA::Support::Repeater do
context 'when retry_on_exception is not provided (default: false)' do
context 'when max duration is reached' do
def test_wait
- Timecop.freeze do
- subject.repeat_until(max_duration: 1, raise_on_failure: false) do
- Timecop.travel(2)
- return_value
- end
+ subject.repeat_until(max_duration: 1, raise_on_failure: false) do
+ travel(10.seconds)
+ return_value
end
end
@@ -274,23 +191,15 @@ RSpec.describe QA::Support::Repeater do
context 'when max duration is not reached' do
it 'returns the value from the block' do
- Timecop.freeze do
- expect(
- subject.repeat_until(max_duration: 1, raise_on_failure: false) do
- return_value
- end
- ).to eq(return_value)
- end
+ expect(subject.repeat_until(max_duration: 10, raise_on_failure: false) { return_value }).to eq(return_value)
end
it 'raises an exception' do
- Timecop.freeze do
- expect do
- subject.repeat_until(max_duration: 1, raise_on_failure: false) do
- raise "this should be raised"
- end
- end.to raise_error(RuntimeError, "this should be raised")
- end
+ expect do
+ subject.repeat_until(max_duration: 10, raise_on_failure: false) do
+ raise "this should be raised"
+ end
+ end.to raise_error(RuntimeError, "this should be raised")
end
end
@@ -300,12 +209,10 @@ RSpec.describe QA::Support::Repeater do
loop_counter = 0
expect(
- Timecop.freeze do
- subject.repeat_until(max_attempts: max_attempts, max_duration: max_duration, raise_on_failure: false) do
- loop_counter += 1
- Timecop.travel(time_start + loop_counter)
- false
- end
+ subject.repeat_until(max_attempts: max_attempts, max_duration: max_duration, raise_on_failure: false) do
+ loop_counter += 1
+ travel(max_attempts.seconds)
+ false
end
).to eq(false)
expect(loop_counter).to eq(1)
@@ -313,7 +220,7 @@ RSpec.describe QA::Support::Repeater do
end
context 'when max_attempts is reached first' do
- it_behaves_like 'repeat until', max_attempts: 1, max_duration: 2
+ it_behaves_like 'repeat until', max_attempts: 1, max_duration: 10
end
context 'when max_duration is reached first' do
@@ -325,11 +232,9 @@ RSpec.describe QA::Support::Repeater do
context 'when retry_on_exception is true' do
context 'when max duration is reached' do
def test_wait
- Timecop.freeze do
- subject.repeat_until(max_duration: 1, raise_on_failure: false, retry_on_exception: true) do
- Timecop.travel(2)
- return_value
- end
+ subject.repeat_until(max_duration: 1, raise_on_failure: false, retry_on_exception: true) do
+ travel(10.seconds)
+ return_value
end
end
@@ -341,61 +246,6 @@ RSpec.describe QA::Support::Repeater do
expect(test_wait).to eq(return_value)
end
end
-
- context 'when max duration is not reached' do
- before do
- @loop_counter = 0
- end
-
- def test_wait_with_counter
- Timecop.freeze(time_start) do
- subject.repeat_until(max_duration: 3, raise_on_failure: false, retry_on_exception: true) do
- @loop_counter += 1
- Timecop.travel(time_start + @loop_counter)
-
- raise "this should not be raised" if @loop_counter == 1
-
- return_value
- end
- end
- end
-
- it 'does not raise an exception' do
- expect { test_wait_with_counter }.not_to raise_error
- end
-
- it 'returns the value from the block' do
- expect(test_wait_with_counter).to eq(return_value)
- expect(@loop_counter).to eq(2)
- end
- end
-
- context 'when both max_attempts and max_duration are provided' do
- shared_examples 'repeat until' do |max_attempts:, max_duration:|
- it "returns when #{max_attempts < max_duration ? 'max_attempts' : 'max_duration'} is reached" do
- loop_counter = 0
-
- expect(
- Timecop.freeze do
- subject.repeat_until(max_attempts: max_attempts, max_duration: max_duration, raise_on_failure: false, retry_on_exception: true) do
- loop_counter += 1
- Timecop.travel(time_start + loop_counter)
- false
- end
- end
- ).to eq(false)
- expect(loop_counter).to eq(1)
- end
- end
-
- context 'when max_attempts is reached first' do
- it_behaves_like 'repeat until', max_attempts: 1, max_duration: 2
- end
-
- context 'when max_duration is reached first' do
- it_behaves_like 'repeat until', max_attempts: 2, max_duration: 1
- end
- end
end
end
diff --git a/qa/spec/tools/ci/qa_changes_spec.rb b/qa/spec/tools/ci/qa_changes_spec.rb
index d93d3cd9258..778a0ad33bb 100644
--- a/qa/spec/tools/ci/qa_changes_spec.rb
+++ b/qa/spec/tools/ci/qa_changes_spec.rb
@@ -49,6 +49,14 @@ RSpec.describe QA::Tools::Ci::QaChanges do
end
end
+ context "with shared example changes" do
+ let(:mr_diff) { [{ path: "qa/qa/specs/features/shared_context/some_context.rb", diff: "" }] }
+
+ it ".qa_tests do not return specific specs" do
+ expect(qa_changes.qa_tests).to be_nil
+ end
+ end
+
context "with non qa changes" do
let(:mr_diff) { [{ path: "Gemfile" }] }
diff --git a/qa/spec/tools/ci/test_metrics_spec.rb b/qa/spec/tools/ci/test_metrics_spec.rb
new file mode 100644
index 00000000000..4c1c4092d15
--- /dev/null
+++ b/qa/spec/tools/ci/test_metrics_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+RSpec.describe QA::Tools::Ci::TestMetrics do
+ include QA::Support::Helpers::StubEnv
+
+ let(:influx_client) { instance_double("InfluxDB2::Client", create_write_api: influx_write_api) }
+ let(:influx_write_api) { instance_double("InfluxDB2::WriteApi", write: nil) }
+ let(:logger) { instance_double("Logger", info: true, warn: true) }
+
+ let(:glob) { "metrics_glob/*.json" }
+ let(:paths) { ["/metrics_glob/metrics.json"] }
+ let(:timestamp) { "2022-11-11 07:54:11 +0000" }
+ let(:metrics_json) { metrics_data.to_json }
+
+ let(:metrics_data) do
+ [
+ {
+ time: timestamp.to_time,
+ name: "name",
+ tags: {},
+ fields: {}
+ }
+ ]
+ end
+
+ before do
+ allow(InfluxDB2::Client).to receive(:new) { influx_client }
+ allow(Gitlab::QA::TestLogger).to receive(:logger) { logger }
+ allow(Dir).to receive(:glob).with(glob) { paths }
+ allow(File).to receive(:read).with(paths.first) { metrics_json }
+
+ stub_env('QA_INFLUXDB_URL', "test")
+ stub_env('QA_INFLUXDB_TOKEN', "test")
+ end
+
+ context "with metrics files present" do
+ it "exports saved metrics to influxdb" do
+ described_class.export(glob)
+
+ expect(influx_write_api).to have_received(:write).with(data: metrics_data, bucket: "e2e-test-stats-main")
+ end
+ end
+
+ context "without metrics files present" do
+ let(:paths) { [] }
+
+ it "exits without error" do
+ described_class.export(glob)
+
+ expect(influx_write_api).not_to have_received(:write)
+ expect(logger).to have_received(:warn).with("No files matched pattern '#{glob}'")
+ end
+ end
+end
diff --git a/qa/spec/tools/test_resources_data_processor_spec.rb b/qa/spec/tools/test_resources_data_processor_spec.rb
index 2ae43974a0c..73fc2f6e853 100644
--- a/qa/spec/tools/test_resources_data_processor_spec.rb
+++ b/qa/spec/tools/test_resources_data_processor_spec.rb
@@ -1,7 +1,5 @@
# frozen_string_literal: true
-
require 'active_support/testing/time_helpers'
-
RSpec.describe QA::Tools::TestResourceDataProcessor do
include QA::Support::Helpers::StubEnv
include ActiveSupport::Testing::TimeHelpers
diff --git a/qa/tasks/ci.rake b/qa/tasks/ci.rake
index 435fe8ebb77..84a26e3e555 100644
--- a/qa/tasks/ci.rake
+++ b/qa/tasks/ci.rake
@@ -1,9 +1,8 @@
# frozen_string_literal: true
-require_relative "helpers/util"
-
-# rubocop:disable Rails/RakeEnvironment
namespace :ci do
+ require_relative "helpers/util"
+
include Task::Helpers::Util
desc "Detect changes and populate test variables for selective test execution and feature flag testing"
@@ -23,18 +22,20 @@ namespace :ci do
# skip running tests when only quarantine changes detected
if qa_changes.quarantine_changes?
logger.info(" merge request contains only quarantine changes, e2e test execution will be skipped!")
- append_to_file(env_file, <<~TXT)
- QA_SKIP_ALL_TESTS=true
- TXT
+ append_to_file(env_file, "QA_SKIP_ALL_TESTS=true")
next
end
- tests = qa_changes.qa_tests
- if qa_changes.framework_changes? # run all tests when framework changes detected
+ run_all_label_present = mr_labels.include?("pipeline:run-all-e2e")
+ # on run-all label of framework changes do not infer specific tests
+ tests = run_all_label_present || qa_changes.framework_changes? ? nil : qa_changes.qa_tests
+
+ if run_all_label_present
+ logger.info(" merge request has pipeline:run-all-e2e label, full test suite will be executed")
+ append_to_file(env_file, "QA_RUN_ALL_TESTS=true\n")
+ elsif qa_changes.framework_changes? # run all tests when framework changes detected
logger.info(" merge request contains qa framework changes, full test suite will be executed")
- append_to_file(env_file, <<~TXT)
- QA_FRAMEWORK_CHANGES=true
- TXT
+ append_to_file(env_file, "QA_FRAMEWORK_CHANGES=true\n")
elsif tests
logger.info(" detected following specs to execute: '#{tests}'")
else
@@ -44,20 +45,24 @@ namespace :ci do
# always check all test suites in case a suite is defined but doesn't have any runnable specs
suites = QA::Tools::Ci::NonEmptySuites.new(tests).fetch
append_to_file(env_file, <<~TXT)
- QA_TESTS='#{tests}'
QA_SUITES='#{suites}'
+ QA_TESTS='#{tests}'
TXT
# check if mr contains feature flag changes
feature_flags = QA::Tools::Ci::FfChanges.new(diff).fetch
- append_to_file(env_file, <<~TXT)
- QA_FEATURE_FLAGS='#{feature_flags}'
- TXT
+ append_to_file(env_file, "QA_FEATURE_FLAGS='#{feature_flags}'")
end
desc "Download test results from downstream pipeline"
task :download_test_results, [:trigger_name, :test_report_job_name, :report_path] do |_, args|
QA::Tools::Ci::TestResults.get(args[:trigger_name], args[:test_report_job_name], args[:report_path])
end
+
+ desc "Export test run metrics to influxdb"
+ task :export_test_metrics, [:glob] do |_, args|
+ raise("Metrics file glob pattern is required") unless args[:glob]
+
+ QA::Tools::Ci::TestMetrics.export(args[:glob])
+ end
end
-# rubocop:enable Rails/RakeEnvironment
diff --git a/qa/tasks/knapsack.rake b/qa/tasks/knapsack.rake
index c1225964aef..c502d1cbb4a 100644
--- a/qa/tasks/knapsack.rake
+++ b/qa/tasks/knapsack.rake
@@ -18,20 +18,20 @@ namespace :knapsack do
desc "Download latest knapsack reports for parallel jobs"
task :download, [:stage_name] do |_, args|
test_stage_name = args[:stage_name]
+ knapsack_reports = ENV["QA_KNAPSACK_REPORTS"]&.split(",")
+ ci_token = ENV["QA_GITLAB_CI_TOKEN"]
- # QA_KNAPSACK_REPORTS remains for changes to be backwards compatible
- # TODO: remove and only use automated detection once changes are merged
- unless ENV["QA_KNAPSACK_REPORTS"] || test_stage_name
- QA::Runtime::Logger.warn("Missing QA_KNAPSACK_REPORTS environment variable or test stage name for autodetection")
- next
- end
+ reports = if knapsack_reports
+ knapsack_reports
+ else
+ unless ci_token
+ QA::Runtime::Logger.error("Missing QA_GITLAB_CI_TOKEN for automatically detecting parallel jobs")
+ next
+ end
- reports = if test_stage_name
QA::Support::ParallelPipelineJobs
- .fetch(stage_name: test_stage_name, access_token: ENV["QA_GITLAB_CI_TOKEN"])
+ .fetch(stage_name: test_stage_name, access_token: ci_token)
.map { |job| job.tr(":", "-") }
- else
- ENV["QA_KNAPSACK_REPORTS"].split(",")
end
reports.each do |report_name|
diff --git a/rubocop/cop/api/ensure_string_detail.rb b/rubocop/cop/api/ensure_string_detail.rb
new file mode 100644
index 00000000000..bc999525055
--- /dev/null
+++ b/rubocop/cop/api/ensure_string_detail.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require_relative '../../code_reuse_helpers'
+
+module RuboCop
+ module Cop
+ module API
+ class EnsureStringDetail < RuboCop::Cop::Base
+ include CodeReuseHelpers
+
+ # This cop checks that API detail entries use Strings
+ #
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/379037
+ #
+ # @example
+ #
+ # # bad
+ # detail ['Foo bar baz bat', 'http://example.com']
+ #
+ # # good
+ # detail 'Foo bar baz bat. http://example.com'
+ #
+ # end
+ #
+ MSG = 'Only String objects are permitted in API detail field.'
+
+ def_node_matcher :detail_in_desc, <<~PATTERN
+ (block
+ (send nil? :desc ...)
+ _args
+ `(send nil? :detail $_ ...)
+ )
+ PATTERN
+
+ RESTRICT_ON_SEND = %i[detail].freeze
+
+ def on_send(node)
+ return unless in_api?(node)
+
+ parent = node.each_ancestor(:block).first
+ detail_arg = detail_in_desc(parent)
+
+ return unless detail_arg
+ return if [:str, :dstr].include?(detail_arg.type)
+
+ add_offense(node)
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/gitlab/duplicate_spec_location.rb b/rubocop/cop/gitlab/duplicate_spec_location.rb
deleted file mode 100644
index f8c19caf351..00000000000
--- a/rubocop/cop/gitlab/duplicate_spec_location.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# frozen_string_literal: true
-
-require 'rubocop/cop/rspec/base'
-require 'rubocop/cop/rspec/mixin/top_level_group'
-
-module RuboCop
- module Cop
- module Gitlab
- # Cop that detects duplicate EE spec files
- #
- # There should not be files in both ee/spec/*/ee/my_spec.rb and ee/spec/*/my_spec.rb
- #
- # # bad
- # ee/spec/controllers/my_spec.rb # describe MyClass
- # ee/spec/controllers/ee/my_spec.rb # describe MyClass
- #
- # # good, spec for EE extension code
- # ee/spec/controllers/ee/my_spec.rb # describe MyClass
- #
- # # good, spec for EE only code
- # ee/spec/controllers/my_spec.rb # describe MyClass
- #
- class DuplicateSpecLocation < RuboCop::Cop::RSpec::Base
- include RuboCop::Cop::RSpec::TopLevelGroup
-
- MSG = 'Duplicate spec location in `%<path>s`.'
-
- def on_top_level_group(node)
- path = file_path_for_node(node.send_node).sub(%r{\A#{rails_root}/}, '')
- duplicate_path = find_duplicate_path(path)
-
- if duplicate_path && File.exist?(File.join(rails_root, duplicate_path))
- add_offense(node.send_node, message: format(MSG, path: duplicate_path))
- end
- end
-
- private
-
- def ee_spec?(path)
- File.fnmatch?('ee/spec/**/*.rb', path, File::FNM_PATHNAME)
- end
-
- def find_duplicate_path(path)
- return unless ee_spec?(path)
-
- if File.fnmatch?('ee/spec/**/ee/**', path)
- path.match('\A(ee/spec/[^/]+)/ee/(.+)') do |match|
- File.join(match[1], match[2])
- end
- else
- path.match('\A(ee/spec/[^/]+)/(.+)') do |match|
- File.join(match[1], 'ee', match[2])
- end
- end
- end
-
- def file_path_for_node(node)
- node.location.expression.source_buffer.name
- end
-
- def 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 4dba4baf1e7..fcf4992a19d 100644
--- a/rubocop/cop/gitlab/feature_available_usage.rb
+++ b/rubocop/cop/gitlab/feature_available_usage.rb
@@ -27,6 +27,7 @@ module RuboCop
environments
feature_flags
releases
+ infrastructure
].freeze
EE_FEATURES = %i[requirements].freeze
ALL_FEATURES = (FEATURES + EE_FEATURES).freeze
diff --git a/rubocop/cop/gitlab/json.rb b/rubocop/cop/gitlab/json.rb
index 56846e3c276..cf2ed0ba536 100644
--- a/rubocop/cop/gitlab/json.rb
+++ b/rubocop/cop/gitlab/json.rb
@@ -7,25 +7,44 @@ module RuboCop
extend RuboCop::Cop::AutoCorrector
MSG = <<~EOL
- Avoid calling `JSON` directly. Instead, use the `Gitlab::Json`
- wrapper. This allows us to alter the JSON parser being used.
+ Prefer `Gitlab::Json` over calling `JSON` directly. See https://docs.gitlab.com/ee/development/json.html
EOL
+ AVAILABLE_METHODS = %i[parse parse! load decode dump generate encode pretty_generate].to_set.freeze
+
def_node_matcher :json_node?, <<~PATTERN
- (send (const {nil? | (const nil? :ActiveSupport)} :JSON)...)
+ (send (const {nil? | (const nil? :ActiveSupport)} :JSON) $_ $...)
PATTERN
def on_send(node)
- return unless json_node?(node)
+ method_name, arg_source = match_node(node)
+ return unless method_name
add_offense(node) do |corrector|
- _, method_name, *arg_nodes = *node
-
- replacement = "Gitlab::Json.#{method_name}(#{arg_nodes.map(&:source).join(', ')})"
+ replacement = "#{cbased(node)}Gitlab::Json.#{method_name}(#{arg_source})"
corrector.replace(node.source_range, replacement)
end
end
+
+ private
+
+ def match_node(node)
+ method_name, arg_nodes = json_node?(node)
+
+ # Only match if the method is implemented by Gitlab::Json
+ if method_name && AVAILABLE_METHODS.include?(method_name)
+ return [method_name, arg_nodes.map(&:source).join(", ")]
+ end
+
+ nil
+ end
+
+ def cbased(node)
+ return unless %r{/ee/}.match?(node.location.expression.source_buffer.name)
+
+ "::"
+ end
end
end
end
diff --git a/rubocop/cop/gitlab/mark_used_feature_flags.rb b/rubocop/cop/gitlab/mark_used_feature_flags.rb
index 23de0644385..d1722a47c8a 100644
--- a/rubocop/cop/gitlab/mark_used_feature_flags.rb
+++ b/rubocop/cop/gitlab/mark_used_feature_flags.rb
@@ -59,7 +59,7 @@ module RuboCop
def on_casgn(node)
_, lhs_name, rhs = *node
- save_used_feature_flag(rhs.value) if lhs_name == :FEATURE_FLAG
+ save_used_feature_flag(rhs.value) if lhs_name.to_s.end_with?('FEATURE_FLAG')
end
def on_send(node)
diff --git a/rubocop/cop/gitlab/rspec/avoid_setup.rb b/rubocop/cop/gitlab/rspec/avoid_setup.rb
new file mode 100644
index 00000000000..fd2ed3b7e34
--- /dev/null
+++ b/rubocop/cop/gitlab/rspec/avoid_setup.rb
@@ -0,0 +1,82 @@
+# frozen_string_literal: true
+
+require 'rubocop-rspec'
+
+module RuboCop
+ module Cop
+ module Gitlab
+ module RSpec
+ # This cop checks for use of constructs that may lead to deterioration in readability
+ # in specs.
+ #
+ # @example
+ #
+ # # bad
+ # before do
+ # enforce_terms
+ # end
+ #
+ # it 'auto accepts terms and redirects to the group path' do
+ # visit sso_group_saml_providers_path(group, token: group.saml_discovery_token)
+ #
+ # click_link 'Sign in'
+ #
+ # expect(page).to have_content('Signed in with SAML')
+ # end
+ #
+ # # good
+ # it 'auto accepts terms and redirects to the group path' do
+ # enforce_terms
+ #
+ # visit sso_group_saml_providers_path(group, token: group.saml_discovery_token)
+ #
+ # click_link 'Sign in'
+ #
+ # expect(page).to have_content('Signed in with SAML')
+ # end
+ #
+ # # good
+ # it 'registers the user and starts to import a project' do
+ # user_signs_up
+ #
+ # expect_to_see_account_confirmation_page
+ #
+ # confirm_account
+ #
+ # user_signs_in
+ #
+ # expect_to_see_welcome_form
+ #
+ # fills_in_welcome_form
+ # click_on 'Continue'
+ #
+ # expect_to_see_group_and_project_creation_form
+ #
+ # click_on 'Import'
+ #
+ # expect_to_see_import_form
+ #
+ # fills_in_import_form
+ # click_on 'GitHub'
+ #
+ # expect_to_be_in_import_process
+ # end
+ #
+ class AvoidSetup < RuboCop::Cop::Base
+ MSG = 'Avoid the use of `%{name}` to keep this area as readable as possible. ' \
+ 'See https://gitlab.com/gitlab-org/gitlab/-/issues/373194'
+
+ NOT_ALLOWED = %i[let_it_be let_it_be_with_refind let_it_be_with_reload let let!
+ before after around it_behaves_like shared_examples shared_examples_for
+ shared_context include_context subject].freeze
+
+ RESTRICT_ON_SEND = NOT_ALLOWED
+
+ def on_send(node)
+ add_offense(node, message: format(MSG, name: node.children[1]))
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/graphql/enum_names.rb b/rubocop/cop/graphql/enum_names.rb
new file mode 100644
index 00000000000..74847cb8d17
--- /dev/null
+++ b/rubocop/cop/graphql/enum_names.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+# This cop enforces the enum naming conventions from the enum style guide:
+# https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#enums
+#
+# @example
+#
+# # bad
+# class FooBar < BaseEnum
+# value 'FOO'
+# end
+#
+# class SubparEnum < BaseEnum
+# end
+#
+# class UngoodEnum < BaseEnum
+# graphql_name 'UngoodEnum'
+# end
+#
+# # good
+#
+# class GreatEnum < BaseEnum
+# graphql_name 'Great'
+#
+# value 'BAR'
+# end
+#
+# class NiceEnum < BaseEnum
+# declarative_enum NiceDeclarativeEnum
+# end
+
+module RuboCop
+ module Cop
+ module Graphql
+ class EnumNames < RuboCop::Cop::Base
+ SEE_SG_MSG = "See https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#enums"
+ CLASS_NAME_SUFFIX_MSG = "Enum class names must end with `Enum`. #{SEE_SG_MSG}"
+ GRAPHQL_NAME_MISSING_MSG = "A `graphql_name` must be defined for a GraphQL enum. #{SEE_SG_MSG}"
+ GRAPHQL_NAME_WITH_ENUM_MSG = "The `graphql_name` must not contain the string \"Enum\". #{SEE_SG_MSG}"
+
+ def_node_matcher :enum_subclass, <<~PATTERN
+ (class $(const nil? _) (const {nil? cbase} /.*Enum$/) ...)
+ PATTERN
+
+ def_node_search :find_graphql_name, <<~PATTERN
+ (... `(send nil? :graphql_name $(...)) ...)
+ PATTERN
+
+ def_node_search :declarative_enum?, <<~PATTERN
+ (... (send nil? :declarative_enum ...) ...)
+ PATTERN
+
+ def on_class(node)
+ const_node = enum_subclass(node)
+ return unless const_node
+
+ check_class_name(const_node)
+ check_graphql_name(node)
+ end
+
+ private
+
+ def check_class_name(const_node)
+ return unless const_node&.const_name
+ return if const_node.const_name.end_with?('Enum')
+
+ add_offense(const_node, message: CLASS_NAME_SUFFIX_MSG)
+ end
+
+ def check_graphql_name(node)
+ graphql_name_node = find_graphql_name(node)&.first
+
+ if graphql_name_node
+ return unless graphql_name_node&.str_content
+ return unless graphql_name_node.str_content.downcase.include?('enum')
+
+ add_offense(graphql_name_node, message: GRAPHQL_NAME_WITH_ENUM_MSG)
+ else
+ return if declarative_enum?(node)
+
+ add_offense(node, message: GRAPHQL_NAME_MISSING_MSG)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/graphql/enum_values.rb b/rubocop/cop/graphql/enum_values.rb
new file mode 100644
index 00000000000..71c42596334
--- /dev/null
+++ b/rubocop/cop/graphql/enum_values.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+
+# This cop enforces the enum value conventions from the enum style guide:
+# https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#enums
+#
+# @example
+#
+# # bad
+# class BadEnum < BaseEnum
+# graphql_name 'Bad'
+#
+# value 'foo'
+# end
+#
+# class UngoodEnum < BaseEnum
+# graphql_name 'Ungood'
+#
+# ['bar'].each do |val|
+# value val
+# end
+# end
+#
+# # good
+# class GoodEnum < BaseEnum
+# graphql_name 'Good'
+#
+# value 'FOO'
+# end
+#
+# class GreatEnum < BaseEnum
+# graphql_name 'Great'
+#
+# ['bar'].each do |val|
+# value val.upcase
+# end
+# end
+
+module RuboCop
+ module Cop
+ module Graphql
+ class EnumValues < RuboCop::Cop::Base
+ MSG = "Enum values must either be an uppercase string literal or uppercased with the `upcase` method. " \
+ "See https://docs.gitlab.com/ee/development/api_graphql_styleguide.html#enums"
+
+ def_node_matcher :enum_value, <<~PATTERN
+ (send nil? :value $_ $...)
+ PATTERN
+
+ def_node_search :deprecated?, <<~PATTERN
+ (hash <(pair (sym :deprecated) _) ...>)
+ PATTERN
+
+ def_node_matcher :upcase_literal?, <<~PATTERN
+ (str #upcase?)
+ PATTERN
+
+ def_node_matcher :upcase_method?, <<~PATTERN
+ `(send _ :upcase)
+ PATTERN
+
+ def on_send(node)
+ value_node, params = enum_value(node)
+
+ return unless value_node
+ return if params.any? { deprecated?(_1) }
+ return if upcase_literal?(value_node) || upcase_method?(value_node)
+
+ add_offense(value_node)
+ end
+
+ private
+
+ def upcase?(str)
+ str == str.upcase
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/migration/schema_addition_methods_no_post.rb b/rubocop/cop/migration/schema_addition_methods_no_post.rb
new file mode 100644
index 00000000000..5bb5bb63f0c
--- /dev/null
+++ b/rubocop/cop/migration/schema_addition_methods_no_post.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require_relative '../../migration_helpers'
+
+module RuboCop
+ module Cop
+ module Migration
+ # Cop that checks that no background batched migration helpers are called by regular migrations.
+ class SchemaAdditionMethodsNoPost < RuboCop::Cop::Base
+ include MigrationHelpers
+
+ MSG = "This method may not be used in post migrations. Please see documentation here: https://docs.gitlab.com/ee/development/migration_style_guide.html#choose-an-appropriate-migration-type"
+
+ FORBIDDEN_METHODS = %w[
+ add_column
+ create_table
+ ].freeze
+
+ SYMBOLIZED_MATCHER = FORBIDDEN_METHODS.map { |w| ":#{w}" }.join(' | ')
+
+ def_node_matcher :on_forbidden_method, <<~PATTERN
+ (send nil? {#{SYMBOLIZED_MATCHER}} ...)
+ PATTERN
+
+ def on_send(node)
+ return unless time_enforced?(node)
+
+ on_forbidden_method(node) do
+ add_offense(node, message: MSG)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/rake/require.rb b/rubocop/cop/rake/require.rb
new file mode 100644
index 00000000000..e3e1696943d
--- /dev/null
+++ b/rubocop/cop/rake/require.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+module RuboCop
+ module Cop
+ module Rake
+ # Flag global `require`s or `require_relative`s in rake files.
+ #
+ # Load dependencies lazily in `task` definitions if possible.
+ #
+ # @example
+ # # bad
+ #
+ # require_relative 'gitlab/json'
+ # require 'json'
+ #
+ # task :parse_json do
+ # Gitlab::Json.parse(...)
+ # end
+ #
+ # # good
+ #
+ # task :parse_json do
+ # require_relative 'gitlab/json'
+ # require 'json'
+ #
+ # Gitlab::Json.parse(...)
+ # end
+ #
+ # RSpec::Core::RakeTask.new(:parse_json) do |t, args|
+ # require_relative 'gitlab/json'
+ # require 'json'
+ #
+ # Gitlab::Json.parse(...)
+ # end
+ #
+ # # Requiring files which contain the word `task` is allowed.
+ # require 'some_gem/rake_task'
+ # require 'some_gem/rake_tasks'
+ #
+ # SomeGem.define_tasks
+ #
+ # # Loading in method definition as well.
+ # def load_deps
+ # require 'json'
+ # end
+ #
+ # task :parse_json
+ # load_deps
+ # end
+ #
+ class Require < RuboCop::Cop::Base
+ MSG = 'Load dependencies inside `task` definitions if possible.'
+
+ METHODS = %i[require require_relative].freeze
+ RESTRICT_ON_SEND = METHODS
+
+ def_node_matcher :require_method, <<~PATTERN
+ (send nil? ${#{METHODS.map(&:inspect).join(' ')}} $_)
+ PATTERN
+
+ def on_send(node)
+ method, file = require_method(node)
+ return unless method
+
+ return if requires_task?(file)
+ return if inside_block_or_method?(node)
+
+ add_offense(node)
+ end
+
+ private
+
+ # Allow `require "foo/rake_task"`
+ def requires_task?(file)
+ file.source.include?('task')
+ end
+
+ def inside_block_or_method?(node)
+ node.each_ancestor(:block, :def).any?
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/rspec/duplicate_spec_location.rb b/rubocop/cop/rspec/duplicate_spec_location.rb
new file mode 100644
index 00000000000..c920104c8c0
--- /dev/null
+++ b/rubocop/cop/rspec/duplicate_spec_location.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+require 'rubocop/cop/rspec/base'
+require 'rubocop/cop/rspec/mixin/top_level_group'
+
+module RuboCop
+ module Cop
+ module RSpec
+ # Cop that detects duplicate EE spec files
+ #
+ # There should not be files in both ee/spec/*/ee/my_spec.rb and ee/spec/*/my_spec.rb
+ #
+ # # bad
+ # ee/spec/controllers/my_spec.rb # describe MyClass
+ # ee/spec/controllers/ee/my_spec.rb # describe MyClass
+ #
+ # # good, spec for EE extension code
+ # ee/spec/controllers/ee/my_spec.rb # describe MyClass
+ #
+ # # good, spec for EE only code
+ # ee/spec/controllers/my_spec.rb # describe MyClass
+ #
+ class DuplicateSpecLocation < RuboCop::Cop::RSpec::Base
+ include RuboCop::Cop::RSpec::TopLevelGroup
+
+ MSG = 'Duplicate spec location in `%<path>s`.'
+
+ def on_top_level_group(node)
+ path = file_path_for_node(node.send_node).sub(%r{\A#{rails_root}/}, '')
+ duplicate_path = find_duplicate_path(path)
+
+ return unless duplicate_path && File.exist?(File.join(rails_root, duplicate_path))
+
+ add_offense(node.send_node, message: format(MSG, path: duplicate_path))
+ end
+
+ private
+
+ def ee_spec?(path)
+ File.fnmatch?('ee/spec/**/*.rb', path, File::FNM_PATHNAME)
+ end
+
+ def find_duplicate_path(path)
+ return unless ee_spec?(path)
+
+ if File.fnmatch?('ee/spec/**/ee/**', path)
+ path.match('\A(ee/spec/[^/]+)/ee/(.+)') do |match|
+ File.join(match[1], match[2])
+ end
+ else
+ path.match('\A(ee/spec/[^/]+)/(.+)') do |match|
+ File.join(match[1], 'ee', match[2])
+ end
+ end
+ end
+
+ def file_path_for_node(node)
+ node.location.expression.source_buffer.name
+ end
+
+ def rails_root
+ File.expand_path('../../..', __dir__)
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/cop/rspec/factory_bot/strategy_in_callback.rb b/rubocop/cop/rspec/factory_bot/strategy_in_callback.rb
new file mode 100644
index 00000000000..3153d54887e
--- /dev/null
+++ b/rubocop/cop/rspec/factory_bot/strategy_in_callback.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'rubocop-rspec'
+
+module RuboCop
+ module Cop
+ module RSpec
+ module FactoryBot
+ class StrategyInCallback < RuboCop::Cop::Base
+ include RuboCop::RSpec::FactoryBot::Language
+
+ MSG = 'Prefer inline `association` over `%{type}`. ' \
+ 'See https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#factories'
+
+ FORBIDDEN_METHODS = %i[build build_list build_stubbed build_stubbed_list create create_list].freeze
+
+ def_node_matcher :forbidden_factory_usage, <<~PATTERN
+ (block
+ (send nil? { :after :before } (sym _strategy))
+ _args
+ ` # in all descandents
+ (send
+ { nil? #factory_bot? }
+ ${ #{FORBIDDEN_METHODS.map(&:inspect).join(' ')} }
+ (sym _factory_name)
+ ...
+ )
+ )
+ PATTERN
+
+ RESTRICT_ON_SEND = FORBIDDEN_METHODS
+
+ def on_send(node)
+ parent = node.each_ancestor(:block).first
+
+ strategy = forbidden_factory_usage(parent)
+ return unless strategy
+
+ add_offense(node, message: format(MSG, type: strategy))
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/rubocop/migration_helpers.rb b/rubocop/migration_helpers.rb
index 16a9aa53cd3..22f3931be73 100644
--- a/rubocop/migration_helpers.rb
+++ b/rubocop/migration_helpers.rb
@@ -49,6 +49,14 @@ module RuboCop
dirname(node).end_with?('db/post_migrate', 'db/geo/post_migrate')
end
+ # Returns true if we've defined an 'EnforcedSince' variable in rubocop.yml and the migration version
+ # is greater.
+ def time_enforced?(node)
+ return false unless enforced_since
+
+ version(node) > enforced_since
+ end
+
def version(node)
File.basename(node.location.expression.source_buffer.name).split('_').first.to_i
end
@@ -80,5 +88,9 @@ module RuboCop
def rubocop_path
File.expand_path(__dir__)
end
+
+ def enforced_since
+ @enforced_since ||= config.for_cop(name)['EnforcedSince']
+ end
end
end
diff --git a/scripts/api/create_issue.rb b/scripts/api/create_issue.rb
new file mode 100644
index 00000000000..2117c285771
--- /dev/null
+++ b/scripts/api/create_issue.rb
@@ -0,0 +1,29 @@
+# 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
+
+ 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/pipeline_failed_jobs.rb b/scripts/api/pipeline_failed_jobs.rb
index c25567af698..df9a7e76dcd 100644
--- a/scripts/api/pipeline_failed_jobs.rb
+++ b/scripts/api/pipeline_failed_jobs.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require 'gitlab'
-require 'optparse'
+
require_relative 'default_options'
class PipelineFailedJobs
diff --git a/scripts/build_qa_image b/scripts/build_qa_image
index f4ecb8ed6b6..477bec29ba7 100755
--- a/scripts/build_qa_image
+++ b/scripts/build_qa_image
@@ -1,32 +1,43 @@
-#!/bin/sh
+#!/bin/bash
QA_IMAGE_NAME="gitlab-ee-qa"
-if [ "${CI_PROJECT_NAME}" == "gitlabhq" ] || [ "${CI_PROJECT_NAME}" == "gitlab-foss" ]; then
+if [[ "${CI_PROJECT_NAME}" == "gitlabhq" || "${CI_PROJECT_NAME}" == "gitlab-foss" ]]; then
QA_IMAGE_NAME="gitlab-ce-qa"
fi
# Tag with commit SHA by default
QA_IMAGE="${CI_REGISTRY}/${CI_PROJECT_PATH}/${QA_IMAGE_NAME}:${CI_COMMIT_SHA}"
+
# For branches, tag with slugified branch name. For tags, use the tag directly
-QA_IMAGE_BRANCH="${CI_REGISTRY}/${CI_PROJECT_PATH}/${QA_IMAGE_NAME}:${CI_COMMIT_TAG:-$CI_COMMIT_REF_SLUG}"
+# with v prefix removed
+IMAGE_TAG=${CI_COMMIT_TAG#v}
+IMAGE_TAG=${IMAGE_TAG:-$CI_COMMIT_REF_SLUG}
+
+QA_IMAGE_BRANCH="${CI_REGISTRY}/${CI_PROJECT_PATH}/${QA_IMAGE_NAME}:${IMAGE_TAG}"
+QA_IMAGE_MASTER="${CI_REGISTRY}/${CI_PROJECT_PATH}/${QA_IMAGE_NAME}:master"
-DESTINATIONS="--destination=${QA_IMAGE} --destination=${QA_IMAGE_BRANCH}"
+DESTINATIONS="--tag ${QA_IMAGE} --tag ${QA_IMAGE_BRANCH}"
# Auto-deploy tag format uses first 12 letters of commit SHA. Tag with that
# reference also for EE images.
if [ "${QA_IMAGE_NAME}" == "gitlab-ee-qa" ]; then
QA_IMAGE_FOR_AUTO_DEPLOY="${CI_REGISTRY}/${CI_PROJECT_PATH}/${QA_IMAGE_NAME}:${CI_COMMIT_SHA:0:11}"
- DESTINATIONS="${DESTINATIONS} --destination=$QA_IMAGE_FOR_AUTO_DEPLOY"
+ DESTINATIONS="${DESTINATIONS} --tag $QA_IMAGE_FOR_AUTO_DEPLOY"
fi
echo "Building QA image for destinations: ${DESTINATIONS}"
-/kaniko/executor \
- --context="${CI_PROJECT_DIR}" \
- --dockerfile="${CI_PROJECT_DIR}/qa/Dockerfile" \
+docker buildx build \
+ --cache-to=type=inline \
+ --cache-from="$QA_IMAGE_BRANCH" \
+ --cache-from="$QA_IMAGE_MASTER" \
+ --platform=${ARCH:-amd64} \
--build-arg=CHROME_VERSION="${CHROME_VERSION}" \
--build-arg=DOCKER_VERSION="${DOCKER_VERSION}" \
+ --build-arg=RUBY_VERSION="${RUBY_VERSION}" \
--build-arg=QA_BUILD_TARGET="${QA_BUILD_TARGET:-qa}" \
- --cache=true \
- ${DESTINATIONS}
+ --file="${CI_PROJECT_DIR}/qa/Dockerfile" \
+ --push \
+ ${DESTINATIONS} \
+ ${CI_PROJECT_DIR}
diff --git a/scripts/create-pipeline-failure-incident.rb b/scripts/create-pipeline-failure-incident.rb
new file mode 100755
index 00000000000..c38f80699e6
--- /dev/null
+++ b/scripts/create-pipeline-failure-incident.rb
@@ -0,0 +1,174 @@
+#!/usr/bin/env ruby
+
+# frozen_string_literal: true
+
+require 'optparse'
+require 'json'
+
+require_relative 'api/pipeline_failed_jobs'
+require_relative 'api/create_issue'
+
+class CreatePipelineFailureIncident
+ DEFAULT_OPTIONS = {
+ project: nil,
+ incident_json_file: 'incident.json'
+ }.freeze
+ DEFAULT_LABELS = ['Engineering Productivity', 'master-broken:undetermined'].freeze
+
+ def initialize(options)
+ @project = options.delete(:project)
+ @api_token = options.delete(:api_token)
+ end
+
+ def execute
+ payload = {
+ issue_type: 'incident',
+ title: title,
+ description: description,
+ labels: incident_labels
+ }
+
+ CreateIssue.new(project: project, api_token: api_token).execute(payload)
+ end
+
+ private
+
+ attr_reader :project, :api_token
+
+ def failed_jobs
+ @failed_jobs ||= PipelineFailedJobs.new(API::DEFAULT_OPTIONS.dup.merge(exclude_allowed_to_fail_jobs: true)).execute
+ end
+
+ def now
+ @now ||= Time.now.utc
+ end
+
+ def title
+ "#{now.strftime('%A %F %R UTC')} - `#{ENV['CI_PROJECT_PATH']}` broken `#{ENV['CI_COMMIT_REF_NAME']}` " \
+ "with #{failed_jobs.size} failed jobs"
+ end
+
+ def description
+ <<~MARKDOWN
+ ## #{project_link} pipeline #{pipeline_link} failed
+
+ **Branch: #{branch_link}**
+
+ **Commit: #{commit_link}**
+
+ **Triggered by** #{triggered_by_link} • **Source:** #{source} • **Duration:** #{pipeline_duration} minutes
+
+ **Failed jobs (#{failed_jobs.size}):**
+
+ #{failed_jobs_list}
+
+ ### General guidelines
+
+ Follow the [Broken `master` handbook guide](https://about.gitlab.com/handbook/engineering/workflow/#broken-master).
+
+ ### Investigation
+
+ **Be sure to fill the `Timeline` for this incident.**
+
+ 1. If the failure is new, and looks like a potential flaky failure, you can retry the failing job.
+ Make sure to mention the retry in the `Timeline` and leave a link to the retried job.
+ 1. If the failure looks like a broken `master`, communicate the broken `master` in Slack using the "Broadcast Master Broken" workflow:
+ - Click the Shortcut lightning bolt icon in the `#master-broken` channel and select "Broadcast Master Broken".
+ - Click "Continue the broadcast" after the automated message in `#master-broken`.
+
+ ### Pre-resolution
+
+ If you believe that there's an easy resolution by either:
+
+ - Reverting a particular merge request.
+ - Making a quick fix (for example, one line or a few similar simple changes in a few lines).
+ You can create a merge request, assign to any available maintainer, and ping people that were involved/related to the introduction of the failure.
+ Additionally, a message can be posted in `#backend_maintainers` or `#frontend_maintainers` to get a maintainer take a look at the fix ASAP.
+
+ In both cases, make sure to add the ~"pipeline:expedite-master-fixing" label, and `master:broken` or `master:foss-broken` label, to speed up the `master`-fixing pipelines.
+
+ ### Resolution
+
+ Follow [the Resolution steps from the handbook](https://about.gitlab.com/handbook/engineering/workflow/#responsibilities-of-the-resolution-dri).
+ MARKDOWN
+ end
+
+ def incident_labels
+ master_broken_label =
+ if ENV['CI_PROJECT_NAME'] == 'gitlab-foss'
+ 'master:foss-broken'
+ else
+ 'master:broken'
+ end
+
+ DEFAULT_LABELS.dup << master_broken_label
+ end
+
+ def pipeline_link
+ "[##{ENV['CI_PIPELINE_ID']}](#{ENV['CI_PIPELINE_URL']})"
+ end
+
+ def branch_link
+ "[`#{ENV['CI_COMMIT_REF_NAME']}`](#{ENV['CI_PROJECT_URL']}/-/commits/#{ENV['CI_COMMIT_REF_NAME']})"
+ end
+
+ def pipeline_duration
+ ((Time.now - Time.parse(ENV['CI_PIPELINE_CREATED_AT'])) / 60.to_f).round(2)
+ end
+
+ def commit_link
+ "[#{ENV['CI_COMMIT_TITLE']}](#{ENV['CI_PROJECT_URL']}/-/commit/#{ENV['CI_COMMIT_SHA']})"
+ end
+
+ def source
+ "`#{ENV['CI_PIPELINE_SOURCE']}`"
+ end
+
+ def project_link
+ "[#{ENV['CI_PROJECT_PATH']}](#{ENV['CI_PROJECT_URL']})"
+ end
+
+ def triggered_by_link
+ "[#{ENV['GITLAB_USER_NAME']}](#{ENV['CI_SERVER_URL']}/#{ENV['GITLAB_USER_LOGIN']})"
+ end
+
+ def failed_jobs_list_for_title
+ failed_jobs.map(&:name).join(', ')
+ end
+
+ def failed_jobs_list
+ failed_jobs.map { |job| "- [#{job.name}](#{job.web_url})" }.join("\n")
+ end
+end
+
+if $PROGRAM_NAME == __FILE__
+ options = CreatePipelineFailureIncident::DEFAULT_OPTIONS.dup
+
+ OptionParser.new do |opts|
+ opts.on("-p", "--project PROJECT", String, "Project where to create the incident (defaults to "\
+ "`#{CreatePipelineFailureIncident::DEFAULT_OPTIONS[:project]}`)") do |value|
+ options[:project] = value
+ end
+
+ opts.on("-f", "--incident-json-file file_path", String, "Path to a file where to save the incident JSON data "\
+ "(defaults to `#{CreatePipelineFailureIncident::DEFAULT_OPTIONS[:incident_json_file]}`)") do |value|
+ options[:incident_json_file] = value
+ end
+
+ opts.on("-t", "--api-token API_TOKEN", String, "A valid Project token with the `Reporter` role and `api` scope "\
+ "to create the incident") do |value|
+ options[:api_token] = value
+ end
+
+ opts.on("-h", "--help", "Prints this help") do
+ puts opts
+ exit
+ end
+ end.parse!
+
+ incident_json_file = options.delete(:incident_json_file)
+
+ CreatePipelineFailureIncident.new(options).execute.tap do |incident|
+ File.write(incident_json_file, JSON.pretty_generate(incident.to_h)) if incident_json_file
+ end
+end
diff --git a/scripts/generate-e2e-pipeline b/scripts/generate-e2e-pipeline
index 0d46a117719..aef2447e800 100755
--- a/scripts/generate-e2e-pipeline
+++ b/scripts/generate-e2e-pipeline
@@ -25,9 +25,12 @@ variables:
GITLAB_QA_CACHE_KEY: "$qa_cache_key"
GITLAB_VERSION: "$(cat VERSION)"
COLORIZED_LOGS: "true"
- QA_TESTS: "$QA_TESTS"
- QA_FEATURE_FLAGS: "${QA_FEATURE_FLAGS}"
+ QA_EXPORT_TEST_METRICS: "${QA_EXPORT_TEST_METRICS:-true}"
+ QA_SAVE_TEST_METRICS: "${QA_SAVE_TEST_METRICS:-false}"
+ QA_RUN_ALL_TESTS: "${QA_RUN_ALL_TESTS:-false}"
QA_FRAMEWORK_CHANGES: "${QA_FRAMEWORK_CHANGES:-false}"
+ QA_FEATURE_FLAGS: "${QA_FEATURE_FLAGS}"
+ QA_TESTS: "$QA_TESTS"
QA_SUITES: "$QA_SUITES"
YML
)
diff --git a/scripts/generate-failed-pipeline-slack-message.rb b/scripts/generate-failed-pipeline-slack-message.rb
index 699e32872e6..b695cdfdbee 100755
--- a/scripts/generate-failed-pipeline-slack-message.rb
+++ b/scripts/generate-failed-pipeline-slack-message.rb
@@ -2,21 +2,23 @@
# frozen_string_literal: true
-require_relative 'api/pipeline_failed_jobs'
+require 'optparse'
+require 'json'
-finder_options = API::DEFAULT_OPTIONS.dup.merge(exclude_allowed_to_fail_jobs: true)
-failed_jobs = PipelineFailedJobs.new(finder_options).execute
+require_relative 'api/pipeline_failed_jobs'
-class SlackReporter
- DEFAULT_FAILED_PIPELINE_REPORT_FILE = 'failed_pipeline_report.json'
+class GenerateFailedPipelineSlackMessage
+ DEFAULT_OPTIONS = {
+ failed_pipeline_slack_message_file: 'failed_pipeline_slack_message.json',
+ incident_json_file: 'incident.json'
+ }.freeze
- def initialize(failed_jobs)
- @failed_jobs = failed_jobs
- @failed_pipeline_report_file = ENV.fetch('FAILED_PIPELINE_REPORT_FILE', DEFAULT_FAILED_PIPELINE_REPORT_FILE)
+ def initialize(options)
+ @incident_json_file = options.delete(:incident_json_file)
end
- def report
- payload = {
+ def execute
+ {
channel: ENV['SLACK_CHANNEL'],
username: "Failed pipeline reporter",
icon_emoji: ":boom:",
@@ -27,33 +29,36 @@ class SlackReporter
text: {
type: "mrkdwn",
text: "*#{title}*"
+ },
+ accessory: {
+ type: "button",
+ text: {
+ type: "plain_text",
+ text: incident_button_text
+ },
+ url: incident_button_link
}
},
{
type: "section",
- fields: [
- {
- type: "mrkdwn",
- text: "*Commit*\n#{commit_link}"
- },
- {
- type: "mrkdwn",
- text: "*Triggered by*\n#{triggered_by_link}"
- }
- ]
+ text: {
+ type: "mrkdwn",
+ text: "*Branch*: #{branch_link}"
+ }
},
{
type: "section",
- fields: [
- {
- type: "mrkdwn",
- text: "*Source*\n#{source} from #{project_link}"
- },
- {
- type: "mrkdwn",
- text: "*Duration*\n#{pipeline_duration} minutes"
- }
- ]
+ text: {
+ type: "mrkdwn",
+ text: "*Commit*: #{commit_link}"
+ }
+ },
+ {
+ type: "section",
+ text: {
+ type: "mrkdwn",
+ text: "*Triggered by* #{triggered_by_link} • *Source:* #{source} • *Duration:* #{pipeline_duration} minutes"
+ }
},
{
type: "section",
@@ -64,16 +69,47 @@ class SlackReporter
}
]
}
-
- File.write(failed_pipeline_report_file, JSON.pretty_generate(payload))
end
private
- attr_reader :failed_jobs, :failed_pipeline_report_file
+ attr_reader :incident_json_file
+
+ def failed_jobs
+ @failed_jobs ||= PipelineFailedJobs.new(API::DEFAULT_OPTIONS.dup.merge(exclude_allowed_to_fail_jobs: true)).execute
+ end
def title
- "Pipeline #{pipeline_link} for #{branch_link} failed"
+ "#{project_link} pipeline #{pipeline_link} failed"
+ end
+
+ def incident_exist?
+ return @incident_exist if defined?(@incident_exist)
+
+ @incident_exist = File.exist?(incident_json_file)
+ end
+
+ def incident
+ return unless incident_exist?
+
+ @incident ||= JSON.parse(File.read(incident_json_file))
+ end
+
+ def incident_button_text
+ if incident_exist?
+ "View incident ##{incident['iid']}"
+ else
+ 'Create incident'
+ end
+ end
+
+ def incident_button_link
+ if incident_exist?
+ incident['web_url']
+ else
+ "#{ENV['CI_SERVER_URL']}/#{ENV['BROKEN_MASTER_INCIDENTS_PROJECT']}/-/issues/new?" \
+ "issuable_template=incident&issue%5Bissue_type%5D=incident"
+ end
end
def pipeline_link
@@ -93,11 +129,15 @@ class SlackReporter
end
def source
- "`#{ENV['CI_PIPELINE_SOURCE']}`"
+ "`#{ENV['CI_PIPELINE_SOURCE']}#{schedule_type}`"
+ end
+
+ def schedule_type
+ ENV['CI_PIPELINE_SOURCE'] == 'schedule' ? ": #{ENV['SCHEDULE_TYPE']}" : ''
end
def project_link
- "<#{ENV['CI_PROJECT_URL']}|#{ENV['CI_PROJECT_NAME']}>"
+ "<#{ENV['CI_PROJECT_URL']}|#{ENV['CI_PROJECT_PATH']}>"
end
def triggered_by_link
@@ -109,4 +149,33 @@ class SlackReporter
end
end
-SlackReporter.new(failed_jobs).report
+if $PROGRAM_NAME == __FILE__
+ options = GenerateFailedPipelineSlackMessage::DEFAULT_OPTIONS.dup
+
+ OptionParser.new do |opts|
+ opts.on("-i", "--incident-json-file file_path", String, "Path to a file where the incident JSON data "\
+ "can be found (defaults to "\
+ "`#{GenerateFailedPipelineSlackMessage::DEFAULT_OPTIONS[:incident_json_file]}`)") do |value|
+ options[:incident_json_file] = value
+ end
+
+ opts.on("-f", "--failed-pipeline-slack-message-file file_path", String, "Path to a file where to save the Slack "\
+ "message (defaults to "\
+ "`#{GenerateFailedPipelineSlackMessage::DEFAULT_OPTIONS[:failed_pipeline_slack_message_file]}`)") do |value|
+ options[:failed_pipeline_slack_message_file] = value
+ end
+
+ opts.on("-h", "--help", "Prints this help") do
+ puts opts
+ exit
+ end
+ end.parse!
+
+ failed_pipeline_slack_message_file = options.delete(:failed_pipeline_slack_message_file)
+
+ GenerateFailedPipelineSlackMessage.new(options).execute.tap do |message_payload|
+ if failed_pipeline_slack_message_file
+ File.write(failed_pipeline_slack_message_file, JSON.pretty_generate(message_payload))
+ end
+ end
+end
diff --git a/scripts/glfm/run-snapshot-tests.sh b/scripts/glfm/run-snapshot-tests.sh
index 6a66d8fbd9a..0a3891e243a 100755
--- a/scripts/glfm/run-snapshot-tests.sh
+++ b/scripts/glfm/run-snapshot-tests.sh
@@ -24,6 +24,9 @@ printf "\nStarting GLFM snapshot example tests. See https://docs.gitlab.com/ee/d
printf "Set 'FOCUSED_MARKDOWN_EXAMPLES=example_name_1[,...]' for focused examples, with example name(s) from https://docs.gitlab.com/ee/development/gitlab_flavored_markdown/specification_guide/#glfm_specificationexample_snapshotsexamples_indexyml.\n"
printf "${Color_Off}"
+# NOTE: Unlike the backend markdown_snapshot_spec.rb which has a CE and EE version, there is only
+# one version of this spec. This is because the frontend markdown rendering does not require EE-only
+# backend features.
printf "\n${BBlue}Running frontend 'yarn jest spec/frontend/content_editor/markdown_snapshot_spec.js'...${Color_Off}\n\n"
yarn jest spec/frontend/content_editor/markdown_snapshot_spec.js
printf "\n${BBlue}'yarn jest spec/frontend/content_editor/markdown_snapshot_spec.js' passed!${Color_Off}\n\n"
diff --git a/scripts/lib/glfm/constants.rb b/scripts/lib/glfm/constants.rb
index d020d2fec5c..c432e5495dd 100644
--- a/scripts/lib/glfm/constants.rb
+++ b/scripts/lib/glfm/constants.rb
@@ -15,24 +15,25 @@ module Glfm
# GitLab Flavored Markdown specification files
specification_input_glfm_path = specification_path.join('input/gitlab_flavored_markdown')
- GLFM_INTRO_MD_PATH = specification_input_glfm_path.join('glfm_intro.md')
- GLFM_OFFICIAL_SPECIFICATION_EXAMPLES_MD_PATH =
- specification_input_glfm_path.join('glfm_official_specification_examples.md')
- GLFM_INTERNAL_EXTENSION_EXAMPLES_MD_PATH = specification_input_glfm_path.join('glfm_internal_extension_examples.md')
+ GLFM_OFFICIAL_SPECIFICATION_MD_PATH =
+ specification_input_glfm_path.join('glfm_official_specification.md')
+ GLFM_INTERNAL_EXTENSIONS_MD_PATH = specification_input_glfm_path.join('glfm_internal_extensions.md')
GLFM_EXAMPLE_STATUS_YML_PATH = specification_input_glfm_path.join('glfm_example_status.yml')
GLFM_EXAMPLE_METADATA_YML_PATH =
specification_input_glfm_path.join('glfm_example_metadata.yml')
GLFM_EXAMPLE_NORMALIZATIONS_YML_PATH = specification_input_glfm_path.join('glfm_example_normalizations.yml')
- GLFM_SPEC_OUTPUT_PATH = specification_path.join('output')
- GLFM_SPEC_TXT_PATH = GLFM_SPEC_OUTPUT_PATH.join('spec.txt')
- GLFM_SPEC_HTML_PATH = GLFM_SPEC_OUTPUT_PATH.join('spec.html')
+ GLFM_OUTPUT_SPEC_PATH = specification_path.join('output_spec')
+ GLFM_SPEC_TXT_PATH = GLFM_OUTPUT_SPEC_PATH.join('spec.txt')
+ GLFM_SPEC_HTML_PATH = GLFM_OUTPUT_SPEC_PATH.join('spec.html')
# Example Snapshot (ES) files
- EXAMPLE_SNAPSHOTS_PATH = File.expand_path("../../../glfm_specification/example_snapshots", __dir__)
- ES_EXAMPLES_INDEX_YML_PATH = File.join(EXAMPLE_SNAPSHOTS_PATH, 'examples_index.yml')
- ES_MARKDOWN_YML_PATH = File.join(EXAMPLE_SNAPSHOTS_PATH, 'markdown.yml')
- ES_HTML_YML_PATH = File.join(EXAMPLE_SNAPSHOTS_PATH, 'html.yml')
- ES_PROSEMIRROR_JSON_YML_PATH = File.join(EXAMPLE_SNAPSHOTS_PATH, 'prosemirror_json.yml')
+ ES_OUTPUT_EXAMPLE_SNAPSHOTS_PATH = specification_path.join('output_example_snapshots')
+ ES_SNAPSHOT_SPEC_MD_PATH = ES_OUTPUT_EXAMPLE_SNAPSHOTS_PATH.join('snapshot_spec.md')
+ ES_SNAPSHOT_SPEC_HTML_PATH = ES_OUTPUT_EXAMPLE_SNAPSHOTS_PATH.join('snapshot_spec.html')
+ ES_EXAMPLES_INDEX_YML_PATH = ES_OUTPUT_EXAMPLE_SNAPSHOTS_PATH.join('examples_index.yml')
+ ES_MARKDOWN_YML_PATH = ES_OUTPUT_EXAMPLE_SNAPSHOTS_PATH.join('markdown.yml')
+ ES_HTML_YML_PATH = ES_OUTPUT_EXAMPLE_SNAPSHOTS_PATH.join('html.yml')
+ ES_PROSEMIRROR_JSON_YML_PATH = ES_OUTPUT_EXAMPLE_SNAPSHOTS_PATH.join('prosemirror_json.yml')
# Other constants used for processing files
GLFM_SPEC_TXT_HEADER = <<~MARKDOWN
@@ -41,8 +42,13 @@ module Glfm
version: alpha
...
MARKDOWN
- INTRODUCTION_HEADER_LINE_TEXT = /\A# Introduction\Z/.freeze
- END_TESTS_COMMENT_LINE_TEXT = /\A<!-- END TESTS -->\Z/.freeze
+ EXAMPLE_BACKTICKS_LENGTH = 32
+ EXAMPLE_BACKTICKS_STRING = '`' * EXAMPLE_BACKTICKS_LENGTH
+ EXAMPLE_BEGIN_STRING = "#{EXAMPLE_BACKTICKS_STRING} example"
+ EXAMPLE_END_STRING = EXAMPLE_BACKTICKS_STRING
+ INTRODUCTION_HEADER_LINE_TEXT = '# Introduction'
+ BEGIN_TESTS_COMMENT_LINE_TEXT = '<!-- BEGIN TESTS -->'
+ END_TESTS_COMMENT_LINE_TEXT = '<!-- END TESTS -->'
MARKDOWN_TEMPFILE_BASENAME = %w[MARKDOWN_TEMPFILE_ .yml].freeze
METADATA_TEMPFILE_BASENAME = %w[METADATA_TEMPFILE_ .yml].freeze
STATIC_HTML_TEMPFILE_BASENAME = %w[STATIC_HTML_TEMPFILE_ .yml].freeze
diff --git a/scripts/lib/glfm/parse_examples.rb b/scripts/lib/glfm/parse_examples.rb
index a15a6ecc47b..aedca274889 100644
--- a/scripts/lib/glfm/parse_examples.rb
+++ b/scripts/lib/glfm/parse_examples.rb
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require_relative 'constants'
+
# This module contains a Ruby port of Python logic from the `get_tests` method of the
# `spec_test.py` script (see copy of original code in a comment at the bottom of this file):
# https://github.com/github/cmark-gfm/blob/5dfedc7/test/spec_tests.py#L82
@@ -20,11 +22,11 @@
# in `scripts/lib/glfm/update_example_snapshots.rb`
module Glfm
module ParseExamples
+ include Constants
+
REGULAR_TEXT = 0
MARKDOWN_EXAMPLE = 1
HTML_OUTPUT = 2
- EXAMPLE_BACKTICKS_LENGTH = 32
- EXAMPLE_BACKTICKS_STRING = '`' * EXAMPLE_BACKTICKS_LENGTH
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/AbcSize
def parse_examples(spec_txt_lines)
@@ -47,11 +49,11 @@ module Glfm
spec_txt_lines.each do |line|
line_number += 1
stripped_line = line.strip
- if stripped_line.start_with?("#{EXAMPLE_BACKTICKS_STRING} example")
+ if stripped_line.start_with?(EXAMPLE_BEGIN_STRING)
# If beginning line of an example block...
state = MARKDOWN_EXAMPLE
extensions = stripped_line[(EXAMPLE_BACKTICKS_LENGTH + " example".length)..].split
- elsif stripped_line == EXAMPLE_BACKTICKS_STRING
+ elsif stripped_line == EXAMPLE_END_STRING
# Else if end line of an example block...
state = REGULAR_TEXT
example_number += 1
diff --git a/scripts/lib/glfm/update_example_snapshots.rb b/scripts/lib/glfm/update_example_snapshots.rb
index 9075260e748..8f817d0173e 100644
--- a/scripts/lib/glfm/update_example_snapshots.rb
+++ b/scripts/lib/glfm/update_example_snapshots.rb
@@ -30,12 +30,12 @@ module Glfm
def process(skip_static_and_wysiwyg: false)
output('Updating example snapshots...')
- output("Reading #{GLFM_SPEC_TXT_PATH}...")
- glfm_spec_txt_lines = File.open(GLFM_SPEC_TXT_PATH).readlines
+ output("Reading #{ES_SNAPSHOT_SPEC_MD_PATH}...")
+ es_snapshot_spec_md_lines = File.open(ES_SNAPSHOT_SPEC_MD_PATH).readlines
- # Parse all the examples from `spec.txt`, using a Ruby port of the Python `get_tests`
+ # Parse all the examples from `snapshot_spec.md`, using a Ruby port of the Python `get_tests`
# function the from original CommonMark/GFM `spec_test.py` script.
- all_examples = parse_examples(glfm_spec_txt_lines)
+ all_examples = parse_examples(es_snapshot_spec_md_lines)
add_example_names(all_examples)
@@ -55,7 +55,7 @@ module Glfm
# in the H1 header count. So, even though due to the concatenation it appears before the
# GitLab examples sections, it doesn't result in their header counts being off by +1.
# 5. If an example contains the 'disabled' string extension, it is skipped (and will thus
- # result in a skip in the `spec_txt_example_position`). This behavior is taken from the
+ # result in a skip in the `spec_example_position`). This behavior is taken from the
# GFM `spec_test.py` script (but it's NOT in the original CommonMark `spec_test.py`).
# 6. If a section contains ONLY disabled examples, the section numbering will still be
# incremented to match the rendered HTML specification section numbering.
@@ -202,7 +202,7 @@ module Glfm
) do |example, hash|
name = example.fetch(:name).to_sym
hash[name] = {
- 'spec_txt_example_position' => example.fetch(:example),
+ 'spec_example_position' => example.fetch(:example),
'source_specification' => source_specification_for_extensions(example.fetch(:extensions))
}
end
diff --git a/scripts/lib/glfm/update_specification.rb b/scripts/lib/glfm/update_specification.rb
index c7264547e44..b87005bdb90 100644
--- a/scripts/lib/glfm/update_specification.rb
+++ b/scripts/lib/glfm/update_specification.rb
@@ -23,17 +23,42 @@ module Glfm
def process(skip_spec_html_generation: false)
output('Updating specification...')
+ # read and optionally update `input/github_flavored_markdown/ghfm_spec_v_x.yy.md`
ghfm_spec_lines = load_ghfm_spec
- glfm_spec_txt_string = build_glfm_spec_txt(ghfm_spec_lines)
+
+ # create `output_spec/spec.txt`
+ glfm_spec_txt_header_lines = GLFM_SPEC_TXT_HEADER.split("\n").map { |line| "#{line}\n" }
+ official_spec_lines = readlines_from_path!(GLFM_OFFICIAL_SPECIFICATION_MD_PATH)
+
+ glfm_spec_txt_string = (glfm_spec_txt_header_lines + official_spec_lines).join('')
write_glfm_spec_txt(glfm_spec_txt_string)
+ # create `output_example_snapshots/snapshot_spec.md`
+ ghfm_spec_example_lines = extract_ghfm_spec_example_lines(ghfm_spec_lines)
+ official_spec_example_lines =
+ extract_glfm_spec_example_lines(official_spec_lines, GLFM_OFFICIAL_SPECIFICATION_MD_PATH)
+ internal_extension_lines = readlines_from_path!(GLFM_INTERNAL_EXTENSIONS_MD_PATH)
+ internal_extension_example_lines =
+ extract_glfm_spec_example_lines(internal_extension_lines, GLFM_INTERNAL_EXTENSIONS_MD_PATH)
+ snapshot_spec_md_string = (
+ glfm_spec_txt_header_lines +
+ ghfm_spec_example_lines +
+ official_spec_example_lines +
+ ["\n"] +
+ internal_extension_example_lines
+ ).join('')
+ write_snapshot_spec_md(snapshot_spec_md_string)
+
if skip_spec_html_generation
- output("Skipping GLFM spec.html generation...")
+ output("Skipping GLFM spec.html and snapshot_spec.html generation...")
return
end
- glfm_spec_html_string = generate_glfm_spec_html(glfm_spec_txt_string)
- write_glfm_spec_html(glfm_spec_html_string)
+ # create `output_spec/spec.html` and `output_snapshot_examples/snapshot_spec.html`
+ spec_html_string, snapshot_spec_html_string =
+ generate_spec_html_files(glfm_spec_txt_string, snapshot_spec_md_string)
+ write_spec_html(spec_html_string)
+ write_snapshot_spec_html(snapshot_spec_html_string)
end
private
@@ -68,9 +93,7 @@ module Glfm
ghfm_spec_txt_uri_parsed = URI.parse(GHFM_SPEC_TXT_URI)
ghfm_spec_txt_uri_io = ghfm_spec_txt_uri_parsed.open
- # Read IO stream into an array of lines for easy processing later
- ghfm_spec_lines = ghfm_spec_txt_uri_io.readlines
- raise "Unable to read lines from #{GHFM_SPEC_TXT_URI}" if ghfm_spec_lines.empty?
+ ghfm_spec_lines = readlines_from_io!(ghfm_spec_txt_uri_io, GHFM_SPEC_TXT_URI)
# Make sure the GHFM spec version has not changed
validate_expected_spec_version!(ghfm_spec_lines[2])
@@ -95,59 +118,42 @@ module Glfm
"Expected 'version: #{GHFM_SPEC_VERSION}', got '#{version_line}'"
end
- def build_glfm_spec_txt(ghfm_spec_txt_lines)
- glfm_spec_txt_lines = ghfm_spec_txt_lines.dup
- replace_header(glfm_spec_txt_lines)
- replace_intro_section(glfm_spec_txt_lines)
- insert_examples(glfm_spec_txt_lines)
- glfm_spec_txt_lines.join('')
- end
-
- def replace_header(spec_txt_lines)
- spec_txt_lines[0, spec_txt_lines.index("...\n") + 1] = GLFM_SPEC_TXT_HEADER
- end
-
- def replace_intro_section(spec_txt_lines)
- glfm_intro_md_lines = File.open(GLFM_INTRO_MD_PATH).readlines
- raise "Unable to read lines from #{GLFM_INTRO_MD_PATH}" if glfm_intro_md_lines.empty?
-
- ghfm_intro_header_begin_index = spec_txt_lines.index do |line|
- line =~ INTRODUCTION_HEADER_LINE_TEXT
+ def extract_ghfm_spec_example_lines(spec_lines)
+ # In the GHFM spec.txt format, all we have to identify the headers containing examples
+ # is the presence of a single initial H1 named "Introduction" before the first
+ # header containing examples, and the <!-- END TESTS --> comment after the last header
+ # containing examples.
+ path = GHFM_SPEC_MD_PATH
+ first_examples_header_index = spec_lines.index do |line|
+ line.start_with?('# ') && !line.start_with?(INTRODUCTION_HEADER_LINE_TEXT)
end
- raise "Unable to locate introduction header line in #{GHFM_SPEC_MD_PATH}" if ghfm_intro_header_begin_index.nil?
+ raise "Unable to find first examples header in #{path}" unless first_examples_header_index
- # Find the index of the next header after the introduction header, starting from the index
- # of the introduction header this is the length of the intro section
- ghfm_intro_section_length = spec_txt_lines[ghfm_intro_header_begin_index + 1..].index do |line|
- line.start_with?('# ')
+ end_tests_comment_index = spec_lines.index do |line|
+ line.start_with?(END_TESTS_COMMENT_LINE_TEXT)
end
+ raise "Unable to locate 'END TESTS' comment line in #{path}" if end_tests_comment_index.nil?
- # Replace the intro section with the GitLab flavored Markdown intro section
- spec_txt_lines[ghfm_intro_header_begin_index, ghfm_intro_section_length] = glfm_intro_md_lines
+ spec_lines[first_examples_header_index..(end_tests_comment_index - 1)]
end
- def insert_examples(spec_txt_lines)
- official_spec_lines = File.open(GLFM_OFFICIAL_SPECIFICATION_EXAMPLES_MD_PATH).readlines
- raise "Unable to read lines from #{GLFM_OFFICIAL_SPECIFICATION_EXAMPLES_MD_PATH}" if official_spec_lines.empty?
-
- internal_extension_lines = File.open(GLFM_INTERNAL_EXTENSION_EXAMPLES_MD_PATH).readlines
- raise "Unable to read lines from #{GLFM_INTERNAL_EXTENSION_EXAMPLES_MD_PATH}" if internal_extension_lines.empty?
+ def extract_glfm_spec_example_lines(spec_lines, path)
+ # In the GLFM input markdown files (unlike the GLFM spec.txt format), we have control over
+ # the contents, so we can use explicit <!-- BEGIN TESTS --> and <!-- END TESTS -->
+ # is the presence of a single initial H1 named "Introduction" before the first
+ # header containing examples, and the <!-- END TESTS --> comment after the last header
+ # containing examples.
+ begin_tests_comment_line_index = spec_lines.index do |line|
+ line.start_with?(BEGIN_TESTS_COMMENT_LINE_TEXT)
+ end
+ raise "Unable to locate 'BEGIN TESTS' comment line in #{path}" unless begin_tests_comment_line_index
- ghfm_end_tests_comment_index = spec_txt_lines.index do |line|
- line =~ END_TESTS_COMMENT_LINE_TEXT
+ end_tests_comment_index = spec_lines.index do |line|
+ line.start_with?(END_TESTS_COMMENT_LINE_TEXT)
end
- raise "Unable to locate 'END TESTS' comment line in #{GHFM_SPEC_MD_PATH}" if ghfm_end_tests_comment_index.nil?
-
- # Insert the GLFM examples before the 'END TESTS' comment line
- spec_txt_lines[ghfm_end_tests_comment_index - 1] = [
- "\n",
- official_spec_lines,
- "\n",
- internal_extension_lines,
- "\n"
- ].flatten
-
- spec_txt_lines
+ raise "Unable to locate 'END TESTS' comment line in #{path}" if end_tests_comment_index.nil?
+
+ spec_lines[(begin_tests_comment_line_index + 1)..(end_tests_comment_index - 1)]
end
def write_glfm_spec_txt(glfm_spec_txt_string)
@@ -156,13 +162,24 @@ module Glfm
write_file(GLFM_SPEC_TXT_PATH, glfm_spec_txt_string)
end
- def generate_glfm_spec_html(glfm_spec_txt_string)
- output("Generating spec.html from spec.txt markdown...")
+ def write_snapshot_spec_md(snapshot_spec_md_string)
+ output("Writing #{ES_SNAPSHOT_SPEC_MD_PATH}...")
+ FileUtils.mkdir_p(Pathname.new(ES_SNAPSHOT_SPEC_MD_PATH).dirname)
+ write_file(ES_SNAPSHOT_SPEC_MD_PATH, snapshot_spec_md_string)
+ end
+
+ def generate_spec_html_files(spec_txt_string, snapshot_spec_md_string)
+ output("Generating spec.html and snapshot_spec.html from spec.txt and snapshot_spec.md markdown...")
+
+ spec_txt_string_split_examples = split_examples_into_html_and_md(spec_txt_string)
+ snapshot_spec_md_string_split_examples = split_examples_into_html_and_md(snapshot_spec_md_string)
input_markdown_yml_string = <<~MARKDOWN
---
spec_txt: |
- #{glfm_spec_txt_string.gsub(/^/, ' ')}
+ #{spec_txt_string_split_examples.gsub(/^/, ' ')}
+ snapshot_spec_md: |
+ #{snapshot_spec_md_string_split_examples.gsub(/^/, ' ')}
MARKDOWN
# NOTE: We must copy the input YAML file used by the `render_static_html.rb`
@@ -190,14 +207,40 @@ module Glfm
cmd = %(bin/rspec #{__dir__}/render_static_html.rb)
run_external_cmd(cmd)
- output("Reading generated spec.html from tempfile #{static_html_tempfile_path}...")
- YAML.safe_load(File.open(static_html_tempfile_path), symbolize_names: true).fetch(:spec_txt)
+ output("Reading generated html from tempfile #{static_html_tempfile_path}...")
+ rendered_html_hash = YAML.safe_load(File.open(static_html_tempfile_path), symbolize_names: true)
+ [rendered_html_hash.fetch(:spec_txt), rendered_html_hash.fetch(:snapshot_spec_md)]
+ end
+
+ def split_examples_into_html_and_md(spec_md_string)
+ spec_md_string.gsub(
+ /(^#{EXAMPLE_BEGIN_STRING}.*?$(?:.|\n)*?)^\.$(\n(?:.|\n)*?^#{EXAMPLE_END_STRING}$)/mo,
+ "\\1#{EXAMPLE_BACKTICKS_STRING}\n\n#{EXAMPLE_BACKTICKS_STRING}\\2"
+ )
end
- def write_glfm_spec_html(glfm_spec_html_string)
+ def write_spec_html(spec_html_string)
output("Writing #{GLFM_SPEC_TXT_PATH}...")
FileUtils.mkdir_p(Pathname.new(GLFM_SPEC_HTML_PATH).dirname)
- write_file(GLFM_SPEC_HTML_PATH, "#{glfm_spec_html_string}\n")
+ write_file(GLFM_SPEC_HTML_PATH, "#{spec_html_string}\n")
+ end
+
+ def write_snapshot_spec_html(snapshot_spec_html_string)
+ output("Writing #{ES_SNAPSHOT_SPEC_HTML_PATH}...")
+ FileUtils.mkdir_p(Pathname.new(ES_SNAPSHOT_SPEC_HTML_PATH).dirname)
+ write_file(ES_SNAPSHOT_SPEC_HTML_PATH, "#{snapshot_spec_html_string}\n")
+ end
+
+ def readlines_from_path!(path)
+ io = File.open(path)
+ readlines_from_io!(io, path)
+ end
+
+ def readlines_from_io!(io, uri_or_path)
+ lines = io.readlines
+ raise "Unable to read lines from #{uri_or_path}" if lines.empty?
+
+ lines
end
end
end
diff --git a/scripts/lib/glfm/verify_all_generated_files_are_up_to_date.rb b/scripts/lib/glfm/verify_all_generated_files_are_up_to_date.rb
index 0b824fc589d..3d4570f74e5 100644
--- a/scripts/lib/glfm/verify_all_generated_files_are_up_to_date.rb
+++ b/scripts/lib/glfm/verify_all_generated_files_are_up_to_date.rb
@@ -12,7 +12,7 @@ module Glfm
include Shared
def process
- verify_cmd = "git status --porcelain #{GLFM_SPEC_OUTPUT_PATH} #{EXAMPLE_SNAPSHOTS_PATH}"
+ verify_cmd = "git status --porcelain #{GLFM_OUTPUT_SPEC_PATH} #{ES_OUTPUT_EXAMPLE_SNAPSHOTS_PATH}"
verify_cmd_output = run_external_cmd(verify_cmd)
unless verify_cmd_output.empty?
msg = "ERROR: Cannot run `#{__FILE__}` because `#{verify_cmd}` shows the following uncommitted changes:\n" \
@@ -41,8 +41,20 @@ module Glfm
return if verify_cmd_output.empty?
- raise "The following files were modified by running GLFM scripts. Please review, verify, and commit " \
- "the changes:\n#{verify_cmd_output}"
+ warn(
+ "ERROR: The following files were modified by running GLFM scripts. Please review, verify, and commit " \
+ "the changes:\n#{verify_cmd_output}\n"
+ )
+ warn("See the CI artifacts for the modified version of the files.\n")
+
+ warn("This is the output of `git diff`:\n")
+ diff_output = run_external_cmd('git diff')
+ warn(diff_output)
+
+ # Ensure that the diff output is flushed and output before we raise and exit.
+ $stderr.flush
+
+ raise('ERROR: The generated files are not up to date.')
end
end
end
diff --git a/scripts/license-check.sh b/scripts/license-check.sh
index c2d5cfd8cde..2a210754a0d 100755
--- a/scripts/license-check.sh
+++ b/scripts/license-check.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+set -euo pipefail
#
# This script runs the LicenseFinder gem to verify that all licenses are
# compliant. However, bundler v2.2+ and LicenseFinder do not play well
diff --git a/scripts/lint-doc.sh b/scripts/lint-doc.sh
index f954b2d8106..68dfac95ef6 100755
--- a/scripts/lint-doc.sh
+++ b/scripts/lint-doc.sh
@@ -151,7 +151,7 @@ if [ -z "${MD_DOC_PATH}" ]
then
echo "Merged results pipeline detected, but no markdown files found. Skipping."
else
- run_locally_or_in_docker 'markdownlint' "--config .markdownlint.yml ${MD_DOC_PATH}"
+ run_locally_or_in_docker 'markdownlint' "--config .markdownlint.yml ${MD_DOC_PATH} --rules doc/.markdownlint/rules"
fi
echo '=> Linting prose...'
diff --git a/scripts/lint_templates_bash.rb b/scripts/lint_templates_bash.rb
index 8db9469ecdf..cd36bb629ab 100755
--- a/scripts/lint_templates_bash.rb
+++ b/scripts/lint_templates_bash.rb
@@ -58,6 +58,12 @@ module LintTemplatesBash
def check_template(template)
parsed = process_content(template.content)
+
+ unless parsed.valid?
+ warn "#{template.full_name} is invalid: #{parsed.errors.inspect}"
+ return true
+ end
+
results = parsed.jobs.map do |name, job|
out, success = check_job(job)
diff --git a/scripts/merge-reports b/scripts/merge-reports
index a1164495f2f..43374d134d4 100755
--- a/scripts/merge-reports
+++ b/scripts/merge-reports
@@ -14,6 +14,8 @@ main_report = JSON.parse(File.read(main_report_file))
new_report = main_report.dup
ARGV.each do |report_file|
+ next unless File.exist?(report_file)
+
report = JSON.parse(File.read(report_file))
# Remove existing values
diff --git a/scripts/perf/gc/print_gc_stats.rb b/scripts/perf/gc/print_gc_stats.rb
index 4aeb2f1ef07..a15b6f5b0e0 100755
--- a/scripts/perf/gc/print_gc_stats.rb
+++ b/scripts/perf/gc/print_gc_stats.rb
@@ -60,7 +60,7 @@ gc_stat_keys = ENV['GC_STAT_KEYS'].to_s.split(',').map(&:to_sym)
values = []
values << ENV['SETTING_CSV']
values += gc_stat_keys.map { |k| gc_stats[k] }
-values << ::Gitlab::Metrics::System.memory_usage_rss
+values << ::Gitlab::Metrics::System.memory_usage_rss[:total]
values << gc_total_time
values << tms.utime + tms.cutime
values << tms.stime + tms.cstime
diff --git a/scripts/perf/query_limiting_report.rb b/scripts/perf/query_limiting_report.rb
index 364cd6fc5d4..6326b2590ae 100755
--- a/scripts/perf/query_limiting_report.rb
+++ b/scripts/perf/query_limiting_report.rb
@@ -124,19 +124,19 @@ class QueryLimitingReport
file_lines.each_index do |index|
line = file_lines[index]
- if line =~ /#{CODE_LINES_SEARCH_STRING}/o
- issue_iid = line.slice(%r{issues/(\d+)\D}, 1)
- line_number = index + 1
- code_line = {
- file_location: "#{filename}:#{line_number}",
- filename: filename,
- line_number: line_number,
- line: line,
- issue_iid: issue_iid.to_i,
- has_issue_iid: !issue_iid.nil?
- }
- code_lines << code_line
- end
+ next unless line =~ /#{CODE_LINES_SEARCH_STRING}/o
+
+ issue_iid = line.slice(%r{issues/(\d+)\D}, 1)
+ line_number = index + 1
+ code_line = {
+ file_location: "#{filename}:#{line_number}",
+ filename: filename,
+ line_number: line_number,
+ line: line,
+ issue_iid: issue_iid.to_i,
+ has_issue_iid: !issue_iid.nil?
+ }
+ code_lines << code_line
end
end
diff --git a/scripts/qa/quarantine-types-check b/scripts/qa/quarantine-types-check
index 44d329a3590..188348b949c 100755
--- a/scripts/qa/quarantine-types-check
+++ b/scripts/qa/quarantine-types-check
@@ -30,19 +30,19 @@ puts "\nAnalyzing quarantined test data...\n"
tests = data_hash['examples']
tests.each do |test|
- if test['quarantine']
- unless QUARANTINE_TYPES.include?(test['quarantine']['type'])
- quarantine_type_errors.push(
- <<~TYPE_ERRORS
+ next unless test['quarantine']
+
+ unless QUARANTINE_TYPES.include?(test['quarantine']['type'])
+ quarantine_type_errors.push(
+ <<~TYPE_ERRORS
==> #{test['full_description']}
in file: #{test['id']}
with type: "#{test['quarantine']['type']}"
- TYPE_ERRORS
- )
- end
-
- missing_issues.push(" ==> #{test['id']} - #{test['full_description']}\n") unless test['quarantine']['issue']
+ TYPE_ERRORS
+ )
end
+
+ missing_issues.push(" ==> #{test['id']} - #{test['full_description']}\n") unless test['quarantine']['issue']
end
if quarantine_type_errors.empty? && missing_issues.empty?
diff --git a/scripts/qa/testcases-check b/scripts/qa/testcases-check
index 12af15fe73f..26098678f7c 100755
--- a/scripts/qa/testcases-check
+++ b/scripts/qa/testcases-check
@@ -74,6 +74,7 @@ else
puts missing_message % missing_testcases.join("\n") unless missing_testcases.empty?
puts format_message % testcase_format_errors.join("\n") unless testcase_format_errors.empty?
puts "\n*** Please link a unique test case from the GitLab project for the errors listed above.\n"
- puts " See: https://docs.gitlab.com/ee/development/testing_guide/end_to_end/best_practices.html#link-a-test-to-its-test-case."
+ puts " See: https://docs.gitlab.com/ee/development/testing_guide/end_to_end/best_practices.html#link-a-test-to-its-test-case"\
+ " for further details on how to create test cases"
exit 1
end
diff --git a/scripts/review_apps/automated_cleanup.rb b/scripts/review_apps/automated_cleanup.rb
index 2440df6958d..f020283de52 100755
--- a/scripts/review_apps/automated_cleanup.rb
+++ b/scripts/review_apps/automated_cleanup.rb
@@ -88,7 +88,7 @@ module ReviewApps
if deployed_at < delete_threshold
deleted_environment = delete_environment(environment, deployment)
if deleted_environment
- release = Tooling::Helm3Client::Release.new(environment.slug, 1, deployed_at.to_s, nil, nil, review_apps_namespace)
+ release = Tooling::Helm3Client::Release.new(environment.slug, 1, deployed_at.to_s, nil, nil, environment.slug)
releases_to_delete << release
end
else
@@ -104,7 +104,7 @@ module ReviewApps
end
delete_stopped_environments(environment_type: :review_app, checked_environments: checked_environments, last_updated_threshold: delete_threshold) do |environment|
- releases_to_delete << Tooling::Helm3Client::Release.new(environment.slug, 1, environment.updated_at, nil, nil, review_apps_namespace)
+ releases_to_delete << Tooling::Helm3Client::Release.new(environment.slug, 1, environment.updated_at, nil, nil, environment.slug)
end
delete_helm_releases(releases_to_delete)
@@ -190,6 +190,8 @@ module ReviewApps
rescue Gitlab::Error::Forbidden
puts "Review app '#{environment.name}' / '#{environment.slug}' (##{environment.id}) is forbidden: skipping it"
+ rescue Gitlab::Error::InternalServerError
+ puts "Review app '#{environment.name}' / '#{environment.slug}' (##{environment.id}) 500 error - ignoring it"
end
def stop_environment(environment, deployment)
diff --git a/scripts/review_apps/base-config.yaml b/scripts/review_apps/base-config.yaml
index 91c645a0ed9..f845dd04e8f 100644
--- a/scripts/review_apps/base-config.yaml
+++ b/scripts/review_apps/base-config.yaml
@@ -18,73 +18,91 @@ global:
preemptible: "true"
certmanager:
install: false
+
gitlab:
gitaly:
resources:
requests:
- cpu: 2400m
- memory: 1000M
+ cpu: 1200m
+ memory: 600Mi
limits:
- cpu: 3600m
- memory: 1500M
+ cpu: 1800m
+ memory: 1000Mi
persistence:
- size: 10G
+ size: 10Gi
storageClass: ssd
nodeSelector:
preemptible: "false"
podAnnotations:
<<: *safe-to-evict
+
gitlab-exporter:
enabled: false
- mailroom:
- enabled: false
- migrations:
- resources:
- requests:
- cpu: 350m
- memory: 200M
- limits:
- cpu: 700m
+
gitlab-shell:
resources:
requests:
cpu: 500m
- memory: 100M
+ memory: 100Mi
limits:
cpu: 750m
- memory: 150M
- maxReplicas: 3
+ memory: 150Mi
+ minReplicas: 1
+ maxReplicas: 1
hpa:
- targetAverageValue: 500m
+ cpu:
+ targetAverageValue: 500m
deployment:
livenessProbe:
timeoutSeconds: 5
+
+ kas:
+ minReplicas: 1
+ maxReplicas: 1
+
+ mailroom:
+ enabled: false
+
+ migrations:
+ resources:
+ requests:
+ cpu: 400m
+ memory: 920Mi
+ limits:
+ cpu: 600m
+ memory: 1100Mi
+
sidekiq:
resources:
requests:
cpu: 855m
- memory: 1927M
+ memory: 1927Mi
limits:
cpu: 1282m
- memory: 2890M
+ memory: 2890Mi
hpa:
- targetAverageValue: 650m
+ cpu:
+ targetAverageValue: 650m
+
toolbox:
resources:
requests:
cpu: 300m
- memory: 1927M
+ memory: 1927Mi
limits:
cpu: 450m
- memory: 2890M
+ memory: 2890Mi
+
webservice:
resources:
requests:
cpu: 746m
- memory: 2809M
+ memory: 2809Mi
limits:
cpu: 1119m
- memory: 4214M
+ memory: 4214Mi
+ minReplicas: 1
+ maxReplicas: 1
deployment:
readinessProbe:
initialDelaySeconds: 5 # Default is 0
@@ -94,38 +112,41 @@ gitlab:
resources:
requests:
cpu: 400m
- memory: 75M
+ memory: 75Mi
limits:
cpu: 600m
- memory: 113M
+ memory: 113Mi
readinessProbe:
initialDelaySeconds: 5 # Default is 0
periodSeconds: 15 # Default is 10
timeoutSeconds: 5 # Default is 2
+
gitlab-runner:
resources:
requests:
cpu: 675m
- memory: 100M
+ memory: 100Mi
limits:
cpu: 1015m
- memory: 150M
+ memory: 150Mi
nodeSelector:
preemptible: "true"
podAnnotations:
<<: *safe-to-evict
+
minio:
resources:
requests:
cpu: 9m
- memory: 128M
+ memory: 128Mi
limits:
cpu: 15m
- memory: 280M
+ memory: 280Mi
nodeSelector:
preemptible: "true"
podAnnotations:
<<: *safe-to-evict
+
nginx-ingress:
controller:
config:
@@ -133,10 +154,10 @@ nginx-ingress:
resources:
requests:
cpu: 300m
- memory: 450M
+ memory: 450Mi
limits:
cpu: 600m
- memory: 675M
+ memory: 675Mi
service:
enableHttp: false
livenessProbe:
@@ -149,53 +170,58 @@ nginx-ingress:
resources:
requests:
cpu: 5m
- memory: 12M
+ memory: 12Mi
limits:
cpu: 10m
- memory: 24M
+ memory: 24Mi
nodeSelector:
preemptible: "true"
+
postgresql:
metrics:
enabled: false
resources:
requests:
cpu: 600m
- memory: 1000M
+ memory: 1000Mi
limits:
cpu: 1300m
- memory: 1500M
+ memory: 1600Mi
master:
nodeSelector:
preemptible: "false"
podAnnotations:
<<: *safe-to-evict
+
prometheus:
install: false
+
redis:
metrics:
enabled: false
resources:
requests:
cpu: 100m
- memory: 60M
+ memory: 60Mi
limits:
cpu: 200m
- memory: 130M
+ memory: 130Mi
master:
nodeSelector:
preemptible: "true"
podAnnotations:
<<: *safe-to-evict
+
registry:
hpa:
minReplicas: 1
+ maxReplicas: 1
resources:
requests:
cpu: 100m
- memory: 30M
+ memory: 30Mi
limits:
cpu: 200m
- memory: 45M
+ memory: 45Mi
nodeSelector:
preemptible: "true"
diff --git a/scripts/review_apps/review-apps.sh b/scripts/review_apps/review-apps.sh
index 0fc245a409f..5883141a943 100755
--- a/scripts/review_apps/review-apps.sh
+++ b/scripts/review_apps/review-apps.sh
@@ -62,7 +62,7 @@ function previous_deploy_failed() {
return $status
}
-function delete_release() {
+function delete_helm_release() {
local namespace="${CI_ENVIRONMENT_SLUG}"
local release="${CI_ENVIRONMENT_SLUG}"
@@ -74,32 +74,6 @@ function delete_release() {
if deploy_exists "${namespace}" "${release}"; then
helm uninstall --namespace="${namespace}" "${release}"
fi
-}
-
-function delete_failed_release() {
- local namespace="${CI_ENVIRONMENT_SLUG}"
- local release="${CI_ENVIRONMENT_SLUG}"
-
- if [ -z "${release}" ]; then
- echoerr "No release given, aborting the delete!"
- return
- fi
-
- if ! deploy_exists "${namespace}" "${release}"; then
- echoinfo "No Review App with ${release} is currently deployed."
- else
- # Cleanup and previous installs, as FAILED and PENDING_UPGRADE will cause errors with `upgrade`
- if previous_deploy_failed "${namespace}" "${release}" ; then
- echoinfo "Review App deployment in bad state, cleaning up namespace ${release}"
- delete_namespace
- else
- echoinfo "Review App deployment in good state"
- fi
- fi
-}
-
-function delete_namespace() {
- local namespace="${CI_ENVIRONMENT_SLUG}"
if namespace_exists "${namespace}"; then
echoinfo "Deleting namespace ${namespace}..." true
@@ -143,7 +117,7 @@ function run_task() {
local ruby_cmd="${1}"
local toolbox_pod=$(get_pod "toolbox")
- kubectl exec --namespace "${namespace}" "${toolbox_pod}" -- gitlab-rails runner "${ruby_cmd}"
+ run_timed_command "kubectl exec --namespace \"${namespace}\" \"${toolbox_pod}\" -- gitlab-rails runner \"${ruby_cmd}\""
}
function disable_sign_ups() {
@@ -346,47 +320,44 @@ EOF
if [ -n "${REVIEW_APPS_EE_LICENSE_FILE}" ]; then
HELM_CMD=$(cat << EOF
${HELM_CMD} \
- --set global.gitlab.license.secret="shared-gitlab-license"
+ --set global.gitlab.license.secret="shared-gitlab-license"
EOF
)
fi
HELM_CMD=$(cat << EOF
${HELM_CMD} \
- --version="${CI_PIPELINE_ID}-${CI_JOB_ID}" \
- -f "${base_config_file}" \
- -v "${HELM_LOG_VERBOSITY:-1}" \
- "${release}" "gitlab-${GITLAB_HELM_CHART_REF}"
+ --version="${CI_PIPELINE_ID}-${CI_JOB_ID}" \
+ -f "${base_config_file}" \
+ -v "${HELM_LOG_VERBOSITY:-1}" \
+ "${release}" "gitlab-${GITLAB_HELM_CHART_REF}"
EOF
)
+ # Pretty-print the command for display
echoinfo "Deploying with:"
- echoinfo "${HELM_CMD}"
+ echo "${HELM_CMD}" | sed 's/ /\n\t/g'
- eval "${HELM_CMD}"
+ run_timed_command "eval \"${HELM_CMD}\""
}
function verify_deploy() {
- echoinfo "Verifying deployment at ${CI_ENVIRONMENT_URL}"
+ local namespace="${CI_ENVIRONMENT_SLUG}"
+
+ echoinfo "[$(date '+%H:%M:%S')] Verifying deployment at ${CI_ENVIRONMENT_URL}"
if retry "test_url \"${CI_ENVIRONMENT_URL}\""; then
- echoinfo "Review app is deployed to ${CI_ENVIRONMENT_URL}"
+ echoinfo "[$(date '+%H:%M:%S')] Review app is deployed to ${CI_ENVIRONMENT_URL}"
return 0
else
- echoerr "Review app is not available at ${CI_ENVIRONMENT_URL}: see the logs from cURL above for more details"
+ echoerr "[$(date '+%H:%M:%S')] Review app is not available at ${CI_ENVIRONMENT_URL}: see the logs from cURL above for more details"
return 1
fi
}
function display_deployment_debug() {
local namespace="${CI_ENVIRONMENT_SLUG}"
- local release="${CI_ENVIRONMENT_SLUG}"
-
- # Get all pods for this release
- echoinfo "Pods for release ${release}"
- kubectl get pods --namespace "${namespace}" -lrelease=${release}
- # Get all non-completed jobs
- echoinfo "Unsuccessful Jobs for release ${release}"
- kubectl get jobs --namespace "${namespace}" -lrelease=${release} --field-selector=status.successful!=1
+ echoinfo "Environment debugging data:"
+ kubectl get svc,pods,jobs --namespace "${namespace}"
}
diff --git a/scripts/rspec_helpers.sh b/scripts/rspec_helpers.sh
index 73030d2ad6c..14c5b94e921 100644
--- a/scripts/rspec_helpers.sh
+++ b/scripts/rspec_helpers.sh
@@ -11,7 +11,6 @@ function retrieve_tests_metadata() {
if [[ ! -f "${FLAKY_RSPEC_SUITE_REPORT_PATH}" ]]; then
curl --location -o "${FLAKY_RSPEC_SUITE_REPORT_PATH}" "https://gitlab-org.gitlab.io/gitlab/${FLAKY_RSPEC_SUITE_REPORT_PATH}" ||
- curl --location -o "${FLAKY_RSPEC_SUITE_REPORT_PATH}" "https://gitlab-org.gitlab.io/gitlab/rspec_flaky/report-suite.json" || # temporary back-compat
echo "{}" > "${FLAKY_RSPEC_SUITE_REPORT_PATH}"
fi
else
@@ -35,13 +34,7 @@ function retrieve_tests_metadata() {
if [[ ! -f "${FLAKY_RSPEC_SUITE_REPORT_PATH}" ]]; then
scripts/api/download_job_artifact.rb --endpoint "https://gitlab.com/api/v4" --project "${project_path}" --job-id "${test_metadata_job_id}" --artifact-path "${FLAKY_RSPEC_SUITE_REPORT_PATH}" ||
- scripts/api/download_job_artifact.rb --endpoint "https://gitlab.com/api/v4" --project "${project_path}" --job-id "${test_metadata_job_id}" --artifact-path "rspec_flaky/report-suite.json" || # temporary back-compat
echo "{}" > "${FLAKY_RSPEC_SUITE_REPORT_PATH}"
-
- # temporary back-compat
- if [[ -f "rspec_flaky/report-suite.json" ]]; then
- mv "rspec_flaky/report-suite.json" "${FLAKY_RSPEC_SUITE_REPORT_PATH}"
- fi
fi
else
echo "test_metadata_job_id couldn't be found!"
@@ -61,10 +54,16 @@ function update_tests_metadata() {
export FLAKY_RSPEC_GENERATE_REPORT="true"
scripts/merge-reports "${FLAKY_RSPEC_SUITE_REPORT_PATH}" ${rspec_flaky_folder_path}all_*.json
+
+ # Prune flaky tests that weren't flaky in the last 7 days, *after* updating the flaky tests detected
+ # in this pipeline, so that first_flaky_at for tests that are still flaky is maintained.
scripts/flaky_examples/prune-old-flaky-examples "${FLAKY_RSPEC_SUITE_REPORT_PATH}"
if [[ "$CI_PIPELINE_SOURCE" == "schedule" ]]; then
- scripts/insert-rspec-profiling-data
+ if [[ -n "$RSPEC_PROFILING_PGSSLKEY" ]]; then
+ chmod 0600 $RSPEC_PROFILING_PGSSLKEY
+ fi
+ PGSSLMODE=$RSPEC_PROFILING_PGSSLMODE PGSSLROOTCERT=$RSPEC_PROFILING_PGSSLROOTCERT PGSSLCERT=$RSPEC_PROFILING_PGSSLCERT PGSSLKEY=$RSPEC_PROFILING_PGSSLKEY scripts/insert-rspec-profiling-data
else
echo "Not inserting profiling data as the pipeline is not a scheduled one."
fi
diff --git a/scripts/rubocop-parse b/scripts/rubocop-parse
index 0a234df81cd..c99d66e99ad 100755
--- a/scripts/rubocop-parse
+++ b/scripts/rubocop-parse
@@ -39,7 +39,34 @@ module Helper
def ast(source, file: '', version: nil)
version ||= ruby_version
- puts RuboCop::AST::ProcessedSource.new(source, version).ast.to_s
+
+ ast = RuboCop::AST::ProcessedSource.new(source, version).ast
+ return ast if ast
+
+ warn "Syntax error in `#{source}`."
+ end
+
+ def pattern(string)
+ RuboCop::NodePattern.new(string)
+ end
+
+ def help!
+ puts <<~HELP
+
+ Use `ast(source_string, version: nil)` method to parse code and return its AST.
+ Use `pattern(string)` to compile RuboCop's node patterns.
+
+ See https://docs.rubocop.org/rubocop-ast/node_pattern.html.
+
+ Examples:
+ node = ast('puts :hello')
+
+ pat = pattern('`(sym :hello)')
+ pat.match(node) # => true
+
+ HELP
+
+ nil
end
def ruby_version
@@ -56,11 +83,12 @@ def start_irb
include Helper # rubocop:disable Style/MixinUsage
- puts "Ruby version: #{ruby_version}"
- puts
- puts "Use `ast(source_string, version: nil)` method to parse code and output AST. For example:"
- puts " ast('puts :hello')"
- puts
+ puts <<~BANNER
+ Ruby version: #{ruby_version}
+
+ Type `help!` for instructions and examples.
+
+ BANNER
IRB.start
end
@@ -103,12 +131,12 @@ elsif options.interactive
start_irb
end
elsif options.eval
- Helper.ast(options.eval)
+ puts Helper.ast(options.eval)
elsif files.any?
files.each do |file|
if File.file?(file)
source = File.read(file)
- Helper.ast(source, file: file)
+ puts Helper.ast(source, file: file)
else
warn "Skipping non-file #{file.inspect}"
end
diff --git a/scripts/security-harness b/scripts/security-harness
index df499be23f5..db397a6c1b1 100755
--- a/scripts/security-harness
+++ b/scripts/security-harness
@@ -75,6 +75,7 @@ end
def delete_hook
FileUtils.rm(HOOK_PATH)
+ system("git checkout master")
puts "#{SHELL_YELLOW}Security harness removed -- you can now push to all remotes.#{SHELL_CLEAR}"
end
diff --git a/scripts/setup/as-if-jh.sh b/scripts/setup/as-if-jh.sh
new file mode 100755
index 00000000000..38c3ac9b913
--- /dev/null
+++ b/scripts/setup/as-if-jh.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+prepare_jh_branch() {
+ set -eu # https://explainshell.com/explain?cmd=set+-eu
+
+ JH_BRANCH="$(./scripts/setup/find-jh-branch.rb)"
+ export JH_BRANCH
+
+ echoinfo "JH_BRANCH: ${JH_BRANCH}"
+}
+
+download_jh_path() {
+ set -eu # https://explainshell.com/explain?cmd=set+-eu
+
+ for path in "$@"; do
+ # https://www.shellcheck.net/wiki/SC3043
+ # shellcheck disable=SC3043
+ local output="${path}.tar.gz"
+
+ echoinfo "Downloading ${path}"
+
+ curl --location -o "${output}" -H "Private-Token: ${ADD_JH_FILES_TOKEN}" "https://gitlab.com/api/v4/projects/${GITLAB_JH_MIRROR_PROJECT}/repository/archive?sha=${JH_BRANCH}&path=${path}"
+
+ tar -zxf "${output}"
+ rm "${output}"
+ mv gitlab-"${JH_BRANCH}"-*/"${path}" ./
+ done
+}
diff --git a/scripts/used-feature-flags b/scripts/used-feature-flags
index 0966795f451..eb7e85be229 100755
--- a/scripts/used-feature-flags
+++ b/scripts/used-feature-flags
@@ -97,7 +97,7 @@ puts
if additional_flags.count > 0
puts "==================================================".green.bold
- puts "There are feature flags that appears to be unknown".yellow
+ puts "There are feature flags that appear to be unknown".yellow
puts
puts "They appear to be used by CI, but we do lack their YAML definition".yellow
puts "This is likely expected, so feel free to ignore that list:".yellow
@@ -110,7 +110,7 @@ end
if unused_flags.count > 0
puts "========================================".green.bold
- puts "These feature flags appears to be UNUSED".red.bold
+ puts "These feature flags appear to be UNUSED".red.bold
puts
puts "If they are really no longer needed REMOVE their .yml definition".red
puts "If they are needed you need to ENSURE that their usage is covered with specs to continue.".red
diff --git a/scripts/utils.sh b/scripts/utils.sh
index ea2b390f249..50ca7f558f6 100644
--- a/scripts/utils.sh
+++ b/scripts/utils.sh
@@ -5,7 +5,7 @@ function retry() {
for i in 2 1; do
sleep 3s
- echo "Retrying $i..."
+ echo "[$(date '+%H:%M:%S')] Retrying $i..."
if eval "$@"; then
return 0
fi
diff --git a/spec/bin/audit_event_type_spec.rb b/spec/bin/audit_event_type_spec.rb
new file mode 100644
index 00000000000..d4b1ebf08de
--- /dev/null
+++ b/spec/bin/audit_event_type_spec.rb
@@ -0,0 +1,293 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+
+load File.expand_path('../../bin/audit-event-type', __dir__)
+
+RSpec.describe 'bin/audit-event-type' do
+ using RSpec::Parameterized::TableSyntax
+
+ describe AuditEventTypeCreator do
+ let(:argv) { %w[test_audit_event -d test -g govern::compliance -s -t -i https://url -m http://url] }
+ let(:options) { AuditEventTypeOptionParser.parse(argv) }
+ let(:creator) { described_class.new(options) }
+ let(:existing_audit_event_types) do
+ { 'existing_audit_event_type' => File.join('config', 'audit_events', 'types', 'existing_audit_event_type.yml') }
+ end
+
+ before do
+ allow(creator).to receive(:all_audit_event_type_names) { existing_audit_event_types }
+ allow(creator).to receive(:branch_name).and_return('feature-branch')
+ allow(creator).to receive(:editor).and_return(nil)
+
+ # ignore writes
+ allow(File).to receive(:write).and_return(true)
+
+ # ignore stdin
+ allow(Readline).to receive(:readline).and_raise('EOF')
+ end
+
+ subject(:create_audit_event_type) { creator.execute }
+
+ it 'properly creates an audit event type' do
+ expect(File).to receive(:write).with(
+ File.join('config', 'audit_events', 'types', 'test_audit_event.yml'),
+ anything)
+
+ expect do
+ create_audit_event_type
+ end.to output(/name: test_audit_event/).to_stdout
+ end
+
+ context 'when running on master' do
+ it 'requires feature branch' do
+ expect(creator).to receive(:branch_name).and_return('master')
+
+ expect { create_audit_event_type }.to raise_error(AuditEventTypeHelpers::Abort, /Create a branch first/)
+ end
+ end
+
+ context 'with invalid audit event type names' do
+ where(:argv, :ex) do
+ %w[.invalid.audit.type] | /Provide a name for the audit event type that is/
+ %w[existing_audit_event_type] | /already exists!/
+ end
+
+ with_them do
+ it do
+ expect { create_audit_event_type }.to raise_error(ex)
+ end
+ end
+ end
+ end
+
+ describe AuditEventTypeOptionParser do
+ describe '.parse' do
+ where(:param, :argv, :result) do
+ :name | %w[foo] | 'foo'
+ :amend | %w[foo --amend] | true
+ :force | %w[foo -f] | true
+ :force | %w[foo --force] | true
+ :description | %w[foo -d desc] | 'desc'
+ :description | %w[foo --description desc] | 'desc'
+ :group | %w[foo -g govern::compliance] | 'govern::compliance'
+ :group | %w[foo --group govern::compliance] | 'govern::compliance'
+ :milestone | %w[foo -M 15.6] | '15.6'
+ :milestone | %w[foo --milestone 15.6] | '15.6'
+ :saved_to_database | %w[foo -s] | true
+ :saved_to_database | %w[foo --saved-to-database] | true
+ :saved_to_database | %w[foo --no-saved-to-database] | false
+ :streamed | %w[foo -t] | true
+ :streamed | %w[foo --streamed] | true
+ :streamed | %w[foo --no-streamed] | false
+ :dry_run | %w[foo -n] | true
+ :dry_run | %w[foo --dry-run] | true
+ :ee | %w[foo -e] | true
+ :ee | %w[foo --ee] | true
+ :jh | %w[foo -j] | true
+ :jh | %w[foo --jh] | true
+ :introduced_by_mr | %w[foo -m https://url] | 'https://url'
+ :introduced_by_mr | %w[foo --introduced-by-mr https://url] | 'https://url'
+ :introduced_by_issue | %w[foo -i https://url] | 'https://url'
+ :introduced_by_issue | %w[foo --introduced-by-issue https://url] | 'https://url'
+ end
+
+ with_them do
+ it do
+ options = described_class.parse(Array(argv))
+
+ expect(options.public_send(param)).to eq(result)
+ end
+ end
+
+ it 'raises an error when name of the audit event type is missing' do
+ expect do
+ expect do
+ described_class.parse(%w[--amend])
+ end.to output(/Name for the type of audit event is required/).to_stdout
+ end.to raise_error(AuditEventTypeHelpers::Abort)
+ end
+
+ it 'parses -h' do
+ expect do
+ expect { described_class.parse(%w[foo -h]) }.to output(%r{Usage: bin/audit-event-type}).to_stdout
+ end.to raise_error(AuditEventTypeHelpers::Done)
+ end
+ end
+
+ describe '.read_description' do
+ let(:description) { 'This is a test description for an audit event type.' }
+
+ it 'reads description from stdin' do
+ expect(Readline).to receive(:readline).and_return(description)
+ expect do
+ expect(described_class.read_description).to eq('This is a test description for an audit event type.')
+ end.to output(/Specify a human-readable description of how this event is triggered:/).to_stdout
+ end
+
+ context 'when description is empty' do
+ let(:description) { '' }
+
+ it 'shows error message and retries' do
+ expect(Readline).to receive(:readline).and_return(description)
+ expect(Readline).to receive(:readline).and_raise('EOF')
+
+ expect do
+ expect { described_class.read_description }.to raise_error(/EOF/)
+ end.to output(/Specify a human-readable description of how this event is triggered:/)
+ .to_stdout.and output(/description is a required field/).to_stderr
+ end
+ end
+ end
+
+ describe '.read_group' do
+ let(:group) { 'govern::compliance' }
+
+ it 'reads group from stdin' do
+ expect(Readline).to receive(:readline).and_return(group)
+ expect do
+ expect(described_class.read_group).to eq('govern::compliance')
+ end.to output(/Specify the group introducing the audit event type, like `govern::compliance`:/).to_stdout
+ end
+
+ context 'when group is empty' do
+ let(:group) { '' }
+
+ it 'shows error message and retries' do
+ expect(Readline).to receive(:readline).and_return(group)
+ expect(Readline).to receive(:readline).and_raise('EOF')
+
+ expect do
+ expect { described_class.read_group }.to raise_error(/EOF/)
+ end.to output(/Specify the group introducing the audit event type, like `govern::compliance`:/)
+ .to_stdout.and output(/group is a required field/).to_stderr
+ end
+ end
+ end
+
+ describe '.read_saved_to_database' do
+ let(:saved_to_database) { 'true' }
+
+ it 'reads saved_to_database from stdin' do
+ expect(Readline).to receive(:readline).and_return(saved_to_database)
+ expect do
+ expect(described_class.read_saved_to_database).to eq(true)
+ end.to output(/Specify whether to persist events to database and JSON logs \[yes, no\]:/).to_stdout
+ end
+
+ context 'when saved_to_database is invalid' do
+ let(:saved_to_database) { 'non boolean value' }
+
+ it 'shows error message and retries' do
+ expect(Readline).to receive(:readline).and_return(saved_to_database)
+ expect(Readline).to receive(:readline).and_raise('EOF')
+
+ expect do
+ expect { described_class.read_saved_to_database }.to raise_error(/EOF/)
+ end.to output(/Specify whether to persist events to database and JSON logs \[yes, no\]:/)
+ .to_stdout.and output(/saved_to_database is a required boolean field/).to_stderr
+ end
+ end
+ end
+
+ describe '.read_streamed' do
+ let(:streamed) { 'true' }
+
+ it 'reads streamed from stdin' do
+ expect(Readline).to receive(:readline).and_return(streamed)
+ expect do
+ expect(described_class.read_streamed).to eq(true)
+ end.to output(/Specify if events should be streamed to external services \(if configured\) \[yes, no\]:/)
+ .to_stdout
+ end
+
+ context 'when streamed is invalid' do
+ let(:streamed) { 'non boolean value' }
+
+ it 'shows error message and retries' do
+ expect(Readline).to receive(:readline).and_return(streamed)
+ expect(Readline).to receive(:readline).and_raise('EOF')
+
+ expect do
+ expect { described_class.read_streamed }.to raise_error(/EOF/)
+ end.to output(/Specify if events should be streamed to external services \(if configured\) \[yes, no\]:/)
+ .to_stdout.and output(/streamed is a required boolean field/).to_stderr
+ end
+ end
+ end
+
+ describe '.read_introduced_by_mr' do
+ let(:url) { 'https://merge-request' }
+
+ it 'reads introduced_by_mr from stdin' do
+ expect(Readline).to receive(:readline).and_return(url)
+ expect do
+ expect(described_class.read_introduced_by_mr).to eq('https://merge-request')
+ end.to output(/URL to GitLab merge request that added this type of audit event:/).to_stdout
+ end
+
+ context 'when URL is empty' do
+ let(:url) { '' }
+
+ it 'does not raise an error' do
+ expect(Readline).to receive(:readline).and_return(url)
+
+ expect do
+ expect(described_class.read_introduced_by_mr).to be_nil
+ end.to output(/URL to GitLab merge request that added this type of audit event:/).to_stdout
+ end
+ end
+
+ context 'when URL is invalid' do
+ let(:url) { 'invalid' }
+
+ it 'shows error message and retries' do
+ expect(Readline).to receive(:readline).and_return(url)
+ expect(Readline).to receive(:readline).and_raise('EOF')
+
+ expect do
+ expect { described_class.read_introduced_by_mr }.to raise_error(/EOF/)
+ end.to output(/URL to GitLab merge request that added this type of audit event:/)
+ .to_stdout.and output(/URL needs to start with https/).to_stderr
+ end
+ end
+ end
+
+ describe '.read_introduced_by_issue' do
+ let(:url) { 'https://issue' }
+
+ it 'reads type from stdin' do
+ expect(Readline).to receive(:readline).and_return(url)
+ expect do
+ expect(described_class.read_introduced_by_issue).to eq('https://issue')
+ end.to output(/URL to GitLab issue that added this type of audit event:/).to_stdout
+ end
+
+ context 'when URL is invalid' do
+ let(:type) { 'invalid' }
+
+ it 'shows error message and retries' do
+ expect(Readline).to receive(:readline).and_return(type)
+ expect(Readline).to receive(:readline).and_raise('EOF')
+
+ expect do
+ expect { described_class.read_introduced_by_issue }.to raise_error(/EOF/)
+ end.to output(/URL to GitLab issue that added this type of audit event:/)
+ .to_stdout.and output(/URL needs to start with https/).to_stderr
+ end
+ end
+ end
+
+ describe '.read_milestone' do
+ before do
+ allow(File).to receive(:read).with('VERSION').and_return('15.6.0-pre')
+ allow(File).to receive(:read).and_call_original
+ end
+
+ it 'returns the correct milestone from the VERSION file' do
+ expect(described_class.read_milestone).to eq('15.6')
+ end
+ end
+ end
+end
diff --git a/spec/components/pajamas/spinner_component_spec.rb b/spec/components/pajamas/spinner_component_spec.rb
index 9aac9a0085c..f03d8c9561b 100644
--- a/spec/components/pajamas/spinner_component_spec.rb
+++ b/spec/components/pajamas/spinner_component_spec.rb
@@ -35,7 +35,7 @@ RSpec.describe Pajamas::SpinnerComponent, type: :component do
describe 'inline' do
context 'by default' do
it 'renders a div' do
- expect(page).to have_css 'div.gl-spinner'
+ expect(page).to have_css 'div.gl-spinner-container'
end
end
@@ -43,7 +43,7 @@ RSpec.describe Pajamas::SpinnerComponent, type: :component do
let(:options) { { inline: true } }
it 'renders a span' do
- expect(page).to have_css 'span.gl-spinner'
+ expect(page).to have_css 'span.gl-spinner-container'
end
end
end
diff --git a/spec/components/previews/pajamas/alert_component_preview.rb b/spec/components/previews/pajamas/alert_component_preview.rb
index e1889032c8b..4768ef47975 100644
--- a/spec/components/previews/pajamas/alert_component_preview.rb
+++ b/spec/components/previews/pajamas/alert_component_preview.rb
@@ -4,7 +4,7 @@ module Pajamas
# @param title text
# @param body text
# @param dismissible toggle
- # @param variant select [info, warning, success, danger, tip]
+ # @param variant select {{ Pajamas::AlertComponent::VARIANT_ICONS.keys }}
def default(title: "Alert title (optional)", body: "Alert message goes here.", dismissible: true, variant: :info)
render(Pajamas::AlertComponent.new(
title: title,
diff --git a/spec/components/previews/pajamas/avatar_component_preview.rb b/spec/components/previews/pajamas/avatar_component_preview.rb
index e5cdde1ccef..147d89169b0 100644
--- a/spec/components/previews/pajamas/avatar_component_preview.rb
+++ b/spec/components/previews/pajamas/avatar_component_preview.rb
@@ -9,17 +9,17 @@ module Pajamas
end
# We show user avatars in a circle.
- # @param size select [16, 24, 32, 48, 64, 96]
+ # @param size select {{ Pajamas::AvatarComponent::SIZE_OPTIONS }}
def user(size: 64)
render(Pajamas::AvatarComponent.new(User.first, size: size))
end
- # @param size select [16, 24, 32, 48, 64, 96]
+ # @param size select {{ Pajamas::AvatarComponent::SIZE_OPTIONS }}
def project(size: 64)
render(Pajamas::AvatarComponent.new(Project.first, size: size))
end
- # @param size select [16, 24, 32, 48, 64, 96]
+ # @param size select {{ Pajamas::AvatarComponent::SIZE_OPTIONS }}
def group(size: 64)
render(Pajamas::AvatarComponent.new(Group.first, size: size))
end
diff --git a/spec/components/previews/pajamas/badge_component_preview.rb b/spec/components/previews/pajamas/badge_component_preview.rb
index e740a4a38aa..e833c4e458d 100644
--- a/spec/components/previews/pajamas/badge_component_preview.rb
+++ b/spec/components/previews/pajamas/badge_component_preview.rb
@@ -10,9 +10,9 @@ module Pajamas
# @param icon select [~, star-o, issue-closed, tanuki]
# @param icon_only toggle
# @param href url
- # @param size select [sm, md, lg]
+ # @param size select {{ Pajamas::BadgeComponent::SIZE_OPTIONS }}
# @param text text
- # @param variant select [muted, neutral, info, success, warning, danger]
+ # @param variant select {{ Pajamas::BadgeComponent::VARIANT_OPTIONS }}
def default(icon: :tanuki, icon_only: false, href: nil, size: :md, text: "Tanuki", variant: :muted)
render Pajamas::BadgeComponent.new(
text,
diff --git a/spec/components/previews/pajamas/banner_component_preview.rb b/spec/components/previews/pajamas/banner_component_preview.rb
index 861e3ff95dc..19f4f5243c0 100644
--- a/spec/components/previews/pajamas/banner_component_preview.rb
+++ b/spec/components/previews/pajamas/banner_component_preview.rb
@@ -9,7 +9,7 @@ module Pajamas
# @param button_link text
# @param content textarea
# @param embedded toggle
- # @param variant select [introduction, promotion]
+ # @param variant select {{ Pajamas::BannerComponent::VARIANT_OPTIONS }}
def default(
button_text: "Learn more",
button_link: "https://about.gitlab.com/",
diff --git a/spec/components/previews/pajamas/button_component_preview.rb b/spec/components/previews/pajamas/button_component_preview.rb
index 1f61d9cf2bc..c07d898d9cd 100644
--- a/spec/components/previews/pajamas/button_component_preview.rb
+++ b/spec/components/previews/pajamas/button_component_preview.rb
@@ -5,10 +5,10 @@ module Pajamas
# ----
# See its design reference [here](https://design.gitlab.com/components/banner).
#
- # @param category select [primary, secondary, tertiary]
- # @param variant select [default, confirm, danger, dashed, link, reset]
- # @param size select [small, medium]
- # @param type select [button, reset, submit]
+ # @param category select {{ Pajamas::ButtonComponent::CATEGORY_OPTIONS }}
+ # @param variant select {{ Pajamas::ButtonComponent::VARIANT_OPTIONS }}
+ # @param size select {{ Pajamas::ButtonComponent::SIZE_OPTIONS }}
+ # @param type select {{ Pajamas::ButtonComponent::TYPE_OPTIONS }}
# @param disabled toggle
# @param loading toggle
# @param block toggle
diff --git a/spec/components/previews/pajamas/progress_component_preview.rb b/spec/components/previews/pajamas/progress_component_preview.rb
index 4de07872a80..1562ffddf7e 100644
--- a/spec/components/previews/pajamas/progress_component_preview.rb
+++ b/spec/components/previews/pajamas/progress_component_preview.rb
@@ -7,8 +7,8 @@ module Pajamas
#
# See its design reference [here](https://design.gitlab.com/components/progress-bar).
#
- # @param value number
- # @param variant select [primary, success]
+ # @param value range { min: 0, max: 100, step: 1 }
+ # @param variant select {{ Pajamas::ProgressComponent::VARIANT_OPTIONS }}
def default(value: 50, variant: :primary)
render Pajamas::ProgressComponent.new(value: value, variant: variant)
end
diff --git a/spec/components/previews/pajamas/spinner_component_preview.rb b/spec/components/previews/pajamas/spinner_component_preview.rb
index 149bfddcfc2..34cc386763f 100644
--- a/spec/components/previews/pajamas/spinner_component_preview.rb
+++ b/spec/components/previews/pajamas/spinner_component_preview.rb
@@ -7,16 +7,30 @@ module Pajamas
#
# @param inline toggle
# @param label text
- # @param size select [[small, sm], [medium, md], [large, lg], [extra large, xl]]
+ # @param size select {{ Pajamas::SpinnerComponent::SIZE_OPTIONS }}
def default(inline: false, label: "Loading", size: :md)
- render(Pajamas::SpinnerComponent.new(inline: inline, label: label, size: size))
+ render Pajamas::SpinnerComponent.new(
+ inline: inline,
+ label: label,
+ size: size
+ )
end
- # Use a light spinner on dark backgrounds
+ # Use a light spinner on dark backgrounds.
#
- # @display bg_color "#222"
+ # @display bg_dark true
def light
render(Pajamas::SpinnerComponent.new(color: :light))
end
+
+ # Any extra HTML attributes like `class`, `data` or `id` get automatically applied to the spinner container element.
+ #
+ def extra_attributes
+ render Pajamas::SpinnerComponent.new(
+ class: "js-do-something",
+ data: { foo: "bar" },
+ id: "my-special-spinner"
+ )
+ end
end
end
diff --git a/spec/config/inject_enterprise_edition_module_spec.rb b/spec/config/inject_enterprise_edition_module_spec.rb
index 6ef74a2b616..96fc26fc80a 100644
--- a/spec/config/inject_enterprise_edition_module_spec.rb
+++ b/spec/config/inject_enterprise_edition_module_spec.rb
@@ -126,4 +126,22 @@ RSpec.describe InjectEnterpriseEditionModule do
describe '#include_mod' do
it_behaves_like 'expand the assumed extension with', :include
end
+
+ describe '#gitlab_extensions' do
+ context 'when there are no extension modules' do
+ it 'returns the class itself' do
+ expect(fish_class.gitlab_extensions).to contain_exactly(fish_class)
+ end
+ end
+
+ context 'when there are extension modules' do
+ it 'returns the class itself and any extensions' do
+ stub_const(extension_name, extension_namespace)
+ extension_namespace.const_set(fish_name, fish_extension)
+ fish_class.prepend_mod
+
+ expect(fish_class.gitlab_extensions).to contain_exactly(fish_class, fish_extension)
+ end
+ end
+ end
end
diff --git a/spec/config/metrics/aggregates/aggregated_metrics_spec.rb b/spec/config/metrics/aggregates/aggregated_metrics_spec.rb
deleted file mode 100644
index 1984aff01db..00000000000
--- a/spec/config/metrics/aggregates/aggregated_metrics_spec.rb
+++ /dev/null
@@ -1,95 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'aggregated metrics' do
- RSpec::Matchers.define :be_known_event do
- match do |event|
- Gitlab::UsageDataCounters::HLLRedisCounter.known_event?(event)
- end
-
- failure_message do |event|
- "Event with name: `#{event}` can not be found within `#{Gitlab::UsageDataCounters::HLLRedisCounter::KNOWN_EVENTS_PATH}`"
- end
- end
-
- RSpec::Matchers.define :has_known_source do
- match do |aggregate|
- Gitlab::Usage::Metrics::Aggregates::SOURCES.include?(aggregate[:source])
- end
-
- failure_message do |aggregate|
- "Aggregate with name: `#{aggregate[:name]}` uses not allowed source `#{aggregate[:source]}`"
- end
- end
-
- RSpec::Matchers.define :have_known_time_frame do
- allowed_time_frames = [
- Gitlab::Usage::TimeFrame::ALL_TIME_TIME_FRAME_NAME,
- Gitlab::Usage::TimeFrame::TWENTY_EIGHT_DAYS_TIME_FRAME_NAME,
- Gitlab::Usage::TimeFrame::SEVEN_DAYS_TIME_FRAME_NAME
- ]
-
- match do |aggregate|
- (aggregate[:time_frame] - allowed_time_frames).empty?
- end
-
- failure_message do |aggregate|
- "Aggregate with name: `#{aggregate[:name]}` uses not allowed time_frame`#{aggregate[:time_frame] - allowed_time_frames}`"
- end
- end
-
- let_it_be(:known_events) do
- Gitlab::UsageDataCounters::HLLRedisCounter.known_events
- end
-
- Gitlab::Usage::Metrics::Aggregates::Aggregate.new(Time.current).send(:aggregated_metrics).tap do |aggregated_metrics|
- it 'all events has unique name' do
- event_names = aggregated_metrics&.map { |event| event[:name] }
-
- expect(event_names).to eq(event_names&.uniq)
- end
-
- it 'all aggregated metrics has known source' do
- expect(aggregated_metrics).to all has_known_source
- end
-
- it 'all aggregated metrics has known time frame' do
- expect(aggregated_metrics).to all have_known_time_frame
- end
-
- aggregated_metrics&.select { |agg| agg[:source] == Gitlab::Usage::Metrics::Aggregates::REDIS_SOURCE }&.each do |aggregate|
- context "for #{aggregate[:name]} aggregate of #{aggregate[:events].join(' ')}" do
- let_it_be(:events_records) { known_events.select { |event| aggregate[:events].include?(event[:name]) } }
-
- it "does not include 'all' time frame for Redis sourced aggregate" do
- expect(aggregate[:time_frame]).not_to include(Gitlab::Usage::TimeFrame::ALL_TIME_TIME_FRAME_NAME)
- end
-
- it "only refers to known events", :skip do
- expect(aggregate[:events]).to all be_known_event
- end
-
- it "has expected structure" do
- expect(aggregate.keys).to include(*%w[name operator events])
- end
-
- it "uses allowed aggregation operators" do
- expect(Gitlab::Usage::Metrics::Aggregates::ALLOWED_METRICS_AGGREGATIONS).to include aggregate[:operator]
- end
-
- it "uses events from the same Redis slot" do
- event_slots = events_records.map { |event| event[:redis_slot] }.uniq
-
- expect(event_slots).to contain_exactly(be_present)
- end
-
- it "uses events with the same aggregation period" do
- event_slots = events_records.map { |event| event[:aggregation] }.uniq
-
- expect(event_slots).to contain_exactly(be_present)
- end
- end
- end
- end
-end
diff --git a/spec/contracts/contracts/project/pipeline/index/pipelines#index-get_list_project_pipelines.json b/spec/contracts/contracts/project/pipeline/index/pipelines#index-get_list_project_pipelines.json
index b725ae400a7..2ebfd1bfdf2 100644
--- a/spec/contracts/contracts/project/pipeline/index/pipelines#index-get_list_project_pipelines.json
+++ b/spec/contracts/contracts/project/pipeline/index/pipelines#index-get_list_project_pipelines.json
@@ -198,6 +198,9 @@
"match": "regex",
"regex": "^(push|web|trigger|schedule|api|external|pipeline|chat|webide|merge_request_event|external_pull_request_event|parent_pipeline|ondemand_dast_scan|ondemand_dast_validation)$"
},
+ "$.body.pipelines[*].name": {
+ "match": "type"
+ },
"$.body.pipelines[*].created_at": {
"match": "regex",
"regex": "^\\d{4}-[01]\\d-[0-3]\\dT[0-2]\\d:[0-5]\\d:[0-5]\\d\\.\\d+([+-][0-2]\\d(:?[0-5]\\d)?|Z)$"
@@ -335,6 +338,9 @@
"$.body.pipelines[*].details.name": {
"match": "type"
},
+ "$.body.pipelines[*].details.event_type_name": {
+ "match": "type"
+ },
"$.body.pipelines[*].details.manual_actions": {
"min": 1
},
diff --git a/spec/contracts/provider/helpers/publish_contract_helper.rb b/spec/contracts/provider/helpers/publish_contract_helper.rb
new file mode 100644
index 00000000000..102a73d87ee
--- /dev/null
+++ b/spec/contracts/provider/helpers/publish_contract_helper.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Provider
+ module PublishContractHelper
+ PROVIDER_VERSION = ENV['GIT_COMMIT'] || `git rev-parse --verify HEAD`.strip
+ PROVIDER_BRANCH = ENV['GIT_BRANCH'] || `git name-rev --name-only HEAD`.strip
+ PUBLISH_FLAG = true
+
+ def self.publish_contract_setup
+ @setup ||= -> {
+ app_version PROVIDER_VERSION
+ app_version_branch PROVIDER_BRANCH
+ publish_verification_results PUBLISH_FLAG
+ }
+ end
+ end
+end
diff --git a/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_batch_helper.rb b/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_batch_helper.rb
index f94ce47b1f3..71f302f2c44 100644
--- a/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_batch_helper.rb
+++ b/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_batch_helper.rb
@@ -11,6 +11,8 @@ module Provider
honours_pact_with 'MergeRequest#show' do
pact_uri '../contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_batch_endpoint.json'
end
+
+ Provider::PublishContractHelper.publish_contract_setup.call
end
end
end
diff --git a/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_metadata_helper.rb b/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_metadata_helper.rb
index 61567214b7a..60a3abea5ae 100644
--- a/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_metadata_helper.rb
+++ b/spec/contracts/provider/pact_helpers/project/merge_request/show/diffs_metadata_helper.rb
@@ -11,6 +11,10 @@ module Provider
honours_pact_with 'MergeRequest#show' do
pact_uri '../contracts/project/merge_request/show/mergerequest#show-merge_request_diffs_metadata_endpoint.json'
end
+
+ app_version Provider::PublishContractHelper::PROVIDER_VERSION
+ app_version_branch Provider::PublishContractHelper::PROVIDER_BRANCH
+ publish_verification_results Provider::PublishContractHelper::PUBLISH_FLAG
end
end
end
diff --git a/spec/contracts/provider/pact_helpers/project/merge_request/show/discussions_helper.rb b/spec/contracts/provider/pact_helpers/project/merge_request/show/discussions_helper.rb
index fa76ce8889a..b9308af0a1a 100644
--- a/spec/contracts/provider/pact_helpers/project/merge_request/show/discussions_helper.rb
+++ b/spec/contracts/provider/pact_helpers/project/merge_request/show/discussions_helper.rb
@@ -11,6 +11,10 @@ module Provider
honours_pact_with 'MergeRequest#show' do
pact_uri '../contracts/project/merge_request/show/mergerequest#show-merge_request_discussions_endpoint.json'
end
+
+ app_version Provider::PublishContractHelper::PROVIDER_VERSION
+ app_version_branch Provider::PublishContractHelper::PROVIDER_BRANCH
+ publish_verification_results Provider::PublishContractHelper::PUBLISH_FLAG
end
end
end
diff --git a/spec/contracts/provider/pact_helpers/project/pipeline/index/create_a_new_pipeline_helper.rb b/spec/contracts/provider/pact_helpers/project/pipeline/index/create_a_new_pipeline_helper.rb
index 247a7c4ca8e..2af960bc9fd 100644
--- a/spec/contracts/provider/pact_helpers/project/pipeline/index/create_a_new_pipeline_helper.rb
+++ b/spec/contracts/provider/pact_helpers/project/pipeline/index/create_a_new_pipeline_helper.rb
@@ -11,6 +11,10 @@ module Provider
honours_pact_with 'Pipelines#new' do
pact_uri '../contracts/project/pipeline/new/pipelines#new-post_create_a_new_pipeline.json'
end
+
+ app_version Provider::PublishContractHelper::PROVIDER_VERSION
+ app_version_branch Provider::PublishContractHelper::PROVIDER_BRANCH
+ publish_verification_results Provider::PublishContractHelper::PUBLISH_FLAG
end
end
end
diff --git a/spec/contracts/provider/pact_helpers/project/pipeline/index/get_list_project_pipelines_helper.rb b/spec/contracts/provider/pact_helpers/project/pipeline/index/get_list_project_pipelines_helper.rb
index 80cbbe3b4dd..37cddd1b80e 100644
--- a/spec/contracts/provider/pact_helpers/project/pipeline/index/get_list_project_pipelines_helper.rb
+++ b/spec/contracts/provider/pact_helpers/project/pipeline/index/get_list_project_pipelines_helper.rb
@@ -11,6 +11,10 @@ module Provider
honours_pact_with 'Pipelines#index' do
pact_uri '../contracts/project/project/pipeline/index/pipelines#index-get_list_project_pipelines.json'
end
+
+ app_version Provider::PublishContractHelper::PROVIDER_VERSION
+ app_version_branch Provider::PublishContractHelper::PROVIDER_BRANCH
+ publish_verification_results Provider::PublishContractHelper::PUBLISH_FLAG
end
end
end
diff --git a/spec/contracts/provider/pact_helpers/project/pipeline/show/delete_pipeline_helper.rb b/spec/contracts/provider/pact_helpers/project/pipeline/show/delete_pipeline_helper.rb
index 2d29fabfeca..0455281fcd7 100644
--- a/spec/contracts/provider/pact_helpers/project/pipeline/show/delete_pipeline_helper.rb
+++ b/spec/contracts/provider/pact_helpers/project/pipeline/show/delete_pipeline_helper.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require_relative '../../../../spec_helper'
+require_relative '../../../../helpers/publish_contract_helper'
require_relative '../../../../states/project/pipeline/show_state'
module Provider
@@ -11,6 +12,10 @@ module Provider
honours_pact_with 'Pipelines#show' do
pact_uri '../contracts/project/pipeline/show/pipelines#show-delete_pipeline.json'
end
+
+ app_version Provider::PublishContractHelper::PROVIDER_VERSION
+ app_version_branch Provider::PublishContractHelper::PROVIDER_BRANCH
+ publish_verification_results Provider::PublishContractHelper::PUBLISH_FLAG
end
end
end
diff --git a/spec/contracts/provider/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb b/spec/contracts/provider/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb
index bc8c04cc455..bce1c4ab3f4 100644
--- a/spec/contracts/provider/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb
+++ b/spec/contracts/provider/pact_helpers/project/pipeline/show/get_pipeline_header_data_helper.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require_relative '../../../../spec_helper'
+require_relative '../../../../helpers/publish_contract_helper'
require_relative '../../../../states/project/pipeline/show_state'
module Provider
@@ -10,7 +11,12 @@ module Provider
honours_pact_with 'Pipelines#show' do
pact_uri '../contracts/project/pipeline/show/pipelines#show-get_project_pipeline_header_data.json'
+ # pact_uri 'http://localhost:9292/pacts/provider/GET%20pipeline%20header%20data/consumer/Pipelines%23show/latest'
end
+
+ app_version Provider::PublishContractHelper::PROVIDER_VERSION
+ app_version_branch Provider::PublishContractHelper::PROVIDER_BRANCH
+ publish_verification_results Provider::PublishContractHelper::PUBLISH_FLAG
end
end
end
diff --git a/spec/contracts/provider/pact_helpers/project/pipeline_schedule/update_pipeline_schedule_helper.rb b/spec/contracts/provider/pact_helpers/project/pipeline_schedule/update_pipeline_schedule_helper.rb
index a83aa9524dc..d95a09abd8d 100644
--- a/spec/contracts/provider/pact_helpers/project/pipeline_schedule/update_pipeline_schedule_helper.rb
+++ b/spec/contracts/provider/pact_helpers/project/pipeline_schedule/update_pipeline_schedule_helper.rb
@@ -11,6 +11,10 @@ module Provider
honours_pact_with 'PipelineSchedule#edit' do
pact_uri '../contracts/project/pipeline_schedule/edit/pipelineschedules#edit-put_edit_a_pipeline_schedule.json'
end
+
+ app_version Provider::PublishContractHelper::PROVIDER_VERSION
+ app_version_branch Provider::PublishContractHelper::PROVIDER_BRANCH
+ publish_verification_results Provider::PublishContractHelper::PUBLISH_FLAG
end
end
end
diff --git a/spec/contracts/publish-contracts.sh b/spec/contracts/publish-contracts.sh
new file mode 100644
index 00000000000..f20cc43e258
--- /dev/null
+++ b/spec/contracts/publish-contracts.sh
@@ -0,0 +1,23 @@
+LATEST_SHA=$(git rev-parse HEAD)
+GIT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
+BROKER_BASE_URL="http://localhost:9292"
+
+CONTRACTS=$(find ./contracts -name "*.json")
+ERROR=0
+
+trap 'catch' ERR
+
+function catch() {
+ printf "\e[31mAn error occured while trying to publish the pact.\033[0m\n"
+ ERROR=1
+}
+
+for contract in $CONTRACTS
+do
+ printf "\e[32mPublishing ${contract}...\033[0m\n"
+ pact-broker publish $contract --consumer-app-version $LATEST_SHA --branch $GIT_BRANCH --broker-base-url $BROKER_BASE_URL --output json
+done
+
+if [ ${ERROR} = 1 ]; then
+ exit 1;
+fi \ No newline at end of file
diff --git a/spec/controllers/admin/groups_controller_spec.rb b/spec/controllers/admin/groups_controller_spec.rb
index 37cb0a1f289..6085f0e1239 100644
--- a/spec/controllers/admin/groups_controller_spec.rb
+++ b/spec/controllers/admin/groups_controller_spec.rb
@@ -43,5 +43,13 @@ RSpec.describe Admin::GroupsController do
post :create, params: { group: { path: 'test', name: 'test', admin_note_attributes: { note: 'test' } } }
end.to change { Namespace::AdminNote.count }.by(1)
end
+
+ it 'delegates to Groups::CreateService service instance' do
+ expect_next_instance_of(::Groups::CreateService) do |service|
+ expect(service).to receive(:execute).once.and_call_original
+ end
+
+ post :create, params: { group: { path: 'test', name: 'test' } }
+ end
end
end
diff --git a/spec/controllers/admin/hooks_controller_spec.rb b/spec/controllers/admin/hooks_controller_spec.rb
index 14f4a2f40e7..82e4b873bf6 100644
--- a/spec/controllers/admin/hooks_controller_spec.rb
+++ b/spec/controllers/admin/hooks_controller_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Admin::HooksController do
- let(:admin) { create(:admin) }
+ let_it_be(:admin) { create(:admin) }
before do
sign_in(admin)
@@ -33,7 +33,23 @@ RSpec.describe Admin::HooksController do
end
describe 'POST #update' do
- let!(:hook) { create(:system_hook) }
+ let_it_be_with_reload(:hook) { create(:system_hook) }
+
+ context 'with an existing token' do
+ hook_params = {
+ token: WebHook::SECRET_MASK,
+ url: "http://example.com"
+ }
+
+ it 'does not change a token' do
+ expect do
+ post :update, params: { id: hook.id, hook: hook_params }
+ end.not_to change { hook.reload.token }
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(flash[:alert]).to be_blank
+ end
+ end
it 'sets all parameters' do
hook.update!(url_variables: { 'foo' => 'bar', 'baz' => 'woo' })
@@ -61,8 +77,8 @@ RSpec.describe Admin::HooksController do
end
describe 'DELETE #destroy' do
- let!(:hook) { create(:system_hook) }
- let!(:log) { create(:web_hook_log, web_hook: hook) }
+ let_it_be(:hook) { create(:system_hook) }
+ let_it_be(:log) { create(:web_hook_log, web_hook: hook) }
let(:params) { { id: hook } }
it_behaves_like 'Web hook destroyer'
diff --git a/spec/controllers/admin/integrations_controller_spec.rb b/spec/controllers/admin/integrations_controller_spec.rb
index 0e456858b49..e75f27589d7 100644
--- a/spec/controllers/admin/integrations_controller_spec.rb
+++ b/spec/controllers/admin/integrations_controller_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe Admin::IntegrationsController do
describe '#edit' do
Integration.available_integration_names.each do |integration_name|
- context "#{integration_name}" do
+ context integration_name.to_s do
it 'successfully displays the template' do
get :edit, params: { id: integration_name }
diff --git a/spec/controllers/admin/spam_logs_controller_spec.rb b/spec/controllers/admin/spam_logs_controller_spec.rb
index 48221f496fb..51f7ecdece6 100644
--- a/spec/controllers/admin/spam_logs_controller_spec.rb
+++ b/spec/controllers/admin/spam_logs_controller_spec.rb
@@ -27,34 +27,17 @@ RSpec.describe Admin::SpamLogsController do
expect(response).to have_gitlab_http_status(:ok)
end
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- it 'initiates user removal', :sidekiq_inline do
- expect do
- delete :destroy, params: { id: first_spam.id, remove_user: true }
- 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(flash[:notice]).to eq("User #{user.username} was successfully removed.")
- end
- end
-
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
- end
-
- it 'removes user and their spam logs when removing the user', :sidekiq_inline do
+ it 'initiates user removal', :sidekiq_inline do
+ expect do
delete :destroy, params: { id: first_spam.id, remove_user: true }
+ end.not_to change { SpamLog.count }
- expect(flash[:notice]).to eq "User #{user.username} was successfully removed."
- expect(response).to have_gitlab_http_status(:found)
- expect(SpamLog.count).to eq(0)
- expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound)
- end
+ expect(response).to have_gitlab_http_status(:found)
+ 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/topics_controller_spec.rb b/spec/controllers/admin/topics_controller_spec.rb
index 111fdcc3be6..e640f8bb7ec 100644
--- a/spec/controllers/admin/topics_controller_spec.rb
+++ b/spec/controllers/admin/topics_controller_spec.rb
@@ -176,7 +176,7 @@ RSpec.describe Admin::TopicsController do
describe 'POST #merge' do
let_it_be(:source_topic) { create(:topic, name: 'source_topic') }
- let_it_be(:project) { create(:project, topic_list: source_topic.name ) }
+ let_it_be(:project) { create(:project, topic_list: source_topic.name) }
it 'merges source topic into target topic' do
post :merge, params: { source_topic_id: source_topic.id, target_topic_id: topic.id }
diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb
index 682399f4dd9..eecb803fb1a 100644
--- a/spec/controllers/admin/users_controller_spec.rb
+++ b/spec/controllers/admin/users_controller_spec.rb
@@ -63,130 +63,179 @@ RSpec.describe Admin::UsersController do
expect(response).to be_redirect
expect(response.location).to end_with(user.username)
end
- end
- describe 'DELETE #destroy', :sidekiq_might_not_need_inline do
- let(:project) { create(:project, namespace: user.namespace) }
- let!(:issue) { create(:issue, author: user) }
+ describe 'impersonation_error_text' do
+ context 'when user can be impersonated' do
+ it 'sets impersonation_error_text to nil' do
+ get :show, params: { id: user.username.downcase }
- before do
- project.add_developer(user)
- end
+ expect(assigns(:impersonation_error_text)).to eq(nil)
+ end
+ end
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- it 'initiates user removal' do
- delete :destroy, params: { id: user.username }, format: :json
+ context 'when impersonation is already in progress' do
+ let(:admin2) { create(:admin) }
- expect(response).to have_gitlab_http_status(:ok)
- expect(
- Users::GhostUserMigration.where(user: user,
- initiator_user: admin,
- hard_delete: false)
- ).to be_exists
+ before do
+ post :impersonate, params: { id: admin2.username }
+ end
+
+ it 'sets impersonation_error_text' do
+ get :show, params: { id: user.username.downcase }
+
+ expect(assigns(:impersonation_error_text)).to eq(_("You are already impersonating another user"))
+ end
end
- it 'initiates user removal and passes hard delete option' do
- delete :destroy, params: { id: user.username, hard_delete: true }, format: :json
+ context 'when user is blocked' do
+ before do
+ user.block
+ end
- expect(response).to have_gitlab_http_status(:ok)
- expect(
- Users::GhostUserMigration.where(user: user,
- initiator_user: admin,
- hard_delete: true)
- ).to be_exists
+ it 'sets impersonation_error_text' do
+ get :show, params: { id: user.username.downcase }
+
+ expect(assigns(:impersonation_error_text)).to eq(_("You cannot impersonate a blocked user"))
+ end
end
- context 'prerequisites for account deletion' do
- context 'solo-owned groups' do
- let(:group) { create(:group) }
+ context "when the user's password is expired" do
+ before do
+ user.update!(password_expires_at: 1.day.ago)
+ end
- context 'if the user is the sole owner of at least one group' do
- before do
- create(:group_member, :owner, group: group, user: user)
- end
+ it 'sets impersonation_error_text' do
+ get :show, params: { id: user.username.downcase }
+
+ expect(assigns(:impersonation_error_text)).to eq(_("You cannot impersonate a user with an expired password"))
+ end
+ end
- context 'soft-delete' do
- it 'fails' do
- delete :destroy, params: { id: user.username }
+ context "when the user is internal" do
+ before do
+ user.update!(user_type: :migration_bot)
+ end
- message = s_('AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account')
+ it 'sets impersonation_error_text' do
+ get :show, params: { id: user.username.downcase }
- expect(flash[:alert]).to eq(message)
- expect(response).to have_gitlab_http_status(:see_other)
- expect(response).to redirect_to admin_user_path(user)
- expect(Users::GhostUserMigration).not_to exist
- end
- end
+ expect(assigns(:impersonation_error_text)).to eq(_("You cannot impersonate an internal user"))
+ end
+ end
- context 'hard-delete' do
- it 'succeeds' do
- delete :destroy, params: { id: user.username, hard_delete: true }
-
- 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
- end
- end
- end
+ context "when the user is a project bot" do
+ before do
+ user.update!(user_type: :project_bot)
+ end
+
+ it 'sets impersonation_error_text' do
+ get :show, params: { id: user.username.downcase }
+
+ expect(assigns(:impersonation_error_text)).to eq(_("You cannot impersonate a user who cannot log in"))
end
end
end
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
+ describe 'can_impersonate' do
+ context 'when user can be impersonated' do
+ it 'sets can_impersonate to true' do
+ get :show, params: { id: user.username.downcase }
+
+ expect(assigns(:can_impersonate)).to eq(true)
+ end
end
- it 'deletes user and ghosts their contributions' do
- delete :destroy, params: { id: user.username }, format: :json
+ context 'when impersonation is already in progress' do
+ let(:admin2) { create(:admin) }
- expect(response).to have_gitlab_http_status(:ok)
- expect(User.exists?(user.id)).to be_falsy
- expect(issue.reload.author).to be_ghost
+ before do
+ post :impersonate, params: { id: admin2.username }
+ end
+
+ it 'sets can_impersonate to false' do
+ get :show, params: { id: user.username.downcase }
+
+ expect(assigns(:can_impersonate)).to eq(false)
+ end
end
- it 'deletes the user and their contributions when hard delete is specified' do
- delete :destroy, params: { id: user.username, hard_delete: true }, format: :json
+ context 'when user cannot log in' do
+ before do
+ user.update!(user_type: :project_bot)
+ end
+
+ it 'sets can_impersonate to false' do
+ get :show, params: { id: user.username.downcase }
- expect(response).to have_gitlab_http_status(:ok)
- expect(User.exists?(user.id)).to be_falsy
- expect(Issue.exists?(issue.id)).to be_falsy
+ expect(assigns(:can_impersonate)).to eq(false)
+ end
end
+ end
+ end
- context 'prerequisites for account deletion' do
- context 'solo-owned groups' do
- let(:group) { create(:group) }
+ describe 'DELETE #destroy', :sidekiq_might_not_need_inline do
+ let(:project) { create(:project, namespace: user.namespace) }
+ let!(:issue) { create(:issue, author: user) }
- context 'if the user is the sole owner of at least one group' do
- before do
- create(:group_member, :owner, group: group, user: user)
- end
+ before do
+ project.add_developer(user)
+ end
- context 'soft-delete' do
- it 'fails' do
- delete :destroy, params: { id: user.username }
+ it 'initiates user removal' do
+ delete :destroy, params: { id: user.username }, format: :json
- message = s_('AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account')
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(
+ Users::GhostUserMigration.where(user: user,
+ initiator_user: admin,
+ hard_delete: false)
+ ).to be_exists
+ end
- expect(flash[:alert]).to eq(message)
- expect(response).to have_gitlab_http_status(:see_other)
- expect(response).to redirect_to admin_user_path(user)
- expect(User.exists?(user.id)).to be_truthy
- end
- 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
+ end
- context 'hard-delete' do
- it 'succeeds' do
- delete :destroy, params: { id: user.username, hard_delete: true }
+ context 'prerequisites for account deletion' do
+ context 'solo-owned groups' do
+ let(:group) { create(:group) }
+
+ context 'if the user is the sole owner of at least one group' do
+ before do
+ create(:group_member, :owner, group: group, user: user)
+ end
+
+ context 'soft-delete' do
+ it 'fails' do
+ delete :destroy, params: { id: user.username }
+
+ message = s_('AdminUsers|You must transfer ownership or delete the groups owned by this user before you can delete their account')
+
+ expect(flash[:alert]).to eq(message)
+ expect(response).to have_gitlab_http_status(:see_other)
+ expect(response).to redirect_to admin_user_path(user)
+ expect(Users::GhostUserMigration).not_to exist
+ end
+ end
- expect(response).to redirect_to(admin_users_path)
- expect(flash[:notice]).to eq(_('The user is being deleted.'))
- expect(User.exists?(user.id)).to be_falsy
- end
+ context 'hard-delete' do
+ it 'succeeds' do
+ delete :destroy, params: { id: user.username, hard_delete: true }
+
+ 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
end
end
end
@@ -200,27 +249,13 @@ RSpec.describe Admin::UsersController do
context 'when rejecting a pending user' do
let(:user) { create(:user, :blocked_pending_approval) }
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- it 'initiates user removal', :sidekiq_inline do
- subject
-
- expect(
- Users::GhostUserMigration.where(user: user,
- initiator_user: admin)
- ).to be_exists
- end
- end
-
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
- end
-
- it 'hard deletes the user', :sidekiq_inline do
- subject
+ it 'initiates user removal', :sidekiq_inline do
+ subject
- expect(User.exists?(user.id)).to be_falsy
- end
+ expect(
+ Users::GhostUserMigration.where(user: user,
+ initiator_user: admin)
+ ).to be_exists
end
it 'displays the rejection message' do
@@ -909,6 +944,60 @@ RSpec.describe Admin::UsersController do
expect(session[:github_access_token]).to be_nil
end
+
+ context "when the user's password is expired" do
+ before do
+ user.update!(password_expires_at: 1.day.ago)
+ end
+
+ it "shows a notice" do
+ post :impersonate, params: { id: user.username }
+
+ expect(flash[:alert]).to eq(_('You cannot impersonate a user with an expired password'))
+ end
+
+ it "doesn't sign us in as the user" do
+ post :impersonate, params: { id: user.username }
+
+ expect(warden.user).to eq(admin)
+ end
+ end
+
+ context "when the user is internal" do
+ before do
+ user.update!(user_type: :migration_bot)
+ end
+
+ it "shows a notice" do
+ post :impersonate, params: { id: user.username }
+
+ expect(flash[:alert]).to eq(_("You cannot impersonate an internal user"))
+ end
+
+ it "doesn't sign us in as the user" do
+ post :impersonate, params: { id: user.username }
+
+ expect(warden.user).to eq(admin)
+ end
+ end
+
+ context "when the user is a project bot" do
+ before do
+ user.update!(user_type: :project_bot)
+ end
+
+ it "shows a notice" do
+ post :impersonate, params: { id: user.username }
+
+ expect(flash[:alert]).to eq(_("You cannot impersonate a user who cannot log in"))
+ end
+
+ it "doesn't sign us in as the user" do
+ post :impersonate, params: { id: user.username }
+
+ expect(warden.user).to eq(admin)
+ end
+ end
end
context "when impersonation is disabled" do
diff --git a/spec/controllers/concerns/issuable_actions_spec.rb b/spec/controllers/concerns/issuable_actions_spec.rb
index c3fef591b91..37d9dc080e1 100644
--- a/spec/controllers/concerns/issuable_actions_spec.rb
+++ b/spec/controllers/concerns/issuable_actions_spec.rb
@@ -6,8 +6,8 @@ RSpec.describe IssuableActions do
let(:project) { double('project') }
let(:user) { double('user') }
let(:issuable) { double('issuable') }
- let(:finder_params_for_issuable) { {} }
- let(:notes_result) { double('notes_result') }
+ let(:finder_params_for_issuable) { { project: project, target: issuable } }
+ let(:notes_result) { [] }
let(:discussion_serializer) { double('discussion_serializer') }
let(:controller) do
@@ -55,13 +55,20 @@ RSpec.describe IssuableActions do
end
it 'instantiates and calls NotesFinder as expected' do
+ expect(issuable).to receive(:to_ability_name).and_return('issue')
+ expect(issuable).to receive(:project).and_return(project)
+ expect(Ability).to receive(:allowed?).at_least(1).and_return(true)
expect(Discussion).to receive(:build_collection).and_return([])
expect(DiscussionSerializer).to receive(:new).and_return(discussion_serializer)
expect(NotesFinder).to receive(:new).with(user, finder_params_for_issuable).and_call_original
expect_any_instance_of(NotesFinder).to receive(:execute).and_return(notes_result)
- expect(notes_result).to receive_messages(inc_relations_for_view: notes_result, includes: notes_result, fresh: notes_result)
+ expect(notes_result).to receive_messages(
+ with_web_entity_associations: notes_result,
+ inc_relations_for_view: notes_result,
+ fresh: notes_result
+ )
controller.discussions
end
diff --git a/spec/controllers/concerns/preferred_language_switcher_spec.rb b/spec/controllers/concerns/preferred_language_switcher_spec.rb
new file mode 100644
index 00000000000..40d6ac10c37
--- /dev/null
+++ b/spec/controllers/concerns/preferred_language_switcher_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe PreferredLanguageSwitcher, type: :controller do
+ controller(ActionController::Base) do
+ include PreferredLanguageSwitcher # rubocop:disable RSpec/DescribedClass
+
+ before_action :init_preferred_language, only: :new
+
+ def new
+ render html: 'new page'
+ end
+ end
+
+ context 'when first visit' do
+ before do
+ get :new
+ end
+
+ it 'sets preferred_language to default' do
+ expect(cookies[:preferred_language]).to eq Gitlab::CurrentSettings.default_preferred_language
+ end
+ end
+
+ context 'when preferred language in cookies has been modified' do
+ let(:user_preferred_language) { nil }
+
+ before do
+ cookies[:preferred_language] = user_preferred_language
+
+ get :new
+ end
+
+ context 'with a valid value' do
+ let(:user_preferred_language) { 'zh_CN' }
+
+ it 'keeps preferred language unchanged' do
+ expect(cookies[:preferred_language]).to eq user_preferred_language
+ end
+ end
+
+ context 'with an invalid value' do
+ let(:user_preferred_language) { 'xxx' }
+
+ it 'sets preferred_language to default' do
+ expect(cookies[:preferred_language]).to eq Gitlab::CurrentSettings.default_preferred_language
+ end
+ end
+ end
+end
diff --git a/spec/controllers/concerns/renders_commits_spec.rb b/spec/controllers/concerns/renders_commits_spec.rb
index acdeb98bb16..6a504681527 100644
--- a/spec/controllers/concerns/renders_commits_spec.rb
+++ b/spec/controllers/concerns/renders_commits_spec.rb
@@ -43,7 +43,7 @@ RSpec.describe RendersCommits do
context 'rendering commits' do
render_views
- it 'avoids N + 1' do
+ it 'avoids N + 1', :request_store do
stub_const("MergeRequestDiff::COMMITS_SAFE_SIZE", 5)
control_count = ActiveRecord::QueryRecorder.new do
@@ -59,7 +59,7 @@ RSpec.describe RendersCommits do
end
describe '.prepare_commits_for_rendering' do
- it 'avoids N+1' do
+ it 'avoids N+1', :request_store do
control = ActiveRecord::QueryRecorder.new do
subject.prepare_commits_for_rendering(merge_request.commits.take(1))
end
diff --git a/spec/controllers/concerns/send_file_upload_spec.rb b/spec/controllers/concerns/send_file_upload_spec.rb
index 32304815bbb..0b24387483b 100644
--- a/spec/controllers/concerns/send_file_upload_spec.rb
+++ b/spec/controllers/concerns/send_file_upload_spec.rb
@@ -18,6 +18,12 @@ RSpec.describe SendFileUpload do
end
end
+ let(:cdn_uploader_class) do
+ Class.new(uploader_class) do
+ include ObjectStorage::CDN::Concern
+ end
+ end
+
let(:controller_class) do
Class.new do
include SendFileUpload
@@ -269,5 +275,28 @@ RSpec.describe SendFileUpload do
it_behaves_like 'handles image resize requests'
end
+
+ context 'when CDN-enabled remote file is used' do
+ let(:uploader) { cdn_uploader_class.new(object, :file) }
+ let(:request) { instance_double('ActionDispatch::Request', remote_ip: '18.245.0.42') }
+ let(:signed_url) { 'https://cdn.example.org.test' }
+ let(:cdn_provider) { instance_double('ObjectStorage::CDN::GoogleCDN', signed_url: signed_url) }
+
+ before do
+ stub_uploads_object_storage(uploader: cdn_uploader_class)
+ uploader.object_store = ObjectStorage::Store::REMOTE
+ uploader.store!(temp_file)
+ allow(Gitlab.config.uploads.object_store).to receive(:proxy_download) { false }
+ end
+
+ it 'sends a file when CDN URL' do
+ expect(uploader).to receive(:use_cdn?).and_return(true)
+ expect(uploader).to receive(:cdn_provider).and_return(cdn_provider)
+ expect(controller).to receive(:request).and_return(request)
+ expect(controller).to receive(:redirect_to).with(signed_url)
+
+ subject
+ end
+ end
end
end
diff --git a/spec/controllers/confirmations_controller_spec.rb b/spec/controllers/confirmations_controller_spec.rb
index 111bfb24c7e..773a416dcb4 100644
--- a/spec/controllers/confirmations_controller_spec.rb
+++ b/spec/controllers/confirmations_controller_spec.rb
@@ -10,17 +10,27 @@ RSpec.describe ConfirmationsController do
end
describe '#show' do
+ let_it_be_with_reload(:user) { create(:user, :unconfirmed) }
+ let(:confirmation_token) { user.confirmation_token }
+
render_views
def perform_request
get :show, params: { confirmation_token: confirmation_token }
end
- context 'user is already confirmed' do
- let_it_be_with_reload(:user) { create(:user, :unconfirmed) }
+ context 'when signup info is required' do
+ before do
+ allow(controller).to receive(:current_user) { user }
+ user.set_role_required!
+ end
- let(:confirmation_token) { user.confirmation_token }
+ it 'does not redirect' do
+ expect(perform_request).not_to redirect_to(users_sign_up_welcome_path)
+ end
+ end
+ context 'user is already confirmed' do
before do
user.confirm
end
@@ -57,10 +67,6 @@ RSpec.describe ConfirmationsController do
end
context 'user accesses the link after the expiry of confirmation token has passed' do
- let_it_be_with_reload(:user) { create(:user, :unconfirmed) }
-
- let(:confirmation_token) { user.confirmation_token }
-
before do
allow(Devise).to receive(:confirm_within).and_return(1.day)
end
@@ -133,6 +139,17 @@ RSpec.describe ConfirmationsController do
stub_feature_flags(identity_verification: false)
end
+ context 'when signup info is required' do
+ before do
+ allow(controller).to receive(:current_user) { user }
+ user.set_role_required!
+ end
+
+ it 'does not redirect' do
+ expect(perform_request).not_to redirect_to(users_sign_up_welcome_path)
+ end
+ end
+
context 'when reCAPTCHA is disabled' do
before do
stub_application_setting(recaptcha_enabled: false)
diff --git a/spec/controllers/dashboard_controller_spec.rb b/spec/controllers/dashboard_controller_spec.rb
index 21810f64cb4..ea12b0c5ad7 100644
--- a/spec/controllers/dashboard_controller_spec.rb
+++ b/spec/controllers/dashboard_controller_spec.rb
@@ -41,20 +41,6 @@ RSpec.describe DashboardController do
expect(assigns[:issues].map(&:id)).to include(task.id)
end
-
- context 'when work_items is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it 'does not include tasks in issue list' do
- task = create(:work_item, :task, project: project, author: user)
-
- get :issues, params: { author_id: user.id }
-
- expect(assigns[:issues].map(&:id)).not_to include(task.id)
- end
- end
end
describe 'GET merge requests' do
diff --git a/spec/controllers/explore/groups_controller_spec.rb b/spec/controllers/explore/groups_controller_spec.rb
index 310fe609cf1..a3bd8102462 100644
--- a/spec/controllers/explore/groups_controller_spec.rb
+++ b/spec/controllers/explore/groups_controller_spec.rb
@@ -9,31 +9,43 @@ RSpec.describe Explore::GroupsController do
sign_in(user)
end
- it 'renders group trees' do
- expect(described_class).to include(GroupTree)
- end
+ shared_examples 'explore groups' do
+ it 'renders group trees' do
+ expect(described_class).to include(GroupTree)
+ end
- it 'includes public projects' do
- member_of_group = create(:group)
- member_of_group.add_developer(user)
- public_group = create(:group, :public)
+ it 'includes public projects' do
+ member_of_group = create(:group)
+ member_of_group.add_developer(user)
+ public_group = create(:group, :public)
- get :index
+ get :index
- expect(assigns(:groups)).to contain_exactly(member_of_group, public_group)
- end
+ expect(assigns(:groups)).to contain_exactly(member_of_group, public_group)
+ end
- context 'restricted visibility level is public' do
- before do
- sign_out(user)
+ context 'restricted visibility level is public' do
+ before do
+ sign_out(user)
- stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+ end
+
+ it 'redirects to login page' do
+ get :index
+
+ expect(response).to redirect_to new_user_session_path
+ end
end
+ end
- it 'redirects to login page' do
- get :index
+ it_behaves_like 'explore groups'
- expect(response).to redirect_to new_user_session_path
+ context 'generic_explore_groups flag is disabled' do
+ before do
+ stub_feature_flags(generic_explore_groups: false)
end
+
+ it_behaves_like 'explore groups'
end
end
diff --git a/spec/controllers/explore/projects_controller_spec.rb b/spec/controllers/explore/projects_controller_spec.rb
index bf578489916..5c977439af4 100644
--- a/spec/controllers/explore/projects_controller_spec.rb
+++ b/spec/controllers/explore/projects_controller_spec.rb
@@ -208,19 +208,26 @@ RSpec.describe Explore::ProjectsController do
render_views
# some N+1 queries still exist
- it 'avoids N+1 queries' do
- projects = create_list(:project, 3, :repository, :public)
- projects.each do |project|
- pipeline = create(:ci_pipeline, :success, project: project, sha: project.commit.id)
- create(:commit_status, :success, pipeline: pipeline, ref: pipeline.ref)
+ it 'avoids N+1 queries', :request_store do
+ # Because we enable the request store for this spec, Gitaly may report too many invocations.
+ # Allow N+1s here and when creating additional objects below because we're just creating test objects.
+ Gitlab::GitalyClient.allow_n_plus_1_calls do
+ projects = create_list(:project, 3, :repository, :public)
+
+ projects.each do |project|
+ pipeline = create(:ci_pipeline, :success, project: project, sha: project.commit.id)
+ create(:commit_status, :success, pipeline: pipeline, ref: pipeline.ref)
+ end
end
control = ActiveRecord::QueryRecorder.new { get endpoint }
- new_projects = create_list(:project, 2, :repository, :public)
- new_projects.each do |project|
- pipeline = create(:ci_pipeline, :success, project: project, sha: project.commit.id)
- create(:commit_status, :success, pipeline: pipeline, ref: pipeline.ref)
+ Gitlab::GitalyClient.allow_n_plus_1_calls do
+ new_projects = create_list(:project, 2, :repository, :public)
+ new_projects.each do |project|
+ pipeline = create(:ci_pipeline, :success, project: project, sha: project.commit.id)
+ create(:commit_status, :success, pipeline: pipeline, ref: pipeline.ref)
+ end
end
expect { get endpoint }.not_to exceed_query_limit(control).with_threshold(8)
diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb
index 7c9236704ec..fe8b0291733 100644
--- a/spec/controllers/graphql_controller_spec.rb
+++ b/spec/controllers/graphql_controller_spec.rb
@@ -8,10 +8,6 @@ RSpec.describe GraphqlController do
# two days is enough to make timezones irrelevant
let_it_be(:last_activity_on) { 2.days.ago.to_date }
- before do
- stub_feature_flags(graphql: true)
- end
-
describe 'rescue_from' do
let_it_be(:message) { 'green ideas sleep furiously' }
@@ -418,4 +414,114 @@ RSpec.describe GraphqlController do
expect(log_payload.dig(:exception_object)).to eq(exception)
end
end
+
+ describe 'removal of deprecated items' do
+ let(:mock_schema) do
+ Class.new(GraphQL::Schema) do
+ lazy_resolve ::Gitlab::Graphql::Lazy, :force
+
+ query(Class.new(::Types::BaseObject) do
+ graphql_name 'Query'
+
+ field :foo, GraphQL::Types::Boolean,
+ deprecated: { milestone: '0.1', reason: :renamed }
+
+ field :bar, (Class.new(::Types::BaseEnum) do
+ graphql_name 'BarEnum'
+
+ value 'FOOBAR', value: 'foobar', deprecated: { milestone: '0.1', reason: :renamed }
+ end)
+
+ field :baz, GraphQL::Types::Boolean do
+ argument :arg, String, required: false, deprecated: { milestone: '0.1', reason: :renamed }
+ end
+
+ def foo
+ false
+ end
+
+ def bar
+ 'foobar'
+ end
+
+ def baz(arg:)
+ false
+ end
+ end)
+ end
+ end
+
+ before do
+ allow(GitlabSchema).to receive(:execute).and_wrap_original do |method, *args|
+ mock_schema.execute(*args)
+ end
+ end
+
+ context 'without `remove_deprecated` param' do
+ let(:params) { { query: '{ foo bar baz(arg: "test") }' } }
+
+ subject { post :execute, params: params }
+
+ it "sets context's `remove_deprecated` value to false" do
+ subject
+
+ expect(assigns(:context)[:remove_deprecated]).to be false
+ end
+
+ it 'returns deprecated items in response' do
+ subject
+
+ expect(json_response).to include('data' => { 'foo' => false, 'bar' => 'FOOBAR', 'baz' => false })
+ end
+ end
+
+ context 'with `remove_deprecated` param' do
+ let(:params) { { remove_deprecated: 'true' } }
+
+ subject { post :execute, params: params }
+
+ it "sets context's `remove_deprecated` value to true" do
+ subject
+
+ expect(assigns(:context)[:remove_deprecated]).to be true
+ end
+
+ it 'does not allow deprecated field' do
+ params[:query] = '{ foo }'
+
+ subject
+
+ expect(json_response).not_to include('data' => { 'foo' => false })
+ expect(json_response).to include(
+ 'errors' => include(a_hash_including('message' => /Field 'foo' doesn't exist on type 'Query'/))
+ )
+ end
+
+ it 'does not allow deprecated enum value' do
+ params[:query] = '{ bar }'
+
+ subject
+
+ expect(json_response).not_to include('data' => { 'bar' => 'FOOBAR' })
+ expect(json_response).to include(
+ 'errors' => include(
+ a_hash_including(
+ 'message' => /`Query.bar` returned `"foobar"` at `bar`, but this isn't a valid value for `BarEnum`/
+ )
+ )
+ )
+ end
+
+ it 'does not allow deprecated argument' do
+ params[:query] = '{ baz(arg: "test") }'
+
+ subject
+
+ expect(json_response).not_to include('data' => { 'bar' => 'FOOBAR' })
+ expect(json_response).to include(
+ 'errors' => include(a_hash_including('message' => /Field 'baz' doesn't accept argument 'arg'/))
+ )
+ end
+ end
+ end
end
diff --git a/spec/controllers/groups/children_controller_spec.rb b/spec/controllers/groups/children_controller_spec.rb
index 04cf7785f1e..f05551432fa 100644
--- a/spec/controllers/groups/children_controller_spec.rb
+++ b/spec/controllers/groups/children_controller_spec.rb
@@ -277,7 +277,7 @@ RSpec.describe Groups::ChildrenController do
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 ) }
+ let!(:first_page_projects) { create_list(:project, per_page, :public, namespace: group) }
it 'has projects on the first page' do
get :index, params: { group_id: group.to_param, sort: 'id_desc' }, format: :json
diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb
index a3659ae9163..4e5dc01f466 100644
--- a/spec/controllers/groups/group_members_controller_spec.rb
+++ b/spec/controllers/groups/group_members_controller_spec.rb
@@ -342,6 +342,41 @@ RSpec.describe Groups::GroupMembersController do
end
end
+ context 'with owners from a parent' do
+ context 'when top-level group' do
+ context 'with group sharing' do
+ let!(:subgroup) { create(:group, parent: group) }
+
+ before do
+ create(:group_group_link, :owner, shared_group: group, shared_with_group: subgroup)
+ create(:group_member, :owner, group: subgroup)
+ end
+
+ it 'does not allow removal of last direct group owner' do
+ delete :leave, params: { group_id: group }
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+
+ context 'when subgroup' do
+ let!(:subgroup) { create(:group, parent: group) }
+
+ before do
+ subgroup.add_owner(user)
+ end
+
+ it 'allows removal of last direct group owner', :aggregate_failures do
+ delete :leave, params: { group_id: subgroup }
+
+ expect(controller).to set_flash.to "You left the \"#{subgroup.human_name}\" group."
+ expect(response).to redirect_to(dashboard_groups_path)
+ expect(subgroup.users).not_to include user
+ end
+ end
+ end
+
context 'and there is another owner' do
before do
create(:group_member, :owner, source: group)
diff --git a/spec/controllers/groups/registry/repositories_controller_spec.rb b/spec/controllers/groups/registry/repositories_controller_spec.rb
index 9ac19b06718..62c15201a95 100644
--- a/spec/controllers/groups/registry/repositories_controller_spec.rb
+++ b/spec/controllers/groups/registry/repositories_controller_spec.rb
@@ -117,7 +117,7 @@ RSpec.describe Groups::Registry::RepositoriesController do
it_behaves_like 'a package tracking event', described_class.name, 'list_repositories'
context 'with project in subgroup' do
- let_it_be(:test_group) { create(:group, parent: group ) }
+ let_it_be(:test_group) { create(:group, parent: group) }
it_behaves_like 'renders a list of repositories'
diff --git a/spec/controllers/groups/releases_controller_spec.rb b/spec/controllers/groups/releases_controller_spec.rb
index 7dd0bc6206a..40e8cb4efc5 100644
--- a/spec/controllers/groups/releases_controller_spec.rb
+++ b/spec/controllers/groups/releases_controller_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe Groups::ReleasesController do
end
it 'does not return any releases' do
- expect(json_response.map { |r| r['tag'] } ).to be_empty
+ expect(json_response.map { |r| r['tag'] }).to be_empty
end
it 'returns OK' do
@@ -56,7 +56,7 @@ RSpec.describe Groups::ReleasesController do
index
- expect(json_response.map { |r| r['tag'] } ).to match_array(%w(p2 p1 v2 v1))
+ expect(json_response.map { |r| r['tag'] }).to match_array(%w(p2 p1 v2 v1))
end
end
diff --git a/spec/controllers/groups/runners_controller_spec.rb b/spec/controllers/groups/runners_controller_spec.rb
index 6dbf0803892..2add3cd3b18 100644
--- a/spec/controllers/groups/runners_controller_spec.rb
+++ b/spec/controllers/groups/runners_controller_spec.rb
@@ -168,7 +168,7 @@ RSpec.describe Groups::RunnersController do
new_desc = runner.description.swapcase
expect do
- post :update, params: params.merge(runner: { description: new_desc } )
+ post :update, params: params.merge(runner: { description: new_desc })
end.to change { runner.ensure_runner_queue_value }
expect(response).to have_gitlab_http_status(:found)
@@ -179,7 +179,7 @@ RSpec.describe Groups::RunnersController do
new_desc = instance_runner.description.swapcase
expect do
- post :update, params: params_runner_instance.merge(runner: { description: new_desc } )
+ post :update, params: params_runner_instance.merge(runner: { description: new_desc })
end.to not_change { instance_runner.ensure_runner_queue_value }
.and not_change { instance_runner.description }
@@ -190,7 +190,7 @@ RSpec.describe Groups::RunnersController do
new_desc = project_runner.description.swapcase
expect do
- post :update, params: params_runner_project.merge(runner: { description: new_desc } )
+ post :update, params: params_runner_project.merge(runner: { description: new_desc })
end.to change { project_runner.ensure_runner_queue_value }
expect(response).to have_gitlab_http_status(:found)
@@ -207,7 +207,7 @@ RSpec.describe Groups::RunnersController do
old_desc = runner.description
expect do
- post :update, params: params.merge(runner: { description: old_desc.swapcase } )
+ post :update, params: params.merge(runner: { description: old_desc.swapcase })
end.not_to change { runner.ensure_runner_queue_value }
expect(response).to have_gitlab_http_status(:not_found)
@@ -218,7 +218,7 @@ RSpec.describe Groups::RunnersController do
old_desc = instance_runner.description
expect do
- post :update, params: params_runner_instance.merge(runner: { description: old_desc.swapcase } )
+ post :update, params: params_runner_instance.merge(runner: { description: old_desc.swapcase })
end.not_to change { instance_runner.ensure_runner_queue_value }
expect(response).to have_gitlab_http_status(:not_found)
@@ -229,7 +229,7 @@ RSpec.describe Groups::RunnersController do
old_desc = project_runner.description
expect do
- post :update, params: params_runner_project.merge(runner: { description: old_desc.swapcase } )
+ post :update, params: params_runner_project.merge(runner: { description: old_desc.swapcase })
end.not_to change { project_runner.ensure_runner_queue_value }
expect(response).to have_gitlab_http_status(:not_found)
diff --git a/spec/controllers/groups/settings/repository_controller_spec.rb b/spec/controllers/groups/settings/repository_controller_spec.rb
index cbf55218b94..73a205069f5 100644
--- a/spec/controllers/groups/settings/repository_controller_spec.rb
+++ b/spec/controllers/groups/settings/repository_controller_spec.rb
@@ -13,88 +13,73 @@ RSpec.describe Groups::Settings::RepositoryController do
end
describe 'POST create_deploy_token' do
- context 'when ajax_new_deploy_token feature flag is disabled for the project' do
- before do
- stub_feature_flags(ajax_new_deploy_token: false)
- entity.add_owner(user)
- end
+ let(:good_deploy_token_params) do
+ {
+ name: 'name',
+ expires_at: 1.day.from_now.to_s,
+ username: 'deployer',
+ read_repository: '1',
+ deploy_token_type: DeployToken.deploy_token_types[:group_type]
+ }
+ end
- it_behaves_like 'a created deploy token' do
- let(:entity) { group }
- let(:create_entity_params) { { group_id: group } }
- let(:deploy_token_type) { DeployToken.deploy_token_types[:group_type] }
- end
+ let(:request_params) do
+ {
+ group_id: group.to_param,
+ deploy_token: deploy_token_params
+ }
end
- context 'when ajax_new_deploy_token feature flag is enabled for the project' do
- let(:good_deploy_token_params) do
- {
- name: 'name',
- expires_at: 1.day.from_now.to_s,
- username: 'deployer',
- read_repository: '1',
- deploy_token_type: DeployToken.deploy_token_types[:group_type]
- }
- end
+ before do
+ group.add_owner(user)
+ end
+
+ subject { post :create_deploy_token, params: request_params, format: :json }
- let(:request_params) do
+ context('a good request') do
+ let(:deploy_token_params) { good_deploy_token_params }
+ let(:expected_response) do
{
- group_id: group.to_param,
- deploy_token: deploy_token_params
+ 'id' => be_a(Integer),
+ 'name' => deploy_token_params[:name],
+ 'username' => deploy_token_params[:username],
+ 'expires_at' => Time.zone.parse(deploy_token_params[:expires_at]),
+ 'token' => be_a(String),
+ 'expired' => false,
+ 'revoked' => false,
+ 'scopes' => deploy_token_params.inject([]) do |scopes, kv|
+ key, value = kv
+ key.to_s.start_with?('read_') && value.to_i != 0 ? scopes << key.to_s : scopes
+ end
}
end
- before do
- group.add_owner(user)
- end
+ it 'creates the deploy token' do
+ subject
- subject { post :create_deploy_token, params: request_params, format: :json }
-
- context('a good request') do
- let(:deploy_token_params) { good_deploy_token_params }
- let(:expected_response) do
- {
- 'id' => be_a(Integer),
- 'name' => deploy_token_params[:name],
- 'username' => deploy_token_params[:username],
- 'expires_at' => Time.zone.parse(deploy_token_params[:expires_at]),
- 'token' => be_a(String),
- 'expired' => false,
- 'revoked' => false,
- 'scopes' => deploy_token_params.inject([]) do |scopes, kv|
- key, value = kv
- key.to_s.start_with?('read_') && value.to_i != 0 ? scopes << key.to_s : scopes
- end
- }
- end
-
- it 'creates the deploy token' do
- subject
-
- expect(response).to have_gitlab_http_status(:created)
- expect(response).to match_response_schema('public_api/v4/deploy_token')
- expect(json_response).to match(expected_response)
- end
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/deploy_token')
+ expect(json_response).to match(expected_response)
end
+ end
- context('a bad request') do
- let(:deploy_token_params) { good_deploy_token_params.except(:read_repository) }
- let(:expected_response) { { 'message' => "Scopes can't be blank" } }
+ context('a bad request') do
+ let(:deploy_token_params) { good_deploy_token_params.except(:read_repository) }
+ let(:expected_response) { { 'message' => "Scopes can't be blank" } }
- it 'does not create the deploy token' do
- subject
+ it 'does not create the deploy token' do
+ subject
- expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response).to match(expected_response)
- end
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response).to match(expected_response)
end
+ end
- context('an invalid request') do
- let(:deploy_token_params) { good_deploy_token_params.except(:name) }
+ context('an invalid request') do
+ let(:deploy_token_params) { good_deploy_token_params.except(:name) }
- it 'raises a validation error' do
- expect { subject }.to raise_error(ActiveRecord::StatementInvalid)
- end
+ it 'raises a validation error' do
+ expect { subject }.to raise_error(ActiveRecord::StatementInvalid)
end
end
end
diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb
index 5bbe236077c..22a406b3197 100644
--- a/spec/controllers/groups_controller_spec.rb
+++ b/spec/controllers/groups_controller_spec.rb
@@ -42,21 +42,15 @@ RSpec.describe GroupsController, factory_default: :keep do
end
end
- shared_examples 'details view' do
- let(:namespace) { group }
+ shared_examples 'details view as atom' do
+ let!(:event) { create(:event, project: project) }
+ let(:format) { :atom }
it { is_expected.to render_template('groups/show') }
- context 'as atom' do
- let!(:event) { create(:event, project: project) }
- let(:format) { :atom }
-
- it { is_expected.to render_template('groups/show') }
-
- it 'assigns events for all the projects in the group', :sidekiq_might_not_need_inline do
- subject
- expect(assigns(:events).map(&:id)).to contain_exactly(event.id)
- end
+ it 'assigns events for all the projects in the group' do
+ subject
+ expect(assigns(:events).map(&:id)).to contain_exactly(event.id)
end
end
@@ -70,7 +64,9 @@ RSpec.describe GroupsController, factory_default: :keep do
subject { get :show, params: { id: group.to_param }, format: format }
context 'when the group is not importing' do
- it_behaves_like 'details view'
+ it { is_expected.to render_template('groups/show') }
+
+ it_behaves_like 'details view as atom'
it 'tracks page views', :snowplow do
subject
@@ -115,7 +111,9 @@ RSpec.describe GroupsController, factory_default: :keep do
subject { get :details, params: { id: group.to_param }, format: format }
- it_behaves_like 'details view'
+ it { is_expected.to redirect_to(group_path(group)) }
+
+ it_behaves_like 'details view as atom'
end
describe 'GET edit' do
@@ -672,7 +670,7 @@ RSpec.describe GroupsController, factory_default: :keep do
end
context 'when there is a conflicting group path' do
- let!(:conflict_group) { create(:group, path: SecureRandom.hex(12) ) }
+ let!(:conflict_group) { create(:group, path: SecureRandom.hex(12)) }
let!(:old_name) { group.name }
it 'does not render references to the conflicting group' do
diff --git a/spec/controllers/oauth/authorizations_controller_spec.rb b/spec/controllers/oauth/authorizations_controller_spec.rb
index fb90a70d91d..5185aa64d9f 100644
--- a/spec/controllers/oauth/authorizations_controller_spec.rb
+++ b/spec/controllers/oauth/authorizations_controller_spec.rb
@@ -213,6 +213,75 @@ RSpec.describe Oauth::AuthorizationsController do
expect(response).to redirect_to(new_user_session_path)
end
end
+
+ context 'when the user is admin' do
+ context 'when disable_admin_oauth_scopes is set' do
+ before do
+ stub_application_setting(disable_admin_oauth_scopes: true)
+ scopes = Doorkeeper::OAuth::Scopes.from_string('api')
+
+ allow(Doorkeeper.configuration).to receive(:scopes).and_return(scopes)
+ end
+
+ let(:user) { create(:user, :admin) }
+
+ it 'returns 200 and renders forbidden view' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template('doorkeeper/authorizations/forbidden')
+ end
+ end
+
+ context 'when disable_admin_oauth_scopes is set and the application is trusted' do
+ before do
+ stub_application_setting(disable_admin_oauth_scopes: true)
+
+ application.update!(trusted: true)
+ end
+
+ let(:application_scopes) { 'api' }
+ let(:user) { create(:user, :admin) }
+
+ it 'returns 200 and renders redirect view' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template('doorkeeper/authorizations/redirect')
+ end
+ end
+
+ context 'when disable_admin_oauth_scopes is disabled' do
+ before do
+ stub_application_setting(disable_admin_oauth_scopes: false)
+ end
+
+ let(:application_scopes) { 'api' }
+ let(:user) { create(:user, :admin) }
+
+ it 'returns 200 and renders new view' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template('doorkeeper/authorizations/new')
+ end
+ end
+ end
+
+ context 'when the user is not admin' do
+ context 'when disable_admin_oauth_scopes is enabled' do
+ before do
+ stub_application_setting(disable_admin_oauth_scopes: true)
+ end
+
+ it 'returns 200 and renders new view' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template('doorkeeper/authorizations/new')
+ end
+ end
+ end
end
describe 'POST #create' do
diff --git a/spec/controllers/omniauth_callbacks_controller_spec.rb b/spec/controllers/omniauth_callbacks_controller_spec.rb
index df5da29495e..0560ccb25dd 100644
--- a/spec/controllers/omniauth_callbacks_controller_spec.rb
+++ b/spec/controllers/omniauth_callbacks_controller_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe OmniauthCallbacksController, type: :controller do
let(:additional_info) { {} }
before do
- @original_env_config_omniauth_auth = mock_auth_hash(provider.to_s, extern_uid, user.email, additional_info: additional_info )
+ @original_env_config_omniauth_auth = mock_auth_hash(provider.to_s, extern_uid, user.email, additional_info: additional_info)
stub_omniauth_provider(provider, context: request)
end
diff --git a/spec/controllers/passwords_controller_spec.rb b/spec/controllers/passwords_controller_spec.rb
index e4be2fbef3c..9494f55c631 100644
--- a/spec/controllers/passwords_controller_spec.rb
+++ b/spec/controllers/passwords_controller_spec.rb
@@ -78,6 +78,22 @@ RSpec.describe PasswordsController do
end
end
+ context 'password is weak' do
+ let(:password) { "password" }
+
+ it 'tracks the event' do
+ subject
+
+ expect(response.body).to have_content("must not contain commonly used combinations of words and letters")
+ expect_snowplow_event(
+ category: 'Gitlab::Tracking::Helpers::WeakPasswordErrorEvent',
+ action: 'track_weak_password_error',
+ controller: 'PasswordsController',
+ method: 'create'
+ )
+ end
+ end
+
it 'sets the username and caller_id in the context' do
expect(controller).to receive(:update).and_wrap_original do |m, *args|
m.call(*args)
diff --git a/spec/controllers/profiles/personal_access_tokens_controller_spec.rb b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb
index 8dee0490fd6..044ce8f397a 100644
--- a/spec/controllers/profiles/personal_access_tokens_controller_spec.rb
+++ b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb
@@ -3,11 +3,11 @@
require 'spec_helper'
RSpec.describe Profiles::PersonalAccessTokensController do
- let(:user) { create(:user) }
+ let(:access_token_user) { create(:user) }
let(:token_attributes) { attributes_for(:personal_access_token) }
before do
- sign_in(user)
+ sign_in(access_token_user)
end
describe '#create' do
@@ -49,13 +49,27 @@ RSpec.describe Profiles::PersonalAccessTokensController do
end
end
+ describe 'GET /-/profile/personal_access_tokens' do
+ let(:get_access_tokens) do
+ get :index
+ response
+ end
+
+ subject(:get_access_tokens_with_page) do
+ get :index, params: { page: 1 }
+ response
+ end
+
+ it_behaves_like 'GET access tokens are paginated and ordered'
+ end
+
describe '#index' do
- let!(:active_personal_access_token) { create(:personal_access_token, user: user) }
+ let!(:active_personal_access_token) { create(:personal_access_token, user: access_token_user) }
before do
# Impersonation and inactive personal tokens are ignored
- create(:personal_access_token, :impersonation, user: user)
- create(:personal_access_token, :revoked, user: user)
+ create(:personal_access_token, :impersonation, user: access_token_user)
+ create(:personal_access_token, :revoked, user: access_token_user)
get :index
end
@@ -63,7 +77,7 @@ RSpec.describe Profiles::PersonalAccessTokensController do
active_personal_access_tokens_detail =
::PersonalAccessTokenSerializer.new.represent([active_personal_access_token])
- expect(assigns(:active_personal_access_tokens).to_json).to eq(active_personal_access_tokens_detail.to_json)
+ expect(assigns(:active_access_tokens).to_json).to eq(active_personal_access_tokens_detail.to_json)
end
it "sets PAT name and scopes" do
@@ -86,73 +100,10 @@ RSpec.describe Profiles::PersonalAccessTokensController do
expect(response).to have_gitlab_http_status(:not_found)
end
- context "access_token_pagination feature flag is enabled" do
- before do
- stub_feature_flags(access_token_pagination: true)
- allow(Kaminari.config).to receive(:default_per_page).and_return(1)
- create(:personal_access_token, user: user)
- end
-
- it "returns paginated response" do
- get :index, params: { page: 1 }
- expect(assigns(:active_personal_access_tokens).count).to eq(1)
- end
-
- it 'adds appropriate headers' do
- get :index, params: { page: 1 }
- expect_header('X-Per-Page', '1')
- expect_header('X-Page', '1')
- expect_header('X-Next-Page', '2')
- expect_header('X-Total', '2')
- end
- end
-
- context "tokens returned are ordered" do
- let(:expires_1_day_from_now) { 1.day.from_now.to_date }
- let(:expires_2_day_from_now) { 2.days.from_now.to_date }
-
- before do
- create(:personal_access_token, user: user, name: "Token1", expires_at: expires_1_day_from_now)
- create(:personal_access_token, user: user, name: "Token2", expires_at: expires_2_day_from_now)
- end
-
- it "orders token list ascending on expires_at" do
- get :index
-
- first_token = assigns(:active_personal_access_tokens).first.as_json
- expect(first_token['name']).to eq("Token1")
- expect(first_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
- end
-
- it "orders tokens on id in case token has same expires_at" do
- create(:personal_access_token, user: user, name: "Token3", expires_at: expires_1_day_from_now)
-
- get :index
-
- first_token = assigns(:active_personal_access_tokens).first.as_json
- expect(first_token['name']).to eq("Token3")
- expect(first_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
-
- second_token = assigns(:active_personal_access_tokens).second.as_json
- expect(second_token['name']).to eq("Token1")
- expect(second_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
- end
- end
-
- context "access_token_pagination feature flag is disabled" do
- before do
- stub_feature_flags(access_token_pagination: false)
- create(:personal_access_token, user: user)
- end
+ it 'returns tokens for json format' do
+ get :index, params: { format: :json }
- it "returns all tokens in system" do
- get :index, params: { page: 1 }
- expect(assigns(:active_personal_access_tokens).count).to eq(2)
- end
+ expect(json_response.count).to eq(1)
end
end
-
- def expect_header(header_name, header_val)
- expect(response.headers[header_name]).to eq(header_val)
- end
end
diff --git a/spec/controllers/projects/alerting/notifications_controller_spec.rb b/spec/controllers/projects/alerting/notifications_controller_spec.rb
index b3feeb7c07b..5ce2950f95f 100644
--- a/spec/controllers/projects/alerting/notifications_controller_spec.rb
+++ b/spec/controllers/projects/alerting/notifications_controller_spec.rb
@@ -16,9 +16,6 @@ RSpec.describe Projects::Alerting::NotificationsController do
end
shared_examples 'process alert payload' do |notify_service_class|
- let(:alert_1) { build(:alert_management_alert, project: project) }
- let(:alert_2) { build(:alert_management_alert, project: project) }
- let(:service_response) { ServiceResponse.success(payload: { alerts: [alert_1, alert_2] }) }
let(:notify_service) { instance_double(notify_service_class, execute: service_response) }
before do
@@ -35,11 +32,14 @@ RSpec.describe Projects::Alerting::NotificationsController do
it 'responds with the alert data' do
make_request
- expect(json_response).to contain_exactly(
- { 'iid' => alert_1.iid, 'title' => alert_1.title },
- { 'iid' => alert_2.iid, 'title' => alert_2.title }
- )
- expect(response).to have_gitlab_http_status(:ok)
+ if service_response.payload.present?
+ expect(json_response).to contain_exactly(
+ { 'iid' => alert_1.iid, 'title' => alert_1.title },
+ { 'iid' => alert_2.iid, 'title' => alert_2.title }
+ )
+ end
+
+ expect(response).to have_gitlab_http_status(service_response.http_status)
end
it 'does not pass excluded parameters to the notify service' do
@@ -146,6 +146,9 @@ RSpec.describe Projects::Alerting::NotificationsController do
context 'with generic alert payload' do
it_behaves_like 'process alert payload', Projects::Alerting::NotifyService do
+ let(:alert_1) { build(:alert_management_alert, project: project) }
+ let(:alert_2) { build(:alert_management_alert, project: project) }
+ let(:service_response) { ServiceResponse.success(payload: { alerts: [alert_1, alert_2] }) }
let(:payload) { { title: 'Alert title' } }
end
end
@@ -154,6 +157,7 @@ RSpec.describe Projects::Alerting::NotificationsController do
include PrometheusHelpers
it_behaves_like 'process alert payload', Projects::Prometheus::Alerts::NotifyService do
+ let(:service_response) { ServiceResponse.success(http_status: :created) }
let(:payload) { prometheus_alert_payload }
end
end
diff --git a/spec/controllers/projects/artifacts_controller_spec.rb b/spec/controllers/projects/artifacts_controller_spec.rb
index f79a2c6a6d0..00efd7d7b56 100644
--- a/spec/controllers/projects/artifacts_controller_spec.rb
+++ b/spec/controllers/projects/artifacts_controller_spec.rb
@@ -30,28 +30,10 @@ RSpec.describe Projects::ArtifactsController do
stub_feature_flags(artifacts_management_page: true)
end
- it 'sets the artifacts variable' do
+ it 'renders the page' do
subject
- expect(assigns(:artifacts)).to contain_exactly(*project.job_artifacts)
- end
-
- it 'sets the total size variable' do
- subject
-
- expect(assigns(:total_size)).to eq(project.job_artifacts.total_size)
- end
-
- describe 'pagination' do
- before do
- stub_const("#{described_class}::MAX_PER_PAGE", 1)
- end
-
- it 'paginates artifacts' do
- subject
-
- expect(assigns(:artifacts)).to contain_exactly(project.reload.job_artifacts.last)
- end
+ expect(response).to have_gitlab_http_status(:ok)
end
end
@@ -65,18 +47,6 @@ RSpec.describe Projects::ArtifactsController do
expect(response).to have_gitlab_http_status(:no_content)
end
-
- it 'does not set the artifacts variable' do
- subject
-
- expect(assigns(:artifacts)).to eq(nil)
- end
-
- it 'does not set the total size variable' do
- subject
-
- expect(assigns(:total_size)).to eq(nil)
- end
end
end
@@ -183,12 +153,17 @@ RSpec.describe Projects::ArtifactsController do
end
context 'when file is stored remotely' do
+ let(:cdn_config) {}
+
before do
- stub_artifacts_object_storage
+ stub_artifacts_object_storage(cdn: cdn_config)
create(:ci_job_artifact, :remote_store, :codequality, job: job)
+ allow(Gitlab::ApplicationContext).to receive(:push).and_call_original
end
it 'sends the codequality report' do
+ expect(Gitlab::ApplicationContext).to receive(:push).with(artifact: an_instance_of(Ci::JobArtifact)).and_call_original
+
expect(controller).to receive(:redirect_to).and_call_original
download_artifact(file_type: file_type)
@@ -201,6 +176,30 @@ RSpec.describe Projects::ArtifactsController do
download_artifact(file_type: file_type, proxy: true)
end
end
+
+ context 'when Google CDN is configured' do
+ let(:cdn_config) do
+ {
+ 'provider' => 'Google',
+ 'url' => 'https://cdn.example.org',
+ 'key_name' => 'some-key',
+ 'key' => Base64.urlsafe_encode64(SecureRandom.hex)
+ }
+ end
+
+ before do
+ request.env['action_dispatch.remote_ip'] = '18.245.0.42'
+ end
+
+ it 'redirects to a Google CDN request' do
+ expect(Gitlab::ApplicationContext).to receive(:push).with(artifact: an_instance_of(Ci::JobArtifact)).and_call_original
+ expect(Gitlab::ApplicationContext).to receive(:push).with(artifact_used_cdn: true).and_call_original
+
+ download_artifact(file_type: file_type)
+
+ expect(response.redirect_url).to start_with("https://cdn.example.org/")
+ end
+ end
end
end
end
@@ -228,8 +227,9 @@ RSpec.describe Projects::ArtifactsController do
expect(response).to have_gitlab_http_status(:forbidden)
expect(response.body).to include(
'You must have developer or higher permissions in the associated project to view job logs when debug trace is enabled. ' \
- 'To disable debug trace, set the &#39;CI_DEBUG_TRACE&#39; variable to &#39;false&#39; in your pipeline configuration or CI/CD settings. ' \
- 'If you need to view this job log, a project maintainer or owner must add you to the project with developer permissions or higher.'
+ 'To disable debug trace, set the &#39;CI_DEBUG_TRACE&#39; and &#39;CI_DEBUG_SERVICES&#39; variables to &#39;false&#39; ' \
+ 'in your pipeline configuration or CI/CD settings. If you must view this job log, a project maintainer or owner must ' \
+ 'add you to the project with developer permissions or higher.'
)
end
end
diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb
index 16a43bae674..5927f20df97 100644
--- a/spec/controllers/projects/environments_controller_spec.rb
+++ b/spec/controllers/projects/environments_controller_spec.rb
@@ -76,7 +76,7 @@ RSpec.describe Projects::EnvironmentsController do
it 'handles search option properly' do
get :index, params: environment_params(format: :json, search: 'staging/r')
- expect(environments.map { |env| env['name'] } ).to contain_exactly('staging/review-1', 'staging/review-2')
+ expect(environments.map { |env| env['name'] }).to contain_exactly('staging/review-1', 'staging/review-2')
expect(json_response['available_count']).to eq 2
expect(json_response['stopped_count']).to eq 1
end
@@ -84,7 +84,7 @@ RSpec.describe Projects::EnvironmentsController do
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',
+ expect(environments.map { |env| env['name'] }).to contain_exactly('production',
'staging/review-1',
'staging/review-2')
expect(json_response['available_count']).to eq 3
@@ -233,7 +233,7 @@ RSpec.describe Projects::EnvironmentsController do
search: 'staging-1.0/z'
}, format: :json)
- expect(environments.map { |env| env['name'] } ).to eq(['staging-1.0/zzz'])
+ expect(environments.map { |env| env['name'] }).to eq(['staging-1.0/zzz'])
expect(json_response['available_count']).to eq 1
expect(json_response['stopped_count']).to eq 0
end
@@ -705,7 +705,7 @@ RSpec.describe Projects::EnvironmentsController do
expect(json_response).to have_key('all_dashboards')
expect(json_response['all_dashboards']).to be_an_instance_of(Array)
- expect(json_response['all_dashboards']).to all( include('path', 'default', 'display_name') )
+ expect(json_response['all_dashboards']).to all(include('path', 'default', 'display_name'))
end
end
diff --git a/spec/controllers/projects/hooks_controller_spec.rb b/spec/controllers/projects/hooks_controller_spec.rb
index ba7b712964c..18f16937505 100644
--- a/spec/controllers/projects/hooks_controller_spec.rb
+++ b/spec/controllers/projects/hooks_controller_spec.rb
@@ -29,6 +29,22 @@ RSpec.describe Projects::HooksController do
{ namespace_id: project.namespace, project_id: project, id: hook.id }
end
+ context 'with an existing token' do
+ hook_params = {
+ token: WebHook::SECRET_MASK,
+ url: "http://example.com"
+ }
+
+ it 'does not change a token' do
+ expect do
+ post :update, params: params.merge({ hook: hook_params })
+ end.not_to change { hook.reload.token }
+
+ expect(response).to have_gitlab_http_status(:found)
+ expect(flash[:alert]).to be_blank
+ end
+ end
+
it 'adds, updates and deletes URL variables' do
hook.update!(url_variables: { 'a' => 'bar', 'b' => 'woo' })
@@ -106,8 +122,9 @@ RSpec.describe Projects::HooksController do
it 'sets all parameters' do
hook_params = {
enable_ssl_verification: true,
- token: "TEST TOKEN",
- url: "http://example.com",
+ token: 'TEST TOKEN',
+ url: 'http://example.com',
+ branch_filter_strategy: 'regex',
push_events: true,
tag_push_events: true,
@@ -124,13 +141,39 @@ RSpec.describe Projects::HooksController do
url_variables: [{ key: 'token', value: 'some secret value' }]
}
- post :create, params: { namespace_id: project.namespace, project_id: project, hook: hook_params }
+ params = { namespace_id: project.namespace, project_id: project, hook: hook_params }
+
+ expect { post :create, params: params }.to change(ProjectHook, :count).by(1)
+
+ project_hook = ProjectHook.order_id_desc.take
+
+ expect(project_hook).to have_attributes(
+ **hook_params.merge(url_variables: { 'token' => 'some secret value' })
+ )
+ expect(response).to have_gitlab_http_status(:found)
+ expect(flash[:alert]).to be_blank
+ end
+
+ it 'ignores branch_filter_strategy when flag is disabled' do
+ stub_feature_flags(enhanced_webhook_support_regex: false)
+ hook_params = {
+ url: 'http://example.com',
+ branch_filter_strategy: 'regex',
+ push_events: true
+ }
+ params = { namespace_id: project.namespace, project_id: project, hook: hook_params }
+
+ expect { post :create, params: params }.to change(ProjectHook, :count).by(1)
+
+ project_hook = ProjectHook.order_id_desc.take
+
+ expect(project_hook).to have_attributes(
+ url: 'http://example.com',
+ branch_filter_strategy: 'wildcard'
+ )
expect(response).to have_gitlab_http_status(:found)
expect(flash[:alert]).to be_blank
- expect(ProjectHook.count).to eq(1)
- expect(ProjectHook.first).to have_attributes(hook_params.except(:url_variables))
- expect(ProjectHook.first).to have_attributes(url_variables: { 'token' => 'some secret value' })
end
it 'alerts the user if the new hook is invalid' do
@@ -186,7 +229,7 @@ RSpec.describe Projects::HooksController do
context 'when the hook fails completely' do
before do
allow_next(::TestHooks::ProjectService)
- .to receive(:execute).and_return({ message: 'All is woe' })
+ .to receive(:execute).and_return(ServiceResponse.error(message: 'All is woe'))
end
it 'informs the user' do
@@ -204,7 +247,7 @@ RSpec.describe Projects::HooksController do
it 'prevents making test requests' do
expect_next_instance_of(TestHooks::ProjectService) do |service|
- expect(service).to receive(:execute).and_return(http_status: 200)
+ expect(service).to receive(:execute).and_return(ServiceResponse.success(payload: { http_status: 200 }))
end
2.times { post :test, params: { namespace_id: project.namespace, project_id: project, id: hook } }
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 0c3795540e0..8f26be442a7 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -168,75 +168,56 @@ RSpec.describe Projects::IssuesController do
let_it_be(:task) { create(:issue, :task, project: project) }
- context 'when work_items feature flag is enabled' do
- shared_examples 'redirects to show work item page' do
- it 'redirects to work item page' do
- expect(response).to redirect_to(project_work_items_path(project, task.id, query))
- end
- end
-
- context 'show action' do
- let(:query) { { query: 'any' } }
-
+ shared_examples 'redirects to show work item page' do
+ context 'when use_iid_in_work_items_path feature flag is disabled' do
before do
- get :show, params: { namespace_id: project.namespace, project_id: project, id: task.iid, **query }
+ stub_feature_flags(use_iid_in_work_items_path: false)
end
- it_behaves_like 'redirects to show work item page'
- end
-
- context 'edit action' do
- let(:query) { { query: 'any' } }
+ it 'redirects to work item page' do
+ make_request
- before do
- get :edit, params: { namespace_id: project.namespace, project_id: project, id: task.iid, **query }
+ expect(response).to redirect_to(project_work_items_path(project, task.id, query))
end
-
- it_behaves_like 'redirects to show work item page'
end
- context 'update action' do
- before do
- put :update, params: { namespace_id: project.namespace, project_id: project, id: task.iid, issue: { title: 'New title' } }
- end
+ it 'redirects to work item page using iid' do
+ make_request
- it_behaves_like 'redirects to show work item page'
+ expect(response).to redirect_to(project_work_items_path(project, task.iid, query.merge(iid_path: true)))
end
end
- context 'when work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
+ context 'show action' do
+ let(:query) { { query: 'any' } }
- shared_examples 'renders 404' do
- it 'renders 404 for show action' do
- expect(response).to have_gitlab_http_status(:not_found)
+ it_behaves_like 'redirects to show work item page' do
+ subject(:make_request) do
+ get :show, params: { namespace_id: project.namespace, project_id: project, id: task.iid, **query }
end
end
+ end
- context 'show action' do
- before do
- get :show, params: { namespace_id: project.namespace, project_id: project, id: task.iid }
- end
-
- it_behaves_like 'renders 404'
- end
+ context 'edit action' do
+ let(:query) { { query: 'any' } }
- context 'edit action' do
- before do
- get :edit, params: { namespace_id: project.namespace, project_id: project, id: task.iid }
+ it_behaves_like 'redirects to show work item page' do
+ subject(:make_request) do
+ get :edit, params: { namespace_id: project.namespace, project_id: project, id: task.iid, **query }
end
-
- it_behaves_like 'renders 404'
end
+ end
- context 'update action' do
- before do
- put :update, params: { namespace_id: project.namespace, project_id: project, id: task.iid, issue: { title: 'New title' } }
+ context 'update action' do
+ it_behaves_like 'redirects to show work item page' do
+ subject(:make_request) do
+ put :update, params: {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: task.iid,
+ issue: { title: 'New title' }
+ }
end
-
- it_behaves_like 'renders 404'
end
end
end
@@ -1107,6 +1088,24 @@ RSpec.describe Projects::IssuesController do
end
end
+ context 'when trying to create a objective' do
+ it 'defaults to issue type' do
+ issue = post_new_issue(issue_type: 'objective')
+
+ expect(issue.issue_type).to eq('issue')
+ expect(issue.work_item_type.base_type).to eq('issue')
+ end
+ end
+
+ context 'when trying to create a key_result' do
+ it 'defaults to issue type' do
+ issue = post_new_issue(issue_type: 'key_result')
+
+ expect(issue.issue_type).to eq('issue')
+ expect(issue.work_item_type.base_type).to eq('issue')
+ end
+ end
+
context 'when create service return an unrecoverable error with http_status' do
let(:http_status) { 403 }
@@ -1291,7 +1290,7 @@ RSpec.describe Projects::IssuesController do
let!(:last_spam_log) { spam_logs.last }
def post_verified_issue
- post_new_issue({}, { spam_log_id: last_spam_log.id, 'g-recaptcha-response': 'abc123' } )
+ post_new_issue({}, { spam_log_id: last_spam_log.id, 'g-recaptcha-response': 'abc123' })
end
before do
@@ -1311,7 +1310,7 @@ RSpec.describe Projects::IssuesController do
it 'does not mark spam log as recaptcha_verified when it does not belong to current_user' do
spam_log = create(:spam_log)
- expect { post_new_issue({}, { spam_log_id: spam_log.id, 'g-recaptcha-response': true } ) }
+ expect { post_new_issue({}, { spam_log_id: spam_log.id, 'g-recaptcha-response': true }) }
.not_to change { last_spam_log.recaptcha_verified }
end
end
@@ -1709,19 +1708,6 @@ RSpec.describe Projects::IssuesController do
expect(response).to redirect_to(project_issues_path(project))
expect(controller).to set_flash[:notice].to match(/\AYour CSV export has started/i)
end
-
- context 'when work_items is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it 'does not include tasks in CSV export' do
- expect(IssuableExportCsvWorker).to receive(:perform_async)
- .with(:issue, viewer.id, project.id, hash_including('issue_types' => Issue::TYPES_FOR_LIST.excluding('task')))
-
- request_csv
- end
- end
end
context 'when not logged in' do
diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb
index 556dd23c135..3dc89365530 100644
--- a/spec/controllers/projects/jobs_controller_spec.rb
+++ b/spec/controllers/projects/jobs_controller_spec.rb
@@ -660,6 +660,38 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
end
end
end
+
+ context 'when CI_DEBUG_SERVICES enabled' do
+ let!(:variable) { create(:ci_instance_variable, key: 'CI_DEBUG_SERVICES', value: 'true') }
+
+ context 'with proper permissions on a project' do
+ let(:user) { developer }
+
+ before do
+ sign_in(user)
+ end
+
+ it 'returns response ok' do
+ get_trace
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'without proper permissions for debug logging' do
+ let(:user) { guest }
+
+ before do
+ sign_in(user)
+ end
+
+ it 'returns response forbidden' do
+ get_trace
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
end
context 'when job has a live trace' do
@@ -1184,36 +1216,51 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
expect(response.header[Gitlab::Workhorse::DETECT_HEADER]).to eq "true"
end
- context 'when CI_DEBUG_TRACE enabled' do
- before do
- create(:ci_instance_variable, key: 'CI_DEBUG_TRACE', value: 'true')
+ context 'when CI_DEBUG_TRACE and/or CI_DEBUG_SERVICES are enabled' do
+ using RSpec::Parameterized::TableSyntax
+ where(:ci_debug_trace, :ci_debug_services) do
+ 'true' | 'true'
+ 'true' | 'false'
+ 'false' | 'true'
+ 'false' | 'false'
end
- context 'with proper permissions for debug logging on a project' do
- let(:user) { developer }
-
+ with_them do
before do
- sign_in(user)
+ create(:ci_instance_variable, key: 'CI_DEBUG_TRACE', value: ci_debug_trace)
+ create(:ci_instance_variable, key: 'CI_DEBUG_SERVICES', value: ci_debug_services)
end
- it 'returns response ok' do
- response = subject
+ context 'with proper permissions for debug logging on a project' do
+ let(:user) { developer }
- expect(response).to have_gitlab_http_status(:ok)
- end
- end
+ before do
+ sign_in(user)
+ end
- context 'without proper permissions for debug logging on a project' do
- let(:user) { reporter }
+ it 'returns response ok' do
+ response = subject
- before do
- sign_in(user)
+ expect(response).to have_gitlab_http_status(:ok)
+ end
end
- it 'returns response forbidden' do
- response = subject
+ context 'without proper permissions for debug logging on a project' do
+ let(:user) { reporter }
- expect(response).to have_gitlab_http_status(:forbidden)
+ before do
+ sign_in(user)
+ end
+
+ it 'returns response forbidden if dev mode enabled' do
+ response = subject
+
+ if ci_debug_trace == 'true' || ci_debug_services == 'true'
+ expect(response).to have_gitlab_http_status(:forbidden)
+ else
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
end
end
end
@@ -1380,7 +1427,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
{
'Channel' => {
'Subprotocols' => ["terminal.gitlab.com"],
- 'Url' => 'wss://localhost/proxy/build/default_port/',
+ 'Url' => 'wss://gitlab.example.com/proxy/build/default_port/',
'Header' => {
'Authorization' => [nil]
},
@@ -1536,7 +1583,8 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
allow(Gitlab::Workhorse).to receive(:verify_api_request!).and_return(nil)
expect(job.runner_session_url).to start_with('https://')
- expect(Gitlab::Workhorse).to receive(:channel_websocket).with(a_hash_including(url: "wss://localhost/proxy/build/default_port/"))
+ expect(Gitlab::Workhorse).to receive(:channel_websocket)
+ .with(a_hash_including(url: "wss://gitlab.example.com/proxy/build/default_port/"))
make_request
end
diff --git a/spec/controllers/projects/learn_gitlab_controller_spec.rb b/spec/controllers/projects/learn_gitlab_controller_spec.rb
index 2d00fcbccf3..a93da82d948 100644
--- a/spec/controllers/projects/learn_gitlab_controller_spec.rb
+++ b/spec/controllers/projects/learn_gitlab_controller_spec.rb
@@ -34,8 +34,15 @@ RSpec.describe Projects::LearnGitlabController do
it { is_expected.to have_gitlab_http_status(:not_found) }
end
- it_behaves_like 'tracks assignment and records the subject', :invite_for_help_continuous_onboarding, :namespace do
- subject { project.namespace }
+ context 'with invite_for_help_continuous_onboarding experiment' do
+ it 'tracks the assignment', :experiment do
+ stub_experiments(invite_for_help_continuous_onboarding: true)
+
+ expect(experiment(:invite_for_help_continuous_onboarding))
+ .to track(:assignment).with_context(namespace: project.namespace).on_next_instance
+
+ action
+ end
end
end
end
diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
index 367781c0e76..613d82efd06 100644
--- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb
@@ -213,7 +213,7 @@ RSpec.describe Projects::MergeRequests::DiffsController do
commit: nil,
latest_diff: true,
only_context_commits: false,
- allow_tree_conflicts: true,
+ merge_conflicts_in_diff: true,
merge_ref_head_diff: false
}
end
@@ -281,7 +281,7 @@ RSpec.describe Projects::MergeRequests::DiffsController do
commit: nil,
latest_diff: true,
only_context_commits: false,
- allow_tree_conflicts: true,
+ merge_conflicts_in_diff: true,
merge_ref_head_diff: nil
}
end
@@ -303,7 +303,7 @@ RSpec.describe Projects::MergeRequests::DiffsController do
commit: merge_request.diff_head_commit,
latest_diff: nil,
only_context_commits: false,
- allow_tree_conflicts: true,
+ merge_conflicts_in_diff: true,
merge_ref_head_diff: nil
}
end
@@ -329,7 +329,7 @@ RSpec.describe Projects::MergeRequests::DiffsController do
commit: nil,
latest_diff: true,
only_context_commits: false,
- allow_tree_conflicts: false,
+ merge_conflicts_in_diff: false,
merge_ref_head_diff: nil
}
end
@@ -488,7 +488,7 @@ RSpec.describe Projects::MergeRequests::DiffsController do
commit: nil,
diff_view: :inline,
merge_ref_head_diff: nil,
- allow_tree_conflicts: true,
+ merge_conflicts_in_diff: true,
pagination_data: {
total_pages: nil
}.merge(pagination_data)
@@ -616,7 +616,7 @@ RSpec.describe Projects::MergeRequests::DiffsController do
it_behaves_like 'serializes diffs with expected arguments' do
let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch }
- let(:expected_options) { collection_arguments(total_pages: 20).merge(allow_tree_conflicts: false) }
+ let(:expected_options) { collection_arguments(total_pages: 20).merge(merge_conflicts_in_diff: false) }
end
it_behaves_like 'successful request'
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index a41abd8c16d..026cf19bde5 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe Projects::MergeRequestsController do
include ProjectForksHelper
include Gitlab::Routing
+ using RSpec::Parameterized::TableSyntax
let_it_be_with_refind(:project) { create(:project, :repository) }
let_it_be_with_reload(:project_public_with_private_builds) { create(:project, :repository, :public, :builds_private) }
@@ -708,12 +709,14 @@ RSpec.describe Projects::MergeRequestsController do
end
describe 'GET commits' do
- def go(format: 'html')
+ 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
+ id: merge_request.iid,
+ page: page,
+ per_page: per_page
},
format: format
end
@@ -723,6 +726,27 @@ RSpec.describe Projects::MergeRequestsController do
expect(response).to render_template('projects/merge_requests/_commits')
expect(json_response).to have_key('html')
+ expect(json_response).to have_key('next_page')
+ expect(json_response['next_page']).to eq(2)
+ end
+
+ describe 'pagination' do
+ where(:page, :next_page) do
+ 1 | 2
+ 2 | 3
+ 3 | nil
+ end
+
+ with_them do
+ it "renders the commits for page #{params[:page]}" do
+ go format: 'json', page: page, per_page: 10
+
+ expect(response).to render_template('projects/merge_requests/_commits')
+ expect(json_response).to have_key('html')
+ expect(json_response).to have_key('next_page')
+ expect(json_response['next_page']).to eq(next_page)
+ end
+ end
end
end
@@ -1756,7 +1780,7 @@ RSpec.describe Projects::MergeRequestsController do
end
it 'renders MergeRequest as JSON' do
- expect(json_response.keys).to include('id', 'iid', 'title', 'has_ci', 'merge_status', 'can_be_merged', 'current_user')
+ expect(json_response.keys).to include('id', 'iid', 'title', 'has_ci', 'current_user')
end
end
@@ -1790,7 +1814,7 @@ RSpec.describe Projects::MergeRequestsController do
it 'renders MergeRequest as JSON' do
subject
- expect(json_response.keys).to include('id', 'iid', 'title', 'has_ci', 'merge_status', 'can_be_merged', 'current_user')
+ expect(json_response.keys).to include('id', 'iid', 'title', 'has_ci', 'current_user')
end
end
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index b132c0b5a69..f66e4b133ca 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -20,23 +20,11 @@ RSpec.describe Projects::PipelinesController do
end
shared_examples 'the show page' do |param|
- it 'redirects to pipeline path with param' do
+ it 'renders the show template' do
get param, params: { namespace_id: project.namespace, project_id: project, id: pipeline }
- expect(response).to redirect_to(pipeline_path(pipeline, tab: param))
- end
-
- context 'when the FF pipeline_tabs_vue is disabled' do
- before do
- stub_feature_flags(pipeline_tabs_vue: false)
- end
-
- it 'renders the show template' do
- get param, params: { namespace_id: project.namespace, project_id: project, id: pipeline }
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template :show
- end
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template :show
end
end
@@ -311,14 +299,15 @@ RSpec.describe Projects::PipelinesController do
stub_application_setting(auto_devops_enabled: false)
end
- def action
- get :index, params: { namespace_id: project.namespace, project_id: project }
- end
+ context 'with runners_availability_section experiment' do
+ it 'tracks the assignment', :experiment do
+ stub_experiments(runners_availability_section: true)
- subject { project.namespace }
+ expect(experiment(:runners_availability_section))
+ .to track(:assignment).with_context(namespace: project.namespace).on_next_instance
- context 'runners_availability_section experiment' do
- it_behaves_like 'tracks assignment and records the subject', :runners_availability_section, :namespace
+ get :index, params: { namespace_id: project.namespace, project_id: project }
+ end
end
end
@@ -710,37 +699,25 @@ RSpec.describe Projects::PipelinesController do
describe 'GET failures' do
let(:pipeline) { create(:ci_pipeline, project: project) }
- context 'with ff `pipeline_tabs_vue` disabled' do
+ context 'with failed jobs' do
before do
- stub_feature_flags(pipeline_tabs_vue: false)
+ create(:ci_build, :failed, pipeline: pipeline, name: 'hello')
end
- context 'with failed jobs' do
- before do
- create(:ci_build, :failed, pipeline: pipeline, name: 'hello')
- end
-
- it 'shows the page' do
- get :failures, params: { namespace_id: project.namespace, project_id: project, id: pipeline }
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template :show
- end
- end
-
- context 'without failed jobs' do
- it 'redirects to the main pipeline page' do
- get :failures, params: { namespace_id: project.namespace, project_id: project, id: pipeline }
+ it 'shows the page' do
+ get :failures, params: { namespace_id: project.namespace, project_id: project, id: pipeline }
- expect(response).to redirect_to(pipeline_path(pipeline))
- end
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to render_template :show
end
end
- it 'redirects to the pipeline page with `failures` query param' do
- get :failures, params: { namespace_id: project.namespace, project_id: project, id: pipeline }
+ context 'without failed jobs' do
+ it 'redirects to the main pipeline page' do
+ get :failures, params: { namespace_id: project.namespace, project_id: project, id: pipeline }
- expect(response).to redirect_to(pipeline_path(pipeline, tab: 'failures'))
+ expect(response).to redirect_to(pipeline_path(pipeline))
+ end
end
end
diff --git a/spec/controllers/projects/product_analytics_controller_spec.rb b/spec/controllers/projects/product_analytics_controller_spec.rb
deleted file mode 100644
index 47f1d96c70b..00000000000
--- a/spec/controllers/projects/product_analytics_controller_spec.rb
+++ /dev/null
@@ -1,95 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Projects::ProductAnalyticsController do
- let_it_be(:project) { create(:project) }
- let_it_be(:user) { create(:user) }
-
- before(:all) do
- project.add_maintainer(user)
- end
-
- before do
- sign_in(user)
- stub_feature_flags(product_analytics: true)
- end
-
- describe 'GET #index' do
- it 'renders index with 200 status code' do
- get :index, params: project_params
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template(:index)
- end
-
- context 'with an anonymous user' do
- before do
- sign_out(user)
- end
-
- it 'redirects to sign-in page' do
- get :index, params: project_params
-
- expect(response).to redirect_to(new_user_session_path)
- end
- end
-
- context 'feature flag disabled' do
- before do
- stub_feature_flags(product_analytics: false)
- end
-
- it 'returns not found' do
- get :index, params: project_params
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
-
- describe 'GET #test' do
- it 'renders test with 200 status code' do
- get :test, params: project_params
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template(:test)
- end
- end
-
- describe 'GET #setup' do
- it 'renders setup with 200 status code' do
- get :setup, params: project_params
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template(:setup)
- end
- end
-
- describe 'GET #graphs' do
- it 'renders graphs with 200 status code' do
- get :graphs, params: project_params
-
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to render_template(:graphs)
- end
-
- context 'feature flag disabled' do
- before do
- stub_feature_flags(product_analytics: false)
- end
-
- it 'returns not found' do
- get :graphs, params: project_params
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
- end
-
- private
-
- def project_params(opts = {})
- opts.reverse_merge(namespace_id: project.namespace, project_id: project)
- end
-end
diff --git a/spec/controllers/projects/prometheus/alerts_controller_spec.rb b/spec/controllers/projects/prometheus/alerts_controller_spec.rb
index 2c2c8180143..09b9f25c0c6 100644
--- a/spec/controllers/projects/prometheus/alerts_controller_spec.rb
+++ b/spec/controllers/projects/prometheus/alerts_controller_spec.rb
@@ -56,7 +56,7 @@ RSpec.describe Projects::Prometheus::AlertsController do
describe 'POST #notify' do
let(:alert_1) { build(:alert_management_alert, :prometheus, project: project) }
let(:alert_2) { build(:alert_management_alert, :prometheus, project: project) }
- let(:service_response) { ServiceResponse.success(payload: { alerts: [alert_1, alert_2] }) }
+ let(:service_response) { ServiceResponse.success(http_status: :created) }
let(:notify_service) { instance_double(Projects::Prometheus::Alerts::NotifyService, execute: service_response) }
before do
@@ -68,17 +68,12 @@ RSpec.describe Projects::Prometheus::AlertsController do
.and_return(notify_service)
end
- it 'returns ok if notification succeeds' do
+ it 'returns created if notification succeeds' do
expect(notify_service).to receive(:execute).and_return(service_response)
post :notify, params: project_params, session: { as: :json }
- expect(json_response).to contain_exactly(
- { 'iid' => alert_1.iid, 'title' => alert_1.title },
- { 'iid' => alert_2.iid, 'title' => alert_2.title }
- )
-
- expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to have_gitlab_http_status(:created)
end
it 'returns unprocessable entity if notification fails' do
diff --git a/spec/controllers/projects/registry/repositories_controller_spec.rb b/spec/controllers/projects/registry/repositories_controller_spec.rb
index a5faaaf5969..f4f5c182850 100644
--- a/spec/controllers/projects/registry/repositories_controller_spec.rb
+++ b/spec/controllers/projects/registry/repositories_controller_spec.rb
@@ -103,10 +103,11 @@ RSpec.describe Projects::Registry::RepositoriesController do
stub_container_registry_tags(repository: :any, tags: [])
end
- it 'schedules a job to delete a repository' do
- expect(DeleteContainerRepositoryWorker).to receive(:perform_async).with(user.id, repository.id)
+ it 'marks the repository as delete_scheduled' do
+ expect(DeleteContainerRepositoryWorker).not_to receive(:perform_async).with(user.id, repository.id)
- delete_repository(repository)
+ expect { delete_repository(repository) }
+ .to change { repository.reload.status }.from(nil).to('delete_scheduled')
expect(repository.reload).to be_delete_scheduled
expect(response).to have_gitlab_http_status(:no_content)
@@ -119,6 +120,22 @@ RSpec.describe Projects::Registry::RepositoriesController do
expect_snowplow_event(category: anything, action: 'delete_repository')
end
+
+ context 'with container_registry_delete_repository_with_cron_worker disabled' do
+ before do
+ stub_feature_flags(container_registry_delete_repository_with_cron_worker: false)
+ end
+
+ it 'schedules a job to delete a repository' do
+ expect(DeleteContainerRepositoryWorker).to receive(:perform_async).with(user.id, repository.id)
+
+ expect { delete_repository(repository) }
+ .to change { repository.reload.status }.from(nil).to('delete_scheduled')
+
+ expect(repository.reload).to be_delete_scheduled
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
+ end
end
end
end
@@ -137,7 +154,7 @@ RSpec.describe Projects::Registry::RepositoriesController do
end
end
- def go_to_index(format: :html, params: {} )
+ def go_to_index(format: :html, params: {})
get :index, params: params.merge({
namespace_id: project.namespace,
project_id: project
diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb
index b307bb357fa..2afd080344d 100644
--- a/spec/controllers/projects/releases_controller_spec.rb
+++ b/spec/controllers/projects/releases_controller_spec.rb
@@ -112,7 +112,7 @@ RSpec.describe Projects::ReleasesController do
it "returns the project's releases as JSON, ordered by released_at" do
get_index
- expect(json_response.map { |release| release["id"] } ).to eq([release_2.id, release_1.id])
+ expect(json_response.map { |release| release["id"] }).to eq([release_2.id, release_1.id])
end
it_behaves_like 'common access controls'
diff --git a/spec/controllers/projects/runners_controller_spec.rb b/spec/controllers/projects/runners_controller_spec.rb
index 57d1695b842..1066c4ec9f6 100644
--- a/spec/controllers/projects/runners_controller_spec.rb
+++ b/spec/controllers/projects/runners_controller_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe Projects::RunnersController do
new_desc = runner.description.swapcase
expect do
- post :update, params: params.merge(runner: { description: new_desc } )
+ post :update, params: params.merge(runner: { description: new_desc })
end.to change { runner.ensure_runner_queue_value }
runner.reload
diff --git a/spec/controllers/projects/settings/integrations_controller_spec.rb b/spec/controllers/projects/settings/integrations_controller_spec.rb
index b76269f6f93..2b23f177a9d 100644
--- a/spec/controllers/projects/settings/integrations_controller_spec.rb
+++ b/spec/controllers/projects/settings/integrations_controller_spec.rb
@@ -334,6 +334,23 @@ RSpec.describe Projects::Settings::IntegrationsController do
)
end
end
+
+ context 'with chat notification integration' do
+ let_it_be(:integration) { project.create_microsoft_teams_integration(webhook: 'http://webhook.com') }
+ let(:message) { 'Microsoft Teams notifications settings saved and active.' }
+
+ it_behaves_like 'integration update'
+
+ context 'with masked token' do
+ let(:integration_params) { { active: true, webhook: '************' } }
+
+ it_behaves_like 'integration update'
+
+ it 'does not update the webhook' do
+ expect(integration.reload.webhook).to eq('http://webhook.com')
+ end
+ end
+ end
end
describe 'as JSON' do
diff --git a/spec/controllers/projects/settings/repository_controller_spec.rb b/spec/controllers/projects/settings/repository_controller_spec.rb
index 22287fea82c..ea50ff6caa0 100644
--- a/spec/controllers/projects/settings/repository_controller_spec.rb
+++ b/spec/controllers/projects/settings/repository_controller_spec.rb
@@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe Projects::Settings::RepositoryController do
let(:project) { create(:project_empty_repo, :public) }
let(:user) { create(:user) }
+ let(:base_params) { { namespace_id: project.namespace, project_id: project } }
before do
project.add_maintainer(user)
@@ -13,7 +14,7 @@ RSpec.describe Projects::Settings::RepositoryController do
describe 'GET show' do
it 'renders show with 200 status code' do
- get :show, params: { namespace_id: project.namespace, project_id: project }
+ get :show, params: base_params
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:show)
@@ -29,7 +30,7 @@ RSpec.describe Projects::Settings::RepositoryController do
.with(project, user, anything)
.and_return(status: :success)
- put :cleanup, params: { namespace_id: project.namespace, project_id: project, project: { bfg_object_map: object_map } }
+ put :cleanup, params: base_params.merge({ project: { bfg_object_map: object_map } })
expect(response).to redirect_to project_settings_repository_path(project)
end
@@ -41,7 +42,7 @@ RSpec.describe Projects::Settings::RepositoryController do
.with(project, user, anything)
.and_return(status: :error, message: 'error message')
- put :cleanup, params: { namespace_id: project.namespace, project_id: project, project: { bfg_object_map: object_map } }
+ put :cleanup, params: base_params.merge({ project: { bfg_object_map: object_map } })
expect(controller).to set_flash[:alert].to('error message')
expect(response).to redirect_to project_settings_repository_path(project)
@@ -50,83 +51,138 @@ RSpec.describe Projects::Settings::RepositoryController do
end
describe 'POST create_deploy_token' do
- context 'when ajax_new_deploy_token feature flag is disabled for the project' do
- before do
- stub_feature_flags(ajax_new_deploy_token: false)
+ let(:good_deploy_token_params) do
+ {
+ name: 'name',
+ expires_at: 1.day.from_now.to_s,
+ username: 'deployer',
+ read_repository: '1',
+ deploy_token_type: DeployToken.deploy_token_types[:project_type]
+ }
+ end
+
+ let(:request_params) { base_params.merge({ deploy_token: deploy_token_params }) }
+
+ subject { post :create_deploy_token, params: request_params, format: :json }
+
+ context('a good request') do
+ let(:deploy_token_params) { good_deploy_token_params }
+ let(:expected_response) do
+ {
+ 'id' => be_a(Integer),
+ 'name' => deploy_token_params[:name],
+ 'username' => deploy_token_params[:username],
+ 'expires_at' => Time.zone.parse(deploy_token_params[:expires_at]),
+ 'token' => be_a(String),
+ 'expired' => false,
+ 'revoked' => false,
+ 'scopes' => deploy_token_params.inject([]) do |scopes, kv|
+ key, value = kv
+ key.to_s.start_with?('read_') && value.to_i != 0 ? scopes << key.to_s : scopes
+ end
+ }
end
- it_behaves_like 'a created deploy token' do
- let(:entity) { project }
- let(:create_entity_params) { { namespace_id: project.namespace, project_id: project } }
- let(:deploy_token_type) { DeployToken.deploy_token_types[:project_type] }
+ it 'creates the deploy token' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('public_api/v4/deploy_token')
+ expect(json_response).to match(expected_response)
end
end
- context 'when ajax_new_deploy_token feature flag is enabled for the project' do
- let(:good_deploy_token_params) do
- {
- name: 'name',
- expires_at: 1.day.from_now.to_s,
- username: 'deployer',
- read_repository: '1',
- deploy_token_type: DeployToken.deploy_token_types[:project_type]
- }
+ context('a bad request') do
+ let(:deploy_token_params) { good_deploy_token_params.except(:read_repository) }
+ let(:expected_response) { { 'message' => "Scopes can't be blank" } }
+
+ it 'does not create the deploy token' do
+ subject
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response).to match(expected_response)
end
+ end
- let(:request_params) do
- {
- namespace_id: project.namespace.to_param,
- project_id: project.to_param,
- deploy_token: deploy_token_params
- }
+ context('an invalid request') do
+ let(:deploy_token_params) { good_deploy_token_params.except(:name) }
+
+ it 'raises a validation error' do
+ expect { subject }.to raise_error(ActiveRecord::StatementInvalid)
end
+ end
+ end
- subject { post :create_deploy_token, params: request_params, format: :json }
-
- context('a good request') do
- let(:deploy_token_params) { good_deploy_token_params }
- let(:expected_response) do
- {
- 'id' => be_a(Integer),
- 'name' => deploy_token_params[:name],
- 'username' => deploy_token_params[:username],
- 'expires_at' => Time.zone.parse(deploy_token_params[:expires_at]),
- 'token' => be_a(String),
- 'expired' => false,
- 'revoked' => false,
- 'scopes' => deploy_token_params.inject([]) do |scopes, kv|
- key, value = kv
- key.to_s.start_with?('read_') && value.to_i != 0 ? scopes << key.to_s : scopes
- end
- }
+ describe 'PUT update' do
+ let(:project) { create(:project, :repository) }
+
+ context 'when updating default branch' do
+ let!(:previous_default_branch) { project.default_branch }
+
+ let(:new_default_branch) { 'feature' }
+ let(:request_params) { base_params.merge({ project: project_params_attributes }) }
+
+ subject { put :update, params: request_params }
+
+ context('with a good request') do
+ let(:project_params_attributes) { { default_branch: new_default_branch } }
+
+ it "updates default branch and redirect to project_settings_repository_path" do
+ expect do
+ subject
+ end.to change {
+ Project.find(project.id).default_branch # refind to reset the default branch cache
+ }.from(previous_default_branch).to(new_default_branch)
+
+ expect(response).to redirect_to project_settings_repository_path(project)
+ expect(controller).to set_flash[:notice].to("Project settings were successfully updated.")
end
+ end
- it 'creates the deploy token' do
- subject
+ context('with a bad input') do
+ let(:project_params_attributes) { { default_branch: 'non_existent_branch' } }
- expect(response).to have_gitlab_http_status(:created)
- expect(response).to match_response_schema('public_api/v4/deploy_token')
- expect(json_response).to match(expected_response)
+ it "does not update default branch and shows an alert" do
+ expect do
+ subject
+ end.not_to change {
+ Project.find(project.id).default_branch # refind to reset the default branch cache
+ }
+
+ expect(response).to redirect_to project_settings_repository_path(project)
+ expect(controller).to set_flash[:alert].to("Could not set the default branch")
end
end
+ end
+
+ context 'when updating branch names template from issues' do
+ let(:branch_name_template) { 'feat/GL-%{id}-%{title}' }
- context('a bad request') do
- let(:deploy_token_params) { good_deploy_token_params.except(:read_repository) }
- let(:expected_response) { { 'message' => "Scopes can't be blank" } }
+ let(:request_params) { base_params.merge({ project: project_params_attributes }) }
- it 'does not create the deploy token' do
+ subject { put :update, params: request_params }
+
+ context('with a good request') do
+ let(:project_params_attributes) { { issue_branch_template: branch_name_template } }
+
+ it "updates issue_branch_template and redirect to project_settings_repository_path" do
subject
- expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response).to match(expected_response)
+ expect(response).to redirect_to project_settings_repository_path(project)
+ expect(controller).to set_flash[:notice].to("Project settings were successfully updated.")
+ expect(project.reload.issue_branch_template).to eq(branch_name_template)
end
end
- context('an invalid request') do
- let(:deploy_token_params) { good_deploy_token_params.except(:name) }
+ context('with a bad input') do
+ let(:project_params_attributes) { { issue_branch_template: 'a' * 260 } }
+
+ it "updates issue_branch_template and redirect to project_settings_repository_path" do
+ subject
- it 'raises a validation error' do
- expect { subject }.to raise_error(ActiveRecord::StatementInvalid)
+ expect(response).to redirect_to project_settings_repository_path(project)
+ expect(controller).to set_flash[:alert].to("Project setting issue branch template is too long (maximum is 255 characters)")
+ expect(project.reload.issue_branch_template).to eq(nil)
end
end
end
diff --git a/spec/controllers/projects/starrers_controller_spec.rb b/spec/controllers/projects/starrers_controller_spec.rb
index 8d03600cd58..2148f495c31 100644
--- a/spec/controllers/projects/starrers_controller_spec.rb
+++ b/spec/controllers/projects/starrers_controller_spec.rb
@@ -6,6 +6,7 @@ RSpec.describe Projects::StarrersController do
let(:user_1) { create(:user, name: 'John') }
let(:user_2) { create(:user, name: 'Michael') }
let(:private_user) { create(:user, name: 'Michael Douglas', private_profile: true) }
+ let(:blocked_user) { create(:user, state: 'blocked') }
let(:admin) { create(:user, admin: true) }
let(:project) { create(:project, :public) }
@@ -13,6 +14,7 @@ RSpec.describe Projects::StarrersController do
user_1.toggle_star(project)
user_2.toggle_star(project)
private_user.toggle_star(project)
+ blocked_user.toggle_star(project)
end
describe 'GET index' do
@@ -61,6 +63,10 @@ RSpec.describe Projects::StarrersController do
expect(user_ids).to contain_exactly(user_1.id, user_2.id)
end
+ it 'non-active users are not visible' do
+ expect(user_ids).not_to include(blocked_user.id)
+ end
+
include_examples 'starrers counts'
end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index b5797e374f3..446e5e38865 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -921,6 +921,7 @@ RSpec.describe ProjectsController do
feature_flags_access_level
releases_access_level
monitor_access_level
+ infrastructure_access_level
]
end
diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb
index 637c774c38b..8775f68a5de 100644
--- a/spec/controllers/registrations_controller_spec.rb
+++ b/spec/controllers/registrations_controller_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe RegistrationsController do
include TermsHelper
+ include FullNameHelper
before do
stub_application_setting(require_admin_approval_after_user_signup: false)
@@ -18,6 +19,8 @@ RSpec.describe RegistrationsController do
expect(response).to have_gitlab_http_status(:ok)
expect(assigns(:resource)).to be_a(User)
end
+
+ it_behaves_like "switches to user preferred language", 'Sign up'
end
describe '#create' do
@@ -463,7 +466,7 @@ RSpec.describe RegistrationsController do
expect(User.last.first_name).to eq(base_user_params[:first_name])
expect(User.last.last_name).to eq(base_user_params[:last_name])
- expect(User.last.name).to eq("#{base_user_params[:first_name]} #{base_user_params[:last_name]}")
+ expect(User.last.name).to eq full_name(base_user_params[:first_name], base_user_params[:last_name])
end
it 'sets the caller_id in the context' do
@@ -477,28 +480,6 @@ RSpec.describe RegistrationsController do
subject
end
- describe 'logged_out_marketing_header experiment', :experiment do
- before do
- stub_experiments(logged_out_marketing_header: :candidate)
- end
-
- it 'tracks signed_up event' do
- expect(experiment(:logged_out_marketing_header)).to track(:signed_up).on_next_instance
-
- subject
- end
-
- context 'when registration fails' do
- let_it_be(:user_params) { { user: base_user_params.merge({ username: '' }) } }
-
- it 'does not track signed_up event' do
- expect(experiment(:logged_out_marketing_header)).not_to track(:signed_up)
-
- subject
- end
- end
- end
-
context 'when the password is weak' do
render_views
let_it_be(:new_user_params) { { new_user: base_user_params.merge({ password: "password" }) } }
@@ -513,6 +494,16 @@ RSpec.describe RegistrationsController do
expect(response).to render_template(:new)
expect(response.body).to include(_('Password must not contain commonly used combinations of words and letters'))
end
+
+ it 'tracks the error' do
+ subject
+ expect_snowplow_event(
+ category: 'Gitlab::Tracking::Helpers::WeakPasswordErrorEvent',
+ action: 'track_weak_password_error',
+ controller: 'RegistrationsController',
+ method: 'create'
+ )
+ end
end
context 'when block_weak_passwords is disabled' do
@@ -525,6 +516,42 @@ RSpec.describe RegistrationsController do
end
end
end
+
+ context 'when the password is not weak' do
+ it 'does not track a weak password error' do
+ subject
+ expect_no_snowplow_event(
+ category: 'Gitlab::Tracking::Helpers::WeakPasswordErrorEvent',
+ action: 'track_weak_password_error'
+ )
+ end
+ end
+
+ context 'with preferred language' do
+ let(:user_preferred_language) { nil }
+
+ before do
+ cookies['preferred_language'] = user_preferred_language
+
+ post :create, params: { new_user: base_user_params }
+ end
+
+ subject { User.last.preferred_language }
+
+ context 'with default behavior' do
+ it 'sets preferred language to default' do
+ is_expected.to eq(Gitlab::CurrentSettings.default_preferred_language)
+ end
+ end
+
+ context 'when user sets preferred language' do
+ let(:user_preferred_language) { 'zh_CN' }
+
+ it 'sets name from first and last name' do
+ is_expected.to eq(user_preferred_language)
+ end
+ end
+ end
end
describe '#destroy' do
diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb
index 392dc2229aa..21df53fb074 100644
--- a/spec/controllers/search_controller_spec.rb
+++ b/spec/controllers/search_controller_spec.rb
@@ -223,7 +223,14 @@ RSpec.describe SearchController do
let(:project) { nil }
let(:category) { described_class.to_s }
- let(:action) { 'i_search_total' }
+ let(:action) { 'executed' }
+ 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]
+ end
+
let(:namespace) { create(:group) }
let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
end
diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb
index 80cf060bc45..69282f951f9 100644
--- a/spec/controllers/sessions_controller_spec.rb
+++ b/spec/controllers/sessions_controller_spec.rb
@@ -69,6 +69,8 @@ RSpec.describe SessionsController do
expect(controller.stored_location_for(:redirect)).to eq(search_path)
end
+
+ it_behaves_like "switches to user preferred language", 'Sign in'
end
describe '#create' do
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb
index 4aeafed5712..ad49a763361 100644
--- a/spec/db/schema_spec.rb
+++ b/spec/db/schema_spec.rb
@@ -14,8 +14,10 @@ RSpec.describe 'Database schema' do
issues: %w[work_item_type_id]
}.with_indifferent_access.freeze
+ TABLE_PARTITIONS = %w[ci_builds_metadata].freeze
+
# List of columns historically missing a FK, don't add more columns
- # See: https://docs.gitlab.com/ee/development/foreign_keys.html#naming-foreign-keys
+ # See: https://docs.gitlab.com/ee/development/database/foreign_keys.html#naming-foreign-keys
IGNORED_FK_COLUMNS = {
abuse_reports: %w[reporter_id user_id],
application_settings: %w[performance_bar_allowed_group_id slack_app_id snowplow_app_id eks_account_id eks_access_key_id],
@@ -32,7 +34,7 @@ RSpec.describe 'Database schema' do
chat_names: %w[chat_id team_id user_id],
chat_teams: %w[team_id],
ci_builds: %w[erased_by_id trigger_request_id partition_id],
- ci_builds_metadata: %w[partition_id],
+ p_ci_builds_metadata: %w[partition_id],
ci_job_artifacts: %w[partition_id],
ci_namespace_monthly_usages: %w[namespace_id],
ci_pipeline_variables: %w[partition_id],
@@ -107,7 +109,7 @@ RSpec.describe 'Database schema' do
}.with_indifferent_access.freeze
context 'for table' do
- ActiveRecord::Base.connection.tables.sort.each do |table|
+ (ActiveRecord::Base.connection.tables - TABLE_PARTITIONS).sort.each do |table|
describe table do
let(:indexes) { connection.indexes(table) }
let(:columns) { connection.columns(table) }
@@ -213,6 +215,7 @@ RSpec.describe 'Database schema' do
"ApplicationSetting" => %w[repository_storages_weighted],
"AlertManagement::Alert" => %w[payload],
"Ci::BuildMetadata" => %w[config_options config_variables],
+ "Ci::BuildMetadata::Partitioned" => %w[config_options config_variables id_tokens runtime_runner_features secrets],
"ExperimentSubject" => %w[context],
"ExperimentUser" => %w[context],
"Geo::Event" => %w[payload],
diff --git a/spec/experiments/application_experiment_spec.rb b/spec/experiments/application_experiment_spec.rb
index b144e6f77d2..7aca5e492f4 100644
--- a/spec/experiments/application_experiment_spec.rb
+++ b/spec/experiments/application_experiment_spec.rb
@@ -43,72 +43,6 @@ RSpec.describe ApplicationExperiment, :experiment do
variant: 'control'
)
end
-
- describe '#publish_to_database' do
- using RSpec::Parameterized::TableSyntax
-
- let(:publish_to_database) { ActiveSupport::Deprecation.silence { application_experiment.publish_to_database } }
-
- shared_examples 'does not record to the database' do
- it 'does not create an experiment record' do
- expect { publish_to_database }.not_to change(Experiment, :count)
- end
-
- it 'does not create an experiment subject record' do
- expect { publish_to_database }.not_to change(ExperimentSubject, :count)
- end
- end
-
- context 'when there is a usable subject' do
- let(:context) { { context_key => context_value } }
-
- where(:context_key, :context_value, :object_type) do
- :namespace | build(:namespace, id: non_existing_record_id) | :namespace
- :group | build(:namespace, id: non_existing_record_id) | :namespace
- :project | build(:project, id: non_existing_record_id) | :project
- :user | build(:user, id: non_existing_record_id) | :user
- :actor | build(:user, id: non_existing_record_id) | :user
- end
-
- with_them do
- it 'creates an experiment and experiment subject record' do
- expect { publish_to_database }.to change(Experiment, :count).by(1)
-
- expect(Experiment.last.name).to eq('namespaced/stub')
- expect(ExperimentSubject.last.send(object_type)).to eq(context[context_key])
- end
- end
- end
-
- context "when experiment hasn't ran" do
- let(:context) { { user: create(:user) } }
-
- it 'sets a variant on the experiment subject' do
- publish_to_database
-
- expect(ExperimentSubject.last.variant).to eq('control')
- end
- end
-
- context 'when there is not a usable subject' do
- let(:context) { { context_key => context_value } }
-
- where(:context_key, :context_value) do
- :namespace | nil
- :foo | :bar
- end
-
- with_them do
- include_examples 'does not record to the database'
- end
- end
-
- context 'but we should not track' do
- let(:should_track) { false }
-
- include_examples 'does not record to the database'
- end
- end
end
describe "#track", :snowplow do
diff --git a/spec/experiments/require_verification_for_namespace_creation_experiment_spec.rb b/spec/experiments/require_verification_for_namespace_creation_experiment_spec.rb
index 269b6222020..c91a8f1950e 100644
--- a/spec/experiments/require_verification_for_namespace_creation_experiment_spec.rb
+++ b/spec/experiments/require_verification_for_namespace_creation_experiment_spec.rb
@@ -30,34 +30,6 @@ RSpec.describe RequireVerificationForNamespaceCreationExperiment, :experiment do
end
end
- describe '#record_conversion' do
- let_it_be(:namespace) { create(:namespace) }
-
- context 'when should_track? is false' do
- before do
- allow(experiment).to receive(:should_track?).and_return(false)
- end
-
- it 'does not record a conversion event' do
- expect(experiment.publish_to_database).to be_nil
- expect(experiment.record_conversion(namespace)).to be_nil
- end
- end
-
- context 'when should_track? is true' do
- before do
- allow(experiment).to receive(:should_track?).and_return(true)
- end
-
- it 'records a conversion event' do
- experiment_subject = experiment.publish_to_database
-
- expect { experiment.record_conversion(namespace) }.to change { experiment_subject.reload.converted_at }.from(nil)
- .and change { experiment_subject.context }.to include('namespace_id' => namespace.id)
- end
- end
- end
-
describe 'exclusions' do
context 'when user is new' do
it 'is not excluded' do
diff --git a/spec/experiments/security_reports_mr_widget_prompt_experiment_spec.rb b/spec/experiments/security_reports_mr_widget_prompt_experiment_spec.rb
index 4328ff12d42..ee02fa5f1f2 100644
--- a/spec/experiments/security_reports_mr_widget_prompt_experiment_spec.rb
+++ b/spec/experiments/security_reports_mr_widget_prompt_experiment_spec.rb
@@ -6,10 +6,4 @@ RSpec.describe SecurityReportsMrWidgetPromptExperiment do
it "defines a control and candidate" do
expect(subject.behaviors.keys).to match_array(%w[control candidate])
end
-
- it "publishes to the database" do
- expect(subject).to receive(:publish_to_database)
-
- subject.publish
- end
end
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 9a3b2837ab8..b88d6b5fda4 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -24,6 +24,16 @@ FactoryBot.define do
project { pipeline.project }
+ trait :with_token do
+ transient do
+ generate_token { true }
+ end
+
+ after(:build) do |build, evaluator|
+ build.ensure_token if evaluator.generate_token
+ end
+ end
+
trait :degenerated do
options { nil }
yaml_variables { nil }
@@ -93,6 +103,7 @@ FactoryBot.define do
end
trait :pending do
+ with_token
queued_at { 'Di 29. Okt 09:50:59 CET 2013' }
status { 'pending' }
@@ -100,6 +111,7 @@ FactoryBot.define do
trait :created do
status { 'created' }
+ generate_token { false }
end
trait :preparing do
@@ -303,14 +315,11 @@ FactoryBot.define do
# Build deployment/environment relations if environment name is set
# to the job. If `build.deployment` has already been set, it doesn't
# build a new instance.
- environment = Gitlab::Ci::Pipeline::Seed::Environment.new(build).to_resource
+ Environments::CreateForBuildService.new.execute(build)
+ end
- build.assign_attributes(
- deployment: Gitlab::Ci::Pipeline::Seed::Deployment.new(build, environment).to_resource,
- metadata_attributes: {
- expanded_environment_name: environment.name
- }
- )
+ after(:create) do |build, evaluator|
+ Deployments::CreateForBuildService.new.execute(build)
end
end
@@ -716,7 +725,7 @@ FactoryBot.define do
trait :with_runner_session do
after(:build) do |build|
- build.build_runner_session(url: 'https://localhost')
+ build.build_runner_session(url: 'https://gitlab.example.com')
end
end
diff --git a/spec/factories/ci/job_artifacts.rb b/spec/factories/ci/job_artifacts.rb
index 304d77e8521..7569e832c60 100644
--- a/spec/factories/ci/job_artifacts.rb
+++ b/spec/factories/ci/job_artifacts.rb
@@ -20,6 +20,8 @@ FactoryBot.define do
after :build do |artifact|
artifact.project ||= artifact.job.project
+
+ artifact.job&.valid?
end
trait :raw do
diff --git a/spec/factories/ci/pipeline_metadata.rb b/spec/factories/ci/pipeline_metadata.rb
index 600cfaa92c6..7849fa1fd4b 100644
--- a/spec/factories/ci/pipeline_metadata.rb
+++ b/spec/factories/ci/pipeline_metadata.rb
@@ -2,7 +2,7 @@
FactoryBot.define do
factory :ci_pipeline_metadata, class: 'Ci::PipelineMetadata' do
- title { 'Pipeline title' }
+ name { 'Pipeline name' }
pipeline factory: :ci_empty_pipeline
project
diff --git a/spec/factories/ci/pipelines.rb b/spec/factories/ci/pipelines.rb
index 650b8647237..891628a0fc2 100644
--- a/spec/factories/ci/pipelines.rb
+++ b/spec/factories/ci/pipelines.rb
@@ -8,7 +8,7 @@ FactoryBot.define do
sha { 'b83d6e391c22777fca1ed3012fce84f633d7fed0' }
status { 'pending' }
add_attribute(:protected) { false }
- partition_id { 1234 }
+ partition_id { 100 }
project
@@ -19,7 +19,7 @@ FactoryBot.define do
transient { child_of { nil } }
transient { upstream_of { nil } }
- transient { title { nil } }
+ transient { name { nil } }
after(:build) do |pipeline, evaluator|
if evaluator.child_of
@@ -29,8 +29,8 @@ FactoryBot.define do
pipeline.ensure_project_iid!
- if evaluator.title
- pipeline.pipeline_metadata = build(:ci_pipeline_metadata, title: evaluator.title, project: pipeline.project, pipeline: pipeline)
+ if evaluator.name
+ pipeline.pipeline_metadata = build(:ci_pipeline_metadata, name: evaluator.name, project: pipeline.project, pipeline: pipeline)
end
end
@@ -54,7 +54,7 @@ FactoryBot.define do
end
factory :ci_pipeline do
- partition_id { 1234 }
+ partition_id { 100 }
transient { ci_ref_presence { true } }
before(:create) do |pipeline, evaluator|
diff --git a/spec/factories/ci/processable.rb b/spec/factories/ci/processable.rb
index 0550f4c23fa..76c7376d24a 100644
--- a/spec/factories/ci/processable.rb
+++ b/spec/factories/ci/processable.rb
@@ -4,7 +4,7 @@ FactoryBot.define do
factory :ci_processable, class: 'Ci::Processable' do
name { 'processable' }
stage { 'test' }
- stage_idx { 0 }
+ stage_idx { ci_stage.try(:position) || 0 }
ref { 'master' }
tag { false }
pipeline factory: :ci_pipeline
diff --git a/spec/factories/ci/reports/codequality_degradations.rb b/spec/factories/ci/reports/codequality_degradations.rb
index 8b53f2bf46e..632f5a3ecaa 100644
--- a/spec/factories/ci/reports/codequality_degradations.rb
+++ b/spec/factories/ci/reports/codequality_degradations.rb
@@ -26,7 +26,8 @@ FactoryBot.define do
"remediation_points": 900000,
"severity": "major",
"type": "issue",
- "engine_name": "structure"
+ "engine_name": "structure",
+ "web_url": "http://localhost/root/test-project/-/blob/f572d396fae9206628714fb2ce00f72e94f2258f/file_a.rb#L10"
}.with_indifferent_access
end
end
@@ -56,7 +57,8 @@ FactoryBot.define do
"remediation_points": 900000,
"severity": "major",
"type": "issue",
- "engine_name": "structure"
+ "engine_name": "structure",
+ "web_url": "http://localhost/root/test-project/-/blob/f572d396fae9206628714fb2ce00f72e94f2258f/file_a.rb#L10"
}.with_indifferent_access
end
end
@@ -91,7 +93,8 @@ FactoryBot.define do
},
"engine_name": "rubocop",
"fingerprint": "ab5f8b935886b942d621399f5a2ca16e",
- "severity": "minor"
+ "severity": "minor",
+ "web_url": "http://localhost/root/test-project/-/blob/f572d396fae9206628714fb2ce00f72e94f2258f/file_b.rb#L10"
}.with_indifferent_access
end
end
diff --git a/spec/factories/ci/reports/sbom/components.rb b/spec/factories/ci/reports/sbom/components.rb
index fd9b4386130..8f2c00b695a 100644
--- a/spec/factories/ci/reports/sbom/components.rb
+++ b/spec/factories/ci/reports/sbom/components.rb
@@ -3,15 +3,29 @@
FactoryBot.define do
factory :ci_reports_sbom_component, class: '::Gitlab::Ci::Reports::Sbom::Component' do
type { "library" }
+
sequence(:name) { |n| "component-#{n}" }
sequence(:version) { |n| "v0.0.#{n}" }
+ transient do
+ purl_type { 'npm' }
+ end
+
+ purl do
+ ::Sbom::PackageUrl.new(
+ type: purl_type,
+ name: name,
+ version: version
+ ).to_s
+ end
+
skip_create
initialize_with do
::Gitlab::Ci::Reports::Sbom::Component.new(
type: type,
name: name,
+ purl: purl,
version: version
)
end
diff --git a/spec/factories/ci/reports/sbom/reports.rb b/spec/factories/ci/reports/sbom/reports.rb
index 4a83b5898ef..7a076282915 100644
--- a/spec/factories/ci/reports/sbom/reports.rb
+++ b/spec/factories/ci/reports/sbom/reports.rb
@@ -8,6 +8,12 @@ FactoryBot.define do
source { association :ci_reports_sbom_source }
end
+ trait :invalid do
+ after(:build) do |report, options|
+ report.add_error('This report is invalid because it contains errors.')
+ end
+ end
+
after(:build) do |report, options|
options.components.each { |component| report.add_component(component) }
report.set_source(options.source)
diff --git a/spec/factories/ci/secure_files.rb b/spec/factories/ci/secure_files.rb
index 74988202c71..31dbcd15cb1 100644
--- a/spec/factories/ci/secure_files.rb
+++ b/spec/factories/ci/secure_files.rb
@@ -13,4 +13,13 @@ FactoryBot.define do
end
end
end
+
+ factory :ci_secure_file_with_metadata, class: 'Ci::SecureFile' do
+ sequence(:name) { |n| "file#{n}.cer" }
+ file { fixture_file_upload('spec/fixtures/ci_secure_files/sample.cer', 'application/octet-stream') }
+ checksum { 'foo1234' }
+ project
+
+ after(:create, &:update_metadata!)
+ end
end
diff --git a/spec/factories/ci/stages.rb b/spec/factories/ci/stages.rb
index 41297b01f92..d9dff4d9a86 100644
--- a/spec/factories/ci/stages.rb
+++ b/spec/factories/ci/stages.rb
@@ -2,7 +2,7 @@
FactoryBot.define do
factory :ci_stage, class: 'Ci::Stage' do
- project factory: :project
+ project { pipeline.project }
pipeline factory: :ci_empty_pipeline
name { 'test' }
diff --git a/spec/factories/container_repositories.rb b/spec/factories/container_repositories.rb
index 210441430b0..66ac72fb5d7 100644
--- a/spec/factories/container_repositories.rb
+++ b/spec/factories/container_repositories.rb
@@ -21,6 +21,10 @@ FactoryBot.define do
status { :delete_failed }
end
+ trait :status_delete_ongoing do
+ status { :delete_ongoing }
+ end
+
trait :cleanup_scheduled do
expiration_policy_cleanup_status { :cleanup_scheduled }
end
diff --git a/spec/factories/dependency_proxy.rb b/spec/factories/dependency_proxy.rb
index afa6c61116a..33356a701df 100644
--- a/spec/factories/dependency_proxy.rb
+++ b/spec/factories/dependency_proxy.rb
@@ -4,13 +4,20 @@ FactoryBot.define do
factory :dependency_proxy_blob, class: 'DependencyProxy::Blob' do
group
size { 1234 }
- file { fixture_file_upload('spec/fixtures/dependency_proxy/a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4.gz') }
file_name { 'a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4.gz' }
status { :default }
+ after(:build) do |blob, _evaluator|
+ blob.file = fixture_file_upload('spec/fixtures/dependency_proxy/a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4.gz')
+ end
+
trait :pending_destruction do
status { :pending_destruction }
end
+
+ trait :remote_store do
+ file_store { DependencyProxy::FileUploader::Store::REMOTE }
+ end
end
factory :dependency_proxy_manifest, class: 'DependencyProxy::Manifest' do
diff --git a/spec/factories/experiment_subjects.rb b/spec/factories/experiment_subjects.rb
deleted file mode 100644
index c35bc370bad..00000000000
--- a/spec/factories/experiment_subjects.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :experiment_subject do
- experiment
- user
- variant { :control }
- end
-end
diff --git a/spec/factories/experiment_users.rb b/spec/factories/experiment_users.rb
deleted file mode 100644
index 66c39d684eb..00000000000
--- a/spec/factories/experiment_users.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :experiment_user do
- experiment
- user
- group_type { :control }
- converted_at { nil }
- end
-end
diff --git a/spec/factories/experiments.rb b/spec/factories/experiments.rb
deleted file mode 100644
index 2c51a6585f4..00000000000
--- a/spec/factories/experiments.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :experiment do
- name { generate(:title) }
- end
-end
diff --git a/spec/factories/integrations.rb b/spec/factories/integrations.rb
index 5ac26b7a260..ebbf1b560e5 100644
--- a/spec/factories/integrations.rb
+++ b/spec/factories/integrations.rb
@@ -43,6 +43,19 @@ FactoryBot.define do
end
end
+ factory :packagist_integration, class: 'Integrations::Packagist' do
+ project
+ type { 'Integrations::Packagist' }
+ active { true }
+ properties do
+ {
+ username: 'username',
+ token: 'test',
+ server: 'https://packagist.example.com'
+ }
+ end
+ end
+
factory :prometheus_integration, class: 'Integrations::Prometheus' do
project
active { true }
diff --git a/spec/factories/member_roles.rb b/spec/factories/member_roles.rb
index bd211844f5a..08df45a85f8 100644
--- a/spec/factories/member_roles.rb
+++ b/spec/factories/member_roles.rb
@@ -4,5 +4,7 @@ FactoryBot.define do
factory :member_role do
namespace { association(:group) }
base_access_level { Gitlab::Access::DEVELOPER }
+
+ trait(:guest) { base_access_level { GroupMember::GUEST } }
end
end
diff --git a/spec/factories/merge_request_reviewers.rb b/spec/factories/merge_request_reviewers.rb
new file mode 100644
index 00000000000..26e047a3fbf
--- /dev/null
+++ b/spec/factories/merge_request_reviewers.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :merge_request_reviewer do
+ merge_request
+ reviewer { association(:user) }
+ state { 'unreviewed' }
+ end
+end
diff --git a/spec/factories/packages/rpm/rpm_repository_files.rb b/spec/factories/packages/rpm/rpm_repository_files.rb
index 079d32b3995..00755f49d98 100644
--- a/spec/factories/packages/rpm/rpm_repository_files.rb
+++ b/spec/factories/packages/rpm/rpm_repository_files.rb
@@ -4,9 +4,10 @@ FactoryBot.define do
factory :rpm_repository_file, class: 'Packages::Rpm::RepositoryFile' do
project
- file_name { 'repomd.xml' }
+ file_name { '364c77dd49e8f814d56e621d0b3306c4fd0696dcad506f527329b818eb0f5db3-repomd.xml' }
file_sha1 { 'efae869b4e95d54796a46481f3a211d6a88d0323' }
file_md5 { 'ddf8a75330c896a8d7709e75f8b5982a' }
+ file_sha256 { '364c77dd49e8f814d56e621d0b3306c4fd0696dcad506f527329b818eb0f5db3' }
size { 3127.kilobytes }
status { :default }
@@ -15,7 +16,11 @@ FactoryBot.define do
end
transient do
- file_fixture { 'spec/fixtures/packages/rpm/repodata/repomd.xml' }
+ file_fixture do
+ # rubocop:disable Layout/LineLength
+ 'spec/fixtures/packages/rpm/repodata/364c77dd49e8f814d56e621d0b3306c4fd0696dcad506f527329b818eb0f5db3-repomd.xml'
+ # rubocop:enable Layout/LineLength
+ end
end
after(:build) do |package_file, evaluator|
diff --git a/spec/factories/project_hooks.rb b/spec/factories/project_hooks.rb
index dbb5c357acb..946b3925ee9 100644
--- a/spec/factories/project_hooks.rb
+++ b/spec/factories/project_hooks.rb
@@ -6,6 +6,10 @@ FactoryBot.define do
enable_ssl_verification { false }
project
+ trait :url_variables do
+ url_variables { { 'abc' => 'supers3cret' } }
+ end
+
trait :token do
token { generate(:token) }
end
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index b62995dce42..6e3a7a3f5ef 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -41,6 +41,7 @@ FactoryBot.define do
environments_access_level { ProjectFeature::ENABLED }
feature_flags_access_level { ProjectFeature::ENABLED }
releases_access_level { ProjectFeature::ENABLED }
+ infrastructure_access_level { ProjectFeature::ENABLED }
# we can't assign the delegated `#ci_cd_settings` attributes directly, as the
# `#ci_cd_settings` relation needs to be created first
@@ -251,6 +252,7 @@ FactoryBot.define do
transient do
create_templates { nil }
create_branch { nil }
+ create_tag { nil }
end
after :create do |project, evaluator|
@@ -287,6 +289,13 @@ FactoryBot.define do
end
+ if evaluator.create_tag
+ project.repository.add_tag(
+ project.creator,
+ evaluator.create_tag,
+ project.repository.commit.sha)
+ end
+
project.track_project_repository
end
end
@@ -467,6 +476,10 @@ FactoryBot.define do
end
end
+ trait :in_group do
+ namespace factory: [:group]
+ end
+
trait :in_subgroup do
namespace factory: [:group, :nested]
end
diff --git a/spec/factories/projects/import_export/export_relation.rb b/spec/factories/projects/import_export/export_relation.rb
deleted file mode 100644
index 2b6419dcecb..00000000000
--- a/spec/factories/projects/import_export/export_relation.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-FactoryBot.define do
- factory :project_relation_export, class: 'Projects::ImportExport::RelationExport' do
- project_export_job factory: :project_export_job
-
- relation { 'labels' }
- status { 0 }
- sequence(:jid) { |n| "project_relation_export_#{n}" }
- end
-end
diff --git a/spec/factories/projects/import_export/relation_export.rb b/spec/factories/projects/import_export/relation_export.rb
new file mode 100644
index 00000000000..7fab5808d2f
--- /dev/null
+++ b/spec/factories/projects/import_export/relation_export.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :project_relation_export, class: 'Projects::ImportExport::RelationExport' do
+ project_export_job factory: :project_export_job
+
+ relation { 'labels' }
+ status { Projects::ImportExport::RelationExport::STATUS[:queued] }
+ sequence(:jid) { |n| "project_relation_export_#{n}" }
+
+ trait :queued do
+ status { Projects::ImportExport::RelationExport::STATUS[:queued] }
+ end
+
+ trait :started do
+ status { Projects::ImportExport::RelationExport::STATUS[:started] }
+ end
+
+ trait :finished do
+ status { Projects::ImportExport::RelationExport::STATUS[:finished] }
+ end
+
+ trait :failed do
+ status { Projects::ImportExport::RelationExport::STATUS[:failed] }
+ end
+ end
+end
diff --git a/spec/factories/projects/import_export/relation_export_upload.rb b/spec/factories/projects/import_export/relation_export_upload.rb
new file mode 100644
index 00000000000..eaa57d6ee59
--- /dev/null
+++ b/spec/factories/projects/import_export/relation_export_upload.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :project_relation_export_upload, class: 'Projects::ImportExport::RelationExportUpload' do
+ relation_export factory: :project_relation_export
+ export_file { fixture_file_upload("spec/fixtures/gitlab/import_export/labels.tar.gz") }
+ end
+end
diff --git a/spec/factories/projects/wiki_repositories.rb b/spec/factories/projects/wiki_repositories.rb
new file mode 100644
index 00000000000..78e02ff297b
--- /dev/null
+++ b/spec/factories/projects/wiki_repositories.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :project_wiki_repository, class: 'Projects::WikiRepository' do
+ project
+ end
+end
diff --git a/spec/factories/protected_branches.rb b/spec/factories/protected_branches.rb
index 425352783dd..75b375733a6 100644
--- a/spec/factories/protected_branches.rb
+++ b/spec/factories/protected_branches.rb
@@ -13,7 +13,8 @@ FactoryBot.define do
end
after(:create) do |protected_branch, evaluator|
- break unless protected_branch.project&.persisted?
+ # Do not use `break` because it will cause `LocalJumpError`
+ next unless protected_branch.project&.persisted?
ProtectedBranches::CacheService.new(protected_branch.project).refresh
end
@@ -39,63 +40,63 @@ FactoryBot.define do
end
end
- trait :maintainers_can_push do
+ trait :no_one_can_merge do
transient do
- default_push_level { false }
+ default_merge_level { false }
end
after(:build) do |protected_branch|
- protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
+ protected_branch.merge_access_levels.new(access_level: Gitlab::Access::NO_ACCESS)
end
end
- trait :maintainers_can_merge do
+ trait :developers_can_merge do
transient do
- default_push_level { false }
+ default_merge_level { false }
end
after(:build) do |protected_branch|
- protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
+ protected_branch.merge_access_levels.new(access_level: Gitlab::Access::DEVELOPER)
end
end
- trait :developers_can_push do
+ trait :maintainers_can_merge do
transient do
- default_push_level { false }
+ default_merge_level { false }
end
after(:build) do |protected_branch|
- protected_branch.push_access_levels.new(access_level: Gitlab::Access::DEVELOPER)
+ protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
end
end
- trait :developers_can_merge do
+ trait :no_one_can_push do
transient do
- default_merge_level { false }
+ default_push_level { false }
end
after(:build) do |protected_branch|
- protected_branch.merge_access_levels.new(access_level: Gitlab::Access::DEVELOPER)
+ protected_branch.push_access_levels.new(access_level: Gitlab::Access::NO_ACCESS)
end
end
- trait :no_one_can_push do
+ trait :developers_can_push do
transient do
default_push_level { false }
end
after(:build) do |protected_branch|
- protected_branch.push_access_levels.new(access_level: Gitlab::Access::NO_ACCESS)
+ protected_branch.push_access_levels.new(access_level: Gitlab::Access::DEVELOPER)
end
end
- trait :no_one_can_merge do
+ trait :maintainers_can_push do
transient do
- default_merge_level { false }
+ default_push_level { false }
end
after(:build) do |protected_branch|
- protected_branch.merge_access_levels.new(access_level: Gitlab::Access::NO_ACCESS)
+ protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
end
end
end
diff --git a/spec/factories/user_statuses.rb b/spec/factories/user_statuses.rb
index dbed6031ce1..79dc1eb7931 100644
--- a/spec/factories/user_statuses.rb
+++ b/spec/factories/user_statuses.rb
@@ -5,5 +5,9 @@ FactoryBot.define do
user
emoji { 'coffee' }
message { 'I crave coffee' }
+
+ trait :busy do
+ availability { 'busy' }
+ end
end
end
diff --git a/spec/factories/users.rb b/spec/factories/users.rb
index 2e7c6116fe6..2b53a469841 100644
--- a/spec/factories/users.rb
+++ b/spec/factories/users.rb
@@ -27,6 +27,10 @@ FactoryBot.define do
after(:build) { |user, _| user.block! }
end
+ trait :locked do
+ after(:build) { |user, _| user.lock_access! }
+ end
+
trait :disallowed_password do
password { User::DISALLOWED_PASSWORDS.first }
end
diff --git a/spec/factories/users/ghost_user_migrations.rb b/spec/factories/users/ghost_user_migrations.rb
index 0fe7cded4f3..77b7f7e6df4 100644
--- a/spec/factories/users/ghost_user_migrations.rb
+++ b/spec/factories/users/ghost_user_migrations.rb
@@ -5,5 +5,6 @@ FactoryBot.define do
association :user
initiator_user { association(:user) }
hard_delete { false }
+ consume_after { Time.current }
end
end
diff --git a/spec/factories/users/namespace_commit_emails.rb b/spec/factories/users/namespace_commit_emails.rb
new file mode 100644
index 00000000000..2f7e89bf766
--- /dev/null
+++ b/spec/factories/users/namespace_commit_emails.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+FactoryBot.define do
+ factory :namespace_commit_email, class: 'Users::NamespaceCommitEmail' do
+ email
+ user { email.user }
+ namespace
+ end
+end
diff --git a/spec/features/admin/admin_dev_ops_reports_spec.rb b/spec/features/admin/admin_dev_ops_reports_spec.rb
index bf32819cb52..f65862c568f 100644
--- a/spec/features/admin/admin_dev_ops_reports_spec.rb
+++ b/spec/features/admin/admin_dev_ops_reports_spec.rb
@@ -9,9 +9,9 @@ RSpec.describe 'DevOps Report page', :js do
gitlab_enable_admin_mode_sign_in(admin)
end
- context 'with devops_adoption feature flag disabled' do
+ context 'without licensed feature devops adoption' do
before do
- stub_feature_flags(devops_adoption: false)
+ stub_licensed_features(devops_adoption: false)
end
it 'has dismissable intro callout' do
diff --git a/spec/features/admin/admin_hook_logs_spec.rb b/spec/features/admin/admin_hook_logs_spec.rb
index 6caf2b24555..a2ee6343886 100644
--- a/spec/features/admin/admin_hook_logs_spec.rb
+++ b/spec/features/admin/admin_hook_logs_spec.rb
@@ -3,12 +3,11 @@
require 'spec_helper'
RSpec.describe 'Admin::HookLogs' do
- let(:project) { create(:project) }
- let(:system_hook) { create(:system_hook) }
- let(:hook_log) { create(:web_hook_log, web_hook: system_hook, internal_error_message: 'some error') }
+ let_it_be(:system_hook) { create(:system_hook) }
+ let_it_be(:hook_log) { create(:web_hook_log, web_hook: system_hook, internal_error_message: 'some error') }
+ let_it_be(:admin) { create(:admin) }
before do
- admin = create(:admin)
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
end
diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb
index 901315752d6..dc5b0ae009e 100644
--- a/spec/features/admin/admin_hooks_spec.rb
+++ b/spec/features/admin/admin_hooks_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Admin::Hooks' do
include Spec::Support::Helpers::ModalHelpers
- let(:user) { create(:admin) }
+ let_it_be(:user) { create(:admin) }
before do
sign_in(user)
diff --git a/spec/features/admin/admin_mode/workers_spec.rb b/spec/features/admin/admin_mode/workers_spec.rb
index 12f5e20e176..8405e9132b6 100644
--- a/spec/features/admin/admin_mode/workers_spec.rb
+++ b/spec/features/admin/admin_mode/workers_spec.rb
@@ -37,56 +37,26 @@ RSpec.describe 'Admin mode for workers', :request_store do
gitlab_enable_admin_mode_sign_in(user)
end
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- it 'can delete user', :js do
- visit admin_user_path(user_to_delete)
-
- click_action_in_user_dropdown(user_to_delete.id, 'Delete user')
-
- page.within '.modal-dialog' do
- find("input[name='username']").send_keys(user_to_delete.name)
- click_button 'Delete user'
-
- wait_for_requests
- end
-
- expect(page).to have_content('The user is being deleted.')
-
- # Perform jobs while logged out so that admin mode is only enabled in job metadata
- execute_jobs_signed_out(user)
+ it 'can delete user', :js do
+ visit admin_user_path(user_to_delete)
- visit admin_user_path(user_to_delete)
+ click_action_in_user_dropdown(user_to_delete.id, 'Delete user')
- expect(find('h1.page-title')).to have_content('(Blocked)')
- end
- end
+ page.within '.modal-dialog' do
+ find("input[name='username']").send_keys(user_to_delete.name)
+ click_button 'Delete user'
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
+ wait_for_requests
end
- it 'can delete user', :js do
- visit admin_user_path(user_to_delete)
-
- click_action_in_user_dropdown(user_to_delete.id, 'Delete user')
-
- page.within '.modal-dialog' do
- find("input[name='username']").send_keys(user_to_delete.name)
- click_button 'Delete user'
-
- wait_for_requests
- end
+ expect(page).to have_content('The user is being deleted.')
- expect(page).to have_content('The user is being deleted.')
+ # Perform jobs while logged out so that admin mode is only enabled in job metadata
+ execute_jobs_signed_out(user)
- # Perform jobs while logged out so that admin mode is only enabled in job metadata
- execute_jobs_signed_out(user)
-
- visit admin_user_path(user_to_delete)
+ visit admin_user_path(user_to_delete)
- expect(page).to have_title('Not Found')
- end
+ expect(find('h1.page-title')).to have_content('(Blocked)')
end
end
end
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 35e57213bdb..92a3b388994 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -72,19 +72,8 @@ RSpec.describe "Admin Runners" do
expect(page).to have_text "#{s_('Runners|Stale')} 1"
end
- describe 'delete all runners in bulk' do
- before do
- check s_('Runners|Select all')
- click_button s_('Runners|Delete selected')
-
- within_modal do
- click_on 'Permanently delete 3 runners'
- end
-
- wait_for_requests
- end
-
- it_behaves_like 'shows no runners registered'
+ it_behaves_like 'deletes runners in bulk' do
+ let(:runner_count) { '3' }
end
end
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index 94c5f397670..72c9053ba49 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -205,6 +205,22 @@ RSpec.describe 'Admin updates settings' do
expect(page).to have_content "Application settings saved successfully"
end
end
+
+ context 'Email confirmation settings' do
+ it "is set to 'hard' by default" do
+ expect(current_settings.email_confirmation_setting).to eq('off')
+ end
+
+ it 'changes the setting', :js do
+ page.within('.as-signup') do
+ choose 'Hard'
+ click_button 'Save changes'
+ end
+
+ expect(current_settings.email_confirmation_setting).to eq('hard')
+ expect(page).to have_content "Application settings saved successfully"
+ end
+ end
end
it 'change Sign-in restrictions' do
@@ -304,10 +320,12 @@ RSpec.describe 'Admin updates settings' do
it 'changes the setting' do
page.within('#js-jira_connect-settings') do
fill_in 'Jira Connect Application ID', with: '1234'
+ fill_in 'Jira Connect Proxy URL', with: 'https://example.com'
click_button 'Save changes'
end
expect(current_settings.jira_connect_application_key).to eq('1234')
+ expect(current_settings.jira_connect_proxy_url).to eq('https://example.com')
expect(page).to have_content "Application settings saved successfully"
end
end
diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
index 45dccf9921f..d93dac4834e 100644
--- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb
+++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb
@@ -4,18 +4,11 @@ require 'spec_helper'
RSpec.describe 'Admin > Users > Impersonation Tokens', :js do
include Spec::Support::Helpers::ModalHelpers
+ include Spec::Support::Helpers::AccessTokenHelpers
let(:admin) { create(:admin) }
let!(:user) { create(:user) }
- def active_impersonation_tokens
- find("[data-testid='active-tokens']")
- end
-
- def created_impersonation_token
- find_field('new-access-token').value
- end
-
before do
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
@@ -39,12 +32,12 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do
click_on "Create impersonation token"
- expect(active_impersonation_tokens).to have_text(name)
- expect(active_impersonation_tokens).to have_text('in')
- expect(active_impersonation_tokens).to have_text('read_api')
- expect(active_impersonation_tokens).to have_text('read_user')
+ expect(active_access_tokens).to have_text(name)
+ expect(active_access_tokens).to have_text('in')
+ expect(active_access_tokens).to have_text('read_api')
+ expect(active_access_tokens).to have_text('read_user')
expect(PersonalAccessTokensFinder.new(impersonation: true).execute.count).to equal(1)
- expect(created_impersonation_token).not_to be_empty
+ expect(created_access_token).to match(/[\w-]{20}/)
end
end
@@ -55,16 +48,16 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do
it 'only shows impersonation tokens' do
visit admin_user_impersonation_tokens_path(user_id: user.username)
- expect(active_impersonation_tokens).to have_text(impersonation_token.name)
- expect(active_impersonation_tokens).not_to have_text(personal_access_token.name)
- expect(active_impersonation_tokens).to have_text('in')
+ expect(active_access_tokens).to have_text(impersonation_token.name)
+ expect(active_access_tokens).not_to have_text(personal_access_token.name)
+ expect(active_access_tokens).to have_text('in')
end
it 'shows absolute times' do
admin.update!(time_display_relative: false)
visit admin_user_impersonation_tokens_path(user_id: user.username)
- expect(active_impersonation_tokens).to have_text(personal_access_token.expires_at.strftime('%b %-d'))
+ expect(active_access_tokens).to have_text(personal_access_token.expires_at.strftime('%b %-d'))
end
end
@@ -76,7 +69,7 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do
accept_gl_confirm(button_text: 'Revoke') { click_on "Revoke" }
- expect(active_impersonation_tokens).to have_text("This user has no active impersonation tokens.")
+ expect(active_access_tokens).to have_text("This user has no active impersonation tokens.")
end
it "removes expired tokens from 'active' section" do
@@ -84,7 +77,7 @@ RSpec.describe 'Admin > Users > Impersonation Tokens', :js do
visit admin_user_impersonation_tokens_path(user_id: user.username)
- expect(active_impersonation_tokens).to have_text("This user has no active impersonation tokens.")
+ expect(active_access_tokens).to have_text("This user has no active impersonation tokens.")
end
end
diff --git a/spec/features/admin/users/user_spec.rb b/spec/features/admin/users/user_spec.rb
index 86acf5a05d4..35b5c755b66 100644
--- a/spec/features/admin/users/user_spec.rb
+++ b/spec/features/admin/users/user_spec.rb
@@ -150,13 +150,32 @@ RSpec.describe 'Admin::Users::User' do
context 'before impersonating' do
subject { visit admin_user_path(user_to_visit) }
- let(:user_to_visit) { another_user }
+ let_it_be(:user_to_visit) { another_user }
+
+ shared_examples "user that cannot be impersonated" do
+ it 'disables impersonate button' do
+ subject
+
+ impersonate_btn = find('[data-testid="impersonate_user_link"]')
+
+ expect(impersonate_btn).not_to be_nil
+ expect(impersonate_btn['disabled']).not_to be_nil
+ end
+
+ it "shows tooltip with correct error message" do
+ subject
+
+ expect(find("span[title='#{impersonation_error_msg}']")).not_to be_nil
+ end
+ end
context 'for other users' do
it 'shows impersonate button for other users' do
subject
expect(page).to have_content('Impersonate')
+ impersonate_btn = find('[data-testid="impersonate_user_link"]')
+ expect(impersonate_btn['disabled']).to be_nil
end
end
@@ -171,15 +190,51 @@ RSpec.describe 'Admin::Users::User' do
end
context 'for blocked user' do
- before do
- another_user.block
+ let_it_be(:blocked_user) { create(:user, :blocked) }
+ let(:user_to_visit) { blocked_user }
+ let(:impersonation_error_msg) { _('You cannot impersonate a blocked user') }
+
+ it_behaves_like "user that cannot be impersonated"
+ end
+
+ context 'for user with expired password' do
+ let(:user_to_visit) do
+ another_user.update!(password_expires_at: Time.zone.now - 5.minutes)
+ another_user
end
- it 'does not show impersonate button for blocked user' do
- subject
+ let(:impersonation_error_msg) { _("You cannot impersonate a user with an expired password") }
- expect(page).not_to have_content('Impersonate')
+ it_behaves_like "user that cannot be impersonated"
+ end
+
+ context 'for internal user' do
+ let_it_be(:internal_user) { create(:user, :bot) }
+ let(:user_to_visit) { internal_user }
+ let(:impersonation_error_msg) { _("You cannot impersonate an internal user") }
+
+ it_behaves_like "user that cannot be impersonated"
+ end
+
+ context 'for locked user' do
+ let_it_be(:locked_user) { create(:user, :locked) }
+ let(:user_to_visit) { locked_user }
+ let(:impersonation_error_msg) { _("You cannot impersonate a user who cannot log in") }
+
+ it_behaves_like "user that cannot be impersonated"
+ end
+
+ context 'when already impersonating another user' do
+ let_it_be(:admin_user) { create(:user, :admin) }
+ let(:impersonation_error_msg) { _("You are already impersonating another user") }
+
+ subject do
+ visit admin_user_path(admin_user)
+ click_link 'Impersonate'
+ visit admin_user_path(another_user)
end
+
+ it_behaves_like "user that cannot be impersonated"
end
context 'when impersonation is disabled' do
@@ -216,18 +271,6 @@ RSpec.describe 'Admin::Users::User' do
icon = first('[data-testid="incognito-icon"]')
expect(icon).not_to be nil
end
-
- context 'a user with an expired password' do
- before do
- another_user.update!(password_expires_at: Time.zone.now - 5.minutes)
- end
-
- it 'does not redirect to password change page' do
- subject
-
- expect(page).to have_current_path('/')
- end
- end
end
context 'ending impersonation' do
diff --git a/spec/features/admin_variables_spec.rb b/spec/features/admin_variables_spec.rb
index 174d4567520..9ec22bbe948 100644
--- a/spec/features/admin_variables_spec.rb
+++ b/spec/features/admin_variables_spec.rb
@@ -12,23 +12,9 @@ RSpec.describe 'Instance variables', :js do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
sign_in(admin)
gitlab_enable_admin_mode_sign_in(admin)
+ visit page_path
wait_for_requests
end
- context 'with disabled ff `ci_variable_settings_graphql' do
- before do
- stub_feature_flags(ci_variable_settings_graphql: false)
- visit page_path
- end
-
- it_behaves_like 'variable list', isAdmin: true
- end
-
- context 'with enabled ff `ci_variable_settings_graphql' do
- before do
- visit page_path
- end
-
- it_behaves_like 'variable list', isAdmin: true
- end
+ it_behaves_like 'variable list', isAdmin: true
end
diff --git a/spec/features/boards/board_filters_spec.rb b/spec/features/boards/board_filters_spec.rb
index 2e4dc4a29fc..eab92de7e8a 100644
--- a/spec/features/boards/board_filters_spec.rb
+++ b/spec/features/boards/board_filters_spec.rb
@@ -7,8 +7,8 @@ RSpec.describe 'Issue board filters', :js do
let_it_be(:user) { create(:user) }
let_it_be(:board) { create(:board, project: project) }
let_it_be(:project_label) { create(:label, project: project, title: 'Label') }
- let_it_be(:milestone_1) { create(:milestone, project: project, due_date: 3.days.from_now ) }
- let_it_be(:milestone_2) { create(:milestone, project: project, due_date: Date.tomorrow ) }
+ let_it_be(:milestone_1) { create(:milestone, project: project, due_date: 3.days.from_now) }
+ let_it_be(:milestone_2) { create(:milestone, project: project, due_date: Date.tomorrow) }
let_it_be(:release) { create(:release, tag: 'v1.0', project: project, milestones: [milestone_1]) }
let_it_be(:release_2) { create(:release, tag: 'v2.0', project: project, milestones: [milestone_2]) }
let_it_be(:issue_1) { create(:issue, project: project, milestone: milestone_1, author: user) }
@@ -22,6 +22,7 @@ RSpec.describe 'Issue board filters', :js do
let(:filter_submit) { find('.gl-search-box-by-click-search-button') }
before do
+ stub_feature_flags(apollo_boards: false)
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index a09c9d258dc..fee9b5b378e 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -19,6 +19,7 @@ RSpec.describe 'Project issue boards', :js do
context 'signed in user' do
before do
+ stub_feature_flags(apollo_boards: false)
project.add_maintainer(user)
project.add_maintainer(user2)
@@ -29,7 +30,7 @@ RSpec.describe 'Project issue boards', :js do
context 'no lists' do
before do
- visit_project_board_path_without_query_limit(project, board)
+ visit_project_board(project, board)
end
it 'creates default lists' do
@@ -73,7 +74,7 @@ RSpec.describe 'Project issue boards', :js do
let_it_be(:issue10) { create(:labeled_issue, project: project, title: 'issue +', description: 'A+ great issue', labels: [a_plus]) }
before do
- visit_project_board_path_without_query_limit(project, board)
+ visit_project_board(project, board)
end
it 'shows description tooltip on list title', :quarantine do
@@ -124,7 +125,7 @@ RSpec.describe 'Project issue boards', :js do
it 'infinite scrolls list' do
create_list(:labeled_issue, 30, project: project, labels: [planning])
- visit_project_board_path_without_query_limit(project, board)
+ visit_project_board(project, board)
page.within(find('.board:nth-child(2)')) do
expect(page.find('.board-header')).to have_content('38')
@@ -203,7 +204,7 @@ RSpec.describe 'Project issue boards', :js do
expect(find('.board:nth-child(3) [data-testid="board-list-header"]')).to have_content(planning.title)
# Make sure list positions are preserved after a reload
- visit_project_board_path_without_query_limit(project, board)
+ visit_project_board(project, board)
expect(find('.board:nth-child(2) [data-testid="board-list-header"]')).to have_content(development.title)
expect(find('.board:nth-child(3) [data-testid="board-list-header"]')).to have_content(planning.title)
@@ -215,15 +216,19 @@ RSpec.describe 'Project issue boards', :js do
let_it_be(:list2) { create(:list, board: board, label: development, position: 1) }
it 'changes position of list' do
- visit_project_board_path_without_query_limit(project, board)
+ inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do
+ visit_project_board(project, board)
+ end
drag(list_from_index: 0, list_to_index: 1, selector: '.board-header')
expect(find('.board:nth-child(1) [data-testid="board-list-header"]')).to have_content(development.title)
expect(find('.board:nth-child(2) [data-testid="board-list-header"]')).to have_content(planning.title)
- # Make sure list positions are preserved after a reload
- visit_project_board_path_without_query_limit(project, board)
+ inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do
+ # Make sure list positions are preserved after a reload
+ visit_project_board(project, board)
+ end
expect(find('.board:nth-child(1) [data-testid="board-list-header"]')).to have_content(development.title)
expect(find('.board:nth-child(2) [data-testid="board-list-header"]')).to have_content(planning.title)
@@ -234,7 +239,9 @@ RSpec.describe 'Project issue boards', :js do
selector = '.board:not(.is-ghost) .board-header'
expect(page).to have_selector(selector, text: development.title, count: 1)
- drag(list_from_index: 2, list_to_index: 1, selector: '.board-header', perform_drop: false)
+ inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do
+ drag(list_from_index: 2, list_to_index: 1, selector: '.board-header', perform_drop: false)
+ end
expect(page).to have_selector(selector, text: development.title, count: 1)
end
@@ -492,7 +499,7 @@ RSpec.describe 'Project issue boards', :js do
context 'keyboard shortcuts' do
before do
- visit_project_board_path_without_query_limit(project, board)
+ visit_project_board(project, board)
wait_for_requests
end
@@ -505,6 +512,7 @@ RSpec.describe 'Project issue boards', :js do
context 'signed out user' do
before do
+ stub_feature_flags(apollo_boards: false)
visit project_board_path(project, board)
wait_for_requests
end
@@ -526,6 +534,7 @@ RSpec.describe 'Project issue boards', :js do
let_it_be(:user_guest) { create(:user) }
before do
+ stub_feature_flags(apollo_boards: false)
project.add_guest(user_guest)
sign_in(user_guest)
visit project_board_path(project, board)
@@ -587,11 +596,9 @@ RSpec.describe 'Project issue boards', :js do
end
end
- def visit_project_board_path_without_query_limit(project, board)
- inspect_requests(inject_headers: { 'X-GITLAB-DISABLE-SQL-QUERY-LIMIT' => 'https://gitlab.com/gitlab-org/gitlab/-/issues/323426' }) do
- visit project_board_path(project, board)
+ def visit_project_board(project, board)
+ visit project_board_path(project, board)
- wait_for_requests
- end
+ wait_for_requests
end
end
diff --git a/spec/features/boards/issue_ordering_spec.rb b/spec/features/boards/issue_ordering_spec.rb
index 57f2bf26752..a3dda3b9d2f 100644
--- a/spec/features/boards/issue_ordering_spec.rb
+++ b/spec/features/boards/issue_ordering_spec.rb
@@ -15,6 +15,7 @@ RSpec.describe 'Issue Boards', :js do
let!(:issue3) { create(:labeled_issue, project: project, title: 'testing 3', labels: [label], relative_position: 1) }
before do
+ stub_feature_flags(apollo_boards: false)
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/boards/sidebar_labels_spec.rb b/spec/features/boards/sidebar_labels_spec.rb
index 511233b50c0..12d91e9c5a8 100644
--- a/spec/features/boards/sidebar_labels_spec.rb
+++ b/spec/features/boards/sidebar_labels_spec.rb
@@ -20,6 +20,7 @@ RSpec.describe 'Project issue boards sidebar labels', :js do
let(:card) { find('.board:nth-child(2)').first('.board-card') }
before do
+ stub_feature_flags(apollo_boards: false)
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb
index 0e914ae19d1..2b2a412194a 100644
--- a/spec/features/boards/sidebar_spec.rb
+++ b/spec/features/boards/sidebar_spec.rb
@@ -15,6 +15,7 @@ RSpec.describe 'Project issue boards sidebar', :js do
let_it_be(:issue, reload: true) { create(:issue, project: project, relative_position: 1) }
before do
+ stub_feature_flags(apollo_boards: false)
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/boards/user_adds_lists_to_board_spec.rb b/spec/features/boards/user_adds_lists_to_board_spec.rb
index 26c310a6f56..480a88a6b84 100644
--- a/spec/features/boards/user_adds_lists_to_board_spec.rb
+++ b/spec/features/boards/user_adds_lists_to_board_spec.rb
@@ -31,13 +31,15 @@ RSpec.describe 'User adds lists', :js do
with_them do
before do
+ stub_feature_flags(apollo_boards: false)
sign_in(user)
set_cookie('sidebar_collapsed', 'true')
- if board_type == :project
+ case board_type
+ when :project
visit project_board_path(project, project_board)
- elsif board_type == :group
+ when :group
visit group_board_path(group, group_board)
end
diff --git a/spec/features/boards/user_visits_board_spec.rb b/spec/features/boards/user_visits_board_spec.rb
index 7fe32557d6a..c386477fa9d 100644
--- a/spec/features/boards/user_visits_board_spec.rb
+++ b/spec/features/boards/user_visits_board_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe 'User visits issue boards', :js do
let_it_be(:label1) { create(:group_label, group: group, name: label_name1) }
let_it_be(:label2) { create(:group_label, group: group, name: label_name2) }
- let_it_be(:assignee) { create_default(:group_member, :maintainer, user: create(:user, username: assignee_username), group: group ).user }
+ let_it_be(:assignee) { create_default(:group_member, :maintainer, user: create(:user, username: assignee_username), group: group).user }
let_it_be(:milestone) { create_default(:milestone, project: project, start_date: Date.today - 1, due_date: 7.days.from_now) }
before_all do
@@ -44,6 +44,7 @@ RSpec.describe 'User visits issue boards', :js do
with_them do
before do
+ stub_feature_flags(apollo_boards: false)
visit board_path
wait_for_requests
@@ -59,6 +60,7 @@ RSpec.describe 'User visits issue boards', :js do
end
context "project boards" do
+ stub_feature_flags(apollo_boards: false)
let_it_be(:board) { create_default(:board, project: project) }
let_it_be(:backlog_list) { create_default(:backlog_list, board: board) }
@@ -68,6 +70,7 @@ RSpec.describe 'User visits issue boards', :js do
end
context "group boards" do
+ stub_feature_flags(apollo_boards: false)
let_it_be(:board) { create_default(:board, group: group) }
let_it_be(:backlog_list) { create_default(:backlog_list, board: board) }
diff --git a/spec/features/broadcast_messages_spec.rb b/spec/features/broadcast_messages_spec.rb
index f339d45671d..1fec68a1d98 100644
--- a/spec/features/broadcast_messages_spec.rb
+++ b/spec/features/broadcast_messages_spec.rb
@@ -31,7 +31,8 @@ RSpec.describe 'Broadcast Messages' do
expect(page).not_to have_content 'SampleMessage'
end
- it 'broadcast message is still hidden after refresh', :js do
+ it 'broadcast message is still hidden after refresh', :js,
+ quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/347118' do
visit root_path
find('.js-dismiss-current-broadcast-notification').click
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
index db841ffc627..97f820c1518 100644
--- a/spec/features/commits_spec.rb
+++ b/spec/features/commits_spec.rb
@@ -212,13 +212,13 @@ RSpec.describe 'Commits' do
end
context 'author is just a name' do
- let(:author) { "#{author_commit.author_name}" }
+ let(:author) { author_commit.author_name.to_s }
it_behaves_like 'show commits by author'
end
context 'author is just an email' do
- let(:author) { "#{author_commit.author_email}" }
+ let(:author) { author_commit.author_email.to_s }
it_behaves_like 'show commits by author'
end
diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb
index 488a4f84297..8de4c66c62f 100644
--- a/spec/features/cycle_analytics_spec.rb
+++ b/spec/features/cycle_analytics_spec.rb
@@ -56,7 +56,7 @@ RSpec.describe 'Value Stream Analytics', :js do
end
end
- context "when there's value stream analytics data" do
+ context "when there's value stream analytics data", :sidekiq_inline do
# NOTE: in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68595 travel back
# 5 days in time before we create data for these specs, to mitigate some flakiness
# So setting the date range to be the last 2 days should skip past the existing data
@@ -103,7 +103,7 @@ RSpec.describe 'Value Stream Analytics', :js do
end
end
- it 'shows data on each stage', :sidekiq_might_not_need_inline, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/338332' do
+ it 'shows data on each stage', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/338332' do
expect_issue_to_be_present
click_stage('Plan')
@@ -207,11 +207,11 @@ RSpec.describe 'Value Stream Analytics', :js do
wait_for_requests
end
- it 'does not show the commit stats' do
+ it 'does not show the commit stats', :sidekiq_inline do
expect(page.find(metrics_selector)).not_to have_selector("#commits")
end
- it 'does not show restricted stages', :aggregate_failures do
+ it 'does not show restricted stages', :aggregate_failures, :sidekiq_inline do
expect(find(stage_table_selector)).to have_content(issue.title)
expect(page).to have_selector('.gl-path-nav-list-item', text: 'Issue')
diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb
index 875ae41c55d..de8858fa8fa 100644
--- a/spec/features/dashboard/datetime_on_tooltips_spec.rb
+++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb
@@ -14,8 +14,8 @@ RSpec.describe 'Tooltips on .timeago dates', :js do
context 'on the activity tab' do
before do
- Event.create!( project: project, author_id: user.id, action: :joined,
- updated_at: created_date, created_at: created_date)
+ Event.create!(project: project, author_id: user.id, action: :joined,
+ updated_at: created_date, created_at: created_date)
sign_in user
visit user_activity_path(user)
diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb
index 0b468854322..c132caa88c8 100644
--- a/spec/features/dashboard/projects_spec.rb
+++ b/spec/features/dashboard/projects_spec.rb
@@ -139,7 +139,7 @@ RSpec.describe 'Dashboard Projects' do
end
describe 'with a pipeline', :clean_gitlab_redis_shared_state do
- let_it_be(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit.sha, ref: project.default_branch) }
+ let!(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit.sha, ref: project.default_branch) }
before do
# Since the cache isn't updated when a new pipeline is created
@@ -151,7 +151,7 @@ RSpec.describe 'Dashboard Projects' do
it 'shows that the last pipeline passed' do
visit dashboard_projects_path
- page.within('.controls') do
+ page.within('[data-testid="project_controls"]') do
expect(page).to have_xpath("//a[@href='#{pipelines_project_commit_path(project, project.commit, ref: pipeline.ref)}']")
expect(page).to have_css('.ci-status-link')
expect(page).to have_css('.ci-status-icon-success')
@@ -163,7 +163,7 @@ RSpec.describe 'Dashboard Projects' do
it 'does not show the pipeline status' do
visit dashboard_projects_path
- page.within('.controls') do
+ page.within('[data-testid="project_controls"]') do
expect(page).not_to have_xpath("//a[@href='#{pipelines_project_commit_path(project, project.commit, ref: pipeline.ref)}']")
expect(page).not_to have_css('.ci-status-link')
expect(page).not_to have_css('.ci-status-icon-success')
diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb
index 666bf3594de..2e63ec2d4f2 100644
--- a/spec/features/global_search_spec.rb
+++ b/spec/features/global_search_spec.rb
@@ -2,14 +2,13 @@
require 'spec_helper'
-RSpec.describe 'Global search' do
+RSpec.describe 'Global search', :js do
include AfterNextHelpers
- let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, namespace: user.namespace) }
before do
- stub_feature_flags(search_page_vertical_nav: false)
project.add_maintainer(user)
sign_in(user)
end
@@ -42,7 +41,7 @@ RSpec.describe 'Global search' do
end
end
- it 'closes the dropdown on blur', :js do
+ it 'closes the dropdown on blur' do
find('#search').click
fill_in 'search', with: "a"
@@ -59,7 +58,7 @@ RSpec.describe 'Global search' do
expect(page).to have_no_selector('#js-header-search')
end
- it 'focuses search input when shortcut "s" is pressed', :js do
+ it 'focuses search input when shortcut "s" is pressed' do
expect(page).not_to have_selector('#search:focus')
find('body').native.send_key('s')
@@ -74,7 +73,7 @@ RSpec.describe 'Global search' do
stub_feature_flags(new_header_search: true)
visit dashboard_projects_path
- # intialize javascript loaded input search input field
+ # initialize javascript loaded input search input field
find('#search').click
find('body').click
end
@@ -84,7 +83,7 @@ RSpec.describe 'Global search' do
expect(page).to have_selector('#js-header-search')
end
- it 'focuses search input when shortcut "s" is pressed', :js do
+ it 'focuses search input when shortcut "s" is pressed' do
expect(page).not_to have_selector('#search:focus')
find('body').native.send_key('s')
diff --git a/spec/features/graphql_known_operations_spec.rb b/spec/features/graphql_known_operations_spec.rb
index ef406f12902..80214307be3 100644
--- a/spec/features/graphql_known_operations_spec.rb
+++ b/spec/features/graphql_known_operations_spec.rb
@@ -24,6 +24,6 @@ RSpec.describe 'Graphql known operations', :js do
expect(known_operations).to include("searchProjects")
expect(known_operations.length).to be > 20
- expect(known_operations).to all( match(%r{^[a-z]+}i) )
+ expect(known_operations).to all(match(%r{^[a-z]+}i))
end
end
diff --git a/spec/features/group_variables_spec.rb b/spec/features/group_variables_spec.rb
index ab24162ad5a..e2c659d7dfe 100644
--- a/spec/features/group_variables_spec.rb
+++ b/spec/features/group_variables_spec.rb
@@ -11,23 +11,9 @@ RSpec.describe 'Group variables', :js do
before do
group.add_owner(user)
gitlab_sign_in(user)
+ visit page_path
wait_for_requests
end
- context 'with disabled ff `ci_variable_settings_graphql' do
- before do
- stub_feature_flags(ci_variable_settings_graphql: false)
- visit page_path
- end
-
- it_behaves_like 'variable list'
- end
-
- context 'with enabled ff `ci_variable_settings_graphql' do
- before do
- visit page_path
- end
-
- it_behaves_like 'variable list'
- end
+ it_behaves_like 'variable list'
end
diff --git a/spec/features/groups/activity_spec.rb b/spec/features/groups/activity_spec.rb
index 6ca69e76d33..5bac80959b1 100644
--- a/spec/features/groups/activity_spec.rb
+++ b/spec/features/groups/activity_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Group activity page' do
- let(:user) { create(:group_member, :developer, user: create(:user), group: group ).user }
+ let(:user) { create(:group_member, :developer, user: create(:user), group: group).user }
let(:group) { create(:group) }
let(:path) { activity_group_path(group) }
diff --git a/spec/features/groups/board_sidebar_spec.rb b/spec/features/groups/board_sidebar_spec.rb
index 69a6788e438..10ef28f3fbc 100644
--- a/spec/features/groups/board_sidebar_spec.rb
+++ b/spec/features/groups/board_sidebar_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Group Issue Boards', :js do
include BoardHelpers
let(:group) { create(:group) }
- let(:user) { create(:group_member, user: create(:user), group: group ).user }
+ let(:user) { create(:group_member, user: create(:user), group: group).user }
let!(:project_1) { create(:project, :public, group: group) }
let!(:project_2) { create(:project, :public, group: group) }
let!(:project_1_label) { create(:label, project: project_1, name: 'Development 1') }
@@ -19,6 +19,7 @@ RSpec.describe 'Group Issue Boards', :js do
let(:card) { find('.board:nth-child(1)').first('.board-card') }
before do
+ stub_feature_flags(apollo_boards: false)
sign_in(user)
visit group_board_path(group, board)
diff --git a/spec/features/groups/empty_states_spec.rb b/spec/features/groups/empty_states_spec.rb
index 84882fc674e..f1a8f97461a 100644
--- a/spec/features/groups/empty_states_spec.rb
+++ b/spec/features/groups/empty_states_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe 'Group empty states' do
let(:group) { create(:group) }
- let(:user) { create(:group_member, :developer, user: create(:user), group: group ).user }
+ let(:user) { create(:group_member, :developer, user: create(:user), group: group).user }
before do
sign_in(user)
diff --git a/spec/features/groups/group_runners_spec.rb b/spec/features/groups/group_runners_spec.rb
index e9807c487d5..c9d1c69e9e1 100644
--- a/spec/features/groups/group_runners_spec.rb
+++ b/spec/features/groups/group_runners_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe "Group Runners" do
include Spec::Support::Helpers::Features::RunnersHelpers
+ include Spec::Support::Helpers::ModalHelpers
let_it_be(:group_owner) { create(:user) }
let_it_be(:group) { create(:group) }
@@ -157,6 +158,19 @@ RSpec.describe "Group Runners" do
end
end
+ context "with multiple runners" do
+ before do
+ create(:ci_runner, :group, groups: [group], description: 'runner-foo')
+ create(:ci_runner, :group, groups: [group], description: 'runner-bar')
+
+ visit group_runners_path(group)
+ end
+
+ it_behaves_like 'deletes runners in bulk' do
+ let(:runner_count) { '2' }
+ end
+ end
+
describe 'filtered search' do
before do
visit group_runners_path(group)
@@ -201,18 +215,32 @@ RSpec.describe "Group Runners" do
end
describe "Group runner edit page", :js do
- let!(:group_runner) do
- create(:ci_runner, :group, groups: [group])
- end
+ context 'when updating a group runner' do
+ let_it_be(:group_runner) { create(:ci_runner, :group, groups: [group]) }
- before do
- visit edit_group_runner_path(group, group_runner)
- wait_for_requests
+ before do
+ visit edit_group_runner_path(group, group_runner)
+ wait_for_requests
+ end
+
+ it_behaves_like 'submits edit runner form' do
+ let(:runner) { group_runner }
+ let(:runner_page_path) { group_runner_path(group, group_runner) }
+ end
end
- it_behaves_like 'submits edit runner form' do
- let(:runner) { group_runner }
- let(:runner_page_path) { group_runner_path(group, group_runner) }
+ context 'when updating a project runner' do
+ let_it_be(:project_runner) { create(:ci_runner, :project, projects: [project]) }
+
+ before do
+ visit edit_group_runner_path(group, project_runner)
+ wait_for_requests
+ end
+
+ it_behaves_like 'submits edit runner form' do
+ let(:runner) { project_runner }
+ let(:runner_page_path) { group_runner_path(group, project_runner) }
+ end
end
end
end
diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb
index 2f599d24b01..81ff0088e1e 100644
--- a/spec/features/groups/group_settings_spec.rb
+++ b/spec/features/groups/group_settings_spec.rb
@@ -150,13 +150,15 @@ RSpec.describe 'Edit group settings' do
it 'can successfully transfer the group' do
visit edit_group_path(selected_group)
- page.within('.js-group-transfer-form') do
- namespace_select.find('button').click
- namespace_select.find('.dropdown-menu p', text: target_group_name, match: :first).click
-
- click_button 'Transfer 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
end
+ click_button s_('GroupSettings|Transfer group')
+
page.within(confirm_modal) do
expect(page).to have_text "You are going to transfer #{selected_group.name} to another namespace. Are you ABSOLUTELY sure?"
@@ -169,16 +171,16 @@ RSpec.describe 'Edit group settings' do
end
end
- context 'from a subgroup' do
+ context 'when transfering from a subgroup' do
let(:selected_group) { create(:group, path: 'foo-subgroup', parent: group) }
- context 'to no parent group' do
+ context 'when transfering to no parent group' do
let(:target_group_name) { 'No parent group' }
it_behaves_like 'can transfer the group'
end
- context 'to a different parent group' do
+ context 'when transfering to a parent group' do
let(:target_group) { create(:group, path: 'foo-parentgroup') }
let(:target_group_name) { target_group.name }
@@ -190,14 +192,11 @@ RSpec.describe 'Edit group settings' do
end
end
- context 'from a root group' do
+ context 'when transfering from a root group to a parent group' do
let(:selected_group) { create(:group, path: 'foo-rootgroup') }
+ let(:target_group_name) { group.name }
- context 'to a parent group' do
- let(:target_group_name) { group.name }
-
- it_behaves_like 'can transfer the group'
- end
+ it_behaves_like 'can transfer the group'
end
end
diff --git a/spec/features/groups/issues_spec.rb b/spec/features/groups/issues_spec.rb
index eec07c84cde..d4e88505118 100644
--- a/spec/features/groups/issues_spec.rb
+++ b/spec/features/groups/issues_spec.rb
@@ -69,7 +69,7 @@ RSpec.describe 'Group issues page' do
context 'issues list', :js do
let(:subgroup) { create(:group, parent: group) }
let(:subgroup_project) { create(:project, :public, group: subgroup) }
- let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group ).user }
+ let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group).user }
let!(:issue) { create(:issue, project: project, title: 'root group issue') }
let!(:subgroup_issue) { create(:issue, project: subgroup_project, title: 'subgroup issue') }
@@ -111,7 +111,7 @@ RSpec.describe 'Group issues page' do
context 'projects with issues disabled' do
describe 'issue dropdown' do
- let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group ).user }
+ let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group).user }
before do
[project, project_with_issues_disabled].each { |project| project.add_maintainer(user_in_group) }
@@ -129,7 +129,7 @@ RSpec.describe 'Group issues page' do
end
context 'manual ordering', :js do
- let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group ).user }
+ let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group).user }
let!(:issue1) { create(:issue, project: project, title: 'Issue #1', relative_position: 1) }
let!(:issue2) { create(:issue, project: project, title: 'Issue #2', relative_position: 2) }
@@ -161,6 +161,8 @@ RSpec.describe 'Group issues page' do
visit issues_group_path(group)
select_manual_sort
+ wait_for_requests
+
drag_to(selector: '.manual-ordering', from_index: 0, to_index: 2)
expect_issue_order
@@ -176,6 +178,8 @@ RSpec.describe 'Group issues page' do
visit issues_group_path(group)
select_manual_sort
+ wait_for_requests
+
drag_to(selector: '.manual-ordering', from_index: 0, to_index: 2)
expect(page).to have_text 'An error occurred while reordering issues.'
@@ -195,7 +199,7 @@ RSpec.describe 'Group issues page' do
end
context 'issues pagination', :js do
- let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group ).user }
+ let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group).user }
let!(:issues) do
(1..25).to_a.map { |index| create(:issue, project: project, title: "Issue #{index}") }
diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb
index 42eaa8358a1..92a40459737 100644
--- a/spec/features/groups/milestone_spec.rb
+++ b/spec/features/groups/milestone_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Group milestones' do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project_empty_repo, group: group) }
- let_it_be(:user) { create(:group_member, :maintainer, user: create(:user), group: group ).user }
+ let_it_be(:user) { create(:group_member, :maintainer, user: create(:user), group: group).user }
around do |example|
freeze_time { example.run }
diff --git a/spec/features/groups/milestones_sorting_spec.rb b/spec/features/groups/milestones_sorting_spec.rb
index 125bf9ce3a7..6f3fc72775f 100644
--- a/spec/features/groups/milestones_sorting_spec.rb
+++ b/spec/features/groups/milestones_sorting_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe 'Milestones sorting', :js do
let!(:project_milestone2) { create(:milestone, project: project, title: 'v2.0', due_date: 5.days.from_now) }
let!(:other_project_milestone2) { create(:milestone, project: other_project, title: 'v2.0', due_date: 5.days.from_now) }
let!(:group_milestone) { create(:milestone, group: group, title: 'v3.0', due_date: 7.days.from_now) }
- let(:user) { create(:group_member, :maintainer, user: create(:user), group: group ).user }
+ let(:user) { create(:group_member, :maintainer, user: create(:user), group: group).user }
before do
sign_in(user)
diff --git a/spec/features/groups/settings/repository_spec.rb b/spec/features/groups/settings/repository_spec.rb
index f6b8bbdd35f..cd7dcbdb28d 100644
--- a/spec/features/groups/settings/repository_spec.rb
+++ b/spec/features/groups/settings/repository_spec.rb
@@ -23,26 +23,9 @@ RSpec.describe 'Group Repository settings', :js do
stub_container_registry_config(enabled: true)
end
- context 'when ajax deploy tokens is enabled' do
- before do
- stub_feature_flags(ajax_new_deploy_token: true)
- end
-
- it_behaves_like 'a deploy token in settings' do
- let(:entity_type) { 'group' }
- let(:page_path) { group_settings_repository_path(group) }
- end
- end
-
- context 'when ajax deploy tokens is disabled' do
- before do
- stub_feature_flags(ajax_new_deploy_token: false)
- end
-
- it_behaves_like 'a deploy token in settings' do
- let(:entity_type) { 'group' }
- let(:page_path) { group_settings_repository_path(group) }
- end
+ it_behaves_like 'a deploy token in settings' do
+ let(:entity_type) { 'group' }
+ let(:page_path) { group_settings_repository_path(group) }
end
end
diff --git a/spec/features/help_pages_spec.rb b/spec/features/help_pages_spec.rb
index 546257b9f10..eef48d09f32 100644
--- a/spec/features/help_pages_spec.rb
+++ b/spec/features/help_pages_spec.rb
@@ -41,7 +41,7 @@ RSpec.describe 'Help Pages' do
end
it 'renders the version check badge' do
- expect(page).to have_selector('.js-gitlab-version-check')
+ expect(page).to have_selector('.js-gitlab-version-check-badge')
end
end
diff --git a/spec/features/ide/user_opens_merge_request_spec.rb b/spec/features/ide/user_opens_merge_request_spec.rb
index 8a95d7c5544..4ffa5212970 100644
--- a/spec/features/ide/user_opens_merge_request_spec.rb
+++ b/spec/features/ide/user_opens_merge_request_spec.rb
@@ -21,6 +21,6 @@ RSpec.describe 'IDE merge request', :js do
wait_for_requests
- expect(page).to have_selector('.monaco-diff-editor')
+ expect(page).not_to have_selector('.monaco-diff-editor')
end
end
diff --git a/spec/features/ide_spec.rb b/spec/features/ide_spec.rb
index c7c740c2293..1f6d34efc0f 100644
--- a/spec/features/ide_spec.rb
+++ b/spec/features/ide_spec.rb
@@ -3,47 +3,90 @@
require 'spec_helper'
RSpec.describe 'IDE', :js do
- describe 'sub-groups' do
- let(:ide_iframe_selector) { '#ide iframe' }
- let(:user) { create(:user) }
- let(:group) { create(:group) }
- let(:subgroup) { create(:group, parent: group) }
- let(:subgroup_project) { create(:project, :repository, namespace: subgroup) }
+ include WebIdeSpecHelpers
+
+ let_it_be(:ide_iframe_selector) { '#ide iframe' }
+ let_it_be(:normal_project) { create(:project, :repository) }
+
+ let(:project) { normal_project }
+ let(:vscode_ff) { false }
+ let(:user) { create(:user) }
+
+ before do
+ project.add_maintainer(user)
+ stub_feature_flags(vscode_web_ide: vscode_ff)
+
+ sign_in(user)
+ end
+
+ shared_examples "legacy Web IDE" do
+ it 'loads legacy Web IDE', :aggregate_failures do
+ expect(page).to have_selector('.context-header', text: project.name)
+
+ # Assert new Web IDE is not loaded
+ expect(page).not_to have_selector(ide_iframe_selector)
+ end
+ end
+
+ shared_examples "new Web IDE" do
+ it 'loads new Web IDE', :aggregate_failures do
+ expect(page).not_to have_selector('.context-header')
+
+ iframe = find(ide_iframe_selector)
+
+ page.within_frame(iframe) do
+ expect(page).to have_selector('.title', text: project.name.upcase)
+ end
+ end
+ end
+ context 'with vscode feature flag off' do
before do
- stub_feature_flags(vscode_web_ide: vscode_ff)
- subgroup_project.add_maintainer(user)
- sign_in(user)
+ ide_visit(project)
+ end
- visit project_path(subgroup_project)
+ it_behaves_like 'legacy Web IDE'
- click_link('Web IDE')
+ it 'does not show switch button' do
+ expect(page).not_to have_button('Switch to new Web IDE')
+ end
+ end
+
+ context 'with vscode feature flag on and use_legacy_web_ide=true' do
+ let(:vscode_ff) { true }
+ let(:user) { create(:user, use_legacy_web_ide: true) }
- wait_for_requests
+ before do
+ ide_visit(project)
end
- context 'with vscode feature flag on' do
- let(:vscode_ff) { true }
+ it_behaves_like 'legacy Web IDE'
- it 'loads project in Web IDE' do
- iframe = find(ide_iframe_selector)
+ describe 'when user switches to new Web IDE' do
+ before do
+ click_button('Switch to new Web IDE')
- page.within_frame(iframe) do
- expect(page).to have_selector('.title', text: subgroup_project.name.upcase)
+ # Confirm modal
+ page.within('#confirmationModal') do
+ click_button('Switch editors')
end
end
+
+ it_behaves_like 'new Web IDE'
end
+ end
- context 'with vscode feature flag off' do
- let(:vscode_ff) { false }
+ describe 'sub-groups' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:subgroup) { create(:group, parent: group) }
+ let_it_be(:subgroup_project) { create(:project, :repository, namespace: subgroup) }
- it 'loads project in legacy Web IDE' do
- expect(page).to have_selector('.context-header', text: subgroup_project.name)
- end
+ let(:project) { subgroup_project }
- it 'does not load new Web IDE' do
- expect(page).not_to have_selector(ide_iframe_selector)
- end
+ before do
+ ide_visit(project)
end
+
+ it_behaves_like 'legacy Web IDE'
end
end
diff --git a/spec/features/incidents/user_views_incident_spec.rb b/spec/features/incidents/user_views_incident_spec.rb
index a669966502e..054a084ea9c 100644
--- a/spec/features/incidents/user_views_incident_spec.rb
+++ b/spec/features/incidents/user_views_incident_spec.rb
@@ -4,12 +4,16 @@ require "spec_helper"
RSpec.describe "User views incident" do
let_it_be(:project) { create(:project_empty_repo, :public) }
- let_it_be(:user) { create(:user) }
- let_it_be(:incident) { create(:incident, project: project, description: "# Description header\n\n**Lorem** _ipsum_ dolor sit [amet](https://example.com)", author: user) }
- let_it_be(:note) { create(:note, noteable: incident, project: project, author: user) }
+ let_it_be(:guest) { create(:user) }
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:user) { developer }
+ let(:author) { developer }
+ let(:description) { "# Description header\n\n**Lorem** _ipsum_ dolor sit [amet](https://example.com)" }
+ let(:incident) { create(:incident, project: project, description: description, author: author) }
before_all do
- project.add_developer(user)
+ project.add_developer(developer)
+ project.add_guest(guest)
end
before do
@@ -18,57 +22,61 @@ RSpec.describe "User views incident" do
visit(project_issues_incident_path(project, incident))
end
- it { expect(page).to have_header_with_correct_id_and_link(1, "Description header", "description-header") }
+ specify do
+ expect(page).to have_header_with_correct_id_and_link(1, 'Description header', 'description-header')
+ end
it_behaves_like 'page meta description', ' Description header Lorem ipsum dolor sit amet'
describe 'user actions' do
it 'shows the merge request and incident actions', :js, :aggregate_failures do
+ expected_href = new_project_issue_path(project,
+ issuable_template: 'incident',
+ issue: { issue_type: 'incident' },
+ add_related_issue: incident.iid)
+
click_button 'Incident actions'
- expect(page).to have_link('New related incident', href: new_project_issue_path(project, { issuable_template: 'incident', issue: { issue_type: 'incident' }, add_related_issue: incident.iid }))
+ expect(page).to have_link('New related incident', href: expected_href)
expect(page).to have_button('Create merge request')
expect(page).to have_button('Close incident')
end
- context 'when user is a guest' do
- before do
- project.add_guest(user)
+ context 'when user is guest' do
+ let(:user) { guest }
- login_as(user)
+ context 'and author' do
+ let(:author) { guest }
- visit(project_issues_incident_path(project, incident))
+ it 'does not show the incident actions', :js do
+ expect(page).not_to have_button('Incident actions')
+ end
end
- it 'does not show the incident actions', :js, :aggregate_failures do
- expect(page).not_to have_button('Incident actions')
+ context 'and not author' do
+ it 'shows incident actions', :js do
+ click_button 'Incident actions'
+
+ expect(page).to have_link 'Report abuse'
+ end
end
end
end
context 'when the project is archived' do
- before do
+ before_all do
project.update!(archived: true)
- visit(project_issues_incident_path(project, incident))
end
- it 'hides the merge request and incident actions', :aggregate_failures do
- expect(page).not_to have_link('New incident')
- expect(page).not_to have_button('Create merge request')
- expect(page).not_to have_link('Close incident')
+ it 'does not show the incident actions', :js do
+ expect(page).not_to have_button('Incident actions')
end
end
describe 'user status' do
- subject { visit(project_issues_incident_path(project, incident)) }
-
context 'when showing status of the author of the incident' do
- it_behaves_like 'showing user status' do
- let(:user_with_status) { user }
- end
- end
+ subject { visit(project_issues_incident_path(project, incident)) }
- context 'when showing status of a user who commented on an incident', :js do
it_behaves_like 'showing user status' do
let(:user_with_status) { user }
end
diff --git a/spec/features/issuables/markdown_references/internal_references_spec.rb b/spec/features/issuables/markdown_references/internal_references_spec.rb
index ab7c0ce2891..c5a8e9f367c 100644
--- a/spec/features/issuables/markdown_references/internal_references_spec.rb
+++ b/spec/features/issuables/markdown_references/internal_references_spec.rb
@@ -21,15 +21,17 @@ RSpec.describe "Internal references", :js do
sign_in(private_project_user)
visit(project_issue_path(private_project, private_project_issue))
+ wait_for_requests
add_note("##{public_project_issue.to_reference(private_project)}")
end
- context "when user doesn't have access to private project", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do
+ context "when user doesn't have access to private project" do
before do
sign_in(public_project_user)
visit(project_issue_path(public_project, public_project_issue))
+ wait_for_requests
end
it { expect(page).not_to have_css(".note") }
@@ -41,6 +43,7 @@ RSpec.describe "Internal references", :js do
sign_in(private_project_user)
visit(project_merge_request_path(private_project, private_project_merge_request))
+ wait_for_requests
add_note("##{public_project_issue.to_reference(private_project)}")
end
@@ -50,9 +53,10 @@ RSpec.describe "Internal references", :js do
sign_in(public_project_user)
visit(project_issue_path(public_project, public_project_issue))
+ wait_for_requests
end
- it "doesn't show any references", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do
+ it "doesn't show any references" do
expect(page).not_to have_text 'Related merge requests'
end
end
@@ -60,6 +64,7 @@ RSpec.describe "Internal references", :js do
context "when user has access to private project" do
before do
visit(project_issue_path(public_project, public_project_issue))
+ wait_for_requests
end
it "shows references", :sidekiq_might_not_need_inline do
@@ -85,15 +90,17 @@ RSpec.describe "Internal references", :js do
sign_in(private_project_user)
visit(project_issue_path(private_project, private_project_issue))
+ wait_for_requests
add_note("##{public_project_merge_request.to_reference(private_project)}")
end
- context "when user doesn't have access to private project", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do
+ context "when user doesn't have access to private project" do
before do
sign_in(public_project_user)
visit(project_merge_request_path(public_project, public_project_merge_request))
+ wait_for_requests
end
it { expect(page).not_to have_css(".note") }
@@ -105,6 +112,7 @@ RSpec.describe "Internal references", :js do
sign_in(private_project_user)
visit(project_merge_request_path(private_project, private_project_merge_request))
+ wait_for_requests
add_note("##{public_project_merge_request.to_reference(private_project)}")
end
@@ -114,9 +122,10 @@ RSpec.describe "Internal references", :js do
sign_in(public_project_user)
visit(project_merge_request_path(public_project, public_project_merge_request))
+ wait_for_requests
end
- it "doesn't show any references", quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/257832' do
+ it "doesn't show any references" do
expect(page).not_to have_text 'Related merge requests'
end
end
@@ -124,6 +133,7 @@ RSpec.describe "Internal references", :js do
context "when user has access to private project" do
before do
visit(project_merge_request_path(public_project, public_project_merge_request))
+ wait_for_requests
end
it "shows references", :sidekiq_might_not_need_inline do
diff --git a/spec/features/issues/confidential_notes_spec.rb b/spec/features/issues/confidential_notes_spec.rb
new file mode 100644
index 00000000000..858c054c803
--- /dev/null
+++ b/spec/features/issues/confidential_notes_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe "Confidential notes on issues", :js do
+ it_behaves_like 'confidential notes on issuables' do
+ let_it_be(:issuable_parent) { create(:project) }
+ let_it_be(:issuable) { create(:issue, project: issuable_parent) }
+ let_it_be(:user) { create(:user) }
+
+ let(:issuable_path) { project_issue_path(issuable_parent, issuable) }
+ end
+end
diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
index 05eb656461e..40b0bfd9aa4 100644
--- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
@@ -9,6 +9,10 @@ RSpec.describe 'Dropdown assignee', :js do
let_it_be(:user) { create(:user) }
let_it_be(:issue) { create(:issue, project: project) }
+ before do
+ stub_feature_flags(or_issuable_queries: false)
+ end
+
describe 'behavior' do
before do
project.add_maintainer(user)
diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb
index 36a8f1f3902..a67d114c6d1 100644
--- a/spec/features/issues/filtered_search/dropdown_author_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe 'Dropdown author', :js do
let_it_be(:issue) { create(:issue, project: project) }
before do
+ stub_feature_flags(or_issuable_queries: false)
project.add_maintainer(user)
sign_in(user)
diff --git a/spec/features/issues/filtered_search/dropdown_hint_spec.rb b/spec/features/issues/filtered_search/dropdown_hint_spec.rb
index dcbab308efa..cbe917931aa 100644
--- a/spec/features/issues/filtered_search/dropdown_hint_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_hint_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe 'Dropdown hint', :js do
let_it_be(:issue) { create(:issue, project: project) }
before do
+ stub_feature_flags(or_issuable_queries: false)
project.add_maintainer(user)
end
diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb
index 8d96bbc38cb..e48df1b1c53 100644
--- a/spec/features/issues/filtered_search/filter_issues_spec.rb
+++ b/spec/features/issues/filtered_search/filter_issues_spec.rb
@@ -19,6 +19,7 @@ RSpec.describe 'Filter issues', :js do
end
before do
+ stub_feature_flags(or_issuable_queries: false)
project.add_maintainer(user)
create(:issue, project: project, author: user2, title: "Bug report 1")
diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb
index c44181a60e4..854b88c3f81 100644
--- a/spec/features/issues/filtered_search/visual_tokens_spec.rb
+++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb
@@ -15,6 +15,7 @@ RSpec.describe 'Visual tokens', :js do
let_it_be(:issue) { create(:issue, project: project) }
before do
+ stub_feature_flags(or_issuable_queries: false)
project.add_member(user, :maintainer)
project.add_member(user_rock, :maintainer)
sign_in(user)
diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb
index e749c555dcf..fe591d7fe3a 100644
--- a/spec/features/issues/form_spec.rb
+++ b/spec/features/issues/form_spec.rb
@@ -140,14 +140,10 @@ RSpec.describe 'New/edit issue', :js do
end
expect(find('a', text: 'Assign to me', visible: false)).not_to be_visible
- click_button 'Milestone'
- page.within '.issue-milestone' do
- click_link milestone.title
- end
+ click_button 'Select milestone'
+ click_button milestone.title
expect(find('input[name="issue[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
- page.within '.js-milestone-select' do
- expect(page).to have_content milestone.title
- end
+ expect(page).to have_button milestone.title
click_button 'Labels'
page.within '.dropdown-menu-labels' do
@@ -307,14 +303,11 @@ RSpec.describe 'New/edit issue', :js do
end
it 'escapes milestone' do
- click_button 'Milestone'
+ click_button 'Select milestone'
+ click_button milestone.title
page.within '.issue-milestone' do
- click_link milestone.title
- end
-
- page.within '.js-milestone-select' do
- expect(page).to have_content milestone.title
+ expect(page).to have_button milestone.title
expect(page).not_to have_selector 'img'
end
end
@@ -444,9 +437,7 @@ RSpec.describe 'New/edit issue', :js do
expect(page).to have_content user.name
end
- page.within '.js-milestone-select' do
- expect(page).to have_content milestone.title
- end
+ expect(page).to have_button milestone.title
click_button 'Labels'
page.within '.dropdown-menu-labels' do
diff --git a/spec/features/issues/user_bulk_edits_issues_labels_spec.rb b/spec/features/issues/user_bulk_edits_issues_labels_spec.rb
index 4837d13574c..2a201e0bc23 100644
--- a/spec/features/issues/user_bulk_edits_issues_labels_spec.rb
+++ b/spec/features/issues/user_bulk_edits_issues_labels_spec.rb
@@ -417,7 +417,7 @@ RSpec.describe 'Issues > Labels bulk assignment' do
click_button 'Select milestone'
wait_for_requests
items.map do |item|
- click_link item
+ click_button item
end
end
diff --git a/spec/features/issues/user_bulk_edits_issues_spec.rb b/spec/features/issues/user_bulk_edits_issues_spec.rb
index 1ef2918adec..d7fad355cb4 100644
--- a/spec/features/issues/user_bulk_edits_issues_spec.rb
+++ b/spec/features/issues/user_bulk_edits_issues_spec.rb
@@ -80,7 +80,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js do
click_button 'Edit issues'
check 'Select all'
click_button 'Select milestone'
- click_link milestone.title
+ click_button milestone.title
click_update_issues_button
expect(page.find('.issue')).to have_content milestone.title
@@ -97,7 +97,7 @@ RSpec.describe 'Multiple issue updating from issues#index', :js do
click_button 'Edit issues'
check 'Select all'
click_button 'Select milestone'
- click_link 'No milestone'
+ click_button 'No milestone'
click_update_issues_button
expect(find('.issue:first-of-type')).not_to have_text milestone.title
diff --git a/spec/features/issues/user_comments_on_issue_spec.rb b/spec/features/issues/user_comments_on_issue_spec.rb
index a1e7c007b90..ef00e66af7e 100644
--- a/spec/features/issues/user_comments_on_issue_spec.rb
+++ b/spec/features/issues/user_comments_on_issue_spec.rb
@@ -5,9 +5,9 @@ require "spec_helper"
RSpec.describe "User comments on issue", :js do
include Spec::Support::Helpers::Features::NotesHelpers
- let(:project) { create(:project_empty_repo, :public) }
- let(:issue) { create(:issue, project: project) }
- let(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be(:user) { create(:user) }
before do
project.add_guest(user)
diff --git a/spec/features/issues/user_creates_issue_spec.rb b/spec/features/issues/user_creates_issue_spec.rb
index b96490bd7e7..1d023a15159 100644
--- a/spec/features/issues/user_creates_issue_spec.rb
+++ b/spec/features/issues/user_creates_issue_spec.rb
@@ -188,7 +188,7 @@ RSpec.describe "User creates issue" do
end
it 'does not hide the milestone select' do
- expect(page).to have_selector('[data-testid="issuable-milestone-dropdown"]')
+ expect(page).to have_button 'Select milestone'
end
end
@@ -204,7 +204,7 @@ RSpec.describe "User creates issue" do
end
it 'shows the milestone select' do
- expect(page).to have_selector('[data-testid="issuable-milestone-dropdown"]')
+ expect(page).to have_button 'Select milestone'
end
it 'hides the incident help text' do
@@ -265,7 +265,7 @@ RSpec.describe "User creates issue" do
end
it 'shows the milestone select' do
- expect(page).to have_selector('[data-testid="issuable-milestone-dropdown"]')
+ expect(page).to have_button 'Select milestone'
end
it 'hides the weight input' do
diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb
index 4eecb63c47e..75df85f362f 100644
--- a/spec/features/issues/user_edits_issue_spec.rb
+++ b/spec/features/issues/user_edits_issue_spec.rb
@@ -101,6 +101,35 @@ RSpec.describe "Issues > User edits issue", :js do
visit project_issue_path(project, issue)
end
+ describe 'edit description' do
+ def click_edit_issue_description
+ click_on 'Edit title and description'
+ end
+
+ it 'places focus on the web editor' do
+ toggle_editing_mode_selector = '[data-testid="toggle-editing-mode-button"] label'
+ content_editor_focused_selector = '[data-testid="content-editor"].is-focused'
+ markdown_field_focused_selector = 'textarea:focus'
+ click_edit_issue_description
+
+ expect(page).to have_selector(markdown_field_focused_selector)
+
+ find(toggle_editing_mode_selector, text: 'Rich text').click
+
+ expect(page).not_to have_selector(content_editor_focused_selector)
+
+ refresh
+
+ click_edit_issue_description
+
+ expect(page).to have_selector(content_editor_focused_selector)
+
+ find(toggle_editing_mode_selector, text: 'Source').click
+
+ expect(page).not_to have_selector(markdown_field_focused_selector)
+ end
+ end
+
describe 'update labels' do
it 'will not send ajax request when no data is changed' do
page.within '.labels' do
@@ -186,7 +215,7 @@ RSpec.describe "Issues > User edits issue", :js do
visit project_issue_path(project, issue)
page.within('.assignee') do
- expect(page).to have_content "#{user.name}"
+ expect(page).to have_content user.name.to_s
click_link 'Edit'
click_link 'Unassigned'
@@ -261,7 +290,7 @@ RSpec.describe "Issues > User edits issue", :js do
visit project_issue_path(project, issue)
page.within('.assignee') do
- expect(page).to have_content "#{user.name}"
+ expect(page).to have_content user.name.to_s
click_button('Edit')
wait_for_requests
diff --git a/spec/features/issues/user_interacts_with_awards_spec.rb b/spec/features/issues/user_interacts_with_awards_spec.rb
index 47b28b88108..a2dea7f048b 100644
--- a/spec/features/issues/user_interacts_with_awards_spec.rb
+++ b/spec/features/issues/user_interacts_with_awards_spec.rb
@@ -209,22 +209,25 @@ RSpec.describe 'User interacts with awards' do
it 'adds award to issue' do
first('[data-testid="award-button"]').click
-
+ wait_for_requests
expect(page).to have_selector('[data-testid="award-button"].selected')
expect(first('[data-testid="award-button"]')).to have_content '1'
visit project_issue_path(project, issue)
+ wait_for_requests
expect(first('[data-testid="award-button"]')).to have_content '1'
end
it 'removes award from issue', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/375241' do
first('[data-testid="award-button"]').click
+ wait_for_requests
find('[data-testid="award-button"].selected').click
-
+ wait_for_requests
expect(first('[data-testid="award-button"]')).to have_content '0'
visit project_issue_path(project, issue)
+ wait_for_requests
expect(first('[data-testid="award-button"]')).to have_content '0'
end
diff --git a/spec/features/issues/user_sees_empty_state_spec.rb b/spec/features/issues/user_sees_empty_state_spec.rb
index 0e2a7cb4358..b4c5a57de4f 100644
--- a/spec/features/issues/user_sees_empty_state_spec.rb
+++ b/spec/features/issues/user_sees_empty_state_spec.rb
@@ -22,9 +22,9 @@ RSpec.describe 'Issues > User sees empty state', :js do
it 'user sees empty state' do
visit project_issues_path(project)
+ expect(page).to have_content('Use issues to collaborate on ideas, solve problems, and plan work')
+ expect(page).to have_content('Learn more about issues.')
expect(page).to have_content('Register / Sign In')
- expect(page).to have_content('The Issue Tracker is the place to add things that need to be improved or solved in a project.')
- expect(page).to have_content('You can register or sign in to create issues for this project.')
end
it_behaves_like 'empty state with filters'
diff --git a/spec/features/issues/user_sorts_issues_spec.rb b/spec/features/issues/user_sorts_issues_spec.rb
index 7add6c782f7..2716d742be3 100644
--- a/spec/features/issues/user_sorts_issues_spec.rb
+++ b/spec/features/issues/user_sorts_issues_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe "User sorts issues" do
sign_in(user)
end
- it 'keeps the sort option', :js do
+ it 'keeps the sort option', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/378184' do
visit(project_issues_path(project))
click_button 'Created date'
diff --git a/spec/features/jira_connect/subscriptions_spec.rb b/spec/features/jira_connect/subscriptions_spec.rb
index 94c293c88b9..0468cfd70fc 100644
--- a/spec/features/jira_connect/subscriptions_spec.rb
+++ b/spec/features/jira_connect/subscriptions_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe 'Subscriptions Content Security Policy' do
p.style_src :self, 'https://some-cdn.test'
end
- setup_existing_csp_for_controller(JiraConnect::SubscriptionsController, csp)
+ setup_csp_for_controller(JiraConnect::SubscriptionsController, csp)
end
it 'appends to CSP directives' do
diff --git a/spec/features/markdown/sandboxed_mermaid_spec.rb b/spec/features/markdown/sandboxed_mermaid_spec.rb
index 05fe83b3107..2bf88d7882d 100644
--- a/spec/features/markdown/sandboxed_mermaid_spec.rb
+++ b/spec/features/markdown/sandboxed_mermaid_spec.rb
@@ -3,30 +3,54 @@
require 'spec_helper'
RSpec.describe 'Sandboxed Mermaid rendering', :js do
- let_it_be(:project) { create(:project, :public) }
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:description) do
+ <<~MERMAID
+ ```mermaid
+ graph TD;
+ A-->B;
+ A-->C;
+ B-->D;
+ C-->D;
+ ```
+ MERMAID
+ end
- before do
- stub_feature_flags(sandboxed_mermaid: true)
+ let_it_be(:expected) do
+ %(<iframe src="/-/sandbox/mermaid" sandbox="allow-scripts allow-popups" frameborder="0" scrolling="no")
end
- it 'includes mermaid frame correctly' do
- description = <<~MERMAID
- ```mermaid
- graph TD;
- A-->B;
- A-->C;
- B-->D;
- C-->D;
- ```
- MERMAID
+ context 'in an issue' do
+ let(:issue) { create(:issue, project: project, description: description) }
+
+ it 'includes mermaid frame correctly' do
+ visit project_issue_path(project, issue)
+
+ wait_for_requests
+
+ expect(page.html).to include(expected)
+ end
+ end
+
+ context 'in a merge request' do
+ let(:merge_request) { create(:merge_request_with_diffs, source_project: project, description: description) }
+
+ it 'renders diffs and includes mermaid frame correctly' do
+ visit(diffs_project_merge_request_path(project, merge_request))
+
+ wait_for_requests
- issue = create(:issue, project: project, description: description)
+ page.within('.tab-content') do
+ expect(page).to have_selector('.diffs')
+ end
- visit project_issue_path(project, issue)
+ visit(project_merge_request_path(project, merge_request))
- wait_for_requests
+ wait_for_requests
- expected = %(<iframe src="/-/sandbox/mermaid" sandbox="allow-scripts allow-popups" frameborder="0" scrolling="no")
- expect(page.html).to include(expected)
+ page.within('.merge-request') do
+ expect(page.html).to include(expected)
+ end
+ end
end
end
diff --git a/spec/features/merge_request/user_accepts_merge_request_spec.rb b/spec/features/merge_request/user_accepts_merge_request_spec.rb
index 159306b28d8..b50e6779e07 100644
--- a/spec/features/merge_request/user_accepts_merge_request_spec.rb
+++ b/spec/features/merge_request/user_accepts_merge_request_spec.rb
@@ -18,6 +18,8 @@ RSpec.describe 'User accepts a merge request', :js, :sidekiq_might_not_need_inli
click_button('Merge')
+ puts merge_request.short_merged_commit_sha
+
expect(page).to have_content("Changes merged into #{merge_request.target_branch} with #{merge_request.short_merged_commit_sha}")
end
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 0dd87ac3e24..59b5923b2a1 100644
--- a/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb
+++ b/spec/features/merge_request/user_edits_assignees_sidebar_spec.rb
@@ -88,7 +88,7 @@ RSpec.describe 'Merge request > User edits assignees sidebar', :js do
end
context 'when GraphQL assignees widget feature flag is enabled' do
- let(:sidebar_assignee_dropdown_item) { sidebar_assignee_block.find(".dropdown-item", text: assignee.username ) }
+ let(:sidebar_assignee_dropdown_item) { sidebar_assignee_block.find(".dropdown-item", text: assignee.username) }
let(:sidebar_assignee_dropdown_tooltip) { sidebar_assignee_dropdown_item['title'] }
context 'when user is an owner' do
diff --git a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb
index 21f96299958..abf916c72b3 100644
--- a/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb
+++ b/spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb
@@ -151,7 +151,7 @@ RSpec.describe 'Merge request > User merges when pipeline succeeds', :js do
# Wait for the `ci_status` and `merge_check` requests
wait_for_requests
- page.within('.mr-section-container') do
+ page.within('.mr-state-widget') do
expect(page).to have_content('Something went wrong. Try again.')
end
end
@@ -170,7 +170,7 @@ RSpec.describe 'Merge request > User merges when pipeline succeeds', :js do
# Wait for the `ci_status` and `merge_check` requests
wait_for_requests
- page.within('.mr-section-container') do
+ page.within('.mr-state-widget') do
expect(page).to have_content('Something went wrong. Try again.')
end
end
diff --git a/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb b/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb
index 60ea168940a..cf4875a7a25 100644
--- a/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb
+++ b/spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe 'Merge request > User scrolls to note on load', :js do
wait_for_all_requests
- expect(page).to have_selector("#{fragment_id}")
+ expect(page).to have_selector(fragment_id.to_s)
page_scroll_y = page.evaluate_script("window.scrollY")
fragment_position_top = page.evaluate_script("Math.round(document.querySelector('#{fragment_id}').getBoundingClientRect().top + window.pageYOffset)")
diff --git a/spec/features/merge_request/user_sees_deployment_widget_spec.rb b/spec/features/merge_request/user_sees_deployment_widget_spec.rb
index 63ac7862b06..6f8ecf5f5c2 100644
--- a/spec/features/merge_request/user_sees_deployment_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_deployment_widget_spec.rb
@@ -18,6 +18,11 @@ RSpec.describe 'Merge request > User sees deployment widget', :js do
let(:build) { create(:ci_build, :with_deployment, environment: environment.name, pipeline: pipeline) }
let!(:deployment) { build.deployment }
+ def assert_env_widget(text, env_name)
+ expect(find('.js-deploy-env-name')[:title]).to have_text(env_name)
+ expect(page).to have_content(text)
+ end
+
before do
merge_request.update!(merge_commit_sha: sha)
project.add_member(user, role)
@@ -33,7 +38,7 @@ RSpec.describe 'Merge request > User sees deployment widget', :js do
visit project_merge_request_path(project, merge_request)
wait_for_requests
- expect(page).to have_content("Deployed to #{environment.name}")
+ assert_env_widget("Deployed to", environment.name)
expect(find('.js-deploy-time')['title']).to eq(deployment.created_at.to_time.in_time_zone.to_s(:medium))
end
@@ -47,8 +52,8 @@ RSpec.describe 'Merge request > User sees deployment widget', :js do
wait_for_requests
expect(page).to have_selector('.js-deployment-info', count: 1)
- expect(page).to have_content("#{environment.name}")
- expect(page).not_to have_content("#{environment2.name}")
+ expect(find('.js-deploy-env-name')[:title]).to have_text(environment.name)
+ expect(find('.js-deploy-env-name')[:title]).not_to have_text(environment2.name)
end
end
end
@@ -62,7 +67,7 @@ RSpec.describe 'Merge request > User sees deployment widget', :js do
visit project_merge_request_path(project, merge_request)
wait_for_requests
- expect(page).to have_content("Failed to deploy to #{environment.name}")
+ assert_env_widget("Failed to deploy to", environment.name)
expect(page).not_to have_css('.js-deploy-time')
end
end
@@ -76,7 +81,7 @@ RSpec.describe 'Merge request > User sees deployment widget', :js do
visit project_merge_request_path(project, merge_request)
wait_for_requests
- expect(page).to have_content("Deploying to #{environment.name}")
+ assert_env_widget("Deploying to", environment.name)
expect(page).not_to have_css('.js-deploy-time')
end
end
@@ -89,7 +94,7 @@ RSpec.describe 'Merge request > User sees deployment widget', :js do
visit project_merge_request_path(project, merge_request)
wait_for_requests
- expect(page).to have_content("Will deploy to #{environment.name}")
+ assert_env_widget("Will deploy to", environment.name)
expect(page).not_to have_css('.js-deploy-time')
end
end
@@ -103,7 +108,7 @@ RSpec.describe 'Merge request > User sees deployment widget', :js do
visit project_merge_request_path(project, merge_request)
wait_for_requests
- expect(page).to have_content("Canceled deployment to #{environment.name}")
+ assert_env_widget("Canceled deployment to", environment.name)
expect(page).not_to have_css('.js-deploy-time')
end
end
diff --git a/spec/features/merge_request/user_sees_diff_spec.rb b/spec/features/merge_request/user_sees_diff_spec.rb
index 2e65183d26f..0bae019793c 100644
--- a/spec/features/merge_request/user_sees_diff_spec.rb
+++ b/spec/features/merge_request/user_sees_diff_spec.rb
@@ -38,6 +38,20 @@ RSpec.describe 'Merge request > User sees diff', :js do
end
end
+ context 'when linking to a line' do
+ let(:note) { create :diff_note_on_merge_request, project: project, noteable: merge_request }
+ let(:line) { note.diff_file.highlighted_diff_lines.last }
+ let(:line_code) { line.line_code }
+
+ before do
+ visit "#{diffs_project_merge_request_path(project, merge_request)}##{line_code}"
+ end
+
+ it 'shows the linked line' do
+ expect(page).to have_selector("[id='#{line_code}']", visible: true, obscured: false)
+ end
+ end
+
context 'when merge request has overflow' do
it 'displays warning' do
allow(Commit).to receive(:max_diff_options).and_return(max_files: 3)
diff --git a/spec/features/merge_request/user_sees_discussions_navigation_spec.rb b/spec/features/merge_request/user_sees_discussions_navigation_spec.rb
new file mode 100644
index 00000000000..9fbe7662fc0
--- /dev/null
+++ b/spec/features/merge_request/user_sees_discussions_navigation_spec.rb
@@ -0,0 +1,222 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Merge request > User sees discussions navigation', :js do
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:user) { project.creator }
+ let_it_be(:merge_request) { create(:merge_request, source_project: project) }
+
+ before do
+ # FIXME: before removing this please fix discussions navigation with this flag enabled
+ stub_feature_flags(moved_mr_sidebar: false)
+ project.add_maintainer(user)
+ sign_in(user)
+ end
+
+ describe 'Code discussions' do
+ let!(:position) do
+ build(:text_diff_position, :added,
+ file: "files/images/wm.svg",
+ new_line: 1,
+ diff_refs: merge_request.diff_refs
+ )
+ end
+
+ let!(:first_discussion) do
+ create(:diff_note_on_merge_request,
+ noteable: merge_request,
+ project: project,
+ position: position
+ ).to_discussion
+ end
+
+ let!(:second_discussion) do
+ create(:diff_note_on_merge_request,
+ noteable: merge_request,
+ project: project,
+ position: position
+ ).to_discussion
+ end
+
+ let(:first_discussion_selector) { ".discussion[data-discussion-id='#{first_discussion.id}']" }
+ let(:second_discussion_selector) { ".discussion[data-discussion-id='#{second_discussion.id}']" }
+
+ shared_examples 'a page with a thread navigation' do
+ context 'with active threads' do
+ it 'navigates to the first thread' do
+ goto_next_thread
+ expect(page).to have_selector(first_discussion_selector, obscured: false)
+ end
+
+ it 'navigates to the last thread' do
+ goto_previous_thread
+ expect(page).to have_selector(second_discussion_selector, obscured: false)
+ end
+
+ it 'navigates through active threads' do
+ goto_next_thread
+ goto_next_thread
+ expect(page).to have_selector(second_discussion_selector, obscured: false)
+ end
+
+ it 'cycles back to the first thread' do
+ goto_next_thread
+ goto_next_thread
+ goto_next_thread
+ expect(page).to have_selector(first_discussion_selector, obscured: false)
+ end
+
+ it 'cycles back to the last thread' do
+ goto_previous_thread
+ goto_previous_thread
+ goto_previous_thread
+ expect(page).to have_selector(second_discussion_selector, obscured: false)
+ end
+ end
+
+ context 'with resolved threads' do
+ let!(:resolved_discussion) do
+ create(:diff_note_on_merge_request,
+ noteable: merge_request,
+ project: project,
+ position: position
+ ).to_discussion
+ end
+
+ let(:resolved_discussion_selector) { ".discussion[data-discussion-id='#{resolved_discussion.id}']" }
+
+ before do
+ # :resolved attr doesn't actually resolve the thread but just collapses it
+ page.within(resolved_discussion_selector) do
+ click_button text: 'Resolve thread'
+ end
+ page.execute_script("window.scrollTo(0,0)")
+ end
+
+ it 'excludes resolved threads during navigation' do
+ goto_next_thread
+ goto_next_thread
+ goto_next_thread
+ expect(page).to have_selector(first_discussion_selector, obscured: false)
+ end
+ end
+ end
+
+ describe "Overview page discussions navigation" do
+ before do
+ visit project_merge_request_path(project, merge_request)
+ end
+
+ it_behaves_like 'a page with a thread navigation'
+
+ context 'with collapsed threads' do
+ before do
+ page.within(first_discussion_selector) do
+ click_button 'Hide thread'
+ end
+ end
+
+ it 'expands threads during navigation' do
+ goto_next_thread
+ expect(page).to have_selector "#note_#{first_discussion.first_note.id}"
+ end
+ end
+ end
+
+ describe "Changes page discussions navigation" do
+ before do
+ visit diffs_project_merge_request_path(project, merge_request)
+ end
+
+ it_behaves_like 'a page with a thread navigation'
+ end
+ end
+
+ describe 'Merge request discussions' do
+ shared_examples 'a page with no code discussions' do
+ let!(:first_discussion) do
+ create(:discussion_note_on_merge_request,
+ noteable: merge_request,
+ project: project
+ ).to_discussion
+ end
+
+ let!(:second_discussion) do
+ create(:discussion_note_on_merge_request,
+ noteable: merge_request,
+ project: project
+ ).to_discussion
+ end
+
+ let(:first_discussion_selector) { ".discussion[data-discussion-id='#{first_discussion.id}']" }
+ let(:second_discussion_selector) { ".discussion[data-discussion-id='#{second_discussion.id}']" }
+
+ describe "Changes page discussions navigation" do
+ it 'navigates to the first discussion on the Overview page' do
+ goto_next_thread
+ expect(page).to have_selector(first_discussion_selector, obscured: false)
+ end
+
+ it 'navigates to the last discussion on the Overview page' do
+ goto_previous_thread
+ expect(page).to have_selector(second_discussion_selector, obscured: false)
+ end
+ end
+ end
+
+ context 'on changes page' do
+ before do
+ visit diffs_project_merge_request_path(project, merge_request)
+ end
+
+ it_behaves_like 'a page with no code discussions'
+ end
+
+ context 'on commits page' do
+ before do
+ # we can't go directly to the commits page since it doesn't load discussions
+ visit project_merge_request_path(project, merge_request)
+ click_link 'Commits'
+ end
+
+ it_behaves_like 'a page with no code discussions'
+ end
+
+ context 'on pipelines page' do
+ before do
+ visit project_merge_request_path(project, merge_request)
+ click_link 'Pipelines'
+ end
+
+ it_behaves_like 'a page with no code discussions'
+ end
+ end
+
+ def goto_next_thread
+ begin
+ # this is required when moved_mr_sidebar is enabled
+ page.within('.issue-sticky-header') do
+ click_button 'Go to next unresolved thread'
+ end
+ rescue StandardError
+ click_button 'Go to next unresolved thread'
+ end
+ wait_for_scroll_end
+ end
+
+ def goto_previous_thread
+ begin
+ page.within('.issue-sticky-header') do
+ click_button 'Go to previous unresolved thread'
+ end
+ rescue StandardError
+ click_button 'Go to previous unresolved thread'
+ end
+ wait_for_scroll_end
+ end
+
+ def wait_for_scroll_end
+ sleep(1)
+ end
+end
diff --git a/spec/features/merge_request/user_sees_merge_widget_spec.rb b/spec/features/merge_request/user_sees_merge_widget_spec.rb
index 77ac6fac22f..c4a29c1fb07 100644
--- a/spec/features/merge_request/user_sees_merge_widget_spec.rb
+++ b/spec/features/merge_request/user_sees_merge_widget_spec.rb
@@ -14,15 +14,13 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
let(:merge_request_in_only_mwps_project) { create(:merge_request, source_project: project_only_mwps) }
def click_expand_button
- find('[data-testid="report-section-expand-button"]').click
+ find('[data-testid="toggle-button"]').click
end
before do
project.add_maintainer(user)
project_only_mwps.add_maintainer(user)
sign_in(user)
-
- stub_feature_flags(refactor_mr_widget_test_summary: false)
end
context 'new merge request', :sidekiq_might_not_need_inline do
@@ -64,7 +62,8 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
wait_for_requests
page.within('.js-pre-deployment') do
- expect(page).to have_content("Deployed to #{environment.name}")
+ expect(find('.js-deploy-env-name')[:title]).to have_text(environment.name)
+ expect(page).to have_content("Deployed to")
expect(find('.js-deploy-url')[:href]).to include(environment.formatted_external_url)
end
end
@@ -343,7 +342,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
# Wait for the `ci_status` and `merge_check` requests
wait_for_requests
- page.within('.mr-section-container') do
+ page.within('.mr-state-widget') do
expect(page).to have_content('Something went wrong.')
end
end
@@ -364,7 +363,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
# Wait for the `ci_status` and `merge_check` requests
wait_for_requests
- page.within('.mr-section-container') do
+ page.within('.mr-state-widget') do
expect(page).to have_content('Something went wrong.')
end
end
@@ -399,9 +398,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
it 'updates the MR widget', :sidekiq_might_not_need_inline do
click_button 'Merge'
- page.within('.mr-widget-body') do
- expect(page).to have_content('An error occurred while merging')
- end
+ expect(page).to have_content('An error occurred while merging')
end
end
@@ -531,7 +528,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
end
it 'shows parsing status' do
- expect(page).to have_content('Test summary results are being parsed')
+ expect(page).to have_content('Test summary results are loading')
end
end
@@ -546,7 +543,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
end
it 'shows parsed results' do
- expect(page).to have_content('Test summary contained')
+ expect(page).to have_content('Test summary:')
end
end
@@ -560,7 +557,7 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
end
it 'shows the error state' do
- expect(page).to have_content('Test summary failed loading results')
+ expect(page).to have_content('Test summary failed to load results')
end
end
@@ -607,13 +604,13 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
end
it 'shows test reports summary which includes the new failure' do
- within(".js-reports-container") do
+ within('[data-testid="widget-extension"]') do
click_expand_button
- expect(page).to have_content('Test summary contained 1 failed out of 2 total tests')
- within(".js-report-section-container") do
- expect(page).to have_content('rspec found no changed test results out of 1 total test')
- expect(page).to have_content('junit found 1 failed out of 1 total test')
+ expect(page).to have_content('Test summary: 1 failed, 2 total tests')
+ within('[data-testid="widget-extension-collapsed-section"]') do
+ expect(page).to have_content('rspec: no changed test results, 1 total test')
+ expect(page).to have_content('junit: 1 failed, 1 total test')
expect(page).to have_content('New')
expect(page).to have_content('addTest')
end
@@ -622,15 +619,15 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
context 'when user clicks the new failure' do
it 'shows the test report detail' do
- within(".js-reports-container") do
+ within('[data-testid="widget-extension"]') do
click_expand_button
- within(".js-report-section-container") do
- click_button 'addTest'
+ within('[data-testid="widget-extension-collapsed-section"]') do
+ click_link 'addTest'
end
end
- within("#modal-mrwidget-reports") do
+ within('[data-testid="test-case-details-modal"]') do
expect(page).to have_content('addTest')
expect(page).to have_content('6.66')
expect(page).to have_content(sample_java_failed_message.gsub(/\s+/, ' ').strip)
@@ -655,13 +652,13 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
end
it 'shows test reports summary which includes the existing failure' do
- within(".js-reports-container") do
+ within('[data-testid="widget-extension"]') do
click_expand_button
- expect(page).to have_content('Test summary contained 1 failed out of 2 total tests')
- within(".js-report-section-container") do
- expect(page).to have_content('rspec found 1 failed out of 1 total test')
- expect(page).to have_content('junit found no changed test results out of 1 total test')
+ expect(page).to have_content('Test summary: 1 failed, 2 total tests')
+ within('[data-testid="widget-extension-collapsed-section"]') do
+ expect(page).to have_content('rspec: 1 failed, 1 total test')
+ expect(page).to have_content('junit: no changed test results, 1 total test')
expect(page).to have_content('Test#sum when a is 1 and b is 3 returns summary')
end
end
@@ -669,15 +666,15 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
context 'when user clicks the existing failure' do
it 'shows test report detail of it' do
- within(".js-reports-container") do
+ within('[data-testid="widget-extension"]') do
click_expand_button
- within(".js-report-section-container") do
- click_button 'Test#sum when a is 1 and b is 3 returns summary'
+ within('[data-testid="widget-extension-collapsed-section"]') do
+ click_link 'Test#sum when a is 1 and b is 3 returns summary'
end
end
- within("#modal-mrwidget-reports") do
+ within('[data-testid="test-case-details-modal"]') do
expect(page).to have_content('Test#sum when a is 1 and b is 3 returns summary')
expect(page).to have_content('2.22')
expect(page).to have_content(sample_rspec_failed_message.gsub(/\s+/, ' ').strip)
@@ -702,13 +699,14 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
end
it 'shows test reports summary which includes the resolved failure' do
- within(".js-reports-container") do
+ within('[data-testid="widget-extension"]') do
click_expand_button
- expect(page).to have_content('Test summary contained 1 fixed test result out of 2 total tests')
- within(".js-report-section-container") do
- expect(page).to have_content('rspec found no changed test results out of 1 total test')
- expect(page).to have_content('junit found 1 fixed test result out of 1 total test')
+ expect(page).to have_content('Test summary: 1 fixed test result, 2 total tests')
+ within('[data-testid="widget-extension-collapsed-section"]') do
+ expect(page).to have_content('rspec: no changed test results, 1 total test')
+ expect(page).to have_content('junit: 1 fixed test result, 1 total test')
+ expect(page).to have_content('Fixed')
expect(page).to have_content('addTest')
end
end
@@ -716,15 +714,15 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
context 'when user clicks the resolved failure' do
it 'shows test report detail of it' do
- within(".js-reports-container") do
+ within('[data-testid="widget-extension"]') do
click_expand_button
- within(".js-report-section-container") do
- click_button 'addTest'
+ within('[data-testid="widget-extension-collapsed-section"]') do
+ click_link 'addTest'
end
end
- within("#modal-mrwidget-reports") do
+ within('[data-testid="test-case-details-modal"]') do
expect(page).to have_content('addTest')
expect(page).to have_content('5.55')
end
@@ -748,13 +746,13 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
end
it 'shows test reports summary which includes the new error' do
- within(".js-reports-container") do
+ within('[data-testid="widget-extension"]') do
click_expand_button
- expect(page).to have_content('Test summary contained 1 error out of 2 total tests')
- within(".js-report-section-container") do
- expect(page).to have_content('rspec found no changed test results out of 1 total test')
- expect(page).to have_content('junit found 1 error out of 1 total test')
+ expect(page).to have_content('Test summary: 1 error, 2 total tests')
+ within('[data-testid="widget-extension-collapsed-section"]') do
+ expect(page).to have_content('rspec: no changed test results, 1 total test')
+ expect(page).to have_content('junit: 1 error, 1 total test')
expect(page).to have_content('New')
expect(page).to have_content('addTest')
end
@@ -763,15 +761,15 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
context 'when user clicks the new error' do
it 'shows the test report detail' do
- within(".js-reports-container") do
+ within('[data-testid="widget-extension"]') do
click_expand_button
- within(".js-report-section-container") do
- click_button 'addTest'
+ within('[data-testid="widget-extension-collapsed-section"]') do
+ click_link 'addTest'
end
end
- within("#modal-mrwidget-reports") do
+ within('[data-testid="test-case-details-modal"]') do
expect(page).to have_content('addTest')
expect(page).to have_content('8.88')
end
@@ -795,13 +793,13 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
end
it 'shows test reports summary which includes the existing error' do
- within(".js-reports-container") do
+ within('[data-testid="widget-extension"]') do
click_expand_button
- expect(page).to have_content('Test summary contained 1 error out of 2 total tests')
- within(".js-report-section-container") do
- expect(page).to have_content('rspec found 1 error out of 1 total test')
- expect(page).to have_content('junit found no changed test results out of 1 total test')
+ expect(page).to have_content('Test summary: 1 error, 2 total tests')
+ within('[data-testid="widget-extension-collapsed-section"]') do
+ expect(page).to have_content('rspec: 1 error, 1 total test')
+ expect(page).to have_content('junit: no changed test results, 1 total test')
expect(page).to have_content('Test#sum when a is 4 and b is 4 returns summary')
end
end
@@ -809,15 +807,15 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
context 'when user clicks the existing error' do
it 'shows test report detail of it' do
- within(".js-reports-container") do
+ within('[data-testid="widget-extension"]') do
click_expand_button
- within(".js-report-section-container") do
- click_button 'Test#sum when a is 4 and b is 4 returns summary'
+ within('[data-testid="widget-extension-collapsed-section"]') do
+ click_link 'Test#sum when a is 4 and b is 4 returns summary'
end
end
- within("#modal-mrwidget-reports") do
+ within('[data-testid="test-case-details-modal"]') do
expect(page).to have_content('Test#sum when a is 4 and b is 4 returns summary')
expect(page).to have_content('4.44')
end
@@ -841,13 +839,14 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
end
it 'shows test reports summary which includes the resolved error' do
- within(".js-reports-container") do
+ within('[data-testid="widget-extension"]') do
click_expand_button
- expect(page).to have_content('Test summary contained 1 fixed test result out of 2 total tests')
- within(".js-report-section-container") do
- expect(page).to have_content('rspec found no changed test results out of 1 total test')
- expect(page).to have_content('junit found 1 fixed test result out of 1 total test')
+ expect(page).to have_content('Test summary: 1 fixed test result, 2 total tests')
+ within('[data-testid="widget-extension-collapsed-section"]') do
+ expect(page).to have_content('rspec: no changed test results, 1 total test')
+ expect(page).to have_content('junit: 1 fixed test result, 1 total test')
+ expect(page).to have_content('Fixed')
expect(page).to have_content('addTest')
end
end
@@ -855,15 +854,15 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
context 'when user clicks the resolved error' do
it 'shows test report detail of it' do
- within(".js-reports-container") do
+ within('[data-testid="widget-extension"]') do
click_expand_button
- within(".js-report-section-container") do
- click_button 'addTest'
+ within('[data-testid="widget-extension-collapsed-section"]') do
+ click_link 'addTest'
end
end
- within("#modal-mrwidget-reports") do
+ within('[data-testid="test-case-details-modal"]') do
expect(page).to have_content('addTest')
expect(page).to have_content('5.55')
end
@@ -895,13 +894,13 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
end
it 'shows test reports summary which includes the resolved failure' do
- within(".js-reports-container") do
+ within('[data-testid="widget-extension"]') do
click_expand_button
- expect(page).to have_content('Test summary contained 20 failed out of 20 total tests')
- within(".js-report-section-container") do
- expect(page).to have_content('rspec found 10 failed out of 10 total tests')
- expect(page).to have_content('junit found 10 failed out of 10 total tests')
+ expect(page).to have_content('Test summary: 20 failed, 20 total tests')
+ within('[data-testid="widget-extension-collapsed-section"]') do
+ expect(page).to have_content('rspec: 10 failed, 10 total tests')
+ expect(page).to have_content('junit: 10 failed, 10 total tests')
expect(page).to have_content('Test#sum when a is 1 and b is 3 returns summary', count: 2)
end
diff --git a/spec/features/merge_requests/user_mass_updates_spec.rb b/spec/features/merge_requests/user_mass_updates_spec.rb
index cf9760bcd7f..5c3cb098e28 100644
--- a/spec/features/merge_requests/user_mass_updates_spec.rb
+++ b/spec/features/merge_requests/user_mass_updates_spec.rb
@@ -130,7 +130,7 @@ RSpec.describe 'Merge requests > User mass updates', :js do
click_button 'Edit merge requests'
check 'Select all'
click_button 'Select milestone'
- click_link text
+ click_button text
click_update_merge_requests_button
end
diff --git a/spec/features/monitor_sidebar_link_spec.rb b/spec/features/monitor_sidebar_link_spec.rb
index f612956600f..4f529179522 100644
--- a/spec/features/monitor_sidebar_link_spec.rb
+++ b/spec/features/monitor_sidebar_link_spec.rb
@@ -64,7 +64,6 @@ RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures do
expect(page).not_to have_link('Metrics', href: project_metrics_dashboard_path(project))
expect(page).not_to have_link('Alerts', href: project_alert_management_index_path(project))
expect(page).not_to have_link('Error Tracking', href: project_error_tracking_index_path(project))
- expect(page).not_to have_link('Product Analytics', href: project_product_analytics_path(project))
expect(page).not_to have_link('Kubernetes', href: project_clusters_path(project))
end
@@ -119,7 +118,6 @@ RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures do
expect(page).not_to have_link('Metrics', href: project_metrics_dashboard_path(project))
expect(page).not_to have_link('Alerts', href: project_alert_management_index_path(project))
expect(page).not_to have_link('Error Tracking', href: project_error_tracking_index_path(project))
- expect(page).not_to have_link('Product Analytics', href: project_product_analytics_path(project))
expect(page).not_to have_link('Kubernetes', href: project_clusters_path(project))
end
@@ -135,7 +133,6 @@ RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures do
expect(page).to have_link('Incidents', href: project_incidents_path(project))
expect(page).to have_link('Environments', href: project_environments_path(project))
expect(page).to have_link('Error Tracking', href: project_error_tracking_index_path(project))
- expect(page).to have_link('Product Analytics', href: project_product_analytics_path(project))
expect(page).not_to have_link('Alerts', href: project_alert_management_index_path(project))
expect(page).not_to have_link('Kubernetes', href: project_clusters_path(project))
@@ -154,7 +151,6 @@ RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures do
expect(page).to have_link('Incidents', href: project_incidents_path(project))
expect(page).to have_link('Environments', href: project_environments_path(project))
expect(page).to have_link('Error Tracking', href: project_error_tracking_index_path(project))
- expect(page).to have_link('Product Analytics', href: project_product_analytics_path(project))
expect(page).to have_link('Kubernetes', href: project_clusters_path(project))
end
@@ -171,7 +167,6 @@ RSpec.describe 'Monitor dropdown sidebar', :aggregate_failures do
expect(page).to have_link('Incidents', href: project_incidents_path(project))
expect(page).to have_link('Environments', href: project_environments_path(project))
expect(page).to have_link('Error Tracking', href: project_error_tracking_index_path(project))
- expect(page).to have_link('Product Analytics', href: project_product_analytics_path(project))
expect(page).to have_link('Kubernetes', href: project_clusters_path(project))
end
diff --git a/spec/features/nav/top_nav_tooltip_spec.rb b/spec/features/nav/top_nav_tooltip_spec.rb
index 73e4571e7a2..a110c6cfecf 100644
--- a/spec/features/nav/top_nav_tooltip_spec.rb
+++ b/spec/features/nav/top_nav_tooltip_spec.rb
@@ -10,7 +10,8 @@ RSpec.describe 'top nav tooltips', :js do
visit explore_projects_path
end
- it 'clicking new dropdown hides tooltip', :aggregate_failures do
+ it 'clicking new dropdown hides tooltip', :aggregate_failures,
+ quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/382786' do
btn = '#js-onboarding-new-project-link'
page.find(btn).hover
diff --git a/spec/features/one_trust_spec.rb b/spec/features/one_trust_spec.rb
index 0ed08e8b99b..a7dfbfd6bdf 100644
--- a/spec/features/one_trust_spec.rb
+++ b/spec/features/one_trust_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe 'OneTrust' do
end
it 'has the OneTrust CSP settings', :aggregate_failures do
- expect(response_headers['Content-Security-Policy']).to include("#{onetrust_url}")
+ expect(response_headers['Content-Security-Policy']).to include(onetrust_url.to_s)
expect(page.html).to include("https://cdn.cookielaw.org/consent/#{one_trust_id}/OtAutoBlock.js")
end
end
diff --git a/spec/features/profile_spec.rb b/spec/features/profile_spec.rb
index 913c375f909..ca156642bc8 100644
--- a/spec/features/profile_spec.rb
+++ b/spec/features/profile_spec.rb
@@ -27,41 +27,20 @@ RSpec.describe 'Profile account page', :js do
expect(User.exists?(user.id)).to be_truthy
end
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- it 'deletes user', :js, :sidekiq_inline do
- click_button 'Delete account'
-
- fill_in 'password', with: user.password
+ it 'deletes user', :js, :sidekiq_inline do
+ click_button 'Delete account'
- page.within '.modal' do
- click_button 'Delete account'
- end
+ fill_in 'password', with: user.password
- expect(page).to have_content('Account scheduled for removal')
- expect(
- Users::GhostUserMigration.where(user: user,
- initiator_user: user)
- ).to be_exists
- end
- end
-
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
- end
-
- it 'deletes user', :js, :sidekiq_inline do
+ page.within '.modal' do
click_button 'Delete account'
-
- fill_in 'password', with: user.password
-
- page.within '.modal' do
- click_button 'Delete account'
- end
-
- expect(page).to have_content('Account scheduled for removal')
- expect(User.exists?(user.id)).to be_falsy
end
+
+ expect(page).to have_content('Account scheduled for removal')
+ expect(
+ Users::GhostUserMigration.where(user: user,
+ initiator_user: user)
+ ).to be_exists
end
it 'shows invalid password flash message', :js do
diff --git a/spec/features/profiles/password_spec.rb b/spec/features/profiles/password_spec.rb
index 6c860740354..8887ff1746d 100644
--- a/spec/features/profiles/password_spec.rb
+++ b/spec/features/profiles/password_spec.rb
@@ -152,6 +152,33 @@ RSpec.describe 'Profile > Password' do
it_behaves_like 'user enters an incorrect current password'
end
+ context 'when the password is too weak' do
+ let(:new_password) { 'password' }
+
+ subject do
+ page.within '.update-password' do
+ fill_in "user_password", with: user.password
+ fill_passwords(new_password, new_password)
+ end
+ end
+
+ it 'tracks the error and does not change the password', :aggregate_failures do
+ expect { subject }.not_to change { user.reload.valid_password?(new_password) }
+ expect(user.failed_attempts).to eq(0)
+
+ page.within '.gl-alert-danger' do
+ expect(page).to have_content('must not contain commonly used combinations of words and letters')
+ end
+
+ expect_snowplow_event(
+ category: 'Gitlab::Tracking::Helpers::WeakPasswordErrorEvent',
+ action: 'track_weak_password_error',
+ controller: 'Profiles::PasswordsController',
+ method: 'update'
+ )
+ end
+ end
+
context 'when the password reset is successful' do
subject do
page.within '.update-password' do
@@ -195,6 +222,23 @@ RSpec.describe 'Profile > Password' do
expect(page).to have_current_path new_user_session_path, ignore_query: true
end
+ it 'tracks weak password error' do
+ visit edit_profile_password_path
+
+ expect(page).to have_current_path new_profile_password_path, ignore_query: true
+
+ fill_in :user_password, with: user.password
+ fill_in :user_new_password, with: "password"
+ fill_in :user_password_confirmation, with: "password"
+ click_button 'Set new password'
+ expect_snowplow_event(
+ category: 'Gitlab::Tracking::Helpers::WeakPasswordErrorEvent',
+ action: 'track_weak_password_error',
+ controller: 'Profiles::PasswordsController',
+ method: 'create'
+ )
+ end
+
context 'when global require_two_factor_authentication is enabled' do
it 'needs change user password' do
stub_application_setting(require_two_factor_authentication: true)
diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb
index 088c8a7a15a..3ae88da06f6 100644
--- a/spec/features/profiles/personal_access_tokens_spec.rb
+++ b/spec/features/profiles/personal_access_tokens_spec.rb
@@ -4,22 +4,11 @@ require 'spec_helper'
RSpec.describe 'Profile > Personal Access Tokens', :js do
include Spec::Support::Helpers::ModalHelpers
+ include Spec::Support::Helpers::AccessTokenHelpers
let(:user) { create(:user) }
let(:pat_create_service) { double('PersonalAccessTokens::CreateService', execute: ServiceResponse.error(message: 'error', payload: { personal_access_token: PersonalAccessToken.new })) }
- def active_personal_access_tokens
- find("[data-testid='active-tokens']")
- end
-
- def created_personal_access_token
- find_field('new-access-token').value
- end
-
- def feed_token_description
- "Your feed token authenticates you when your RSS reader loads a personalized RSS feed or when your calendar application loads a personalized calendar. It is visible in those feed URLs."
- end
-
before do
sign_in(user)
end
@@ -43,11 +32,11 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
click_on "Create personal access token"
wait_for_all_requests
- expect(active_personal_access_tokens).to have_text(name)
- expect(active_personal_access_tokens).to have_text('in')
- expect(active_personal_access_tokens).to have_text('read_api')
- expect(active_personal_access_tokens).to have_text('read_user')
- expect(created_personal_access_token).not_to be_empty
+ expect(active_access_tokens).to have_text(name)
+ expect(active_access_tokens).to have_text('in')
+ expect(active_access_tokens).to have_text('read_api')
+ expect(active_access_tokens).to have_text('read_user')
+ expect(created_access_token).to match(/[\w-]{20}/)
end
context "when creation fails" do
@@ -73,8 +62,8 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
it 'only shows personal access tokens' do
visit profile_personal_access_tokens_path
- expect(active_personal_access_tokens).to have_text(personal_access_token.name)
- expect(active_personal_access_tokens).not_to have_text(impersonation_token.name)
+ expect(active_access_tokens).to have_text(personal_access_token.name)
+ expect(active_access_tokens).not_to have_text(impersonation_token.name)
end
context 'when User#time_display_relative is false' do
@@ -85,7 +74,7 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
it 'shows absolute times for expires_at' do
visit profile_personal_access_tokens_path
- expect(active_personal_access_tokens).to have_text(PersonalAccessToken.last.expires_at.strftime('%b %-d'))
+ expect(active_access_tokens).to have_text(PersonalAccessToken.last.expires_at.strftime('%b %-d'))
end
end
end
@@ -97,14 +86,14 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
visit profile_personal_access_tokens_path
accept_gl_confirm(button_text: 'Revoke') { click_on "Revoke" }
- expect(active_personal_access_tokens).to have_text("This user has no active personal access tokens.")
+ expect(active_access_tokens).to have_text("This user has no active personal access tokens.")
end
it "removes expired tokens from 'active' section" do
personal_access_token.update!(expires_at: 5.days.ago)
visit profile_personal_access_tokens_path
- expect(active_personal_access_tokens).to have_text("This user has no active personal access tokens.")
+ expect(active_access_tokens).to have_text("This user has no active personal access tokens.")
end
context "when revocation fails" do
@@ -115,12 +104,16 @@ RSpec.describe 'Profile > Personal Access Tokens', :js do
visit profile_personal_access_tokens_path
accept_gl_confirm(button_text: "Revoke") { click_on "Revoke" }
- expect(active_personal_access_tokens).to have_text(personal_access_token.name)
+ expect(active_access_tokens).to have_text(personal_access_token.name)
end
end
end
describe "feed token" do
+ def feed_token_description
+ "Your feed token authenticates you when your RSS reader loads a personalized RSS feed or when your calendar application loads a personalized calendar. It is visible in those feed URLs."
+ end
+
context "when enabled" do
it "displays feed token" do
allow(Gitlab::CurrentSettings).to receive(:disable_feed_token).and_return(false)
diff --git a/spec/features/profiles/two_factor_auths_spec.rb b/spec/features/profiles/two_factor_auths_spec.rb
index b4355f2d669..decc2904b6e 100644
--- a/spec/features/profiles/two_factor_auths_spec.rb
+++ b/spec/features/profiles/two_factor_auths_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe 'Two factor auths' do
end
context 'when user has two-factor authentication disabled' do
- let_it_be(:user) { create(:user ) }
+ let_it_be(:user) { create(:user) }
it 'requires the current password to set up two factor authentication', :js do
visit profile_two_factor_auth_path
diff --git a/spec/features/project_variables_spec.rb b/spec/features/project_variables_spec.rb
index d3bedbf3a75..33b4af3b5aa 100644
--- a/spec/features/project_variables_spec.rb
+++ b/spec/features/project_variables_spec.rb
@@ -12,62 +12,29 @@ RSpec.describe 'Project variables', :js do
sign_in(user)
project.add_maintainer(user)
project.variables << variable
+ visit page_path
+ wait_for_requests
end
- context 'with disabled ff `ci_variable_settings_graphql' do
- before do
- stub_feature_flags(ci_variable_settings_graphql: false)
- visit page_path
- end
-
- it_behaves_like 'variable list'
-
- it 'adds a new variable with an environment scope' do
- click_button('Add variable')
-
- page.within('#add-ci-variable') do
- fill_in 'Key', with: 'akey'
- find('#ci-variable-value').set('akey_value')
- find('[data-testid="environment-scope"]').click
- find('[data-testid="ci-environment-search"]').set('review/*')
- find('[data-testid="create-wildcard-button"]').click
-
- click_button('Add variable')
- end
-
- wait_for_requests
+ it_behaves_like 'variable list'
- page.within('[data-testid="ci-variable-table"]') do
- expect(find('.js-ci-variable-row:first-child [data-label="Environments"]').text).to eq('review/*')
- end
- end
- end
-
- context 'with enabled ff `ci_variable_settings_graphql' do
- before do
- visit page_path
- end
+ it 'adds a new variable with an environment scope' do
+ click_button('Add variable')
- it_behaves_like 'variable list'
+ page.within('#add-ci-variable') do
+ fill_in 'Key', with: 'akey'
+ find('#ci-variable-value').set('akey_value')
+ find('[data-testid="environment-scope"]').click
+ find('[data-testid="ci-environment-search"]').set('review/*')
+ find('[data-testid="create-wildcard-button"]').click
- it 'adds a new variable with an environment scope' do
click_button('Add variable')
+ end
- page.within('#add-ci-variable') do
- fill_in 'Key', with: 'akey'
- find('#ci-variable-value').set('akey_value')
- find('[data-testid="environment-scope"]').click
- find('[data-testid="ci-environment-search"]').set('review/*')
- find('[data-testid="create-wildcard-button"]').click
-
- click_button('Add variable')
- end
-
- wait_for_requests
+ wait_for_requests
- page.within('[data-testid="ci-variable-table"]') do
- expect(find('.js-ci-variable-row:first-child [data-label="Environments"]').text).to eq('review/*')
- end
+ page.within('[data-testid="ci-variable-table"]') do
+ expect(find('.js-ci-variable-row:first-child [data-label="Environments"]').text).to eq('review/*')
end
end
end
diff --git a/spec/features/projects/branches/user_views_branches_spec.rb b/spec/features/projects/branches/user_views_branches_spec.rb
index b6b6dcb5cf1..3f0614532f1 100644
--- a/spec/features/projects/branches/user_views_branches_spec.rb
+++ b/spec/features/projects/branches/user_views_branches_spec.rb
@@ -21,7 +21,7 @@ RSpec.describe "User views branches", :js do
it "shows branches" do
expect(page).to have_content("Branches").and have_content("master")
- expect(page.all(".graph-side")).to all( have_content(/\d+/) )
+ expect(page.all(".graph-side")).to all(have_content(/\d+/))
end
it "displays a disabled button with a tooltip for the default branch that cannot be deleted", :js do
diff --git a/spec/features/projects/branches_spec.rb b/spec/features/projects/branches_spec.rb
index 361a07ebd0b..ecf6349e431 100644
--- a/spec/features/projects/branches_spec.rb
+++ b/spec/features/projects/branches_spec.rb
@@ -7,7 +7,20 @@ RSpec.describe 'Branches' do
let_it_be(:project) { create(:project, :public, :repository) }
let(:repository) { project.repository }
- context 'logged in as developer' do
+ context 'when logged in as reporter' do
+ before do
+ sign_in(user)
+ project.add_reporter(user)
+ end
+
+ it 'does not show delete button' do
+ visit project_branches_path(project)
+
+ expect(page).not_to have_css '.js-delete-branch-button'
+ end
+ end
+
+ context 'when logged in as developer' do
before do
sign_in(user)
project.add_developer(user)
@@ -21,11 +34,15 @@ RSpec.describe 'Branches' do
before do
# Add 4 stale branches
(1..4).reverse_each do |i|
- travel_to((threshold + i.hours).ago) { create_file(message: "a commit in stale-#{i}", branch_name: "stale-#{i}") }
+ travel_to((threshold + i.hours).ago) do
+ create_file(message: "a commit in stale-#{i}", branch_name: "stale-#{i}")
+ end
end
# Add 6 active branches
(1..6).each do |i|
- travel_to((threshold - i.hours).ago) { create_file(message: "a commit in active-#{i}", branch_name: "active-#{i}") }
+ travel_to((threshold - i.hours).ago) do
+ create_file(message: "a commit in active-#{i}", branch_name: "active-#{i}")
+ end
end
end
@@ -38,7 +55,10 @@ RSpec.describe 'Branches' do
expect(page).to have_button('Copy branch name')
- expect(page).to have_link('Show more active branches', href: project_branches_filtered_path(project, state: 'active'))
+ expect(page).to have_link(
+ 'Show more active branches',
+ href: project_branches_filtered_path(project, state: 'active')
+ )
expect(page).not_to have_content('Show more stale branches')
end
end
@@ -75,13 +95,15 @@ RSpec.describe 'Branches' do
it 'shows only default_per_page active branches sorted by last updated' do
visit project_branches_filtered_path(project, state: 'active')
- expect(page).to have_content(sorted_branches(repository, count: Kaminari.config.default_per_page, sort_by: :updated_desc, state: 'active'))
+ expect(page).to have_content(sorted_branches(repository, count: Kaminari.config.default_per_page,
+ sort_by: :updated_desc, state: 'active'))
end
it 'shows only default_per_page branches sorted by last updated on All branches' do
visit project_branches_filtered_path(project, state: 'all')
- expect(page).to have_content(sorted_branches(repository, count: Kaminari.config.default_per_page, sort_by: :updated_desc))
+ expect(page).to have_content(sorted_branches(repository, count: Kaminari.config.default_per_page,
+ sort_by: :updated_desc))
end
end
end
@@ -141,7 +163,7 @@ RSpec.describe 'Branches' do
it 'avoids a N+1 query in branches index' do
control_count = ActiveRecord::QueryRecorder.new { visit project_branches_path(project) }.count
- %w(one two three four five).each { |ref| repository.add_branch(user, ref, 'master') }
+ %w[one two three four five].each { |ref| repository.add_branch(user, ref, 'master') }
expect { visit project_branches_filtered_path(project, state: 'all') }.not_to exceed_query_limit(control_count)
end
@@ -193,7 +215,7 @@ RSpec.describe 'Branches' do
end
end
- context 'logged in as maintainer' do
+ context 'when logged in as maintainer' do
before do
sign_in(user)
project.add_maintainer(user)
@@ -220,7 +242,7 @@ RSpec.describe 'Branches' do
end
end
- context 'logged out' do
+ context 'when logged out' do
before do
visit project_branches_path(project)
end
@@ -314,7 +336,7 @@ RSpec.describe 'Branches' do
Regexp.new(sorted_branches.join('.*'))
end
- def create_file(message: 'message', branch_name:)
+ def create_file(branch_name:, message: 'message')
repository.create_file(user, generate(:branch), 'content', message: message, branch_name: branch_name)
end
diff --git a/spec/features/projects/container_registry_spec.rb b/spec/features/projects/container_registry_spec.rb
index 54685441300..e99af734c43 100644
--- a/spec/features/projects/container_registry_spec.rb
+++ b/spec/features/projects/container_registry_spec.rb
@@ -56,10 +56,11 @@ RSpec.describe 'Container Registry', :js do
expect(page).to have_content 'my/image'
end
- it 'user removes entire container repository', :sidekiq_might_not_need_inline do
+ it 'user removes entire container repository' do
visit_container_registry
- expect_any_instance_of(ContainerRepository).to receive(:delete_tags!).and_return(true)
+ expect_any_instance_of(ContainerRepository).to receive(:delete_scheduled!).and_call_original
+ expect(DeleteContainerRepositoryWorker).not_to receive(:perform_async)
find('[title="Remove repository"]').click
expect(find('.modal .modal-title')).to have_content _('Remove repository')
diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb
index dc6e496d081..706c880d097 100644
--- a/spec/features/projects/environments/environment_spec.rb
+++ b/spec/features/projects/environments/environment_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe 'Environment' do
- let(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:role) { :developer }
@@ -17,7 +17,7 @@ RSpec.describe 'Environment' do
end
describe 'environment details page' do
- let!(:environment) { create(:environment, project: project) }
+ let_it_be(:environment) { create(:environment, project: project) }
let!(:permissions) {}
let!(:deployment) {}
let!(:action) {}
@@ -160,10 +160,20 @@ RSpec.describe 'Environment' do
end
context 'with related deployable present' do
- let(:pipeline) { create(:ci_pipeline, project: project) }
- let(:build) { create(:ci_build, pipeline: pipeline, environment: environment.name) }
+ let_it_be(:previous_pipeline) { create(:ci_pipeline, project: project) }
- let(:deployment) do
+ let_it_be(:previous_build) do
+ create(:ci_build, :success, pipeline: previous_pipeline, environment: environment.name)
+ end
+
+ let_it_be(:previous_deployment) do
+ create(:deployment, :success, environment: environment, deployable: previous_build)
+ end
+
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+ let_it_be(:build) { create(:ci_build, pipeline: pipeline, environment: environment.name) }
+
+ let_it_be(:deployment) do
create(:deployment, :success, environment: environment, deployable: build)
end
@@ -171,12 +181,10 @@ RSpec.describe 'Environment' do
visit_environment(environment)
end
- it 'does show build name' do
- expect(page).to have_link("#{build.name} (##{build.id})")
- end
-
- it 'shows the re-deploy button' do
+ it 'shows deployment information and buttons', :js do
expect(page).to have_button('Re-deploy to environment')
+ expect(page).to have_button('Rollback environment')
+ expect(page).to have_link("#{build.name} (##{build.id})")
end
context 'with manual action' do
diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb
index 9ec41cd8f8d..b445b0da901 100644
--- a/spec/features/projects/environments/environments_spec.rb
+++ b/spec/features/projects/environments/environments_spec.rb
@@ -336,6 +336,11 @@ RSpec.describe 'Environments page', :js do
accept_gl_confirm do
find(action_link_selector).click
end
+
+ # Wait for UI to transition to ensure we an GraphQL request has been made
+ within(actions_button_selector) { find('.gl-spinner') }
+ within(actions_button_selector) { find('[data-testid="play-icon"]') }
+
wait_for_requests
end
diff --git a/spec/features/projects/fork_spec.rb b/spec/features/projects/fork_spec.rb
index 24943e7dd0f..9ceadb63178 100644
--- a/spec/features/projects/fork_spec.rb
+++ b/spec/features/projects/fork_spec.rb
@@ -134,7 +134,7 @@ RSpec.describe 'Project fork' do
context 'fork form', :js do
let(:group) { create(:group) }
let(:group2) { create(:group) }
- let(:user) { create(:group_member, :maintainer, user: create(:user), group: group ).user }
+ let(:user) { create(:group_member, :maintainer, user: create(:user), group: group).user }
def submit_form(group_obj = group)
find('[data-testid="select_namespace_dropdown"]').click
@@ -180,7 +180,7 @@ RSpec.describe 'Project fork' do
context 'with cache_home_panel feature flag' do
before do
- create(:group_member, :maintainer, user: user, group: group2 )
+ create(:group_member, :maintainer, user: user, group: group2)
end
context 'when caching is enabled' do
diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb
index c7fbaa85483..6f015f9cd22 100644
--- a/spec/features/projects/import_export/import_file_spec.rb
+++ b/spec/features/projects/import_export/import_file_spec.rb
@@ -3,8 +3,6 @@
require 'spec_helper'
RSpec.describe 'Import/Export - project import integration test', :js do
- include GitHelpers
-
let(:user) { create(:user) }
let(:file) { File.join(Rails.root, 'spec', 'features', 'projects', 'import_export', 'test_project_export.tar.gz') }
let(:export_path) { "#{Dir.tmpdir}/import_file_spec" }
diff --git a/spec/features/projects/integrations/user_activates_issue_tracker_spec.rb b/spec/features/projects/integrations/user_activates_issue_tracker_spec.rb
index e7d4ed58549..d2c48cb2af0 100644
--- a/spec/features/projects/integrations/user_activates_issue_tracker_spec.rb
+++ b/spec/features/projects/integrations/user_activates_issue_tracker_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'User activates issue tracker', :js do
+RSpec.describe 'User activates issue tracker', :js, feature_category: :integrations do
include_context 'project integration activation'
let(:url) { 'http://tracker.example.com' }
diff --git a/spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb b/spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb
index b423543dc33..3d40bae8544 100644
--- a/spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb
+++ b/spec/features/projects/issues/viewing_issues_with_external_authorization_enabled_spec.rb
@@ -41,7 +41,7 @@ RSpec.describe 'viewing an issue with cross project references' do
let(:issue) do
create(:issue,
project: project,
- description: description_referencing_other_issue )
+ description: description_referencing_other_issue)
end
let(:confidential_issue) do
@@ -102,8 +102,8 @@ RSpec.describe 'viewing an issue with cross project references' do
it 'shows only the link to the cross project references' do
visit project_issue_path(project, issue)
- expect(page).to have_link("#{other_issue.to_reference(project)}")
- expect(page).to have_link("#{other_merge_request.to_reference(project)}")
+ expect(page).to have_link(other_issue.to_reference(project).to_s)
+ expect(page).to have_link(other_merge_request.to_reference(project).to_s)
expect(page).not_to have_content("#{other_issue.to_reference(project)} (#{other_issue.state})")
expect(page).not_to have_xpath("//a[@title='#{other_issue.title}']")
expect(page).not_to have_content("#{other_merge_request.to_reference(project)} (#{other_merge_request.state})")
@@ -113,7 +113,7 @@ RSpec.describe 'viewing an issue with cross project references' do
it 'does not link a cross project confidential issue if the user does not have access' do
visit project_issue_path(project, issue)
- expect(page).not_to have_link("#{other_confidential_issue.to_reference(project)}")
+ expect(page).not_to have_link(other_confidential_issue.to_reference(project).to_s)
expect(page).not_to have_xpath("//a[@title='#{other_confidential_issue.title}']")
end
@@ -122,7 +122,7 @@ RSpec.describe 'viewing an issue with cross project references' do
visit project_issue_path(project, issue)
- expect(page).to have_link("#{other_confidential_issue.to_reference(project)}")
+ expect(page).to have_link(other_confidential_issue.to_reference(project).to_s)
expect(page).not_to have_xpath("//a[@title='#{other_confidential_issue.title}']")
end
diff --git a/spec/features/projects/jobs/permissions_spec.rb b/spec/features/projects/jobs/permissions_spec.rb
index b6019944071..740d009d6b8 100644
--- a/spec/features/projects/jobs/permissions_spec.rb
+++ b/spec/features/projects/jobs/permissions_spec.rb
@@ -211,4 +211,48 @@ RSpec.describe 'Project Jobs Permissions' do
end
end
end
+
+ context 'with CI_DEBUG_SERVICES' do
+ let_it_be(:ci_instance_variable) { create(:ci_instance_variable, key: 'CI_DEBUG_SERVICES') }
+
+ describe 'trace endpoint and raw page' do
+ let_it_be(:job) { create(:ci_build, :running, :coverage, :trace_artifact, pipeline: pipeline) }
+
+ where(:public_builds, :user_project_role, :ci_debug_services, :expected_status_code, :expected_msg) do
+ true | 'developer' | true | 200 | nil
+ true | 'guest' | true | 403 | 'You must have developer or higher permissions'
+ true | nil | true | 404 | 'Page Not Found Make sure the address is correct'
+ true | 'developer' | false | 200 | nil
+ true | 'guest' | false | 200 | nil
+ true | nil | false | 404 | 'Page Not Found Make sure the address is correct'
+ false | 'developer' | true | 200 | nil
+ false | 'guest' | true | 403 | 'You must have developer or higher permissions'
+ false | nil | true | 404 | 'Page Not Found Make sure the address is correct'
+ false | 'developer' | false | 200 | nil
+ false | 'guest' | false | 403 | 'The current user is not authorized to access the job log'
+ false | nil | false | 404 | 'Page Not Found Make sure the address is correct'
+ end
+
+ with_them do
+ before do
+ ci_instance_variable.update!(value: ci_debug_services)
+ project.update!(public_builds: public_builds)
+ user_project_role && project.add_role(user, user_project_role)
+ end
+
+ it 'renders trace to authorized users' do
+ visit trace_project_job_path(project, job)
+
+ expect(status_code).to eq(expected_status_code)
+ end
+
+ it 'renders raw trace to authorized users' do
+ visit raw_project_job_path(project, job)
+
+ expect(status_code).to eq(expected_status_code)
+ expect(page).to have_content(expected_msg)
+ end
+ end
+ end
+ end
end
diff --git a/spec/features/projects/jobs/user_browses_jobs_spec.rb b/spec/features/projects/jobs/user_browses_jobs_spec.rb
index 995f4a1e3d2..cb3c1594868 100644
--- a/spec/features/projects/jobs/user_browses_jobs_spec.rb
+++ b/spec/features/projects/jobs/user_browses_jobs_spec.rb
@@ -203,15 +203,15 @@ RSpec.describe 'User browses jobs' do
end
it 'contains a link to the job sha' do
- expect(page.find('[data-testid="job-sha"]')).to have_content "#{job.sha[0..7]}"
+ expect(page.find('[data-testid="job-sha"]')).to have_content job.sha[0..7].to_s
end
it 'contains a link to the job id' do
- expect(page.find('[data-testid="job-id-link"]')).to have_content "#{job.id}"
+ expect(page.find('[data-testid="job-id-link"]')).to have_content job.id.to_s
end
it 'contains a link to the job ref' do
- expect(page.find('[data-testid="job-ref"]')).to have_content "#{job.ref}"
+ expect(page.find('[data-testid="job-ref"]')).to have_content job.ref.to_s
end
end
end
diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb
index 84c75752bc1..96a8168e708 100644
--- a/spec/features/projects/jobs_spec.rb
+++ b/spec/features/projects/jobs_spec.rb
@@ -463,7 +463,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
context 'when variables are stored in trigger_request' do
before do
- trigger_request.update_attribute(:variables, { 'TRIGGER_KEY_1' => 'TRIGGER_VALUE_1' } )
+ trigger_request.update_attribute(:variables, { 'TRIGGER_KEY_1' => 'TRIGGER_VALUE_1' })
visit project_job_path(project, job)
end
@@ -508,7 +508,7 @@ RSpec.describe 'Jobs', :clean_gitlab_redis_shared_state do
context 'when variables are stored in trigger_request' do
before do
- trigger_request.update_attribute(:variables, { 'TRIGGER_KEY_1' => 'TRIGGER_VALUE_1' } )
+ trigger_request.update_attribute(:variables, { 'TRIGGER_KEY_1' => 'TRIGGER_VALUE_1' })
visit project_job_path(project, job)
end
diff --git a/spec/features/projects/members/manage_members_spec.rb b/spec/features/projects/members/manage_members_spec.rb
index 56eb02607a5..1f317c55256 100644
--- a/spec/features/projects/members/manage_members_spec.rb
+++ b/spec/features/projects/members/manage_members_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Projects > Members > Manage members', :js do
+RSpec.describe 'Projects > Members > Manage members', :js, product_group: :onboarding do
include Spec::Support::Helpers::Features::MembersHelpers
include Spec::Support::Helpers::Features::InviteMembersModalHelper
include Spec::Support::Helpers::ModalHelpers
diff --git a/spec/features/projects/network_graph_spec.rb b/spec/features/projects/network_graph_spec.rb
index 1ee0ea51e53..97b743b4d73 100644
--- a/spec/features/projects/network_graph_spec.rb
+++ b/spec/features/projects/network_graph_spec.rb
@@ -13,98 +13,110 @@ RSpec.describe 'Project Network Graph', :js do
allow(Network::Graph).to receive(:max_count).and_return(10)
end
- context 'when branch is master' do
- def switch_ref_to(ref_name)
- first('.js-project-refs-dropdown').click
-
- page.within '.project-refs-form' do
- click_link ref_name
+ shared_examples 'network graph' do
+ context 'when branch is master' do
+ def switch_ref_to(ref_name)
+ first('.js-project-refs-dropdown').click
+
+ page.within '.project-refs-form' do
+ click_link ref_name
+ end
end
- end
- def click_show_only_selected_branch_checkbox
- find('#filter_ref').click
- end
+ def click_show_only_selected_branch_checkbox
+ find('#filter_ref').click
+ end
- before do
- visit project_network_path(project, 'master')
- end
+ before do
+ visit project_network_path(project, 'master')
+ end
- it 'renders project network' do
- expect(page).to have_selector ".network-graph"
- expect(page).to have_selector '.dropdown-menu-toggle', text: "master"
- page.within '.network-graph' do
- expect(page).to have_content 'master'
+ it 'renders project network' do
+ expect(page).to have_selector ".network-graph"
+ expect(page).to have_selector '.dropdown-menu-toggle', text: "master"
+ page.within '.network-graph' do
+ expect(page).to have_content 'master'
+ end
end
- end
- it 'switches ref to branch' do
- switch_ref_to('feature')
+ it 'switches ref to branch' do
+ switch_ref_to('feature')
- expect(page).to have_selector '.dropdown-menu-toggle', text: 'feature'
- page.within '.network-graph' do
- expect(page).to have_content 'feature'
+ expect(page).to have_selector '.dropdown-menu-toggle', text: 'feature'
+ page.within '.network-graph' do
+ expect(page).to have_content 'feature'
+ end
end
- end
- it 'switches ref to tag' do
- switch_ref_to('v1.0.0')
+ it 'switches ref to tag' do
+ switch_ref_to('v1.0.0')
- expect(page).to have_selector '.dropdown-menu-toggle', text: 'v1.0.0'
- page.within '.network-graph' do
- expect(page).to have_content 'v1.0.0'
+ expect(page).to have_selector '.dropdown-menu-toggle', text: 'v1.0.0'
+ page.within '.network-graph' do
+ expect(page).to have_content 'v1.0.0'
+ end
end
- end
- it 'renders by commit sha of "v1.0.0"' do
- page.within ".network-form" do
- fill_in 'extended_sha1', with: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9'
- find('button').click
+ it 'renders by commit sha of "v1.0.0"' do
+ page.within ".network-form" do
+ fill_in 'extended_sha1', with: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9'
+ find('button').click
+ end
+
+ expect(page).to have_selector ".network-graph"
+ expect(page).to have_selector '.dropdown-menu-toggle', text: "master"
+ page.within '.network-graph' do
+ expect(page).to have_content 'v1.0.0'
+ end
end
- expect(page).to have_selector ".network-graph"
- expect(page).to have_selector '.dropdown-menu-toggle', text: "master"
- page.within '.network-graph' do
- expect(page).to have_content 'v1.0.0'
- end
- end
+ it 'filters select tag' do
+ switch_ref_to('v1.0.0')
- it 'filters select tag' do
- switch_ref_to('v1.0.0')
+ expect(page).to have_css 'title', text: 'Graph · v1.0.0', visible: false
+ page.within '.network-graph' do
+ expect(page).to have_content 'Change some files'
+ end
- expect(page).to have_css 'title', text: 'Graph · v1.0.0', visible: false
- page.within '.network-graph' do
- expect(page).to have_content 'Change some files'
- end
+ click_show_only_selected_branch_checkbox
- click_show_only_selected_branch_checkbox
+ page.within '.network-graph' do
+ expect(page).not_to have_content 'Change some files'
+ end
- page.within '.network-graph' do
- expect(page).not_to have_content 'Change some files'
+ click_show_only_selected_branch_checkbox
+
+ page.within '.network-graph' do
+ expect(page).to have_content 'Change some files'
+ end
end
- click_show_only_selected_branch_checkbox
+ it 'renders error message when sha commit not exists' do
+ page.within ".network-form" do
+ fill_in 'extended_sha1', with: ';'
+ find('button').click
+ end
- page.within '.network-graph' do
- expect(page).to have_content 'Change some files'
+ expect(page).to have_selector '[data-testid="alert-danger"]', text: "Git revision ';' does not exist."
end
end
- it 'renders error message when sha commit not exists' do
- page.within ".network-form" do
- fill_in 'extended_sha1', with: ';'
- find('button').click
- end
+ it 'renders project network with test branch' do
+ visit project_network_path(project, "'test'")
- expect(page).to have_selector '[data-testid="alert-danger"]', text: "Git revision ';' does not exist."
+ page.within '.network-graph' do
+ expect(page).to have_content "'test'"
+ end
end
end
- it 'renders project network with test branch' do
- visit project_network_path(project, "'test'")
+ it_behaves_like 'network graph'
- page.within '.network-graph' do
- expect(page).to have_content "'test'"
+ context 'when disable_network_graph_notes_count is disabled' do
+ before do
+ stub_feature_flags(disable_network_graph_notes_count: false)
end
+
+ it_behaves_like 'network graph'
end
end
diff --git a/spec/features/projects/pipeline_schedules_spec.rb b/spec/features/projects/pipeline_schedules_spec.rb
index 4ed0a11da38..e569fef76f8 100644
--- a/spec/features/projects/pipeline_schedules_spec.rb
+++ b/spec/features/projects/pipeline_schedules_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Pipeline Schedules', :js do
include Spec::Support::Helpers::ModalHelpers
let!(:project) { create(:project, :repository) }
- let!(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project ) }
+ let!(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project) }
let!(:pipeline) { create(:ci_pipeline, pipeline_schedule: pipeline_schedule) }
let(:scope) { nil }
let!(:user) { create(:user) }
@@ -45,7 +45,7 @@ RSpec.describe 'Pipeline Schedules', :js do
description = find_field('schedule_description').value
expect(description).to eq('pipeline schedule')
expect(page).to have_button('master')
- expect(page).to have_button('UTC')
+ expect(page).to have_button('Select timezone')
end
it 'edits the scheduled pipeline' do
@@ -164,7 +164,7 @@ RSpec.describe 'Pipeline Schedules', :js do
it 'sets defaults for timezone and target branch' do
expect(page).to have_button('master')
- expect(page).to have_button('UTC')
+ expect(page).to have_button('Select timezone')
end
it 'creates a new scheduled pipeline' do
@@ -314,8 +314,8 @@ RSpec.describe 'Pipeline Schedules', :js do
end
def select_timezone
- find('.js-timezone-dropdown').click
- click_link 'American Samoa'
+ find('[data-testid="schedule-timezone"] .dropdown-toggle').click
+ find("button", text: "Arizona").click
end
def select_target_branch
diff --git a/spec/features/projects/pipelines/legacy_pipeline_spec.rb b/spec/features/projects/pipelines/legacy_pipeline_spec.rb
index d93c951791d..c4fc194f0cd 100644
--- a/spec/features/projects/pipelines/legacy_pipeline_spec.rb
+++ b/spec/features/projects/pipelines/legacy_pipeline_spec.rb
@@ -726,12 +726,7 @@ RSpec.describe 'Pipeline', :js do
before do
schedule.owner.block!
-
- begin
- PipelineScheduleWorker.new.perform
- rescue Ci::CreatePipelineService::CreateError
- # Do nothing, assert view code after the Pipeline failed to create.
- end
+ PipelineScheduleWorker.new.perform
end
it 'displays the PipelineSchedule in an inactive state' do
diff --git a/spec/features/projects/pipelines/legacy_pipelines_spec.rb b/spec/features/projects/pipelines/legacy_pipelines_spec.rb
index 2e0ea695ab3..9d3ac71a875 100644
--- a/spec/features/projects/pipelines/legacy_pipelines_spec.rb
+++ b/spec/features/projects/pipelines/legacy_pipelines_spec.rb
@@ -316,7 +316,6 @@ RSpec.describe 'Pipelines', :js do
end
before do
- stub_feature_flags(bootstrap_confirmation_modals: false)
visit_project_pipelines
end
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index 0b43e13996f..2d729af513a 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -64,7 +64,9 @@ RSpec.describe 'Pipeline', :js do
let_it_be(:group) { create(:group) }
let_it_be(:project, reload: true) { create(:project, :repository, group: group) }
- let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id, user: user) }
+ let(:pipeline) do
+ create(:ci_pipeline, name: 'Build pipeline', project: project, ref: 'master', sha: project.commit.id, user: user)
+ end
subject(:visit_pipeline) { visit project_pipeline_path(project, pipeline) }
@@ -96,6 +98,45 @@ RSpec.describe 'Pipeline', :js do
end
end
+ context 'with pipeline_name feature flag enabled' do
+ before do
+ stub_feature_flags(pipeline_name: true)
+ end
+
+ it 'displays pipeline name instead of commit title' do
+ visit_pipeline
+
+ within 'h3' do
+ expect(page).to have_content(pipeline.name)
+ end
+
+ within '.well-segment[data-testid="commit-row"]' do
+ expect(page).to have_content(project.commit.title)
+ expect(page).to have_content(project.commit.short_id)
+ end
+ end
+ end
+
+ context 'with pipeline_name feature flag disabled' do
+ before do
+ stub_feature_flags(pipeline_name: false)
+ end
+
+ it 'displays commit title' do
+ visit_pipeline
+
+ within 'h3' do
+ expect(page).not_to have_content(pipeline.name)
+ expect(page).to have_content(project.commit.title)
+ end
+
+ within '.well-segment[data-testid="commit-row"]' do
+ expect(page).not_to have_content(project.commit.title)
+ expect(page).to have_content(project.commit.short_id)
+ 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
@@ -363,7 +404,7 @@ RSpec.describe 'Pipeline', :js do
project: downstream_project,
ref: 'master',
sha: downstream_project.commit.id,
- child_of: pipeline )
+ child_of: pipeline)
end
let!(:build) { create(:ci_build, status, pipeline: downstream_pipeline, user: user) }
@@ -851,12 +892,7 @@ RSpec.describe 'Pipeline', :js do
before do
schedule.owner.block!
-
- begin
- PipelineScheduleWorker.new.perform
- rescue Ci::CreatePipelineService::CreateError
- # Do nothing, assert view code after the Pipeline failed to create.
- end
+ PipelineScheduleWorker.new.perform
end
it 'displays the PipelineSchedule in an inactive state' do
diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb
index eabbcd5e38e..b7b715cb6db 100644
--- a/spec/features/projects/pipelines/pipelines_spec.rb
+++ b/spec/features/projects/pipelines/pipelines_spec.rb
@@ -680,7 +680,7 @@ RSpec.describe 'Pipelines', :js 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')
@@ -708,7 +708,7 @@ RSpec.describe 'Pipelines', :js 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
@@ -722,6 +722,7 @@ RSpec.describe 'Pipelines', :js do
# Run Pipeline form with REST endpoints
# TODO: Clean up tests when run_pipeline_graphql is enabled
+ # Issue https://gitlab.com/gitlab-org/gitlab/-/issues/372310
context 'with feature flag disabled' do
before do
stub_feature_flags(run_pipeline_graphql: false)
diff --git a/spec/features/projects/product_analytics/events_spec.rb b/spec/features/projects/product_analytics/events_spec.rb
deleted file mode 100644
index 05d12e12acb..00000000000
--- a/spec/features/projects/product_analytics/events_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Product Analytics > Events' do
- let_it_be(:project) { create(:project_empty_repo) }
- let_it_be(:user) { create(:user) }
-
- let(:event) { create(:product_analytics_event, project: project) }
-
- before do
- project.add_maintainer(user)
- sign_in(user)
- end
-
- it 'shows no events message' do
- visit(project_product_analytics_path(project))
-
- expect(page).to have_content('There are currently no events')
- end
-
- it 'shows events' do
- event
-
- visit(project_product_analytics_path(project))
-
- expect(page).to have_content('dvce_created_tstamp')
- expect(page).to have_content(event.event_id)
- end
-end
diff --git a/spec/features/projects/product_analytics/graphs_spec.rb b/spec/features/projects/product_analytics/graphs_spec.rb
deleted file mode 100644
index e2293893589..00000000000
--- a/spec/features/projects/product_analytics/graphs_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Product Analytics > Graphs' do
- let_it_be(:project) { create(:project) }
- let_it_be(:user) { create(:user) }
-
- before do
- project.add_maintainer(user)
- sign_in(user)
- end
-
- it 'shows graphs', :js do
- create(:product_analytics_event, project: project)
-
- visit(graphs_project_product_analytics_path(project))
-
- expect(page).to have_content('Showing graphs based on events')
- expect(page).to have_content('platform')
- expect(page).to have_content('os_timezone')
- expect(page).to have_content('br_lang')
- expect(page).to have_content('doc_charset')
- end
-end
diff --git a/spec/features/projects/product_analytics/setup_spec.rb b/spec/features/projects/product_analytics/setup_spec.rb
deleted file mode 100644
index 45c2b67502c..00000000000
--- a/spec/features/projects/product_analytics/setup_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Product Analytics > Setup' do
- let_it_be(:project) { create(:project_empty_repo) }
- let_it_be(:user) { create(:user) }
-
- before do
- project.add_maintainer(user)
- sign_in(user)
- end
-
- it 'shows the setup instructions' do
- visit(setup_project_product_analytics_path(project))
-
- expect(page).to have_content('Copy the code below to implement tracking in your application')
- end
-end
diff --git a/spec/features/projects/product_analytics/test_spec.rb b/spec/features/projects/product_analytics/test_spec.rb
deleted file mode 100644
index 8984fb409d1..00000000000
--- a/spec/features/projects/product_analytics/test_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Product Analytics > Test' do
- let_it_be(:project) { create(:project_empty_repo) }
- let_it_be(:user) { create(:user) }
-
- before do
- project.add_maintainer(user)
- sign_in(user)
- end
-
- it 'says it sends a payload' do
- visit(test_project_product_analytics_path(project))
-
- expect(page).to have_content('This page sends a payload.')
- end
-
- it 'shows the last event if there is one' do
- event = create(:product_analytics_event, project: project)
-
- visit(test_project_product_analytics_path(project))
-
- expect(page).to have_content(event.event_id)
- end
-end
diff --git a/spec/features/projects/releases/user_views_edit_release_spec.rb b/spec/features/projects/releases/user_views_edit_release_spec.rb
index 6551b254643..78b9798941a 100644
--- a/spec/features/projects/releases/user_views_edit_release_spec.rb
+++ b/spec/features/projects/releases/user_views_edit_release_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe 'User edits Release', :js do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
- let(:release) { create(:release, :with_milestones, milestones_count: 1, project: project, name: 'The first release', tag: "v1.1.0" ) }
+ let(:release) { create(:release, :with_milestones, milestones_count: 1, project: project, name: 'The first release', tag: "v1.1.0") }
let(:release_link) { create(:release_link, release: release) }
before do
diff --git a/spec/features/projects/releases/user_views_releases_spec.rb b/spec/features/projects/releases/user_views_releases_spec.rb
index a7348b62fc0..10418e8072d 100644
--- a/spec/features/projects/releases/user_views_releases_spec.rb
+++ b/spec/features/projects/releases/user_views_releases_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe 'User views releases', :js do
let_it_be(:guest) { create(:user) }
let_it_be(:internal_link) { create(:release_link, release: release_v1, name: 'An internal link', url: "#{project.web_url}/-/jobs/1/artifacts/download", filepath: nil) }
- let_it_be(:internal_link_with_redirect) { create(:release_link, release: release_v1, name: 'An internal link with a redirect', url: "#{project.web_url}/-/jobs/2/artifacts/download", filepath: '/binaries/linux-amd64' ) }
+ let_it_be(:internal_link_with_redirect) { create(:release_link, release: release_v1, name: 'An internal link with a redirect', url: "#{project.web_url}/-/jobs/2/artifacts/download", filepath: '/binaries/linux-amd64') }
let_it_be(:external_link) { create(:release_link, release: release_v1, name: 'An external link', url: "https://example.com/an/external/link", filepath: nil) }
before do
diff --git a/spec/features/projects/settings/branch_names_settings_spec.rb b/spec/features/projects/settings/branch_names_settings_spec.rb
new file mode 100644
index 00000000000..fdd883bc2b6
--- /dev/null
+++ b/spec/features/projects/settings/branch_names_settings_spec.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Project settings > repositories > Branch names', :js do
+ let_it_be(:project) { create(:project, :public) }
+ let(:user) { create(:user) }
+
+ before do
+ project.add_maintainer(user)
+
+ sign_in(user)
+ end
+
+ context 'when Issues are initially disabled' do
+ let(:project_feature) { project.project_feature }
+
+ before do
+ project_feature.update!(issues_access_level: ProjectFeature::DISABLED)
+ visit project_settings_repository_path(project)
+ end
+
+ it 'do not render the Branch names settings' do
+ expect(page).not_to have_content('Branch name template')
+ end
+ end
+
+ context 'when Issues are initially enabled' do
+ before do
+ visit project_settings_repository_path(project)
+ end
+
+ it 'shows the Branch names settings' do
+ expect(page).to have_content('Branch name template')
+
+ value = "feature-%{id}"
+
+ within('section#branch-defaults-settings') do
+ fill_in 'project[issue_branch_template]', with: value
+
+ click_on('Save changes')
+ end
+
+ expect(project.reload.issue_branch_template).to eq(value)
+ expect(page).to have_content('Branch name template')
+ end
+ end
+end
diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb
index d9bdbf7aa1a..b25ae80b3c3 100644
--- a/spec/features/projects/settings/repository_settings_spec.rb
+++ b/spec/features/projects/settings/repository_settings_spec.rb
@@ -30,7 +30,6 @@ RSpec.describe 'Projects > Settings > Repository settings' do
before do
stub_container_registry_config(enabled: true)
- stub_feature_flags(ajax_new_deploy_token: project)
end
it_behaves_like 'a deploy token in settings' do
diff --git a/spec/features/projects/settings/user_changes_default_branch_spec.rb b/spec/features/projects/settings/user_changes_default_branch_spec.rb
index 508bbcc5327..bf064839bd7 100644
--- a/spec/features/projects/settings/user_changes_default_branch_spec.rb
+++ b/spec/features/projects/settings/user_changes_default_branch_spec.rb
@@ -25,11 +25,11 @@ RSpec.describe 'Projects > Settings > User changes default branch' do
fill_in 'Search branch', with: 'fix'
click_button 'fix'
- page.within '#default-branch-settings' do
+ page.within '#branch-defaults-settings' do
click_button 'Save changes'
end
- expect(find("#{dropdown_selector} input", visible: false).value).to eq 'fix'
+ expect(find(dropdown_selector)).to have_text 'fix'
end
end
diff --git a/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb b/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb
index eed3494ef5b..47383be1ba1 100644
--- a/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb
+++ b/spec/features/projects/settings/user_sees_revoke_deploy_token_modal_spec.rb
@@ -11,7 +11,6 @@ RSpec.describe 'Repository Settings > User sees revoke deploy token modal', :js
before do
project.add_role(user, role)
sign_in(user)
- stub_feature_flags(ajax_new_deploy_token: project)
visit(project_settings_repository_path(project))
click_button('Revoke')
end
diff --git a/spec/features/projects/settings/webhooks_settings_spec.rb b/spec/features/projects/settings/webhooks_settings_spec.rb
index 25752bcaf45..adbf2f6ee5c 100644
--- a/spec/features/projects/settings/webhooks_settings_spec.rb
+++ b/spec/features/projects/settings/webhooks_settings_spec.rb
@@ -48,22 +48,47 @@ RSpec.describe 'Projects > Settings > Webhook Settings' do
expect(page).to have_content('Releases events')
end
- it 'create webhook', :js do
- visit webhooks_path
+ context 'when feature flag "enhanced_webhook_support_regex" is disabled' do
+ before do
+ stub_feature_flags(enhanced_webhook_support_regex: false)
+ end
- fill_in 'URL', with: url
- check 'Tag push events'
- fill_in 'hook_push_events_branch_filter', with: 'master'
- check 'Enable SSL verification'
- check 'Job events'
+ it 'create webhook', :js do
+ visit webhooks_path
- click_button 'Add webhook'
+ fill_in 'URL', with: url
+ check 'Tag push events'
+ fill_in 'hook_push_events_branch_filter', with: 'master'
+ check 'Enable SSL verification'
+ check 'Job events'
- expect(page).to have_content(url)
- expect(page).to have_content('SSL Verification: enabled')
- expect(page).to have_content('Push events')
- expect(page).to have_content('Tag push events')
- expect(page).to have_content('Job events')
+ click_button 'Add webhook'
+
+ expect(page).to have_content(url)
+ expect(page).to have_content('SSL Verification: enabled')
+ expect(page).to have_content('Tag push events')
+ expect(page).to have_content('Job events')
+ expect(page).to have_content('Push events')
+ end
+ end
+
+ context 'when feature flag "enhanced_webhook_support_regex" is enabled' do
+ it 'create webhook', :js do
+ visit webhooks_path
+
+ fill_in 'URL', with: url
+ check 'Tag push events'
+ check 'Enable SSL verification'
+ check 'Job events'
+
+ click_button 'Add webhook'
+
+ expect(page).to have_content(url)
+ expect(page).to have_content('SSL Verification: enabled')
+ expect(page).to have_content('Tag push events')
+ expect(page).to have_content('Job events')
+ expect(page).to have_content('Push events')
+ end
end
it 'edit existing webhook', :js do
diff --git a/spec/features/projects/user_changes_project_visibility_spec.rb b/spec/features/projects/user_changes_project_visibility_spec.rb
index d2a7596aec0..df13bb55c6d 100644
--- a/spec/features/projects/user_changes_project_visibility_spec.rb
+++ b/spec/features/projects/user_changes_project_visibility_spec.rb
@@ -103,6 +103,9 @@ RSpec.describe 'User changes public project visibility', :js do
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'
diff --git a/spec/features/search/user_searches_for_code_spec.rb b/spec/features/search/user_searches_for_code_spec.rb
index 50e6eb66466..ee74ac84a73 100644
--- a/spec/features/search/user_searches_for_code_spec.rb
+++ b/spec/features/search/user_searches_for_code_spec.rb
@@ -2,228 +2,237 @@
require 'spec_helper'
-RSpec.describe 'User searches for code' do
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository, namespace: user.namespace) }
-
- context 'when signed in' do
- before do
- stub_feature_flags(search_page_vertical_nav: false)
- project.add_maintainer(user)
- sign_in(user)
- end
-
- it 'finds a file' do
- visit(project_path(project))
+RSpec.describe 'User searches for code', :js, :disable_rate_limiter do
+ using RSpec::Parameterized::TableSyntax
- submit_search('application.js')
- select_search_scope('Code')
+ let_it_be(:user) { create(:user) }
+ let_it_be_with_reload(:project) { create(:project, :repository, namespace: user.namespace) }
- expect(page).to have_selector('.results', text: 'application.js')
- expect(page).to have_selector('.file-content .code')
- expect(page).to have_selector("span.line[lang='javascript']")
- expect(page).to have_link('application.js', href: %r{master/files/js/application.js})
- expect(page).to have_button('Copy file path')
- end
-
- context 'when on a project page', :js do
+ where(search_page_vertical_nav_enabled: [true, false])
+ with_them do
+ context 'when signed in' do
before do
- visit(search_path)
- find('[data-testid="project-filter"]').click
-
- wait_for_requests
-
- page.within('[data-testid="project-filter"]') do
- click_on(project.name)
- end
+ stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
+ project.add_maintainer(user)
+ sign_in(user)
end
- include_examples 'top right search form'
- include_examples 'search timeouts', 'blobs'
+ it 'finds a file' do
+ visit(project_path(project))
- it 'finds code and links to blob' do
- fill_in('dashboard_search', with: 'rspec')
- find('.gl-search-box-by-click-search-button').click
+ submit_search('application.js')
+ select_search_scope('Code')
- expect(page).to have_selector('.results', text: 'Update capybara, rspec-rails, poltergeist to recent versions')
-
- find("#blob-L3").click
- expect(current_url).to match(%r{blob/master/.gitignore#L3})
+ expect(page).to have_selector('.results', text: 'application.js')
+ expect(page).to have_selector('.file-content .code')
+ expect(page).to have_selector("span.line[lang='javascript']")
+ expect(page).to have_link('application.js', href: %r{master/files/js/application.js})
+ expect(page).to have_button('Copy file path')
end
- it 'finds code and links to blame' do
- fill_in('dashboard_search', with: 'rspec')
- find('.gl-search-box-by-click-search-button').click
+ context 'when on a project page' do
+ before do
+ visit(search_path)
+ find('[data-testid="project-filter"]').click
- expect(page).to have_selector('.results', text: 'Update capybara, rspec-rails, poltergeist to recent versions')
+ wait_for_requests
- find("#blame-L3").click
- expect(current_url).to match(%r{blame/master/.gitignore#L3})
- end
+ page.within('[data-testid="project-filter"]') do
+ click_on(project.name)
+ end
+ end
- it 'search mutiple words with refs switching' do
- expected_result = 'Use `snake_case` for naming files'
- search = 'for naming files'
+ include_examples 'top right search form'
+ include_examples 'search timeouts', 'blobs' do
+ let(:additional_params) { { project_id: project.id } }
+ end
- fill_in('dashboard_search', with: search)
- find('.gl-search-box-by-click-search-button').click
+ it 'finds code and links to blob' do
+ expected_result = 'Update capybara, rspec-rails, poltergeist to recent versions'
- expect(page).to have_selector('.results', text: expected_result)
+ fill_in('dashboard_search', with: 'rspec')
+ find('.gl-search-box-by-click-search-button').click
- find('.ref-selector').click
- wait_for_requests
+ expect(page).to have_selector('.results', text: expected_result)
- page.within('.ref-selector') do
- find('li', text: 'v1.0.0').click
+ find("#blob-L3").click
+ expect(current_url).to match(%r{blob/master/.gitignore#L3})
end
- expect(page).to have_selector('.results', text: expected_result)
+ it 'finds code and links to blame' do
+ expected_result = 'Update capybara, rspec-rails, poltergeist to recent versions'
- expect(find_field('dashboard_search').value).to eq(search)
- expect(find("#blob-L1502")[:href]).to match(%r{blob/v1.0.0/files/markdown/ruby-style-guide.md#L1502})
- expect(find("#blame-L1502")[:href]).to match(%r{blame/v1.0.0/files/markdown/ruby-style-guide.md#L1502})
- end
- end
+ fill_in('dashboard_search', with: 'rspec')
+ find('.gl-search-box-by-click-search-button').click
- context 'when :new_header_search is true' do
- context 'search code within refs', :js do
- let(:ref_name) { 'v1.0.0' }
+ expect(page).to have_selector('.results', text: expected_result)
- before do
- # This feature is diabled by default in spec_helper.rb.
- # We missed a feature breaking bug, so to prevent this regression, testing both scenarios for this spec.
- # This can be removed as part of closing https://gitlab.com/gitlab-org/gitlab/-/issues/339348.
- stub_feature_flags(new_header_search: true)
- visit(project_tree_path(project, ref_name))
-
- submit_search('gitlab-grack')
- select_search_scope('Code')
+ find("#blame-L3").click
+ expect(current_url).to match(%r{blame/master/.gitignore#L3})
end
- it 'shows ref switcher in code result summary' do
- expect(find('.ref-selector')).to have_text(ref_name)
- end
+ it 'search multiple words with refs switching' do
+ expected_result = 'Use `snake_case` for naming files'
+ search = 'for naming files'
- it 'persists branch name across search' do
+ fill_in('dashboard_search', with: search)
find('.gl-search-box-by-click-search-button').click
- expect(find('.ref-selector')).to have_text(ref_name)
- end
- # this example is use to test the desgine that the refs is not
- # only repersent the branch as well as the tags.
- it 'ref swither list all the branchs and tags' do
+ expect(page).to have_selector('.results', text: expected_result)
+
find('.ref-selector').click
wait_for_requests
page.within('.ref-selector') do
- expect(page).to have_selector('li', text: 'add-ipython-files')
- expect(page).to have_selector('li', text: 'v1.0.0')
+ find('li', text: 'v1.0.0').click
end
+
+ expect(page).to have_selector('.results', text: expected_result)
+
+ expect(find_field('dashboard_search').value).to eq(search)
+ expect(find("#blob-L1502")[:href]).to match(%r{blob/v1.0.0/files/markdown/ruby-style-guide.md#L1502})
+ expect(find("#blame-L1502")[:href]).to match(%r{blame/v1.0.0/files/markdown/ruby-style-guide.md#L1502})
end
+ end
- it 'search result changes when refs switched' do
- ref = 'master'
- expect(find('.results')).not_to have_content('path = gitlab-grack')
+ context 'when :new_header_search is true' do
+ context 'search code within refs' do
+ let(:ref_name) { 'v1.0.0' }
- find('.ref-selector').click
- wait_for_requests
+ before do
+ # This feature is disabled by default in spec_helper.rb.
+ # We missed a feature breaking bug, so to prevent this regression, testing both scenarios for this spec.
+ # This can be removed as part of closing https://gitlab.com/gitlab-org/gitlab/-/issues/339348.
+ stub_feature_flags(new_header_search: true)
+ visit(project_tree_path(project, ref_name))
- page.within('.ref-selector') do
- fill_in _('Search by Git revision'), with: ref
+ submit_search('gitlab-grack')
+ select_search_scope('Code')
+ end
+
+ it 'shows ref switcher in code result summary' do
+ expect(find('.ref-selector')).to have_text(ref_name)
+ end
+
+ it 'persists branch name across search' do
+ find('.gl-search-box-by-click-search-button').click
+ expect(find('.ref-selector')).to have_text(ref_name)
+ end
+
+ # this example is use to test the design that the refs is not
+ # only represent the branch as well as the tags.
+ it 'ref switcher list all the branches and tags' do
+ find('.ref-selector').click
wait_for_requests
- find('li', text: ref).click
+ page.within('.ref-selector') do
+ expect(page).to have_selector('li', text: 'add-ipython-files')
+ expect(page).to have_selector('li', text: 'v1.0.0')
+ end
end
- expect(page).to have_selector('.results', text: 'path = gitlab-grack')
- end
- end
- end
+ it 'search result changes when refs switched' do
+ ref = 'master'
+ expect(find('.results')).not_to have_content('path = gitlab-grack')
- context 'when :new_header_search is false' do
- context 'search code within refs', :js do
- let(:ref_name) { 'v1.0.0' }
+ find('.ref-selector').click
+ wait_for_requests
- before do
- # This feature is diabled by default in spec_helper.rb.
- # We missed a feature breaking bug, so to prevent this regression, testing both scenarios for this spec.
- # This can be removed as part of closing https://gitlab.com/gitlab-org/gitlab/-/issues/339348.
- stub_feature_flags(new_header_search: false)
- visit(project_tree_path(project, ref_name))
-
- submit_search('gitlab-grack')
- select_search_scope('Code')
- end
+ page.within('.ref-selector') do
+ fill_in _('Search by Git revision'), with: ref
+ wait_for_requests
- it 'shows ref switcher in code result summary' do
- expect(find('.ref-selector')).to have_text(ref_name)
- end
+ find('li', text: ref).click
+ end
- it 'persists branch name across search' do
- find('.gl-search-box-by-click-search-button').click
- expect(find('.ref-selector')).to have_text(ref_name)
+ expect(page).to have_selector('.results', text: 'path = gitlab-grack')
+ end
end
+ end
- # this example is use to test the desgine that the refs is not
- # only repersent the branch as well as the tags.
- it 'ref swither list all the branchs and tags' do
- find('.ref-selector').click
- wait_for_requests
+ context 'when :new_header_search is false' do
+ context 'search code within refs' do
+ let(:ref_name) { 'v1.0.0' }
- page.within('.ref-selector') do
- expect(page).to have_selector('li', text: 'add-ipython-files')
- expect(page).to have_selector('li', text: 'v1.0.0')
+ before do
+ # This feature is disabled by default in spec_helper.rb.
+ # We missed a feature breaking bug, so to prevent this regression, testing both scenarios for this spec.
+ # This can be removed as part of closing https://gitlab.com/gitlab-org/gitlab/-/issues/339348.
+ stub_feature_flags(new_header_search: false)
+ visit(project_tree_path(project, ref_name))
+
+ submit_search('gitlab-grack')
+ select_search_scope('Code')
end
- end
- it 'search result changes when refs switched' do
- ref = 'master'
- expect(find('.results')).not_to have_content('path = gitlab-grack')
+ it 'shows ref switcher in code result summary' do
+ expect(find('.ref-selector')).to have_text(ref_name)
+ end
- find('.ref-selector').click
- wait_for_requests
+ it 'persists branch name across search' do
+ find('.gl-search-box-by-click-search-button').click
+ expect(find('.ref-selector')).to have_text(ref_name)
+ end
- page.within('.ref-selector') do
- fill_in _('Search by Git revision'), with: ref
+ # this example is use to test the design that the refs is not
+ # only represent the branch as well as the tags.
+ it 'ref switcher list all the branches and tags' do
+ find('.ref-selector').click
wait_for_requests
- find('li', text: ref).click
+ page.within('.ref-selector') do
+ expect(page).to have_selector('li', text: 'add-ipython-files')
+ expect(page).to have_selector('li', text: 'v1.0.0')
+ end
end
- expect(page).to have_selector('.results', text: 'path = gitlab-grack')
+ it 'search result changes when refs switched' do
+ ref = 'master'
+ expect(find('.results')).not_to have_content('path = gitlab-grack')
+
+ find('.ref-selector').click
+ wait_for_requests
+
+ page.within('.ref-selector') do
+ fill_in _('Search by Git revision'), with: ref
+ wait_for_requests
+
+ find('li', text: ref).click
+ end
+
+ expect(page).to have_selector('.results', text: 'path = gitlab-grack')
+ end
end
end
- end
- it 'no ref switcher shown in issue result summary', :js do
- issue = create(:issue, title: 'test', project: project)
- visit(project_tree_path(project))
+ it 'no ref switcher shown in issue result summary' do
+ issue = create(:issue, title: 'test', project: project)
+ visit(project_tree_path(project))
- submit_search('test')
- select_search_scope('Code')
+ submit_search('test')
+ select_search_scope('Code')
- expect(page).to have_selector('.ref-selector')
+ expect(page).to have_selector('.ref-selector')
- select_search_scope('Issues')
+ select_search_scope('Issues')
- expect(find(:css, '.results')).to have_link(issue.title)
- expect(page).not_to have_selector('.ref-selector')
+ expect(find(:css, '.results')).to have_link(issue.title)
+ expect(page).not_to have_selector('.ref-selector')
+ end
end
- end
- context 'when signed out' do
- let(:project) { create(:project, :public, :repository) }
-
- before do
- stub_feature_flags(search_page_vertical_nav: false)
- visit(project_path(project))
- end
+ context 'when signed out' do
+ before do
+ stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
+ end
- it 'finds code' do
- submit_search('rspec')
- select_search_scope('Code')
+ context 'when block_anonymous_global_searches is enabled' do
+ it 'is redirected to login page' do
+ visit(search_path)
- expect(page).to have_selector('.results', text: 'Update capybara, rspec-rails, poltergeist to recent versions')
+ expect(page).to have_content('You must be logged in to search across all of GitLab')
+ end
+ end
end
end
end
diff --git a/spec/features/search/user_searches_for_comments_spec.rb b/spec/features/search/user_searches_for_comments_spec.rb
index a6793bc3aa7..3c39e9f41d4 100644
--- a/spec/features/search/user_searches_for_comments_spec.rb
+++ b/spec/features/search/user_searches_for_comments_spec.rb
@@ -2,45 +2,52 @@
require 'spec_helper'
-RSpec.describe 'User searches for comments' do
- let(:project) { create(:project, :repository) }
- let(:user) { create(:user) }
+RSpec.describe 'User searches for comments', :js, :disable_rate_limiter do
+ using RSpec::Parameterized::TableSyntax
- before do
- stub_feature_flags(search_page_vertical_nav: false)
- project.add_reporter(user)
- sign_in(user)
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
- visit(project_path(project))
- end
+ where(search_page_vertical_nav_enabled: [true, false])
+ with_them do
+ before do
+ stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
+ project.add_reporter(user)
+ sign_in(user)
- include_examples 'search timeouts', 'notes'
+ visit(project_path(project))
+ end
- context 'when a comment is in commits' do
- context 'when comment belongs to an invalid commit' do
- let(:comment) { create(:note_on_commit, author: user, project: project, commit_id: 12345678, note: 'Bug here') }
+ include_examples 'search timeouts', 'notes' do
+ let(:additional_params) { { project_id: project.id } }
+ end
- it 'finds a commit' do
- submit_search(comment.note)
- select_search_scope('Comments')
+ context 'when a comment is in commits' do
+ context 'when comment belongs to an invalid commit' do
+ let(:comment) { create(:note_on_commit, author: user, project: project, commit_id: 12345678, note: 'Bug here') }
- page.within('.results') do
- expect(page).to have_content('Commit deleted')
- expect(page).to have_content('12345678')
+ it 'finds a commit' do
+ submit_search(comment.note)
+ select_search_scope('Comments')
+
+ page.within('.results') do
+ expect(page).to have_content('Commit deleted')
+ expect(page).to have_content('12345678')
+ end
end
end
end
- end
- context 'when a comment is in a snippet' do
- let(:snippet) { create(:project_snippet, :private, project: project, author: user, title: 'Some title') }
- let(:comment) { create(:note, noteable: snippet, author: user, note: 'Supercalifragilisticexpialidocious', project: project) }
+ context 'when a comment is in a snippet' do
+ let(:snippet) { create(:project_snippet, :private, project: project, author: user, title: 'Some title') }
+ let(:comment) { create(:note, noteable: snippet, author: user, note: 'Supercalifragilisticexpialidocious', project: project) }
- it 'finds a snippet' do
- submit_search(comment.note)
- select_search_scope('Comments')
+ it 'finds a snippet' do
+ submit_search(comment.note)
+ select_search_scope('Comments')
- expect(page).to have_selector('.results', text: snippet.title)
+ expect(page).to have_selector('.results', text: snippet.title)
+ end
end
end
end
diff --git a/spec/features/search/user_searches_for_commits_spec.rb b/spec/features/search/user_searches_for_commits_spec.rb
index 4ec2a9e6cff..e5d86c27942 100644
--- a/spec/features/search/user_searches_for_commits_spec.rb
+++ b/spec/features/search/user_searches_for_commits_spec.rb
@@ -2,54 +2,62 @@
require 'spec_helper'
-RSpec.describe 'User searches for commits', :js do
+RSpec.describe 'User searches for commits', :js, :clean_gitlab_redis_rate_limiting do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:user) { create(:user) }
+
let(:project) { create(:project, :repository) }
let(:sha) { '6d394385cf567f80a8fd85055db1ab4c5295806f' }
- let(:user) { create(:user) }
- before do
- stub_feature_flags(search_page_vertical_nav: false)
- project.add_reporter(user)
- sign_in(user)
+ where(search_page_vertical_nav_enabled: [true, false])
+ with_them do
+ before do
+ stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
+ project.add_reporter(user)
+ sign_in(user)
- visit(search_path(project_id: project.id))
- end
+ visit(search_path(project_id: project.id))
+ end
- include_examples 'search timeouts', 'commits'
+ include_examples 'search timeouts', 'commits' do
+ let(:additional_params) { { project_id: project.id } }
+ end
- context 'when searching by SHA' do
- it 'finds a commit and redirects to its page' do
- submit_search(sha)
+ context 'when searching by SHA' do
+ it 'finds a commit and redirects to its page' do
+ submit_search(sha)
- expect(page).to have_current_path(project_commit_path(project, sha))
- end
+ expect(page).to have_current_path(project_commit_path(project, sha))
+ end
- it 'finds a commit in uppercase and redirects to its page' do
- submit_search(sha.upcase)
+ it 'finds a commit in uppercase and redirects to its page' do
+ submit_search(sha.upcase)
- expect(page).to have_current_path(project_commit_path(project, sha))
+ expect(page).to have_current_path(project_commit_path(project, sha))
+ end
end
- end
- context 'when searching by message' do
- it 'finds a commit and holds on /search page' do
- project.repository.commit_files(
- user,
- message: 'Message referencing another sha: "deadbeef"',
- branch_name: 'master',
- actions: [{ action: :create, file_path: 'a/new.file', contents: 'new file' }]
- )
+ context 'when searching by message' do
+ it 'finds a commit and holds on /search page' do
+ project.repository.commit_files(
+ user,
+ message: 'Message referencing another sha: "deadbeef"',
+ branch_name: 'master',
+ actions: [{ action: :create, file_path: 'a/new.file', contents: 'new file' }]
+ )
- submit_search('deadbeef')
+ submit_search('deadbeef')
- expect(page).to have_current_path('/search', ignore_query: true)
- end
+ expect(page).to have_current_path('/search', ignore_query: true)
+ end
- it 'finds multiple commits' do
- submit_search('See merge request')
- select_search_scope('Commits')
+ it 'finds multiple commits' do
+ submit_search('See merge request')
+ select_search_scope('Commits')
- expect(page).to have_selector('.commit-row-description', visible: false, count: 9)
+ expect(page).to have_selector('.commit-row-description', visible: false, count: 9)
+ end
end
end
end
diff --git a/spec/features/search/user_searches_for_issues_spec.rb b/spec/features/search/user_searches_for_issues_spec.rb
index 51d2f355848..22d48bd38f2 100644
--- a/spec/features/search/user_searches_for_issues_spec.rb
+++ b/spec/features/search/user_searches_for_issues_spec.rb
@@ -2,9 +2,12 @@
require 'spec_helper'
-RSpec.describe 'User searches for issues', :js do
- let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace) }
+RSpec.describe 'User searches for issues', :js, :clean_gitlab_redis_rate_limiting do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, namespace: user.namespace) }
+
let!(:issue1) { create(:issue, title: 'issue Foo', project: project, created_at: 1.hour.ago) }
let!(:issue2) { create(:issue, :closed, :confidential, title: 'issue Bar', project: project) }
@@ -14,127 +17,133 @@ RSpec.describe 'User searches for issues', :js do
select_search_scope('Issues')
end
- context 'when signed in' do
- before do
- project.add_maintainer(user)
- sign_in(user)
- stub_feature_flags(search_page_vertical_nav: false)
-
- visit(search_path)
- end
+ where(search_page_vertical_nav_enabled: [true, false])
- include_examples 'top right search form'
- include_examples 'search timeouts', 'issues'
+ with_them do
+ context 'when signed in' do
+ before do
+ stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
- it 'finds an issue' do
- search_for_issue(issue1.title)
+ project.add_maintainer(user)
+ sign_in(user)
- page.within('.results') do
- expect(page).to have_link(issue1.title)
- expect(page).not_to have_link(issue2.title)
+ visit(search_path)
end
- end
-
- it 'hides confidential icon for non-confidential issues' do
- search_for_issue(issue1.title)
- page.within('.results') do
- expect(page).not_to have_css('[data-testid="eye-slash-icon"]')
- end
- end
+ include_examples 'top right search form'
+ include_examples 'search timeouts', 'issues'
- it 'shows confidential icon for confidential issues' do
- search_for_issue(issue2.title)
+ it 'finds an issue' do
+ search_for_issue(issue1.title)
- page.within('.results') do
- expect(page).to have_css('[data-testid="eye-slash-icon"]')
+ page.within('.results') do
+ expect(page).to have_link(issue1.title)
+ expect(page).not_to have_link(issue2.title)
+ end
end
- end
- it 'shows correct badge for open issues' do
- search_for_issue(issue1.title)
+ it 'hides confidential icon for non-confidential issues' do
+ search_for_issue(issue1.title)
- page.within('.results') do
- expect(page).to have_css('.badge-success')
- expect(page).not_to have_css('.badge-info')
+ page.within('.results') do
+ expect(page).not_to have_css('[data-testid="eye-slash-icon"]')
+ end
end
- end
- it 'shows correct badge for closed issues' do
- search_for_issue(issue2.title)
+ it 'shows confidential icon for confidential issues' do
+ search_for_issue(issue2.title)
- page.within('.results') do
- expect(page).not_to have_css('.badge-success')
- expect(page).to have_css('.badge-info')
+ page.within('.results') do
+ expect(page).to have_css('[data-testid="eye-slash-icon"]')
+ end
end
- end
- it 'sorts by created date' do
- search_for_issue('issue')
+ it 'shows correct badge for open issues' do
+ search_for_issue(issue1.title)
- page.within('.results') do
- expect(page.all('.search-result-row').first).to have_link(issue2.title)
- expect(page.all('.search-result-row').last).to have_link(issue1.title)
+ page.within('.results') do
+ expect(page).to have_css('.badge-success')
+ expect(page).not_to have_css('.badge-info')
+ end
end
- find('[data-testid="sort-highest-icon"]').click
+ it 'shows correct badge for closed issues' do
+ search_for_issue(issue2.title)
- page.within('.results') do
- expect(page.all('.search-result-row').first).to have_link(issue1.title)
- expect(page.all('.search-result-row').last).to have_link(issue2.title)
+ page.within('.results') do
+ expect(page).not_to have_css('.badge-success')
+ expect(page).to have_css('.badge-info')
+ end
end
- end
-
- context 'when on a project page' do
- it 'finds an issue' do
- find('[data-testid="project-filter"]').click
- wait_for_requests
+ it 'sorts by created date' do
+ search_for_issue('issue')
- page.within('[data-testid="project-filter"]') do
- click_on(project.name)
+ page.within('.results') do
+ expect(page.all('.search-result-row').first).to have_link(issue2.title)
+ expect(page.all('.search-result-row').last).to have_link(issue1.title)
end
- search_for_issue(issue1.title)
+ find('[data-testid="sort-highest-icon"]').click
page.within('.results') do
- expect(page).to have_link(issue1.title)
- expect(page).not_to have_link(issue2.title)
+ expect(page.all('.search-result-row').first).to have_link(issue1.title)
+ expect(page.all('.search-result-row').last).to have_link(issue2.title)
end
end
- end
- end
- context 'when signed out' do
- context 'when block_anonymous_global_searches is disabled' do
- let(:project) { create(:project, :public) }
+ context 'when on a project page' do
+ it 'finds an issue' do
+ find('[data-testid="project-filter"]').click
- before do
- stub_feature_flags(block_anonymous_global_searches: false)
- stub_feature_flags(search_page_vertical_nav: false)
- visit(search_path)
- end
+ wait_for_requests
- include_examples 'top right search form'
+ page.within('[data-testid="project-filter"]') do
+ click_on(project.name)
+ end
- it 'finds an issue' do
- search_for_issue(issue1.title)
+ search_for_issue(issue1.title)
- page.within('.results') do
- expect(page).to have_link(issue1.title)
- expect(page).not_to have_link(issue2.title)
+ page.within('.results') do
+ expect(page).to have_link(issue1.title)
+ expect(page).not_to have_link(issue2.title)
+ end
end
end
end
- context 'when block_anonymous_global_searches is enabled' do
+ context 'when signed out' do
before do
- stub_feature_flags(search_page_vertical_nav: false)
- visit(search_path)
+ stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
end
- it 'is redirected to login page' do
- expect(page).to have_content('You must be logged in to search across all of GitLab')
+ context 'when block_anonymous_global_searches is disabled' do
+ let_it_be(:project) { create(:project, :public) }
+
+ before do
+ stub_feature_flags(block_anonymous_global_searches: false)
+
+ visit(search_path)
+ end
+
+ include_examples 'top right search form'
+
+ it 'finds an issue' do
+ search_for_issue(issue1.title)
+
+ page.within('.results') do
+ expect(page).to have_link(issue1.title)
+ expect(page).not_to have_link(issue2.title)
+ end
+ end
+ end
+
+ context 'when block_anonymous_global_searches is enabled' do
+ it 'is redirected to login page' do
+ visit(search_path)
+
+ expect(page).to have_content('You must be logged in to search across all of GitLab')
+ end
end
end
end
diff --git a/spec/features/search/user_searches_for_merge_requests_spec.rb b/spec/features/search/user_searches_for_merge_requests_spec.rb
index a4fbe3a6e59..9bbf2cf16d8 100644
--- a/spec/features/search/user_searches_for_merge_requests_spec.rb
+++ b/spec/features/search/user_searches_for_merge_requests_spec.rb
@@ -2,7 +2,9 @@
require 'spec_helper'
-RSpec.describe 'User searches for merge requests', :js do
+RSpec.describe 'User searches for merge requests', :js, :clean_gitlab_redis_rate_limiting do
+ using RSpec::Parameterized::TableSyntax
+
let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) }
let!(:merge_request1) { create(:merge_request, title: 'Merge Request Foo', source_project: project, target_project: project, created_at: 1.hour.ago) }
@@ -14,62 +16,64 @@ RSpec.describe 'User searches for merge requests', :js do
select_search_scope('Merge requests')
end
- before do
- stub_feature_flags(search_page_vertical_nav: false)
- project.add_maintainer(user)
- sign_in(user)
+ where(search_page_vertical_nav_enabled: [true, false])
+ with_them do
+ before do
+ stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
+ sign_in(user)
- visit(search_path)
- end
+ visit(search_path)
+ end
- include_examples 'top right search form'
- include_examples 'search timeouts', 'merge_requests'
+ include_examples 'top right search form'
+ include_examples 'search timeouts', 'merge_requests'
- it 'finds a merge request' do
- search_for_mr(merge_request1.title)
+ it 'finds a merge request' do
+ search_for_mr(merge_request1.title)
- page.within('.results') do
- expect(page).to have_link(merge_request1.title)
- expect(page).not_to have_link(merge_request2.title)
+ page.within('.results') do
+ expect(page).to have_link(merge_request1.title)
+ expect(page).not_to have_link(merge_request2.title)
- # Each result should have MR refs like `gitlab-org/gitlab!1`
- page.all('.search-result-row').each do |e|
- expect(e.text).to match(/!\d+/)
+ # Each result should have MR refs like `gitlab-org/gitlab!1`
+ page.all('.search-result-row').each do |e|
+ expect(e.text).to match(/!\d+/)
+ end
end
end
- end
- it 'sorts by created date' do
- search_for_mr('Merge Request')
+ it 'sorts by created date' do
+ search_for_mr('Merge Request')
- page.within('.results') do
- expect(page.all('.search-result-row').first).to have_link(merge_request2.title)
- expect(page.all('.search-result-row').last).to have_link(merge_request1.title)
- end
+ page.within('.results') do
+ expect(page.all('.search-result-row').first).to have_link(merge_request2.title)
+ expect(page.all('.search-result-row').last).to have_link(merge_request1.title)
+ end
- find('[data-testid="sort-highest-icon"]').click
+ find('[data-testid="sort-highest-icon"]').click
- page.within('.results') do
- expect(page.all('.search-result-row').first).to have_link(merge_request1.title)
- expect(page.all('.search-result-row').last).to have_link(merge_request2.title)
+ page.within('.results') do
+ expect(page.all('.search-result-row').first).to have_link(merge_request1.title)
+ expect(page.all('.search-result-row').last).to have_link(merge_request2.title)
+ end
end
- end
- context 'when on a project page' do
- it 'finds a merge request' do
- find('[data-testid="project-filter"]').click
+ context 'when on a project page' do
+ it 'finds a merge request' do
+ find('[data-testid="project-filter"]').click
- wait_for_requests
+ wait_for_requests
- page.within('[data-testid="project-filter"]') do
- click_on(project.name)
- end
+ page.within('[data-testid="project-filter"]') do
+ click_on(project.name)
+ end
- search_for_mr(merge_request1.title)
+ search_for_mr(merge_request1.title)
- page.within('.results') do
- expect(page).to have_link(merge_request1.title)
- expect(page).not_to have_link(merge_request2.title)
+ page.within('.results') do
+ expect(page).to have_link(merge_request1.title)
+ expect(page).not_to have_link(merge_request2.title)
+ end
end
end
end
diff --git a/spec/features/search/user_searches_for_milestones_spec.rb b/spec/features/search/user_searches_for_milestones_spec.rb
index 6773059830c..702d4e60022 100644
--- a/spec/features/search/user_searches_for_milestones_spec.rb
+++ b/spec/features/search/user_searches_for_milestones_spec.rb
@@ -2,44 +2,30 @@
require 'spec_helper'
-RSpec.describe 'User searches for milestones', :js do
- let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace) }
- let!(:milestone1) { create(:milestone, title: 'Foo', project: project) }
- let!(:milestone2) { create(:milestone, title: 'Bar', project: project) }
+RSpec.describe 'User searches for milestones', :js, :clean_gitlab_redis_rate_limiting do
+ using RSpec::Parameterized::TableSyntax
- before do
- project.add_maintainer(user)
- sign_in(user)
- stub_feature_flags(search_page_vertical_nav: false)
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, namespace: user.namespace) }
- visit(search_path)
- end
+ let!(:milestone1) { create(:milestone, title: 'Foo', project: project) }
+ let!(:milestone2) { create(:milestone, title: 'Bar', project: project) }
- include_examples 'top right search form'
- include_examples 'search timeouts', 'milestones'
+ where(search_page_vertical_nav_enabled: [true, false])
- it 'finds a milestone' do
- fill_in('dashboard_search', with: milestone1.title)
- find('.gl-search-box-by-click-search-button').click
- select_search_scope('Milestones')
+ with_them do
+ before do
+ project.add_maintainer(user)
+ sign_in(user)
+ stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
- page.within('.results') do
- expect(page).to have_link(milestone1.title)
- expect(page).not_to have_link(milestone2.title)
+ visit(search_path)
end
- end
-
- context 'when on a project page' do
- it 'finds a milestone' do
- find('[data-testid="project-filter"]').click
-
- wait_for_requests
- page.within('[data-testid="project-filter"]') do
- click_on(project.name)
- end
+ include_examples 'top right search form'
+ include_examples 'search timeouts', 'milestones'
+ it 'finds a milestone' do
fill_in('dashboard_search', with: milestone1.title)
find('.gl-search-box-by-click-search-button').click
select_search_scope('Milestones')
@@ -49,5 +35,26 @@ RSpec.describe 'User searches for milestones', :js do
expect(page).not_to have_link(milestone2.title)
end
end
+
+ context 'when on a project page' do
+ it 'finds a milestone' do
+ find('[data-testid="project-filter"]').click
+
+ wait_for_requests
+
+ page.within('[data-testid="project-filter"]') do
+ click_on(project.name)
+ end
+
+ fill_in('dashboard_search', with: milestone1.title)
+ find('.gl-search-box-by-click-search-button').click
+ select_search_scope('Milestones')
+
+ page.within('.results') do
+ expect(page).to have_link(milestone1.title)
+ expect(page).not_to have_link(milestone2.title)
+ end
+ end
+ end
end
end
diff --git a/spec/features/search/user_searches_for_projects_spec.rb b/spec/features/search/user_searches_for_projects_spec.rb
index 5902859d1f5..15c6224b61b 100644
--- a/spec/features/search/user_searches_for_projects_spec.rb
+++ b/spec/features/search/user_searches_for_projects_spec.rb
@@ -2,15 +2,12 @@
require 'spec_helper'
-RSpec.describe 'User searches for projects', :js do
+RSpec.describe 'User searches for projects', :js, :disable_rate_limiter do
let!(:project) { create(:project, :public, name: 'Shop') }
context 'when signed out' do
context 'when block_anonymous_global_searches is disabled' do
before do
- stub_feature_flags(search_page_vertical_nav: false)
- allow(Gitlab::ApplicationRateLimiter).to receive(:threshold).with(:search_rate_limit).and_return(1000)
- allow(Gitlab::ApplicationRateLimiter).to receive(:threshold).with(:search_rate_limit_unauthenticated).and_return(1000)
stub_feature_flags(block_anonymous_global_searches: false)
end
diff --git a/spec/features/search/user_searches_for_users_spec.rb b/spec/features/search/user_searches_for_users_spec.rb
index e21a66fed92..1d649b42c8c 100644
--- a/spec/features/search/user_searches_for_users_spec.rb
+++ b/spec/features/search/user_searches_for_users_spec.rb
@@ -2,84 +2,90 @@
require 'spec_helper'
-RSpec.describe 'User searches for users' do
- let(:user1) { create(:user, username: 'gob_bluth', name: 'Gob Bluth') }
- let(:user2) { create(:user, username: 'michael_bluth', name: 'Michael Bluth') }
- let(:user3) { create(:user, username: 'gob_2018', name: 'George Oscar Bluth') }
-
- before do
- stub_feature_flags(search_page_vertical_nav: false)
- sign_in(user1)
- end
-
- include_examples 'search timeouts', 'users'
+RSpec.describe 'User searches for users', :js, :clean_gitlab_redis_rate_limiting do
+ let_it_be(:user1) { create(:user, username: 'gob_bluth', name: 'Gob Bluth') }
+ let_it_be(:user2) { create(:user, username: 'michael_bluth', name: 'Michael Bluth') }
+ let_it_be(:user3) { create(:user, username: 'gob_2018', name: 'George Oscar Bluth') }
- context 'when on the dashboard' do
- it 'finds the user', :js do
- visit dashboard_projects_path
+ where(search_page_vertical_nav_enabled: [true, false])
+ with_them do
+ before do
+ stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
- submit_search('gob')
- select_search_scope('Users')
+ sign_in(user1)
+ end
- page.within('.results') do
- expect(page).to have_content('Gob Bluth')
- expect(page).to have_content('@gob_bluth')
+ include_examples 'search timeouts', 'users' do
+ before do
+ visit(search_path)
end
end
- end
- context 'when on the project page' do
- let(:project) { create(:project) }
+ context 'when on the dashboard' do
+ it 'finds the user' do
+ visit dashboard_projects_path
- before do
- create(:project_member, :developer, user: user1, project: project)
- create(:project_member, :developer, user: user2, project: project)
- user3
+ submit_search('gob')
+ select_search_scope('Users')
+
+ page.within('.results') do
+ expect(page).to have_content('Gob Bluth')
+ expect(page).to have_content('@gob_bluth')
+ end
+ end
end
- it 'finds the user belonging to the project' do
- visit project_path(project)
+ context 'when on the project page' do
+ let_it_be_with_reload(:project) { create(:project) }
- submit_search('gob')
- select_search_scope('Users')
+ before do
+ project.add_developer(user1)
+ project.add_developer(user2)
+ end
+
+ it 'finds the user belonging to the project' do
+ visit project_path(project)
- page.within('.results') do
- expect(page).to have_content('Gob Bluth')
- expect(page).to have_content('@gob_bluth')
+ submit_search('gob')
+ select_search_scope('Users')
- expect(page).not_to have_content('Michael Bluth')
- expect(page).not_to have_content('@michael_bluth')
+ page.within('.results') do
+ expect(page).to have_content('Gob Bluth')
+ expect(page).to have_content('@gob_bluth')
- expect(page).not_to have_content('George Oscar Bluth')
- expect(page).not_to have_content('@gob_2018')
+ expect(page).not_to have_content('Michael Bluth')
+ expect(page).not_to have_content('@michael_bluth')
+
+ expect(page).not_to have_content('George Oscar Bluth')
+ expect(page).not_to have_content('@gob_2018')
+ end
end
end
- end
- context 'when on the group page' do
- let(:group) { create(:group) }
+ context 'when on the group page' do
+ let(:group) { create(:group) }
- before do
- create(:group_member, :developer, user: user1, group: group)
- create(:group_member, :developer, user: user2, group: group)
- user3
- end
+ before do
+ group.add_developer(user1)
+ group.add_developer(user2)
+ end
- it 'finds the user belonging to the group' do
- visit group_path(group)
+ it 'finds the user belonging to the group' do
+ visit group_path(group)
- submit_search('gob')
- select_search_scope('Users')
+ submit_search('gob')
+ select_search_scope('Users')
- page.within('.results') do
- expect(page).to have_content('Gob Bluth')
- expect(page).to have_content('@gob_bluth')
+ page.within('.results') do
+ expect(page).to have_content('Gob Bluth')
+ expect(page).to have_content('@gob_bluth')
- expect(page).not_to have_content('Michael Bluth')
- expect(page).not_to have_content('@michael_bluth')
+ expect(page).not_to have_content('Michael Bluth')
+ expect(page).not_to have_content('@michael_bluth')
- expect(page).not_to have_content('George Oscar Bluth')
- expect(page).not_to have_content('@gob_2018')
+ expect(page).not_to have_content('George Oscar Bluth')
+ expect(page).not_to have_content('@gob_2018')
+ end
end
end
end
diff --git a/spec/features/search/user_searches_for_wiki_pages_spec.rb b/spec/features/search/user_searches_for_wiki_pages_spec.rb
index 2e390309022..0f20ad0aa07 100644
--- a/spec/features/search/user_searches_for_wiki_pages_spec.rb
+++ b/spec/features/search/user_searches_for_wiki_pages_spec.rb
@@ -2,55 +2,59 @@
require 'spec_helper'
-RSpec.describe 'User searches for wiki pages', :js do
- let(:user) { create(:user) }
+RSpec.describe 'User searches for wiki pages', :js, :clean_gitlab_redis_rate_limiting do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:user) { create(:user) }
+
let(:project) { create(:project, :repository, :wiki_repo, namespace: user.namespace) }
let!(:wiki_page) { create(:wiki_page, wiki: project.wiki, title: 'directory/title', content: 'Some Wiki content') }
- before do
- stub_feature_flags(search_page_vertical_nav: false)
- project.add_maintainer(user)
- sign_in(user)
-
- visit(search_path)
- end
+ where(search_page_vertical_nav_enabled: [true, false])
+ with_them do
+ before do
+ stub_feature_flags(search_page_vertical_nav: search_page_vertical_nav_enabled)
+ project.add_maintainer(user)
+ sign_in(user)
- include_examples 'top right search form'
- include_examples 'search timeouts', 'wiki_blobs'
+ visit(search_path)
+ end
- shared_examples 'search wiki blobs' do
- before do
- stub_feature_flags(search_page_vertical_nav: false)
+ include_examples 'top right search form'
+ include_examples 'search timeouts', 'wiki_blobs' do
+ let(:additional_params) { { project_id: project.id } }
end
- it 'finds a page' do
- find('[data-testid="project-filter"]').click
+ shared_examples 'search wiki blobs' do
+ it 'finds a page' do
+ find('[data-testid="project-filter"]').click
- wait_for_requests
+ wait_for_requests
- page.within('[data-testid="project-filter"]') do
- click_on(project.name)
- end
+ page.within('[data-testid="project-filter"]') do
+ click_on(project.name)
+ end
- fill_in('dashboard_search', with: search_term)
- find('.gl-search-box-by-click-search-button').click
- select_search_scope('Wiki')
+ fill_in('dashboard_search', with: search_term)
+ find('.gl-search-box-by-click-search-button').click
+ select_search_scope('Wiki')
- page.within('.results') do
- expect(page).to have_link(wiki_page.title, href: project_wiki_path(project, wiki_page.slug))
+ page.within('.results') do
+ expect(page).to have_link(wiki_page.title, href: project_wiki_path(project, wiki_page.slug))
+ end
end
end
- end
- context 'when searching by content' do
- it_behaves_like 'search wiki blobs' do
- let(:search_term) { 'content' }
+ context 'when searching by content' do
+ it_behaves_like 'search wiki blobs' do
+ let(:search_term) { 'content' }
+ end
end
- end
- context 'when searching by title' do
- it_behaves_like 'search wiki blobs' do
- let(:search_term) { 'title' }
+ context 'when searching by title' do
+ it_behaves_like 'search wiki blobs' do
+ let(:search_term) { 'title' }
+ end
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 827e3984896..04f22cd2a31 100644
--- a/spec/features/search/user_uses_header_search_field_spec.rb
+++ b/spec/features/search/user_uses_header_search_field_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe 'User uses header search field', :js do
+RSpec.describe 'User uses header search field', :js, :disable_rate_limiter do
include FilteredSearchHelpers
let_it_be(:project) { create(:project, :repository) }
@@ -17,10 +17,6 @@ RSpec.describe 'User uses header search field', :js do
end
before do
- stub_feature_flags(search_page_vertical_nav: false)
- allow(Gitlab::ApplicationRateLimiter).to receive(:threshold).and_return(0)
- allow(Gitlab::ApplicationRateLimiter).to receive(:threshold).with(:search_rate_limit).and_return(1000)
- allow(Gitlab::ApplicationRateLimiter).to receive(:threshold).with(:search_rate_limit_unauthenticated).and_return(1000)
sign_in(user)
end
diff --git a/spec/features/snippets/search_snippets_spec.rb b/spec/features/snippets/search_snippets_spec.rb
index 69b9a0aa64d..d18729d080a 100644
--- a/spec/features/snippets/search_snippets_spec.rb
+++ b/spec/features/snippets/search_snippets_spec.rb
@@ -2,11 +2,7 @@
require 'spec_helper'
-RSpec.describe 'Search Snippets' do
- before do
- stub_feature_flags(search_page_vertical_nav: false)
- end
-
+RSpec.describe 'Search Snippets', :js do
it 'user searches for snippets by title' do
public_snippet = create(:personal_snippet, :public, title: 'Beginning and Middle')
private_snippet = create(:personal_snippet, :private, title: 'Middle and End')
diff --git a/spec/features/user_sees_marketing_header_spec.rb b/spec/features/user_sees_marketing_header_spec.rb
index 31f088ce010..eae964cec02 100644
--- a/spec/features/user_sees_marketing_header_spec.rb
+++ b/spec/features/user_sees_marketing_header_spec.rb
@@ -6,50 +6,14 @@ RSpec.describe 'User sees experimental lmarketing header' do
let_it_be(:project) { create(:project, :public) }
context 'when not logged in' do
- context 'when experiment candidate' do
- it 'shows marketing header links', :aggregate_failures do
- stub_experiments(logged_out_marketing_header: :candidate)
-
- visit project_path(project)
-
- expect(page).to have_text "About GitLab"
- expect(page).to have_text "Pricing"
- expect(page).to have_text "Talk to an expert"
- expect(page).to have_text "Sign up now"
- expect(page).to have_text "Login"
- end
- end
-
- context 'when experiment candidate (trial focused variant)' do
- it 'shows marketing header links', :aggregate_failures do
- stub_experiments(logged_out_marketing_header: :trial_focused)
-
- visit project_path(project)
-
- expect(page).to have_text "About GitLab"
- expect(page).to have_text "Pricing"
- expect(page).to have_text "Talk to an expert"
- expect(page).to have_text "Get a free trial"
- expect(page).to have_text "Sign up"
- expect(page).to have_text "Login"
- end
- end
-
- context 'when experiment control' do
- it 'does not show marketing header links', :aggregate_failures do
- stub_experiments(logged_out_marketing_header: :control)
-
- visit project_path(project)
+ it 'shows marketing header links', :aggregate_failures do
+ visit project_path(project)
- expect(page).not_to have_text "About GitLab"
- expect(page).not_to have_text "Pricing"
- expect(page).not_to have_text "Talk to an expert"
- expect(page).not_to have_text "Sign up now"
- expect(page).not_to have_text "Login"
- expect(page).not_to have_text "Get a free trial"
- expect(page).not_to have_text "Sign up"
- expect(page).to have_text "Sign in / Register"
- end
+ expect(page).to have_text "About GitLab"
+ expect(page).to have_text "Pricing"
+ expect(page).to have_text "Talk to an expert"
+ expect(page).to have_text "Sign up now"
+ expect(page).to have_text "Login"
end
end
@@ -57,8 +21,6 @@ RSpec.describe 'User sees experimental lmarketing header' do
it 'does not show marketing header links', :aggregate_failures do
sign_in(create(:user))
- stub_experiments(logged_out_marketing_header: :candidate)
-
visit project_path(project)
expect(page).not_to have_text "About GitLab"
diff --git a/spec/features/users/active_sessions_spec.rb b/spec/features/users/active_sessions_spec.rb
index c722a4ec05c..e2ee78a7cc5 100644
--- a/spec/features/users/active_sessions_spec.rb
+++ b/spec/features/users/active_sessions_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe 'Active user sessions', :clean_gitlab_redis_sessions do
user = create(:user)
Gitlab::Redis::Sessions.with do |redis|
- redis.sadd("session:lookup:user:gitlab:#{user.id}", '59822c7d9fcdfa03725eff41782ad97d')
+ redis.sadd?("session:lookup:user:gitlab:#{user.id}", '59822c7d9fcdfa03725eff41782ad97d')
end
gitlab_sign_in(user)
@@ -45,7 +45,7 @@ RSpec.describe 'Active user sessions', :clean_gitlab_redis_sessions do
personal_access_token = create(:personal_access_token, user: user)
Gitlab::Redis::Sessions.with do |redis|
- redis.sadd("session:lookup:user:gitlab:#{user.id}", '59822c7d9fcdfa03725eff41782ad97d')
+ redis.sadd?("session:lookup:user:gitlab:#{user.id}", '59822c7d9fcdfa03725eff41782ad97d')
end
visit user_path(user, :atom, private_token: personal_access_token.token)
diff --git a/spec/features/work_items/work_item_children_spec.rb b/spec/features/work_items/work_item_children_spec.rb
index 95774680a2b..10a1bf7541e 100644
--- a/spec/features/work_items/work_item_children_spec.rb
+++ b/spec/features/work_items/work_item_children_spec.rb
@@ -15,7 +15,6 @@ RSpec.describe 'Work item children', :js do
sign_in(user)
stub_feature_flags(work_items: true)
- stub_feature_flags(work_items_hierarchy: true)
visit project_issue_path(project, issue)
@@ -49,6 +48,7 @@ RSpec.describe 'Work item children', :js 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"]')
@@ -58,9 +58,10 @@ RSpec.describe 'Work item children', :js do
end
end
- it 'addss a child task', :aggregate_failures do
+ 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'
@@ -78,6 +79,7 @@ RSpec.describe 'Work item children', :js do
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
@@ -106,5 +108,29 @@ RSpec.describe 'Work item children', :js do
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/finders/autocomplete/users_finder_spec.rb b/spec/finders/autocomplete/users_finder_spec.rb
index de031041e18..57f804e471f 100644
--- a/spec/finders/autocomplete/users_finder_spec.rb
+++ b/spec/finders/autocomplete/users_finder_spec.rb
@@ -8,7 +8,8 @@ RSpec.describe Autocomplete::UsersFinder do
describe '#execute' do
let_it_be(:user1) { create(:user, name: 'zzzzzname', username: 'johndoe') }
- let_it_be(:user2) { create(:user, :blocked, username: 'notsorandom') }
+ let_it_be(:blocked_user) { create(:user, :blocked, username: 'blocked_user') }
+ let_it_be(:banned_user) { create(:user, :banned, username: 'banned_user') }
let_it_be(:external_user) { create(:user, :external) }
let_it_be(:omniauth_user) { create(:omniauth_user, provider: 'twitter', extern_uid: '123456') }
@@ -39,7 +40,13 @@ RSpec.describe Autocomplete::UsersFinder do
end
context 'and author is blocked' do
- let(:params) { { author_id: user2.id } }
+ let(:params) { { author_id: blocked_user.id } }
+
+ it { is_expected.to match_array([project.first_owner]) }
+ end
+
+ context 'and author is banned' do
+ let(:params) { { author_id: banned_user.id } }
it { is_expected.to match_array([project.first_owner]) }
end
@@ -108,7 +115,7 @@ RSpec.describe Autocomplete::UsersFinder do
end
context 'when filtered by skip_users' do
- let(:params) { { skip_users: [omniauth_user.id, current_user.id] } }
+ let(:params) { { skip_users: [omniauth_user.id, current_user.id, blocked_user] } }
it { is_expected.to match_array([user1, external_user]) }
end
@@ -139,10 +146,10 @@ RSpec.describe Autocomplete::UsersFinder do
end
context 'when filtered by current_user' do
- let(:current_user) { user2 }
+ let(:current_user) { blocked_user }
let(:params) { { current_user: true } }
- it { is_expected.to match_array([user2, user1, external_user, omniauth_user]) }
+ it { is_expected.to match_array([blocked_user, user1, external_user, omniauth_user]) }
end
context 'when filtered by author_id' do
@@ -155,5 +162,37 @@ RSpec.describe Autocomplete::UsersFinder do
associations = subject.map { |user| user.association(:status) }
expect(associations).to all(be_loaded)
end
+
+ context 'when filtered by state' do
+ context "searching without states" do
+ let(:params) { { states: nil } }
+
+ it { is_expected.to match_array([user1, external_user, omniauth_user, current_user]) }
+ end
+
+ context "searching with states=active" do
+ let(:params) { { states: %w[active] } }
+
+ it { is_expected.to match_array([user1, external_user, omniauth_user, current_user]) }
+ end
+
+ context "searching with states=blocked" do
+ let(:params) { { states: %w[blocked] } }
+
+ it { is_expected.to match_array([blocked_user]) }
+ end
+
+ context "searching with states=banned" do
+ let(:params) { { states: %w[banned] } }
+
+ it { is_expected.to match_array([banned_user]) }
+ end
+
+ context "searching with states=blocked,banned" do
+ let(:params) { { states: %w[blocked banned] } }
+
+ it { is_expected.to match_array([blocked_user, banned_user]) }
+ end
+ end
end
end
diff --git a/spec/finders/branches_finder_spec.rb b/spec/finders/branches_finder_spec.rb
index 9314f616c44..f14c60c4b8f 100644
--- a/spec/finders/branches_finder_spec.rb
+++ b/spec/finders/branches_finder_spec.rb
@@ -211,7 +211,7 @@ RSpec.describe BranchesFinder do
it 'raises an error' do
expect do
subject
- end.to raise_error(Gitlab::Git::CommandError, '13:could not find page token.')
+ end.to raise_error(Gitlab::Git::CommandError, /could not find page token/)
end
end
diff --git a/spec/finders/clusters/agent_authorizations_finder_spec.rb b/spec/finders/clusters/agent_authorizations_finder_spec.rb
index 2d90f32adc5..f680792d6c4 100644
--- a/spec/finders/clusters/agent_authorizations_finder_spec.rb
+++ b/spec/finders/clusters/agent_authorizations_finder_spec.rb
@@ -64,14 +64,6 @@ RSpec.describe Clusters::AgentAuthorizationsFinder do
let!(:project_authorization) { create(:agent_project_authorization, agent: non_ancestor_agent, project: requesting_project) }
it { is_expected.to match_array([project_authorization]) }
-
- context 'agent_authorization_include_descendants feature flag is disabled' do
- before do
- stub_feature_flags(agent_authorization_include_descendants: false)
- end
-
- it { is_expected.to be_empty }
- end
end
context 'with project authorizations present' do
@@ -138,14 +130,6 @@ RSpec.describe Clusters::AgentAuthorizationsFinder do
let!(:group_authorization) { create(:agent_group_authorization, agent: non_ancestor_agent, group: bottom_level_group) }
it { is_expected.to match_array([group_authorization]) }
-
- context 'agent_authorization_include_descendants feature flag is disabled' do
- before do
- stub_feature_flags(agent_authorization_include_descendants: false)
- end
-
- it { is_expected.to be_empty }
- end
end
it_behaves_like 'access_as' do
diff --git a/spec/finders/clusters/agent_tokens_finder_spec.rb b/spec/finders/clusters/agent_tokens_finder_spec.rb
new file mode 100644
index 00000000000..619aca891c1
--- /dev/null
+++ b/spec/finders/clusters/agent_tokens_finder_spec.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Clusters::AgentTokensFinder do
+ describe '#execute' do
+ let_it_be(:project) { create(:project) }
+ let(:user) { create(:user, maintainer_projects: [project]) }
+ let(:agent) { create(:cluster_agent, project: project) }
+ let(:agent_id) { agent.id }
+
+ let!(:matching_agent_tokens) do
+ [
+ create(:cluster_agent_token, agent: agent),
+ create(:cluster_agent_token, :revoked, agent: agent)
+ ]
+ end
+
+ subject(:execute) { described_class.new(project, user, agent_id).execute }
+
+ it 'returns the tokens of the specified agent' do
+ # creating a token in a different agent to make sure it will not be included in the result
+ create(:cluster_agent_token, agent: create(:cluster_agent))
+
+ expect(execute).to match_array(matching_agent_tokens)
+ end
+
+ context 'when user does not have permission' do
+ let(:user) { create(:user) }
+
+ before do
+ project.add_reporter(user)
+ end
+
+ it 'raises an error' do
+ expect { execute }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+
+ context 'when agent does not exist' do
+ let(:agent_id) { non_existing_record_id }
+
+ it 'raises an error' do
+ expect { execute }.to raise_error(ActiveRecord::RecordNotFound)
+ end
+ end
+ end
+end
diff --git a/spec/finders/incident_management/timeline_event_tags_finder_spec.rb b/spec/finders/incident_management/timeline_event_tags_finder_spec.rb
new file mode 100644
index 00000000000..5bdb356ff62
--- /dev/null
+++ b/spec/finders/incident_management/timeline_event_tags_finder_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IncidentManagement::TimelineEventTagsFinder do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:incident) { create(:incident, project: project) }
+ let_it_be(:timeline_event) do
+ create(:incident_management_timeline_event, project: project, incident: incident, occurred_at: Time.current)
+ end
+
+ let_it_be(:timeline_event_tag) do
+ create(:incident_management_timeline_event_tag, project: project)
+ end
+
+ let_it_be(:timeline_event_tag_link) do
+ create(:incident_management_timeline_event_tag_link,
+ timeline_event: timeline_event,
+ timeline_event_tag: timeline_event_tag)
+ end
+
+ let(:params) { {} }
+
+ describe '#execute' do
+ subject(:execute) { described_class.new(user, timeline_event, params).execute }
+
+ context 'when user has permissions' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'returns tags on the event' do
+ is_expected.to match_array([timeline_event_tag])
+ end
+
+ context 'when event does not have tags' do
+ let(:timeline_event) do
+ create(:incident_management_timeline_event, project: project, incident: incident, occurred_at: Time.current)
+ end
+
+ it 'returns empty result' do
+ is_expected.to match_array([])
+ end
+ end
+
+ context 'when timeline event is nil' do
+ let(:timeline_event) { nil }
+
+ it { is_expected.to eq(IncidentManagement::TimelineEventTag.none) }
+ end
+ end
+
+ context 'when user does not have permissions' do
+ it { is_expected.to eq(IncidentManagement::TimelineEventTag.none) }
+ end
+ end
+end
diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb
index 1fa2a975ec3..02153715eac 100644
--- a/spec/finders/projects_finder_spec.rb
+++ b/spec/finders/projects_finder_spec.rb
@@ -350,43 +350,6 @@ RSpec.describe ProjectsFinder do
end
end
- describe 'filter by without_deleted' do
- let_it_be(:pending_delete_project) { create(:project, :public, pending_delete: true) }
-
- let(:params) { { without_deleted: without_deleted } }
-
- shared_examples 'returns all projects' do
- it { expect(subject).to include(public_project, internal_project, pending_delete_project) }
- end
-
- context 'when without_deleted is true' do
- let(:without_deleted) { true }
-
- it 'returns projects that are not pending_delete' do
- expect(subject).not_to include(pending_delete_project)
- expect(subject).to include(public_project, internal_project)
- end
- end
-
- context 'when without_deleted is false' do
- let(:without_deleted) { false }
-
- it_behaves_like 'returns all projects'
- end
-
- context 'when without_deleted is nil' do
- let(:without_deleted) { nil }
-
- it_behaves_like 'returns all projects'
- end
-
- context 'when without_deleted is not present' do
- let(:params) { {} }
-
- it_behaves_like 'returns all projects'
- end
- end
-
describe 'filter by last_activity_after' do
let(:params) { { last_activity_after: 60.minutes.ago } }
@@ -398,6 +361,15 @@ RSpec.describe ProjectsFinder do
it { is_expected.to match_array([internal_project]) }
end
+ describe 'always filters by without_deleted' do
+ let_it_be(:pending_delete_project) { create(:project, :public, pending_delete: true) }
+
+ it 'returns projects that are not pending_delete' do
+ expect(subject).not_to include(pending_delete_project)
+ expect(subject).to include(public_project, internal_project)
+ end
+ end
+
describe 'filter by last_activity_before' do
let(:params) { { last_activity_before: 60.minutes.ago } }
diff --git a/spec/finders/users_star_projects_finder_spec.rb b/spec/finders/users_star_projects_finder_spec.rb
index 038506cc93f..e824940430c 100644
--- a/spec/finders/users_star_projects_finder_spec.rb
+++ b/spec/finders/users_star_projects_finder_spec.rb
@@ -8,10 +8,12 @@ RSpec.describe UsersStarProjectsFinder do
let(:user) { create(:user) }
let(:private_user) { create(:user, private_profile: true) }
let(:other_user) { create(:user) }
+ let(:blocked_user) { create(:user, state: 'blocked') }
before do
user.toggle_star(project)
private_user.toggle_star(project)
+ blocked_user.toggle_star(project)
end
describe '#execute' do
@@ -38,5 +40,13 @@ RSpec.describe UsersStarProjectsFinder do
it { is_expected.to match_array(public_stars) }
end
+
+ describe 'with active users only' do
+ let(:current_user) { private_user }
+
+ it 'ignores stars of non-active users' do
+ is_expected.not_to include(*blocked_user.users_star_projects)
+ end
+ end
end
end
diff --git a/spec/fixtures/api/schemas/entities/codequality_degradation.json b/spec/fixtures/api/schemas/entities/codequality_degradation.json
index 6cf20ee8b9e..863b9f0c77e 100644
--- a/spec/fixtures/api/schemas/entities/codequality_degradation.json
+++ b/spec/fixtures/api/schemas/entities/codequality_degradation.json
@@ -18,7 +18,10 @@
},
"line": {
"type": "integer"
+ },
+ "web_url": {
+ "type": "string"
}
},
"additionalProperties": false
-}
+} \ No newline at end of file
diff --git a/spec/fixtures/api/schemas/entities/codequality_reports_comparer.json b/spec/fixtures/api/schemas/entities/codequality_reports_comparer.json
index afe82f5e632..05ae036d986 100644
--- a/spec/fixtures/api/schemas/entities/codequality_reports_comparer.json
+++ b/spec/fixtures/api/schemas/entities/codequality_reports_comparer.json
@@ -1,6 +1,12 @@
{
"type": "object",
- "required": ["status", "summary", "new_errors", "resolved_errors", "existing_errors"],
+ "required": [
+ "status",
+ "summary",
+ "new_errors",
+ "resolved_errors",
+ "existing_errors"
+ ],
"properties": {
"status": {
"type": "string"
@@ -18,7 +24,11 @@
"type": "integer"
}
},
- "required": ["total", "resolved", "errored"]
+ "required": [
+ "total",
+ "resolved",
+ "errored"
+ ]
},
"new_errors": {
"type": "array",
@@ -40,4 +50,4 @@
}
},
"additionalProperties": false
-}
+} \ No newline at end of file
diff --git a/spec/fixtures/api/schemas/entities/protected_ref_access.json b/spec/fixtures/api/schemas/entities/protected_ref_access.json
new file mode 100644
index 00000000000..144852e1558
--- /dev/null
+++ b/spec/fixtures/api/schemas/entities/protected_ref_access.json
@@ -0,0 +1,25 @@
+{
+ "type": "object",
+ "required": [
+ "id",
+ "access_level",
+ "access_level_description"
+ ],
+ "properties": {
+ "id": {
+ "type": "integer"
+ },
+ "access_level": {
+ "type": [
+ "integer",
+ "null"
+ ]
+ },
+ "access_level_description": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ }
+}
diff --git a/spec/fixtures/api/schemas/graphql/packages/package_details.json b/spec/fixtures/api/schemas/graphql/packages/package_details.json
index 33eb67a0280..1f3de0e0ff5 100644
--- a/spec/fixtures/api/schemas/graphql/packages/package_details.json
+++ b/spec/fixtures/api/schemas/graphql/packages/package_details.json
@@ -14,7 +14,8 @@
"versions",
"status",
"canDestroy",
- "lastDownloadedAt"
+ "lastDownloadedAt",
+ "_links"
],
"properties": {
"id": {
@@ -177,6 +178,15 @@
},
"lastDownloadedAt": {
"type": ["string", "null"]
+ },
+ "_links": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "webPath": {
+ "type": ["string", "null"]
+ }
+ }
}
}
}
diff --git a/spec/fixtures/api/schemas/ml/run.json b/spec/fixtures/api/schemas/ml/run.json
index 2418f44b21f..48d0ed25ce4 100644
--- a/spec/fixtures/api/schemas/ml/run.json
+++ b/spec/fixtures/api/schemas/ml/run.json
@@ -27,15 +27,43 @@
"end_time"
],
"properties": {
- "run_id": { "type": "string" },
- "run_uuid": { "type": "string" },
- "experiment_id": { "type": "string" },
- "artifact_location": { "type": "string" },
- "start_time": { "type": "integer" },
- "end_time": { "type": "integer" },
+ "run_id": {
+ "type": "string"
+ },
+ "run_uuid": {
+ "type": "string"
+ },
+ "experiment_id": {
+ "type": "string"
+ },
+ "artifact_uri": {
+ "type": "string"
+ },
+ "start_time": {
+ "type": "integer"
+ },
+ "end_time": {
+ "type": "integer"
+ },
"user_id": "",
- "status": { "type": { "enum" : ["RUNNING", "SCHEDULED", "FINISHED", "FAILED", "KILLED"] } },
- "lifecycle_stage": { "type": { "enum" : ["active"] } }
+ "status": {
+ "type": {
+ "enum": [
+ "RUNNING",
+ "SCHEDULED",
+ "FINISHED",
+ "FAILED",
+ "KILLED"
+ ]
+ }
+ },
+ "lifecycle_stage": {
+ "type": {
+ "enum": [
+ "active"
+ ]
+ }
+ }
}
},
"data": {
@@ -44,4 +72,4 @@
}
}
}
-}
+} \ No newline at end of file
diff --git a/spec/fixtures/api/schemas/pipeline_schedule_variable.json b/spec/fixtures/api/schemas/pipeline_schedule_variable.json
index 022d36cb88c..83eed11f458 100644
--- a/spec/fixtures/api/schemas/pipeline_schedule_variable.json
+++ b/spec/fixtures/api/schemas/pipeline_schedule_variable.json
@@ -6,9 +6,18 @@
"variable_type"
],
"properties": {
- "key": { "type": "string" },
- "value": { "type": "string" },
- "variable_type": { "type": "string" }
+ "key": {
+ "type": "string"
+ },
+ "value": {
+ "type": "string"
+ },
+ "variable_type": {
+ "type": "string"
+ },
+ "raw": {
+ "type": "boolean"
+ }
},
"additionalProperties": false
-}
+} \ No newline at end of file
diff --git a/spec/fixtures/api/schemas/project_mirror.json b/spec/fixtures/api/schemas/project_mirror.json
new file mode 100644
index 00000000000..0f626c04f24
--- /dev/null
+++ b/spec/fixtures/api/schemas/project_mirror.json
@@ -0,0 +1,48 @@
+{
+ "type": "object",
+ "required": [
+ "id",
+ "url",
+ "update_status",
+ "last_update_at",
+ "last_update_started_at",
+ "last_successful_update_at",
+ "last_error"
+ ],
+ "properties": {
+ "id": {
+ "type": "integer"
+ },
+ "url": {
+ "type": "string"
+ },
+ "update_status": {
+ "type": "string"
+ },
+ "last_update_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "last_update_started_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "last_successful_update_at": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "last_error": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
+ },
+ "additionalProperties": false
+} \ No newline at end of file
diff --git a/spec/fixtures/api/schemas/protected_branch.json b/spec/fixtures/api/schemas/protected_branch.json
new file mode 100644
index 00000000000..4ad5dbe2313
--- /dev/null
+++ b/spec/fixtures/api/schemas/protected_branch.json
@@ -0,0 +1,33 @@
+{
+ "type": "object",
+ "required": [
+ "id",
+ "name",
+ "push_access_levels",
+ "merge_access_levels",
+ "allow_force_push"
+ ],
+ "properties": {
+ "id": {
+ "type": "integer"
+ },
+ "name": {
+ "type": "string"
+ },
+ "push_access_levels": {
+ "type": "array",
+ "items": {
+ "$ref": "entities/protected_ref_access.json"
+ }
+ },
+ "merge_access_levels": {
+ "type": "array",
+ "items": {
+ "$ref": "entities/protected_ref_access.json"
+ }
+ },
+ "allow_force_push": {
+ "type": "boolean"
+ }
+ }
+}
diff --git a/spec/fixtures/api/schemas/protected_branches.json b/spec/fixtures/api/schemas/protected_branches.json
new file mode 100644
index 00000000000..c87b3b153a9
--- /dev/null
+++ b/spec/fixtures/api/schemas/protected_branches.json
@@ -0,0 +1,6 @@
+{
+ "type": "array",
+ "items": {
+ "$ref": "protected_branch.json"
+ }
+}
diff --git a/spec/fixtures/api/schemas/protected_tag.json b/spec/fixtures/api/schemas/protected_tag.json
new file mode 100644
index 00000000000..c5aaf0f0cba
--- /dev/null
+++ b/spec/fixtures/api/schemas/protected_tag.json
@@ -0,0 +1,19 @@
+{
+ "type": "object",
+ "required": [
+ "name",
+ "create_access_levels"
+ ],
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "create_access_levels": {
+ "type": "array",
+ "items": {
+ "$ref": "entities/protected_ref_access.json"
+ }
+ },
+ "additionalProperties": false
+ }
+}
diff --git a/spec/fixtures/api/schemas/protected_tags.json b/spec/fixtures/api/schemas/protected_tags.json
new file mode 100644
index 00000000000..731d0368a09
--- /dev/null
+++ b/spec/fixtures/api/schemas/protected_tags.json
@@ -0,0 +1,6 @@
+{
+ "type": "array",
+ "items": {
+ "$ref": "protected_tag.json"
+ }
+}
diff --git a/spec/fixtures/api/schemas/public_api/v4/metadata.json b/spec/fixtures/api/schemas/public_api/v4/metadata.json
index fd219b95df8..f5a6aa86890 100644
--- a/spec/fixtures/api/schemas/public_api/v4/metadata.json
+++ b/spec/fixtures/api/schemas/public_api/v4/metadata.json
@@ -3,11 +3,16 @@
"required": [
"version",
"revision",
- "kas"
+ "kas",
+ "enterprise"
],
"properties": {
- "version": { "type": "string" },
- "revision": { "type": "string" },
+ "version": {
+ "type": "string"
+ },
+ "revision": {
+ "type": "string"
+ },
"kas": {
"type": "object",
"required": [
@@ -16,11 +21,26 @@
"version"
],
"properties": {
- "enabled": { "type": "boolean" },
- "externalUrl": { "type": ["string", "null"] },
- "version": { "type": ["string", "null"] }
+ "enabled": {
+ "type": "boolean"
+ },
+ "externalUrl": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "version": {
+ "type": [
+ "string",
+ "null"
+ ]
+ }
}
+ },
+ "enterprise": {
+ "type": "boolean"
}
},
"additionalProperties": false
-}
+} \ No newline at end of file
diff --git a/spec/fixtures/gitlab/import_export/project.tar.gz b/spec/fixtures/gitlab/import_export/project.tar.gz
new file mode 100644
index 00000000000..eec5d6f66ce
--- /dev/null
+++ b/spec/fixtures/gitlab/import_export/project.tar.gz
Binary files differ
diff --git a/spec/fixtures/gitlab/import_export/uploads.tar.gz b/spec/fixtures/gitlab/import_export/uploads.tar.gz
new file mode 100644
index 00000000000..3f1aa18c113
--- /dev/null
+++ b/spec/fixtures/gitlab/import_export/uploads.tar.gz
Binary files differ
diff --git a/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric.yml b/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric.yml
index a5bdd378f53..520328f1041 100644
--- a/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric.yml
+++ b/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric.yml
@@ -14,7 +14,7 @@ time_frame: 7d
data_source:
data_category: operational
instrumentation_class: Count
-performance_indicator_type:
+performance_indicator_type: []
distribution:
- ce
# Add here corresponding tiers
diff --git a/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_ee.yml b/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_ee.yml
index 4931285f6cf..1942f33e043 100644
--- a/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_ee.yml
+++ b/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_ee.yml
@@ -14,7 +14,7 @@ time_frame: 7d
data_source:
data_category: optional
instrumentation_class: Count
-performance_indicator_type:
+performance_indicator_type: []
distribution:
- ee
tier:
diff --git a/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_name_suggestions.yml b/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_name_suggestions.yml
index 39472af686d..a72ba5109cc 100644
--- a/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_name_suggestions.yml
+++ b/spec/fixtures/lib/generators/gitlab/usage_metric_definition_generator/sample_metric_with_name_suggestions.yml
@@ -15,7 +15,7 @@ time_frame: 7d
data_source:
data_category: optional
instrumentation_class: Count
-performance_indicator_type:
+performance_indicator_type: []
distribution:
- ce
- ee
diff --git a/spec/fixtures/lib/gitlab/import_export/complex/project.json b/spec/fixtures/lib/gitlab/import_export/complex/project.json
index a03177ba85e..8e7cb487444 100644
--- a/spec/fixtures/lib/gitlab/import_export/complex/project.json
+++ b/spec/fixtures/lib/gitlab/import_export/complex/project.json
@@ -6961,7 +6961,7 @@
"id": 2,
"pipeline_id": 36,
"project_id": 5,
- "title": "Build pipeline"
+ "name": "Build pipeline"
},
"notes": [
{
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 0c19f23cc24..cadaa5abfcd 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, "title": "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":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":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/sbom/package-url-test-cases.json b/spec/fixtures/lib/sbom/package-url-test-cases.json
new file mode 100644
index 00000000000..448387397f6
--- /dev/null
+++ b/spec/fixtures/lib/sbom/package-url-test-cases.json
@@ -0,0 +1,502 @@
+[
+ {
+ "description": "valid maven purl",
+ "purl": "pkg:maven/org.apache.commons/io@1.3.4",
+ "canonical_purl": "pkg:maven/org.apache.commons/io@1.3.4",
+ "type": "maven",
+ "namespace": "org.apache.commons",
+ "name": "io",
+ "version": "1.3.4",
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "basic valid maven purl without version",
+ "purl": "pkg:maven/org.apache.commons/io",
+ "canonical_purl": "pkg:maven/org.apache.commons/io",
+ "type": "maven",
+ "namespace": "org.apache.commons",
+ "name": "io",
+ "version": null,
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "valid go purl without version and with subpath",
+ "purl": "pkg:GOLANG/google.golang.org/genproto#/googleapis/api/annotations/",
+ "canonical_purl": "pkg:golang/google.golang.org/genproto#googleapis/api/annotations",
+ "type": "golang",
+ "namespace": "google.golang.org",
+ "name": "genproto",
+ "version": null,
+ "qualifiers": null,
+ "subpath": "googleapis/api/annotations",
+ "is_invalid": false
+ },
+ {
+ "description": "valid go purl with version and subpath",
+ "purl": "pkg:GOLANG/google.golang.org/genproto@abcdedf#/googleapis/api/annotations/",
+ "canonical_purl": "pkg:golang/google.golang.org/genproto@abcdedf#googleapis/api/annotations",
+ "type": "golang",
+ "namespace": "google.golang.org",
+ "name": "genproto",
+ "version": "abcdedf",
+ "qualifiers": null,
+ "subpath": "googleapis/api/annotations",
+ "is_invalid": false
+ },
+ {
+ "description": "bitbucket namespace and name should be lowercased",
+ "purl": "pkg:bitbucket/birKenfeld/pyGments-main@244fd47e07d1014f0aed9c",
+ "canonical_purl": "pkg:bitbucket/birkenfeld/pygments-main@244fd47e07d1014f0aed9c",
+ "type": "bitbucket",
+ "namespace": "birkenfeld",
+ "name": "pygments-main",
+ "version": "244fd47e07d1014f0aed9c",
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "github namespace and name should be lowercased",
+ "purl": "pkg:github/Package-url/purl-Spec@244fd47e07d1004f0aed9c",
+ "canonical_purl": "pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c",
+ "type": "github",
+ "namespace": "package-url",
+ "name": "purl-spec",
+ "version": "244fd47e07d1004f0aed9c",
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "debian can use qualifiers",
+ "purl": "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie",
+ "canonical_purl": "pkg:deb/debian/curl@7.50.3-1?arch=i386&distro=jessie",
+ "type": "deb",
+ "namespace": "debian",
+ "name": "curl",
+ "version": "7.50.3-1",
+ "qualifiers": {
+ "arch": "i386",
+ "distro": "jessie"
+ },
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "docker uses qualifiers and hash image id as versions",
+ "purl": "pkg:docker/customer/dockerimage@sha256:244fd47e07d1004f0aed9c?repository_url=gcr.io",
+ "canonical_purl": "pkg:docker/customer/dockerimage@sha256%3A244fd47e07d1004f0aed9c?repository_url=gcr.io",
+ "type": "docker",
+ "namespace": "customer",
+ "name": "dockerimage",
+ "version": "sha256:244fd47e07d1004f0aed9c",
+ "qualifiers": {
+ "repository_url": "gcr.io"
+ },
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "Java gem can use a qualifier",
+ "purl": "pkg:gem/jruby-launcher@1.1.2?Platform=java",
+ "canonical_purl": "pkg:gem/jruby-launcher@1.1.2?platform=java",
+ "type": "gem",
+ "namespace": null,
+ "name": "jruby-launcher",
+ "version": "1.1.2",
+ "qualifiers": {
+ "platform": "java"
+ },
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "maven often uses qualifiers",
+ "purl": "pkg:Maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources&repositorY_url=repo.spring.io/release",
+ "canonical_purl": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?classifier=sources&repository_url=repo.spring.io%2Frelease",
+ "type": "maven",
+ "namespace": "org.apache.xmlgraphics",
+ "name": "batik-anim",
+ "version": "1.9.1",
+ "qualifiers": {
+ "classifier": "sources",
+ "repository_url": "repo.spring.io/release"
+ },
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "maven pom reference",
+ "purl": "pkg:Maven/org.apache.xmlgraphics/batik-anim@1.9.1?extension=pom&repositorY_url=repo.spring.io/release",
+ "canonical_purl": "pkg:maven/org.apache.xmlgraphics/batik-anim@1.9.1?extension=pom&repository_url=repo.spring.io%2Frelease",
+ "type": "maven",
+ "namespace": "org.apache.xmlgraphics",
+ "name": "batik-anim",
+ "version": "1.9.1",
+ "qualifiers": {
+ "extension": "pom",
+ "repository_url": "repo.spring.io/release"
+ },
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "maven can come with a type qualifier",
+ "purl": "pkg:Maven/net.sf.jacob-project/jacob@1.14.3?classifier=x86&type=dll",
+ "canonical_purl": "pkg:maven/net.sf.jacob-project/jacob@1.14.3?classifier=x86&type=dll",
+ "type": "maven",
+ "namespace": "net.sf.jacob-project",
+ "name": "jacob",
+ "version": "1.14.3",
+ "qualifiers": {
+ "classifier": "x86",
+ "type": "dll"
+ },
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "npm can be scoped",
+ "purl": "pkg:npm/%40angular/animation@12.3.1",
+ "canonical_purl": "pkg:npm/%40angular/animation@12.3.1",
+ "type": "npm",
+ "namespace": "@angular",
+ "name": "animation",
+ "version": "12.3.1",
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "nuget names are case sensitive",
+ "purl": "pkg:Nuget/EnterpriseLibrary.Common@6.0.1304",
+ "canonical_purl": "pkg:nuget/EnterpriseLibrary.Common@6.0.1304",
+ "type": "nuget",
+ "namespace": null,
+ "name": "EnterpriseLibrary.Common",
+ "version": "6.0.1304",
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "pypi names have special rules and not case sensitive",
+ "purl": "pkg:PYPI/Django_package@1.11.1.dev1",
+ "canonical_purl": "pkg:pypi/django-package@1.11.1.dev1",
+ "type": "pypi",
+ "namespace": null,
+ "name": "django-package",
+ "version": "1.11.1.dev1",
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "rpm often use qualifiers",
+ "purl": "pkg:Rpm/fedora/curl@7.50.3-1.fc25?Arch=i386&Distro=fedora-25",
+ "canonical_purl": "pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25",
+ "type": "rpm",
+ "namespace": "fedora",
+ "name": "curl",
+ "version": "7.50.3-1.fc25",
+ "qualifiers": {
+ "arch": "i386",
+ "distro": "fedora-25"
+ },
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "a scheme is always required",
+ "purl": "EnterpriseLibrary.Common@6.0.1304",
+ "canonical_purl": "EnterpriseLibrary.Common@6.0.1304",
+ "type": null,
+ "namespace": null,
+ "name": "EnterpriseLibrary.Common",
+ "version": null,
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": true
+ },
+ {
+ "description": "a type is always required",
+ "purl": "pkg:EnterpriseLibrary.Common@6.0.1304",
+ "canonical_purl": "pkg:EnterpriseLibrary.Common@6.0.1304",
+ "type": null,
+ "namespace": null,
+ "name": "EnterpriseLibrary.Common",
+ "version": null,
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": true
+ },
+ {
+ "description": "a name is required",
+ "purl": "pkg:maven/@1.3.4",
+ "canonical_purl": "pkg:maven/@1.3.4",
+ "type": "maven",
+ "namespace": null,
+ "name": null,
+ "version": null,
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": true
+ },
+ {
+ "description": "slash / after scheme is not significant",
+ "purl": "pkg:/maven/org.apache.commons/io",
+ "canonical_purl": "pkg:maven/org.apache.commons/io",
+ "type": "maven",
+ "namespace": "org.apache.commons",
+ "name": "io",
+ "version": null,
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "double slash // after scheme is not significant",
+ "purl": "pkg://maven/org.apache.commons/io",
+ "canonical_purl": "pkg:maven/org.apache.commons/io",
+ "type": "maven",
+ "namespace": "org.apache.commons",
+ "name": "io",
+ "version": null,
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "slash /// after type is not significant",
+ "purl": "pkg:///maven/org.apache.commons/io",
+ "canonical_purl": "pkg:maven/org.apache.commons/io",
+ "type": "maven",
+ "namespace": "org.apache.commons",
+ "name": "io",
+ "version": null,
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "valid maven purl with case sensitive namespace and name",
+ "purl": "pkg:maven/HTTPClient/HTTPClient@0.3-3",
+ "canonical_purl": "pkg:maven/HTTPClient/HTTPClient@0.3-3",
+ "type": "maven",
+ "namespace": "HTTPClient",
+ "name": "HTTPClient",
+ "version": "0.3-3",
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "valid maven purl containing a space in the version and qualifier",
+ "purl": "pkg:maven/mygroup/myartifact@1.0.0%20Final?mykey=my%20value",
+ "canonical_purl": "pkg:maven/mygroup/myartifact@1.0.0+Final?mykey=my+value",
+ "type": "maven",
+ "namespace": "mygroup",
+ "name": "myartifact",
+ "version": "1.0.0 Final",
+ "qualifiers": {
+ "mykey": "my value"
+ },
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "checks for invalid qualifier keys",
+ "purl": "pkg:npm/myartifact@1.0.0?in%20production=true",
+ "canonical_purl": null,
+ "type": "npm",
+ "namespace": null,
+ "name": "myartifact",
+ "version": "1.0.0",
+ "qualifiers": {
+ "in production": "true"
+ },
+ "subpath": null,
+ "is_invalid": true
+ },
+ {
+ "description": "valid conan purl",
+ "purl": "pkg:conan/cctz@2.3",
+ "canonical_purl": "pkg:conan/cctz@2.3",
+ "type": "conan",
+ "namespace": null,
+ "name": "cctz",
+ "version": "2.3",
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "valid conan purl with namespace and qualifier channel",
+ "purl": "pkg:conan/bincrafters/cctz@2.3?channel=stable",
+ "canonical_purl": "pkg:conan/bincrafters/cctz@2.3?channel=stable",
+ "type": "conan",
+ "namespace": "bincrafters",
+ "name": "cctz",
+ "version": "2.3",
+ "qualifiers": {
+ "channel": "stable"
+ },
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "invalid conan purl only namespace",
+ "purl": "pkg:conan/bincrafters/cctz@2.3",
+ "canonical_purl": "pkg:conan/bincrafters/cctz@2.3",
+ "type": "conan",
+ "namespace": "bincrafters",
+ "name": "cctz",
+ "version": "2.3",
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": true
+ },
+ {
+ "description": "invalid conan purl only channel qualifier",
+ "purl": "pkg:conan/cctz@2.3?channel=stable",
+ "canonical_purl": "pkg:conan/cctz@2.3?channel=stable",
+ "type": "conan",
+ "namespace": null,
+ "name": "cctz",
+ "version": "2.3",
+ "qualifiers": {
+ "channel": "stable"
+ },
+ "subpath": null,
+ "is_invalid": true
+ },
+ {
+ "description": "valid conda purl with qualifiers",
+ "purl": "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2",
+ "canonical_purl": "pkg:conda/absl-py@0.4.1?build=py36h06a4308_0&channel=main&subdir=linux-64&type=tar.bz2",
+ "type": "conda",
+ "namespace": null,
+ "name": "absl-py",
+ "version": "0.4.1",
+ "qualifiers": {
+ "build": "py36h06a4308_0",
+ "channel": "main",
+ "subdir": "linux-64",
+ "type": "tar.bz2"
+ },
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "valid cran purl",
+ "purl": "pkg:cran/A3@0.9.1",
+ "canonical_purl": "pkg:cran/A3@0.9.1",
+ "type": "cran",
+ "namespace": null,
+ "name": "A3",
+ "version": "0.9.1",
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "invalid cran purl without name",
+ "purl": "pkg:cran/@0.9.1",
+ "canonical_purl": "pkg:cran/@0.9.1",
+ "type": "cran",
+ "namespace": null,
+ "name": null,
+ "version": "0.9.1",
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": true
+ },
+ {
+ "description": "invalid cran purl without version",
+ "purl": "pkg:cran/A3",
+ "canonical_purl": "pkg:cran/A3",
+ "type": "cran",
+ "namespace": null,
+ "name": "A3",
+ "version": null,
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": true
+ },
+ {
+ "description": "valid swift purl",
+ "purl": "pkg:swift/github.com/Alamofire/Alamofire@5.4.3",
+ "canonical_purl": "pkg:swift/github.com/Alamofire/Alamofire@5.4.3",
+ "type": "swift",
+ "namespace": "github.com/Alamofire",
+ "name": "Alamofire",
+ "version": "5.4.3",
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "invalid swift purl without namespace",
+ "purl": "pkg:swift/Alamofire@5.4.3",
+ "canonical_purl": "pkg:swift/Alamofire@5.4.3",
+ "type": "swift",
+ "namespace": null,
+ "name": "Alamofire",
+ "version": "5.4.3",
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": true
+ },
+ {
+ "description": "invalid swift purl without name",
+ "purl": "pkg:swift/github.com/Alamofire/@5.4.3",
+ "canonical_purl": "pkg:swift/github.com/Alamofire/@5.4.3",
+ "type": "swift",
+ "namespace": "github.com/Alamofire",
+ "name": null,
+ "version": "5.4.3",
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": true
+ },
+ {
+ "description": "invalid swift purl without version",
+ "purl": "pkg:swift/github.com/Alamofire/Alamofire",
+ "canonical_purl": "pkg:swift/github.com/Alamofire/Alamofire",
+ "type": "swift",
+ "namespace": "github.com/Alamofire",
+ "name": "Alamofire",
+ "version": null,
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": true
+ },
+ {
+ "description": "valid hackage purl",
+ "purl": "pkg:hackage/AC-HalfInteger@1.2.1",
+ "canonical_purl": "pkg:hackage/AC-HalfInteger@1.2.1",
+ "type": "hackage",
+ "namespace": null,
+ "name": "AC-HalfInteger",
+ "version": "1.2.1",
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": false
+ },
+ {
+ "description": "name and version are always required",
+ "purl": "pkg:hackage",
+ "canonical_purl": "pkg:hackage",
+ "type": "hackage",
+ "namespace": null,
+ "name": null,
+ "version": null,
+ "qualifiers": null,
+ "subpath": null,
+ "is_invalid": true
+ }
+] \ No newline at end of file
diff --git a/spec/fixtures/markdown/markdown_golden_master_examples.yml b/spec/fixtures/markdown/markdown_golden_master_examples.yml
index 6a1e75348cf..0c7e6ab5cd2 100644
--- a/spec/fixtures/markdown/markdown_golden_master_examples.yml
+++ b/spec/fixtures/markdown/markdown_golden_master_examples.yml
@@ -297,7 +297,7 @@
```
html: |-
<div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-javascript" lang="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="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>
<copy-code></copy-code>
</div>
@@ -308,7 +308,7 @@
```
html: |-
<div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> plaintext</span></code></pre>
+ <pre data-sourcepos="1:1-3:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> plaintext</span></code></pre>
<copy-code></copy-code>
</div>
@@ -319,7 +319,7 @@
```
html: |-
<div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="foobar" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> custom_language = &gt;&gt; this &lt;&lt;</span></code></pre>
+ <pre data-sourcepos="1:1-3:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="foobar" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"> custom_language = &gt;&gt; this &lt;&lt;</span></code></pre>
<copy-code></copy-code>
</div>
@@ -531,7 +531,7 @@
;;;
html: |-
<div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-5:3" class="code highlight js-syntax-highlight language-json" lang="json" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="json"><span class="p">{</span></span>
+ <pre data-sourcepos="1:1-5:3" lang="json" class="code highlight js-syntax-highlight language-json" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="json"><span class="p">{</span></span>
<span id="LC2" class="line" lang="json"><span class="w"> </span><span class="nl">"title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Page title"</span></span>
<span id="LC3" class="line" lang="json"><span class="p">}</span></span></code></pre>
<copy-code></copy-code>
@@ -544,7 +544,7 @@
+++
html: |-
<div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-toml" lang="toml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="toml"><span class="py">title</span> <span class="p">=</span> <span class="s">"Page title"</span></span></code></pre>
+ <pre data-sourcepos="1:1-3:3" lang="toml" class="code highlight js-syntax-highlight language-toml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="toml"><span class="py">title</span> <span class="p">=</span> <span class="s">"Page title"</span></span></code></pre>
<copy-code></copy-code>
</div>
@@ -555,7 +555,7 @@
---
html: |-
<div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-yaml" lang="yaml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="yaml"><span class="na">title</span><span class="pi">:</span> <span class="s">Page title</span></span></code></pre>
+ <pre data-sourcepos="1:1-3:3" lang="yaml" class="code highlight js-syntax-highlight language-yaml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="yaml"><span class="na">title</span><span class="pi">:</span> <span class="s">Page title</span></span></code></pre>
<copy-code></copy-code>
</div>
@@ -690,7 +690,7 @@
<p data-sourcepos="1:1-1:36" dir="auto">This math is inline <code class="code math js-render-math" data-math-style="inline">a^2+b^2=c^2</code>.</p>
<p data-sourcepos="3:1-3:27" dir="auto">This is on a separate line:</p>
<div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="5:1-7:3" class="code highlight js-syntax-highlight language-math js-render-math" lang="math" v-pre="true" data-math-style="display"><code><span id="LC1" class="line" lang="math">a^2+b^2=c^2</span></code></pre>
+ <pre data-sourcepos="5:1-7:3" lang="math" data-math-style="display" class="js-render-math code highlight js-syntax-highlight language-math" v-pre="true"><code><span id="LC1" class="line" lang="math">a^2+b^2=c^2</span></code></pre>
<copy-code></copy-code>
</div>
diff --git a/spec/fixtures/packages/rpm/payload.json b/spec/fixtures/packages/rpm/payload.json
index 0240dbaca21..ef948c0bb6f 100644
--- a/spec/fixtures/packages/rpm/payload.json
+++ b/spec/fixtures/packages/rpm/payload.json
@@ -1,11 +1,23 @@
{
"files": [
- "/usr/bin/hello.sh"
+ "/usr/bin/test",
+ "/usr/bin/test/hello.sh"
+ ],
+ "directories": [
+ "/usr/bin/test/"
],
"changelogs": [
{
"changelogtext": "First build",
"changelogtime": 1662552000
+ },
+ {
+ "changelogtext": "Next build",
+ "changelogtime": 1662552123
+ },
+ {
+ "changelogtext": "Last build",
+ "changelogtime": 1662552321
}
],
"requirements": [
@@ -43,5 +55,7 @@
"group": "Unspecified",
"buildhost": "localhost",
"packager": null,
- "vendor": null
+ "vendor": null,
+ "pkgid": "qwe123wer234ert345",
+ "epoch": "1"
} \ No newline at end of file
diff --git a/spec/fixtures/packages/rpm/repodata/364c77dd49e8f814d56e621d0b3306c4fd0696dcad506f527329b818eb0f5db3-repomd.xml b/spec/fixtures/packages/rpm/repodata/364c77dd49e8f814d56e621d0b3306c4fd0696dcad506f527329b818eb0f5db3-repomd.xml
new file mode 100644
index 00000000000..177a9be4723
--- /dev/null
+++ b/spec/fixtures/packages/rpm/repodata/364c77dd49e8f814d56e621d0b3306c4fd0696dcad506f527329b818eb0f5db3-repomd.xml
@@ -0,0 +1,30 @@
+<repomd
+ xmlns="http://gitlab.com/api/v4/projects/1/packages/rpm/repodata/364c77dd49e8f814d56e621d0b3306c4fd0696dcad506f527329b818eb0f5db3-repomd.xml"
+ xmlns:rpm="http://gitlab.com/api/v4/projects/1/packages/rpm/repodata/364c77dd49e8f814d56e621d0b3306c4fd0696dcad506f527329b818eb0f5db3-repomd.xml"
+>
+ <revision>1644602779</revision>
+ <data type="filelists">
+ <checksum type="sha256">6503673de76312406ff8ecb06d9733c32b546a65abae4d4170d9b51fb75bf253</checksum>
+ <open-checksum type="sha256">7652c7496daa2507f08675a5b4f59a5428aaba72997400ae3d5e7bab8e3d9cc1</open-checksum>
+ <location href="repodata/6503673de76312406ff8ecb06d9733c32b546a65abae4d4170d9b51fb75bf253-filelists.xml"/>
+ <timestamp>1644602784</timestamp>
+ <size>1144067</size>
+ <open-size>25734004</open-size>
+ </data>
+ <data type="primary">
+ <checksum type="sha256">80279a863b6236e60c3e63036b8a9a25e3764dfb3121292b91e9f583af9e7b7e</checksum>
+ <open-checksum type="sha256">f852f3bb39f89520434d97f6913716dc448077ad49f2e5200327367f98a89d55</open-checksum>
+ <location href="repodata/80279a863b6236e60c3e63036b8a9a25e3764dfb3121292b91e9f583af9e7b7e-primary.xml"/>
+ <timestamp>1644602784</timestamp>
+ <size>66996</size>
+ <open-size>1008586</open-size>
+ </data>
+ <data type="other">
+ <checksum type="sha256">34408890500ec72c0f181542a91f7ff9320d2ef32c8e613540a5b9e1b8763e02</checksum>
+ <open-checksum type="sha256">acac5033036264cd26100713b014242471ade45487c28c7793466a84af512624</open-checksum>
+ <location href="repodata/34408890500ec72c0f181542a91f7ff9320d2ef32c8e613540a5b9e1b8763e02-other.xml"/>
+ <timestamp>1644602784</timestamp>
+ <size>43329</size>
+ <open-size>730393</open-size>
+ </data>
+</repomd>
diff --git a/spec/fixtures/packages/rpm/repodata/repomd.xml b/spec/fixtures/packages/rpm/repodata/repomd.xml
deleted file mode 100644
index 4554ee9a6d0..00000000000
--- a/spec/fixtures/packages/rpm/repodata/repomd.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<repomd xmlns="http://gitlab.com/api/v4/projects/1/packages/rpm/repodata/repomd.xml" xmlns:rpm="http://gitlab.com/api/v4/projects/1/packages/rpm/repodata/repomd.xml">
- <revision>1644602779</revision>
- <data type="filelists">
- <checksum type="sha256">6503673de76312406ff8ecb06d9733c32b546a65abae4d4170d9b51fb75bf253</checksum>
- <open-checksum type="sha256">7652c7496daa2507f08675a5b4f59a5428aaba72997400ae3d5e7bab8e3d9cc1</open-checksum>
- <location href="repodata/6503673de76312406ff8ecb06d9733c32b546a65abae4d4170d9b51fb75bf253-filelists.xml"/>
- <timestamp>1644602784</timestamp>
- <size>1144067</size>
- <open-size>25734004</open-size>
- </data>
- <data type="primary">
- <checksum type="sha256">80279a863b6236e60c3e63036b8a9a25e3764dfb3121292b91e9f583af9e7b7e</checksum>
- <open-checksum type="sha256">f852f3bb39f89520434d97f6913716dc448077ad49f2e5200327367f98a89d55</open-checksum>
- <location href="repodata/80279a863b6236e60c3e63036b8a9a25e3764dfb3121292b91e9f583af9e7b7e-primary.xml"/>
- <timestamp>1644602784</timestamp>
- <size>66996</size>
- <open-size>1008586</open-size>
- </data>
- <data type="other">
- <checksum type="sha256">34408890500ec72c0f181542a91f7ff9320d2ef32c8e613540a5b9e1b8763e02</checksum>
- <open-checksum type="sha256">acac5033036264cd26100713b014242471ade45487c28c7793466a84af512624</open-checksum>
- <location href="repodata/34408890500ec72c0f181542a91f7ff9320d2ef32c8e613540a5b9e1b8763e02-other.xml"/>
- <timestamp>1644602784</timestamp>
- <size>43329</size>
- <open-size>730393</open-size>
- </data>
-</repomd>
diff --git a/spec/frontend/__helpers__/raw_transformer.js b/spec/frontend/__helpers__/raw_transformer.js
new file mode 100644
index 00000000000..09101b7a64f
--- /dev/null
+++ b/spec/frontend/__helpers__/raw_transformer.js
@@ -0,0 +1,6 @@
+/* eslint-disable import/no-commonjs */
+module.exports = {
+ process: (content) => {
+ return `module.exports = ${JSON.stringify(content)}`;
+ },
+};
diff --git a/spec/frontend/access_tokens/components/__snapshots__/expires_at_field_spec.js.snap b/spec/frontend/access_tokens/components/__snapshots__/expires_at_field_spec.js.snap
index 2bd2b17a12d..42818c14029 100644
--- a/spec/frontend/access_tokens/components/__snapshots__/expires_at_field_spec.js.snap
+++ b/spec/frontend/access_tokens/components/__snapshots__/expires_at_field_spec.js.snap
@@ -21,6 +21,7 @@ exports[`~/access_tokens/components/expires_at_field should render datepicker wi
mindate="Mon Jul 06 2020 00:00:00 GMT+0000 (Greenwich Mean Time)"
placeholder="YYYY-MM-DD"
showclearbutton="true"
+ size="medium"
theme=""
/>
</gl-form-group-stub>
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 b4af11169ad..e4313bdfa26 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
@@ -73,7 +73,6 @@ describe('~/access_tokens/components/new_access_token_app', () => {
expect(InputCopyToggleVisibilityComponent.props('copyButtonTitle')).toBe(
sprintf(__('Copy %{accessTokenType}'), { accessTokenType }),
);
- expect(InputCopyToggleVisibilityComponent.props('initialVisibility')).toBe(true);
expect(InputCopyToggleVisibilityComponent.attributes('label')).toBe(
sprintf(__('Your new %{accessTokenType}'), { accessTokenType }),
);
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 411126d0c89..e6718f62b91 100644
--- a/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js
+++ b/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js
@@ -1,4 +1,4 @@
-import { GlButton, GlModal } from '@gitlab/ui';
+import { GlButton, GlModal, GlLink } from '@gitlab/ui';
import { within } from '@testing-library/dom';
import { shallowMount, mount, createWrapper } from '@vue/test-utils';
import { stubComponent } from 'helpers/stub_component';
@@ -36,6 +36,7 @@ describe('Signup Form', () => {
const findDenyListRawInputGroup = () => wrapper.findByTestId('domain-denylist-raw-input-group');
const findDenyListFileInputGroup = () => wrapper.findByTestId('domain-denylist-file-input-group');
const findUserCapInput = () => wrapper.findByTestId('user-cap-input');
+ const findUserCapFormGroup = () => wrapper.findByTestId('user-cap-form-group');
const findModal = () => wrapper.findComponent(GlModal);
afterEach(() => {
@@ -214,4 +215,19 @@ describe('Signup Form', () => {
});
});
});
+
+ describe('rendering help links within user cap description', () => {
+ beforeEach(() => {
+ mountComponent({ mountFn: mount });
+ });
+
+ it('renders projectSharingHelpLink and groupSharingHelpLink', () => {
+ const [projectSharingLink, groupSharingLink] = findUserCapFormGroup().findAllComponents(
+ GlLink,
+ ).wrappers;
+
+ expect(projectSharingLink.attributes('href')).toBe(mockData.projectSharingHelpLink);
+ expect(groupSharingLink.attributes('href')).toBe(mockData.groupSharingHelpLink);
+ });
+ });
});
diff --git a/spec/frontend/admin/signup_restrictions/mock_data.js b/spec/frontend/admin/signup_restrictions/mock_data.js
index 9e001e122a4..dd1ed317497 100644
--- a/spec/frontend/admin/signup_restrictions/mock_data.js
+++ b/spec/frontend/admin/signup_restrictions/mock_data.js
@@ -4,6 +4,7 @@ export const rawMockData = {
signupEnabled: 'true',
requireAdminApprovalAfterUserSignup: 'true',
sendUserConfirmationEmail: 'true',
+ emailConfirmationSetting: 'hard',
minimumPasswordLength: '8',
minimumPasswordLengthMin: '3',
minimumPasswordLengthMax: '10',
@@ -22,6 +23,8 @@ export const rawMockData = {
passwordLowercaseRequired: 'true',
passwordUppercaseRequired: 'true',
passwordSymbolRequired: 'true',
+ projectSharingHelpLink: 'project-sharing/help/link',
+ groupSharingHelpLink: 'group-sharing/help/link',
};
export const mockData = {
@@ -30,6 +33,7 @@ export const mockData = {
signupEnabled: true,
requireAdminApprovalAfterUserSignup: true,
sendUserConfirmationEmail: true,
+ emailConfirmationSetting: 'hard',
minimumPasswordLength: '8',
minimumPasswordLengthMin: '3',
minimumPasswordLengthMax: '10',
@@ -48,4 +52,6 @@ export const mockData = {
passwordLowercaseRequired: true,
passwordUppercaseRequired: true,
passwordSymbolRequired: true,
+ projectSharingHelpLink: 'project-sharing/help/link',
+ groupSharingHelpLink: 'group-sharing/help/link',
};
diff --git a/spec/frontend/admin/users/components/actions/actions_spec.js b/spec/frontend/admin/users/components/actions/actions_spec.js
index 4967753b91c..8e9652332c1 100644
--- a/spec/frontend/admin/users/components/actions/actions_spec.js
+++ b/spec/frontend/admin/users/components/actions/actions_spec.js
@@ -1,13 +1,13 @@
import { GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Actions from '~/admin/users/components/actions';
+import Delete from '~/admin/users/components/actions/delete.vue';
import eventHub, {
EVENT_OPEN_DELETE_USER_MODAL,
} from '~/admin/users/components/modals/delete_user_modal_event_hub';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
-import { OBSTACLE_TYPES } from '~/vue_shared/components/user_deletion_obstacles/constants';
-import { CONFIRMATION_ACTIONS, DELETE_ACTIONS } from '../../constants';
-import { paths } from '../../mock_data';
+import { CONFIRMATION_ACTIONS } from '../../constants';
+import { paths, userDeletionObstacles } from '../../mock_data';
describe('Action components', () => {
let wrapper;
@@ -41,40 +41,33 @@ describe('Action components', () => {
});
});
- describe('DELETE_ACTION_COMPONENTS', () => {
+ describe('DELETE', () => {
beforeEach(() => {
jest.spyOn(eventHub, '$emit').mockImplementation();
});
- const userDeletionObstacles = [
- { name: 'schedule1', type: OBSTACLE_TYPES.oncallSchedules },
- { name: 'policy1', type: OBSTACLE_TYPES.escalationPolicies },
- ];
-
- it.each(DELETE_ACTIONS)(
- 'renders a dropdown item that opens the delete user modal when clicked for "%s"',
- async (action) => {
- initComponent({
- component: Actions[capitalizeFirstCharacter(action)],
- props: {
- username: 'John Doe',
- paths,
- userDeletionObstacles,
- },
- });
+ it('renders a dropdown item that opens the delete user modal when Delete is clicked', async () => {
+ initComponent({
+ component: Delete,
+ props: {
+ username: 'John Doe',
+ userId: 1,
+ paths,
+ userDeletionObstacles,
+ },
+ });
- await findDropdownItem().vm.$emit('click');
+ await findDropdownItem().vm.$emit('click');
- expect(eventHub.$emit).toHaveBeenCalledWith(
- EVENT_OPEN_DELETE_USER_MODAL,
- expect.objectContaining({
- username: 'John Doe',
- blockPath: paths.block,
- deletePath: paths[action],
- userDeletionObstacles,
- }),
- );
- },
- );
+ expect(eventHub.$emit).toHaveBeenCalledWith(
+ EVENT_OPEN_DELETE_USER_MODAL,
+ expect.objectContaining({
+ username: 'John Doe',
+ blockPath: paths.block,
+ deletePath: paths.delete,
+ userDeletionObstacles,
+ }),
+ );
+ });
});
});
diff --git a/spec/frontend/admin/users/components/actions/delete_with_contributions_spec.js b/spec/frontend/admin/users/components/actions/delete_with_contributions_spec.js
new file mode 100644
index 00000000000..64a88aab2c2
--- /dev/null
+++ b/spec/frontend/admin/users/components/actions/delete_with_contributions_spec.js
@@ -0,0 +1,107 @@
+import { GlLoadingIcon } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import DeleteWithContributions from '~/admin/users/components/actions/delete_with_contributions.vue';
+import eventHub, {
+ EVENT_OPEN_DELETE_USER_MODAL,
+} from '~/admin/users/components/modals/delete_user_modal_event_hub';
+import { associationsCount } from '~/api/user_api';
+import {
+ paths,
+ associationsCount as associationsCountData,
+ userDeletionObstacles,
+} from '../../mock_data';
+
+jest.mock('~/admin/users/components/modals/delete_user_modal_event_hub', () => ({
+ ...jest.requireActual('~/admin/users/components/modals/delete_user_modal_event_hub'),
+ __esModule: true,
+ default: {
+ $emit: jest.fn(),
+ },
+}));
+
+jest.mock('~/api/user_api', () => ({
+ associationsCount: jest.fn(),
+}));
+
+describe('DeleteWithContributions', () => {
+ let wrapper;
+
+ const defaultPropsData = {
+ username: 'John Doe',
+ userId: 1,
+ paths,
+ userDeletionObstacles,
+ };
+
+ const createComponent = () => {
+ wrapper = mountExtended(DeleteWithContributions, { propsData: defaultPropsData });
+ };
+
+ describe('when action is clicked', () => {
+ describe('when API request is loading', () => {
+ beforeEach(() => {
+ associationsCount.mockReturnValueOnce(new Promise(() => {}));
+
+ createComponent();
+ });
+
+ it('displays loading icon and disables button', async () => {
+ await wrapper.trigger('click');
+
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
+ expect(wrapper.findByRole('menuitem').attributes()).toMatchObject({
+ disabled: 'disabled',
+ 'aria-busy': 'true',
+ });
+ });
+ });
+
+ describe('when API request is successful', () => {
+ beforeEach(() => {
+ associationsCount.mockResolvedValueOnce({
+ data: associationsCountData,
+ });
+
+ createComponent();
+ });
+
+ it('emits event with association counts', async () => {
+ await wrapper.trigger('click');
+ await waitForPromises();
+
+ expect(associationsCount).toHaveBeenCalledWith(defaultPropsData.userId);
+ expect(eventHub.$emit).toHaveBeenCalledWith(
+ EVENT_OPEN_DELETE_USER_MODAL,
+ expect.objectContaining({
+ associationsCount: associationsCountData,
+ username: defaultPropsData.username,
+ blockPath: paths.block,
+ deletePath: paths.deleteWithContributions,
+ userDeletionObstacles,
+ }),
+ );
+ });
+ });
+
+ describe('when API request is not successful', () => {
+ beforeEach(() => {
+ associationsCount.mockRejectedValueOnce();
+
+ createComponent();
+ });
+
+ it('emits event with error', async () => {
+ await wrapper.trigger('click');
+ await waitForPromises();
+
+ expect(eventHub.$emit).toHaveBeenCalledWith(
+ EVENT_OPEN_DELETE_USER_MODAL,
+ expect.objectContaining({
+ associationsCount: new Error(),
+ }),
+ );
+ });
+ });
+ });
+});
diff --git a/spec/frontend/admin/users/components/associations/__snapshots__/associations_list_item_spec.js.snap b/spec/frontend/admin/users/components/associations/__snapshots__/associations_list_item_spec.js.snap
new file mode 100644
index 00000000000..4237685e45c
--- /dev/null
+++ b/spec/frontend/admin/users/components/associations/__snapshots__/associations_list_item_spec.js.snap
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AssociationsListItem renders interpolated message in a \`li\` element 1`] = `"<li><strong>5</strong> groups</li>"`;
diff --git a/spec/frontend/admin/users/components/associations/__snapshots__/associations_list_spec.js.snap b/spec/frontend/admin/users/components/associations/__snapshots__/associations_list_spec.js.snap
new file mode 100644
index 00000000000..dc98d367af7
--- /dev/null
+++ b/spec/frontend/admin/users/components/associations/__snapshots__/associations_list_spec.js.snap
@@ -0,0 +1,34 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AssociationsList when counts are 0 does not render items 1`] = `""`;
+
+exports[`AssociationsList when counts are plural renders plural counts 1`] = `
+"<ul class=\\"gl-mb-5\\">
+ <li><strong>2</strong> groups</li>
+ <li><strong>3</strong> projects</li>
+ <li><strong>4</strong> issues</li>
+ <li><strong>5</strong> merge requests</li>
+</ul>"
+`;
+
+exports[`AssociationsList when counts are singular renders singular counts 1`] = `
+"<ul class=\\"gl-mb-5\\">
+ <li><strong>1</strong> group</li>
+ <li><strong>1</strong> project</li>
+ <li><strong>1</strong> issue</li>
+ <li><strong>1</strong> merge request</li>
+</ul>"
+`;
+
+exports[`AssociationsList when there is an error displays an alert 1`] = `
+"<div class=\\"gl-mb-5 gl-alert gl-alert-not-dismissible gl-alert-danger\\"><svg data-testid=\\"error-icon\\" role=\\"img\\" aria-hidden=\\"true\\" class=\\"gl-icon s16 gl-alert-icon gl-alert-icon-no-title\\">
+ <use href=\\"#error\\"></use>
+ </svg>
+ <div role=\\"alert\\" aria-live=\\"assertive\\" class=\\"gl-alert-content\\">
+ <!---->
+ <div class=\\"gl-alert-body\\">An error occurred while fetching this user's contributions, and the request cannot return the number of issues, merge requests, groups, and projects linked to this user. If you proceed with deleting the user, all their contributions will still be deleted.</div>
+ <!---->
+ </div>
+ <!---->
+</div>"
+`;
diff --git a/spec/frontend/admin/users/components/associations/associations_list_item_spec.js b/spec/frontend/admin/users/components/associations/associations_list_item_spec.js
new file mode 100644
index 00000000000..5126df12c24
--- /dev/null
+++ b/spec/frontend/admin/users/components/associations/associations_list_item_spec.js
@@ -0,0 +1,25 @@
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import AssociationsListItem from '~/admin/users/components/associations/associations_list_item.vue';
+import { n__ } from '~/locale';
+
+describe('AssociationsListItem', () => {
+ let wrapper;
+ const count = 5;
+
+ const createComponent = () => {
+ wrapper = mountExtended(AssociationsListItem, {
+ propsData: {
+ message: n__('%{count} group', '%{count} groups', count),
+ count,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders interpolated message in a `li` element', () => {
+ expect(wrapper.html()).toMatchSnapshot();
+ });
+});
diff --git a/spec/frontend/admin/users/components/associations/associations_list_spec.js b/spec/frontend/admin/users/components/associations/associations_list_spec.js
new file mode 100644
index 00000000000..d77a645111f
--- /dev/null
+++ b/spec/frontend/admin/users/components/associations/associations_list_spec.js
@@ -0,0 +1,78 @@
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import AssociationsList from '~/admin/users/components/associations/associations_list.vue';
+
+describe('AssociationsList', () => {
+ let wrapper;
+
+ const defaultPropsData = {
+ associationsCount: {
+ groups_count: 1,
+ projects_count: 1,
+ issues_count: 1,
+ merge_requests_count: 1,
+ },
+ };
+
+ const createComponent = ({ propsData = {} } = {}) => {
+ wrapper = mountExtended(AssociationsList, {
+ propsData: {
+ ...defaultPropsData,
+ ...propsData,
+ },
+ });
+ };
+
+ describe('when there is an error', () => {
+ it('displays an alert', () => {
+ createComponent({
+ propsData: {
+ associationsCount: new Error(),
+ },
+ });
+
+ expect(wrapper.html()).toMatchSnapshot();
+ });
+ });
+
+ describe('when counts are singular', () => {
+ it('renders singular counts', () => {
+ createComponent();
+
+ expect(wrapper.html()).toMatchSnapshot();
+ });
+ });
+
+ describe('when counts are plural', () => {
+ it('renders plural counts', () => {
+ createComponent({
+ propsData: {
+ associationsCount: {
+ groups_count: 2,
+ projects_count: 3,
+ issues_count: 4,
+ merge_requests_count: 5,
+ },
+ },
+ });
+
+ expect(wrapper.html()).toMatchSnapshot();
+ });
+ });
+
+ describe('when counts are 0', () => {
+ it('does not render items', () => {
+ createComponent({
+ propsData: {
+ associationsCount: {
+ groups_count: 0,
+ projects_count: 0,
+ issues_count: 0,
+ merge_requests_count: 0,
+ },
+ },
+ });
+
+ expect(wrapper.html()).toMatchSnapshot();
+ });
+ });
+});
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 70ed9eeb3e1..2e892e292d7 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
@@ -1,10 +1,12 @@
import { GlButton, GlFormInput, GlSprintf } from '@gitlab/ui';
+import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import eventHub, {
EVENT_OPEN_DELETE_USER_MODAL,
} from '~/admin/users/components/modals/delete_user_modal_event_hub';
import DeleteUserModal from '~/admin/users/components/modals/delete_user_modal.vue';
import UserDeletionObstaclesList from '~/vue_shared/components/user_deletion_obstacles/user_deletion_obstacles_list.vue';
+import AssociationsList from '~/admin/users/components/associations/associations_list.vue';
import ModalStub from './stubs/modal_stub';
const TEST_DELETE_USER_URL = 'delete-url';
@@ -200,4 +202,24 @@ describe('Delete user modal', () => {
expect(obstacles.props('obstacles')).toEqual(userDeletionObstacles);
});
});
+
+ it('renders `AssociationsList` component and passes `associationsCount` prop', async () => {
+ const associationsCount = {
+ groups_count: 5,
+ projects_count: 0,
+ issues_count: 5,
+ merge_requests_count: 5,
+ };
+
+ createComponent();
+ emitOpenModalEvent({
+ ...mockModalData,
+ associationsCount,
+ });
+ await nextTick();
+
+ expect(wrapper.findComponent(AssociationsList).props('associationsCount')).toEqual(
+ associationsCount,
+ );
+ });
});
diff --git a/spec/frontend/admin/users/components/user_actions_spec.js b/spec/frontend/admin/users/components/user_actions_spec.js
index ffc05e744c8..1b080b05c95 100644
--- a/spec/frontend/admin/users/components/user_actions_spec.js
+++ b/spec/frontend/admin/users/components/user_actions_spec.js
@@ -121,8 +121,11 @@ describe('AdminUserActions component', () => {
it.each(DELETE_ACTIONS)('renders a delete action component item for "%s"', (action) => {
const component = wrapper.findComponent(Actions[capitalizeFirstCharacter(action)]);
- expect(component.props('username')).toBe(user.name);
- expect(component.props('paths')).toEqual(userPaths);
+ expect(component.props()).toMatchObject({
+ username: user.name,
+ userId: user.id,
+ paths: userPaths,
+ });
expect(component.text()).toBe(I18N_USER_ACTIONS[action]);
});
});
diff --git a/spec/frontend/admin/users/mock_data.js b/spec/frontend/admin/users/mock_data.js
index 73fa73c0b47..193ac3fa043 100644
--- a/spec/frontend/admin/users/mock_data.js
+++ b/spec/frontend/admin/users/mock_data.js
@@ -1,3 +1,5 @@
+import { OBSTACLE_TYPES } from '~/vue_shared/components/user_deletion_obstacles/constants';
+
export const users = [
{
id: 2177,
@@ -48,3 +50,15 @@ export const createGroupCountResponse = (groupCounts) => ({
},
},
});
+
+export const associationsCount = {
+ groups_count: 5,
+ projects_count: 5,
+ issues_count: 5,
+ merge_requests_count: 5,
+};
+
+export const userDeletionObstacles = [
+ { name: 'schedule1', type: OBSTACLE_TYPES.oncallSchedules },
+ { name: 'policy1', type: OBSTACLE_TYPES.escalationPolicies },
+];
diff --git a/spec/frontend/analytics/shared/components/daterange_spec.js b/spec/frontend/analytics/shared/components/daterange_spec.js
index 7a09fe3319d..562e86529ee 100644
--- a/spec/frontend/analytics/shared/components/daterange_spec.js
+++ b/spec/frontend/analytics/shared/components/daterange_spec.js
@@ -77,7 +77,7 @@ describe('Daterange component', () => {
it('sets the tooltip', () => {
const tooltip = findDaterangePicker().props('tooltip');
expect(tooltip).toBe(
- 'Showing data for workflow items created in this date range. Date range limited to 30 days.',
+ 'Showing data for workflow items completed in this date range. Date range limited to 30 days.',
);
});
});
diff --git a/spec/frontend/api/groups_api_spec.js b/spec/frontend/api/groups_api_spec.js
index e14ead0b8eb..9de588a02aa 100644
--- a/spec/frontend/api/groups_api_spec.js
+++ b/spec/frontend/api/groups_api_spec.js
@@ -1,10 +1,13 @@
import MockAdapter from 'axios-mock-adapter';
+import getGroupTransferLocationsResponse from 'test_fixtures/api/groups/transfer_locations.json';
import httpStatus from '~/lib/utils/http_status';
import axios from '~/lib/utils/axios_utils';
-import { updateGroup } from '~/api/groups_api';
+import { DEFAULT_PER_PAGE } from '~/api';
+import { updateGroup, getGroupTransferLocations } from '~/api/groups_api';
const mockApiVersion = 'v4';
const mockUrlRoot = '/gitlab';
+const mockGroupId = '99';
describe('GroupsApi', () => {
let originalGon;
@@ -27,7 +30,6 @@ describe('GroupsApi', () => {
});
describe('updateGroup', () => {
- const mockGroupId = '99';
const mockData = { attr: 'value' };
const expectedUrl = `${mockUrlRoot}/api/${mockApiVersion}/groups/${mockGroupId}`;
@@ -43,4 +45,25 @@ describe('GroupsApi', () => {
expect(res.data).toMatchObject({ id: mockGroupId, ...mockData });
});
});
+
+ describe('getGroupTransferLocations', () => {
+ beforeEach(() => {
+ jest.spyOn(axios, 'get');
+ });
+
+ it('retrieves transfer locations from the correct URL and returns them in the response data', async () => {
+ const params = { page: 1 };
+ const expectedUrl = `${mockUrlRoot}/api/${mockApiVersion}/groups/${mockGroupId}/transfer_locations`;
+
+ mock.onGet(expectedUrl).replyOnce(200, { data: getGroupTransferLocationsResponse });
+
+ await expect(getGroupTransferLocations(mockGroupId, params)).resolves.toMatchObject({
+ data: { data: getGroupTransferLocationsResponse },
+ });
+
+ expect(axios.get).toHaveBeenCalledWith(expectedUrl, {
+ params: { ...params, per_page: DEFAULT_PER_PAGE },
+ });
+ });
+ });
});
diff --git a/spec/frontend/api/user_api_spec.js b/spec/frontend/api/user_api_spec.js
index ee7194bdf5f..ba6b73e8c1a 100644
--- a/spec/frontend/api/user_api_spec.js
+++ b/spec/frontend/api/user_api_spec.js
@@ -1,7 +1,8 @@
import MockAdapter from 'axios-mock-adapter';
-import { followUser, unfollowUser } from '~/api/user_api';
+import { followUser, unfollowUser, associationsCount } from '~/api/user_api';
import axios from '~/lib/utils/axios_utils';
+import { associationsCount as associationsCountData } from 'jest/admin/users/mock_data';
describe('~/api/user_api', () => {
let axiosMock;
@@ -47,4 +48,18 @@ describe('~/api/user_api', () => {
expect(axiosMock.history.post[0].url).toBe(expectedUrl);
});
});
+
+ describe('associationsCount', () => {
+ it('calls correct URL and returns expected response', async () => {
+ const expectedUrl = '/api/v4/users/1/associations_count';
+ const expectedResponse = { data: associationsCountData };
+
+ axiosMock.onGet(expectedUrl).replyOnce(200, expectedResponse);
+
+ await expect(associationsCount(1)).resolves.toEqual(
+ expect.objectContaining({ data: expectedResponse }),
+ );
+ expect(axiosMock.history.get[0].url).toBe(expectedUrl);
+ });
+ });
});
diff --git a/spec/frontend/artifacts/components/artifact_row_spec.js b/spec/frontend/artifacts/components/artifact_row_spec.js
new file mode 100644
index 00000000000..dcc0d684f13
--- /dev/null
+++ b/spec/frontend/artifacts/components/artifact_row_spec.js
@@ -0,0 +1,67 @@
+import { GlBadge, GlButton, GlFriendlyWrap } 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';
+
+describe('ArtifactRow component', () => {
+ let wrapper;
+
+ const artifact = mockGetJobArtifactsResponse.data.project.jobs.nodes[0].artifacts.nodes[0];
+
+ const findName = () => wrapper.findByTestId('job-artifact-row-name');
+ const findBadge = () => wrapper.findComponent(GlBadge);
+ 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 createComponent = (mountFn = shallowMountExtended) => {
+ wrapper = mountFn(ArtifactRow, {
+ propsData: {
+ artifact,
+ isLoading: false,
+ isLastRow: false,
+ },
+ stubs: { GlBadge, GlButton, GlFriendlyWrap },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('artifact details', () => {
+ beforeEach(async () => {
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('displays the artifact name and type', () => {
+ expect(findName().text()).toContain(artifact.name);
+ expect(findBadge().text()).toBe(artifact.fileType.toLowerCase());
+ });
+
+ it('displays the artifact size', () => {
+ expect(findSize().text()).toBe(numberToHumanSize(artifact.size));
+ });
+
+ it('displays the download button as a link to the download path', () => {
+ expect(findDownloadButton().attributes('href')).toBe(artifact.downloadPath);
+ });
+
+ it('displays the delete button', () => {
+ expect(findDeleteButton().exists()).toBe(true);
+ });
+
+ it('emits the delete event when the delete button is clicked', async () => {
+ expect(wrapper.emitted('delete')).toBeUndefined();
+
+ findDeleteButton().trigger('click');
+ await waitForPromises();
+
+ expect(wrapper.emitted('delete')).toBeDefined();
+ });
+ });
+});
diff --git a/spec/frontend/artifacts/components/artifacts_table_row_details_spec.js b/spec/frontend/artifacts/components/artifacts_table_row_details_spec.js
new file mode 100644
index 00000000000..c6ad13462f9
--- /dev/null
+++ b/spec/frontend/artifacts/components/artifacts_table_row_details_spec.js
@@ -0,0 +1,122 @@
+import { GlModal } 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';
+import waitForPromises from 'helpers/wait_for_promises';
+import ArtifactsTableRowDetails from '~/artifacts/components/artifacts_table_row_details.vue';
+import ArtifactRow from '~/artifacts/components/artifact_row.vue';
+import ArtifactDeleteModal from '~/artifacts/components/artifact_delete_modal.vue';
+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';
+
+jest.mock('~/flash');
+
+const { artifacts } = getJobArtifactsResponse.data.project.jobs.nodes[0];
+const refetchArtifacts = jest.fn();
+
+Vue.use(VueApollo);
+
+describe('ArtifactsTableRowDetails component', () => {
+ let wrapper;
+ let requestHandlers;
+
+ const findModal = () => wrapper.findComponent(GlModal);
+
+ const createComponent = (
+ handlers = {
+ destroyArtifactMutation: jest.fn(),
+ },
+ ) => {
+ requestHandlers = handlers;
+ wrapper = mountExtended(ArtifactsTableRowDetails, {
+ apolloProvider: createMockApollo([
+ [destroyArtifactMutation, requestHandlers.destroyArtifactMutation],
+ ]),
+ propsData: {
+ artifacts,
+ refetchArtifacts,
+ queryVariables: {},
+ },
+ data() {
+ return { deletingArtifactId: null };
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('passes correct props', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('to the artifact rows', () => {
+ [0, 1, 2].forEach((index) => {
+ expect(wrapper.findAllComponents(ArtifactRow).at(index).props()).toMatchObject({
+ artifact: artifacts.nodes[index],
+ });
+ });
+ });
+ });
+
+ describe('when the artifact row emits the delete event', () => {
+ it('shows the artifact delete modal', async () => {
+ createComponent();
+ await waitForPromises();
+
+ expect(findModal().props('visible')).toBe(false);
+
+ await wrapper.findComponent(ArtifactRow).vm.$emit('delete');
+
+ expect(findModal().props('visible')).toBe(true);
+ expect(findModal().props('title')).toBe(I18N_MODAL_TITLE(artifacts.nodes[0].name));
+ });
+ });
+
+ describe('when the artifact delete modal emits its primary event', () => {
+ it('triggers the destroyArtifact GraphQL mutation', async () => {
+ createComponent();
+ await waitForPromises();
+
+ wrapper.findComponent(ArtifactRow).vm.$emit('delete');
+ wrapper.findComponent(ArtifactDeleteModal).vm.$emit('primary');
+
+ expect(requestHandlers.destroyArtifactMutation).toHaveBeenCalledWith({
+ id: artifacts.nodes[0].id,
+ });
+ });
+
+ it('displays a flash message and refetches artifacts when the mutation fails', async () => {
+ createComponent({
+ destroyArtifactMutation: jest.fn().mockRejectedValue(new Error('Error!')),
+ });
+ await waitForPromises();
+
+ expect(wrapper.emitted('refetch')).toBeUndefined();
+
+ wrapper.findComponent(ArtifactRow).vm.$emit('delete');
+ wrapper.findComponent(ArtifactDeleteModal).vm.$emit('primary');
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({ message: I18N_DESTROY_ERROR });
+ expect(wrapper.emitted('refetch')).toBeDefined();
+ });
+ });
+
+ describe('when the artifact delete modal is cancelled', () => {
+ it('does not trigger the destroyArtifact GraphQL mutation', async () => {
+ createComponent();
+ await waitForPromises();
+
+ wrapper.findComponent(ArtifactRow).vm.$emit('delete');
+ wrapper.findComponent(ArtifactDeleteModal).vm.$emit('cancel');
+
+ expect(requestHandlers.destroyArtifactMutation).not.toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/artifacts/components/job_artifacts_table_spec.js b/spec/frontend/artifacts/components/job_artifacts_table_spec.js
new file mode 100644
index 00000000000..131b4b99bb2
--- /dev/null
+++ b/spec/frontend/artifacts/components/job_artifacts_table_spec.js
@@ -0,0 +1,341 @@
+import { GlLoadingIcon, GlTable, GlLink, GlBadge, GlPagination, GlModal } 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';
+import CiIcon from '~/vue_shared/components/ci_icon.vue';
+import waitForPromises from 'helpers/wait_for_promises';
+import JobArtifactsTable from '~/artifacts/components/job_artifacts_table.vue';
+import ArtifactsTableRowDetails from '~/artifacts/components/artifacts_table_row_details.vue';
+import ArtifactDeleteModal from '~/artifacts/components/artifact_delete_modal.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 { totalArtifactsSizeForJob } from '~/artifacts/utils';
+import { createAlert } from '~/flash';
+
+jest.mock('~/flash');
+
+Vue.use(VueApollo);
+
+describe('JobArtifactsTable component', () => {
+ let wrapper;
+ let requestHandlers;
+
+ const findLoadingState = () => wrapper.findComponent(GlLoadingIcon);
+ const findTable = () => wrapper.findComponent(GlTable);
+ const findDetailsRows = () => wrapper.findAllComponents(ArtifactsTableRowDetails);
+ const findDetailsInRow = (i) =>
+ findTable().findAll('tbody tr').at(i).findComponent(ArtifactsTableRowDetails);
+
+ const findCount = () => wrapper.findByTestId('job-artifacts-count');
+ const findCountAt = (i) => wrapper.findAllByTestId('job-artifacts-count').at(i);
+
+ const findModal = () => wrapper.findComponent(GlModal);
+
+ const findStatuses = () => wrapper.findAllByTestId('job-artifacts-job-status');
+ const findSuccessfulJobStatus = () => findStatuses().at(0);
+ const findFailedJobStatus = () => findStatuses().at(1);
+
+ const findLinks = () => wrapper.findAllComponents(GlLink);
+ const findJobLink = () => findLinks().at(0);
+ const findPipelineLink = () => findLinks().at(1);
+ const findRefLink = () => findLinks().at(2);
+ const findCommitLink = () => findLinks().at(3);
+
+ const findSize = () => wrapper.findByTestId('job-artifacts-size');
+ const findCreated = () => wrapper.findByTestId('job-artifacts-created');
+
+ const findDownloadButton = () => wrapper.findByTestId('job-artifacts-download-button');
+ const findBrowseButton = () => wrapper.findByTestId('job-artifacts-browse-button');
+ const findDeleteButton = () => wrapper.findByTestId('job-artifacts-delete-button');
+ const findArtifactDeleteButton = () => wrapper.findByTestId('job-artifact-row-delete-button');
+
+ const findPagination = () => wrapper.findComponent(GlPagination);
+ const setPage = async (page) => {
+ findPagination().vm.$emit('input', page);
+ await waitForPromises();
+ };
+
+ let enoughJobsToPaginate = [...getJobArtifactsResponse.data.project.jobs.nodes];
+ while (enoughJobsToPaginate.length <= JOBS_PER_PAGE) {
+ enoughJobsToPaginate = [
+ ...enoughJobsToPaginate,
+ ...getJobArtifactsResponse.data.project.jobs.nodes,
+ ];
+ }
+ const getJobArtifactsResponseThatPaginates = {
+ data: { project: { jobs: { nodes: enoughJobsToPaginate } } },
+ };
+
+ const job = getJobArtifactsResponse.data.project.jobs.nodes[0];
+ const archiveArtifact = job.artifacts.nodes.find(
+ (artifact) => artifact.fileType === ARCHIVE_FILE_TYPE,
+ );
+
+ const createComponent = (
+ handlers = {
+ getJobArtifactsQuery: jest.fn().mockResolvedValue(getJobArtifactsResponse),
+ },
+ data = {},
+ ) => {
+ requestHandlers = handlers;
+ wrapper = mountExtended(JobArtifactsTable, {
+ apolloProvider: createMockApollo([
+ [getJobArtifactsQuery, requestHandlers.getJobArtifactsQuery],
+ ]),
+ provide: { projectPath: 'project/path' },
+ data() {
+ return data;
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('when loading, shows a loading state', () => {
+ createComponent();
+
+ expect(findLoadingState().exists()).toBe(true);
+ });
+
+ it('on error, shows an alert', async () => {
+ createComponent({
+ getJobArtifactsQuery: jest.fn().mockRejectedValue(new Error('Error!')),
+ });
+
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({ message: I18N_FETCH_ERROR });
+ });
+
+ it('with data, renders the table', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findTable().exists()).toBe(true);
+ });
+
+ describe('job details', () => {
+ beforeEach(async () => {
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('shows the artifact count', () => {
+ expect(findCount().text()).toBe(`${job.artifacts.nodes.length} files`);
+ });
+
+ it('shows the job status as an icon for a successful job', () => {
+ expect(findSuccessfulJobStatus().findComponent(CiIcon).exists()).toBe(true);
+ expect(findSuccessfulJobStatus().findComponent(GlBadge).exists()).toBe(false);
+ });
+
+ it('shows the job status as a badge for other job statuses', () => {
+ expect(findFailedJobStatus().findComponent(GlBadge).exists()).toBe(true);
+ expect(findFailedJobStatus().findComponent(CiIcon).exists()).toBe(false);
+ });
+
+ it('shows links to the job, pipeline, ref, and commit', () => {
+ expect(findJobLink().text()).toBe(job.name);
+ expect(findJobLink().attributes('href')).toBe(job.webPath);
+
+ expect(findPipelineLink().text()).toBe(`#${getIdFromGraphQLId(job.pipeline.id)}`);
+ expect(findPipelineLink().attributes('href')).toBe(job.pipeline.path);
+
+ expect(findRefLink().text()).toBe(job.refName);
+ expect(findRefLink().attributes('href')).toBe(job.refPath);
+
+ expect(findCommitLink().text()).toBe(job.shortSha);
+ expect(findCommitLink().attributes('href')).toBe(job.commitPath);
+ });
+
+ it('shows the total size of artifacts', () => {
+ expect(findSize().text()).toBe(totalArtifactsSizeForJob(job));
+ });
+
+ it('shows the created time', () => {
+ expect(findCreated().text()).toBe('5 years ago');
+ });
+
+ describe('row expansion', () => {
+ it('toggles the visibility of the row details', async () => {
+ expect(findDetailsRows().length).toBe(0);
+
+ findCount().trigger('click');
+ await waitForPromises();
+
+ expect(findDetailsRows().length).toBe(1);
+
+ findCount().trigger('click');
+ await waitForPromises();
+
+ expect(findDetailsRows().length).toBe(0);
+ });
+
+ it('expands and collapses jobs', async () => {
+ // both jobs start collapsed
+ expect(findDetailsInRow(0).exists()).toBe(false);
+ expect(findDetailsInRow(1).exists()).toBe(false);
+
+ findCountAt(0).trigger('click');
+ await waitForPromises();
+
+ // first job is expanded, second row has its details
+ expect(findDetailsInRow(0).exists()).toBe(false);
+ expect(findDetailsInRow(1).exists()).toBe(true);
+ expect(findDetailsInRow(2).exists()).toBe(false);
+
+ findCountAt(1).trigger('click');
+ await waitForPromises();
+
+ // both jobs are expanded, each has details below it
+ expect(findDetailsInRow(0).exists()).toBe(false);
+ expect(findDetailsInRow(1).exists()).toBe(true);
+ expect(findDetailsInRow(2).exists()).toBe(false);
+ expect(findDetailsInRow(3).exists()).toBe(true);
+
+ findCountAt(0).trigger('click');
+ await waitForPromises();
+
+ // first job collapsed, second job expanded
+ expect(findDetailsInRow(0).exists()).toBe(false);
+ expect(findDetailsInRow(1).exists()).toBe(false);
+ expect(findDetailsInRow(2).exists()).toBe(true);
+ });
+
+ it('keeps the job expanded when an artifact is deleted', async () => {
+ findCount().trigger('click');
+ await waitForPromises();
+
+ expect(findDetailsInRow(0).exists()).toBe(false);
+ expect(findDetailsInRow(1).exists()).toBe(true);
+
+ findArtifactDeleteButton().trigger('click');
+ await waitForPromises();
+
+ expect(findModal().props('visible')).toBe(true);
+
+ wrapper.findComponent(ArtifactDeleteModal).vm.$emit('primary');
+ await waitForPromises();
+
+ expect(findDetailsInRow(0).exists()).toBe(false);
+ expect(findDetailsInRow(1).exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('download button', () => {
+ it('is a link to the download path for the archive artifact', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findDownloadButton().attributes('href')).toBe(archiveArtifact.downloadPath);
+ });
+
+ it('is disabled when there is no download path', async () => {
+ const jobWithoutDownloadPath = {
+ ...job,
+ archive: { downloadPath: null },
+ };
+
+ createComponent(
+ { getJobArtifactsQuery: jest.fn() },
+ { jobArtifacts: [jobWithoutDownloadPath] },
+ );
+
+ await waitForPromises();
+
+ expect(findDownloadButton().attributes('disabled')).toBe('disabled');
+ });
+ });
+
+ describe('browse button', () => {
+ it('is a link to the browse path for the job', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findBrowseButton().attributes('href')).toBe(job.browseArtifactsPath);
+ });
+
+ it('is disabled when there is no browse path', async () => {
+ const jobWithoutBrowsePath = {
+ ...job,
+ browseArtifactsPath: null,
+ };
+
+ createComponent(
+ { getJobArtifactsQuery: jest.fn() },
+ { jobArtifacts: [jobWithoutBrowsePath] },
+ );
+
+ await waitForPromises();
+
+ expect(findBrowseButton().attributes('disabled')).toBe('disabled');
+ });
+ });
+
+ describe('delete button', () => {
+ it('shows a disabled delete button for now (coming soon)', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findDeleteButton().attributes('disabled')).toBe('disabled');
+ });
+ });
+
+ describe('pagination', () => {
+ const { pageInfo } = getJobArtifactsResponse.data.project.jobs;
+
+ beforeEach(async () => {
+ createComponent(
+ {
+ getJobArtifactsQuery: jest.fn().mockResolvedValue(getJobArtifactsResponseThatPaginates),
+ },
+ {
+ count: enoughJobsToPaginate.length,
+ 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,
+ });
+ });
+
+ 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 next page', () => {
+ return setPage(2).then(() => {
+ expect(wrapper.vm.queryVariables).toMatchObject({
+ lastPageSize: null,
+ nextPageCursor: pageInfo.endCursor,
+ prevPageCursor: '',
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/artifacts/graphql/cache_update_spec.js b/spec/frontend/artifacts/graphql/cache_update_spec.js
new file mode 100644
index 00000000000..4d610328298
--- /dev/null
+++ b/spec/frontend/artifacts/graphql/cache_update_spec.js
@@ -0,0 +1,67 @@
+import getJobArtifactsQuery from '~/artifacts/graphql/queries/get_job_artifacts.query.graphql';
+import { removeArtifactFromStore } from '~/artifacts/graphql/cache_update';
+
+describe('Artifact table cache updates', () => {
+ let store;
+
+ const cacheMock = {
+ project: {
+ jobs: {
+ nodes: [
+ { artifacts: { nodes: [{ id: 'foo' }] } },
+ { artifacts: { nodes: [{ id: 'bar' }] } },
+ ],
+ },
+ },
+ };
+
+ const query = getJobArtifactsQuery;
+ const variables = { fullPath: 'path/to/project' };
+
+ beforeEach(() => {
+ store = {
+ readQuery: jest.fn().mockReturnValue(cacheMock),
+ writeQuery: jest.fn(),
+ };
+ });
+
+ describe('removeArtifactFromStore', () => {
+ it('calls readQuery', () => {
+ removeArtifactFromStore(store, 'foo', query, variables);
+ expect(store.readQuery).toHaveBeenCalledWith({ query, variables });
+ });
+
+ it('writes the correct result in the cache', () => {
+ removeArtifactFromStore(store, 'foo', query, variables);
+ expect(store.writeQuery).toHaveBeenCalledWith({
+ query,
+ variables,
+ data: {
+ project: {
+ jobs: {
+ nodes: [{ artifacts: { nodes: [] } }, { artifacts: { nodes: [{ id: 'bar' }] } }],
+ },
+ },
+ },
+ });
+ });
+
+ it('does not remove an unknown artifact', () => {
+ removeArtifactFromStore(store, 'baz', query, variables);
+ expect(store.writeQuery).toHaveBeenCalledWith({
+ query,
+ variables,
+ data: {
+ project: {
+ jobs: {
+ nodes: [
+ { artifacts: { nodes: [{ id: 'foo' }] } },
+ { artifacts: { nodes: [{ id: 'bar' }] } },
+ ],
+ },
+ },
+ },
+ });
+ });
+ });
+});
diff --git a/spec/frontend/behaviors/markdown/render_sandboxed_mermaid_spec.js b/spec/frontend/behaviors/markdown/render_sandboxed_mermaid_spec.js
index 2b9442162aa..de0e5063e49 100644
--- a/spec/frontend/behaviors/markdown/render_sandboxed_mermaid_spec.js
+++ b/spec/frontend/behaviors/markdown/render_sandboxed_mermaid_spec.js
@@ -1,34 +1,127 @@
-import $ from 'jquery';
+import { createWrapper } from '@vue/test-utils';
+import { __ } from '~/locale';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import renderMermaid from '~/behaviors/markdown/render_sandboxed_mermaid';
+import renderMermaid, {
+ MAX_CHAR_LIMIT,
+ MAX_MERMAID_BLOCK_LIMIT,
+ LAZY_ALERT_SHOWN_CLASS,
+} from '~/behaviors/markdown/render_sandboxed_mermaid';
-describe('Render mermaid diagrams for Gitlab Flavoured Markdown', () => {
- it('Does something', () => {
- document.body.dataset.page = '';
- setHTMLFixture(`
- <div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-7:3" class="code highlight js-syntax-highlight language-mermaid white" lang="mermaid" id="code-4">
- <code class="js-render-mermaid">
- <span id="LC1" class="line" lang="mermaid">graph TD;</span>
- <span id="LC2" class="line" lang="mermaid">A--&gt;B</span>
- <span id="LC3" class="line" lang="mermaid">A--&gt;C</span>
- <span id="LC4" class="line" lang="mermaid">B--&gt;D</span>
- <span id="LC5" class="line" lang="mermaid">C--&gt;D</span>
- </code>
- </pre>
- <copy-code>
- <button type="button" class="btn btn-default btn-md gl-button btn-icon has-tooltip" data-title="Copy to clipboard" data-clipboard-target="pre#code-4">
- <svg><use xlink:href="/assets/icons-7f1680a3670112fe4c8ef57b9dfb93f0f61b43a2a479d7abd6c83bcb724b9201.svg#copy-to-clipboard"></use></svg>
- </button>
- </copy-code>
- </div>`);
- const els = $('pre.js-syntax-highlight').find('.js-render-mermaid');
-
- renderMermaid(els);
+describe('Mermaid diagrams renderer', () => {
+ // Finders
+ const findMermaidIframes = () => document.querySelectorAll('iframe[src="/-/sandbox/mermaid"]');
+ const findDangerousMermaidAlert = () =>
+ createWrapper(document.querySelector('[data-testid="alert-warning"]'));
+ // Helpers
+ const renderDiagrams = () => {
+ renderMermaid([...document.querySelectorAll('.js-render-mermaid')]);
jest.runAllTimers();
- expect(document.querySelector('pre.js-syntax-highlight').classList).toContain('gl-sr-only');
+ };
+
+ beforeEach(() => {
+ document.body.dataset.page = '';
+ });
+ afterEach(() => {
resetHTMLFixture();
});
+
+ it('renders a mermaid diagram', () => {
+ setHTMLFixture('<pre><code class="js-render-mermaid"></code></pre>');
+
+ expect(findMermaidIframes()).toHaveLength(0);
+
+ renderDiagrams();
+
+ expect(document.querySelector('pre').classList).toContain('gl-sr-only');
+ expect(findMermaidIframes()).toHaveLength(1);
+ });
+
+ describe('within a details element', () => {
+ beforeEach(() => {
+ setHTMLFixture('<details><pre><code class="js-render-mermaid"></code></pre></details>');
+ renderDiagrams();
+ });
+
+ it('does not render the diagram on load', () => {
+ expect(findMermaidIframes()).toHaveLength(0);
+ });
+
+ it('render the diagram when the details element is opened', () => {
+ document.querySelector('details').setAttribute('open', true);
+ document.querySelector('details').dispatchEvent(new Event('toggle'));
+ jest.runAllTimers();
+
+ expect(findMermaidIframes()).toHaveLength(1);
+ });
+ });
+
+ describe('dangerous diagrams', () => {
+ describe(`when the diagram's source exceeds ${MAX_CHAR_LIMIT} characters`, () => {
+ beforeEach(() => {
+ setHTMLFixture(
+ `<pre>
+ <code class="js-render-mermaid">${Array(MAX_CHAR_LIMIT + 1)
+ .fill('a')
+ .join('')}</code>
+ </pre>`,
+ );
+ renderDiagrams();
+ });
+ it('does not render the diagram on load', () => {
+ expect(findMermaidIframes()).toHaveLength(0);
+ });
+
+ it('shows a warning about performance impact when rendering the diagram', () => {
+ expect(document.querySelector('pre').classList).toContain(LAZY_ALERT_SHOWN_CLASS);
+ expect(findDangerousMermaidAlert().exists()).toBe(true);
+ expect(findDangerousMermaidAlert().text()).toContain(
+ __('Warning: Displaying this diagram might cause performance issues on this page.'),
+ );
+ });
+
+ it("renders the diagram when clicking on the alert's button", () => {
+ findDangerousMermaidAlert().find('button').trigger('click');
+ jest.runAllTimers();
+
+ expect(findMermaidIframes()).toHaveLength(1);
+ });
+ });
+
+ it(`stops rendering diagrams once the total rendered source exceeds ${MAX_CHAR_LIMIT} characters`, () => {
+ setHTMLFixture(
+ `<pre>
+ <code class="js-render-mermaid">${Array(MAX_CHAR_LIMIT - 1)
+ .fill('a')
+ .join('')}</code>
+ <code class="js-render-mermaid">2</code>
+ <code class="js-render-mermaid">3</code>
+ <code class="js-render-mermaid">4</code>
+ </pre>`,
+ );
+ renderDiagrams();
+
+ expect(findMermaidIframes()).toHaveLength(3);
+ });
+
+ // Note: The test case below is provided for convenience but should remain skipped as the DOM
+ // operations it requires are too expensive and would significantly slow down the test suite.
+ // eslint-disable-next-line jest/no-disabled-tests
+ it.skip(`stops rendering diagrams when the rendered diagrams count exceeds ${MAX_MERMAID_BLOCK_LIMIT}`, () => {
+ setHTMLFixture(
+ `<pre>
+ ${Array(MAX_MERMAID_BLOCK_LIMIT + 1)
+ .fill('<code class="js-render-mermaid"></code>')
+ .join('')}
+ </pre>`,
+ );
+ renderDiagrams();
+
+ expect([...document.querySelectorAll('.js-render-mermaid')]).toHaveLength(
+ MAX_MERMAID_BLOCK_LIMIT + 1,
+ );
+ expect(findMermaidIframes()).toHaveLength(MAX_MERMAID_BLOCK_LIMIT);
+ });
+ });
});
diff --git a/spec/frontend/blob/blob_blame_link_spec.js b/spec/frontend/blob/blob_blame_link_spec.js
index 060e8803520..18adeed1f02 100644
--- a/spec/frontend/blob/blob_blame_link_spec.js
+++ b/spec/frontend/blob/blob_blame_link_spec.js
@@ -1,5 +1,5 @@
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import addBlameLink from '~/blob/blob_blame_link';
+import { addBlameLink } from '~/blob/blob_blame_link';
describe('Blob links', () => {
const mouseoverEvent = new MouseEvent('mouseover', {
@@ -10,9 +10,10 @@ describe('Blob links', () => {
beforeEach(() => {
setHTMLFixture(`
- <div id="blob-content-holder">
+ <div id="blob-content-holder" class="js-per-page" data-blame-per-page="1000">
<div class="line-numbers" data-blame-path="/blamePath">
<a id="L5" href="#L5" data-line-number="5" class="file-line-num js-line-links">5</a>
+ <a id="L1005" href="#L1005" data-line-number="1005" class="file-line-num js-line-links">1005</a>
</div>
<pre id="LC5">Line 5 content</pre>
</div>
@@ -44,4 +45,11 @@ describe('Blob links', () => {
expect(lineLink).not.toBeNull();
expect(lineLink.getAttribute('href')).toBe('#L5');
});
+
+ it('adds page parameter when needed', () => {
+ document.querySelectorAll('.file-line-num')[1].dispatchEvent(mouseoverEvent);
+ const blameLink = document.querySelectorAll('.file-line-blame')[1];
+ expect(blameLink).not.toBeNull();
+ expect(blameLink.getAttribute('href')).toBe('/blamePath?page=2#L1005');
+ });
});
diff --git a/spec/frontend/blob/components/__snapshots__/blob_edit_content_spec.js.snap b/spec/frontend/blob/components/__snapshots__/blob_edit_content_spec.js.snap
deleted file mode 100644
index 72761c18b3d..00000000000
--- a/spec/frontend/blob/components/__snapshots__/blob_edit_content_spec.js.snap
+++ /dev/null
@@ -1,18 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Blob Header Editing rendering matches the snapshot 1`] = `
-<div
- class="file-content code"
->
- <div
- data-editor-loading=""
- id="editor"
- >
- <pre
- class="editor-loading-content"
- >
- Lorem ipsum dolor sit amet, consectetur adipiscing elit.
- </pre>
- </div>
-</div>
-`;
diff --git a/spec/frontend/blob/components/blob_edit_content_spec.js b/spec/frontend/blob/components/blob_edit_content_spec.js
deleted file mode 100644
index 5017b624292..00000000000
--- a/spec/frontend/blob/components/blob_edit_content_spec.js
+++ /dev/null
@@ -1,105 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import BlobEditContent from '~/blob/components/blob_edit_content.vue';
-import * as utils from '~/blob/utils';
-
-jest.mock('~/editor/source_editor');
-
-describe('Blob Header Editing', () => {
- let wrapper;
- const onDidChangeModelContent = jest.fn();
- const updateModelLanguage = jest.fn();
- const getValue = jest.fn();
- const value = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';
- const fileName = 'lorem.txt';
- const fileGlobalId = 'snippet_777';
-
- function createComponent(props = {}) {
- wrapper = shallowMount(BlobEditContent, {
- propsData: {
- value,
- fileName,
- fileGlobalId,
- ...props,
- },
- });
- }
-
- beforeEach(() => {
- jest.spyOn(utils, 'initSourceEditor').mockImplementation(() => ({
- onDidChangeModelContent,
- updateModelLanguage,
- getValue,
- dispose: jest.fn(),
- }));
-
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- const triggerChangeContent = (val) => {
- getValue.mockReturnValue(val);
- const [cb] = onDidChangeModelContent.mock.calls[0];
-
- cb();
-
- jest.runOnlyPendingTimers();
- };
-
- describe('rendering', () => {
- it('matches the snapshot', () => {
- expect(wrapper.element).toMatchSnapshot();
- });
-
- it('renders content', () => {
- expect(wrapper.text()).toContain(value);
- });
- });
-
- describe('functionality', () => {
- it('does not fail without content', () => {
- const spy = jest.spyOn(global.console, 'error');
- createComponent({ value: undefined });
-
- expect(spy).not.toHaveBeenCalled();
- expect(wrapper.find('#editor').exists()).toBe(true);
- });
-
- it('initialises Source Editor', () => {
- const el = wrapper.findComponent({ ref: 'editor' }).element;
- expect(utils.initSourceEditor).toHaveBeenCalledWith({
- el,
- blobPath: fileName,
- blobGlobalId: fileGlobalId,
- blobContent: value,
- });
- });
-
- it('reacts to the changes in fileName', () => {
- const newFileName = 'ipsum.txt';
-
- wrapper.setProps({
- fileName: newFileName,
- });
-
- return nextTick().then(() => {
- expect(updateModelLanguage).toHaveBeenCalledWith(newFileName);
- });
- });
-
- it('registers callback with editor onChangeContent', () => {
- expect(onDidChangeModelContent).toHaveBeenCalledWith(expect.any(Function));
- });
-
- it('emits input event when the blob content is changed', () => {
- expect(wrapper.emitted().input).toBeUndefined();
-
- triggerChangeContent(value);
-
- expect(wrapper.emitted().input).toEqual([[value]]);
- });
- });
-});
diff --git a/spec/frontend/blob/utils_spec.js b/spec/frontend/blob/utils_spec.js
index a543c0060cb..24f70acb093 100644
--- a/spec/frontend/blob/utils_spec.js
+++ b/spec/frontend/blob/utils_spec.js
@@ -1,44 +1,32 @@
import * as utils from '~/blob/utils';
-import Editor from '~/editor/source_editor';
-
-jest.mock('~/editor/source_editor');
describe('Blob utilities', () => {
- describe('initSourceEditor', () => {
- let editorEl;
- const blobPath = 'foo.txt';
- const blobContent = 'Foo bar';
- const blobGlobalId = 'snippet_777';
-
- beforeEach(() => {
- editorEl = document.createElement('div');
+ describe('getPageParamValue', () => {
+ it('returns empty string if no perPage parameter is provided', () => {
+ const pageParamValue = utils.getPageParamValue(5);
+ expect(pageParamValue).toEqual('');
});
-
- describe('Monaco editor', () => {
- it('initializes the Source Editor', () => {
- utils.initSourceEditor({ el: editorEl });
- expect(Editor).toHaveBeenCalledWith({
- scrollbar: {
- alwaysConsumeMouseWheel: false,
- },
- });
- });
-
- it.each([[{}], [{ blobPath, blobContent, blobGlobalId }]])(
- 'creates the instance with the passed parameters %s',
- (extraParams) => {
- const params = {
- el: editorEl,
- ...extraParams,
- };
-
- expect(Editor.prototype.createInstance).not.toHaveBeenCalled();
-
- utils.initSourceEditor(params);
-
- expect(Editor.prototype.createInstance).toHaveBeenCalledWith(params);
- },
- );
+ it('returns empty string if page is equal 1', () => {
+ const pageParamValue = utils.getPageParamValue(1000, 1000);
+ expect(pageParamValue).toEqual('');
+ });
+ it('returns correct page parameter value', () => {
+ const pageParamValue = utils.getPageParamValue(1001, 1000);
+ expect(pageParamValue).toEqual(2);
+ });
+ it('accepts strings as a parameter and returns correct result', () => {
+ const pageParamValue = utils.getPageParamValue('1001', '1000');
+ expect(pageParamValue).toEqual(2);
+ });
+ });
+ describe('getPageSearchString', () => {
+ it('returns empty search string if page parameter is empty value', () => {
+ const path = utils.getPageSearchString('/blamePath', '');
+ expect(path).toEqual('');
+ });
+ it('returns correct search string if value is provided', () => {
+ const searchString = utils.getPageSearchString('/blamePath', 3);
+ expect(searchString).toEqual('?page=3');
});
});
});
diff --git a/spec/frontend/blob_edit/edit_blob_spec.js b/spec/frontend/blob_edit/edit_blob_spec.js
index c031cae11df..dda46e97b85 100644
--- a/spec/frontend/blob_edit/edit_blob_spec.js
+++ b/spec/frontend/blob_edit/edit_blob_spec.js
@@ -1,3 +1,4 @@
+import MockAdapter from 'axios-mock-adapter';
import { Emitter } from 'monaco-editor';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import waitForPromises from 'helpers/wait_for_promises';
@@ -8,6 +9,7 @@ import { EditorMarkdownExtension } from '~/editor/extensions/source_editor_markd
import { EditorMarkdownPreviewExtension } from '~/editor/extensions/source_editor_markdown_livepreview_ext';
import { ToolbarExtension } from '~/editor/extensions/source_editor_toolbar_ext';
import SourceEditor from '~/editor/source_editor';
+import axios from '~/lib/utils/axios_utils';
jest.mock('~/editor/source_editor');
jest.mock('~/editor/extensions/source_editor_extension_base');
@@ -32,6 +34,7 @@ const markdownExtensions = [
describe('Blob Editing', () => {
let blobInstance;
+ let mock;
const useMock = jest.fn(() => markdownExtensions);
const unuseMock = jest.fn();
const emitter = new Emitter();
@@ -44,7 +47,10 @@ describe('Blob Editing', () => {
onDidChangeModelLanguage: emitter.event,
};
beforeEach(() => {
+ mock = new MockAdapter(axios);
setHTMLFixture(`
+ <div class="js-edit-mode-pane"></div>
+ <div class="js-edit-mode"><a href="#write">Write</a><a href="#preview">Preview</a></div>
<form class="js-edit-blob-form">
<div id="file_path"></div>
<div id="editor"></div>
@@ -54,6 +60,7 @@ describe('Blob Editing', () => {
jest.spyOn(SourceEditor.prototype, 'createInstance').mockReturnValue(mockInstance);
});
afterEach(() => {
+ mock.restore();
jest.clearAllMocks();
unuseMock.mockClear();
useMock.mockClear();
@@ -108,6 +115,47 @@ describe('Blob Editing', () => {
});
});
+ describe('correctly handles toggling the live-preview panel for different file types', () => {
+ it.each`
+ desc | isMarkdown | isPreviewOpened | tabToClick | shouldOpenPreview | shouldClosePreview | expectedDesc
+ ${'not markdown with preview closed'} | ${false} | ${false} | ${'#write'} | ${false} | ${false} | ${'not toggle preview'}
+ ${'not markdown with preview closed'} | ${false} | ${false} | ${'#preview'} | ${false} | ${false} | ${'not toggle preview'}
+ ${'markdown with preview closed'} | ${true} | ${false} | ${'#write'} | ${false} | ${false} | ${'not toggle preview'}
+ ${'markdown with preview closed'} | ${true} | ${false} | ${'#preview'} | ${true} | ${false} | ${'open preview'}
+ ${'markdown with preview opened'} | ${true} | ${true} | ${'#write'} | ${false} | ${true} | ${'close preview'}
+ ${'markdown with preview opened'} | ${true} | ${true} | ${'#preview'} | ${false} | ${false} | ${'not toggle preview'}
+ `(
+ 'when $desc, clicking $tabToClick should $expectedDesc',
+ async ({
+ isMarkdown,
+ isPreviewOpened,
+ tabToClick,
+ shouldOpenPreview,
+ shouldClosePreview,
+ }) => {
+ const fire = jest.fn();
+ SourceEditor.prototype.createInstance = jest.fn().mockReturnValue({
+ ...mockInstance,
+ markdownPreview: {
+ eventEmitter: {
+ fire,
+ },
+ },
+ });
+ await initEditor(isMarkdown);
+ blobInstance.markdownLivePreviewOpened = isPreviewOpened;
+ const elToClick = document.querySelector(`a[href='${tabToClick}']`);
+ elToClick.dispatchEvent(new Event('click'));
+
+ if (shouldOpenPreview || shouldClosePreview) {
+ expect(fire).toHaveBeenCalled();
+ } else {
+ expect(fire).not.toHaveBeenCalled();
+ }
+ },
+ );
+ });
+
it('adds trailing newline to the blob content on submit', async () => {
const form = document.querySelector('.js-edit-blob-form');
const fileContentEl = document.getElementById('file-content');
diff --git a/spec/frontend/boards/board_card_inner_spec.js b/spec/frontend/boards/board_card_inner_spec.js
index 3ebc51c4bcb..d05e057095d 100644
--- a/spec/frontend/boards/board_card_inner_spec.js
+++ b/spec/frontend/boards/board_card_inner_spec.js
@@ -7,7 +7,6 @@ import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import IssuableBlockedIcon from '~/vue_shared/components/issuable_blocked_icon/issuable_blocked_icon.vue';
import BoardCardInner from '~/boards/components/board_card_inner.vue';
-import BoardCardMoveToPosition from '~/boards/components/board_card_move_to_position.vue';
import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue';
import { issuableTypes } from '~/boards/constants';
import eventHub from '~/boards/eventhub';
@@ -49,12 +48,11 @@ describe('Board card component', () => {
const findEpicCountablesTotalWeight = () => wrapper.findByTestId('epic-countables-total-weight');
const findEpicProgressTooltip = () => wrapper.findByTestId('epic-progress-tooltip-content');
const findHiddenIssueIcon = () => wrapper.findByTestId('hidden-icon');
- const findMoveToPositionComponent = () => wrapper.findComponent(BoardCardMoveToPosition);
const findWorkItemIcon = () => wrapper.findComponent(WorkItemTypeIcon);
const performSearchMock = jest.fn();
- const createStore = ({ isEpicBoard = false, isProjectBoard = false } = {}) => {
+ const createStore = ({ isProjectBoard = false } = {}) => {
store = new Vuex.Store({
...defaultStore,
actions: {
@@ -67,13 +65,12 @@ describe('Board card component', () => {
},
getters: {
isGroupBoard: () => true,
- isEpicBoard: () => isEpicBoard,
isProjectBoard: () => isProjectBoard,
},
});
};
- const createWrapper = (props = {}) => {
+ const createWrapper = ({ props = {}, isEpicBoard = false } = {}) => {
wrapper = mountExtended(BoardCardInner, {
store,
propsData: {
@@ -99,6 +96,7 @@ describe('Board card component', () => {
provide: {
rootPath: '/',
scopedLabelsAvailable: false,
+ isEpicBoard,
},
});
};
@@ -113,7 +111,7 @@ describe('Board card component', () => {
};
createStore();
- createWrapper({ item: issue, list });
+ createWrapper({ props: { item: issue, list } });
});
afterEach(() => {
@@ -143,16 +141,12 @@ describe('Board card component', () => {
expect(findHiddenIssueIcon().exists()).toBe(false);
});
- it('renders the move to position icon', () => {
- expect(findMoveToPositionComponent().exists()).toBe(true);
- });
-
it('does not render the work type icon by default', () => {
expect(findWorkItemIcon().exists()).toBe(false);
});
it('renders the work type icon when props is passed', () => {
- createWrapper({ item: issue, list, showWorkItemTypeIcon: true });
+ createWrapper({ props: { item: issue, list, showWorkItemTypeIcon: true } });
expect(findWorkItemIcon().exists()).toBe(true);
expect(findWorkItemIcon().props('workItemType')).toBe(issue.type);
});
@@ -183,9 +177,11 @@ describe('Board card component', () => {
describe('blocked', () => {
it('renders blocked icon if issue is blocked', async () => {
createWrapper({
- item: {
- ...issue,
- blocked: true,
+ props: {
+ item: {
+ ...issue,
+ blocked: true,
+ },
},
});
@@ -194,9 +190,11 @@ describe('Board card component', () => {
it('does not show blocked icon if issue is not blocked', () => {
createWrapper({
- item: {
- ...issue,
- blocked: false,
+ props: {
+ item: {
+ ...issue,
+ blocked: false,
+ },
},
});
@@ -207,9 +205,11 @@ describe('Board card component', () => {
describe('confidential issue', () => {
beforeEach(() => {
createWrapper({
- item: {
- ...wrapper.props('item'),
- confidential: true,
+ props: {
+ item: {
+ ...wrapper.props('item'),
+ confidential: true,
+ },
},
});
});
@@ -222,9 +222,11 @@ describe('Board card component', () => {
describe('hidden issue', () => {
beforeEach(() => {
createWrapper({
- item: {
- ...wrapper.props('item'),
- hidden: true,
+ props: {
+ item: {
+ ...wrapper.props('item'),
+ hidden: true,
+ },
},
});
});
@@ -247,11 +249,13 @@ describe('Board card component', () => {
describe('with avatar', () => {
beforeEach(() => {
createWrapper({
- item: {
- ...wrapper.props('item'),
- assignees: [user],
- updateData(newData) {
- Object.assign(this, newData);
+ props: {
+ item: {
+ ...wrapper.props('item'),
+ assignees: [user],
+ updateData(newData) {
+ Object.assign(this, newData);
+ },
},
},
});
@@ -300,15 +304,17 @@ describe('Board card component', () => {
global.gon.default_avatar_url = 'default_avatar';
createWrapper({
- item: {
- ...wrapper.props('item'),
- assignees: [
- {
- id: 1,
- name: 'testing 123',
- username: 'test',
- },
- ],
+ props: {
+ item: {
+ ...wrapper.props('item'),
+ assignees: [
+ {
+ id: 1,
+ name: 'testing 123',
+ username: 'test',
+ },
+ ],
+ },
},
});
});
@@ -329,28 +335,30 @@ describe('Board card component', () => {
describe('multiple assignees', () => {
beforeEach(() => {
createWrapper({
- item: {
- ...wrapper.props('item'),
- assignees: [
- {
- id: 2,
- name: 'user2',
- username: 'user2',
- avatarUrl: 'test_image',
- },
- {
- id: 3,
- name: 'user3',
- username: 'user3',
- avatarUrl: 'test_image',
- },
- {
- id: 4,
- name: 'user4',
- username: 'user4',
- avatarUrl: 'test_image',
- },
- ],
+ props: {
+ item: {
+ ...wrapper.props('item'),
+ assignees: [
+ {
+ id: 2,
+ name: 'user2',
+ username: 'user2',
+ avatarUrl: 'test_image',
+ },
+ {
+ id: 3,
+ name: 'user3',
+ username: 'user3',
+ avatarUrl: 'test_image',
+ },
+ {
+ id: 4,
+ name: 'user4',
+ username: 'user4',
+ avatarUrl: 'test_image',
+ },
+ ],
+ },
},
});
});
@@ -370,9 +378,11 @@ describe('Board card component', () => {
});
createWrapper({
- item: {
- ...wrapper.props('item'),
- assignees,
+ props: {
+ item: {
+ ...wrapper.props('item'),
+ assignees,
+ },
},
});
});
@@ -396,9 +406,11 @@ describe('Board card component', () => {
})),
];
createWrapper({
- item: {
- ...wrapper.props('item'),
- assignees,
+ props: {
+ item: {
+ ...wrapper.props('item'),
+ assignees,
+ },
},
});
@@ -411,7 +423,7 @@ describe('Board card component', () => {
describe('labels', () => {
beforeEach(() => {
- createWrapper({ item: { ...issue, labels: [list.label, label1] } });
+ createWrapper({ props: { item: { ...issue, labels: [list.label, label1] } } });
});
it('does not render list label but renders all other labels', () => {
@@ -423,7 +435,7 @@ describe('Board card component', () => {
});
it('does not render label if label does not have an ID', async () => {
- createWrapper({ item: { ...issue, labels: [label1, { title: 'closed' }] } });
+ createWrapper({ props: { item: { ...issue, labels: [label1, { title: 'closed' }] } } });
await nextTick();
@@ -435,11 +447,13 @@ describe('Board card component', () => {
describe('filterByLabel method', () => {
beforeEach(() => {
createWrapper({
- item: {
- ...issue,
- labels: [label1],
+ props: {
+ item: {
+ ...issue,
+ labels: [label1],
+ },
+ updateFilters: true,
},
- updateFilters: true,
});
});
@@ -486,9 +500,11 @@ describe('Board card component', () => {
describe('loading', () => {
it('renders loading icon', async () => {
createWrapper({
- item: {
- ...issue,
- isLoading: true,
+ props: {
+ item: {
+ ...issue,
+ isLoading: true,
+ },
},
});
@@ -510,17 +526,20 @@ describe('Board card component', () => {
};
beforeEach(() => {
- createStore({ isEpicBoard: true });
+ createStore();
});
it('should render if the item has issues', () => {
createWrapper({
- item: {
- ...issue,
- descendantCounts,
- descendantWeightSum,
- hasIssues: true,
+ props: {
+ item: {
+ ...issue,
+ descendantCounts,
+ descendantWeightSum,
+ hasIssues: true,
+ },
},
+ isEpicBoard: true,
});
expect(findEpicCountables().exists()).toBe(true);
@@ -541,18 +560,21 @@ describe('Board card component', () => {
it('shows render item countBadge, weights, and progress correctly', () => {
createWrapper({
- item: {
- ...issue,
- descendantCounts: {
- ...descendantCounts,
- openedIssues: 1,
- },
- descendantWeightSum: {
- closedIssues: 10,
- openedIssues: 5,
+ props: {
+ item: {
+ ...issue,
+ descendantCounts: {
+ ...descendantCounts,
+ openedIssues: 1,
+ },
+ descendantWeightSum: {
+ closedIssues: 10,
+ openedIssues: 5,
+ },
+ hasIssues: true,
},
- hasIssues: true,
},
+ isEpicBoard: true,
});
expect(findEpicCountablesBadgeIssues().text()).toBe('1');
@@ -562,15 +584,18 @@ describe('Board card component', () => {
it('does not render progress when weight is zero', () => {
createWrapper({
- item: {
- ...issue,
- descendantCounts: {
- ...descendantCounts,
- openedIssues: 1,
+ props: {
+ item: {
+ ...issue,
+ descendantCounts: {
+ ...descendantCounts,
+ openedIssues: 1,
+ },
+ descendantWeightSum,
+ hasIssues: true,
},
- descendantWeightSum,
- hasIssues: true,
},
+ isEpicBoard: true,
});
expect(findEpicBadgeProgress().exists()).toBe(false);
@@ -578,15 +603,18 @@ describe('Board card component', () => {
it('renders the tooltip with the correct data', () => {
createWrapper({
- item: {
- ...issue,
- descendantCounts,
- descendantWeightSum: {
- closedIssues: 10,
- openedIssues: 5,
+ props: {
+ item: {
+ ...issue,
+ descendantCounts,
+ descendantWeightSum: {
+ closedIssues: 10,
+ openedIssues: 5,
+ },
+ hasIssues: true,
},
- hasIssues: true,
},
+ isEpicBoard: true,
});
const tooltip = findEpicCountablesTotalTooltip();
@@ -595,10 +623,5 @@ describe('Board card component', () => {
expect(findEpicCountablesTotalWeight().text()).toBe('15');
expect(findEpicProgressTooltip().text()).toBe('10 of 15 weight completed');
});
-
- it('does not render the move to position icon', () => {
- createWrapper();
- expect(findMoveToPositionComponent().exists()).toBe(false);
- });
});
});
diff --git a/spec/frontend/boards/board_list_helper.js b/spec/frontend/boards/board_list_helper.js
index 65a41c49e7f..c5c3faf1712 100644
--- a/spec/frontend/boards/board_list_helper.js
+++ b/spec/frontend/boards/board_list_helper.js
@@ -101,6 +101,8 @@ export default function createComponent({
weightFeatureAvailable: false,
boardWeight: null,
canAdminList: true,
+ isIssueBoard: true,
+ isEpicBoard: false,
...provide,
},
stubs,
diff --git a/spec/frontend/boards/board_list_spec.js b/spec/frontend/boards/board_list_spec.js
index 9b0c0b93ffb..3a2beb714e9 100644
--- a/spec/frontend/boards/board_list_spec.js
+++ b/spec/frontend/boards/board_list_spec.js
@@ -6,6 +6,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import createComponent from 'jest/boards/board_list_helper';
import BoardCard from '~/boards/components/board_card.vue';
import eventHub from '~/boards/eventhub';
+import BoardCardMoveToPosition from '~/boards/components/board_card_move_to_position.vue';
import { mockIssues } from './mock_data';
@@ -15,6 +16,7 @@ describe('Board list component', () => {
const findByTestId = (testId) => wrapper.find(`[data-testid="${testId}"]`);
const findIssueCountLoadingIcon = () => wrapper.find('[data-testid="count-loading-icon"]');
const findDraggable = () => wrapper.findComponent(Draggable);
+ const findMoveToPositionComponent = () => wrapper.findComponent(BoardCardMoveToPosition);
const startDrag = (
params = {
@@ -99,6 +101,10 @@ describe('Board list component', () => {
await nextTick();
expect(wrapper.find('.board-list-count').attributes('data-issue-id')).toBe('-1');
});
+
+ it('renders the move to position icon', () => {
+ expect(findMoveToPositionComponent().exists()).toBe(true);
+ });
});
describe('load more issues', () => {
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 5fae1c4359f..a3b2988ce75 100644
--- a/spec/frontend/boards/components/board_add_new_column_spec.js
+++ b/spec/frontend/boards/components/board_add_new_column_spec.js
@@ -53,11 +53,11 @@ describe('Board card layout', () => {
state: {
labels,
labelsLoading: false,
- isEpicBoard: false,
},
}),
provide: {
scopedLabelsAvailable: true,
+ isEpicBoard: false,
},
}),
);
diff --git a/spec/frontend/boards/components/board_app_spec.js b/spec/frontend/boards/components/board_app_spec.js
index dee097bfb08..c209f2f82e6 100644
--- a/spec/frontend/boards/components/board_app_spec.js
+++ b/spec/frontend/boards/components/board_app_spec.js
@@ -28,6 +28,7 @@ describe('BoardApp', () => {
store,
provide: {
...provide,
+ fullBoardId: 'gid://gitlab/Board/1',
},
});
};
diff --git a/spec/frontend/boards/components/board_card_move_to_position_spec.js b/spec/frontend/boards/components/board_card_move_to_position_spec.js
index 7254b9486ef..8dee3c77787 100644
--- a/spec/frontend/boards/components/board_card_move_to_position_spec.js
+++ b/spec/frontend/boards/components/board_card_move_to_position_spec.js
@@ -48,6 +48,7 @@ describe('Board Card Move to position', () => {
propsData: {
item: mockIssue2,
list: mockList,
+ listItemsLength: 3,
index: 0,
...propsData,
},
diff --git a/spec/frontend/boards/components/board_card_spec.js b/spec/frontend/boards/components/board_card_spec.js
index 2feaa5dff8c..38b79e2e3f3 100644
--- a/spec/frontend/boards/components/board_card_spec.js
+++ b/spec/frontend/boards/components/board_card_spec.js
@@ -30,7 +30,6 @@ describe('Board card', () => {
},
actions: mockActions,
getters: {
- isEpicBoard: () => false,
isProjectBoard: () => false,
},
});
@@ -61,6 +60,7 @@ describe('Board card', () => {
groupId: null,
rootPath: '/',
scopedLabelsAvailable: false,
+ isEpicBoard: false,
...provide,
},
});
diff --git a/spec/frontend/boards/components/board_content_spec.js b/spec/frontend/boards/components/board_content_spec.js
index 97d9e08f5d4..b2138700602 100644
--- a/spec/frontend/boards/components/board_content_spec.js
+++ b/spec/frontend/boards/components/board_content_spec.js
@@ -1,15 +1,20 @@
import { GlAlert } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
import Draggable from 'vuedraggable';
import Vuex from 'vuex';
+import waitForPromises from 'helpers/wait_for_promises';
+import createMockApollo from 'helpers/mock_apollo_helper';
import EpicsSwimlanes from 'ee_component/boards/components/epics_swimlanes.vue';
import getters from 'ee_else_ce/boards/stores/getters';
+import boardListsQuery from 'ee_else_ce/boards/graphql/board_lists.query.graphql';
import BoardColumn from '~/boards/components/board_column.vue';
import BoardContent from '~/boards/components/board_content.vue';
import BoardContentSidebar from '~/boards/components/board_content_sidebar.vue';
-import { mockLists } from '../mock_data';
+import { mockLists, boardListsQueryResponse } from '../mock_data';
+Vue.use(VueApollo);
Vue.use(Vuex);
const actions = {
@@ -18,6 +23,7 @@ const actions = {
describe('BoardContent', () => {
let wrapper;
+ let fakeApollo;
window.gon = {};
const defaultState = {
@@ -35,26 +41,68 @@ describe('BoardContent', () => {
});
};
- const createComponent = ({ state, props = {}, canAdminList = true } = {}) => {
+ const createComponent = ({
+ state,
+ props = {},
+ canAdminList = true,
+ isApolloBoard = false,
+ issuableType = 'issue',
+ isIssueBoard = true,
+ isEpicBoard = false,
+ boardListQueryHandler = jest.fn().mockResolvedValue(boardListsQueryResponse),
+ } = {}) => {
+ fakeApollo = createMockApollo([[boardListsQuery, boardListQueryHandler]]);
+
const store = createStore({
...defaultState,
...state,
});
wrapper = shallowMount(BoardContent, {
+ apolloProvider: fakeApollo,
propsData: {
- lists: mockLists,
disabled: false,
+ boardId: 'gid://gitlab/Board/1',
...props,
},
provide: {
canAdminList,
+ boardType: 'group',
+ fullPath: 'gitlab-org/gitlab',
+ issuableType,
+ isIssueBoard,
+ isEpicBoard,
+ isApolloBoard,
},
store,
});
};
+ beforeAll(() => {
+ global.ResizeObserver = class MockResizeObserver {
+ constructor(callback) {
+ this.callback = callback;
+
+ this.entries = [];
+ }
+
+ observe(entry) {
+ this.entries.push(entry);
+ }
+
+ disconnect() {
+ this.entries = [];
+ this.callback = null;
+ }
+
+ trigger() {
+ this.callback(this.entries);
+ }
+ };
+ });
+
afterEach(() => {
wrapper.destroy();
+ fakeApollo = null;
});
describe('default', () => {
@@ -74,11 +122,22 @@ describe('BoardContent', () => {
expect(wrapper.findComponent(EpicsSwimlanes).exists()).toBe(false);
expect(wrapper.findComponent(GlAlert).exists()).toBe(false);
});
+
+ it('resizes the list on resize', async () => {
+ window.innerHeight = 1000;
+ jest.spyOn(Element.prototype, 'getBoundingClientRect').mockReturnValue({ top: 100 });
+
+ wrapper.vm.resizeObserver.trigger();
+
+ await nextTick();
+
+ expect(wrapper.findComponent({ ref: 'list' }).attributes('style')).toBe('height: 900px;');
+ });
});
describe('when issuableType is not issue', () => {
beforeEach(() => {
- createComponent({ state: { issuableType: 'foo' } });
+ createComponent({ issuableType: 'foo', isIssueBoard: false });
});
it('does not render BoardContentSidebar', () => {
@@ -105,4 +164,19 @@ describe('BoardContent', () => {
expect(wrapper.findComponent(Draggable).exists()).toBe(false);
});
});
+
+ describe('when Apollo boards FF is on', () => {
+ beforeEach(async () => {
+ createComponent({ isApolloBoard: true });
+ await waitForPromises();
+ });
+
+ it('renders a BoardColumn component per list', () => {
+ expect(wrapper.findAllComponents(BoardColumn)).toHaveLength(mockLists.length);
+ });
+
+ it('renders BoardContentSidebar', () => {
+ expect(wrapper.findComponent(BoardContentSidebar).exists()).toBe(true);
+ });
+ });
});
diff --git a/spec/frontend/boards/components/board_filtered_search_spec.js b/spec/frontend/boards/components/board_filtered_search_spec.js
index 1a07b9f0b78..6f17e4193a3 100644
--- a/spec/frontend/boards/components/board_filtered_search_spec.js
+++ b/spec/frontend/boards/components/board_filtered_search_spec.js
@@ -3,7 +3,19 @@ import Vue from 'vue';
import Vuex from 'vuex';
import BoardFilteredSearch from '~/boards/components/board_filtered_search.vue';
import * as urlUtility from '~/lib/utils/url_utility';
-import { __ } from '~/locale';
+import {
+ TOKEN_TITLE_AUTHOR,
+ TOKEN_TITLE_LABEL,
+ TOKEN_TYPE_ASSIGNEE,
+ TOKEN_TYPE_AUTHOR,
+ TOKEN_TYPE_HEALTH,
+ TOKEN_TYPE_ITERATION,
+ TOKEN_TYPE_LABEL,
+ TOKEN_TYPE_MILESTONE,
+ TOKEN_TYPE_RELEASE,
+ TOKEN_TYPE_TYPE,
+ TOKEN_TYPE_WEIGHT,
+} from '~/vue_shared/components/filtered_search_bar/constants';
import FilteredSearchBarRoot from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
@@ -17,7 +29,7 @@ describe('BoardFilteredSearch', () => {
const tokens = [
{
icon: 'labels',
- title: __('Label'),
+ title: TOKEN_TITLE_LABEL,
type: 'label',
operators: [
{ value: '=', description: 'is' },
@@ -30,7 +42,7 @@ describe('BoardFilteredSearch', () => {
},
{
icon: 'pencil',
- title: __('Author'),
+ title: TOKEN_TITLE_AUTHOR,
type: 'author',
operators: [
{ value: '=', description: 'is' },
@@ -117,16 +129,16 @@ describe('BoardFilteredSearch', () => {
it('sets the url params to the correct results', async () => {
const mockFilters = [
- { type: 'author', value: { data: 'root', operator: '=' } },
- { type: 'assignee', value: { data: 'root', operator: '=' } },
- { type: 'label', value: { data: 'label', operator: '=' } },
- { type: 'label', value: { data: 'label&2', operator: '=' } },
- { type: 'milestone', value: { data: 'New Milestone', operator: '=' } },
- { type: 'type', value: { data: 'INCIDENT', operator: '=' } },
- { type: 'weight', value: { data: '2', operator: '=' } },
- { type: 'iteration', value: { data: 'Any&3', operator: '=' } },
- { type: 'release', value: { data: 'v1.0.0', operator: '=' } },
- { type: 'health_status', value: { data: 'onTrack', operator: '=' } },
+ { type: TOKEN_TYPE_AUTHOR, value: { data: 'root', operator: '=' } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'root', operator: '=' } },
+ { type: TOKEN_TYPE_LABEL, value: { data: 'label', operator: '=' } },
+ { type: TOKEN_TYPE_LABEL, value: { data: 'label&2', operator: '=' } },
+ { type: TOKEN_TYPE_MILESTONE, value: { data: 'New Milestone', operator: '=' } },
+ { type: TOKEN_TYPE_TYPE, value: { data: 'INCIDENT', operator: '=' } },
+ { type: TOKEN_TYPE_WEIGHT, value: { data: '2', operator: '=' } },
+ { type: TOKEN_TYPE_ITERATION, value: { data: 'Any&3', operator: '=' } },
+ { type: TOKEN_TYPE_RELEASE, value: { data: 'v1.0.0', operator: '=' } },
+ { type: TOKEN_TYPE_HEALTH, value: { data: 'onTrack', operator: '=' } },
];
jest.spyOn(urlUtility, 'updateHistory');
findFilteredSearch().vm.$emit('onFilter', mockFilters);
@@ -170,9 +182,9 @@ describe('BoardFilteredSearch', () => {
it('passes the correct props to FilterSearchBar', () => {
expect(findFilteredSearch().props('initialFilterValue')).toEqual([
- { type: 'author', value: { data: 'root', operator: '=' } },
- { type: 'label', value: { data: 'label', operator: '=' } },
- { type: 'health_status', value: { data: 'Any', operator: '=' } },
+ { type: TOKEN_TYPE_AUTHOR, value: { data: 'root', operator: '=' } },
+ { type: TOKEN_TYPE_LABEL, value: { data: 'label', operator: '=' } },
+ { type: TOKEN_TYPE_HEALTH, value: { data: 'Any', operator: '=' } },
]);
});
});
diff --git a/spec/frontend/boards/components/board_list_header_spec.js b/spec/frontend/boards/components/board_list_header_spec.js
index 50901f3fe84..4633612891c 100644
--- a/spec/frontend/boards/components/board_list_header_spec.js
+++ b/spec/frontend/boards/components/board_list_header_spec.js
@@ -59,7 +59,6 @@ describe('Board List Header Component', () => {
store = new Vuex.Store({
state: {},
actions: { updateList: updateListSpy, toggleListCollapsed: toggleListCollapsedSpy },
- getters: { isEpicBoard: () => false },
});
fakeApollo = createMockApollo([[listQuery, listQueryHandler]]);
@@ -76,6 +75,7 @@ describe('Board List Header Component', () => {
boardId,
weightFeatureAvailable: false,
currentUserId,
+ isEpicBoard: false,
},
}),
);
diff --git a/spec/frontend/boards/components/board_settings_sidebar_spec.js b/spec/frontend/boards/components/board_settings_sidebar_spec.js
index 4171a6236de..7d602042685 100644
--- a/spec/frontend/boards/components/board_settings_sidebar_spec.js
+++ b/spec/frontend/boards/components/board_settings_sidebar_spec.js
@@ -45,6 +45,7 @@ describe('BoardSettingsSidebar', () => {
provide: {
canAdminList,
scopedLabelsAvailable: false,
+ isIssueBoard: true,
},
directives: {
GlModal: createMockDirective(),
diff --git a/spec/frontend/boards/components/board_top_bar_spec.js b/spec/frontend/boards/components/board_top_bar_spec.js
index 997768a0cc7..08b5042f70f 100644
--- a/spec/frontend/boards/components/board_top_bar_spec.js
+++ b/spec/frontend/boards/components/board_top_bar_spec.js
@@ -15,18 +15,14 @@ describe('BoardTopBar', () => {
Vue.use(Vuex);
- const createStore = ({ mockGetters = {} } = {}) => {
+ const createStore = () => {
return new Vuex.Store({
state: {},
- getters: {
- isEpicBoard: () => false,
- ...mockGetters,
- },
});
};
- const createComponent = ({ provide = {}, mockGetters = {} } = {}) => {
- const store = createStore({ mockGetters });
+ const createComponent = ({ provide = {} } = {}) => {
+ const store = createStore();
wrapper = shallowMount(BoardTopBar, {
store,
provide: {
@@ -36,6 +32,7 @@ describe('BoardTopBar', () => {
fullPath: 'gitlab-org',
boardType: 'group',
releasesFetchPath: '/releases',
+ isIssueBoard: true,
...provide,
},
stubs: { IssueBoardFilteredSearch },
diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js
index dc1f3246be0..3c26fa97338 100644
--- a/spec/frontend/boards/mock_data.js
+++ b/spec/frontend/boards/mock_data.js
@@ -1,7 +1,22 @@
import { GlFilteredSearchToken } from '@gitlab/ui';
import { keyBy } from 'lodash';
import { ListType } from '~/boards/constants';
-import { __ } from '~/locale';
+import {
+ OPERATOR_IS_AND_IS_NOT,
+ OPERATOR_IS_ONLY,
+ TOKEN_TITLE_ASSIGNEE,
+ TOKEN_TITLE_AUTHOR,
+ TOKEN_TITLE_LABEL,
+ TOKEN_TITLE_MILESTONE,
+ TOKEN_TITLE_RELEASE,
+ TOKEN_TITLE_TYPE,
+ TOKEN_TYPE_ASSIGNEE,
+ TOKEN_TYPE_AUTHOR,
+ TOKEN_TYPE_LABEL,
+ TOKEN_TYPE_MILESTONE,
+ TOKEN_TYPE_RELEASE,
+ TOKEN_TYPE_TYPE,
+} from '~/vue_shared/components/filtered_search_bar/constants';
import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue';
import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue';
import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue';
@@ -433,8 +448,11 @@ export const mockList = {
label: null,
assignee: null,
milestone: null,
+ iteration: null,
loading: false,
issuesCount: 1,
+ maxIssueCount: 0,
+ __typename: 'BoardList',
};
export const mockLabelList = {
@@ -449,11 +467,15 @@ export const mockLabelList = {
color: '#F0AD4E',
textColor: '#FFFFFF',
description: null,
+ descriptionHtml: null,
},
assignee: null,
milestone: null,
+ iteration: null,
loading: false,
issuesCount: 0,
+ maxIssueCount: 0,
+ __typename: 'BoardList',
};
export const mockMilestoneList = {
@@ -725,7 +747,7 @@ export const mockConfidentialToken = {
title: 'Confidential',
unique: true,
token: GlFilteredSearchToken,
- operators: [{ value: '=', description: 'is' }],
+ operators: OPERATOR_IS_ONLY,
options: [
{ icon: 'eye-slash', value: 'yes', title: 'Yes' },
{ icon: 'eye', value: 'no', title: 'No' },
@@ -735,12 +757,9 @@ export const mockConfidentialToken = {
export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, isSignedIn) => [
{
icon: 'user',
- title: __('Assignee'),
- type: 'assignee',
- operators: [
- { value: '=', description: 'is' },
- { value: '!=', description: 'is not' },
- ],
+ title: TOKEN_TITLE_ASSIGNEE,
+ type: TOKEN_TYPE_ASSIGNEE,
+ operators: OPERATOR_IS_AND_IS_NOT,
token: AuthorToken,
unique: true,
fetchAuthors,
@@ -748,12 +767,9 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, isSignedI
},
{
icon: 'pencil',
- title: __('Author'),
- type: 'author',
- operators: [
- { value: '=', description: 'is' },
- { value: '!=', description: 'is not' },
- ],
+ title: TOKEN_TITLE_AUTHOR,
+ type: TOKEN_TYPE_AUTHOR,
+ operators: OPERATOR_IS_AND_IS_NOT,
symbol: '@',
token: AuthorToken,
unique: true,
@@ -762,12 +778,9 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, isSignedI
},
{
icon: 'labels',
- title: __('Label'),
- type: 'label',
- operators: [
- { value: '=', description: 'is' },
- { value: '!=', description: 'is not' },
- ],
+ title: TOKEN_TITLE_LABEL,
+ type: TOKEN_TYPE_LABEL,
+ operators: OPERATOR_IS_AND_IS_NOT,
token: LabelToken,
unique: false,
symbol: '~',
@@ -776,9 +789,9 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, isSignedI
...(isSignedIn ? [mockEmojiToken, mockConfidentialToken] : []),
{
icon: 'clock',
- title: __('Milestone'),
+ title: TOKEN_TITLE_MILESTONE,
symbol: '%',
- type: 'milestone',
+ type: TOKEN_TYPE_MILESTONE,
shouldSkipSort: true,
token: MilestoneToken,
unique: true,
@@ -786,8 +799,8 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, isSignedI
},
{
icon: 'issues',
- title: __('Type'),
- type: 'type',
+ title: TOKEN_TITLE_TYPE,
+ type: TOKEN_TYPE_TYPE,
token: GlFilteredSearchToken,
unique: true,
options: [
@@ -796,8 +809,8 @@ export const mockTokens = (fetchLabels, fetchAuthors, fetchMilestones, isSignedI
],
},
{
- type: 'release',
- title: __('Release'),
+ type: TOKEN_TYPE_RELEASE,
+ title: TOKEN_TITLE_RELEASE,
icon: 'rocket',
token: ReleaseToken,
fetchReleases: expect.any(Function),
@@ -844,6 +857,22 @@ export const mockGroupLabelsResponse = {
},
};
+export const boardListsQueryResponse = {
+ data: {
+ group: {
+ id: 'gid://gitlab/Group/1',
+ board: {
+ id: 'gid://gitlab/Board/1',
+ hideBacklogList: false,
+ lists: {
+ nodes: mockLists,
+ },
+ },
+ __typename: 'Group',
+ },
+ },
+};
+
export const boardListQueryResponse = (issuesCount = 20) => ({
data: {
boardList: {
diff --git a/spec/frontend/boards/stores/actions_spec.js b/spec/frontend/boards/stores/actions_spec.js
index 78859525a63..b3e90e34161 100644
--- a/spec/frontend/boards/stores/actions_spec.js
+++ b/spec/frontend/boards/stores/actions_spec.js
@@ -8,7 +8,6 @@ import {
ListType,
issuableTypes,
BoardType,
- listsQuery,
DraggableItemTypes,
} from 'ee_else_ce/boards/constants';
import issueMoveListMutation from 'ee_else_ce/boards/graphql/issue_move_list.mutation.graphql';
@@ -21,7 +20,7 @@ import {
getMoveData,
updateListPosition,
} from 'ee_else_ce/boards/boards_util';
-import { gqlClient } from '~/boards/graphql';
+import { defaultClient as gqlClient } from '~/graphql_shared/issuable_client';
import destroyBoardListMutation from '~/boards/graphql/board_list_destroy.mutation.graphql';
import issueCreateMutation from '~/boards/graphql/issue_create.mutation.graphql';
import actions from '~/boards/stores/actions';
@@ -318,21 +317,18 @@ describe('fetchLists', () => {
};
const variables = {
- query: listsQuery[issuableType].query,
- variables: {
- fullPath: 'gitlab-org',
- boardId: fullBoardId,
- filters: {},
- isGroup,
- isProject,
- },
+ fullPath: 'gitlab-org',
+ boardId: fullBoardId,
+ filters: {},
+ isGroup,
+ isProject,
};
jest.spyOn(gqlClient, 'query').mockResolvedValue(queryResponse);
await actions.fetchLists({ commit, state, dispatch });
- expect(gqlClient.query).toHaveBeenCalledWith(variables);
+ expect(gqlClient.query).toHaveBeenCalledWith(expect.objectContaining({ variables }));
},
);
});
diff --git a/spec/frontend/branches/components/__snapshots__/delete_merged_branches_spec.js.snap b/spec/frontend/branches/components/__snapshots__/delete_merged_branches_spec.js.snap
new file mode 100644
index 00000000000..6aab3b51806
--- /dev/null
+++ b/spec/frontend/branches/components/__snapshots__/delete_merged_branches_spec.js.snap
@@ -0,0 +1,139 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Delete merged branches component Delete merged branches confirmation modal matches snapshot 1`] = `
+<div>
+ <b-button-stub
+ class="gl-mr-3 gl-button btn-danger-secondary"
+ data-qa-selector="delete_merged_branches_button"
+ size="md"
+ tag="button"
+ type="button"
+ variant="danger"
+ >
+ <!---->
+
+ <!---->
+
+ <span
+ class="gl-button-text"
+ >
+ Delete merged branches
+
+ </span>
+ </b-button-stub>
+
+ <div>
+ <form
+ action="/namespace/project/-/merged_branches"
+ method="post"
+ >
+ <p>
+ You are about to
+ <strong>
+ delete all branches
+ </strong>
+ that were merged into
+ <code>
+ master
+ </code>
+ .
+ </p>
+
+ <p>
+
+ This may include merged branches that are not visible on the current screen.
+
+ </p>
+
+ <p>
+
+ A branch won't be deleted if it is protected or associated with an open merge request.
+
+ </p>
+
+ <p>
+ This bulk action is
+ <strong>
+ permanent and cannot be undone or recovered
+ </strong>
+ .
+ </p>
+
+ <p>
+ Plese type the following to confirm:
+ <code>
+ delete
+ </code>
+ .
+ <b-form-input-stub
+ aria-labelledby="input-label"
+ autocomplete="off"
+ class="gl-form-input gl-mt-2 gl-form-input-sm"
+ data-qa-selector="delete_merged_branches_input"
+ debounce="0"
+ formatter="[Function]"
+ type="text"
+ value=""
+ />
+ </p>
+
+ <input
+ name="_method"
+ type="hidden"
+ value="delete"
+ />
+
+ <input
+ name="authenticity_token"
+ type="hidden"
+ value="mock-csrf-token"
+ />
+ </form>
+ <div
+ class="gl-display-flex gl-flex-direction-row gl-justify-content-end gl-flex-wrap gl-m-0 gl-mr-3"
+ >
+ <b-button-stub
+ class="gl-button"
+ data-testid="delete-merged-branches-cancel-button"
+ size="md"
+ tag="button"
+ type="button"
+ variant="default"
+ >
+ <!---->
+
+ <!---->
+
+ <span
+ class="gl-button-text"
+ >
+
+ Cancel
+
+ </span>
+ </b-button-stub>
+
+ <b-button-stub
+ class="gl-button"
+ data-qa-selector="delete_merged_branches_confirmation_button"
+ data-testid="delete-merged-branches-confirmation-button"
+ disabled="true"
+ size="md"
+ tag="button"
+ type="button"
+ variant="danger"
+ >
+ <!---->
+
+ <!---->
+
+ <span
+ class="gl-button-text"
+ >
+ Delete merged branches
+ </span>
+ </b-button-stub>
+ </div>
+ </div>
+</div>
+`;
diff --git a/spec/frontend/branches/components/delete_merged_branches_spec.js b/spec/frontend/branches/components/delete_merged_branches_spec.js
new file mode 100644
index 00000000000..4f1e772f4a4
--- /dev/null
+++ b/spec/frontend/branches/components/delete_merged_branches_spec.js
@@ -0,0 +1,143 @@
+import { GlButton, GlModal, GlFormInput, GlSprintf } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { stubComponent } from 'helpers/stub_component';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import DeleteMergedBranches, { i18n } from '~/branches/components/delete_merged_branches.vue';
+import { formPath, propsDataMock } from '../mock_data';
+
+jest.mock('~/lib/utils/csrf', () => ({ token: 'mock-csrf-token' }));
+
+let wrapper;
+
+const stubsData = {
+ GlModal: stubComponent(GlModal, {
+ template:
+ '<div><slot name="modal-title"></slot><slot></slot><slot name="modal-footer"></slot></div>',
+ }),
+ GlButton,
+ GlFormInput,
+ GlSprintf,
+};
+
+const createComponent = (mountFn = shallowMountExtended, stubs = {}) => {
+ wrapper = mountFn(DeleteMergedBranches, {
+ propsData: {
+ ...propsDataMock,
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ stubs,
+ });
+};
+
+const findDeleteButton = () => wrapper.findComponent(GlButton);
+const findModal = () => wrapper.findComponent(GlModal);
+const findConfirmationButton = () =>
+ wrapper.findByTestId('delete-merged-branches-confirmation-button');
+const findCancelButton = () => wrapper.findByTestId('delete-merged-branches-cancel-button');
+const findFormInput = () => wrapper.findComponent(GlFormInput);
+const findForm = () => wrapper.find('form');
+const submitFormSpy = () => jest.spyOn(wrapper.vm.$refs.form, 'submit');
+
+describe('Delete merged branches component', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ describe('Delete merged branches button', () => {
+ it('has correct attributes, text and tooltip', () => {
+ expect(findDeleteButton().attributes()).toMatchObject({
+ category: 'secondary',
+ variant: 'danger',
+ });
+
+ expect(findDeleteButton().text()).toBe(i18n.deleteButtonText);
+ });
+
+ it('displays a tooltip', () => {
+ const tooltip = getBinding(findDeleteButton().element, 'gl-tooltip');
+
+ expect(tooltip).toBeDefined();
+ expect(tooltip.value).toBe(wrapper.vm.buttonTooltipText);
+ });
+
+ it('opens modal when clicked', () => {
+ createComponent(mount);
+ jest.spyOn(wrapper.vm.$refs.modal, 'show');
+ findDeleteButton().trigger('click');
+
+ expect(wrapper.vm.$refs.modal.show).toHaveBeenCalled();
+ });
+ });
+
+ describe('Delete merged branches confirmation modal', () => {
+ beforeEach(() => {
+ createComponent(shallowMountExtended, stubsData);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders correct modal title and text', () => {
+ const modalText = findModal().text();
+ expect(findModal().props('title')).toBe(i18n.modalTitle);
+ expect(modalText).toContain(i18n.notVisibleBranchesWarning);
+ expect(modalText).toContain(i18n.protectedBranchWarning);
+ });
+
+ it('renders confirm and cancel buttons with correct text', () => {
+ expect(findConfirmationButton().text()).toContain(i18n.deleteButtonText);
+ expect(findCancelButton().text()).toContain(i18n.cancelButtonText);
+ });
+
+ it('renders form with correct attributes and hiden inputs', () => {
+ const form = findForm();
+ expect(form.attributes()).toEqual({
+ action: formPath,
+ method: 'post',
+ });
+ expect(form.find('input[name="_method"]').attributes('value')).toBe('delete');
+ expect(form.find('input[name="authenticity_token"]').attributes('value')).toBe(
+ 'mock-csrf-token',
+ );
+ });
+
+ it('matches snapshot', () => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('has a disabled confirm button by default', () => {
+ expect(findConfirmationButton().props('disabled')).toBe(true);
+ });
+
+ it('keeps disabled state when wrong input is provided', async () => {
+ findFormInput().vm.$emit('input', 'hello');
+ await waitForPromises();
+ expect(findConfirmationButton().props('disabled')).toBe(true);
+ findConfirmationButton().trigger('click');
+
+ expect(submitFormSpy()).not.toHaveBeenCalled();
+ findFormInput().trigger('keyup.enter');
+
+ expect(submitFormSpy()).not.toHaveBeenCalled();
+ });
+
+ it('submits form when correct amount is provided and the confirm button is clicked', async () => {
+ findFormInput().vm.$emit('input', 'delete');
+ await waitForPromises();
+ expect(findDeleteButton().props('disabled')).not.toBe(true);
+ findConfirmationButton().trigger('click');
+ expect(submitFormSpy()).toHaveBeenCalled();
+ });
+
+ it('calls hide on the modal when cancel button is clicked', () => {
+ const closeModalSpy = jest.spyOn(wrapper.vm.$refs.modal, 'hide');
+ findCancelButton().trigger('click');
+ expect(closeModalSpy).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/branches/mock_data.js b/spec/frontend/branches/mock_data.js
new file mode 100644
index 00000000000..9e8839d8ce9
--- /dev/null
+++ b/spec/frontend/branches/mock_data.js
@@ -0,0 +1,7 @@
+export const formPath = '/namespace/project/-/merged_branches';
+const defaultBranch = 'master';
+
+export const propsDataMock = {
+ formPath,
+ defaultBranch,
+};
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
new file mode 100644
index 00000000000..ba948f12b33
--- /dev/null
+++ b/spec/frontend/ci/pipeline_schedules/components/delete_pipeline_schedule_modal_spec.js
@@ -0,0 +1,38 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlModal } from '@gitlab/ui';
+import DeletePipelineScheduleModal from '~/ci/pipeline_schedules/components/delete_pipeline_schedule_modal.vue';
+
+describe('Delete pipeline schedule modal', () => {
+ let wrapper;
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(DeletePipelineScheduleModal, {
+ propsData: {
+ visible: true,
+ ...props,
+ },
+ });
+ };
+
+ const findModal = () => wrapper.findComponent(GlModal);
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('emits the deleteSchedule event', async () => {
+ findModal().vm.$emit('primary');
+
+ expect(wrapper.emitted()).toEqual({ deleteSchedule: [[]] });
+ });
+
+ it('emits the hideModal event', async () => {
+ findModal().vm.$emit('hide');
+
+ expect(wrapper.emitted()).toEqual({ hideModal: [[]] });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js
new file mode 100644
index 00000000000..e5d9b378a42
--- /dev/null
+++ b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_form_spec.js
@@ -0,0 +1,25 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlForm } from '@gitlab/ui';
+import PipelineSchedulesForm from '~/ci/pipeline_schedules/components/pipeline_schedules_form.vue';
+
+describe('Pipeline schedules form', () => {
+ let wrapper;
+
+ const createComponent = () => {
+ wrapper = shallowMount(PipelineSchedulesForm);
+ };
+
+ const findForm = () => wrapper.findComponent(GlForm);
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('displays form', () => {
+ expect(findForm().exists()).toBe(true);
+ });
+});
diff --git a/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js
new file mode 100644
index 00000000000..4aa4cdf89a1
--- /dev/null
+++ b/spec/frontend/ci/pipeline_schedules/components/pipeline_schedules_spec.js
@@ -0,0 +1,280 @@
+import { GlAlert, GlLoadingIcon, GlTabs } from '@gitlab/ui';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import { trimText } from 'helpers/text_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import PipelineSchedules from '~/ci/pipeline_schedules/components/pipeline_schedules.vue';
+import DeletePipelineScheduleModal from '~/ci/pipeline_schedules/components/delete_pipeline_schedule_modal.vue';
+import TakeOwnershipModal from '~/ci/pipeline_schedules/components/take_ownership_modal.vue';
+import PipelineSchedulesTable from '~/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue';
+import deletePipelineScheduleMutation from '~/ci/pipeline_schedules/graphql/mutations/delete_pipeline_schedule.mutation.graphql';
+import takeOwnershipMutation from '~/ci/pipeline_schedules/graphql/mutations/take_ownership.mutation.graphql';
+import getPipelineSchedulesQuery from '~/ci/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql';
+import {
+ mockGetPipelineSchedulesGraphQLResponse,
+ mockPipelineScheduleNodes,
+ deleteMutationResponse,
+ takeOwnershipMutationResponse,
+} from '../mock_data';
+
+Vue.use(VueApollo);
+
+const $toast = {
+ show: jest.fn(),
+};
+
+describe('Pipeline schedules app', () => {
+ let wrapper;
+
+ const successHandler = jest.fn().mockResolvedValue(mockGetPipelineSchedulesGraphQLResponse);
+ const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
+
+ const deleteMutationHandlerSuccess = jest.fn().mockResolvedValue(deleteMutationResponse);
+ const deleteMutationHandlerFailed = jest.fn().mockRejectedValue(new Error('GraphQL error'));
+ const takeOwnershipMutationHandlerSuccess = jest
+ .fn()
+ .mockResolvedValue(takeOwnershipMutationResponse);
+ const takeOwnershipMutationHandlerFailed = jest
+ .fn()
+ .mockRejectedValue(new Error('GraphQL error'));
+
+ const createMockApolloProvider = (
+ requestHandlers = [[getPipelineSchedulesQuery, successHandler]],
+ ) => {
+ return createMockApollo(requestHandlers);
+ };
+
+ const createComponent = (requestHandlers) => {
+ wrapper = mountExtended(PipelineSchedules, {
+ provide: {
+ fullPath: 'gitlab-org/gitlab',
+ },
+ mocks: {
+ $toast,
+ },
+ apolloProvider: createMockApolloProvider(requestHandlers),
+ });
+ };
+
+ const findTable = () => wrapper.findComponent(PipelineSchedulesTable);
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findDeleteModal = () => wrapper.findComponent(DeletePipelineScheduleModal);
+ const findTakeOwnershipModal = () => wrapper.findComponent(TakeOwnershipModal);
+ const findTabs = () => wrapper.findComponent(GlTabs);
+ const findNewButton = () => wrapper.findByTestId('new-schedule-button');
+ const findAllTab = () => wrapper.findByTestId('pipeline-schedules-all-tab');
+ const findActiveTab = () => wrapper.findByTestId('pipeline-schedules-active-tab');
+ const findInactiveTab = () => wrapper.findByTestId('pipeline-schedules-inactive-tab');
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('default', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('displays table, tabs and new button', async () => {
+ await waitForPromises();
+
+ expect(findTable().exists()).toBe(true);
+ expect(findNewButton().exists()).toBe(true);
+ expect(findTabs().exists()).toBe(true);
+ expect(findAlert().exists()).toBe(false);
+ });
+
+ it('handles loading state', async () => {
+ expect(findLoadingIcon().exists()).toBe(true);
+
+ await waitForPromises();
+
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+ });
+
+ describe('fetching pipeline schedules', () => {
+ it('fetches query and passes an array of pipeline schedules', async () => {
+ createComponent();
+
+ expect(successHandler).toHaveBeenCalled();
+
+ await waitForPromises();
+
+ expect(findTable().props('schedules')).toEqual(mockPipelineScheduleNodes);
+ });
+
+ it('shows query error alert', async () => {
+ createComponent([[getPipelineSchedulesQuery, failedHandler]]);
+
+ await waitForPromises();
+
+ expect(findAlert().text()).toBe('There was a problem fetching pipeline schedules.');
+ });
+ });
+
+ describe('deleting a pipeline schedule', () => {
+ it('shows delete mutation error alert', async () => {
+ createComponent([
+ [getPipelineSchedulesQuery, successHandler],
+ [deletePipelineScheduleMutation, deleteMutationHandlerFailed],
+ ]);
+
+ await waitForPromises();
+
+ findDeleteModal().vm.$emit('deleteSchedule');
+
+ await waitForPromises();
+
+ expect(findAlert().text()).toBe('There was a problem deleting the pipeline schedule.');
+ });
+
+ it('deletes pipeline schedule and refetches query', async () => {
+ createComponent([
+ [getPipelineSchedulesQuery, successHandler],
+ [deletePipelineScheduleMutation, deleteMutationHandlerSuccess],
+ ]);
+
+ jest.spyOn(wrapper.vm.$apollo.queries.schedules, 'refetch');
+
+ await waitForPromises();
+
+ const scheduleId = mockPipelineScheduleNodes[0].id;
+
+ findTable().vm.$emit('showDeleteModal', scheduleId);
+
+ expect(wrapper.vm.$apollo.queries.schedules.refetch).not.toHaveBeenCalled();
+
+ findDeleteModal().vm.$emit('deleteSchedule');
+
+ await waitForPromises();
+
+ expect(deleteMutationHandlerSuccess).toHaveBeenCalledWith({
+ id: scheduleId,
+ });
+ expect(wrapper.vm.$apollo.queries.schedules.refetch).toHaveBeenCalled();
+ expect($toast.show).toHaveBeenCalledWith('Pipeline schedule successfully deleted.');
+ });
+
+ it('handles delete modal visibility correctly', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findDeleteModal().props('visible')).toBe(false);
+
+ findTable().vm.$emit('showDeleteModal', mockPipelineScheduleNodes[0].id);
+
+ await nextTick();
+
+ expect(findDeleteModal().props('visible')).toBe(true);
+ expect(findTakeOwnershipModal().props('visible')).toBe(false);
+
+ findDeleteModal().vm.$emit('hideModal');
+
+ await nextTick();
+
+ expect(findDeleteModal().props('visible')).toBe(false);
+ });
+ });
+
+ describe('taking ownership of a pipeline schedule', () => {
+ it('shows take ownership mutation error alert', async () => {
+ createComponent([
+ [getPipelineSchedulesQuery, successHandler],
+ [takeOwnershipMutation, takeOwnershipMutationHandlerFailed],
+ ]);
+
+ await waitForPromises();
+
+ findTakeOwnershipModal().vm.$emit('takeOwnership');
+
+ await waitForPromises();
+
+ expect(findAlert().text()).toBe(
+ 'There was a problem taking ownership of the pipeline schedule.',
+ );
+ });
+
+ it('takes ownership of pipeline schedule and refetches query', async () => {
+ createComponent([
+ [getPipelineSchedulesQuery, successHandler],
+ [takeOwnershipMutation, takeOwnershipMutationHandlerSuccess],
+ ]);
+
+ jest.spyOn(wrapper.vm.$apollo.queries.schedules, 'refetch');
+
+ await waitForPromises();
+
+ const scheduleId = mockPipelineScheduleNodes[1].id;
+
+ findTable().vm.$emit('showTakeOwnershipModal', scheduleId);
+
+ expect(wrapper.vm.$apollo.queries.schedules.refetch).not.toHaveBeenCalled();
+
+ findTakeOwnershipModal().vm.$emit('takeOwnership');
+
+ await waitForPromises();
+
+ expect(takeOwnershipMutationHandlerSuccess).toHaveBeenCalledWith({
+ id: scheduleId,
+ });
+ expect(wrapper.vm.$apollo.queries.schedules.refetch).toHaveBeenCalled();
+ expect($toast.show).toHaveBeenCalledWith('Successfully taken ownership from Admin.');
+ });
+
+ it('handles take ownership modal visibility correctly', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(findTakeOwnershipModal().props('visible')).toBe(false);
+
+ findTable().vm.$emit('showTakeOwnershipModal', mockPipelineScheduleNodes[0].id);
+
+ await nextTick();
+
+ expect(findTakeOwnershipModal().props('visible')).toBe(true);
+ expect(findDeleteModal().props('visible')).toBe(false);
+
+ findTakeOwnershipModal().vm.$emit('hideModal');
+
+ await nextTick();
+
+ expect(findTakeOwnershipModal().props('visible')).toBe(false);
+ });
+ });
+
+ describe('pipeline schedule tabs', () => {
+ beforeEach(async () => {
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('displays All tab with count', () => {
+ expect(trimText(findAllTab().text())).toBe(`All ${mockPipelineScheduleNodes.length}`);
+ });
+
+ it('displays Active tab with no count', () => {
+ expect(findActiveTab().text()).toBe('Active');
+ });
+
+ it('displays Inactive tab with no count', () => {
+ expect(findInactiveTab().text()).toBe('Inactive');
+ });
+
+ it('should refetch the schedules query on a tab click', async () => {
+ jest.spyOn(wrapper.vm.$apollo.queries.schedules, 'refetch').mockImplementation(jest.fn());
+
+ expect(wrapper.vm.$apollo.queries.schedules.refetch).toHaveBeenCalledTimes(0);
+
+ await findAllTab().trigger('click');
+
+ expect(wrapper.vm.$apollo.queries.schedules.refetch).toHaveBeenCalledTimes(1);
+ });
+ });
+});
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
new file mode 100644
index 00000000000..3364c61d155
--- /dev/null
+++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js
@@ -0,0 +1,64 @@
+import { GlButton } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import PipelineScheduleActions from '~/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue';
+import {
+ mockPipelineScheduleNodes,
+ mockPipelineScheduleAsGuestNodes,
+ mockTakeOwnershipNodes,
+} from '../../../mock_data';
+
+describe('Pipeline schedule actions', () => {
+ let wrapper;
+
+ const defaultProps = {
+ schedule: mockPipelineScheduleNodes[0],
+ };
+
+ const createComponent = (props = defaultProps) => {
+ wrapper = shallowMountExtended(PipelineScheduleActions, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ const findAllButtons = () => wrapper.findAllComponents(GlButton);
+ const findDeleteBtn = () => wrapper.findByTestId('delete-pipeline-schedule-btn');
+ const findTakeOwnershipBtn = () => wrapper.findByTestId('take-ownership-pipeline-schedule-btn');
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('displays action buttons', () => {
+ createComponent();
+
+ expect(findAllButtons()).toHaveLength(3);
+ });
+
+ it('does not display action buttons', () => {
+ createComponent({ schedule: mockPipelineScheduleAsGuestNodes[0] });
+
+ expect(findAllButtons()).toHaveLength(0);
+ });
+
+ it('delete button emits showDeleteModal event and schedule id', () => {
+ createComponent();
+
+ findDeleteBtn().vm.$emit('click');
+
+ expect(wrapper.emitted()).toEqual({
+ showDeleteModal: [[mockPipelineScheduleNodes[0].id]],
+ });
+ });
+
+ it('take ownership button emits showTakeOwnershipModal event and schedule id', () => {
+ createComponent({ schedule: mockTakeOwnershipNodes[0] });
+
+ findTakeOwnershipBtn().vm.$emit('click');
+
+ expect(wrapper.emitted()).toEqual({
+ showTakeOwnershipModal: [[mockTakeOwnershipNodes[0].id]],
+ });
+ });
+});
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
new file mode 100644
index 00000000000..17bf465baf3
--- /dev/null
+++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js
@@ -0,0 +1,42 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
+import PipelineScheduleLastPipeline from '~/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline.vue';
+import { mockPipelineScheduleNodes } from '../../../mock_data';
+
+describe('Pipeline schedule last pipeline', () => {
+ let wrapper;
+
+ const defaultProps = {
+ schedule: mockPipelineScheduleNodes[2],
+ };
+
+ const createComponent = (props = defaultProps) => {
+ wrapper = shallowMountExtended(PipelineScheduleLastPipeline, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ const findCIBadge = () => wrapper.findComponent(CiBadge);
+ const findStatusText = () => wrapper.findByTestId('pipeline-schedule-status-text');
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('displays pipeline status', () => {
+ createComponent();
+
+ expect(findCIBadge().exists()).toBe(true);
+ expect(findCIBadge().props('status')).toBe(defaultProps.schedule.lastPipeline.detailedStatus);
+ expect(findStatusText().exists()).toBe(false);
+ });
+
+ it('displays "none" status text', () => {
+ createComponent({ schedule: mockPipelineScheduleNodes[0] });
+
+ expect(findStatusText().text()).toBe('None');
+ expect(findCIBadge().exists()).toBe(false);
+ });
+});
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
new file mode 100644
index 00000000000..1c06c411097
--- /dev/null
+++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js
@@ -0,0 +1,43 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import PipelineScheduleNextRun from '~/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run.vue';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import { mockPipelineScheduleNodes } from '../../../mock_data';
+
+describe('Pipeline schedule next run', () => {
+ let wrapper;
+
+ const defaultProps = {
+ schedule: mockPipelineScheduleNodes[0],
+ };
+
+ const createComponent = (props = defaultProps) => {
+ wrapper = shallowMountExtended(PipelineScheduleNextRun, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ const findTimeAgo = () => wrapper.findComponent(TimeAgoTooltip);
+ const findInactive = () => wrapper.findByTestId('pipeline-schedule-inactive');
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('displays time ago', () => {
+ createComponent();
+
+ expect(findTimeAgo().exists()).toBe(true);
+ expect(findInactive().exists()).toBe(false);
+ expect(findTimeAgo().props('time')).toBe(defaultProps.schedule.realNextRun);
+ });
+
+ it('displays inactive state', () => {
+ const inactiveSchedule = mockPipelineScheduleNodes[1];
+ createComponent({ schedule: inactiveSchedule });
+
+ expect(findInactive().text()).toBe('Inactive');
+ expect(findTimeAgo().exists()).toBe(false);
+ });
+});
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
new file mode 100644
index 00000000000..6c1991cb4ac
--- /dev/null
+++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js
@@ -0,0 +1,40 @@
+import { GlAvatar, GlAvatarLink } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import PipelineScheduleOwner from '~/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner.vue';
+import { mockPipelineScheduleNodes } from '../../../mock_data';
+
+describe('Pipeline schedule owner', () => {
+ let wrapper;
+
+ const defaultProps = {
+ schedule: mockPipelineScheduleNodes[0],
+ };
+
+ const createComponent = (props = defaultProps) => {
+ wrapper = shallowMount(PipelineScheduleOwner, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ const findAvatar = () => wrapper.findComponent(GlAvatar);
+ const findAvatarLink = () => wrapper.findComponent(GlAvatarLink);
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('displays avatar', () => {
+ expect(findAvatar().exists()).toBe(true);
+ expect(findAvatar().props('src')).toBe(defaultProps.schedule.owner.avatarUrl);
+ });
+
+ it('avatar links to user', () => {
+ expect(findAvatarLink().attributes('href')).toBe(defaultProps.schedule.owner.webPath);
+ });
+});
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
new file mode 100644
index 00000000000..f531f04a736
--- /dev/null
+++ b/spec/frontend/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js
@@ -0,0 +1,41 @@
+import { GlIcon, GlLink } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import PipelineScheduleTarget from '~/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue';
+import { mockPipelineScheduleNodes } from '../../../mock_data';
+
+describe('Pipeline schedule target', () => {
+ let wrapper;
+
+ const defaultProps = {
+ schedule: mockPipelineScheduleNodes[0],
+ };
+
+ const createComponent = (props = defaultProps) => {
+ wrapper = shallowMount(PipelineScheduleTarget, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ const findIcon = () => wrapper.findComponent(GlIcon);
+ const findLink = () => wrapper.findComponent(GlLink);
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('displays icon', () => {
+ expect(findIcon().exists()).toBe(true);
+ expect(findIcon().props('name')).toBe('fork');
+ });
+
+ it('displays ref link', () => {
+ expect(findLink().attributes('href')).toBe(defaultProps.schedule.refPath);
+ expect(findLink().text()).toBe(defaultProps.schedule.refForDisplay);
+ });
+});
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
new file mode 100644
index 00000000000..316b3bcf926
--- /dev/null
+++ b/spec/frontend/ci/pipeline_schedules/components/table/pipeline_schedules_table_spec.js
@@ -0,0 +1,39 @@
+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';
+
+describe('Pipeline schedules table', () => {
+ let wrapper;
+
+ const defaultProps = {
+ schedules: mockPipelineScheduleNodes,
+ };
+
+ const createComponent = (props = defaultProps) => {
+ wrapper = mountExtended(PipelineSchedulesTable, {
+ propsData: {
+ ...props,
+ },
+ });
+ };
+
+ const findTable = () => wrapper.findComponent(GlTableLite);
+ const findScheduleDescription = () => wrapper.findByTestId('pipeline-schedule-description');
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('displays table', () => {
+ expect(findTable().exists()).toBe(true);
+ });
+
+ it('displays schedule description', () => {
+ expect(findScheduleDescription().text()).toBe('pipeline schedule');
+ });
+});
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
new file mode 100644
index 00000000000..7e6d4ec4bf8
--- /dev/null
+++ b/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_legacy_spec.js
@@ -0,0 +1,44 @@
+import { GlModal } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import TakeOwnershipModalLegacy from '~/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue';
+
+describe('Take ownership modal', () => {
+ let wrapper;
+ const url = `/root/job-log-tester/-/pipeline_schedules/3/take_ownership`;
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMountExtended(TakeOwnershipModalLegacy, {
+ propsData: {
+ ownershipUrl: url,
+ ...props,
+ },
+ });
+ };
+
+ const findModal = () => wrapper.findComponent(GlModal);
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('has a primary action set to a url and a post data-method', () => {
+ const actionPrimary = findModal().props('actionPrimary');
+
+ expect(actionPrimary.attributes).toEqual(
+ expect.objectContaining([
+ {
+ category: 'primary',
+ variant: 'confirm',
+ href: url,
+ 'data-method': 'post',
+ },
+ ]),
+ );
+ });
+
+ it('shows a take ownership message', () => {
+ expect(findModal().text()).toBe(
+ 'Only the owner of a pipeline schedule can make changes to it. Do you want to take ownership of this schedule?',
+ );
+ });
+});
diff --git a/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_spec.js b/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_spec.js
new file mode 100644
index 00000000000..e3965d13c19
--- /dev/null
+++ b/spec/frontend/ci/pipeline_schedules/components/take_ownership_modal_spec.js
@@ -0,0 +1,40 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlModal } from '@gitlab/ui';
+import TakeOwnershipModal from '~/ci/pipeline_schedules/components/take_ownership_modal.vue';
+
+describe('Take ownership modal', () => {
+ let wrapper;
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(TakeOwnershipModal, {
+ propsData: {
+ visible: true,
+ ...props,
+ },
+ });
+ };
+
+ const findModal = () => wrapper.findComponent(GlModal);
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('shows a take ownership message', () => {
+ expect(findModal().text()).toBe(
+ 'Only the owner of a pipeline schedule can make changes to it. Do you want to take ownership of this schedule?',
+ );
+ });
+
+ it('emits the takeOwnership event', async () => {
+ findModal().vm.$emit('primary');
+
+ expect(wrapper.emitted()).toEqual({ takeOwnership: [[]] });
+ });
+
+ it('emits the hideModal event', async () => {
+ findModal().vm.$emit('hide');
+
+ expect(wrapper.emitted()).toEqual({ hideModal: [[]] });
+ });
+});
diff --git a/spec/frontend/ci/pipeline_schedules/mock_data.js b/spec/frontend/ci/pipeline_schedules/mock_data.js
new file mode 100644
index 00000000000..3010f1d06c3
--- /dev/null
+++ b/spec/frontend/ci/pipeline_schedules/mock_data.js
@@ -0,0 +1,62 @@
+// Fixture located at spec/frontend/fixtures/pipeline_schedules.rb
+import mockGetPipelineSchedulesGraphQLResponse from 'test_fixtures/graphql/pipeline_schedules/get_pipeline_schedules.query.graphql.json';
+import mockGetPipelineSchedulesAsGuestGraphQLResponse from 'test_fixtures/graphql/pipeline_schedules/get_pipeline_schedules.query.graphql.as_guest.json';
+import mockGetPipelineSchedulesTakeOwnershipGraphQLResponse from 'test_fixtures/graphql/pipeline_schedules/get_pipeline_schedules.query.graphql.take_ownership.json';
+
+const {
+ data: {
+ project: {
+ pipelineSchedules: { nodes },
+ },
+ },
+} = mockGetPipelineSchedulesGraphQLResponse;
+
+const {
+ data: {
+ project: {
+ pipelineSchedules: { nodes: guestNodes },
+ },
+ },
+} = mockGetPipelineSchedulesAsGuestGraphQLResponse;
+
+const {
+ data: {
+ project: {
+ pipelineSchedules: { nodes: takeOwnershipNodes },
+ },
+ },
+} = mockGetPipelineSchedulesTakeOwnershipGraphQLResponse;
+
+export const mockPipelineScheduleNodes = nodes;
+
+export const mockPipelineScheduleAsGuestNodes = guestNodes;
+
+export const mockTakeOwnershipNodes = takeOwnershipNodes;
+
+export const deleteMutationResponse = {
+ data: {
+ pipelineScheduleDelete: {
+ clientMutationId: null,
+ errors: [],
+ __typename: 'PipelineScheduleDeletePayload',
+ },
+ },
+};
+
+export const takeOwnershipMutationResponse = {
+ data: {
+ pipelineScheduleTakeOwnership: {
+ pipelineSchedule: {
+ id: '1',
+ owner: {
+ id: '2',
+ name: 'Admin',
+ },
+ },
+ errors: [],
+ __typename: 'PipelineScheduleTakeOwnershipPayload',
+ },
+ },
+};
+
+export { mockGetPipelineSchedulesGraphQLResponse };
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
new file mode 100644
index 00000000000..7081bc57467
--- /dev/null
+++ b/spec/frontend/ci/runner/admin_runner_show/admin_runner_show_app_spec.js
@@ -0,0 +1,266 @@
+import Vue from 'vue';
+import { GlTab, GlTabs } from '@gitlab/ui';
+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 { redirectTo } from '~/lib/utils/url_utility';
+
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import RunnerHeader from '~/ci/runner/components/runner_header.vue';
+import RunnerDetails from '~/ci/runner/components/runner_details.vue';
+import RunnerPauseButton from '~/ci/runner/components/runner_pause_button.vue';
+import RunnerDeleteButton from '~/ci/runner/components/runner_delete_button.vue';
+import RunnerEditButton from '~/ci/runner/components/runner_edit_button.vue';
+import RunnersJobs from '~/ci/runner/components/runner_jobs.vue';
+
+import runnerQuery from '~/ci/runner/graphql/show/runner.query.graphql';
+import AdminRunnerShowApp from '~/ci/runner/admin_runner_show/admin_runner_show_app.vue';
+import { captureException } from '~/ci/runner/sentry_utils';
+import { saveAlertToLocalStorage } from '~/ci/runner/local_storage_alert/save_alert_to_local_storage';
+
+import { runnerData } from '../mock_data';
+
+jest.mock('~/ci/runner/local_storage_alert/save_alert_to_local_storage');
+jest.mock('~/flash');
+jest.mock('~/ci/runner/sentry_utils');
+jest.mock('~/lib/utils/url_utility');
+
+const mockRunner = runnerData.data.runner;
+const mockRunnerGraphqlId = mockRunner.id;
+const mockRunnerId = `${getIdFromGraphQLId(mockRunnerGraphqlId)}`;
+const mockRunnersPath = '/admin/runners';
+
+Vue.use(VueApollo);
+
+describe('AdminRunnerShowApp', () => {
+ let wrapper;
+ let mockRunnerQuery;
+
+ const findRunnerHeader = () => wrapper.findComponent(RunnerHeader);
+ const findRunnerDetails = () => wrapper.findComponent(RunnerDetails);
+ const findRunnerDeleteButton = () => wrapper.findComponent(RunnerDeleteButton);
+ const findRunnerEditButton = () => wrapper.findComponent(RunnerEditButton);
+ const findRunnerPauseButton = () => wrapper.findComponent(RunnerPauseButton);
+ const findRunnersJobs = () => wrapper.findComponent(RunnersJobs);
+ const findJobCountBadge = () => wrapper.findByTestId('job-count-badge');
+
+ const mockRunnerQueryResult = (runner = {}) => {
+ mockRunnerQuery = jest.fn().mockResolvedValue({
+ data: {
+ runner: { ...mockRunner, ...runner },
+ },
+ });
+ };
+
+ const createComponent = ({ props = {}, mountFn = shallowMountExtended, ...options } = {}) => {
+ wrapper = mountFn(AdminRunnerShowApp, {
+ apolloProvider: createMockApollo([[runnerQuery, mockRunnerQuery]]),
+ propsData: {
+ runnerId: mockRunnerId,
+ runnersPath: mockRunnersPath,
+ ...props,
+ },
+ ...options,
+ });
+
+ return waitForPromises();
+ };
+
+ afterEach(() => {
+ mockRunnerQuery.mockReset();
+ wrapper.destroy();
+ });
+
+ describe('When showing runner details', () => {
+ beforeEach(async () => {
+ mockRunnerQueryResult();
+
+ await createComponent({ mountFn: mountExtended });
+ });
+
+ it('expect GraphQL ID to be requested', async () => {
+ expect(mockRunnerQuery).toHaveBeenCalledWith({ id: mockRunnerGraphqlId });
+ });
+
+ it('displays the runner header', async () => {
+ expect(findRunnerHeader().text()).toContain(`Runner #${mockRunnerId}`);
+ });
+
+ it('displays the runner edit and pause buttons', async () => {
+ expect(findRunnerEditButton().exists()).toBe(true);
+ expect(findRunnerPauseButton().exists()).toBe(true);
+ expect(findRunnerDeleteButton().exists()).toBe(true);
+ });
+
+ it('shows basic runner details', async () => {
+ const expected = `Description My Runner
+ Last contact Never contacted
+ Version 1.0.0
+ IP Address None
+ Executor None
+ Architecture None
+ Platform darwin
+ Configuration Runs untagged jobs
+ Maximum job timeout None
+ Token expiry
+ Runner authentication token expiration
+ Runner authentication tokens will expire based on a set interval.
+ They will automatically rotate once expired. Learn more Never expires
+ Tags None`.replace(/\s+/g, ' ');
+
+ expect(wrapper.text().replace(/\s+/g, ' ')).toContain(expected);
+ });
+
+ describe('when runner cannot be updated', () => {
+ beforeEach(async () => {
+ mockRunnerQueryResult({
+ userPermissions: {
+ updateRunner: false,
+ },
+ });
+
+ await createComponent({
+ mountFn: mountExtended,
+ });
+ });
+
+ it('does not display the runner edit and pause buttons', () => {
+ expect(findRunnerEditButton().exists()).toBe(false);
+ expect(findRunnerPauseButton().exists()).toBe(false);
+ });
+ });
+
+ describe('when runner cannot be deleted', () => {
+ beforeEach(async () => {
+ mockRunnerQueryResult({
+ userPermissions: {
+ deleteRunner: false,
+ },
+ });
+
+ await createComponent({
+ mountFn: mountExtended,
+ });
+ });
+
+ it('does not display the runner edit and pause buttons', () => {
+ expect(findRunnerDeleteButton().exists()).toBe(false);
+ });
+ });
+
+ describe('when runner is deleted', () => {
+ beforeEach(async () => {
+ await createComponent({
+ mountFn: mountExtended,
+ });
+ });
+
+ it('redirects to the runner list page', () => {
+ findRunnerDeleteButton().vm.$emit('deleted', { message: 'Runner deleted' });
+
+ expect(saveAlertToLocalStorage).toHaveBeenCalledWith({
+ message: 'Runner deleted',
+ variant: VARIANT_SUCCESS,
+ });
+ expect(redirectTo).toHaveBeenCalledWith(mockRunnersPath);
+ });
+ });
+
+ describe('when runner does not have an edit url', () => {
+ beforeEach(async () => {
+ mockRunnerQueryResult({
+ editAdminUrl: null,
+ });
+
+ await createComponent({
+ mountFn: mountExtended,
+ });
+ });
+
+ it('does not display the runner edit button', () => {
+ expect(findRunnerEditButton().exists()).toBe(false);
+ expect(findRunnerPauseButton().exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('When loading', () => {
+ it('does not show runner details', () => {
+ mockRunnerQueryResult();
+
+ createComponent();
+
+ expect(findRunnerDetails().exists()).toBe(false);
+ });
+
+ it('does not show runner jobs', () => {
+ mockRunnerQueryResult();
+
+ createComponent();
+
+ expect(findRunnersJobs().exists()).toBe(false);
+ });
+ });
+
+ describe('When there is an error', () => {
+ beforeEach(async () => {
+ mockRunnerQuery = jest.fn().mockRejectedValueOnce(new Error('Error!'));
+ await createComponent();
+ });
+
+ it('does not show runner details', () => {
+ expect(findRunnerDetails().exists()).toBe(false);
+ });
+
+ it('error is reported to sentry', () => {
+ expect(captureException).toHaveBeenCalledWith({
+ error: new Error('Error!'),
+ component: 'AdminRunnerShowApp',
+ });
+ });
+
+ it('error is shown to the user', () => {
+ expect(createAlert).toHaveBeenCalled();
+ });
+ });
+
+ describe('Jobs tab', () => {
+ const stubs = {
+ GlTab,
+ GlTabs,
+ };
+
+ it('without a runner, shows no jobs', () => {
+ mockRunnerQuery = jest.fn().mockResolvedValue({
+ data: {
+ runner: null,
+ },
+ });
+
+ createComponent({ stubs });
+
+ expect(findJobCountBadge().exists()).toBe(false);
+ expect(findRunnersJobs().exists()).toBe(false);
+ });
+
+ it('without a job count, shows no jobs count', async () => {
+ mockRunnerQueryResult({ jobCount: null });
+
+ await createComponent({ stubs });
+
+ expect(findJobCountBadge().exists()).toBe(false);
+ });
+
+ it('with a job count, shows jobs count', async () => {
+ const runner = { jobCount: 3 };
+ mockRunnerQueryResult(runner);
+
+ await createComponent({ stubs });
+
+ expect(findJobCountBadge().text()).toBe('3');
+ expect(findRunnersJobs().props('runner')).toEqual({ ...mockRunner, ...runner });
+ });
+ });
+});
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
new file mode 100644
index 00000000000..9778a6fe66c
--- /dev/null
+++ b/spec/frontend/ci/runner/admin_runners/admin_runners_app_spec.js
@@ -0,0 +1,473 @@
+import Vue, { nextTick } from 'vue';
+import { GlToast, GlLink } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import setWindowLocation from 'helpers/set_window_location_helper';
+import {
+ extendedWrapper,
+ shallowMountExtended,
+ mountExtended,
+} from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/flash';
+import { s__ } from '~/locale';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { updateHistory } from '~/lib/utils/url_utility';
+
+import { upgradeStatusTokenConfig } from 'ee_else_ce/ci/runner/components/search_tokens/upgrade_status_token_config';
+import { createLocalState } from '~/ci/runner/graphql/list/local_state';
+import AdminRunnersApp from '~/ci/runner/admin_runners/admin_runners_app.vue';
+import RunnerTypeTabs from '~/ci/runner/components/runner_type_tabs.vue';
+import RunnerFilteredSearchBar from '~/ci/runner/components/runner_filtered_search_bar.vue';
+import RunnerList from '~/ci/runner/components/runner_list.vue';
+import RunnerListEmptyState from '~/ci/runner/components/runner_list_empty_state.vue';
+import RunnerStats from '~/ci/runner/components/stat/runner_stats.vue';
+import RunnerActionsCell from '~/ci/runner/components/cells/runner_actions_cell.vue';
+import RegistrationDropdown from '~/ci/runner/components/registration/registration_dropdown.vue';
+import RunnerPagination from '~/ci/runner/components/runner_pagination.vue';
+
+import {
+ ADMIN_FILTERED_SEARCH_NAMESPACE,
+ CREATED_ASC,
+ CREATED_DESC,
+ DEFAULT_SORT,
+ I18N_STATUS_ONLINE,
+ I18N_STATUS_OFFLINE,
+ I18N_STATUS_STALE,
+ I18N_INSTANCE_TYPE,
+ I18N_GROUP_TYPE,
+ I18N_PROJECT_TYPE,
+ INSTANCE_TYPE,
+ PARAM_KEY_PAUSED,
+ PARAM_KEY_STATUS,
+ PARAM_KEY_TAG,
+ STATUS_ONLINE,
+ DEFAULT_MEMBERSHIP,
+ RUNNER_PAGE_SIZE,
+} from '~/ci/runner/constants';
+import allRunnersQuery from 'ee_else_ce/ci/runner/graphql/list/all_runners.query.graphql';
+import allRunnersCountQuery from 'ee_else_ce/ci/runner/graphql/list/all_runners_count.query.graphql';
+import { captureException } from '~/ci/runner/sentry_utils';
+
+import {
+ allRunnersData,
+ runnersCountData,
+ allRunnersDataPaginated,
+ onlineContactTimeoutSecs,
+ staleTimeoutSecs,
+ emptyPageInfo,
+ emptyStateSvgPath,
+ emptyStateFilteredSvgPath,
+} from '../mock_data';
+
+const mockRegistrationToken = 'MOCK_REGISTRATION_TOKEN';
+const mockRunners = allRunnersData.data.runners.nodes;
+const mockRunnersCount = runnersCountData.data.runners.count;
+
+const mockRunnersHandler = jest.fn();
+const mockRunnersCountHandler = jest.fn();
+
+jest.mock('~/flash');
+jest.mock('~/ci/runner/sentry_utils');
+jest.mock('~/lib/utils/url_utility', () => ({
+ ...jest.requireActual('~/lib/utils/url_utility'),
+ updateHistory: jest.fn(),
+}));
+
+Vue.use(VueApollo);
+Vue.use(GlToast);
+
+const COUNT_QUERIES = 7; // 4 tabs + 3 status queries
+
+describe('AdminRunnersApp', () => {
+ let wrapper;
+ let showToast;
+
+ const findRunnerStats = () => wrapper.findComponent(RunnerStats);
+ const findRunnerActionsCell = () => wrapper.findComponent(RunnerActionsCell);
+ const findRegistrationDropdown = () => wrapper.findComponent(RegistrationDropdown);
+ const findRunnerTypeTabs = () => wrapper.findComponent(RunnerTypeTabs);
+ const findRunnerList = () => wrapper.findComponent(RunnerList);
+ const findRunnerListEmptyState = () => wrapper.findComponent(RunnerListEmptyState);
+ const findRunnerPagination = () => extendedWrapper(wrapper.findComponent(RunnerPagination));
+ const findRunnerPaginationNext = () => findRunnerPagination().findByText(s__('Pagination|Next'));
+ const findRunnerFilteredSearchBar = () => wrapper.findComponent(RunnerFilteredSearchBar);
+
+ const createComponent = ({
+ props = {},
+ mountFn = shallowMountExtended,
+ provide,
+ ...options
+ } = {}) => {
+ const { cacheConfig, localMutations } = createLocalState();
+
+ const handlers = [
+ [allRunnersQuery, mockRunnersHandler],
+ [allRunnersCountQuery, mockRunnersCountHandler],
+ ];
+
+ wrapper = mountFn(AdminRunnersApp, {
+ apolloProvider: createMockApollo(handlers, {}, cacheConfig),
+ propsData: {
+ registrationToken: mockRegistrationToken,
+ ...props,
+ },
+ provide: {
+ localMutations,
+ onlineContactTimeoutSecs,
+ staleTimeoutSecs,
+ emptyStateSvgPath,
+ emptyStateFilteredSvgPath,
+ ...provide,
+ },
+ ...options,
+ });
+
+ showToast = jest.spyOn(wrapper.vm.$root.$toast, 'show');
+
+ return waitForPromises();
+ };
+
+ beforeEach(() => {
+ mockRunnersHandler.mockResolvedValue(allRunnersData);
+ mockRunnersCountHandler.mockResolvedValue(runnersCountData);
+ });
+
+ afterEach(() => {
+ mockRunnersHandler.mockReset();
+ mockRunnersCountHandler.mockReset();
+ showToast.mockReset();
+ wrapper.destroy();
+ });
+
+ it('shows the runner setup instructions', () => {
+ createComponent();
+
+ expect(findRegistrationDropdown().props('registrationToken')).toBe(mockRegistrationToken);
+ expect(findRegistrationDropdown().props('type')).toBe(INSTANCE_TYPE);
+ });
+
+ describe('shows total runner counts', () => {
+ beforeEach(async () => {
+ await createComponent({ mountFn: mountExtended });
+ });
+
+ it('fetches counts', () => {
+ expect(mockRunnersCountHandler).toHaveBeenCalledTimes(COUNT_QUERIES);
+ });
+
+ it('shows the runner tabs', () => {
+ const tabs = findRunnerTypeTabs().text();
+ expect(tabs).toMatchInterpolatedText(
+ `All ${mockRunnersCount} ${I18N_INSTANCE_TYPE} ${mockRunnersCount} ${I18N_GROUP_TYPE} ${mockRunnersCount} ${I18N_PROJECT_TYPE} ${mockRunnersCount}`,
+ );
+ });
+
+ it('shows the total', () => {
+ expect(findRunnerStats().text()).toContain(`${I18N_STATUS_ONLINE} ${mockRunnersCount}`);
+ expect(findRunnerStats().text()).toContain(`${I18N_STATUS_OFFLINE} ${mockRunnersCount}`);
+ expect(findRunnerStats().text()).toContain(`${I18N_STATUS_STALE} ${mockRunnersCount}`);
+ });
+ });
+
+ it('shows the runners list', async () => {
+ await createComponent();
+
+ expect(mockRunnersHandler).toHaveBeenCalledTimes(1);
+ expect(findRunnerList().props('runners')).toEqual(mockRunners);
+ });
+
+ it('runner item links to the runner admin page', async () => {
+ await createComponent({ mountFn: mountExtended });
+
+ const { id, shortSha } = mockRunners[0];
+ const numericId = getIdFromGraphQLId(id);
+
+ const runnerLink = wrapper.find('tr [data-testid="td-summary"]').findComponent(GlLink);
+
+ expect(runnerLink.text()).toBe(`#${numericId} (${shortSha})`);
+ expect(runnerLink.attributes('href')).toBe(`http://localhost/admin/runners/${numericId}`);
+ });
+
+ it('renders runner actions for each runner', async () => {
+ await createComponent({ mountFn: mountExtended });
+
+ const runnerActions = wrapper
+ .find('tr [data-testid="td-actions"]')
+ .findComponent(RunnerActionsCell);
+ const runner = mockRunners[0];
+
+ expect(runnerActions.props()).toEqual({
+ runner,
+ editUrl: runner.editAdminUrl,
+ });
+ });
+
+ it('requests the runners with no filters', async () => {
+ await createComponent();
+
+ expect(mockRunnersHandler).toHaveBeenLastCalledWith({
+ status: undefined,
+ type: undefined,
+ membership: DEFAULT_MEMBERSHIP,
+ sort: DEFAULT_SORT,
+ first: RUNNER_PAGE_SIZE,
+ });
+ });
+
+ it('sets tokens in the filtered search', () => {
+ createComponent();
+
+ expect(findRunnerFilteredSearchBar().props('tokens')).toEqual([
+ expect.objectContaining({
+ type: PARAM_KEY_PAUSED,
+ options: expect.any(Array),
+ }),
+ expect.objectContaining({
+ type: PARAM_KEY_STATUS,
+ options: expect.any(Array),
+ }),
+ expect.objectContaining({
+ type: PARAM_KEY_TAG,
+ recentSuggestionsStorageKey: `${ADMIN_FILTERED_SEARCH_NAMESPACE}-recent-tags`,
+ }),
+ upgradeStatusTokenConfig,
+ ]);
+ });
+
+ describe('Single runner row', () => {
+ const { id: graphqlId, shortSha } = mockRunners[0];
+ const id = getIdFromGraphQLId(graphqlId);
+
+ beforeEach(async () => {
+ mockRunnersCountHandler.mockClear();
+
+ await createComponent({ mountFn: mountExtended });
+ });
+
+ it('Links to the runner page', async () => {
+ const runnerLink = wrapper.find('tr [data-testid="td-summary"]').findComponent(GlLink);
+
+ expect(runnerLink.text()).toBe(`#${id} (${shortSha})`);
+ expect(runnerLink.attributes('href')).toBe(`http://localhost/admin/runners/${id}`);
+ });
+
+ it('When runner is paused or unpaused, some data is refetched', async () => {
+ expect(mockRunnersCountHandler).toHaveBeenCalledTimes(COUNT_QUERIES);
+
+ findRunnerActionsCell().vm.$emit('toggledPaused');
+
+ expect(mockRunnersCountHandler).toHaveBeenCalledTimes(COUNT_QUERIES * 2);
+ expect(showToast).toHaveBeenCalledTimes(0);
+ });
+
+ it('When runner is deleted, data is refetched and a toast message is shown', async () => {
+ findRunnerActionsCell().vm.$emit('deleted', { message: 'Runner deleted' });
+
+ expect(showToast).toHaveBeenCalledTimes(1);
+ expect(showToast).toHaveBeenCalledWith('Runner deleted');
+ });
+ });
+
+ describe('when a filter is preselected', () => {
+ beforeEach(async () => {
+ setWindowLocation(`?status[]=${STATUS_ONLINE}&runner_type[]=${INSTANCE_TYPE}&paused[]=true`);
+
+ await createComponent({ mountFn: mountExtended });
+ });
+
+ it('sets the filters in the search bar', () => {
+ expect(findRunnerFilteredSearchBar().props('value')).toEqual({
+ runnerType: INSTANCE_TYPE,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [
+ { type: PARAM_KEY_STATUS, value: { data: STATUS_ONLINE, operator: '=' } },
+ { type: PARAM_KEY_PAUSED, value: { data: 'true', operator: '=' } },
+ ],
+ sort: 'CREATED_DESC',
+ pagination: {},
+ });
+ });
+
+ it('requests the runners with filter parameters', () => {
+ expect(mockRunnersHandler).toHaveBeenLastCalledWith({
+ status: STATUS_ONLINE,
+ type: INSTANCE_TYPE,
+ membership: DEFAULT_MEMBERSHIP,
+ paused: true,
+ sort: DEFAULT_SORT,
+ first: RUNNER_PAGE_SIZE,
+ });
+ });
+
+ it('fetches count results for requested status', () => {
+ expect(mockRunnersCountHandler).toHaveBeenCalledWith({
+ type: INSTANCE_TYPE,
+ membership: DEFAULT_MEMBERSHIP,
+ status: STATUS_ONLINE,
+ paused: true,
+ });
+ });
+ });
+
+ describe('when a filter is selected by the user', () => {
+ beforeEach(async () => {
+ await createComponent({ mountFn: mountExtended });
+
+ findRunnerFilteredSearchBar().vm.$emit('input', {
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [{ type: PARAM_KEY_STATUS, value: { data: STATUS_ONLINE, operator: '=' } }],
+ sort: CREATED_ASC,
+ });
+
+ await nextTick();
+ });
+
+ it('updates the browser url', () => {
+ expect(updateHistory).toHaveBeenLastCalledWith({
+ title: expect.any(String),
+ url: expect.stringContaining('?status[]=ONLINE&sort=CREATED_ASC'),
+ });
+ });
+
+ it('requests the runners with filters', () => {
+ expect(mockRunnersHandler).toHaveBeenLastCalledWith({
+ status: STATUS_ONLINE,
+ membership: DEFAULT_MEMBERSHIP,
+ sort: CREATED_ASC,
+ first: RUNNER_PAGE_SIZE,
+ });
+ });
+
+ it('fetches count results for requested status', () => {
+ expect(mockRunnersCountHandler).toHaveBeenCalledWith({
+ status: STATUS_ONLINE,
+ membership: DEFAULT_MEMBERSHIP,
+ });
+ });
+ });
+
+ it('when runners have not loaded, shows a loading state', () => {
+ createComponent();
+ expect(findRunnerList().props('loading')).toBe(true);
+ expect(findRunnerPagination().attributes('disabled')).toBe('true');
+ });
+
+ describe('Bulk delete', () => {
+ describe('Before runners are deleted', () => {
+ beforeEach(async () => {
+ await createComponent({ mountFn: mountExtended });
+ });
+
+ it('runner list is checkable', () => {
+ expect(findRunnerList().props('checkable')).toBe(true);
+ });
+ });
+
+ describe('When runners are deleted', () => {
+ beforeEach(async () => {
+ await createComponent({ mountFn: mountExtended });
+ });
+
+ it('count data is refetched', async () => {
+ expect(mockRunnersCountHandler).toHaveBeenCalledTimes(COUNT_QUERIES);
+
+ findRunnerList().vm.$emit('deleted', { message: 'Runners deleted' });
+
+ expect(mockRunnersCountHandler).toHaveBeenCalledTimes(COUNT_QUERIES * 2);
+ });
+
+ it('toast is shown', async () => {
+ expect(showToast).toHaveBeenCalledTimes(0);
+
+ findRunnerList().vm.$emit('deleted', { message: 'Runners deleted' });
+
+ expect(showToast).toHaveBeenCalledTimes(1);
+ expect(showToast).toHaveBeenCalledWith('Runners deleted');
+ });
+ });
+ });
+
+ describe('when no runners are found', () => {
+ beforeEach(async () => {
+ mockRunnersHandler.mockResolvedValue({
+ data: {
+ runners: {
+ nodes: [],
+ pageInfo: emptyPageInfo,
+ },
+ },
+ });
+
+ await createComponent();
+ });
+
+ it('shows no errors', () => {
+ expect(createAlert).not.toHaveBeenCalled();
+ });
+
+ it('shows an empty state', () => {
+ expect(findRunnerListEmptyState().props('isSearchFiltered')).toBe(false);
+ });
+
+ describe('when a filter is selected by the user', () => {
+ beforeEach(async () => {
+ findRunnerFilteredSearchBar().vm.$emit('input', {
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [{ type: PARAM_KEY_STATUS, value: { data: STATUS_ONLINE, operator: '=' } }],
+ sort: CREATED_ASC,
+ });
+ await waitForPromises();
+ });
+
+ it('shows an empty state for a filtered search', () => {
+ expect(findRunnerListEmptyState().props('isSearchFiltered')).toBe(true);
+ });
+ });
+ });
+
+ describe('when runners query fails', () => {
+ beforeEach(async () => {
+ mockRunnersHandler.mockRejectedValue(new Error('Error!'));
+ await createComponent();
+ });
+
+ it('error is shown to the user', async () => {
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ });
+
+ it('error is reported to sentry', async () => {
+ expect(captureException).toHaveBeenCalledWith({
+ error: new Error('Error!'),
+ component: 'AdminRunnersApp',
+ });
+ });
+ });
+
+ describe('Pagination', () => {
+ const { pageInfo } = allRunnersDataPaginated.data.runners;
+
+ beforeEach(async () => {
+ mockRunnersHandler.mockResolvedValue(allRunnersDataPaginated);
+
+ await createComponent({ mountFn: mountExtended });
+ });
+
+ it('passes the page info', () => {
+ expect(findRunnerPagination().props('pageInfo')).toEqual(pageInfo);
+ });
+
+ it('navigates to the next page', async () => {
+ await findRunnerPaginationNext().trigger('click');
+
+ expect(mockRunnersHandler).toHaveBeenLastCalledWith({
+ membership: DEFAULT_MEMBERSHIP,
+ sort: CREATED_DESC,
+ first: RUNNER_PAGE_SIZE,
+ after: pageInfo.endCursor,
+ });
+ });
+ });
+});
diff --git a/spec/frontend/runner/components/__snapshots__/runner_status_popover_spec.js.snap b/spec/frontend/ci/runner/components/__snapshots__/runner_status_popover_spec.js.snap
index b27a1adf01b..b27a1adf01b 100644
--- a/spec/frontend/runner/components/__snapshots__/runner_status_popover_spec.js.snap
+++ b/spec/frontend/ci/runner/components/__snapshots__/runner_status_popover_spec.js.snap
diff --git a/spec/frontend/ci/runner/components/cells/link_cell_spec.js b/spec/frontend/ci/runner/components/cells/link_cell_spec.js
new file mode 100644
index 00000000000..61bb4432c8e
--- /dev/null
+++ b/spec/frontend/ci/runner/components/cells/link_cell_spec.js
@@ -0,0 +1,72 @@
+import { GlLink } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import LinkCell from '~/ci/runner/components/cells/link_cell.vue';
+
+describe('LinkCell', () => {
+ let wrapper;
+
+ const findGlLink = () => wrapper.findComponent(GlLink);
+ const findSpan = () => wrapper.find('span');
+
+ const createComponent = ({ props = {}, ...options } = {}) => {
+ wrapper = shallowMountExtended(LinkCell, {
+ propsData: {
+ ...props,
+ },
+ ...options,
+ });
+ };
+
+ it('when an href is provided, renders a link', () => {
+ createComponent({ props: { href: '/url' } });
+ expect(findGlLink().exists()).toBe(true);
+ });
+
+ it('when an href is not provided, renders no link', () => {
+ createComponent();
+ expect(findGlLink().exists()).toBe(false);
+ });
+
+ describe.each`
+ href | findContent
+ ${null} | ${findSpan}
+ ${'/url'} | ${findGlLink}
+ `('When href is $href', ({ href, findContent }) => {
+ const content = 'My Text';
+ const attrs = { foo: 'bar' };
+ const listeners = {
+ click: jest.fn(),
+ };
+
+ beforeEach(() => {
+ createComponent({
+ props: { href },
+ slots: {
+ default: content,
+ },
+ attrs,
+ listeners,
+ });
+ });
+
+ afterAll(() => {
+ listeners.click.mockReset();
+ });
+
+ it('Renders content', () => {
+ expect(findContent().text()).toBe(content);
+ });
+
+ it('Passes attributes', () => {
+ expect(findContent().attributes()).toMatchObject(attrs);
+ });
+
+ it('Passes event listeners', () => {
+ expect(listeners.click).toHaveBeenCalledTimes(0);
+
+ findContent().vm.$emit('click');
+
+ expect(listeners.click).toHaveBeenCalledTimes(1);
+ });
+ });
+});
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
new file mode 100644
index 00000000000..82e262d1b73
--- /dev/null
+++ b/spec/frontend/ci/runner/components/cells/runner_actions_cell_spec.js
@@ -0,0 +1,138 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+
+import RunnerActionsCell from '~/ci/runner/components/cells/runner_actions_cell.vue';
+import RunnerPauseButton from '~/ci/runner/components/runner_pause_button.vue';
+import RunnerEditButton from '~/ci/runner/components/runner_edit_button.vue';
+import RunnerDeleteButton from '~/ci/runner/components/runner_delete_button.vue';
+import { allRunnersData } from '../../mock_data';
+
+const mockRunner = allRunnersData.data.runners.nodes[0];
+
+describe('RunnerActionsCell', () => {
+ let wrapper;
+
+ const findEditBtn = () => wrapper.findComponent(RunnerEditButton);
+ const findRunnerPauseBtn = () => wrapper.findComponent(RunnerPauseButton);
+ const findDeleteBtn = () => wrapper.findComponent(RunnerDeleteButton);
+
+ const createComponent = ({ runner = {}, ...props } = {}) => {
+ wrapper = shallowMountExtended(RunnerActionsCell, {
+ propsData: {
+ editUrl: mockRunner.editAdminUrl,
+ runner: {
+ id: mockRunner.id,
+ shortSha: mockRunner.shortSha,
+ editAdminUrl: mockRunner.editAdminUrl,
+ userPermissions: mockRunner.userPermissions,
+ ...runner,
+ },
+ ...props,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('Edit Action', () => {
+ it('Displays the runner edit link with the correct href', () => {
+ createComponent();
+
+ expect(findEditBtn().attributes('href')).toBe(mockRunner.editAdminUrl);
+ });
+
+ it('Does not render the runner edit link when user cannot update', () => {
+ createComponent({
+ runner: {
+ userPermissions: {
+ ...mockRunner.userPermissions,
+ updateRunner: false,
+ },
+ },
+ });
+
+ expect(findEditBtn().exists()).toBe(false);
+ });
+
+ it('Does not render the runner edit link when editUrl is not provided', () => {
+ createComponent({
+ editUrl: null,
+ });
+
+ expect(findEditBtn().exists()).toBe(false);
+ });
+ });
+
+ describe('Pause action', () => {
+ it('Renders a compact pause button', () => {
+ createComponent();
+
+ expect(findRunnerPauseBtn().props('compact')).toBe(true);
+ });
+
+ it('Does not render the runner pause button when user cannot update', () => {
+ createComponent({
+ runner: {
+ userPermissions: {
+ ...mockRunner.userPermissions,
+ updateRunner: false,
+ },
+ },
+ });
+
+ expect(findRunnerPauseBtn().exists()).toBe(false);
+ });
+ });
+
+ describe('Delete action', () => {
+ it('Renders a compact delete button', () => {
+ createComponent();
+
+ expect(findDeleteBtn().props('compact')).toBe(true);
+ });
+
+ it('Passes runner data to delete button', () => {
+ createComponent({
+ runner: mockRunner,
+ });
+
+ expect(findDeleteBtn().props('runner')).toEqual(mockRunner);
+ });
+
+ it('Emits toggledPaused events', () => {
+ createComponent();
+
+ expect(wrapper.emitted('toggledPaused')).toBe(undefined);
+
+ findRunnerPauseBtn().vm.$emit('toggledPaused');
+
+ expect(wrapper.emitted('toggledPaused')).toHaveLength(1);
+ });
+
+ it('Emits delete events', () => {
+ const value = { name: 'Runner' };
+
+ createComponent();
+
+ expect(wrapper.emitted('deleted')).toBe(undefined);
+
+ findDeleteBtn().vm.$emit('deleted', value);
+
+ expect(wrapper.emitted('deleted')).toEqual([[value]]);
+ });
+
+ it('Does not render the runner delete button when user cannot delete', () => {
+ createComponent({
+ runner: {
+ userPermissions: {
+ ...mockRunner.userPermissions,
+ deleteRunner: false,
+ },
+ },
+ });
+
+ expect(findDeleteBtn().exists()).toBe(false);
+ });
+ });
+});
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
new file mode 100644
index 00000000000..3097e43e583
--- /dev/null
+++ b/spec/frontend/ci/runner/components/cells/runner_owner_cell_spec.js
@@ -0,0 +1,111 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlLink } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+
+import RunnerOwnerCell from '~/ci/runner/components/cells/runner_owner_cell.vue';
+
+import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '~/ci/runner/constants';
+
+describe('RunnerOwnerCell', () => {
+ let wrapper;
+
+ const findLink = () => wrapper.findComponent(GlLink);
+ const getLinkTooltip = () => getBinding(findLink().element, 'gl-tooltip').value;
+
+ const createComponent = ({ runner } = {}) => {
+ wrapper = shallowMount(RunnerOwnerCell, {
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ propsData: {
+ runner,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('When its an instance runner', () => {
+ beforeEach(() => {
+ createComponent({
+ runner: {
+ runnerType: INSTANCE_TYPE,
+ },
+ });
+ });
+
+ it('shows an administrator label', () => {
+ expect(findLink().exists()).toBe(false);
+ expect(wrapper.text()).toBe(s__('Runners|Administrator'));
+ });
+ });
+
+ describe('When its a group runner', () => {
+ const mockName = 'Group 2';
+ const mockFullName = 'Group 1 / Group 2';
+ const mockWebUrl = '/group-1/group-2';
+
+ beforeEach(() => {
+ createComponent({
+ runner: {
+ runnerType: GROUP_TYPE,
+ groups: {
+ nodes: [
+ {
+ name: mockName,
+ fullName: mockFullName,
+ webUrl: mockWebUrl,
+ },
+ ],
+ },
+ },
+ });
+ });
+
+ it('Displays a group link', () => {
+ expect(findLink().attributes('href')).toBe(mockWebUrl);
+ expect(wrapper.text()).toBe(mockName);
+ expect(getLinkTooltip()).toBe(mockFullName);
+ });
+ });
+
+ describe('When its a project runner', () => {
+ const mockName = 'Project 1';
+ const mockNameWithNamespace = 'Group 1 / Project 1';
+ const mockWebUrl = '/group-1/project-1';
+
+ beforeEach(() => {
+ createComponent({
+ runner: {
+ runnerType: PROJECT_TYPE,
+ ownerProject: {
+ name: mockName,
+ nameWithNamespace: mockNameWithNamespace,
+ webUrl: mockWebUrl,
+ },
+ },
+ });
+ });
+
+ it('Displays a project link', () => {
+ expect(findLink().attributes('href')).toBe(mockWebUrl);
+ expect(wrapper.text()).toBe(mockName);
+ expect(getLinkTooltip()).toBe(mockNameWithNamespace);
+ });
+ });
+
+ describe('When its an empty runner', () => {
+ beforeEach(() => {
+ createComponent({
+ runner: {},
+ });
+ });
+
+ it('shows no label', () => {
+ expect(wrapper.text()).toBe('');
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/cells/runner_stacked_summary_cell_spec.js b/spec/frontend/ci/runner/components/cells/runner_stacked_summary_cell_spec.js
new file mode 100644
index 00000000000..4aa354f9b62
--- /dev/null
+++ b/spec/frontend/ci/runner/components/cells/runner_stacked_summary_cell_spec.js
@@ -0,0 +1,164 @@
+import { __ } from '~/locale';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import RunnerStackedSummaryCell from '~/ci/runner/components/cells/runner_stacked_summary_cell.vue';
+import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
+import RunnerTags from '~/ci/runner/components/runner_tags.vue';
+import RunnerSummaryField from '~/ci/runner/components/cells/runner_summary_field.vue';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+
+import { INSTANCE_TYPE, I18N_INSTANCE_TYPE, PROJECT_TYPE } from '~/ci/runner/constants';
+
+import { allRunnersData } from '../../mock_data';
+
+const mockRunner = allRunnersData.data.runners.nodes[0];
+
+describe('RunnerTypeCell', () => {
+ let wrapper;
+
+ const findLockIcon = () => wrapper.findByTestId('lock-icon');
+ const findRunnerTags = () => wrapper.findComponent(RunnerTags);
+ const findRunnerSummaryField = (icon) =>
+ wrapper.findAllComponents(RunnerSummaryField).filter((w) => w.props('icon') === icon)
+ .wrappers[0];
+
+ const createComponent = (runner, options) => {
+ wrapper = mountExtended(RunnerStackedSummaryCell, {
+ propsData: {
+ runner: {
+ ...mockRunner,
+ ...runner,
+ },
+ },
+ stubs: {
+ RunnerSummaryField,
+ },
+ ...options,
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Displays the runner name as id and short token', () => {
+ expect(wrapper.text()).toContain(
+ `#${getIdFromGraphQLId(mockRunner.id)} (${mockRunner.shortSha})`,
+ );
+ });
+
+ it('Does not display the locked icon', () => {
+ expect(findLockIcon().exists()).toBe(false);
+ });
+
+ it('Displays the locked icon for locked runners', () => {
+ createComponent({
+ runnerType: PROJECT_TYPE,
+ locked: true,
+ });
+
+ expect(findLockIcon().exists()).toBe(true);
+ });
+
+ it('Displays the runner type', () => {
+ createComponent({
+ runnerType: INSTANCE_TYPE,
+ locked: true,
+ });
+
+ expect(wrapper.text()).toContain(I18N_INSTANCE_TYPE);
+ });
+
+ it('Displays the runner version', () => {
+ expect(wrapper.text()).toContain(mockRunner.version);
+ });
+
+ it('Displays the runner description', () => {
+ expect(wrapper.text()).toContain(mockRunner.description);
+ });
+
+ it('Displays last contact', () => {
+ createComponent({
+ contactedAt: '2022-01-02',
+ });
+
+ expect(findRunnerSummaryField('clock').findComponent(TimeAgo).props('time')).toBe('2022-01-02');
+ });
+
+ it('Displays empty last contact', () => {
+ createComponent({
+ contactedAt: null,
+ });
+
+ expect(findRunnerSummaryField('clock').findComponent(TimeAgo).exists()).toBe(false);
+ expect(findRunnerSummaryField('clock').text()).toContain(__('Never'));
+ });
+
+ it('Displays ip address', () => {
+ createComponent({
+ ipAddress: '127.0.0.1',
+ });
+
+ expect(findRunnerSummaryField('disk').text()).toContain('127.0.0.1');
+ });
+
+ it('Displays no ip address', () => {
+ createComponent({
+ ipAddress: null,
+ });
+
+ expect(findRunnerSummaryField('disk')).toBeUndefined();
+ });
+
+ it('Displays job count', () => {
+ expect(findRunnerSummaryField('pipeline').text()).toContain(`${mockRunner.jobCount}`);
+ });
+
+ it('Formats large job counts', () => {
+ createComponent({
+ jobCount: 1000,
+ });
+
+ expect(findRunnerSummaryField('pipeline').text()).toContain('1,000');
+ });
+
+ it('Formats large job counts with a plus symbol', () => {
+ createComponent({
+ jobCount: 1001,
+ });
+
+ expect(findRunnerSummaryField('pipeline').text()).toContain('1,000+');
+ });
+
+ it('Displays created at', () => {
+ expect(findRunnerSummaryField('calendar').findComponent(TimeAgo).props('time')).toBe(
+ mockRunner.createdAt,
+ );
+ });
+
+ it('Displays tag list', () => {
+ createComponent({
+ tagList: ['shell', 'linux'],
+ });
+
+ expect(findRunnerTags().props('tagList')).toEqual(['shell', 'linux']);
+ });
+
+ it('Displays a custom slot', () => {
+ const slotContent = 'My custom runner name';
+
+ createComponent(
+ {},
+ {
+ slots: {
+ 'runner-name': slotContent,
+ },
+ },
+ );
+
+ expect(wrapper.text()).toContain(slotContent);
+ });
+});
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
new file mode 100644
index 00000000000..2fb824a8fa5
--- /dev/null
+++ b/spec/frontend/ci/runner/components/cells/runner_status_cell_spec.js
@@ -0,0 +1,77 @@
+import { mount } from '@vue/test-utils';
+import RunnerStatusCell from '~/ci/runner/components/cells/runner_status_cell.vue';
+
+import RunnerStatusBadge from '~/ci/runner/components/runner_status_badge.vue';
+import RunnerPausedBadge from '~/ci/runner/components/runner_paused_badge.vue';
+import {
+ I18N_PAUSED,
+ I18N_STATUS_ONLINE,
+ I18N_STATUS_OFFLINE,
+ INSTANCE_TYPE,
+ STATUS_ONLINE,
+ STATUS_OFFLINE,
+} from '~/ci/runner/constants';
+
+describe('RunnerStatusCell', () => {
+ let wrapper;
+
+ const findStatusBadge = () => wrapper.findComponent(RunnerStatusBadge);
+ const findPausedBadge = () => wrapper.findComponent(RunnerPausedBadge);
+
+ const createComponent = ({ runner = {} } = {}) => {
+ wrapper = mount(RunnerStatusCell, {
+ propsData: {
+ runner: {
+ runnerType: INSTANCE_TYPE,
+ active: true,
+ status: STATUS_ONLINE,
+ ...runner,
+ },
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Displays online status', () => {
+ createComponent();
+
+ expect(wrapper.text()).toContain(I18N_STATUS_ONLINE);
+ expect(findStatusBadge().text()).toBe(I18N_STATUS_ONLINE);
+ });
+
+ it('Displays offline status', () => {
+ createComponent({
+ runner: {
+ status: STATUS_OFFLINE,
+ },
+ });
+
+ expect(wrapper.text()).toMatchInterpolatedText(I18N_STATUS_OFFLINE);
+ expect(findStatusBadge().text()).toBe(I18N_STATUS_OFFLINE);
+ });
+
+ it('Displays paused status', () => {
+ createComponent({
+ runner: {
+ active: false,
+ status: STATUS_ONLINE,
+ },
+ });
+
+ expect(wrapper.text()).toMatchInterpolatedText(`${I18N_STATUS_ONLINE} ${I18N_PAUSED}`);
+ expect(findPausedBadge().text()).toBe(I18N_PAUSED);
+ });
+
+ it('Is empty when data is missing', () => {
+ createComponent({
+ runner: {
+ status: null,
+ },
+ });
+
+ expect(wrapper.text()).toBe('');
+ });
+});
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
new file mode 100644
index 00000000000..f536e0dcbcf
--- /dev/null
+++ b/spec/frontend/ci/runner/components/cells/runner_summary_field_spec.js
@@ -0,0 +1,49 @@
+import { GlIcon } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import RunnerSummaryField from '~/ci/runner/components/cells/runner_summary_field.vue';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+
+describe('RunnerSummaryField', () => {
+ let wrapper;
+
+ const findIcon = () => wrapper.findComponent(GlIcon);
+ const getTooltipValue = () => getBinding(wrapper.element, 'gl-tooltip').value;
+
+ const createComponent = ({ props, ...options } = {}) => {
+ wrapper = shallowMount(RunnerSummaryField, {
+ propsData: {
+ icon: '',
+ tooltip: '',
+ ...props,
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ ...options,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('shows content in slot', () => {
+ createComponent({
+ slots: { default: 'content' },
+ });
+
+ expect(wrapper.text()).toBe('content');
+ });
+
+ it('shows icon', () => {
+ createComponent({ props: { icon: 'git' } });
+
+ expect(findIcon().props('name')).toBe('git');
+ });
+
+ it('shows tooltip', () => {
+ createComponent({ props: { tooltip: 'tooltip' } });
+
+ expect(getTooltipValue()).toBe('tooltip');
+ });
+});
diff --git a/spec/frontend/ci/runner/components/registration/registration_dropdown_spec.js b/spec/frontend/ci/runner/components/registration/registration_dropdown_spec.js
new file mode 100644
index 00000000000..cb46c668930
--- /dev/null
+++ b/spec/frontend/ci/runner/components/registration/registration_dropdown_spec.js
@@ -0,0 +1,198 @@
+import { GlModal, GlDropdown, GlDropdownItem, GlDropdownForm } from '@gitlab/ui';
+import { mount, shallowMount, createWrapper } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+
+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 RegistrationDropdown from '~/ci/runner/components/registration/registration_dropdown.vue';
+import RegistrationToken from '~/ci/runner/components/registration/registration_token.vue';
+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 getRunnerPlatformsQuery from '~/vue_shared/components/runner_instructions/graphql/queries/get_runner_platforms.query.graphql';
+import getRunnerSetupInstructionsQuery from '~/vue_shared/components/runner_instructions/graphql/queries/get_runner_setup.query.graphql';
+
+import {
+ mockGraphqlRunnerPlatforms,
+ mockGraphqlInstructions,
+} from 'jest/vue_shared/components/runner_instructions/mock_data';
+
+const mockToken = '0123456789';
+const maskToken = '**********';
+
+Vue.use(VueApollo);
+
+describe('RegistrationDropdown', () => {
+ let wrapper;
+
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
+
+ const findRegistrationInstructionsDropdownItem = () => wrapper.findComponent(GlDropdownItem);
+ const findTokenDropdownItem = () => wrapper.findComponent(GlDropdownForm);
+ const findRegistrationToken = () => wrapper.findComponent(RegistrationToken);
+ const findRegistrationTokenInput = () =>
+ wrapper.findByLabelText(RegistrationToken.i18n.registrationToken);
+ const findTokenResetDropdownItem = () =>
+ wrapper.findComponent(RegistrationTokenResetDropdownItem);
+ const findModal = () => wrapper.findComponent(GlModal);
+ const findModalContent = () =>
+ createWrapper(document.body)
+ .find('[data-testid="runner-instructions-modal"]')
+ .text()
+ .replace(/[\n\t\s]+/g, ' ');
+
+ const openModal = async () => {
+ await findRegistrationInstructionsDropdownItem().trigger('click');
+ findModal().vm.$emit('shown');
+
+ await waitForPromises();
+ };
+
+ const createComponent = ({ props = {}, ...options } = {}, mountFn = shallowMount) => {
+ wrapper = extendedWrapper(
+ mountFn(RegistrationDropdown, {
+ propsData: {
+ registrationToken: mockToken,
+ type: INSTANCE_TYPE,
+ ...props,
+ },
+ ...options,
+ }),
+ );
+ };
+
+ const createComponentWithModal = () => {
+ const requestHandlers = [
+ [getRunnerPlatformsQuery, jest.fn().mockResolvedValue(mockGraphqlRunnerPlatforms)],
+ [getRunnerSetupInstructionsQuery, jest.fn().mockResolvedValue(mockGraphqlInstructions)],
+ ];
+
+ createComponent(
+ {
+ // Mock load modal contents from API
+ apolloProvider: createMockApollo(requestHandlers),
+ // Use `attachTo` to find the modal
+ attachTo: document.body,
+ },
+ mount,
+ );
+ };
+
+ it.each`
+ type | text
+ ${INSTANCE_TYPE} | ${'Register an instance runner'}
+ ${GROUP_TYPE} | ${'Register a group runner'}
+ ${PROJECT_TYPE} | ${'Register a project runner'}
+ `('Dropdown text for type $type is "$text"', () => {
+ createComponent({ props: { type: INSTANCE_TYPE } }, mount);
+
+ expect(wrapper.text()).toContain('Register an instance runner');
+ });
+
+ it('Passes attributes to the dropdown component', () => {
+ createComponent({ attrs: { right: true } });
+
+ expect(findDropdown().attributes()).toMatchObject({ right: 'true' });
+ });
+
+ describe('Instructions dropdown item', () => {
+ it('Displays "Show runner" dropdown item', () => {
+ createComponent();
+
+ expect(findRegistrationInstructionsDropdownItem().text()).toBe(
+ 'Show runner installation and registration instructions',
+ );
+ });
+
+ describe('When the dropdown item is clicked', () => {
+ beforeEach(async () => {
+ createComponentWithModal({}, mount);
+
+ await openModal();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('opens the modal with contents', () => {
+ const modalText = findModalContent();
+
+ expect(modalText).toContain('Install a runner');
+
+ // Environment selector
+ expect(modalText).toContain('Environment');
+ expect(modalText).toContain('Linux macOS Windows Docker Kubernetes');
+
+ // Architecture selector
+ expect(modalText).toContain('Architecture');
+ expect(modalText).toContain('amd64 amd64 386 arm arm64');
+
+ expect(modalText).toContain('Download and install binary');
+ });
+ });
+ });
+
+ describe('Registration token', () => {
+ it('Displays dropdown form for the registration token', () => {
+ createComponent();
+
+ expect(findTokenDropdownItem().exists()).toBe(true);
+ });
+
+ it('Displays masked value by default', () => {
+ createComponent({}, mount);
+
+ expect(findRegistrationTokenInput().element.value).toBe(maskToken);
+ });
+ });
+
+ describe('Reset token item', () => {
+ it('Displays registration token reset item', () => {
+ createComponent();
+
+ expect(findTokenResetDropdownItem().exists()).toBe(true);
+ });
+
+ it.each([INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE])('Set up token reset for %s', (type) => {
+ createComponent({ props: { type } });
+
+ expect(findTokenResetDropdownItem().props('type')).toBe(type);
+ });
+ });
+
+ describe('When token is reset', () => {
+ const newToken = 'mock1';
+
+ const resetToken = async () => {
+ findTokenResetDropdownItem().vm.$emit('tokenReset', newToken);
+ await nextTick();
+ };
+
+ it('Updates token input', async () => {
+ createComponent({}, mount);
+
+ expect(findRegistrationToken().props('value')).not.toBe(newToken);
+
+ await resetToken();
+
+ expect(findRegistrationToken().props('value')).toBe(newToken);
+ });
+
+ it('Updates token in modal', async () => {
+ createComponentWithModal({}, mount);
+
+ await openModal();
+
+ expect(findModalContent()).toContain(mockToken);
+
+ await resetToken();
+
+ expect(findModalContent()).toContain(newToken);
+ });
+ });
+});
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
new file mode 100644
index 00000000000..783a4d9252a
--- /dev/null
+++ b/spec/frontend/ci/runner/components/registration/registration_token_reset_dropdown_item_spec.js
@@ -0,0 +1,209 @@
+import { GlDropdownItem, GlLoadingIcon, GlToast, GlModal } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/flash';
+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('~/ci/runner/sentry_utils');
+
+Vue.use(VueApollo);
+Vue.use(GlToast);
+
+const mockNewToken = 'NEW_TOKEN';
+const modalID = 'token-reset-modal';
+
+describe('RegistrationTokenResetDropdownItem', () => {
+ let wrapper;
+ let runnersRegistrationTokenResetMutationHandler;
+ let showToast;
+
+ const mockEvent = { preventDefault: jest.fn() };
+ const findDropdownItem = () => wrapper.findComponent(GlDropdownItem);
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findModal = () => wrapper.findComponent(GlModal);
+ const clickSubmit = () => findModal().vm.$emit('primary', mockEvent);
+
+ const createComponent = ({ props, provide = {} } = {}) => {
+ wrapper = shallowMount(RegistrationTokenResetDropdownItem, {
+ provide,
+ propsData: {
+ type: INSTANCE_TYPE,
+ ...props,
+ },
+ apolloProvider: createMockApollo([
+ [runnersRegistrationTokenResetMutation, runnersRegistrationTokenResetMutationHandler],
+ ]),
+ directives: {
+ GlModal: createMockDirective(),
+ },
+ });
+
+ showToast = wrapper.vm.$toast ? jest.spyOn(wrapper.vm.$toast, 'show') : null;
+ };
+
+ beforeEach(() => {
+ runnersRegistrationTokenResetMutationHandler = jest.fn().mockResolvedValue({
+ data: {
+ runnersRegistrationTokenReset: {
+ token: mockNewToken,
+ errors: [],
+ },
+ },
+ });
+
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Displays reset button', () => {
+ expect(findDropdownItem().exists()).toBe(true);
+ });
+
+ describe('modal directive integration', () => {
+ it('has the correct ID on the dropdown', () => {
+ const binding = getBinding(findDropdownItem().element, 'gl-modal');
+
+ expect(binding.value).toBe(modalID);
+ });
+
+ it('has the correct ID on the modal', () => {
+ expect(findModal().props('modalId')).toBe(modalID);
+ });
+ });
+
+ describe('On click and confirmation', () => {
+ const mockGroupId = '11';
+ const mockProjectId = '22';
+
+ describe.each`
+ type | provide | expectedInput
+ ${INSTANCE_TYPE} | ${{}} | ${{ type: INSTANCE_TYPE }}
+ ${GROUP_TYPE} | ${{ groupId: mockGroupId }} | ${{ type: GROUP_TYPE, id: `gid://gitlab/Group/${mockGroupId}` }}
+ ${PROJECT_TYPE} | ${{ projectId: mockProjectId }} | ${{ type: PROJECT_TYPE, id: `gid://gitlab/Project/${mockProjectId}` }}
+ `('Resets token of type $type', ({ type, provide, expectedInput }) => {
+ beforeEach(async () => {
+ createComponent({
+ provide,
+ props: { type },
+ });
+
+ findDropdownItem().trigger('click');
+ clickSubmit();
+ await waitForPromises();
+ });
+
+ it('resets token', () => {
+ expect(runnersRegistrationTokenResetMutationHandler).toHaveBeenCalledTimes(1);
+ expect(runnersRegistrationTokenResetMutationHandler).toHaveBeenCalledWith({
+ input: expectedInput,
+ });
+ });
+
+ it('emits result', () => {
+ expect(wrapper.emitted('tokenReset')).toHaveLength(1);
+ expect(wrapper.emitted('tokenReset')[0]).toEqual([mockNewToken]);
+ });
+
+ it('does not show a loading state', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('shows confirmation', () => {
+ expect(showToast).toHaveBeenLastCalledWith(
+ expect.stringContaining('registration token generated'),
+ );
+ });
+ });
+ });
+
+ describe('On click without confirmation', () => {
+ beforeEach(async () => {
+ findDropdownItem().vm.$emit('click');
+ await waitForPromises();
+ });
+
+ it('does not reset token', () => {
+ expect(runnersRegistrationTokenResetMutationHandler).not.toHaveBeenCalled();
+ });
+
+ it('does not emit any result', () => {
+ expect(wrapper.emitted('tokenReset')).toBeUndefined();
+ });
+
+ it('does not show a loading state', () => {
+ expect(findLoadingIcon().exists()).toBe(false);
+ });
+
+ it('does not shows confirmation', () => {
+ expect(showToast).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('On error', () => {
+ it('On network error, error message is shown', async () => {
+ const mockErrorMsg = 'Token reset failed!';
+
+ runnersRegistrationTokenResetMutationHandler.mockRejectedValueOnce(new Error(mockErrorMsg));
+
+ findDropdownItem().trigger('click');
+ clickSubmit();
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenLastCalledWith({
+ message: mockErrorMsg,
+ });
+ expect(captureException).toHaveBeenCalledWith({
+ error: new Error(mockErrorMsg),
+ component: 'RunnerRegistrationTokenReset',
+ });
+ });
+
+ it('On validation error, error message is shown', async () => {
+ const mockErrorMsg = 'User not allowed!';
+ const mockErrorMsg2 = 'Type is not valid!';
+
+ runnersRegistrationTokenResetMutationHandler.mockResolvedValue({
+ data: {
+ runnersRegistrationTokenReset: {
+ token: null,
+ errors: [mockErrorMsg, mockErrorMsg2],
+ },
+ },
+ });
+
+ findDropdownItem().trigger('click');
+ clickSubmit();
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenLastCalledWith({
+ message: `${mockErrorMsg} ${mockErrorMsg2}`,
+ });
+ expect(captureException).toHaveBeenCalledWith({
+ error: new Error(`${mockErrorMsg} ${mockErrorMsg2}`),
+ component: 'RunnerRegistrationTokenReset',
+ });
+ });
+ });
+
+ describe('Immediately after click', () => {
+ it('shows loading state', async () => {
+ findDropdownItem().trigger('click');
+ clickSubmit();
+ await nextTick();
+
+ expect(findLoadingIcon().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
new file mode 100644
index 00000000000..d2a51c0d910
--- /dev/null
+++ b/spec/frontend/ci/runner/components/registration/registration_token_spec.js
@@ -0,0 +1,62 @@
+import { GlToast } from '@gitlab/ui';
+import Vue from 'vue';
+import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import RegistrationToken from '~/ci/runner/components/registration/registration_token.vue';
+import InputCopyToggleVisibility from '~/vue_shared/components/form/input_copy_toggle_visibility.vue';
+
+const mockToken = '01234567890';
+const mockMasked = '***********';
+
+describe('RegistrationToken', () => {
+ let wrapper;
+ let showToast;
+
+ Vue.use(GlToast);
+
+ const findInputCopyToggleVisibility = () => wrapper.findComponent(InputCopyToggleVisibility);
+
+ const createComponent = ({ props = {}, mountFn = shallowMountExtended } = {}) => {
+ wrapper = mountFn(RegistrationToken, {
+ propsData: {
+ value: mockToken,
+ inputId: 'token-value',
+ ...props,
+ },
+ });
+
+ showToast = wrapper.vm.$toast ? jest.spyOn(wrapper.vm.$toast, 'show') : null;
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Displays value and copy button', () => {
+ createComponent();
+
+ expect(findInputCopyToggleVisibility().props('value')).toBe(mockToken);
+ expect(findInputCopyToggleVisibility().props('copyButtonTitle')).toBe(
+ 'Copy registration token',
+ );
+ });
+
+ // Component integration test to ensure secure masking
+ it('Displays masked value by default', () => {
+ createComponent({ mountFn: mountExtended });
+
+ expect(wrapper.find('input').element.value).toBe(mockMasked);
+ });
+
+ describe('When the copy to clipboard button is clicked', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('shows a copied message', () => {
+ findInputCopyToggleVisibility().vm.$emit('copy');
+
+ expect(showToast).toHaveBeenCalledTimes(1);
+ expect(showToast).toHaveBeenCalledWith('Registration token copied!');
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_assigned_item_spec.js b/spec/frontend/ci/runner/components/runner_assigned_item_spec.js
new file mode 100644
index 00000000000..5df2e04c340
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_assigned_item_spec.js
@@ -0,0 +1,68 @@
+import { GlAvatar, GlBadge } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import RunnerAssignedItem from '~/ci/runner/components/runner_assigned_item.vue';
+import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants';
+
+const mockHref = '/group/project';
+const mockName = 'Project';
+const mockDescription = 'Project description';
+const mockFullName = 'Group / Project';
+const mockAvatarUrl = '/avatar.png';
+
+describe('RunnerAssignedItem', () => {
+ let wrapper;
+
+ const findAvatar = () => wrapper.findByTestId('item-avatar');
+ const findBadge = () => wrapper.findComponent(GlBadge);
+
+ const createComponent = ({ props = {} } = {}) => {
+ wrapper = shallowMountExtended(RunnerAssignedItem, {
+ propsData: {
+ href: mockHref,
+ name: mockName,
+ fullName: mockFullName,
+ avatarUrl: mockAvatarUrl,
+ description: mockDescription,
+ ...props,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Shows an avatar', () => {
+ const avatar = findAvatar();
+
+ expect(avatar.attributes('href')).toBe(mockHref);
+ expect(avatar.findComponent(GlAvatar).props()).toMatchObject({
+ alt: mockName,
+ entityName: mockName,
+ src: mockAvatarUrl,
+ shape: AVATAR_SHAPE_OPTION_RECT,
+ size: 48,
+ });
+ });
+
+ it('Shows an item link', () => {
+ const groupFullName = wrapper.findByText(mockFullName);
+
+ expect(groupFullName.attributes('href')).toBe(mockHref);
+ });
+
+ it('Shows description', () => {
+ expect(wrapper.text()).toContain(mockDescription);
+ });
+
+ it('Shows owner badge', () => {
+ createComponent({ props: { isOwner: true } });
+
+ expect(findBadge().text()).toBe(s__('Runner|Owner'));
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_bulk_delete_checkbox_spec.js b/spec/frontend/ci/runner/components/runner_bulk_delete_checkbox_spec.js
new file mode 100644
index 00000000000..dad36b0179f
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_bulk_delete_checkbox_spec.js
@@ -0,0 +1,140 @@
+import Vue from 'vue';
+import { GlFormCheckbox } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import RunnerBulkDeleteCheckbox from '~/ci/runner/components/runner_bulk_delete_checkbox.vue';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { createLocalState } from '~/ci/runner/graphql/list/local_state';
+
+Vue.use(VueApollo);
+
+const makeRunner = (id, deleteRunner = true) => ({
+ id,
+ userPermissions: { deleteRunner },
+});
+
+// Multi-select checkbox possible states:
+const stateToAttrs = {
+ unchecked: { disabled: undefined, checked: undefined, indeterminate: undefined },
+ checked: { disabled: undefined, checked: 'true', indeterminate: undefined },
+ indeterminate: { disabled: undefined, checked: undefined, indeterminate: 'true' },
+ disabled: { disabled: 'true', checked: undefined, indeterminate: undefined },
+};
+
+describe('RunnerBulkDeleteCheckbox', () => {
+ let wrapper;
+ let mockState;
+ let mockCheckedRunnerIds;
+
+ const findCheckbox = () => wrapper.findComponent(GlFormCheckbox);
+
+ const expectCheckboxToBe = (state) => {
+ const expected = stateToAttrs[state];
+ expect(findCheckbox().attributes('disabled')).toBe(expected.disabled);
+ expect(findCheckbox().attributes('checked')).toBe(expected.checked);
+ expect(findCheckbox().attributes('indeterminate')).toBe(expected.indeterminate);
+ };
+
+ const createComponent = ({ runners = [] } = {}) => {
+ const { cacheConfig, localMutations } = mockState;
+ const apolloProvider = createMockApollo(undefined, undefined, cacheConfig);
+
+ wrapper = shallowMountExtended(RunnerBulkDeleteCheckbox, {
+ apolloProvider,
+ provide: {
+ localMutations,
+ },
+ propsData: {
+ runners,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ mockState = createLocalState();
+
+ jest
+ .spyOn(mockState.cacheConfig.typePolicies.Query.fields, 'checkedRunnerIds')
+ .mockImplementation(() => mockCheckedRunnerIds);
+
+ jest.spyOn(mockState.localMutations, 'setRunnersChecked');
+ });
+
+ describe('when all runners can be deleted', () => {
+ const mockIds = ['1', '2', '3'];
+ const mockIdAnotherPage = '4';
+ const mockRunners = mockIds.map((id) => makeRunner(id));
+
+ it.each`
+ case | checkedRunnerIds | state
+ ${'no runners'} | ${[]} | ${'unchecked'}
+ ${'no runners in this page'} | ${[mockIdAnotherPage]} | ${'unchecked'}
+ ${'all runners'} | ${mockIds} | ${'checked'}
+ ${'some runners'} | ${[mockIds[0]]} | ${'indeterminate'}
+ ${'all plus other runners'} | ${[...mockIds, mockIdAnotherPage]} | ${'checked'}
+ `('if $case are checked, checkbox is $state', ({ checkedRunnerIds, state }) => {
+ mockCheckedRunnerIds = checkedRunnerIds;
+
+ createComponent({ runners: mockRunners });
+ expectCheckboxToBe(state);
+ });
+ });
+
+ describe('when some runners cannot be deleted', () => {
+ it('all allowed runners are selected, checkbox is checked', () => {
+ mockCheckedRunnerIds = ['a', 'b', 'c'];
+ createComponent({
+ runners: [makeRunner('a'), makeRunner('b'), makeRunner('c', false)],
+ });
+
+ expectCheckboxToBe('checked');
+ });
+
+ it('some allowed runners are selected, checkbox is indeterminate', () => {
+ mockCheckedRunnerIds = ['a', 'b'];
+ createComponent({
+ runners: [makeRunner('a'), makeRunner('b'), makeRunner('c')],
+ });
+
+ expectCheckboxToBe('indeterminate');
+ });
+
+ it('no allowed runners are selected, checkbox is disabled', () => {
+ mockCheckedRunnerIds = ['a', 'b'];
+ createComponent({
+ runners: [makeRunner('a', false), makeRunner('b', false)],
+ });
+
+ expectCheckboxToBe('disabled');
+ });
+ });
+
+ describe('When user selects', () => {
+ const mockRunners = [makeRunner('1'), makeRunner('2')];
+
+ beforeEach(() => {
+ mockCheckedRunnerIds = ['1', '2'];
+ createComponent({ runners: mockRunners });
+ });
+
+ it.each([[true], [false]])('sets checked to %s', (checked) => {
+ findCheckbox().vm.$emit('change', checked);
+
+ expect(mockState.localMutations.setRunnersChecked).toHaveBeenCalledTimes(1);
+ expect(mockState.localMutations.setRunnersChecked).toHaveBeenCalledWith({
+ isChecked: checked,
+ runners: mockRunners,
+ });
+ });
+ });
+
+ describe('When runners are loading', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('is disabled', () => {
+ expectCheckboxToBe('disabled');
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_bulk_delete_spec.js b/spec/frontend/ci/runner/components/runner_bulk_delete_spec.js
new file mode 100644
index 00000000000..64f5a0e3b57
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_bulk_delete_spec.js
@@ -0,0 +1,295 @@
+import Vue from 'vue';
+import { GlModal, GlSprintf } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import { createAlert } from '~/flash';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { s__ } from '~/locale';
+import RunnerBulkDelete from '~/ci/runner/components/runner_bulk_delete.vue';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import BulkRunnerDeleteMutation from '~/ci/runner/graphql/list/bulk_runner_delete.mutation.graphql';
+import { createLocalState } from '~/ci/runner/graphql/list/local_state';
+import waitForPromises from 'helpers/wait_for_promises';
+import { allRunnersData } from '../mock_data';
+
+Vue.use(VueApollo);
+
+jest.mock('~/flash');
+
+describe('RunnerBulkDelete', () => {
+ let wrapper;
+ let apolloCache;
+ let mockState;
+ let mockCheckedRunnerIds;
+
+ const findClearBtn = () => wrapper.findByText(s__('Runners|Clear selection'));
+ const findDeleteBtn = () => wrapper.findByText(s__('Runners|Delete selected'));
+ const findModal = () => wrapper.findComponent(GlModal);
+
+ const mockRunners = allRunnersData.data.runners.nodes;
+ const mockId1 = allRunnersData.data.runners.nodes[0].id;
+ const mockId2 = allRunnersData.data.runners.nodes[1].id;
+
+ const bulkRunnerDeleteHandler = jest.fn();
+
+ const createComponent = () => {
+ const { cacheConfig, localMutations } = mockState;
+ const apolloProvider = createMockApollo(
+ [[BulkRunnerDeleteMutation, bulkRunnerDeleteHandler]],
+ undefined,
+ cacheConfig,
+ );
+
+ wrapper = shallowMountExtended(RunnerBulkDelete, {
+ apolloProvider,
+ provide: {
+ localMutations,
+ },
+ propsData: {
+ runners: mockRunners,
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ stubs: {
+ GlSprintf,
+ GlModal,
+ },
+ });
+
+ apolloCache = apolloProvider.defaultClient.cache;
+ jest.spyOn(apolloCache, 'evict');
+ jest.spyOn(apolloCache, 'gc');
+ };
+
+ beforeEach(() => {
+ mockState = createLocalState();
+
+ jest
+ .spyOn(mockState.cacheConfig.typePolicies.Query.fields, 'checkedRunnerIds')
+ .mockImplementation(() => mockCheckedRunnerIds);
+ });
+
+ afterEach(() => {
+ bulkRunnerDeleteHandler.mockReset();
+ });
+
+ describe('When no runners are checked', () => {
+ beforeEach(async () => {
+ mockCheckedRunnerIds = [];
+
+ createComponent();
+
+ await waitForPromises();
+ });
+
+ it('shows no contents', () => {
+ expect(wrapper.html()).toBe('');
+ });
+ });
+
+ describe.each`
+ count | ids | text
+ ${1} | ${[mockId1]} | ${'1 runner'}
+ ${2} | ${[mockId1, mockId2]} | ${'2 runners'}
+ `('When $count runner(s) are checked', ({ ids, text }) => {
+ beforeEach(() => {
+ mockCheckedRunnerIds = ids;
+
+ createComponent();
+
+ jest.spyOn(mockState.localMutations, 'clearChecked').mockImplementation(() => {});
+ });
+
+ it(`shows "${text}"`, () => {
+ expect(wrapper.text()).toContain(text);
+ });
+
+ it('clears selection', () => {
+ expect(mockState.localMutations.clearChecked).toHaveBeenCalledTimes(0);
+
+ findClearBtn().vm.$emit('click');
+
+ expect(mockState.localMutations.clearChecked).toHaveBeenCalledTimes(1);
+ });
+
+ it('shows confirmation modal', () => {
+ const modalId = getBinding(findDeleteBtn().element, 'gl-modal');
+
+ expect(findModal().props('modal-id')).toBe(modalId);
+ expect(findModal().text()).toContain(text);
+ });
+ });
+
+ describe('when runners are deleted', () => {
+ let evt;
+ let mockHideModal;
+
+ const confirmDeletion = () => {
+ evt = {
+ preventDefault: jest.fn(),
+ };
+ findModal().vm.$emit('primary', evt);
+ };
+
+ beforeEach(() => {
+ mockCheckedRunnerIds = [mockId1, mockId2];
+
+ createComponent();
+
+ jest.spyOn(mockState.localMutations, 'clearChecked').mockImplementation(() => {});
+ mockHideModal = jest.spyOn(findModal().vm, 'hide').mockImplementation(() => {});
+ });
+
+ describe('when deletion is confirmed', () => {
+ beforeEach(() => {
+ confirmDeletion();
+ });
+
+ it('has loading state', () => {
+ expect(findModal().props('actionPrimary').attributes.loading).toBe(true);
+ expect(findModal().props('actionCancel').attributes.loading).toBe(true);
+ });
+
+ it('modal is not prevented from closing', () => {
+ expect(evt.preventDefault).toHaveBeenCalledTimes(1);
+ });
+
+ it('mutation is called', () => {
+ expect(bulkRunnerDeleteHandler).toHaveBeenCalledWith({
+ input: { ids: mockCheckedRunnerIds },
+ });
+ });
+ });
+
+ describe('when deletion is successful', () => {
+ beforeEach(async () => {
+ bulkRunnerDeleteHandler.mockResolvedValue({
+ data: {
+ bulkRunnerDelete: { deletedIds: mockCheckedRunnerIds, errors: [] },
+ },
+ });
+
+ confirmDeletion();
+ await waitForPromises();
+ });
+
+ it('removes loading state', () => {
+ expect(findModal().props('actionPrimary').attributes.loading).toBe(false);
+ expect(findModal().props('actionCancel').attributes.loading).toBe(false);
+ });
+
+ it('user interface is updated', () => {
+ const { evict, gc } = apolloCache;
+
+ expect(evict).toHaveBeenCalledTimes(mockCheckedRunnerIds.length);
+ expect(evict).toHaveBeenCalledWith({
+ id: expect.stringContaining(mockCheckedRunnerIds[0]),
+ });
+ expect(evict).toHaveBeenCalledWith({
+ id: expect.stringContaining(mockCheckedRunnerIds[1]),
+ });
+
+ expect(gc).toHaveBeenCalledTimes(1);
+ });
+
+ it('emits deletion confirmation', () => {
+ expect(wrapper.emitted('deleted')).toEqual([
+ [{ message: expect.stringContaining(`${mockCheckedRunnerIds.length}`) }],
+ ]);
+ });
+
+ it('modal is hidden', () => {
+ expect(mockHideModal).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('when deletion fails partially', () => {
+ beforeEach(async () => {
+ bulkRunnerDeleteHandler.mockResolvedValue({
+ data: {
+ bulkRunnerDelete: {
+ deletedIds: [mockId1], // only one runner could be deleted
+ errors: ['Can only delete up to 1 runners per call. Ignored 1 runner(s).'],
+ },
+ },
+ });
+
+ confirmDeletion();
+ await waitForPromises();
+ });
+
+ it('removes loading state', () => {
+ expect(findModal().props('actionPrimary').attributes.loading).toBe(false);
+ expect(findModal().props('actionCancel').attributes.loading).toBe(false);
+ });
+
+ it('user interface is partially updated', () => {
+ const { evict, gc } = apolloCache;
+
+ expect(evict).toHaveBeenCalledTimes(1);
+ expect(evict).toHaveBeenCalledWith({
+ id: expect.stringContaining(mockId1),
+ });
+
+ expect(gc).toHaveBeenCalledTimes(1);
+ });
+
+ it('emits deletion confirmation', () => {
+ expect(wrapper.emitted('deleted')).toEqual([[{ message: expect.stringContaining('1') }]]);
+ });
+
+ it('alert is called', () => {
+ expect(createAlert).toHaveBeenCalled();
+ expect(createAlert).toHaveBeenCalledWith({
+ message: expect.any(String),
+ captureError: true,
+ error: expect.any(Error),
+ });
+ });
+
+ it('modal is hidden', () => {
+ expect(mockHideModal).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('when deletion fails', () => {
+ beforeEach(async () => {
+ bulkRunnerDeleteHandler.mockRejectedValue(new Error('error!'));
+
+ confirmDeletion();
+ await waitForPromises();
+ });
+
+ it('resolves loading state', () => {
+ expect(findModal().props('actionPrimary').attributes.loading).toBe(false);
+ expect(findModal().props('actionCancel').attributes.loading).toBe(false);
+ });
+
+ it('user interface is not updated', () => {
+ const { evict, gc } = apolloCache;
+
+ expect(evict).not.toHaveBeenCalled();
+ expect(gc).not.toHaveBeenCalled();
+ expect(mockState.localMutations.clearChecked).not.toHaveBeenCalled();
+ });
+
+ it('does not emit deletion confirmation', () => {
+ expect(wrapper.emitted('deleted')).toBeUndefined();
+ });
+
+ it('alert is called', () => {
+ expect(createAlert).toHaveBeenCalled();
+ expect(createAlert).toHaveBeenCalledWith({
+ message: expect.any(String),
+ captureError: true,
+ error: expect.any(Error),
+ });
+ });
+
+ it('modal is hidden', () => {
+ expect(mockHideModal).toHaveBeenCalledTimes(1);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_delete_button_spec.js b/spec/frontend/ci/runner/components/runner_delete_button_spec.js
new file mode 100644
index 00000000000..02960ad427e
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_delete_button_spec.js
@@ -0,0 +1,275 @@
+import Vue from 'vue';
+import { GlButton } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
+import runnerDeleteMutation from '~/ci/runner/graphql/shared/runner_delete.mutation.graphql';
+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 { I18N_DELETE_RUNNER } from '~/ci/runner/constants';
+
+import RunnerDeleteButton from '~/ci/runner/components/runner_delete_button.vue';
+import RunnerDeleteModal from '~/ci/runner/components/runner_delete_modal.vue';
+import { allRunnersData } from '../mock_data';
+
+const mockRunner = allRunnersData.data.runners.nodes[0];
+const mockRunnerId = getIdFromGraphQLId(mockRunner.id);
+const mockRunnerName = `#${mockRunnerId} (${mockRunner.shortSha})`;
+
+Vue.use(VueApollo);
+
+jest.mock('~/flash');
+jest.mock('~/ci/runner/sentry_utils');
+
+describe('RunnerDeleteButton', () => {
+ let wrapper;
+ let apolloProvider;
+ let apolloCache;
+ let runnerDeleteHandler;
+
+ const findBtn = () => wrapper.findComponent(GlButton);
+ const findModal = () => wrapper.findComponent(RunnerDeleteModal);
+
+ const getTooltip = () => getBinding(wrapper.element, 'gl-tooltip').value;
+ const getModal = () => getBinding(findBtn().element, 'gl-modal').value;
+
+ const createComponent = ({ props = {}, mountFn = shallowMountExtended } = {}) => {
+ const { runner, ...propsData } = props;
+
+ wrapper = mountFn(RunnerDeleteButton, {
+ propsData: {
+ runner: {
+ // We need typename so that cache.identify works
+ // eslint-disable-next-line no-underscore-dangle
+ __typename: mockRunner.__typename,
+ id: mockRunner.id,
+ shortSha: mockRunner.shortSha,
+ ...runner,
+ },
+ ...propsData,
+ },
+ apolloProvider,
+ directives: {
+ GlTooltip: createMockDirective(),
+ GlModal: createMockDirective(),
+ },
+ });
+ };
+
+ const clickOkAndWait = async () => {
+ findModal().vm.$emit('primary');
+ await waitForPromises();
+ };
+
+ beforeEach(() => {
+ runnerDeleteHandler = jest.fn().mockImplementation(() => {
+ return Promise.resolve({
+ data: {
+ runnerDelete: {
+ errors: [],
+ },
+ },
+ });
+ });
+ apolloProvider = createMockApollo([[runnerDeleteMutation, runnerDeleteHandler]]);
+ apolloCache = apolloProvider.defaultClient.cache;
+
+ jest.spyOn(apolloCache, 'evict');
+ jest.spyOn(apolloCache, 'gc');
+
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Displays a delete button without an icon', () => {
+ expect(findBtn().props()).toMatchObject({
+ loading: false,
+ icon: '',
+ });
+ expect(findBtn().classes('btn-icon')).toBe(false);
+ expect(findBtn().text()).toBe(I18N_DELETE_RUNNER);
+ });
+
+ it('Displays a modal with the runner name', () => {
+ expect(findModal().props('runnerName')).toBe(mockRunnerName);
+ });
+
+ it('Does not have tabindex when button is enabled', () => {
+ expect(wrapper.attributes('tabindex')).toBeUndefined();
+ });
+
+ it('Displays a modal when clicked', () => {
+ const modalId = `delete-runner-modal-${mockRunnerId}`;
+
+ expect(getModal()).toBe(modalId);
+ expect(findModal().attributes('modal-id')).toBe(modalId);
+ });
+
+ it('Does not display redundant text for screen readers', () => {
+ expect(findBtn().attributes('aria-label')).toBe(undefined);
+ });
+
+ it('Passes other attributes to the button', () => {
+ createComponent({ props: { category: 'secondary' } });
+
+ expect(findBtn().props('category')).toBe('secondary');
+ });
+
+ describe(`Before the delete button is clicked`, () => {
+ it('The mutation has not been called', () => {
+ expect(runnerDeleteHandler).toHaveBeenCalledTimes(0);
+ });
+ });
+
+ describe('Immediately after the delete button is clicked', () => {
+ beforeEach(async () => {
+ findModal().vm.$emit('primary');
+ });
+
+ it('The button has a loading state', async () => {
+ expect(findBtn().props('loading')).toBe(true);
+ });
+
+ it('The stale tooltip is removed', async () => {
+ expect(getTooltip()).toBe('');
+ });
+ });
+
+ describe('After clicking on the delete button', () => {
+ beforeEach(async () => {
+ await clickOkAndWait();
+ });
+
+ it('The mutation to delete is called', () => {
+ expect(runnerDeleteHandler).toHaveBeenCalledTimes(1);
+ expect(runnerDeleteHandler).toHaveBeenCalledWith({
+ input: {
+ id: mockRunner.id,
+ },
+ });
+ });
+
+ it('The user can be notified with an event', () => {
+ const deleted = wrapper.emitted('deleted');
+
+ expect(deleted).toHaveLength(1);
+ expect(deleted[0][0].message).toMatch(`#${mockRunnerId}`);
+ expect(deleted[0][0].message).toMatch(`${mockRunner.shortSha}`);
+ });
+
+ it('evicts runner from apollo cache', () => {
+ expect(apolloCache.evict).toHaveBeenCalledWith({
+ id: apolloCache.identify(mockRunner),
+ });
+ expect(apolloCache.gc).toHaveBeenCalled();
+ });
+ });
+
+ describe('When update fails', () => {
+ describe('On a network error', () => {
+ const mockErrorMsg = 'Update error!';
+
+ beforeEach(async () => {
+ runnerDeleteHandler.mockRejectedValueOnce(new Error(mockErrorMsg));
+
+ await clickOkAndWait();
+ });
+
+ it('error is reported to sentry', () => {
+ expect(captureException).toHaveBeenCalledWith({
+ error: new Error(mockErrorMsg),
+ component: 'RunnerDeleteButton',
+ });
+ });
+
+ it('error is shown to the user', () => {
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith({
+ title: expect.stringContaining(mockRunnerName),
+ message: mockErrorMsg,
+ });
+ });
+ });
+
+ describe('On a validation error', () => {
+ const mockErrorMsg = 'Runner not found!';
+ const mockErrorMsg2 = 'User not allowed!';
+
+ beforeEach(async () => {
+ runnerDeleteHandler.mockResolvedValueOnce({
+ data: {
+ runnerDelete: {
+ errors: [mockErrorMsg, mockErrorMsg2],
+ },
+ },
+ });
+
+ await clickOkAndWait();
+ });
+
+ it('error is reported to sentry', () => {
+ expect(captureException).toHaveBeenCalledWith({
+ error: new Error(`${mockErrorMsg} ${mockErrorMsg2}`),
+ component: 'RunnerDeleteButton',
+ });
+ });
+
+ it('error is shown to the user', () => {
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith({
+ title: expect.stringContaining(mockRunnerName),
+ message: `${mockErrorMsg} ${mockErrorMsg2}`,
+ });
+ });
+
+ it('does not evict runner from apollo cache', () => {
+ expect(apolloCache.evict).not.toHaveBeenCalled();
+ expect(apolloCache.gc).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('When displaying a compact button for an active runner', () => {
+ beforeEach(() => {
+ createComponent({
+ props: {
+ runner: {
+ active: true,
+ },
+ compact: true,
+ },
+ mountFn: mountExtended,
+ });
+ });
+
+ it('Displays no text', () => {
+ expect(findBtn().text()).toBe('');
+ expect(findBtn().classes('btn-icon')).toBe(true);
+ });
+
+ it('Display correctly for screen readers', () => {
+ expect(findBtn().attributes('aria-label')).toBe(I18N_DELETE_RUNNER);
+ expect(getTooltip()).toBe(I18N_DELETE_RUNNER);
+ });
+
+ describe('Immediately after the button is clicked', () => {
+ beforeEach(async () => {
+ findModal().vm.$emit('primary');
+ });
+
+ it('The button has a loading state', async () => {
+ expect(findBtn().props('loading')).toBe(true);
+ });
+
+ it('The stale tooltip is removed', async () => {
+ expect(getTooltip()).toBe('');
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_delete_modal_spec.js b/spec/frontend/ci/runner/components/runner_delete_modal_spec.js
new file mode 100644
index 00000000000..f2fb0206763
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_delete_modal_spec.js
@@ -0,0 +1,60 @@
+import { GlModal } from '@gitlab/ui';
+import { mount, shallowMount } from '@vue/test-utils';
+import RunnerDeleteModal from '~/ci/runner/components/runner_delete_modal.vue';
+
+describe('RunnerDeleteModal', () => {
+ let wrapper;
+
+ const findGlModal = () => wrapper.findComponent(GlModal);
+
+ const createComponent = ({ props = {} } = {}, mountFn = shallowMount) => {
+ wrapper = mountFn(RunnerDeleteModal, {
+ attachTo: document.body,
+ propsData: {
+ runnerName: '#99 (AABBCCDD)',
+ ...props,
+ },
+ attrs: {
+ modalId: 'delete-runner-modal-99',
+ },
+ });
+ };
+
+ it('Displays title', () => {
+ createComponent();
+
+ expect(findGlModal().props('title')).toBe('Delete runner #99 (AABBCCDD)?');
+ });
+
+ it('Displays buttons', () => {
+ createComponent();
+
+ expect(findGlModal().props('actionPrimary')).toMatchObject({ text: 'Delete runner' });
+ expect(findGlModal().props('actionCancel')).toMatchObject({ text: 'Cancel' });
+ });
+
+ it('Displays contents', () => {
+ createComponent();
+
+ expect(findGlModal().html()).toContain(
+ 'The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?',
+ );
+ });
+
+ describe('When modal is confirmed by the user', () => {
+ let hideModalSpy;
+
+ beforeEach(() => {
+ createComponent({}, mount);
+ hideModalSpy = jest.spyOn(wrapper.vm.$refs.modal, 'hide').mockImplementation(() => {});
+ });
+
+ it('Modal gets hidden', () => {
+ expect(hideModalSpy).toHaveBeenCalledTimes(0);
+
+ findGlModal().vm.$emit('primary');
+
+ expect(hideModalSpy).toHaveBeenCalledTimes(1);
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_details_spec.js b/spec/frontend/ci/runner/components/runner_details_spec.js
new file mode 100644
index 00000000000..65a81973869
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_details_spec.js
@@ -0,0 +1,130 @@
+import { GlSprintf, GlIntersperse } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
+import { useFakeDate } from 'helpers/fake_date';
+import { findDd } from 'helpers/dl_locator_helper';
+import { ACCESS_LEVEL_REF_PROTECTED, ACCESS_LEVEL_NOT_PROTECTED } from '~/ci/runner/constants';
+
+import RunnerDetails from '~/ci/runner/components/runner_details.vue';
+import RunnerDetail from '~/ci/runner/components/runner_detail.vue';
+import RunnerGroups from '~/ci/runner/components/runner_groups.vue';
+import RunnerTags from '~/ci/runner/components/runner_tags.vue';
+import RunnerTag from '~/ci/runner/components/runner_tag.vue';
+
+import { runnerData, runnerWithGroupData } from '../mock_data';
+
+const mockRunner = runnerData.data.runner;
+const mockGroupRunner = runnerWithGroupData.data.runner;
+
+describe('RunnerDetails', () => {
+ let wrapper;
+ const mockNow = '2021-01-15T12:00:00Z';
+ const mockOneHourAgo = '2021-01-15T11:00:00Z';
+
+ useFakeDate(mockNow);
+
+ const findDetailGroups = () => wrapper.findComponent(RunnerGroups);
+
+ const createComponent = ({ props = {}, stubs, mountFn = shallowMountExtended } = {}) => {
+ wrapper = mountFn(RunnerDetails, {
+ propsData: {
+ ...props,
+ },
+ stubs: {
+ RunnerDetail,
+ ...stubs,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('Details tab', () => {
+ describe.each`
+ field | runner | expectedValue
+ ${'Description'} | ${{ description: 'My runner' }} | ${'My runner'}
+ ${'Description'} | ${{ description: null }} | ${'None'}
+ ${'Last contact'} | ${{ contactedAt: mockOneHourAgo }} | ${'1 hour ago'}
+ ${'Last contact'} | ${{ contactedAt: null }} | ${'Never contacted'}
+ ${'Version'} | ${{ version: '12.3' }} | ${'12.3'}
+ ${'Version'} | ${{ version: null }} | ${'None'}
+ ${'Executor'} | ${{ executorName: 'shell' }} | ${'shell'}
+ ${'Architecture'} | ${{ architectureName: 'amd64' }} | ${'amd64'}
+ ${'Platform'} | ${{ platformName: 'darwin' }} | ${'darwin'}
+ ${'IP Address'} | ${{ ipAddress: '127.0.0.1' }} | ${'127.0.0.1'}
+ ${'IP Address'} | ${{ ipAddress: null }} | ${'None'}
+ ${'Configuration'} | ${{ accessLevel: ACCESS_LEVEL_REF_PROTECTED, runUntagged: true }} | ${'Protected, Runs untagged jobs'}
+ ${'Configuration'} | ${{ accessLevel: ACCESS_LEVEL_REF_PROTECTED, runUntagged: false }} | ${'Protected'}
+ ${'Configuration'} | ${{ accessLevel: ACCESS_LEVEL_NOT_PROTECTED, runUntagged: true }} | ${'Runs untagged jobs'}
+ ${'Configuration'} | ${{ accessLevel: ACCESS_LEVEL_NOT_PROTECTED, runUntagged: false }} | ${'None'}
+ ${'Maximum job timeout'} | ${{ maximumTimeout: null }} | ${'None'}
+ ${'Maximum job timeout'} | ${{ maximumTimeout: 0 }} | ${'0 seconds'}
+ ${'Maximum job timeout'} | ${{ maximumTimeout: 59 }} | ${'59 seconds'}
+ ${'Maximum job timeout'} | ${{ maximumTimeout: 10 * 60 + 5 }} | ${'10 minutes 5 seconds'}
+ ${'Token expiry'} | ${{ tokenExpiresAt: mockOneHourAgo }} | ${'1 hour ago'}
+ ${'Token expiry'} | ${{ tokenExpiresAt: null }} | ${'Never expires'}
+ `('"$field" field', ({ field, runner, expectedValue }) => {
+ beforeEach(() => {
+ createComponent({
+ props: {
+ runner: {
+ ...mockRunner,
+ ...runner,
+ },
+ },
+ stubs: {
+ GlIntersperse,
+ GlSprintf,
+ TimeAgo,
+ },
+ });
+ });
+
+ it(`displays expected value "${expectedValue}"`, () => {
+ expect(findDd(field, wrapper).text()).toBe(expectedValue);
+ });
+ });
+
+ describe('"Tags" field', () => {
+ const stubs = { RunnerTags, RunnerTag };
+
+ it('displays expected value "tag-1 tag-2"', () => {
+ createComponent({
+ props: {
+ runner: { ...mockRunner, tagList: ['tag-1', 'tag-2'] },
+ },
+ stubs,
+ });
+
+ expect(findDd('Tags', wrapper).text().replace(/\s+/g, ' ')).toBe('tag-1 tag-2');
+ });
+
+ it('displays "None" when runner has no tags', () => {
+ createComponent({
+ props: {
+ runner: { ...mockRunner, tagList: [] },
+ },
+ stubs,
+ });
+
+ expect(findDd('Tags', wrapper).text().replace(/\s+/g, ' ')).toBe('None');
+ });
+ });
+
+ describe('Group runners', () => {
+ beforeEach(() => {
+ createComponent({
+ props: {
+ runner: mockGroupRunner,
+ },
+ });
+ });
+
+ it('Shows a group runner details', () => {
+ expect(findDetailGroups().props('runner')).toEqual(mockGroupRunner);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_edit_button_spec.js b/spec/frontend/ci/runner/components/runner_edit_button_spec.js
new file mode 100644
index 00000000000..907cdc90100
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_edit_button_spec.js
@@ -0,0 +1,41 @@
+import { shallowMount, mount } from '@vue/test-utils';
+import RunnerEditButton from '~/ci/runner/components/runner_edit_button.vue';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+
+describe('RunnerEditButton', () => {
+ let wrapper;
+
+ const getTooltipValue = () => getBinding(wrapper.element, 'gl-tooltip').value;
+
+ const createComponent = ({ attrs = {}, mountFn = shallowMount } = {}) => {
+ wrapper = mountFn(RunnerEditButton, {
+ attrs,
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Displays Edit text', () => {
+ expect(wrapper.attributes('aria-label')).toBe('Edit');
+ });
+
+ it('Displays Edit tooltip', () => {
+ expect(getTooltipValue()).toBe('Edit');
+ });
+
+ it('Renders a link and adds an href attribute', () => {
+ createComponent({ attrs: { href: '/edit' }, mountFn: mount });
+
+ expect(wrapper.element.tagName).toBe('A');
+ expect(wrapper.attributes('href')).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
new file mode 100644
index 00000000000..496c144083e
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_filtered_search_bar_spec.js
@@ -0,0 +1,188 @@
+import { GlFilteredSearch, GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import RunnerFilteredSearchBar from '~/ci/runner/components/runner_filtered_search_bar.vue';
+import { statusTokenConfig } from '~/ci/runner/components/search_tokens/status_token_config';
+import TagToken from '~/ci/runner/components/search_tokens/tag_token.vue';
+import { tagTokenConfig } from '~/ci/runner/components/search_tokens/tag_token_config';
+import {
+ PARAM_KEY_STATUS,
+ PARAM_KEY_TAG,
+ STATUS_ONLINE,
+ INSTANCE_TYPE,
+ DEFAULT_MEMBERSHIP,
+ DEFAULT_SORT,
+ CONTACTED_DESC,
+} from '~/ci/runner/constants';
+import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
+import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
+
+const mockSearch = {
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [],
+ pagination: { page: 1 },
+ sort: DEFAULT_SORT,
+};
+
+describe('RunnerList', () => {
+ let wrapper;
+
+ const findFilteredSearch = () => wrapper.findComponent(FilteredSearch);
+ const findGlFilteredSearch = () => wrapper.findComponent(GlFilteredSearch);
+ const findSortOptions = () => wrapper.findAllComponents(GlDropdownItem);
+
+ const mockOtherSort = CONTACTED_DESC;
+ const mockFilters = [
+ { type: PARAM_KEY_STATUS, value: { data: STATUS_ONLINE, operator: '=' } },
+ { type: 'filtered-search-term', value: { data: '' } },
+ ];
+
+ const expectToHaveLastEmittedInput = (value) => {
+ const inputs = wrapper.emitted('input');
+ expect(inputs[inputs.length - 1][0]).toEqual(value);
+ };
+
+ const createComponent = ({ props = {}, options = {} } = {}) => {
+ wrapper = shallowMountExtended(RunnerFilteredSearchBar, {
+ propsData: {
+ namespace: 'runners',
+ tokens: [],
+ value: mockSearch,
+ ...props,
+ },
+ stubs: {
+ FilteredSearch,
+ GlFilteredSearch,
+ GlDropdown,
+ GlDropdownItem,
+ },
+ ...options,
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('binds a namespace to the filtered search', () => {
+ expect(findFilteredSearch().props('namespace')).toBe('runners');
+ });
+
+ it('sets sorting options', () => {
+ const SORT_OPTIONS_COUNT = 2;
+
+ expect(findSortOptions()).toHaveLength(SORT_OPTIONS_COUNT);
+ expect(findSortOptions().at(0).text()).toBe('Created date');
+ expect(findSortOptions().at(1).text()).toBe('Last contact');
+ });
+
+ it('sets tokens to the filtered search', () => {
+ createComponent({
+ props: {
+ tokens: [statusTokenConfig, tagTokenConfig],
+ },
+ });
+
+ expect(findFilteredSearch().props('tokens')).toEqual([
+ expect.objectContaining({
+ type: PARAM_KEY_STATUS,
+ token: BaseToken,
+ options: expect.any(Array),
+ }),
+ expect.objectContaining({
+ type: PARAM_KEY_TAG,
+ token: TagToken,
+ }),
+ ]);
+ });
+
+ it('can be configured with null or undefined tokens, which are ignored', () => {
+ createComponent({
+ props: {
+ tokens: [statusTokenConfig, null, undefined],
+ },
+ });
+
+ expect(findFilteredSearch().props('tokens')).toEqual([statusTokenConfig]);
+ });
+
+ it('fails validation for v-model with the wrong shape', () => {
+ expect(() => {
+ createComponent({ props: { value: { filters: 'wrong_filters', sort: 'sort' } } });
+ }).toThrow('Invalid prop: custom validator check failed');
+
+ expect(() => {
+ createComponent({ props: { value: { sort: 'sort' } } });
+ }).toThrow('Invalid prop: custom validator check failed');
+ });
+
+ describe('when a search is preselected', () => {
+ beforeEach(() => {
+ createComponent({
+ props: {
+ value: {
+ runnerType: INSTANCE_TYPE,
+ membership: DEFAULT_MEMBERSHIP,
+ sort: mockOtherSort,
+ filters: mockFilters,
+ },
+ },
+ });
+ });
+
+ it('filter values are shown', () => {
+ expect(findGlFilteredSearch().props('value')).toMatchObject(mockFilters);
+ });
+
+ it('sort option is selected', () => {
+ expect(
+ findSortOptions()
+ .filter((w) => w.props('isChecked'))
+ .at(0)
+ .text(),
+ ).toEqual('Last contact');
+ });
+
+ it('when the user sets a filter, the "search" preserves the other filters', () => {
+ findGlFilteredSearch().vm.$emit('input', mockFilters);
+ findGlFilteredSearch().vm.$emit('submit');
+
+ expectToHaveLastEmittedInput({
+ runnerType: INSTANCE_TYPE,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: mockFilters,
+ sort: mockOtherSort,
+ pagination: {},
+ });
+ });
+ });
+
+ it('when the user sets a filter, the "search" is emitted with filters', () => {
+ findGlFilteredSearch().vm.$emit('input', mockFilters);
+ findGlFilteredSearch().vm.$emit('submit');
+
+ expectToHaveLastEmittedInput({
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: mockFilters,
+ sort: DEFAULT_SORT,
+ pagination: {},
+ });
+ });
+
+ it('when the user sets a sorting method, the "search" is emitted with the sort', () => {
+ findSortOptions().at(1).vm.$emit('click');
+
+ expectToHaveLastEmittedInput({
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [],
+ sort: mockOtherSort,
+ pagination: {},
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_groups_spec.js b/spec/frontend/ci/runner/components/runner_groups_spec.js
new file mode 100644
index 00000000000..0991feb2e55
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_groups_spec.js
@@ -0,0 +1,67 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+
+import RunnerGroups from '~/ci/runner/components/runner_groups.vue';
+import RunnerAssignedItem from '~/ci/runner/components/runner_assigned_item.vue';
+
+import { runnerData, runnerWithGroupData } from '../mock_data';
+
+const mockInstanceRunner = runnerData.data.runner;
+const mockGroupRunner = runnerWithGroupData.data.runner;
+const mockGroup = mockGroupRunner.groups.nodes[0];
+
+describe('RunnerGroups', () => {
+ let wrapper;
+
+ const findHeading = () => wrapper.find('h3');
+ const findRunnerAssignedItems = () => wrapper.findAllComponents(RunnerAssignedItem);
+
+ const createComponent = ({ runner = mockGroupRunner, mountFn = shallowMountExtended } = {}) => {
+ wrapper = mountFn(RunnerGroups, {
+ propsData: {
+ runner,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Shows a heading', () => {
+ createComponent();
+
+ expect(findHeading().text()).toBe('Assigned Group');
+ });
+
+ describe('When there is a group runner', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('Shows a project', () => {
+ createComponent();
+
+ const item = findRunnerAssignedItems().at(0);
+ const { webUrl, name, fullName, avatarUrl } = mockGroup;
+
+ expect(item.props()).toMatchObject({
+ href: webUrl,
+ name,
+ fullName,
+ avatarUrl,
+ });
+ });
+ });
+
+ describe('When there are no groups', () => {
+ beforeEach(() => {
+ createComponent({
+ runner: mockInstanceRunner,
+ });
+ });
+
+ it('Shows a "None" label', () => {
+ expect(wrapper.findByText('None').exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_header_spec.js b/spec/frontend/ci/runner/components/runner_header_spec.js
new file mode 100644
index 00000000000..a04011de1cd
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_header_spec.js
@@ -0,0 +1,124 @@
+import { GlSprintf } from '@gitlab/ui';
+import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import {
+ I18N_STATUS_ONLINE,
+ I18N_GROUP_TYPE,
+ GROUP_TYPE,
+ STATUS_ONLINE,
+} from '~/ci/runner/constants';
+import { TYPE_CI_RUNNER } from '~/graphql_shared/constants';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
+
+import RunnerHeader from '~/ci/runner/components/runner_header.vue';
+import RunnerTypeBadge from '~/ci/runner/components/runner_type_badge.vue';
+import RunnerStatusBadge from '~/ci/runner/components/runner_status_badge.vue';
+
+import { runnerData } from '../mock_data';
+
+const mockRunner = runnerData.data.runner;
+
+describe('RunnerHeader', () => {
+ let wrapper;
+
+ const findRunnerTypeBadge = () => wrapper.findComponent(RunnerTypeBadge);
+ const findRunnerStatusBadge = () => wrapper.findComponent(RunnerStatusBadge);
+ const findRunnerLockedIcon = () => wrapper.findByTestId('lock-icon');
+ const findTimeAgo = () => wrapper.findComponent(TimeAgo);
+
+ const createComponent = ({ runner = {}, options = {}, mountFn = shallowMountExtended } = {}) => {
+ wrapper = mountFn(RunnerHeader, {
+ propsData: {
+ runner: {
+ ...mockRunner,
+ ...runner,
+ },
+ },
+ stubs: {
+ GlSprintf,
+ TimeAgo,
+ },
+ ...options,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('displays the runner status', () => {
+ createComponent({
+ mountFn: mountExtended,
+ runner: {
+ status: STATUS_ONLINE,
+ },
+ });
+
+ expect(findRunnerStatusBadge().text()).toContain(I18N_STATUS_ONLINE);
+ });
+
+ it('displays the runner type', () => {
+ createComponent({
+ mountFn: mountExtended,
+ runner: {
+ runnerType: GROUP_TYPE,
+ },
+ });
+
+ expect(findRunnerTypeBadge().text()).toContain(I18N_GROUP_TYPE);
+ });
+
+ it('displays the runner id', () => {
+ createComponent({
+ runner: {
+ id: convertToGraphQLId(TYPE_CI_RUNNER, 99),
+ },
+ });
+
+ expect(wrapper.text()).toContain('Runner #99');
+ });
+
+ it('displays the runner locked icon', () => {
+ createComponent({
+ runner: {
+ locked: true,
+ },
+ mountFn: mountExtended,
+ });
+
+ expect(findRunnerLockedIcon().exists()).toBe(true);
+ });
+
+ it('displays the runner creation time', () => {
+ createComponent();
+
+ expect(wrapper.text()).toMatch(/created .+/);
+ expect(findTimeAgo().props('time')).toBe(mockRunner.createdAt);
+ });
+
+ it('does not display runner creation time if "createdAt" is missing', () => {
+ createComponent({
+ runner: {
+ id: convertToGraphQLId(TYPE_CI_RUNNER, 99),
+ createdAt: null,
+ },
+ });
+
+ expect(wrapper.text()).toContain('Runner #99');
+ expect(wrapper.text()).not.toMatch(/created .+/);
+ expect(findTimeAgo().exists()).toBe(false);
+ });
+
+ it('displays actions in a slot', () => {
+ createComponent({
+ options: {
+ slots: {
+ actions: '<div data-testid="actions-content">My Actions</div>',
+ },
+ mountFn: mountExtended,
+ },
+ });
+
+ expect(wrapper.findByTestId('actions-content').text()).toBe('My Actions');
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_jobs_spec.js b/spec/frontend/ci/runner/components/runner_jobs_spec.js
new file mode 100644
index 00000000000..bdb8a4a31a3
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_jobs_spec.js
@@ -0,0 +1,155 @@
+import { GlSkeletonLoader } from '@gitlab/ui';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/flash';
+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';
+import { captureException } from '~/ci/runner/sentry_utils';
+import { I18N_NO_JOBS_FOUND, RUNNER_DETAILS_JOBS_PAGE_SIZE } from '~/ci/runner/constants';
+
+import runnerJobsQuery from '~/ci/runner/graphql/show/runner_jobs.query.graphql';
+
+import { runnerData, runnerJobsData } from '../mock_data';
+
+jest.mock('~/flash');
+jest.mock('~/ci/runner/sentry_utils');
+
+const mockRunner = runnerData.data.runner;
+const mockRunnerWithJobs = runnerJobsData.data.runner;
+const mockJobs = mockRunnerWithJobs.jobs.nodes;
+
+Vue.use(VueApollo);
+
+describe('RunnerJobs', () => {
+ let wrapper;
+ let mockRunnerJobsQuery;
+
+ const findGlSkeletonLoading = () => wrapper.findComponent(GlSkeletonLoader);
+ const findRunnerJobsTable = () => wrapper.findComponent(RunnerJobsTable);
+ const findRunnerPagination = () => wrapper.findComponent(RunnerPagination);
+
+ const createComponent = ({ mountFn = shallowMountExtended } = {}) => {
+ wrapper = mountFn(RunnerJobs, {
+ apolloProvider: createMockApollo([[runnerJobsQuery, mockRunnerJobsQuery]]),
+ propsData: {
+ runner: mockRunner,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ mockRunnerJobsQuery = jest.fn();
+ });
+
+ afterEach(() => {
+ mockRunnerJobsQuery.mockReset();
+ wrapper.destroy();
+ });
+
+ it('Requests runner jobs', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(mockRunnerJobsQuery).toHaveBeenCalledTimes(1);
+ expect(mockRunnerJobsQuery).toHaveBeenCalledWith({
+ id: mockRunner.id,
+ first: RUNNER_DETAILS_JOBS_PAGE_SIZE,
+ });
+ });
+
+ describe('When there are jobs assigned', () => {
+ beforeEach(async () => {
+ mockRunnerJobsQuery.mockResolvedValueOnce(runnerJobsData);
+
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('Shows jobs', () => {
+ const jobs = findRunnerJobsTable().props('jobs');
+
+ expect(jobs).toEqual(mockJobs);
+ });
+
+ describe('When "Next" page is clicked', () => {
+ beforeEach(async () => {
+ findRunnerPagination().vm.$emit('input', { page: 2, after: 'AFTER_CURSOR' });
+
+ await waitForPromises();
+ });
+
+ it('A new page is requested', () => {
+ expect(mockRunnerJobsQuery).toHaveBeenCalledTimes(2);
+ expect(mockRunnerJobsQuery).toHaveBeenLastCalledWith({
+ id: mockRunner.id,
+ first: RUNNER_DETAILS_JOBS_PAGE_SIZE,
+ after: 'AFTER_CURSOR',
+ });
+ });
+ });
+ });
+
+ describe('When loading', () => {
+ it('shows loading indicator and no other content', () => {
+ createComponent();
+
+ expect(findGlSkeletonLoading().exists()).toBe(true);
+ expect(findRunnerJobsTable().exists()).toBe(false);
+ expect(findRunnerPagination().attributes('disabled')).toBe('true');
+ });
+ });
+
+ describe('When there are no jobs', () => {
+ beforeEach(async () => {
+ mockRunnerJobsQuery.mockResolvedValueOnce({
+ data: {
+ runner: {
+ id: mockRunner.id,
+ projectCount: 0,
+ jobs: {
+ nodes: [],
+ pageInfo: {
+ hasNextPage: false,
+ hasPreviousPage: false,
+ startCursor: '',
+ endCursor: '',
+ },
+ },
+ },
+ },
+ });
+
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('Shows a "None" label', () => {
+ expect(wrapper.text()).toBe(I18N_NO_JOBS_FOUND);
+ });
+ });
+
+ describe('When an error occurs', () => {
+ beforeEach(async () => {
+ mockRunnerJobsQuery.mockRejectedValue(new Error('Error!'));
+
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('shows an error', () => {
+ expect(createAlert).toHaveBeenCalled();
+ });
+
+ it('reports an error', () => {
+ expect(captureException).toHaveBeenCalledWith({
+ component: 'RunnerJobs',
+ error: expect.any(Error),
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_jobs_table_spec.js b/spec/frontend/ci/runner/components/runner_jobs_table_spec.js
new file mode 100644
index 00000000000..8defe568df8
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_jobs_table_spec.js
@@ -0,0 +1,137 @@
+import { GlTableLite } from '@gitlab/ui';
+import {
+ extendedWrapper,
+ shallowMountExtended,
+ mountExtended,
+} from 'helpers/vue_test_utils_helper';
+import { __, s__ } from '~/locale';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import RunnerJobsTable from '~/ci/runner/components/runner_jobs_table.vue';
+import { useFakeDate } from 'helpers/fake_date';
+import { runnerJobsData } from '../mock_data';
+
+const mockJobs = runnerJobsData.data.runner.jobs.nodes;
+
+describe('RunnerJobsTable', () => {
+ let wrapper;
+ const mockNow = '2021-01-15T12:00:00Z';
+ const mockOneHourAgo = '2021-01-15T11:00:00Z';
+
+ useFakeDate(mockNow);
+
+ const findTable = () => wrapper.findComponent(GlTableLite);
+ const findHeaders = () => wrapper.findAll('th');
+ const findRows = () => wrapper.findAll('[data-testid^="job-row-"]');
+ const findCell = ({ field }) =>
+ extendedWrapper(findRows().at(0).find(`[data-testid="td-${field}"]`));
+
+ const createComponent = ({ props = {} } = {}, mountFn = shallowMountExtended) => {
+ wrapper = mountFn(RunnerJobsTable, {
+ propsData: {
+ jobs: mockJobs,
+ ...props,
+ },
+ stubs: {
+ GlTableLite,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Sets job id as a row key', () => {
+ createComponent();
+
+ expect(findTable().attributes('primarykey')).toBe('id');
+ });
+
+ describe('Table data', () => {
+ beforeEach(() => {
+ createComponent({}, mountExtended);
+ });
+
+ it('Displays headers', () => {
+ const headerLabels = findHeaders().wrappers.map((w) => w.text());
+
+ expect(headerLabels).toEqual([
+ s__('Job|Status'),
+ __('Job'),
+ __('Project'),
+ __('Commit'),
+ s__('Job|Finished at'),
+ s__('Job|Duration'),
+ s__('Job|Queued'),
+ s__('Runners|Tags'),
+ ]);
+ });
+
+ it('Displays a list of jobs', () => {
+ expect(findRows()).toHaveLength(1);
+ });
+
+ it('Displays details of a job', () => {
+ const { id, detailedStatus, pipeline, shortSha, commitPath } = mockJobs[0];
+
+ expect(findCell({ field: 'status' }).text()).toMatchInterpolatedText(detailedStatus.text);
+
+ expect(findCell({ field: 'job' }).text()).toContain(`#${getIdFromGraphQLId(id)}`);
+ expect(findCell({ field: 'job' }).find('a').attributes('href')).toBe(
+ detailedStatus.detailsPath,
+ );
+
+ expect(findCell({ field: 'project' }).text()).toBe(pipeline.project.name);
+ expect(findCell({ field: 'project' }).find('a').attributes('href')).toBe(
+ pipeline.project.webUrl,
+ );
+
+ expect(findCell({ field: 'commit' }).text()).toBe(shortSha);
+ expect(findCell({ field: 'commit' }).find('a').attributes('href')).toBe(commitPath);
+ });
+ });
+
+ describe('Table data formatting', () => {
+ let mockJobsCopy;
+
+ beforeEach(() => {
+ mockJobsCopy = [
+ {
+ ...mockJobs[0],
+ },
+ ];
+ });
+
+ it('Formats finishedAt time', () => {
+ mockJobsCopy[0].finishedAt = mockOneHourAgo;
+
+ createComponent({ props: { jobs: mockJobsCopy } }, mountExtended);
+
+ expect(findCell({ field: 'finished_at' }).text()).toBe('1 hour ago');
+ });
+
+ it('Formats duration time', () => {
+ mockJobsCopy[0].duration = 60;
+
+ createComponent({ props: { jobs: mockJobsCopy } }, mountExtended);
+
+ expect(findCell({ field: 'duration' }).text()).toBe('00:01:00');
+ });
+
+ it('Formats queued time', () => {
+ mockJobsCopy[0].queuedDuration = 30;
+
+ createComponent({ props: { jobs: mockJobsCopy } }, mountExtended);
+
+ expect(findCell({ field: 'queued' }).text()).toBe('00:00:30');
+ });
+
+ it('Formats tags', () => {
+ mockJobsCopy[0].tags = ['tag-1', 'tag-2'];
+
+ createComponent({ props: { jobs: mockJobsCopy } }, mountExtended);
+
+ expect(findCell({ field: 'tags' }).text()).toMatchInterpolatedText('tag-1 tag-2');
+ });
+ });
+});
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
new file mode 100644
index 00000000000..d351f7b6908
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_list_empty_state_spec.js
@@ -0,0 +1,103 @@
+import { GlEmptyState, GlLink, 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 RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
+
+import RunnerListEmptyState from '~/ci/runner/components/runner_list_empty_state.vue';
+
+const mockSvgPath = 'mock-svg-path.svg';
+const mockFilteredSvgPath = 'mock-filtered-svg-path.svg';
+const mockRegistrationToken = 'REGISTRATION_TOKEN';
+
+describe('RunnerListEmptyState', () => {
+ let wrapper;
+
+ const findEmptyState = () => wrapper.findComponent(GlEmptyState);
+ const findLink = () => wrapper.findComponent(GlLink);
+ const findRunnerInstructionsModal = () => wrapper.findComponent(RunnerInstructionsModal);
+
+ const createComponent = ({ props, mountFn = shallowMountExtended } = {}) => {
+ wrapper = mountFn(RunnerListEmptyState, {
+ propsData: {
+ svgPath: mockSvgPath,
+ filteredSvgPath: mockFilteredSvgPath,
+ registrationToken: mockRegistrationToken,
+ ...props,
+ },
+ directives: {
+ GlModal: createMockDirective(),
+ },
+ stubs: {
+ GlEmptyState,
+ GlSprintf,
+ GlLink,
+ },
+ });
+ };
+
+ describe('when search is not filtered', () => {
+ const title = s__('Runners|Get started with runners');
+
+ describe('when there is a registration token', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders an illustration', () => {
+ expect(findEmptyState().props('svgPath')).toBe(mockSvgPath);
+ });
+
+ it('displays "no results" text with instructions', () => {
+ const desc = s__(
+ 'Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner.',
+ );
+
+ expect(findEmptyState().text()).toMatchInterpolatedText(`${title} ${desc}`);
+ });
+
+ it('opens a runner registration instructions modal with a link', () => {
+ const { value } = getBinding(findLink().element, 'gl-modal');
+
+ expect(findRunnerInstructionsModal().props('modalId')).toEqual(value);
+ });
+ });
+
+ describe('when there is no registration token', () => {
+ beforeEach(() => {
+ createComponent({ props: { registrationToken: null } });
+ });
+
+ it('renders an illustration', () => {
+ expect(findEmptyState().props('svgPath')).toBe(mockSvgPath);
+ });
+
+ it('displays "no results" text', () => {
+ const desc = s__(
+ 'Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator.',
+ );
+
+ expect(findEmptyState().text()).toMatchInterpolatedText(`${title} ${desc}`);
+ });
+
+ it('has no registration instructions link', () => {
+ expect(findLink().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('when search is filtered', () => {
+ beforeEach(() => {
+ createComponent({ props: { isSearchFiltered: true } });
+ });
+
+ it('renders a "filtered search" illustration', () => {
+ expect(findEmptyState().props('svgPath')).toBe(mockFilteredSvgPath);
+ });
+
+ it('displays "no filtered results" text', () => {
+ expect(findEmptyState().text()).toContain(s__('Runners|No results found'));
+ expect(findEmptyState().text()).toContain(s__('Runners|Edit your search and try again'));
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_list_spec.js b/spec/frontend/ci/runner/components/runner_list_spec.js
new file mode 100644
index 00000000000..d53a0ce8f4f
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_list_spec.js
@@ -0,0 +1,231 @@
+import { GlTableLite, GlSkeletonLoader } from '@gitlab/ui';
+import HelpPopover from '~/vue_shared/components/help_popover.vue';
+import {
+ extendedWrapper,
+ shallowMountExtended,
+ mountExtended,
+} from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { s__ } from '~/locale';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { createLocalState } from '~/ci/runner/graphql/list/local_state';
+
+import RunnerList from '~/ci/runner/components/runner_list.vue';
+import RunnerBulkDelete from '~/ci/runner/components/runner_bulk_delete.vue';
+import RunnerBulkDeleteCheckbox from '~/ci/runner/components/runner_bulk_delete_checkbox.vue';
+
+import { I18N_PROJECT_TYPE, I18N_STATUS_NEVER_CONTACTED } from '~/ci/runner/constants';
+import { allRunnersData, onlineContactTimeoutSecs, staleTimeoutSecs } from '../mock_data';
+
+const mockRunners = allRunnersData.data.runners.nodes;
+const mockActiveRunnersCount = mockRunners.length;
+
+describe('RunnerList', () => {
+ let wrapper;
+ let cacheConfig;
+ let localMutations;
+
+ const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
+ const findTable = () => wrapper.findComponent(GlTableLite);
+ const findHeaders = () => wrapper.findAll('th');
+ const findRows = () => wrapper.findAll('[data-testid^="runner-row-"]');
+ const findCell = ({ row = 0, fieldKey }) =>
+ extendedWrapper(findRows().at(row).find(`[data-testid="td-${fieldKey}"]`));
+ const findRunnerBulkDelete = () => wrapper.findComponent(RunnerBulkDelete);
+ const findRunnerBulkDeleteCheckbox = () => wrapper.findComponent(RunnerBulkDeleteCheckbox);
+
+ const createComponent = (
+ { props = {}, provide = {}, ...options } = {},
+ mountFn = shallowMountExtended,
+ ) => {
+ ({ cacheConfig, localMutations } = createLocalState());
+
+ wrapper = mountFn(RunnerList, {
+ apolloProvider: createMockApollo([], {}, cacheConfig),
+ propsData: {
+ runners: mockRunners,
+ activeRunnersCount: mockActiveRunnersCount,
+ ...props,
+ },
+ provide: {
+ localMutations,
+ onlineContactTimeoutSecs,
+ staleTimeoutSecs,
+ ...provide,
+ },
+ ...options,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Displays headers', () => {
+ createComponent(
+ {
+ stubs: {
+ HelpPopover: {
+ template: '<div/>',
+ },
+ },
+ },
+ mountExtended,
+ );
+
+ const headerLabels = findHeaders().wrappers.map((w) => w.text());
+
+ expect(findHeaders().at(0).findComponent(HelpPopover).exists()).toBe(true);
+ expect(findHeaders().at(2).findComponent(HelpPopover).exists()).toBe(true);
+
+ expect(headerLabels).toEqual([
+ s__('Runners|Status'),
+ s__('Runners|Runner'),
+ s__('Runners|Owner'),
+ '', // actions has no label
+ ]);
+ });
+
+ it('Sets runner id as a row key', () => {
+ createComponent();
+
+ expect(findTable().attributes('primary-key')).toBe('id');
+ });
+
+ it('Displays a list of runners', () => {
+ createComponent({}, mountExtended);
+
+ expect(findRows()).toHaveLength(4);
+
+ expect(findSkeletonLoader().exists()).toBe(false);
+ });
+
+ it('Displays details of a runner', () => {
+ createComponent({}, mountExtended);
+
+ const { id, description, version, shortSha } = mockRunners[0];
+ const numericId = getIdFromGraphQLId(id);
+
+ // Badges
+ expect(findCell({ fieldKey: 'status' }).text()).toMatchInterpolatedText(
+ I18N_STATUS_NEVER_CONTACTED,
+ );
+
+ // Runner summary
+ const summary = findCell({ fieldKey: 'summary' }).text();
+
+ expect(summary).toContain(`#${numericId} (${shortSha})`);
+ expect(summary).toContain(I18N_PROJECT_TYPE);
+
+ expect(summary).toContain(version);
+ expect(summary).toContain(description);
+
+ expect(summary).toContain('Last contact');
+ expect(summary).toContain('0'); // job count
+ expect(summary).toContain('Created');
+
+ // Actions
+ expect(findCell({ fieldKey: 'actions' }).exists()).toBe(true);
+ });
+
+ describe('When the list is checkable', () => {
+ beforeEach(() => {
+ createComponent(
+ {
+ props: {
+ checkable: true,
+ },
+ },
+ mountExtended,
+ );
+ });
+
+ it('runner bulk delete is available', () => {
+ expect(findRunnerBulkDelete().props('runners')).toEqual(mockRunners);
+ });
+
+ it('runner bulk delete checkbox is available', () => {
+ expect(findRunnerBulkDeleteCheckbox().props('runners')).toEqual(mockRunners);
+ });
+
+ it('Displays a checkbox field', () => {
+ expect(findCell({ fieldKey: 'checkbox' }).find('input').exists()).toBe(true);
+ });
+
+ it('Sets a runner as checked', async () => {
+ const runner = mockRunners[0];
+ const setRunnerCheckedMock = jest
+ .spyOn(localMutations, 'setRunnerChecked')
+ .mockImplementation(() => {});
+
+ const checkbox = findCell({ fieldKey: 'checkbox' }).find('input');
+ await checkbox.setChecked();
+
+ expect(setRunnerCheckedMock).toHaveBeenCalledTimes(1);
+ expect(setRunnerCheckedMock).toHaveBeenCalledWith({
+ runner,
+ isChecked: true,
+ });
+ });
+
+ it('Emits a deleted event', async () => {
+ const event = { message: 'Deleted!' };
+ findRunnerBulkDelete().vm.$emit('deleted', event);
+
+ expect(wrapper.emitted('deleted')).toEqual([[event]]);
+ });
+ });
+
+ describe('Scoped cell slots', () => {
+ it('Render #runner-name slot in "summary" cell', () => {
+ createComponent(
+ {
+ scopedSlots: { 'runner-name': ({ runner }) => `Summary: ${runner.id}` },
+ },
+ mountExtended,
+ );
+
+ expect(findCell({ fieldKey: 'summary' }).text()).toContain(`Summary: ${mockRunners[0].id}`);
+ });
+
+ it('Render #runner-actions-cell slot in "actions" cell', () => {
+ createComponent(
+ {
+ scopedSlots: { 'runner-actions-cell': ({ runner }) => `Actions: ${runner.id}` },
+ },
+ mountExtended,
+ );
+
+ expect(findCell({ fieldKey: 'actions' }).text()).toBe(`Actions: ${mockRunners[0].id}`);
+ });
+ });
+
+ it('Shows runner identifier', () => {
+ const { id, shortSha } = mockRunners[0];
+ const numericId = getIdFromGraphQLId(id);
+
+ createComponent({}, mountExtended);
+
+ expect(findCell({ fieldKey: 'summary' }).text()).toContain(`#${numericId} (${shortSha})`);
+ });
+
+ describe('When data is loading', () => {
+ it('shows a busy state', () => {
+ createComponent({ props: { runners: [], loading: true } });
+
+ expect(findTable().classes('gl-opacity-6')).toBe(true);
+ });
+
+ it('when there are no runners, shows an skeleton loader', () => {
+ createComponent({ props: { runners: [], loading: true } }, mountExtended);
+
+ expect(findSkeletonLoader().exists()).toBe(true);
+ });
+
+ it('when there are runners, shows a busy indicator skeleton loader', () => {
+ createComponent({ props: { loading: true } }, mountExtended);
+
+ expect(findSkeletonLoader().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_membership_toggle_spec.js b/spec/frontend/ci/runner/components/runner_membership_toggle_spec.js
new file mode 100644
index 00000000000..f089becd400
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_membership_toggle_spec.js
@@ -0,0 +1,57 @@
+import { GlToggle } from '@gitlab/ui';
+import { shallowMount, mount } from '@vue/test-utils';
+import RunnerMembershipToggle from '~/ci/runner/components/runner_membership_toggle.vue';
+import {
+ I18N_SHOW_ONLY_INHERITED,
+ MEMBERSHIP_DESCENDANTS,
+ MEMBERSHIP_ALL_AVAILABLE,
+} from '~/ci/runner/constants';
+
+describe('RunnerMembershipToggle', () => {
+ let wrapper;
+
+ const findToggle = () => wrapper.findComponent(GlToggle);
+
+ const createComponent = ({ props = {}, mountFn = shallowMount } = {}) => {
+ wrapper = mountFn(RunnerMembershipToggle, {
+ propsData: props,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Displays text', () => {
+ createComponent({ mountFn: mount });
+
+ expect(wrapper.text()).toBe(I18N_SHOW_ONLY_INHERITED);
+ });
+
+ it.each`
+ membershipValue | toggleValue
+ ${MEMBERSHIP_DESCENDANTS} | ${true}
+ ${MEMBERSHIP_ALL_AVAILABLE} | ${false}
+ `(
+ 'Displays a membership of $membershipValue as enabled=$toggleValue',
+ ({ membershipValue, toggleValue }) => {
+ createComponent({ props: { value: membershipValue } });
+
+ expect(findToggle().props('value')).toBe(toggleValue);
+ },
+ );
+
+ it.each`
+ changeEvt | membershipValue
+ ${true} | ${MEMBERSHIP_DESCENDANTS}
+ ${false} | ${MEMBERSHIP_ALL_AVAILABLE}
+ `(
+ 'Emits $changeEvt when value is changed to $membershipValue',
+ ({ changeEvt, membershipValue }) => {
+ createComponent();
+ findToggle().vm.$emit('change', changeEvt);
+
+ expect(wrapper.emitted('input')).toStrictEqual([[membershipValue]]);
+ },
+ );
+});
diff --git a/spec/frontend/ci/runner/components/runner_pagination_spec.js b/spec/frontend/ci/runner/components/runner_pagination_spec.js
new file mode 100644
index 00000000000..f835ee4514d
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_pagination_spec.js
@@ -0,0 +1,115 @@
+import { GlKeysetPagination } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import RunnerPagination from '~/ci/runner/components/runner_pagination.vue';
+
+const mockStartCursor = 'START_CURSOR';
+const mockEndCursor = 'END_CURSOR';
+
+describe('RunnerPagination', () => {
+ let wrapper;
+
+ const findPagination = () => wrapper.findComponent(GlKeysetPagination);
+
+ const createComponent = (propsData = {}) => {
+ wrapper = shallowMount(RunnerPagination, {
+ propsData,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('When in between pages', () => {
+ const mockPageInfo = {
+ startCursor: mockStartCursor,
+ endCursor: mockEndCursor,
+ hasPreviousPage: true,
+ hasNextPage: true,
+ };
+
+ beforeEach(() => {
+ createComponent({
+ pageInfo: mockPageInfo,
+ });
+ });
+
+ it('Contains the current page information', () => {
+ expect(findPagination().props()).toMatchObject(mockPageInfo);
+ });
+
+ it('Goes to the prev page', () => {
+ findPagination().vm.$emit('prev');
+
+ expect(wrapper.emitted('input')[0]).toEqual([
+ {
+ before: mockStartCursor,
+ },
+ ]);
+ });
+
+ it('Goes to the next page', () => {
+ findPagination().vm.$emit('next');
+
+ expect(wrapper.emitted('input')[0]).toEqual([
+ {
+ after: mockEndCursor,
+ },
+ ]);
+ });
+ });
+
+ describe.each`
+ page | hasPreviousPage | hasNextPage
+ ${'first'} | ${false} | ${true}
+ ${'last'} | ${true} | ${false}
+ `('When on the $page page', ({ page, hasPreviousPage, hasNextPage }) => {
+ const mockPageInfo = {
+ startCursor: mockStartCursor,
+ endCursor: mockEndCursor,
+ hasPreviousPage,
+ hasNextPage,
+ };
+
+ beforeEach(() => {
+ createComponent({
+ pageInfo: mockPageInfo,
+ });
+ });
+
+ it(`Contains the ${page} page information`, () => {
+ expect(findPagination().props()).toMatchObject(mockPageInfo);
+ });
+ });
+
+ describe('When no other pages', () => {
+ beforeEach(() => {
+ createComponent({
+ pageInfo: {
+ hasPreviousPage: false,
+ hasNextPage: false,
+ },
+ });
+ });
+
+ it('is not shown', () => {
+ expect(findPagination().exists()).toBe(false);
+ });
+ });
+
+ describe('When adding more attributes', () => {
+ beforeEach(() => {
+ createComponent({
+ pageInfo: {
+ hasPreviousPage: true,
+ hasNextPage: false,
+ },
+ disabled: true,
+ });
+ });
+
+ it('attributes are passed', () => {
+ expect(findPagination().props('disabled')).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_pause_button_spec.js b/spec/frontend/ci/runner/components/runner_pause_button_spec.js
new file mode 100644
index 00000000000..12680e01b98
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_pause_button_spec.js
@@ -0,0 +1,263 @@
+import Vue, { nextTick } from 'vue';
+import { GlButton } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
+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 {
+ I18N_PAUSE,
+ I18N_PAUSE_TOOLTIP,
+ I18N_RESUME,
+ I18N_RESUME_TOOLTIP,
+} from '~/ci/runner/constants';
+
+import RunnerPauseButton from '~/ci/runner/components/runner_pause_button.vue';
+import { allRunnersData } from '../mock_data';
+
+const mockRunner = allRunnersData.data.runners.nodes[0];
+
+Vue.use(VueApollo);
+
+jest.mock('~/flash');
+jest.mock('~/ci/runner/sentry_utils');
+
+describe('RunnerPauseButton', () => {
+ let wrapper;
+ let runnerToggleActiveHandler;
+
+ const getTooltip = () => getBinding(wrapper.element, 'gl-tooltip').value;
+ const findBtn = () => wrapper.findComponent(GlButton);
+
+ const createComponent = ({ props = {}, mountFn = shallowMountExtended } = {}) => {
+ const { runner, ...propsData } = props;
+
+ wrapper = mountFn(RunnerPauseButton, {
+ propsData: {
+ runner: {
+ id: mockRunner.id,
+ active: mockRunner.active,
+ ...runner,
+ },
+ ...propsData,
+ },
+ apolloProvider: createMockApollo([[runnerToggleActiveMutation, runnerToggleActiveHandler]]),
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+ };
+
+ const clickAndWait = async () => {
+ findBtn().vm.$emit('click');
+ await waitForPromises();
+ };
+
+ beforeEach(() => {
+ runnerToggleActiveHandler = jest.fn().mockImplementation(({ input }) => {
+ return Promise.resolve({
+ data: {
+ runnerUpdate: {
+ runner: {
+ id: input.id,
+ active: input.active,
+ },
+ errors: [],
+ },
+ },
+ });
+ });
+
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('Pause/Resume action', () => {
+ describe.each`
+ runnerState | icon | content | tooltip | isActive | newActiveValue
+ ${'paused'} | ${'play'} | ${I18N_RESUME} | ${I18N_RESUME_TOOLTIP} | ${false} | ${true}
+ ${'active'} | ${'pause'} | ${I18N_PAUSE} | ${I18N_PAUSE_TOOLTIP} | ${true} | ${false}
+ `('When the runner is $runnerState', ({ icon, content, tooltip, isActive, newActiveValue }) => {
+ beforeEach(() => {
+ createComponent({
+ props: {
+ runner: {
+ active: isActive,
+ },
+ },
+ });
+ });
+
+ it(`Displays a ${icon} button`, () => {
+ expect(findBtn().props('loading')).toBe(false);
+ expect(findBtn().props('icon')).toBe(icon);
+ });
+
+ it('Displays button content', () => {
+ expect(findBtn().text()).toBe(content);
+ expect(getTooltip()).toBe(tooltip);
+ });
+
+ it('Does not display redundant text for screen readers', () => {
+ expect(findBtn().attributes('aria-label')).toBe(undefined);
+ });
+
+ describe(`Before the ${icon} button is clicked`, () => {
+ it('The mutation has not been called', () => {
+ expect(runnerToggleActiveHandler).toHaveBeenCalledTimes(0);
+ });
+ });
+
+ describe(`Immediately after the ${icon} button is clicked`, () => {
+ const setup = async () => {
+ findBtn().vm.$emit('click');
+ await nextTick();
+ };
+
+ it('The button has a loading state', async () => {
+ await setup();
+
+ expect(findBtn().props('loading')).toBe(true);
+ });
+
+ it('The stale tooltip is removed', async () => {
+ await setup();
+
+ expect(getTooltip()).toBe('');
+ });
+ });
+
+ describe(`After clicking on the ${icon} button`, () => {
+ beforeEach(async () => {
+ await clickAndWait();
+ });
+
+ it(`The mutation to that sets active to ${newActiveValue} is called`, async () => {
+ expect(runnerToggleActiveHandler).toHaveBeenCalledTimes(1);
+ expect(runnerToggleActiveHandler).toHaveBeenCalledWith({
+ input: {
+ id: mockRunner.id,
+ active: newActiveValue,
+ },
+ });
+ });
+
+ it('The button does not have a loading state', () => {
+ expect(findBtn().props('loading')).toBe(false);
+ });
+
+ it('The button emits toggledPaused', () => {
+ expect(wrapper.emitted('toggledPaused')).toHaveLength(1);
+ });
+ });
+
+ describe('When update fails', () => {
+ describe('On a network error', () => {
+ const mockErrorMsg = 'Update error!';
+
+ beforeEach(async () => {
+ runnerToggleActiveHandler.mockRejectedValueOnce(new Error(mockErrorMsg));
+
+ await clickAndWait();
+ });
+
+ it('error is reported to sentry', () => {
+ expect(captureException).toHaveBeenCalledWith({
+ error: new Error(mockErrorMsg),
+ component: 'RunnerPauseButton',
+ });
+ });
+
+ it('error is shown to the user', () => {
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('On a validation error', () => {
+ const mockErrorMsg = 'Runner not found!';
+ const mockErrorMsg2 = 'User not allowed!';
+
+ beforeEach(async () => {
+ runnerToggleActiveHandler.mockResolvedValueOnce({
+ data: {
+ runnerUpdate: {
+ runner: {
+ id: mockRunner.id,
+ active: isActive,
+ },
+ errors: [mockErrorMsg, mockErrorMsg2],
+ },
+ },
+ });
+
+ await clickAndWait();
+ });
+
+ it('error is reported to sentry', () => {
+ expect(captureException).toHaveBeenCalledWith({
+ error: new Error(`${mockErrorMsg} ${mockErrorMsg2}`),
+ component: 'RunnerPauseButton',
+ });
+ });
+
+ it('error is shown to the user', () => {
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ });
+ });
+ });
+ });
+ });
+
+ describe('When displaying a compact button for an active runner', () => {
+ beforeEach(() => {
+ createComponent({
+ props: {
+ runner: {
+ active: true,
+ },
+ compact: true,
+ },
+ mountFn: mountExtended,
+ });
+ });
+
+ it('Displays no text', () => {
+ expect(findBtn().text()).toBe('');
+
+ // Note: Use <template v-if> to ensure rendering a
+ // text-less button. Ensure we don't send even empty an
+ // content slot to prevent a distorted/rectangular button.
+ expect(wrapper.find('.gl-button-text').exists()).toBe(false);
+ });
+
+ it('Display correctly for screen readers', () => {
+ expect(findBtn().attributes('aria-label')).toBe(I18N_PAUSE);
+ expect(getTooltip()).toBe(I18N_PAUSE_TOOLTIP);
+ });
+
+ describe('Immediately after the button is clicked', () => {
+ const setup = async () => {
+ findBtn().vm.$emit('click');
+ await nextTick();
+ };
+
+ it('The button has a loading state', async () => {
+ await setup();
+
+ expect(findBtn().props('loading')).toBe(true);
+ });
+
+ it('The stale tooltip is removed', async () => {
+ await setup();
+
+ expect(getTooltip()).toBe('');
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_paused_badge_spec.js b/spec/frontend/ci/runner/components/runner_paused_badge_spec.js
new file mode 100644
index 00000000000..b051ebe99a7
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_paused_badge_spec.js
@@ -0,0 +1,46 @@
+import { GlBadge } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import RunnerStatePausedBadge from '~/ci/runner/components/runner_paused_badge.vue';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import { I18N_PAUSED } from '~/ci/runner/constants';
+
+describe('RunnerTypeBadge', () => {
+ let wrapper;
+
+ const findBadge = () => wrapper.findComponent(GlBadge);
+ const getTooltip = () => getBinding(findBadge().element, 'gl-tooltip');
+
+ const createComponent = ({ props = {} } = {}) => {
+ wrapper = shallowMount(RunnerStatePausedBadge, {
+ propsData: {
+ ...props,
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders paused state', () => {
+ expect(wrapper.text()).toBe(I18N_PAUSED);
+ expect(findBadge().props('variant')).toBe('warning');
+ });
+
+ it('renders tooltip', () => {
+ expect(getTooltip().value).toBeDefined();
+ });
+
+ it('passes arbitrary attributes to the badge', () => {
+ createComponent({ props: { size: 'sm' } });
+
+ expect(findBadge().props('size')).toBe('sm');
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_projects_spec.js b/spec/frontend/ci/runner/components/runner_projects_spec.js
new file mode 100644
index 00000000000..17517c4db66
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_projects_spec.js
@@ -0,0 +1,251 @@
+import { GlSearchBoxByType, GlSkeletonLoader } from '@gitlab/ui';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/flash';
+import { sprintf } from '~/locale';
+import {
+ I18N_ASSIGNED_PROJECTS,
+ I18N_CLEAR_FILTER_PROJECTS,
+ I18N_FILTER_PROJECTS,
+ I18N_NO_PROJECTS_FOUND,
+ RUNNER_DETAILS_PROJECTS_PAGE_SIZE,
+} from '~/ci/runner/constants';
+import RunnerProjects from '~/ci/runner/components/runner_projects.vue';
+import RunnerAssignedItem from '~/ci/runner/components/runner_assigned_item.vue';
+import RunnerPagination from '~/ci/runner/components/runner_pagination.vue';
+import { captureException } from '~/ci/runner/sentry_utils';
+
+import runnerProjectsQuery from '~/ci/runner/graphql/show/runner_projects.query.graphql';
+
+import { runnerData, runnerProjectsData } from '../mock_data';
+
+jest.mock('~/flash');
+jest.mock('~/ci/runner/sentry_utils');
+
+const mockRunner = runnerData.data.runner;
+const mockRunnerWithProjects = runnerProjectsData.data.runner;
+const mockProjects = mockRunnerWithProjects.projects.nodes;
+
+Vue.use(VueApollo);
+
+describe('RunnerProjects', () => {
+ let wrapper;
+ let mockRunnerProjectsQuery;
+
+ const findHeading = () => wrapper.find('h3');
+ const findGlSkeletonLoading = () => wrapper.findComponent(GlSkeletonLoader);
+ const findGlSearchBoxByType = () => wrapper.findComponent(GlSearchBoxByType);
+ const findRunnerAssignedItems = () => wrapper.findAllComponents(RunnerAssignedItem);
+ const findRunnerPagination = () => wrapper.findComponent(RunnerPagination);
+
+ const createComponent = ({ mountFn = shallowMountExtended } = {}) => {
+ wrapper = mountFn(RunnerProjects, {
+ apolloProvider: createMockApollo([[runnerProjectsQuery, mockRunnerProjectsQuery]]),
+ propsData: {
+ runner: mockRunner,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ mockRunnerProjectsQuery = jest.fn();
+ });
+
+ afterEach(() => {
+ mockRunnerProjectsQuery.mockReset();
+ wrapper.destroy();
+ });
+
+ it('Requests runner projects', async () => {
+ createComponent();
+
+ await waitForPromises();
+
+ expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(1);
+ expect(mockRunnerProjectsQuery).toHaveBeenCalledWith({
+ id: mockRunner.id,
+ search: '',
+ first: RUNNER_DETAILS_PROJECTS_PAGE_SIZE,
+ });
+ });
+
+ it('Shows a filter box', () => {
+ createComponent();
+
+ expect(findGlSearchBoxByType().attributes()).toMatchObject({
+ clearbuttontitle: I18N_CLEAR_FILTER_PROJECTS,
+ debounce: '500',
+ placeholder: I18N_FILTER_PROJECTS,
+ });
+ });
+
+ describe('When there are projects assigned', () => {
+ beforeEach(async () => {
+ mockRunnerProjectsQuery.mockResolvedValueOnce(runnerProjectsData);
+
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('Shows a heading', async () => {
+ const expected = sprintf(I18N_ASSIGNED_PROJECTS, { projectCount: mockProjects.length });
+
+ expect(findHeading().text()).toBe(expected);
+ });
+
+ it('Shows projects', () => {
+ expect(findRunnerAssignedItems().length).toBe(mockProjects.length);
+ });
+
+ it('Shows a project', () => {
+ const item = findRunnerAssignedItems().at(0);
+ const { webUrl, name, nameWithNamespace, avatarUrl } = mockProjects[0];
+
+ expect(item.props()).toMatchObject({
+ href: webUrl,
+ name,
+ fullName: nameWithNamespace,
+ avatarUrl,
+ isOwner: true, // first project is always owner
+ });
+ });
+
+ describe('When "Next" page is clicked', () => {
+ beforeEach(async () => {
+ findRunnerPagination().vm.$emit('input', { page: 3, after: 'AFTER_CURSOR' });
+
+ await waitForPromises();
+ });
+
+ it('A new page is requested', () => {
+ expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(2);
+ expect(mockRunnerProjectsQuery).toHaveBeenLastCalledWith({
+ id: mockRunner.id,
+ search: '',
+ first: RUNNER_DETAILS_PROJECTS_PAGE_SIZE,
+ after: 'AFTER_CURSOR',
+ });
+ });
+
+ it('When "Prev" page is clicked, the previous page is requested', async () => {
+ findRunnerPagination().vm.$emit('input', { page: 2, before: 'BEFORE_CURSOR' });
+
+ await waitForPromises();
+
+ expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(3);
+ expect(mockRunnerProjectsQuery).toHaveBeenLastCalledWith({
+ id: mockRunner.id,
+ search: '',
+ last: RUNNER_DETAILS_PROJECTS_PAGE_SIZE,
+ before: 'BEFORE_CURSOR',
+ });
+ });
+
+ it('When user filters after paginating, the first page is requested', async () => {
+ findGlSearchBoxByType().vm.$emit('input', 'my search');
+ await waitForPromises();
+
+ expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(3);
+ expect(mockRunnerProjectsQuery).toHaveBeenLastCalledWith({
+ id: mockRunner.id,
+ search: 'my search',
+ first: RUNNER_DETAILS_PROJECTS_PAGE_SIZE,
+ });
+ });
+ });
+
+ describe('When user filters', () => {
+ it('Filtered results are requested', async () => {
+ expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(1);
+
+ findGlSearchBoxByType().vm.$emit('input', 'my search');
+ await waitForPromises();
+
+ expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(2);
+ expect(mockRunnerProjectsQuery).toHaveBeenLastCalledWith({
+ id: mockRunner.id,
+ search: 'my search',
+ first: RUNNER_DETAILS_PROJECTS_PAGE_SIZE,
+ });
+ });
+
+ it('Filtered results are not requested for short searches', async () => {
+ expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(1);
+
+ findGlSearchBoxByType().vm.$emit('input', 'm');
+ await waitForPromises();
+
+ findGlSearchBoxByType().vm.$emit('input', 'my');
+ await waitForPromises();
+
+ expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(1);
+ });
+ });
+ });
+
+ describe('When loading', () => {
+ it('shows loading indicator and no other content', () => {
+ createComponent();
+
+ expect(findGlSkeletonLoading().exists()).toBe(true);
+
+ expect(wrapper.findByText(I18N_NO_PROJECTS_FOUND).exists()).toBe(false);
+ expect(findRunnerAssignedItems().length).toBe(0);
+
+ expect(findRunnerPagination().attributes('disabled')).toBe('true');
+ expect(findGlSearchBoxByType().props('isLoading')).toBe(true);
+ });
+ });
+
+ describe('When there are no projects', () => {
+ beforeEach(async () => {
+ mockRunnerProjectsQuery.mockResolvedValueOnce({
+ data: {
+ runner: {
+ id: mockRunner.id,
+ projectCount: 0,
+ projects: {
+ nodes: [],
+ pageInfo: {
+ hasNextPage: false,
+ hasPreviousPage: false,
+ startCursor: '',
+ endCursor: '',
+ },
+ },
+ },
+ },
+ });
+
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('Shows a "None" label', () => {
+ expect(wrapper.findByText(I18N_NO_PROJECTS_FOUND).exists()).toBe(true);
+ });
+ });
+
+ describe('When an error occurs', () => {
+ beforeEach(async () => {
+ mockRunnerProjectsQuery.mockRejectedValue(new Error('Error!'));
+
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('shows an error', () => {
+ expect(createAlert).toHaveBeenCalled();
+ });
+
+ it('reports an error', () => {
+ expect(captureException).toHaveBeenCalledWith({
+ component: 'RunnerProjects',
+ error: expect.any(Error),
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_status_badge_spec.js b/spec/frontend/ci/runner/components/runner_status_badge_spec.js
new file mode 100644
index 00000000000..7d3064c2aef
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_status_badge_spec.js
@@ -0,0 +1,133 @@
+import { GlBadge } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import RunnerStatusBadge from '~/ci/runner/components/runner_status_badge.vue';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import {
+ I18N_STATUS_ONLINE,
+ I18N_STATUS_NEVER_CONTACTED,
+ I18N_STATUS_OFFLINE,
+ I18N_STATUS_STALE,
+ I18N_NEVER_CONTACTED_TOOLTIP,
+ I18N_STALE_NEVER_CONTACTED_TOOLTIP,
+ STATUS_ONLINE,
+ STATUS_OFFLINE,
+ STATUS_STALE,
+ STATUS_NEVER_CONTACTED,
+} from '~/ci/runner/constants';
+
+describe('RunnerTypeBadge', () => {
+ let wrapper;
+
+ const findBadge = () => wrapper.findComponent(GlBadge);
+ const getTooltip = () => getBinding(findBadge().element, 'gl-tooltip');
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(RunnerStatusBadge, {
+ propsData: {
+ runner: {
+ contactedAt: '2020-12-31T23:59:00Z',
+ status: STATUS_ONLINE,
+ },
+ ...props,
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+ };
+
+ beforeEach(() => {
+ jest.useFakeTimers('modern');
+ jest.setSystemTime(new Date('2021-01-01T00:00:00Z'));
+ });
+
+ afterEach(() => {
+ jest.useFakeTimers('legacy');
+
+ wrapper.destroy();
+ });
+
+ it('renders online state', () => {
+ createComponent();
+
+ expect(wrapper.text()).toBe(I18N_STATUS_ONLINE);
+ expect(findBadge().props('variant')).toBe('success');
+ expect(getTooltip().value).toBe('Runner is online; last contact was 1 minute ago');
+ });
+
+ it('renders never contacted state', () => {
+ createComponent({
+ runner: {
+ contactedAt: null,
+ status: STATUS_NEVER_CONTACTED,
+ },
+ });
+
+ expect(wrapper.text()).toBe(I18N_STATUS_NEVER_CONTACTED);
+ expect(findBadge().props('variant')).toBe('muted');
+ expect(getTooltip().value).toBe(I18N_NEVER_CONTACTED_TOOLTIP);
+ });
+
+ it('renders offline state', () => {
+ createComponent({
+ runner: {
+ contactedAt: '2020-12-31T00:00:00Z',
+ status: STATUS_OFFLINE,
+ },
+ });
+
+ expect(wrapper.text()).toBe(I18N_STATUS_OFFLINE);
+ expect(findBadge().props('variant')).toBe('muted');
+ expect(getTooltip().value).toBe('Runner is offline; last contact was 1 day ago');
+ });
+
+ it('renders stale state', () => {
+ createComponent({
+ runner: {
+ contactedAt: '2020-01-01T00:00:00Z',
+ status: STATUS_STALE,
+ },
+ });
+
+ expect(wrapper.text()).toBe(I18N_STATUS_STALE);
+ expect(findBadge().props('variant')).toBe('warning');
+ expect(getTooltip().value).toBe('Runner is stale; last contact was 1 year ago');
+ });
+
+ it('renders stale state with no contact time', () => {
+ createComponent({
+ runner: {
+ contactedAt: null,
+ status: STATUS_STALE,
+ },
+ });
+
+ expect(wrapper.text()).toBe(I18N_STATUS_STALE);
+ expect(findBadge().props('variant')).toBe('warning');
+ expect(getTooltip().value).toBe(I18N_STALE_NEVER_CONTACTED_TOOLTIP);
+ });
+
+ describe('does not fail when data is missing', () => {
+ it('contacted_at is missing', () => {
+ createComponent({
+ runner: {
+ contactedAt: null,
+ status: STATUS_ONLINE,
+ },
+ });
+
+ expect(wrapper.text()).toBe(I18N_STATUS_ONLINE);
+ expect(getTooltip().value).toBe('Runner is online; last contact was never');
+ });
+
+ it('status is missing', () => {
+ createComponent({
+ runner: {
+ status: null,
+ },
+ });
+
+ expect(wrapper.text()).toBe('');
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_status_popover_spec.js b/spec/frontend/ci/runner/components/runner_status_popover_spec.js
new file mode 100644
index 00000000000..89fb95f2da4
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_status_popover_spec.js
@@ -0,0 +1,36 @@
+import { GlSprintf } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import RunnerStatusPopover from '~/ci/runner/components/runner_status_popover.vue';
+import HelpPopover from '~/vue_shared/components/help_popover.vue';
+import { onlineContactTimeoutSecs, staleTimeoutSecs } from '../mock_data';
+
+describe('RunnerStatusPopover', () => {
+ let wrapper;
+
+ const createComponent = ({ provide = {} } = {}) => {
+ wrapper = shallowMountExtended(RunnerStatusPopover, {
+ provide: {
+ onlineContactTimeoutSecs,
+ staleTimeoutSecs,
+ ...provide,
+ },
+ stubs: {
+ GlSprintf,
+ },
+ });
+ };
+
+ const findHelpPopover = () => wrapper.findComponent(HelpPopover);
+
+ it('renders popoover', () => {
+ createComponent();
+
+ expect(findHelpPopover().exists()).toBe(true);
+ });
+
+ it('renders complete text', () => {
+ createComponent();
+
+ expect(findHelpPopover().text()).toMatchSnapshot();
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_tag_spec.js b/spec/frontend/ci/runner/components/runner_tag_spec.js
new file mode 100644
index 00000000000..7bcb046ae43
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_tag_spec.js
@@ -0,0 +1,79 @@
+import { GlBadge } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+
+import { RUNNER_TAG_BADGE_VARIANT } from '~/ci/runner/constants';
+import RunnerTag from '~/ci/runner/components/runner_tag.vue';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+
+const mockTag = 'tag1';
+
+describe('RunnerTag', () => {
+ let wrapper;
+
+ const findBadge = () => wrapper.findComponent(GlBadge);
+ const getTooltipValue = () => getBinding(findBadge().element, 'gl-tooltip').value;
+
+ const setDimensions = ({ scrollWidth, offsetWidth }) => {
+ jest.spyOn(findBadge().element, 'scrollWidth', 'get').mockReturnValue(scrollWidth);
+ jest.spyOn(findBadge().element, 'offsetWidth', 'get').mockReturnValue(offsetWidth);
+
+ // Mock trigger resize
+ getBinding(findBadge().element, 'gl-resize-observer').value();
+ };
+
+ const createComponent = ({ props = {} } = {}) => {
+ wrapper = shallowMount(RunnerTag, {
+ propsData: {
+ tag: mockTag,
+ ...props,
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ GlResizeObserver: createMockDirective(),
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Displays tag text', () => {
+ expect(wrapper.text()).toBe(mockTag);
+ });
+
+ it('Displays tags with correct style', () => {
+ expect(findBadge().props()).toMatchObject({
+ size: 'sm',
+ variant: RUNNER_TAG_BADGE_VARIANT,
+ });
+ });
+
+ it('Displays tags with md size', () => {
+ createComponent({
+ props: { size: 'md' },
+ });
+
+ expect(findBadge().props('size')).toBe('md');
+ });
+
+ it.each`
+ case | scrollWidth | offsetWidth | expectedTooltip
+ ${'overflowing'} | ${110} | ${100} | ${mockTag}
+ ${'not overflowing'} | ${90} | ${100} | ${''}
+ ${'almost overflowing'} | ${100} | ${100} | ${''}
+ `(
+ 'Sets "$expectedTooltip" as tooltip when $case',
+ async ({ scrollWidth, offsetWidth, expectedTooltip }) => {
+ setDimensions({ scrollWidth, offsetWidth });
+ await nextTick();
+
+ expect(getTooltipValue()).toBe(expectedTooltip);
+ },
+ );
+});
diff --git a/spec/frontend/ci/runner/components/runner_tags_spec.js b/spec/frontend/ci/runner/components/runner_tags_spec.js
new file mode 100644
index 00000000000..96bec00302b
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_tags_spec.js
@@ -0,0 +1,54 @@
+import { GlBadge } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import RunnerTags from '~/ci/runner/components/runner_tags.vue';
+
+describe('RunnerTags', () => {
+ let wrapper;
+
+ const findBadge = () => wrapper.findComponent(GlBadge);
+ const findBadgesAt = (i = 0) => wrapper.findAllComponents(GlBadge).at(i);
+
+ const createComponent = ({ props = {} } = {}) => {
+ wrapper = mount(RunnerTags, {
+ propsData: {
+ tagList: ['tag1', 'tag2'],
+ ...props,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Displays tags text', () => {
+ expect(wrapper.text()).toMatchInterpolatedText('tag1 tag2');
+
+ expect(findBadgesAt(0).text()).toBe('tag1');
+ expect(findBadgesAt(1).text()).toBe('tag2');
+ });
+
+ it('Displays tags with correct style', () => {
+ expect(findBadge().props('size')).toBe('sm');
+ });
+
+ it('Displays tags with md size', () => {
+ createComponent({
+ props: { size: 'md' },
+ });
+
+ expect(findBadge().props('size')).toBe('md');
+ });
+
+ it('Is empty when there are no tags', () => {
+ createComponent({
+ props: { tagList: null },
+ });
+
+ expect(wrapper.html()).toEqual('');
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_type_badge_spec.js b/spec/frontend/ci/runner/components/runner_type_badge_spec.js
new file mode 100644
index 00000000000..58f09362759
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_type_badge_spec.js
@@ -0,0 +1,66 @@
+import { GlBadge } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import RunnerTypeBadge from '~/ci/runner/components/runner_type_badge.vue';
+import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
+import {
+ INSTANCE_TYPE,
+ GROUP_TYPE,
+ PROJECT_TYPE,
+ I18N_INSTANCE_TYPE,
+ I18N_GROUP_TYPE,
+ I18N_PROJECT_TYPE,
+} from '~/ci/runner/constants';
+
+describe('RunnerTypeBadge', () => {
+ let wrapper;
+
+ const findBadge = () => wrapper.findComponent(GlBadge);
+ const getTooltip = () => getBinding(findBadge().element, 'gl-tooltip');
+
+ const createComponent = ({ props = {} } = {}) => {
+ wrapper = shallowMount(RunnerTypeBadge, {
+ propsData: {
+ ...props,
+ },
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe.each`
+ type | text
+ ${INSTANCE_TYPE} | ${I18N_INSTANCE_TYPE}
+ ${GROUP_TYPE} | ${I18N_GROUP_TYPE}
+ ${PROJECT_TYPE} | ${I18N_PROJECT_TYPE}
+ `('displays $type runner', ({ type, text }) => {
+ beforeEach(() => {
+ createComponent({ props: { type } });
+ });
+
+ it(`as "${text}" with an "info" variant`, () => {
+ expect(findBadge().text()).toBe(text);
+ expect(findBadge().props('variant')).toBe('muted');
+ });
+
+ it('with a tooltip', () => {
+ expect(getTooltip().value).toBeDefined();
+ });
+ });
+
+ it('validation fails for an incorrect type', () => {
+ expect(() => {
+ createComponent({ props: { type: 'AN_UNKNOWN_VALUE' } });
+ }).toThrow();
+ });
+
+ it('does not render content when type is missing', () => {
+ createComponent({ props: { type: undefined } });
+
+ expect(findBadge().exists()).toBe(false);
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_type_tabs_spec.js b/spec/frontend/ci/runner/components/runner_type_tabs_spec.js
new file mode 100644
index 00000000000..3347c190083
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_type_tabs_spec.js
@@ -0,0 +1,214 @@
+import { GlTab } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import RunnerTypeTabs from '~/ci/runner/components/runner_type_tabs.vue';
+import RunnerCount from '~/ci/runner/components/stat/runner_count.vue';
+import {
+ INSTANCE_TYPE,
+ GROUP_TYPE,
+ PROJECT_TYPE,
+ DEFAULT_MEMBERSHIP,
+ DEFAULT_SORT,
+} from '~/ci/runner/constants';
+
+const mockSearch = {
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [],
+ pagination: { page: 1 },
+ sort: DEFAULT_SORT,
+};
+
+const mockCount = (type, multiplier = 1) => {
+ let count;
+ switch (type) {
+ case INSTANCE_TYPE:
+ count = 3;
+ break;
+ case GROUP_TYPE:
+ count = 2;
+ break;
+ case PROJECT_TYPE:
+ count = 1;
+ break;
+ default:
+ count = 6;
+ break;
+ }
+ return count * multiplier;
+};
+
+describe('RunnerTypeTabs', () => {
+ let wrapper;
+
+ const findTabs = () => wrapper.findAllComponents(GlTab);
+ const findActiveTab = () =>
+ findTabs()
+ .filter((tab) => tab.attributes('active') === 'true')
+ .at(0);
+ const getTabsTitles = () => findTabs().wrappers.map((tab) => tab.text().replace(/\s+/g, ' '));
+
+ const createComponent = ({ props, stubs, ...options } = {}) => {
+ wrapper = shallowMount(RunnerTypeTabs, {
+ propsData: {
+ value: mockSearch,
+ countScope: INSTANCE_TYPE,
+ countVariables: {},
+ ...props,
+ },
+ stubs: {
+ GlTab,
+ ...stubs,
+ },
+ ...options,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Renders all options to filter runners by default', () => {
+ createComponent();
+
+ expect(getTabsTitles()).toEqual(['All', 'Instance', 'Group', 'Project']);
+ });
+
+ it('Shows count when receiving a number', () => {
+ createComponent({
+ stubs: {
+ RunnerCount: {
+ props: ['variables'],
+ render() {
+ return this.$scopedSlots.default({
+ count: mockCount(this.variables.type),
+ });
+ },
+ },
+ },
+ });
+
+ expect(getTabsTitles()).toEqual([`All 6`, `Instance 3`, `Group 2`, `Project 1`]);
+ });
+
+ it('Shows formatted count when receiving a large number', () => {
+ createComponent({
+ stubs: {
+ RunnerCount: {
+ props: ['variables'],
+ render() {
+ return this.$scopedSlots.default({
+ count: mockCount(this.variables.type, 1000),
+ });
+ },
+ },
+ },
+ });
+
+ expect(getTabsTitles()).toEqual([
+ `All 6,000`,
+ `Instance 3,000`,
+ `Group 2,000`,
+ `Project 1,000`,
+ ]);
+ });
+
+ it('Renders a count next to each tab', () => {
+ const mockVariables = {
+ paused: true,
+ status: 'ONLINE',
+ };
+
+ createComponent({
+ props: {
+ countVariables: mockVariables,
+ },
+ });
+
+ findTabs().wrappers.forEach((tab) => {
+ expect(tab.findComponent(RunnerCount).props()).toEqual({
+ scope: INSTANCE_TYPE,
+ skip: false,
+ variables: expect.objectContaining(mockVariables),
+ });
+ });
+ });
+
+ it('Renders fewer options to filter runners', () => {
+ createComponent({
+ props: {
+ runnerTypes: [GROUP_TYPE, PROJECT_TYPE],
+ },
+ });
+
+ expect(getTabsTitles()).toEqual(['All', 'Group', 'Project']);
+ });
+
+ it('"All" is selected by default', () => {
+ createComponent();
+
+ expect(findActiveTab().text()).toBe('All');
+ });
+
+ it('Another tab can be preselected by the user', () => {
+ createComponent({
+ props: {
+ value: {
+ ...mockSearch,
+ runnerType: INSTANCE_TYPE,
+ },
+ },
+ });
+
+ expect(findActiveTab().text()).toBe('Instance');
+ });
+
+ describe('When the user selects a tab', () => {
+ const emittedValue = () => wrapper.emitted('input')[0][0];
+
+ beforeEach(() => {
+ createComponent();
+ findTabs().at(2).vm.$emit('click');
+ });
+
+ it(`Runner type is emitted`, () => {
+ expect(emittedValue()).toEqual({
+ ...mockSearch,
+ runnerType: GROUP_TYPE,
+ });
+ });
+
+ it('Runner type is selected', async () => {
+ const newValue = emittedValue();
+ await wrapper.setProps({ value: newValue });
+
+ expect(findActiveTab().text()).toBe('Group');
+ });
+ });
+
+ describe('Component API', () => {
+ describe('When .refetch() is called', () => {
+ let mockRefetch;
+
+ beforeEach(() => {
+ mockRefetch = jest.fn();
+
+ createComponent({
+ stubs: {
+ RunnerCount: {
+ methods: {
+ refetch: mockRefetch,
+ },
+ render() {},
+ },
+ },
+ });
+
+ wrapper.vm.refetch();
+ });
+
+ it('refetch is called for each count', () => {
+ expect(mockRefetch).toHaveBeenCalledTimes(4);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/runner_update_form_spec.js b/spec/frontend/ci/runner/components/runner_update_form_spec.js
new file mode 100644
index 00000000000..a0e51ebf958
--- /dev/null
+++ b/spec/frontend/ci/runner/components/runner_update_form_spec.js
@@ -0,0 +1,288 @@
+import Vue, { nextTick } from 'vue';
+import { GlForm, GlSkeletonLoader } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+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 { redirectTo } from '~/lib/utils/url_utility';
+import RunnerUpdateForm from '~/ci/runner/components/runner_update_form.vue';
+import {
+ INSTANCE_TYPE,
+ GROUP_TYPE,
+ PROJECT_TYPE,
+ ACCESS_LEVEL_REF_PROTECTED,
+ ACCESS_LEVEL_NOT_PROTECTED,
+} from '~/ci/runner/constants';
+import runnerUpdateMutation from '~/ci/runner/graphql/edit/runner_update.mutation.graphql';
+import { captureException } from '~/ci/runner/sentry_utils';
+import { saveAlertToLocalStorage } from '~/ci/runner/local_storage_alert/save_alert_to_local_storage';
+import { runnerFormData } from '../mock_data';
+
+jest.mock('~/ci/runner/local_storage_alert/save_alert_to_local_storage');
+jest.mock('~/flash');
+jest.mock('~/ci/runner/sentry_utils');
+jest.mock('~/lib/utils/url_utility');
+
+const mockRunner = runnerFormData.data.runner;
+const mockRunnerPath = '/admin/runners/1';
+
+Vue.use(VueApollo);
+
+describe('RunnerUpdateForm', () => {
+ let wrapper;
+ let runnerUpdateHandler;
+
+ const findForm = () => wrapper.findComponent(GlForm);
+ const findPausedCheckbox = () => wrapper.findByTestId('runner-field-paused');
+ const findProtectedCheckbox = () => wrapper.findByTestId('runner-field-protected');
+ const findRunUntaggedCheckbox = () => wrapper.findByTestId('runner-field-run-untagged');
+ const findLockedCheckbox = () => wrapper.findByTestId('runner-field-locked');
+ const findFields = () => wrapper.findAll('[data-testid^="runner-field"');
+
+ const findDescriptionInput = () => wrapper.findByTestId('runner-field-description').find('input');
+ const findMaxJobTimeoutInput = () =>
+ wrapper.findByTestId('runner-field-max-timeout').find('input');
+ const findTagsInput = () => wrapper.findByTestId('runner-field-tags').find('input');
+
+ const findSubmit = () => wrapper.find('[type="submit"]');
+ const findSubmitDisabledAttr = () => findSubmit().attributes('disabled');
+ const findCancelBtn = () => wrapper.findByRole('link', { name: __('Cancel') });
+ const submitForm = () => findForm().trigger('submit');
+ const submitFormAndWait = () => submitForm().then(waitForPromises);
+
+ const getFieldsModel = () => ({
+ active: !findPausedCheckbox().element.checked,
+ accessLevel: findProtectedCheckbox().element.checked
+ ? ACCESS_LEVEL_REF_PROTECTED
+ : ACCESS_LEVEL_NOT_PROTECTED,
+ runUntagged: findRunUntaggedCheckbox().element.checked,
+ locked: findLockedCheckbox().element?.checked || false,
+ maximumTimeout: findMaxJobTimeoutInput().element.value || null,
+ tagList: findTagsInput().element.value.split(',').filter(Boolean),
+ });
+
+ const createComponent = ({ props } = {}) => {
+ wrapper = mountExtended(RunnerUpdateForm, {
+ propsData: {
+ runner: mockRunner,
+ runnerPath: mockRunnerPath,
+ ...props,
+ },
+ apolloProvider: createMockApollo([[runnerUpdateMutation, runnerUpdateHandler]]),
+ });
+ };
+
+ const expectToHaveSubmittedRunnerContaining = (submittedRunner) => {
+ expect(runnerUpdateHandler).toHaveBeenCalledTimes(1);
+ expect(runnerUpdateHandler).toHaveBeenCalledWith({
+ input: expect.objectContaining(submittedRunner),
+ });
+
+ expect(saveAlertToLocalStorage).toHaveBeenCalledWith(
+ expect.objectContaining({
+ message: expect.any(String),
+ variant: VARIANT_SUCCESS,
+ }),
+ );
+ expect(redirectTo).toHaveBeenCalledWith(mockRunnerPath);
+ };
+
+ beforeEach(() => {
+ runnerUpdateHandler = jest.fn().mockImplementation(({ input }) => {
+ return Promise.resolve({
+ data: {
+ runnerUpdate: {
+ runner: {
+ ...mockRunner,
+ ...input,
+ },
+ errors: [],
+ },
+ },
+ });
+ });
+
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Form has a submit button', () => {
+ expect(findSubmit().exists()).toBe(true);
+ });
+
+ it('Form fields match data', () => {
+ expect(mockRunner).toMatchObject(getFieldsModel());
+ });
+
+ it('Form shows a cancel button', () => {
+ expect(runnerUpdateHandler).not.toHaveBeenCalled();
+ expect(findCancelBtn().attributes('href')).toBe(mockRunnerPath);
+ });
+
+ it('Form prevent multiple submissions', async () => {
+ await submitForm();
+
+ expect(findSubmitDisabledAttr()).toBe('disabled');
+ });
+
+ it('Updates runner with no changes', async () => {
+ await submitFormAndWait();
+
+ // Some read-only fields are not submitted
+ const { __typename, shortSha, runnerType, createdAt, status, ...submitted } = mockRunner;
+
+ expectToHaveSubmittedRunnerContaining(submitted);
+ });
+
+ describe('When data is being loaded', () => {
+ beforeEach(() => {
+ createComponent({ props: { loading: true } });
+ });
+
+ it('Form skeleton is shown', () => {
+ expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(true);
+ expect(findFields()).toHaveLength(0);
+ });
+
+ it('Form cannot be submitted', () => {
+ expect(findSubmit().props('loading')).toBe(true);
+ });
+
+ it('Form is updated when data loads', async () => {
+ wrapper.setProps({
+ loading: false,
+ });
+
+ await nextTick();
+
+ expect(findFields()).not.toHaveLength(0);
+ expect(mockRunner).toMatchObject(getFieldsModel());
+ });
+ });
+
+ it.each`
+ runnerType | exists | outcome
+ ${INSTANCE_TYPE} | ${false} | ${'hidden'}
+ ${GROUP_TYPE} | ${false} | ${'hidden'}
+ ${PROJECT_TYPE} | ${true} | ${'shown'}
+ `(`When runner is $runnerType, locked field is $outcome`, ({ runnerType, exists }) => {
+ const runner = { ...mockRunner, runnerType };
+ createComponent({ props: { runner } });
+
+ expect(findLockedCheckbox().exists()).toBe(exists);
+ });
+
+ describe('On submit, runner gets updated', () => {
+ it.each`
+ test | initialValue | findCheckbox | checked | submitted
+ ${'pauses'} | ${{ active: true }} | ${findPausedCheckbox} | ${true} | ${{ active: false }}
+ ${'activates'} | ${{ active: false }} | ${findPausedCheckbox} | ${false} | ${{ active: true }}
+ ${'unprotects'} | ${{ accessLevel: ACCESS_LEVEL_NOT_PROTECTED }} | ${findProtectedCheckbox} | ${true} | ${{ accessLevel: ACCESS_LEVEL_REF_PROTECTED }}
+ ${'protects'} | ${{ accessLevel: ACCESS_LEVEL_REF_PROTECTED }} | ${findProtectedCheckbox} | ${false} | ${{ accessLevel: ACCESS_LEVEL_NOT_PROTECTED }}
+ ${'"runs untagged jobs"'} | ${{ runUntagged: true }} | ${findRunUntaggedCheckbox} | ${false} | ${{ runUntagged: false }}
+ ${'"runs tagged jobs"'} | ${{ runUntagged: false }} | ${findRunUntaggedCheckbox} | ${true} | ${{ runUntagged: true }}
+ ${'locks'} | ${{ runnerType: PROJECT_TYPE, locked: true }} | ${findLockedCheckbox} | ${false} | ${{ locked: false }}
+ ${'unlocks'} | ${{ runnerType: PROJECT_TYPE, locked: false }} | ${findLockedCheckbox} | ${true} | ${{ locked: true }}
+ `('Checkbox $test runner', async ({ initialValue, findCheckbox, checked, submitted }) => {
+ const runner = { ...mockRunner, ...initialValue };
+ createComponent({ props: { runner } });
+
+ await findCheckbox().setChecked(checked);
+ await submitFormAndWait();
+
+ expectToHaveSubmittedRunnerContaining({
+ id: runner.id,
+ ...submitted,
+ });
+ });
+
+ it.each`
+ test | initialValue | findInput | value | submitted
+ ${'description'} | ${{ description: 'Desc. 1' }} | ${findDescriptionInput} | ${'Desc. 2'} | ${{ description: 'Desc. 2' }}
+ ${'max timeout'} | ${{ maximumTimeout: 36000 }} | ${findMaxJobTimeoutInput} | ${'40000'} | ${{ maximumTimeout: 40000 }}
+ ${'tags'} | ${{ tagList: ['tag1'] }} | ${findTagsInput} | ${'tag2, tag3'} | ${{ tagList: ['tag2', 'tag3'] }}
+ `("Field updates runner's $test", async ({ initialValue, findInput, value, submitted }) => {
+ const runner = { ...mockRunner, ...initialValue };
+ createComponent({ props: { runner } });
+
+ await findInput().setValue(value);
+ await submitFormAndWait();
+
+ expectToHaveSubmittedRunnerContaining({
+ id: runner.id,
+ ...submitted,
+ });
+ });
+
+ it.each`
+ value | submitted
+ ${''} | ${{ tagList: [] }}
+ ${'tag1, tag2'} | ${{ tagList: ['tag1', 'tag2'] }}
+ ${'with spaces'} | ${{ tagList: ['with spaces'] }}
+ ${'more ,,,,, commas'} | ${{ tagList: ['more', 'commas'] }}
+ `('Field updates runner\'s tags for "$value"', async ({ value, submitted }) => {
+ const runner = { ...mockRunner, tagList: ['tag1'] };
+ createComponent({ props: { runner } });
+
+ await findTagsInput().setValue(value);
+ await submitFormAndWait();
+
+ expectToHaveSubmittedRunnerContaining({
+ id: runner.id,
+ ...submitted,
+ });
+ });
+ });
+
+ describe('On error', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('On network error, error message is shown', async () => {
+ const mockErrorMsg = 'Update error!';
+
+ runnerUpdateHandler.mockRejectedValue(new Error(mockErrorMsg));
+
+ await submitFormAndWait();
+
+ expect(createAlert).toHaveBeenLastCalledWith({
+ message: mockErrorMsg,
+ });
+ expect(captureException).toHaveBeenCalledWith({
+ component: 'RunnerUpdateForm',
+ error: new Error(mockErrorMsg),
+ });
+ expect(findSubmitDisabledAttr()).toBeUndefined();
+ });
+
+ it('On validation error, error message is shown and it is not sent to sentry', async () => {
+ const mockErrorMsg = 'Invalid value!';
+
+ runnerUpdateHandler.mockResolvedValue({
+ data: {
+ runnerUpdate: {
+ runner: mockRunner,
+ errors: [mockErrorMsg],
+ },
+ },
+ });
+
+ await submitFormAndWait();
+
+ expect(createAlert).toHaveBeenLastCalledWith({
+ message: mockErrorMsg,
+ });
+ expect(findSubmitDisabledAttr()).toBeUndefined();
+
+ expect(captureException).not.toHaveBeenCalled();
+ expect(saveAlertToLocalStorage).not.toHaveBeenCalled();
+ expect(redirectTo).not.toHaveBeenCalled();
+ });
+ });
+});
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
new file mode 100644
index 00000000000..d3c7ea50f9d
--- /dev/null
+++ b/spec/frontend/ci/runner/components/search_tokens/tag_token_spec.js
@@ -0,0 +1,208 @@
+import { GlFilteredSearchSuggestion, GlLoadingIcon, GlToken } from '@gitlab/ui';
+import { mount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import { nextTick } from 'vue';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/flash';
+import axios from '~/lib/utils/axios_utils';
+
+import TagToken, { TAG_SUGGESTIONS_PATH } from '~/ci/runner/components/search_tokens/tag_token.vue';
+import { OPERATOR_IS_ONLY } 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('~/vue_shared/components/filtered_search_bar/filtered_search_utils', () => ({
+ ...jest.requireActual('~/vue_shared/components/filtered_search_bar/filtered_search_utils'),
+ getRecentlyUsedSuggestions: jest.fn(),
+}));
+
+const mockStorageKey = 'stored-recent-tags';
+
+const mockTags = [
+ { id: 1, name: 'linux' },
+ { id: 2, name: 'windows' },
+ { id: 3, name: 'mac' },
+];
+
+const mockTagsFiltered = [mockTags[0]];
+
+const mockSearchTerm = mockTags[0].name;
+
+const GlFilteredSearchTokenStub = {
+ template: `<div>
+ <slot name="view-token"></slot>
+ <slot name="suggestions"></slot>
+ </div>`,
+};
+
+const mockTagTokenConfig = {
+ icon: 'tag',
+ title: 'Tags',
+ type: 'tag',
+ token: TagToken,
+ recentSuggestionsStorageKey: mockStorageKey,
+ operators: OPERATOR_IS_ONLY,
+};
+
+describe('TagToken', () => {
+ let mock;
+ let wrapper;
+
+ const createComponent = (props = {}) => {
+ wrapper = mount(TagToken, {
+ propsData: {
+ config: mockTagTokenConfig,
+ value: { data: '' },
+ active: false,
+ ...props,
+ },
+ provide: {
+ portalName: 'fake target',
+ alignSuggestions: function fakeAlignSuggestions() {},
+ filteredSearchSuggestionListInstance: {
+ register: jest.fn(),
+ unregister: jest.fn(),
+ },
+ },
+ stubs: {
+ GlFilteredSearchToken: GlFilteredSearchTokenStub,
+ },
+ });
+ };
+
+ const findGlFilteredSearchSuggestions = () =>
+ wrapper.findAllComponents(GlFilteredSearchSuggestion);
+ const findGlFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchTokenStub);
+ const findToken = () => wrapper.findComponent(GlToken);
+ const findGlLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+
+ mock.onGet(TAG_SUGGESTIONS_PATH, { params: { search: '' } }).reply(200, mockTags);
+ mock
+ .onGet(TAG_SUGGESTIONS_PATH, { params: { search: mockSearchTerm } })
+ .reply(200, mockTagsFiltered);
+
+ getRecentlyUsedSuggestions.mockReturnValue([]);
+ });
+
+ afterEach(() => {
+ getRecentlyUsedSuggestions.mockReset();
+ wrapper.destroy();
+ });
+
+ describe('when the tags token is displayed', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('requests tags suggestions', () => {
+ expect(mock.history.get[0].params).toEqual({ search: '' });
+ });
+
+ it('displays tags suggestions', async () => {
+ await waitForPromises();
+
+ mockTags.forEach(({ name }, i) => {
+ expect(findGlFilteredSearchSuggestions().at(i).text()).toBe(name);
+ });
+ });
+ });
+
+ describe('when suggestions are stored', () => {
+ const storedSuggestions = [{ id: 4, value: 'docker', text: 'docker' }];
+
+ beforeEach(async () => {
+ getRecentlyUsedSuggestions.mockReturnValue(storedSuggestions);
+
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('suggestions are loaded from a correct key', () => {
+ expect(getRecentlyUsedSuggestions).toHaveBeenCalledWith(mockStorageKey);
+ });
+
+ it('displays stored tags suggestions', () => {
+ expect(findGlFilteredSearchSuggestions()).toHaveLength(
+ mockTags.length + storedSuggestions.length,
+ );
+
+ expect(findGlFilteredSearchSuggestions().at(0).text()).toBe(storedSuggestions[0].text);
+ });
+ });
+
+ describe('when the users filters suggestions', () => {
+ beforeEach(() => {
+ createComponent();
+
+ findGlFilteredSearchToken().vm.$emit('input', { data: mockSearchTerm });
+ });
+
+ it('requests filtered tags suggestions', () => {
+ expect(mock.history.get[1].params).toEqual({ search: mockSearchTerm });
+ });
+
+ it('shows the loading icon', async () => {
+ findGlFilteredSearchToken().vm.$emit('input', { data: mockSearchTerm });
+ await nextTick();
+
+ expect(findGlLoadingIcon().exists()).toBe(true);
+ });
+
+ it('displays filtered tags suggestions', async () => {
+ await waitForPromises();
+
+ expect(findGlFilteredSearchSuggestions()).toHaveLength(mockTagsFiltered.length);
+
+ expect(findGlFilteredSearchSuggestions().at(0).text()).toBe(mockTagsFiltered[0].name);
+ });
+ });
+
+ describe('when suggestions cannot be loaded', () => {
+ beforeEach(async () => {
+ mock.onGet(TAG_SUGGESTIONS_PATH, { params: { search: '' } }).reply(500);
+
+ createComponent();
+ await waitForPromises();
+ });
+
+ it('error is shown', () => {
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith({ message: expect.any(String) });
+ });
+ });
+
+ describe('when the user selects a value', () => {
+ beforeEach(async () => {
+ createComponent({ value: { data: mockTags[0].name } });
+ findGlFilteredSearchToken().vm.$emit('select');
+
+ await waitForPromises();
+ });
+
+ it('selected tag is displayed', () => {
+ expect(findToken().exists()).toBe(true);
+ });
+ });
+
+ describe('when suggestions are disabled', () => {
+ beforeEach(async () => {
+ createComponent({
+ config: {
+ ...mockTagTokenConfig,
+ suggestionsDisabled: true,
+ },
+ });
+
+ await waitForPromises();
+ });
+
+ it('displays no suggestions', () => {
+ expect(findGlFilteredSearchSuggestions()).toHaveLength(0);
+ expect(mock.history.get).toHaveLength(0);
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/components/stat/runner_count_spec.js b/spec/frontend/ci/runner/components/stat/runner_count_spec.js
new file mode 100644
index 00000000000..42d8c9a1080
--- /dev/null
+++ b/spec/frontend/ci/runner/components/stat/runner_count_spec.js
@@ -0,0 +1,148 @@
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import { shallowMount } from '@vue/test-utils';
+import RunnerCount from '~/ci/runner/components/stat/runner_count.vue';
+import { INSTANCE_TYPE, GROUP_TYPE } from '~/ci/runner/constants';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { captureException } from '~/ci/runner/sentry_utils';
+
+import allRunnersCountQuery from 'ee_else_ce/ci/runner/graphql/list/all_runners_count.query.graphql';
+import groupRunnersCountQuery from 'ee_else_ce/ci/runner/graphql/list/group_runners_count.query.graphql';
+
+import { runnersCountData, groupRunnersCountData } from '../../mock_data';
+
+jest.mock('~/ci/runner/sentry_utils');
+
+Vue.use(VueApollo);
+
+describe('RunnerCount', () => {
+ let wrapper;
+ let mockRunnersCountHandler;
+ let mockGroupRunnersCountHandler;
+
+ const createComponent = ({ props = {}, ...options } = {}) => {
+ const handlers = [
+ [allRunnersCountQuery, mockRunnersCountHandler],
+ [groupRunnersCountQuery, mockGroupRunnersCountHandler],
+ ];
+
+ wrapper = shallowMount(RunnerCount, {
+ apolloProvider: createMockApollo(handlers),
+ propsData: {
+ ...props,
+ },
+ scopedSlots: {
+ default: '<strong>{{props.count}}</strong>',
+ },
+ ...options,
+ });
+
+ return waitForPromises();
+ };
+
+ beforeEach(() => {
+ mockRunnersCountHandler = jest.fn().mockResolvedValue(runnersCountData);
+ mockGroupRunnersCountHandler = jest.fn().mockResolvedValue(groupRunnersCountData);
+ });
+
+ describe('in admin scope', () => {
+ const mockVariables = { status: 'ONLINE' };
+
+ beforeEach(async () => {
+ await createComponent({ props: { scope: INSTANCE_TYPE } });
+ });
+
+ it('fetches data from admin query', () => {
+ expect(mockRunnersCountHandler).toHaveBeenCalledTimes(1);
+ expect(mockRunnersCountHandler).toHaveBeenCalledWith({});
+ });
+
+ it('fetches data with filters', async () => {
+ await createComponent({ props: { scope: INSTANCE_TYPE, variables: mockVariables } });
+
+ expect(mockRunnersCountHandler).toHaveBeenCalledTimes(2);
+ expect(mockRunnersCountHandler).toHaveBeenCalledWith(mockVariables);
+
+ expect(wrapper.html()).toBe(`<strong>${runnersCountData.data.runners.count}</strong>`);
+ });
+
+ it('does not fetch from the group query', async () => {
+ expect(mockGroupRunnersCountHandler).not.toHaveBeenCalled();
+ });
+
+ describe('when this query is skipped after data was loaded', () => {
+ beforeEach(async () => {
+ wrapper.setProps({ skip: true });
+
+ await nextTick();
+ });
+
+ it('clears current data', () => {
+ expect(wrapper.html()).toBe('<strong></strong>');
+ });
+ });
+ });
+
+ describe('when skipping query', () => {
+ beforeEach(async () => {
+ await createComponent({ props: { scope: INSTANCE_TYPE, skip: true } });
+ });
+
+ it('does not fetch data', async () => {
+ expect(mockRunnersCountHandler).not.toHaveBeenCalled();
+ expect(mockGroupRunnersCountHandler).not.toHaveBeenCalled();
+
+ expect(wrapper.html()).toBe('<strong></strong>');
+ });
+ });
+
+ describe('when runners query fails', () => {
+ const mockError = new Error('error!');
+
+ beforeEach(async () => {
+ mockRunnersCountHandler.mockRejectedValue(mockError);
+
+ await createComponent({ props: { scope: INSTANCE_TYPE } });
+ });
+
+ it('data is not shown and error is reported', async () => {
+ expect(wrapper.html()).toBe('<strong></strong>');
+
+ expect(captureException).toHaveBeenCalledWith({
+ component: 'RunnerCount',
+ error: mockError,
+ });
+ });
+ });
+
+ describe('in group scope', () => {
+ beforeEach(async () => {
+ await createComponent({ props: { scope: GROUP_TYPE } });
+ });
+
+ it('fetches data from the group query', async () => {
+ expect(mockGroupRunnersCountHandler).toHaveBeenCalledTimes(1);
+ expect(mockGroupRunnersCountHandler).toHaveBeenCalledWith({});
+
+ expect(wrapper.html()).toBe(
+ `<strong>${groupRunnersCountData.data.group.runners.count}</strong>`,
+ );
+ });
+
+ it('does not fetch from the group query', () => {
+ expect(mockRunnersCountHandler).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when .refetch() is called', () => {
+ beforeEach(async () => {
+ await createComponent({ props: { scope: INSTANCE_TYPE } });
+ wrapper.vm.refetch();
+ });
+
+ it('data is not shown and error is reported', async () => {
+ expect(mockRunnersCountHandler).toHaveBeenCalledTimes(2);
+ });
+ });
+});
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
new file mode 100644
index 00000000000..cad61f26012
--- /dev/null
+++ b/spec/frontend/ci/runner/components/stat/runner_single_stat_spec.js
@@ -0,0 +1,61 @@
+import { GlSingleStat } from '@gitlab/ui/dist/charts';
+import { shallowMount } from '@vue/test-utils';
+import RunnerSingleStat from '~/ci/runner/components/stat/runner_single_stat.vue';
+import RunnerCount from '~/ci/runner/components/stat/runner_count.vue';
+import { INSTANCE_TYPE, GROUP_TYPE } from '~/ci/runner/constants';
+
+describe('RunnerStats', () => {
+ let wrapper;
+
+ const findRunnerCount = () => wrapper.findComponent(RunnerCount);
+ const findGlSingleStat = () => wrapper.findComponent(GlSingleStat);
+
+ const createComponent = ({ props = {}, count, mountFn = shallowMount, ...options } = {}) => {
+ wrapper = mountFn(RunnerSingleStat, {
+ propsData: {
+ scope: INSTANCE_TYPE,
+ title: 'My title',
+ variables: {},
+ ...props,
+ },
+ stubs: {
+ RunnerCount: {
+ props: ['scope', 'variables', 'skip'],
+ render() {
+ return this.$scopedSlots.default({
+ count,
+ });
+ },
+ },
+ },
+ ...options,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it.each`
+ case | count | value
+ ${'number'} | ${99} | ${'99'}
+ ${'long number'} | ${1000} | ${'1,000'}
+ ${'empty number'} | ${null} | ${'-'}
+ `('formats $case', ({ count, value }) => {
+ createComponent({ count });
+
+ expect(findGlSingleStat().props('value')).toBe(value);
+ });
+
+ it('Passes runner count props', () => {
+ const props = {
+ scope: GROUP_TYPE,
+ variables: { paused: true },
+ skip: true,
+ };
+
+ createComponent({ props });
+
+ expect(findRunnerCount().props()).toEqual(props);
+ });
+});
diff --git a/spec/frontend/ci/runner/components/stat/runner_stats_spec.js b/spec/frontend/ci/runner/components/stat/runner_stats_spec.js
new file mode 100644
index 00000000000..daebf3df050
--- /dev/null
+++ b/spec/frontend/ci/runner/components/stat/runner_stats_spec.js
@@ -0,0 +1,81 @@
+import { shallowMount, mount } from '@vue/test-utils';
+import RunnerStats from '~/ci/runner/components/stat/runner_stats.vue';
+import RunnerSingleStat from '~/ci/runner/components/stat/runner_single_stat.vue';
+import {
+ I18N_STATUS_ONLINE,
+ I18N_STATUS_OFFLINE,
+ I18N_STATUS_STALE,
+ INSTANCE_TYPE,
+ STATUS_ONLINE,
+ STATUS_OFFLINE,
+ STATUS_STALE,
+} from '~/ci/runner/constants';
+
+describe('RunnerStats', () => {
+ let wrapper;
+
+ const findSingleStats = () => wrapper.findAllComponents(RunnerSingleStat);
+
+ const createComponent = ({ props = {}, mountFn = shallowMount, ...options } = {}) => {
+ wrapper = mountFn(RunnerStats, {
+ propsData: {
+ scope: INSTANCE_TYPE,
+ variables: {},
+ ...props,
+ },
+ ...options,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('Displays all the stats', () => {
+ const mockCounts = {
+ [STATUS_ONLINE]: 3,
+ [STATUS_OFFLINE]: 2,
+ [STATUS_STALE]: 1,
+ };
+
+ createComponent({
+ mountFn: mount,
+ stubs: {
+ RunnerCount: {
+ props: ['variables'],
+ render() {
+ return this.$scopedSlots.default({
+ count: mockCounts[this.variables.status],
+ });
+ },
+ },
+ },
+ });
+
+ const text = wrapper.text();
+ expect(text).toContain(`${I18N_STATUS_ONLINE} 3`);
+ expect(text).toContain(`${I18N_STATUS_OFFLINE} 2`);
+ expect(text).toContain(`${I18N_STATUS_STALE} 1`);
+ });
+
+ it('Skips query for other stats', () => {
+ createComponent({
+ props: {
+ variables: { status: STATUS_ONLINE },
+ },
+ });
+
+ expect(findSingleStats().at(0).props('skip')).toBe(false);
+ expect(findSingleStats().at(1).props('skip')).toBe(true);
+ expect(findSingleStats().at(2).props('skip')).toBe(true);
+ });
+
+ it('Displays all counts for filtered searches', () => {
+ const mockVariables = { paused: true };
+ createComponent({ props: { variables: mockVariables } });
+
+ findSingleStats().wrappers.forEach((stat) => {
+ expect(stat.props('variables')).toMatchObject(mockVariables);
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/graphql/local_state_spec.js b/spec/frontend/ci/runner/graphql/local_state_spec.js
new file mode 100644
index 00000000000..ce07a6a618d
--- /dev/null
+++ b/spec/frontend/ci/runner/graphql/local_state_spec.js
@@ -0,0 +1,167 @@
+import { gql } from '@apollo/client/core';
+import createApolloClient from '~/lib/graphql';
+import { createLocalState } from '~/ci/runner/graphql/list/local_state';
+import getCheckedRunnerIdsQuery from '~/ci/runner/graphql/list/checked_runner_ids.query.graphql';
+import { RUNNER_TYPENAME } from '~/ci/runner/constants';
+
+const makeRunner = (id, deleteRunner = true) => ({
+ id,
+ userPermissions: {
+ deleteRunner,
+ },
+});
+
+describe('~/ci/runner/graphql/list/local_state', () => {
+ let localState;
+ let apolloClient;
+
+ const createSubject = () => {
+ if (apolloClient) {
+ throw new Error('test subject already exists!');
+ }
+
+ localState = createLocalState();
+
+ const { cacheConfig, typeDefs } = localState;
+
+ apolloClient = createApolloClient({}, { cacheConfig, typeDefs });
+ };
+
+ const addMockRunnerToCache = (id) => {
+ // mock some runners in the cache to prevent dangling references
+ apolloClient.writeFragment({
+ id: `${RUNNER_TYPENAME}:${id}`,
+ fragment: gql`
+ fragment DummyRunner on CiRunner {
+ __typename
+ }
+ `,
+ data: {
+ __typename: RUNNER_TYPENAME,
+ },
+ });
+ };
+
+ const queryCheckedRunnerIds = () => {
+ const { checkedRunnerIds } = apolloClient.readQuery({
+ query: getCheckedRunnerIdsQuery,
+ });
+ return checkedRunnerIds;
+ };
+
+ beforeEach(() => {
+ createSubject();
+ });
+
+ afterEach(() => {
+ localState = null;
+ apolloClient = null;
+ });
+
+ describe('queryCheckedRunnerIds', () => {
+ it('has empty checked list by default', () => {
+ expect(queryCheckedRunnerIds()).toEqual([]);
+ });
+
+ it('returns checked runners that have a reference in the cache', () => {
+ const id = 'a';
+
+ addMockRunnerToCache(id);
+ localState.localMutations.setRunnerChecked({
+ runner: makeRunner(id),
+ isChecked: true,
+ });
+
+ expect(queryCheckedRunnerIds()).toEqual(['a']);
+ });
+
+ it('return checked runners that are not dangling references', () => {
+ addMockRunnerToCache('a'); // 'b' is missing from the cache, perhaps because it was deleted
+ localState.localMutations.setRunnerChecked({ runner: makeRunner('a'), isChecked: true });
+ localState.localMutations.setRunnerChecked({ runner: makeRunner('b'), isChecked: true });
+
+ expect(queryCheckedRunnerIds()).toEqual(['a']);
+ });
+ });
+
+ describe.each`
+ inputs | expected
+ ${[['a', true], ['b', true], ['b', true]]} | ${['a', 'b']}
+ ${[['a', true], ['b', true], ['a', false]]} | ${['b']}
+ ${[['c', true], ['b', true], ['a', true], ['d', false]]} | ${['c', 'b', 'a']}
+ `('setRunnerChecked', ({ inputs, expected }) => {
+ beforeEach(() => {
+ inputs.forEach(([id, isChecked]) => {
+ addMockRunnerToCache(id);
+ localState.localMutations.setRunnerChecked({ runner: makeRunner(id), isChecked });
+ });
+ });
+ it(`for inputs="${inputs}" has a ids="[${expected}]"`, () => {
+ expect(queryCheckedRunnerIds()).toEqual(expected);
+ });
+ });
+
+ describe.each`
+ inputs | expected
+ ${[[['a', 'b'], true]]} | ${['a', 'b']}
+ ${[[['a', 'b'], false]]} | ${[]}
+ ${[[['a', 'b'], true], [['c', 'd'], true]]} | ${['a', 'b', 'c', 'd']}
+ ${[[['a', 'b'], true], [['a', 'b'], false]]} | ${[]}
+ ${[[['a', 'b'], true], [['b'], false]]} | ${['a']}
+ `('setRunnersChecked', ({ inputs, expected }) => {
+ beforeEach(() => {
+ inputs.forEach(([ids, isChecked]) => {
+ ids.forEach(addMockRunnerToCache);
+
+ localState.localMutations.setRunnersChecked({
+ runners: ids.map((id) => makeRunner(id)),
+ isChecked,
+ });
+ });
+ });
+
+ it(`for inputs="${inputs}" has a ids="[${expected}]"`, () => {
+ expect(queryCheckedRunnerIds()).toEqual(expected);
+ });
+ });
+
+ describe('clearChecked', () => {
+ it('clears all checked items', () => {
+ ['a', 'b', 'c'].forEach((id) => {
+ addMockRunnerToCache(id);
+ localState.localMutations.setRunnerChecked({ runner: makeRunner(id), isChecked: true });
+ });
+
+ expect(queryCheckedRunnerIds()).toEqual(['a', 'b', 'c']);
+
+ localState.localMutations.clearChecked();
+
+ expect(queryCheckedRunnerIds()).toEqual([]);
+ });
+ });
+
+ describe('when some runners cannot be deleted', () => {
+ beforeEach(() => {
+ addMockRunnerToCache('a');
+ addMockRunnerToCache('b');
+ });
+
+ it('setRunnerChecked does not check runner that cannot be deleted', () => {
+ localState.localMutations.setRunnerChecked({
+ runner: makeRunner('a', false),
+ isChecked: true,
+ });
+
+ expect(queryCheckedRunnerIds()).toEqual([]);
+ });
+
+ it('setRunnersChecked does not check runner that cannot be deleted', () => {
+ localState.localMutations.setRunnersChecked({
+ runners: [makeRunner('a', false), makeRunner('b', false)],
+ isChecked: true,
+ });
+
+ expect(queryCheckedRunnerIds()).toEqual([]);
+ });
+ });
+});
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
new file mode 100644
index 00000000000..c6c3f3b7040
--- /dev/null
+++ b/spec/frontend/ci/runner/group_runner_show/group_runner_show_app_spec.js
@@ -0,0 +1,215 @@
+import Vue from 'vue';
+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 { redirectTo } from '~/lib/utils/url_utility';
+
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import RunnerHeader from '~/ci/runner/components/runner_header.vue';
+import RunnerDetails from '~/ci/runner/components/runner_details.vue';
+import RunnerPauseButton from '~/ci/runner/components/runner_pause_button.vue';
+import RunnerDeleteButton from '~/ci/runner/components/runner_delete_button.vue';
+import RunnerEditButton from '~/ci/runner/components/runner_edit_button.vue';
+import runnerQuery from '~/ci/runner/graphql/show/runner.query.graphql';
+import GroupRunnerShowApp from '~/ci/runner/group_runner_show/group_runner_show_app.vue';
+import { captureException } from '~/ci/runner/sentry_utils';
+import { saveAlertToLocalStorage } from '~/ci/runner/local_storage_alert/save_alert_to_local_storage';
+
+import { runnerData } from '../mock_data';
+
+jest.mock('~/ci/runner/local_storage_alert/save_alert_to_local_storage');
+jest.mock('~/flash');
+jest.mock('~/ci/runner/sentry_utils');
+jest.mock('~/lib/utils/url_utility');
+
+const mockRunner = runnerData.data.runner;
+const mockRunnerGraphqlId = mockRunner.id;
+const mockRunnerId = `${getIdFromGraphQLId(mockRunnerGraphqlId)}`;
+const mockRunnersPath = '/groups/group1/-/runners';
+const mockEditGroupRunnerPath = `/groups/group1/-/runners/${mockRunnerId}/edit`;
+
+Vue.use(VueApollo);
+
+describe('GroupRunnerShowApp', () => {
+ let wrapper;
+ let mockRunnerQuery;
+
+ const findRunnerHeader = () => wrapper.findComponent(RunnerHeader);
+ const findRunnerDetails = () => wrapper.findComponent(RunnerDetails);
+ const findRunnerDeleteButton = () => wrapper.findComponent(RunnerDeleteButton);
+ const findRunnerEditButton = () => wrapper.findComponent(RunnerEditButton);
+ const findRunnerPauseButton = () => wrapper.findComponent(RunnerPauseButton);
+
+ const mockRunnerQueryResult = (runner = {}) => {
+ mockRunnerQuery = jest.fn().mockResolvedValue({
+ data: {
+ runner: { ...mockRunner, ...runner },
+ },
+ });
+ };
+
+ const createComponent = ({ props = {}, mountFn = shallowMountExtended, ...options } = {}) => {
+ wrapper = mountFn(GroupRunnerShowApp, {
+ apolloProvider: createMockApollo([[runnerQuery, mockRunnerQuery]]),
+ propsData: {
+ runnerId: mockRunnerId,
+ runnersPath: mockRunnersPath,
+ editGroupRunnerPath: mockEditGroupRunnerPath,
+ ...props,
+ },
+ ...options,
+ });
+
+ return waitForPromises();
+ };
+
+ afterEach(() => {
+ mockRunnerQuery.mockReset();
+ wrapper.destroy();
+ });
+
+ describe('When showing runner details', () => {
+ beforeEach(async () => {
+ mockRunnerQueryResult();
+
+ await createComponent({ mountFn: mountExtended });
+ });
+
+ it('expect GraphQL ID to be requested', async () => {
+ expect(mockRunnerQuery).toHaveBeenCalledWith({ id: mockRunnerGraphqlId });
+ });
+
+ it('displays the header', async () => {
+ expect(findRunnerHeader().text()).toContain(`Runner #${mockRunnerId}`);
+ });
+
+ it('displays edit, pause, delete buttons', async () => {
+ expect(findRunnerEditButton().exists()).toBe(true);
+ expect(findRunnerPauseButton().exists()).toBe(true);
+ expect(findRunnerDeleteButton().exists()).toBe(true);
+ });
+
+ it('shows basic runner details', () => {
+ const expected = `Description My Runner
+ Last contact Never contacted
+ Version 1.0.0
+ IP Address None
+ Executor None
+ Architecture None
+ Platform darwin
+ Configuration Runs untagged jobs
+ Maximum job timeout None
+ Token expiry
+ Runner authentication token expiration
+ Runner authentication tokens will expire based on a set interval.
+ They will automatically rotate once expired. Learn more
+ Never expires
+ Tags None`.replace(/\s+/g, ' ');
+
+ expect(wrapper.text().replace(/\s+/g, ' ')).toContain(expected);
+ });
+
+ it('renders runner details component', () => {
+ expect(findRunnerDetails().props('runner')).toEqual(mockRunner);
+ });
+
+ describe('when runner cannot be updated', () => {
+ beforeEach(async () => {
+ mockRunnerQueryResult({
+ userPermissions: {
+ ...mockRunner.userPermissions,
+ updateRunner: false,
+ },
+ });
+
+ await createComponent({
+ mountFn: mountExtended,
+ });
+ });
+
+ it('does not display edit and pause buttons', () => {
+ expect(findRunnerEditButton().exists()).toBe(false);
+ expect(findRunnerPauseButton().exists()).toBe(false);
+ });
+
+ it('displays delete button', () => {
+ expect(findRunnerDeleteButton().exists()).toBe(true);
+ });
+ });
+
+ describe('when runner cannot be deleted', () => {
+ beforeEach(async () => {
+ mockRunnerQueryResult({
+ userPermissions: {
+ ...mockRunner.userPermissions,
+ deleteRunner: false,
+ },
+ });
+
+ await createComponent({
+ mountFn: mountExtended,
+ });
+ });
+
+ it('does not display delete button', () => {
+ expect(findRunnerDeleteButton().exists()).toBe(false);
+ });
+
+ it('displays edit and pause buttons', () => {
+ expect(findRunnerEditButton().exists()).toBe(true);
+ expect(findRunnerPauseButton().exists()).toBe(true);
+ });
+ });
+
+ describe('when runner is deleted', () => {
+ beforeEach(async () => {
+ await createComponent({
+ mountFn: mountExtended,
+ });
+ });
+
+ it('redirects to the runner list page', () => {
+ findRunnerDeleteButton().vm.$emit('deleted', { message: 'Runner deleted' });
+
+ expect(saveAlertToLocalStorage).toHaveBeenCalledWith({
+ message: 'Runner deleted',
+ variant: VARIANT_SUCCESS,
+ });
+ expect(redirectTo).toHaveBeenCalledWith(mockRunnersPath);
+ });
+ });
+ });
+
+ describe('When loading', () => {
+ it('does not show runner details', () => {
+ mockRunnerQueryResult();
+
+ createComponent();
+ expect(findRunnerDetails().exists()).toBe(false);
+ });
+ });
+
+ describe('When there is an error', () => {
+ beforeEach(async () => {
+ mockRunnerQuery = jest.fn().mockRejectedValueOnce(new Error('Error!'));
+ await createComponent();
+ });
+
+ it('does not show runner details', () => {
+ expect(findRunnerDetails().exists()).toBe(false);
+ });
+
+ it('error is reported to sentry', () => {
+ expect(captureException).toHaveBeenCalledWith({
+ error: new Error('Error!'),
+ component: 'GroupRunnerShowApp',
+ });
+ });
+
+ it('error is shown to the user', () => {
+ expect(createAlert).toHaveBeenCalled();
+ });
+ });
+});
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
new file mode 100644
index 00000000000..c3493b3c9fd
--- /dev/null
+++ b/spec/frontend/ci/runner/group_runners/group_runners_app_spec.js
@@ -0,0 +1,492 @@
+import Vue, { nextTick } from 'vue';
+import { GlButton, GlLink, GlToast } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import setWindowLocation from 'helpers/set_window_location_helper';
+import {
+ extendedWrapper,
+ shallowMountExtended,
+ mountExtended,
+} from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/flash';
+import { s__ } from '~/locale';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { updateHistory } from '~/lib/utils/url_utility';
+import { upgradeStatusTokenConfig } from 'ee_else_ce/ci/runner/components/search_tokens/upgrade_status_token_config';
+import { createLocalState } from '~/ci/runner/graphql/list/local_state';
+
+import RunnerTypeTabs from '~/ci/runner/components/runner_type_tabs.vue';
+import RunnerFilteredSearchBar from '~/ci/runner/components/runner_filtered_search_bar.vue';
+import RunnerList from '~/ci/runner/components/runner_list.vue';
+import RunnerListEmptyState from '~/ci/runner/components/runner_list_empty_state.vue';
+import RunnerStats from '~/ci/runner/components/stat/runner_stats.vue';
+import RunnerActionsCell from '~/ci/runner/components/cells/runner_actions_cell.vue';
+import RegistrationDropdown from '~/ci/runner/components/registration/registration_dropdown.vue';
+import RunnerPagination from '~/ci/runner/components/runner_pagination.vue';
+import RunnerMembershipToggle from '~/ci/runner/components/runner_membership_toggle.vue';
+
+import {
+ CREATED_ASC,
+ CREATED_DESC,
+ DEFAULT_SORT,
+ I18N_STATUS_ONLINE,
+ I18N_STATUS_OFFLINE,
+ I18N_STATUS_STALE,
+ INSTANCE_TYPE,
+ GROUP_TYPE,
+ PARAM_KEY_PAUSED,
+ PARAM_KEY_STATUS,
+ PARAM_KEY_TAG,
+ STATUS_ONLINE,
+ STATUS_OFFLINE,
+ STATUS_STALE,
+ MEMBERSHIP_ALL_AVAILABLE,
+ MEMBERSHIP_DESCENDANTS,
+ RUNNER_PAGE_SIZE,
+ I18N_EDIT,
+} from '~/ci/runner/constants';
+import groupRunnersQuery from 'ee_else_ce/ci/runner/graphql/list/group_runners.query.graphql';
+import groupRunnersCountQuery from 'ee_else_ce/ci/runner/graphql/list/group_runners_count.query.graphql';
+import GroupRunnersApp from '~/ci/runner/group_runners/group_runners_app.vue';
+import { captureException } from '~/ci/runner/sentry_utils';
+import {
+ groupRunnersData,
+ groupRunnersDataPaginated,
+ groupRunnersCountData,
+ onlineContactTimeoutSecs,
+ staleTimeoutSecs,
+ emptyPageInfo,
+ emptyStateSvgPath,
+ emptyStateFilteredSvgPath,
+} from '../mock_data';
+
+Vue.use(VueApollo);
+Vue.use(GlToast);
+
+const mockGroupFullPath = 'group1';
+const mockRegistrationToken = 'AABBCC';
+const mockGroupRunnersEdges = groupRunnersData.data.group.runners.edges;
+const mockGroupRunnersCount = mockGroupRunnersEdges.length;
+
+const mockGroupRunnersHandler = jest.fn();
+const mockGroupRunnersCountHandler = jest.fn();
+
+jest.mock('~/flash');
+jest.mock('~/ci/runner/sentry_utils');
+jest.mock('~/lib/utils/url_utility', () => ({
+ ...jest.requireActual('~/lib/utils/url_utility'),
+ updateHistory: jest.fn(),
+}));
+
+describe('GroupRunnersApp', () => {
+ let wrapper;
+
+ const findRunnerStats = () => wrapper.findComponent(RunnerStats);
+ const findRunnerActionsCell = () => wrapper.findComponent(RunnerActionsCell);
+ const findRegistrationDropdown = () => wrapper.findComponent(RegistrationDropdown);
+ const findRunnerTypeTabs = () => wrapper.findComponent(RunnerTypeTabs);
+ const findRunnerList = () => wrapper.findComponent(RunnerList);
+ const findRunnerListEmptyState = () => wrapper.findComponent(RunnerListEmptyState);
+ const findRunnerRow = (id) => extendedWrapper(wrapper.findByTestId(`runner-row-${id}`));
+ const findRunnerPagination = () => extendedWrapper(wrapper.findComponent(RunnerPagination));
+ const findRunnerPaginationNext = () => findRunnerPagination().findByText(s__('Pagination|Next'));
+ const findRunnerFilteredSearchBar = () => wrapper.findComponent(RunnerFilteredSearchBar);
+ const findRunnerMembershipToggle = () => wrapper.findComponent(RunnerMembershipToggle);
+
+ const createComponent = ({
+ props = {},
+ provide = {},
+ mountFn = shallowMountExtended,
+ ...options
+ } = {}) => {
+ const { cacheConfig, localMutations } = createLocalState();
+
+ const handlers = [
+ [groupRunnersQuery, mockGroupRunnersHandler],
+ [groupRunnersCountQuery, mockGroupRunnersCountHandler],
+ ];
+
+ wrapper = mountFn(GroupRunnersApp, {
+ apolloProvider: createMockApollo(handlers, {}, cacheConfig),
+ propsData: {
+ registrationToken: mockRegistrationToken,
+ groupFullPath: mockGroupFullPath,
+ groupRunnersLimitedCount: mockGroupRunnersCount,
+ ...props,
+ },
+ provide: {
+ localMutations,
+ onlineContactTimeoutSecs,
+ staleTimeoutSecs,
+ emptyStateSvgPath,
+ emptyStateFilteredSvgPath,
+ ...provide,
+ },
+ ...options,
+ });
+
+ return waitForPromises();
+ };
+
+ beforeEach(() => {
+ mockGroupRunnersHandler.mockResolvedValue(groupRunnersData);
+ mockGroupRunnersCountHandler.mockResolvedValue(groupRunnersCountData);
+ });
+
+ afterEach(() => {
+ mockGroupRunnersHandler.mockReset();
+ mockGroupRunnersCountHandler.mockReset();
+ wrapper.destroy();
+ });
+
+ it('shows the runner tabs with a runner count for each type', async () => {
+ await createComponent({ mountFn: mountExtended });
+
+ expect(findRunnerTypeTabs().text()).toMatchInterpolatedText(
+ `All ${mockGroupRunnersCount} Group ${mockGroupRunnersCount} Project ${mockGroupRunnersCount}`,
+ );
+ });
+
+ it('shows the runner setup instructions', () => {
+ createComponent();
+
+ expect(findRegistrationDropdown().props('registrationToken')).toBe(mockRegistrationToken);
+ expect(findRegistrationDropdown().props('type')).toBe(GROUP_TYPE);
+ });
+
+ describe('show all available runners toggle', () => {
+ it('shows the membership toggle', () => {
+ createComponent();
+ expect(findRunnerMembershipToggle().exists()).toBe(true);
+ });
+
+ it('sets the membership toggle', () => {
+ setWindowLocation(`?membership[]=${MEMBERSHIP_ALL_AVAILABLE}`);
+
+ createComponent();
+
+ expect(findRunnerMembershipToggle().props('value')).toBe(MEMBERSHIP_ALL_AVAILABLE);
+ });
+
+ it('requests filter', async () => {
+ createComponent();
+ findRunnerMembershipToggle().vm.$emit('input', MEMBERSHIP_ALL_AVAILABLE);
+
+ await waitForPromises();
+
+ expect(mockGroupRunnersHandler).toHaveBeenLastCalledWith(
+ expect.objectContaining({
+ membership: MEMBERSHIP_ALL_AVAILABLE,
+ }),
+ );
+ });
+ });
+
+ it('shows total runner counts', async () => {
+ await createComponent({ mountFn: mountExtended });
+
+ expect(mockGroupRunnersCountHandler).toHaveBeenCalledWith({
+ status: STATUS_ONLINE,
+ membership: MEMBERSHIP_DESCENDANTS,
+ groupFullPath: mockGroupFullPath,
+ });
+ expect(mockGroupRunnersCountHandler).toHaveBeenCalledWith({
+ status: STATUS_OFFLINE,
+ membership: MEMBERSHIP_DESCENDANTS,
+ groupFullPath: mockGroupFullPath,
+ });
+ expect(mockGroupRunnersCountHandler).toHaveBeenCalledWith({
+ status: STATUS_STALE,
+ membership: MEMBERSHIP_DESCENDANTS,
+ groupFullPath: mockGroupFullPath,
+ });
+
+ const text = findRunnerStats().text();
+ expect(text).toContain(`${I18N_STATUS_ONLINE} ${mockGroupRunnersCount}`);
+ expect(text).toContain(`${I18N_STATUS_OFFLINE} ${mockGroupRunnersCount}`);
+ expect(text).toContain(`${I18N_STATUS_STALE} ${mockGroupRunnersCount}`);
+ });
+
+ it('shows the runners list', async () => {
+ await createComponent();
+
+ const runners = findRunnerList().props('runners');
+ expect(runners).toEqual(mockGroupRunnersEdges.map(({ node }) => node));
+ });
+
+ it('requests the runners with group path and no other filters', async () => {
+ await createComponent();
+
+ expect(mockGroupRunnersHandler).toHaveBeenLastCalledWith({
+ groupFullPath: mockGroupFullPath,
+ status: undefined,
+ type: undefined,
+ membership: MEMBERSHIP_DESCENDANTS,
+ sort: DEFAULT_SORT,
+ first: RUNNER_PAGE_SIZE,
+ });
+ });
+
+ it('sets tokens in the filtered search', () => {
+ createComponent();
+
+ const tokens = findRunnerFilteredSearchBar().props('tokens');
+
+ expect(tokens).toEqual([
+ expect.objectContaining({
+ type: PARAM_KEY_PAUSED,
+ options: expect.any(Array),
+ }),
+ expect.objectContaining({
+ type: PARAM_KEY_STATUS,
+ options: expect.any(Array),
+ }),
+ expect.objectContaining({
+ type: PARAM_KEY_TAG,
+ suggestionsDisabled: true,
+ }),
+ upgradeStatusTokenConfig,
+ ]);
+ });
+
+ describe('Single runner row', () => {
+ let showToast;
+
+ const { webUrl, editUrl, node } = mockGroupRunnersEdges[0];
+ const { id: graphqlId, shortSha } = node;
+ const id = getIdFromGraphQLId(graphqlId);
+ const COUNT_QUERIES = 6; // Smart queries that display a filtered count of runners
+ const FILTERED_COUNT_QUERIES = 6; // Smart queries that display a count of runners in tabs and single stats
+
+ beforeEach(async () => {
+ await createComponent({ mountFn: mountExtended });
+ showToast = jest.spyOn(wrapper.vm.$root.$toast, 'show');
+ });
+
+ it('view link is displayed correctly', () => {
+ const viewLink = findRunnerRow(id).findByTestId('td-summary').findComponent(GlLink);
+
+ expect(viewLink.text()).toBe(`#${id} (${shortSha})`);
+ expect(viewLink.attributes('href')).toBe(webUrl);
+ });
+
+ it('edit link is displayed correctly', () => {
+ const editLink = findRunnerRow(id).findByTestId('td-actions').findComponent(GlButton);
+
+ expect(editLink.attributes()).toMatchObject({
+ 'aria-label': I18N_EDIT,
+ href: editUrl,
+ });
+ });
+
+ it('When runner is paused or unpaused, some data is refetched', async () => {
+ expect(mockGroupRunnersCountHandler).toHaveBeenCalledTimes(COUNT_QUERIES);
+
+ findRunnerActionsCell().vm.$emit('toggledPaused');
+
+ expect(mockGroupRunnersCountHandler).toHaveBeenCalledTimes(
+ COUNT_QUERIES + FILTERED_COUNT_QUERIES,
+ );
+
+ expect(showToast).toHaveBeenCalledTimes(0);
+ });
+
+ it('When runner is deleted, data is refetched and a toast message is shown', async () => {
+ findRunnerActionsCell().vm.$emit('deleted', { message: 'Runner deleted' });
+
+ expect(showToast).toHaveBeenCalledTimes(1);
+ expect(showToast).toHaveBeenCalledWith('Runner deleted');
+ });
+ });
+
+ describe('when a filter is preselected', () => {
+ beforeEach(async () => {
+ setWindowLocation(`?status[]=${STATUS_ONLINE}&runner_type[]=${INSTANCE_TYPE}`);
+
+ await createComponent({ mountFn: mountExtended });
+ });
+
+ it('sets the filters in the search bar', () => {
+ expect(findRunnerFilteredSearchBar().props('value')).toEqual({
+ runnerType: INSTANCE_TYPE,
+ membership: MEMBERSHIP_DESCENDANTS,
+ filters: [{ type: 'status', value: { data: STATUS_ONLINE, operator: '=' } }],
+ sort: 'CREATED_DESC',
+ pagination: {},
+ });
+ });
+
+ it('requests the runners with filter parameters', () => {
+ expect(mockGroupRunnersHandler).toHaveBeenLastCalledWith({
+ groupFullPath: mockGroupFullPath,
+ status: STATUS_ONLINE,
+ type: INSTANCE_TYPE,
+ membership: MEMBERSHIP_DESCENDANTS,
+ sort: DEFAULT_SORT,
+ first: RUNNER_PAGE_SIZE,
+ });
+ });
+
+ it('fetches count results for requested status', () => {
+ expect(mockGroupRunnersCountHandler).toHaveBeenCalledWith({
+ groupFullPath: mockGroupFullPath,
+ type: INSTANCE_TYPE,
+ membership: MEMBERSHIP_DESCENDANTS,
+ status: STATUS_ONLINE,
+ });
+ });
+ });
+
+ describe('when a filter is selected by the user', () => {
+ beforeEach(async () => {
+ await createComponent({ mountFn: mountExtended });
+
+ findRunnerFilteredSearchBar().vm.$emit('input', {
+ runnerType: null,
+ membership: MEMBERSHIP_DESCENDANTS,
+ filters: [{ type: PARAM_KEY_STATUS, value: { data: STATUS_ONLINE, operator: '=' } }],
+ sort: CREATED_ASC,
+ });
+
+ await nextTick();
+ });
+
+ it('updates the browser url', () => {
+ expect(updateHistory).toHaveBeenLastCalledWith({
+ title: expect.any(String),
+ url: expect.stringContaining('?status[]=ONLINE&sort=CREATED_ASC'),
+ });
+ });
+
+ it('requests the runners with filters', () => {
+ expect(mockGroupRunnersHandler).toHaveBeenLastCalledWith({
+ groupFullPath: mockGroupFullPath,
+ status: STATUS_ONLINE,
+ membership: MEMBERSHIP_DESCENDANTS,
+ sort: CREATED_ASC,
+ first: RUNNER_PAGE_SIZE,
+ });
+ });
+
+ it('fetches count results for requested status', () => {
+ expect(mockGroupRunnersCountHandler).toHaveBeenCalledWith({
+ groupFullPath: mockGroupFullPath,
+ status: STATUS_ONLINE,
+ membership: MEMBERSHIP_DESCENDANTS,
+ });
+ });
+ });
+
+ it('when runners have not loaded, shows a loading state', () => {
+ createComponent();
+ expect(findRunnerList().props('loading')).toBe(true);
+ expect(findRunnerPagination().attributes('disabled')).toBe('true');
+ });
+
+ it('runners can be deleted in bulk', () => {
+ createComponent();
+ expect(findRunnerList().props('checkable')).toBe(true);
+ });
+
+ describe('when no runners are found', () => {
+ beforeEach(async () => {
+ mockGroupRunnersHandler.mockResolvedValue({
+ data: {
+ group: {
+ id: '1',
+ runners: {
+ edges: [],
+ pageInfo: emptyPageInfo,
+ },
+ },
+ },
+ });
+ await createComponent();
+ });
+
+ it('shows no errors', () => {
+ expect(createAlert).not.toHaveBeenCalled();
+ });
+
+ it('shows an empty state', async () => {
+ expect(findRunnerListEmptyState().exists()).toBe(true);
+ });
+ });
+
+ describe('when runners query fails', () => {
+ beforeEach(async () => {
+ mockGroupRunnersHandler.mockRejectedValue(new Error('Error!'));
+ await createComponent();
+ });
+
+ it('error is shown to the user', async () => {
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ });
+
+ it('error is reported to sentry', async () => {
+ expect(captureException).toHaveBeenCalledWith({
+ error: new Error('Error!'),
+ component: 'GroupRunnersApp',
+ });
+ });
+ });
+
+ describe('Pagination', () => {
+ const { pageInfo } = groupRunnersDataPaginated.data.group.runners;
+
+ beforeEach(async () => {
+ mockGroupRunnersHandler.mockResolvedValue(groupRunnersDataPaginated);
+
+ await createComponent({ mountFn: mountExtended });
+ });
+
+ it('passes the page info', () => {
+ expect(findRunnerPagination().props('pageInfo')).toEqual(pageInfo);
+ });
+
+ it('navigates to the next page', async () => {
+ await findRunnerPaginationNext().trigger('click');
+
+ expect(mockGroupRunnersHandler).toHaveBeenLastCalledWith({
+ groupFullPath: mockGroupFullPath,
+ membership: MEMBERSHIP_DESCENDANTS,
+ sort: CREATED_DESC,
+ first: RUNNER_PAGE_SIZE,
+ after: pageInfo.endCursor,
+ });
+ });
+ });
+
+ describe('when user has permission to register group runner', () => {
+ beforeEach(() => {
+ createComponent({
+ propsData: {
+ registrationToken: mockRegistrationToken,
+ groupFullPath: mockGroupFullPath,
+ groupRunnersLimitedCount: mockGroupRunnersCount,
+ },
+ });
+ });
+
+ it('shows the register group runner button', () => {
+ expect(findRegistrationDropdown().exists()).toBe(true);
+ });
+ });
+
+ describe('when user has no permission to register group runner', () => {
+ beforeEach(() => {
+ createComponent({
+ propsData: {
+ registrationToken: null,
+ groupFullPath: mockGroupFullPath,
+ groupRunnersLimitedCount: mockGroupRunnersCount,
+ },
+ });
+ });
+
+ it('does not show the register group runner button', () => {
+ expect(findRegistrationDropdown().exists()).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/local_storage_alert/save_alert_to_local_storage_spec.js b/spec/frontend/ci/runner/local_storage_alert/save_alert_to_local_storage_spec.js
new file mode 100644
index 00000000000..b34ef01eeed
--- /dev/null
+++ b/spec/frontend/ci/runner/local_storage_alert/save_alert_to_local_storage_spec.js
@@ -0,0 +1,24 @@
+import AccessorUtilities from '~/lib/utils/accessor';
+import { saveAlertToLocalStorage } from '~/ci/runner/local_storage_alert/save_alert_to_local_storage';
+import { LOCAL_STORAGE_ALERT_KEY } from '~/ci/runner/local_storage_alert/constants';
+import { useLocalStorageSpy } from 'helpers/local_storage_helper';
+
+const mockAlert = { message: 'Message!' };
+
+describe('saveAlertToLocalStorage', () => {
+ useLocalStorageSpy();
+
+ beforeEach(() => {
+ jest.spyOn(AccessorUtilities, 'canUseLocalStorage').mockReturnValue(true);
+ });
+
+ it('saves message to local storage', () => {
+ saveAlertToLocalStorage(mockAlert);
+
+ expect(localStorage.setItem).toHaveBeenCalledTimes(1);
+ expect(localStorage.setItem).toHaveBeenCalledWith(
+ LOCAL_STORAGE_ALERT_KEY,
+ JSON.stringify(mockAlert),
+ );
+ });
+});
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
new file mode 100644
index 00000000000..03908891cfd
--- /dev/null
+++ b/spec/frontend/ci/runner/local_storage_alert/show_alert_from_local_storage_spec.js
@@ -0,0 +1,40 @@
+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';
+
+jest.mock('~/flash');
+
+describe('showAlertFromLocalStorage', () => {
+ useLocalStorageSpy();
+
+ beforeEach(() => {
+ jest.spyOn(AccessorUtilities, 'canUseLocalStorage').mockReturnValue(true);
+ });
+
+ it('retrieves message from local storage and displays it', async () => {
+ const mockAlert = { message: 'Message!' };
+
+ localStorage.getItem.mockReturnValueOnce(JSON.stringify(mockAlert));
+
+ await showAlertFromLocalStorage();
+
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith(mockAlert);
+
+ expect(localStorage.removeItem).toHaveBeenCalledTimes(1);
+ expect(localStorage.removeItem).toHaveBeenCalledWith(LOCAL_STORAGE_ALERT_KEY);
+ });
+
+ it.each(['not a json string', null])('does not fail when stored message is %o', async (item) => {
+ localStorage.getItem.mockReturnValueOnce(item);
+
+ await showAlertFromLocalStorage();
+
+ expect(createAlert).not.toHaveBeenCalled();
+
+ expect(localStorage.removeItem).toHaveBeenCalledTimes(1);
+ expect(localStorage.removeItem).toHaveBeenCalledWith(LOCAL_STORAGE_ALERT_KEY);
+ });
+});
diff --git a/spec/frontend/ci/runner/mock_data.js b/spec/frontend/ci/runner/mock_data.js
new file mode 100644
index 00000000000..eff5abc21b5
--- /dev/null
+++ b/spec/frontend/ci/runner/mock_data.js
@@ -0,0 +1,322 @@
+// Fixtures generated by: spec/frontend/fixtures/runner.rb
+
+// Show runner queries
+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';
+import runnerJobsData from 'test_fixtures/graphql/ci/runner/show/runner_jobs.query.graphql.json';
+
+// Edit runner queries
+import runnerFormData from 'test_fixtures/graphql/ci/runner/edit/runner_form.query.graphql.json';
+
+// 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';
+import runnersCountData from 'test_fixtures/graphql/ci/runner/list/all_runners_count.query.graphql.json';
+import groupRunnersData from 'test_fixtures/graphql/ci/runner/list/group_runners.query.graphql.json';
+import groupRunnersDataPaginated from 'test_fixtures/graphql/ci/runner/list/group_runners.query.graphql.paginated.json';
+import groupRunnersCountData from 'test_fixtures/graphql/ci/runner/list/group_runners_count.query.graphql.json';
+
+import { DEFAULT_MEMBERSHIP, RUNNER_PAGE_SIZE } from '~/ci/runner/constants';
+
+const emptyPageInfo = {
+ __typename: 'PageInfo',
+ hasNextPage: false,
+ hasPreviousPage: false,
+ startCursor: '',
+ endCursor: '',
+};
+
+// Other mock data
+
+// Mock searches and their corresponding urls
+export const mockSearchExamples = [
+ {
+ name: 'a default query',
+ urlQuery: '',
+ search: {
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [],
+ pagination: {},
+ sort: 'CREATED_DESC',
+ },
+ graphqlVariables: {
+ membership: DEFAULT_MEMBERSHIP,
+ sort: 'CREATED_DESC',
+ first: RUNNER_PAGE_SIZE,
+ },
+ isDefault: true,
+ },
+ {
+ name: 'a single status',
+ urlQuery: '?status[]=ACTIVE',
+ search: {
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [{ type: 'status', value: { data: 'ACTIVE', operator: '=' } }],
+ pagination: {},
+ sort: 'CREATED_DESC',
+ },
+ graphqlVariables: {
+ membership: DEFAULT_MEMBERSHIP,
+ status: 'ACTIVE',
+ sort: 'CREATED_DESC',
+ first: RUNNER_PAGE_SIZE,
+ },
+ },
+ {
+ name: 'a single term text search',
+ urlQuery: '?search=something',
+ search: {
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [
+ {
+ type: 'filtered-search-term',
+ value: { data: 'something' },
+ },
+ ],
+ pagination: {},
+ sort: 'CREATED_DESC',
+ },
+ graphqlVariables: {
+ membership: DEFAULT_MEMBERSHIP,
+ search: 'something',
+ sort: 'CREATED_DESC',
+ first: RUNNER_PAGE_SIZE,
+ },
+ },
+ {
+ name: 'a two terms text search',
+ urlQuery: '?search=something+else',
+ search: {
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [
+ {
+ type: 'filtered-search-term',
+ value: { data: 'something' },
+ },
+ {
+ type: 'filtered-search-term',
+ value: { data: 'else' },
+ },
+ ],
+ pagination: {},
+ sort: 'CREATED_DESC',
+ },
+ graphqlVariables: {
+ membership: DEFAULT_MEMBERSHIP,
+ search: 'something else',
+ sort: 'CREATED_DESC',
+ first: RUNNER_PAGE_SIZE,
+ },
+ },
+ {
+ name: 'single instance type',
+ urlQuery: '?runner_type[]=INSTANCE_TYPE',
+ search: {
+ runnerType: 'INSTANCE_TYPE',
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [],
+ pagination: {},
+ sort: 'CREATED_DESC',
+ },
+ graphqlVariables: {
+ type: 'INSTANCE_TYPE',
+ membership: DEFAULT_MEMBERSHIP,
+ sort: 'CREATED_DESC',
+ first: RUNNER_PAGE_SIZE,
+ },
+ },
+ {
+ name: 'multiple runner status',
+ urlQuery: '?status[]=ACTIVE&status[]=PAUSED',
+ search: {
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [
+ { type: 'status', value: { data: 'ACTIVE', operator: '=' } },
+ { type: 'status', value: { data: 'PAUSED', operator: '=' } },
+ ],
+ pagination: {},
+ sort: 'CREATED_DESC',
+ },
+ graphqlVariables: {
+ status: 'ACTIVE',
+ membership: DEFAULT_MEMBERSHIP,
+ sort: 'CREATED_DESC',
+ first: RUNNER_PAGE_SIZE,
+ },
+ },
+ {
+ name: 'multiple status, a single instance type and a non default sort',
+ urlQuery: '?status[]=ACTIVE&runner_type[]=INSTANCE_TYPE&sort=CREATED_ASC',
+ search: {
+ runnerType: 'INSTANCE_TYPE',
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [{ type: 'status', value: { data: 'ACTIVE', operator: '=' } }],
+ pagination: {},
+ sort: 'CREATED_ASC',
+ },
+ graphqlVariables: {
+ status: 'ACTIVE',
+ type: 'INSTANCE_TYPE',
+ membership: DEFAULT_MEMBERSHIP,
+ sort: 'CREATED_ASC',
+ first: RUNNER_PAGE_SIZE,
+ },
+ },
+ {
+ name: 'a tag',
+ urlQuery: '?tag[]=tag-1',
+ search: {
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [{ type: 'tag', value: { data: 'tag-1', operator: '=' } }],
+ pagination: {},
+ sort: 'CREATED_DESC',
+ },
+ graphqlVariables: {
+ membership: DEFAULT_MEMBERSHIP,
+ tagList: ['tag-1'],
+ first: 20,
+ sort: 'CREATED_DESC',
+ },
+ },
+ {
+ name: 'two tags',
+ urlQuery: '?tag[]=tag-1&tag[]=tag-2',
+ search: {
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [
+ { type: 'tag', value: { data: 'tag-1', operator: '=' } },
+ { type: 'tag', value: { data: 'tag-2', operator: '=' } },
+ ],
+ pagination: {},
+ sort: 'CREATED_DESC',
+ },
+ graphqlVariables: {
+ membership: DEFAULT_MEMBERSHIP,
+ tagList: ['tag-1', 'tag-2'],
+ first: 20,
+ sort: 'CREATED_DESC',
+ },
+ },
+ {
+ name: 'the next page',
+ urlQuery: '?after=AFTER_CURSOR',
+ search: {
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [],
+ pagination: { after: 'AFTER_CURSOR' },
+ sort: 'CREATED_DESC',
+ },
+ graphqlVariables: {
+ membership: DEFAULT_MEMBERSHIP,
+ sort: 'CREATED_DESC',
+ after: 'AFTER_CURSOR',
+ first: RUNNER_PAGE_SIZE,
+ },
+ },
+ {
+ name: 'the previous page',
+ urlQuery: '?before=BEFORE_CURSOR',
+ search: {
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [],
+ pagination: { before: 'BEFORE_CURSOR' },
+ sort: 'CREATED_DESC',
+ },
+ graphqlVariables: {
+ membership: DEFAULT_MEMBERSHIP,
+ sort: 'CREATED_DESC',
+ before: 'BEFORE_CURSOR',
+ last: RUNNER_PAGE_SIZE,
+ },
+ },
+ {
+ name: 'the next page filtered by a status, an instance type, tags and a non default sort',
+ urlQuery:
+ '?status[]=ACTIVE&runner_type[]=INSTANCE_TYPE&tag[]=tag-1&tag[]=tag-2&sort=CREATED_ASC&after=AFTER_CURSOR',
+ search: {
+ runnerType: 'INSTANCE_TYPE',
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [
+ { type: 'status', value: { data: 'ACTIVE', operator: '=' } },
+ { type: 'tag', value: { data: 'tag-1', operator: '=' } },
+ { type: 'tag', value: { data: 'tag-2', operator: '=' } },
+ ],
+ pagination: { after: 'AFTER_CURSOR' },
+ sort: 'CREATED_ASC',
+ },
+ graphqlVariables: {
+ status: 'ACTIVE',
+ type: 'INSTANCE_TYPE',
+ membership: DEFAULT_MEMBERSHIP,
+ tagList: ['tag-1', 'tag-2'],
+ sort: 'CREATED_ASC',
+ after: 'AFTER_CURSOR',
+ first: RUNNER_PAGE_SIZE,
+ },
+ },
+ {
+ name: 'paused runners',
+ urlQuery: '?paused[]=true',
+ search: {
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [{ type: 'paused', value: { data: 'true', operator: '=' } }],
+ pagination: {},
+ sort: 'CREATED_DESC',
+ },
+ graphqlVariables: {
+ paused: true,
+ membership: DEFAULT_MEMBERSHIP,
+ sort: 'CREATED_DESC',
+ first: RUNNER_PAGE_SIZE,
+ },
+ },
+ {
+ name: 'active runners',
+ urlQuery: '?paused[]=false',
+ search: {
+ runnerType: null,
+ membership: DEFAULT_MEMBERSHIP,
+ filters: [{ type: 'paused', value: { data: 'false', operator: '=' } }],
+ pagination: {},
+ sort: 'CREATED_DESC',
+ },
+ graphqlVariables: {
+ paused: false,
+ membership: DEFAULT_MEMBERSHIP,
+ sort: 'CREATED_DESC',
+ first: RUNNER_PAGE_SIZE,
+ },
+ },
+];
+
+export const onlineContactTimeoutSecs = 2 * 60 * 60;
+export const staleTimeoutSecs = 7889238; // Ruby's `3.months`
+
+export const emptyStateSvgPath = 'emptyStateSvgPath.svg';
+export const emptyStateFilteredSvgPath = 'emptyStateFilteredSvgPath.svg';
+
+export {
+ allRunnersData,
+ allRunnersDataPaginated,
+ runnersCountData,
+ groupRunnersData,
+ groupRunnersDataPaginated,
+ groupRunnersCountData,
+ emptyPageInfo,
+ runnerData,
+ runnerWithGroupData,
+ runnerProjectsData,
+ runnerJobsData,
+ runnerFormData,
+};
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
new file mode 100644
index 00000000000..a9369a5e626
--- /dev/null
+++ b/spec/frontend/ci/runner/runner_edit/runner_edit_app_spec.js
@@ -0,0 +1,114 @@
+import { mount, shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { createAlert } from '~/flash';
+
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import RunnerHeader from '~/ci/runner/components/runner_header.vue';
+import RunnerUpdateForm from '~/ci/runner/components/runner_update_form.vue';
+import runnerFormQuery from '~/ci/runner/graphql/edit/runner_form.query.graphql';
+import RunnerEditApp from '~/ci/runner/runner_edit/runner_edit_app.vue';
+import { captureException } from '~/ci/runner/sentry_utils';
+import { I18N_STATUS_NEVER_CONTACTED, I18N_INSTANCE_TYPE } from '~/ci/runner/constants';
+
+import { runnerFormData } from '../mock_data';
+
+jest.mock('~/flash');
+jest.mock('~/ci/runner/sentry_utils');
+
+const mockRunner = runnerFormData.data.runner;
+const mockRunnerGraphqlId = mockRunner.id;
+const mockRunnerId = `${getIdFromGraphQLId(mockRunnerGraphqlId)}`;
+const mockRunnerPath = `/admin/runners/${mockRunnerId}`;
+
+Vue.use(VueApollo);
+
+describe('RunnerEditApp', () => {
+ let wrapper;
+ let mockRunnerQuery;
+
+ const findRunnerHeader = () => wrapper.findComponent(RunnerHeader);
+ const findRunnerUpdateForm = () => wrapper.findComponent(RunnerUpdateForm);
+
+ const createComponentWithApollo = ({ props = {}, mountFn = shallowMount } = {}) => {
+ wrapper = mountFn(RunnerEditApp, {
+ apolloProvider: createMockApollo([[runnerFormQuery, mockRunnerQuery]]),
+ propsData: {
+ runnerId: mockRunnerId,
+ runnerPath: mockRunnerPath,
+ ...props,
+ },
+ });
+
+ return waitForPromises();
+ };
+
+ beforeEach(() => {
+ mockRunnerQuery = jest.fn().mockResolvedValue(runnerFormData);
+ });
+
+ afterEach(() => {
+ mockRunnerQuery.mockReset();
+ wrapper.destroy();
+ });
+
+ it('expect GraphQL ID to be requested', async () => {
+ await createComponentWithApollo();
+
+ expect(mockRunnerQuery).toHaveBeenCalledWith({ id: mockRunnerGraphqlId });
+ });
+
+ it('displays the runner id and creation date', async () => {
+ await createComponentWithApollo({ mountFn: mount });
+
+ expect(findRunnerHeader().text()).toContain(`Runner #${mockRunnerId}`);
+ expect(findRunnerHeader().text()).toContain('created');
+ });
+
+ it('displays the runner type and status', async () => {
+ await createComponentWithApollo({ mountFn: mount });
+
+ expect(findRunnerHeader().text()).toContain(I18N_STATUS_NEVER_CONTACTED);
+ expect(findRunnerHeader().text()).toContain(I18N_INSTANCE_TYPE);
+ });
+
+ it('displays a loading runner form', () => {
+ createComponentWithApollo();
+
+ expect(findRunnerUpdateForm().props()).toMatchObject({
+ runner: null,
+ loading: true,
+ runnerPath: mockRunnerPath,
+ });
+ });
+
+ it('displays the runner form', async () => {
+ await createComponentWithApollo();
+
+ expect(findRunnerUpdateForm().props()).toMatchObject({
+ loading: false,
+ runnerPath: mockRunnerPath,
+ });
+ expect(findRunnerUpdateForm().props('runner')).toEqual(mockRunner);
+ });
+
+ describe('When there is an error', () => {
+ beforeEach(async () => {
+ mockRunnerQuery = jest.fn().mockRejectedValueOnce(new Error('Error!'));
+ await createComponentWithApollo();
+ });
+
+ it('error is reported to sentry', () => {
+ expect(captureException).toHaveBeenCalledWith({
+ error: new Error('Error!'),
+ component: 'RunnerEditApp',
+ });
+ });
+
+ it('error is shown to the user', () => {
+ expect(createAlert).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/runner_search_utils_spec.js b/spec/frontend/ci/runner/runner_search_utils_spec.js
new file mode 100644
index 00000000000..1db8fa1829b
--- /dev/null
+++ b/spec/frontend/ci/runner/runner_search_utils_spec.js
@@ -0,0 +1,138 @@
+import {
+ searchValidator,
+ updateOutdatedUrl,
+ fromUrlQueryToSearch,
+ fromSearchToUrl,
+ fromSearchToVariables,
+ isSearchFiltered,
+} from 'ee_else_ce/ci/runner/runner_search_utils';
+import { mockSearchExamples } from './mock_data';
+
+describe('search_params.js', () => {
+ describe('searchValidator', () => {
+ mockSearchExamples.forEach(({ name, search }) => {
+ it(`Validates ${name} as a search object`, () => {
+ expect(searchValidator(search)).toBe(true);
+ });
+ });
+ });
+
+ describe('updateOutdatedUrl', () => {
+ it('returns null for urls that do not need updating', () => {
+ expect(updateOutdatedUrl('http://test.host/')).toBe(null);
+ expect(updateOutdatedUrl('http://test.host/?a=b')).toBe(null);
+ });
+
+ it.each`
+ query | updatedQuery
+ ${'status[]=ACTIVE'} | ${'paused[]=false'}
+ ${'status[]=ACTIVE&a=b'} | ${'a=b&paused[]=false'}
+ ${'status[]=ACTIVE'} | ${'paused[]=false'}
+ ${'status[]=PAUSED'} | ${'paused[]=true'}
+ ${'page=2&after=AFTER'} | ${'after=AFTER'}
+ ${'page=2&before=BEFORE'} | ${'before=BEFORE'}
+ ${'status[]=PAUSED&page=2&after=AFTER'} | ${'after=AFTER&paused[]=true'}
+ `('updates "$query" to "$updatedQuery"', ({ query, updatedQuery }) => {
+ const mockUrl = 'http://test.host/admin/runners?';
+
+ expect(updateOutdatedUrl(`${mockUrl}${query}`)).toBe(`${mockUrl}${updatedQuery}`);
+ });
+ });
+
+ describe('fromUrlQueryToSearch', () => {
+ mockSearchExamples.forEach(({ name, urlQuery, search }) => {
+ it(`Converts ${name} to a search object`, () => {
+ expect(fromUrlQueryToSearch(urlQuery)).toEqual(search);
+ });
+ });
+
+ it('When search params appear as array, they are concatenated', () => {
+ expect(fromUrlQueryToSearch('?search[]=my&search[]=text').filters).toEqual([
+ { type: 'filtered-search-term', value: { data: 'my' } },
+ { type: 'filtered-search-term', value: { data: 'text' } },
+ ]);
+ });
+ });
+
+ describe('fromSearchToUrl', () => {
+ mockSearchExamples.forEach(({ name, urlQuery, search }) => {
+ it(`Converts ${name} to a url`, () => {
+ expect(fromSearchToUrl(search)).toBe(`http://test.host/${urlQuery}`);
+ });
+ });
+
+ it.each([
+ 'http://test.host/?status[]=ACTIVE',
+ 'http://test.host/?runner_type[]=INSTANCE_TYPE',
+ 'http://test.host/?search=my_text',
+ ])('When a filter is removed, it is removed from the URL', (initalUrl) => {
+ const search = { filters: [], sort: 'CREATED_DESC' };
+ const expectedUrl = `http://test.host/`;
+
+ expect(fromSearchToUrl(search, initalUrl)).toBe(expectedUrl);
+ });
+
+ it('When unrelated search parameter is present, it does not get removed', () => {
+ const initialUrl = `http://test.host/?unrelated=UNRELATED&status[]=ACTIVE`;
+ const search = { filters: [], sort: 'CREATED_DESC' };
+ const expectedUrl = `http://test.host/?unrelated=UNRELATED`;
+
+ expect(fromSearchToUrl(search, initialUrl)).toBe(expectedUrl);
+ });
+ });
+
+ describe('fromSearchToVariables', () => {
+ mockSearchExamples.forEach(({ name, graphqlVariables, search }) => {
+ it(`Converts ${name} to a GraphQL query variables object`, () => {
+ expect(fromSearchToVariables(search)).toEqual(graphqlVariables);
+ });
+ });
+
+ it('When a search param is empty, it gets removed', () => {
+ expect(
+ fromSearchToVariables({
+ filters: [
+ {
+ type: 'filtered-search-term',
+ value: { data: '' },
+ },
+ ],
+ }),
+ ).toMatchObject({
+ search: '',
+ });
+
+ expect(
+ fromSearchToVariables({
+ filters: [
+ {
+ type: 'filtered-search-term',
+ value: { data: 'something' },
+ },
+ {
+ type: 'filtered-search-term',
+ value: { data: '' },
+ },
+ ],
+ }),
+ ).toMatchObject({
+ search: 'something',
+ });
+ });
+ });
+
+ describe('isSearchFiltered', () => {
+ mockSearchExamples.forEach(({ name, search, isDefault }) => {
+ it(`Given ${name}, evaluates to ${isDefault ? 'not ' : ''}filtered`, () => {
+ expect(isSearchFiltered(search)).toBe(!isDefault);
+ });
+ });
+
+ it.each([null, undefined, {}])(
+ 'given a missing pagination, evaluates as not filtered',
+ (mockPagination) => {
+ expect(isSearchFiltered({ pagination: mockPagination })).toBe(false);
+ },
+ );
+ });
+});
diff --git a/spec/frontend/ci/runner/runner_update_form_utils_spec.js b/spec/frontend/ci/runner/runner_update_form_utils_spec.js
new file mode 100644
index 00000000000..b2f7bbc49a9
--- /dev/null
+++ b/spec/frontend/ci/runner/runner_update_form_utils_spec.js
@@ -0,0 +1,96 @@
+import { ACCESS_LEVEL_NOT_PROTECTED } from '~/ci/runner/constants';
+import {
+ modelToUpdateMutationVariables,
+ runnerToModel,
+} from '~/ci/runner/runner_update_form_utils';
+
+const mockId = 'gid://gitlab/Ci::Runner/1';
+const mockDescription = 'Runner Desc.';
+
+const mockRunner = {
+ id: mockId,
+ description: mockDescription,
+ maximumTimeout: 100,
+ accessLevel: ACCESS_LEVEL_NOT_PROTECTED,
+ active: true,
+ locked: true,
+ runUntagged: true,
+ tagList: ['tag-1', 'tag-2'],
+};
+
+const mockModel = {
+ ...mockRunner,
+ tagList: 'tag-1, tag-2',
+};
+
+describe('~/ci/runner/runner_update_form_utils', () => {
+ describe('runnerToModel', () => {
+ it('collects all model data', () => {
+ expect(runnerToModel(mockRunner)).toEqual(mockModel);
+ });
+
+ it('does not collect other data', () => {
+ const model = runnerToModel({
+ ...mockRunner,
+ unrelated: 'unrelatedValue',
+ });
+
+ expect(model.unrelated).toEqual(undefined);
+ });
+
+ it('tag list defaults to an empty string', () => {
+ const model = runnerToModel({
+ ...mockRunner,
+ tagList: undefined,
+ });
+
+ expect(model.tagList).toEqual('');
+ });
+ });
+
+ describe('modelToUpdateMutationVariables', () => {
+ it('collects all model data', () => {
+ expect(modelToUpdateMutationVariables(mockModel)).toEqual({
+ input: {
+ ...mockRunner,
+ },
+ });
+ });
+
+ it('collects a nullable timeout from the model', () => {
+ const variables = modelToUpdateMutationVariables({
+ ...mockModel,
+ maximumTimeout: '',
+ });
+
+ expect(variables).toEqual({
+ input: {
+ ...mockRunner,
+ maximumTimeout: null,
+ },
+ });
+ });
+
+ it.each`
+ tagList | tagListInput
+ ${''} | ${[]}
+ ${'tag1, tag2'} | ${['tag1', 'tag2']}
+ ${'with spaces'} | ${['with spaces']}
+ ${',,,,, commas'} | ${['commas']}
+ ${'more ,,,,, commas'} | ${['more', 'commas']}
+ ${' trimmed , trimmed2 '} | ${['trimmed', 'trimmed2']}
+ `('collect tags separated by commas for "$value"', ({ tagList, tagListInput }) => {
+ const variables = modelToUpdateMutationVariables({
+ ...mockModel,
+ tagList,
+ });
+
+ expect(variables).toEqual({
+ input: {
+ ...mockRunner,
+ tagList: tagListInput,
+ },
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/sentry_utils_spec.js b/spec/frontend/ci/runner/sentry_utils_spec.js
new file mode 100644
index 00000000000..f7b689272ce
--- /dev/null
+++ b/spec/frontend/ci/runner/sentry_utils_spec.js
@@ -0,0 +1,39 @@
+import * as Sentry from '@sentry/browser';
+import { captureException } from '~/ci/runner/sentry_utils';
+
+jest.mock('@sentry/browser');
+
+describe('~/ci/runner/sentry_utils', () => {
+ let mockSetTag;
+
+ beforeEach(async () => {
+ mockSetTag = jest.fn();
+
+ Sentry.withScope.mockImplementation((fn) => {
+ const scope = { setTag: mockSetTag };
+ fn(scope);
+ });
+ });
+
+ describe('captureException', () => {
+ const mockError = new Error('Something went wrong!');
+
+ it('error is reported to sentry', () => {
+ captureException({ error: mockError });
+
+ expect(Sentry.withScope).toHaveBeenCalled();
+ expect(Sentry.captureException).toHaveBeenCalledWith(mockError);
+ });
+
+ it('error is reported to sentry with a component name', () => {
+ const mockComponentName = 'MyComponent';
+
+ captureException({ error: mockError, component: mockComponentName });
+
+ expect(Sentry.withScope).toHaveBeenCalled();
+ expect(Sentry.captureException).toHaveBeenCalledWith(mockError);
+
+ expect(mockSetTag).toHaveBeenCalledWith('vue_component', mockComponentName);
+ });
+ });
+});
diff --git a/spec/frontend/ci/runner/utils_spec.js b/spec/frontend/ci/runner/utils_spec.js
new file mode 100644
index 00000000000..56b758f00e4
--- /dev/null
+++ b/spec/frontend/ci/runner/utils_spec.js
@@ -0,0 +1,85 @@
+import {
+ formatJobCount,
+ tableField,
+ getPaginationVariables,
+ parseInterval,
+} from '~/ci/runner/utils';
+
+describe('~/ci/runner/utils', () => {
+ describe('formatJobCount', () => {
+ it('formats a number', () => {
+ expect(formatJobCount(1)).toBe('1');
+ expect(formatJobCount(99)).toBe('99');
+ });
+
+ it('formats a large count', () => {
+ expect(formatJobCount(1000)).toBe('1,000');
+ expect(formatJobCount(1001)).toBe('1,000+');
+ });
+
+ it('returns an empty string for non-numeric values', () => {
+ expect(formatJobCount(undefined)).toBe('');
+ expect(formatJobCount(null)).toBe('');
+ expect(formatJobCount('number')).toBe('');
+ });
+ });
+
+ describe('tableField', () => {
+ it('a field with options', () => {
+ expect(tableField({ key: 'name' })).toEqual({
+ key: 'name',
+ label: '',
+ tdAttr: { 'data-testid': 'td-name' },
+ thClass: expect.any(Array),
+ });
+ });
+
+ it('a field with a label', () => {
+ const label = 'A field name';
+
+ expect(tableField({ key: 'name', label })).toMatchObject({
+ label,
+ });
+ });
+
+ it('a field with custom classes', () => {
+ const mockClasses = ['foo', 'bar'];
+
+ expect(tableField({ thClasses: mockClasses })).toMatchObject({
+ thClass: expect.arrayContaining(mockClasses),
+ });
+ });
+
+ it('a field with custom options', () => {
+ expect(tableField({ foo: 'bar' })).toMatchObject({ foo: 'bar' });
+ });
+ });
+
+ describe('getPaginationVariables', () => {
+ const after = 'AFTER_CURSOR';
+ const before = 'BEFORE_CURSOR';
+
+ it.each`
+ case | pagination | pageSize | variables
+ ${'next page'} | ${{ after }} | ${undefined} | ${{ after, first: 10 }}
+ ${'prev page'} | ${{ before }} | ${undefined} | ${{ before, last: 10 }}
+ ${'first page'} | ${{}} | ${undefined} | ${{ first: 10 }}
+ ${'next page with N items'} | ${{ after }} | ${20} | ${{ after, first: 20 }}
+ ${'prev page with N items'} | ${{ before }} | ${20} | ${{ before, last: 20 }}
+ ${'first page with N items'} | ${{}} | ${20} | ${{ first: 20 }}
+ `('navigates to $case', ({ pagination, pageSize, variables }) => {
+ expect(getPaginationVariables(pagination, pageSize)).toEqual(variables);
+ });
+ });
+
+ describe('parseInterval', () => {
+ it.each`
+ case | argument | returnValue
+ ${'parses integer'} | ${'86400'} | ${86400}
+ ${'returns null for undefined'} | ${undefined} | ${null}
+ ${'returns null for null'} | ${null} | ${null}
+ `('$case', ({ argument, returnValue }) => {
+ expect(parseInterval(argument)).toStrictEqual(returnValue);
+ });
+ });
+});
diff --git a/spec/frontend/ci_variable_list/components/ci_admin_variables_spec.js b/spec/frontend/ci_variable_list/components/ci_admin_variables_spec.js
index 864041141b8..c7375acd8e5 100644
--- a/spec/frontend/ci_variable_list/components/ci_admin_variables_spec.js
+++ b/spec/frontend/ci_variable_list/components/ci_admin_variables_spec.js
@@ -1,178 +1,35 @@
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
-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 { resolvers } from '~/ci_variable_list/graphql/settings';
import ciAdminVariables from '~/ci_variable_list/components/ci_admin_variables.vue';
-import ciVariableSettings from '~/ci_variable_list/components/ci_variable_settings.vue';
-import ciVariableTable from '~/ci_variable_list/components/ci_variable_table.vue';
-import getAdminVariables from '~/ci_variable_list/graphql/queries/variables.query.graphql';
+import ciVariableShared from '~/ci_variable_list/components/ci_variable_shared.vue';
-import addAdminVariable from '~/ci_variable_list/graphql/mutations/admin_add_variable.mutation.graphql';
-import deleteAdminVariable from '~/ci_variable_list/graphql/mutations/admin_delete_variable.mutation.graphql';
-import updateAdminVariable from '~/ci_variable_list/graphql/mutations/admin_update_variable.mutation.graphql';
-
-import { genericMutationErrorText, variableFetchErrorText } from '~/ci_variable_list/constants';
-
-import { mockAdminVariables, newVariable } from '../mocks';
-
-jest.mock('~/flash');
-
-Vue.use(VueApollo);
-
-const mockProvide = {
- endpoint: '/variables',
-};
-
-describe('Ci Admin Variable list', () => {
+describe('Ci Project Variable wrapper', () => {
let wrapper;
- let mockApollo;
- let mockVariables;
-
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findCiTable = () => wrapper.findComponent(GlTable);
- const findCiSettings = () => wrapper.findComponent(ciVariableSettings);
-
- // eslint-disable-next-line consistent-return
- const createComponentWithApollo = async ({ isLoading = false } = {}) => {
- const handlers = [[getAdminVariables, mockVariables]];
-
- mockApollo = createMockApollo(handlers, resolvers);
+ const findCiShared = () => wrapper.findComponent(ciVariableShared);
- wrapper = shallowMount(ciAdminVariables, {
- provide: mockProvide,
- apolloProvider: mockApollo,
- stubs: { ciVariableSettings, ciVariableTable },
- });
-
- if (!isLoading) {
- return waitForPromises();
- }
+ const createComponent = () => {
+ wrapper = shallowMount(ciAdminVariables);
};
beforeEach(() => {
- mockVariables = jest.fn();
+ createComponent();
});
afterEach(() => {
wrapper.destroy();
});
- 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);
+ it('Passes down the correct props to ci_variable_shared', () => {
+ expect(findCiShared().props()).toEqual({
+ areScopedVariablesAvailable: false,
+ componentName: 'InstanceVariables',
+ hideEnvironmentScope: true,
+ mutationData: wrapper.vm.$options.mutationData,
+ queryData: wrapper.vm.$options.queryData,
+ refetchAfterMutation: true,
+ fullPath: null,
+ id: null,
});
});
-
- describe('when queries are resolved', () => {
- describe('successfuly', () => {
- beforeEach(async () => {
- mockVariables.mockResolvedValue(mockAdminVariables);
-
- await createComponentWithApollo();
- });
-
- it('passes down the expected environments as props', () => {
- expect(findCiSettings().props('environments')).toEqual([]);
- });
-
- it('passes down the expected variables as props', () => {
- expect(findCiSettings().props('variables')).toEqual(
- mockAdminVariables.data.ciVariables.nodes,
- );
- });
-
- it('createAlert was not called', () => {
- expect(createAlert).not.toHaveBeenCalled();
- });
- });
-
- describe('with an error for variables', () => {
- beforeEach(async () => {
- mockVariables.mockRejectedValue();
-
- await createComponentWithApollo();
- });
-
- it('calls createAlert with the expected error message', () => {
- expect(createAlert).toHaveBeenCalledWith({ message: variableFetchErrorText });
- });
- });
- });
-
- describe('mutations', () => {
- beforeEach(async () => {
- mockVariables.mockResolvedValue(mockAdminVariables);
-
- await createComponentWithApollo();
- });
- it.each`
- actionName | mutation | event
- ${'add'} | ${addAdminVariable} | ${'add-variable'}
- ${'update'} | ${updateAdminVariable} | ${'update-variable'}
- ${'delete'} | ${deleteAdminVariable} | ${'delete-variable'}
- `(
- 'calls the right mutation 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,
- variable: newVariable,
- },
- });
- },
- );
-
- it.each`
- actionName | event | mutationName
- ${'add'} | ${'add-variable'} | ${'addAdminVariable'}
- ${'update'} | ${'update-variable'} | ${'updateAdminVariable'}
- ${'delete'} | ${'delete-variable'} | ${'deleteAdminVariable'}
- `(
- 'throws with the specific graphql error if present when user performs $actionName variable',
- async ({ event, mutationName }) => {
- const graphQLErrorMessage = 'There is a problem with this graphQL action';
- jest
- .spyOn(wrapper.vm.$apollo, 'mutate')
- .mockResolvedValue({ data: { [mutationName]: { 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 when the mutation fails 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 });
- },
- );
- });
});
diff --git a/spec/frontend/ci_variable_list/components/ci_group_variables_spec.js b/spec/frontend/ci_variable_list/components/ci_group_variables_spec.js
index 8a48e73eb9f..ef5a86ccb61 100644
--- a/spec/frontend/ci_variable_list/components/ci_group_variables_spec.js
+++ b/spec/frontend/ci_variable_list/components/ci_group_variables_spec.js
@@ -1,183 +1,72 @@
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
-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 { resolvers } from '~/ci_variable_list/graphql/settings';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import ciGroupVariables from '~/ci_variable_list/components/ci_group_variables.vue';
-import ciVariableSettings from '~/ci_variable_list/components/ci_variable_settings.vue';
-import ciVariableTable from '~/ci_variable_list/components/ci_variable_table.vue';
-import getGroupVariables from '~/ci_variable_list/graphql/queries/group_variables.query.graphql';
+import ciVariableShared from '~/ci_variable_list/components/ci_variable_shared.vue';
-import addGroupVariable from '~/ci_variable_list/graphql/mutations/group_add_variable.mutation.graphql';
-import deleteGroupVariable from '~/ci_variable_list/graphql/mutations/group_delete_variable.mutation.graphql';
-import updateGroupVariable from '~/ci_variable_list/graphql/mutations/group_update_variable.mutation.graphql';
-
-import { genericMutationErrorText, variableFetchErrorText } from '~/ci_variable_list/constants';
-
-import { mockGroupVariables, newVariable } from '../mocks';
-
-jest.mock('~/flash');
-
-Vue.use(VueApollo);
+import { GRAPHQL_GROUP_TYPE } from '~/ci_variable_list/constants';
const mockProvide = {
- endpoint: '/variables',
- groupPath: '/namespace/group',
- groupId: 1,
+ glFeatures: {
+ groupScopedCiVariables: false,
+ },
+ groupPath: '/group',
+ groupId: 12,
};
-describe('Ci Group Variable list', () => {
+describe('Ci Group Variable wrapper', () => {
let wrapper;
- let mockApollo;
- let mockVariables;
-
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findCiTable = () => wrapper.findComponent(GlTable);
- const findCiSettings = () => wrapper.findComponent(ciVariableSettings);
-
- // eslint-disable-next-line consistent-return
- const createComponentWithApollo = async ({ isLoading = false } = {}) => {
- const handlers = [[getGroupVariables, mockVariables]];
-
- mockApollo = createMockApollo(handlers, resolvers);
+ const findCiShared = () => wrapper.findComponent(ciVariableShared);
+ const createComponent = ({ provide = {} } = {}) => {
wrapper = shallowMount(ciGroupVariables, {
- provide: mockProvide,
- apolloProvider: mockApollo,
- stubs: { ciVariableSettings, ciVariableTable },
+ provide: { ...mockProvide, ...provide },
});
-
- if (!isLoading) {
- return waitForPromises();
- }
};
- beforeEach(() => {
- mockVariables = jest.fn();
- });
-
afterEach(() => {
wrapper.destroy();
});
- describe('while queries are being fetch', () => {
+ describe('Props', () => {
beforeEach(() => {
- createComponentWithApollo({ isLoading: true });
+ createComponent();
});
- it('shows a loading icon', () => {
- expect(findLoadingIcon().exists()).toBe(true);
- expect(findCiTable().exists()).toBe(false);
+ it('are passed down the correctly to ci_variable_shared', () => {
+ expect(findCiShared().props()).toEqual({
+ id: convertToGraphQLId(GRAPHQL_GROUP_TYPE, mockProvide.groupId),
+ areScopedVariablesAvailable: false,
+ componentName: 'GroupVariables',
+ fullPath: mockProvide.groupPath,
+ hideEnvironmentScope: false,
+ mutationData: wrapper.vm.$options.mutationData,
+ queryData: wrapper.vm.$options.queryData,
+ refetchAfterMutation: false,
+ });
});
});
- describe('when queries are resolved', () => {
- describe('successfuly', () => {
- beforeEach(async () => {
- mockVariables.mockResolvedValue(mockGroupVariables);
-
- await createComponentWithApollo();
- });
-
- it('passes down the expected environments as props', () => {
- expect(findCiSettings().props('environments')).toEqual([]);
- });
-
- it('passes down the expected variables as props', () => {
- expect(findCiSettings().props('variables')).toEqual(
- mockGroupVariables.data.group.ciVariables.nodes,
- );
+ describe('feature flag', () => {
+ describe('When enabled', () => {
+ beforeEach(() => {
+ createComponent({ provide: { glFeatures: { groupScopedCiVariables: true } } });
});
- it('createAlert was not called', () => {
- expect(createAlert).not.toHaveBeenCalled();
+ it('Passes down `true` to variable shared component', () => {
+ expect(findCiShared().props('areScopedVariablesAvailable')).toBe(true);
});
});
- describe('with an error for variables', () => {
- beforeEach(async () => {
- mockVariables.mockRejectedValue();
-
- await createComponentWithApollo();
+ describe('When disabled', () => {
+ beforeEach(() => {
+ createComponent({ provide: { glFeatures: { groupScopedCiVariables: false } } });
});
- it('calls createAlert with the expected error message', () => {
- expect(createAlert).toHaveBeenCalledWith({ message: variableFetchErrorText });
+ it('Passes down `false` to variable shared component', () => {
+ expect(findCiShared().props('areScopedVariablesAvailable')).toBe(false);
});
});
});
-
- describe('mutations', () => {
- beforeEach(async () => {
- mockVariables.mockResolvedValue(mockGroupVariables);
-
- await createComponentWithApollo();
- });
- it.each`
- actionName | mutation | event
- ${'add'} | ${addGroupVariable} | ${'add-variable'}
- ${'update'} | ${updateGroupVariable} | ${'update-variable'}
- ${'delete'} | ${deleteGroupVariable} | ${'delete-variable'}
- `(
- 'calls the right mutation 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: mockProvide.groupPath,
- groupId: convertToGraphQLId('Group', mockProvide.groupId),
- variable: newVariable,
- },
- });
- },
- );
-
- it.each`
- actionName | event | mutationName
- ${'add'} | ${'add-variable'} | ${'addGroupVariable'}
- ${'update'} | ${'update-variable'} | ${'updateGroupVariable'}
- ${'delete'} | ${'delete-variable'} | ${'deleteGroupVariable'}
- `(
- 'throws with the specific graphql error if present when user performs $actionName variable',
- async ({ event, mutationName }) => {
- const graphQLErrorMessage = 'There is a problem with this graphQL action';
- jest
- .spyOn(wrapper.vm.$apollo, 'mutate')
- .mockResolvedValue({ data: { [mutationName]: { 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 when the mutation fails 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 });
- },
- );
- });
});
diff --git a/spec/frontend/ci_variable_list/components/ci_project_variables_spec.js b/spec/frontend/ci_variable_list/components/ci_project_variables_spec.js
index c630278fbde..97051325f59 100644
--- a/spec/frontend/ci_variable_list/components/ci_project_variables_spec.js
+++ b/spec/frontend/ci_variable_list/components/ci_project_variables_spec.js
@@ -1,215 +1,45 @@
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
-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 { resolvers } from '~/ci_variable_list/graphql/settings';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import ciProjectVariables from '~/ci_variable_list/components/ci_project_variables.vue';
-import ciVariableSettings from '~/ci_variable_list/components/ci_variable_settings.vue';
-import ciVariableTable from '~/ci_variable_list/components/ci_variable_table.vue';
-import getProjectEnvironments from '~/ci_variable_list/graphql/queries/project_environments.query.graphql';
-import getProjectVariables from '~/ci_variable_list/graphql/queries/project_variables.query.graphql';
+import ciVariableShared from '~/ci_variable_list/components/ci_variable_shared.vue';
-import addProjectVariable from '~/ci_variable_list/graphql/mutations/project_add_variable.mutation.graphql';
-import deleteProjectVariable from '~/ci_variable_list/graphql/mutations/project_delete_variable.mutation.graphql';
-import updateProjectVariable from '~/ci_variable_list/graphql/mutations/project_update_variable.mutation.graphql';
-
-import {
- environmentFetchErrorText,
- genericMutationErrorText,
- variableFetchErrorText,
-} from '~/ci_variable_list/constants';
-
-import {
- devName,
- mockProjectEnvironments,
- mockProjectVariables,
- newVariable,
- prodName,
-} from '../mocks';
-
-jest.mock('~/flash');
-
-Vue.use(VueApollo);
+import { GRAPHQL_PROJECT_TYPE } from '~/ci_variable_list/constants';
const mockProvide = {
- endpoint: '/variables',
projectFullPath: '/namespace/project',
projectId: 1,
};
-describe('Ci Project Variable list', () => {
+describe('Ci Project Variable wrapper', () => {
let wrapper;
- let mockApollo;
- let mockEnvironments;
- let mockVariables;
-
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findCiTable = () => wrapper.findComponent(GlTable);
- const findCiSettings = () => wrapper.findComponent(ciVariableSettings);
-
- // eslint-disable-next-line consistent-return
- const createComponentWithApollo = async ({ isLoading = false } = {}) => {
- const handlers = [
- [getProjectEnvironments, mockEnvironments],
- [getProjectVariables, mockVariables],
- ];
-
- mockApollo = createMockApollo(handlers, resolvers);
+ const findCiShared = () => wrapper.findComponent(ciVariableShared);
+ const createComponent = () => {
wrapper = shallowMount(ciProjectVariables, {
provide: mockProvide,
- apolloProvider: mockApollo,
- stubs: { ciVariableSettings, ciVariableTable },
});
-
- if (!isLoading) {
- return waitForPromises();
- }
};
beforeEach(() => {
- mockEnvironments = jest.fn();
- mockVariables = jest.fn();
+ createComponent();
});
afterEach(() => {
wrapper.destroy();
});
- 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('successfuly', () => {
- beforeEach(async () => {
- mockEnvironments.mockResolvedValue(mockProjectEnvironments);
- mockVariables.mockResolvedValue(mockProjectVariables);
-
- await createComponentWithApollo();
- });
-
- it('passes down the expected environments as props', () => {
- expect(findCiSettings().props('environments')).toEqual([prodName, devName]);
- });
-
- it('passes down the expected variables as props', () => {
- expect(findCiSettings().props('variables')).toEqual(
- mockProjectVariables.data.project.ciVariables.nodes,
- );
- });
-
- it('createAlert was not called', () => {
- expect(createAlert).not.toHaveBeenCalled();
- });
- });
-
- describe('with an error for variables', () => {
- beforeEach(async () => {
- mockEnvironments.mockResolvedValue(mockProjectEnvironments);
- mockVariables.mockRejectedValue();
-
- await createComponentWithApollo();
- });
-
- it('calls createAlert with the expected error message', () => {
- expect(createAlert).toHaveBeenCalledWith({ message: variableFetchErrorText });
- });
- });
-
- describe('with an error for environments', () => {
- beforeEach(async () => {
- mockEnvironments.mockRejectedValue();
- mockVariables.mockResolvedValue(mockProjectVariables);
-
- await createComponentWithApollo();
- });
-
- it('calls createAlert with the expected error message', () => {
- expect(createAlert).toHaveBeenCalledWith({ message: environmentFetchErrorText });
- });
- });
- });
-
- describe('mutations', () => {
- beforeEach(async () => {
- mockEnvironments.mockResolvedValue(mockProjectEnvironments);
- mockVariables.mockResolvedValue(mockProjectVariables);
-
- await createComponentWithApollo();
+ it('Passes down the correct props to ci_variable_shared', () => {
+ expect(findCiShared().props()).toEqual({
+ id: convertToGraphQLId(GRAPHQL_PROJECT_TYPE, mockProvide.projectId),
+ areScopedVariablesAvailable: true,
+ componentName: 'ProjectVariables',
+ fullPath: mockProvide.projectFullPath,
+ hideEnvironmentScope: false,
+ mutationData: wrapper.vm.$options.mutationData,
+ queryData: wrapper.vm.$options.queryData,
+ refetchAfterMutation: false,
});
- it.each`
- actionName | mutation | event
- ${'add'} | ${addProjectVariable} | ${'add-variable'}
- ${'update'} | ${updateProjectVariable} | ${'update-variable'}
- ${'delete'} | ${deleteProjectVariable} | ${'delete-variable'}
- `(
- 'calls the right mutation 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: mockProvide.projectFullPath,
- projectId: convertToGraphQLId('Project', mockProvide.projectId),
- variable: newVariable,
- },
- });
- },
- );
-
- it.each`
- actionName | event | mutationName
- ${'add'} | ${'add-variable'} | ${'addProjectVariable'}
- ${'update'} | ${'update-variable'} | ${'updateProjectVariable'}
- ${'delete'} | ${'delete-variable'} | ${'deleteProjectVariable'}
- `(
- 'throws with the specific graphql error if present when user performs $actionName variable',
- async ({ event, mutationName }) => {
- const graphQLErrorMessage = 'There is a problem with this graphQL action';
- jest
- .spyOn(wrapper.vm.$apollo, 'mutate')
- .mockResolvedValue({ data: { [mutationName]: { 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 when the mutation fails 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 });
- },
- );
});
});
diff --git a/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js b/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js
index 1ea4e4f833b..e4771f040d1 100644
--- a/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js
+++ b/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js
@@ -39,6 +39,7 @@ describe('Ci variable modal', () => {
const defaultProps = {
areScopedVariablesAvailable: true,
environments: [],
+ hideEnvironmentScope: false,
mode: ADD_VARIABLE_ACTION,
selectedVariable: {},
variable: [],
@@ -75,6 +76,7 @@ describe('Ci variable modal', () => {
const findEnvScopeInput = () =>
wrapper.findByTestId('environment-scope').findComponent(GlFormInput);
const findVariableTypeDropdown = () => wrapper.find('#ci-variable-type');
+ const findEnvironmentScopeText = () => wrapper.findByText('Environment scope');
afterEach(() => {
wrapper.destroy();
@@ -250,39 +252,83 @@ describe('Ci variable modal', () => {
describe('Environment scope', () => {
describe('when feature is available', () => {
- it('renders the environment dropdown', () => {
- createComponent({
- mountFn: mountExtended,
- props: {
- areScopedVariablesAvailable: true,
- },
+ describe('and section is not hidden', () => {
+ beforeEach(() => {
+ createComponent({
+ mountFn: mountExtended,
+ props: {
+ areScopedVariablesAvailable: true,
+ hideEnvironmentScope: false,
+ },
+ });
});
- expect(findCiEnvironmentsDropdown().exists()).toBe(true);
- expect(findCiEnvironmentsDropdown().isVisible()).toBe(true);
- });
+ it('renders the environment dropdown and section title', () => {
+ expect(findCiEnvironmentsDropdown().exists()).toBe(true);
+ expect(findCiEnvironmentsDropdown().isVisible()).toBe(true);
+ expect(findEnvironmentScopeText().exists()).toBe(true);
+ });
- it('renders a link to documentation on scopes', () => {
- createComponent({ mountFn: mountExtended });
+ it('renders a link to documentation on scopes', () => {
+ const link = findEnvScopeLink();
+
+ expect(link.attributes('title')).toBe(ENVIRONMENT_SCOPE_LINK_TITLE);
+ expect(link.attributes('href')).toBe(defaultProvide.environmentScopeLink);
+ });
+ });
- const link = findEnvScopeLink();
+ describe('and section is hidden', () => {
+ beforeEach(() => {
+ createComponent({
+ mountFn: mountExtended,
+ props: {
+ areScopedVariablesAvailable: true,
+ hideEnvironmentScope: true,
+ },
+ });
+ });
- expect(link.attributes('title')).toBe(ENVIRONMENT_SCOPE_LINK_TITLE);
- expect(link.attributes('href')).toBe(defaultProvide.environmentScopeLink);
+ it('does not renders the environment dropdown and section title', () => {
+ expect(findCiEnvironmentsDropdown().exists()).toBe(false);
+ expect(findEnvironmentScopeText().exists()).toBe(false);
+ });
});
});
describe('when feature is not available', () => {
- it('disables the dropdown', () => {
- createComponent({
- mountFn: mountExtended,
- props: {
- areScopedVariablesAvailable: false,
- },
+ describe('and section is not hidden', () => {
+ beforeEach(() => {
+ createComponent({
+ mountFn: mountExtended,
+ props: {
+ areScopedVariablesAvailable: false,
+ hideEnvironmentScope: false,
+ },
+ });
});
- expect(findCiEnvironmentsDropdown().exists()).toBe(false);
- expect(findEnvScopeInput().attributes('readonly')).toBe('readonly');
+ it('disables the dropdown', () => {
+ expect(findCiEnvironmentsDropdown().exists()).toBe(false);
+ expect(findEnvironmentScopeText().exists()).toBe(true);
+ expect(findEnvScopeInput().attributes('readonly')).toBe('readonly');
+ });
+ });
+
+ describe('and section is hidden', () => {
+ beforeEach(() => {
+ createComponent({
+ mountFn: mountExtended,
+ props: {
+ areScopedVariablesAvailable: false,
+ hideEnvironmentScope: true,
+ },
+ });
+ });
+
+ it('hides the dropdown', () => {
+ expect(findEnvironmentScopeText().exists()).toBe(false);
+ expect(findCiEnvironmentsDropdown().exists()).toBe(false);
+ });
});
});
});
diff --git a/spec/frontend/ci_variable_list/components/ci_variable_popover_spec.js b/spec/frontend/ci_variable_list/components/ci_variable_popover_spec.js
deleted file mode 100644
index 4d0c378d10e..00000000000
--- a/spec/frontend/ci_variable_list/components/ci_variable_popover_spec.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import { GlButton } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import CiVariablePopover from '~/ci_variable_list/components/ci_variable_popover.vue';
-import mockData from '../services/mock_data';
-
-describe('Ci Variable Popover', () => {
- let wrapper;
-
- const defaultProps = {
- target: 'ci-variable-value-22',
- value: mockData.mockPemCert,
- tooltipText: 'Copy value',
- };
-
- const createComponent = (props = defaultProps) => {
- wrapper = shallowMount(CiVariablePopover, {
- propsData: { ...props },
- });
- };
-
- const findButton = () => wrapper.findComponent(GlButton);
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- it('displays max count plus ... when character count is over 95', () => {
- expect(wrapper.text()).toHaveLength(98);
- });
-
- it('copies full value to clipboard', () => {
- expect(findButton().attributes('data-clipboard-text')).toEqual(mockData.mockPemCert);
- });
-
- it('displays full value when count is less than max count', () => {
- createComponent({
- target: 'ci-variable-value-22',
- value: 'test_variable_value',
- tooltipText: 'Copy value',
- });
- expect(wrapper.text()).toEqual('test_variable_value');
- });
-});
diff --git a/spec/frontend/ci_variable_list/components/ci_variable_settings_spec.js b/spec/frontend/ci_variable_list/components/ci_variable_settings_spec.js
index 5c77ce71b41..8b5a0f7ae9d 100644
--- a/spec/frontend/ci_variable_list/components/ci_variable_settings_spec.js
+++ b/spec/frontend/ci_variable_list/components/ci_variable_settings_spec.js
@@ -18,6 +18,7 @@ describe('Ci variable table', () => {
const defaultProps = {
areScopedVariablesAvailable: true,
environments: mapEnvironmentNames(mockEnvs),
+ hideEnvironmentScope: false,
isLoading: false,
variables: mockVariablesWithScopes(projectString),
};
@@ -56,6 +57,7 @@ describe('Ci variable table', () => {
expect(findCiVariableModal().props()).toEqual({
areScopedVariablesAvailable: defaultProps.areScopedVariablesAvailable,
environments: defaultProps.environments,
+ hideEnvironmentScope: defaultProps.hideEnvironmentScope,
variables: defaultProps.variables,
mode: ADD_VARIABLE_ACTION,
selectedVariable: {},
diff --git a/spec/frontend/ci_variable_list/components/ci_variable_shared_spec.js b/spec/frontend/ci_variable_list/components/ci_variable_shared_spec.js
new file mode 100644
index 00000000000..0cc0ee7a9c7
--- /dev/null
+++ b/spec/frontend/ci_variable_list/components/ci_variable_shared_spec.js
@@ -0,0 +1,428 @@
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+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 { resolvers } from '~/ci_variable_list/graphql/settings';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+
+import ciVariableShared from '~/ci_variable_list/components/ci_variable_shared.vue';
+import ciVariableSettings from '~/ci_variable_list/components/ci_variable_settings.vue';
+import ciVariableTable from '~/ci_variable_list/components/ci_variable_table.vue';
+import getProjectEnvironments from '~/ci_variable_list/graphql/queries/project_environments.query.graphql';
+import getAdminVariables from '~/ci_variable_list/graphql/queries/variables.query.graphql';
+import getGroupVariables from '~/ci_variable_list/graphql/queries/group_variables.query.graphql';
+import getProjectVariables from '~/ci_variable_list/graphql/queries/project_variables.query.graphql';
+
+import {
+ ADD_MUTATION_ACTION,
+ DELETE_MUTATION_ACTION,
+ UPDATE_MUTATION_ACTION,
+ environmentFetchErrorText,
+ genericMutationErrorText,
+ variableFetchErrorText,
+} from '~/ci_variable_list/constants';
+
+import {
+ createGroupProps,
+ createInstanceProps,
+ createProjectProps,
+ devName,
+ mockProjectEnvironments,
+ mockProjectVariables,
+ newVariable,
+ prodName,
+ mockGroupVariables,
+ mockAdminVariables,
+} from '../mocks';
+
+jest.mock('~/flash');
+
+Vue.use(VueApollo);
+
+const mockProvide = {
+ endpoint: '/variables',
+};
+
+const defaultProps = {
+ areScopedVariablesAvailable: true,
+ hideEnvironmentScope: false,
+ refetchAfterMutation: false,
+};
+
+describe('Ci Variable Shared Component', () => {
+ let wrapper;
+
+ let mockApollo;
+ let mockEnvironments;
+ let mockVariables;
+
+ const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
+ const findCiTable = () => wrapper.findComponent(GlTable);
+ const findCiSettings = () => wrapper.findComponent(ciVariableSettings);
+
+ // eslint-disable-next-line consistent-return
+ async function createComponentWithApollo({
+ customHandlers = null,
+ isLoading = false,
+ props = { ...createProjectProps() },
+ } = {}) {
+ const handlers = customHandlers || [
+ [getProjectEnvironments, mockEnvironments],
+ [getProjectVariables, mockVariables],
+ ];
+
+ mockApollo = createMockApollo(handlers, resolvers);
+
+ wrapper = shallowMount(ciVariableShared, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ provide: mockProvide,
+ apolloProvider: mockApollo,
+ stubs: { ciVariableSettings, ciVariableTable },
+ });
+
+ if (!isLoading) {
+ return waitForPromises();
+ }
+ }
+
+ beforeEach(() => {
+ mockEnvironments = jest.fn();
+ 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('successfuly', () => {
+ beforeEach(async () => {
+ mockEnvironments.mockResolvedValue(mockProjectEnvironments);
+ mockVariables.mockResolvedValue(mockProjectVariables);
+
+ await createComponentWithApollo();
+ });
+
+ it('passes down the expected environments as props', () => {
+ expect(findCiSettings().props('environments')).toEqual([prodName, devName]);
+ });
+
+ it('passes down the expected variables as props', () => {
+ expect(findCiSettings().props('variables')).toEqual(
+ mockProjectVariables.data.project.ciVariables.nodes,
+ );
+ });
+
+ it('createAlert was not called', () => {
+ expect(createAlert).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('with an error for variables', () => {
+ beforeEach(async () => {
+ mockEnvironments.mockResolvedValue(mockProjectEnvironments);
+ mockVariables.mockRejectedValue();
+
+ await createComponentWithApollo();
+ });
+
+ it('calls createAlert with the expected error message', () => {
+ expect(createAlert).toHaveBeenCalledWith({ message: variableFetchErrorText });
+ });
+ });
+
+ describe('with an error for environments', () => {
+ beforeEach(async () => {
+ mockEnvironments.mockRejectedValue();
+ mockVariables.mockResolvedValue(mockProjectVariables);
+
+ await createComponentWithApollo();
+ });
+
+ it('calls createAlert with the expected error message', () => {
+ expect(createAlert).toHaveBeenCalledWith({ message: environmentFetchErrorText });
+ });
+ });
+ });
+
+ describe('environment query', () => {
+ describe('when there is an environment key in queryData', () => {
+ beforeEach(async () => {
+ mockEnvironments.mockResolvedValue(mockProjectEnvironments);
+ mockVariables.mockResolvedValue(mockProjectVariables);
+
+ await createComponentWithApollo({ props: { ...createProjectProps() } });
+ });
+
+ it('is executed', () => {
+ expect(mockVariables).toHaveBeenCalled();
+ });
+ });
+
+ describe('when there isnt an environment key in queryData', () => {
+ beforeEach(async () => {
+ mockVariables.mockResolvedValue(mockGroupVariables);
+
+ await createComponentWithApollo({ props: { ...createGroupProps() } });
+ });
+
+ it('is skipped', () => {
+ expect(mockVariables).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('mutations', () => {
+ const groupProps = createGroupProps();
+
+ beforeEach(async () => {
+ mockVariables.mockResolvedValue(mockGroupVariables);
+
+ await createComponentWithApollo({
+ customHandlers: [[getGroupVariables, mockVariables]],
+ props: groupProps,
+ });
+ });
+ 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('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('without fullpath and ID props', () => {
+ beforeEach(async () => {
+ mockVariables.mockResolvedValue(mockAdminVariables);
+
+ await createComponentWithApollo({
+ customHandlers: [[getAdminVariables, mockVariables]],
+ props: createInstanceProps(),
+ });
+ });
+
+ 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', () => {
+ describe('in a specific context as', () => {
+ it.each`
+ name | mockVariablesValue | mockEnvironmentsValue | withEnvironments | expectedEnvironments | propsFn | mutation
+ ${'project'} | ${mockProjectVariables} | ${mockProjectEnvironments} | ${true} | ${['prod', 'dev']} | ${createProjectProps} | ${null}
+ ${'group'} | ${mockGroupVariables} | ${[]} | ${false} | ${[]} | ${createGroupProps} | ${getGroupVariables}
+ ${'instance'} | ${mockAdminVariables} | ${[]} | ${false} | ${[]} | ${createInstanceProps} | ${getAdminVariables}
+ `(
+ 'passes down all the required props when its a $name component',
+ async ({
+ mutation,
+ mockVariablesValue,
+ mockEnvironmentsValue,
+ withEnvironments,
+ expectedEnvironments,
+ propsFn,
+ }) => {
+ const props = propsFn();
+
+ mockVariables.mockResolvedValue(mockVariablesValue);
+
+ if (withEnvironments) {
+ mockEnvironments.mockResolvedValue(mockEnvironmentsValue);
+ }
+
+ let customHandlers = null;
+
+ if (mutation) {
+ customHandlers = [[mutation, mockVariables]];
+ }
+
+ await createComponentWithApollo({ customHandlers, props });
+
+ expect(findCiSettings().props()).toEqual({
+ areScopedVariablesAvailable: wrapper.props().areScopedVariablesAvailable,
+ hideEnvironmentScope: defaultProps.hideEnvironmentScope,
+ isLoading: false,
+ variables: wrapper.props().queryData.ciVariables.lookup(mockVariablesValue.data)?.nodes,
+ environments: expectedEnvironments,
+ });
+ },
+ );
+ });
+
+ 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 },
+ });
+
+ 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('Validators', () => {
+ describe('queryData', () => {
+ let error;
+
+ beforeEach(async () => {
+ mockVariables.mockResolvedValue(mockGroupVariables);
+ });
+
+ it('will mount component with right data', async () => {
+ try {
+ await createComponentWithApollo({
+ customHandlers: [[getGroupVariables, mockVariables]],
+ props: { ...createGroupProps() },
+ });
+ } 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: {} } },
+ });
+ } 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() },
+ });
+ } 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: {} } },
+ });
+ } 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_variable_list/components/legacy_ci_environments_dropdown_spec.js b/spec/frontend/ci_variable_list/components/legacy_ci_environments_dropdown_spec.js
deleted file mode 100644
index b3e23ba4201..00000000000
--- a/spec/frontend/ci_variable_list/components/legacy_ci_environments_dropdown_spec.js
+++ /dev/null
@@ -1,119 +0,0 @@
-import { GlDropdown, GlDropdownItem, GlIcon } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
-import Vuex from 'vuex';
-import LegacyCiEnvironmentsDropdown from '~/ci_variable_list/components/legacy_ci_environments_dropdown.vue';
-
-Vue.use(Vuex);
-
-describe('Ci environments dropdown', () => {
- let wrapper;
- let store;
-
- const enterSearchTerm = (value) =>
- wrapper.find('[data-testid="ci-environment-search"]').setValue(value);
-
- const createComponent = (term) => {
- store = new Vuex.Store({
- getters: {
- joinedEnvironments: () => ['dev', 'prod', 'staging'],
- },
- });
-
- wrapper = mount(LegacyCiEnvironmentsDropdown, {
- store,
- propsData: {
- value: term,
- },
- });
- enterSearchTerm(term);
- };
-
- const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- const findDropdownItemByIndex = (index) => wrapper.findAllComponents(GlDropdownItem).at(index);
- const findActiveIconByIndex = (index) => findDropdownItemByIndex(index).findComponent(GlIcon);
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- describe('No environments found', () => {
- beforeEach(() => {
- createComponent('stable');
- });
-
- it('renders create button with search term if environments do not contain search term', () => {
- expect(findAllDropdownItems()).toHaveLength(2);
- expect(findDropdownItemByIndex(1).text()).toBe('Create wildcard: stable');
- });
-
- it('renders empty results message', () => {
- expect(findDropdownItemByIndex(0).text()).toBe('No matching results');
- });
- });
-
- describe('Search term is empty', () => {
- beforeEach(() => {
- createComponent('');
- });
-
- it('renders all environments when search term is empty', () => {
- expect(findAllDropdownItems()).toHaveLength(3);
- expect(findDropdownItemByIndex(0).text()).toBe('dev');
- expect(findDropdownItemByIndex(1).text()).toBe('prod');
- expect(findDropdownItemByIndex(2).text()).toBe('staging');
- });
-
- it('should not display active checkmark on the inactive stage', () => {
- expect(findActiveIconByIndex(0).classes('gl-visibility-hidden')).toBe(true);
- });
- });
-
- describe('Environments found', () => {
- beforeEach(async () => {
- createComponent('prod');
- await nextTick();
- });
-
- it('renders only the environment searched for', () => {
- expect(findAllDropdownItems()).toHaveLength(1);
- expect(findDropdownItemByIndex(0).text()).toBe('prod');
- });
-
- it('should not display create button', () => {
- const environments = findAllDropdownItems().filter((env) => env.text().startsWith('Create'));
- expect(environments).toHaveLength(0);
- expect(findAllDropdownItems()).toHaveLength(1);
- });
-
- it('should not display empty results message', () => {
- expect(wrapper.findComponent({ ref: 'noMatchingResults' }).exists()).toBe(false);
- });
-
- it('should display active checkmark if active', () => {
- expect(findActiveIconByIndex(0).classes('gl-visibility-hidden')).toBe(false);
- });
-
- it('should clear the search term when showing the dropdown', () => {
- wrapper.findComponent(GlDropdown).trigger('click');
-
- expect(wrapper.find('[data-testid="ci-environment-search"]').text()).toBe('');
- });
-
- describe('Custom events', () => {
- it('should emit selectEnvironment if an environment is clicked', () => {
- findDropdownItemByIndex(0).vm.$emit('click');
- expect(wrapper.emitted('selectEnvironment')).toEqual([['prod']]);
- });
-
- it('should emit createClicked if an environment is clicked', async () => {
- createComponent('newscope');
-
- await nextTick();
- findDropdownItemByIndex(1).vm.$emit('click');
- expect(wrapper.emitted('createClicked')).toEqual([['newscope']]);
- });
- });
- });
-});
diff --git a/spec/frontend/ci_variable_list/components/legacy_ci_variable_modal_spec.js b/spec/frontend/ci_variable_list/components/legacy_ci_variable_modal_spec.js
deleted file mode 100644
index b607232907b..00000000000
--- a/spec/frontend/ci_variable_list/components/legacy_ci_variable_modal_spec.js
+++ /dev/null
@@ -1,323 +0,0 @@
-import { GlButton, GlFormInput } from '@gitlab/ui';
-import { shallowMount, mount } from '@vue/test-utils';
-import Vue from 'vue';
-import Vuex from 'vuex';
-import { mockTracking } from 'helpers/tracking_helper';
-import CiEnvironmentsDropdown from '~/ci_variable_list/components/ci_environments_dropdown.vue';
-import LegacyCiVariableModal from '~/ci_variable_list/components/legacy_ci_variable_modal.vue';
-import {
- AWS_ACCESS_KEY_ID,
- EVENT_LABEL,
- EVENT_ACTION,
- ENVIRONMENT_SCOPE_LINK_TITLE,
-} from '~/ci_variable_list/constants';
-import createStore from '~/ci_variable_list/store';
-import mockData from '../services/mock_data';
-import ModalStub from '../stubs';
-
-Vue.use(Vuex);
-
-describe('Ci variable modal', () => {
- let wrapper;
- let store;
- let trackingSpy;
-
- const maskableRegex = '^[a-zA-Z0-9_+=/@:.~-]{8,}$';
-
- const createComponent = (method, options = {}) => {
- store = createStore({
- maskableRegex,
- isGroup: options.isGroup,
- environmentScopeLink: '/help/environments',
- });
- wrapper = method(LegacyCiVariableModal, {
- attachTo: document.body,
- stubs: {
- GlModal: ModalStub,
- },
- store,
- ...options,
- });
- };
-
- const findCiEnvironmentsDropdown = () => wrapper.findComponent(CiEnvironmentsDropdown);
- const findModal = () => wrapper.findComponent(ModalStub);
- const findAddorUpdateButton = () => findModal().find('[data-testid="ciUpdateOrAddVariableBtn"]');
- const deleteVariableButton = () =>
- findModal()
- .findAllComponents(GlButton)
- .wrappers.find((button) => button.props('variant') === 'danger');
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('Basic interactions', () => {
- beforeEach(() => {
- createComponent(shallowMount);
- });
-
- it('button is disabled when no key/value pair are present', () => {
- expect(findAddorUpdateButton().attributes('disabled')).toBe('true');
- });
- });
-
- describe('Adding a new variable', () => {
- beforeEach(() => {
- const [variable] = mockData.mockVariables;
- createComponent(shallowMount);
- jest.spyOn(store, 'dispatch').mockImplementation();
- store.state.variable = variable;
- });
-
- it('button is enabled when key/value pair are present', () => {
- expect(findAddorUpdateButton().attributes('disabled')).toBeUndefined();
- });
-
- it('Add variable button dispatches addVariable action', () => {
- findAddorUpdateButton().vm.$emit('click');
- expect(store.dispatch).toHaveBeenCalledWith('addVariable');
- });
-
- it('Clears the modal state once modal is hidden', () => {
- findModal().vm.$emit('hidden');
- expect(store.dispatch).toHaveBeenCalledWith('clearModal');
- });
-
- it('should dispatch setVariableProtected when admin settings are configured to protect variables', () => {
- store.state.isProtectedByDefault = true;
- findModal().vm.$emit('shown');
-
- expect(store.dispatch).toHaveBeenCalledWith('setVariableProtected');
- });
- });
-
- describe('Adding a new non-AWS variable', () => {
- beforeEach(() => {
- const [variable] = mockData.mockVariables;
- const invalidKeyVariable = {
- ...variable,
- key: 'key',
- value: 'value',
- secret_value: 'secret_value',
- };
- createComponent(mount);
- store.state.variable = invalidKeyVariable;
- });
-
- it('does not show AWS guidance tip', () => {
- const tip = wrapper.find(`div[data-testid='aws-guidance-tip']`);
- expect(tip.exists()).toBe(true);
- expect(tip.isVisible()).toBe(false);
- });
- });
-
- describe('Adding a new AWS variable', () => {
- beforeEach(() => {
- const [variable] = mockData.mockVariables;
- const invalidKeyVariable = {
- ...variable,
- key: AWS_ACCESS_KEY_ID,
- value: 'AKIAIOSFODNN7EXAMPLEjdhy',
- secret_value: 'AKIAIOSFODNN7EXAMPLEjdhy',
- };
- createComponent(mount);
- store.state.variable = invalidKeyVariable;
- });
-
- it('shows AWS guidance tip', () => {
- const tip = wrapper.find(`[data-testid='aws-guidance-tip']`);
- expect(tip.exists()).toBe(true);
- expect(tip.isVisible()).toBe(true);
- });
- });
-
- describe.each`
- value | secret | rendered
- ${'value'} | ${'secret_value'} | ${false}
- ${'dollar$ign'} | ${'dollar$ign'} | ${true}
- `('Adding a new variable', ({ value, secret, rendered }) => {
- beforeEach(() => {
- const [variable] = mockData.mockVariables;
- const invalidKeyVariable = {
- ...variable,
- key: 'key',
- value,
- secret_value: secret,
- };
- createComponent(mount);
- store.state.variable = invalidKeyVariable;
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- });
-
- it(`${rendered ? 'renders' : 'does not render'} the variable reference warning`, () => {
- const warning = wrapper.find(`[data-testid='contains-variable-reference']`);
- expect(warning.exists()).toBe(rendered);
- });
- });
-
- describe('Editing a variable', () => {
- beforeEach(() => {
- const [variable] = mockData.mockVariables;
- createComponent(shallowMount);
- jest.spyOn(store, 'dispatch').mockImplementation();
- store.state.variableBeingEdited = variable;
- });
-
- it('button text is Update variable when updating', () => {
- expect(findAddorUpdateButton().text()).toBe('Update variable');
- });
-
- it('Update variable button dispatches updateVariable with correct variable', () => {
- findAddorUpdateButton().vm.$emit('click');
- expect(store.dispatch).toHaveBeenCalledWith('updateVariable');
- });
-
- it('Resets the editing state once modal is hidden', () => {
- findModal().vm.$emit('hidden');
- expect(store.dispatch).toHaveBeenCalledWith('resetEditing');
- });
-
- it('dispatches deleteVariable with correct variable to delete', () => {
- deleteVariableButton().vm.$emit('click');
- expect(store.dispatch).toHaveBeenCalledWith('deleteVariable');
- });
- });
-
- describe('Environment scope', () => {
- describe('group level variables', () => {
- it('renders the environment dropdown', () => {
- createComponent(shallowMount, {
- isGroup: true,
- provide: {
- glFeatures: {
- groupScopedCiVariables: true,
- },
- },
- });
-
- expect(findCiEnvironmentsDropdown().exists()).toBe(true);
- expect(findCiEnvironmentsDropdown().isVisible()).toBe(true);
- });
-
- describe('licensed feature is not available', () => {
- it('disables the dropdown', () => {
- createComponent(mount, {
- isGroup: true,
- provide: {
- glFeatures: {
- groupScopedCiVariables: false,
- },
- },
- });
-
- const environmentScopeInput = wrapper
- .find('[data-testid="environment-scope"]')
- .findComponent(GlFormInput);
- expect(findCiEnvironmentsDropdown().exists()).toBe(false);
- expect(environmentScopeInput.attributes('readonly')).toBe('readonly');
- });
- });
- });
-
- it('renders a link to documentation on scopes', () => {
- createComponent(mount);
-
- const link = wrapper.find('[data-testid="environment-scope-link"]');
-
- expect(link.attributes('title')).toBe(ENVIRONMENT_SCOPE_LINK_TITLE);
- expect(link.attributes('href')).toBe('/help/environments');
- });
- });
-
- describe('Validations', () => {
- const maskError = 'This variable can not be masked.';
-
- describe('when the mask state is invalid', () => {
- beforeEach(() => {
- const [variable] = mockData.mockVariables;
- const invalidMaskVariable = {
- ...variable,
- key: 'qs',
- value: 'd:;',
- secret_value: 'd:;',
- masked: true,
- };
- createComponent(mount);
- store.state.variable = invalidMaskVariable;
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- });
-
- it('disables the submit button', () => {
- expect(findAddorUpdateButton().attributes('disabled')).toBe('disabled');
- });
-
- it('shows the correct error text', () => {
- expect(findModal().text()).toContain(maskError);
- });
-
- it('sends the correct tracking event', () => {
- expect(trackingSpy).toHaveBeenCalledWith(undefined, EVENT_ACTION, {
- label: EVENT_LABEL,
- property: ';',
- });
- });
- });
-
- describe.each`
- value | secret | masked | eventSent | trackingErrorProperty
- ${'value'} | ${'secretValue'} | ${false} | ${0} | ${null}
- ${'shortMasked'} | ${'short'} | ${true} | ${0} | ${null}
- ${'withDollar$Sign'} | ${'dollar$ign'} | ${false} | ${1} | ${'$'}
- ${'withDollar$Sign'} | ${'dollar$ign'} | ${true} | ${1} | ${'$'}
- ${'unsupported'} | ${'unsupported|char'} | ${true} | ${1} | ${'|'}
- ${'unsupportedMasked'} | ${'unsupported|char'} | ${false} | ${0} | ${null}
- `('Adding a new variable', ({ value, secret, masked, eventSent, trackingErrorProperty }) => {
- beforeEach(() => {
- const [variable] = mockData.mockVariables;
- const invalidKeyVariable = {
- ...variable,
- key: 'key',
- value,
- secret_value: secret,
- masked,
- };
- createComponent(mount);
- store.state.variable = invalidKeyVariable;
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- });
-
- it(`${
- eventSent > 0 ? 'sends the correct' : 'does not send the'
- } variable validation tracking event`, () => {
- expect(trackingSpy).toHaveBeenCalledTimes(eventSent);
-
- if (eventSent > 0) {
- expect(trackingSpy).toHaveBeenCalledWith(undefined, EVENT_ACTION, {
- label: EVENT_LABEL,
- property: trackingErrorProperty,
- });
- }
- });
- });
-
- describe('when both states are valid', () => {
- beforeEach(() => {
- const [variable] = mockData.mockVariables;
- const validMaskandKeyVariable = {
- ...variable,
- key: AWS_ACCESS_KEY_ID,
- value: '12345678',
- secret_value: '87654321',
- masked: true,
- };
- createComponent(mount);
- store.state.variable = validMaskandKeyVariable;
- });
-
- it('does not disable the submit button', () => {
- expect(findAddorUpdateButton().attributes('disabled')).toBeUndefined();
- });
- });
- });
-});
diff --git a/spec/frontend/ci_variable_list/components/legacy_ci_variable_settings_spec.js b/spec/frontend/ci_variable_list/components/legacy_ci_variable_settings_spec.js
deleted file mode 100644
index 7def4dd4f29..00000000000
--- a/spec/frontend/ci_variable_list/components/legacy_ci_variable_settings_spec.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
-import Vuex from 'vuex';
-import LegacyCiVariableSettings from '~/ci_variable_list/components/legacy_ci_variable_settings.vue';
-import createStore from '~/ci_variable_list/store';
-
-Vue.use(Vuex);
-
-describe('Ci variable table', () => {
- let wrapper;
- let store;
- let isProject;
-
- const createComponent = (projectState) => {
- store = createStore();
- store.state.isProject = projectState;
- jest.spyOn(store, 'dispatch').mockImplementation();
- wrapper = shallowMount(LegacyCiVariableSettings, {
- store,
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('dispatches fetchEnvironments when mounted', () => {
- isProject = true;
- createComponent(isProject);
- expect(store.dispatch).toHaveBeenCalledWith('fetchEnvironments');
- });
-
- it('does not dispatch fetchenvironments when in group context', () => {
- isProject = false;
- createComponent(isProject);
- expect(store.dispatch).not.toHaveBeenCalled();
- });
-});
diff --git a/spec/frontend/ci_variable_list/components/legacy_ci_variable_table_spec.js b/spec/frontend/ci_variable_list/components/legacy_ci_variable_table_spec.js
deleted file mode 100644
index 310afc8003a..00000000000
--- a/spec/frontend/ci_variable_list/components/legacy_ci_variable_table_spec.js
+++ /dev/null
@@ -1,86 +0,0 @@
-import Vue from 'vue';
-import Vuex from 'vuex';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import LegacyCiVariableTable from '~/ci_variable_list/components/legacy_ci_variable_table.vue';
-import createStore from '~/ci_variable_list/store';
-import mockData from '../services/mock_data';
-
-Vue.use(Vuex);
-
-describe('Ci variable table', () => {
- let wrapper;
- let store;
-
- const createComponent = () => {
- store = createStore();
- jest.spyOn(store, 'dispatch').mockImplementation();
- wrapper = mountExtended(LegacyCiVariableTable, {
- attachTo: document.body,
- store,
- });
- };
-
- const findRevealButton = () => wrapper.findByText('Reveal values');
- const findEditButton = () => wrapper.findByLabelText('Edit');
- const findEmptyVariablesPlaceholder = () => wrapper.findByText('There are no variables yet.');
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('dispatches fetchVariables when mounted', () => {
- expect(store.dispatch).toHaveBeenCalledWith('fetchVariables');
- });
-
- describe('When table is empty', () => {
- beforeEach(() => {
- store.state.variables = [];
- });
-
- it('displays empty message', () => {
- expect(findEmptyVariablesPlaceholder().exists()).toBe(true);
- });
-
- it('hides the reveal button', () => {
- expect(findRevealButton().exists()).toBe(false);
- });
- });
-
- describe('When table has variables', () => {
- beforeEach(() => {
- store.state.variables = mockData.mockVariables;
- });
-
- it('does not display the empty message', () => {
- expect(findEmptyVariablesPlaceholder().exists()).toBe(false);
- });
-
- it('displays the reveal button', () => {
- expect(findRevealButton().exists()).toBe(true);
- });
-
- it('displays the correct amount of variables', async () => {
- expect(wrapper.findAll('.js-ci-variable-row')).toHaveLength(1);
- });
- });
-
- describe('Table click actions', () => {
- beforeEach(() => {
- store.state.variables = mockData.mockVariables;
- });
-
- it('reveals secret values when button is clicked', () => {
- findRevealButton().trigger('click');
- expect(store.dispatch).toHaveBeenCalledWith('toggleValues', false);
- });
-
- it('dispatches editVariable with correct variable to edit', () => {
- findEditButton().trigger('click');
- expect(store.dispatch).toHaveBeenCalledWith('editVariable', mockData.mockVariables[0]);
- });
- });
-});
diff --git a/spec/frontend/ci_variable_list/mocks.js b/spec/frontend/ci_variable_list/mocks.js
index 6f3e73f8b83..03b77f80430 100644
--- a/spec/frontend/ci_variable_list/mocks.js
+++ b/spec/frontend/ci_variable_list/mocks.js
@@ -1,10 +1,28 @@
import {
+ ADD_MUTATION_ACTION,
+ DELETE_MUTATION_ACTION,
+ UPDATE_MUTATION_ACTION,
variableTypes,
groupString,
instanceString,
projectString,
} from '~/ci_variable_list/constants';
+import addAdminVariable from '~/ci_variable_list/graphql/mutations/admin_add_variable.mutation.graphql';
+import deleteAdminVariable from '~/ci_variable_list/graphql/mutations/admin_delete_variable.mutation.graphql';
+import updateAdminVariable from '~/ci_variable_list/graphql/mutations/admin_update_variable.mutation.graphql';
+import addGroupVariable from '~/ci_variable_list/graphql/mutations/group_add_variable.mutation.graphql';
+import deleteGroupVariable from '~/ci_variable_list/graphql/mutations/group_delete_variable.mutation.graphql';
+import updateGroupVariable from '~/ci_variable_list/graphql/mutations/group_update_variable.mutation.graphql';
+import addProjectVariable from '~/ci_variable_list/graphql/mutations/project_add_variable.mutation.graphql';
+import deleteProjectVariable from '~/ci_variable_list/graphql/mutations/project_delete_variable.mutation.graphql';
+import updateProjectVariable from '~/ci_variable_list/graphql/mutations/project_update_variable.mutation.graphql';
+
+import getAdminVariables from '~/ci_variable_list/graphql/queries/variables.query.graphql';
+import getGroupVariables from '~/ci_variable_list/graphql/queries/group_variables.query.graphql';
+import getProjectEnvironments from '~/ci_variable_list/graphql/queries/project_environments.query.graphql';
+import getProjectVariables from '~/ci_variable_list/graphql/queries/project_variables.query.graphql';
+
export const devName = 'dev';
export const prodName = 'prod';
@@ -118,3 +136,62 @@ export const newVariable = {
value: 'devops',
variableType: variableTypes.variableType,
};
+
+export const createProjectProps = () => {
+ return {
+ componentName: 'ProjectVariable',
+ fullPath: '/namespace/project/',
+ id: 'gid://gitlab/Project/20',
+ mutationData: {
+ [ADD_MUTATION_ACTION]: addProjectVariable,
+ [UPDATE_MUTATION_ACTION]: updateProjectVariable,
+ [DELETE_MUTATION_ACTION]: deleteProjectVariable,
+ },
+ queryData: {
+ ciVariables: {
+ lookup: (data) => data?.project?.ciVariables,
+ query: getProjectVariables,
+ },
+ environments: {
+ lookup: (data) => data?.project?.environments,
+ query: getProjectEnvironments,
+ },
+ },
+ };
+};
+
+export const createGroupProps = () => {
+ return {
+ componentName: 'GroupVariable',
+ fullPath: '/my-group',
+ id: 'gid://gitlab/Group/20',
+ mutationData: {
+ [ADD_MUTATION_ACTION]: addGroupVariable,
+ [UPDATE_MUTATION_ACTION]: updateGroupVariable,
+ [DELETE_MUTATION_ACTION]: deleteGroupVariable,
+ },
+ queryData: {
+ ciVariables: {
+ lookup: (data) => data?.group?.ciVariables,
+ query: getGroupVariables,
+ },
+ },
+ };
+};
+
+export const createInstanceProps = () => {
+ return {
+ componentName: 'InstanceVariable',
+ mutationData: {
+ [ADD_MUTATION_ACTION]: addAdminVariable,
+ [UPDATE_MUTATION_ACTION]: updateAdminVariable,
+ [DELETE_MUTATION_ACTION]: deleteAdminVariable,
+ },
+ queryData: {
+ ciVariables: {
+ lookup: (data) => data?.ciVariables,
+ query: getAdminVariables,
+ },
+ },
+ };
+};
diff --git a/spec/frontend/ci_variable_list/store/actions_spec.js b/spec/frontend/ci_variable_list/store/actions_spec.js
deleted file mode 100644
index e8c81a53a55..00000000000
--- a/spec/frontend/ci_variable_list/store/actions_spec.js
+++ /dev/null
@@ -1,319 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import testAction from 'helpers/vuex_action_helper';
-import Api from '~/api';
-import * as actions from '~/ci_variable_list/store/actions';
-import * as types from '~/ci_variable_list/store/mutation_types';
-import getInitialState from '~/ci_variable_list/store/state';
-import { prepareDataForDisplay, prepareEnvironments } from '~/ci_variable_list/store/utils';
-import { createAlert } from '~/flash';
-import axios from '~/lib/utils/axios_utils';
-import mockData from '../services/mock_data';
-
-jest.mock('~/api.js');
-jest.mock('~/flash.js');
-
-describe('CI variable list store actions', () => {
- let mock;
- let state;
- const mockVariable = {
- environment_scope: '*',
- id: 63,
- key: 'test_var',
- masked: false,
- protected: false,
- value: 'test_val',
- variable_type: 'env_var',
- _destory: true,
- };
- const payloadError = new Error('Request failed with status code 500');
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
- state = getInitialState();
- state.endpoint = '/variables';
- });
-
- afterEach(() => {
- mock.restore();
- });
-
- describe('toggleValues', () => {
- const valuesHidden = false;
- it('commits TOGGLE_VALUES mutation', () => {
- testAction(actions.toggleValues, valuesHidden, {}, [
- {
- type: types.TOGGLE_VALUES,
- payload: valuesHidden,
- },
- ]);
- });
- });
-
- describe('clearModal', () => {
- it('commits CLEAR_MODAL mutation', () => {
- testAction(actions.clearModal, {}, {}, [
- {
- type: types.CLEAR_MODAL,
- },
- ]);
- });
- });
-
- describe('resetEditing', () => {
- it('commits RESET_EDITING mutation', () => {
- testAction(
- actions.resetEditing,
- {},
- {},
- [
- {
- type: types.RESET_EDITING,
- },
- ],
- [{ type: 'fetchVariables' }],
- );
- });
- });
-
- describe('setVariableProtected', () => {
- it('commits SET_VARIABLE_PROTECTED mutation', () => {
- testAction(actions.setVariableProtected, {}, {}, [
- {
- type: types.SET_VARIABLE_PROTECTED,
- },
- ]);
- });
- });
-
- describe('deleteVariable', () => {
- it('dispatch correct actions on successful deleted variable', () => {
- mock.onPatch(state.endpoint).reply(200);
-
- return testAction(
- actions.deleteVariable,
- {},
- state,
- [],
- [
- { type: 'requestDeleteVariable' },
- { type: 'receiveDeleteVariableSuccess' },
- { type: 'fetchVariables' },
- ],
- );
- });
-
- it('should show flash error and set error in state on delete failure', async () => {
- mock.onPatch(state.endpoint).reply(500, '');
-
- await testAction(
- actions.deleteVariable,
- {},
- state,
- [],
- [
- { type: 'requestDeleteVariable' },
- {
- type: 'receiveDeleteVariableError',
- payload: payloadError,
- },
- ],
- );
- expect(createAlert).toHaveBeenCalled();
- });
- });
-
- describe('updateVariable', () => {
- it('dispatch correct actions on successful updated variable', () => {
- mock.onPatch(state.endpoint).reply(200);
-
- return testAction(
- actions.updateVariable,
- {},
- state,
- [],
- [
- { type: 'requestUpdateVariable' },
- { type: 'receiveUpdateVariableSuccess' },
- { type: 'fetchVariables' },
- ],
- );
- });
-
- it('should show flash error and set error in state on update failure', async () => {
- mock.onPatch(state.endpoint).reply(500, '');
-
- await testAction(
- actions.updateVariable,
- mockVariable,
- state,
- [],
- [
- { type: 'requestUpdateVariable' },
- {
- type: 'receiveUpdateVariableError',
- payload: payloadError,
- },
- ],
- );
- expect(createAlert).toHaveBeenCalled();
- });
- });
-
- describe('addVariable', () => {
- it('dispatch correct actions on successful added variable', () => {
- mock.onPatch(state.endpoint).reply(200);
-
- return testAction(
- actions.addVariable,
- {},
- state,
- [],
- [
- { type: 'requestAddVariable' },
- { type: 'receiveAddVariableSuccess' },
- { type: 'fetchVariables' },
- ],
- );
- });
-
- it('should show flash error and set error in state on add failure', async () => {
- mock.onPatch(state.endpoint).reply(500, '');
-
- await testAction(
- actions.addVariable,
- {},
- state,
- [],
- [
- { type: 'requestAddVariable' },
- {
- type: 'receiveAddVariableError',
- payload: payloadError,
- },
- ],
- );
- expect(createAlert).toHaveBeenCalled();
- });
- });
-
- describe('fetchVariables', () => {
- it('dispatch correct actions on fetchVariables', () => {
- mock.onGet(state.endpoint).reply(200, { variables: mockData.mockVariables });
-
- return testAction(
- actions.fetchVariables,
- {},
- state,
- [],
- [
- { type: 'requestVariables' },
- {
- type: 'receiveVariablesSuccess',
- payload: prepareDataForDisplay(mockData.mockVariables),
- },
- ],
- );
- });
-
- it('should show flash error and set error in state on fetch variables failure', async () => {
- mock.onGet(state.endpoint).reply(500);
-
- await testAction(actions.fetchVariables, {}, state, [], [{ type: 'requestVariables' }]);
- expect(createAlert).toHaveBeenCalledWith({
- message: 'There was an error fetching the variables.',
- });
- });
- });
-
- describe('fetchEnvironments', () => {
- it('dispatch correct actions on fetchEnvironments', () => {
- Api.environments = jest.fn().mockResolvedValue({ data: mockData.mockEnvironments });
-
- return testAction(
- actions.fetchEnvironments,
- {},
- state,
- [],
- [
- { type: 'requestEnvironments' },
- {
- type: 'receiveEnvironmentsSuccess',
- payload: prepareEnvironments(mockData.mockEnvironments),
- },
- ],
- );
- });
-
- it('should show flash error and set error in state on fetch environments failure', async () => {
- Api.environments = jest.fn().mockRejectedValue();
-
- await testAction(actions.fetchEnvironments, {}, state, [], [{ type: 'requestEnvironments' }]);
-
- expect(createAlert).toHaveBeenCalledWith({
- message: 'There was an error fetching the environments information.',
- });
- });
- });
-
- describe('Update variable values', () => {
- it('updateVariableKey', () => {
- testAction(
- actions.updateVariableKey,
- { key: mockVariable.key },
- {},
- [
- {
- type: types.UPDATE_VARIABLE_KEY,
- payload: mockVariable.key,
- },
- ],
- [],
- );
- });
-
- it('updateVariableValue', () => {
- testAction(
- actions.updateVariableValue,
- { secret_value: mockVariable.value },
- {},
- [
- {
- type: types.UPDATE_VARIABLE_VALUE,
- payload: mockVariable.value,
- },
- ],
- [],
- );
- });
-
- it('updateVariableType', () => {
- testAction(
- actions.updateVariableType,
- { variable_type: mockVariable.variable_type },
- {},
- [{ type: types.UPDATE_VARIABLE_TYPE, payload: mockVariable.variable_type }],
- [],
- );
- });
-
- it('updateVariableProtected', () => {
- testAction(
- actions.updateVariableProtected,
- { protected_variable: mockVariable.protected },
- {},
- [{ type: types.UPDATE_VARIABLE_PROTECTED, payload: mockVariable.protected }],
- [],
- );
- });
-
- it('updateVariableMasked', () => {
- testAction(
- actions.updateVariableMasked,
- { masked: mockVariable.masked },
- {},
- [{ type: types.UPDATE_VARIABLE_MASKED, payload: mockVariable.masked }],
- [],
- );
- });
- });
-});
diff --git a/spec/frontend/ci_variable_list/store/getters_spec.js b/spec/frontend/ci_variable_list/store/getters_spec.js
deleted file mode 100644
index 92f22b18763..00000000000
--- a/spec/frontend/ci_variable_list/store/getters_spec.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import * as getters from '~/ci_variable_list/store/getters';
-import mockData from '../services/mock_data';
-
-describe('Ci variable getters', () => {
- describe('joinedEnvironments', () => {
- it('should join fetched environments with variable environment scopes', () => {
- const state = {
- environments: ['All (default)', 'staging', 'deployment', 'prod'],
- variables: mockData.mockVariableScopes,
- };
-
- expect(getters.joinedEnvironments(state)).toEqual([
- 'All (default)',
- 'deployment',
- 'prod',
- 'production',
- 'staging',
- ]);
- });
- });
-});
diff --git a/spec/frontend/ci_variable_list/store/mutations_spec.js b/spec/frontend/ci_variable_list/store/mutations_spec.js
deleted file mode 100644
index c7d07ead09b..00000000000
--- a/spec/frontend/ci_variable_list/store/mutations_spec.js
+++ /dev/null
@@ -1,136 +0,0 @@
-import * as types from '~/ci_variable_list/store/mutation_types';
-import mutations from '~/ci_variable_list/store/mutations';
-import state from '~/ci_variable_list/store/state';
-
-describe('CI variable list mutations', () => {
- let stateCopy;
-
- beforeEach(() => {
- stateCopy = state();
- });
-
- describe('TOGGLE_VALUES', () => {
- it('should toggle state', () => {
- const valuesHidden = false;
-
- mutations[types.TOGGLE_VALUES](stateCopy, valuesHidden);
-
- expect(stateCopy.valuesHidden).toEqual(valuesHidden);
- });
- });
-
- describe('VARIABLE_BEING_EDITED', () => {
- it('should set the variable that is being edited', () => {
- mutations[types.VARIABLE_BEING_EDITED](stateCopy);
-
- expect(stateCopy.variableBeingEdited).toBe(true);
- });
- });
-
- describe('RESET_EDITING', () => {
- it('should reset variableBeingEdited to false', () => {
- mutations[types.RESET_EDITING](stateCopy);
-
- expect(stateCopy.variableBeingEdited).toBe(false);
- });
- });
-
- describe('CLEAR_MODAL', () => {
- it('should clear modal state', () => {
- const modalState = {
- variable_type: 'Variable',
- key: '',
- secret_value: '',
- protected_variable: false,
- masked: false,
- environment_scope: 'All (default)',
- };
-
- mutations[types.CLEAR_MODAL](stateCopy);
-
- expect(stateCopy.variable).toEqual(modalState);
- });
- });
-
- describe('RECEIVE_ENVIRONMENTS_SUCCESS', () => {
- it('should set environments', () => {
- const environments = ['env1', 'env2'];
-
- mutations[types.RECEIVE_ENVIRONMENTS_SUCCESS](stateCopy, environments);
-
- expect(stateCopy.environments).toEqual(['All (default)', 'env1', 'env2']);
- });
- });
-
- describe('SET_ENVIRONMENT_SCOPE', () => {
- const environment = 'production';
-
- it('should set environment scope on variable', () => {
- mutations[types.SET_ENVIRONMENT_SCOPE](stateCopy, environment);
-
- expect(stateCopy.variable.environment_scope).toBe('production');
- });
- });
-
- describe('ADD_WILD_CARD_SCOPE', () => {
- it('should add wild card scope to environments array and sort', () => {
- stateCopy.environments = ['dev', 'staging'];
- mutations[types.ADD_WILD_CARD_SCOPE](stateCopy, 'production');
-
- expect(stateCopy.environments).toEqual(['dev', 'production', 'staging']);
- });
- });
-
- describe('SET_VARIABLE_PROTECTED', () => {
- it('should set protected value to true', () => {
- mutations[types.SET_VARIABLE_PROTECTED](stateCopy);
-
- expect(stateCopy.variable.protected_variable).toBe(true);
- });
- });
-
- describe('UPDATE_VARIABLE_KEY', () => {
- it('should update variable key value', () => {
- const key = 'new_var';
- mutations[types.UPDATE_VARIABLE_KEY](stateCopy, key);
-
- expect(stateCopy.variable.key).toBe(key);
- });
- });
-
- describe('UPDATE_VARIABLE_VALUE', () => {
- it('should update variable value', () => {
- const value = 'variable_value';
- mutations[types.UPDATE_VARIABLE_VALUE](stateCopy, value);
-
- expect(stateCopy.variable.secret_value).toBe(value);
- });
- });
-
- describe('UPDATE_VARIABLE_TYPE', () => {
- it('should update variable type value', () => {
- const type = 'File';
- mutations[types.UPDATE_VARIABLE_TYPE](stateCopy, type);
-
- expect(stateCopy.variable.variable_type).toBe(type);
- });
- });
-
- describe('UPDATE_VARIABLE_PROTECTED', () => {
- it('should update variable protected value', () => {
- const protectedValue = true;
- mutations[types.UPDATE_VARIABLE_PROTECTED](stateCopy, protectedValue);
-
- expect(stateCopy.variable.protected_variable).toBe(protectedValue);
- });
- });
-
- describe('UPDATE_VARIABLE_MASKED', () => {
- it('should update variable masked value', () => {
- const masked = true;
- mutations[types.UPDATE_VARIABLE_MASKED](stateCopy, masked);
-
- expect(stateCopy.variable.masked).toBe(masked);
- });
- });
-});
diff --git a/spec/frontend/ci_variable_list/store/utils_spec.js b/spec/frontend/ci_variable_list/store/utils_spec.js
deleted file mode 100644
index 5b10370324a..00000000000
--- a/spec/frontend/ci_variable_list/store/utils_spec.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import {
- prepareDataForDisplay,
- prepareEnvironments,
- prepareDataForApi,
-} from '~/ci_variable_list/store/utils';
-import mockData from '../services/mock_data';
-
-describe('CI variables store utils', () => {
- it('prepares ci variables for display', () => {
- expect(prepareDataForDisplay(mockData.mockVariablesApi)).toStrictEqual(
- mockData.mockVariablesDisplay,
- );
- });
-
- it('prepares single ci variable for api', () => {
- expect(prepareDataForApi(mockData.mockVariablesDisplay[0])).toStrictEqual({
- environment_scope: '*',
- id: 113,
- key: 'test_var',
- masked: 'false',
- protected: 'false',
- secret_value: 'test_val',
- value: 'test_val',
- variable_type: 'env_var',
- });
-
- expect(prepareDataForApi(mockData.mockVariablesDisplay[1])).toStrictEqual({
- environment_scope: '*',
- id: 114,
- key: 'test_var_2',
- masked: 'false',
- protected: 'false',
- secret_value: 'test_val_2',
- value: 'test_val_2',
- variable_type: 'file',
- });
- });
-
- it('prepares single ci variable for delete', () => {
- expect(prepareDataForApi(mockData.mockVariablesDisplay[0], true)).toHaveProperty(
- '_destroy',
- true,
- );
- });
-
- it('prepares environments for display', () => {
- expect(prepareEnvironments(mockData.mockEnvironments)).toStrictEqual(['staging', 'production']);
- });
-});
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 cce17176129..98001858851 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
@@ -56,6 +56,7 @@ describe('content_editor/components/bubble_menus/formatting_bubble_menu', () =>
${'code'} | ${{ contentType: 'code', iconName: 'code', label: 'Code', editorCommand: 'toggleCode' }}
${'superscript'} | ${{ contentType: 'superscript', iconName: 'superscript', label: 'Superscript', editorCommand: 'toggleSuperscript' }}
${'subscript'} | ${{ contentType: 'subscript', iconName: 'subscript', label: 'Subscript', editorCommand: 'toggleSubscript' }}
+ ${'highlight'} | ${{ contentType: 'highlight', iconName: 'highlight', label: 'Highlight', editorCommand: 'toggleHighlight' }}
${'link'} | ${{ contentType: 'link', iconName: 'link', label: 'Insert link', editorCommand: 'toggleLink', editorCommandParams: { href: '' } }}
`('given a $testId toolbar control', ({ testId, controlProps }) => {
beforeEach(() => {
diff --git a/spec/frontend/content_editor/markdown_snapshot_spec.js b/spec/frontend/content_editor/markdown_snapshot_spec.js
index 63ca66172e6..146208bf8c7 100644
--- a/spec/frontend/content_editor/markdown_snapshot_spec.js
+++ b/spec/frontend/content_editor/markdown_snapshot_spec.js
@@ -1,10 +1,11 @@
-import path from 'path';
import { describeMarkdownSnapshots } from 'jest/content_editor/markdown_snapshot_spec_helper';
jest.mock('~/emoji');
-const glfmSpecificationDir = path.join(__dirname, '..', '..', '..', 'glfm_specification');
-
// See https://docs.gitlab.com/ee/development/gitlab_flavored_markdown/specification_guide/#markdown-snapshot-testing
// for documentation on this spec.
-describeMarkdownSnapshots('CE markdown snapshots in ContentEditor', glfmSpecificationDir);
+//
+// NOTE: Unlike the backend markdown_snapshot_spec.rb which has a CE and EE version, there is only
+// one version of this spec. This is because the frontend markdown rendering does not require EE-only
+// backend features.
+describeMarkdownSnapshots('markdown example snapshots in ContentEditor');
diff --git a/spec/frontend/content_editor/markdown_snapshot_spec_helper.js b/spec/frontend/content_editor/markdown_snapshot_spec_helper.js
index 05fa8e6a6b2..64988c5b717 100644
--- a/spec/frontend/content_editor/markdown_snapshot_spec_helper.js
+++ b/spec/frontend/content_editor/markdown_snapshot_spec_helper.js
@@ -1,10 +1,12 @@
// See https://docs.gitlab.com/ee/development/gitlab_flavored_markdown/specification_guide/#markdown-snapshot-testing
// for documentation on this spec.
-import fs from 'fs';
-import path from 'path';
import jsYaml from 'js-yaml';
import { pick } from 'lodash';
+import glfmExampleStatusYml from '../../../glfm_specification/input/gitlab_flavored_markdown/glfm_example_status.yml';
+import markdownYml from '../../../glfm_specification/output_example_snapshots/markdown.yml';
+import htmlYml from '../../../glfm_specification/output_example_snapshots/html.yml';
+import prosemirrorJsonYml from '../../../glfm_specification/output_example_snapshots/prosemirror_json.yml';
import {
IMPLEMENTATION_ERROR_MSG,
renderHtmlAndJsonForAllExamples,
@@ -18,29 +20,21 @@ const filterExamples = (examples) => {
return pick(examples, focusedMarkdownExamples);
};
-const loadExamples = (dir, fileName) => {
- const yaml = fs.readFileSync(path.join(dir, fileName));
+const loadExamples = (yaml) => {
const examples = jsYaml.safeLoad(yaml, {});
return filterExamples(examples);
};
// eslint-disable-next-line jest/no-export
-export const describeMarkdownSnapshots = (description, glfmSpecificationDir) => {
+export const describeMarkdownSnapshots = (description) => {
let actualHtmlAndJsonExamples;
let skipRunningSnapshotWysiwygHtmlTests;
let skipRunningSnapshotProsemirrorJsonTests;
- const exampleStatuses = loadExamples(
- path.join(glfmSpecificationDir, 'input', 'gitlab_flavored_markdown'),
- 'glfm_example_status.yml',
- );
- const glfmExampleSnapshotsDir = path.join(glfmSpecificationDir, 'example_snapshots');
- const markdownExamples = loadExamples(glfmExampleSnapshotsDir, 'markdown.yml');
- const expectedHtmlExamples = loadExamples(glfmExampleSnapshotsDir, 'html.yml');
- const expectedProseMirrorJsonExamples = loadExamples(
- glfmExampleSnapshotsDir,
- 'prosemirror_json.yml',
- );
+ const exampleStatuses = loadExamples(glfmExampleStatusYml);
+ const markdownExamples = loadExamples(markdownYml);
+ const expectedHtmlExamples = loadExamples(htmlYml);
+ const expectedProseMirrorJsonExamples = loadExamples(prosemirrorJsonYml);
beforeAll(async () => {
return renderHtmlAndJsonForAllExamples(markdownExamples).then((examples) => {
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 bd48b7fdd23..5df901e0f15 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,87 +1,8 @@
import { DOMSerializer } from 'prosemirror-model';
-// TODO: DRY up duplication with spec/frontend/content_editor/services/markdown_serializer_spec.js
-// See https://gitlab.com/groups/gitlab-org/-/epics/7719#plan
-import Audio from '~/content_editor/extensions/audio';
-import Blockquote from '~/content_editor/extensions/blockquote';
-import Bold from '~/content_editor/extensions/bold';
-import BulletList from '~/content_editor/extensions/bullet_list';
-import Code from '~/content_editor/extensions/code';
-import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight';
-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 Emoji from '~/content_editor/extensions/emoji';
-import Figure from '~/content_editor/extensions/figure';
-import FigureCaption from '~/content_editor/extensions/figure_caption';
-import FootnoteDefinition from '~/content_editor/extensions/footnote_definition';
-import FootnoteReference from '~/content_editor/extensions/footnote_reference';
-import FootnotesSection from '~/content_editor/extensions/footnotes_section';
-import Frontmatter from '~/content_editor/extensions/frontmatter';
-import HardBreak from '~/content_editor/extensions/hard_break';
-import Heading from '~/content_editor/extensions/heading';
-import HorizontalRule from '~/content_editor/extensions/horizontal_rule';
-import HTMLNodes from '~/content_editor/extensions/html_nodes';
-import Image from '~/content_editor/extensions/image';
-import InlineDiff from '~/content_editor/extensions/inline_diff';
-import Italic from '~/content_editor/extensions/italic';
-import Link from '~/content_editor/extensions/link';
-import ListItem from '~/content_editor/extensions/list_item';
-import OrderedList from '~/content_editor/extensions/ordered_list';
-import ReferenceDefinition from '~/content_editor/extensions/reference_definition';
-import Strike from '~/content_editor/extensions/strike';
-import Table from '~/content_editor/extensions/table';
-import TableCell from '~/content_editor/extensions/table_cell';
-import TableHeader from '~/content_editor/extensions/table_header';
-import TableRow from '~/content_editor/extensions/table_row';
-import TableOfContents from '~/content_editor/extensions/table_of_contents';
-import TaskItem from '~/content_editor/extensions/task_item';
-import TaskList from '~/content_editor/extensions/task_list';
-import Video from '~/content_editor/extensions/video';
import createMarkdownDeserializer from '~/content_editor/services/remark_markdown_deserializer';
-import { createTestEditor } from 'jest/content_editor/test_utils';
+import { createTiptapEditor } from 'jest/content_editor/test_utils';
-const tiptapEditor = createTestEditor({
- extensions: [
- Audio,
- Blockquote,
- Bold,
- BulletList,
- Code,
- CodeBlockHighlight,
- DescriptionItem,
- DescriptionList,
- Details,
- DetailsContent,
- Emoji,
- FootnoteDefinition,
- FootnoteReference,
- FootnotesSection,
- Frontmatter,
- Figure,
- FigureCaption,
- HardBreak,
- Heading,
- HorizontalRule,
- ...HTMLNodes,
- Image,
- InlineDiff,
- Italic,
- Link,
- ListItem,
- OrderedList,
- ReferenceDefinition,
- Strike,
- Table,
- TableCell,
- TableHeader,
- TableRow,
- TableOfContents,
- TaskItem,
- TaskList,
- Video,
- ],
-});
+const tiptapEditor = createTiptapEditor();
export const IMPLEMENTATION_ERROR_MSG = 'Error - check implementation';
diff --git a/spec/frontend/content_editor/services/markdown_serializer_spec.js b/spec/frontend/content_editor/services/markdown_serializer_spec.js
index 32193d97fd8..1bf23415052 100644
--- a/spec/frontend/content_editor/services/markdown_serializer_spec.js
+++ b/spec/frontend/content_editor/services/markdown_serializer_spec.js
@@ -1,4 +1,3 @@
-import Audio from '~/content_editor/extensions/audio';
import Blockquote from '~/content_editor/extensions/blockquote';
import Bold from '~/content_editor/extensions/bold';
import BulletList from '~/content_editor/extensions/bullet_list';
@@ -16,7 +15,7 @@ import FootnoteReference from '~/content_editor/extensions/footnote_reference';
import HardBreak from '~/content_editor/extensions/hard_break';
import Heading from '~/content_editor/extensions/heading';
import HorizontalRule from '~/content_editor/extensions/horizontal_rule';
-import HTMLMarks from '~/content_editor/extensions/html_marks';
+import Highlight from '~/content_editor/extensions/highlight';
import HTMLNodes from '~/content_editor/extensions/html_nodes';
import Image from '~/content_editor/extensions/image';
import InlineDiff from '~/content_editor/extensions/inline_diff';
@@ -34,53 +33,13 @@ import TableHeader from '~/content_editor/extensions/table_header';
import TableRow from '~/content_editor/extensions/table_row';
import TaskItem from '~/content_editor/extensions/task_item';
import TaskList from '~/content_editor/extensions/task_list';
-import Video from '~/content_editor/extensions/video';
import markdownSerializer from '~/content_editor/services/markdown_serializer';
import remarkMarkdownDeserializer from '~/content_editor/services/remark_markdown_deserializer';
-import { createTestEditor, createDocBuilder } from '../test_utils';
+import { createTiptapEditor, createDocBuilder } from '../test_utils';
jest.mock('~/emoji');
-const tiptapEditor = createTestEditor({
- extensions: [
- Audio,
- Blockquote,
- Bold,
- BulletList,
- Code,
- CodeBlockHighlight,
- DescriptionItem,
- DescriptionList,
- Details,
- DetailsContent,
- Emoji,
- FootnoteDefinition,
- FootnoteReference,
- Figure,
- FigureCaption,
- HardBreak,
- Heading,
- HorizontalRule,
- Image,
- InlineDiff,
- Italic,
- Link,
- ListItem,
- OrderedList,
- ReferenceDefinition,
- Sourcemap,
- Strike,
- Table,
- TableCell,
- TableHeader,
- TableRow,
- TaskItem,
- TaskList,
- Video,
- ...HTMLMarks,
- ...HTMLNodes,
- ],
-});
+const tiptapEditor = createTiptapEditor([Sourcemap]);
const {
builders: {
@@ -103,6 +62,7 @@ const {
figureCaption,
heading,
hardBreak,
+ highlight,
horizontalRule,
image,
inlineDiff,
@@ -141,6 +101,7 @@ const {
hardBreak: { nodeType: HardBreak.name },
heading: { nodeType: Heading.name },
horizontalRule: { nodeType: HorizontalRule.name },
+ highlight: { markType: Highlight.name },
image: { nodeType: Image.name },
inlineDiff: { markType: InlineDiff.name },
italic: { nodeType: Italic.name },
@@ -202,6 +163,12 @@ describe('markdownSerializer', () => {
).toBe('{++30 lines+}{--10 lines-}');
});
+ it('correctly serializes highlight', () => {
+ expect(serialize(paragraph('this is some ', highlight('highlighted'), ' text'))).toBe(
+ 'this is some <mark>highlighted</mark> text',
+ );
+ });
+
it('correctly serializes a line break', () => {
expect(serialize(paragraph('hello', hardBreak(), 'world'))).toBe('hello\\\nworld');
});
diff --git a/spec/frontend/content_editor/test_utils.js b/spec/frontend/content_editor/test_utils.js
index 4ed1ed97cbd..0768fa6e8df 100644
--- a/spec/frontend/content_editor/test_utils.js
+++ b/spec/frontend/content_editor/test_utils.js
@@ -5,6 +5,45 @@ import { Text } from '@tiptap/extension-text';
import { Editor } from '@tiptap/vue-2';
import { builders, eq } from 'prosemirror-test-builder';
import { nextTick } from 'vue';
+import Audio from '~/content_editor/extensions/audio';
+import Blockquote from '~/content_editor/extensions/blockquote';
+import Bold from '~/content_editor/extensions/bold';
+import BulletList from '~/content_editor/extensions/bullet_list';
+import Code from '~/content_editor/extensions/code';
+import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight';
+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 Emoji from '~/content_editor/extensions/emoji';
+import FootnoteDefinition from '~/content_editor/extensions/footnote_definition';
+import FootnoteReference from '~/content_editor/extensions/footnote_reference';
+import FootnotesSection from '~/content_editor/extensions/footnotes_section';
+import Frontmatter from '~/content_editor/extensions/frontmatter';
+import Figure from '~/content_editor/extensions/figure';
+import FigureCaption from '~/content_editor/extensions/figure_caption';
+import HardBreak from '~/content_editor/extensions/hard_break';
+import Heading from '~/content_editor/extensions/heading';
+import HorizontalRule from '~/content_editor/extensions/horizontal_rule';
+import Highlight from '~/content_editor/extensions/highlight';
+import Image from '~/content_editor/extensions/image';
+import InlineDiff from '~/content_editor/extensions/inline_diff';
+import Italic from '~/content_editor/extensions/italic';
+import Link from '~/content_editor/extensions/link';
+import ListItem from '~/content_editor/extensions/list_item';
+import OrderedList from '~/content_editor/extensions/ordered_list';
+import ReferenceDefinition from '~/content_editor/extensions/reference_definition';
+import Strike from '~/content_editor/extensions/strike';
+import Table from '~/content_editor/extensions/table';
+import TableCell from '~/content_editor/extensions/table_cell';
+import TableHeader from '~/content_editor/extensions/table_header';
+import TableRow from '~/content_editor/extensions/table_row';
+import TableOfContents from '~/content_editor/extensions/table_of_contents';
+import TaskItem from '~/content_editor/extensions/task_item';
+import TaskList from '~/content_editor/extensions/task_list';
+import Video from '~/content_editor/extensions/video';
+import HTMLMarks from '~/content_editor/extensions/html_marks';
+import HTMLNodes from '~/content_editor/extensions/html_nodes';
export const createDocBuilder = ({ tiptapEditor, names = {} }) => {
const docBuilders = builders(tiptapEditor.schema, {
@@ -162,3 +201,49 @@ export const waitUntilNextDocTransaction = ({ tiptapEditor, action = () => {} })
action();
});
};
+
+export const createTiptapEditor = (extensions = []) =>
+ createTestEditor({
+ extensions: [
+ Audio,
+ Blockquote,
+ Bold,
+ BulletList,
+ Code,
+ CodeBlockHighlight,
+ DescriptionItem,
+ DescriptionList,
+ Details,
+ DetailsContent,
+ Emoji,
+ FootnoteDefinition,
+ FootnoteReference,
+ FootnotesSection,
+ Frontmatter,
+ Figure,
+ FigureCaption,
+ HardBreak,
+ Heading,
+ HorizontalRule,
+ ...HTMLMarks,
+ ...HTMLNodes,
+ Highlight,
+ Image,
+ InlineDiff,
+ Italic,
+ Link,
+ ListItem,
+ OrderedList,
+ ReferenceDefinition,
+ Strike,
+ Table,
+ TableCell,
+ TableHeader,
+ TableRow,
+ TableOfContents,
+ TaskItem,
+ TaskList,
+ Video,
+ ...extensions,
+ ],
+ });
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 19e9ba8b268..990f18d64c1 100644
--- a/spec/frontend/deploy_tokens/components/new_deploy_token_spec.js
+++ b/spec/frontend/deploy_tokens/components/new_deploy_token_spec.js
@@ -59,6 +59,19 @@ describe('New Deploy Token', () => {
expect(checkbox.text()).toBe('read_registry');
});
+ function submitTokenThenCheck() {
+ wrapper.findAllComponents(GlButton).at(0).vm.$emit('click');
+
+ return waitForPromises()
+ .then(() => nextTick())
+ .then(() => {
+ const [tokenUsername, tokenValue] = wrapper.findAllComponents(GlFormInputGroup).wrappers;
+
+ expect(tokenUsername.props('value')).toBe('test token username');
+ expect(tokenValue.props('value')).toBe('test token');
+ });
+ }
+
it('should make a request to create a token on submit', () => {
const mockAxios = new MockAdapter(axios);
@@ -72,9 +85,18 @@ describe('New Deploy Token', () => {
const datepicker = wrapper.findAllComponents(GlDatepicker).at(0);
datepicker.vm.$emit('input', date);
- const [readRepo, readRegistry] = wrapper.findAllComponents(GlFormCheckbox).wrappers;
+ const [
+ readRepo,
+ readRegistry,
+ writeRegistry,
+ readPackageRegistry,
+ writePackageRegistry,
+ ] = wrapper.findAllComponents(GlFormCheckbox).wrappers;
readRepo.vm.$emit('input', true);
readRegistry.vm.$emit('input', true);
+ writeRegistry.vm.$emit('input', true);
+ readPackageRegistry.vm.$emit('input', true);
+ writePackageRegistry.vm.$emit('input', true);
mockAxios
.onPost(createNewTokenPath, {
@@ -84,20 +106,47 @@ describe('New Deploy Token', () => {
username: 'test username',
read_repository: true,
read_registry: true,
+ write_registry: true,
+ read_package_registry: true,
+ write_package_registry: true,
},
})
.replyOnce(200, { username: 'test token username', token: 'test token' });
- wrapper.findAllComponents(GlButton).at(0).vm.$emit('click');
+ return submitTokenThenCheck();
+ });
- return waitForPromises()
- .then(() => nextTick())
- .then(() => {
- const [tokenUsername, tokenValue] = wrapper.findAllComponents(GlFormInputGroup).wrappers;
+ it('should request a token without an expiration date', () => {
+ const mockAxios = new MockAdapter(axios);
- expect(tokenUsername.props('value')).toBe('test token username');
- expect(tokenValue.props('value')).toBe('test token');
- });
+ const formInputs = wrapper.findAllComponents(GlFormInput);
+ const name = formInputs.at(0);
+ const username = formInputs.at(2);
+ name.vm.$emit('input', 'test never expire name');
+ username.vm.$emit('input', 'test never expire username');
+
+ const [, , , readPackageRegistry, writePackageRegistry] = wrapper.findAllComponents(
+ GlFormCheckbox,
+ ).wrappers;
+ readPackageRegistry.vm.$emit('input', true);
+ writePackageRegistry.vm.$emit('input', true);
+
+ mockAxios
+ .onPost(createNewTokenPath, {
+ deploy_token: {
+ name: 'test never expire name',
+ expires_at: null,
+ username: 'test never expire username',
+ read_repository: false,
+ read_registry: false,
+ write_registry: false,
+ read_package_registry: true,
+ write_package_registry: true,
+ },
+ })
+ .replyOnce(200, { username: 'test token username', token: 'test token' });
+
+ return submitTokenThenCheck();
});
});
});
diff --git a/spec/frontend/deprecated_jquery_dropdown_spec.js b/spec/frontend/deprecated_jquery_dropdown_spec.js
index 4a070395eaf..439c20e0fb5 100644
--- a/spec/frontend/deprecated_jquery_dropdown_spec.js
+++ b/spec/frontend/deprecated_jquery_dropdown_spec.js
@@ -193,16 +193,18 @@ describe('deprecatedJQueryDropdown', () => {
});
it('should not focus search input while remote task is not complete', () => {
- expect($(document.activeElement)).not.toEqual($(SEARCH_INPUT_SELECTOR));
+ expect(document.activeElement).toBeDefined();
+ expect(document.activeElement).not.toEqual(document.querySelector(SEARCH_INPUT_SELECTOR));
remoteCallback();
- expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR));
+ expect(document.activeElement).toEqual(document.querySelector(SEARCH_INPUT_SELECTOR));
});
it('should focus search input after remote task is complete', () => {
remoteCallback();
- expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR));
+ expect(document.activeElement).toBeDefined();
+ expect(document.activeElement).toEqual(document.querySelector(SEARCH_INPUT_SELECTOR));
});
it('should focus on input when opening for the second time after transition', () => {
@@ -215,7 +217,8 @@ describe('deprecatedJQueryDropdown', () => {
test.dropdownButtonElement.click();
test.dropdownContainerElement.trigger('transitionend');
- expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR));
+ expect(document.activeElement).toBeDefined();
+ expect(document.activeElement).toEqual(document.querySelector(SEARCH_INPUT_SELECTOR));
});
});
@@ -225,7 +228,8 @@ describe('deprecatedJQueryDropdown', () => {
test.dropdownButtonElement.click();
test.dropdownContainerElement.trigger('transitionend');
- expect($(document.activeElement)).toEqual($(SEARCH_INPUT_SELECTOR));
+ expect(document.activeElement).toBeDefined();
+ expect(document.activeElement).toEqual(document.querySelector(SEARCH_INPUT_SELECTOR));
});
});
diff --git a/spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap b/spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap
index 8cfe11c9040..ef1ed9bee51 100644
--- a/spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap
+++ b/spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap
@@ -2,7 +2,7 @@
exports[`Design management index page designs renders error 1`] = `
<div
- class="gl-mt-5"
+ class="gl-mt-4"
data-testid="designs-root"
>
<!---->
@@ -34,7 +34,7 @@ exports[`Design management index page designs renders error 1`] = `
exports[`Design management index page designs renders loading icon 1`] = `
<div
- class="gl-mt-5"
+ class="gl-mt-4"
data-testid="designs-root"
>
<!---->
diff --git a/spec/frontend/diffs/components/diff_row_utils_spec.js b/spec/frontend/diffs/components/diff_row_utils_spec.js
index 8b25691ce34..a6f508c73eb 100644
--- a/spec/frontend/diffs/components/diff_row_utils_spec.js
+++ b/spec/frontend/diffs/components/diff_row_utils_spec.js
@@ -9,6 +9,18 @@ import {
const LINE_CODE = 'abc123';
+function problemsClone({
+ brokenSymlink = false,
+ brokenLineCode = false,
+ fileOnlyMoved = false,
+} = {}) {
+ return {
+ brokenSymlink,
+ brokenLineCode,
+ fileOnlyMoved,
+ };
+}
+
describe('isHighlighted', () => {
it('should return true if line is highlighted', () => {
const line = { line_code: LINE_CODE };
@@ -137,9 +149,12 @@ describe('classNameMapCell', () => {
describe('addCommentTooltip', () => {
const brokenSymLinkTooltip =
- 'Commenting on symbolic links that replace or are replaced by files is currently not supported.';
+ 'Commenting on symbolic links that replace or are replaced by files is not supported';
const brokenRealTooltip =
- 'Commenting on files that replace or are replaced by symbolic links is currently not supported.';
+ 'Commenting on files that replace or are replaced by symbolic links is not supported';
+ const lineMovedOrRenamedFileTooltip =
+ 'Commenting on files that are only moved or renamed is not supported';
+ const lineWithNoLineCodeTooltip = 'Commenting on this line is not supported';
const dragTooltip = 'Add a comment to this line or drag for multiple lines';
it('should return default tooltip', () => {
@@ -147,24 +162,38 @@ describe('addCommentTooltip', () => {
});
it('should return drag comment tooltip when dragging is enabled', () => {
- expect(utils.addCommentTooltip({})).toEqual(dragTooltip);
+ expect(utils.addCommentTooltip({ problems: problemsClone() })).toEqual(dragTooltip);
});
it('should return broken symlink tooltip', () => {
- expect(utils.addCommentTooltip({ commentsDisabled: { wasSymbolic: true } })).toEqual(
- brokenSymLinkTooltip,
- );
- expect(utils.addCommentTooltip({ commentsDisabled: { isSymbolic: true } })).toEqual(
- brokenSymLinkTooltip,
- );
+ expect(
+ utils.addCommentTooltip({
+ problems: problemsClone({ brokenSymlink: { wasSymbolic: true } }),
+ }),
+ ).toEqual(brokenSymLinkTooltip);
+ expect(
+ utils.addCommentTooltip({ problems: problemsClone({ brokenSymlink: { isSymbolic: true } }) }),
+ ).toEqual(brokenSymLinkTooltip);
});
it('should return broken real tooltip', () => {
- expect(utils.addCommentTooltip({ commentsDisabled: { wasReal: true } })).toEqual(
- brokenRealTooltip,
+ expect(
+ utils.addCommentTooltip({ problems: problemsClone({ brokenSymlink: { wasReal: true } }) }),
+ ).toEqual(brokenRealTooltip);
+ expect(
+ utils.addCommentTooltip({ problems: problemsClone({ brokenSymlink: { isReal: true } }) }),
+ ).toEqual(brokenRealTooltip);
+ });
+
+ it('reports a tooltip when the line is in a file that has only been moved or renamed', () => {
+ expect(utils.addCommentTooltip({ problems: problemsClone({ fileOnlyMoved: true }) })).toEqual(
+ lineMovedOrRenamedFileTooltip,
);
- expect(utils.addCommentTooltip({ commentsDisabled: { isReal: true } })).toEqual(
- brokenRealTooltip,
+ });
+
+ it("reports a tooltip when the line doesn't have a line code to leave a comment on", () => {
+ expect(utils.addCommentTooltip({ problems: problemsClone({ brokenLineCode: true }) })).toEqual(
+ lineWithNoLineCodeTooltip,
);
});
});
@@ -211,6 +240,7 @@ describe('mapParallel', () => {
discussions: [{}],
discussionsExpanded: true,
hasForm: true,
+ problems: problemsClone(),
};
const content = {
diffFile: {},
diff --git a/spec/frontend/diffs/mock_data/diff_file.js b/spec/frontend/diffs/mock_data/diff_file.js
index dd200b0248c..e0e5778e0d5 100644
--- a/spec/frontend/diffs/mock_data/diff_file.js
+++ b/spec/frontend/diffs/mock_data/diff_file.js
@@ -1,3 +1,11 @@
+function problemsClone() {
+ return {
+ brokenSymlink: false,
+ brokenLineCode: false,
+ fileOnlyMoved: false,
+ };
+}
+
export const getDiffFileMock = () => ({
submodule: false,
submodule_link: null,
@@ -61,6 +69,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
rich_text: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
meta_data: null,
+ problems: problemsClone(),
},
{
line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_2',
@@ -71,6 +80,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC2" class="line" lang="plaintext"></span>\n',
rich_text: '<span id="LC2" class="line" lang="plaintext"></span>\n',
meta_data: null,
+ problems: problemsClone(),
},
{
line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3',
@@ -81,6 +91,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
rich_text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
meta_data: null,
+ problems: problemsClone(),
},
{
line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_2_4',
@@ -91,6 +102,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
rich_text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
meta_data: null,
+ problems: problemsClone(),
},
{
line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_3_5',
@@ -101,6 +113,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
rich_text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
meta_data: null,
+ problems: problemsClone(),
},
{
line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_6',
@@ -111,6 +124,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC6" class="line" lang="plaintext"></span>\n',
rich_text: '<span id="LC6" class="line" lang="plaintext"></span>\n',
meta_data: null,
+ problems: problemsClone(),
},
{
line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_7',
@@ -121,6 +135,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
rich_text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
meta_data: null,
+ problems: problemsClone(),
},
{
line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_9',
@@ -131,6 +146,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
rich_text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
meta_data: null,
+ problems: problemsClone(),
},
{
line_code: null,
@@ -144,6 +160,7 @@ export const getDiffFileMock = () => ({
old_pos: 3,
new_pos: 5,
},
+ problems: problemsClone(),
},
],
parallel_diff_lines: [
@@ -158,6 +175,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
rich_text: '<span id="LC1" class="line" lang="plaintext"> - Bad dates</span>\n',
meta_data: null,
+ problems: problemsClone(),
},
},
{
@@ -171,6 +189,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC2" class="line" lang="plaintext"></span>\n',
rich_text: '<span id="LC2" class="line" lang="plaintext"></span>\n',
meta_data: null,
+ problems: problemsClone(),
},
},
{
@@ -183,6 +202,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
rich_text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
meta_data: null,
+ problems: problemsClone(),
},
right: {
line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3',
@@ -193,6 +213,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
rich_text: '<span id="LC3" class="line" lang="plaintext">v6.8.0</span>\n',
meta_data: null,
+ problems: problemsClone(),
},
},
{
@@ -205,6 +226,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
rich_text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
meta_data: null,
+ problems: problemsClone(),
},
right: {
line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_2_4',
@@ -215,6 +237,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
rich_text: '<span id="LC4" class="line" lang="plaintext"></span>\n',
meta_data: null,
+ problems: problemsClone(),
},
},
{
@@ -227,6 +250,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
rich_text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
meta_data: null,
+ problems: problemsClone(),
},
right: {
line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_3_5',
@@ -237,6 +261,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
rich_text: '<span id="LC5" class="line" lang="plaintext">v6.7.0</span>\n',
meta_data: null,
+ problems: problemsClone(),
},
},
{
@@ -249,6 +274,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC6" class="line" lang="plaintext"></span>\n',
rich_text: '<span id="LC6" class="line" lang="plaintext"></span>\n',
meta_data: null,
+ problems: problemsClone(),
},
right: {
line_code: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_7',
@@ -259,6 +285,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
rich_text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
meta_data: null,
+ problems: problemsClone(),
},
},
{
@@ -272,6 +299,7 @@ export const getDiffFileMock = () => ({
text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
rich_text: '<span id="LC7" class="line" lang="plaintext"></span>\n',
meta_data: null,
+ problems: problemsClone(),
},
},
{
@@ -287,6 +315,7 @@ export const getDiffFileMock = () => ({
old_pos: 3,
new_pos: 5,
},
+ problems: problemsClone(),
},
right: {
line_code: null,
@@ -300,6 +329,7 @@ export const getDiffFileMock = () => ({
old_pos: 3,
new_pos: 5,
},
+ problems: problemsClone(),
},
},
],
diff --git a/spec/frontend/diffs/store/actions_spec.js b/spec/frontend/diffs/store/actions_spec.js
index bf75f956d7f..87366cdbfc5 100644
--- a/spec/frontend/diffs/store/actions_spec.js
+++ b/spec/frontend/diffs/store/actions_spec.js
@@ -183,11 +183,11 @@ describe('DiffsStoreActions', () => {
beforeEach(() => {
delete noFilesData.diff_files;
-
- mock.onGet(endpointMetadata).reply(200, diffMetadata);
});
it('should fetch diff meta information', () => {
+ mock.onGet(endpointMetadata).reply(200, diffMetadata);
+
return testAction(
diffActions.fetchDiffFilesMeta,
{},
@@ -206,6 +206,40 @@ describe('DiffsStoreActions', () => {
[],
);
});
+
+ it('should show a warning on 404 reponse', async () => {
+ mock.onGet(endpointMetadata).reply(404);
+
+ await testAction(
+ diffActions.fetchDiffFilesMeta,
+ {},
+ { endpointMetadata, diffViewType: 'inline', showWhitespace: true },
+ [{ type: types.SET_LOADING, payload: true }],
+ [],
+ );
+
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith({
+ message: expect.stringMatching(
+ 'Building your merge request. Wait a few moments, then refresh this page.',
+ ),
+ variant: 'warning',
+ });
+ });
+
+ it('should show no warning on any other status code', async () => {
+ mock.onGet(endpointMetadata).reply(500);
+
+ await testAction(
+ diffActions.fetchDiffFilesMeta,
+ {},
+ { endpointMetadata, diffViewType: 'inline', showWhitespace: true },
+ [{ type: types.SET_LOADING, payload: true }],
+ [],
+ );
+
+ expect(createAlert).not.toHaveBeenCalled();
+ });
});
describe('fetchCoverageFiles', () => {
diff --git a/spec/frontend/diffs/store/utils_spec.js b/spec/frontend/diffs/store/utils_spec.js
index 3f870a98396..b5c44b084d8 100644
--- a/spec/frontend/diffs/store/utils_spec.js
+++ b/spec/frontend/diffs/store/utils_spec.js
@@ -311,9 +311,14 @@ describe('DiffsStoreUtils', () => {
describe('prepareLineForRenamedFile', () => {
const diffFile = {
file_hash: 'file-hash',
+ brokenSymlink: false,
+ renamed_file: false,
+ added_lines: 1,
+ removed_lines: 1,
};
const lineIndex = 4;
const sourceLine = {
+ line_code: 'abc',
foo: 'test',
rich_text: ' <p>rich</p>', // Note the leading space
};
@@ -328,6 +333,12 @@ describe('DiffsStoreUtils', () => {
hasForm: false,
text: undefined,
alreadyPrepared: true,
+ commentsDisabled: false,
+ problems: {
+ brokenLineCode: false,
+ brokenSymlink: false,
+ fileOnlyMoved: false,
+ },
};
let preppedLine;
@@ -360,24 +371,35 @@ describe('DiffsStoreUtils', () => {
});
it.each`
- brokenSymlink
- ${false}
- ${{}}
- ${'anything except `false`'}
+ brokenSymlink | renamed | added | removed | lineCode | commentsDisabled
+ ${false} | ${false} | ${0} | ${0} | ${'a'} | ${false}
+ ${{}} | ${false} | ${1} | ${1} | ${'a'} | ${true}
+ ${'truthy'} | ${false} | ${1} | ${1} | ${'a'} | ${true}
+ ${false} | ${true} | ${1} | ${1} | ${'a'} | ${false}
+ ${false} | ${true} | ${1} | ${0} | ${'a'} | ${false}
+ ${false} | ${true} | ${0} | ${1} | ${'a'} | ${false}
+ ${false} | ${true} | ${0} | ${0} | ${'a'} | ${true}
`(
- "properly assigns each line's `commentsDisabled` as the same value as the parent file's `brokenSymlink` value (`$brokenSymlink`)",
- ({ brokenSymlink }) => {
- preppedLine = utils.prepareLineForRenamedFile({
- diffViewType: INLINE_DIFF_VIEW_TYPE,
- line: sourceLine,
+ "properly sets a line's `commentsDisabled` to '$commentsDisabled' for file and line settings { brokenSymlink: $brokenSymlink, renamed: $renamed, added: $added, removed: $removed, line_code: $lineCode }",
+ ({ brokenSymlink, renamed, added, removed, lineCode, commentsDisabled }) => {
+ const line = {
+ ...sourceLine,
+ line_code: lineCode,
+ };
+ const file = {
+ ...diffFile,
+ brokenSymlink,
+ renamed_file: renamed,
+ added_lines: added,
+ removed_lines: removed,
+ };
+ const preparedLine = utils.prepareLineForRenamedFile({
index: lineIndex,
- diffFile: {
- ...diffFile,
- brokenSymlink,
- },
+ diffFile: file,
+ line,
});
- expect(preppedLine.commentsDisabled).toStrictEqual(brokenSymlink);
+ expect(preparedLine.commentsDisabled).toBe(commentsDisabled);
},
);
});
@@ -477,7 +499,7 @@ describe('DiffsStoreUtils', () => {
it('adds the `.brokenSymlink` property to each diff file', () => {
preparedDiff.diff_files.forEach((file) => {
- expect(file).toEqual(expect.objectContaining({ brokenSymlink: false }));
+ expect(file).toHaveProperty('brokenSymlink', false);
});
});
@@ -490,7 +512,7 @@ describe('DiffsStoreUtils', () => {
].flatMap((file) => [...file[INLINE_DIFF_LINES_KEY]]);
lines.forEach((line) => {
- expect(line.commentsDisabled).toBe(false);
+ expect(line.problems.brokenSymlink).toBe(false);
});
});
});
diff --git a/spec/frontend/diffs/utils/tree_worker_utils_spec.js b/spec/frontend/diffs/utils/tree_worker_utils_spec.js
index 8113428f712..4df5fe75004 100644
--- a/spec/frontend/diffs/utils/tree_worker_utils_spec.js
+++ b/spec/frontend/diffs/utils/tree_worker_utils_spec.js
@@ -35,6 +35,23 @@ describe('~/diffs/utils/tree_worker_utils', () => {
file_hash: 'test',
},
{
+ new_path: 'constructor/test/aFile.js',
+ deleted_file: false,
+ new_file: true,
+ removed_lines: 0,
+ added_lines: 42,
+ file_hash: 'test',
+ },
+ {
+ new_path: 'submodule @ abcdef123',
+ deleted_file: false,
+ new_file: true,
+ removed_lines: 0,
+ added_lines: 1,
+ submodule: true,
+ file_hash: 'test',
+ },
+ {
new_path: 'package.json',
deleted_file: true,
new_file: false,
@@ -66,6 +83,7 @@ describe('~/diffs/utils/tree_worker_utils', () => {
path: 'app/index.js',
removedLines: 10,
tempFile: false,
+ submodule: undefined,
type: 'blob',
tree: [],
},
@@ -87,6 +105,7 @@ describe('~/diffs/utils/tree_worker_utils', () => {
path: 'app/test/index.js',
removedLines: 0,
tempFile: true,
+ submodule: undefined,
type: 'blob',
tree: [],
},
@@ -101,6 +120,7 @@ describe('~/diffs/utils/tree_worker_utils', () => {
path: 'app/test/filepathneedstruncating.js',
removedLines: 0,
tempFile: true,
+ submodule: undefined,
type: 'blob',
tree: [],
},
@@ -110,6 +130,45 @@ describe('~/diffs/utils/tree_worker_utils', () => {
opened: true,
},
{
+ key: 'constructor',
+ name: 'constructor/test',
+ opened: true,
+ path: 'constructor',
+ tree: [
+ {
+ addedLines: 42,
+ changed: true,
+ deleted: false,
+ fileHash: 'test',
+ key: 'constructor/test/aFile.js',
+ name: 'aFile.js',
+ parentPath: 'constructor/test/',
+ path: 'constructor/test/aFile.js',
+ removedLines: 0,
+ submodule: undefined,
+ tempFile: true,
+ tree: [],
+ type: 'blob',
+ },
+ ],
+ type: 'tree',
+ },
+ {
+ key: 'submodule @ abcdef123',
+ parentPath: '/',
+ path: 'submodule @ abcdef123',
+ name: 'submodule @ abcdef123',
+ type: 'blob',
+ changed: true,
+ tempFile: true,
+ submodule: true,
+ deleted: false,
+ fileHash: 'test',
+ addedLines: 1,
+ removedLines: 0,
+ tree: [],
+ },
+ {
key: 'package.json',
parentPath: '/',
path: 'package.json',
@@ -117,6 +176,7 @@ describe('~/diffs/utils/tree_worker_utils', () => {
type: 'blob',
changed: true,
tempFile: false,
+ submodule: undefined,
deleted: true,
fileHash: 'test',
addedLines: 0,
@@ -135,6 +195,10 @@ describe('~/diffs/utils/tree_worker_utils', () => {
'app/test',
'app/test/index.js',
'app/test/filepathneedstruncating.js',
+ 'constructor',
+ 'constructor/test',
+ 'constructor/test/aFile.js',
+ 'submodule @ abcdef123',
'package.json',
]);
});
diff --git a/spec/frontend/editor/schema/ci/ci_schema_spec.js b/spec/frontend/editor/schema/ci/ci_schema_spec.js
index fc86907c144..32126a5fd9a 100644
--- a/spec/frontend/editor/schema/ci/ci_schema_spec.js
+++ b/spec/frontend/editor/schema/ci/ci_schema_spec.js
@@ -18,9 +18,7 @@ import VariablesJson from './json_tests/positive_tests/variables.json';
import DefaultNoAdditionalPropertiesJson from './json_tests/negative_tests/default_no_additional_properties.json';
import InheritDefaultNoAdditionalPropertiesJson from './json_tests/negative_tests/inherit_default_no_additional_properties.json';
import JobVariablesMustNotContainObjectsJson from './json_tests/negative_tests/job_variables_must_not_contain_objects.json';
-import ReleaseAssetsLinksEmptyJson from './json_tests/negative_tests/release_assets_links_empty.json';
-import ReleaseAssetsLinksInvalidLinkTypeJson from './json_tests/negative_tests/release_assets_links_invalid_link_type.json';
-import ReleaseAssetsLinksMissingJson from './json_tests/negative_tests/release_assets_links_missing.json';
+import ReleaseAssetsLinksJson from './json_tests/negative_tests/release_assets_links.json';
import RetryUnknownWhenJson from './json_tests/negative_tests/retry_unknown_when.json';
// YAML POSITIVE TEST
@@ -31,34 +29,22 @@ import IncludeYaml from './yaml_tests/positive_tests/include.yml';
import RulesYaml from './yaml_tests/positive_tests/rules.yml';
import ProjectPathYaml from './yaml_tests/positive_tests/project_path.yml';
import VariablesYaml from './yaml_tests/positive_tests/variables.yml';
+import JobWhenYaml from './yaml_tests/positive_tests/job_when.yml';
// YAML NEGATIVE TEST
import ArtifactsNegativeYaml from './yaml_tests/negative_tests/artifacts.yml';
-import CacheNegativeYaml from './yaml_tests/negative_tests/cache.yml';
+import CacheKeyNeative from './yaml_tests/negative_tests/cache.yml';
import IncludeNegativeYaml from './yaml_tests/negative_tests/include.yml';
-import RulesNegativeYaml from './yaml_tests/negative_tests/rules.yml';
-import VariablesNegativeYaml from './yaml_tests/negative_tests/variables.yml';
-
+import JobWhenNegativeYaml from './yaml_tests/negative_tests/job_when.yml';
import ProjectPathIncludeEmptyYaml from './yaml_tests/negative_tests/project_path/include/empty.yml';
import ProjectPathIncludeInvalidVariableYaml from './yaml_tests/negative_tests/project_path/include/invalid_variable.yml';
import ProjectPathIncludeLeadSlashYaml from './yaml_tests/negative_tests/project_path/include/leading_slash.yml';
import ProjectPathIncludeNoSlashYaml from './yaml_tests/negative_tests/project_path/include/no_slash.yml';
import ProjectPathIncludeTailSlashYaml from './yaml_tests/negative_tests/project_path/include/tailing_slash.yml';
-import ProjectPathTriggerIncludeEmptyYaml from './yaml_tests/negative_tests/project_path/trigger/include/empty.yml';
-import ProjectPathTriggerIncludeInvalidVariableYaml from './yaml_tests/negative_tests/project_path/trigger/include/invalid_variable.yml';
-import ProjectPathTriggerIncludeLeadSlashYaml from './yaml_tests/negative_tests/project_path/trigger/include/leading_slash.yml';
-import ProjectPathTriggerIncludeNoSlashYaml from './yaml_tests/negative_tests/project_path/trigger/include/no_slash.yml';
-import ProjectPathTriggerIncludeTailSlashYaml from './yaml_tests/negative_tests/project_path/trigger/include/tailing_slash.yml';
-import ProjectPathTriggerMinimalEmptyYaml from './yaml_tests/negative_tests/project_path/trigger/minimal/empty.yml';
-import ProjectPathTriggerMinimalInvalidVariableYaml from './yaml_tests/negative_tests/project_path/trigger/minimal/invalid_variable.yml';
-import ProjectPathTriggerMinimalLeadSlashYaml from './yaml_tests/negative_tests/project_path/trigger/minimal/leading_slash.yml';
-import ProjectPathTriggerMinimalNoSlashYaml from './yaml_tests/negative_tests/project_path/trigger/minimal/no_slash.yml';
-import ProjectPathTriggerMinimalTailSlashYaml from './yaml_tests/negative_tests/project_path/trigger/minimal/tailing_slash.yml';
-import ProjectPathTriggerProjectEmptyYaml from './yaml_tests/negative_tests/project_path/trigger/project/empty.yml';
-import ProjectPathTriggerProjectInvalidVariableYaml from './yaml_tests/negative_tests/project_path/trigger/project/invalid_variable.yml';
-import ProjectPathTriggerProjectLeadSlashYaml from './yaml_tests/negative_tests/project_path/trigger/project/leading_slash.yml';
-import ProjectPathTriggerProjectNoSlashYaml from './yaml_tests/negative_tests/project_path/trigger/project/no_slash.yml';
-import ProjectPathTriggerProjectTailSlashYaml from './yaml_tests/negative_tests/project_path/trigger/project/tailing_slash.yml';
+import RulesNegativeYaml from './yaml_tests/negative_tests/rules.yml';
+import TriggerNegative from './yaml_tests/negative_tests/trigger.yml';
+import VariablesInvalidSyntaxDescYaml from './yaml_tests/negative_tests/variables/invalid_syntax_desc.yml';
+import VariablesWrongSyntaxUsageExpand from './yaml_tests/negative_tests/variables/wrong_syntax_usage_expand.yml';
const ajv = new Ajv({
strictTypes: false,
@@ -68,7 +54,7 @@ const ajv = new Ajv({
ajv.addKeyword('markdownDescription');
AjvFormats(ajv);
-const schema = ajv.compile(CiSchema);
+const ajvSchema = ajv.compile(CiSchema);
describe('positive tests', () => {
it.each(
@@ -90,12 +76,17 @@ describe('positive tests', () => {
CacheYaml,
FilterYaml,
IncludeYaml,
+ JobWhenYaml,
RulesYaml,
VariablesYaml,
ProjectPathYaml,
}),
)('schema validates %s', (_, input) => {
- expect(input).toValidateJsonSchema(schema);
+ // We construct a new "JSON" from each main key that is inside a
+ // file which allow us to make sure each blob is valid.
+ Object.keys(input).forEach((key) => {
+ expect({ [key]: input[key] }).toValidateJsonSchema(ajvSchema);
+ });
});
});
@@ -106,39 +97,29 @@ describe('negative tests', () => {
DefaultNoAdditionalPropertiesJson,
JobVariablesMustNotContainObjectsJson,
InheritDefaultNoAdditionalPropertiesJson,
- ReleaseAssetsLinksEmptyJson,
- ReleaseAssetsLinksInvalidLinkTypeJson,
- ReleaseAssetsLinksMissingJson,
+ ReleaseAssetsLinksJson,
RetryUnknownWhenJson,
// YAML
ArtifactsNegativeYaml,
- CacheNegativeYaml,
+ CacheKeyNeative,
IncludeNegativeYaml,
+ JobWhenNegativeYaml,
RulesNegativeYaml,
- VariablesNegativeYaml,
+ VariablesInvalidSyntaxDescYaml,
+ VariablesWrongSyntaxUsageExpand,
ProjectPathIncludeEmptyYaml,
ProjectPathIncludeInvalidVariableYaml,
ProjectPathIncludeLeadSlashYaml,
ProjectPathIncludeNoSlashYaml,
ProjectPathIncludeTailSlashYaml,
- ProjectPathTriggerIncludeEmptyYaml,
- ProjectPathTriggerIncludeInvalidVariableYaml,
- ProjectPathTriggerIncludeLeadSlashYaml,
- ProjectPathTriggerIncludeNoSlashYaml,
- ProjectPathTriggerIncludeTailSlashYaml,
- ProjectPathTriggerMinimalEmptyYaml,
- ProjectPathTriggerMinimalInvalidVariableYaml,
- ProjectPathTriggerMinimalLeadSlashYaml,
- ProjectPathTriggerMinimalNoSlashYaml,
- ProjectPathTriggerMinimalTailSlashYaml,
- ProjectPathTriggerProjectEmptyYaml,
- ProjectPathTriggerProjectInvalidVariableYaml,
- ProjectPathTriggerProjectLeadSlashYaml,
- ProjectPathTriggerProjectNoSlashYaml,
- ProjectPathTriggerProjectTailSlashYaml,
+ TriggerNegative,
}),
)('schema validates %s', (_, input) => {
- expect(input).not.toValidateJsonSchema(schema);
+ // We construct a new "JSON" from each main key that is inside a
+ // file which allow us to make sure each blob is invalid.
+ Object.keys(input).forEach((key) => {
+ expect({ [key]: input[key] }).not.toValidateJsonSchema(ajvSchema);
+ });
});
});
diff --git a/spec/frontend/editor/schema/ci/json_tests/negative_tests/default_no_additional_properties.json b/spec/frontend/editor/schema/ci/json_tests/negative_tests/default_no_additional_properties.json
index 955c19ef1ab..d30bc4649ab 100644
--- a/spec/frontend/editor/schema/ci/json_tests/negative_tests/default_no_additional_properties.json
+++ b/spec/frontend/editor/schema/ci/json_tests/negative_tests/default_no_additional_properties.json
@@ -9,4 +9,4 @@
"name": "test"
}
}
-}
+} \ No newline at end of file
diff --git a/spec/frontend/editor/schema/ci/json_tests/negative_tests/inherit_default_no_additional_properties.json b/spec/frontend/editor/schema/ci/json_tests/negative_tests/inherit_default_no_additional_properties.json
index 7411e4c2434..1a31467f9ae 100644
--- a/spec/frontend/editor/schema/ci/json_tests/negative_tests/inherit_default_no_additional_properties.json
+++ b/spec/frontend/editor/schema/ci/json_tests/negative_tests/inherit_default_no_additional_properties.json
@@ -1,8 +1,10 @@
{
"karma": {
"inherit": {
- "default": ["secrets"]
+ "default": [
+ "secrets"
+ ]
},
"script": "karma"
}
-}
+} \ No newline at end of file
diff --git a/spec/frontend/editor/schema/ci/json_tests/negative_tests/job_variables_must_not_contain_objects.json b/spec/frontend/editor/schema/ci/json_tests/negative_tests/job_variables_must_not_contain_objects.json
index bfdbf26ee70..68dd57824ab 100644
--- a/spec/frontend/editor/schema/ci/json_tests/negative_tests/job_variables_must_not_contain_objects.json
+++ b/spec/frontend/editor/schema/ci/json_tests/negative_tests/job_variables_must_not_contain_objects.json
@@ -1,7 +1,9 @@
{
"gitlab-ci-variables-object": {
"stage": "test",
- "script": ["true"],
+ "script": [
+ "true"
+ ],
"variables": {
"DEPLOY_ENVIRONMENT": {
"value": "staging",
@@ -9,4 +11,4 @@
}
}
}
-}
+} \ No newline at end of file
diff --git a/spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links.json b/spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links.json
new file mode 100644
index 00000000000..00b5b54c7e2
--- /dev/null
+++ b/spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links.json
@@ -0,0 +1,44 @@
+{
+ "gitlab-ci-release-assets-links-missing": {
+ "script": "dostuff",
+ "stage": "deploy",
+ "release": {
+ "description": "Created using the release-cli $EXTRA_DESCRIPTION",
+ "tag_name": "$CI_COMMIT_TAG",
+ "assets": {}
+ }
+ },
+ "gitlab-ci-release-assets-links-empty": {
+ "script": "dostuff",
+ "stage": "deploy",
+ "release": {
+ "description": "Created using the release-cli $EXTRA_DESCRIPTION",
+ "tag_name": "$CI_COMMIT_TAG",
+ "assets": {
+ "links": []
+ }
+ }
+ },
+ "gitlab-ci-release-assets-links-invalid-link-type": {
+ "script": "dostuff",
+ "stage": "deploy",
+ "release": {
+ "description": "Created using the release-cli $EXTRA_DESCRIPTION",
+ "tag_name": "$CI_COMMIT_TAG",
+ "assets": {
+ "links": [
+ {
+ "name": "asset1",
+ "url": "https://example.com/assets/1"
+ },
+ {
+ "name": "asset2",
+ "url": "https://example.com/assets/2",
+ "filepath": "/pretty/url/1",
+ "link_type": "invalid"
+ }
+ ]
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links_empty.json b/spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links_empty.json
deleted file mode 100644
index 84a1aa14698..00000000000
--- a/spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links_empty.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "gitlab-ci-release-assets-links-empty": {
- "script": "dostuff",
- "stage": "deploy",
- "release": {
- "description": "Created using the release-cli $EXTRA_DESCRIPTION",
- "tag_name": "$CI_COMMIT_TAG",
- "assets": {
- "links": []
- }
- }
- }
-}
diff --git a/spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links_invalid_link_type.json b/spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links_invalid_link_type.json
deleted file mode 100644
index 048911aefa3..00000000000
--- a/spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links_invalid_link_type.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "gitlab-ci-release-assets-links-invalid-link-type": {
- "script": "dostuff",
- "stage": "deploy",
- "release": {
- "description": "Created using the release-cli $EXTRA_DESCRIPTION",
- "tag_name": "$CI_COMMIT_TAG",
- "assets": {
- "links": [
- {
- "name": "asset1",
- "url": "https://example.com/assets/1"
- },
- {
- "name": "asset2",
- "url": "https://example.com/assets/2",
- "filepath": "/pretty/url/1",
- "link_type": "invalid"
- }
- ]
- }
- }
- }
-}
diff --git a/spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links_missing.json b/spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links_missing.json
deleted file mode 100644
index 6f0b5a3bff8..00000000000
--- a/spec/frontend/editor/schema/ci/json_tests/negative_tests/release_assets_links_missing.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "gitlab-ci-release-assets-links-missing": {
- "script": "dostuff",
- "stage": "deploy",
- "release": {
- "description": "Created using the release-cli $EXTRA_DESCRIPTION",
- "tag_name": "$CI_COMMIT_TAG",
- "assets": {}
- }
- }
-}
diff --git a/spec/frontend/editor/schema/ci/json_tests/negative_tests/retry_unknown_when.json b/spec/frontend/editor/schema/ci/json_tests/negative_tests/retry_unknown_when.json
index 433504f52c6..2c53ce07109 100644
--- a/spec/frontend/editor/schema/ci/json_tests/negative_tests/retry_unknown_when.json
+++ b/spec/frontend/editor/schema/ci/json_tests/negative_tests/retry_unknown_when.json
@@ -6,4 +6,4 @@
"when": "gitlab-ci-retry-object-unknown-when"
}
}
-}
+} \ No newline at end of file
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/cache.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/cache.yml
index 04020c06753..3979c9ae2ac 100644
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/cache.yml
+++ b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/cache.yml
@@ -1,13 +1,62 @@
-stages:
- - prepare
+cache-key-files-not-an-array:
+ script: echo "This job uses a cache."
+ cache:
+ key:
+ files: package.json
+ paths:
+ - vendor/ruby
+ - node_modules
+
+cache-key-prefix-array:
+ script: echo "This job uses a cache."
+ cache:
+ key:
+ files:
+ - Gemfile.lock
+ prefix:
+ - binaries-cache-$CI_JOB_NAME
+ paths:
+ - binaries/
+
+cache-key-with-.:
+ script: echo "This job uses a cache."
+ cache:
+ key: .
+ paths:
+ - binaries/
+
+cache-key-with-multiple-.:
+ stage: test
+ script: echo "This job uses a cache."
+ cache:
+ key: ..
+ paths:
+ - binaries/
+
+cache-key-with-/:
+ script: echo "This job uses a cache."
+ cache:
+ key: binaries-ca/che
+ paths:
+ - binaries/
+
+cache-path-not-an-array:
+ script: echo "This job uses a cache."
+ cache:
+ key: binaries-cache
+ paths: binaries/*.apk
+
+cache-untracked-string:
+ script: echo "This job uses a cache."
+ cache:
+ untracked: 'true'
-# invalid cache:when values
-when no integer:
- stage: prepare
+when_integer:
+ script: echo "This job uses a cache."
cache:
when: 0
-when must be a reserved word:
- stage: prepare
+when_not_reserved_keyword:
+ script: echo "This job uses a cache."
cache:
when: 'never'
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/include.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/include.yml
index 1e16bb55405..6afd8baa0e8 100644
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/include.yml
+++ b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/include.yml
@@ -1,6 +1,3 @@
-stages:
- - prepare
-
# invalid trigger:include
trigger missing file property:
stage: prepare
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/job_when.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/job_when.yml
new file mode 100644
index 00000000000..d4e3911ff60
--- /dev/null
+++ b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/job_when.yml
@@ -0,0 +1,11 @@
+job_with_wrong_when:
+ script: exit 0
+ when: on_xyz
+
+job_with_boolean_when:
+ script: exit 0
+ when: true
+
+job_with_array_when:
+ script: exit 0
+ when: [on_success]
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/empty.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/empty.yml
deleted file mode 100644
index ee2bb3e8ace..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/empty.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-trigger-include:
- trigger:
- include:
- - file: '/path/to/child-pipeline.yml'
- project: ''
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/invalid_variable.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/invalid_variable.yml
deleted file mode 100644
index 770305be0dc..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/invalid_variable.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-trigger-include:
- trigger:
- include:
- - file: '/path/to/child-pipeline.yml'
- project: 'slug#'
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/leading_slash.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/leading_slash.yml
deleted file mode 100644
index 82fd77cf0d3..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/leading_slash.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-trigger-include:
- trigger:
- include:
- - file: '/path/to/child-pipeline.yml'
- project: '/slug'
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/no_slash.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/no_slash.yml
deleted file mode 100644
index f4ea59c7945..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/no_slash.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-trigger-include:
- trigger:
- include:
- - file: '/path/to/child-pipeline.yml'
- project: 'slug'
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/tailing_slash.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/tailing_slash.yml
deleted file mode 100644
index a0195c03352..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/include/tailing_slash.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-trigger-include:
- trigger:
- include:
- - file: '/path/to/child-pipeline.yml'
- project: 'slug/'
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/empty.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/empty.yml
deleted file mode 100644
index cad8dbbf430..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/empty.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-trigger-minimal:
- trigger: ''
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/invalid_variable.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/invalid_variable.yml
deleted file mode 100644
index 6ca37666d09..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/invalid_variable.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-trigger-minimal:
- trigger: 'slug#'
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/leading_slash.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/leading_slash.yml
deleted file mode 100644
index 9d7c6b44125..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/leading_slash.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-trigger-minimal:
- trigger: '/slug'
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/no_slash.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/no_slash.yml
deleted file mode 100644
index acd047477c8..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/no_slash.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-trigger-minimal:
- trigger: 'slug'
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/tailing_slash.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/tailing_slash.yml
deleted file mode 100644
index 0fdd00da3de..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/minimal/tailing_slash.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-trigger-minimal:
- trigger: 'slug/'
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/empty.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/empty.yml
deleted file mode 100644
index 0aa2330cecb..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/empty.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-trigger-project:
- trigger:
- project: ''
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/invalid_variable.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/invalid_variable.yml
deleted file mode 100644
index 3c17ec62039..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/invalid_variable.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-trigger-project:
- trigger:
- project: 'slug#'
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/leading_slash.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/leading_slash.yml
deleted file mode 100644
index f9884603171..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/leading_slash.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-trigger-project:
- trigger:
- project: '/slug'
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/no_slash.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/no_slash.yml
deleted file mode 100644
index d89e09756eb..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/no_slash.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-trigger-project:
- trigger:
- project: 'slug'
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/tailing_slash.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/tailing_slash.yml
deleted file mode 100644
index 3c39d6be4cb..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/project_path/trigger/project/tailing_slash.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-trigger-project:
- trigger:
- project: 'slug/'
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/trigger.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/trigger.yml
new file mode 100644
index 00000000000..73cc82f2f1c
--- /dev/null
+++ b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/trigger.yml
@@ -0,0 +1,64 @@
+trigger-minimal-empty:
+ trigger: ''
+
+trigger-minimal-invalid-variable:
+ trigger: 'slug#'
+
+trigger-minimal-leading-slash:
+ trigger: '/slug'
+
+trigger-minimal-no-slash:
+ trigger: 'slug'
+
+trigger-minimal-trailing-slash:
+ trigger: 'slug/'
+
+trigger-project-empty:
+ trigger:
+ project: ''
+
+trigger-project-invalid-variable:
+ trigger:
+ project: 'slug#'
+
+trigger-project-leading-slash:
+ trigger:
+ project: '/slug'
+
+trigger-project-no-slash:
+ trigger:
+ project: 'slug'
+
+trigger-project-trailing-slash:
+ trigger:
+ project: 'slug/'
+
+trigger-include-empty:
+ trigger:
+ include:
+ - file: '/path/to/child-pipeline.yml'
+ project: ''
+
+trigger-include-invalid:
+ trigger:
+ include:
+ - file: '/path/to/child-pipeline.yml'
+ project: 'slug#'
+
+trigger-include-leading-slash:
+ trigger:
+ include:
+ - file: '/path/to/child-pipeline.yml'
+ project: '/slug'
+
+trigger-include-no-slash:
+ trigger:
+ include:
+ - file: '/path/to/child-pipeline.yml'
+ project: 'slug'
+
+trigger-include-trailing-slash:
+ trigger:
+ include:
+ - file: '/path/to/child-pipeline.yml'
+ project: 'slug/'
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/variables.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/variables.yml
deleted file mode 100644
index a7f23cf0d73..00000000000
--- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/variables.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-# invalid variable (unknown keyword is used)
-variables:
- FOO:
- value: BAR
- desc: A single value variable
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/variables/invalid_syntax_desc.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/variables/invalid_syntax_desc.yml
new file mode 100644
index 00000000000..4916a6b354e
--- /dev/null
+++ b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/variables/invalid_syntax_desc.yml
@@ -0,0 +1,4 @@
+variables:
+ FOO:
+ value: BAR
+ desc: A single value variable
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/variables/wrong_syntax_usage_expand.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/variables/wrong_syntax_usage_expand.yml
new file mode 100644
index 00000000000..62bebfa57e7
--- /dev/null
+++ b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/variables/wrong_syntax_usage_expand.yml
@@ -0,0 +1,4 @@
+variables:
+ RAW_VAR:
+ value: Hello $FOO
+ expand: okay
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/cache.yml b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/cache.yml
index d83e14fdc6a..75918cd2a1b 100644
--- a/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/cache.yml
+++ b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/cache.yml
@@ -1,24 +1,124 @@
-stages:
- - prepare
-
# valid cache:when values
job1:
- stage: prepare
script:
- echo 'running job'
cache:
when: 'on_success'
job2:
- stage: prepare
script:
- echo 'running job'
cache:
when: 'on_failure'
job3:
- stage: prepare
script:
- echo 'running job'
cache:
when: 'always'
+
+# valid cache:paths
+cache-paths:
+ script: echo "This job uses a cache."
+ cache:
+ key: binaries-cache
+ paths:
+ - binaries/*.apk
+ - .config
+
+# valid cache:key
+cache-key-string:
+ script: echo "This job uses a cache."
+ cache:
+ key: random-string
+ paths:
+ - binaries/
+
+cache-key-string-with-dots:
+ script: echo "This job uses a cache."
+ cache:
+ key: random-..string
+ paths:
+ - binaries/
+
+cache-key-string-beginning-with-dot:
+ script: echo "This job uses a cache."
+ cache:
+ key: .random-string
+ paths:
+ - binaries/
+
+cache-key-string-ending-with-dot:
+ script: echo "This job uses a cache."
+ cache:
+ key: random-string.
+ paths:
+ - binaries/
+
+cache-key-predefined-variable:
+ script: echo "This job uses a cache."
+ cache:
+ key: $CI_COMMIT_REF_SLUG
+ paths:
+ - binaries/
+
+cache-key-combination:
+ script: echo "This job uses a cache."
+ cache:
+ key: binaries-cache-$CI_COMMIT_REF_SLUG
+ paths:
+ - binaries/
+
+# valid cache:key:files
+cache-key-files:
+ script: echo "This job uses a cache."
+ cache:
+ key:
+ files:
+ - Gemfile.lock
+ - package.json
+ paths:
+ - vendor/ruby
+ - node_modules
+
+# valide cache:key:prefix
+cache-key-prefix-string:
+ script: echo "This job uses a cache."
+ cache:
+ key:
+ files:
+ - Gemfile.lock
+ prefix: random-string
+ paths:
+ - binaries/
+
+cache-key-prefix-predefined-variable:
+ script: echo "This job uses a cache."
+ cache:
+ key:
+ files:
+ - Gemfile.lock
+ prefix: $CI_JOB_NAME
+ paths:
+ - binaries/
+
+cache-key-prefix-combination:
+ script: echo "This job uses a cache."
+ cache:
+ key:
+ files:
+ - Gemfile.lock
+ prefix: binaries-cache-$CI_JOB_NAME
+ paths:
+ - binaries/
+
+# valid cache:untracked
+cache-untracked-true:
+ script: test
+ cache:
+ untracked: true
+
+cache-untracked-false:
+ script: test
+ cache:
+ untracked: false
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/job_when.yml b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/job_when.yml
new file mode 100644
index 00000000000..2a684a78f4e
--- /dev/null
+++ b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/job_when.yml
@@ -0,0 +1,10 @@
+job_with_no_when:
+ script: exit 0
+
+job_with_when_always:
+ script: exit 0
+ when: always
+
+job_with_when_on_failure:
+ script: exit 0
+ when: on_failure
diff --git a/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/variables.yml b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/variables.yml
index ee71087a72e..53d020c432f 100644
--- a/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/variables.yml
+++ b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/variables.yml
@@ -6,3 +6,13 @@ variables:
description: "A single value variable"
DEPLOY_ENVIRONMENT:
description: "A multi-value variable"
+ RAW_VAR:
+ value: "Hello $FOO"
+ expand: false
+
+rspec:
+ script: rspec
+ variables:
+ RAW_VAR2:
+ value: "Hello $DEPLOY_ENVIRONMENT"
+ expand: false \ No newline at end of file
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 1ff351b6554..19ebe0e3cb7 100644
--- a/spec/frontend/editor/source_editor_markdown_livepreview_ext_spec.js
+++ b/spec/frontend/editor/source_editor_markdown_livepreview_ext_spec.js
@@ -81,9 +81,18 @@ describe('Markdown Live Preview Extension for Source Editor', () => {
},
path: previewMarkdownPath,
actionShowPreviewCondition: expect.any(Object),
+ eventEmitter: expect.any(Object),
});
});
+ it('support external preview trigger via emitter event', () => {
+ expect(panelSpy).not.toHaveBeenCalled();
+
+ instance.markdownPreview.eventEmitter.fire();
+
+ expect(panelSpy).toHaveBeenCalled();
+ });
+
describe('onDidLayoutChange', () => {
const emitter = new Emitter();
let layoutSpy;
diff --git a/spec/frontend/environments/environment_actions_spec.js b/spec/frontend/environments/environment_actions_spec.js
index 68895b194a1..48483152f7a 100644
--- a/spec/frontend/environments/environment_actions_spec.js
+++ b/spec/frontend/environments/environment_actions_spec.js
@@ -10,11 +10,7 @@ import actionMutation from '~/environments/graphql/mutations/action.mutation.gra
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
import createMockApollo from 'helpers/mock_apollo_helper';
-jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal', () => {
- return {
- confirmAction: jest.fn(),
- };
-});
+jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
const scheduledJobAction = {
name: 'scheduled action',
diff --git a/spec/frontend/environments/environment_rollback_spec.js b/spec/frontend/environments/environment_rollback_spec.js
index be61c6fcc90..5d36209f8a6 100644
--- a/spec/frontend/environments/environment_rollback_spec.js
+++ b/spec/frontend/environments/environment_rollback_spec.js
@@ -76,7 +76,7 @@ describe('Rollback Component', () => {
expect(apolloProvider.defaultClient.mutate).toHaveBeenCalledWith({
mutation: setEnvironmentToRollback,
- variables: { environment },
+ variables: { environment: { ...environment, isLastDeployment: true, retryUrl } },
});
});
});
diff --git a/spec/frontend/environments/graphql/mock_data.js b/spec/frontend/environments/graphql/mock_data.js
index d246641b94b..355b77b55c3 100644
--- a/spec/frontend/environments/graphql/mock_data.js
+++ b/spec/frontend/environments/graphql/mock_data.js
@@ -537,6 +537,7 @@ export const folder = {
export const resolvedEnvironment = {
id: 41,
+ retryUrl: '/h5bp/html5-boilerplate/-/jobs/1014/retry',
globalId: 'gid://gitlab/Environment/41',
name: 'review/hello',
state: 'available',
diff --git a/spec/frontend/filtered_search/droplab/plugins/ajax_filter_spec.js b/spec/frontend/filtered_search/droplab/plugins/ajax_filter_spec.js
index 212b9ffc8f9..c958f669f9a 100644
--- a/spec/frontend/filtered_search/droplab/plugins/ajax_filter_spec.js
+++ b/spec/frontend/filtered_search/droplab/plugins/ajax_filter_spec.js
@@ -10,6 +10,9 @@ describe('AjaxFilter', () => {
dummyConfig = {
endpoint: 'dummy endpoint',
searchKey: 'dummy search key',
+ searchValueFunction() {
+ return 'test';
+ },
};
dummyList = {
data: [],
@@ -40,7 +43,7 @@ describe('AjaxFilter', () => {
it('calls onLoadingFinished after loading data', async () => {
ajaxSpy = (url) => {
- expect(url).toBe('dummy endpoint?dummy search key=');
+ expect(url).toBe('dummy endpoint?dummy%20search%20key=test');
return Promise.resolve(dummyData);
};
@@ -51,7 +54,7 @@ describe('AjaxFilter', () => {
it('does not call onLoadingFinished if Ajax call fails', async () => {
const dummyError = new Error('My dummy is sick! :-(');
ajaxSpy = (url) => {
- expect(url).toBe('dummy endpoint?dummy search key=');
+ expect(url).toBe('dummy endpoint?dummy%20search%20key=test');
return Promise.reject(dummyError);
};
diff --git a/spec/frontend/fixtures/api_merge_requests.rb b/spec/frontend/fixtures/api_merge_requests.rb
index 7d95c506e6c..fae1f4056fb 100644
--- a/spec/frontend/fixtures/api_merge_requests.rb
+++ b/spec/frontend/fixtures/api_merge_requests.rb
@@ -7,7 +7,7 @@ RSpec.describe API::MergeRequests, '(JavaScript fixtures)', type: :request do
include JavaScriptFixturesHelpers
let_it_be(:admin) { create(:admin, name: 'root') }
- let_it_be(:namespace) { create(:namespace, name: 'gitlab-test' ) }
+ let_it_be(:namespace) { create(:namespace, name: 'gitlab-test') }
let_it_be(:project) { create(:project, :repository, namespace: namespace, path: 'lorem-ipsum') }
let_it_be(:early_mrs) do
4.times { |i| create(:merge_request, source_project: project, source_branch: "branch-#{i}") }
diff --git a/spec/frontend/fixtures/api_projects.rb b/spec/frontend/fixtures/api_projects.rb
index 5acc1095d5c..b14f402a7b9 100644
--- a/spec/frontend/fixtures/api_projects.rb
+++ b/spec/frontend/fixtures/api_projects.rb
@@ -7,7 +7,7 @@ RSpec.describe API::Projects, '(JavaScript fixtures)', type: :request do
include JavaScriptFixturesHelpers
let(:admin) { create(:admin, name: 'root') }
- let(:namespace) { create(:namespace, name: 'gitlab-test' ) }
+ let(:namespace) { create(:namespace, name: 'gitlab-test') }
let(:project) { create(:project, :repository, namespace: namespace, path: 'lorem-ipsum') }
let(:project_empty) { create(:project_empty_repo, namespace: namespace, path: 'lorem-ipsum-empty') }
diff --git a/spec/frontend/fixtures/application_settings.rb b/spec/frontend/fixtures/application_settings.rb
index b3ce23c8cd7..34e99ec647c 100644
--- a/spec/frontend/fixtures/application_settings.rb
+++ b/spec/frontend/fixtures/application_settings.rb
@@ -8,7 +8,7 @@ RSpec.describe Admin::ApplicationSettingsController, '(JavaScript fixtures)', ty
include AdminModeHelper
let(:admin) { create(:admin) }
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project_empty_repo, namespace: namespace, path: 'application-settings') }
before do
diff --git a/spec/frontend/fixtures/blob.rb b/spec/frontend/fixtures/blob.rb
index 54c5b83da3e..b7b75247a59 100644
--- a/spec/frontend/fixtures/blob.rb
+++ b/spec/frontend/fixtures/blob.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Projects::BlobController, '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project, :repository, namespace: namespace, path: 'branches-project') }
let(:user) { project.first_owner }
diff --git a/spec/frontend/fixtures/branches.rb b/spec/frontend/fixtures/branches.rb
index 6cda2f0f665..25626ed8c76 100644
--- a/spec/frontend/fixtures/branches.rb
+++ b/spec/frontend/fixtures/branches.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Branches (JavaScript fixtures)' do
include JavaScriptFixturesHelpers
- let_it_be(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let_it_be(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let_it_be(:project) { create(:project, :repository, namespace: namespace, path: 'branches-project') }
let_it_be(:user) { project.first_owner }
diff --git a/spec/frontend/fixtures/clusters.rb b/spec/frontend/fixtures/clusters.rb
index 426a76f29e0..ff15cfb62c3 100644
--- a/spec/frontend/fixtures/clusters.rb
+++ b/spec/frontend/fixtures/clusters.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Projects::ClustersController, '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project, :repository, namespace: namespace) }
let(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
let(:user) { project.first_owner }
diff --git a/spec/frontend/fixtures/deploy_keys.rb b/spec/frontend/fixtures/deploy_keys.rb
index 24d602216d8..05fca368fd5 100644
--- a/spec/frontend/fixtures/deploy_keys.rb
+++ b/spec/frontend/fixtures/deploy_keys.rb
@@ -7,7 +7,7 @@ RSpec.describe Projects::DeployKeysController, '(JavaScript fixtures)', type: :c
include AdminModeHelper
let(:admin) { create(:admin) }
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project_empty_repo, namespace: namespace, path: 'todos-project') }
let(:project2) { create(:project, :internal) }
let(:project3) { create(:project, :internal) }
diff --git a/spec/frontend/fixtures/freeze_period.rb b/spec/frontend/fixtures/freeze_period.rb
index dd16bd81b51..5aa466ef015 100644
--- a/spec/frontend/fixtures/freeze_period.rb
+++ b/spec/frontend/fixtures/freeze_period.rb
@@ -16,7 +16,7 @@ RSpec.describe 'Freeze Periods (JavaScript fixtures)' do
around do |example|
freeze_time do
# Mock time to sept 19 (intl. talk like a pirate day)
- Timecop.travel(2020, 9, 19)
+ travel_to(Time.utc(2020, 9, 19))
example.run
end
diff --git a/spec/frontend/fixtures/integrations.rb b/spec/frontend/fixtures/integrations.rb
index 45d1c400f5d..c26b9524324 100644
--- a/spec/frontend/fixtures/integrations.rb
+++ b/spec/frontend/fixtures/integrations.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Projects::Settings::IntegrationsController, '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project_empty_repo, namespace: namespace, path: 'integrations-project') }
let!(:service) { create(:custom_issue_tracker_integration, project: project) }
let(:user) { project.first_owner }
diff --git a/spec/frontend/fixtures/issues.rb b/spec/frontend/fixtures/issues.rb
index e3d88098841..bc5ece20032 100644
--- a/spec/frontend/fixtures/issues.rb
+++ b/spec/frontend/fixtures/issues.rb
@@ -6,7 +6,7 @@ RSpec.describe Projects::IssuesController, '(JavaScript fixtures)', type: :contr
include JavaScriptFixturesHelpers
let(:user) { create(:user, feed_token: 'feedtoken:coldfeed') }
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project_empty_repo, namespace: namespace, path: 'issues-project') }
render_views
diff --git a/spec/frontend/fixtures/job_artifacts.rb b/spec/frontend/fixtures/job_artifacts.rb
new file mode 100644
index 00000000000..e53cdbbaaa5
--- /dev/null
+++ b/spec/frontend/fixtures/job_artifacts.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Job Artifacts (GraphQL fixtures)' do
+ describe GraphQL::Query, type: :request do
+ include ApiHelpers
+ include GraphqlHelpers
+ include JavaScriptFixturesHelpers
+
+ let_it_be(:project) { create(:project, :repository, :public) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+ let_it_be(:user) { create(:user) }
+
+ job_artifacts_query_path = 'artifacts/graphql/queries/get_job_artifacts.query.graphql'
+
+ it "graphql/#{job_artifacts_query_path}.json" do
+ create(:ci_build, :failed, :artifacts, :trace_artifact, pipeline: pipeline)
+ create(:ci_build, :success, :artifacts, :trace_artifact, pipeline: pipeline)
+
+ query = get_graphql_query_as_string(job_artifacts_query_path)
+
+ post_graphql(query, current_user: user, variables: { projectPath: project.full_path })
+
+ expect_graphql_errors_to_be_empty
+ end
+ end
+end
diff --git a/spec/frontend/fixtures/jobs.rb b/spec/frontend/fixtures/jobs.rb
index 3657a5405a4..ac58b99875b 100644
--- a/spec/frontend/fixtures/jobs.rb
+++ b/spec/frontend/fixtures/jobs.rb
@@ -7,7 +7,7 @@ RSpec.describe 'Jobs (JavaScript fixtures)' do
include JavaScriptFixturesHelpers
include GraphqlHelpers
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project, :repository, namespace: namespace, path: 'builds-project') }
let(:user) { project.first_owner }
let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.id) }
diff --git a/spec/frontend/fixtures/labels.rb b/spec/frontend/fixtures/labels.rb
index 2445c9376e2..9b8d073e74c 100644
--- a/spec/frontend/fixtures/labels.rb
+++ b/spec/frontend/fixtures/labels.rb
@@ -6,7 +6,7 @@ RSpec.describe 'Labels (JavaScript fixtures)' do
include JavaScriptFixturesHelpers
let(:user) { create(:user) }
- let(:group) { create(:group, name: 'frontend-fixtures-group' ) }
+ let(:group) { create(:group, name: 'frontend-fixtures-group') }
let(:project) { create(:project_empty_repo, namespace: group, path: 'labels-project') }
let!(:project_label_bug) { create(:label, project: project, title: 'bug', color: '#FF0000') }
diff --git a/spec/frontend/fixtures/merge_requests.rb b/spec/frontend/fixtures/merge_requests.rb
index cbf26a70e5f..18f89fbc5e5 100644
--- a/spec/frontend/fixtures/merge_requests.rb
+++ b/spec/frontend/fixtures/merge_requests.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project, :repository, namespace: namespace, path: 'merge-requests-project') }
let(:user) { project.first_owner }
@@ -147,6 +147,20 @@ RSpec.describe Projects::MergeRequestsController, '(JavaScript fixtures)', type:
expect_graphql_errors_to_be_empty
end
end
+
+ context 'merge request in state getState query' do
+ base_input_path = 'vue_merge_request_widget/queries/'
+ base_output_path = 'graphql/merge_requests/'
+ query_name = 'get_state.query.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: user, variables: { projectPath: project.full_path, iid: merge_request.iid.to_s })
+
+ expect_graphql_errors_to_be_empty
+ end
+ end
end
private
diff --git a/spec/frontend/fixtures/merge_requests_diffs.rb b/spec/frontend/fixtures/merge_requests_diffs.rb
index ff4b27844a6..cd22d110e38 100644
--- a/spec/frontend/fixtures/merge_requests_diffs.rb
+++ b/spec/frontend/fixtures/merge_requests_diffs.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Projects::MergeRequests::DiffsController, '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project, :repository, namespace: namespace, path: 'merge-requests-project') }
let(:user) { project.first_owner }
let(:merge_request) { create(:merge_request, source_project: project, target_project: project, description: '- [ ] Task List Item') }
diff --git a/spec/frontend/fixtures/metrics_dashboard.rb b/spec/frontend/fixtures/metrics_dashboard.rb
index 7f8b3d378d3..109b016d980 100644
--- a/spec/frontend/fixtures/metrics_dashboard.rb
+++ b/spec/frontend/fixtures/metrics_dashboard.rb
@@ -7,7 +7,7 @@ RSpec.describe MetricsDashboard, '(JavaScript fixtures)', type: :controller do
include MetricsDashboardHelpers
let_it_be(:user) { create(:user) }
- let_it_be(:namespace) { create(:namespace, name: 'monitoring' ) }
+ let_it_be(:namespace) { create(:namespace, name: 'monitoring') }
let_it_be(:project) { project_with_dashboard_namespace('.gitlab/dashboards/test.yml', nil, namespace: namespace) }
let_it_be(:environment) { create(:environment, id: 1, project: project) }
let_it_be(:params) { { environment: environment } }
diff --git a/spec/frontend/fixtures/namespaces.rb b/spec/frontend/fixtures/namespaces.rb
index a3f295f4e66..9858e3241cb 100644
--- a/spec/frontend/fixtures/namespaces.rb
+++ b/spec/frontend/fixtures/namespaces.rb
@@ -32,6 +32,26 @@ RSpec.describe 'Jobs (JavaScript fixtures)' do
end
end
+ describe API::Groups, type: :request do
+ let_it_be(:user) { create(:user) }
+
+ describe 'transfer_locations' do
+ let_it_be(:groups) { create_list(:group, 4) }
+ let_it_be(:transfer_from_group) { create(:group) }
+
+ before_all do
+ groups.each { |group| group.add_owner(user) }
+ transfer_from_group.add_owner(user)
+ end
+
+ it 'api/groups/transfer_locations.json' do
+ get api("/groups/#{transfer_from_group.id}/transfer_locations", user)
+
+ expect(response).to be_successful
+ end
+ end
+ end
+
describe GraphQL::Query, type: :request do
let_it_be(:user) { create(:user) }
diff --git a/spec/frontend/fixtures/pipeline_schedules.rb b/spec/frontend/fixtures/pipeline_schedules.rb
index 4de0bd762f8..3bfe9113e83 100644
--- a/spec/frontend/fixtures/pipeline_schedules.rb
+++ b/spec/frontend/fixtures/pipeline_schedules.rb
@@ -7,7 +7,7 @@ RSpec.describe 'Pipeline schedules (JavaScript fixtures)' do
include JavaScriptFixturesHelpers
include GraphqlHelpers
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project, :public, :repository) }
let(:user) { project.first_owner }
let!(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: user) }
@@ -54,7 +54,7 @@ RSpec.describe 'Pipeline schedules (JavaScript fixtures)' do
get_pipeline_schedules_query = 'get_pipeline_schedules.query.graphql'
let_it_be(:query) do
- get_graphql_query_as_string("pipeline_schedules/graphql/queries/#{get_pipeline_schedules_query}")
+ get_graphql_query_as_string("ci/pipeline_schedules/graphql/queries/#{get_pipeline_schedules_query}")
end
it "#{fixtures_path}#{get_pipeline_schedules_query}.json" do
@@ -71,5 +71,14 @@ RSpec.describe 'Pipeline schedules (JavaScript fixtures)' do
expect_graphql_errors_to_be_empty
end
+
+ it "#{fixtures_path}#{get_pipeline_schedules_query}.take_ownership.json" do
+ maintainer = create(:user)
+ project.add_maintainer(maintainer)
+
+ post_graphql(query, current_user: maintainer, variables: { projectPath: project.full_path })
+
+ expect_graphql_errors_to_be_empty
+ end
end
end
diff --git a/spec/frontend/fixtures/pipelines.rb b/spec/frontend/fixtures/pipelines.rb
index 114db26d6a9..44b471a70d8 100644
--- a/spec/frontend/fixtures/pipelines.rb
+++ b/spec/frontend/fixtures/pipelines.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Projects::PipelinesController, '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
- let_it_be(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let_it_be(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let_it_be(:project) { create(:project, :repository, namespace: namespace, path: 'pipelines-project') }
let_it_be(:commit_without_author) { RepoHelpers.another_sample_commit }
diff --git a/spec/frontend/fixtures/projects.rb b/spec/frontend/fixtures/projects.rb
index b9c427c7505..101ba203a57 100644
--- a/spec/frontend/fixtures/projects.rb
+++ b/spec/frontend/fixtures/projects.rb
@@ -8,7 +8,7 @@ RSpec.describe 'Projects (JavaScript fixtures)', type: :controller do
runners_token = 'runnerstoken:intabulasreferre'
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project, namespace: namespace, path: 'builds-project', runners_token: runners_token, avatar: fixture_file_upload('spec/fixtures/dk.png', 'image/png')) }
let(:project_with_repo) { create(:project, :repository, description: 'Code and stuff', avatar: fixture_file_upload('spec/fixtures/dk.png', 'image/png')) }
let(:project_variable_populated) { create(:project, namespace: namespace, path: 'builds-project2', runners_token: runners_token) }
diff --git a/spec/frontend/fixtures/prometheus_integration.rb b/spec/frontend/fixtures/prometheus_integration.rb
index 250c50bc8bb..13130c00118 100644
--- a/spec/frontend/fixtures/prometheus_integration.rb
+++ b/spec/frontend/fixtures/prometheus_integration.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Projects::Settings::IntegrationsController, '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project_empty_repo, namespace: namespace, path: 'integrations-project') }
let!(:integration) { create(:prometheus_integration, project: project) }
let(:user) { project.first_owner }
diff --git a/spec/frontend/fixtures/raw.rb b/spec/frontend/fixtures/raw.rb
index 7bd5b8c5f6c..886f5525ac5 100644
--- a/spec/frontend/fixtures/raw.rb
+++ b/spec/frontend/fixtures/raw.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Raw files', '(JavaScript fixtures)' do
include JavaScriptFixturesHelpers
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project, :repository, namespace: namespace, path: 'raw-project') }
let(:response) { @response }
diff --git a/spec/frontend/fixtures/runner.rb b/spec/frontend/fixtures/runner.rb
index b523650dda5..de87114766e 100644
--- a/spec/frontend/fixtures/runner.rb
+++ b/spec/frontend/fixtures/runner.rb
@@ -20,8 +20,8 @@ RSpec.describe 'Runner (JavaScript fixtures)' do
let_it_be(:build) { create(:ci_build, runner: runner) }
- query_path = 'runner/graphql/'
- fixtures_path = 'graphql/runner/'
+ query_path = 'ci/runner/graphql/'
+ fixtures_path = 'graphql/ci/runner/'
after(:all) do
remove_repository(project)
diff --git a/spec/frontend/fixtures/snippet.rb b/spec/frontend/fixtures/snippet.rb
index 58d4bc5c1f3..0510746a944 100644
--- a/spec/frontend/fixtures/snippet.rb
+++ b/spec/frontend/fixtures/snippet.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe SnippetsController, '(JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project, :repository, namespace: namespace, path: 'branches-project') }
let(:user) { project.first_owner }
let(:snippet) { create(:personal_snippet, :public, title: 'snippet.md', content: '# snippet', file_name: 'snippet.md', author: user) }
diff --git a/spec/frontend/fixtures/static/gl_field_errors.html b/spec/frontend/fixtures/static/gl_field_errors.html
index f8470e02b7c..a53366fc29f 100644
--- a/spec/frontend/fixtures/static/gl_field_errors.html
+++ b/spec/frontend/fixtures/static/gl_field_errors.html
@@ -17,6 +17,9 @@
<div class="form-group">
<input class="custom gl-field-error-ignore" type="text">Custom, do not validate</input>
</div>
+<div class="form-group">
+<textarea required title="Textarea is required">Textarea</textarea>
+</div>
<div class="form-group"></div>
<input class="submit" type="submit">Submit</input>
</form>
diff --git a/spec/frontend/fixtures/todos.rb b/spec/frontend/fixtures/todos.rb
index d934396f803..58f230de546 100644
--- a/spec/frontend/fixtures/todos.rb
+++ b/spec/frontend/fixtures/todos.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'Todos (JavaScript fixtures)' do
include JavaScriptFixturesHelpers
- let(:namespace) { create(:namespace, name: 'frontend-fixtures' ) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures') }
let(:project) { create(:project_empty_repo, namespace: namespace, path: 'todos-project') }
let(:user) { project.first_owner }
let(:issue_1) { create(:issue, title: 'issue_1', project: project) }
diff --git a/spec/frontend/flash_spec.js b/spec/frontend/flash_spec.js
index a809bf248bf..a105b0b165c 100644
--- a/spec/frontend/flash_spec.js
+++ b/spec/frontend/flash_spec.js
@@ -193,6 +193,20 @@ describe('Flash', () => {
);
});
+ describe('with title', () => {
+ const mockTitle = 'my title';
+
+ it('shows title and message', () => {
+ createAlert({
+ title: mockTitle,
+ message: mockMessage,
+ });
+
+ const text = document.querySelector('.flash-container').textContent.trim();
+ expect(text).toBe(`${mockTitle} ${mockMessage}`);
+ });
+ });
+
describe('with buttons', () => {
const findAlertAction = () => document.querySelector('.flash-container .gl-alert-action');
diff --git a/spec/frontend/gfm_auto_complete/mock_data.js b/spec/frontend/gfm_auto_complete/mock_data.js
index 86795ffd0a5..9c5a9d7ef3d 100644
--- a/spec/frontend/gfm_auto_complete/mock_data.js
+++ b/spec/frontend/gfm_auto_complete/mock_data.js
@@ -32,3 +32,60 @@ export const eventlistenersMockDefaultMap = [
namespace: 'atwho',
},
];
+
+export const crmContactsMock = [
+ {
+ id: 1,
+ email: 'contact.1@email.com',
+ firstName: 'Contact',
+ lastName: 'One',
+ search: 'contact.1@email.com',
+ state: 'active',
+ set: false,
+ },
+ {
+ id: 2,
+ email: 'contact.2@email.com',
+ firstName: 'Contact',
+ lastName: 'Two',
+ search: 'contact.2@email.com',
+ state: 'active',
+ set: false,
+ },
+ {
+ id: 3,
+ email: 'contact.3@email.com',
+ firstName: 'Contact',
+ lastName: 'Three',
+ search: 'contact.3@email.com',
+ state: 'inactive',
+ set: false,
+ },
+ {
+ id: 4,
+ email: 'contact.4@email.com',
+ firstName: 'Contact',
+ lastName: 'Four',
+ search: 'contact.4@email.com',
+ state: 'inactive',
+ set: true,
+ },
+ {
+ id: 5,
+ email: 'contact.5@email.com',
+ firstName: 'Contact',
+ lastName: 'Five',
+ search: 'contact.5@email.com',
+ state: 'active',
+ set: true,
+ },
+ {
+ id: 5,
+ email: 'contact.6@email.com',
+ firstName: 'Contact',
+ lastName: 'Six',
+ search: 'contact.6@email.com',
+ state: 'active',
+ set: undefined, // On purpose
+ },
+];
diff --git a/spec/frontend/gfm_auto_complete_spec.js b/spec/frontend/gfm_auto_complete_spec.js
index c3dfc4570f9..68225f39c66 100644
--- a/spec/frontend/gfm_auto_complete_spec.js
+++ b/spec/frontend/gfm_auto_complete_spec.js
@@ -3,14 +3,23 @@ import MockAdapter from 'axios-mock-adapter';
import $ from 'jquery';
import labelsFixture from 'test_fixtures/autocomplete_sources/labels.json';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
-import GfmAutoComplete, { membersBeforeSave, highlighter } from 'ee_else_ce/gfm_auto_complete';
+import GfmAutoComplete, {
+ membersBeforeSave,
+ highlighter,
+ CONTACT_STATE_ACTIVE,
+ CONTACTS_ADD_COMMAND,
+ CONTACTS_REMOVE_COMMAND,
+} from 'ee_else_ce/gfm_auto_complete';
import { initEmojiMock, clearEmojiMock } from 'helpers/emoji';
import '~/lib/utils/jquery_at_who';
import { TEST_HOST } from 'helpers/test_constants';
import waitForPromises from 'helpers/wait_for_promises';
import AjaxCache from '~/lib/utils/ajax_cache';
import axios from '~/lib/utils/axios_utils';
-import { eventlistenersMockDefaultMap } from 'ee_else_ce_jest/gfm_auto_complete/mock_data';
+import {
+ eventlistenersMockDefaultMap,
+ crmContactsMock,
+} from 'ee_else_ce_jest/gfm_auto_complete/mock_data';
describe('GfmAutoComplete', () => {
const fetchDataMock = { fetchData: jest.fn() };
@@ -871,7 +880,87 @@ describe('GfmAutoComplete', () => {
});
});
- describe('Contacts', () => {
+ describe('CRM Contacts', () => {
+ const dataSources = {
+ contacts: `${TEST_HOST}/autocomplete_sources/contacts`,
+ };
+
+ const allContacts = crmContactsMock;
+ const assignedContacts = allContacts.filter((contact) => contact.set);
+ const unassignedContacts = allContacts.filter(
+ (contact) => contact.state === CONTACT_STATE_ACTIVE && !contact.set,
+ );
+
+ let autocomplete;
+ let $textarea;
+
+ beforeEach(() => {
+ setHTMLFixture('<textarea></textarea>');
+ autocomplete = new GfmAutoComplete(dataSources);
+ $textarea = $('textarea');
+ autocomplete.setup($textarea, { contacts: true });
+ });
+
+ afterEach(() => {
+ autocomplete.destroy();
+ resetHTMLFixture();
+ });
+
+ const triggerDropdown = (text) => {
+ $textarea.trigger('focus').val(text).caret('pos', -1);
+ $textarea.trigger('keyup');
+
+ jest.runOnlyPendingTimers();
+ };
+
+ const getDropdownItems = () => {
+ const dropdown = document.getElementById('at-view-contacts');
+ const items = dropdown.getElementsByTagName('li');
+ return [].map.call(items, (item) => item.textContent.trim());
+ };
+
+ const expectContacts = ({ input, output }) => {
+ triggerDropdown(input);
+
+ expect(getDropdownItems()).toEqual(output.map((contact) => contact.email));
+ };
+
+ describe('with no contacts assigned', () => {
+ beforeEach(() => {
+ autocomplete.cachedData['[contact:'] = [...unassignedContacts];
+ });
+
+ it.each`
+ input | output
+ ${`${CONTACTS_ADD_COMMAND} [contact:`} | ${unassignedContacts}
+ ${`${CONTACTS_REMOVE_COMMAND} [contact:`} | ${[]}
+ `('$input shows $output.length contacts', expectContacts);
+ });
+
+ describe('with some contacts assigned', () => {
+ beforeEach(() => {
+ autocomplete.cachedData['[contact:'] = allContacts;
+ });
+
+ it.each`
+ input | output
+ ${`${CONTACTS_ADD_COMMAND} [contact:`} | ${unassignedContacts}
+ ${`${CONTACTS_REMOVE_COMMAND} [contact:`} | ${assignedContacts}
+ `('$input shows $output.length contacts', expectContacts);
+ });
+
+ describe('with all contacts assigned', () => {
+ beforeEach(() => {
+ autocomplete.cachedData['[contact:'] = [...assignedContacts];
+ });
+
+ it.each`
+ input | output
+ ${`${CONTACTS_ADD_COMMAND} [contact:`} | ${[]}
+ ${`${CONTACTS_REMOVE_COMMAND} [contact:`} | ${assignedContacts}
+ `('$input shows $output.length contacts', expectContacts);
+ });
+
it('escapes name and email correct', () => {
const xssPayload = '<script>alert(1)</script>';
const escapedPayload = '&lt;script&gt;alert(1)&lt;/script&gt;';
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
new file mode 100644
index 00000000000..949bcf71ff5
--- /dev/null
+++ b/spec/frontend/gitlab_version_check/components/gitlab_version_check_badge_spec.js
@@ -0,0 +1,102 @@
+import { GlBadge } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
+import GitlabVersionCheckBadge from '~/gitlab_version_check/components/gitlab_version_check_badge.vue';
+import { STATUS_TYPES, UPGRADE_DOCS_URL } from '~/gitlab_version_check/constants';
+
+describe('GitlabVersionCheckBadge', () => {
+ let wrapper;
+ let trackingSpy;
+
+ const defaultProps = {
+ status: STATUS_TYPES.SUCCESS,
+ };
+
+ const createComponent = (props = {}) => {
+ trackingSpy = mockTracking(undefined, undefined, jest.spyOn);
+
+ wrapper = shallowMountExtended(GitlabVersionCheckBadge, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+ };
+
+ afterEach(() => {
+ unmockTracking();
+ wrapper.destroy();
+ });
+
+ const findGlBadgeClickWrapper = () => wrapper.findByTestId('badge-click-wrapper');
+ const findGlBadge = () => wrapper.findComponent(GlBadge);
+
+ describe('template', () => {
+ describe.each`
+ status | expectedUI
+ ${STATUS_TYPES.SUCCESS} | ${{ title: 'Up to date', variant: 'success' }}
+ ${STATUS_TYPES.WARNING} | ${{ title: 'Update available', variant: 'warning' }}
+ ${STATUS_TYPES.DANGER} | ${{ title: 'Update ASAP', variant: 'danger' }}
+ `('badge ui', ({ status, expectedUI }) => {
+ beforeEach(() => {
+ createComponent({ status, actionable: true });
+ });
+
+ describe(`when status is ${status}`, () => {
+ it(`title is ${expectedUI.title}`, () => {
+ expect(findGlBadge().text()).toBe(expectedUI.title);
+ });
+
+ it(`variant is ${expectedUI.variant}`, () => {
+ expect(findGlBadge().attributes('variant')).toBe(expectedUI.variant);
+ });
+
+ it(`tracks rendered_version_badge with label ${expectedUI.title}`, () => {
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'render', {
+ label: 'version_badge',
+ property: expectedUI.title,
+ });
+ });
+
+ it(`link is ${UPGRADE_DOCS_URL}`, () => {
+ expect(findGlBadge().attributes('href')).toBe(UPGRADE_DOCS_URL);
+ });
+
+ it(`tracks click_version_badge with label ${expectedUI.title} when badge is clicked`, async () => {
+ await findGlBadgeClickWrapper().trigger('click');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_link', {
+ label: 'version_badge',
+ property: expectedUI.title,
+ });
+ });
+ });
+ });
+
+ describe('when actionable is false', () => {
+ beforeEach(() => {
+ createComponent({ actionable: false });
+ });
+
+ it('tracks rendered_version_badge correctly', () => {
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'render', {
+ label: 'version_badge',
+ property: 'Up to date',
+ });
+ });
+
+ it('does not provide a link to GlBadge', () => {
+ expect(findGlBadge().attributes('href')).toBe(undefined);
+ });
+
+ it('does not track click_version_badge', async () => {
+ await findGlBadgeClickWrapper().trigger('click');
+
+ expect(trackingSpy).not.toHaveBeenCalledWith(undefined, 'click_link', {
+ label: 'version_badge',
+ property: 'Up to date',
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/gitlab_version_check/index_spec.js b/spec/frontend/gitlab_version_check/index_spec.js
new file mode 100644
index 00000000000..8a11ff48bf2
--- /dev/null
+++ b/spec/frontend/gitlab_version_check/index_spec.js
@@ -0,0 +1,116 @@
+import Vue from 'vue';
+import * as Sentry from '@sentry/browser';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
+import initGitlabVersionCheck from '~/gitlab_version_check';
+
+describe('initGitlabVersionCheck', () => {
+ let originalGon;
+ let mock;
+ let vueApps;
+
+ const defaultResponse = {
+ code: 200,
+ res: { severity: 'success' },
+ };
+
+ const dummyGon = {
+ relative_url_root: '/',
+ };
+
+ const createApp = async (mockResponse, htmlClass) => {
+ originalGon = window.gon;
+
+ const response = {
+ ...defaultResponse,
+ ...mockResponse,
+ };
+
+ mock = new MockAdapter(axios);
+ mock.onGet().replyOnce(response.code, response.res);
+
+ setHTMLFixture(`<div class="${htmlClass}"></div>`);
+
+ vueApps = await initGitlabVersionCheck();
+ };
+
+ afterEach(() => {
+ mock.restore();
+ window.gon = originalGon;
+ resetHTMLFixture();
+ });
+
+ describe('with no .js-gitlab-version-check-badge elements', () => {
+ beforeEach(async () => {
+ await createApp();
+ });
+
+ it('does not make axios GET request', () => {
+ expect(mock.history.get.length).toBe(0);
+ });
+
+ it('does not render the Version Check Badge', () => {
+ expect(vueApps).toBeNull();
+ });
+ });
+
+ describe('with .js-gitlab-version-check-badge element but API errors', () => {
+ beforeEach(async () => {
+ jest.spyOn(Sentry, 'captureException');
+ await createApp({ code: 500, res: null }, 'js-gitlab-version-check-badge');
+ });
+
+ it('does make axios GET request', () => {
+ expect(mock.history.get.length).toBe(1);
+ expect(mock.history.get[0].url).toContain('/admin/version_check.json');
+ });
+
+ it('logs error to Sentry', () => {
+ expect(Sentry.captureException).toHaveBeenCalled();
+ });
+
+ it('does not render the Version Check Badge', () => {
+ expect(vueApps).toBeNull();
+ });
+ });
+
+ describe('with .js-gitlab-version-check-badge element and successful API call', () => {
+ beforeEach(async () => {
+ await createApp({}, 'js-gitlab-version-check-badge');
+ });
+
+ it('does make axios GET request', () => {
+ expect(mock.history.get.length).toBe(1);
+ expect(mock.history.get[0].url).toContain('/admin/version_check.json');
+ });
+
+ it('does render the Version Check Badge', () => {
+ expect(vueApps).toHaveLength(1);
+ expect(vueApps[0]).toBeInstanceOf(Vue);
+ });
+ });
+
+ describe.each`
+ root | description
+ ${'/'} | ${'not used (uses its own (sub)domain)'}
+ ${'/gitlab'} | ${'custom path'}
+ ${'/service/gitlab'} | ${'custom path with 2 depth'}
+ `('path for version_check.json', ({ root, description }) => {
+ describe(`when relative url is ${description}: ${root}`, () => {
+ beforeEach(async () => {
+ originalGon = window.gon;
+ window.gon = { ...dummyGon };
+ window.gon.relative_url_root = root;
+ await createApp({}, 'js-gitlab-version-check-badge');
+ });
+
+ it('reflects the relative url setting', () => {
+ expect(mock.history.get.length).toBe(1);
+
+ const pathRegex = new RegExp(`^${root}`);
+ expect(mock.history.get[0].url).toMatch(pathRegex);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/gl_field_errors_spec.js b/spec/frontend/gl_field_errors_spec.js
index 92d04927ee5..1f6929baa75 100644
--- a/spec/frontend/gl_field_errors_spec.js
+++ b/spec/frontend/gl_field_errors_spec.js
@@ -27,7 +27,7 @@ describe('GL Style Field Errors', () => {
expect(testContext.fieldErrors).toBeDefined();
const { inputs } = testContext.fieldErrors.state;
- expect(inputs.length).toBe(4);
+ expect(inputs.length).toBe(5);
});
it('should ignore elements with custom error handling', () => {
diff --git a/spec/frontend/google_cloud/service_accounts/list_spec.js b/spec/frontend/google_cloud/service_accounts/list_spec.js
index 7a76a893757..c2bd2005b5d 100644
--- a/spec/frontend/google_cloud/service_accounts/list_spec.js
+++ b/spec/frontend/google_cloud/service_accounts/list_spec.js
@@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils';
-import { GlAlert, GlButton, GlEmptyState, GlTable } from '@gitlab/ui';
+import { GlAlert, GlButton, GlEmptyState, GlLink, GlTable } from '@gitlab/ui';
import ServiceAccountsList from '~/google_cloud/service_accounts/list.vue';
describe('google_cloud/service_accounts/list', () => {
@@ -45,7 +45,26 @@ describe('google_cloud/service_accounts/list', () => {
beforeEach(() => {
const propsData = {
- list: [{}, {}, {}],
+ list: [
+ {
+ ref: '*',
+ gcp_project: 'gcp-project-123',
+ service_account_exists: true,
+ service_account_key_exists: true,
+ },
+ {
+ ref: 'prod',
+ gcp_project: 'gcp-project-456',
+ service_account_exists: true,
+ service_account_key_exists: true,
+ },
+ {
+ ref: 'stag',
+ gcp_project: 'gcp-project-789',
+ service_account_exists: true,
+ service_account_key_exists: true,
+ },
+ ],
createUrl: '#create-url',
emptyIllustrationUrl: '#empty-illustration-url',
};
@@ -68,6 +87,12 @@ describe('google_cloud/service_accounts/list', () => {
expect(findRows().length).toBe(4);
});
+ it('table row must contain link to the google cloud console', () => {
+ expect(findRows().at(1).findComponent(GlLink).attributes('href')).toBe(
+ `${ServiceAccountsList.GOOGLE_CONSOLE_URL}?project=gcp-project-123`,
+ );
+ });
+
it('shows the link to create new service accounts', () => {
const button = findButton();
expect(button.exists()).toBe(true);
diff --git a/spec/frontend/groups/components/overview_tabs_spec.js b/spec/frontend/groups/components/overview_tabs_spec.js
index 93e087e10f2..b615679dcc5 100644
--- a/spec/frontend/groups/components/overview_tabs_spec.js
+++ b/spec/frontend/groups/components/overview_tabs_spec.js
@@ -67,6 +67,7 @@ describe('OverviewTabs', () => {
const findTabPanels = () => wrapper.findAllComponents(GlTab);
const findTab = (name) => wrapper.findByRole('tab', { name });
const findSelectedTab = () => wrapper.findByRole('tab', { selected: true });
+ const findSearchInput = () => wrapper.findByPlaceholderText(OverviewTabs.i18n.searchPlaceholder);
beforeEach(() => {
axiosMock = new AxiosMockAdapter(axios);
@@ -244,18 +245,39 @@ describe('OverviewTabs', () => {
};
describe('when search is typed in', () => {
- const search = 'Foo bar';
+ describe('when search is greater than or equal to 3 characters', () => {
+ const search = 'Foo bar';
- beforeEach(async () => {
- await setup();
- await wrapper.findByPlaceholderText(OverviewTabs.i18n.searchPlaceholder).setValue(search);
- });
+ beforeEach(async () => {
+ await setup();
+ await findSearchInput().setValue(search);
+ });
- it('updates query string with `filter` key', () => {
- expect(routerMock.push).toHaveBeenCalledWith({ query: { filter: search } });
+ it('updates query string with `filter` key', () => {
+ expect(routerMock.push).toHaveBeenCalledWith({ query: { filter: search } });
+ });
+
+ sharedAssertions({ search, sort: defaultProvide.initialSort });
});
- sharedAssertions({ search, sort: defaultProvide.initialSort });
+ describe('when search is less than 3 characters', () => {
+ const search = 'Fo';
+
+ beforeEach(async () => {
+ await setup();
+ await findSearchInput().setValue(search);
+ });
+
+ it('does not emit `fetchFilteredAndSortedGroups` event from `eventHub`', () => {
+ expect(eventHub.$emit).not.toHaveBeenCalledWith(
+ `${ACTIVE_TAB_SUBGROUPS_AND_PROJECTS}fetchFilteredAndSortedGroups`,
+ {
+ filterGroupsBy: search,
+ sortBy: defaultProvide.initialSort,
+ },
+ );
+ });
+ });
});
describe('when sort is changed', () => {
@@ -308,6 +330,16 @@ describe('OverviewTabs', () => {
).toBe('Foo bar');
});
+ describe('when search is cleared', () => {
+ it('removes `filter` key from query string', async () => {
+ await findSearchInput().setValue('');
+
+ expect(routerMock.push).toHaveBeenCalledWith({
+ query: { sort: SORTING_ITEM_UPDATED.desc },
+ });
+ });
+ });
+
it('sets sort dropdown', () => {
expect(wrapper.findComponent(GlSorting).props()).toMatchObject({
text: SORTING_ITEM_UPDATED.label,
diff --git a/spec/frontend/groups/components/transfer_group_form_spec.js b/spec/frontend/groups/components/transfer_group_form_spec.js
index 7cbe6e5bbab..0065820f78f 100644
--- a/spec/frontend/groups/components/transfer_group_form_spec.js
+++ b/spec/frontend/groups/components/transfer_group_form_spec.js
@@ -1,8 +1,13 @@
import { GlAlert, GlSprintf } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import Component from '~/groups/components/transfer_group_form.vue';
+import TransferLocationsForm, { i18n } from '~/groups/components/transfer_group_form.vue';
import ConfirmDanger from '~/vue_shared/components/confirm_danger/confirm_danger.vue';
-import NamespaceSelect from '~/vue_shared/components/namespace_select/namespace_select_deprecated.vue';
+import TransferLocations from '~/groups_projects/components/transfer_locations.vue';
+import { getGroupTransferLocations } from '~/api/groups_api';
+
+jest.mock('~/api/groups_api', () => ({
+ getGroupTransferLocations: jest.fn(),
+}));
describe('Transfer group form', () => {
let wrapper;
@@ -22,25 +27,25 @@ describe('Transfer group form', () => {
];
const defaultProps = {
- groupNamespaces,
paidGroupHelpLink,
isPaidGroup: false,
confirmationPhrase,
confirmButtonText,
};
- const createComponent = (propsData = {}) =>
- shallowMountExtended(Component, {
+ const createComponent = (propsData = {}) => {
+ wrapper = shallowMountExtended(TransferLocationsForm, {
propsData: {
...defaultProps,
...propsData,
},
stubs: { GlSprintf },
});
+ };
const findAlert = () => wrapper.findComponent(GlAlert);
const findConfirmDanger = () => wrapper.findComponent(ConfirmDanger);
- const findNamespaceSelect = () => wrapper.findComponent(NamespaceSelect);
+ const findTransferLocations = () => wrapper.findComponent(TransferLocations);
const findHiddenInput = () => wrapper.find('[name="new_parent_group_id"]');
afterEach(() => {
@@ -49,21 +54,17 @@ describe('Transfer group form', () => {
describe('default', () => {
beforeEach(() => {
- wrapper = createComponent();
+ createComponent();
});
- it('renders the namespace select component', () => {
- expect(findNamespaceSelect().exists()).toBe(true);
- });
+ it('renders the transfer locations dropdown and passes correct props', () => {
+ findTransferLocations().props('groupTransferLocationsApiMethod')();
- it('sets the namespace select properties', () => {
- expect(findNamespaceSelect().props()).toMatchObject({
- defaultText: 'Select parent group',
- fullWidth: false,
- includeHeaders: false,
- emptyNamespaceTitle: 'No parent group',
- includeEmptyNamespace: true,
- groupNamespaces,
+ expect(getGroupTransferLocations).toHaveBeenCalled();
+ expect(findTransferLocations().props()).toMatchObject({
+ value: null,
+ label: i18n.dropdownLabel,
+ additionalDropdownItems: TransferLocationsForm.additionalDropdownItems,
});
});
@@ -90,10 +91,15 @@ describe('Transfer group form', () => {
});
describe('with a selected project', () => {
- const [firstGroup] = groupNamespaces;
+ const [selectedItem] = groupNamespaces;
+
beforeEach(() => {
- wrapper = createComponent();
- findNamespaceSelect().vm.$emit('select', firstGroup);
+ createComponent();
+ findTransferLocations().vm.$emit('input', selectedItem);
+ });
+
+ it('sets `value` prop on `TransferLocations` component', () => {
+ expect(findTransferLocations().props('value')).toEqual(selectedItem);
});
it('sets the confirm danger disabled property to false', () => {
@@ -102,7 +108,7 @@ describe('Transfer group form', () => {
it('sets the hidden input field', () => {
expect(findHiddenInput().exists()).toBe(true);
- expect(parseInt(findHiddenInput().attributes('value'), 10)).toBe(firstGroup.id);
+ expect(findHiddenInput().attributes('value')).toBe(String(selectedItem.id));
});
it('emits "confirm" event when the danger modal is confirmed', () => {
@@ -116,15 +122,15 @@ describe('Transfer group form', () => {
describe('isPaidGroup = true', () => {
beforeEach(() => {
- wrapper = createComponent({ isPaidGroup: true });
+ createComponent({ isPaidGroup: true });
});
it('disables the transfer button', () => {
expect(findConfirmDanger().props()).toMatchObject({ disabled: true });
});
- it('hides the namespace selector button', () => {
- expect(findNamespaceSelect().exists()).toBe(false);
+ it('hides the transfer locations dropdown', () => {
+ expect(findTransferLocations().exists()).toBe(false);
});
});
});
diff --git a/spec/frontend/groups_projects/components/transfer_locations_spec.js b/spec/frontend/groups_projects/components/transfer_locations_spec.js
new file mode 100644
index 00000000000..74424ee3230
--- /dev/null
+++ b/spec/frontend/groups_projects/components/transfer_locations_spec.js
@@ -0,0 +1,377 @@
+import {
+ GlDropdown,
+ GlDropdownItem,
+ GlAlert,
+ GlSearchBoxByType,
+ GlIntersectionObserver,
+ GlLoadingIcon,
+} from '@gitlab/ui';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import currentUserNamespaceQueryResponse from 'test_fixtures/graphql/projects/settings/current_user_namespace.query.graphql.json';
+import transferLocationsResponsePage1 from 'test_fixtures/api/projects/transfer_locations_page_1.json';
+import transferLocationsResponsePage2 from 'test_fixtures/api/projects/transfer_locations_page_2.json';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import { __ } from '~/locale';
+import TransferLocations from '~/groups_projects/components/transfer_locations.vue';
+import { getTransferLocations } from '~/api/projects_api';
+import currentUserNamespaceQuery from '~/projects/settings/graphql/queries/current_user_namespace.query.graphql';
+
+jest.mock('~/api/projects_api', () => ({
+ getTransferLocations: jest.fn(),
+}));
+
+describe('TransferLocations', () => {
+ let wrapper;
+
+ // Default data
+ const resourceId = '1';
+ const defaultPropsData = {
+ groupTransferLocationsApiMethod: getTransferLocations,
+ value: null,
+ };
+ const additionalDropdownItem = {
+ id: -1,
+ humanName: __('No parent group'),
+ };
+
+ // Mock requests
+ const defaultQueryHandler = jest.fn().mockResolvedValue(currentUserNamespaceQueryResponse);
+ const mockResolvedGetTransferLocations = ({
+ data = transferLocationsResponsePage1,
+ page = '1',
+ nextPage = '2',
+ total = '4',
+ totalPages = '2',
+ prevPage = null,
+ } = {}) => {
+ getTransferLocations.mockResolvedValueOnce({
+ data,
+ headers: {
+ 'x-per-page': '2',
+ 'x-page': page,
+ 'x-total': total,
+ 'x-total-pages': totalPages,
+ 'x-next-page': nextPage,
+ 'x-prev-page': prevPage,
+ },
+ });
+ };
+ const mockRejectedGetTransferLocations = () => {
+ const error = new Error();
+
+ getTransferLocations.mockRejectedValueOnce(error);
+ };
+
+ // VTU wrapper helpers
+ Vue.use(VueApollo);
+ const createComponent = ({
+ propsData = {},
+ requestHandlers = [[currentUserNamespaceQuery, defaultQueryHandler]],
+ } = {}) => {
+ wrapper = mountExtended(TransferLocations, {
+ provide: {
+ resourceId,
+ },
+ propsData: {
+ ...defaultPropsData,
+ ...propsData,
+ },
+ apolloProvider: createMockApollo(requestHandlers),
+ });
+ };
+
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const showDropdown = async () => {
+ findDropdown().vm.$emit('show');
+ await waitForPromises();
+ };
+ const findUserTransferLocations = () =>
+ wrapper
+ .findByTestId('user-transfer-locations')
+ .findAllComponents(GlDropdownItem)
+ .wrappers.map((dropdownItem) => dropdownItem.text());
+ const findGroupTransferLocations = () =>
+ wrapper
+ .findByTestId('group-transfer-locations')
+ .findAllComponents(GlDropdownItem)
+ .wrappers.map((dropdownItem) => dropdownItem.text());
+ const findDropdownItemByText = (text) =>
+ wrapper
+ .findAllComponents(GlDropdownItem)
+ .wrappers.find((dropdownItem) => dropdownItem.text() === text);
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findSearch = () => wrapper.findComponent(GlSearchBoxByType);
+ const searchEmitInput = (searchTerm = 'foo') => findSearch().vm.$emit('input', searchTerm);
+ const findIntersectionObserver = () => wrapper.findComponent(GlIntersectionObserver);
+ 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(() => {}));
+ createComponent();
+ findDropdown().vm.$emit('show');
+ await nextTick();
+
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+
+ it('fetches and renders user and group transfer locations', async () => {
+ mockResolvedGetTransferLocations();
+ createComponent();
+ await showDropdown();
+
+ const { namespace } = currentUserNamespaceQueryResponse.data.currentUser;
+
+ expect(findUserTransferLocations()).toEqual([namespace.fullName]);
+ expect(findGroupTransferLocations()).toEqual(
+ transferLocationsResponsePage1.map((transferLocation) => transferLocation.full_name),
+ );
+ });
+
+ describe('when `showUserTransferLocations` prop is `false`', () => {
+ it('does not fetch user transfer locations', async () => {
+ mockResolvedGetTransferLocations();
+ createComponent({
+ propsData: {
+ showUserTransferLocations: false,
+ },
+ });
+ await showDropdown();
+
+ expect(wrapper.findByTestId('user-transfer-locations').exists()).toBe(false);
+ });
+ });
+
+ describe('when `additionalDropdownItems` prop is passed', () => {
+ it('displays additional dropdown items', async () => {
+ mockResolvedGetTransferLocations();
+ createComponent({
+ propsData: {
+ additionalDropdownItems: [additionalDropdownItem],
+ },
+ });
+ await showDropdown();
+
+ expect(findDropdownItemByText(additionalDropdownItem.humanName).exists()).toBe(true);
+ });
+
+ describe('when loading', () => {
+ it('does not display additional dropdown items', async () => {
+ getTransferLocations.mockReturnValueOnce(new Promise(() => {}));
+ createComponent({
+ propsData: {
+ additionalDropdownItems: [additionalDropdownItem],
+ },
+ });
+ findDropdown().vm.$emit('show');
+ await nextTick();
+
+ expect(findDropdownItemByText(additionalDropdownItem.humanName)).toBeUndefined();
+ });
+ });
+ });
+
+ describe('when transfer locations have already been fetched', () => {
+ beforeEach(async () => {
+ mockResolvedGetTransferLocations();
+ createComponent();
+ await showDropdown();
+ });
+
+ it('does not fetch transfer locations', async () => {
+ getTransferLocations.mockClear();
+ defaultQueryHandler.mockClear();
+
+ await showDropdown();
+
+ expect(getTransferLocations).not.toHaveBeenCalled();
+ expect(defaultQueryHandler).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when `getTransferLocations` API call fails', () => {
+ it('displays dismissible error alert', async () => {
+ mockRejectedGetTransferLocations();
+ createComponent();
+ await showDropdown();
+
+ const alert = findAlert();
+
+ expect(alert.exists()).toBe(true);
+
+ alert.vm.$emit('dismiss');
+ await nextTick();
+
+ expect(alert.exists()).toBe(false);
+ });
+ });
+
+ describe('when `currentUser` GraphQL query fails', () => {
+ it('displays error alert', async () => {
+ mockResolvedGetTransferLocations();
+ const error = new Error();
+ createComponent({
+ requestHandlers: [[currentUserNamespaceQuery, jest.fn().mockRejectedValueOnce(error)]],
+ });
+ await showDropdown();
+
+ expect(findAlert().exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('when transfer location is selected', () => {
+ it('displays transfer location as selected', () => {
+ const [{ id, full_name: humanName }] = transferLocationsResponsePage1;
+
+ createComponent({
+ propsData: {
+ value: {
+ id,
+ humanName,
+ },
+ },
+ });
+
+ expect(findDropdown().props('text')).toBe(humanName);
+ });
+ });
+
+ describe('when search is typed in', () => {
+ const transferLocationsResponseSearch = [transferLocationsResponsePage1[0]];
+
+ const arrange = async ({ propsData, searchTerm } = {}) => {
+ mockResolvedGetTransferLocations();
+ createComponent({ propsData });
+ await showDropdown();
+ mockResolvedGetTransferLocations({ data: transferLocationsResponseSearch });
+ searchEmitInput(searchTerm);
+ await nextTick();
+ };
+
+ it('sets `isSearchLoading` prop to `true`', async () => {
+ await arrange();
+
+ expect(findSearch().props('isLoading')).toBe(true);
+ });
+
+ it('passes `search` param to API call and updates group transfer locations', async () => {
+ await arrange();
+
+ await waitForPromises();
+
+ expect(getTransferLocations).toHaveBeenCalledWith(
+ resourceId,
+ expect.objectContaining({ search: 'foo' }),
+ );
+ expect(findGroupTransferLocations()).toEqual(
+ transferLocationsResponseSearch.map((transferLocation) => transferLocation.full_name),
+ );
+ });
+
+ it('does not display additional dropdown items if they do not match the search', async () => {
+ await arrange({
+ propsData: {
+ additionalDropdownItems: [additionalDropdownItem],
+ },
+ });
+ await waitForPromises();
+
+ expect(findDropdownItemByText(additionalDropdownItem.humanName)).toBeUndefined();
+ });
+
+ it('displays additional dropdown items if they match the search', async () => {
+ await arrange({
+ propsData: {
+ additionalDropdownItems: [additionalDropdownItem],
+ },
+ searchTerm: 'No par',
+ });
+ await waitForPromises();
+
+ expect(findDropdownItemByText(additionalDropdownItem.humanName).exists()).toBe(true);
+ });
+ });
+
+ describe('when there are no more pages', () => {
+ it('does not show intersection observer', async () => {
+ mockResolvedGetTransferLocations({
+ data: transferLocationsResponsePage1,
+ nextPage: null,
+ total: '2',
+ totalPages: '1',
+ prevPage: null,
+ });
+ createComponent();
+ await showDropdown();
+
+ expect(findIntersectionObserver().exists()).toBe(false);
+ });
+ });
+
+ describe('when intersection observer appears', () => {
+ const arrange = async () => {
+ mockResolvedGetTransferLocations();
+ createComponent();
+ await showDropdown();
+
+ mockResolvedGetTransferLocations({
+ data: transferLocationsResponsePage2,
+ page: '2',
+ nextPage: null,
+ prevPage: '1',
+ totalPages: '2',
+ });
+
+ intersectionObserverEmitAppear();
+ await nextTick();
+ };
+
+ it('shows loading icon', async () => {
+ await arrange();
+
+ expect(findLoadingIcon().exists()).toBe(true);
+ });
+
+ it('passes `page` param to API call', async () => {
+ await arrange();
+
+ await waitForPromises();
+
+ expect(getTransferLocations).toHaveBeenCalledWith(
+ resourceId,
+ expect.objectContaining({ page: 2 }),
+ );
+ });
+
+ it('updates dropdown with new group transfer locations', async () => {
+ await arrange();
+
+ await waitForPromises();
+
+ expect(findGroupTransferLocations()).toEqual(
+ [...transferLocationsResponsePage1, ...transferLocationsResponsePage2].map(
+ ({ full_name: fullName }) => fullName,
+ ),
+ );
+ });
+ });
+
+ describe('when `label` prop is passed', () => {
+ it('renders label', () => {
+ const label = 'Foo bar';
+
+ createComponent({ propsData: { label } });
+
+ expect(wrapper.findByRole('group', { name: label }).exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/ide/components/ide_spec.js b/spec/frontend/ide/components/ide_spec.js
index 48c670757a2..a575f428a69 100644
--- a/spec/frontend/ide/components/ide_spec.js
+++ b/spec/frontend/ide/components/ide_spec.js
@@ -3,9 +3,11 @@ import Vue from 'vue';
import Vuex from 'vuex';
import waitForPromises from 'helpers/wait_for_promises';
import { stubPerformanceWebAPI } from 'helpers/performance';
+import { __ } from '~/locale';
import CannotPushCodeAlert from '~/ide/components/cannot_push_code_alert.vue';
import ErrorMessage from '~/ide/components/error_message.vue';
import Ide from '~/ide/components/ide.vue';
+import eventHub from '~/ide/eventhub';
import { MSG_CANNOT_PUSH_CODE_GO_TO_FORK, MSG_GO_TO_FORK } from '~/ide/messages';
import { createStore } from '~/ide/stores';
import { file } from '../helpers';
@@ -14,6 +16,7 @@ import { projectData } from '../mock_data';
Vue.use(Vuex);
const TEST_FORK_IDE_PATH = '/test/ide/path';
+const MSG_ARE_YOU_SURE = __('Are you sure you want to lose unsaved changes?');
describe('WebIDE', () => {
const emptyProjData = { ...projectData, empty_repo: true, branches: {} };
@@ -40,6 +43,8 @@ describe('WebIDE', () => {
const findAlert = () => wrapper.findComponent(CannotPushCodeAlert);
+ const callOnBeforeUnload = (e = {}) => window.onbeforeunload(e);
+
beforeEach(() => {
stubPerformanceWebAPI();
@@ -49,6 +54,7 @@ describe('WebIDE', () => {
afterEach(() => {
wrapper.destroy();
wrapper = null;
+ window.onbeforeunload = null;
});
describe('ide component, empty repo', () => {
@@ -90,7 +96,8 @@ describe('WebIDE', () => {
describe('onBeforeUnload', () => {
it('returns undefined when no staged files or changed files', () => {
createComponent();
- expect(wrapper.vm.onBeforeUnload()).toBe(undefined);
+
+ expect(callOnBeforeUnload()).toBe(undefined);
});
it('returns warning text when their are changed files', () => {
@@ -100,7 +107,10 @@ describe('WebIDE', () => {
},
});
- expect(wrapper.vm.onBeforeUnload()).toBe('Are you sure you want to lose unsaved changes?');
+ const e = {};
+
+ expect(callOnBeforeUnload(e)).toBe(MSG_ARE_YOU_SURE);
+ expect(e.returnValue).toBe(MSG_ARE_YOU_SURE);
});
it('returns warning text when their are staged files', () => {
@@ -110,20 +120,27 @@ describe('WebIDE', () => {
},
});
- expect(wrapper.vm.onBeforeUnload()).toBe('Are you sure you want to lose unsaved changes?');
+ const e = {};
+
+ expect(callOnBeforeUnload(e)).toBe(MSG_ARE_YOU_SURE);
+ expect(e.returnValue).toBe(MSG_ARE_YOU_SURE);
});
- it('updates event object', () => {
- const event = {};
+ it('returns undefined once after "skip-beforeunload" was emitted', () => {
createComponent({
state: {
stagedFiles: [file()],
},
});
- wrapper.vm.onBeforeUnload(event);
+ eventHub.$emit('skip-beforeunload');
+ const e = {};
+
+ expect(callOnBeforeUnload()).toBe(undefined);
+ expect(e.returnValue).toBe(undefined);
- expect(event.returnValue).toBe('Are you sure you want to lose unsaved changes?');
+ expect(callOnBeforeUnload(e)).toBe(MSG_ARE_YOU_SURE);
+ expect(e.returnValue).toBe(MSG_ARE_YOU_SURE);
});
});
diff --git a/spec/frontend/ide/components/panes/collapsible_sidebar_spec.js b/spec/frontend/ide/components/panes/collapsible_sidebar_spec.js
index 1d38231a767..e92f843ae6e 100644
--- a/spec/frontend/ide/components/panes/collapsible_sidebar_spec.js
+++ b/spec/frontend/ide/components/panes/collapsible_sidebar_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
+import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import IdeSidebarNav from '~/ide/components/ide_sidebar_nav.vue';
import CollapsibleSidebar from '~/ide/components/panes/collapsible_sidebar.vue';
@@ -127,5 +127,29 @@ describe('ide/components/panes/collapsible_sidebar.vue', () => {
});
});
});
+
+ describe('with initOpenView that does not exist', () => {
+ beforeEach(async () => {
+ createComponent({ extensionTabs, initOpenView: 'does-not-exist' });
+
+ await nextTick();
+ });
+
+ it('nothing is dispatched', () => {
+ expect(store.dispatch).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('with initOpenView that does exist', () => {
+ beforeEach(async () => {
+ createComponent({ extensionTabs, initOpenView: fakeView.name });
+
+ await nextTick();
+ });
+
+ it('dispatches open with view on create', () => {
+ expect(store.dispatch).toHaveBeenCalledWith('rightPane/open', fakeView);
+ });
+ });
});
});
diff --git a/spec/frontend/ide/components/panes/right_spec.js b/spec/frontend/ide/components/panes/right_spec.js
index 4555f519bc2..b7349b8fed1 100644
--- a/spec/frontend/ide/components/panes/right_spec.js
+++ b/spec/frontend/ide/components/panes/right_spec.js
@@ -3,12 +3,16 @@ import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import CollapsibleSidebar from '~/ide/components/panes/collapsible_sidebar.vue';
import RightPane from '~/ide/components/panes/right.vue';
+import SwitchEditorsView from '~/ide/components/switch_editors/switch_editors_view.vue';
import { rightSidebarViews } from '~/ide/constants';
import { createStore } from '~/ide/stores';
import extendStore from '~/ide/stores/extend';
+import { __ } from '~/locale';
Vue.use(Vuex);
+const SWITCH_EDITORS_VIEW_NAME = 'switch-editors';
+
describe('ide/components/panes/right.vue', () => {
let wrapper;
let store;
@@ -33,6 +37,19 @@ describe('ide/components/panes/right.vue', () => {
wrapper = null;
});
+ describe('default', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders collapsible-sidebar', () => {
+ expect(wrapper.findComponent(CollapsibleSidebar).props()).toMatchObject({
+ side: 'right',
+ initOpenView: SWITCH_EDITORS_VIEW_NAME,
+ });
+ });
+ });
+
describe('pipelines tab', () => {
it('is always shown', () => {
createComponent();
@@ -113,4 +130,32 @@ describe('ide/components/panes/right.vue', () => {
);
});
});
+
+ describe('switch editors tab', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it.each`
+ desc | canUseNewWebIde | expectedShow
+ ${'is shown'} | ${true} | ${true}
+ ${'is not shown'} | ${false} | ${false}
+ `('with canUseNewWebIde=$canUseNewWebIde, $desc', async ({ canUseNewWebIde, expectedShow }) => {
+ Object.assign(store.state, { canUseNewWebIde });
+
+ await nextTick();
+
+ expect(wrapper.findComponent(CollapsibleSidebar).props('extensionTabs')).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({
+ show: expectedShow,
+ title: __('Switch editors'),
+ views: [
+ { component: SwitchEditorsView, name: SWITCH_EDITORS_VIEW_NAME, keepAlive: true },
+ ],
+ }),
+ ]),
+ );
+ });
+ });
});
diff --git a/spec/frontend/ide/components/switch_editors/switch_editors_view_spec.js b/spec/frontend/ide/components/switch_editors/switch_editors_view_spec.js
new file mode 100644
index 00000000000..7a958391fea
--- /dev/null
+++ b/spec/frontend/ide/components/switch_editors/switch_editors_view_spec.js
@@ -0,0 +1,214 @@
+import { GlButton, GlEmptyState, GlLink } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import MockAdapter from 'axios-mock-adapter';
+import waitForPromises from 'helpers/wait_for_promises';
+import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
+import { createAlert } from '~/flash';
+import axios from '~/lib/utils/axios_utils';
+import { logError } from '~/lib/logger';
+import { __ } from '~/locale';
+import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
+import SwitchEditorsView, {
+ MSG_ERROR_ALERT,
+ MSG_CONFIRM,
+ MSG_TITLE,
+ MSG_LEARN_MORE,
+ MSG_DESCRIPTION,
+} from '~/ide/components/switch_editors/switch_editors_view.vue';
+import eventHub from '~/ide/eventhub';
+import { createStore } from '~/ide/stores';
+
+jest.mock('~/flash');
+jest.mock('~/lib/logger');
+jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
+
+const TEST_USER_PREFERENCES_PATH = '/test/user-pref/path';
+const TEST_SWITCH_EDITOR_SVG_PATH = '/test/switch/editor/path.svg';
+const TEST_HREF = '/test/new/web/ide/href';
+
+describe('~/ide/components/switch_editors/switch_editors_view.vue', () => {
+ useMockLocationHelper();
+
+ let store;
+ let wrapper;
+ let confirmResolve;
+ let requestSpy;
+ let skipBeforeunloadSpy;
+ let axiosMock;
+
+ // region: finders ------------------
+ const findButton = () => wrapper.findComponent(GlButton);
+ const findEmptyState = () => wrapper.findComponent(GlEmptyState);
+
+ // region: actions ------------------
+ const triggerSwitchPreference = () => findButton().vm.$emit('click');
+ const submitConfirm = async (val) => {
+ confirmResolve(val);
+
+ // why: We need to wait for promises for the immediate next lines to be executed
+ await waitForPromises();
+ };
+
+ const createComponent = () => {
+ wrapper = shallowMount(SwitchEditorsView, {
+ store,
+ stubs: {
+ GlEmptyState,
+ },
+ });
+ };
+
+ // region: test setup ------------------
+ beforeEach(() => {
+ // Setup skip-beforeunload side-effect
+ skipBeforeunloadSpy = jest.fn();
+ eventHub.$on('skip-beforeunload', skipBeforeunloadSpy);
+
+ // Setup request side-effect
+ requestSpy = jest.fn().mockImplementation(() => new Promise(() => {}));
+ axiosMock = new MockAdapter(axios);
+ axiosMock.onPut(TEST_USER_PREFERENCES_PATH).reply(({ data }) => requestSpy(data));
+
+ // Setup store
+ store = createStore();
+ store.state.userPreferencesPath = TEST_USER_PREFERENCES_PATH;
+ store.state.switchEditorSvgPath = TEST_SWITCH_EDITOR_SVG_PATH;
+ store.state.links = {
+ newWebIDEHelpPagePath: TEST_HREF,
+ };
+
+ // Setup user confirm side-effect
+ confirmAction.mockImplementation(
+ () =>
+ new Promise((resolve) => {
+ confirmResolve = resolve;
+ }),
+ );
+ });
+
+ afterEach(() => {
+ eventHub.$off('skip-beforeunload', skipBeforeunloadSpy);
+
+ axiosMock.restore();
+ });
+
+ // region: tests ------------------
+ describe('default', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('render empty state', () => {
+ expect(findEmptyState().props()).toMatchObject({
+ svgPath: TEST_SWITCH_EDITOR_SVG_PATH,
+ svgHeight: 150,
+ title: MSG_TITLE,
+ });
+ });
+
+ it('render link', () => {
+ expect(wrapper.findComponent(GlLink).attributes('href')).toBe(TEST_HREF);
+ expect(wrapper.findComponent(GlLink).text()).toBe(MSG_LEARN_MORE);
+ });
+
+ it('renders description', () => {
+ expect(findEmptyState().text()).toContain(MSG_DESCRIPTION);
+ });
+
+ it('is not loading', () => {
+ expect(findButton().props('loading')).toBe(false);
+ });
+ });
+
+ describe('when user triggers switch preference', () => {
+ beforeEach(() => {
+ createComponent();
+
+ triggerSwitchPreference();
+ });
+
+ it('creates a single confirm', () => {
+ // Call again to ensure that we only show 1 confirm action
+ triggerSwitchPreference();
+
+ expect(confirmAction).toHaveBeenCalledTimes(1);
+ expect(confirmAction).toHaveBeenCalledWith(MSG_CONFIRM, {
+ primaryBtnText: __('Switch editors'),
+ cancelBtnText: __('Cancel'),
+ });
+ });
+
+ it('starts loading', () => {
+ expect(findButton().props('loading')).toBe(true);
+ });
+
+ describe('when user cancels confirm', () => {
+ beforeEach(async () => {
+ await submitConfirm(false);
+ });
+
+ it('does not make request', () => {
+ expect(requestSpy).not.toHaveBeenCalled();
+ });
+
+ it('can be triggered again', () => {
+ triggerSwitchPreference();
+
+ expect(confirmAction).toHaveBeenCalledTimes(2);
+ });
+ });
+
+ describe('when user accepts confirm and response success', () => {
+ beforeEach(async () => {
+ requestSpy.mockReturnValue([200, {}]);
+ await submitConfirm(true);
+ });
+
+ it('does not handle error', () => {
+ expect(logError).not.toHaveBeenCalled();
+ expect(createAlert).not.toHaveBeenCalled();
+ });
+
+ it('emits "skip-beforeunload" and reloads', () => {
+ expect(skipBeforeunloadSpy).toHaveBeenCalledTimes(1);
+ expect(window.location.reload).toHaveBeenCalledTimes(1);
+ });
+
+ it('calls request', () => {
+ expect(requestSpy).toHaveBeenCalledTimes(1);
+ expect(requestSpy).toHaveBeenCalledWith(
+ JSON.stringify({ user: { use_legacy_web_ide: false } }),
+ );
+ });
+
+ it('is not loading', () => {
+ expect(findButton().props('loading')).toBe(false);
+ });
+ });
+
+ describe('when user accepts confirm and response fails', () => {
+ beforeEach(async () => {
+ requestSpy.mockReturnValue([400, {}]);
+ await submitConfirm(true);
+ });
+
+ it('handles error', () => {
+ expect(logError).toHaveBeenCalledTimes(1);
+ expect(logError).toHaveBeenCalledWith(
+ 'Error while updating user preferences',
+ expect.any(Error),
+ );
+
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith({
+ message: MSG_ERROR_ALERT,
+ });
+ });
+
+ it('does not reload', () => {
+ expect(skipBeforeunloadSpy).not.toHaveBeenCalled();
+ expect(window.location.reload).not.toHaveBeenCalled();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ide/stores/mutations_spec.js b/spec/frontend/ide/stores/mutations_spec.js
index 4117f2648bd..ae21d257bb2 100644
--- a/spec/frontend/ide/stores/mutations_spec.js
+++ b/spec/frontend/ide/stores/mutations_spec.js
@@ -87,11 +87,13 @@ describe('Multi-file store mutations', () => {
emptyStateSvgPath: 'emptyState',
noChangesStateSvgPath: 'noChanges',
committedStateSvgPath: 'committed',
+ switchEditorSvgPath: 'switchEditorSvg',
});
expect(localState.emptyStateSvgPath).toBe('emptyState');
expect(localState.noChangesStateSvgPath).toBe('noChanges');
expect(localState.committedStateSvgPath).toBe('committed');
+ expect(localState.switchEditorSvgPath).toBe('switchEditorSvg');
});
});
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 a0115cb9349..61f860688dc 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
@@ -1,10 +1,11 @@
-import { GlAlert, GlEmptyState, GlLoadingIcon } from '@gitlab/ui';
+import { GlAlert, GlEmptyState, GlIcon, GlLoadingIcon } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
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 httpStatus from '~/lib/utils/http_status';
import axios from '~/lib/utils/axios_utils';
@@ -50,6 +51,7 @@ describe('import table', () => {
rowWrapper.find('[data-testid="target-namespace-selector"]');
const findPaginationDropdownText = () => findPaginationDropdown().find('button').text();
const findSelectionCount = () => wrapper.find('[data-test-id="selection-count"]');
+ const findNewPathCol = () => wrapper.find('[data-test-id="new-path-col"]');
const triggerSelectAllCheckbox = (checked = true) =>
wrapper.find('thead input[type=checkbox]').setChecked(checked);
@@ -76,6 +78,9 @@ describe('import table', () => {
historyPath: '/fake_history_path',
defaultTargetNamespace,
},
+ directives: {
+ GlTooltip: createMockDirective(),
+ },
apolloProvider,
});
};
@@ -540,6 +545,26 @@ describe('import table', () => {
);
});
+ it('displays info icon with a tooltip', async () => {
+ const NEW_GROUPS = [generateFakeEntry({ id: 1, status: STATUSES.NONE })];
+
+ createComponent({
+ bulkImportSourceGroups: () => ({
+ nodes: NEW_GROUPS,
+ pageInfo: FAKE_PAGE_INFO,
+ versionValidation: FAKE_VERSION_VALIDATION,
+ }),
+ });
+ jest.spyOn(apolloProvider.defaultClient, 'mutate');
+ await waitForPromises();
+
+ const icon = findNewPathCol().findComponent(GlIcon);
+ const tooltip = getBinding(icon.element, 'gl-tooltip');
+
+ expect(tooltip).toBeDefined();
+ expect(tooltip.value).toBe('Path of the new group.');
+ });
+
describe('unavailable features warning', () => {
it('renders alert when there are unavailable features', async () => {
createComponent({
diff --git a/spec/frontend/integrations/edit/components/integration_form_spec.js b/spec/frontend/integrations/edit/components/integration_form_spec.js
index 0a3beee0507..7e67379f5ab 100644
--- a/spec/frontend/integrations/edit/components/integration_form_spec.js
+++ b/spec/frontend/integrations/edit/components/integration_form_spec.js
@@ -1,4 +1,4 @@
-import { GlBadge, GlForm } from '@gitlab/ui';
+import { GlAlert, GlBadge, GlForm } from '@gitlab/ui';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import * as Sentry from '@sentry/browser';
@@ -80,6 +80,7 @@ describe('IntegrationForm', () => {
const findInstanceOrGroupSaveButton = () => wrapper.findByTestId('save-button-instance-group');
const findTestButton = () => wrapper.findByTestId('test-button');
const findTriggerFields = () => wrapper.findComponent(TriggerFields);
+ const findAlert = () => wrapper.findComponent(GlAlert);
const findGlBadge = () => wrapper.findComponent(GlBadge);
const findGlForm = () => wrapper.findComponent(GlForm);
const findRedirectToField = () => wrapper.findByTestId('redirect-to-field');
@@ -715,45 +716,72 @@ describe('IntegrationForm', () => {
});
});
- describe('Help and sections rendering', () => {
- const dummyHelp = 'Foo Help';
+ describe('Slack integration', () => {
+ describe('Help and sections rendering', () => {
+ 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}
+ `(
+ '$sections sections, and "$helpHtml" helpHtml when the FF is "$flagIsOn" for "$integration" integration',
+ ({ integration, flagIsOn, helpHtml, sections, shouldShowSections, shouldShowHelp }) => {
+ createComponent({
+ provide: {
+ helpHtml,
+ glFeatures: { integrationSlackAppNotifications: flagIsOn },
+ },
+ customStateProps: {
+ sections,
+ type: integration,
+ },
+ });
+ expect(findAllSections().length > 0).toEqual(shouldShowSections);
+ expect(findHelpHtml().exists()).toBe(shouldShowHelp);
+ if (shouldShowHelp) {
+ expect(findHelpHtml().html()).toContain(helpHtml);
+ }
+ },
+ );
+ });
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}
+ 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}
`(
- '$sections sections, and "$helpHtml" helpHtml when the FF is "$flagIsOn" for "$integration" integration',
- ({ integration, flagIsOn, helpHtml, sections, shouldShowSections, shouldShowHelp }) => {
+ '$prefix render the upgrade warnning when we are in "$integration" integration with the flag "$flagIsOn" and Slack-needs-upgrade is "$shouldUpgradeSlack"',
+ ({ integration, shouldUpgradeSlack, flagIsOn, shouldShowAlert }) => {
createComponent({
provide: {
- helpHtml,
glFeatures: { integrationSlackAppNotifications: flagIsOn },
},
customStateProps: {
- sections,
+ shouldUpgradeSlack,
type: integration,
+ sections: [mockSectionConnection],
},
});
- expect(findAllSections().length > 0).toEqual(shouldShowSections);
- expect(findHelpHtml().exists()).toBe(shouldShowHelp);
- if (shouldShowHelp) {
- expect(findHelpHtml().html()).toContain(helpHtml);
- }
+ expect(findAlert().exists()).toBe(shouldShowAlert);
},
);
});
diff --git a/spec/frontend/integrations/edit/components/trigger_fields_spec.js b/spec/frontend/integrations/edit/components/trigger_fields_spec.js
index c329ca8522f..082eeea30f1 100644
--- a/spec/frontend/integrations/edit/components/trigger_fields_spec.js
+++ b/spec/frontend/integrations/edit/components/trigger_fields_spec.js
@@ -1,5 +1,6 @@
import { GlFormGroup, GlFormCheckbox, GlFormInput } from '@gitlab/ui';
import { mountExtended } from 'helpers/vue_test_utils_helper';
+import { placeholderForType } from 'jh_else_ce/integrations/constants';
import TriggerFields from '~/integrations/edit/components/trigger_fields.vue';
@@ -28,6 +29,50 @@ describe('TriggerFields', () => {
const findAllGlFormCheckboxes = () => wrapper.findAllComponents(GlFormCheckbox);
const findAllGlFormInputs = () => wrapper.findAllComponents(GlFormInput);
+ describe('placeholder text on the event fields and default values', () => {
+ const dummyFieldPlaceholder = '#foo';
+ const integrationTypes = {
+ INTEGRATION_TYPE_SLACK: 'slack',
+ INTEGRATION_TYPE_SLACK_APPLICATION: 'gitlab_slack_application',
+ INTEGRATION_TYPE_MATTERMOST: 'mattermost',
+ INTEGRATION_TYPE_NON_EXISTING: 'non_existing',
+ };
+ it.each`
+ integrationType | fieldPlaceholder | expectedPlaceholder
+ ${integrationTypes.INTEGRATION_TYPE_SLACK} | ${undefined} | ${placeholderForType[integrationTypes.INTEGRATION_TYPE_SLACK]}
+ ${integrationTypes.INTEGRATION_TYPE_SLACK} | ${''} | ${placeholderForType[integrationTypes.INTEGRATION_TYPE_SLACK]}
+ ${integrationTypes.INTEGRATION_TYPE_SLACK} | ${dummyFieldPlaceholder} | ${dummyFieldPlaceholder}
+ ${integrationTypes.INTEGRATION_TYPE_SLACK_APPLICATION} | ${undefined} | ${placeholderForType[integrationTypes.INTEGRATION_TYPE_SLACK_APPLICATION]}
+ ${integrationTypes.INTEGRATION_TYPE_SLACK_APPLICATION} | ${''} | ${placeholderForType[integrationTypes.INTEGRATION_TYPE_SLACK_APPLICATION]}
+ ${integrationTypes.INTEGRATION_TYPE_SLACK_APPLICATION} | ${dummyFieldPlaceholder} | ${dummyFieldPlaceholder}
+ ${integrationTypes.INTEGRATION_TYPE_MATTERMOST} | ${undefined} | ${placeholderForType[integrationTypes.INTEGRATION_TYPE_MATTERMOST]}
+ ${integrationTypes.INTEGRATION_TYPE_MATTERMOST} | ${''} | ${placeholderForType[integrationTypes.INTEGRATION_TYPE_MATTERMOST]}
+ ${integrationTypes.INTEGRATION_TYPE_MATTERMOST} | ${dummyFieldPlaceholder} | ${dummyFieldPlaceholder}
+ ${integrationTypes.INTEGRATION_TYPE_NON_EXISTING} | ${undefined} | ${undefined}
+ ${integrationTypes.INTEGRATION_TYPE_NON_EXISTING} | ${''} | ${undefined}
+ ${integrationTypes.INTEGRATION_TYPE_NON_EXISTING} | ${dummyFieldPlaceholder} | ${dummyFieldPlaceholder}
+ `(
+ 'passed down correct placeholder for "$integrationType" type and "$fieldPlaceholder" placeholder on the field',
+ ({ integrationType, fieldPlaceholder, expectedPlaceholder }) => {
+ createComponent({
+ type: integrationType,
+ events: [
+ {
+ field: {
+ name: 'foo',
+ value: '',
+ placeholder: fieldPlaceholder,
+ },
+ },
+ ],
+ });
+ const field = wrapper.findComponent(GlFormInput);
+
+ expect(field.attributes('placeholder')).toBe(expectedPlaceholder);
+ },
+ );
+ });
+
describe.each([true, false])('template, isInheriting = `%p`', (isInheriting) => {
it('renders a label with text "Trigger"', () => {
createComponent();
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 e9e1fbad07b..47be1933ed7 100644
--- a/spec/frontend/invite_members/components/invite_members_modal_spec.js
+++ b/spec/frontend/invite_members/components/invite_members_modal_spec.js
@@ -10,12 +10,12 @@ import InviteMembersModal from '~/invite_members/components/invite_members_modal
import InviteModalBase from '~/invite_members/components/invite_modal_base.vue';
import ModalConfetti from '~/invite_members/components/confetti.vue';
import MembersTokenSelect from '~/invite_members/components/members_token_select.vue';
+import UserLimitNotification from '~/invite_members/components/user_limit_notification.vue';
import {
INVITE_MEMBERS_FOR_TASK,
MEMBERS_MODAL_CELEBRATE_INTRO,
MEMBERS_MODAL_CELEBRATE_TITLE,
MEMBERS_PLACEHOLDER,
- MEMBERS_PLACEHOLDER_DISABLED,
MEMBERS_TO_PROJECT_CELEBRATE_INTRO_TEXT,
LEARN_GITLAB,
EXPANDED_ERRORS,
@@ -31,8 +31,6 @@ import {
propsData,
inviteSource,
newProjectPath,
- freeUsersLimit,
- membersCount,
user1,
user2,
user3,
@@ -99,6 +97,7 @@ describe('InviteMembersModal', () => {
const findIntroText = () => wrapper.findByTestId('modal-base-intro-text').text();
const findMemberErrorAlert = () => wrapper.findByTestId('alert-member-error');
const findMoreInviteErrorsButton = () => wrapper.findByTestId('accordion-button');
+ const findUserLimitAlert = () => wrapper.findComponent(UserLimitNotification);
const findAccordion = () => wrapper.findComponent(GlCollapse);
const findErrorsIcon = () => wrapper.findComponent(GlIcon);
const findMemberErrorMessage = (element) =>
@@ -112,7 +111,7 @@ describe('InviteMembersModal', () => {
const findMembersFormGroup = () => wrapper.findByTestId('members-form-group');
const membersFormGroupInvalidFeedback = () =>
findMembersFormGroup().attributes('invalid-feedback');
- const membersFormGroupText = () => findMembersFormGroup().text();
+ const membersFormGroupDescription = () => findMembersFormGroup().attributes('description');
const findMembersSelect = () => wrapper.findComponent(MembersTokenSelect);
const findTasksToBeDone = () => wrapper.findByTestId('invite-members-modal-tasks-to-be-done');
const findTasks = () => wrapper.findByTestId('invite-members-modal-tasks');
@@ -299,19 +298,8 @@ describe('InviteMembersModal', () => {
describe('members form group description', () => {
it('renders correct description', () => {
- createInviteMembersToProjectWrapper({ freeUsersLimit, membersCount }, { GlFormGroup });
- expect(membersFormGroupText()).toContain(MEMBERS_PLACEHOLDER);
- });
-
- describe('when reached user limit', () => {
- it('renders correct description', () => {
- createInviteMembersToProjectWrapper(
- { freeUsersLimit, membersCount: 5 },
- { GlFormGroup },
- );
-
- expect(membersFormGroupText()).toContain(MEMBERS_PLACEHOLDER_DISABLED);
- });
+ createInviteMembersToProjectWrapper({ GlFormGroup });
+ expect(membersFormGroupDescription()).toContain(MEMBERS_PLACEHOLDER);
});
});
});
@@ -339,23 +327,10 @@ describe('InviteMembersModal', () => {
describe('members form group description', () => {
it('renders correct description', async () => {
- createInviteMembersToProjectWrapper({ freeUsersLimit, membersCount }, { GlFormGroup });
+ createInviteMembersToProjectWrapper({ GlFormGroup });
await triggerOpenModal({ mode: 'celebrate' });
- expect(membersFormGroupText()).toContain(MEMBERS_PLACEHOLDER);
- });
-
- describe('when reached user limit', () => {
- it('renders correct description', async () => {
- createInviteMembersToProjectWrapper(
- { freeUsersLimit, membersCount: 5 },
- { GlFormGroup },
- );
-
- await triggerOpenModal({ mode: 'celebrate' });
-
- expect(membersFormGroupText()).toContain(MEMBERS_PLACEHOLDER_DISABLED);
- });
+ expect(membersFormGroupDescription()).toContain(MEMBERS_PLACEHOLDER);
});
});
});
@@ -370,20 +345,39 @@ describe('InviteMembersModal', () => {
describe('members form group description', () => {
it('renders correct description', () => {
- createInviteMembersToGroupWrapper({ freeUsersLimit, membersCount }, { GlFormGroup });
- expect(membersFormGroupText()).toContain(MEMBERS_PLACEHOLDER);
- });
-
- describe('when reached user limit', () => {
- it('renders correct description', () => {
- createInviteMembersToGroupWrapper({ freeUsersLimit, membersCount: 5 }, { GlFormGroup });
- expect(membersFormGroupText()).toContain(MEMBERS_PLACEHOLDER_DISABLED);
- });
+ createInviteMembersToGroupWrapper({ GlFormGroup });
+ expect(membersFormGroupDescription()).toContain(MEMBERS_PLACEHOLDER);
});
});
});
});
+ describe('rendering the user limit notification', () => {
+ it('shows the user limit notification alert when reached limit', () => {
+ const usersLimitDataset = { reachedLimit: true };
+
+ createInviteMembersToProjectWrapper(usersLimitDataset);
+
+ expect(findUserLimitAlert().exists()).toBe(true);
+ });
+
+ it('shows the user limit notification alert when close to dashboard limit', () => {
+ const usersLimitDataset = { closeToDashboardLimit: true };
+
+ createInviteMembersToProjectWrapper(usersLimitDataset);
+
+ expect(findUserLimitAlert().exists()).toBe(true);
+ });
+
+ it('does not show the user limit notification alert', () => {
+ const usersLimitDataset = {};
+
+ createInviteMembersToProjectWrapper(usersLimitDataset);
+
+ expect(findUserLimitAlert().exists()).toBe(false);
+ });
+ });
+
describe('submitting the invite form', () => {
const mockInvitationsApi = (code, data) => {
mock.onPost(GROUPS_INVITATIONS_PATH).reply(code, data);
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 b55eeb72471..aeead8809fd 100644
--- a/spec/frontend/invite_members/components/invite_modal_base_spec.js
+++ b/spec/frontend/invite_members/components/invite_modal_base_spec.js
@@ -18,10 +18,7 @@ import {
CANCEL_BUTTON_TEXT,
INVITE_BUTTON_TEXT_DISABLED,
INVITE_BUTTON_TEXT,
- CANCEL_BUTTON_TEXT_DISABLED,
ON_SHOW_TRACK_LABEL,
- ON_CLOSE_TRACK_LABEL,
- ON_SUBMIT_TRACK_LABEL,
} from '~/invite_members/constants';
import { propsData, membersPath, purchasePath } from '../mock_data/modal_base';
@@ -131,7 +128,9 @@ describe('InviteModalBase', () => {
it('renders description', () => {
createComponent({}, { GlFormGroup });
- expect(findMembersFormGroup().text()).toContain(propsData.formGroupDescription);
+ expect(findMembersFormGroup().attributes('description')).toContain(
+ propsData.formGroupDescription,
+ );
});
describe('when users limit is reached', () => {
@@ -145,30 +144,13 @@ describe('InviteModalBase', () => {
beforeEach(() => {
createComponent(
- { usersLimitDataset: { membersPath, purchasePath }, reachedLimit: true },
+ { usersLimitDataset: { membersPath, purchasePath, reachedLimit: true } },
{ GlModal, GlFormGroup },
);
});
- it('renders correct blocks', () => {
- expect(findIcon().exists()).toBe(true);
- expect(findDisabledInput().exists()).toBe(true);
- expect(findDropdown().exists()).toBe(false);
- expect(findDatepicker().exists()).toBe(false);
- });
-
- it('renders correct buttons', () => {
- const cancelButton = findCancelButton();
- const actionButton = findActionButton();
-
- expect(cancelButton.attributes('href')).toBe(purchasePath);
- expect(cancelButton.text()).toBe(CANCEL_BUTTON_TEXT_DISABLED);
- expect(actionButton.attributes('href')).toBe(membersPath);
- expect(actionButton.text()).toBe(INVITE_BUTTON_TEXT_DISABLED);
- });
-
it('tracks actions', () => {
- createComponent({ reachedLimit: true }, { GlFormGroup, GlModal });
+ createComponent({ usersLimitDataset: { reachedLimit: true } }, { GlFormGroup, GlModal });
trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
const modal = wrapper.findComponent(GlModal);
@@ -176,37 +158,20 @@ describe('InviteModalBase', () => {
modal.vm.$emit('shown');
expectTracking('render', ON_SHOW_TRACK_LABEL);
- modal.vm.$emit('cancel', { preventDefault: jest.fn() });
- expectTracking('click_button', ON_CLOSE_TRACK_LABEL);
-
- modal.vm.$emit('primary', { preventDefault: jest.fn() });
- expectTracking('click_button', ON_SUBMIT_TRACK_LABEL);
-
unmockTracking();
});
-
- describe('when free user namespace', () => {
- it('hides cancel button', () => {
- createComponent(
- {
- usersLimitDataset: { membersPath, purchasePath, userNamespace: true },
- reachedLimit: true,
- },
- { GlModal, GlFormGroup },
- );
-
- expect(findCancelButton().exists()).toBe(false);
- });
- });
});
describe('when user limit is close on a personal namespace', () => {
beforeEach(() => {
createComponent(
{
- closeToLimit: true,
- reachedLimit: false,
- usersLimitDataset: { membersPath, userNamespace: true },
+ usersLimitDataset: {
+ membersPath,
+ userNamespace: true,
+ closeToDashboardLimit: true,
+ reachedLimit: false,
+ },
},
{ GlModal, GlFormGroup },
);
diff --git a/spec/frontend/invite_members/components/user_limit_notification_spec.js b/spec/frontend/invite_members/components/user_limit_notification_spec.js
index 1ff2e86412f..2a780490468 100644
--- a/spec/frontend/invite_members/components/user_limit_notification_spec.js
+++ b/spec/frontend/invite_members/components/user_limit_notification_spec.js
@@ -1,8 +1,8 @@
import { GlAlert, GlSprintf } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import UserLimitNotification from '~/invite_members/components/user_limit_notification.vue';
-import { REACHED_LIMIT_UPGRADE_SUGGESTION_MESSAGE } from '~/invite_members/constants';
-import { freeUsersLimit, membersCount } from '../mock_data/member_modal';
+import { REACHED_LIMIT_VARIANT, CLOSE_TO_LIMIT_VARIANT } from '~/invite_members/constants';
+import { freeUsersLimit, remainingSeats } from '../mock_data/member_modal';
const WARNING_ALERT_TITLE = 'You only have space for 2 more members in name';
@@ -10,20 +10,16 @@ describe('UserLimitNotification', () => {
let wrapper;
const findAlert = () => wrapper.findComponent(GlAlert);
+ const findTrialLink = () => wrapper.findByTestId('trial-link');
+ const findUpgradeLink = () => wrapper.findByTestId('upgrade-link');
- const createComponent = (
- closeToLimit = false,
- reachedLimit = false,
- usersLimitDataset = {},
- props = {},
- ) => {
+ const createComponent = (limitVariant, usersLimitDataset = {}, props = {}) => {
wrapper = shallowMountExtended(UserLimitNotification, {
propsData: {
- closeToLimit,
- reachedLimit,
+ limitVariant,
usersLimitDataset: {
+ remainingSeats,
freeUsersLimit,
- membersCount,
newTrialRegistrationPath: 'newTrialRegistrationPath',
purchasePath: 'purchasePath',
...usersLimitDataset,
@@ -35,40 +31,46 @@ describe('UserLimitNotification', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('when limit is not reached', () => {
- it('renders empty block', () => {
- createComponent();
-
- expect(findAlert().exists()).toBe(false);
- });
- });
-
describe('when close to limit within a group', () => {
it("renders user's limit notification", () => {
- createComponent(true, false, { membersCount: 3 });
+ createComponent(CLOSE_TO_LIMIT_VARIANT);
const alert = findAlert();
expect(alert.attributes('title')).toEqual(WARNING_ALERT_TITLE);
- expect(alert.text()).toEqual(
- 'To get more members an owner of the group can start a trial or upgrade to a paid tier.',
- );
+ expect(alert.text()).toContain('To get more members an owner of the group can');
});
});
describe('when limit is reached', () => {
it("renders user's limit notification", () => {
- createComponent(true, true);
+ createComponent(REACHED_LIMIT_VARIANT);
const alert = findAlert();
expect(alert.attributes('title')).toEqual("You've reached your 5 members limit for name");
- expect(alert.text()).toEqual(REACHED_LIMIT_UPGRADE_SUGGESTION_MESSAGE);
+ expect(alert.text()).toContain(
+ 'To invite new users to this namespace, you must remove existing users.',
+ );
});
});
+
+ describe('tracking', () => {
+ it.each([CLOSE_TO_LIMIT_VARIANT, REACHED_LIMIT_VARIANT])(
+ `has tracking attributes for %j variant`,
+ (variant) => {
+ createComponent(variant);
+
+ expect(findTrialLink().attributes('data-track-action')).toBe('click_link');
+ expect(findTrialLink().attributes('data-track-label')).toBe(
+ `start_trial_user_limit_notification_${variant}`,
+ );
+ expect(findUpgradeLink().attributes('data-track-action')).toBe('click_link');
+ expect(findUpgradeLink().attributes('data-track-label')).toBe(
+ `upgrade_user_limit_notification_${variant}`,
+ );
+ },
+ );
+ });
});
diff --git a/spec/frontend/invite_members/mock_data/member_modal.js b/spec/frontend/invite_members/mock_data/member_modal.js
index 4f4e9345e46..59d58f21bb0 100644
--- a/spec/frontend/invite_members/mock_data/member_modal.js
+++ b/spec/frontend/invite_members/mock_data/member_modal.js
@@ -19,7 +19,7 @@ export const propsData = {
export const inviteSource = 'unknown';
export const newProjectPath = 'projects/new';
export const freeUsersLimit = 5;
-export const membersCount = 1;
+export const remainingSeats = 2;
export const user1 = { id: 1, name: 'Name One', username: 'one_1', avatar_url: '' };
export const user2 = { id: 2, name: 'Name Two', username: 'one_2', avatar_url: '' };
diff --git a/spec/frontend/issuable/bulk_update_sidebar/components/move_issues_button_spec.js b/spec/frontend/issuable/bulk_update_sidebar/components/move_issues_button_spec.js
new file mode 100644
index 00000000000..c432d722637
--- /dev/null
+++ b/spec/frontend/issuable/bulk_update_sidebar/components/move_issues_button_spec.js
@@ -0,0 +1,554 @@
+import { shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import { cloneDeep } from 'lodash';
+import VueApollo from 'vue-apollo';
+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 createFlash from '~/flash';
+import { logError } from '~/lib/logger';
+import IssuableMoveDropdown from '~/vue_shared/components/sidebar/issuable_move_dropdown.vue';
+import MoveIssuesButton from '~/issuable/bulk_update_sidebar/components/move_issues_button.vue';
+import issuableEventHub from '~/issues/list/eventhub';
+import moveIssueMutation from '~/issuable/bulk_update_sidebar/components/graphql/mutations/move_issue.mutation.graphql';
+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 { getIssuesCountsQueryResponse, getIssuesQueryResponse } from 'jest/issues/list/mock_data';
+import {
+ WORK_ITEM_TYPE_ENUM_ISSUE,
+ WORK_ITEM_TYPE_ENUM_INCIDENT,
+ WORK_ITEM_TYPE_ENUM_TASK,
+ WORK_ITEM_TYPE_ENUM_TEST_CASE,
+} from '~/work_items/constants';
+
+jest.mock('~/flash');
+jest.mock('~/lib/logger');
+useMockLocationHelper();
+
+const mockDefaultProps = {
+ projectFullPath: 'flight/FlightJS',
+ projectsFetchPath: '/-/autocomplete/projects?project_id=1',
+};
+
+const mockDestinationProject = {
+ full_path: 'gitlab-org/GitLabTest',
+};
+
+const mockMutationErrorMessage = 'Example error message';
+
+const mockIssue = {
+ iid: '15',
+ type: WORK_ITEM_TYPE_ENUM_ISSUE,
+};
+
+const mockIncident = {
+ iid: '32',
+ type: WORK_ITEM_TYPE_ENUM_INCIDENT,
+};
+
+const mockTask = {
+ iid: '40',
+ type: WORK_ITEM_TYPE_ENUM_TASK,
+};
+
+const mockTestCase = {
+ iid: '51',
+ type: WORK_ITEM_TYPE_ENUM_TEST_CASE,
+};
+
+const selectedIssuesMocks = {
+ tasksOnly: [mockTask],
+ testCasesOnly: [mockTestCase],
+ issuesOnly: [mockIssue, mockIncident],
+ tasksAndTestCases: [mockTask, mockTestCase],
+ issuesAndTasks: [mockIssue, mockIncident, mockTask],
+ issuesAndTestCases: [mockIssue, mockIncident, mockTestCase],
+ issuesTasksAndTestCases: [mockIssue, mockIncident, mockTask, mockTestCase],
+};
+
+let getIssuesQueryCompleteResponse = getIssuesQueryResponse;
+if (IS_EE) {
+ getIssuesQueryCompleteResponse = cloneDeep(getIssuesQueryResponse);
+ getIssuesQueryCompleteResponse.data.project.issues.nodes[0].blockingCount = 1;
+ getIssuesQueryCompleteResponse.data.project.issues.nodes[0].healthStatus = null;
+ getIssuesQueryCompleteResponse.data.project.issues.nodes[0].weight = 5;
+}
+
+const resolvedMutationWithoutErrorsMock = jest.fn().mockResolvedValue({
+ data: {
+ issueMove: {
+ errors: [],
+ },
+ },
+});
+
+const resolvedMutationWithErrorsMock = jest.fn().mockResolvedValue({
+ data: {
+ issueMove: {
+ errors: [{ message: mockMutationErrorMessage }],
+ },
+ },
+});
+
+const rejectedMutationMock = jest.fn().mockRejectedValue({});
+
+const mockIssuesQueryResponse = jest.fn().mockResolvedValue(getIssuesQueryCompleteResponse);
+const mockIssuesCountsQueryResponse = jest.fn().mockResolvedValue(getIssuesCountsQueryResponse);
+
+describe('MoveIssuesButton', () => {
+ Vue.use(VueApollo);
+
+ let wrapper;
+ let fakeApollo;
+
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findDropdown = () => wrapper.findComponent(IssuableMoveDropdown);
+ const emitMoveIssuablesEvent = () => {
+ findDropdown().vm.$emit('move-issuable', mockDestinationProject);
+ };
+
+ const createComponent = (data = {}, mutationResolverMock = rejectedMutationMock) => {
+ fakeApollo = createMockApollo([
+ [moveIssueMutation, mutationResolverMock],
+ [getIssuesQuery, mockIssuesQueryResponse],
+ [getIssuesCountsQuery, mockIssuesCountsQueryResponse],
+ ]);
+
+ fakeApollo.defaultClient.cache.writeQuery({
+ query: getIssuesQuery,
+ variables: {
+ isProject: true,
+ fullPath: mockDefaultProps.projectFullPath,
+ },
+ data: getIssuesQueryCompleteResponse.data,
+ });
+
+ fakeApollo.defaultClient.cache.writeQuery({
+ query: getIssuesCountsQuery,
+ variables: {
+ isProject: true,
+ },
+ data: getIssuesCountsQueryResponse.data,
+ });
+
+ wrapper = shallowMount(MoveIssuesButton, {
+ data() {
+ return {
+ ...data,
+ };
+ },
+ propsData: {
+ ...mockDefaultProps,
+ },
+ apolloProvider: fakeApollo,
+ });
+ };
+
+ beforeEach(() => {
+ // Needed due to a bug in Apollo: https://github.com/apollographql/apollo-client/issues/8900
+ // eslint-disable-next-line no-console
+ console.warn = jest.fn();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ fakeApollo = null;
+ });
+
+ describe('`Move selected` dropdown', () => {
+ it('renders disabled by default', () => {
+ createComponent();
+ expect(findDropdown().exists()).toBe(true);
+ expect(findDropdown().attributes('disabled')).toBe('true');
+ });
+
+ it.each`
+ selectedIssuablesMock | disabled | status | testMessage
+ ${[]} | ${true} | ${'disabled'} | ${'nothing is selected'}
+ ${selectedIssuesMocks.tasksOnly} | ${true} | ${'disabled'} | ${'only tasks are selected'}
+ ${selectedIssuesMocks.testCasesOnly} | ${true} | ${'disabled'} | ${'only test cases are selected'}
+ ${selectedIssuesMocks.issuesOnly} | ${false} | ${'enabled'} | ${'only issues are selected'}
+ ${selectedIssuesMocks.tasksAndTestCases} | ${true} | ${'disabled'} | ${'tasks and test cases are selected'}
+ ${selectedIssuesMocks.issuesAndTasks} | ${false} | ${'enabled'} | ${'issues and tasks are selected'}
+ ${selectedIssuesMocks.issuesAndTestCases} | ${false} | ${'enabled'} | ${'issues and test cases are selected'}
+ ${selectedIssuesMocks.issuesTasksAndTestCases} | ${false} | ${'enabled'} | ${'issues and tasks and test cases are selected'}
+ `('renders $status if $testMessage', async ({ selectedIssuablesMock, disabled }) => {
+ createComponent({ selectedIssuables: selectedIssuablesMock });
+
+ await nextTick();
+
+ if (disabled) {
+ expect(findDropdown().attributes('disabled')).toBe('true');
+ } else {
+ expect(findDropdown().attributes('disabled')).toBeUndefined();
+ }
+ });
+ });
+
+ describe('warning message', () => {
+ it.each`
+ selectedIssuablesMock | warningExists | visibility | message | testMessage
+ ${[]} | ${false} | ${'not visible'} | ${'empty'} | ${'nothing is selected'}
+ ${selectedIssuesMocks.tasksOnly} | ${true} | ${'visible'} | ${'Tasks can not be moved.'} | ${'only tasks are selected'}
+ ${selectedIssuesMocks.testCasesOnly} | ${true} | ${'visible'} | ${'Test cases can not be moved.'} | ${'only test cases are selected'}
+ ${selectedIssuesMocks.issuesOnly} | ${false} | ${'not visible'} | ${'empty'} | ${'only issues are selected'}
+ ${selectedIssuesMocks.tasksAndTestCases} | ${true} | ${'visible'} | ${'Tasks and test cases can not be moved.'} | ${'tasks and test cases are selected'}
+ ${selectedIssuesMocks.issuesAndTasks} | ${true} | ${'visible'} | ${'Tasks can not be moved.'} | ${'issues and tasks are selected'}
+ ${selectedIssuesMocks.issuesAndTestCases} | ${true} | ${'visible'} | ${'Test cases can not be moved.'} | ${'issues and test cases are selected'}
+ ${selectedIssuesMocks.issuesTasksAndTestCases} | ${true} | ${'visible'} | ${'Tasks and test cases can not be moved.'} | ${'issues and tasks and test cases are selected'}
+ `(
+ 'is $visibility with `$message` message if $testMessage',
+ async ({ selectedIssuablesMock, warningExists, message }) => {
+ createComponent({ selectedIssuables: selectedIssuablesMock });
+
+ await nextTick();
+
+ const alert = findAlert();
+ expect(alert.exists()).toBe(warningExists);
+
+ if (warningExists) {
+ expect(alert.text()).toBe(message);
+ expect(alert.attributes('variant')).toBe('warning');
+ }
+ },
+ );
+ });
+
+ describe('moveIssues method', () => {
+ describe('changes the `Move selected` dropdown loading state', () => {
+ it('keeps loading state to false when no issue is selected', async () => {
+ createComponent();
+ emitMoveIssuablesEvent();
+
+ await nextTick();
+
+ expect(findDropdown().props('moveInProgress')).toBe(false);
+ });
+
+ it('keeps loading state to false when only tasks are selected', async () => {
+ createComponent({ selectedIssuables: selectedIssuesMocks.tasksOnly });
+ emitMoveIssuablesEvent();
+
+ await nextTick();
+
+ expect(findDropdown().props('moveInProgress')).toBe(false);
+ });
+
+ it('keeps loading state to false when only test cases are selected', async () => {
+ createComponent({ selectedIssuables: selectedIssuesMocks.testCasesOnly });
+ emitMoveIssuablesEvent();
+
+ await nextTick();
+
+ expect(findDropdown().props('moveInProgress')).toBe(false);
+ });
+
+ it('keeps loading state to false when only tasks and test cases are selected', async () => {
+ createComponent({ selectedIssuables: selectedIssuesMocks.tasksAndTestCases });
+ emitMoveIssuablesEvent();
+
+ await nextTick();
+
+ expect(findDropdown().props('moveInProgress')).toBe(false);
+ });
+
+ it('sets loading state to true when issues are moving', async () => {
+ createComponent({ selectedIssuables: selectedIssuesMocks.issuesTasksAndTestCases });
+ emitMoveIssuablesEvent();
+
+ await nextTick();
+
+ expect(findDropdown().props('moveInProgress')).toBe(true);
+ });
+
+ it('sets loading state to false when all mutations succeed', async () => {
+ createComponent(
+ { selectedIssuables: selectedIssuesMocks.issuesTasksAndTestCases },
+ resolvedMutationWithoutErrorsMock,
+ );
+ emitMoveIssuablesEvent();
+
+ await nextTick();
+ await waitForPromises();
+
+ expect(findDropdown().props('moveInProgress')).toBe(false);
+ });
+
+ it('sets loading state to false when a mutation returns errors', async () => {
+ createComponent(
+ { selectedIssuables: selectedIssuesMocks.issuesTasksAndTestCases },
+ resolvedMutationWithErrorsMock,
+ );
+ emitMoveIssuablesEvent();
+
+ await nextTick();
+ await waitForPromises();
+
+ expect(findDropdown().props('moveInProgress')).toBe(false);
+ });
+
+ it('sets loading state to false when a mutation is rejected', async () => {
+ createComponent({ selectedIssuables: selectedIssuesMocks.issuesTasksAndTestCases });
+ emitMoveIssuablesEvent();
+
+ await nextTick();
+ await waitForPromises();
+
+ expect(findDropdown().props('moveInProgress')).toBe(false);
+ });
+ });
+
+ describe('handles events', () => {
+ beforeEach(() => {
+ jest.spyOn(issuableEventHub, '$emit');
+ });
+
+ it('does not emit any event when no issue is selected', async () => {
+ createComponent();
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(issuableEventHub.$emit).not.toHaveBeenCalled();
+ });
+
+ it('does not emit any event when only tasks are selected', async () => {
+ createComponent({ selectedIssuables: selectedIssuesMocks.tasksOnly });
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(issuableEventHub.$emit).not.toHaveBeenCalled();
+ });
+
+ it('does not emit any event when only test cases are selected', async () => {
+ createComponent({ selectedIssuables: selectedIssuesMocks.testCasesOnly });
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(issuableEventHub.$emit).not.toHaveBeenCalled();
+ });
+
+ it('does not emit any event when only tasks and test cases are selected', async () => {
+ createComponent({ selectedIssuables: selectedIssuesMocks.tasksAndTestCases });
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(issuableEventHub.$emit).not.toHaveBeenCalled();
+ });
+
+ it('emits `issuables:bulkMoveStarted` when issues are moving', async () => {
+ createComponent({ selectedIssuables: selectedIssuesMocks.issuesTasksAndTestCases });
+ emitMoveIssuablesEvent();
+
+ expect(issuableEventHub.$emit).toHaveBeenCalledWith('issuables:bulkMoveStarted');
+ });
+
+ it('emits `issuables:bulkMoveEnded` when all mutations succeed', async () => {
+ createComponent(
+ { selectedIssuables: selectedIssuesMocks.issuesTasksAndTestCases },
+ resolvedMutationWithoutErrorsMock,
+ );
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(issuableEventHub.$emit).toHaveBeenCalledWith('issuables:bulkMoveEnded');
+ });
+
+ it('emits `issuables:bulkMoveEnded` when a mutation returns errors', async () => {
+ createComponent(
+ { selectedIssuables: selectedIssuesMocks.issuesTasksAndTestCases },
+ resolvedMutationWithErrorsMock,
+ );
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(issuableEventHub.$emit).toHaveBeenCalledWith('issuables:bulkMoveEnded');
+ });
+
+ it('emits `issuables:bulkMoveEnded` when a mutation is rejected', async () => {
+ createComponent({ selectedIssuables: selectedIssuesMocks.issuesTasksAndTestCases });
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(issuableEventHub.$emit).toHaveBeenCalledWith('issuables:bulkMoveEnded');
+ });
+ });
+
+ describe('shows errors', () => {
+ it('does not create flashes or logs errors when no issue is selected', async () => {
+ createComponent();
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(logError).not.toHaveBeenCalled();
+ expect(createFlash).not.toHaveBeenCalled();
+ });
+
+ it('does not create flashes or logs errors when only tasks are selected', async () => {
+ createComponent({ selectedIssuables: selectedIssuesMocks.tasksOnly });
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(logError).not.toHaveBeenCalled();
+ expect(createFlash).not.toHaveBeenCalled();
+ });
+
+ it('does not create flashes or logs errors when only test cases are selected', async () => {
+ createComponent({ selectedIssuables: selectedIssuesMocks.testCasesOnly });
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(logError).not.toHaveBeenCalled();
+ expect(createFlash).not.toHaveBeenCalled();
+ });
+
+ it('does not create flashes or logs errors when only tasks and test cases are selected', async () => {
+ createComponent({ selectedIssuables: selectedIssuesMocks.tasksAndTestCases });
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(logError).not.toHaveBeenCalled();
+ expect(createFlash).not.toHaveBeenCalled();
+ });
+
+ it('does not create flashes or logs errors when issues are moved without errors', async () => {
+ createComponent(
+ { selectedIssuables: selectedIssuesMocks.issuesTasksAndTestCases },
+ resolvedMutationWithoutErrorsMock,
+ );
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(logError).not.toHaveBeenCalled();
+ expect(createFlash).not.toHaveBeenCalled();
+ });
+
+ it('creates a flash and logs errors when a mutation returns errors', async () => {
+ createComponent(
+ { selectedIssuables: selectedIssuesMocks.issuesTasksAndTestCases },
+ resolvedMutationWithErrorsMock,
+ );
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ // We're mocking two issues so it will log two errors
+ expect(logError).toHaveBeenCalledTimes(2);
+ expect(logError).toHaveBeenNthCalledWith(
+ 1,
+ `Error moving issue. Error message: ${mockMutationErrorMessage}`,
+ );
+ expect(logError).toHaveBeenNthCalledWith(
+ 2,
+ `Error moving issue. Error message: ${mockMutationErrorMessage}`,
+ );
+
+ // Only one flash is created even if multiple errors are reported
+ expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createFlash).toHaveBeenCalledWith({
+ message: 'There was an error while moving the issues.',
+ });
+ });
+
+ it('creates a flash but not logs errors when a mutation is rejected', async () => {
+ createComponent({ selectedIssuables: selectedIssuesMocks.issuesTasksAndTestCases });
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(logError).not.toHaveBeenCalled();
+ expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createFlash).toHaveBeenCalledWith({
+ message: 'There was an error while moving the issues.',
+ });
+ });
+ });
+
+ describe('calls mutations', () => {
+ it('does not call any mutation when no issue is selected', async () => {
+ createComponent({}, resolvedMutationWithoutErrorsMock);
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(resolvedMutationWithoutErrorsMock).not.toHaveBeenCalled();
+ });
+
+ it('does not call any mutation when only tasks are selected', async () => {
+ createComponent(
+ { selectedIssuables: selectedIssuesMocks.tasksOnly },
+ resolvedMutationWithoutErrorsMock,
+ );
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(resolvedMutationWithoutErrorsMock).not.toHaveBeenCalled();
+ });
+
+ it('does not call any mutation when only test cases are selected', async () => {
+ createComponent(
+ { selectedIssuables: selectedIssuesMocks.testCasesOnly },
+ resolvedMutationWithoutErrorsMock,
+ );
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(resolvedMutationWithoutErrorsMock).not.toHaveBeenCalled();
+ });
+
+ it('does not call any mutation when only tasks and test cases are selected', async () => {
+ createComponent(
+ { selectedIssuables: selectedIssuesMocks.tasksAndTestCases },
+ resolvedMutationWithoutErrorsMock,
+ );
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ expect(resolvedMutationWithoutErrorsMock).not.toHaveBeenCalled();
+ });
+
+ it('calls a mutation for every selected issue skipping tasks', async () => {
+ createComponent(
+ { selectedIssuables: selectedIssuesMocks.issuesTasksAndTestCases },
+ resolvedMutationWithoutErrorsMock,
+ );
+ emitMoveIssuablesEvent();
+
+ await waitForPromises();
+
+ // We mock three elements but only two are valid issues since the task is skipped
+ expect(resolvedMutationWithoutErrorsMock).toHaveBeenCalledTimes(2);
+ expect(resolvedMutationWithoutErrorsMock).toHaveBeenNthCalledWith(1, {
+ moveIssueInput: {
+ projectPath: mockDefaultProps.projectFullPath,
+ iid: selectedIssuesMocks.issuesTasksAndTestCases[0].iid.toString(),
+ targetProjectPath: mockDestinationProject.full_path,
+ },
+ });
+
+ expect(resolvedMutationWithoutErrorsMock).toHaveBeenNthCalledWith(2, {
+ moveIssueInput: {
+ projectPath: mockDefaultProps.projectFullPath,
+ iid: selectedIssuesMocks.issuesTasksAndTestCases[1].iid.toString(),
+ targetProjectPath: mockDestinationProject.full_path,
+ },
+ });
+ });
+ });
+ });
+});
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 1b2935ce5d1..996b2406240 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
@@ -40,12 +40,12 @@ describe('RelatedIssuesBlock', () => {
});
it.each`
- issuableType | pathIdSeparator | titleText | helpLinkText | addButtonText
- ${'issue'} | ${PathIdSeparator.Issue} | ${'Linked items'} | ${'Read more about related issues'} | ${'Add a related issue'}
- ${'epic'} | ${PathIdSeparator.Epic} | ${'Linked epics'} | ${'Read more about related epics'} | ${'Add a related epic'}
+ issuableType | pathIdSeparator | titleText | addButtonText
+ ${'issue'} | ${PathIdSeparator.Issue} | ${'Linked items'} | ${'Add a related issue'}
+ ${'epic'} | ${PathIdSeparator.Epic} | ${'Linked epics'} | ${'Add a related epic'}
`(
- 'displays "$titleText" in the header, "$helpLinkText" aria-label for help link, and "$addButtonText" aria-label for add button when issuableType is set to "$issuableType"',
- ({ issuableType, pathIdSeparator, titleText, helpLinkText, addButtonText }) => {
+ 'displays "$titleText" in the header and "$addButtonText" aria-label for add button when issuableType is set to "$issuableType"',
+ ({ issuableType, pathIdSeparator, titleText, addButtonText }) => {
wrapper = mountExtended(RelatedIssuesBlock, {
propsData: {
pathIdSeparator,
@@ -56,9 +56,6 @@ describe('RelatedIssuesBlock', () => {
});
expect(wrapper.find('.card-title').text()).toContain(titleText);
- expect(wrapper.find('[data-testid="help-link"]').attributes('aria-label')).toBe(
- helpLinkText,
- );
expect(findIssueCountBadgeAddButton().attributes('aria-label')).toBe(addButtonText);
},
);
@@ -100,7 +97,7 @@ describe('RelatedIssuesBlock', () => {
slots: { 'header-actions': headerActions },
});
- expect(wrapper.find('[data-testid="custom-button"]').html()).toBe(headerActions);
+ expect(wrapper.findByTestId('custom-button').html()).toBe(headerActions);
});
});
@@ -260,15 +257,30 @@ describe('RelatedIssuesBlock', () => {
});
});
- it('toggle button is disabled when issue has no related items', () => {
- wrapper = shallowMountExtended(RelatedIssuesBlock, {
- propsData: {
- pathIdSeparator: PathIdSeparator.Issue,
- relatedIssues: [],
- issuableType: 'issue',
- },
- });
+ describe('empty state', () => {
+ it.each`
+ issuableType | pathIdSeparator | showCategorizedIssues | emptyText | helpLinkText
+ ${'issue'} | ${PathIdSeparator.Issue} | ${false} | ${"Link issues together to show that they're related."} | ${'Learn more about linking issues'}
+ ${'issue'} | ${PathIdSeparator.Issue} | ${true} | ${"Link issues together to show that they're related or that one is blocking others."} | ${'Learn more about linking issues'}
+ ${'incident'} | ${PathIdSeparator.Issue} | ${false} | ${"Link incidents together to show that they're related."} | ${'Learn more about linking issues and incidents'}
+ ${'incident'} | ${PathIdSeparator.Issue} | ${true} | ${"Link incidents together to show that they're related or that one is blocking others."} | ${'Learn more about linking issues and incidents'}
+ ${'epic'} | ${PathIdSeparator.Epic} | ${true} | ${"Link epics together to show that they're related or that one is blocking others."} | ${'Learn more about linking epics'}
+ `(
+ 'displays "$emptyText" in the body and "$helpLinkText" aria-label for help link',
+ ({ issuableType, pathIdSeparator, showCategorizedIssues, emptyText, helpLinkText }) => {
+ wrapper = mountExtended(RelatedIssuesBlock, {
+ propsData: {
+ pathIdSeparator,
+ issuableType,
+ canAdmin: true,
+ helpPath: '/help/user/project/issues/related_issues',
+ showCategorizedIssues,
+ },
+ });
- expect(findToggleButton().props('disabled')).toBe(true);
+ expect(wrapper.findByTestId('related-issues-body').text()).toContain(emptyText);
+ expect(wrapper.findByTestId('help-link').attributes('aria-label')).toBe(helpLinkText);
+ },
+ );
});
});
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 680dbd68493..bedf8bcaf34 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
@@ -201,18 +201,20 @@ describe('RelatedIssuesRoot', () => {
]);
});
- it('displays a message from the backend upon error', async () => {
+ it('passes an error message from the backend upon error', async () => {
const input = '#123';
const message = 'error';
mock.onPost(defaultProps.endpoint).reply(409, { message });
wrapper.vm.store.setPendingReferences([issuable1.reference, issuable2.reference]);
- expect(createAlert).not.toHaveBeenCalled();
+ expect(findRelatedIssuesBlock().props('hasError')).toBe(false);
+ expect(findRelatedIssuesBlock().props('itemAddFailureMessage')).toBe(null);
findRelatedIssuesBlock().vm.$emit('addIssuableFormSubmit', input);
await waitForPromises();
- expect(createAlert).toHaveBeenCalledWith({ message });
+ expect(findRelatedIssuesBlock().props('hasError')).toBe(true);
+ expect(findRelatedIssuesBlock().props('itemAddFailureMessage')).toBe(message);
});
});
diff --git a/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js b/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
new file mode 100644
index 00000000000..3f72396cce6
--- /dev/null
+++ b/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
@@ -0,0 +1,58 @@
+import { GlEmptyState } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import IssuesDashboardApp from '~/issues/dashboard/components/issues_dashboard_app.vue';
+import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
+import { IssuableStates } from '~/vue_shared/issuable/list/constants';
+
+describe('IssuesDashboardApp component', () => {
+ let wrapper;
+
+ const defaultProvide = {
+ calendarPath: 'calendar/path',
+ emptyStateSvgPath: 'empty-state.svg',
+ isSignedIn: true,
+ rssPath: 'rss/path',
+ };
+
+ const findCalendarButton = () =>
+ wrapper.findByRole('link', { name: IssuesDashboardApp.i18n.calendarButtonText });
+ const findEmptyState = () => wrapper.findComponent(GlEmptyState);
+ const findIssuableList = () => wrapper.findComponent(IssuableList);
+ const findRssButton = () =>
+ wrapper.findByRole('link', { name: IssuesDashboardApp.i18n.rssButtonText });
+
+ const mountComponent = () => {
+ wrapper = mountExtended(IssuesDashboardApp, { provide: defaultProvide });
+ };
+
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('renders IssuableList component', () => {
+ expect(findIssuableList().props()).toMatchObject({
+ currentTab: IssuableStates.Opened,
+ namespace: 'dashboard',
+ recentSearchesStorageKey: 'issues',
+ searchInputPlaceholder: IssuesDashboardApp.i18n.searchInputPlaceholder,
+ tabs: IssuesDashboardApp.IssuableListTabs,
+ });
+ });
+
+ it('renders RSS button link', () => {
+ expect(findRssButton().attributes('href')).toBe(defaultProvide.rssPath);
+ expect(findRssButton().props('icon')).toBe('rss');
+ });
+
+ it('renders calendar button link', () => {
+ expect(findCalendarButton().attributes('href')).toBe(defaultProvide.calendarPath);
+ expect(findCalendarButton().props('icon')).toBe('calendar');
+ });
+
+ it('renders empty state', () => {
+ expect(findEmptyState().props()).toMatchObject({
+ svgPath: defaultProvide.emptyStateSvgPath,
+ title: IssuesDashboardApp.i18n.emptyStateTitle,
+ });
+ });
+});
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 5133c02b190..d0c93c896b3 100644
--- a/spec/frontend/issues/list/components/issues_list_app_spec.js
+++ b/spec/frontend/issues/list/components/issues_list_app_spec.js
@@ -33,16 +33,6 @@ import {
CREATED_DESC,
RELATIVE_POSITION,
RELATIVE_POSITION_ASC,
- TOKEN_TYPE_ASSIGNEE,
- TOKEN_TYPE_AUTHOR,
- TOKEN_TYPE_CONFIDENTIAL,
- TOKEN_TYPE_CONTACT,
- TOKEN_TYPE_LABEL,
- TOKEN_TYPE_MILESTONE,
- TOKEN_TYPE_MY_REACTION,
- TOKEN_TYPE_ORGANIZATION,
- TOKEN_TYPE_RELEASE,
- TOKEN_TYPE_TYPE,
urlSortParams,
} from '~/issues/list/constants';
import eventHub from '~/issues/list/eventhub';
@@ -57,7 +47,19 @@ import {
WORK_ITEM_TYPE_ENUM_TASK,
WORK_ITEM_TYPE_ENUM_TEST_CASE,
} from '~/work_items/constants';
-import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
+import {
+ FILTERED_SEARCH_TERM,
+ TOKEN_TYPE_ASSIGNEE,
+ TOKEN_TYPE_AUTHOR,
+ TOKEN_TYPE_CONFIDENTIAL,
+ TOKEN_TYPE_CONTACT,
+ TOKEN_TYPE_LABEL,
+ TOKEN_TYPE_MILESTONE,
+ TOKEN_TYPE_MY_REACTION,
+ TOKEN_TYPE_ORGANIZATION,
+ TOKEN_TYPE_RELEASE,
+ TOKEN_TYPE_TYPE,
+} from '~/vue_shared/components/filtered_search_bar/constants';
import('~/issuable/bulk_update_sidebar');
import('~/users_select');
@@ -89,7 +91,6 @@ describe('CE IssuesListApp component', () => {
hasIssuableHealthStatusFeature: true,
hasIssueWeightsFeature: true,
hasIterationsFeature: true,
- hasMultipleIssueAssigneesFeature: true,
hasScopedLabelsFeature: true,
initialEmail: 'email@example.com',
initialSort: CREATED_DESC,
@@ -131,7 +132,6 @@ describe('CE IssuesListApp component', () => {
const mountComponent = ({
provide = {},
data = {},
- workItems = false,
issuesQueryResponse = mockIssuesQueryResponse,
issuesCountsQueryResponse = mockIssuesCountsQueryResponse,
sortPreferenceMutationResponse = jest.fn().mockResolvedValue(setSortPreferenceMutationResponse),
@@ -150,9 +150,6 @@ describe('CE IssuesListApp component', () => {
apolloProvider: createMockApollo(requestHandlers),
router,
provide: {
- glFeatures: {
- workItems,
- },
...defaultProvide,
...provide,
},
@@ -605,17 +602,20 @@ describe('CE IssuesListApp component', () => {
beforeEach(() => {
wrapper = mountComponent({
provide: { hasAnyIssues: false, isSignedIn: false },
+ mountFn: mount,
});
});
it('shows empty state', () => {
expect(findGlEmptyState().props()).toMatchObject({
- description: IssuesListApp.i18n.noIssuesSignedOutDescription,
title: IssuesListApp.i18n.noIssuesSignedOutTitle,
svgPath: defaultProvide.emptyStateSvgPath,
primaryButtonText: IssuesListApp.i18n.noIssuesSignedOutButtonText,
primaryButtonLink: defaultProvide.signInPath,
});
+ expect(findGlEmptyState().text()).toContain(
+ IssuesListApp.i18n.noIssuesSignedOutDescription,
+ );
});
});
});
@@ -1060,45 +1060,23 @@ describe('CE IssuesListApp component', () => {
});
describe('fetching issues', () => {
- describe('when work_items feature flag is disabled', () => {
- beforeEach(() => {
- wrapper = mountComponent({ workItems: false });
- jest.runOnlyPendingTimers();
- });
-
- it('fetches issue, incident, and test case types', () => {
- const types = [
- WORK_ITEM_TYPE_ENUM_ISSUE,
- WORK_ITEM_TYPE_ENUM_INCIDENT,
- WORK_ITEM_TYPE_ENUM_TEST_CASE,
- ];
-
- expect(mockIssuesQueryResponse).toHaveBeenCalledWith(expect.objectContaining({ types }));
- expect(mockIssuesCountsQueryResponse).toHaveBeenCalledWith(
- expect.objectContaining({ types }),
- );
- });
+ beforeEach(() => {
+ wrapper = mountComponent();
+ jest.runOnlyPendingTimers();
});
- describe('when work_items feature flag is enabled', () => {
- beforeEach(() => {
- wrapper = mountComponent({ workItems: true });
- jest.runOnlyPendingTimers();
- });
-
- it('fetches issue, incident, test case, and task types', () => {
- const types = [
- WORK_ITEM_TYPE_ENUM_ISSUE,
- WORK_ITEM_TYPE_ENUM_INCIDENT,
- WORK_ITEM_TYPE_ENUM_TEST_CASE,
- WORK_ITEM_TYPE_ENUM_TASK,
- ];
-
- expect(mockIssuesQueryResponse).toHaveBeenCalledWith(expect.objectContaining({ types }));
- expect(mockIssuesCountsQueryResponse).toHaveBeenCalledWith(
- expect.objectContaining({ types }),
- );
- });
+ it('fetches issue, incident, test case, and task types', () => {
+ const types = [
+ WORK_ITEM_TYPE_ENUM_ISSUE,
+ WORK_ITEM_TYPE_ENUM_INCIDENT,
+ WORK_ITEM_TYPE_ENUM_TEST_CASE,
+ WORK_ITEM_TYPE_ENUM_TASK,
+ ];
+
+ expect(mockIssuesQueryResponse).toHaveBeenCalledWith(expect.objectContaining({ types }));
+ expect(mockIssuesCountsQueryResponse).toHaveBeenCalledWith(
+ expect.objectContaining({ types }),
+ );
});
});
});
diff --git a/spec/frontend/issues/list/mock_data.js b/spec/frontend/issues/list/mock_data.js
index 42e9d348b16..62fcbf7aad0 100644
--- a/spec/frontend/issues/list/mock_data.js
+++ b/spec/frontend/issues/list/mock_data.js
@@ -1,6 +1,21 @@
import {
+ FILTERED_SEARCH_TERM,
OPERATOR_IS,
OPERATOR_IS_NOT,
+ OPERATOR_OR,
+ TOKEN_TYPE_ASSIGNEE,
+ TOKEN_TYPE_AUTHOR,
+ TOKEN_TYPE_CONFIDENTIAL,
+ TOKEN_TYPE_CONTACT,
+ TOKEN_TYPE_EPIC,
+ TOKEN_TYPE_ITERATION,
+ TOKEN_TYPE_LABEL,
+ TOKEN_TYPE_MILESTONE,
+ TOKEN_TYPE_MY_REACTION,
+ TOKEN_TYPE_ORGANIZATION,
+ TOKEN_TYPE_RELEASE,
+ TOKEN_TYPE_TYPE,
+ TOKEN_TYPE_WEIGHT,
} from '~/vue_shared/components/filtered_search_bar/constants';
export const getIssuesQueryResponse = {
@@ -122,6 +137,8 @@ export const locationSearch = [
'assignee_username[]=5',
'not[assignee_username][]=patty',
'not[assignee_username][]=selma',
+ 'or[assignee_username][]=carl',
+ 'or[assignee_username][]=lenny',
'milestone_title=season+3',
'milestone_title=season+4',
'not[milestone_title]=season+20',
@@ -166,56 +183,58 @@ export const locationSearchWithSpecialValues = [
].join('&');
export const filteredTokens = [
- { type: 'author_username', value: { data: 'homer', operator: OPERATOR_IS } },
- { type: 'author_username', value: { data: 'marge', operator: OPERATOR_IS_NOT } },
- { type: 'assignee_username', value: { data: 'bart', operator: OPERATOR_IS } },
- { type: 'assignee_username', value: { data: 'lisa', operator: OPERATOR_IS } },
- { type: 'assignee_username', value: { data: '5', operator: OPERATOR_IS } },
- { type: 'assignee_username', value: { data: 'patty', operator: OPERATOR_IS_NOT } },
- { type: 'assignee_username', value: { data: 'selma', operator: OPERATOR_IS_NOT } },
- { type: 'milestone', value: { data: 'season 3', operator: OPERATOR_IS } },
- { type: 'milestone', value: { data: 'season 4', operator: OPERATOR_IS } },
- { type: 'milestone', value: { data: 'season 20', operator: OPERATOR_IS_NOT } },
- { type: 'milestone', value: { data: 'season 30', operator: OPERATOR_IS_NOT } },
- { type: 'labels', value: { data: 'cartoon', operator: OPERATOR_IS } },
- { type: 'labels', value: { data: 'tv', operator: OPERATOR_IS } },
- { type: 'labels', value: { data: 'live action', operator: OPERATOR_IS_NOT } },
- { type: 'labels', value: { data: 'drama', operator: OPERATOR_IS_NOT } },
- { type: 'release', value: { data: 'v3', operator: OPERATOR_IS } },
- { type: 'release', value: { data: 'v4', operator: OPERATOR_IS } },
- { type: 'release', value: { data: 'v20', operator: OPERATOR_IS_NOT } },
- { type: 'release', value: { data: 'v30', operator: OPERATOR_IS_NOT } },
- { type: 'type', value: { data: 'issue', operator: OPERATOR_IS } },
- { type: 'type', value: { data: 'feature', operator: OPERATOR_IS } },
- { type: 'type', value: { data: 'bug', operator: OPERATOR_IS_NOT } },
- { type: 'type', value: { data: 'incident', operator: OPERATOR_IS_NOT } },
- { type: 'my_reaction_emoji', value: { data: 'thumbsup', operator: OPERATOR_IS } },
- { type: 'my_reaction_emoji', value: { data: 'thumbsdown', operator: OPERATOR_IS_NOT } },
- { type: 'confidential', value: { data: 'yes', operator: OPERATOR_IS } },
- { type: 'iteration', value: { data: '4', operator: OPERATOR_IS } },
- { type: 'iteration', value: { data: '12', operator: OPERATOR_IS } },
- { type: 'iteration', value: { data: '20', operator: OPERATOR_IS_NOT } },
- { type: 'iteration', value: { data: '42', operator: OPERATOR_IS_NOT } },
- { type: 'epic_id', value: { data: '12', operator: OPERATOR_IS } },
- { type: 'epic_id', value: { data: '34', operator: OPERATOR_IS_NOT } },
- { type: 'weight', value: { data: '1', operator: OPERATOR_IS } },
- { type: 'weight', value: { data: '3', operator: OPERATOR_IS_NOT } },
- { type: 'crm_contact', value: { data: '123', operator: OPERATOR_IS } },
- { type: 'crm_organization', value: { data: '456', operator: OPERATOR_IS } },
- { type: 'filtered-search-term', value: { data: 'find' } },
- { type: 'filtered-search-term', value: { data: 'issues' } },
+ { type: TOKEN_TYPE_AUTHOR, value: { data: 'homer', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_AUTHOR, value: { data: 'marge', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'bart', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'lisa', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: '5', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'patty', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'selma', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'carl', operator: OPERATOR_OR } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'lenny', operator: OPERATOR_OR } },
+ { type: TOKEN_TYPE_MILESTONE, value: { data: 'season 3', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_MILESTONE, value: { data: 'season 4', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_MILESTONE, value: { data: 'season 20', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_MILESTONE, value: { data: 'season 30', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_LABEL, value: { data: 'cartoon', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_LABEL, value: { data: 'tv', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_LABEL, value: { data: 'live action', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_LABEL, value: { data: 'drama', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_RELEASE, value: { data: 'v3', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_RELEASE, value: { data: 'v4', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_RELEASE, value: { data: 'v20', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_RELEASE, value: { data: 'v30', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_TYPE, value: { data: 'issue', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_TYPE, value: { data: 'feature', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_TYPE, value: { data: 'bug', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_TYPE, value: { data: 'incident', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_MY_REACTION, value: { data: 'thumbsup', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_MY_REACTION, value: { data: 'thumbsdown', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_CONFIDENTIAL, value: { data: 'yes', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ITERATION, value: { data: '4', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ITERATION, value: { data: '12', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ITERATION, value: { data: '20', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_ITERATION, value: { data: '42', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_EPIC, value: { data: '12', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_EPIC, value: { data: '34', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_WEIGHT, value: { data: '1', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_WEIGHT, value: { data: '3', operator: OPERATOR_IS_NOT } },
+ { type: TOKEN_TYPE_CONTACT, value: { data: '123', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ORGANIZATION, value: { data: '456', operator: OPERATOR_IS } },
+ { type: FILTERED_SEARCH_TERM, value: { data: 'find' } },
+ { type: FILTERED_SEARCH_TERM, value: { data: 'issues' } },
];
export const filteredTokensWithSpecialValues = [
- { type: 'assignee_username', value: { data: '123', operator: OPERATOR_IS } },
- { type: 'assignee_username', value: { data: 'bart', operator: OPERATOR_IS } },
- { type: 'my_reaction_emoji', value: { data: 'None', operator: OPERATOR_IS } },
- { type: 'iteration', value: { data: 'Current', operator: OPERATOR_IS } },
- { type: 'labels', value: { data: 'None', operator: OPERATOR_IS } },
- { type: 'release', value: { data: 'None', operator: OPERATOR_IS } },
- { type: 'milestone', value: { data: 'Upcoming', operator: OPERATOR_IS } },
- { type: 'epic_id', value: { data: 'None', operator: OPERATOR_IS } },
- { type: 'weight', value: { data: 'None', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: '123', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ASSIGNEE, value: { data: 'bart', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_MY_REACTION, value: { data: 'None', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_ITERATION, value: { data: 'Current', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_LABEL, value: { data: 'None', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_RELEASE, value: { data: 'None', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_MILESTONE, value: { data: 'Upcoming', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_EPIC, value: { data: 'None', operator: OPERATOR_IS } },
+ { type: TOKEN_TYPE_WEIGHT, value: { data: 'None', operator: OPERATOR_IS } },
];
export const apiParams = {
@@ -244,6 +263,9 @@ export const apiParams = {
epicId: '34',
weight: '3',
},
+ or: {
+ assigneeUsernames: ['carl', 'lenny'],
+ },
};
export const apiParamsWithSpecialValues = {
@@ -263,6 +285,7 @@ export const urlParams = {
'not[author_username]': 'marge',
'assignee_username[]': ['bart', 'lisa', '5'],
'not[assignee_username][]': ['patty', 'selma'],
+ 'or[assignee_username][]': ['carl', 'lenny'],
milestone_title: ['season 3', 'season 4'],
'not[milestone_title]': ['season 20', 'season 30'],
'label_name[]': ['cartoon', 'tv'],
diff --git a/spec/frontend/issues/show/components/fields/description_spec.js b/spec/frontend/issues/show/components/fields/description_spec.js
index cd4d422583b..273ddfdd5d4 100644
--- a/spec/frontend/issues/show/components/fields/description_spec.js
+++ b/spec/frontend/issues/show/components/fields/description_spec.js
@@ -86,7 +86,7 @@ describe('Description field component', () => {
renderMarkdownPath: '/',
markdownDocsPath: '/',
quickActionsDocsPath: expect.any(String),
- initOnAutofocus: true,
+ autofocus: true,
supportsQuickActions: true,
enableAutocomplete: true,
}),
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 2e7449974e5..0ce3f75f576 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
@@ -52,6 +52,9 @@ describe('Timeline events form', () => {
findMinuteInput().setValue(45);
};
const findTextarea = () => wrapper.findByTestId('input-note');
+ const findCountNumeric = (count) => wrapper.findByText(count);
+ const findCountVerbose = (count) => wrapper.findByText(`${count} characters remaining`);
+ const findCountHint = () => wrapper.findByText(timelineFormI18n.hint);
const submitForm = async () => {
findSubmitButton().vm.$emit('click');
@@ -135,4 +138,31 @@ describe('Timeline events form', () => {
expect(findSubmitAndAddButton().props('disabled')).toBe(false);
});
});
+
+ describe('form character limit', () => {
+ beforeEach(() => {
+ mountComponent({ mountMethod: mountExtended });
+ });
+
+ it('sets a character limit hint', () => {
+ expect(findCountHint().exists()).toBe(true);
+ });
+
+ it('sets a character limit when text is entered', async () => {
+ await findTextarea().setValue('hello');
+
+ expect(findCountNumeric('275').text()).toBe('275');
+ expect(findCountVerbose('275').text()).toBe('275 characters remaining');
+ });
+
+ it('prevents form submission when text is beyond maximum length', async () => {
+ // 281 characters long
+ const longText =
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in volupte';
+ await findTextarea().setValue(longText);
+
+ expect(findSubmitButton().props('disabled')).toBe(true);
+ expect(findSubmitAndAddButton().props('disabled')).toBe(true);
+ });
+ });
});
diff --git a/spec/frontend/jobs/components/job/legacy_sidebar_header_spec.js b/spec/frontend/jobs/components/job/legacy_sidebar_header_spec.js
index cb32ca9d3dc..95eb10118ee 100644
--- a/spec/frontend/jobs/components/job/legacy_sidebar_header_spec.js
+++ b/spec/frontend/jobs/components/job/legacy_sidebar_header_spec.js
@@ -3,7 +3,7 @@ import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import JobRetryButton from '~/jobs/components/job/sidebar/job_sidebar_retry_button.vue';
import LegacySidebarHeader from '~/jobs/components/job/sidebar/legacy_sidebar_header.vue';
import createStore from '~/jobs/store';
-import job from '../../mock_data';
+import job, { failedJobStatus } from '../../mock_data';
describe('Legacy Sidebar Header', () => {
let store;
@@ -67,6 +67,12 @@ describe('Legacy Sidebar Header', () => {
it('should render the retry button', () => {
expect(findRetryButton().props('href')).toBe(job.retry_path);
});
+
+ it('should have a different label when the job status is passed', () => {
+ expect(findRetryButton().attributes('title')).toBe(
+ LegacySidebarHeader.i18n.runAgainJobButtonLabel,
+ );
+ });
});
describe('when there is no retry path', () => {
@@ -88,4 +94,16 @@ describe('Legacy Sidebar Header', () => {
expect(findCancelButton().attributes('href')).toBe(job.cancel_path);
});
});
+
+ describe('when the job is failed', () => {
+ describe('retry button', () => {
+ it('should have a different label when the job status is failed', () => {
+ createWrapper({ job: { ...job, status: failedJobStatus } });
+
+ expect(findRetryButton().attributes('title')).toBe(
+ LegacySidebarHeader.i18n.retryJobButtonLabel,
+ );
+ });
+ });
+ });
});
diff --git a/spec/frontend/jobs/components/job/sidebar_spec.js b/spec/frontend/jobs/components/job/sidebar_spec.js
index dc1aa67489d..27911eb76eb 100644
--- a/spec/frontend/jobs/components/job/sidebar_spec.js
+++ b/spec/frontend/jobs/components/job/sidebar_spec.js
@@ -1,6 +1,9 @@
import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
+import MockAdapter from 'axios-mock-adapter';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import axios from '~/lib/utils/axios_utils';
+import httpStatus from '~/lib/utils/http_status';
import ArtifactsBlock from '~/jobs/components/job/sidebar/artifacts_block.vue';
import JobRetryForwardDeploymentModal from '~/jobs/components/job/sidebar/job_retry_forward_deployment_modal.vue';
import JobsContainer from '~/jobs/components/job/sidebar/jobs_container.vue';
@@ -10,6 +13,7 @@ import createStore from '~/jobs/store';
import job, { jobsInStage } from '../../mock_data';
describe('Sidebar details block', () => {
+ let mock;
let store;
let wrapper;
@@ -18,6 +22,8 @@ describe('Sidebar details block', () => {
const findArtifactsBlock = () => wrapper.findComponent(ArtifactsBlock);
const findNewIssueButton = () => wrapper.findByTestId('job-new-issue');
const findTerminalLink = () => wrapper.findByTestId('terminal-link');
+ const findJobStagesDropdown = () => wrapper.findComponent(StagesDropdown);
+ const findJobsContainer = () => wrapper.findComponent(JobsContainer);
const createWrapper = (props) => {
store = createStore();
@@ -35,6 +41,13 @@ describe('Sidebar details block', () => {
);
};
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onGet().reply(httpStatus.OK, {
+ name: job.stage,
+ });
+ });
+
afterEach(() => {
wrapper.destroy();
});
@@ -110,31 +123,72 @@ describe('Sidebar details block', () => {
describe('stages dropdown', () => {
beforeEach(() => {
createWrapper();
- return store.dispatch('receiveJobSuccess', { ...job, stage: 'aStage' });
+ return store.dispatch('receiveJobSuccess', job);
});
describe('with stages', () => {
it('renders value provided as selectedStage as selected', () => {
- expect(wrapper.findComponent(StagesDropdown).props('selectedStage')).toBe('aStage');
+ expect(findJobStagesDropdown().props('selectedStage')).toBe(job.stage);
});
});
describe('without jobs for stages', () => {
- beforeEach(() => store.dispatch('receiveJobSuccess', job));
-
it('does not render jobs container', () => {
- expect(wrapper.findComponent(JobsContainer).exists()).toBe(false);
+ expect(findJobsContainer().exists()).toBe(false);
});
});
describe('with jobs for stages', () => {
+ beforeEach(() => {
+ return store.dispatch('receiveJobsForStageSuccess', jobsInStage.latest_statuses);
+ });
+
+ it('renders list of jobs', async () => {
+ expect(findJobsContainer().exists()).toBe(true);
+ });
+ });
+
+ describe('when job data changes', () => {
+ const stageArg = job.pipeline.details.stages.find((stage) => stage.name === job.stage);
+
beforeEach(async () => {
- await store.dispatch('receiveJobSuccess', job);
- await store.dispatch('receiveJobsForStageSuccess', jobsInStage.latest_statuses);
+ jest.spyOn(store, 'dispatch');
});
- it('renders list of jobs', () => {
- expect(wrapper.findComponent(JobsContainer).exists()).toBe(true);
+ describe('and the job stage is currently selected', () => {
+ describe('when the status changed', () => {
+ it('refetch the jobs list for the stage', async () => {
+ await store.dispatch('receiveJobSuccess', { ...job, status: 'new' });
+
+ expect(store.dispatch).toHaveBeenNthCalledWith(2, 'fetchJobsForStage', { ...stageArg });
+ });
+ });
+
+ describe('when the status did not change', () => {
+ it('does not refetch the jobs list for the stage', async () => {
+ await store.dispatch('receiveJobSuccess', { ...job });
+
+ expect(store.dispatch).toHaveBeenCalledTimes(1);
+ expect(store.dispatch).toHaveBeenNthCalledWith(1, 'receiveJobSuccess', {
+ ...job,
+ });
+ });
+ });
+ });
+
+ describe('and the job stage is not currently selected', () => {
+ it('does not refetch the jobs list for the stage', async () => {
+ // Setting stage to `random` on the job means that we are looking
+ // at `build` stage currently, but the job we are seeing in the logs
+ // belong to `random`, so we shouldn't have to refetch
+ await store.dispatch('receiveJobSuccess', { ...job, stage: 'random' });
+
+ expect(store.dispatch).toHaveBeenCalledTimes(1);
+ expect(store.dispatch).toHaveBeenNthCalledWith(1, 'receiveJobSuccess', {
+ ...job,
+ stage: 'random',
+ });
+ });
});
});
});
diff --git a/spec/frontend/jobs/mock_data.js b/spec/frontend/jobs/mock_data.js
index bf238b2e39a..a7fe6d5a626 100644
--- a/spec/frontend/jobs/mock_data.js
+++ b/spec/frontend/jobs/mock_data.js
@@ -925,6 +925,7 @@ export default {
locked: false,
},
name: 'test',
+ stage: 'build',
build_path: '/root/ci-mock/-/jobs/4757',
retry_path: '/root/ci-mock/-/jobs/4757/retry',
cancel_path: '/root/ci-mock/-/jobs/4757/cancel',
@@ -1085,6 +1086,29 @@ export default {
has_trace: true,
};
+export const failedJobStatus = {
+ icon: 'status_warning',
+ text: 'failed',
+ label: 'failed (allowed to fail)',
+ group: 'failed-with-warnings',
+ tooltip: 'failed - (unknown failure) (allowed to fail)',
+ has_details: true,
+ details_path: '/gitlab-org/gitlab-shell/-/jobs/454',
+ illustration: {
+ image: 'illustrations/skipped-job_empty.svg',
+ size: 'svg-430',
+ title: 'This job does not have a trace.',
+ },
+ favicon:
+ '/assets/ci_favicons/favicon_status_failed-41304d7f7e3828808b0c26771f0309e55296819a9beea3ea9fbf6689d9857c12.png',
+ action: {
+ icon: 'retry',
+ title: 'Retry',
+ path: '/gitlab-org/gitlab-shell/-/jobs/454/retry',
+ method: 'post',
+ },
+};
+
export const jobsInStage = {
name: 'build',
title: 'build: running',
diff --git a/spec/frontend/lib/utils/common_utils_spec.js b/spec/frontend/lib/utils/common_utils_spec.js
index a0140d1d8a8..947c38c8ae8 100644
--- a/spec/frontend/lib/utils/common_utils_spec.js
+++ b/spec/frontend/lib/utils/common_utils_spec.js
@@ -1016,45 +1016,6 @@ describe('common_utils', () => {
});
});
- describe('searchBy', () => {
- const searchSpace = {
- iid: 1,
- reference: '&1',
- title: 'Error omnis quos consequatur ullam a vitae sed omnis libero cupiditate.',
- url: '/groups/gitlab-org/-/epics/1',
- };
-
- it('returns null when `query` or `searchSpace` params are empty/undefined', () => {
- expect(commonUtils.searchBy('omnis', null)).toBeNull();
- expect(commonUtils.searchBy('', searchSpace)).toBeNull();
- expect(commonUtils.searchBy()).toBeNull();
- });
-
- it('returns object with matching props based on `query` & `searchSpace` params', () => {
- // String `omnis` is found only in `title` prop so return just that
- expect(commonUtils.searchBy('omnis', searchSpace)).toEqual(
- expect.objectContaining({
- title: searchSpace.title,
- }),
- );
-
- // String `1` is found in both `iid` and `reference` props so return both
- expect(commonUtils.searchBy('1', searchSpace)).toEqual(
- expect.objectContaining({
- iid: searchSpace.iid,
- reference: searchSpace.reference,
- }),
- );
-
- // String `/epics/1` is found in `url` prop so return just that
- expect(commonUtils.searchBy('/epics/1', searchSpace)).toEqual(
- expect.objectContaining({
- url: searchSpace.url,
- }),
- );
- });
- });
-
describe('isScopedLabel', () => {
it('returns true when `::` is present in title', () => {
expect(commonUtils.isScopedLabel({ title: 'foo::bar' })).toBe(true);
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
new file mode 100644
index 00000000000..142c76f7bc0
--- /dev/null
+++ b/spec/frontend/lib/utils/confirm_via_gl_modal/confirm_action_spec.js
@@ -0,0 +1,103 @@
+import Vue, { nextTick } from 'vue';
+import { createWrapper } from '@vue/test-utils';
+import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
+import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_action';
+import ConfirmModal from '~/lib/utils/confirm_via_gl_modal/confirm_modal.vue';
+
+const originalMount = Vue.prototype.$mount;
+
+describe('confirmAction', () => {
+ let modalWrapper;
+ let confirActionPromise;
+ let modal;
+
+ const findConfirmModal = () => modalWrapper.findComponent(ConfirmModal);
+ const renderRootComponent = async (message, opts) => {
+ confirActionPromise = confirmAction(message, opts);
+ // We have to wait for two ticks here.
+ // The first one is to wait for rendering of the root component
+ // The second one to wait for rendering of the dynamically
+ // loaded confirm-modal component
+ await nextTick();
+ await nextTick();
+ modal = findConfirmModal();
+ };
+ const mockMount = (vm, el) => {
+ originalMount.call(vm, el);
+ modalWrapper = createWrapper(vm);
+ return vm;
+ };
+
+ beforeEach(() => {
+ setHTMLFixture('<div id="component"></div>');
+ const el = document.getElementById('component');
+ // We mock the implementation only once to make sure that we mock
+ // it only for the root component in confirm_action.
+ // Mounting other components (like confirm-modal) should not be affected with
+ // this mock
+ jest.spyOn(Vue.prototype, '$mount').mockImplementationOnce(function mock() {
+ return mockMount(this, el);
+ });
+ });
+
+ afterEach(() => {
+ resetHTMLFixture();
+ Vue.prototype.$mount.mockRestore();
+ modalWrapper?.destroy();
+ modalWrapper = null;
+ modal?.destroy();
+ modal = null;
+ });
+
+ it('creats a ConfirmModal with message as slot', async () => {
+ const message = 'Bonjour le monde!';
+ await renderRootComponent(message);
+
+ expect(modal.vm.$slots.default[0].text).toBe(message);
+ });
+
+ it('creats a ConfirmModal with props', async () => {
+ const options = {
+ primaryBtnText: 'primaryBtnText',
+ primaryBtnVariant: 'info',
+ secondaryBtnText: 'secondaryBtnText',
+ secondaryBtnVariant: 'success',
+ cancelBtnText: 'cancelBtnText',
+ cancelBtnVariant: 'danger',
+ modalHtmlMessage: '<strong>Hello</strong>',
+ title: 'title',
+ hideCancel: true,
+ };
+ await renderRootComponent('', options);
+ expect(modal.props()).toEqual(
+ expect.objectContaining({
+ primaryText: options.primaryBtnText,
+ primaryVariant: options.primaryBtnVariant,
+ secondaryText: options.secondaryBtnText,
+ secondaryVariant: options.secondaryBtnVariant,
+ cancelText: options.cancelBtnText,
+ cancelVariant: options.cancelBtnVariant,
+ modalHtmlMessage: options.modalHtmlMessage,
+ title: options.title,
+ hideCancel: options.hideCancel,
+ }),
+ );
+ });
+
+ it('resolves promise when modal emit `closed`', async () => {
+ await renderRootComponent('');
+
+ modal.vm.$emit('closed');
+
+ await expect(confirActionPromise).resolves.toBe(false);
+ });
+
+ it('confirms when modal emit `confirmed` before `closed`', async () => {
+ await renderRootComponent('');
+
+ modal.vm.$emit('confirmed');
+ modal.vm.$emit('closed');
+
+ await expect(confirActionPromise).resolves.toBe(true);
+ });
+});
diff --git a/spec/frontend/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal_spec.js b/spec/frontend/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal_spec.js
new file mode 100644
index 00000000000..6966c79b232
--- /dev/null
+++ b/spec/frontend/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal_spec.js
@@ -0,0 +1,80 @@
+import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
+import { confirmViaGlModal } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
+import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_action';
+
+jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_action');
+
+describe('confirmViaGlModal', () => {
+ let el;
+
+ afterEach(() => {
+ el = undefined;
+ resetHTMLFixture();
+ jest.resetAllMocks();
+ });
+
+ const createElement = (html) => {
+ setHTMLFixture(html);
+ return document.body.firstChild;
+ };
+
+ it('returns confirmAction result', async () => {
+ confirmAction.mockReturnValue(Promise.resolve(true));
+ el = createElement(`<div/>`);
+
+ await expect(confirmViaGlModal('', el)).resolves.toBe(true);
+ });
+
+ it('calls confirmAction with message', () => {
+ el = createElement(`<div/>`);
+
+ confirmViaGlModal('message', el);
+
+ expect(confirmAction).toHaveBeenCalledWith('message', {});
+ });
+
+ it.each(['gl-sr-only', 'sr-only'])(
+ `uses slot.%s contentText as primaryBtnText`,
+ (srOnlyClass) => {
+ el = createElement(
+ `<a href="#"><span class="${srOnlyClass}">Delete merge request</span></a>`,
+ );
+
+ confirmViaGlModal('', el);
+
+ expect(confirmAction).toHaveBeenCalledWith('', {
+ primaryBtnText: 'Delete merge request',
+ });
+ },
+ );
+
+ it('uses `aria-label` value as `primaryBtnText`', () => {
+ el = createElement(`<a aria-label="Delete merge request" href="#"></a>`);
+
+ confirmViaGlModal('', el);
+
+ expect(confirmAction).toHaveBeenCalledWith('', {
+ primaryBtnText: 'Delete merge request',
+ });
+ });
+
+ it.each([
+ ['title', 'title', 'Delete?'],
+ ['confirm-btn-variant', `primaryBtnVariant`, 'danger'],
+ ])('uses data-%s value as confirmAction config', (dataKey, configKey, value) => {
+ el = createElement(`<a data-${dataKey}="${value}" href="#"></a>`);
+
+ confirmViaGlModal('message', el);
+
+ expect(confirmAction).toHaveBeenCalledWith('message', { [configKey]: value });
+ });
+
+ it('uses message as modalHtmlMessage value when data-is-html-message is true', () => {
+ el = createElement(`<a data-is-html-message="true" href="#"></a>`);
+ const message = 'Hola mundo!';
+
+ confirmViaGlModal(message, el);
+
+ expect(confirmAction).toHaveBeenCalledWith(message, { modalHtmlMessage: message });
+ });
+});
diff --git a/spec/frontend/lib/utils/datetime/date_calculation_utility_spec.js b/spec/frontend/lib/utils/datetime/date_calculation_utility_spec.js
index 59b3b4c02df..055d57d6ada 100644
--- a/spec/frontend/lib/utils/datetime/date_calculation_utility_spec.js
+++ b/spec/frontend/lib/utils/datetime/date_calculation_utility_spec.js
@@ -1,4 +1,9 @@
-import { getDateWithUTC, newDateAsLocaleTime } from '~/lib/utils/datetime/date_calculation_utility';
+import {
+ getDateWithUTC,
+ newDateAsLocaleTime,
+ nSecondsAfter,
+ nSecondsBefore,
+} from '~/lib/utils/datetime/date_calculation_utility';
describe('newDateAsLocaleTime', () => {
it.each`
@@ -31,3 +36,33 @@ describe('getDateWithUTC', () => {
expect(getDateWithUTC(date)).toEqual(expected);
});
});
+
+describe('nSecondsAfter', () => {
+ const start = new Date('2022-03-22T01:23:45.678Z');
+ it.each`
+ date | seconds | expected
+ ${start} | ${0} | ${start}
+ ${start} | ${1} | ${new Date('2022-03-22T01:23:46.678Z')}
+ ${start} | ${5} | ${new Date('2022-03-22T01:23:50.678Z')}
+ ${start} | ${60} | ${new Date('2022-03-22T01:24:45.678Z')}
+ ${start} | ${3600} | ${new Date('2022-03-22T02:23:45.678Z')}
+ ${start} | ${86400} | ${new Date('2022-03-23T01:23:45.678Z')}
+ `('returns $expected given $string', ({ date, seconds, expected }) => {
+ expect(nSecondsAfter(date, seconds)).toEqual(expected);
+ });
+});
+
+describe('nSecondsBefore', () => {
+ const start = new Date('2022-03-22T01:23:45.678Z');
+ it.each`
+ date | seconds | expected
+ ${start} | ${0} | ${start}
+ ${start} | ${1} | ${new Date('2022-03-22T01:23:44.678Z')}
+ ${start} | ${5} | ${new Date('2022-03-22T01:23:40.678Z')}
+ ${start} | ${60} | ${new Date('2022-03-22T01:22:45.678Z')}
+ ${start} | ${3600} | ${new Date('2022-03-22T00:23:45.678Z')}
+ ${start} | ${86400} | ${new Date('2022-03-21T01:23:45.678Z')}
+ `('returns $expected given $string', ({ date, seconds, expected }) => {
+ expect(nSecondsBefore(date, seconds)).toEqual(expected);
+ });
+});
diff --git a/spec/frontend/lib/utils/dom_utils_spec.js b/spec/frontend/lib/utils/dom_utils_spec.js
index b537e6b2bf8..d6bac935970 100644
--- a/spec/frontend/lib/utils/dom_utils_spec.js
+++ b/spec/frontend/lib/utils/dom_utils_spec.js
@@ -1,8 +1,10 @@
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
+
import {
addClassIfElementExists,
canScrollUp,
canScrollDown,
+ getContentWrapperHeight,
parseBooleanDataAttributes,
isElementVisible,
getParents,
@@ -235,4 +237,30 @@ describe('DOM Utils', () => {
expect(div.getAttribute('title')).toBe('another test');
});
});
+
+ describe('getContentWrapperHeight', () => {
+ const fixture = `
+ <div>
+ <div class="content-wrapper">
+ <div class="content"></div>
+ </div>
+ </div>
+ `;
+
+ beforeEach(() => {
+ setHTMLFixture(fixture);
+ });
+
+ afterEach(() => {
+ resetHTMLFixture();
+ });
+
+ it('returns the height of an element that exists', () => {
+ expect(getContentWrapperHeight('.content-wrapper')).toBe('0px');
+ });
+
+ it('returns an empty string for a class that does not exist', () => {
+ expect(getContentWrapperHeight('.does-not-exist')).toBe('');
+ });
+ });
});
diff --git a/spec/frontend/lib/utils/unit_format/index_spec.js b/spec/frontend/lib/utils/unit_format/index_spec.js
index dc9d6ece48e..057d7aded02 100644
--- a/spec/frontend/lib/utils/unit_format/index_spec.js
+++ b/spec/frontend/lib/utils/unit_format/index_spec.js
@@ -2,6 +2,7 @@ import {
number,
percent,
percentHundred,
+ days,
seconds,
milliseconds,
decimalBytes,
@@ -72,6 +73,11 @@ describe('unit_format', () => {
expect(percentHundred(1000)).toBe('1,000%');
});
+ it('days', () => {
+ expect(days(1)).toBe('1d');
+ expect(days(1, undefined, { unitSeparator: '/' })).toBe('1/d');
+ });
+
it('seconds', () => {
expect(seconds(1)).toBe('1s');
expect(seconds(1, undefined, { unitSeparator: ' ' })).toBe('1 s');
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 3dac47974e7..df5c884f42e 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
@@ -24,86 +24,52 @@ describe('AccessRequestActionButtons', () => {
wrapper.destroy();
});
- describe('when user has `canRemove` permissions', () => {
- beforeEach(() => {
- createComponent({
- permissions: {
- canRemove: true,
- },
- });
- });
+ it('renders remove member button', () => {
+ createComponent();
- it('renders remove member button', () => {
- expect(findRemoveMemberButton().exists()).toBe(true);
- });
-
- it('sets props correctly', () => {
- expect(findRemoveMemberButton().props()).toMatchObject({
- memberId: member.id,
- title: 'Deny access',
- isAccessRequest: true,
- isInvite: false,
- icon: 'close',
- });
- });
-
- describe('when member is the current user', () => {
- it('sets `message` prop correctly', () => {
- expect(findRemoveMemberButton().props('message')).toBe(
- `Are you sure you want to withdraw your access request for "${member.source.fullName}"`,
- );
- });
- });
+ expect(findRemoveMemberButton().exists()).toBe(true);
+ });
- describe('when member is not the current user', () => {
- it('sets `message` prop correctly', () => {
- createComponent({
- isCurrentUser: false,
- permissions: {
- canRemove: true,
- },
- });
+ it('sets props correctly on remove member button', () => {
+ createComponent();
- expect(findRemoveMemberButton().props('message')).toBe(
- `Are you sure you want to deny ${member.user.name}'s request to join "${member.source.fullName}"`,
- );
- });
+ expect(findRemoveMemberButton().props()).toMatchObject({
+ memberId: member.id,
+ title: 'Deny access',
+ isAccessRequest: true,
+ isInvite: false,
+ icon: 'close',
});
});
- describe('when user does not have `canRemove` permissions', () => {
- it('does not render remove member button', () => {
- createComponent({
- permissions: {
- canRemove: false,
- },
- });
+ describe('when member is the current user', () => {
+ it('sets `message` prop correctly', () => {
+ createComponent();
- expect(findRemoveMemberButton().exists()).toBe(false);
+ expect(findRemoveMemberButton().props('message')).toBe(
+ `Are you sure you want to withdraw your access request for "${member.source.fullName}"`,
+ );
});
});
- describe('when user has `canUpdate` permissions', () => {
- it('renders the approve button', () => {
+ describe('when member is not the current user', () => {
+ it('sets `message` prop correctly', () => {
createComponent({
+ isCurrentUser: false,
permissions: {
- canUpdate: true,
+ canRemove: true,
},
});
- expect(findApproveButton().exists()).toBe(true);
+ expect(findRemoveMemberButton().props('message')).toBe(
+ `Are you sure you want to deny ${member.user.name}'s request to join "${member.source.fullName}"`,
+ );
});
});
- describe('when user does not have `canUpdate` permissions', () => {
- it('does not render the approve button', () => {
- createComponent({
- permissions: {
- canUpdate: false,
- },
- });
+ it('renders the approve button', () => {
+ createComponent();
- expect(findApproveButton().exists()).toBe(false);
- });
+ expect(findApproveButton().exists()).toBe(true);
});
});
diff --git a/spec/frontend/members/components/members_tabs_spec.js b/spec/frontend/members/components/members_tabs_spec.js
index 1354b938d77..77af5e7293e 100644
--- a/spec/frontend/members/components/members_tabs_spec.js
+++ b/spec/frontend/members/components/members_tabs_spec.js
@@ -81,6 +81,7 @@ describe('MembersTabs', () => {
stubs: ['members-app'],
provide: {
canManageMembers: true,
+ canManageAccessRequests: true,
canExportMembers: true,
exportCsvPath: '',
...provide,
@@ -181,7 +182,9 @@ describe('MembersTabs', () => {
describe('when `canManageMembers` is `false`', () => {
it('shows all tabs except `Invited` and `Access requests`', async () => {
- await createComponent({ provide: { canManageMembers: false } });
+ await createComponent({
+ provide: { canManageMembers: false, canManageAccessRequests: false },
+ });
expect(findTabByText('Members')).not.toBeUndefined();
expect(findTabByText('Groups')).not.toBeUndefined();
diff --git a/spec/frontend/ml/experiment_tracking/components/__snapshots__/experiment_spec.js.snap b/spec/frontend/ml/experiment_tracking/components/__snapshots__/experiment_spec.js.snap
new file mode 100644
index 00000000000..2eba8869535
--- /dev/null
+++ b/spec/frontend/ml/experiment_tracking/components/__snapshots__/experiment_spec.js.snap
@@ -0,0 +1,223 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`ShowExperiment with candidates 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
+ </a>
+ </div>
+
+ <div
+ class="gl-alert-actions"
+ >
+ <a
+ class="btn gl-alert-action btn-confirm btn-md gl-button"
+ href="https://gitlab.com/groups/gitlab-org/-/epics/8560"
+ >
+ <!---->
+
+ <!---->
+
+ <span
+ class="gl-button-text"
+ >
+
+ Feedback and Updates
+
+ </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>
+
+ Experiment Candidates
+
+ </h3>
+
+ <table
+ aria-busy="false"
+ aria-colcount="4"
+ class="table b-table gl-table gl-mt-0!"
+ role="table"
+ >
+ <!---->
+ <!---->
+ <thead
+ class=""
+ role="rowgroup"
+ >
+ <!---->
+ <tr
+ class=""
+ role="row"
+ >
+ <th
+ aria-colindex="1"
+ class=""
+ role="columnheader"
+ scope="col"
+ >
+ <div>
+ L1 Ratio
+ </div>
+ </th>
+ <th
+ aria-colindex="2"
+ class=""
+ role="columnheader"
+ scope="col"
+ >
+ <div>
+ Rmse
+ </div>
+ </th>
+ <th
+ aria-colindex="3"
+ class=""
+ role="columnheader"
+ scope="col"
+ >
+ <div>
+ Auc
+ </div>
+ </th>
+ <th
+ aria-colindex="4"
+ class=""
+ role="columnheader"
+ scope="col"
+ >
+ <div>
+ Mae
+ </div>
+ </th>
+ </tr>
+ </thead>
+ <tbody
+ role="rowgroup"
+ >
+ <!---->
+ <tr
+ class=""
+ role="row"
+ >
+ <td
+ aria-colindex="1"
+ class=""
+ role="cell"
+ >
+ 0.4
+ </td>
+ <td
+ aria-colindex="2"
+ class=""
+ role="cell"
+ >
+ 1
+ </td>
+ <td
+ aria-colindex="3"
+ class=""
+ role="cell"
+ />
+ <td
+ aria-colindex="4"
+ class=""
+ role="cell"
+ />
+ </tr>
+ <tr
+ class=""
+ role="row"
+ >
+ <td
+ aria-colindex="1"
+ class=""
+ role="cell"
+ >
+ 0.5
+ </td>
+ <td
+ aria-colindex="2"
+ class=""
+ role="cell"
+ />
+ <td
+ aria-colindex="3"
+ class=""
+ role="cell"
+ >
+ 0.3
+ </td>
+ <td
+ aria-colindex="4"
+ class=""
+ role="cell"
+ />
+ </tr>
+ <!---->
+ <!---->
+ </tbody>
+ <!---->
+ </table>
+</div>
+`;
diff --git a/spec/frontend/ml/experiment_tracking/components/experiment_spec.js b/spec/frontend/ml/experiment_tracking/components/experiment_spec.js
new file mode 100644
index 00000000000..af722d77532
--- /dev/null
+++ b/spec/frontend/ml/experiment_tracking/components/experiment_spec.js
@@ -0,0 +1,44 @@
+import { GlAlert } from '@gitlab/ui';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import ShowExperiment from '~/ml/experiment_tracking/components/experiment.vue';
+
+describe('ShowExperiment', () => {
+ let wrapper;
+
+ const createWrapper = (candidates = [], metricNames = [], paramNames = []) => {
+ return mountExtended(ShowExperiment, { provide: { candidates, metricNames, paramNames } });
+ };
+
+ const findAlert = () => wrapper.findComponent(GlAlert);
+
+ const findEmptyState = () => wrapper.findByText('This Experiment has no logged Candidates');
+
+ it('shows incubation warning', () => {
+ wrapper = createWrapper();
+
+ expect(findAlert().exists()).toBe(true);
+ });
+
+ describe('no candidates', () => {
+ it('shows empty state', () => {
+ wrapper = createWrapper();
+
+ expect(findEmptyState().exists()).toBe(true);
+ });
+ });
+
+ describe('with candidates', () => {
+ it('renders correctly', () => {
+ wrapper = createWrapper(
+ [
+ { rmse: 1, l1_ratio: 0.4 },
+ { auc: 0.3, l1_ratio: 0.5 },
+ ],
+ ['rmse', 'auc', 'mae'],
+ ['l1_ratio'],
+ );
+
+ expect(wrapper.element).toMatchSnapshot();
+ });
+ });
+});
diff --git a/spec/frontend/ml/experiment_tracking/components/incubation_alert_spec.js b/spec/frontend/ml/experiment_tracking/components/incubation_alert_spec.js
new file mode 100644
index 00000000000..e07a4ed816b
--- /dev/null
+++ b/spec/frontend/ml/experiment_tracking/components/incubation_alert_spec.js
@@ -0,0 +1,27 @@
+import { mount } from '@vue/test-utils';
+import { GlAlert, GlButton } from '@gitlab/ui';
+import IncubationAlert from '~/ml/experiment_tracking/components/incubation_alert.vue';
+
+describe('IncubationAlert', () => {
+ let wrapper;
+
+ const findAlert = () => wrapper.findComponent(GlAlert);
+
+ const findButton = () => wrapper.findComponent(GlButton);
+
+ beforeEach(() => {
+ wrapper = mount(IncubationAlert);
+ });
+
+ it('displays link to issue', () => {
+ expect(findButton().attributes().href).toBe(
+ 'https://gitlab.com/groups/gitlab-org/-/epics/8560',
+ );
+ });
+
+ it('is removed if dismissed', async () => {
+ await wrapper.find('[aria-label="Dismiss"]').trigger('click');
+
+ expect(findAlert().exists()).toBe(false);
+ });
+});
diff --git a/spec/frontend/notebook/cells/markdown_spec.js b/spec/frontend/notebook/cells/markdown_spec.js
index c757b55faf4..a7776bd5b69 100644
--- a/spec/frontend/notebook/cells/markdown_spec.js
+++ b/spec/frontend/notebook/cells/markdown_spec.js
@@ -5,20 +5,22 @@ 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 = '') {
+function buildCellComponent(cell, relativePath = '', hidePrompt) {
return mount(Component, {
propsData: {
cell,
+ hidePrompt,
},
provide: {
relativeRawPath: relativePath,
},
- }).vm;
+ });
}
function buildMarkdownComponent(markdownContent, relativePath = '') {
@@ -33,7 +35,7 @@ function buildMarkdownComponent(markdownContent, relativePath = '') {
}
describe('Markdown component', () => {
- let vm;
+ let wrapper;
let cell;
let json;
@@ -43,21 +45,30 @@ describe('Markdown component', () => {
// eslint-disable-next-line prefer-destructuring
cell = json.cells[1];
- vm = buildCellComponent(cell);
+ wrapper = buildCellComponent(cell);
await nextTick();
});
- it('does not render prompt', () => {
- expect(vm.$el.querySelector('.prompt span')).toBeNull();
+ const findPrompt = () => wrapper.findComponent(Prompt);
+
+ it('renders a prompt by default', () => {
+ expect(findPrompt().exists()).toBe(true);
+ });
+
+ it('does not render a prompt if hidePrompt is true', () => {
+ wrapper = buildCellComponent(cell, '', true);
+ expect(findPrompt().exists()).toBe(false);
});
it('does not render the markdown text', () => {
- expect(vm.$el.querySelector('.markdown').innerHTML.trim()).not.toEqual(cell.source.join(''));
+ expect(wrapper.vm.$el.querySelector('.markdown').innerHTML.trim()).not.toEqual(
+ cell.source.join(''),
+ );
});
it('renders the markdown HTML', () => {
- expect(vm.$el.querySelector('.markdown h1')).not.toBeNull();
+ expect(wrapper.vm.$el.querySelector('.markdown h1')).not.toBeNull();
});
it('sanitizes Markdown output', async () => {
@@ -68,11 +79,11 @@ describe('Markdown component', () => {
});
await nextTick();
- expect(vm.$el.querySelector('a').getAttribute('href')).toBeNull();
+ expect(wrapper.vm.$el.querySelector('a').getAttribute('href')).toBeNull();
});
it('sanitizes HTML', async () => {
- const findLink = () => vm.$el.querySelector('.xss-link');
+ const findLink = () => wrapper.vm.$el.querySelector('.xss-link');
Object.assign(cell, {
source: ['<a href="test.js" data-remote=true data-type="script" class="xss-link">XSS</a>\n'],
});
@@ -97,11 +108,11 @@ describe('Markdown component', () => {
["for embedded images, it doesn't", '![](data:image/jpeg;base64)\n', 'src="data:'],
["for images urls, it doesn't", '![](http://image.png)\n', 'src="http:'],
])('%s', async ([testMd, mustContain]) => {
- vm = buildMarkdownComponent([testMd], '/raw/');
+ wrapper = buildMarkdownComponent([testMd], '/raw/');
await nextTick();
- expect(vm.$el.innerHTML).toContain(mustContain);
+ expect(wrapper.vm.$el.innerHTML).toContain(mustContain);
});
});
@@ -111,13 +122,13 @@ describe('Markdown component', () => {
});
it('renders images and text', async () => {
- vm = buildCellComponent(json.cells[0]);
+ wrapper = buildCellComponent(json.cells[0]);
await nextTick();
- const images = vm.$el.querySelectorAll('img');
+ const images = wrapper.vm.$el.querySelectorAll('img');
expect(images.length).toBe(5);
- const columns = vm.$el.querySelectorAll('td');
+ const columns = wrapper.vm.$el.querySelectorAll('td');
expect(columns.length).toBe(6);
expect(columns[0].textContent).toEqual('Hello ');
@@ -141,81 +152,93 @@ describe('Markdown component', () => {
});
it('renders multi-line katex', async () => {
- vm = buildCellComponent(json.cells[0]);
+ wrapper = buildCellComponent(json.cells[0]);
await nextTick();
- expect(vm.$el.querySelector('.katex')).not.toBeNull();
+ expect(wrapper.vm.$el.querySelector('.katex')).not.toBeNull();
});
it('renders inline katex', async () => {
- vm = buildCellComponent(json.cells[1]);
+ wrapper = buildCellComponent(json.cells[1]);
await nextTick();
- expect(vm.$el.querySelector('p:first-child .katex')).not.toBeNull();
+ expect(wrapper.vm.$el.querySelector('p:first-child .katex')).not.toBeNull();
});
it('renders multiple inline katex', async () => {
- vm = buildCellComponent(json.cells[1]);
+ wrapper = buildCellComponent(json.cells[1]);
await nextTick();
- expect(vm.$el.querySelectorAll('p:nth-child(2) .katex')).toHaveLength(4);
+ expect(wrapper.vm.$el.querySelectorAll('p:nth-child(2) .katex')).toHaveLength(4);
});
it('output cell in case of katex error', async () => {
- vm = buildMarkdownComponent(['Some invalid $a & b$ inline formula $b & c$\n', '\n']);
+ wrapper = buildMarkdownComponent(['Some invalid $a & b$ inline formula $b & c$\n', '\n']);
await nextTick();
// expect one paragraph with no katex formula in it
- expect(vm.$el.querySelectorAll('p')).toHaveLength(1);
- expect(vm.$el.querySelectorAll('p .katex')).toHaveLength(0);
+ expect(wrapper.vm.$el.querySelectorAll('p')).toHaveLength(1);
+ expect(wrapper.vm.$el.querySelectorAll('p .katex')).toHaveLength(0);
});
it('output cell and render remaining formula in case of katex error', async () => {
- vm = buildMarkdownComponent([
+ wrapper = buildMarkdownComponent([
'An invalid $a & b$ inline formula and a vaild one $b = c$\n',
'\n',
]);
await nextTick();
// expect one paragraph with no katex formula in it
- expect(vm.$el.querySelectorAll('p')).toHaveLength(1);
- expect(vm.$el.querySelectorAll('p .katex')).toHaveLength(1);
+ expect(wrapper.vm.$el.querySelectorAll('p')).toHaveLength(1);
+ expect(wrapper.vm.$el.querySelectorAll('p .katex')).toHaveLength(1);
});
it('renders math formula in list object', async () => {
- vm = buildMarkdownComponent(["- list with inline $a=2$ inline formula $a' + b = c$\n", '\n']);
+ wrapper = buildMarkdownComponent([
+ "- list with inline $a=2$ inline formula $a' + b = c$\n",
+ '\n',
+ ]);
await nextTick();
// expect one list with a katex formula in it
- expect(vm.$el.querySelectorAll('li')).toHaveLength(1);
- expect(vm.$el.querySelectorAll('li .katex')).toHaveLength(2);
+ expect(wrapper.vm.$el.querySelectorAll('li')).toHaveLength(1);
+ expect(wrapper.vm.$el.querySelectorAll('li .katex')).toHaveLength(2);
});
it("renders math formula with tick ' in it", async () => {
- vm = buildMarkdownComponent(["- list with inline $a=2$ inline formula $a' + b = c$\n", '\n']);
+ wrapper = buildMarkdownComponent([
+ "- list with inline $a=2$ inline formula $a' + b = c$\n",
+ '\n',
+ ]);
await nextTick();
// expect one list with a katex formula in it
- expect(vm.$el.querySelectorAll('li')).toHaveLength(1);
- expect(vm.$el.querySelectorAll('li .katex')).toHaveLength(2);
+ expect(wrapper.vm.$el.querySelectorAll('li')).toHaveLength(1);
+ expect(wrapper.vm.$el.querySelectorAll('li .katex')).toHaveLength(2);
});
it('renders math formula with less-than-operator < in it', async () => {
- vm = buildMarkdownComponent(['- list with inline $a=2$ inline formula $a + b < c$\n', '\n']);
+ wrapper = buildMarkdownComponent([
+ '- list with inline $a=2$ inline formula $a + b < c$\n',
+ '\n',
+ ]);
await nextTick();
// expect one list with a katex formula in it
- expect(vm.$el.querySelectorAll('li')).toHaveLength(1);
- expect(vm.$el.querySelectorAll('li .katex')).toHaveLength(2);
+ expect(wrapper.vm.$el.querySelectorAll('li')).toHaveLength(1);
+ expect(wrapper.vm.$el.querySelectorAll('li .katex')).toHaveLength(2);
});
it('renders math formula with greater-than-operator > in it', async () => {
- vm = buildMarkdownComponent(['- list with inline $a=2$ inline formula $a + b > c$\n', '\n']);
+ wrapper = buildMarkdownComponent([
+ '- list with inline $a=2$ inline formula $a + b > c$\n',
+ '\n',
+ ]);
await nextTick();
// expect one list with a katex formula in it
- expect(vm.$el.querySelectorAll('li')).toHaveLength(1);
- expect(vm.$el.querySelectorAll('li .katex')).toHaveLength(2);
+ expect(wrapper.vm.$el.querySelectorAll('li')).toHaveLength(1);
+ expect(wrapper.vm.$el.querySelectorAll('li .katex')).toHaveLength(2);
});
});
});
diff --git a/spec/frontend/notebook/cells/output/index_spec.js b/spec/frontend/notebook/cells/output/index_spec.js
index 8bf049235a9..585cbb68eeb 100644
--- a/spec/frontend/notebook/cells/output/index_spec.js
+++ b/spec/frontend/notebook/cells/output/index_spec.js
@@ -1,12 +1,15 @@
import { mount } from '@vue/test-utils';
import json from 'test_fixtures/blob/notebook/basic.json';
import Output from '~/notebook/cells/output/index.vue';
+import MarkdownOutput from '~/notebook/cells/output/markdown.vue';
+import { relativeRawPath, markdownCellContent } from '../../mock_data';
describe('Output component', () => {
let wrapper;
const createComponent = (output) => {
wrapper = mount(Output, {
+ provide: { relativeRawPath },
propsData: {
outputs: [].concat(output),
count: 1,
@@ -95,6 +98,17 @@ describe('Output component', () => {
});
});
+ describe('Markdown output', () => {
+ beforeEach(() => {
+ const markdownType = { data: { 'text/markdown': markdownCellContent } };
+ createComponent(markdownType);
+ });
+
+ it('renders a markdown component', () => {
+ expect(wrapper.findComponent(MarkdownOutput).props('rawCode')).toBe(markdownCellContent);
+ });
+ });
+
describe('default to plain text', () => {
beforeEach(() => {
const unknownType = json.cells[6];
diff --git a/spec/frontend/notebook/cells/output/markdown_spec.js b/spec/frontend/notebook/cells/output/markdown_spec.js
new file mode 100644
index 00000000000..e3490ed3bea
--- /dev/null
+++ b/spec/frontend/notebook/cells/output/markdown_spec.js
@@ -0,0 +1,44 @@
+import { mount } from '@vue/test-utils';
+import MarkdownOutput from '~/notebook/cells/output/markdown.vue';
+import Prompt from '~/notebook/cells/prompt.vue';
+import Markdown from '~/notebook/cells/markdown.vue';
+import { relativeRawPath, markdownCellContent } from '../../mock_data';
+
+describe('markdown output cell', () => {
+ let wrapper;
+
+ const createComponent = ({ count = 0, index = 0 } = {}) => {
+ wrapper = mount(MarkdownOutput, {
+ provide: { relativeRawPath },
+ propsData: {
+ rawCode: markdownCellContent,
+ count,
+ index,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ const findPrompt = () => wrapper.findComponent(Prompt);
+ const findMarkdown = () => wrapper.findComponent(Markdown);
+
+ it.each`
+ index | count | showOutput
+ ${0} | ${1} | ${true}
+ ${1} | ${2} | ${false}
+ ${2} | ${3} | ${false}
+ `('renders a prompt', ({ index, count, showOutput }) => {
+ createComponent({ count, index });
+ expect(findPrompt().props()).toMatchObject({ count, showOutput, type: 'Out' });
+ });
+
+ it('renders a Markdown component', () => {
+ expect(findMarkdown().props()).toMatchObject({
+ cell: { source: markdownCellContent },
+ hidePrompt: true,
+ });
+ });
+});
diff --git a/spec/frontend/notebook/mock_data.js b/spec/frontend/notebook/mock_data.js
new file mode 100644
index 00000000000..b1419e1256f
--- /dev/null
+++ b/spec/frontend/notebook/mock_data.js
@@ -0,0 +1,2 @@
+export const relativeRawPath = '/test';
+export const markdownCellContent = ['# Test'];
diff --git a/spec/frontend/notes/components/__snapshots__/notes_app_spec.js.snap b/spec/frontend/notes/components/__snapshots__/notes_app_spec.js.snap
index bc29903d4bf..a4611149432 100644
--- a/spec/frontend/notes/components/__snapshots__/notes_app_spec.js.snap
+++ b/spec/frontend/notes/components/__snapshots__/notes_app_spec.js.snap
@@ -2,7 +2,7 @@
exports[`note_app when sort direction is asc shows skeleton notes after the loaded discussions 1`] = `
"<ul id=\\"notes-list\\" class=\\"notes main-notes-list timeline\\">
- <noteable-discussion-stub discussion=\\"[object Object]\\" renderdifffile=\\"true\\" helppagepath=\\"\\" isoverviewtab=\\"true\\"></noteable-discussion-stub>
+ <noteable-discussion-stub discussion=\\"[object Object]\\" renderdifffile=\\"true\\" helppagepath=\\"\\" isoverviewtab=\\"true\\" shouldscrolltonote=\\"true\\"></noteable-discussion-stub>
<skeleton-loading-container-stub class=\\"note-skeleton\\"></skeleton-loading-container-stub>
<!---->
</ul>"
@@ -11,7 +11,7 @@ exports[`note_app when sort direction is asc shows skeleton notes after the load
exports[`note_app when sort direction is desc shows skeleton notes before the loaded discussions 1`] = `
"<ul id=\\"notes-list\\" class=\\"notes main-notes-list timeline\\">
<skeleton-loading-container-stub class=\\"note-skeleton\\"></skeleton-loading-container-stub>
- <noteable-discussion-stub discussion=\\"[object Object]\\" renderdifffile=\\"true\\" helppagepath=\\"\\" isoverviewtab=\\"true\\"></noteable-discussion-stub>
+ <noteable-discussion-stub discussion=\\"[object Object]\\" renderdifffile=\\"true\\" helppagepath=\\"\\" isoverviewtab=\\"true\\" shouldscrolltonote=\\"true\\"></noteable-discussion-stub>
<!---->
</ul>"
`;
diff --git a/spec/frontend/notes/components/note_actions_spec.js b/spec/frontend/notes/components/note_actions_spec.js
index cbe11c20798..c7420ca9c48 100644
--- a/spec/frontend/notes/components/note_actions_spec.js
+++ b/spec/frontend/notes/components/note_actions_spec.js
@@ -5,6 +5,8 @@ import { TEST_HOST } from 'spec/test_constants';
import axios from '~/lib/utils/axios_utils';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import noteActions from '~/notes/components/note_actions.vue';
+import { NOTEABLE_TYPE_MAPPING } from '~/notes/constants';
+import TimelineEventButton from '~/notes/components/note_actions/timeline_event_button.vue';
import createStore from '~/notes/stores';
import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.vue';
import { userDataMock } from '../mock_data';
@@ -18,6 +20,23 @@ describe('noteActions', () => {
const findUserAccessRoleBadge = (idx) => wrapper.findAllComponents(UserAccessRoleBadge).at(idx);
const findUserAccessRoleBadgeText = (idx) => findUserAccessRoleBadge(idx).text().trim();
+ const findTimelineButton = () => wrapper.findComponent(TimelineEventButton);
+
+ const setupStoreForIncidentTimelineEvents = ({
+ userCanAdd,
+ noteableType,
+ isPromotionInProgress = true,
+ }) => {
+ store.dispatch('setUserData', {
+ ...userDataMock,
+ can_add_timeline_events: userCanAdd,
+ });
+ store.state.noteableData = {
+ ...store.state.noteableData,
+ type: noteableType,
+ };
+ store.state.isPromoteCommentToTimelineEventInProgress = isPromotionInProgress;
+ };
const mountNoteActions = (propsData, computed) => {
return mount(noteActions, {
@@ -238,7 +257,8 @@ describe('noteActions', () => {
describe('user is not logged in', () => {
beforeEach(() => {
- store.dispatch('setUserData', {});
+ // userData can be null https://gitlab.com/gitlab-org/gitlab/-/issues/379375
+ store.dispatch('setUserData', null);
wrapper = mountNoteActions({
...props,
canDelete: false,
@@ -301,4 +321,56 @@ describe('noteActions', () => {
expect(resolveButton.attributes('title')).toBe('Thread stays unresolved');
});
});
+
+ describe('timeline event button', () => {
+ // why: We are working with an integrated store, so let's imply the getter is used
+ describe.each`
+ desc | userCanAdd | noteableType | exists
+ ${'default'} | ${true} | ${NOTEABLE_TYPE_MAPPING.Incident} | ${true}
+ ${'when cannot add incident timeline event'} | ${false} | ${NOTEABLE_TYPE_MAPPING.Incident} | ${false}
+ ${'when is not incident'} | ${true} | ${NOTEABLE_TYPE_MAPPING.MergeRequest} | ${false}
+ `('$desc', ({ userCanAdd, noteableType, exists }) => {
+ beforeEach(() => {
+ setupStoreForIncidentTimelineEvents({
+ userCanAdd,
+ noteableType,
+ });
+
+ wrapper = mountNoteActions({ ...props });
+ });
+
+ it(`handles rendering of timeline button (exists=${exists})`, () => {
+ expect(findTimelineButton().exists()).toBe(exists);
+ });
+ });
+
+ describe('default', () => {
+ beforeEach(() => {
+ setupStoreForIncidentTimelineEvents({
+ userCanAdd: true,
+ noteableType: NOTEABLE_TYPE_MAPPING.Incident,
+ });
+
+ wrapper = mountNoteActions({ ...props });
+ });
+
+ it('should render timeline-event-button', () => {
+ expect(findTimelineButton().props()).toEqual({
+ noteId: props.noteId,
+ isPromotionInProgress: true,
+ });
+ });
+
+ it('when timeline-event-button emits click-promote-comment-to-event, dispatches action', () => {
+ jest.spyOn(store, 'dispatch').mockImplementation();
+
+ expect(store.dispatch).not.toHaveBeenCalled();
+
+ findTimelineButton().vm.$emit('click-promote-comment-to-event');
+
+ expect(store.dispatch).toHaveBeenCalledTimes(1);
+ expect(store.dispatch).toHaveBeenCalledWith('promoteCommentToTimelineEvent');
+ });
+ });
+ });
});
diff --git a/spec/frontend/notes/components/note_header_spec.js b/spec/frontend/notes/components/note_header_spec.js
index b870cda2a24..56c22b09e1b 100644
--- a/spec/frontend/notes/components/note_header_spec.js
+++ b/spec/frontend/notes/components/note_header_spec.js
@@ -18,7 +18,7 @@ describe('NoteHeader component', () => {
const findActionText = () => wrapper.findComponent({ ref: 'actionText' });
const findTimestampLink = () => wrapper.findComponent({ ref: 'noteTimestampLink' });
const findTimestamp = () => wrapper.findComponent({ ref: 'noteTimestamp' });
- const findInternalNoteIndicator = () => wrapper.findByTestId('internalNoteIndicator');
+ const findInternalNoteIndicator = () => wrapper.findByTestId('internal-note-indicator');
const findSpinner = () => wrapper.findComponent({ ref: 'spinner' });
const statusHtml =
diff --git a/spec/frontend/notes/mixins/discussion_navigation_spec.js b/spec/frontend/notes/mixins/discussion_navigation_spec.js
index 45625d0a23f..81e4ed3ebe7 100644
--- a/spec/frontend/notes/mixins/discussion_navigation_spec.js
+++ b/spec/frontend/notes/mixins/discussion_navigation_spec.js
@@ -34,7 +34,7 @@ describe('Discussion navigation mixin', () => {
beforeEach(() => {
setHTMLFixture(
- `<div class="notes">
+ `<div class="tab-pane notes">
${[...'abcde']
.map(
(id) =>
diff --git a/spec/frontend/notes/stores/getters_spec.js b/spec/frontend/notes/stores/getters_spec.js
index e03fa854e54..1514602d424 100644
--- a/spec/frontend/notes/stores/getters_spec.js
+++ b/spec/frontend/notes/stores/getters_spec.js
@@ -1,5 +1,5 @@
import discussionWithTwoUnresolvedNotes from 'test_fixtures/merge_requests/resolved_diff_discussion.json';
-import { DESC, ASC } from '~/notes/constants';
+import { DESC, ASC, NOTEABLE_TYPE_MAPPING } from '~/notes/constants';
import * as getters from '~/notes/stores/getters';
import {
notesDataMock,
@@ -536,4 +536,24 @@ describe('Getters Notes Store', () => {
expect(getters.sortDirection(state)).toBe(DESC);
});
});
+
+ describe('canUserAddIncidentTimelineEvents', () => {
+ it.each`
+ userData | noteableData | expected
+ ${{ can_add_timeline_events: true }} | ${{ type: NOTEABLE_TYPE_MAPPING.Incident }} | ${true}
+ ${{ can_add_timeline_events: true }} | ${{ type: NOTEABLE_TYPE_MAPPING.Issue }} | ${false}
+ ${null} | ${{ type: NOTEABLE_TYPE_MAPPING.Incident }} | ${false}
+ ${{ can_add_timeline_events: false }} | ${{ type: NOTEABLE_TYPE_MAPPING.Incident }} | ${false}
+ `(
+ 'with userData=$userData and noteableData=$noteableData, expected=$expected',
+ ({ userData, noteableData, expected }) => {
+ Object.assign(state, {
+ userData,
+ noteableData,
+ });
+
+ expect(getters.canUserAddIncidentTimelineEvents(state)).toBe(expected);
+ },
+ );
+ });
});
diff --git a/spec/frontend/observability/observability_app_spec.js b/spec/frontend/observability/observability_app_spec.js
new file mode 100644
index 00000000000..f0b318e69ec
--- /dev/null
+++ b/spec/frontend/observability/observability_app_spec.js
@@ -0,0 +1,73 @@
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import ObservabilityApp from '~/observability/components/observability_app.vue';
+
+describe('Observability root app', () => {
+ let wrapper;
+ const replace = jest.fn();
+ const $router = {
+ replace,
+ };
+ const $route = {
+ pathname: 'https://gitlab.com/gitlab-org/',
+ query: { otherQuery: 100 },
+ };
+
+ const findIframe = () => wrapper.findByTestId('observability-ui-iframe');
+
+ const TEST_IFRAME_SRC = 'https://observe.gitlab.com/9970/?groupId=14485840';
+
+ const mountComponent = (route = $route) => {
+ wrapper = shallowMountExtended(ObservabilityApp, {
+ propsData: {
+ observabilityIframeSrc: TEST_IFRAME_SRC,
+ },
+ mocks: {
+ $router,
+ $route: route,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('should render an iframe with observabilityIframeSrc as src', () => {
+ mountComponent();
+ const iframe = findIframe();
+ expect(iframe.exists()).toBe(true);
+ expect(iframe.attributes('src')).toBe(TEST_IFRAME_SRC);
+ });
+
+ it('should not call replace method from vue router if message event does not have url', () => {
+ mountComponent();
+ wrapper.vm.messageHandler({ data: 'some other data' });
+ expect(replace).not.toHaveBeenCalled();
+ });
+
+ 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 } });
+ wrapper.vm.messageHandler({ data: { url }, origin });
+ expect(replace).not.toHaveBeenCalled();
+ },
+ );
+
+ it('should call replace method from vue router on messageHandle call', () => {
+ mountComponent();
+ wrapper.vm.messageHandler({ data: { url: '/explore' }, origin: 'https://observe.gitlab.com' });
+ expect(replace).toHaveBeenCalled();
+ expect(replace).toHaveBeenCalledWith({
+ name: 'https://gitlab.com/gitlab-org/',
+ query: {
+ otherQuery: 100,
+ observability_path: '/explore',
+ },
+ });
+ });
+});
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 0b59fe2d8ce..7da91c4af96 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
@@ -33,7 +33,7 @@ describe('Image List Row', () => {
const findListItemComponent = () => wrapper.findComponent(ListItem);
const findShowFullPathButton = () => wrapper.findComponent(GlButton);
- const mountComponent = (props, features = {}) => {
+ const mountComponent = (props) => {
wrapper = shallowMount(Component, {
stubs: {
RouterLink,
@@ -47,9 +47,6 @@ describe('Image List Row', () => {
},
provide: {
config: {},
- glFeatures: {
- ...features,
- },
},
directives: {
GlTooltip: createMockDirective(),
@@ -88,23 +85,43 @@ describe('Image List Row', () => {
});
describe('image title and path', () => {
- it('contains a link to the details page', () => {
+ it('renders shortened name of image and contains a link to the details page', () => {
mountComponent();
const link = findDetailsLink();
- expect(link.text()).toBe(item.path);
- expect(findDetailsLink().props('to')).toMatchObject({
+ expect(link.text()).toBe('gitlab-test/rails-12009');
+
+ expect(link.props('to')).toMatchObject({
name: 'details',
params: {
id: getIdFromGraphQLId(item.id),
},
});
+
+ expect(findShowFullPathButton().exists()).toBe(true);
});
it('when the image has no name lists the path', () => {
mountComponent({ item: { ...item, name: '' } });
+ expect(findDetailsLink().text()).toBe('gitlab-test');
+ });
+
+ it('clicking on shortened name of image hides the button & shows full path', async () => {
+ mountComponent();
+
+ const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ const mockFocusFn = jest.fn();
+ wrapper.vm.$refs.imageName.$el.focus = mockFocusFn;
+
+ await findShowFullPathButton().trigger('click');
+
+ expect(findShowFullPathButton().exists()).toBe(false);
expect(findDetailsLink().text()).toBe(item.path);
+ expect(mockFocusFn).toHaveBeenCalled();
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_show_full_path', {
+ label: 'registry_image_list',
+ });
});
it('contains a clipboard button', () => {
@@ -149,35 +166,6 @@ describe('Image List Row', () => {
expect(findClipboardButton().attributes('disabled')).toBe('true');
});
});
-
- describe('when containerRegistryShowShortenedPath feature enabled', () => {
- let trackingSpy;
-
- beforeEach(() => {
- mountComponent({}, { containerRegistryShowShortenedPath: true });
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- });
-
- it('renders shortened name of image', () => {
- expect(findShowFullPathButton().exists()).toBe(true);
- expect(findDetailsLink().text()).toBe('gitlab-test/rails-12009');
- });
-
- it('clicking on shortened name of image hides the button & shows full path', async () => {
- const btn = findShowFullPathButton();
- const mockFocusFn = jest.fn();
- wrapper.vm.$refs.imageName.$el.focus = mockFocusFn;
-
- await btn.trigger('click');
-
- expect(findShowFullPathButton().exists()).toBe(false);
- expect(findDetailsLink().text()).toBe(item.path);
- expect(mockFocusFn).toHaveBeenCalled();
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_show_full_path', {
- label: 'registry_image_list',
- });
- });
- });
});
describe('delete button', () => {
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 e6d81d4a28f..bcc8e41fce8 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
@@ -58,6 +58,12 @@ describe('registry_header', () => {
describe('sub header parts', () => {
describe('images count', () => {
+ it('does not exist', async () => {
+ await mountComponent({ imagesCount: 0 });
+
+ expect(findImagesCountSubHeader().exists()).toBe(false);
+ });
+
it('exists', async () => {
await mountComponent({ imagesCount: 1 });
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 ee6470a9df8..310398b01cf 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
@@ -26,6 +26,7 @@ import {
import deleteContainerRepositoryTagsMutation from '~/packages_and_registries/container_registry/explorer/graphql/mutations/delete_container_repository_tags.mutation.graphql';
import getContainerRepositoryDetailsQuery from '~/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_details.query.graphql';
import getContainerRepositoryTagsQuery from '~/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql';
+import getContainerRepositoriesDetails from '~/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repositories_details.query.graphql';
import component from '~/packages_and_registries/container_registry/explorer/pages/details.vue';
import Tracking from '~/tracking';
@@ -34,6 +35,7 @@ import {
graphQLImageDetailsMock,
graphQLDeleteImageRepositoryTagsMock,
graphQLDeleteImageRepositoryTagImportingErrorMock,
+ graphQLProjectImageRepositoriesDetailsMock,
containerRepositoryMock,
graphQLEmptyImageDetailsMock,
tagsMock,
@@ -64,6 +66,9 @@ describe('Details Page', () => {
const defaultConfig = {
noContainersImage: 'noContainersImage',
+ projectListUrl: 'projectListUrl',
+ groupListUrl: 'groupListUrl',
+ isGroupPage: false,
};
const cleanTags = tagsMock.map((t) => {
@@ -81,7 +86,8 @@ describe('Details Page', () => {
const mountComponent = ({
resolver = jest.fn().mockResolvedValue(graphQLImageDetailsMock()),
mutationResolver = jest.fn().mockResolvedValue(graphQLDeleteImageRepositoryTagsMock),
- tagsResolver = jest.fn().mockResolvedValue(graphQLImageDetailsMock(imageTagsMock)),
+ tagsResolver = jest.fn().mockResolvedValue(graphQLImageDetailsMock(imageTagsMock())),
+ detailsResolver = jest.fn().mockResolvedValue(graphQLProjectImageRepositoriesDetailsMock),
options,
config = defaultConfig,
} = {}) => {
@@ -91,6 +97,7 @@ describe('Details Page', () => {
[getContainerRepositoryDetailsQuery, resolver],
[deleteContainerRepositoryTagsMutation, mutationResolver],
[getContainerRepositoryTagsQuery, tagsResolver],
+ [getContainerRepositoriesDetails, detailsResolver],
];
apolloProvider = createMockApollo(requestHandlers);
@@ -256,11 +263,13 @@ describe('Details Page', () => {
describe('confirmDelete event', () => {
let mutationResolver;
let tagsResolver;
+ let detailsResolver;
beforeEach(() => {
mutationResolver = jest.fn().mockResolvedValue(graphQLDeleteImageRepositoryTagsMock);
- tagsResolver = jest.fn().mockResolvedValue(graphQLImageDetailsMock(imageTagsMock));
- mountComponent({ mutationResolver, tagsResolver });
+ tagsResolver = jest.fn().mockResolvedValue(graphQLImageDetailsMock(imageTagsMock()));
+ detailsResolver = jest.fn().mockResolvedValue(graphQLProjectImageRepositoriesDetailsMock);
+ mountComponent({ mutationResolver, tagsResolver, detailsResolver });
return waitForApolloRequestRender();
});
@@ -280,6 +289,7 @@ describe('Details Page', () => {
await waitForPromises();
expect(tagsResolver).toHaveBeenCalled();
+ expect(detailsResolver).toHaveBeenCalled();
});
});
@@ -298,6 +308,7 @@ describe('Details Page', () => {
await waitForPromises();
expect(tagsResolver).toHaveBeenCalled();
+ expect(detailsResolver).toHaveBeenCalled();
});
});
});
@@ -359,14 +370,16 @@ describe('Details Page', () => {
describe('importing repository error', () => {
let mutationResolver;
let tagsResolver;
+ let detailsResolver;
beforeEach(async () => {
mutationResolver = jest
.fn()
.mockResolvedValue(graphQLDeleteImageRepositoryTagImportingErrorMock);
- tagsResolver = jest.fn().mockResolvedValue(graphQLImageDetailsMock(imageTagsMock));
+ tagsResolver = jest.fn().mockResolvedValue(graphQLImageDetailsMock(imageTagsMock()));
+ detailsResolver = jest.fn().mockResolvedValue(graphQLProjectImageRepositoriesDetailsMock);
- mountComponent({ mutationResolver, tagsResolver });
+ mountComponent({ mutationResolver, tagsResolver, detailsResolver });
await waitForApolloRequestRender();
});
@@ -378,6 +391,7 @@ describe('Details Page', () => {
await waitForPromises();
expect(tagsResolver).toHaveBeenCalled();
+ expect(detailsResolver).toHaveBeenCalled();
const deleteAlert = findDeleteAlert();
expect(deleteAlert.exists()).toBe(true);
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 fb5ee4e6884..0164d92ce34 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
@@ -1,12 +1,13 @@
-import { GlTable, GlPagination, GlModal } from '@gitlab/ui';
+import { GlTable, GlPagination } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
+import Vue from 'vue';
import { last } from 'lodash';
import Vuex from 'vuex';
import stubChildren from 'helpers/stub_children';
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';
@@ -22,7 +23,7 @@ describe('packages_list', () => {
const findPackagesListLoader = () => wrapper.findComponent(PackagesListLoader);
const findPackageListPagination = () => wrapper.findComponent(GlPagination);
- const findPackageListDeleteModal = () => wrapper.findComponent(GlModal);
+ const findPackageListDeleteModal = () => wrapper.findComponent(DeletePackageModal);
const findEmptySlot = () => wrapper.findComponent(EmptySlotStub);
const findPackagesListRow = () => wrapper.findComponent(PackagesListRow);
@@ -65,7 +66,7 @@ describe('packages_list', () => {
stubs: {
...stubChildren(PackagesList),
GlTable,
- GlModal,
+ DeletePackageModal,
},
...options,
});
@@ -109,52 +110,38 @@ describe('packages_list', () => {
expect(sorting.exists()).toBe(true);
});
- it('contains a modal component', () => {
- const sorting = findPackageListDeleteModal();
- expect(sorting.exists()).toBe(true);
+ it("doesn't contain a modal component", () => {
+ expect(findPackageListDeleteModal().props('itemToBeDeleted')).toBeNull();
});
});
describe('when the user can destroy the package', () => {
- beforeEach(() => {
+ let itemToBeDeleted;
+
+ beforeEach(async () => {
mountComponent();
+ itemToBeDeleted = last(packageList);
+ await findPackagesListRow().vm.$emit('packageToDelete', itemToBeDeleted);
});
- it('setItemToBeDeleted sets itemToBeDeleted and open the modal', async () => {
- const mockModalShow = jest.spyOn(wrapper.vm.$refs.packageListDeleteModal, 'show');
- const item = last(wrapper.vm.list);
-
- findPackagesListRow().vm.$emit('packageToDelete', item);
-
- await nextTick();
- expect(wrapper.vm.itemToBeDeleted).toEqual(item);
- expect(mockModalShow).toHaveBeenCalled();
+ afterEach(() => {
+ itemToBeDeleted = null;
});
- it('deleteItemConfirmation resets itemToBeDeleted', () => {
- // 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: 1 });
- wrapper.vm.deleteItemConfirmation();
- expect(wrapper.vm.itemToBeDeleted).toEqual(null);
+ it('passes itemToBeDeleted to the modal', () => {
+ expect(findPackageListDeleteModal().props('itemToBeDeleted')).toStrictEqual(itemToBeDeleted);
});
it('deleteItemConfirmation emit package:delete', async () => {
- const itemToBeDeleted = { id: 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({ itemToBeDeleted });
- wrapper.vm.deleteItemConfirmation();
- await nextTick();
+ await findPackageListDeleteModal().vm.$emit('ok');
+
expect(wrapper.emitted('package:delete')[0]).toEqual([itemToBeDeleted]);
});
- it('deleteItemCanceled resets itemToBeDeleted', () => {
- // 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: 1 });
- wrapper.vm.deleteItemCanceled();
- expect(wrapper.vm.itemToBeDeleted).toEqual(null);
+ it.each(['ok', 'cancel'])('resets itemToBeDeleted when modal emits %s', async (event) => {
+ await findPackageListDeleteModal().vm.$emit(event);
+
+ expect(findPackageListDeleteModal().props('itemToBeDeleted')).toBeNull();
});
});
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
new file mode 100644
index 00000000000..e0e26434680
--- /dev/null
+++ b/spec/frontend/packages_and_registries/package_registry/components/delete_modal_spec.js
@@ -0,0 +1,71 @@
+import { GlModal as RealGlModal } from '@gitlab/ui';
+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';
+
+const GlModal = stubComponent(RealGlModal, {
+ methods: {
+ show: jest.fn(),
+ },
+});
+
+describe('DeleteModal', () => {
+ let wrapper;
+
+ const defaultItemsToBeDeleted = [
+ {
+ name: 'package 01',
+ },
+ {
+ name: 'package 02',
+ },
+ ];
+
+ const findModal = () => wrapper.findComponent(GlModal);
+
+ const mountComponent = ({ itemsToBeDeleted = defaultItemsToBeDeleted } = {}) => {
+ wrapper = shallowMountExtended(DeleteModal, {
+ propsData: {
+ itemsToBeDeleted,
+ },
+ stubs: {
+ GlModal,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('passes title prop', () => {
+ expect(findModal().props('title')).toMatchInterpolatedText('Delete packages');
+ });
+
+ it('passes actionPrimary prop', () => {
+ expect(findModal().props('actionPrimary')).toStrictEqual({
+ text: 'Permanently delete',
+ attributes: [{ variant: 'danger' }, { category: 'primary' }],
+ });
+ });
+
+ it('renders description', () => {
+ expect(findModal().text()).toContain(
+ 'You are about to delete 2 packages. This operation is irreversible.',
+ );
+ });
+
+ it('emits confirm when primary event is emitted', () => {
+ expect(wrapper.emitted('confirm')).toBeUndefined();
+
+ findModal().vm.$emit('primary');
+
+ expect(wrapper.emitted('confirm')).toHaveLength(1);
+ });
+
+ it('show calls gl-modal show', () => {
+ findModal().vm.show();
+
+ expect(GlModal.methods.show).toHaveBeenCalled();
+ });
+});
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
new file mode 100644
index 00000000000..f0fa9592419
--- /dev/null
+++ b/spec/frontend/packages_and_registries/package_registry/components/details/package_versions_list_spec.js
@@ -0,0 +1,152 @@
+import { GlKeysetPagination } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+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 VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
+import { packageData } from '../../mock_data';
+
+describe('PackageVersionsList', () => {
+ let wrapper;
+
+ const EmptySlotStub = { name: 'empty-slot-stub', template: '<div>empty message</div>' };
+ const packageList = [
+ packageData({
+ name: 'version 1',
+ }),
+ packageData({
+ id: `gid://gitlab/Packages::Package/112`,
+ name: 'version 2',
+ }),
+ ];
+
+ const uiElements = {
+ findLoader: () => wrapper.findComponent(PackagesListLoader),
+ findListPagination: () => wrapper.findComponent(GlKeysetPagination),
+ findEmptySlot: () => wrapper.findComponent(EmptySlotStub),
+ findListRow: () => wrapper.findAllComponents(VersionRow),
+ };
+ const mountComponent = (props) => {
+ wrapper = shallowMountExtended(PackageVersionsList, {
+ propsData: {
+ versions: packageList,
+ pageInfo: {},
+ isLoading: false,
+ ...props,
+ },
+ slots: {
+ 'empty-state': EmptySlotStub,
+ },
+ });
+ };
+
+ describe('when list is loading', () => {
+ beforeEach(() => {
+ mountComponent({ isLoading: true, versions: [] });
+ });
+ it('displays loader', () => {
+ expect(uiElements.findLoader().exists()).toBe(true);
+ });
+
+ it('does not display rows', () => {
+ expect(uiElements.findListRow().exists()).toBe(false);
+ });
+
+ it('does not display empty slot message', () => {
+ expect(uiElements.findEmptySlot().exists()).toBe(false);
+ });
+
+ it('does not display pagination', () => {
+ expect(uiElements.findListPagination().exists()).toBe(false);
+ });
+ });
+
+ describe('when list is loaded and has no data', () => {
+ beforeEach(() => {
+ mountComponent({ isLoading: false, versions: [] });
+ });
+
+ it('displays empty slot message', () => {
+ expect(uiElements.findEmptySlot().exists()).toBe(true);
+ });
+
+ it('does not display loader', () => {
+ expect(uiElements.findLoader().exists()).toBe(false);
+ });
+
+ it('does not display rows', () => {
+ expect(uiElements.findListRow().exists()).toBe(false);
+ });
+
+ it('does not display pagination', () => {
+ expect(uiElements.findListPagination().exists()).toBe(false);
+ });
+ });
+
+ describe('when list is loaded with data', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('displays package version rows', () => {
+ expect(uiElements.findListRow().exists()).toEqual(true);
+ expect(uiElements.findListRow()).toHaveLength(packageList.length);
+ });
+
+ it('binds the correct props', () => {
+ expect(uiElements.findListRow().at(0).props()).toMatchObject({
+ packageEntity: expect.objectContaining(packageList[0]),
+ });
+
+ expect(uiElements.findListRow().at(1).props()).toMatchObject({
+ packageEntity: expect.objectContaining(packageList[1]),
+ });
+ });
+
+ describe('pagination display', () => {
+ it('does not display pagination if there is no previous or next page', () => {
+ expect(uiElements.findListPagination().exists()).toBe(false);
+ });
+
+ it('displays pagination if pageInfo.hasNextPage is true', async () => {
+ await wrapper.setProps({ pageInfo: { hasNextPage: true } });
+ expect(uiElements.findListPagination().exists()).toBe(true);
+ });
+
+ it('displays pagination if pageInfo.hasPreviousPage is true', async () => {
+ await wrapper.setProps({ pageInfo: { hasPreviousPage: true } });
+ expect(uiElements.findListPagination().exists()).toBe(true);
+ });
+
+ it('displays pagination if both pageInfo.hasNextPage and pageInfo.hasPreviousPage are true', async () => {
+ await wrapper.setProps({ pageInfo: { hasNextPage: true, hasPreviousPage: true } });
+ expect(uiElements.findListPagination().exists()).toBe(true);
+ });
+ });
+
+ it('does not display loader', () => {
+ expect(uiElements.findLoader().exists()).toBe(false);
+ });
+
+ it('does not display empty slot message', () => {
+ expect(uiElements.findEmptySlot().exists()).toBe(false);
+ });
+ });
+
+ describe('when user interacts with pagination', () => {
+ beforeEach(() => {
+ mountComponent({ pageInfo: { hasNextPage: true } });
+ });
+
+ it('emits prev-page event when paginator emits prev event', () => {
+ uiElements.findListPagination().vm.$emit('prev');
+
+ expect(wrapper.emitted('prev-page')).toHaveLength(1);
+ });
+
+ it('emits next-page when paginator emits next event', () => {
+ uiElements.findListPagination().vm.$emit('next');
+
+ expect(wrapper.emitted('next-page')).toHaveLength(1);
+ });
+ });
+});
diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/package_list_row_spec.js.snap b/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/package_list_row_spec.js.snap
index 5be05ddf629..a7de751aadd 100644
--- a/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/package_list_row_spec.js.snap
+++ b/spec/frontend/packages_and_registries/package_registry/components/list/__snapshots__/package_list_row_spec.js.snap
@@ -8,7 +8,14 @@ exports[`packages_list_row renders 1`] = `
<div
class="gl-display-flex gl-align-items-center gl-py-3"
>
- <!---->
+ <div
+ class="gl-w-7 gl-display-flex gl-justify-content-start gl-pl-2"
+ >
+ <gl-form-checkbox-stub
+ class="gl-m-0"
+ id="2"
+ />
+ </div>
<div
class="gl-display-flex gl-xs-flex-direction-column gl-justify-content-space-between gl-align-items-stretch gl-flex-grow-1"
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 b5a512b8806..913b4f5926f 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,4 +1,4 @@
-import { GlSprintf } from '@gitlab/ui';
+import { GlFormCheckbox, GlSprintf } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import VueRouter from 'vue-router';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
@@ -40,9 +40,11 @@ describe('packages_list_row', () => {
const findPublishMethod = () => wrapper.findComponent(PublishMethod);
const findCreatedDateText = () => wrapper.findByTestId('created-date');
const findTimeAgoTooltip = () => wrapper.findComponent(TimeagoTooltip);
+ const findBulkDeleteAction = () => wrapper.findComponent(GlFormCheckbox);
const mountComponent = ({
packageEntity = packageWithoutTags,
+ selected = false,
provide = defaultProvide,
} = {}) => {
wrapper = shallowMountExtended(PackagesListRow, {
@@ -53,6 +55,7 @@ describe('packages_list_row', () => {
},
propsData: {
packageEntity,
+ selected,
},
directives: {
GlTooltip: createMockDirective(),
@@ -117,14 +120,13 @@ describe('packages_list_row', () => {
});
});
- it('emits the packageToDelete event when the delete button is clicked', async () => {
+ it('emits the delete event when the delete button is clicked', async () => {
mountComponent({ packageEntity: packageWithoutTags });
findDeleteDropdown().vm.$emit('click');
await nextTick();
- expect(wrapper.emitted('packageToDelete')).toHaveLength(1);
- expect(wrapper.emitted('packageToDelete')[0]).toEqual([packageWithoutTags]);
+ expect(wrapper.emitted('delete')).toHaveLength(1);
});
});
@@ -151,6 +153,39 @@ describe('packages_list_row', () => {
});
});
+ describe('left action template', () => {
+ it('does not render checkbox if not permitted', () => {
+ mountComponent({
+ packageEntity: { ...packageWithoutTags, canDestroy: false },
+ });
+
+ expect(findBulkDeleteAction().exists()).toBe(false);
+ });
+
+ it('renders checkbox', () => {
+ mountComponent();
+
+ expect(findBulkDeleteAction().exists()).toBe(true);
+ expect(findBulkDeleteAction().attributes('checked')).toBeUndefined();
+ });
+
+ it('emits select when checked', () => {
+ mountComponent();
+
+ findBulkDeleteAction().vm.$emit('change');
+
+ expect(wrapper.emitted('select')).toHaveLength(1);
+ });
+
+ it('renders checkbox in selected state if selected', () => {
+ mountComponent({
+ selected: true,
+ });
+
+ expect(findBulkDeleteAction().attributes('checked')).toBe('true');
+ });
+ });
+
describe('secondary left info', () => {
it('has the package version', () => {
mountComponent();
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 3e3607a361c..7cc5bea0f7a 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
@@ -1,8 +1,10 @@
-import { GlAlert, GlKeysetPagination, GlModal, GlSprintf } from '@gitlab/ui';
+import { GlAlert, GlSprintf } from '@gitlab/ui';
import { nextTick } from 'vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import PackagesListRow from '~/packages_and_registries/package_registry/components/list/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 RegistryList from '~/packages_and_registries/shared/components/registry_list.vue';
import {
DELETE_PACKAGE_TRACKING_ACTION,
REQUEST_DELETE_PACKAGE_TRACKING_ACTION,
@@ -35,16 +37,11 @@ describe('packages_list', () => {
};
const EmptySlotStub = { name: 'empty-slot-stub', template: '<div>bar</div>' };
- const GlModalStub = {
- name: GlModal.name,
- template: '<div><slot></slot></div>',
- methods: { show: jest.fn() },
- };
const findPackagesListLoader = () => wrapper.findComponent(PackagesListLoader);
- const findPackageListPagination = () => wrapper.findComponent(GlKeysetPagination);
- const findPackageListDeleteModal = () => wrapper.findComponent(GlModalStub);
+ const findPackageListDeleteModal = () => wrapper.findComponent(DeletePackageModal);
const findEmptySlot = () => wrapper.findComponent(EmptySlotStub);
+ const findRegistryList = () => wrapper.findComponent(RegistryList);
const findPackagesListRow = () => wrapper.findComponent(PackagesListRow);
const findErrorPackageAlert = () => wrapper.findComponent(GlAlert);
@@ -55,8 +52,9 @@ describe('packages_list', () => {
...props,
},
stubs: {
- GlModal: GlModalStub,
+ DeletePackageModal,
GlSprintf,
+ RegistryList,
},
slots: {
'empty-state': EmptySlotStub,
@@ -64,10 +62,6 @@ describe('packages_list', () => {
});
};
- beforeEach(() => {
- GlModalStub.methods.show.mockReset();
- });
-
afterEach(() => {
wrapper.destroy();
});
@@ -81,12 +75,12 @@ describe('packages_list', () => {
expect(findPackagesListLoader().exists()).toBe(true);
});
- it('does not show the rows', () => {
- expect(findPackagesListRow().exists()).toBe(false);
+ it('does not show the registry list', () => {
+ expect(findRegistryList().exists()).toBe(false);
});
- it('does not show the pagination', () => {
- expect(findPackageListPagination().exists()).toBe(false);
+ it('does not show the rows', () => {
+ expect(findPackagesListRow().exists()).toBe(false);
});
});
@@ -99,22 +93,29 @@ describe('packages_list', () => {
expect(findPackagesListLoader().exists()).toBe(false);
});
+ it('shows the registry list', () => {
+ expect(findRegistryList().exists()).toBe(true);
+ });
+
+ it('shows the registry list with the right props', () => {
+ expect(findRegistryList().props()).toMatchObject({
+ title: '2 packages',
+ items: defaultProps.list,
+ pagination: defaultProps.pageInfo,
+ isLoading: false,
+ });
+ });
+
it('shows the rows', () => {
expect(findPackagesListRow().exists()).toBe(true);
});
});
describe('layout', () => {
- it('contains a pagination component', () => {
- mountComponent({ pageInfo: { hasPreviousPage: true } });
-
- expect(findPackageListPagination().exists()).toBe(true);
- });
-
- it('contains a modal component', () => {
+ it("doesn't contain a visible modal component", () => {
mountComponent();
- expect(findPackageListDeleteModal().exists()).toBe(true);
+ expect(findPackageListDeleteModal().props('itemToBeDeleted')).toBeNull();
});
it('does not have an error alert displayed', () => {
@@ -125,31 +126,46 @@ describe('packages_list', () => {
});
describe('when the user can destroy the package', () => {
- beforeEach(() => {
+ beforeEach(async () => {
mountComponent();
- findPackagesListRow().vm.$emit('packageToDelete', firstPackage);
- return nextTick();
+ await findPackagesListRow().vm.$emit('delete', firstPackage);
});
- it('deleting a package opens the modal', () => {
- expect(findPackageListDeleteModal().text()).toContain(firstPackage.name);
+ it('passes itemToBeDeleted to the modal', () => {
+ expect(findPackageListDeleteModal().props('itemToBeDeleted')).toStrictEqual(firstPackage);
});
- it('confirming on the modal emits package:delete', async () => {
- findPackageListDeleteModal().vm.$emit('ok');
-
- await nextTick();
+ it('emits package:delete when modal confirms', async () => {
+ await findPackageListDeleteModal().vm.$emit('ok');
expect(wrapper.emitted('package:delete')[0]).toEqual([firstPackage]);
});
- it('closing the modal resets itemToBeDeleted', async () => {
- // triggering the v-model
- findPackageListDeleteModal().vm.$emit('input', false);
+ it.each(['ok', 'cancel'])('resets itemToBeDeleted when modal emits %s', async (event) => {
+ await findPackageListDeleteModal().vm.$emit(event);
- await nextTick();
+ expect(findPackageListDeleteModal().props('itemToBeDeleted')).toBeNull();
+ });
+ });
+
+ describe('when the user can bulk destroy packages', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('passes itemToBeDeleted to the modal when there is only one package', async () => {
+ await findRegistryList().vm.$emit('delete', [firstPackage]);
+
+ expect(findPackageListDeleteModal().props('itemToBeDeleted')).toStrictEqual(firstPackage);
+ expect(wrapper.emitted('delete')).toBeUndefined();
+ });
+
+ it('emits delete when there is more than one package', () => {
+ const items = [firstPackage, secondPackage];
+ findRegistryList().vm.$emit('delete', items);
- expect(findPackageListDeleteModal().text()).not.toContain(firstPackage.name);
+ expect(wrapper.emitted('delete')).toHaveLength(1);
+ expect(wrapper.emitted('delete')[0]).toEqual([items]);
});
});
@@ -196,15 +212,15 @@ describe('packages_list', () => {
});
it('emits prev-page events when the prev event is fired', () => {
- findPackageListPagination().vm.$emit('prev');
+ findRegistryList().vm.$emit('prev-page');
- expect(wrapper.emitted('prev-page')).toEqual([[]]);
+ expect(wrapper.emitted('prev-page')).toHaveLength(1);
});
it('emits next-page events when the next event is fired', () => {
- findPackageListPagination().vm.$emit('next');
+ findRegistryList().vm.$emit('next-page');
- expect(wrapper.emitted('next-page')).toEqual([[]]);
+ expect(wrapper.emitted('next-page')).toHaveLength(1);
});
});
@@ -215,7 +231,7 @@ describe('packages_list', () => {
beforeEach(() => {
eventSpy = jest.spyOn(Tracking, 'event');
mountComponent();
- findPackagesListRow().vm.$emit('packageToDelete', firstPackage);
+ findPackagesListRow().vm.$emit('delete', firstPackage);
return nextTick();
});
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 c2b6fb734d6..f36c5923532 100644
--- a/spec/frontend/packages_and_registries/package_registry/mock_data.js
+++ b/spec/frontend/packages_and_registries/package_registry/mock_data.js
@@ -233,6 +233,12 @@ export const packageDetailsQuery = (extendPackage) => ({
},
versions: {
nodes: packageVersions(),
+ pageInfo: {
+ hasNextPage: true,
+ hasPreviousPage: false,
+ endCursor: 'endCursor',
+ startCursor: 'startCursor',
+ },
__typename: 'PackageConnection',
},
dependencyLinks: {
@@ -288,6 +294,33 @@ export const packageDestroyMutation = () => ({
},
});
+export const packagesDestroyMutation = () => ({
+ data: {
+ destroyPackages: {
+ errors: [],
+ },
+ },
+});
+
+export const packagesDestroyMutationError = () => ({
+ data: {
+ destroyPackages: null,
+ },
+ errors: [
+ {
+ message:
+ "The resource that you are attempting to access does not exist or you don't have permission to perform this action",
+ locations: [
+ {
+ line: 2,
+ column: 3,
+ },
+ ],
+ path: ['destroyPackages'],
+ },
+ ],
+});
+
export const packageDestroyMutationError = () => ({
data: {
destroyPackage: null,
@@ -314,6 +347,7 @@ export const packageDestroyFilesMutation = () => ({
},
},
});
+
export const packageDestroyFilesMutationError = () => ({
data: {
destroyPackageFiles: null,
diff --git a/spec/frontend/packages_and_registries/package_registry/pages/__snapshots__/list_spec.js.snap b/spec/frontend/packages_and_registries/package_registry/pages/__snapshots__/list_spec.js.snap
index 17905a8db2d..c2fecf87428 100644
--- a/spec/frontend/packages_and_registries/package_registry/pages/__snapshots__/list_spec.js.snap
+++ b/spec/frontend/packages_and_registries/package_registry/pages/__snapshots__/list_spec.js.snap
@@ -2,12 +2,62 @@
exports[`PackagesListApp renders 1`] = `
<div>
+ <!---->
+
+ <gl-card-stub
+ bodyclass="gl-display-flex gl-p-0!"
+ class="gl-px-8 gl-py-6 gl-line-height-20 gl-mt-3"
+ footerclass=""
+ headerclass=""
+ >
+ <!---->
+
+ <div
+ class="gl-banner-content"
+ >
+ <h2
+ class="gl-banner-title"
+ >
+ Help us learn about your registry migration needs
+ </h2>
+
+ <p>
+ If you are interested in migrating packages from your private registry to the GitLab Package Registry, take our survey and tell us more about your needs.
+ </p>
+
+ <gl-button-stub
+ buttontextclasses=""
+ category="primary"
+ data-testid="gl-banner-primary-button"
+ href="https://gitlab.fra1.qualtrics.com/jfe/form/SV_cHomH9FPzOaiDTU"
+ icon=""
+ size="medium"
+ variant="confirm"
+ >
+ Take survey
+ </gl-button-stub>
+
+ </div>
+
+ <gl-button-stub
+ aria-label="Close banner"
+ buttontextclasses=""
+ category="tertiary"
+ class="gl-banner-close"
+ icon="close"
+ size="small"
+ variant="default"
+ />
+ </gl-card-stub>
+
<package-title-stub
count="2"
helpurl="/help/user/packages/index"
/>
- <package-search-stub />
+ <package-search-stub
+ class="gl-mb-5"
+ />
<div>
<section
@@ -69,5 +119,7 @@ exports[`PackagesListApp renders 1`] = `
</div>
</section>
</div>
+
+ <div />
</div>
`;
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 a32e76a132e..f942a334f40 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
@@ -15,8 +15,8 @@ import InstallationCommands from '~/packages_and_registries/package_registry/com
import PackageFiles from '~/packages_and_registries/package_registry/components/details/package_files.vue';
import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue';
-import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
import DeletePackage from '~/packages_and_registries/package_registry/components/functional/delete_package.vue';
+import PackageVersionsList from '~/packages_and_registries/package_registry/components/details/package_versions_list.vue';
import {
FETCH_PACKAGE_DETAILS_ERROR_MESSAGE,
PACKAGE_TYPE_COMPOSER,
@@ -99,6 +99,7 @@ describe('PackagesApp', () => {
GlSprintf,
GlTabs,
GlTab,
+ PackageVersionsList,
},
mocks: {
$route: {
@@ -120,8 +121,7 @@ describe('PackagesApp', () => {
const findPackageFiles = () => wrapper.findComponent(PackageFiles);
const findDeleteFileModal = () => wrapper.findByTestId('delete-file-modal');
const findDeleteFilesModal = () => wrapper.findByTestId('delete-files-modal');
- const findVersionRows = () => wrapper.findAllComponents(VersionRow);
- const noVersionsMessage = () => wrapper.findByTestId('no-versions-message');
+ const findVersionsList = () => wrapper.findComponent(PackageVersionsList);
const findDependenciesCountBadge = () => wrapper.findComponent(GlBadge);
const findNoDependenciesMessage = () => wrapper.findByTestId('no-dependencies-message');
const findDependencyRows = () => wrapper.findAllComponents(DependencyRow);
@@ -558,38 +558,23 @@ describe('PackagesApp', () => {
});
describe('versions', () => {
- it('displays the correct version count when the package has versions', async () => {
+ it('displays versions list when the package has versions', async () => {
createComponent();
await waitForPromises();
- expect(findVersionRows()).toHaveLength(packageVersions().length);
+ expect(findVersionsList()).toBeDefined();
});
it('binds the correct props', async () => {
- const [versionPackage] = packageVersions();
- // eslint-disable-next-line no-underscore-dangle
- delete versionPackage.__typename;
- delete versionPackage.tags;
-
- createComponent();
-
+ const versionNodes = packageVersions();
+ createComponent({ packageEntity: { versions: { nodes: versionNodes } } });
await waitForPromises();
- expect(findVersionRows().at(0).props()).toMatchObject({
- packageEntity: expect.objectContaining(versionPackage),
+ expect(findVersionsList().props()).toMatchObject({
+ versions: expect.arrayContaining(versionNodes),
});
});
-
- it('displays the no versions message when there are none', async () => {
- createComponent({
- resolver: jest.fn().mockResolvedValue(packageDetailsQuery({ versions: { nodes: [] } })),
- });
-
- await waitForPromises();
-
- expect(noVersionsMessage().exists()).toBe(true);
- });
});
describe('dependency links', () => {
it('does not show the dependency links for a non nuget package', async () => {
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 0e74fbbc6d9..abdb875e839 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
@@ -1,30 +1,39 @@
-import { GlEmptyState, GlSprintf, GlLink } from '@gitlab/ui';
+import { GlAlert, GlBanner, GlEmptyState, GlSprintf, GlLink } from '@gitlab/ui';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
-
+import * as utils from '~/lib/utils/common_utils';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
+import { stubComponent } from 'helpers/stub_component';
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 DeletePackage from '~/packages_and_registries/package_registry/components/functional/delete_package.vue';
-
+import DeleteModal from '~/packages_and_registries/package_registry/components/delete_modal.vue';
import {
PROJECT_RESOURCE_TYPE,
GROUP_RESOURCE_TYPE,
GRAPHQL_PAGE_SIZE,
+ HIDE_PACKAGE_MIGRATION_SURVEY_COOKIE,
EMPTY_LIST_HELP_URL,
PACKAGE_HELP_URL,
+ DELETE_PACKAGES_ERROR_MESSAGE,
+ DELETE_PACKAGES_SUCCESS_MESSAGE,
} from '~/packages_and_registries/package_registry/constants';
import getPackagesQuery from '~/packages_and_registries/package_registry/graphql/queries/get_packages.query.graphql';
+import destroyPackagesMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_packages.mutation.graphql';
+import {
+ packagesListQuery,
+ packageData,
+ pagination,
+ packagesDestroyMutation,
+ packagesDestroyMutationError,
+} from '../mock_data';
-import { packagesListQuery, packageData, pagination } from '../mock_data';
-
-jest.mock('~/lib/utils/common_utils');
jest.mock('~/flash');
describe('PackagesListApp', () => {
@@ -49,31 +58,44 @@ describe('PackagesListApp', () => {
filters: { packageName: 'foo', packageType: 'CONAN' },
};
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findBanner = () => wrapper.findComponent(GlBanner);
const findPackageTitle = () => wrapper.findComponent(PackageTitle);
const findSearch = () => wrapper.findComponent(PackageSearch);
const findListComponent = () => wrapper.findComponent(PackageList);
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
const findDeletePackage = () => wrapper.findComponent(DeletePackage);
+ const findDeletePackagesModal = () => wrapper.findComponent(DeleteModal);
const mountComponent = ({
resolver = jest.fn().mockResolvedValue(packagesListQuery()),
+ mutationResolver,
provide = defaultProvide,
} = {}) => {
Vue.use(VueApollo);
- const requestHandlers = [[getPackagesQuery, resolver]];
+ const requestHandlers = [
+ [getPackagesQuery, resolver],
+ [destroyPackagesMutation, mutationResolver],
+ ];
apolloProvider = createMockApollo(requestHandlers);
wrapper = shallowMountExtended(ListPage, {
apolloProvider,
provide,
stubs: {
+ GlBanner,
GlEmptyState,
GlLoadingIcon,
GlSprintf,
GlLink,
PackageList,
DeletePackage,
+ DeleteModal: stubComponent(DeleteModal, {
+ methods: {
+ show: jest.fn(),
+ },
+ }),
},
});
};
@@ -116,6 +138,70 @@ describe('PackagesListApp', () => {
});
});
+ describe('package migration survey banner', () => {
+ describe('with no cookie set', () => {
+ beforeEach(() => {
+ utils.setCookie = jest.fn();
+
+ mountComponent();
+ });
+
+ it('displays the banner', () => {
+ expect(findBanner().exists()).toBe(true);
+ });
+
+ it('does not call setCookie', () => {
+ expect(utils.setCookie).not.toHaveBeenCalled();
+ });
+
+ describe('when the close button is clicked', () => {
+ beforeEach(() => {
+ findBanner().vm.$emit('close');
+ });
+
+ it('sets the dismissed cookie', () => {
+ expect(utils.setCookie).toHaveBeenCalledWith(
+ HIDE_PACKAGE_MIGRATION_SURVEY_COOKIE,
+ 'true',
+ );
+ });
+
+ it('does not display the banner', () => {
+ expect(findBanner().exists()).toBe(false);
+ });
+ });
+
+ describe('when the primary button is clicked', () => {
+ beforeEach(() => {
+ findBanner().vm.$emit('primary');
+ });
+
+ it('sets the dismissed cookie', () => {
+ expect(utils.setCookie).toHaveBeenCalledWith(
+ HIDE_PACKAGE_MIGRATION_SURVEY_COOKIE,
+ 'true',
+ );
+ });
+
+ it('does not display the banner', () => {
+ expect(findBanner().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('with the dismissed cookie set', () => {
+ beforeEach(() => {
+ jest.spyOn(utils, 'getCookie').mockReturnValue('true');
+
+ mountComponent();
+ });
+
+ it('does not display the banner', () => {
+ expect(findBanner().exists()).toBe(false);
+ });
+ });
+ });
+
describe('search component', () => {
it('exists', () => {
mountComponent();
@@ -282,4 +368,62 @@ describe('PackagesListApp', () => {
expect(findListComponent().props('isLoading')).toBe(false);
});
});
+
+ describe('bulk delete package', () => {
+ const items = [{ id: '1' }, { id: '2' }];
+
+ it('deletePackage is bound to package-list package:delete event', async () => {
+ mountComponent();
+
+ await waitForFirstRequest();
+
+ findListComponent().vm.$emit('delete', [{ id: '1' }, { id: '2' }]);
+
+ await waitForPromises();
+
+ expect(findDeletePackagesModal().props('itemsToBeDeleted')).toEqual(items);
+ });
+
+ it('calls mutation with the right values and shows success alert', async () => {
+ const mutationResolver = jest.fn().mockResolvedValue(packagesDestroyMutation());
+ mountComponent({
+ mutationResolver,
+ });
+
+ await waitForFirstRequest();
+
+ findListComponent().vm.$emit('delete', items);
+
+ findDeletePackagesModal().vm.$emit('confirm');
+
+ expect(mutationResolver).toHaveBeenCalledWith({
+ ids: items.map((item) => item.id),
+ });
+
+ await waitForPromises();
+
+ expect(findAlert().exists()).toBe(true);
+ expect(findAlert().props('variant')).toEqual('success');
+ expect(findAlert().text()).toMatchInterpolatedText(DELETE_PACKAGES_SUCCESS_MESSAGE);
+ });
+
+ it('on error shows danger alert', async () => {
+ const mutationResolver = jest.fn().mockResolvedValue(packagesDestroyMutationError());
+ mountComponent({
+ mutationResolver,
+ });
+
+ await waitForFirstRequest();
+
+ findListComponent().vm.$emit('delete', items);
+
+ findDeletePackagesModal().vm.$emit('confirm');
+
+ await waitForPromises();
+
+ expect(findAlert().exists()).toBe(true);
+ expect(findAlert().props('variant')).toEqual('danger');
+ expect(findAlert().text()).toMatchInterpolatedText(DELETE_PACKAGES_ERROR_MESSAGE);
+ });
+ });
});
diff --git a/spec/frontend/packages_and_registries/settings/group/components/forwarding_settings_spec.js b/spec/frontend/packages_and_registries/settings/group/components/forwarding_settings_spec.js
new file mode 100644
index 00000000000..8f229182fe5
--- /dev/null
+++ b/spec/frontend/packages_and_registries/settings/group/components/forwarding_settings_spec.js
@@ -0,0 +1,78 @@
+import { GlFormGroup, GlSprintf } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import component from '~/packages_and_registries/settings/group/components/forwarding_settings.vue';
+
+describe('Forwarding Settings', () => {
+ let wrapper;
+
+ const defaultProps = {
+ disabled: false,
+ forwarding: false,
+ label: 'label',
+ lockForwarding: false,
+ modelNames: {
+ forwarding: 'forwardField',
+ lockForwarding: 'lockForwardingField',
+ isLocked: 'lockedField',
+ },
+ };
+
+ const mountComponent = (propsData = defaultProps) => {
+ wrapper = shallowMountExtended(component, {
+ propsData,
+ stubs: {
+ GlSprintf,
+ },
+ });
+ };
+
+ const findFormGroup = () => wrapper.findComponent(GlFormGroup);
+ const findForwardingCheckbox = () => wrapper.findByTestId('forwarding-checkbox');
+ const findLockForwardingCheckbox = () => wrapper.findByTestId('lock-forwarding-checkbox');
+
+ it('has a form group', () => {
+ mountComponent();
+
+ expect(findFormGroup().exists()).toBe(true);
+ expect(findFormGroup().attributes()).toMatchObject({
+ label: defaultProps.label,
+ });
+ });
+
+ describe.each`
+ name | finder | label | extraProps | field
+ ${'forwarding'} | ${findForwardingCheckbox} | ${'Forward label package requests'} | ${{ forwarding: true }} | ${defaultProps.modelNames.forwarding}
+ ${'lock forwarding'} | ${findLockForwardingCheckbox} | ${'Enforce label setting for all subgroups'} | ${{ lockForwarding: true }} | ${defaultProps.modelNames.lockForwarding}
+ `('$name checkbox', ({ name, finder, label, extraProps, field }) => {
+ it('is rendered', () => {
+ mountComponent();
+ expect(finder().exists()).toBe(true);
+ expect(finder().text()).toMatchInterpolatedText(label);
+ expect(finder().attributes('disabled')).toBeUndefined();
+ expect(finder().attributes('checked')).toBeUndefined();
+ });
+
+ it(`is checked when ${name} set`, () => {
+ mountComponent({ ...defaultProps, ...extraProps });
+
+ expect(finder().attributes('checked')).toBe('true');
+ });
+
+ it(`emits an update event with field ${field} set`, () => {
+ mountComponent();
+
+ finder().vm.$emit('change', true);
+
+ expect(wrapper.emitted('update')).toStrictEqual([[field, true]]);
+ });
+ });
+
+ describe('disabled', () => {
+ it('disables both checkboxes', () => {
+ mountComponent({ ...defaultProps, disabled: true });
+
+ expect(findForwardingCheckbox().attributes('disabled')).toEqual('true');
+ expect(findLockForwardingCheckbox().attributes('disabled')).toEqual('true');
+ });
+ });
+});
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 31fc3ad419c..7edc321867c 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
@@ -7,6 +7,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import PackagesSettings from '~/packages_and_registries/settings/group/components/packages_settings.vue';
import DependencyProxySettings from '~/packages_and_registries/settings/group/components/dependency_proxy_settings.vue';
+import PackagesForwardingSettings from '~/packages_and_registries/settings/group/components/packages_forwarding_settings.vue';
import component from '~/packages_and_registries/settings/group/components/group_settings_app.vue';
@@ -60,6 +61,7 @@ describe('Group Settings App', () => {
const findAlert = () => wrapper.findComponent(GlAlert);
const findPackageSettings = () => wrapper.findComponent(PackagesSettings);
+ const findPackageForwardingSettings = () => wrapper.findComponent(PackagesForwardingSettings);
const findDependencyProxySettings = () => wrapper.findComponent(DependencyProxySettings);
const waitForApolloQueryAndRender = async () => {
@@ -67,16 +69,18 @@ describe('Group Settings App', () => {
await nextTick();
};
- const packageSettingsProps = { packageSettings: packageSettings() };
+ const packageSettingsProps = { packageSettings };
+ const packageForwardingSettingsProps = { forwardSettings: { ...packageSettings } };
const dependencyProxyProps = {
dependencyProxySettings: dependencyProxySettings(),
dependencyProxyImageTtlPolicy: dependencyProxyImageTtlPolicy(),
};
describe.each`
- finder | entitySpecificProps | successMessage | errorMessage
- ${findPackageSettings} | ${packageSettingsProps} | ${'Settings saved successfully'} | ${'An error occurred while saving the settings'}
- ${findDependencyProxySettings} | ${dependencyProxyProps} | ${'Setting saved successfully'} | ${'An error occurred while saving the setting'}
+ finder | entitySpecificProps | successMessage | errorMessage
+ ${findPackageSettings} | ${packageSettingsProps} | ${'Settings saved successfully'} | ${'An error occurred while saving the settings'}
+ ${findPackageForwardingSettings} | ${packageForwardingSettingsProps} | ${'Settings saved successfully'} | ${'An error occurred while saving the settings'}
+ ${findDependencyProxySettings} | ${dependencyProxyProps} | ${'Setting saved successfully'} | ${'An error occurred while saving the setting'}
`('settings blocks', ({ finder, entitySpecificProps, successMessage, errorMessage }) => {
beforeEach(() => {
mountComponent();
@@ -88,10 +92,7 @@ describe('Group Settings App', () => {
});
it('binds the correctProps', () => {
- expect(finder().props()).toMatchObject({
- isLoading: false,
- ...entitySpecificProps,
- });
+ expect(finder().props()).toMatchObject(entitySpecificProps);
});
describe('success event', () => {
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 13eba39ec8c..807f332f4d3 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
@@ -48,7 +48,7 @@ describe('Packages Settings', () => {
apolloProvider,
provide: defaultProvide,
propsData: {
- packageSettings: packageSettings(),
+ packageSettings,
},
stubs: {
SettingsBlock,
@@ -83,7 +83,7 @@ describe('Packages Settings', () => {
};
const emitMavenSettingsUpdate = (override) => {
- findGenericDuplicatedSettingsExceptionsInput().vm.$emit('update', {
+ findMavenDuplicatedSettingsExceptionsInput().vm.$emit('update', {
mavenDuplicateExceptionRegex: ')',
...override,
});
@@ -117,7 +117,7 @@ describe('Packages Settings', () => {
it('renders toggle', () => {
mountComponent({ mountFn: mountExtended });
- const { mavenDuplicatesAllowed } = packageSettings();
+ const { mavenDuplicatesAllowed } = packageSettings;
expect(findMavenDuplicatedSettingsToggle().exists()).toBe(true);
@@ -132,7 +132,7 @@ describe('Packages Settings', () => {
it('renders ExceptionsInput and assigns duplication allowness and exception props', () => {
mountComponent({ mountFn: mountExtended });
- const { mavenDuplicatesAllowed, mavenDuplicateExceptionRegex } = packageSettings();
+ const { mavenDuplicatesAllowed, mavenDuplicateExceptionRegex } = packageSettings;
expect(findMavenDuplicatedSettingsExceptionsInput().exists()).toBe(true);
@@ -170,7 +170,7 @@ describe('Packages Settings', () => {
it('renders toggle', () => {
mountComponent({ mountFn: mountExtended });
- const { genericDuplicatesAllowed } = packageSettings();
+ const { genericDuplicatesAllowed } = packageSettings;
expect(findGenericDuplicatedSettingsToggle().exists()).toBe(true);
expect(findGenericDuplicatedSettingsToggle().props()).toMatchObject({
@@ -184,7 +184,7 @@ describe('Packages Settings', () => {
it('renders ExceptionsInput and assigns duplication allowness and exception props', async () => {
mountComponent({ mountFn: mountExtended });
- const { genericDuplicatesAllowed, genericDuplicateExceptionRegex } = packageSettings();
+ const { genericDuplicatesAllowed, genericDuplicateExceptionRegex } = packageSettings;
expect(findGenericDuplicatedSettingsExceptionsInput().props()).toMatchObject({
duplicatesAllowed: genericDuplicatesAllowed,
@@ -239,7 +239,7 @@ describe('Packages Settings', () => {
emitMavenSettingsUpdate({ mavenDuplicateExceptionRegex });
expect(updateGroupPackagesSettingsOptimisticResponse).toHaveBeenCalledWith({
- ...packageSettings(),
+ ...packageSettings,
mavenDuplicateExceptionRegex,
});
});
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
new file mode 100644
index 00000000000..a0b257a9496
--- /dev/null
+++ b/spec/frontend/packages_and_registries/settings/group/components/packages_forwarding_settings_spec.js
@@ -0,0 +1,280 @@
+import Vue from 'vue';
+import { GlButton } from '@gitlab/ui';
+import VueApollo from 'vue-apollo';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import component from '~/packages_and_registries/settings/group/components/packages_forwarding_settings.vue';
+import {
+ PACKAGE_FORWARDING_SETTINGS_DESCRIPTION,
+ PACKAGE_FORWARDING_SETTINGS_HEADER,
+} from '~/packages_and_registries/settings/group/constants';
+
+import updateNamespacePackageSettings from '~/packages_and_registries/settings/group/graphql/mutations/update_group_packages_settings.mutation.graphql';
+import getGroupPackagesSettingsQuery from '~/packages_and_registries/settings/group/graphql/queries/get_group_packages_settings.query.graphql';
+import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue';
+import { updateGroupPackagesSettingsOptimisticResponse } from '~/packages_and_registries/settings/group/graphql/utils/optimistic_responses';
+import {
+ packageSettings,
+ packageForwardingSettings,
+ groupPackageSettingsMock,
+ groupPackageForwardSettingsMutationMock,
+ mutationErrorMock,
+ npmProps,
+ pypiProps,
+ mavenProps,
+} from '../mock_data';
+
+jest.mock('~/flash');
+jest.mock('~/packages_and_registries/settings/group/graphql/utils/optimistic_responses');
+
+describe('Packages Forwarding Settings', () => {
+ let wrapper;
+ let apolloProvider;
+ const mutationResolverFn = jest.fn().mockResolvedValue(groupPackageForwardSettingsMutationMock());
+
+ const defaultProvide = {
+ groupPath: 'foo_group_path',
+ };
+
+ const mountComponent = ({
+ forwardSettings = { ...packageSettings },
+ features = {},
+ mutationResolver = mutationResolverFn,
+ } = {}) => {
+ Vue.use(VueApollo);
+
+ const requestHandlers = [[updateNamespacePackageSettings, mutationResolver]];
+
+ apolloProvider = createMockApollo(requestHandlers);
+
+ wrapper = shallowMountExtended(component, {
+ apolloProvider,
+ provide: {
+ ...defaultProvide,
+ glFeatures: {
+ ...features,
+ },
+ },
+ propsData: {
+ forwardSettings,
+ },
+ stubs: {
+ SettingsBlock,
+ },
+ });
+ };
+
+ const findSettingsBlock = () => wrapper.findComponent(SettingsBlock);
+ const findForm = () => wrapper.find('form');
+ const findSubmitButton = () => findForm().findComponent(GlButton);
+ const findDescription = () => wrapper.findByTestId('description');
+ const findMavenForwardingSettings = () => wrapper.findByTestId('maven');
+ const findNpmForwardingSettings = () => wrapper.findByTestId('npm');
+ const findPyPiForwardingSettings = () => wrapper.findByTestId('pypi');
+
+ const fillApolloCache = () => {
+ apolloProvider.defaultClient.cache.writeQuery({
+ query: getGroupPackagesSettingsQuery,
+ variables: {
+ fullPath: defaultProvide.groupPath,
+ },
+ ...groupPackageSettingsMock,
+ });
+ };
+
+ const updateNpmSettings = () => {
+ findNpmForwardingSettings().vm.$emit('update', 'npmPackageRequestsForwarding', false);
+ };
+
+ const submitForm = () => {
+ findForm().trigger('submit');
+ return waitForPromises();
+ };
+
+ afterEach(() => {
+ apolloProvider = null;
+ });
+
+ it('renders a settings block', () => {
+ mountComponent();
+
+ expect(findSettingsBlock().exists()).toBe(true);
+ });
+
+ it('has the correct header text', () => {
+ mountComponent();
+
+ expect(wrapper.text()).toContain(PACKAGE_FORWARDING_SETTINGS_HEADER);
+ });
+
+ it('has the correct description text', () => {
+ mountComponent();
+
+ expect(findDescription().text()).toMatchInterpolatedText(
+ PACKAGE_FORWARDING_SETTINGS_DESCRIPTION,
+ );
+ });
+
+ it('watches changes to props', async () => {
+ mountComponent();
+
+ expect(findNpmForwardingSettings().props()).toMatchObject(npmProps);
+
+ await wrapper.setProps({
+ forwardSettings: {
+ ...packageSettings,
+ npmPackageRequestsForwardingLocked: true,
+ },
+ });
+
+ expect(findNpmForwardingSettings().props()).toMatchObject({ ...npmProps, disabled: true });
+ });
+
+ it('submit button is disabled', () => {
+ mountComponent();
+
+ expect(findSubmitButton().props('disabled')).toBe(true);
+ });
+
+ describe.each`
+ type | finder | props | field
+ ${'npm'} | ${findNpmForwardingSettings} | ${npmProps} | ${'npmPackageRequestsForwarding'}
+ ${'pypi'} | ${findPyPiForwardingSettings} | ${pypiProps} | ${'pypiPackageRequestsForwarding'}
+ ${'maven'} | ${findMavenForwardingSettings} | ${mavenProps} | ${'mavenPackageRequestsForwarding'}
+ `('$type settings', ({ finder, props, field }) => {
+ beforeEach(() => {
+ mountComponent({ features: { mavenCentralRequestForwarding: true } });
+ });
+
+ it('assigns forwarding settings props', () => {
+ expect(finder().props()).toMatchObject(props);
+ });
+
+ it('on update event enables submit button', async () => {
+ finder().vm.$emit('update', field, false);
+
+ await waitForPromises();
+
+ expect(findSubmitButton().props('disabled')).toBe(false);
+ });
+ });
+
+ describe('maven settings', () => {
+ describe('with feature turned off', () => {
+ it('does not exist', () => {
+ mountComponent();
+
+ expect(findMavenForwardingSettings().exists()).toBe(false);
+ });
+ });
+ });
+
+ describe('settings update', () => {
+ describe('success state', () => {
+ it('calls the mutation with the right variables', async () => {
+ const {
+ mavenPackageRequestsForwardingLocked,
+ npmPackageRequestsForwardingLocked,
+ pypiPackageRequestsForwardingLocked,
+ ...packageSettingsInput
+ } = packageForwardingSettings;
+
+ mountComponent();
+
+ fillApolloCache();
+ updateNpmSettings();
+
+ await submitForm();
+
+ expect(mutationResolverFn).toHaveBeenCalledWith({
+ input: {
+ namespacePath: defaultProvide.groupPath,
+ ...packageSettingsInput,
+ npmPackageRequestsForwarding: false,
+ },
+ });
+ });
+
+ it('when field are locked calls the mutation with the right variables', async () => {
+ mountComponent({
+ forwardSettings: {
+ ...packageSettings,
+ mavenPackageRequestsForwardingLocked: true,
+ pypiPackageRequestsForwardingLocked: true,
+ },
+ });
+
+ fillApolloCache();
+ updateNpmSettings();
+
+ await submitForm();
+
+ expect(mutationResolverFn).toHaveBeenCalledWith({
+ input: {
+ namespacePath: defaultProvide.groupPath,
+ lockNpmPackageRequestsForwarding: false,
+ npmPackageRequestsForwarding: false,
+ },
+ });
+ });
+
+ it('emits a success event', async () => {
+ mountComponent();
+ fillApolloCache();
+ updateNpmSettings();
+
+ await submitForm();
+
+ expect(wrapper.emitted('success')).toHaveLength(1);
+ });
+
+ it('has an optimistic response', async () => {
+ const npmPackageRequestsForwarding = false;
+ mountComponent();
+
+ fillApolloCache();
+
+ expect(findNpmForwardingSettings().props('forwarding')).toBe(true);
+
+ updateNpmSettings();
+ await submitForm();
+
+ expect(updateGroupPackagesSettingsOptimisticResponse).toHaveBeenCalledWith({
+ ...packageSettings,
+ npmPackageRequestsForwarding,
+ });
+ expect(findNpmForwardingSettings().props('forwarding')).toBe(npmPackageRequestsForwarding);
+ });
+ });
+
+ describe('errors', () => {
+ it('mutation payload with root level errors', async () => {
+ const mutationResolver = jest.fn().mockResolvedValue(mutationErrorMock);
+ mountComponent({ mutationResolver });
+
+ fillApolloCache();
+
+ updateNpmSettings();
+ await submitForm();
+
+ expect(wrapper.emitted('error')).toHaveLength(1);
+ });
+
+ it.each`
+ type | mutationResolver
+ ${'local'} | ${jest.fn().mockResolvedValue(groupPackageForwardSettingsMutationMock({ errors: ['foo'] }))}
+ ${'network'} | ${jest.fn().mockRejectedValue()}
+ `('mutation payload with $type error', async ({ mutationResolver }) => {
+ mountComponent({ mutationResolver });
+
+ fillApolloCache();
+
+ updateNpmSettings();
+ await submitForm();
+
+ expect(wrapper.emitted('error')).toHaveLength(1);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/packages_and_registries/settings/group/mock_data.js b/spec/frontend/packages_and_registries/settings/group/mock_data.js
index d53446de910..1ca9dc6daeb 100644
--- a/spec/frontend/packages_and_registries/settings/group/mock_data.js
+++ b/spec/frontend/packages_and_registries/settings/group/mock_data.js
@@ -1,9 +1,26 @@
-export const packageSettings = () => ({
+const packageDuplicateSettings = {
mavenDuplicatesAllowed: true,
mavenDuplicateExceptionRegex: '',
genericDuplicatesAllowed: true,
genericDuplicateExceptionRegex: '',
-});
+};
+
+export const packageForwardingSettings = {
+ mavenPackageRequestsForwarding: true,
+ lockMavenPackageRequestsForwarding: false,
+ npmPackageRequestsForwarding: true,
+ lockNpmPackageRequestsForwarding: false,
+ pypiPackageRequestsForwarding: true,
+ lockPypiPackageRequestsForwarding: false,
+ mavenPackageRequestsForwardingLocked: false,
+ npmPackageRequestsForwardingLocked: false,
+ pypiPackageRequestsForwardingLocked: false,
+};
+
+export const packageSettings = {
+ ...packageDuplicateSettings,
+ ...packageForwardingSettings,
+};
export const dependencyProxySettings = (extend) => ({
enabled: true,
@@ -21,13 +38,52 @@ export const groupPackageSettingsMock = {
group: {
id: '1',
fullPath: 'foo_group_path',
- packageSettings: packageSettings(),
+ packageSettings: {
+ ...packageSettings,
+ __typename: 'PackageSettings',
+ },
dependencyProxySetting: dependencyProxySettings(),
dependencyProxyImageTtlPolicy: dependencyProxyImageTtlPolicy(),
},
},
};
+export const npmProps = {
+ forwarding: packageForwardingSettings.npmPackageRequestsForwarding,
+ lockForwarding: packageForwardingSettings.lockNpmPackageRequestsForwarding,
+ label: 'npm',
+ disabled: false,
+ modelNames: {
+ forwarding: 'npmPackageRequestsForwarding',
+ lockForwarding: 'lockNpmPackageRequestsForwarding',
+ isLocked: 'npmPackageRequestsForwardingLocked',
+ },
+};
+
+export const pypiProps = {
+ forwarding: packageForwardingSettings.pypiPackageRequestsForwarding,
+ lockForwarding: packageForwardingSettings.lockPypiPackageRequestsForwarding,
+ label: 'PyPI',
+ disabled: false,
+ modelNames: {
+ forwarding: 'pypiPackageRequestsForwarding',
+ lockForwarding: 'lockPypiPackageRequestsForwarding',
+ isLocked: 'pypiPackageRequestsForwardingLocked',
+ },
+};
+
+export const mavenProps = {
+ forwarding: packageForwardingSettings.mavenPackageRequestsForwarding,
+ lockForwarding: packageForwardingSettings.lockMavenPackageRequestsForwarding,
+ label: 'Maven',
+ disabled: false,
+ modelNames: {
+ forwarding: 'mavenPackageRequestsForwarding',
+ lockForwarding: 'lockMavenPackageRequestsForwarding',
+ isLocked: 'mavenPackageRequestsForwardingLocked',
+ },
+};
+
export const groupPackageSettingsMutationMock = (override) => ({
data: {
updateNamespacePackageSettings: {
@@ -43,6 +99,19 @@ export const groupPackageSettingsMutationMock = (override) => ({
},
});
+export const groupPackageForwardSettingsMutationMock = (override) => ({
+ data: {
+ updateNamespacePackageSettings: {
+ packageSettings: {
+ npmPackageRequestsForwarding: true,
+ lockNpmPackageRequestsForwarding: false,
+ },
+ errors: [],
+ ...override,
+ },
+ },
+});
+
export const dependencyProxySettingMutationMock = (override) => ({
data: {
updateDependencyProxySettings: {
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
new file mode 100644
index 00000000000..357dab593e8
--- /dev/null
+++ b/spec/frontend/packages_and_registries/shared/components/delete_package_modal_spec.js
@@ -0,0 +1,82 @@
+import { GlSprintf, GlModal } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import DeletePackageModal from '~/packages_and_registries/shared/components/delete_package_modal.vue';
+
+describe('DeletePackageModal', () => {
+ let wrapper;
+
+ const defaultItemToBeDeleted = {
+ name: 'package 01',
+ };
+
+ const findModal = () => wrapper.findComponent(GlModal);
+
+ const mountComponent = ({ itemToBeDeleted = defaultItemToBeDeleted } = {}) => {
+ wrapper = shallowMountExtended(DeletePackageModal, {
+ propsData: {
+ itemToBeDeleted,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('when itemToBeDeleted prop is defined', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ it('displays modal', () => {
+ expect(findModal().props('visible')).toBe(true);
+ });
+
+ it('passes title prop', () => {
+ expect(findModal().props('title')).toBe(wrapper.vm.$options.i18n.modalTitle);
+ });
+
+ it('passes actionPrimary prop', () => {
+ expect(findModal().props('actionPrimary')).toStrictEqual({
+ text: wrapper.vm.$options.i18n.modalAction,
+ attributes: {
+ variant: 'danger',
+ },
+ });
+ });
+
+ it('displays description', () => {
+ const descriptionEl = findModal().findComponent(GlSprintf);
+
+ expect(descriptionEl.exists()).toBe(true);
+ expect(descriptionEl.attributes('message')).toBe(wrapper.vm.$options.i18n.modalDescription);
+ });
+
+ it('emits ok when modal is validate', () => {
+ expect(wrapper.emitted().ok).toBeUndefined();
+
+ findModal().vm.$emit('ok');
+
+ expect(wrapper.emitted().ok).toHaveLength(1);
+ });
+
+ it('emits cancel when modal close', () => {
+ expect(wrapper.emitted().cancel).toBeUndefined();
+
+ findModal().vm.$emit('change', false);
+
+ expect(wrapper.emitted().cancel).toHaveLength(1);
+ });
+ });
+
+ describe('when itemToBeDeleted prop is null', () => {
+ beforeEach(() => {
+ mountComponent({ itemToBeDeleted: null });
+ });
+
+ it("doesn't display modal", () => {
+ expect(findModal().props('visible')).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_spec.js.snap b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_spec.js.snap
index aab78c99190..6b6833b00c3 100644
--- a/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_spec.js.snap
+++ b/spec/frontend/pages/projects/learn_gitlab/components/__snapshots__/learn_gitlab_spec.js.snap
@@ -147,6 +147,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<div>
<a
class="gl-link"
+ data-qa-selector="uncompleted_learn_gitlab_link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="set_up_your_first_project_s_ci_cd"
@@ -171,6 +172,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<div>
<a
class="gl-link"
+ data-qa-selector="uncompleted_learn_gitlab_link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="start_a_free_trial_of_gitlab_ultimate"
@@ -196,6 +198,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<div>
<a
class="gl-link"
+ data-qa-selector="uncompleted_learn_gitlab_link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="add_code_owners"
@@ -228,6 +231,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<div>
<a
class="gl-link"
+ data-qa-selector="uncompleted_learn_gitlab_link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="enable_require_merge_approvals"
@@ -294,6 +298,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<div>
<a
class="gl-link"
+ data-qa-selector="uncompleted_learn_gitlab_link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="create_an_issue"
@@ -318,6 +323,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<div>
<a
class="gl-link"
+ data-qa-selector="uncompleted_learn_gitlab_link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="submit_a_merge_request_mr"
@@ -376,6 +382,7 @@ exports[`Learn GitLab renders correctly 1`] = `
<div>
<a
class="gl-link"
+ data-qa-selector="uncompleted_learn_gitlab_link"
data-testid="uncompleted-learn-gitlab-link"
data-track-action="click_link"
data-track-label="run_a_security_scan_using_ci_cd"
diff --git a/spec/frontend/pages/projects/pipeline_schedules/shared/components/timezone_dropdown_spec.js b/spec/frontend/pages/projects/pipeline_schedules/shared/components/timezone_dropdown_spec.js
index f54d56c3af4..4cac642bb50 100644
--- a/spec/frontend/pages/projects/pipeline_schedules/shared/components/timezone_dropdown_spec.js
+++ b/spec/frontend/pages/projects/pipeline_schedules/shared/components/timezone_dropdown_spec.js
@@ -1,139 +1,7 @@
-import $ from 'jquery';
-import { loadHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import { formatUtcOffset, formatTimezone } from '~/lib/utils/datetime_utility';
-import TimezoneDropdown, {
- findTimezoneByIdentifier,
-} from '~/pages/projects/pipeline_schedules/shared/components/timezone_dropdown';
+import { findTimezoneByIdentifier } from '~/pages/projects/pipeline_schedules/shared/components/timezone_dropdown';
describe('Timezone Dropdown', () => {
- let $inputEl = null;
- let $dropdownEl = null;
- let $wrapper = null;
- const tzListSel = '.dropdown-content ul li a.is-active';
-
- const initTimezoneDropdown = (options = {}) => {
- // eslint-disable-next-line no-new
- new TimezoneDropdown({
- $inputEl,
- $dropdownEl,
- ...options,
- });
- };
-
- const findDropdownToggleText = () => $wrapper.find('.dropdown-toggle-text');
-
- describe('Initialize', () => {
- describe('with dropdown already loaded', () => {
- beforeEach(() => {
- loadHTMLFixture('pipeline_schedules/edit.html');
- $wrapper = $('.dropdown');
- $inputEl = $('#schedule_cron_timezone');
- $inputEl.val('');
- $dropdownEl = $('.js-timezone-dropdown');
- });
-
- afterEach(() => {
- resetHTMLFixture();
- });
-
- it('can take an $inputEl in the constructor', () => {
- initTimezoneDropdown();
-
- const tzStr = '[UTC + 5.5] Sri Jayawardenepura';
- const tzValue = 'Asia/Colombo';
-
- expect($inputEl.val()).toBe('Etc/UTC');
-
- $(`${tzListSel}:contains('${tzStr}')`, $wrapper).trigger('click');
-
- const val = $inputEl.val();
-
- expect(val).toBe(tzValue);
- expect(val).not.toBe('Etc/UTC');
- });
-
- it('will format data array of timezones into a list of offsets', () => {
- initTimezoneDropdown();
-
- const data = $dropdownEl.data('data');
- const formatted = $wrapper.find(tzListSel).text();
-
- data.forEach((item) => {
- expect(formatted).toContain(formatTimezone(item));
- });
- });
-
- describe('when `allowEmpty` property is `false`', () => {
- beforeEach(() => {
- initTimezoneDropdown();
- });
-
- it('will default the timezone to UTC', () => {
- const tz = $inputEl.val();
-
- expect(tz).toBe('Etc/UTC');
- });
- });
-
- describe('when `allowEmpty` property is `true`', () => {
- beforeEach(() => {
- initTimezoneDropdown({
- allowEmpty: true,
- });
- });
-
- it('will default the value of the input to an empty string', () => {
- expect($inputEl.val()).toBe('');
- });
- });
- });
-
- describe('without dropdown loaded', () => {
- beforeEach(() => {
- loadHTMLFixture('pipeline_schedules/edit.html');
- $wrapper = $('.dropdown');
- $inputEl = $('#schedule_cron_timezone');
- $dropdownEl = $('.js-timezone-dropdown');
- });
-
- it('will populate the list of UTC offsets after the dropdown is loaded', () => {
- expect($wrapper.find(tzListSel).length).toEqual(0);
-
- initTimezoneDropdown();
-
- expect($wrapper.find(tzListSel).length).toEqual($($dropdownEl).data('data').length);
- });
-
- it('will call a provided handler when a new timezone is selected', () => {
- const onSelectTimezone = jest.fn();
-
- initTimezoneDropdown({ onSelectTimezone });
-
- $wrapper.find(tzListSel).first().trigger('click');
-
- expect(onSelectTimezone).toHaveBeenCalled();
- });
-
- it('will correctly set the dropdown label if a timezone identifier is set on the inputEl', () => {
- $inputEl.val('America/St_Johns');
-
- initTimezoneDropdown({ displayFormat: (selectedItem) => formatTimezone(selectedItem) });
-
- expect(findDropdownToggleText().html()).toEqual('[UTC - 2.5] Newfoundland');
- });
-
- it('will call a provided `displayFormat` handler to format the dropdown value', () => {
- const displayFormat = jest.fn();
-
- initTimezoneDropdown({ displayFormat });
-
- $wrapper.find(tzListSel).first().trigger('click');
-
- expect(displayFormat).toHaveBeenCalled();
- });
- });
- });
-
describe('formatUtcOffset', () => {
it('will convert negative utc offsets in seconds to hours and minutes', () => {
expect(formatUtcOffset(-21600)).toEqual('- 6');
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 ed7d4ad269e..b202a148306 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
@@ -137,6 +137,8 @@ describe('Settings Panel', () => {
const findConfirmDangerButton = () => wrapper.findComponent(ConfirmDanger);
const findEnvironmentsSettings = () => wrapper.findComponent({ ref: 'environments-settings' });
const findFeatureFlagsSettings = () => wrapper.findComponent({ ref: 'feature-flags-settings' });
+ const findInfrastructureSettings = () =>
+ wrapper.findComponent({ ref: 'infrastructure-settings' });
const findReleasesSettings = () => wrapper.findComponent({ ref: 'environments-settings' });
const findMonitorSettings = () => wrapper.findComponent({ ref: 'monitor-settings' });
@@ -841,6 +843,24 @@ describe('Settings Panel', () => {
});
});
});
+ describe('Infrastructure', () => {
+ describe('with feature flag', () => {
+ it('should show the infrastructure toggle', () => {
+ wrapper = mountComponent({
+ glFeatures: { splitOperationsVisibilityPermissions: true },
+ });
+
+ expect(findInfrastructureSettings().exists()).toBe(true);
+ });
+ });
+ describe('without feature flag', () => {
+ it('should not show the infrastructure toggle', () => {
+ wrapper = mountComponent({});
+
+ expect(findInfrastructureSettings().exists()).toBe(false);
+ });
+ });
+ });
describe('Releases', () => {
describe('with feature flag', () => {
it('should show the releases toggle', () => {
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 0f947e84e0f..67d0fbdd9d1 100644
--- a/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
+++ b/spec/frontend/pages/shared/wikis/components/wiki_form_spec.js
@@ -116,7 +116,7 @@ describe('WikiForm', () => {
renderMarkdownPath: pageInfoPersisted.markdownPreviewPath,
markdownDocsPath: pageInfoPersisted.markdownHelpPath,
uploadsPath: pageInfoPersisted.uploadsPath,
- initOnAutofocus: pageInfoPersisted.persisted,
+ autofocus: pageInfoPersisted.persisted,
formFieldId: 'wiki_content',
formFieldName: 'wiki[content]',
}),
diff --git a/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js b/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js
index 3b79739630d..27707f8b01a 100644
--- a/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js
+++ b/spec/frontend/pipeline_editor/components/pipeline_editor_tabs_spec.js
@@ -253,7 +253,7 @@ describe('Pipeline editor tabs component', () => {
appStatus | editor | viz | validate | merged
${undefined} | ${true} | ${true} | ${true} | ${true}
${EDITOR_APP_STATUS_EMPTY} | ${true} | ${false} | ${true} | ${false}
- ${EDITOR_APP_STATUS_INVALID} | ${true} | ${false} | ${true} | ${false}
+ ${EDITOR_APP_STATUS_INVALID} | ${true} | ${false} | ${true} | ${true}
${EDITOR_APP_STATUS_VALID} | ${true} | ${true} | ${true} | ${true}
`(
'when status is $appStatus, we show - editor:$editor | viz:$viz | validate:$validate | merged:$merged',
diff --git a/spec/frontend/pipeline_schedules/components/pipeline_schedules_form_spec.js b/spec/frontend/pipeline_schedules/components/pipeline_schedules_form_spec.js
deleted file mode 100644
index 4b5a9611251..00000000000
--- a/spec/frontend/pipeline_schedules/components/pipeline_schedules_form_spec.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { GlForm } from '@gitlab/ui';
-import PipelineSchedulesForm from '~/pipeline_schedules/components/pipeline_schedules_form.vue';
-
-describe('Pipeline schedules form', () => {
- let wrapper;
-
- const createComponent = () => {
- wrapper = shallowMount(PipelineSchedulesForm);
- };
-
- const findForm = () => wrapper.findComponent(GlForm);
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('displays form', () => {
- expect(findForm().exists()).toBe(true);
- });
-});
diff --git a/spec/frontend/pipeline_schedules/components/pipeline_schedules_spec.js b/spec/frontend/pipeline_schedules/components/pipeline_schedules_spec.js
deleted file mode 100644
index cce8f480928..00000000000
--- a/spec/frontend/pipeline_schedules/components/pipeline_schedules_spec.js
+++ /dev/null
@@ -1,161 +0,0 @@
-import { GlAlert, GlLoadingIcon, GlModal } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import PipelineSchedules from '~/pipeline_schedules/components/pipeline_schedules.vue';
-import PipelineSchedulesTable from '~/pipeline_schedules/components/table/pipeline_schedules_table.vue';
-import deletePipelineScheduleMutation from '~/pipeline_schedules/graphql/mutations/delete_pipeline_schedule.mutation.graphql';
-import getPipelineSchedulesQuery from '~/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql';
-import {
- mockGetPipelineSchedulesGraphQLResponse,
- mockPipelineScheduleNodes,
- deleteMutationResponse,
-} from '../mock_data';
-
-Vue.use(VueApollo);
-
-describe('Pipeline schedules app', () => {
- let wrapper;
-
- const successHandler = jest.fn().mockResolvedValue(mockGetPipelineSchedulesGraphQLResponse);
- const failedHandler = jest.fn().mockRejectedValue(new Error('GraphQL error'));
-
- const deleteMutationHandlerSuccess = jest.fn().mockResolvedValue(deleteMutationResponse);
- const deleteMutationHandlerFailed = jest.fn().mockRejectedValue(new Error('GraphQL error'));
-
- const createMockApolloProvider = (
- requestHandlers = [[getPipelineSchedulesQuery, successHandler]],
- ) => {
- return createMockApollo(requestHandlers);
- };
-
- const createComponent = (requestHandlers) => {
- wrapper = shallowMount(PipelineSchedules, {
- provide: {
- fullPath: 'gitlab-org/gitlab',
- },
- apolloProvider: createMockApolloProvider(requestHandlers),
- });
- };
-
- const findTable = () => wrapper.findComponent(PipelineSchedulesTable);
- const findAlert = () => wrapper.findComponent(GlAlert);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findModal = () => wrapper.findComponent(GlModal);
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('displays table', async () => {
- createComponent();
-
- await waitForPromises();
-
- expect(findTable().exists()).toBe(true);
- expect(findAlert().exists()).toBe(false);
- });
-
- it('fetches query and passes an array of pipeline schedules', async () => {
- createComponent();
-
- expect(successHandler).toHaveBeenCalled();
-
- await waitForPromises();
-
- expect(findTable().props('schedules')).toEqual(mockPipelineScheduleNodes);
- });
-
- it('handles loading state', async () => {
- createComponent();
-
- expect(findLoadingIcon().exists()).toBe(true);
-
- await waitForPromises();
-
- expect(findLoadingIcon().exists()).toBe(false);
- });
-
- it('shows query error alert', async () => {
- createComponent([[getPipelineSchedulesQuery, failedHandler]]);
-
- await waitForPromises();
-
- expect(findAlert().text()).toBe('There was a problem fetching pipeline schedules.');
- });
-
- it('shows delete mutation error alert', async () => {
- createComponent([
- [getPipelineSchedulesQuery, successHandler],
- [deletePipelineScheduleMutation, deleteMutationHandlerFailed],
- ]);
-
- await waitForPromises();
-
- findModal().vm.$emit('primary');
-
- await waitForPromises();
-
- expect(findAlert().text()).toBe('There was a problem deleting the pipeline schedule.');
- });
-
- it('deletes pipeline schedule and refetches query', async () => {
- createComponent([
- [getPipelineSchedulesQuery, successHandler],
- [deletePipelineScheduleMutation, deleteMutationHandlerSuccess],
- ]);
-
- jest.spyOn(wrapper.vm.$apollo.queries.schedules, 'refetch');
-
- await waitForPromises();
-
- const scheduleId = mockPipelineScheduleNodes[0].id;
-
- findTable().vm.$emit('showDeleteModal', scheduleId);
-
- expect(wrapper.vm.$apollo.queries.schedules.refetch).not.toHaveBeenCalled();
-
- findModal().vm.$emit('primary');
-
- await waitForPromises();
-
- expect(deleteMutationHandlerSuccess).toHaveBeenCalledWith({
- id: scheduleId,
- });
- expect(wrapper.vm.$apollo.queries.schedules.refetch).toHaveBeenCalled();
- });
-
- it('modal should be visible after event', async () => {
- createComponent();
-
- await waitForPromises();
-
- expect(findModal().props('visible')).toBe(false);
-
- findTable().vm.$emit('showDeleteModal', mockPipelineScheduleNodes[0].id);
-
- await nextTick();
-
- expect(findModal().props('visible')).toBe(true);
- });
-
- it('modal should be hidden', async () => {
- createComponent();
-
- await waitForPromises();
-
- findTable().vm.$emit('showDeleteModal', mockPipelineScheduleNodes[0].id);
-
- await nextTick();
-
- expect(findModal().props('visible')).toBe(true);
-
- findModal().vm.$emit('hide');
-
- await nextTick();
-
- expect(findModal().props('visible')).toBe(false);
- });
-});
diff --git a/spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js b/spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js
deleted file mode 100644
index ecc1bdeb679..00000000000
--- a/spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_actions_spec.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import { GlButton } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import PipelineScheduleActions from '~/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue';
-import { mockPipelineScheduleNodes, mockPipelineScheduleAsGuestNodes } from '../../../mock_data';
-
-describe('Pipeline schedule actions', () => {
- let wrapper;
-
- const defaultProps = {
- schedule: mockPipelineScheduleNodes[0],
- };
-
- const createComponent = (props = defaultProps) => {
- wrapper = shallowMountExtended(PipelineScheduleActions, {
- propsData: {
- ...props,
- },
- });
- };
-
- const findAllButtons = () => wrapper.findAllComponents(GlButton);
- const findDeleteBtn = () => wrapper.findByTestId('delete-pipeline-schedule-btn');
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('displays action buttons', () => {
- createComponent();
-
- expect(findAllButtons()).toHaveLength(3);
- });
-
- it('does not display action buttons', () => {
- createComponent({ schedule: mockPipelineScheduleAsGuestNodes[0] });
-
- expect(findAllButtons()).toHaveLength(0);
- });
-
- it('delete button emits showDeleteModal event and schedule id', () => {
- createComponent();
-
- findDeleteBtn().vm.$emit('click');
-
- expect(wrapper.emitted()).toEqual({
- showDeleteModal: [[mockPipelineScheduleNodes[0].id]],
- });
- });
-});
diff --git a/spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js b/spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js
deleted file mode 100644
index 5a47b24232f..00000000000
--- a/spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline_spec.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
-import PipelineScheduleLastPipeline from '~/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline.vue';
-import { mockPipelineScheduleNodes } from '../../../mock_data';
-
-describe('Pipeline schedule last pipeline', () => {
- let wrapper;
-
- const defaultProps = {
- schedule: mockPipelineScheduleNodes[2],
- };
-
- const createComponent = (props = defaultProps) => {
- wrapper = shallowMountExtended(PipelineScheduleLastPipeline, {
- propsData: {
- ...props,
- },
- });
- };
-
- const findCIBadge = () => wrapper.findComponent(CiBadge);
- const findStatusText = () => wrapper.findByTestId('pipeline-schedule-status-text');
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('displays pipeline status', () => {
- createComponent();
-
- expect(findCIBadge().exists()).toBe(true);
- expect(findCIBadge().props('status')).toBe(defaultProps.schedule.lastPipeline.detailedStatus);
- expect(findStatusText().exists()).toBe(false);
- });
-
- it('displays "none" status text', () => {
- createComponent({ schedule: mockPipelineScheduleNodes[0] });
-
- expect(findStatusText().text()).toBe('None');
- expect(findCIBadge().exists()).toBe(false);
- });
-});
diff --git a/spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js b/spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js
deleted file mode 100644
index b1bdc1e91a0..00000000000
--- a/spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_next_run_spec.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import PipelineScheduleNextRun from '~/pipeline_schedules/components/table/cells/pipeline_schedule_next_run.vue';
-import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import { mockPipelineScheduleNodes } from '../../../mock_data';
-
-describe('Pipeline schedule next run', () => {
- let wrapper;
-
- const defaultProps = {
- schedule: mockPipelineScheduleNodes[0],
- };
-
- const createComponent = (props = defaultProps) => {
- wrapper = shallowMountExtended(PipelineScheduleNextRun, {
- propsData: {
- ...props,
- },
- });
- };
-
- const findTimeAgo = () => wrapper.findComponent(TimeAgoTooltip);
- const findInactive = () => wrapper.findByTestId('pipeline-schedule-inactive');
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('displays time ago', () => {
- createComponent();
-
- expect(findTimeAgo().exists()).toBe(true);
- expect(findInactive().exists()).toBe(false);
- expect(findTimeAgo().props('time')).toBe(defaultProps.schedule.realNextRun);
- });
-
- it('displays inactive state', () => {
- const inactiveSchedule = mockPipelineScheduleNodes[1];
- createComponent({ schedule: inactiveSchedule });
-
- expect(findInactive().text()).toBe('Inactive');
- expect(findTimeAgo().exists()).toBe(false);
- });
-});
diff --git a/spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js b/spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js
deleted file mode 100644
index 3ab04958f5e..00000000000
--- a/spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_owner_spec.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import { GlAvatar, GlAvatarLink } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import PipelineScheduleOwner from '~/pipeline_schedules/components/table/cells/pipeline_schedule_owner.vue';
-import { mockPipelineScheduleNodes } from '../../../mock_data';
-
-describe('Pipeline schedule owner', () => {
- let wrapper;
-
- const defaultProps = {
- schedule: mockPipelineScheduleNodes[0],
- };
-
- const createComponent = (props = defaultProps) => {
- wrapper = shallowMount(PipelineScheduleOwner, {
- propsData: {
- ...props,
- },
- });
- };
-
- const findAvatar = () => wrapper.findComponent(GlAvatar);
- const findAvatarLink = () => wrapper.findComponent(GlAvatarLink);
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('displays avatar', () => {
- expect(findAvatar().exists()).toBe(true);
- expect(findAvatar().props('src')).toBe(defaultProps.schedule.owner.avatarUrl);
- });
-
- it('avatar links to user', () => {
- expect(findAvatarLink().attributes('href')).toBe(defaultProps.schedule.owner.webPath);
- });
-});
diff --git a/spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js b/spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js
deleted file mode 100644
index 6817e58790b..00000000000
--- a/spec/frontend/pipeline_schedules/components/table/cells/pipeline_schedule_target_spec.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import { GlIcon, GlLink } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import PipelineScheduleTarget from '~/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue';
-import { mockPipelineScheduleNodes } from '../../../mock_data';
-
-describe('Pipeline schedule target', () => {
- let wrapper;
-
- const defaultProps = {
- schedule: mockPipelineScheduleNodes[0],
- };
-
- const createComponent = (props = defaultProps) => {
- wrapper = shallowMount(PipelineScheduleTarget, {
- propsData: {
- ...props,
- },
- });
- };
-
- const findIcon = () => wrapper.findComponent(GlIcon);
- const findLink = () => wrapper.findComponent(GlLink);
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('displays icon', () => {
- expect(findIcon().exists()).toBe(true);
- expect(findIcon().props('name')).toBe('fork');
- });
-
- it('displays ref link', () => {
- expect(findLink().attributes('href')).toBe(defaultProps.schedule.refPath);
- expect(findLink().text()).toBe(defaultProps.schedule.refForDisplay);
- });
-});
diff --git a/spec/frontend/pipeline_schedules/components/table/pipeline_schedules_table_spec.js b/spec/frontend/pipeline_schedules/components/table/pipeline_schedules_table_spec.js
deleted file mode 100644
index 914897946ee..00000000000
--- a/spec/frontend/pipeline_schedules/components/table/pipeline_schedules_table_spec.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { GlTableLite } from '@gitlab/ui';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import PipelineSchedulesTable from '~/pipeline_schedules/components/table/pipeline_schedules_table.vue';
-import { mockPipelineScheduleNodes } from '../../mock_data';
-
-describe('Pipeline schedules table', () => {
- let wrapper;
-
- const defaultProps = {
- schedules: mockPipelineScheduleNodes,
- };
-
- const createComponent = (props = defaultProps) => {
- wrapper = mountExtended(PipelineSchedulesTable, {
- propsData: {
- ...props,
- },
- });
- };
-
- const findTable = () => wrapper.findComponent(GlTableLite);
- const findScheduleDescription = () => wrapper.findByTestId('pipeline-schedule-description');
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('displays table', () => {
- expect(findTable().exists()).toBe(true);
- });
-
- it('displays schedule description', () => {
- expect(findScheduleDescription().text()).toBe('pipeline schedule');
- });
-});
diff --git a/spec/frontend/pipeline_schedules/components/take_ownership_modal_spec.js b/spec/frontend/pipeline_schedules/components/take_ownership_modal_spec.js
deleted file mode 100644
index d787611fe8f..00000000000
--- a/spec/frontend/pipeline_schedules/components/take_ownership_modal_spec.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import { GlModal } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import TakeOwnershipModal from '~/pipeline_schedules/components/take_ownership_modal.vue';
-
-describe('Take ownership modal', () => {
- let wrapper;
- const url = `/root/job-log-tester/-/pipeline_schedules/3/take_ownership`;
-
- const createComponent = (props = {}) => {
- wrapper = shallowMountExtended(TakeOwnershipModal, {
- propsData: {
- ownershipUrl: url,
- ...props,
- },
- });
- };
-
- const findModal = () => wrapper.findComponent(GlModal);
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('has a primary action set to a url and a post data-method', () => {
- const actionPrimary = findModal().props('actionPrimary');
-
- expect(actionPrimary.attributes).toEqual(
- expect.objectContaining([
- {
- category: 'primary',
- variant: 'confirm',
- href: url,
- 'data-method': 'post',
- },
- ]),
- );
- });
-
- it('shows a take ownership message', () => {
- expect(findModal().text()).toBe(
- 'Only the owner of a pipeline schedule can make changes to it. Do you want to take ownership of this schedule?',
- );
- });
-
- it('emits the cancel event when clicking on cancel', async () => {
- findModal().vm.$emit('cancel');
-
- expect(findModal().emitted('cancel')).toHaveLength(1);
- });
-});
diff --git a/spec/frontend/pipeline_schedules/mock_data.js b/spec/frontend/pipeline_schedules/mock_data.js
deleted file mode 100644
index 0a60998d8fb..00000000000
--- a/spec/frontend/pipeline_schedules/mock_data.js
+++ /dev/null
@@ -1,35 +0,0 @@
-// Fixture located at spec/frontend/fixtures/pipeline_schedules.rb
-import mockGetPipelineSchedulesGraphQLResponse from 'test_fixtures/graphql/pipeline_schedules/get_pipeline_schedules.query.graphql.json';
-import mockGetPipelineSchedulesAsGuestGraphQLResponse from 'test_fixtures/graphql/pipeline_schedules/get_pipeline_schedules.query.graphql.as_guest.json';
-
-const {
- data: {
- project: {
- pipelineSchedules: { nodes },
- },
- },
-} = mockGetPipelineSchedulesGraphQLResponse;
-
-const {
- data: {
- project: {
- pipelineSchedules: { nodes: guestNodes },
- },
- },
-} = mockGetPipelineSchedulesAsGuestGraphQLResponse;
-
-export const mockPipelineScheduleNodes = nodes;
-
-export const mockPipelineScheduleAsGuestNodes = guestNodes;
-
-export const deleteMutationResponse = {
- data: {
- pipelineScheduleDelete: {
- clientMutationId: null,
- errors: [],
- __typename: 'PipelineScheduleDeletePayload',
- },
- },
-};
-
-export { mockGetPipelineSchedulesGraphQLResponse };
diff --git a/spec/frontend/pipelines/components/pipeline_tabs_spec.js b/spec/frontend/pipelines/components/pipeline_tabs_spec.js
index 3680d9d62c7..c2cb95d4320 100644
--- a/spec/frontend/pipelines/components/pipeline_tabs_spec.js
+++ b/spec/frontend/pipelines/components/pipeline_tabs_spec.js
@@ -2,10 +2,6 @@ import { shallowMount } from '@vue/test-utils';
import { GlTab } from '@gitlab/ui';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import PipelineTabs from '~/pipelines/components/pipeline_tabs.vue';
-import PipelineGraphWrapper from '~/pipelines/components/graph/graph_component_wrapper.vue';
-import Dag from '~/pipelines/components/dag/dag.vue';
-import JobsApp from '~/pipelines/components/jobs/jobs_app.vue';
-import TestReports from '~/pipelines/components/test_reports/test_reports.vue';
describe('The Pipeline Tabs', () => {
let wrapper;
@@ -16,12 +12,6 @@ describe('The Pipeline Tabs', () => {
const findPipelineTab = () => wrapper.findByTestId('pipeline-tab');
const findTestsTab = () => wrapper.findByTestId('tests-tab');
- const findDagApp = () => wrapper.findComponent(Dag);
- const findFailedJobsApp = () => wrapper.findComponent(JobsApp);
- const findJobsApp = () => wrapper.findComponent(JobsApp);
- const findPipelineApp = () => wrapper.findComponent(PipelineGraphWrapper);
- const findTestsApp = () => wrapper.findComponent(TestReports);
-
const findFailedJobsBadge = () => wrapper.findByTestId('failed-builds-counter');
const findJobsBadge = () => wrapper.findByTestId('builds-counter');
const findTestsBadge = () => wrapper.findByTestId('tests-counter');
@@ -43,6 +33,7 @@ describe('The Pipeline Tabs', () => {
},
stubs: {
GlTab,
+ RouterView: true,
},
}),
);
@@ -54,17 +45,16 @@ describe('The Pipeline Tabs', () => {
describe('Tabs', () => {
it.each`
- tabName | tabComponent | appComponent
- ${'Pipeline'} | ${findPipelineTab} | ${findPipelineApp}
- ${'Dag'} | ${findDagTab} | ${findDagApp}
- ${'Jobs'} | ${findJobsTab} | ${findJobsApp}
- ${'Failed Jobs'} | ${findFailedJobsTab} | ${findFailedJobsApp}
- ${'Tests'} | ${findTestsTab} | ${findTestsApp}
- `('shows $tabName tab with its associated component', ({ appComponent, tabComponent }) => {
+ tabName | tabComponent
+ ${'Pipeline'} | ${findPipelineTab}
+ ${'Dag'} | ${findDagTab}
+ ${'Jobs'} | ${findJobsTab}
+ ${'Failed Jobs'} | ${findFailedJobsTab}
+ ${'Tests'} | ${findTestsTab}
+ `('shows $tabName tab', ({ tabComponent }) => {
createComponent();
expect(tabComponent().exists()).toBe(true);
- expect(appComponent().exists()).toBe(true);
});
describe('with no failed jobs', () => {
diff --git a/spec/frontend/pipelines/mock_data.js b/spec/frontend/pipelines/mock_data.js
index 57d1511d859..36bce65dd56 100644
--- a/spec/frontend/pipelines/mock_data.js
+++ b/spec/frontend/pipelines/mock_data.js
@@ -730,6 +730,7 @@ export const mockPipelineTag = () => {
},
active: false,
source: 'push',
+ name: 'Build pipeline',
created_at: '2022-02-02T15:39:04.012Z',
updated_at: '2022-02-02T15:40:59.573Z',
path: '/root/mr-widgets/-/pipelines/311',
@@ -835,6 +836,7 @@ export const mockPipelineTag = () => {
],
duration: 93,
finished_at: '2022-02-02T15:40:59.384Z',
+ event_type_name: 'Pipeline',
name: 'Pipeline',
manual_actions: [],
scheduled_actions: [],
@@ -954,6 +956,7 @@ export const mockPipelineBranch = () => {
},
active: false,
source: 'push',
+ name: 'Build pipeline',
created_at: '2022-01-14T17:40:27.866Z',
updated_at: '2022-01-14T18:02:35.850Z',
path: '/root/mr-widgets/-/pipelines/268',
@@ -1041,6 +1044,7 @@ export const mockPipelineBranch = () => {
],
duration: 75,
finished_at: '2022-01-14T18:02:35.842Z',
+ event_type_name: 'Pipeline',
name: 'Pipeline',
manual_actions: [],
scheduled_actions: [],
diff --git a/spec/frontend/pipelines/pipeline_graph/utils_spec.js b/spec/frontend/pipelines/pipeline_graph/utils_spec.js
index d6b13da3c3a..41b020189d0 100644
--- a/spec/frontend/pipelines/pipeline_graph/utils_spec.js
+++ b/spec/frontend/pipelines/pipeline_graph/utils_spec.js
@@ -1,5 +1,5 @@
import { createJobsHash, generateJobNeedsDict, getPipelineDefaultTab } from '~/pipelines/utils';
-import { TAB_QUERY_PARAM, validPipelineTabNames } from '~/pipelines/constants';
+import { validPipelineTabNames } from '~/pipelines/constants';
describe('utils functions', () => {
const jobName1 = 'build_1';
@@ -173,18 +173,25 @@ describe('utils functions', () => {
describe('getPipelineDefaultTab', () => {
const baseUrl = 'http://gitlab.com/user/multi-projects-small/-/pipelines/332/';
- it('returns null if there was no `tab` params', () => {
+ it('returns null if there is only the base url', () => {
expect(getPipelineDefaultTab(baseUrl)).toBe(null);
});
- it('returns null if there was no valid tab param', () => {
- expect(getPipelineDefaultTab(`${baseUrl}?${TAB_QUERY_PARAM}=invalid`)).toBe(null);
+ it('returns null if there was no valid last url part', () => {
+ expect(getPipelineDefaultTab(`${baseUrl}something`)).toBe(null);
});
it('returns the correct tab name if present', () => {
validPipelineTabNames.forEach((tabName) => {
- expect(getPipelineDefaultTab(`${baseUrl}?${TAB_QUERY_PARAM}=${tabName}`)).toBe(tabName);
+ expect(getPipelineDefaultTab(`${baseUrl}${tabName}`)).toBe(tabName);
});
});
+
+ it('returns the right value even with query params', () => {
+ const [tabName] = validPipelineTabNames;
+ expect(getPipelineDefaultTab(`${baseUrl}${tabName}?query="something"&query2="else"`)).toBe(
+ tabName,
+ );
+ });
});
});
diff --git a/spec/frontend/pipelines/pipeline_tabs_spec.js b/spec/frontend/pipelines/pipeline_tabs_spec.js
index b184ce31d20..099748a5cca 100644
--- a/spec/frontend/pipelines/pipeline_tabs_spec.js
+++ b/spec/frontend/pipelines/pipeline_tabs_spec.js
@@ -1,9 +1,7 @@
-import { createAppOptions, createPipelineTabs } from '~/pipelines/pipeline_tabs';
-import { updateHistory } from '~/lib/utils/url_utility';
+import { createAppOptions } from '~/pipelines/pipeline_tabs';
jest.mock('~/lib/utils/url_utility', () => ({
removeParams: () => 'gitlab.com',
- updateHistory: jest.fn(),
joinPaths: () => {},
setUrlFragment: () => {},
}));
@@ -64,32 +62,4 @@ describe('~/pipelines/pipeline_tabs.js', () => {
expect(createAppOptions('foo', null)).toBe(null);
});
});
-
- describe('createPipelineTabs', () => {
- const title = 'Pipeline Tabs';
-
- beforeAll(() => {
- document.title = title;
- });
-
- afterAll(() => {
- document.title = '';
- });
-
- it('calls `updateHistory` with correct params', () => {
- createPipelineTabs({});
-
- expect(updateHistory).toHaveBeenCalledWith({
- title,
- url: 'gitlab.com',
- replace: true,
- });
- });
-
- it("returns early if options aren't provided", () => {
- createPipelineTabs();
-
- expect(updateHistory).not.toHaveBeenCalled();
- });
- });
});
diff --git a/spec/frontend/pipelines/pipeline_url_spec.js b/spec/frontend/pipelines/pipeline_url_spec.js
index 1d66607e72b..c62898f0c83 100644
--- a/spec/frontend/pipelines/pipeline_url_spec.js
+++ b/spec/frontend/pipelines/pipeline_url_spec.js
@@ -1,3 +1,4 @@
+import { merge } from 'lodash';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import PipelineUrlComponent from '~/pipelines/components/pipelines_list/pipeline_url.vue';
@@ -20,6 +21,7 @@ describe('Pipeline Url Component', () => {
const findCommitRefName = () => wrapper.findByTestId('commit-ref-name');
const findCommitTitleContainer = () => wrapper.findByTestId('commit-title-container');
+ const findPipelineNameContainer = () => wrapper.findByTestId('pipeline-name-container');
const findCommitTitle = (commitWrapper) => commitWrapper.find('[data-testid="commit-title"]');
const defaultProps = mockPipeline(projectPath);
@@ -51,7 +53,16 @@ describe('Pipeline Url Component', () => {
expect(findPipelineUrlLink().text()).toBe('#1');
});
- it('should render the commit title, commit reference and commit-short-sha', () => {
+ it('should render the pipeline name instead of commit title', () => {
+ createComponent(merge(mockPipeline(projectPath), { pipeline: { name: 'Build pipeline' } }));
+
+ expect(findCommitTitleContainer().exists()).toBe(false);
+ expect(findPipelineNameContainer().exists()).toBe(true);
+ expect(findRefName().exists()).toBe(true);
+ expect(findCommitShortSha().exists()).toBe(true);
+ });
+
+ it('should render the commit title when pipeline has no name', () => {
createComponent();
const commitWrapper = findCommitTitleContainer();
@@ -59,6 +70,7 @@ describe('Pipeline Url Component', () => {
expect(findCommitTitle(commitWrapper).exists()).toBe(true);
expect(findRefName().exists()).toBe(true);
expect(findCommitShortSha().exists()).toBe(true);
+ expect(findPipelineNameContainer().exists()).toBe(false);
});
describe('commit user avatar', () => {
@@ -142,7 +154,7 @@ describe('Pipeline Url Component', () => {
});
it('tracks commit title click', () => {
- createComponent(mockPipelineBranch());
+ createComponent(merge(mockPipelineBranch(), { pipeline: { name: null } }));
findCommitTitle(findCommitTitleContainer()).vm.$emit('click');
diff --git a/spec/frontend/pipelines/pipelines_actions_spec.js b/spec/frontend/pipelines/pipelines_actions_spec.js
index 26e61efc4f6..a70ef10aa7b 100644
--- a/spec/frontend/pipelines/pipelines_actions_spec.js
+++ b/spec/frontend/pipelines/pipelines_actions_spec.js
@@ -13,11 +13,7 @@ import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
import { TRACKING_CATEGORIES } from '~/pipelines/constants';
jest.mock('~/flash');
-jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal', () => {
- return {
- confirmAction: jest.fn(),
- };
-});
+jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
describe('Pipelines Actions dropdown', () => {
let wrapper;
diff --git a/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap b/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap
index 736d149f06d..974650a2c7c 100644
--- a/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap
+++ b/spec/frontend/projects/components/__snapshots__/project_delete_button_spec.js.snap
@@ -19,6 +19,7 @@ exports[`Project remove modal initialized matches the snapshot 1`] = `
<gl-button-stub
buttontextclasses=""
category="primary"
+ data-qa-selector="delete_button"
icon=""
role="button"
size="medium"
@@ -102,6 +103,7 @@ exports[`Project remove modal initialized matches the snapshot 1`] = `
</p>
<gl-form-input-stub
+ data-qa-selector="confirm_name_field"
id="confirm_name_input"
name="confirm_name_input"
type="text"
diff --git a/spec/frontend/projects/components/shared/__snapshots__/delete_button_spec.js.snap b/spec/frontend/projects/components/shared/__snapshots__/delete_button_spec.js.snap
index 26495fbcf83..ac020fe6915 100644
--- a/spec/frontend/projects/components/shared/__snapshots__/delete_button_spec.js.snap
+++ b/spec/frontend/projects/components/shared/__snapshots__/delete_button_spec.js.snap
@@ -20,6 +20,7 @@ exports[`Project remove modal intialized matches the snapshot 1`] = `
<gl-button-stub
buttontextclasses=""
category="primary"
+ data-qa-selector="delete_button"
icon=""
role="button"
size="medium"
@@ -103,6 +104,7 @@ exports[`Project remove modal intialized matches the snapshot 1`] = `
</p>
<gl-form-input-stub
+ data-qa-selector="confirm_name_field"
id="confirm_name_input"
name="confirm_name_input"
type="text"
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 f50dd393174..16b4493c622 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
@@ -71,7 +71,7 @@ describe('New project push tip popover', () => {
it('displays a link to open the push command help page reference', () => {
expect(findHelpLink().attributes().href).toBe(
- `${workingWithProjectsHelpPath}#push-to-create-a-new-project`,
+ `${workingWithProjectsHelpPath}#create-a-new-project-with-git-push`,
);
});
});
diff --git a/spec/frontend/projects/pipelines/charts/components/app_spec.js b/spec/frontend/projects/pipelines/charts/components/app_spec.js
index e3aaf760d1e..d8876349c5e 100644
--- a/spec/frontend/projects/pipelines/charts/components/app_spec.js
+++ b/spec/frontend/projects/pipelines/charts/components/app_spec.js
@@ -8,6 +8,12 @@ import { mergeUrlParams, updateHistory, getParameterValues } from '~/lib/utils/u
import Component from '~/projects/pipelines/charts/components/app.vue';
import PipelineCharts from '~/projects/pipelines/charts/components/pipeline_charts.vue';
import API from '~/api';
+import { mockTracking } from 'helpers/tracking_helper';
+import {
+ SNOWPLOW_DATA_SOURCE,
+ SNOWPLOW_LABEL,
+ SNOWPLOW_SCHEMA,
+} from '~/projects/pipelines/charts/constants';
jest.mock('~/lib/utils/url_utility');
@@ -125,21 +131,59 @@ describe('ProjectsPipelinesChartsApp', () => {
});
describe('event tracking', () => {
- it.each`
- testId | event
- ${'pipelines-tab'} | ${'p_analytics_ci_cd_pipelines'}
- ${'deployment-frequency-tab'} | ${'p_analytics_ci_cd_deployment_frequency'}
- ${'lead-time-tab'} | ${'p_analytics_ci_cd_lead_time'}
- ${'time-to-restore-service-tab'} | ${'p_analytics_ci_cd_time_to_restore_service'}
- ${'change-failure-rate-tab'} | ${'p_analytics_ci_cd_change_failure_rate'}
- `('tracks the $event event when clicked', ({ testId, event }) => {
- jest.spyOn(API, 'trackRedisHllUserEvent');
+ describe('RedisHLL events', () => {
+ it.each`
+ testId | event
+ ${'pipelines-tab'} | ${'p_analytics_ci_cd_pipelines'}
+ ${'deployment-frequency-tab'} | ${'p_analytics_ci_cd_deployment_frequency'}
+ ${'lead-time-tab'} | ${'p_analytics_ci_cd_lead_time'}
+ ${'time-to-restore-service-tab'} | ${'p_analytics_ci_cd_time_to_restore_service'}
+ ${'change-failure-rate-tab'} | ${'p_analytics_ci_cd_change_failure_rate'}
+ `('tracks the $event event when clicked', ({ testId, event }) => {
+ const trackApiSpy = jest.spyOn(API, 'trackRedisHllUserEvent');
+
+ expect(trackApiSpy).not.toHaveBeenCalled();
+
+ wrapper.findByTestId(testId).vm.$emit('click');
+
+ expect(trackApiSpy).toHaveBeenCalledWith(event);
+ });
+ });
- expect(API.trackRedisHllUserEvent).not.toHaveBeenCalled();
+ describe('Snowplow events', () => {
+ it.each`
+ testId | event
+ ${'pipelines-tab'} | ${'p_analytics_ci_cd_pipelines'}
+ ${'deployment-frequency-tab'} | ${'p_analytics_ci_cd_deployment_frequency'}
+ ${'lead-time-tab'} | ${'p_analytics_ci_cd_lead_time'}
+ `('tracks the $event event when clicked', ({ testId, event }) => {
+ const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+
+ wrapper.findByTestId(testId).vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_tab', {
+ label: SNOWPLOW_LABEL,
+ context: {
+ schema: SNOWPLOW_SCHEMA,
+ data: {
+ event_name: event,
+ data_source: SNOWPLOW_DATA_SOURCE,
+ },
+ },
+ });
+ });
- wrapper.findByTestId(testId).vm.$emit('click');
+ it.each`
+ tab
+ ${'time-to-restore-service-tab'}
+ ${'change-failure-rate-tab'}
+ `('does not track when tab $tab is clicked', ({ tab }) => {
+ const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- expect(API.trackRedisHllUserEvent).toHaveBeenCalledWith(event);
+ wrapper.findByTestId(tab).vm.$emit('click');
+
+ expect(trackingSpy).not.toHaveBeenCalled();
+ });
});
});
});
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 bf4026b65db..27065a704e2 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
@@ -12,7 +12,11 @@ import {
import Protection from '~/projects/settings/branch_rules/components/view/protection.vue';
import branchRulesQuery from '~/projects/settings/branch_rules/queries/branch_rules_details.query.graphql';
import { sprintf } from '~/locale';
-import { branchProtectionsMockResponse } from './mock_data';
+import {
+ branchProtectionsMockResponse,
+ approvalRulesMock,
+ statusChecksRulesMock,
+} from './mock_data';
jest.mock('~/lib/utils/url_utility', () => ({
getParameterByName: jest.fn().mockReturnValue('main'),
@@ -34,6 +38,7 @@ describe('View branch rules', () => {
const projectPath = 'test/testing';
const protectedBranchesPath = 'protected/branches';
const approvalRulesPath = 'approval/rules';
+ const statusChecksPath = 'status/checks';
const branchProtectionsMockRequestHandler = jest
.fn()
.mockResolvedValue(branchProtectionsMockResponse);
@@ -43,7 +48,7 @@ describe('View branch rules', () => {
wrapper = shallowMountExtended(RuleView, {
apolloProvider: fakeApollo,
- provide: { projectPath, protectedBranchesPath, approvalRulesPath },
+ provide: { projectPath, protectedBranchesPath, approvalRulesPath, statusChecksPath },
});
await waitForPromises();
@@ -59,6 +64,7 @@ describe('View branch rules', () => {
const findBranchProtections = () => wrapper.findAllComponents(Protection);
const findForcePushTitle = () => wrapper.findByText(I18N.allowForcePushDescription);
const findApprovalsTitle = () => wrapper.findByText(I18N.approvalsTitle);
+ const findStatusChecksTitle = () => wrapper.findByText(I18N.statusChecksTitle);
it('gets the branch param from url and renders it in the view', () => {
expect(util.getParameterByName).toHaveBeenCalledWith('branch');
@@ -105,9 +111,21 @@ describe('View branch rules', () => {
expect(findApprovalsTitle().exists()).toBe(true);
expect(findBranchProtections().at(2).props()).toMatchObject({
- header: sprintf(I18N.approvalsHeader, { total: 0 }),
+ header: sprintf(I18N.approvalsHeader, { total: 3 }),
headerLinkHref: approvalRulesPath,
headerLinkTitle: I18N.manageApprovalsLinkTitle,
+ approvals: approvalRulesMock,
+ });
+ });
+
+ it('renders a branch protection component for status checks', () => {
+ expect(findStatusChecksTitle().exists()).toBe(true);
+
+ expect(findBranchProtections().at(3).props()).toMatchObject({
+ header: sprintf(I18N.statusChecksHeader, { total: 2 }),
+ headerLinkHref: statusChecksPath,
+ headerLinkTitle: I18N.statusChecksLinkTitle,
+ statusChecks: statusChecksRulesMock,
});
});
});
diff --git a/spec/frontend/projects/settings/branch_rules/components/view/mock_data.js b/spec/frontend/projects/settings/branch_rules/components/view/mock_data.js
index c3f573061da..c07d4673344 100644
--- a/spec/frontend/projects/settings/branch_rules/components/view/mock_data.js
+++ b/spec/frontend/projects/settings/branch_rules/components/view/mock_data.js
@@ -1,29 +1,34 @@
const usersMock = [
{
+ id: '123',
username: 'usr1',
webUrl: 'http://test.test/usr1',
name: 'User 1',
avatarUrl: 'http://test.test/avt1.png',
},
{
+ id: '456',
username: 'usr2',
webUrl: 'http://test.test/usr2',
name: 'User 2',
avatarUrl: 'http://test.test/avt2.png',
},
{
+ id: '789',
username: 'usr3',
webUrl: 'http://test.test/usr3',
name: 'User 3',
avatarUrl: 'http://test.test/avt3.png',
},
{
+ id: '987',
username: 'usr4',
webUrl: 'http://test.test/usr4',
name: 'User 4',
avatarUrl: 'http://test.test/avt4.png',
},
{
+ id: '654',
username: 'usr5',
webUrl: 'http://test.test/usr5',
name: 'User 5',
@@ -40,6 +45,22 @@ const approvalsRequired = 3;
const groupsMock = [{ name: 'test_group_1' }, { name: 'test_group_2' }];
+export const approvalRulesMock = [
+ {
+ __typename: 'ApprovalProjectRule',
+ id: '123',
+ name: 'test',
+ type: 'REGULAR',
+ eligibleApprovers: { nodes: usersMock },
+ approvalsRequired,
+ },
+];
+
+export const statusChecksRulesMock = [
+ { __typename: 'StatusCheckRule', id: '123', name: 'test', externalUrl: 'https://test.test' },
+ { __typename: 'StatusCheckRule', id: '456', name: 'test 2', externalUrl: 'https://test2.test2' },
+];
+
export const protectionPropsMock = {
header: 'Test protection',
headerLinkTitle: 'Test link title',
@@ -47,13 +68,8 @@ export const protectionPropsMock = {
roles: accessLevelsMock,
users: usersMock,
groups: groupsMock,
- approvals: [
- {
- name: 'test',
- eligibleApprovers: { nodes: usersMock },
- approvalsRequired,
- },
- ],
+ approvals: approvalRulesMock,
+ statusChecks: statusChecksRulesMock,
};
export const protectionRowPropsMock = {
@@ -61,6 +77,7 @@ export const protectionRowPropsMock = {
users: usersMock,
accessLevels: accessLevelsMock,
approvalsRequired,
+ statusCheckUrl: statusChecksRulesMock[0].externalUrl,
};
export const accessLevelsMockResponse = [
@@ -116,6 +133,14 @@ export const branchProtectionsMockResponse = {
edges: accessLevelsMockResponse,
},
},
+ approvalRules: {
+ __typename: 'ApprovalProjectRuleConnection',
+ nodes: approvalRulesMock,
+ },
+ externalStatusChecks: {
+ __typename: 'ExternalStatusCheckConnection',
+ nodes: statusChecksRulesMock,
+ },
},
{
__typename: 'BranchRule',
@@ -133,6 +158,14 @@ export const branchProtectionsMockResponse = {
edges: [],
},
},
+ approvalRules: {
+ __typename: 'ApprovalProjectRuleConnection',
+ nodes: [],
+ },
+ externalStatusChecks: {
+ __typename: 'ExternalStatusCheckConnection',
+ nodes: [],
+ },
},
],
},
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 b0a69bedd3e..a98b156f94e 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
@@ -27,6 +27,7 @@ describe('Branch rule protection row', () => {
const findAccessLevels = () => wrapper.findAllByTestId('access-level');
const findApprovalsRequired = () =>
wrapper.findByText(`${protectionRowPropsMock.approvalsRequired} approvals required`);
+ const findStatusChecksUrl = () => wrapper.findByText(protectionRowPropsMock.statusCheckUrl);
it('renders a title', () => {
expect(findTitle().exists()).toBe(true);
@@ -68,4 +69,8 @@ describe('Branch rule protection row', () => {
it('renders the number of approvals required', () => {
expect(findApprovalsRequired().exists()).toBe(true);
});
+
+ it('renders status checks URL', () => {
+ expect(findStatusChecksUrl().exists()).toBe(true);
+ });
});
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 e2fbb4f5bbb..caf967b4257 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
@@ -65,4 +65,15 @@ describe('Branch rule protection', () => {
approvalsRequired: approval.approvalsRequired,
});
});
+
+ it('renders a protection row for status checks', () => {
+ const statusCheck = protectionPropsMock.statusChecks[0];
+ expect(findProtectionRows().at(4).props()).toMatchObject({
+ title: statusCheck.name,
+ showDivider: false,
+ statusCheckUrl: statusCheck.externalUrl,
+ });
+
+ expect(findProtectionRows().at(5).props('showDivider')).toBe(true);
+ });
});
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 6e639f895a8..e091f3e25c3 100644
--- a/spec/frontend/projects/settings/components/transfer_project_form_spec.js
+++ b/spec/frontend/projects/settings/components/transfer_project_form_spec.js
@@ -1,18 +1,9 @@
-import Vue, { nextTick } from 'vue';
-import { GlAlert } from '@gitlab/ui';
-import VueApollo from 'vue-apollo';
-import currentUserNamespaceQueryResponse from 'test_fixtures/graphql/projects/settings/current_user_namespace.query.graphql.json';
import transferLocationsResponsePage1 from 'test_fixtures/api/projects/transfer_locations_page_1.json';
-import transferLocationsResponsePage2 from 'test_fixtures/api/projects/transfer_locations_page_2.json';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import TransferProjectForm from '~/projects/settings/components/transfer_project_form.vue';
-import NamespaceSelect from '~/vue_shared/components/namespace_select/namespace_select_deprecated.vue';
+import TransferLocations from '~/groups_projects/components/transfer_locations.vue';
import ConfirmDanger from '~/vue_shared/components/confirm_danger/confirm_danger.vue';
-import currentUserNamespaceQuery from '~/projects/settings/graphql/queries/current_user_namespace.query.graphql';
import { getTransferLocations } from '~/api/projects_api';
-import waitForPromises from 'helpers/wait_for_promises';
jest.mock('~/api/projects_api', () => ({
getTransferLocations: jest.fn(),
@@ -21,68 +12,36 @@ jest.mock('~/api/projects_api', () => ({
describe('Transfer project form', () => {
let wrapper;
- const projectId = '1';
+ const resourceId = '1';
const confirmButtonText = 'Confirm';
const confirmationPhrase = 'You must construct additional pylons!';
- Vue.use(VueApollo);
-
- const defaultQueryHandler = jest.fn().mockResolvedValue(currentUserNamespaceQueryResponse);
- const mockResolvedGetTransferLocations = ({
- data = transferLocationsResponsePage1,
- page = '1',
- nextPage = '2',
- prevPage = null,
- } = {}) => {
- getTransferLocations.mockResolvedValueOnce({
- data,
- headers: {
- 'x-per-page': '2',
- 'x-page': page,
- 'x-total': '4',
- 'x-total-pages': '2',
- 'x-next-page': nextPage,
- 'x-prev-page': prevPage,
- },
- });
- };
- const mockRejectedGetTransferLocations = () => {
- const error = new Error();
-
- getTransferLocations.mockRejectedValueOnce(error);
- };
-
- const createComponent = ({
- requestHandlers = [[currentUserNamespaceQuery, defaultQueryHandler]],
- } = {}) => {
+ const createComponent = () => {
wrapper = shallowMountExtended(TransferProjectForm, {
provide: {
- projectId,
+ resourceId,
},
propsData: {
confirmButtonText,
confirmationPhrase,
},
- apolloProvider: createMockApollo(requestHandlers),
});
};
- const findNamespaceSelect = () => wrapper.findComponent(NamespaceSelect);
- const showNamespaceSelect = async () => {
- findNamespaceSelect().vm.$emit('show');
- await waitForPromises();
- };
+ const findTransferLocations = () => wrapper.findComponent(TransferLocations);
const findConfirmDanger = () => wrapper.findComponent(ConfirmDanger);
- const findAlert = () => wrapper.findComponent(GlAlert);
afterEach(() => {
wrapper.destroy();
});
- it('renders the namespace selector', () => {
+ it('renders the namespace selector and passes `groupTransferLocationsApiMethod` prop', () => {
createComponent();
- expect(findNamespaceSelect().exists()).toBe(true);
+ expect(findTransferLocations().exists()).toBe(true);
+
+ findTransferLocations().props('groupTransferLocationsApiMethod')();
+ expect(getTransferLocations).toHaveBeenCalled();
});
it('renders the confirm button', () => {
@@ -100,220 +59,29 @@ describe('Transfer project form', () => {
describe('with a selected namespace', () => {
const [selectedItem] = transferLocationsResponsePage1;
- const arrange = async () => {
- mockResolvedGetTransferLocations();
+ beforeEach(() => {
createComponent();
- await showNamespaceSelect();
- findNamespaceSelect().vm.$emit('select', selectedItem);
- };
+ findTransferLocations().vm.$emit('input', selectedItem);
+ });
- it('emits the `selectNamespace` event when a namespace is selected', async () => {
- await arrange();
+ it('sets `value` prop on `TransferLocations` component', () => {
+ expect(findTransferLocations().props('value')).toEqual(selectedItem);
+ });
+ it('emits the `selectTransferLocation` event when a namespace is selected', async () => {
const args = [selectedItem.id];
- expect(wrapper.emitted('selectNamespace')).toEqual([args]);
+ expect(wrapper.emitted('selectTransferLocation')).toEqual([args]);
});
it('enables the confirm button', async () => {
- await arrange();
-
expect(findConfirmDanger().attributes('disabled')).toBeUndefined();
});
it('clicking the confirm button emits the `confirm` event', async () => {
- await arrange();
-
findConfirmDanger().vm.$emit('confirm');
expect(wrapper.emitted('confirm')).toBeDefined();
});
});
-
- describe('when `NamespaceSelect` is opened', () => {
- it('fetches user and group namespaces and passes correct props to `NamespaceSelect` component', async () => {
- mockResolvedGetTransferLocations();
- createComponent();
- await showNamespaceSelect();
-
- const { namespace } = currentUserNamespaceQueryResponse.data.currentUser;
-
- expect(findNamespaceSelect().props()).toMatchObject({
- userNamespaces: [
- {
- id: getIdFromGraphQLId(namespace.id),
- humanName: namespace.fullName,
- },
- ],
- groupNamespaces: transferLocationsResponsePage1.map(({ id, full_name: humanName }) => ({
- id,
- humanName,
- })),
- hasNextPageOfGroups: true,
- isLoading: false,
- isSearchLoading: false,
- shouldFilterNamespaces: false,
- });
- });
-
- describe('when namespaces have already been fetched', () => {
- beforeEach(async () => {
- mockResolvedGetTransferLocations();
- createComponent();
- await showNamespaceSelect();
- });
-
- it('does not fetch namespaces', async () => {
- getTransferLocations.mockClear();
- defaultQueryHandler.mockClear();
-
- await showNamespaceSelect();
-
- expect(getTransferLocations).not.toHaveBeenCalled();
- expect(defaultQueryHandler).not.toHaveBeenCalled();
- });
- });
-
- describe('when `getTransferLocations` API call fails', () => {
- it('displays error alert', async () => {
- mockRejectedGetTransferLocations();
- createComponent();
- await showNamespaceSelect();
-
- expect(findAlert().exists()).toBe(true);
- });
- });
-
- describe('when `currentUser` GraphQL query fails', () => {
- it('displays error alert', async () => {
- mockResolvedGetTransferLocations();
- const error = new Error();
- createComponent({
- requestHandlers: [[currentUserNamespaceQuery, jest.fn().mockRejectedValueOnce(error)]],
- });
- await showNamespaceSelect();
-
- expect(findAlert().exists()).toBe(true);
- });
- });
- });
-
- describe('when `search` event is fired', () => {
- const arrange = async () => {
- mockResolvedGetTransferLocations();
- createComponent();
- await showNamespaceSelect();
- mockResolvedGetTransferLocations();
- findNamespaceSelect().vm.$emit('search', 'foo');
- await nextTick();
- };
-
- it('sets `isSearchLoading` prop to `true`', async () => {
- await arrange();
-
- expect(findNamespaceSelect().props('isSearchLoading')).toBe(true);
- });
-
- it('passes `search` param to API call', async () => {
- await arrange();
-
- await waitForPromises();
-
- expect(getTransferLocations).toHaveBeenCalledWith(
- projectId,
- expect.objectContaining({ search: 'foo' }),
- );
- });
-
- describe('when `getTransferLocations` API call fails', () => {
- it('displays dismissible error alert', async () => {
- mockResolvedGetTransferLocations();
- createComponent();
- await showNamespaceSelect();
- mockRejectedGetTransferLocations();
- findNamespaceSelect().vm.$emit('search', 'foo');
- await waitForPromises();
-
- const alert = findAlert();
-
- expect(alert.exists()).toBe(true);
-
- alert.vm.$emit('dismiss');
- await nextTick();
-
- expect(alert.exists()).toBe(false);
- });
- });
- });
-
- describe('when `load-more-groups` event is fired', () => {
- const arrange = async () => {
- mockResolvedGetTransferLocations();
- createComponent();
- await showNamespaceSelect();
-
- mockResolvedGetTransferLocations({
- data: transferLocationsResponsePage2,
- page: '2',
- nextPage: null,
- prevPage: '1',
- });
-
- findNamespaceSelect().vm.$emit('load-more-groups');
- await nextTick();
- };
-
- it('sets `isLoading` prop to `true`', async () => {
- await arrange();
-
- expect(findNamespaceSelect().props('isLoading')).toBe(true);
- });
-
- it('passes `page` param to API call', async () => {
- await arrange();
-
- await waitForPromises();
-
- expect(getTransferLocations).toHaveBeenCalledWith(
- projectId,
- expect.objectContaining({ page: 2 }),
- );
- });
-
- it('updates `groupNamespaces` prop with new groups', async () => {
- await arrange();
-
- await waitForPromises();
-
- expect(findNamespaceSelect().props('groupNamespaces')).toMatchObject(
- [...transferLocationsResponsePage1, ...transferLocationsResponsePage2].map(
- ({ id, full_name: humanName }) => ({
- id,
- humanName,
- }),
- ),
- );
- });
-
- it('updates `hasNextPageOfGroups` prop', async () => {
- await arrange();
-
- await waitForPromises();
-
- expect(findNamespaceSelect().props('hasNextPageOfGroups')).toBe(false);
- });
-
- describe('when `getTransferLocations` API call fails', () => {
- it('displays error alert', async () => {
- mockResolvedGetTransferLocations();
- createComponent();
- await showNamespaceSelect();
- mockRejectedGetTransferLocations();
- findNamespaceSelect().vm.$emit('load-more-groups');
- await waitForPromises();
-
- expect(findAlert().exists()).toBe(true);
- });
- });
- });
});
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 4603436c40a..6369f04781f 100644
--- a/spec/frontend/projects/settings/repository/branch_rules/app_spec.js
+++ b/spec/frontend/projects/settings/repository/branch_rules/app_spec.js
@@ -52,6 +52,10 @@ describe('Branch rules app', () => {
expect(findAllBranchRules().at(0).props('name')).toBe(nodes[0].name);
+ expect(findAllBranchRules().at(0).props('branchProtection')).toEqual(nodes[0].branchProtection);
+
expect(findAllBranchRules().at(1).props('name')).toBe(nodes[1].name);
+
+ expect(findAllBranchRules().at(1).props('branchProtection')).toEqual(nodes[1].branchProtection);
});
});
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 2bc705f538b..2aa93fd0e28 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
@@ -2,7 +2,12 @@ import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import BranchRule, {
i18n,
} from '~/projects/settings/repository/branch_rules/components/branch_rule.vue';
-import { branchRuleProvideMock, branchRulePropsMock } from '../mock_data';
+import { sprintf, n__ } from '~/locale';
+import {
+ branchRuleProvideMock,
+ branchRulePropsMock,
+ branchRuleWithoutDetailsPropsMock,
+} from '../mock_data';
describe('Branch rule', () => {
let wrapper;
@@ -15,7 +20,6 @@ describe('Branch rule', () => {
};
const findDefaultBadge = () => wrapper.findByText(i18n.defaultLabel);
- const findProtectedBadge = () => wrapper.findByText(i18n.protectedLabel);
const findBranchName = () => wrapper.findByText(branchRulePropsMock.name);
const findProtectionDetailsList = () => wrapper.findByRole('list');
const findProtectionDetailsListItems = () => wrapper.findAllByRole('listitem');
@@ -28,33 +32,36 @@ describe('Branch rule', () => {
});
describe('badges', () => {
- it('renders both default and protected badges', () => {
+ it('renders default badge', () => {
expect(findDefaultBadge().exists()).toBe(true);
- expect(findProtectedBadge().exists()).toBe(true);
});
it('does not render default badge if isDefault is set to false', () => {
createComponent({ isDefault: false });
expect(findDefaultBadge().exists()).toBe(false);
});
-
- it('does not render protected badge if isProtected is set to false', () => {
- createComponent({ isProtected: false });
- expect(findProtectedBadge().exists()).toBe(false);
- });
});
- it('does not render the protection details list of no details are present', () => {
- createComponent({ approvalDetails: null });
+ it('does not render the protection details list if no details are present', () => {
+ createComponent(branchRuleWithoutDetailsPropsMock);
expect(findProtectionDetailsList().exists()).toBe(false);
});
it('renders the protection details list items', () => {
- expect(findProtectionDetailsListItems().at(0).text()).toBe(
- branchRulePropsMock.approvalDetails[0],
+ expect(findProtectionDetailsListItems()).toHaveLength(wrapper.vm.approvalDetails.length);
+ expect(findProtectionDetailsListItems().at(0).text()).toBe(i18n.allowForcePush);
+ expect(findProtectionDetailsListItems().at(1).text()).toBe(i18n.codeOwnerApprovalRequired);
+ expect(findProtectionDetailsListItems().at(2).text()).toMatchInterpolatedText(
+ sprintf(i18n.statusChecks, {
+ total: branchRulePropsMock.statusChecksTotal,
+ subject: n__('check', 'checks', branchRulePropsMock.statusChecksTotal),
+ }),
);
- expect(findProtectionDetailsListItems().at(1).text()).toBe(
- branchRulePropsMock.approvalDetails[1],
+ expect(findProtectionDetailsListItems().at(3).text()).toMatchInterpolatedText(
+ sprintf(i18n.approvalRules, {
+ total: branchRulePropsMock.approvalRulesTotal,
+ subject: n__('rule', 'rules', branchRulePropsMock.approvalRulesTotal),
+ }),
);
});
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 bac82992c4d..8aa03a12996 100644
--- a/spec/frontend/projects/settings/repository/branch_rules/mock_data.js
+++ b/spec/frontend/projects/settings/repository/branch_rules/mock_data.js
@@ -8,10 +8,36 @@ export const branchRulesMockResponse = {
nodes: [
{
name: 'main',
+ isDefault: true,
+ branchProtection: {
+ allowForcePush: true,
+ codeOwnerApprovalRequired: true,
+ },
+ approvalRules: {
+ nodes: [{ id: 1 }],
+ __typename: 'ApprovalProjectRuleConnection',
+ },
+ externalStatusChecks: {
+ nodes: [{ id: 1 }, { id: 2 }],
+ __typename: 'BranchRule',
+ },
__typename: 'BranchRule',
},
{
name: 'test-*',
+ isDefault: false,
+ branchProtection: {
+ allowForcePush: false,
+ codeOwnerApprovalRequired: false,
+ },
+ approvalRules: {
+ nodes: [],
+ __typename: 'ApprovalProjectRuleConnection',
+ },
+ externalStatusChecks: {
+ nodes: [],
+ __typename: 'BranchRule',
+ },
__typename: 'BranchRule',
},
],
@@ -31,6 +57,21 @@ export const branchRuleProvideMock = {
export const branchRulePropsMock = {
name: 'main',
isDefault: true,
- isProtected: true,
- approvalDetails: ['requires approval from TEST', '2 status checks'],
+ branchProtection: {
+ allowForcePush: true,
+ codeOwnerApprovalRequired: true,
+ },
+ approvalRulesTotal: 1,
+ statusChecksTotal: 2,
+};
+
+export const branchRuleWithoutDetailsPropsMock = {
+ name: 'main',
+ isDefault: false,
+ branchProtection: {
+ allowForcePush: false,
+ codeOwnerApprovalRequired: false,
+ },
+ approvalRulesTotal: 0,
+ statusChecksTotal: 0,
};
diff --git a/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js b/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js
index 7c3f4e76ae5..f9762491507 100644
--- a/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js
+++ b/spec/frontend/projects/settings_service_desk/components/service_desk_setting_spec.js
@@ -64,20 +64,14 @@ describe('ServiceDeskSetting', () => {
});
});
- describe('when customEmailEnabled', () => {
- beforeEach(() => {
- wrapper = createComponent({
- props: { customEmailEnabled: true },
- });
- });
+ describe('service desk email "from" name', () => {
+ it('service desk e-mail "from" name input appears', () => {
+ wrapper = createComponent();
- it('should not display help text', () => {
- expect(findSuffixFormGroup().text()).not.toContain(
- 'To add a custom suffix, set up a Service Desk email address',
- );
- expect(findSuffixFormGroup().text()).toContain(
- 'Add a suffix to Service Desk email address',
- );
+ const input = wrapper.findByTestId('email-from-name');
+
+ expect(input.exists()).toBe(true);
+ expect(input.attributes('disabled')).toBeUndefined();
});
});
diff --git a/spec/frontend/releases/components/asset_links_form_spec.js b/spec/frontend/releases/components/asset_links_form_spec.js
index 1ff5766b074..b1e9d8d1256 100644
--- a/spec/frontend/releases/components/asset_links_form_spec.js
+++ b/spec/frontend/releases/components/asset_links_form_spec.js
@@ -292,6 +292,42 @@ describe('Release edit component', () => {
});
});
+ describe('remove button state', () => {
+ describe('when there is only one link', () => {
+ beforeEach(() => {
+ factory({
+ release: {
+ ...release,
+ assets: {
+ links: release.assets.links.slice(0, 1),
+ },
+ },
+ });
+ });
+
+ it('remove asset link button should not be present', () => {
+ expect(wrapper.find('.remove-button').exists()).toBe(false);
+ });
+ });
+
+ describe('when there are multiple links', () => {
+ beforeEach(() => {
+ factory({
+ release: {
+ ...release,
+ assets: {
+ links: release.assets.links.slice(0, 2),
+ },
+ },
+ });
+ });
+
+ it('remove asset link button should be visible', () => {
+ expect(wrapper.find('.remove-button').exists()).toBe(true);
+ });
+ });
+ });
+
describe('empty state', () => {
describe('when the release fetched from the API has no links', () => {
beforeEach(() => {
@@ -325,12 +361,6 @@ describe('Release edit component', () => {
it('does not call the addEmptyAssetLink store method when the component is created', () => {
expect(actions.addEmptyAssetLink).not.toHaveBeenCalled();
});
-
- it('calls addEmptyAssetLink when the final link is deleted by the user', () => {
- wrapper.find('.remove-button').vm.$emit('click');
-
- expect(actions.addEmptyAssetLink).toHaveBeenCalledTimes(1);
- });
});
});
});
diff --git a/spec/frontend/reports/codequality_report/grouped_codequality_reports_app_spec.js b/spec/frontend/reports/codequality_report/grouped_codequality_reports_app_spec.js
deleted file mode 100644
index 962ff068b92..00000000000
--- a/spec/frontend/reports/codequality_report/grouped_codequality_reports_app_spec.js
+++ /dev/null
@@ -1,151 +0,0 @@
-import { mount } from '@vue/test-utils';
-import Vue from 'vue';
-import Vuex from 'vuex';
-import CodequalityIssueBody from '~/reports/codequality_report/components/codequality_issue_body.vue';
-import GroupedCodequalityReportsApp from '~/reports/codequality_report/grouped_codequality_reports_app.vue';
-import { getStoreConfig } from '~/reports/codequality_report/store';
-import { STATUS_NOT_FOUND } from '~/reports/constants';
-import { parsedReportIssues } from './mock_data';
-
-Vue.use(Vuex);
-
-describe('Grouped code quality reports app', () => {
- let wrapper;
- let mockStore;
-
- const PATHS = {
- codequalityHelpPath: 'codequality_help.html',
- baseBlobPath: 'base/blob/path/',
- headBlobPath: 'head/blob/path/',
- };
-
- const mountComponent = (props = {}) => {
- wrapper = mount(GroupedCodequalityReportsApp, {
- store: mockStore,
- propsData: {
- ...PATHS,
- ...props,
- },
- });
- };
-
- const findWidget = () => wrapper.find('.js-codequality-widget');
- const findIssueBody = () => wrapper.findComponent(CodequalityIssueBody);
-
- beforeEach(() => {
- const { state, ...storeConfig } = getStoreConfig();
- mockStore = new Vuex.Store({
- ...storeConfig,
- actions: {
- setPaths: () => {},
- fetchReports: () => {},
- },
- state: {
- ...state,
- ...PATHS,
- },
- });
-
- mountComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('when it is loading reports', () => {
- beforeEach(() => {
- mockStore.state.isLoading = true;
- });
-
- it('should render loading text', () => {
- expect(findWidget().text()).toEqual('Loading Code quality report');
- });
- });
-
- describe('when base and head reports are loaded and compared', () => {
- describe('with no issues', () => {
- beforeEach(() => {
- mockStore.state.newIssues = [];
- mockStore.state.resolvedIssues = [];
- });
-
- it('renders no changes text', () => {
- expect(findWidget().text()).toEqual('No changes to code quality');
- });
- });
-
- describe('with issues', () => {
- describe('with new issues', () => {
- beforeEach(() => {
- mockStore.state.newIssues = parsedReportIssues.newIssues;
- mockStore.state.resolvedIssues = [];
- });
-
- it('renders summary text', () => {
- expect(findWidget().text()).toContain('Code quality degraded');
- });
-
- it('renders custom codequality issue body', () => {
- expect(findIssueBody().props('issue')).toEqual(parsedReportIssues.newIssues[0]);
- });
- });
-
- describe('with resolved issues', () => {
- beforeEach(() => {
- mockStore.state.newIssues = [];
- mockStore.state.resolvedIssues = parsedReportIssues.resolvedIssues;
- });
-
- it('renders summary text', () => {
- expect(findWidget().text()).toContain('Code quality improved');
- });
-
- it('renders custom codequality issue body', () => {
- expect(findIssueBody().props('issue')).toEqual(parsedReportIssues.resolvedIssues[0]);
- });
- });
-
- describe('with new and resolved issues', () => {
- beforeEach(() => {
- mockStore.state.newIssues = parsedReportIssues.newIssues;
- mockStore.state.resolvedIssues = parsedReportIssues.resolvedIssues;
- });
-
- it('renders summary text', () => {
- expect(findWidget().text()).toContain(
- 'Code quality scanning detected 2 changes in merged results',
- );
- });
-
- it('renders custom codequality issue body', () => {
- expect(findIssueBody().props('issue')).toEqual(parsedReportIssues.newIssues[0]);
- });
- });
- });
- });
-
- describe('on error', () => {
- beforeEach(() => {
- mockStore.state.hasError = true;
- });
-
- it('renders error text', () => {
- expect(findWidget().text()).toContain('Failed to load Code quality report');
- });
-
- it('does not render a help icon', () => {
- expect(findWidget().find('[data-testid="question-o-icon"]').exists()).toBe(false);
- });
-
- describe('when base report was not found', () => {
- beforeEach(() => {
- mockStore.state.status = STATUS_NOT_FOUND;
- });
-
- it('renders a help icon with more information', () => {
- expect(findWidget().find('[data-testid="question-o-icon"]').exists()).toBe(true);
- });
- });
- });
-});
diff --git a/spec/frontend/reports/codequality_report/store/actions_spec.js b/spec/frontend/reports/codequality_report/store/actions_spec.js
index 71f1a0f4de0..1878b9f44b2 100644
--- a/spec/frontend/reports/codequality_report/store/actions_spec.js
+++ b/spec/frontend/reports/codequality_report/store/actions_spec.js
@@ -28,7 +28,6 @@ describe('Codequality Reports actions', () => {
baseBlobPath: 'baseBlobPath',
headBlobPath: 'headBlobPath',
reportsPath: 'reportsPath',
- helpPath: 'codequalityHelpPath',
};
return testAction(
diff --git a/spec/frontend/reports/components/__snapshots__/grouped_issues_list_spec.js.snap b/spec/frontend/reports/components/__snapshots__/grouped_issues_list_spec.js.snap
index 111757e2d30..311a67a3e31 100644
--- a/spec/frontend/reports/components/__snapshots__/grouped_issues_list_spec.js.snap
+++ b/spec/frontend/reports/components/__snapshots__/grouped_issues_list_spec.js.snap
@@ -13,7 +13,7 @@ Object {
exports[`Grouped Issues List with data renders a report item with the correct props 1`] = `
Object {
- "component": "TestIssueBody",
+ "component": "CodequalityIssueBody",
"iconComponent": "IssueStatusIcon",
"isNew": false,
"issue": Object {
diff --git a/spec/frontend/reports/components/grouped_issues_list_spec.js b/spec/frontend/reports/components/grouped_issues_list_spec.js
index 6c0275dc47d..cacbde590d6 100644
--- a/spec/frontend/reports/components/grouped_issues_list_spec.js
+++ b/spec/frontend/reports/components/grouped_issues_list_spec.js
@@ -74,7 +74,7 @@ describe('Grouped Issues List', () => {
createComponent({
propsData: {
resolvedIssues: [{ name: 'foo' }],
- component: 'TestIssueBody',
+ component: 'CodequalityIssueBody',
},
stubs: {
ReportItem,
diff --git a/spec/frontend/reports/components/report_item_spec.js b/spec/frontend/reports/components/report_item_spec.js
index b52c163eb26..60c7e5f2b44 100644
--- a/spec/frontend/reports/components/report_item_spec.js
+++ b/spec/frontend/reports/components/report_item_spec.js
@@ -10,7 +10,7 @@ describe('ReportItem', () => {
const wrapper = shallowMount(ReportItem, {
propsData: {
issue: { foo: 'bar' },
- component: componentNames.TestIssueBody,
+ component: componentNames.CodequalityIssueBody,
status: STATUS_SUCCESS,
showReportSectionStatusIcon: false,
},
@@ -23,7 +23,7 @@ describe('ReportItem', () => {
const wrapper = shallowMount(ReportItem, {
propsData: {
issue: { foo: 'bar' },
- component: componentNames.TestIssueBody,
+ component: componentNames.CodequalityIssueBody,
status: STATUS_SUCCESS,
},
});
diff --git a/spec/frontend/reports/grouped_test_report/components/modal_spec.js b/spec/frontend/reports/grouped_test_report/components/modal_spec.js
deleted file mode 100644
index e8564d2428d..00000000000
--- a/spec/frontend/reports/grouped_test_report/components/modal_spec.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import { GlLink, GlSprintf } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-
-import ReportsModal from '~/reports/grouped_test_report/components/modal.vue';
-import state from '~/reports/grouped_test_report/store/state';
-import CodeBlock from '~/vue_shared/components/code_block.vue';
-
-const StubbedGlModal = { template: '<div><slot></slot></div>', name: 'GlModal', props: ['title'] };
-
-describe('Grouped Test Reports Modal', () => {
- const modalDataStructure = state().modal.data;
- const title = 'Test#sum when a is 1 and b is 2 returns summary';
-
- // populate data
- modalDataStructure.execution_time.value = 0.009411;
- modalDataStructure.system_output.value = 'Failure/Error: is_expected.to eq(3)\n\n';
- modalDataStructure.filename.value = {
- text: 'link',
- path: '/file/path',
- };
-
- let wrapper;
-
- beforeEach(() => {
- wrapper = extendedWrapper(
- shallowMount(ReportsModal, {
- propsData: {
- title,
- modalData: modalDataStructure,
- visible: true,
- },
- stubs: { GlModal: StubbedGlModal, GlSprintf },
- }),
- );
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('renders code block', () => {
- expect(wrapper.findComponent(CodeBlock).props().code).toEqual(
- modalDataStructure.system_output.value,
- );
- });
-
- it('renders link', () => {
- const link = wrapper.findComponent(GlLink);
-
- expect(link.attributes().href).toEqual(modalDataStructure.filename.value.path);
-
- expect(link.text()).toEqual(modalDataStructure.filename.value.text);
- });
-
- it('renders seconds', () => {
- expect(wrapper.text()).toContain(`${modalDataStructure.execution_time.value} s`);
- });
-
- it('render title', () => {
- expect(wrapper.findComponent(StubbedGlModal).props().title).toEqual(title);
- });
-
- it('re-emits hide event', () => {
- wrapper.findComponent(StubbedGlModal).vm.$emit('hide');
- expect(wrapper.emitted().hide).toEqual([[]]);
- });
-});
diff --git a/spec/frontend/reports/grouped_test_report/components/test_issue_body_spec.js b/spec/frontend/reports/grouped_test_report/components/test_issue_body_spec.js
deleted file mode 100644
index 8a854a92ad7..00000000000
--- a/spec/frontend/reports/grouped_test_report/components/test_issue_body_spec.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import { GlBadge, GlButton } 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 IssueStatusIcon from '~/reports/components/issue_status_icon.vue';
-import TestIssueBody from '~/reports/grouped_test_report/components/test_issue_body.vue';
-import { failedIssue, successIssue } from '../../mock_data/mock_data';
-
-Vue.use(Vuex);
-
-describe('Test issue body', () => {
- let wrapper;
- let store;
-
- const findDescription = () => wrapper.findByTestId('test-issue-body-description');
- const findStatusIcon = () => wrapper.findComponent(IssueStatusIcon);
- const findBadge = () => wrapper.findComponent(GlBadge);
-
- const actionSpies = {
- openModal: jest.fn(),
- };
-
- const createComponent = ({ issue = failedIssue } = {}) => {
- store = new Vuex.Store({
- actions: actionSpies,
- });
-
- wrapper = extendedWrapper(
- shallowMount(TestIssueBody, {
- store,
- propsData: {
- issue,
- },
- stubs: {
- GlBadge,
- GlButton,
- IssueStatusIcon,
- },
- }),
- );
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('when issue has failed status', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders issue name', () => {
- expect(findDescription().text()).toContain(failedIssue.name);
- });
-
- it('renders failed status icon', () => {
- expect(findStatusIcon().props('status')).toBe('failed');
- });
-
- describe('when issue has recent failures', () => {
- it('renders recent failures badge', () => {
- expect(findBadge().exists()).toBe(true);
- });
- });
- });
-
- describe('when issue has success status', () => {
- beforeEach(() => {
- createComponent({ issue: successIssue });
- });
-
- it('does not render recent failures', () => {
- expect(findBadge().exists()).toBe(false);
- });
-
- it('renders issue name', () => {
- expect(findDescription().text()).toBe(successIssue.name);
- });
-
- it('renders success status icon', () => {
- expect(findStatusIcon().props('status')).toBe('success');
- });
- });
-
- describe('when clicking on an issue', () => {
- it('calls openModal action', () => {
- createComponent();
- wrapper.findComponent(GlButton).trigger('click');
-
- expect(actionSpies.openModal).toHaveBeenCalledWith(expect.any(Object), {
- issue: failedIssue,
- });
- });
- });
-});
diff --git a/spec/frontend/reports/grouped_test_report/grouped_test_reports_app_spec.js b/spec/frontend/reports/grouped_test_report/grouped_test_reports_app_spec.js
deleted file mode 100644
index 90edb27d1d6..00000000000
--- a/spec/frontend/reports/grouped_test_report/grouped_test_reports_app_spec.js
+++ /dev/null
@@ -1,355 +0,0 @@
-import { mount } from '@vue/test-utils';
-import Vue from 'vue';
-import Vuex from 'vuex';
-import Api from '~/api';
-import GroupedTestReportsApp from '~/reports/grouped_test_report/grouped_test_reports_app.vue';
-import { getStoreConfig } from '~/reports/grouped_test_report/store';
-
-import { failedReport } from '../mock_data/mock_data';
-import mixedResultsTestReports from '../mock_data/new_and_fixed_failures_report.json';
-import newErrorsTestReports from '../mock_data/new_errors_report.json';
-import newFailedTestReports from '../mock_data/new_failures_report.json';
-import successTestReports from '../mock_data/no_failures_report.json';
-import recentFailuresTestReports from '../mock_data/recent_failures_report.json';
-import resolvedFailures from '../mock_data/resolved_failures.json';
-
-jest.mock('~/api.js');
-
-Vue.use(Vuex);
-
-describe('Grouped test reports app', () => {
- const endpoint = 'endpoint.json';
- const headBlobPath = '/blob/path';
- const pipelinePath = '/path/to/pipeline';
- let wrapper;
- let mockStore;
-
- const mountComponent = ({ props = { pipelinePath } } = {}) => {
- wrapper = mount(GroupedTestReportsApp, {
- store: mockStore,
- propsData: {
- endpoint,
- headBlobPath,
- pipelinePath,
- ...props,
- },
- });
- };
-
- const setReports = (reports) => {
- mockStore.state.status = reports.status;
- mockStore.state.summary = reports.summary;
- mockStore.state.reports = reports.suites;
- };
-
- const findHeader = () => wrapper.find('[data-testid="report-section-code-text"]');
- const findExpandButton = () => wrapper.find('[data-testid="report-section-expand-button"]');
- const findFullTestReportLink = () => wrapper.find('[data-testid="group-test-reports-full-link"]');
- const findSummaryDescription = () => wrapper.find('[data-testid="summary-row-description"]');
- const findIssueListUnresolvedHeading = () => wrapper.find('[data-testid="unresolvedHeading"]');
- const findIssueListResolvedHeading = () => wrapper.find('[data-testid="resolvedHeading"]');
- const findIssueDescription = () => wrapper.find('[data-testid="test-issue-body-description"]');
- const findIssueRecentFailures = () =>
- wrapper.find('[data-testid="test-issue-body-recent-failures"]');
- const findAllIssueDescriptions = () =>
- wrapper.findAll('[data-testid="test-issue-body-description"]');
-
- beforeEach(() => {
- mockStore = new Vuex.Store({
- ...getStoreConfig(),
- actions: {
- fetchReports: () => {},
- setPaths: () => {},
- },
- });
- mountComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- wrapper = null;
- });
-
- describe('with success result', () => {
- beforeEach(() => {
- setReports(successTestReports);
- mountComponent();
- });
-
- it('renders success summary text', () => {
- expect(findHeader().text()).toBe(
- 'Test summary contained no changed test results out of 11 total tests',
- );
- });
- });
-
- describe('`View full report` button', () => {
- it('should render the full test report link', () => {
- const fullTestReportLink = findFullTestReportLink();
-
- expect(fullTestReportLink.exists()).toBe(true);
- expect(pipelinePath).not.toBe('');
- expect(fullTestReportLink.attributes('href')).toBe(`${pipelinePath}/test_report`);
- });
-
- describe('Without a pipelinePath', () => {
- beforeEach(() => {
- mountComponent({
- props: { pipelinePath: '' },
- });
- });
-
- it('should not render the full test report link', () => {
- expect(findFullTestReportLink().exists()).toBe(false);
- });
- });
- });
-
- describe('`Expand` button', () => {
- beforeEach(() => {
- setReports(newFailedTestReports);
- });
-
- it('tracks service ping metric', () => {
- mountComponent();
- findExpandButton().trigger('click');
-
- expect(Api.trackRedisHllUserEvent).toHaveBeenCalledTimes(1);
- expect(Api.trackRedisHllUserEvent).toHaveBeenCalledWith(wrapper.vm.$options.expandEvent);
- });
-
- it('only tracks the first expansion', () => {
- mountComponent();
- const expandButton = findExpandButton();
- expandButton.trigger('click');
- expandButton.trigger('click');
- expandButton.trigger('click');
-
- expect(Api.trackRedisHllUserEvent).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('with new failed result', () => {
- beforeEach(() => {
- setReports(newFailedTestReports);
- mountComponent();
- });
-
- it('renders New heading', () => {
- expect(findIssueListUnresolvedHeading().text()).toBe('New');
- });
-
- it('renders failed summary text', () => {
- expect(findHeader().text()).toBe('Test summary contained 2 failed out of 11 total tests');
- });
-
- it('renders failed test suite', () => {
- expect(findSummaryDescription().text()).toContain(
- 'rspec:pg found 2 failed out of 8 total tests',
- );
- });
-
- it('renders failed issue in list', () => {
- expect(findIssueDescription().text()).toContain(
- 'Test#sum when a is 1 and b is 2 returns summary',
- );
- });
- });
-
- describe('with new error result', () => {
- beforeEach(() => {
- setReports(newErrorsTestReports);
- mountComponent();
- });
-
- it('renders New heading', () => {
- expect(findIssueListUnresolvedHeading().text()).toBe('New');
- });
-
- it('renders error summary text', () => {
- expect(findHeader().text()).toBe('Test summary contained 2 errors out of 11 total tests');
- });
-
- it('renders error test suite', () => {
- expect(findSummaryDescription().text()).toContain(
- 'karma found 2 errors out of 3 total tests',
- );
- });
-
- it('renders error issue in list', () => {
- expect(findIssueDescription().text()).toContain(
- 'Test#sum when a is 1 and b is 2 returns summary',
- );
- });
- });
-
- describe('with mixed results', () => {
- beforeEach(() => {
- setReports(mixedResultsTestReports);
- mountComponent();
- });
-
- it('renders New and Fixed headings', () => {
- expect(findIssueListUnresolvedHeading().text()).toBe('New');
- expect(findIssueListResolvedHeading().text()).toBe('Fixed');
- });
-
- it('renders summary text', () => {
- expect(findHeader().text()).toBe(
- 'Test summary contained 2 failed and 2 fixed test results out of 11 total tests',
- );
- });
-
- it('renders failed test suite', () => {
- expect(findSummaryDescription().text()).toContain(
- 'rspec:pg found 1 failed and 2 fixed test results out of 8 total tests',
- );
- });
-
- it('renders failed issue in list', () => {
- expect(findIssueDescription().text()).toContain(
- 'Test#subtract when a is 2 and b is 1 returns correct result',
- );
- });
- });
-
- describe('with resolved failures and resolved errors', () => {
- beforeEach(() => {
- setReports(resolvedFailures);
- mountComponent();
- });
-
- it('renders Fixed heading', () => {
- expect(findIssueListResolvedHeading().text()).toBe('Fixed');
- });
-
- it('renders summary text', () => {
- expect(findHeader().text()).toBe(
- 'Test summary contained 4 fixed test results out of 11 total tests',
- );
- });
-
- it('renders resolved test suite', () => {
- expect(findSummaryDescription().text()).toContain(
- 'rspec:pg found 4 fixed test results out of 8 total tests',
- );
- });
-
- it('renders resolved failures', () => {
- expect(findIssueDescription().text()).toContain(
- resolvedFailures.suites[0].resolved_failures[0].name,
- );
- });
-
- it('renders resolved errors', () => {
- expect(findAllIssueDescriptions().at(2).text()).toContain(
- resolvedFailures.suites[0].resolved_errors[0].name,
- );
- });
- });
-
- describe('recent failures counts', () => {
- describe('with recent failures counts', () => {
- beforeEach(() => {
- setReports(recentFailuresTestReports);
- mountComponent();
- });
-
- it('renders the recently failed tests summary', () => {
- expect(findHeader().text()).toContain(
- '2 out of 3 failed tests have failed more than once in the last 14 days',
- );
- });
-
- it('renders the recently failed count on the test suite', () => {
- expect(findSummaryDescription().text()).toContain(
- '1 out of 2 failed tests has failed more than once in the last 14 days',
- );
- });
-
- it('renders the recent failures count on the test case', () => {
- expect(findIssueRecentFailures().text()).toBe('Failed 8 times in main in the last 14 days');
- });
- });
-
- describe('without recent failures counts', () => {
- beforeEach(() => {
- setReports(mixedResultsTestReports);
- mountComponent();
- });
-
- it('does not render the recently failed tests summary', () => {
- expect(findHeader().text()).not.toContain('failed more than once in the last 14 days');
- });
-
- it('does not render the recently failed count on the test suite', () => {
- expect(findSummaryDescription().text()).not.toContain(
- 'failed more than once in the last 14 days',
- );
- });
-
- it('does not render the recent failures count on the test case', () => {
- expect(findIssueDescription().text()).not.toContain('in the last 14 days');
- });
- });
- });
-
- describe('with a report that failed to load', () => {
- beforeEach(() => {
- setReports(failedReport);
- mountComponent();
- });
-
- it('renders an error status for the report', () => {
- const { name } = failedReport.suites[0];
-
- expect(findSummaryDescription().text()).toContain(
- `An error occurred while loading ${name} result`,
- );
- });
- });
-
- describe('with a report parsing errors', () => {
- beforeEach(() => {
- const reports = failedReport;
- reports.suites[0].suite_errors = {
- head: 'JUnit XML parsing failed: 2:24: FATAL: attributes construct error',
- base: 'JUnit data parsing failed: string not matched',
- };
- setReports(reports);
- mountComponent();
- });
-
- it('renders the error messages', () => {
- expect(findSummaryDescription().text()).toContain(
- 'JUnit XML parsing failed: 2:24: FATAL: attributes construct error',
- );
- expect(findSummaryDescription().text()).toContain(
- 'JUnit data parsing failed: string not matched',
- );
- });
- });
-
- describe('with error', () => {
- beforeEach(() => {
- mockStore.state.isLoading = false;
- mockStore.state.hasError = true;
- mountComponent();
- });
-
- it('renders loading state', () => {
- expect(findHeader().text()).toBe('Test summary failed loading results');
- });
- });
-
- describe('while loading', () => {
- beforeEach(() => {
- mockStore.state.isLoading = true;
- mountComponent();
- });
-
- it('renders loading state', () => {
- expect(findHeader().text()).toBe('Test summary results are being parsed');
- });
- });
-});
diff --git a/spec/frontend/reports/grouped_test_report/store/actions_spec.js b/spec/frontend/reports/grouped_test_report/store/actions_spec.js
deleted file mode 100644
index 7469c31cf84..00000000000
--- a/spec/frontend/reports/grouped_test_report/store/actions_spec.js
+++ /dev/null
@@ -1,168 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import { TEST_HOST } from 'helpers/test_constants';
-import testAction from 'helpers/vuex_action_helper';
-import axios from '~/lib/utils/axios_utils';
-import {
- setPaths,
- requestReports,
- fetchReports,
- stopPolling,
- clearEtagPoll,
- receiveReportsSuccess,
- receiveReportsError,
- openModal,
- closeModal,
-} from '~/reports/grouped_test_report/store/actions';
-import * as types from '~/reports/grouped_test_report/store/mutation_types';
-import state from '~/reports/grouped_test_report/store/state';
-
-describe('Reports Store Actions', () => {
- let mockedState;
-
- beforeEach(() => {
- mockedState = state();
- });
-
- describe('setPaths', () => {
- it('should commit SET_PATHS mutation', () => {
- return testAction(
- setPaths,
- { endpoint: 'endpoint.json', headBlobPath: '/blob/path' },
- mockedState,
- [
- {
- type: types.SET_PATHS,
- payload: { endpoint: 'endpoint.json', headBlobPath: '/blob/path' },
- },
- ],
- [],
- );
- });
- });
-
- describe('requestReports', () => {
- it('should commit REQUEST_REPORTS mutation', () => {
- return testAction(requestReports, null, mockedState, [{ type: types.REQUEST_REPORTS }], []);
- });
- });
-
- describe('fetchReports', () => {
- let mock;
-
- beforeEach(() => {
- mockedState.endpoint = `${TEST_HOST}/endpoint.json`;
- mock = new MockAdapter(axios);
- });
-
- afterEach(() => {
- mock.restore();
- stopPolling();
- clearEtagPoll();
- });
-
- describe('success', () => {
- it('dispatches requestReports and receiveReportsSuccess', () => {
- mock
- .onGet(`${TEST_HOST}/endpoint.json`)
- .replyOnce(200, { summary: {}, suites: [{ name: 'rspec' }] });
-
- return testAction(
- fetchReports,
- null,
- mockedState,
- [],
- [
- {
- type: 'requestReports',
- },
- {
- payload: { data: { summary: {}, suites: [{ name: 'rspec' }] }, status: 200 },
- type: 'receiveReportsSuccess',
- },
- ],
- );
- });
- });
-
- describe('error', () => {
- beforeEach(() => {
- mock.onGet(`${TEST_HOST}/endpoint.json`).reply(500);
- });
-
- it('dispatches requestReports and receiveReportsError', () => {
- return testAction(
- fetchReports,
- null,
- mockedState,
- [],
- [
- {
- type: 'requestReports',
- },
- {
- type: 'receiveReportsError',
- },
- ],
- );
- });
- });
- });
-
- describe('receiveReportsSuccess', () => {
- it('should commit RECEIVE_REPORTS_SUCCESS mutation with 200', () => {
- return testAction(
- receiveReportsSuccess,
- { data: { summary: {} }, status: 200 },
- mockedState,
- [{ type: types.RECEIVE_REPORTS_SUCCESS, payload: { summary: {} } }],
- [],
- );
- });
-
- it('should not commit RECEIVE_REPORTS_SUCCESS mutation with 204', () => {
- return testAction(
- receiveReportsSuccess,
- { data: { summary: {} }, status: 204 },
- mockedState,
- [],
- [],
- );
- });
- });
-
- describe('receiveReportsError', () => {
- it('should commit RECEIVE_REPORTS_ERROR mutation', () => {
- return testAction(
- receiveReportsError,
- null,
- mockedState,
- [{ type: types.RECEIVE_REPORTS_ERROR }],
- [],
- );
- });
- });
-
- describe('openModal', () => {
- it('should commit SET_ISSUE_MODAL_DATA', () => {
- return testAction(
- openModal,
- { name: 'foo' },
- mockedState,
- [{ type: types.SET_ISSUE_MODAL_DATA, payload: { name: 'foo' } }],
- [],
- );
- });
- });
-
- describe('closeModal', () => {
- it('should commit RESET_ISSUE_MODAL_DATA', () => {
- return testAction(
- closeModal,
- {},
- mockedState,
- [{ type: types.RESET_ISSUE_MODAL_DATA, payload: {} }],
- [],
- );
- });
- });
-});
diff --git a/spec/frontend/reports/grouped_test_report/store/mutations_spec.js b/spec/frontend/reports/grouped_test_report/store/mutations_spec.js
deleted file mode 100644
index b2890d7285f..00000000000
--- a/spec/frontend/reports/grouped_test_report/store/mutations_spec.js
+++ /dev/null
@@ -1,162 +0,0 @@
-import * as types from '~/reports/grouped_test_report/store/mutation_types';
-import mutations from '~/reports/grouped_test_report/store/mutations';
-import state from '~/reports/grouped_test_report/store/state';
-import { failedIssue } from '../../mock_data/mock_data';
-
-describe('Reports Store Mutations', () => {
- let stateCopy;
-
- beforeEach(() => {
- stateCopy = state();
- });
-
- describe('SET_PATHS', () => {
- it('should set endpoint', () => {
- mutations[types.SET_PATHS](stateCopy, {
- endpoint: 'endpoint.json',
- headBlobPath: '/blob/path',
- });
-
- expect(stateCopy.endpoint).toEqual('endpoint.json');
- expect(stateCopy.headBlobPath).toEqual('/blob/path');
- });
- });
-
- describe('REQUEST_REPORTS', () => {
- it('should set isLoading to true', () => {
- mutations[types.REQUEST_REPORTS](stateCopy);
-
- expect(stateCopy.isLoading).toEqual(true);
- });
- });
-
- describe('RECEIVE_REPORTS_SUCCESS', () => {
- const mockedResponse = {
- summary: {
- total: 14,
- resolved: 0,
- failed: 7,
- },
- suites: [
- {
- name: 'build:linux',
- summary: {
- total: 2,
- resolved: 0,
- failed: 1,
- },
- new_failures: [
- {
- name: 'StringHelper#concatenate when a is git and b is lab returns summary',
- execution_time: 0.0092435,
- system_output: "Failure/Error: is_expected.to eq('gitlab')",
- recent_failures: {
- count: 4,
- base_branch: 'main',
- },
- },
- ],
- resolved_failures: [
- {
- name: 'StringHelper#concatenate when a is git and b is lab returns summary',
- execution_time: 0.009235,
- system_output: "Failure/Error: is_expected.to eq('gitlab')",
- },
- ],
- existing_failures: [
- {
- name: 'StringHelper#concatenate when a is git and b is lab returns summary',
- execution_time: 1232.08,
- system_output: "Failure/Error: is_expected.to eq('gitlab')",
- },
- ],
- },
- ],
- };
-
- beforeEach(() => {
- mutations[types.RECEIVE_REPORTS_SUCCESS](stateCopy, mockedResponse);
- });
-
- it('should reset isLoading', () => {
- expect(stateCopy.isLoading).toEqual(false);
- });
-
- it('should reset hasError', () => {
- expect(stateCopy.hasError).toEqual(false);
- });
-
- it('should set summary counts', () => {
- expect(stateCopy.summary.total).toEqual(mockedResponse.summary.total);
- expect(stateCopy.summary.resolved).toEqual(mockedResponse.summary.resolved);
- expect(stateCopy.summary.failed).toEqual(mockedResponse.summary.failed);
- expect(stateCopy.summary.recentlyFailed).toEqual(1);
- });
-
- it('should set reports', () => {
- expect(stateCopy.reports).toEqual(mockedResponse.suites);
- });
- });
-
- describe('RECEIVE_REPORTS_ERROR', () => {
- beforeEach(() => {
- mutations[types.RECEIVE_REPORTS_ERROR](stateCopy);
- });
-
- it('should reset isLoading', () => {
- expect(stateCopy.isLoading).toEqual(false);
- });
-
- it('should set hasError to true', () => {
- expect(stateCopy.hasError).toEqual(true);
- });
-
- it('should reset reports', () => {
- expect(stateCopy.reports).toEqual([]);
- });
- });
-
- describe('SET_ISSUE_MODAL_DATA', () => {
- beforeEach(() => {
- mutations[types.SET_ISSUE_MODAL_DATA](stateCopy, {
- issue: failedIssue,
- });
- });
-
- it('should set modal title', () => {
- expect(stateCopy.modal.title).toEqual(failedIssue.name);
- });
-
- it('should set modal data', () => {
- expect(stateCopy.modal.data.execution_time.value).toEqual(failedIssue.execution_time);
- expect(stateCopy.modal.data.system_output.value).toEqual(failedIssue.system_output);
- });
-
- it('should open modal', () => {
- expect(stateCopy.modal.open).toEqual(true);
- });
- });
-
- describe('RESET_ISSUE_MODAL_DATA', () => {
- beforeEach(() => {
- mutations[types.SET_ISSUE_MODAL_DATA](stateCopy, {
- issue: failedIssue,
- });
-
- mutations[types.RESET_ISSUE_MODAL_DATA](stateCopy);
- });
-
- it('should reset modal title', () => {
- expect(stateCopy.modal.title).toEqual(null);
- });
-
- it('should reset modal data', () => {
- expect(stateCopy.modal.data.execution_time.value).toEqual(null);
- expect(stateCopy.modal.data.system_output.value).toEqual(null);
- });
-
- it('should close modal', () => {
- expect(stateCopy.modal.open).toEqual(false);
- });
- });
-});
diff --git a/spec/frontend/reports/grouped_test_report/store/utils_spec.js b/spec/frontend/reports/grouped_test_report/store/utils_spec.js
deleted file mode 100644
index 760afe1c11a..00000000000
--- a/spec/frontend/reports/grouped_test_report/store/utils_spec.js
+++ /dev/null
@@ -1,255 +0,0 @@
-import {
- STATUS_FAILED,
- STATUS_SUCCESS,
- ICON_WARNING,
- ICON_SUCCESS,
- ICON_NOTFOUND,
-} from '~/reports/constants';
-import * as utils from '~/reports/grouped_test_report/store/utils';
-
-describe('Reports store utils', () => {
- describe('summaryTextbuilder', () => {
- it('should render text for no changed results in multiple tests', () => {
- const name = 'Test summary';
- const data = { total: 10 };
- const result = utils.summaryTextBuilder(name, data);
-
- expect(result).toBe('Test summary contained no changed test results out of 10 total tests');
- });
-
- it('should render text for no changed results in one test', () => {
- const name = 'Test summary';
- const data = { total: 1 };
- const result = utils.summaryTextBuilder(name, data);
-
- expect(result).toBe('Test summary contained no changed test results out of 1 total test');
- });
-
- it('should render text for multiple failed results', () => {
- const name = 'Test summary';
- const data = { failed: 3, total: 10 };
- const result = utils.summaryTextBuilder(name, data);
-
- expect(result).toBe('Test summary contained 3 failed out of 10 total tests');
- });
-
- it('should render text for multiple errored results', () => {
- const name = 'Test summary';
- const data = { errored: 7, total: 10 };
- const result = utils.summaryTextBuilder(name, data);
-
- expect(result).toBe('Test summary contained 7 errors out of 10 total tests');
- });
-
- it('should render text for multiple fixed results', () => {
- const name = 'Test summary';
- const data = { resolved: 4, total: 10 };
- const result = utils.summaryTextBuilder(name, data);
-
- expect(result).toBe('Test summary contained 4 fixed test results out of 10 total tests');
- });
-
- it('should render text for multiple fixed, and multiple failed results', () => {
- const name = 'Test summary';
- const data = { failed: 3, resolved: 4, total: 10 };
- const result = utils.summaryTextBuilder(name, data);
-
- expect(result).toBe(
- 'Test summary contained 3 failed and 4 fixed test results out of 10 total tests',
- );
- });
-
- it('should render text for a singular fixed, and a singular failed result', () => {
- const name = 'Test summary';
- const data = { failed: 1, resolved: 1, total: 10 };
- const result = utils.summaryTextBuilder(name, data);
-
- expect(result).toBe(
- 'Test summary contained 1 failed and 1 fixed test result out of 10 total tests',
- );
- });
-
- it('should render text for singular failed, errored, and fixed results', () => {
- const name = 'Test summary';
- const data = { failed: 1, errored: 1, resolved: 1, total: 10 };
- const result = utils.summaryTextBuilder(name, data);
-
- expect(result).toBe(
- 'Test summary contained 1 failed, 1 error and 1 fixed test result out of 10 total tests',
- );
- });
-
- it('should render text for multiple failed, errored, and fixed results', () => {
- const name = 'Test summary';
- const data = { failed: 2, errored: 3, resolved: 4, total: 10 };
- const result = utils.summaryTextBuilder(name, data);
-
- expect(result).toBe(
- 'Test summary contained 2 failed, 3 errors and 4 fixed test results out of 10 total tests',
- );
- });
- });
-
- describe('reportTextBuilder', () => {
- it('should render text for no changed results in multiple tests', () => {
- const name = 'Rspec';
- const data = { total: 10 };
- const result = utils.reportTextBuilder(name, data);
-
- expect(result).toBe('Rspec found no changed test results out of 10 total tests');
- });
-
- it('should render text for no changed results in one test', () => {
- const name = 'Rspec';
- const data = { total: 1 };
- const result = utils.reportTextBuilder(name, data);
-
- expect(result).toBe('Rspec found no changed test results out of 1 total test');
- });
-
- it('should render text for multiple failed results', () => {
- const name = 'Rspec';
- const data = { failed: 3, total: 10 };
- const result = utils.reportTextBuilder(name, data);
-
- expect(result).toBe('Rspec found 3 failed out of 10 total tests');
- });
-
- it('should render text for multiple errored results', () => {
- const name = 'Rspec';
- const data = { errored: 7, total: 10 };
- const result = utils.reportTextBuilder(name, data);
-
- expect(result).toBe('Rspec found 7 errors out of 10 total tests');
- });
-
- it('should render text for multiple fixed results', () => {
- const name = 'Rspec';
- const data = { resolved: 4, total: 10 };
- const result = utils.reportTextBuilder(name, data);
-
- expect(result).toBe('Rspec found 4 fixed test results out of 10 total tests');
- });
-
- it('should render text for multiple fixed, and multiple failed results', () => {
- const name = 'Rspec';
- const data = { failed: 3, resolved: 4, total: 10 };
- const result = utils.reportTextBuilder(name, data);
-
- expect(result).toBe('Rspec found 3 failed and 4 fixed test results out of 10 total tests');
- });
-
- it('should render text for a singular fixed, and a singular failed result', () => {
- const name = 'Rspec';
- const data = { failed: 1, resolved: 1, total: 10 };
- const result = utils.reportTextBuilder(name, data);
-
- expect(result).toBe('Rspec found 1 failed and 1 fixed test result out of 10 total tests');
- });
-
- it('should render text for singular failed, errored, and fixed results', () => {
- const name = 'Rspec';
- const data = { failed: 1, errored: 1, resolved: 1, total: 10 };
- const result = utils.reportTextBuilder(name, data);
-
- expect(result).toBe(
- 'Rspec found 1 failed, 1 error and 1 fixed test result out of 10 total tests',
- );
- });
-
- it('should render text for multiple failed, errored, and fixed results', () => {
- const name = 'Rspec';
- const data = { failed: 2, errored: 3, resolved: 4, total: 10 };
- const result = utils.reportTextBuilder(name, data);
-
- expect(result).toBe(
- 'Rspec found 2 failed, 3 errors and 4 fixed test results out of 10 total tests',
- );
- });
- });
-
- describe('recentFailuresTextBuilder', () => {
- it.each`
- recentlyFailed | failed | expected
- ${0} | ${1} | ${''}
- ${1} | ${1} | ${'1 out of 1 failed test has failed more than once in the last 14 days'}
- ${1} | ${2} | ${'1 out of 2 failed tests has failed more than once in the last 14 days'}
- ${2} | ${3} | ${'2 out of 3 failed tests have failed more than once in the last 14 days'}
- `(
- 'should render summary for $recentlyFailed out of $failed failures',
- ({ recentlyFailed, failed, expected }) => {
- const result = utils.recentFailuresTextBuilder({ recentlyFailed, failed });
-
- expect(result).toBe(expected);
- },
- );
- });
-
- describe('countRecentlyFailedTests', () => {
- it('counts tests with more than one recent failure in a report', () => {
- const report = {
- new_failures: [{ recent_failures: { count: 2 } }],
- existing_failures: [{ recent_failures: { count: 1 } }],
- resolved_failures: [{ recent_failures: { count: 20 } }, { recent_failures: { count: 5 } }],
- };
- const result = utils.countRecentlyFailedTests(report);
-
- expect(result).toBe(3);
- });
-
- it('counts tests with more than one recent failure in an array of reports', () => {
- const reports = [
- {
- new_failures: [{ recent_failures: { count: 2 } }],
- existing_failures: [
- { recent_failures: { count: 20 } },
- { recent_failures: { count: 5 } },
- ],
- resolved_failures: [{ recent_failures: { count: 2 } }],
- },
- {
- new_failures: [{ recent_failures: { count: 8 } }, { recent_failures: { count: 14 } }],
- existing_failures: [{ recent_failures: { count: 1 } }],
- resolved_failures: [{ recent_failures: { count: 7 } }, { recent_failures: { count: 5 } }],
- },
- ];
- const result = utils.countRecentlyFailedTests(reports);
-
- expect(result).toBe(8);
- });
- });
-
- describe('statusIcon', () => {
- describe('with failed status', () => {
- it('returns ICON_WARNING', () => {
- expect(utils.statusIcon(STATUS_FAILED)).toEqual(ICON_WARNING);
- });
- });
-
- describe('with success status', () => {
- it('returns ICON_SUCCESS', () => {
- expect(utils.statusIcon(STATUS_SUCCESS)).toEqual(ICON_SUCCESS);
- });
- });
-
- describe('without a status', () => {
- it('returns ICON_NOTFOUND', () => {
- expect(utils.statusIcon()).toEqual(ICON_NOTFOUND);
- });
- });
- });
-
- describe('formatFilePath', () => {
- it.each`
- file | expected
- ${'./test.js'} | ${'test.js'}
- ${'/test.js'} | ${'test.js'}
- ${'.//////////////test.js'} | ${'test.js'}
- ${'test.js'} | ${'test.js'}
- ${'mock/path./test.js'} | ${'mock/path./test.js'}
- ${'./mock/path./test.js'} | ${'mock/path./test.js'}
- `('should format $file to be $expected', ({ file, expected }) => {
- expect(utils.formatFilePath(file)).toBe(expected);
- });
- });
-});
diff --git a/spec/frontend/runner/admin_runner_show/admin_runner_show_app_spec.js b/spec/frontend/runner/admin_runner_show/admin_runner_show_app_spec.js
deleted file mode 100644
index 64f66d8f3ba..00000000000
--- a/spec/frontend/runner/admin_runner_show/admin_runner_show_app_spec.js
+++ /dev/null
@@ -1,266 +0,0 @@
-import Vue from 'vue';
-import { GlTab, GlTabs } from '@gitlab/ui';
-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 { redirectTo } from '~/lib/utils/url_utility';
-
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import RunnerHeader from '~/runner/components/runner_header.vue';
-import RunnerDetails from '~/runner/components/runner_details.vue';
-import RunnerPauseButton from '~/runner/components/runner_pause_button.vue';
-import RunnerDeleteButton from '~/runner/components/runner_delete_button.vue';
-import RunnerEditButton from '~/runner/components/runner_edit_button.vue';
-import RunnersJobs from '~/runner/components/runner_jobs.vue';
-
-import runnerQuery from '~/runner/graphql/show/runner.query.graphql';
-import AdminRunnerShowApp from '~/runner/admin_runner_show/admin_runner_show_app.vue';
-import { captureException } from '~/runner/sentry_utils';
-import { saveAlertToLocalStorage } from '~/runner/local_storage_alert/save_alert_to_local_storage';
-
-import { runnerData } from '../mock_data';
-
-jest.mock('~/runner/local_storage_alert/save_alert_to_local_storage');
-jest.mock('~/flash');
-jest.mock('~/runner/sentry_utils');
-jest.mock('~/lib/utils/url_utility');
-
-const mockRunner = runnerData.data.runner;
-const mockRunnerGraphqlId = mockRunner.id;
-const mockRunnerId = `${getIdFromGraphQLId(mockRunnerGraphqlId)}`;
-const mockRunnersPath = '/admin/runners';
-
-Vue.use(VueApollo);
-
-describe('AdminRunnerShowApp', () => {
- let wrapper;
- let mockRunnerQuery;
-
- const findRunnerHeader = () => wrapper.findComponent(RunnerHeader);
- const findRunnerDetails = () => wrapper.findComponent(RunnerDetails);
- const findRunnerDeleteButton = () => wrapper.findComponent(RunnerDeleteButton);
- const findRunnerEditButton = () => wrapper.findComponent(RunnerEditButton);
- const findRunnerPauseButton = () => wrapper.findComponent(RunnerPauseButton);
- const findRunnersJobs = () => wrapper.findComponent(RunnersJobs);
- const findJobCountBadge = () => wrapper.findByTestId('job-count-badge');
-
- const mockRunnerQueryResult = (runner = {}) => {
- mockRunnerQuery = jest.fn().mockResolvedValue({
- data: {
- runner: { ...mockRunner, ...runner },
- },
- });
- };
-
- const createComponent = ({ props = {}, mountFn = shallowMountExtended, ...options } = {}) => {
- wrapper = mountFn(AdminRunnerShowApp, {
- apolloProvider: createMockApollo([[runnerQuery, mockRunnerQuery]]),
- propsData: {
- runnerId: mockRunnerId,
- runnersPath: mockRunnersPath,
- ...props,
- },
- ...options,
- });
-
- return waitForPromises();
- };
-
- afterEach(() => {
- mockRunnerQuery.mockReset();
- wrapper.destroy();
- });
-
- describe('When showing runner details', () => {
- beforeEach(async () => {
- mockRunnerQueryResult();
-
- await createComponent({ mountFn: mountExtended });
- });
-
- it('expect GraphQL ID to be requested', async () => {
- expect(mockRunnerQuery).toHaveBeenCalledWith({ id: mockRunnerGraphqlId });
- });
-
- it('displays the runner header', async () => {
- expect(findRunnerHeader().text()).toContain(`Runner #${mockRunnerId}`);
- });
-
- it('displays the runner edit and pause buttons', async () => {
- expect(findRunnerEditButton().exists()).toBe(true);
- expect(findRunnerPauseButton().exists()).toBe(true);
- expect(findRunnerDeleteButton().exists()).toBe(true);
- });
-
- it('shows basic runner details', async () => {
- const expected = `Description My Runner
- Last contact Never contacted
- Version 1.0.0
- IP Address None
- Executor None
- Architecture None
- Platform darwin
- Configuration Runs untagged jobs
- Maximum job timeout None
- Token expiry
- Runner authentication token expiration
- Runner authentication tokens will expire based on a set interval.
- They will automatically rotate once expired. Learn more Never expires
- Tags None`.replace(/\s+/g, ' ');
-
- expect(wrapper.text().replace(/\s+/g, ' ')).toContain(expected);
- });
-
- describe('when runner cannot be updated', () => {
- beforeEach(async () => {
- mockRunnerQueryResult({
- userPermissions: {
- updateRunner: false,
- },
- });
-
- await createComponent({
- mountFn: mountExtended,
- });
- });
-
- it('does not display the runner edit and pause buttons', () => {
- expect(findRunnerEditButton().exists()).toBe(false);
- expect(findRunnerPauseButton().exists()).toBe(false);
- });
- });
-
- describe('when runner cannot be deleted', () => {
- beforeEach(async () => {
- mockRunnerQueryResult({
- userPermissions: {
- deleteRunner: false,
- },
- });
-
- await createComponent({
- mountFn: mountExtended,
- });
- });
-
- it('does not display the runner edit and pause buttons', () => {
- expect(findRunnerDeleteButton().exists()).toBe(false);
- });
- });
-
- describe('when runner is deleted', () => {
- beforeEach(async () => {
- await createComponent({
- mountFn: mountExtended,
- });
- });
-
- it('redirects to the runner list page', () => {
- findRunnerDeleteButton().vm.$emit('deleted', { message: 'Runner deleted' });
-
- expect(saveAlertToLocalStorage).toHaveBeenCalledWith({
- message: 'Runner deleted',
- variant: VARIANT_SUCCESS,
- });
- expect(redirectTo).toHaveBeenCalledWith(mockRunnersPath);
- });
- });
-
- describe('when runner does not have an edit url', () => {
- beforeEach(async () => {
- mockRunnerQueryResult({
- editAdminUrl: null,
- });
-
- await createComponent({
- mountFn: mountExtended,
- });
- });
-
- it('does not display the runner edit button', () => {
- expect(findRunnerEditButton().exists()).toBe(false);
- expect(findRunnerPauseButton().exists()).toBe(true);
- });
- });
- });
-
- describe('When loading', () => {
- it('does not show runner details', () => {
- mockRunnerQueryResult();
-
- createComponent();
-
- expect(findRunnerDetails().exists()).toBe(false);
- });
-
- it('does not show runner jobs', () => {
- mockRunnerQueryResult();
-
- createComponent();
-
- expect(findRunnersJobs().exists()).toBe(false);
- });
- });
-
- describe('When there is an error', () => {
- beforeEach(async () => {
- mockRunnerQuery = jest.fn().mockRejectedValueOnce(new Error('Error!'));
- await createComponent();
- });
-
- it('does not show runner details', () => {
- expect(findRunnerDetails().exists()).toBe(false);
- });
-
- it('error is reported to sentry', () => {
- expect(captureException).toHaveBeenCalledWith({
- error: new Error('Error!'),
- component: 'AdminRunnerShowApp',
- });
- });
-
- it('error is shown to the user', () => {
- expect(createAlert).toHaveBeenCalled();
- });
- });
-
- describe('Jobs tab', () => {
- const stubs = {
- GlTab,
- GlTabs,
- };
-
- it('without a runner, shows no jobs', () => {
- mockRunnerQuery = jest.fn().mockResolvedValue({
- data: {
- runner: null,
- },
- });
-
- createComponent({ stubs });
-
- expect(findJobCountBadge().exists()).toBe(false);
- expect(findRunnersJobs().exists()).toBe(false);
- });
-
- it('without a job count, shows no jobs count', async () => {
- mockRunnerQueryResult({ jobCount: null });
-
- await createComponent({ stubs });
-
- expect(findJobCountBadge().exists()).toBe(false);
- });
-
- it('with a job count, shows jobs count', async () => {
- const runner = { jobCount: 3 };
- mockRunnerQueryResult(runner);
-
- await createComponent({ stubs });
-
- expect(findJobCountBadge().text()).toBe('3');
- expect(findRunnersJobs().props('runner')).toEqual({ ...mockRunner, ...runner });
- });
- });
-});
diff --git a/spec/frontend/runner/admin_runners/admin_runners_app_spec.js b/spec/frontend/runner/admin_runners/admin_runners_app_spec.js
deleted file mode 100644
index 7afde3bdc96..00000000000
--- a/spec/frontend/runner/admin_runners/admin_runners_app_spec.js
+++ /dev/null
@@ -1,480 +0,0 @@
-import Vue, { nextTick } from 'vue';
-import { GlToast, GlLink } from '@gitlab/ui';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import setWindowLocation from 'helpers/set_window_location_helper';
-import {
- extendedWrapper,
- shallowMountExtended,
- mountExtended,
-} from 'helpers/vue_test_utils_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
-import { s__ } from '~/locale';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { updateHistory } from '~/lib/utils/url_utility';
-
-import { upgradeStatusTokenConfig } from 'ee_else_ce/runner/components/search_tokens/upgrade_status_token_config';
-import { createLocalState } from '~/runner/graphql/list/local_state';
-import AdminRunnersApp from '~/runner/admin_runners/admin_runners_app.vue';
-import RunnerStackedLayoutBanner from '~/runner/components/runner_stacked_layout_banner.vue';
-import RunnerTypeTabs from '~/runner/components/runner_type_tabs.vue';
-import RunnerFilteredSearchBar from '~/runner/components/runner_filtered_search_bar.vue';
-import RunnerList from '~/runner/components/runner_list.vue';
-import RunnerListEmptyState from '~/runner/components/runner_list_empty_state.vue';
-import RunnerStats from '~/runner/components/stat/runner_stats.vue';
-import RunnerActionsCell from '~/runner/components/cells/runner_actions_cell.vue';
-import RegistrationDropdown from '~/runner/components/registration/registration_dropdown.vue';
-import RunnerPagination from '~/runner/components/runner_pagination.vue';
-
-import {
- ADMIN_FILTERED_SEARCH_NAMESPACE,
- CREATED_ASC,
- CREATED_DESC,
- DEFAULT_SORT,
- I18N_STATUS_ONLINE,
- I18N_STATUS_OFFLINE,
- I18N_STATUS_STALE,
- I18N_INSTANCE_TYPE,
- I18N_GROUP_TYPE,
- I18N_PROJECT_TYPE,
- INSTANCE_TYPE,
- PARAM_KEY_PAUSED,
- PARAM_KEY_STATUS,
- PARAM_KEY_TAG,
- STATUS_ONLINE,
- DEFAULT_MEMBERSHIP,
- RUNNER_PAGE_SIZE,
-} from '~/runner/constants';
-import allRunnersQuery from 'ee_else_ce/runner/graphql/list/all_runners.query.graphql';
-import allRunnersCountQuery from 'ee_else_ce/runner/graphql/list/all_runners_count.query.graphql';
-import { captureException } from '~/runner/sentry_utils';
-
-import {
- allRunnersData,
- runnersCountData,
- allRunnersDataPaginated,
- onlineContactTimeoutSecs,
- staleTimeoutSecs,
- emptyPageInfo,
- emptyStateSvgPath,
- emptyStateFilteredSvgPath,
-} from '../mock_data';
-
-const mockRegistrationToken = 'MOCK_REGISTRATION_TOKEN';
-const mockRunners = allRunnersData.data.runners.nodes;
-const mockRunnersCount = runnersCountData.data.runners.count;
-
-const mockRunnersHandler = jest.fn();
-const mockRunnersCountHandler = jest.fn();
-
-jest.mock('~/flash');
-jest.mock('~/runner/sentry_utils');
-jest.mock('~/lib/utils/url_utility', () => ({
- ...jest.requireActual('~/lib/utils/url_utility'),
- updateHistory: jest.fn(),
-}));
-
-Vue.use(VueApollo);
-Vue.use(GlToast);
-
-const COUNT_QUERIES = 7; // 4 tabs + 3 status queries
-
-describe('AdminRunnersApp', () => {
- let wrapper;
- let showToast;
-
- const findRunnerStackedLayoutBanner = () => wrapper.findComponent(RunnerStackedLayoutBanner);
- const findRunnerStats = () => wrapper.findComponent(RunnerStats);
- const findRunnerActionsCell = () => wrapper.findComponent(RunnerActionsCell);
- const findRegistrationDropdown = () => wrapper.findComponent(RegistrationDropdown);
- const findRunnerTypeTabs = () => wrapper.findComponent(RunnerTypeTabs);
- const findRunnerList = () => wrapper.findComponent(RunnerList);
- const findRunnerListEmptyState = () => wrapper.findComponent(RunnerListEmptyState);
- const findRunnerPagination = () => extendedWrapper(wrapper.findComponent(RunnerPagination));
- const findRunnerPaginationNext = () => findRunnerPagination().findByText(s__('Pagination|Next'));
- const findRunnerFilteredSearchBar = () => wrapper.findComponent(RunnerFilteredSearchBar);
-
- const createComponent = ({
- props = {},
- mountFn = shallowMountExtended,
- provide,
- ...options
- } = {}) => {
- const { cacheConfig, localMutations } = createLocalState();
-
- const handlers = [
- [allRunnersQuery, mockRunnersHandler],
- [allRunnersCountQuery, mockRunnersCountHandler],
- ];
-
- wrapper = mountFn(AdminRunnersApp, {
- apolloProvider: createMockApollo(handlers, {}, cacheConfig),
- propsData: {
- registrationToken: mockRegistrationToken,
- ...props,
- },
- provide: {
- localMutations,
- onlineContactTimeoutSecs,
- staleTimeoutSecs,
- emptyStateSvgPath,
- emptyStateFilteredSvgPath,
- ...provide,
- },
- ...options,
- });
-
- showToast = jest.spyOn(wrapper.vm.$root.$toast, 'show');
-
- return waitForPromises();
- };
-
- beforeEach(() => {
- mockRunnersHandler.mockResolvedValue(allRunnersData);
- mockRunnersCountHandler.mockResolvedValue(runnersCountData);
- });
-
- afterEach(() => {
- mockRunnersHandler.mockReset();
- mockRunnersCountHandler.mockReset();
- showToast.mockReset();
- wrapper.destroy();
- });
-
- it('shows the feedback banner', () => {
- createComponent();
- expect(findRunnerStackedLayoutBanner().exists()).toBe(true);
- });
-
- it('shows the runner setup instructions', () => {
- createComponent();
-
- expect(findRegistrationDropdown().props('registrationToken')).toBe(mockRegistrationToken);
- expect(findRegistrationDropdown().props('type')).toBe(INSTANCE_TYPE);
- });
-
- describe('shows total runner counts', () => {
- beforeEach(async () => {
- await createComponent({ mountFn: mountExtended });
- });
-
- it('fetches counts', () => {
- expect(mockRunnersCountHandler).toHaveBeenCalledTimes(COUNT_QUERIES);
- });
-
- it('shows the runner tabs', () => {
- const tabs = findRunnerTypeTabs().text();
- expect(tabs).toMatchInterpolatedText(
- `All ${mockRunnersCount} ${I18N_INSTANCE_TYPE} ${mockRunnersCount} ${I18N_GROUP_TYPE} ${mockRunnersCount} ${I18N_PROJECT_TYPE} ${mockRunnersCount}`,
- );
- });
-
- it('shows the total', () => {
- expect(findRunnerStats().text()).toContain(`${I18N_STATUS_ONLINE} ${mockRunnersCount}`);
- expect(findRunnerStats().text()).toContain(`${I18N_STATUS_OFFLINE} ${mockRunnersCount}`);
- expect(findRunnerStats().text()).toContain(`${I18N_STATUS_STALE} ${mockRunnersCount}`);
- });
- });
-
- it('shows the runners list', async () => {
- await createComponent();
-
- expect(mockRunnersHandler).toHaveBeenCalledTimes(1);
- expect(findRunnerList().props('runners')).toEqual(mockRunners);
- });
-
- it('runner item links to the runner admin page', async () => {
- await createComponent({ mountFn: mountExtended });
-
- const { id, shortSha } = mockRunners[0];
- const numericId = getIdFromGraphQLId(id);
-
- const runnerLink = wrapper.find('tr [data-testid="td-summary"]').findComponent(GlLink);
-
- expect(runnerLink.text()).toBe(`#${numericId} (${shortSha})`);
- expect(runnerLink.attributes('href')).toBe(`http://localhost/admin/runners/${numericId}`);
- });
-
- it('renders runner actions for each runner', async () => {
- await createComponent({ mountFn: mountExtended });
-
- const runnerActions = wrapper
- .find('tr [data-testid="td-actions"]')
- .findComponent(RunnerActionsCell);
- const runner = mockRunners[0];
-
- expect(runnerActions.props()).toEqual({
- runner,
- editUrl: runner.editAdminUrl,
- });
- });
-
- it('requests the runners with no filters', async () => {
- await createComponent();
-
- expect(mockRunnersHandler).toHaveBeenLastCalledWith({
- status: undefined,
- type: undefined,
- membership: DEFAULT_MEMBERSHIP,
- sort: DEFAULT_SORT,
- first: RUNNER_PAGE_SIZE,
- });
- });
-
- it('sets tokens in the filtered search', () => {
- createComponent();
-
- expect(findRunnerFilteredSearchBar().props('tokens')).toEqual([
- expect.objectContaining({
- type: PARAM_KEY_PAUSED,
- options: expect.any(Array),
- }),
- expect.objectContaining({
- type: PARAM_KEY_STATUS,
- options: expect.any(Array),
- }),
- expect.objectContaining({
- type: PARAM_KEY_TAG,
- recentSuggestionsStorageKey: `${ADMIN_FILTERED_SEARCH_NAMESPACE}-recent-tags`,
- }),
- upgradeStatusTokenConfig,
- ]);
- });
-
- describe('Single runner row', () => {
- const { id: graphqlId, shortSha } = mockRunners[0];
- const id = getIdFromGraphQLId(graphqlId);
-
- beforeEach(async () => {
- mockRunnersCountHandler.mockClear();
-
- await createComponent({ mountFn: mountExtended });
- });
-
- it('Links to the runner page', async () => {
- const runnerLink = wrapper.find('tr [data-testid="td-summary"]').findComponent(GlLink);
-
- expect(runnerLink.text()).toBe(`#${id} (${shortSha})`);
- expect(runnerLink.attributes('href')).toBe(`http://localhost/admin/runners/${id}`);
- });
-
- it('When runner is paused or unpaused, some data is refetched', async () => {
- expect(mockRunnersCountHandler).toHaveBeenCalledTimes(COUNT_QUERIES);
-
- findRunnerActionsCell().vm.$emit('toggledPaused');
-
- expect(mockRunnersCountHandler).toHaveBeenCalledTimes(COUNT_QUERIES * 2);
- expect(showToast).toHaveBeenCalledTimes(0);
- });
-
- it('When runner is deleted, data is refetched and a toast message is shown', async () => {
- findRunnerActionsCell().vm.$emit('deleted', { message: 'Runner deleted' });
-
- expect(showToast).toHaveBeenCalledTimes(1);
- expect(showToast).toHaveBeenCalledWith('Runner deleted');
- });
- });
-
- describe('when a filter is preselected', () => {
- beforeEach(async () => {
- setWindowLocation(`?status[]=${STATUS_ONLINE}&runner_type[]=${INSTANCE_TYPE}&paused[]=true`);
-
- await createComponent({ mountFn: mountExtended });
- });
-
- it('sets the filters in the search bar', () => {
- expect(findRunnerFilteredSearchBar().props('value')).toEqual({
- runnerType: INSTANCE_TYPE,
- membership: DEFAULT_MEMBERSHIP,
- filters: [
- { type: PARAM_KEY_STATUS, value: { data: STATUS_ONLINE, operator: '=' } },
- { type: PARAM_KEY_PAUSED, value: { data: 'true', operator: '=' } },
- ],
- sort: 'CREATED_DESC',
- pagination: {},
- });
- });
-
- it('requests the runners with filter parameters', () => {
- expect(mockRunnersHandler).toHaveBeenLastCalledWith({
- status: STATUS_ONLINE,
- type: INSTANCE_TYPE,
- membership: DEFAULT_MEMBERSHIP,
- paused: true,
- sort: DEFAULT_SORT,
- first: RUNNER_PAGE_SIZE,
- });
- });
-
- it('fetches count results for requested status', () => {
- expect(mockRunnersCountHandler).toHaveBeenCalledWith({
- type: INSTANCE_TYPE,
- membership: DEFAULT_MEMBERSHIP,
- status: STATUS_ONLINE,
- paused: true,
- });
- });
- });
-
- describe('when a filter is selected by the user', () => {
- beforeEach(async () => {
- await createComponent({ mountFn: mountExtended });
-
- findRunnerFilteredSearchBar().vm.$emit('input', {
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [{ type: PARAM_KEY_STATUS, value: { data: STATUS_ONLINE, operator: '=' } }],
- sort: CREATED_ASC,
- });
-
- await nextTick();
- });
-
- it('updates the browser url', () => {
- expect(updateHistory).toHaveBeenLastCalledWith({
- title: expect.any(String),
- url: expect.stringContaining('?status[]=ONLINE&sort=CREATED_ASC'),
- });
- });
-
- it('requests the runners with filters', () => {
- expect(mockRunnersHandler).toHaveBeenLastCalledWith({
- status: STATUS_ONLINE,
- membership: DEFAULT_MEMBERSHIP,
- sort: CREATED_ASC,
- first: RUNNER_PAGE_SIZE,
- });
- });
-
- it('fetches count results for requested status', () => {
- expect(mockRunnersCountHandler).toHaveBeenCalledWith({
- status: STATUS_ONLINE,
- membership: DEFAULT_MEMBERSHIP,
- });
- });
- });
-
- it('when runners have not loaded, shows a loading state', () => {
- createComponent();
- expect(findRunnerList().props('loading')).toBe(true);
- expect(findRunnerPagination().attributes('disabled')).toBe('true');
- });
-
- describe('Bulk delete', () => {
- describe('Before runners are deleted', () => {
- beforeEach(async () => {
- await createComponent({ mountFn: mountExtended });
- });
-
- it('runner list is checkable', () => {
- expect(findRunnerList().props('checkable')).toBe(true);
- });
- });
-
- describe('When runners are deleted', () => {
- beforeEach(async () => {
- await createComponent({ mountFn: mountExtended });
- });
-
- it('count data is refetched', async () => {
- expect(mockRunnersCountHandler).toHaveBeenCalledTimes(COUNT_QUERIES);
-
- findRunnerList().vm.$emit('deleted', { message: 'Runners deleted' });
-
- expect(mockRunnersCountHandler).toHaveBeenCalledTimes(COUNT_QUERIES * 2);
- });
-
- it('toast is shown', async () => {
- expect(showToast).toHaveBeenCalledTimes(0);
-
- findRunnerList().vm.$emit('deleted', { message: 'Runners deleted' });
-
- expect(showToast).toHaveBeenCalledTimes(1);
- expect(showToast).toHaveBeenCalledWith('Runners deleted');
- });
- });
- });
-
- describe('when no runners are found', () => {
- beforeEach(async () => {
- mockRunnersHandler.mockResolvedValue({
- data: {
- runners: {
- nodes: [],
- pageInfo: emptyPageInfo,
- },
- },
- });
-
- await createComponent();
- });
-
- it('shows no errors', () => {
- expect(createAlert).not.toHaveBeenCalled();
- });
-
- it('shows an empty state', () => {
- expect(findRunnerListEmptyState().props('isSearchFiltered')).toBe(false);
- });
-
- describe('when a filter is selected by the user', () => {
- beforeEach(async () => {
- findRunnerFilteredSearchBar().vm.$emit('input', {
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [{ type: PARAM_KEY_STATUS, value: { data: STATUS_ONLINE, operator: '=' } }],
- sort: CREATED_ASC,
- });
- await waitForPromises();
- });
-
- it('shows an empty state for a filtered search', () => {
- expect(findRunnerListEmptyState().props('isSearchFiltered')).toBe(true);
- });
- });
- });
-
- describe('when runners query fails', () => {
- beforeEach(async () => {
- mockRunnersHandler.mockRejectedValue(new Error('Error!'));
- await createComponent();
- });
-
- it('error is shown to the user', async () => {
- expect(createAlert).toHaveBeenCalledTimes(1);
- });
-
- it('error is reported to sentry', async () => {
- expect(captureException).toHaveBeenCalledWith({
- error: new Error('Error!'),
- component: 'AdminRunnersApp',
- });
- });
- });
-
- describe('Pagination', () => {
- const { pageInfo } = allRunnersDataPaginated.data.runners;
-
- beforeEach(async () => {
- mockRunnersHandler.mockResolvedValue(allRunnersDataPaginated);
-
- await createComponent({ mountFn: mountExtended });
- });
-
- it('passes the page info', () => {
- expect(findRunnerPagination().props('pageInfo')).toEqual(pageInfo);
- });
-
- it('navigates to the next page', async () => {
- await findRunnerPaginationNext().trigger('click');
-
- expect(mockRunnersHandler).toHaveBeenLastCalledWith({
- membership: DEFAULT_MEMBERSHIP,
- sort: CREATED_DESC,
- first: RUNNER_PAGE_SIZE,
- after: pageInfo.endCursor,
- });
- });
- });
-});
diff --git a/spec/frontend/runner/components/cells/link_cell_spec.js b/spec/frontend/runner/components/cells/link_cell_spec.js
deleted file mode 100644
index 46ab1adb6b6..00000000000
--- a/spec/frontend/runner/components/cells/link_cell_spec.js
+++ /dev/null
@@ -1,72 +0,0 @@
-import { GlLink } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import LinkCell from '~/runner/components/cells/link_cell.vue';
-
-describe('LinkCell', () => {
- let wrapper;
-
- const findGlLink = () => wrapper.findComponent(GlLink);
- const findSpan = () => wrapper.find('span');
-
- const createComponent = ({ props = {}, ...options } = {}) => {
- wrapper = shallowMountExtended(LinkCell, {
- propsData: {
- ...props,
- },
- ...options,
- });
- };
-
- it('when an href is provided, renders a link', () => {
- createComponent({ props: { href: '/url' } });
- expect(findGlLink().exists()).toBe(true);
- });
-
- it('when an href is not provided, renders no link', () => {
- createComponent();
- expect(findGlLink().exists()).toBe(false);
- });
-
- describe.each`
- href | findContent
- ${null} | ${findSpan}
- ${'/url'} | ${findGlLink}
- `('When href is $href', ({ href, findContent }) => {
- const content = 'My Text';
- const attrs = { foo: 'bar' };
- const listeners = {
- click: jest.fn(),
- };
-
- beforeEach(() => {
- createComponent({
- props: { href },
- slots: {
- default: content,
- },
- attrs,
- listeners,
- });
- });
-
- afterAll(() => {
- listeners.click.mockReset();
- });
-
- it('Renders content', () => {
- expect(findContent().text()).toBe(content);
- });
-
- it('Passes attributes', () => {
- expect(findContent().attributes()).toMatchObject(attrs);
- });
-
- it('Passes event listeners', () => {
- expect(listeners.click).toHaveBeenCalledTimes(0);
-
- findContent().vm.$emit('click');
-
- expect(listeners.click).toHaveBeenCalledTimes(1);
- });
- });
-});
diff --git a/spec/frontend/runner/components/cells/runner_actions_cell_spec.js b/spec/frontend/runner/components/cells/runner_actions_cell_spec.js
deleted file mode 100644
index 58974d4f85f..00000000000
--- a/spec/frontend/runner/components/cells/runner_actions_cell_spec.js
+++ /dev/null
@@ -1,138 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-
-import RunnerActionsCell from '~/runner/components/cells/runner_actions_cell.vue';
-import RunnerPauseButton from '~/runner/components/runner_pause_button.vue';
-import RunnerEditButton from '~/runner/components/runner_edit_button.vue';
-import RunnerDeleteButton from '~/runner/components/runner_delete_button.vue';
-import { allRunnersData } from '../../mock_data';
-
-const mockRunner = allRunnersData.data.runners.nodes[0];
-
-describe('RunnerActionsCell', () => {
- let wrapper;
-
- const findEditBtn = () => wrapper.findComponent(RunnerEditButton);
- const findRunnerPauseBtn = () => wrapper.findComponent(RunnerPauseButton);
- const findDeleteBtn = () => wrapper.findComponent(RunnerDeleteButton);
-
- const createComponent = ({ runner = {}, ...props } = {}) => {
- wrapper = shallowMountExtended(RunnerActionsCell, {
- propsData: {
- editUrl: mockRunner.editAdminUrl,
- runner: {
- id: mockRunner.id,
- shortSha: mockRunner.shortSha,
- editAdminUrl: mockRunner.editAdminUrl,
- userPermissions: mockRunner.userPermissions,
- ...runner,
- },
- ...props,
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('Edit Action', () => {
- it('Displays the runner edit link with the correct href', () => {
- createComponent();
-
- expect(findEditBtn().attributes('href')).toBe(mockRunner.editAdminUrl);
- });
-
- it('Does not render the runner edit link when user cannot update', () => {
- createComponent({
- runner: {
- userPermissions: {
- ...mockRunner.userPermissions,
- updateRunner: false,
- },
- },
- });
-
- expect(findEditBtn().exists()).toBe(false);
- });
-
- it('Does not render the runner edit link when editUrl is not provided', () => {
- createComponent({
- editUrl: null,
- });
-
- expect(findEditBtn().exists()).toBe(false);
- });
- });
-
- describe('Pause action', () => {
- it('Renders a compact pause button', () => {
- createComponent();
-
- expect(findRunnerPauseBtn().props('compact')).toBe(true);
- });
-
- it('Does not render the runner pause button when user cannot update', () => {
- createComponent({
- runner: {
- userPermissions: {
- ...mockRunner.userPermissions,
- updateRunner: false,
- },
- },
- });
-
- expect(findRunnerPauseBtn().exists()).toBe(false);
- });
- });
-
- describe('Delete action', () => {
- it('Renders a compact delete button', () => {
- createComponent();
-
- expect(findDeleteBtn().props('compact')).toBe(true);
- });
-
- it('Passes runner data to delete button', () => {
- createComponent({
- runner: mockRunner,
- });
-
- expect(findDeleteBtn().props('runner')).toEqual(mockRunner);
- });
-
- it('Emits toggledPaused events', () => {
- createComponent();
-
- expect(wrapper.emitted('toggledPaused')).toBe(undefined);
-
- findRunnerPauseBtn().vm.$emit('toggledPaused');
-
- expect(wrapper.emitted('toggledPaused')).toHaveLength(1);
- });
-
- it('Emits delete events', () => {
- const value = { name: 'Runner' };
-
- createComponent();
-
- expect(wrapper.emitted('deleted')).toBe(undefined);
-
- findDeleteBtn().vm.$emit('deleted', value);
-
- expect(wrapper.emitted('deleted')).toEqual([[value]]);
- });
-
- it('Does not render the runner delete button when user cannot delete', () => {
- createComponent({
- runner: {
- userPermissions: {
- ...mockRunner.userPermissions,
- deleteRunner: false,
- },
- },
- });
-
- expect(findDeleteBtn().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/runner/components/cells/runner_owner_cell_spec.js b/spec/frontend/runner/components/cells/runner_owner_cell_spec.js
deleted file mode 100644
index e9965d8855d..00000000000
--- a/spec/frontend/runner/components/cells/runner_owner_cell_spec.js
+++ /dev/null
@@ -1,111 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { GlLink } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-
-import RunnerOwnerCell from '~/runner/components/cells/runner_owner_cell.vue';
-
-import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '~/runner/constants';
-
-describe('RunnerOwnerCell', () => {
- let wrapper;
-
- const findLink = () => wrapper.findComponent(GlLink);
- const getLinkTooltip = () => getBinding(findLink().element, 'gl-tooltip').value;
-
- const createComponent = ({ runner } = {}) => {
- wrapper = shallowMount(RunnerOwnerCell, {
- directives: {
- GlTooltip: createMockDirective(),
- },
- propsData: {
- runner,
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('When its an instance runner', () => {
- beforeEach(() => {
- createComponent({
- runner: {
- runnerType: INSTANCE_TYPE,
- },
- });
- });
-
- it('shows an administrator label', () => {
- expect(findLink().exists()).toBe(false);
- expect(wrapper.text()).toBe(s__('Runners|Administrator'));
- });
- });
-
- describe('When its a group runner', () => {
- const mockName = 'Group 2';
- const mockFullName = 'Group 1 / Group 2';
- const mockWebUrl = '/group-1/group-2';
-
- beforeEach(() => {
- createComponent({
- runner: {
- runnerType: GROUP_TYPE,
- groups: {
- nodes: [
- {
- name: mockName,
- fullName: mockFullName,
- webUrl: mockWebUrl,
- },
- ],
- },
- },
- });
- });
-
- it('Displays a group link', () => {
- expect(findLink().attributes('href')).toBe(mockWebUrl);
- expect(wrapper.text()).toBe(mockName);
- expect(getLinkTooltip()).toBe(mockFullName);
- });
- });
-
- describe('When its a project runner', () => {
- const mockName = 'Project 1';
- const mockNameWithNamespace = 'Group 1 / Project 1';
- const mockWebUrl = '/group-1/project-1';
-
- beforeEach(() => {
- createComponent({
- runner: {
- runnerType: PROJECT_TYPE,
- ownerProject: {
- name: mockName,
- nameWithNamespace: mockNameWithNamespace,
- webUrl: mockWebUrl,
- },
- },
- });
- });
-
- it('Displays a project link', () => {
- expect(findLink().attributes('href')).toBe(mockWebUrl);
- expect(wrapper.text()).toBe(mockName);
- expect(getLinkTooltip()).toBe(mockNameWithNamespace);
- });
- });
-
- describe('When its an empty runner', () => {
- beforeEach(() => {
- createComponent({
- runner: {},
- });
- });
-
- it('shows no label', () => {
- expect(wrapper.text()).toBe('');
- });
- });
-});
diff --git a/spec/frontend/runner/components/cells/runner_stacked_summary_cell_spec.js b/spec/frontend/runner/components/cells/runner_stacked_summary_cell_spec.js
deleted file mode 100644
index e7cadefc140..00000000000
--- a/spec/frontend/runner/components/cells/runner_stacked_summary_cell_spec.js
+++ /dev/null
@@ -1,164 +0,0 @@
-import { __ } from '~/locale';
-import { mountExtended } from 'helpers/vue_test_utils_helper';
-import RunnerStackedSummaryCell from '~/runner/components/cells/runner_stacked_summary_cell.vue';
-import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
-import RunnerTags from '~/runner/components/runner_tags.vue';
-import RunnerSummaryField from '~/runner/components/cells/runner_summary_field.vue';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-
-import { INSTANCE_TYPE, I18N_INSTANCE_TYPE, PROJECT_TYPE } from '~/runner/constants';
-
-import { allRunnersData } from '../../mock_data';
-
-const mockRunner = allRunnersData.data.runners.nodes[0];
-
-describe('RunnerTypeCell', () => {
- let wrapper;
-
- const findLockIcon = () => wrapper.findByTestId('lock-icon');
- const findRunnerTags = () => wrapper.findComponent(RunnerTags);
- const findRunnerSummaryField = (icon) =>
- wrapper.findAllComponents(RunnerSummaryField).filter((w) => w.props('icon') === icon)
- .wrappers[0];
-
- const createComponent = (runner, options) => {
- wrapper = mountExtended(RunnerStackedSummaryCell, {
- propsData: {
- runner: {
- ...mockRunner,
- ...runner,
- },
- },
- stubs: {
- RunnerSummaryField,
- },
- ...options,
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Displays the runner name as id and short token', () => {
- expect(wrapper.text()).toContain(
- `#${getIdFromGraphQLId(mockRunner.id)} (${mockRunner.shortSha})`,
- );
- });
-
- it('Does not display the locked icon', () => {
- expect(findLockIcon().exists()).toBe(false);
- });
-
- it('Displays the locked icon for locked runners', () => {
- createComponent({
- runnerType: PROJECT_TYPE,
- locked: true,
- });
-
- expect(findLockIcon().exists()).toBe(true);
- });
-
- it('Displays the runner type', () => {
- createComponent({
- runnerType: INSTANCE_TYPE,
- locked: true,
- });
-
- expect(wrapper.text()).toContain(I18N_INSTANCE_TYPE);
- });
-
- it('Displays the runner version', () => {
- expect(wrapper.text()).toContain(mockRunner.version);
- });
-
- it('Displays the runner description', () => {
- expect(wrapper.text()).toContain(mockRunner.description);
- });
-
- it('Displays last contact', () => {
- createComponent({
- contactedAt: '2022-01-02',
- });
-
- expect(findRunnerSummaryField('clock').findComponent(TimeAgo).props('time')).toBe('2022-01-02');
- });
-
- it('Displays empty last contact', () => {
- createComponent({
- contactedAt: null,
- });
-
- expect(findRunnerSummaryField('clock').findComponent(TimeAgo).exists()).toBe(false);
- expect(findRunnerSummaryField('clock').text()).toContain(__('Never'));
- });
-
- it('Displays ip address', () => {
- createComponent({
- ipAddress: '127.0.0.1',
- });
-
- expect(findRunnerSummaryField('disk').text()).toContain('127.0.0.1');
- });
-
- it('Displays no ip address', () => {
- createComponent({
- ipAddress: null,
- });
-
- expect(findRunnerSummaryField('disk')).toBeUndefined();
- });
-
- it('Displays job count', () => {
- expect(findRunnerSummaryField('pipeline').text()).toContain(`${mockRunner.jobCount}`);
- });
-
- it('Formats large job counts', () => {
- createComponent({
- jobCount: 1000,
- });
-
- expect(findRunnerSummaryField('pipeline').text()).toContain('1,000');
- });
-
- it('Formats large job counts with a plus symbol', () => {
- createComponent({
- jobCount: 1001,
- });
-
- expect(findRunnerSummaryField('pipeline').text()).toContain('1,000+');
- });
-
- it('Displays created at', () => {
- expect(findRunnerSummaryField('calendar').findComponent(TimeAgo).props('time')).toBe(
- mockRunner.createdAt,
- );
- });
-
- it('Displays tag list', () => {
- createComponent({
- tagList: ['shell', 'linux'],
- });
-
- expect(findRunnerTags().props('tagList')).toEqual(['shell', 'linux']);
- });
-
- it('Displays a custom slot', () => {
- const slotContent = 'My custom runner name';
-
- createComponent(
- {},
- {
- slots: {
- 'runner-name': slotContent,
- },
- },
- );
-
- expect(wrapper.text()).toContain(slotContent);
- });
-});
diff --git a/spec/frontend/runner/components/cells/runner_status_cell_spec.js b/spec/frontend/runner/components/cells/runner_status_cell_spec.js
deleted file mode 100644
index 1d4e3762c91..00000000000
--- a/spec/frontend/runner/components/cells/runner_status_cell_spec.js
+++ /dev/null
@@ -1,77 +0,0 @@
-import { mount } from '@vue/test-utils';
-import RunnerStatusCell from '~/runner/components/cells/runner_status_cell.vue';
-
-import RunnerStatusBadge from '~/runner/components/runner_status_badge.vue';
-import RunnerPausedBadge from '~/runner/components/runner_paused_badge.vue';
-import {
- I18N_PAUSED,
- I18N_STATUS_ONLINE,
- I18N_STATUS_OFFLINE,
- INSTANCE_TYPE,
- STATUS_ONLINE,
- STATUS_OFFLINE,
-} from '~/runner/constants';
-
-describe('RunnerStatusCell', () => {
- let wrapper;
-
- const findStatusBadge = () => wrapper.findComponent(RunnerStatusBadge);
- const findPausedBadge = () => wrapper.findComponent(RunnerPausedBadge);
-
- const createComponent = ({ runner = {} } = {}) => {
- wrapper = mount(RunnerStatusCell, {
- propsData: {
- runner: {
- runnerType: INSTANCE_TYPE,
- active: true,
- status: STATUS_ONLINE,
- ...runner,
- },
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Displays online status', () => {
- createComponent();
-
- expect(wrapper.text()).toContain(I18N_STATUS_ONLINE);
- expect(findStatusBadge().text()).toBe(I18N_STATUS_ONLINE);
- });
-
- it('Displays offline status', () => {
- createComponent({
- runner: {
- status: STATUS_OFFLINE,
- },
- });
-
- expect(wrapper.text()).toMatchInterpolatedText(I18N_STATUS_OFFLINE);
- expect(findStatusBadge().text()).toBe(I18N_STATUS_OFFLINE);
- });
-
- it('Displays paused status', () => {
- createComponent({
- runner: {
- active: false,
- status: STATUS_ONLINE,
- },
- });
-
- expect(wrapper.text()).toMatchInterpolatedText(`${I18N_STATUS_ONLINE} ${I18N_PAUSED}`);
- expect(findPausedBadge().text()).toBe(I18N_PAUSED);
- });
-
- it('Is empty when data is missing', () => {
- createComponent({
- runner: {
- status: null,
- },
- });
-
- expect(wrapper.text()).toBe('');
- });
-});
diff --git a/spec/frontend/runner/components/cells/runner_summary_field_spec.js b/spec/frontend/runner/components/cells/runner_summary_field_spec.js
deleted file mode 100644
index b49addf112f..00000000000
--- a/spec/frontend/runner/components/cells/runner_summary_field_spec.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import { GlIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import RunnerSummaryField from '~/runner/components/cells/runner_summary_field.vue';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-
-describe('RunnerSummaryField', () => {
- let wrapper;
-
- const findIcon = () => wrapper.findComponent(GlIcon);
- const getTooltipValue = () => getBinding(wrapper.element, 'gl-tooltip').value;
-
- const createComponent = ({ props, ...options } = {}) => {
- wrapper = shallowMount(RunnerSummaryField, {
- propsData: {
- icon: '',
- tooltip: '',
- ...props,
- },
- directives: {
- GlTooltip: createMockDirective(),
- },
- ...options,
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('shows content in slot', () => {
- createComponent({
- slots: { default: 'content' },
- });
-
- expect(wrapper.text()).toBe('content');
- });
-
- it('shows icon', () => {
- createComponent({ props: { icon: 'git' } });
-
- expect(findIcon().props('name')).toBe('git');
- });
-
- it('shows tooltip', () => {
- createComponent({ props: { tooltip: 'tooltip' } });
-
- expect(getTooltipValue()).toBe('tooltip');
- });
-});
diff --git a/spec/frontend/runner/components/registration/registration_dropdown_spec.js b/spec/frontend/runner/components/registration/registration_dropdown_spec.js
deleted file mode 100644
index d3f38bc1d26..00000000000
--- a/spec/frontend/runner/components/registration/registration_dropdown_spec.js
+++ /dev/null
@@ -1,198 +0,0 @@
-import { GlModal, GlDropdown, GlDropdownItem, GlDropdownForm } from '@gitlab/ui';
-import { mount, shallowMount, createWrapper } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
-
-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 RegistrationDropdown from '~/runner/components/registration/registration_dropdown.vue';
-import RegistrationToken from '~/runner/components/registration/registration_token.vue';
-import RegistrationTokenResetDropdownItem from '~/runner/components/registration/registration_token_reset_dropdown_item.vue';
-
-import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '~/runner/constants';
-
-import getRunnerPlatformsQuery from '~/vue_shared/components/runner_instructions/graphql/queries/get_runner_platforms.query.graphql';
-import getRunnerSetupInstructionsQuery from '~/vue_shared/components/runner_instructions/graphql/queries/get_runner_setup.query.graphql';
-
-import {
- mockGraphqlRunnerPlatforms,
- mockGraphqlInstructions,
-} from 'jest/vue_shared/components/runner_instructions/mock_data';
-
-const mockToken = '0123456789';
-const maskToken = '**********';
-
-Vue.use(VueApollo);
-
-describe('RegistrationDropdown', () => {
- let wrapper;
-
- const findDropdown = () => wrapper.findComponent(GlDropdown);
-
- const findRegistrationInstructionsDropdownItem = () => wrapper.findComponent(GlDropdownItem);
- const findTokenDropdownItem = () => wrapper.findComponent(GlDropdownForm);
- const findRegistrationToken = () => wrapper.findComponent(RegistrationToken);
- const findRegistrationTokenInput = () =>
- wrapper.findByLabelText(RegistrationToken.i18n.registrationToken);
- const findTokenResetDropdownItem = () =>
- wrapper.findComponent(RegistrationTokenResetDropdownItem);
- const findModal = () => wrapper.findComponent(GlModal);
- const findModalContent = () =>
- createWrapper(document.body)
- .find('[data-testid="runner-instructions-modal"]')
- .text()
- .replace(/[\n\t\s]+/g, ' ');
-
- const openModal = async () => {
- await findRegistrationInstructionsDropdownItem().trigger('click');
- findModal().vm.$emit('shown');
-
- await waitForPromises();
- };
-
- const createComponent = ({ props = {}, ...options } = {}, mountFn = shallowMount) => {
- wrapper = extendedWrapper(
- mountFn(RegistrationDropdown, {
- propsData: {
- registrationToken: mockToken,
- type: INSTANCE_TYPE,
- ...props,
- },
- ...options,
- }),
- );
- };
-
- const createComponentWithModal = () => {
- const requestHandlers = [
- [getRunnerPlatformsQuery, jest.fn().mockResolvedValue(mockGraphqlRunnerPlatforms)],
- [getRunnerSetupInstructionsQuery, jest.fn().mockResolvedValue(mockGraphqlInstructions)],
- ];
-
- createComponent(
- {
- // Mock load modal contents from API
- apolloProvider: createMockApollo(requestHandlers),
- // Use `attachTo` to find the modal
- attachTo: document.body,
- },
- mount,
- );
- };
-
- it.each`
- type | text
- ${INSTANCE_TYPE} | ${'Register an instance runner'}
- ${GROUP_TYPE} | ${'Register a group runner'}
- ${PROJECT_TYPE} | ${'Register a project runner'}
- `('Dropdown text for type $type is "$text"', () => {
- createComponent({ props: { type: INSTANCE_TYPE } }, mount);
-
- expect(wrapper.text()).toContain('Register an instance runner');
- });
-
- it('Passes attributes to the dropdown component', () => {
- createComponent({ attrs: { right: true } });
-
- expect(findDropdown().attributes()).toMatchObject({ right: 'true' });
- });
-
- describe('Instructions dropdown item', () => {
- it('Displays "Show runner" dropdown item', () => {
- createComponent();
-
- expect(findRegistrationInstructionsDropdownItem().text()).toBe(
- 'Show runner installation and registration instructions',
- );
- });
-
- describe('When the dropdown item is clicked', () => {
- beforeEach(async () => {
- createComponentWithModal({}, mount);
-
- await openModal();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('opens the modal with contents', () => {
- const modalText = findModalContent();
-
- expect(modalText).toContain('Install a runner');
-
- // Environment selector
- expect(modalText).toContain('Environment');
- expect(modalText).toContain('Linux macOS Windows Docker Kubernetes');
-
- // Architecture selector
- expect(modalText).toContain('Architecture');
- expect(modalText).toContain('amd64 amd64 386 arm arm64');
-
- expect(modalText).toContain('Download and install binary');
- });
- });
- });
-
- describe('Registration token', () => {
- it('Displays dropdown form for the registration token', () => {
- createComponent();
-
- expect(findTokenDropdownItem().exists()).toBe(true);
- });
-
- it('Displays masked value by default', () => {
- createComponent({}, mount);
-
- expect(findRegistrationTokenInput().element.value).toBe(maskToken);
- });
- });
-
- describe('Reset token item', () => {
- it('Displays registration token reset item', () => {
- createComponent();
-
- expect(findTokenResetDropdownItem().exists()).toBe(true);
- });
-
- it.each([INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE])('Set up token reset for %s', (type) => {
- createComponent({ props: { type } });
-
- expect(findTokenResetDropdownItem().props('type')).toBe(type);
- });
- });
-
- describe('When token is reset', () => {
- const newToken = 'mock1';
-
- const resetToken = async () => {
- findTokenResetDropdownItem().vm.$emit('tokenReset', newToken);
- await nextTick();
- };
-
- it('Updates token input', async () => {
- createComponent({}, mount);
-
- expect(findRegistrationToken().props('value')).not.toBe(newToken);
-
- await resetToken();
-
- expect(findRegistrationToken().props('value')).toBe(newToken);
- });
-
- it('Updates token in modal', async () => {
- createComponentWithModal({}, mount);
-
- await openModal();
-
- expect(findModalContent()).toContain(mockToken);
-
- await resetToken();
-
- expect(findModalContent()).toContain(newToken);
- });
- });
-});
diff --git a/spec/frontend/runner/components/registration/registration_token_reset_dropdown_item_spec.js b/spec/frontend/runner/components/registration/registration_token_reset_dropdown_item_spec.js
deleted file mode 100644
index 2510aaf0334..00000000000
--- a/spec/frontend/runner/components/registration/registration_token_reset_dropdown_item_spec.js
+++ /dev/null
@@ -1,209 +0,0 @@
-import { GlDropdownItem, GlLoadingIcon, GlToast, GlModal } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
-
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
-import RegistrationTokenResetDropdownItem from '~/runner/components/registration/registration_token_reset_dropdown_item.vue';
-import { INSTANCE_TYPE, GROUP_TYPE, PROJECT_TYPE } from '~/runner/constants';
-import runnersRegistrationTokenResetMutation from '~/runner/graphql/list/runners_registration_token_reset.mutation.graphql';
-import { captureException } from '~/runner/sentry_utils';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-
-jest.mock('~/flash');
-jest.mock('~/runner/sentry_utils');
-
-Vue.use(VueApollo);
-Vue.use(GlToast);
-
-const mockNewToken = 'NEW_TOKEN';
-const modalID = 'token-reset-modal';
-
-describe('RegistrationTokenResetDropdownItem', () => {
- let wrapper;
- let runnersRegistrationTokenResetMutationHandler;
- let showToast;
-
- const mockEvent = { preventDefault: jest.fn() };
- const findDropdownItem = () => wrapper.findComponent(GlDropdownItem);
- const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
- const findModal = () => wrapper.findComponent(GlModal);
- const clickSubmit = () => findModal().vm.$emit('primary', mockEvent);
-
- const createComponent = ({ props, provide = {} } = {}) => {
- wrapper = shallowMount(RegistrationTokenResetDropdownItem, {
- provide,
- propsData: {
- type: INSTANCE_TYPE,
- ...props,
- },
- apolloProvider: createMockApollo([
- [runnersRegistrationTokenResetMutation, runnersRegistrationTokenResetMutationHandler],
- ]),
- directives: {
- GlModal: createMockDirective(),
- },
- });
-
- showToast = wrapper.vm.$toast ? jest.spyOn(wrapper.vm.$toast, 'show') : null;
- };
-
- beforeEach(() => {
- runnersRegistrationTokenResetMutationHandler = jest.fn().mockResolvedValue({
- data: {
- runnersRegistrationTokenReset: {
- token: mockNewToken,
- errors: [],
- },
- },
- });
-
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Displays reset button', () => {
- expect(findDropdownItem().exists()).toBe(true);
- });
-
- describe('modal directive integration', () => {
- it('has the correct ID on the dropdown', () => {
- const binding = getBinding(findDropdownItem().element, 'gl-modal');
-
- expect(binding.value).toBe(modalID);
- });
-
- it('has the correct ID on the modal', () => {
- expect(findModal().props('modalId')).toBe(modalID);
- });
- });
-
- describe('On click and confirmation', () => {
- const mockGroupId = '11';
- const mockProjectId = '22';
-
- describe.each`
- type | provide | expectedInput
- ${INSTANCE_TYPE} | ${{}} | ${{ type: INSTANCE_TYPE }}
- ${GROUP_TYPE} | ${{ groupId: mockGroupId }} | ${{ type: GROUP_TYPE, id: `gid://gitlab/Group/${mockGroupId}` }}
- ${PROJECT_TYPE} | ${{ projectId: mockProjectId }} | ${{ type: PROJECT_TYPE, id: `gid://gitlab/Project/${mockProjectId}` }}
- `('Resets token of type $type', ({ type, provide, expectedInput }) => {
- beforeEach(async () => {
- createComponent({
- provide,
- props: { type },
- });
-
- findDropdownItem().trigger('click');
- clickSubmit();
- await waitForPromises();
- });
-
- it('resets token', () => {
- expect(runnersRegistrationTokenResetMutationHandler).toHaveBeenCalledTimes(1);
- expect(runnersRegistrationTokenResetMutationHandler).toHaveBeenCalledWith({
- input: expectedInput,
- });
- });
-
- it('emits result', () => {
- expect(wrapper.emitted('tokenReset')).toHaveLength(1);
- expect(wrapper.emitted('tokenReset')[0]).toEqual([mockNewToken]);
- });
-
- it('does not show a loading state', () => {
- expect(findLoadingIcon().exists()).toBe(false);
- });
-
- it('shows confirmation', () => {
- expect(showToast).toHaveBeenLastCalledWith(
- expect.stringContaining('registration token generated'),
- );
- });
- });
- });
-
- describe('On click without confirmation', () => {
- beforeEach(async () => {
- findDropdownItem().vm.$emit('click');
- await waitForPromises();
- });
-
- it('does not reset token', () => {
- expect(runnersRegistrationTokenResetMutationHandler).not.toHaveBeenCalled();
- });
-
- it('does not emit any result', () => {
- expect(wrapper.emitted('tokenReset')).toBeUndefined();
- });
-
- it('does not show a loading state', () => {
- expect(findLoadingIcon().exists()).toBe(false);
- });
-
- it('does not shows confirmation', () => {
- expect(showToast).not.toHaveBeenCalled();
- });
- });
-
- describe('On error', () => {
- it('On network error, error message is shown', async () => {
- const mockErrorMsg = 'Token reset failed!';
-
- runnersRegistrationTokenResetMutationHandler.mockRejectedValueOnce(new Error(mockErrorMsg));
-
- findDropdownItem().trigger('click');
- clickSubmit();
- await waitForPromises();
-
- expect(createAlert).toHaveBeenLastCalledWith({
- message: mockErrorMsg,
- });
- expect(captureException).toHaveBeenCalledWith({
- error: new Error(mockErrorMsg),
- component: 'RunnerRegistrationTokenReset',
- });
- });
-
- it('On validation error, error message is shown', async () => {
- const mockErrorMsg = 'User not allowed!';
- const mockErrorMsg2 = 'Type is not valid!';
-
- runnersRegistrationTokenResetMutationHandler.mockResolvedValue({
- data: {
- runnersRegistrationTokenReset: {
- token: null,
- errors: [mockErrorMsg, mockErrorMsg2],
- },
- },
- });
-
- findDropdownItem().trigger('click');
- clickSubmit();
- await waitForPromises();
-
- expect(createAlert).toHaveBeenLastCalledWith({
- message: `${mockErrorMsg} ${mockErrorMsg2}`,
- });
- expect(captureException).toHaveBeenCalledWith({
- error: new Error(`${mockErrorMsg} ${mockErrorMsg2}`),
- component: 'RunnerRegistrationTokenReset',
- });
- });
- });
-
- describe('Immediately after click', () => {
- it('shows loading state', async () => {
- findDropdownItem().trigger('click');
- clickSubmit();
- await nextTick();
-
- expect(findLoadingIcon().exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/runner/components/registration/registration_token_spec.js b/spec/frontend/runner/components/registration/registration_token_spec.js
deleted file mode 100644
index 19344a68f79..00000000000
--- a/spec/frontend/runner/components/registration/registration_token_spec.js
+++ /dev/null
@@ -1,62 +0,0 @@
-import { GlToast } from '@gitlab/ui';
-import Vue from 'vue';
-import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import RegistrationToken from '~/runner/components/registration/registration_token.vue';
-import InputCopyToggleVisibility from '~/vue_shared/components/form/input_copy_toggle_visibility.vue';
-
-const mockToken = '01234567890';
-const mockMasked = '***********';
-
-describe('RegistrationToken', () => {
- let wrapper;
- let showToast;
-
- Vue.use(GlToast);
-
- const findInputCopyToggleVisibility = () => wrapper.findComponent(InputCopyToggleVisibility);
-
- const createComponent = ({ props = {}, mountFn = shallowMountExtended } = {}) => {
- wrapper = mountFn(RegistrationToken, {
- propsData: {
- value: mockToken,
- inputId: 'token-value',
- ...props,
- },
- });
-
- showToast = wrapper.vm.$toast ? jest.spyOn(wrapper.vm.$toast, 'show') : null;
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Displays value and copy button', () => {
- createComponent();
-
- expect(findInputCopyToggleVisibility().props('value')).toBe(mockToken);
- expect(findInputCopyToggleVisibility().props('copyButtonTitle')).toBe(
- 'Copy registration token',
- );
- });
-
- // Component integration test to ensure secure masking
- it('Displays masked value by default', () => {
- createComponent({ mountFn: mountExtended });
-
- expect(wrapper.find('input').element.value).toBe(mockMasked);
- });
-
- describe('When the copy to clipboard button is clicked', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('shows a copied message', () => {
- findInputCopyToggleVisibility().vm.$emit('copy');
-
- expect(showToast).toHaveBeenCalledTimes(1);
- expect(showToast).toHaveBeenCalledWith('Registration token copied!');
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_assigned_item_spec.js b/spec/frontend/runner/components/runner_assigned_item_spec.js
deleted file mode 100644
index cc09046c000..00000000000
--- a/spec/frontend/runner/components/runner_assigned_item_spec.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import { GlAvatar, GlBadge } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import RunnerAssignedItem from '~/runner/components/runner_assigned_item.vue';
-import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants';
-
-const mockHref = '/group/project';
-const mockName = 'Project';
-const mockDescription = 'Project description';
-const mockFullName = 'Group / Project';
-const mockAvatarUrl = '/avatar.png';
-
-describe('RunnerAssignedItem', () => {
- let wrapper;
-
- const findAvatar = () => wrapper.findByTestId('item-avatar');
- const findBadge = () => wrapper.findComponent(GlBadge);
-
- const createComponent = ({ props = {} } = {}) => {
- wrapper = shallowMountExtended(RunnerAssignedItem, {
- propsData: {
- href: mockHref,
- name: mockName,
- fullName: mockFullName,
- avatarUrl: mockAvatarUrl,
- description: mockDescription,
- ...props,
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Shows an avatar', () => {
- const avatar = findAvatar();
-
- expect(avatar.attributes('href')).toBe(mockHref);
- expect(avatar.findComponent(GlAvatar).props()).toMatchObject({
- alt: mockName,
- entityName: mockName,
- src: mockAvatarUrl,
- shape: AVATAR_SHAPE_OPTION_RECT,
- size: 48,
- });
- });
-
- it('Shows an item link', () => {
- const groupFullName = wrapper.findByText(mockFullName);
-
- expect(groupFullName.attributes('href')).toBe(mockHref);
- });
-
- it('Shows description', () => {
- expect(wrapper.text()).toContain(mockDescription);
- });
-
- it('Shows owner badge', () => {
- createComponent({ props: { isOwner: true } });
-
- expect(findBadge().text()).toBe(s__('Runner|Owner'));
- });
-});
diff --git a/spec/frontend/runner/components/runner_bulk_delete_checkbox_spec.js b/spec/frontend/runner/components/runner_bulk_delete_checkbox_spec.js
deleted file mode 100644
index 424a4e61ccd..00000000000
--- a/spec/frontend/runner/components/runner_bulk_delete_checkbox_spec.js
+++ /dev/null
@@ -1,140 +0,0 @@
-import Vue from 'vue';
-import { GlFormCheckbox } from '@gitlab/ui';
-import VueApollo from 'vue-apollo';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import RunnerBulkDeleteCheckbox from '~/runner/components/runner_bulk_delete_checkbox.vue';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import { createLocalState } from '~/runner/graphql/list/local_state';
-
-Vue.use(VueApollo);
-
-const makeRunner = (id, deleteRunner = true) => ({
- id,
- userPermissions: { deleteRunner },
-});
-
-// Multi-select checkbox possible states:
-const stateToAttrs = {
- unchecked: { disabled: undefined, checked: undefined, indeterminate: undefined },
- checked: { disabled: undefined, checked: 'true', indeterminate: undefined },
- indeterminate: { disabled: undefined, checked: undefined, indeterminate: 'true' },
- disabled: { disabled: 'true', checked: undefined, indeterminate: undefined },
-};
-
-describe('RunnerBulkDeleteCheckbox', () => {
- let wrapper;
- let mockState;
- let mockCheckedRunnerIds;
-
- const findCheckbox = () => wrapper.findComponent(GlFormCheckbox);
-
- const expectCheckboxToBe = (state) => {
- const expected = stateToAttrs[state];
- expect(findCheckbox().attributes('disabled')).toBe(expected.disabled);
- expect(findCheckbox().attributes('checked')).toBe(expected.checked);
- expect(findCheckbox().attributes('indeterminate')).toBe(expected.indeterminate);
- };
-
- const createComponent = ({ runners = [] } = {}) => {
- const { cacheConfig, localMutations } = mockState;
- const apolloProvider = createMockApollo(undefined, undefined, cacheConfig);
-
- wrapper = shallowMountExtended(RunnerBulkDeleteCheckbox, {
- apolloProvider,
- provide: {
- localMutations,
- },
- propsData: {
- runners,
- },
- });
- };
-
- beforeEach(() => {
- mockState = createLocalState();
-
- jest
- .spyOn(mockState.cacheConfig.typePolicies.Query.fields, 'checkedRunnerIds')
- .mockImplementation(() => mockCheckedRunnerIds);
-
- jest.spyOn(mockState.localMutations, 'setRunnersChecked');
- });
-
- describe('when all runners can be deleted', () => {
- const mockIds = ['1', '2', '3'];
- const mockIdAnotherPage = '4';
- const mockRunners = mockIds.map((id) => makeRunner(id));
-
- it.each`
- case | checkedRunnerIds | state
- ${'no runners'} | ${[]} | ${'unchecked'}
- ${'no runners in this page'} | ${[mockIdAnotherPage]} | ${'unchecked'}
- ${'all runners'} | ${mockIds} | ${'checked'}
- ${'some runners'} | ${[mockIds[0]]} | ${'indeterminate'}
- ${'all plus other runners'} | ${[...mockIds, mockIdAnotherPage]} | ${'checked'}
- `('if $case are checked, checkbox is $state', ({ checkedRunnerIds, state }) => {
- mockCheckedRunnerIds = checkedRunnerIds;
-
- createComponent({ runners: mockRunners });
- expectCheckboxToBe(state);
- });
- });
-
- describe('when some runners cannot be deleted', () => {
- it('all allowed runners are selected, checkbox is checked', () => {
- mockCheckedRunnerIds = ['a', 'b', 'c'];
- createComponent({
- runners: [makeRunner('a'), makeRunner('b'), makeRunner('c', false)],
- });
-
- expectCheckboxToBe('checked');
- });
-
- it('some allowed runners are selected, checkbox is indeterminate', () => {
- mockCheckedRunnerIds = ['a', 'b'];
- createComponent({
- runners: [makeRunner('a'), makeRunner('b'), makeRunner('c')],
- });
-
- expectCheckboxToBe('indeterminate');
- });
-
- it('no allowed runners are selected, checkbox is disabled', () => {
- mockCheckedRunnerIds = ['a', 'b'];
- createComponent({
- runners: [makeRunner('a', false), makeRunner('b', false)],
- });
-
- expectCheckboxToBe('disabled');
- });
- });
-
- describe('When user selects', () => {
- const mockRunners = [makeRunner('1'), makeRunner('2')];
-
- beforeEach(() => {
- mockCheckedRunnerIds = ['1', '2'];
- createComponent({ runners: mockRunners });
- });
-
- it.each([[true], [false]])('sets checked to %s', (checked) => {
- findCheckbox().vm.$emit('change', checked);
-
- expect(mockState.localMutations.setRunnersChecked).toHaveBeenCalledTimes(1);
- expect(mockState.localMutations.setRunnersChecked).toHaveBeenCalledWith({
- isChecked: checked,
- runners: mockRunners,
- });
- });
- });
-
- describe('When runners are loading', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('is disabled', () => {
- expectCheckboxToBe('disabled');
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_bulk_delete_spec.js b/spec/frontend/runner/components/runner_bulk_delete_spec.js
deleted file mode 100644
index 6df918c684f..00000000000
--- a/spec/frontend/runner/components/runner_bulk_delete_spec.js
+++ /dev/null
@@ -1,243 +0,0 @@
-import Vue from 'vue';
-import { GlModal, GlSprintf } from '@gitlab/ui';
-import VueApollo from 'vue-apollo';
-import { createAlert } from '~/flash';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { s__ } from '~/locale';
-import RunnerBulkDelete from '~/runner/components/runner_bulk_delete.vue';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import BulkRunnerDeleteMutation from '~/runner/graphql/list/bulk_runner_delete.mutation.graphql';
-import { createLocalState } from '~/runner/graphql/list/local_state';
-import waitForPromises from 'helpers/wait_for_promises';
-import { allRunnersData } from '../mock_data';
-
-Vue.use(VueApollo);
-
-jest.mock('~/flash');
-
-describe('RunnerBulkDelete', () => {
- let wrapper;
- let apolloCache;
- let mockState;
- let mockCheckedRunnerIds;
-
- const findClearBtn = () => wrapper.findByText(s__('Runners|Clear selection'));
- const findDeleteBtn = () => wrapper.findByText(s__('Runners|Delete selected'));
- const findModal = () => wrapper.findComponent(GlModal);
-
- const mockRunners = allRunnersData.data.runners.nodes;
- const mockId1 = allRunnersData.data.runners.nodes[0].id;
- const mockId2 = allRunnersData.data.runners.nodes[1].id;
-
- const bulkRunnerDeleteHandler = jest.fn();
-
- const createComponent = () => {
- const { cacheConfig, localMutations } = mockState;
- const apolloProvider = createMockApollo(
- [[BulkRunnerDeleteMutation, bulkRunnerDeleteHandler]],
- undefined,
- cacheConfig,
- );
-
- wrapper = shallowMountExtended(RunnerBulkDelete, {
- apolloProvider,
- provide: {
- localMutations,
- },
- propsData: {
- runners: mockRunners,
- },
- directives: {
- GlTooltip: createMockDirective(),
- },
- stubs: {
- GlSprintf,
- GlModal,
- },
- });
-
- apolloCache = apolloProvider.defaultClient.cache;
- jest.spyOn(apolloCache, 'evict');
- jest.spyOn(apolloCache, 'gc');
- };
-
- beforeEach(() => {
- mockState = createLocalState();
-
- jest
- .spyOn(mockState.cacheConfig.typePolicies.Query.fields, 'checkedRunnerIds')
- .mockImplementation(() => mockCheckedRunnerIds);
- });
-
- afterEach(() => {
- bulkRunnerDeleteHandler.mockReset();
- wrapper.destroy();
- });
-
- describe('When no runners are checked', () => {
- beforeEach(async () => {
- mockCheckedRunnerIds = [];
-
- createComponent();
-
- await waitForPromises();
- });
-
- it('shows no contents', () => {
- expect(wrapper.html()).toBe('');
- });
- });
-
- describe.each`
- count | ids | text
- ${1} | ${[mockId1]} | ${'1 runner'}
- ${2} | ${[mockId1, mockId2]} | ${'2 runners'}
- `('When $count runner(s) are checked', ({ ids, text }) => {
- beforeEach(() => {
- mockCheckedRunnerIds = ids;
-
- createComponent();
-
- jest.spyOn(mockState.localMutations, 'clearChecked').mockImplementation(() => {});
- });
-
- it(`shows "${text}"`, () => {
- expect(wrapper.text()).toContain(text);
- });
-
- it('clears selection', () => {
- expect(mockState.localMutations.clearChecked).toHaveBeenCalledTimes(0);
-
- findClearBtn().vm.$emit('click');
-
- expect(mockState.localMutations.clearChecked).toHaveBeenCalledTimes(1);
- });
-
- it('shows confirmation modal', () => {
- const modalId = getBinding(findDeleteBtn().element, 'gl-modal');
-
- expect(findModal().props('modal-id')).toBe(modalId);
- expect(findModal().text()).toContain(text);
- });
- });
-
- describe('when runners are deleted', () => {
- let evt;
- let mockHideModal;
-
- beforeEach(() => {
- mockCheckedRunnerIds = [mockId1, mockId2];
-
- createComponent();
-
- jest.spyOn(mockState.localMutations, 'clearChecked').mockImplementation(() => {});
- mockHideModal = jest.spyOn(findModal().vm, 'hide');
- });
-
- describe('when deletion is successful', () => {
- beforeEach(() => {
- bulkRunnerDeleteHandler.mockResolvedValue({
- data: {
- bulkRunnerDelete: { deletedIds: mockCheckedRunnerIds, errors: [] },
- },
- });
-
- evt = {
- preventDefault: jest.fn(),
- };
- findModal().vm.$emit('primary', evt);
- });
-
- it('has loading state', async () => {
- expect(findModal().props('actionPrimary').attributes.loading).toBe(true);
- expect(findModal().props('actionCancel').attributes.loading).toBe(true);
-
- await waitForPromises();
-
- expect(findModal().props('actionPrimary').attributes.loading).toBe(false);
- expect(findModal().props('actionCancel').attributes.loading).toBe(false);
- });
-
- it('modal is not prevented from closing', () => {
- expect(evt.preventDefault).toHaveBeenCalledTimes(1);
- });
-
- it('mutation is called', async () => {
- expect(bulkRunnerDeleteHandler).toHaveBeenCalledWith({
- input: { ids: mockCheckedRunnerIds },
- });
- });
-
- it('user interface is updated', async () => {
- const { evict, gc } = apolloCache;
-
- expect(evict).toHaveBeenCalledTimes(mockCheckedRunnerIds.length);
- expect(evict).toHaveBeenCalledWith({
- id: expect.stringContaining(mockCheckedRunnerIds[0]),
- });
- expect(evict).toHaveBeenCalledWith({
- id: expect.stringContaining(mockCheckedRunnerIds[1]),
- });
-
- expect(gc).toHaveBeenCalledTimes(1);
- });
-
- it('modal is hidden', () => {
- expect(mockHideModal).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('when deletion fails', () => {
- beforeEach(() => {
- bulkRunnerDeleteHandler.mockRejectedValue(new Error('error!'));
-
- evt = {
- preventDefault: jest.fn(),
- };
- findModal().vm.$emit('primary', evt);
- });
-
- it('has loading state', async () => {
- expect(findModal().props('actionPrimary').attributes.loading).toBe(true);
- expect(findModal().props('actionCancel').attributes.loading).toBe(true);
-
- await waitForPromises();
-
- expect(findModal().props('actionPrimary').attributes.loading).toBe(false);
- expect(findModal().props('actionCancel').attributes.loading).toBe(false);
- });
-
- it('modal is not prevented from closing', () => {
- expect(evt.preventDefault).toHaveBeenCalledTimes(1);
- });
-
- it('mutation is called', () => {
- expect(bulkRunnerDeleteHandler).toHaveBeenCalledWith({
- input: { ids: mockCheckedRunnerIds },
- });
- });
-
- it('user interface is not updated', async () => {
- await waitForPromises();
-
- const { evict, gc } = apolloCache;
-
- expect(evict).not.toHaveBeenCalled();
- expect(gc).not.toHaveBeenCalled();
- expect(mockState.localMutations.clearChecked).not.toHaveBeenCalled();
- });
-
- it('alert is called', async () => {
- await waitForPromises();
-
- expect(createAlert).toHaveBeenCalled();
- expect(createAlert).toHaveBeenCalledWith({
- message: expect.any(String),
- captureError: true,
- error: expect.any(Error),
- });
- });
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_delete_button_spec.js b/spec/frontend/runner/components/runner_delete_button_spec.js
deleted file mode 100644
index c8fb7a69379..00000000000
--- a/spec/frontend/runner/components/runner_delete_button_spec.js
+++ /dev/null
@@ -1,266 +0,0 @@
-import Vue from 'vue';
-import { GlButton } from '@gitlab/ui';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
-import runnerDeleteMutation from '~/runner/graphql/shared/runner_delete.mutation.graphql';
-import waitForPromises from 'helpers/wait_for_promises';
-import { captureException } from '~/runner/sentry_utils';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { createAlert } from '~/flash';
-import { I18N_DELETE_RUNNER } from '~/runner/constants';
-
-import RunnerDeleteButton from '~/runner/components/runner_delete_button.vue';
-import RunnerDeleteModal from '~/runner/components/runner_delete_modal.vue';
-import { allRunnersData } from '../mock_data';
-
-const mockRunner = allRunnersData.data.runners.nodes[0];
-const mockRunnerId = getIdFromGraphQLId(mockRunner.id);
-
-Vue.use(VueApollo);
-
-jest.mock('~/flash');
-jest.mock('~/runner/sentry_utils');
-
-describe('RunnerDeleteButton', () => {
- let wrapper;
- let apolloProvider;
- let apolloCache;
- let runnerDeleteHandler;
-
- const findBtn = () => wrapper.findComponent(GlButton);
- const findModal = () => wrapper.findComponent(RunnerDeleteModal);
-
- const getTooltip = () => getBinding(wrapper.element, 'gl-tooltip').value;
- const getModal = () => getBinding(findBtn().element, 'gl-modal').value;
-
- const createComponent = ({ props = {}, mountFn = shallowMountExtended } = {}) => {
- const { runner, ...propsData } = props;
-
- wrapper = mountFn(RunnerDeleteButton, {
- propsData: {
- runner: {
- // We need typename so that cache.identify works
- // eslint-disable-next-line no-underscore-dangle
- __typename: mockRunner.__typename,
- id: mockRunner.id,
- shortSha: mockRunner.shortSha,
- ...runner,
- },
- ...propsData,
- },
- apolloProvider,
- directives: {
- GlTooltip: createMockDirective(),
- GlModal: createMockDirective(),
- },
- });
- };
-
- const clickOkAndWait = async () => {
- findModal().vm.$emit('primary');
- await waitForPromises();
- };
-
- beforeEach(() => {
- runnerDeleteHandler = jest.fn().mockImplementation(() => {
- return Promise.resolve({
- data: {
- runnerDelete: {
- errors: [],
- },
- },
- });
- });
- apolloProvider = createMockApollo([[runnerDeleteMutation, runnerDeleteHandler]]);
- apolloCache = apolloProvider.defaultClient.cache;
-
- jest.spyOn(apolloCache, 'evict');
- jest.spyOn(apolloCache, 'gc');
-
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Displays a delete button without an icon', () => {
- expect(findBtn().props()).toMatchObject({
- loading: false,
- icon: '',
- });
- expect(findBtn().classes('btn-icon')).toBe(false);
- expect(findBtn().text()).toBe(I18N_DELETE_RUNNER);
- });
-
- it('Displays a modal with the runner name', () => {
- expect(findModal().props('runnerName')).toBe(`#${mockRunnerId} (${mockRunner.shortSha})`);
- });
-
- it('Does not have tabindex when button is enabled', () => {
- expect(wrapper.attributes('tabindex')).toBeUndefined();
- });
-
- it('Displays a modal when clicked', () => {
- const modalId = `delete-runner-modal-${mockRunnerId}`;
-
- expect(getModal()).toBe(modalId);
- expect(findModal().attributes('modal-id')).toBe(modalId);
- });
-
- it('Does not display redundant text for screen readers', () => {
- expect(findBtn().attributes('aria-label')).toBe(undefined);
- });
-
- it('Passes other attributes to the button', () => {
- createComponent({ props: { category: 'secondary' } });
-
- expect(findBtn().props('category')).toBe('secondary');
- });
-
- describe(`Before the delete button is clicked`, () => {
- it('The mutation has not been called', () => {
- expect(runnerDeleteHandler).toHaveBeenCalledTimes(0);
- });
- });
-
- describe('Immediately after the delete button is clicked', () => {
- beforeEach(async () => {
- findModal().vm.$emit('primary');
- });
-
- it('The button has a loading state', async () => {
- expect(findBtn().props('loading')).toBe(true);
- });
-
- it('The stale tooltip is removed', async () => {
- expect(getTooltip()).toBe('');
- });
- });
-
- describe('After clicking on the delete button', () => {
- beforeEach(async () => {
- await clickOkAndWait();
- });
-
- it('The mutation to delete is called', () => {
- expect(runnerDeleteHandler).toHaveBeenCalledTimes(1);
- expect(runnerDeleteHandler).toHaveBeenCalledWith({
- input: {
- id: mockRunner.id,
- },
- });
- });
-
- it('The user can be notified with an event', () => {
- const deleted = wrapper.emitted('deleted');
-
- expect(deleted).toHaveLength(1);
- expect(deleted[0][0].message).toMatch(`#${mockRunnerId}`);
- expect(deleted[0][0].message).toMatch(`${mockRunner.shortSha}`);
- });
-
- it('evicts runner from apollo cache', () => {
- expect(apolloCache.evict).toHaveBeenCalledWith({
- id: apolloCache.identify(mockRunner),
- });
- expect(apolloCache.gc).toHaveBeenCalled();
- });
- });
-
- describe('When update fails', () => {
- describe('On a network error', () => {
- const mockErrorMsg = 'Update error!';
-
- beforeEach(async () => {
- runnerDeleteHandler.mockRejectedValueOnce(new Error(mockErrorMsg));
-
- await clickOkAndWait();
- });
-
- it('error is reported to sentry', () => {
- expect(captureException).toHaveBeenCalledWith({
- error: new Error(mockErrorMsg),
- component: 'RunnerDeleteButton',
- });
- });
-
- it('error is shown to the user', () => {
- expect(createAlert).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('On a validation error', () => {
- const mockErrorMsg = 'Runner not found!';
- const mockErrorMsg2 = 'User not allowed!';
-
- beforeEach(async () => {
- runnerDeleteHandler.mockResolvedValueOnce({
- data: {
- runnerDelete: {
- errors: [mockErrorMsg, mockErrorMsg2],
- },
- },
- });
-
- await clickOkAndWait();
- });
-
- it('error is reported to sentry', () => {
- expect(captureException).toHaveBeenCalledWith({
- error: new Error(`${mockErrorMsg} ${mockErrorMsg2}`),
- component: 'RunnerDeleteButton',
- });
- });
-
- it('error is shown to the user', () => {
- expect(createAlert).toHaveBeenCalledTimes(1);
- });
-
- it('does not evict runner from apollo cache', () => {
- expect(apolloCache.evict).not.toHaveBeenCalled();
- expect(apolloCache.gc).not.toHaveBeenCalled();
- });
- });
- });
-
- describe('When displaying a compact button for an active runner', () => {
- beforeEach(() => {
- createComponent({
- props: {
- runner: {
- active: true,
- },
- compact: true,
- },
- mountFn: mountExtended,
- });
- });
-
- it('Displays no text', () => {
- expect(findBtn().text()).toBe('');
- expect(findBtn().classes('btn-icon')).toBe(true);
- });
-
- it('Display correctly for screen readers', () => {
- expect(findBtn().attributes('aria-label')).toBe(I18N_DELETE_RUNNER);
- expect(getTooltip()).toBe(I18N_DELETE_RUNNER);
- });
-
- describe('Immediately after the button is clicked', () => {
- beforeEach(async () => {
- findModal().vm.$emit('primary');
- });
-
- it('The button has a loading state', async () => {
- expect(findBtn().props('loading')).toBe(true);
- });
-
- it('The stale tooltip is removed', async () => {
- expect(getTooltip()).toBe('');
- });
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_delete_modal_spec.js b/spec/frontend/runner/components/runner_delete_modal_spec.js
deleted file mode 100644
index 3e5b634d815..00000000000
--- a/spec/frontend/runner/components/runner_delete_modal_spec.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import { GlModal } from '@gitlab/ui';
-import { mount, shallowMount } from '@vue/test-utils';
-import RunnerDeleteModal from '~/runner/components/runner_delete_modal.vue';
-
-describe('RunnerDeleteModal', () => {
- let wrapper;
-
- const findGlModal = () => wrapper.findComponent(GlModal);
-
- const createComponent = ({ props = {} } = {}, mountFn = shallowMount) => {
- wrapper = mountFn(RunnerDeleteModal, {
- attachTo: document.body,
- propsData: {
- runnerName: '#99 (AABBCCDD)',
- ...props,
- },
- attrs: {
- modalId: 'delete-runner-modal-99',
- },
- });
- };
-
- it('Displays title', () => {
- createComponent();
-
- expect(findGlModal().props('title')).toBe('Delete runner #99 (AABBCCDD)?');
- });
-
- it('Displays buttons', () => {
- createComponent();
-
- expect(findGlModal().props('actionPrimary')).toMatchObject({ text: 'Delete runner' });
- expect(findGlModal().props('actionCancel')).toMatchObject({ text: 'Cancel' });
- });
-
- it('Displays contents', () => {
- createComponent();
-
- expect(findGlModal().html()).toContain(
- 'The runner will be permanently deleted and no longer available for projects or groups in the instance. Are you sure you want to continue?',
- );
- });
-
- describe('When modal is confirmed by the user', () => {
- let hideModalSpy;
-
- beforeEach(() => {
- createComponent({}, mount);
- hideModalSpy = jest.spyOn(wrapper.vm.$refs.modal, 'hide').mockImplementation(() => {});
- });
-
- it('Modal gets hidden', () => {
- expect(hideModalSpy).toHaveBeenCalledTimes(0);
-
- findGlModal().vm.$emit('primary');
-
- expect(hideModalSpy).toHaveBeenCalledTimes(1);
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_details_spec.js b/spec/frontend/runner/components/runner_details_spec.js
deleted file mode 100644
index e6cc936e260..00000000000
--- a/spec/frontend/runner/components/runner_details_spec.js
+++ /dev/null
@@ -1,130 +0,0 @@
-import { GlSprintf, GlIntersperse } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
-import { useFakeDate } from 'helpers/fake_date';
-import { findDd } from 'helpers/dl_locator_helper';
-import { ACCESS_LEVEL_REF_PROTECTED, ACCESS_LEVEL_NOT_PROTECTED } from '~/runner/constants';
-
-import RunnerDetails from '~/runner/components/runner_details.vue';
-import RunnerDetail from '~/runner/components/runner_detail.vue';
-import RunnerGroups from '~/runner/components/runner_groups.vue';
-import RunnerTags from '~/runner/components/runner_tags.vue';
-import RunnerTag from '~/runner/components/runner_tag.vue';
-
-import { runnerData, runnerWithGroupData } from '../mock_data';
-
-const mockRunner = runnerData.data.runner;
-const mockGroupRunner = runnerWithGroupData.data.runner;
-
-describe('RunnerDetails', () => {
- let wrapper;
- const mockNow = '2021-01-15T12:00:00Z';
- const mockOneHourAgo = '2021-01-15T11:00:00Z';
-
- useFakeDate(mockNow);
-
- const findDetailGroups = () => wrapper.findComponent(RunnerGroups);
-
- const createComponent = ({ props = {}, stubs, mountFn = shallowMountExtended } = {}) => {
- wrapper = mountFn(RunnerDetails, {
- propsData: {
- ...props,
- },
- stubs: {
- RunnerDetail,
- ...stubs,
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('Details tab', () => {
- describe.each`
- field | runner | expectedValue
- ${'Description'} | ${{ description: 'My runner' }} | ${'My runner'}
- ${'Description'} | ${{ description: null }} | ${'None'}
- ${'Last contact'} | ${{ contactedAt: mockOneHourAgo }} | ${'1 hour ago'}
- ${'Last contact'} | ${{ contactedAt: null }} | ${'Never contacted'}
- ${'Version'} | ${{ version: '12.3' }} | ${'12.3'}
- ${'Version'} | ${{ version: null }} | ${'None'}
- ${'Executor'} | ${{ executorName: 'shell' }} | ${'shell'}
- ${'Architecture'} | ${{ architectureName: 'amd64' }} | ${'amd64'}
- ${'Platform'} | ${{ platformName: 'darwin' }} | ${'darwin'}
- ${'IP Address'} | ${{ ipAddress: '127.0.0.1' }} | ${'127.0.0.1'}
- ${'IP Address'} | ${{ ipAddress: null }} | ${'None'}
- ${'Configuration'} | ${{ accessLevel: ACCESS_LEVEL_REF_PROTECTED, runUntagged: true }} | ${'Protected, Runs untagged jobs'}
- ${'Configuration'} | ${{ accessLevel: ACCESS_LEVEL_REF_PROTECTED, runUntagged: false }} | ${'Protected'}
- ${'Configuration'} | ${{ accessLevel: ACCESS_LEVEL_NOT_PROTECTED, runUntagged: true }} | ${'Runs untagged jobs'}
- ${'Configuration'} | ${{ accessLevel: ACCESS_LEVEL_NOT_PROTECTED, runUntagged: false }} | ${'None'}
- ${'Maximum job timeout'} | ${{ maximumTimeout: null }} | ${'None'}
- ${'Maximum job timeout'} | ${{ maximumTimeout: 0 }} | ${'0 seconds'}
- ${'Maximum job timeout'} | ${{ maximumTimeout: 59 }} | ${'59 seconds'}
- ${'Maximum job timeout'} | ${{ maximumTimeout: 10 * 60 + 5 }} | ${'10 minutes 5 seconds'}
- ${'Token expiry'} | ${{ tokenExpiresAt: mockOneHourAgo }} | ${'1 hour ago'}
- ${'Token expiry'} | ${{ tokenExpiresAt: null }} | ${'Never expires'}
- `('"$field" field', ({ field, runner, expectedValue }) => {
- beforeEach(() => {
- createComponent({
- props: {
- runner: {
- ...mockRunner,
- ...runner,
- },
- },
- stubs: {
- GlIntersperse,
- GlSprintf,
- TimeAgo,
- },
- });
- });
-
- it(`displays expected value "${expectedValue}"`, () => {
- expect(findDd(field, wrapper).text()).toBe(expectedValue);
- });
- });
-
- describe('"Tags" field', () => {
- const stubs = { RunnerTags, RunnerTag };
-
- it('displays expected value "tag-1 tag-2"', () => {
- createComponent({
- props: {
- runner: { ...mockRunner, tagList: ['tag-1', 'tag-2'] },
- },
- stubs,
- });
-
- expect(findDd('Tags', wrapper).text().replace(/\s+/g, ' ')).toBe('tag-1 tag-2');
- });
-
- it('displays "None" when runner has no tags', () => {
- createComponent({
- props: {
- runner: { ...mockRunner, tagList: [] },
- },
- stubs,
- });
-
- expect(findDd('Tags', wrapper).text().replace(/\s+/g, ' ')).toBe('None');
- });
- });
-
- describe('Group runners', () => {
- beforeEach(() => {
- createComponent({
- props: {
- runner: mockGroupRunner,
- },
- });
- });
-
- it('Shows a group runner details', () => {
- expect(findDetailGroups().props('runner')).toEqual(mockGroupRunner);
- });
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_edit_button_spec.js b/spec/frontend/runner/components/runner_edit_button_spec.js
deleted file mode 100644
index 428c1ef07e9..00000000000
--- a/spec/frontend/runner/components/runner_edit_button_spec.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import { shallowMount, mount } from '@vue/test-utils';
-import RunnerEditButton from '~/runner/components/runner_edit_button.vue';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-
-describe('RunnerEditButton', () => {
- let wrapper;
-
- const getTooltipValue = () => getBinding(wrapper.element, 'gl-tooltip').value;
-
- const createComponent = ({ attrs = {}, mountFn = shallowMount } = {}) => {
- wrapper = mountFn(RunnerEditButton, {
- attrs,
- directives: {
- GlTooltip: createMockDirective(),
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Displays Edit text', () => {
- expect(wrapper.attributes('aria-label')).toBe('Edit');
- });
-
- it('Displays Edit tooltip', () => {
- expect(getTooltipValue()).toBe('Edit');
- });
-
- it('Renders a link and adds an href attribute', () => {
- createComponent({ attrs: { href: '/edit' }, mountFn: mount });
-
- expect(wrapper.element.tagName).toBe('A');
- expect(wrapper.attributes('href')).toBe('/edit');
- });
-});
diff --git a/spec/frontend/runner/components/runner_filtered_search_bar_spec.js b/spec/frontend/runner/components/runner_filtered_search_bar_spec.js
deleted file mode 100644
index c92e19f9263..00000000000
--- a/spec/frontend/runner/components/runner_filtered_search_bar_spec.js
+++ /dev/null
@@ -1,188 +0,0 @@
-import { GlFilteredSearch, GlDropdown, GlDropdownItem } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import RunnerFilteredSearchBar from '~/runner/components/runner_filtered_search_bar.vue';
-import { statusTokenConfig } from '~/runner/components/search_tokens/status_token_config';
-import TagToken from '~/runner/components/search_tokens/tag_token.vue';
-import { tagTokenConfig } from '~/runner/components/search_tokens/tag_token_config';
-import {
- PARAM_KEY_STATUS,
- PARAM_KEY_TAG,
- STATUS_ONLINE,
- INSTANCE_TYPE,
- DEFAULT_MEMBERSHIP,
- DEFAULT_SORT,
- CONTACTED_DESC,
-} from '~/runner/constants';
-import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
-import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue';
-
-const mockSearch = {
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [],
- pagination: { page: 1 },
- sort: DEFAULT_SORT,
-};
-
-describe('RunnerList', () => {
- let wrapper;
-
- const findFilteredSearch = () => wrapper.findComponent(FilteredSearch);
- const findGlFilteredSearch = () => wrapper.findComponent(GlFilteredSearch);
- const findSortOptions = () => wrapper.findAllComponents(GlDropdownItem);
-
- const mockOtherSort = CONTACTED_DESC;
- const mockFilters = [
- { type: PARAM_KEY_STATUS, value: { data: STATUS_ONLINE, operator: '=' } },
- { type: 'filtered-search-term', value: { data: '' } },
- ];
-
- const expectToHaveLastEmittedInput = (value) => {
- const inputs = wrapper.emitted('input');
- expect(inputs[inputs.length - 1][0]).toEqual(value);
- };
-
- const createComponent = ({ props = {}, options = {} } = {}) => {
- wrapper = shallowMountExtended(RunnerFilteredSearchBar, {
- propsData: {
- namespace: 'runners',
- tokens: [],
- value: mockSearch,
- ...props,
- },
- stubs: {
- FilteredSearch,
- GlFilteredSearch,
- GlDropdown,
- GlDropdownItem,
- },
- ...options,
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('binds a namespace to the filtered search', () => {
- expect(findFilteredSearch().props('namespace')).toBe('runners');
- });
-
- it('sets sorting options', () => {
- const SORT_OPTIONS_COUNT = 2;
-
- expect(findSortOptions()).toHaveLength(SORT_OPTIONS_COUNT);
- expect(findSortOptions().at(0).text()).toBe('Created date');
- expect(findSortOptions().at(1).text()).toBe('Last contact');
- });
-
- it('sets tokens to the filtered search', () => {
- createComponent({
- props: {
- tokens: [statusTokenConfig, tagTokenConfig],
- },
- });
-
- expect(findFilteredSearch().props('tokens')).toEqual([
- expect.objectContaining({
- type: PARAM_KEY_STATUS,
- token: BaseToken,
- options: expect.any(Array),
- }),
- expect.objectContaining({
- type: PARAM_KEY_TAG,
- token: TagToken,
- }),
- ]);
- });
-
- it('can be configured with null or undefined tokens, which are ignored', () => {
- createComponent({
- props: {
- tokens: [statusTokenConfig, null, undefined],
- },
- });
-
- expect(findFilteredSearch().props('tokens')).toEqual([statusTokenConfig]);
- });
-
- it('fails validation for v-model with the wrong shape', () => {
- expect(() => {
- createComponent({ props: { value: { filters: 'wrong_filters', sort: 'sort' } } });
- }).toThrow('Invalid prop: custom validator check failed');
-
- expect(() => {
- createComponent({ props: { value: { sort: 'sort' } } });
- }).toThrow('Invalid prop: custom validator check failed');
- });
-
- describe('when a search is preselected', () => {
- beforeEach(() => {
- createComponent({
- props: {
- value: {
- runnerType: INSTANCE_TYPE,
- membership: DEFAULT_MEMBERSHIP,
- sort: mockOtherSort,
- filters: mockFilters,
- },
- },
- });
- });
-
- it('filter values are shown', () => {
- expect(findGlFilteredSearch().props('value')).toMatchObject(mockFilters);
- });
-
- it('sort option is selected', () => {
- expect(
- findSortOptions()
- .filter((w) => w.props('isChecked'))
- .at(0)
- .text(),
- ).toEqual('Last contact');
- });
-
- it('when the user sets a filter, the "search" preserves the other filters', () => {
- findGlFilteredSearch().vm.$emit('input', mockFilters);
- findGlFilteredSearch().vm.$emit('submit');
-
- expectToHaveLastEmittedInput({
- runnerType: INSTANCE_TYPE,
- membership: DEFAULT_MEMBERSHIP,
- filters: mockFilters,
- sort: mockOtherSort,
- pagination: {},
- });
- });
- });
-
- it('when the user sets a filter, the "search" is emitted with filters', () => {
- findGlFilteredSearch().vm.$emit('input', mockFilters);
- findGlFilteredSearch().vm.$emit('submit');
-
- expectToHaveLastEmittedInput({
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: mockFilters,
- sort: DEFAULT_SORT,
- pagination: {},
- });
- });
-
- it('when the user sets a sorting method, the "search" is emitted with the sort', () => {
- findSortOptions().at(1).vm.$emit('click');
-
- expectToHaveLastEmittedInput({
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [],
- sort: mockOtherSort,
- pagination: {},
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_groups_spec.js b/spec/frontend/runner/components/runner_groups_spec.js
deleted file mode 100644
index b83733b9972..00000000000
--- a/spec/frontend/runner/components/runner_groups_spec.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-
-import RunnerGroups from '~/runner/components/runner_groups.vue';
-import RunnerAssignedItem from '~/runner/components/runner_assigned_item.vue';
-
-import { runnerData, runnerWithGroupData } from '../mock_data';
-
-const mockInstanceRunner = runnerData.data.runner;
-const mockGroupRunner = runnerWithGroupData.data.runner;
-const mockGroup = mockGroupRunner.groups.nodes[0];
-
-describe('RunnerGroups', () => {
- let wrapper;
-
- const findHeading = () => wrapper.find('h3');
- const findRunnerAssignedItems = () => wrapper.findAllComponents(RunnerAssignedItem);
-
- const createComponent = ({ runner = mockGroupRunner, mountFn = shallowMountExtended } = {}) => {
- wrapper = mountFn(RunnerGroups, {
- propsData: {
- runner,
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Shows a heading', () => {
- createComponent();
-
- expect(findHeading().text()).toBe('Assigned Group');
- });
-
- describe('When there is a group runner', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('Shows a project', () => {
- createComponent();
-
- const item = findRunnerAssignedItems().at(0);
- const { webUrl, name, fullName, avatarUrl } = mockGroup;
-
- expect(item.props()).toMatchObject({
- href: webUrl,
- name,
- fullName,
- avatarUrl,
- });
- });
- });
-
- describe('When there are no groups', () => {
- beforeEach(() => {
- createComponent({
- runner: mockInstanceRunner,
- });
- });
-
- it('Shows a "None" label', () => {
- expect(wrapper.findByText('None').exists()).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_header_spec.js b/spec/frontend/runner/components/runner_header_spec.js
deleted file mode 100644
index 701d39108cb..00000000000
--- a/spec/frontend/runner/components/runner_header_spec.js
+++ /dev/null
@@ -1,119 +0,0 @@
-import { GlSprintf } from '@gitlab/ui';
-import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { I18N_STATUS_ONLINE, I18N_GROUP_TYPE, GROUP_TYPE, STATUS_ONLINE } from '~/runner/constants';
-import { TYPE_CI_RUNNER } from '~/graphql_shared/constants';
-import { convertToGraphQLId } from '~/graphql_shared/utils';
-import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
-
-import RunnerHeader from '~/runner/components/runner_header.vue';
-import RunnerTypeBadge from '~/runner/components/runner_type_badge.vue';
-import RunnerStatusBadge from '~/runner/components/runner_status_badge.vue';
-
-import { runnerData } from '../mock_data';
-
-const mockRunner = runnerData.data.runner;
-
-describe('RunnerHeader', () => {
- let wrapper;
-
- const findRunnerTypeBadge = () => wrapper.findComponent(RunnerTypeBadge);
- const findRunnerStatusBadge = () => wrapper.findComponent(RunnerStatusBadge);
- const findRunnerLockedIcon = () => wrapper.findByTestId('lock-icon');
- const findTimeAgo = () => wrapper.findComponent(TimeAgo);
-
- const createComponent = ({ runner = {}, options = {}, mountFn = shallowMountExtended } = {}) => {
- wrapper = mountFn(RunnerHeader, {
- propsData: {
- runner: {
- ...mockRunner,
- ...runner,
- },
- },
- stubs: {
- GlSprintf,
- TimeAgo,
- },
- ...options,
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('displays the runner status', () => {
- createComponent({
- mountFn: mountExtended,
- runner: {
- status: STATUS_ONLINE,
- },
- });
-
- expect(findRunnerStatusBadge().text()).toContain(I18N_STATUS_ONLINE);
- });
-
- it('displays the runner type', () => {
- createComponent({
- mountFn: mountExtended,
- runner: {
- runnerType: GROUP_TYPE,
- },
- });
-
- expect(findRunnerTypeBadge().text()).toContain(I18N_GROUP_TYPE);
- });
-
- it('displays the runner id', () => {
- createComponent({
- runner: {
- id: convertToGraphQLId(TYPE_CI_RUNNER, 99),
- },
- });
-
- expect(wrapper.text()).toContain('Runner #99');
- });
-
- it('displays the runner locked icon', () => {
- createComponent({
- runner: {
- locked: true,
- },
- mountFn: mountExtended,
- });
-
- expect(findRunnerLockedIcon().exists()).toBe(true);
- });
-
- it('displays the runner creation time', () => {
- createComponent();
-
- expect(wrapper.text()).toMatch(/created .+/);
- expect(findTimeAgo().props('time')).toBe(mockRunner.createdAt);
- });
-
- it('does not display runner creation time if "createdAt" is missing', () => {
- createComponent({
- runner: {
- id: convertToGraphQLId(TYPE_CI_RUNNER, 99),
- createdAt: null,
- },
- });
-
- expect(wrapper.text()).toContain('Runner #99');
- expect(wrapper.text()).not.toMatch(/created .+/);
- expect(findTimeAgo().exists()).toBe(false);
- });
-
- it('displays actions in a slot', () => {
- createComponent({
- options: {
- slots: {
- actions: '<div data-testid="actions-content">My Actions</div>',
- },
- mountFn: mountExtended,
- },
- });
-
- expect(wrapper.findByTestId('actions-content').text()).toBe('My Actions');
- });
-});
diff --git a/spec/frontend/runner/components/runner_jobs_spec.js b/spec/frontend/runner/components/runner_jobs_spec.js
deleted file mode 100644
index 4d38afb25ee..00000000000
--- a/spec/frontend/runner/components/runner_jobs_spec.js
+++ /dev/null
@@ -1,155 +0,0 @@
-import { GlSkeletonLoader } from '@gitlab/ui';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
-import RunnerJobs from '~/runner/components/runner_jobs.vue';
-import RunnerJobsTable from '~/runner/components/runner_jobs_table.vue';
-import RunnerPagination from '~/runner/components/runner_pagination.vue';
-import { captureException } from '~/runner/sentry_utils';
-import { I18N_NO_JOBS_FOUND, RUNNER_DETAILS_JOBS_PAGE_SIZE } from '~/runner/constants';
-
-import runnerJobsQuery from '~/runner/graphql/show/runner_jobs.query.graphql';
-
-import { runnerData, runnerJobsData } from '../mock_data';
-
-jest.mock('~/flash');
-jest.mock('~/runner/sentry_utils');
-
-const mockRunner = runnerData.data.runner;
-const mockRunnerWithJobs = runnerJobsData.data.runner;
-const mockJobs = mockRunnerWithJobs.jobs.nodes;
-
-Vue.use(VueApollo);
-
-describe('RunnerJobs', () => {
- let wrapper;
- let mockRunnerJobsQuery;
-
- const findGlSkeletonLoading = () => wrapper.findComponent(GlSkeletonLoader);
- const findRunnerJobsTable = () => wrapper.findComponent(RunnerJobsTable);
- const findRunnerPagination = () => wrapper.findComponent(RunnerPagination);
-
- const createComponent = ({ mountFn = shallowMountExtended } = {}) => {
- wrapper = mountFn(RunnerJobs, {
- apolloProvider: createMockApollo([[runnerJobsQuery, mockRunnerJobsQuery]]),
- propsData: {
- runner: mockRunner,
- },
- });
- };
-
- beforeEach(() => {
- mockRunnerJobsQuery = jest.fn();
- });
-
- afterEach(() => {
- mockRunnerJobsQuery.mockReset();
- wrapper.destroy();
- });
-
- it('Requests runner jobs', async () => {
- createComponent();
-
- await waitForPromises();
-
- expect(mockRunnerJobsQuery).toHaveBeenCalledTimes(1);
- expect(mockRunnerJobsQuery).toHaveBeenCalledWith({
- id: mockRunner.id,
- first: RUNNER_DETAILS_JOBS_PAGE_SIZE,
- });
- });
-
- describe('When there are jobs assigned', () => {
- beforeEach(async () => {
- mockRunnerJobsQuery.mockResolvedValueOnce(runnerJobsData);
-
- createComponent();
- await waitForPromises();
- });
-
- it('Shows jobs', () => {
- const jobs = findRunnerJobsTable().props('jobs');
-
- expect(jobs).toEqual(mockJobs);
- });
-
- describe('When "Next" page is clicked', () => {
- beforeEach(async () => {
- findRunnerPagination().vm.$emit('input', { page: 2, after: 'AFTER_CURSOR' });
-
- await waitForPromises();
- });
-
- it('A new page is requested', () => {
- expect(mockRunnerJobsQuery).toHaveBeenCalledTimes(2);
- expect(mockRunnerJobsQuery).toHaveBeenLastCalledWith({
- id: mockRunner.id,
- first: RUNNER_DETAILS_JOBS_PAGE_SIZE,
- after: 'AFTER_CURSOR',
- });
- });
- });
- });
-
- describe('When loading', () => {
- it('shows loading indicator and no other content', () => {
- createComponent();
-
- expect(findGlSkeletonLoading().exists()).toBe(true);
- expect(findRunnerJobsTable().exists()).toBe(false);
- expect(findRunnerPagination().attributes('disabled')).toBe('true');
- });
- });
-
- describe('When there are no jobs', () => {
- beforeEach(async () => {
- mockRunnerJobsQuery.mockResolvedValueOnce({
- data: {
- runner: {
- id: mockRunner.id,
- projectCount: 0,
- jobs: {
- nodes: [],
- pageInfo: {
- hasNextPage: false,
- hasPreviousPage: false,
- startCursor: '',
- endCursor: '',
- },
- },
- },
- },
- });
-
- createComponent();
- await waitForPromises();
- });
-
- it('Shows a "None" label', () => {
- expect(wrapper.text()).toBe(I18N_NO_JOBS_FOUND);
- });
- });
-
- describe('When an error occurs', () => {
- beforeEach(async () => {
- mockRunnerJobsQuery.mockRejectedValue(new Error('Error!'));
-
- createComponent();
- await waitForPromises();
- });
-
- it('shows an error', () => {
- expect(createAlert).toHaveBeenCalled();
- });
-
- it('reports an error', () => {
- expect(captureException).toHaveBeenCalledWith({
- component: 'RunnerJobs',
- error: expect.any(Error),
- });
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_jobs_table_spec.js b/spec/frontend/runner/components/runner_jobs_table_spec.js
deleted file mode 100644
index 5f4905ad2a8..00000000000
--- a/spec/frontend/runner/components/runner_jobs_table_spec.js
+++ /dev/null
@@ -1,119 +0,0 @@
-import { GlTableLite } from '@gitlab/ui';
-import {
- extendedWrapper,
- shallowMountExtended,
- mountExtended,
-} from 'helpers/vue_test_utils_helper';
-import { __, s__ } from '~/locale';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import RunnerJobsTable from '~/runner/components/runner_jobs_table.vue';
-import { useFakeDate } from 'helpers/fake_date';
-import { runnerJobsData } from '../mock_data';
-
-const mockJobs = runnerJobsData.data.runner.jobs.nodes;
-
-describe('RunnerJobsTable', () => {
- let wrapper;
- const mockNow = '2021-01-15T12:00:00Z';
- const mockOneHourAgo = '2021-01-15T11:00:00Z';
-
- useFakeDate(mockNow);
-
- const findTable = () => wrapper.findComponent(GlTableLite);
- const findHeaders = () => wrapper.findAll('th');
- const findRows = () => wrapper.findAll('[data-testid^="job-row-"]');
- const findCell = ({ field }) =>
- extendedWrapper(findRows().at(0).find(`[data-testid="td-${field}"]`));
-
- const createComponent = ({ props = {} } = {}, mountFn = shallowMountExtended) => {
- wrapper = mountFn(RunnerJobsTable, {
- propsData: {
- jobs: mockJobs,
- ...props,
- },
- stubs: {
- GlTableLite,
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Sets job id as a row key', () => {
- createComponent();
-
- expect(findTable().attributes('primarykey')).toBe('id');
- });
-
- describe('Table data', () => {
- beforeEach(() => {
- createComponent({}, mountExtended);
- });
-
- it('Displays headers', () => {
- const headerLabels = findHeaders().wrappers.map((w) => w.text());
-
- expect(headerLabels).toEqual([
- s__('Job|Status'),
- __('Job'),
- __('Project'),
- __('Commit'),
- s__('Job|Finished at'),
- s__('Runners|Tags'),
- ]);
- });
-
- it('Displays a list of jobs', () => {
- expect(findRows()).toHaveLength(1);
- });
-
- it('Displays details of a job', () => {
- const { id, detailedStatus, pipeline, shortSha, commitPath } = mockJobs[0];
-
- expect(findCell({ field: 'status' }).text()).toMatchInterpolatedText(detailedStatus.text);
-
- expect(findCell({ field: 'job' }).text()).toContain(`#${getIdFromGraphQLId(id)}`);
- expect(findCell({ field: 'job' }).find('a').attributes('href')).toBe(
- detailedStatus.detailsPath,
- );
-
- expect(findCell({ field: 'project' }).text()).toBe(pipeline.project.name);
- expect(findCell({ field: 'project' }).find('a').attributes('href')).toBe(
- pipeline.project.webUrl,
- );
-
- expect(findCell({ field: 'commit' }).text()).toBe(shortSha);
- expect(findCell({ field: 'commit' }).find('a').attributes('href')).toBe(commitPath);
- });
- });
-
- describe('Table data formatting', () => {
- let mockJobsCopy;
-
- beforeEach(() => {
- mockJobsCopy = [
- {
- ...mockJobs[0],
- },
- ];
- });
-
- it('Formats finishedAt time', () => {
- mockJobsCopy[0].finishedAt = mockOneHourAgo;
-
- createComponent({ props: { jobs: mockJobsCopy } }, mountExtended);
-
- expect(findCell({ field: 'finished_at' }).text()).toBe('1 hour ago');
- });
-
- it('Formats tags', () => {
- mockJobsCopy[0].tags = ['tag-1', 'tag-2'];
-
- createComponent({ props: { jobs: mockJobsCopy } }, mountExtended);
-
- expect(findCell({ field: 'tags' }).text()).toMatchInterpolatedText('tag-1 tag-2');
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_list_empty_state_spec.js b/spec/frontend/runner/components/runner_list_empty_state_spec.js
deleted file mode 100644
index 038162b889e..00000000000
--- a/spec/frontend/runner/components/runner_list_empty_state_spec.js
+++ /dev/null
@@ -1,103 +0,0 @@
-import { GlEmptyState, GlLink, 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 RunnerInstructionsModal from '~/vue_shared/components/runner_instructions/runner_instructions_modal.vue';
-
-import RunnerListEmptyState from '~/runner/components/runner_list_empty_state.vue';
-
-const mockSvgPath = 'mock-svg-path.svg';
-const mockFilteredSvgPath = 'mock-filtered-svg-path.svg';
-const mockRegistrationToken = 'REGISTRATION_TOKEN';
-
-describe('RunnerListEmptyState', () => {
- let wrapper;
-
- const findEmptyState = () => wrapper.findComponent(GlEmptyState);
- const findLink = () => wrapper.findComponent(GlLink);
- const findRunnerInstructionsModal = () => wrapper.findComponent(RunnerInstructionsModal);
-
- const createComponent = ({ props, mountFn = shallowMountExtended } = {}) => {
- wrapper = mountFn(RunnerListEmptyState, {
- propsData: {
- svgPath: mockSvgPath,
- filteredSvgPath: mockFilteredSvgPath,
- registrationToken: mockRegistrationToken,
- ...props,
- },
- directives: {
- GlModal: createMockDirective(),
- },
- stubs: {
- GlEmptyState,
- GlSprintf,
- GlLink,
- },
- });
- };
-
- describe('when search is not filtered', () => {
- const title = s__('Runners|Get started with runners');
-
- describe('when there is a registration token', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders an illustration', () => {
- expect(findEmptyState().props('svgPath')).toBe(mockSvgPath);
- });
-
- it('displays "no results" text with instructions', () => {
- const desc = s__(
- 'Runners|Runners are the agents that run your CI/CD jobs. Follow the %{linkStart}installation and registration instructions%{linkEnd} to set up a runner.',
- );
-
- expect(findEmptyState().text()).toMatchInterpolatedText(`${title} ${desc}`);
- });
-
- it('opens a runner registration instructions modal with a link', () => {
- const { value } = getBinding(findLink().element, 'gl-modal');
-
- expect(findRunnerInstructionsModal().props('modalId')).toEqual(value);
- });
- });
-
- describe('when there is no registration token', () => {
- beforeEach(() => {
- createComponent({ props: { registrationToken: null } });
- });
-
- it('renders an illustration', () => {
- expect(findEmptyState().props('svgPath')).toBe(mockSvgPath);
- });
-
- it('displays "no results" text', () => {
- const desc = s__(
- 'Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator.',
- );
-
- expect(findEmptyState().text()).toMatchInterpolatedText(`${title} ${desc}`);
- });
-
- it('has no registration instructions link', () => {
- expect(findLink().exists()).toBe(false);
- });
- });
- });
-
- describe('when search is filtered', () => {
- beforeEach(() => {
- createComponent({ props: { isSearchFiltered: true } });
- });
-
- it('renders a "filtered search" illustration', () => {
- expect(findEmptyState().props('svgPath')).toBe(mockFilteredSvgPath);
- });
-
- it('displays "no filtered results" text', () => {
- expect(findEmptyState().text()).toContain(s__('Runners|No results found'));
- expect(findEmptyState().text()).toContain(s__('Runners|Edit your search and try again'));
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_list_spec.js b/spec/frontend/runner/components/runner_list_spec.js
deleted file mode 100644
index a31990f8f7e..00000000000
--- a/spec/frontend/runner/components/runner_list_spec.js
+++ /dev/null
@@ -1,231 +0,0 @@
-import { GlTableLite, GlSkeletonLoader } from '@gitlab/ui';
-import HelpPopover from '~/vue_shared/components/help_popover.vue';
-import {
- extendedWrapper,
- shallowMountExtended,
- mountExtended,
-} from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import { s__ } from '~/locale';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { createLocalState } from '~/runner/graphql/list/local_state';
-
-import RunnerList from '~/runner/components/runner_list.vue';
-import RunnerBulkDelete from '~/runner/components/runner_bulk_delete.vue';
-import RunnerBulkDeleteCheckbox from '~/runner/components/runner_bulk_delete_checkbox.vue';
-
-import { I18N_PROJECT_TYPE, I18N_STATUS_NEVER_CONTACTED } from '~/runner/constants';
-import { allRunnersData, onlineContactTimeoutSecs, staleTimeoutSecs } from '../mock_data';
-
-const mockRunners = allRunnersData.data.runners.nodes;
-const mockActiveRunnersCount = mockRunners.length;
-
-describe('RunnerList', () => {
- let wrapper;
- let cacheConfig;
- let localMutations;
-
- const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
- const findTable = () => wrapper.findComponent(GlTableLite);
- const findHeaders = () => wrapper.findAll('th');
- const findRows = () => wrapper.findAll('[data-testid^="runner-row-"]');
- const findCell = ({ row = 0, fieldKey }) =>
- extendedWrapper(findRows().at(row).find(`[data-testid="td-${fieldKey}"]`));
- const findRunnerBulkDelete = () => wrapper.findComponent(RunnerBulkDelete);
- const findRunnerBulkDeleteCheckbox = () => wrapper.findComponent(RunnerBulkDeleteCheckbox);
-
- const createComponent = (
- { props = {}, provide = {}, ...options } = {},
- mountFn = shallowMountExtended,
- ) => {
- ({ cacheConfig, localMutations } = createLocalState());
-
- wrapper = mountFn(RunnerList, {
- apolloProvider: createMockApollo([], {}, cacheConfig),
- propsData: {
- runners: mockRunners,
- activeRunnersCount: mockActiveRunnersCount,
- ...props,
- },
- provide: {
- localMutations,
- onlineContactTimeoutSecs,
- staleTimeoutSecs,
- ...provide,
- },
- ...options,
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Displays headers', () => {
- createComponent(
- {
- stubs: {
- HelpPopover: {
- template: '<div/>',
- },
- },
- },
- mountExtended,
- );
-
- const headerLabels = findHeaders().wrappers.map((w) => w.text());
-
- expect(findHeaders().at(0).findComponent(HelpPopover).exists()).toBe(true);
- expect(findHeaders().at(2).findComponent(HelpPopover).exists()).toBe(true);
-
- expect(headerLabels).toEqual([
- s__('Runners|Status'),
- s__('Runners|Runner'),
- s__('Runners|Owner'),
- '', // actions has no label
- ]);
- });
-
- it('Sets runner id as a row key', () => {
- createComponent();
-
- expect(findTable().attributes('primary-key')).toBe('id');
- });
-
- it('Displays a list of runners', () => {
- createComponent({}, mountExtended);
-
- expect(findRows()).toHaveLength(4);
-
- expect(findSkeletonLoader().exists()).toBe(false);
- });
-
- it('Displays details of a runner', () => {
- createComponent({}, mountExtended);
-
- const { id, description, version, shortSha } = mockRunners[0];
- const numericId = getIdFromGraphQLId(id);
-
- // Badges
- expect(findCell({ fieldKey: 'status' }).text()).toMatchInterpolatedText(
- I18N_STATUS_NEVER_CONTACTED,
- );
-
- // Runner summary
- const summary = findCell({ fieldKey: 'summary' }).text();
-
- expect(summary).toContain(`#${numericId} (${shortSha})`);
- expect(summary).toContain(I18N_PROJECT_TYPE);
-
- expect(summary).toContain(version);
- expect(summary).toContain(description);
-
- expect(summary).toContain('Last contact');
- expect(summary).toContain('0'); // job count
- expect(summary).toContain('Created');
-
- // Actions
- expect(findCell({ fieldKey: 'actions' }).exists()).toBe(true);
- });
-
- describe('When the list is checkable', () => {
- beforeEach(() => {
- createComponent(
- {
- props: {
- checkable: true,
- },
- },
- mountExtended,
- );
- });
-
- it('runner bulk delete is available', () => {
- expect(findRunnerBulkDelete().props('runners')).toEqual(mockRunners);
- });
-
- it('runner bulk delete checkbox is available', () => {
- expect(findRunnerBulkDeleteCheckbox().props('runners')).toEqual(mockRunners);
- });
-
- it('Displays a checkbox field', () => {
- expect(findCell({ fieldKey: 'checkbox' }).find('input').exists()).toBe(true);
- });
-
- it('Sets a runner as checked', async () => {
- const runner = mockRunners[0];
- const setRunnerCheckedMock = jest
- .spyOn(localMutations, 'setRunnerChecked')
- .mockImplementation(() => {});
-
- const checkbox = findCell({ fieldKey: 'checkbox' }).find('input');
- await checkbox.setChecked();
-
- expect(setRunnerCheckedMock).toHaveBeenCalledTimes(1);
- expect(setRunnerCheckedMock).toHaveBeenCalledWith({
- runner,
- isChecked: true,
- });
- });
-
- it('Emits a deleted event', async () => {
- const event = { message: 'Deleted!' };
- findRunnerBulkDelete().vm.$emit('deleted', event);
-
- expect(wrapper.emitted('deleted')).toEqual([[event]]);
- });
- });
-
- describe('Scoped cell slots', () => {
- it('Render #runner-name slot in "summary" cell', () => {
- createComponent(
- {
- scopedSlots: { 'runner-name': ({ runner }) => `Summary: ${runner.id}` },
- },
- mountExtended,
- );
-
- expect(findCell({ fieldKey: 'summary' }).text()).toContain(`Summary: ${mockRunners[0].id}`);
- });
-
- it('Render #runner-actions-cell slot in "actions" cell', () => {
- createComponent(
- {
- scopedSlots: { 'runner-actions-cell': ({ runner }) => `Actions: ${runner.id}` },
- },
- mountExtended,
- );
-
- expect(findCell({ fieldKey: 'actions' }).text()).toBe(`Actions: ${mockRunners[0].id}`);
- });
- });
-
- it('Shows runner identifier', () => {
- const { id, shortSha } = mockRunners[0];
- const numericId = getIdFromGraphQLId(id);
-
- createComponent({}, mountExtended);
-
- expect(findCell({ fieldKey: 'summary' }).text()).toContain(`#${numericId} (${shortSha})`);
- });
-
- describe('When data is loading', () => {
- it('shows a busy state', () => {
- createComponent({ props: { runners: [], loading: true } });
-
- expect(findTable().classes('gl-opacity-6')).toBe(true);
- });
-
- it('when there are no runners, shows an skeleton loader', () => {
- createComponent({ props: { runners: [], loading: true } }, mountExtended);
-
- expect(findSkeletonLoader().exists()).toBe(true);
- });
-
- it('when there are runners, shows a busy indicator skeleton loader', () => {
- createComponent({ props: { loading: true } }, mountExtended);
-
- expect(findSkeletonLoader().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_membership_toggle_spec.js b/spec/frontend/runner/components/runner_membership_toggle_spec.js
deleted file mode 100644
index 1a7ae22618a..00000000000
--- a/spec/frontend/runner/components/runner_membership_toggle_spec.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import { GlToggle } from '@gitlab/ui';
-import { shallowMount, mount } from '@vue/test-utils';
-import RunnerMembershipToggle from '~/runner/components/runner_membership_toggle.vue';
-import {
- I18N_SHOW_ONLY_INHERITED,
- MEMBERSHIP_DESCENDANTS,
- MEMBERSHIP_ALL_AVAILABLE,
-} from '~/runner/constants';
-
-describe('RunnerMembershipToggle', () => {
- let wrapper;
-
- const findToggle = () => wrapper.findComponent(GlToggle);
-
- const createComponent = ({ props = {}, mountFn = shallowMount } = {}) => {
- wrapper = mountFn(RunnerMembershipToggle, {
- propsData: props,
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Displays text', () => {
- createComponent({ mountFn: mount });
-
- expect(wrapper.text()).toBe(I18N_SHOW_ONLY_INHERITED);
- });
-
- it.each`
- membershipValue | toggleValue
- ${MEMBERSHIP_DESCENDANTS} | ${true}
- ${MEMBERSHIP_ALL_AVAILABLE} | ${false}
- `(
- 'Displays a membership of $membershipValue as enabled=$toggleValue',
- ({ membershipValue, toggleValue }) => {
- createComponent({ props: { value: membershipValue } });
-
- expect(findToggle().props('value')).toBe(toggleValue);
- },
- );
-
- it.each`
- changeEvt | membershipValue
- ${true} | ${MEMBERSHIP_DESCENDANTS}
- ${false} | ${MEMBERSHIP_ALL_AVAILABLE}
- `(
- 'Emits $changeEvt when value is changed to $membershipValue',
- ({ changeEvt, membershipValue }) => {
- createComponent();
- findToggle().vm.$emit('change', changeEvt);
-
- expect(wrapper.emitted('input')).toStrictEqual([[membershipValue]]);
- },
- );
-});
diff --git a/spec/frontend/runner/components/runner_pagination_spec.js b/spec/frontend/runner/components/runner_pagination_spec.js
deleted file mode 100644
index 499cc59250d..00000000000
--- a/spec/frontend/runner/components/runner_pagination_spec.js
+++ /dev/null
@@ -1,115 +0,0 @@
-import { GlKeysetPagination } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import RunnerPagination from '~/runner/components/runner_pagination.vue';
-
-const mockStartCursor = 'START_CURSOR';
-const mockEndCursor = 'END_CURSOR';
-
-describe('RunnerPagination', () => {
- let wrapper;
-
- const findPagination = () => wrapper.findComponent(GlKeysetPagination);
-
- const createComponent = (propsData = {}) => {
- wrapper = shallowMount(RunnerPagination, {
- propsData,
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('When in between pages', () => {
- const mockPageInfo = {
- startCursor: mockStartCursor,
- endCursor: mockEndCursor,
- hasPreviousPage: true,
- hasNextPage: true,
- };
-
- beforeEach(() => {
- createComponent({
- pageInfo: mockPageInfo,
- });
- });
-
- it('Contains the current page information', () => {
- expect(findPagination().props()).toMatchObject(mockPageInfo);
- });
-
- it('Goes to the prev page', () => {
- findPagination().vm.$emit('prev');
-
- expect(wrapper.emitted('input')[0]).toEqual([
- {
- before: mockStartCursor,
- },
- ]);
- });
-
- it('Goes to the next page', () => {
- findPagination().vm.$emit('next');
-
- expect(wrapper.emitted('input')[0]).toEqual([
- {
- after: mockEndCursor,
- },
- ]);
- });
- });
-
- describe.each`
- page | hasPreviousPage | hasNextPage
- ${'first'} | ${false} | ${true}
- ${'last'} | ${true} | ${false}
- `('When on the $page page', ({ page, hasPreviousPage, hasNextPage }) => {
- const mockPageInfo = {
- startCursor: mockStartCursor,
- endCursor: mockEndCursor,
- hasPreviousPage,
- hasNextPage,
- };
-
- beforeEach(() => {
- createComponent({
- pageInfo: mockPageInfo,
- });
- });
-
- it(`Contains the ${page} page information`, () => {
- expect(findPagination().props()).toMatchObject(mockPageInfo);
- });
- });
-
- describe('When no other pages', () => {
- beforeEach(() => {
- createComponent({
- pageInfo: {
- hasPreviousPage: false,
- hasNextPage: false,
- },
- });
- });
-
- it('is not shown', () => {
- expect(findPagination().exists()).toBe(false);
- });
- });
-
- describe('When adding more attributes', () => {
- beforeEach(() => {
- createComponent({
- pageInfo: {
- hasPreviousPage: true,
- hasNextPage: false,
- },
- disabled: true,
- });
- });
-
- it('attributes are passed', () => {
- expect(findPagination().props('disabled')).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_pause_button_spec.js b/spec/frontend/runner/components/runner_pause_button_spec.js
deleted file mode 100644
index 61476007571..00000000000
--- a/spec/frontend/runner/components/runner_pause_button_spec.js
+++ /dev/null
@@ -1,263 +0,0 @@
-import Vue, { nextTick } from 'vue';
-import { GlButton } from '@gitlab/ui';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
-import runnerToggleActiveMutation from '~/runner/graphql/shared/runner_toggle_active.mutation.graphql';
-import waitForPromises from 'helpers/wait_for_promises';
-import { captureException } from '~/runner/sentry_utils';
-import { createAlert } from '~/flash';
-import {
- I18N_PAUSE,
- I18N_PAUSE_TOOLTIP,
- I18N_RESUME,
- I18N_RESUME_TOOLTIP,
-} from '~/runner/constants';
-
-import RunnerPauseButton from '~/runner/components/runner_pause_button.vue';
-import { allRunnersData } from '../mock_data';
-
-const mockRunner = allRunnersData.data.runners.nodes[0];
-
-Vue.use(VueApollo);
-
-jest.mock('~/flash');
-jest.mock('~/runner/sentry_utils');
-
-describe('RunnerPauseButton', () => {
- let wrapper;
- let runnerToggleActiveHandler;
-
- const getTooltip = () => getBinding(wrapper.element, 'gl-tooltip').value;
- const findBtn = () => wrapper.findComponent(GlButton);
-
- const createComponent = ({ props = {}, mountFn = shallowMountExtended } = {}) => {
- const { runner, ...propsData } = props;
-
- wrapper = mountFn(RunnerPauseButton, {
- propsData: {
- runner: {
- id: mockRunner.id,
- active: mockRunner.active,
- ...runner,
- },
- ...propsData,
- },
- apolloProvider: createMockApollo([[runnerToggleActiveMutation, runnerToggleActiveHandler]]),
- directives: {
- GlTooltip: createMockDirective(),
- },
- });
- };
-
- const clickAndWait = async () => {
- findBtn().vm.$emit('click');
- await waitForPromises();
- };
-
- beforeEach(() => {
- runnerToggleActiveHandler = jest.fn().mockImplementation(({ input }) => {
- return Promise.resolve({
- data: {
- runnerUpdate: {
- runner: {
- id: input.id,
- active: input.active,
- },
- errors: [],
- },
- },
- });
- });
-
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('Pause/Resume action', () => {
- describe.each`
- runnerState | icon | content | tooltip | isActive | newActiveValue
- ${'paused'} | ${'play'} | ${I18N_RESUME} | ${I18N_RESUME_TOOLTIP} | ${false} | ${true}
- ${'active'} | ${'pause'} | ${I18N_PAUSE} | ${I18N_PAUSE_TOOLTIP} | ${true} | ${false}
- `('When the runner is $runnerState', ({ icon, content, tooltip, isActive, newActiveValue }) => {
- beforeEach(() => {
- createComponent({
- props: {
- runner: {
- active: isActive,
- },
- },
- });
- });
-
- it(`Displays a ${icon} button`, () => {
- expect(findBtn().props('loading')).toBe(false);
- expect(findBtn().props('icon')).toBe(icon);
- });
-
- it('Displays button content', () => {
- expect(findBtn().text()).toBe(content);
- expect(getTooltip()).toBe(tooltip);
- });
-
- it('Does not display redundant text for screen readers', () => {
- expect(findBtn().attributes('aria-label')).toBe(undefined);
- });
-
- describe(`Before the ${icon} button is clicked`, () => {
- it('The mutation has not been called', () => {
- expect(runnerToggleActiveHandler).toHaveBeenCalledTimes(0);
- });
- });
-
- describe(`Immediately after the ${icon} button is clicked`, () => {
- const setup = async () => {
- findBtn().vm.$emit('click');
- await nextTick();
- };
-
- it('The button has a loading state', async () => {
- await setup();
-
- expect(findBtn().props('loading')).toBe(true);
- });
-
- it('The stale tooltip is removed', async () => {
- await setup();
-
- expect(getTooltip()).toBe('');
- });
- });
-
- describe(`After clicking on the ${icon} button`, () => {
- beforeEach(async () => {
- await clickAndWait();
- });
-
- it(`The mutation to that sets active to ${newActiveValue} is called`, async () => {
- expect(runnerToggleActiveHandler).toHaveBeenCalledTimes(1);
- expect(runnerToggleActiveHandler).toHaveBeenCalledWith({
- input: {
- id: mockRunner.id,
- active: newActiveValue,
- },
- });
- });
-
- it('The button does not have a loading state', () => {
- expect(findBtn().props('loading')).toBe(false);
- });
-
- it('The button emits toggledPaused', () => {
- expect(wrapper.emitted('toggledPaused')).toHaveLength(1);
- });
- });
-
- describe('When update fails', () => {
- describe('On a network error', () => {
- const mockErrorMsg = 'Update error!';
-
- beforeEach(async () => {
- runnerToggleActiveHandler.mockRejectedValueOnce(new Error(mockErrorMsg));
-
- await clickAndWait();
- });
-
- it('error is reported to sentry', () => {
- expect(captureException).toHaveBeenCalledWith({
- error: new Error(mockErrorMsg),
- component: 'RunnerPauseButton',
- });
- });
-
- it('error is shown to the user', () => {
- expect(createAlert).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('On a validation error', () => {
- const mockErrorMsg = 'Runner not found!';
- const mockErrorMsg2 = 'User not allowed!';
-
- beforeEach(async () => {
- runnerToggleActiveHandler.mockResolvedValueOnce({
- data: {
- runnerUpdate: {
- runner: {
- id: mockRunner.id,
- active: isActive,
- },
- errors: [mockErrorMsg, mockErrorMsg2],
- },
- },
- });
-
- await clickAndWait();
- });
-
- it('error is reported to sentry', () => {
- expect(captureException).toHaveBeenCalledWith({
- error: new Error(`${mockErrorMsg} ${mockErrorMsg2}`),
- component: 'RunnerPauseButton',
- });
- });
-
- it('error is shown to the user', () => {
- expect(createAlert).toHaveBeenCalledTimes(1);
- });
- });
- });
- });
- });
-
- describe('When displaying a compact button for an active runner', () => {
- beforeEach(() => {
- createComponent({
- props: {
- runner: {
- active: true,
- },
- compact: true,
- },
- mountFn: mountExtended,
- });
- });
-
- it('Displays no text', () => {
- expect(findBtn().text()).toBe('');
-
- // Note: Use <template v-if> to ensure rendering a
- // text-less button. Ensure we don't send even empty an
- // content slot to prevent a distorted/rectangular button.
- expect(wrapper.find('.gl-button-text').exists()).toBe(false);
- });
-
- it('Display correctly for screen readers', () => {
- expect(findBtn().attributes('aria-label')).toBe(I18N_PAUSE);
- expect(getTooltip()).toBe(I18N_PAUSE_TOOLTIP);
- });
-
- describe('Immediately after the button is clicked', () => {
- const setup = async () => {
- findBtn().vm.$emit('click');
- await nextTick();
- };
-
- it('The button has a loading state', async () => {
- await setup();
-
- expect(findBtn().props('loading')).toBe(true);
- });
-
- it('The stale tooltip is removed', async () => {
- await setup();
-
- expect(getTooltip()).toBe('');
- });
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_paused_badge_spec.js b/spec/frontend/runner/components/runner_paused_badge_spec.js
deleted file mode 100644
index c1c7351aab2..00000000000
--- a/spec/frontend/runner/components/runner_paused_badge_spec.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import { GlBadge } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import RunnerStatePausedBadge from '~/runner/components/runner_paused_badge.vue';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import { I18N_PAUSED } from '~/runner/constants';
-
-describe('RunnerTypeBadge', () => {
- let wrapper;
-
- const findBadge = () => wrapper.findComponent(GlBadge);
- const getTooltip = () => getBinding(findBadge().element, 'gl-tooltip');
-
- const createComponent = ({ props = {} } = {}) => {
- wrapper = shallowMount(RunnerStatePausedBadge, {
- propsData: {
- ...props,
- },
- directives: {
- GlTooltip: createMockDirective(),
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('renders paused state', () => {
- expect(wrapper.text()).toBe(I18N_PAUSED);
- expect(findBadge().props('variant')).toBe('warning');
- });
-
- it('renders tooltip', () => {
- expect(getTooltip().value).toBeDefined();
- });
-
- it('passes arbitrary attributes to the badge', () => {
- createComponent({ props: { size: 'sm' } });
-
- expect(findBadge().props('size')).toBe('sm');
- });
-});
diff --git a/spec/frontend/runner/components/runner_projects_spec.js b/spec/frontend/runner/components/runner_projects_spec.js
deleted file mode 100644
index eca042cae86..00000000000
--- a/spec/frontend/runner/components/runner_projects_spec.js
+++ /dev/null
@@ -1,251 +0,0 @@
-import { GlSearchBoxByType, GlSkeletonLoader } from '@gitlab/ui';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
-import { sprintf } from '~/locale';
-import {
- I18N_ASSIGNED_PROJECTS,
- I18N_CLEAR_FILTER_PROJECTS,
- I18N_FILTER_PROJECTS,
- I18N_NO_PROJECTS_FOUND,
- RUNNER_DETAILS_PROJECTS_PAGE_SIZE,
-} from '~/runner/constants';
-import RunnerProjects from '~/runner/components/runner_projects.vue';
-import RunnerAssignedItem from '~/runner/components/runner_assigned_item.vue';
-import RunnerPagination from '~/runner/components/runner_pagination.vue';
-import { captureException } from '~/runner/sentry_utils';
-
-import runnerProjectsQuery from '~/runner/graphql/show/runner_projects.query.graphql';
-
-import { runnerData, runnerProjectsData } from '../mock_data';
-
-jest.mock('~/flash');
-jest.mock('~/runner/sentry_utils');
-
-const mockRunner = runnerData.data.runner;
-const mockRunnerWithProjects = runnerProjectsData.data.runner;
-const mockProjects = mockRunnerWithProjects.projects.nodes;
-
-Vue.use(VueApollo);
-
-describe('RunnerProjects', () => {
- let wrapper;
- let mockRunnerProjectsQuery;
-
- const findHeading = () => wrapper.find('h3');
- const findGlSkeletonLoading = () => wrapper.findComponent(GlSkeletonLoader);
- const findGlSearchBoxByType = () => wrapper.findComponent(GlSearchBoxByType);
- const findRunnerAssignedItems = () => wrapper.findAllComponents(RunnerAssignedItem);
- const findRunnerPagination = () => wrapper.findComponent(RunnerPagination);
-
- const createComponent = ({ mountFn = shallowMountExtended } = {}) => {
- wrapper = mountFn(RunnerProjects, {
- apolloProvider: createMockApollo([[runnerProjectsQuery, mockRunnerProjectsQuery]]),
- propsData: {
- runner: mockRunner,
- },
- });
- };
-
- beforeEach(() => {
- mockRunnerProjectsQuery = jest.fn();
- });
-
- afterEach(() => {
- mockRunnerProjectsQuery.mockReset();
- wrapper.destroy();
- });
-
- it('Requests runner projects', async () => {
- createComponent();
-
- await waitForPromises();
-
- expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(1);
- expect(mockRunnerProjectsQuery).toHaveBeenCalledWith({
- id: mockRunner.id,
- search: '',
- first: RUNNER_DETAILS_PROJECTS_PAGE_SIZE,
- });
- });
-
- it('Shows a filter box', () => {
- createComponent();
-
- expect(findGlSearchBoxByType().attributes()).toMatchObject({
- clearbuttontitle: I18N_CLEAR_FILTER_PROJECTS,
- debounce: '500',
- placeholder: I18N_FILTER_PROJECTS,
- });
- });
-
- describe('When there are projects assigned', () => {
- beforeEach(async () => {
- mockRunnerProjectsQuery.mockResolvedValueOnce(runnerProjectsData);
-
- createComponent();
- await waitForPromises();
- });
-
- it('Shows a heading', async () => {
- const expected = sprintf(I18N_ASSIGNED_PROJECTS, { projectCount: mockProjects.length });
-
- expect(findHeading().text()).toBe(expected);
- });
-
- it('Shows projects', () => {
- expect(findRunnerAssignedItems().length).toBe(mockProjects.length);
- });
-
- it('Shows a project', () => {
- const item = findRunnerAssignedItems().at(0);
- const { webUrl, name, nameWithNamespace, avatarUrl } = mockProjects[0];
-
- expect(item.props()).toMatchObject({
- href: webUrl,
- name,
- fullName: nameWithNamespace,
- avatarUrl,
- isOwner: true, // first project is always owner
- });
- });
-
- describe('When "Next" page is clicked', () => {
- beforeEach(async () => {
- findRunnerPagination().vm.$emit('input', { page: 3, after: 'AFTER_CURSOR' });
-
- await waitForPromises();
- });
-
- it('A new page is requested', () => {
- expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(2);
- expect(mockRunnerProjectsQuery).toHaveBeenLastCalledWith({
- id: mockRunner.id,
- search: '',
- first: RUNNER_DETAILS_PROJECTS_PAGE_SIZE,
- after: 'AFTER_CURSOR',
- });
- });
-
- it('When "Prev" page is clicked, the previous page is requested', async () => {
- findRunnerPagination().vm.$emit('input', { page: 2, before: 'BEFORE_CURSOR' });
-
- await waitForPromises();
-
- expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(3);
- expect(mockRunnerProjectsQuery).toHaveBeenLastCalledWith({
- id: mockRunner.id,
- search: '',
- last: RUNNER_DETAILS_PROJECTS_PAGE_SIZE,
- before: 'BEFORE_CURSOR',
- });
- });
-
- it('When user filters after paginating, the first page is requested', async () => {
- findGlSearchBoxByType().vm.$emit('input', 'my search');
- await waitForPromises();
-
- expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(3);
- expect(mockRunnerProjectsQuery).toHaveBeenLastCalledWith({
- id: mockRunner.id,
- search: 'my search',
- first: RUNNER_DETAILS_PROJECTS_PAGE_SIZE,
- });
- });
- });
-
- describe('When user filters', () => {
- it('Filtered results are requested', async () => {
- expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(1);
-
- findGlSearchBoxByType().vm.$emit('input', 'my search');
- await waitForPromises();
-
- expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(2);
- expect(mockRunnerProjectsQuery).toHaveBeenLastCalledWith({
- id: mockRunner.id,
- search: 'my search',
- first: RUNNER_DETAILS_PROJECTS_PAGE_SIZE,
- });
- });
-
- it('Filtered results are not requested for short searches', async () => {
- expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(1);
-
- findGlSearchBoxByType().vm.$emit('input', 'm');
- await waitForPromises();
-
- findGlSearchBoxByType().vm.$emit('input', 'my');
- await waitForPromises();
-
- expect(mockRunnerProjectsQuery).toHaveBeenCalledTimes(1);
- });
- });
- });
-
- describe('When loading', () => {
- it('shows loading indicator and no other content', () => {
- createComponent();
-
- expect(findGlSkeletonLoading().exists()).toBe(true);
-
- expect(wrapper.findByText(I18N_NO_PROJECTS_FOUND).exists()).toBe(false);
- expect(findRunnerAssignedItems().length).toBe(0);
-
- expect(findRunnerPagination().attributes('disabled')).toBe('true');
- expect(findGlSearchBoxByType().props('isLoading')).toBe(true);
- });
- });
-
- describe('When there are no projects', () => {
- beforeEach(async () => {
- mockRunnerProjectsQuery.mockResolvedValueOnce({
- data: {
- runner: {
- id: mockRunner.id,
- projectCount: 0,
- projects: {
- nodes: [],
- pageInfo: {
- hasNextPage: false,
- hasPreviousPage: false,
- startCursor: '',
- endCursor: '',
- },
- },
- },
- },
- });
-
- createComponent();
- await waitForPromises();
- });
-
- it('Shows a "None" label', () => {
- expect(wrapper.findByText(I18N_NO_PROJECTS_FOUND).exists()).toBe(true);
- });
- });
-
- describe('When an error occurs', () => {
- beforeEach(async () => {
- mockRunnerProjectsQuery.mockRejectedValue(new Error('Error!'));
-
- createComponent();
- await waitForPromises();
- });
-
- it('shows an error', () => {
- expect(createAlert).toHaveBeenCalled();
- });
-
- it('reports an error', () => {
- expect(captureException).toHaveBeenCalledWith({
- component: 'RunnerProjects',
- error: expect.any(Error),
- });
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_stacked_layout_banner_spec.js b/spec/frontend/runner/components/runner_stacked_layout_banner_spec.js
deleted file mode 100644
index d1f04f0ee37..00000000000
--- a/spec/frontend/runner/components/runner_stacked_layout_banner_spec.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import { nextTick } from 'vue';
-import { GlBanner } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import RunnerStackedLayoutBanner from '~/runner/components/runner_stacked_layout_banner.vue';
-import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue';
-
-describe('RunnerStackedLayoutBanner', () => {
- let wrapper;
-
- const findBanner = () => wrapper.findComponent(GlBanner);
- const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync);
-
- const createComponent = ({ ...options } = {}, mountFn = shallowMount) => {
- wrapper = mountFn(RunnerStackedLayoutBanner, {
- ...options,
- });
- };
-
- it('Displays a banner', () => {
- createComponent();
-
- expect(findBanner().props()).toMatchObject({
- svgPath: expect.stringContaining('data:image/svg+xml;utf8,'),
- title: expect.any(String),
- buttonText: expect.any(String),
- buttonLink: expect.stringContaining('https://gitlab.com/gitlab-org/gitlab/-/issues/'),
- });
- expect(findLocalStorageSync().exists()).toBe(true);
- });
-
- it('Does not display a banner when dismissed', async () => {
- createComponent();
-
- findLocalStorageSync().vm.$emit('input', true);
-
- await nextTick();
-
- expect(findBanner().exists()).toBe(false);
- expect(findLocalStorageSync().exists()).toBe(true); // continues syncing after removal
- });
-});
diff --git a/spec/frontend/runner/components/runner_status_badge_spec.js b/spec/frontend/runner/components/runner_status_badge_spec.js
deleted file mode 100644
index 9ab6378304f..00000000000
--- a/spec/frontend/runner/components/runner_status_badge_spec.js
+++ /dev/null
@@ -1,133 +0,0 @@
-import { GlBadge } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import RunnerStatusBadge from '~/runner/components/runner_status_badge.vue';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import {
- I18N_STATUS_ONLINE,
- I18N_STATUS_NEVER_CONTACTED,
- I18N_STATUS_OFFLINE,
- I18N_STATUS_STALE,
- I18N_NEVER_CONTACTED_TOOLTIP,
- I18N_STALE_NEVER_CONTACTED_TOOLTIP,
- STATUS_ONLINE,
- STATUS_OFFLINE,
- STATUS_STALE,
- STATUS_NEVER_CONTACTED,
-} from '~/runner/constants';
-
-describe('RunnerTypeBadge', () => {
- let wrapper;
-
- const findBadge = () => wrapper.findComponent(GlBadge);
- const getTooltip = () => getBinding(findBadge().element, 'gl-tooltip');
-
- const createComponent = (props = {}) => {
- wrapper = shallowMount(RunnerStatusBadge, {
- propsData: {
- runner: {
- contactedAt: '2020-12-31T23:59:00Z',
- status: STATUS_ONLINE,
- },
- ...props,
- },
- directives: {
- GlTooltip: createMockDirective(),
- },
- });
- };
-
- beforeEach(() => {
- jest.useFakeTimers('modern');
- jest.setSystemTime(new Date('2021-01-01T00:00:00Z'));
- });
-
- afterEach(() => {
- jest.useFakeTimers('legacy');
-
- wrapper.destroy();
- });
-
- it('renders online state', () => {
- createComponent();
-
- expect(wrapper.text()).toBe(I18N_STATUS_ONLINE);
- expect(findBadge().props('variant')).toBe('success');
- expect(getTooltip().value).toBe('Runner is online; last contact was 1 minute ago');
- });
-
- it('renders never contacted state', () => {
- createComponent({
- runner: {
- contactedAt: null,
- status: STATUS_NEVER_CONTACTED,
- },
- });
-
- expect(wrapper.text()).toBe(I18N_STATUS_NEVER_CONTACTED);
- expect(findBadge().props('variant')).toBe('muted');
- expect(getTooltip().value).toBe(I18N_NEVER_CONTACTED_TOOLTIP);
- });
-
- it('renders offline state', () => {
- createComponent({
- runner: {
- contactedAt: '2020-12-31T00:00:00Z',
- status: STATUS_OFFLINE,
- },
- });
-
- expect(wrapper.text()).toBe(I18N_STATUS_OFFLINE);
- expect(findBadge().props('variant')).toBe('muted');
- expect(getTooltip().value).toBe('Runner is offline; last contact was 1 day ago');
- });
-
- it('renders stale state', () => {
- createComponent({
- runner: {
- contactedAt: '2020-01-01T00:00:00Z',
- status: STATUS_STALE,
- },
- });
-
- expect(wrapper.text()).toBe(I18N_STATUS_STALE);
- expect(findBadge().props('variant')).toBe('warning');
- expect(getTooltip().value).toBe('Runner is stale; last contact was 1 year ago');
- });
-
- it('renders stale state with no contact time', () => {
- createComponent({
- runner: {
- contactedAt: null,
- status: STATUS_STALE,
- },
- });
-
- expect(wrapper.text()).toBe(I18N_STATUS_STALE);
- expect(findBadge().props('variant')).toBe('warning');
- expect(getTooltip().value).toBe(I18N_STALE_NEVER_CONTACTED_TOOLTIP);
- });
-
- describe('does not fail when data is missing', () => {
- it('contacted_at is missing', () => {
- createComponent({
- runner: {
- contactedAt: null,
- status: STATUS_ONLINE,
- },
- });
-
- expect(wrapper.text()).toBe(I18N_STATUS_ONLINE);
- expect(getTooltip().value).toBe('Runner is online; last contact was never');
- });
-
- it('status is missing', () => {
- createComponent({
- runner: {
- status: null,
- },
- });
-
- expect(wrapper.text()).toBe('');
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_status_popover_spec.js b/spec/frontend/runner/components/runner_status_popover_spec.js
deleted file mode 100644
index 789283d1245..00000000000
--- a/spec/frontend/runner/components/runner_status_popover_spec.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import { GlSprintf } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import RunnerStatusPopover from '~/runner/components/runner_status_popover.vue';
-import HelpPopover from '~/vue_shared/components/help_popover.vue';
-import { onlineContactTimeoutSecs, staleTimeoutSecs } from '../mock_data';
-
-describe('RunnerStatusPopover', () => {
- let wrapper;
-
- const createComponent = ({ provide = {} } = {}) => {
- wrapper = shallowMountExtended(RunnerStatusPopover, {
- provide: {
- onlineContactTimeoutSecs,
- staleTimeoutSecs,
- ...provide,
- },
- stubs: {
- GlSprintf,
- },
- });
- };
-
- const findHelpPopover = () => wrapper.findComponent(HelpPopover);
-
- it('renders popoover', () => {
- createComponent();
-
- expect(findHelpPopover().exists()).toBe(true);
- });
-
- it('renders complete text', () => {
- createComponent();
-
- expect(findHelpPopover().text()).toMatchSnapshot();
- });
-});
diff --git a/spec/frontend/runner/components/runner_tag_spec.js b/spec/frontend/runner/components/runner_tag_spec.js
deleted file mode 100644
index 391c17f81cb..00000000000
--- a/spec/frontend/runner/components/runner_tag_spec.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import { GlBadge } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-
-import { RUNNER_TAG_BADGE_VARIANT } from '~/runner/constants';
-import RunnerTag from '~/runner/components/runner_tag.vue';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-
-const mockTag = 'tag1';
-
-describe('RunnerTag', () => {
- let wrapper;
-
- const findBadge = () => wrapper.findComponent(GlBadge);
- const getTooltipValue = () => getBinding(findBadge().element, 'gl-tooltip').value;
-
- const setDimensions = ({ scrollWidth, offsetWidth }) => {
- jest.spyOn(findBadge().element, 'scrollWidth', 'get').mockReturnValue(scrollWidth);
- jest.spyOn(findBadge().element, 'offsetWidth', 'get').mockReturnValue(offsetWidth);
-
- // Mock trigger resize
- getBinding(findBadge().element, 'gl-resize-observer').value();
- };
-
- const createComponent = ({ props = {} } = {}) => {
- wrapper = shallowMount(RunnerTag, {
- propsData: {
- tag: mockTag,
- ...props,
- },
- directives: {
- GlTooltip: createMockDirective(),
- GlResizeObserver: createMockDirective(),
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Displays tag text', () => {
- expect(wrapper.text()).toBe(mockTag);
- });
-
- it('Displays tags with correct style', () => {
- expect(findBadge().props()).toMatchObject({
- size: 'sm',
- variant: RUNNER_TAG_BADGE_VARIANT,
- });
- });
-
- it('Displays tags with md size', () => {
- createComponent({
- props: { size: 'md' },
- });
-
- expect(findBadge().props('size')).toBe('md');
- });
-
- it.each`
- case | scrollWidth | offsetWidth | expectedTooltip
- ${'overflowing'} | ${110} | ${100} | ${mockTag}
- ${'not overflowing'} | ${90} | ${100} | ${''}
- ${'almost overflowing'} | ${100} | ${100} | ${''}
- `(
- 'Sets "$expectedTooltip" as tooltip when $case',
- async ({ scrollWidth, offsetWidth, expectedTooltip }) => {
- setDimensions({ scrollWidth, offsetWidth });
- await nextTick();
-
- expect(getTooltipValue()).toBe(expectedTooltip);
- },
- );
-});
diff --git a/spec/frontend/runner/components/runner_tags_spec.js b/spec/frontend/runner/components/runner_tags_spec.js
deleted file mode 100644
index c6bfabdb18a..00000000000
--- a/spec/frontend/runner/components/runner_tags_spec.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import { GlBadge } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import RunnerTags from '~/runner/components/runner_tags.vue';
-
-describe('RunnerTags', () => {
- let wrapper;
-
- const findBadge = () => wrapper.findComponent(GlBadge);
- const findBadgesAt = (i = 0) => wrapper.findAllComponents(GlBadge).at(i);
-
- const createComponent = ({ props = {} } = {}) => {
- wrapper = mount(RunnerTags, {
- propsData: {
- tagList: ['tag1', 'tag2'],
- ...props,
- },
- });
- };
-
- beforeEach(() => {
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Displays tags text', () => {
- expect(wrapper.text()).toMatchInterpolatedText('tag1 tag2');
-
- expect(findBadgesAt(0).text()).toBe('tag1');
- expect(findBadgesAt(1).text()).toBe('tag2');
- });
-
- it('Displays tags with correct style', () => {
- expect(findBadge().props('size')).toBe('sm');
- });
-
- it('Displays tags with md size', () => {
- createComponent({
- props: { size: 'md' },
- });
-
- expect(findBadge().props('size')).toBe('md');
- });
-
- it('Is empty when there are no tags', () => {
- createComponent({
- props: { tagList: null },
- });
-
- expect(wrapper.html()).toEqual('');
- });
-});
diff --git a/spec/frontend/runner/components/runner_type_badge_spec.js b/spec/frontend/runner/components/runner_type_badge_spec.js
deleted file mode 100644
index fe922fb9d18..00000000000
--- a/spec/frontend/runner/components/runner_type_badge_spec.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import { GlBadge } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import RunnerTypeBadge from '~/runner/components/runner_type_badge.vue';
-import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
-import {
- INSTANCE_TYPE,
- GROUP_TYPE,
- PROJECT_TYPE,
- I18N_INSTANCE_TYPE,
- I18N_GROUP_TYPE,
- I18N_PROJECT_TYPE,
-} from '~/runner/constants';
-
-describe('RunnerTypeBadge', () => {
- let wrapper;
-
- const findBadge = () => wrapper.findComponent(GlBadge);
- const getTooltip = () => getBinding(findBadge().element, 'gl-tooltip');
-
- const createComponent = ({ props = {} } = {}) => {
- wrapper = shallowMount(RunnerTypeBadge, {
- propsData: {
- ...props,
- },
- directives: {
- GlTooltip: createMockDirective(),
- },
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe.each`
- type | text
- ${INSTANCE_TYPE} | ${I18N_INSTANCE_TYPE}
- ${GROUP_TYPE} | ${I18N_GROUP_TYPE}
- ${PROJECT_TYPE} | ${I18N_PROJECT_TYPE}
- `('displays $type runner', ({ type, text }) => {
- beforeEach(() => {
- createComponent({ props: { type } });
- });
-
- it(`as "${text}" with an "info" variant`, () => {
- expect(findBadge().text()).toBe(text);
- expect(findBadge().props('variant')).toBe('muted');
- });
-
- it('with a tooltip', () => {
- expect(getTooltip().value).toBeDefined();
- });
- });
-
- it('validation fails for an incorrect type', () => {
- expect(() => {
- createComponent({ props: { type: 'AN_UNKNOWN_VALUE' } });
- }).toThrow();
- });
-
- it('does not render content when type is missing', () => {
- createComponent({ props: { type: undefined } });
-
- expect(findBadge().exists()).toBe(false);
- });
-});
diff --git a/spec/frontend/runner/components/runner_type_tabs_spec.js b/spec/frontend/runner/components/runner_type_tabs_spec.js
deleted file mode 100644
index dde35533bc3..00000000000
--- a/spec/frontend/runner/components/runner_type_tabs_spec.js
+++ /dev/null
@@ -1,214 +0,0 @@
-import { GlTab } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import RunnerTypeTabs from '~/runner/components/runner_type_tabs.vue';
-import RunnerCount from '~/runner/components/stat/runner_count.vue';
-import {
- INSTANCE_TYPE,
- GROUP_TYPE,
- PROJECT_TYPE,
- DEFAULT_MEMBERSHIP,
- DEFAULT_SORT,
-} from '~/runner/constants';
-
-const mockSearch = {
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [],
- pagination: { page: 1 },
- sort: DEFAULT_SORT,
-};
-
-const mockCount = (type, multiplier = 1) => {
- let count;
- switch (type) {
- case INSTANCE_TYPE:
- count = 3;
- break;
- case GROUP_TYPE:
- count = 2;
- break;
- case PROJECT_TYPE:
- count = 1;
- break;
- default:
- count = 6;
- break;
- }
- return count * multiplier;
-};
-
-describe('RunnerTypeTabs', () => {
- let wrapper;
-
- const findTabs = () => wrapper.findAllComponents(GlTab);
- const findActiveTab = () =>
- findTabs()
- .filter((tab) => tab.attributes('active') === 'true')
- .at(0);
- const getTabsTitles = () => findTabs().wrappers.map((tab) => tab.text().replace(/\s+/g, ' '));
-
- const createComponent = ({ props, stubs, ...options } = {}) => {
- wrapper = shallowMount(RunnerTypeTabs, {
- propsData: {
- value: mockSearch,
- countScope: INSTANCE_TYPE,
- countVariables: {},
- ...props,
- },
- stubs: {
- GlTab,
- ...stubs,
- },
- ...options,
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Renders all options to filter runners by default', () => {
- createComponent();
-
- expect(getTabsTitles()).toEqual(['All', 'Instance', 'Group', 'Project']);
- });
-
- it('Shows count when receiving a number', () => {
- createComponent({
- stubs: {
- RunnerCount: {
- props: ['variables'],
- render() {
- return this.$scopedSlots.default({
- count: mockCount(this.variables.type),
- });
- },
- },
- },
- });
-
- expect(getTabsTitles()).toEqual([`All 6`, `Instance 3`, `Group 2`, `Project 1`]);
- });
-
- it('Shows formatted count when receiving a large number', () => {
- createComponent({
- stubs: {
- RunnerCount: {
- props: ['variables'],
- render() {
- return this.$scopedSlots.default({
- count: mockCount(this.variables.type, 1000),
- });
- },
- },
- },
- });
-
- expect(getTabsTitles()).toEqual([
- `All 6,000`,
- `Instance 3,000`,
- `Group 2,000`,
- `Project 1,000`,
- ]);
- });
-
- it('Renders a count next to each tab', () => {
- const mockVariables = {
- paused: true,
- status: 'ONLINE',
- };
-
- createComponent({
- props: {
- countVariables: mockVariables,
- },
- });
-
- findTabs().wrappers.forEach((tab) => {
- expect(tab.findComponent(RunnerCount).props()).toEqual({
- scope: INSTANCE_TYPE,
- skip: false,
- variables: expect.objectContaining(mockVariables),
- });
- });
- });
-
- it('Renders fewer options to filter runners', () => {
- createComponent({
- props: {
- runnerTypes: [GROUP_TYPE, PROJECT_TYPE],
- },
- });
-
- expect(getTabsTitles()).toEqual(['All', 'Group', 'Project']);
- });
-
- it('"All" is selected by default', () => {
- createComponent();
-
- expect(findActiveTab().text()).toBe('All');
- });
-
- it('Another tab can be preselected by the user', () => {
- createComponent({
- props: {
- value: {
- ...mockSearch,
- runnerType: INSTANCE_TYPE,
- },
- },
- });
-
- expect(findActiveTab().text()).toBe('Instance');
- });
-
- describe('When the user selects a tab', () => {
- const emittedValue = () => wrapper.emitted('input')[0][0];
-
- beforeEach(() => {
- createComponent();
- findTabs().at(2).vm.$emit('click');
- });
-
- it(`Runner type is emitted`, () => {
- expect(emittedValue()).toEqual({
- ...mockSearch,
- runnerType: GROUP_TYPE,
- });
- });
-
- it('Runner type is selected', async () => {
- const newValue = emittedValue();
- await wrapper.setProps({ value: newValue });
-
- expect(findActiveTab().text()).toBe('Group');
- });
- });
-
- describe('Component API', () => {
- describe('When .refetch() is called', () => {
- let mockRefetch;
-
- beforeEach(() => {
- mockRefetch = jest.fn();
-
- createComponent({
- stubs: {
- RunnerCount: {
- methods: {
- refetch: mockRefetch,
- },
- render() {},
- },
- },
- });
-
- wrapper.vm.refetch();
- });
-
- it('refetch is called for each count', () => {
- expect(mockRefetch).toHaveBeenCalledTimes(4);
- });
- });
- });
-});
diff --git a/spec/frontend/runner/components/runner_update_form_spec.js b/spec/frontend/runner/components/runner_update_form_spec.js
deleted file mode 100644
index e12736216a0..00000000000
--- a/spec/frontend/runner/components/runner_update_form_spec.js
+++ /dev/null
@@ -1,288 +0,0 @@
-import Vue, { nextTick } from 'vue';
-import { GlForm, GlSkeletonLoader } from '@gitlab/ui';
-import VueApollo from 'vue-apollo';
-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 { redirectTo } from '~/lib/utils/url_utility';
-import RunnerUpdateForm from '~/runner/components/runner_update_form.vue';
-import {
- INSTANCE_TYPE,
- GROUP_TYPE,
- PROJECT_TYPE,
- ACCESS_LEVEL_REF_PROTECTED,
- ACCESS_LEVEL_NOT_PROTECTED,
-} from '~/runner/constants';
-import runnerUpdateMutation from '~/runner/graphql/edit/runner_update.mutation.graphql';
-import { captureException } from '~/runner/sentry_utils';
-import { saveAlertToLocalStorage } from '~/runner/local_storage_alert/save_alert_to_local_storage';
-import { runnerFormData } from '../mock_data';
-
-jest.mock('~/runner/local_storage_alert/save_alert_to_local_storage');
-jest.mock('~/flash');
-jest.mock('~/runner/sentry_utils');
-jest.mock('~/lib/utils/url_utility');
-
-const mockRunner = runnerFormData.data.runner;
-const mockRunnerPath = '/admin/runners/1';
-
-Vue.use(VueApollo);
-
-describe('RunnerUpdateForm', () => {
- let wrapper;
- let runnerUpdateHandler;
-
- const findForm = () => wrapper.findComponent(GlForm);
- const findPausedCheckbox = () => wrapper.findByTestId('runner-field-paused');
- const findProtectedCheckbox = () => wrapper.findByTestId('runner-field-protected');
- const findRunUntaggedCheckbox = () => wrapper.findByTestId('runner-field-run-untagged');
- const findLockedCheckbox = () => wrapper.findByTestId('runner-field-locked');
- const findFields = () => wrapper.findAll('[data-testid^="runner-field"');
-
- const findDescriptionInput = () => wrapper.findByTestId('runner-field-description').find('input');
- const findMaxJobTimeoutInput = () =>
- wrapper.findByTestId('runner-field-max-timeout').find('input');
- const findTagsInput = () => wrapper.findByTestId('runner-field-tags').find('input');
-
- const findSubmit = () => wrapper.find('[type="submit"]');
- const findSubmitDisabledAttr = () => findSubmit().attributes('disabled');
- const findCancelBtn = () => wrapper.findByRole('link', { name: __('Cancel') });
- const submitForm = () => findForm().trigger('submit');
- const submitFormAndWait = () => submitForm().then(waitForPromises);
-
- const getFieldsModel = () => ({
- active: !findPausedCheckbox().element.checked,
- accessLevel: findProtectedCheckbox().element.checked
- ? ACCESS_LEVEL_REF_PROTECTED
- : ACCESS_LEVEL_NOT_PROTECTED,
- runUntagged: findRunUntaggedCheckbox().element.checked,
- locked: findLockedCheckbox().element?.checked || false,
- maximumTimeout: findMaxJobTimeoutInput().element.value || null,
- tagList: findTagsInput().element.value.split(',').filter(Boolean),
- });
-
- const createComponent = ({ props } = {}) => {
- wrapper = mountExtended(RunnerUpdateForm, {
- propsData: {
- runner: mockRunner,
- runnerPath: mockRunnerPath,
- ...props,
- },
- apolloProvider: createMockApollo([[runnerUpdateMutation, runnerUpdateHandler]]),
- });
- };
-
- const expectToHaveSubmittedRunnerContaining = (submittedRunner) => {
- expect(runnerUpdateHandler).toHaveBeenCalledTimes(1);
- expect(runnerUpdateHandler).toHaveBeenCalledWith({
- input: expect.objectContaining(submittedRunner),
- });
-
- expect(saveAlertToLocalStorage).toHaveBeenCalledWith(
- expect.objectContaining({
- message: expect.any(String),
- variant: VARIANT_SUCCESS,
- }),
- );
- expect(redirectTo).toHaveBeenCalledWith(mockRunnerPath);
- };
-
- beforeEach(() => {
- runnerUpdateHandler = jest.fn().mockImplementation(({ input }) => {
- return Promise.resolve({
- data: {
- runnerUpdate: {
- runner: {
- ...mockRunner,
- ...input,
- },
- errors: [],
- },
- },
- });
- });
-
- createComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Form has a submit button', () => {
- expect(findSubmit().exists()).toBe(true);
- });
-
- it('Form fields match data', () => {
- expect(mockRunner).toMatchObject(getFieldsModel());
- });
-
- it('Form shows a cancel button', () => {
- expect(runnerUpdateHandler).not.toHaveBeenCalled();
- expect(findCancelBtn().attributes('href')).toBe(mockRunnerPath);
- });
-
- it('Form prevent multiple submissions', async () => {
- await submitForm();
-
- expect(findSubmitDisabledAttr()).toBe('disabled');
- });
-
- it('Updates runner with no changes', async () => {
- await submitFormAndWait();
-
- // Some read-only fields are not submitted
- const { __typename, shortSha, runnerType, createdAt, status, ...submitted } = mockRunner;
-
- expectToHaveSubmittedRunnerContaining(submitted);
- });
-
- describe('When data is being loaded', () => {
- beforeEach(() => {
- createComponent({ props: { loading: true } });
- });
-
- it('Form skeleton is shown', () => {
- expect(wrapper.findComponent(GlSkeletonLoader).exists()).toBe(true);
- expect(findFields()).toHaveLength(0);
- });
-
- it('Form cannot be submitted', () => {
- expect(findSubmit().props('loading')).toBe(true);
- });
-
- it('Form is updated when data loads', async () => {
- wrapper.setProps({
- loading: false,
- });
-
- await nextTick();
-
- expect(findFields()).not.toHaveLength(0);
- expect(mockRunner).toMatchObject(getFieldsModel());
- });
- });
-
- it.each`
- runnerType | exists | outcome
- ${INSTANCE_TYPE} | ${false} | ${'hidden'}
- ${GROUP_TYPE} | ${false} | ${'hidden'}
- ${PROJECT_TYPE} | ${true} | ${'shown'}
- `(`When runner is $runnerType, locked field is $outcome`, ({ runnerType, exists }) => {
- const runner = { ...mockRunner, runnerType };
- createComponent({ props: { runner } });
-
- expect(findLockedCheckbox().exists()).toBe(exists);
- });
-
- describe('On submit, runner gets updated', () => {
- it.each`
- test | initialValue | findCheckbox | checked | submitted
- ${'pauses'} | ${{ active: true }} | ${findPausedCheckbox} | ${true} | ${{ active: false }}
- ${'activates'} | ${{ active: false }} | ${findPausedCheckbox} | ${false} | ${{ active: true }}
- ${'unprotects'} | ${{ accessLevel: ACCESS_LEVEL_NOT_PROTECTED }} | ${findProtectedCheckbox} | ${true} | ${{ accessLevel: ACCESS_LEVEL_REF_PROTECTED }}
- ${'protects'} | ${{ accessLevel: ACCESS_LEVEL_REF_PROTECTED }} | ${findProtectedCheckbox} | ${false} | ${{ accessLevel: ACCESS_LEVEL_NOT_PROTECTED }}
- ${'"runs untagged jobs"'} | ${{ runUntagged: true }} | ${findRunUntaggedCheckbox} | ${false} | ${{ runUntagged: false }}
- ${'"runs tagged jobs"'} | ${{ runUntagged: false }} | ${findRunUntaggedCheckbox} | ${true} | ${{ runUntagged: true }}
- ${'locks'} | ${{ runnerType: PROJECT_TYPE, locked: true }} | ${findLockedCheckbox} | ${false} | ${{ locked: false }}
- ${'unlocks'} | ${{ runnerType: PROJECT_TYPE, locked: false }} | ${findLockedCheckbox} | ${true} | ${{ locked: true }}
- `('Checkbox $test runner', async ({ initialValue, findCheckbox, checked, submitted }) => {
- const runner = { ...mockRunner, ...initialValue };
- createComponent({ props: { runner } });
-
- await findCheckbox().setChecked(checked);
- await submitFormAndWait();
-
- expectToHaveSubmittedRunnerContaining({
- id: runner.id,
- ...submitted,
- });
- });
-
- it.each`
- test | initialValue | findInput | value | submitted
- ${'description'} | ${{ description: 'Desc. 1' }} | ${findDescriptionInput} | ${'Desc. 2'} | ${{ description: 'Desc. 2' }}
- ${'max timeout'} | ${{ maximumTimeout: 36000 }} | ${findMaxJobTimeoutInput} | ${'40000'} | ${{ maximumTimeout: 40000 }}
- ${'tags'} | ${{ tagList: ['tag1'] }} | ${findTagsInput} | ${'tag2, tag3'} | ${{ tagList: ['tag2', 'tag3'] }}
- `("Field updates runner's $test", async ({ initialValue, findInput, value, submitted }) => {
- const runner = { ...mockRunner, ...initialValue };
- createComponent({ props: { runner } });
-
- await findInput().setValue(value);
- await submitFormAndWait();
-
- expectToHaveSubmittedRunnerContaining({
- id: runner.id,
- ...submitted,
- });
- });
-
- it.each`
- value | submitted
- ${''} | ${{ tagList: [] }}
- ${'tag1, tag2'} | ${{ tagList: ['tag1', 'tag2'] }}
- ${'with spaces'} | ${{ tagList: ['with spaces'] }}
- ${'more ,,,,, commas'} | ${{ tagList: ['more', 'commas'] }}
- `('Field updates runner\'s tags for "$value"', async ({ value, submitted }) => {
- const runner = { ...mockRunner, tagList: ['tag1'] };
- createComponent({ props: { runner } });
-
- await findTagsInput().setValue(value);
- await submitFormAndWait();
-
- expectToHaveSubmittedRunnerContaining({
- id: runner.id,
- ...submitted,
- });
- });
- });
-
- describe('On error', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('On network error, error message is shown', async () => {
- const mockErrorMsg = 'Update error!';
-
- runnerUpdateHandler.mockRejectedValue(new Error(mockErrorMsg));
-
- await submitFormAndWait();
-
- expect(createAlert).toHaveBeenLastCalledWith({
- message: mockErrorMsg,
- });
- expect(captureException).toHaveBeenCalledWith({
- component: 'RunnerUpdateForm',
- error: new Error(mockErrorMsg),
- });
- expect(findSubmitDisabledAttr()).toBeUndefined();
- });
-
- it('On validation error, error message is shown and it is not sent to sentry', async () => {
- const mockErrorMsg = 'Invalid value!';
-
- runnerUpdateHandler.mockResolvedValue({
- data: {
- runnerUpdate: {
- runner: mockRunner,
- errors: [mockErrorMsg],
- },
- },
- });
-
- await submitFormAndWait();
-
- expect(createAlert).toHaveBeenLastCalledWith({
- message: mockErrorMsg,
- });
- expect(findSubmitDisabledAttr()).toBeUndefined();
-
- expect(captureException).not.toHaveBeenCalled();
- expect(saveAlertToLocalStorage).not.toHaveBeenCalled();
- expect(redirectTo).not.toHaveBeenCalled();
- });
- });
-});
diff --git a/spec/frontend/runner/components/search_tokens/tag_token_spec.js b/spec/frontend/runner/components/search_tokens/tag_token_spec.js
deleted file mode 100644
index a7363eb11cd..00000000000
--- a/spec/frontend/runner/components/search_tokens/tag_token_spec.js
+++ /dev/null
@@ -1,208 +0,0 @@
-import { GlFilteredSearchSuggestion, GlLoadingIcon, GlToken } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
-import MockAdapter from 'axios-mock-adapter';
-import { nextTick } from 'vue';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
-import axios from '~/lib/utils/axios_utils';
-
-import TagToken, { TAG_SUGGESTIONS_PATH } from '~/runner/components/search_tokens/tag_token.vue';
-import { OPERATOR_IS_ONLY } 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('~/vue_shared/components/filtered_search_bar/filtered_search_utils', () => ({
- ...jest.requireActual('~/vue_shared/components/filtered_search_bar/filtered_search_utils'),
- getRecentlyUsedSuggestions: jest.fn(),
-}));
-
-const mockStorageKey = 'stored-recent-tags';
-
-const mockTags = [
- { id: 1, name: 'linux' },
- { id: 2, name: 'windows' },
- { id: 3, name: 'mac' },
-];
-
-const mockTagsFiltered = [mockTags[0]];
-
-const mockSearchTerm = mockTags[0].name;
-
-const GlFilteredSearchTokenStub = {
- template: `<div>
- <slot name="view-token"></slot>
- <slot name="suggestions"></slot>
- </div>`,
-};
-
-const mockTagTokenConfig = {
- icon: 'tag',
- title: 'Tags',
- type: 'tag',
- token: TagToken,
- recentSuggestionsStorageKey: mockStorageKey,
- operators: OPERATOR_IS_ONLY,
-};
-
-describe('TagToken', () => {
- let mock;
- let wrapper;
-
- const createComponent = (props = {}) => {
- wrapper = mount(TagToken, {
- propsData: {
- config: mockTagTokenConfig,
- value: { data: '' },
- active: false,
- ...props,
- },
- provide: {
- portalName: 'fake target',
- alignSuggestions: function fakeAlignSuggestions() {},
- filteredSearchSuggestionListInstance: {
- register: jest.fn(),
- unregister: jest.fn(),
- },
- },
- stubs: {
- GlFilteredSearchToken: GlFilteredSearchTokenStub,
- },
- });
- };
-
- const findGlFilteredSearchSuggestions = () =>
- wrapper.findAllComponents(GlFilteredSearchSuggestion);
- const findGlFilteredSearchToken = () => wrapper.findComponent(GlFilteredSearchTokenStub);
- const findToken = () => wrapper.findComponent(GlToken);
- const findGlLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
-
- beforeEach(() => {
- mock = new MockAdapter(axios);
-
- mock.onGet(TAG_SUGGESTIONS_PATH, { params: { search: '' } }).reply(200, mockTags);
- mock
- .onGet(TAG_SUGGESTIONS_PATH, { params: { search: mockSearchTerm } })
- .reply(200, mockTagsFiltered);
-
- getRecentlyUsedSuggestions.mockReturnValue([]);
- });
-
- afterEach(() => {
- getRecentlyUsedSuggestions.mockReset();
- wrapper.destroy();
- });
-
- describe('when the tags token is displayed', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('requests tags suggestions', () => {
- expect(mock.history.get[0].params).toEqual({ search: '' });
- });
-
- it('displays tags suggestions', async () => {
- await waitForPromises();
-
- mockTags.forEach(({ name }, i) => {
- expect(findGlFilteredSearchSuggestions().at(i).text()).toBe(name);
- });
- });
- });
-
- describe('when suggestions are stored', () => {
- const storedSuggestions = [{ id: 4, value: 'docker', text: 'docker' }];
-
- beforeEach(async () => {
- getRecentlyUsedSuggestions.mockReturnValue(storedSuggestions);
-
- createComponent();
- await waitForPromises();
- });
-
- it('suggestions are loaded from a correct key', () => {
- expect(getRecentlyUsedSuggestions).toHaveBeenCalledWith(mockStorageKey);
- });
-
- it('displays stored tags suggestions', () => {
- expect(findGlFilteredSearchSuggestions()).toHaveLength(
- mockTags.length + storedSuggestions.length,
- );
-
- expect(findGlFilteredSearchSuggestions().at(0).text()).toBe(storedSuggestions[0].text);
- });
- });
-
- describe('when the users filters suggestions', () => {
- beforeEach(() => {
- createComponent();
-
- findGlFilteredSearchToken().vm.$emit('input', { data: mockSearchTerm });
- });
-
- it('requests filtered tags suggestions', () => {
- expect(mock.history.get[1].params).toEqual({ search: mockSearchTerm });
- });
-
- it('shows the loading icon', async () => {
- findGlFilteredSearchToken().vm.$emit('input', { data: mockSearchTerm });
- await nextTick();
-
- expect(findGlLoadingIcon().exists()).toBe(true);
- });
-
- it('displays filtered tags suggestions', async () => {
- await waitForPromises();
-
- expect(findGlFilteredSearchSuggestions()).toHaveLength(mockTagsFiltered.length);
-
- expect(findGlFilteredSearchSuggestions().at(0).text()).toBe(mockTagsFiltered[0].name);
- });
- });
-
- describe('when suggestions cannot be loaded', () => {
- beforeEach(async () => {
- mock.onGet(TAG_SUGGESTIONS_PATH, { params: { search: '' } }).reply(500);
-
- createComponent();
- await waitForPromises();
- });
-
- it('error is shown', () => {
- expect(createAlert).toHaveBeenCalledTimes(1);
- expect(createAlert).toHaveBeenCalledWith({ message: expect.any(String) });
- });
- });
-
- describe('when the user selects a value', () => {
- beforeEach(async () => {
- createComponent({ value: { data: mockTags[0].name } });
- findGlFilteredSearchToken().vm.$emit('select');
-
- await waitForPromises();
- });
-
- it('selected tag is displayed', () => {
- expect(findToken().exists()).toBe(true);
- });
- });
-
- describe('when suggestions are disabled', () => {
- beforeEach(async () => {
- createComponent({
- config: {
- ...mockTagTokenConfig,
- suggestionsDisabled: true,
- },
- });
-
- await waitForPromises();
- });
-
- it('displays no suggestions', () => {
- expect(findGlFilteredSearchSuggestions()).toHaveLength(0);
- expect(mock.history.get).toHaveLength(0);
- });
- });
-});
diff --git a/spec/frontend/runner/components/stat/runner_count_spec.js b/spec/frontend/runner/components/stat/runner_count_spec.js
deleted file mode 100644
index 2a6a745099f..00000000000
--- a/spec/frontend/runner/components/stat/runner_count_spec.js
+++ /dev/null
@@ -1,148 +0,0 @@
-import Vue, { nextTick } from 'vue';
-import VueApollo from 'vue-apollo';
-import { shallowMount } from '@vue/test-utils';
-import RunnerCount from '~/runner/components/stat/runner_count.vue';
-import { INSTANCE_TYPE, GROUP_TYPE } from '~/runner/constants';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { captureException } from '~/runner/sentry_utils';
-
-import allRunnersCountQuery from 'ee_else_ce/runner/graphql/list/all_runners_count.query.graphql';
-import groupRunnersCountQuery from 'ee_else_ce/runner/graphql/list/group_runners_count.query.graphql';
-
-import { runnersCountData, groupRunnersCountData } from '../../mock_data';
-
-jest.mock('~/runner/sentry_utils');
-
-Vue.use(VueApollo);
-
-describe('RunnerCount', () => {
- let wrapper;
- let mockRunnersCountHandler;
- let mockGroupRunnersCountHandler;
-
- const createComponent = ({ props = {}, ...options } = {}) => {
- const handlers = [
- [allRunnersCountQuery, mockRunnersCountHandler],
- [groupRunnersCountQuery, mockGroupRunnersCountHandler],
- ];
-
- wrapper = shallowMount(RunnerCount, {
- apolloProvider: createMockApollo(handlers),
- propsData: {
- ...props,
- },
- scopedSlots: {
- default: '<strong>{{props.count}}</strong>',
- },
- ...options,
- });
-
- return waitForPromises();
- };
-
- beforeEach(() => {
- mockRunnersCountHandler = jest.fn().mockResolvedValue(runnersCountData);
- mockGroupRunnersCountHandler = jest.fn().mockResolvedValue(groupRunnersCountData);
- });
-
- describe('in admin scope', () => {
- const mockVariables = { status: 'ONLINE' };
-
- beforeEach(async () => {
- await createComponent({ props: { scope: INSTANCE_TYPE } });
- });
-
- it('fetches data from admin query', () => {
- expect(mockRunnersCountHandler).toHaveBeenCalledTimes(1);
- expect(mockRunnersCountHandler).toHaveBeenCalledWith({});
- });
-
- it('fetches data with filters', async () => {
- await createComponent({ props: { scope: INSTANCE_TYPE, variables: mockVariables } });
-
- expect(mockRunnersCountHandler).toHaveBeenCalledTimes(2);
- expect(mockRunnersCountHandler).toHaveBeenCalledWith(mockVariables);
-
- expect(wrapper.html()).toBe(`<strong>${runnersCountData.data.runners.count}</strong>`);
- });
-
- it('does not fetch from the group query', async () => {
- expect(mockGroupRunnersCountHandler).not.toHaveBeenCalled();
- });
-
- describe('when this query is skipped after data was loaded', () => {
- beforeEach(async () => {
- wrapper.setProps({ skip: true });
-
- await nextTick();
- });
-
- it('clears current data', () => {
- expect(wrapper.html()).toBe('<strong></strong>');
- });
- });
- });
-
- describe('when skipping query', () => {
- beforeEach(async () => {
- await createComponent({ props: { scope: INSTANCE_TYPE, skip: true } });
- });
-
- it('does not fetch data', async () => {
- expect(mockRunnersCountHandler).not.toHaveBeenCalled();
- expect(mockGroupRunnersCountHandler).not.toHaveBeenCalled();
-
- expect(wrapper.html()).toBe('<strong></strong>');
- });
- });
-
- describe('when runners query fails', () => {
- const mockError = new Error('error!');
-
- beforeEach(async () => {
- mockRunnersCountHandler.mockRejectedValue(mockError);
-
- await createComponent({ props: { scope: INSTANCE_TYPE } });
- });
-
- it('data is not shown and error is reported', async () => {
- expect(wrapper.html()).toBe('<strong></strong>');
-
- expect(captureException).toHaveBeenCalledWith({
- component: 'RunnerCount',
- error: mockError,
- });
- });
- });
-
- describe('in group scope', () => {
- beforeEach(async () => {
- await createComponent({ props: { scope: GROUP_TYPE } });
- });
-
- it('fetches data from the group query', async () => {
- expect(mockGroupRunnersCountHandler).toHaveBeenCalledTimes(1);
- expect(mockGroupRunnersCountHandler).toHaveBeenCalledWith({});
-
- expect(wrapper.html()).toBe(
- `<strong>${groupRunnersCountData.data.group.runners.count}</strong>`,
- );
- });
-
- it('does not fetch from the group query', () => {
- expect(mockRunnersCountHandler).not.toHaveBeenCalled();
- });
- });
-
- describe('when .refetch() is called', () => {
- beforeEach(async () => {
- await createComponent({ props: { scope: INSTANCE_TYPE } });
- wrapper.vm.refetch();
- });
-
- it('data is not shown and error is reported', async () => {
- expect(mockRunnersCountHandler).toHaveBeenCalledTimes(2);
- });
- });
-});
diff --git a/spec/frontend/runner/components/stat/runner_single_stat_spec.js b/spec/frontend/runner/components/stat/runner_single_stat_spec.js
deleted file mode 100644
index 964a6a6ff71..00000000000
--- a/spec/frontend/runner/components/stat/runner_single_stat_spec.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import { GlSingleStat } from '@gitlab/ui/dist/charts';
-import { shallowMount } from '@vue/test-utils';
-import RunnerSingleStat from '~/runner/components/stat/runner_single_stat.vue';
-import RunnerCount from '~/runner/components/stat/runner_count.vue';
-import { INSTANCE_TYPE, GROUP_TYPE } from '~/runner/constants';
-
-describe('RunnerStats', () => {
- let wrapper;
-
- const findRunnerCount = () => wrapper.findComponent(RunnerCount);
- const findGlSingleStat = () => wrapper.findComponent(GlSingleStat);
-
- const createComponent = ({ props = {}, count, mountFn = shallowMount, ...options } = {}) => {
- wrapper = mountFn(RunnerSingleStat, {
- propsData: {
- scope: INSTANCE_TYPE,
- title: 'My title',
- variables: {},
- ...props,
- },
- stubs: {
- RunnerCount: {
- props: ['scope', 'variables', 'skip'],
- render() {
- return this.$scopedSlots.default({
- count,
- });
- },
- },
- },
- ...options,
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it.each`
- case | count | value
- ${'number'} | ${99} | ${'99'}
- ${'long number'} | ${1000} | ${'1,000'}
- ${'empty number'} | ${null} | ${'-'}
- `('formats $case', ({ count, value }) => {
- createComponent({ count });
-
- expect(findGlSingleStat().props('value')).toBe(value);
- });
-
- it('Passes runner count props', () => {
- const props = {
- scope: GROUP_TYPE,
- variables: { paused: true },
- skip: true,
- };
-
- createComponent({ props });
-
- expect(findRunnerCount().props()).toEqual(props);
- });
-});
diff --git a/spec/frontend/runner/components/stat/runner_stats_spec.js b/spec/frontend/runner/components/stat/runner_stats_spec.js
deleted file mode 100644
index 4afbe453903..00000000000
--- a/spec/frontend/runner/components/stat/runner_stats_spec.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import { shallowMount, mount } from '@vue/test-utils';
-import RunnerStats from '~/runner/components/stat/runner_stats.vue';
-import RunnerSingleStat from '~/runner/components/stat/runner_single_stat.vue';
-import {
- I18N_STATUS_ONLINE,
- I18N_STATUS_OFFLINE,
- I18N_STATUS_STALE,
- INSTANCE_TYPE,
- STATUS_ONLINE,
- STATUS_OFFLINE,
- STATUS_STALE,
-} from '~/runner/constants';
-
-describe('RunnerStats', () => {
- let wrapper;
-
- const findSingleStats = () => wrapper.findAllComponents(RunnerSingleStat);
-
- const createComponent = ({ props = {}, mountFn = shallowMount, ...options } = {}) => {
- wrapper = mountFn(RunnerStats, {
- propsData: {
- scope: INSTANCE_TYPE,
- variables: {},
- ...props,
- },
- ...options,
- });
- };
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('Displays all the stats', () => {
- const mockCounts = {
- [STATUS_ONLINE]: 3,
- [STATUS_OFFLINE]: 2,
- [STATUS_STALE]: 1,
- };
-
- createComponent({
- mountFn: mount,
- stubs: {
- RunnerCount: {
- props: ['variables'],
- render() {
- return this.$scopedSlots.default({
- count: mockCounts[this.variables.status],
- });
- },
- },
- },
- });
-
- const text = wrapper.text();
- expect(text).toContain(`${I18N_STATUS_ONLINE} 3`);
- expect(text).toContain(`${I18N_STATUS_OFFLINE} 2`);
- expect(text).toContain(`${I18N_STATUS_STALE} 1`);
- });
-
- it('Skips query for other stats', () => {
- createComponent({
- props: {
- variables: { status: STATUS_ONLINE },
- },
- });
-
- expect(findSingleStats().at(0).props('skip')).toBe(false);
- expect(findSingleStats().at(1).props('skip')).toBe(true);
- expect(findSingleStats().at(2).props('skip')).toBe(true);
- });
-
- it('Displays all counts for filtered searches', () => {
- const mockVariables = { paused: true };
- createComponent({ props: { variables: mockVariables } });
-
- findSingleStats().wrappers.forEach((stat) => {
- expect(stat.props('variables')).toMatchObject(mockVariables);
- });
- });
-});
diff --git a/spec/frontend/runner/graphql/local_state_spec.js b/spec/frontend/runner/graphql/local_state_spec.js
deleted file mode 100644
index 915170b53f9..00000000000
--- a/spec/frontend/runner/graphql/local_state_spec.js
+++ /dev/null
@@ -1,167 +0,0 @@
-import { gql } from '@apollo/client/core';
-import createApolloClient from '~/lib/graphql';
-import { createLocalState } from '~/runner/graphql/list/local_state';
-import getCheckedRunnerIdsQuery from '~/runner/graphql/list/checked_runner_ids.query.graphql';
-import { RUNNER_TYPENAME } from '~/runner/constants';
-
-const makeRunner = (id, deleteRunner = true) => ({
- id,
- userPermissions: {
- deleteRunner,
- },
-});
-
-describe('~/runner/graphql/list/local_state', () => {
- let localState;
- let apolloClient;
-
- const createSubject = () => {
- if (apolloClient) {
- throw new Error('test subject already exists!');
- }
-
- localState = createLocalState();
-
- const { cacheConfig, typeDefs } = localState;
-
- apolloClient = createApolloClient({}, { cacheConfig, typeDefs });
- };
-
- const addMockRunnerToCache = (id) => {
- // mock some runners in the cache to prevent dangling references
- apolloClient.writeFragment({
- id: `${RUNNER_TYPENAME}:${id}`,
- fragment: gql`
- fragment DummyRunner on CiRunner {
- __typename
- }
- `,
- data: {
- __typename: RUNNER_TYPENAME,
- },
- });
- };
-
- const queryCheckedRunnerIds = () => {
- const { checkedRunnerIds } = apolloClient.readQuery({
- query: getCheckedRunnerIdsQuery,
- });
- return checkedRunnerIds;
- };
-
- beforeEach(() => {
- createSubject();
- });
-
- afterEach(() => {
- localState = null;
- apolloClient = null;
- });
-
- describe('queryCheckedRunnerIds', () => {
- it('has empty checked list by default', () => {
- expect(queryCheckedRunnerIds()).toEqual([]);
- });
-
- it('returns checked runners that have a reference in the cache', () => {
- const id = 'a';
-
- addMockRunnerToCache(id);
- localState.localMutations.setRunnerChecked({
- runner: makeRunner(id),
- isChecked: true,
- });
-
- expect(queryCheckedRunnerIds()).toEqual(['a']);
- });
-
- it('return checked runners that are not dangling references', () => {
- addMockRunnerToCache('a'); // 'b' is missing from the cache, perhaps because it was deleted
- localState.localMutations.setRunnerChecked({ runner: makeRunner('a'), isChecked: true });
- localState.localMutations.setRunnerChecked({ runner: makeRunner('b'), isChecked: true });
-
- expect(queryCheckedRunnerIds()).toEqual(['a']);
- });
- });
-
- describe.each`
- inputs | expected
- ${[['a', true], ['b', true], ['b', true]]} | ${['a', 'b']}
- ${[['a', true], ['b', true], ['a', false]]} | ${['b']}
- ${[['c', true], ['b', true], ['a', true], ['d', false]]} | ${['c', 'b', 'a']}
- `('setRunnerChecked', ({ inputs, expected }) => {
- beforeEach(() => {
- inputs.forEach(([id, isChecked]) => {
- addMockRunnerToCache(id);
- localState.localMutations.setRunnerChecked({ runner: makeRunner(id), isChecked });
- });
- });
- it(`for inputs="${inputs}" has a ids="[${expected}]"`, () => {
- expect(queryCheckedRunnerIds()).toEqual(expected);
- });
- });
-
- describe.each`
- inputs | expected
- ${[[['a', 'b'], true]]} | ${['a', 'b']}
- ${[[['a', 'b'], false]]} | ${[]}
- ${[[['a', 'b'], true], [['c', 'd'], true]]} | ${['a', 'b', 'c', 'd']}
- ${[[['a', 'b'], true], [['a', 'b'], false]]} | ${[]}
- ${[[['a', 'b'], true], [['b'], false]]} | ${['a']}
- `('setRunnersChecked', ({ inputs, expected }) => {
- beforeEach(() => {
- inputs.forEach(([ids, isChecked]) => {
- ids.forEach(addMockRunnerToCache);
-
- localState.localMutations.setRunnersChecked({
- runners: ids.map((id) => makeRunner(id)),
- isChecked,
- });
- });
- });
-
- it(`for inputs="${inputs}" has a ids="[${expected}]"`, () => {
- expect(queryCheckedRunnerIds()).toEqual(expected);
- });
- });
-
- describe('clearChecked', () => {
- it('clears all checked items', () => {
- ['a', 'b', 'c'].forEach((id) => {
- addMockRunnerToCache(id);
- localState.localMutations.setRunnerChecked({ runner: makeRunner(id), isChecked: true });
- });
-
- expect(queryCheckedRunnerIds()).toEqual(['a', 'b', 'c']);
-
- localState.localMutations.clearChecked();
-
- expect(queryCheckedRunnerIds()).toEqual([]);
- });
- });
-
- describe('when some runners cannot be deleted', () => {
- beforeEach(() => {
- addMockRunnerToCache('a');
- addMockRunnerToCache('b');
- });
-
- it('setRunnerChecked does not check runner that cannot be deleted', () => {
- localState.localMutations.setRunnerChecked({
- runner: makeRunner('a', false),
- isChecked: true,
- });
-
- expect(queryCheckedRunnerIds()).toEqual([]);
- });
-
- it('setRunnersChecked does not check runner that cannot be deleted', () => {
- localState.localMutations.setRunnersChecked({
- runners: [makeRunner('a', false), makeRunner('b', false)],
- isChecked: true,
- });
-
- expect(queryCheckedRunnerIds()).toEqual([]);
- });
- });
-});
diff --git a/spec/frontend/runner/group_runner_show/group_runner_show_app_spec.js b/spec/frontend/runner/group_runner_show/group_runner_show_app_spec.js
deleted file mode 100644
index a3b67674c94..00000000000
--- a/spec/frontend/runner/group_runner_show/group_runner_show_app_spec.js
+++ /dev/null
@@ -1,215 +0,0 @@
-import Vue from 'vue';
-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 { redirectTo } from '~/lib/utils/url_utility';
-
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import RunnerHeader from '~/runner/components/runner_header.vue';
-import RunnerDetails from '~/runner/components/runner_details.vue';
-import RunnerPauseButton from '~/runner/components/runner_pause_button.vue';
-import RunnerDeleteButton from '~/runner/components/runner_delete_button.vue';
-import RunnerEditButton from '~/runner/components/runner_edit_button.vue';
-import runnerQuery from '~/runner/graphql/show/runner.query.graphql';
-import GroupRunnerShowApp from '~/runner/group_runner_show/group_runner_show_app.vue';
-import { captureException } from '~/runner/sentry_utils';
-import { saveAlertToLocalStorage } from '~/runner/local_storage_alert/save_alert_to_local_storage';
-
-import { runnerData } from '../mock_data';
-
-jest.mock('~/runner/local_storage_alert/save_alert_to_local_storage');
-jest.mock('~/flash');
-jest.mock('~/runner/sentry_utils');
-jest.mock('~/lib/utils/url_utility');
-
-const mockRunner = runnerData.data.runner;
-const mockRunnerGraphqlId = mockRunner.id;
-const mockRunnerId = `${getIdFromGraphQLId(mockRunnerGraphqlId)}`;
-const mockRunnersPath = '/groups/group1/-/runners';
-const mockEditGroupRunnerPath = `/groups/group1/-/runners/${mockRunnerId}/edit`;
-
-Vue.use(VueApollo);
-
-describe('GroupRunnerShowApp', () => {
- let wrapper;
- let mockRunnerQuery;
-
- const findRunnerHeader = () => wrapper.findComponent(RunnerHeader);
- const findRunnerDetails = () => wrapper.findComponent(RunnerDetails);
- const findRunnerDeleteButton = () => wrapper.findComponent(RunnerDeleteButton);
- const findRunnerEditButton = () => wrapper.findComponent(RunnerEditButton);
- const findRunnerPauseButton = () => wrapper.findComponent(RunnerPauseButton);
-
- const mockRunnerQueryResult = (runner = {}) => {
- mockRunnerQuery = jest.fn().mockResolvedValue({
- data: {
- runner: { ...mockRunner, ...runner },
- },
- });
- };
-
- const createComponent = ({ props = {}, mountFn = shallowMountExtended, ...options } = {}) => {
- wrapper = mountFn(GroupRunnerShowApp, {
- apolloProvider: createMockApollo([[runnerQuery, mockRunnerQuery]]),
- propsData: {
- runnerId: mockRunnerId,
- runnersPath: mockRunnersPath,
- editGroupRunnerPath: mockEditGroupRunnerPath,
- ...props,
- },
- ...options,
- });
-
- return waitForPromises();
- };
-
- afterEach(() => {
- mockRunnerQuery.mockReset();
- wrapper.destroy();
- });
-
- describe('When showing runner details', () => {
- beforeEach(async () => {
- mockRunnerQueryResult();
-
- await createComponent({ mountFn: mountExtended });
- });
-
- it('expect GraphQL ID to be requested', async () => {
- expect(mockRunnerQuery).toHaveBeenCalledWith({ id: mockRunnerGraphqlId });
- });
-
- it('displays the header', async () => {
- expect(findRunnerHeader().text()).toContain(`Runner #${mockRunnerId}`);
- });
-
- it('displays edit, pause, delete buttons', async () => {
- expect(findRunnerEditButton().exists()).toBe(true);
- expect(findRunnerPauseButton().exists()).toBe(true);
- expect(findRunnerDeleteButton().exists()).toBe(true);
- });
-
- it('shows basic runner details', () => {
- const expected = `Description My Runner
- Last contact Never contacted
- Version 1.0.0
- IP Address None
- Executor None
- Architecture None
- Platform darwin
- Configuration Runs untagged jobs
- Maximum job timeout None
- Token expiry
- Runner authentication token expiration
- Runner authentication tokens will expire based on a set interval.
- They will automatically rotate once expired. Learn more
- Never expires
- Tags None`.replace(/\s+/g, ' ');
-
- expect(wrapper.text().replace(/\s+/g, ' ')).toContain(expected);
- });
-
- it('renders runner details component', () => {
- expect(findRunnerDetails().props('runner')).toEqual(mockRunner);
- });
-
- describe('when runner cannot be updated', () => {
- beforeEach(async () => {
- mockRunnerQueryResult({
- userPermissions: {
- ...mockRunner.userPermissions,
- updateRunner: false,
- },
- });
-
- await createComponent({
- mountFn: mountExtended,
- });
- });
-
- it('does not display edit and pause buttons', () => {
- expect(findRunnerEditButton().exists()).toBe(false);
- expect(findRunnerPauseButton().exists()).toBe(false);
- });
-
- it('displays delete button', () => {
- expect(findRunnerDeleteButton().exists()).toBe(true);
- });
- });
-
- describe('when runner cannot be deleted', () => {
- beforeEach(async () => {
- mockRunnerQueryResult({
- userPermissions: {
- ...mockRunner.userPermissions,
- deleteRunner: false,
- },
- });
-
- await createComponent({
- mountFn: mountExtended,
- });
- });
-
- it('does not display delete button', () => {
- expect(findRunnerDeleteButton().exists()).toBe(false);
- });
-
- it('displays edit and pause buttons', () => {
- expect(findRunnerEditButton().exists()).toBe(true);
- expect(findRunnerPauseButton().exists()).toBe(true);
- });
- });
-
- describe('when runner is deleted', () => {
- beforeEach(async () => {
- await createComponent({
- mountFn: mountExtended,
- });
- });
-
- it('redirects to the runner list page', () => {
- findRunnerDeleteButton().vm.$emit('deleted', { message: 'Runner deleted' });
-
- expect(saveAlertToLocalStorage).toHaveBeenCalledWith({
- message: 'Runner deleted',
- variant: VARIANT_SUCCESS,
- });
- expect(redirectTo).toHaveBeenCalledWith(mockRunnersPath);
- });
- });
- });
-
- describe('When loading', () => {
- it('does not show runner details', () => {
- mockRunnerQueryResult();
-
- createComponent();
- expect(findRunnerDetails().exists()).toBe(false);
- });
- });
-
- describe('When there is an error', () => {
- beforeEach(async () => {
- mockRunnerQuery = jest.fn().mockRejectedValueOnce(new Error('Error!'));
- await createComponent();
- });
-
- it('does not show runner details', () => {
- expect(findRunnerDetails().exists()).toBe(false);
- });
-
- it('error is reported to sentry', () => {
- expect(captureException).toHaveBeenCalledWith({
- error: new Error('Error!'),
- component: 'GroupRunnerShowApp',
- });
- });
-
- it('error is shown to the user', () => {
- expect(createAlert).toHaveBeenCalled();
- });
- });
-});
diff --git a/spec/frontend/runner/group_runners/group_runners_app_spec.js b/spec/frontend/runner/group_runners/group_runners_app_spec.js
deleted file mode 100644
index 7482926e151..00000000000
--- a/spec/frontend/runner/group_runners/group_runners_app_spec.js
+++ /dev/null
@@ -1,499 +0,0 @@
-import Vue, { nextTick } from 'vue';
-import { GlButton, GlLink, GlToast } from '@gitlab/ui';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import setWindowLocation from 'helpers/set_window_location_helper';
-import {
- extendedWrapper,
- shallowMountExtended,
- mountExtended,
-} from 'helpers/vue_test_utils_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
-import { s__ } from '~/locale';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { updateHistory } from '~/lib/utils/url_utility';
-import { upgradeStatusTokenConfig } from 'ee_else_ce/runner/components/search_tokens/upgrade_status_token_config';
-import { createLocalState } from '~/runner/graphql/list/local_state';
-
-import RunnerStackedLayoutBanner from '~/runner/components/runner_stacked_layout_banner.vue';
-import RunnerTypeTabs from '~/runner/components/runner_type_tabs.vue';
-import RunnerFilteredSearchBar from '~/runner/components/runner_filtered_search_bar.vue';
-import RunnerList from '~/runner/components/runner_list.vue';
-import RunnerListEmptyState from '~/runner/components/runner_list_empty_state.vue';
-import RunnerStats from '~/runner/components/stat/runner_stats.vue';
-import RunnerActionsCell from '~/runner/components/cells/runner_actions_cell.vue';
-import RegistrationDropdown from '~/runner/components/registration/registration_dropdown.vue';
-import RunnerPagination from '~/runner/components/runner_pagination.vue';
-import RunnerMembershipToggle from '~/runner/components/runner_membership_toggle.vue';
-
-import {
- CREATED_ASC,
- CREATED_DESC,
- DEFAULT_SORT,
- I18N_STATUS_ONLINE,
- I18N_STATUS_OFFLINE,
- I18N_STATUS_STALE,
- INSTANCE_TYPE,
- GROUP_TYPE,
- PARAM_KEY_PAUSED,
- PARAM_KEY_STATUS,
- PARAM_KEY_TAG,
- STATUS_ONLINE,
- STATUS_OFFLINE,
- STATUS_STALE,
- MEMBERSHIP_ALL_AVAILABLE,
- MEMBERSHIP_DESCENDANTS,
- RUNNER_PAGE_SIZE,
- I18N_EDIT,
-} from '~/runner/constants';
-import groupRunnersQuery from 'ee_else_ce/runner/graphql/list/group_runners.query.graphql';
-import groupRunnersCountQuery from 'ee_else_ce/runner/graphql/list/group_runners_count.query.graphql';
-import GroupRunnersApp from '~/runner/group_runners/group_runners_app.vue';
-import { captureException } from '~/runner/sentry_utils';
-import {
- groupRunnersData,
- groupRunnersDataPaginated,
- groupRunnersCountData,
- onlineContactTimeoutSecs,
- staleTimeoutSecs,
- emptyPageInfo,
- emptyStateSvgPath,
- emptyStateFilteredSvgPath,
-} from '../mock_data';
-
-Vue.use(VueApollo);
-Vue.use(GlToast);
-
-const mockGroupFullPath = 'group1';
-const mockRegistrationToken = 'AABBCC';
-const mockGroupRunnersEdges = groupRunnersData.data.group.runners.edges;
-const mockGroupRunnersCount = mockGroupRunnersEdges.length;
-
-const mockGroupRunnersHandler = jest.fn();
-const mockGroupRunnersCountHandler = jest.fn();
-
-jest.mock('~/flash');
-jest.mock('~/runner/sentry_utils');
-jest.mock('~/lib/utils/url_utility', () => ({
- ...jest.requireActual('~/lib/utils/url_utility'),
- updateHistory: jest.fn(),
-}));
-
-describe('GroupRunnersApp', () => {
- let wrapper;
-
- const findRunnerStackedLayoutBanner = () => wrapper.findComponent(RunnerStackedLayoutBanner);
- const findRunnerStats = () => wrapper.findComponent(RunnerStats);
- const findRunnerActionsCell = () => wrapper.findComponent(RunnerActionsCell);
- const findRegistrationDropdown = () => wrapper.findComponent(RegistrationDropdown);
- const findRunnerTypeTabs = () => wrapper.findComponent(RunnerTypeTabs);
- const findRunnerList = () => wrapper.findComponent(RunnerList);
- const findRunnerListEmptyState = () => wrapper.findComponent(RunnerListEmptyState);
- const findRunnerRow = (id) => extendedWrapper(wrapper.findByTestId(`runner-row-${id}`));
- const findRunnerPagination = () => extendedWrapper(wrapper.findComponent(RunnerPagination));
- const findRunnerPaginationNext = () => findRunnerPagination().findByText(s__('Pagination|Next'));
- const findRunnerFilteredSearchBar = () => wrapper.findComponent(RunnerFilteredSearchBar);
- const findRunnerMembershipToggle = () => wrapper.findComponent(RunnerMembershipToggle);
-
- const createComponent = ({
- props = {},
- provide = {},
- mountFn = shallowMountExtended,
- ...options
- } = {}) => {
- const { cacheConfig, localMutations } = createLocalState();
-
- const handlers = [
- [groupRunnersQuery, mockGroupRunnersHandler],
- [groupRunnersCountQuery, mockGroupRunnersCountHandler],
- ];
-
- wrapper = mountFn(GroupRunnersApp, {
- apolloProvider: createMockApollo(handlers, {}, cacheConfig),
- propsData: {
- registrationToken: mockRegistrationToken,
- groupFullPath: mockGroupFullPath,
- groupRunnersLimitedCount: mockGroupRunnersCount,
- ...props,
- },
- provide: {
- localMutations,
- onlineContactTimeoutSecs,
- staleTimeoutSecs,
- emptyStateSvgPath,
- emptyStateFilteredSvgPath,
- ...provide,
- },
- ...options,
- });
-
- return waitForPromises();
- };
-
- beforeEach(() => {
- mockGroupRunnersHandler.mockResolvedValue(groupRunnersData);
- mockGroupRunnersCountHandler.mockResolvedValue(groupRunnersCountData);
- });
-
- afterEach(() => {
- mockGroupRunnersHandler.mockReset();
- mockGroupRunnersCountHandler.mockReset();
- wrapper.destroy();
- });
-
- it('shows the feedback banner', () => {
- createComponent();
- expect(findRunnerStackedLayoutBanner().exists()).toBe(true);
- });
-
- it('shows the runner tabs with a runner count for each type', async () => {
- await createComponent({ mountFn: mountExtended });
-
- expect(findRunnerTypeTabs().text()).toMatchInterpolatedText(
- `All ${mockGroupRunnersCount} Group ${mockGroupRunnersCount} Project ${mockGroupRunnersCount}`,
- );
- });
-
- it('shows the runner setup instructions', () => {
- createComponent();
-
- expect(findRegistrationDropdown().props('registrationToken')).toBe(mockRegistrationToken);
- expect(findRegistrationDropdown().props('type')).toBe(GROUP_TYPE);
- });
-
- describe('show all available runners toggle', () => {
- it('shows the membership toggle', () => {
- createComponent();
- expect(findRunnerMembershipToggle().exists()).toBe(true);
- });
-
- it('sets the membership toggle', () => {
- setWindowLocation(`?membership[]=${MEMBERSHIP_ALL_AVAILABLE}`);
-
- createComponent();
-
- expect(findRunnerMembershipToggle().props('value')).toBe(MEMBERSHIP_ALL_AVAILABLE);
- });
-
- it('requests filter', async () => {
- createComponent();
- findRunnerMembershipToggle().vm.$emit('input', MEMBERSHIP_ALL_AVAILABLE);
-
- await waitForPromises();
-
- expect(mockGroupRunnersHandler).toHaveBeenLastCalledWith(
- expect.objectContaining({
- membership: MEMBERSHIP_ALL_AVAILABLE,
- }),
- );
- });
- });
-
- it('shows total runner counts', async () => {
- await createComponent({ mountFn: mountExtended });
-
- expect(mockGroupRunnersCountHandler).toHaveBeenCalledWith({
- status: STATUS_ONLINE,
- membership: MEMBERSHIP_DESCENDANTS,
- groupFullPath: mockGroupFullPath,
- });
- expect(mockGroupRunnersCountHandler).toHaveBeenCalledWith({
- status: STATUS_OFFLINE,
- membership: MEMBERSHIP_DESCENDANTS,
- groupFullPath: mockGroupFullPath,
- });
- expect(mockGroupRunnersCountHandler).toHaveBeenCalledWith({
- status: STATUS_STALE,
- membership: MEMBERSHIP_DESCENDANTS,
- groupFullPath: mockGroupFullPath,
- });
-
- const text = findRunnerStats().text();
- expect(text).toContain(`${I18N_STATUS_ONLINE} ${mockGroupRunnersCount}`);
- expect(text).toContain(`${I18N_STATUS_OFFLINE} ${mockGroupRunnersCount}`);
- expect(text).toContain(`${I18N_STATUS_STALE} ${mockGroupRunnersCount}`);
- });
-
- it('shows the runners list', async () => {
- await createComponent();
-
- const runners = findRunnerList().props('runners');
- expect(runners).toEqual(mockGroupRunnersEdges.map(({ node }) => node));
- });
-
- it('requests the runners with group path and no other filters', async () => {
- await createComponent();
-
- expect(mockGroupRunnersHandler).toHaveBeenLastCalledWith({
- groupFullPath: mockGroupFullPath,
- status: undefined,
- type: undefined,
- membership: MEMBERSHIP_DESCENDANTS,
- sort: DEFAULT_SORT,
- first: RUNNER_PAGE_SIZE,
- });
- });
-
- it('sets tokens in the filtered search', () => {
- createComponent();
-
- const tokens = findRunnerFilteredSearchBar().props('tokens');
-
- expect(tokens).toEqual([
- expect.objectContaining({
- type: PARAM_KEY_PAUSED,
- options: expect.any(Array),
- }),
- expect.objectContaining({
- type: PARAM_KEY_STATUS,
- options: expect.any(Array),
- }),
- expect.objectContaining({
- type: PARAM_KEY_TAG,
- suggestionsDisabled: true,
- }),
- upgradeStatusTokenConfig,
- ]);
- });
-
- describe('Single runner row', () => {
- let showToast;
-
- const { webUrl, editUrl, node } = mockGroupRunnersEdges[0];
- const { id: graphqlId, shortSha } = node;
- const id = getIdFromGraphQLId(graphqlId);
- const COUNT_QUERIES = 6; // Smart queries that display a filtered count of runners
- const FILTERED_COUNT_QUERIES = 6; // Smart queries that display a count of runners in tabs and single stats
-
- beforeEach(async () => {
- await createComponent({ mountFn: mountExtended });
- showToast = jest.spyOn(wrapper.vm.$root.$toast, 'show');
- });
-
- it('view link is displayed correctly', () => {
- const viewLink = findRunnerRow(id).findByTestId('td-summary').findComponent(GlLink);
-
- expect(viewLink.text()).toBe(`#${id} (${shortSha})`);
- expect(viewLink.attributes('href')).toBe(webUrl);
- });
-
- it('edit link is displayed correctly', () => {
- const editLink = findRunnerRow(id).findByTestId('td-actions').findComponent(GlButton);
-
- expect(editLink.attributes()).toMatchObject({
- 'aria-label': I18N_EDIT,
- href: editUrl,
- });
- });
-
- it('When runner is paused or unpaused, some data is refetched', async () => {
- expect(mockGroupRunnersCountHandler).toHaveBeenCalledTimes(COUNT_QUERIES);
-
- findRunnerActionsCell().vm.$emit('toggledPaused');
-
- expect(mockGroupRunnersCountHandler).toHaveBeenCalledTimes(
- COUNT_QUERIES + FILTERED_COUNT_QUERIES,
- );
-
- expect(showToast).toHaveBeenCalledTimes(0);
- });
-
- it('When runner is deleted, data is refetched and a toast message is shown', async () => {
- findRunnerActionsCell().vm.$emit('deleted', { message: 'Runner deleted' });
-
- expect(showToast).toHaveBeenCalledTimes(1);
- expect(showToast).toHaveBeenCalledWith('Runner deleted');
- });
- });
-
- describe('when a filter is preselected', () => {
- beforeEach(async () => {
- setWindowLocation(`?status[]=${STATUS_ONLINE}&runner_type[]=${INSTANCE_TYPE}`);
-
- await createComponent({ mountFn: mountExtended });
- });
-
- it('sets the filters in the search bar', () => {
- expect(findRunnerFilteredSearchBar().props('value')).toEqual({
- runnerType: INSTANCE_TYPE,
- membership: MEMBERSHIP_DESCENDANTS,
- filters: [{ type: 'status', value: { data: STATUS_ONLINE, operator: '=' } }],
- sort: 'CREATED_DESC',
- pagination: {},
- });
- });
-
- it('requests the runners with filter parameters', () => {
- expect(mockGroupRunnersHandler).toHaveBeenLastCalledWith({
- groupFullPath: mockGroupFullPath,
- status: STATUS_ONLINE,
- type: INSTANCE_TYPE,
- membership: MEMBERSHIP_DESCENDANTS,
- sort: DEFAULT_SORT,
- first: RUNNER_PAGE_SIZE,
- });
- });
-
- it('fetches count results for requested status', () => {
- expect(mockGroupRunnersCountHandler).toHaveBeenCalledWith({
- groupFullPath: mockGroupFullPath,
- type: INSTANCE_TYPE,
- membership: MEMBERSHIP_DESCENDANTS,
- status: STATUS_ONLINE,
- });
- });
- });
-
- describe('when a filter is selected by the user', () => {
- beforeEach(async () => {
- await createComponent({ mountFn: mountExtended });
-
- findRunnerFilteredSearchBar().vm.$emit('input', {
- runnerType: null,
- membership: MEMBERSHIP_DESCENDANTS,
- filters: [{ type: PARAM_KEY_STATUS, value: { data: STATUS_ONLINE, operator: '=' } }],
- sort: CREATED_ASC,
- });
-
- await nextTick();
- });
-
- it('updates the browser url', () => {
- expect(updateHistory).toHaveBeenLastCalledWith({
- title: expect.any(String),
- url: expect.stringContaining('?status[]=ONLINE&sort=CREATED_ASC'),
- });
- });
-
- it('requests the runners with filters', () => {
- expect(mockGroupRunnersHandler).toHaveBeenLastCalledWith({
- groupFullPath: mockGroupFullPath,
- status: STATUS_ONLINE,
- membership: MEMBERSHIP_DESCENDANTS,
- sort: CREATED_ASC,
- first: RUNNER_PAGE_SIZE,
- });
- });
-
- it('fetches count results for requested status', () => {
- expect(mockGroupRunnersCountHandler).toHaveBeenCalledWith({
- groupFullPath: mockGroupFullPath,
- status: STATUS_ONLINE,
- membership: MEMBERSHIP_DESCENDANTS,
- });
- });
- });
-
- it('when runners have not loaded, shows a loading state', () => {
- createComponent();
- expect(findRunnerList().props('loading')).toBe(true);
- expect(findRunnerPagination().attributes('disabled')).toBe('true');
- });
-
- it('runners cannot be deleted in bulk', () => {
- createComponent();
- expect(findRunnerList().props('checkable')).toBe(false);
- });
-
- describe('when no runners are found', () => {
- beforeEach(async () => {
- mockGroupRunnersHandler.mockResolvedValue({
- data: {
- group: {
- id: '1',
- runners: {
- edges: [],
- pageInfo: emptyPageInfo,
- },
- },
- },
- });
- await createComponent();
- });
-
- it('shows no errors', () => {
- expect(createAlert).not.toHaveBeenCalled();
- });
-
- it('shows an empty state', async () => {
- expect(findRunnerListEmptyState().exists()).toBe(true);
- });
- });
-
- describe('when runners query fails', () => {
- beforeEach(async () => {
- mockGroupRunnersHandler.mockRejectedValue(new Error('Error!'));
- await createComponent();
- });
-
- it('error is shown to the user', async () => {
- expect(createAlert).toHaveBeenCalledTimes(1);
- });
-
- it('error is reported to sentry', async () => {
- expect(captureException).toHaveBeenCalledWith({
- error: new Error('Error!'),
- component: 'GroupRunnersApp',
- });
- });
- });
-
- describe('Pagination', () => {
- const { pageInfo } = groupRunnersDataPaginated.data.group.runners;
-
- beforeEach(async () => {
- mockGroupRunnersHandler.mockResolvedValue(groupRunnersDataPaginated);
-
- await createComponent({ mountFn: mountExtended });
- });
-
- it('passes the page info', () => {
- expect(findRunnerPagination().props('pageInfo')).toEqual(pageInfo);
- });
-
- it('navigates to the next page', async () => {
- await findRunnerPaginationNext().trigger('click');
-
- expect(mockGroupRunnersHandler).toHaveBeenLastCalledWith({
- groupFullPath: mockGroupFullPath,
- membership: MEMBERSHIP_DESCENDANTS,
- sort: CREATED_DESC,
- first: RUNNER_PAGE_SIZE,
- after: pageInfo.endCursor,
- });
- });
- });
-
- describe('when user has permission to register group runner', () => {
- beforeEach(() => {
- createComponent({
- propsData: {
- registrationToken: mockRegistrationToken,
- groupFullPath: mockGroupFullPath,
- groupRunnersLimitedCount: mockGroupRunnersCount,
- },
- });
- });
-
- it('shows the register group runner button', () => {
- expect(findRegistrationDropdown().exists()).toBe(true);
- });
- });
-
- describe('when user has no permission to register group runner', () => {
- beforeEach(() => {
- createComponent({
- propsData: {
- registrationToken: null,
- groupFullPath: mockGroupFullPath,
- groupRunnersLimitedCount: mockGroupRunnersCount,
- },
- });
- });
-
- it('does not show the register group runner button', () => {
- expect(findRegistrationDropdown().exists()).toBe(false);
- });
- });
-});
diff --git a/spec/frontend/runner/local_storage_alert/save_alert_to_local_storage_spec.js b/spec/frontend/runner/local_storage_alert/save_alert_to_local_storage_spec.js
deleted file mode 100644
index 69cda6d6022..00000000000
--- a/spec/frontend/runner/local_storage_alert/save_alert_to_local_storage_spec.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import AccessorUtilities from '~/lib/utils/accessor';
-import { saveAlertToLocalStorage } from '~/runner/local_storage_alert/save_alert_to_local_storage';
-import { LOCAL_STORAGE_ALERT_KEY } from '~/runner/local_storage_alert/constants';
-import { useLocalStorageSpy } from 'helpers/local_storage_helper';
-
-const mockAlert = { message: 'Message!' };
-
-describe('saveAlertToLocalStorage', () => {
- useLocalStorageSpy();
-
- beforeEach(() => {
- jest.spyOn(AccessorUtilities, 'canUseLocalStorage').mockReturnValue(true);
- });
-
- it('saves message to local storage', () => {
- saveAlertToLocalStorage(mockAlert);
-
- expect(localStorage.setItem).toHaveBeenCalledTimes(1);
- expect(localStorage.setItem).toHaveBeenCalledWith(
- LOCAL_STORAGE_ALERT_KEY,
- JSON.stringify(mockAlert),
- );
- });
-});
diff --git a/spec/frontend/runner/local_storage_alert/show_alert_from_local_storage_spec.js b/spec/frontend/runner/local_storage_alert/show_alert_from_local_storage_spec.js
deleted file mode 100644
index cabbe642dac..00000000000
--- a/spec/frontend/runner/local_storage_alert/show_alert_from_local_storage_spec.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import AccessorUtilities from '~/lib/utils/accessor';
-import { showAlertFromLocalStorage } from '~/runner/local_storage_alert/show_alert_from_local_storage';
-import { LOCAL_STORAGE_ALERT_KEY } from '~/runner/local_storage_alert/constants';
-import { useLocalStorageSpy } from 'helpers/local_storage_helper';
-import { createAlert } from '~/flash';
-
-jest.mock('~/flash');
-
-describe('showAlertFromLocalStorage', () => {
- useLocalStorageSpy();
-
- beforeEach(() => {
- jest.spyOn(AccessorUtilities, 'canUseLocalStorage').mockReturnValue(true);
- });
-
- it('retrieves message from local storage and displays it', async () => {
- const mockAlert = { message: 'Message!' };
-
- localStorage.getItem.mockReturnValueOnce(JSON.stringify(mockAlert));
-
- await showAlertFromLocalStorage();
-
- expect(createAlert).toHaveBeenCalledTimes(1);
- expect(createAlert).toHaveBeenCalledWith(mockAlert);
-
- expect(localStorage.removeItem).toHaveBeenCalledTimes(1);
- expect(localStorage.removeItem).toHaveBeenCalledWith(LOCAL_STORAGE_ALERT_KEY);
- });
-
- it.each(['not a json string', null])('does not fail when stored message is %o', async (item) => {
- localStorage.getItem.mockReturnValueOnce(item);
-
- await showAlertFromLocalStorage();
-
- expect(createAlert).not.toHaveBeenCalled();
-
- expect(localStorage.removeItem).toHaveBeenCalledTimes(1);
- expect(localStorage.removeItem).toHaveBeenCalledWith(LOCAL_STORAGE_ALERT_KEY);
- });
-});
diff --git a/spec/frontend/runner/mock_data.js b/spec/frontend/runner/mock_data.js
deleted file mode 100644
index da0c0433b3e..00000000000
--- a/spec/frontend/runner/mock_data.js
+++ /dev/null
@@ -1,322 +0,0 @@
-// Fixtures generated by: spec/frontend/fixtures/runner.rb
-
-// Show runner queries
-import runnerData from 'test_fixtures/graphql/runner/show/runner.query.graphql.json';
-import runnerWithGroupData from 'test_fixtures/graphql/runner/show/runner.query.graphql.with_group.json';
-import runnerProjectsData from 'test_fixtures/graphql/runner/show/runner_projects.query.graphql.json';
-import runnerJobsData from 'test_fixtures/graphql/runner/show/runner_jobs.query.graphql.json';
-
-// Edit runner queries
-import runnerFormData from 'test_fixtures/graphql/runner/edit/runner_form.query.graphql.json';
-
-// List queries
-import allRunnersData from 'test_fixtures/graphql/runner/list/all_runners.query.graphql.json';
-import allRunnersDataPaginated from 'test_fixtures/graphql/runner/list/all_runners.query.graphql.paginated.json';
-import runnersCountData from 'test_fixtures/graphql/runner/list/all_runners_count.query.graphql.json';
-import groupRunnersData from 'test_fixtures/graphql/runner/list/group_runners.query.graphql.json';
-import groupRunnersDataPaginated from 'test_fixtures/graphql/runner/list/group_runners.query.graphql.paginated.json';
-import groupRunnersCountData from 'test_fixtures/graphql/runner/list/group_runners_count.query.graphql.json';
-
-import { DEFAULT_MEMBERSHIP, RUNNER_PAGE_SIZE } from '~/runner/constants';
-
-const emptyPageInfo = {
- __typename: 'PageInfo',
- hasNextPage: false,
- hasPreviousPage: false,
- startCursor: '',
- endCursor: '',
-};
-
-// Other mock data
-
-// Mock searches and their corresponding urls
-export const mockSearchExamples = [
- {
- name: 'a default query',
- urlQuery: '',
- search: {
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [],
- pagination: {},
- sort: 'CREATED_DESC',
- },
- graphqlVariables: {
- membership: DEFAULT_MEMBERSHIP,
- sort: 'CREATED_DESC',
- first: RUNNER_PAGE_SIZE,
- },
- isDefault: true,
- },
- {
- name: 'a single status',
- urlQuery: '?status[]=ACTIVE',
- search: {
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [{ type: 'status', value: { data: 'ACTIVE', operator: '=' } }],
- pagination: {},
- sort: 'CREATED_DESC',
- },
- graphqlVariables: {
- membership: DEFAULT_MEMBERSHIP,
- status: 'ACTIVE',
- sort: 'CREATED_DESC',
- first: RUNNER_PAGE_SIZE,
- },
- },
- {
- name: 'a single term text search',
- urlQuery: '?search=something',
- search: {
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [
- {
- type: 'filtered-search-term',
- value: { data: 'something' },
- },
- ],
- pagination: {},
- sort: 'CREATED_DESC',
- },
- graphqlVariables: {
- membership: DEFAULT_MEMBERSHIP,
- search: 'something',
- sort: 'CREATED_DESC',
- first: RUNNER_PAGE_SIZE,
- },
- },
- {
- name: 'a two terms text search',
- urlQuery: '?search=something+else',
- search: {
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [
- {
- type: 'filtered-search-term',
- value: { data: 'something' },
- },
- {
- type: 'filtered-search-term',
- value: { data: 'else' },
- },
- ],
- pagination: {},
- sort: 'CREATED_DESC',
- },
- graphqlVariables: {
- membership: DEFAULT_MEMBERSHIP,
- search: 'something else',
- sort: 'CREATED_DESC',
- first: RUNNER_PAGE_SIZE,
- },
- },
- {
- name: 'single instance type',
- urlQuery: '?runner_type[]=INSTANCE_TYPE',
- search: {
- runnerType: 'INSTANCE_TYPE',
- membership: DEFAULT_MEMBERSHIP,
- filters: [],
- pagination: {},
- sort: 'CREATED_DESC',
- },
- graphqlVariables: {
- type: 'INSTANCE_TYPE',
- membership: DEFAULT_MEMBERSHIP,
- sort: 'CREATED_DESC',
- first: RUNNER_PAGE_SIZE,
- },
- },
- {
- name: 'multiple runner status',
- urlQuery: '?status[]=ACTIVE&status[]=PAUSED',
- search: {
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [
- { type: 'status', value: { data: 'ACTIVE', operator: '=' } },
- { type: 'status', value: { data: 'PAUSED', operator: '=' } },
- ],
- pagination: {},
- sort: 'CREATED_DESC',
- },
- graphqlVariables: {
- status: 'ACTIVE',
- membership: DEFAULT_MEMBERSHIP,
- sort: 'CREATED_DESC',
- first: RUNNER_PAGE_SIZE,
- },
- },
- {
- name: 'multiple status, a single instance type and a non default sort',
- urlQuery: '?status[]=ACTIVE&runner_type[]=INSTANCE_TYPE&sort=CREATED_ASC',
- search: {
- runnerType: 'INSTANCE_TYPE',
- membership: DEFAULT_MEMBERSHIP,
- filters: [{ type: 'status', value: { data: 'ACTIVE', operator: '=' } }],
- pagination: {},
- sort: 'CREATED_ASC',
- },
- graphqlVariables: {
- status: 'ACTIVE',
- type: 'INSTANCE_TYPE',
- membership: DEFAULT_MEMBERSHIP,
- sort: 'CREATED_ASC',
- first: RUNNER_PAGE_SIZE,
- },
- },
- {
- name: 'a tag',
- urlQuery: '?tag[]=tag-1',
- search: {
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [{ type: 'tag', value: { data: 'tag-1', operator: '=' } }],
- pagination: {},
- sort: 'CREATED_DESC',
- },
- graphqlVariables: {
- membership: DEFAULT_MEMBERSHIP,
- tagList: ['tag-1'],
- first: 20,
- sort: 'CREATED_DESC',
- },
- },
- {
- name: 'two tags',
- urlQuery: '?tag[]=tag-1&tag[]=tag-2',
- search: {
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [
- { type: 'tag', value: { data: 'tag-1', operator: '=' } },
- { type: 'tag', value: { data: 'tag-2', operator: '=' } },
- ],
- pagination: {},
- sort: 'CREATED_DESC',
- },
- graphqlVariables: {
- membership: DEFAULT_MEMBERSHIP,
- tagList: ['tag-1', 'tag-2'],
- first: 20,
- sort: 'CREATED_DESC',
- },
- },
- {
- name: 'the next page',
- urlQuery: '?after=AFTER_CURSOR',
- search: {
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [],
- pagination: { after: 'AFTER_CURSOR' },
- sort: 'CREATED_DESC',
- },
- graphqlVariables: {
- membership: DEFAULT_MEMBERSHIP,
- sort: 'CREATED_DESC',
- after: 'AFTER_CURSOR',
- first: RUNNER_PAGE_SIZE,
- },
- },
- {
- name: 'the previous page',
- urlQuery: '?before=BEFORE_CURSOR',
- search: {
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [],
- pagination: { before: 'BEFORE_CURSOR' },
- sort: 'CREATED_DESC',
- },
- graphqlVariables: {
- membership: DEFAULT_MEMBERSHIP,
- sort: 'CREATED_DESC',
- before: 'BEFORE_CURSOR',
- last: RUNNER_PAGE_SIZE,
- },
- },
- {
- name: 'the next page filtered by a status, an instance type, tags and a non default sort',
- urlQuery:
- '?status[]=ACTIVE&runner_type[]=INSTANCE_TYPE&tag[]=tag-1&tag[]=tag-2&sort=CREATED_ASC&after=AFTER_CURSOR',
- search: {
- runnerType: 'INSTANCE_TYPE',
- membership: DEFAULT_MEMBERSHIP,
- filters: [
- { type: 'status', value: { data: 'ACTIVE', operator: '=' } },
- { type: 'tag', value: { data: 'tag-1', operator: '=' } },
- { type: 'tag', value: { data: 'tag-2', operator: '=' } },
- ],
- pagination: { after: 'AFTER_CURSOR' },
- sort: 'CREATED_ASC',
- },
- graphqlVariables: {
- status: 'ACTIVE',
- type: 'INSTANCE_TYPE',
- membership: DEFAULT_MEMBERSHIP,
- tagList: ['tag-1', 'tag-2'],
- sort: 'CREATED_ASC',
- after: 'AFTER_CURSOR',
- first: RUNNER_PAGE_SIZE,
- },
- },
- {
- name: 'paused runners',
- urlQuery: '?paused[]=true',
- search: {
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [{ type: 'paused', value: { data: 'true', operator: '=' } }],
- pagination: {},
- sort: 'CREATED_DESC',
- },
- graphqlVariables: {
- paused: true,
- membership: DEFAULT_MEMBERSHIP,
- sort: 'CREATED_DESC',
- first: RUNNER_PAGE_SIZE,
- },
- },
- {
- name: 'active runners',
- urlQuery: '?paused[]=false',
- search: {
- runnerType: null,
- membership: DEFAULT_MEMBERSHIP,
- filters: [{ type: 'paused', value: { data: 'false', operator: '=' } }],
- pagination: {},
- sort: 'CREATED_DESC',
- },
- graphqlVariables: {
- paused: false,
- membership: DEFAULT_MEMBERSHIP,
- sort: 'CREATED_DESC',
- first: RUNNER_PAGE_SIZE,
- },
- },
-];
-
-export const onlineContactTimeoutSecs = 2 * 60 * 60;
-export const staleTimeoutSecs = 7889238; // Ruby's `3.months`
-
-export const emptyStateSvgPath = 'emptyStateSvgPath.svg';
-export const emptyStateFilteredSvgPath = 'emptyStateFilteredSvgPath.svg';
-
-export {
- allRunnersData,
- allRunnersDataPaginated,
- runnersCountData,
- groupRunnersData,
- groupRunnersDataPaginated,
- groupRunnersCountData,
- emptyPageInfo,
- runnerData,
- runnerWithGroupData,
- runnerProjectsData,
- runnerJobsData,
- runnerFormData,
-};
diff --git a/spec/frontend/runner/runner_edit/runner_edit_app_spec.js b/spec/frontend/runner/runner_edit/runner_edit_app_spec.js
deleted file mode 100644
index fb118817d51..00000000000
--- a/spec/frontend/runner/runner_edit/runner_edit_app_spec.js
+++ /dev/null
@@ -1,114 +0,0 @@
-import { mount, shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { createAlert } from '~/flash';
-
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import RunnerHeader from '~/runner/components/runner_header.vue';
-import RunnerUpdateForm from '~/runner/components/runner_update_form.vue';
-import runnerFormQuery from '~/runner/graphql/edit/runner_form.query.graphql';
-import RunnerEditApp from '~//runner/runner_edit/runner_edit_app.vue';
-import { captureException } from '~/runner/sentry_utils';
-import { I18N_STATUS_NEVER_CONTACTED, I18N_INSTANCE_TYPE } from '~/runner/constants';
-
-import { runnerFormData } from '../mock_data';
-
-jest.mock('~/flash');
-jest.mock('~/runner/sentry_utils');
-
-const mockRunner = runnerFormData.data.runner;
-const mockRunnerGraphqlId = mockRunner.id;
-const mockRunnerId = `${getIdFromGraphQLId(mockRunnerGraphqlId)}`;
-const mockRunnerPath = `/admin/runners/${mockRunnerId}`;
-
-Vue.use(VueApollo);
-
-describe('RunnerEditApp', () => {
- let wrapper;
- let mockRunnerQuery;
-
- const findRunnerHeader = () => wrapper.findComponent(RunnerHeader);
- const findRunnerUpdateForm = () => wrapper.findComponent(RunnerUpdateForm);
-
- const createComponentWithApollo = ({ props = {}, mountFn = shallowMount } = {}) => {
- wrapper = mountFn(RunnerEditApp, {
- apolloProvider: createMockApollo([[runnerFormQuery, mockRunnerQuery]]),
- propsData: {
- runnerId: mockRunnerId,
- runnerPath: mockRunnerPath,
- ...props,
- },
- });
-
- return waitForPromises();
- };
-
- beforeEach(() => {
- mockRunnerQuery = jest.fn().mockResolvedValue(runnerFormData);
- });
-
- afterEach(() => {
- mockRunnerQuery.mockReset();
- wrapper.destroy();
- });
-
- it('expect GraphQL ID to be requested', async () => {
- await createComponentWithApollo();
-
- expect(mockRunnerQuery).toHaveBeenCalledWith({ id: mockRunnerGraphqlId });
- });
-
- it('displays the runner id and creation date', async () => {
- await createComponentWithApollo({ mountFn: mount });
-
- expect(findRunnerHeader().text()).toContain(`Runner #${mockRunnerId}`);
- expect(findRunnerHeader().text()).toContain('created');
- });
-
- it('displays the runner type and status', async () => {
- await createComponentWithApollo({ mountFn: mount });
-
- expect(findRunnerHeader().text()).toContain(I18N_STATUS_NEVER_CONTACTED);
- expect(findRunnerHeader().text()).toContain(I18N_INSTANCE_TYPE);
- });
-
- it('displays a loading runner form', () => {
- createComponentWithApollo();
-
- expect(findRunnerUpdateForm().props()).toMatchObject({
- runner: null,
- loading: true,
- runnerPath: mockRunnerPath,
- });
- });
-
- it('displays the runner form', async () => {
- await createComponentWithApollo();
-
- expect(findRunnerUpdateForm().props()).toMatchObject({
- loading: false,
- runnerPath: mockRunnerPath,
- });
- expect(findRunnerUpdateForm().props('runner')).toEqual(mockRunner);
- });
-
- describe('When there is an error', () => {
- beforeEach(async () => {
- mockRunnerQuery = jest.fn().mockRejectedValueOnce(new Error('Error!'));
- await createComponentWithApollo();
- });
-
- it('error is reported to sentry', () => {
- expect(captureException).toHaveBeenCalledWith({
- error: new Error('Error!'),
- component: 'RunnerEditApp',
- });
- });
-
- it('error is shown to the user', () => {
- expect(createAlert).toHaveBeenCalled();
- });
- });
-});
diff --git a/spec/frontend/runner/runner_search_utils_spec.js b/spec/frontend/runner/runner_search_utils_spec.js
deleted file mode 100644
index e1f90482b34..00000000000
--- a/spec/frontend/runner/runner_search_utils_spec.js
+++ /dev/null
@@ -1,138 +0,0 @@
-import {
- searchValidator,
- updateOutdatedUrl,
- fromUrlQueryToSearch,
- fromSearchToUrl,
- fromSearchToVariables,
- isSearchFiltered,
-} from 'ee_else_ce/runner/runner_search_utils';
-import { mockSearchExamples } from './mock_data';
-
-describe('search_params.js', () => {
- describe('searchValidator', () => {
- mockSearchExamples.forEach(({ name, search }) => {
- it(`Validates ${name} as a search object`, () => {
- expect(searchValidator(search)).toBe(true);
- });
- });
- });
-
- describe('updateOutdatedUrl', () => {
- it('returns null for urls that do not need updating', () => {
- expect(updateOutdatedUrl('http://test.host/')).toBe(null);
- expect(updateOutdatedUrl('http://test.host/?a=b')).toBe(null);
- });
-
- it.each`
- query | updatedQuery
- ${'status[]=ACTIVE'} | ${'paused[]=false'}
- ${'status[]=ACTIVE&a=b'} | ${'a=b&paused[]=false'}
- ${'status[]=ACTIVE'} | ${'paused[]=false'}
- ${'status[]=PAUSED'} | ${'paused[]=true'}
- ${'page=2&after=AFTER'} | ${'after=AFTER'}
- ${'page=2&before=BEFORE'} | ${'before=BEFORE'}
- ${'status[]=PAUSED&page=2&after=AFTER'} | ${'after=AFTER&paused[]=true'}
- `('updates "$query" to "$updatedQuery"', ({ query, updatedQuery }) => {
- const mockUrl = 'http://test.host/admin/runners?';
-
- expect(updateOutdatedUrl(`${mockUrl}${query}`)).toBe(`${mockUrl}${updatedQuery}`);
- });
- });
-
- describe('fromUrlQueryToSearch', () => {
- mockSearchExamples.forEach(({ name, urlQuery, search }) => {
- it(`Converts ${name} to a search object`, () => {
- expect(fromUrlQueryToSearch(urlQuery)).toEqual(search);
- });
- });
-
- it('When search params appear as array, they are concatenated', () => {
- expect(fromUrlQueryToSearch('?search[]=my&search[]=text').filters).toEqual([
- { type: 'filtered-search-term', value: { data: 'my' } },
- { type: 'filtered-search-term', value: { data: 'text' } },
- ]);
- });
- });
-
- describe('fromSearchToUrl', () => {
- mockSearchExamples.forEach(({ name, urlQuery, search }) => {
- it(`Converts ${name} to a url`, () => {
- expect(fromSearchToUrl(search)).toBe(`http://test.host/${urlQuery}`);
- });
- });
-
- it.each([
- 'http://test.host/?status[]=ACTIVE',
- 'http://test.host/?runner_type[]=INSTANCE_TYPE',
- 'http://test.host/?search=my_text',
- ])('When a filter is removed, it is removed from the URL', (initalUrl) => {
- const search = { filters: [], sort: 'CREATED_DESC' };
- const expectedUrl = `http://test.host/`;
-
- expect(fromSearchToUrl(search, initalUrl)).toBe(expectedUrl);
- });
-
- it('When unrelated search parameter is present, it does not get removed', () => {
- const initialUrl = `http://test.host/?unrelated=UNRELATED&status[]=ACTIVE`;
- const search = { filters: [], sort: 'CREATED_DESC' };
- const expectedUrl = `http://test.host/?unrelated=UNRELATED`;
-
- expect(fromSearchToUrl(search, initialUrl)).toBe(expectedUrl);
- });
- });
-
- describe('fromSearchToVariables', () => {
- mockSearchExamples.forEach(({ name, graphqlVariables, search }) => {
- it(`Converts ${name} to a GraphQL query variables object`, () => {
- expect(fromSearchToVariables(search)).toEqual(graphqlVariables);
- });
- });
-
- it('When a search param is empty, it gets removed', () => {
- expect(
- fromSearchToVariables({
- filters: [
- {
- type: 'filtered-search-term',
- value: { data: '' },
- },
- ],
- }),
- ).toMatchObject({
- search: '',
- });
-
- expect(
- fromSearchToVariables({
- filters: [
- {
- type: 'filtered-search-term',
- value: { data: 'something' },
- },
- {
- type: 'filtered-search-term',
- value: { data: '' },
- },
- ],
- }),
- ).toMatchObject({
- search: 'something',
- });
- });
- });
-
- describe('isSearchFiltered', () => {
- mockSearchExamples.forEach(({ name, search, isDefault }) => {
- it(`Given ${name}, evaluates to ${isDefault ? 'not ' : ''}filtered`, () => {
- expect(isSearchFiltered(search)).toBe(!isDefault);
- });
- });
-
- it.each([null, undefined, {}])(
- 'given a missing pagination, evaluates as not filtered',
- (mockPagination) => {
- expect(isSearchFiltered({ pagination: mockPagination })).toBe(false);
- },
- );
- });
-});
diff --git a/spec/frontend/runner/runner_update_form_utils_spec.js b/spec/frontend/runner/runner_update_form_utils_spec.js
deleted file mode 100644
index a633aee92f7..00000000000
--- a/spec/frontend/runner/runner_update_form_utils_spec.js
+++ /dev/null
@@ -1,93 +0,0 @@
-import { ACCESS_LEVEL_NOT_PROTECTED } from '~/runner/constants';
-import { modelToUpdateMutationVariables, runnerToModel } from '~/runner/runner_update_form_utils';
-
-const mockId = 'gid://gitlab/Ci::Runner/1';
-const mockDescription = 'Runner Desc.';
-
-const mockRunner = {
- id: mockId,
- description: mockDescription,
- maximumTimeout: 100,
- accessLevel: ACCESS_LEVEL_NOT_PROTECTED,
- active: true,
- locked: true,
- runUntagged: true,
- tagList: ['tag-1', 'tag-2'],
-};
-
-const mockModel = {
- ...mockRunner,
- tagList: 'tag-1, tag-2',
-};
-
-describe('~/runner/runner_update_form_utils', () => {
- describe('runnerToModel', () => {
- it('collects all model data', () => {
- expect(runnerToModel(mockRunner)).toEqual(mockModel);
- });
-
- it('does not collect other data', () => {
- const model = runnerToModel({
- ...mockRunner,
- unrelated: 'unrelatedValue',
- });
-
- expect(model.unrelated).toEqual(undefined);
- });
-
- it('tag list defaults to an empty string', () => {
- const model = runnerToModel({
- ...mockRunner,
- tagList: undefined,
- });
-
- expect(model.tagList).toEqual('');
- });
- });
-
- describe('modelToUpdateMutationVariables', () => {
- it('collects all model data', () => {
- expect(modelToUpdateMutationVariables(mockModel)).toEqual({
- input: {
- ...mockRunner,
- },
- });
- });
-
- it('collects a nullable timeout from the model', () => {
- const variables = modelToUpdateMutationVariables({
- ...mockModel,
- maximumTimeout: '',
- });
-
- expect(variables).toEqual({
- input: {
- ...mockRunner,
- maximumTimeout: null,
- },
- });
- });
-
- it.each`
- tagList | tagListInput
- ${''} | ${[]}
- ${'tag1, tag2'} | ${['tag1', 'tag2']}
- ${'with spaces'} | ${['with spaces']}
- ${',,,,, commas'} | ${['commas']}
- ${'more ,,,,, commas'} | ${['more', 'commas']}
- ${' trimmed , trimmed2 '} | ${['trimmed', 'trimmed2']}
- `('collect tags separated by commas for "$value"', ({ tagList, tagListInput }) => {
- const variables = modelToUpdateMutationVariables({
- ...mockModel,
- tagList,
- });
-
- expect(variables).toEqual({
- input: {
- ...mockRunner,
- tagList: tagListInput,
- },
- });
- });
- });
-});
diff --git a/spec/frontend/runner/sentry_utils_spec.js b/spec/frontend/runner/sentry_utils_spec.js
deleted file mode 100644
index b61eb63961e..00000000000
--- a/spec/frontend/runner/sentry_utils_spec.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import * as Sentry from '@sentry/browser';
-import { captureException } from '~/runner/sentry_utils';
-
-jest.mock('@sentry/browser');
-
-describe('~/runner/sentry_utils', () => {
- let mockSetTag;
-
- beforeEach(async () => {
- mockSetTag = jest.fn();
-
- Sentry.withScope.mockImplementation((fn) => {
- const scope = { setTag: mockSetTag };
- fn(scope);
- });
- });
-
- describe('captureException', () => {
- const mockError = new Error('Something went wrong!');
-
- it('error is reported to sentry', () => {
- captureException({ error: mockError });
-
- expect(Sentry.withScope).toHaveBeenCalled();
- expect(Sentry.captureException).toHaveBeenCalledWith(mockError);
- });
-
- it('error is reported to sentry with a component name', () => {
- const mockComponentName = 'MyComponent';
-
- captureException({ error: mockError, component: mockComponentName });
-
- expect(Sentry.withScope).toHaveBeenCalled();
- expect(Sentry.captureException).toHaveBeenCalledWith(mockError);
-
- expect(mockSetTag).toHaveBeenCalledWith('vue_component', mockComponentName);
- });
- });
-});
diff --git a/spec/frontend/runner/utils_spec.js b/spec/frontend/runner/utils_spec.js
deleted file mode 100644
index 33de1345f85..00000000000
--- a/spec/frontend/runner/utils_spec.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import { formatJobCount, tableField, getPaginationVariables, parseInterval } from '~/runner/utils';
-
-describe('~/runner/utils', () => {
- describe('formatJobCount', () => {
- it('formats a number', () => {
- expect(formatJobCount(1)).toBe('1');
- expect(formatJobCount(99)).toBe('99');
- });
-
- it('formats a large count', () => {
- expect(formatJobCount(1000)).toBe('1,000');
- expect(formatJobCount(1001)).toBe('1,000+');
- });
-
- it('returns an empty string for non-numeric values', () => {
- expect(formatJobCount(undefined)).toBe('');
- expect(formatJobCount(null)).toBe('');
- expect(formatJobCount('number')).toBe('');
- });
- });
-
- describe('tableField', () => {
- it('a field with options', () => {
- expect(tableField({ key: 'name' })).toEqual({
- key: 'name',
- label: '',
- tdAttr: { 'data-testid': 'td-name' },
- thClass: expect.any(Array),
- });
- });
-
- it('a field with a label', () => {
- const label = 'A field name';
-
- expect(tableField({ key: 'name', label })).toMatchObject({
- label,
- });
- });
-
- it('a field with custom classes', () => {
- const mockClasses = ['foo', 'bar'];
-
- expect(tableField({ thClasses: mockClasses })).toMatchObject({
- thClass: expect.arrayContaining(mockClasses),
- });
- });
-
- it('a field with custom options', () => {
- expect(tableField({ foo: 'bar' })).toMatchObject({ foo: 'bar' });
- });
- });
-
- describe('getPaginationVariables', () => {
- const after = 'AFTER_CURSOR';
- const before = 'BEFORE_CURSOR';
-
- it.each`
- case | pagination | pageSize | variables
- ${'next page'} | ${{ after }} | ${undefined} | ${{ after, first: 10 }}
- ${'prev page'} | ${{ before }} | ${undefined} | ${{ before, last: 10 }}
- ${'first page'} | ${{}} | ${undefined} | ${{ first: 10 }}
- ${'next page with N items'} | ${{ after }} | ${20} | ${{ after, first: 20 }}
- ${'prev page with N items'} | ${{ before }} | ${20} | ${{ before, last: 20 }}
- ${'first page with N items'} | ${{}} | ${20} | ${{ first: 20 }}
- `('navigates to $case', ({ pagination, pageSize, variables }) => {
- expect(getPaginationVariables(pagination, pageSize)).toEqual(variables);
- });
- });
-
- describe('parseInterval', () => {
- it.each`
- case | argument | returnValue
- ${'parses integer'} | ${'86400'} | ${86400}
- ${'returns null for undefined'} | ${undefined} | ${null}
- ${'returns null for null'} | ${null} | ${null}
- `('$case', ({ argument, returnValue }) => {
- expect(parseInterval(argument)).toStrictEqual(returnValue);
- });
- });
-});
diff --git a/spec/frontend/search/mock_data.js b/spec/frontend/search/mock_data.js
index 0542e96c77c..fa5ccfeb478 100644
--- a/spec/frontend/search/mock_data.js
+++ b/spec/frontend/search/mock_data.js
@@ -107,3 +107,87 @@ export const PROMISE_ALL_EXPECTED_MUTATIONS = {
payload: { key: PROJECTS_LOCAL_STORAGE_KEY, data: [MOCK_FRESH_DATA_RES, MOCK_FRESH_DATA_RES] },
},
};
+
+export const MOCK_NAVIGATION = {
+ projects: {
+ label: 'Projects',
+ scope: 'projects',
+ link: '/search?scope=projects&search=et',
+ count_link: '/search/count?scope=projects&search=et',
+ },
+ blobs: {
+ label: 'Code',
+ scope: 'blobs',
+ link: '/search?scope=blobs&search=et',
+ count_link: '/search/count?scope=blobs&search=et',
+ },
+ issues: {
+ label: 'Issues',
+ scope: 'issues',
+ link: '/search?scope=issues&search=et',
+ active: true,
+ count: '2,430',
+ },
+ merge_requests: {
+ label: 'Merge requests',
+ scope: 'merge_requests',
+ link: '/search?scope=merge_requests&search=et',
+ count_link: '/search/count?scope=merge_requests&search=et',
+ },
+ wiki_blobs: {
+ label: 'Wiki',
+ scope: 'wiki_blobs',
+ link: '/search?scope=wiki_blobs&search=et',
+ count_link: '/search/count?scope=wiki_blobs&search=et',
+ },
+ commits: {
+ label: 'Commits',
+ scope: 'commits',
+ link: '/search?scope=commits&search=et',
+ count_link: '/search/count?scope=commits&search=et',
+ },
+ notes: {
+ label: 'Comments',
+ scope: 'notes',
+ link: '/search?scope=notes&search=et',
+ count_link: '/search/count?scope=notes&search=et',
+ },
+ milestones: {
+ label: 'Milestones',
+ scope: 'milestones',
+ link: '/search?scope=milestones&search=et',
+ count_link: '/search/count?scope=milestones&search=et',
+ },
+ users: {
+ label: 'Users',
+ scope: 'users',
+ link: '/search?scope=users&search=et',
+ count_link: '/search/count?scope=users&search=et',
+ },
+};
+
+export const MOCK_NAVIGATION_DATA = {
+ projects: {
+ label: 'Projects',
+ scope: 'projects',
+ link: '/search?scope=projects&search=et',
+ count_link: '/search/count?scope=projects&search=et',
+ },
+};
+
+export const MOCK_ENDPOINT_RESPONSE = { count: '13' };
+
+export const MOCK_DATA_FOR_NAVIGATION_ACTION_MUTATION = {
+ projects: {
+ count: '13',
+ label: 'Projects',
+ scope: 'projects',
+ link: '/search?scope=projects&search=et',
+ count_link: '/search/count?scope=projects&search=et',
+ },
+};
+
+export const MOCK_NAVIGATION_ACTION_MUTATION = {
+ type: types.RECEIVE_NAVIGATION_COUNT,
+ payload: { key: 'projects', count: '13' },
+};
diff --git a/spec/frontend/search/sidebar/components/app_spec.js b/spec/frontend/search/sidebar/components/app_spec.js
index 89959feec39..e87217950cd 100644
--- a/spec/frontend/search/sidebar/components/app_spec.js
+++ b/spec/frontend/search/sidebar/components/app_spec.js
@@ -1,11 +1,10 @@
-import { GlButton, GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue from 'vue';
import Vuex from 'vuex';
import { MOCK_QUERY } from 'jest/search/mock_data';
import GlobalSearchSidebar from '~/search/sidebar/components/app.vue';
-import ConfidentialityFilter from '~/search/sidebar/components/confidentiality_filter.vue';
-import StatusFilter from '~/search/sidebar/components/status_filter.vue';
+import ResultsFilters from '~/search/sidebar/components/results_filters.vue';
+import ScopeNavigation from '~/search/sidebar/components/scope_navigation.vue';
Vue.use(Vuex);
@@ -17,7 +16,7 @@ describe('GlobalSearchSidebar', () => {
resetQuery: jest.fn(),
};
- const createComponent = (initialState) => {
+ const createComponent = (initialState, featureFlags) => {
const store = new Vuex.Store({
state: {
urlQuery: MOCK_QUERY,
@@ -28,6 +27,11 @@ describe('GlobalSearchSidebar', () => {
wrapper = shallowMount(GlobalSearchSidebar, {
store,
+ provide: {
+ glFeatures: {
+ ...featureFlags,
+ },
+ },
});
};
@@ -35,118 +39,68 @@ describe('GlobalSearchSidebar', () => {
wrapper.destroy();
});
- const findSidebarForm = () => wrapper.find('form');
- const findStatusFilter = () => wrapper.findComponent(StatusFilter);
- const findConfidentialityFilter = () => wrapper.findComponent(ConfidentialityFilter);
- const findApplyButton = () => wrapper.findComponent(GlButton);
- const findResetLinkButton = () => wrapper.findComponent(GlLink);
+ const findSidebarSection = () => wrapper.find('section');
+ const findFilters = () => wrapper.findComponent(ResultsFilters);
+ const findSidebarNavigation = () => wrapper.findComponent(ScopeNavigation);
- describe('template', () => {
+ describe('renders properly', () => {
describe('scope=projects', () => {
beforeEach(() => {
createComponent({ urlQuery: { ...MOCK_QUERY, scope: 'projects' } });
});
- it("doesn't render StatusFilter", () => {
- expect(findStatusFilter().exists()).toBe(false);
- });
-
- it("doesn't render ConfidentialityFilter", () => {
- expect(findConfidentialityFilter().exists()).toBe(false);
+ it('shows section', () => {
+ expect(findSidebarSection().exists()).toBe(true);
});
- it("doesn't render ApplyButton", () => {
- expect(findApplyButton().exists()).toBe(false);
+ it("doesn't shows filters", () => {
+ expect(findFilters().exists()).toBe(false);
});
});
- describe('scope=issues', () => {
+ describe('scope=merge_requests', () => {
beforeEach(() => {
- createComponent({ urlQuery: MOCK_QUERY });
- });
- it('renders StatusFilter', () => {
- expect(findStatusFilter().exists()).toBe(true);
+ createComponent({ urlQuery: { ...MOCK_QUERY, scope: 'merge_requests' } });
});
- it('renders ConfidentialityFilter', () => {
- expect(findConfidentialityFilter().exists()).toBe(true);
+ it('shows section', () => {
+ expect(findSidebarSection().exists()).toBe(true);
});
- it('renders ApplyButton', () => {
- expect(findApplyButton().exists()).toBe(true);
+ it('shows filters', () => {
+ expect(findFilters().exists()).toBe(true);
});
});
- });
- describe('ApplyButton', () => {
- describe('when sidebarDirty is false', () => {
+ describe('scope=issues', () => {
beforeEach(() => {
- createComponent({ sidebarDirty: false });
- });
-
- it('disables the button', () => {
- expect(findApplyButton().attributes('disabled')).toBe('true');
+ createComponent({ urlQuery: MOCK_QUERY });
});
- });
-
- describe('when sidebarDirty is true', () => {
- beforeEach(() => {
- createComponent({ sidebarDirty: true });
+ it('shows section', () => {
+ expect(findSidebarSection().exists()).toBe(true);
});
- it('enables the button', () => {
- expect(findApplyButton().attributes('disabled')).toBe(undefined);
+ it('shows filters', () => {
+ expect(findFilters().exists()).toBe(true);
});
});
});
- describe('ResetLinkButton', () => {
- describe('with no filter selected', () => {
- beforeEach(() => {
- createComponent({ urlQuery: {} });
- });
-
- it('does not render', () => {
- expect(findResetLinkButton().exists()).toBe(false);
- });
- });
-
- describe('with filter selected', () => {
- beforeEach(() => {
- createComponent({ urlQuery: MOCK_QUERY });
- });
-
- it('does render', () => {
- expect(findResetLinkButton().exists()).toBe(true);
- });
+ describe('when search_page_vertical_nav is enabled', () => {
+ beforeEach(() => {
+ createComponent({}, { searchPageVerticalNav: true });
});
-
- describe('with filter selected and user updated query back to default', () => {
- beforeEach(() => {
- createComponent({ urlQuery: MOCK_QUERY, query: {} });
- });
-
- it('does render', () => {
- expect(findResetLinkButton().exists()).toBe(true);
- });
+ it('shows the vertical navigation', () => {
+ expect(findSidebarNavigation().exists()).toBe(true);
});
});
- describe('actions', () => {
+ describe('when search_page_vertical_nav is disabled', () => {
beforeEach(() => {
- createComponent({});
+ createComponent({}, { searchPageVerticalNav: false });
});
-
- it('clicking ApplyButton calls applyQuery', () => {
- findSidebarForm().trigger('submit');
-
- expect(actionSpies.applyQuery).toHaveBeenCalled();
- });
-
- it('clicking ResetLinkButton calls resetQuery', () => {
- findResetLinkButton().vm.$emit('click');
-
- expect(actionSpies.resetQuery).toHaveBeenCalled();
+ it('hides the vertical navigation', () => {
+ expect(findSidebarNavigation().exists()).toBe(false);
});
});
});
diff --git a/spec/frontend/search/sidebar/components/filters_spec.js b/spec/frontend/search/sidebar/components/filters_spec.js
new file mode 100644
index 00000000000..4f217709297
--- /dev/null
+++ b/spec/frontend/search/sidebar/components/filters_spec.js
@@ -0,0 +1,132 @@
+import { GlButton, GlLink } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import Vuex from 'vuex';
+import { MOCK_QUERY } from 'jest/search/mock_data';
+import ResultsFilters from '~/search/sidebar/components/results_filters.vue';
+import ConfidentialityFilter from '~/search/sidebar/components/confidentiality_filter.vue';
+import StatusFilter from '~/search/sidebar/components/status_filter.vue';
+
+Vue.use(Vuex);
+
+describe('GlobalSearchSidebarFilters', () => {
+ let wrapper;
+
+ const actionSpies = {
+ applyQuery: jest.fn(),
+ resetQuery: jest.fn(),
+ };
+
+ const createComponent = (initialState) => {
+ const store = new Vuex.Store({
+ state: {
+ urlQuery: MOCK_QUERY,
+ ...initialState,
+ },
+ actions: actionSpies,
+ });
+
+ wrapper = shallowMount(ResultsFilters, {
+ store,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const findSidebarForm = () => wrapper.find('form');
+ const findStatusFilter = () => wrapper.findComponent(StatusFilter);
+ const findConfidentialityFilter = () => wrapper.findComponent(ConfidentialityFilter);
+ const findApplyButton = () => wrapper.findComponent(GlButton);
+ const findResetLinkButton = () => wrapper.findComponent(GlLink);
+
+ describe('Renders correctly', () => {
+ beforeEach(() => {
+ createComponent({ urlQuery: MOCK_QUERY });
+ });
+ it('renders StatusFilter', () => {
+ expect(findStatusFilter().exists()).toBe(true);
+ });
+
+ it('renders ConfidentialityFilter', () => {
+ expect(findConfidentialityFilter().exists()).toBe(true);
+ });
+
+ it('renders ApplyButton', () => {
+ expect(findApplyButton().exists()).toBe(true);
+ });
+ });
+
+ 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('ResetLinkButton', () => {
+ describe('with no filter selected', () => {
+ beforeEach(() => {
+ createComponent({ urlQuery: {} });
+ });
+
+ it('does not render', () => {
+ expect(findResetLinkButton().exists()).toBe(false);
+ });
+ });
+
+ describe('with filter selected', () => {
+ beforeEach(() => {
+ createComponent({ urlQuery: MOCK_QUERY });
+ });
+
+ it('does render', () => {
+ expect(findResetLinkButton().exists()).toBe(true);
+ });
+ });
+
+ describe('with filter selected and user updated query back to default', () => {
+ beforeEach(() => {
+ createComponent({ urlQuery: MOCK_QUERY, query: {} });
+ });
+
+ it('does render', () => {
+ expect(findResetLinkButton().exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('actions', () => {
+ beforeEach(() => {
+ createComponent({});
+ });
+
+ it('clicking ApplyButton calls applyQuery', () => {
+ findSidebarForm().trigger('submit');
+
+ expect(actionSpies.applyQuery).toHaveBeenCalled();
+ });
+
+ it('clicking ResetLinkButton calls resetQuery', () => {
+ findResetLinkButton().vm.$emit('click');
+
+ expect(actionSpies.resetQuery).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/search/sidebar/components/scope_navigation_spec.js b/spec/frontend/search/sidebar/components/scope_navigation_spec.js
new file mode 100644
index 00000000000..6262a52e01a
--- /dev/null
+++ b/spec/frontend/search/sidebar/components/scope_navigation_spec.js
@@ -0,0 +1,80 @@
+import { GlNav, GlNavItem } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import Vuex from 'vuex';
+import { MOCK_QUERY, MOCK_NAVIGATION } from 'jest/search/mock_data';
+import ScopeNavigation from '~/search/sidebar/components/scope_navigation.vue';
+
+Vue.use(Vuex);
+
+describe('ScopeNavigation', () => {
+ let wrapper;
+
+ const actionSpies = {
+ fetchSidebarCount: jest.fn(),
+ };
+
+ const createComponent = (initialState) => {
+ const store = new Vuex.Store({
+ state: {
+ urlQuery: MOCK_QUERY,
+ navigation: MOCK_NAVIGATION,
+ ...initialState,
+ },
+ actions: actionSpies,
+ });
+
+ wrapper = shallowMount(ScopeNavigation, {
+ store,
+ });
+ };
+
+ 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 findGlNavItemActiveCount = () => findGlNavItemActive().at(0).findAll('span').at(1);
+
+ describe('scope navigation', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders section', () => {
+ expect(findNavElement().exists()).toBe(true);
+ });
+
+ it('renders nav component', () => {
+ expect(findGlNav().exists()).toBe(true);
+ });
+
+ it('renders all nav item components', () => {
+ expect(findGlNavItems()).toHaveLength(9);
+ });
+
+ it('nav items have proper links', () => {
+ const linkAtPosition = 3;
+ const { link } = MOCK_NAVIGATION[Object.keys(MOCK_NAVIGATION)[linkAtPosition]];
+
+ expect(findGlNavItems().at(linkAtPosition).attributes('href')).toBe(link);
+ });
+ });
+
+ describe('scope navigation sets proper state', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('sets proper class to active item', () => {
+ expect(findGlNavItemActive()).toHaveLength(1);
+ });
+
+ it('active item', () => {
+ expect(findGlNavItemActiveCount().text()).toBe('2.4K');
+ });
+ });
+});
diff --git a/spec/frontend/search/store/actions_spec.js b/spec/frontend/search/store/actions_spec.js
index c442ffa521d..3d19b27ff86 100644
--- a/spec/frontend/search/store/actions_spec.js
+++ b/spec/frontend/search/store/actions_spec.js
@@ -2,6 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import Api from '~/api';
import { createAlert } from '~/flash';
+import * as logger from '~/lib/logger';
import axios from '~/lib/utils/axios_utils';
import * as urlUtils from '~/lib/utils/url_utility';
import * as actions from '~/search/store/actions';
@@ -23,6 +24,9 @@ import {
MOCK_FRESH_DATA_RES,
PRELOAD_EXPECTED_MUTATIONS,
PROMISE_ALL_EXPECTED_MUTATIONS,
+ MOCK_NAVIGATION_DATA,
+ MOCK_NAVIGATION_ACTION_MUTATION,
+ MOCK_ENDPOINT_RESPONSE,
} from '../mock_data';
jest.mock('~/flash');
@@ -31,6 +35,9 @@ jest.mock('~/lib/utils/url_utility', () => ({
joinPaths: jest.fn().mockReturnValue(''),
visitUrl: jest.fn(),
}));
+jest.mock('~/lib/logger', () => ({
+ logError: jest.fn(),
+}));
describe('Global Search Store Actions', () => {
let mock;
@@ -260,4 +267,32 @@ describe('Global Search Store Actions', () => {
);
});
});
+
+ describe.each`
+ action | axiosMock | type | scope | expectedMutations | errorLogs
+ ${actions.fetchSidebarCount} | ${{ method: 'onGet', code: 200 }} | ${'success'} | ${'issues'} | ${[MOCK_NAVIGATION_ACTION_MUTATION]} | ${0}
+ ${actions.fetchSidebarCount} | ${{ method: null, code: 0 }} | ${'success'} | ${'projects'} | ${[]} | ${0}
+ ${actions.fetchSidebarCount} | ${{ method: 'onGet', code: 500 }} | ${'error'} | ${'issues'} | ${[]} | ${1}
+ `('fetchSidebarCount', ({ action, axiosMock, type, expectedMutations, scope, errorLogs }) => {
+ describe(`on ${type}`, () => {
+ beforeEach(() => {
+ state.navigation = MOCK_NAVIGATION_DATA;
+ state.urlQuery = {
+ scope,
+ };
+
+ if (axiosMock.method) {
+ mock[axiosMock.method]().reply(axiosMock.code, MOCK_ENDPOINT_RESPONSE);
+ }
+ });
+
+ 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);
+ });
+ });
+ });
+ });
});
diff --git a/spec/frontend/search/store/mutations_spec.js b/spec/frontend/search/store/mutations_spec.js
index 25f9b692955..a79ec8f70b0 100644
--- a/spec/frontend/search/store/mutations_spec.js
+++ b/spec/frontend/search/store/mutations_spec.js
@@ -1,13 +1,20 @@
import * as types from '~/search/store/mutation_types';
import mutations from '~/search/store/mutations';
import createState from '~/search/store/state';
-import { MOCK_QUERY, MOCK_GROUPS, MOCK_PROJECTS } from '../mock_data';
+import {
+ MOCK_QUERY,
+ MOCK_GROUPS,
+ MOCK_PROJECTS,
+ MOCK_NAVIGATION_DATA,
+ MOCK_NAVIGATION_ACTION_MUTATION,
+ MOCK_DATA_FOR_NAVIGATION_ACTION_MUTATION,
+} from '../mock_data';
describe('Global Search Store Mutations', () => {
let state;
beforeEach(() => {
- state = createState({ query: MOCK_QUERY });
+ state = createState({ query: MOCK_QUERY, navigation: MOCK_NAVIGATION_DATA });
});
describe('REQUEST_GROUPS', () => {
@@ -90,4 +97,15 @@ describe('Global Search Store Mutations', () => {
expect(state.frequentItems[payload.key]).toStrictEqual(payload.data);
});
});
+
+ describe('RECEIVE_NAVIGATION_COUNT', () => {
+ it('sets frequentItems[key] to data', () => {
+ const { payload } = MOCK_NAVIGATION_ACTION_MUTATION;
+ mutations[types.RECEIVE_NAVIGATION_COUNT](state, payload);
+
+ expect(state.navigation[payload.key]).toStrictEqual(
+ MOCK_DATA_FOR_NAVIGATION_ACTION_MUTATION[payload.key],
+ );
+ });
+ });
});
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 11841106ed0..efe3f7e8dbf 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
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`self monitor component When the self monitor project has not been created default state to match the default snapshot 1`] = `
+exports[`self-monitor component When the self-monitor project has not been created default state to match the default snapshot 1`] = `
<section
class="settings no-animate js-self-monitoring-settings"
>
@@ -11,7 +11,7 @@ exports[`self monitor component When the self monitor project has not been creat
class="js-section-header settings-title js-settings-toggle js-settings-toggle-trigger-only"
>
- Self monitoring
+ Self-monitoring
</h4>
@@ -30,7 +30,7 @@ exports[`self monitor component When the self monitor project has not been creat
class="js-section-sub-header"
>
- Activate or deactivate instance self monitoring.
+ Activate or deactivate instance self-monitoring.
<gl-link-stub
href="/help/administration/monitoring/gitlab_self_monitoring_project/index"
@@ -47,7 +47,7 @@ exports[`self monitor component When the self monitor project has not been creat
name="self-monitoring-form"
>
<p>
- Activate self monitoring to create a project to use to monitor the health of your instance.
+ Activate self-monitoring to create a project to use to monitor the health of your instance.
</p>
<gl-form-group-stub
@@ -55,7 +55,7 @@ exports[`self monitor component When the self monitor project has not been creat
optionaltext="(optional)"
>
<gl-toggle-stub
- label="Self monitoring"
+ label="Self-monitoring"
labelposition="top"
/>
</gl-form-group-stub>
@@ -69,15 +69,15 @@ exports[`self monitor component When the self monitor project has not been creat
dismisslabel="Close"
modalclass=""
modalid="delete-self-monitor-modal"
- ok-title="Delete self monitoring project"
+ ok-title="Delete self-monitoring project"
ok-variant="danger"
size="md"
- title="Deactivate self monitoring?"
+ title="Deactivate self-monitoring?"
titletag="h4"
>
<div>
- Deactivating self monitoring deletes the self monitoring project. Are you sure you want to deactivate self monitoring and delete the project?
+ Deactivating self-monitoring deletes the self-monitoring project. Are you sure you want to deactivate self-monitoring and delete the project?
</div>
</gl-modal-stub>
diff --git a/spec/frontend/self_monitor/components/self_monitor_form_spec.js b/spec/frontend/self_monitor/components/self_monitor_form_spec.js
index c690bbf1c57..35f2734dde3 100644
--- a/spec/frontend/self_monitor/components/self_monitor_form_spec.js
+++ b/spec/frontend/self_monitor/components/self_monitor_form_spec.js
@@ -4,11 +4,11 @@ import { TEST_HOST } from 'helpers/test_constants';
import SelfMonitor from '~/self_monitor/components/self_monitor_form.vue';
import { createStore } from '~/self_monitor/store';
-describe('self monitor component', () => {
+describe('self-monitor component', () => {
let wrapper;
let store;
- describe('When the self monitor project has not been created', () => {
+ describe('When the self-monitor project has not been created', () => {
beforeEach(() => {
store = createStore({
projectEnabled: false,
@@ -35,7 +35,7 @@ describe('self monitor component', () => {
it('renders header text', () => {
wrapper = shallowMount(SelfMonitor, { store });
- expect(wrapper.find('.js-section-header').text()).toBe('Self monitoring');
+ expect(wrapper.find('.js-section-header').text()).toBe('Self-monitoring');
});
describe('expand/collapse button', () => {
@@ -53,7 +53,7 @@ describe('self monitor component', () => {
wrapper = shallowMount(SelfMonitor, { store });
expect(wrapper.find('.js-section-sub-header').text()).toContain(
- 'Activate or deactivate instance self monitoring.',
+ 'Activate or deactivate instance self-monitoring.',
);
});
});
@@ -63,7 +63,7 @@ describe('self monitor component', () => {
wrapper = shallowMount(SelfMonitor, { store });
expect(wrapper.vm.selfMonitoringFormText).toContain(
- 'Activate self monitoring to create a project to use to monitor the health of your instance.',
+ 'Activate self-monitoring to create a project to use to monitor the health of your instance.',
);
});
diff --git a/spec/frontend/self_monitor/store/actions_spec.js b/spec/frontend/self_monitor/store/actions_spec.js
index 59ee87c4a02..21e63533c66 100644
--- a/spec/frontend/self_monitor/store/actions_spec.js
+++ b/spec/frontend/self_monitor/store/actions_spec.js
@@ -6,7 +6,7 @@ import * as actions from '~/self_monitor/store/actions';
import * as types from '~/self_monitor/store/mutation_types';
import createState from '~/self_monitor/store/state';
-describe('self monitor actions', () => {
+describe('self-monitor actions', () => {
let state;
let mock;
@@ -129,7 +129,7 @@ describe('self monitor actions', () => {
payload: {
actionName: 'viewSelfMonitorProject',
actionText: 'View project',
- message: 'Self monitoring project successfully created.',
+ message: 'Self-monitoring project successfully created.',
},
},
{ type: types.SET_SHOW_ALERT, payload: true },
@@ -236,7 +236,7 @@ describe('self monitor actions', () => {
payload: {
actionName: 'createProject',
actionText: 'Undo',
- message: 'Self monitoring project successfully deleted.',
+ message: 'Self-monitoring project successfully deleted.',
},
},
{ type: types.SET_SHOW_ALERT, payload: true },
diff --git a/spec/frontend/self_monitor/store/mutations_spec.js b/spec/frontend/self_monitor/store/mutations_spec.js
index 5282ae3b2f5..315450f3aef 100644
--- a/spec/frontend/self_monitor/store/mutations_spec.js
+++ b/spec/frontend/self_monitor/store/mutations_spec.js
@@ -1,7 +1,7 @@
import mutations from '~/self_monitor/store/mutations';
import createState from '~/self_monitor/store/state';
-describe('self monitoring mutations', () => {
+describe('self-monitoring mutations', () => {
let localState;
beforeEach(() => {
diff --git a/spec/frontend/sidebar/components/milestone/milestone_dropdown_spec.js b/spec/frontend/sidebar/components/milestone/milestone_dropdown_spec.js
new file mode 100644
index 00000000000..843ac1da4bb
--- /dev/null
+++ b/spec/frontend/sidebar/components/milestone/milestone_dropdown_spec.js
@@ -0,0 +1,93 @@
+import { shallowMount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { IssuableType, WorkspaceType } from '~/issues/constants';
+import { __ } from '~/locale';
+import MilestoneDropdown from '~/sidebar/components/milestone/milestone_dropdown.vue';
+import SidebarDropdown from '~/sidebar/components/sidebar_dropdown.vue';
+
+describe('MilestoneDropdown component', () => {
+ let wrapper;
+
+ const propsData = {
+ attrWorkspacePath: 'full/path',
+ issuableType: IssuableType.Issue,
+ workspaceType: WorkspaceType.project,
+ };
+
+ const findHiddenInput = () => wrapper.find('input');
+ const findSidebarDropdown = () => wrapper.findComponent(SidebarDropdown);
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(MilestoneDropdown, { propsData: { ...propsData, ...props } });
+ };
+
+ it('renders SidebarDropdown', () => {
+ createComponent();
+
+ expect(findSidebarDropdown().props()).toMatchObject({
+ attrWorkspacePath: propsData.attrWorkspacePath,
+ issuableAttribute: MilestoneDropdown.issuableAttribute,
+ issuableType: propsData.issuableType,
+ workspaceType: propsData.workspaceType,
+ });
+ });
+
+ it('renders hidden input', () => {
+ createComponent();
+
+ expect(findHiddenInput().attributes()).toEqual({
+ type: 'hidden',
+ name: 'update[milestone_id]',
+ value: undefined,
+ });
+ });
+
+ describe('when milestone ID and title is provided', () => {
+ it('is used in the dropdown and hidden input', () => {
+ const milestone = {
+ id: 'gid://gitlab/Milestone/52',
+ title: __('Milestone 52'),
+ };
+ createComponent({ milestoneId: milestone.id, milestoneTitle: milestone.title });
+
+ expect(findSidebarDropdown().props('currentAttribute')).toEqual(milestone);
+ expect(findHiddenInput().attributes('value')).toBe(
+ getIdFromGraphQLId(milestone.id).toString(),
+ );
+ });
+ });
+
+ describe('when SidebarDropdown emits `change` event', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ describe('when valid milestone is emitted', () => {
+ it('updates the hidden input value', async () => {
+ const milestone = {
+ id: 'gid://gitlab/Milestone/52',
+ title: __('Milestone 52'),
+ };
+
+ findSidebarDropdown().vm.$emit('change', milestone);
+ await nextTick();
+
+ expect(findHiddenInput().attributes('value')).toBe(
+ getIdFromGraphQLId(milestone.id).toString(),
+ );
+ });
+ });
+
+ describe('when null milestone is emitted', () => {
+ it('updates the hidden input value to `0`', async () => {
+ const milestone = { id: null };
+
+ findSidebarDropdown().vm.$emit('change', milestone);
+ await nextTick();
+
+ expect(findHiddenInput().attributes('value')).toBe('0');
+ });
+ });
+ });
+});
diff --git a/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_inputs_spec.js b/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_inputs_spec.js
new file mode 100644
index 00000000000..277ef6d9561
--- /dev/null
+++ b/spec/frontend/sidebar/components/reviewers/sidebar_reviewers_inputs_spec.js
@@ -0,0 +1,36 @@
+import { shallowMount } from '@vue/test-utils';
+import SidebarReviewersInputs from '~/sidebar/components/reviewers/sidebar_reviewers_inputs.vue';
+import { state } from '~/sidebar/components/reviewers/sidebar_reviewers.vue';
+
+let wrapper;
+
+function factory() {
+ wrapper = shallowMount(SidebarReviewersInputs);
+}
+
+describe('Sidebar reviewers inputs component', () => {
+ it('renders hidden input', () => {
+ state.issuable.reviewers = {
+ nodes: [
+ {
+ id: 1,
+ avatarUrl: '',
+ name: 'root',
+ username: 'root',
+ mergeRequestInteraction: { canMerge: true },
+ },
+ {
+ id: 2,
+ avatarUrl: '',
+ name: 'root',
+ username: 'root',
+ mergeRequestInteraction: { canMerge: true },
+ },
+ ],
+ };
+
+ factory();
+
+ expect(wrapper.findAll('input[type="hidden"]').length).toBe(2);
+ });
+});
diff --git a/spec/frontend/sidebar/components/sidebar_dropdown_spec.js b/spec/frontend/sidebar/components/sidebar_dropdown_spec.js
new file mode 100644
index 00000000000..83bc8cf7002
--- /dev/null
+++ b/spec/frontend/sidebar/components/sidebar_dropdown_spec.js
@@ -0,0 +1,285 @@
+import {
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownText,
+ GlFormInput,
+ GlSearchBoxByType,
+} from '@gitlab/ui';
+import Vue, { nextTick } from 'vue';
+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 { IssuableType } from '~/issues/constants';
+import SidebarDropdown from '~/sidebar/components/sidebar_dropdown.vue';
+import { IssuableAttributeType } from '~/sidebar/constants';
+import projectIssueMilestoneQuery from '~/sidebar/queries/project_issue_milestone.query.graphql';
+import projectMilestonesQuery from '~/sidebar/queries/project_milestones.query.graphql';
+import {
+ emptyProjectMilestonesResponse,
+ mockIssue,
+ mockProjectMilestonesResponse,
+ noCurrentMilestoneResponse,
+} from '../mock_data';
+
+jest.mock('~/flash');
+
+describe('SidebarDropdown component', () => {
+ let wrapper;
+
+ const promiseData = { issuableSetAttribute: { issue: { attribute: { id: '123' } } } };
+ const mutationSuccess = () => jest.fn().mockResolvedValue({ data: promiseData });
+
+ const findDropdown = () => wrapper.findComponent(GlDropdown);
+ const findDropdownText = () => wrapper.findComponent(GlDropdownText);
+ const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
+ const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
+ const findDropdownItemWithText = (text) =>
+ findAllDropdownItems().wrappers.find((x) => x.text() === text);
+ const findAttributeItems = () => wrapper.findByTestId('milestone-items');
+ const findNoAttributeItem = () => wrapper.findByTestId('no-milestone-item');
+ const findLoadingIconDropdown = () => wrapper.findByTestId('loading-icon-dropdown');
+
+ const toggleDropdown = async () => {
+ wrapper.vm.$refs.dropdown.show();
+ findDropdown().vm.$emit('show');
+
+ await nextTick();
+ jest.runOnlyPendingTimers();
+ await waitForPromises();
+ };
+
+ const createComponentWithApollo = ({
+ requestHandlers = [],
+ projectMilestonesSpy = jest.fn().mockResolvedValue(mockProjectMilestonesResponse),
+ currentMilestoneSpy = jest.fn().mockResolvedValue(noCurrentMilestoneResponse),
+ } = {}) => {
+ Vue.use(VueApollo);
+
+ wrapper = mountExtended(SidebarDropdown, {
+ apolloProvider: createMockApollo([
+ [projectMilestonesQuery, projectMilestonesSpy],
+ [projectIssueMilestoneQuery, currentMilestoneSpy],
+ ...requestHandlers,
+ ]),
+ propsData: {
+ attrWorkspacePath: mockIssue.projectPath,
+ currentAttribute: {},
+ issuableType: IssuableType.Issue,
+ issuableAttribute: IssuableAttributeType.Milestone,
+ },
+ attachTo: document.body,
+ });
+ };
+
+ const createComponent = ({
+ props = {},
+ data = {},
+ mutationPromise = mutationSuccess,
+ queries = {},
+ } = {}) => {
+ wrapper = mountExtended(SidebarDropdown, {
+ propsData: {
+ attrWorkspacePath: mockIssue.projectPath,
+ currentAttribute: {},
+ issuableType: IssuableType.Issue,
+ issuableAttribute: IssuableAttributeType.Milestone,
+ ...props,
+ },
+ data() {
+ return data;
+ },
+ mocks: {
+ $apollo: {
+ mutate: mutationPromise(),
+ queries: {
+ currentAttribute: { loading: false },
+ attributesList: { loading: false },
+ ...queries,
+ },
+ },
+ },
+ });
+ };
+
+ describe('when a user can edit', () => {
+ describe('when user is editing', () => {
+ describe('when rendering the dropdown', () => {
+ it('shows a loading spinner while fetching a list of attributes', async () => {
+ createComponent({
+ queries: {
+ attributesList: { loading: true },
+ },
+ });
+
+ await toggleDropdown();
+
+ expect(findLoadingIconDropdown().exists()).toBe(true);
+ });
+
+ describe('GlDropdownItem with the right title and id', () => {
+ const id = 'id';
+ const title = 'title';
+
+ beforeEach(async () => {
+ createComponent({
+ props: { currentAttribute: { id, title } },
+ data: { attributesList: [{ id, title }] },
+ });
+
+ await toggleDropdown();
+ });
+
+ it('does not show a loading spinner', () => {
+ expect(findLoadingIconDropdown().exists()).toBe(false);
+ });
+
+ it('renders title $title', () => {
+ expect(findDropdownItemWithText(title).exists()).toBe(true);
+ });
+
+ it('checks the correct dropdown item', () => {
+ expect(
+ findAllDropdownItems()
+ .filter((w) => w.props('isChecked') === true)
+ .at(0)
+ .text(),
+ ).toBe(title);
+ });
+ });
+
+ describe('when no data is assigned', () => {
+ beforeEach(async () => {
+ createComponent();
+
+ await toggleDropdown();
+ });
+
+ it('finds GlDropdownItem with "No milestone"', () => {
+ expect(findNoAttributeItem().text()).toBe('No milestone');
+ });
+
+ it('"No milestone" is checked', () => {
+ expect(findAllDropdownItems('No milestone').at(0).props('isChecked')).toBe(true);
+ });
+
+ it('does not render any dropdown item', () => {
+ expect(findAttributeItems().exists()).toBe(false);
+ });
+ });
+
+ describe('when clicking on dropdown item', () => {
+ describe('when currentAttribute is equal to attribute id', () => {
+ it('does not call setIssueAttribute mutation', async () => {
+ createComponent({
+ props: { currentAttribute: { id: 'id', title: 'title' } },
+ data: { attributesList: [{ id: 'id', title: 'title' }] },
+ });
+
+ await toggleDropdown();
+
+ findDropdownItemWithText('title').vm.$emit('click');
+
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledTimes(0);
+ });
+ });
+ });
+ });
+
+ describe('when a user is searching', () => {
+ describe('when search result is not found', () => {
+ describe('when milestone', () => {
+ it('renders "No milestone found"', async () => {
+ createComponent();
+
+ await toggleDropdown();
+
+ findSearchBox().vm.$emit('input', 'non existing milestones');
+ await nextTick();
+
+ expect(findDropdownText().text()).toBe('No milestone found');
+ });
+ });
+ });
+ });
+ });
+ });
+
+ describe('with mock apollo', () => {
+ describe("when issuable type is 'issue'", () => {
+ describe('when dropdown is expanded and user can edit', () => {
+ it('renders the dropdown on clicking edit', async () => {
+ createComponentWithApollo();
+
+ await toggleDropdown();
+
+ expect(findDropdown().isVisible()).toBe(true);
+ });
+
+ it('focuses on the input when dropdown is shown', async () => {
+ createComponentWithApollo();
+
+ await toggleDropdown();
+
+ expect(document.activeElement).toEqual(wrapper.findComponent(GlFormInput).element);
+ });
+
+ describe('milestones', () => {
+ it('should call createAlert if milestones query fails', async () => {
+ createComponentWithApollo({
+ projectMilestonesSpy: jest.fn().mockRejectedValue(new Error()),
+ });
+
+ await toggleDropdown();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: wrapper.vm.i18n.listFetchError,
+ captureError: true,
+ error: expect.any(Error),
+ });
+ });
+
+ it('only fetches attributes when dropdown is opened', async () => {
+ const projectMilestonesSpy = jest
+ .fn()
+ .mockResolvedValueOnce(emptyProjectMilestonesResponse);
+ createComponentWithApollo({ projectMilestonesSpy });
+
+ expect(projectMilestonesSpy).not.toHaveBeenCalled();
+
+ await toggleDropdown();
+
+ expect(projectMilestonesSpy).toHaveBeenNthCalledWith(1, {
+ fullPath: mockIssue.projectPath,
+ state: 'active',
+ title: '',
+ });
+ });
+
+ describe('when a user is searching', () => {
+ it('sends a projectMilestones query with the entered search term "foo"', async () => {
+ const mockSearchTerm = 'foobar';
+ const projectMilestonesSpy = jest
+ .fn()
+ .mockResolvedValueOnce(emptyProjectMilestonesResponse);
+ createComponentWithApollo({ projectMilestonesSpy });
+
+ await toggleDropdown();
+
+ findSearchBox().vm.$emit('input', mockSearchTerm);
+ await nextTick();
+ jest.runOnlyPendingTimers(); // Account for debouncing
+
+ expect(projectMilestonesSpy).toHaveBeenNthCalledWith(2, {
+ fullPath: mockIssue.projectPath,
+ state: 'active',
+ title: mockSearchTerm,
+ });
+ });
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js b/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js
index 8ab4d8ea051..cf5e220a705 100644
--- a/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js
+++ b/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js
@@ -1,12 +1,4 @@
-import {
- GlDropdown,
- GlDropdownItem,
- GlDropdownText,
- GlLink,
- GlSearchBoxByType,
- GlFormInput,
- GlLoadingIcon,
-} from '@gitlab/ui';
+import { GlDropdown, GlLink, GlLoadingIcon, GlSearchBoxByType } from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
import { shallowMount, mount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
@@ -19,6 +11,7 @@ import { createAlert } from '~/flash';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { IssuableType } from '~/issues/constants';
import { timeFor } from '~/lib/utils/datetime_utility';
+import SidebarDropdown from '~/sidebar/components/sidebar_dropdown.vue';
import SidebarDropdownWidget from '~/sidebar/components/sidebar_dropdown_widget.vue';
import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue';
import { IssuableAttributeType } from '~/sidebar/constants';
@@ -32,7 +25,6 @@ import {
noCurrentMilestoneResponse,
mockMilestoneMutationResponse,
mockMilestone2,
- emptyProjectMilestonesResponse,
} from '../mock_data';
jest.mock('~/flash');
@@ -55,20 +47,11 @@ describe('SidebarDropdownWidget', () => {
const findGlLink = () => wrapper.findComponent(GlLink);
const findDateTooltip = () => getBinding(findGlLink().element, 'gl-tooltip');
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findDropdownText = () => wrapper.findComponent(GlDropdownText);
- const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
- const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- const findDropdownItemWithText = (text) =>
- findAllDropdownItems().wrappers.find((x) => x.text() === text);
-
+ const findSidebarDropdown = () => wrapper.findComponent(SidebarDropdown);
const findSidebarEditableItem = () => wrapper.findComponent(SidebarEditableItem);
const findEditButton = () => findSidebarEditableItem().find('[data-testid="edit-button"]');
const findEditableLoadingIcon = () => findSidebarEditableItem().findComponent(GlLoadingIcon);
- const findAttributeItems = () => wrapper.findByTestId('milestone-items');
const findSelectedAttribute = () => wrapper.findByTestId('select-milestone');
- const findNoAttributeItem = () => wrapper.findByTestId('no-milestone-item');
- const findLoadingIconDropdown = () => wrapper.findByTestId('loading-icon-dropdown');
const waitForDropdown = async () => {
// BDropdown first changes its `visible` property
@@ -167,6 +150,8 @@ describe('SidebarDropdownWidget', () => {
}),
);
+ wrapper.vm.$refs.dropdown.show = jest.fn();
+
// We need to mock out `showDropdown` which
// invokes `show` method of BDropdown used inside GlDropdown.
jest.spyOn(wrapper.vm, 'showDropdown').mockImplementation();
@@ -261,86 +246,7 @@ describe('SidebarDropdownWidget', () => {
describe('when a user can edit', () => {
describe('when user is editing', () => {
describe('when rendering the dropdown', () => {
- it('shows a loading spinner while fetching a list of attributes', async () => {
- createComponent({
- queries: {
- attributesList: { loading: true },
- },
- });
-
- await toggleDropdown();
-
- expect(findLoadingIconDropdown().exists()).toBe(true);
- });
-
- describe('GlDropdownItem with the right title and id', () => {
- const id = 'id';
- const title = 'title';
-
- beforeEach(async () => {
- createComponent({
- data: { attributesList: [{ id, title }], currentAttribute: { id, title } },
- });
-
- await toggleDropdown();
- });
-
- it('does not show a loading spinner', () => {
- expect(findLoadingIconDropdown().exists()).toBe(false);
- });
-
- it('renders title $title', () => {
- expect(findDropdownItemWithText(title).exists()).toBe(true);
- });
-
- it('checks the correct dropdown item', () => {
- expect(
- findAllDropdownItems()
- .filter((w) => w.props('isChecked') === true)
- .at(0)
- .text(),
- ).toBe(title);
- });
- });
-
- describe('when no data is assigned', () => {
- beforeEach(async () => {
- createComponent();
-
- await toggleDropdown();
- });
-
- it('finds GlDropdownItem with "No milestone"', () => {
- expect(findNoAttributeItem().text()).toBe('No milestone');
- });
-
- it('"No milestone" is checked', () => {
- expect(findNoAttributeItem().props('isChecked')).toBe(true);
- });
-
- it('does not render any dropdown item', () => {
- expect(findAttributeItems().exists()).toBe(false);
- });
- });
-
describe('when clicking on dropdown item', () => {
- describe('when currentAttribute is equal to attribute id', () => {
- it('does not call setIssueAttribute mutation', async () => {
- createComponent({
- data: {
- attributesList: [{ id: 'id', title: 'title' }],
- currentAttribute: { id: 'id', title: 'title' },
- },
- });
-
- await toggleDropdown();
-
- findDropdownItemWithText('title').vm.$emit('click');
-
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledTimes(0);
- });
- });
-
describe('when currentAttribute is not equal to attribute id', () => {
describe('when error', () => {
const bootstrapComponent = (mutationResp) => {
@@ -350,7 +256,7 @@ describe('SidebarDropdownWidget', () => {
{ id: '123', title: '123' },
{ id: 'id', title: 'title' },
],
- currentAttribute: '123',
+ currentAttribute: { id: '123' },
},
mutationPromise: mutationResp,
});
@@ -366,7 +272,7 @@ describe('SidebarDropdownWidget', () => {
await toggleDropdown();
- findDropdownItemWithText('title').vm.$emit('click');
+ findSidebarDropdown().vm.$emit('change', { id: 'error' });
});
it(`calls createAlert with "${expectedMsg}"`, async () => {
@@ -382,24 +288,6 @@ describe('SidebarDropdownWidget', () => {
});
});
});
-
- describe('when a user is searching', () => {
- describe('when search result is not found', () => {
- describe('when milestone', () => {
- it('renders "No milestone found"', async () => {
- createComponent();
-
- await toggleDropdown();
-
- findSearchBox().vm.$emit('input', 'non existing milestones');
-
- await nextTick();
-
- expect(findDropdownText().text()).toBe('No milestone found');
- });
- });
- });
- });
});
});
@@ -424,18 +312,10 @@ describe('SidebarDropdownWidget', () => {
await clickEdit();
});
- it('renders the dropdown on clicking edit', async () => {
- expect(findDropdown().isVisible()).toBe(true);
- });
-
- it('focuses on the input when dropdown is shown', async () => {
- expect(document.activeElement).toEqual(wrapper.findComponent(GlFormInput).element);
- });
-
describe('when currentAttribute is not equal to attribute id', () => {
describe('when update is successful', () => {
it('calls setIssueAttribute mutation', () => {
- findDropdownItemWithText(mockMilestone2.title).vm.$emit('click');
+ findSidebarDropdown().vm.$emit('change', { id: mockMilestone2.id });
expect(milestoneMutationSpy).toHaveBeenCalledWith({
iid: mockIssue.iid,
@@ -443,72 +323,6 @@ describe('SidebarDropdownWidget', () => {
fullPath: mockIssue.projectPath,
});
});
-
- it('sets the value returned from the mutation to currentAttribute', async () => {
- findDropdownItemWithText(mockMilestone2.title).vm.$emit('click');
- await nextTick();
- expect(findSelectedAttribute().text()).toBe(mockMilestone2.title);
- });
- });
- });
-
- describe('milestones', () => {
- let projectMilestonesSpy;
-
- it('should call createAlert if milestones query fails', async () => {
- await createComponentWithApollo({
- projectMilestonesSpy: jest.fn().mockRejectedValue(error),
- });
-
- await clickEdit();
-
- expect(createAlert).toHaveBeenCalledWith({
- message: wrapper.vm.i18n.listFetchError,
- captureError: true,
- error: expect.any(Error),
- });
- });
-
- it('only fetches attributes when dropdown is opened', async () => {
- projectMilestonesSpy = jest.fn().mockResolvedValueOnce(emptyProjectMilestonesResponse);
- await createComponentWithApollo({ projectMilestonesSpy });
-
- expect(projectMilestonesSpy).not.toHaveBeenCalled();
-
- await clickEdit();
-
- expect(projectMilestonesSpy).toHaveBeenNthCalledWith(1, {
- fullPath: mockIssue.projectPath,
- state: 'active',
- title: '',
- });
- });
-
- describe('when a user is searching', () => {
- const mockSearchTerm = 'foobar';
-
- beforeEach(async () => {
- projectMilestonesSpy = jest
- .fn()
- .mockResolvedValueOnce(emptyProjectMilestonesResponse);
- await createComponentWithApollo({ projectMilestonesSpy });
-
- await clickEdit();
- });
-
- it('sends a projectMilestones query with the entered search term "foo"', async () => {
- findSearchBox().vm.$emit('input', mockSearchTerm);
- await nextTick();
-
- // Account for debouncing
- jest.runAllTimers();
-
- expect(projectMilestonesSpy).toHaveBeenNthCalledWith(2, {
- fullPath: mockIssue.projectPath,
- state: 'active',
- title: mockSearchTerm,
- });
- });
});
});
});
diff --git a/spec/frontend/token_access/mock_data.js b/spec/frontend/token_access/mock_data.js
index 6e2908e659f..2eed1e30d0d 100644
--- a/spec/frontend/token_access/mock_data.js
+++ b/spec/frontend/token_access/mock_data.js
@@ -38,6 +38,10 @@ export const projectsWithScope = {
id: '2',
fullPath: 'root/332268-test',
name: 'root/332268-test',
+ namespace: {
+ id: '1234',
+ fullPath: 'root',
+ },
},
],
},
@@ -68,6 +72,10 @@ export const mockProjects = [
{
id: '1',
name: 'merge-train-stuff',
+ namespace: {
+ id: '1235',
+ fullPath: 'root',
+ },
fullPath: 'root/merge-train-stuff',
isLocked: false,
__typename: 'Project',
@@ -75,6 +83,10 @@ export const mockProjects = [
{
id: '2',
name: 'ci-project',
+ namespace: {
+ id: '1236',
+ fullPath: 'root',
+ },
fullPath: 'root/ci-project',
isLocked: true,
__typename: 'Project',
diff --git a/spec/frontend/token_access/token_access_spec.js b/spec/frontend/token_access/token_access_spec.js
index c55ac32b6a6..ea1d9db515a 100644
--- a/spec/frontend/token_access/token_access_spec.js
+++ b/spec/frontend/token_access/token_access_spec.js
@@ -19,7 +19,8 @@ import {
} from './mock_data';
const projectPath = 'root/my-repo';
-const error = new Error('Error');
+const message = 'An error occurred';
+const error = new Error(message);
Vue.use(VueApollo);
@@ -144,7 +145,7 @@ describe('TokenAccess component', () => {
await waitForPromises();
- expect(createAlert).toHaveBeenCalled();
+ expect(createAlert).toHaveBeenCalledWith({ message });
});
});
@@ -187,7 +188,7 @@ describe('TokenAccess component', () => {
await waitForPromises();
- expect(createAlert).toHaveBeenCalled();
+ expect(createAlert).toHaveBeenCalledWith({ message });
});
});
});
diff --git a/spec/frontend/token_access/token_projects_table_spec.js b/spec/frontend/token_access/token_projects_table_spec.js
index 3bda0d0b530..0fa1a2453f7 100644
--- a/spec/frontend/token_access/token_projects_table_spec.js
+++ b/spec/frontend/token_access/token_projects_table_spec.js
@@ -1,5 +1,5 @@
import { GlTable, GlButton } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
import TokenProjectsTable from '~/token_access/components/token_projects_table.vue';
import { mockProjects } from './mock_data';
@@ -7,7 +7,7 @@ describe('Token projects table', () => {
let wrapper;
const createComponent = () => {
- wrapper = mount(TokenProjectsTable, {
+ wrapper = mountExtended(TokenProjectsTable, {
provide: {
fullPath: 'root/ci-project',
},
@@ -18,9 +18,11 @@ describe('Token projects table', () => {
};
const findTable = () => wrapper.findComponent(GlTable);
- const findAllTableRows = () => wrapper.findAll('[data-testid="projects-token-table-row"]');
const findDeleteProjectBtn = () => wrapper.findComponent(GlButton);
const findAllDeleteProjectBtn = () => wrapper.findAllComponents(GlButton);
+ const findAllTableRows = () => wrapper.findAllByTestId('projects-token-table-row');
+ const findProjectNameCell = () => wrapper.findByTestId('token-access-project-name');
+ const findProjectNamespaceCell = () => wrapper.findByTestId('token-access-project-namespace');
beforeEach(() => {
createComponent();
@@ -48,4 +50,9 @@ describe('Token projects table', () => {
// currently two mock projects with one being a locked project
expect(findAllDeleteProjectBtn()).toHaveLength(1);
});
+
+ it('displays project and namespace cells', () => {
+ expect(findProjectNameCell().text()).toBe('merge-train-stuff');
+ expect(findProjectNamespaceCell().text()).toBe('root');
+ });
});
diff --git a/spec/frontend/users_select/utils_spec.js b/spec/frontend/users_select/utils_spec.js
index a09935d8a04..7a080ddaf0f 100644
--- a/spec/frontend/users_select/utils_spec.js
+++ b/spec/frontend/users_select/utils_spec.js
@@ -1,21 +1,10 @@
-import $ from 'jquery';
-import { getAjaxUsersSelectOptions, getAjaxUsersSelectParams } from '~/users_select/utils';
+import { getAjaxUsersSelectParams } from '~/users_select/utils';
const options = {
fooBar: 'baz',
activeUserId: 1,
};
-describe('getAjaxUsersSelectOptions', () => {
- it('returns options built from select data attributes', () => {
- const $select = $('<select />', { 'data-foo-bar': 'baz', 'data-user-id': 1 });
-
- expect(
- getAjaxUsersSelectOptions($select, { fooBar: 'fooBar', activeUserId: 'user-id' }),
- ).toEqual(options);
- });
-});
-
describe('getAjaxUsersSelectParams', () => {
it('returns query parameters built from provided options', () => {
expect(
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 4e3e918f7fb..8dadb0c65d0 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
@@ -20,7 +20,7 @@ describe('MrWidgetContainer', () => {
it('has layout', () => {
factory();
- expect(wrapper.classes()).toContain('mr-widget-heading');
+ expect(wrapper.classes()).toEqual(['mr-section-container', 'mr-widget-workflow']);
expect(wrapper.find('.mr-widget-content').exists()).toBe(true);
});
diff --git a/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js b/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js
index 7f0173b7445..144e176b0f0 100644
--- a/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js
@@ -222,6 +222,7 @@ describe('MRWidgetPipeline', () => {
beforeEach(() => {
({ pipeline } = JSON.parse(JSON.stringify(mockData)));
+ pipeline.details.event_type_name = 'Pipeline';
pipeline.details.name = 'Pipeline';
pipeline.merge_request_event_type = undefined;
pipeline.ref.tag = false;
@@ -263,6 +264,7 @@ describe('MRWidgetPipeline', () => {
describe('for a detached merge request pipeline', () => {
it('renders a pipeline widget that reads "Merge request pipeline <ID> <status> for <SHA>"', () => {
+ pipeline.details.event_type_name = 'Merge request pipeline';
pipeline.details.name = 'Merge request pipeline';
pipeline.merge_request_event_type = 'detached';
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 05c259de370..7b52773e92d 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
@@ -8,7 +8,7 @@ jest.mock('~/vue_shared/plugins/global_toast');
let wrapper;
-function createWrapper(propsData, mergeRequestWidgetGraphql) {
+function createWrapper(propsData) {
wrapper = mount(WidgetRebase, {
propsData,
data() {
@@ -22,7 +22,6 @@ function createWrapper(propsData, mergeRequestWidgetGraphql) {
},
};
},
- provide: { glFeatures: { mergeRequestWidgetGraphql } },
mocks: {
$apollo: {
queries: {
@@ -43,276 +42,244 @@ describe('Merge request widget rebase component', () => {
wrapper.destroy();
wrapper = null;
});
-
- [true, false].forEach((mergeRequestWidgetGraphql) => {
- describe(`widget graphql is ${mergeRequestWidgetGraphql ? 'enabled' : 'disabled'}`, () => {
- describe('while rebasing', () => {
- it('should show progress message', () => {
- createWrapper(
- {
- mr: { rebaseInProgress: true },
- service: {},
- },
- mergeRequestWidgetGraphql,
- );
-
- expect(findRebaseMessageText()).toContain('Rebase in progress');
- });
+ describe('while rebasing', () => {
+ it('should show progress message', () => {
+ createWrapper({
+ mr: { rebaseInProgress: true },
+ service: {},
});
- describe('with permissions', () => {
- const rebaseMock = jest.fn().mockResolvedValue();
- const pollMock = jest.fn().mockResolvedValue({});
+ expect(findRebaseMessageText()).toContain('Rebase in progress');
+ });
+ });
+
+ describe('with permissions', () => {
+ const rebaseMock = jest.fn().mockResolvedValue();
+ const pollMock = jest.fn().mockResolvedValue({});
- it('renders the warning message', () => {
- createWrapper(
- {
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
- },
- service: {
- rebase: rebaseMock,
- poll: pollMock,
- },
- },
- mergeRequestWidgetGraphql,
- );
+ it('renders the warning message', () => {
+ createWrapper({
+ mr: {
+ rebaseInProgress: false,
+ canPushToSourceBranch: true,
+ },
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
+ });
- const text = findRebaseMessageText();
+ const text = findRebaseMessageText();
- expect(text).toContain('Merge blocked');
- expect(text.replace(/\s\s+/g, ' ')).toContain(
- 'the source branch must be rebased onto the target branch',
- );
- });
+ expect(text).toContain('Merge blocked');
+ expect(text.replace(/\s\s+/g, ' ')).toContain(
+ 'the source branch must be rebased onto the target branch',
+ );
+ });
- it('renders an error message when rebasing has failed', async () => {
- createWrapper(
- {
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
- },
- service: {
- rebase: rebaseMock,
- poll: pollMock,
- },
- },
- mergeRequestWidgetGraphql,
- );
+ it('renders an error message when rebasing has failed', async () => {
+ createWrapper({
+ mr: {
+ rebaseInProgress: false,
+ canPushToSourceBranch: true,
+ },
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
+ });
+
+ // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
+ // eslint-disable-next-line no-restricted-syntax
+ wrapper.setData({ rebasingError: 'Something went wrong!' });
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ rebasingError: 'Something went wrong!' });
+ await nextTick();
+ expect(findRebaseMessageText()).toContain('Something went wrong!');
+ });
- await nextTick();
- expect(findRebaseMessageText()).toContain('Something went wrong!');
+ describe('Rebase buttons', () => {
+ beforeEach(() => {
+ createWrapper({
+ mr: {
+ rebaseInProgress: false,
+ canPushToSourceBranch: true,
+ },
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
});
+ });
- describe('Rebase buttons', () => {
- beforeEach(() => {
- createWrapper(
- {
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
- },
- service: {
- rebase: rebaseMock,
- poll: pollMock,
- },
- },
- mergeRequestWidgetGraphql,
- );
- });
+ it('renders both buttons', () => {
+ expect(findRebaseWithoutCiButton().exists()).toBe(true);
+ expect(findStandardRebaseButton().exists()).toBe(true);
+ });
- it('renders both buttons', () => {
- expect(findRebaseWithoutCiButton().exists()).toBe(true);
- expect(findStandardRebaseButton().exists()).toBe(true);
- });
+ it('starts the rebase when clicking', async () => {
+ findStandardRebaseButton().vm.$emit('click');
- it('starts the rebase when clicking', async () => {
- findStandardRebaseButton().vm.$emit('click');
+ await nextTick();
- await nextTick();
+ expect(rebaseMock).toHaveBeenCalledWith({ skipCi: false });
+ });
- expect(rebaseMock).toHaveBeenCalledWith({ skipCi: false });
- });
+ it('starts the CI-skipping rebase when clicking on "Rebase without CI"', async () => {
+ findRebaseWithoutCiButton().vm.$emit('click');
- it('starts the CI-skipping rebase when clicking on "Rebase without CI"', async () => {
- findRebaseWithoutCiButton().vm.$emit('click');
+ await nextTick();
- await nextTick();
+ expect(rebaseMock).toHaveBeenCalledWith({ skipCi: true });
+ });
+ });
- expect(rebaseMock).toHaveBeenCalledWith({ skipCi: true });
- });
+ describe('Rebase when pipelines must succeed is enabled', () => {
+ beforeEach(() => {
+ createWrapper({
+ mr: {
+ rebaseInProgress: false,
+ canPushToSourceBranch: true,
+ onlyAllowMergeIfPipelineSucceeds: true,
+ },
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
});
+ });
- describe('Rebase when pipelines must succeed is enabled', () => {
- beforeEach(() => {
- createWrapper(
- {
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
- onlyAllowMergeIfPipelineSucceeds: true,
- },
- service: {
- rebase: rebaseMock,
- poll: pollMock,
- },
- },
- mergeRequestWidgetGraphql,
- );
- });
+ it('renders only the rebase button', () => {
+ expect(findRebaseWithoutCiButton().exists()).toBe(false);
+ expect(findStandardRebaseButton().exists()).toBe(true);
+ });
- it('renders only the rebase button', () => {
- expect(findRebaseWithoutCiButton().exists()).toBe(false);
- expect(findStandardRebaseButton().exists()).toBe(true);
- });
+ it('starts the rebase when clicking', async () => {
+ findStandardRebaseButton().vm.$emit('click');
- it('starts the rebase when clicking', async () => {
- findStandardRebaseButton().vm.$emit('click');
+ await nextTick();
- await nextTick();
+ expect(rebaseMock).toHaveBeenCalledWith({ skipCi: false });
+ });
+ });
- expect(rebaseMock).toHaveBeenCalledWith({ skipCi: false });
- });
+ describe('Rebase when pipelines must succeed and skipped pipelines are considered successful are enabled', () => {
+ beforeEach(() => {
+ createWrapper({
+ mr: {
+ rebaseInProgress: false,
+ canPushToSourceBranch: true,
+ onlyAllowMergeIfPipelineSucceeds: true,
+ allowMergeOnSkippedPipeline: true,
+ },
+ service: {
+ rebase: rebaseMock,
+ poll: pollMock,
+ },
});
+ });
- describe('Rebase when pipelines must succeed and skipped pipelines are considered successful are enabled', () => {
- beforeEach(() => {
- createWrapper(
- {
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: true,
- onlyAllowMergeIfPipelineSucceeds: true,
- allowMergeOnSkippedPipeline: true,
- },
- service: {
- rebase: rebaseMock,
- poll: pollMock,
- },
- },
- mergeRequestWidgetGraphql,
- );
- });
+ it('renders both rebase buttons', () => {
+ expect(findRebaseWithoutCiButton().exists()).toBe(true);
+ expect(findStandardRebaseButton().exists()).toBe(true);
+ });
+
+ it('starts the rebase when clicking', async () => {
+ findStandardRebaseButton().vm.$emit('click');
- it('renders both rebase buttons', () => {
- expect(findRebaseWithoutCiButton().exists()).toBe(true);
- expect(findStandardRebaseButton().exists()).toBe(true);
- });
+ await nextTick();
- it('starts the rebase when clicking', async () => {
- findStandardRebaseButton().vm.$emit('click');
+ expect(rebaseMock).toHaveBeenCalledWith({ skipCi: false });
+ });
- await nextTick();
+ it('starts the CI-skipping rebase when clicking on "Rebase without CI"', async () => {
+ findRebaseWithoutCiButton().vm.$emit('click');
- expect(rebaseMock).toHaveBeenCalledWith({ skipCi: false });
- });
+ await nextTick();
- it('starts the CI-skipping rebase when clicking on "Rebase without CI"', async () => {
- findRebaseWithoutCiButton().vm.$emit('click');
+ expect(rebaseMock).toHaveBeenCalledWith({ skipCi: true });
+ });
+ });
+ });
- await nextTick();
+ describe('without permissions', () => {
+ const exampleTargetBranch = 'fake-branch-to-test-with';
- expect(rebaseMock).toHaveBeenCalledWith({ skipCi: true });
- });
+ describe('UI text', () => {
+ beforeEach(() => {
+ createWrapper({
+ mr: {
+ rebaseInProgress: false,
+ canPushToSourceBranch: false,
+ targetBranch: exampleTargetBranch,
+ },
+ service: {},
});
});
- describe('without permissions', () => {
- const exampleTargetBranch = 'fake-branch-to-test-with';
-
- describe('UI text', () => {
- beforeEach(() => {
- createWrapper(
- {
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: false,
- targetBranch: exampleTargetBranch,
- },
- service: {},
- },
- mergeRequestWidgetGraphql,
- );
- });
-
- it('renders a message explaining user does not have permissions', () => {
- const text = findRebaseMessageText();
-
- expect(text).toContain(
- 'Merge blocked: the source branch must be rebased onto the target branch.',
- );
- expect(text).toContain('the source branch must be rebased');
- });
-
- it('renders the correct target branch name', () => {
- const elem = findRebaseMessage();
-
- expect(elem.text()).toContain(
- 'Merge blocked: the source branch must be rebased onto the target branch.',
- );
- });
- });
+ it('renders a message explaining user does not have permissions', () => {
+ const text = findRebaseMessageText();
- it('does render the "Rebase without pipeline" button', () => {
- createWrapper(
- {
- mr: {
- rebaseInProgress: false,
- canPushToSourceBranch: false,
- targetBranch: exampleTargetBranch,
- },
- service: {},
- },
- mergeRequestWidgetGraphql,
- );
+ expect(text).toContain(
+ 'Merge blocked: the source branch must be rebased onto the target branch.',
+ );
+ expect(text).toContain('the source branch must be rebased');
+ });
- expect(findRebaseWithoutCiButton().exists()).toBe(true);
- });
+ it('renders the correct target branch name', () => {
+ const elem = findRebaseMessage();
+
+ expect(elem.text()).toContain(
+ 'Merge blocked: the source branch must be rebased onto the target branch.',
+ );
+ });
+ });
+
+ it('does render the "Rebase without pipeline" button', () => {
+ createWrapper({
+ mr: {
+ rebaseInProgress: false,
+ canPushToSourceBranch: false,
+ targetBranch: exampleTargetBranch,
+ },
+ service: {},
});
- describe('methods', () => {
- it('checkRebaseStatus', async () => {
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
- createWrapper(
- {
- mr: {},
- service: {
- rebase() {
- return Promise.resolve();
- },
- poll() {
- return Promise.resolve({
- data: {
- rebase_in_progress: false,
- should_be_rebased: false,
- merge_error: null,
- },
- });
- },
+ expect(findRebaseWithoutCiButton().exists()).toBe(true);
+ });
+ });
+
+ describe('methods', () => {
+ it('checkRebaseStatus', async () => {
+ jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
+ createWrapper({
+ mr: {},
+ service: {
+ rebase() {
+ return Promise.resolve();
+ },
+ poll() {
+ return Promise.resolve({
+ data: {
+ rebase_in_progress: false,
+ should_be_rebased: false,
+ merge_error: null,
},
- },
- mergeRequestWidgetGraphql,
- );
+ });
+ },
+ },
+ });
- wrapper.vm.rebase();
+ wrapper.vm.rebase();
- // Wait for the rebase request
- await nextTick();
- // Wait for the polling request
- await nextTick();
- // Wait for the eventHub to be called
- await nextTick();
+ // Wait for the rebase request
+ await nextTick();
+ // Wait for the polling request
+ await nextTick();
+ // Wait for the eventHub to be called
+ await nextTick();
- expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetRebaseSuccess');
- expect(toast).toHaveBeenCalledWith('Rebase completed');
- });
- });
+ expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetRebaseSuccess');
+ expect(toast).toHaveBeenCalledWith('Rebase completed');
});
});
});
diff --git a/spec/frontend/vue_merge_request_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap b/spec/frontend/vue_merge_request_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap
index 5f383c468d8..bd40a968392 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap
+++ b/spec/frontend/vue_merge_request_widget/components/states/__snapshots__/mr_widget_auto_merge_enabled_spec.js.snap
@@ -1,8 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`MRWidgetAutoMergeEnabled when graphql is disabled template should have correct elements 1`] = `
+exports[`MRWidgetAutoMergeEnabled template should have correct elements 1`] = `
<div
- class="mr-widget-body media"
+ class="mr-widget-body media mr-widget-body-line-height-1 gl-line-height-normal"
>
<div
class="gl-w-6 gl-h-6 gl-display-flex gl-align-self-start gl-mr-3"
@@ -44,210 +44,18 @@ exports[`MRWidgetAutoMergeEnabled when graphql is disabled template should have
class="gl-display-flex gl-w-full"
>
<div
- class="media-body gl-display-flex"
+ class="media-body gl-display-flex gl-align-items-center"
>
<h4
class="gl-mr-3"
data-testid="statusText"
>
- Set by
- <a
- class="author-link inline"
- >
- <img
- class="avatar avatar-inline s16"
- src="no_avatar.png"
- />
-
- <span
- class="author"
- >
-
- </span>
- </a>
- to be merged automatically when the pipeline succeeds
- </h4>
-
- <div
- class="gl-display-flex gl-md-display-block gl-font-size-0 gl-ml-auto"
- >
- <div
- class="gl-display-flex gl-align-items-flex-start"
- >
- <div
- class="dropdown b-dropdown gl-new-dropdown gl-display-block gl-md-display-none! btn-group"
- lazy=""
- no-caret=""
- title="Options"
- >
- <!---->
- <button
- aria-expanded="false"
- aria-haspopup="true"
- class="btn dropdown-toggle btn-default btn-sm gl-p-2! gl-button gl-dropdown-toggle btn-default-tertiary dropdown-icon-only dropdown-toggle-no-caret"
- type="button"
- >
- <!---->
-
- <svg
- aria-hidden="true"
- class="dropdown-icon gl-icon s16"
- data-testid="ellipsis_v-icon"
- role="img"
- >
- <use
- href="#ellipsis_v"
- />
- </svg>
-
- <span
- class="gl-new-dropdown-button-text gl-sr-only"
- >
-
- </span>
-
- <svg
- aria-hidden="true"
- class="gl-button-icon dropdown-chevron gl-icon s16"
- data-testid="chevron-down-icon"
- role="img"
- >
- <use
- href="#chevron-down"
- />
- </svg>
- </button>
- <ul
- class="dropdown-menu dropdown-menu-right"
- role="menu"
- tabindex="-1"
- >
- <!---->
- </ul>
- </div>
-
- <button
- class="btn gl-display-none gl-md-display-block gl-float-left btn-confirm btn-sm gl-button btn-confirm-tertiary js-cancel-auto-merge"
- data-qa-selector="cancel_auto_merge_button"
- data-testid="cancelAutomaticMergeButton"
- type="button"
- >
- <!---->
-
- <!---->
-
- <span
- class="gl-button-text"
- >
-
- Cancel auto-merge
-
- </span>
- </button>
- </div>
- </div>
- </div>
-
- <div
- class="gl-md-display-none gl-border-l-1 gl-border-l-solid gl-border-gray-100 gl-ml-3 gl-pl-3 gl-h-6 gl-mt-1"
- >
- <button
- class="btn gl-vertical-align-top btn-default btn-sm gl-button btn-default-tertiary btn-icon"
- title="Collapse merge details"
- type="button"
- >
- <!---->
-
- <svg
- aria-hidden="true"
- class="gl-button-icon gl-icon s16"
- data-testid="chevron-lg-up-icon"
- role="img"
- >
- <use
- href="#chevron-lg-up"
- />
- </svg>
-
- <!---->
- </button>
- </div>
- </div>
-</div>
-`;
-
-exports[`MRWidgetAutoMergeEnabled when graphql is enabled template should have correct elements 1`] = `
-<div
- class="mr-widget-body media"
->
- <div
- class="gl-w-6 gl-h-6 gl-display-flex gl-align-self-start gl-mr-3"
- >
- <div
- class="gl-display-flex gl-m-auto"
- >
- <div
- class="gl-mr-3 gl-p-2 gl-m-0! gl-text-blue-500 gl-w-6 gl-p-2"
- >
- <div
- class="gl-rounded-full gl-relative gl-display-flex mr-widget-extension-icon"
- >
- <div
- class="gl-absolute gl-top-half gl-left-50p gl-translate-x-n50 gl-display-flex gl-m-auto"
- >
- <div
- class="gl-display-flex gl-m-auto gl-translate-y-n50"
- >
- <svg
- aria-label="Scheduled "
- class="gl-display-block gl-icon s12"
- data-qa-selector="status_scheduled_icon"
- data-testid="status-scheduled-icon"
- role="img"
- >
- <use
- href="#status-scheduled"
- />
- </svg>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <div
- class="gl-display-flex gl-w-full"
- >
- <div
- class="media-body gl-display-flex"
- >
-
- <h4
- class="gl-mr-3"
- data-testid="statusText"
- >
- Set by
- <a
- class="author-link inline"
- >
- <img
- class="avatar avatar-inline s16"
- src="no_avatar.png"
- />
-
- <span
- class="author"
- >
-
- </span>
- </a>
- to be merged automatically when the pipeline succeeds
+ Set by to be merged automatically when the pipeline succeeds
</h4>
<div
- class="gl-display-flex gl-md-display-block gl-font-size-0 gl-ml-auto"
+ class="gl-display-flex gl-font-size-0 gl-ml-auto gl-gap-3"
>
<div
class="gl-display-flex gl-align-items-flex-start"
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 d85574262fe..8eeba4d6274 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
@@ -1,5 +1,6 @@
import { shallowMount } from '@vue/test-utils';
import MergeChecksFailed from '~/vue_merge_request_widget/components/states/merge_checks_failed.vue';
+import { DETAILED_MERGE_STATUS } from '~/vue_merge_request_widget/constants';
let wrapper;
@@ -15,9 +16,10 @@ describe('Merge request widget merge checks failed state component', () => {
});
it.each`
- mrState | displayText
- ${{ approvals: true, isApproved: false }} | ${'approvalNeeded'}
- ${{ detailedMergeStatus: 'BLOCKED_STATUS' }} | ${'blockingMergeRequests'}
+ mrState | displayText
+ ${{ approvals: true, isApproved: false }} | ${'approvalNeeded'}
+ ${{ detailedMergeStatus: DETAILED_MERGE_STATUS.BLOCKED_STATUS }} | ${'blockingMergeRequests'}
+ ${{ detailedMergeStatus: DETAILED_MERGE_STATUS.EXTERNAL_STATUS_CHECKS }} | ${'externalStatusChecksFailed'}
`('display $displayText text for $mrState', ({ mrState, displayText }) => {
factory({ mr: mrState });
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 28182793683..5b9f30dfb86 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
@@ -9,7 +9,6 @@ import eventHub from '~/vue_merge_request_widget/event_hub';
import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service';
let wrapper;
-let mergeRequestWidgetGraphqlEnabled = false;
function convertPropsToGraphqlState(props) {
return {
@@ -30,12 +29,6 @@ function convertPropsToGraphqlState(props) {
}
function factory(propsData, stateOverride = {}) {
- let state = {};
-
- if (mergeRequestWidgetGraphqlEnabled) {
- state = { ...convertPropsToGraphqlState(propsData), ...stateOverride };
- }
-
wrapper = extendedWrapper(
mount(autoMergeEnabledComponent, {
propsData: {
@@ -43,9 +36,8 @@ function factory(propsData, stateOverride = {}) {
service: new MRWidgetService({}),
},
data() {
- return { state };
+ return { ...convertPropsToGraphqlState(propsData), ...stateOverride };
},
- provide: { glFeatures: { mergeRequestWidgetGraphql: mergeRequestWidgetGraphqlEnabled } },
mocks: {
$apollo: {
queries: {
@@ -95,130 +87,88 @@ describe('MRWidgetAutoMergeEnabled', () => {
wrapper = null;
});
- [true, false].forEach((mergeRequestWidgetGraphql) => {
- describe(`when graphql is ${mergeRequestWidgetGraphql ? 'enabled' : 'disabled'}`, () => {
- beforeEach(() => {
- mergeRequestWidgetGraphqlEnabled = mergeRequestWidgetGraphql;
+ describe('computed', () => {
+ describe('cancelButtonText', () => {
+ it('should return "Cancel" if MWPS is selected', () => {
+ factory({
+ ...defaultMrProps(),
+ autoMergeStrategy: MWPS_MERGE_STRATEGY,
+ });
+
+ expect(wrapper.findByTestId('cancelAutomaticMergeButton').text()).toBe('Cancel auto-merge');
});
+ });
+ });
- describe('computed', () => {
- describe('cancelButtonText', () => {
- it('should return "Cancel" if MWPS is selected', () => {
- factory({
- ...defaultMrProps(),
- autoMergeStrategy: MWPS_MERGE_STRATEGY,
+ describe('methods', () => {
+ describe('cancelAutomaticMerge', () => {
+ it('should set flag and call service then tell main component to update the widget with data', async () => {
+ factory({
+ ...defaultMrProps(),
+ });
+ const mrObj = {
+ is_new_mr_data: true,
+ };
+ jest.spyOn(wrapper.vm.service, 'cancelAutomaticMerge').mockReturnValue(
+ new Promise((resolve) => {
+ resolve({
+ data: mrObj,
});
+ }),
+ );
- expect(wrapper.findByTestId('cancelAutomaticMergeButton').text()).toBe(
- 'Cancel auto-merge',
- );
- });
- });
- });
+ wrapper.vm.cancelAutomaticMerge();
- describe('methods', () => {
- describe('cancelAutomaticMerge', () => {
- it('should set flag and call service then tell main component to update the widget with data', async () => {
- factory({
- ...defaultMrProps(),
- });
- const mrObj = {
- is_new_mr_data: true,
- };
- jest.spyOn(wrapper.vm.service, 'cancelAutomaticMerge').mockReturnValue(
- new Promise((resolve) => {
- resolve({
- data: mrObj,
- });
- }),
- );
-
- wrapper.vm.cancelAutomaticMerge();
-
- await waitForPromises();
-
- expect(wrapper.vm.isCancellingAutoMerge).toBe(true);
- if (mergeRequestWidgetGraphql) {
- expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
- } else {
- expect(eventHub.$emit).toHaveBeenCalledWith('UpdateWidgetData', mrObj);
- }
- });
- });
+ await waitForPromises();
- describe('removeSourceBranch', () => {
- it('should set flag and call service then request main component to update the widget', async () => {
- factory({
- ...defaultMrProps(),
- });
- jest.spyOn(wrapper.vm.service, 'merge').mockReturnValue(
- Promise.resolve({
- data: {
- status: MWPS_MERGE_STRATEGY,
- },
- }),
- );
-
- wrapper.vm.removeSourceBranch();
-
- await waitForPromises();
-
- expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
- expect(wrapper.vm.service.merge).toHaveBeenCalledWith({
- sha,
- auto_merge_strategy: MWPS_MERGE_STRATEGY,
- should_remove_source_branch: true,
- });
- });
- });
+ expect(wrapper.vm.isCancellingAutoMerge).toBe(true);
+ expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
});
+ });
+ });
- describe('template', () => {
- it('should have correct elements', () => {
- factory({
- ...defaultMrProps(),
- });
+ describe('template', () => {
+ it('should have correct elements', () => {
+ factory({
+ ...defaultMrProps(),
+ });
- expect(wrapper.element).toMatchSnapshot();
- });
+ expect(wrapper.element).toMatchSnapshot();
+ });
- it('should disable cancel auto merge button when the action is in progress', async () => {
- factory({
- ...defaultMrProps(),
- });
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- isCancellingAutoMerge: true,
- });
+ it('should disable cancel auto merge button when the action is in progress', async () => {
+ factory({
+ ...defaultMrProps(),
+ });
+ // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
+ // eslint-disable-next-line no-restricted-syntax
+ wrapper.setData({
+ isCancellingAutoMerge: true,
+ });
- await nextTick();
+ await nextTick();
- expect(wrapper.find('.js-cancel-auto-merge').props('loading')).toBe(true);
- });
+ expect(wrapper.find('.js-cancel-auto-merge').props('loading')).toBe(true);
+ });
- it('should render the status text as "...to merged automatically" if MWPS is selected', () => {
- factory({
- ...defaultMrProps(),
- autoMergeStrategy: MWPS_MERGE_STRATEGY,
- });
+ it('should render the status text as "...to merged automatically" if MWPS is selected', () => {
+ factory({
+ ...defaultMrProps(),
+ autoMergeStrategy: MWPS_MERGE_STRATEGY,
+ });
- expect(getStatusText()).toContain(
- 'to be merged automatically when the pipeline succeeds',
- );
- });
+ expect(getStatusText()).toContain('to be merged automatically when the pipeline succeeds');
+ });
- it('should render the cancel button as "Cancel" if MWPS is selected', () => {
- factory({
- ...defaultMrProps(),
- autoMergeStrategy: MWPS_MERGE_STRATEGY,
- });
+ it('should render the cancel button as "Cancel" if MWPS is selected', () => {
+ factory({
+ ...defaultMrProps(),
+ autoMergeStrategy: MWPS_MERGE_STRATEGY,
+ });
- const cancelButtonText = trimText(wrapper.find('.js-cancel-auto-merge').text());
+ const cancelButtonText = trimText(wrapper.find('.js-cancel-auto-merge').text());
- expect(cancelButtonText).toBe('Cancel auto-merge');
- });
- });
+ expect(cancelButtonText).toBe('Cancel auto-merge');
});
});
});
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 398a3912882..826f708069c 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
@@ -9,18 +9,11 @@ describe('MRWidgetAutoMergeFailed', () => {
const mergeError = 'This is the merge error';
const findButton = () => wrapper.findComponent(GlButton);
- const createComponent = (props = {}, mergeRequestWidgetGraphql = false) => {
+ const createComponent = (props = {}) => {
wrapper = mount(AutoMergeFailedComponent, {
propsData: { ...props },
data() {
- if (mergeRequestWidgetGraphql) {
- return { mergeError: props.mr?.mergeError };
- }
-
- return {};
- },
- provide: {
- glFeatures: { mergeRequestWidgetGraphql },
+ return { mergeError: props.mr?.mergeError };
},
});
};
@@ -29,40 +22,33 @@ describe('MRWidgetAutoMergeFailed', () => {
wrapper.destroy();
});
- [true, false].forEach((mergeRequestWidgetGraphql) => {
- describe(`when graphql is ${mergeRequestWidgetGraphql ? 'enabled' : 'dislabed'}`, () => {
- beforeEach(() => {
- createComponent(
- {
- mr: { mergeError },
- },
- mergeRequestWidgetGraphql,
- );
- });
+ beforeEach(() => {
+ createComponent({
+ mr: { mergeError },
+ });
+ });
- it('renders failed message', () => {
- expect(wrapper.text()).toContain('This merge request failed to be merged automatically');
- });
+ it('renders failed message', () => {
+ expect(wrapper.text()).toContain('This merge request failed to be merged automatically');
+ });
- it('renders merge error provided', () => {
- expect(wrapper.text()).toContain(mergeError);
- });
+ it('renders merge error provided', () => {
+ expect(wrapper.text()).toContain(mergeError);
+ });
- it('render refresh button', () => {
- expect(findButton().text()).toBe('Refresh');
- });
+ it('render refresh button', () => {
+ expect(findButton().text()).toBe('Refresh');
+ });
- it('emits event and shows loading icon when button is clicked', async () => {
- jest.spyOn(eventHub, '$emit');
- findButton().vm.$emit('click');
+ it('emits event and shows loading icon when button is clicked', async () => {
+ jest.spyOn(eventHub, '$emit');
+ findButton().vm.$emit('click');
- expect(eventHub.$emit.mock.calls[0][0]).toBe('MRWidgetUpdateRequested');
+ expect(eventHub.$emit.mock.calls[0][0]).toBe('MRWidgetUpdateRequested');
- await nextTick();
+ await nextTick();
- expect(findButton().attributes('disabled')).toBe('disabled');
- expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
- });
- });
+ expect(findButton().attributes('disabled')).toBe('disabled');
+ expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
});
});
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 7a9fd5b002d..a16e4d4a6ea 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
@@ -7,7 +7,6 @@ import ConflictsComponent from '~/vue_merge_request_widget/components/states/mr_
describe('MRWidgetConflicts', () => {
let wrapper;
- let mergeRequestWidgetGraphql = null;
const path = '/conflicts';
const findResolveButton = () => wrapper.findByTestId('resolve-conflicts-button');
@@ -25,10 +24,17 @@ describe('MRWidgetConflicts', () => {
wrapper = extendedWrapper(
mount(ConflictsComponent, {
propsData,
- provide: {
- glFeatures: {
- mergeRequestWidgetGraphql,
- },
+ data() {
+ return {
+ userPermissions: {
+ canMerge: propsData.mr.canMerge,
+ pushToSourceBranch: propsData.mr.canPushToSourceBranch,
+ },
+ state: {
+ shouldBeRebased: propsData.mr.shouldBeRebased,
+ sourceBranchProtected: propsData.mr.sourceBranchProtected,
+ },
+ };
},
mocks: {
$apollo: {
@@ -41,212 +47,188 @@ describe('MRWidgetConflicts', () => {
}),
);
- if (mergeRequestWidgetGraphql) {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({
- userPermissions: {
- canMerge: propsData.mr.canMerge,
- pushToSourceBranch: propsData.mr.canPushToSourceBranch,
- },
- stateData: {
- shouldBeRebased: propsData.mr.shouldBeRebased,
- sourceBranchProtected: propsData.mr.sourceBranchProtected,
- },
- });
- }
-
await nextTick();
}
afterEach(() => {
- mergeRequestWidgetGraphql = null;
wrapper.destroy();
});
- [false, true].forEach((featureEnabled) => {
- describe(`with GraphQL feature flag ${featureEnabled ? 'enabled' : 'disabled'}`, () => {
- beforeEach(() => {
- mergeRequestWidgetGraphql = featureEnabled;
+ // There are two permissions we need to consider:
+ //
+ // 1. Is the user allowed to merge to the target branch?
+ // 2. Is the user allowed to push to the source branch?
+ //
+ // This yields 4 possible permutations that we need to test, and
+ // we test them below. A user who can push to the source
+ // branch should be allowed to resolve conflicts. This is
+ // consistent with what the backend does.
+ describe('when allowed to merge but not allowed to push to source branch', () => {
+ beforeEach(async () => {
+ await createComponent({
+ mr: {
+ canMerge: true,
+ canPushToSourceBranch: false,
+ conflictResolutionPath: path,
+ conflictsDocsPath: '',
+ },
});
+ });
- // There are two permissions we need to consider:
- //
- // 1. Is the user allowed to merge to the target branch?
- // 2. Is the user allowed to push to the source branch?
- //
- // This yields 4 possible permutations that we need to test, and
- // we test them below. A user who can push to the source
- // branch should be allowed to resolve conflicts. This is
- // consistent with what the backend does.
- describe('when allowed to merge but not allowed to push to source branch', () => {
- beforeEach(async () => {
- await createComponent({
- mr: {
- canMerge: true,
- canPushToSourceBranch: false,
- conflictResolutionPath: path,
- conflictsDocsPath: '',
- },
- });
- });
+ it('should tell you about conflicts without bothering other people', () => {
+ expect(wrapper.text()).toContain(mergeConflictsText);
+ expect(wrapper.text()).not.toContain(userCannotMergeText);
+ });
- it('should tell you about conflicts without bothering other people', () => {
- expect(wrapper.text()).toContain(mergeConflictsText);
- expect(wrapper.text()).not.toContain(userCannotMergeText);
- });
+ it('should not allow you to resolve the conflicts', () => {
+ expect(wrapper.text()).not.toContain(resolveConflictsBtnText);
+ });
- it('should not allow you to resolve the conflicts', () => {
- expect(wrapper.text()).not.toContain(resolveConflictsBtnText);
- });
+ it('should have merge buttons', () => {
+ expect(findMergeLocalButton().text()).toContain(mergeLocallyBtnText);
+ });
+ });
- it('should have merge buttons', () => {
- expect(findMergeLocalButton().text()).toContain(mergeLocallyBtnText);
- });
+ describe('when not allowed to merge but allowed to push to source branch', () => {
+ beforeEach(async () => {
+ await createComponent({
+ mr: {
+ canMerge: false,
+ canPushToSourceBranch: true,
+ conflictResolutionPath: path,
+ conflictsDocsPath: '',
+ },
});
+ });
- describe('when not allowed to merge but allowed to push to source branch', () => {
- beforeEach(async () => {
- await createComponent({
- mr: {
- canMerge: false,
- canPushToSourceBranch: true,
- conflictResolutionPath: path,
- conflictsDocsPath: '',
- },
- });
- });
-
- it('should tell you about conflicts', () => {
- expect(wrapper.text()).toContain(mergeConflictsText);
- expect(wrapper.text()).toContain(userCannotMergeText);
- });
-
- it('should allow you to resolve the conflicts', () => {
- expect(findResolveButton().text()).toContain(resolveConflictsBtnText);
- expect(findResolveButton().attributes('href')).toEqual(path);
- });
-
- it('should not have merge buttons', () => {
- expect(wrapper.text()).not.toContain(mergeLocallyBtnText);
- });
+ it('should tell you about conflicts', () => {
+ expect(wrapper.text()).toContain(mergeConflictsText);
+ expect(wrapper.text()).toContain(userCannotMergeText);
+ });
+
+ it('should allow you to resolve the conflicts', () => {
+ expect(findResolveButton().text()).toContain(resolveConflictsBtnText);
+ expect(findResolveButton().attributes('href')).toEqual(path);
+ });
+
+ it('should not have merge buttons', () => {
+ expect(wrapper.text()).not.toContain(mergeLocallyBtnText);
+ });
+ });
+
+ describe('when allowed to merge and push to source branch', () => {
+ beforeEach(async () => {
+ await createComponent({
+ mr: {
+ canMerge: true,
+ canPushToSourceBranch: true,
+ conflictResolutionPath: path,
+ conflictsDocsPath: '',
+ },
});
+ });
- describe('when allowed to merge and push to source branch', () => {
- beforeEach(async () => {
- await createComponent({
- mr: {
- canMerge: true,
- canPushToSourceBranch: true,
- conflictResolutionPath: path,
- conflictsDocsPath: '',
- },
- });
- });
-
- it('should tell you about conflicts without bothering other people', () => {
- expect(wrapper.text()).toContain(mergeConflictsText);
- expect(wrapper.text()).not.toContain(userCannotMergeText);
- });
-
- it('should allow you to resolve the conflicts', () => {
- expect(findResolveButton().text()).toContain(resolveConflictsBtnText);
- expect(findResolveButton().attributes('href')).toEqual(path);
- });
-
- it('should have merge buttons', () => {
- expect(findMergeLocalButton().text()).toContain(mergeLocallyBtnText);
- });
+ it('should tell you about conflicts without bothering other people', () => {
+ expect(wrapper.text()).toContain(mergeConflictsText);
+ expect(wrapper.text()).not.toContain(userCannotMergeText);
+ });
+
+ it('should allow you to resolve the conflicts', () => {
+ expect(findResolveButton().text()).toContain(resolveConflictsBtnText);
+ expect(findResolveButton().attributes('href')).toEqual(path);
+ });
+
+ it('should have merge buttons', () => {
+ expect(findMergeLocalButton().text()).toContain(mergeLocallyBtnText);
+ });
+ });
+
+ describe('when user does not have permission to push to source branch', () => {
+ it('should show proper message', async () => {
+ await createComponent({
+ mr: {
+ canMerge: false,
+ canPushToSourceBranch: false,
+ conflictsDocsPath: '',
+ },
});
- describe('when user does not have permission to push to source branch', () => {
- it('should show proper message', async () => {
- await createComponent({
- mr: {
- canMerge: false,
- canPushToSourceBranch: false,
- conflictsDocsPath: '',
- },
- });
+ expect(wrapper.text().trim().replace(/\s\s+/g, ' ')).toContain(userCannotMergeText);
+ });
- expect(wrapper.text().trim().replace(/\s\s+/g, ' ')).toContain(userCannotMergeText);
- });
+ it('should not have action buttons', async () => {
+ await createComponent({
+ mr: {
+ canMerge: false,
+ canPushToSourceBranch: false,
+ conflictsDocsPath: '',
+ },
+ });
- it('should not have action buttons', async () => {
- await createComponent({
- mr: {
- canMerge: false,
- canPushToSourceBranch: false,
- conflictsDocsPath: '',
- },
- });
-
- expect(findResolveButton().exists()).toBe(false);
- expect(findMergeLocalButton().exists()).toBe(false);
- });
-
- it('should not have resolve button when no conflict resolution path', async () => {
- await createComponent({
- mr: {
- canMerge: true,
- conflictResolutionPath: null,
- conflictsDocsPath: '',
- },
- });
+ expect(findResolveButton().exists()).toBe(false);
+ expect(findMergeLocalButton().exists()).toBe(false);
+ });
- expect(findResolveButton().exists()).toBe(false);
- });
+ it('should not have resolve button when no conflict resolution path', async () => {
+ await createComponent({
+ mr: {
+ canMerge: true,
+ conflictResolutionPath: null,
+ conflictsDocsPath: '',
+ },
});
- describe('when fast-forward or semi-linear merge enabled', () => {
- it('should tell you to rebase locally', async () => {
- await createComponent({
- mr: {
- shouldBeRebased: true,
- conflictsDocsPath: '',
- },
- });
+ expect(findResolveButton().exists()).toBe(false);
+ });
+ });
- expect(removeBreakLine(wrapper.text()).trim()).toContain(fastForwardMergeText);
- });
+ describe('when fast-forward or semi-linear merge enabled', () => {
+ it('should tell you to rebase locally', async () => {
+ await createComponent({
+ mr: {
+ shouldBeRebased: true,
+ conflictsDocsPath: '',
+ },
});
- describe('when source branch protected', () => {
- beforeEach(async () => {
- await createComponent({
- mr: {
- canMerge: true,
- canPushToSourceBranch: true,
- conflictResolutionPath: TEST_HOST,
- sourceBranchProtected: true,
- conflictsDocsPath: '',
- },
- });
- });
+ expect(removeBreakLine(wrapper.text()).trim()).toContain(fastForwardMergeText);
+ });
+ });
- it('should allow you to resolve the conflicts', () => {
- expect(findResolveButton().exists()).toBe(true);
- });
+ describe('when source branch protected', () => {
+ beforeEach(async () => {
+ await createComponent({
+ mr: {
+ canMerge: true,
+ canPushToSourceBranch: true,
+ conflictResolutionPath: TEST_HOST,
+ sourceBranchProtected: true,
+ conflictsDocsPath: '',
+ },
});
+ });
- describe('when source branch not protected', () => {
- beforeEach(async () => {
- await createComponent({
- mr: {
- canMerge: true,
- canPushToSourceBranch: true,
- conflictResolutionPath: TEST_HOST,
- sourceBranchProtected: false,
- conflictsDocsPath: '',
- },
- });
- });
+ it('should not allow you to resolve the conflicts', () => {
+ expect(findResolveButton().exists()).toBe(false);
+ });
+ });
- it('should allow you to resolve the conflicts', () => {
- expect(findResolveButton().text()).toContain(resolveConflictsBtnText);
- expect(findResolveButton().attributes('href')).toEqual(TEST_HOST);
- });
+ describe('when source branch not protected', () => {
+ beforeEach(async () => {
+ await createComponent({
+ mr: {
+ canMerge: true,
+ canPushToSourceBranch: true,
+ conflictResolutionPath: TEST_HOST,
+ sourceBranchProtected: false,
+ conflictsDocsPath: '',
+ },
});
});
+
+ it('should allow you to resolve the conflicts', () => {
+ expect(findResolveButton().text()).toContain(resolveConflictsBtnText);
+ expect(findResolveButton().attributes('href')).toEqual(TEST_HOST);
+ });
});
});
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 ddce07954ab..f29cf55f7ce 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
@@ -1,26 +1,17 @@
import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
import MissingBranchComponent from '~/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue';
let wrapper;
-async function factory(sourceBranchRemoved, mergeRequestWidgetGraphql) {
+function factory(sourceBranchRemoved) {
wrapper = shallowMount(MissingBranchComponent, {
propsData: {
mr: { sourceBranchRemoved },
},
- provide: {
- glFeatures: { mergeRequestWidgetGraphql },
+ data() {
+ return { state: { sourceBranchExists: !sourceBranchRemoved } };
},
});
-
- if (mergeRequestWidgetGraphql) {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ state: { sourceBranchExists: !sourceBranchRemoved } });
- }
-
- await nextTick();
}
describe('MRWidgetMissingBranch', () => {
@@ -28,22 +19,16 @@ describe('MRWidgetMissingBranch', () => {
wrapper.destroy();
});
- [true, false].forEach((mergeRequestWidgetGraphql) => {
- describe(`widget GraphQL feature flag is ${
- mergeRequestWidgetGraphql ? 'enabled' : 'disabled'
- }`, () => {
- it.each`
- sourceBranchRemoved | branchName
- ${true} | ${'source'}
- ${false} | ${'target'}
- `(
- 'should set missing branch name as $branchName when sourceBranchRemoved is $sourceBranchRemoved',
- async ({ sourceBranchRemoved, branchName }) => {
- await factory(sourceBranchRemoved, mergeRequestWidgetGraphql);
+ it.each`
+ sourceBranchRemoved | branchName
+ ${true} | ${'source'}
+ ${false} | ${'target'}
+ `(
+ 'should set missing branch name as $branchName when sourceBranchRemoved is $sourceBranchRemoved',
+ ({ sourceBranchRemoved, branchName }) => {
+ factory(sourceBranchRemoved);
- expect(wrapper.find('[data-testid="widget-content"]').text()).toContain(branchName);
- },
- );
- });
- });
+ expect(wrapper.find('[data-testid="widget-content"]').text()).toContain(branchName);
+ },
+ );
});
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_ready_to_merge_spec.js
index 48d3f15560b..407bd60b2b7 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_ready_to_merge_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_ready_to_merge_spec.js
@@ -60,6 +60,11 @@ const createTestMr = (customConfig) => {
translateStateToMachine: () => this.transitionStateMachine(),
state: 'open',
canMerge: true,
+ mergeable: true,
+ userPermissions: {
+ removeSourceBranch: true,
+ canMerge: true,
+ },
};
Object.assign(mr, customConfig.mr);
@@ -68,7 +73,7 @@ const createTestMr = (customConfig) => {
};
const createTestService = () => ({
- merge: jest.fn(),
+ merge: jest.fn().mockResolvedValue(),
poll: jest.fn().mockResolvedValue(),
});
@@ -87,21 +92,24 @@ const createReadyToMergeResponse = (customMr) => {
});
};
-const createComponent = (
- customConfig = {},
- mergeRequestWidgetGraphql = false,
- restructuredMrWidget = true,
-) => {
+const createComponent = (customConfig = {}, createState = true) => {
wrapper = shallowMount(ReadyToMerge, {
propsData: {
mr: createTestMr(customConfig),
service: createTestService(),
},
- provide: {
- glFeatures: {
- mergeRequestWidgetGraphql,
- restructuredMrWidget,
- },
+ data() {
+ if (createState) {
+ return {
+ loading: false,
+ state: {
+ ...createTestMr(customConfig),
+ },
+ };
+ }
+ return {
+ loading: true,
+ };
},
stubs: {
CommitEdit,
@@ -136,7 +144,7 @@ describe('ReadyToMerge', () => {
describe('computed', () => {
describe('isAutoMergeAvailable', () => {
it('should return true when at least one merge strategy is available', () => {
- createComponent();
+ createComponent({});
expect(wrapper.vm.isAutoMergeAvailable).toBe(true);
});
@@ -168,14 +176,14 @@ describe('ReadyToMerge', () => {
});
it('returns pending when pipeline is active', () => {
- createComponent({ mr: { pipeline: {}, isPipelineActive: true } });
+ createComponent({ mr: { pipeline: { active: true }, isPipelineActive: true } });
expect(wrapper.vm.status).toEqual('pending');
});
it('returns failed when pipeline is failed', () => {
createComponent({
- mr: { pipeline: {}, isPipelineFailed: true, availableAutoMergeStrategies: [] },
+ mr: { pipeline: { status: 'FAILED' }, availableAutoMergeStrategies: [], hasCI: true },
});
expect(wrapper.vm.status).toEqual('failed');
@@ -185,7 +193,7 @@ describe('ReadyToMerge', () => {
describe('Merge Button Variant', () => {
it('defaults to confirm class', () => {
createComponent({
- mr: { availableAutoMergeStrategies: [] },
+ mr: { availableAutoMergeStrategies: [], mergeable: true },
});
expect(findMergeButton().attributes('variant')).toBe('confirm');
@@ -194,19 +202,19 @@ describe('ReadyToMerge', () => {
describe('status icon', () => {
it('defaults to tick icon', () => {
- createComponent();
+ createComponent({ mr: { mergeable: true } });
expect(wrapper.vm.iconClass).toEqual('success');
});
it('shows tick for success status', () => {
- createComponent({ mr: { pipeline: true } });
+ createComponent({ mr: { pipeline: { status: 'SUCCESS' }, mergeable: true } });
expect(wrapper.vm.iconClass).toEqual('success');
});
it('shows tick for pending status', () => {
- createComponent({ mr: { pipeline: {}, isPipelineActive: true } });
+ createComponent({ mr: { pipeline: { active: true }, mergeable: true } });
expect(wrapper.vm.iconClass).toEqual('success');
});
@@ -266,7 +274,7 @@ describe('ReadyToMerge', () => {
describe('isMergeButtonDisabled', () => {
it('should return false with initial data', () => {
- createComponent({ mr: { isMergeAllowed: true } });
+ createComponent({ mr: { isMergeAllowed: true, mergeable: false } });
expect(wrapper.vm.isMergeButtonDisabled).toBe(false);
});
@@ -283,6 +291,7 @@ describe('ReadyToMerge', () => {
isMergeAllowed: false,
availableAutoMergeStrategies: [],
onlyAllowMergeIfPipelineSucceeds: true,
+ mergeable: false,
},
});
@@ -544,7 +553,15 @@ describe('ReadyToMerge', () => {
describe('Remove source branch checkbox', () => {
describe('when user can merge but cannot delete branch', () => {
it('should be disabled in the rendered output', () => {
- createComponent();
+ createComponent({
+ mr: {
+ mergeable: true,
+ userPermissions: {
+ removeSourceBranch: false,
+ canMerge: true,
+ },
+ },
+ });
expect(wrapper.find('#remove-source-branch-input').exists()).toBe(false);
});
@@ -553,7 +570,7 @@ describe('ReadyToMerge', () => {
describe('when user can merge and can delete branch', () => {
beforeEach(() => {
createComponent({
- mr: { canRemoveSourceBranch: true },
+ mr: { canRemoveSourceBranch: true, mergeable: true },
});
});
@@ -567,7 +584,7 @@ describe('ReadyToMerge', () => {
describe('squash checkbox', () => {
it('should be rendered when squash before merge is enabled and there is more than 1 commit', () => {
createComponent({
- mr: { commitsCount: 2, enableSquashBeforeMerge: true },
+ mr: { commitsCount: 2, enableSquashBeforeMerge: true, mergeable: true },
});
expect(findCheckboxElement().exists()).toBe(true);
@@ -665,6 +682,7 @@ describe('ReadyToMerge', () => {
squashIsSelected: true,
enableSquashBeforeMerge: true,
commitsCount: 2,
+ mergeRequestsFfOnlyEnabled: true,
},
});
@@ -795,7 +813,9 @@ describe('ReadyToMerge', () => {
});
it('shows the diverged commits text when the source branch is behind the target', () => {
- createComponent({ mr: { divergedCommitsCount: 9001, canMerge: false } });
+ createComponent({
+ mr: { divergedCommitsCount: 9001, userPermissions: { canMerge: false }, canMerge: false },
+ });
expect(wrapper.text()).toEqual(
expect.stringContaining('The source branch is 9001 commits behind the target branch'),
@@ -807,7 +827,7 @@ describe('ReadyToMerge', () => {
describe('Merge button when pipeline has failed', () => {
beforeEach(() => {
createComponent({
- mr: { pipeline: {}, isPipelineFailed: true, availableAutoMergeStrategies: [] },
+ mr: { headPipeline: { status: 'FAILED' }, availableAutoMergeStrategies: [], hasCI: true },
});
});
@@ -830,7 +850,7 @@ describe('ReadyToMerge', () => {
const USER_COMMIT_MESSAGE = 'Merge message provided manually by user';
const createDefaultGqlComponent = () =>
- createComponent({ mr: { commitsCount: 2, enableSquashBeforeMerge: true } }, true);
+ createComponent({ mr: { commitsCount: 2, enableSquashBeforeMerge: true } }, false);
beforeEach(() => {
readyToMergeResponseSpy = jest
diff --git a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_wip_spec.js b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_wip_spec.js
index 7259f210b6e..82aeac1a47d 100644
--- a/spec/frontend/vue_merge_request_widget/components/states/mr_widget_wip_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/states/mr_widget_wip_spec.js
@@ -1,101 +1,42 @@
-import Vue, { nextTick } from 'vue';
-import waitForPromises from 'helpers/wait_for_promises';
+import { mount } from '@vue/test-utils';
import WorkInProgress from '~/vue_merge_request_widget/components/states/work_in_progress.vue';
-import toast from '~/vue_shared/plugins/global_toast';
-import eventHub from '~/vue_merge_request_widget/event_hub';
-jest.mock('~/vue_shared/plugins/global_toast');
-
-const createComponent = () => {
- const Component = Vue.extend(WorkInProgress);
- const mr = {
- title: 'The best MR ever',
- removeWIPPath: '/path/to/remove/wip',
- };
- const service = {
- removeWIP() {},
- };
- return new Component({
- el: document.createElement('div'),
- propsData: { mr, service },
+let wrapper;
+
+const createComponent = (updateMergeRequest = true) => {
+ wrapper = mount(WorkInProgress, {
+ propsData: {
+ mr: {},
+ },
+ data() {
+ return {
+ userPermissions: {
+ updateMergeRequest,
+ },
+ };
+ },
});
};
-describe('Wip', () => {
- describe('props', () => {
- it('should have props', () => {
- const { mr, service } = WorkInProgress.props;
-
- expect(mr.type instanceof Object).toBe(true);
- expect(mr.required).toBe(true);
-
- expect(service.type instanceof Object).toBe(true);
- expect(service.required).toBe(true);
- });
- });
-
- describe('data', () => {
- it('should have default data', () => {
- const vm = createComponent();
-
- expect(vm.isMakingRequest).toBe(false);
- });
- });
-
- describe('methods', () => {
- const mrObj = {
- is_new_mr_data: true,
- };
-
- describe('handleRemoveDraft', () => {
- it('should make a request to service and handle response', async () => {
- const vm = createComponent();
-
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
- jest.spyOn(vm.service, 'removeWIP').mockReturnValue(
- new Promise((resolve) => {
- resolve({
- data: mrObj,
- });
- }),
- );
-
- vm.handleRemoveDraft();
-
- await waitForPromises();
-
- expect(vm.isMakingRequest).toBe(true);
- expect(eventHub.$emit).toHaveBeenCalledWith('UpdateWidgetData', mrObj);
- expect(toast).toHaveBeenCalledWith('Marked as ready. Merging is now allowed.');
- });
- });
+describe('Merge request widget draft state component', () => {
+ afterEach(() => {
+ wrapper.destroy();
});
describe('template', () => {
- let vm;
- let el;
-
- beforeEach(() => {
- vm = createComponent();
- el = vm.$el;
- });
-
it('should have correct elements', () => {
- expect(el.classList.contains('mr-widget-body')).toBe(true);
- expect(el.innerText).toContain(
+ createComponent(true);
+
+ expect(wrapper.text()).toContain(
"Merge blocked: merge request must be marked as ready. It's still marked as draft.",
);
- expect(el.querySelector('.js-remove-draft').innerText.replace(/\s\s+/g, ' ')).toContain(
- 'Mark as ready',
- );
+ expect(wrapper.find('[data-testid="removeWipButton"]').text()).toContain('Mark as ready');
});
- it('should not show removeWIP button is user cannot update MR', async () => {
- vm.mr.removeWIPPath = '';
-
- await nextTick();
+ it('should not show removeWIP button is user cannot update MR', () => {
+ createComponent(false);
- expect(el.querySelector('.js-remove-draft')).toBeNull();
+ expect(wrapper.find('[data-testid="removeWipButton"]').exists()).toBe(false);
});
});
});
diff --git a/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap b/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap
index 08424077269..e9a34453930 100644
--- a/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap
+++ b/spec/frontend/vue_merge_request_widget/components/widget/__snapshots__/dynamic_content_spec.js.snap
@@ -1,13 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`~/vue_merge_request_widget/components/widget/dynamic_content.vue renders given data 1`] = `
-"<content-row-stub level=\\"2\\" statusiconname=\\"success\\" widgetname=\\"MyWidget\\" header=\\"This is a header,This is a subheader\\">
+"<content-row-stub level=\\"2\\" statusiconname=\\"success\\" widgetname=\\"MyWidget\\" header=\\"This is a header,This is a subheader\\" helppopover=\\"[object Object]\\" actionbuttons=\\"\\">
<div class=\\"gl-display-flex gl-flex-direction-column\\">
<div>
<p class=\\"gl-mb-0\\">Main text for the row</p>
<gl-link-stub href=\\"https://gitlab.com\\">Optional link to display after text</gl-link-stub>
<!---->
- <gl-badge-stub size=\\"md\\" variant=\\"info\\">
+ <gl-badge-stub size=\\"md\\" variant=\\"info\\" iconsize=\\"md\\">
Badge is optional. Text to be displayed inside badge
</gl-badge-stub>
<actions-stub widget=\\"MyWidget\\" tertiarybuttons=\\"\\" class=\\"gl-ml-auto gl-pl-3\\"></actions-stub>
@@ -15,7 +15,7 @@ exports[`~/vue_merge_request_widget/components/widget/dynamic_content.vue render
</div>
<ul class=\\"gl-m-0 gl-p-0 gl-list-style-none\\">
<li>
- <content-row-stub level=\\"3\\" statusiconname=\\"\\" widgetname=\\"MyWidget\\" header=\\"Child row header\\" data-qa-selector=\\"child_content\\">
+ <content-row-stub level=\\"3\\" statusiconname=\\"\\" widgetname=\\"MyWidget\\" header=\\"Child row header\\" actionbuttons=\\"\\" data-qa-selector=\\"child_content\\">
<div class=\\"gl-display-flex gl-flex-direction-column\\">
<div>
<p class=\\"gl-mb-0\\">This is recursive. It will be listed in level 3.</p>
diff --git a/spec/frontend/vue_merge_request_widget/components/widget/dynamic_content_spec.js b/spec/frontend/vue_merge_request_widget/components/widget/dynamic_content_spec.js
index b7753a58747..527e800ddcf 100644
--- a/spec/frontend/vue_merge_request_widget/components/widget/dynamic_content_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/widget/dynamic_content_spec.js
@@ -25,6 +25,10 @@ describe('~/vue_merge_request_widget/components/widget/dynamic_content.vue', ()
header: ['This is a header', 'This is a subheader'],
text: 'Main text for the row',
subtext: 'Optional: Smaller sub-text to be displayed below the main text',
+ helpPopover: {
+ options: { title: 'Widget help popover title' },
+ content: { text: 'Widget help popover content' },
+ },
icon: {
name: EXTENSION_ICONS.success,
},
diff --git a/spec/frontend/vue_merge_request_widget/components/widget/widget_content_row_spec.js b/spec/frontend/vue_merge_request_widget/components/widget/widget_content_row_spec.js
index 9eddd091ad0..e4bee6b8652 100644
--- a/spec/frontend/vue_merge_request_widget/components/widget/widget_content_row_spec.js
+++ b/spec/frontend/vue_merge_request_widget/components/widget/widget_content_row_spec.js
@@ -1,11 +1,15 @@
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import WidgetContentRow from '~/vue_merge_request_widget/components/widget/widget_content_row.vue';
import StatusIcon from '~/vue_merge_request_widget/components/widget/status_icon.vue';
+import ActionButtons from '~/vue_merge_request_widget/components/action_buttons.vue';
+import HelpPopover from '~/vue_shared/components/help_popover.vue';
describe('~/vue_merge_request_widget/components/widget/widget_content_row.vue', () => {
let wrapper;
const findStatusIcon = () => wrapper.findComponent(StatusIcon);
+ const findHelpPopover = () => wrapper.findComponent(HelpPopover);
+ const findActionButtons = () => wrapper.findComponent(ActionButtons);
const createComponent = ({ propsData, slots } = {}) => {
wrapper = shallowMountExtended(WidgetContentRow, {
@@ -61,5 +65,38 @@ describe('~/vue_merge_request_widget/components/widget/widget_content_row.vue',
createComponent({ propsData: { header: '<b role="header">this is a header</b>' } });
expect(wrapper.findByText('<b role="header">this is a header</b>').exists()).toBe(true);
});
+
+ it('renders a help popover', () => {
+ createComponent({
+ propsData: {
+ helpPopover: {
+ options: { title: 'Help popover title' },
+ content: { text: 'Help popover content', learnMorePath: '/path/to/docs' },
+ },
+ },
+ });
+
+ expect(findHelpPopover().props('options')).toEqual({ title: 'Help popover title' });
+ expect(wrapper.findByText('Help popover content').exists()).toBe(true);
+ expect(wrapper.findByText('Learn more').attributes('href')).toBe('/path/to/docs');
+ expect(wrapper.findByText('Learn more').attributes('target')).toBe('_blank');
+ });
+
+ it('does not render help popover when it is not provided', () => {
+ createComponent({});
+ expect(findHelpPopover().exists()).toBe(false);
+ });
+
+ it('does not display action buttons if actionButtons is not provided', () => {
+ createComponent({});
+ expect(findActionButtons().exists()).toBe(false);
+ });
+
+ it('does display action buttons if actionButtons is provided', () => {
+ const actionButtons = [{ text: 'click-me', href: '#' }];
+
+ createComponent({ propsData: { actionButtons } });
+ expect(findActionButtons().props('tertiaryButtons')).toEqual(actionButtons);
+ });
});
});
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 4826fecf98d..9635e050e4d 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
@@ -1,12 +1,21 @@
import { nextTick } from 'vue';
import * as Sentry from '@sentry/browser';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import HelpPopover from '~/vue_shared/components/help_popover.vue';
import waitForPromises from 'helpers/wait_for_promises';
import StatusIcon from '~/vue_merge_request_widget/components/extensions/status_icon.vue';
import ActionButtons from '~/vue_merge_request_widget/components/action_buttons.vue';
import Widget from '~/vue_merge_request_widget/components/widget/widget.vue';
import WidgetContentRow from '~/vue_merge_request_widget/components/widget/widget_content_row.vue';
+jest.mock('~/vue_merge_request_widget/components/extensions/telemetry', () => ({
+ createTelemetryHub: jest.fn().mockReturnValue({
+ viewed: jest.fn(),
+ expanded: jest.fn(),
+ fullReportClicked: jest.fn(),
+ }),
+}));
+
describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
let wrapper;
@@ -14,13 +23,15 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
const findExpandedSection = () => wrapper.findByTestId('widget-extension-collapsed-section');
const findActionButtons = () => wrapper.findComponent(ActionButtons);
const findToggleButton = () => wrapper.findByTestId('toggle-button');
+ const findHelpPopover = () => wrapper.findComponent(HelpPopover);
const createComponent = ({ propsData, slots } = {}) => {
wrapper = shallowMountExtended(Widget, {
propsData: {
isCollapsible: false,
loadingText: 'Loading widget',
- widgetName: 'MyWidget',
+ widgetName: 'WidgetTest',
+ fetchCollapsedData: () => Promise.resolve([]),
value: {
collapsed: null,
expanded: null,
@@ -30,6 +41,7 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
slots,
stubs: {
StatusIcon,
+ ActionButtons,
ContentRow: WidgetContentRow,
},
});
@@ -52,8 +64,9 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
});
it('sets the error text when fetch method fails', async () => {
- const fetchCollapsedData = jest.fn().mockReturnValue(() => Promise.reject());
- createComponent({ propsData: { fetchCollapsedData } });
+ createComponent({
+ propsData: { fetchCollapsedData: jest.fn().mockRejectedValue('Something went wrong') },
+ });
await waitForPromises();
expect(wrapper.findByText('Failed to load').exists()).toBe(true);
expect(findStatusIcon().props()).toMatchObject({ iconName: 'failed', isLoading: false });
@@ -79,12 +92,24 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
});
it('displays the loading text', async () => {
- const fetchCollapsedData = jest.fn().mockReturnValue(() => Promise.reject());
- createComponent({ propsData: { fetchCollapsedData, statusIconName: 'warning' } });
+ createComponent({
+ propsData: {
+ statusIconName: 'warning',
+ },
+ });
+
expect(wrapper.text()).not.toContain('Loading');
await nextTick();
expect(wrapper.text()).toContain('Loading');
});
+
+ it('validates widget name', () => {
+ expect(() => {
+ createComponent({
+ propsData: { widgetName: 'InvalidWidgetName' },
+ });
+ }).toThrow();
+ });
});
describe('fetch', () => {
@@ -136,7 +161,6 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
createComponent({
propsData: {
summary: 'Hello world',
- fetchCollapsedData: () => Promise.resolve(),
},
});
@@ -145,28 +169,22 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
it.todo('displays content property when content slot is not provided');
- it('displays the summary slot when provided', () => {
+ it('displays the summary slot when provided', async () => {
createComponent({
- propsData: {
- fetchCollapsedData: () => Promise.resolve(),
- },
slots: {
summary: '<b>More complex summary</b>',
},
});
+ await waitForPromises();
+
expect(wrapper.findByTestId('widget-extension-top-level-summary').text()).toBe(
'More complex summary',
);
});
it('does not display action buttons if actionButtons is not provided', () => {
- createComponent({
- propsData: {
- fetchCollapsedData: () => Promise.resolve(),
- },
- });
-
+ createComponent();
expect(findActionButtons().exists()).toBe(false);
});
@@ -175,7 +193,6 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
createComponent({
propsData: {
- fetchCollapsedData: () => Promise.resolve(),
actionButtons,
},
});
@@ -184,12 +201,34 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
});
});
+ describe('help popover', () => {
+ it('renders a help popover', () => {
+ createComponent({
+ propsData: {
+ helpPopover: {
+ options: { title: 'My help popover title' },
+ content: { text: 'Help popover content', learnMorePath: '/path/to/docs' },
+ },
+ },
+ });
+
+ expect(findHelpPopover().props('options')).toEqual({ title: 'My help popover title' });
+ expect(wrapper.findByText('Help popover content').exists()).toBe(true);
+ expect(wrapper.findByText('Learn more').attributes('href')).toBe('/path/to/docs');
+ expect(wrapper.findByText('Learn more').attributes('target')).toBe('_blank');
+ });
+
+ it('does not render help popover when it is not provided', () => {
+ createComponent();
+ expect(findHelpPopover().exists()).toBe(false);
+ });
+ });
+
describe('handle collapse toggle', () => {
it('displays the toggle button correctly', () => {
createComponent({
propsData: {
isCollapsible: true,
- fetchCollapsedData: () => Promise.resolve(),
},
slots: {
content: '<b>More complex content</b>',
@@ -204,7 +243,6 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
createComponent({
propsData: {
isCollapsible: true,
- fetchCollapsedData: () => Promise.resolve(),
},
slots: {
content: '<b>More complex content</b>',
@@ -221,7 +259,6 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
createComponent({
propsData: {
isCollapsible: false,
- fetchCollapsedData: () => Promise.resolve(),
},
});
@@ -278,7 +315,6 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
createComponent({
propsData: {
isCollapsible: true,
- fetchCollapsedData: () => Promise.resolve([]),
fetchExpandedData,
},
});
@@ -306,7 +342,6 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
createComponent({
propsData: {
isCollapsible: true,
- fetchCollapsedData: () => Promise.resolve([]),
fetchExpandedData,
},
});
@@ -323,4 +358,54 @@ describe('~/vue_merge_request_widget/components/widget/widget.vue', () => {
expect(wrapper.findByText('Failed to load').exists()).toBe(false);
});
});
+
+ describe('telemetry - enabled', () => {
+ beforeEach(() => {
+ createComponent({
+ propsData: {
+ isCollapsible: true,
+ actionButtons: [
+ {
+ fullReport: true,
+ href: '#',
+ target: '_blank',
+ id: 'full-report-button',
+ text: 'Full Report',
+ },
+ ],
+ },
+ });
+ });
+
+ it('should call create a telemetry hub', () => {
+ expect(wrapper.vm.telemetryHub).not.toBe(null);
+ });
+
+ it('should call the viewed state', async () => {
+ await nextTick();
+ expect(wrapper.vm.telemetryHub.viewed).toHaveBeenCalledTimes(1);
+ });
+
+ it('when full report is clicked it should call the respective telemetry event', async () => {
+ expect(wrapper.vm.telemetryHub.fullReportClicked).not.toHaveBeenCalled();
+ wrapper.findByText('Full Report').vm.$emit('click');
+ await nextTick();
+ expect(wrapper.vm.telemetryHub.fullReportClicked).toHaveBeenCalledTimes(1);
+ });
+ });
+
+ describe('telemetry - disabled', () => {
+ beforeEach(() => {
+ createComponent({
+ propsData: {
+ isCollapsible: true,
+ telemetry: false,
+ },
+ });
+ });
+
+ it('should not call create a telemetry hub', () => {
+ expect(wrapper.vm.telemetryHub).toBe(null);
+ });
+ });
});
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 58dadb2c679..41df485b0de 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
@@ -23,11 +23,7 @@ import {
jest.mock('~/flash');
jest.mock('~/lib/utils/url_utility');
-jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal', () => {
- return {
- confirmAction: jest.fn(),
- };
-});
+jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
describe('DeploymentAction component', () => {
let wrapper;
diff --git a/spec/frontend/vue_merge_request_widget/deployment/deployment_info_spec.js b/spec/frontend/vue_merge_request_widget/deployment/deployment_info_spec.js
new file mode 100644
index 00000000000..c6b73f63301
--- /dev/null
+++ b/spec/frontend/vue_merge_request_widget/deployment/deployment_info_spec.js
@@ -0,0 +1,42 @@
+import { mount } from '@vue/test-utils';
+import { GlTruncate, GlLink } from '@gitlab/ui';
+import DeploymentInfo from '~/vue_merge_request_widget/components/deployment/deployment_info.vue';
+import { deploymentMockData } from './deployment_mock_data';
+
+// This component is well covered in ./deployment_spec.js
+// more component-specific tests are added below
+describe('Deployment Info component', () => {
+ let wrapper;
+
+ const defaultDeploymentInfoOptions = {
+ computedDeploymentStatus: 'computed deployment status',
+ deployment: deploymentMockData,
+ showMetrics: false,
+ };
+
+ const factory = (options = {}) => {
+ const componentProps = { ...defaultDeploymentInfoOptions, ...options };
+ const componentOptions = { propsData: componentProps };
+ wrapper = mount(DeploymentInfo, componentOptions);
+ };
+
+ beforeEach(() => {
+ factory();
+ });
+
+ it('should render gl-truncate for environment name', () => {
+ const envNameComponent = wrapper.findComponent(GlTruncate);
+ expect(envNameComponent.exists()).toBe(true, 'We should use gl-truncate for environment name');
+ expect(envNameComponent.props()).toEqual({
+ text: deploymentMockData.name,
+ withTooltip: true,
+ position: 'middle',
+ });
+ });
+
+ it('should have a link with a correct href to deployed environment', () => {
+ const envLink = wrapper.findComponent(GlLink);
+ expect(envLink.exists()).toBe(true, 'We should have gl-link pointing to deployed environment');
+ expect(envLink.attributes().href).toBe(deploymentMockData.url);
+ });
+});
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 6622749da92..0f4637d18d9 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
@@ -4,6 +4,8 @@ import MockAdapter from 'axios-mock-adapter';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import * as Sentry from '@sentry/browser';
+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';
import waitForPromises from 'helpers/wait_for_promises';
import { securityReportMergeRequestDownloadPathsQueryResponse } from 'jest/vue_shared/security_reports/mock_data';
@@ -22,6 +24,10 @@ import eventHub from '~/vue_merge_request_widget/event_hub';
import MrWidgetOptions from '~/vue_merge_request_widget/mr_widget_options.vue';
import StatusIcon from '~/vue_merge_request_widget/components/extensions/status_icon.vue';
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 userPermissionsQuery from '~/vue_merge_request_widget/queries/permissions.query.graphql';
+import conflictsStateQuery from '~/vue_merge_request_widget/queries/states/conflicts.query.graphql';
import { faviconDataUrl, overlayDataUrl } from '../lib/utils/mock_data';
import mockData from './mock_data';
import {
@@ -83,7 +89,39 @@ describe('MrWidgetOptions', () => {
propsData: {
mrData: { ...mrData },
},
+ data() {
+ return { loading: false };
+ },
+
...options,
+ apolloProvider: createMockApollo([
+ [
+ getStateQuery,
+ jest.fn().mockResolvedValue({
+ data: {
+ project: {
+ ...getStateQueryResponse.data.project,
+ mergeRequest: {
+ ...getStateQueryResponse.data.project.mergeRequest,
+ mergeError: mrData.mergeError || null,
+ },
+ },
+ },
+ }),
+ ],
+ [readyToMergeQuery, jest.fn().mockResolvedValue(readyToMergeResponse)],
+ [
+ userPermissionsQuery,
+ jest.fn().mockResolvedValue({
+ data: { project: { mergeRequest: { userPermissions: {} } } },
+ }),
+ ],
+ [
+ conflictsStateQuery,
+ jest.fn().mockResolvedValue({ data: { project: { mergeRequest: {} } } }),
+ ],
+ ...(options.apolloMock || []),
+ ]),
});
return axios.waitForAll();
@@ -563,21 +601,6 @@ describe('MrWidgetOptions', () => {
});
});
- describe('code quality widget', () => {
- beforeEach(() => {
- jest.spyOn(document, 'dispatchEvent');
- });
- it('renders the component when refactorCodeQualityExtension is false', () => {
- createComponent(mockData, {}, { refactorCodeQualityExtension: false });
- expect(wrapper.find('.js-codequality-widget').exists()).toBe(true);
- });
-
- it('does not render the component when refactorCodeQualityExtension is true', () => {
- createComponent(mockData, {}, { refactorCodeQualityExtension: true });
- expect(wrapper.find('.js-codequality-widget').exists()).toBe(true);
- });
- });
-
describe('pipeline for target branch after merge', () => {
describe('with information for target branch pipeline', () => {
beforeEach(() => {
@@ -784,12 +807,12 @@ describe('MrWidgetOptions', () => {
mock.onGet(mockData.merge_request_cached_widget_path).reply(() => [200, mrData]);
return createComponent(mrData, {
- apolloProvider: createMockApollo([
+ apolloMock: [
[
securityReportMergeRequestDownloadPathsQuery,
async () => ({ data: securityReportMergeRequestDownloadPathsQueryResponse }),
],
- ]),
+ ],
});
};
@@ -852,8 +875,10 @@ describe('MrWidgetOptions', () => {
${'closed'} | ${false} | ${'hides'}
${'merged'} | ${true} | ${'shows'}
${'open'} | ${true} | ${'shows'}
- `('$showText merge error when state is $state', ({ state, show }) => {
- createComponent({ ...mockData, state, merge_error: 'Error!' });
+ `('$showText merge error when state is $state', async ({ state, show }) => {
+ createComponent({ ...mockData, state, mergeError: 'Error!' });
+
+ await waitForPromises();
expect(wrapper.find('[data-testid="merge_error"]').exists()).toBe(show);
});
@@ -917,8 +942,7 @@ describe('MrWidgetOptions', () => {
});
it('extension polling is not called if enablePolling flag is not passed', () => {
- // called one time due to parent component polling (mount)
- expect(pollRequest).toHaveBeenCalledTimes(1);
+ expect(pollRequest).toHaveBeenCalledTimes(0);
});
});
@@ -1004,7 +1028,7 @@ describe('MrWidgetOptions', () => {
await createComponent();
- expect(pollRequest).toHaveBeenCalledTimes(2);
+ expect(pollRequest).toHaveBeenCalledTimes(1);
});
});
@@ -1042,7 +1066,7 @@ describe('MrWidgetOptions', () => {
registerExtension(pollingErrorExtension);
await createComponent();
- expect(pollRequest).toHaveBeenCalledTimes(2);
+ expect(pollRequest).toHaveBeenCalledTimes(1);
});
it('captures sentry error and displays error when poll has failed', async () => {
@@ -1085,7 +1109,7 @@ describe('MrWidgetOptions', () => {
await nextTick();
await waitForPromises();
- expect(Sentry.captureException).toHaveBeenCalledTimes(1);
+ expect(Sentry.captureException).toHaveBeenCalledTimes(2);
expect(Sentry.captureException).toHaveBeenCalledWith(new Error('Fetch error'));
expect(wrapper.findComponent(StatusIcon).props('iconName')).toBe('failed');
});
diff --git a/spec/frontend/vue_merge_request_widget/stores/mr_widget_store_spec.js b/spec/frontend/vue_merge_request_widget/stores/mr_widget_store_spec.js
index 3cdb4265ef0..37df041210c 100644
--- a/spec/frontend/vue_merge_request_widget/stores/mr_widget_store_spec.js
+++ b/spec/frontend/vue_merge_request_widget/stores/mr_widget_store_spec.js
@@ -21,22 +21,9 @@ describe('MergeRequestStore', () => {
});
describe('setData', () => {
- it('should set isSHAMismatch when the diff SHA changes', () => {
- store.setData({ ...mockData, diff_head_sha: 'a-different-string' });
-
- expect(store.isSHAMismatch).toBe(true);
- });
-
- it('should not set isSHAMismatch when other data changes', () => {
- store.setData({ ...mockData, work_in_progress: !mockData.work_in_progress });
-
- expect(store.isSHAMismatch).toBe(false);
- });
-
it('should update cached sha after rebasing', () => {
store.setData({ ...mockData, diff_head_sha: 'abc123' }, true);
- expect(store.isSHAMismatch).toBe(false);
expect(store.sha).toBe('abc123');
});
diff --git a/spec/frontend/vue_shared/alert_details/alert_details_spec.js b/spec/frontend/vue_shared/alert_details/alert_details_spec.js
index d309432bc63..3bc191d988f 100644
--- a/spec/frontend/vue_shared/alert_details/alert_details_spec.js
+++ b/spec/frontend/vue_shared/alert_details/alert_details_spec.js
@@ -30,7 +30,7 @@ describe('AlertDetails', () => {
const projectPath = 'root/alerts';
const projectIssuesPath = 'root/alerts/-/issues';
const projectId = '1';
- const $router = { replace: jest.fn() };
+ const $router = { push: jest.fn() };
function mountComponent({
data,
@@ -352,7 +352,7 @@ describe('AlertDetails', () => {
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ currentTabIndex: index });
- expect($router.replace).toHaveBeenCalledWith({ name: 'tab', params: { tabId } });
+ expect($router.push).toHaveBeenCalledWith({ name: 'tab', params: { tabId } });
});
});
});
diff --git a/spec/frontend/vue_shared/alert_details/router_spec.js b/spec/frontend/vue_shared/alert_details/router_spec.js
new file mode 100644
index 00000000000..e3efc104862
--- /dev/null
+++ b/spec/frontend/vue_shared/alert_details/router_spec.js
@@ -0,0 +1,35 @@
+import createRouter from '~/vue_shared/alert_details/router';
+import setWindowLocation from 'helpers/set_window_location_helper';
+
+const BASE_PATH = '/-/alert_management/1/details';
+const EMPTY_HASH = '';
+const NOOP = () => {};
+
+describe('AlertDetails router', () => {
+ const originalLocation = window.location.href;
+ let router;
+
+ beforeEach(() => {
+ setWindowLocation(originalLocation);
+ router = createRouter(BASE_PATH);
+ });
+
+ describe('redirects hash route mode URLs to history route mode', () => {
+ it.each`
+ hashPath | historyPath
+ ${'/#/overview'} | ${'/overview'}
+ ${'#/overview'} | ${'/overview'}
+ ${'/#/'} | ${'/'}
+ ${'#/'} | ${'/'}
+ ${'/#'} | ${'/'}
+ ${'#'} | ${'/'}
+ ${'/'} | ${'/'}
+ ${'/overview'} | ${'/overview'}
+ `('should redirect "$hashPath" to "$historyPath"', ({ hashPath, historyPath }) => {
+ router.push(hashPath, NOOP);
+
+ expect(window.location.hash).toBe(EMPTY_HASH);
+ expect(window.location.pathname).toBe(BASE_PATH + historyPath);
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/file_row_spec.js b/spec/frontend/vue_shared/components/file_row_spec.js
index f5a545891d5..c3a71d7fda3 100644
--- a/spec/frontend/vue_shared/components/file_row_spec.js
+++ b/spec/frontend/vue_shared/components/file_row_spec.js
@@ -106,7 +106,7 @@ describe('File row component', () => {
level: 2,
});
- expect(wrapper.find('.file-row-name').element.style.marginLeft).toBe('32px');
+ expect(wrapper.find('.file-row-name').element.style.marginLeft).toBe('16px');
});
it('renders header for file', () => {
diff --git a/spec/frontend/vue_shared/components/gitlab_version_check_spec.js b/spec/frontend/vue_shared/components/gitlab_version_check_spec.js
deleted file mode 100644
index 38f28837cc1..00000000000
--- a/spec/frontend/vue_shared/components/gitlab_version_check_spec.js
+++ /dev/null
@@ -1,135 +0,0 @@
-import { GlBadge } from '@gitlab/ui';
-import MockAdapter from 'axios-mock-adapter';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import waitForPromises from 'helpers/wait_for_promises';
-import { mockTracking } from 'helpers/tracking_helper';
-import { helpPagePath } from '~/helpers/help_page_helper';
-import axios from '~/lib/utils/axios_utils';
-import GitlabVersionCheck from '~/vue_shared/components/gitlab_version_check.vue';
-
-describe('GitlabVersionCheck', () => {
- let wrapper;
- let mock;
-
- const UPGRADE_DOCS_URL = helpPagePath('update/index');
-
- const defaultResponse = {
- code: 200,
- res: { severity: 'success' },
- };
-
- const createComponent = (mockResponse) => {
- const response = {
- ...defaultResponse,
- ...mockResponse,
- };
-
- mock = new MockAdapter(axios);
- mock.onGet().replyOnce(response.code, response.res);
-
- wrapper = shallowMountExtended(GitlabVersionCheck);
- };
-
- const dummyGon = {
- relative_url_root: '/',
- };
-
- let originalGon;
-
- afterEach(() => {
- wrapper.destroy();
- mock.restore();
- window.gon = originalGon;
- });
-
- const findGlBadgeClickWrapper = () => wrapper.findByTestId('badge-click-wrapper');
- const findGlBadge = () => wrapper.findComponent(GlBadge);
-
- describe.each`
- root | description
- ${'/'} | ${'not used (uses its own (sub)domain)'}
- ${'/gitlab'} | ${'custom path'}
- ${'/service/gitlab'} | ${'custom path with 2 depth'}
- `('path for version_check.json', ({ root, description }) => {
- describe(`when relative url is ${description}: ${root}`, () => {
- beforeEach(async () => {
- originalGon = window.gon;
- window.gon = { ...dummyGon };
- window.gon.relative_url_root = root;
- createComponent(defaultResponse);
- await waitForPromises(); // Ensure we wrap up the axios call
- });
-
- it('reflects the relative url setting', () => {
- expect(mock.history.get.length).toBe(1);
-
- const pathRegex = new RegExp(`^${root}`);
- expect(mock.history.get[0].url).toMatch(pathRegex);
- });
- });
- });
-
- describe('template', () => {
- describe.each`
- description | mockResponse | renders
- ${'successful but null'} | ${{ code: 200, res: null }} | ${false}
- ${'successful and valid'} | ${{ code: 200, res: { severity: 'success' } }} | ${true}
- ${'an error'} | ${{ code: 500, res: null }} | ${false}
- `('version_check.json response', ({ description, mockResponse, renders }) => {
- describe(`is ${description}`, () => {
- beforeEach(async () => {
- createComponent(mockResponse);
- await waitForPromises(); // Ensure we wrap up the axios call
- });
-
- it(`does${renders ? '' : ' not'} render Badge Click Wrapper and GlBadge`, () => {
- expect(findGlBadgeClickWrapper().exists()).toBe(renders);
- expect(findGlBadge().exists()).toBe(renders);
- });
- });
- });
-
- describe.each`
- mockResponse | expectedUI
- ${{ code: 200, res: { severity: 'success' } }} | ${{ title: 'Up to date', variant: 'success' }}
- ${{ code: 200, res: { severity: 'warning' } }} | ${{ title: 'Update available', variant: 'warning' }}
- ${{ code: 200, res: { severity: 'danger' } }} | ${{ title: 'Update ASAP', variant: 'danger' }}
- `('badge ui', ({ mockResponse, expectedUI }) => {
- describe(`when response is ${mockResponse.res.severity}`, () => {
- let trackingSpy;
-
- beforeEach(async () => {
- createComponent(mockResponse);
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- await waitForPromises(); // Ensure we wrap up the axios call
- });
-
- it(`title is ${expectedUI.title}`, () => {
- expect(findGlBadge().text()).toBe(expectedUI.title);
- });
-
- it(`variant is ${expectedUI.variant}`, () => {
- expect(findGlBadge().attributes('variant')).toBe(expectedUI.variant);
- });
-
- it(`tracks rendered_version_badge with label ${expectedUI.title}`, () => {
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'rendered_version_badge', {
- label: expectedUI.title,
- });
- });
-
- it(`link is ${UPGRADE_DOCS_URL}`, () => {
- expect(findGlBadge().attributes('href')).toBe(UPGRADE_DOCS_URL);
- });
-
- it(`tracks click_version_badge with label ${expectedUI.title} when badge is clicked`, async () => {
- await findGlBadgeClickWrapper().trigger('click');
-
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_version_badge', {
- label: expectedUI.title,
- });
- });
- });
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/group_select/group_select_spec.js b/spec/frontend/vue_shared/components/group_select/group_select_spec.js
new file mode 100644
index 00000000000..f959d2225fa
--- /dev/null
+++ b/spec/frontend/vue_shared/components/group_select/group_select_spec.js
@@ -0,0 +1,202 @@
+import { nextTick } from 'vue';
+import { GlListbox } from '@gitlab/ui';
+import MockAdapter from 'axios-mock-adapter';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import axios from '~/lib/utils/axios_utils';
+import { createAlert } from '~/flash';
+import GroupSelect from '~/vue_shared/components/group_select/group_select.vue';
+import {
+ TOGGLE_TEXT,
+ FETCH_GROUPS_ERROR,
+ FETCH_GROUP_ERROR,
+ QUERY_TOO_SHORT_MESSAGE,
+} from '~/vue_shared/components/group_select/constants';
+import waitForPromises from 'helpers/wait_for_promises';
+
+jest.mock('~/flash');
+
+describe('GroupSelect', () => {
+ let wrapper;
+ let mock;
+
+ // Mocks
+ const groupMock = {
+ full_name: 'selectedGroup',
+ id: '1',
+ };
+ const groupEndpoint = `/api/undefined/groups/${groupMock.id}`;
+
+ // Props
+ const inputName = 'inputName';
+ const inputId = 'inputId';
+
+ // Finders
+ const findListbox = () => wrapper.findComponent(GlListbox);
+ const findInput = () => wrapper.findByTestId('input');
+
+ // Helpers
+ const createComponent = ({ props = {} } = {}) => {
+ wrapper = shallowMountExtended(GroupSelect, {
+ propsData: {
+ inputName,
+ inputId,
+ ...props,
+ },
+ });
+ };
+ const openListbox = () => findListbox().vm.$emit('shown');
+ const search = (searchString) => findListbox().vm.$emit('search', searchString);
+ const createComponentWithGroups = () => {
+ mock.onGet('/api/undefined/groups.json').reply(200, [groupMock]);
+ createComponent();
+ openListbox();
+ return waitForPromises();
+ };
+ const selectGroup = () => {
+ findListbox().vm.$emit('select', groupMock.id);
+ return nextTick();
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('on mount', () => {
+ it('fetches groups when the listbox is opened', async () => {
+ createComponent();
+ await waitForPromises();
+
+ expect(mock.history.get).toHaveLength(0);
+
+ openListbox();
+ await waitForPromises();
+
+ expect(mock.history.get).toHaveLength(1);
+ });
+
+ describe('with an initial selection', () => {
+ it('if the selected group is not part of the fetched list, fetches it individually', async () => {
+ mock.onGet(groupEndpoint).reply(200, groupMock);
+ createComponent({ props: { initialSelection: groupMock.id } });
+ await waitForPromises();
+
+ expect(mock.history.get).toHaveLength(1);
+ expect(findListbox().props('toggleText')).toBe(groupMock.full_name);
+ });
+
+ it('show an error if fetching the individual group fails', async () => {
+ mock
+ .onGet('/api/undefined/groups.json')
+ .reply(200, [{ full_name: 'notTheSelectedGroup', id: '2' }]);
+ mock.onGet(groupEndpoint).reply(500);
+ createComponent({ props: { initialSelection: groupMock.id } });
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: FETCH_GROUP_ERROR,
+ error: expect.any(Error),
+ parent: wrapper.vm.$el,
+ });
+ });
+ });
+ });
+
+ it('shows an error when fetching groups fails', async () => {
+ mock.onGet('/api/undefined/groups.json').reply(500);
+ createComponent();
+ openListbox();
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: FETCH_GROUPS_ERROR,
+ error: expect.any(Error),
+ parent: wrapper.vm.$el,
+ });
+ });
+
+ describe('selection', () => {
+ it('uses the default toggle text while no group is selected', async () => {
+ await createComponentWithGroups();
+
+ expect(findListbox().props('toggleText')).toBe(TOGGLE_TEXT);
+ });
+
+ describe('once a group is selected', () => {
+ it(`uses the selected group's name as the toggle text`, async () => {
+ await createComponentWithGroups();
+ await selectGroup();
+
+ expect(findListbox().props('toggleText')).toBe(groupMock.full_name);
+ });
+
+ it(`uses the selected group's ID as the listbox' and input value`, async () => {
+ await createComponentWithGroups();
+ await selectGroup();
+
+ expect(findListbox().attributes('selected')).toBe(groupMock.id);
+ expect(findInput().attributes('value')).toBe(groupMock.id);
+ });
+
+ it(`on reset, falls back to the default toggle text`, async () => {
+ await createComponentWithGroups();
+ await selectGroup();
+
+ findListbox().vm.$emit('reset');
+ await nextTick();
+
+ expect(findListbox().props('toggleText')).toBe(TOGGLE_TEXT);
+ });
+ });
+ });
+
+ describe('search', () => {
+ it('sets `searching` to `true` when first opening the dropdown', async () => {
+ createComponent();
+
+ expect(findListbox().props('searching')).toBe(false);
+
+ openListbox();
+ await nextTick();
+
+ expect(findListbox().props('searching')).toBe(true);
+ });
+
+ it('sets `searching` to `true` while searching', async () => {
+ await createComponentWithGroups();
+
+ expect(findListbox().props('searching')).toBe(false);
+
+ search('foo');
+ await nextTick();
+
+ expect(findListbox().props('searching')).toBe(true);
+ });
+
+ it('fetches groups matching the search string', async () => {
+ const searchString = 'searchString';
+ await createComponentWithGroups();
+
+ expect(mock.history.get).toHaveLength(1);
+
+ search(searchString);
+ await waitForPromises();
+
+ expect(mock.history.get).toHaveLength(2);
+ expect(mock.history.get[1].params).toStrictEqual({ search: searchString });
+ });
+
+ it('shows a notice if the search query is too short', async () => {
+ const searchString = 'a';
+ await createComponentWithGroups();
+ search(searchString);
+ await waitForPromises();
+
+ expect(mock.history.get).toHaveLength(1);
+ expect(findListbox().props('noResultsText')).toBe(QUERY_TOO_SHORT_MESSAGE);
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/help_popover_spec.js b/spec/frontend/vue_shared/components/help_popover_spec.js
index 6fd5ae0e946..77c03dc0c3c 100644
--- a/spec/frontend/vue_shared/components/help_popover_spec.js
+++ b/spec/frontend/vue_shared/components/help_popover_spec.js
@@ -96,6 +96,20 @@ describe('HelpPopover', () => {
});
});
+ describe('with alternative icon', () => {
+ beforeEach(() => {
+ createComponent({
+ props: {
+ icon: 'information-o',
+ },
+ });
+ });
+
+ it('uses the given icon', () => {
+ expect(findQuestionButton().props('icon')).toBe('information-o');
+ });
+ });
+
describe('with custom slots', () => {
const titleSlot = '<h1>title</h1>';
const defaultSlot = '<strong>content</strong>';
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 f7e93f45148..625e67c7cc1 100644
--- a/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
+++ b/spec/frontend/vue_shared/components/markdown/markdown_editor_spec.js
@@ -27,7 +27,7 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
const formFieldAriaLabel = 'Edit your content';
let mock;
- const buildWrapper = ({ propsData = {}, attachTo } = {}) => {
+ const buildWrapper = ({ propsData = {}, attachTo, stubs = {} } = {}) => {
wrapper = mountExtended(MarkdownEditor, {
attachTo,
propsData: {
@@ -45,6 +45,7 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
},
stubs: {
BubbleMenu: stubComponent(BubbleMenu),
+ ...stubs,
},
});
};
@@ -138,9 +139,9 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
expect(wrapper.emitted('input')).toEqual([[newValue]]);
});
- describe('when initOnAutofocus is true', () => {
+ describe('when autofocus is true', () => {
beforeEach(async () => {
- buildWrapper({ attachTo: document.body, propsData: { initOnAutofocus: true } });
+ buildWrapper({ attachTo: document.body, propsData: { autofocus: true } });
await nextTick();
});
@@ -171,7 +172,6 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
renderMarkdown: expect.any(Function),
uploadsPath: window.uploads_path,
markdown: value,
- autofocus: 'end',
}),
);
});
@@ -204,10 +204,12 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
findSegmentedControl().vm.$emit('input', EDITING_MODE_CONTENT_EDITOR);
});
- describe('when initOnAutofocus is true', () => {
+ describe('when autofocus is true', () => {
beforeEach(() => {
- buildWrapper({ propsData: { initOnAutofocus: true } });
- findLocalStorageSync().vm.$emit('input', EDITING_MODE_CONTENT_EDITOR);
+ buildWrapper({
+ propsData: { autofocus: true },
+ stubs: { ContentEditor: stubComponent(ContentEditor) },
+ });
});
it('sets the content editor autofocus property to end', () => {
@@ -247,19 +249,6 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
it('updates localStorage value', () => {
expect(findLocalStorageSync().props().value).toBe(EDITING_MODE_MARKDOWN_FIELD);
});
-
- it('sets the textarea as the activeElement in the document', async () => {
- // The component should be rebuilt to attach it to the document body
- buildWrapper({ attachTo: document.body });
- await findSegmentedControl().vm.$emit('input', EDITING_MODE_CONTENT_EDITOR);
-
- expect(findContentEditor().exists()).toBe(true);
-
- await findSegmentedControl().vm.$emit('input', EDITING_MODE_MARKDOWN_FIELD);
- await findSegmentedControl().vm.$emit('change', EDITING_MODE_MARKDOWN_FIELD);
-
- expect(document.activeElement).toBe(findTextarea().element);
- });
});
describe('when content editor emits loading event', () => {
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
new file mode 100644
index 00000000000..8edcb905096
--- /dev/null
+++ b/spec/frontend/vue_shared/components/markdown_drawer/markdown_drawer_spec.js
@@ -0,0 +1,205 @@
+import { GlDrawer, GlAlert, GlSkeletonLoader } from '@gitlab/ui';
+import { nextTick } from 'vue';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import MarkdownDrawer, { cache } from '~/vue_shared/components/markdown_drawer/markdown_drawer.vue';
+import { getRenderedMarkdown } from '~/vue_shared/components/markdown_drawer/utils/fetch';
+import { contentTop } from '~/lib/utils/common_utils';
+
+jest.mock('~/vue_shared/components/markdown_drawer/utils/fetch', () => ({
+ getRenderedMarkdown: jest.fn().mockReturnValue({
+ title: 'test title test',
+ body: `<div id="content-body">
+ <div class="documentation md gl-mt-3">
+ test body
+ </div>
+ </div>`,
+ }),
+}));
+
+jest.mock('~/lib/utils/common_utils', () => ({
+ contentTop: jest.fn(),
+}));
+
+describe('MarkdownDrawer', () => {
+ let wrapper;
+ const defaultProps = {
+ documentPath: 'user/search/global_search/advanced_search_syntax.json',
+ };
+
+ const createComponent = (props) => {
+ wrapper = shallowMountExtended(MarkdownDrawer, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ Object.keys(cache).forEach((key) => delete cache[key]);
+ });
+
+ const findDrawer = () => wrapper.findComponent(GlDrawer);
+ const findAlert = () => wrapper.findComponent(GlAlert);
+ const findSkeleton = () => wrapper.findComponent(GlSkeletonLoader);
+ const findDrawerTitle = () => wrapper.findComponent('[data-testid="title-element"]');
+ const findDrawerBody = () => wrapper.findComponent({ ref: 'content-element' });
+
+ describe('component', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders correctly', () => {
+ expect(findDrawer().exists()).toBe(true);
+ expect(findDrawerTitle().text()).toBe('test title test');
+ expect(findDrawerBody().text()).toBe('test body');
+ });
+ });
+
+ describe.each`
+ hasNavbar | navbarHeight
+ ${false} | ${0}
+ ${true} | ${100}
+ `('computes offsetTop', ({ hasNavbar, navbarHeight }) => {
+ beforeEach(() => {
+ global.document.querySelector = jest.fn(() =>
+ hasNavbar
+ ? {
+ dataset: {
+ page: 'test',
+ },
+ }
+ : undefined,
+ );
+ contentTop.mockReturnValue(navbarHeight);
+ createComponent();
+ });
+
+ afterEach(() => {
+ contentTop.mockClear();
+ });
+
+ it(`computes offsetTop ${hasNavbar ? 'with' : 'without'} .navbar-gitlab`, () => {
+ expect(findDrawer().attributes('headerheight')).toBe(`${navbarHeight}px`);
+ });
+ });
+
+ describe('watcher', () => {
+ let renderGLFMSpy;
+ let fetchMarkdownSpy;
+
+ beforeEach(async () => {
+ renderGLFMSpy = jest.spyOn(MarkdownDrawer.methods, 'renderGLFM');
+ fetchMarkdownSpy = jest.spyOn(MarkdownDrawer.methods, 'fetchMarkdown');
+ global.document.querySelector = jest.fn(() => ({
+ getBoundingClientRect: jest.fn(() => ({ bottom: 100 })),
+ dataset: {
+ page: 'test',
+ },
+ }));
+ createComponent();
+ await nextTick();
+ });
+
+ afterEach(() => {
+ renderGLFMSpy.mockClear();
+ fetchMarkdownSpy.mockClear();
+ });
+
+ it('for documentPath triggers fetch', async () => {
+ expect(fetchMarkdownSpy).toHaveBeenCalledTimes(1);
+
+ await wrapper.setProps({ documentPath: '/test/me' });
+ await nextTick();
+
+ expect(fetchMarkdownSpy).toHaveBeenCalledTimes(2);
+ });
+
+ it('for open triggers renderGLFM', async () => {
+ wrapper.vm.fetchMarkdown();
+ wrapper.vm.openDrawer();
+ await nextTick();
+ expect(renderGLFMSpy).toHaveBeenCalled();
+ });
+ });
+
+ describe('Markdown fetching', () => {
+ let renderGLFMSpy;
+
+ beforeEach(async () => {
+ renderGLFMSpy = jest.spyOn(MarkdownDrawer.methods, 'renderGLFM');
+ createComponent();
+ await nextTick();
+ });
+
+ afterEach(() => {
+ renderGLFMSpy.mockClear();
+ });
+
+ it('fetches the Markdown and caches it', async () => {
+ expect(getRenderedMarkdown).toHaveBeenCalledTimes(1);
+ expect(Object.keys(cache)).toHaveLength(1);
+ });
+
+ it('when the document changes, fetches it and caches it as well', async () => {
+ expect(getRenderedMarkdown).toHaveBeenCalledTimes(1);
+ expect(Object.keys(cache)).toHaveLength(1);
+
+ await wrapper.setProps({ documentPath: '/test/me2' });
+ await nextTick();
+
+ expect(getRenderedMarkdown).toHaveBeenCalledTimes(2);
+ expect(Object.keys(cache)).toHaveLength(2);
+ });
+
+ it('when re-using an already fetched document, gets it from the cache', async () => {
+ await wrapper.setProps({ documentPath: '/test/me2' });
+ await nextTick();
+
+ expect(getRenderedMarkdown).toHaveBeenCalledTimes(2);
+ expect(Object.keys(cache)).toHaveLength(2);
+
+ await wrapper.setProps({ documentPath: defaultProps.documentPath });
+ await nextTick();
+
+ expect(getRenderedMarkdown).toHaveBeenCalledTimes(2);
+ expect(Object.keys(cache)).toHaveLength(2);
+ });
+ });
+
+ describe('Markdown fetching returns error', () => {
+ beforeEach(async () => {
+ getRenderedMarkdown.mockReturnValue({
+ hasFetchError: true,
+ });
+
+ createComponent();
+ await nextTick();
+ });
+ afterEach(() => {
+ getRenderedMarkdown.mockClear();
+ });
+ it('shows alert', () => {
+ expect(findAlert().exists()).toBe(true);
+ });
+ });
+
+ describe('While Markdown is fetching', () => {
+ beforeEach(async () => {
+ getRenderedMarkdown.mockReturnValue(new Promise(() => {}));
+
+ createComponent();
+ });
+
+ afterEach(() => {
+ getRenderedMarkdown.mockClear();
+ });
+
+ it('shows skeleton', async () => {
+ expect(findSkeleton().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/markdown_drawer/mock_data.js b/spec/frontend/vue_shared/components/markdown_drawer/mock_data.js
new file mode 100644
index 00000000000..53b40407556
--- /dev/null
+++ b/spec/frontend/vue_shared/components/markdown_drawer/mock_data.js
@@ -0,0 +1,42 @@
+export const MOCK_HTML = `<!DOCTYPE html>
+<html>
+<body>
+ <div id="content-body">
+ <h1>test title <strong>test</strong></h1>
+ <div class="documentation md gl-mt-3">
+ <a href="../advanced_search.md">Advanced Search</a>
+ <a href="../advanced_search2.md">Advanced Search2</a>
+ <h2>test header h2</h2>
+ <table class="testClass">
+ <tr>
+ <td>Emil</td>
+ <td>Tobias</td>
+ <td>Linus</td>
+ </tr>
+ <tr>
+ <td>16</td>
+ <td>14</td>
+ <td>10</td>
+ </tr>
+ </table>
+ </div>
+ </div>
+</body>
+</html>`.replace(/\n/g, '');
+
+export const MOCK_DRAWER_DATA = {
+ hasFetchError: false,
+ title: 'test title test',
+ body: ` <div id="content-body"> <div class="documentation md gl-mt-3"> <a href="../advanced_search.md">Advanced Search</a> <a href="../advanced_search2.md">Advanced Search2</a> <h2>test header h2</h2> <table class="testClass"> <tbody><tr> <td>Emil</td> <td>Tobias</td> <td>Linus</td> </tr> <tr> <td>16</td> <td>14</td> <td>10</td> </tr> </tbody></table> </div> </div>`,
+};
+
+export const MOCK_DRAWER_DATA_ERROR = {
+ hasFetchError: true,
+};
+
+export const MOCK_TABLE_DATA_BEFORE = `<head></head><body><h1>test</h1></test><table><tbody><tr><td></td></tr></tbody></table></body>`;
+
+export const MOCK_HTML_DATA_AFTER = {
+ body: '<table><tbody><tr><td></td></tr></tbody></table>',
+ title: 'test',
+};
diff --git a/spec/frontend/vue_shared/components/markdown_drawer/utils/fetch_spec.js b/spec/frontend/vue_shared/components/markdown_drawer/utils/fetch_spec.js
new file mode 100644
index 00000000000..ff07b2cf838
--- /dev/null
+++ b/spec/frontend/vue_shared/components/markdown_drawer/utils/fetch_spec.js
@@ -0,0 +1,43 @@
+import MockAdapter from 'axios-mock-adapter';
+import {
+ getRenderedMarkdown,
+ splitDocument,
+} from '~/vue_shared/components/markdown_drawer/utils/fetch';
+import axios from '~/lib/utils/axios_utils';
+import {
+ MOCK_HTML,
+ MOCK_DRAWER_DATA,
+ MOCK_DRAWER_DATA_ERROR,
+ MOCK_TABLE_DATA_BEFORE,
+ MOCK_HTML_DATA_AFTER,
+} from '../mock_data';
+
+describe('utils/fetch', () => {
+ let mock;
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe.each`
+ axiosMock | type | toExpect
+ ${{ code: 200, res: { html: MOCK_HTML } }} | ${'success'} | ${MOCK_DRAWER_DATA}
+ ${{ code: 500, res: null }} | ${'error'} | ${MOCK_DRAWER_DATA_ERROR}
+ `('process markdown data', ({ axiosMock, type, toExpect }) => {
+ describe(`if api fetch responds with ${type}`, () => {
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onGet().reply(axiosMock.code, axiosMock.res);
+ });
+ it(`should update drawer correctly`, async () => {
+ expect(await getRenderedMarkdown('/any/path')).toStrictEqual(toExpect);
+ });
+ });
+ });
+
+ describe('splitDocument', () => {
+ it(`should update tables correctly`, () => {
+ expect(splitDocument(MOCK_TABLE_DATA_BEFORE)).toStrictEqual(MOCK_HTML_DATA_AFTER);
+ });
+ });
+});
diff --git a/spec/frontend/vue_shared/components/namespace_select/mock_data.js b/spec/frontend/vue_shared/components/namespace_select/mock_data.js
deleted file mode 100644
index cfd521c67cb..00000000000
--- a/spec/frontend/vue_shared/components/namespace_select/mock_data.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export const groupNamespaces = [
- { id: 1, name: 'Group 1', humanName: 'Group 1' },
- { id: 2, name: 'Subgroup 1', humanName: 'Group 1 / Subgroup 1' },
-];
-
-export const userNamespaces = [{ id: 3, name: 'User namespace 1', humanName: 'User namespace 1' }];
diff --git a/spec/frontend/vue_shared/components/namespace_select/namespace_select_deprecated_spec.js b/spec/frontend/vue_shared/components/namespace_select/namespace_select_deprecated_spec.js
deleted file mode 100644
index d930ef63dad..00000000000
--- a/spec/frontend/vue_shared/components/namespace_select/namespace_select_deprecated_spec.js
+++ /dev/null
@@ -1,236 +0,0 @@
-import { nextTick } from 'vue';
-import {
- GlDropdown,
- GlDropdownItem,
- GlDropdownSectionHeader,
- GlSearchBoxByType,
- GlIntersectionObserver,
- GlLoadingIcon,
-} from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import NamespaceSelect, {
- i18n,
- EMPTY_NAMESPACE_ID,
-} from '~/vue_shared/components/namespace_select/namespace_select_deprecated.vue';
-import { userNamespaces, groupNamespaces } from './mock_data';
-
-const FLAT_NAMESPACES = [...userNamespaces, ...groupNamespaces];
-const EMPTY_NAMESPACE_TITLE = 'Empty namespace TEST';
-const EMPTY_NAMESPACE_ITEM = { id: EMPTY_NAMESPACE_ID, humanName: EMPTY_NAMESPACE_TITLE };
-
-describe('NamespaceSelectDeprecated', () => {
- let wrapper;
-
- const createComponent = (props = {}) =>
- shallowMountExtended(NamespaceSelect, {
- propsData: {
- userNamespaces,
- groupNamespaces,
- ...props,
- },
- stubs: {
- // We have to "full" mount GlDropdown so that slot children will render
- GlDropdown,
- },
- });
-
- const wrappersText = (arr) => arr.wrappers.map((w) => w.text());
- const findDropdown = () => wrapper.findComponent(GlDropdown);
- const findDropdownText = () => findDropdown().props('text');
- const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
- const findGroupDropdownItems = () =>
- wrapper.findByTestId('namespace-list-groups').findAllComponents(GlDropdownItem);
- const findDropdownItemsTexts = () => findDropdownItems().wrappers.map((x) => x.text());
- const findSectionHeaders = () => wrapper.findAllComponents(GlDropdownSectionHeader);
- const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
- const search = (term) => findSearchBox().vm.$emit('input', term);
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- describe('default', () => {
- beforeEach(() => {
- wrapper = createComponent();
- });
-
- it('renders the dropdown', () => {
- expect(findDropdown().exists()).toBe(true);
- });
-
- it('renders each dropdown item', () => {
- expect(findDropdownItemsTexts()).toEqual(FLAT_NAMESPACES.map((x) => x.humanName));
- });
-
- it('renders default dropdown text', () => {
- expect(findDropdownText()).toBe(i18n.DEFAULT_TEXT);
- });
-
- it('splits group and user namespaces', () => {
- const headers = findSectionHeaders();
- expect(wrappersText(headers)).toEqual([i18n.USERS, i18n.GROUPS]);
- });
-
- it('does not render wrapper as full width', () => {
- expect(findDropdown().attributes('block')).toBeUndefined();
- });
- });
-
- it('with defaultText, it overrides dropdown text', () => {
- const textOverride = 'Select an option';
-
- wrapper = createComponent({ defaultText: textOverride });
-
- expect(findDropdownText()).toBe(textOverride);
- });
-
- it('with includeHeaders=false, hides group/user headers', () => {
- wrapper = createComponent({ includeHeaders: false });
-
- expect(findSectionHeaders()).toHaveLength(0);
- });
-
- it('with fullWidth=true, sets the dropdown to full width', () => {
- wrapper = createComponent({ fullWidth: true });
-
- expect(findDropdown().attributes('block')).toBe('true');
- });
-
- describe('with search', () => {
- it.each`
- term | includeEmptyNamespace | shouldFilterNamespaces | expectedItems
- ${''} | ${false} | ${true} | ${[...userNamespaces, ...groupNamespaces]}
- ${'sub'} | ${false} | ${true} | ${[groupNamespaces[1]]}
- ${'User'} | ${false} | ${true} | ${[...userNamespaces]}
- ${'User'} | ${true} | ${true} | ${[...userNamespaces]}
- ${'namespace'} | ${true} | ${true} | ${[EMPTY_NAMESPACE_ITEM, ...userNamespaces]}
- ${'sub'} | ${false} | ${false} | ${[...userNamespaces, ...groupNamespaces]}
- `(
- 'with term=$term, includeEmptyNamespace=$includeEmptyNamespace, and shouldFilterNamespaces=$shouldFilterNamespaces should show $expectedItems.length',
- async ({ term, includeEmptyNamespace, shouldFilterNamespaces, expectedItems }) => {
- wrapper = createComponent({
- includeEmptyNamespace,
- emptyNamespaceTitle: EMPTY_NAMESPACE_TITLE,
- shouldFilterNamespaces,
- });
-
- search(term);
-
- await nextTick();
-
- const expected = expectedItems.map((x) => x.humanName);
-
- expect(findDropdownItemsTexts()).toEqual(expected);
- },
- );
- });
-
- describe('when search is typed in', () => {
- it('emits `search` event', async () => {
- wrapper = createComponent();
-
- wrapper.findComponent(GlSearchBoxByType).vm.$emit('input', 'foo');
-
- await nextTick();
-
- expect(wrapper.emitted('search')).toEqual([['foo']]);
- });
- });
-
- describe('with a selected namespace', () => {
- const selectedGroupIndex = 1;
- const selectedItem = groupNamespaces[selectedGroupIndex];
-
- beforeEach(() => {
- wrapper = createComponent();
-
- wrapper.findComponent(GlSearchBoxByType).vm.$emit('input', 'foo');
- findGroupDropdownItems().at(selectedGroupIndex).vm.$emit('click');
- });
-
- it('sets the dropdown text', () => {
- expect(findDropdownText()).toBe(selectedItem.humanName);
- });
-
- it('emits the `select` event when a namespace is selected', () => {
- const args = [selectedItem];
- expect(wrapper.emitted('select')).toEqual([args]);
- });
-
- it('clears search', () => {
- expect(wrapper.findComponent(GlSearchBoxByType).props('value')).toBe('');
- });
- });
-
- describe('with an empty namespace option', () => {
- beforeEach(() => {
- wrapper = createComponent({
- includeEmptyNamespace: true,
- emptyNamespaceTitle: EMPTY_NAMESPACE_TITLE,
- });
- });
-
- it('includes the empty namespace', () => {
- const first = findDropdownItems().at(0);
-
- expect(first.text()).toBe(EMPTY_NAMESPACE_TITLE);
- });
-
- it('emits the `select` event when a namespace is selected', () => {
- findDropdownItems().at(0).vm.$emit('click');
-
- expect(wrapper.emitted('select')).toEqual([[EMPTY_NAMESPACE_ITEM]]);
- });
-
- it.each`
- desc | term | shouldShow
- ${'should hide empty option'} | ${'group'} | ${false}
- ${'should show empty option'} | ${'Empty'} | ${true}
- `('when search for $term, $desc', async ({ term, shouldShow }) => {
- search(term);
-
- await nextTick();
-
- expect(findDropdownItemsTexts().includes(EMPTY_NAMESPACE_TITLE)).toBe(shouldShow);
- });
- });
-
- describe('when `hasNextPageOfGroups` prop is `true`', () => {
- it('renders `GlIntersectionObserver` and emits `load-more-groups` event when bottom is reached', () => {
- wrapper = createComponent({ hasNextPageOfGroups: true });
-
- const intersectionObserver = wrapper.findComponent(GlIntersectionObserver);
-
- intersectionObserver.vm.$emit('appear');
-
- expect(intersectionObserver.exists()).toBe(true);
- expect(wrapper.emitted('load-more-groups')).toEqual([[]]);
- });
-
- describe('when `isLoading` prop is `true`', () => {
- it('renders a loading icon', () => {
- wrapper = createComponent({ hasNextPageOfGroups: true, isLoading: true });
-
- expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
- });
- });
- });
-
- describe('when `isSearchLoading` prop is `true`', () => {
- it('sets `isLoading` prop to `true`', () => {
- wrapper = createComponent({ isSearchLoading: true });
-
- expect(wrapper.findComponent(GlSearchBoxByType).props('isLoading')).toBe(true);
- });
- });
-
- describe('when dropdown is opened', () => {
- it('emits `show` event', () => {
- wrapper = createComponent();
-
- findDropdown().vm.$emit('show');
-
- expect(wrapper.emitted('show')).toEqual([[]]);
- });
- });
-});
diff --git a/spec/frontend/vue_shared/components/sidebar/issuable_move_dropdown_spec.js b/spec/frontend/vue_shared/components/sidebar/issuable_move_dropdown_spec.js
index 9b1316677d7..d531147c0e6 100644
--- a/spec/frontend/vue_shared/components/sidebar/issuable_move_dropdown_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/issuable_move_dropdown_spec.js
@@ -37,6 +37,7 @@ const mockProps = {
dropdownButtonTitle: 'Move issuable',
dropdownHeaderTitle: 'Move issuable',
moveInProgress: false,
+ disabled: false,
};
const mockEvent = {
@@ -44,20 +45,21 @@ const mockEvent = {
preventDefault: jest.fn(),
};
-const createComponent = (propsData = mockProps) =>
- shallowMount(IssuableMoveDropdown, {
- propsData,
- });
-
describe('IssuableMoveDropdown', () => {
let mock;
let wrapper;
- beforeEach(() => {
- mock = new MockAdapter(axios);
- wrapper = createComponent();
+ const createComponent = (propsData = mockProps) => {
+ wrapper = shallowMount(IssuableMoveDropdown, {
+ propsData,
+ });
wrapper.vm.$refs.dropdown.hide = jest.fn();
wrapper.vm.$refs.searchInput.focusInput = jest.fn();
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ createComponent();
});
afterEach(() => {
@@ -194,6 +196,12 @@ describe('IssuableMoveDropdown', () => {
expect(findDropdownEl().findComponent(GlDropdownForm).exists()).toBe(true);
});
+ it('renders disabled dropdown when `disabled` is true', () => {
+ createComponent({ ...mockProps, disabled: true });
+
+ expect(findDropdownEl().attributes('disabled')).toBe('true');
+ });
+
it('renders header element', () => {
const headerEl = findDropdownEl().find('[data-testid="header"]');
diff --git a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/labels_select_root_spec.js b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/labels_select_root_spec.js
index b58c44645d6..74ddd07d041 100644
--- a/spec/frontend/vue_shared/components/sidebar/labels_select_widget/labels_select_root_spec.js
+++ b/spec/frontend/vue_shared/components/sidebar/labels_select_widget/labels_select_root_spec.js
@@ -49,7 +49,6 @@ describe('LabelsSelectRoot', () => {
issuableType = IssuableType.Issue,
queryHandler = successfulQueryHandler,
mutationHandler = successfulMutationHandler,
- isRealtimeEnabled = false,
} = {}) => {
const mockApollo = createMockApollo([
[issueLabelsQuery, queryHandler],
@@ -74,9 +73,6 @@ describe('LabelsSelectRoot', () => {
allowLabelEdit: true,
allowLabelCreate: true,
labelsManagePath: 'test',
- glFeatures: {
- realtimeLabels: isRealtimeEnabled,
- },
},
});
};
@@ -204,17 +200,10 @@ describe('LabelsSelectRoot', () => {
});
});
- it('does not emit `updateSelectedLabels` event when the subscription is triggered and FF is disabled', async () => {
+ it('emits `updateSelectedLabels` event when the subscription is triggered', async () => {
createComponent();
await waitForPromises();
- expect(wrapper.emitted('updateSelectedLabels')).toBeUndefined();
- });
-
- it('emits `updateSelectedLabels` event when the subscription is triggered and FF is enabled', async () => {
- createComponent({ isRealtimeEnabled: true });
- await waitForPromises();
-
expect(wrapper.emitted('updateSelectedLabels')).toEqual([
[
{
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 8dc3348acfa..d720574ce6d 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
@@ -2,6 +2,9 @@ import { GlIntersectionObserver } from '@gitlab/ui';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import Chunk from '~/vue_shared/components/source_viewer/components/chunk.vue';
import ChunkLine from '~/vue_shared/components/source_viewer/components/chunk_line.vue';
+import { scrollToElement } from '~/lib/utils/common_utils';
+
+jest.mock('~/lib/utils/common_utils');
const DEFAULT_PROPS = {
chunkIndex: 2,
@@ -13,11 +16,17 @@ const DEFAULT_PROPS = {
blamePath: 'blame/file.js',
};
+const hash = '#L142';
+
describe('Chunk component', () => {
let wrapper;
+ let idleCallbackSpy;
const createComponent = (props = {}) => {
- wrapper = shallowMountExtended(Chunk, { propsData: { ...DEFAULT_PROPS, ...props } });
+ wrapper = shallowMountExtended(Chunk, {
+ mocks: { $route: { hash } },
+ propsData: { ...DEFAULT_PROPS, ...props },
+ });
};
const findIntersectionObserver = () => wrapper.findComponent(GlIntersectionObserver);
@@ -26,6 +35,7 @@ describe('Chunk component', () => {
const findContent = () => wrapper.findByTestId('content');
beforeEach(() => {
+ idleCallbackSpy = jest.spyOn(window, 'requestIdleCallback').mockImplementation((fn) => fn());
createComponent();
});
@@ -51,18 +61,30 @@ describe('Chunk component', () => {
});
describe('rendering', () => {
+ it('does not register window.requestIdleCallback if isFirstChunk prop is true, renders lines immediately', () => {
+ jest.clearAllMocks();
+ createComponent({ isFirstChunk: true });
+
+ expect(window.requestIdleCallback).not.toHaveBeenCalled();
+ expect(findContent().exists()).toBe(true);
+ });
+
it('does not render a Chunk Line component if isHighlighted is false', () => {
expect(findChunkLines().length).toBe(0);
});
+ it('does not render simplified line numbers and content if browser is not in idle state', () => {
+ idleCallbackSpy.mockRestore();
+ createComponent();
+
+ expect(findLineNumbers()).toHaveLength(0);
+ expect(findContent().exists()).toBe(false);
+ });
+
it('renders simplified line numbers and content if isHighlighted is false', () => {
expect(findLineNumbers().length).toBe(DEFAULT_PROPS.totalLines);
- expect(findLineNumbers().at(0).attributes()).toMatchObject({
- 'data-line-number': `${DEFAULT_PROPS.startingFrom + 1}`,
- href: `#L${DEFAULT_PROPS.startingFrom + 1}`,
- id: `L${DEFAULT_PROPS.startingFrom + 1}`,
- });
+ expect(findLineNumbers().at(0).attributes('id')).toBe(`L${DEFAULT_PROPS.startingFrom + 1}`);
expect(findContent().text()).toBe(DEFAULT_PROPS.content);
});
@@ -80,5 +102,14 @@ describe('Chunk component', () => {
blamePath: DEFAULT_PROPS.blamePath,
});
});
+
+ it('does not scroll to route hash if last chunk is not loaded', () => {
+ expect(scrollToElement).not.toHaveBeenCalled();
+ });
+
+ it('scrolls to route hash if last chunk is loaded', () => {
+ createComponent({ totalChunks: DEFAULT_PROPS.chunkIndex + 1 });
+ expect(scrollToElement).toHaveBeenCalledWith(hash, { behavior: 'auto' });
+ });
});
});
diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/link_dependencies_spec.js b/spec/frontend/vue_shared/components/source_viewer/plugins/link_dependencies_spec.js
index 375b1307616..a7b55d7332f 100644
--- a/spec/frontend/vue_shared/components/source_viewer/plugins/link_dependencies_spec.js
+++ b/spec/frontend/vue_shared/components/source_viewer/plugins/link_dependencies_spec.js
@@ -1,10 +1,26 @@
import packageJsonLinker from '~/vue_shared/components/source_viewer/plugins/utils/package_json_linker';
+import godepsJsonLinker from '~/vue_shared/components/source_viewer/plugins/utils/godeps_json_linker';
import gemspecLinker from '~/vue_shared/components/source_viewer/plugins/utils/gemspec_linker';
+import gemfileLinker from '~/vue_shared/components/source_viewer/plugins/utils/gemfile_linker';
+import podspecJsonLinker from '~/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker';
+import composerJsonLinker from '~/vue_shared/components/source_viewer/plugins/utils/composer_json_linker';
import linkDependencies from '~/vue_shared/components/source_viewer/plugins/link_dependencies';
-import { PACKAGE_JSON_FILE_TYPE, PACKAGE_JSON_CONTENT, GEMSPEC_FILE_TYPE } from './mock_data';
+import {
+ PACKAGE_JSON_FILE_TYPE,
+ PACKAGE_JSON_CONTENT,
+ GEMSPEC_FILE_TYPE,
+ GODEPS_JSON_FILE_TYPE,
+ GEMFILE_FILE_TYPE,
+ PODSPEC_JSON_FILE_TYPE,
+ COMPOSER_JSON_FILE_TYPE,
+} from './mock_data';
jest.mock('~/vue_shared/components/source_viewer/plugins/utils/package_json_linker');
jest.mock('~/vue_shared/components/source_viewer/plugins/utils/gemspec_linker');
+jest.mock('~/vue_shared/components/source_viewer/plugins/utils/godeps_json_linker');
+jest.mock('~/vue_shared/components/source_viewer/plugins/utils/gemfile_linker');
+jest.mock('~/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker');
+jest.mock('~/vue_shared/components/source_viewer/plugins/utils/composer_json_linker');
describe('Highlight.js plugin for linking dependencies', () => {
const hljsResultMock = { value: 'test' };
@@ -18,4 +34,24 @@ describe('Highlight.js plugin for linking dependencies', () => {
linkDependencies(hljsResultMock, GEMSPEC_FILE_TYPE);
expect(gemspecLinker).toHaveBeenCalled();
});
+
+ it('calls godepsJsonLinker for godeps_json file types', () => {
+ linkDependencies(hljsResultMock, GODEPS_JSON_FILE_TYPE);
+ expect(godepsJsonLinker).toHaveBeenCalled();
+ });
+
+ it('calls gemfileLinker for gemfile file types', () => {
+ linkDependencies(hljsResultMock, GEMFILE_FILE_TYPE);
+ expect(gemfileLinker).toHaveBeenCalled();
+ });
+
+ it('calls podspecJsonLinker for podspec_json file types', () => {
+ linkDependencies(hljsResultMock, PODSPEC_JSON_FILE_TYPE);
+ expect(podspecJsonLinker).toHaveBeenCalled();
+ });
+
+ it('calls composerJsonLinker for composer_json file types', () => {
+ linkDependencies(hljsResultMock, COMPOSER_JSON_FILE_TYPE);
+ expect(composerJsonLinker).toHaveBeenCalled();
+ });
});
diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/mock_data.js b/spec/frontend/vue_shared/components/source_viewer/plugins/mock_data.js
index aa874c9c081..5455479ec71 100644
--- a/spec/frontend/vue_shared/components/source_viewer/plugins/mock_data.js
+++ b/spec/frontend/vue_shared/components/source_viewer/plugins/mock_data.js
@@ -1,4 +1,34 @@
export const PACKAGE_JSON_FILE_TYPE = 'package_json';
+
export const PACKAGE_JSON_CONTENT = '{ "dependencies": { "@babel/core": "^7.18.5" } }';
+export const COMPOSER_JSON_EXAMPLES = {
+ packagist: '{ "require": { "composer/installers": "^1.2" } }',
+ drupal: '{ "require": { "drupal/bootstrap": "3.x-dev" } }',
+ withoutLink: '{ "require": { "drupal/erp_common": "dev-master" } }',
+};
+
export const GEMSPEC_FILE_TYPE = 'gemspec';
+
+export const GODEPS_JSON_FILE_TYPE = 'godeps_json';
+
+export const GEMFILE_FILE_TYPE = 'gemfile';
+
+export const PODSPEC_JSON_FILE_TYPE = 'podspec_json';
+
+export const PODSPEC_JSON_CONTENT = `{
+ "dependencies": {
+ "MyCheckCore": [
+ ]
+ },
+ "subspecs": [
+ {
+ "dependencies": {
+ "AFNetworking/Security": [
+ ]
+ }
+ }
+ ]
+ }`;
+
+export const COMPOSER_JSON_FILE_TYPE = 'composer_json';
diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/utils/composer_json_linker_spec.js b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/composer_json_linker_spec.js
new file mode 100644
index 00000000000..3ecb16ddcd0
--- /dev/null
+++ b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/composer_json_linker_spec.js
@@ -0,0 +1,38 @@
+import composerJsonLinker from '~/vue_shared/components/source_viewer/plugins/utils/composer_json_linker';
+import { COMPOSER_JSON_EXAMPLES } from '../mock_data';
+
+describe('Highlight.js plugin for linking composer.json dependencies', () => {
+ it('mutates the input value by wrapping dependency names and versions in anchors', () => {
+ const inputValue =
+ '<span class="hljs-attr">&quot;drupal/erp_common"&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;dev-master&quot;</span>';
+ const outputValue =
+ '<span class="hljs-attr">&quot;drupal/erp_common"&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;dev-master&quot;</span>';
+ const hljsResultMock = { value: inputValue };
+
+ const output = composerJsonLinker(hljsResultMock, COMPOSER_JSON_EXAMPLES.withoutLink);
+ expect(output).toBe(outputValue);
+ });
+});
+
+const getInputValue = (dependencyString, version) =>
+ `<span class="hljs-attr">&quot;${dependencyString}&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;${version}&quot;</span>`;
+const getOutputValue = (dependencyString, version, expectedHref) =>
+ `<span class="hljs-attr">&quot;<a href="${expectedHref}" target="_blank" rel="nofollow noreferrer noopener">${dependencyString}</a>&quot;</span>: <span class="hljs-attr">&quot;<a href="${expectedHref}" target="_blank" rel="nofollow noreferrer noopener">${version}</a>&quot;</span>`;
+
+describe('Highlight.js plugin for linking Godeps.json dependencies', () => {
+ it.each`
+ type | dependency | version | expectedHref
+ ${'packagist'} | ${'composer/installers'} | ${'^1.2'} | ${'https://packagist.org/packages/composer/installers'}
+ ${'drupal'} | ${'drupal/bootstrap'} | ${'3.x-dev'} | ${'https://www.drupal.org/project/bootstrap'}
+ `(
+ 'mutates the input value by wrapping dependency names in anchors and altering path when needed',
+ ({ type, dependency, version, expectedHref }) => {
+ const inputValue = getInputValue(dependency, version);
+ const outputValue = getOutputValue(dependency, version, expectedHref);
+ const hljsResultMock = { value: inputValue };
+
+ const output = composerJsonLinker(hljsResultMock, COMPOSER_JSON_EXAMPLES[type]);
+ expect(output).toBe(outputValue);
+ },
+ );
+});
diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/utils/dependency_linker_util_spec.js b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/dependency_linker_util_spec.js
index e4ce07ec668..66e2020da27 100644
--- a/spec/frontend/vue_shared/components/source_viewer/plugins/utils/dependency_linker_util_spec.js
+++ b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/dependency_linker_util_spec.js
@@ -1,13 +1,15 @@
import {
createLink,
generateHLJSOpenTag,
+ getObjectKeysByKeyName,
} from '~/vue_shared/components/source_viewer/plugins/utils/dependency_linker_util';
+import { PODSPEC_JSON_CONTENT } from '../mock_data';
describe('createLink', () => {
it('generates a link with the correct attributes', () => {
const href = 'http://test.com';
const innerText = 'testing';
- const result = `<a href="${href}" rel="nofollow noreferrer noopener">${innerText}</a>`;
+ const result = `<a href="${href}" target="_blank" rel="nofollow noreferrer noopener">${innerText}</a>`;
expect(createLink(href, innerText)).toBe(result);
});
@@ -18,7 +20,7 @@ describe('createLink', () => {
const escapedHref = '&lt;script&gt;XSS&lt;/script&gt;';
const href = `http://test.com/${unescapedXSS}`;
const innerText = `testing${unescapedXSS}`;
- const result = `<a href="http://test.com/${escapedHref}" rel="nofollow noreferrer noopener">testing${escapedPackageName}</a>`;
+ const result = `<a href="http://test.com/${escapedHref}" target="_blank" rel="nofollow noreferrer noopener">testing${escapedPackageName}</a>`;
expect(createLink(href, innerText)).toBe(result);
});
@@ -32,3 +34,11 @@ describe('generateHLJSOpenTag', () => {
expect(generateHLJSOpenTag(type)).toBe(result);
});
});
+
+describe('getObjectKeysByKeyName method', () => {
+ it('gets all object keys within specified key', () => {
+ const acc = [];
+ const keys = getObjectKeysByKeyName(JSON.parse(PODSPEC_JSON_CONTENT), 'dependencies', acc);
+ expect(keys).toEqual(['MyCheckCore', 'AFNetworking/Security']);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/utils/gemfile_linker_spec.js b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/gemfile_linker_spec.js
new file mode 100644
index 00000000000..4e188c9af7e
--- /dev/null
+++ b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/gemfile_linker_spec.js
@@ -0,0 +1,13 @@
+import gemfileLinker from '~/vue_shared/components/source_viewer/plugins/utils/gemfile_linker';
+
+describe('Highlight.js plugin for linking gemfile dependencies', () => {
+ it('mutates the input value by wrapping dependency names in anchors', () => {
+ const inputValue = 'gem </span><span class="hljs-string">&#39;paranoia&#39;';
+ const outputValue =
+ 'gem </span><span class="hljs-string">&#39;<a href="https://rubygems.org/gems/paranoia" target="_blank" rel="nofollow noreferrer noopener">paranoia</a>&#39;';
+ const hljsResultMock = { value: inputValue };
+
+ const output = gemfileLinker(hljsResultMock);
+ expect(output).toBe(outputValue);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/utils/gemspec_linker_spec.js b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/gemspec_linker_spec.js
index 3f74bfa117f..4b104b0bf43 100644
--- a/spec/frontend/vue_shared/components/source_viewer/plugins/utils/gemspec_linker_spec.js
+++ b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/gemspec_linker_spec.js
@@ -5,7 +5,7 @@ describe('Highlight.js plugin for linking gemspec dependencies', () => {
const inputValue =
's.add_dependency(<span class="hljs-string">&#x27;rugged&#x27;</span>, <span class="hljs-string">&#x27;~&gt; 0.24.0&#x27;</span>)';
const outputValue =
- 's.add_dependency(<span class="hljs-string linked">&#x27;<a href="https://rubygems.org/gems/rugged" rel="nofollow noreferrer noopener">rugged</a>&#x27;</span>, <span class="hljs-string">&#x27;~&gt; 0.24.0&#x27;</span>)';
+ 's.add_dependency(<span class="hljs-string linked">&#x27;<a href="https://rubygems.org/gems/rugged" target="_blank" rel="nofollow noreferrer noopener">rugged</a>&#x27;</span>, <span class="hljs-string">&#x27;~&gt; 0.24.0&#x27;</span>)';
const hljsResultMock = { value: inputValue };
const output = gemspecLinker(hljsResultMock);
diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/utils/godeps_json_linker_spec.js b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/godeps_json_linker_spec.js
new file mode 100644
index 00000000000..ea7e3936846
--- /dev/null
+++ b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/godeps_json_linker_spec.js
@@ -0,0 +1,27 @@
+import godepsJsonLinker from '~/vue_shared/components/source_viewer/plugins/utils/godeps_json_linker';
+
+const getInputValue = (dependencyString) =>
+ `<span class="hljs-attr">&quot;ImportPath&quot;</span><span class="hljs-punctuation">:</span><span class=""> </span><span class="hljs-string">&quot;${dependencyString}&quot;</span>`;
+const getOutputValue = (dependencyString, expectedHref) =>
+ `<span class="hljs-attr">&quot;ImportPath&quot;</span><span class="hljs-punctuation">:</span><span class=""> </span><span class="hljs-attr">&quot;<a href="${expectedHref}" target="_blank" rel="nofollow noreferrer noopener">${dependencyString}</a>&quot;</span>`;
+
+describe('Highlight.js plugin for linking Godeps.json dependencies', () => {
+ it.each`
+ dependency | expectedHref
+ ${'gitlab.com/group/project/path'} | ${'https://gitlab.com/group/project/_/tree/master/path'}
+ ${'gitlab.com/group/subgroup/project.git/path'} | ${'https://gitlab.com/group/subgroup/_/tree/master/project.git/path'}
+ ${'github.com/docker/docker/pkg/homedir'} | ${'https://github.com/docker/docker/tree/master/pkg/homedir'}
+ ${'golang.org/x/net/http2'} | ${'https://godoc.org/golang.org/x/net/http2'}
+ ${'gopkg.in/yaml.v1'} | ${'https://gopkg.in/yaml.v1'}
+ `(
+ 'mutates the input value by wrapping dependency names in anchors and altering path when needed',
+ ({ dependency, expectedHref }) => {
+ const inputValue = getInputValue(dependency);
+ const outputValue = getOutputValue(dependency, expectedHref);
+ const hljsResultMock = { value: inputValue };
+
+ const output = godepsJsonLinker(hljsResultMock);
+ expect(output).toBe(outputValue);
+ },
+ );
+});
diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/utils/package_json_linker_spec.js b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/package_json_linker_spec.js
index e83c129818c..170a44f8ee2 100644
--- a/spec/frontend/vue_shared/components/source_viewer/plugins/utils/package_json_linker_spec.js
+++ b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/package_json_linker_spec.js
@@ -6,7 +6,7 @@ describe('Highlight.js plugin for linking package.json dependencies', () => {
const inputValue =
'<span class="hljs-attr">&quot;@babel/core&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;^7.18.5&quot;</span>';
const outputValue =
- '<span class="hljs-attr">&quot;<a href="https://npmjs.com/package/@babel/core" rel="nofollow noreferrer noopener">@babel/core</a>&quot;</span>: <span class="hljs-attr">&quot;<a href="https://npmjs.com/package/@babel/core" rel="nofollow noreferrer noopener">^7.18.5</a>&quot;</span>';
+ '<span class="hljs-attr">&quot;<a href="https://npmjs.com/package/@babel/core" target="_blank" rel="nofollow noreferrer noopener">@babel/core</a>&quot;</span>: <span class="hljs-attr">&quot;<a href="https://npmjs.com/package/@babel/core" target="_blank" rel="nofollow noreferrer noopener">^7.18.5</a>&quot;</span>';
const hljsResultMock = { value: inputValue };
const output = packageJsonLinker(hljsResultMock, PACKAGE_JSON_CONTENT);
diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker_spec.js b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker_spec.js
new file mode 100644
index 00000000000..0ef63de68c6
--- /dev/null
+++ b/spec/frontend/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker_spec.js
@@ -0,0 +1,14 @@
+import podspecJsonLinker from '~/vue_shared/components/source_viewer/plugins/utils/podspec_json_linker';
+import { PODSPEC_JSON_CONTENT } from '../mock_data';
+
+describe('Highlight.js plugin for linking podspec_json dependencies', () => {
+ it('mutates the input value by wrapping dependency names in anchors', () => {
+ const inputValue =
+ '<span class="hljs-attr">&quot;AFNetworking/Security&quot;</span><span class="hljs-punctuation">:</span><span class=""> </span><span class="hljs-punctuation">[';
+ const outputValue =
+ '<span class="hljs-attr">&quot;<a href="https://cocoapods.org/pods/AFNetworking" target="_blank" rel="nofollow noreferrer noopener">AFNetworking/Security</a>&quot;</span><span class="hljs-punctuation">:</span><span class=""> </span><span class="hljs-punctuation">[';
+ const hljsResultMock = { value: inputValue };
+ const output = podspecJsonLinker(hljsResultMock, PODSPEC_JSON_CONTENT);
+ expect(output).toBe(outputValue);
+ });
+});
diff --git a/spec/frontend/vue_shared/components/source_viewer/plugins/wrap_child_nodes_spec.js b/spec/frontend/vue_shared/components/source_viewer/plugins/wrap_child_nodes_spec.js
index bc6df1a2565..8d072c8c8de 100644
--- a/spec/frontend/vue_shared/components/source_viewer/plugins/wrap_child_nodes_spec.js
+++ b/spec/frontend/vue_shared/components/source_viewer/plugins/wrap_child_nodes_spec.js
@@ -8,13 +8,14 @@ describe('Highlight.js plugin for wrapping _emitter nodes', () => {
children: [
{ kind: 'string', children: ['Text 1'] },
{ kind: 'string', children: ['Text 2', { kind: 'comment', children: ['Text 3'] }] },
+ { kind: undefined, sublanguage: true, children: ['Text 3 (sublanguage)'] },
'Text4\nText5',
],
},
},
};
- const outputValue = `<span class="hljs-string">Text 1</span><span class="hljs-string"><span class="hljs-string">Text 2</span><span class="hljs-comment">Text 3</span></span><span class="">Text4</span>\n<span class="">Text5</span>`;
+ const outputValue = `<span class="hljs-string">Text 1</span><span class="hljs-string"><span class="hljs-string">Text 2</span><span class="hljs-comment">Text 3</span></span><span class="">Text 3 (sublanguage)</span><span class="">Text4</span>\n<span class="">Text5</span>`;
wrapChildNodes(hljsResultMock);
expect(hljsResultMock.value).toBe(outputValue);
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 6d319b37b02..33f370efdfa 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
@@ -10,6 +10,7 @@ import {
EVENT_LABEL_VIEWER,
EVENT_LABEL_FALLBACK,
ROUGE_TO_HLJS_LANGUAGE_MAP,
+ LINES_PER_CHUNK,
} from '~/vue_shared/components/source_viewer/constants';
import waitForPromises from 'helpers/wait_for_promises';
import LineHighlighter from '~/blob/line_highlighter';
@@ -121,6 +122,7 @@ describe('Source Viewer component', () => {
it('highlights the first chunk', () => {
expect(hljs.highlight).toHaveBeenCalledWith(chunk1.trim(), { language: mappedLanguage });
+ expect(findChunks().at(0).props('isFirstChunk')).toBe(true);
});
describe('auto-detects if a language cannot be loaded', () => {
@@ -133,45 +135,27 @@ describe('Source Viewer component', () => {
});
describe('rendering', () => {
- it('renders the first chunk', async () => {
- const firstChunk = findChunks().at(0);
-
- expect(firstChunk.props('content')).toContain(chunk1);
-
- expect(firstChunk.props()).toMatchObject({
- totalLines: 70,
- startingFrom: 0,
+ it.each`
+ chunkIndex | chunkContent | totalChunks
+ ${0} | ${chunk1} | ${0}
+ ${1} | ${chunk2} | ${3}
+ ${2} | ${chunk3Result} | ${3}
+ `('renders chunk $chunkIndex', ({ chunkIndex, chunkContent, totalChunks }) => {
+ const chunk = findChunks().at(chunkIndex);
+
+ expect(chunk.props('content')).toContain(chunkContent.trim());
+
+ expect(chunk.props()).toMatchObject({
+ totalLines: LINES_PER_CHUNK,
+ startingFrom: LINES_PER_CHUNK * chunkIndex,
+ totalChunks,
});
});
- it('renders the second chunk', async () => {
- const secondChunk = findChunks().at(1);
-
- expect(secondChunk.props('content')).toContain(chunk2.trim());
-
- expect(secondChunk.props()).toMatchObject({
- totalLines: 70,
- startingFrom: 70,
- });
+ it('emits showBlobInteractionZones on the eventHub when chunk appears', () => {
+ findChunks().at(0).vm.$emit('appear');
+ expect(eventHub.$emit).toHaveBeenCalledWith('showBlobInteractionZones', path);
});
-
- it('renders the third chunk', async () => {
- const thirdChunk = findChunks().at(2);
-
- expect(thirdChunk.props('content')).toContain(chunk3Result.trim());
-
- expect(chunk3Result).toEqual(chunk3.replace(/\r?\n/g, '\n'));
-
- expect(thirdChunk.props()).toMatchObject({
- totalLines: 70,
- startingFrom: 140,
- });
- });
- });
-
- it('emits showBlobInteractionZones on the eventHub when chunk appears', () => {
- findChunks().at(0).vm.$emit('appear');
- expect(eventHub.$emit).toHaveBeenCalledWith('showBlobInteractionZones', path);
});
describe('LineHighlighter', () => {
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 f55d3156581..e1c6020686c 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
@@ -543,24 +543,6 @@ describe('IssuableItem', () => {
});
});
- describe('when issuable was created within the past 24 hours', () => {
- it('renders issuable card with a recently-created style', () => {
- wrapper = createComponent({
- issuable: { ...mockIssuable, createdAt: '2020-12-10T12:34:56' },
- });
-
- expect(wrapper.classes()).toContain('today');
- });
- });
-
- describe('when issuable was created earlier than the past 24 hours', () => {
- it('renders issuable card without a recently-created style', () => {
- wrapper = createComponent({ issuable: { ...mockIssuable, createdAt: '2020-12-09' } });
-
- expect(wrapper.classes()).not.toContain('today');
- });
- });
-
describe('scoped labels', () => {
describe.each`
description | labelPosition | hasScopedLabelsFeature | scoped
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 0c53f599d55..371844e66f4 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
@@ -322,6 +322,18 @@ describe('IssuableListRoot', () => {
});
});
+ describe('showFilteredSearchFriendlyText prop', () => {
+ describe.each([true, false])('when %s', (showFilteredSearchFriendlyText) => {
+ it('passes its value to FilteredSearchBar', () => {
+ wrapper = createComponent({ props: { showFilteredSearchFriendlyText } });
+
+ expect(findFilteredSearchBar().props('showFriendlyText')).toBe(
+ showFilteredSearchFriendlyText,
+ );
+ });
+ });
+ });
+
describe('alert', () => {
const error = 'oopsie!';
diff --git a/spec/frontend/webhooks/components/__snapshots__/push_events_spec.js.snap b/spec/frontend/webhooks/components/__snapshots__/push_events_spec.js.snap
new file mode 100644
index 00000000000..3dbff024a6b
--- /dev/null
+++ b/spec/frontend/webhooks/components/__snapshots__/push_events_spec.js.snap
@@ -0,0 +1,453 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Webhook push events form editor component Different push events rules when editing existing hook with "all_branches" strategy selected 1`] = `
+<gl-form-radio-group-stub
+ checked="all_branches"
+ disabledfield="disabled"
+ htmlfield="html"
+ name="hook[branch_filter_strategy]"
+ options=""
+ textfield="text"
+ valuefield="value"
+>
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_all_branches"
+ value="all_branches"
+ >
+ <div
+ data-qa-selector="strategy_radio_all"
+ >
+ All branches
+ </div>
+ </gl-form-radio-stub>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_wildcard"
+ value="wildcard"
+ >
+ <div
+ data-qa-selector="strategy_radio_wildcard"
+ >
+
+ Wildcard pattern
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_regex"
+ value="regex"
+ >
+ <div
+ data-qa-selector="strategy_radio_regex"
+ >
+
+ Regular expression
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+</gl-form-radio-group-stub>
+`;
+
+exports[`Webhook push events form editor component Different push events rules when editing existing hook with "regex" strategy selected 1`] = `
+<gl-form-radio-group-stub
+ checked="regex"
+ disabledfield="disabled"
+ htmlfield="html"
+ name="hook[branch_filter_strategy]"
+ options=""
+ textfield="text"
+ valuefield="value"
+>
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_all_branches"
+ value="all_branches"
+ >
+ <div
+ data-qa-selector="strategy_radio_all"
+ >
+ All branches
+ </div>
+ </gl-form-radio-stub>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_wildcard"
+ value="wildcard"
+ >
+ <div
+ data-qa-selector="strategy_radio_wildcard"
+ >
+
+ Wildcard pattern
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_regex"
+ value="regex"
+ >
+ <div
+ data-qa-selector="strategy_radio_regex"
+ >
+
+ Regular expression
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <gl-form-input-stub
+ data-qa-selector="webhook_branch_filter_field"
+ data-testid="webhook_branch_filter_field"
+ name="hook[push_events_branch_filter]"
+ value="foo"
+ />
+ </div>
+
+ <p
+ class="form-text text-muted custom-control"
+ >
+ <gl-sprintf-stub
+ message="Regex such as %{REGEX_CODE} is supported."
+ />
+ </p>
+</gl-form-radio-group-stub>
+`;
+
+exports[`Webhook push events form editor component Different push events rules when editing existing hook with "wildcard" strategy selected 1`] = `
+<gl-form-radio-group-stub
+ checked="wildcard"
+ disabledfield="disabled"
+ htmlfield="html"
+ name="hook[branch_filter_strategy]"
+ options=""
+ textfield="text"
+ valuefield="value"
+>
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_all_branches"
+ value="all_branches"
+ >
+ <div
+ data-qa-selector="strategy_radio_all"
+ >
+ All branches
+ </div>
+ </gl-form-radio-stub>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_wildcard"
+ value="wildcard"
+ >
+ <div
+ data-qa-selector="strategy_radio_wildcard"
+ >
+
+ Wildcard pattern
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <gl-form-input-stub
+ data-qa-selector="webhook_branch_filter_field"
+ data-testid="webhook_branch_filter_field"
+ name="hook[push_events_branch_filter]"
+ value="foo"
+ />
+ </div>
+
+ <p
+ class="form-text text-muted custom-control"
+ >
+ <gl-sprintf-stub
+ message="Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+ />
+ </p>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_regex"
+ value="regex"
+ >
+ <div
+ data-qa-selector="strategy_radio_regex"
+ >
+
+ Regular expression
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+</gl-form-radio-group-stub>
+`;
+
+exports[`Webhook push events form editor component Different push events rules when editing new hook all_branches should be selected by default 1`] = `
+<gl-form-radio-group-stub
+ checked="all_branches"
+ disabledfield="disabled"
+ htmlfield="html"
+ name="hook[branch_filter_strategy]"
+ options=""
+ textfield="text"
+ valuefield="value"
+>
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_all_branches"
+ value="all_branches"
+ >
+ <div
+ data-qa-selector="strategy_radio_all"
+ >
+ All branches
+ </div>
+ </gl-form-radio-stub>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_wildcard"
+ value="wildcard"
+ >
+ <div
+ data-qa-selector="strategy_radio_wildcard"
+ >
+
+ Wildcard pattern
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_regex"
+ value="regex"
+ >
+ <div
+ data-qa-selector="strategy_radio_regex"
+ >
+
+ Regular expression
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+</gl-form-radio-group-stub>
+`;
+
+exports[`Webhook push events form editor component Different push events rules when editing new hook should be able to set regex rule 1`] = `
+<gl-form-radio-group-stub
+ checked="regex"
+ disabledfield="disabled"
+ htmlfield="html"
+ name="hook[branch_filter_strategy]"
+ options=""
+ textfield="text"
+ valuefield="value"
+>
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_all_branches"
+ value="all_branches"
+ >
+ <div
+ data-qa-selector="strategy_radio_all"
+ >
+ All branches
+ </div>
+ </gl-form-radio-stub>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_wildcard"
+ value="wildcard"
+ >
+ <div
+ data-qa-selector="strategy_radio_wildcard"
+ >
+
+ Wildcard pattern
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_regex"
+ value="regex"
+ >
+ <div
+ data-qa-selector="strategy_radio_regex"
+ >
+
+ Regular expression
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <gl-form-input-stub
+ data-qa-selector="webhook_branch_filter_field"
+ data-testid="webhook_branch_filter_field"
+ name="hook[push_events_branch_filter]"
+ value=""
+ />
+ </div>
+
+ <p
+ class="form-text text-muted custom-control"
+ >
+ <gl-sprintf-stub
+ message="Regex such as %{REGEX_CODE} is supported."
+ />
+ </p>
+</gl-form-radio-group-stub>
+`;
+
+exports[`Webhook push events form editor component Different push events rules when editing new hook should be able to set wildcard rule 1`] = `
+<gl-form-radio-group-stub
+ checked="wildcard"
+ disabledfield="disabled"
+ htmlfield="html"
+ name="hook[branch_filter_strategy]"
+ options=""
+ textfield="text"
+ valuefield="value"
+>
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_all_branches"
+ value="all_branches"
+ >
+ <div
+ data-qa-selector="strategy_radio_all"
+ >
+ All branches
+ </div>
+ </gl-form-radio-stub>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_wildcard"
+ value="wildcard"
+ >
+ <div
+ data-qa-selector="strategy_radio_wildcard"
+ >
+
+ Wildcard pattern
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <gl-form-input-stub
+ data-qa-selector="webhook_branch_filter_field"
+ data-testid="webhook_branch_filter_field"
+ name="hook[push_events_branch_filter]"
+ value=""
+ />
+ </div>
+
+ <p
+ class="form-text text-muted custom-control"
+ >
+ <gl-sprintf-stub
+ message="Wildcards such as %{WILDCARD_CODE_STABLE} or %{WILDCARD_CODE_PRODUCTION} are supported."
+ />
+ </p>
+
+ <gl-form-radio-stub
+ class="gl-mt-2 branch-filter-strategy-radio"
+ data-testid="rule_regex"
+ value="regex"
+ >
+ <div
+ data-qa-selector="strategy_radio_regex"
+ >
+
+ Regular expression
+
+ </div>
+ </gl-form-radio-stub>
+
+ <div
+ class="gl-ml-6"
+ >
+ <!---->
+ </div>
+
+ <!---->
+</gl-form-radio-group-stub>
+`;
diff --git a/spec/frontend/webhooks/components/form_url_app_spec.js b/spec/frontend/webhooks/components/form_url_app_spec.js
index 16e0a3f549e..45a39d2dd58 100644
--- a/spec/frontend/webhooks/components/form_url_app_spec.js
+++ b/spec/frontend/webhooks/components/form_url_app_spec.js
@@ -1,10 +1,14 @@
import { nextTick } from 'vue';
-import { GlFormRadio, GlFormRadioGroup, GlLink } from '@gitlab/ui';
+import { GlFormGroup, GlFormRadio, GlFormRadioGroup, GlLink } from '@gitlab/ui';
+import { scrollToElement } from '~/lib/utils/common_utils';
import FormUrlApp from '~/webhooks/components/form_url_app.vue';
import FormUrlMaskItem from '~/webhooks/components/form_url_mask_item.vue';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
+
+jest.mock('~/lib/utils/common_utils');
describe('FormUrlApp', () => {
let wrapper;
@@ -26,8 +30,11 @@ describe('FormUrlApp', () => {
const findAllUrlMaskItems = () => wrapper.findAllComponents(FormUrlMaskItem);
const findAddItem = () => wrapper.findComponent(GlLink);
const findFormUrl = () => wrapper.findByTestId('form-url');
+ const findFormUrlGroup = () => wrapper.findAllComponents(GlFormGroup).at(0);
const findFormUrlPreview = () => wrapper.findByTestId('form-url-preview');
const findUrlMaskSection = () => wrapper.findByTestId('url-mask-section');
+ const findFormEl = () => document.querySelector('.js-webhook-form');
+ const submitForm = () => findFormEl().dispatchEvent(new Event('submit'));
describe('template', () => {
it('renders radio buttons for URL masking', () => {
@@ -60,8 +67,10 @@ describe('FormUrlApp', () => {
expect(findAllUrlMaskItems()).toHaveLength(1);
const firstItem = findAllUrlMaskItems().at(0);
- expect(firstItem.props('itemKey')).toBeNull();
- expect(firstItem.props('itemValue')).toBeNull();
+ expect(firstItem.props()).toMatchObject({
+ itemKey: null,
+ itemValue: null,
+ });
});
});
@@ -90,12 +99,18 @@ describe('FormUrlApp', () => {
expect(findAllUrlMaskItems()).toHaveLength(2);
const firstItem = findAllUrlMaskItems().at(0);
- expect(firstItem.props('itemKey')).toBe(mockItem1.key);
- expect(firstItem.props('itemValue')).toBe(mockItem1.value);
+ expect(firstItem.props()).toMatchObject({
+ itemKey: mockItem1.key,
+ itemValue: mockItem1.value,
+ isEditing: true,
+ });
const secondItem = findAllUrlMaskItems().at(1);
- expect(secondItem.props('itemKey')).toBe(mockItem2.key);
- expect(secondItem.props('itemValue')).toBe(mockItem2.value);
+ expect(secondItem.props()).toMatchObject({
+ itemKey: mockItem2.key,
+ itemValue: mockItem2.value,
+ isEditing: true,
+ });
});
describe('on mask item input', () => {
@@ -106,8 +121,10 @@ describe('FormUrlApp', () => {
firstItem.vm.$emit('input', mockInput);
await nextTick();
- expect(firstItem.props('itemKey')).toBe(mockInput.key);
- expect(firstItem.props('itemValue')).toBe(mockInput.value);
+ expect(firstItem.props()).toMatchObject({
+ itemKey: mockInput.key,
+ itemValue: mockInput.value,
+ });
});
});
@@ -119,8 +136,10 @@ describe('FormUrlApp', () => {
expect(findAllUrlMaskItems()).toHaveLength(3);
const lastItem = findAllUrlMaskItems().at(-1);
- expect(lastItem.props('itemKey')).toBeNull();
- expect(lastItem.props('itemValue')).toBeNull();
+ expect(lastItem.props()).toMatchObject({
+ itemKey: null,
+ itemValue: null,
+ });
});
});
@@ -133,8 +152,88 @@ describe('FormUrlApp', () => {
expect(findAllUrlMaskItems()).toHaveLength(1);
const newFirstItem = findAllUrlMaskItems().at(0);
- expect(newFirstItem.props('itemKey')).toBe(mockItem2.key);
- expect(newFirstItem.props('itemValue')).toBe(mockItem2.value);
+ expect(newFirstItem.props()).toMatchObject({
+ itemKey: mockItem2.key,
+ itemValue: mockItem2.value,
+ });
+ });
+ });
+ });
+
+ describe('validations', () => {
+ const inputRequiredText = FormUrlApp.i18n.inputRequired;
+
+ beforeEach(() => {
+ setHTMLFixture('<form class="js-webhook-form"></form>');
+ });
+
+ afterEach(() => {
+ resetHTMLFixture();
+ });
+
+ it.each`
+ url | state | scrollToElementCalls
+ ${null} | ${undefined} | ${1}
+ ${''} | ${undefined} | ${1}
+ ${'https://example.com/'} | ${'true'} | ${0}
+ `('when URL is `$url`, state is `$state`', async ({ url, state, scrollToElementCalls }) => {
+ createComponent({
+ props: { initialUrl: url },
+ });
+
+ submitForm();
+ await nextTick();
+
+ expect(findFormUrlGroup().attributes('state')).toBe(state);
+ expect(scrollToElement).toHaveBeenCalledTimes(scrollToElementCalls);
+ expect(findFormUrlGroup().attributes('invalid-feedback')).toBe(inputRequiredText);
+ });
+
+ it.each`
+ key | value | keyInvalidFeedback | valueInvalidFeedback | scrollToElementCalls
+ ${null} | ${null} | ${inputRequiredText} | ${inputRequiredText} | ${1}
+ ${null} | ${'random'} | ${inputRequiredText} | ${FormUrlApp.i18n.valuePartOfUrl} | ${1}
+ ${null} | ${'secret'} | ${inputRequiredText} | ${null} | ${1}
+ ${'key'} | ${null} | ${null} | ${inputRequiredText} | ${1}
+ ${'key'} | ${'secret'} | ${null} | ${null} | ${0}
+ `(
+ 'when key is `$key` and value is `$value`',
+ async ({ key, value, keyInvalidFeedback, valueInvalidFeedback, scrollToElementCalls }) => {
+ createComponent({
+ props: { initialUrl: 'http://example.com?password=secret' },
+ });
+ findRadioGroup().vm.$emit('input', true);
+ await nextTick();
+
+ const maskItem = findAllUrlMaskItems().at(0);
+ const mockInput = { index: 0, key, value };
+ maskItem.vm.$emit('input', mockInput);
+
+ submitForm();
+ await nextTick();
+
+ expect(maskItem.props('keyInvalidFeedback')).toBe(keyInvalidFeedback);
+ expect(maskItem.props('valueInvalidFeedback')).toBe(valueInvalidFeedback);
+ expect(scrollToElement).toHaveBeenCalledTimes(scrollToElementCalls);
+ },
+ );
+
+ describe('when initialUrlVariables is passed', () => {
+ it('does not validate empty values', async () => {
+ const initialUrlVariables = [{ key: 'key' }];
+
+ createComponent({
+ props: { initialUrl: 'url', initialUrlVariables },
+ });
+
+ submitForm();
+ await nextTick();
+
+ const maskItem = findAllUrlMaskItems().at(0);
+
+ expect(maskItem.props('keyInvalidFeedback')).toBeNull();
+ expect(maskItem.props('valueInvalidFeedback')).toBeNull();
+ expect(scrollToElement).not.toHaveBeenCalled();
});
});
});
diff --git a/spec/frontend/webhooks/components/form_url_mask_item_spec.js b/spec/frontend/webhooks/components/form_url_mask_item_spec.js
index ab028ef2997..06c743749a6 100644
--- a/spec/frontend/webhooks/components/form_url_mask_item_spec.js
+++ b/spec/frontend/webhooks/components/form_url_mask_item_spec.js
@@ -14,6 +14,7 @@ describe('FormUrlMaskItem', () => {
const mockKey = 'key';
const mockValue = 'value';
const mockInput = 'input';
+ const mockFeedback = 'feedback';
const createComponent = ({ props } = {}) => {
wrapper = shallowMountExtended(FormUrlMaskItem, {
@@ -21,29 +22,80 @@ describe('FormUrlMaskItem', () => {
});
};
- afterEach(() => {
- wrapper.destroy();
- });
-
const findMaskItemKey = () => wrapper.findByTestId('mask-item-key');
const findMaskItemValue = () => wrapper.findByTestId('mask-item-value');
const findRemoveButton = () => wrapper.findComponent(GlButton);
describe('template', () => {
it('renders input for key and value', () => {
- createComponent();
+ createComponent({ props: { itemKey: mockKey, itemValue: mockValue } });
const keyInput = findMaskItemKey();
- expect(keyInput.attributes('label')).toBe(FormUrlMaskItem.i18n.keyLabel);
- expect(keyInput.findComponent(GlFormInput).attributes('name')).toBe(
- 'hook[url_variables][][key]',
- );
+ expect(keyInput.attributes()).toMatchObject({
+ label: FormUrlMaskItem.i18n.keyLabel,
+ state: 'true',
+ });
+ expect(keyInput.findComponent(GlFormInput).attributes()).toMatchObject({
+ name: 'hook[url_variables][][key]',
+ value: mockKey,
+ });
const valueInput = findMaskItemValue();
- expect(valueInput.attributes('label')).toBe(FormUrlMaskItem.i18n.valueLabel);
- expect(valueInput.findComponent(GlFormInput).attributes('name')).toBe(
- 'hook[url_variables][][value]',
- );
+ expect(valueInput.attributes()).toMatchObject({
+ label: FormUrlMaskItem.i18n.valueLabel,
+ state: 'true',
+ });
+ expect(valueInput.findComponent(GlFormInput).attributes()).toMatchObject({
+ name: 'hook[url_variables][][value]',
+ value: mockValue,
+ });
+ });
+
+ describe('when isEditing is true', () => {
+ beforeEach(() => {
+ createComponent({ props: { isEditing: true } });
+ });
+
+ it('renders disabled key and value', () => {
+ expect(findMaskItemKey().findComponent(GlFormInput).attributes('disabled')).toBe('true');
+ expect(findMaskItemValue().findComponent(GlFormInput).attributes('disabled')).toBe('true');
+ });
+
+ it('renders disabled remove button', () => {
+ expect(findRemoveButton().attributes('disabled')).toBe('true');
+ });
+
+ it('displays ************ as input value', () => {
+ expect(findMaskItemValue().findComponent(GlFormInput).attributes('value')).toBe(
+ '************',
+ );
+ });
+ });
+
+ describe('when keyInvalidFeedback is passed', () => {
+ beforeEach(() => {
+ createComponent({
+ props: { keyInvalidFeedback: mockFeedback },
+ });
+ });
+
+ it('sets validation message on key', () => {
+ expect(findMaskItemKey().attributes('invalid-feedback')).toBe(mockFeedback);
+ expect(findMaskItemKey().attributes('state')).toBeUndefined();
+ });
+ });
+
+ describe('when valueInvalidFeedback is passed', () => {
+ beforeEach(() => {
+ createComponent({
+ props: { valueInvalidFeedback: mockFeedback },
+ });
+ });
+
+ it('sets validation message on value', () => {
+ expect(findMaskItemValue().attributes('invalid-feedback')).toBe(mockFeedback);
+ expect(findMaskItemValue().attributes('state')).toBeUndefined();
+ });
});
describe('on key input', () => {
diff --git a/spec/frontend/webhooks/components/push_events_spec.js b/spec/frontend/webhooks/components/push_events_spec.js
new file mode 100644
index 00000000000..ccb61c4049a
--- /dev/null
+++ b/spec/frontend/webhooks/components/push_events_spec.js
@@ -0,0 +1,117 @@
+import { nextTick } from 'vue';
+import { GlFormCheckbox, GlFormRadioGroup } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import PushEvents from '~/webhooks/components/push_events.vue';
+
+describe('Webhook push events form editor component', () => {
+ let wrapper;
+
+ const findPushEventsCheckBox = (w = wrapper) => w.findComponent(GlFormCheckbox);
+ const findPushEventsIndicator = (w = wrapper) => w.find('input[name="hook[push_events]"]');
+ const findPushEventRulesGroup = (w = wrapper) => w.findComponent(GlFormRadioGroup);
+ const getPushEventsRuleValue = (w = wrapper) => findPushEventRulesGroup(w).vm.$attrs.checked;
+ const findWildcardRuleInput = (w = wrapper) => w.findByTestId('webhook_branch_filter_field');
+ const findRegexRuleInput = (w = wrapper) => w.findByTestId('webhook_branch_filter_field');
+
+ const createComponent = (provides) =>
+ shallowMountExtended(PushEvents, {
+ provide: {
+ isNewHook: true,
+ pushEvents: false,
+ strategy: 'wildcard',
+ pushEventsBranchFilter: '',
+ ...provides,
+ },
+ });
+
+ describe('Renders push events checkbox', () => {
+ it('when it is a new hook', async () => {
+ wrapper = createComponent({
+ isNewHook: true,
+ });
+ await nextTick();
+
+ const checkbox = findPushEventsCheckBox();
+ expect(checkbox.exists()).toBe(true);
+ expect(findPushEventRulesGroup().exists()).toBe(false);
+ expect(findPushEventsIndicator().attributes('value')).toBe('false');
+ });
+
+ it('when it is not a new hook and push events is enabled', async () => {
+ wrapper = createComponent({
+ isNewHook: false,
+ pushEvents: true,
+ });
+ await nextTick();
+
+ expect(findPushEventsCheckBox().exists()).toBe(true);
+ expect(findPushEventRulesGroup().exists()).toBe(true);
+ expect(findPushEventsIndicator().attributes('value')).toBe('true');
+ });
+ });
+
+ describe('Different push events rules', () => {
+ describe('when editing new hook', () => {
+ beforeEach(async () => {
+ wrapper = createComponent({
+ isNewHook: true,
+ });
+ await nextTick();
+ await findPushEventsCheckBox().vm.$emit('input', true);
+ await nextTick();
+ });
+
+ it('all_branches should be selected by default', async () => {
+ expect(findPushEventRulesGroup().element).toMatchSnapshot();
+ });
+
+ it('should be able to set wildcard rule', async () => {
+ expect(getPushEventsRuleValue()).toBe('all_branches');
+ expect(findWildcardRuleInput().exists()).toBe(false);
+ expect(findRegexRuleInput().exists()).toBe(false);
+
+ await findPushEventRulesGroup(wrapper).vm.$emit('input', 'wildcard');
+ expect(findWildcardRuleInput().exists()).toBe(true);
+ expect(findPushEventRulesGroup().element).toMatchSnapshot();
+
+ const testVal = 'test-val';
+ findWildcardRuleInput().vm.$emit('input', testVal);
+ await nextTick();
+ expect(findWildcardRuleInput().attributes('value')).toBe(testVal);
+ });
+
+ it('should be able to set regex rule', async () => {
+ expect(getPushEventsRuleValue()).toBe('all_branches');
+ expect(findRegexRuleInput().exists()).toBe(false);
+ expect(findWildcardRuleInput().exists()).toBe(false);
+
+ await findPushEventRulesGroup(wrapper).vm.$emit('input', 'regex');
+ expect(findRegexRuleInput().exists()).toBe(true);
+ expect(findPushEventRulesGroup().element).toMatchSnapshot();
+
+ const testVal = 'test-val';
+ findRegexRuleInput().vm.$emit('input', testVal);
+ await nextTick();
+ expect(findRegexRuleInput().attributes('value')).toBe(testVal);
+ });
+ });
+
+ describe('when editing existing hook', () => {
+ it.each(['all_branches', 'wildcard', 'regex'])(
+ 'with "%s" strategy selected',
+ async (strategy) => {
+ wrapper = createComponent({
+ isNewHook: false,
+ pushEvents: true,
+ pushEventsBranchFilter: 'foo',
+ strategy,
+ });
+ await nextTick();
+
+ expect(findPushEventsIndicator().attributes('value')).toBe('true');
+ expect(findPushEventRulesGroup().element).toMatchSnapshot();
+ },
+ );
+ });
+ });
+});
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 1b204b6fd60..7367212e49f 100644
--- a/spec/frontend/work_items/components/work_item_assignees_spec.js
+++ b/spec/frontend/work_items/components/work_item_assignees_spec.js
@@ -8,7 +8,7 @@ import { mockTracking } from 'helpers/tracking_helper';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import userSearchQuery from '~/graphql_shared/queries/users_search.query.graphql';
import currentUserQuery from '~/graphql_shared/queries/current_user.query.graphql';
-import { temporaryConfig } from '~/graphql_shared/issuable_client';
+import { config } from '~/graphql_shared/issuable_client';
import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
@@ -86,7 +86,7 @@ describe('WorkItemAssignees component', () => {
],
{},
{
- typePolicies: temporaryConfig.cacheConfig.typePolicies,
+ typePolicies: config.cacheConfig.typePolicies,
},
);
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
new file mode 100644
index 00000000000..01ab7824975
--- /dev/null
+++ b/spec/frontend/work_items/components/work_item_description_rendered_spec.js
@@ -0,0 +1,108 @@
+import { shallowMount } from '@vue/test-utils';
+import $ from 'jquery';
+import { nextTick } from 'vue';
+import WorkItemDescriptionRendered from '~/work_items/components/work_item_description_rendered.vue';
+import { descriptionTextWithCheckboxes, descriptionHtmlWithCheckboxes } from '../mock_data';
+
+describe('WorkItemDescription', () => {
+ let wrapper;
+
+ const findEditButton = () => wrapper.find('[data-testid="edit-description"]');
+ const findCheckboxAtIndex = (index) => wrapper.findAll('input[type="checkbox"]').at(index);
+
+ const defaultWorkItemDescription = {
+ description: descriptionTextWithCheckboxes,
+ descriptionHtml: descriptionHtmlWithCheckboxes,
+ };
+
+ const createComponent = ({
+ workItemDescription = defaultWorkItemDescription,
+ canEdit = false,
+ } = {}) => {
+ wrapper = shallowMount(WorkItemDescriptionRendered, {
+ propsData: {
+ workItemDescription,
+ canEdit,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders gfm', async () => {
+ const renderGFMSpy = jest.spyOn($.fn, 'renderGFM');
+
+ createComponent();
+
+ await nextTick();
+
+ expect(renderGFMSpy).toHaveBeenCalled();
+ });
+
+ describe('with checkboxes', () => {
+ beforeEach(() => {
+ createComponent({
+ canEdit: true,
+ workItemDescription: {
+ description: `- [x] todo 1\n- [ ] todo 2`,
+ descriptionHtml: `<ul dir="auto" class="task-list" data-sourcepos="1:1-4:0">
+<li class="task-list-item" data-sourcepos="1:1-2:15">
+<input checked="" class="task-list-item-checkbox" type="checkbox"> todo 1</li>
+<li class="task-list-item" data-sourcepos="2:1-2:15">
+<input class="task-list-item-checkbox" type="checkbox"> todo 2</li>
+</ul>`,
+ },
+ });
+ });
+
+ it('checks unchecked checkbox', async () => {
+ findCheckboxAtIndex(1).setChecked();
+
+ await nextTick();
+
+ const updatedDescription = `- [x] todo 1\n- [x] todo 2`;
+ expect(wrapper.emitted('descriptionUpdated')).toEqual([[updatedDescription]]);
+ });
+
+ it('disables checkbox while updating', async () => {
+ findCheckboxAtIndex(1).setChecked();
+
+ await nextTick();
+
+ expect(findCheckboxAtIndex(1).attributes().disabled).toBeDefined();
+ });
+
+ it('unchecks checked checkbox', async () => {
+ findCheckboxAtIndex(0).setChecked(false);
+
+ await nextTick();
+
+ const updatedDescription = `- [ ] todo 1\n- [ ] todo 2`;
+ expect(wrapper.emitted('descriptionUpdated')).toEqual([[updatedDescription]]);
+ });
+ });
+
+ describe('Edit button', () => {
+ it('is not visible when canUpdate = false', async () => {
+ await createComponent({
+ canUpdate: false,
+ });
+
+ expect(findEditButton().exists()).toBe(false);
+ });
+
+ it('toggles edit mode', async () => {
+ createComponent({
+ canEdit: true,
+ });
+
+ findEditButton().vm.$emit('click');
+
+ await nextTick();
+
+ expect(wrapper.emitted('startEditing')).toEqual([[]]);
+ });
+ });
+});
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 0691fe25e0d..c79b049442d 100644
--- a/spec/frontend/work_items/components/work_item_description_spec.js
+++ b/spec/frontend/work_items/components/work_item_description_spec.js
@@ -8,21 +8,23 @@ import EditedAt from '~/issues/show/components/edited.vue';
import { updateDraft } from '~/lib/utils/autosave';
import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
+import MarkdownEditor from '~/vue_shared/components/markdown/markdown_editor.vue';
import WorkItemDescription from '~/work_items/components/work_item_description.vue';
+import WorkItemDescriptionRendered from '~/work_items/components/work_item_description_rendered.vue';
import { TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
+import workItemDescriptionSubscription from '~/work_items/graphql/work_item_description.subscription.graphql';
import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
+import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql';
import {
updateWorkItemMutationResponse,
+ workItemDescriptionSubscriptionResponse,
workItemResponseFactory,
workItemQueryResponse,
+ projectWorkItemResponse,
} from '../mock_data';
-jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal', () => {
- return {
- confirmAction: jest.fn(),
- };
-});
+jest.mock('~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal');
jest.mock('~/lib/utils/autosave');
const workItemId = workItemQueryResponse.data.workItem.id;
@@ -33,12 +35,22 @@ describe('WorkItemDescription', () => {
Vue.use(VueApollo);
const mutationSuccessHandler = jest.fn().mockResolvedValue(updateWorkItemMutationResponse);
+ const subscriptionHandler = jest.fn().mockResolvedValue(workItemDescriptionSubscriptionResponse);
+ const workItemByIidResponseHandler = jest.fn().mockResolvedValue(projectWorkItemResponse);
+ let workItemResponseHandler;
+ let workItemsMvc2;
- const findEditButton = () => wrapper.find('[data-testid="edit-description"]');
const findMarkdownField = () => wrapper.findComponent(MarkdownField);
+ const findMarkdownEditor = () => wrapper.findComponent(MarkdownEditor);
+ const findRenderedDescription = () => wrapper.findComponent(WorkItemDescriptionRendered);
const findEditedAt = () => wrapper.findComponent(EditedAt);
- const editDescription = (newText) => wrapper.find('textarea').setValue(newText);
+ const editDescription = (newText) => {
+ if (workItemsMvc2) {
+ return findMarkdownEditor().vm.$emit('input', newText);
+ }
+ return wrapper.find('textarea').setValue(newText);
+ };
const clickCancel = () => wrapper.find('[data-testid="cancel"]').vm.$emit('click');
const clickSave = () => wrapper.find('[data-testid="save-description"]').vm.$emit('click', {});
@@ -48,18 +60,30 @@ describe('WorkItemDescription', () => {
canUpdate = true,
workItemResponse = workItemResponseFactory({ canUpdate }),
isEditing = false,
+ fetchByIid = false,
} = {}) => {
- const workItemResponseHandler = jest.fn().mockResolvedValue(workItemResponse);
+ workItemResponseHandler = jest.fn().mockResolvedValue(workItemResponse);
const { id } = workItemQueryResponse.data.workItem;
wrapper = shallowMount(WorkItemDescription, {
apolloProvider: createMockApollo([
[workItemQuery, workItemResponseHandler],
[updateWorkItemMutation, mutationHandler],
+ [workItemDescriptionSubscription, subscriptionHandler],
+ [workItemByIidQuery, workItemByIidResponseHandler],
]),
propsData: {
workItemId: id,
fullPath: 'test-project-path',
+ queryVariables: {
+ id: workItemId,
+ },
+ fetchByIid,
+ },
+ provide: {
+ glFeatures: {
+ workItemsMvc2,
+ },
},
stubs: {
MarkdownField,
@@ -69,7 +93,7 @@ describe('WorkItemDescription', () => {
await waitForPromises();
if (isEditing) {
- findEditButton().vm.$emit('click');
+ findRenderedDescription().vm.$emit('startEditing');
await nextTick();
}
@@ -79,171 +103,178 @@ describe('WorkItemDescription', () => {
wrapper.destroy();
});
- describe('Edit button', () => {
- it('is not visible when canUpdate = false', async () => {
- await createComponent({
- canUpdate: false,
+ describe.each([true, false])(
+ 'editing description with workItemsMvc2 %workItemsMvc2Enabled',
+ (workItemsMvc2Enabled) => {
+ beforeEach(() => {
+ beforeEach(() => {
+ workItemsMvc2 = workItemsMvc2Enabled;
+ });
});
- expect(findEditButton().exists()).toBe(false);
- });
+ describe('editing description', () => {
+ it('shows edited by text', async () => {
+ const lastEditedAt = '2022-09-21T06:18:42Z';
+ const lastEditedBy = {
+ name: 'Administrator',
+ webPath: '/root',
+ };
- it('toggles edit mode', async () => {
- await createComponent({
- canUpdate: true,
- });
+ await createComponent({
+ workItemResponse: workItemResponseFactory({
+ lastEditedAt,
+ lastEditedBy,
+ }),
+ });
- findEditButton().vm.$emit('click');
+ expect(findEditedAt().props()).toEqual({
+ updatedAt: lastEditedAt,
+ updatedByName: lastEditedBy.name,
+ updatedByPath: lastEditedBy.webPath,
+ });
+ });
- await nextTick();
+ it('does not show edited by text', async () => {
+ await createComponent();
- expect(findMarkdownField().exists()).toBe(true);
- });
- });
+ expect(findEditedAt().exists()).toBe(false);
+ });
- describe('editing description', () => {
- it('shows edited by text', async () => {
- const lastEditedAt = '2022-09-21T06:18:42Z';
- const lastEditedBy = {
- name: 'Administrator',
- webPath: '/root',
- };
-
- await createComponent({
- workItemResponse: workItemResponseFactory({
- lastEditedAt,
- lastEditedBy,
- }),
- });
+ it('cancels when clicking cancel', async () => {
+ await createComponent({
+ isEditing: true,
+ });
- expect(findEditedAt().props()).toEqual({
- updatedAt: lastEditedAt,
- updatedByName: lastEditedBy.name,
- updatedByPath: lastEditedBy.webPath,
- });
- });
+ clickCancel();
- it('does not show edited by text', async () => {
- await createComponent();
+ await nextTick();
- expect(findEditedAt().exists()).toBe(false);
- });
+ expect(confirmAction).not.toHaveBeenCalled();
+ expect(findMarkdownField().exists()).toBe(false);
+ });
- it('cancels when clicking cancel', async () => {
- await createComponent({
- isEditing: true,
- });
+ it('prompts for confirmation when clicking cancel after changes', async () => {
+ await createComponent({
+ isEditing: true,
+ });
- clickCancel();
+ editDescription('updated desc');
- await nextTick();
+ clickCancel();
- expect(confirmAction).not.toHaveBeenCalled();
- expect(findMarkdownField().exists()).toBe(false);
- });
+ await nextTick();
- it('prompts for confirmation when clicking cancel after changes', async () => {
- await createComponent({
- isEditing: true,
- });
+ expect(confirmAction).toHaveBeenCalled();
+ });
- editDescription('updated desc');
+ it('calls update widgets mutation', async () => {
+ const updatedDesc = 'updated desc';
- clickCancel();
+ await createComponent({
+ isEditing: true,
+ });
- await nextTick();
+ editDescription(updatedDesc);
- expect(confirmAction).toHaveBeenCalled();
- });
+ clickSave();
- it('calls update widgets mutation', async () => {
- await createComponent({
- isEditing: true,
- });
+ await waitForPromises();
- editDescription('updated desc');
+ expect(mutationSuccessHandler).toHaveBeenCalledWith({
+ input: {
+ id: workItemId,
+ descriptionWidget: {
+ description: updatedDesc,
+ },
+ },
+ });
+ });
- clickSave();
+ it('tracks editing description', async () => {
+ await createComponent({
+ isEditing: true,
+ markdownPreviewPath: '/preview',
+ });
+ const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
- await waitForPromises();
+ clickSave();
- expect(mutationSuccessHandler).toHaveBeenCalledWith({
- input: {
- id: workItemId,
- descriptionWidget: {
- description: 'updated desc',
- },
- },
- });
- });
+ await waitForPromises();
- it('tracks editing description', async () => {
- await createComponent({
- isEditing: true,
- markdownPreviewPath: '/preview',
- });
- const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ expect(trackingSpy).toHaveBeenCalledWith(TRACKING_CATEGORY_SHOW, 'updated_description', {
+ category: TRACKING_CATEGORY_SHOW,
+ label: 'item_description',
+ property: 'type_Task',
+ });
+ });
- clickSave();
+ it('emits error when mutation returns error', async () => {
+ const error = 'eror';
- await waitForPromises();
+ await createComponent({
+ isEditing: true,
+ mutationHandler: jest.fn().mockResolvedValue({
+ data: {
+ workItemUpdate: {
+ workItem: {},
+ errors: [error],
+ },
+ },
+ }),
+ });
- expect(trackingSpy).toHaveBeenCalledWith(TRACKING_CATEGORY_SHOW, 'updated_description', {
- category: TRACKING_CATEGORY_SHOW,
- label: 'item_description',
- property: 'type_Task',
- });
- });
+ editDescription('updated desc');
- it('emits error when mutation returns error', async () => {
- const error = 'eror';
+ clickSave();
- await createComponent({
- isEditing: true,
- mutationHandler: jest.fn().mockResolvedValue({
- data: {
- workItemUpdate: {
- workItem: {},
- errors: [error],
- },
- },
- }),
- });
+ await waitForPromises();
- editDescription('updated desc');
+ expect(wrapper.emitted('error')).toEqual([[error]]);
+ });
- clickSave();
+ it('emits error when mutation fails', async () => {
+ const error = 'eror';
- await waitForPromises();
+ await createComponent({
+ isEditing: true,
+ mutationHandler: jest.fn().mockRejectedValue(new Error(error)),
+ });
- expect(wrapper.emitted('error')).toEqual([[error]]);
- });
+ editDescription('updated desc');
- it('emits error when mutation fails', async () => {
- const error = 'eror';
+ clickSave();
- await createComponent({
- isEditing: true,
- mutationHandler: jest.fn().mockRejectedValue(new Error(error)),
- });
+ await waitForPromises();
- editDescription('updated desc');
+ expect(wrapper.emitted('error')).toEqual([[error]]);
+ });
- clickSave();
+ it('autosaves description', async () => {
+ await createComponent({
+ isEditing: true,
+ });
- await waitForPromises();
+ editDescription('updated desc');
- expect(wrapper.emitted('error')).toEqual([[error]]);
- });
+ expect(updateDraft).toHaveBeenCalled();
+ });
+ });
+
+ it('calls the global ID work item query when `fetchByIid` prop is false', async () => {
+ createComponent({ fetchByIid: false });
+ await waitForPromises();
- it('autosaves description', async () => {
- await createComponent({
- isEditing: true,
+ expect(workItemResponseHandler).toHaveBeenCalled();
+ expect(workItemByIidResponseHandler).not.toHaveBeenCalled();
});
- editDescription('updated desc');
+ it('calls the IID work item query when when `fetchByIid` prop is true', async () => {
+ createComponent({ fetchByIid: true });
+ await waitForPromises();
- expect(updateDraft).toHaveBeenCalled();
- });
- });
+ expect(workItemResponseHandler).not.toHaveBeenCalled();
+ expect(workItemByIidResponseHandler).toHaveBeenCalled();
+ });
+ },
+ );
});
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 6b1ef8971d3..4029e47c390 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
@@ -86,6 +86,7 @@ describe('WorkItemDetailModal component', () => {
isModal: true,
workItemId: defaultPropsData.workItemId,
workItemParentId: defaultPropsData.issueGid,
+ iid: null,
});
});
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 aae61b11196..26777b57797 100644
--- a/spec/frontend/work_items/components/work_item_detail_spec.js
+++ b/spec/frontend/work_items/components/work_item_detail_spec.js
@@ -24,12 +24,13 @@ import WorkItemMilestone from '~/work_items/components/work_item_milestone.vue';
import WorkItemInformation from '~/work_items/components/work_item_information.vue';
import { i18n } from '~/work_items/constants';
import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
+import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql';
import workItemDatesSubscription from '~/work_items/graphql/work_item_dates.subscription.graphql';
import workItemTitleSubscription from '~/work_items/graphql/work_item_title.subscription.graphql';
import workItemAssigneesSubscription from '~/work_items/graphql/work_item_assignees.subscription.graphql';
+import workItemMilestoneSubscription from '~/work_items/graphql/work_item_milestone.subscription.graphql';
import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
import updateWorkItemTaskMutation from '~/work_items/graphql/update_work_item_task.mutation.graphql';
-import { temporaryConfig } from '~/graphql_shared/issuable_client';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import {
mockParent,
@@ -37,6 +38,8 @@ import {
workItemResponseFactory,
workItemTitleSubscriptionResponse,
workItemAssigneesSubscriptionResponse,
+ workItemMilestoneSubscriptionResponse,
+ projectWorkItemResponse,
} from '../mock_data';
describe('WorkItemDetail component', () => {
@@ -52,8 +55,12 @@ describe('WorkItemDetail component', () => {
canDelete: true,
});
const successHandler = jest.fn().mockResolvedValue(workItemQueryResponse);
+ const successByIidHandler = jest.fn().mockResolvedValue(projectWorkItemResponse);
const datesSubscriptionHandler = jest.fn().mockResolvedValue(workItemDatesSubscriptionResponse);
const titleSubscriptionHandler = jest.fn().mockResolvedValue(workItemTitleSubscriptionResponse);
+ const milestoneSubscriptionHandler = jest
+ .fn()
+ .mockResolvedValue(workItemMilestoneSubscriptionResponse);
const assigneesSubscriptionHandler = jest
.fn()
.mockResolvedValue(workItemAssigneesSubscriptionResponse);
@@ -85,26 +92,23 @@ describe('WorkItemDetail component', () => {
subscriptionHandler = titleSubscriptionHandler,
confidentialityMock = [updateWorkItemMutation, jest.fn()],
error = undefined,
- includeWidgets = false,
workItemsMvc2Enabled = false,
+ fetchByIid = false,
+ iidPathQueryParam = undefined,
} = {}) => {
const handlers = [
[workItemQuery, handler],
[workItemTitleSubscription, subscriptionHandler],
[workItemDatesSubscription, datesSubscriptionHandler],
[workItemAssigneesSubscription, assigneesSubscriptionHandler],
+ [workItemMilestoneSubscription, milestoneSubscriptionHandler],
+ [workItemByIidQuery, successByIidHandler],
confidentialityMock,
];
wrapper = shallowMount(WorkItemDetail, {
- apolloProvider: createMockApollo(
- handlers,
- {},
- {
- typePolicies: includeWidgets ? temporaryConfig.cacheConfig.typePolicies : {},
- },
- ),
- propsData: { isModal, workItemId },
+ apolloProvider: createMockApollo(handlers),
+ propsData: { isModal, workItemId, iid: '1' },
data() {
return {
updateInProgress,
@@ -114,15 +118,24 @@ describe('WorkItemDetail component', () => {
provide: {
glFeatures: {
workItemsMvc2: workItemsMvc2Enabled,
+ useIidInWorkItemsPath: fetchByIid,
},
hasIssueWeightsFeature: true,
hasIterationsFeature: true,
projectNamespace: 'namespace',
+ fullPath: 'group/project',
},
stubs: {
WorkItemWeight: true,
WorkItemIteration: true,
},
+ mocks: {
+ $route: {
+ query: {
+ iid_path: iidPathQueryParam,
+ },
+ },
+ },
});
};
@@ -421,8 +434,9 @@ describe('WorkItemDetail component', () => {
});
describe('subscriptions', () => {
- it('calls the title subscription', () => {
+ it('calls the title subscription', async () => {
createComponent();
+ await waitForPromises();
expect(titleSubscriptionHandler).toHaveBeenCalledWith({
issuableId: workItemQueryResponse.data.workItem.id,
@@ -543,15 +557,41 @@ describe('WorkItemDetail component', () => {
describe('milestone widget', () => {
it.each`
- description | includeWidgets | exists
- ${'renders when widget is returned from API'} | ${true} | ${true}
- ${'does not render when widget is not returned from API'} | ${false} | ${false}
- `('$description', async ({ includeWidgets, exists }) => {
- createComponent({ includeWidgets, workItemsMvc2Enabled: true });
+ description | milestoneWidgetPresent | exists
+ ${'renders when widget is returned from API'} | ${true} | ${true}
+ ${'does not render when widget is not returned from API'} | ${false} | ${false}
+ `('$description', async ({ milestoneWidgetPresent, exists }) => {
+ const response = workItemResponseFactory({ milestoneWidgetPresent });
+ const handler = jest.fn().mockResolvedValue(response);
+ createComponent({ handler, workItemsMvc2Enabled: true });
await waitForPromises();
expect(findWorkItemMilestone().exists()).toBe(exists);
});
+
+ describe('milestone subscription', () => {
+ describe('when the milestone widget exists', () => {
+ it('calls the milestone subscription', async () => {
+ createComponent();
+ await waitForPromises();
+
+ expect(milestoneSubscriptionHandler).toHaveBeenCalledWith({
+ issuableId: workItemQueryResponse.data.workItem.id,
+ });
+ });
+ });
+
+ describe('when the assignees widget does not exist', () => {
+ it('does not call the milestone subscription', async () => {
+ const response = workItemResponseFactory({ milestoneWidgetPresent: false });
+ const handler = jest.fn().mockResolvedValue(response);
+ createComponent({ handler });
+ await waitForPromises();
+
+ expect(milestoneSubscriptionHandler).not.toHaveBeenCalled();
+ });
+ });
+ });
});
describe('work item information', () => {
@@ -571,4 +611,35 @@ describe('WorkItemDetail component', () => {
expect(findWorkItemInformationAlert().exists()).toBe(false);
});
});
+
+ it('calls the global ID work item query when `useIidInWorkItemsPath` feature flag is false', async () => {
+ createComponent();
+ await waitForPromises();
+
+ expect(successHandler).toHaveBeenCalledWith({
+ id: workItemQueryResponse.data.workItem.id,
+ });
+ 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 () => {
+ createComponent({ fetchByIid: true, iidPathQueryParam: 'true' });
+ await waitForPromises();
+
+ expect(successHandler).not.toHaveBeenCalled();
+ expect(successByIidHandler).toHaveBeenCalledWith({
+ fullPath: 'group/project',
+ iid: '1',
+ });
+ });
});
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 701406b9588..7ebaf8209c7 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
@@ -140,7 +140,7 @@ describe('WorkItemDueDate component', () => {
beforeEach(() => {
createComponent({ canUpdate: true, dueDate: '2022-12-31', startDate: '2022-12-31' });
- datePickerOpenSpy = jest.spyOn(wrapper.vm.$refs.dueDatePicker.calendar, 'show');
+ datePickerOpenSpy = jest.spyOn(wrapper.vm.$refs.dueDatePicker, 'show');
findStartDatePicker().vm.$emit('input', startDate);
findStartDatePicker().vm.$emit('close');
});
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 e6ff7e8502d..9f7659b3f8d 100644
--- a/spec/frontend/work_items/components/work_item_labels_spec.js
+++ b/spec/frontend/work_items/components/work_item_labels_spec.js
@@ -9,6 +9,7 @@ import labelSearchQuery from '~/vue_shared/components/sidebar/labels_select_widg
import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
import workItemLabelsSubscription from 'ee_else_ce/work_items/graphql/work_item_labels.subscription.graphql';
import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
+import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql';
import WorkItemLabels from '~/work_items/components/work_item_labels.vue';
import { i18n, I18N_WORK_ITEM_ERROR_FETCHING_LABELS } from '~/work_items/constants';
import {
@@ -18,6 +19,7 @@ import {
workItemResponseFactory,
updateWorkItemMutationResponse,
workItemLabelsSubscriptionResponse,
+ projectWorkItemResponse,
} from '../mock_data';
Vue.use(VueApollo);
@@ -33,6 +35,7 @@ describe('WorkItemLabels component', () => {
const findLabelsTitle = () => wrapper.findByTestId('labels-title');
const workItemQuerySuccess = jest.fn().mockResolvedValue(workItemQueryResponse);
+ const workItemByIidResponseHandler = jest.fn().mockResolvedValue(projectWorkItemResponse);
const successSearchQueryHandler = jest.fn().mockResolvedValue(projectLabelsResponse);
const successUpdateWorkItemMutationHandler = jest
.fn()
@@ -45,12 +48,14 @@ describe('WorkItemLabels component', () => {
workItemQueryHandler = workItemQuerySuccess,
searchQueryHandler = successSearchQueryHandler,
updateWorkItemMutationHandler = successUpdateWorkItemMutationHandler,
+ fetchByIid = false,
} = {}) => {
const apolloProvider = createMockApollo([
[workItemQuery, workItemQueryHandler],
[labelSearchQuery, searchQueryHandler],
[updateWorkItemMutation, updateWorkItemMutationHandler],
[workItemLabelsSubscription, subscriptionHandler],
+ [workItemByIidQuery, workItemByIidResponseHandler],
]);
wrapper = mountExtended(WorkItemLabels, {
@@ -58,6 +63,10 @@ describe('WorkItemLabels component', () => {
workItemId,
canUpdate,
fullPath: 'test-project-path',
+ queryVariables: {
+ id: workItemId,
+ },
+ fetchByIid,
},
attachTo: document.body,
apolloProvider,
@@ -226,4 +235,20 @@ describe('WorkItemLabels component', () => {
});
});
});
+
+ it('calls the global ID work item query when `fetchByIid` prop is false', async () => {
+ createComponent({ fetchByIid: false });
+ await waitForPromises();
+
+ expect(workItemQuerySuccess).toHaveBeenCalled();
+ expect(workItemByIidResponseHandler).not.toHaveBeenCalled();
+ });
+
+ it('calls the IID work item query when when `fetchByIid` prop is true', async () => {
+ createComponent({ fetchByIid: true });
+ await waitForPromises();
+
+ expect(workItemQuerySuccess).not.toHaveBeenCalled();
+ expect(workItemByIidResponseHandler).toHaveBeenCalled();
+ });
});
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 ab3ea623e3e..071d5fb715a 100644
--- a/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js
+++ b/spec/frontend/work_items/components/work_item_links/work_item_links_form_spec.js
@@ -1,10 +1,11 @@
import Vue from 'vue';
-import { GlForm, GlFormInput, GlFormCombobox } from '@gitlab/ui';
+import { GlForm, GlFormInput, GlTokenSelector } from '@gitlab/ui';
import VueApollo from 'vue-apollo';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
import WorkItemLinksForm from '~/work_items/components/work_item_links/work_item_links_form.vue';
+import { FORM_TYPES } from '~/work_items/constants';
import projectWorkItemsQuery from '~/work_items/graphql/project_work_items.query.graphql';
import projectWorkItemTypesQuery from '~/work_items/graphql/project_work_item_types.query.graphql';
import createWorkItemMutation from '~/work_items/graphql/create_work_item.mutation.graphql';
@@ -14,6 +15,7 @@ import {
projectWorkItemTypesQueryResponse,
createWorkItemMutationResponse,
updateWorkItemMutationResponse,
+ mockIterationWidgetResponse,
} from '../../mock_data';
Vue.use(VueApollo);
@@ -23,22 +25,35 @@ describe('WorkItemLinksForm', () => {
const updateMutationResolver = jest.fn().mockResolvedValue(updateWorkItemMutationResponse);
const createMutationResolver = jest.fn().mockResolvedValue(createWorkItemMutationResponse);
+ const availableWorkItemsResolver = jest.fn().mockResolvedValue(availableWorkItemsResponse);
+
+ const mockParentIteration = mockIterationWidgetResponse;
const createComponent = async ({
- listResponse = availableWorkItemsResponse,
typesResponse = projectWorkItemTypesQueryResponse,
parentConfidential = false,
hasIterationsFeature = false,
+ workItemsMvc2Enabled = false,
+ parentIteration = null,
+ formType = FORM_TYPES.create,
} = {}) => {
wrapper = shallowMountExtended(WorkItemLinksForm, {
apolloProvider: createMockApollo([
- [projectWorkItemsQuery, jest.fn().mockResolvedValue(listResponse)],
+ [projectWorkItemsQuery, availableWorkItemsResolver],
[projectWorkItemTypesQuery, jest.fn().mockResolvedValue(typesResponse)],
[updateWorkItemMutation, updateMutationResolver],
[createWorkItemMutation, createMutationResolver],
]),
- propsData: { issuableGid: 'gid://gitlab/WorkItem/1', parentConfidential },
+ propsData: {
+ issuableGid: 'gid://gitlab/WorkItem/1',
+ parentConfidential,
+ parentIteration,
+ formType,
+ },
provide: {
+ glFeatures: {
+ workItemsMvc2: workItemsMvc2Enabled,
+ },
projectPath: 'project/path',
hasIterationsFeature,
},
@@ -48,89 +63,155 @@ describe('WorkItemLinksForm', () => {
};
const findForm = () => wrapper.findComponent(GlForm);
- const findCombobox = () => wrapper.findComponent(GlFormCombobox);
+ const findTokenSelector = () => wrapper.findComponent(GlTokenSelector);
const findInput = () => wrapper.findComponent(GlFormInput);
const findAddChildButton = () => wrapper.findByTestId('add-child-button');
- beforeEach(async () => {
- await createComponent();
- });
-
afterEach(() => {
wrapper.destroy();
});
- it('renders form', () => {
- expect(findForm().exists()).toBe(true);
- });
-
- it('creates child task in non confidential parent', async () => {
- findInput().vm.$emit('input', 'Create task test');
+ describe('creating a new work item', () => {
+ beforeEach(async () => {
+ await createComponent();
+ });
- findForm().vm.$emit('submit', {
- preventDefault: jest.fn(),
+ it('renders create form', () => {
+ expect(findForm().exists()).toBe(true);
+ expect(findInput().exists()).toBe(true);
+ expect(findAddChildButton().text()).toBe('Create task');
+ expect(findTokenSelector().exists()).toBe(false);
});
- await waitForPromises();
- expect(createMutationResolver).toHaveBeenCalledWith({
- input: {
- title: 'Create task test',
- projectPath: 'project/path',
- workItemTypeId: 'gid://gitlab/WorkItems::Type/3',
- hierarchyWidget: {
- parentId: 'gid://gitlab/WorkItem/1',
+
+ it('creates child task in non confidential parent', async () => {
+ findInput().vm.$emit('input', 'Create task test');
+
+ findForm().vm.$emit('submit', {
+ preventDefault: jest.fn(),
+ });
+ await waitForPromises();
+ expect(createMutationResolver).toHaveBeenCalledWith({
+ input: {
+ title: 'Create task test',
+ projectPath: 'project/path',
+ workItemTypeId: 'gid://gitlab/WorkItems::Type/3',
+ hierarchyWidget: {
+ parentId: 'gid://gitlab/WorkItem/1',
+ },
+ confidential: false,
},
- confidential: false,
- },
+ });
});
- });
- it('creates child task in confidential parent', async () => {
- await createComponent({ parentConfidential: true });
+ it('creates child task in confidential parent', async () => {
+ await createComponent({ parentConfidential: true });
- findInput().vm.$emit('input', 'Create confidential task');
+ findInput().vm.$emit('input', 'Create confidential task');
- findForm().vm.$emit('submit', {
- preventDefault: jest.fn(),
- });
- await waitForPromises();
- expect(createMutationResolver).toHaveBeenCalledWith({
- input: {
- title: 'Create confidential task',
- projectPath: 'project/path',
- workItemTypeId: 'gid://gitlab/WorkItems::Type/3',
- hierarchyWidget: {
- parentId: 'gid://gitlab/WorkItem/1',
+ findForm().vm.$emit('submit', {
+ preventDefault: jest.fn(),
+ });
+ await waitForPromises();
+ expect(createMutationResolver).toHaveBeenCalledWith({
+ input: {
+ title: 'Create confidential task',
+ projectPath: 'project/path',
+ workItemTypeId: 'gid://gitlab/WorkItems::Type/3',
+ hierarchyWidget: {
+ parentId: 'gid://gitlab/WorkItem/1',
+ },
+ confidential: true,
},
- confidential: true,
- },
+ });
});
});
- // Follow up issue to turn this functionality back on https://gitlab.com/gitlab-org/gitlab/-/issues/368757
- // eslint-disable-next-line jest/no-disabled-tests
- it.skip('selects and add child', async () => {
- findCombobox().vm.$emit('input', availableWorkItemsResponse.data.workspace.workItems.edges[0]);
+ describe('adding an existing work item', () => {
+ beforeEach(async () => {
+ await createComponent({ formType: FORM_TYPES.add });
+ });
- findAddChildButton().vm.$emit('click');
- await waitForPromises();
- expect(updateMutationResolver).toHaveBeenCalled();
- });
+ it('renders add form', () => {
+ expect(findForm().exists()).toBe(true);
+ expect(findTokenSelector().exists()).toBe(true);
+ expect(findAddChildButton().text()).toBe('Add task');
+ expect(findInput().exists()).toBe(false);
+ });
- // eslint-disable-next-line jest/no-disabled-tests
- describe.skip('when typing in combobox', () => {
- beforeEach(async () => {
- findCombobox().vm.$emit('input', 'Task');
+ it('searches for available work items as prop when typing in input', async () => {
+ findTokenSelector().vm.$emit('focus');
+ findTokenSelector().vm.$emit('text-input', 'Task');
await waitForPromises();
- await jest.runOnlyPendingTimers();
+
+ expect(availableWorkItemsResolver).toHaveBeenCalled();
});
- it('passes available work items as prop', () => {
- expect(findCombobox().exists()).toBe(true);
- expect(findCombobox().props('tokenList').length).toBe(2);
+ it('selects and adds children', async () => {
+ findTokenSelector().vm.$emit(
+ 'input',
+ availableWorkItemsResponse.data.workspace.workItems.nodes,
+ );
+ findTokenSelector().vm.$emit('blur', new FocusEvent({ relatedTarget: null }));
+
+ await waitForPromises();
+
+ expect(findAddChildButton().text()).toBe('Add tasks');
+ findForm().vm.$emit('submit', {
+ preventDefault: jest.fn(),
+ });
+ await waitForPromises();
+ expect(updateMutationResolver).toHaveBeenCalled();
});
+ });
+
+ describe('associate iteration with task', () => {
+ it('does not update iteration when mvc2 feature flag is not enabled', async () => {
+ await createComponent({
+ hasIterationsFeature: true,
+ parentIteration: mockParentIteration,
+ });
- it('passes action to create task', () => {
- expect(findCombobox().props('actionList').length).toBe(1);
+ findInput().vm.$emit('input', 'Create task test');
+
+ findForm().vm.$emit('submit', {
+ preventDefault: jest.fn(),
+ });
+ await waitForPromises();
+ expect(updateMutationResolver).not.toHaveBeenCalled();
+ });
+ it('updates when parent has an iteration associated', async () => {
+ await createComponent({
+ workItemsMvc2Enabled: true,
+ hasIterationsFeature: true,
+ parentIteration: mockParentIteration,
+ });
+ findInput().vm.$emit('input', 'Create task test');
+
+ findForm().vm.$emit('submit', {
+ preventDefault: jest.fn(),
+ });
+ await waitForPromises();
+ expect(updateMutationResolver).toHaveBeenCalledWith({
+ input: {
+ id: 'gid://gitlab/WorkItem/1',
+ iterationWidget: {
+ iterationId: mockParentIteration.id,
+ },
+ },
+ });
+ });
+ it('does not update when parent has no iteration associated', async () => {
+ await createComponent({
+ workItemsMvc2Enabled: true,
+ hasIterationsFeature: true,
+ });
+ findInput().vm.$emit('input', 'Create task test');
+
+ findForm().vm.$emit('submit', {
+ preventDefault: jest.fn(),
+ });
+ await waitForPromises();
+ expect(updateMutationResolver).not.toHaveBeenCalled();
});
});
});
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 6961996f912..66ce2c1becf 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
@@ -8,6 +8,7 @@ import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import issueDetailsQuery from 'ee_else_ce/work_items/graphql/get_issue_details.query.graphql';
import WorkItemLinks from '~/work_items/components/work_item_links/work_item_links.vue';
import WorkItemLinkChild from '~/work_items/components/work_item_links/work_item_link_child.vue';
+import { FORM_TYPES } from '~/work_items/constants';
import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
import changeWorkItemParentMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
import getWorkItemLinksQuery from '~/work_items/graphql/work_item_links.query.graphql';
@@ -41,6 +42,13 @@ const issueDetailsResponse = (confidential = false) => ({
},
__typename: 'Iteration',
},
+ milestone: {
+ dueDate: null,
+ expired: false,
+ id: 'gid://gitlab/Milestone/28',
+ title: 'v2.0',
+ __typename: 'Milestone',
+ },
__typename: 'Issue',
},
__typename: 'Project',
@@ -107,7 +115,9 @@ describe('WorkItemLinks', () => {
const findToggleButton = () => wrapper.findByTestId('toggle-links');
const findLinksBody = () => wrapper.findByTestId('links-body');
const findEmptyState = () => wrapper.findByTestId('links-empty');
+ const findToggleFormDropdown = () => wrapper.findByTestId('toggle-form');
const findToggleAddFormButton = () => wrapper.findByTestId('toggle-add-form');
+ const findToggleCreateFormButton = () => wrapper.findByTestId('toggle-create-form');
const findWorkItemLinkChildItems = () => wrapper.findAllComponents(WorkItemLinkChild);
const findFirstWorkItemLinkChild = () => findWorkItemLinkChildItems().at(0);
const findAddLinksForm = () => wrapper.findByTestId('add-links-form');
@@ -136,11 +146,27 @@ describe('WorkItemLinks', () => {
});
describe('add link form', () => {
- it('displays form on click add button and hides form on cancel', async () => {
+ it('displays add work item form on click add dropdown then add existing button and hides form on cancel', async () => {
+ findToggleFormDropdown().vm.$emit('click');
findToggleAddFormButton().vm.$emit('click');
await nextTick();
expect(findAddLinksForm().exists()).toBe(true);
+ expect(findAddLinksForm().props('formType')).toBe(FORM_TYPES.add);
+
+ findAddLinksForm().vm.$emit('cancel');
+ await nextTick();
+
+ expect(findAddLinksForm().exists()).toBe(false);
+ });
+
+ it('displays create work item form on click add dropdown then create button and hides form on cancel', async () => {
+ findToggleFormDropdown().vm.$emit('click');
+ findToggleCreateFormButton().vm.$emit('click');
+ await nextTick();
+
+ expect(findAddLinksForm().exists()).toBe(true);
+ expect(findAddLinksForm().props('formType')).toBe(FORM_TYPES.create);
findAddLinksForm().vm.$emit('cancel');
await nextTick();
@@ -193,7 +219,7 @@ describe('WorkItemLinks', () => {
});
it('does not display button to toggle Add form', () => {
- expect(findToggleAddFormButton().exists()).toBe(false);
+ expect(findToggleFormDropdown().exists()).toBe(false);
});
it('does not display link menu on children', () => {
@@ -283,6 +309,7 @@ describe('WorkItemLinks', () => {
await createComponent({
issueDetailsQueryHandler: jest.fn().mockResolvedValue(issueDetailsResponse(true)),
});
+ findToggleFormDropdown().vm.$emit('click');
findToggleAddFormButton().vm.$emit('click');
await nextTick();
diff --git a/spec/frontend/work_items/components/work_item_milestone_spec.js b/spec/frontend/work_items/components/work_item_milestone_spec.js
index 08cdf62ae52..60ba2b55f76 100644
--- a/spec/frontend/work_items/components/work_item_milestone_spec.js
+++ b/spec/frontend/work_items/components/work_item_milestone_spec.js
@@ -9,7 +9,7 @@ import {
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import WorkItemMilestone from '~/work_items/components/work_item_milestone.vue';
-import { resolvers, temporaryConfig } from '~/graphql_shared/issuable_client';
+import { resolvers, config } from '~/graphql_shared/issuable_client';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mockTracking } from 'helpers/tracking_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
@@ -22,8 +22,14 @@ import {
mockMilestoneWidgetResponse,
workItemResponseFactory,
updateWorkItemMutationErrorResponse,
+ workItemMilestoneSubscriptionResponse,
+ projectWorkItemResponse,
+ updateWorkItemMutationResponse,
} from 'jest/work_items/mock_data';
import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
+import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql';
+import workItemMilestoneSubscription from '~/work_items/graphql/work_item_milestone.subscription.graphql';
+import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
describe('WorkItemMilestone component', () => {
Vue.use(VueApollo);
@@ -47,6 +53,8 @@ describe('WorkItemMilestone component', () => {
const findInputGroup = () => wrapper.findComponent(GlFormGroup);
const workItemQueryResponse = workItemResponseFactory({ canUpdate: true, canDelete: true });
+ const workItemQueryHandler = jest.fn().mockResolvedValue(workItemQueryResponse);
+ const workItemByIidResponseHandler = jest.fn().mockResolvedValue(projectWorkItemResponse);
const networkResolvedValue = new Error();
@@ -54,6 +62,12 @@ describe('WorkItemMilestone component', () => {
const successSearchWithNoMatchingMilestones = jest
.fn()
.mockResolvedValue(projectMilestonesResponseWithNoMilestones);
+ const milestoneSubscriptionHandler = jest
+ .fn()
+ .mockResolvedValue(workItemMilestoneSubscriptionResponse);
+ const successUpdateWorkItemMutationHandler = jest
+ .fn()
+ .mockResolvedValue(updateWorkItemMutationResponse);
const showDropdown = () => {
findDropdown().vm.$emit('shown');
@@ -67,12 +81,20 @@ describe('WorkItemMilestone component', () => {
canUpdate = true,
milestone = mockMilestoneWidgetResponse,
searchQueryHandler = successSearchQueryHandler,
+ fetchByIid = false,
+ mutationHandler = successUpdateWorkItemMutationHandler,
} = {}) => {
const apolloProvider = createMockApollo(
- [[projectMilestonesQuery, searchQueryHandler]],
+ [
+ [workItemQuery, workItemQueryHandler],
+ [workItemMilestoneSubscription, milestoneSubscriptionHandler],
+ [projectMilestonesQuery, searchQueryHandler],
+ [updateWorkItemMutation, mutationHandler],
+ [workItemByIidQuery, workItemByIidResponseHandler],
+ ],
resolvers,
{
- typePolicies: temporaryConfig.cacheConfig.typePolicies,
+ typePolicies: config.cacheConfig.typePolicies,
},
);
@@ -92,6 +114,10 @@ describe('WorkItemMilestone component', () => {
workItemId,
workItemType,
fullPath,
+ queryVariables: {
+ id: workItemId,
+ },
+ fetchByIid,
},
stubs: {
GlDropdown,
diff --git a/spec/frontend/work_items/mock_data.js b/spec/frontend/work_items/mock_data.js
index ed90b11222a..635a1f326f8 100644
--- a/spec/frontend/work_items/mock_data.js
+++ b/spec/frontend/work_items/mock_data.js
@@ -41,6 +41,7 @@ export const workItemQueryResponse = {
workItem: {
__typename: 'WorkItem',
id: 'gid://gitlab/WorkItem/1',
+ iid: '1',
title: 'Test',
state: 'OPEN',
description: 'description',
@@ -113,6 +114,7 @@ export const updateWorkItemMutationResponse = {
workItem: {
__typename: 'WorkItem',
id: 'gid://gitlab/WorkItem/1',
+ iid: '1',
title: 'Updated title',
state: 'OPEN',
description: 'description',
@@ -178,6 +180,19 @@ export const mockParent = {
},
};
+export const descriptionTextWithCheckboxes = `- [ ] todo 1\n- [ ] todo 2`;
+
+export const descriptionHtmlWithCheckboxes = `
+ <ul dir="auto" class="task-list" data-sourcepos"1:1-2:12">
+ <li class="task-list-item" data-sourcepos="1:1-1:11">
+ <input class="task-list-item-checkbox" type="checkbox"> todo 1
+ </li>
+ <li class="task-list-item" data-sourcepos="2:1-2:12">
+ <input class="task-list-item-checkbox" type="checkbox"> todo 2
+ </li>
+ </ul>
+`;
+
export const workItemResponseFactory = ({
canUpdate = false,
canDelete = false,
@@ -193,12 +208,14 @@ export const workItemResponseFactory = ({
allowsScopedLabels = false,
lastEditedAt = null,
lastEditedBy = null,
+ withCheckboxes = false,
parent = mockParent.parent,
} = {}) => ({
data: {
workItem: {
__typename: 'WorkItem',
id: 'gid://gitlab/WorkItem/1',
+ iid: 1,
title: 'Updated title',
state: 'OPEN',
description: 'description',
@@ -224,9 +241,10 @@ export const workItemResponseFactory = ({
{
__typename: 'WorkItemWidgetDescription',
type: 'DESCRIPTION',
- description: 'some **great** text',
- descriptionHtml:
- '<p data-sourcepos="1:1-1:19" dir="auto">some <strong>great</strong> text</p>',
+ description: withCheckboxes ? descriptionTextWithCheckboxes : 'some **great** text',
+ descriptionHtml: withCheckboxes
+ ? descriptionHtmlWithCheckboxes
+ : '<p data-sourcepos="1:1-1:19" dir="auto">some <strong>great</strong> text</p>',
lastEditedAt,
lastEditedBy,
},
@@ -283,11 +301,12 @@ export const workItemResponseFactory = ({
milestoneWidgetPresent
? {
__typename: 'WorkItemWidgetMilestone',
- dueDate: null,
- expired: false,
- id: 'gid://gitlab/Milestone/30',
- title: 'v4.0',
type: 'MILESTONE',
+ milestone: {
+ expired: false,
+ id: 'gid://gitlab/Milestone/30',
+ title: 'v4.0',
+ },
}
: { type: 'MOCK TYPE' },
{
@@ -312,7 +331,8 @@ export const workItemResponseFactory = ({
export const projectWorkItemTypesQueryResponse = {
data: {
workspace: {
- id: 'gid://gitlab/WorkItem/1',
+ __typename: 'Project',
+ id: 'gid://gitlab/Project/2',
workItemTypes: {
nodes: [
{ id: 'gid://gitlab/WorkItems::Type/1', name: 'Issue' },
@@ -331,6 +351,7 @@ export const createWorkItemMutationResponse = {
workItem: {
__typename: 'WorkItem',
id: 'gid://gitlab/WorkItem/1',
+ iid: '1',
title: 'Updated title',
state: 'OPEN',
description: 'description',
@@ -368,6 +389,7 @@ export const createWorkItemFromTaskMutationResponse = {
__typename: 'WorkItem',
description: 'New description',
id: 'gid://gitlab/WorkItem/1',
+ iid: '1',
title: 'Updated title',
state: 'OPEN',
confidential: false,
@@ -405,6 +427,7 @@ export const createWorkItemFromTaskMutationResponse = {
newWorkItem: {
__typename: 'WorkItem',
id: 'gid://gitlab/WorkItem/1000000',
+ iid: '100',
title: 'Updated title',
state: 'OPEN',
createdAt: '2022-08-03T12:41:54Z',
@@ -498,6 +521,28 @@ export const workItemTitleSubscriptionResponse = {
},
};
+export const workItemDescriptionSubscriptionResponse = {
+ data: {
+ issuableDescriptionUpdated: {
+ id: 'gid://gitlab/WorkItem/1',
+ widgets: [
+ {
+ __typename: 'WorkItemWidgetDescription',
+ type: 'DESCRIPTION',
+ description: 'New description',
+ descriptionHtml: '<p>New description</p>',
+ lastEditedAt: '2022-09-21T06:18:42Z',
+ lastEditedBy: {
+ id: 'gid://gitlab/User/2',
+ name: 'Someone else',
+ webPath: '/not-you',
+ },
+ },
+ ],
+ },
+ },
+};
+
export const workItemWeightSubscriptionResponse = {
data: {
issuableWeightUpdated: {
@@ -567,6 +612,25 @@ export const workItemIterationSubscriptionResponse = {
},
};
+export const workItemMilestoneSubscriptionResponse = {
+ data: {
+ issuableMilestoneUpdated: {
+ id: 'gid://gitlab/WorkItem/1',
+ widgets: [
+ {
+ __typename: 'WorkItemWidgetMilestone',
+ type: 'MILESTONE',
+ milestone: {
+ id: 'gid://gitlab/Milestone/1125',
+ expired: false,
+ title: 'Milestone title',
+ },
+ },
+ ],
+ },
+ },
+};
+
export const workItemHierarchyEmptyResponse = {
data: {
workItem: {
@@ -776,6 +840,7 @@ export const changeWorkItemParentMutationResponse = {
},
description: null,
id: 'gid://gitlab/WorkItem/2',
+ iid: '2',
state: 'OPEN',
title: 'Foo',
confidential: false,
@@ -809,22 +874,20 @@ export const availableWorkItemsResponse = {
__typename: 'Project',
id: 'gid://gitlab/Project/2',
workItems: {
- edges: [
+ nodes: [
{
- node: {
- id: 'gid://gitlab/WorkItem/458',
- title: 'Task 1',
- state: 'OPEN',
- createdAt: '2022-08-03T12:41:54Z',
- },
+ id: 'gid://gitlab/WorkItem/458',
+ title: 'Task 1',
+ state: 'OPEN',
+ createdAt: '2022-08-03T12:41:54Z',
+ __typename: 'WorkItem',
},
{
- node: {
- id: 'gid://gitlab/WorkItem/459',
- title: 'Task 2',
- state: 'OPEN',
- createdAt: '2022-08-03T12:41:54Z',
- },
+ id: 'gid://gitlab/WorkItem/459',
+ title: 'Task 2',
+ state: 'OPEN',
+ createdAt: '2022-08-03T12:41:54Z',
+ __typename: 'WorkItem',
},
],
},
@@ -1072,7 +1135,7 @@ export const groupIterationsResponseWithNoIterations = {
};
export const mockMilestoneWidgetResponse = {
- dueDate: null,
+ state: 'active',
expired: false,
id: 'gid://gitlab/Milestone/30',
title: 'v4.0',
@@ -1122,3 +1185,14 @@ export const projectMilestonesResponseWithNoMilestones = {
},
},
};
+
+export const projectWorkItemResponse = {
+ data: {
+ workspace: {
+ id: 'gid://gitlab/Project/1',
+ workItems: {
+ nodes: [workItemQueryResponse.data.workItem],
+ },
+ },
+ },
+};
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 15dac25b7d9..387c8a355fa 100644
--- a/spec/frontend/work_items/pages/create_work_item_spec.js
+++ b/spec/frontend/work_items/pages/create_work_item_spec.js
@@ -37,12 +37,17 @@ describe('Create work item component', () => {
props = {},
queryHandler = querySuccessHandler,
mutationHandler = createWorkItemSuccessHandler,
+ fetchByIid = false,
} = {}) => {
- fakeApollo = createMockApollo([
- [projectWorkItemTypesQuery, queryHandler],
- [createWorkItemMutation, mutationHandler],
- [createWorkItemFromTaskMutation, mutationHandler],
- ]);
+ fakeApollo = createMockApollo(
+ [
+ [projectWorkItemTypesQuery, queryHandler],
+ [createWorkItemMutation, mutationHandler],
+ [createWorkItemFromTaskMutation, mutationHandler],
+ ],
+ {},
+ { typePolicies: { Project: { merge: true } } },
+ );
wrapper = shallowMount(CreateWorkItem, {
apolloProvider: fakeApollo,
data() {
@@ -61,6 +66,9 @@ describe('Create work item component', () => {
},
provide: {
fullPath: 'full-path',
+ glFeatures: {
+ useIidInWorkItemsPath: fetchByIid,
+ },
},
});
};
@@ -99,7 +107,12 @@ describe('Create work item component', () => {
wrapper.find('form').trigger('submit');
await waitForPromises();
- expect(wrapper.vm.$router.push).toHaveBeenCalled();
+ expect(wrapper.vm.$router.push).toHaveBeenCalledWith({
+ name: 'workItem',
+ params: {
+ id: '1',
+ },
+ });
});
it('adds right margin for create button', () => {
@@ -197,4 +210,18 @@ 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 d9372f2bcf0..880c4271024 100644
--- a/spec/frontend/work_items/pages/work_item_root_spec.js
+++ b/spec/frontend/work_items/pages/work_item_root_spec.js
@@ -55,6 +55,7 @@ describe('Work items root component', () => {
isModal: false,
workItemId: 'gid://gitlab/WorkItem/1',
workItemParentId: null,
+ iid: '1',
});
});
@@ -65,11 +66,15 @@ describe('Work items root component', () => {
deleteWorkItemHandler,
});
- findWorkItemDetail().vm.$emit('deleteWorkItem');
+ findWorkItemDetail().vm.$emit('deleteWorkItem', { workItemType: 'task', workItemId: '1' });
await waitForPromises();
- expect(deleteWorkItemHandler).toHaveBeenCalled();
+ expect(deleteWorkItemHandler).toHaveBeenCalledWith({
+ input: {
+ id: '1',
+ },
+ });
expect(mockToastShow).toHaveBeenCalled();
expect(visitUrl).toHaveBeenCalledWith(issuesListPath);
});
@@ -81,7 +86,7 @@ describe('Work items root component', () => {
deleteWorkItemHandler,
});
- findWorkItemDetail().vm.$emit('deleteWorkItem');
+ findWorkItemDetail().vm.$emit('deleteWorkItem', { workItemType: 'task', workItemId: '1' });
await waitForPromises();
diff --git a/spec/frontend/work_items/router_spec.js b/spec/frontend/work_items/router_spec.js
index 66a917d8052..982f9f71f9e 100644
--- a/spec/frontend/work_items/router_spec.js
+++ b/spec/frontend/work_items/router_spec.js
@@ -10,6 +10,8 @@ import {
workItemTitleSubscriptionResponse,
workItemWeightSubscriptionResponse,
workItemLabelsSubscriptionResponse,
+ workItemMilestoneSubscriptionResponse,
+ workItemDescriptionSubscriptionResponse,
} from 'jest/work_items/mock_data';
import App from '~/work_items/components/app.vue';
import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
@@ -17,6 +19,8 @@ import workItemDatesSubscription from '~/work_items/graphql/work_item_dates.subs
import workItemTitleSubscription from '~/work_items/graphql/work_item_title.subscription.graphql';
import workItemAssigneesSubscription from '~/work_items/graphql/work_item_assignees.subscription.graphql';
import workItemLabelsSubscription from 'ee_else_ce/work_items/graphql/work_item_labels.subscription.graphql';
+import workItemMilestoneSubscription from '~/work_items/graphql/work_item_milestone.subscription.graphql';
+import workItemDescriptionSubscription from '~/work_items/graphql/work_item_description.subscription.graphql';
import CreateWorkItem from '~/work_items/pages/create_work_item.vue';
import WorkItemsRoot from '~/work_items/pages/work_item_root.vue';
import { createRouter } from '~/work_items/router';
@@ -34,6 +38,12 @@ describe('Work items router', () => {
.fn()
.mockResolvedValue(workItemAssigneesSubscriptionResponse);
const labelsSubscriptionHandler = jest.fn().mockResolvedValue(workItemLabelsSubscriptionResponse);
+ const milestoneSubscriptionHandler = jest
+ .fn()
+ .mockResolvedValue(workItemMilestoneSubscriptionResponse);
+ const descriptionSubscriptionHandler = jest
+ .fn()
+ .mockResolvedValue(workItemDescriptionSubscriptionResponse);
const createComponent = async (routeArg) => {
const router = createRouter('/work_item');
@@ -47,6 +57,8 @@ describe('Work items router', () => {
[workItemTitleSubscription, titleSubscriptionHandler],
[workItemAssigneesSubscription, assigneesSubscriptionHandler],
[workItemLabelsSubscription, labelsSubscriptionHandler],
+ [workItemMilestoneSubscription, milestoneSubscriptionHandler],
+ [workItemDescriptionSubscription, descriptionSubscriptionHandler],
];
if (IS_EE) {
@@ -59,10 +71,19 @@ describe('Work items router', () => {
provide: {
fullPath: 'full-path',
issuesListPath: 'full-path/-/issues',
+ hasIssueWeightsFeature: false,
},
});
};
+ beforeEach(() => {
+ window.gon = {
+ features: {
+ workItemsMvc2: false,
+ },
+ };
+ });
+
afterEach(() => {
wrapper.destroy();
window.location.hash = '';
@@ -74,7 +95,14 @@ describe('Work items router', () => {
expect(wrapper.findComponent(WorkItemsRoot).exists()).toBe(true);
});
+ it('does not render create work item page on `/new` route if `workItemsMvc2` feature flag is off', async () => {
+ await createComponent('/new');
+
+ expect(wrapper.findComponent(CreateWorkItem).exists()).toBe(false);
+ });
+
it('renders create work item page on `/new` route', async () => {
+ window.gon.features.workItemsMvc2 = true;
await createComponent('/new');
expect(wrapper.findComponent(CreateWorkItem).exists()).toBe(true);
diff --git a/spec/graphql/graphql_triggers_spec.rb b/spec/graphql/graphql_triggers_spec.rb
index a4a643582f5..a54cb8a7988 100644
--- a/spec/graphql/graphql_triggers_spec.rb
+++ b/spec/graphql/graphql_triggers_spec.rb
@@ -3,76 +3,89 @@
require 'spec_helper'
RSpec.describe GraphqlTriggers do
+ let_it_be(:issuable, refind: true) { create(:work_item) }
+
describe '.issuable_assignees_updated' do
- it 'triggers the issuableAssigneesUpdated subscription' do
- assignees = create_list(:user, 2)
- issue = create(:issue, assignees: assignees)
+ let(:assignees) { create_list(:user, 2) }
+ before do
+ issuable.update!(assignees: assignees)
+ end
+
+ it 'triggers the issuableAssigneesUpdated subscription' do
expect(GitlabSchema.subscriptions).to receive(:trigger).with(
'issuableAssigneesUpdated',
- { issuable_id: issue.to_gid },
- issue
+ { issuable_id: issuable.to_gid },
+ issuable
)
- GraphqlTriggers.issuable_assignees_updated(issue)
+ GraphqlTriggers.issuable_assignees_updated(issuable)
end
end
describe '.issuable_title_updated' do
it 'triggers the issuableTitleUpdated subscription' do
- work_item = create(:work_item)
-
expect(GitlabSchema.subscriptions).to receive(:trigger).with(
'issuableTitleUpdated',
- { issuable_id: work_item.to_gid },
- work_item
+ { issuable_id: issuable.to_gid },
+ issuable
).and_call_original
- GraphqlTriggers.issuable_title_updated(work_item)
+ GraphqlTriggers.issuable_title_updated(issuable)
end
end
describe '.issuable_description_updated' do
it 'triggers the issuableDescriptionUpdated subscription' do
- work_item = create(:work_item)
-
expect(GitlabSchema.subscriptions).to receive(:trigger).with(
'issuableDescriptionUpdated',
- { issuable_id: work_item.to_gid },
- work_item
+ { issuable_id: issuable.to_gid },
+ issuable
).and_call_original
- GraphqlTriggers.issuable_description_updated(work_item)
+ GraphqlTriggers.issuable_description_updated(issuable)
end
end
describe '.issuable_labels_updated' do
- it 'triggers the issuableLabelsUpdated subscription' do
- project = create(:project)
- labels = create_list(:label, 3, project: project)
- issue = create(:issue, labels: labels)
+ let(:labels) { create_list(:label, 3, project: create(:project)) }
+
+ before do
+ issuable.update!(labels: labels)
+ end
+ it 'triggers the issuableLabelsUpdated subscription' do
expect(GitlabSchema.subscriptions).to receive(:trigger).with(
'issuableLabelsUpdated',
- { issuable_id: issue.to_gid },
- issue
+ { issuable_id: issuable.to_gid },
+ issuable
)
- GraphqlTriggers.issuable_labels_updated(issue)
+ GraphqlTriggers.issuable_labels_updated(issuable)
end
end
describe '.issuable_dates_updated' do
it 'triggers the issuableDatesUpdated subscription' do
- work_item = create(:work_item)
-
expect(GitlabSchema.subscriptions).to receive(:trigger).with(
'issuableDatesUpdated',
- { issuable_id: work_item.to_gid },
- work_item
+ { issuable_id: issuable.to_gid },
+ issuable
+ ).and_call_original
+
+ GraphqlTriggers.issuable_dates_updated(issuable)
+ end
+ end
+
+ describe '.issuable_milestone_updated' do
+ it 'triggers the issuableMilestoneUpdated subscription' do
+ expect(GitlabSchema.subscriptions).to receive(:trigger).with(
+ 'issuableMilestoneUpdated',
+ { issuable_id: issuable.to_gid },
+ issuable
).and_call_original
- GraphqlTriggers.issuable_dates_updated(work_item)
+ GraphqlTriggers.issuable_milestone_updated(issuable)
end
end
diff --git a/spec/graphql/mutations/ci/runner/bulk_delete_spec.rb b/spec/graphql/mutations/ci/runner/bulk_delete_spec.rb
index f47f1b9869e..2eccfd3409f 100644
--- a/spec/graphql/mutations/ci/runner/bulk_delete_spec.rb
+++ b/spec/graphql/mutations/ci/runner/bulk_delete_spec.rb
@@ -6,7 +6,6 @@ RSpec.describe Mutations::Ci::Runner::BulkDelete do
include GraphqlHelpers
let_it_be(:admin_user) { create(:user, :admin) }
- let_it_be(:user) { create(:user) }
let(:current_ctx) { { current_user: user } }
@@ -19,24 +18,15 @@ RSpec.describe Mutations::Ci::Runner::BulkDelete do
sync(resolve(described_class, args: mutation_params, ctx: current_ctx))
end
- context 'when the user cannot admin the runner' do
- let(:runner) { create(:ci_runner) }
- let(:mutation_params) do
- { ids: [runner.to_global_id] }
- end
-
- it 'generates an error' do
- expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) { response }
- end
- end
-
context 'when user can delete runners' do
+ let_it_be(:group) { create(:group) }
+
let(:user) { admin_user }
let!(:runners) do
- create_list(:ci_runner, 2, :instance)
+ create_list(:ci_runner, 2, :group, groups: [group])
end
- context 'when required arguments are missing' do
+ context 'when runner IDs are missing' do
let(:mutation_params) { {} }
context 'when admin mode is enabled', :enable_admin_mode do
@@ -47,43 +37,48 @@ RSpec.describe Mutations::Ci::Runner::BulkDelete do
end
context 'with runners specified by id' do
- let(:mutation_params) do
+ let!(:mutation_params) do
{ ids: runners.map(&:to_global_id) }
end
context 'when admin mode is enabled', :enable_admin_mode do
it 'deletes runners', :aggregate_failures do
- expect_next_instance_of(
- ::Ci::Runners::BulkDeleteRunnersService, { runners: runners }
- ) do |service|
- expect(service).to receive(:execute).once.and_call_original
- end
-
expect { response }.to change { Ci::Runner.count }.by(-2)
expect(response[:errors]).to be_empty
end
+ end
- context 'when runner list is is above limit' do
- before do
- stub_const('::Ci::Runners::BulkDeleteRunnersService::RUNNER_LIMIT', 1)
- end
-
- it 'only deletes up to the defined limit', :aggregate_failures do
- expect { response }.to change { Ci::Runner.count }
- .by(-::Ci::Runners::BulkDeleteRunnersService::RUNNER_LIMIT)
- expect(response[:errors]).to be_empty
- end
+ it 'ignores unknown keys from service response payload', :aggregate_failures do
+ expect_next_instance_of(
+ ::Ci::Runners::BulkDeleteRunnersService, { runners: runners, current_user: user }
+ ) do |service|
+ expect(service).to receive(:execute).once.and_return(
+ ServiceResponse.success(
+ payload: {
+ extra_key: 'extra_value',
+ deleted_count: 10,
+ deleted_ids: (1..10).to_a,
+ errors: []
+ }))
end
+
+ expect(response).not_to include(extra_key: 'extra_value')
end
+ end
+ end
- context 'when admin mode is disabled', :aggregate_failures do
- it 'returns error', :aggregate_failures do
- expect do
- expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do
- response
- end
- end.not_to change { Ci::Runner.count }
- end
+ context 'when the user cannot delete the runner' do
+ let(:runner) { create(:ci_runner) }
+ let!(:mutation_params) do
+ { ids: [runner.to_global_id] }
+ end
+
+ context 'when user is admin and admin mode is not enabled' do
+ let(:user) { admin_user }
+
+ it 'returns error', :aggregate_failures do
+ expect { response }.not_to change { Ci::Runner.count }
+ expect(response[:errors]).to match_array("User does not have permission to delete any of the runners")
end
end
end
diff --git a/spec/graphql/mutations/ci/runner/update_spec.rb b/spec/graphql/mutations/ci/runner/update_spec.rb
index ee65be1e085..098b7ac6aa4 100644
--- a/spec/graphql/mutations/ci/runner/update_spec.rb
+++ b/spec/graphql/mutations/ci/runner/update_spec.rb
@@ -7,8 +7,10 @@ RSpec.describe Mutations::Ci::Runner::Update do
let_it_be(:user) { create(:user) }
let_it_be(:project1) { create(:project) }
- let_it_be(:runner) do
- create(:ci_runner, :project, projects: [project1], active: true, locked: false, run_untagged: true)
+ let_it_be(:project2) { create(:project) }
+
+ let(:runner) do
+ create(:ci_runner, :project, projects: [project1, project2], active: true, locked: false, run_untagged: true)
end
let(:current_ctx) { { current_user: user } }
@@ -79,14 +81,14 @@ RSpec.describe Mutations::Ci::Runner::Update do
end
context 'with associatedProjects argument' do
- let_it_be(:project2) { create(:project) }
+ let_it_be(:project3) { create(:project) }
context 'with id set to project runner' do
let(:mutation_params) do
{
id: runner.to_global_id,
description: 'updated description',
- associated_projects: [project2.to_global_id.to_s]
+ associated_projects: [project3.to_global_id.to_s]
}
end
@@ -96,7 +98,7 @@ RSpec.describe Mutations::Ci::Runner::Update do
{
runner: runner,
current_user: admin_user,
- project_ids: [project2.id]
+ project_ids: [project3.id]
}
) do |service|
expect(service).to receive(:execute).and_call_original
@@ -110,7 +112,7 @@ RSpec.describe Mutations::Ci::Runner::Update do
expect(response[:runner]).to be_an_instance_of(Ci::Runner)
expect(response[:runner]).to have_attributes(expected_attributes)
expect(runner.reload).to have_attributes(expected_attributes)
- expect(runner.projects).to match_array([project1, project2])
+ expect(runner.projects).to match_array([project1, project3])
end
context 'with user not allowed to assign runner' do
@@ -124,7 +126,7 @@ RSpec.describe Mutations::Ci::Runner::Update do
{
runner: runner,
current_user: admin_user,
- project_ids: [project2.id]
+ project_ids: [project3.id]
}
) do |service|
expect(service).to receive(:execute).and_call_original
@@ -137,11 +139,39 @@ RSpec.describe Mutations::Ci::Runner::Update do
expect(response[:errors]).to match_array(['user not allowed to assign runner'])
expect(response[:runner]).to be_nil
expect(runner.reload).not_to have_attributes(expected_attributes)
- expect(runner.projects).to match_array([project1])
+ expect(runner.projects).to match_array([project1, project2])
end
end
end
+ context 'with an empty list of projects' do
+ let(:mutation_params) do
+ {
+ id: runner.to_global_id,
+ associated_projects: []
+ }
+ end
+
+ it 'removes project relationships', :aggregate_failures do
+ expect_next_instance_of(
+ ::Ci::Runners::SetRunnerAssociatedProjectsService,
+ {
+ runner: runner,
+ current_user: admin_user,
+ project_ids: []
+ }
+ ) do |service|
+ expect(service).to receive(:execute).and_call_original
+ end
+
+ response
+
+ expect(response[:errors]).to be_empty
+ expect(response[:runner]).to be_an_instance_of(Ci::Runner)
+ expect(runner.reload.projects).to contain_exactly(project1)
+ end
+ end
+
context 'with id set to instance runner' do
let(:instance_runner) { create(:ci_runner, :instance) }
let(:mutation_params) do
diff --git a/spec/graphql/mutations/commits/create_spec.rb b/spec/graphql/mutations/commits/create_spec.rb
index fd0c2c46b2e..2c452410cca 100644
--- a/spec/graphql/mutations/commits/create_spec.rb
+++ b/spec/graphql/mutations/commits/create_spec.rb
@@ -179,7 +179,7 @@ RSpec.describe Mutations::Commits::Create do
it 'returns errors' do
expect(mutated_commit).to be_nil
- expect(subject[:errors].to_s).to match(/3:UserCommitFiles: empty CommitMessage/)
+ expect(subject[:errors].to_s).to match(/empty CommitMessage/)
end
end
diff --git a/spec/graphql/mutations/concerns/mutations/resolves_group_spec.rb b/spec/graphql/mutations/concerns/mutations/resolves_group_spec.rb
index 6bed3a752ed..3198419fb81 100644
--- a/spec/graphql/mutations/concerns/mutations/resolves_group_spec.rb
+++ b/spec/graphql/mutations/concerns/mutations/resolves_group_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Mutations::ResolvesGroup do
end
end
- let(:context) { double }
+ let(:context) { {} }
subject(:mutation) { mutation_class.new(object: nil, context: context, field: nil) }
diff --git a/spec/graphql/mutations/container_repositories/destroy_spec.rb b/spec/graphql/mutations/container_repositories/destroy_spec.rb
index 97da7846339..9f3ff8da80b 100644
--- a/spec/graphql/mutations/container_repositories/destroy_spec.rb
+++ b/spec/graphql/mutations/container_repositories/destroy_spec.rb
@@ -20,11 +20,10 @@ RSpec.describe Mutations::ContainerRepositories::Destroy do
end
shared_examples 'destroying the container repository' do
- it 'destroys the container repistory' do
+ it 'marks the repository as delete_scheduled' do
expect(::Packages::CreateEventService)
.to receive(:new).with(nil, user, event_name: :delete_repository, scope: :container).and_call_original
- expect(DeleteContainerRepositoryWorker)
- .to receive(:perform_async).with(user.id, container_repository.id)
+ expect(DeleteContainerRepositoryWorker).not_to receive(:perform_async)
expect { subject }.to change { ::Packages::Event.count }.by(1)
expect(container_repository.reload.delete_scheduled?).to be true
@@ -56,6 +55,23 @@ RSpec.describe Mutations::ContainerRepositories::Destroy do
it_behaves_like params[:shared_examples_name]
end
+
+ context 'with container_registry_delete_repository_with_cron_worker disabled' do
+ before do
+ project.add_maintainer(user)
+ stub_feature_flags(container_registry_delete_repository_with_cron_worker: false)
+ end
+
+ it 'enqueues a removal job' do
+ expect(::Packages::CreateEventService)
+ .to receive(:new).with(nil, user, event_name: :delete_repository, scope: :container).and_call_original
+ expect(DeleteContainerRepositoryWorker)
+ .to receive(:perform_async).with(user.id, container_repository.id)
+
+ expect { subject }.to change { ::Packages::Event.count }.by(1)
+ expect(container_repository.reload.delete_scheduled?).to be true
+ end
+ end
end
end
end
diff --git a/spec/graphql/mutations/incident_management/timeline_event/create_spec.rb b/spec/graphql/mutations/incident_management/timeline_event/create_spec.rb
index 9254d84b29c..aab21776a99 100644
--- a/spec/graphql/mutations/incident_management/timeline_event/create_spec.rb
+++ b/spec/graphql/mutations/incident_management/timeline_event/create_spec.rb
@@ -6,6 +6,9 @@ RSpec.describe Mutations::IncidentManagement::TimelineEvent::Create do
let_it_be(:current_user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:incident) { create(:incident, project: project) }
+ let_it_be(:timeline_event_tag) do
+ create(:incident_management_timeline_event_tag, project: project, name: 'Test tag 1')
+ end
let(:args) { { note: 'note', occurred_at: Time.current } }
@@ -39,6 +42,104 @@ RSpec.describe Mutations::IncidentManagement::TimelineEvent::Create do
it_behaves_like 'responding with an incident timeline errors',
errors: ["Occurred at can't be blank and Timeline text can't be blank"]
end
+
+ context 'when timeline event tags are passed' do
+ let(:args) do
+ {
+ note: 'note',
+ occurred_at: Time.current,
+ timeline_event_tag_names: [timeline_event_tag.name.to_s]
+ }
+ end
+
+ it_behaves_like 'creating an incident timeline event'
+ end
+
+ context 'when predefined tags are passed' do
+ let(:args) do
+ {
+ note: 'note',
+ occurred_at: Time.current,
+ timeline_event_tag_names: ['Start time']
+ }
+ end
+
+ it_behaves_like 'creating an incident timeline event'
+
+ it 'creates and sets the tag on the event' do
+ timeline_event = resolve[:timeline_event]
+
+ expect(timeline_event.timeline_event_tags.by_names(['Start time']).count).to eq 1
+ end
+ end
+
+ context 'when predefined tags exist' do
+ let_it_be(:end_time_tag) do
+ create(:incident_management_timeline_event_tag, project: project, name: 'End time')
+ end
+
+ let(:args) do
+ {
+ note: 'note',
+ occurred_at: Time.current,
+ timeline_event_tag_names: ['End time']
+ }
+ end
+
+ it 'does not create a new tag' do
+ expect { resolve }.not_to change(IncidentManagement::TimelineEventTag, :count)
+ end
+ end
+
+ context 'when same tags are tried to be assigned to same timeline event' do
+ let(:args) do
+ {
+ note: 'note',
+ occurred_at: Time.current,
+ timeline_event_tag_names: ['Start time', 'Start time']
+ }
+ end
+
+ it 'only assigns the tag once on the event' do
+ timeline_event = resolve[:timeline_event]
+
+ expect(timeline_event.timeline_event_tags.by_names(['Start time']).count).to eq(1)
+ expect(timeline_event.timeline_event_tags.count).to eq(1)
+ end
+ end
+
+ context 'with case-insentive tags' do
+ let(:args) do
+ {
+ note: 'note',
+ occurred_at: Time.current,
+ timeline_event_tag_names: ['tESt tAg 1']
+ }
+ end
+
+ it 'sets the tag on the event' do
+ timeline_event = resolve[:timeline_event]
+
+ expect(timeline_event.timeline_event_tags.by_names(['Test tag 1']).count).to eq(1)
+ end
+ end
+
+ context 'when non-existing tags are passed' do
+ let(:args) do
+ {
+ note: 'note',
+ occurred_at: Time.current,
+ timeline_event_tag_names: ['other time']
+ }
+ end
+
+ it_behaves_like 'responding with an incident timeline errors',
+ errors: ["Following tags don't exist: [\"other time\"]"]
+
+ it 'does not create the timeline event' do
+ expect { resolve }.not_to change(IncidentManagement::TimelineEvent, :count)
+ end
+ end
end
it_behaves_like 'failing to create an incident timeline event'
diff --git a/spec/graphql/mutations/incident_management/timeline_event_tag/create_spec.rb b/spec/graphql/mutations/incident_management/timeline_event_tag/create_spec.rb
new file mode 100644
index 00000000000..57a32f7e4bc
--- /dev/null
+++ b/spec/graphql/mutations/incident_management/timeline_event_tag/create_spec.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Mutations::IncidentManagement::TimelineEventTag::Create do
+ let_it_be(:current_user) { create(:user) }
+ let_it_be_with_reload(:project) { create(:project) }
+
+ let(:args) { { name: 'Test tag 1' } }
+
+ before do
+ project.add_maintainer(current_user)
+ end
+
+ specify { expect(described_class).to require_graphql_authorizations(:admin_incident_management_timeline_event_tag) }
+
+ describe '#resolve' do
+ subject(:resolve) { mutation_for(project, current_user).resolve(project_path: project.full_path, **args) }
+
+ context 'when user has permission to create timeline event tag' do
+ it 'adds the tag to the project' do
+ expect { resolve }.to change(IncidentManagement::TimelineEventTag, :count).by(1)
+ expect(project.incident_management_timeline_event_tags.by_names(['Test tag 1']).pluck_names)
+ .to match_array(['Test tag 1'])
+ end
+ end
+
+ context 'when TimelineEventTags::CreateService responds with an error' do
+ let(:args) { {} }
+
+ it 'returns errors' do
+ expect(resolve).to eq(timeline_event_tag: nil, errors: ["Name can't be blank and Name is invalid"])
+ end
+ end
+
+ context 'when user has no permissions to create tags on a project' do
+ before do
+ project.add_developer(current_user)
+ end
+
+ it 'raises an error' do
+ expect { resolve }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+ end
+ end
+
+ private
+
+ def mutation_for(project, user)
+ described_class.new(object: project, context: { current_user: user }, field: nil)
+ end
+end
diff --git a/spec/graphql/mutations/security/ci_configuration/base_security_analyzer_spec.rb b/spec/graphql/mutations/security/ci_configuration/base_security_analyzer_spec.rb
index 668768189df..c081f9f0cd2 100644
--- a/spec/graphql/mutations/security/ci_configuration/base_security_analyzer_spec.rb
+++ b/spec/graphql/mutations/security/ci_configuration/base_security_analyzer_spec.rb
@@ -11,6 +11,6 @@ RSpec.describe Mutations::Security::CiConfiguration::BaseSecurityAnalyzer do
project = create(:project, :public, :repository)
project.add_developer(user)
- expect { mutation.resolve(project_path: project.full_path ) }.to raise_error(NotImplementedError)
+ expect { mutation.resolve(project_path: project.full_path) }.to raise_error(NotImplementedError)
end
end
diff --git a/spec/graphql/mutations/todos/restore_many_spec.rb b/spec/graphql/mutations/todos/restore_many_spec.rb
index d43f1c8a2e9..3235be8486e 100644
--- a/spec/graphql/mutations/todos/restore_many_spec.rb
+++ b/spec/graphql/mutations/todos/restore_many_spec.rb
@@ -80,7 +80,7 @@ RSpec.describe Mutations::Todos::RestoreMany do
end
def restore_mutation(todos)
- mutation.resolve(ids: todos.map { |todo| global_id_of(todo) } )
+ mutation.resolve(ids: todos.map { |todo| global_id_of(todo) })
end
def expect_states_were_not_changed
diff --git a/spec/graphql/resolvers/board_list_issues_resolver_spec.rb b/spec/graphql/resolvers/board_list_issues_resolver_spec.rb
index ab1f19abaad..d346b7aee93 100644
--- a/spec/graphql/resolvers/board_list_issues_resolver_spec.rb
+++ b/spec/graphql/resolvers/board_list_issues_resolver_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Resolvers::BoardListIssuesResolver do
let_it_be(:user) { create(:user) }
let_it_be(:unauth_user) { create(:user) }
- let_it_be(:user_project) { create(:project, creator_id: user.id, namespace: user.namespace ) }
+ let_it_be(:user_project) { create(:project, creator_id: user.id, namespace: user.namespace) }
let_it_be(:group) { create(:group, :private) }
shared_examples_for 'group and project board list issues resolver' do
diff --git a/spec/graphql/resolvers/board_lists_resolver_spec.rb b/spec/graphql/resolvers/board_lists_resolver_spec.rb
index 2fb7c5c4717..0f6e51ebbd0 100644
--- a/spec/graphql/resolvers/board_lists_resolver_spec.rb
+++ b/spec/graphql/resolvers/board_lists_resolver_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe Resolvers::BoardListsResolver do
let_it_be(:user) { create(:user) }
let_it_be(:guest) { create(:user) }
let_it_be(:unauth_user) { create(:user) }
- let_it_be(:project) { create(:project, creator_id: user.id, namespace: user.namespace ) }
+ let_it_be(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
let_it_be(:group) { create(:group, :private) }
let_it_be(:project_label) { create(:label, project: project, name: 'Development') }
let_it_be(:group_label) { create(:group_label, group: group, name: 'Development') }
@@ -65,7 +65,7 @@ RSpec.describe Resolvers::BoardListsResolver do
it 'returns empty result if list is not found' do
external_group = create(:group, :private)
- external_board = create(:board, resource_parent: external_group )
+ external_board = create(:board, resource_parent: external_group)
external_label = create(:group_label, group: group)
external_list = create(:list, board: external_board, label: external_label)
diff --git a/spec/graphql/resolvers/board_resolver_spec.rb b/spec/graphql/resolvers/board_resolver_spec.rb
index 51a13850366..e83d2cbfd1f 100644
--- a/spec/graphql/resolvers/board_resolver_spec.rb
+++ b/spec/graphql/resolvers/board_resolver_spec.rb
@@ -54,7 +54,7 @@ RSpec.describe Resolvers::BoardResolver do
end
context 'when project boards' do
- let(:board_parent) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) }
+ let(:board_parent) { create(:project, :public, creator_id: user.id, namespace: user.namespace) }
it_behaves_like 'group and project boards resolver'
end
diff --git a/spec/graphql/resolvers/boards_resolver_spec.rb b/spec/graphql/resolvers/boards_resolver_spec.rb
index 07d0902d3ba..aa78f0db188 100644
--- a/spec/graphql/resolvers/boards_resolver_spec.rb
+++ b/spec/graphql/resolvers/boards_resolver_spec.rb
@@ -72,7 +72,7 @@ RSpec.describe Resolvers::BoardsResolver do
end
context 'when project boards' do
- let(:board_parent) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) }
+ let(:board_parent) { create(:project, :public, creator_id: user.id, namespace: user.namespace) }
it_behaves_like 'group and project boards resolver'
end
diff --git a/spec/graphql/resolvers/container_repositories_resolver_spec.rb b/spec/graphql/resolvers/container_repositories_resolver_spec.rb
index 8cbb366f873..df0a98b1536 100644
--- a/spec/graphql/resolvers/container_repositories_resolver_spec.rb
+++ b/spec/graphql/resolvers/container_repositories_resolver_spec.rb
@@ -43,7 +43,7 @@ RSpec.describe Resolvers::ContainerRepositoriesResolver do
end
[:created_desc, :updated_asc, :name_desc].each do |order|
- context "#{order}" do
+ context order.to_s do
let(:args) { { sort: order } }
it { is_expected.to eq([sort_repository2, sort_repository]) }
@@ -51,7 +51,7 @@ RSpec.describe Resolvers::ContainerRepositoriesResolver do
end
[:created_asc, :updated_desc, :name_asc].each do |order|
- context "#{order}" do
+ context order.to_s do
let(:args) { { sort: order } }
it { is_expected.to eq([sort_repository, sort_repository2]) }
diff --git a/spec/graphql/resolvers/group_packages_resolver_spec.rb b/spec/graphql/resolvers/group_packages_resolver_spec.rb
index c600f9c9f9a..639d4d93b79 100644
--- a/spec/graphql/resolvers/group_packages_resolver_spec.rb
+++ b/spec/graphql/resolvers/group_packages_resolver_spec.rb
@@ -21,10 +21,10 @@ RSpec.describe 'Resolvers::GroupPackagesResolver' do
describe 'project_path sorting' do
let_it_be(:project2) { create(:project, :public, group: group, path: 'b') }
- let_it_be(:package) { create(:package, project: project ) }
- let_it_be(:package2) { create(:package, project: project2 ) }
- let_it_be(:package3) { create(:package, project: project ) }
- let_it_be(:package4) { create(:package, project: project2 ) }
+ let_it_be(:package) { create(:package, project: project) }
+ let_it_be(:package2) { create(:package, project: project2) }
+ let_it_be(:package3) { create(:package, project: project) }
+ let_it_be(:package4) { create(:package, project: project2) }
context 'filter by package_name' do
let(:args) { { sort: 'PROJECT_PATH_DESC' } }
diff --git a/spec/graphql/resolvers/incident_management/timeline_event_tags_resolver_spec.rb b/spec/graphql/resolvers/incident_management/timeline_event_tags_resolver_spec.rb
new file mode 100644
index 00000000000..8ab34e05e52
--- /dev/null
+++ b/spec/graphql/resolvers/incident_management/timeline_event_tags_resolver_spec.rb
@@ -0,0 +1,92 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::IncidentManagement::TimelineEventTagsResolver do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:incident) { create(:incident, project: project) }
+
+ let_it_be(:timeline_event) do
+ create(:incident_management_timeline_event, project: project, incident: incident)
+ end
+
+ let_it_be(:timeline_event_with_no_tags) do
+ create(:incident_management_timeline_event, project: project, incident: incident)
+ end
+
+ let_it_be(:timeline_event_tag) do
+ create(:incident_management_timeline_event_tag, project: project)
+ end
+
+ let_it_be(:timeline_event_tag2) do
+ create(:incident_management_timeline_event_tag, project: project, name: 'Test tag 2')
+ end
+
+ let_it_be(:timeline_event_tag_link) do
+ create(:incident_management_timeline_event_tag_link,
+ timeline_event: timeline_event,
+ timeline_event_tag: timeline_event_tag)
+ end
+
+ let(:resolver) { described_class }
+
+ subject(:resolved_timeline_event_tags) do
+ sync(resolve_timeline_event_tags(timeline_event, current_user: current_user).to_a)
+ end
+
+ before do
+ project.add_guest(current_user)
+ end
+
+ specify do
+ expect(resolver).to have_nullable_graphql_type(
+ Types::IncidentManagement::TimelineEventTagType.connection_type
+ )
+ end
+
+ it 'returns timeline event tags', :aggregate_failures do
+ expect(resolved_timeline_event_tags.length).to eq(1)
+ expect(resolved_timeline_event_tags.first).to be_a(::IncidentManagement::TimelineEventTag)
+ end
+
+ context 'when timeline event is nil' do
+ subject(:resolved_timeline_event_tags) do
+ sync(resolve_timeline_event_tags(nil, current_user: current_user).to_a)
+ end
+
+ it 'returns no timeline event tags' do
+ expect(resolved_timeline_event_tags).to be_empty
+ end
+ end
+
+ context 'when there is no timeline event tag link' do
+ subject(:resolved_timeline_event_tags) do
+ sync(resolve_timeline_event_tags(timeline_event_with_no_tags, current_user: current_user).to_a)
+ end
+
+ it 'returns no timeline event tags' do
+ expect(resolved_timeline_event_tags).to be_empty
+ end
+ end
+
+ context 'when user does not have permissions' do
+ let(:non_member) { create(:user) }
+
+ subject(:resolved_timeline_event_tags) do
+ sync(resolve_timeline_event_tags(timeline_event, current_user: non_member).to_a)
+ end
+
+ it 'returns no timeline event tags' do
+ expect(resolved_timeline_event_tags).to be_empty
+ end
+ end
+
+ private
+
+ def resolve_timeline_event_tags(obj, context = { current_user: current_user })
+ resolve(resolver, obj: obj, args: {}, ctx: context, arg_style: :internal_prepared)
+ end
+end
diff --git a/spec/graphql/resolvers/issues_resolver_spec.rb b/spec/graphql/resolvers/issues_resolver_spec.rb
deleted file mode 100644
index a74b2a3f18c..00000000000
--- a/spec/graphql/resolvers/issues_resolver_spec.rb
+++ /dev/null
@@ -1,677 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Resolvers::IssuesResolver do
- include GraphqlHelpers
-
- let_it_be(:current_user) { create(:user) }
- let_it_be(:reporter) { create(:user) }
-
- let_it_be(:group) { create(:group) }
- let_it_be(:project) { create(:project, group: group) }
- let_it_be(:other_project) { create(:project, group: group) }
-
- let_it_be(:started_milestone) { create(:milestone, project: project, title: "started milestone", start_date: 1.day.ago) }
- let_it_be(:assignee) { create(:user) }
- let_it_be(:issue1) { create(:incident, project: project, state: :opened, created_at: 3.hours.ago, updated_at: 3.hours.ago, milestone: started_milestone) }
- let_it_be(:issue2) { create(:issue, project: project, state: :closed, title: 'foo', created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at: 1.hour.ago, assignees: [assignee]) }
- let_it_be(:issue3) { create(:issue, project: other_project, state: :closed, title: 'foo', created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at: 1.hour.ago, assignees: [assignee]) }
- let_it_be(:issue4) { create(:issue) }
- let_it_be(:label1) { create(:label, project: project) }
- let_it_be(:label2) { create(:label, project: project) }
- let_it_be(:upvote_award) { create(:award_emoji, :upvote, user: current_user, awardable: issue1) }
-
- specify do
- expect(described_class).to have_nullable_graphql_type(Types::IssueType.connection_type)
- end
-
- context "with a project" do
- before_all do
- project.add_developer(current_user)
- project.add_reporter(reporter)
-
- create(:crm_settings, group: group, enabled: true)
-
- create(:label_link, label: label1, target: issue1)
- create(:label_link, label: label1, target: issue2)
- create(:label_link, label: label2, target: issue2)
- end
-
- describe '#resolve' do
- it 'finds all issues' do
- expect(resolve_issues).to contain_exactly(issue1, issue2)
- end
-
- it 'filters by state' do
- expect(resolve_issues(state: 'opened')).to contain_exactly(issue1)
- expect(resolve_issues(state: 'closed')).to contain_exactly(issue2)
- end
-
- it 'filters by milestone' do
- expect(resolve_issues(milestone_title: [started_milestone.title])).to contain_exactly(issue1)
- end
-
- describe 'filtering by milestone wildcard id' do
- let_it_be(:upcoming_milestone) { create(:milestone, project: project, title: "upcoming milestone", start_date: 1.day.ago, due_date: 1.day.from_now) }
- let_it_be(:past_milestone) { create(:milestone, project: project, title: "past milestone", due_date: 1.day.ago) }
- let_it_be(:future_milestone) { create(:milestone, project: project, title: "future milestone", start_date: 1.day.from_now) }
- let_it_be(:issue5) { create(:issue, project: project, state: :opened, milestone: upcoming_milestone) }
- let_it_be(:issue6) { create(:issue, project: project, state: :opened, milestone: past_milestone) }
- let_it_be(:issue7) { create(:issue, project: project, state: :opened, milestone: future_milestone) }
-
- let(:wildcard_started) { 'STARTED' }
- let(:wildcard_upcoming) { 'UPCOMING' }
- let(:wildcard_any) { 'ANY' }
- let(:wildcard_none) { 'NONE' }
-
- it 'returns issues with started milestone' do
- expect(resolve_issues(milestone_wildcard_id: wildcard_started)).to contain_exactly(issue1, issue5)
- end
-
- it 'returns issues with upcoming milestone' do
- expect(resolve_issues(milestone_wildcard_id: wildcard_upcoming)).to contain_exactly(issue5)
- end
-
- it 'returns issues with any milestone' do
- expect(resolve_issues(milestone_wildcard_id: wildcard_any)).to contain_exactly(issue1, issue5, issue6, issue7)
- end
-
- it 'returns issues with no milestone' do
- expect(resolve_issues(milestone_wildcard_id: wildcard_none)).to contain_exactly(issue2)
- end
-
- it 'generates a mutually exclusive filter error when wildcard and title are provided' do
- expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'only one of [milestoneTitle, milestoneWildcardId] arguments is allowed at the same time.') do
- resolve_issues(milestone_title: ["started milestone"], milestone_wildcard_id: wildcard_started)
- end
- end
-
- context 'negated filtering' do
- it 'returns issues matching the searched title after applying a negated filter' do
- expect(resolve_issues(milestone_title: ['past milestone'], not: { milestone_wildcard_id: wildcard_upcoming })).to contain_exactly(issue6)
- end
-
- it 'returns issues excluding the ones with started milestone' do
- expect(resolve_issues(not: { milestone_wildcard_id: wildcard_started })).to contain_exactly(issue7)
- end
-
- it 'returns issues excluding the ones with upcoming milestone' do
- expect(resolve_issues(not: { milestone_wildcard_id: wildcard_upcoming })).to contain_exactly(issue6)
- end
-
- it 'generates a mutually exclusive filter error when wildcard and title are provided as negated filters' do
- expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'only one of [milestoneTitle, milestoneWildcardId] arguments is allowed at the same time.') do
- resolve_issues(not: { milestone_title: ["started milestone"], milestone_wildcard_id: wildcard_started })
- end
- end
- end
- end
-
- describe 'filter by release' do
- let_it_be(:milestone1) { create(:milestone, project: project, start_date: 1.day.from_now, title: 'Version 1') }
- let_it_be(:milestone2) { create(:milestone, project: project, start_date: 1.day.from_now, title: 'Version 2') }
- let_it_be(:milestone3) { create(:milestone, project: project, start_date: 1.day.from_now, title: 'Version 3') }
- let_it_be(:release1) { create(:release, tag: 'v1.0', milestones: [milestone1], project: project) }
- let_it_be(:release2) { create(:release, tag: 'v2.0', milestones: [milestone2], project: project) }
- let_it_be(:release3) { create(:release, tag: 'v3.0', milestones: [milestone3], project: project) }
- let_it_be(:release_issue1) { create(:issue, project: project, milestone: milestone1) }
- let_it_be(:release_issue2) { create(:issue, project: project, milestone: milestone2) }
- let_it_be(:release_issue3) { create(:issue, project: project, milestone: milestone3) }
-
- describe 'filter by release_tag' do
- it 'returns all issues associated with the specified tags' do
- expect(resolve_issues(release_tag: [release1.tag, release3.tag])).to contain_exactly(release_issue1, release_issue3)
- end
-
- context 'when release_tag_wildcard_id is also provided' do
- it 'generates a mutually eclusive argument error' do
- expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'only one of [releaseTag, releaseTagWildcardId] arguments is allowed at the same time.') do
- resolve_issues(release_tag: [release1.tag], release_tag_wildcard_id: 'ANY')
- end
- end
- end
- end
-
- describe 'filter by negated release_tag' do
- it 'returns all issues not associated with the specified tags' do
- expect(resolve_issues(not: { release_tag: [release1.tag, release3.tag] })).to contain_exactly(release_issue2)
- end
- end
-
- describe 'filter by release_tag_wildcard_id' do
- subject { resolve_issues(release_tag_wildcard_id: wildcard_id) }
-
- context 'when filtering by ANY' do
- let(:wildcard_id) { 'ANY' }
-
- it { is_expected.to contain_exactly(release_issue1, release_issue2, release_issue3) }
- end
-
- context 'when filtering by NONE' do
- let(:wildcard_id) { 'NONE' }
-
- it { is_expected.to contain_exactly(issue1, issue2) }
- end
- end
- end
-
- it 'filters by two assignees' do
- assignee2 = create(:user)
- issue2.update!(assignees: [assignee, assignee2])
-
- expect(resolve_issues(assignee_id: [assignee.id, assignee2.id])).to contain_exactly(issue2)
- end
-
- it 'filters by assignee_id' do
- expect(resolve_issues(assignee_id: assignee.id)).to contain_exactly(issue2)
- end
-
- it 'filters by any assignee' do
- expect(resolve_issues(assignee_id: IssuableFinder::Params::FILTER_ANY)).to contain_exactly(issue2)
- end
-
- it 'filters by no assignee' do
- expect(resolve_issues(assignee_id: IssuableFinder::Params::FILTER_NONE)).to contain_exactly(issue1)
- end
-
- it 'filters by author' do
- expect(resolve_issues(author_username: issue1.author.username)).to contain_exactly(issue1, issue2)
- end
-
- it 'filters by labels' do
- expect(resolve_issues(label_name: [label1.title])).to contain_exactly(issue1, issue2)
- expect(resolve_issues(label_name: [label1.title, label2.title])).to contain_exactly(issue2)
- end
-
- describe 'filters by assignee_username' do
- it 'filters by assignee_username' do
- expect(resolve_issues(assignee_username: [assignee.username])).to contain_exactly(issue2)
- end
-
- it 'filters by assignee_usernames' do
- expect(resolve_issues(assignee_usernames: [assignee.username])).to contain_exactly(issue2)
- end
-
- context 'when both assignee_username and assignee_usernames are provided' do
- it 'generates a mutually exclusive filter error' do
- expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'only one of [assigneeUsernames, assigneeUsername] arguments is allowed at the same time.') do
- resolve_issues(assignee_usernames: [assignee.username], assignee_username: assignee.username)
- end
- end
- end
- end
-
- describe 'filters by created_at' do
- it 'filters by created_before' do
- expect(resolve_issues(created_before: 2.hours.ago)).to contain_exactly(issue1)
- end
-
- it 'filters by created_after' do
- expect(resolve_issues(created_after: 2.hours.ago)).to contain_exactly(issue2)
- end
- end
-
- describe 'filters by updated_at' do
- it 'filters by updated_before' do
- expect(resolve_issues(updated_before: 2.hours.ago)).to contain_exactly(issue1)
- end
-
- it 'filters by updated_after' do
- expect(resolve_issues(updated_after: 2.hours.ago)).to contain_exactly(issue2)
- end
- end
-
- describe 'filters by closed_at' do
- let!(:issue3) { create(:issue, project: project, state: :closed, closed_at: 3.hours.ago) }
-
- it 'filters by closed_before' do
- expect(resolve_issues(closed_before: 2.hours.ago)).to contain_exactly(issue3)
- end
-
- it 'filters by closed_after' do
- expect(resolve_issues(closed_after: 2.hours.ago)).to contain_exactly(issue2)
- end
- end
-
- describe 'filters by issue_type' do
- it 'filters by a single type' do
- expect(resolve_issues(types: %w[incident])).to contain_exactly(issue1)
- end
-
- it 'filters by a single type, negative assertion' do
- expect(resolve_issues(types: %w[issue])).not_to include(issue1)
- end
-
- it 'filters by more than one type' do
- expect(resolve_issues(types: %w[incident issue])).to contain_exactly(issue1, issue2)
- end
-
- it 'ignores the filter if none given' do
- expect(resolve_issues(types: [])).to contain_exactly(issue1, issue2)
- end
- end
-
- context 'filtering by reaction emoji' do
- let_it_be(:downvoted_issue) { create(:issue, project: project) }
- let_it_be(:downvote_award) { create(:award_emoji, :downvote, user: current_user, awardable: downvoted_issue) }
-
- it 'filters by reaction emoji' do
- expect(resolve_issues(my_reaction_emoji: upvote_award.name)).to contain_exactly(issue1)
- end
-
- it 'filters by reaction emoji wildcard "none"' do
- expect(resolve_issues(my_reaction_emoji: 'none')).to contain_exactly(issue2)
- end
-
- it 'filters by reaction emoji wildcard "any"' do
- expect(resolve_issues(my_reaction_emoji: 'any')).to contain_exactly(issue1, downvoted_issue)
- end
-
- it 'filters by negated reaction emoji' do
- expect(resolve_issues(not: { my_reaction_emoji: downvote_award.name })).to contain_exactly(issue1, issue2)
- end
- end
-
- context 'confidential issues' do
- let_it_be(:confidential_issue1) { create(:issue, project: project, confidential: true) }
- let_it_be(:confidential_issue2) { create(:issue, project: other_project, confidential: true) }
-
- context "when user is allowed to view confidential issues" do
- it 'returns all viewable issues by default' do
- expect(resolve_issues).to contain_exactly(issue1, issue2, confidential_issue1)
- end
-
- it 'returns only the non-confidential issues for the project when filter is set to false' do
- expect(resolve_issues({ confidential: false })).to contain_exactly(issue1, issue2)
- end
-
- it "returns only the confidential issues for the project when filter is set to true" do
- expect(resolve_issues({ confidential: true })).to contain_exactly(confidential_issue1)
- end
- end
-
- context "when user is not allowed to see confidential issues" do
- before do
- project.add_guest(current_user)
- end
-
- it 'returns all viewable issues by default' do
- expect(resolve_issues).to contain_exactly(issue1, issue2)
- end
-
- it 'does not return the confidential issues when filter is set to false' do
- expect(resolve_issues({ confidential: false })).to contain_exactly(issue1, issue2)
- end
-
- it 'does not return the confidential issues when filter is set to true' do
- expect(resolve_issues({ confidential: true })).to be_empty
- end
- end
- end
-
- context 'when searching issues' do
- it_behaves_like 'graphql query for searching issuables' do
- let_it_be(:parent) { project }
- let_it_be(:issuable1) { create(:issue, project: project, title: 'first created') }
- let_it_be(:issuable2) { create(:issue, project: project, title: 'second created', description: 'text 1') }
- let_it_be(:issuable3) { create(:issue, project: project, title: 'third', description: 'text 2') }
- let_it_be(:issuable4) { create(:issue, project: project) }
-
- let_it_be(:finder_class) { IssuesFinder }
- let_it_be(:optimization_param) { :attempt_project_search_optimizations }
- end
- end
-
- describe 'filters by negated params' do
- it 'returns issues without the specified iids' do
- expect(resolve_issues(not: { iids: [issue1.iid] })).to contain_exactly(issue2)
- end
-
- it 'returns issues without the specified label names' do
- expect(resolve_issues(not: { label_name: [label1.title] })).to be_empty
- expect(resolve_issues(not: { label_name: [label2.title] })).to contain_exactly(issue1)
- end
-
- it 'returns issues without the specified milestone' do
- expect(resolve_issues(not: { milestone_title: [started_milestone.title] })).to contain_exactly(issue2)
- end
-
- it 'returns issues without the specified assignee_usernames' do
- expect(resolve_issues(not: { assignee_usernames: [assignee.username] })).to contain_exactly(issue1)
- end
-
- it 'returns issues without the specified assignee_id' do
- expect(resolve_issues(not: { assignee_id: [assignee.id] })).to contain_exactly(issue1)
- end
-
- it 'returns issues without the specified issue_type' do
- expect(resolve_issues(not: { types: ['issue'] })).to contain_exactly(issue1)
- end
-
- context 'when filtering by negated author' do
- let_it_be(:issue_by_reporter) { create(:issue, author: reporter, project: project, state: :opened) }
-
- it 'returns issues without the specified author_username' do
- expect(resolve_issues(not: { author_username: issue1.author.username })).to contain_exactly(issue_by_reporter)
- end
- end
- end
-
- describe 'filtering by crm' do
- let_it_be(:organization) { create(:organization, group: group) }
- let_it_be(:contact1) { create(:contact, group: group, organization: organization) }
- let_it_be(:contact2) { create(:contact, group: group, organization: organization) }
- let_it_be(:contact3) { create(:contact, group: group) }
- let_it_be(:crm_issue1) { create(:issue, project: project) }
- let_it_be(:crm_issue2) { create(:issue, project: project) }
- let_it_be(:crm_issue3) { create(:issue, project: project) }
-
- before_all do
- group.add_developer(current_user)
-
- create(:issue_customer_relations_contact, issue: crm_issue1, contact: contact1)
- create(:issue_customer_relations_contact, issue: crm_issue2, contact: contact2)
- create(:issue_customer_relations_contact, issue: crm_issue3, contact: contact3)
- end
-
- context 'contact' do
- it 'returns only the issues for the contact' do
- expect(resolve_issues({ crm_contact_id: contact1.id })).to contain_exactly(crm_issue1)
- end
- end
-
- context 'organization' do
- it 'returns only the issues for the contact' do
- expect(resolve_issues({ crm_organization_id: organization.id })).to contain_exactly(crm_issue1, crm_issue2)
- end
- end
- end
-
- describe 'sorting' do
- context 'when sorting by created' do
- it 'sorts issues ascending' do
- expect(resolve_issues(sort: 'created_asc').to_a).to eq [issue1, issue2]
- end
-
- it 'sorts issues descending' do
- expect(resolve_issues(sort: 'created_desc').to_a).to eq [issue2, issue1]
- end
- end
-
- context 'when sorting by closed at' do
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:closed_issue1) { create(:issue, project: project, closed_at: 3.days.from_now) }
- let_it_be(:closed_issue2) { create(:issue, project: project, closed_at: nil) }
- let_it_be(:closed_issue3) { create(:issue, project: project, closed_at: 2.days.ago) }
- let_it_be(:closed_issue4) { create(:issue, project: project, closed_at: nil) }
-
- it 'sorts issues ascending' do
- expect(resolve_issues(sort: :closed_at_asc).to_a).to eq [closed_issue3, closed_issue1, closed_issue4, closed_issue2]
- end
-
- it 'sorts issues descending' do
- expect(resolve_issues(sort: :closed_at_desc).to_a).to eq [closed_issue1, closed_issue3, closed_issue4, closed_issue2]
- end
- end
-
- context 'when sorting by due date' do
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:due_issue1) { create(:issue, project: project, due_date: 3.days.from_now) }
- let_it_be(:due_issue2) { create(:issue, project: project, due_date: nil) }
- let_it_be(:due_issue3) { create(:issue, project: project, due_date: 2.days.ago) }
- let_it_be(:due_issue4) { create(:issue, project: project, due_date: nil) }
-
- it 'sorts issues ascending' do
- expect(resolve_issues(sort: :due_date_asc).to_a).to eq [due_issue3, due_issue1, due_issue4, due_issue2]
- end
-
- it 'sorts issues descending' do
- expect(resolve_issues(sort: :due_date_desc).to_a).to eq [due_issue1, due_issue3, due_issue4, due_issue2]
- end
- end
-
- context 'when sorting by relative position' do
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:relative_issue1) { create(:issue, project: project, relative_position: 2000) }
- let_it_be(:relative_issue2) { create(:issue, project: project, relative_position: nil) }
- let_it_be(:relative_issue3) { create(:issue, project: project, relative_position: 1000) }
- let_it_be(:relative_issue4) { create(:issue, project: project, relative_position: nil) }
-
- it 'sorts issues ascending' do
- expect(resolve_issues(sort: :relative_position_asc).to_a).to eq [relative_issue3, relative_issue1, relative_issue2, relative_issue4]
- end
- end
-
- context 'when sorting by priority' do
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:early_milestone) { create(:milestone, project: project, due_date: 10.days.from_now) }
- let_it_be(:late_milestone) { create(:milestone, project: project, due_date: 30.days.from_now) }
- let_it_be(:priority_label1) { create(:label, project: project, priority: 1) }
- let_it_be(:priority_label2) { create(:label, project: project, priority: 5) }
- let_it_be(:priority_issue1) { create(:issue, project: project, labels: [priority_label1], milestone: late_milestone) }
- let_it_be(:priority_issue2) { create(:issue, project: project, labels: [priority_label2]) }
- let_it_be(:priority_issue3) { create(:issue, project: project, milestone: early_milestone) }
- let_it_be(:priority_issue4) { create(:issue, project: project) }
-
- it 'sorts issues ascending' do
- expect(resolve_issues(sort: :priority_asc).to_a).to eq([priority_issue3, priority_issue1, priority_issue2, priority_issue4])
- end
-
- it 'sorts issues descending' do
- expect(resolve_issues(sort: :priority_desc).to_a).to eq([priority_issue1, priority_issue3, priority_issue2, priority_issue4])
- end
- end
-
- context 'when sorting by label priority' do
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:label1) { create(:label, project: project, priority: 1) }
- let_it_be(:label2) { create(:label, project: project, priority: 5) }
- let_it_be(:label3) { create(:label, project: project, priority: 10) }
- let_it_be(:label_issue1) { create(:issue, project: project, labels: [label1]) }
- let_it_be(:label_issue2) { create(:issue, project: project, labels: [label2]) }
- let_it_be(:label_issue3) { create(:issue, project: project, labels: [label1, label3]) }
- let_it_be(:label_issue4) { create(:issue, project: project) }
-
- it 'sorts issues ascending' do
- expect(resolve_issues(sort: :label_priority_asc).to_a).to eq([label_issue3, label_issue1, label_issue2, label_issue4])
- end
-
- it 'sorts issues descending' do
- expect(resolve_issues(sort: :label_priority_desc).to_a).to eq([label_issue2, label_issue3, label_issue1, label_issue4])
- end
- end
-
- context 'when sorting by milestone due date' do
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:early_milestone) { create(:milestone, project: project, due_date: 10.days.from_now) }
- let_it_be(:late_milestone) { create(:milestone, project: project, due_date: 30.days.from_now) }
- let_it_be(:milestone_issue1) { create(:issue, project: project) }
- let_it_be(:milestone_issue2) { create(:issue, project: project, milestone: early_milestone) }
- let_it_be(:milestone_issue3) { create(:issue, project: project, milestone: late_milestone) }
-
- it 'sorts issues ascending' do
- expect(resolve_issues(sort: :milestone_due_asc).to_a).to eq([milestone_issue2, milestone_issue3, milestone_issue1])
- end
-
- it 'sorts issues descending' do
- expect(resolve_issues(sort: :milestone_due_desc).to_a).to eq([milestone_issue3, milestone_issue2, milestone_issue1])
- end
- end
-
- context 'when sorting by severity' do
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:issue_high_severity) { create_issue_with_severity(project, severity: :high) }
- let_it_be(:issue_low_severity) { create_issue_with_severity(project, severity: :low) }
- let_it_be(:issue_no_severity) { create(:incident, project: project) }
-
- it 'sorts issues ascending' do
- expect(resolve_issues(sort: :severity_asc).to_a).to eq([issue_no_severity, issue_low_severity, issue_high_severity])
- end
-
- it 'sorts issues descending' do
- expect(resolve_issues(sort: :severity_desc).to_a).to eq([issue_high_severity, issue_low_severity, issue_no_severity])
- end
- end
-
- context 'when sorting by popularity' do
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:issue1) { create(:issue, project: project) } # has one upvote
- let_it_be(:issue2) { create(:issue, project: project) } # has two upvote
- let_it_be(:issue3) { create(:issue, project: project) }
- let_it_be(:issue4) { create(:issue, project: project) } # has one upvote
-
- before do
- create(:award_emoji, :upvote, awardable: issue1)
- create(:award_emoji, :upvote, awardable: issue2)
- create(:award_emoji, :upvote, awardable: issue2)
- create(:award_emoji, :upvote, awardable: issue4)
- end
-
- it 'sorts issues ascending (ties broken by id in desc order)' do
- expect(resolve_issues(sort: :popularity_asc).to_a).to eq([issue3, issue4, issue1, issue2])
- end
-
- it 'sorts issues descending (ties broken by id in desc order)' do
- expect(resolve_issues(sort: :popularity_desc).to_a).to eq([issue2, issue4, issue1, issue3])
- end
- end
-
- context 'when sorting by escalation status' do
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:triggered_incident) { create(:incident, :with_escalation_status, project: project) }
- let_it_be(:issue_no_status) { create(:issue, project: project) }
- let_it_be(:resolved_incident) do
- create(:incident, :with_escalation_status, project: project)
- .tap { |issue| issue.escalation_status.resolve }
- end
-
- it 'sorts issues ascending' do
- issues = resolve_issues(sort: :escalation_status_asc).to_a
- expect(issues).to eq([triggered_incident, resolved_incident, issue_no_status])
- end
-
- it 'sorts issues descending' do
- issues = resolve_issues(sort: :escalation_status_desc).to_a
- expect(issues).to eq([resolved_incident, triggered_incident, issue_no_status])
- end
-
- it 'sorts issues created_at' do
- issues = resolve_issues(sort: :created_desc).to_a
- expect(issues).to eq([resolved_incident, issue_no_status, triggered_incident])
- end
- end
-
- context 'when sorting with non-stable cursors' do
- %i[priority_asc priority_desc
- popularity_asc popularity_desc
- label_priority_asc label_priority_desc
- milestone_due_asc milestone_due_desc
- escalation_status_asc escalation_status_desc].each do |sort_by|
- it "uses offset-pagination when sorting by #{sort_by}" do
- resolved = resolve_issues(sort: sort_by)
-
- expect(resolved).to be_a(::Gitlab::Graphql::Pagination::OffsetActiveRecordRelationConnection)
- end
- end
- end
-
- context 'when sorting by title' do
- let_it_be(:project) { create(:project, :public) }
- let_it_be(:issue1) { create(:issue, project: project, title: 'foo') }
- let_it_be(:issue2) { create(:issue, project: project, title: 'bar') }
- let_it_be(:issue3) { create(:issue, project: project, title: 'baz') }
- let_it_be(:issue4) { create(:issue, project: project, title: 'Baz 2') }
-
- it 'sorts issues ascending' do
- expect(resolve_issues(sort: :title_asc).to_a).to eq [issue2, issue3, issue4, issue1]
- end
-
- it 'sorts issues descending' do
- expect(resolve_issues(sort: :title_desc).to_a).to eq [issue1, issue4, issue3, issue2]
- end
- end
- end
-
- it 'returns issues user can see' do
- project.add_guest(current_user)
-
- create(:issue, confidential: true)
-
- expect(resolve_issues).to contain_exactly(issue1, issue2)
- end
-
- it 'finds a specific issue with iid', :request_store do
- result = batch_sync(max_queries: 8) { resolve_issues(iid: issue1.iid).to_a }
-
- expect(result).to contain_exactly(issue1)
- end
-
- it 'batches queries that only include IIDs', :request_store do
- result = batch_sync(max_queries: 8) do
- [issue1, issue2]
- .map { |issue| resolve_issues(iid: issue.iid.to_s) }
- .flat_map(&:to_a)
- end
-
- expect(result).to contain_exactly(issue1, issue2)
- end
-
- it 'finds a specific issue with iids', :request_store do
- result = batch_sync(max_queries: 8) do
- resolve_issues(iids: [issue1.iid]).to_a
- end
-
- expect(result).to contain_exactly(issue1)
- end
-
- it 'finds multiple issues with iids' do
- create(:issue, project: project, author: current_user)
-
- expect(batch_sync { resolve_issues(iids: [issue1.iid, issue2.iid]).to_a })
- .to contain_exactly(issue1, issue2)
- end
-
- it 'finds only the issues within the project we are looking at' do
- another_project = create(:project)
- iids = [issue1, issue2].map(&:iid)
-
- iids.each do |iid|
- create(:issue, project: another_project, iid: iid)
- end
-
- expect(batch_sync { resolve_issues(iids: iids).to_a }).to contain_exactly(issue1, issue2)
- end
- end
- end
-
- context "when passing a non existent, batch loaded project" do
- let!(:project) do
- BatchLoader::GraphQL.for("non-existent-path").batch do |_fake_paths, loader, _|
- loader.call("non-existent-path", nil)
- end
- end
-
- it "returns nil without breaking" do
- expect(resolve_issues(iids: ["don't", "break"])).to be_empty
- end
- end
-
- it 'increases field complexity based on arguments' do
- field = Types::BaseField.new(name: 'test', type: GraphQL::Types::String.connection_type, resolver_class: described_class, null: false, max_page_size: 100)
-
- expect(field.complexity.call({}, {}, 1)).to eq 4
- expect(field.complexity.call({}, { labelName: 'foo' }, 1)).to eq 8
- end
-
- def create_issue_with_severity(project, severity:)
- issue = create(:incident, project: project)
- create(:issuable_severity, issue: issue, severity: severity)
-
- issue
- end
-
- def resolve_issues(args = {}, context = { current_user: current_user })
- resolve(described_class, obj: project, args: args, ctx: context, arg_style: :internal)
- end
-end
diff --git a/spec/graphql/resolvers/project_issues_resolver_spec.rb b/spec/graphql/resolvers/project_issues_resolver_spec.rb
new file mode 100644
index 00000000000..b2796ad9b18
--- /dev/null
+++ b/spec/graphql/resolvers/project_issues_resolver_spec.rb
@@ -0,0 +1,677 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Resolvers::ProjectIssuesResolver do
+ include GraphqlHelpers
+
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
+ let_it_be(:other_project) { create(:project, group: group) }
+
+ let_it_be(:started_milestone) { create(:milestone, project: project, title: "started milestone", start_date: 1.day.ago) }
+ let_it_be(:assignee) { create(:user) }
+ let_it_be(:issue1) { create(:incident, project: project, state: :opened, created_at: 3.hours.ago, updated_at: 3.hours.ago, milestone: started_milestone) }
+ let_it_be(:issue2) { create(:issue, project: project, state: :closed, title: 'foo', created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at: 1.hour.ago, assignees: [assignee]) }
+ let_it_be(:issue3) { create(:issue, project: other_project, state: :closed, title: 'foo', created_at: 1.hour.ago, updated_at: 1.hour.ago, closed_at: 1.hour.ago, assignees: [assignee]) }
+ let_it_be(:issue4) { create(:issue) }
+ let_it_be(:label1) { create(:label, project: project) }
+ let_it_be(:label2) { create(:label, project: project) }
+ let_it_be(:upvote_award) { create(:award_emoji, :upvote, user: current_user, awardable: issue1) }
+
+ specify do
+ expect(described_class).to have_nullable_graphql_type(Types::IssueType.connection_type)
+ end
+
+ context "with a project" do
+ before_all do
+ project.add_developer(current_user)
+ project.add_reporter(reporter)
+
+ create(:crm_settings, group: group, enabled: true)
+
+ create(:label_link, label: label1, target: issue1)
+ create(:label_link, label: label1, target: issue2)
+ create(:label_link, label: label2, target: issue2)
+ end
+
+ describe '#resolve' do
+ it 'finds all issues' do
+ expect(resolve_issues).to contain_exactly(issue1, issue2)
+ end
+
+ it 'filters by state' do
+ expect(resolve_issues(state: 'opened')).to contain_exactly(issue1)
+ expect(resolve_issues(state: 'closed')).to contain_exactly(issue2)
+ end
+
+ it 'filters by milestone' do
+ expect(resolve_issues(milestone_title: [started_milestone.title])).to contain_exactly(issue1)
+ end
+
+ describe 'filtering by milestone wildcard id' do
+ let_it_be(:upcoming_milestone) { create(:milestone, project: project, title: "upcoming milestone", start_date: 1.day.ago, due_date: 1.day.from_now) }
+ let_it_be(:past_milestone) { create(:milestone, project: project, title: "past milestone", due_date: 1.day.ago) }
+ let_it_be(:future_milestone) { create(:milestone, project: project, title: "future milestone", start_date: 1.day.from_now) }
+ let_it_be(:issue5) { create(:issue, project: project, state: :opened, milestone: upcoming_milestone) }
+ let_it_be(:issue6) { create(:issue, project: project, state: :opened, milestone: past_milestone) }
+ let_it_be(:issue7) { create(:issue, project: project, state: :opened, milestone: future_milestone) }
+
+ let(:wildcard_started) { 'STARTED' }
+ let(:wildcard_upcoming) { 'UPCOMING' }
+ let(:wildcard_any) { 'ANY' }
+ let(:wildcard_none) { 'NONE' }
+
+ it 'returns issues with started milestone' do
+ expect(resolve_issues(milestone_wildcard_id: wildcard_started)).to contain_exactly(issue1, issue5)
+ end
+
+ it 'returns issues with upcoming milestone' do
+ expect(resolve_issues(milestone_wildcard_id: wildcard_upcoming)).to contain_exactly(issue5)
+ end
+
+ it 'returns issues with any milestone' do
+ expect(resolve_issues(milestone_wildcard_id: wildcard_any)).to contain_exactly(issue1, issue5, issue6, issue7)
+ end
+
+ it 'returns issues with no milestone' do
+ expect(resolve_issues(milestone_wildcard_id: wildcard_none)).to contain_exactly(issue2)
+ end
+
+ it 'generates a mutually exclusive filter error when wildcard and title are provided' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'only one of [milestoneTitle, milestoneWildcardId] arguments is allowed at the same time.') do
+ resolve_issues(milestone_title: ["started milestone"], milestone_wildcard_id: wildcard_started)
+ end
+ end
+
+ context 'when using negated filters' do
+ it 'returns issues matching the searched title after applying a negated filter' do
+ expect(resolve_issues(milestone_title: ['past milestone'], not: { milestone_wildcard_id: wildcard_upcoming })).to contain_exactly(issue6)
+ end
+
+ it 'returns issues excluding the ones with started milestone' do
+ expect(resolve_issues(not: { milestone_wildcard_id: wildcard_started })).to contain_exactly(issue7)
+ end
+
+ it 'returns issues excluding the ones with upcoming milestone' do
+ expect(resolve_issues(not: { milestone_wildcard_id: wildcard_upcoming })).to contain_exactly(issue6)
+ end
+
+ it 'generates a mutually exclusive filter error when wildcard and title are provided as negated filters' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'only one of [milestoneTitle, milestoneWildcardId] arguments is allowed at the same time.') do
+ resolve_issues(not: { milestone_title: ["started milestone"], milestone_wildcard_id: wildcard_started })
+ end
+ end
+ end
+ end
+
+ describe 'filter by release' do
+ let_it_be(:milestone1) { create(:milestone, project: project, start_date: 1.day.from_now, title: 'Version 1') }
+ let_it_be(:milestone2) { create(:milestone, project: project, start_date: 1.day.from_now, title: 'Version 2') }
+ let_it_be(:milestone3) { create(:milestone, project: project, start_date: 1.day.from_now, title: 'Version 3') }
+ let_it_be(:release1) { create(:release, tag: 'v1.0', milestones: [milestone1], project: project) }
+ let_it_be(:release2) { create(:release, tag: 'v2.0', milestones: [milestone2], project: project) }
+ let_it_be(:release3) { create(:release, tag: 'v3.0', milestones: [milestone3], project: project) }
+ let_it_be(:release_issue1) { create(:issue, project: project, milestone: milestone1) }
+ let_it_be(:release_issue2) { create(:issue, project: project, milestone: milestone2) }
+ let_it_be(:release_issue3) { create(:issue, project: project, milestone: milestone3) }
+
+ describe 'filter by release_tag' do
+ it 'returns all issues associated with the specified tags' do
+ expect(resolve_issues(release_tag: [release1.tag, release3.tag])).to contain_exactly(release_issue1, release_issue3)
+ end
+
+ context 'when release_tag_wildcard_id is also provided' do
+ it 'generates a mutually eclusive argument error' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'only one of [releaseTag, releaseTagWildcardId] arguments is allowed at the same time.') do
+ resolve_issues(release_tag: [release1.tag], release_tag_wildcard_id: 'ANY')
+ end
+ end
+ end
+ end
+
+ describe 'filter by negated release_tag' do
+ it 'returns all issues not associated with the specified tags' do
+ expect(resolve_issues(not: { release_tag: [release1.tag, release3.tag] })).to contain_exactly(release_issue2)
+ end
+ end
+
+ describe 'filter by release_tag_wildcard_id' do
+ subject { resolve_issues(release_tag_wildcard_id: wildcard_id) }
+
+ context 'when filtering by ANY' do
+ let(:wildcard_id) { 'ANY' }
+
+ it { is_expected.to contain_exactly(release_issue1, release_issue2, release_issue3) }
+ end
+
+ context 'when filtering by NONE' do
+ let(:wildcard_id) { 'NONE' }
+
+ it { is_expected.to contain_exactly(issue1, issue2) }
+ end
+ end
+ end
+
+ it 'filters by two assignees' do
+ assignee2 = create(:user)
+ issue2.update!(assignees: [assignee, assignee2])
+
+ expect(resolve_issues(assignee_id: [assignee.id, assignee2.id])).to contain_exactly(issue2)
+ end
+
+ it 'filters by assignee_id' do
+ expect(resolve_issues(assignee_id: assignee.id)).to contain_exactly(issue2)
+ end
+
+ it 'filters by any assignee' do
+ expect(resolve_issues(assignee_id: IssuableFinder::Params::FILTER_ANY)).to contain_exactly(issue2)
+ end
+
+ it 'filters by no assignee' do
+ expect(resolve_issues(assignee_id: IssuableFinder::Params::FILTER_NONE)).to contain_exactly(issue1)
+ end
+
+ it 'filters by author' do
+ expect(resolve_issues(author_username: issue1.author.username)).to contain_exactly(issue1, issue2)
+ end
+
+ it 'filters by labels' do
+ expect(resolve_issues(label_name: [label1.title])).to contain_exactly(issue1, issue2)
+ expect(resolve_issues(label_name: [label1.title, label2.title])).to contain_exactly(issue2)
+ end
+
+ describe 'filters by assignee_username' do
+ it 'filters by assignee_username' do
+ expect(resolve_issues(assignee_username: [assignee.username])).to contain_exactly(issue2)
+ end
+
+ it 'filters by assignee_usernames' do
+ expect(resolve_issues(assignee_usernames: [assignee.username])).to contain_exactly(issue2)
+ end
+
+ context 'when both assignee_username and assignee_usernames are provided' do
+ it 'generates a mutually exclusive filter error' do
+ expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError, 'only one of [assigneeUsernames, assigneeUsername] arguments is allowed at the same time.') do
+ resolve_issues(assignee_usernames: [assignee.username], assignee_username: assignee.username)
+ end
+ end
+ end
+ end
+
+ describe 'filters by created_at' do
+ it 'filters by created_before' do
+ expect(resolve_issues(created_before: 2.hours.ago)).to contain_exactly(issue1)
+ end
+
+ it 'filters by created_after' do
+ expect(resolve_issues(created_after: 2.hours.ago)).to contain_exactly(issue2)
+ end
+ end
+
+ describe 'filters by updated_at' do
+ it 'filters by updated_before' do
+ expect(resolve_issues(updated_before: 2.hours.ago)).to contain_exactly(issue1)
+ end
+
+ it 'filters by updated_after' do
+ expect(resolve_issues(updated_after: 2.hours.ago)).to contain_exactly(issue2)
+ end
+ end
+
+ describe 'filters by closed_at' do
+ let!(:issue3) { create(:issue, project: project, state: :closed, closed_at: 3.hours.ago) }
+
+ it 'filters by closed_before' do
+ expect(resolve_issues(closed_before: 2.hours.ago)).to contain_exactly(issue3)
+ end
+
+ it 'filters by closed_after' do
+ expect(resolve_issues(closed_after: 2.hours.ago)).to contain_exactly(issue2)
+ end
+ end
+
+ describe 'filters by issue_type' do
+ it 'filters by a single type' do
+ expect(resolve_issues(types: %w[incident])).to contain_exactly(issue1)
+ end
+
+ it 'filters by a single type, negative assertion' do
+ expect(resolve_issues(types: %w[issue])).not_to include(issue1)
+ end
+
+ it 'filters by more than one type' do
+ expect(resolve_issues(types: %w[incident issue])).to contain_exactly(issue1, issue2)
+ end
+
+ it 'ignores the filter if none given' do
+ expect(resolve_issues(types: [])).to contain_exactly(issue1, issue2)
+ end
+ end
+
+ context 'when filtering by reaction emoji' do
+ let_it_be(:downvoted_issue) { create(:issue, project: project) }
+ let_it_be(:downvote_award) { create(:award_emoji, :downvote, user: current_user, awardable: downvoted_issue) }
+
+ it 'filters by reaction emoji' do
+ expect(resolve_issues(my_reaction_emoji: upvote_award.name)).to contain_exactly(issue1)
+ end
+
+ it 'filters by reaction emoji wildcard "none"' do
+ expect(resolve_issues(my_reaction_emoji: 'none')).to contain_exactly(issue2)
+ end
+
+ it 'filters by reaction emoji wildcard "any"' do
+ expect(resolve_issues(my_reaction_emoji: 'any')).to contain_exactly(issue1, downvoted_issue)
+ end
+
+ it 'filters by negated reaction emoji' do
+ expect(resolve_issues(not: { my_reaction_emoji: downvote_award.name })).to contain_exactly(issue1, issue2)
+ end
+ end
+
+ context 'when listing confidential issues' do
+ let_it_be(:confidential_issue1) { create(:issue, project: project, confidential: true) }
+ let_it_be(:confidential_issue2) { create(:issue, project: other_project, confidential: true) }
+
+ context "when user is allowed to view confidential issues" do
+ it 'returns all viewable issues by default' do
+ expect(resolve_issues).to contain_exactly(issue1, issue2, confidential_issue1)
+ end
+
+ it 'returns only the non-confidential issues for the project when filter is set to false' do
+ expect(resolve_issues({ confidential: false })).to contain_exactly(issue1, issue2)
+ end
+
+ it "returns only the confidential issues for the project when filter is set to true" do
+ expect(resolve_issues({ confidential: true })).to contain_exactly(confidential_issue1)
+ end
+ end
+
+ context "when user is not allowed to see confidential issues" do
+ before do
+ project.add_guest(current_user)
+ end
+
+ it 'returns all viewable issues by default' do
+ expect(resolve_issues).to contain_exactly(issue1, issue2)
+ end
+
+ it 'does not return the confidential issues when filter is set to false' do
+ expect(resolve_issues({ confidential: false })).to contain_exactly(issue1, issue2)
+ end
+
+ it 'does not return the confidential issues when filter is set to true' do
+ expect(resolve_issues({ confidential: true })).to be_empty
+ end
+ end
+ end
+
+ context 'when searching issues' do
+ it_behaves_like 'graphql query for searching issuables' do
+ let_it_be(:parent) { project }
+ let_it_be(:issuable1) { create(:issue, project: project, title: 'first created') }
+ let_it_be(:issuable2) { create(:issue, project: project, title: 'second created', description: 'text 1') }
+ let_it_be(:issuable3) { create(:issue, project: project, title: 'third', description: 'text 2') }
+ let_it_be(:issuable4) { create(:issue, project: project) }
+
+ let_it_be(:finder_class) { IssuesFinder }
+ let_it_be(:optimization_param) { :attempt_project_search_optimizations }
+ end
+ end
+
+ describe 'filters by negated params' do
+ it 'returns issues without the specified iids' do
+ expect(resolve_issues(not: { iids: [issue1.iid] })).to contain_exactly(issue2)
+ end
+
+ it 'returns issues without the specified label names' do
+ expect(resolve_issues(not: { label_name: [label1.title] })).to be_empty
+ expect(resolve_issues(not: { label_name: [label2.title] })).to contain_exactly(issue1)
+ end
+
+ it 'returns issues without the specified milestone' do
+ expect(resolve_issues(not: { milestone_title: [started_milestone.title] })).to contain_exactly(issue2)
+ end
+
+ it 'returns issues without the specified assignee_usernames' do
+ expect(resolve_issues(not: { assignee_usernames: [assignee.username] })).to contain_exactly(issue1)
+ end
+
+ it 'returns issues without the specified assignee_id' do
+ expect(resolve_issues(not: { assignee_id: [assignee.id] })).to contain_exactly(issue1)
+ end
+
+ it 'returns issues without the specified issue_type' do
+ expect(resolve_issues(not: { types: ['issue'] })).to contain_exactly(issue1)
+ end
+
+ context 'when filtering by negated author' do
+ let_it_be(:issue_by_reporter) { create(:issue, author: reporter, project: project, state: :opened) }
+
+ it 'returns issues without the specified author_username' do
+ expect(resolve_issues(not: { author_username: issue1.author.username })).to contain_exactly(issue_by_reporter)
+ end
+ end
+ end
+
+ describe 'filtering by crm' do
+ let_it_be(:organization) { create(:organization, group: group) }
+ let_it_be(:contact1) { create(:contact, group: group, organization: organization) }
+ let_it_be(:contact2) { create(:contact, group: group, organization: organization) }
+ let_it_be(:contact3) { create(:contact, group: group) }
+ let_it_be(:crm_issue1) { create(:issue, project: project) }
+ let_it_be(:crm_issue2) { create(:issue, project: project) }
+ let_it_be(:crm_issue3) { create(:issue, project: project) }
+
+ before_all do
+ group.add_developer(current_user)
+
+ create(:issue_customer_relations_contact, issue: crm_issue1, contact: contact1)
+ create(:issue_customer_relations_contact, issue: crm_issue2, contact: contact2)
+ create(:issue_customer_relations_contact, issue: crm_issue3, contact: contact3)
+ end
+
+ context 'when filtering by contact' do
+ it 'returns only the issues for the contact' do
+ expect(resolve_issues({ crm_contact_id: contact1.id })).to contain_exactly(crm_issue1)
+ end
+ end
+
+ context 'when filtering by organization' do
+ it 'returns only the issues for the contact' do
+ expect(resolve_issues({ crm_organization_id: organization.id })).to contain_exactly(crm_issue1, crm_issue2)
+ end
+ end
+ end
+
+ describe 'sorting' do
+ context 'when sorting by created' do
+ it 'sorts issues ascending' do
+ expect(resolve_issues(sort: 'created_asc').to_a).to eq [issue1, issue2]
+ end
+
+ it 'sorts issues descending' do
+ expect(resolve_issues(sort: 'created_desc').to_a).to eq [issue2, issue1]
+ end
+ end
+
+ context 'when sorting by closed at' do
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:closed_issue1) { create(:issue, project: project, closed_at: 3.days.from_now) }
+ let_it_be(:closed_issue2) { create(:issue, project: project, closed_at: nil) }
+ let_it_be(:closed_issue3) { create(:issue, project: project, closed_at: 2.days.ago) }
+ let_it_be(:closed_issue4) { create(:issue, project: project, closed_at: nil) }
+
+ it 'sorts issues ascending' do
+ expect(resolve_issues(sort: :closed_at_asc).to_a).to eq [closed_issue3, closed_issue1, closed_issue4, closed_issue2]
+ end
+
+ it 'sorts issues descending' do
+ expect(resolve_issues(sort: :closed_at_desc).to_a).to eq [closed_issue1, closed_issue3, closed_issue4, closed_issue2]
+ end
+ end
+
+ context 'when sorting by due date' do
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:due_issue1) { create(:issue, project: project, due_date: 3.days.from_now) }
+ let_it_be(:due_issue2) { create(:issue, project: project, due_date: nil) }
+ let_it_be(:due_issue3) { create(:issue, project: project, due_date: 2.days.ago) }
+ let_it_be(:due_issue4) { create(:issue, project: project, due_date: nil) }
+
+ it 'sorts issues ascending' do
+ expect(resolve_issues(sort: :due_date_asc).to_a).to eq [due_issue3, due_issue1, due_issue4, due_issue2]
+ end
+
+ it 'sorts issues descending' do
+ expect(resolve_issues(sort: :due_date_desc).to_a).to eq [due_issue1, due_issue3, due_issue4, due_issue2]
+ end
+ end
+
+ context 'when sorting by relative position' do
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:relative_issue1) { create(:issue, project: project, relative_position: 2000) }
+ let_it_be(:relative_issue2) { create(:issue, project: project, relative_position: nil) }
+ let_it_be(:relative_issue3) { create(:issue, project: project, relative_position: 1000) }
+ let_it_be(:relative_issue4) { create(:issue, project: project, relative_position: nil) }
+
+ it 'sorts issues ascending' do
+ expect(resolve_issues(sort: :relative_position_asc).to_a).to eq [relative_issue3, relative_issue1, relative_issue2, relative_issue4]
+ end
+ end
+
+ context 'when sorting by priority' do
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:early_milestone) { create(:milestone, project: project, due_date: 10.days.from_now) }
+ let_it_be(:late_milestone) { create(:milestone, project: project, due_date: 30.days.from_now) }
+ let_it_be(:priority_label1) { create(:label, project: project, priority: 1) }
+ let_it_be(:priority_label2) { create(:label, project: project, priority: 5) }
+ let_it_be(:priority_issue1) { create(:issue, project: project, labels: [priority_label1], milestone: late_milestone) }
+ let_it_be(:priority_issue2) { create(:issue, project: project, labels: [priority_label2]) }
+ let_it_be(:priority_issue3) { create(:issue, project: project, milestone: early_milestone) }
+ let_it_be(:priority_issue4) { create(:issue, project: project) }
+
+ it 'sorts issues ascending' do
+ expect(resolve_issues(sort: :priority_asc).to_a).to eq([priority_issue3, priority_issue1, priority_issue2, priority_issue4])
+ end
+
+ it 'sorts issues descending' do
+ expect(resolve_issues(sort: :priority_desc).to_a).to eq([priority_issue1, priority_issue3, priority_issue2, priority_issue4])
+ end
+ end
+
+ context 'when sorting by label priority' do
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:label1) { create(:label, project: project, priority: 1) }
+ let_it_be(:label2) { create(:label, project: project, priority: 5) }
+ let_it_be(:label3) { create(:label, project: project, priority: 10) }
+ let_it_be(:label_issue1) { create(:issue, project: project, labels: [label1]) }
+ let_it_be(:label_issue2) { create(:issue, project: project, labels: [label2]) }
+ let_it_be(:label_issue3) { create(:issue, project: project, labels: [label1, label3]) }
+ let_it_be(:label_issue4) { create(:issue, project: project) }
+
+ it 'sorts issues ascending' do
+ expect(resolve_issues(sort: :label_priority_asc).to_a).to eq([label_issue3, label_issue1, label_issue2, label_issue4])
+ end
+
+ it 'sorts issues descending' do
+ expect(resolve_issues(sort: :label_priority_desc).to_a).to eq([label_issue2, label_issue3, label_issue1, label_issue4])
+ end
+ end
+
+ context 'when sorting by milestone due date' do
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:early_milestone) { create(:milestone, project: project, due_date: 10.days.from_now) }
+ let_it_be(:late_milestone) { create(:milestone, project: project, due_date: 30.days.from_now) }
+ let_it_be(:milestone_issue1) { create(:issue, project: project) }
+ let_it_be(:milestone_issue2) { create(:issue, project: project, milestone: early_milestone) }
+ let_it_be(:milestone_issue3) { create(:issue, project: project, milestone: late_milestone) }
+
+ it 'sorts issues ascending' do
+ expect(resolve_issues(sort: :milestone_due_asc).to_a).to eq([milestone_issue2, milestone_issue3, milestone_issue1])
+ end
+
+ it 'sorts issues descending' do
+ expect(resolve_issues(sort: :milestone_due_desc).to_a).to eq([milestone_issue3, milestone_issue2, milestone_issue1])
+ end
+ end
+
+ context 'when sorting by severity' do
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:issue_high_severity) { create_issue_with_severity(project, severity: :high) }
+ let_it_be(:issue_low_severity) { create_issue_with_severity(project, severity: :low) }
+ let_it_be(:issue_no_severity) { create(:incident, project: project) }
+
+ it 'sorts issues ascending' do
+ expect(resolve_issues(sort: :severity_asc).to_a).to eq([issue_no_severity, issue_low_severity, issue_high_severity])
+ end
+
+ it 'sorts issues descending' do
+ expect(resolve_issues(sort: :severity_desc).to_a).to eq([issue_high_severity, issue_low_severity, issue_no_severity])
+ end
+ end
+
+ context 'when sorting by popularity' do
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:issue1) { create(:issue, project: project) } # has one upvote
+ let_it_be(:issue2) { create(:issue, project: project) } # has two upvote
+ let_it_be(:issue3) { create(:issue, project: project) }
+ let_it_be(:issue4) { create(:issue, project: project) } # has one upvote
+
+ before do
+ create(:award_emoji, :upvote, awardable: issue1)
+ create(:award_emoji, :upvote, awardable: issue2)
+ create(:award_emoji, :upvote, awardable: issue2)
+ create(:award_emoji, :upvote, awardable: issue4)
+ end
+
+ it 'sorts issues ascending (ties broken by id in desc order)' do
+ expect(resolve_issues(sort: :popularity_asc).to_a).to eq([issue3, issue4, issue1, issue2])
+ end
+
+ it 'sorts issues descending (ties broken by id in desc order)' do
+ expect(resolve_issues(sort: :popularity_desc).to_a).to eq([issue2, issue4, issue1, issue3])
+ end
+ end
+
+ context 'when sorting by escalation status' do
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:triggered_incident) { create(:incident, :with_escalation_status, project: project) }
+ let_it_be(:issue_no_status) { create(:issue, project: project) }
+ let_it_be(:resolved_incident) do
+ create(:incident, :with_escalation_status, project: project)
+ .tap { |issue| issue.escalation_status.resolve }
+ end
+
+ it 'sorts issues ascending' do
+ issues = resolve_issues(sort: :escalation_status_asc).to_a
+ expect(issues).to eq([triggered_incident, resolved_incident, issue_no_status])
+ end
+
+ it 'sorts issues descending' do
+ issues = resolve_issues(sort: :escalation_status_desc).to_a
+ expect(issues).to eq([resolved_incident, triggered_incident, issue_no_status])
+ end
+
+ it 'sorts issues created_at' do
+ issues = resolve_issues(sort: :created_desc).to_a
+ expect(issues).to eq([resolved_incident, issue_no_status, triggered_incident])
+ end
+ end
+
+ context 'when sorting with non-stable cursors' do
+ %i[priority_asc priority_desc
+ popularity_asc popularity_desc
+ label_priority_asc label_priority_desc
+ milestone_due_asc milestone_due_desc
+ escalation_status_asc escalation_status_desc].each do |sort_by|
+ it "uses offset-pagination when sorting by #{sort_by}" do
+ resolved = resolve_issues(sort: sort_by)
+
+ expect(resolved).to be_a(::Gitlab::Graphql::Pagination::OffsetActiveRecordRelationConnection)
+ end
+ end
+ end
+
+ context 'when sorting by title' do
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:issue1) { create(:issue, project: project, title: 'foo') }
+ let_it_be(:issue2) { create(:issue, project: project, title: 'bar') }
+ let_it_be(:issue3) { create(:issue, project: project, title: 'baz') }
+ let_it_be(:issue4) { create(:issue, project: project, title: 'Baz 2') }
+
+ it 'sorts issues ascending' do
+ expect(resolve_issues(sort: :title_asc).to_a).to eq [issue2, issue3, issue4, issue1]
+ end
+
+ it 'sorts issues descending' do
+ expect(resolve_issues(sort: :title_desc).to_a).to eq [issue1, issue4, issue3, issue2]
+ end
+ end
+ end
+
+ it 'returns issues user can see' do
+ project.add_guest(current_user)
+
+ create(:issue, confidential: true)
+
+ expect(resolve_issues).to contain_exactly(issue1, issue2)
+ end
+
+ it 'finds a specific issue with iid', :request_store do
+ result = batch_sync(max_queries: 8) { resolve_issues(iid: issue1.iid).to_a }
+
+ expect(result).to contain_exactly(issue1)
+ end
+
+ it 'batches queries that only include IIDs', :request_store do
+ result = batch_sync(max_queries: 8) do
+ [issue1, issue2]
+ .map { |issue| resolve_issues(iid: issue.iid.to_s) }
+ .flat_map(&:to_a)
+ end
+
+ expect(result).to contain_exactly(issue1, issue2)
+ end
+
+ it 'finds a specific issue with iids', :request_store do
+ result = batch_sync(max_queries: 8) do
+ resolve_issues(iids: [issue1.iid]).to_a
+ end
+
+ expect(result).to contain_exactly(issue1)
+ end
+
+ it 'finds multiple issues with iids' do
+ create(:issue, project: project, author: current_user)
+
+ expect(batch_sync { resolve_issues(iids: [issue1.iid, issue2.iid]).to_a })
+ .to contain_exactly(issue1, issue2)
+ end
+
+ it 'finds only the issues within the project we are looking at' do
+ another_project = create(:project)
+ iids = [issue1, issue2].map(&:iid)
+
+ iids.each do |iid|
+ create(:issue, project: another_project, iid: iid)
+ end
+
+ expect(batch_sync { resolve_issues(iids: iids).to_a }).to contain_exactly(issue1, issue2)
+ end
+ end
+ end
+
+ context "when passing a non existent, batch loaded project" do
+ let!(:project) do
+ BatchLoader::GraphQL.for("non-existent-path").batch do |_fake_paths, loader, _|
+ loader.call("non-existent-path", nil)
+ end
+ end
+
+ it "returns nil without breaking" do
+ expect(resolve_issues(iids: ["don't", "break"])).to be_empty
+ end
+ end
+
+ it 'increases field complexity based on arguments' do
+ field = Types::BaseField.new(name: 'test', type: GraphQL::Types::String.connection_type, resolver_class: described_class, null: false, max_page_size: 100)
+
+ expect(field.complexity.call({}, {}, 1)).to eq 4
+ expect(field.complexity.call({}, { labelName: 'foo' }, 1)).to eq 8
+ end
+
+ def create_issue_with_severity(project, severity:)
+ issue = create(:incident, project: project)
+ create(:issuable_severity, issue: issue, severity: severity)
+
+ issue
+ end
+
+ def resolve_issues(args = {}, context = { current_user: current_user })
+ resolve(described_class, obj: project, args: args, ctx: context, arg_style: :internal)
+ end
+end
diff --git a/spec/graphql/resolvers/projects_resolver_spec.rb b/spec/graphql/resolvers/projects_resolver_spec.rb
index 453fafb9590..77507474170 100644
--- a/spec/graphql/resolvers/projects_resolver_spec.rb
+++ b/spec/graphql/resolvers/projects_resolver_spec.rb
@@ -142,7 +142,7 @@ RSpec.describe Resolvers::ProjectsResolver do
context 'when no sort is provided' do
it 'returns projects in descending order by id' do
- is_expected.to match_array((visible_projecs + named_projects).sort_by { |p| p[:id] }.reverse )
+ is_expected.to match_array((visible_projecs + named_projects).sort_by { |p| p[:id] }.reverse)
end
end
end
diff --git a/spec/graphql/resolvers/recent_boards_resolver_spec.rb b/spec/graphql/resolvers/recent_boards_resolver_spec.rb
index 1afdcd42b4f..059e4a538fe 100644
--- a/spec/graphql/resolvers/recent_boards_resolver_spec.rb
+++ b/spec/graphql/resolvers/recent_boards_resolver_spec.rb
@@ -53,7 +53,7 @@ RSpec.describe Resolvers::RecentBoardsResolver do
end
context 'when project boards' do
- let_it_be(:board_parent) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) }
+ let_it_be(:board_parent) { create(:project, :public, creator_id: user.id, namespace: user.namespace) }
it_behaves_like 'group and project recent boards resolver'
end
diff --git a/spec/graphql/resolvers/users_resolver_spec.rb b/spec/graphql/resolvers/users_resolver_spec.rb
index dda15303676..2ae1b53c40f 100644
--- a/spec/graphql/resolvers/users_resolver_spec.rb
+++ b/spec/graphql/resolvers/users_resolver_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe Resolvers::UsersResolver do
context 'when both ids and usernames are passed ' do
it 'generates an error' do
expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError) do
- resolve_users( args: { ids: [user1.to_global_id.to_s], usernames: [user1.username] } )
+ resolve_users(args: { ids: [user1.to_global_id.to_s], usernames: [user1.username] })
end
end
end
@@ -31,7 +31,7 @@ RSpec.describe Resolvers::UsersResolver do
context 'when a set of IDs is passed' do
it 'returns those users' do
expect(
- resolve_users( args: { ids: [user1.to_global_id.to_s, user2.to_global_id.to_s] } )
+ resolve_users(args: { ids: [user1.to_global_id.to_s, user2.to_global_id.to_s] })
).to contain_exactly(user1, user2)
end
end
@@ -39,7 +39,7 @@ RSpec.describe Resolvers::UsersResolver do
context 'when a set of usernames is passed' do
it 'returns those users' do
expect(
- resolve_users( args: { usernames: [user1.username, user2.username] } )
+ resolve_users(args: { usernames: [user1.username, user2.username] })
).to contain_exactly(user1, user2)
end
end
@@ -49,16 +49,16 @@ RSpec.describe Resolvers::UsersResolver do
it 'returns only admins' do
expect(
- resolve_users( args: { admins: true }, ctx: { current_user: admin_user } )
+ resolve_users(args: { admins: true }, ctx: { current_user: admin_user })
).to contain_exactly(admin_user)
end
end
context 'when a search term is passed' do
it 'returns all users who match', :aggregate_failures do
- expect(resolve_users( args: { search: "some" } )).to contain_exactly(user1, user2)
- expect(resolve_users( args: { search: "123784" } )).to contain_exactly(user2)
- expect(resolve_users( args: { search: "someperson" } )).to contain_exactly(user1)
+ expect(resolve_users(args: { search: "some" })).to contain_exactly(user1, user2)
+ expect(resolve_users(args: { search: "123784" })).to contain_exactly(user2)
+ expect(resolve_users(args: { search: "someperson" })).to contain_exactly(user1)
end
end
diff --git a/spec/graphql/resolvers/work_item_resolver_spec.rb b/spec/graphql/resolvers/work_item_resolver_spec.rb
index c44ed395102..dacc6ac11d8 100644
--- a/spec/graphql/resolvers/work_item_resolver_spec.rb
+++ b/spec/graphql/resolvers/work_item_resolver_spec.rb
@@ -27,14 +27,6 @@ RSpec.describe Resolvers::WorkItemResolver do
end
end
end
-
- context 'when the work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it { is_expected.to be_nil }
- end
end
private
diff --git a/spec/graphql/resolvers/work_items/types_resolver_spec.rb b/spec/graphql/resolvers/work_items/types_resolver_spec.rb
index 868f4566ad6..5121a105523 100644
--- a/spec/graphql/resolvers/work_items/types_resolver_spec.rb
+++ b/spec/graphql/resolvers/work_items/types_resolver_spec.rb
@@ -29,16 +29,6 @@ RSpec.describe Resolvers::WorkItems::TypesResolver do
expect(result.to_a).to contain_exactly(WorkItems::Type.default_by_type(:task))
end
end
-
- context 'when work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it 'returns nil' do
- expect(result).to be_nil
- end
- end
end
describe '#resolve' do
@@ -53,15 +43,5 @@ RSpec.describe Resolvers::WorkItems::TypesResolver do
it_behaves_like 'a work item type resolver'
end
-
- context 'when parent is not a group or project' do
- let(:object) { 'not a project/group' }
-
- it 'returns nil because of feature flag check' do
- result = resolve(described_class, obj: object, args: {})
-
- expect(result).to be_nil
- end
- end
end
end
diff --git a/spec/graphql/types/ci/pipeline_schedule_status_enum_spec.rb b/spec/graphql/types/ci/pipeline_schedule_status_enum_spec.rb
index d271e72b17f..dcf37df5070 100644
--- a/spec/graphql/types/ci/pipeline_schedule_status_enum_spec.rb
+++ b/spec/graphql/types/ci/pipeline_schedule_status_enum_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Types::Ci::PipelineScheduleStatusEnum do
- specify { expect(described_class.graphql_name ).to eq('PipelineScheduleStatus') }
+ specify { expect(described_class.graphql_name).to eq('PipelineScheduleStatus') }
it 'exposes the status of a pipeline schedule' do
expect(described_class.values.keys).to match_array(%w[ACTIVE INACTIVE])
diff --git a/spec/graphql/types/ci/pipeline_type_spec.rb b/spec/graphql/types/ci/pipeline_type_spec.rb
index 9dee834d05f..5683b3f86c4 100644
--- a/spec/graphql/types/ci/pipeline_type_spec.rb
+++ b/spec/graphql/types/ci/pipeline_type_spec.rb
@@ -18,7 +18,10 @@ RSpec.describe Types::Ci::PipelineType do
]
if Gitlab.ee?
- expected_fields += %w[security_report_summary security_report_findings code_quality_reports dast_profile]
+ expected_fields += %w[
+ security_report_summary security_report_findings security_report_finding
+ code_quality_reports dast_profile
+ ]
end
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/commit_signature_interface_spec.rb b/spec/graphql/types/commit_signature_interface_spec.rb
new file mode 100644
index 00000000000..4962131d9b5
--- /dev/null
+++ b/spec/graphql/types/commit_signature_interface_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['CommitSignature'] do
+ it 'exposes the expected fields' do
+ expect(described_class).to have_graphql_fields(:verification_status, :commit_sha, :project)
+ end
+
+ describe '.resolve_type' do
+ it 'resolves gpg signatures' do
+ expect(described_class.resolve_type(build(:gpg_signature), {})).to eq(
+ Types::CommitSignatures::GpgSignatureType)
+ end
+
+ it 'resolves x509 signatures' do
+ expect(described_class.resolve_type(build(:x509_commit_signature), {})).to eq(
+ Types::CommitSignatures::X509SignatureType)
+ 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
+ end
+end
diff --git a/spec/graphql/types/commit_signatures/gpg_signature_type_spec.rb b/spec/graphql/types/commit_signatures/gpg_signature_type_spec.rb
new file mode 100644
index 00000000000..0b69ee169f2
--- /dev/null
+++ b/spec/graphql/types/commit_signatures/gpg_signature_type_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['GpgSignature'] do
+ specify { expect(described_class.graphql_name).to eq('GpgSignature') }
+
+ specify { expect(described_class).to require_graphql_authorizations(:download_code) }
+
+ specify { expect(described_class).to include(Types::CommitSignatureInterface) }
+
+ it 'contains attributes related to GPG signatures' do
+ expect(described_class).to have_graphql_fields(
+ :user, :verification_status, :commit_sha, :project,
+ :gpg_key_user_name, :gpg_key_user_email, :gpg_key_primary_keyid
+ )
+ end
+end
diff --git a/spec/graphql/types/commit_signatures/verification_status_enum_spec.rb b/spec/graphql/types/commit_signatures/verification_status_enum_spec.rb
new file mode 100644
index 00000000000..cb7ce19c9fc
--- /dev/null
+++ b/spec/graphql/types/commit_signatures/verification_status_enum_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['VerificationStatus'] do
+ specify { expect(described_class.graphql_name).to eq('VerificationStatus') }
+
+ it 'exposes all signature verification states' do
+ expect(described_class.values.keys)
+ .to match_array(%w[
+ UNVERIFIED UNVERIFIED_KEY VERIFIED
+ SAME_USER_DIFFERENT_EMAIL OTHER_USER UNKNOWN_KEY
+ MULTIPLE_SIGNATURES
+ ])
+ end
+end
diff --git a/spec/graphql/types/commit_signatures/x509_signature_type_spec.rb b/spec/graphql/types/commit_signatures/x509_signature_type_spec.rb
new file mode 100644
index 00000000000..e268bd5b3b4
--- /dev/null
+++ b/spec/graphql/types/commit_signatures/x509_signature_type_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['X509Signature'] do
+ specify { expect(described_class.graphql_name).to eq('X509Signature') }
+
+ specify { expect(described_class).to require_graphql_authorizations(:download_code) }
+
+ specify { expect(described_class).to include(Types::CommitSignatureInterface) }
+
+ it 'contains attributes related to X.509 signatures' do
+ expect(described_class).to have_graphql_fields(
+ :user, :verification_status, :commit_sha, :project,
+ :x509_certificate
+ )
+ end
+end
diff --git a/spec/graphql/types/commit_type_spec.rb b/spec/graphql/types/commit_type_spec.rb
index fe8df15028d..561d165148b 100644
--- a/spec/graphql/types/commit_type_spec.rb
+++ b/spec/graphql/types/commit_type_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['Commit'] do
specify { expect(described_class.graphql_name).to eq('Commit') }
- specify { expect(described_class).to require_graphql_authorizations(:download_code) }
+ specify { expect(described_class).to require_graphql_authorizations(:read_code) }
specify { expect(described_class).to include(Types::TodoableInterface) }
@@ -13,7 +13,7 @@ RSpec.describe GitlabSchema.types['Commit'] do
expect(described_class).to have_graphql_fields(
:id, :sha, :short_id, :title, :full_title, :full_title_html, :description, :description_html, :message, :title_html, :authored_date,
:author_name, :author_email, :author_gravatar, :author, :web_url, :web_path,
- :pipelines, :signature_html
+ :pipelines, :signature_html, :signature
)
end
end
diff --git a/spec/graphql/types/deployment_details_type_spec.rb b/spec/graphql/types/deployment_details_type_spec.rb
index 70fdc38019e..7dc0c8f97ac 100644
--- a/spec/graphql/types/deployment_details_type_spec.rb
+++ b/spec/graphql/types/deployment_details_type_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe GitlabSchema.types['DeploymentDetails'] do
id iid ref tag tags sha created_at updated_at finished_at status commit job triggerer
]
- expect(described_class).to have_graphql_fields(*expected_fields)
+ expect(described_class).to include_graphql_fields(*expected_fields)
end
specify { expect(described_class).to require_graphql_authorizations(:read_deployment) }
diff --git a/spec/graphql/types/incident_management/timeline_event_tag_type_spec.rb b/spec/graphql/types/incident_management/timeline_event_tag_type_spec.rb
new file mode 100644
index 00000000000..831a598ab66
--- /dev/null
+++ b/spec/graphql/types/incident_management/timeline_event_tag_type_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['TimelineEventTagType'] do
+ specify { expect(described_class.graphql_name).to eq('TimelineEventTagType') }
+
+ specify { expect(described_class).to require_graphql_authorizations(:read_incident_management_timeline_event_tag) }
+
+ it 'exposes the expected fields' do
+ expected_fields = %i[
+ id
+ name
+ ]
+
+ expect(described_class).to have_graphql_fields(*expected_fields)
+ end
+end
diff --git a/spec/graphql/types/incident_management/timeline_event_type_spec.rb b/spec/graphql/types/incident_management/timeline_event_type_spec.rb
index 5a6bc461f20..6805e0cdc9b 100644
--- a/spec/graphql/types/incident_management/timeline_event_type_spec.rb
+++ b/spec/graphql/types/incident_management/timeline_event_type_spec.rb
@@ -21,6 +21,7 @@ RSpec.describe GitlabSchema.types['TimelineEventType'] do
occurred_at
created_at
updated_at
+ timeline_event_tags
]
expect(described_class).to have_graphql_fields(*expected_fields)
diff --git a/spec/graphql/types/issue_type_enum_spec.rb b/spec/graphql/types/issue_type_enum_spec.rb
index 8f4b6f3bf74..cd1737c3ebb 100644
--- a/spec/graphql/types/issue_type_enum_spec.rb
+++ b/spec/graphql/types/issue_type_enum_spec.rb
@@ -5,9 +5,9 @@ require 'spec_helper'
RSpec.describe Types::IssueTypeEnum do
specify { expect(described_class.graphql_name).to eq('IssueType') }
- it 'exposes all the existing issue type values' do
+ it 'exposes all the existing issue type values except key_result' do
expect(described_class.values.keys).to match_array(
- %w[ISSUE INCIDENT TEST_CASE REQUIREMENT TASK]
+ %w[ISSUE INCIDENT TEST_CASE REQUIREMENT TASK OBJECTIVE]
)
end
end
diff --git a/spec/graphql/types/issue_type_spec.rb b/spec/graphql/types/issue_type_spec.rb
index 2a0ae79b2c4..dc444f90627 100644
--- a/spec/graphql/types/issue_type_spec.rb
+++ b/spec/graphql/types/issue_type_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe GitlabSchema.types['Issue'] do
fields = %i[id iid title description state reference author assignees updated_by participants labels milestone due_date
confidential hidden discussion_locked upvotes downvotes merge_requests_count user_notes_count user_discussions_count web_path web_url relative_position
emails_disabled subscribed time_estimate total_time_spent human_time_estimate human_total_time_spent closed_at created_at updated_at task_completion_status
- design_collection alert_management_alert severity current_user_todos moved moved_to
+ design_collection alert_management_alert alert_management_alerts severity current_user_todos moved moved_to
closed_as_duplicate_of create_note_email timelogs project_id customer_relations_contacts escalation_status]
fields.each do |field_name|
diff --git a/spec/graphql/types/permission_types/ci/runner_spec.rb b/spec/graphql/types/permission_types/ci/runner_spec.rb
index e5fbbb346e4..b4685794950 100644
--- a/spec/graphql/types/permission_types/ci/runner_spec.rb
+++ b/spec/graphql/types/permission_types/ci/runner_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Types::PermissionTypes::Ci::Runner do
it do
expected_permissions = [
- :read_runner, :update_runner, :delete_runner
+ :read_runner, :update_runner, :delete_runner, :assign_runner
]
expected_permissions.each do |permission|
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index b435f3ed5ff..30fabb8e9e2 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -36,7 +36,8 @@ RSpec.describe GitlabSchema.types['Project'] do
cluster_agent cluster_agents agent_configurations
ci_template timelogs merge_commit_template squash_commit_template work_item_types
recent_issue_boards ci_config_path_or_default packages_cleanup_policy ci_variables
- timelog_categories fork_targets branch_rules ci_config_variables pipeline_schedules
+ timelog_categories fork_targets branch_rules ci_config_variables pipeline_schedules languages
+ incident_management_timeline_event_tags
]
expect(described_class).to include_graphql_fields(*expected_fields)
@@ -212,8 +213,8 @@ RSpec.describe GitlabSchema.types['Project'] do
it "returns the project's sast configuration for analyzer variables" do
analyzer = subject.dig('data', 'project', 'sastCiConfiguration', 'analyzers', 'nodes').first
- expect(analyzer['name']).to eq('bandit')
- expect(analyzer['label']).to eq('Bandit')
+ expect(analyzer['name']).to eq('brakeman')
+ expect(analyzer['label']).to eq('Brakeman')
expect(analyzer['enabled']).to eq(true)
end
@@ -290,14 +291,14 @@ RSpec.describe GitlabSchema.types['Project'] do
subject { described_class.fields['issue'] }
it { is_expected.to have_graphql_type(Types::IssueType) }
- it { is_expected.to have_graphql_resolver(Resolvers::IssuesResolver.single) }
+ it { is_expected.to have_graphql_resolver(Resolvers::ProjectIssuesResolver.single) }
end
describe 'issues field' do
subject { described_class.fields['issues'] }
it { is_expected.to have_graphql_type(Types::IssueType.connection_type) }
- it { is_expected.to have_graphql_resolver(Resolvers::IssuesResolver) }
+ it { is_expected.to have_graphql_resolver(Resolvers::ProjectIssuesResolver) }
end
describe 'merge_request field' do
@@ -508,6 +509,12 @@ RSpec.describe GitlabSchema.types['Project'] do
it { is_expected.to have_graphql_resolver(Resolvers::Ci::JobTokenScopeResolver) }
end
+ describe 'incident_management_timeline_event_tags field' do
+ subject { described_class.fields['incidentManagementTimelineEventTags'] }
+
+ it { is_expected.to have_graphql_type(Types::IncidentManagement::TimelineEventTagType) }
+ end
+
describe 'agent_configurations' do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
@@ -731,4 +738,114 @@ RSpec.describe GitlabSchema.types['Project'] do
end
end
end
+
+ describe 'timeline_event_tags' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) do
+ create(:project,
+ :private,
+ :repository,
+ creator_id: user.id,
+ namespace: user.namespace)
+ end
+
+ let_it_be(:tag1) do
+ create(:incident_management_timeline_event_tag,
+ project: project,
+ name: 'Tag 1')
+ end
+
+ let_it_be(:tag2) do
+ create(:incident_management_timeline_event_tag,
+ project: project,
+ name: 'Tag 2')
+ end
+
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ incidentManagementTimelineEventTags {
+ name
+ id
+ }
+ }
+ }
+ )
+ end
+
+ let(:tags) do
+ subject.dig('data', 'project', 'incidentManagementTimelineEventTags')
+ end
+
+ subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
+
+ context 'when user has permissions to read project' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'contains timeline event tags' do
+ expect(tags.count).to eq(2)
+ expect(tags.first['name']).to eq(tag1.name)
+ expect(tags.last['name']).to eq(tag2.name)
+ end
+ end
+ end
+
+ describe 'languages' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) do
+ create(:project,
+ :private,
+ :repository,
+ creator_id: user.id,
+ namespace: user.namespace)
+ end
+
+ let(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ languages {
+ name
+ share
+ color
+ }
+ }
+ }
+ )
+ end
+
+ let(:mock_languages) { [] }
+
+ before do
+ allow_next_instance_of(::Projects::RepositoryLanguagesService) do |service|
+ allow(service).to receive(:execute).and_return(mock_languages)
+ end
+ end
+
+ subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
+
+ let(:languages) { subject.dig('data', 'project', 'languages') }
+
+ context "when the languages haven't been detected yet" do
+ it 'returns an empty array' do
+ expect(languages).to eq([])
+ end
+ end
+
+ context 'when the languages were detected before' do
+ let(:mock_languages) do
+ [{ share: 66.69, name: "Ruby", color: "#701516" },
+ { share: 22.98, name: "JavaScript", color: "#f1e05a" },
+ { share: 7.91, name: "HTML", color: "#e34c26" },
+ { share: 2.42, name: "CoffeeScript", color: "#244776" }]
+ end
+
+ it 'returns the repository languages' do
+ expect(languages).to eq(mock_languages.map(&:stringify_keys))
+ end
+ end
+ end
end
diff --git a/spec/graphql/types/projects/branch_rule_type_spec.rb b/spec/graphql/types/projects/branch_rule_type_spec.rb
index 119ecf8a097..54ea4f6857b 100644
--- a/spec/graphql/types/projects/branch_rule_type_spec.rb
+++ b/spec/graphql/types/projects/branch_rule_type_spec.rb
@@ -12,12 +12,13 @@ RSpec.describe GitlabSchema.types['BranchRule'] do
name
isDefault
branch_protection
+ matching_branches_count
created_at
updated_at
]
end
- specify { is_expected.to require_graphql_authorizations(:read_protected_branch) }
+ it { is_expected.to require_graphql_authorizations(:read_protected_branch) }
- specify { is_expected.to have_graphql_fields(fields).at_least }
+ it { is_expected.to have_graphql_fields(fields).at_least }
end
diff --git a/spec/graphql/types/projects/repository_language_type_spec.rb b/spec/graphql/types/projects/repository_language_type_spec.rb
new file mode 100644
index 00000000000..fd3e0ee4e90
--- /dev/null
+++ b/spec/graphql/types/projects/repository_language_type_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Types::Projects::RepositoryLanguageType do
+ specify { expect(described_class.graphql_name).to eq('RepositoryLanguage') }
+
+ specify do
+ expect(described_class).to have_graphql_fields(
+ :name,
+ :share,
+ :color
+ )
+ end
+end
diff --git a/spec/graphql/types/release_links_type_spec.rb b/spec/graphql/types/release_links_type_spec.rb
index e77c4e3ddd1..5a29050a4a2 100644
--- a/spec/graphql/types/release_links_type_spec.rb
+++ b/spec/graphql/types/release_links_type_spec.rb
@@ -26,31 +26,31 @@ RSpec.describe GitlabSchema.types['ReleaseLinks'] do
describe 'openedMergeRequestsUrl' do
it 'has valid authorization' do
- expect(fetch_authorizations('openedMergeRequestsUrl')).to include(:download_code)
+ expect(fetch_authorizations('openedMergeRequestsUrl')).to include(:read_code)
end
end
describe 'mergedMergeRequestsUrl' do
it 'has valid authorization' do
- expect(fetch_authorizations('mergedMergeRequestsUrl')).to include(:download_code)
+ expect(fetch_authorizations('mergedMergeRequestsUrl')).to include(:read_code)
end
end
describe 'closedMergeRequestsUrl' do
it 'has valid authorization' do
- expect(fetch_authorizations('closedMergeRequestsUrl')).to include(:download_code)
+ expect(fetch_authorizations('closedMergeRequestsUrl')).to include(:read_code)
end
end
describe 'openedIssuesUrl' do
it 'has valid authorization' do
- expect(fetch_authorizations('openedIssuesUrl')).to include(:download_code)
+ expect(fetch_authorizations('openedIssuesUrl')).to include(:read_code)
end
end
describe 'closedIssuesUrl' do
it 'has valid authorization' do
- expect(fetch_authorizations('closedIssuesUrl')).to include(:download_code)
+ expect(fetch_authorizations('closedIssuesUrl')).to include(:read_code)
end
end
diff --git a/spec/graphql/types/release_source_type_spec.rb b/spec/graphql/types/release_source_type_spec.rb
index 69a1ca30dbc..52f1e3a4ff5 100644
--- a/spec/graphql/types/release_source_type_spec.rb
+++ b/spec/graphql/types/release_source_type_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe GitlabSchema.types['ReleaseSource'] do
- it { expect(described_class).to require_graphql_authorizations(:download_code) }
+ it { expect(described_class).to require_graphql_authorizations(:read_code) }
it 'has the expected fields' do
expected_fields = %w[
diff --git a/spec/graphql/types/repository_type_spec.rb b/spec/graphql/types/repository_type_spec.rb
index 5488d78b720..4ff2cbcad46 100644
--- a/spec/graphql/types/repository_type_spec.rb
+++ b/spec/graphql/types/repository_type_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['Repository'] do
specify { expect(described_class.graphql_name).to eq('Repository') }
- specify { expect(described_class).to require_graphql_authorizations(:download_code) }
+ specify { expect(described_class).to require_graphql_authorizations(:read_code) }
specify { expect(described_class).to have_graphql_field(:root_ref) }
diff --git a/spec/graphql/types/subscription_type_spec.rb b/spec/graphql/types/subscription_type_spec.rb
index c23a14deaf3..04f0c72b06f 100644
--- a/spec/graphql/types/subscription_type_spec.rb
+++ b/spec/graphql/types/subscription_type_spec.rb
@@ -11,6 +11,7 @@ RSpec.describe GitlabSchema.types['Subscription'] do
issuable_description_updated
issuable_labels_updated
issuable_dates_updated
+ issuable_milestone_updated
merge_request_reviewers_updated
merge_request_merge_status_updated
]
diff --git a/spec/graphql/types/x509_certificate_type_spec.rb b/spec/graphql/types/x509_certificate_type_spec.rb
new file mode 100644
index 00000000000..e59d1f83b28
--- /dev/null
+++ b/spec/graphql/types/x509_certificate_type_spec.rb
@@ -0,0 +1,14 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['X509Certificate'] do
+ specify { expect(described_class.graphql_name).to eq('X509Certificate') }
+
+ it 'contains attributes for X.509 certifcates' do
+ expect(described_class).to have_graphql_fields(
+ :certificate_status, :created_at, :email, :id, :serial_number, :subject,
+ :subject_key_identifier, :updated_at, :x509_issuer
+ )
+ end
+end
diff --git a/spec/graphql/types/x509_issuer_type_spec.rb b/spec/graphql/types/x509_issuer_type_spec.rb
new file mode 100644
index 00000000000..5446dcf07c7
--- /dev/null
+++ b/spec/graphql/types/x509_issuer_type_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe GitlabSchema.types['X509Issuer'] do
+ specify { expect(described_class.graphql_name).to eq('X509Issuer') }
+
+ it 'contains attributes for X.509 issuers' do
+ expect(described_class).to have_graphql_fields(
+ :created_at, :crl_url, :id, :subject, :subject_key_identifier, :updated_at
+ )
+ end
+end
diff --git a/spec/helpers/appearances_helper_spec.rb b/spec/helpers/appearances_helper_spec.rb
index 2206c1ce2ae..b3afd350397 100644
--- a/spec/helpers/appearances_helper_spec.rb
+++ b/spec/helpers/appearances_helper_spec.rb
@@ -169,4 +169,13 @@ RSpec.describe AppearancesHelper do
expect(helper.brand_title).to eq(helper.default_brand_title)
end
end
+
+ describe '#default_brand_title' do
+ it 'returns the default title' do
+ edition = Gitlab.ee? ? 'Enterprise' : 'Community'
+ expected_default_brand_title = "GitLab #{edition} Edition"
+
+ expect(helper.default_brand_title).to eq _(expected_default_brand_title)
+ end
+ end
end
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index a4b2c963c74..7f838167bd2 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -253,17 +253,44 @@ RSpec.describe ApplicationHelper do
end
describe '#client_class_list' do
- it 'returns string containing CSS classes representing client browser and platform' do
- class_list = helper.client_class_list
- expect(class_list).to eq('gl-browser-generic gl-platform-other')
+ context 'when browser or platform are unknown' do
+ it 'returns string containing CSS classes representing fallbacks' do
+ class_list = helper.client_class_list
+ expect(class_list).to eq('gl-browser-generic gl-platform-other')
+ end
+ end
+
+ context 'when browser and platform are known' do
+ before do
+ allow(helper.controller).to receive(:browser).and_return(::Browser.new('Google Chrome/Linux'))
+ end
+
+ it 'returns string containing CSS classes representing them' do
+ class_list = helper.client_class_list
+ expect(class_list).to eq('gl-browser-chrome gl-platform-linux')
+ end
end
end
describe '#client_js_flags' do
- it 'returns map containing JS flags representing client browser and platform' do
- flags_list = helper.client_js_flags
- expect(flags_list[:isGeneric]).to eq(true)
- expect(flags_list[:isOther]).to eq(true)
+ context 'when browser or platform are unknown' do
+ it 'returns map containing JS flags representing falllbacks' do
+ flags_list = helper.client_js_flags
+ expect(flags_list[:isGeneric]).to eq(true)
+ expect(flags_list[:isOther]).to eq(true)
+ end
+ end
+
+ context 'when browser and platform are known' do
+ before do
+ allow(helper.controller).to receive(:browser).and_return(::Browser.new('Google Chrome/Linux'))
+ end
+
+ it 'returns map containing JS flags representing client browser and platform' do
+ flags_list = helper.client_js_flags
+ expect(flags_list[:isChrome]).to eq(true)
+ expect(flags_list[:isLinux]).to eq(true)
+ end
end
end
@@ -506,42 +533,24 @@ RSpec.describe ApplicationHelper do
end
describe '#page_class' do
- context 'when logged_out_marketing_header experiment is enabled' do
- let_it_be(:expected_class) { 'logged-out-marketing-header-candidate' }
+ let_it_be(:expected_class) { 'logged-out-marketing-header' }
- let(:current_user) { nil }
- let(:variant) { :candidate }
+ let(:current_user) { nil }
- subject do
- helper.page_class.flatten
- end
-
- before do
- stub_experiments(logged_out_marketing_header: variant)
- allow(helper).to receive(:current_user) { current_user }
- end
-
- context 'when candidate' do
- it { is_expected.to include(expected_class) }
- end
-
- context 'when candidate (:trial_focused variant)' do
- let(:variant) { :trial_focused }
-
- it { is_expected.to include(expected_class) }
- end
+ subject do
+ helper.page_class.flatten
+ end
- context 'when control' do
- let(:variant) { :control }
+ before do
+ allow(helper).to receive(:current_user) { current_user }
+ end
- it { is_expected.not_to include(expected_class) }
- end
+ it { is_expected.to include(expected_class) }
- context 'when a user is logged in' do
- let(:current_user) { create(:user) }
+ context 'when a user is logged in' do
+ let(:current_user) { create(:user) }
- it { is_expected.not_to include(expected_class) }
- end
+ it { is_expected.not_to include(expected_class) }
end
end
diff --git a/spec/helpers/application_settings_helper_spec.rb b/spec/helpers/application_settings_helper_spec.rb
index c75e9caa77a..eafdbfa8d0a 100644
--- a/spec/helpers/application_settings_helper_spec.rb
+++ b/spec/helpers/application_settings_helper_spec.rb
@@ -95,7 +95,7 @@ RSpec.describe ApplicationSettingsHelper do
end
describe '.self_monitoring_project_data' do
- context 'when self monitoring project does not exist' do
+ context 'when self-monitoring project does not exist' do
it 'returns create_self_monitoring_project_path' do
expect(helper.self_monitoring_project_data).to include(
'create_self_monitoring_project_path' =>
@@ -137,7 +137,7 @@ RSpec.describe ApplicationSettingsHelper do
end
end
- context 'when self monitoring project exists' do
+ context 'when self-monitoring project exists' do
let(:project) { build(:project) }
before do
diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb
index 93efce6b58b..78c0d0a2b11 100644
--- a/spec/helpers/diff_helper_spec.rb
+++ b/spec/helpers/diff_helper_spec.rb
@@ -445,6 +445,19 @@ RSpec.describe DiffHelper do
end
end
+ describe '#params_with_whitespace' do
+ before do
+ controller.params[:protocol] = 'HACKED!'
+ controller.params[:host] = 'HACKED!'
+ end
+
+ subject { helper.params_with_whitespace }
+
+ it "filters with safe_params" do
+ expect(subject).to eq({ 'w' => 1 })
+ end
+ end
+
describe "#render_fork_suggestion" do
subject { helper.render_fork_suggestion }
@@ -471,7 +484,6 @@ RSpec.describe DiffHelper do
describe '#conflicts' do
let(:merge_request) { instance_double(MergeRequest, cannot_be_merged?: true) }
- let(:merge_ref_head_diff) { true }
let(:can_be_resolved_in_ui?) { true }
let(:allow_tree_conflicts) { false }
let(:files) { [instance_double(Gitlab::Conflict::File, path: 'a')] }
@@ -479,7 +491,6 @@ RSpec.describe DiffHelper do
before do
allow(helper).to receive(:merge_request).and_return(merge_request)
- allow(helper).to receive(:options).and_return(merge_ref_head_diff: merge_ref_head_diff)
allow_next_instance_of(MergeRequests::Conflicts::ListService, merge_request, allow_tree_conflicts: allow_tree_conflicts) do |svc|
allow(svc).to receive(:can_be_resolved_in_ui?).and_return(can_be_resolved_in_ui?)
@@ -496,14 +507,6 @@ RSpec.describe DiffHelper do
expect(helper.conflicts).to eq('a' => files.first)
end
- context 'when merge_ref_head_diff option is false' do
- let(:merge_ref_head_diff) { false }
-
- it 'returns nil' do
- expect(helper.conflicts).to be_nil
- end
- end
-
context 'when merge request can be merged' do
let(:merge_request) { instance_double(MergeRequest, cannot_be_merged?: false) }
@@ -536,4 +539,42 @@ RSpec.describe DiffHelper do
end
end
end
+
+ describe '#show_only_context_commits?' do
+ let(:params) { {} }
+ let(:merge_request) { build_stubbed(:merge_request) }
+ let(:has_no_commits) { true }
+
+ subject(:result) { helper.show_only_context_commits? }
+
+ before do
+ assign(:merge_request, merge_request)
+ allow(helper).to receive(:params).and_return(params)
+ allow(merge_request).to receive(:has_no_commits?).and_return(has_no_commits)
+ end
+
+ context 'when only_context_commits param is set to true' do
+ let(:params) { { only_context_commits: true } }
+
+ it { is_expected.to be_truthy }
+
+ context 'when merge request has commits' do
+ let(:has_no_commits) { false }
+
+ it { is_expected.to be_truthy }
+ end
+ end
+
+ context 'when only_context_commits param is set to false' do
+ let(:params) { { only_context_commits: false } }
+
+ it { is_expected.to be_truthy }
+
+ context 'when merge request has commits' do
+ let(:has_no_commits) { false }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+ end
end
diff --git a/spec/helpers/environments_helper_spec.rb b/spec/helpers/environments_helper_spec.rb
index c1eaf1b1bcd..cf33f8a4939 100644
--- a/spec/helpers/environments_helper_spec.rb
+++ b/spec/helpers/environments_helper_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe EnvironmentsHelper do
'default_branch' => 'master',
'project_path' => project_path(project),
'tags_path' => project_tags_path(project),
- 'has_metrics' => "#{environment.has_metrics?}",
+ 'has_metrics' => environment.has_metrics?.to_s,
'external_dashboard_url' => nil,
'environment_state' => environment.state,
'custom_metrics_path' => project_prometheus_metrics_path(project),
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
index 7005b3dc53e..39901047b0f 100644
--- a/spec/helpers/events_helper_spec.rb
+++ b/spec/helpers/events_helper_spec.rb
@@ -4,6 +4,30 @@ require 'spec_helper'
RSpec.describe EventsHelper do
include Gitlab::Routing
+ include Banzai::Filter::OutputSafety
+
+ describe '#link_to_author' do
+ let(:user) { create(:user) }
+ let(:event) { create(:event, author: user) }
+
+ it 'returns a link to the author' do
+ name = user.name
+ expect(helper.link_to_author(event)).to eq(link_to(name, user_path(user.username), title: name))
+ end
+
+ it 'returns the author name if the author is not present' do
+ event.author = nil
+
+ expect(helper.link_to_author(event)).to eq(escape_once(event.author_name))
+ end
+
+ it 'returns "You" if the author is the current user' do
+ allow(helper).to receive(:current_user).and_return(user)
+
+ name = _('You')
+ expect(helper.link_to_author(event, self_added: true)).to eq(link_to(name, user_path(user.username), title: name))
+ end
+ end
describe '#event_target_path' do
subject { helper.event_target_path(event.present) }
diff --git a/spec/helpers/form_helper_spec.rb b/spec/helpers/form_helper_spec.rb
index 14ff5d97057..1797b0e32cd 100644
--- a/spec/helpers/form_helper_spec.rb
+++ b/spec/helpers/form_helper_spec.rb
@@ -44,43 +44,19 @@ RSpec.describe FormHelper do
describe '#assignees_dropdown_options' do
let(:merge_request) { build(:merge_request) }
- context "with the :limit_assignees_per_issuable feature flag on" do
- context "with multiple assignees" do
- it 'correctly returns the max amount of assignees to allow' do
- allow(helper).to receive(:merge_request_supports_multiple_assignees?).and_return(true)
+ context "with multiple assignees" do
+ it 'correctly returns the max amount of assignees to allow' do
+ allow(helper).to receive(:merge_request_supports_multiple_assignees?).and_return(true)
- expect(helper.assignees_dropdown_options(:merge_request)[:data][:'max-select'])
- .to eq(Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS)
- end
- end
-
- context "with only 1 assignee" do
- it 'correctly returns the max amount of assignees to allow' do
- expect(helper.assignees_dropdown_options(:merge_request)[:data][:'max-select'])
- .to eq(1)
- end
+ expect(helper.assignees_dropdown_options(:merge_request)[:data][:'max-select'])
+ .to eq(Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS)
end
end
- context "with the :limit_assignees_per_issuable feature flag off" do
- before do
- stub_feature_flags(limit_assignees_per_issuable: false)
- end
-
- context "with multiple assignees" do
- it 'correctly returns the max amount of assignees to allow' do
- allow(helper).to receive(:merge_request_supports_multiple_assignees?).and_return(true)
-
- expect(helper.assignees_dropdown_options(:merge_request)[:data][:'max-select'])
- .to eq(nil)
- end
- end
-
- context "with only 1 assignee" do
- it 'correctly returns the max amount of assignees to allow' do
- expect(helper.assignees_dropdown_options(:merge_request)[:data][:'max-select'])
- .to eq(1)
- end
+ context "with only 1 assignee" do
+ it 'correctly returns the max amount of assignees to allow' do
+ expect(helper.assignees_dropdown_options(:merge_request)[:data][:'max-select'])
+ .to eq(1)
end
end
end
diff --git a/spec/helpers/groups/group_members_helper_spec.rb b/spec/helpers/groups/group_members_helper_spec.rb
index 0d53225bbcf..4d1280533dd 100644
--- a/spec/helpers/groups/group_members_helper_spec.rb
+++ b/spec/helpers/groups/group_members_helper_spec.rb
@@ -7,16 +7,6 @@ RSpec.describe Groups::GroupMembersHelper do
let_it_be(:group) { create(:group) }
- describe '.group_member_select_options' do
- before do
- helper.instance_variable_set(:@group, group)
- end
-
- it 'returns an options hash' do
- expect(helper.group_member_select_options).to include(multiple: true, scope: :all, email_user: true)
- end
- end
-
describe '#group_members_app_data' do
include_context 'group_group_link'
@@ -36,6 +26,7 @@ RSpec.describe Groups::GroupMembersHelper do
allow(helper).to receive(:group_group_member_path).with(shared_group, ':id').and_return('/groups/foo-bar/-/group_members/:id')
allow(helper).to receive(:group_group_link_path).with(shared_group, ':id').and_return('/groups/foo-bar/-/group_links/:id')
allow(helper).to receive(:can?).with(current_user, :admin_group_member, shared_group).and_return(true)
+ allow(helper).to receive(:can?).with(current_user, :admin_member_access_request, shared_group).and_return(true)
end
subject do
@@ -63,7 +54,8 @@ RSpec.describe Groups::GroupMembersHelper do
it 'returns expected json' do
expected = {
source_id: shared_group.id,
- can_manage_members: true
+ can_manage_members: true,
+ can_manage_access_requests: true
}
expect(subject).to include(expected)
@@ -109,6 +101,7 @@ RSpec.describe Groups::GroupMembersHelper do
allow(helper).to receive(:group_group_member_path).with(sub_shared_group, ':id').and_return('/groups/foo-bar/-/group_members/:id')
allow(helper).to receive(:group_group_link_path).with(sub_shared_group, ':id').and_return('/groups/foo-bar/-/group_links/:id')
allow(helper).to receive(:can?).with(current_user, :admin_group_member, sub_shared_group).and_return(true)
+ allow(helper).to receive(:can?).with(current_user, :admin_member_access_request, sub_shared_group).and_return(true)
allow(helper).to receive(:can?).with(current_user, :export_group_memberships, sub_shared_group).and_return(true)
end
diff --git a/spec/helpers/groups/observability_helper_spec.rb b/spec/helpers/groups/observability_helper_spec.rb
new file mode 100644
index 00000000000..4393f4e9bec
--- /dev/null
+++ b/spec/helpers/groups/observability_helper_spec.rb
@@ -0,0 +1,92 @@
+# frozen_string_literal: true
+
+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
+ 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
+ end
+
+ context 'when observability ui is standalone' do
+ before do
+ stub_env('STANDALONE_OBSERVABILITY_UI', 'true')
+ 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 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 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
+ end
+ end
+
+ describe '#observability_page_title' do
+ it 'returns the title for action: dashboards' do
+ allow(helper).to receive(:params).and_return({ action: 'dashboards' })
+ expect(helper.observability_page_title).to eq("Dashboards")
+ end
+
+ it 'returns the title for action: manage' do
+ allow(helper).to receive(:params).and_return({ action: 'manage' })
+ expect(helper.observability_page_title).to eq("Manage Dashboards")
+ end
+
+ it 'returns the title for action: explore' do
+ allow(helper).to receive(:params).and_return({ action: 'explore' })
+ expect(helper.observability_page_title).to eq("Explore")
+ end
+
+ it 'returns the default title for unknown action' do
+ allow(helper).to receive(:params).and_return({ action: 'unknown' })
+ expect(helper.observability_page_title).to eq("Dashboards")
+ end
+ end
+end
diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index a38483a956d..8b4ac6a7cfd 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -287,39 +287,6 @@ RSpec.describe GroupsHelper do
end
end
- describe '#parent_group_options' do
- let_it_be(:current_user) { create(:user) }
- let_it_be(:group) { create(:group, name: 'group') }
- let_it_be(:group2) { create(:group, name: 'group2') }
-
- before do
- group.add_owner(current_user)
- group2.add_owner(current_user)
- end
-
- it 'includes explicitly owned groups except self' do
- expect(parent_group_options(group2)).to eq([{ id: group.id, text: group.human_name }].to_json)
- end
-
- it 'excludes parent group' do
- subgroup = create(:group, parent: group2)
-
- expect(parent_group_options(subgroup)).to eq([{ id: group.id, text: group.human_name }].to_json)
- end
-
- it 'includes subgroups with inherited ownership' do
- subgroup = create(:group, parent: group)
-
- expect(parent_group_options(group2)).to eq([{ id: group.id, text: group.human_name }, { id: subgroup.id, text: subgroup.human_name }].to_json)
- end
-
- it 'excludes own subgroups' do
- create(:group, parent: group2)
-
- expect(parent_group_options(group2)).to eq([{ id: group.id, text: group.human_name }].to_json)
- end
- end
-
describe '#can_disable_group_emails?' do
let_it_be(:current_user) { create(:user) }
let_it_be(:group) { create(:group, name: 'group') }
@@ -502,32 +469,6 @@ RSpec.describe GroupsHelper do
end
end
- describe '#subgroups_and_projects_list_app_data' do
- let_it_be(:group) { create(:group) }
- let_it_be(:user) { create(:user) }
-
- before do
- allow(helper).to receive(:current_user).and_return(user)
-
- allow(helper).to receive(:can?).with(user, :create_subgroup, group) { true }
- allow(helper).to receive(:can?).with(user, :create_projects, group) { true }
- end
-
- it 'returns expected hash' do
- expect(helper.subgroups_and_projects_list_app_data(group)).to match({
- show_schema_markup: 'true',
- new_subgroup_path: including("groups/new?parent_id=#{group.id}#create-group-pane"),
- new_project_path: including("/projects/new?namespace_id=#{group.id}"),
- new_subgroup_illustration: including('illustrations/subgroup-create-new-sm'),
- new_project_illustration: including('illustrations/project-create-new-sm'),
- empty_subgroup_illustration: including('illustrations/empty-state/empty-subgroup-md'),
- render_empty_state: 'true',
- can_create_subgroups: 'true',
- can_create_projects: 'true'
- })
- end
- end
-
describe '#group_overview_tabs_app_data' do
let_it_be(:group) { create(:group) }
let_it_be(:user) { create(:user) }
@@ -548,8 +489,17 @@ RSpec.describe GroupsHelper do
shared_projects_endpoint: including("/groups/#{group.path}/-/shared_projects.json"),
archived_projects_endpoint: including("/groups/#{group.path}/-/children.json?archived=only"),
current_group_visibility: group.visibility,
- initial_sort: initial_sort
- }.merge(helper.group_overview_tabs_app_data(group))
+ initial_sort: initial_sort,
+ show_schema_markup: 'true',
+ new_subgroup_path: including("groups/new?parent_id=#{group.id}#create-group-pane"),
+ new_project_path: including("/projects/new?namespace_id=#{group.id}"),
+ new_subgroup_illustration: including('illustrations/subgroup-create-new-sm'),
+ new_project_illustration: including('illustrations/project-create-new-sm'),
+ empty_subgroup_illustration: including('illustrations/empty-state/empty-subgroup-md'),
+ render_empty_state: 'true',
+ can_create_subgroups: 'true',
+ can_create_projects: 'true'
+ }
)
end
end
diff --git a/spec/helpers/hooks_helper_spec.rb b/spec/helpers/hooks_helper_spec.rb
index 8f438a3ddc8..98a1f77b414 100644
--- a/spec/helpers/hooks_helper_spec.rb
+++ b/spec/helpers/hooks_helper_spec.rb
@@ -3,16 +3,33 @@
require 'spec_helper'
RSpec.describe HooksHelper do
- let(:project) { create(:project) }
- let(:project_hook) { create(:project_hook, project: project) }
- let(:service_hook) { create(:service_hook, integration: create(:drone_ci_integration)) }
- let(:system_hook) { create(:system_hook) }
+ let(:project) { build_stubbed(:project) }
+ let(:project_hook) { build_stubbed(:project_hook, project: project) }
+ let(:service_hook) { build_stubbed(:service_hook, integration: build_stubbed(:drone_ci_integration)) }
+ let(:system_hook) { build_stubbed(:system_hook) }
describe '#webhook_form_data' do
subject { helper.webhook_form_data(project_hook) }
- it { expect(subject[:url]).to eq(project_hook.url) }
- it { expect(subject[:url_variables]).to be_nil }
+ context 'when there are no URL variables' do
+ it 'returns proper data' do
+ expect(subject).to match(
+ url: project_hook.url,
+ url_variables: "[]"
+ )
+ end
+ end
+
+ context 'when there are URL variables' do
+ let(:project_hook) { build_stubbed(:project_hook, :url_variables, project: project) }
+
+ it 'returns proper data' do
+ expect(subject).to match(
+ url: project_hook.url,
+ url_variables: Gitlab::Json.dump([{ key: 'abc' }])
+ )
+ end
+ end
end
describe '#link_to_test_hook' do
@@ -31,7 +48,7 @@ RSpec.describe HooksHelper do
describe '#hook_log_path' do
context 'with a project hook' do
- let(:web_hook_log) { create(:web_hook_log, web_hook: project_hook) }
+ let(:web_hook_log) { build_stubbed(:web_hook_log, web_hook: project_hook) }
it 'returns project-namespaced link' do
expect(helper.hook_log_path(project_hook, web_hook_log))
@@ -40,7 +57,7 @@ RSpec.describe HooksHelper do
end
context 'with a service hook' do
- let(:web_hook_log) { create(:web_hook_log, web_hook: service_hook) }
+ let(:web_hook_log) { build_stubbed(:web_hook_log, web_hook: service_hook) }
it 'returns project-namespaced link' do
expect(helper.hook_log_path(project_hook, web_hook_log))
@@ -49,7 +66,7 @@ RSpec.describe HooksHelper do
end
context 'with a system hook' do
- let(:web_hook_log) { create(:web_hook_log, web_hook: system_hook) }
+ let(:web_hook_log) { build_stubbed(:web_hook_log, web_hook: system_hook) }
it 'returns admin-namespaced link' do
expect(helper.hook_log_path(system_hook, web_hook_log))
diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb
index 139e8be33d5..2f1682e9194 100644
--- a/spec/helpers/icons_helper_spec.rb
+++ b/spec/helpers/icons_helper_spec.rb
@@ -234,7 +234,7 @@ RSpec.describe IconsHelper do
describe 'gl_loading_icon' do
it 'returns the default spinner markup' do
expect(gl_loading_icon.to_s)
- .to eq '<div class="gl-spinner-container" role="status"><span class="gl-spinner gl-spinner-dark gl-spinner-sm gl-vertical-align-text-bottom!" aria-label="Loading"></span></div>'
+ .to eq '<div class="gl-spinner-container" role="status"><span aria-label="Loading" class="gl-spinner gl-spinner-sm gl-spinner-dark gl-vertical-align-text-bottom!"></span></div>'
end
context 'when css_class is provided' do
diff --git a/spec/helpers/ide_helper_spec.rb b/spec/helpers/ide_helper_spec.rb
index e750379f62d..447967fd345 100644
--- a/spec/helpers/ide_helper_spec.rb
+++ b/spec/helpers/ide_helper_spec.rb
@@ -26,6 +26,8 @@ RSpec.describe IdeHelper 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'),
'branch-name' => 'master',
'project-path' => project.path_with_namespace,
'csp-nonce' => 'test-csp-nonce'
diff --git a/spec/helpers/integrations_helper_spec.rb b/spec/helpers/integrations_helper_spec.rb
index 95dfc51e8fd..9822f9fac05 100644
--- a/spec/helpers/integrations_helper_spec.rb
+++ b/spec/helpers/integrations_helper_spec.rb
@@ -150,4 +150,54 @@ RSpec.describe IntegrationsHelper do
end
end
end
+
+ describe '#integration_issue_type' do
+ using RSpec::Parameterized::TableSyntax
+ let_it_be(:issue) { create(:issue) }
+
+ where(:issue_type, :expected_i18n_issue_type) do
+ "issue" | _('Issue')
+ "incident" | _('Incident')
+ "test_case" | _('Test case')
+ "requirement" | _('Requirement')
+ "task" | _('Task')
+ end
+
+ with_them do
+ before do
+ issue.update!(issue_type: issue_type)
+ end
+
+ it "return the correct i18n issue type" do
+ expect(described_class.integration_issue_type(issue.issue_type)).to eq(expected_i18n_issue_type)
+ end
+ end
+
+ it "only consider these enumeration values are valid" do
+ expected_valid_types = %w[issue incident test_case requirement task objective key_result]
+ expect(Issue.issue_types.keys).to contain_exactly(*expected_valid_types)
+ end
+ end
+
+ describe '#integration_todo_target_type' do
+ using RSpec::Parameterized::TableSyntax
+ let!(:todo) { create(:todo, commit_id: '123') }
+
+ where(:target_type, :expected_i18n_target_type) do
+ "Commit" | _("Commit")
+ "Issue" | _("Issue")
+ "MergeRequest" | _("Merge Request")
+ 'Epic' | _('Epic')
+ DesignManagement::Design.name | _('design')
+ AlertManagement::Alert.name | _('alert')
+ end
+
+ with_them do
+ before do
+ todo.update!(target_type: target_type)
+ end
+
+ it { expect(described_class.integration_todo_target_type(todo.target_type)).to eq(expected_i18n_target_type) }
+ end
+ end
end
diff --git a/spec/helpers/json_helper_spec.rb b/spec/helpers/json_helper_spec.rb
new file mode 100644
index 00000000000..b9dfabb1b23
--- /dev/null
+++ b/spec/helpers/json_helper_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe JsonHelper do
+ let(:hash) { { "foo" => "bar" } }
+ let(:json) { '{"foo":"bar"}' }
+
+ describe ".json_generate" do
+ subject { helper.json_generate(hash) }
+
+ it "generates JSON" do
+ expect(subject).to eq(json)
+ end
+
+ it "calls the Gitlab::Json class" do
+ expect(Gitlab::Json).to receive(:generate).with(hash)
+
+ subject
+ end
+ end
+
+ describe ".json_parse" do
+ subject { helper.json_parse(json) }
+
+ it "parses JSON" do
+ expect(subject).to eq(hash)
+ end
+
+ it "calls the Gitlab::Json class" do
+ expect(Gitlab::Json).to receive(:parse).with(json)
+
+ subject
+ end
+ end
+end
diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb
index a2e34471324..0b3d400041c 100644
--- a/spec/helpers/markup_helper_spec.rb
+++ b/spec/helpers/markup_helper_spec.rb
@@ -332,8 +332,8 @@ RSpec.describe MarkupHelper do
context 'when file is Markdown' do
let(:extension) { 'md' }
- it 'renders using #markdown_unsafe helper method' do
- expect(helper).to receive(:markdown_unsafe).with('wiki content', context)
+ it 'renders using CommonMark method' do
+ expect(Banzai).to receive(:render).with('wiki content', context)
helper.render_wiki_content(wiki_page)
end
@@ -377,24 +377,16 @@ RSpec.describe MarkupHelper do
end
end
- context 'when file is Kramdown' do
+ context 'when file is R Markdown' do
let(:extension) { 'rmd' }
- let(:content) do
- <<-EOF
-{::options parse_block_html="true" /}
-
-<div>
-FooBar
-</div>
- EOF
- end
+ let(:content) { '## Header' }
- it 'renders using #markdown_unsafe helper method' do
- expect(helper).to receive(:markdown_unsafe).with(content, context)
+ it 'renders using CommonMark method' do
+ expect(Markup::RenderingService).to receive(:new).and_call_original
result = helper.render_wiki_content(wiki_page)
- expect(result).to be_empty
+ expect(result).to include('Header</h2>')
end
end
@@ -424,23 +416,9 @@ FooBar
expect(helper.markup('foo.rst', content).encoding.name).to eq('UTF-8')
end
- it 'delegates to #markdown_unsafe when file name corresponds to Markdown' do
- expect(Gitlab::MarkupHelper).to receive(:gitlab_markdown?).with('foo.md').and_return(true)
- expect(helper).to receive(:markdown_unsafe).and_return('NOEL')
-
- expect(helper.markup('foo.md', content)).to eq('NOEL')
- end
-
- it 'delegates to #asciidoc_unsafe when file name corresponds to AsciiDoc' do
- expect(Gitlab::MarkupHelper).to receive(:asciidoc?).with('foo.adoc').and_return(true)
- expect(helper).to receive(:asciidoc_unsafe).and_return('NOEL')
-
- expect(helper.markup('foo.adoc', content)).to eq('NOEL')
- end
-
it 'uses passed in rendered content' do
expect(Gitlab::MarkupHelper).not_to receive(:gitlab_markdown?)
- expect(helper).not_to receive(:markdown_unsafe)
+ expect(Markup::RenderingService).not_to receive(:execute)
expect(helper.markup('foo.md', content, rendered: '<p>NOEL</p>')).to eq('<p>NOEL</p>')
end
@@ -448,113 +426,18 @@ FooBar
it 'defaults to CommonMark' do
expect(helper.markup('foo.md', 'x^2')).to include('x^2')
end
- end
-
- describe '#markup_unsafe' do
- subject { helper.markup_unsafe(file_name, text, context) }
-
- let_it_be(:project_base) { create(:project, :repository) }
- let_it_be(:context) { { project: project_base } }
-
- let(:file_name) { 'foo.bar' }
- let(:text) { 'Noël' }
-
- context 'when text is missing' do
- let(:text) { nil }
-
- it 'returns an empty string' do
- is_expected.to eq('')
- end
- end
-
- context 'when rendering takes too long' do
- before do
- stub_const("MarkupHelper::RENDER_TIMEOUT", 0.1)
- allow(Gitlab::OtherMarkup).to receive(:render) { sleep(0.2) }
- end
-
- it 'times out' do
- expect(Gitlab::RenderTimeout).to receive(:timeout).and_call_original
- expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
- instance_of(Timeout::Error),
- project_id: project.id, file_name: file_name
- )
-
- subject
- end
-
- context 'when markup_rendering_timeout is disabled' do
- it 'waits until the execution completes' do
- stub_feature_flags(markup_rendering_timeout: false)
-
- expect(Gitlab::RenderTimeout).not_to receive(:timeout)
-
- subject
- end
- end
- end
-
- context 'when file is a markdown file' do
- let(:file_name) { 'foo.md' }
- it 'returns html (rendered by Banzai)' do
- expected_html = '<p data-sourcepos="1:1-1:5" dir="auto">Noël</p>'
-
- expect(Banzai).to receive(:render).with(text, context) { expected_html }
-
- is_expected.to eq(expected_html)
- end
-
- context 'when renderer returns an error' do
- before do
- allow(Banzai).to receive(:render).and_raise(StandardError, "An error")
- end
-
- it 'returns html (rendered by ActionView:TextHelper)' do
- is_expected.to eq('<p>Noël</p>')
- end
-
- it 'logs the error' do
- expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
- instance_of(StandardError),
- project_id: project.id, file_name: 'foo.md'
- )
-
- subject
- end
- end
- end
-
- context 'when file is asciidoc file' do
- let(:file_name) { 'foo.adoc' }
-
- it 'returns html (rendered by Gitlab::Asciidoc)' do
- expected_html = "<div>\n<p>Noël</p>\n</div>"
-
- expect(Gitlab::Asciidoc).to receive(:render).with(text, context) { expected_html }
-
- is_expected.to eq(expected_html)
- end
- end
-
- context 'when file is a regular text file' do
- let(:file_name) { 'foo.txt' }
-
- it 'returns html (rendered by ActionView::TagHelper)' do
- is_expected.to eq('<pre class="plain-readme">Noël</pre>')
- end
- end
-
- context 'when file has an unknown type' do
- let(:file_name) { 'foo.tex' }
+ it 'sets additional context for Asciidoc' do
+ context = {}
+ assign(:commit, commit)
+ assign(:ref, 'ref')
+ assign(:path, 'path')
- it 'returns html (rendered by Gitlab::OtherMarkup)' do
- expected_html = 'Noël'
+ expect(Gitlab::Asciidoc).to receive(:render)
- expect(Gitlab::OtherMarkup).to receive(:render).with(file_name, text, context) { expected_html }
+ helper.markup('foo.adoc', content, context)
- is_expected.to eq(expected_html)
- end
+ expect(context).to include(commit: commit, ref: 'ref', requested_path: 'path')
end
end
diff --git a/spec/helpers/nav/top_nav_helper_spec.rb b/spec/helpers/nav/top_nav_helper_spec.rb
index 9c396d6bf25..0d43cfaae90 100644
--- a/spec/helpers/nav/top_nav_helper_spec.rb
+++ b/spec/helpers/nav/top_nav_helper_spec.rb
@@ -27,11 +27,9 @@ RSpec.describe Nav::TopNavHelper do
let(:subject) { helper.top_nav_view_model(project: current_project, group: current_group) }
- let(:menu_title) { 'Menu' }
+ let(:menu_tooltip) { 'Main menu' }
before do
- stub_feature_flags(new_navbar_layout: false)
-
allow(Gitlab::CurrentSettings).to receive(:admin_mode) { with_current_settings_admin_mode }
allow(helper).to receive(:header_link?).with(:admin_mode) { with_header_link_admin_mode }
@@ -46,8 +44,8 @@ RSpec.describe Nav::TopNavHelper do
allow(helper).to receive(:dashboard_nav_link?).with(:activity) { with_activity }
end
- it 'has :menuTitle' do
- expect(subject[:menuTitle]).to eq(menu_title)
+ it 'has :menuTooltip' do
+ expect(subject[:menuTooltip]).to eq(menu_tooltip)
end
context 'when current_user is nil (anonymous)' do
@@ -108,7 +106,7 @@ RSpec.describe Nav::TopNavHelper do
let(:current_user) { user }
it 'has no menu items or views by default' do
- expect(subject).to eq({ menuTitle: menu_title,
+ expect(subject).to eq({ menuTooltip: menu_tooltip,
primary: [],
secondary: [],
shortcuts: [],
@@ -176,74 +174,6 @@ RSpec.describe Nav::TopNavHelper do
expect(projects_view[:linksSecondary]).to eq([])
end
- context 'when extra submenu options are not hidden' do
- before do
- stub_feature_flags(remove_extra_primary_submenu_options: false)
- end
-
- it 'has expected :linksPrimary' do
- expected_links_primary = [
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Your projects',
- **menu_data_tracking_attrs('your_projects')
- },
- href: '/dashboard/projects',
- id: 'your',
- title: 'Your projects'
- ),
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Starred projects',
- **menu_data_tracking_attrs('starred_projects')
- },
- href: '/dashboard/projects/starred',
- id: 'starred',
- title: 'Starred projects'
- ),
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Explore projects',
- **menu_data_tracking_attrs('explore_projects')
- },
- href: '/explore',
- id: 'explore',
- title: 'Explore projects'
- ),
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Explore topics',
- **menu_data_tracking_attrs('explore_topics')
- },
- href: '/explore/projects/topics',
- id: 'topics',
- title: 'Explore topics'
- )
- ]
- expect(projects_view[:linksPrimary]).to eq(expected_links_primary)
- end
-
- it 'has expected :linksSecondary' do
- expected_links_secondary = [
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Create new project',
- **menu_data_tracking_attrs('create_new_project')
- },
- href: '/projects/new',
- id: 'create',
- title: 'Create new project'
- )
- ]
- expect(projects_view[:linksSecondary]).to eq(expected_links_secondary)
- end
- end
-
context 'with current nav as project' do
before do
helper.nav('project')
@@ -341,54 +271,6 @@ RSpec.describe Nav::TopNavHelper do
expect(groups_view[:linksSecondary]).to eq([])
end
- context 'when extra submenu options are not hidden' do
- before do
- stub_feature_flags(remove_extra_primary_submenu_options: false)
- end
-
- it 'has expected :linksPrimary' do
- expected_links_primary = [
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Your groups',
- **menu_data_tracking_attrs('your_groups')
- },
- href: '/dashboard/groups',
- id: 'your',
- title: 'Your groups'
- ),
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Explore groups',
- **menu_data_tracking_attrs('explore_groups')
- },
- href: '/explore/groups',
- id: 'explore',
- title: 'Explore groups'
- )
- ]
- expect(groups_view[:linksPrimary]).to eq(expected_links_primary)
- end
-
- it 'has expected :linksSecondary' do
- expected_links_secondary = [
- ::Gitlab::Nav::TopNavMenuItem.build(
- data: {
- qa_selector: 'menu_item_link',
- qa_title: 'Create group',
- **menu_data_tracking_attrs('create_group')
- },
- href: '/groups/new',
- id: 'create',
- title: 'Create group'
- )
- ]
- expect(groups_view[:linksSecondary]).to eq(expected_links_secondary)
- end
- end
-
context 'with external user' do
let(:current_user) { external_user }
diff --git a/spec/helpers/projects/alert_management_helper_spec.rb b/spec/helpers/projects/alert_management_helper_spec.rb
index a78a8add336..97b75ae5080 100644
--- a/spec/helpers/projects/alert_management_helper_spec.rb
+++ b/spec/helpers/projects/alert_management_helper_spec.rb
@@ -110,6 +110,7 @@ RSpec.describe Projects::AlertManagementHelper do
describe '#alert_management_detail_data' do
let(:alert_id) { 1 }
let(:issues_path) { project_issues_path(project) }
+ let(:details_alert_management_path) { details_project_alert_management_path(project, alert_id) }
let(:can_update_alert) { true }
before do
@@ -125,6 +126,7 @@ RSpec.describe Projects::AlertManagementHelper do
'project-path' => project_path,
'project-id' => project_id,
'project-issues-path' => issues_path,
+ 'project-alert-management-details-path' => details_alert_management_path,
'page' => 'OPERATIONS',
'can-update' => 'true'
)
diff --git a/spec/helpers/projects/ml/experiments_helper_spec.rb b/spec/helpers/projects/ml/experiments_helper_spec.rb
new file mode 100644
index 00000000000..e4421ff7606
--- /dev/null
+++ b/spec/helpers/projects/ml/experiments_helper_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'rspec'
+
+require 'spec_helper'
+require 'mime/types'
+
+RSpec.describe Projects::Ml::ExperimentsHelper do
+ let_it_be(:project) { build(:project, :private) }
+ let_it_be(:experiment) { build(:ml_experiments, user_id: project.creator, project: project) }
+ let_it_be(:candidates) do
+ create_list(:ml_candidates, 2, experiment: experiment, user: project.creator).tap do |c|
+ c[0].params.create!([{ name: 'param1', value: 'p1' }, { name: 'param2', value: 'p2' }])
+ c[0].metrics.create!(
+ [{ name: 'metric1', value: 0.1 }, { name: 'metric2', value: 0.2 }, { name: 'metric3', value: 0.3 }]
+ )
+
+ c[1].params.create!([{ name: 'param2', value: 'p3' }, { name: 'param3', value: 'p4' }])
+ c[1].metrics.create!(name: 'metric3', value: 0.4)
+ end
+ end
+
+ describe '#candidates_table_items' do
+ subject { helper.candidates_table_items(candidates) }
+
+ it 'creates the correct model for the table' do
+ expected_value = [
+ { 'param1' => 'p1', 'param2' => 'p2', 'metric1' => '0.1000', 'metric2' => '0.2000', 'metric3' => '0.3000' },
+ { 'param2' => 'p3', 'param3' => 'p4', 'metric3' => '0.4000' }
+ ]
+
+ expect(Gitlab::Json.parse(subject)).to match_array(expected_value)
+ end
+ end
+
+ describe '#unique_logged_names' do
+ context 'when for params' do
+ subject { Gitlab::Json.parse(helper.unique_logged_names(candidates, &:params)) }
+
+ it { is_expected.to match_array(%w[param1 param2 param3]) }
+ end
+
+ context 'when latest_metrics is passed' do
+ subject { Gitlab::Json.parse(helper.unique_logged_names(candidates, &:latest_metrics)) }
+
+ it { is_expected.to match_array(%w[metric1 metric2 metric3]) }
+ end
+ end
+end
diff --git a/spec/helpers/projects/pipeline_helper_spec.rb b/spec/helpers/projects/pipeline_helper_spec.rb
index a70544ace1a..0d3466d6ed2 100644
--- a/spec/helpers/projects/pipeline_helper_spec.rb
+++ b/spec/helpers/projects/pipeline_helper_spec.rb
@@ -31,6 +31,7 @@ RSpec.describe Projects::PipelineHelper do
suite_endpoint: project_pipeline_test_path(project, pipeline, suite_name: 'suite', format: :json),
blob_path: project_blob_path(project, pipeline.sha),
has_test_report: pipeline.complete_and_has_reports?(Ci::JobArtifact.of_report_type(:test)),
+ empty_dag_svg_path: match_asset_path('illustrations/empty-state/empty-dag-md.svg'),
empty_state_image_path: match_asset_path('illustrations/empty-state/empty-test-cases-lg.svg'),
artifacts_expired_image_path: match_asset_path('illustrations/pipeline.svg'),
tests_count: pipeline.test_report_summary.total[:count]
diff --git a/spec/helpers/projects/project_members_helper_spec.rb b/spec/helpers/projects/project_members_helper_spec.rb
index 844c33de635..f3201ce0e14 100644
--- a/spec/helpers/projects/project_members_helper_spec.rb
+++ b/spec/helpers/projects/project_members_helper_spec.rb
@@ -41,7 +41,8 @@ RSpec.describe Projects::ProjectMembersHelper do
it 'returns expected json' do
expected = {
source_id: project.id,
- can_manage_members: true
+ can_manage_members: true,
+ can_manage_access_requests: true
}.as_json
expect(subject).to include(expected)
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 07c2d50f70a..39b8b552672 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -969,7 +969,8 @@ RSpec.describe ProjectsHelper do
containerRegistryAccessLevel: project.project_feature.container_registry_access_level,
environmentsAccessLevel: project.project_feature.environments_access_level,
featureFlagsAccessLevel: project.project_feature.feature_flags_access_level,
- releasesAccessLevel: project.project_feature.releases_access_level
+ releasesAccessLevel: project.project_feature.releases_access_level,
+ infrastructureAccessLevel: project.project_feature.infrastructure_access_level
)
end
diff --git a/spec/helpers/recaptcha_helper_spec.rb b/spec/helpers/recaptcha_helper_spec.rb
index 2c327431437..d97712ce302 100644
--- a/spec/helpers/recaptcha_helper_spec.rb
+++ b/spec/helpers/recaptcha_helper_spec.rb
@@ -10,29 +10,12 @@ RSpec.describe RecaptchaHelper, type: :helper do
end
shared_examples 'Gitlab QA bypass' do
- context 'when GITLAB_QA_USER_AGENT env var is present' do
- using RSpec::Parameterized::TableSyntax
-
- where(:dot_com, :user_agent, :qa_user_agent, :result) do
- false | 'qa_user_agent' | 'qa_user_agent' | true
- true | nil | 'qa_user_agent' | true
- true | '' | 'qa_user_agent' | true
- true | 'qa_user_agent' | '' | true
- true | 'qa_user_agent' | nil | true
- true | 'qa_user_agent' | 'qa_user_agent' | false
+ context 'when it is a QA request' do
+ before do
+ allow(Gitlab::Qa).to receive(:request?).and_return(true)
end
- with_them do
- before do
- allow(Gitlab).to receive(:com?).and_return(dot_com)
- stub_env('GITLAB_QA_USER_AGENT', qa_user_agent)
-
- request_double = instance_double(ActionController::TestRequest, user_agent: user_agent)
- allow(helper).to receive(:request).and_return(request_double)
- end
-
- it { is_expected.to eq result }
- end
+ it { is_expected.to eq false }
end
end
diff --git a/spec/helpers/routing/packages_helper_spec.rb b/spec/helpers/routing/packages_helper_spec.rb
new file mode 100644
index 00000000000..fa5d34fed73
--- /dev/null
+++ b/spec/helpers/routing/packages_helper_spec.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Routing::PackagesHelper do
+ describe '#package_path' do
+ let(:package) { build_stubbed(:package) }
+
+ it "creates package's path" do
+ expect(helper.package_path(package)).to eq("/#{package.project.full_path}/-/packages/#{package.id}")
+ end
+ end
+end
diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb
index 20718ad2f48..192dfaa9caf 100644
--- a/spec/helpers/search_helper_spec.rb
+++ b/spec/helpers/search_helper_spec.rb
@@ -195,7 +195,7 @@ RSpec.describe SearchHelper do
expect(search_autocomplete_opts("Network").size).to eq(1)
expect(search_autocomplete_opts("Graph").size).to eq(1)
- allow(self).to receive(:can?).with(user, :download_code, @project).and_return(false)
+ allow(self).to receive(:can?).with(user, :read_code, @project).and_return(false)
expect(search_autocomplete_opts("Files").size).to eq(0)
expect(search_autocomplete_opts("Commits").size).to eq(0)
@@ -597,6 +597,7 @@ RSpec.describe SearchHelper do
'<script type="text/javascript">alert(\'Another XSS\');</script> test' | ' <span class="gl-text-gray-900 gl-font-weight-bold">test</span>'
'Lorem test ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec.' | 'Lorem <span class="gl-text-gray-900 gl-font-weight-bold">test</span> ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Don...'
'<img src="https://random.foo.com/test.png" width="128" height="128" />some image' | 'some image'
+ '<h2 data-sourcepos="11:1-11:26" dir="auto"><a id="user-content-additional-information" class="anchor" href="#additional-information" aria-hidden="true"></a>Additional information test:</h2><textarea data-update-url="/freepascal.org/fpc/source/-/issues/6163.json" dir="auto" data-testid="textarea" class="hidden js-task-list-field"></textarea>' | '<a class="anchor" href="#additional-information"></a>Additional information <span class="gl-text-gray-900 gl-font-weight-bold">test</span>:'
end
with_them do
@@ -705,112 +706,94 @@ RSpec.describe SearchHelper do
let(:user) { create(:user) }
let(:can_download) { false }
- let(:for_group) { false }
- let(:group) { nil }
- let(:group_metadata) { nil }
-
- let(:for_project) { false }
- let(:project) { nil }
- let(:project_metadata) { nil }
+ let_it_be(:group) { nil }
+ let_it_be(:project) { nil }
let(:scope) { nil }
- let(:code_search) { false }
+
let(:ref) { nil }
- let(:for_snippets) { false }
-
- let(:search_context) do
- instance_double(Gitlab::SearchContext,
- group: group,
- group_metadata: group_metadata,
- project: project,
- project_metadata: project_metadata,
- scope: scope,
- ref: ref)
- end
+ let(:snippet) { nil }
before do
- allow(self).to receive(:search_context).and_return(search_context)
+ @project = project
+ @group = group
+ @ref = ref
+ @snippet = snippet
+
allow(self).to receive(:current_user).and_return(user)
+ allow(self).to receive(:search_scope).and_return(scope)
allow(self).to receive(:can?).and_return(can_download)
+ end
- allow(search_context).to receive(:for_group?).and_return(for_group)
- allow(search_context).to receive(:for_project?).and_return(for_project)
+ context 'no group or project data' do
+ it 'does not add :group, :group_metadata, or :scope to hash' do
+ expect(header_search_context[:group]).to eq(nil)
+ expect(header_search_context[:group_metadata]).to eq(nil)
+ expect(header_search_context[:scope]).to eq(nil)
+ end
- allow(search_context).to receive(:code_search?).and_return(code_search)
- allow(search_context).to receive(:for_snippets?).and_return(for_snippets)
+ it 'does not add :project, :project_metadata, :code_search, or :ref' do
+ expect(header_search_context[:project]).to eq(nil)
+ expect(header_search_context[:project_metadata]).to eq(nil)
+ expect(header_search_context[:code_search]).to eq(nil)
+ expect(header_search_context[:ref]).to eq(nil)
+ end
end
context 'group data' do
- let(:group) { create(:group) }
- let(:group_metadata) { { group_path: group.path, issues_path: "/issues" } }
+ let_it_be(:group) { create(:group) }
+ let(:group_metadata) { { issues_path: issues_group_path(group), mr_path: merge_requests_group_path(group) } }
let(:scope) { 'issues' }
- let(:code_search) { true }
-
- context 'when for_group? is true' do
- let(:for_group) { true }
-
- it 'adds the :group and :group_metadata correctly to hash' do
- expect(header_search_context[:group]).to eq({ id: group.id, name: group.name, full_name: group.full_name })
- expect(header_search_context[:group_metadata]).to eq(group_metadata)
- end
- it 'adds scope and code_search? correctly to hash' do
- expect(header_search_context[:scope]).to eq(scope)
- expect(header_search_context[:code_search]).to eq(code_search)
- end
+ it 'adds the :group, :group_metadata, and :scope correctly to hash' do
+ expect(header_search_context[:group]).to eq({ id: group.id, name: group.name, full_name: group.full_name })
+ expect(header_search_context[:group_metadata]).to eq(group_metadata)
+ expect(header_search_context[:scope]).to eq(scope)
end
- context 'when for_group? is false' do
- let(:for_group) { false }
-
- it 'does not add the :group and :group_metadata to hash' do
- expect(header_search_context[:group]).to eq(nil)
- expect(header_search_context[:group_metadata]).to eq(nil)
- end
-
- it 'does not add scope and code_search? to hash' do
- expect(header_search_context[:scope]).to eq(nil)
- expect(header_search_context[:code_search]).to eq(nil)
- end
+ it 'does not add :project, :project_metadata, :code_search, or :ref' do
+ expect(header_search_context[:project]).to eq(nil)
+ expect(header_search_context[:project_metadata]).to eq(nil)
+ expect(header_search_context[:code_search]).to eq(nil)
+ expect(header_search_context[:ref]).to eq(nil)
end
end
context 'project data' do
- let_it_be(:project) { create(:project) }
- let(:project_metadata) { { project_path: project.path, issues_path: "/issues" } }
- let(:scope) { 'issues' }
- let(:code_search) { true }
+ let_it_be(:project_group) { create(:group) }
+ let_it_be(:project) { create(:project, group: project_group) }
+ let(:project_metadata) { { issues_path: project_issues_path(project), mr_path: project_merge_requests_path(project) } }
+ let(:group_metadata) { { issues_path: issues_group_path(project_group), mr_path: merge_requests_group_path(project_group) } }
- context 'when for_project? is true' do
- let(:for_project) { true }
-
- 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
+ it 'adds the :group and :group-metadata from the project correctly to hash' do
+ expect(header_search_context[:group]).to eq({ id: project_group.id, name: project_group.name, full_name: project_group.full_name })
+ expect(header_search_context[:group_metadata]).to eq(group_metadata)
+ end
- it 'adds scope and code_search? correctly to hash' do
- expect(header_search_context[:scope]).to eq(scope)
- expect(header_search_context[:code_search]).to eq(code_search)
- 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
- context 'when for_project? is false' do
- let(:for_project) { false }
+ context 'with scope' do
+ let(:scope) { 'issues' }
- it 'does not add the :project and :project_metadata to hash' do
- expect(header_search_context[:project]).to eq(nil)
- expect(header_search_context[:project_metadata]).to eq(nil)
+ it 'adds :scope and false :code_search to hash' do
+ expect(header_search_context[:scope]).to eq(scope)
+ expect(header_search_context[:code_search]).to eq(false)
end
+ end
- it 'does not add scope and code_search? to hash' do
+ context 'without scope' do
+ it 'adds code_search true to hash and not :scope' do
expect(header_search_context[:scope]).to eq(nil)
- expect(header_search_context[:code_search]).to eq(nil)
+ expect(header_search_context[:code_search]).to eq(true)
end
end
end
context 'ref data' do
+ let_it_be(:project) { create(:project) }
let(:ref) { 'test-branch' }
context 'when user can? download project data' do
@@ -830,20 +813,18 @@ RSpec.describe SearchHelper do
end
end
- context 'snippets' do
- context 'when for_snippets? is true' do
- let(:for_snippets) { true }
+ context 'snippet' do
+ context 'when searching from snippets' do
+ let(:snippet) { create(:snippet) }
- it 'adds :for_snippets correctly to hash' do
- expect(header_search_context[:for_snippets]).to eq(for_snippets)
+ it 'adds :for_snippets true correctly to hash' do
+ expect(header_search_context[:for_snippets]).to eq(true)
end
end
- context 'when for_snippets? is false' do
- let(:for_snippets) { false }
-
- it 'adds :for_snippets correctly to hash' do
- expect(header_search_context[:for_snippets]).to eq(for_snippets)
+ context 'when not searching from snippets' do
+ it 'adds :for_snippets nil correctly to hash' do
+ expect(header_search_context[:for_snippets]).to eq(nil)
end
end
end
@@ -880,8 +861,8 @@ RSpec.describe SearchHelper do
where(:feature_flag_tab_enabled, :show_elasticsearch_tabs, :project_search_tabs, :condition) do
false | false | false | false
true | true | true | true
- true | false | false | true
- false | true | false | true
+ true | false | false | false
+ false | true | false | false
false | false | true | true
true | false | true | true
end
@@ -1042,6 +1023,7 @@ RSpec.describe SearchHelper do
describe '.search_navigation_json' do
using RSpec::Parameterized::TableSyntax
+
context 'with data' do
example_data_1 = {
projects: { label: _("Projects"), condition: true },
@@ -1060,13 +1042,13 @@ RSpec.describe SearchHelper do
}
where(:data, :matcher) do
- example_data_1 | -> { include("projects") }
- example_data_2 | -> { eq("{}") }
- example_data_3 | -> { include("projects", "blobs", "epics") }
+ example_data_1 | -> { include("projects") }
+ example_data_2 | -> { eq("{}") }
+ example_data_3 | -> { include("projects", "blobs", "epics") }
end
with_them do
- it 'converts correctly' do
+ it 'renders data correctly' do
allow(self).to receive(:search_navigation).with(no_args).and_return(data)
expect(search_navigation_json).to instance_exec(&matcher)
@@ -1075,6 +1057,23 @@ RSpec.describe SearchHelper do
end
end
+ describe '.search_navigation_json with .search_navigation' do
+ before do
+ allow(self).to receive(:current_user).and_return(build(:user))
+ allow(self).to receive(:can?).and_return(true)
+ allow(self).to receive(:project_search_tabs?).and_return(true)
+ allow(self).to receive(:feature_flag_tab_enabled?).and_return(true)
+ allow(search_service).to receive(:show_elasticsearch_tabs?).and_return(true)
+ allow(self).to receive(:feature_flag_tab_enabled?).and_return(true)
+ @show_snippets = true
+ @project = nil
+ end
+
+ it 'test search navigation item order for CE all options enabled' do
+ expect(Gitlab::Json.parse(search_navigation_json).keys).to eq(%w[projects blobs issues merge_requests wiki_blobs commits notes milestones users snippet_titles])
+ end
+ end
+
describe '.search_filter_link_json' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/helpers/snippets_helper_spec.rb b/spec/helpers/snippets_helper_spec.rb
index 37520affc5a..48f67a291c4 100644
--- a/spec/helpers/snippets_helper_spec.rb
+++ b/spec/helpers/snippets_helper_spec.rb
@@ -74,7 +74,7 @@ RSpec.describe SnippetsHelper do
let(:snippet) { public_personal_snippet }
it 'returns copy button of embedded snippets' do
- expect(subject).to eq(copy_button("#{blob.id}"))
+ expect(subject).to eq(copy_button(blob.id.to_s))
end
end
@@ -82,7 +82,7 @@ RSpec.describe SnippetsHelper do
let(:snippet) { public_project_snippet }
it 'returns copy button of embedded snippets' do
- expect(subject).to eq(copy_button("#{blob.id}"))
+ expect(subject).to eq(copy_button(blob.id.to_s))
end
end
diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb
index c64d5990cd9..7c91dd0570f 100644
--- a/spec/helpers/todos_helper_spec.rb
+++ b/spec/helpers/todos_helper_spec.rb
@@ -127,10 +127,22 @@ RSpec.describe TodosHelper do
context 'when given a task' do
let(:todo) { task_todo }
- it 'responds with an appropriate path' do
+ 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)
- expect(path).to eq("/#{todo.project.full_path}/-/work_items/#{todo.target.id}")
+ expect(path).to eq("/#{todo.project.full_path}/-/work_items/#{todo.target.iid}?iid_path=true")
end
end
@@ -310,4 +322,33 @@ RSpec.describe TodosHelper do
it { expect(helper.todos_filter_params[:state]).to eq(result) }
end
end
+
+ describe '#todo_action_name' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:action, :self_added?, :expected_action_name) do
+ Todo::ASSIGNED | false | s_('Todos|assigned you')
+ Todo::ASSIGNED | true | s_('Todos|assigned')
+ Todo::REVIEW_REQUESTED | true | s_('Todos|requested a review of')
+ Todo::MENTIONED | true | format(s_("Todos|mentioned %{who} on"), who: s_('Todos|yourself'))
+ Todo::MENTIONED | false | format(s_("Todos|mentioned %{who} on"), who: _('you'))
+ Todo::DIRECTLY_ADDRESSED | true | format(s_("Todos|mentioned %{who} on"), who: s_('Todos|yourself'))
+ Todo::DIRECTLY_ADDRESSED | false | format(s_("Todos|mentioned %{who} on"), who: _('you'))
+ Todo::BUILD_FAILED | true | s_('Todos|The pipeline failed in')
+ Todo::MARKED | true | s_('Todos|added a todo for')
+ Todo::APPROVAL_REQUIRED | true | format(s_("Todos|set %{who} as an approver for"), who: s_('Todos|yourself'))
+ Todo::APPROVAL_REQUIRED | false | format(s_("Todos|set %{who} as an approver for"), who: _('you'))
+ Todo::UNMERGEABLE | true | s_('Todos|Could not merge')
+ Todo::MERGE_TRAIN_REMOVED | true | s_("Todos|Removed from Merge Train:")
+ end
+
+ with_them do
+ before do
+ alert_todo.action = action
+ alert_todo.user = self_added? ? alert_todo.author : user
+ end
+
+ it { expect(helper.todo_action_name(alert_todo)).to eq(expected_action_name) }
+ end
+ end
end
diff --git a/spec/initializers/hashie_mash_permitted_patch_spec.rb b/spec/initializers/hashie_mash_permitted_patch_spec.rb
new file mode 100644
index 00000000000..0e9f8a485ff
--- /dev/null
+++ b/spec/initializers/hashie_mash_permitted_patch_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Hashie::Mash#permitted patch' do
+ let(:mash) { Hashie::Mash.new }
+
+ before do
+ load Rails.root.join('config/initializers/hashie_mash_permitted_patch.rb')
+ end
+
+ describe '#respond_to? with :permitted?' do
+ it 'returns false' do
+ expect(Gitlab::AppLogger).to receive(:info).with(
+ { message: 'Hashie::Mash#respond_to?(:permitted?)', caller: instance_of(Array) })
+
+ expect(mash.respond_to?(:permitted?)).to be false
+ end
+ end
+
+ describe '#permitted' do
+ it 'raises ArgumentError' do
+ expect(Gitlab::AppLogger).to receive(:info).with(
+ { message: 'Hashie::Mash#permitted?', caller: instance_of(Array) })
+
+ expect { mash.permitted? }.to raise_error(ArgumentError)
+ end
+ end
+end
diff --git a/spec/initializers/memory_watchdog_spec.rb b/spec/initializers/memory_watchdog_spec.rb
index 36f96131c3d..92834c889c2 100644
--- a/spec/initializers/memory_watchdog_spec.rb
+++ b/spec/initializers/memory_watchdog_spec.rb
@@ -3,6 +3,24 @@
require 'fast_spec_helper'
RSpec.describe 'memory watchdog' do
+ shared_examples 'starts configured watchdog' do |configure_monitor_method|
+ shared_examples 'configures and starts watchdog' do
+ it "correctly configures and starts watchdog", :aggregate_failures do
+ expect(Gitlab::Memory::Watchdog::Configurator).to receive(configure_monitor_method)
+
+ expect(Gitlab::Memory::Watchdog).to receive(:new).and_return(watchdog)
+ expect(Gitlab::BackgroundTask).to receive(:new).with(watchdog).and_return(background_task)
+ expect(background_task).to receive(:start)
+ expect(Gitlab::Cluster::LifecycleEvents).to receive(:on_worker_start).and_yield
+
+ run_initializer
+ end
+ end
+ end
+
+ let(:watchdog) { instance_double(Gitlab::Memory::Watchdog) }
+ let(:background_task) { instance_double(Gitlab::BackgroundTask) }
+
subject(:run_initializer) do
load rails_root_join('config/initializers/memory_watchdog.rb')
end
@@ -15,10 +33,6 @@ RSpec.describe 'memory watchdog' do
end
context 'when runtime is an application' do
- let(:watchdog) { instance_double(Gitlab::Memory::Watchdog) }
- let(:background_task) { instance_double(Gitlab::BackgroundTask) }
- let(:logger) { Gitlab::AppLogger }
-
before do
allow(Gitlab::Runtime).to receive(:application?).and_return(true)
end
@@ -29,100 +43,20 @@ RSpec.describe 'memory watchdog' do
run_initializer
end
- shared_examples 'starts configured watchdog' do |handler_class|
- let(:configuration) { Gitlab::Memory::Watchdog::Configuration.new }
- let(:watchdog_monitors_params) do
- {
- Gitlab::Memory::Watchdog::Monitor::HeapFragmentation => {
- max_heap_fragmentation: max_heap_fragmentation,
- max_strikes: max_strikes
- },
- Gitlab::Memory::Watchdog::Monitor::UniqueMemoryGrowth => {
- max_mem_growth: max_mem_growth,
- max_strikes: max_strikes
- }
- }
- end
-
- shared_examples 'configures and starts watchdog' do
- it "correctly configures and starts watchdog", :aggregate_failures do
- expect(watchdog).to receive(:configure).and_yield(configuration)
-
- watchdog_monitors_params.each do |monitor_class, params|
- expect(configuration.monitors).to receive(:use).with(monitor_class, **params)
- end
-
- expect(Gitlab::Memory::Watchdog).to receive(:new).and_return(watchdog)
- expect(Gitlab::BackgroundTask).to receive(:new).with(watchdog).and_return(background_task)
- expect(background_task).to receive(:start)
- expect(Gitlab::Cluster::LifecycleEvents).to receive(:on_worker_start).and_yield
-
- run_initializer
-
- expect(configuration.handler).to be_an_instance_of(handler_class)
- expect(configuration.logger).to eq(logger)
- expect(configuration.sleep_time_seconds).to eq(sleep_time_seconds)
- end
- end
-
- context 'when settings are not passed through the environment' do
- let(:max_strikes) { 5 }
- let(:max_heap_fragmentation) { 0.5 }
- let(:max_mem_growth) { 3.0 }
- let(:sleep_time_seconds) { 60 }
-
- include_examples 'configures and starts watchdog'
- end
-
- context 'when settings are passed through the environment' do
- let(:max_strikes) { 6 }
- let(:max_heap_fragmentation) { 0.4 }
- let(:max_mem_growth) { 2.0 }
- let(:sleep_time_seconds) { 50 }
-
- before do
- stub_env('GITLAB_MEMWD_MAX_STRIKES', 6)
- stub_env('GITLAB_MEMWD_SLEEP_TIME_SEC', 50)
- stub_env('GITLAB_MEMWD_MAX_MEM_GROWTH', 2.0)
- stub_env('GITLAB_MEMWD_MAX_HEAP_FRAG', 0.4)
- end
-
- include_examples 'configures and starts watchdog'
- end
- end
-
- # In tests, the Puma constant does not exist so we cannot use a verified double.
- # rubocop: disable RSpec/VerifiedDoubles
context 'when puma' do
- let(:puma) do
- Class.new do
- def self.cli_config
- Struct.new(:options).new
- end
- end
- end
-
before do
- stub_const('Puma', puma)
- stub_const('Puma::Cluster::WorkerHandle', double.as_null_object)
-
allow(Gitlab::Runtime).to receive(:puma?).and_return(true)
end
- it_behaves_like 'starts configured watchdog', Gitlab::Memory::Watchdog::PumaHandler
+ it_behaves_like 'starts configured watchdog', :configure_for_puma
end
- # rubocop: enable RSpec/VerifiedDoubles
context 'when sidekiq' do
before do
allow(Gitlab::Runtime).to receive(:sidekiq?).and_return(true)
end
- it_behaves_like 'starts configured watchdog', Gitlab::Memory::Watchdog::TermProcessHandler
- end
-
- context 'when other runtime' do
- it_behaves_like 'starts configured watchdog', Gitlab::Memory::Watchdog::NullHandler
+ it_behaves_like 'starts configured watchdog', :configure_for_sidekiq
end
end
@@ -157,10 +91,24 @@ RSpec.describe 'memory watchdog' do
allow(Gitlab::Runtime).to receive(:application?).and_return(true)
end
- it 'does not register life-cycle hook' do
- expect(Gitlab::Cluster::LifecycleEvents).not_to receive(:on_worker_start)
+ context 'when puma' do
+ before do
+ allow(Gitlab::Runtime).to receive(:puma?).and_return(true)
+ end
- run_initializer
+ it_behaves_like 'starts configured watchdog', :configure_for_puma
+ end
+
+ context 'when sidekiq' do
+ before do
+ allow(Gitlab::Runtime).to receive(:sidekiq?).and_return(true)
+ end
+
+ it 'does not register life-cycle hook' do
+ expect(Gitlab::Cluster::LifecycleEvents).not_to receive(:on_worker_start)
+
+ run_initializer
+ end
end
end
end
diff --git a/spec/initializers/sawyer_patch_spec.rb b/spec/initializers/sawyer_patch_spec.rb
index b3c10e63460..9fcdc9583aa 100644
--- a/spec/initializers/sawyer_patch_spec.rb
+++ b/spec/initializers/sawyer_patch_spec.rb
@@ -1,36 +1,33 @@
# frozen_string_literal: true
+
require 'spec_helper'
require 'sawyer'
require_relative '../../config/initializers/sawyer_patch'
RSpec.describe 'sawyer_patch' do
- it 'raises error when acessing a method that overlaps a Ruby method' do
+ it 'raises error when acessing Sawyer Resource dynamic methods' do
sawyer_resource = Sawyer::Resource.new(
Sawyer::Agent.new(''),
{
to_s: 'Overriding method',
+ nil?: 'value',
+ login: 'Login',
user: { to_s: 'Overriding method', name: 'User name' }
}
)
- error_message = 'Sawyer method "to_s" overlaps Ruby method. Convert to a hash to access the attribute.'
- expect { sawyer_resource.to_s }.to raise_error(Sawyer::Error, error_message)
- expect { sawyer_resource.to_s? }.to raise_error(Sawyer::Error, error_message)
- expect { sawyer_resource.to_s = 'new value' }.to raise_error(Sawyer::Error, error_message)
- expect { sawyer_resource.user.to_s }.to raise_error(Sawyer::Error, error_message)
- expect(sawyer_resource.user.name).to eq('User name')
- end
-
- it 'raises error when acessing a boolean method that overlaps a Ruby method' do
- sawyer_resource = Sawyer::Resource.new(
- Sawyer::Agent.new(''),
- {
- nil?: 'value'
- }
- )
-
+ expect { sawyer_resource.to_s }.to raise_error(Sawyer::Error)
+ expect { sawyer_resource.to_s? }.to raise_error(Sawyer::Error)
+ expect { sawyer_resource.to_s = 'new value' }.to raise_error(Sawyer::Error)
expect { sawyer_resource.nil? }.to raise_error(Sawyer::Error)
+ expect { sawyer_resource.user.to_s }.to raise_error(Sawyer::Error)
+ expect { sawyer_resource.login }.to raise_error(Sawyer::Error)
+ expect { sawyer_resource.login? }.to raise_error(Sawyer::Error)
+ expect { sawyer_resource.login = 'New value' }.to raise_error(Sawyer::Error)
+ expect { sawyer_resource.user.name }.to raise_error(Sawyer::Error)
+ expect { sawyer_resource.user.name? }.to raise_error(Sawyer::Error)
+ expect { sawyer_resource.user.name = 'New value' }.to raise_error(Sawyer::Error)
end
it 'raises error when acessing a method that expects an argument' do
@@ -45,47 +42,8 @@ RSpec.describe 'sawyer_patch' do
}
)
- expect(sawyer_resource.user).to eq('value')
- expect { sawyer_resource.user = 'New user' }.to raise_error(ArgumentError)
expect { sawyer_resource == true }.to raise_error(ArgumentError)
expect { sawyer_resource != true }.to raise_error(ArgumentError)
expect { sawyer_resource + 1 }.to raise_error(ArgumentError)
end
-
- it 'does not raise error if is not an overlapping method' do
- sawyer_resource = Sawyer::Resource.new(
- Sawyer::Agent.new(''),
- {
- count_total: 1,
- user: { name: 'User name' }
- }
- )
-
- expect(sawyer_resource.count_total).to eq(1)
- expect(sawyer_resource.count_total?).to eq(true)
- expect(sawyer_resource.count_total + 1).to eq(2)
- sawyer_resource.count_total = 3
- expect(sawyer_resource.count_total).to eq(3)
- expect(sawyer_resource.user.name).to eq('User name')
- end
-
- it 'logs when a sawyer resource dynamic method is called' do
- sawyer_resource = Sawyer::Resource.new(
- Sawyer::Agent.new(''),
- {
- count_total: 1,
- user: { name: 'User name' }
- }
- )
- expected_attributes = []
- allow(Gitlab::Import::Logger).to receive(:warn) do |params|
- expected_attributes.push(params[:attribute])
- end
-
- sawyer_resource.count_total
- sawyer_resource.user
- sawyer_resource.user.name
-
- expect(expected_attributes).to match_array(%i[count_total user user name])
- end
end
diff --git a/spec/lib/api/entities/merge_request_basic_spec.rb b/spec/lib/api/entities/merge_request_basic_spec.rb
index 40f259b86e2..bb0e25d2613 100644
--- a/spec/lib/api/entities/merge_request_basic_spec.rb
+++ b/spec/lib/api/entities/merge_request_basic_spec.rb
@@ -18,12 +18,16 @@ RSpec.describe ::API::Entities::MergeRequestBasic do
subject { entity.as_json }
- it 'includes basic fields' do
- is_expected.to include(
- draft: merge_request.draft?,
- work_in_progress: merge_request.draft?,
- merge_user: nil
- )
+ it 'includes expected fields' do
+ expected_fields = %i[
+ merged_by merge_user merged_at closed_by closed_at target_branch user_notes_count upvotes downvotes
+ author assignees assignee reviewers source_project_id target_project_id labels draft work_in_progress
+ milestone merge_when_pipeline_succeeds merge_status detailed_merge_status sha merge_commit_sha
+ squash_commit_sha discussion_locked should_remove_source_branch force_remove_source_branch
+ reference references web_url time_stats squash task_completion_status has_conflicts blocking_discussions_resolved
+ ]
+
+ is_expected.to include(*expected_fields)
end
context "with :with_api_entity_associations scope" do
diff --git a/spec/lib/api/entities/ml/mlflow/run_info_spec.rb b/spec/lib/api/entities/ml/mlflow/run_info_spec.rb
index 2a6d0825e5c..d5a37f53e21 100644
--- a/spec/lib/api/entities/ml/mlflow/run_info_spec.rb
+++ b/spec/lib/api/entities/ml/mlflow/run_info_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe API::Entities::Ml::Mlflow::RunInfo do
let_it_be(:candidate) { create(:ml_candidates) }
- subject { described_class.new(candidate).as_json }
+ subject { described_class.new(candidate, packages_url: 'http://example.com').as_json }
context 'when start_time is nil' do
it { expect(subject[:start_time]).to eq(0) }
@@ -53,7 +53,7 @@ RSpec.describe API::Entities::Ml::Mlflow::RunInfo do
describe 'artifact_uri' do
it 'is not implemented' do
- expect(subject[:artifact_uri]).to eq('not_implemented')
+ expect(subject[:artifact_uri]).to eq("http://example.com#{candidate.artifact_root}")
end
end
diff --git a/spec/lib/api/entities/release_spec.rb b/spec/lib/api/entities/release_spec.rb
index aa2c5126bb9..d1e5f191614 100644
--- a/spec/lib/api/entities/release_spec.rb
+++ b/spec/lib/api/entities/release_spec.rb
@@ -16,13 +16,13 @@ RSpec.describe API::Entities::Release do
end
describe 'evidences' do
- context 'when the current user can download code' do
+ context 'when the current user can read code' do
let(:entity_evidence) { entity[:evidences].first }
it 'exposes the evidence sha and the json path' do
allow(Ability).to receive(:allowed?).and_call_original
allow(Ability).to receive(:allowed?)
- .with(user, :download_code, project).and_return(true)
+ .with(user, :read_code, project).and_return(true)
expect(entity_evidence[:sha]).to eq(evidence.summary_sha)
expect(entity_evidence[:collected_at]).to eq(evidence.collected_at)
@@ -36,11 +36,11 @@ RSpec.describe API::Entities::Release do
end
end
- context 'when the current user cannot download code' do
+ context 'when the current user cannot read code' do
it 'does not expose any evidence data' do
allow(Ability).to receive(:allowed?).and_call_original
allow(Ability).to receive(:allowed?)
- .with(user, :download_code, project).and_return(false)
+ .with(user, :read_code, project).and_return(false)
expect(entity.keys).not_to include(:evidences)
end
diff --git a/spec/lib/api/entities/user_counts_spec.rb b/spec/lib/api/entities/user_counts_spec.rb
new file mode 100644
index 00000000000..0ed989ad7e9
--- /dev/null
+++ b/spec/lib/api/entities/user_counts_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe API::Entities::UserCounts do
+ let(:user) { build(:user) }
+
+ subject(:entity) { described_class.new(user).as_json }
+
+ it 'represents user counts', :aggregate_failures do
+ expect(user).to receive(:assigned_open_merge_requests_count).and_return(1).twice
+ expect(user).to receive(:assigned_open_issues_count).and_return(2).once
+ expect(user).to receive(:review_requested_open_merge_requests_count).and_return(3).once
+ expect(user).to receive(:todos_pending_count).and_return(4).once
+
+ expect(entity).to include(
+ merge_requests: 1,
+ assigned_issues: 2,
+ assigned_merge_requests: 1,
+ review_requested_merge_requests: 3,
+ todos: 4
+ )
+ end
+end
diff --git a/spec/lib/api/helpers/packages/dependency_proxy_helpers_spec.rb b/spec/lib/api/helpers/packages/dependency_proxy_helpers_spec.rb
index 66cf06cde20..582795acc4e 100644
--- a/spec/lib/api/helpers/packages/dependency_proxy_helpers_spec.rb
+++ b/spec/lib/api/helpers/packages/dependency_proxy_helpers_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe API::Helpers::Packages::DependencyProxyHelpers do
include_context 'dependency proxy helpers context'
let_it_be(:group) { create(:group) }
- let_it_be(:project) { create(:project, group: group) }
+ let_it_be_with_reload(:project) { create(:project, group: group) }
let_it_be_with_reload(:package_setting) { create(:namespace_package_setting, namespace: group) }
let(:target) { project }
@@ -76,19 +76,6 @@ RSpec.describe API::Helpers::Packages::DependencyProxyHelpers do
end
end
- context 'when cascade_package_forwarding_settings is disabled' do
- let(:package_type) { forwardable_package_type }
- let(:forward_to_registry) { true }
-
- before do
- stub_feature_flags(cascade_package_forwarding_settings: false)
- allow_fetch_cascade_application_setting(attribute: "#{forwardable_package_type}_package_requests_forwarding", return_value: true)
- package_setting.update!("#{forwardable_package_type}_package_requests_forwarding" => false)
- end
-
- it_behaves_like 'executing redirect'
- end
-
context 'when no target is present' do
let(:package_type) { forwardable_package_type }
let(:forward_to_registry) { true }
@@ -133,7 +120,7 @@ RSpec.describe API::Helpers::Packages::DependencyProxyHelpers do
end
Packages::Package.package_types.keys.without('maven', 'npm', 'pypi').each do |pkg_type|
- context "#{pkg_type}" do
+ context pkg_type.to_s do
let(:package_type) { pkg_type.to_sym }
it 'raises an error' do
diff --git a/spec/lib/api/helpers/packages_helpers_spec.rb b/spec/lib/api/helpers/packages_helpers_spec.rb
index d764ed4afff..b9c887b3e16 100644
--- a/spec/lib/api/helpers/packages_helpers_spec.rb
+++ b/spec/lib/api/helpers/packages_helpers_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe API::Helpers::PackagesHelpers do
- let_it_be(:helper) { Class.new.include(described_class).new }
+ let_it_be(:helper) { Class.new.include(API::Helpers).include(described_class).new }
let_it_be(:project) { create(:project) }
let_it_be(:group) { create(:group) }
let_it_be(:package) { create(:package) }
@@ -121,4 +121,121 @@ RSpec.describe API::Helpers::PackagesHelpers do
expect(subject).to eq nil
end
end
+
+ describe '#user_project' do
+ before do
+ allow(helper).to receive(:params).and_return(id: project.id)
+ end
+
+ it 'calls find_project! on default action' do
+ expect(helper).to receive(:find_project!)
+
+ helper.user_project
+ end
+
+ it 'calls find_project! on read_project action' do
+ expect(helper).to receive(:find_project!)
+
+ helper.user_project(action: :read_project)
+ end
+
+ it 'calls user_project_with_read_package on read_package action' do
+ expect(helper).to receive(:user_project_with_read_package)
+
+ helper.user_project(action: :read_package)
+ end
+
+ it 'throws ArgumentError on unexpected action' do
+ expect { helper.user_project(action: :other_action) }.to raise_error(ArgumentError, 'unexpected action: other_action')
+ end
+ end
+
+ describe '#user_project_with_read_package' do
+ before do
+ helper.clear_memoization(:user_project_with_read_package)
+
+ allow(helper).to receive(:params).and_return(id: params_id)
+ allow(helper).to receive(:route_authentication_setting).and_return({ authenticate_non_public: true })
+ allow(helper).to receive(:current_user).and_return(user)
+ allow(helper).to receive(:initial_current_user).and_return(user)
+ end
+
+ subject { helper.user_project_with_read_package }
+
+ context 'with non-existing project' do
+ let_it_be(:params_id) { non_existing_record_id }
+
+ context 'with current user' do
+ let_it_be(:user) { create(:user) }
+
+ it 'returns Not Found' do
+ expect(helper).to receive(:render_api_error!).with('404 Project Not Found', 404)
+
+ is_expected.to be_nil
+ end
+ end
+
+ context 'without current user' do
+ let_it_be(:user) { nil }
+
+ it 'returns Unauthorized' do
+ expect(helper).to receive(:render_api_error!).with('401 Unauthorized', 401)
+
+ is_expected.to be_nil
+ end
+ end
+ end
+
+ context 'with existing project' do
+ let_it_be(:params_id) { project.id }
+
+ context 'with current user' do
+ let_it_be(:user) { create(:user) }
+
+ context 'as developer member' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'returns project' do
+ is_expected.to eq(project)
+ end
+ end
+
+ context 'as guest member' do
+ before do
+ project.add_guest(user)
+ end
+
+ it 'returns Forbidden' do
+ expect(helper).to receive(:render_api_error!).with('403 Forbidden', 403)
+
+ is_expected.to be_nil
+ end
+ end
+ end
+
+ context 'without current user' do
+ let_it_be(:user) { nil }
+
+ it 'returns Unauthorized' do
+ expect(helper).to receive(:render_api_error!).with('401 Unauthorized', 401)
+
+ is_expected.to be_nil
+ end
+ end
+ end
+
+ context 'if no authorized project scope' do
+ let_it_be(:params_id) { project.id }
+ let_it_be(:user) { nil }
+
+ it 'returns Forbidden' do
+ expect(helper).to receive(:authorized_project_scope?).and_return(false)
+ expect(helper).to receive(:render_api_error!).with('403 Forbidden', 403)
+
+ is_expected.to be_nil
+ end
+ end
+ end
end
diff --git a/spec/lib/api/helpers_spec.rb b/spec/lib/api/helpers_spec.rb
index 652727f371b..d24a3bd13c0 100644
--- a/spec/lib/api/helpers_spec.rb
+++ b/spec/lib/api/helpers_spec.rb
@@ -798,7 +798,7 @@ RSpec.describe API::Helpers do
context 'with object storage' do
let(:artifact) { create(:ci_job_artifact, :zip, :remote_store) }
- subject { helper.present_artifacts_file!(artifact.file, project: artifact.job.project) }
+ subject { helper.present_artifacts_file!(artifact.file) }
before do
allow(helper).to receive(:env).and_return({})
@@ -830,7 +830,7 @@ RSpec.describe API::Helpers do
it 'retrieves a CDN-fronted URL' do
expect(artifact.file).to receive(:cdn_enabled_url).and_call_original
expect(Gitlab::ApplicationContext).to receive(:push).with(artifact_used_cdn: false).and_call_original
- expect(helper.cdn_fronted_url(artifact.file, artifact.job.project)).to be_a(String)
+ expect(helper.cdn_fronted_url(artifact.file)).to be_a(String)
end
end
@@ -841,7 +841,7 @@ RSpec.describe API::Helpers do
file = double(url: url)
expect(Gitlab::ApplicationContext).not_to receive(:push)
- expect(helper.cdn_fronted_url(file, nil)).to eq(url)
+ expect(helper.cdn_fronted_url(file)).to eq(url)
end
end
end
diff --git a/spec/lib/api/validations/validators/email_or_email_list_spec.rb b/spec/lib/api/validations/validators/email_or_email_list_spec.rb
index ac3111c2319..17cfdf93cdc 100644
--- a/spec/lib/api/validations/validators/email_or_email_list_spec.rb
+++ b/spec/lib/api/validations/validators/email_or_email_list_spec.rb
@@ -14,6 +14,7 @@ RSpec.describe API::Validations::Validators::EmailOrEmailList do
expect_no_validation_error('test' => 'test@example.org')
expect_no_validation_error('test' => 'test1@example.com,test2@example.org')
expect_no_validation_error('test' => 'test1@example.com,test2@example.org,test3@example.co.uk')
+ expect_no_validation_error('test' => %w[test1@example.com test2@example.org test3@example.co.uk])
end
end
@@ -23,6 +24,7 @@ RSpec.describe API::Validations::Validators::EmailOrEmailList do
expect_validation_error('test' => '@example.com')
expect_validation_error('test' => 'test1@example.com,asdf')
expect_validation_error('test' => 'asdf,testa1@example.com,asdf')
+ expect_validation_error('test' => %w[asdf testa1@example.com asdf])
end
end
end
diff --git a/spec/lib/api/validations/validators/git_ref_spec.rb b/spec/lib/api/validations/validators/git_ref_spec.rb
index 0d2d9e8f39a..6b9f5dee5fc 100644
--- a/spec/lib/api/validations/validators/git_ref_spec.rb
+++ b/spec/lib/api/validations/validators/git_ref_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe API::Validations::Validators::GitRef do
expect_validation_error('test' => 'heads/f[/bar')
expect_validation_error('test' => "heads/foo\t")
expect_validation_error('test' => "heads/foo\177")
- expect_validation_error('test' => "#{'a' * 1025}")
+ expect_validation_error('test' => 'a' * 1025)
expect_validation_error('test' => nil)
expect_validation_error('test' => '')
end
diff --git a/spec/lib/api/validations/validators/limit_spec.rb b/spec/lib/api/validations/validators/limit_spec.rb
index 0c10e2f74d2..11d808d390b 100644
--- a/spec/lib/api/validations/validators/limit_spec.rb
+++ b/spec/lib/api/validations/validators/limit_spec.rb
@@ -13,13 +13,13 @@ RSpec.describe API::Validations::Validators::Limit do
it 'does not raise a validation error' do
expect_no_validation_error('test' => '123-456')
expect_no_validation_error('test' => '00000000-ffff-0000-ffff-000000000000')
- expect_no_validation_error('test' => "#{'a' * 255}")
+ expect_no_validation_error('test' => 'a' * 255)
end
end
context 'longer than limit param' do
it 'raises a validation error' do
- expect_validation_error('test' => "#{'a' * 256}")
+ expect_validation_error('test' => 'a' * 256)
end
end
diff --git a/spec/lib/atlassian/jira_connect/jwt/asymmetric_spec.rb b/spec/lib/atlassian/jira_connect/jwt/asymmetric_spec.rb
index b3157dd15fb..86d672067a3 100644
--- a/spec/lib/atlassian/jira_connect/jwt/asymmetric_spec.rb
+++ b/spec/lib/atlassian/jira_connect/jwt/asymmetric_spec.rb
@@ -16,7 +16,8 @@ RSpec.describe Atlassian::JiraConnect::Jwt::Asymmetric do
let(:jwt_headers) { { kid: public_key_id } }
let(:jwt) { JWT.encode(jwt_claims, private_key, 'RS256', jwt_headers) }
let(:public_key) { private_key.public_key }
- let(:install_keys_url) { "https://connect-install-keys.atlassian.com/#{public_key_id}" }
+ let(:stub_asymmetric_jwt_cdn) { 'https://connect-install-keys.atlassian.com' }
+ let(:install_keys_url) { "#{stub_asymmetric_jwt_cdn}/#{public_key_id}" }
let(:qsh) do
Atlassian::Jwt.create_query_string_hash('https://gitlab.test/events/installed', 'POST', 'https://gitlab.test')
end
@@ -85,6 +86,38 @@ RSpec.describe Atlassian::JiraConnect::Jwt::Asymmetric do
it { is_expected.not_to be_valid }
end
+
+ context 'with jira_connect_proxy_url setting' do
+ let(:stub_asymmetric_jwt_cdn) { 'https://example.com/-/jira_connect/public_keys' }
+
+ before do
+ stub_application_setting(jira_connect_proxy_url: 'https://example.com')
+ end
+
+ it 'requests the settings CDN' do
+ expect(JWT).to receive(:decode).twice.and_call_original
+
+ expect(asymmetric_jwt).to be_valid
+
+ expect(WebMock).to have_requested(:get, "https://example.com/-/jira_connect/public_keys/#{public_key_id}")
+ end
+
+ context 'when jira_connect_oauth_self_managed disabled' do
+ let(:stub_asymmetric_jwt_cdn) { 'https://connect-install-keys.atlassian.com' }
+
+ before do
+ stub_feature_flags(jira_connect_oauth_self_managed: false)
+ end
+
+ it 'requests the default CDN' do
+ expect(JWT).to receive(:decode).twice.and_call_original
+
+ expect(asymmetric_jwt).to be_valid
+
+ expect(WebMock).to have_requested(:get, install_keys_url)
+ end
+ end
+ end
end
describe '#iss_claim' do
diff --git a/spec/lib/backup/database_backup_error_spec.rb b/spec/lib/backup/database_backup_error_spec.rb
index e001f65465c..2745d1540ea 100644
--- a/spec/lib/backup/database_backup_error_spec.rb
+++ b/spec/lib/backup/database_backup_error_spec.rb
@@ -19,12 +19,12 @@ RSpec.describe Backup::DatabaseBackupError do
it { is_expected.to respond_to :db_file_name }
it 'expects exception message to include database file' do
- expect(subject.message).to include("#{db_file_name}")
+ expect(subject.message).to include(db_file_name.to_s)
end
it 'expects exception message to include database paths being back-up' do
- expect(subject.message).to include("#{config[:host]}")
- expect(subject.message).to include("#{config[:port]}")
- expect(subject.message).to include("#{config[:database]}")
+ expect(subject.message).to include(config[:host].to_s)
+ expect(subject.message).to include(config[:port].to_s)
+ expect(subject.message).to include(config[:database].to_s)
end
end
diff --git a/spec/lib/backup/file_backup_error_spec.rb b/spec/lib/backup/file_backup_error_spec.rb
index bb174bbe4a0..948e15b7e5c 100644
--- a/spec/lib/backup/file_backup_error_spec.rb
+++ b/spec/lib/backup/file_backup_error_spec.rb
@@ -13,11 +13,11 @@ RSpec.describe Backup::FileBackupError do
it { is_expected.to respond_to :backup_tarball }
it 'expects exception message to include file backup path location' do
- expect(subject.message).to include("#{subject.backup_tarball}")
+ expect(subject.message).to include(subject.backup_tarball.to_s)
end
it 'expects exception message to include file being back-up' do
- expect(subject.message).to include("#{subject.app_files_dir}")
+ expect(subject.message).to include(subject.app_files_dir.to_s)
end
end
diff --git a/spec/lib/banzai/filter/autolink_filter_spec.rb b/spec/lib/banzai/filter/autolink_filter_spec.rb
index ba15860f3c9..75108130602 100644
--- a/spec/lib/banzai/filter/autolink_filter_spec.rb
+++ b/spec/lib/banzai/filter/autolink_filter_spec.rb
@@ -195,7 +195,7 @@ RSpec.describe Banzai::Filter::AutolinkFilter do
it 'escapes RTLO and other characters' do
# rendered text looks like "http://example.com/evilexe.mp3"
evil_link = "#{link}evil\u202E3pm.exe"
- doc = filter("#{evil_link}")
+ doc = filter(evil_link.to_s)
expect(doc.at_css('a')['href']).to eq "http://about.gitlab.com/evil%E2%80%AE3pm.exe"
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 ef23725c790..a11fe203541 100644
--- a/spec/lib/banzai/filter/issuable_reference_expansion_filter_spec.rb
+++ b/spec/lib/banzai/filter/issuable_reference_expansion_filter_spec.rb
@@ -91,7 +91,7 @@ RSpec.describe Banzai::Filter::IssuableReferenceExpansionFilter do
link = create_link(closed_issue.to_reference(other_project), issue: closed_issue.id, reference_type: 'issue')
doc = filter(link, context.merge(project: other_project))
- expect(doc.css('a').last.text).to eq("#{closed_issue.to_reference(other_project)}")
+ expect(doc.css('a').last.text).to eq(closed_issue.to_reference(other_project).to_s)
end
it 'does not append state when filter is not enabled' do
diff --git a/spec/lib/banzai/filter/math_filter_spec.rb b/spec/lib/banzai/filter/math_filter_spec.rb
index dd116eb1109..c5d2bcd5363 100644
--- a/spec/lib/banzai/filter/math_filter_spec.rb
+++ b/spec/lib/banzai/filter/math_filter_spec.rb
@@ -97,7 +97,8 @@ RSpec.describe Banzai::Filter::MathFilter do
describe 'block display math using $$\n...\n$$ syntax' do
context 'with valid syntax' do
where(:text, :result_template) do
- "$$\n2+2\n$$" | "<math>2+2</math>"
+ "$$\n2+2\n$$" | "<math>2+2</math>"
+ "$$\n2+2\n3+4\n$$" | "<math>2+2\n3+4</math>"
end
with_them do
@@ -110,35 +111,35 @@ RSpec.describe Banzai::Filter::MathFilter do
describe 'display math using ```math...``` syntax' do
it 'adds data-math-style display attribute to display math' do
- doc = filter('<pre class="code highlight js-syntax-highlight language-math" v-pre="true"><code>2+2</code></pre>')
+ doc = filter('<pre lang="math"><code>2+2</code></pre>')
pre = doc.xpath('descendant-or-self::pre').first
expect(pre['data-math-style']).to eq 'display'
end
it 'adds js-render-math class to display math' do
- doc = filter('<pre class="code highlight js-syntax-highlight language-math" v-pre="true"><code>2+2</code></pre>')
+ doc = filter('<pre lang="math"><code>2+2</code></pre>')
pre = doc.xpath('descendant-or-self::pre').first
expect(pre[:class]).to include("js-render-math")
end
it 'ignores code blocks that are not math' do
- input = '<pre class="code highlight js-syntax-highlight language-plaintext" v-pre="true"><code>2+2</code></pre>'
+ input = '<pre lang="plaintext"><code>2+2</code></pre>'
doc = filter(input)
expect(doc.to_s).to eq input
end
it 'requires the pre to contain both code and math' do
- input = '<pre class="highlight js-syntax-highlight language-plaintext language-math" v-pre="true"><code>2+2</code></pre>'
+ input = '<pre lang="math">something</pre>'
doc = filter(input)
expect(doc.to_s).to eq input
end
it 'dollar signs around to display math' do
- doc = filter('$<pre class="code highlight js-syntax-highlight language-math" v-pre="true"><code>2+2</code></pre>$')
+ doc = filter('$<pre lang="math"><code>2+2</code></pre>$')
before = doc.xpath('descendant-or-self::text()[1]').first
after = doc.xpath('descendant-or-self::text()[3]').first
diff --git a/spec/lib/banzai/filter/references/alert_reference_filter_spec.rb b/spec/lib/banzai/filter/references/alert_reference_filter_spec.rb
index cba41166be4..c1fdee48f12 100644
--- a/spec/lib/banzai/filter/references/alert_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/alert_reference_filter_spec.rb
@@ -229,7 +229,7 @@ RSpec.describe Banzai::Filter::References::AlertReferenceFilter do
let(:alert2_reference) { alert2.to_reference(full: true) }
it 'does not have N+1 per multiple references per project', :use_sql_query_cache do
- markdown = "#{alert_reference}"
+ markdown = alert_reference.to_s
max_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
reference_filter(markdown)
end.count
diff --git a/spec/lib/banzai/filter/references/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/references/commit_reference_filter_spec.rb
index 6bcea41a603..c368a852ea9 100644
--- a/spec/lib/banzai/filter/references/commit_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/commit_reference_filter_spec.rb
@@ -282,7 +282,7 @@ RSpec.describe Banzai::Filter::References::CommitReferenceFilter do
let(:commit3_reference) { commit3.to_reference(full: true) }
it 'does not have N+1 per multiple references per project', :use_sql_query_cache do
- markdown = "#{commit_reference}"
+ markdown = commit_reference.to_s
max_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
reference_filter(markdown)
end.count
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 d17deaa4736..32538948b4b 100644
--- a/spec/lib/banzai/filter/references/issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/issue_reference_filter_spec.rb
@@ -392,7 +392,7 @@ RSpec.describe Banzai::Filter::References::IssueReferenceFilter do
context 'cross-project URL in link href' do
let(:reference_link) { %{<a href="#{reference}">Reference</a>} }
- let(:reference) { "#{issue_url + "#note_123"}" }
+ let(:reference) { (issue_url + "#note_123").to_s }
let(:issue) { create(:issue, project: project2) }
let(:project2) { create(:project, :public, namespace: namespace) }
let(:namespace) { create(:namespace, name: 'cross-reference') }
@@ -497,7 +497,7 @@ RSpec.describe Banzai::Filter::References::IssueReferenceFilter do
end
it 'links to a valid reference for cross-reference in link href' do
- reference = "#{issue_url + "#note_123"}"
+ reference = (issue_url + "#note_123").to_s
reference_link = %{<a href="#{reference}">Reference</a>}
doc = reference_filter("See #{reference_link}", context)
diff --git a/spec/lib/banzai/filter/references/label_reference_filter_spec.rb b/spec/lib/banzai/filter/references/label_reference_filter_spec.rb
index 12cdb5cfb95..d5b9c71b861 100644
--- a/spec/lib/banzai/filter/references/label_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/label_reference_filter_spec.rb
@@ -715,13 +715,13 @@ RSpec.describe Banzai::Filter::References::LabelReferenceFilter do
let_it_be(:project_label2) { create(:label, project: project) }
let_it_be(:project2_label) { create(:label, project: project2) }
let_it_be(:group2_label) { create(:group_label, group: group2, color: '#00ff00') }
- let_it_be(:project_reference) { "#{project_label.to_reference}" }
- let_it_be(:project_reference2) { "#{project_label2.to_reference}" }
- let_it_be(:project2_reference) { "#{project2_label.to_reference}" }
+ let_it_be(:project_reference) { project_label.to_reference.to_s }
+ let_it_be(:project_reference2) { project_label2.to_reference.to_s }
+ let_it_be(:project2_reference) { project2_label.to_reference.to_s }
let_it_be(:group2_reference) { "#{project2.full_path}~#{group2_label.name}" }
it 'does not have N+1 per multiple references per project', :use_sql_query_cache do
- markdown = "#{project_reference}"
+ markdown = project_reference.to_s
control_count = 1
expect do
@@ -737,7 +737,7 @@ RSpec.describe Banzai::Filter::References::LabelReferenceFilter do
it 'has N+1 for multiple unique project/group references', :use_sql_query_cache do
# reference to already loaded project, only one query
- markdown = "#{project_reference}"
+ markdown = project_reference.to_s
control_count = 1
expect do
diff --git a/spec/lib/banzai/filter/references/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/references/milestone_reference_filter_spec.rb
index c21a9339ebb..98090af06b1 100644
--- a/spec/lib/banzai/filter/references/milestone_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/milestone_reference_filter_spec.rb
@@ -490,13 +490,13 @@ RSpec.describe Banzai::Filter::References::MilestoneReferenceFilter do
let_it_be(:project_milestone2) { create(:milestone, project: project) }
let_it_be(:project2_milestone) { create(:milestone, project: project2) }
let_it_be(:group2_milestone) { create(:milestone, group: group2) }
- let_it_be(:project_reference) { "#{project_milestone.to_reference}" }
- let_it_be(:project_reference2) { "#{project_milestone2.to_reference}" }
- let_it_be(:project2_reference) { "#{project2_milestone.to_reference(full: true)}" }
+ let_it_be(:project_reference) { project_milestone.to_reference.to_s }
+ let_it_be(:project_reference2) { project_milestone2.to_reference.to_s }
+ let_it_be(:project2_reference) { project2_milestone.to_reference(full: true).to_s }
let_it_be(:group2_reference) { "#{project2.full_path}%\"#{group2_milestone.name}\"" }
it 'does not have N+1 per multiple references per project', :use_sql_query_cache do
- markdown = "#{project_reference}"
+ markdown = project_reference.to_s
control_count = 4
expect do
@@ -511,7 +511,7 @@ RSpec.describe Banzai::Filter::References::MilestoneReferenceFilter do
end
it 'has N+1 for multiple unique project/group references', :use_sql_query_cache do
- markdown = "#{project_reference}"
+ markdown = project_reference.to_s
control_count = 4
expect do
diff --git a/spec/lib/banzai/filter/references/project_reference_filter_spec.rb b/spec/lib/banzai/filter/references/project_reference_filter_spec.rb
index d88e262883f..0dd52b45f5d 100644
--- a/spec/lib/banzai/filter/references/project_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/project_reference_filter_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Banzai::Filter::References::ProjectReferenceFilter do
include FilterSpecHelper
def invalidate_reference(reference)
- "#{reference.reverse}"
+ reference.reverse.to_s
end
def get_reference(project)
@@ -109,7 +109,7 @@ RSpec.describe Banzai::Filter::References::ProjectReferenceFilter do
let_it_be(:nested_project_reference) { get_reference(nested_project) }
it 'does not have N+1 per multiple project references', :use_sql_query_cache do
- markdown = "#{normal_project_reference}"
+ markdown = normal_project_reference.to_s
# warm up first
reference_filter(markdown)
diff --git a/spec/lib/banzai/filter/references/user_reference_filter_spec.rb b/spec/lib/banzai/filter/references/user_reference_filter_spec.rb
index 70cbdb080a4..b153efd9655 100644
--- a/spec/lib/banzai/filter/references/user_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/references/user_reference_filter_spec.rb
@@ -209,7 +209,7 @@ RSpec.describe Banzai::Filter::References::UserReferenceFilter do
let(:reference3) { group.to_reference }
it 'does not have N+1 per multiple user references', :use_sql_query_cache do
- markdown = "#{reference}"
+ markdown = reference.to_s
control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
reference_filter(markdown)
diff --git a/spec/lib/banzai/filter/repository_link_filter_spec.rb b/spec/lib/banzai/filter/repository_link_filter_spec.rb
index c220263b238..4aeb6e2a722 100644
--- a/spec/lib/banzai/filter/repository_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/repository_link_filter_spec.rb
@@ -3,7 +3,6 @@
require 'spec_helper'
RSpec.describe Banzai::Filter::RepositoryLinkFilter do
- include GitHelpers
include RepoHelpers
def filter(doc, contexts = {})
diff --git a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
index 33adca0ddfc..a409c15533b 100644
--- a/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
+++ b/spec/lib/banzai/filter/syntax_highlight_filter_spec.rb
@@ -23,7 +23,7 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
it "highlights as plaintext" do
result = filter('<pre><code>def fun end</code></pre>')
- expect(result.to_html.delete("\n")).to eq('<div class="gl-relative markdown-code-block js-markdown-code"><pre class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">def fun end</span></code></pre><copy-code></copy-code></div>')
+ expect(result.to_html.delete("\n")).to eq('<div class="gl-relative markdown-code-block js-markdown-code"><pre lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">def fun end</span></code></pre><copy-code></copy-code></div>')
end
include_examples "XSS prevention", ""
@@ -31,9 +31,9 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
context "when contains mermaid diagrams" do
it "ignores mermaid blocks" do
- result = filter('<pre data-mermaid-style="display"><code>mermaid code</code></pre>')
+ result = filter('<pre data-mermaid-style="display" lang="mermaid"><code class="js-render-mermaid">mermaid code</code></pre>')
- expect(result.to_html).to eq('<pre data-mermaid-style="display"><code>mermaid code</code></pre>')
+ expect(result.to_html.delete("\n")).to eq('<div class="gl-relative markdown-code-block js-markdown-code"><pre data-mermaid-style="display" lang="mermaid" class="code highlight js-syntax-highlight language-mermaid" v-pre="true"><code class="js-render-mermaid"><span id="LC1" class="line" lang="mermaid">mermaid code</span></code></pre><copy-code></copy-code></div>')
end
end
@@ -45,11 +45,32 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
end
end
+ # This can happen with the following markdown
+ #
+ # <div>
+ # <pre><code>
+ # something
+ #
+ # else
+ # </code></pre>
+ # </div>
+ #
+ # The blank line causes markdown to process ` else` as a code block.
+ # Which could lead to an orphaned node being replaced and failing
+ context "when <pre><code> is a child of <pre><code> which is a child of a div " do
+ it "captures all text and doesn't fail trying to replace a node with no parent" do
+ text = "<div>\n<pre><code>\nsomething\n<pre><code>else\n</code></pre></code></pre>\n</div>"
+ result = filter(text)
+
+ expect(result.to_html.delete("\n")).to eq('<div><div class="gl-relative markdown-code-block js-markdown-code"><pre lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext"></span><span id="LC2" class="line" lang="plaintext">something</span><span id="LC3" class="line" lang="plaintext">else</span></code></pre><copy-code></copy-code></div></div>')
+ end
+ end
+
context "when a valid language is specified" do
it "highlights as that language" do
result = filter('<pre lang="ruby"><code>def fun end</code></pre>')
- expect(result.to_html.delete("\n")).to eq('<div class="gl-relative markdown-code-block js-markdown-code"><pre class="code highlight js-syntax-highlight language-ruby" lang="ruby" v-pre="true"><code><span id="LC1" class="line" lang="ruby"><span class="k">def</span> <span class="nf">fun</span> <span class="k">end</span></span></code></pre><copy-code></copy-code></div>')
+ expect(result.to_html.delete("\n")).to eq('<div class="gl-relative markdown-code-block js-markdown-code"><pre lang="ruby" class="code highlight js-syntax-highlight language-ruby" v-pre="true"><code><span id="LC1" class="line" lang="ruby"><span class="k">def</span> <span class="nf">fun</span> <span class="k">end</span></span></code></pre><copy-code></copy-code></div>')
end
include_examples "XSS prevention", "ruby"
@@ -59,7 +80,7 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
it "highlights as plaintext" do
result = filter('<pre lang="gnuplot"><code>This is a test</code></pre>')
- expect(result.to_html.delete("\n")).to eq('<div class="gl-relative markdown-code-block js-markdown-code"><pre class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="gnuplot" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This is a test</span></code></pre><copy-code></copy-code></div>')
+ expect(result.to_html.delete("\n")).to eq('<div class="gl-relative markdown-code-block js-markdown-code"><pre lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="gnuplot" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This is a test</span></code></pre><copy-code></copy-code></div>')
end
include_examples "XSS prevention", "gnuplot"
@@ -74,7 +95,7 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
it "highlights as plaintext but with the correct language attribute and class" do
result = filter(%{<pre lang="#{lang}"><code>This is a test</code></pre>})
- expect(result.to_html.delete("\n")).to eq(%{<div class="gl-relative markdown-code-block js-markdown-code"><pre class="code highlight js-syntax-highlight language-#{lang}" lang="#{lang}" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre><copy-code></copy-code></div>})
+ expect(result.to_html.delete("\n")).to eq(%{<div class="gl-relative markdown-code-block js-markdown-code"><pre lang="#{lang}" class="code highlight js-syntax-highlight language-#{lang}" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre><copy-code></copy-code></div>})
end
include_examples "XSS prevention", lang
@@ -87,7 +108,7 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
it "includes data-lang-params tag with extra information" do
result = filter(%{<pre lang="#{lang}" data-meta="#{lang_params}"><code>This is a test</code></pre>})
- expect(result.to_html.delete("\n")).to eq(%{<div class="gl-relative markdown-code-block js-markdown-code"><pre class="code highlight js-syntax-highlight language-#{lang}" lang="#{lang}" #{data_attr}="#{lang_params}" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre><copy-code></copy-code></div>})
+ expect(result.to_html.delete("\n")).to eq(%{<div class="gl-relative markdown-code-block js-markdown-code"><pre lang="#{lang}" class="code highlight js-syntax-highlight language-#{lang}" #{data_attr}="#{lang_params}" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre><copy-code></copy-code></div>})
end
include_examples "XSS prevention", lang
@@ -105,7 +126,7 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
let(:lang_params) { '-1+10' }
let(:expected_result) do
- %{<div class="gl-relative markdown-code-block js-markdown-code"><pre class="code highlight js-syntax-highlight language-#{lang}" lang="#{lang}" #{data_attr}="#{lang_params} more-things" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre><copy-code></copy-code></div>}
+ %{<div class="gl-relative markdown-code-block js-markdown-code"><pre lang="#{lang}" class="code highlight js-syntax-highlight language-#{lang}" #{data_attr}="#{lang_params} more-things" v-pre="true"><code><span id="LC1" class="line" lang="#{lang}">This is a test</span></code></pre><copy-code></copy-code></div>}
end
context 'when delimiter is space' do
@@ -130,13 +151,13 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
it "includes it in the highlighted code block" do
result = filter('<pre data-sourcepos="1:1-3:3"><code lang="plaintext">This is a test</code></pre>')
- expect(result.to_html.delete("\n")).to eq('<div class="gl-relative markdown-code-block js-markdown-code"><pre data-sourcepos="1:1-3:3" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">This is a test</span></code></pre><copy-code></copy-code></div>')
+ expect(result.to_html.delete("\n")).to eq('<div class="gl-relative markdown-code-block js-markdown-code"><pre data-sourcepos="1:1-3:3" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code lang="plaintext"><span id="LC1" class="line" lang="plaintext">This is a test</span></code></pre><copy-code></copy-code></div>')
end
it "escape sourcepos metadata to prevent XSS" do
result = filter('<pre data-sourcepos="&#34;%22 href=&#34;x&#34;></pre><base href=http://unsafe-website.com/><pre x=&#34;"><code></code></pre>')
- expect(result.to_html.delete("\n")).to eq('<div class="gl-relative markdown-code-block js-markdown-code"><pre data-sourcepos=\'"%22 href="x"&gt;&lt;/pre&gt;&lt;base href=http://unsafe-website.com/&gt;&lt;pre x="\' class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="" v-pre="true"><code></code></pre><copy-code></copy-code></div>')
+ expect(result.to_html.delete("\n")).to eq('<div class="gl-relative markdown-code-block js-markdown-code"><pre data-sourcepos=\'"%22 href="x"&gt;&lt;/pre&gt;&lt;base href=http://unsafe-website.com/&gt;&lt;pre x="\' lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code></code></pre><copy-code></copy-code></div>')
end
end
@@ -150,7 +171,7 @@ RSpec.describe Banzai::Filter::SyntaxHighlightFilter do
it "highlights as plaintext" do
result = filter('<pre lang="ruby"><code>This is a test</code></pre>')
- expect(result.to_html.delete("\n")).to eq('<div class="gl-relative markdown-code-block js-markdown-code"><pre class="code highlight js-syntax-highlight" lang="" data-canonical-lang="ruby" v-pre="true"><code><span id="LC1" class="line" lang="">This is a test</span></code></pre><copy-code></copy-code></div>')
+ expect(result.to_html.delete("\n")).to eq('<div class="gl-relative markdown-code-block js-markdown-code"><pre lang="" class="code highlight js-syntax-highlight" data-canonical-lang="ruby" v-pre="true"><code><span id="LC1" class="line" lang="">This is a test</span></code></pre><copy-code></copy-code></div>')
end
include_examples "XSS prevention", "ruby"
diff --git a/spec/lib/banzai/reference_parser/base_parser_spec.rb b/spec/lib/banzai/reference_parser/base_parser_spec.rb
index d31ccccd6c3..9e77137795a 100644
--- a/spec/lib/banzai/reference_parser/base_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/base_parser_spec.rb
@@ -63,7 +63,7 @@ RSpec.describe Banzai::ReferenceParser::BaseParser do
context 'when the link does not have a data-project attribute' do
it 'returns the nodes' do
- expect(subject.nodes_visible_to_user(user, [link])).to eq([link])
+ expect(subject.nodes_visible_to_user(user, [link])).to match_array([link])
end
end
end
diff --git a/spec/lib/banzai/reference_parser/commit_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_parser_spec.rb
index 31cece108bf..3569a1019f0 100644
--- a/spec/lib/banzai/reference_parser/commit_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/commit_parser_spec.rb
@@ -12,12 +12,30 @@ RSpec.describe Banzai::ReferenceParser::CommitParser do
let(:link) { empty_html_link }
describe '#nodes_visible_to_user' do
- context 'when the link has a data-issue attribute' do
+ context 'when the link has a data-project attribute' do
before do
- link['data-commit'] = 123
+ link['data-project'] = project.id.to_s
end
it_behaves_like "referenced feature visibility", "repository"
+
+ it 'includes the link if can_read_reference? returns true' do
+ expect(subject).to receive(:can_read_reference?).with(user, project, link).and_return(true)
+
+ expect(subject.nodes_visible_to_user(user, [link])).to contain_exactly(link)
+ end
+
+ it 'excludes the link if can_read_reference? returns false' do
+ expect(subject).to receive(:can_read_reference?).with(user, project, link).and_return(false)
+
+ expect(subject.nodes_visible_to_user(user, [link])).to be_empty
+ end
+ end
+
+ context 'when the link does not have a data-project attribute' do
+ it 'returns the nodes' do
+ expect(subject.nodes_visible_to_user(user, [link])).to eq([link])
+ end
end
end
@@ -129,7 +147,7 @@ RSpec.describe Banzai::ReferenceParser::CommitParser do
end
end
- context 'when checking commits on another projects' do
+ context 'when checking commits on another projects', :request_store do
let!(:control_links) do
[commit_link]
end
@@ -141,7 +159,7 @@ RSpec.describe Banzai::ReferenceParser::CommitParser do
def commit_link
project = create(:project, :repository, :public)
- Nokogiri::HTML.fragment(%Q{<a data-commit="#{project.commit.id}" data-project="#{project.id}"></a>}).children[0]
+ Nokogiri::HTML.fragment(%(<a data-commit="#{project.commit.id}" data-project="#{project.id}"></a>)).children[0]
end
it_behaves_like 'no project N+1 queries'
diff --git a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
index 2f64aef4fb7..172347fc421 100644
--- a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb
@@ -12,12 +12,30 @@ RSpec.describe Banzai::ReferenceParser::CommitRangeParser do
let(:link) { empty_html_link }
describe '#nodes_visible_to_user' do
- context 'when the link has a data-issue attribute' do
+ context 'when the link has a data-project attribute' do
before do
- link['data-commit-range'] = '123..456'
+ link['data-project'] = project.id.to_s
end
it_behaves_like "referenced feature visibility", "repository"
+
+ it 'includes the link if can_read_reference? returns true' do
+ expect(subject).to receive(:can_read_reference?).with(user, project, link).and_return(true)
+
+ expect(subject.nodes_visible_to_user(user, [link])).to contain_exactly(link)
+ end
+
+ it 'excludes the link if can_read_reference? returns false' do
+ expect(subject).to receive(:can_read_reference?).with(user, project, link).and_return(false)
+
+ expect(subject.nodes_visible_to_user(user, [link])).to be_empty
+ end
+ end
+
+ context 'when the link does not have a data-project attribute' do
+ it 'returns the nodes' do
+ expect(subject.nodes_visible_to_user(user, [link])).to match_array([link])
+ end
end
end
@@ -136,4 +154,22 @@ RSpec.describe Banzai::ReferenceParser::CommitRangeParser do
end
end
end
+
+ context 'when checking commits ranges on another projects', :request_store do
+ let!(:control_links) do
+ [commit_range_link]
+ end
+
+ let!(:actual_links) do
+ control_links + [commit_range_link, commit_range_link]
+ end
+
+ def commit_range_link
+ project = create(:project, :repository, :public)
+
+ Nokogiri::HTML.fragment(%(<a data-commit-range="123...456" data-project="#{project.id}"></a>)).children[0]
+ end
+
+ it_behaves_like 'no project N+1 queries'
+ end
end
diff --git a/spec/lib/banzai/reference_parser/issue_parser_spec.rb b/spec/lib/banzai/reference_parser/issue_parser_spec.rb
index 7de78710d34..c180a42c91e 100644
--- a/spec/lib/banzai/reference_parser/issue_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/issue_parser_spec.rb
@@ -5,10 +5,10 @@ require 'spec_helper'
RSpec.describe Banzai::ReferenceParser::IssueParser do
include ReferenceParserHelpers
- let_it_be(:group) { create(:group, :public) }
- let_it_be(:project) { create(:project, :public, group: group) }
- let_it_be(:user) { create(:user) }
- let_it_be(:issue) { create(:issue, project: project) }
+ let_it_be(:group) { create(:group, :public) }
+ let_it_be_with_reload(:project) { create(:project, :public, group: group) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:issue) { create(:issue, project: project) }
let(:link) { empty_html_link }
diff --git a/spec/lib/bulk_imports/clients/http_spec.rb b/spec/lib/bulk_imports/clients/http_spec.rb
index 75c5f363b1f..6962a943755 100644
--- a/spec/lib/bulk_imports/clients/http_spec.rb
+++ b/spec/lib/bulk_imports/clients/http_spec.rb
@@ -202,6 +202,22 @@ RSpec.describe BulkImports::Clients::HTTP do
it 'returns version as an instance of Gitlab::VersionInfo' do
expect(subject.instance_version).to eq(Gitlab::VersionInfo.parse(version))
end
+
+ context 'when /version endpoint is not available' do
+ it 'requests /metadata endpoint' do
+ response_double = double(code: 404, success?: false, parsed_response: 'Not Found', request: double(path: double(path: '/version')))
+
+ allow(Gitlab::HTTP).to receive(:get)
+ .with('http://gitlab.example/api/v4/version', anything)
+ .and_return(response_double)
+
+ expect(Gitlab::HTTP).to receive(:get)
+ .with('http://gitlab.example/api/v4/metadata', anything)
+ .and_return(version_response)
+
+ expect(subject.instance_version).to eq(Gitlab::VersionInfo.parse(version))
+ end
+ end
end
describe '#compatible_for_project_migration?' do
diff --git a/spec/lib/bulk_imports/common/pipelines/entity_finisher_spec.rb b/spec/lib/bulk_imports/common/pipelines/entity_finisher_spec.rb
index 9ea519d367e..dc17dc594a8 100644
--- a/spec/lib/bulk_imports/common/pipelines/entity_finisher_spec.rb
+++ b/spec/lib/bulk_imports/common/pipelines/entity_finisher_spec.rb
@@ -16,8 +16,10 @@ RSpec.describe BulkImports::Common::Pipelines::EntityFinisher do
bulk_import_id: entity.bulk_import_id,
bulk_import_entity_id: entity.id,
bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
pipeline_class: described_class.name,
message: 'Entity finished',
+ source_version: entity.bulk_import.source_version_info.to_s,
importer: 'gitlab_migration'
)
end
diff --git a/spec/lib/bulk_imports/pipeline/runner_spec.rb b/spec/lib/bulk_imports/pipeline/runner_spec.rb
index a5a01354d0e..e66f2d26911 100644
--- a/spec/lib/bulk_imports/pipeline/runner_spec.rb
+++ b/spec/lib/bulk_imports/pipeline/runner_spec.rb
@@ -55,14 +55,21 @@ RSpec.describe BulkImports::Pipeline::Runner do
expect_next_instance_of(Gitlab::Import::Logger) do |logger|
expect(logger).to receive(:error)
.with(
- log_params(
- context,
- pipeline_step: :extractor,
- pipeline_class: 'BulkImports::MyPipeline',
- exception_class: exception_class,
- exception_message: exception_message,
- message: "Pipeline failed",
- importer: 'gitlab_migration'
+ a_hash_including(
+ 'bulk_import_entity_id' => entity.id,
+ 'bulk_import_id' => entity.bulk_import_id,
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path,
+ 'pipeline_step' => :extractor,
+ 'pipeline_class' => 'BulkImports::MyPipeline',
+ 'exception.class' => exception_class,
+ 'exception.message' => exception_message,
+ 'correlation_id' => anything,
+ 'class' => 'BulkImports::MyPipeline',
+ 'message' => "Pipeline failed",
+ 'importer' => 'gitlab_migration',
+ 'exception.backtrace' => anything,
+ 'source_version' => entity.bulk_import.source_version_info.to_s
)
)
end
@@ -296,6 +303,8 @@ RSpec.describe BulkImports::Pipeline::Runner do
bulk_import_id: context.bulk_import_id,
bulk_import_entity_id: context.entity.id,
bulk_import_entity_type: context.entity.source_type,
+ source_full_path: entity.source_full_path,
+ source_version: context.entity.bulk_import.source_version_info.to_s,
importer: 'gitlab_migration',
context_extra: context.extra
}.merge(extra)
diff --git a/spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb b/spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb
new file mode 100644
index 00000000000..3c3d0a6d1c4
--- /dev/null
+++ b/spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb
@@ -0,0 +1,131 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe BulkImports::Projects::Pipelines::ReferencesPipeline do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:bulk_import) { create(:bulk_import, user: user) }
+ let_it_be(:config) { create(:bulk_import_configuration, bulk_import: bulk_import, url: 'https://my.gitlab.com') }
+ let_it_be(:entity) do
+ create(
+ :bulk_import_entity,
+ :project_entity,
+ project: project,
+ bulk_import: bulk_import,
+ source_full_path: 'source/full/path'
+ )
+ end
+
+ let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) }
+ let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) }
+
+ let(:issue) { create(:issue, project: project, description: 'https://my.gitlab.com/source/full/path/-/issues/1') }
+ let(:mr) { create(:merge_request, source_project: project, description: 'https://my.gitlab.com/source/full/path/-/merge_requests/1') }
+ let(:issue_note) { create(:note, project: project, noteable: issue, note: 'https://my.gitlab.com/source/full/path/-/issues/1') }
+ let(:mr_note) { create(:note, project: project, noteable: mr, note: 'https://my.gitlab.com/source/full/path/-/merge_requests/1') }
+
+ subject(:pipeline) { described_class.new(context) }
+
+ before do
+ project.add_owner(user)
+ end
+
+ def create_project_data
+ [issue, mr, issue_note, mr_note]
+ end
+
+ describe '#extract' do
+ it 'returns ExtractedData containing issues, mrs & their notes' do
+ create_project_data
+
+ extracted_data = subject.extract(context)
+
+ expect(extracted_data).to be_instance_of(BulkImports::Pipeline::ExtractedData)
+ expect(extracted_data.data).to contain_exactly(issue_note, mr, issue, mr_note)
+ end
+ end
+
+ describe '#transform' do
+ it 'updates matching urls with new ones' do
+ transformed_mr = subject.transform(context, mr)
+ transformed_note = subject.transform(context, mr_note)
+
+ expected_url = URI('')
+ expected_url.scheme = ::Gitlab.config.gitlab.https ? 'https' : 'http'
+ expected_url.host = ::Gitlab.config.gitlab.host
+ expected_url.port = ::Gitlab.config.gitlab.port
+ expected_url.path = "/#{project.full_path}/-/merge_requests/#{mr.iid}"
+
+ expect(transformed_mr.description).to eq(expected_url.to_s)
+ expect(transformed_note.note).to eq(expected_url.to_s)
+ end
+
+ context 'when object does not have reference' do
+ it 'returns object unchanged' do
+ issue.update!(description: 'foo')
+
+ transformed_issue = subject.transform(context, issue)
+
+ expect(transformed_issue.description).to eq('foo')
+ end
+ end
+
+ context 'when there are not matched urls' do
+ let(:url) { 'https://my.gitlab.com/another/project/path/-/issues/1' }
+
+ shared_examples 'returns object unchanged' do
+ it 'returns object unchanged' do
+ issue.update!(description: url)
+
+ transformed_issue = subject.transform(context, issue)
+
+ expect(transformed_issue.description).to eq(url)
+ end
+ end
+
+ include_examples 'returns object unchanged'
+
+ context 'when url path does not start with source full path' do
+ let(:url) { 'https://my.gitlab.com/another/source/full/path/-/issues/1' }
+
+ include_examples 'returns object unchanged'
+ end
+
+ context 'when host does not match and url path starts with source full path' do
+ let(:url) { 'https://another.gitlab.com/source/full/path/-/issues/1' }
+
+ include_examples 'returns object unchanged'
+ end
+
+ context 'when url does not match at all' do
+ let(:url) { 'https://website.example/foo/bar' }
+
+ include_examples 'returns object unchanged'
+ end
+ end
+ end
+
+ describe '#load' do
+ it 'saves the object when object body changed' do
+ transformed_issue = subject.transform(context, issue)
+ transformed_note = subject.transform(context, issue_note)
+
+ expect(transformed_issue).to receive(:save!)
+ expect(transformed_note).to receive(:save!)
+
+ subject.load(context, transformed_issue)
+ subject.load(context, transformed_note)
+ end
+
+ context 'when object body is not changed' do
+ it 'does not save the object' do
+ expect(mr).not_to receive(:save!)
+ expect(mr_note).not_to receive(:save!)
+
+ subject.load(context, mr)
+ subject.load(context, mr_note)
+ end
+ end
+ end
+end
diff --git a/spec/lib/error_tracking/sentry_client/issue_spec.rb b/spec/lib/error_tracking/sentry_client/issue_spec.rb
index ac6a4b9e8cd..eaa3c7ee8bc 100644
--- a/spec/lib/error_tracking/sentry_client/issue_spec.rb
+++ b/spec/lib/error_tracking/sentry_client/issue_spec.rb
@@ -59,7 +59,7 @@ RSpec.describe ErrorTracking::SentryClient::Issue do
it_behaves_like 'issues have correct return type', Gitlab::ErrorTracking::Error
it_behaves_like 'issues have correct length', 3
it_behaves_like 'maps Sentry exceptions'
- it_behaves_like 'Sentry API response size limit', enabled_by_default: true
+ it_behaves_like 'Sentry API response size limit'
shared_examples 'has correct external_url' do
describe '#external_url' do
diff --git a/spec/lib/feature/gitaly_spec.rb b/spec/lib/feature/gitaly_spec.rb
index ed80e31e3cd..33696290483 100644
--- a/spec/lib/feature/gitaly_spec.rb
+++ b/spec/lib/feature/gitaly_spec.rb
@@ -6,73 +6,207 @@ RSpec.describe Feature::Gitaly do
let_it_be(:project) { create(:project) }
let_it_be(:project_2) { create(:project) }
+ let_it_be(:repository) { project.repository.raw }
+ let_it_be(:repository_2) { project_2.repository.raw }
+
before do
skip_feature_flags_yaml_validation
+ allow(Feature::Definition).to receive(:get).with(any_args).and_return(
+ Feature::Definition.new('flag.yml', name: :flag, type: :development)
+ )
end
- describe ".enabled?" do
+ describe ".enabled_for_any?" do
context 'when the flag is set globally' do
- let(:feature_flag) { 'global_flag' }
-
context 'when the gate is closed' do
before do
stub_feature_flags(gitaly_global_flag: false)
end
it 'returns false' do
- expect(described_class.enabled?(feature_flag)).to be(false)
+ expect(described_class.enabled_for_any?(:gitaly_global_flag)).to be(false)
end
end
context 'when the flag defaults to on' do
it 'returns true' do
- expect(described_class.enabled?(feature_flag)).to be(true)
+ expect(described_class.enabled_for_any?(:gitaly_global_flag)).to be(true)
end
end
end
context 'when the flag is enabled for a particular project' do
- let(:feature_flag) { 'project_flag' }
-
before do
stub_feature_flags(gitaly_project_flag: project)
end
it 'returns true for that project' do
- expect(described_class.enabled?(feature_flag, project)).to be(true)
+ expect(described_class.enabled_for_any?(:gitaly_project_flag, project)).to be(true)
end
it 'returns false for any other project' do
- expect(described_class.enabled?(feature_flag, project_2)).to be(false)
+ expect(described_class.enabled_for_any?(:gitaly_project_flag, project_2)).to be(false)
end
it 'returns false when no project is passed' do
- expect(described_class.enabled?(feature_flag)).to be(false)
+ expect(described_class.enabled_for_any?(:gitaly_project_flag)).to be(false)
+ end
+ end
+
+ context 'when the flag is enabled for a particular repository' do
+ before do
+ stub_feature_flags(gitaly_repository_flag: repository)
+ end
+
+ it 'returns true for that repository' do
+ expect(described_class.enabled_for_any?(:gitaly_repository_flag, repository)).to be(true)
+ end
+
+ it 'returns false for any other repository' do
+ expect(described_class.enabled_for_any?(:gitaly_repository_flag, repository_2)).to be(false)
+ end
+
+ it 'returns false when no repository is passed' do
+ expect(described_class.enabled_for_any?(:gitaly_repository_flag)).to be(false)
+ end
+ end
+
+ context 'when the flag is checked with multiple input actors' do
+ before do
+ stub_feature_flags(gitaly_flag: repository)
+ end
+
+ it 'returns true if any of the flag is enabled for any of the input actors' do
+ expect(described_class.enabled_for_any?(:gitaly_flag, project, repository)).to be(true)
+ end
+
+ it 'returns false if any of the flag is not enabled for any of the input actors' do
+ expect(
+ described_class.enabled_for_any?(:gitaly_flag, project, project_2, repository_2)
+ ).to be(false)
end
end
end
describe ".server_feature_flags" do
+ let(:group) { create(:group) }
+ let(:user) { create(:user) }
+
before do
- stub_feature_flags(gitaly_global_flag: true, gitaly_project_flag: project, non_gitaly_flag: false)
+ stub_feature_flags(
+ gitaly_global_flag: true,
+ gitaly_project_flag: project,
+ gitaly_repository_flag: repository,
+ gitaly_user_flag: user,
+ gitaly_group_flag: group,
+ non_gitaly_flag: false
+ )
end
subject { described_class.server_feature_flags }
it 'returns a hash of flags starting with the prefix, with dashes instead of underscores' do
expect(subject).to eq('gitaly-feature-global-flag' => 'true',
- 'gitaly-feature-project-flag' => 'false')
+ 'gitaly-feature-project-flag' => 'false',
+ 'gitaly-feature-repository-flag' => 'false',
+ 'gitaly-feature-user-flag' => 'false',
+ 'gitaly-feature-group-flag' => 'false')
end
context 'when a project is passed' do
it 'returns the value for the flag on the given project' do
- expect(described_class.server_feature_flags(project))
+ expect(described_class.server_feature_flags(project: project))
+ .to eq('gitaly-feature-global-flag' => 'true',
+ 'gitaly-feature-project-flag' => 'true',
+ 'gitaly-feature-repository-flag' => 'false',
+ 'gitaly-feature-user-flag' => 'false',
+ 'gitaly-feature-group-flag' => 'false')
+
+ expect(described_class.server_feature_flags(project: project_2))
+ .to eq('gitaly-feature-global-flag' => 'true',
+ 'gitaly-feature-project-flag' => 'false',
+ 'gitaly-feature-repository-flag' => 'false',
+ 'gitaly-feature-user-flag' => 'false',
+ 'gitaly-feature-group-flag' => 'false')
+ end
+ end
+
+ context 'when a repository is passed' do
+ it 'returns the value for the flag on the given repository' do
+ expect(described_class.server_feature_flags(repository: repository))
+ .to eq('gitaly-feature-global-flag' => 'true',
+ 'gitaly-feature-project-flag' => 'false',
+ 'gitaly-feature-repository-flag' => 'true',
+ 'gitaly-feature-user-flag' => 'false',
+ 'gitaly-feature-group-flag' => 'false')
+
+ expect(described_class.server_feature_flags(repository: repository_2))
+ .to eq('gitaly-feature-global-flag' => 'true',
+ 'gitaly-feature-project-flag' => 'false',
+ 'gitaly-feature-repository-flag' => 'false',
+ 'gitaly-feature-user-flag' => 'false',
+ 'gitaly-feature-group-flag' => 'false')
+ end
+ end
+
+ context 'when a user is passed' do
+ it 'returns the value for the flag on the given user' do
+ expect(described_class.server_feature_flags(user: user))
+ .to eq('gitaly-feature-global-flag' => 'true',
+ 'gitaly-feature-project-flag' => 'false',
+ 'gitaly-feature-repository-flag' => 'false',
+ 'gitaly-feature-user-flag' => 'true',
+ 'gitaly-feature-group-flag' => 'false')
+
+ expect(described_class.server_feature_flags(user: create(:user)))
+ .to eq('gitaly-feature-global-flag' => 'true',
+ 'gitaly-feature-project-flag' => 'false',
+ 'gitaly-feature-repository-flag' => 'false',
+ 'gitaly-feature-user-flag' => 'false',
+ 'gitaly-feature-group-flag' => 'false')
+ end
+ end
+
+ context 'when a group is passed' do
+ it 'returns the value for the flag on the given group' do
+ expect(described_class.server_feature_flags(group: group))
.to eq('gitaly-feature-global-flag' => 'true',
- 'gitaly-feature-project-flag' => 'true')
+ 'gitaly-feature-project-flag' => 'false',
+ 'gitaly-feature-repository-flag' => 'false',
+ 'gitaly-feature-user-flag' => 'false',
+ 'gitaly-feature-group-flag' => 'true')
- expect(described_class.server_feature_flags(project_2))
+ expect(described_class.server_feature_flags(group: create(:group)))
.to eq('gitaly-feature-global-flag' => 'true',
- 'gitaly-feature-project-flag' => 'false')
+ 'gitaly-feature-project-flag' => 'false',
+ 'gitaly-feature-repository-flag' => 'false',
+ 'gitaly-feature-user-flag' => 'false',
+ 'gitaly-feature-group-flag' => 'false')
+ end
+ end
+
+ context 'when multiple actors are passed' do
+ it 'returns the corresponding enablement status for actors' do
+ expect(described_class.server_feature_flags(project: project_2, repository: repository))
+ .to eq('gitaly-feature-global-flag' => 'true',
+ 'gitaly-feature-project-flag' => 'false',
+ 'gitaly-feature-repository-flag' => 'true',
+ 'gitaly-feature-user-flag' => 'false',
+ 'gitaly-feature-group-flag' => 'false')
+
+ expect(described_class.server_feature_flags(project: project, repository: repository_2))
+ .to eq('gitaly-feature-global-flag' => 'true',
+ 'gitaly-feature-project-flag' => 'true',
+ 'gitaly-feature-repository-flag' => 'false',
+ 'gitaly-feature-user-flag' => 'false',
+ 'gitaly-feature-group-flag' => 'false')
+
+ expect(described_class.server_feature_flags(user: user, project: project, repository: repository, group: group))
+ .to eq('gitaly-feature-global-flag' => 'true',
+ 'gitaly-feature-project-flag' => 'true',
+ 'gitaly-feature-repository-flag' => 'true',
+ 'gitaly-feature-user-flag' => 'true',
+ 'gitaly-feature-group-flag' => 'true')
end
end
@@ -88,4 +222,67 @@ RSpec.describe Feature::Gitaly do
end
end
end
+
+ describe ".user_actor" do
+ let(:user) { create(:user) }
+
+ context 'when user is passed in' do
+ it 'returns a actor wrapper from user' do
+ expect(described_class.user_actor(user).flipper_id).to eql(user.flipper_id)
+ end
+ end
+
+ context 'when called without user and user_id is available in application context' do
+ it 'returns a actor wrapper from user_id' do
+ ::Gitlab::ApplicationContext.with_context(user: user) do
+ expect(described_class.user_actor.flipper_id).to eql(user.flipper_id)
+ end
+ end
+ end
+
+ context 'when called without user and user_id is absent from application context' do
+ it 'returns nil' do
+ expect(described_class.user_actor).to be(nil)
+ end
+ end
+
+ context 'when something else is passed' do
+ it 'returns nil' do
+ expect(described_class.user_actor(1234)).to be(nil)
+ end
+ end
+ end
+
+ describe ".project_actor" do
+ let_it_be(:project) { create(:project) }
+
+ context 'when project is passed in' do
+ it 'returns a actor wrapper from project' do
+ expect(described_class.project_actor(project).flipper_id).to eql(project.flipper_id)
+ end
+ end
+
+ context 'when something else is passed in' do
+ it 'returns nil' do
+ expect(described_class.project_actor(1234)).to be(nil)
+ end
+ end
+ end
+
+ describe ".group_actor" do
+ let_it_be(:group) { create(:group ) }
+ let_it_be(:project) { create(:project, group: group) }
+
+ context 'when project is passed in' do
+ it "returns a actor wrapper from project's group" do
+ expect(described_class.group_actor(project).flipper_id).to eql(group.flipper_id)
+ end
+ end
+
+ context 'when something else is passed in' do
+ it 'returns nil' do
+ expect(described_class.group_actor(1234)).to be(nil)
+ end
+ end
+ end
end
diff --git a/spec/lib/feature_spec.rb b/spec/lib/feature_spec.rb
index 56e0b4bca30..ad324406450 100644
--- a/spec/lib/feature_spec.rb
+++ b/spec/lib/feature_spec.rb
@@ -522,7 +522,7 @@ RSpec.describe Feature, stub_feature_flags: false do
it_behaves_like 'logging' do
let(:expected_action) { :enable }
- let(:expected_extra) { { "extra.thing" => "#{thing.flipper_id}" } }
+ let(:expected_extra) { { "extra.thing" => thing.flipper_id.to_s } }
end
end
end
@@ -548,7 +548,7 @@ RSpec.describe Feature, stub_feature_flags: false do
it_behaves_like 'logging' do
let(:expected_action) { :disable }
- let(:expected_extra) { { "extra.thing" => "#{thing.flipper_id}" } }
+ let(:expected_extra) { { "extra.thing" => thing.flipper_id.to_s } }
end
end
end
@@ -561,7 +561,7 @@ RSpec.describe Feature, stub_feature_flags: false do
it_behaves_like 'logging' do
let(:expected_action) { :enable_percentage_of_time }
- let(:expected_extra) { { "extra.percentage" => "#{percentage}" } }
+ let(:expected_extra) { { "extra.percentage" => percentage.to_s } }
end
end
@@ -584,7 +584,7 @@ RSpec.describe Feature, stub_feature_flags: false do
it_behaves_like 'logging' do
let(:expected_action) { :enable_percentage_of_actors }
- let(:expected_extra) { { "extra.percentage" => "#{percentage}" } }
+ let(:expected_extra) { { "extra.percentage" => percentage.to_s } }
end
end
@@ -790,11 +790,47 @@ RSpec.describe Feature, stub_feature_flags: false do
let(:group) { create(:group) }
let(:user_name) { project.first_owner.username }
- subject { described_class.new(user: user_name, project: project.full_path, group: group.full_path) }
+ subject do
+ described_class.new(
+ user: user_name,
+ project: project.full_path,
+ group: group.full_path,
+ repository: project.repository.full_path
+ )
+ end
it 'returns all found targets' do
expect(subject.targets).to be_an(Array)
- expect(subject.targets).to eq([project.first_owner, project, group])
+ expect(subject.targets).to eq([project.first_owner, project, group, project.repository])
+ end
+
+ context 'when repository target works with different types of repositories' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :wiki_repo, group: group) }
+ let_it_be(:project_in_user_namespace) { create(:project, namespace: create(:user).namespace) }
+ let(:personal_snippet) { create(:personal_snippet) }
+ let(:project_snippet) { create(:project_snippet, project: project) }
+
+ let(:targets) do
+ [
+ project,
+ project.wiki,
+ project_in_user_namespace,
+ personal_snippet,
+ project_snippet
+ ]
+ end
+
+ subject do
+ described_class.new(
+ repository: targets.map { |t| t.repository.full_path }.join(",")
+ )
+ end
+
+ it 'returns all found targets' do
+ expect(subject.targets).to be_an(Array)
+ expect(subject.targets).to eq(targets.map(&:repository))
+ end
end
end
end
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb
index b4aa843bcd7..258f4a0d019 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/median_spec.rb
@@ -38,6 +38,6 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::Median do
merge_request2.metrics.update!(merged_at: Time.zone.now)
end
- expect(subject).to be_within(0.5).of(7.5.minutes.seconds)
+ expect(subject).to be_within(5.seconds).of(7.5.minutes.seconds)
end
end
diff --git a/spec/lib/gitlab/app_logger_spec.rb b/spec/lib/gitlab/app_logger_spec.rb
index 23bac444dbe..85ca60d539f 100644
--- a/spec/lib/gitlab/app_logger_spec.rb
+++ b/spec/lib/gitlab/app_logger_spec.rb
@@ -5,10 +5,9 @@ require 'spec_helper'
RSpec.describe Gitlab::AppLogger do
subject { described_class }
- it 'builds a Gitlab::Logger object twice' do
- expect(Gitlab::Logger).to receive(:new)
- .exactly(described_class.loggers.size)
- .and_call_original
+ it 'builds two Logger instances' do
+ expect(Gitlab::Logger).to receive(:new).and_call_original
+ expect(Gitlab::JsonLogger).to receive(:new).and_call_original
subject.info('Hello World!')
end
diff --git a/spec/lib/gitlab/application_context_spec.rb b/spec/lib/gitlab/application_context_spec.rb
index 8b2a228b935..58d462aa27f 100644
--- a/spec/lib/gitlab/application_context_spec.rb
+++ b/spec/lib/gitlab/application_context_spec.rb
@@ -44,7 +44,7 @@ RSpec.describe Gitlab::ApplicationContext do
describe '.push' do
it 'passes the expected context on to labkit' do
fake_proc = duck_type(:call)
- expected_context = { user: fake_proc, client_id: fake_proc }
+ expected_context = { user: fake_proc, user_id: fake_proc, client_id: fake_proc }
expect(Labkit::Context).to receive(:push).with(expected_context)
@@ -108,14 +108,16 @@ RSpec.describe Gitlab::ApplicationContext do
context = described_class.new(user: -> { user }, project: -> { project }, namespace: -> { subgroup })
expect(result(context))
- .to include(user: user.username, project: project.full_path, root_namespace: namespace.full_path)
+ .to include(user: user.username, user_id: user.id, project: project.full_path,
+ root_namespace: namespace.full_path)
end
it 'correctly loads the expected values when passed directly' do
context = described_class.new(user: user, project: project, namespace: subgroup)
expect(result(context))
- .to include(user: user.username, project: project.full_path, root_namespace: namespace.full_path)
+ .to include(user: user.username, user_id: user.id, project: project.full_path,
+ root_namespace: namespace.full_path)
end
it 'falls back to a projects namespace when a project is passed but no namespace' do
diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb
index 8fec8bce23e..d2eb9209f42 100644
--- a/spec/lib/gitlab/asciidoc_spec.rb
+++ b/spec/lib/gitlab/asciidoc_spec.rb
@@ -94,9 +94,18 @@ module Gitlab
# Move this test back to the items hash when removing `use_cmark_renderer` feature flag.
it "does not convert dangerous fenced code with inline script into HTML" do
input = '```mypre"><script>alert(3)</script>'
- output = "<div>\n<div>\n<div class=\"gl-relative markdown-code-block js-markdown-code\">\n<pre class=\"code highlight js-syntax-highlight language-plaintext\" lang=\"plaintext\" data-canonical-lang=\"mypre\" v-pre=\"true\"><code></code></pre>\n<copy-code></copy-code>\n</div>\n</div>\n</div>"
+ output = <<~HTML
+ <div>
+ <div>
+ <div class=\"gl-relative markdown-code-block js-markdown-code\">
+ <pre lang=\"plaintext\" class=\"code highlight js-syntax-highlight language-plaintext\" data-canonical-lang=\"mypre\" v-pre=\"true\"><code></code></pre>
+ <copy-code></copy-code>
+ </div>
+ </div>
+ </div>
+ HTML
- expect(render(input, context)).to include(output)
+ expect(render(input, context)).to include(output.strip)
end
it 'does not allow locked attributes to be overridden' do
@@ -360,7 +369,7 @@ module Gitlab
<div>
<div>
<div class="gl-relative markdown-code-block js-markdown-code">
- <pre class="code highlight js-syntax-highlight language-javascript" lang="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="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>
<copy-code></copy-code>
</div>
</div>
@@ -390,7 +399,7 @@ module Gitlab
<div>class.cpp</div>
<div>
<div class="gl-relative markdown-code-block js-markdown-code">
- <pre class="code highlight js-syntax-highlight language-cpp" lang="cpp" data-canonical-lang="c++" v-pre="true"><code><span id="LC1" class="line" lang="cpp"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span></span>
+ <pre lang="cpp" class="code highlight js-syntax-highlight language-cpp" data-canonical-lang="c++" v-pre="true"><code><span id="LC1" class="line" lang="cpp"><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span></span>
<span id="LC2" class="line" lang="cpp"></span>
<span id="LC3" class="line" lang="cpp"><span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">5</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span></span>
<span id="LC4" class="line" lang="cpp"> <span class="n">std</span><span class="o">::</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">"*"</span><span class="o">&lt;&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span></span>
@@ -448,7 +457,7 @@ module Gitlab
stem:[2+2] is 4
MD
- expect(render(input, context)).to include('<pre data-math-style="display" class="code math js-render-math"><code>eta_x gamma</code></pre>')
+ expect(render(input, context)).to include('<pre data-math-style="display" lang="plaintext" class="code math js-render-math" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">eta_x gamma</span></code></pre>')
expect(render(input, context)).to include('<p><code data-math-style="inline" class="code math js-render-math">2+2</code> is 4</p>')
end
end
@@ -567,7 +576,7 @@ module Gitlab
it 'does not allow kroki-plantuml-include to be overridden' do
input = <<~ADOC
- [plantuml, test="{counter:kroki-plantuml-include:/etc/passwd}", format="png"]
+ [plantuml, test="{counter:kroki-plantuml-include:README.md}", format="png"]
....
class BlockProcessor
@@ -578,7 +587,7 @@ module Gitlab
output = <<~HTML
<div>
<div>
- <a class=\"no-attachment-icon\" href=\"https://kroki.io/plantuml/png/eNpLzkksLlZwyslPzg4oyk9OLS7OL-LiQuUr2NTo6ipUJ-eX5pWkFlllF-VnZ-oW5CTmlZTm5uhm5iXnlKak1gIABQEb8A==\" target=\"_blank\" rel=\"noopener noreferrer\"><img src=\"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Diagram\" decoding=\"async\" class=\"lazy\" data-src=\"https://kroki.io/plantuml/png/eNpLzkksLlZwyslPzg4oyk9OLS7OL-LiQuUr2NTo6ipUJ-eX5pWkFlllF-VnZ-oW5CTmlZTm5uhm5iXnlKak1gIABQEb8A==\"></a>
+ <a class=\"no-attachment-icon\" href=\"https://kroki.io/plantuml/png/eNpLzkksLlZwyslPzg4oyk9OLS7OL-LiQuUr2NTo6ipUJ-eX5pWkFlllF-VnZ-oW5CTmlZTm5uhm5iXnlKak1gIABQEb8A==?test=README.md\" target=\"_blank\" rel=\"noopener noreferrer\"><img src=\"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==\" alt=\"Diagram\" decoding=\"async\" class=\"lazy\" data-src=\"https://kroki.io/plantuml/png/eNpLzkksLlZwyslPzg4oyk9OLS7OL-LiQuUr2NTo6ipUJ-eX5pWkFlllF-VnZ-oW5CTmlZTm5uhm5iXnlKak1gIABQEb8A==?test=README.md\"></a>
</div>
</div>
HTML
diff --git a/spec/lib/gitlab/auth/auth_finders_spec.rb b/spec/lib/gitlab/auth/auth_finders_spec.rb
index e2226952d15..05eca4cf70f 100644
--- a/spec/lib/gitlab/auth/auth_finders_spec.rb
+++ b/spec/lib/gitlab/auth/auth_finders_spec.rb
@@ -89,12 +89,13 @@ RSpec.describe Gitlab::Auth::AuthFinders do
context 'with a running job' do
let(:token) { job.token }
- if without_job_token_allowed == :error
+ case without_job_token_allowed
+ when :error
it 'returns an Unauthorized exception' do
expect { subject }.to raise_error(Gitlab::Auth::UnauthorizedError)
expect(@current_authenticated_job).to be_nil
end
- elsif without_job_token_allowed == :user
+ when :user
it 'returns the user' do
expect(subject).to eq(user)
expect(@current_authenticated_job).to eq job
diff --git a/spec/lib/gitlab/background_migration/backfill_project_namespace_details_spec.rb b/spec/lib/gitlab/background_migration/backfill_project_namespace_details_spec.rb
new file mode 100644
index 00000000000..77d6cc43114
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/backfill_project_namespace_details_spec.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::BackfillProjectNamespaceDetails, :migration do
+ let_it_be(:namespace_details) { table(:namespace_details) }
+ let_it_be(:namespaces) { table(:namespaces) }
+ let_it_be(:projects) { table(:projects) }
+
+ subject(:perform_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)
+ .perform
+ end
+
+ describe '#perform' do
+ it 'creates details for all project namespaces in range' do
+ namespaces.create!(id: 5, name: 'test1', path: 'test1', description: "Some description1",
+ description_html: "Some description html1", cached_markdown_version: 4)
+ project_namespace1 = namespaces.create!(id: 6, name: 'test2', path: 'test2', type: 'Project')
+ namespaces.create!(id: 7, name: 'test3', path: 'test3', description: "Some description3",
+ description_html: "Some description html3", cached_markdown_version: 4)
+ project_namespace2 = namespaces.create!(id: 8, name: 'test4', path: 'test4', type: 'Project')
+
+ project1 = projects.create!(namespace_id: project_namespace1.id, name: 'gitlab1', path: 'gitlab1',
+ project_namespace_id: project_namespace1.id, description: "Some description2",
+ description_html: "Some description html2", cached_markdown_version: 4)
+ project2 = projects.create!(namespace_id: project_namespace2.id, name: 'gitlab2', path: 'gitlab2',
+ project_namespace_id: project_namespace2.id,
+ description: "Some description3",
+ description_html: "Some description html4", cached_markdown_version: 4)
+
+ namespace_details.delete_all
+
+ expect(namespace_details.pluck(:namespace_id)).to eql []
+
+ expect { perform_migration }
+ .to change { namespace_details.pluck(:namespace_id) }.from([]).to contain_exactly(
+ project_namespace1.id,
+ project_namespace2.id
+ )
+
+ expect(namespace_details.find_by_namespace_id(project_namespace1.id))
+ .to have_attributes(migrated_attributes(project1))
+ expect(namespace_details.find_by_namespace_id(project_namespace2.id))
+ .to have_attributes(migrated_attributes(project2))
+ end
+ end
+
+ def migrated_attributes(project)
+ {
+ description: project.description,
+ description_html: project.description_html,
+ cached_markdown_version: project.cached_markdown_version
+ }
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/backfill_project_namespace_on_issues_spec.rb b/spec/lib/gitlab/background_migration/backfill_project_namespace_on_issues_spec.rb
index 29833074109..3ca7d28f09d 100644
--- a/spec/lib/gitlab/background_migration/backfill_project_namespace_on_issues_spec.rb
+++ b/spec/lib/gitlab/background_migration/backfill_project_namespace_on_issues_spec.rb
@@ -54,4 +54,21 @@ RSpec.describe Gitlab::BackgroundMigration::BackfillProjectNamespaceOnIssues do
expect { perform_migration }.to change { migration.batch_metrics.timings }
end
+
+ context 'when database timeouts' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(error_class: [ActiveRecord::StatementTimeout, ActiveRecord::QueryCanceled])
+
+ with_them do
+ it 'retries on timeout error' do
+ expect(migration).to receive(:update_batch).exactly(3).times.and_raise(error_class)
+ expect(migration).to receive(:sleep).with(5).twice
+
+ expect do
+ perform_migration
+ end.to raise_error(error_class)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/background_migration/backfill_projects_with_coverage_spec.rb b/spec/lib/gitlab/background_migration/backfill_projects_with_coverage_spec.rb
deleted file mode 100644
index 4a65ecf8c75..00000000000
--- a/spec/lib/gitlab/background_migration/backfill_projects_with_coverage_spec.rb
+++ /dev/null
@@ -1,95 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::BackfillProjectsWithCoverage,
- :suppress_gitlab_schemas_validate_connection, schema: 20210818185845 do
- let(:projects) { table(:projects) }
- let(:project_ci_feature_usages) { table(:project_ci_feature_usages) }
- let(:ci_pipelines) { table(:ci_pipelines) }
- let(:ci_daily_build_group_report_results) { table(:ci_daily_build_group_report_results) }
- let(:group) { table(:namespaces).create!(name: 'user', path: 'user') }
- let(:project_1) { projects.create!(namespace_id: group.id) }
- let(:project_2) { projects.create!(namespace_id: group.id) }
- let(:pipeline_1) { ci_pipelines.create!(project_id: project_1.id, source: 13) }
- let(:pipeline_2) { ci_pipelines.create!(project_id: project_1.id, source: 13) }
- let(:pipeline_3) { ci_pipelines.create!(project_id: project_2.id, source: 13) }
- let(:pipeline_4) { ci_pipelines.create!(project_id: project_2.id, source: 13) }
-
- subject { described_class.new }
-
- describe '#perform' do
- before do
- ci_daily_build_group_report_results.create!(
- id: 1,
- project_id: project_1.id,
- date: 4.days.ago,
- last_pipeline_id: pipeline_1.id,
- ref_path: 'main',
- group_name: 'rspec',
- data: { coverage: 95.0 },
- default_branch: true,
- group_id: group.id
- )
-
- ci_daily_build_group_report_results.create!(
- id: 2,
- project_id: project_1.id,
- date: 3.days.ago,
- last_pipeline_id: pipeline_2.id,
- ref_path: 'main',
- group_name: 'rspec',
- data: { coverage: 95.0 },
- default_branch: true,
- group_id: group.id
- )
-
- ci_daily_build_group_report_results.create!(
- id: 3,
- project_id: project_2.id,
- date: 2.days.ago,
- last_pipeline_id: pipeline_3.id,
- ref_path: 'main',
- group_name: 'rspec',
- data: { coverage: 95.0 },
- default_branch: true,
- group_id: group.id
- )
-
- ci_daily_build_group_report_results.create!(
- id: 4,
- project_id: project_2.id,
- date: 1.day.ago,
- last_pipeline_id: pipeline_4.id,
- ref_path: 'test_branch',
- group_name: 'rspec',
- data: { coverage: 95.0 },
- default_branch: false,
- group_id: group.id
- )
-
- stub_const("#{described_class}::INSERT_DELAY_SECONDS", 0)
- end
-
- it 'creates entries per project and default_branch combination in the given range', :aggregate_failures do
- subject.perform(1, 4, 2)
-
- entries = project_ci_feature_usages.order('project_id ASC, default_branch DESC')
-
- expect(entries.count).to eq(3)
- expect(entries[0]).to have_attributes(project_id: project_1.id, feature: 1, default_branch: true)
- expect(entries[1]).to have_attributes(project_id: project_2.id, feature: 1, default_branch: true)
- expect(entries[2]).to have_attributes(project_id: project_2.id, feature: 1, default_branch: false)
- end
-
- context 'when an entry for the project and default branch combination already exists' do
- before do
- subject.perform(1, 4, 2)
- end
-
- it 'does not create a new entry' do
- expect { subject.perform(1, 4, 2) }.not_to change { project_ci_feature_usages.count }
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/backfill_user_details_fields_spec.rb b/spec/lib/gitlab/background_migration/backfill_user_details_fields_spec.rb
new file mode 100644
index 00000000000..04ada1703bc
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/backfill_user_details_fields_spec.rb
@@ -0,0 +1,222 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::BackfillUserDetailsFields, :migration, schema: 20221018232820 do
+ let(:users) { table(:users) }
+ let(:user_details) { table(:user_details) }
+
+ let!(:user_all_fields_backfill) do
+ users.create!(
+ name: generate(:name),
+ email: generate(:email),
+ projects_limit: 1,
+ linkedin: 'linked-in',
+ twitter: '@twitter',
+ skype: 'skype',
+ website_url: 'https://example.com',
+ location: 'Antarctica',
+ organization: 'Gitlab'
+ )
+ end
+
+ let!(:user_long_details_fields) do
+ length = UserDetail::DEFAULT_FIELD_LENGTH + 1
+ users.create!(
+ name: generate(:name),
+ email: generate(:email),
+ projects_limit: 1,
+ linkedin: 'l' * length,
+ twitter: 't' * length,
+ skype: 's' * length,
+ website_url: "https://#{'a' * (length - 12)}.com",
+ location: 'l' * length,
+ organization: 'o' * length
+ )
+ end
+
+ let!(:user_nil_details_fields) do
+ users.create!(
+ name: generate(:name),
+ email: generate(:email),
+ projects_limit: 1
+ )
+ end
+
+ let!(:user_empty_details_fields) do
+ users.create!(
+ name: generate(:name),
+ email: generate(:email),
+ projects_limit: 1,
+ linkedin: '',
+ twitter: '',
+ skype: '',
+ website_url: '',
+ location: '',
+ organization: ''
+ )
+ end
+
+ let!(:user_with_bio) do
+ users.create!(
+ name: generate(:name),
+ email: generate(:email),
+ projects_limit: 1,
+ linkedin: 'linked-in',
+ twitter: '@twitter',
+ skype: 'skype',
+ website_url: 'https://example.com',
+ location: 'Antarctica',
+ organization: 'Gitlab'
+ )
+ end
+
+ let!(:bio_user_details) do
+ user_details
+ .find_or_create_by!(user_id: user_with_bio.id)
+ .update!(bio: 'bio')
+ end
+
+ let!(:user_with_details) do
+ users.create!(
+ name: generate(:name),
+ email: generate(:email),
+ projects_limit: 1,
+ linkedin: 'linked-in',
+ twitter: '@twitter',
+ skype: 'skype',
+ website_url: 'https://example.com',
+ location: 'Antarctica',
+ organization: 'Gitlab'
+ )
+ end
+
+ let!(:existing_user_details) do
+ user_details
+ .find_or_create_by!(user_id: user_with_details.id)
+ .update!(
+ linkedin: 'linked-in',
+ twitter: '@twitter',
+ skype: 'skype',
+ website_url: 'https://example.com',
+ location: 'Antarctica',
+ organization: 'Gitlab'
+ )
+ end
+
+ let!(:user_different_details) do
+ users.create!(
+ name: generate(:name),
+ email: generate(:email),
+ projects_limit: 1,
+ linkedin: 'linked-in',
+ twitter: '@twitter',
+ skype: 'skype',
+ website_url: 'https://example.com',
+ location: 'Antarctica',
+ organization: 'Gitlab'
+ )
+ end
+
+ let!(:differing_details) do
+ user_details
+ .find_or_create_by!(user_id: user_different_details.id)
+ .update!(
+ linkedin: 'details-in',
+ twitter: '@details',
+ skype: 'details_skype',
+ website_url: 'https://details.site',
+ location: 'Details Location',
+ organization: 'Details Organization'
+ )
+ end
+
+ let(:user_ids) do
+ [
+ user_all_fields_backfill,
+ user_long_details_fields,
+ user_nil_details_fields,
+ user_empty_details_fields,
+ user_with_bio,
+ user_with_details,
+ user_different_details
+ ].map(&:id)
+ end
+
+ subject do
+ described_class.new(
+ start_id: user_ids.min,
+ end_id: user_ids.max,
+ batch_table: 'users',
+ batch_column: 'id',
+ sub_batch_size: 1_000,
+ pause_ms: 0,
+ connection: ApplicationRecord.connection
+ )
+ end
+
+ it 'processes all relevant records' do
+ expect { subject.perform }.to change { user_details.all.size }.to(5)
+ end
+
+ it 'backfills new user_details fields' do
+ subject.perform
+
+ user_detail = user_details.find_by!(user_id: user_all_fields_backfill.id)
+ expect(user_detail.linkedin).to eq('linked-in')
+ expect(user_detail.twitter).to eq('@twitter')
+ expect(user_detail.skype).to eq('skype')
+ expect(user_detail.website_url).to eq('https://example.com')
+ expect(user_detail.location).to eq('Antarctica')
+ expect(user_detail.organization).to eq('Gitlab')
+ end
+
+ it 'does not migrate nil fields' do
+ subject.perform
+
+ expect(user_details.find_by(user_id: user_nil_details_fields)).to be_nil
+ end
+
+ it 'does not migrate empty fields' do
+ subject.perform
+
+ expect(user_details.find_by(user_id: user_empty_details_fields)).to be_nil
+ end
+
+ it 'backfills new fields without overwriting existing `bio` field' do
+ subject.perform
+
+ user_detail = user_details.find_by!(user_id: user_with_bio.id)
+ expect(user_detail.bio).to eq('bio')
+ expect(user_detail.linkedin).to eq('linked-in')
+ expect(user_detail.twitter).to eq('@twitter')
+ expect(user_detail.skype).to eq('skype')
+ expect(user_detail.website_url).to eq('https://example.com')
+ expect(user_detail.location).to eq('Antarctica')
+ expect(user_detail.organization).to eq('Gitlab')
+ end
+
+ context 'when user details are unchanged' do
+ it 'does not change existing details' do
+ expect { subject.perform }.not_to change {
+ user_details.find_by!(user_id: user_with_details.id).attributes
+ }
+ end
+ end
+
+ context 'when user details are changed' do
+ it 'updates existing user details' do
+ expect { subject.perform }.to change {
+ user_details.find_by!(user_id: user_different_details.id).attributes
+ }
+
+ user_detail = user_details.find_by!(user_id: user_different_details.id)
+ expect(user_detail.linkedin).to eq('linked-in')
+ expect(user_detail.twitter).to eq('@twitter')
+ expect(user_detail.skype).to eq('skype')
+ expect(user_detail.website_url).to eq('https://example.com')
+ expect(user_detail.location).to eq('Antarctica')
+ expect(user_detail.organization).to eq('Gitlab')
+ 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 f03f90ddbbb..95be14cefb1 100644
--- a/spec/lib/gitlab/background_migration/batched_migration_job_spec.rb
+++ b/spec/lib/gitlab/background_migration/batched_migration_job_spec.rb
@@ -57,6 +57,71 @@ RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do
end
end
+ describe '.operation_name' do
+ subject(:perform_job) { job_instance.perform }
+
+ 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,
+ job_arguments: %w(a b),
+ connection: connection)
+ end
+
+ let(:job_class) do
+ Class.new(described_class) do
+ operation_name :update_all
+ end
+ end
+
+ it 'defines method' do
+ expect(job_instance.operation_name).to eq(:update_all)
+ end
+
+ context 'when `operation_name` is not defined' do
+ let(:job_class) do
+ Class.new(described_class) do
+ def perform
+ each_sub_batch do |sub_batch|
+ sub_batch.update_all('to_column = from_column')
+ end
+ end
+ end
+ end
+
+ let(:test_table) { table(:_test_table) }
+ let(:test_insert_table) { table(:_test_insert_table) }
+
+ before do
+ allow(job_instance).to receive(:sleep)
+
+ connection.create_table :_test_table do |t|
+ t.timestamps_with_timezone null: false
+ t.integer :from_column, null: false
+ end
+
+ connection.create_table :_test_insert_table, id: false do |t|
+ t.integer :to_column
+ t.index :to_column, unique: true
+ end
+
+ test_table.create!(id: 1, from_column: 5)
+ test_table.create!(id: 2, from_column: 10)
+ end
+
+ after do
+ connection.drop_table(:_test_table)
+ connection.drop_table(:_test_insert_table)
+ end
+
+ it 'raises an exception' do
+ expect { perform_job }.to raise_error(RuntimeError, /Operation name is required/)
+ end
+ end
+ end
+
describe '.scope_to' do
subject(:job_instance) do
job_class.new(start_id: 1, end_id: 10,
@@ -133,9 +198,10 @@ RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do
context 'when the subclass uses sub-batching' do
let(:job_class) do
Class.new(described_class) do
+ operation_name :update
+
def perform(*job_arguments)
each_sub_batch(
- operation_name: :update,
batching_arguments: { order_hint: :updated_at },
batching_scope: -> (relation) { relation.where.not(bar: nil) }
) do |sub_batch|
@@ -177,10 +243,10 @@ RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do
let(:job_class) do
Class.new(described_class) do
scope_to ->(r) { r.where('mod(id, 2) = 0') }
+ operation_name :update
def perform(*job_arguments)
each_sub_batch(
- operation_name: :update,
batching_arguments: { order_hint: :updated_at },
batching_scope: -> (relation) { relation.where.not(bar: nil) }
) do |sub_batch|
@@ -237,8 +303,10 @@ RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do
let(:job_class) do
Class.new(described_class) do
+ operation_name :insert
+
def perform(*job_arguments)
- distinct_each_batch(operation_name: :insert) do |sub_batch|
+ distinct_each_batch do |sub_batch|
sub_batch.pluck(:from_column).each do |value|
connection.execute("INSERT INTO _test_insert_table VALUES (#{value})")
end
@@ -291,9 +359,10 @@ RSpec.describe Gitlab::BackgroundMigration::BatchedMigrationJob do
let(:job_class) do
Class.new(described_class) do
scope_to ->(r) { r.where.not(from_column: 10) }
+ operation_name :insert
def perform(*job_arguments)
- distinct_each_batch(operation_name: :insert) do |sub_batch|
+ distinct_each_batch do |sub_batch|
end
end
end
diff --git a/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb b/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb
index 264faa4de3b..c522c8b307f 100644
--- a/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb
+++ b/spec/lib/gitlab/background_migration/legacy_upload_mover_spec.rb
@@ -241,7 +241,7 @@ RSpec.describe Gitlab::BackgroundMigration::LegacyUploadMover, :aggregate_failur
context 'when legacy uploads are stored in object storage' do
let(:legacy_upload) { create_remote_upload(note, filename) }
let(:remote_file) do
- { key: "#{legacy_upload.path}" }
+ { key: legacy_upload.path.to_s }
end
let(:connection) { ::Fog::Storage.new(FileUploader.object_store_credentials) }
diff --git a/spec/lib/gitlab/background_migration/populate_projects_star_count_spec.rb b/spec/lib/gitlab/background_migration/populate_projects_star_count_spec.rb
new file mode 100644
index 00000000000..74f674e052d
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/populate_projects_star_count_spec.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::PopulateProjectsStarCount, schema: 20221019105041 do
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+ let(:users) { table(:users) }
+ let(:users_star_projects) { table(:users_star_projects) }
+
+ let(:namespace1) { namespaces.create!(name: 'namespace 1', path: 'namespace1') }
+ let(:namespace2) { namespaces.create!(name: 'namespace 2', path: 'namespace2') }
+ let(:namespace3) { namespaces.create!(name: 'namespace 3', path: 'namespace3') }
+ let(:namespace4) { namespaces.create!(name: 'namespace 4', path: 'namespace4') }
+ let(:namespace5) { namespaces.create!(name: 'namespace 5', path: 'namespace5') }
+
+ let(:project1) { projects.create!(namespace_id: namespace1.id, project_namespace_id: namespace1.id) }
+ let(:project2) { projects.create!(namespace_id: namespace2.id, project_namespace_id: namespace2.id) }
+ let(:project3) { projects.create!(namespace_id: namespace3.id, project_namespace_id: namespace3.id) }
+ let(:project4) { projects.create!(namespace_id: namespace4.id, project_namespace_id: namespace4.id) }
+ let(:project5) { projects.create!(namespace_id: namespace5.id, project_namespace_id: namespace5.id) }
+
+ let(:user_active) { users.create!(state: 'active', email: 'test1@example.com', projects_limit: 5) }
+ let(:user_blocked) { users.create!(state: 'blocked', email: 'test2@example.com', projects_limit: 5) }
+
+ let(:migration) do
+ described_class.new(
+ start_id: project1.id,
+ end_id: project4.id,
+ batch_table: :projects,
+ batch_column: :id,
+ sub_batch_size: 2,
+ pause_ms: 2,
+ connection: ApplicationRecord.connection
+ )
+ end
+
+ subject(:perform_migration) { migration.perform }
+
+ it 'correctly populates the star counters' do
+ users_star_projects.create!(project_id: project1.id, user_id: user_active.id)
+ users_star_projects.create!(project_id: project2.id, user_id: user_blocked.id)
+ users_star_projects.create!(project_id: project4.id, user_id: user_active.id)
+ users_star_projects.create!(project_id: project4.id, user_id: user_blocked.id)
+ users_star_projects.create!(project_id: project5.id, user_id: user_active.id)
+
+ perform_migration
+
+ expect(project1.reload.star_count).to eq(1)
+ expect(project2.reload.star_count).to eq(0)
+ expect(project3.reload.star_count).to eq(0)
+ expect(project4.reload.star_count).to eq(1)
+ expect(project5.reload.star_count).to eq(0)
+ end
+
+ context 'when database timeouts' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(error_class: [ActiveRecord::StatementTimeout, ActiveRecord::QueryCanceled])
+
+ with_them do
+ it 'retries on timeout error' do
+ expect(migration).to receive(:update_batch).exactly(3).times.and_raise(error_class)
+ expect(migration).to receive(:sleep).with(5).twice
+
+ expect do
+ perform_migration
+ end.to raise_error(error_class)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/populate_vulnerability_reads_spec.rb b/spec/lib/gitlab/background_migration/populate_vulnerability_reads_spec.rb
index 3de84a4e880..fc06012ed20 100644
--- a/spec/lib/gitlab/background_migration/populate_vulnerability_reads_spec.rb
+++ b/spec/lib/gitlab/background_migration/populate_vulnerability_reads_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe Gitlab::BackgroundMigration::PopulateVulnerabilityReads, :migrati
project_id: project.id,
external_type: 'uuid-v5',
external_id: 'uuid-v5',
- fingerprint: Digest::SHA1.hexdigest("#{vulnerability.id}"),
+ fingerprint: Digest::SHA1.hexdigest(vulnerability.id.to_s),
name: 'Identifier for UUIDv5')
create_finding!(
diff --git a/spec/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at_spec.rb b/spec/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at_spec.rb
index 41266cb24da..10597e65910 100644
--- a/spec/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at_spec.rb
+++ b/spec/lib/gitlab/background_migration/remove_backfilled_job_artifacts_expire_at_spec.rb
@@ -85,8 +85,9 @@ RSpec.describe Gitlab::BackgroundMigration::RemoveBackfilledJobArtifactsExpireAt
private
def create_job_artifact(id:, file_type:, expire_at:)
- job = table(:ci_builds, database: :ci).create!(id: id)
- job_artifact.create!(id: id, job_id: job.id, expire_at: expire_at, project_id: project.id, file_type: file_type)
+ job = table(:ci_builds, database: :ci).create!(id: id, partition_id: 100)
+ job_artifact.create!(id: id, job_id: job.id, expire_at: expire_at, project_id: project.id,
+ file_type: file_type, partition_id: 100)
end
end
end
diff --git a/spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values_spec.rb b/spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values_spec.rb
deleted file mode 100644
index b6da8f7fc2d..00000000000
--- a/spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values_spec.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::ResetDuplicateCiRunnersTokenEncryptedValues,
- :migration,
- schema: 20220922143634 do
- it { expect(described_class).to be < Gitlab::BackgroundMigration::BatchedMigrationJob }
-
- describe '#perform' do
- let(:ci_runners) { table(:ci_runners, database: :ci) }
-
- let(:test_worker) do
- described_class.new(
- start_id: 1,
- end_id: 4,
- batch_table: :ci_runners,
- batch_column: :id,
- sub_batch_size: 2,
- pause_ms: 0,
- connection: Ci::ApplicationRecord.connection
- )
- end
-
- subject(:perform) { test_worker.perform }
-
- before do
- ci_runners.create!(id: 1, runner_type: 1, token_encrypted: 'duplicate')
- ci_runners.create!(id: 2, runner_type: 1, token_encrypted: 'a-token')
- ci_runners.create!(id: 3, runner_type: 1, token_encrypted: 'duplicate-2')
- ci_runners.create!(id: 4, runner_type: 1, token_encrypted: nil)
- ci_runners.create!(id: 5, runner_type: 1, token_encrypted: 'duplicate-2')
- ci_runners.create!(id: 6, runner_type: 1, token_encrypted: 'duplicate')
- ci_runners.create!(id: 7, runner_type: 1, token_encrypted: 'another-token')
- ci_runners.create!(id: 8, runner_type: 1, token_encrypted: 'another-token')
- end
-
- it 'nullifies duplicate encrypted tokens', :aggregate_failures do
- expect { perform }.to change { ci_runners.all.order(:id).pluck(:id, :token_encrypted).to_h }
- .from(
- {
- 1 => 'duplicate',
- 2 => 'a-token',
- 3 => 'duplicate-2',
- 4 => nil,
- 5 => 'duplicate-2',
- 6 => 'duplicate',
- 7 => 'another-token',
- 8 => 'another-token'
- }
- )
- .to(
- {
- 1 => nil,
- 2 => 'a-token',
- 3 => nil,
- 4 => nil,
- 5 => nil,
- 6 => nil,
- 7 => 'another-token',
- 8 => 'another-token'
- }
- )
- expect(ci_runners.count).to eq(8)
- expect(ci_runners.pluck(:token_encrypted).uniq).to match_array [
- nil, 'a-token', 'another-token'
- ]
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values_spec.rb b/spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values_spec.rb
deleted file mode 100644
index 423b1815e75..00000000000
--- a/spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values_spec.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::BackgroundMigration::ResetDuplicateCiRunnersTokenValues,
- :migration,
- schema: 20220922143143 do
- it { expect(described_class).to be < Gitlab::BackgroundMigration::BatchedMigrationJob }
-
- describe '#perform' do
- let(:ci_runners) { table(:ci_runners, database: :ci) }
-
- let(:test_worker) do
- described_class.new(
- start_id: 1,
- end_id: 4,
- batch_table: :ci_runners,
- batch_column: :id,
- sub_batch_size: 2,
- pause_ms: 0,
- connection: Ci::ApplicationRecord.connection
- )
- end
-
- subject(:perform) { test_worker.perform }
-
- before do
- ci_runners.create!(id: 1, runner_type: 1, token: 'duplicate')
- ci_runners.create!(id: 2, runner_type: 1, token: 'a-token')
- ci_runners.create!(id: 3, runner_type: 1, token: 'duplicate-2')
- ci_runners.create!(id: 4, runner_type: 1, token: nil)
- ci_runners.create!(id: 5, runner_type: 1, token: 'duplicate-2')
- ci_runners.create!(id: 6, runner_type: 1, token: 'duplicate')
- ci_runners.create!(id: 7, runner_type: 1, token: 'another-token')
- ci_runners.create!(id: 8, runner_type: 1, token: 'another-token')
- end
-
- it 'nullifies duplicate tokens', :aggregate_failures do
- expect { perform }.to change { ci_runners.all.order(:id).pluck(:id, :token).to_h }
- .from(
- {
- 1 => 'duplicate',
- 2 => 'a-token',
- 3 => 'duplicate-2',
- 4 => nil,
- 5 => 'duplicate-2',
- 6 => 'duplicate',
- 7 => 'another-token',
- 8 => 'another-token'
- }
- )
- .to(
- {
- 1 => nil,
- 2 => 'a-token',
- 3 => nil,
- 4 => nil,
- 5 => nil,
- 6 => nil,
- 7 => 'another-token',
- 8 => 'another-token'
- }
- )
- expect(ci_runners.count).to eq(8)
- expect(ci_runners.pluck(:token).uniq).to match_array [
- nil, 'a-token', 'another-token'
- ]
- end
- end
-end
diff --git a/spec/lib/gitlab/background_migration/sanitize_confidential_todos_spec.rb b/spec/lib/gitlab/background_migration/sanitize_confidential_todos_spec.rb
new file mode 100644
index 00000000000..2c5c47e39c9
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/sanitize_confidential_todos_spec.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::BackgroundMigration::SanitizeConfidentialTodos, :migration, schema: 20221110045406 do
+ let(:todos) { table(:todos) }
+ let(:notes) { table(:notes) }
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+ let(:project_features) { table(:project_features) }
+ let(:users) { table(:users) }
+ let(:issues) { table(:issues) }
+ let(:members) { table(:members) }
+ let(:project_authorizations) { table(:project_authorizations) }
+
+ let(:user) { users.create!(first_name: 'Test', last_name: 'User', email: 'test@user.com', projects_limit: 1) }
+ let(:project_namespace1) { namespaces.create!(path: 'pns1', name: 'pns1') }
+ let(:project_namespace2) { namespaces.create!(path: 'pns2', name: 'pns2') }
+
+ let(:project1) do
+ projects.create!(namespace_id: project_namespace1.id,
+ project_namespace_id: project_namespace1.id, visibility_level: 20)
+ end
+
+ let(:project2) do
+ projects.create!(namespace_id: project_namespace2.id,
+ project_namespace_id: project_namespace2.id)
+ end
+
+ let(:issue1) { issues.create!(project_id: project1.id, issue_type: 1, title: 'issue1', author_id: user.id) }
+ let(:issue2) { issues.create!(project_id: project2.id, issue_type: 1, title: 'issue2') }
+
+ let(:public_note) { notes.create!(note: 'text', project_id: project1.id) }
+
+ let(:confidential_note) do
+ notes.create!(note: 'text', project_id: project1.id, confidential: true,
+ noteable_id: issue1.id, noteable_type: 'Issue')
+ end
+
+ let(:other_confidential_note) do
+ notes.create!(note: 'text', project_id: project2.id, confidential: true,
+ noteable_id: issue2.id, noteable_type: 'Issue')
+ end
+
+ let(:common_params) { { user_id: user.id, author_id: user.id, action: 1, state: 'pending', target_type: 'Note' } }
+ let!(:ignored_todo1) { todos.create!(**common_params) }
+ let!(:ignored_todo2) { todos.create!(**common_params, target_id: public_note.id, note_id: public_note.id) }
+ let!(:valid_todo) { todos.create!(**common_params, target_id: confidential_note.id, note_id: confidential_note.id) }
+ let!(:invalid_todo) do
+ todos.create!(**common_params, target_id: other_confidential_note.id, note_id: other_confidential_note.id)
+ end
+
+ describe '#perform' do
+ before do
+ project_features.create!(project_id: project1.id, issues_access_level: 20, pages_access_level: 20)
+ members.create!(state: 0, source_id: project1.id, source_type: 'Project',
+ type: 'ProjectMember', user_id: user.id, access_level: 50, notification_level: 0,
+ member_namespace_id: project_namespace1.id)
+ project_authorizations.create!(project_id: project1.id, user_id: user.id, access_level: 50)
+ end
+
+ subject(:perform) do
+ described_class.new(
+ start_id: notes.minimum(:id),
+ end_id: notes.maximum(:id),
+ batch_table: :notes,
+ batch_column: :id,
+ sub_batch_size: 1,
+ pause_ms: 0,
+ connection: ApplicationRecord.connection
+ ).perform
+ end
+
+ it 'deletes todos where user can not read its note and logs deletion', :aggregate_failures do
+ expect_next_instance_of(Gitlab::BackgroundMigration::Logger) do |logger|
+ expect(logger).to receive(:info).with(
+ hash_including(
+ message: "#{described_class.name} deleting invalid todo",
+ attributes: hash_including(invalid_todo.attributes.slice(:id, :user_id, :target_id, :target_type))
+ )
+ ).once
+ end
+
+ expect { perform }.to change(todos, :count).by(-1)
+
+ expect(todos.all).to match_array([ignored_todo1, ignored_todo2, valid_todo])
+ end
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/update_ci_pipeline_artifacts_unknown_locked_status_spec.rb b/spec/lib/gitlab/background_migration/update_ci_pipeline_artifacts_unknown_locked_status_spec.rb
index 98939e15952..fad10aba882 100644
--- a/spec/lib/gitlab/background_migration/update_ci_pipeline_artifacts_unknown_locked_status_spec.rb
+++ b/spec/lib/gitlab/background_migration/update_ci_pipeline_artifacts_unknown_locked_status_spec.rb
@@ -26,8 +26,8 @@ RSpec.describe Gitlab::BackgroundMigration::UpdateCiPipelineArtifactsUnknownLock
let(:locked) { 1 }
let(:unknown) { 2 }
- let(:unlocked_pipeline) { pipelines.create!(locked: unlocked) }
- let(:locked_pipeline) { pipelines.create!(locked: locked) }
+ let(:unlocked_pipeline) { pipelines.create!(locked: unlocked, partition_id: 100) }
+ let(:locked_pipeline) { pipelines.create!(locked: locked, partition_id: 100) }
# rubocop:disable Layout/LineLength
let!(:locked_artifact) { pipeline_artifacts.create!(project_id: project.id, pipeline_id: locked_pipeline.id, size: 1024, file_type: 0, file_format: 'gzip', file: 'a.gz', locked: unknown) }
diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
index 186d4e1fb42..f83ce01c617 100644
--- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb
@@ -7,7 +7,6 @@ RSpec.describe Gitlab::BitbucketImport::Importer do
before do
stub_omniauth_provider('bitbucket')
- stub_feature_flags(stricter_mr_branch_name: false)
end
let(:statuses) do
diff --git a/spec/lib/gitlab/cache/metrics_spec.rb b/spec/lib/gitlab/cache/metrics_spec.rb
new file mode 100644
index 00000000000..d8103837708
--- /dev/null
+++ b/spec/lib/gitlab/cache/metrics_spec.rb
@@ -0,0 +1,118 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Cache::Metrics do
+ subject(:metrics) do
+ described_class.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) { 'ApplicationController#show' }
+ let(:feature_category) { :source_code_management }
+ let(:backing_resource) { :unknown }
+
+ let(:counter_mock) { instance_double(Prometheus::Client::Counter) }
+
+ before do
+ allow(Gitlab::Metrics).to receive(:counter)
+ .with(
+ :redis_hit_miss_operations_total,
+ 'Hit/miss Redis cache counter'
+ ).and_return(counter_mock)
+ end
+
+ describe '#initialize' do
+ context 'when backing resource is not supported' do
+ let(:backing_resource) { 'foo' }
+
+ it { expect { metrics }.to raise_error(RuntimeError) }
+
+ context 'when on production' do
+ before do
+ allow(Gitlab).to receive(:dev_or_test_env?).and_return(false)
+ end
+
+ it 'does not raise an exception' do
+ expect { metrics }.not_to raise_error
+ end
+ end
+ end
+ end
+
+ describe '#increment_cache_hit' do
+ subject { metrics.increment_cache_hit }
+
+ it 'increments number of hits' do
+ expect(counter_mock)
+ .to receive(:increment)
+ .with(
+ {
+ caller_id: caller_id,
+ cache_identifier: cache_identifier,
+ feature_category: feature_category,
+ backing_resource: backing_resource,
+ cache_hit: true
+ }
+ ).once
+
+ subject
+ end
+ end
+
+ describe '#increment_cache_miss' do
+ subject { metrics.increment_cache_miss }
+
+ it 'increments number of misses' do
+ expect(counter_mock)
+ .to receive(:increment)
+ .with(
+ {
+ caller_id: caller_id,
+ cache_identifier: cache_identifier,
+ feature_category: feature_category,
+ backing_resource: backing_resource,
+ cache_hit: false
+ }
+ ).once
+
+ subject
+ end
+ end
+
+ describe '#observe_cache_generation' do
+ subject do
+ metrics.observe_cache_generation { action }
+ end
+
+ let(:action) { 'action' }
+ let(:histogram_mock) { instance_double(Prometheus::Client::Histogram) }
+
+ before do
+ allow(Gitlab::Metrics::System).to receive(:monotonic_time).and_return(100.0, 500.0)
+ end
+
+ it 'updates histogram metric' do
+ expect(Gitlab::Metrics).to receive(:histogram).with(
+ :redis_cache_generation_duration_seconds,
+ 'Duration of Redis cache generation',
+ {
+ caller_id: caller_id,
+ cache_identifier: cache_identifier,
+ feature_category: feature_category,
+ backing_resource: backing_resource
+ },
+ [0, 1, 5]
+ ).and_return(histogram_mock)
+
+ expect(histogram_mock).to receive(:observe).with({}, 400.0)
+
+ is_expected.to eq(action)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/checks/lfs_integrity_spec.rb b/spec/lib/gitlab/checks/lfs_integrity_spec.rb
index 3468094ffa5..abad2bfa905 100644
--- a/spec/lib/gitlab/checks/lfs_integrity_spec.rb
+++ b/spec/lib/gitlab/checks/lfs_integrity_spec.rb
@@ -9,13 +9,26 @@ RSpec.describe Gitlab::Checks::LfsIntegrity do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:newrev) do
- operations = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- BareRepoOperations.new(repository.path)
- end
+ newrev = repository.commit_files(
+ project.creator,
+ branch_name: 'lfs_integrity_spec',
+ message: 'New LFS objects',
+ actions: [{
+ action: :create,
+ file_path: 'files/lfs/some.iso',
+ content: <<~LFS
+ version https://git-lfs.github.com/spec/v1
+ oid sha256:91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897
+ size 1575078
+ LFS
+ }]
+ )
# Create a commit not pointed at by any ref to emulate being in the
# pre-receive hook so that `--not --all` returns some objects
- operations.commit_tree('8856a329dd38ca86dfb9ce5aa58a16d88cc119bd', "New LFS objects")
+ repository.delete_branch('lfs_integrity_spec')
+
+ newrev
end
let(:newrevs) { [newrev] }
diff --git a/spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb b/spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb
index f9ebab149a5..647653f8e9e 100644
--- a/spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb
+++ b/spec/lib/gitlab/ci/build/rules/rule/clause/exists_spec.rb
@@ -4,11 +4,37 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Build::Rules::Rule::Clause::Exists do
describe '#satisfied_by?' do
- shared_examples 'an exists rule with a context' do
+ subject(:satisfied_by?) { described_class.new(globs).satisfied_by?(nil, context) }
+
+ shared_examples 'a rules:exists with a context' do
it_behaves_like 'a glob matching rule' do
let(:project) { create(:project, :custom_repo, files: files) }
end
+ context 'when the rules:exists has a variable' do
+ let_it_be(:project) { create(:project, :custom_repo, files: { 'helm/helm_file.txt' => '' }) }
+
+ let(:globs) { ['$HELM_DIR/**/*'] }
+
+ let(:variables_hash) do
+ { 'HELM_DIR' => 'helm' }
+ end
+
+ before do
+ allow(context).to receive(:variables_hash).and_return(variables_hash)
+ end
+
+ context 'when the context has the specified variables' do
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when variable expansion does not match' do
+ let(:variables_hash) { {} }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
context 'after pattern comparision limit is reached' do
let(:globs) { ['*definitely_not_a_matching_glob*'] }
let(:project) { create(:project, :repository) }
@@ -22,26 +48,24 @@ RSpec.describe Gitlab::Ci::Build::Rules::Rule::Clause::Exists do
end
end
- subject(:satisfied_by?) { described_class.new(globs).satisfied_by?(nil, context) }
-
- context 'when context is Build::Context::Build' do
- it_behaves_like 'an exists rule with a context' do
+ context 'when the rules are being evaluated at job level' do
+ it_behaves_like 'a rules:exists with a context' do
let(:pipeline) { build(:ci_pipeline, project: project, sha: project.repository.commit.sha) }
let(:context) { Gitlab::Ci::Build::Context::Build.new(pipeline, sha: project.repository.commit.sha) }
end
end
- context 'when context is Build::Context::Global' do
- it_behaves_like 'an exists rule with a context' do
+ context 'when the rules are being evaluated for an entire pipeline' do
+ it_behaves_like 'a rules:exists with a context' do
let(:pipeline) { build(:ci_pipeline, project: project, sha: project.repository.commit.sha) }
let(:context) { Gitlab::Ci::Build::Context::Global.new(pipeline, yaml_variables: {}) }
end
end
- context 'when context is Config::External::Context' do
+ context 'when rules are being evaluated with `include`' do
let(:context) { Gitlab::Ci::Config::External::Context.new(project: project, sha: sha) }
- it_behaves_like 'an exists rule with a context' do
+ it_behaves_like 'a rules:exists with a context' do
let(:sha) { project.repository.commit.sha }
end
diff --git a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
index c56f2d25074..8da46561b73 100644
--- a/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/bridge_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Gitlab::Ci::Config::Entry::Bridge do
- subject { described_class.new(config, name: :my_bridge) }
+ subject(:entry) { described_class.new(config, name: :my_bridge) }
it_behaves_like 'with inheritable CI config' do
let(:inheritable_key) { 'default' }
@@ -380,4 +380,38 @@ RSpec.describe Gitlab::Ci::Config::Entry::Bridge do
end
end
end
+
+ describe '#when' do
+ context 'when bridge is a manual action' do
+ let(:config) { { script: 'deploy', when: 'manual' } }
+
+ it { expect(entry.when).to eq('manual') }
+ end
+
+ context 'when bridge has no `when` attribute' do
+ let(:config) { { script: 'deploy' } }
+
+ it { expect(entry.when).to be_nil }
+ end
+
+ context 'when the `when` keyword is not a string' do
+ context 'when it is an array' do
+ let(:config) { { script: 'exit 0', when: ['always'] } }
+
+ it 'returns error' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include 'bridge when should be a string'
+ end
+ end
+
+ context 'when it is a boolean' do
+ let(:config) { { script: 'exit 0', when: true } }
+
+ it 'returns error' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include 'bridge when should be a string'
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index 75ac2ca87ab..acf60a6cdda 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -317,6 +317,26 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
end
end
+ context 'when the `when` keyword is not a string' do
+ context 'when it is an array' do
+ let(:config) { { script: 'exit 0', when: ['always'] } }
+
+ it 'returns error' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include 'job when should be a string'
+ end
+ end
+
+ context 'when it is a boolean' do
+ let(:config) { { script: 'exit 0', when: true } }
+
+ it 'returns error' do
+ expect(entry).not_to be_valid
+ expect(entry.errors).to include 'job when should be a string'
+ end
+ end
+ end
+
context 'when only: is used with rules:' do
let(:config) { { only: ['merge_requests'], rules: [{ if: '$THIS' }] } }
@@ -653,7 +673,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
with_them do
let(:config) { { script: 'ls', rules: rules, only: only }.compact }
- it "#{name}" do
+ it name.to_s do
expect(workflow).to receive(:has_rules?) { has_workflow_rules? }
entry.compose!(deps)
diff --git a/spec/lib/gitlab/ci/config/entry/processable_spec.rb b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
index ad90dd59585..f1578a068b9 100644
--- a/spec/lib/gitlab/ci/config/entry/processable_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/processable_spec.rb
@@ -208,7 +208,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do
it 'reports error about variable' do
expect(entry.errors)
- .to include 'variables:var2 config must be a string'
+ .to include 'variables:var2 config uses invalid data keys: description'
end
end
end
@@ -248,7 +248,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do
with_them do
let(:config) { { script: 'ls', rules: rules, only: only }.compact }
- it "#{name}" do
+ it name.to_s do
expect(workflow).to receive(:has_rules?) { has_workflow_rules? }
entry.compose!(deps)
@@ -447,6 +447,29 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do
)
end
end
+
+ context 'when variables have "expand" data' do
+ let(:config) do
+ {
+ script: 'echo',
+ variables: { 'VAR1' => 'val 1',
+ 'VAR2' => { value: 'val 2', expand: false },
+ 'VAR3' => { value: 'val 3', expand: true } }
+ }
+ end
+
+ it 'returns correct value' do
+ expect(entry.value).to eq(
+ name: :rspec,
+ stage: 'test',
+ only: { refs: %w[branches tags] },
+ job_variables: { 'VAR1' => { value: 'val 1' },
+ 'VAR2' => { value: 'val 2', raw: true },
+ 'VAR3' => { value: 'val 3', raw: false } },
+ root_variables_inheritance: true
+ )
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/root_spec.rb b/spec/lib/gitlab/ci/config/entry/root_spec.rb
index a55e13e7c2d..085293d7368 100644
--- a/spec/lib/gitlab/ci/config/entry/root_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb
@@ -316,6 +316,35 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
end
end
end
+
+ context 'when variables have "expand" data' do
+ let(:hash) do
+ {
+ variables: { 'VAR1' => 'val 1',
+ 'VAR2' => { value: 'val 2', expand: false },
+ 'VAR3' => { value: 'val 3', expand: true } },
+ rspec: { script: 'rspec' }
+ }
+ end
+
+ before do
+ root.compose!
+ end
+
+ it 'returns correct value' do
+ expect(root.variables_entry.value_with_data).to eq(
+ 'VAR1' => { value: 'val 1' },
+ 'VAR2' => { value: 'val 2', raw: true },
+ 'VAR3' => { value: 'val 3', raw: false }
+ )
+
+ expect(root.variables_value).to eq(
+ 'VAR1' => 'val 1',
+ 'VAR2' => 'val 2',
+ 'VAR3' => 'val 3'
+ )
+ end
+ end
end
context 'when configuration is not valid' do
diff --git a/spec/lib/gitlab/ci/config/entry/variable_spec.rb b/spec/lib/gitlab/ci/config/entry/variable_spec.rb
index 076a5b32e92..d7023072312 100644
--- a/spec/lib/gitlab/ci/config/entry/variable_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/variable_spec.rb
@@ -92,6 +92,12 @@ RSpec.describe Gitlab::Ci::Config::Entry::Variable do
describe '#value_with_data' do
subject(:value_with_data) { entry.value_with_data }
+ it { is_expected.to eq(value: 'value') }
+ end
+
+ describe '#value_with_prefill_data' do
+ subject(:value_with_prefill_data) { entry.value_with_prefill_data }
+
it { is_expected.to eq(value: 'value', description: 'description') }
end
@@ -107,6 +113,12 @@ RSpec.describe Gitlab::Ci::Config::Entry::Variable do
describe '#value_with_data' do
subject(:value_with_data) { entry.value_with_data }
+ it { is_expected.to eq(value: 'value') }
+ end
+
+ describe '#value_with_prefill_data' do
+ subject(:value_with_prefill_data) { entry.value_with_prefill_data }
+
it { is_expected.to eq(value: 'value', description: 'description') }
end
end
@@ -123,6 +135,12 @@ RSpec.describe Gitlab::Ci::Config::Entry::Variable do
describe '#value_with_data' do
subject(:value_with_data) { entry.value_with_data }
+ it { is_expected.to eq(value: '123') }
+ end
+
+ describe '#value_with_prefill_data' do
+ subject(:value_with_prefill_data) { entry.value_with_prefill_data }
+
it { is_expected.to eq(value: '123', description: 'description') }
end
end
@@ -139,6 +157,12 @@ RSpec.describe Gitlab::Ci::Config::Entry::Variable do
describe '#value_with_data' do
subject(:value_with_data) { entry.value_with_data }
+ it { is_expected.to eq(value: 'value') }
+ end
+
+ describe '#value_with_prefill_data' do
+ subject(:value_with_prefill_data) { entry.value_with_prefill_data }
+
it { is_expected.to eq(value: 'value', description: :description) }
end
end
@@ -192,6 +216,94 @@ RSpec.describe Gitlab::Ci::Config::Entry::Variable do
it { is_expected.to eq(value: 'value') }
end
+
+ describe '#value_with_prefill_data' do
+ subject(:value_with_prefill_data) { entry.value_with_prefill_data }
+
+ it { is_expected.to eq(value: 'value') }
+ end
+ end
+ end
+
+ context 'when config is a hash with expand' do
+ let(:config) { { value: 'value', expand: false } }
+
+ context 'when metadata allowed_value_data is not provided' do
+ describe '#valid?' do
+ it { is_expected.not_to be_valid }
+ end
+
+ describe '#errors' do
+ subject(:errors) { entry.errors }
+
+ it { is_expected.to include 'var1 config must be a string' }
+ end
+ end
+
+ context 'when metadata allowed_value_data is (value, expand)' do
+ let(:metadata) { { allowed_value_data: %i[value expand] } }
+
+ describe '#valid?' do
+ it { is_expected.to be_valid }
+ end
+
+ describe '#value' do
+ subject(:value) { entry.value }
+
+ it { is_expected.to eq('value') }
+ end
+
+ describe '#value_with_data' do
+ subject(:value_with_data) { entry.value_with_data }
+
+ it { is_expected.to eq(value: 'value', raw: true) }
+
+ context 'when the FF ci_raw_variables_in_yaml_config is disabled' do
+ before do
+ stub_feature_flags(ci_raw_variables_in_yaml_config: false)
+ end
+
+ it { is_expected.to eq(value: 'value') }
+ end
+ end
+
+ context 'when config expand is true' do
+ let(:config) { { value: 'value', expand: true } }
+
+ describe '#value_with_data' do
+ subject(:value_with_data) { entry.value_with_data }
+
+ it { is_expected.to eq(value: 'value', raw: false) }
+ end
+ end
+
+ context 'when config expand is a string' do
+ let(:config) { { value: 'value', expand: "true" } }
+
+ describe '#valid?' do
+ it { is_expected.not_to be_valid }
+ end
+
+ describe '#errors' do
+ subject(:errors) { entry.errors }
+
+ it { is_expected.to include 'var1 config expand should be a boolean value' }
+ end
+ end
+ end
+
+ context 'when metadata allowed_value_data is (value, xyz)' do
+ let(:metadata) { { allowed_value_data: %i[value xyz] } }
+
+ describe '#valid?' do
+ it { is_expected.not_to be_valid }
+ end
+
+ describe '#errors' do
+ subject(:errors) { entry.errors }
+
+ it { is_expected.to include 'var1 config uses invalid data keys: expand' }
+ end
end
end
end
@@ -229,6 +341,12 @@ RSpec.describe Gitlab::Ci::Config::Entry::Variable do
describe '#value_with_data' do
subject(:value_with_data) { entry.value_with_data }
+ it { is_expected.to eq(value: 'value') }
+ end
+
+ describe '#value_with_prefill_data' do
+ subject(:value_with_prefill_data) { entry.value_with_prefill_data }
+
it { is_expected.to eq(value: 'value', description: 'description', value_options: %w[value value2]) }
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/variables_spec.rb b/spec/lib/gitlab/ci/config/entry/variables_spec.rb
index 085f304094e..609e4422d5c 100644
--- a/spec/lib/gitlab/ci/config/entry/variables_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/variables_spec.rb
@@ -66,6 +66,15 @@ RSpec.describe Gitlab::Ci::Config::Entry::Variables do
)
end
end
+
+ describe '#value_with_prefill_data' do
+ it 'returns variable with prefill data' do
+ expect(entry.value_with_prefill_data).to eq(
+ 'VARIABLE_1' => { value: 'value 1' },
+ 'VARIABLE_2' => { value: 'value 2' }
+ )
+ end
+ end
end
context 'with numeric keys and values in the config' do
@@ -119,6 +128,14 @@ RSpec.describe Gitlab::Ci::Config::Entry::Variables do
describe '#value_with_data' do
it 'returns variable with data' do
expect(entry.value_with_data).to eq(
+ 'VARIABLE_1' => { value: 'value' }
+ )
+ end
+ end
+
+ describe '#value_with_prefill_data' do
+ it 'returns variable with prefill data' do
+ expect(entry.value_with_prefill_data).to eq(
'VARIABLE_1' => { value: 'value', description: 'variable 1' }
)
end
@@ -147,6 +164,14 @@ RSpec.describe Gitlab::Ci::Config::Entry::Variables do
describe '#value_with_data' do
it 'returns variable with data' do
expect(entry.value_with_data).to eq(
+ 'VARIABLE_1' => { value: 'value1' }
+ )
+ end
+ end
+
+ describe '#value_with_prefill_data' do
+ it 'returns variable with prefill data' do
+ expect(entry.value_with_prefill_data).to eq(
'VARIABLE_1' => { value: 'value1', value_options: %w[value1 value2], description: 'variable 1' }
)
end
@@ -174,6 +199,15 @@ RSpec.describe Gitlab::Ci::Config::Entry::Variables do
describe '#value_with_data' do
it 'returns variable with data' do
expect(entry.value_with_data).to eq(
+ 'VARIABLE_1' => { value: 'value 1' },
+ 'VARIABLE_2' => { value: 'value 2' }
+ )
+ end
+ end
+
+ describe '#value_with_prefill_data' do
+ it 'returns variable with prefill data' do
+ expect(entry.value_with_prefill_data).to eq(
'VARIABLE_1' => { value: 'value 1', description: 'variable 1' },
'VARIABLE_2' => { value: 'value 2' }
)
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 1306d61d99c..8475c3a8b19 100644
--- a/spec/lib/gitlab/ci/config/external/file/base_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/file/base_spec.rb
@@ -14,6 +14,10 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do
super
end
+
+ def validate_context!
+ # no-op
+ end
end
end
@@ -95,6 +99,24 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base do
expect(file.error_message).to eq('Included file `some/file/xxxxxxxxxxxxxxxx.yml` does not have valid YAML syntax!')
end
end
+
+ context 'when the class has no validate_context!' do
+ let(:test_class) do
+ Class.new(described_class) do
+ def initialize(params, context)
+ @location = params
+
+ super
+ end
+ end
+ end
+
+ let(:location) { 'some/file/config.yaml' }
+
+ it 'raises an error' do
+ expect { valid? }.to raise_error(NotImplementedError)
+ end
+ end
end
describe '#to_hash' do
diff --git a/spec/lib/gitlab/ci/config/external/mapper_spec.rb b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
index e12f5dcee0a..d905568f01e 100644
--- a/spec/lib/gitlab/ci/config/external/mapper_spec.rb
+++ b/spec/lib/gitlab/ci/config/external/mapper_spec.rb
@@ -113,7 +113,19 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
it_behaves_like 'logging config file fetch', 'config_file_fetch_template_content_duration_s', 1
end
- context 'when the key is a hash of file and remote' do
+ context 'when the key is not valid' do
+ let(:local_file) { 'secret-file.yml' }
+ let(:values) do
+ { include: { invalid: local_file },
+ image: 'image:1.0' }
+ end
+
+ it 'returns ambigious specification error' do
+ expect { subject }.to raise_error(described_class::AmbigiousSpecificationError, '`{"invalid":"secret-file.yml"}` does not have a valid subkey for include. Valid subkeys are: `local`, `project`, `remote`, `template`, `artifact`')
+ end
+ end
+
+ context 'when the key is a hash of local and remote' do
let(:variables) { Gitlab::Ci::Variables::Collection.new([{ 'key' => 'GITLAB_TOKEN', 'value' => 'secret-file', 'masked' => true }]) }
let(:local_file) { 'secret-file.yml' }
let(:remote_url) { 'https://gitlab.com/secret-file.yml' }
@@ -123,7 +135,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do
end
it 'returns ambigious specification error' do
- expect { subject }.to raise_error(described_class::AmbigiousSpecificationError, 'Include `{"local":"xxxxxxxxxxx.yml","remote":"https://gitlab.com/xxxxxxxxxxx.yml"}` needs to match exactly one accessor!')
+ expect { subject }.to raise_error(described_class::AmbigiousSpecificationError, 'Each include must use only one of: `local`, `project`, `remote`, `template`, `artifact`')
end
end
diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb
index 475503de7da..c4a6641ff6b 100644
--- a/spec/lib/gitlab/ci/config_spec.rb
+++ b/spec/lib/gitlab/ci/config_spec.rb
@@ -484,7 +484,7 @@ RSpec.describe Gitlab::Ci::Config do
it 'raises ConfigError' do
expect { config }.to raise_error(
described_class::ConfigError,
- 'Include `{"remote":"http://url","local":"/local/file.yml"}` needs to match exactly one accessor!'
+ /Each include must use only one of/
)
end
end
@@ -714,7 +714,7 @@ RSpec.describe Gitlab::Ci::Config do
it 'raises an error' do
expect { config }.to raise_error(
described_class::ConfigError,
- /needs to match exactly one accessor!/
+ /does not have a valid subkey for include/
)
end
end
diff --git a/spec/lib/gitlab/ci/parsers/codequality/code_climate_spec.rb b/spec/lib/gitlab/ci/parsers/codequality/code_climate_spec.rb
index 6a08e8f0b7f..1ef341ff863 100644
--- a/spec/lib/gitlab/ci/parsers/codequality/code_climate_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/codequality/code_climate_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Parsers::Codequality::CodeClimate do
describe '#parse!' do
- subject(:parse) { described_class.new.parse!(code_climate, codequality_report) }
+ subject(:parse) { described_class.new.parse!(code_climate, codequality_report, metadata) }
let(:codequality_report) { Gitlab::Ci::Reports::CodequalityReports.new }
let(:code_climate) do
@@ -35,6 +35,15 @@ RSpec.describe Gitlab::Ci::Parsers::Codequality::CodeClimate do
].to_json
end
+ let_it_be(:group) { create(:group, name: 'test-group') }
+ let_it_be(:project) { create(:project, path: 'test-project', group: group) }
+ let(:metadata) do
+ {
+ project: project,
+ commit_sha: 'f0cc5229e2aa5e9429f1b17a3b3b102f21d7fe31'
+ }
+ end
+
context "when data is code_climate style JSON" do
context "when there are no degradations" do
let(:code_climate) { [].to_json }
@@ -133,5 +142,56 @@ RSpec.describe Gitlab::Ci::Parsers::Codequality::CodeClimate do
expect(codequality_report.degradations_count).to eq(0)
end
end
+
+ context 'for web_url' do
+ let(:code_climate) do
+ [
+ {
+ "categories": [
+ "Complexity"
+ ],
+ "check_name": "argument_count",
+ "content": {
+ "body": ""
+ },
+ "description": "Method `new_array` has 12 arguments (exceeds 4 allowed). Consider refactoring.",
+ "fingerprint": "15cdb5c53afd42bc22f8ca366a08d547",
+ "location": {
+ "path": "foo.rb",
+ "lines": {
+ "begin": 10,
+ "end": 10
+ }
+ },
+ "other_locations": [],
+ "remediation_points": 900000,
+ "severity": "major",
+ "type": "issue",
+ "engine_name": "structure"
+ }
+ ].to_json
+ end
+
+ context 'when metadata has project and commit_sha' do
+ it 'adds a non nil url' do
+ want = 'http://localhost/test-group/test-project/-/blob/f0cc5229e2aa5e9429f1b17a3b3b102f21d7fe31/foo.rb#L10'
+ expect { parse }.not_to raise_error
+
+ expect(codequality_report.degradations_count).to eq(1)
+ expect(codequality_report.all_degradations[0]['web_url']).to eq(want)
+ end
+ end
+
+ context 'when metadata does not have project and commit_sha' do
+ let(:metadata) { {} }
+
+ it 'adds a nil url' do
+ expect { parse }.not_to raise_error
+
+ expect(codequality_report.degradations_count).to eq(1)
+ expect(codequality_report.all_degradations[0]['web_url']).to be_nil
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/parsers/coverage/sax_document_spec.rb b/spec/lib/gitlab/ci/parsers/coverage/sax_document_spec.rb
index a9851d78f48..e4ae6b25362 100644
--- a/spec/lib/gitlab/ci/parsers/coverage/sax_document_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/coverage/sax_document_spec.rb
@@ -8,6 +8,7 @@ RSpec.describe Gitlab::Ci::Parsers::Coverage::SaxDocument do
describe '#parse!' do
let(:coverage_report) { Gitlab::Ci::Reports::CoverageReport.new }
let(:project_path) { 'foo/bar' }
+ let(:windows_path) { 'foo\bar' }
let(:paths) { ['app/user.rb'] }
let(:cobertura) do
@@ -269,6 +270,36 @@ RSpec.describe Gitlab::Ci::Parsers::Coverage::SaxDocument do
it_behaves_like 'ignoring sources, project_path, and worktree_paths'
end
+ context 'and has Windows-style paths' do
+ let(:sources_xml) do
+ <<~EOF_WIN
+ <sources>
+ <source>D:\\builds\\#{windows_path}\\app</source>
+ </sources>
+ EOF_WIN
+ end
+
+ context 'when there is a single <class>' do
+ context 'with a single line' do
+ let(:classes_xml) do
+ <<~EOF
+ <packages><package name="app"><classes>
+ <class filename="user.rb"><lines>
+ <line number="1" hits="2"/>
+ </lines></class>
+ </classes></package></packages>
+ EOF
+ end
+
+ it 'parses XML and returns a single file with the filename relative to project root' do
+ expect { parse_report }.not_to raise_error
+
+ expect(coverage_report.files).to eq({ 'app/user.rb' => { 1 => 2 } })
+ end
+ end
+ end
+ end
+
context 'and has multiple sources with a pattern for Go projects' do
let(:project_path) { 'local/go' } # Make sure we're not making false positives
let(:sources_xml) do
diff --git a/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_properties_spec.rb b/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_properties_spec.rb
index 38b229e0dd8..f09b85aa2c7 100644
--- a/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_properties_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_properties_spec.rb
@@ -3,7 +3,7 @@
require 'fast_spec_helper'
RSpec.describe Gitlab::Ci::Parsers::Sbom::CyclonedxProperties do
- subject(:parse_source) { described_class.parse_source(properties) }
+ subject(:parse_source_from_properties) { described_class.parse_source(properties) }
context 'when properties are nil' do
let(:properties) { nil }
@@ -50,9 +50,9 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::CyclonedxProperties do
end
it 'does not call dependency_scanning parser' do
- expect(Gitlab::Ci::Parsers::Sbom::Source::DependencyScanning).not_to receive(:parse_source)
+ expect(Gitlab::Ci::Parsers::Sbom::Source::DependencyScanning).not_to receive(:source)
- parse_source
+ parse_source_from_properties
end
end
@@ -82,7 +82,7 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::CyclonedxProperties do
it 'passes only supported properties to the dependency scanning parser' do
expect(Gitlab::Ci::Parsers::Sbom::Source::DependencyScanning).to receive(:source).with(expected_input)
- parse_source
+ parse_source_from_properties
end
end
end
diff --git a/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb b/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb
index f3636106b98..0b094880f69 100644
--- a/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/sbom/cyclonedx_spec.rb
@@ -100,16 +100,53 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Cyclonedx do
]
end
+ before do
+ allow(report).to receive(:add_component)
+ end
+
it 'adds each component, ignoring unused attributes' do
expect(report).to receive(:add_component)
- .with(an_object_having_attributes(name: "activesupport", version: "5.1.4", component_type: "library"))
+ .with(
+ an_object_having_attributes(
+ name: "activesupport",
+ version: "5.1.4",
+ component_type: "library",
+ purl: an_object_having_attributes(type: "gem")
+ )
+ )
expect(report).to receive(:add_component)
- .with(an_object_having_attributes(name: "byebug", version: "10.0.0", component_type: "library"))
+ .with(
+ an_object_having_attributes(
+ name: "byebug",
+ version: "10.0.0",
+ component_type: "library",
+ purl: an_object_having_attributes(type: "gem")
+ )
+ )
expect(report).to receive(:add_component)
.with(an_object_having_attributes(name: "minimal-component", version: nil, component_type: "library"))
parse!
end
+
+ context 'when a component has an invalid purl' do
+ before do
+ components.push(
+ {
+ "name" => "invalid-component",
+ "version" => "v0.0.1",
+ "purl" => "pkg:nil",
+ "type" => "library"
+ }
+ )
+ end
+
+ it 'adds an error to the report' do
+ expect(report).to receive(:add_error).with("/components/#{components.size - 1}/purl is invalid")
+
+ parse!
+ end
+ end
end
context 'when report has metadata properties' do
diff --git a/spec/lib/gitlab/ci/parsers/security/common_spec.rb b/spec/lib/gitlab/ci/parsers/security/common_spec.rb
index 7dbad354e4c..03cab021c17 100644
--- a/spec/lib/gitlab/ci/parsers/security/common_spec.rb
+++ b/spec/lib/gitlab/ci/parsers/security/common_spec.rb
@@ -400,26 +400,7 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do
end
describe 'parsing tracking' do
- let(:tracking_data) do
- {
- 'type' => 'source',
- 'items' => [
- 'signatures' => [
- { 'algorithm' => 'hash', 'value' => 'hash_value' },
- { 'algorithm' => 'location', 'value' => 'location_value' },
- { 'algorithm' => 'scope_offset', 'value' => 'scope_offset_value' }
- ]
- ]
- }
- end
-
- context 'with valid tracking information' do
- it 'creates signatures for each algorithm' do
- finding = report.findings.first
- expect(finding.signatures.size).to eq(3)
- expect(finding.signatures.map(&:algorithm_type).to_set).to eq(Set['hash', 'location', 'scope_offset'])
- end
- end
+ let(:finding) { report.findings.first }
context 'with invalid tracking information' do
let(:tracking_data) do
@@ -436,15 +417,26 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do
end
it 'ignores invalid algorithm types' do
- finding = report.findings.first
expect(finding.signatures.size).to eq(2)
expect(finding.signatures.map(&:algorithm_type).to_set).to eq(Set['hash', 'location'])
end
end
context 'with valid tracking information' do
+ let(:tracking_data) do
+ {
+ 'type' => 'source',
+ 'items' => [
+ 'signatures' => [
+ { 'algorithm' => 'hash', 'value' => 'hash_value' },
+ { 'algorithm' => 'location', 'value' => 'location_value' },
+ { 'algorithm' => 'scope_offset', 'value' => 'scope_offset_value' }
+ ]
+ ]
+ }
+ end
+
it 'creates signatures for each signature algorithm' do
- finding = report.findings.first
expect(finding.signatures.size).to eq(3)
expect(finding.signatures.map(&:algorithm_type)).to eq(%w[hash location scope_offset])
@@ -456,7 +448,6 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common do
end
it 'sets the uuid according to the higest priority signature' do
- finding = report.findings.first
highest_signature = finding.signatures.max_by(&:priority)
identifiers = if signatures_enabled
diff --git a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
index 6e8b6e40928..9126c6dab21 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb
@@ -409,4 +409,21 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Command do
end
end
end
+
+ describe '#observe_pipeline_size' do
+ let(:command) { described_class.new(project: project) }
+
+ let(:pipeline) { instance_double(Ci::Pipeline, total_size: 5, project: project, source: "schedule") }
+
+ it 'logs the pipeline total size to histogram' do
+ histogram = instance_double(Prometheus::Client::Histogram)
+
+ expect(::Gitlab::Ci::Pipeline::Metrics).to receive(:pipeline_size_histogram)
+ .and_return(histogram)
+ expect(histogram).to receive(:observe)
+ .with({ source: pipeline.source, plan: project.actual_plan_name }, pipeline.total_size)
+
+ command.observe_pipeline_size(pipeline)
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/limit/active_jobs_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/limit/active_jobs_spec.rb
index bc453f1502b..c5a5e905d17 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/limit/active_jobs_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/limit/active_jobs_spec.rb
@@ -69,7 +69,9 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Chain::Limit::ActiveJobs do
class: described_class.name,
message: described_class::MESSAGE,
project_id: project.id,
- plan: default_plan.name
+ plan: default_plan.name,
+ project_path: project.path,
+ jobs_in_alive_pipelines_count: step.send(:count_jobs_in_alive_pipelines)
)
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb
new file mode 100644
index 00000000000..ce1ee2fcda0
--- /dev/null
+++ b/spec/lib/gitlab/ci/pipeline/chain/populate_metadata_spec.rb
@@ -0,0 +1,136 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Pipeline::Chain::PopulateMetadata do
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+
+ let(:pipeline) do
+ build(:ci_pipeline, project: project, ref: 'master', user: user)
+ end
+
+ let(:command) do
+ Gitlab::Ci::Pipeline::Chain::Command.new(
+ project: project,
+ current_user: user,
+ origin_ref: 'master')
+ end
+
+ let(:dependencies) do
+ [
+ Gitlab::Ci::Pipeline::Chain::Config::Content.new(pipeline, command),
+ Gitlab::Ci::Pipeline::Chain::Config::Process.new(pipeline, command),
+ Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules.new(pipeline, command),
+ Gitlab::Ci::Pipeline::Chain::SeedBlock.new(pipeline, command),
+ Gitlab::Ci::Pipeline::Chain::Seed.new(pipeline, command),
+ Gitlab::Ci::Pipeline::Chain::Populate.new(pipeline, command)
+ ]
+ end
+
+ let(:step) { described_class.new(pipeline, command) }
+
+ let(:config) do
+ { rspec: { script: 'rspec' } }
+ end
+
+ def run_chain
+ dependencies.map(&:perform!)
+ step.perform!
+ end
+
+ before do
+ stub_ci_pipeline_yaml_file(YAML.dump(config))
+ end
+
+ context 'with pipeline name' do
+ let(:config) do
+ { workflow: { name: ' Pipeline name ' }, rspec: { script: 'rspec' } }
+ end
+
+ it 'does not break the chain' do
+ run_chain
+
+ expect(step.break?).to be false
+ end
+
+ context 'with feature flag disabled' do
+ before do
+ stub_feature_flags(pipeline_name: false)
+ end
+
+ it 'does not build pipeline_metadata' do
+ run_chain
+
+ expect(pipeline.pipeline_metadata).to be_nil
+ end
+ end
+
+ context 'with feature flag enabled' do
+ before do
+ stub_feature_flags(pipeline_name: true)
+ end
+
+ it 'builds pipeline_metadata' do
+ run_chain
+
+ expect(pipeline.pipeline_metadata.name).to eq('Pipeline name')
+ expect(pipeline.pipeline_metadata.project).to eq(pipeline.project)
+ expect(pipeline.pipeline_metadata).not_to be_persisted
+ end
+
+ context 'with empty name' do
+ let(:config) do
+ { workflow: { name: ' ' }, rspec: { script: 'rspec' } }
+ end
+
+ it 'strips whitespace from name' do
+ run_chain
+
+ expect(pipeline.pipeline_metadata).to be_nil
+ end
+ end
+
+ context 'with variables' do
+ let(:config) do
+ {
+ variables: { ROOT_VAR: 'value $WORKFLOW_VAR1' },
+ workflow: {
+ name: 'Pipeline $ROOT_VAR $WORKFLOW_VAR2 $UNKNOWN_VAR',
+ rules: [{ variables: { WORKFLOW_VAR1: 'value1', WORKFLOW_VAR2: 'value2' } }]
+ },
+ rspec: { script: 'rspec' }
+ }
+ end
+
+ it 'substitutes variables' do
+ run_chain
+
+ expect(pipeline.pipeline_metadata.name).to eq('Pipeline value value1 value2 ')
+ end
+ end
+
+ context 'with invalid name' do
+ let(:config) do
+ {
+ variables: { ROOT_VAR: 'a' * 256 },
+ workflow: {
+ name: 'Pipeline $ROOT_VAR'
+ },
+ rspec: { script: 'rspec' }
+ }
+ end
+
+ it 'returns error and breaks chain' do
+ ret = run_chain
+
+ expect(ret)
+ .to match_array(["Failed to build pipeline metadata! Name is too long (maximum is 255 characters)"])
+ expect(pipeline.pipeline_metadata.errors.full_messages)
+ .to match_array(['Name is too long (maximum is 255 characters)'])
+ expect(step.break?).to be true
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
index 51d1661b586..62de4d2e96d 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
@@ -236,47 +236,4 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Populate do
end
end
end
-
- context 'with pipeline name' do
- let(:config) do
- { workflow: { name: ' Pipeline name ' }, rspec: { script: 'rspec' } }
- end
-
- context 'with feature flag disabled' do
- before do
- stub_feature_flags(pipeline_name: false)
- end
-
- it 'does not build pipeline_metadata' do
- run_chain
-
- expect(pipeline.pipeline_metadata).to be_nil
- end
- end
-
- context 'with feature flag enabled' do
- before do
- stub_feature_flags(pipeline_name: true)
- end
-
- it 'builds pipeline_metadata' do
- run_chain
-
- expect(pipeline.pipeline_metadata.title).to eq('Pipeline name')
- expect(pipeline.pipeline_metadata.project).to eq(pipeline.project)
- end
-
- context 'with empty name' do
- let(:config) do
- { workflow: { name: ' ' }, rspec: { script: 'rspec' } }
- end
-
- it 'strips whitespace from name' do
- run_chain
-
- expect(pipeline.pipeline_metadata).to be_nil
- end
- end
- end
- end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb
index c69aa661b05..31086f6ae4a 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb
@@ -80,7 +80,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Sequence do
subject.build!
expect(histogram).to have_received(:observe)
- .with({ source: 'push' }, 0)
+ .with({ source: 'push', plan: project.actual_plan_name }, 0)
end
describe 'active jobs by pipeline plan histogram' do
diff --git a/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb
deleted file mode 100644
index 6569ce937ac..00000000000
--- a/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb
+++ /dev/null
@@ -1,119 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Ci::Pipeline::Seed::Deployment do
- let_it_be(:project, refind: true) { create(:project, :repository) }
-
- let(:pipeline) do
- create(:ci_pipeline, project: project, sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0')
- end
-
- let(:job) { build(:ci_build, project: project, pipeline: pipeline) }
- let(:environment) { Gitlab::Ci::Pipeline::Seed::Environment.new(job).to_resource }
- let(:seed) { described_class.new(job, environment) }
- let(:attributes) { {} }
-
- before do
- job.assign_attributes(**attributes)
- end
-
- describe '#to_resource' do
- subject { seed.to_resource }
-
- context 'when job has environment attribute' do
- let(:attributes) do
- {
- environment: 'production',
- options: { environment: { name: 'production', **kubernetes_options } }
- }
- end
-
- let(:kubernetes_options) { {} }
-
- it 'returns a deployment object with environment' do
- expect(subject).to be_a(Deployment)
- expect(subject.iid).to be_present
- expect(subject.environment.name).to eq('production')
- expect(subject.cluster).to be_nil
- expect(subject.deployment_cluster).to be_nil
- end
-
- context 'when environment has deployment platform' do
- let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project], managed: managed_cluster) }
- let(:managed_cluster) { true }
-
- it 'sets the cluster and deployment_cluster' do
- expect(subject.cluster).to eq(cluster) # until we stop double writing in 12.9: https://gitlab.com/gitlab-org/gitlab/issues/202628
- expect(subject.deployment_cluster.cluster).to eq(cluster)
- end
-
- context 'when a custom namespace is given' do
- let(:kubernetes_options) { { kubernetes: { namespace: 'the-custom-namespace' } } }
-
- context 'when cluster is managed' do
- it 'does not set the custom namespace' do
- expect(subject.deployment_cluster.kubernetes_namespace).not_to eq('the-custom-namespace')
- end
- end
-
- context 'when cluster is not managed' do
- let(:managed_cluster) { false }
-
- it 'sets the custom namespace' do
- expect(subject.deployment_cluster.kubernetes_namespace).to eq('the-custom-namespace')
- end
- end
- end
- end
-
- context 'when environment has an invalid URL' do
- let(:attributes) do
- {
- environment: '!!!',
- options: { environment: { name: '!!!' } }
- }
- end
-
- it 'returns nothing' do
- is_expected.to be_nil
- end
- end
-
- context 'when job has already deployment' do
- let(:job) { build(:ci_build, :with_deployment, project: project, environment: 'production') }
-
- it 'returns the persisted deployment' do
- is_expected.to eq(job.deployment)
- end
- end
- end
-
- context 'when job does not start environment' do
- where(:action) do
- %w(stop prepare verify access)
- end
-
- with_them do
- let(:attributes) do
- {
- environment: 'production',
- options: { environment: { name: 'production', action: action } }
- }
- end
-
- it 'returns nothing' do
- is_expected.to be_nil
- end
- end
- end
-
- context 'when job does not have environment attribute' do
- let(:attributes) { { name: 'test' } }
-
- it 'returns nothing' do
- is_expected.to be_nil
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb
deleted file mode 100644
index 2b9d8127886..00000000000
--- a/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb
+++ /dev/null
@@ -1,224 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Ci::Pipeline::Seed::Environment do
- let_it_be(:project) { create(:project) }
-
- let!(:pipeline) { create(:ci_pipeline, project: project) }
-
- let(:job) { build(:ci_build, project: project, pipeline: pipeline) }
- let(:seed) { described_class.new(job) }
- let(:attributes) { {} }
-
- before do
- job.assign_attributes(**attributes)
- end
-
- describe '#to_resource' do
- subject { seed.to_resource }
-
- shared_examples_for 'returning a correct environment' do
- let(:expected_auto_stop_in_seconds) do
- if expected_auto_stop_in
- ChronicDuration.parse(expected_auto_stop_in).seconds
- end
- end
-
- it 'returns a persisted environment object' do
- freeze_time do
- expect { subject }.to change { Environment.count }.by(1)
-
- expect(subject).to be_a(Environment)
- expect(subject).to be_persisted
- expect(subject.project).to eq(project)
- expect(subject.name).to eq(expected_environment_name)
- expect(subject.auto_stop_in).to eq(expected_auto_stop_in_seconds)
- end
- end
-
- context 'when environment has already existed' do
- let!(:environment) do
- create(:environment,
- project: project,
- name: expected_environment_name
- ).tap do |env|
- env.auto_stop_in = expected_auto_stop_in
- end
- end
-
- it 'returns the existing environment object' do
- expect { subject }.not_to change { Environment.count }
- expect { subject }.not_to change { environment.auto_stop_at }
-
- expect(subject).to be_persisted
- expect(subject).to eq(environment)
- end
- end
- end
-
- context 'when job has environment name attribute' do
- let(:environment_name) { 'production' }
- let(:expected_environment_name) { 'production' }
- let(:expected_auto_stop_in) { nil }
-
- let(:attributes) do
- {
- environment: environment_name,
- options: { environment: { name: environment_name } }
- }
- end
-
- it_behaves_like 'returning a correct environment'
-
- context 'and job environment also has an auto_stop_in attribute' do
- let(:environment_auto_stop_in) { '5 minutes' }
- let(:expected_auto_stop_in) { '5 minutes' }
-
- let(:attributes) do
- {
- environment: environment_name,
- options: {
- environment: {
- name: environment_name,
- auto_stop_in: environment_auto_stop_in
- }
- }
- }
- end
-
- it_behaves_like 'returning a correct environment'
- end
-
- context 'and job environment has an auto_stop_in variable attribute' do
- let(:environment_auto_stop_in) { '10 minutes' }
- let(:expected_auto_stop_in) { '10 minutes' }
-
- let(:attributes) do
- {
- environment: environment_name,
- options: {
- environment: {
- name: environment_name,
- auto_stop_in: '$TTL'
- }
- },
- yaml_variables: [
- { key: "TTL", value: environment_auto_stop_in, public: true }
- ]
- }
- end
-
- it_behaves_like 'returning a correct environment'
- end
- end
-
- context 'when job has deployment tier attribute' do
- let(:attributes) do
- {
- environment: 'customer-portal',
- options: {
- environment: {
- name: 'customer-portal',
- deployment_tier: deployment_tier
- }
- }
- }
- end
-
- let(:deployment_tier) { 'production' }
-
- context 'when environment has not been created yet' do
- it 'sets the specified deployment tier' do
- is_expected.to be_production
- end
-
- context 'when deployment tier is staging' do
- let(:deployment_tier) { 'staging' }
-
- it 'sets the specified deployment tier' do
- is_expected.to be_staging
- end
- end
-
- context 'when deployment tier is unknown' do
- let(:deployment_tier) { 'unknown' }
-
- it 'raises an error' do
- expect { subject }.to raise_error(ArgumentError, "'unknown' is not a valid tier")
- end
- end
- end
-
- context 'when environment has already been created' do
- before do
- create(:environment, project: project, name: 'customer-portal', tier: :staging)
- end
-
- it 'does not overwrite the specified deployment tier' do
- # This is to be updated when a deployment succeeded i.e. Deployments::UpdateEnvironmentService.
- is_expected.to be_staging
- end
- end
- end
-
- context 'when job starts a review app' do
- let(:environment_name) { 'review/$CI_COMMIT_REF_NAME' }
- let(:expected_environment_name) { "review/#{job.ref}" }
- let(:expected_auto_stop_in) { nil }
-
- let(:attributes) do
- {
- environment: environment_name,
- options: { environment: { name: environment_name } }
- }
- end
-
- it_behaves_like 'returning a correct environment'
- end
-
- context 'when job stops a review app' do
- let(:environment_name) { 'review/$CI_COMMIT_REF_NAME' }
- let(:expected_environment_name) { "review/#{job.ref}" }
- let(:expected_auto_stop_in) { nil }
-
- let(:attributes) do
- {
- environment: environment_name,
- options: { environment: { name: environment_name, action: 'stop' } }
- }
- end
-
- it_behaves_like 'returning a correct environment'
- end
-
- context 'when merge_request is provided' do
- let(:environment_name) { 'development' }
- let(:attributes) { { environment: environment_name, options: { environment: { name: environment_name } } } }
- let(:merge_request) { create(:merge_request, source_project: project) }
- let(:seed) { described_class.new(job, merge_request: merge_request) }
-
- context 'and environment does not exist' do
- let(:environment_name) { 'review/$CI_COMMIT_REF_NAME' }
-
- it 'creates an environment associated with the merge request' do
- expect { subject }.to change { Environment.count }.by(1)
-
- expect(subject.merge_request).to eq(merge_request)
- end
- end
-
- context 'and environment already exists' do
- before do
- create(:environment, project: project, name: environment_name)
- end
-
- it 'does not change the merge request associated with the environment' do
- expect { subject }.not_to change { Environment.count }
-
- expect(subject.merge_request).to be_nil
- end
- end
- end
- end
-end
diff --git a/spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb
index a76b4874eca..55980ae72a0 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb
@@ -6,7 +6,9 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Pipeline do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
- let(:seed_context) { Gitlab::Ci::Pipeline::Seed::Context.new(pipeline, root_variables: []) }
+ let(:root_variables) { [] }
+
+ let(:seed_context) { Gitlab::Ci::Pipeline::Seed::Context.new(pipeline, root_variables: root_variables) }
let(:stages_attributes) do
[
@@ -75,4 +77,12 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Pipeline do
expect(seed.deployments_count).to eq(2)
end
end
+
+ describe '#root_variables' do
+ let(:root_variables) { %w[var1 value1] }
+
+ it 'returns root_variables' do
+ expect(seed.root_variables).to eq(root_variables)
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/reports/sbom/component_spec.rb b/spec/lib/gitlab/ci/reports/sbom/component_spec.rb
index 06ea3433ef0..cdaf9354104 100644
--- a/spec/lib/gitlab/ci/reports/sbom/component_spec.rb
+++ b/spec/lib/gitlab/ci/reports/sbom/component_spec.rb
@@ -1,23 +1,67 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
RSpec.describe Gitlab::Ci::Reports::Sbom::Component do
- let(:attributes) do
- {
- type: 'library',
- name: 'component-name',
- version: 'v0.0.1'
- }
- end
+ let(:component_type) { 'library' }
+ let(:name) { 'component-name' }
+ let(:purl_type) { 'npm' }
+ let(:purl) { Sbom::PackageUrl.new(type: purl_type, name: name, version: version).to_s }
+ let(:version) { 'v0.0.1' }
- subject { described_class.new(**attributes) }
+ subject(:component) do
+ described_class.new(
+ type: component_type,
+ name: name,
+ purl: purl,
+ version: version
+ )
+ end
it 'has correct attributes' do
- expect(subject).to have_attributes(
- component_type: attributes[:type],
- name: attributes[:name],
- version: attributes[:version]
+ expect(component).to have_attributes(
+ component_type: component_type,
+ name: name,
+ purl: an_object_having_attributes(type: purl_type),
+ version: version
)
end
+
+ describe '#ingestible?' do
+ subject { component.ingestible? }
+
+ context 'when component_type is invalid' do
+ let(:component_type) { 'invalid' }
+
+ it { is_expected.to be(false) }
+ end
+
+ context 'when purl_type is invalid' do
+ let(:purl_type) { 'invalid' }
+
+ it { is_expected.to be(false) }
+ end
+
+ context 'when component_type is valid' do
+ where(:component_type) { ::Enums::Sbom.component_types.keys.map(&:to_s) }
+
+ with_them do
+ it { is_expected.to be(true) }
+ end
+ end
+
+ context 'when purl_type is valid' do
+ where(:purl_type) { ::Enums::Sbom.purl_types.keys.map(&:to_s) }
+
+ with_them do
+ it { is_expected.to be(true) }
+ end
+ end
+
+ context 'when there is no purl' do
+ let(:purl) { nil }
+
+ it { is_expected.to be(true) }
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/reports/sbom/report_spec.rb b/spec/lib/gitlab/ci/reports/sbom/report_spec.rb
index 6ffa93e5fc8..f9a83378f46 100644
--- a/spec/lib/gitlab/ci/reports/sbom/report_spec.rb
+++ b/spec/lib/gitlab/ci/reports/sbom/report_spec.rb
@@ -5,6 +5,21 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Reports::Sbom::Report do
subject(:report) { described_class.new }
+ describe '#valid?' do
+ context 'when there are no errors' do
+ it { is_expected.to be_valid }
+ end
+
+ context 'when report contains errors' do
+ before do
+ report.add_error('error1')
+ report.add_error('error2')
+ end
+
+ it { is_expected.not_to be_valid }
+ end
+ end
+
describe '#add_error' do
it 'appends errors to a list' do
report.add_error('error1')
diff --git a/spec/lib/gitlab/ci/reports/security/flag_spec.rb b/spec/lib/gitlab/ci/reports/security/flag_spec.rb
index 6ee074f7aeb..0ef8f6c75a0 100644
--- a/spec/lib/gitlab/ci/reports/security/flag_spec.rb
+++ b/spec/lib/gitlab/ci/reports/security/flag_spec.rb
@@ -29,5 +29,11 @@ RSpec.describe Gitlab::Ci::Reports::Security::Flag do
)
end
end
+
+ describe '#false_positive?' do
+ subject { security_flag.false_positive? }
+
+ it { is_expected.to be_truthy }
+ end
end
end
diff --git a/spec/lib/gitlab/ci/reports/security/reports_spec.rb b/spec/lib/gitlab/ci/reports/security/reports_spec.rb
index e240edc4a12..33f3317c655 100644
--- a/spec/lib/gitlab/ci/reports/security/reports_spec.rb
+++ b/spec/lib/gitlab/ci/reports/security/reports_spec.rb
@@ -125,6 +125,32 @@ RSpec.describe Gitlab::Ci::Reports::Security::Reports do
it { is_expected.to be(false) }
end
+
+ context 'when target_reports is not nil and reports is empty' do
+ let(:without_reports) { described_class.new(pipeline) }
+
+ subject { without_reports.violates_default_policy_against?(target_reports, vulnerabilities_allowed, severity_levels, vulnerability_states) }
+
+ before do
+ target_reports.get_report('sast', artifact).add_finding(high_severity_dast)
+ end
+
+ context 'when require_approval_on_scan_removal feature is enabled' do
+ before do
+ stub_feature_flags(require_approval_on_scan_removal: true)
+ end
+
+ it { is_expected.to be(true) }
+ end
+
+ context 'when require_approval_on_scan_removal feature is disabled' do
+ before do
+ stub_feature_flags(require_approval_on_scan_removal: false)
+ end
+
+ it { is_expected.to be(false) }
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/ci/reports/test_suite_spec.rb b/spec/lib/gitlab/ci/reports/test_suite_spec.rb
index 4a1f77bed65..05f6a8a8cb6 100644
--- a/spec/lib/gitlab/ci/reports/test_suite_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_suite_spec.rb
@@ -209,7 +209,7 @@ RSpec.describe Gitlab::Ci::Reports::TestSuite do
Gitlab::Ci::Reports::TestCase::STATUS_TYPES.each do |status_type|
describe "##{status_type}" do
- subject { test_suite.public_send("#{status_type}") }
+ subject { test_suite.public_send(status_type.to_s) }
context "when #{status_type} test case exists" do
before do
diff --git a/spec/lib/gitlab/ci/templates/5_minute_production_app_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/5_minute_production_app_ci_yaml_spec.rb
index 8204b104832..43deb465025 100644
--- a/spec/lib/gitlab/ci/templates/5_minute_production_app_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/5_minute_production_app_ci_yaml_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe '5-Minute-Production-App.gitlab-ci.yml' do
let(:default_branch) { 'master' }
let(:pipeline_branch) { default_branch }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_branch ) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
diff --git a/spec/lib/gitlab/ci/templates/AWS/deploy_ecs_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/AWS/deploy_ecs_gitlab_ci_yaml_spec.rb
index 65fd2b016ac..f2bff5ff3e0 100644
--- a/spec/lib/gitlab/ci/templates/AWS/deploy_ecs_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/AWS/deploy_ecs_gitlab_ci_yaml_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe 'Deploy-ECS.gitlab-ci.yml' do
let(:project) { create(:project, :auto_devops, :custom_repo, files: { 'README.md' => '' }) }
let(:user) { project.first_owner }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_branch ) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
let(:platform_target) { 'ECS' }
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 21052f03cb8..07cfa939623 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
@@ -3,8 +3,20 @@
require 'spec_helper'
RSpec.describe 'Jobs/Build.gitlab-ci.yml' do
+ include Ci::TemplateHelpers
+
subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('Jobs/Build') }
+ 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"
+ reference = YAML.safe_load(template.content).dig('variables', 'AUTO_BUILD_IMAGE_VERSION')
+
+ expect(public_image_exist?(registry, repository, reference)).to be true
+ end
+ end
+
describe 'the created pipeline' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
@@ -12,7 +24,7 @@ RSpec.describe 'Jobs/Build.gitlab-ci.yml' do
let(:default_branch) { 'master' }
let(:pipeline_ref) { default_branch }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_ref) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
diff --git a/spec/lib/gitlab/ci/templates/Jobs/code_quality_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Jobs/code_quality_gitlab_ci_yaml_spec.rb
index d88d9782021..16c5d7a4b6d 100644
--- a/spec/lib/gitlab/ci/templates/Jobs/code_quality_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/Jobs/code_quality_gitlab_ci_yaml_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'Jobs/Code-Quality.gitlab-ci.yml' do
let(:default_branch) { 'master' }
let(:pipeline_ref) { default_branch }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_ref) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
@@ -62,7 +62,8 @@ RSpec.describe 'Jobs/Code-Quality.gitlab-ci.yml' do
context 'on master' do
it 'has no jobs' do
- expect { pipeline }.to raise_error(Ci::CreatePipelineService::CreateError)
+ expect(build_names).to be_empty
+ expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."])
end
end
@@ -70,7 +71,8 @@ RSpec.describe 'Jobs/Code-Quality.gitlab-ci.yml' do
let(:pipeline_ref) { 'feature' }
it 'has no jobs' do
- expect { pipeline }.to raise_error(Ci::CreatePipelineService::CreateError)
+ expect(build_names).to be_empty
+ expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."])
end
end
@@ -78,7 +80,8 @@ RSpec.describe 'Jobs/Code-Quality.gitlab-ci.yml' do
let(:pipeline_ref) { 'v1.0.0' }
it 'has no jobs' do
- expect { pipeline }.to raise_error(Ci::CreatePipelineService::CreateError)
+ expect(build_names).to be_empty
+ expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."])
end
end
end
diff --git a/spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb
index b657f73fa77..acb296082b8 100644
--- a/spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/Jobs/deploy_gitlab_ci_yaml_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe 'Jobs/Deploy.gitlab-ci.yml' do
+ include Ci::TemplateHelpers
+
subject(:template) do
<<~YAML
stages:
@@ -26,6 +28,17 @@ RSpec.describe 'Jobs/Deploy.gitlab-ci.yml' do
YAML
end
+ describe 'AUTO_DEPLOY_IMAGE_VERSION' do
+ it 'corresponds to a published image in the registry' do
+ template = Gitlab::Template::GitlabCiYmlTemplate.find('Jobs/Deploy')
+ registry = "https://#{template_registry_host}"
+ repository = "gitlab-org/cluster-integration/auto-deploy-image"
+ reference = YAML.safe_load(template.content, aliases: true).dig('variables', 'AUTO_DEPLOY_IMAGE_VERSION')
+
+ expect(public_image_exist?(registry, repository, reference)).to be true
+ end
+ end
+
describe 'the created pipeline' do
let_it_be(:project, refind: true) { create(:project, :repository) }
@@ -33,7 +46,7 @@ RSpec.describe 'Jobs/Deploy.gitlab-ci.yml' do
let(:default_branch) { 'master' }
let(:pipeline_ref) { default_branch }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_ref) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
diff --git a/spec/lib/gitlab/ci/templates/Jobs/sast_iac_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Jobs/sast_iac_gitlab_ci_yaml_spec.rb
index 85516d0bbb0..8a5aea7c0f0 100644
--- a/spec/lib/gitlab/ci/templates/Jobs/sast_iac_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/Jobs/sast_iac_gitlab_ci_yaml_spec.rb
@@ -9,10 +9,10 @@ RSpec.describe 'Jobs/SAST-IaC.gitlab-ci.yml' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
- let(:default_branch) { 'main' }
+ let(:default_branch) { "master" }
let(:pipeline_ref) { default_branch }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_ref) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
@@ -49,7 +49,8 @@ RSpec.describe 'Jobs/SAST-IaC.gitlab-ci.yml' do
context 'on default branch' do
it 'has no jobs' do
- expect { pipeline }.to raise_error(Ci::CreatePipelineService::CreateError)
+ expect(build_names).to be_empty
+ expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."])
end
end
@@ -57,7 +58,8 @@ RSpec.describe 'Jobs/SAST-IaC.gitlab-ci.yml' do
let(:pipeline_ref) { 'feature' }
it 'has no jobs' do
- expect { pipeline }.to raise_error(Ci::CreatePipelineService::CreateError)
+ expect(build_names).to be_empty
+ expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."])
end
end
end
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 5ff179b6fee..d540b035f81 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
@@ -9,10 +9,10 @@ RSpec.describe 'Jobs/SAST-IaC.latest.gitlab-ci.yml' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
- let(:default_branch) { 'main' }
+ let(:default_branch) { "master" }
let(:pipeline_ref) { default_branch }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_ref) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
@@ -50,7 +50,8 @@ RSpec.describe 'Jobs/SAST-IaC.latest.gitlab-ci.yml' do
context 'on default branch' do
it 'has no jobs' do
- expect { pipeline }.to raise_error(Ci::CreatePipelineService::CreateError)
+ expect(build_names).to be_empty
+ expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."])
end
end
@@ -58,7 +59,8 @@ RSpec.describe 'Jobs/SAST-IaC.latest.gitlab-ci.yml' do
let(:pipeline_ref) { 'feature' }
it 'has no jobs' do
- expect { pipeline }.to raise_error(Ci::CreatePipelineService::CreateError)
+ expect(build_names).to be_empty
+ expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."])
end
end
end
diff --git a/spec/lib/gitlab/ci/templates/Jobs/test_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Jobs/test_gitlab_ci_yaml_spec.rb
index a92a8397e96..7cf0cf3ed33 100644
--- a/spec/lib/gitlab/ci/templates/Jobs/test_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/Jobs/test_gitlab_ci_yaml_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'Jobs/Test.gitlab-ci.yml' do
let(:default_branch) { 'master' }
let(:pipeline_ref) { default_branch }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_ref) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
@@ -62,7 +62,8 @@ RSpec.describe 'Jobs/Test.gitlab-ci.yml' do
context 'on master' do
it 'has no jobs' do
- expect { pipeline }.to raise_error(Ci::CreatePipelineService::CreateError)
+ expect(build_names).to be_empty
+ expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."])
end
end
@@ -70,7 +71,8 @@ RSpec.describe 'Jobs/Test.gitlab-ci.yml' do
let(:pipeline_ref) { 'feature' }
it 'has no jobs' do
- expect { pipeline }.to raise_error(Ci::CreatePipelineService::CreateError)
+ expect(build_names).to be_empty
+ expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."])
end
end
@@ -78,7 +80,8 @@ RSpec.describe 'Jobs/Test.gitlab-ci.yml' do
let(:pipeline_ref) { 'v1.0.0' }
it 'has no jobs' do
- expect { pipeline }.to raise_error(Ci::CreatePipelineService::CreateError)
+ expect(build_names).to be_empty
+ expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."])
end
end
end
diff --git a/spec/lib/gitlab/ci/templates/MATLAB_spec.rb b/spec/lib/gitlab/ci/templates/MATLAB_spec.rb
index 432040c4a14..3889d1fc8c9 100644
--- a/spec/lib/gitlab/ci/templates/MATLAB_spec.rb
+++ b/spec/lib/gitlab/ci/templates/MATLAB_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe 'MATLAB.gitlab-ci.yml' do
let(:default_branch) { 'master' }
let(:pipeline_branch) { default_branch }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_branch ) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
diff --git a/spec/lib/gitlab/ci/templates/Terraform/base_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Terraform/base_gitlab_ci_yaml_spec.rb
index eca79f37779..42df924f8fd 100644
--- a/spec/lib/gitlab/ci/templates/Terraform/base_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/Terraform/base_gitlab_ci_yaml_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe 'Terraform/Base.gitlab-ci.yml' do
let(:project) { create(:project, :custom_repo, files: { 'README.md' => '' }) }
let(:user) { project.first_owner }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_branch ) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
diff --git a/spec/lib/gitlab/ci/templates/Terraform/base_latest_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Terraform/base_latest_gitlab_ci_yaml_spec.rb
index 0ab81f97f20..332708ffa13 100644
--- a/spec/lib/gitlab/ci/templates/Terraform/base_latest_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/Terraform/base_latest_gitlab_ci_yaml_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe 'Terraform/Base.latest.gitlab-ci.yml' do
let(:project) { create(:project, :custom_repo, files: { 'README.md' => '' }) }
let(:user) { project.first_owner }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_branch ) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
diff --git a/spec/lib/gitlab/ci/templates/Verify/load_performance_testing_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/Verify/load_performance_testing_gitlab_ci_yaml_spec.rb
index d6c7cd32f79..0f0192ad38f 100644
--- a/spec/lib/gitlab/ci/templates/Verify/load_performance_testing_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/Verify/load_performance_testing_gitlab_ci_yaml_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe 'Verify/Load-Performance-Testing.gitlab-ci.yml' do
let(:default_branch) { 'master' }
let(:pipeline_ref) { default_branch }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_ref) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
diff --git a/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb
index 1a909f52ec3..b2ca906e172 100644
--- a/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/auto_devops_gitlab_ci_yaml_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe 'Auto-DevOps.gitlab-ci.yml' do
let(:project) { create(:project, :auto_devops, :custom_repo, files: { 'README.md' => '' }) }
let(:user) { project.first_owner }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_branch ) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
diff --git a/spec/lib/gitlab/ci/templates/flutter_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/flutter_gitlab_ci_yaml_spec.rb
index de94eec09fe..afb7773ad7a 100644
--- a/spec/lib/gitlab/ci/templates/flutter_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/flutter_gitlab_ci_yaml_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe 'Flutter.gitlab-ci.yml' do
let(:project) { create(:project, :custom_repo, files: { 'README.md' => '' }) }
let(:user) { project.first_owner }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_branch ) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
diff --git a/spec/lib/gitlab/ci/templates/kaniko_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/kaniko_gitlab_ci_yaml_spec.rb
index ebf52e6d65a..62e4188f59b 100644
--- a/spec/lib/gitlab/ci/templates/kaniko_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/kaniko_gitlab_ci_yaml_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe 'Kaniko.gitlab-ci.yml' do
let(:project) { create(:project, :custom_repo, files: { 'Dockerfile' => 'FROM alpine:latest' }) }
let(:user) { project.first_owner }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_branch ) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
diff --git a/spec/lib/gitlab/ci/templates/katalon_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/katalon_gitlab_ci_yaml_spec.rb
index 5a62324da74..a44833b0c01 100644
--- a/spec/lib/gitlab/ci/templates/katalon_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/katalon_gitlab_ci_yaml_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe 'Katalon.gitlab-ci.yml' do
let(:user) { project.first_owner }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: 'master' ) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
diff --git a/spec/lib/gitlab/ci/templates/npm_spec.rb b/spec/lib/gitlab/ci/templates/npm_spec.rb
index d86a3a67823..55fd4675f11 100644
--- a/spec/lib/gitlab/ci/templates/npm_spec.rb
+++ b/spec/lib/gitlab/ci/templates/npm_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe 'npm.gitlab-ci.yml' do
let(:pipeline_tag) { 'v1.2.1' }
let(:pipeline_ref) { pipeline_branch }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_ref ) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
def create_branch(name:)
@@ -42,7 +42,8 @@ RSpec.describe 'npm.gitlab-ci.yml' do
shared_examples 'no pipeline created' do
it 'does not create a pipeline because the only job (publish) is not created' do
- expect { pipeline }.to raise_error(Ci::CreatePipelineService::CreateError, 'No stages / jobs for this pipeline.')
+ expect(build_names).to be_empty
+ expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."])
end
end
diff --git a/spec/lib/gitlab/ci/templates/terraform_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/terraform_gitlab_ci_yaml_spec.rb
index 2fc4b509aab..aa7d0249066 100644
--- a/spec/lib/gitlab/ci/templates/terraform_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/terraform_gitlab_ci_yaml_spec.rb
@@ -12,10 +12,10 @@ RSpec.describe 'Terraform.gitlab-ci.yml' do
describe 'the created pipeline' do
let(:default_branch) { project.default_branch_or_main }
let(:pipeline_branch) { default_branch }
- let(:project) { create(:project, :custom_repo, files: { 'README.md' => '' }) }
+ let_it_be(:project) { create(:project, :repository, create_branch: 'patch-1') }
let(:user) { project.first_owner }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_branch ) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
@@ -27,23 +27,30 @@ RSpec.describe 'Terraform.gitlab-ci.yml' do
end
context 'on master branch' do
- it 'creates init, validate and build jobs', :aggregate_failures do
+ it 'creates init, validate,build terraform jobs as well as kics-iac-sast job', :aggregate_failures do
expect(pipeline.errors).to be_empty
- expect(build_names).to include('validate', 'build', 'deploy')
+ expect(build_names).to include('kics-iac-sast', 'validate', 'build', 'deploy')
end
end
context 'outside the master branch' do
let(:pipeline_branch) { 'patch-1' }
- before do
- project.repository.create_branch(pipeline_branch, default_branch)
- end
-
it 'does not creates a deploy and a test job', :aggregate_failures do
expect(pipeline.errors).to be_empty
expect(build_names).not_to include('deploy')
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 }
+
+ it 'creates a pipeline with no jobs' do
+ expect(pipeline).to be_merge_request_event
+ expect(pipeline.builds.count).to be_zero
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/templates/terraform_latest_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/terraform_latest_gitlab_ci_yaml_spec.rb
index 42e56c4ab3c..6ae51f9783b 100644
--- a/spec/lib/gitlab/ci/templates/terraform_latest_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/terraform_latest_gitlab_ci_yaml_spec.rb
@@ -12,10 +12,10 @@ RSpec.describe 'Terraform.latest.gitlab-ci.yml' do
describe 'the created pipeline' do
let(:default_branch) { project.default_branch_or_main }
let(:pipeline_branch) { default_branch }
- let(:project) { create(:project, :custom_repo, files: { 'README.md' => '' }) }
- let(:user) { project.first_owner }
+ let_it_be(:project) { create(:project, :repository, create_branch: 'patch-1') }
+ let_it_be(:user) { project.first_owner }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_branch ) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
@@ -36,14 +36,38 @@ RSpec.describe 'Terraform.latest.gitlab-ci.yml' do
context 'outside the master branch' do
let(:pipeline_branch) { 'patch-1' }
- before do
- project.repository.create_branch(pipeline_branch, default_branch)
- end
-
it 'does not creates a deploy and a test job', :aggregate_failures do
expect(pipeline.errors).to be_empty
expect(build_names).not_to include('deploy')
end
end
+
+ context 'on merge request' do
+ let(:pipeline_branch) { 'patch-1' }
+ let(:mr_service) { MergeRequests::CreatePipelineService.new(project: project, current_user: user) }
+ let(:merge_request) { create(:merge_request, :simple, source_project: project, source_branch: pipeline_branch ) }
+ let(:mr_pipeline) { mr_service.execute(merge_request).payload }
+ let(:mr_build_names) { mr_pipeline.builds.pluck(:name) }
+ let(:branch_service) { Ci::CreatePipelineService.new(project, user, ref: merge_request.source_branch ) }
+ let(:branch_pipeline) { branch_service.execute(:push).payload }
+ let(:branch_build_names) { branch_pipeline.builds.pluck(:name) }
+
+ # This is needed so that the terraform artifacts and sast_iac artifacts
+ # are both available in the MR
+ it 'creates a pipeline with the terraform and sast_iac jobs' do
+ expect(mr_pipeline).to be_merge_request_event
+ expect(mr_pipeline.errors.full_messages).to be_empty
+ expect(mr_build_names).to include('kics-iac-sast', 'validate', 'build')
+ end
+
+ it 'does not creates a deploy', :aggregate_failures do
+ expect(mr_build_names).not_to include('deploy')
+ end
+
+ it 'does not create a branch pipeline', :aggregate_failures do
+ expect(branch_build_names).to be_empty
+ expect(branch_pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."])
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/templates/themekit_gitlab_ci_yaml_spec.rb b/spec/lib/gitlab/ci/templates/themekit_gitlab_ci_yaml_spec.rb
index 4708108f404..157fd39f1cc 100644
--- a/spec/lib/gitlab/ci/templates/themekit_gitlab_ci_yaml_spec.rb
+++ b/spec/lib/gitlab/ci/templates/themekit_gitlab_ci_yaml_spec.rb
@@ -14,7 +14,7 @@ RSpec.describe 'ThemeKit.gitlab-ci.yml' do
let(:project) { create(:project, :custom_repo, files: { 'README.md' => '' }) }
let(:user) { project.first_owner }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_ref) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
let(:build_names) { pipeline.builds.pluck(:name) }
before do
@@ -51,9 +51,8 @@ RSpec.describe 'ThemeKit.gitlab-ci.yml' do
end
it 'has no jobs' do
- expect { pipeline }.to raise_error(
- Ci::CreatePipelineService::CreateError, 'No stages / jobs for this pipeline.'
- )
+ expect(build_names).to be_empty
+ expect(pipeline.errors.full_messages).to match_array(["No stages / jobs for this pipeline."])
end
end
end
diff --git a/spec/lib/gitlab/ci/variables/collection/item_spec.rb b/spec/lib/gitlab/ci/variables/collection/item_spec.rb
index 9443bf6d6d5..f7c6f7f51df 100644
--- a/spec/lib/gitlab/ci/variables/collection/item_spec.rb
+++ b/spec/lib/gitlab/ci/variables/collection/item_spec.rb
@@ -197,11 +197,11 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Item do
end
end
- describe '#raw' do
+ describe '#raw?' do
it 'returns false when :raw is not specified' do
item = described_class.new(**variable)
- expect(item.raw).to eq false
+ expect(item.raw?).to eq false
end
context 'when :raw is specified as true' do
@@ -212,7 +212,7 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Item do
it 'returns true' do
item = described_class.new(**variable)
- expect(item.raw).to eq true
+ expect(item.raw?).to eq true
end
end
end
diff --git a/spec/lib/gitlab/ci/variables/collection_spec.rb b/spec/lib/gitlab/ci/variables/collection_spec.rb
index 7d4a1eef70b..10b8f0065d9 100644
--- a/spec/lib/gitlab/ci/variables/collection_spec.rb
+++ b/spec/lib/gitlab/ci/variables/collection_spec.rb
@@ -300,7 +300,6 @@ RSpec.describe Gitlab::Ci::Variables::Collection do
Gitlab::Ci::Variables::Collection.new
.append(key: 'CI_JOB_NAME', value: 'test-1')
.append(key: 'CI_BUILD_ID', value: '1')
- .append(key: 'RAW_VAR', value: '$TEST1', raw: true)
.append(key: 'TEST1', value: 'test-3')
.append(key: 'FILEVAR1', value: 'file value 1', file: true)
end
@@ -322,10 +321,6 @@ RSpec.describe Gitlab::Ci::Variables::Collection do
value: 'key${TEST1}-${CI_JOB_NAME}',
result: 'keytest-3-test-1'
},
- "complex expansions with raw variable": {
- value: 'key${RAW_VAR}-${CI_JOB_NAME}',
- result: 'key$TEST1-test-1'
- },
"missing variable not keeping original": {
value: 'key${MISSING_VAR}-${CI_JOB_NAME}',
result: 'key-test-1'
@@ -339,22 +334,22 @@ RSpec.describe Gitlab::Ci::Variables::Collection do
value: 'key-$TEST1-%%HOME%%-$${HOME}',
result: 'key-test-3-%%HOME%%-$${HOME}'
},
- "file variable with expand_file_vars: true": {
+ "file variable with expand_file_refs: true": {
value: 'key-$FILEVAR1-$TEST1',
result: 'key-file value 1-test-3'
},
- "file variable with expand_file_vars: false": {
+ "file variable with expand_file_refs: false": {
value: 'key-$FILEVAR1-$TEST1',
result: 'key-$FILEVAR1-test-3',
- expand_file_vars: false
+ expand_file_refs: false
}
}
end
with_them do
- let(:options) { { keep_undefined: keep_undefined, expand_file_vars: expand_file_vars }.compact }
+ let(:options) { { keep_undefined: keep_undefined, expand_file_refs: expand_file_refs }.compact }
- subject(:result) { collection.expand_value(value, **options) }
+ subject(:expanded_result) { collection.expand_value(value, **options) }
it 'matches expected expansion' do
is_expected.to eq(result)
@@ -509,17 +504,35 @@ RSpec.describe Gitlab::Ci::Variables::Collection do
{ key: 'variable4', value: 'keyvalue${variable2}value3' }
]
},
- "complex expansions with raw variable": {
+ "complex expansions with raw variable with expand_raw_refs: true (default)": {
+ variables: [
+ { key: 'variable1', value: 'value1' },
+ { key: 'raw_var', value: 'raw-$variable1', raw: true },
+ { key: 'nonraw_var', value: 'nonraw-$variable1' },
+ { key: 'variable2', value: '$raw_var and $nonraw_var' }
+ ],
+ keep_undefined: false,
+ result: [
+ { key: 'variable1', value: 'value1' },
+ { key: 'raw_var', value: 'raw-$variable1', raw: true },
+ { key: 'nonraw_var', value: 'nonraw-value1' },
+ { key: 'variable2', value: 'raw-$variable1 and nonraw-value1' }
+ ]
+ },
+ "complex expansions with raw variable with expand_raw_refs: false": {
variables: [
- { key: 'variable3', value: 'key_${variable}_${variable2}' },
- { key: 'variable', value: '$variable2', raw: true },
- { key: 'variable2', value: 'value2' }
+ { key: 'variable1', value: 'value1' },
+ { key: 'raw_var', value: 'raw-$variable1', raw: true },
+ { key: 'nonraw_var', value: 'nonraw-$variable1' },
+ { key: 'variable2', value: '$raw_var and $nonraw_var' }
],
keep_undefined: false,
+ expand_raw_refs: false,
result: [
- { key: 'variable', value: '$variable2', raw: true },
- { key: 'variable2', value: 'value2' },
- { key: 'variable3', value: 'key_$variable2_value2' }
+ { key: 'variable1', value: 'value1' },
+ { key: 'raw_var', value: 'raw-$variable1', raw: true },
+ { key: 'nonraw_var', value: 'nonraw-value1' },
+ { key: 'variable2', value: '$raw_var and nonraw-value1' }
]
},
"variable value referencing password with special characters": {
@@ -553,8 +566,9 @@ RSpec.describe Gitlab::Ci::Variables::Collection do
with_them do
let(:collection) { Gitlab::Ci::Variables::Collection.new(variables) }
+ let(:options) { { keep_undefined: keep_undefined, expand_raw_refs: expand_raw_refs }.compact }
- subject { collection.sort_and_expand_all(keep_undefined: keep_undefined) }
+ subject(:expanded_result) { collection.sort_and_expand_all(**options) }
it 'returns Collection' do
is_expected.to be_an_instance_of(Gitlab::Ci::Variables::Collection)
@@ -601,7 +615,8 @@ RSpec.describe Gitlab::Ci::Variables::Collection do
it 'logs file_variable_is_referenced_in_another_variable once for VAR5' do
expect(Gitlab::AppJsonLogger).to receive(:info).with(
event: 'file_variable_is_referenced_in_another_variable',
- project_id: project.id
+ project_id: project.id,
+ variable: 'FILEVAR4'
).once
sort_and_expand_all
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index ebf8422489e..5de813f7739 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -1071,6 +1071,7 @@ module Gitlab
let(:build) { execute.builds.first }
let(:job_variables) { build[:job_variables] }
+ let(:root_variables) { execute.root_variables }
let(:root_variables_inheritance) { build[:root_variables_inheritance] }
context 'when global variables are defined' do
@@ -1193,6 +1194,78 @@ module Gitlab
expect(root_variables_inheritance).to eq(true)
end
end
+
+ context 'when variables have data other than value' do
+ let(:config) do
+ <<~YAML
+ variables:
+ VAR1: value1
+ VAR2:
+ value: value2
+ description: description2
+ VAR3:
+ value: value3
+ expand: false
+
+ rspec:
+ script: rspec
+ variables:
+ VAR4: value4
+ VAR5:
+ value: value5
+ expand: false
+ VAR6:
+ value: value6
+ expand: true
+ YAML
+ end
+
+ it 'returns variables' do
+ expect(job_variables).to contain_exactly(
+ { key: 'VAR4', value: 'value4' },
+ { key: 'VAR5', value: 'value5', raw: true },
+ { key: 'VAR6', value: 'value6', raw: false }
+ )
+
+ expect(execute.root_variables).to contain_exactly(
+ { key: 'VAR1', value: 'value1' },
+ { key: 'VAR2', value: 'value2' },
+ { key: 'VAR3', value: 'value3', raw: true }
+ )
+
+ expect(execute.root_variables_with_prefill_data).to eq(
+ 'VAR1' => { value: 'value1' },
+ 'VAR2' => { value: 'value2', description: 'description2' },
+ 'VAR3' => { value: 'value3', raw: true }
+ )
+ end
+
+ context 'when the FF ci_raw_variables_in_yaml_config is disabled' do
+ before do
+ stub_feature_flags(ci_raw_variables_in_yaml_config: false)
+ end
+
+ it 'returns variables without description and raw' do
+ expect(job_variables).to contain_exactly(
+ { key: 'VAR4', value: 'value4' },
+ { key: 'VAR5', value: 'value5' },
+ { key: 'VAR6', value: 'value6' }
+ )
+
+ expect(execute.root_variables).to contain_exactly(
+ { key: 'VAR1', value: 'value1' },
+ { key: 'VAR2', value: 'value2' },
+ { key: 'VAR3', value: 'value3' }
+ )
+
+ expect(execute.root_variables_with_prefill_data).to eq(
+ 'VAR1' => { value: 'value1' },
+ 'VAR2' => { value: 'value2', description: 'description2' },
+ 'VAR3' => { value: 'value3' }
+ )
+ end
+ end
+ end
end
context 'when using `extends`' do
@@ -1334,7 +1407,7 @@ module Gitlab
context "when an array of wrong keyed object is provided" do
let(:include_content) { [{ yolo: "/local.gitlab-ci.yml" }] }
- it_behaves_like 'returns errors', /needs to match exactly one accessor/
+ it_behaves_like 'returns errors', /does not have a valid subkey for include/
end
context "when an array of mixed typed objects is provided" do
@@ -1359,7 +1432,7 @@ module Gitlab
context "when the include type is incorrect" do
let(:include_content) { { name: "/local.gitlab-ci.yml" } }
- it_behaves_like 'returns errors', /needs to match exactly one accessor/
+ it_behaves_like 'returns errors', /does not have a valid subkey for include/
end
end
diff --git a/spec/lib/gitlab/cluster/lifecycle_events_spec.rb b/spec/lib/gitlab/cluster/lifecycle_events_spec.rb
index 5eea78acd98..45becb8370c 100644
--- a/spec/lib/gitlab/cluster/lifecycle_events_spec.rb
+++ b/spec/lib/gitlab/cluster/lifecycle_events_spec.rb
@@ -3,38 +3,55 @@
require 'spec_helper'
RSpec.describe Gitlab::Cluster::LifecycleEvents do
+ using RSpec::Parameterized::TableSyntax
+
# we create a new instance to ensure that we do not touch existing hooks
let(:replica) { Class.new(described_class) }
- context 'hooks execution' do
- using RSpec::Parameterized::TableSyntax
+ before do
+ # disable blackout period to speed-up tests
+ stub_config(shutdown: { blackout_seconds: 0 })
+ end
- where(:method, :hook_names) do
- :do_worker_start | %i[worker_start_hooks]
- :do_before_fork | %i[before_fork_hooks]
- :do_before_graceful_shutdown | %i[master_blackout_period master_graceful_shutdown]
- :do_before_master_restart | %i[master_restart_hooks]
+ context 'outside of clustered environments' do
+ where(:hook, :was_executed_immediately) do
+ :on_worker_start | true
+ :on_before_fork | false
+ :on_before_graceful_shutdown | false
+ :on_before_master_restart | false
+ :on_worker_stop | false
end
- before do
- # disable blackout period to speed-up tests
- stub_config(shutdown: { blackout_seconds: 0 })
+ with_them do
+ it 'executes the given block immediately' do
+ was_executed = false
+ replica.public_send(hook, &proc { was_executed = true })
+
+ expect(was_executed).to eq(was_executed_immediately)
+ end
end
+ end
- with_them do
- subject { replica.public_send(method) }
+ context 'in clustered environments' do
+ before do
+ allow(Gitlab::Runtime).to receive(:puma?).and_return(true)
+ replica.set_puma_options(workers: 2)
+ end
- it 'executes all hooks' do
- hook_names.each do |hook_name|
- hook = double
- replica.instance_variable_set(:"@#{hook_name}", [hook])
+ where(:hook, :execution_helper) do
+ :on_worker_start | :do_worker_start
+ :on_before_fork | :do_before_fork
+ :on_before_graceful_shutdown | :do_before_graceful_shutdown
+ :on_before_master_restart | :do_before_master_restart
+ :on_worker_stop | :do_worker_stop
+ end
- # ensure that proper hooks are called
- expect(hook).to receive(:call)
- expect(replica).to receive(:call).with(hook_name, anything).and_call_original
- end
+ with_them do
+ it 'requires explicit execution via do_* helper' do
+ was_executed = false
+ replica.public_send(hook, &proc { was_executed = true })
- subject
+ expect { replica.public_send(execution_helper) }.to change { was_executed }.from(false).to(true)
end
end
end
diff --git a/spec/lib/gitlab/cluster/puma_worker_killer_initializer_spec.rb b/spec/lib/gitlab/cluster/puma_worker_killer_initializer_spec.rb
new file mode 100644
index 00000000000..cb13a711857
--- /dev/null
+++ b/spec/lib/gitlab/cluster/puma_worker_killer_initializer_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'puma_worker_killer'
+
+RSpec.describe Gitlab::Cluster::PumaWorkerKillerInitializer do
+ describe '.start' do
+ context 'when GITLAB_MEMORY_WATCHDOG_ENABLED is false' do
+ before do
+ stub_env('GITLAB_MEMORY_WATCHDOG_ENABLED', 'false')
+ end
+
+ it 'configures and start PumaWorkerKiller' do
+ expect(PumaWorkerKiller).to receive(:config)
+ expect(PumaWorkerKiller).to receive(:start)
+
+ described_class.start({})
+ end
+ end
+
+ context 'when GITLAB_MEMORY_WATCHDOG_ENABLED is not set' do
+ it 'configures and start PumaWorkerKiller' do
+ expect(PumaWorkerKiller).not_to receive(:config)
+ expect(PumaWorkerKiller).not_to receive(:start)
+
+ described_class.start({})
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/config_checker/external_database_checker_spec.rb b/spec/lib/gitlab/config_checker/external_database_checker_spec.rb
index 9af6aed2b02..963c9fe1576 100644
--- a/spec/lib/gitlab/config_checker/external_database_checker_spec.rb
+++ b/spec/lib/gitlab/config_checker/external_database_checker_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe Gitlab::ConfigChecker::ExternalDatabaseChecker do
end
it 'reports deprecated database notice' do
- is_expected.to contain_exactly(notice_deprecated_database(old_database_version))
+ is_expected.to contain_exactly(notice_deprecated_database('main', old_database_version))
end
end
end
@@ -59,13 +59,13 @@ RSpec.describe Gitlab::ConfigChecker::ExternalDatabaseChecker do
it 'reports deprecated database notice if the main database is using an old version' do
allow(Gitlab::Database::Reflection).to receive(:new).with(ActiveRecord::Base).and_return(old_database)
allow(Gitlab::Database::Reflection).to receive(:new).with(Ci::ApplicationRecord).and_return(new_database)
- is_expected.to contain_exactly(notice_deprecated_database(old_database_version))
+ is_expected.to contain_exactly(notice_deprecated_database('main', old_database_version))
end
it 'reports deprecated database notice if the ci database is using an old version' do
allow(Gitlab::Database::Reflection).to receive(:new).with(ActiveRecord::Base).and_return(new_database)
allow(Gitlab::Database::Reflection).to receive(:new).with(Ci::ApplicationRecord).and_return(old_database)
- is_expected.to contain_exactly(notice_deprecated_database(old_database_version))
+ is_expected.to contain_exactly(notice_deprecated_database('ci', old_database_version))
end
end
@@ -77,22 +77,23 @@ RSpec.describe Gitlab::ConfigChecker::ExternalDatabaseChecker do
it 'reports deprecated database notice' do
is_expected.to match_array [
- notice_deprecated_database(old_database_version),
- notice_deprecated_database(old_database_version)
+ notice_deprecated_database('main', old_database_version),
+ notice_deprecated_database('ci', old_database_version)
]
end
end
end
end
- def notice_deprecated_database(database_version)
+ def notice_deprecated_database(database_name, database_version)
{
type: 'warning',
- message: _('You are using PostgreSQL %{pg_version_current}, but PostgreSQL ' \
- '%{pg_version_minimum} is required for this version of GitLab. ' \
- 'Please upgrade your environment to a supported PostgreSQL version, ' \
- 'see %{pg_requirements_url} for details.') % \
+ message: _('Database \'%{database_name}\' is using PostgreSQL %{pg_version_current}, ' \
+ 'but PostgreSQL %{pg_version_minimum} is required for this version of GitLab. ' \
+ 'Please upgrade your environment to a supported PostgreSQL version, ' \
+ 'see %{pg_requirements_url} for details.') % \
{
+ database_name: database_name,
pg_version_current: database_version,
pg_version_minimum: Gitlab::Database::MINIMUM_POSTGRES_VERSION,
pg_requirements_url: Gitlab::ConfigChecker::ExternalDatabaseChecker::PG_REQUIREMENTS_LINK
diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb
index 1fa6eee9813..165305476d2 100644
--- a/spec/lib/gitlab/conflict/file_spec.rb
+++ b/spec/lib/gitlab/conflict/file_spec.rb
@@ -3,18 +3,15 @@
require 'spec_helper'
RSpec.describe Gitlab::Conflict::File do
- include GitHelpers
-
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
- let(:rugged) { rugged_repo(repository) }
- let(:their_commit) { rugged.branches['conflict-start'].target }
- let(:our_commit) { rugged.branches['conflict-resolvable'].target }
+ let(:their_commit) { TestEnv::BRANCH_SHA['conflict-start'] }
+ let(:our_commit) { TestEnv::BRANCH_SHA['conflict-resolvable'] }
let(:merge_request) { create(:merge_request, source_branch: 'conflict-resolvable', target_branch: 'conflict-start', source_project: project) }
- let(:index) { rugged.merge_commits(our_commit, their_commit) }
- let(:rugged_conflict) { index.conflicts.last }
- let(:raw_conflict_content) { index.merge_file('files/ruby/regex.rb')[:data] }
- let(:raw_conflict_file) { Gitlab::Git::Conflict::File.new(repository, our_commit.oid, rugged_conflict, raw_conflict_content) }
+ let(:conflicts_client) { repository.gitaly_conflicts_client(our_commit, their_commit) }
+ let(:raw_conflict_files) { conflicts_client.list_conflict_files }
+ let(:conflict_file_name) { 'files/ruby/regex.rb' }
+ let(:raw_conflict_file) { raw_conflict_files.find { |conflict| conflict.our_path == conflict_file_name } }
let(:conflict_file) { described_class.new(raw_conflict_file, merge_request: merge_request) }
describe 'delegates' do
@@ -137,8 +134,7 @@ RSpec.describe Gitlab::Conflict::File do
end
context 'when there are unchanged trailing lines' do
- let(:rugged_conflict) { index.conflicts.first }
- let(:raw_conflict_content) { index.merge_file('files/ruby/popen.rb')[:data] }
+ let(:conflict_file_name) { 'files/ruby/popen.rb' }
it 'assign conflict types and adds match line to the end of the section' do
expect(diff_line_types).to eq(
@@ -294,6 +290,8 @@ RSpec.describe Gitlab::Conflict::File do
FILE
end
+ let(:conflict) { { ancestor: { path: '' }, theirs: { path: conflict_file_name }, ours: { path: conflict_file_name } } }
+ let(:raw_conflict_file) { Gitlab::Git::Conflict::File.new(repository, our_commit, conflict, raw_conflict_content) }
let(:sections) { conflict_file.sections }
it 'sets the correct match line headers' do
@@ -324,7 +322,7 @@ RSpec.describe Gitlab::Conflict::File do
describe '#as_json' do
it 'includes the blob path for the file' do
expect(conflict_file.as_json[:blob_path])
- .to eq("/#{project.full_path}/-/blob/#{our_commit.oid}/files/ruby/regex.rb")
+ .to eq("/#{project.full_path}/-/blob/#{our_commit}/files/ruby/regex.rb")
end
it 'includes the blob icon for the file' do
@@ -341,7 +339,8 @@ RSpec.describe Gitlab::Conflict::File do
describe '#conflict_type' do
using RSpec::Parameterized::TableSyntax
- let(:rugged_conflict) { { ancestor: { path: ancestor_path }, theirs: { path: their_path }, ours: { path: our_path } } }
+ let(:conflict) { { ancestor: { path: ancestor_path }, theirs: { path: their_path }, ours: { path: our_path } } }
+ let(:raw_conflict_file) { Gitlab::Git::Conflict::File.new(repository, our_commit, conflict, '') }
let(:diff_file) { double(renamed_file?: renamed_file?) }
subject(:conflict_type) { conflict_file.conflict_type(diff_file) }
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 6b1d8d8d1af..aadfb41a46e 100644
--- a/spec/lib/gitlab/content_security_policy/config_loader_spec.rb
+++ b/spec/lib/gitlab/content_security_policy/config_loader_spec.rb
@@ -53,6 +53,18 @@ RSpec.describe Gitlab::ContentSecurityPolicy::ConfigLoader do
expect(directives['child_src']).to eq("#{directives['frame_src']} #{directives['worker_src']}")
end
+ describe 'the images-src directive' do
+ it 'can be loaded from anywhere' do
+ expect(directives['img_src']).to include('http: https:')
+ end
+ end
+
+ describe 'the media-src directive' do
+ it 'can be loaded from anywhere' do
+ expect(directives['media_src']).to include('http: https:')
+ end
+ end
+
context 'adds all websocket origins to support Safari' do
it 'with insecure domain' do
stub_config_setting(host: 'example.com', https: false)
diff --git a/spec/lib/gitlab/data_builder/build_spec.rb b/spec/lib/gitlab/data_builder/build_spec.rb
index 2c239d5868a..544b210651b 100644
--- a/spec/lib/gitlab/data_builder/build_spec.rb
+++ b/spec/lib/gitlab/data_builder/build_spec.rb
@@ -3,10 +3,9 @@
require 'spec_helper'
RSpec.describe Gitlab::DataBuilder::Build do
- let!(:tag_names) { %w(tag-1 tag-2) }
- let(:runner) { create(:ci_runner, :instance, tag_list: tag_names.map { |n| ActsAsTaggableOn::Tag.create!(name: n) }) }
- let(:user) { create(:user, :public_email) }
- let(:build) { create(:ci_build, :running, runner: runner, user: user) }
+ let_it_be(:runner) { create(:ci_runner, :instance, :tagged_only) }
+ let_it_be(:user) { create(:user, :public_email) }
+ let_it_be(:ci_build) { create(:ci_build, :running, runner: runner, user: user) }
describe '.build' do
around do |example|
@@ -14,25 +13,26 @@ RSpec.describe Gitlab::DataBuilder::Build do
end
let(:data) do
- described_class.build(build)
+ described_class.build(ci_build)
end
it { expect(data).to be_a(Hash) }
- it { expect(data[:ref]).to eq(build.ref) }
- it { expect(data[:sha]).to eq(build.sha) }
- it { expect(data[:tag]).to eq(build.tag) }
- it { expect(data[:build_id]).to eq(build.id) }
- it { expect(data[:build_status]).to eq(build.status) }
- it { expect(data[:build_created_at]).to eq(build.created_at) }
- it { expect(data[:build_started_at]).to eq(build.started_at) }
- it { expect(data[:build_finished_at]).to eq(build.finished_at) }
- it { expect(data[:build_duration]).to eq(build.duration) }
- it { expect(data[:build_queued_duration]).to eq(build.queued_duration) }
+ it { expect(data[:ref]).to eq(ci_build.ref) }
+ it { expect(data[:sha]).to eq(ci_build.sha) }
+ it { expect(data[:tag]).to eq(ci_build.tag) }
+ it { expect(data[:build_id]).to eq(ci_build.id) }
+ it { expect(data[:build_status]).to eq(ci_build.status) }
+ it { expect(data[:build_created_at]).to eq(ci_build.created_at) }
+ it { expect(data[:build_started_at]).to eq(ci_build.started_at) }
+ it { expect(data[:build_finished_at]).to eq(ci_build.finished_at) }
+ it { expect(data[:build_duration]).to eq(ci_build.duration) }
+ it { expect(data[:build_queued_duration]).to eq(ci_build.queued_duration) }
it { expect(data[:build_allow_failure]).to eq(false) }
- it { expect(data[:build_failure_reason]).to eq(build.failure_reason) }
- it { expect(data[:project_id]).to eq(build.project.id) }
- it { expect(data[:project_name]).to eq(build.project.full_name) }
- it { expect(data[:pipeline_id]).to eq(build.pipeline.id) }
+ it { expect(data[:build_failure_reason]).to eq(ci_build.failure_reason) }
+ it { expect(data[:project_id]).to eq(ci_build.project.id) }
+ it { expect(data[:project_name]).to eq(ci_build.project.full_name) }
+ it { expect(data[:pipeline_id]).to eq(ci_build.pipeline.id) }
+ it { expect(data[:retries_count]).to eq(ci_build.retries_count) }
it {
expect(data[:user]).to eq(
@@ -45,44 +45,74 @@ RSpec.describe Gitlab::DataBuilder::Build do
})
}
- it { expect(data[:commit][:id]).to eq(build.pipeline.id) }
- it { expect(data[:runner][:id]).to eq(build.runner.id) }
- it { expect(data[:runner][:tags]).to match_array(tag_names) }
- it { expect(data[:runner][:description]).to eq(build.runner.description) }
- it { expect(data[:runner][:runner_type]).to eq(build.runner.runner_type) }
- it { expect(data[:runner][:is_shared]).to eq(build.runner.instance_type?) }
+ it { expect(data[:commit][:id]).to eq(ci_build.pipeline.id) }
+ it { expect(data[:runner][:id]).to eq(ci_build.runner.id) }
+ it { expect(data[:runner][:tags]).to match_array(%w(tag1 tag2)) }
+ it { expect(data[:runner][:description]).to eq(ci_build.runner.description) }
+ it { expect(data[:runner][:runner_type]).to eq(ci_build.runner.runner_type) }
+ it { expect(data[:runner][:is_shared]).to eq(ci_build.runner.instance_type?) }
it { expect(data[:environment]).to be_nil }
+ it 'does not exceed number of expected queries' do
+ ci_build # Make sure the Ci::Build model is created before recording.
+
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ b = Ci::Build.find(ci_build.id)
+ described_class.build(b) # Don't use ci_build variable here since it has all associations loaded into memory
+ end
+
+ expect(control.count).to eq(13)
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(job_webhook_retries_count: false)
+ end
+
+ it { expect(data).not_to have_key(:retries_count) }
+
+ it 'does not exceed number of expected queries' do
+ ci_build # Make sure the Ci::Build model is created before recording.
+
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ b = Ci::Build.find(ci_build.id)
+ described_class.build(b) # Don't use ci_build variable here since it has all associations loaded into memory
+ end
+
+ expect(control.count).to eq(12)
+ end
+ end
+
context 'commit author_url' do
context 'when no commit present' do
- let(:build) { create(:ci_build) }
+ let(:build) { build(:ci_build) }
it 'sets to mailing address of git_author_email' do
- expect(data[:commit][:author_url]).to eq("mailto:#{build.pipeline.git_author_email}")
+ expect(data[:commit][:author_url]).to eq("mailto:#{ci_build.pipeline.git_author_email}")
end
end
context 'when commit present but has no author' do
- let(:build) { create(:ci_build, :with_commit) }
+ let(:ci_build) { build(:ci_build, :with_commit) }
it 'sets to mailing address of git_author_email' do
- expect(data[:commit][:author_url]).to eq("mailto:#{build.pipeline.git_author_email}")
+ expect(data[:commit][:author_url]).to eq("mailto:#{ci_build.pipeline.git_author_email}")
end
end
context 'when commit and author are present' do
- let(:build) { create(:ci_build, :with_commit_and_author) }
+ let(:ci_build) { build(:ci_build, :with_commit_and_author) }
it 'sets to GitLab user url' do
- expect(data[:commit][:author_url]).to eq(Gitlab::Routing.url_helpers.user_url(username: build.commit.author.username))
+ expect(data[:commit][:author_url]).to eq(Gitlab::Routing.url_helpers.user_url(username: ci_build.commit.author.username))
end
end
context 'with environment' do
- let(:build) { create(:ci_build, :teardown_environment) }
+ let(:ci_build) { build(:ci_build, :teardown_environment) }
- it { expect(data[:environment][:name]).to eq(build.expanded_environment_name) }
- it { expect(data[:environment][:action]).to eq(build.environment_action) }
+ it { expect(data[:environment][:name]).to eq(ci_build.expanded_environment_name) }
+ it { expect(data[:environment][:action]).to eq(ci_build.environment_action) }
end
end
end
diff --git a/spec/lib/gitlab/data_builder/pipeline_spec.rb b/spec/lib/gitlab/data_builder/pipeline_spec.rb
index 46a12d8c6f6..eb348f5b497 100644
--- a/spec/lib/gitlab/data_builder/pipeline_spec.rb
+++ b/spec/lib/gitlab/data_builder/pipeline_spec.rb
@@ -103,6 +103,7 @@ RSpec.describe Gitlab::DataBuilder::Pipeline do
expect(merge_request_attrs[:target_project_id]).to eq(merge_request.target_project_id)
expect(merge_request_attrs[:state]).to eq(merge_request.state)
expect(merge_request_attrs[:merge_status]).to eq(merge_request.public_merge_status)
+ expect(merge_request_attrs[:detailed_merge_status]).to eq("mergeable")
expect(merge_request_attrs[:url]).to eq("http://localhost/#{merge_request.target_project.full_path}/-/merge_requests/#{merge_request.iid}")
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 32746a46308..cc9f3d5b7f1 100644
--- a/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
@@ -7,7 +7,15 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedJob, type: :model d
it { is_expected.to be_a Gitlab::Database::SharedModel }
- it { expect(described_class::TIMEOUT_EXCEPTIONS).to match_array [ActiveRecord::StatementTimeout, ActiveRecord::ConnectionTimeoutError, ActiveRecord::AdapterTimeout, ActiveRecord::LockWaitTimeout] }
+ specify do
+ expect(described_class::TIMEOUT_EXCEPTIONS).to contain_exactly(
+ ActiveRecord::StatementTimeout,
+ ActiveRecord::ConnectionTimeoutError,
+ ActiveRecord::AdapterTimeout,
+ ActiveRecord::LockWaitTimeout,
+ ActiveRecord::QueryCanceled
+ )
+ end
describe 'associations' do
it { is_expected.to belong_to(:batched_migration).with_foreign_key(:batched_background_migration_id) }
@@ -272,7 +280,13 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedJob, type: :model d
context 'when is a timeout exception' do
let(:exception) { ActiveRecord::StatementTimeout.new }
- it { expect(subject).to be_truthy }
+ it { expect(subject).to be_truthy }
+ end
+
+ context 'when is a QueryCanceled exception' do
+ let(:exception) { ActiveRecord::QueryCanceled.new }
+
+ it { expect(subject).to be_truthy }
end
context 'when is not a timeout exception' do
diff --git a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
index 1ac9cbae036..31ae5e9b55d 100644
--- a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
@@ -211,6 +211,102 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m
expect(active_migration).to eq(migration3)
end
end
+
+ context 'when there are no active migrations available' do
+ it 'returns nil' do
+ expect(active_migration).to eq(nil)
+ end
+ end
+ end
+
+ describe '.find_executable' do
+ let(:connection) { Gitlab::Database.database_base_models[:main].connection }
+ let(:migration_id) { migration.id }
+
+ subject(:executable_migration) { described_class.find_executable(migration_id, connection: connection) }
+
+ around do |example|
+ Gitlab::Database::SharedModel.using_connection(connection) do
+ example.run
+ end
+ end
+
+ context 'when the migration does not exist' do
+ let(:migration_id) { non_existing_record_id }
+
+ it 'returns nil' do
+ expect(executable_migration).to be_nil
+ end
+ end
+
+ context 'when the migration is not active' do
+ let!(:migration) { create(:batched_background_migration, :finished) }
+
+ it 'returns nil' do
+ expect(executable_migration).to be_nil
+ end
+ end
+
+ context 'when the migration is on hold' do
+ let!(:migration) { create(:batched_background_migration, :active, on_hold_until: 10.minutes.from_now) }
+
+ it 'returns nil' do
+ expect(executable_migration).to be_nil
+ end
+ end
+
+ context 'when the migration is not available for the current connection' do
+ let!(:migration) { create(:batched_background_migration, :active, gitlab_schema: :gitlab_not_existing) }
+
+ it 'returns nil' do
+ expect(executable_migration).to be_nil
+ end
+ end
+
+ context 'when ther migration exists and is executable' do
+ let!(:migration) { create(:batched_background_migration, :active, gitlab_schema: :gitlab_main) }
+
+ it 'returns the migration' do
+ expect(executable_migration).to eq(migration)
+ end
+ end
+ end
+
+ describe '.active_migrations_distinct_on_table' do
+ let(:connection) { Gitlab::Database.database_base_models[:main].connection }
+
+ around do |example|
+ Gitlab::Database::SharedModel.using_connection(connection) do
+ example.run
+ end
+ end
+
+ it 'returns one pending executable migration per table' do
+ # non-active migration
+ create(:batched_background_migration, :finished)
+ # migration put on hold
+ create(:batched_background_migration, :active, on_hold_until: 10.minutes.from_now)
+ # migration not availab for the current connection
+ create(:batched_background_migration, :active, gitlab_schema: :gitlab_not_existing)
+ # active migration that is no longer on hold
+ migration_1 = create(:batched_background_migration, :active, table_name: :users, on_hold_until: 10.minutes.ago)
+ # another active migration for the same table
+ create(:batched_background_migration, :active, table_name: :users)
+ # active migration for different table
+ migration_2 = create(:batched_background_migration, :active, table_name: :projects)
+ # active migration for third table
+ create(:batched_background_migration, :active, table_name: :namespaces)
+
+ actual = described_class.active_migrations_distinct_on_table(connection: connection, limit: 2)
+
+ expect(actual).to eq([migration_1, migration_2])
+ end
+
+ it 'returns epmty collection when there are no pending executable migrations' do
+ actual = described_class.active_migrations_distinct_on_table(connection: connection, limit: 2)
+
+ expect(actual).to be_empty
+ end
end
describe '.created_after' do
diff --git a/spec/lib/gitlab/database/batch_count_spec.rb b/spec/lib/gitlab/database/batch_count_spec.rb
index a87b0c1a3a8..852cc719d01 100644
--- a/spec/lib/gitlab/database/batch_count_spec.rb
+++ b/spec/lib/gitlab/database/batch_count_spec.rb
@@ -330,7 +330,7 @@ RSpec.describe Gitlab::Database::BatchCount do
end
it 'counts with "id" field' do
- expect(described_class.batch_distinct_count(model, "#{column}")).to eq(2)
+ expect(described_class.batch_distinct_count(model, column.to_s)).to eq(2)
end
it 'counts with table.column field' do
diff --git a/spec/lib/gitlab/database/load_balancing/configuration_spec.rb b/spec/lib/gitlab/database/load_balancing/configuration_spec.rb
index 34370c9a21f..7dc2e0be3e5 100644
--- a/spec/lib/gitlab/database/load_balancing/configuration_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/configuration_spec.rb
@@ -23,7 +23,8 @@ RSpec.describe Gitlab::Database::LoadBalancing::Configuration, :request_store do
record_type: 'A',
interval: 60,
disconnect_timeout: 120,
- use_tcp: false
+ use_tcp: false,
+ max_replica_pools: nil
)
expect(config.pool_size).to eq(Gitlab::Database.default_pool_size)
end
@@ -39,7 +40,8 @@ RSpec.describe Gitlab::Database::LoadBalancing::Configuration, :request_store do
replica_check_interval: 3,
hosts: %w[foo bar],
discover: {
- 'record' => 'foo.example.com'
+ record: 'foo.example.com',
+ max_replica_pools: 5
}
}
}
@@ -59,7 +61,8 @@ RSpec.describe Gitlab::Database::LoadBalancing::Configuration, :request_store do
record_type: 'A',
interval: 60,
disconnect_timeout: 120,
- use_tcp: false
+ use_tcp: false,
+ max_replica_pools: 5
)
expect(config.pool_size).to eq(4)
end
@@ -95,7 +98,8 @@ RSpec.describe Gitlab::Database::LoadBalancing::Configuration, :request_store do
record_type: 'A',
interval: 60,
disconnect_timeout: 120,
- use_tcp: false
+ use_tcp: false,
+ max_replica_pools: nil
)
expect(config.pool_size).to eq(4)
end
diff --git a/spec/lib/gitlab/database/load_balancing/connection_proxy_spec.rb b/spec/lib/gitlab/database/load_balancing/connection_proxy_spec.rb
index 41312dbedd6..a2076f5b950 100644
--- a/spec/lib/gitlab/database/load_balancing/connection_proxy_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/connection_proxy_spec.rb
@@ -53,7 +53,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::ConnectionProxy do
end
Gitlab::Database::LoadBalancing::ConnectionProxy::NON_STICKY_READS.each do |name|
- describe "#{name}" do
+ describe name.to_s do
it 'runs the query on the replica' do
expect(proxy).to receive(:read_using_load_balancer)
.with(name, 'foo')
@@ -64,7 +64,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::ConnectionProxy do
end
Gitlab::Database::LoadBalancing::ConnectionProxy::STICKY_WRITES.each do |name|
- describe "#{name}" do
+ describe name.to_s do
it 'runs the query on the primary and sticks to it' do
session = Gitlab::Database::LoadBalancing::Session.new
diff --git a/spec/lib/gitlab/database/load_balancing/service_discovery/sampler_spec.rb b/spec/lib/gitlab/database/load_balancing/service_discovery/sampler_spec.rb
new file mode 100644
index 00000000000..1a49aa2871f
--- /dev/null
+++ b/spec/lib/gitlab/database/load_balancing/service_discovery/sampler_spec.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Gitlab::Database::LoadBalancing::ServiceDiscovery::Sampler do
+ let(:sampler) { described_class.new(max_replica_pools: max_replica_pools, seed: 100) }
+ let(:max_replica_pools) { 3 }
+ let(:address_class) { ::Gitlab::Database::LoadBalancing::ServiceDiscovery::Address }
+ let(:addresses) do
+ [
+ address_class.new("127.0.0.1", 6432),
+ address_class.new("127.0.0.1", 6433),
+ address_class.new("127.0.0.1", 6434),
+ address_class.new("127.0.0.1", 6435),
+ address_class.new("127.0.0.2", 6432),
+ address_class.new("127.0.0.2", 6433),
+ address_class.new("127.0.0.2", 6434),
+ address_class.new("127.0.0.2", 6435)
+ ]
+ end
+
+ describe '#sample' do
+ it 'samples max_replica_pools addresses' do
+ expect(sampler.sample(addresses).count).to eq(max_replica_pools)
+ end
+
+ it 'samples random ports across all hosts' do
+ expect(sampler.sample(addresses)).to eq([
+ address_class.new("127.0.0.1", 6432),
+ address_class.new("127.0.0.2", 6435),
+ address_class.new("127.0.0.1", 6435)
+ ])
+ end
+
+ it 'returns the same answer for the same input when called multiple times' do
+ result = sampler.sample(addresses)
+ expect(sampler.sample(addresses)).to eq(result)
+ expect(sampler.sample(addresses)).to eq(result)
+ end
+
+ it 'gives a consistent answer regardless of input ordering' do
+ expect(sampler.sample(addresses.reverse)).to eq(sampler.sample(addresses))
+ end
+
+ it 'samples fairly across all hosts' do
+ # Choose a bunch of different seeds to prove that it always chooses 2
+ # different ports from each host when selecting 4
+ (1..10).each do |seed|
+ sampler = described_class.new(max_replica_pools: 4, seed: seed)
+
+ result = sampler.sample(addresses)
+
+ expect(result.count { |r| r.hostname == "127.0.0.1" }).to eq(2)
+ expect(result.count { |r| r.hostname == "127.0.0.2" }).to eq(2)
+ end
+ end
+
+ context 'when input is an empty array' do
+ it 'returns an empty array' do
+ expect(sampler.sample([])).to eq([])
+ end
+ end
+
+ context 'when there are less replicas than max_replica_pools' do
+ let(:max_replica_pools) { 100 }
+
+ it 'returns the same addresses' do
+ expect(sampler.sample(addresses)).to eq(addresses)
+ end
+ end
+
+ context 'when max_replica_pools is nil' do
+ let(:max_replica_pools) { nil }
+
+ it 'returns the same addresses' do
+ expect(sampler.sample(addresses)).to eq(addresses)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/load_balancing/service_discovery_spec.rb b/spec/lib/gitlab/database/load_balancing/service_discovery_spec.rb
index f05910e5123..984d60e9962 100644
--- a/spec/lib/gitlab/database/load_balancing/service_discovery_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/service_discovery_spec.rb
@@ -231,10 +231,13 @@ RSpec.describe Gitlab::Database::LoadBalancing::ServiceDiscovery do
nameserver: 'localhost',
port: 8600,
record: 'foo',
- record_type: record_type
+ record_type: record_type,
+ max_replica_pools: max_replica_pools
)
end
+ let(:max_replica_pools) { nil }
+
let(:packet) { double(:packet, answer: [res1, res2]) }
before do
@@ -266,24 +269,51 @@ RSpec.describe Gitlab::Database::LoadBalancing::ServiceDiscovery do
let(:res1) { double(:resource, host: 'foo1.service.consul.', port: 5432, weight: 1, priority: 1, ttl: 90) }
let(:res2) { double(:resource, host: 'foo2.service.consul.', port: 5433, weight: 1, priority: 1, ttl: 90) }
let(:res3) { double(:resource, host: 'foo3.service.consul.', port: 5434, weight: 1, priority: 1, ttl: 90) }
- let(:packet) { double(:packet, answer: [res1, res2, res3], additional: []) }
+ let(:res4) { double(:resource, host: 'foo4.service.consul.', port: 5432, weight: 1, priority: 1, ttl: 90) }
+ let(:packet) { double(:packet, answer: [res1, res2, res3, res4], additional: []) }
before do
expect_next_instance_of(Gitlab::Database::LoadBalancing::SrvResolver) do |resolver|
allow(resolver).to receive(:address_for).with('foo1.service.consul.').and_return(IPAddr.new('255.255.255.0'))
allow(resolver).to receive(:address_for).with('foo2.service.consul.').and_return(IPAddr.new('127.0.0.1'))
allow(resolver).to receive(:address_for).with('foo3.service.consul.').and_return(nil)
+ allow(resolver).to receive(:address_for).with('foo4.service.consul.').and_return("127.0.0.2")
end
end
it 'returns a TTL and ordered list of hosts' do
addresses = [
described_class::Address.new('127.0.0.1', 5433),
+ described_class::Address.new('127.0.0.2', 5432),
described_class::Address.new('255.255.255.0', 5432)
]
expect(service.addresses_from_dns).to eq([90, addresses])
end
+
+ context 'when max_replica_pools is set' do
+ context 'when the number of addresses exceeds max_replica_pools' do
+ let(:max_replica_pools) { 2 }
+
+ it 'limits to max_replica_pools' do
+ expect(service.addresses_from_dns[1].count).to eq(2)
+ end
+ end
+
+ context 'when the number of addresses is less than max_replica_pools' do
+ let(:max_replica_pools) { 5 }
+
+ it 'returns all addresses' do
+ addresses = [
+ described_class::Address.new('127.0.0.1', 5433),
+ described_class::Address.new('127.0.0.2', 5432),
+ described_class::Address.new('255.255.255.0', 5432)
+ ]
+
+ expect(service.addresses_from_dns).to eq([90, addresses])
+ end
+ end
+ end
end
context 'when the resolver returns an empty response' do
diff --git a/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb b/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb
index 88007de53d3..61b63016f1a 100644
--- a/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/sidekiq_server_middleware_spec.rb
@@ -358,7 +358,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqServerMiddleware, :clean_
end
def process_job(job)
- Sidekiq::JobRetry.new.local(worker_class, job.to_json, 'default') do
+ Sidekiq::JobRetry.new(Sidekiq).local(worker_class, job.to_json, 'default') do
worker_class.process_job(job)
end
end
diff --git a/spec/lib/gitlab/database/load_balancing/transaction_leaking_spec.rb b/spec/lib/gitlab/database/load_balancing/transaction_leaking_spec.rb
index 6026d979bcf..1eb077fe6ca 100644
--- a/spec/lib/gitlab/database/load_balancing/transaction_leaking_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing/transaction_leaking_spec.rb
@@ -4,18 +4,18 @@ require 'spec_helper'
RSpec.describe 'Load balancer behavior with errors inside a transaction', :redis, :delete do
include StubENV
- let(:model) { ApplicationRecord }
+ let(:model) { ActiveRecord::Base }
let(:db_host) { model.connection_pool.db_config.host }
let(:test_table_name) { '_test_foo' }
before do
# Patch in our load balancer config, simply pointing at the test database twice
- allow(Gitlab::Database::LoadBalancing::Configuration).to receive(:for_model) do |base_model|
+ allow(Gitlab::Database::LoadBalancing::Configuration).to receive(:for_model).with(model) do |base_model|
Gitlab::Database::LoadBalancing::Configuration.new(base_model, [db_host, db_host])
end
- Gitlab::Database::LoadBalancing::Setup.new(ApplicationRecord).setup
+ Gitlab::Database::LoadBalancing::Setup.new(model).setup
model.connection.execute(<<~SQL)
CREATE TABLE IF NOT EXISTS #{test_table_name} (id SERIAL PRIMARY KEY, value INTEGER)
@@ -30,6 +30,10 @@ RSpec.describe 'Load balancer behavior with errors inside a transaction', :redis
model.connection.execute(<<~SQL)
DROP TABLE IF EXISTS #{test_table_name}
SQL
+
+ # reset load balancing to original state
+ allow(Gitlab::Database::LoadBalancing::Configuration).to receive(:for_model).and_call_original
+ Gitlab::Database::LoadBalancing::Setup.new(model).setup
end
def execute(conn)
@@ -56,6 +60,7 @@ RSpec.describe 'Load balancer behavior with errors inside a transaction', :redis
conn = model.connection
expect(::Gitlab::Database::LoadBalancing::Logger).to receive(:warn).with(hash_including(event: :transaction_leak))
+ expect(::Gitlab::Database::LoadBalancing::Logger).to receive(:warn).with(hash_including(event: :read_write_retry))
conn.transaction do
expect(conn).to be_transaction_open
@@ -74,6 +79,8 @@ RSpec.describe 'Load balancer behavior with errors inside a transaction', :redis
expect(::Gitlab::Database::LoadBalancing::Logger)
.not_to receive(:warn).with(hash_including(event: :transaction_leak))
+ expect(::Gitlab::Database::LoadBalancing::Logger)
+ .to receive(:warn).with(hash_including(event: :read_write_retry))
expect(conn).not_to be_transaction_open
@@ -105,6 +112,8 @@ RSpec.describe 'Load balancer behavior with errors inside a transaction', :redis
it 'retries when not in a transaction' do
expect(::Gitlab::Database::LoadBalancing::Logger)
.not_to receive(:warn).with(hash_including(event: :transaction_leak))
+ expect(::Gitlab::Database::LoadBalancing::Logger)
+ .to receive(:warn).with(hash_including(event: :read_write_retry))
expect { execute(model.connection) }.not_to raise_error
end
diff --git a/spec/lib/gitlab/database/load_balancing_spec.rb b/spec/lib/gitlab/database/load_balancing_spec.rb
index 76dfaa74ae6..1c85abac91c 100644
--- a/spec/lib/gitlab/database/load_balancing_spec.rb
+++ b/spec/lib/gitlab/database/load_balancing_spec.rb
@@ -468,9 +468,10 @@ RSpec.describe Gitlab::Database::LoadBalancing, :suppress_gitlab_schemas_validat
payload = event.payload
assert =
- if payload[:name] == 'SCHEMA'
+ case payload[:name]
+ when 'SCHEMA'
false
- elsif payload[:name] == 'SQL' # Custom query
+ when 'SQL' # Custom query
true
else
keywords = %w[_test_load_balancing_test]
diff --git a/spec/lib/gitlab/database/migration_helpers/v2_spec.rb b/spec/lib/gitlab/database/migration_helpers/v2_spec.rb
index 2055dc33d48..0d75094a2fd 100644
--- a/spec/lib/gitlab/database/migration_helpers/v2_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers/v2_spec.rb
@@ -35,15 +35,15 @@ RSpec.describe Gitlab::Database::MigrationHelpers::V2 do
end
end
- context 'when the existing column has a default value' do
+ context 'when the existing column has a default function' do
before do
- migration.change_column_default :_test_table, existing_column, 'default value'
+ migration.change_column_default :_test_table, existing_column, -> { 'now()' }
end
it 'raises an error' do
expect do
migration.public_send(operation, :_test_table, :original, :renamed)
- end.to raise_error("#{operation} does not currently support columns with default values")
+ end.to raise_error("#{operation} does not currently support columns with default functions")
end
end
@@ -67,6 +67,94 @@ RSpec.describe Gitlab::Database::MigrationHelpers::V2 do
end
end
+ context 'when the existing column has a default value' do
+ before do
+ migration.change_column_default :_test_table, existing_column, 'default value'
+ end
+
+ it 'creates the renamed column, syncing existing data' do
+ existing_record_1 = model.create!(status: 0, existing_column => 'existing')
+ existing_record_2 = model.create!(status: 0)
+
+ migration.send(operation, :_test_table, :original, :renamed)
+ model.reset_column_information
+
+ expect(migration.column_exists?(:_test_table, added_column)).to eq(true)
+
+ expect(existing_record_1.reload).to have_attributes(status: 0, original: 'existing', renamed: 'existing')
+ expect(existing_record_2.reload).to have_attributes(status: 0, original: 'default value', renamed: 'default value')
+ end
+
+ it 'installs triggers to sync new data' do
+ migration.public_send(operation, :_test_table, :original, :renamed)
+ model.reset_column_information
+
+ new_record_1 = model.create!(status: 1, original: 'first')
+ new_record_2 = model.create!(status: 1, renamed: 'second')
+ new_record_3 = model.create!(status: 1)
+ new_record_4 = model.create!(status: 1)
+
+ expect(new_record_1.reload).to have_attributes(status: 1, original: 'first', renamed: 'first')
+ expect(new_record_2.reload).to have_attributes(status: 1, original: 'second', renamed: 'second')
+ expect(new_record_3.reload).to have_attributes(status: 1, original: 'default value', renamed: 'default value')
+ expect(new_record_4.reload).to have_attributes(status: 1, original: 'default value', renamed: 'default value')
+
+ new_record_1.update!(original: 'updated')
+ new_record_2.update!(renamed: nil)
+ new_record_3.update!(renamed: 'update renamed')
+ new_record_4.update!(original: 'update original')
+
+ expect(new_record_1.reload).to have_attributes(status: 1, original: 'updated', renamed: 'updated')
+ expect(new_record_2.reload).to have_attributes(status: 1, original: nil, renamed: nil)
+ expect(new_record_3.reload).to have_attributes(status: 1, original: 'update renamed', renamed: 'update renamed')
+ expect(new_record_4.reload).to have_attributes(status: 1, original: 'update original', renamed: 'update original')
+ end
+ end
+
+ context 'when the existing column has a default value that evaluates to NULL' do
+ before do
+ migration.change_column_default :_test_table, existing_column, -> { "('test' || null)" }
+ end
+
+ it 'creates the renamed column, syncing existing data' do
+ existing_record_1 = model.create!(status: 0, existing_column => 'existing')
+ existing_record_2 = model.create!(status: 0)
+
+ migration.send(operation, :_test_table, :original, :renamed)
+ model.reset_column_information
+
+ expect(migration.column_exists?(:_test_table, added_column)).to eq(true)
+
+ expect(existing_record_1.reload).to have_attributes(status: 0, original: 'existing', renamed: 'existing')
+ expect(existing_record_2.reload).to have_attributes(status: 0, original: nil, renamed: nil)
+ end
+
+ it 'installs triggers to sync new data' do
+ migration.public_send(operation, :_test_table, :original, :renamed)
+ model.reset_column_information
+
+ new_record_1 = model.create!(status: 1, original: 'first')
+ new_record_2 = model.create!(status: 1, renamed: 'second')
+ new_record_3 = model.create!(status: 1)
+ new_record_4 = model.create!(status: 1)
+
+ expect(new_record_1.reload).to have_attributes(status: 1, original: 'first', renamed: 'first')
+ expect(new_record_2.reload).to have_attributes(status: 1, original: 'second', renamed: 'second')
+ expect(new_record_3.reload).to have_attributes(status: 1, original: nil, renamed: nil)
+ expect(new_record_4.reload).to have_attributes(status: 1, original: nil, renamed: nil)
+
+ new_record_1.update!(original: 'updated')
+ new_record_2.update!(renamed: nil)
+ new_record_3.update!(renamed: 'update renamed')
+ new_record_4.update!(original: 'update original')
+
+ expect(new_record_1.reload).to have_attributes(status: 1, original: 'updated', renamed: 'updated')
+ expect(new_record_2.reload).to have_attributes(status: 1, original: nil, renamed: nil)
+ expect(new_record_3.reload).to have_attributes(status: 1, original: 'update renamed', renamed: 'update renamed')
+ expect(new_record_4.reload).to have_attributes(status: 1, original: 'update original', renamed: 'update original')
+ end
+ end
+
it 'creates the renamed column, syncing existing data' do
existing_record_1 = model.create!(status: 0, existing_column => 'existing')
existing_record_2 = model.create!(status: 0, existing_column => nil)
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index bcdd5646994..65fbc8d9935 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -389,6 +389,40 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
model.add_concurrent_index(:users, :foo)
end
+
+ context 'when targeting a partition table' do
+ let(:schema) { 'public' }
+ let(:name) { '_test_partition_01' }
+ let(:identifier) { "#{schema}.#{name}" }
+
+ before do
+ model.execute(<<~SQL)
+ CREATE TABLE public._test_partitioned_table (
+ id serial NOT NULL,
+ partition_id serial NOT NULL,
+ PRIMARY KEY (id, partition_id)
+ ) PARTITION BY LIST(partition_id);
+
+ CREATE TABLE #{identifier} PARTITION OF public._test_partitioned_table
+ FOR VALUES IN (1);
+ SQL
+ end
+
+ context 'when allow_partition is true' do
+ it 'creates the index concurrently' do
+ expect(model).to receive(:add_index).with(:_test_partition_01, :foo, algorithm: :concurrently)
+
+ model.add_concurrent_index(:_test_partition_01, :foo, allow_partition: true)
+ end
+ end
+
+ context 'when allow_partition is not provided' do
+ it 'raises ArgumentError' do
+ expect { model.add_concurrent_index(:_test_partition_01, :foo) }
+ .to raise_error(ArgumentError, /use add_concurrent_partitioned_index/)
+ end
+ end
+ end
end
context 'inside a transaction' do
@@ -435,6 +469,37 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
model.remove_concurrent_index(:users, :foo)
end
+ context 'when targeting a partition table' do
+ let(:schema) { 'public' }
+ let(:partition_table_name) { '_test_partition_01' }
+ let(:identifier) { "#{schema}.#{partition_table_name}" }
+ let(:index_name) { '_test_partitioned_index' }
+ let(:partition_index_name) { '_test_partition_01_partition_id_idx' }
+ let(:column_name) { 'partition_id' }
+
+ before do
+ model.execute(<<~SQL)
+ CREATE TABLE public._test_partitioned_table (
+ id serial NOT NULL,
+ partition_id serial NOT NULL,
+ PRIMARY KEY (id, partition_id)
+ ) PARTITION BY LIST(partition_id);
+
+ CREATE INDEX #{index_name} ON public._test_partitioned_table(#{column_name});
+
+ CREATE TABLE #{identifier} PARTITION OF public._test_partitioned_table
+ FOR VALUES IN (1);
+ SQL
+ end
+
+ context 'when dropping an index on the partition table' do
+ it 'raises ArgumentError' do
+ expect { model.remove_concurrent_index(partition_table_name, column_name) }
+ .to raise_error(ArgumentError, /use remove_concurrent_partitioned_index_by_name/)
+ end
+ end
+ end
+
describe 'by index name' do
before do
allow(model).to receive(:index_exists_by_name?).with(:users, "index_x_by_y").and_return(true)
@@ -476,6 +541,36 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
model.remove_concurrent_index_by_name(:users, "index_x_by_y")
end
+
+ context 'when targeting a partition table' do
+ let(:schema) { 'public' }
+ let(:partition_table_name) { '_test_partition_01' }
+ let(:identifier) { "#{schema}.#{partition_table_name}" }
+ let(:index_name) { '_test_partitioned_index' }
+ let(:partition_index_name) { '_test_partition_01_partition_id_idx' }
+
+ before do
+ model.execute(<<~SQL)
+ CREATE TABLE public._test_partitioned_table (
+ id serial NOT NULL,
+ partition_id serial NOT NULL,
+ PRIMARY KEY (id, partition_id)
+ ) PARTITION BY LIST(partition_id);
+
+ CREATE INDEX #{index_name} ON public._test_partitioned_table(partition_id);
+
+ CREATE TABLE #{identifier} PARTITION OF public._test_partitioned_table
+ FOR VALUES IN (1);
+ SQL
+ end
+
+ context 'when dropping an index on the partition table' do
+ it 'raises ArgumentError' do
+ expect { model.remove_concurrent_index_by_name(partition_table_name, partition_index_name) }
+ .to raise_error(ArgumentError, /use remove_concurrent_partitioned_index_by_name/)
+ end
+ end
+ end
end
end
end
@@ -1006,88 +1101,6 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
end
end
- describe '#disable_statement_timeout' do
- it 'disables statement timeouts to current transaction only' do
- expect(model).to receive(:execute).with('SET LOCAL statement_timeout TO 0')
-
- model.disable_statement_timeout
- end
-
- # this specs runs without an enclosing transaction (:delete truncation method for db_cleaner)
- context 'with real environment', :delete do
- before do
- model.execute("SET statement_timeout TO '20000'")
- end
-
- after do
- model.execute('RESET statement_timeout')
- end
-
- it 'defines statement to 0 only for current transaction' do
- expect(model.execute('SHOW statement_timeout').first['statement_timeout']).to eq('20s')
-
- model.connection.transaction do
- model.disable_statement_timeout
- expect(model.execute('SHOW statement_timeout').first['statement_timeout']).to eq('0')
- end
-
- expect(model.execute('SHOW statement_timeout').first['statement_timeout']).to eq('20s')
- end
-
- context 'when passing a blocks' do
- it 'disables statement timeouts on session level and executes the block' do
- expect(model).to receive(:execute).with('SET statement_timeout TO 0')
- expect(model).to receive(:execute).with('RESET statement_timeout').at_least(:once)
-
- expect { |block| model.disable_statement_timeout(&block) }.to yield_control
- end
-
- # this specs runs without an enclosing transaction (:delete truncation method for db_cleaner)
- context 'with real environment', :delete do
- before do
- model.execute("SET statement_timeout TO '20000'")
- end
-
- after do
- model.execute('RESET statement_timeout')
- end
-
- it 'defines statement to 0 for any code run inside the block' do
- expect(model.execute('SHOW statement_timeout').first['statement_timeout']).to eq('20s')
-
- model.disable_statement_timeout do
- model.connection.transaction do
- expect(model.execute('SHOW statement_timeout').first['statement_timeout']).to eq('0')
- end
-
- expect(model.execute('SHOW statement_timeout').first['statement_timeout']).to eq('0')
- end
- end
- end
- end
- end
-
- # This spec runs without an enclosing transaction (:delete truncation method for db_cleaner)
- context 'when the statement_timeout is already disabled', :delete do
- before do
- ActiveRecord::Migration.connection.execute('SET statement_timeout TO 0')
- end
-
- after do
- # Use ActiveRecord::Migration.connection instead of model.execute
- # so that this call is not counted below
- ActiveRecord::Migration.connection.execute('RESET statement_timeout')
- end
-
- it 'yields control without disabling the timeout or resetting' do
- expect(model).not_to receive(:execute).with('SET statement_timeout TO 0')
- expect(model).not_to receive(:execute).with('RESET statement_timeout')
-
- expect { |block| model.disable_statement_timeout(&block) }.to yield_control
- end
- end
- end
-
describe '#true_value' do
it 'returns the appropriate value' do
expect(model.true_value).to eq("'t'")
@@ -2006,8 +2019,116 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
end
end
+ let(:same_queue_different_worker) do
+ Class.new do
+ include Sidekiq::Worker
+
+ sidekiq_options queue: 'test'
+
+ def self.name
+ 'SameQueueDifferentWorkerClass'
+ end
+ end
+ end
+
+ let(:unrelated_worker) do
+ Class.new do
+ include Sidekiq::Worker
+
+ sidekiq_options queue: 'unrelated'
+
+ def self.name
+ 'UnrelatedWorkerClass'
+ end
+ end
+ end
+
before do
stub_const(worker.name, worker)
+ stub_const(unrelated_worker.name, unrelated_worker)
+ stub_const(same_queue_different_worker.name, same_queue_different_worker)
+ end
+
+ describe '#sidekiq_remove_jobs', :clean_gitlab_redis_queues do
+ def clear_queues
+ Sidekiq::Queue.new('test').clear
+ Sidekiq::Queue.new('unrelated').clear
+ Sidekiq::RetrySet.new.clear
+ Sidekiq::ScheduledSet.new.clear
+ end
+
+ around do |example|
+ clear_queues
+ Sidekiq::Testing.disable!(&example)
+ clear_queues
+ end
+
+ it "removes all related job instances from the job class's queue" do
+ worker.perform_async
+ same_queue_different_worker.perform_async
+ unrelated_worker.perform_async
+
+ queue_we_care_about = Sidekiq::Queue.new(worker.queue)
+ unrelated_queue = Sidekiq::Queue.new(unrelated_worker.queue)
+
+ expect(queue_we_care_about.size).to eq(2)
+ expect(unrelated_queue.size).to eq(1)
+
+ model.sidekiq_remove_jobs(job_klass: worker)
+
+ expect(queue_we_care_about.size).to eq(1)
+ expect(queue_we_care_about.map(&:klass)).not_to include(worker.name)
+ expect(queue_we_care_about.map(&:klass)).to include(
+ same_queue_different_worker.name
+ )
+ expect(unrelated_queue.size).to eq(1)
+ end
+
+ context 'when job instances are in the scheduled set' do
+ it 'removes all related job instances from the scheduled set' do
+ worker.perform_in(1.hour)
+ unrelated_worker.perform_in(1.hour)
+
+ scheduled = Sidekiq::ScheduledSet.new
+
+ expect(scheduled.size).to eq(2)
+ expect(scheduled.map(&:klass)).to include(
+ worker.name,
+ unrelated_worker.name
+ )
+
+ model.sidekiq_remove_jobs(job_klass: worker)
+
+ expect(scheduled.size).to eq(1)
+ expect(scheduled.map(&:klass)).not_to include(worker.name)
+ expect(scheduled.map(&:klass)).to include(unrelated_worker.name)
+ end
+ end
+
+ context 'when job instances are in the retry set' do
+ include_context 'when handling retried jobs'
+
+ it 'removes all related job instances from the retry set' do
+ retry_in(worker, 1.hour)
+ retry_in(worker, 2.hours)
+ retry_in(worker, 3.hours)
+ retry_in(unrelated_worker, 4.hours)
+
+ retries = Sidekiq::RetrySet.new
+
+ expect(retries.size).to eq(4)
+ expect(retries.map(&:klass)).to include(
+ worker.name,
+ unrelated_worker.name
+ )
+
+ model.sidekiq_remove_jobs(job_klass: worker)
+
+ expect(retries.size).to eq(1)
+ expect(retries.map(&:klass)).not_to include(worker.name)
+ expect(retries.map(&:klass)).to include(unrelated_worker.name)
+ end
+ end
end
describe '#sidekiq_queue_length' do
@@ -2031,7 +2152,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
end
end
- describe '#migrate_sidekiq_queue' do
+ describe '#sidekiq_queue_migrate' do
it 'migrates jobs from one sidekiq queue to another' do
Sidekiq::Testing.disable! do
worker.perform_async('Something', [1])
@@ -2071,6 +2192,110 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
end
end
+ describe '#convert_to_type_column' do
+ it 'returns the name of the temporary column used to convert to bigint' do
+ expect(model.convert_to_type_column(:id, :int, :bigint)).to eq('id_convert_int_to_bigint')
+ end
+
+ it 'returns the name of the temporary column used to convert to uuid' do
+ expect(model.convert_to_type_column(:uuid, :string, :uuid)).to eq('uuid_convert_string_to_uuid')
+ end
+ end
+
+ describe '#create_temporary_columns_and_triggers' do
+ let(:table) { :test_table }
+ let(:column) { :id }
+ let(:mappings) do
+ {
+ id: {
+ from_type: :int,
+ to_type: :bigint
+ }
+ }
+ end
+
+ let(:old_bigint_column_naming) { false }
+
+ subject do
+ model.create_temporary_columns_and_triggers(
+ table,
+ mappings,
+ old_bigint_column_naming: old_bigint_column_naming
+ )
+ end
+
+ before do
+ model.create_table table, id: false do |t|
+ t.integer :id, primary_key: true
+ t.integer :non_nullable_column, null: false
+ t.integer :nullable_column
+ t.timestamps
+ end
+ end
+
+ context 'when no mappings are provided' do
+ let(:mappings) { nil }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error("No mappings for column conversion provided")
+ end
+ end
+
+ context 'when any of the mappings does not have the required keys' do
+ let(:mappings) do
+ {
+ id: {
+ from_type: :int
+ }
+ }
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error("Some mappings don't have required keys provided")
+ end
+ end
+
+ context 'when the target table does not exist' do
+ it 'raises an error' do
+ expect { model.create_temporary_columns_and_triggers(:non_existent_table, mappings) }.to raise_error("Table non_existent_table does not exist")
+ end
+ end
+
+ context 'when the column to migrate does not exist' do
+ let(:missing_column) { :test }
+ let(:mappings) do
+ {
+ missing_column => {
+ from_type: :int,
+ to_type: :bigint
+ }
+ }
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error("Column #{missing_column} does not exist on #{table}")
+ end
+ end
+
+ context 'when old_bigint_column_naming is true' do
+ let(:old_bigint_column_naming) { true }
+
+ it 'calls convert_to_bigint_column' do
+ expect(model).to receive(:convert_to_bigint_column).with(:id).and_return("id_convert_to_bigint")
+
+ subject
+ end
+ end
+
+ context 'when old_bigint_column_naming is false' do
+ it 'calls convert_to_type_column' do
+ expect(model).to receive(:convert_to_type_column).with(:id, :int, :bigint).and_return("id_convert_to_bigint")
+
+ subject
+ end
+ end
+ end
+
describe '#initialize_conversion_of_integer_to_bigint' do
let(:table) { :test_table }
let(:column) { :id }
@@ -2227,7 +2452,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
let(:columns) { :id }
it 'removes column, trigger, and function' do
- temporary_column = model.convert_to_bigint_column(:id)
+ temporary_column = model.convert_to_bigint_column(columns)
trigger_name = model.rename_trigger_name(table, :id, temporary_column)
model.revert_initialize_conversion_of_integer_to_bigint(table, columns)
@@ -2420,101 +2645,6 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
end
end
- describe '#ensure_batched_background_migration_is_finished' do
- let(:job_class_name) { 'CopyColumnUsingBackgroundMigrationJob' }
- let(:table) { :events }
- let(:column_name) { :id }
- let(:job_arguments) { [["id"], ["id_convert_to_bigint"], nil] }
-
- let(:configuration) do
- {
- job_class_name: job_class_name,
- table_name: table,
- column_name: column_name,
- job_arguments: job_arguments
- }
- end
-
- let(:migration_attributes) do
- configuration.merge(gitlab_schema: Gitlab::Database.gitlab_schemas_for_connection(model.connection).first)
- end
-
- before do
- allow(model).to receive(:transaction_open?).and_return(false)
- end
-
- subject(:ensure_batched_background_migration_is_finished) { model.ensure_batched_background_migration_is_finished(**configuration) }
-
- it 'raises an error when migration exists and is not marked as finished' do
- expect(Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas).to receive(:require_dml_mode!).twice
-
- create(:batched_background_migration, :active, migration_attributes)
-
- allow_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationRunner) do |runner|
- allow(runner).to receive(:finalize).with(job_class_name, table, column_name, job_arguments).and_return(false)
- end
-
- expect { ensure_batched_background_migration_is_finished }
- .to raise_error "Expected batched background migration for the given configuration to be marked as 'finished', but it is 'active':" \
- "\t#{configuration}" \
- "\n\n" \
- "Finalize it manually by running the following command in a `bash` or `sh` shell:" \
- "\n\n" \
- "\tsudo gitlab-rake gitlab:background_migrations:finalize[CopyColumnUsingBackgroundMigrationJob,events,id,'[[\"id\"]\\,[\"id_convert_to_bigint\"]\\,null]']" \
- "\n\n" \
- "For more information, check the documentation" \
- "\n\n" \
- "\thttps://docs.gitlab.com/ee/user/admin_area/monitoring/background_migrations.html#database-migrations-failing-because-of-batched-background-migration-not-finished"
- end
-
- it 'does not raise error when migration exists and is marked as finished' do
- expect(Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas).to receive(:require_dml_mode!)
-
- create(:batched_background_migration, :finished, migration_attributes)
-
- expect { ensure_batched_background_migration_is_finished }
- .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!)
-
- create(:batched_background_migration, :active, migration_attributes.merge(gitlab_schema: :gitlab_something_else))
-
- 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
-
- it 'finalizes the migration' do
- expect(Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas).to receive(:require_dml_mode!).twice
-
- migration = create(:batched_background_migration, :active, configuration)
-
- allow_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationRunner) do |runner|
- expect(runner).to receive(:finalize).with(job_class_name, table, column_name, job_arguments).and_return(migration.finish!)
- end
-
- ensure_batched_background_migration_is_finished
- end
-
- context 'when the flag finalize is false' do
- it 'does not finalize the migration' do
- expect(Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas).to receive(:require_dml_mode!)
-
- create(:batched_background_migration, :active, configuration)
-
- allow_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationRunner) do |runner|
- expect(runner).not_to receive(:finalize).with(job_class_name, table, column_name, job_arguments)
- end
-
- expect { model.ensure_batched_background_migration_is_finished(**configuration.merge(finalize: false)) }.to raise_error(RuntimeError)
- end
- end
- end
-
describe '#index_exists_by_name?' do
it 'returns true if an index exists' do
ActiveRecord::Migration.connection.execute(
@@ -2621,48 +2751,6 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
end
end
- describe '#with_lock_retries' do
- let(:buffer) { StringIO.new }
- let(:in_memory_logger) { Gitlab::JsonLogger.new(buffer) }
- let(:env) { { 'DISABLE_LOCK_RETRIES' => 'true' } }
-
- it 'sets the migration class name in the logs' do
- model.with_lock_retries(env: env, logger: in_memory_logger) {}
-
- buffer.rewind
- expect(buffer.read).to include("\"class\":\"#{model.class}\"")
- end
-
- where(raise_on_exhaustion: [true, false])
-
- with_them do
- it 'sets raise_on_exhaustion as requested' do
- with_lock_retries = double
- expect(Gitlab::Database::WithLockRetries).to receive(:new).and_return(with_lock_retries)
- expect(with_lock_retries).to receive(:run).with(raise_on_exhaustion: raise_on_exhaustion)
-
- model.with_lock_retries(env: env, logger: in_memory_logger, raise_on_exhaustion: raise_on_exhaustion) {}
- end
- end
-
- it 'does not raise on exhaustion by default' do
- with_lock_retries = double
- expect(Gitlab::Database::WithLockRetries).to receive(:new).and_return(with_lock_retries)
- expect(with_lock_retries).to receive(:run).with(raise_on_exhaustion: false)
-
- model.with_lock_retries(env: env, logger: in_memory_logger) {}
- end
-
- it 'defaults to allowing subtransactions' do
- with_lock_retries = double
-
- expect(Gitlab::Database::WithLockRetries).to receive(:new).with(hash_including(allow_savepoints: true)).and_return(with_lock_retries)
- expect(with_lock_retries).to receive(:run).with(raise_on_exhaustion: false)
-
- model.with_lock_retries(env: env, logger: in_memory_logger) {}
- end
- end
-
describe '#backfill_iids' do
include MigrationsHelpers
@@ -2778,720 +2866,6 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
end
end
- describe '#check_constraint_name' do
- it 'returns a valid constraint name' do
- name = model.check_constraint_name(:this_is_a_very_long_table_name,
- :with_a_very_long_column_name,
- :with_a_very_long_type)
-
- expect(name).to be_an_instance_of(String)
- expect(name).to start_with('check_')
- expect(name.length).to eq(16)
- end
- end
-
- describe '#check_constraint_exists?' 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)'
- )
- end
-
- it 'returns true if a constraint exists' do
- expect(model.check_constraint_exists?(:projects, 'check_1'))
- .to be_truthy
- end
-
- it 'returns false if a constraint does not exist' do
- expect(model.check_constraint_exists?(:projects, 'this_does_not_exist'))
- .to be_falsy
- end
-
- it 'returns false if a constraint with the same name exists in another table' do
- expect(model.check_constraint_exists?(:users, 'check_1'))
- .to be_falsy
- end
-
- it 'returns false if a constraint with the same name exists for the same table in another schema' do
- expect(model.check_constraint_exists?(:projects, 'check_2'))
- .to be_falsy
- end
- end
-
- describe '#add_check_constraint' do
- before do
- allow(model).to receive(:check_constraint_exists?).and_return(false)
- end
-
- context 'constraint name validation' do
- it 'raises an error when too long' do
- expect do
- model.add_check_constraint(
- :test_table,
- 'name IS NOT NULL',
- 'a' * (Gitlab::Database::MigrationHelpers::MAX_IDENTIFIER_NAME_LENGTH + 1)
- )
- end.to raise_error(RuntimeError)
- end
-
- it 'does not raise error when the length is acceptable' do
- constraint_name = 'a' * Gitlab::Database::MigrationHelpers::MAX_IDENTIFIER_NAME_LENGTH
-
- expect(model).to receive(:transaction_open?).and_return(false)
- expect(model).to receive(:check_constraint_exists?).and_return(false)
- expect(model).to receive(:with_lock_retries).and_call_original
- expect(model).to receive(:execute).with(/ADD CONSTRAINT/)
-
- model.add_check_constraint(
- :test_table,
- 'name IS NOT NULL',
- constraint_name,
- validate: false
- )
- end
- end
-
- context 'inside a transaction' do
- it 'raises an error' do
- expect(model).to receive(:transaction_open?).and_return(true)
-
- expect do
- model.add_check_constraint(
- :test_table,
- 'name IS NOT NULL',
- 'check_name_not_null'
- )
- end.to raise_error(RuntimeError)
- end
- end
-
- context 'outside a transaction' do
- before do
- allow(model).to receive(:transaction_open?).and_return(false)
- end
-
- context 'when the constraint is already defined in the database' do
- it 'does not create a constraint' do
- expect(model).to receive(:check_constraint_exists?)
- .with(:test_table, 'check_name_not_null')
- .and_return(true)
-
- expect(model).not_to receive(:execute).with(/ADD CONSTRAINT/)
-
- # setting validate: false to only focus on the ADD CONSTRAINT command
- model.add_check_constraint(
- :test_table,
- 'name IS NOT NULL',
- 'check_name_not_null',
- validate: false
- )
- end
- end
-
- context 'when the constraint is not defined in the database' do
- it 'creates the constraint' do
- expect(model).to receive(:with_lock_retries).and_call_original
- expect(model).to receive(:execute).with(/ADD CONSTRAINT check_name_not_null/)
-
- # setting validate: false to only focus on the ADD CONSTRAINT command
- model.add_check_constraint(
- :test_table,
- 'char_length(name) <= 255',
- 'check_name_not_null',
- validate: false
- )
- end
- end
-
- context 'when validate is not provided' do
- it 'performs validation' do
- expect(model).to receive(:check_constraint_exists?)
- .with(:test_table, 'check_name_not_null')
- .and_return(false).exactly(1)
-
- 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(:with_lock_retries).and_call_original
- expect(model).to receive(:execute).with(/ADD CONSTRAINT check_name_not_null/)
-
- # we need the check constraint to exist so that the validation proceeds
- expect(model).to receive(:check_constraint_exists?)
- .with(:test_table, 'check_name_not_null')
- .and_return(true).exactly(1)
-
- expect(model).to receive(:execute).ordered.with(/VALIDATE CONSTRAINT/)
- expect(model).to receive(:execute).ordered.with(/RESET statement_timeout/)
-
- model.add_check_constraint(
- :test_table,
- 'char_length(name) <= 255',
- 'check_name_not_null'
- )
- end
- end
-
- context 'when validate is provided with a falsey value' do
- it 'skips validation' do
- expect(model).not_to receive(:disable_statement_timeout)
- expect(model).to receive(:with_lock_retries).and_call_original
- expect(model).to receive(:execute).with(/ADD CONSTRAINT/)
- expect(model).not_to receive(:execute).with(/VALIDATE CONSTRAINT/)
-
- model.add_check_constraint(
- :test_table,
- 'char_length(name) <= 255',
- 'check_name_not_null',
- validate: false
- )
- end
- end
-
- context 'when validate is provided with a truthy value' do
- it 'performs validation' do
- expect(model).to receive(:check_constraint_exists?)
- .with(:test_table, 'check_name_not_null')
- .and_return(false).exactly(1)
-
- 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(:with_lock_retries).and_call_original
- expect(model).to receive(:execute).with(/ADD CONSTRAINT check_name_not_null/)
-
- expect(model).to receive(:check_constraint_exists?)
- .with(:test_table, 'check_name_not_null')
- .and_return(true).exactly(1)
-
- expect(model).to receive(:execute).ordered.with(/VALIDATE CONSTRAINT/)
- expect(model).to receive(:execute).ordered.with(/RESET statement_timeout/)
-
- model.add_check_constraint(
- :test_table,
- 'char_length(name) <= 255',
- 'check_name_not_null',
- validate: true
- )
- end
- end
- end
- end
-
- describe '#validate_check_constraint' do
- context 'when the constraint does not exist' do
- it 'raises an error' do
- error_message = /Could not find check constraint "check_1" on table "test_table"/
-
- expect(model).to receive(:check_constraint_exists?).and_return(false)
-
- expect do
- model.validate_check_constraint(:test_table, 'check_1')
- end.to raise_error(RuntimeError, error_message)
- end
- end
-
- context 'when the constraint exists' do
- it 'performs validation' do
- validate_sql = /ALTER TABLE test_table VALIDATE CONSTRAINT check_name/
-
- expect(model).to receive(:check_constraint_exists?).and_return(true)
- 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_sql)
- expect(model).to receive(:execute).ordered.with(/RESET statement_timeout/)
-
- model.validate_check_constraint(:test_table, 'check_name')
- end
- end
- end
-
- describe '#remove_check_constraint' do
- before do
- allow(model).to receive(:transaction_open?).and_return(false)
- end
-
- it 'removes the constraint' do
- drop_sql = /ALTER TABLE test_table\s+DROP CONSTRAINT IF EXISTS check_name/
-
- expect(model).to receive(:with_lock_retries).and_call_original
- expect(model).to receive(:execute).with(drop_sql)
-
- model.remove_check_constraint(:test_table, 'check_name')
- end
- end
-
- describe '#copy_check_constraints' do
- context 'inside a transaction' do
- it 'raises an error' do
- expect(model).to receive(:transaction_open?).and_return(true)
-
- expect do
- model.copy_check_constraints(:test_table, :old_column, :new_column)
- end.to raise_error(RuntimeError)
- end
- end
-
- context 'outside a transaction' do
- before do
- allow(model).to receive(:transaction_open?).and_return(false)
- allow(model).to receive(:column_exists?).and_return(true)
- end
-
- let(:old_column_constraints) do
- [
- {
- 'schema_name' => 'public',
- 'table_name' => 'test_table',
- 'column_name' => 'old_column',
- 'constraint_name' => 'check_d7d49d475d',
- 'constraint_def' => 'CHECK ((old_column IS NOT NULL))'
- },
- {
- 'schema_name' => 'public',
- 'table_name' => 'test_table',
- 'column_name' => 'old_column',
- 'constraint_name' => 'check_48560e521e',
- 'constraint_def' => 'CHECK ((char_length(old_column) <= 255))'
- },
- {
- 'schema_name' => 'public',
- 'table_name' => 'test_table',
- 'column_name' => 'old_column',
- 'constraint_name' => 'custom_check_constraint',
- 'constraint_def' => 'CHECK (((old_column IS NOT NULL) AND (another_column IS NULL)))'
- },
- {
- 'schema_name' => 'public',
- 'table_name' => 'test_table',
- 'column_name' => 'old_column',
- 'constraint_name' => 'not_valid_check_constraint',
- 'constraint_def' => 'CHECK ((old_column IS NOT NULL)) NOT VALID'
- }
- ]
- end
-
- it 'copies check constraints from one column to another' do
- allow(model).to receive(:check_constraints_for)
- .with(:test_table, :old_column, schema: nil)
- .and_return(old_column_constraints)
-
- allow(model).to receive(:not_null_constraint_name).with(:test_table, :new_column)
- .and_return('check_1')
-
- allow(model).to receive(:text_limit_name).with(:test_table, :new_column)
- .and_return('check_2')
-
- allow(model).to receive(:check_constraint_name)
- .with(:test_table, :new_column, 'copy_check_constraint')
- .and_return('check_3')
-
- expect(model).to receive(:add_check_constraint)
- .with(
- :test_table,
- '(new_column IS NOT NULL)',
- 'check_1',
- validate: true
- ).once
-
- expect(model).to receive(:add_check_constraint)
- .with(
- :test_table,
- '(char_length(new_column) <= 255)',
- 'check_2',
- validate: true
- ).once
-
- expect(model).to receive(:add_check_constraint)
- .with(
- :test_table,
- '((new_column IS NOT NULL) AND (another_column IS NULL))',
- 'check_3',
- validate: true
- ).once
-
- expect(model).to receive(:add_check_constraint)
- .with(
- :test_table,
- '(new_column IS NOT NULL)',
- 'check_1',
- validate: false
- ).once
-
- model.copy_check_constraints(:test_table, :old_column, :new_column)
- end
-
- it 'does nothing if there are no constraints defined for the old column' do
- allow(model).to receive(:check_constraints_for)
- .with(:test_table, :old_column, schema: nil)
- .and_return([])
-
- expect(model).not_to receive(:add_check_constraint)
-
- model.copy_check_constraints(:test_table, :old_column, :new_column)
- end
-
- it 'raises an error when the orginating column does not exist' do
- allow(model).to receive(:column_exists?).with(:test_table, :old_column).and_return(false)
-
- error_message = /Column old_column does not exist on test_table/
-
- expect do
- model.copy_check_constraints(:test_table, :old_column, :new_column)
- end.to raise_error(RuntimeError, error_message)
- end
-
- it 'raises an error when the target column does not exist' do
- allow(model).to receive(:column_exists?).with(:test_table, :new_column).and_return(false)
-
- error_message = /Column new_column does not exist on test_table/
-
- expect do
- model.copy_check_constraints(:test_table, :old_column, :new_column)
- end.to raise_error(RuntimeError, error_message)
- end
- end
- end
-
- describe '#add_text_limit' do
- context 'when it is called with the default options' do
- it 'calls add_check_constraint with an infered constraint name and validate: true' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'max_length')
- check = "char_length(name) <= 255"
-
- expect(model).to receive(:check_constraint_name).and_call_original
- expect(model).to receive(:add_check_constraint)
- .with(:test_table, check, constraint_name, validate: true)
-
- model.add_text_limit(:test_table, :name, 255)
- end
- end
-
- context 'when all parameters are provided' do
- it 'calls add_check_constraint with the correct parameters' do
- constraint_name = 'check_name_limit'
- check = "char_length(name) <= 255"
-
- expect(model).not_to receive(:check_constraint_name)
- expect(model).to receive(:add_check_constraint)
- .with(:test_table, check, constraint_name, validate: false)
-
- model.add_text_limit(
- :test_table,
- :name,
- 255,
- constraint_name: constraint_name,
- validate: false
- )
- end
- end
- end
-
- describe '#validate_text_limit' do
- context 'when constraint_name is not provided' do
- it 'calls validate_check_constraint with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'max_length')
-
- expect(model).to receive(:check_constraint_name).and_call_original
- expect(model).to receive(:validate_check_constraint)
- .with(:test_table, constraint_name)
-
- model.validate_text_limit(:test_table, :name)
- end
- end
-
- context 'when constraint_name is provided' do
- it 'calls validate_check_constraint with the correct parameters' do
- constraint_name = 'check_name_limit'
-
- expect(model).not_to receive(:check_constraint_name)
- expect(model).to receive(:validate_check_constraint)
- .with(:test_table, constraint_name)
-
- model.validate_text_limit(:test_table, :name, constraint_name: constraint_name)
- end
- end
- end
-
- describe '#remove_text_limit' do
- context 'when constraint_name is not provided' do
- it 'calls remove_check_constraint with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'max_length')
-
- expect(model).to receive(:check_constraint_name).and_call_original
- expect(model).to receive(:remove_check_constraint)
- .with(:test_table, constraint_name)
-
- model.remove_text_limit(:test_table, :name)
- end
- end
-
- context 'when constraint_name is provided' do
- it 'calls remove_check_constraint with the correct parameters' do
- constraint_name = 'check_name_limit'
-
- expect(model).not_to receive(:check_constraint_name)
- expect(model).to receive(:remove_check_constraint)
- .with(:test_table, constraint_name)
-
- model.remove_text_limit(:test_table, :name, constraint_name: constraint_name)
- end
- end
- end
-
- describe '#check_text_limit_exists?' do
- context 'when constraint_name is not provided' do
- it 'calls check_constraint_exists? with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'max_length')
-
- expect(model).to receive(:check_constraint_name).and_call_original
- expect(model).to receive(:check_constraint_exists?)
- .with(:test_table, constraint_name)
-
- model.check_text_limit_exists?(:test_table, :name)
- end
- end
-
- context 'when constraint_name is provided' do
- it 'calls check_constraint_exists? with the correct parameters' do
- constraint_name = 'check_name_limit'
-
- expect(model).not_to receive(:check_constraint_name)
- expect(model).to receive(:check_constraint_exists?)
- .with(:test_table, constraint_name)
-
- model.check_text_limit_exists?(:test_table, :name, constraint_name: constraint_name)
- end
- end
- end
-
- describe '#add_not_null_constraint' do
- context 'when it is called with the default options' do
- it 'calls add_check_constraint with an infered constraint name and validate: true' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'not_null')
- check = "name IS NOT NULL"
-
- expect(model).to receive(:column_is_nullable?).and_return(true)
- expect(model).to receive(:check_constraint_name).and_call_original
- expect(model).to receive(:add_check_constraint)
- .with(:test_table, check, constraint_name, validate: true)
-
- model.add_not_null_constraint(:test_table, :name)
- end
- end
-
- context 'when all parameters are provided' do
- it 'calls add_check_constraint with the correct parameters' do
- constraint_name = 'check_name_not_null'
- check = "name IS NOT NULL"
-
- expect(model).to receive(:column_is_nullable?).and_return(true)
- expect(model).not_to receive(:check_constraint_name)
- expect(model).to receive(:add_check_constraint)
- .with(:test_table, check, constraint_name, validate: false)
-
- model.add_not_null_constraint(
- :test_table,
- :name,
- constraint_name: constraint_name,
- validate: false
- )
- end
- end
-
- context 'when the column is defined as NOT NULL' do
- it 'does not add a check constraint' do
- expect(model).to receive(:column_is_nullable?).and_return(false)
- expect(model).not_to receive(:check_constraint_name)
- expect(model).not_to receive(:add_check_constraint)
-
- model.add_not_null_constraint(:test_table, :name)
- end
- end
- end
-
- describe '#validate_not_null_constraint' do
- context 'when constraint_name is not provided' do
- it 'calls validate_check_constraint with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'not_null')
-
- expect(model).to receive(:check_constraint_name).and_call_original
- expect(model).to receive(:validate_check_constraint)
- .with(:test_table, constraint_name)
-
- model.validate_not_null_constraint(:test_table, :name)
- end
- end
-
- context 'when constraint_name is provided' do
- it 'calls validate_check_constraint with the correct parameters' do
- constraint_name = 'check_name_not_null'
-
- expect(model).not_to receive(:check_constraint_name)
- expect(model).to receive(:validate_check_constraint)
- .with(:test_table, constraint_name)
-
- model.validate_not_null_constraint(:test_table, :name, constraint_name: constraint_name)
- end
- end
- end
-
- describe '#remove_not_null_constraint' do
- context 'when constraint_name is not provided' do
- it 'calls remove_check_constraint with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'not_null')
-
- expect(model).to receive(:check_constraint_name).and_call_original
- expect(model).to receive(:remove_check_constraint)
- .with(:test_table, constraint_name)
-
- model.remove_not_null_constraint(:test_table, :name)
- end
- end
-
- context 'when constraint_name is provided' do
- it 'calls remove_check_constraint with the correct parameters' do
- constraint_name = 'check_name_not_null'
-
- expect(model).not_to receive(:check_constraint_name)
- expect(model).to receive(:remove_check_constraint)
- .with(:test_table, constraint_name)
-
- model.remove_not_null_constraint(:test_table, :name, constraint_name: constraint_name)
- end
- end
- end
-
- describe '#check_not_null_constraint_exists?' do
- context 'when constraint_name is not provided' do
- it 'calls check_constraint_exists? with an infered constraint name' do
- constraint_name = model.check_constraint_name(:test_table,
- :name,
- 'not_null')
-
- expect(model).to receive(:check_constraint_name).and_call_original
- expect(model).to receive(:check_constraint_exists?)
- .with(:test_table, constraint_name)
-
- model.check_not_null_constraint_exists?(:test_table, :name)
- end
- end
-
- context 'when constraint_name is provided' do
- it 'calls check_constraint_exists? with the correct parameters' do
- constraint_name = 'check_name_not_null'
-
- expect(model).not_to receive(:check_constraint_name)
- expect(model).to receive(:check_constraint_exists?)
- .with(:test_table, constraint_name)
-
- model.check_not_null_constraint_exists?(:test_table, :name, constraint_name: constraint_name)
- end
- end
- end
-
- describe '#create_extension' do
- subject { model.create_extension(extension) }
-
- let(:extension) { :btree_gist }
-
- it 'executes CREATE EXTENSION statement' do
- expect(model).to receive(:execute).with(/CREATE EXTENSION IF NOT EXISTS #{extension}/)
-
- subject
- end
-
- context 'without proper permissions' do
- before do
- allow(model).to receive(:execute)
- .with(/CREATE EXTENSION IF NOT EXISTS #{extension}/)
- .and_raise(ActiveRecord::StatementInvalid, 'InsufficientPrivilege: permission denied')
- end
-
- it 'raises an exception and prints an error message' do
- expect { subject }
- .to output(/user is not allowed/).to_stderr
- .and raise_error(ActiveRecord::StatementInvalid, /InsufficientPrivilege/)
- end
- end
- end
-
- describe '#drop_extension' do
- subject { model.drop_extension(extension) }
-
- let(:extension) { 'btree_gist' }
-
- it 'executes CREATE EXTENSION statement' do
- expect(model).to receive(:execute).with(/DROP EXTENSION IF EXISTS #{extension}/)
-
- subject
- end
-
- context 'without proper permissions' do
- before do
- allow(model).to receive(:execute)
- .with(/DROP EXTENSION IF EXISTS #{extension}/)
- .and_raise(ActiveRecord::StatementInvalid, 'InsufficientPrivilege: permission denied')
- end
-
- it 'raises an exception and prints an error message' do
- expect { subject }
- .to output(/user is not allowed/).to_stderr
- .and raise_error(ActiveRecord::StatementInvalid, /InsufficientPrivilege/)
- end
- end
- end
-
- describe '#rename_constraint' do
- it "executes the statement to rename constraint" do
- expect(model).to receive(:execute).with /ALTER TABLE "test_table"\nRENAME CONSTRAINT "fk_old_name" TO "fk_new_name"/
-
- model.rename_constraint(:test_table, :fk_old_name, :fk_new_name)
- end
- end
-
- describe '#drop_constraint' do
- it "executes the statement to drop the constraint" do
- expect(model).to receive(:execute).with("ALTER TABLE \"test_table\" DROP CONSTRAINT \"constraint_name\" CASCADE\n")
-
- model.drop_constraint(:test_table, :constraint_name, cascade: true)
- end
-
- context 'when cascade option is false' do
- it "executes the statement to drop the constraint without cascade" do
- expect(model).to receive(:execute).with("ALTER TABLE \"test_table\" DROP CONSTRAINT \"constraint_name\" \n")
-
- model.drop_constraint(:test_table, :constraint_name, cascade: false)
- end
- end
- end
-
describe '#add_primary_key_using_index' do
it "executes the statement to add the primary key" do
expect(model).to receive(:execute).with /ALTER TABLE "test_table" ADD CONSTRAINT "old_name" PRIMARY KEY USING INDEX "new_name"/
@@ -3558,4 +2932,36 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
model.add_sequence(:test_table, :test_column, :test_table_id_seq, 1)
end
end
+
+ describe "#partition?" do
+ subject { model.partition?(table_name) }
+
+ let(:table_name) { 'ci_builds_metadata' }
+
+ context "when a partition table exist" do
+ context 'when the view postgres_partitions exists' do
+ it 'calls the view', :aggregate_failures do
+ expect(Gitlab::Database::PostgresPartition).to receive(:partition_exists?).with(table_name).and_call_original
+ expect(subject).to be_truthy
+ end
+ end
+
+ context 'when the view postgres_partitions does not exist' do
+ before do
+ allow(model).to receive(:view_exists?).and_return(false)
+ end
+
+ it 'does not call the view', :aggregate_failures do
+ expect(Gitlab::Database::PostgresPartition).to receive(:legacy_partition_exists?).with(table_name).and_call_original
+ expect(subject).to be_truthy
+ end
+ end
+ end
+
+ context "when a partition table does not exist" do
+ let(:table_name) { 'partition_does_not_exist' }
+
+ it { is_expected.to be_falsey }
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/migrations/background_migration_helpers_spec.rb b/spec/lib/gitlab/database/migrations/background_migration_helpers_spec.rb
index f21f1ac5e52..d4fff947c29 100644
--- a/spec/lib/gitlab/database/migrations/background_migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migrations/background_migration_helpers_spec.rb
@@ -14,9 +14,6 @@ RSpec.describe Gitlab::Database::Migrations::BackgroundMigrationHelpers do
shared_examples_for 'helpers that enqueue background migrations' do |worker_class, connection_class, tracking_database|
before do
allow(model).to receive(:tracking_database).and_return(tracking_database)
-
- # Due to lib/gitlab/database/load_balancing/configuration.rb:92 requiring RequestStore
- # we cannot use stub_feature_flags(force_no_sharing_primary_model: true)
allow(connection_class.connection.load_balancer.configuration)
.to receive(:use_dedicated_connection?).and_return(true)
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 a2f6e6b43ed..3e249b14f2e 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
@@ -425,4 +425,99 @@ RSpec.describe Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers d
end
end
end
+
+ describe '#ensure_batched_background_migration_is_finished' do
+ let(:job_class_name) { 'CopyColumnUsingBackgroundMigrationJob' }
+ let(:table) { :events }
+ let(:column_name) { :id }
+ let(:job_arguments) { [["id"], ["id_convert_to_bigint"], nil] }
+
+ let(:configuration) do
+ {
+ job_class_name: job_class_name,
+ table_name: table,
+ column_name: column_name,
+ job_arguments: job_arguments
+ }
+ end
+
+ let(:migration_attributes) do
+ configuration.merge(gitlab_schema: Gitlab::Database.gitlab_schemas_for_connection(migration.connection).first)
+ end
+
+ before do
+ allow(migration).to receive(:transaction_open?).and_return(false)
+ end
+
+ subject(:ensure_batched_background_migration_is_finished) { migration.ensure_batched_background_migration_is_finished(**configuration) }
+
+ it 'raises an error when migration exists and is not marked as finished' do
+ expect(Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas).to receive(:require_dml_mode!).twice
+
+ create(:batched_background_migration, :active, migration_attributes)
+
+ allow_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationRunner) do |runner|
+ allow(runner).to receive(:finalize).with(job_class_name, table, column_name, job_arguments).and_return(false)
+ end
+
+ expect { ensure_batched_background_migration_is_finished }
+ .to raise_error "Expected batched background migration for the given configuration to be marked as 'finished', but it is 'active':" \
+ "\t#{configuration}" \
+ "\n\n" \
+ "Finalize it manually by running the following command in a `bash` or `sh` shell:" \
+ "\n\n" \
+ "\tsudo gitlab-rake gitlab:background_migrations:finalize[CopyColumnUsingBackgroundMigrationJob,events,id,'[[\"id\"]\\,[\"id_convert_to_bigint\"]\\,null]']" \
+ "\n\n" \
+ "For more information, check the documentation" \
+ "\n\n" \
+ "\thttps://docs.gitlab.com/ee/user/admin_area/monitoring/background_migrations.html#database-migrations-failing-because-of-batched-background-migration-not-finished"
+ end
+
+ it 'does not raise error when migration exists and is marked as finished' do
+ expect(Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas).to receive(:require_dml_mode!)
+
+ create(:batched_background_migration, :finished, migration_attributes)
+
+ expect { ensure_batched_background_migration_is_finished }
+ .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!)
+
+ create(:batched_background_migration, :active, migration_attributes.merge(gitlab_schema: :gitlab_something_else))
+
+ 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
+
+ it 'finalizes the migration' do
+ expect(Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas).to receive(:require_dml_mode!).twice
+
+ migration = create(:batched_background_migration, :active, configuration)
+
+ allow_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationRunner) do |runner|
+ expect(runner).to receive(:finalize).with(job_class_name, table, column_name, job_arguments).and_return(migration.finish!)
+ end
+
+ ensure_batched_background_migration_is_finished
+ end
+
+ context 'when the flag finalize is false' do
+ it 'does not finalize the migration' do
+ expect(Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas).to receive(:require_dml_mode!)
+
+ create(:batched_background_migration, :active, configuration)
+
+ allow_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationRunner) do |runner|
+ expect(runner).not_to receive(:finalize).with(job_class_name, table, column_name, job_arguments)
+ end
+
+ expect { migration.ensure_batched_background_migration_is_finished(**configuration.merge(finalize: false)) }.to raise_error(RuntimeError)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb b/spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb
new file mode 100644
index 00000000000..6848fc85aa1
--- /dev/null
+++ b/spec/lib/gitlab/database/migrations/constraints_helpers_spec.rb
@@ -0,0 +1,679 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::Migrations::ConstraintsHelpers do
+ let(:model) do
+ ActiveRecord::Migration.new.extend(described_class)
+ end
+
+ before do
+ allow(model).to receive(:puts)
+ end
+
+ describe '#check_constraint_name' do
+ it 'returns a valid constraint name' do
+ name = model.check_constraint_name(:this_is_a_very_long_table_name,
+ :with_a_very_long_column_name,
+ :with_a_very_long_type)
+
+ expect(name).to be_an_instance_of(String)
+ expect(name).to start_with('check_')
+ expect(name.length).to eq(16)
+ end
+ end
+
+ describe '#check_constraint_exists?' 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)'
+ )
+ end
+
+ it 'returns true if a constraint exists' do
+ expect(model)
+ .to be_check_constraint_exists(:projects, 'check_1')
+ end
+
+ it 'returns false if a constraint does not exist' do
+ expect(model)
+ .not_to be_check_constraint_exists(:projects, 'this_does_not_exist')
+ 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')
+ 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')
+ end
+ end
+
+ describe '#add_check_constraint' do
+ before do
+ allow(model).to receive(:check_constraint_exists?).and_return(false)
+ end
+
+ context 'when constraint name validation' do
+ it 'raises an error when too long' do
+ expect do
+ model.add_check_constraint(
+ :test_table,
+ 'name IS NOT NULL',
+ 'a' * (Gitlab::Database::MigrationHelpers::MAX_IDENTIFIER_NAME_LENGTH + 1)
+ )
+ end.to raise_error(RuntimeError)
+ end
+
+ it 'does not raise error when the length is acceptable' do
+ constraint_name = 'a' * Gitlab::Database::MigrationHelpers::MAX_IDENTIFIER_NAME_LENGTH
+
+ expect(model).to receive(:transaction_open?).and_return(false)
+ expect(model).to receive(:check_constraint_exists?).and_return(false)
+ expect(model).to receive(:with_lock_retries).and_call_original
+ expect(model).to receive(:execute).with(/ADD CONSTRAINT/)
+
+ model.add_check_constraint(
+ :test_table,
+ 'name IS NOT NULL',
+ constraint_name,
+ validate: false
+ )
+ end
+ end
+
+ context 'when inside a transaction' do
+ it 'raises an error' do
+ expect(model).to receive(:transaction_open?).and_return(true)
+
+ expect do
+ model.add_check_constraint(
+ :test_table,
+ 'name IS NOT NULL',
+ 'check_name_not_null'
+ )
+ end.to raise_error(RuntimeError)
+ end
+ end
+
+ context 'when outside a transaction' do
+ before do
+ allow(model).to receive(:transaction_open?).and_return(false)
+ end
+
+ context 'when the constraint is already defined in the database' do
+ it 'does not create a constraint' do
+ expect(model).to receive(:check_constraint_exists?)
+ .with(:test_table, 'check_name_not_null')
+ .and_return(true)
+
+ expect(model).not_to receive(:execute).with(/ADD CONSTRAINT/)
+
+ # setting validate: false to only focus on the ADD CONSTRAINT command
+ model.add_check_constraint(
+ :test_table,
+ 'name IS NOT NULL',
+ 'check_name_not_null',
+ validate: false
+ )
+ end
+ end
+
+ context 'when the constraint is not defined in the database' do
+ it 'creates the constraint' do
+ expect(model).to receive(:with_lock_retries).and_call_original
+ expect(model).to receive(:execute).with(/ADD CONSTRAINT check_name_not_null/)
+
+ # setting validate: false to only focus on the ADD CONSTRAINT command
+ model.add_check_constraint(
+ :test_table,
+ 'char_length(name) <= 255',
+ 'check_name_not_null',
+ validate: false
+ )
+ end
+ end
+
+ context 'when validate is not provided' do
+ it 'performs validation' do
+ expect(model).to receive(:check_constraint_exists?)
+ .with(:test_table, 'check_name_not_null')
+ .and_return(false).exactly(1)
+
+ 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(:with_lock_retries).and_call_original
+ expect(model).to receive(:execute).with(/ADD CONSTRAINT check_name_not_null/)
+
+ # we need the check constraint to exist so that the validation proceeds
+ expect(model).to receive(:check_constraint_exists?)
+ .with(:test_table, 'check_name_not_null')
+ .and_return(true).exactly(1)
+
+ expect(model).to receive(:execute).ordered.with(/VALIDATE CONSTRAINT/)
+ expect(model).to receive(:execute).ordered.with(/RESET statement_timeout/)
+
+ model.add_check_constraint(
+ :test_table,
+ 'char_length(name) <= 255',
+ 'check_name_not_null'
+ )
+ end
+ end
+
+ context 'when validate is provided with a falsey value' do
+ it 'skips validation' do
+ expect(model).not_to receive(:disable_statement_timeout)
+ expect(model).to receive(:with_lock_retries).and_call_original
+ expect(model).to receive(:execute).with(/ADD CONSTRAINT/)
+ expect(model).not_to receive(:execute).with(/VALIDATE CONSTRAINT/)
+
+ model.add_check_constraint(
+ :test_table,
+ 'char_length(name) <= 255',
+ 'check_name_not_null',
+ validate: false
+ )
+ end
+ end
+
+ context 'when validate is provided with a truthy value' do
+ it 'performs validation' do
+ expect(model).to receive(:check_constraint_exists?)
+ .with(:test_table, 'check_name_not_null')
+ .and_return(false).exactly(1)
+
+ 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(:with_lock_retries).and_call_original
+ expect(model).to receive(:execute).with(/ADD CONSTRAINT check_name_not_null/)
+
+ expect(model).to receive(:check_constraint_exists?)
+ .with(:test_table, 'check_name_not_null')
+ .and_return(true).exactly(1)
+
+ expect(model).to receive(:execute).ordered.with(/VALIDATE CONSTRAINT/)
+ expect(model).to receive(:execute).ordered.with(/RESET statement_timeout/)
+
+ model.add_check_constraint(
+ :test_table,
+ 'char_length(name) <= 255',
+ 'check_name_not_null',
+ validate: true
+ )
+ end
+ end
+ end
+ end
+
+ describe '#validate_check_constraint' do
+ context 'when the constraint does not exist' do
+ it 'raises an error' do
+ error_message = /Could not find check constraint "check_1" on table "test_table"/
+
+ expect(model).to receive(:check_constraint_exists?).and_return(false)
+
+ expect do
+ model.validate_check_constraint(:test_table, 'check_1')
+ end.to raise_error(RuntimeError, error_message)
+ end
+ end
+
+ context 'when the constraint exists' do
+ it 'performs validation' do
+ validate_sql = /ALTER TABLE test_table VALIDATE CONSTRAINT check_name/
+
+ expect(model).to receive(:check_constraint_exists?).and_return(true)
+ 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_sql)
+ expect(model).to receive(:execute).ordered.with(/RESET statement_timeout/)
+
+ model.validate_check_constraint(:test_table, 'check_name')
+ end
+ end
+ end
+
+ describe '#remove_check_constraint' do
+ before do
+ allow(model).to receive(:transaction_open?).and_return(false)
+ end
+
+ it 'removes the constraint' do
+ drop_sql = /ALTER TABLE test_table\s+DROP CONSTRAINT IF EXISTS check_name/
+
+ expect(model).to receive(:with_lock_retries).and_call_original
+ expect(model).to receive(:execute).with(drop_sql)
+
+ model.remove_check_constraint(:test_table, 'check_name')
+ end
+ end
+
+ describe '#copy_check_constraints' do
+ context 'when inside a transaction' do
+ it 'raises an error' do
+ expect(model).to receive(:transaction_open?).and_return(true)
+
+ expect do
+ model.copy_check_constraints(:test_table, :old_column, :new_column)
+ end.to raise_error(RuntimeError)
+ end
+ end
+
+ context 'when outside a transaction' do
+ before do
+ allow(model).to receive(:transaction_open?).and_return(false)
+ allow(model).to receive(:column_exists?).and_return(true)
+ end
+
+ let(:old_column_constraints) do
+ [
+ {
+ 'schema_name' => 'public',
+ 'table_name' => 'test_table',
+ 'column_name' => 'old_column',
+ 'constraint_name' => 'check_d7d49d475d',
+ 'constraint_def' => 'CHECK ((old_column IS NOT NULL))'
+ },
+ {
+ 'schema_name' => 'public',
+ 'table_name' => 'test_table',
+ 'column_name' => 'old_column',
+ 'constraint_name' => 'check_48560e521e',
+ 'constraint_def' => 'CHECK ((char_length(old_column) <= 255))'
+ },
+ {
+ 'schema_name' => 'public',
+ 'table_name' => 'test_table',
+ 'column_name' => 'old_column',
+ 'constraint_name' => 'custom_check_constraint',
+ 'constraint_def' => 'CHECK (((old_column IS NOT NULL) AND (another_column IS NULL)))'
+ },
+ {
+ 'schema_name' => 'public',
+ 'table_name' => 'test_table',
+ 'column_name' => 'old_column',
+ 'constraint_name' => 'not_valid_check_constraint',
+ 'constraint_def' => 'CHECK ((old_column IS NOT NULL)) NOT VALID'
+ }
+ ]
+ end
+
+ it 'copies check constraints from one column to another' do
+ allow(model).to receive(:check_constraints_for)
+ .with(:test_table, :old_column, schema: nil)
+ .and_return(old_column_constraints)
+
+ allow(model).to receive(:not_null_constraint_name).with(:test_table, :new_column)
+ .and_return('check_1')
+
+ allow(model).to receive(:text_limit_name).with(:test_table, :new_column)
+ .and_return('check_2')
+
+ allow(model).to receive(:check_constraint_name)
+ .with(:test_table, :new_column, 'copy_check_constraint')
+ .and_return('check_3')
+
+ expect(model).to receive(:add_check_constraint)
+ .with(
+ :test_table,
+ '(new_column IS NOT NULL)',
+ 'check_1',
+ validate: true
+ ).once
+
+ expect(model).to receive(:add_check_constraint)
+ .with(
+ :test_table,
+ '(char_length(new_column) <= 255)',
+ 'check_2',
+ validate: true
+ ).once
+
+ expect(model).to receive(:add_check_constraint)
+ .with(
+ :test_table,
+ '((new_column IS NOT NULL) AND (another_column IS NULL))',
+ 'check_3',
+ validate: true
+ ).once
+
+ expect(model).to receive(:add_check_constraint)
+ .with(
+ :test_table,
+ '(new_column IS NOT NULL)',
+ 'check_1',
+ validate: false
+ ).once
+
+ model.copy_check_constraints(:test_table, :old_column, :new_column)
+ end
+
+ it 'does nothing if there are no constraints defined for the old column' do
+ allow(model).to receive(:check_constraints_for)
+ .with(:test_table, :old_column, schema: nil)
+ .and_return([])
+
+ expect(model).not_to receive(:add_check_constraint)
+
+ model.copy_check_constraints(:test_table, :old_column, :new_column)
+ end
+
+ it 'raises an error when the orginating column does not exist' do
+ allow(model).to receive(:column_exists?).with(:test_table, :old_column).and_return(false)
+
+ error_message = /Column old_column does not exist on test_table/
+
+ expect do
+ model.copy_check_constraints(:test_table, :old_column, :new_column)
+ end.to raise_error(RuntimeError, error_message)
+ end
+
+ it 'raises an error when the target column does not exist' do
+ allow(model).to receive(:column_exists?).with(:test_table, :new_column).and_return(false)
+
+ error_message = /Column new_column does not exist on test_table/
+
+ expect do
+ model.copy_check_constraints(:test_table, :old_column, :new_column)
+ end.to raise_error(RuntimeError, error_message)
+ end
+ end
+ end
+
+ describe '#add_text_limit' do
+ context 'when it is called with the default options' do
+ it 'calls add_check_constraint with an infered constraint name and validate: true' do
+ constraint_name = model.check_constraint_name(:test_table,
+ :name,
+ 'max_length')
+ check = "char_length(name) <= 255"
+
+ expect(model).to receive(:check_constraint_name).and_call_original
+ expect(model).to receive(:add_check_constraint)
+ .with(:test_table, check, constraint_name, validate: true)
+
+ model.add_text_limit(:test_table, :name, 255)
+ end
+ end
+
+ context 'when all parameters are provided' do
+ it 'calls add_check_constraint with the correct parameters' do
+ constraint_name = 'check_name_limit'
+ check = "char_length(name) <= 255"
+
+ expect(model).not_to receive(:check_constraint_name)
+ expect(model).to receive(:add_check_constraint)
+ .with(:test_table, check, constraint_name, validate: false)
+
+ model.add_text_limit(
+ :test_table,
+ :name,
+ 255,
+ constraint_name: constraint_name,
+ validate: false
+ )
+ end
+ end
+ end
+
+ describe '#validate_text_limit' do
+ context 'when constraint_name is not provided' do
+ it 'calls validate_check_constraint with an infered constraint name' do
+ constraint_name = model.check_constraint_name(:test_table,
+ :name,
+ 'max_length')
+
+ expect(model).to receive(:check_constraint_name).and_call_original
+ expect(model).to receive(:validate_check_constraint)
+ .with(:test_table, constraint_name)
+
+ model.validate_text_limit(:test_table, :name)
+ end
+ end
+
+ context 'when constraint_name is provided' do
+ it 'calls validate_check_constraint with the correct parameters' do
+ constraint_name = 'check_name_limit'
+
+ expect(model).not_to receive(:check_constraint_name)
+ expect(model).to receive(:validate_check_constraint)
+ .with(:test_table, constraint_name)
+
+ model.validate_text_limit(:test_table, :name, constraint_name: constraint_name)
+ end
+ end
+ end
+
+ describe '#remove_text_limit' do
+ context 'when constraint_name is not provided' do
+ it 'calls remove_check_constraint with an infered constraint name' do
+ constraint_name = model.check_constraint_name(:test_table,
+ :name,
+ 'max_length')
+
+ expect(model).to receive(:check_constraint_name).and_call_original
+ expect(model).to receive(:remove_check_constraint)
+ .with(:test_table, constraint_name)
+
+ model.remove_text_limit(:test_table, :name)
+ end
+ end
+
+ context 'when constraint_name is provided' do
+ it 'calls remove_check_constraint with the correct parameters' do
+ constraint_name = 'check_name_limit'
+
+ expect(model).not_to receive(:check_constraint_name)
+ expect(model).to receive(:remove_check_constraint)
+ .with(:test_table, constraint_name)
+
+ model.remove_text_limit(:test_table, :name, constraint_name: constraint_name)
+ end
+ end
+ end
+
+ describe '#check_text_limit_exists?' do
+ context 'when constraint_name is not provided' do
+ it 'calls check_constraint_exists? with an infered constraint name' do
+ constraint_name = model.check_constraint_name(:test_table,
+ :name,
+ 'max_length')
+
+ expect(model).to receive(:check_constraint_name).and_call_original
+ expect(model).to receive(:check_constraint_exists?)
+ .with(:test_table, constraint_name)
+
+ model.check_text_limit_exists?(:test_table, :name)
+ end
+ end
+
+ context 'when constraint_name is provided' do
+ it 'calls check_constraint_exists? with the correct parameters' do
+ constraint_name = 'check_name_limit'
+
+ expect(model).not_to receive(:check_constraint_name)
+ expect(model).to receive(:check_constraint_exists?)
+ .with(:test_table, constraint_name)
+
+ model.check_text_limit_exists?(:test_table, :name, constraint_name: constraint_name)
+ end
+ end
+ end
+
+ describe '#add_not_null_constraint' do
+ context 'when it is called with the default options' do
+ it 'calls add_check_constraint with an infered constraint name and validate: true' do
+ constraint_name = model.check_constraint_name(:test_table,
+ :name,
+ 'not_null')
+ check = "name IS NOT NULL"
+
+ expect(model).to receive(:column_is_nullable?).and_return(true)
+ expect(model).to receive(:check_constraint_name).and_call_original
+ expect(model).to receive(:add_check_constraint)
+ .with(:test_table, check, constraint_name, validate: true)
+
+ model.add_not_null_constraint(:test_table, :name)
+ end
+ end
+
+ context 'when all parameters are provided' do
+ it 'calls add_check_constraint with the correct parameters' do
+ constraint_name = 'check_name_not_null'
+ check = "name IS NOT NULL"
+
+ expect(model).to receive(:column_is_nullable?).and_return(true)
+ expect(model).not_to receive(:check_constraint_name)
+ expect(model).to receive(:add_check_constraint)
+ .with(:test_table, check, constraint_name, validate: false)
+
+ model.add_not_null_constraint(
+ :test_table,
+ :name,
+ constraint_name: constraint_name,
+ validate: false
+ )
+ end
+ end
+
+ context 'when the column is defined as NOT NULL' do
+ it 'does not add a check constraint' do
+ expect(model).to receive(:column_is_nullable?).and_return(false)
+ expect(model).not_to receive(:check_constraint_name)
+ expect(model).not_to receive(:add_check_constraint)
+
+ model.add_not_null_constraint(:test_table, :name)
+ end
+ end
+ end
+
+ describe '#validate_not_null_constraint' do
+ context 'when constraint_name is not provided' do
+ it 'calls validate_check_constraint with an infered constraint name' do
+ constraint_name = model.check_constraint_name(:test_table,
+ :name,
+ 'not_null')
+
+ expect(model).to receive(:check_constraint_name).and_call_original
+ expect(model).to receive(:validate_check_constraint)
+ .with(:test_table, constraint_name)
+
+ model.validate_not_null_constraint(:test_table, :name)
+ end
+ end
+
+ context 'when constraint_name is provided' do
+ it 'calls validate_check_constraint with the correct parameters' do
+ constraint_name = 'check_name_not_null'
+
+ expect(model).not_to receive(:check_constraint_name)
+ expect(model).to receive(:validate_check_constraint)
+ .with(:test_table, constraint_name)
+
+ model.validate_not_null_constraint(:test_table, :name, constraint_name: constraint_name)
+ end
+ end
+ end
+
+ describe '#remove_not_null_constraint' do
+ context 'when constraint_name is not provided' do
+ it 'calls remove_check_constraint with an infered constraint name' do
+ constraint_name = model.check_constraint_name(:test_table,
+ :name,
+ 'not_null')
+
+ expect(model).to receive(:check_constraint_name).and_call_original
+ expect(model).to receive(:remove_check_constraint)
+ .with(:test_table, constraint_name)
+
+ model.remove_not_null_constraint(:test_table, :name)
+ end
+ end
+
+ context 'when constraint_name is provided' do
+ it 'calls remove_check_constraint with the correct parameters' do
+ constraint_name = 'check_name_not_null'
+
+ expect(model).not_to receive(:check_constraint_name)
+ expect(model).to receive(:remove_check_constraint)
+ .with(:test_table, constraint_name)
+
+ model.remove_not_null_constraint(:test_table, :name, constraint_name: constraint_name)
+ end
+ end
+ end
+
+ describe '#check_not_null_constraint_exists?' do
+ context 'when constraint_name is not provided' do
+ it 'calls check_constraint_exists? with an infered constraint name' do
+ constraint_name = model.check_constraint_name(:test_table,
+ :name,
+ 'not_null')
+
+ expect(model).to receive(:check_constraint_name).and_call_original
+ expect(model).to receive(:check_constraint_exists?)
+ .with(:test_table, constraint_name)
+
+ model.check_not_null_constraint_exists?(:test_table, :name)
+ end
+ end
+
+ context 'when constraint_name is provided' do
+ it 'calls check_constraint_exists? with the correct parameters' do
+ constraint_name = 'check_name_not_null'
+
+ expect(model).not_to receive(:check_constraint_name)
+ expect(model).to receive(:check_constraint_exists?)
+ .with(:test_table, constraint_name)
+
+ model.check_not_null_constraint_exists?(:test_table, :name, constraint_name: constraint_name)
+ end
+ end
+ end
+
+ describe '#rename_constraint' do
+ it "executes the statement to rename constraint" do
+ expect(model).to receive(:execute).with(
+ /ALTER TABLE "test_table"\nRENAME CONSTRAINT "fk_old_name" TO "fk_new_name"/
+ )
+
+ model.rename_constraint(:test_table, :fk_old_name, :fk_new_name)
+ end
+ end
+
+ describe '#drop_constraint' do
+ it "executes the statement to drop the constraint" do
+ expect(model).to receive(:execute).with(
+ "ALTER TABLE \"test_table\" DROP CONSTRAINT \"constraint_name\" CASCADE\n"
+ )
+
+ model.drop_constraint(:test_table, :constraint_name, cascade: true)
+ end
+
+ context 'when cascade option is false' do
+ it "executes the statement to drop the constraint without cascade" do
+ expect(model).to receive(:execute).with("ALTER TABLE \"test_table\" DROP CONSTRAINT \"constraint_name\" \n")
+
+ model.drop_constraint(:test_table, :constraint_name, cascade: false)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/migrations/extension_helpers_spec.rb b/spec/lib/gitlab/database/migrations/extension_helpers_spec.rb
new file mode 100644
index 00000000000..fb29e06bc01
--- /dev/null
+++ b/spec/lib/gitlab/database/migrations/extension_helpers_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::Migrations::ExtensionHelpers do
+ let(:model) do
+ ActiveRecord::Migration.new.extend(described_class)
+ end
+
+ before do
+ allow(model).to receive(:puts)
+ end
+
+ describe '#create_extension' do
+ subject { model.create_extension(extension) }
+
+ let(:extension) { :btree_gist }
+
+ it 'executes CREATE EXTENSION statement' do
+ expect(model).to receive(:execute).with(/CREATE EXTENSION IF NOT EXISTS #{extension}/)
+
+ subject
+ end
+
+ context 'without proper permissions' do
+ before do
+ allow(model).to receive(:execute)
+ .with(/CREATE EXTENSION IF NOT EXISTS #{extension}/)
+ .and_raise(ActiveRecord::StatementInvalid, 'InsufficientPrivilege: permission denied')
+ end
+
+ it 'raises an exception and prints an error message' do
+ expect { subject }
+ .to output(/user is not allowed/).to_stderr
+ .and raise_error(ActiveRecord::StatementInvalid, /InsufficientPrivilege/)
+ end
+ end
+ end
+
+ describe '#drop_extension' do
+ subject { model.drop_extension(extension) }
+
+ let(:extension) { 'btree_gist' }
+
+ it 'executes CREATE EXTENSION statement' do
+ expect(model).to receive(:execute).with(/DROP EXTENSION IF EXISTS #{extension}/)
+
+ subject
+ end
+
+ context 'without proper permissions' do
+ before do
+ allow(model).to receive(:execute)
+ .with(/DROP EXTENSION IF EXISTS #{extension}/)
+ .and_raise(ActiveRecord::StatementInvalid, 'InsufficientPrivilege: permission denied')
+ end
+
+ it 'raises an exception and prints an error message' do
+ expect { subject }
+ .to output(/user is not allowed/).to_stderr
+ .and raise_error(ActiveRecord::StatementInvalid, /InsufficientPrivilege/)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/migrations/lock_retries_helpers_spec.rb b/spec/lib/gitlab/database/migrations/lock_retries_helpers_spec.rb
new file mode 100644
index 00000000000..a8739f6758f
--- /dev/null
+++ b/spec/lib/gitlab/database/migrations/lock_retries_helpers_spec.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::Migrations::LockRetriesHelpers do
+ let(:model) do
+ ActiveRecord::Migration.new.extend(described_class)
+ end
+
+ describe '#with_lock_retries' do
+ let(:buffer) { StringIO.new }
+ let(:in_memory_logger) { Gitlab::JsonLogger.new(buffer) }
+ let(:env) { { 'DISABLE_LOCK_RETRIES' => 'true' } }
+
+ it 'sets the migration class name in the logs' do
+ model.with_lock_retries(env: env, logger: in_memory_logger) {}
+
+ buffer.rewind
+ expect(buffer.read).to include("\"class\":\"#{model.class}\"")
+ end
+
+ where(raise_on_exhaustion: [true, false])
+
+ with_them do
+ it 'sets raise_on_exhaustion as requested' do
+ with_lock_retries = double
+ expect(Gitlab::Database::WithLockRetries).to receive(:new).and_return(with_lock_retries)
+ expect(with_lock_retries).to receive(:run).with(raise_on_exhaustion: raise_on_exhaustion)
+
+ model.with_lock_retries(env: env, logger: in_memory_logger, raise_on_exhaustion: raise_on_exhaustion) {}
+ end
+ end
+
+ it 'does not raise on exhaustion by default' do
+ with_lock_retries = double
+ expect(Gitlab::Database::WithLockRetries).to receive(:new).and_return(with_lock_retries)
+ expect(with_lock_retries).to receive(:run).with(raise_on_exhaustion: false)
+
+ model.with_lock_retries(env: env, logger: in_memory_logger) {}
+ end
+
+ it 'defaults to allowing subtransactions' do
+ with_lock_retries = double
+
+ expect(Gitlab::Database::WithLockRetries)
+ .to receive(:new).with(hash_including(allow_savepoints: true)).and_return(with_lock_retries)
+ expect(with_lock_retries).to receive(:run).with(raise_on_exhaustion: false)
+
+ model.with_lock_retries(env: env, logger: in_memory_logger) {}
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/migrations/runner_spec.rb b/spec/lib/gitlab/database/migrations/runner_spec.rb
index f364ebfa522..bd382547689 100644
--- a/spec/lib/gitlab/database/migrations/runner_spec.rb
+++ b/spec/lib/gitlab/database/migrations/runner_spec.rb
@@ -2,26 +2,65 @@
require 'spec_helper'
RSpec.describe Gitlab::Database::Migrations::Runner, :reestablished_active_record_base do
- include Database::MultipleDatabases
-
let(:base_result_dir) { Pathname.new(Dir.mktmpdir) }
let(:migration_runs) { [] } # This list gets populated as the runner tries to run migrations
# Tests depend on all of these lists being sorted in the order migrations would be applied
- let(:applied_migrations_other_branches) { [double(ActiveRecord::Migration, version: 1, name: 'migration_complete_other_branch')] }
+ let(:applied_migrations_other_branches) do
+ [
+ double(
+ ActiveRecord::Migration,
+ version: 1,
+ name: 'migration_complete_other_branch',
+ filename: 'db/migrate/1_migration_complete_other_branch.rb'
+ )
+ ]
+ end
let(:applied_migrations_this_branch) do
[
- double(ActiveRecord::Migration, version: 2, name: 'older_migration_complete_this_branch'),
- double(ActiveRecord::Migration, version: 3, name: 'newer_migration_complete_this_branch')
+ double(
+ ActiveRecord::Migration,
+ version: 2,
+ name: 'older_migration_complete_this_branch',
+ filename: 'db/migrate/2_older_migration_complete_this_branch.rb'
+ ),
+ double(
+ ActiveRecord::Migration,
+ version: 3,
+ name: 'post_migration_complete_this_branch',
+ filename: 'db/post_migrate/3_post_migration_complete_this_branch.rb'
+ ),
+ double(
+ ActiveRecord::Migration,
+ version: 4,
+ name: 'newer_migration_complete_this_branch',
+ filename: 'db/migrate/4_newer_migration_complete_this_branch.rb'
+ )
].sort_by(&:version)
end
let(:pending_migrations) do
[
- double(ActiveRecord::Migration, version: 4, name: 'older_migration_pending'),
- double(ActiveRecord::Migration, version: 5, name: 'newer_migration_pending')
+ double(
+ ActiveRecord::Migration,
+ version: 5,
+ name: 'older_migration_pending',
+ filename: 'db/migrate/5_older_migration_pending.rb'
+ ),
+ double(
+ ActiveRecord::Migration,
+ version: 6,
+ name: 'post_migration_pending',
+ filename: 'db/post_migrate/6_post_migration_pending.rb'
+ ),
+ double(
+ ActiveRecord::Migration,
+ version: 7,
+ name: 'newer_migration_pending',
+ filename: 'db/migrate/7_newer_migration_pending.rb'
+ )
].sort_by(&:version)
end
@@ -87,11 +126,11 @@ RSpec.describe Gitlab::Database::Migrations::Runner, :reestablished_active_recor
context 'running migrations' do
subject(:up) { described_class.up(database: database, legacy_mode: legacy_mode) }
- it 'runs the unapplied migrations in version order', :aggregate_failures do
+ it 'runs the unapplied migrations in regular/post order, then version order', :aggregate_failures do
up.run
- expect(migration_runs.map(&:dir)).to match_array([:up, :up])
- expect(migration_runs.map(&:version_to_migrate)).to eq(pending_migrations.map(&:version))
+ expect(migration_runs.map(&:dir)).to match_array([:up, :up, :up])
+ expect(migration_runs.map(&:version_to_migrate)).to eq([5, 7, 6])
end
it 'writes a metadata file with the current schema version and database name' do
@@ -130,8 +169,8 @@ RSpec.describe Gitlab::Database::Migrations::Runner, :reestablished_active_recor
it 'runs the applied migrations for the current branch in reverse order', :aggregate_failures do
down.run
- expect(migration_runs.map(&:dir)).to match_array([:down, :down])
- expect(migration_runs.map(&:version_to_migrate)).to eq(applied_migrations_this_branch.reverse.map(&:version))
+ expect(migration_runs.map(&:dir)).to match_array([:down, :down, :down])
+ expect(migration_runs.map(&:version_to_migrate)).to eq([3, 4, 2])
end
end
diff --git a/spec/lib/gitlab/database/migrations/timeout_helpers_spec.rb b/spec/lib/gitlab/database/migrations/timeout_helpers_spec.rb
new file mode 100644
index 00000000000..d35211af680
--- /dev/null
+++ b/spec/lib/gitlab/database/migrations/timeout_helpers_spec.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::Migrations::TimeoutHelpers do
+ let(:model) do
+ ActiveRecord::Migration.new.extend(described_class)
+ end
+
+ describe '#disable_statement_timeout' do
+ it 'disables statement timeouts to current transaction only' do
+ expect(model).to receive(:execute).with('SET LOCAL statement_timeout TO 0')
+
+ model.disable_statement_timeout
+ end
+
+ # this specs runs without an enclosing transaction (:delete truncation method for db_cleaner)
+ context 'with real environment', :delete do
+ before do
+ model.execute("SET statement_timeout TO '20000'")
+ end
+
+ after do
+ model.execute('RESET statement_timeout')
+ end
+
+ it 'defines statement to 0 only for current transaction' do
+ expect(model.execute('SHOW statement_timeout').first['statement_timeout']).to eq('20s')
+
+ model.connection.transaction do
+ model.disable_statement_timeout
+ expect(model.execute('SHOW statement_timeout').first['statement_timeout']).to eq('0')
+ end
+
+ expect(model.execute('SHOW statement_timeout').first['statement_timeout']).to eq('20s')
+ end
+
+ context 'when passing a blocks' do
+ it 'disables statement timeouts on session level and executes the block' do
+ expect(model).to receive(:execute).with('SET statement_timeout TO 0')
+ expect(model).to receive(:execute).with('RESET statement_timeout').at_least(:once)
+
+ expect { |block| model.disable_statement_timeout(&block) }.to yield_control
+ end
+
+ # this specs runs without an enclosing transaction (:delete truncation method for db_cleaner)
+ context 'with real environment', :delete do
+ before do
+ model.execute("SET statement_timeout TO '20000'")
+ end
+
+ after do
+ model.execute('RESET statement_timeout')
+ end
+
+ it 'defines statement to 0 for any code run inside the block' do
+ expect(model.execute('SHOW statement_timeout').first['statement_timeout']).to eq('20s')
+
+ model.disable_statement_timeout do
+ model.connection.transaction do
+ expect(model.execute('SHOW statement_timeout').first['statement_timeout']).to eq('0')
+ end
+
+ expect(model.execute('SHOW statement_timeout').first['statement_timeout']).to eq('0')
+ end
+ end
+ end
+ end
+ end
+
+ # This spec runs without an enclosing transaction (:delete truncation method for db_cleaner)
+ context 'when the statement_timeout is already disabled', :delete do
+ before do
+ ActiveRecord::Migration.connection.execute('SET statement_timeout TO 0')
+ end
+
+ after do
+ # Use ActiveRecord::Migration.connection instead of model.execute
+ # so that this call is not counted below
+ ActiveRecord::Migration.connection.execute('RESET statement_timeout')
+ end
+
+ it 'yields control without disabling the timeout or resetting' do
+ expect(model).not_to receive(:execute).with('SET statement_timeout TO 0')
+ expect(model).not_to receive(:execute).with('RESET statement_timeout')
+
+ expect { |block| model.disable_statement_timeout(&block) }.to yield_control
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/partitioning/convert_table_to_first_list_partition_spec.rb b/spec/lib/gitlab/database/partitioning/convert_table_to_first_list_partition_spec.rb
index 0e804b4feac..cd3a94f5737 100644
--- a/spec/lib/gitlab/database/partitioning/convert_table_to_first_list_partition_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/convert_table_to_first_list_partition_spec.rb
@@ -16,6 +16,7 @@ RSpec.describe Gitlab::Database::Partitioning::ConvertTableToFirstListPartition
let(:referenced_table_name) { '_test_referenced_table' }
let(:other_referenced_table_name) { '_test_other_referenced_table' }
let(:parent_table_name) { "#{table_name}_parent" }
+ let(:lock_tables) { [] }
let(:model) { define_batchable_model(table_name, connection: connection) }
@@ -27,7 +28,8 @@ RSpec.describe Gitlab::Database::Partitioning::ConvertTableToFirstListPartition
table_name: table_name,
partitioning_column: partitioning_column,
parent_table_name: parent_table_name,
- zero_partition_value: partitioning_default
+ zero_partition_value: partitioning_default,
+ lock_tables: lock_tables
)
end
@@ -168,6 +170,16 @@ RSpec.describe Gitlab::Database::Partitioning::ConvertTableToFirstListPartition
end
end
+ context 'with locking tables' do
+ let(:lock_tables) { [table_name] }
+
+ it 'locks the table' do
+ recorder = ActiveRecord::QueryRecorder.new { partition }
+
+ expect(recorder.log).to include(/LOCK "_test_table_to_partition" IN ACCESS EXCLUSIVE MODE/)
+ end
+ end
+
context 'when an error occurs during the conversion' do
def fail_first_time
# We can't directly use a boolean here, as we need something that will be passed by-reference to the proc
diff --git a/spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb b/spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb
index 2ef873e8adb..336dec3a8a0 100644
--- a/spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb
+++ b/spec/lib/gitlab/database/partitioning/detached_partition_dropper_spec.rb
@@ -92,11 +92,11 @@ RSpec.describe Gitlab::Database::Partitioning::DetachedPartitionDropper do
context 'removing foreign keys' do
it 'removes foreign keys from the table before dropping it' do
- expect(dropper).to receive(:drop_detached_partition).and_wrap_original do |drop_method, partition_name|
- expect(partition_name).to eq('test_partition')
- expect(foreign_key_exists_by_name(partition_name, 'fk_referenced', schema: Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA)).to be_falsey
+ expect(dropper).to receive(:drop_detached_partition).and_wrap_original do |drop_method, partition|
+ expect(partition.table_name).to eq('test_partition')
+ expect(foreign_key_exists_by_name(partition.table_name, 'fk_referenced', schema: Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA)).to be_falsey
- drop_method.call(partition_name)
+ drop_method.call(partition)
end
expect(foreign_key_exists_by_name('test_partition', 'fk_referenced', schema: Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA)).to be_truthy
diff --git a/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb b/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb
index 7465f69b87c..a81c8a5a49c 100644
--- a/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb
+++ b/spec/lib/gitlab/database/partitioning_migration_helpers/index_helpers_spec.rb
@@ -65,8 +65,11 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::IndexHelpers do
end
def expect_add_concurrent_index_and_call_original(table, column, index)
- expect(migration).to receive(:add_concurrent_index).ordered.with(table, column, { name: index })
- .and_wrap_original { |_, table, column, options| connection.add_index(table, column, **options) }
+ expect(migration).to receive(:add_concurrent_index).ordered.with(table, column, { name: index, allow_partition: true })
+ .and_wrap_original do |_, table, column, options|
+ options.delete(:allow_partition)
+ connection.add_index(table, column, **options)
+ end
end
end
@@ -91,7 +94,7 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::IndexHelpers do
it 'forwards them to the index helper methods', :aggregate_failures do
expect(migration).to receive(:add_concurrent_index)
- .with(partition1_identifier, column_name, { name: partition1_index, where: 'x > 0', unique: true })
+ .with(partition1_identifier, column_name, { name: partition1_index, where: 'x > 0', unique: true, allow_partition: true })
expect(migration).to receive(:add_index)
.with(table_name, column_name, { name: index_name, where: 'x > 0', unique: true })
@@ -231,4 +234,165 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::IndexHelpers do
end
end
end
+
+ describe '#indexes_by_definition_for_table' do
+ context 'when a partitioned table has indexes' do
+ subject do
+ migration.indexes_by_definition_for_table(table_name)
+ end
+
+ before do
+ connection.execute(<<~SQL)
+ CREATE INDEX #{index_name} ON #{table_name} (#{column_name});
+ SQL
+ end
+
+ it 'captures partitioned index names by index definition' do
+ expect(subject).to match(a_hash_including({ "CREATE _ btree (#{column_name})" => index_name }))
+ end
+ end
+
+ context 'when a non-partitioned table has indexes' do
+ let(:regular_table_name) { '_test_regular_table' }
+ let(:regular_index_name) { '_test_regular_index_name' }
+
+ subject do
+ migration.indexes_by_definition_for_table(regular_table_name)
+ end
+
+ before do
+ connection.execute(<<~SQL)
+ CREATE TABLE #{regular_table_name} (
+ #{column_name} timestamptz NOT NULL
+ );
+
+ CREATE INDEX #{regular_index_name} ON #{regular_table_name} (#{column_name});
+ SQL
+ end
+
+ it 'captures index names by index definition' do
+ expect(subject).to match(a_hash_including({ "CREATE _ btree (#{column_name})" => regular_index_name }))
+ end
+ end
+
+ context 'when a non-partitioned table has duplicate indexes' do
+ let(:regular_table_name) { '_test_regular_table' }
+ let(:regular_index_name) { '_test_regular_index_name' }
+ let(:duplicate_index_name) { '_test_duplicate_index_name' }
+
+ subject do
+ migration.indexes_by_definition_for_table(regular_table_name)
+ end
+
+ before do
+ connection.execute(<<~SQL)
+ CREATE TABLE #{regular_table_name} (
+ #{column_name} timestamptz NOT NULL
+ );
+
+ CREATE INDEX #{regular_index_name} ON #{regular_table_name} (#{column_name});
+ CREATE INDEX #{duplicate_index_name} ON #{regular_table_name} (#{column_name});
+ SQL
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error { described_class::DuplicatedIndexesError }
+ end
+ end
+ end
+
+ describe '#rename_indexes_for_table' do
+ let(:original_table_name) { '_test_rename_indexes_table' }
+ let(:first_partition_name) { '_test_rename_indexes_table_1' }
+ let(:transient_table_name) { '_test_rename_indexes_table_child' }
+ let(:custom_column_name) { 'created_at' }
+ let(:generated_column_name) { 'updated_at' }
+ let(:custom_index_name) { 'index_test_rename_indexes_table_on_created_at' }
+ let(:custom_index_name_regenerated) { '_test_rename_indexes_table_created_at_idx' }
+ let(:generated_index_name) { '_test_rename_indexes_table_updated_at_idx' }
+ let(:generated_index_name_collided) { '_test_rename_indexes_table_updated_at_idx1' }
+
+ before do
+ connection.execute(<<~SQL)
+ CREATE TABLE #{original_table_name} (
+ #{custom_column_name} timestamptz NOT NULL,
+ #{generated_column_name} timestamptz NOT NULL
+ );
+
+ CREATE INDEX #{custom_index_name} ON #{original_table_name} (#{custom_column_name});
+ CREATE INDEX ON #{original_table_name} (#{generated_column_name});
+ SQL
+ end
+
+ context 'when changing a table within the current schema' do
+ let!(:identifiers) { migration.indexes_by_definition_for_table(original_table_name) }
+
+ before do
+ connection.execute(<<~SQL)
+ ALTER TABLE #{original_table_name} RENAME TO #{first_partition_name};
+ CREATE TABLE #{original_table_name} (LIKE #{first_partition_name} INCLUDING ALL);
+ DROP TABLE #{first_partition_name};
+ SQL
+ end
+
+ it 'maps index names after they are changed' do
+ migration.rename_indexes_for_table(original_table_name, identifiers)
+
+ expect_index_to_exist(custom_index_name)
+ expect_index_to_exist(generated_index_name)
+ end
+
+ it 'does not rename an index which does not exist in the to_hash' do
+ partial_identifiers = identifiers.reject { |_, name| name == custom_index_name }
+
+ migration.rename_indexes_for_table(original_table_name, partial_identifiers)
+
+ expect_index_not_to_exist(custom_index_name)
+ expect_index_to_exist(generated_index_name)
+ end
+ end
+
+ context 'when partitioning an existing table' do
+ before do
+ connection.execute(<<~SQL)
+ /* Create new parent table */
+ CREATE TABLE #{first_partition_name} (LIKE #{original_table_name} INCLUDING ALL);
+ SQL
+ end
+
+ it 'renames indexes across schemas' do
+ # Capture index names generated by postgres
+ generated_index_names = migration.indexes_by_definition_for_table(first_partition_name)
+
+ # Capture index names from original table
+ original_index_names = migration.indexes_by_definition_for_table(original_table_name)
+
+ connection.execute(<<~SQL)
+ /* Rename original table out of the way */
+ ALTER TABLE #{original_table_name} RENAME TO #{transient_table_name};
+
+ /* Rename new parent table to original name */
+ ALTER TABLE #{first_partition_name} RENAME TO #{original_table_name};
+
+ /* Move original table to gitlab_partitions_dynamic schema */
+ ALTER TABLE #{transient_table_name} SET SCHEMA #{partition_schema};
+
+ /* Rename original table to be the first partition */
+ ALTER TABLE #{partition_schema}.#{transient_table_name} RENAME TO #{first_partition_name};
+ SQL
+
+ # Apply index names generated by postgres to first partition
+ migration.rename_indexes_for_table(first_partition_name, generated_index_names, schema_name: partition_schema)
+
+ expect_index_to_exist('_test_rename_indexes_table_1_created_at_idx')
+ expect_index_to_exist('_test_rename_indexes_table_1_updated_at_idx')
+
+ # Apply index names from original table to new parent table
+ migration.rename_indexes_for_table(original_table_name, original_index_names)
+
+ expect_index_to_exist(custom_index_name)
+ expect_index_to_exist(generated_index_name)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb b/spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb
index 8bb9ad2737a..e76b1da3834 100644
--- a/spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb
+++ b/spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb
@@ -43,6 +43,7 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
context 'list partitioning conversion helpers' do
shared_examples_for 'delegates to ConvertTableToFirstListPartition' do
+ let(:extra_options) { {} }
it 'throws an error if in a transaction' do
allow(migration).to receive(:transaction_open?).and_return(true)
expect { migrate }.to raise_error(/cannot be run inside a transaction/)
@@ -54,7 +55,8 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
table_name: source_table,
parent_table_name: partitioned_table,
partitioning_column: partition_column,
- zero_partition_value: min_date) do |converter|
+ zero_partition_value: min_date,
+ **extra_options) do |converter|
expect(converter).to receive(expected_method)
end
@@ -64,12 +66,15 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::TableManagementHe
describe '#convert_table_to_first_list_partition' do
it_behaves_like 'delegates to ConvertTableToFirstListPartition' do
+ let(:lock_tables) { [source_table] }
+ let(:extra_options) { { lock_tables: lock_tables } }
let(:expected_method) { :partition }
let(:migrate) do
migration.convert_table_to_first_list_partition(table_name: source_table,
partitioning_column: partition_column,
parent_table_name: partitioned_table,
- initial_partitioning_value: min_date)
+ initial_partitioning_value: min_date,
+ lock_tables: lock_tables)
end
end
end
diff --git a/spec/lib/gitlab/database/postgres_partition_spec.rb b/spec/lib/gitlab/database/postgres_partition_spec.rb
index 5a44090d5ae..14a4d405621 100644
--- a/spec/lib/gitlab/database/postgres_partition_spec.rb
+++ b/spec/lib/gitlab/database/postgres_partition_spec.rb
@@ -72,4 +72,36 @@ RSpec.describe Gitlab::Database::PostgresPartition, type: :model do
expect(find(identifier).condition).to eq("FOR VALUES FROM ('2020-01-01 00:00:00+00') TO ('2020-02-01 00:00:00+00')")
end
end
+
+ describe '.partition_exists?' do
+ subject { described_class.partition_exists?(table_name) }
+
+ context 'when the partition exists' do
+ let(:table_name) { "ci_builds_metadata" }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when the partition does not exist' do
+ let(:table_name) { 'partition_does_not_exist' }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe '.legacy_partition_exists?' do
+ subject { described_class.legacy_partition_exists?(table_name) }
+
+ context 'when the partition exists' do
+ let(:table_name) { "ci_builds_metadata" }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when the partition does not exist' do
+ let(:table_name) { 'partition_does_not_exist' }
+
+ it { is_expected.to be_falsey }
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/query_analyzer_spec.rb b/spec/lib/gitlab/database/query_analyzer_spec.rb
index 0b849063562..6dc9ffc4aba 100644
--- a/spec/lib/gitlab/database/query_analyzer_spec.rb
+++ b/spec/lib/gitlab/database/query_analyzer_spec.rb
@@ -10,6 +10,7 @@ RSpec.describe Gitlab::Database::QueryAnalyzer, query_analyzers: false do
before do
allow(described_class.instance).to receive(:all_analyzers).and_return([analyzer, disabled_analyzer])
allow(analyzer).to receive(:enabled?).and_return(true)
+ allow(analyzer).to receive(:raw?).and_return(false)
allow(analyzer).to receive(:suppressed?).and_return(false)
allow(analyzer).to receive(:begin!)
allow(analyzer).to receive(:end!)
@@ -181,6 +182,13 @@ RSpec.describe Gitlab::Database::QueryAnalyzer, query_analyzers: false do
expect { process_sql("SELECT 1 FROM projects") }.not_to raise_error
end
+ it 'does call analyze with raw sql when raw? is true' do
+ expect(analyzer).to receive(:raw?).and_return(true)
+ expect(analyzer).to receive(:analyze).with('SELECT 1 FROM projects')
+
+ expect { process_sql("SELECT 1 FROM projects") }.not_to raise_error
+ end
+
def process_sql(sql)
described_class.instance.within do
ApplicationRecord.load_balancer.read_write do |connection|
diff --git a/spec/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer_spec.rb b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer_spec.rb
deleted file mode 100644
index ef7c7965c09..00000000000
--- a/spec/lib/gitlab/database/query_analyzers/ci/partitioning_analyzer_spec.rb
+++ /dev/null
@@ -1,78 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Database::QueryAnalyzers::Ci::PartitioningAnalyzer, query_analyzers: false do
- let(:analyzer) { described_class }
-
- before do
- allow(Gitlab::Database::QueryAnalyzer.instance).to receive(:all_analyzers).and_return([analyzer])
- end
-
- context 'when ci_partitioning_analyze_queries is disabled' do
- before do
- stub_feature_flags(ci_partitioning_analyze_queries: false)
- end
-
- it 'does not analyze the query' do
- expect(analyzer).not_to receive(:analyze)
-
- process_sql(Ci::BuildMetadata, "SELECT 1 FROM ci_builds_metadata")
- end
- end
-
- context 'when ci_partitioning_analyze_queries is enabled' do
- context 'when analyzing targeted tables' do
- described_class::ENABLED_TABLES.each do |enabled_table|
- context 'when querying a non routing table' do
- it 'tracks exception' do
- expect(::Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
- process_sql(Ci::ApplicationRecord, "SELECT 1 FROM #{enabled_table}")
- end
-
- it 'raises RoutingTableNotUsedError' do
- expect { process_sql(Ci::ApplicationRecord, "SELECT 1 FROM #{enabled_table}") }
- .to raise_error(described_class::RoutingTableNotUsedError)
- end
- end
- end
-
- context 'when updating a record' do
- it 'raises RoutingTableNotUsedError' do
- expect { process_sql(Ci::BuildMetadata, "UPDATE ci_builds_metadata SET id = 1") }
- .to raise_error(described_class::RoutingTableNotUsedError)
- end
- end
-
- context 'when inserting a record' do
- it 'raises RoutingTableNotUsedError' do
- expect { process_sql(Ci::BuildMetadata, "INSERT INTO ci_builds_metadata (id) VALUES(1)") }
- .to raise_error(described_class::RoutingTableNotUsedError)
- end
- end
- end
-
- context 'when analyzing non targeted table' do
- it 'does not raise error' do
- expect { process_sql(Ci::BuildMetadata, "SELECT 1 FROM projects") }
- .not_to raise_error
- end
- end
-
- context 'when querying a routing table' do
- it 'does not raise error' do
- expect { process_sql(Ci::BuildMetadata, "SELECT 1 FROM p_ci_builds_metadata") }
- .not_to raise_error
- end
- end
- end
-
- private
-
- def process_sql(model, sql)
- Gitlab::Database::QueryAnalyzer.instance.within do
- # Skip load balancer and retrieve connection assigned to model
- Gitlab::Database::QueryAnalyzer.instance.send(:process_sql, sql, model.retrieve_connection)
- end
- end
-end
diff --git a/spec/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer_spec.rb b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer_spec.rb
new file mode 100644
index 00000000000..0fe19041b6d
--- /dev/null
+++ b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_id_analyzer_spec.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::QueryAnalyzers::Ci::PartitioningIdAnalyzer, query_analyzers: false do
+ let(:analyzer) { described_class }
+
+ before do
+ allow(Gitlab::Database::QueryAnalyzer.instance).to receive(:all_analyzers).and_return([analyzer])
+ end
+
+ context 'when ci_partitioning_analyze_queries_partition_id_check is disabled' do
+ before do
+ stub_feature_flags(ci_partitioning_analyze_queries_partition_id_check: false)
+ end
+
+ it 'does not analyze the query' do
+ expect(analyzer).not_to receive(:analyze)
+
+ process_sql(Ci::BuildMetadata, "SELECT 1 FROM ci_builds_metadata")
+ end
+ end
+
+ context 'when ci_partitioning_analyze_queries_partition_id_check is enabled' do
+ context 'when querying a routing table' do
+ shared_examples 'a good query' do |sql|
+ it 'does not raise error' do
+ expect { process_sql(Ci::BuildMetadata, sql) }.not_to raise_error
+ end
+ end
+
+ shared_examples 'a bad query' do |sql|
+ it 'raises PartitionIdMissingError' do
+ expect { process_sql(Ci::BuildMetadata, sql) }.to raise_error(described_class::PartitionIdMissingError)
+ end
+ end
+
+ context 'when partition_id is present' do
+ context 'when selecting data' do
+ it_behaves_like 'a good query', 'SELECT * FROM p_ci_builds_metadata WHERE partition_id = 100'
+ end
+
+ context 'with a join query' do
+ sql = <<~SQL
+ SELECT ci_builds.id
+ FROM p_ci_builds
+ JOIN p_ci_builds_metadata ON p_ci_builds_metadata.build_id = ci_builds.id
+ WHERE ci_builds.type = 'Ci::Build'
+ AND ci_builds.partition_id = 100
+ AND (NOT p_ci_builds_metadata.id IN
+ (SELECT p_ci_builds_metadata.id
+ FROM p_ci_builds_metadata
+ WHERE p_ci_builds_metadata.build_id = ci_builds.id
+ AND p_ci_builds_metadata.interruptible = TRUE
+ AND p_ci_builds_metadata.partition_id = 100 ));
+ SQL
+
+ it_behaves_like 'a good query', sql
+ end
+
+ context 'when removing data' do
+ it_behaves_like 'a good query', 'DELETE FROM p_ci_builds_metadata WHERE partition_id = 100'
+ end
+
+ context 'when updating data' do
+ sql = 'UPDATE p_ci_builds_metadata SET interruptible = false WHERE partition_id = 100'
+
+ it_behaves_like 'a good query', sql
+ end
+
+ context 'when inserting a record' do
+ it_behaves_like 'a good query', 'INSERT INTO p_ci_builds_metadata (id, partition_id) VALUES(1, 1)'
+ end
+ end
+
+ context 'when partition_id is missing' do
+ context 'when inserting a record' do
+ it_behaves_like 'a bad query', 'INSERT INTO p_ci_builds_metadata (id) VALUES(1)'
+ end
+
+ context 'when selecting data' do
+ it_behaves_like 'a bad query', 'SELECT * FROM p_ci_builds_metadata WHERE id = 1'
+ end
+
+ context 'when removing data' do
+ it_behaves_like 'a bad query', 'DELETE FROM p_ci_builds_metadata WHERE id = 1'
+ end
+
+ context 'when updating data' do
+ it_behaves_like 'a bad query', 'UPDATE p_ci_builds_metadata SET interruptible = false WHERE id = 1'
+ end
+
+ context 'with a join query' do
+ sql = <<~SQL
+ SELECT ci_builds.id
+ FROM ci_builds
+ JOIN p_ci_builds_metadata ON p_ci_builds_metadata.build_id = ci_builds.id
+ WHERE ci_builds.type = 'Ci::Build'
+ AND ci_builds.partition_id = 100
+ AND (NOT p_ci_builds_metadata.id IN
+ (SELECT p_ci_builds_metadata.id
+ FROM p_ci_builds_metadata
+ WHERE p_ci_builds_metadata.build_id = ci_builds.id
+ AND p_ci_builds_metadata.interruptible = TRUE ));
+ SQL
+
+ it_behaves_like 'a bad query', sql
+ end
+ end
+ end
+ end
+
+ private
+
+ def process_sql(model, sql)
+ Gitlab::Database::QueryAnalyzer.instance.within do
+ # Skip load balancer and retrieve connection assigned to model
+ Gitlab::Database::QueryAnalyzer.instance.send(:process_sql, sql, model.retrieve_connection)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer_spec.rb b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer_spec.rb
new file mode 100644
index 00000000000..1f86c2ccbb0
--- /dev/null
+++ b/spec/lib/gitlab/database/query_analyzers/ci/partitioning_routing_analyzer_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::QueryAnalyzers::Ci::PartitioningRoutingAnalyzer, query_analyzers: false do
+ let(:analyzer) { described_class }
+
+ before do
+ allow(Gitlab::Database::QueryAnalyzer.instance).to receive(:all_analyzers).and_return([analyzer])
+ end
+
+ context 'when ci_partitioning_analyze_queries is disabled' do
+ before do
+ stub_feature_flags(ci_partitioning_analyze_queries: false)
+ end
+
+ it 'does not analyze the query' do
+ expect(analyzer).not_to receive(:analyze)
+
+ process_sql(Ci::BuildMetadata, "SELECT 1 FROM ci_builds_metadata")
+ end
+ end
+
+ context 'when ci_partitioning_analyze_queries is enabled' do
+ context 'when analyzing targeted tables' do
+ described_class::ENABLED_TABLES.each do |enabled_table|
+ context 'when querying a non routing table' do
+ it 'tracks exception' do
+ expect(::Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception)
+ process_sql(Ci::ApplicationRecord, "SELECT 1 FROM #{enabled_table}")
+ end
+
+ it 'raises RoutingTableNotUsedError' do
+ expect { process_sql(Ci::ApplicationRecord, "SELECT 1 FROM #{enabled_table}") }
+ .to raise_error(described_class::RoutingTableNotUsedError)
+ end
+ end
+ end
+
+ context 'when updating a record' do
+ it 'raises RoutingTableNotUsedError' do
+ expect { process_sql(Ci::BuildMetadata, "UPDATE ci_builds_metadata SET id = 1") }
+ .to raise_error(described_class::RoutingTableNotUsedError)
+ end
+ end
+
+ context 'when inserting a record' do
+ it 'raises RoutingTableNotUsedError' do
+ expect { process_sql(Ci::BuildMetadata, "INSERT INTO ci_builds_metadata (id) VALUES(1)") }
+ .to raise_error(described_class::RoutingTableNotUsedError)
+ end
+ end
+ end
+
+ context 'when analyzing non targeted table' do
+ it 'does not raise error' do
+ expect { process_sql(Ci::BuildMetadata, "SELECT 1 FROM projects") }.not_to raise_error
+ end
+ end
+ end
+
+ private
+
+ def process_sql(model, sql)
+ Gitlab::Database::QueryAnalyzer.instance.within do
+ # Skip load balancer and retrieve connection assigned to model
+ Gitlab::Database::QueryAnalyzer.instance.send(:process_sql, sql, model.retrieve_connection)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/query_analyzers/query_recorder_spec.rb b/spec/lib/gitlab/database/query_analyzers/query_recorder_spec.rb
new file mode 100644
index 00000000000..ec01ae623ae
--- /dev/null
+++ b/spec/lib/gitlab/database/query_analyzers/query_recorder_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::QueryAnalyzers::QueryRecorder, query_analyzers: false do
+ # We keep only the QueryRecorder analyzer running
+ around do |example|
+ described_class.with_suppressed(false) do
+ example.run
+ end
+ end
+
+ context 'when analyzer is enabled for tests' do
+ let(:query) { 'SELECT 1 FROM projects' }
+ let(:log_path) { Rails.root.join(described_class::LOG_FILE) }
+
+ before do
+ stub_env('CI', 'true')
+
+ # This is needed to be able to stub_env the CI variable
+ ::Gitlab::Database::QueryAnalyzer.instance.begin!([described_class])
+ end
+
+ after do
+ ::Gitlab::Database::QueryAnalyzer.instance.end!([described_class])
+ end
+
+ it 'logs queries to a file' do
+ allow(FileUtils).to receive(:mkdir_p)
+ .with(File.dirname(log_path))
+ expect(File).to receive(:write)
+ .with(log_path, /^{"sql":"#{query}/, mode: 'a')
+ expect(described_class).to receive(:analyze).with(/^#{query}/).and_call_original
+
+ expect { ApplicationRecord.connection.execute(query) }.not_to raise_error
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/tables_truncate_spec.rb b/spec/lib/gitlab/database/tables_truncate_spec.rb
index 01af9efd782..4f68cd93a8e 100644
--- a/spec/lib/gitlab/database/tables_truncate_spec.rb
+++ b/spec/lib/gitlab/database/tables_truncate_spec.rb
@@ -233,6 +233,26 @@ RSpec.describe Gitlab::Database::TablesTruncate, :reestablished_active_record_ba
it_behaves_like 'truncating legacy tables on a database'
end
+ context 'when running with multiple shared databases' do
+ before do
+ skip_if_multiple_databases_not_setup
+ ci_db_config = Ci::ApplicationRecord.connection_db_config
+ allow(::Gitlab::Database).to receive(:db_config_share_with).with(ci_db_config).and_return('main')
+ end
+
+ it 'raises an error when truncating the main database that it is a single database setup' do
+ expect do
+ described_class.new(database_name: 'main', min_batch_size: min_batch_size).execute
+ end.to raise_error(/Cannot truncate legacy tables in single-db setup/)
+ end
+
+ it 'raises an error when truncating the ci database that it is a single database setup' do
+ expect do
+ described_class.new(database_name: 'ci', min_batch_size: min_batch_size).execute
+ end.to raise_error(/Cannot truncate legacy tables in single-db setup/)
+ end
+ end
+
context 'when running in a single database mode' do
before do
skip_if_multiple_databases_are_setup
diff --git a/spec/lib/gitlab/database/type/symbolized_jsonb_spec.rb b/spec/lib/gitlab/database/type/symbolized_jsonb_spec.rb
new file mode 100644
index 00000000000..a8401667b34
--- /dev/null
+++ b/spec/lib/gitlab/database/type/symbolized_jsonb_spec.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Database::Type::SymbolizedJsonb do
+ let(:type) { described_class.new }
+
+ describe '#deserialize' do
+ using RSpec::Parameterized::TableSyntax
+
+ subject { type.deserialize(json) }
+
+ where(:json, :value) do
+ nil | nil
+ '{"key":"value"}' | { key: 'value' }
+ '{"key":[1,2,3]}' | { key: [1, 2, 3] }
+ '{"key":{"subkey":"value"}}' | { key: { subkey: 'value' } }
+ '{"key":{"a":[{"b":"c"},{"d":"e"}]}}' | { key: { a: [{ b: 'c' }, { d: 'e' }] } }
+ end
+
+ with_them do
+ it { is_expected.to match(value) }
+ end
+ end
+
+ context 'when used by a model' do
+ let(:model) do
+ Class.new(ApplicationRecord) do
+ self.table_name = :_test_symbolized_jsonb
+
+ attribute :options, :sym_jsonb
+ end
+ end
+
+ let(:record) do
+ model.create!(name: 'test', options: { key: 'value' })
+ end
+
+ before do
+ ApplicationRecord.connection.execute(<<~SQL)
+ CREATE TABLE _test_symbolized_jsonb(
+ id serial NOT NULL PRIMARY KEY,
+ name text,
+ options jsonb);
+ SQL
+
+ model.reset_column_information
+ end
+
+ it { expect(record.options).to match({ key: 'value' }) }
+
+ it 'ignores changes to other attributes' do
+ record.name = 'other test'
+
+ expect(record.changes).to match('name' => ['test', 'other test'])
+ end
+
+ it 'tracks changes to options' do
+ record.options = { key: 'other value' }
+
+ expect(record.changes).to match('options' => [{ 'key' => 'value' }, { 'key' => 'other value' }])
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database_importers/self_monitoring/project/delete_service_spec.rb b/spec/lib/gitlab/database_importers/self_monitoring/project/delete_service_spec.rb
index 9d514bcc661..d67e50a50d4 100644
--- a/spec/lib/gitlab/database_importers/self_monitoring/project/delete_service_spec.rb
+++ b/spec/lib/gitlab/database_importers/self_monitoring/project/delete_service_spec.rb
@@ -11,13 +11,13 @@ RSpec.describe Gitlab::DatabaseImporters::SelfMonitoring::Project::DeleteService
it 'returns error' do
expect(result).to eq(
status: :error,
- message: 'Self monitoring project does not exist',
+ message: 'Self-monitoring project does not exist',
last_step: :validate_self_monitoring_project_exists
)
end
end
- context 'when self monitoring project exists' do
+ context 'when self-monitoring project exists' do
let(:group) { create(:group) }
let(:project) { create(:project, namespace: group) }
diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb
index eb42734d044..c788022bd3a 100644
--- a/spec/lib/gitlab/database_spec.rb
+++ b/spec/lib/gitlab/database_spec.rb
@@ -242,13 +242,9 @@ RSpec.describe Gitlab::Database do
pool&.disconnect!
end
- context "when there's CI connection", :request_store do
+ context "when there's CI connection" do
before do
skip_if_multiple_databases_not_setup
-
- # FF due to lib/gitlab/database/load_balancing/configuration.rb:92
- # Requires usage of `:request_store`
- stub_feature_flags(force_no_sharing_primary_model: true)
end
context 'when CI uses database_tasks: false does indicate that ci: is subset of main:' do
diff --git a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
index c24d6a44d9b..02fac96a02f 100644
--- a/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
+++ b/spec/lib/gitlab/dependency_linker/composer_json_linker_spec.rb
@@ -40,7 +40,8 @@ RSpec.describe Gitlab::DependencyLinker::ComposerJsonLinker do
"mockery/mockery": "0.9.*",
"phpunit/phpunit": "~4.0",
"symfony/css-selector": "2.8.*|3.0.*",
- "symfony/dom-crawler": "2.8.*|3.0.*"
+ "symfony/dom-crawler": "2.8.*|3.0.*",
+ "drupal/bootstrap": "3.x-dev"
}
}
CONTENT
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index d623a390dc8..ad2524e40c5 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -55,22 +55,8 @@ RSpec.describe Gitlab::Diff::File do
let(:commit) { project.commit("532c837") }
context 'when file is ipynb' do
- let(:ipynb_semantic_diff) { false }
-
- before do
- stub_feature_flags(ipynb_semantic_diff: ipynb_semantic_diff)
- end
-
- subject { diff_file.rendered }
-
- context 'when ipynb_semantic_diff is off' do
- it { is_expected.to be_nil }
- end
-
- context 'and rendered_viewer is on' do
- let(:ipynb_semantic_diff) { true }
-
- it { is_expected.not_to be_nil }
+ it 'creates a rendered diff file' do
+ expect(diff_file.rendered).not_to be_nil
end
end
end
@@ -152,20 +138,6 @@ RSpec.describe Gitlab::Diff::File do
expect(diff_file.rendered).to be_nil
end
end
-
- context 'when semantic ipynb is off' do
- before do
- stub_feature_flags(ipynb_semantic_diff: false)
- end
-
- it 'returns nil' do
- expect(diff_file).not_to receive(:modified_file?)
- expect(diff_file).not_to receive(:ipynb?)
- expect(diff).not_to receive(:too_large?)
-
- expect(diff_file.rendered).to be_nil
- end
- end
end
end
diff --git a/spec/lib/gitlab/doorkeeper_secret_storing/token/pbkdf2_sha512_spec.rb b/spec/lib/gitlab/doorkeeper_secret_storing/token/pbkdf2_sha512_spec.rb
index c73744cd481..e267d27ed13 100644
--- a/spec/lib/gitlab/doorkeeper_secret_storing/token/pbkdf2_sha512_spec.rb
+++ b/spec/lib/gitlab/doorkeeper_secret_storing/token/pbkdf2_sha512_spec.rb
@@ -10,16 +10,6 @@ RSpec.describe Gitlab::DoorkeeperSecretStoring::Token::Pbkdf2Sha512 do
expect(described_class.transform_secret(plaintext_token))
.to eq("$pbkdf2-sha512$20000$$.c0G5XJVEew1TyeJk5TrkvB0VyOaTmDzPrsdNRED9vVeZlSyuG3G90F0ow23zUCiWKAVwmNnR/ceh.nJG3MdpQ") # rubocop:disable Layout/LineLength
end
-
- context 'when hash_oauth_tokens is disabled' do
- before do
- stub_feature_flags(hash_oauth_tokens: false)
- end
-
- it 'returns a plaintext token' do
- expect(described_class.transform_secret(plaintext_token)).to eq(plaintext_token)
- end
- end
end
describe 'STRETCHES' do
diff --git a/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb b/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb
index 2c1badbd113..2bc3cd81b48 100644
--- a/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Gitlab::Email::Handler::UnsubscribeHandler do
stub_config_setting(host: 'localhost')
end
- let(:email_raw) { fixture_file('emails/valid_reply.eml').gsub(mail_key, "#{mail_key}#{Gitlab::IncomingEmail::UNSUBSCRIBE_SUFFIX}") }
+ let(:email_raw) { fixture_file('emails/valid_reply.eml').gsub(mail_key, "#{mail_key}#{Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX}") }
let(:project) { create(:project, :public) }
let(:user) { create(:user) }
let(:noteable) { create(:issue, project: project) }
@@ -21,19 +21,19 @@ RSpec.describe Gitlab::Email::Handler::UnsubscribeHandler do
let(:mail) { Mail::Message.new(email_raw) }
it "matches the new format" do
- handler = described_class.new(mail, "#{mail_key}#{Gitlab::IncomingEmail::UNSUBSCRIBE_SUFFIX}")
+ handler = described_class.new(mail, "#{mail_key}#{Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX}")
expect(handler.can_handle?).to be_truthy
end
it "matches the legacy format" do
- handler = described_class.new(mail, "#{mail_key}#{Gitlab::IncomingEmail::UNSUBSCRIBE_SUFFIX_LEGACY}")
+ handler = described_class.new(mail, "#{mail_key}#{Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX_LEGACY}")
expect(handler.can_handle?).to be_truthy
end
it "doesn't match either format" do
- handler = described_class.new(mail, "+#{mail_key}#{Gitlab::IncomingEmail::UNSUBSCRIBE_SUFFIX}")
+ handler = described_class.new(mail, "+#{mail_key}#{Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX}")
expect(handler.can_handle?).to be_falsey
end
@@ -64,7 +64,7 @@ RSpec.describe Gitlab::Email::Handler::UnsubscribeHandler do
end
context 'when using old style unsubscribe link' do
- let(:email_raw) { fixture_file('emails/valid_reply.eml').gsub(mail_key, "#{mail_key}#{Gitlab::IncomingEmail::UNSUBSCRIBE_SUFFIX_LEGACY}") }
+ let(:email_raw) { fixture_file('emails/valid_reply.eml').gsub(mail_key, "#{mail_key}#{Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX_LEGACY}") }
it 'unsubscribes user from notable' do
expect { receiver.execute }.to change { noteable.subscribed?(user) }.from(true).to(false)
diff --git a/spec/lib/gitlab/email/handler_spec.rb b/spec/lib/gitlab/email/handler_spec.rb
index eff6fb63a5f..d38b7d9c85c 100644
--- a/spec/lib/gitlab/email/handler_spec.rb
+++ b/spec/lib/gitlab/email/handler_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe Gitlab::Email::Handler do
describe 'regexps are set properly' do
let(:addresses) do
- %W(sent_notification_key#{Gitlab::IncomingEmail::UNSUBSCRIBE_SUFFIX} sent_notification_key#{Gitlab::IncomingEmail::UNSUBSCRIBE_SUFFIX_LEGACY}) +
+ %W(sent_notification_key#{Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX} sent_notification_key#{Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX_LEGACY}) +
%w(sent_notification_key path-to-project-123-user_email_token-merge-request) +
%w(path-to-project-123-user_email_token-issue path-to-project-123-user_email_token-issue-123) +
%w(path/to/project+user_email_token path/to/project+merge-request+user_email_token some/project)
diff --git a/spec/lib/gitlab/email/receiver_spec.rb b/spec/lib/gitlab/email/receiver_spec.rb
index 79476c63e66..9240d07fd59 100644
--- a/spec/lib/gitlab/email/receiver_spec.rb
+++ b/spec/lib/gitlab/email/receiver_spec.rb
@@ -5,11 +5,10 @@ require 'spec_helper'
RSpec.describe Gitlab::Email::Receiver do
include_context :email_shared_context
+ let_it_be(:project) { create(:project) }
let(:metric_transaction) { instance_double(Gitlab::Metrics::WebTransaction) }
shared_examples 'successful receive' do
- let_it_be(:project) { create(:project) }
-
let(:handler) { double(:handler, project: project, execute: true, metrics_event: nil, metrics_params: nil) }
let(:client_id) { 'email/jake@example.com' }
@@ -39,7 +38,7 @@ RSpec.describe Gitlab::Email::Receiver do
end
end
- shared_examples 'failed receive' do
+ shared_examples 'failed receive with event' do
it 'adds metric event' do
expect(::Gitlab::Metrics::BackgroundTransaction).to receive(:current).and_return(metric_transaction)
expect(metric_transaction).to receive(:add_event).with('email_receiver_error', { error: expected_error.name })
@@ -48,6 +47,14 @@ RSpec.describe Gitlab::Email::Receiver do
end
end
+ shared_examples 'failed receive without event' do
+ it 'adds metric event' do
+ expect(::Gitlab::Metrics::BackgroundTransaction).not_to receive(:current)
+
+ expect { receiver.execute }.to raise_error(expected_error)
+ end
+ end
+
context 'when the email contains a valid email address in a header' do
before do
stub_incoming_email_setting(enabled: true, address: "incoming+%{key}@appmail.example.com")
@@ -100,21 +107,21 @@ RSpec.describe Gitlab::Email::Receiver do
let(:email_raw) { fixture_file('emails/valid_reply.eml').gsub(mail_key, '!!!') }
let(:expected_error) { Gitlab::Email::UnknownIncomingEmail }
- it_behaves_like 'failed receive'
+ it_behaves_like 'failed receive with event'
end
context 'when the email is blank' do
let(:email_raw) { '' }
let(:expected_error) { Gitlab::Email::EmptyEmailError }
- it_behaves_like 'failed receive'
+ it_behaves_like 'failed receive without event'
end
context 'when the email was auto generated with Auto-Submitted header' do
let(:email_raw) { fixture_file('emails/auto_submitted.eml') }
let(:expected_error) { Gitlab::Email::AutoGeneratedEmailError }
- it_behaves_like 'failed receive'
+ it_behaves_like 'failed receive without event'
end
context "when the email's To field is blank" do
@@ -164,7 +171,48 @@ RSpec.describe Gitlab::Email::Receiver do
let(:email_raw) { fixture_file('emails/auto_reply.eml') }
let(:expected_error) { Gitlab::Email::AutoGeneratedEmailError }
- it_behaves_like 'failed receive'
+ it_behaves_like 'failed receive without event'
+ end
+
+ describe 'event raising via errors' do
+ let(:handler) { double(:handler, project: project, execute: true, metrics_event: nil, metrics_params: nil) }
+ let(:email_raw) { "arbitrary text. could be anything really. we're going to raise an error anyway." }
+
+ before do
+ allow(receiver).to receive(:handler).and_return(handler)
+ allow(handler).to receive(:execute).and_raise(expected_error)
+ end
+
+ describe 'handling errors which do not raise events' do
+ where(:expected_error) do
+ [
+ Gitlab::Email::AutoGeneratedEmailError,
+ Gitlab::Email::ProjectNotFound,
+ Gitlab::Email::EmptyEmailError,
+ Gitlab::Email::UserNotFoundError,
+ Gitlab::Email::UserBlockedError,
+ Gitlab::Email::UserNotAuthorizedError,
+ Gitlab::Email::NoteableNotFoundError,
+ Gitlab::Email::InvalidAttachment,
+ Gitlab::Email::InvalidRecordError,
+ Gitlab::Email::EmailTooLarge
+ ]
+ end
+
+ with_them do
+ it_behaves_like 'failed receive without event'
+ end
+ end
+
+ describe 'handling errors which do raise events' do
+ where(:expected_error) do
+ [Gitlab::Email::EmailUnparsableError, Gitlab::Email::UnknownIncomingEmail, ArgumentError, StandardError]
+ end
+
+ with_them do
+ it_behaves_like 'failed receive with event'
+ end
+ end
end
it 'requires all handlers to have a unique metric_event' do
diff --git a/spec/lib/gitlab/error_tracking_spec.rb b/spec/lib/gitlab/error_tracking_spec.rb
index fd859ae40fb..4900547e9e9 100644
--- a/spec/lib/gitlab/error_tracking_spec.rb
+++ b/spec/lib/gitlab/error_tracking_spec.rb
@@ -369,6 +369,25 @@ RSpec.describe Gitlab::ErrorTracking do
end
end
+ context 'when exception is excluded' do
+ before do
+ stub_const('SubclassRetryError', Class.new(Gitlab::SidekiqMiddleware::RetryError))
+ end
+
+ ['Gitlab::SidekiqMiddleware::RetryError', 'SubclassRetryError'].each do |ex|
+ let(:exception) { ex.constantize.new }
+
+ it "does not report #{ex} exception to Sentry" do
+ expect(Gitlab::ErrorTracking::Logger).to receive(:error)
+
+ track_exception
+
+ expect(Raven.client.transport.events).to eq([])
+ expect(Sentry.get_current_client.transport.events).to eq([])
+ end
+ end
+ end
+
context 'when processing invalid URI exceptions' do
let(:invalid_uri) { 'http://foo:bar' }
let(:raven_exception_values) { raven_event['exception']['values'] }
diff --git a/spec/lib/gitlab/experimentation/group_types_spec.rb b/spec/lib/gitlab/experimentation/group_types_spec.rb
deleted file mode 100644
index 2b118d76fa4..00000000000
--- a/spec/lib/gitlab/experimentation/group_types_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-require 'fast_spec_helper'
-
-RSpec.describe Gitlab::Experimentation::GroupTypes do
- it 'defines a GROUP_CONTROL constant' do
- expect(described_class.const_defined?(:GROUP_CONTROL)).to be_truthy
- end
-
- it 'defines a GROUP_EXPERIMENTAL constant' do
- expect(described_class.const_defined?(:GROUP_EXPERIMENTAL)).to be_truthy
- end
-end
diff --git a/spec/lib/gitlab/feature_categories_spec.rb b/spec/lib/gitlab/feature_categories_spec.rb
index 477da900d0a..a35166a4499 100644
--- a/spec/lib/gitlab/feature_categories_spec.rb
+++ b/spec/lib/gitlab/feature_categories_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::FeatureCategories do
let(:fake_categories) { %w(foo bar) }
- subject { described_class.new(fake_categories) }
+ subject(:feature_categories) { described_class.new(fake_categories) }
describe "#valid?" do
it "returns true if category is known", :aggregate_failures do
@@ -14,6 +14,28 @@ RSpec.describe Gitlab::FeatureCategories do
end
end
+ describe '#get!' do
+ subject { feature_categories.get!(category) }
+
+ let(:category) { 'foo' }
+
+ it { is_expected.to eq('foo') }
+
+ context 'when category does not exist' do
+ let(:category) { 'zzz' }
+
+ it { expect { subject }.to raise_error(RuntimeError) }
+
+ context 'when on production' do
+ before do
+ allow(Gitlab).to receive(:dev_or_test_env?).and_return(false)
+ end
+
+ it { is_expected.to eq('unknown') }
+ end
+ end
+ end
+
describe "#from_request" do
let(:request_env) { {} }
let(:verified) { true }
diff --git a/spec/lib/gitlab/git/object_pool_spec.rb b/spec/lib/gitlab/git/object_pool_spec.rb
index 3b1eb0319f8..b158c7227d4 100644
--- a/spec/lib/gitlab/git/object_pool_spec.rb
+++ b/spec/lib/gitlab/git/object_pool_spec.rb
@@ -78,44 +78,40 @@ RSpec.describe Gitlab::Git::ObjectPool do
end
describe '#fetch' do
- let(:commit_count) { source_repository.commit_count }
+ context 'when the object pool repository exists' do
+ let!(:pool_repository) { create(:pool_repository, :ready) }
- context "when the object's pool repository exists" do
- it 'does not raise an error' do
- expect { subject.fetch }.not_to raise_error
+ context 'without changes' do
+ it 'does not raise an error' do
+ expect { subject.fetch }.not_to raise_error
+ end
end
- end
-
- context "when the object's pool repository does not exist" do
- before do
- subject.delete
- end
-
- it "re-creates the object pool's repository" do
- subject.fetch
-
- expect(subject.repository.exists?).to be true
- end
-
- it 'does not raise an error' do
- expect { subject.fetch }.not_to raise_error
- end
-
- it 'fetches objects from the source repository' do
- new_commit_id = source_repository.create_file(
- pool_repository.source_project.owner,
- 'a.file',
- 'This is a file',
- branch_name: source_repository.root_ref,
- message: 'Add a file'
- )
-
- expect(subject.repository.exists?).to be false
-
- subject.fetch
- expect(subject.repository.commit_count('refs/remotes/origin/heads/master')).to eq(commit_count)
- expect(subject.repository.commit(new_commit_id).id).to eq(new_commit_id)
+ context 'with new commit in source repository' do
+ let(:branch_name) { Gitlab::Git::Ref.extract_branch_name(source_repository.root_ref) }
+ let(:source_ref_name) { "refs/heads/#{branch_name}" }
+ let(:pool_ref_name) { "refs/remotes/origin/heads/#{branch_name}" }
+
+ let(:new_commit_id) do
+ source_repository.create_file(
+ pool_repository.source_project.owner,
+ 'a.file',
+ 'This is a file',
+ branch_name: branch_name,
+ message: 'Add a file'
+ )
+ end
+
+ it 'fetches objects from the source repository' do
+ # Sanity-check that the commit does not yet exist in the pool repository.
+ expect(subject.repository.commit(new_commit_id)).to be_nil
+
+ subject.fetch
+
+ expect(subject.repository.commit(pool_ref_name).id).to eq(new_commit_id)
+ expect(subject.repository.commit_count(pool_ref_name))
+ .to eq(source_repository.raw_repository.commit_count(source_ref_name))
+ end
end
end
end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index f3d3fd2034c..5e27979cbf3 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -461,11 +461,7 @@ RSpec.describe Gitlab::Git::Repository do
end
it 'raises an error if it failed' do
- # TODO: Once https://gitlab.com/gitlab-org/gitaly/-/merge_requests/4921
- # is merged, remove the assertion for Gitlab::Git::Repository::GitError
- expect { repository.delete_refs('refs\heads\fix') }.to raise_error do |e|
- expect(e).to be_a(Gitlab::Git::Repository::GitError).or be_a(Gitlab::Git::InvalidRefFormatError)
- end
+ expect { repository.delete_refs('refs\heads\fix') }.to raise_error(Gitlab::Git::InvalidRefFormatError)
end
end
@@ -940,10 +936,8 @@ RSpec.describe Gitlab::Git::Repository do
let(:options) { { ref: 'master', path: ['PROCESS.md', 'README.md'] } }
def commit_files(commit)
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- commit.deltas.flat_map do |delta|
- [delta.old_path, delta.new_path].uniq.compact
- end
+ commit.deltas.flat_map do |delta|
+ [delta.old_path, delta.new_path].uniq.compact
end
end
diff --git a/spec/lib/gitlab/git/tree_spec.rb b/spec/lib/gitlab/git/tree_spec.rb
index 7c84c737c00..17f802b9f66 100644
--- a/spec/lib/gitlab/git/tree_spec.rb
+++ b/spec/lib/gitlab/git/tree_spec.rb
@@ -239,7 +239,7 @@ RSpec.describe Gitlab::Git::Tree do
let(:pagination_params) { { limit: 5, page_token: 'aabbccdd' } }
it 'raises a command error' do
- expect { entries }.to raise_error(Gitlab::Git::CommandError, 'could not find starting OID: aabbccdd')
+ expect { entries }.to raise_error(Gitlab::Git::CommandError, /could not find starting OID: aabbccdd/)
end
end
diff --git a/spec/lib/gitlab/git_ref_validator_spec.rb b/spec/lib/gitlab/git_ref_validator_spec.rb
index 6938ad51189..03dd4e7b89b 100644
--- a/spec/lib/gitlab/git_ref_validator_spec.rb
+++ b/spec/lib/gitlab/git_ref_validator_spec.rb
@@ -35,6 +35,8 @@ RSpec.describe Gitlab::GitRefValidator do
it { expect(described_class.validate('.tag')).to be false }
it { expect(described_class.validate('my branch')).to be false }
it { expect(described_class.validate("\xA0\u0000\xB0")).to be false }
+ it { expect(described_class.validate("")).to be false }
+ it { expect(described_class.validate(nil)).to be false }
end
describe '.validate_merge_request_branch' do
@@ -67,5 +69,7 @@ RSpec.describe Gitlab::GitRefValidator do
it { expect(described_class.validate_merge_request_branch('.tag')).to be false }
it { expect(described_class.validate_merge_request_branch('my branch')).to be false }
it { expect(described_class.validate_merge_request_branch("\xA0\u0000\xB0")).to be false }
+ it { expect(described_class.validate_merge_request_branch("")).to be false }
+ it { expect(described_class.validate_merge_request_branch(nil)).to be false }
end
end
diff --git a/spec/lib/gitlab/gitaly_client/object_pool_service_spec.rb b/spec/lib/gitlab/gitaly_client/object_pool_service_spec.rb
index 9c3bc935acc..baf7076c718 100644
--- a/spec/lib/gitlab/gitaly_client/object_pool_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/object_pool_service_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Gitlab::GitalyClient::ObjectPoolService do
let(:pool_repository) { create(:pool_repository) }
- let(:project) { create(:project, :repository) }
+ let(:project) { pool_repository.source_project }
let(:raw_repository) { project.repository.raw }
let(:object_pool) { pool_repository.object_pool }
@@ -45,21 +45,32 @@ RSpec.describe Gitlab::GitalyClient::ObjectPoolService do
end
describe '#fetch' do
- before do
- subject.delete
+ context 'without changes' do
+ it 'fetches changes' do
+ expect(subject.fetch(project.repository)).to eq(Gitaly::FetchIntoObjectPoolResponse.new)
+ end
end
- it 'restores the pool repository objects' do
- subject.fetch(project.repository)
+ context 'with new reference in source repository' do
+ let(:branch) { 'ref-to-be-fetched' }
+ let(:source_ref) { "refs/heads/#{branch}" }
+ let(:pool_ref) { "refs/remotes/origin/heads/#{branch}" }
- expect(object_pool.repository.exists?).to be(true)
- end
+ before do
+ # Create a new reference in the source repository that we can fetch.
+ project.repository.write_ref(source_ref, 'refs/heads/master')
+ end
- context 'when called twice' do
- it "doesn't raise an error" do
- subject.delete
+ it 'fetches changes' do
+ # Sanity-check to verify that the reference only exists in the source repository now, but not in the
+ # object pool.
+ expect(project.repository.ref_exists?(source_ref)).to be(true)
+ expect(object_pool.repository.ref_exists?(pool_ref)).to be(false)
+
+ subject.fetch(project.repository)
- expect { subject.fetch(project.repository) }.not_to raise_error
+ # The fetch should've created the reference in the object pool.
+ expect(object_pool.repository.ref_exists?(pool_ref)).to be(true)
end
end
end
diff --git a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
index 7e8aaa3cdf4..604feeea325 100644
--- a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb
@@ -830,32 +830,225 @@ RSpec.describe Gitlab::GitalyClient::OperationService do
'master', repository)
end
- before do
- expect_any_instance_of(Gitaly::OperationService::Stub)
- .to receive(:user_commit_files).with(kind_of(Enumerator), kind_of(Hash))
- .and_return(response)
- end
+ context 'with unstructured errors' do
+ before do
+ expect_any_instance_of(Gitaly::OperationService::Stub)
+ .to receive(:user_commit_files).with(kind_of(Enumerator), kind_of(Hash))
+ .and_return(response)
+ end
- context 'when a pre_receive_error is present' do
- let(:response) { Gitaly::UserCommitFilesResponse.new(pre_receive_error: "GitLab: something failed") }
+ context 'when a pre_receive_error is present' do
+ let(:response) { Gitaly::UserCommitFilesResponse.new(pre_receive_error: "GitLab: something failed") }
- it 'raises a PreReceiveError' do
- expect { subject }.to raise_error(Gitlab::Git::PreReceiveError, "something failed")
+ it 'raises a PreReceiveError' do
+ expect { subject }.to raise_error(Gitlab::Git::PreReceiveError, "something failed")
+ end
end
- end
- context 'when an index_error is present' do
- let(:response) { Gitaly::UserCommitFilesResponse.new(index_error: "something failed") }
+ context 'when an index_error is present' do
+ let(:response) { Gitaly::UserCommitFilesResponse.new(index_error: "something failed") }
- it 'raises a PreReceiveError' do
- expect { subject }.to raise_error(Gitlab::Git::Index::IndexError, "something failed")
+ it 'raises an IndexError' do
+ expect { subject }.to raise_error(Gitlab::Git::Index::IndexError, "something failed")
+ end
+ end
+
+ context 'when branch_update is nil' do
+ let(:response) { Gitaly::UserCommitFilesResponse.new }
+
+ it { expect(subject).to be_nil }
end
end
- context 'when branch_update is nil' do
- let(:response) { Gitaly::UserCommitFilesResponse.new }
+ context 'with structured errors' do
+ context 'with AccessCheckError' do
+ before do
+ expect_any_instance_of(Gitaly::OperationService::Stub)
+ .to receive(:user_commit_files).with(kind_of(Enumerator), kind_of(Hash))
+ .and_raise(raised_error)
+ end
- it { expect(subject).to be_nil }
+ let(:raised_error) do
+ new_detailed_error(
+ GRPC::Core::StatusCodes::PERMISSION_DENIED,
+ "error updating file",
+ Gitaly::UserCommitFilesError.new(
+ access_check: Gitaly::AccessCheckError.new(
+ error_message: "something went wrong"
+ )))
+ end
+
+ it 'raises a PreReceiveError' do
+ expect { subject }.to raise_error do |error|
+ expect(error).to be_a(Gitlab::Git::PreReceiveError)
+ expect(error.message).to eq("something went wrong")
+ end
+ end
+ end
+
+ context 'with IndexError' do
+ let(:status_code) { nil }
+ let(:expected_error) { nil }
+
+ let(:structured_error) do
+ new_detailed_error(
+ status_code,
+ "unused error message",
+ expected_error)
+ end
+
+ shared_examples '#user_commit_files failure' do
+ it 'raises a PreReceiveError' do
+ expect_any_instance_of(Gitaly::OperationService::Stub)
+ .to receive(:user_commit_files).with(kind_of(Enumerator), kind_of(Hash))
+ .and_raise(structured_error)
+
+ expect { subject }.to raise_error do |error|
+ expect(error).to be_a(Gitlab::Git::Index::IndexError)
+ expect(error.message).to eq(expected_message)
+ end
+ end
+ end
+
+ context 'with missing file' do
+ let(:status_code) { GRPC::Core::StatusCodes::NOT_FOUND }
+ let(:expected_message) { "File not found: README.md" }
+ let(:expected_error) do
+ Gitaly::UserCommitFilesError.new(
+ index_update: Gitaly::IndexError.new(
+ path: "README.md",
+ error_type: Gitaly::IndexError::ErrorType::ERROR_TYPE_FILE_NOT_FOUND
+ ))
+ end
+
+ it_behaves_like '#user_commit_files failure'
+ end
+
+ context 'with existing directory' do
+ let(:status_code) { GRPC::Core::StatusCodes::ALREADY_EXISTS }
+ let(:expected_message) { "Directory already exists: dir1" }
+ let(:expected_error) do
+ Gitaly::UserCommitFilesError.new(
+ index_update: Gitaly::IndexError.new(
+ path: "dir1",
+ error_type: Gitaly::IndexError::ErrorType::ERROR_TYPE_DIRECTORY_EXISTS
+ ))
+ end
+
+ it_behaves_like '#user_commit_files failure'
+ end
+
+ context 'with existing file' do
+ let(:status_code) { GRPC::Core::StatusCodes::ALREADY_EXISTS }
+ let(:expected_message) { "File already exists: README.md" }
+ let(:expected_error) do
+ Gitaly::UserCommitFilesError.new(
+ index_update: Gitaly::IndexError.new(
+ path: "README.md",
+ error_type: Gitaly::IndexError::ErrorType::ERROR_TYPE_FILE_EXISTS
+ ))
+ end
+
+ it_behaves_like '#user_commit_files failure'
+ end
+
+ context 'with invalid path' do
+ let(:status_code) { GRPC::Core::StatusCodes::INVALID_ARGUMENT }
+ let(:expected_message) { "Invalid path: invalid://file/name" }
+ let(:expected_error) do
+ Gitaly::UserCommitFilesError.new(
+ index_update: Gitaly::IndexError.new(
+ path: "invalid://file/name",
+ error_type: Gitaly::IndexError::ErrorType::ERROR_TYPE_INVALID_PATH
+ ))
+ end
+
+ it_behaves_like '#user_commit_files failure'
+ end
+
+ context 'with directory traversal' do
+ let(:status_code) { GRPC::Core::StatusCodes::INVALID_ARGUMENT }
+ let(:expected_message) { "Directory traversal in path escapes repository: ../../../../etc/shadow" }
+ let(:expected_error) do
+ Gitaly::UserCommitFilesError.new(
+ index_update: Gitaly::IndexError.new(
+ path: "../../../../etc/shadow",
+ error_type: Gitaly::IndexError::ErrorType::ERROR_TYPE_DIRECTORY_TRAVERSAL
+ ))
+ end
+
+ it_behaves_like '#user_commit_files failure'
+ end
+
+ context 'with empty path' do
+ let(:status_code) { GRPC::Core::StatusCodes::INVALID_ARGUMENT }
+ let(:expected_message) { "Received empty path" }
+ let(:expected_error) do
+ Gitaly::UserCommitFilesError.new(
+ index_update: Gitaly::IndexError.new(
+ path: "",
+ error_type: Gitaly::IndexError::ErrorType::ERROR_TYPE_EMPTY_PATH
+ ))
+ end
+
+ it_behaves_like '#user_commit_files failure'
+ end
+
+ context 'with unspecified error' do
+ let(:status_code) { GRPC::Core::StatusCodes::INVALID_ARGUMENT }
+ let(:expected_message) { "Unknown error performing git operation" }
+ let(:expected_error) do
+ Gitaly::UserCommitFilesError.new(
+ index_update: Gitaly::IndexError.new(
+ path: "",
+ error_type: Gitaly::IndexError::ErrorType::ERROR_TYPE_UNSPECIFIED
+ ))
+ end
+
+ it_behaves_like '#user_commit_files failure'
+ end
+
+ context 'with an exception without the detailed error' do
+ let(:permission_error) do
+ GRPC::PermissionDenied.new
+ end
+
+ it 'raises PermissionDenied' do
+ expect_any_instance_of(Gitaly::OperationService::Stub)
+ .to receive(:user_commit_files).with(kind_of(Enumerator), kind_of(Hash))
+ .and_raise(permission_error)
+
+ expect { subject }.to raise_error(GRPC::PermissionDenied)
+ end
+ end
+ end
+
+ context 'with CustomHookError' do
+ before do
+ expect_any_instance_of(Gitaly::OperationService::Stub)
+ .to receive(:user_commit_files).with(kind_of(Enumerator), kind_of(Hash))
+ .and_raise(raised_error)
+ end
+
+ let(:raised_error) do
+ new_detailed_error(
+ GRPC::Core::StatusCodes::PERMISSION_DENIED,
+ "error updating file",
+ Gitaly::UserCommitFilesError.new(
+ custom_hook: Gitaly::CustomHookError.new(
+ stdout: "some stdout",
+ stderr: "GitLab: some custom hook error message",
+ hook_type: Gitaly::CustomHookError::HookType::HOOK_TYPE_PRERECEIVE
+ )))
+ end
+
+ it 'raises a PreReceiveError' do
+ expect { subject }.to raise_error do |error|
+ expect(error).to be_a(Gitlab::Git::PreReceiveError)
+ expect(error.message).to eq("some custom hook error message")
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
index 5ce88b06241..bd96e9baf1d 100644
--- a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Gitlab::GitalyClient::RefService do
- let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project, :repository, create_tag: 'test') }
let(:storage_name) { project.repository_storage }
let(:relative_path) { project.disk_path + '.git' }
@@ -438,12 +438,28 @@ RSpec.describe Gitlab::GitalyClient::RefService do
it 'sends a find_refs_by_oid message' do
expect_any_instance_of(Gitaly::RefService::Stub)
.to receive(:find_refs_by_oid)
- .with(gitaly_request_with_params(sort_field: 'refname', oid: oid, limit: 1), kind_of(Hash))
+ .with(gitaly_request_with_params(sort_field: 'refname',
+ oid: oid,
+ limit: 1), kind_of(Hash))
.and_call_original
refs = client.find_refs_by_oid(oid: oid, limit: 1)
expect(refs.to_a).to eq([Gitlab::Git::BRANCH_REF_PREFIX + project.repository.root_ref])
end
+
+ it 'filters by ref_patterns' do
+ expect_any_instance_of(Gitaly::RefService::Stub)
+ .to receive(:find_refs_by_oid)
+ .with(gitaly_request_with_params(sort_field: 'refname',
+ oid: oid,
+ limit: 1,
+ ref_patterns: [Gitlab::Git::TAG_REF_PREFIX]), kind_of(Hash))
+ .and_call_original
+
+ refs = client.find_refs_by_oid(oid: oid, limit: 1, ref_patterns: [Gitlab::Git::TAG_REF_PREFIX])
+
+ expect(refs.to_a).to eq([Gitlab::Git::TAG_REF_PREFIX + 'test'])
+ end
end
end
diff --git a/spec/lib/gitlab/gitaly_client/with_feature_flag_actors_spec.rb b/spec/lib/gitlab/gitaly_client/with_feature_flag_actors_spec.rb
new file mode 100644
index 00000000000..41dce5d76dd
--- /dev/null
+++ b/spec/lib/gitlab/gitaly_client/with_feature_flag_actors_spec.rb
@@ -0,0 +1,275 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::GitalyClient::WithFeatureFlagActors do
+ let(:user) { create(:user) }
+ let(:service) do
+ Class.new do
+ include Gitlab::GitalyClient::WithFeatureFlagActors
+ end.new
+ end
+
+ describe '#user_actor' do
+ context 'when user is not available in ApplicationContext' do
+ it 'returns nil' do
+ expect(service.user_actor).to be(nil)
+ end
+ end
+
+ context 'when user is available in ApplicationContext' do
+ around do |example|
+ ::Gitlab::ApplicationContext.with_context(user: user) { example.run }
+ end
+
+ it 'returns corresponding user record' do
+ expect(service.user_actor.flipper_id).to eql(user.flipper_id)
+ end
+ end
+
+ context 'when user does not exist' do
+ around do |example|
+ ::Gitlab::ApplicationContext.with_context(user: SecureRandom.uuid) { example.run }
+ end
+
+ it 'returns corresponding user record' do
+ expect(service.user_actor).to be(nil)
+ end
+ end
+ end
+
+ describe '#repository, #project_actor, #group_actor' do
+ context 'when normal project repository' do
+ let_it_be(:project) { create(:project, group: create(:group)) }
+ let(:expected_project) { project }
+ let(:expected_group) { Feature::Gitaly::ActorWrapper.new(::Group, project.group.id) }
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { project.repository }
+ end
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { project.repository.raw }
+ end
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { raw_repo_without_container(project.repository) }
+ end
+ end
+
+ context 'when project wiki repository' do
+ let_it_be(:project) { create(:project, :wiki_repo, group: create(:group)) }
+ let(:expected_project) { nil }
+ let(:expected_group) { nil }
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { project.wiki.repository }
+ end
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { project.wiki.repository.raw }
+ end
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { raw_repo_without_container(project.wiki.repository) }
+ end
+ end
+
+ context 'when repository of project in user namespace' do
+ let_it_be(:project) { create(:project, namespace: create(:user).namespace) }
+ let(:expected_project) { project }
+ let(:expected_group) { Feature::Gitaly::ActorWrapper.new(::Group, project.namespace_id) }
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { project.repository }
+ end
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { project.repository.raw }
+ end
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { raw_repo_without_container(project.repository) }
+ end
+ end
+
+ context 'when personal snippet' do
+ let(:snippet) { create(:personal_snippet) }
+ let(:expected_project) { nil }
+ let(:expected_group) { nil }
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { snippet.repository }
+ end
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { snippet.repository.raw }
+ end
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { raw_repo_without_container(snippet.repository) }
+ end
+ end
+
+ context 'when project snippet' do
+ let_it_be(:project) { create(:project, group: create(:group)) }
+ let(:snippet) { create(:project_snippet, project: project) }
+ let(:expected_project) { nil }
+ let(:expected_group) { nil }
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { snippet.repository }
+ end
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { snippet.repository.raw }
+ end
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { raw_repo_without_container(snippet.repository) }
+ end
+ end
+
+ context 'when project design' do
+ let_it_be(:project) { create(:project, group: create(:group)) }
+ let(:issue) { create(:issue, project: project) }
+ let(:design) { create(:design, issue: issue) }
+
+ let(:expected_project) { project }
+ let(:expected_group) { project.group }
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { design.repository }
+ end
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { design.repository.raw }
+ end
+
+ it_behaves_like 'Gitaly feature flag actors are inferred from repository' do
+ let(:repository) { raw_repo_without_container(design.repository) }
+ end
+ end
+ end
+
+ describe '#gitaly_client_call' do
+ let(:call_arg_1) { double }
+ let(:call_arg_2) { double }
+ let(:call_arg_3) { double }
+ let(:call_result) { double }
+
+ before do
+ allow(Gitlab::GitalyClient).to receive(:call).and_return(call_result)
+ end
+
+ context 'when actors_aware_gitaly_calls flag is enabled' do
+ let(:repository_actor) { instance_double(::Repository) }
+ let(:user_actor) { instance_double(::User) }
+ let(:project_actor) { instance_double(Project) }
+ let(:group_actor) { instance_double(Group) }
+
+ before do
+ stub_feature_flags(actors_aware_gitaly_calls: true)
+
+ allow(service).to receive(:user_actor).and_return(user_actor)
+ allow(service).to receive(:repository_actor).and_return(repository_actor)
+ allow(service).to receive(:project_actor).and_return(project_actor)
+ allow(service).to receive(:group_actor).and_return(group_actor)
+ allow(Gitlab::GitalyClient).to receive(:with_feature_flag_actors).and_call_original
+ end
+
+ it 'triggers client call with feature flag actors' do
+ result = service.gitaly_client_call(call_arg_1, call_arg_2, karg: call_arg_3)
+
+ expect(Gitlab::GitalyClient).to have_received(:call).with(call_arg_1, call_arg_2, karg: call_arg_3)
+ expect(Gitlab::GitalyClient).to have_received(:with_feature_flag_actors).with(
+ repository: repository_actor,
+ user: user_actor,
+ project: project_actor,
+ group: group_actor
+ )
+ expect(result).to be(call_result)
+ end
+
+ context 'when call without repository_actor' do
+ before do
+ allow(service).to receive(:repository_actor).and_return(nil)
+ allow(Gitlab::ErrorTracking).to receive(:track_and_raise_for_dev_exception).and_call_original
+ end
+
+ it 'calls error tracking track_and_raise_for_dev_exception' do
+ expect do
+ service.gitaly_client_call(call_arg_1, call_arg_2, karg: call_arg_3)
+ end.to raise_error /gitaly_client_call called without setting repository_actor/
+
+ expect(Gitlab::ErrorTracking).to have_received(:track_and_raise_for_dev_exception).with(
+ be_a(Feature::InvalidFeatureFlagError)
+ )
+ end
+ end
+ end
+
+ context 'when actors_aware_gitaly_calls not enabled' do
+ before do
+ stub_feature_flags(actors_aware_gitaly_calls: false)
+ end
+
+ it 'triggers client call without feature flag actors' do
+ expect(Gitlab::GitalyClient).not_to receive(:with_feature_flag_actors)
+
+ result = service.gitaly_client_call(call_arg_1, call_arg_2, karg: call_arg_3)
+
+ expect(Gitlab::GitalyClient).to have_received(:call).with(call_arg_1, call_arg_2, karg: call_arg_3)
+ expect(result).to be(call_result)
+ end
+ end
+
+ describe '#gitaly_feature_flag_actors' do
+ let_it_be(:project) { create(:project) }
+ let(:repository_actor) { project.repository }
+
+ context 'when actors_aware_gitaly_calls flag is enabled' do
+ let(:user_actor) { instance_double(::User) }
+ let(:project_actor) { instance_double(Project) }
+ let(:group_actor) { instance_double(Group) }
+
+ before do
+ stub_feature_flags(actors_aware_gitaly_calls: true)
+
+ allow(Feature::Gitaly).to receive(:user_actor).and_return(user_actor)
+ allow(Feature::Gitaly).to receive(:project_actor).with(project).and_return(project_actor)
+ allow(Feature::Gitaly).to receive(:group_actor).with(project).and_return(group_actor)
+ end
+
+ it 'returns a hash with collected feature flag actors' do
+ result = service.gitaly_feature_flag_actors(repository_actor)
+ expect(result).to eql(
+ repository: repository_actor,
+ user: user_actor,
+ project: project_actor,
+ group: group_actor
+ )
+
+ expect(Feature::Gitaly).to have_received(:user_actor).with(no_args)
+ expect(Feature::Gitaly).to have_received(:project_actor).with(project)
+ expect(Feature::Gitaly).to have_received(:group_actor).with(project)
+ end
+ end
+
+ context 'when actors_aware_gitaly_calls not enabled' do
+ before do
+ stub_feature_flags(actors_aware_gitaly_calls: false)
+ end
+
+ it 'returns an empty hash' do
+ expect(Feature::Gitaly).not_to receive(:user_actor)
+ expect(Feature::Gitaly).not_to receive(:project_actor)
+ expect(Feature::Gitaly).not_to receive(:group_actor)
+
+ result = service.gitaly_feature_flag_actors(repository_actor)
+ expect(result).to eql({})
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index a3840ca843f..3d33bf93c23 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -259,6 +259,102 @@ RSpec.describe Gitlab::GitalyClient do
end
end
+ shared_examples 'gitaly feature flags in metadata' do
+ before do
+ allow(Feature::Gitaly).to receive(:server_feature_flags).and_return(
+ 'gitaly-feature-a' => 'true',
+ 'gitaly-feature-b' => 'false'
+ )
+ end
+
+ it 'evaluates Gitaly server feature flags' do
+ metadata = described_class.request_kwargs('default', timeout: 1)[:metadata]
+
+ expect(Feature::Gitaly).to have_received(:server_feature_flags).with(no_args)
+ expect(metadata['gitaly-feature-a']).to be('true')
+ expect(metadata['gitaly-feature-b']).to be('false')
+ end
+
+ context 'when there are actors' do
+ let(:repository_actor) { double(:actor) }
+ let(:project_actor) { double(:actor) }
+ let(:user_actor) { double(:actor) }
+ let(:group_actor) { double(:actor) }
+
+ it 'evaluates Gitaly server feature flags with actors' do
+ metadata = described_class.with_feature_flag_actors(
+ repository: repository_actor,
+ project: project_actor,
+ user: user_actor,
+ group: group_actor
+ ) do
+ described_class.request_kwargs('default', timeout: 1)[:metadata]
+ end
+
+ expect(Feature::Gitaly).to have_received(:server_feature_flags).with(
+ repository: repository_actor,
+ project: project_actor,
+ user: user_actor,
+ group: group_actor
+ )
+ expect(metadata['gitaly-feature-a']).to be('true')
+ expect(metadata['gitaly-feature-b']).to be('false')
+ end
+ end
+ end
+
+ context 'server_feature_flags when RequestStore is activated', :request_store do
+ it_behaves_like 'gitaly feature flags in metadata'
+ end
+
+ context 'server_feature_flags when RequestStore is not activated' do
+ it_behaves_like 'gitaly feature flags in metadata'
+ end
+
+ context 'logging information in metadata' do
+ let(:user) { create(:user) }
+
+ context 'user is added to application context' do
+ it 'injects username and user_id into gRPC metadata' do
+ metadata = {}
+ ::Gitlab::ApplicationContext.with_context(user: user) do
+ metadata = described_class.request_kwargs('default', timeout: 1)[:metadata]
+ end
+
+ expect(metadata['username']).to eql(user.username)
+ expect(metadata['user_id']).to eql(user.id.to_s)
+ end
+ end
+
+ context 'user is not added to application context' do
+ it 'does not inject username and user_id into gRPC metadata' do
+ metadata = described_class.request_kwargs('default', timeout: 1)[:metadata]
+
+ expect(metadata).not_to have_key('username')
+ expect(metadata).not_to have_key('user_id')
+ end
+ end
+
+ context 'remote_ip is added to application context' do
+ it 'injects remote_ip into gRPC metadata' do
+ metadata = {}
+ ::Gitlab::ApplicationContext.with_context(remote_ip: '1.2.3.4') do
+ metadata = described_class.request_kwargs('default', timeout: 1)[:metadata]
+ end
+
+ expect(metadata['remote_ip']).to eql('1.2.3.4')
+ end
+ end
+
+ context 'remote_ip is not added to application context' do
+ it 'does not inject remote_ip into gRPC metadata' do
+ metadata = described_class.request_kwargs('default', timeout: 1)[:metadata]
+
+ expect(metadata).not_to have_key('remote_ip')
+ end
+ end
+ end
+
context 'gitlab_git_env' do
let(:policy) { 'gitaly-route-repository-accessor-policy' }
@@ -585,4 +681,42 @@ RSpec.describe Gitlab::GitalyClient do
end
end
end
+
+ describe '.with_feature_flag_actor', :request_store do
+ shared_examples 'with_feature_flag_actor' do
+ let(:repository_actor) { double(:actor) }
+ let(:project_actor) { double(:actor) }
+ let(:user_actor) { double(:actor) }
+ let(:group_actor) { double(:actor) }
+
+ it 'allows access to feature flag actors inside the block' do
+ expect(described_class.feature_flag_actors).to eql({})
+
+ described_class.with_feature_flag_actors(
+ repository: repository_actor,
+ project: project_actor,
+ user: user_actor,
+ group: group_actor
+ ) do
+ expect(
+ described_class.feature_flag_actors
+ ).to eql(
+ repository: repository_actor,
+ project: project_actor,
+ user: user_actor,
+ group: group_actor)
+ end
+
+ expect(described_class.feature_flag_actors).to eql({})
+ end
+ end
+
+ context 'when RequestStore is activated', :request_store do
+ it_behaves_like 'with_feature_flag_actor'
+ end
+
+ context 'when RequestStore is not activated' do
+ it_behaves_like 'with_feature_flag_actor'
+ end
+ end
end
diff --git a/spec/lib/gitlab/github_import/attachments_downloader_spec.rb b/spec/lib/gitlab/github_import/attachments_downloader_spec.rb
index 57391e06192..dc9f939a19b 100644
--- a/spec/lib/gitlab/github_import/attachments_downloader_spec.rb
+++ b/spec/lib/gitlab/github_import/attachments_downloader_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Gitlab::GithubImport::AttachmentsDownloader do
let_it_be(:content_type) { 'application/octet-stream' }
let(:content_length) { 1000 }
- let(:chunk_double) { instance_double(HTTParty::FragmentWithResponse, code: 200) }
+ let(:chunk_double) { instance_double(HTTParty::ResponseFragment, code: 200) }
let(:headers_double) do
instance_double(
HTTParty::Response,
diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb
index 3361b039a27..95f7933fbc5 100644
--- a/spec/lib/gitlab/github_import/client_spec.rb
+++ b/spec/lib/gitlab/github_import/client_spec.rb
@@ -3,24 +3,24 @@
require 'spec_helper'
RSpec.describe Gitlab::GithubImport::Client do
- describe '#parallel?' do
- it 'returns true when the client is running in parallel mode' do
- client = described_class.new('foo', parallel: true)
+ subject(:client) { described_class.new('foo', parallel: parallel) }
+
+ let(:parallel) { true }
- expect(client).to be_parallel
+ describe '#parallel?' do
+ context 'when the client is running in parallel mode' do
+ it { expect(client).to be_parallel }
end
- it 'returns false when the client is running in sequential mode' do
- client = described_class.new('foo', parallel: false)
+ context 'when the client is running in sequential mode' do
+ let(:parallel) { false }
- expect(client).not_to be_parallel
+ it { expect(client).not_to be_parallel }
end
end
describe '#user' do
it 'returns the details for the given username' do
- client = described_class.new('foo')
-
expect(client.octokit).to receive(:user).with('foo')
expect(client).to receive(:with_rate_limit).and_yield
@@ -30,8 +30,6 @@ RSpec.describe Gitlab::GithubImport::Client do
describe '#pull_request_reviews' do
it 'returns the pull request reviews' do
- client = described_class.new('foo')
-
expect(client)
.to receive(:each_object)
.with(:pull_request_reviews, 'foo/bar', 999)
@@ -40,10 +38,17 @@ RSpec.describe Gitlab::GithubImport::Client do
end
end
+ describe '#pull_request_review_requests' do
+ it 'returns the pull request review requests' do
+ expect(client.octokit).to receive(:pull_request_review_requests).with('foo/bar', 999)
+ expect(client).to receive(:with_rate_limit).and_yield
+
+ client.pull_request_review_requests('foo/bar', 999)
+ end
+ end
+
describe '#repos' do
it 'returns the user\'s repositories as a hash' do
- client = described_class.new('foo')
-
stub_request(:get, 'https://api.github.com/rate_limit')
.to_return(status: 200, headers: { 'X-RateLimit-Limit' => 5000, 'X-RateLimit-Remaining' => 5000 })
@@ -58,8 +63,6 @@ RSpec.describe Gitlab::GithubImport::Client do
describe '#repository' do
it 'returns the details of a repository' do
- client = described_class.new('foo')
-
expect(client.octokit).to receive(:repo).with('foo/bar')
expect(client).to receive(:with_rate_limit).and_yield
@@ -67,8 +70,6 @@ RSpec.describe Gitlab::GithubImport::Client do
end
it 'returns repository data as a hash' do
- client = described_class.new('foo')
-
stub_request(:get, 'https://api.github.com/rate_limit')
.to_return(status: 200, headers: { 'X-RateLimit-Limit' => 5000, 'X-RateLimit-Remaining' => 5000 })
@@ -83,8 +84,6 @@ RSpec.describe Gitlab::GithubImport::Client do
describe '#pull_request' do
it 'returns the details of a pull_request' do
- client = described_class.new('foo')
-
expect(client.octokit).to receive(:pull_request).with('foo/bar', 999)
expect(client).to receive(:with_rate_limit).and_yield
@@ -94,8 +93,6 @@ RSpec.describe Gitlab::GithubImport::Client do
describe '#labels' do
it 'returns the labels' do
- client = described_class.new('foo')
-
expect(client)
.to receive(:each_object)
.with(:labels, 'foo/bar')
@@ -106,8 +103,6 @@ RSpec.describe Gitlab::GithubImport::Client do
describe '#milestones' do
it 'returns the milestones' do
- client = described_class.new('foo')
-
expect(client)
.to receive(:each_object)
.with(:milestones, 'foo/bar')
@@ -118,8 +113,6 @@ RSpec.describe Gitlab::GithubImport::Client do
describe '#releases' do
it 'returns the releases' do
- client = described_class.new('foo')
-
expect(client)
.to receive(:each_object)
.with(:releases, 'foo/bar')
@@ -130,8 +123,6 @@ RSpec.describe Gitlab::GithubImport::Client do
describe '#branches' do
it 'returns the branches' do
- client = described_class.new('foo')
-
expect(client)
.to receive(:each_object)
.with(:branches, 'foo/bar')
@@ -142,8 +133,6 @@ RSpec.describe Gitlab::GithubImport::Client do
describe '#branch_protection' do
it 'returns the protection details for the given branch' do
- client = described_class.new('foo')
-
expect(client.octokit)
.to receive(:branch_protection).with('org/repo', 'bar')
expect(client).to receive(:with_rate_limit).and_yield
@@ -156,8 +145,6 @@ RSpec.describe Gitlab::GithubImport::Client do
describe '#each_object' do
it 'converts each object into a hash' do
- client = described_class.new('foo')
-
stub_request(:get, 'https://api.github.com/rate_limit')
.to_return(status: 200, headers: { 'X-RateLimit-Limit' => 5000, 'X-RateLimit-Remaining' => 5000 })
@@ -171,7 +158,6 @@ RSpec.describe Gitlab::GithubImport::Client do
end
describe '#each_page' do
- let(:client) { described_class.new('foo') }
let(:object1) { double(:object1) }
let(:object2) { double(:object2) }
@@ -242,8 +228,6 @@ RSpec.describe Gitlab::GithubImport::Client do
end
describe '#with_rate_limit' do
- let(:client) { described_class.new('foo') }
-
it 'yields the supplied block when enough requests remain' do
expect(client).to receive(:requests_remaining?).and_return(true)
@@ -340,8 +324,6 @@ RSpec.describe Gitlab::GithubImport::Client do
end
describe '#requests_remaining?' do
- let(:client) { described_class.new('foo') }
-
context 'when default requests limit is set' do
before do
allow(client).to receive(:requests_limit).and_return(5000)
@@ -380,44 +362,43 @@ RSpec.describe Gitlab::GithubImport::Client do
end
describe '#raise_or_wait_for_rate_limit' do
- it 'raises RateLimitError when running in parallel mode' do
- client = described_class.new('foo', parallel: true)
-
- expect { client.raise_or_wait_for_rate_limit }
- .to raise_error(Gitlab::GithubImport::RateLimitError)
+ context 'when running in parallel mode' do
+ it 'raises RateLimitError' do
+ expect { client.raise_or_wait_for_rate_limit }
+ .to raise_error(Gitlab::GithubImport::RateLimitError)
+ end
end
- it 'sleeps when running in sequential mode' do
- client = described_class.new('foo', parallel: false)
-
- expect(client).to receive(:rate_limit_resets_in).and_return(1)
- expect(client).to receive(:sleep).with(1)
+ context 'when running in sequential mode' do
+ let(:parallel) { false }
- client.raise_or_wait_for_rate_limit
- end
+ it 'sleeps' do
+ expect(client).to receive(:rate_limit_resets_in).and_return(1)
+ expect(client).to receive(:sleep).with(1)
- it 'increments the rate limit counter' do
- client = described_class.new('foo', parallel: false)
+ client.raise_or_wait_for_rate_limit
+ end
- expect(client)
- .to receive(:rate_limit_resets_in)
- .and_return(1)
+ it 'increments the rate limit counter' do
+ expect(client)
+ .to receive(:rate_limit_resets_in)
+ .and_return(1)
- expect(client)
- .to receive(:sleep)
- .with(1)
+ expect(client)
+ .to receive(:sleep)
+ .with(1)
- expect(client.rate_limit_counter)
- .to receive(:increment)
- .and_call_original
+ expect(client.rate_limit_counter)
+ .to receive(:increment)
+ .and_call_original
- client.raise_or_wait_for_rate_limit
+ client.raise_or_wait_for_rate_limit
+ end
end
end
describe '#remaining_requests' do
it 'returns the number of remaining requests' do
- client = described_class.new('foo')
rate_limit = double(remaining: 1)
expect(client.octokit).to receive(:rate_limit).and_return(rate_limit)
@@ -427,7 +408,6 @@ RSpec.describe Gitlab::GithubImport::Client do
describe '#requests_limit' do
it 'returns requests limit' do
- client = described_class.new('foo')
rate_limit = double(limit: 1)
expect(client.octokit).to receive(:rate_limit).and_return(rate_limit)
@@ -437,7 +417,6 @@ RSpec.describe Gitlab::GithubImport::Client do
describe '#rate_limit_resets_in' do
it 'returns the number of seconds after which the rate limit is reset' do
- client = described_class.new('foo')
rate_limit = double(resets_in: 1)
expect(client.octokit).to receive(:rate_limit).and_return(rate_limit)
@@ -447,8 +426,6 @@ RSpec.describe Gitlab::GithubImport::Client do
end
describe '#api_endpoint' do
- let(:client) { described_class.new('foo') }
-
context 'without a custom endpoint configured in Omniauth' do
it 'returns the default API endpoint' do
expect(client)
@@ -473,8 +450,6 @@ RSpec.describe Gitlab::GithubImport::Client do
end
describe '#web_endpoint' do
- let(:client) { described_class.new('foo') }
-
context 'without a custom endpoint configured in Omniauth' do
it 'returns the default web endpoint' do
expect(client)
@@ -499,8 +474,6 @@ RSpec.describe Gitlab::GithubImport::Client do
end
describe '#custom_api_endpoint' do
- let(:client) { described_class.new('foo') }
-
context 'without a custom endpoint' do
it 'returns nil' do
expect(client)
@@ -533,8 +506,6 @@ RSpec.describe Gitlab::GithubImport::Client do
end
describe '#verify_ssl' do
- let(:client) { described_class.new('foo') }
-
context 'without a custom configuration' do
it 'returns true' do
expect(client)
@@ -553,8 +524,6 @@ RSpec.describe Gitlab::GithubImport::Client do
end
describe '#github_omniauth_provider' do
- let(:client) { described_class.new('foo') }
-
context 'without a configured provider' do
it 'returns an empty Hash' do
expect(Gitlab.config.omniauth)
@@ -576,8 +545,6 @@ RSpec.describe Gitlab::GithubImport::Client do
end
describe '#rate_limiting_enabled?' do
- let(:client) { described_class.new('foo') }
-
it 'returns true when using GitHub.com' do
expect(client.rate_limiting_enabled?).to eq(true)
end
@@ -592,7 +559,6 @@ RSpec.describe Gitlab::GithubImport::Client do
end
describe 'search' do
- let(:client) { described_class.new('foo') }
let(:user) { { login: 'user' } }
let(:org1) { { login: 'org1' } }
let(:org2) { { login: 'org2' } }
diff --git a/spec/lib/gitlab/github_import/importer/events/changed_label_spec.rb b/spec/lib/gitlab/github_import/importer/events/changed_label_spec.rb
index 4476b4123ee..6a409762599 100644
--- a/spec/lib/gitlab/github_import/importer/events/changed_label_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/events/changed_label_spec.rb
@@ -10,7 +10,9 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedLabel do
let(:client) { instance_double('Gitlab::GithubImport::Client') }
let(:issuable) { create(:issue, project: project) }
- let!(:label) { create(:label, project: project) }
+ let(:label) { create(:label, project: project) }
+ let(:label_title) { label.title }
+ let(:label_id) { label.id }
let(:issue_event) do
Gitlab::GithubImport::Representation::IssueEvent.from_json_hash(
@@ -18,7 +20,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedLabel do
'actor' => { 'id' => user.id, 'login' => user.username },
'event' => event_type,
'commit_id' => nil,
- 'label_title' => label.title,
+ 'label_title' => label_title,
'created_at' => '2022-04-26 18:30:53 UTC',
'issue' => { 'number' => issuable.iid, pull_request: issuable.is_a?(MergeRequest) }
)
@@ -27,7 +29,7 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedLabel do
let(:event_attrs) do
{
user_id: user.id,
- label_id: label.id,
+ label_id: label_id,
created_at: issue_event.created_at
}.stringify_keys
end
@@ -42,7 +44,6 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedLabel do
end
before do
- allow(Gitlab::Cache::Import::Caching).to receive(:read_integer).and_return(label.id)
allow_next_instance_of(Gitlab::GithubImport::IssuableFinder) do |finder|
allow(finder).to receive(:database_id).and_return(issuable.id)
end
@@ -52,16 +53,35 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedLabel do
end
context 'with Issue' do
- context 'when importing a labeled event' do
- let(:event_type) { 'labeled' }
- let(:expected_event_attrs) { event_attrs.merge(issue_id: issuable.id, action: 'add') }
+ context 'when importing event with associated label' do
+ before do
+ allow(Gitlab::Cache::Import::Caching).to receive(:read_integer).and_return(label.id)
+ end
- it_behaves_like 'new event'
+ context 'when importing a labeled event' do
+ let(:event_type) { 'labeled' }
+ let(:expected_event_attrs) { event_attrs.merge(issue_id: issuable.id, action: 'add') }
+
+ it_behaves_like 'new event'
+ end
+
+ context 'when importing an unlabeled event' do
+ let(:event_type) { 'unlabeled' }
+ let(:expected_event_attrs) { event_attrs.merge(issue_id: issuable.id, action: 'remove') }
+
+ it_behaves_like 'new event'
+ end
end
- context 'when importing an unlabeled event' do
- let(:event_type) { 'unlabeled' }
- let(:expected_event_attrs) { event_attrs.merge(issue_id: issuable.id, action: 'remove') }
+ context 'when importing event without associated label' do
+ before do
+ allow(Gitlab::Cache::Import::Caching).to receive(:read_integer).and_return(nil)
+ end
+
+ let(:label_title) { 'deleted_label' }
+ let(:label_id) { nil }
+ let(:event_type) { 'labeled' }
+ let(:expected_event_attrs) { event_attrs.merge(issue_id: issuable.id, action: 'add') }
it_behaves_like 'new event'
end
@@ -70,16 +90,35 @@ RSpec.describe Gitlab::GithubImport::Importer::Events::ChangedLabel do
context 'with MergeRequest' do
let(:issuable) { create(:merge_request, source_project: project, target_project: project) }
- context 'when importing a labeled event' do
- let(:event_type) { 'labeled' }
- let(:expected_event_attrs) { event_attrs.merge(merge_request_id: issuable.id, action: 'add') }
+ context 'when importing event with associated label' do
+ before do
+ allow(Gitlab::Cache::Import::Caching).to receive(:read_integer).and_return(label.id)
+ end
- it_behaves_like 'new event'
+ context 'when importing a labeled event' do
+ let(:event_type) { 'labeled' }
+ let(:expected_event_attrs) { event_attrs.merge(merge_request_id: issuable.id, action: 'add') }
+
+ it_behaves_like 'new event'
+ end
+
+ context 'when importing an unlabeled event' do
+ let(:event_type) { 'unlabeled' }
+ let(:expected_event_attrs) { event_attrs.merge(merge_request_id: issuable.id, action: 'remove') }
+
+ it_behaves_like 'new event'
+ end
end
- context 'when importing an unlabeled event' do
- let(:event_type) { 'unlabeled' }
- let(:expected_event_attrs) { event_attrs.merge(merge_request_id: issuable.id, action: 'remove') }
+ context 'when importing event without associated label' do
+ before do
+ allow(Gitlab::Cache::Import::Caching).to receive(:read_integer).and_return(nil)
+ end
+
+ let(:label_title) { 'deleted_label' }
+ let(:label_id) { nil }
+ let(:event_type) { 'labeled' }
+ let(:expected_event_attrs) { event_attrs.merge(merge_request_id: issuable.id, action: 'add') }
it_behaves_like 'new event'
end
diff --git a/spec/lib/gitlab/github_import/importer/protected_branch_importer_spec.rb b/spec/lib/gitlab/github_import/importer/protected_branch_importer_spec.rb
index 027b2ac422e..d6b7411e640 100644
--- a/spec/lib/gitlab/github_import/importer/protected_branch_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/protected_branch_importer_spec.rb
@@ -6,20 +6,23 @@ RSpec.describe Gitlab::GithubImport::Importer::ProtectedBranchImporter do
subject(:importer) { described_class.new(github_protected_branch, project, client) }
let(:branch_name) { 'protection' }
- let(:allow_force_pushes_on_github) { true }
+ let(:allow_force_pushes_on_github) { false }
+ let(:require_code_owner_reviews_on_github) { false }
let(:required_conversation_resolution) { false }
let(:required_signatures) { false }
let(:required_pull_request_reviews) { false }
let(:expected_push_access_level) { Gitlab::Access::MAINTAINER }
let(:expected_merge_access_level) { Gitlab::Access::MAINTAINER }
- let(:expected_allow_force_push) { true }
+ let(:expected_allow_force_push) { false }
+ let(:expected_code_owner_approval_required) { false }
let(:github_protected_branch) do
Gitlab::GithubImport::Representation::ProtectedBranch.new(
id: branch_name,
allow_force_pushes: allow_force_pushes_on_github,
required_conversation_resolution: required_conversation_resolution,
required_signatures: required_signatures,
- required_pull_request_reviews: required_pull_request_reviews
+ required_pull_request_reviews: required_pull_request_reviews,
+ require_code_owner_reviews: require_code_owner_reviews_on_github
)
end
@@ -35,7 +38,8 @@ RSpec.describe Gitlab::GithubImport::Importer::ProtectedBranchImporter do
name: 'protection',
push_access_levels_attributes: [{ access_level: expected_push_access_level }],
merge_access_levels_attributes: [{ access_level: expected_merge_access_level }],
- allow_force_push: expected_allow_force_push
+ allow_force_push: expected_allow_force_push,
+ code_owner_approval_required: expected_code_owner_approval_required
}
end
@@ -70,41 +74,35 @@ RSpec.describe Gitlab::GithubImport::Importer::ProtectedBranchImporter do
end
context 'when branch is protected on GitLab' do
- before do
- create(
- :protected_branch,
- project: project,
- name: 'protect*',
- allow_force_push: allow_force_pushes_on_gitlab
- )
+ using RSpec::Parameterized::TableSyntax
+
+ where(
+ :allow_force_pushes_on_github,
+ :allow_force_pushes_on_gitlab,
+ :expected_allow_force_push
+ ) do
+ true | true | true
+ true | false | false
+ false | true | false
+ false | false | false
end
- context 'when branch protection rule on Gitlab is stricter than on Github' do
- let(:allow_force_pushes_on_github) { true }
- let(:allow_force_pushes_on_gitlab) { false }
- let(:expected_allow_force_push) { false }
-
- it_behaves_like 'create branch protection by the strictest ruleset'
- end
-
- context 'when branch protection rule on Github is stricter than on Gitlab' do
- let(:allow_force_pushes_on_github) { false }
- let(:allow_force_pushes_on_gitlab) { true }
- let(:expected_allow_force_push) { false }
-
- it_behaves_like 'create branch protection by the strictest ruleset'
- end
-
- context 'when branch protection rules on Github and Gitlab are the same' do
- let(:allow_force_pushes_on_github) { true }
- let(:allow_force_pushes_on_gitlab) { true }
- let(:expected_allow_force_push) { true }
+ with_them do
+ before do
+ create(
+ :protected_branch,
+ project: project,
+ name: 'protect*',
+ allow_force_push: allow_force_pushes_on_gitlab
+ )
+ end
it_behaves_like 'create branch protection by the strictest ruleset'
end
end
context 'when branch is not protected on GitLab' do
+ let(:allow_force_pushes_on_github) { true }
let(:expected_allow_force_push) { true }
it_behaves_like 'create branch protection by the strictest ruleset'
@@ -115,6 +113,30 @@ RSpec.describe Gitlab::GithubImport::Importer::ProtectedBranchImporter do
allow(project).to receive(:default_branch).and_return(branch_name)
end
+ context 'when "allow force pushes - everyone" rule is enabled' do
+ let(:allow_force_pushes_on_github) { true }
+
+ context 'when there is any default branch protection' do
+ before do
+ stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_FULL)
+ end
+
+ let(:expected_allow_force_push) { false }
+
+ it_behaves_like 'create branch protection by the strictest ruleset'
+ end
+
+ context 'when there is no default branch protection' do
+ before do
+ stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE)
+ end
+
+ let(:expected_allow_force_push) { allow_force_pushes_on_github }
+
+ it_behaves_like 'create branch protection by the strictest ruleset'
+ end
+ end
+
context 'when required_conversation_resolution rule is enabled' do
let(:required_conversation_resolution) { true }
@@ -241,7 +263,8 @@ RSpec.describe Gitlab::GithubImport::Importer::ProtectedBranchImporter do
:protected_branch,
project: project,
name: 'protect*',
- allow_force_push: true
+ allow_force_push: true,
+ code_owner_approval_required: false
)
end
@@ -297,5 +320,67 @@ RSpec.describe Gitlab::GithubImport::Importer::ProtectedBranchImporter do
it_behaves_like 'create branch protection by the strictest ruleset'
end
end
+
+ context 'when the code_owner_approval_required feature is available', if: Gitlab.ee? do
+ before do
+ stub_licensed_features(code_owner_approval_required: true)
+ end
+
+ context 'when branch is protected on GitLab' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(
+ :require_code_owner_reviews_on_github,
+ :require_code_owner_reviews_on_gitlab,
+ :expected_code_owner_approval_required
+ ) do
+ true | true | true
+ true | false | true
+ false | true | true
+ false | false | false
+ end
+
+ with_them do
+ before do
+ create(
+ :protected_branch,
+ project: project,
+ name: 'protect*',
+ allow_force_push: true,
+ code_owner_approval_required: require_code_owner_reviews_on_gitlab
+ )
+ end
+
+ it_behaves_like 'create branch protection by the strictest ruleset'
+ end
+ end
+
+ context 'when branch is not protected on GitLab' do
+ context 'when require_code_owner_reviews rule is enabled on GitHub' do
+ let(:require_code_owner_reviews_on_github) { true }
+ let(:expected_code_owner_approval_required) { true }
+
+ it_behaves_like 'create branch protection by the strictest ruleset'
+ end
+
+ context 'when require_code_owner_reviews rule is disabled on GitHub' do
+ let(:require_code_owner_reviews_on_github) { false }
+ let(:expected_code_owner_approval_required) { false }
+
+ it_behaves_like 'create branch protection by the strictest ruleset'
+ end
+ end
+ end
+
+ context 'when the code_owner_approval_required feature is not available' do
+ before do
+ stub_licensed_features(code_owner_approval_required: false)
+ end
+
+ let(:require_code_owner_reviews_on_github) { true }
+ let(:expected_code_owner_approval_required) { false }
+
+ it_behaves_like 'create branch protection by the strictest ruleset'
+ end
end
end
diff --git a/spec/lib/gitlab/github_import/importer/protected_branches_importer_spec.rb b/spec/lib/gitlab/github_import/importer/protected_branches_importer_spec.rb
index a0ced456391..8809d58a252 100644
--- a/spec/lib/gitlab/github_import/importer/protected_branches_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/protected_branches_importer_spec.rb
@@ -29,7 +29,10 @@ RSpec.describe Gitlab::GithubImport::Importer::ProtectedBranchesImporter do
required_signatures = Struct.new(:url, :enabled, keyword_init: true)
enforce_admins = Struct.new(:url, :enabled, keyword_init: true)
allow_option = Struct.new(:enabled, keyword_init: true)
- required_pull_request_reviews = Struct.new(:url, :dismissal_restrictions, keyword_init: true)
+ required_pull_request_reviews = Struct.new(
+ :url, :dismissal_restrictions, :require_code_owner_reviews,
+ keyword_init: true
+ )
response.new(
name: 'main',
url: 'https://example.com/branches/main/protection',
@@ -58,7 +61,8 @@ RSpec.describe Gitlab::GithubImport::Importer::ProtectedBranchesImporter do
),
required_pull_request_reviews: required_pull_request_reviews.new(
url: 'https://example.com/branches/main/protection/required_pull_request_reviews',
- dismissal_restrictions: {}
+ dismissal_restrictions: {},
+ require_code_owner_reviews: true
)
)
end
@@ -160,6 +164,7 @@ RSpec.describe Gitlab::GithubImport::Importer::ProtectedBranchesImporter do
let(:branch_struct) { Struct.new(:protection, :name, :url, keyword_init: true) }
let(:protection_struct) { Struct.new(:enabled, keyword_init: true) }
let(:protected_branch) { branch_struct.new(name: 'main', protection: protection_struct.new(enabled: true)) }
+ let(:second_protected_branch) { branch_struct.new(name: 'fix', protection: protection_struct.new(enabled: true)) }
let(:unprotected_branch) { branch_struct.new(name: 'staging', protection: protection_struct.new(enabled: false)) }
# when user has no admin rights on repo
let(:unknown_protection_branch) { branch_struct.new(name: 'development', protection: nil) }
@@ -168,9 +173,9 @@ RSpec.describe Gitlab::GithubImport::Importer::ProtectedBranchesImporter do
before do
allow(client).to receive(:branches).with(project.import_source)
- .and_return([protected_branch, unprotected_branch, unknown_protection_branch])
+ .and_return([protected_branch, second_protected_branch, unprotected_branch, unknown_protection_branch])
allow(client).to receive(:branch_protection)
- .with(project.import_source, protected_branch.name).once
+ .with(project.import_source, anything)
.and_return(github_protection_rule)
allow(Gitlab::GithubImport::ObjectCounter).to receive(:increment)
.with(project, :protected_branch, :fetched)
@@ -180,12 +185,13 @@ RSpec.describe Gitlab::GithubImport::Importer::ProtectedBranchesImporter do
subject.each_object_to_import do |object|
expect(object).to eq github_protection_rule
end
- expect(Gitlab::GithubImport::ObjectCounter).to have_received(:increment).once
+ expect(Gitlab::GithubImport::ObjectCounter).to have_received(:increment).twice
end
context 'when protected branch is already processed' do
it "doesn't process this branch" do
subject.mark_as_imported(protected_branch)
+ subject.mark_as_imported(second_protected_branch)
subject.each_object_to_import {}
expect(Gitlab::GithubImport::ObjectCounter).not_to have_received(:increment)
diff --git a/spec/lib/gitlab/github_import/importer/pull_request_review_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_request_review_importer_spec.rb
index fb6024d0952..49794eceb5a 100644
--- a/spec/lib/gitlab/github_import/importer/pull_request_review_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/pull_request_review_importer_spec.rb
@@ -8,11 +8,48 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestReviewImporter, :clean
let_it_be(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
- let(:client_double) { double(user: { id: 999, login: 'author', email: 'author@email.com' }) }
let(:submitted_at) { Time.new(2017, 1, 1, 12, 00).utc }
+ let(:client_double) do
+ instance_double(
+ 'Gitlab::GithubImport::Client',
+ user: { id: 999, login: 'author', email: 'author@email.com' }
+ )
+ end
subject { described_class.new(review, project, client_double) }
+ shared_examples 'imports a reviewer for the Merge Request' do
+ it 'creates reviewer for the Merge Request' do
+ expect { subject.execute }.to change(MergeRequestReviewer, :count).by(1)
+
+ expect(merge_request.reviewers).to contain_exactly(author)
+ end
+
+ context 'when reviewer already exists' do
+ before do
+ create(
+ :merge_request_reviewer,
+ reviewer: author, merge_request: merge_request, state: 'unreviewed'
+ )
+ end
+
+ it 'does not change Merge Request reviewers' do
+ expect { subject.execute }.not_to change(MergeRequestReviewer, :count)
+
+ expect(merge_request.reviewers).to contain_exactly(author)
+ end
+ end
+ end
+
+ shared_examples 'imports an approval for the Merge Request' do
+ it 'creates an approval for the Merge Request' do
+ expect { subject.execute }.to change(Approval, :count).by(1)
+
+ expect(merge_request.approved_by_users.reload).to include(author)
+ expect(merge_request.approvals.last.created_at).to eq(submitted_at)
+ end
+ end
+
context 'when the review author can be mapped to a gitlab user' do
let_it_be(:author) { create(:user, email: 'author@email.com') }
@@ -20,34 +57,38 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestReviewImporter, :clean
context 'when the review is "APPROVED"' do
let(:review) { create_review(type: 'APPROVED', note: '') }
- it 'creates a note for the review and approves the Merge Request' do
- expect { subject.execute }
- .to change(Note, :count).by(1)
- .and change(Approval, :count).by(1)
+ it_behaves_like 'imports an approval for the Merge Request'
+ it_behaves_like 'imports a reviewer for the Merge Request'
+
+ it 'creates a note for the review' do
+ expect { subject.execute }.to change(Note, :count).by(1)
last_note = merge_request.notes.last
expect(last_note.note).to eq('approved this merge request')
expect(last_note.author).to eq(author)
expect(last_note.created_at).to eq(submitted_at)
expect(last_note.system_note_metadata.action).to eq('approved')
-
- expect(merge_request.approved_by_users.reload).to include(author)
- expect(merge_request.approvals.last.created_at).to eq(submitted_at)
end
- it 'does nothing if the user already approved the merge request' do
- create(:approval, merge_request: merge_request, user: author)
+ context 'when the user already approved the merge request' do
+ before do
+ create(:approval, merge_request: merge_request, user: author)
+ end
- expect { subject.execute }
- .to change(Note, :count).by(0)
- .and change(Approval, :count).by(0)
+ it 'does not import second approve and note' do
+ expect { subject.execute }
+ .to change(Note, :count).by(0)
+ .and change(Approval, :count).by(0)
+ end
end
end
context 'when the review is "COMMENTED"' do
let(:review) { create_review(type: 'COMMENTED', note: '') }
- it 'creates a note for the review' do
+ it_behaves_like 'imports a reviewer for the Merge Request'
+
+ it 'does not create note for the review' do
expect { subject.execute }.not_to change(Note, :count)
end
end
@@ -55,7 +96,9 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestReviewImporter, :clean
context 'when the review is "CHANGES_REQUESTED"' do
let(:review) { create_review(type: 'CHANGES_REQUESTED', note: '') }
- it 'creates a note for the review' do
+ it_behaves_like 'imports a reviewer for the Merge Request'
+
+ it 'does not create a note for the review' do
expect { subject.execute }.not_to change(Note, :count)
end
end
@@ -65,10 +108,11 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestReviewImporter, :clean
context 'when the review is "APPROVED"' do
let(:review) { create_review(type: 'APPROVED') }
+ it_behaves_like 'imports an approval for the Merge Request'
+ it_behaves_like 'imports a reviewer for the Merge Request'
+
it 'creates a note for the review' do
- expect { subject.execute }
- .to change(Note, :count).by(2)
- .and change(Approval, :count).by(1)
+ expect { subject.execute }.to change(Note, :count).by(2)
note = merge_request.notes.where(system: false).last
expect(note.note).to eq("**Review:** Approved\n\nnote")
@@ -80,9 +124,6 @@ RSpec.describe Gitlab::GithubImport::Importer::PullRequestReviewImporter, :clean
expect(system_note.author).to eq(author)
expect(system_note.created_at).to eq(submitted_at)
expect(system_note.system_note_metadata.action).to eq('approved')
-
- expect(merge_request.approved_by_users.reload).to include(author)
- expect(merge_request.approvals.last.created_at).to eq(submitted_at)
end
end
diff --git a/spec/lib/gitlab/github_import/importer/pull_requests/review_request_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_requests/review_request_importer_spec.rb
new file mode 100644
index 00000000000..6dcbc4e32e6
--- /dev/null
+++ b/spec/lib/gitlab/github_import/importer/pull_requests/review_request_importer_spec.rb
@@ -0,0 +1,35 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::GithubImport::Importer::PullRequests::ReviewRequestImporter, :clean_gitlab_redis_cache do
+ subject(:importer) { described_class.new(review_request, project, client) }
+
+ let(:project) { instance_double('Project') }
+ let(:client) { instance_double('Gitlab::GithubImport::Client') }
+ let(:merge_request) { create(:merge_request) }
+ let(:reviewer) { create(:user, username: 'alice') }
+ let(:review_request) do
+ Gitlab::GithubImport::Representation::PullRequests::ReviewRequests.from_json_hash(
+ merge_request_id: merge_request.id,
+ users: [
+ { 'id' => 1, 'login' => reviewer.username },
+ { 'id' => 2, 'login' => 'foo' }
+ ]
+ )
+ end
+
+ before do
+ allow_next_instance_of(Gitlab::GithubImport::UserFinder) do |finder|
+ allow(finder).to receive(:find).with(1, reviewer.username).and_return(reviewer.id)
+ allow(finder).to receive(:find).with(2, 'foo').and_return(nil)
+ end
+ end
+
+ it 'imports merge request reviewers that were found' do
+ importer.execute
+
+ expect(merge_request.reviewers.size).to eq 1
+ expect(merge_request.reviewers[0].id).to eq reviewer.id
+ end
+end
diff --git a/spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb
new file mode 100644
index 00000000000..6c7fc4d5b15
--- /dev/null
+++ b/spec/lib/gitlab/github_import/importer/pull_requests/review_requests_importer_spec.rb
@@ -0,0 +1,141 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::GithubImport::Importer::PullRequests::ReviewRequestsImporter, :clean_gitlab_redis_cache do
+ subject(:importer) { described_class.new(project, client) }
+
+ let_it_be(:project) { create(:project, import_source: 'foo') }
+
+ let(:client) { instance_double(Gitlab::GithubImport::Client) }
+ let(:review_request_struct) { Struct.new(:merge_request_id, :users, keyword_init: true) }
+ let(:user_struct) { Struct.new(:id, :login, keyword_init: true) }
+
+ shared_context 'when project with merge requests' do
+ let_it_be(:merge_request_1) { create(:merge_request, source_project: project, target_branch: 'feature1') }
+ let_it_be(:merge_request_2) { create(:merge_request, source_project: project, target_branch: 'feature2') }
+
+ let(:importer_stub) { instance_double('Gitlab::GithubImport::Importer::NoteAttachmentsImporter') }
+ let(:importer_attrs) do
+ [instance_of(Gitlab::GithubImport::Representation::PullRequests::ReviewRequests), project, client]
+ end
+
+ let(:review_requests_1) do
+ {
+ users: [
+ { id: 4, login: 'alice' },
+ { id: 5, login: 'bob' }
+ ]
+ }
+ end
+
+ let(:review_requests_2) do
+ {
+ users: [{ id: 4, login: 'alice' }]
+ }
+ end
+
+ before do
+ allow(client).to receive(:pull_request_review_requests)
+ .with(project.import_source, merge_request_1.iid).and_return(review_requests_1)
+ allow(client).to receive(:pull_request_review_requests)
+ .with(project.import_source, merge_request_2.iid).and_return(review_requests_2)
+ end
+ end
+
+ describe '#sequential_import' do
+ include_context 'when project with merge requests'
+
+ it 'imports each project merge request reviewers' do
+ expect_next_instances_of(
+ Gitlab::GithubImport::Importer::PullRequests::ReviewRequestImporter, 2, false, *importer_attrs
+ ) do |note_attachments_importer|
+ expect(note_attachments_importer).to receive(:execute)
+ end
+
+ importer.sequential_import
+ end
+
+ context 'when merge request is already processed' do
+ before do
+ Gitlab::Cache::Import::Caching.set_add(
+ "github-importer/pull_requests/pull_request_review_requests/already-imported/#{project.id}",
+ merge_request_1.iid
+ )
+ end
+
+ it "doesn't import this merge request reviewers" do
+ expect_next_instance_of(
+ Gitlab::GithubImport::Importer::PullRequests::ReviewRequestImporter, *importer_attrs
+ ) do |note_attachments_importer|
+ expect(note_attachments_importer).to receive(:execute)
+ end
+
+ importer.sequential_import
+ end
+ end
+ end
+
+ describe '#parallel_import' do
+ include_context 'when project with merge requests'
+
+ let(:expected_worker_payload) do
+ [
+ [
+ project.id,
+ {
+ merge_request_id: merge_request_1.id,
+ users: [
+ { id: 4, login: 'alice' },
+ { id: 5, login: 'bob' }
+ ]
+ },
+ instance_of(String)
+ ],
+ [
+ project.id,
+ {
+ merge_request_id: merge_request_2.id,
+ users: [
+ { id: 4, login: 'alice' }
+ ]
+ },
+ instance_of(String)
+ ]
+ ]
+ end
+
+ it 'schedule import for each merge request reviewers' do
+ expect(Gitlab::GithubImport::PullRequests::ImportReviewRequestWorker)
+ .to receive(:bulk_perform_in).with(
+ 1.second,
+ expected_worker_payload,
+ batch_size: 1000,
+ batch_delay: 1.minute
+ )
+
+ importer.parallel_import
+ end
+
+ context 'when merge request is already processed' do
+ before do
+ Gitlab::Cache::Import::Caching.set_add(
+ "github-importer/pull_requests/pull_request_review_requests/already-imported/#{project.id}",
+ merge_request_1.iid
+ )
+ end
+
+ it "doesn't schedule import this merge request reviewers" do
+ expect(Gitlab::GithubImport::PullRequests::ImportReviewRequestWorker)
+ .to receive(:bulk_perform_in).with(
+ 1.second,
+ expected_worker_payload.slice(1, 1),
+ batch_size: 1000,
+ batch_delay: 1.minute
+ )
+
+ importer.parallel_import
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/github_import/representation/protected_branch_spec.rb b/spec/lib/gitlab/github_import/representation/protected_branch_spec.rb
index 30b29659eee..60cae79459e 100644
--- a/spec/lib/gitlab/github_import/representation/protected_branch_spec.rb
+++ b/spec/lib/gitlab/github_import/representation/protected_branch_spec.rb
@@ -24,6 +24,10 @@ RSpec.describe Gitlab::GithubImport::Representation::ProtectedBranch do
it 'includes the protected branch required_pull_request_reviews' do
expect(protected_branch.required_pull_request_reviews).to eq true
end
+
+ it 'includes the protected branch require_code_owner_reviews' do
+ expect(protected_branch.require_code_owner_reviews).to eq true
+ end
end
end
@@ -35,7 +39,10 @@ RSpec.describe Gitlab::GithubImport::Representation::ProtectedBranch do
keyword_init: true
)
enabled_setting = Struct.new(:enabled, keyword_init: true)
- required_pull_request_reviews = Struct.new(:url, :dismissal_restrictions, keyword_init: true)
+ required_pull_request_reviews = Struct.new(
+ :url, :dismissal_restrictions, :require_code_owner_reviews,
+ keyword_init: true
+ )
response.new(
url: 'https://example.com/branches/main/protection',
allow_force_pushes: enabled_setting.new(
@@ -49,7 +56,8 @@ RSpec.describe Gitlab::GithubImport::Representation::ProtectedBranch do
),
required_pull_request_reviews: required_pull_request_reviews.new(
url: 'https://example.com/branches/main/protection/required_pull_request_reviews',
- dismissal_restrictions: {}
+ dismissal_restrictions: {},
+ require_code_owner_reviews: true
)
)
end
@@ -67,7 +75,8 @@ RSpec.describe Gitlab::GithubImport::Representation::ProtectedBranch do
'allow_force_pushes' => true,
'required_conversation_resolution' => true,
'required_signatures' => true,
- 'required_pull_request_reviews' => true
+ 'required_pull_request_reviews' => true,
+ 'require_code_owner_reviews' => true
}
end
diff --git a/spec/lib/gitlab/github_import/representation/pull_requests/review_requests_spec.rb b/spec/lib/gitlab/github_import/representation/pull_requests/review_requests_spec.rb
new file mode 100644
index 00000000000..0393f692a69
--- /dev/null
+++ b/spec/lib/gitlab/github_import/representation/pull_requests/review_requests_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::GithubImport::Representation::PullRequests::ReviewRequests do
+ shared_examples 'Review requests' do
+ it 'returns an instance of Review Request' do
+ expect(review_requests).to be_an_instance_of(described_class)
+ end
+
+ context 'for returned Review Requests' do
+ it 'includes merge request id' do
+ expect(review_requests.merge_request_id).to eq(merge_request_id)
+ end
+
+ it 'includes reviewers' do
+ expect(review_requests.users.size).to eq 2
+
+ user = review_requests.users[0]
+ expect(user).to be_an_instance_of(Gitlab::GithubImport::Representation::User)
+ expect(user.id).to eq(4)
+ expect(user.login).to eq('alice')
+ end
+ end
+ end
+
+ let(:merge_request_id) { 6501124486 }
+ let(:response) do
+ {
+ 'merge_request_id' => merge_request_id,
+ 'users' => [
+ { 'id' => 4, 'login' => 'alice' },
+ { 'id' => 5, 'login' => 'bob' }
+ ]
+ }
+ end
+
+ describe '.from_api_response' do
+ it_behaves_like 'Review requests' do
+ let(:review_requests) { described_class.from_api_response(response) }
+ end
+ end
+
+ describe '.from_json_hash' do
+ it_behaves_like 'Review requests' do
+ let(:review_requests) { described_class.from_json_hash(response) }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gon_helper_spec.rb b/spec/lib/gitlab/gon_helper_spec.rb
index dd4dcca809b..5a1fcc5e2dc 100644
--- a/spec/lib/gitlab/gon_helper_spec.rb
+++ b/spec/lib/gitlab/gon_helper_spec.rb
@@ -39,6 +39,58 @@ RSpec.describe Gitlab::GonHelper do
helper.add_gon_variables
end
end
+
+ describe 'sentry configuration' do
+ let(:clientside_dsn) { 'https://xxx@sentry.example.com/1' }
+ let(:environment) { 'staging' }
+
+ describe 'sentry integration' do
+ before do
+ stub_config(sentry: { enabled: true, clientside_dsn: clientside_dsn, environment: environment })
+ end
+
+ it 'sets sentry dsn and environment from config' do
+ expect(gon).to receive(:sentry_dsn=).with(clientside_dsn)
+ expect(gon).to receive(:sentry_environment=).with(environment)
+
+ helper.add_gon_variables
+ end
+ end
+
+ describe 'new sentry integration' do
+ before do
+ stub_application_setting(sentry_enabled: true)
+ stub_application_setting(sentry_clientside_dsn: clientside_dsn)
+ stub_application_setting(sentry_environment: environment)
+ end
+
+ context 'when enable_new_sentry_clientside_integration is disabled' do
+ before do
+ stub_feature_flags(enable_new_sentry_clientside_integration: false)
+ end
+
+ it 'does not set sentry dsn and environment from config' do
+ expect(gon).not_to receive(:sentry_dsn=).with(clientside_dsn)
+ expect(gon).not_to receive(:sentry_environment=).with(environment)
+
+ helper.add_gon_variables
+ end
+ end
+
+ context 'when enable_new_sentry_clientside_integration is enabled' do
+ before do
+ stub_feature_flags(enable_new_sentry_clientside_integration: true)
+ end
+
+ it 'sets sentry dsn and environment from config' do
+ expect(gon).to receive(:sentry_dsn=).with(clientside_dsn)
+ expect(gon).to receive(:sentry_environment=).with(environment)
+
+ helper.add_gon_variables
+ end
+ end
+ end
+ end
end
describe '#push_frontend_feature_flag' do
diff --git a/spec/lib/gitlab/grape_logging/loggers/filter_parameters_spec.rb b/spec/lib/gitlab/grape_logging/loggers/filter_parameters_spec.rb
new file mode 100644
index 00000000000..15c842c9f44
--- /dev/null
+++ b/spec/lib/gitlab/grape_logging/loggers/filter_parameters_spec.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::GrapeLogging::Loggers::FilterParameters do
+ subject { described_class.new }
+
+ describe ".parameters" do
+ let(:route) { instance_double('Grape::Router::Route', settings: settings) }
+ let(:endpoint) { instance_double('Grape::Endpoint', route: route) }
+
+ let(:env) do
+ { 'rack.input' => '', Grape::Env::API_ENDPOINT => endpoint }
+ end
+
+ let(:mock_request) { ActionDispatch::Request.new(env) }
+
+ before do
+ mock_request.params['key'] = 'some key'
+ mock_request.params['foo'] = 'wibble'
+ mock_request.params['value'] = 'some value'
+ mock_request.params['oof'] = 'wobble'
+ mock_request.params['other'] = 'Unaffected'
+ end
+
+ context 'when the log_safety setting is provided' do
+ let(:settings) { { log_safety: { safe: %w[foo bar key], unsafe: %w[oof rab value] } } }
+
+ it 'includes safe parameters, and filters unsafe ones' do
+ data = subject.parameters(mock_request, nil)
+
+ expect(data).to eq(
+ params: {
+ 'key' => 'some key',
+ 'foo' => 'wibble',
+ 'value' => '[FILTERED]',
+ 'oof' => '[FILTERED]',
+ 'other' => 'Unaffected'
+ }
+ )
+ end
+ end
+
+ context 'when the log_safety is not provided' do
+ let(:settings) { {} }
+
+ it 'behaves like the normal parameter filter' do
+ data = subject.parameters(mock_request, nil)
+
+ expect(data).to eq(
+ params: {
+ 'key' => '[FILTERED]',
+ 'foo' => 'wibble',
+ 'value' => 'some value',
+ 'oof' => 'wobble',
+ 'other' => 'Unaffected'
+ }
+ )
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/health_checks/gitaly_check_spec.rb b/spec/lib/gitlab/health_checks/gitaly_check_spec.rb
index 000b8eff661..948452c0b58 100644
--- a/spec/lib/gitlab/health_checks/gitaly_check_spec.rb
+++ b/spec/lib/gitlab/health_checks/gitaly_check_spec.rb
@@ -40,9 +40,9 @@ RSpec.describe Gitlab::HealthChecks::GitalyCheck do
end
let(:healthy_check) { double(check: { success: true }) }
- let(:ready_check) { double(readiness_check: { success: false, message: 'Clock is out of sync' }) }
+ let(:ready_check) { double(readiness_check: { success: false, message: 'A readiness check has failed' }) }
- it { is_expected.to match_array([result_class.new('gitaly_check', false, 'Clock is out of sync', shard: 'default')]) }
+ it { is_expected.to match_array([result_class.new('gitaly_check', false, 'A readiness check has failed', shard: 'default')]) }
end
end
diff --git a/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb b/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb
index cb8fef60ab2..f9a6c25b786 100644
--- a/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb
+++ b/spec/lib/gitlab/hook_data/merge_request_builder_spec.rb
@@ -78,6 +78,7 @@ RSpec.describe Gitlab::HookData::MergeRequestBuilder do
state
blocking_discussions_resolved
first_contribution
+ detailed_merge_status
].freeze
expect(data).to include(*expected_additional_attributes)
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index ccc4f1f7149..e9dde1c6180 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -52,6 +52,7 @@ issues:
- user_mentions
- system_note_metadata
- alert_management_alert
+- alert_management_alerts
- status_page_published_incident
- namespace
- note_authors
@@ -361,10 +362,12 @@ hooks:
- web_hook_logs
protected_branches:
- project
+- group
- merge_access_levels
- push_access_levels
- unprotect_access_levels
- approval_project_rules
+- external_status_checks
- required_code_owners_sections
protected_tags:
- project
@@ -538,6 +541,7 @@ project:
- jenkins_integration
- index_status
- feature_usage
+- regular_or_any_approver_approval_rules
- approval_rules
- approval_merge_request_rules
- approval_merge_request_rule_sources
@@ -548,6 +552,7 @@ project:
- path_locks
- approver_groups
- repository_state
+- wiki_repository
- wiki_repository_state
- source_pipelines
- sourced_pipelines
@@ -643,6 +648,7 @@ project:
- build_artifacts_size_refresh
- project_callouts
- pipeline_metadata
+- disable_download_button
award_emoji:
- awardable
- user
diff --git a/spec/lib/gitlab/import_export/decompressed_archive_size_validator_spec.rb b/spec/lib/gitlab/import_export/decompressed_archive_size_validator_spec.rb
index 9af72cc0dea..a6cb74c3c9f 100644
--- a/spec/lib/gitlab/import_export/decompressed_archive_size_validator_spec.rb
+++ b/spec/lib/gitlab/import_export/decompressed_archive_size_validator_spec.rb
@@ -112,7 +112,7 @@ RSpec.describe Gitlab::ImportExport::DecompressedArchiveSizeValidator do
context 'when archive path is not a string' do
let(:filepath) { 123 }
- let(:error_message) { 'Archive path is not a string' }
+ let(:error_message) { 'Invalid path' }
it 'returns false' do
expect(subject.valid?).to eq(false)
diff --git a/spec/lib/gitlab/import_export/design_repo_restorer_spec.rb b/spec/lib/gitlab/import_export/design_repo_restorer_spec.rb
index 346f653acd4..5ef9eb78d3b 100644
--- a/spec/lib/gitlab/import_export/design_repo_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/design_repo_restorer_spec.rb
@@ -3,8 +3,6 @@
require 'spec_helper'
RSpec.describe Gitlab::ImportExport::DesignRepoRestorer do
- include GitHelpers
-
describe 'bundle a design Git repo' do
let(:user) { create(:user) }
let!(:project_with_design_repo) { create(:project, :design_repo) }
@@ -29,10 +27,8 @@ RSpec.describe Gitlab::ImportExport::DesignRepoRestorer do
after do
FileUtils.rm_rf(export_path)
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- FileUtils.rm_rf(project_with_design_repo.design_repository.path_to_repo)
- FileUtils.rm_rf(project.design_repository.path_to_repo)
- end
+ project_with_design_repo.design_repository.remove
+ project.design_repository.remove
end
it 'restores the repo successfully' do
diff --git a/spec/lib/gitlab/import_export/fork_spec.rb b/spec/lib/gitlab/import_export/fork_spec.rb
index 25c82588c13..9d766eb3af1 100644
--- a/spec/lib/gitlab/import_export/fork_spec.rb
+++ b/spec/lib/gitlab/import_export/fork_spec.rb
@@ -47,10 +47,8 @@ RSpec.describe 'forked project import' do
after do
FileUtils.rm_rf(export_path)
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- FileUtils.rm_rf(project_with_repo.repository.path_to_repo)
- FileUtils.rm_rf(project.repository.path_to_repo)
- end
+ project_with_repo.repository.remove
+ project.repository.remove
end
it 'can access the MR', :sidekiq_might_not_need_inline do
diff --git a/spec/lib/gitlab/import_export/group/tree_saver_spec.rb b/spec/lib/gitlab/import_export/group/tree_saver_spec.rb
index 85d07e3fe63..79ab1913e7e 100644
--- a/spec/lib/gitlab/import_export/group/tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/group/tree_saver_spec.rb
@@ -106,7 +106,7 @@ RSpec.describe Gitlab::ImportExport::Group::TreeSaver do
members
milestones
].each do |association|
- path = exported_path_for("#{g.id}", "#{association}.ndjson")
+ path = exported_path_for(g.id.to_s, "#{association}.ndjson")
expect(File.exist?(path)).to eq(true), "#{path} does not exist"
end
end
diff --git a/spec/lib/gitlab/import_export/import_test_coverage_spec.rb b/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
index 51c0008b2b4..b1f5574fba1 100644
--- a/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
+++ b/spec/lib/gitlab/import_export/import_test_coverage_spec.rb
@@ -96,11 +96,11 @@ RSpec.describe 'Test coverage of the Project Import' do
case item
when Hash
item.each do |k, v|
- if (v.is_a?(Array) || v.is_a?(Hash)) && v.present?
- new_path = path + [k]
- res << new_path
- gather_relations(v, res, new_path)
- end
+ next unless (v.is_a?(Array) || v.is_a?(Hash)) && v.present?
+
+ new_path = path + [k]
+ res << new_path
+ gather_relations(v, res, new_path)
end
when Array
item.each { |i| gather_relations(i, res, path) }
diff --git a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb
index 550cefea805..3ca9f727033 100644
--- a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb
+++ b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb
@@ -23,9 +23,7 @@ RSpec.describe Gitlab::ImportExport::MergeRequestParser do
end
after do
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- FileUtils.rm_rf(project.repository.path_to_repo)
- end
+ project.repository.remove
end
it 'has a source branch' do
diff --git a/spec/lib/gitlab/import_export/project/exported_relations_merger_spec.rb b/spec/lib/gitlab/import_export/project/exported_relations_merger_spec.rb
new file mode 100644
index 00000000000..a781139acab
--- /dev/null
+++ b/spec/lib/gitlab/import_export/project/exported_relations_merger_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::ImportExport::Project::ExportedRelationsMerger do
+ let(:export_job) { create(:project_export_job) }
+
+ let(:shared) { Gitlab::ImportExport::Shared.new(export_job.project) }
+
+ before do
+ create(:project_relation_export_upload,
+ relation_export: create(:project_relation_export, relation: 'project', project_export_job: export_job),
+ export_file: fixture_file_upload("spec/fixtures/gitlab/import_export/project.tar.gz")
+ )
+
+ create(:project_relation_export_upload,
+ relation_export: create(:project_relation_export, relation: 'labels', project_export_job: export_job),
+ export_file: fixture_file_upload("spec/fixtures/gitlab/import_export/labels.tar.gz")
+ )
+
+ create(:project_relation_export_upload,
+ relation_export: create(:project_relation_export, relation: 'uploads', project_export_job: export_job),
+ export_file: fixture_file_upload("spec/fixtures/gitlab/import_export/uploads.tar.gz")
+ )
+ end
+
+ describe '#save' do
+ subject(:service) { described_class.new(export_job: export_job, shared: shared) }
+
+ it 'downloads, extracts, and merges all files into export_path' do
+ Dir.mktmpdir do |dirpath|
+ allow(shared).to receive(:export_path).and_return(dirpath)
+
+ result = service.save
+
+ expect(result).to eq(true)
+ expect(Dir.glob("#{dirpath}/**/*")).to match_array(
+ [
+ "#{dirpath}/project",
+ "#{dirpath}/project/project.json",
+ "#{dirpath}/project/labels.ndjson",
+ "#{dirpath}/uploads",
+ "#{dirpath}/uploads/70edb596c34ad7795baa6a0f0aa03d44",
+ "#{dirpath}/uploads/70edb596c34ad7795baa6a0f0aa03d44/file1.txt",
+ "#{dirpath}/uploads/c8c93c6f546b002cbce4cb8d05d0dfb8",
+ "#{dirpath}/uploads/c8c93c6f546b002cbce4cb8d05d0dfb8/file2.txt"
+ ]
+ )
+ end
+ end
+
+ context 'when exception occurs' do
+ before do
+ create(:project_relation_export, relation: 'releases', project_export_job: export_job)
+ create(:project_relation_export, relation: 'issues', project_export_job: export_job)
+ end
+
+ it 'registers the exception messages and returns false' do
+ Dir.mktmpdir do |dirpath|
+ allow(shared).to receive(:export_path).and_return(dirpath)
+
+ result = service.save
+
+ expect(result).to eq(false)
+ expect(shared.errors).to match_array(
+ [
+ "undefined method `export_file' for nil:NilClass",
+ "undefined method `export_file' for nil:NilClass"
+ ]
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_export/project/relation_saver_spec.rb b/spec/lib/gitlab/import_export/project/relation_saver_spec.rb
index dec51b3afd1..0467b63e918 100644
--- a/spec/lib/gitlab/import_export/project/relation_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project/relation_saver_spec.rb
@@ -28,14 +28,14 @@ RSpec.describe Gitlab::ImportExport::Project::RelationSaver do
it 'serializes the root node as a json file in the export path' do
relation_saver.save # rubocop:disable Rails/SaveBang
- json = read_json(File.join(shared.export_path, 'project.json'))
+ json = read_json(File.join(shared.export_path, 'tree', 'project.json'))
expect(json).to include({ 'description' => 'Project description' })
end
it 'serializes only allowed attributes' do
relation_saver.save # rubocop:disable Rails/SaveBang
- json = read_json(File.join(shared.export_path, 'project.json'))
+ json = read_json(File.join(shared.export_path, 'tree', 'project.json'))
expect(json).to include({ 'description' => 'Project description' })
expect(json.keys).not_to include('name')
end
@@ -54,7 +54,7 @@ RSpec.describe Gitlab::ImportExport::Project::RelationSaver do
it 'serializes the child node as a ndjson file in the export path inside the project folder' do
relation_saver.save # rubocop:disable Rails/SaveBang
- ndjson = read_ndjson(File.join(shared.export_path, 'project', "#{relation}.ndjson"))
+ ndjson = read_ndjson(File.join(shared.export_path, 'tree', 'project', "#{relation}.ndjson"))
expect(ndjson.first).to include({ 'title' => 'Label 1' })
expect(ndjson.second).to include({ 'title' => 'Label 2' })
end
@@ -62,7 +62,7 @@ RSpec.describe Gitlab::ImportExport::Project::RelationSaver do
it 'serializes only allowed attributes' do
relation_saver.save # rubocop:disable Rails/SaveBang
- ndjson = read_ndjson(File.join(shared.export_path, 'project', "#{relation}.ndjson"))
+ ndjson = read_ndjson(File.join(shared.export_path, 'tree', 'project', "#{relation}.ndjson"))
expect(ndjson.first.keys).not_to include('description_html')
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 fae94a3b544..b753746cd8c 100644
--- a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
@@ -160,7 +160,7 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer do
pipeline = Ci::Pipeline.find_by_sha('sha-notes')
pipeline_metadata = pipeline.pipeline_metadata
- expect(pipeline_metadata.title).to eq('Build pipeline')
+ expect(pipeline_metadata.name).to eq('Build pipeline')
expect(pipeline_metadata.pipeline_id).to eq(pipeline.id)
expect(pipeline_metadata.project_id).to eq(pipeline.project_id)
end
diff --git a/spec/lib/gitlab/import_export/recursive_merge_folders_spec.rb b/spec/lib/gitlab/import_export/recursive_merge_folders_spec.rb
new file mode 100644
index 00000000000..6e5be0b2829
--- /dev/null
+++ b/spec/lib/gitlab/import_export/recursive_merge_folders_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::ImportExport::RecursiveMergeFolders do
+ describe '.merge' do
+ it 'merge folder and ignore symlinks' do
+ Dir.mktmpdir do |tmpdir|
+ source = "#{tmpdir}/source"
+ FileUtils.mkdir_p("#{source}/folder/folder")
+ FileUtils.touch("#{source}/file1.txt")
+ FileUtils.touch("#{source}/folder/file2.txt")
+ FileUtils.touch("#{source}/folder/folder/file3.txt")
+ FileUtils.ln_s("#{source}/file1.txt", "#{source}/symlink-file1.txt")
+ FileUtils.ln_s("#{source}/folder", "#{source}/symlink-folder")
+
+ target = "#{tmpdir}/target"
+ FileUtils.mkdir_p("#{target}/folder/folder")
+ FileUtils.mkdir_p("#{target}/folderA")
+ FileUtils.touch("#{target}/fileA.txt")
+
+ described_class.merge(source, target)
+
+ expect(Dir.children("#{tmpdir}/target")).to match_array(%w[folder file1.txt folderA fileA.txt])
+ expect(Dir.children("#{tmpdir}/target/folder")).to match_array(%w[folder file2.txt])
+ expect(Dir.children("#{tmpdir}/target/folder/folder")).to match_array(%w[file3.txt])
+ end
+ end
+
+ it 'raises an error for invalid source path' do
+ Dir.mktmpdir do |tmpdir|
+ expect do
+ described_class.merge("#{tmpdir}/../", tmpdir)
+ end.to raise_error(Gitlab::Utils::PathTraversalAttackError)
+ end
+ end
+
+ it 'raises an error for source path outside temp dir' do
+ Dir.mktmpdir do |tmpdir|
+ expect do
+ described_class.merge('/', tmpdir )
+ end.to raise_error(StandardError, 'path / is not allowed')
+ end
+ end
+
+ it 'raises an error for invalid target path' do
+ Dir.mktmpdir do |tmpdir|
+ expect do
+ described_class.merge(tmpdir, "#{tmpdir}/../")
+ end.to raise_error(Gitlab::Utils::PathTraversalAttackError)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_export/repo_restorer_spec.rb b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
index c0215ff5843..727ca4f630b 100644
--- a/spec/lib/gitlab/import_export/repo_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/repo_restorer_spec.rb
@@ -3,8 +3,6 @@
require 'spec_helper'
RSpec.describe Gitlab::ImportExport::RepoRestorer do
- include GitHelpers
-
let_it_be(:project_with_repo) do
create(:project, :repository, :wiki_repo, name: 'test-repo-restorer', path: 'test-repo-restorer').tap do |p|
p.wiki.create_page('page', 'foobar', :markdown, 'created page')
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index 23eb93a1bce..75d980cd5f4 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -336,7 +336,7 @@ Ci::PipelineMetadata:
- id
- project_id
- pipeline_id
-- title
+- name
Ci::Stage:
- id
- name
@@ -568,6 +568,7 @@ Project:
- suggestion_commit_message
- merge_commit_template
- squash_commit_template
+- issue_branch_template
Author:
- name
ProjectFeature:
@@ -592,6 +593,7 @@ ProjectFeature:
- feature_flags_access_level
- releases_access_level
- monitor_access_level
+- infrastructure_access_level
- created_at
- updated_at
ProtectedBranch::MergeAccessLevel:
diff --git a/spec/lib/gitlab/import_export/snippets_repo_restorer_spec.rb b/spec/lib/gitlab/import_export/snippets_repo_restorer_spec.rb
index e529d36fd11..ebb0d62afa0 100644
--- a/spec/lib/gitlab/import_export/snippets_repo_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/snippets_repo_restorer_spec.rb
@@ -3,8 +3,6 @@
require 'spec_helper'
RSpec.describe Gitlab::ImportExport::SnippetsRepoRestorer do
- include GitHelpers
-
describe 'bundle a snippet Git repo' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, namespace: user.namespace) }
diff --git a/spec/lib/gitlab/inactive_projects_deletion_warning_tracker_spec.rb b/spec/lib/gitlab/inactive_projects_deletion_warning_tracker_spec.rb
index 7afb80488d8..cb4fdeed1a1 100644
--- a/spec/lib/gitlab/inactive_projects_deletion_warning_tracker_spec.rb
+++ b/spec/lib/gitlab/inactive_projects_deletion_warning_tracker_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Gitlab::InactiveProjectsDeletionWarningTracker, :freeze_time do
end
it 'returns the list of projects for which deletion warning email has been sent' do
- expected_hash = { "project:1" => "#{Date.current}" }
+ expected_hash = { "project:1" => Date.current.to_s }
expect(Gitlab::InactiveProjectsDeletionWarningTracker.notified_projects).to eq(expected_hash)
end
@@ -57,7 +57,7 @@ RSpec.describe Gitlab::InactiveProjectsDeletionWarningTracker, :freeze_time do
end
it 'returns the date if a deletion warning email has been sent for a given project' do
- expect(Gitlab::InactiveProjectsDeletionWarningTracker.new(project_id).notification_date).to eq("#{Date.current}")
+ expect(Gitlab::InactiveProjectsDeletionWarningTracker.new(project_id).notification_date).to eq(Date.current.to_s)
end
it 'returns nil if a deletion warning email has not been sent for a given project' do
diff --git a/spec/lib/gitlab/incoming_email_spec.rb b/spec/lib/gitlab/incoming_email_spec.rb
index 1545de6d8fd..acd6634058f 100644
--- a/spec/lib/gitlab/incoming_email_spec.rb
+++ b/spec/lib/gitlab/incoming_email_spec.rb
@@ -1,87 +1,17 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
RSpec.describe Gitlab::IncomingEmail do
- describe "self.enabled?" do
- context "when reply by email is enabled" do
- before do
- stub_incoming_email_setting(enabled: true)
- end
-
- it 'returns true' do
- expect(described_class.enabled?).to be(true)
- end
- end
-
- context "when reply by email is disabled" do
- before do
- stub_incoming_email_setting(enabled: false)
- end
+ let(:setting_name) { :incoming_email }
- it "returns false" do
- expect(described_class.enabled?).to be(false)
- end
- end
- end
+ it_behaves_like 'common email methods'
- describe 'self.supports_wildcard?' do
- context 'address contains the wildcard placeholder' do
- before do
- stub_incoming_email_setting(address: 'replies+%{key}@example.com')
- end
-
- it 'confirms that wildcard is supported' do
- expect(described_class.supports_wildcard?).to be(true)
- end
- end
-
- context "address doesn't contain the wildcard placeholder" do
- before do
- stub_incoming_email_setting(address: 'replies@example.com')
- end
-
- it 'returns that wildcard is not supported' do
- expect(described_class.supports_wildcard?).to be(false)
- end
- end
-
- context 'address is not set' do
- before do
- stub_incoming_email_setting(address: nil)
- end
-
- it 'returns that wildcard is not supported' do
- expect(described_class.supports_wildcard?).to be(false)
- end
- end
- end
-
- context 'self.unsubscribe_address' do
+ describe 'self.key_from_address' do
before do
stub_incoming_email_setting(address: 'replies+%{key}@example.com')
end
- it 'returns the address with interpolated reply key and unsubscribe suffix' do
- expect(described_class.unsubscribe_address('key')).to eq("replies+key#{Gitlab::IncomingEmail::UNSUBSCRIBE_SUFFIX}@example.com")
- end
- end
-
- context "self.reply_address" do
- before do
- stub_incoming_email_setting(address: "replies+%{key}@example.com")
- end
-
- it "returns the address with an interpolated reply key" do
- expect(described_class.reply_address("key")).to eq("replies+key@example.com")
- end
- end
-
- context "self.key_from_address" do
- before do
- stub_incoming_email_setting(address: "replies+%{key}@example.com")
- end
-
it "returns reply key" do
expect(described_class.key_from_address("replies+key@example.com")).to eq("key")
end
@@ -101,25 +31,4 @@ RSpec.describe Gitlab::IncomingEmail do
end
end
end
-
- context 'self.key_from_fallback_message_id' do
- it 'returns reply key' do
- expect(described_class.key_from_fallback_message_id('reply-key@localhost')).to eq('key')
- end
- end
-
- context 'self.scan_fallback_references' do
- let(:references) do
- '<issue_1@localhost>' \
- ' <reply-59d8df8370b7e95c5a49fbf86aeb2c93@localhost>' \
- ',<exchange@microsoft.com>'
- end
-
- it 'returns reply key' do
- expect(described_class.scan_fallback_references(references))
- .to eq(%w[issue_1@localhost
- reply-59d8df8370b7e95c5a49fbf86aeb2c93@localhost
- exchange@microsoft.com])
- end
- end
end
diff --git a/spec/lib/gitlab/instrumentation/redis_cluster_validator_spec.rb b/spec/lib/gitlab/instrumentation/redis_cluster_validator_spec.rb
index e4af3f77d5d..58c75bff9dd 100644
--- a/spec/lib/gitlab/instrumentation/redis_cluster_validator_spec.rb
+++ b/spec/lib/gitlab/instrumentation/redis_cluster_validator_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe Gitlab::Instrumentation::RedisClusterValidator do
it do
stub_rails_env(env)
- args = [:mget, 'foo', 'bar']
+ args = [[:mget, 'foo', 'bar']]
if should_raise
expect { described_class.validate!(args) }
@@ -58,7 +58,7 @@ RSpec.describe Gitlab::Instrumentation::RedisClusterValidator do
with_them do
it do
- args = [command] + arguments
+ args = [[command] + arguments]
if should_raise
expect { described_class.validate!(args) }
@@ -68,13 +68,32 @@ RSpec.describe Gitlab::Instrumentation::RedisClusterValidator do
end
end
end
+
+ where(:arguments, :should_raise) do
+ [[:get, "foo"], [:get, "bar"]] | true
+ [[:get, "foo"], [:mget, "foo", "bar"]] | true # mix of single-key and multi-key cmds
+ [[:get, "{foo}:name"], [:get, "{foo}:profile"]] | false
+ [[:del, "foo"], [:del, "bar"]] | true
+ [] | false # pipeline or transaction opened and closed without ops
+ end
+
+ with_them do
+ it do
+ if should_raise
+ expect { described_class.validate!(arguments) }
+ .to raise_error(described_class::CrossSlotError)
+ else
+ expect { described_class.validate!(arguments) }.not_to raise_error
+ end
+ end
+ end
end
describe '.allow_cross_slot_commands' do
it 'does not raise for invalid arguments' do
expect do
described_class.allow_cross_slot_commands do
- described_class.validate!([:mget, 'foo', 'bar'])
+ described_class.validate!([[:mget, 'foo', 'bar']])
end
end.not_to raise_error
end
@@ -83,10 +102,10 @@ RSpec.describe Gitlab::Instrumentation::RedisClusterValidator do
expect do
described_class.allow_cross_slot_commands do
described_class.allow_cross_slot_commands do
- described_class.validate!([:mget, 'foo', 'bar'])
+ described_class.validate!([[:mget, 'foo', 'bar']])
end
- described_class.validate!([:mget, 'foo', 'bar'])
+ described_class.validate!([[:mget, 'foo', 'bar']])
end
end.not_to raise_error
end
diff --git a/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb b/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb
index 5b5516f100b..02c5dfb7521 100644
--- a/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb
+++ b/spec/lib/gitlab/instrumentation/redis_interceptor_spec.rb
@@ -57,8 +57,8 @@ RSpec.describe Gitlab::Instrumentation::RedisInterceptor, :clean_gitlab_redis_sh
Gitlab::Redis::SharedState.with do |redis|
redis.pipelined do |pipeline|
- pipeline.call(:get, 'foobar')
- pipeline.call(:get, 'foobarbaz')
+ pipeline.call(:get, '{foobar}buz')
+ pipeline.call(:get, '{foobar}baz')
end
end
end
@@ -103,11 +103,22 @@ RSpec.describe Gitlab::Instrumentation::RedisInterceptor, :clean_gitlab_redis_sh
Gitlab::Redis::SharedState.with do |redis|
redis.pipelined do |pipeline|
- pipeline.call(:get, 'foobar')
- pipeline.call(:get, 'foobarbaz')
+ pipeline.call(:get, '{foobar}:buz')
+ pipeline.call(:get, '{foobar}baz')
end
end
end
+
+ it 'raises error when keys are not from the same slot' do
+ expect do
+ Gitlab::Redis::SharedState.with do |redis|
+ redis.pipelined do |pipeline|
+ pipeline.call(:get, 'foo')
+ pipeline.call(:get, 'bar')
+ end
+ end
+ end.to raise_error(instance_of(Gitlab::Instrumentation::RedisClusterValidator::CrossSlotError))
+ end
end
end
diff --git a/spec/lib/gitlab/json_logger_spec.rb b/spec/lib/gitlab/json_logger_spec.rb
index 23f7191454a..801de357ddc 100644
--- a/spec/lib/gitlab/json_logger_spec.rb
+++ b/spec/lib/gitlab/json_logger_spec.rb
@@ -7,6 +7,26 @@ RSpec.describe Gitlab::JsonLogger do
let(:now) { Time.now }
+ describe '#file_name' do
+ let(:subclass) do
+ Class.new(Gitlab::JsonLogger) do
+ def self.file_name_noext
+ 'testlogger'
+ end
+ end
+ end
+
+ it 'raises error when file_name_noext not implemented' do
+ expect { described_class.file_name }.to raise_error(
+ 'JsonLogger implementations must provide file_name_noext implementation'
+ )
+ end
+
+ it 'returns log file name when file_name_noext is implemented' do
+ expect(subclass.file_name).to eq('testlogger.log')
+ end
+ end
+
describe '#format_message' do
before do
allow(Labkit::Correlation::CorrelationId).to receive(:current_id).and_return('new-correlation-id')
diff --git a/spec/lib/gitlab/json_spec.rb b/spec/lib/gitlab/json_spec.rb
index 73276288765..cbfab7e8884 100644
--- a/spec/lib/gitlab/json_spec.rb
+++ b/spec/lib/gitlab/json_spec.rb
@@ -2,6 +2,10 @@
require "spec_helper"
+# We can disable the cop that enforces the use of this class
+# as we need to test around it.
+#
+# rubocop: disable Gitlab/Json
RSpec.describe Gitlab::Json do
before do
stub_feature_flags(json_wrapper_legacy_mode: true)
@@ -429,4 +433,56 @@ RSpec.describe Gitlab::Json do
end
end
end
+
+ describe Gitlab::Json::RailsEncoder do
+ let(:obj) do
+ { foo: "<span>bar</span>" }
+ end
+
+ it "is used by ActiveSupport::JSON" do
+ expect_next_instance_of(described_class) do |encoder|
+ expect(encoder).to receive(:encode).with(obj)
+ end
+
+ ActiveSupport::JSON.encode(obj)
+ end
+
+ it "is used by .to_json calls" do
+ expect_next_instance_of(described_class) do |encoder|
+ expect(encoder).to receive(:encode).with(obj)
+ end
+
+ obj.to_json
+ end
+
+ it "is consistent with the original JSON implementation" do
+ default_encoder = ActiveSupport::JSON::Encoding::JSONGemEncoder
+
+ original_result = ActiveSupport::JSON::Encoding.use_encoder(default_encoder) do
+ ActiveSupport::JSON.encode(obj)
+ end
+
+ new_result = ActiveSupport::JSON::Encoding.use_encoder(described_class) do
+ ActiveSupport::JSON.encode(obj)
+ end
+
+ expect(new_result).to eq(original_result)
+ end
+
+ it "behaves the same when processing invalid unicode data" do
+ invalid_obj = { test: "Gr\x80\x81e" }
+ default_encoder = ActiveSupport::JSON::Encoding::JSONGemEncoder
+
+ original_result = ActiveSupport::JSON::Encoding.use_encoder(default_encoder) do
+ expect { ActiveSupport::JSON.encode(invalid_obj) }.to raise_error(JSON::GeneratorError)
+ end
+
+ new_result = ActiveSupport::JSON::Encoding.use_encoder(described_class) do
+ expect { ActiveSupport::JSON.encode(invalid_obj) }.to raise_error(JSON::GeneratorError)
+ end
+
+ expect(new_result).to eq(original_result)
+ end
+ end
end
+# rubocop: enable Gitlab/Json
diff --git a/spec/lib/gitlab/kas_spec.rb b/spec/lib/gitlab/kas_spec.rb
index 0fbb5f31210..34eb48a3221 100644
--- a/spec/lib/gitlab/kas_spec.rb
+++ b/spec/lib/gitlab/kas_spec.rb
@@ -125,6 +125,18 @@ RSpec.describe Gitlab::Kas do
end
end
+ describe '.version_info' do
+ let(:version) { '15.6.0-rc1' }
+
+ before do
+ allow(described_class).to receive(:version).and_return(version)
+ end
+
+ it 'returns gitlab_kas version config, including suffix' do
+ expect(described_class.version_info.to_s).to eq(version)
+ end
+ end
+
describe '.ensure_secret!' do
context 'secret file exists' do
before do
diff --git a/spec/lib/gitlab/kroki_spec.rb b/spec/lib/gitlab/kroki_spec.rb
index 7d29d018ff1..3d6ecf20377 100644
--- a/spec/lib/gitlab/kroki_spec.rb
+++ b/spec/lib/gitlab/kroki_spec.rb
@@ -6,7 +6,8 @@ RSpec.describe Gitlab::Kroki do
describe '.formats' do
def default_formats
- %w[bytefield c4plantuml ditaa erd graphviz nomnoml pikchr plantuml svgbob umlet vega vegalite wavedrom].freeze
+ %w[bytefield c4plantuml ditaa erd graphviz nomnoml pikchr plantuml
+ structurizr svgbob umlet vega vegalite wavedrom].freeze
end
subject { described_class.formats(Gitlab::CurrentSettings) }
diff --git a/spec/lib/gitlab/memory/watchdog/configuration_spec.rb b/spec/lib/gitlab/memory/watchdog/configuration_spec.rb
index 892a4b06ad0..38a39f6a33a 100644
--- a/spec/lib/gitlab/memory/watchdog/configuration_spec.rb
+++ b/spec/lib/gitlab/memory/watchdog/configuration_spec.rb
@@ -78,36 +78,53 @@ RSpec.describe Gitlab::Memory::Watchdog::Configuration do
end
end
- context 'when two monitors are configured to be used' do
- before do
- configuration.monitors.use monitor_class_1, false, { message: 'monitor_1_text' }, max_strikes: 5
- configuration.monitors.use monitor_class_2, true, { message: 'monitor_2_text' }, max_strikes: 0
+ context 'when two different monitor class are configured' do
+ shared_examples 'executes monitors and returns correct results' do
+ it 'calls each monitor and returns correct results', :aggregate_failures do
+ payloads = []
+ thresholds = []
+ strikes = []
+ monitor_names = []
+
+ configuration.monitors.call_each do |result|
+ payloads << result.payload
+ thresholds << result.threshold_violated?
+ strikes << result.strikes_exceeded?
+ monitor_names << result.monitor_name
+ end
+
+ expect(payloads).to eq([payload1, payload2])
+ expect(thresholds).to eq([false, true])
+ expect(strikes).to eq([false, true])
+ expect(monitor_names).to eq([:monitor1, :monitor2])
+ end
+ end
+
+ context 'when monitors are configured inline' do
+ before do
+ configuration.monitors.push monitor_class_1, false, { message: 'monitor_1_text' }, max_strikes: 5
+ configuration.monitors.push monitor_class_2, true, { message: 'monitor_2_text' }, max_strikes: 0
+ end
+
+ include_examples 'executes monitors and returns correct results'
end
- it 'calls each monitor and returns correct results', :aggregate_failures do
- payloads = []
- thresholds = []
- strikes = []
- monitor_names = []
-
- configuration.monitors.call_each do |result|
- payloads << result.payload
- thresholds << result.threshold_violated?
- strikes << result.strikes_exceeded?
- monitor_names << result.monitor_name
+ context 'when monitors are configured in a block' do
+ before do
+ configuration.monitors do |stack|
+ stack.push monitor_class_1, false, { message: 'monitor_1_text' }, max_strikes: 5
+ stack.push monitor_class_2, true, { message: 'monitor_2_text' }, max_strikes: 0
+ end
end
- expect(payloads).to eq([payload1, payload2])
- expect(thresholds).to eq([false, true])
- expect(strikes).to eq([false, true])
- expect(monitor_names).to eq([:monitor1, :monitor2])
+ include_examples 'executes monitors and returns correct results'
end
end
- context 'when same monitor class is configured to be used twice' do
+ context 'when same monitor class is configured twice' do
before do
- configuration.monitors.use monitor_class_1, max_strikes: 1
- configuration.monitors.use monitor_class_1, max_strikes: 1
+ configuration.monitors.push monitor_class_1, max_strikes: 1
+ configuration.monitors.push monitor_class_1, max_strikes: 1
end
it 'calls same monitor only once' do
diff --git a/spec/lib/gitlab/memory/watchdog/configurator_spec.rb b/spec/lib/gitlab/memory/watchdog/configurator_spec.rb
new file mode 100644
index 00000000000..e6f2d57e9e6
--- /dev/null
+++ b/spec/lib/gitlab/memory/watchdog/configurator_spec.rb
@@ -0,0 +1,199 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'prometheus/client'
+require 'sidekiq'
+require_dependency 'gitlab/cluster/lifecycle_events'
+
+RSpec.describe Gitlab::Memory::Watchdog::Configurator do
+ shared_examples 'as configurator' do |handler_class, sleep_time_env, sleep_time|
+ it 'configures the correct handler' do
+ configurator.call(configuration)
+
+ expect(configuration.handler).to be_an_instance_of(handler_class)
+ end
+
+ it 'configures the correct logger' do
+ configurator.call(configuration)
+
+ expect(configuration.logger).to eq(logger)
+ end
+
+ context 'when sleep_time_seconds is not passed through the environment' do
+ let(:sleep_time_seconds) { sleep_time }
+
+ it 'configures the correct sleep time' do
+ configurator.call(configuration)
+
+ expect(configuration.sleep_time_seconds).to eq(sleep_time_seconds)
+ end
+ end
+
+ context 'when sleep_time_seconds is passed through the environment' do
+ let(:sleep_time_seconds) { sleep_time - 1 }
+
+ before do
+ stub_env(sleep_time_env, sleep_time - 1)
+ end
+
+ it 'configures the correct sleep time' do
+ configurator.call(configuration)
+
+ expect(configuration.sleep_time_seconds).to eq(sleep_time_seconds)
+ end
+ end
+ end
+
+ shared_examples 'as monitor configurator' do
+ it 'executes monitors and returns correct results' do
+ configurator.call(configuration)
+
+ payloads = {}
+ configuration.monitors.call_each do |result|
+ payloads[result.monitor_name] = result.payload
+ end
+
+ expect(payloads).to eq(expected_payloads)
+ end
+ end
+
+ let(:configuration) { Gitlab::Memory::Watchdog::Configuration.new }
+
+ # In tests, the Puma constant does not exist so we cannot use a verified double.
+ # rubocop: disable RSpec/VerifiedDoubles
+ describe '.configure_for_puma' do
+ let(:logger) { Gitlab::AppLogger }
+ let(:puma) do
+ Class.new do
+ def self.cli_config
+ Struct.new(:options).new
+ end
+ end
+ end
+
+ subject(:configurator) { described_class.configure_for_puma }
+
+ def stub_prometheus_metrics
+ gauge = instance_double(::Prometheus::Client::Gauge)
+ allow(Gitlab::Metrics).to receive(:gauge).and_return(gauge)
+ allow(gauge).to receive(:set)
+ end
+
+ before do
+ stub_const('Puma', puma)
+ stub_const('Puma::Cluster::WorkerHandle', double.as_null_object)
+ stub_prometheus_metrics
+ end
+
+ it_behaves_like 'as configurator',
+ Gitlab::Memory::Watchdog::PumaHandler,
+ 'GITLAB_MEMWD_SLEEP_TIME_SEC',
+ 60
+
+ context 'with DISABLE_PUMA_WORKER_KILLER set to true' do
+ let(:primary_memory) { 2048 }
+ let(:worker_memory) { max_mem_growth * primary_memory + 1 }
+ let(:expected_payloads) do
+ {
+ heap_fragmentation: {
+ message: 'heap fragmentation limit exceeded',
+ memwd_cur_heap_frag: max_heap_fragmentation + 0.1,
+ memwd_max_heap_frag: max_heap_fragmentation,
+ memwd_max_strikes: max_strikes,
+ memwd_cur_strikes: 1
+
+ },
+ unique_memory_growth: {
+ message: 'memory limit exceeded',
+ memwd_uss_bytes: worker_memory,
+ memwd_ref_uss_bytes: primary_memory,
+ memwd_max_uss_bytes: max_mem_growth * primary_memory,
+ memwd_max_strikes: max_strikes,
+ memwd_cur_strikes: 1
+ }
+ }
+ end
+
+ before do
+ stub_env('DISABLE_PUMA_WORKER_KILLER', true)
+ allow(Gitlab::Metrics::Memory).to receive(:gc_heap_fragmentation).and_return(max_heap_fragmentation + 0.1)
+ allow(Gitlab::Metrics::System).to receive(:memory_usage_uss_pss).and_return({ uss: worker_memory })
+ allow(Gitlab::Metrics::System).to receive(:memory_usage_uss_pss).with(
+ pid: Gitlab::Cluster::PRIMARY_PID
+ ).and_return({ uss: primary_memory })
+ end
+
+ context 'when settings are set via environment variables' do
+ let(:max_heap_fragmentation) { 0.4 }
+ let(:max_mem_growth) { 4.0 }
+ let(:max_strikes) { 4 }
+
+ before do
+ stub_env('GITLAB_MEMWD_MAX_HEAP_FRAG', 0.4)
+ stub_env('GITLAB_MEMWD_MAX_MEM_GROWTH', 4.0)
+ stub_env('GITLAB_MEMWD_MAX_STRIKES', 4)
+ end
+
+ it_behaves_like 'as monitor configurator'
+ end
+
+ context 'when settings are not set via environment variables' do
+ let(:max_heap_fragmentation) { 0.5 }
+ let(:max_mem_growth) { 3.0 }
+ let(:max_strikes) { 5 }
+
+ it_behaves_like 'as monitor configurator'
+ end
+ end
+
+ context 'with DISABLE_PUMA_WORKER_KILLER set to false' do
+ let(:expected_payloads) do
+ {
+ rss_memory_limit: {
+ message: 'rss memory limit exceeded',
+ memwd_rss_bytes: memory_limit + 1,
+ memwd_max_rss_bytes: memory_limit,
+ memwd_max_strikes: max_strikes,
+ memwd_cur_strikes: 1
+ }
+ }
+ end
+
+ before do
+ stub_env('DISABLE_PUMA_WORKER_KILLER', false)
+ allow(Gitlab::Metrics::System).to receive(:memory_usage_rss).and_return({ total: memory_limit + 1 })
+ end
+
+ context 'when settings are set via environment variables' do
+ let(:memory_limit) { 1300 }
+ let(:max_strikes) { 4 }
+
+ before do
+ stub_env('PUMA_WORKER_MAX_MEMORY', 1300)
+ stub_env('GITLAB_MEMWD_MAX_STRIKES', 4)
+ end
+
+ it_behaves_like 'as monitor configurator'
+ end
+
+ context 'when settings are not set via environment variables' do
+ let(:memory_limit) { 1200 }
+ let(:max_strikes) { 5 }
+
+ it_behaves_like 'as monitor configurator'
+ end
+ end
+ end
+ # rubocop: enable RSpec/VerifiedDoubles
+
+ describe '.configure_for_sidekiq' do
+ let(:logger) { ::Sidekiq.logger }
+
+ subject(:configurator) { described_class.configure_for_sidekiq }
+
+ it_behaves_like 'as configurator',
+ Gitlab::Memory::Watchdog::TermProcessHandler,
+ 'SIDEKIQ_MEMORY_KILLER_CHECK_INTERVAL',
+ 3
+ 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
new file mode 100644
index 00000000000..9e25cfda782
--- /dev/null
+++ b/spec/lib/gitlab/memory/watchdog/monitor/rss_memory_limit_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'support/shared_examples/lib/gitlab/memory/watchdog/monitor_result_shared_examples'
+
+RSpec.describe Gitlab::Memory::Watchdog::Monitor::RssMemoryLimit do
+ let(:memory_limit) { 2048 }
+ let(:worker_memory) { 1024 }
+
+ subject(:monitor) do
+ described_class.new(memory_limit: memory_limit)
+ end
+
+ before do
+ allow(Gitlab::Metrics::System).to receive(:memory_usage_rss).and_return({ total: worker_memory })
+ end
+
+ describe '#call' do
+ context 'when process exceeds threshold' do
+ let(:worker_memory) { memory_limit + 1 }
+ let(:payload) do
+ {
+ message: 'rss memory limit exceeded',
+ memwd_rss_bytes: worker_memory,
+ memwd_max_rss_bytes: memory_limit
+ }
+ end
+
+ include_examples 'returns Watchdog Monitor result', threshold_violated: true
+ end
+
+ context 'when process does not exceed threshold' do
+ let(:worker_memory) { memory_limit - 1 }
+ let(:payload) { {} }
+
+ include_examples 'returns Watchdog Monitor result', threshold_violated: false
+ end
+ end
+end
diff --git a/spec/lib/gitlab/memory/watchdog_spec.rb b/spec/lib/gitlab/memory/watchdog_spec.rb
index 84e9a577afb..5d9599d6eab 100644
--- a/spec/lib/gitlab/memory/watchdog_spec.rb
+++ b/spec/lib/gitlab/memory/watchdog_spec.rb
@@ -60,14 +60,16 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do
describe '#call' do
before do
stub_prometheus_metrics
- allow(Gitlab::Metrics::System).to receive(:memory_usage_rss).at_least(:once).and_return(1024)
+ allow(Gitlab::Metrics::System).to receive(:memory_usage_rss).at_least(:once).and_return(
+ total: 1024
+ )
allow(::Prometheus::PidProvider).to receive(:worker_id).and_return('worker_1')
watchdog.configure do |config|
config.handler = handler
config.logger = logger
config.sleep_time_seconds = sleep_time_seconds
- config.monitors.use monitor_class, threshold_violated, payload, max_strikes: max_strikes
+ config.monitors.push monitor_class, threshold_violated, payload, max_strikes: max_strikes
end
allow(handler).to receive(:call).and_return(true)
@@ -203,8 +205,8 @@ RSpec.describe Gitlab::Memory::Watchdog, :aggregate_failures do
config.handler = handler
config.logger = logger
config.sleep_time_seconds = sleep_time_seconds
- config.monitors.use monitor_class, threshold_violated, payload, max_strikes: max_strikes
- config.monitors.use monitor_class, threshold_violated, payload, max_strikes: max_strikes
+ config.monitors.push monitor_class, threshold_violated, payload, max_strikes: max_strikes
+ config.monitors.push monitor_class, threshold_violated, payload, max_strikes: max_strikes
end
end
diff --git a/spec/lib/gitlab/merge_requests/mergeability/check_result_spec.rb b/spec/lib/gitlab/merge_requests/mergeability/check_result_spec.rb
index 50cfa6b64ea..4f437e57600 100644
--- a/spec/lib/gitlab/merge_requests/mergeability/check_result_spec.rb
+++ b/spec/lib/gitlab/merge_requests/mergeability/check_result_spec.rb
@@ -70,8 +70,8 @@ RSpec.describe Gitlab::MergeRequests::Mergeability::CheckResult do
let(:payload) { { test: 'test' } }
let(:hash) do
{
- 'status' => status,
- 'payload' => payload
+ status: status,
+ payload: payload
}
end
diff --git a/spec/lib/gitlab/merge_requests/mergeability/redis_interface_spec.rb b/spec/lib/gitlab/merge_requests/mergeability/redis_interface_spec.rb
index 2471faf76b2..787ac2874d3 100644
--- a/spec/lib/gitlab/merge_requests/mergeability/redis_interface_spec.rb
+++ b/spec/lib/gitlab/merge_requests/mergeability/redis_interface_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Gitlab::MergeRequests::Mergeability::RedisInterface, :clean_gitla
subject(:redis_interface) { described_class.new }
let(:merge_check) { double(cache_key: '13') }
- let(:result_hash) { { 'test' => 'test' } }
+ let(:result_hash) { { test: 'test' } }
let(:expected_key) { "#{merge_check.cache_key}:#{described_class::VERSION}" }
describe '#save_check' do
diff --git a/spec/lib/gitlab/merge_requests/mergeability/results_store_spec.rb b/spec/lib/gitlab/merge_requests/mergeability/results_store_spec.rb
index 0e8b598730c..e4211c6dfd7 100644
--- a/spec/lib/gitlab/merge_requests/mergeability/results_store_spec.rb
+++ b/spec/lib/gitlab/merge_requests/mergeability/results_store_spec.rb
@@ -10,15 +10,15 @@ RSpec.describe Gitlab::MergeRequests::Mergeability::ResultsStore do
let(:merge_request) { double }
describe '#read' do
- let(:result_hash) { { 'status' => 'success', 'payload' => {} } }
+ let(:result_hash) { { status: 'success', payload: {} } }
it 'calls #retrieve_check on the interface' do
expect(interface).to receive(:retrieve_check).with(merge_check: merge_check).and_return(result_hash)
cached_result = results_store.read(merge_check: merge_check)
- expect(cached_result.status).to eq(result_hash['status'].to_sym)
- expect(cached_result.payload).to eq(result_hash['payload'])
+ expect(cached_result.status).to eq(result_hash[:status].to_sym)
+ expect(cached_result.payload).to eq(result_hash[:payload])
end
context 'when #retrieve_check returns nil' do
diff --git a/spec/lib/gitlab/metrics/dashboard/finder_spec.rb b/spec/lib/gitlab/metrics/dashboard/finder_spec.rb
index 730a31346d7..f922eff2980 100644
--- a/spec/lib/gitlab/metrics/dashboard/finder_spec.rb
+++ b/spec/lib/gitlab/metrics/dashboard/finder_spec.rb
@@ -44,7 +44,7 @@ RSpec.describe Gitlab::Metrics::Dashboard::Finder, :use_clean_rails_memory_store
it_behaves_like 'valid dashboard service response'
end
- context 'when the self monitoring dashboard is specified' do
+ context 'when the self-monitoring dashboard is specified' do
let(:dashboard_path) { self_monitoring_dashboard_path }
it_behaves_like 'valid dashboard service response'
@@ -181,7 +181,7 @@ RSpec.describe Gitlab::Metrics::Dashboard::Finder, :use_clean_rails_memory_store
end
end
- context 'when the project is self monitoring' do
+ context 'when the project is self-monitoring' do
let(:self_monitoring_dashboard) do
{
path: self_monitoring_dashboard_path,
@@ -199,7 +199,7 @@ RSpec.describe Gitlab::Metrics::Dashboard::Finder, :use_clean_rails_memory_store
stub_application_setting(self_monitoring_project_id: project.id)
end
- it 'includes self monitoring and project dashboards' do
+ it 'includes self-monitoring and project dashboards' do
project_dashboard = {
path: dashboard_path,
display_name: 'test.yml',
diff --git a/spec/lib/gitlab/metrics/dashboard/service_selector_spec.rb b/spec/lib/gitlab/metrics/dashboard/service_selector_spec.rb
index f3c8209e0b6..b41b51f53c3 100644
--- a/spec/lib/gitlab/metrics/dashboard/service_selector_spec.rb
+++ b/spec/lib/gitlab/metrics/dashboard/service_selector_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe Gitlab::Metrics::Dashboard::ServiceSelector do
end
end
- context 'when the path is for the self monitoring dashboard' do
+ context 'when the path is for the self-monitoring dashboard' do
let(:arguments) { { dashboard_path: self_monitoring_dashboard_path } }
it { is_expected.to be Metrics::Dashboard::SelfMonitoringDashboardService }
diff --git a/spec/lib/gitlab/metrics/dashboard/url_spec.rb b/spec/lib/gitlab/metrics/dashboard/url_spec.rb
index 830d43169a9..d49200f87cc 100644
--- a/spec/lib/gitlab/metrics/dashboard/url_spec.rb
+++ b/spec/lib/gitlab/metrics/dashboard/url_spec.rb
@@ -61,7 +61,7 @@ RSpec.describe Gitlab::Metrics::Dashboard::Url do
'url' => url,
'namespace' => 'namespace1',
'project' => 'project1',
- 'environment' => "#{environment_id}",
+ 'environment' => environment_id.to_s,
'query' => "?dashboard=config%2Fprometheus%2Fcommon_metrics.yml&environment=#{environment_id}&group=awesome+group&start=2019-08-02T05%3A43%3A09.000Z",
'anchor' => '#title'
}
diff --git a/spec/lib/gitlab/metrics/global_search_slis_spec.rb b/spec/lib/gitlab/metrics/global_search_slis_spec.rb
index 0c09cf6dd71..c10d83664ea 100644
--- a/spec/lib/gitlab/metrics/global_search_slis_spec.rb
+++ b/spec/lib/gitlab/metrics/global_search_slis_spec.rb
@@ -47,10 +47,10 @@ RSpec.describe Gitlab::Metrics::GlobalSearchSlis do
describe '#record_apdex' do
where(:search_type, :code_search, :duration_target) do
- 'basic' | false | 7.031
- 'basic' | true | 21.903
- 'advanced' | false | 4.865
- 'advanced' | true | 13.546
+ 'basic' | false | 8.812
+ 'basic' | true | 27.538
+ 'advanced' | false | 2.452
+ 'advanced' | true | 15.52
end
with_them do
diff --git a/spec/lib/gitlab/metrics/loose_foreign_keys_slis_spec.rb b/spec/lib/gitlab/metrics/loose_foreign_keys_slis_spec.rb
new file mode 100644
index 00000000000..58740278425
--- /dev/null
+++ b/spec/lib/gitlab/metrics/loose_foreign_keys_slis_spec.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ::Gitlab::Metrics::LooseForeignKeysSlis do
+ # This needs to be dynamic because db_config_names depends on
+ # config/database.yml and the specs need to work for all configurations. That
+ # means this assertion is a copy of the implementation.
+ let(:possible_labels) do
+ ::Gitlab::Database.db_config_names.map do |db_config_name|
+ {
+ db_config_name: db_config_name,
+ feature_category: :database
+ }
+ end
+ end
+
+ describe '#initialize_slis!' do
+ it 'initializes Apdex and ErrorRate SLIs for loose_foreign_key_clean_ups' do
+ expect(::Gitlab::Metrics::Sli::Apdex).to receive(:initialize_sli).with(
+ :loose_foreign_key_clean_ups,
+ possible_labels
+ )
+
+ expect(::Gitlab::Metrics::Sli::ErrorRate).to receive(:initialize_sli).with(
+ :loose_foreign_key_clean_ups,
+ possible_labels
+ )
+
+ described_class.initialize_slis!
+ end
+ end
+
+ describe '#record_apdex' do
+ context 'with success: true' do
+ it 'increments the loose_foreign_key_clean_ups Apdex as a success' do
+ expect(Gitlab::Metrics::Sli::Apdex[:loose_foreign_key_clean_ups]).to receive(:increment).with(
+ labels: { feature_category: :database, db_config_name: 'main' },
+ success: true
+ )
+
+ described_class.record_apdex(success: true, db_config_name: 'main')
+ end
+ end
+
+ context 'with success: false' do
+ it 'increments the loose_foreign_key_clean_ups Apdex as not a success' do
+ expect(Gitlab::Metrics::Sli::Apdex[:loose_foreign_key_clean_ups]).to receive(:increment).with(
+ labels: { feature_category: :database, db_config_name: 'main' },
+ success: false
+ )
+
+ described_class.record_apdex(success: false, db_config_name: 'main')
+ end
+ end
+ end
+
+ describe '#record_error_rate' do
+ context 'with error: true' do
+ it 'increments the loose_foreign_key_clean_ups ErrorRate as an error' do
+ expect(Gitlab::Metrics::Sli::ErrorRate[:loose_foreign_key_clean_ups]).to receive(:increment).with(
+ labels: { feature_category: :database, db_config_name: 'main' },
+ error: true
+ )
+
+ described_class.record_error_rate(error: true, db_config_name: 'main')
+ end
+ end
+
+ context 'with error: false' do
+ it 'increments the loose_foreign_key_clean_ups ErrorRate as not an error' do
+ expect(Gitlab::Metrics::Sli::ErrorRate[:loose_foreign_key_clean_ups]).to receive(:increment).with(
+ labels: { feature_category: :database, db_config_name: 'main' },
+ error: false
+ )
+
+ described_class.record_error_rate(error: false, db_config_name: 'main')
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/metrics/method_call_spec.rb b/spec/lib/gitlab/metrics/method_call_spec.rb
index 6aa89c7cb05..091f35bfbcc 100644
--- a/spec/lib/gitlab/metrics/method_call_spec.rb
+++ b/spec/lib/gitlab/metrics/method_call_spec.rb
@@ -24,47 +24,22 @@ RSpec.describe Gitlab::Metrics::MethodCall do
allow(method_call).to receive(:above_threshold?).and_return(true)
end
- context 'prometheus instrumentation is enabled' do
- before do
- stub_feature_flags(prometheus_metrics_method_instrumentation: true)
- end
-
- around do |example|
- freeze_time do
- example.run
- end
- end
-
- it 'metric is not a NullMetric' do
- method_call.measure { 'foo' }
- expect(::Gitlab::Metrics::WebTransaction.prometheus_metric(:gitlab_method_call_duration_seconds, :histogram)).not_to be_instance_of(Gitlab::Metrics::NullMetric)
- end
-
- it 'observes the performance of the supplied block' do
- expect(transaction)
- .to receive(:observe).with(:gitlab_method_call_duration_seconds, be_a_kind_of(Numeric), { method: "#bar", module: :Foo })
-
- method_call.measure { 'foo' }
+ around do |example|
+ freeze_time do
+ example.run
end
end
- context 'prometheus instrumentation is disabled' do
- before do
- stub_feature_flags(prometheus_metrics_method_instrumentation: false)
- end
-
- it 'observes the performance of the supplied block' do
- expect(transaction)
- .to receive(:observe).with(:gitlab_method_call_duration_seconds, be_a_kind_of(Numeric), { method: "#bar", module: :Foo })
-
- method_call.measure { 'foo' }
- end
+ it 'metric is not a NullMetric' do
+ method_call.measure { 'foo' }
+ expect(::Gitlab::Metrics::WebTransaction.prometheus_metric(:gitlab_method_call_duration_seconds, :histogram)).not_to be_instance_of(Gitlab::Metrics::NullMetric)
+ end
- it 'observes using NullMetric' do
- method_call.measure { 'foo' }
+ it 'observes the performance of the supplied block' do
+ expect(transaction)
+ .to receive(:observe).with(:gitlab_method_call_duration_seconds, be_a_kind_of(Numeric), { method: "#bar", module: :Foo })
- expect(::Gitlab::Metrics::WebTransaction.prometheus_metric(:gitlab_method_call_duration_seconds, :histogram)).to be_instance_of(Gitlab::Metrics::NullMetric)
- end
+ method_call.measure { 'foo' }
end
end
diff --git a/spec/lib/gitlab/metrics/samplers/ruby_sampler_spec.rb b/spec/lib/gitlab/metrics/samplers/ruby_sampler_spec.rb
index b1566ffa7b4..8c46c881ef0 100644
--- a/spec/lib/gitlab/metrics/samplers/ruby_sampler_spec.rb
+++ b/spec/lib/gitlab/metrics/samplers/ruby_sampler_spec.rb
@@ -35,14 +35,30 @@ RSpec.describe Gitlab::Metrics::Samplers::RubySampler do
end
describe '#sample' do
- it 'adds a metric containing the process resident memory bytes' do
- expect(Gitlab::Metrics::System).to receive(:memory_usage_rss).and_return(9000)
+ it 'adds a metric containing the process total resident memory bytes' do
+ expect(Gitlab::Metrics::System).to receive(:memory_usage_rss).and_return({ total: 9000 })
expect(sampler.metrics[:process_resident_memory_bytes]).to receive(:set).with({}, 9000)
sampler.sample
end
+ it 'adds a metric containing the process anonymous resident memory bytes' do
+ expect(Gitlab::Metrics::System).to receive(:memory_usage_rss).and_return({ anon: 9000 })
+
+ expect(sampler.metrics[:process_resident_anon_memory_bytes]).to receive(:set).with({}, 9000)
+
+ sampler.sample
+ end
+
+ it 'adds a metric containing the process file backed resident memory bytes' do
+ expect(Gitlab::Metrics::System).to receive(:memory_usage_rss).and_return({ file: 9000 })
+
+ expect(sampler.metrics[:process_resident_file_memory_bytes]).to receive(:set).with({}, 9000)
+
+ sampler.sample
+ end
+
it 'adds a metric containing the process unique and proportional memory bytes' do
expect(Gitlab::Metrics::System).to receive(:memory_usage_uss_pss).and_return(uss: 9000, pss: 10_000)
diff --git a/spec/lib/gitlab/metrics/system_spec.rb b/spec/lib/gitlab/metrics/system_spec.rb
index b86469eacd1..e4f53ab3f49 100644
--- a/spec/lib/gitlab/metrics/system_spec.rb
+++ b/spec/lib/gitlab/metrics/system_spec.rb
@@ -20,6 +20,7 @@ RSpec.describe Gitlab::Metrics::System do
VmHWM: 2468 kB
VmRSS: 2468 kB
RssAnon: 260 kB
+ RssFile: 1024 kB
SNIP
end
@@ -132,18 +133,26 @@ RSpec.describe Gitlab::Metrics::System do
describe '.memory_usage_rss' do
context 'without PID' do
- it "returns the current process' resident set size (RSS) in bytes" do
+ it "returns a hash containing RSS metrics in bytes for current process" do
mock_existing_proc_file('/proc/self/status', proc_status)
- expect(described_class.memory_usage_rss).to eq(2527232)
+ expect(described_class.memory_usage_rss).to eq(
+ total: 2527232,
+ anon: 266240,
+ file: 1048576
+ )
end
end
context 'with PID' do
- it "returns the given process' resident set size (RSS) in bytes" do
+ it "returns a hash containing RSS metrics in bytes for given process" do
mock_existing_proc_file('/proc/7/status', proc_status)
- expect(described_class.memory_usage_rss(pid: 7)).to eq(2527232)
+ expect(described_class.memory_usage_rss(pid: 7)).to eq(
+ total: 2527232,
+ anon: 266240,
+ file: 1048576
+ )
end
end
end
@@ -241,8 +250,12 @@ RSpec.describe Gitlab::Metrics::System do
end
describe '.memory_usage_rss' do
- it 'returns 0' do
- expect(described_class.memory_usage_rss).to eq(0)
+ it 'returns 0 for all components' do
+ expect(described_class.memory_usage_rss).to eq(
+ total: 0,
+ anon: 0,
+ file: 0
+ )
end
end
diff --git a/spec/lib/gitlab/observability_spec.rb b/spec/lib/gitlab/observability_spec.rb
new file mode 100644
index 00000000000..2b1d22d9019
--- /dev/null
+++ b/spec/lib/gitlab/observability_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Observability do
+ describe '.observability_url' do
+ let(:gitlab_url) { 'https://example.com' }
+
+ subject { described_class.observability_url }
+
+ before do
+ stub_config_setting(url: gitlab_url)
+ end
+
+ it { is_expected.to eq('https://observe.gitlab.com') }
+
+ context 'when on staging.gitlab.com' do
+ let(:gitlab_url) { Gitlab::Saas.staging_com_url }
+
+ it { is_expected.to eq('https://observe.staging.gitlab.com') }
+ end
+
+ context 'when overriden via ENV' do
+ let(:observe_url) { 'https://example.net' }
+
+ before do
+ stub_env('OVERRIDE_OBSERVABILITY_URL', observe_url)
+ end
+
+ it { is_expected.to eq(observe_url) }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/octokit/middleware_spec.rb b/spec/lib/gitlab/octokit/middleware_spec.rb
index 92e424978ff..7bce0788327 100644
--- a/spec/lib/gitlab/octokit/middleware_spec.rb
+++ b/spec/lib/gitlab/octokit/middleware_spec.rb
@@ -66,5 +66,13 @@ RSpec.describe Gitlab::Octokit::Middleware do
it_behaves_like 'Public URL'
end
end
+
+ context 'when a non HTTP/HTTPS URL is provided' do
+ let(:env) { { url: 'ssh://172.16.0.0' } }
+
+ it 'raises an error' do
+ expect { middleware.call(env) }.to raise_error(Gitlab::UrlBlocker::BlockedUrlError)
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/pagination/gitaly_keyset_pager_spec.rb b/spec/lib/gitlab/pagination/gitaly_keyset_pager_spec.rb
index 0bafd436bd0..b5ed583b1f1 100644
--- a/spec/lib/gitlab/pagination/gitaly_keyset_pager_spec.rb
+++ b/spec/lib/gitlab/pagination/gitaly_keyset_pager_spec.rb
@@ -99,7 +99,7 @@ RSpec.describe Gitlab::Pagination::GitalyKeysetPager do
before do
allow(request_context).to receive(:request).and_return(fake_request)
- allow(finder).to receive(:is_a?).with(BranchesFinder) { true }
+ allow(BranchesFinder).to receive(:===).with(finder).and_return(true)
expect(finder).to receive(:execute).with(gitaly_pagination: true).and_return(branches)
end
diff --git a/spec/lib/gitlab/pagination_delegate_spec.rb b/spec/lib/gitlab/pagination_delegate_spec.rb
new file mode 100644
index 00000000000..7693decd881
--- /dev/null
+++ b/spec/lib/gitlab/pagination_delegate_spec.rb
@@ -0,0 +1,157 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::PaginationDelegate do
+ context 'when there is no data' do
+ let(:delegate) do
+ described_class.new(page: 1,
+ per_page: 10,
+ count: 0)
+ end
+
+ it 'shows the correct total count' do
+ expect(delegate.total_count).to eq(0)
+ end
+
+ it 'shows the correct total pages' do
+ expect(delegate.total_pages).to eq(0)
+ end
+
+ it 'shows the correct next page' do
+ expect(delegate.next_page).to be_nil
+ end
+
+ it 'shows the correct previous page' do
+ expect(delegate.prev_page).to be_nil
+ end
+
+ it 'shows the correct current page' do
+ expect(delegate.current_page).to eq(1)
+ end
+
+ it 'shows the correct limit value' do
+ expect(delegate.limit_value).to eq(10)
+ end
+
+ it 'shows the correct first page' do
+ expect(delegate.first_page?).to be true
+ end
+
+ it 'shows the correct last page' do
+ expect(delegate.last_page?).to be true
+ end
+
+ it 'shows the correct offset' do
+ expect(delegate.offset).to eq(0)
+ end
+ end
+
+ context 'with data' do
+ let(:delegate) do
+ described_class.new(page: 5,
+ per_page: 100,
+ count: 1000)
+ end
+
+ it 'shows the correct total count' do
+ expect(delegate.total_count).to eq(1000)
+ end
+
+ it 'shows the correct total pages' do
+ expect(delegate.total_pages).to eq(10)
+ end
+
+ it 'shows the correct next page' do
+ expect(delegate.next_page).to eq(6)
+ end
+
+ it 'shows the correct previous page' do
+ expect(delegate.prev_page).to eq(4)
+ end
+
+ it 'shows the correct current page' do
+ expect(delegate.current_page).to eq(5)
+ end
+
+ it 'shows the correct limit value' do
+ expect(delegate.limit_value).to eq(100)
+ end
+
+ it 'shows the correct first page' do
+ expect(delegate.first_page?).to be false
+ end
+
+ it 'shows the correct last page' do
+ expect(delegate.last_page?).to be false
+ end
+
+ it 'shows the correct offset' do
+ expect(delegate.offset).to eq(400)
+ end
+ end
+
+ context 'for last page' do
+ let(:delegate) do
+ described_class.new(page: 10,
+ per_page: 100,
+ count: 1000)
+ end
+
+ it 'shows the correct total count' do
+ expect(delegate.total_count).to eq(1000)
+ end
+
+ it 'shows the correct total pages' do
+ expect(delegate.total_pages).to eq(10)
+ end
+
+ it 'shows the correct next page' do
+ expect(delegate.next_page).to be_nil
+ end
+
+ it 'shows the correct previous page' do
+ expect(delegate.prev_page).to eq(9)
+ end
+
+ it 'shows the correct current page' do
+ expect(delegate.current_page).to eq(10)
+ end
+
+ it 'shows the correct limit value' do
+ expect(delegate.limit_value).to eq(100)
+ end
+
+ it 'shows the correct first page' do
+ expect(delegate.first_page?).to be false
+ end
+
+ it 'shows the correct last page' do
+ expect(delegate.last_page?).to be true
+ end
+
+ it 'shows the correct offset' do
+ expect(delegate.offset).to eq(900)
+ end
+ end
+
+ context 'with limits and defaults' do
+ it 'has a maximum limit per page' do
+ expect(described_class.new(page: nil,
+ per_page: 1000,
+ count: 0).limit_value).to eq(described_class::MAX_PER_PAGE)
+ end
+
+ it 'has a default per page' do
+ expect(described_class.new(page: nil,
+ per_page: nil,
+ count: 0).limit_value).to eq(described_class::DEFAULT_PER_PAGE)
+ end
+
+ it 'has a maximum page' do
+ expect(described_class.new(page: 100,
+ per_page: 10,
+ count: 1).current_page).to eq(1)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled_spec.rb b/spec/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled_spec.rb
index 05cdc5bb79b..d42cef8bcba 100644
--- a/spec/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled_spec.rb
+++ b/spec/lib/gitlab/performance_bar/redis_adapter_when_peek_enabled_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe Gitlab::PerformanceBar::RedisAdapterWhenPeekEnabled do
it 'stores request id and enqueues stats job' do
expect_to_obtain_exclusive_lease(GitlabPerformanceBarStatsWorker::LEASE_KEY, uuid)
expect(GitlabPerformanceBarStatsWorker).to receive(:perform_in).with(GitlabPerformanceBarStatsWorker::WORKER_DELAY, uuid)
- expect(client).to receive(:sadd).with(GitlabPerformanceBarStatsWorker::STATS_KEY, uuid)
+ expect(client).to receive(:sadd?).with(GitlabPerformanceBarStatsWorker::STATS_KEY, uuid)
expect(client).to receive(:expire).with(GitlabPerformanceBarStatsWorker::STATS_KEY, GitlabPerformanceBarStatsWorker::STATS_KEY_EXPIRE)
peek_adapter.new(client).save('foo')
@@ -56,7 +56,7 @@ RSpec.describe Gitlab::PerformanceBar::RedisAdapterWhenPeekEnabled do
it 'stores request id but does not enqueue any job' do
expect(GitlabPerformanceBarStatsWorker).not_to receive(:perform_in)
- expect(client).to receive(:sadd).with(GitlabPerformanceBarStatsWorker::STATS_KEY, uuid)
+ expect(client).to receive(:sadd?).with(GitlabPerformanceBarStatsWorker::STATS_KEY, uuid)
peek_adapter.new(client).save('foo')
end
diff --git a/spec/lib/gitlab/project_template_spec.rb b/spec/lib/gitlab/project_template_spec.rb
index 630369977ff..998fff12e94 100644
--- a/spec/lib/gitlab/project_template_spec.rb
+++ b/spec/lib/gitlab/project_template_spec.rb
@@ -12,6 +12,20 @@ RSpec.describe Gitlab::ProjectTemplate do
end
end
+ describe '#project_host' do
+ context "when `preview` is valid" do
+ subject { described_class.new('name', 'title', 'description', 'https://gitlab.com/some/project/path').project_host }
+
+ it { is_expected.to eq 'https://gitlab.com' }
+ end
+
+ context "when `preview` is `nil`" do
+ subject { described_class.new('name', 'title', 'description', nil).project_host }
+
+ it { is_expected.to eq nil }
+ end
+ end
+
describe '#project_path' do
subject { described_class.new('name', 'title', 'description', 'https://gitlab.com/some/project/path').project_path }
diff --git a/spec/lib/gitlab/qa_spec.rb b/spec/lib/gitlab/qa_spec.rb
new file mode 100644
index 00000000000..c26f4c89fec
--- /dev/null
+++ b/spec/lib/gitlab/qa_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Qa do
+ describe '.request?' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:dot_com, :request_user_agent, :qa_user_agent, :result) do
+ false | 'qa_user_agent' | 'qa_user_agent' | false
+ true | nil | 'qa_user_agent' | false
+ true | '' | 'qa_user_agent' | false
+ true | 'qa_user_agent' | '' | false
+ true | 'qa_user_agent' | nil | false
+ true | 'qa_user_agent' | 'qa_user_agent' | true
+ end
+
+ with_them do
+ before do
+ allow(Gitlab).to receive(:com?).and_return(dot_com)
+ stub_env('GITLAB_QA_USER_AGENT', qa_user_agent)
+ end
+
+ subject { described_class.request?(request_user_agent) }
+
+ it { is_expected.to eq(result) }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/query_limiting/transaction_spec.rb b/spec/lib/gitlab/query_limiting/transaction_spec.rb
index d8eb2040ccc..c11d0a7c18d 100644
--- a/spec/lib/gitlab/query_limiting/transaction_spec.rb
+++ b/spec/lib/gitlab/query_limiting/transaction_spec.rb
@@ -91,6 +91,9 @@ RSpec.describe Gitlab::QueryLimiting::Transaction do
SELECT a.attname, a.other_column
FROM pg_attribute a
SQL
+ transaction.increment(
+ "SELECT a.attnum, a.attname\nFROM pg_attribute a\nWHERE a.attrelid = 10605202\nAND a.attnum IN (3)\n"
+ )
end.not_to change(transaction, :count)
end
end
diff --git a/spec/lib/gitlab/redis/multi_store_spec.rb b/spec/lib/gitlab/redis/multi_store_spec.rb
index 8b73b5e03c0..207fe28e84e 100644
--- a/spec/lib/gitlab/redis/multi_store_spec.rb
+++ b/spec/lib/gitlab/redis/multi_store_spec.rb
@@ -127,19 +127,15 @@ RSpec.describe Gitlab::Redis::MultiStore do
end
before(:all) do
- primary_store.multi do |multi|
- multi.set(key1, value1)
- multi.set(key2, value2)
- multi.sadd(skey, value1)
- multi.sadd(skey, value2)
- end
+ primary_store.set(key1, value1)
+ primary_store.set(key2, value2)
+ primary_store.sadd?(skey, value1)
+ primary_store.sadd?(skey, value2)
- secondary_store.multi do |multi|
- multi.set(key1, value1)
- multi.set(key2, value2)
- multi.sadd(skey, value1)
- multi.sadd(skey, value2)
- end
+ secondary_store.set(key1, value1)
+ secondary_store.set(key2, value2)
+ secondary_store.sadd?(skey, value1)
+ secondary_store.sadd?(skey, value2)
end
RSpec.shared_examples_for 'reads correct value' do
@@ -211,126 +207,86 @@ RSpec.describe Gitlab::Redis::MultiStore do
end
with_them do
- describe "#{name}" do
+ describe name.to_s do
before do
allow(primary_store).to receive(name).and_call_original
allow(secondary_store).to receive(name).and_call_original
end
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: true)
- end
-
- context 'when reading from the primary is successful' do
- it 'returns the correct value' do
- expect(primary_store).to receive(name).with(*args).and_call_original
-
- subject
- end
-
- it 'does not execute on the secondary store' do
- expect(secondary_store).not_to receive(name)
+ context 'when reading from the primary is successful' do
+ it 'returns the correct value' do
+ expect(primary_store).to receive(name).with(*args).and_call_original
- subject
- end
-
- include_examples 'reads correct value'
+ subject
end
- context 'when reading from primary instance is raising an exception' do
- before do
- allow(primary_store).to receive(name).with(*args).and_raise(StandardError)
- allow(Gitlab::ErrorTracking).to receive(:log_exception)
- end
+ it 'does not execute on the secondary store' do
+ expect(secondary_store).not_to receive(name)
- it 'logs the exception' 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
+ end
- subject
- end
+ include_examples 'reads correct value'
+ end
- include_examples 'fallback read from the secondary store'
+ context 'when reading from primary instance is raising an exception' do
+ before do
+ allow(primary_store).to receive(name).with(*args).and_raise(StandardError)
+ allow(Gitlab::ErrorTracking).to receive(:log_exception)
end
- context 'when reading from primary instance return no value' do
- before do
- allow(primary_store).to receive(name).and_return(nil)
- end
+ it 'logs the exception' 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))
- include_examples 'fallback read from the secondary store'
+ subject
end
- context 'when the command is executed within pipelined block' do
- subject do
- multi_store.pipelined do |pipeline|
- pipeline.send(name, *args)
- end
- end
+ include_examples 'fallback read from the secondary store'
+ end
- it 'is executed only 1 time on primary and secondary instance' do
- expect(primary_store).to receive(:pipelined).and_call_original
- expect(secondary_store).to receive(:pipelined).and_call_original
+ context 'when reading from primary instance return no value' do
+ before do
+ allow(primary_store).to receive(name).and_return(nil)
+ end
- 2.times do
- expect_next_instance_of(Redis::PipelinedConnection) do |pipeline|
- expect(pipeline).to receive(name).with(*args).once.and_call_original
- end
- end
+ include_examples 'fallback read from the secondary store'
+ end
- subject
+ context 'when the command is executed within pipelined block' do
+ subject do
+ multi_store.pipelined do |pipeline|
+ pipeline.send(name, *args)
end
end
- if params[:block]
- subject do
- multi_store.send(name, *args, &block)
- end
-
- context 'when block is provided' do
- it 'yields to the block' do
- expect(primary_store).to receive(name).and_yield(value)
+ it 'is executed only 1 time on primary and secondary instance' do
+ expect(primary_store).to receive(:pipelined).and_call_original
+ expect(secondary_store).to receive(:pipelined).and_call_original
- subject
+ 2.times do
+ expect_next_instance_of(Redis::PipelinedConnection) do |pipeline|
+ expect(pipeline).to receive(name).with(*args).once.and_call_original
end
-
- include_examples 'reads correct value'
end
- end
- end
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: false)
+ subject
end
+ end
- context 'with feature flag :use_primary_store_as_default_for_test_store is disabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: false)
- end
-
- it_behaves_like 'secondary store'
+ if params[:block]
+ subject do
+ multi_store.send(name, *args, &block)
end
- context 'with feature flag :use_primary_store_as_default_for_test_store is enabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: true)
- end
-
- it 'execute on the primary instance' do
- expect(primary_store).to receive(name).with(*args).and_call_original
+ context 'when block is provided' do
+ it 'yields to the block' do
+ expect(primary_store).to receive(name).and_yield(value)
subject
end
include_examples 'reads correct value'
-
- it 'does not execute on the secondary store' do
- expect(secondary_store).not_to receive(name)
-
- subject
- end
end
end
@@ -372,8 +328,9 @@ RSpec.describe Gitlab::Redis::MultiStore do
let_it_be(:skey) { "redis:set:key" }
let_it_be(:svalues1) { [value2, value1] }
let_it_be(:svalues2) { [value1] }
- let_it_be(:skey_value1) { [skey, value1] }
- let_it_be(:skey_value2) { [skey, value2] }
+ let_it_be(:skey_value1) { [skey, [value1]] }
+ let_it_be(:skey_value2) { [skey, [value2]] }
+ let_it_be(:script) { %(redis.call("set", "#{key1}", "#{value1}")) }
where(:case_name, :name, :args, :expected_value, :verification_name, :verification_args) do
'execute :set command' | :set | ref(:key1_value1) | ref(:value1) | :get | ref(:key1)
@@ -383,25 +340,22 @@ RSpec.describe Gitlab::Redis::MultiStore do
'execute :srem command' | :srem | ref(:skey_value1) | [] | :smembers | ref(:skey)
'execute :del command' | :del | ref(:key2) | nil | :get | ref(:key2)
'execute :flushdb command' | :flushdb | nil | 0 | :dbsize | nil
+ 'execute :eval command' | :eval | ref(:script) | ref(:value1) | :get | ref(:key1)
end
before do
primary_store.flushdb
secondary_store.flushdb
- primary_store.multi do |multi|
- multi.set(key2, value1)
- multi.sadd(skey, value1)
- end
+ primary_store.set(key2, value1)
+ primary_store.sadd?(skey, value1)
- secondary_store.multi do |multi|
- multi.set(key2, value1)
- multi.sadd(skey, value1)
- end
+ secondary_store.set(key2, value1)
+ secondary_store.sadd?(skey, value1)
end
with_them do
- describe "#{name}" do
+ describe name.to_s do
let(:expected_args) { args || no_args }
before do
@@ -409,100 +363,58 @@ RSpec.describe Gitlab::Redis::MultiStore do
allow(secondary_store).to receive(name).and_call_original
end
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: true)
- end
-
- context 'when executing on primary instance is successful' do
- it 'executes on both primary and secondary redis store', :aggregate_errors 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
-
- subject
- end
-
- include_examples 'verify that store contains values', :primary_store
- include_examples 'verify that store contains values', :secondary_store
- end
-
- context 'when executing on the primary instance is raising an exception' do
- before do
- allow(primary_store).to receive(name).with(*expected_args).and_raise(StandardError)
- allow(Gitlab::ErrorTracking).to receive(:log_exception)
- end
-
- it 'logs the exception and execute on secondary instance', :aggregate_errors do
- expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
- hash_including(:multi_store_error_message, command_name: name, instance_name: instance_name))
- expect(secondary_store).to receive(name).with(*expected_args).and_call_original
-
- subject
- end
+ context 'when executing on primary instance is successful' do
+ it 'executes on both primary and secondary redis store', :aggregate_errors 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
- include_examples 'verify that store contains values', :secondary_store
+ subject
end
- context 'when the command is executed within pipelined block' do
- subject do
- multi_store.pipelined do |pipeline|
- pipeline.send(name, *args)
- end
- end
-
- it 'is executed only 1 time on each instance', :aggregate_errors do
- expect(primary_store).to receive(:pipelined).and_call_original
- expect_next_instance_of(Redis::PipelinedConnection) do |pipeline|
- expect(pipeline).to receive(name).with(*expected_args).once.and_call_original
- end
-
- expect(secondary_store).to receive(:pipelined).and_call_original
- expect_next_instance_of(Redis::PipelinedConnection) do |pipeline|
- expect(pipeline).to receive(name).with(*expected_args).once.and_call_original
- end
-
- subject
- end
-
- include_examples 'verify that store contains values', :primary_store
- include_examples 'verify that store contains values', :secondary_store
- end
+ include_examples 'verify that store contains values', :primary_store
+ include_examples 'verify that store contains values', :secondary_store
end
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store is disabled' do
+ context 'when executing on the primary instance is raising an exception' do
before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: false)
+ allow(primary_store).to receive(name).with(*expected_args).and_raise(StandardError)
+ allow(Gitlab::ErrorTracking).to receive(:log_exception)
end
- context 'with feature flag :use_primary_store_as_default_for_test_store is disabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: false)
- end
+ it 'logs the exception and execute on secondary instance', :aggregate_errors do
+ expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
+ hash_including(:multi_store_error_message, command_name: name, instance_name: instance_name))
+ expect(secondary_store).to receive(name).with(*expected_args).and_call_original
+
+ subject
+ end
- it 'executes only on the secondary redis store', :aggregate_errors do
- expect(secondary_store).to receive(name).with(*expected_args)
- expect(primary_store).not_to receive(name).with(*expected_args)
+ include_examples 'verify that store contains values', :secondary_store
+ end
- subject
+ context 'when the command is executed within pipelined block' do
+ subject do
+ multi_store.pipelined do |pipeline|
+ pipeline.send(name, *args)
end
-
- include_examples 'verify that store contains values', :secondary_store
end
- context 'with feature flag :use_primary_store_as_default_for_test_store is enabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: true)
+ it 'is executed only 1 time on each instance', :aggregate_errors do
+ expect(primary_store).to receive(:pipelined).and_call_original
+ expect_next_instance_of(Redis::PipelinedConnection) do |pipeline|
+ expect(pipeline).to receive(name).with(*expected_args).once.and_call_original
end
- it 'executes only on the primary_redis redis store', :aggregate_errors do
- expect(primary_store).to receive(name).with(*expected_args)
- expect(secondary_store).not_to receive(name).with(*expected_args)
-
- subject
+ expect(secondary_store).to receive(:pipelined).and_call_original
+ expect_next_instance_of(Redis::PipelinedConnection) do |pipeline|
+ expect(pipeline).to receive(name).with(*expected_args).once.and_call_original
end
- include_examples 'verify that store contains values', :primary_store
+ subject
end
+
+ include_examples 'verify that store contains values', :primary_store
+ include_examples 'verify that store contains values', :secondary_store
end
end
end
@@ -537,151 +449,109 @@ RSpec.describe Gitlab::Redis::MultiStore do
end
end
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: true)
- end
-
- context 'when executing on primary instance is successful' do
- it 'executes on both primary and secondary redis store', :aggregate_errors do
- expect(primary_store).to receive(name).and_call_original
- expect(secondary_store).to receive(name).and_call_original
-
- subject
- end
+ context 'when executing on primary instance is successful' do
+ it 'executes on both primary and secondary redis store', :aggregate_errors do
+ expect(primary_store).to receive(name).and_call_original
+ expect(secondary_store).to receive(name).and_call_original
- include_examples 'verify that store contains values', :primary_store
- include_examples 'verify that store contains values', :secondary_store
+ subject
end
- context 'when executing on the primary instance is raising an exception' do
- before do
- allow(primary_store).to receive(name).and_raise(StandardError)
- allow(Gitlab::ErrorTracking).to receive(:log_exception)
- end
-
- it 'logs the exception and execute on secondary instance', :aggregate_errors do
- expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
- hash_including(:multi_store_error_message, command_name: name))
- expect(secondary_store).to receive(name).and_call_original
-
- subject
- end
+ include_examples 'verify that store contains values', :primary_store
+ include_examples 'verify that store contains values', :secondary_store
+ end
- include_examples 'verify that store contains values', :secondary_store
+ context 'when executing on the primary instance is raising an exception' do
+ before do
+ allow(primary_store).to receive(name).and_raise(StandardError)
+ allow(Gitlab::ErrorTracking).to receive(:log_exception)
end
- describe 'return values from a pipelined command' do
- RSpec::Matchers.define :pipeline_diff_error_with_stacktrace do |message|
- match do |object|
- expect(object).to be_a(Gitlab::Redis::MultiStore::PipelinedDiffError)
- expect(object.backtrace).not_to be_nil
- expect(object.message).to eq(message)
- end
- end
+ it 'logs the exception and execute on secondary instance', :aggregate_errors do
+ expect(Gitlab::ErrorTracking).to receive(:log_exception).with(an_instance_of(StandardError),
+ hash_including(:multi_store_error_message, command_name: name))
+ expect(secondary_store).to receive(name).and_call_original
- subject do
- multi_store.send(name) do |redis|
- redis.get(key1)
- end
- end
-
- context 'when the value exists on both and are equal' do
- before do
- primary_store.set(key1, value1)
- secondary_store.set(key1, value1)
- end
+ subject
+ end
- it 'returns the value' do
- expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
+ include_examples 'verify that store contains values', :secondary_store
+ end
- expect(subject).to eq([value1])
- end
+ describe 'return values from a pipelined command' do
+ RSpec::Matchers.define :pipeline_diff_error_with_stacktrace do |message|
+ match do |object|
+ expect(object).to be_a(Gitlab::Redis::MultiStore::PipelinedDiffError)
+ expect(object.backtrace).not_to be_nil
+ expect(object.message).to eq(message)
end
+ end
- context 'when the value exists on both but differ' do
- before do
- primary_store.set(key1, value1)
- secondary_store.set(key1, value2)
- end
-
- it 'returns the value from the secondary store, logging an error' do
- expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
- pipeline_diff_error_with_stacktrace(
- 'Pipelined command executed on both stores successfully but results differ between them. ' \
- "Result from the primary: [#{value1.inspect}]. Result from the secondary: [#{value2.inspect}]."
- ),
- hash_including(command_name: name, instance_name: instance_name)
- ).and_call_original
- expect(counter).to receive(:increment).with(command: name, instance_name: instance_name)
-
- expect(subject).to eq([value2])
- end
+ subject do
+ multi_store.send(name) do |redis|
+ redis.get(key1)
end
+ end
- context 'when the value does not exist on the primary but it does on the secondary' do
- before do
- secondary_store.set(key1, value2)
- end
-
- it 'returns the value from the secondary store, logging an error' do
- expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
- pipeline_diff_error_with_stacktrace(
- 'Pipelined command executed on both stores successfully but results differ between them. ' \
- "Result from the primary: [nil]. Result from the secondary: [#{value2.inspect}]."
- ),
- hash_including(command_name: name, instance_name: instance_name)
- )
- expect(counter).to receive(:increment).with(command: name, instance_name: instance_name)
-
- expect(subject).to eq([value2])
- end
+ context 'when the value exists on both and are equal' do
+ before do
+ primary_store.set(key1, value1)
+ secondary_store.set(key1, value1)
end
- context 'when the value does not exist in either' do
- it 'returns nil without logging an error' do
- expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
- expect(counter).not_to receive(:increment)
+ it 'returns the value' do
+ expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
- expect(subject).to eq([nil])
- end
+ expect(subject).to eq([value1])
end
end
- end
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store is disabled' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: false)
- end
-
- context 'with feature flag :use_primary_store_as_default_for_test_store is disabled' do
+ context 'when the value exists on both but differ' do
before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: false)
+ primary_store.set(key1, value1)
+ secondary_store.set(key1, value2)
end
- it 'executes only on the secondary redis store', :aggregate_errors do
- expect(secondary_store).to receive(name)
- expect(primary_store).not_to receive(name)
-
- subject
+ it 'returns the value from the secondary store, logging an error' do
+ expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
+ pipeline_diff_error_with_stacktrace(
+ 'Pipelined command executed on both stores successfully but results differ between them. ' \
+ "Result from the primary: [#{value1.inspect}]. Result from the secondary: [#{value2.inspect}]."
+ ),
+ hash_including(command_name: name, instance_name: instance_name)
+ ).and_call_original
+ expect(counter).to receive(:increment).with(command: name, instance_name: instance_name)
+
+ expect(subject).to eq([value2])
end
-
- include_examples 'verify that store contains values', :secondary_store
end
- context 'with feature flag :use_primary_store_as_default_for_test_store is enabled' do
+ context 'when the value does not exist on the primary but it does on the secondary' do
before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: true)
+ secondary_store.set(key1, value2)
end
- it 'executes only on the primary_redis redis store', :aggregate_errors do
- expect(primary_store).to receive(name)
- expect(secondary_store).not_to receive(name)
-
- subject
+ it 'returns the value from the secondary store, logging an error' do
+ expect(Gitlab::ErrorTracking).to receive(:log_exception).with(
+ pipeline_diff_error_with_stacktrace(
+ 'Pipelined command executed on both stores successfully but results differ between them. ' \
+ "Result from the primary: [nil]. Result from the secondary: [#{value2.inspect}]."
+ ),
+ hash_including(command_name: name, instance_name: instance_name)
+ )
+ expect(counter).to receive(:increment).with(command: name, instance_name: instance_name)
+
+ expect(subject).to eq([value2])
end
+ end
- include_examples 'verify that store contains values', :primary_store
+ context 'when the value does not exist in either' do
+ it 'returns nil without logging an error' do
+ expect(Gitlab::ErrorTracking).not_to receive(:log_exception)
+ expect(counter).not_to receive(:increment)
+
+ expect(subject).to eq([nil])
+ end
end
end
end
@@ -825,40 +695,8 @@ RSpec.describe Gitlab::Redis::MultiStore do
describe '#to_s' do
subject { multi_store.to_s }
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store is enabled' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: true)
- end
-
- it 'returns same value as primary_store' do
- is_expected.to eq(primary_store.to_s)
- end
- end
-
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store is disabled' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: false)
- end
-
- context 'with feature flag :use_primary_store_as_default_for_test_store is enabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: true)
- end
-
- it 'returns same value as primary_store' do
- is_expected.to eq(primary_store.to_s)
- end
- end
-
- context 'with feature flag :use_primary_store_as_default_for_test_store is disabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: false)
- end
-
- it 'returns same value as primary_store' do
- is_expected.to eq(secondary_store.to_s)
- end
- end
+ it 'returns same value as primary_store' do
+ is_expected.to eq(primary_store.to_s)
end
end
@@ -869,24 +707,8 @@ RSpec.describe Gitlab::Redis::MultiStore do
end
describe '#use_primary_and_secondary_stores?' do
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store is enabled' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: true)
- end
-
- it 'multi store is disabled' do
- expect(multi_store.use_primary_and_secondary_stores?).to be true
- end
- end
-
- context 'with feature flag :use_primary_and_secondary_stores_for_test_store is disabled' do
- before do
- stub_feature_flags(use_primary_and_secondary_stores_for_test_store: false)
- end
-
- it 'multi store is disabled' do
- expect(multi_store.use_primary_and_secondary_stores?).to be false
- end
+ it 'multi store is enabled' do
+ expect(multi_store.use_primary_and_secondary_stores?).to be true
end
context 'with empty DB' do
@@ -911,24 +733,8 @@ RSpec.describe Gitlab::Redis::MultiStore do
end
describe '#use_primary_store_as_default?' do
- context 'with feature flag :use_primary_store_as_default_for_test_store is enabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: true)
- end
-
- it 'multi store is disabled' do
- expect(multi_store.use_primary_store_as_default?).to be true
- end
- end
-
- context 'with feature flag :use_primary_store_as_default_for_test_store is disabled' do
- before do
- stub_feature_flags(use_primary_store_as_default_for_test_store: false)
- end
-
- it 'multi store is disabled' do
- expect(multi_store.use_primary_store_as_default?).to be false
- end
+ it 'multi store is disabled' do
+ expect(multi_store.use_primary_store_as_default?).to be true
end
context 'with empty DB' do
diff --git a/spec/lib/gitlab/request_forgery_protection_spec.rb b/spec/lib/gitlab/request_forgery_protection_spec.rb
index a7b777cf4f2..10842173365 100644
--- a/spec/lib/gitlab/request_forgery_protection_spec.rb
+++ b/spec/lib/gitlab/request_forgery_protection_spec.rb
@@ -13,6 +13,12 @@ RSpec.describe Gitlab::RequestForgeryProtection, :allow_forgery_protection do
}
end
+ it 'logs to /dev/null' do
+ expect(ActiveSupport::Logger).to receive(:new).with(File::NULL)
+
+ described_class::Controller.new.logger
+ end
+
describe '.call' do
context 'when the request method is GET' do
before do
diff --git a/spec/lib/gitlab/runtime_spec.rb b/spec/lib/gitlab/runtime_spec.rb
index 86640efed5a..181a911c667 100644
--- a/spec/lib/gitlab/runtime_spec.rb
+++ b/spec/lib/gitlab/runtime_spec.rb
@@ -113,7 +113,7 @@ RSpec.describe Gitlab::Runtime do
before do
stub_const('::Sidekiq', sidekiq_type)
allow(sidekiq_type).to receive(:server?).and_return(true)
- allow(sidekiq_type).to receive(:options).and_return(concurrency: 2)
+ allow(sidekiq_type).to receive(:[]).with(:concurrency).and_return(2)
end
it_behaves_like "valid runtime", :sidekiq, 5
diff --git a/spec/lib/gitlab/service_desk_email_spec.rb b/spec/lib/gitlab/service_desk_email_spec.rb
index 6667b61c02b..69569c0f194 100644
--- a/spec/lib/gitlab/service_desk_email_spec.rb
+++ b/spec/lib/gitlab/service_desk_email_spec.rb
@@ -1,39 +1,11 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+require 'spec_helper'
RSpec.describe Gitlab::ServiceDeskEmail do
- describe '.enabled?' do
- context 'when service_desk_email is enabled and address is set' do
- before do
- stub_service_desk_email_setting(enabled: true, address: 'foo')
- end
+ let(:setting_name) { :service_desk_email }
- it 'returns true' do
- expect(described_class.enabled?).to be_truthy
- end
- end
-
- context 'when service_desk_email is disabled' do
- before do
- stub_service_desk_email_setting(enabled: false, address: 'foo')
- end
-
- it 'returns false' do
- expect(described_class.enabled?).to be_falsey
- end
- end
-
- context 'when service desk address is not set' do
- before do
- stub_service_desk_email_setting(enabled: true, address: nil)
- end
-
- it 'returns false' do
- expect(described_class.enabled?).to be_falsey
- end
- end
- end
+ it_behaves_like 'common email methods'
describe '.key_from_address' do
context 'when service desk address is set' do
@@ -78,10 +50,4 @@ RSpec.describe Gitlab::ServiceDeskEmail do
end
end
end
-
- context 'self.key_from_fallback_message_id' do
- it 'returns reply key' do
- expect(described_class.key_from_fallback_message_id('reply-key@localhost')).to eq('key')
- end
- end
end
diff --git a/spec/lib/gitlab/sidekiq_config_spec.rb b/spec/lib/gitlab/sidekiq_config_spec.rb
index c5b00afe672..5f72a3feba7 100644
--- a/spec/lib/gitlab/sidekiq_config_spec.rb
+++ b/spec/lib/gitlab/sidekiq_config_spec.rb
@@ -157,7 +157,7 @@ RSpec.describe Gitlab::SidekiqConfig do
allow(::Gitlab::SidekiqConfig::WorkerRouter)
.to receive(:global).and_return(::Gitlab::SidekiqConfig::WorkerRouter.new(test_routes))
- allow(Sidekiq).to receive(:options).and_return(queues: %w[default background_migration])
+ allow(Sidekiq).to receive(:[]).with(:queues).and_return(%w[default background_migration])
mappings = described_class.current_worker_queue_mappings
diff --git a/spec/lib/gitlab/sidekiq_daemon/memory_killer_spec.rb b/spec/lib/gitlab/sidekiq_daemon/memory_killer_spec.rb
index 62681b21756..8c9a1abba5a 100644
--- a/spec/lib/gitlab/sidekiq_daemon/memory_killer_spec.rb
+++ b/spec/lib/gitlab/sidekiq_daemon/memory_killer_spec.rb
@@ -126,7 +126,7 @@ RSpec.describe Gitlab::SidekiqDaemon::MemoryKiller do
stub_const("#{described_class}::CHECK_INTERVAL_SECONDS", check_interval_seconds)
stub_const("#{described_class}::GRACE_BALLOON_SECONDS", grace_balloon_seconds)
allow(Process).to receive(:getpgrp).and_return(pid)
- allow(Sidekiq).to receive(:options).and_return(timeout: 9)
+ allow(Sidekiq).to receive(:[]).with(:timeout).and_return(9)
end
it 'return true when everything is within limit', :aggregate_failures do
@@ -257,7 +257,7 @@ RSpec.describe Gitlab::SidekiqDaemon::MemoryKiller do
before do
stub_const("#{described_class}::SHUTDOWN_TIMEOUT_SECONDS", shutdown_timeout_seconds)
stub_feature_flags(sidekiq_memory_killer_read_only_mode: false)
- allow(Sidekiq).to receive(:options).and_return(timeout: 9)
+ allow(Sidekiq).to receive(:[]).with(:timeout).and_return(9)
allow(memory_killer).to receive(:get_rss_kb).and_return(100)
allow(memory_killer).to receive(:get_soft_limit_rss_kb).and_return(200)
allow(memory_killer).to receive(:get_hard_limit_rss_kb).and_return(300)
diff --git a/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/client_spec.rb b/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/client_spec.rb
index 4d12e4b3f6f..44c8df73463 100644
--- a/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/client_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/client_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::Client, :clean_gitlab_redis_queues do
+RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::Client, :clean_gitlab_redis_queues,
+:clean_gitlab_redis_shared_state do
shared_context 'deduplication worker class' do |strategy, including_scheduled|
let(:worker_class) do
Class.new do
diff --git a/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb b/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb
index d240bf51e67..b6748d49739 100644
--- a/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job_spec.rb
@@ -11,8 +11,8 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
let(:wal_locations) do
{
- main: '0/D525E3A8',
- ci: 'AB/12345'
+ 'main' => '0/D525E3A8',
+ 'ci' => 'AB/12345'
}
end
@@ -24,10 +24,6 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
"#{Gitlab::Redis::Queues::SIDEKIQ_NAMESPACE}:duplicate:#{queue}:#{hash}"
end
- let(:deduplicated_flag_key) do
- "#{idempotency_key}:deduplicate_flag"
- end
-
describe '#schedule' do
shared_examples 'scheduling with deduplication class' do |strategy_class|
it 'calls schedule on the strategy' do
@@ -81,29 +77,26 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
end
end
- shared_examples 'tracking duplicates in redis' do
+ shared_examples 'with Redis cookies' do
+ let(:cookie_key) { "#{idempotency_key}:cookie:v2" }
+ let(:cookie) { get_redis_msgpack(cookie_key) }
+
describe '#check!' do
context 'when there was no job in the queue yet' do
it { expect(duplicate_job.check!).to eq('123') }
shared_examples 'sets Redis keys with correct TTL' do
it "adds an idempotency key with correct ttl" do
- expect { duplicate_job.check! }
- .to change { read_idempotency_key_with_ttl(idempotency_key) }
- .from([nil, -2])
- .to(['123', be_within(1).of(expected_ttl)])
- end
+ expected_cookie = {
+ 'jid' => '123',
+ 'offsets' => {},
+ 'wal_locations' => {},
+ 'existing_wal_locations' => wal_locations
+ }
- context 'when wal locations is not empty' do
- it "adds an existing wal locations key with correct ttl" do
- expect { duplicate_job.check! }
- .to change { read_idempotency_key_with_ttl(existing_wal_location_key(idempotency_key, :main)) }
- .from([nil, -2])
- .to([wal_locations[:main], be_within(1).of(expected_ttl)])
- .and change { read_idempotency_key_with_ttl(existing_wal_location_key(idempotency_key, :ci)) }
- .from([nil, -2])
- .to([wal_locations[:ci], be_within(1).of(expected_ttl)])
- end
+ duplicate_job.check!
+ expect(cookie).to eq(expected_cookie)
+ expect(redis_ttl(cookie_key)).to be_within(1).of(expected_ttl)
end
end
@@ -130,32 +123,23 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
context 'when there was already a job with same arguments in the same queue' do
before do
- set_idempotency_key(idempotency_key, 'existing-key')
- wal_locations.each do |config_name, location|
- set_idempotency_key(existing_wal_location_key(idempotency_key, config_name), location)
- end
+ set_idempotency_key(cookie_key, existing_cookie.to_msgpack)
end
- it { expect(duplicate_job.check!).to eq('existing-key') }
+ let(:existing_cookie) { { 'jid' => 'existing-jid' } }
- it "does not change the existing key's TTL" do
- expect { duplicate_job.check! }
- .not_to change { read_idempotency_key_with_ttl(idempotency_key) }
- .from(['existing-key', -1])
- end
+ it { expect(duplicate_job.check!).to eq('existing-jid') }
- it "does not change the existing wal locations key's TTL" do
+ it "does not change the existing key's TTL" do
expect { duplicate_job.check! }
- .to not_change { read_idempotency_key_with_ttl(existing_wal_location_key(idempotency_key, :main)) }
- .from([wal_locations[:main], -1])
- .and not_change { read_idempotency_key_with_ttl(existing_wal_location_key(idempotency_key, :ci)) }
- .from([wal_locations[:ci], -1])
+ .not_to change { redis_ttl(cookie_key) }
+ .from(-1)
end
it 'sets the existing jid' do
duplicate_job.check!
- expect(duplicate_job.existing_jid).to eq('existing-key')
+ expect(duplicate_job.existing_jid).to eq('existing-jid')
end
end
end
@@ -166,115 +150,90 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
{ main: ::ActiveRecord::Base,
ci: ::ActiveRecord::Base })
- set_idempotency_key(existing_wal_location_key(idempotency_key, :main), existing_wal[:main])
- set_idempotency_key(existing_wal_location_key(idempotency_key, :ci), existing_wal[:ci])
+ with_redis { |r| r.set(cookie_key, initial_cookie.to_msgpack, ex: expected_ttl) }
# read existing_wal_locations
duplicate_job.check!
end
- context "when the key doesn't exists in redis" do
- let(:existing_wal) do
- {
- main: '0/D525E3A0',
- ci: 'AB/12340'
- }
- end
+ let(:initial_cookie) do
+ {
+ 'jid' => 'foobar',
+ 'existing_wal_locations' => { 'main' => '0/D525E3A0', 'ci' => 'AB/12340' },
+ 'offsets' => {},
+ 'wal_locations' => {}
+ }
+ end
- let(:new_wal_location_with_offset) do
- {
- # offset is relative to `existing_wal`
- main: ['0/D525E3A8', '8'],
- ci: ['AB/12345', '5']
- }
- end
+ let(:expected_ttl) { 123 }
+ let(:new_wal) do
+ {
+ # offset is relative to `existing_wal`
+ 'main' => { location: '0/D525E3A8', offset: '8' },
+ 'ci' => { location: 'AB/12345', offset: '5' }
+ }
+ end
- let(:wal_locations) { new_wal_location_with_offset.transform_values(&:first) }
+ let(:wal_locations) { new_wal.transform_values { |v| v[:location] } }
- it 'stores a wal location to redis with an offset relative to existing wal location' do
- expect { duplicate_job.update_latest_wal_location! }
- .to change { read_range_from_redis(wal_location_key(idempotency_key, :main)) }
- .from([])
- .to(new_wal_location_with_offset[:main])
- .and change { read_range_from_redis(wal_location_key(idempotency_key, :ci)) }
- .from([])
- .to(new_wal_location_with_offset[:ci])
- end
+ it 'stores a wal location to redis with an offset relative to existing wal location' do
+ duplicate_job.update_latest_wal_location!
+
+ expect(cookie['wal_locations']).to eq(wal_locations)
+ expect(cookie['offsets']).to eq(new_wal.transform_values { |v| v[:offset].to_i })
+ expect(redis_ttl(cookie_key)).to be_within(1).of(expected_ttl)
end
+ end
- context "when the key exists in redis" do
- before do
- rpush_to_redis_key(wal_location_key(idempotency_key, :main), *stored_wal_location_with_offset[:main])
- rpush_to_redis_key(wal_location_key(idempotency_key, :ci), *stored_wal_location_with_offset[:ci])
+ describe 'UPDATE_WAL_COOKIE_SCRIPT' do
+ subject do
+ with_redis do |redis|
+ redis.eval(described_class::UPDATE_WAL_COOKIE_SCRIPT, keys: [cookie_key], argv: argv)
end
+ end
- let(:wal_locations) { new_wal_location_with_offset.transform_values(&:first) }
+ let(:argv) { ['c1', 1, 'loc1', 'c2', 2, 'loc2', 'c3', 3, 'loc3'] }
- context "when the new offset is bigger then the existing one" do
- let(:existing_wal) do
- {
- main: '0/D525E3A0',
- ci: 'AB/12340'
- }
- end
+ it 'does not create the key' do
+ subject
- let(:stored_wal_location_with_offset) do
- {
- # offset is relative to `existing_wal`
- main: ['0/D525E3A3', '3'],
- ci: ['AB/12342', '2']
- }
- end
+ expect(with_redis { |r| r.get(cookie_key) }).to eq(nil)
+ end
- let(:new_wal_location_with_offset) do
- {
- # offset is relative to `existing_wal`
- main: ['0/D525E3A8', '8'],
- ci: ['AB/12345', '5']
- }
- end
+ context 'when the key exists' do
+ let(:existing_cookie) { { 'offsets' => {}, 'wal_locations' => {} } }
+ let(:expected_ttl) { 123 }
- it 'updates a wal location to redis with an offset' do
- expect { duplicate_job.update_latest_wal_location! }
- .to change { read_range_from_redis(wal_location_key(idempotency_key, :main)) }
- .from(stored_wal_location_with_offset[:main])
- .to(new_wal_location_with_offset[:main])
- .and change { read_range_from_redis(wal_location_key(idempotency_key, :ci)) }
- .from(stored_wal_location_with_offset[:ci])
- .to(new_wal_location_with_offset[:ci])
- end
+ before do
+ with_redis { |r| r.set(cookie_key, existing_cookie.to_msgpack, ex: expected_ttl) }
end
- context "when the old offset is not bigger then the existing one" do
- let(:existing_wal) do
- {
- main: '0/D525E3A0',
- ci: 'AB/12340'
- }
- end
+ it 'updates all connections' do
+ subject
- let(:stored_wal_location_with_offset) do
- {
- # offset is relative to `existing_wal`
- main: ['0/D525E3A8', '8'],
- ci: ['AB/12345', '5']
- }
- end
+ expect(cookie['wal_locations']).to eq({ 'c1' => 'loc1', 'c2' => 'loc2', 'c3' => 'loc3' })
+ expect(cookie['offsets']).to eq({ 'c1' => 1, 'c2' => 2, 'c3' => 3 })
+ end
+
+ it 'preserves the ttl' do
+ subject
- let(:new_wal_location_with_offset) do
+ expect(redis_ttl(cookie_key)).to be_within(1).of(expected_ttl)
+ end
+
+ context 'and low offsets' do
+ let(:existing_cookie) do
{
- # offset is relative to `existing_wal`
- main: ['0/D525E3A2', '2'],
- ci: ['AB/12342', '2']
+ 'offsets' => { 'c1' => 0, 'c2' => 2 },
+ 'wal_locations' => { 'c1' => 'loc1old', 'c2' => 'loc2old' }
}
end
- it "does not update a wal location to redis with an offset" do
- expect { duplicate_job.update_latest_wal_location! }
- .to not_change { read_range_from_redis(wal_location_key(idempotency_key, :main)) }
- .from(stored_wal_location_with_offset[:main])
- .and not_change { read_range_from_redis(wal_location_key(idempotency_key, :ci)) }
- .from(stored_wal_location_with_offset[:ci])
+ it 'updates only some connections' do
+ subject
+
+ expect(cookie['wal_locations']).to eq({ 'c1' => 'loc1', 'c2' => 'loc2old', 'c3' => 'loc3' })
+ expect(cookie['offsets']).to eq({ 'c1' => 1, 'c2' => 2, 'c3' => 3 })
end
end
end
@@ -283,11 +242,11 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
describe '#latest_wal_locations' do
context 'when job was deduplicated and wal locations were already persisted' do
before do
- rpush_to_redis_key(wal_location_key(idempotency_key, :main), wal_locations[:main], 1024)
- rpush_to_redis_key(wal_location_key(idempotency_key, :ci), wal_locations[:ci], 1024)
+ cookie = { 'wal_locations' => { 'main' => 'abc', 'ci' => 'def' } }.to_msgpack
+ set_idempotency_key(cookie_key, cookie)
end
- it { expect(duplicate_job.latest_wal_locations).to eq(wal_locations) }
+ it { expect(duplicate_job.latest_wal_locations).to eq({ 'main' => 'abc', 'ci' => 'def' }) }
end
context 'when job is not deduplication and wal locations were not persisted' do
@@ -302,60 +261,22 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
context 'when the key exists in redis' do
before do
- set_idempotency_key(idempotency_key, 'existing-jid')
- set_idempotency_key(deduplicated_flag_key, 1)
- wal_locations.each do |config_name, location|
- set_idempotency_key(existing_wal_location_key(idempotency_key, config_name), location)
- set_idempotency_key(wal_location_key(idempotency_key, config_name), location)
- end
+ set_idempotency_key(cookie_key, "garbage")
end
shared_examples 'deleting the duplicate job' do
shared_examples 'deleting keys from redis' do |key_name|
it "removes the #{key_name} from redis" do
expect { duplicate_job.delete! }
- .to change { read_idempotency_key_with_ttl(key) }
- .from([from_value, -1])
- .to([nil, -2])
+ .to change { with_redis { |r| r.get(key) } }
+ .from(from_value)
+ .to(nil)
end
end
- shared_examples 'does not delete key from redis' do |key_name|
- it "does not remove the #{key_name} from redis" do
- expect { duplicate_job.delete! }
- .to not_change { read_idempotency_key_with_ttl(key) }
- .from([from_value, -1])
- end
- end
-
- it_behaves_like 'deleting keys from redis', 'idempotent key' do
- let(:key) { idempotency_key }
- let(:from_value) { 'existing-jid' }
- end
-
- it_behaves_like 'deleting keys from redis', 'deduplication counter key' do
- let(:key) { deduplicated_flag_key }
- let(:from_value) { '1' }
- end
-
- it_behaves_like 'deleting keys from redis', 'existing wal location keys for main database' do
- let(:key) { existing_wal_location_key(idempotency_key, :main) }
- let(:from_value) { wal_locations[:main] }
- end
-
- it_behaves_like 'deleting keys from redis', 'existing wal location keys for ci database' do
- let(:key) { existing_wal_location_key(idempotency_key, :ci) }
- let(:from_value) { wal_locations[:ci] }
- end
-
- it_behaves_like 'deleting keys from redis', 'latest wal location keys for main database' do
- let(:key) { wal_location_key(idempotency_key, :main) }
- let(:from_value) { wal_locations[:main] }
- end
-
- it_behaves_like 'deleting keys from redis', 'latest wal location keys for ci database' do
- let(:key) { wal_location_key(idempotency_key, :ci) }
- let(:from_value) { wal_locations[:ci] }
+ it_behaves_like 'deleting keys from redis', 'cookie key' do
+ let(:key) { cookie_key }
+ let(:from_value) { "garbage" }
end
end
@@ -387,15 +308,14 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
describe '#set_deduplicated_flag!' do
context 'when the job is reschedulable' do
before do
+ duplicate_job.check! # ensure cookie exists
allow(duplicate_job).to receive(:reschedulable?) { true }
end
it 'sets the key in Redis' do
duplicate_job.set_deduplicated_flag!
- flag = with_redis { |redis| redis.get(deduplicated_flag_key) }
-
- expect(flag).to eq(described_class::DEDUPLICATED_FLAG_VALUE.to_s)
+ expect(cookie['deduplicated']).to eq('1')
end
it 'sets, gets and cleans up the deduplicated flag' do
@@ -415,11 +335,10 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
end
it 'does not set the key in Redis' do
+ duplicate_job.check!
duplicate_job.set_deduplicated_flag!
- flag = with_redis { |redis| redis.get(deduplicated_flag_key) }
-
- expect(flag).to be_nil
+ expect(cookie['deduplicated']).to eq(nil)
end
it 'does not set the deduplicated flag' do
@@ -445,43 +364,24 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
expect(duplicate_job.duplicate?).to be(false)
end
- it 'returns false if the existing jid is different from the job jid' do
- set_idempotency_key(idempotency_key, 'a different jid')
+ it 'returns true if the existing jid is different from the job jid' do
+ set_idempotency_key(cookie_key, { 'jid' => 'a different jid' }.to_msgpack)
duplicate_job.check!
expect(duplicate_job.duplicate?).to be(true)
end
end
- def existing_wal_location_key(idempotency_key, connection_name)
- "#{idempotency_key}:#{connection_name}:existing_wal_location"
- end
-
- def wal_location_key(idempotency_key, connection_name)
- "#{idempotency_key}:#{connection_name}:wal_location"
- end
-
- def set_idempotency_key(key, value = '1')
+ def set_idempotency_key(key, value)
with_redis { |r| r.set(key, value) }
end
- def rpush_to_redis_key(key, wal, offset)
- with_redis { |r| r.rpush(key, [wal, offset]) }
- end
-
- def read_idempotency_key_with_ttl(key)
- with_redis do |redis|
- redis.pipelined do |p|
- p.get(key)
- p.ttl(key)
- end
- end
+ def get_redis_msgpack(key)
+ MessagePack.unpack(with_redis { |redis| redis.get(key) })
end
- def read_range_from_redis(key)
- with_redis do |redis|
- redis.lrange(key, 0, -1)
- end
+ def redis_ttl(key)
+ with_redis { |redis| redis.ttl(key) }
end
end
@@ -497,7 +397,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
duplicate_job.check!
end
- it_behaves_like 'tracking duplicates in redis'
+ it_behaves_like 'with Redis cookies'
end
context 'when both multi-store feature flags are off' do
@@ -517,7 +417,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
duplicate_job.check!
end
- it_behaves_like 'tracking duplicates in redis'
+ it_behaves_like 'with Redis cookies'
end
describe '#scheduled?' do
@@ -562,6 +462,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
context 'with deduplicated flag' do
before do
+ duplicate_job.check! # ensure cookie exists
duplicate_job.set_deduplicated_flag!
end
@@ -578,6 +479,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gi
context 'with deduplicated flag' do
before do
+ duplicate_job.check! # ensure cookie exists
duplicate_job.set_deduplicated_flag!
end
diff --git a/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb b/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb
index 54a1723afbc..1a53a9b8701 100644
--- a/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/server_metrics_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
describe '.initialize_process_metrics' do
it 'sets concurrency metrics' do
- expect(concurrency_metric).to receive(:set).with({}, Sidekiq.options[:concurrency].to_i)
+ expect(concurrency_metric).to receive(:set).with({}, Sidekiq[:concurrency].to_i)
described_class.initialize_process_metrics
end
@@ -65,7 +65,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::ServerMetrics do
end
it 'sets the concurrency metric' do
- expect(concurrency_metric).to receive(:set).with({}, Sidekiq.options[:concurrency].to_i)
+ expect(concurrency_metric).to receive(:set).with({}, Sidekiq[:concurrency].to_i)
described_class.initialize_process_metrics
end
diff --git a/spec/lib/gitlab/sidekiq_middleware_spec.rb b/spec/lib/gitlab/sidekiq_middleware_spec.rb
index 14dbeac37e8..af9075f5aa0 100644
--- a/spec/lib/gitlab/sidekiq_middleware_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware_spec.rb
@@ -6,7 +6,7 @@ require 'sidekiq/testing'
RSpec.describe Gitlab::SidekiqMiddleware do
let(:job_args) { [0.01] }
let(:disabled_sidekiq_middlewares) { [] }
- let(:chain) { Sidekiq::Middleware::Chain.new }
+ let(:chain) { Sidekiq::Middleware::Chain.new(Sidekiq) }
let(:queue) { 'test' }
let(:enabled_sidekiq_middlewares) { all_sidekiq_middlewares - disabled_sidekiq_middlewares }
let(:worker_class) do
diff --git a/spec/lib/gitlab/sidekiq_migrate_jobs_spec.rb b/spec/lib/gitlab/sidekiq_migrate_jobs_spec.rb
index d4391d3023a..9ed2a0642fc 100644
--- a/spec/lib/gitlab/sidekiq_migrate_jobs_spec.rb
+++ b/spec/lib/gitlab/sidekiq_migrate_jobs_spec.rb
@@ -16,34 +16,42 @@ RSpec.describe Gitlab::SidekiqMigrateJobs, :clean_gitlab_redis_queues do
clear_queues
end
- describe '#execute', :aggregate_failures do
+ describe '#migrate_set', :aggregate_failures do
shared_examples 'processing a set' do
- let(:migrator) { described_class.new(set_name) }
+ let(:migrator) { described_class.new(mappings) }
let(:set_after) do
Sidekiq.redis { |c| c.zrange(set_name, 0, -1, with_scores: true) }
- .map { |item, score| [Sidekiq.load_json(item), score] }
+ .map { |item, score| [Gitlab::Json.load(item), score] }
end
context 'when the set is empty' do
+ let(:mappings) { { 'AuthorizedProjectsWorker' => 'new_queue' } }
+
it 'returns the number of scanned and migrated jobs' do
- expect(migrator.execute('AuthorizedProjectsWorker' => 'new_queue')).to eq(scanned: 0, migrated: 0)
+ expect(migrator.migrate_set(set_name)).to eq(
+ scanned: 0,
+ migrated: 0)
end
end
context 'when the set is not empty' do
+ let(:mappings) { {} }
+
it 'returns the number of scanned and migrated jobs' do
create_jobs
- expect(migrator.execute({})).to eq(scanned: 4, migrated: 0)
+ expect(migrator.migrate_set(set_name)).to eq(scanned: 4, migrated: 0)
end
end
context 'when there are no matching jobs' do
+ let(:mappings) { { 'PostReceive' => 'new_queue' } }
+
it 'does not change any queue names' do
create_jobs(include_post_receive: false)
- expect(migrator.execute('PostReceive' => 'new_queue')).to eq(scanned: 3, migrated: 0)
+ expect(migrator.migrate_set(set_name)).to eq(scanned: 3, migrated: 0)
expect(set_after.length).to eq(3)
expect(set_after.map(&:first)).to all(include('queue' => 'authorized_projects',
@@ -53,10 +61,13 @@ RSpec.describe Gitlab::SidekiqMigrateJobs, :clean_gitlab_redis_queues do
context 'when there are matching jobs' do
it 'migrates only the workers matching the given worker from the set' do
+ migrator = described_class.new({ 'AuthorizedProjectsWorker' => 'new_queue' })
freeze_time do
create_jobs
- expect(migrator.execute('AuthorizedProjectsWorker' => 'new_queue')).to eq(scanned: 4, migrated: 3)
+ expect(migrator.migrate_set(set_name)).to eq(
+ scanned: 4,
+ migrated: 3)
set_after.each.with_index do |(item, score), i|
if item['class'] == 'AuthorizedProjectsWorker'
@@ -71,11 +82,14 @@ RSpec.describe Gitlab::SidekiqMigrateJobs, :clean_gitlab_redis_queues do
end
it 'allows migrating multiple workers at once' do
+ migrator = described_class.new({
+ 'AuthorizedProjectsWorker' => 'new_queue',
+ 'PostReceive' => 'another_queue'
+ })
freeze_time do
create_jobs
- expect(migrator.execute('AuthorizedProjectsWorker' => 'new_queue', 'PostReceive' => 'another_queue'))
- .to eq(scanned: 4, migrated: 4)
+ expect(migrator.migrate_set(set_name)).to eq(scanned: 4, migrated: 4)
set_after.each.with_index do |(item, score), i|
if item['class'] == 'AuthorizedProjectsWorker'
@@ -90,11 +104,14 @@ RSpec.describe Gitlab::SidekiqMigrateJobs, :clean_gitlab_redis_queues do
end
it 'allows migrating multiple workers to the same queue' do
+ migrator = described_class.new({
+ 'AuthorizedProjectsWorker' => 'new_queue',
+ 'PostReceive' => 'new_queue'
+ })
freeze_time do
create_jobs
- expect(migrator.execute('AuthorizedProjectsWorker' => 'new_queue', 'PostReceive' => 'new_queue'))
- .to eq(scanned: 4, migrated: 4)
+ expect(migrator.migrate_set(set_name)).to eq(scanned: 4, migrated: 4)
set_after.each.with_index do |(item, score), i|
expect(item).to include('queue' => 'new_queue', 'args' => [i])
@@ -104,16 +121,17 @@ RSpec.describe Gitlab::SidekiqMigrateJobs, :clean_gitlab_redis_queues do
end
it 'does not try to migrate jobs that are removed from the set during the migration' do
+ migrator = described_class.new({ 'PostReceive' => 'new_queue' })
freeze_time do
create_jobs
- allow(migrator).to receive(:migrate_job).and_wrap_original do |meth, *args|
- Sidekiq.redis { |c| c.zrem(set_name, args.first) }
+ allow(migrator).to receive(:migrate_job_in_set).and_wrap_original do |meth, *args|
+ Sidekiq.redis { |c| c.zrem(set_name, args.second) }
meth.call(*args)
end
- expect(migrator.execute('PostReceive' => 'new_queue')).to eq(scanned: 4, migrated: 0)
+ expect(migrator.migrate_set(set_name)).to eq(scanned: 4, migrated: 0)
expect(set_after.length).to eq(3)
expect(set_after.map(&:first)).to all(include('queue' => 'authorized_projects'))
@@ -121,11 +139,12 @@ RSpec.describe Gitlab::SidekiqMigrateJobs, :clean_gitlab_redis_queues do
end
it 'does not try to migrate unmatched jobs that are added to the set during the migration' do
+ migrator = described_class.new({ 'PostReceive' => 'new_queue' })
create_jobs
calls = 0
- allow(migrator).to receive(:migrate_job).and_wrap_original do |meth, *args|
+ allow(migrator).to receive(:migrate_job_in_set).and_wrap_original do |meth, *args|
if calls == 0
travel_to(5.hours.from_now) { create_jobs(include_post_receive: false) }
end
@@ -135,18 +154,19 @@ RSpec.describe Gitlab::SidekiqMigrateJobs, :clean_gitlab_redis_queues do
meth.call(*args)
end
- expect(migrator.execute('PostReceive' => 'new_queue')).to eq(scanned: 4, migrated: 1)
+ expect(migrator.migrate_set(set_name)).to eq(scanned: 4, migrated: 1)
expect(set_after.group_by { |job| job.first['queue'] }.transform_values(&:count))
.to eq('authorized_projects' => 6, 'new_queue' => 1)
end
it 'iterates through the entire set of jobs' do
+ migrator = described_class.new({ 'NonExistentWorker' => 'new_queue' })
50.times do |i|
travel_to(i.hours.from_now) { create_jobs }
end
- expect(migrator.execute('NonExistentWorker' => 'new_queue')).to eq(scanned: 200, migrated: 0)
+ expect(migrator.migrate_set(set_name)).to eq(scanned: 200, migrated: 0)
expect(set_after.length).to eq(200)
end
@@ -158,14 +178,16 @@ RSpec.describe Gitlab::SidekiqMigrateJobs, :clean_gitlab_redis_queues do
stub_const("#{described_class}::LOG_FREQUENCY", 2)
logger = Logger.new(StringIO.new)
- migrator = described_class.new(set_name, logger: logger)
+ migrator = described_class.new({
+ 'AuthorizedProjectsWorker' => 'new_queue',
+ 'PostReceive' => 'another_queue'
+ }, logger: logger)
expect(logger).to receive(:info).with(a_string_matching('Processing')).once.ordered
expect(logger).to receive(:info).with(a_string_matching('In progress')).once.ordered
expect(logger).to receive(:info).with(a_string_matching('Done')).once.ordered
- expect(migrator.execute('AuthorizedProjectsWorker' => 'new_queue', 'PostReceive' => 'new_queue'))
- .to eq(scanned: 4, migrated: 4)
+ expect(migrator.migrate_set(set_name)).to eq(scanned: 4, migrated: 4)
end
end
end
@@ -186,25 +208,6 @@ RSpec.describe Gitlab::SidekiqMigrateJobs, :clean_gitlab_redis_queues do
end
context 'retried jobs' do
- let(:set_name) { 'retry' }
- # Account for Sidekiq retry jitter
- # https://github.com/mperham/sidekiq/blob/3575ccb44c688dd08bfbfd937696260b12c622fb/lib/sidekiq/job_retry.rb#L217
- let(:schedule_jitter) { 10 }
-
- # Try to mimic as closely as possible what Sidekiq will actually
- # do to retry a job.
- def retry_in(klass, time, args)
- message = { 'class' => klass.name, 'args' => [args], 'retry' => true }.to_json
-
- allow(klass).to receive(:sidekiq_retry_in_block).and_return(proc { time })
-
- begin
- Sidekiq::JobRetry.new.local(klass, message, klass.queue) { raise 'boom' }
- rescue Sidekiq::JobRetry::Skip
- # Sidekiq scheduled the retry
- end
- end
-
def create_jobs(include_post_receive: true)
retry_in(AuthorizedProjectsWorker, 1.hour, 0)
retry_in(AuthorizedProjectsWorker, 2.hours, 1)
@@ -212,7 +215,248 @@ RSpec.describe Gitlab::SidekiqMigrateJobs, :clean_gitlab_redis_queues do
retry_in(AuthorizedProjectsWorker, 4.hours, 3)
end
+ include_context 'when handling retried jobs'
it_behaves_like 'processing a set'
end
end
+
+ describe '#migrate_queues', :aggregate_failures do
+ let(:migrator) { described_class.new(mappings, logger: logger) }
+ let(:logger) { nil }
+
+ def list_queues
+ queues = Sidekiq.redis do |conn|
+ conn.scan_each(match: "queue:*").to_a
+ end
+ queues.uniq.map { |queue| queue.split(':', 2).last }
+ end
+
+ def list_jobs(queue_name)
+ Sidekiq.redis { |conn| conn.lrange("queue:#{queue_name}", 0, -1) }
+ .map { |item| Gitlab::Json.load(item) }
+ end
+
+ def pre_migrate_checks; end
+
+ before do
+ queue_name_from_worker_name = Gitlab::SidekiqConfig::WorkerRouter.method(:queue_name_from_worker_name)
+ EmailReceiverWorker.sidekiq_options(queue: queue_name_from_worker_name.call(EmailReceiverWorker))
+ EmailReceiverWorker.perform_async('foo')
+ EmailReceiverWorker.perform_async('bar')
+
+ # test worker that has ':' inside the queue name
+ AuthorizedProjectUpdate::ProjectRecalculateWorker.sidekiq_options(
+ queue: queue_name_from_worker_name.call(AuthorizedProjectUpdate::ProjectRecalculateWorker)
+ )
+ AuthorizedProjectUpdate::ProjectRecalculateWorker.perform_async
+ end
+
+ after do
+ # resets the queue name to its original
+ EmailReceiverWorker.set_queue
+ AuthorizedProjectUpdate::ProjectRecalculateWorker.set_queue
+ end
+
+ shared_examples 'migrating queues' do
+ it 'migrates the jobs to the correct destination queue' do
+ queues = list_queues
+ expect(queues).to include(*queues_included_pre_migrate)
+ expect(queues).not_to include(*queues_excluded_pre_migrate)
+ pre_migrate_checks
+
+ migrator.migrate_queues
+
+ queues = list_queues
+ expect(queues).not_to include(*queues_excluded_post_migrate)
+ expect(queues).to include(*queues_included_post_migrate)
+ post_migrate_checks
+ end
+ end
+
+ context 'with all workers mapped to default queue' do
+ let(:mappings) do
+ { 'EmailReceiverWorker' => 'default', 'AuthorizedProjectUpdate::ProjectRecalculateWorker' => 'default' }
+ end
+
+ let(:queues_included_pre_migrate) do
+ ['email_receiver',
+ 'authorized_project_update:authorized_project_update_project_recalculate']
+ end
+
+ let(:queues_excluded_pre_migrate) { ['default'] }
+ let(:queues_excluded_post_migrate) do
+ ['email_receiver',
+ 'authorized_project_update:authorized_project_update_project_recalculate']
+ end
+
+ let(:queues_included_post_migrate) { ['default'] }
+
+ def post_migrate_checks
+ jobs = list_jobs('default')
+ expect(jobs.length).to eq(3)
+ sorted = jobs.sort_by { |job| [job["class"], job["args"]] }
+ expect(sorted[0]).to include('class' => 'AuthorizedProjectUpdate::ProjectRecalculateWorker',
+ 'queue' => 'default')
+ expect(sorted[1]).to include('class' => 'EmailReceiverWorker', 'args' => ['bar'], 'queue' => 'default')
+ expect(sorted[2]).to include('class' => 'EmailReceiverWorker', 'args' => ['foo'], 'queue' => 'default')
+ end
+
+ it_behaves_like 'migrating queues'
+ end
+
+ context 'with custom mapping to different queues' do
+ let(:mappings) do
+ { 'EmailReceiverWorker' => 'new_email',
+ 'AuthorizedProjectUpdate::ProjectRecalculateWorker' => 'new_authorized' }
+ end
+
+ let(:queues_included_pre_migrate) do
+ ['email_receiver',
+ 'authorized_project_update:authorized_project_update_project_recalculate']
+ end
+
+ let(:queues_excluded_pre_migrate) { %w[new_email new_authorized] }
+ let(:queues_excluded_post_migrate) do
+ ['email_receiver',
+ 'authorized_project_update:authorized_project_update_project_recalculate']
+ end
+
+ let(:queues_included_post_migrate) { %w[new_email new_authorized] }
+
+ def post_migrate_checks
+ email_jobs = list_jobs('new_email')
+ expect(email_jobs.length).to eq(2)
+ expect(email_jobs[0]).to include('class' => 'EmailReceiverWorker', 'args' => ['bar'], 'queue' => 'new_email')
+ expect(email_jobs[1]).to include('class' => 'EmailReceiverWorker', 'args' => ['foo'], 'queue' => 'new_email')
+
+ export_jobs = list_jobs('new_authorized')
+ expect(export_jobs.length).to eq(1)
+ expect(export_jobs[0]).to include('class' => 'AuthorizedProjectUpdate::ProjectRecalculateWorker',
+ 'queue' => 'new_authorized')
+ end
+
+ it_behaves_like 'migrating queues'
+ end
+
+ context 'with illegal JSON payload' do
+ let(:job) { '{foo: 1}' }
+ let(:mappings) do
+ { 'EmailReceiverWorker' => 'default', 'AuthorizedProjectUpdate::ProjectRecalculateWorker' => 'default' }
+ end
+
+ let(:queues_included_pre_migrate) do
+ ['email_receiver',
+ 'authorized_project_update:authorized_project_update_project_recalculate']
+ end
+
+ let(:queues_excluded_pre_migrate) { ['default'] }
+ let(:queues_excluded_post_migrate) do
+ ['email_receiver',
+ 'authorized_project_update:authorized_project_update_project_recalculate']
+ end
+
+ let(:queues_included_post_migrate) { ['default'] }
+ let(:logger) { Logger.new(StringIO.new) }
+
+ before do
+ Sidekiq.redis do |conn|
+ conn.lpush("queue:email_receiver", job)
+ end
+ end
+
+ def pre_migrate_checks
+ expect(logger).to receive(:error)
+ .with(a_string_matching('Unmarshal JSON payload from SidekiqMigrateJobs failed'))
+ .once
+ end
+
+ def post_migrate_checks
+ jobs = list_jobs('default')
+ expect(jobs.length).to eq(3)
+ sorted = jobs.sort_by { |job| [job["class"], job["args"]] }
+ expect(sorted[0]).to include('class' => 'AuthorizedProjectUpdate::ProjectRecalculateWorker',
+ 'queue' => 'default')
+ expect(sorted[1]).to include('class' => 'EmailReceiverWorker', 'args' => ['bar'], 'queue' => 'default')
+ expect(sorted[2]).to include('class' => 'EmailReceiverWorker', 'args' => ['foo'], 'queue' => 'default')
+ end
+
+ it_behaves_like 'migrating queues'
+ end
+
+ context 'when multiple workers are in the same queue' do
+ before do
+ ExportCsvWorker.sidekiq_options(queue: 'email_receiver') # follows EmailReceiverWorker's queue
+ ExportCsvWorker.perform_async('fizz')
+ end
+
+ after do
+ ExportCsvWorker.set_queue
+ end
+
+ context 'when the queue exists in mappings' do
+ let(:mappings) do
+ { 'EmailReceiverWorker' => 'email_receiver', 'AuthorizedProjectUpdate::ProjectRecalculateWorker' => 'default',
+ 'ExportCsvWorker' => 'default' }
+ end
+
+ let(:queues_included_pre_migrate) do
+ ['email_receiver',
+ 'authorized_project_update:authorized_project_update_project_recalculate']
+ end
+
+ let(:queues_excluded_pre_migrate) { ['default'] }
+ let(:queues_excluded_post_migrate) do
+ ['authorized_project_update:authorized_project_update_project_recalculate']
+ end
+
+ let(:queues_included_post_migrate) { %w[default email_receiver] }
+
+ it_behaves_like 'migrating queues'
+ def post_migrate_checks
+ # jobs from email_receiver are not migrated at all
+ jobs = list_jobs('email_receiver')
+ expect(jobs.length).to eq(3)
+ sorted = jobs.sort_by { |job| [job["class"], job["args"]] }
+ expect(sorted[0]).to include('class' => 'EmailReceiverWorker', 'args' => ['bar'], 'queue' => 'email_receiver')
+ expect(sorted[1]).to include('class' => 'EmailReceiverWorker', 'args' => ['foo'], 'queue' => 'email_receiver')
+ expect(sorted[2]).to include('class' => 'ExportCsvWorker', 'args' => ['fizz'], 'queue' => 'email_receiver')
+ end
+ end
+
+ context 'when the queue doesnt exist in mappings' do
+ let(:mappings) do
+ { 'EmailReceiverWorker' => 'default', 'AuthorizedProjectUpdate::ProjectRecalculateWorker' => 'default',
+ 'ExportCsvWorker' => 'default' }
+ end
+
+ let(:queues_included_pre_migrate) do
+ ['email_receiver',
+ 'authorized_project_update:authorized_project_update_project_recalculate']
+ end
+
+ let(:queues_excluded_pre_migrate) { ['default'] }
+ let(:queues_excluded_post_migrate) do
+ ['email_receiver', 'authorized_project_update:authorized_project_update_project_recalculate']
+ end
+
+ let(:queues_included_post_migrate) { ['default'] }
+
+ it_behaves_like 'migrating queues'
+ def post_migrate_checks
+ # jobs from email_receiver are all migrated
+ jobs = list_jobs('email_receiver')
+ expect(jobs.length).to eq(0)
+
+ jobs = list_jobs('default')
+ expect(jobs.length).to eq(4)
+ sorted = jobs.sort_by { |job| [job["class"], job["args"]] }
+ expect(sorted[0]).to include('class' => 'AuthorizedProjectUpdate::ProjectRecalculateWorker',
+ 'queue' => 'default')
+ expect(sorted[1]).to include('class' => 'EmailReceiverWorker', 'args' => ['bar'], 'queue' => 'default')
+ expect(sorted[2]).to include('class' => 'EmailReceiverWorker', 'args' => ['foo'], 'queue' => 'default')
+ expect(sorted[3]).to include('class' => 'ExportCsvWorker', 'args' => ['fizz'], 'queue' => 'default')
+ end
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/slash_commands/application_help_spec.rb b/spec/lib/gitlab/slash_commands/application_help_spec.rb
index b82121bf3a8..b182c0e5cc6 100644
--- a/spec/lib/gitlab/slash_commands/application_help_spec.rb
+++ b/spec/lib/gitlab/slash_commands/application_help_spec.rb
@@ -4,11 +4,13 @@ require 'spec_helper'
RSpec.describe Gitlab::SlashCommands::ApplicationHelp do
let(:params) { { command: '/gitlab', text: 'help' } }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:chat_user) { create(:chat_name, user: user) }
let(:project) { build(:project) }
describe '#execute' do
subject do
- described_class.new(project, params).execute
+ described_class.new(project, chat_user, params).execute
end
it 'displays the help section' do
@@ -16,5 +18,23 @@ RSpec.describe Gitlab::SlashCommands::ApplicationHelp do
expect(subject[:text]).to include('Available commands')
expect(subject[:text]).to include('/gitlab [project name or alias] issue show')
end
+
+ context 'with incident declare command' do
+ context 'when feature flag is enabled' do
+ it 'displays the declare command' do
+ expect(subject[:text]).to include('/gitlab incident declare')
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(incident_declare_slash_command: false)
+ end
+
+ it 'does not displays the declare command' do
+ expect(subject[:text]).not_to include('/gitlab incident declare')
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/slash_commands/command_spec.rb b/spec/lib/gitlab/slash_commands/command_spec.rb
index 069577b3846..f4664bcfef9 100644
--- a/spec/lib/gitlab/slash_commands/command_spec.rb
+++ b/spec/lib/gitlab/slash_commands/command_spec.rb
@@ -122,5 +122,25 @@ RSpec.describe Gitlab::SlashCommands::Command do
it { is_expected.to eq(Gitlab::SlashCommands::IssueComment) }
end
+
+ context 'when incident declare is triggered' do
+ context 'IncidentNew is triggered' do
+ let(:params) { { text: 'incident declare' } }
+
+ it { is_expected.to eq(Gitlab::SlashCommands::IncidentManagement::IncidentNew) }
+ end
+
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(incident_declare_slash_command: false)
+ end
+
+ context 'IncidentNew is triggered' do
+ let(:params) { { text: 'incident declare' } }
+
+ it { is_expected.not_to eq(Gitlab::SlashCommands::IncidentManagement::IncidentNew) }
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/slash_commands/presenters/incident_management/incident_new_spec.rb b/spec/lib/gitlab/slash_commands/presenters/incident_management/incident_new_spec.rb
new file mode 100644
index 00000000000..cbc584b931f
--- /dev/null
+++ b/spec/lib/gitlab/slash_commands/presenters/incident_management/incident_new_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::SlashCommands::Presenters::IncidentManagement::IncidentNew do
+ subject { described_class.new }
+
+ it 'returns the ephemeral message' do
+ message = subject.present('It works!')
+
+ expect(message).to be_a(Hash)
+ expect(message[:text]).to eq('It works!')
+ expect(message[:response_type]).to be(:ephemeral)
+ end
+end
diff --git a/spec/lib/gitlab/sql/pattern_spec.rb b/spec/lib/gitlab/sql/pattern_spec.rb
index 9bf6f0b82bc..60bb006673f 100644
--- a/spec/lib/gitlab/sql/pattern_spec.rb
+++ b/spec/lib/gitlab/sql/pattern_spec.rb
@@ -29,6 +29,9 @@ RSpec.describe Gitlab::SQL::Pattern do
'AH' | %i[title description] | %i[issue3]
'oh' | %i[title] | %i[issue3]
'ah' | %i[description] | %i[issue3]
+
+ '' | %i[title] | %i[issue1 issue2 issue3]
+ %w[a b] | %i[title] | %i[issue1 issue2 issue3]
end
with_them do
@@ -104,14 +107,14 @@ RSpec.describe Gitlab::SQL::Pattern do
end
end
- describe '.select_fuzzy_words' do
- subject(:select_fuzzy_words) { Issue.select_fuzzy_words(query) }
+ describe '.select_fuzzy_terms' do
+ subject(:select_fuzzy_terms) { Issue.select_fuzzy_terms(query) }
context 'with a word equal to 3 chars' do
let(:query) { 'foo' }
- it 'returns array cotaining a word' do
- expect(select_fuzzy_words).to match_array(['foo'])
+ it 'returns array containing a word' do
+ expect(select_fuzzy_terms).to match_array(['foo'])
end
end
@@ -119,7 +122,7 @@ RSpec.describe Gitlab::SQL::Pattern do
let(:query) { 'fo' }
it 'returns empty array' do
- expect(select_fuzzy_words).to match_array([])
+ expect(select_fuzzy_terms).to match_array([])
end
end
@@ -127,7 +130,7 @@ RSpec.describe Gitlab::SQL::Pattern do
let(:query) { 'foo baz' }
it 'returns array containing two words' do
- expect(select_fuzzy_words).to match_array(%w[foo baz])
+ expect(select_fuzzy_terms).to match_array(%w[foo baz])
end
end
@@ -135,7 +138,7 @@ RSpec.describe Gitlab::SQL::Pattern do
let(:query) { 'foo baz' }
it 'returns array containing two words' do
- expect(select_fuzzy_words).to match_array(%w[foo baz])
+ expect(select_fuzzy_terms).to match_array(%w[foo baz])
end
end
@@ -143,7 +146,19 @@ RSpec.describe Gitlab::SQL::Pattern do
let(:query) { 'foo ba' }
it 'returns array containing a word' do
- expect(select_fuzzy_words).to match_array(['foo'])
+ expect(select_fuzzy_terms).to match_array(['foo'])
+ end
+ end
+ end
+
+ describe '.split_query_to_search_terms' do
+ subject(:split_query_to_search_terms) { described_class.split_query_to_search_terms(query) }
+
+ context 'with words separated by spaces' do
+ let(:query) { 'really bar baz' }
+
+ it 'returns array containing individual words' do
+ expect(split_query_to_search_terms).to match_array(%w[really bar baz])
end
end
@@ -151,15 +166,15 @@ RSpec.describe Gitlab::SQL::Pattern do
let(:query) { '"really bar"' }
it 'returns array containing a multi-word' do
- expect(select_fuzzy_words).to match_array(['really bar'])
+ expect(split_query_to_search_terms).to match_array(['really bar'])
end
end
context 'with a multi-word surrounded by double quote and two words' do
let(:query) { 'foo "really bar" baz' }
- it 'returns array containing a multi-word and tow words' do
- expect(select_fuzzy_words).to match_array(['foo', 'really bar', 'baz'])
+ it 'returns array containing a multi-word and two words' do
+ expect(split_query_to_search_terms).to match_array(['foo', 'really bar', 'baz'])
end
end
@@ -167,7 +182,7 @@ RSpec.describe Gitlab::SQL::Pattern do
let(:query) { 'foo"really bar"' }
it 'returns array containing two words with double quote' do
- expect(select_fuzzy_words).to match_array(['foo"really', 'bar"'])
+ expect(split_query_to_search_terms).to match_array(['foo"really', 'bar"'])
end
end
@@ -175,15 +190,15 @@ RSpec.describe Gitlab::SQL::Pattern do
let(:query) { '"really bar"baz' }
it 'returns array containing two words with double quote' do
- expect(select_fuzzy_words).to match_array(['"really', 'bar"baz'])
+ expect(split_query_to_search_terms).to match_array(['"really', 'bar"baz'])
end
end
context 'with two multi-word surrounded by double quote and two words' do
let(:query) { 'foo "really bar" baz "awesome feature"' }
- it 'returns array containing two multi-words and tow words' do
- expect(select_fuzzy_words).to match_array(['foo', 'really bar', 'baz', 'awesome feature'])
+ it 'returns array containing two multi-words and two words' do
+ expect(split_query_to_search_terms).to match_array(['foo', 'really bar', 'baz', 'awesome feature'])
end
end
end
diff --git a/spec/lib/gitlab/tracking/helpers/weak_password_error_event_spec.rb b/spec/lib/gitlab/tracking/helpers/weak_password_error_event_spec.rb
new file mode 100644
index 00000000000..3df10f79e98
--- /dev/null
+++ b/spec/lib/gitlab/tracking/helpers/weak_password_error_event_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Tracking::Helpers::WeakPasswordErrorEvent do
+ let(:user) { build(:user) }
+
+ subject(:helper) { Class.new.include(described_class).new }
+
+ context "when user has a weak password error" do
+ before do
+ user.password = "password"
+ user.valid?
+ end
+
+ it "tracks the event" do
+ helper.track_weak_password_error(user, 'A', 'B')
+ expect_snowplow_event(
+ category: 'Gitlab::Tracking::Helpers::WeakPasswordErrorEvent',
+ action: 'track_weak_password_error',
+ controller: 'A',
+ method: 'B'
+ )
+ end
+ end
+
+ context "when user does not have a weak password error" do
+ before do
+ user.password = "short"
+ user.valid?
+ end
+
+ it "does not track the event" do
+ helper.track_weak_password_error(user, 'A', 'B')
+ expect_no_snowplow_event
+ end
+ end
+
+ context "when user does not have any errors" do
+ it "does not track the event" do
+ helper.track_weak_password_error(user, 'A', 'B')
+ expect_no_snowplow_event
+ end
+ end
+end
diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb
index d4f96f1a37f..2e9a444bd24 100644
--- a/spec/lib/gitlab/url_builder_spec.rb
+++ b/spec/lib/gitlab/url_builder_spec.rb
@@ -22,8 +22,8 @@ RSpec.describe Gitlab::UrlBuilder do
:group_board | ->(board) { "/groups/#{board.group.full_path}/-/boards/#{board.id}" }
:commit | ->(commit) { "/#{commit.project.full_path}/-/commit/#{commit.id}" }
:issue | ->(issue) { "/#{issue.project.full_path}/-/issues/#{issue.iid}" }
- [:issue, :task] | ->(issue) { "/#{issue.project.full_path}/-/work_items/#{issue.id}" }
- :work_item | ->(work_item) { "/#{work_item.project.full_path}/-/work_items/#{work_item.id}" }
+ [:issue, :task] | ->(issue) { "/#{issue.project.full_path}/-/work_items/#{issue.iid}?iid_path=true" }
+ :work_item | ->(work_item) { "/#{work_item.project.full_path}/-/work_items/#{work_item.iid}?iid_path=true" }
:merge_request | ->(merge_request) { "/#{merge_request.project.full_path}/-/merge_requests/#{merge_request.iid}" }
:project_milestone | ->(milestone) { "/#{milestone.project.full_path}/-/milestones/#{milestone.iid}" }
:project_snippet | ->(snippet) { "/#{snippet.project.full_path}/-/snippets/#{snippet.id}" }
@@ -56,6 +56,7 @@ RSpec.describe Gitlab::UrlBuilder do
:discussion_note_on_project_snippet | ->(note) { "/#{note.project.full_path}/-/snippets/#{note.noteable_id}#note_#{note.id}" }
:discussion_note_on_personal_snippet | ->(note) { "/-/snippets/#{note.noteable_id}#note_#{note.id}" }
:note_on_personal_snippet | ->(note) { "/-/snippets/#{note.noteable_id}#note_#{note.id}" }
+ :package | ->(package) { "/#{package.project.full_path}/-/packages/#{package.id}" }
end
with_them do
@@ -71,18 +72,6 @@ RSpec.describe Gitlab::UrlBuilder do
end
end
- context 'when work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it 'returns an issue path for an issue of type task' do
- task = create(:issue, :task)
-
- expect(subject.build(task, only_path: true)).to eq("/#{task.project.full_path}/-/issues/#{task.iid}")
- end
- end
-
context 'when passing a compare' do
# NOTE: The Compare requires an actual repository, which isn't available
# with the `build_stubbed` strategy used by the table tests above
@@ -196,6 +185,18 @@ RSpec.describe Gitlab::UrlBuilder do
end
end
+ context 'when passing Packages::Package' do
+ let(:package) { build_stubbed(:terraform_module_package) }
+
+ context 'with infrastructure package' do
+ it 'returns the url for infrastucture registry' do
+ url = subject.build(package)
+
+ expect(url).to eq "#{Gitlab.config.gitlab.url}/#{package.project.full_path}/-/infrastructure_registry/#{package.id}"
+ end
+ end
+ end
+
context 'when passing a DesignManagement::Design' do
let(:design) { build_stubbed(:design) }
@@ -226,5 +227,27 @@ 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/metric_definition_spec.rb b/spec/lib/gitlab/usage/metric_definition_spec.rb
index a1bddcb3a47..931340947a2 100644
--- a/spec/lib/gitlab/usage/metric_definition_spec.rb
+++ b/spec/lib/gitlab/usage/metric_definition_spec.rb
@@ -74,13 +74,12 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
end
describe '#with_instrumentation_class' do
- let(:metric_status) { 'active' }
let(:all_definitions) do
metrics_definitions = [
- { key_path: 'metric1', instrumentation_class: 'RedisHLLMetric', status: 'data_available' },
- { key_path: 'metric2', instrumentation_class: 'RedisHLLMetric', status: 'implemented' },
- { key_path: 'metric3', instrumentation_class: 'RedisHLLMetric', status: 'deprecated' },
- { key_path: 'metric4', instrumentation_class: 'RedisHLLMetric', status: metric_status },
+ { key_path: 'metric1', instrumentation_class: 'RedisHLLMetric', status: 'active' },
+ { key_path: 'metric2', instrumentation_class: 'RedisHLLMetric', status: 'broken' },
+ { key_path: 'metric3', instrumentation_class: 'RedisHLLMetric', status: 'active' },
+ { key_path: 'metric4', instrumentation_class: 'RedisHLLMetric', status: 'removed' },
{ key_path: 'metric5', status: 'active' },
{ key_path: 'metric_missing_status' }
]
@@ -92,7 +91,7 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
end
it 'includes definitions with instrumentation_class' do
- expect(described_class.with_instrumentation_class.count).to eq(4)
+ expect(described_class.with_instrumentation_class.count).to eq(3)
end
context 'with removed metric' do
@@ -135,8 +134,9 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
:repair_issue_url | nil
:removed_by_url | 1
- :instrumentation_class | 'Metric_Class'
- :instrumentation_class | 'metricClass'
+ :performance_indicator_type | nil
+ :instrumentation_class | 'Metric_Class'
+ :instrumentation_class | 'metricClass'
end
with_them do
@@ -201,9 +201,9 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
using RSpec::Parameterized::TableSyntax
where(:status, :skip_validation?) do
- 'deprecated' | true
- 'removed' | true
'active' | false
+ 'broken' | false
+ 'removed' | true
end
with_them do
diff --git a/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb b/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb
index 76eec2755df..1f00f7bbec3 100644
--- a/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/aggregates/aggregate_spec.rb
@@ -3,403 +3,133 @@
require 'spec_helper'
RSpec.describe Gitlab::Usage::Metrics::Aggregates::Aggregate, :clean_gitlab_redis_shared_state do
- let(:entity1) { 'dfb9d2d2-f56c-4c77-8aeb-6cddc4a1f857' }
- let(:entity2) { '1dd9afb2-a3ee-4de1-8ae3-a405579c8584' }
- let(:entity3) { '34rfjuuy-ce56-sa35-ds34-dfer567dfrf2' }
- let(:entity4) { '8b9a2671-2abf-4bec-a682-22f6a8f7bf31' }
let(:end_date) { Date.current }
- let(:sources) { Gitlab::Usage::Metrics::Aggregates::Sources }
let(:namespace) { described_class.to_s.deconstantize.constantize }
+ let(:sources) { Gitlab::Usage::Metrics::Aggregates::Sources }
let_it_be(:recorded_at) { Time.current.to_i }
- def aggregated_metric(name:, time_frame:, source: "redis", events: %w[event1 event2 event3], operator: "OR", feature_flag: nil)
- {
- name: name,
- source: source,
- events: events,
- operator: operator,
- time_frame: time_frame,
- feature_flag: feature_flag
- }.compact.with_indifferent_access
- end
-
- context 'aggregated_metrics_data' do
- shared_examples 'aggregated_metrics_data' do
- context 'no aggregated metric is defined' do
- it 'returns empty hash' do
- allow_next_instance_of(described_class) do |instance|
- allow(instance).to receive(:aggregated_metrics).and_return([])
- end
-
- expect(aggregated_metrics_data).to eq({})
- end
+ describe '.calculate_count_for_aggregation' do
+ using RSpec::Parameterized::TableSyntax
+
+ context 'with valid configuration' do
+ where(:number_of_days, :operator, :datasource, :expected_method) do
+ 28 | 'AND' | 'redis_hll' | :calculate_metrics_intersections
+ 7 | 'AND' | 'redis_hll' | :calculate_metrics_intersections
+ 28 | 'AND' | 'database' | :calculate_metrics_intersections
+ 7 | 'AND' | 'database' | :calculate_metrics_intersections
+ 28 | 'OR' | 'redis_hll' | :calculate_metrics_union
+ 7 | 'OR' | 'redis_hll' | :calculate_metrics_union
+ 28 | 'OR' | 'database' | :calculate_metrics_union
+ 7 | 'OR' | 'database' | :calculate_metrics_union
end
- context 'there are aggregated metrics defined' do
- let(:aggregated_metrics) do
- [
- aggregated_metric(name: "gmau_1", source: datasource, time_frame: time_frame, operator: operator)
- ]
- end
-
- let(:results) { { 'gmau_1' => 5 } }
+ with_them do
+ let(:time_frame) { "#{number_of_days}d" }
+ let(:start_date) { number_of_days.days.ago.to_date }
let(:params) { { start_date: start_date, end_date: end_date, recorded_at: recorded_at } }
-
- before do
- allow_next_instance_of(described_class) do |instance|
- allow(instance).to receive(:aggregated_metrics).and_return(aggregated_metrics)
- end
- end
-
- context 'with OR operator' do
- let(:operator) { Gitlab::Usage::Metrics::Aggregates::UNION_OF_AGGREGATED_METRICS }
-
- it 'returns the number of unique events occurred for any metric in aggregate', :aggregate_failures do
- expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).with(params.merge(metric_names: %w[event1 event2 event3])).and_return(5)
- expect(aggregated_metrics_data).to eq(results)
- end
+ let(:aggregate) do
+ {
+ source: datasource,
+ operator: operator,
+ events: %w[event1 event2]
+ }
end
- context 'with AND operator' do
- let(:operator) { Gitlab::Usage::Metrics::Aggregates::INTERSECTION_OF_AGGREGATED_METRICS }
-
- it 'returns the number of unique events that occurred for all of metrics in the aggregate', :aggregate_failures do
- expect(namespace::SOURCES[datasource]).to receive(:calculate_metrics_intersections).with(params.merge(metric_names: %w[event1 event2 event3])).and_return(5)
- expect(aggregated_metrics_data).to eq(results)
- end
- end
-
- context 'hidden behind feature flag' do
- let(:enabled_feature_flag) { 'test_ff_enabled' }
- let(:disabled_feature_flag) { 'test_ff_disabled' }
- let(:aggregated_metrics) do
- params = { source: datasource, time_frame: time_frame }
- [
- # represents stable aggregated metrics that has been fully released
- aggregated_metric(**params.merge(name: "gmau_without_ff")),
- # represents new aggregated metric that is under performance testing on gitlab.com
- aggregated_metric(**params.merge(name: "gmau_enabled", feature_flag: enabled_feature_flag)),
- # represents aggregated metric that is under development and shouldn't be yet collected even on gitlab.com
- aggregated_metric(**params.merge(name: "gmau_disabled", feature_flag: disabled_feature_flag))
- ]
- end
-
- it 'does not calculate data for aggregates with ff turned off' do
- skip_feature_flags_yaml_validation
- skip_default_enabled_yaml_check
- stub_feature_flags(enabled_feature_flag => true, disabled_feature_flag => false)
- allow(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).and_return(6)
-
- expect(aggregated_metrics_data).to eq('gmau_without_ff' => 6, 'gmau_enabled' => 6)
- end
- end
- end
-
- context 'error handling' do
- context 'development and test environment' do
- it 'raises error when unknown aggregation operator is used' do
- allow_next_instance_of(described_class) do |instance|
- allow(instance).to receive(:aggregated_metrics)
- .and_return([aggregated_metric(name: 'gmau_1', source: datasource, operator: "SUM", time_frame: time_frame)])
- end
-
- expect { aggregated_metrics_data }.to raise_error namespace::UnknownAggregationOperator
- end
-
- it 'raises error when unknown aggregation source is used' do
- allow_next_instance_of(described_class) do |instance|
- allow(instance).to receive(:aggregated_metrics)
- .and_return([aggregated_metric(name: 'gmau_1', source: 'whoami', time_frame: time_frame)])
- end
-
- expect { aggregated_metrics_data }.to raise_error namespace::UnknownAggregationSource
- end
-
- it 'raises error when union is missing' do
- allow_next_instance_of(described_class) do |instance|
- allow(instance).to receive(:aggregated_metrics)
- .and_return([aggregated_metric(name: 'gmau_1', source: datasource, time_frame: time_frame)])
- end
- allow(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).and_raise(sources::UnionNotAvailable)
-
- expect { aggregated_metrics_data }.to raise_error sources::UnionNotAvailable
- end
+ subject(:calculate_count_for_aggregation) do
+ described_class
+ .new(recorded_at)
+ .calculate_count_for_aggregation(aggregation: aggregate, time_frame: time_frame)
end
- context 'production' do
- before do
- stub_rails_env('production')
- end
-
- it 'rescues unknown aggregation operator error' do
- allow_next_instance_of(described_class) do |instance|
- allow(instance).to receive(:aggregated_metrics)
- .and_return([aggregated_metric(name: 'gmau_1', source: datasource, operator: "SUM", time_frame: time_frame)])
- end
-
- expect(aggregated_metrics_data).to eq('gmau_1' => -1)
- end
-
- it 'rescues unknown aggregation source error' do
- allow_next_instance_of(described_class) do |instance|
- allow(instance).to receive(:aggregated_metrics)
- .and_return([aggregated_metric(name: 'gmau_1', source: 'whoami', time_frame: time_frame)])
- end
-
- expect(aggregated_metrics_data).to eq('gmau_1' => -1)
- end
-
- it 'rescues error when union is missing' do
- allow_next_instance_of(described_class) do |instance|
- allow(instance).to receive(:aggregated_metrics)
- .and_return([aggregated_metric(name: 'gmau_1', source: datasource, time_frame: time_frame)])
- end
- allow(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).and_raise(sources::UnionNotAvailable)
-
- expect(aggregated_metrics_data).to eq('gmau_1' => -1)
- end
+ it 'returns the number of unique events for aggregation', :aggregate_failures do
+ expect(namespace::SOURCES[datasource])
+ .to receive(expected_method)
+ .with(params.merge(metric_names: %w[event1 event2]))
+ .and_return(5)
+ expect(calculate_count_for_aggregation).to eq(5)
end
end
end
- shared_examples 'database_sourced_aggregated_metrics' do
- let(:datasource) { namespace::DATABASE_SOURCE }
-
- it_behaves_like 'aggregated_metrics_data'
- end
-
- shared_examples 'redis_sourced_aggregated_metrics' do
- let(:datasource) { namespace::REDIS_SOURCE }
-
- it_behaves_like 'aggregated_metrics_data' do
- context 'error handling' do
- let(:aggregated_metrics) { [aggregated_metric(name: 'gmau_1', source: datasource, time_frame: time_frame)] }
- let(:error) { Gitlab::UsageDataCounters::HLLRedisCounter::EventError }
-
- before do
- allow_next_instance_of(described_class) do |instance|
- allow(instance).to receive(:aggregated_metrics).and_return(aggregated_metrics)
- end
- allow(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:calculate_events_union).and_raise(error)
- end
-
- context 'development and test environment' do
- it 're raises Gitlab::UsageDataCounters::HLLRedisCounter::EventError' do
- expect { aggregated_metrics_data }.to raise_error error
- end
- end
-
- context 'production' do
- it 'rescues Gitlab::UsageDataCounters::HLLRedisCounter::EventError' do
- stub_rails_env('production')
-
- expect(aggregated_metrics_data).to eq('gmau_1' => -1)
- end
- end
- end
+ context 'with invalid configuration' do
+ where(:time_frame, :operator, :datasource, :expected_error) do
+ '28d' | 'SUM' | 'redis_hll' | namespace::UnknownAggregationOperator
+ '7d' | 'AND' | 'mongodb' | namespace::UnknownAggregationSource
+ 'all' | 'AND' | 'redis_hll' | namespace::DisallowedAggregationTimeFrame
end
- end
-
- describe '.aggregated_metrics_all_time_data' do
- subject(:aggregated_metrics_data) { described_class.new(recorded_at).all_time_data }
- let(:start_date) { nil }
- let(:end_date) { nil }
- let(:time_frame) { ['all'] }
-
- it_behaves_like 'database_sourced_aggregated_metrics'
-
- context 'redis sourced aggregated metrics' do
- let(:aggregated_metrics) { [aggregated_metric(name: 'gmau_1', time_frame: time_frame)] }
+ with_them do
+ let(:aggregate) do
+ {
+ source: datasource,
+ operator: operator,
+ events: %w[event1 event2]
+ }
+ end
- before do
- allow_next_instance_of(described_class) do |instance|
- allow(instance).to receive(:aggregated_metrics).and_return(aggregated_metrics)
- end
+ subject(:calculate_count_for_aggregation) do
+ described_class
+ .new(recorded_at)
+ .calculate_count_for_aggregation(aggregation: aggregate, time_frame: time_frame)
end
- context 'development and test environment' do
- it 'raises Gitlab::Usage::Metrics::Aggregates::DisallowedAggregationTimeFrame' do
- expect { aggregated_metrics_data }.to raise_error namespace::DisallowedAggregationTimeFrame
+ context 'with non prod environment' do
+ it 'raises error' do
+ expect { calculate_count_for_aggregation }.to raise_error expected_error
end
end
- context 'production env' do
- it 'returns fallback value for unsupported time frame' do
+ context 'with prod environment' do
+ before do
stub_rails_env('production')
+ end
- expect(aggregated_metrics_data).to eq('gmau_1' => -1)
+ it 'returns fallback value' do
+ expect(calculate_count_for_aggregation).to be(-1)
end
end
end
end
- context 'legacy aggregated metrics configuration' do
- let(:temp_dir) { Dir.mktmpdir }
- let(:temp_file) { Tempfile.new(%w[common .yml], temp_dir) }
-
- before do
- stub_const("#{namespace}::AGGREGATED_METRICS_PATH", File.expand_path('*.yml', temp_dir))
- File.open(temp_file.path, "w+b") do |file|
- file.write [aggregated_metric(name: "gmau_1", time_frame: '7d')].to_yaml
- end
- end
-
- after do
- temp_file.unlink
- FileUtils.remove_entry(temp_dir) if Dir.exist?(temp_dir)
+ context 'when union data is not available' do
+ subject(:calculate_count_for_aggregation) do
+ described_class
+ .new(recorded_at)
+ .calculate_count_for_aggregation(aggregation: aggregate, time_frame: time_frame)
end
- it 'allows for YAML aliases in aggregated metrics configs' do
- expect(YAML).to receive(:safe_load).with(kind_of(String), aliases: true).at_least(:once)
-
- described_class.new(recorded_at)
+ where(:time_frame, :operator, :datasource) do
+ '28d' | 'OR' | 'redis_hll'
+ '7d' | 'OR' | 'database'
end
- end
-
- describe '.aggregated_metrics_weekly_data' do
- subject(:aggregated_metrics_data) { described_class.new(recorded_at).weekly_data }
- let(:start_date) { 7.days.ago.to_date }
- let(:time_frame) { ['7d'] }
-
- it_behaves_like 'database_sourced_aggregated_metrics'
- it_behaves_like 'redis_sourced_aggregated_metrics'
- end
-
- describe '.aggregated_metrics_monthly_data' do
- subject(:aggregated_metrics_data) { described_class.new(recorded_at).monthly_data }
-
- let(:start_date) { 4.weeks.ago.to_date }
- let(:time_frame) { ['28d'] }
-
- it_behaves_like 'database_sourced_aggregated_metrics'
- it_behaves_like 'redis_sourced_aggregated_metrics'
- end
-
- describe '.calculate_count_for_aggregation' do
- using RSpec::Parameterized::TableSyntax
-
- context 'with valid configuration' do
- where(:number_of_days, :operator, :datasource, :expected_method) do
- 28 | 'AND' | 'redis' | :calculate_metrics_intersections
- 7 | 'AND' | 'redis' | :calculate_metrics_intersections
- 28 | 'AND' | 'database' | :calculate_metrics_intersections
- 7 | 'AND' | 'database' | :calculate_metrics_intersections
- 28 | 'OR' | 'redis' | :calculate_metrics_union
- 7 | 'OR' | 'redis' | :calculate_metrics_union
- 28 | 'OR' | 'database' | :calculate_metrics_union
- 7 | 'OR' | 'database' | :calculate_metrics_union
- end
-
- with_them do
- let(:time_frame) { "#{number_of_days}d" }
- let(:start_date) { number_of_days.days.ago.to_date }
- let(:params) { { start_date: start_date, end_date: end_date, recorded_at: recorded_at } }
- let(:aggregate) do
- {
- source: datasource,
- operator: operator,
- events: %w[event1 event2]
- }
- end
-
- subject(:calculate_count_for_aggregation) do
- described_class
- .new(recorded_at)
- .calculate_count_for_aggregation(aggregation: aggregate, time_frame: time_frame)
- end
-
- it 'returns the number of unique events for aggregation', :aggregate_failures do
- expect(namespace::SOURCES[datasource])
- .to receive(expected_method)
- .with(params.merge(metric_names: %w[event1 event2]))
- .and_return(5)
- expect(calculate_count_for_aggregation).to eq(5)
- end
+ with_them do
+ before do
+ allow(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).and_raise(sources::UnionNotAvailable)
end
- end
- context 'with invalid configuration' do
- where(:time_frame, :operator, :datasource, :expected_error) do
- '28d' | 'SUM' | 'redis' | namespace::UnknownAggregationOperator
- '7d' | 'AND' | 'mongodb' | namespace::UnknownAggregationSource
- 'all' | 'AND' | 'redis' | namespace::DisallowedAggregationTimeFrame
+ let(:aggregate) do
+ {
+ source: datasource,
+ operator: operator,
+ events: %w[event1 event2]
+ }
end
- with_them do
- let(:aggregate) do
- {
- source: datasource,
- operator: operator,
- events: %w[event1 event2]
- }
- end
-
- subject(:calculate_count_for_aggregation) do
- described_class
- .new(recorded_at)
- .calculate_count_for_aggregation(aggregation: aggregate, time_frame: time_frame)
- end
-
- context 'with non prod environment' do
- it 'raises error' do
- expect { calculate_count_for_aggregation }.to raise_error expected_error
- end
- end
-
- context 'with prod environment' do
- before do
- stub_rails_env('production')
- end
-
- it 'returns fallback value' do
- expect(calculate_count_for_aggregation).to be(-1)
- end
+ context 'with non prod environment' do
+ it 'raises error' do
+ expect { calculate_count_for_aggregation }.to raise_error sources::UnionNotAvailable
end
end
- end
-
- context 'when union data is not available' do
- subject(:calculate_count_for_aggregation) do
- described_class
- .new(recorded_at)
- .calculate_count_for_aggregation(aggregation: aggregate, time_frame: time_frame)
- end
- where(:time_frame, :operator, :datasource) do
- '28d' | 'OR' | 'redis'
- '7d' | 'OR' | 'database'
- end
-
- with_them do
+ context 'with prod environment' do
before do
- allow(namespace::SOURCES[datasource]).to receive(:calculate_metrics_union).and_raise(sources::UnionNotAvailable)
- end
-
- let(:aggregate) do
- {
- source: datasource,
- operator: operator,
- events: %w[event1 event2]
- }
- end
-
- context 'with non prod environment' do
- it 'raises error' do
- expect { calculate_count_for_aggregation }.to raise_error sources::UnionNotAvailable
- end
+ stub_rails_env('production')
end
- context 'with prod environment' do
- before do
- stub_rails_env('production')
- end
-
- it 'returns fallback value' do
- expect(calculate_count_for_aggregation).to be(-1)
- end
+ it 'returns fallback value' do
+ expect(calculate_count_for_aggregation).to be(-1)
end
end
end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/count_merge_request_authors_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/count_merge_request_authors_metric_spec.rb
new file mode 100644
index 00000000000..92459e92eac
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/count_merge_request_authors_metric_spec.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::CountMergeRequestAuthorsMetric do
+ let(:expected_value) { 1 }
+ let(:start) { 30.days.ago.to_s(:db) }
+ let(:finish) { 2.days.ago.to_s(:db) }
+
+ let(:expected_query) do
+ "SELECT COUNT(DISTINCT \"merge_requests\".\"author_id\") FROM \"merge_requests\"" \
+ " WHERE \"merge_requests\".\"created_at\" BETWEEN '#{start}' AND '#{finish}'"
+ end
+
+ before do
+ user = create(:user)
+ user2 = create(:user)
+
+ create(:merge_request, created_at: 1.year.ago, author: user)
+ create(:merge_request, created_at: 1.week.ago, author: user2)
+ create(:merge_request, created_at: 1.week.ago, author: user2)
+ end
+
+ it_behaves_like 'a correct instrumented metric value and query', { time_frame: '28d' }
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/database_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/database_metric_spec.rb
index f73155642d6..f1ecc8c8ab5 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/database_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/database_metric_spec.rb
@@ -3,12 +3,14 @@
require 'spec_helper'
RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
+ let(:database_metric_class) { Class.new(described_class) }
+
subject do
- described_class.tap do |metric_class|
+ database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :count
- metric_class.start { metric_class.relation.minimum(:id) }
- metric_class.finish { metric_class.relation.maximum(:id) }
+ metric_class.start { Issue.minimum(:id) }
+ metric_class.finish { Issue.maximum(:id) }
end.new(time_frame: 'all')
end
@@ -38,11 +40,11 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with metric options specified with custom batch_size' do
subject do
- described_class.tap do |metric_class|
+ database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :count
- metric_class.start { metric_class.relation.minimum(:id) }
- metric_class.finish { metric_class.relation.maximum(:id) }
+ metric_class.start { Issue.minimum(:id) }
+ metric_class.finish { Issue.maximum(:id) }
metric_class.metric_options { { batch_size: 12345 } }
end.new(time_frame: 'all')
end
@@ -60,7 +62,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with start and finish not called' do
subject do
- described_class.tap do |metric_class|
+ database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :count
end.new(time_frame: 'all')
@@ -73,7 +75,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with availability defined' do
subject do
- described_class.tap do |metric_class|
+ database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :count
metric_class.available? { false }
@@ -87,7 +89,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with availability not defined' do
subject do
- Class.new(described_class) do
+ database_metric_class do
relation { Issue }
operation :count
end.new(time_frame: 'all')
@@ -100,11 +102,11 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with cache_start_and_finish_as called' do
subject do
- described_class.tap do |metric_class|
+ database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :count
- metric_class.start { metric_class.relation.minimum(:id) }
- metric_class.finish { metric_class.relation.maximum(:id) }
+ metric_class.start { Issue.minimum(:id) }
+ metric_class.finish { Issue.maximum(:id) }
metric_class.cache_start_and_finish_as :special_issue_count
end.new(time_frame: 'all')
end
@@ -123,11 +125,11 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with estimate_batch_distinct_count' do
subject do
- described_class.tap do |metric_class|
+ database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation(:estimate_batch_distinct_count)
- metric_class.start { metric_class.relation.minimum(:id) }
- metric_class.finish { metric_class.relation.maximum(:id) }
+ metric_class.start { Issue.minimum(:id) }
+ metric_class.finish { Issue.maximum(:id) }
end.new(time_frame: 'all')
end
@@ -139,13 +141,13 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
let(:buckets) { double('Buckets').as_null_object }
subject do
- described_class.tap do |metric_class|
+ database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation(:estimate_batch_distinct_count) do |result|
result.foo
end
- metric_class.start { metric_class.relation.minimum(:id) }
- metric_class.finish { metric_class.relation.maximum(:id) }
+ metric_class.start { Issue.minimum(:id) }
+ metric_class.finish { Issue.maximum(:id) }
end.new(time_frame: 'all')
end
@@ -163,7 +165,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with custom timestamp column' do
subject do
- described_class.tap do |metric_class|
+ database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :count
metric_class.timestamp_column :last_edited_at
@@ -171,6 +173,7 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
end
it 'calculates a correct result' do
+ create(:issue, last_edited_at: 40.days.ago)
create(:issue, last_edited_at: 5.days.ago)
expect(subject.value).to eq(1)
@@ -179,24 +182,40 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DatabaseMetric do
context 'with default timestamp column' do
subject do
- described_class.tap do |metric_class|
+ database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :count
end.new(time_frame: '28d')
end
it 'calculates a correct result' do
- create(:issue, last_edited_at: 5.days.ago)
+ create(:issue, created_at: 40.days.ago)
create(:issue, created_at: 5.days.ago)
expect(subject.value).to eq(1)
end
end
+
+ context 'with additional parameters passed via options' do
+ subject do
+ database_metric_class.tap do |metric_class|
+ metric_class.relation ->(options) { Issue.where(confidential: options[:confidential]) }
+ metric_class.operation :count
+ end.new(time_frame: '28d', options: { confidential: true })
+ end
+
+ it 'calculates a correct result' do
+ create(:issue, created_at: 5.days.ago, confidential: true)
+ create(:issue, created_at: 5.days.ago, confidential: false)
+
+ expect(subject.value).to eq(1)
+ end
+ end
end
context 'with unimplemented operation method used' do
subject do
- described_class.tap do |metric_class|
+ database_metric_class.tap do |metric_class|
metric_class.relation { Issue }
metric_class.operation :invalid_operation
end.new(time_frame: 'all')
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_disabled_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_disabled_metric_spec.rb
deleted file mode 100644
index 757adee6117..00000000000
--- a/spec/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_disabled_metric_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DistinctCountProjectsWithExpirationPolicyDisabledMetric do
- before_all do
- create(:container_expiration_policy, enabled: false)
- create(:container_expiration_policy, enabled: false, created_at: 29.days.ago)
- create(:container_expiration_policy, enabled: true)
- end
-
- it_behaves_like 'a correct instrumented metric value', { time_frame: '28d' } do
- let(:expected_value) { 1 }
- end
-
- it_behaves_like 'a correct instrumented metric value', { time_frame: 'all' } do
- let(:expected_value) { 2 }
- end
-end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_metric_spec.rb
new file mode 100644
index 00000000000..a1ca658a0d7
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/distinct_count_projects_with_expiration_policy_metric_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DistinctCountProjectsWithExpirationPolicyMetric do
+ before_all do
+ create(:container_expiration_policy, enabled: false)
+ create(:container_expiration_policy, enabled: false, created_at: 29.days.ago)
+ create(:container_expiration_policy, keep_n: nil)
+ create(:container_expiration_policy, keep_n: 5, enabled: true)
+ create(:container_expiration_policy, keep_n: 5, enabled: true)
+ create(:container_expiration_policy, keep_n: 5, enabled: true)
+ create(:container_expiration_policy, older_than: '7d')
+ create(:container_expiration_policy, cadence: '14d')
+ create(:container_expiration_policy, enabled: true)
+ end
+
+ it_behaves_like 'a correct instrumented metric value', { time_frame: '28d', options: { enabled: false } } do
+ let(:expected_value) { 1 }
+ end
+
+ it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', options: { enabled: false } } do
+ let(:expected_value) { 2 }
+ end
+
+ it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', options: { keep_n: 5, enabled: true } } do
+ let(:expected_value) { 3 }
+ end
+
+ it_behaves_like 'a correct instrumented metric value', { time_frame: 'all', options: { cadence: '14d' } } do
+ let(:expected_value) { 1 }
+ end
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/dormant_user_period_setting_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/dormant_user_period_setting_metric_spec.rb
new file mode 100644
index 00000000000..a63616aeb48
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/dormant_user_period_setting_metric_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DormantUserPeriodSettingMetric do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:deactivate_dormant_users_period_value, :expected_value) do
+ 90 | 90 # default
+ 365 | 365
+ end
+
+ with_them do
+ before do
+ stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
+ stub_application_setting(deactivate_dormant_users_period: deactivate_dormant_users_period_value)
+ end
+
+ it_behaves_like 'a correct instrumented metric value', {}
+ end
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/dormant_user_setting_enabled_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/dormant_user_setting_enabled_metric_spec.rb
new file mode 100644
index 00000000000..5c8ca502f82
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/dormant_user_setting_enabled_metric_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::DormantUserSettingEnabledMetric do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:deactivate_dormant_users_enabled, :expected_value) do
+ 1 | 1
+ 0 | 0
+ end
+
+ with_them do
+ before do
+ stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
+ stub_application_setting(deactivate_dormant_users: deactivate_dormant_users_enabled)
+ end
+
+ it_behaves_like 'a correct instrumented metric value', {}
+ end
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_cta_clicked_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_cta_clicked_metric_spec.rb
new file mode 100644
index 00000000000..cb94da11d58
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_cta_clicked_metric_spec.rb
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::InProductMarketingEmailCtaClickedMetric do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:email_attributes) { { cta_clicked_at: Date.yesterday, track: 'verify', series: 0 } }
+ let(:options) { { track: 'verify', series: 0 } }
+ let(:expected_value) { 2 }
+ let(:expected_query) do
+ 'SELECT COUNT("in_product_marketing_emails"."id") FROM "in_product_marketing_emails"' \
+ ' WHERE "in_product_marketing_emails"."cta_clicked_at" IS NOT NULL' \
+ ' AND "in_product_marketing_emails"."series" = 0'\
+ ' AND "in_product_marketing_emails"."track" = 1'
+ end
+
+ before do
+ create_list :in_product_marketing_email, 2, email_attributes
+
+ create :in_product_marketing_email, email_attributes.merge(cta_clicked_at: nil)
+ create :in_product_marketing_email, email_attributes.merge(track: 'team')
+ create :in_product_marketing_email, email_attributes.merge(series: 1)
+ end
+
+ it_behaves_like 'a correct instrumented metric value and query', {
+ options: { track: 'verify', series: 0 },
+ time_frame: 'all'
+ }
+
+ where(:options_key, :valid_value, :invalid_value) do
+ :track | 'admin_verify' | 'invite_team'
+ :series | 1 | 5
+ end
+
+ with_them do
+ it "raises an exception if option is not present" do
+ expect do
+ described_class.new(options: options.except(options_key), time_frame: 'all')
+ end.to raise_error(ArgumentError, %r{#{options_key} .* must be one of})
+ end
+
+ it "raises an exception if option has invalid value" do
+ expect do
+ options[options_key] = invalid_value
+ described_class.new(options: options, time_frame: 'all')
+ end.to raise_error(ArgumentError, %r{#{options_key} .* must be one of})
+ end
+
+ it "doesn't raise exceptions if option has valid value" do
+ options[options_key] = valid_value
+ described_class.new(options: options, time_frame: 'all')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_sent_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_sent_metric_spec.rb
new file mode 100644
index 00000000000..0cc82773d56
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/in_product_marketing_email_sent_metric_spec.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::Instrumentations::InProductMarketingEmailSentMetric do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:email_attributes) { { track: 'verify', series: 0 } }
+ let(:expected_value) { 2 }
+ let(:expected_query) do
+ 'SELECT COUNT("in_product_marketing_emails"."id") FROM "in_product_marketing_emails"' \
+ ' WHERE "in_product_marketing_emails"."series" = 0'\
+ ' AND "in_product_marketing_emails"."track" = 1'
+ end
+
+ before do
+ create_list :in_product_marketing_email, 2, email_attributes
+
+ create :in_product_marketing_email, email_attributes.merge(track: 'team')
+ create :in_product_marketing_email, email_attributes.merge(series: 1)
+ end
+
+ it_behaves_like 'a correct instrumented metric value and query', {
+ options: { track: 'verify', series: 0 },
+ time_frame: 'all'
+ }
+
+ where(:options_key, :valid_value, :invalid_value) do
+ :track | 'admin_verify' | 'invite_team'
+ :series | 1 | 5
+ end
+
+ with_them do
+ it "raises an exception if option is not present" do
+ expect do
+ described_class.new(options: email_attributes.except(options_key), time_frame: 'all')
+ end.to raise_error(ArgumentError, %r{#{options_key} .* must be one of})
+ end
+
+ it "raises an exception if option has invalid value" do
+ expect do
+ email_attributes[options_key] = invalid_value
+ described_class.new(options: email_attributes, time_frame: 'all')
+ end.to raise_error(ArgumentError, %r{#{options_key} .* must be one of})
+ end
+
+ it "doesn't raise exceptions if option has valid value" do
+ email_attributes[options_key] = valid_value
+ described_class.new(options: email_attributes, time_frame: 'all')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/usage/metrics/instrumentations/work_items_activity_aggregated_metric_spec.rb b/spec/lib/gitlab/usage/metrics/instrumentations/work_items_activity_aggregated_metric_spec.rb
index 3e315692d0a..35e5d7f2796 100644
--- a/spec/lib/gitlab/usage/metrics/instrumentations/work_items_activity_aggregated_metric_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/instrumentations/work_items_activity_aggregated_metric_spec.rb
@@ -15,6 +15,8 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::WorkItemsActivityAggreg
users_creating_work_items
users_updating_work_item_title
users_updating_work_item_dates
+ users_updating_work_item_labels
+ users_updating_work_item_milestone
users_updating_work_item_iteration
]
}
@@ -44,16 +46,26 @@ RSpec.describe Gitlab::Usage::Metrics::Instrumentations::WorkItemsActivityAggreg
describe '#value', :clean_gitlab_redis_shared_state do
let(:counter) { Gitlab::UsageDataCounters::HLLRedisCounter }
+ let(:author1_id) { 1 }
+ let(:author2_id) { 2 }
+ let(:event_time) { 1.week.ago }
before do
- counter.track_event(:users_creating_work_items, values: 1, time: 1.week.ago)
- counter.track_event(:users_updating_work_item_title, values: 1, time: 1.week.ago)
- counter.track_event(:users_updating_work_item_dates, values: 2, time: 1.week.ago)
- counter.track_event(:users_updating_work_item_iteration, values: 2, time: 1.week.ago)
+ counter.track_event(:users_creating_work_items, values: author1_id, time: event_time)
end
- it 'has correct value' do
- expect(described_class.new(metric_definition).value).to eq 2
+ it 'has correct value after events are tracked', :aggregate_failures do
+ expect do
+ counter.track_event(:users_updating_work_item_title, values: author1_id, time: event_time)
+ counter.track_event(:users_updating_work_item_dates, values: author1_id, time: event_time)
+ counter.track_event(:users_updating_work_item_labels, values: author1_id, time: event_time)
+ counter.track_event(:users_updating_work_item_milestone, values: author1_id, time: event_time)
+ end.to not_change { described_class.new(metric_definition).value }
+
+ expect do
+ counter.track_event(:users_updating_work_item_iteration, values: author2_id, time: event_time)
+ counter.track_event(:users_updating_weight_estimate, values: author1_id, time: event_time)
+ end.to change { described_class.new(metric_definition).value }.from(1).to(2)
end
end
end
diff --git a/spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb b/spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb
index f9cd6e88e0a..24107727a8e 100644
--- a/spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb
+++ b/spec/lib/gitlab/usage/metrics/name_suggestion_spec.rb
@@ -63,7 +63,6 @@ RSpec.describe Gitlab::Usage::Metrics::NameSuggestion do
context 'for sum metrics' do
it_behaves_like 'name suggestion' do
# corresponding metric is collected with sum(JiraImportState.finished, :imported_issues_count)
- let(:key_path) { 'counts.jira_imports_total_imported_issues_count' }
let(:operation) { :sum }
let(:relation) { JiraImportState.finished }
let(:column) { :imported_issues_count }
@@ -74,7 +73,6 @@ RSpec.describe Gitlab::Usage::Metrics::NameSuggestion do
context 'for average metrics' do
it_behaves_like 'name suggestion' do
# corresponding metric is collected with average(Ci::Pipeline, :duration)
- let(:key_path) { 'counts.ci_pipeline_duration' }
let(:operation) { :average }
let(:relation) { Ci::Pipeline }
let(:column) { :duration }
@@ -100,5 +98,16 @@ RSpec.describe Gitlab::Usage::Metrics::NameSuggestion do
let(:name_suggestion) { /<please fill metric name>/ }
end
end
+
+ context 'for metrics with `having` keyword' do
+ it_behaves_like 'name suggestion' do
+ let(:operation) { :count }
+ let(:relation) { Issue.with_alert_management_alerts.having('COUNT(alert_management_alerts) > 1').group(:id) }
+
+ let(:column) { nil }
+ let(:constraints) { /<adjective describing: '\(\(COUNT\(alert_management_alerts\) > 1\)\)'>/ }
+ let(:name_suggestion) { /count_#{constraints}_issues_<with>_alert_management_alerts/ }
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/constraints_spec.rb b/spec/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/constraints_spec.rb
deleted file mode 100644
index 68016e760e4..00000000000
--- a/spec/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/constraints_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Gitlab::Usage::Metrics::NamesSuggestions::RelationParsers::Constraints do
- describe '#accept' do
- let(:collector) { Arel::Collectors::SubstituteBinds.new(ActiveRecord::Base.connection, Arel::Collectors::SQLString.new) }
-
- it 'builds correct constraints description' do
- table = Arel::Table.new('records')
- arel = table.from.project(table['id'].count).where(table[:attribute].eq(true).and(table[:some_value].gt(5)))
- described_class.new(ApplicationRecord.connection).accept(arel, collector)
-
- expect(collector.value).to eql '(records.attribute = true AND records.some_value > 5)'
- end
- end
-end
diff --git a/spec/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/having_constraints_spec.rb b/spec/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/having_constraints_spec.rb
new file mode 100644
index 00000000000..492acf2a902
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/having_constraints_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::NamesSuggestions::RelationParsers::HavingConstraints do
+ describe '#accept' do
+ let(:connection) { ApplicationRecord.connection }
+ let(:collector) { Arel::Collectors::SubstituteBinds.new(connection, Arel::Collectors::SQLString.new) }
+
+ it 'builds correct constraints description' do
+ table = Arel::Table.new('records')
+ havings = table[:attribute].sum.eq(6).and(table[:attribute].count.gt(5))
+ arel = table.from.project(table['id'].count).having(havings).group(table[:attribute2])
+ described_class.new(connection).accept(arel, collector)
+
+ expect(collector.value).to eql '(SUM(records.attribute) = 6 AND COUNT(records.attribute) > 5)'
+ end
+ end
+end
diff --git a/spec/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/where_constraints_spec.rb b/spec/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/where_constraints_spec.rb
new file mode 100644
index 00000000000..42a776478a4
--- /dev/null
+++ b/spec/lib/gitlab/usage/metrics/names_suggestions/relation_parsers/where_constraints_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Usage::Metrics::NamesSuggestions::RelationParsers::WhereConstraints do
+ describe '#accept' do
+ let(:connection) { ApplicationRecord.connection }
+ let(:collector) { Arel::Collectors::SubstituteBinds.new(connection, Arel::Collectors::SQLString.new) }
+
+ it 'builds correct constraints description' do
+ table = Arel::Table.new('records')
+ arel = table.from.project(table['id'].count).where(table[:attribute].eq(true).and(table[:some_value].gt(5)))
+ described_class.new(connection).accept(arel, collector)
+
+ expect(collector.value).to eql '(records.attribute = true AND records.some_value > 5)'
+ end
+ end
+end
diff --git a/spec/lib/gitlab/usage_data_counters/ci_template_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/ci_template_unique_counter_spec.rb
index 1ca0bb0e9ea..f1115a8813d 100644
--- a/spec/lib/gitlab/usage_data_counters/ci_template_unique_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/ci_template_unique_counter_spec.rb
@@ -12,6 +12,10 @@ RSpec.describe Gitlab::UsageDataCounters::CiTemplateUniqueCounter do
shared_examples 'tracks template' do
let(:subject) { described_class.track_unique_project_event(project: project, template: template_path, config_source: config_source, user: user) }
+ let(:template_name) do
+ expanded_template_name = described_class.expand_template_name(template_path)
+ described_class.ci_template_event_name(expanded_template_name, config_source)
+ end
it "has an event defined for template" do
expect do
@@ -20,33 +24,18 @@ RSpec.describe Gitlab::UsageDataCounters::CiTemplateUniqueCounter do
end
it "tracks template" do
- expanded_template_name = described_class.expand_template_name(template_path)
- expected_template_event_name = described_class.ci_template_event_name(expanded_template_name, config_source)
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).to(receive(:track_event)).with(expected_template_event_name, values: project.id)
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter).to(receive(:track_event)).with(template_name, values: project.id)
subject
end
- context 'Snowplow' do
- it 'event is not tracked if FF is disabled' do
- stub_feature_flags(route_hll_to_snowplow: false)
-
- subject
-
- expect_no_snowplow_event
- end
-
- it 'tracks event' do
- subject
-
- expect_snowplow_event(
- category: described_class.to_s,
- action: 'ci_templates_unique',
- namespace: project.namespace,
- user: user,
- project: project
- )
- end
+ it_behaves_like 'Snowplow event tracking with RedisHLL context' do
+ let(:feature_flag_name) { :route_hll_to_snowplow }
+ let(:category) { described_class.to_s }
+ let(:action) { 'ci_templates_unique' }
+ let(:namespace) { project.namespace }
+ let(:label) { 'redis_hll_counters.ci_templates.ci_templates_total_unique_counts_monthly' }
+ let(:context) { [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: template_name).to_context] }
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 d0b935d59dd..08c712889a8 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
@@ -17,6 +17,7 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s
# Without freezing the time, the test may behave inconsistently
# depending on which day of the week test is run.
# Monday 6th of June
+ described_class.clear_memoization(:known_events)
reference_time = Time.utc(2020, 6, 1)
travel_to(reference_time) { example.run }
described_class.clear_memoization(:known_events)
diff --git a/spec/lib/gitlab/usage_data_counters/kubernetes_agent_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/kubernetes_agent_counter_spec.rb
index e7edb8b9cf1..ced9ec7f221 100644
--- a/spec/lib/gitlab/usage_data_counters/kubernetes_agent_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/kubernetes_agent_counter_spec.rb
@@ -26,6 +26,12 @@ RSpec.describe Gitlab::UsageDataCounters::KubernetesAgentCounter do
expect(described_class.totals).to eq(kubernetes_agent_gitops_sync: 3, kubernetes_agent_k8s_api_proxy_request: 6)
end
+ context 'with empty events' do
+ let(:events) { nil }
+
+ it { expect { subject }.not_to change(described_class, :totals) }
+ end
+
context 'event is unknown' do
let(:events) do
{
diff --git a/spec/lib/gitlab/usage_data_counters/work_item_activity_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/work_item_activity_unique_counter_spec.rb
index 2d251017c87..aaf509b6f81 100644
--- a/spec/lib/gitlab/usage_data_counters/work_item_activity_unique_counter_spec.rb
+++ b/spec/lib/gitlab/usage_data_counters/work_item_activity_unique_counter_spec.rb
@@ -36,4 +36,12 @@ RSpec.describe Gitlab::UsageDataCounters::WorkItemActivityUniqueCounter, :clean_
it_behaves_like 'work item unique counter'
end
+
+ describe '.track_work_item_milestone_changed_action' do
+ subject(:track_event) { described_class.track_work_item_milestone_changed_action(author: user) }
+
+ let(:event_name) { described_class::WORK_ITEM_MILESTONE_CHANGED }
+
+ it_behaves_like 'work item unique counter'
+ end
end
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index cb645ae3e53..d8f50fa27bb 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -33,8 +33,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
.not_to include(:merge_requests_users)
expect(subject[:usage_activity_by_stage_monthly][:create])
.to include(:merge_requests_users)
- expect(subject[:counts_weekly]).to include(:aggregated_metrics)
- expect(subject[:counts_monthly]).to include(:aggregated_metrics)
end
it 'clears memoized values' do
@@ -608,13 +606,10 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
let_it_be(:disabled) { create(:container_expiration_policy, enabled: false) }
let_it_be(:enabled) { create(:container_expiration_policy, enabled: true) }
- %i[keep_n cadence older_than].each do |attribute|
- ContainerExpirationPolicy.send("#{attribute}_options").keys.each do |value|
- let_it_be("container_expiration_policy_with_#{attribute}_set_to_#{value}") { create(:container_expiration_policy, attribute => value) }
- end
+ ::ContainerExpirationPolicy.older_than_options.keys.each do |value|
+ let_it_be("container_expiration_policy_with_older_than_set_to_#{value}") { create(:container_expiration_policy, older_than: value) }
end
- let_it_be('container_expiration_policy_with_keep_n_set_to_null') { create(:container_expiration_policy, keep_n: nil) }
let_it_be('container_expiration_policy_with_older_than_set_to_null') { create(:container_expiration_policy, older_than: nil) }
let(:inactive_policies) { ::ContainerExpirationPolicy.where(enabled: false) }
@@ -623,27 +618,12 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
subject { described_class.data[:counts] }
it 'gathers usage data' do
- expect(subject[:projects_with_expiration_policy_enabled]).to eq 19
-
- expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_unset]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_set_to_1]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_set_to_5]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_set_to_10]).to eq 13
- expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_set_to_25]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_keep_n_set_to_50]).to eq 1
-
expect(subject[:projects_with_expiration_policy_enabled_with_older_than_unset]).to eq 1
expect(subject[:projects_with_expiration_policy_enabled_with_older_than_set_to_7d]).to eq 1
expect(subject[:projects_with_expiration_policy_enabled_with_older_than_set_to_14d]).to eq 1
expect(subject[:projects_with_expiration_policy_enabled_with_older_than_set_to_30d]).to eq 1
expect(subject[:projects_with_expiration_policy_enabled_with_older_than_set_to_60d]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_older_than_set_to_90d]).to eq 14
-
- expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_1d]).to eq 15
- expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_7d]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_14d]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_1month]).to eq 1
- expect(subject[:projects_with_expiration_policy_enabled_with_cadence_set_to_3month]).to eq 1
+ expect(subject[:projects_with_expiration_policy_enabled_with_older_than_set_to_90d]).to eq 2
end
end
@@ -757,33 +737,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
end
end
- describe '.usage_data_counters' do
- subject { described_class.usage_data_counters }
-
- it { is_expected.to all(respond_to :totals) }
- it { is_expected.to all(respond_to :fallback_totals) }
-
- describe 'the results of calling #totals on all objects in the array' do
- subject { described_class.usage_data_counters.map(&:totals) }
-
- it { is_expected.to all(be_a Hash) }
- it { is_expected.to all(have_attributes(keys: all(be_a Symbol), values: all(be_a Integer))) }
- end
-
- describe 'the results of calling #fallback_totals on all objects in the array' do
- subject { described_class.usage_data_counters.map(&:fallback_totals) }
-
- it { is_expected.to all(be_a Hash) }
- it { is_expected.to all(have_attributes(keys: all(be_a Symbol), values: all(eq(-1)))) }
- end
-
- it 'does not have any conflicts' do
- all_keys = subject.flat_map { |counter| counter.totals.keys }
-
- expect(all_keys.size).to eq all_keys.to_set.size
- end
- end
-
describe '.license_usage_data' do
subject { described_class.license_usage_data }
@@ -1107,10 +1060,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
end
context 'snowplow stats' do
- before do
- stub_feature_flags(usage_data_instrumentation: false)
- end
-
it 'gathers snowplow stats' do
expect(subject[:settings][:snowplow_enabled]).to eq(Gitlab::CurrentSettings.snowplow_enabled?)
expect(subject[:settings][:snowplow_configured_to_gitlab_collector]).to eq(snowplow_gitlab_host?)
@@ -1159,20 +1108,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
let(:project) { build(:project) }
before do
- counter = Gitlab::UsageDataCounters::TrackUniqueEvents
- project_type = Event::TARGET_TYPES[:project]
- wiki = Event::TARGET_TYPES[:wiki]
- design = Event::TARGET_TYPES[:design]
-
- counter.track_event(event_action: :pushed, event_target: project_type, author_id: 1)
- counter.track_event(event_action: :pushed, event_target: project_type, author_id: 1)
- counter.track_event(event_action: :pushed, event_target: project_type, author_id: 2)
- counter.track_event(event_action: :pushed, event_target: project_type, author_id: 3)
- counter.track_event(event_action: :pushed, event_target: project_type, author_id: 4, time: time - 3.days)
- counter.track_event(event_action: :created, event_target: wiki, author_id: 3)
- counter.track_event(event_action: :created, event_target: design, author_id: 3)
- counter.track_event(event_action: :created, event_target: design, author_id: 4)
-
counter = Gitlab::UsageDataCounters::EditorUniqueCounter
counter.track_web_ide_edit_action(author: user1, project: project)
@@ -1191,10 +1126,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
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_design_management: 2,
- action_monthly_active_users_project_repo: 3,
- action_monthly_active_users_wiki_repo: 1,
- action_monthly_active_users_git_write: 4,
action_monthly_active_users_web_ide_edit: 2,
action_monthly_active_users_sfe_edit: 2,
action_monthly_active_users_snippet_editor_edit: 2,
@@ -1234,23 +1165,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
end
end
- describe '.aggregated_metrics_data' do
- it 'uses ::Gitlab::Usage::Metrics::Aggregates::Aggregate methods', :aggregate_failures do
- expected_payload = {
- counts_weekly: { aggregated_metrics: { global_search_gmau: 123 } },
- counts_monthly: { aggregated_metrics: { global_search_gmau: 456 } },
- counts: { aggregate_global_search_gmau: 789 }
- }
-
- expect_next_instance_of(::Gitlab::Usage::Metrics::Aggregates::Aggregate) do |instance|
- expect(instance).to receive(:weekly_data).and_return(global_search_gmau: 123)
- expect(instance).to receive(:monthly_data).and_return(global_search_gmau: 456)
- expect(instance).to receive(:all_time_data).and_return(global_search_gmau: 789)
- end
- expect(described_class.aggregated_metrics_data).to eq(expected_payload)
- end
- end
-
describe '.service_desk_counts' do
subject { described_class.send(:service_desk_counts) }
@@ -1264,110 +1178,6 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
end
end
- describe '.email_campaign_counts' do
- subject { described_class.send(:email_campaign_counts) }
-
- context 'when queries time out' do
- before do
- allow_any_instance_of(ActiveRecord::Relation).to receive(:count).and_raise(ActiveRecord::StatementInvalid)
- allow(Gitlab::ErrorTracking).to receive(:should_raise_for_dev?).and_return(should_raise_for_dev)
- end
-
- context 'with should_raise_for_dev? true' do
- let(:should_raise_for_dev) { true }
-
- it 'raises an error' do
- expect { subject }.to raise_error(ActiveRecord::StatementInvalid)
- end
- end
-
- context 'with should_raise_for_dev? false' do
- let(:should_raise_for_dev) { false }
-
- it 'returns -1 for email campaign data' do
- expected_data = {
- "in_product_marketing_email_create_0_sent" => -1,
- "in_product_marketing_email_create_0_cta_clicked" => -1,
- "in_product_marketing_email_create_1_sent" => -1,
- "in_product_marketing_email_create_1_cta_clicked" => -1,
- "in_product_marketing_email_create_2_sent" => -1,
- "in_product_marketing_email_create_2_cta_clicked" => -1,
- "in_product_marketing_email_team_short_0_sent" => -1,
- "in_product_marketing_email_team_short_0_cta_clicked" => -1,
- "in_product_marketing_email_trial_short_0_sent" => -1,
- "in_product_marketing_email_trial_short_0_cta_clicked" => -1,
- "in_product_marketing_email_admin_verify_0_sent" => -1,
- "in_product_marketing_email_admin_verify_0_cta_clicked" => -1,
- "in_product_marketing_email_verify_0_sent" => -1,
- "in_product_marketing_email_verify_0_cta_clicked" => -1,
- "in_product_marketing_email_verify_1_sent" => -1,
- "in_product_marketing_email_verify_1_cta_clicked" => -1,
- "in_product_marketing_email_verify_2_sent" => -1,
- "in_product_marketing_email_verify_2_cta_clicked" => -1,
- "in_product_marketing_email_trial_0_sent" => -1,
- "in_product_marketing_email_trial_0_cta_clicked" => -1,
- "in_product_marketing_email_trial_1_sent" => -1,
- "in_product_marketing_email_trial_1_cta_clicked" => -1,
- "in_product_marketing_email_trial_2_sent" => -1,
- "in_product_marketing_email_trial_2_cta_clicked" => -1,
- "in_product_marketing_email_team_0_sent" => -1,
- "in_product_marketing_email_team_0_cta_clicked" => -1,
- "in_product_marketing_email_team_1_sent" => -1,
- "in_product_marketing_email_team_1_cta_clicked" => -1,
- "in_product_marketing_email_team_2_sent" => -1,
- "in_product_marketing_email_team_2_cta_clicked" => -1
- }
-
- expect(subject).to eq(expected_data)
- end
- end
- end
-
- context 'when there are entries' do
- before do
- create(:in_product_marketing_email, track: :create, series: 0, cta_clicked_at: Time.zone.now)
- create(:in_product_marketing_email, track: :verify, series: 0)
- end
-
- it 'gathers email campaign data' do
- expected_data = {
- "in_product_marketing_email_create_0_sent" => 1,
- "in_product_marketing_email_create_0_cta_clicked" => 1,
- "in_product_marketing_email_create_1_sent" => 0,
- "in_product_marketing_email_create_1_cta_clicked" => 0,
- "in_product_marketing_email_create_2_sent" => 0,
- "in_product_marketing_email_create_2_cta_clicked" => 0,
- "in_product_marketing_email_team_short_0_sent" => 0,
- "in_product_marketing_email_team_short_0_cta_clicked" => 0,
- "in_product_marketing_email_trial_short_0_sent" => 0,
- "in_product_marketing_email_trial_short_0_cta_clicked" => 0,
- "in_product_marketing_email_admin_verify_0_sent" => 0,
- "in_product_marketing_email_admin_verify_0_cta_clicked" => 0,
- "in_product_marketing_email_verify_0_sent" => 1,
- "in_product_marketing_email_verify_0_cta_clicked" => 0,
- "in_product_marketing_email_verify_1_sent" => 0,
- "in_product_marketing_email_verify_1_cta_clicked" => 0,
- "in_product_marketing_email_verify_2_sent" => 0,
- "in_product_marketing_email_verify_2_cta_clicked" => 0,
- "in_product_marketing_email_trial_0_sent" => 0,
- "in_product_marketing_email_trial_0_cta_clicked" => 0,
- "in_product_marketing_email_trial_1_sent" => 0,
- "in_product_marketing_email_trial_1_cta_clicked" => 0,
- "in_product_marketing_email_trial_2_sent" => 0,
- "in_product_marketing_email_trial_2_cta_clicked" => 0,
- "in_product_marketing_email_team_0_sent" => 0,
- "in_product_marketing_email_team_0_cta_clicked" => 0,
- "in_product_marketing_email_team_1_sent" => 0,
- "in_product_marketing_email_team_1_cta_clicked" => 0,
- "in_product_marketing_email_team_2_sent" => 0,
- "in_product_marketing_email_team_2_cta_clicked" => 0
- }
-
- expect(subject).to eq(expected_data)
- end
- end
- end
-
describe ".with_duration" do
it 'records duration' do
expect(::Gitlab::Usage::ServicePing::LegacyMetricTimingDecorator)
diff --git a/spec/lib/gitlab/utils/strong_memoize_spec.rb b/spec/lib/gitlab/utils/strong_memoize_spec.rb
index cb03797b3d9..236b6d29ba7 100644
--- a/spec/lib/gitlab/utils/strong_memoize_spec.rb
+++ b/spec/lib/gitlab/utils/strong_memoize_spec.rb
@@ -35,16 +35,23 @@ RSpec.describe Gitlab::Utils::StrongMemoize do
end
strong_memoize_attr :method_name_attr
- strong_memoize_attr :different_method_name_attr, :different_member_name_attr
def different_method_name_attr
trace << value
value
end
+ strong_memoize_attr :different_method_name_attr, :different_member_name_attr
- strong_memoize_attr :enabled?
def enabled?
true
end
+ strong_memoize_attr :enabled?
+
+ def method_name_with_args(*args)
+ strong_memoize_with(:method_name_with_args, args) do
+ trace << [value, args]
+ value
+ end
+ end
def trace
@trace ||= []
@@ -141,6 +148,36 @@ RSpec.describe Gitlab::Utils::StrongMemoize do
end
end
+ describe '#strong_memoize_with' do
+ [nil, false, true, 'value', 0, [0]].each do |value|
+ context "with value #{value}" do
+ let(:value) { value }
+
+ it 'only calls the block once' do
+ value0 = object.method_name_with_args(1)
+ value1 = object.method_name_with_args(1)
+ value2 = object.method_name_with_args([2, 3])
+ value3 = object.method_name_with_args([2, 3])
+
+ expect(value0).to eq(value)
+ expect(value1).to eq(value)
+ expect(value2).to eq(value)
+ expect(value3).to eq(value)
+
+ expect(object.trace).to contain_exactly([value, [1]], [value, [[2, 3]]])
+ end
+
+ it 'returns and defines the instance variable for the exact value' do
+ returned_value = object.method_name_with_args(1, 2, 3)
+ memoized_value = object.instance_variable_get(:@method_name_with_args)
+
+ expect(returned_value).to eql(value)
+ expect(memoized_value).to eql({ [[1, 2, 3]] => value })
+ end
+ end
+ end
+ end
+
describe '#strong_memoized?' do
let(:value) { :anything }
@@ -227,5 +264,21 @@ RSpec.describe Gitlab::Utils::StrongMemoize do
expect(klass.public_instance_methods).to include(:public_method)
end
end
+
+ context "when method doesn't exist" do
+ let(:klass) do
+ strong_memoize_class = described_class
+
+ Struct.new(:value) do
+ include strong_memoize_class
+ end
+ end
+
+ subject { klass.strong_memoize_attr(:nonexistent_method) }
+
+ it 'fails when strong-memoizing a nonexistent method' do
+ expect { subject }.to raise_error(NameError, %r{undefined method `nonexistent_method' for class})
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/utils_spec.rb b/spec/lib/gitlab/utils_spec.rb
index d1fdaf7a9db..80b2ec63af9 100644
--- a/spec/lib/gitlab/utils_spec.rb
+++ b/spec/lib/gitlab/utils_spec.rb
@@ -63,9 +63,21 @@ RSpec.describe Gitlab::Utils do
expect(check_path_traversal!('dir/.foo.rb')).to eq('dir/.foo.rb')
end
- it 'does nothing for a non-string' do
+ it 'does nothing for nil' do
expect(check_path_traversal!(nil)).to be_nil
end
+
+ it 'does nothing for safe HashedPath' do
+ expect(check_path_traversal!(Gitlab::HashedPath.new('tmp', root_hash: 1))).to eq '6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b/tmp'
+ end
+
+ it 'raises for unsafe HashedPath' do
+ expect { check_path_traversal!(Gitlab::HashedPath.new('tmp', '..', 'etc', 'passwd', root_hash: 1)) }.to raise_error(/Invalid path/)
+ end
+
+ it 'raises for other non-strings' do
+ expect { check_path_traversal!(%w[/tmp /tmp/../etc/passwd]) }.to raise_error(/Invalid path/)
+ end
end
describe '.check_allowed_absolute_path_and_path_traversal!' do
diff --git a/spec/lib/gitlab/webpack/file_loader_spec.rb b/spec/lib/gitlab/webpack/file_loader_spec.rb
index 6475ef58611..c2e9cd8124d 100644
--- a/spec/lib/gitlab/webpack/file_loader_spec.rb
+++ b/spec/lib/gitlab/webpack/file_loader_spec.rb
@@ -31,8 +31,8 @@ RSpec.describe Gitlab::Webpack::FileLoader do
stub_request(:get, "http://hostname:2000/public_path/#{error_file_path}").to_raise(StandardError)
end
- it "returns content when respondes succesfully" do
- expect(Gitlab::Webpack::FileLoader.load(file_path)).to be(file_contents)
+ it "returns content when responds successfully" do
+ expect(Gitlab::Webpack::FileLoader.load(file_path)).to eq(file_contents)
end
it "raises error when 404" do
diff --git a/spec/lib/grafana/client_spec.rb b/spec/lib/grafana/client_spec.rb
index c233d0b8445..13fe9acc6e9 100644
--- a/spec/lib/grafana/client_spec.rb
+++ b/spec/lib/grafana/client_spec.rb
@@ -54,7 +54,7 @@ RSpec.describe Grafana::Client do
}
exceptions.each do |exception, message|
- context "#{exception}" do
+ context exception.to_s do
before do
stub_request(:get, grafana_api_url).to_raise(exception)
end
diff --git a/spec/lib/object_storage/direct_upload_spec.rb b/spec/lib/object_storage/direct_upload_spec.rb
index 1629aec89f5..c2201fb60ac 100644
--- a/spec/lib/object_storage/direct_upload_spec.rb
+++ b/spec/lib/object_storage/direct_upload_spec.rb
@@ -192,11 +192,28 @@ RSpec.describe ObjectStorage::DirectUpload do
end
end
- shared_examples 'a valid Google upload' do
+ shared_examples 'a valid Google upload' do |use_workhorse_client: true|
+ let(:gocloud_url) { "gs://#{bucket_name}" }
+
it_behaves_like 'a valid upload'
- it 'does not set Workhorse client data' do
- expect(subject.keys).not_to include(:UseWorkhorseClient, :RemoteTempObjectID, :ObjectStorage)
+ if use_workhorse_client
+ it 'enables the Workhorse client' do
+ expect(subject[:UseWorkhorseClient]).to be true
+ expect(subject[:RemoteTempObjectID]).to eq(object_name)
+ expect(subject[:ObjectStorage][:Provider]).to eq('Google')
+ expect(subject[:ObjectStorage][:GoCloudConfig]).to eq({ URL: gocloud_url })
+ end
+ end
+
+ context 'with workhorse_google_client disabled' do
+ before do
+ stub_feature_flags(workhorse_google_client: false)
+ end
+
+ it 'does not set Workhorse client data' do
+ expect(subject.keys).not_to include(:UseWorkhorseClient, :RemoteTempObjectID, :ObjectStorage)
+ end
end
end
@@ -411,28 +428,88 @@ RSpec.describe ObjectStorage::DirectUpload do
end
context 'when Google is used' do
- let(:credentials) do
- {
- provider: 'Google',
- google_storage_access_key_id: 'GOOGLE_ACCESS_KEY_ID',
- google_storage_secret_access_key: 'GOOGLE_SECRET_ACCESS_KEY'
- }
+ let(:consolidated_settings) { true }
+
+ # We need to use fog mocks as using google_application_default
+ # will trigger network requests which we don't want in this spec.
+ # In turn, using fog mocks will don't use a specific storage endpoint,
+ # hence the storage_url with the empty host.
+ let(:storage_url) { 'https:///uploads/' }
+
+ before do
+ Fog.mock!
end
- let(:storage_url) { 'https://storage.googleapis.com/uploads/' }
+ context 'with google_application_default' do
+ let(:credentials) do
+ {
+ provider: 'Google',
+ google_project: 'GOOGLE_PROJECT',
+ google_application_default: true
+ }
+ end
- context 'when length is known' do
- let(:has_length) { true }
+ context 'when length is known' do
+ let(:has_length) { true }
- it_behaves_like 'a valid Google upload'
- it_behaves_like 'a valid upload without multipart data'
+ it_behaves_like 'a valid Google upload'
+ it_behaves_like 'a valid upload without multipart data'
+ end
+
+ context 'when length is unknown' do
+ let(:has_length) { false }
+
+ it_behaves_like 'a valid Google upload'
+ it_behaves_like 'a valid upload without multipart data'
+ end
end
- context 'when length is unknown' do
- let(:has_length) { false }
+ context 'with google_json_key_location' do
+ let(:credentials) do
+ {
+ provider: 'Google',
+ google_project: 'GOOGLE_PROJECT',
+ google_json_key_location: 'LOCATION'
+ }
+ end
+
+ context 'when length is known' do
+ let(:has_length) { true }
+
+ it_behaves_like 'a valid Google upload', use_workhorse_client: true
+ it_behaves_like 'a valid upload without multipart data'
+ end
+
+ context 'when length is unknown' do
+ let(:has_length) { false }
+
+ it_behaves_like 'a valid Google upload', use_workhorse_client: true
+ it_behaves_like 'a valid upload without multipart data'
+ end
+ end
+
+ context 'with google_json_key_string' do
+ let(:credentials) do
+ {
+ provider: 'Google',
+ google_project: 'GOOGLE_PROJECT',
+ google_json_key_string: 'STRING'
+ }
+ end
+
+ context 'when length is known' do
+ let(:has_length) { true }
+
+ it_behaves_like 'a valid Google upload', use_workhorse_client: true
+ it_behaves_like 'a valid upload without multipart data'
+ end
+
+ context 'when length is unknown' do
+ let(:has_length) { false }
- it_behaves_like 'a valid Google upload'
- it_behaves_like 'a valid upload without multipart data'
+ it_behaves_like 'a valid Google upload', use_workhorse_client: true
+ it_behaves_like 'a valid upload without multipart data'
+ end
end
end
@@ -466,4 +543,38 @@ RSpec.describe ObjectStorage::DirectUpload do
end
end
end
+
+ describe '#use_workhorse_google_client?' do
+ let(:direct_upload) { described_class.new(config, object_name, has_length: true) }
+
+ subject { direct_upload.use_workhorse_google_client? }
+
+ context 'with consolidated_settings' do
+ let(:consolidated_settings) { true }
+
+ [
+ { google_application_default: true },
+ { google_json_key_string: 'TEST' },
+ { google_json_key_location: 'PATH' }
+ ].each do |google_config|
+ context "with #{google_config.each_key.first}" do
+ let(:credentials) { google_config }
+
+ it { is_expected.to be_truthy }
+ end
+ end
+
+ context 'without any google setting' do
+ let(:credentials) { {} }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ context 'without consolidated_settings' do
+ let(:consolidated_settings) { true }
+
+ it { is_expected.to be_falsey }
+ end
+ end
end
diff --git a/spec/lib/omni_auth/strategies/jwt_spec.rb b/spec/lib/omni_auth/strategies/jwt_spec.rb
index b29e48b0de5..97547912663 100644
--- a/spec/lib/omni_auth/strategies/jwt_spec.rb
+++ b/spec/lib/omni_auth/strategies/jwt_spec.rb
@@ -51,6 +51,7 @@ RSpec.describe OmniAuth::Strategies::Jwt do
context "when the #{algorithm} algorithm is used" do
let(:algorithm) { algorithm }
let(:secret) do
+ # rubocop:disable Style/CaseLikeIf
if private_key_class == OpenSSL::PKey::RSA
private_key_class.generate(2048)
.to_pem
@@ -61,6 +62,7 @@ RSpec.describe OmniAuth::Strategies::Jwt do
else
private_key_class.new(jwt_config.strategy.secret)
end
+ # rubocop:enable Style/CaseLikeIf
end
let(:private_key) { private_key_class ? private_key_class.new(secret) : secret }
diff --git a/spec/lib/rouge/formatters/html_gitlab_spec.rb b/spec/lib/rouge/formatters/html_gitlab_spec.rb
index 7c92c62e30b..79bfdb262c0 100644
--- a/spec/lib/rouge/formatters/html_gitlab_spec.rb
+++ b/spec/lib/rouge/formatters/html_gitlab_spec.rb
@@ -11,6 +11,16 @@ RSpec.describe Rouge::Formatters::HTMLGitlab do
let(:tokens) { lexer.lex("def hello", continue: false) }
let(:options) { { tag: lang } }
+ context 'when svg and indexes are present to trim' do
+ let(:options) { { tag: lang, ellipsis_indexes: [0], ellipsis_svg: "svg_icon" } }
+
+ it 'returns highlighted ruby code with svg' do
+ code = %q{<span id="LC1" class="line" lang="ruby"><span class="k">def</span> <span class="nf">hello</span><span class="gl-px-2 gl-rounded-base gl-mx-2 gl-bg-gray-100 gl-cursor-help has-tooltip" title="Content has been trimmed">svg_icon</span></span>}
+
+ is_expected.to eq(code)
+ end
+ end
+
it 'returns highlighted ruby code' do
code = %q{<span id="LC1" class="line" lang="ruby"><span class="k">def</span> <span class="nf">hello</span></span>}
diff --git a/spec/lib/sbom/package_url/argument_validator_spec.rb b/spec/lib/sbom/package_url/argument_validator_spec.rb
new file mode 100644
index 00000000000..246da1c0bda
--- /dev/null
+++ b/spec/lib/sbom/package_url/argument_validator_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+
+require_relative '../../../support/shared_contexts/lib/sbom/package_url_shared_contexts'
+
+RSpec.describe Sbom::PackageUrl::ArgumentValidator do
+ let(:mock_package_url) { Struct.new(:type, :namespace, :name, :version, :qualifiers, keyword_init: true) }
+ let(:package) do
+ mock_package_url.new(
+ type: type,
+ namespace: namespace,
+ name: name,
+ version: version,
+ qualifiers: qualifiers
+ )
+ end
+
+ subject(:validate) { described_class.new(package).validate! }
+
+ context 'with valid arguments' do
+ include_context 'with valid purl examples'
+
+ with_them do
+ it 'does not raise error' do
+ expect { validate }.not_to raise_error
+ end
+ end
+ end
+
+ context 'with invalid arguments' do
+ include_context 'with invalid purl examples'
+
+ with_them do
+ it 'raises an ArgumentError' do
+ expect { validate }.to raise_error(ArgumentError)
+ end
+ end
+ end
+
+ context 'with multiple errors' do
+ let(:type) { nil }
+ let(:name) { nil }
+ let(:package) { mock_package_url.new(type: type, name: name) }
+
+ it 'reports all errors' do
+ expect { validate }.to raise_error(ArgumentError, 'Type is required, Name is required')
+ end
+ end
+end
diff --git a/spec/lib/sbom/package_url/decoder_spec.rb b/spec/lib/sbom/package_url/decoder_spec.rb
new file mode 100644
index 00000000000..5b480475b7c
--- /dev/null
+++ b/spec/lib/sbom/package_url/decoder_spec.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+
+require_relative '../../../support/shared_contexts/lib/sbom/package_url_shared_contexts'
+
+RSpec.describe Sbom::PackageUrl::Decoder do
+ describe '#decode' do
+ subject(:decode) { described_class.new(purl).decode! }
+
+ include_context 'with valid purl examples'
+
+ with_them do
+ it do
+ is_expected.to have_attributes(
+ type: type,
+ namespace: namespace,
+ name: name,
+ version: version,
+ qualifiers: qualifiers,
+ subpath: subpath
+ )
+ end
+ end
+
+ context 'when no argument is passed' do
+ let(:purl) { nil }
+
+ it 'raises an error' do
+ expect { decode }.to raise_error(ArgumentError)
+ end
+ end
+
+ context 'when an invalid package URL string is passed' do
+ include_context 'with invalid purl examples'
+
+ with_them do
+ it 'raises an error' do
+ expect { decode }.to raise_error(Sbom::PackageUrl::InvalidPackageUrl)
+ end
+ end
+ end
+
+ context 'when namespace or subpath contains an encoded slash' do
+ where(:purl) do
+ [
+ 'pkg:golang/google.org/golang/genproto#googleapis%2fapi%2fannotations',
+ 'pkg:golang/google.org%2fgolang/genproto#googleapis/api/annotations'
+ ]
+ end
+
+ with_them do
+ it { expect { decode }.to raise_error(Sbom::PackageUrl::InvalidPackageUrl) }
+ end
+ end
+
+ context 'when name contains an encoded slash' do
+ let(:purl) { 'pkg:golang/google.org/golang%2fgenproto#googleapis/api/annotations' }
+
+ it do
+ is_expected.to have_attributes(
+ type: 'golang',
+ namespace: 'google.org',
+ name: 'golang/genproto',
+ version: nil,
+ qualifiers: nil,
+ subpath: 'googleapis/api/annotations'
+ )
+ end
+ end
+
+ context 'with URL encoded segments' do
+ let(:purl) do
+ 'pkg:golang/namespace%21/google.golang.org%20genproto@version%21?k=v%21#googleapis%20api%20annotations'
+ end
+
+ it 'decodes them' do
+ is_expected.to have_attributes(
+ type: 'golang',
+ namespace: 'namespace!',
+ name: 'google.golang.org genproto',
+ version: 'version!',
+ qualifiers: { 'k' => 'v!' },
+ subpath: 'googleapis api annotations'
+ )
+ end
+ end
+
+ context 'when segments contain empty values' do
+ let(:purl) { 'pkg:golang/google.golang.org//.././genproto#googleapis/..//./api/annotations' }
+
+ it 'removes them from the segments' do
+ is_expected.to have_attributes(
+ type: 'golang',
+ namespace: 'google.golang.org/../.', # . and .. are allowed in the namespace, but not the subpath
+ name: 'genproto',
+ version: nil,
+ qualifiers: nil,
+ subpath: 'googleapis/api/annotations'
+ )
+ end
+ end
+
+ context 'when qualifiers have no value' do
+ let(:purl) { 'pkg:rpm/fedora/curl@7.50.3-1.fc25?arch=i386&distro=fedora-25&foo=&bar=' }
+
+ it 'they are ignored' do
+ is_expected.to have_attributes(
+ type: 'rpm',
+ namespace: 'fedora',
+ name: 'curl',
+ version: '7.50.3-1.fc25',
+ qualifiers: { 'arch' => 'i386',
+ 'distro' => 'fedora-25' },
+ subpath: nil
+ )
+ end
+ end
+ end
+end
diff --git a/spec/lib/sbom/package_url/encoder_spec.rb b/spec/lib/sbom/package_url/encoder_spec.rb
new file mode 100644
index 00000000000..bdbd61636b5
--- /dev/null
+++ b/spec/lib/sbom/package_url/encoder_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+
+require_relative '../../../support/shared_contexts/lib/sbom/package_url_shared_contexts'
+
+RSpec.describe Sbom::PackageUrl::Encoder do
+ describe '#encode' do
+ let(:package) do
+ ::Sbom::PackageUrl.new(
+ type: type,
+ namespace: namespace,
+ name: name,
+ version: version,
+ qualifiers: qualifiers,
+ subpath: subpath
+ )
+ end
+
+ subject(:encode) { described_class.new(package).encode }
+
+ include_context 'with valid purl examples'
+
+ with_them do
+ it { is_expected.to eq(canonical_purl) }
+ end
+ end
+end
diff --git a/spec/lib/sbom/package_url/normalizer_spec.rb b/spec/lib/sbom/package_url/normalizer_spec.rb
new file mode 100644
index 00000000000..bbc2bd3ca13
--- /dev/null
+++ b/spec/lib/sbom/package_url/normalizer_spec.rb
@@ -0,0 +1,76 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+
+require_relative '../../../support/shared_contexts/lib/sbom/package_url_shared_contexts'
+
+RSpec.describe Sbom::PackageUrl::Normalizer do
+ shared_examples 'name normalization' do
+ context 'with bitbucket url' do
+ let(:type) { 'bitbucket' }
+ let(:text) { 'Purl_Spec' }
+
+ it 'downcases text' do
+ is_expected.to eq('purl_spec')
+ end
+ end
+
+ context 'with github url' do
+ let(:type) { 'github' }
+ let(:text) { 'Purl_Spec' }
+
+ it 'downcases text' do
+ is_expected.to eq('purl_spec')
+ end
+ end
+
+ context 'with pypi url' do
+ let(:type) { 'pypi' }
+ let(:text) { 'Purl_Spec' }
+
+ it 'downcases text and replaces underscores' do
+ is_expected.to eq('purl-spec')
+ end
+ end
+
+ context 'with other urls' do
+ let(:type) { 'npm' }
+ let(:text) { 'Purl_Spec' }
+
+ it 'does not change the text' do
+ is_expected.to eq(text)
+ end
+ end
+ end
+
+ describe '#normalize_name' do
+ subject(:normalize_name) { described_class.new(type: type, text: text).normalize_name }
+
+ it_behaves_like 'name normalization'
+
+ context 'when text is nil' do
+ let(:type) { 'npm' }
+ let(:text) { nil }
+
+ it 'raises an error' do
+ expect { normalize_name }.to raise_error(ArgumentError, 'Name is required')
+ end
+ end
+ end
+
+ describe '#normalize_namespace' do
+ subject(:normalize_namespace) { described_class.new(type: type, text: text).normalize_namespace }
+
+ it_behaves_like 'name normalization'
+
+ context 'when text is nil' do
+ let(:type) { 'npm' }
+ let(:text) { nil }
+
+ it 'allows nil values' do
+ expect(normalize_namespace).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/lib/sbom/package_url_spec.rb b/spec/lib/sbom/package_url_spec.rb
new file mode 100644
index 00000000000..6760b0a68e5
--- /dev/null
+++ b/spec/lib/sbom/package_url_spec.rb
@@ -0,0 +1,162 @@
+# frozen_string_literal: true
+
+# MIT License
+#
+# Copyright (c) 2021 package-url
+# Portions Copyright 2022 Gitlab B.V.
+#
+# 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.
+
+require 'fast_spec_helper'
+require 'rspec-parameterized'
+
+require_relative '../../support/helpers/next_instance_of'
+require_relative '../../support/shared_contexts/lib/sbom/package_url_shared_contexts'
+
+RSpec.describe Sbom::PackageUrl do
+ include NextInstanceOf
+
+ describe '#initialize' do
+ subject do
+ described_class.new(
+ type: type,
+ namespace: namespace,
+ name: name,
+ version: version,
+ qualifiers: qualifiers,
+ subpath: subpath
+ )
+ end
+
+ context 'with well-formed arguments' do
+ include_context 'with valid purl examples'
+
+ with_them do
+ it do
+ is_expected.to have_attributes(
+ type: type,
+ namespace: namespace,
+ name: name,
+ version: version,
+ qualifiers: qualifiers,
+ subpath: subpath
+ )
+ end
+ end
+ end
+
+ context 'when no arguments are given' do
+ it { expect { described_class.new }.to raise_error(ArgumentError) }
+ end
+
+ context 'when parameters are invalid' do
+ include_context 'with invalid purl examples'
+
+ with_them do
+ it 'raises an ArgumentError' do
+ expect { subject }.to raise_error(ArgumentError)
+ end
+ end
+ end
+
+ describe 'normalization' do
+ it 'downcases provided type component' do
+ purl = described_class.new(type: 'EXAMPLE', name: 'test')
+
+ expect(purl.type).to eq('example')
+ expect(purl.name).to eq('test')
+ end
+
+ it 'does not down provided name component' do
+ purl = described_class.new(type: 'example', name: 'TEST')
+
+ expect(purl.type).to eq('example')
+ expect(purl.name).to eq('TEST')
+ end
+ end
+ end
+
+ describe '#parse' do
+ let(:url) { 'pkg:gem/rails@6.1.6.1' }
+
+ subject(:parse) { described_class.parse(url) }
+
+ it 'delegates parsing to the decoder' do
+ expect_next_instance_of(described_class::Decoder, url) do |decoder|
+ expect(decoder).to receive(:decode!)
+ end
+
+ parse
+ end
+ end
+
+ describe '#to_h' do
+ let(:package) do
+ described_class.new(
+ type: type,
+ namespace: namespace,
+ name: name,
+ version: version,
+ qualifiers: qualifiers,
+ subpath: subpath
+ )
+ end
+
+ subject(:to_h) { package.to_h }
+
+ include_context 'with valid purl examples'
+
+ with_them do
+ it do
+ is_expected.to eq(
+ {
+ scheme: 'pkg',
+ type: type,
+ namespace: namespace,
+ name: name,
+ version: version,
+ qualifiers: qualifiers,
+ subpath: subpath
+ }
+ )
+ end
+ end
+ end
+
+ describe '#to_s' do
+ let(:package) do
+ described_class.new(
+ type: 'npm',
+ namespace: nil,
+ name: 'lodash',
+ version: nil,
+ qualifiers: nil,
+ subpath: nil
+ )
+ end
+
+ it 'delegates to_s to the encoder' do
+ expect_next_instance_of(described_class::Encoder, package) do |encoder|
+ expect(encoder).to receive(:encode)
+ end
+
+ package.to_s
+ end
+ end
+end
diff --git a/spec/lib/serializers/symbolized_json_spec.rb b/spec/lib/serializers/symbolized_json_spec.rb
deleted file mode 100644
index b9217854d9a..00000000000
--- a/spec/lib/serializers/symbolized_json_spec.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-require 'fast_spec_helper'
-require 'oj'
-
-RSpec.describe Serializers::SymbolizedJson do
- describe '.dump' do
- let(:obj) { { key: "value" } }
-
- subject { described_class.dump(obj) }
-
- it 'returns a hash' do
- is_expected.to eq(obj)
- end
- end
-
- describe '.load' do
- let(:data_string) { '{"key":"value","variables":[{"key":"VAR1","value":"VALUE1"}]}' }
- let(:data_hash) { Gitlab::Json.parse(data_string) }
-
- context 'when loading a hash' do
- subject { described_class.load(data_hash) }
-
- it 'decodes a string' do
- is_expected.to be_a(Hash)
- end
-
- it 'allows to access with symbols' do
- expect(subject[:key]).to eq('value')
- expect(subject[:variables].first[:key]).to eq('VAR1')
- end
- end
-
- context 'when loading a nil' do
- subject { described_class.load(nil) }
-
- it 'returns nil' do
- is_expected.to be_nil
- end
- end
- end
-end
diff --git a/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb b/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb
index 2da7d324708..64408ac3b88 100644
--- a/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/infrastructure_menu_spec.rb
@@ -23,6 +23,52 @@ RSpec.describe Sidebars::Projects::Menus::InfrastructureMenu do
expect(subject.render?).to be true
end
end
+
+ describe 'behavior based on access level setting' do
+ using RSpec::Parameterized::TableSyntax
+
+ let_it_be(:project) { create(:project) }
+ let(:enabled) { Featurable::PRIVATE }
+ let(:disabled) { Featurable::DISABLED }
+
+ where(:operations_access_level, :infrastructure_access_level, :render) do
+ ref(:disabled) | ref(:enabled) | true
+ ref(:disabled) | ref(:disabled) | false
+ ref(:enabled) | ref(:enabled) | true
+ ref(:enabled) | ref(:disabled) | false
+ end
+
+ with_them do
+ it 'renders based on the infrastructure access level' do
+ project.project_feature.update!(operations_access_level: operations_access_level)
+ project.project_feature.update!(infrastructure_access_level: infrastructure_access_level)
+
+ expect(subject.render?).to be render
+ end
+ end
+
+ context 'when `split_operations_visibility_permissions` feature flag is disabled' do
+ before do
+ stub_feature_flags(split_operations_visibility_permissions: false)
+ end
+
+ where(:operations_access_level, :infrastructure_access_level, :render) do
+ ref(:disabled) | ref(:enabled) | false
+ ref(:disabled) | ref(:disabled) | false
+ ref(:enabled) | ref(:enabled) | true
+ ref(:enabled) | ref(:disabled) | true
+ end
+
+ with_them do
+ it 'renders based on the operations access level' do
+ project.project_feature.update!(operations_access_level: operations_access_level)
+ project.project_feature.update!(infrastructure_access_level: infrastructure_access_level)
+
+ expect(subject.render?).to be render
+ end
+ end
+ end
+ end
end
describe '#link' do
diff --git a/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb b/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb
index bd0904b9db2..f6a8dd7367d 100644
--- a/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb
+++ b/spec/lib/sidebars/projects/menus/monitor_menu_spec.rb
@@ -102,19 +102,5 @@ RSpec.describe Sidebars::Projects::Menus::MonitorMenu do
it_behaves_like 'access rights checks'
end
-
- describe 'Product Analytics' do
- let(:item_id) { :product_analytics }
-
- specify { is_expected.not_to be_nil }
-
- describe 'when feature flag :product_analytics is disabled' do
- specify do
- stub_feature_flags(product_analytics: false)
-
- is_expected.to be_nil
- end
- end
- end
end
end
diff --git a/spec/lib/unnested_in_filters/rewriter_spec.rb b/spec/lib/unnested_in_filters/rewriter_spec.rb
index 21bab42c95c..fe34fba579b 100644
--- a/spec/lib/unnested_in_filters/rewriter_spec.rb
+++ b/spec/lib/unnested_in_filters/rewriter_spec.rb
@@ -12,6 +12,12 @@ RSpec.describe UnnestedInFilters::Rewriter do
describe '#rewrite?' do
subject(:rewrite?) { rewriter.rewrite? }
+ context 'when a join table is receiving an IN list query' do
+ let(:relation) { User.joins(:status).where(status: { message: %w[foo bar] }).order(id: :desc).limit(2) }
+
+ it { is_expected.to be_falsey }
+ end
+
context 'when the given relation does not have an `IN` predicate' do
let(:relation) { User.where(username: 'user') }
@@ -170,6 +176,91 @@ RSpec.describe UnnestedInFilters::Rewriter do
end
end
+ context 'when the combined attributes include the primary key' do
+ let(:relation) { User.where(user_type: %i(support_bot alert_bot)).order(id: :desc).limit(2) }
+
+ let(:expected_query) do
+ <<~SQL
+ SELECT
+ "users".*
+ FROM
+ "users"
+ WHERE
+ "users"."id" IN (
+ SELECT
+ "users"."id"
+ FROM
+ unnest('{1,2}' :: smallint []) AS "user_types"("user_type"),
+ LATERAL (
+ SELECT
+ "users"."user_type",
+ "users"."id"
+ FROM
+ "users"
+ WHERE
+ (users."user_type" = "user_types"."user_type")
+ ORDER BY
+ "users"."id" DESC
+ LIMIT
+ 2
+ ) AS users
+ ORDER BY
+ "users"."id" DESC
+ LIMIT
+ 2
+ )
+ ORDER BY
+ "users"."id" DESC
+ LIMIT
+ 2
+ SQL
+ end
+
+ it 'changes the query' do
+ expect(issued_query.gsub(/\s/, '')).to start_with(expected_query.gsub(/\s/, ''))
+ end
+ end
+
+ context 'when a join table is receiving an IN list query' do
+ let(:relation) { User.joins(:status).where(status: { message: %w[foo bar] }).order(id: :desc).limit(2) }
+
+ let(:expected_query) do
+ <<~SQL
+ SELECT
+ "users".*
+ FROM
+ "users"
+ WHERE
+ "users"."id" IN (
+ SELECT
+ "users"."id"
+ FROM
+ LATERAL (
+ SELECT
+ message,
+ "users"."id"
+ FROM
+ "users"
+ INNER JOIN "user_statuses" "status" ON "status"."user_id" = "users"."id"
+ WHERE
+ "status"."message" IN ('foo', 'bar')
+ ORDER BY
+ "users"."id" DESC
+ LIMIT 2) AS users
+ ORDER BY
+ "users"."id" DESC
+ LIMIT 2)
+ ORDER BY
+ "users"."id" DESC
+ LIMIT 2
+ SQL
+ end
+
+ it 'does not rewrite the in statement for the joined table' do
+ expect(issued_query.gsub(/\s/, '')).to start_with(expected_query.gsub(/\s/, ''))
+ end
+ end
+
describe 'logging' do
subject(:load_reload) { rewriter.rewrite }
diff --git a/spec/mailers/emails/identity_verification_spec.rb b/spec/mailers/emails/identity_verification_spec.rb
new file mode 100644
index 00000000000..57ae95cc1ee
--- /dev/null
+++ b/spec/mailers/emails/identity_verification_spec.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Emails::IdentityVerification do
+ include EmailSpec::Matchers
+ include_context 'gitlab email notification'
+
+ describe 'verification_instructions_email' do
+ let_it_be(:user) { build_stubbed(:user) }
+ let_it_be(:token) { '123456' }
+
+ subject do
+ Notify.verification_instructions_email(user.email, token: token)
+ end
+
+ it_behaves_like 'an email sent from GitLab'
+
+ it 'is sent to the user' do
+ is_expected.to deliver_to user.email
+ end
+
+ it 'has the correct subject' do
+ is_expected.to have_subject s_('IdentityVerification|Verify your identity')
+ end
+
+ it 'has the mailgun suppression bypass header' do
+ is_expected.to have_header 'X-Mailgun-Suppressions-Bypass', 'true'
+ end
+
+ it 'includes the token' do
+ is_expected.to have_body_text token
+ end
+
+ it 'includes the expiration time' do
+ expires_in_minutes = Users::EmailVerification::ValidateTokenService::TOKEN_VALID_FOR_MINUTES
+
+ is_expected.to have_body_text format(s_('IdentityVerification|Your verification code expires after '\
+ '%{expires_in_minutes} minutes.'), expires_in_minutes: expires_in_minutes)
+ end
+ end
+end
diff --git a/spec/mailers/emails/releases_spec.rb b/spec/mailers/emails/releases_spec.rb
index d1d7f5e6d6a..e8ca9533256 100644
--- a/spec/mailers/emails/releases_spec.rb
+++ b/spec/mailers/emails/releases_spec.rb
@@ -16,6 +16,7 @@ RSpec.describe Emails::Releases do
subject { Notify.new_release_email(user.id, release) }
it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'an email with X-GitLab headers containing project details'
context 'when the release has a name' do
it 'shows the correct subject' do
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index 1f53c472c5c..5733e892d2a 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -750,7 +750,7 @@ RSpec.describe Notify do
before_all do
private_project.add_guest(recipient)
- note.update!(note: "#{private_issue.to_reference(full: true)}")
+ note.update!(note: private_issue.to_reference(full: true).to_s)
end
let(:html_part) { subject.body.parts.last.to_s }
diff --git a/spec/migrations/20210818185845_backfill_projects_with_coverage_spec.rb b/spec/migrations/20210818185845_backfill_projects_with_coverage_spec.rb
deleted file mode 100644
index 13a6aa5413e..00000000000
--- a/spec/migrations/20210818185845_backfill_projects_with_coverage_spec.rb
+++ /dev/null
@@ -1,71 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require_migration!
-
-RSpec.describe BackfillProjectsWithCoverage, :suppress_gitlab_schemas_validate_connection do
- let(:projects) { table(:projects) }
- let(:ci_pipelines) { table(:ci_pipelines) }
- let(:ci_daily_build_group_report_results) { table(:ci_daily_build_group_report_results) }
- let(:group) { table(:namespaces).create!(name: 'user', path: 'user') }
- let(:project_1) { projects.create!(namespace_id: group.id) }
- let(:project_2) { projects.create!(namespace_id: group.id) }
- let(:pipeline_1) { ci_pipelines.create!(project_id: project_1.id) }
- let(:pipeline_2) { ci_pipelines.create!(project_id: project_2.id) }
- let(:pipeline_3) { ci_pipelines.create!(project_id: project_2.id) }
-
- describe '#up' do
- before do
- stub_const("#{described_class}::BATCH_SIZE", 2)
- stub_const("#{described_class}::SUB_BATCH_SIZE", 1)
-
- ci_daily_build_group_report_results.create!(
- id: 1,
- project_id: project_1.id,
- date: 3.days.ago,
- last_pipeline_id: pipeline_1.id,
- ref_path: 'main',
- group_name: 'rspec',
- data: { coverage: 95.0 },
- default_branch: true,
- group_id: group.id
- )
-
- ci_daily_build_group_report_results.create!(
- id: 2,
- project_id: project_2.id,
- date: 2.days.ago,
- last_pipeline_id: pipeline_2.id,
- ref_path: 'main',
- group_name: 'rspec',
- data: { coverage: 95.0 },
- default_branch: true,
- group_id: group.id
- )
-
- ci_daily_build_group_report_results.create!(
- id: 3,
- project_id: project_2.id,
- date: 1.day.ago,
- last_pipeline_id: pipeline_3.id,
- ref_path: 'test_branch',
- group_name: 'rspec',
- data: { coverage: 95.0 },
- default_branch: false,
- group_id: group.id
- )
- end
-
- it 'schedules BackfillProjectsWithCoverage background jobs', :aggregate_failures do
- Sidekiq::Testing.fake! do
- freeze_time do
- migrate!
-
- expect(described_class::MIGRATION).to be_scheduled_delayed_migration(2.minutes, 1, 2, 1)
- expect(described_class::MIGRATION).to be_scheduled_delayed_migration(4.minutes, 3, 3, 1)
- expect(BackgroundMigrationWorker.jobs.size).to eq(2)
- end
- end
- end
- end
-end
diff --git a/spec/migrations/20220107064845_populate_vulnerability_reads_spec.rb b/spec/migrations/20220107064845_populate_vulnerability_reads_spec.rb
index ece971a50c9..063a51227dd 100644
--- a/spec/migrations/20220107064845_populate_vulnerability_reads_spec.rb
+++ b/spec/migrations/20220107064845_populate_vulnerability_reads_spec.rb
@@ -29,7 +29,7 @@ RSpec.describe PopulateVulnerabilityReads, :migration do
project_id: project.id,
external_type: 'uuid-v5',
external_id: 'uuid-v5',
- fingerprint: Digest::SHA1.hexdigest("#{vulnerability.id}"),
+ fingerprint: Digest::SHA1.hexdigest(vulnerability.id.to_s),
name: 'Identifier for UUIDv5')
create_finding!(
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 614044657ec..174cfda1a46 100644
--- a/spec/migrations/20220921144258_remove_orphan_group_token_users_spec.rb
+++ b/spec/migrations/20220921144258_remove_orphan_group_token_users_spec.rb
@@ -34,11 +34,7 @@ RSpec.describe RemoveOrphanGroupTokenUsers, :migration, :sidekiq_inline do
let(:members) { table(:members) }
let(:namespaces) { table(:namespaces) }
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
- end
-
- it 'removes orphan project bot and its tokens', :aggregate_failures do
+ it 'initiates orphan project bot removal', :aggregate_failures do
expect(DeleteUserWorker)
.to receive(:perform_async)
.with(orphan_bot.id, orphan_bot.id, skip_authorization: true)
@@ -46,7 +42,8 @@ RSpec.describe RemoveOrphanGroupTokenUsers, :migration, :sidekiq_inline do
migrate!
- expect(users.count).to eq 2
+ expect(Users::GhostUserMigration.where(user: orphan_bot)).to be_exists
+ expect(users.count).to eq 3
expect(personal_access_tokens.count).to eq 2
expect(personal_access_tokens.find_by(user_id: orphan_bot.id)).to eq nil
end
diff --git a/spec/migrations/20221018050323_add_objective_and_keyresult_to_work_item_types_spec.rb b/spec/migrations/20221018050323_add_objective_and_keyresult_to_work_item_types_spec.rb
new file mode 100644
index 00000000000..4de897802b9
--- /dev/null
+++ b/spec/migrations/20221018050323_add_objective_and_keyresult_to_work_item_types_spec.rb
@@ -0,0 +1,66 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe AddObjectiveAndKeyresultToWorkItemTypes, :migration do
+ include MigrationHelpers::WorkItemTypesHelper
+
+ let_it_be(:work_item_types) { table(:work_item_types) }
+
+ let(:base_types) do
+ {
+ issue: 0,
+ incident: 1,
+ test_case: 2,
+ requirement: 3,
+ task: 4,
+ objective: 5,
+ key_result: 6
+ }
+ end
+
+ after(:all) do
+ # Make sure base types are recreated after running the migration
+ # because migration specs are not run in a transaction
+ reset_work_item_types
+ end
+
+ it 'skips creating both objective & keyresult type record if it already exists' do
+ reset_db_state_prior_to_migration
+ work_item_types.find_or_create_by!(name: 'Key Result', namespace_id: nil, base_type: base_types[:key_result],
+ icon_name: 'issue-type-keyresult')
+ work_item_types.find_or_create_by!(name: 'Objective', namespace_id: nil, base_type: base_types[:objective],
+ icon_name: 'issue-type-objective')
+
+ expect do
+ migrate!
+ end.to not_change(work_item_types, :count)
+ end
+
+ it 'adds both objective & keyresult to base work item types' do
+ reset_db_state_prior_to_migration
+
+ expect do
+ migrate!
+ end.to change(work_item_types, :count).from(5).to(7)
+
+ expect(work_item_types.all.pluck(:base_type)).to include(base_types[:objective])
+ expect(work_item_types.all.pluck(:base_type)).to include(base_types[:key_result])
+ end
+
+ def reset_db_state_prior_to_migration
+ # Database needs to be in a similar state as when this migration was created
+ work_item_types.delete_all
+ work_item_types.find_or_create_by!(name: 'Issue', namespace_id: nil, base_type: base_types[:issue],
+ icon_name: 'issue-type-issue')
+ work_item_types.find_or_create_by!(name: 'Incident', namespace_id: nil, base_type: base_types[:incident],
+ icon_name: 'issue-type-incident')
+ work_item_types.find_or_create_by!(name: 'Test Case', namespace_id: nil, base_type: base_types[:test_case],
+ icon_name: 'issue-type-test-case')
+ work_item_types.find_or_create_by!(name: 'Requirement', namespace_id: nil, base_type: base_types[:requirement],
+ icon_name: 'issue-type-requirements')
+ work_item_types.find_or_create_by!(name: 'Task', namespace_id: nil, base_type: base_types[:task],
+ icon_name: 'issue-type-task')
+ end
+end
diff --git a/spec/migrations/20221018062308_schedule_backfill_project_namespace_details_spec.rb b/spec/migrations/20221018062308_schedule_backfill_project_namespace_details_spec.rb
new file mode 100644
index 00000000000..4dd6d5757ce
--- /dev/null
+++ b/spec/migrations/20221018062308_schedule_backfill_project_namespace_details_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe ScheduleBackfillProjectNamespaceDetails, schema: 20221018062308 do
+ context 'when on gitlab.com' do
+ let_it_be(:background_migration) { described_class::MIGRATION }
+ let_it_be(:migration) { described_class.new }
+
+ before do
+ migration.up
+ end
+
+ describe '#up' do
+ it 'schedules background jobs for each batch of projects' do
+ expect(background_migration).to(
+ have_scheduled_batched_migration(
+ table_name: :projects,
+ column_name: :id,
+ interval: described_class::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
+ migration.down
+
+ expect(described_class::MIGRATION).not_to have_scheduled_batched_migration
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20221018193635_ensure_task_note_renaming_background_migration_finished_spec.rb b/spec/migrations/20221018193635_ensure_task_note_renaming_background_migration_finished_spec.rb
new file mode 100644
index 00000000000..ea95c34674e
--- /dev/null
+++ b/spec/migrations/20221018193635_ensure_task_note_renaming_background_migration_finished_spec.rb
@@ -0,0 +1,91 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe EnsureTaskNoteRenamingBackgroundMigrationFinished, :migration do
+ let(:batched_migrations) { table(:batched_background_migrations) }
+ let(:batch_failed_status) { 2 }
+ let(:batch_finalized_status) { 3 }
+
+ let_it_be(:migration) { described_class::MIGRATION }
+
+ describe '#up' do
+ shared_examples 'finalizes the migration' do
+ it 'finalizes the migration' do
+ expect do
+ migrate!
+
+ task_renaming_migration.reload
+ failed_job.reload
+ end.to change(task_renaming_migration, :status).from(task_renaming_migration.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!(:task_renaming_migration) do
+ batched_migrations.create!(
+ job_class_name: 'RenameTaskSystemNoteToChecklistItem',
+ table_name: :system_note_metadata,
+ column_name: :id,
+ job_arguments: [],
+ interval: 2.minutes,
+ min_value: 1,
+ max_value: 2,
+ batch_size: 1000,
+ sub_batch_size: 200,
+ 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: task_renaming_migration.id,
+ status: batch_failed_status,
+ min_value: 1,
+ max_value: 10,
+ attempts: 2,
+ batch_size: 100,
+ sub_batch_size: 10
+ )
+ end
+
+ before do
+ task_renaming_migration.update!(status: status)
+ end
+
+ it_behaves_like 'finalizes the migration'
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20221021145820_create_routing_table_for_builds_metadata_v2_spec.rb b/spec/migrations/20221021145820_create_routing_table_for_builds_metadata_v2_spec.rb
new file mode 100644
index 00000000000..48a00df430d
--- /dev/null
+++ b/spec/migrations/20221021145820_create_routing_table_for_builds_metadata_v2_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe CreateRoutingTableForBuildsMetadataV2, :migration do
+ let_it_be(:migration) { described_class.new }
+
+ describe '#up' do
+ context 'when the table is already partitioned' do
+ before do
+ # `convert_table_to_first_list_partition` checks if it's being executed
+ # inside a transaction, but we're using transactional fixtures here so we
+ # need to tell it that it's not inside a transaction.
+ # We toggle the behavior depending on how many transactions we have open
+ # instead of just returning `false` because the migration could have the
+ # DDL transaction enabled.
+ #
+ open_transactions = ActiveRecord::Base.connection.open_transactions
+ allow(migration).to receive(:transaction_open?) do
+ ActiveRecord::Base.connection.open_transactions > open_transactions
+ end
+
+ migration.convert_table_to_first_list_partition(
+ table_name: :ci_builds_metadata,
+ partitioning_column: :partition_id,
+ parent_table_name: :p_ci_builds_metadata,
+ initial_partitioning_value: 100)
+ end
+
+ it 'skips the migration' do
+ expect { migrate! }.not_to raise_error
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20221025043930_change_default_value_on_password_last_changed_at_to_user_details_spec.rb b/spec/migrations/20221025043930_change_default_value_on_password_last_changed_at_to_user_details_spec.rb
new file mode 100644
index 00000000000..4d6f06eb146
--- /dev/null
+++ b/spec/migrations/20221025043930_change_default_value_on_password_last_changed_at_to_user_details_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe ChangeDefaultValueOnPasswordLastChangedAtToUserDetails, :migration do
+ let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') }
+ let(:users) { table(:users) }
+ let(:user_details) { table(:user_details) }
+
+ it 'correctly migrates up and down' do
+ user = create_user!(email: '1234@abc')
+ user_details.create!(user_id: user.id, provisioned_by_group_id: namespace.id)
+
+ expect(UserDetail.find_by(user_id: user.id).password_last_changed_at).to be_nil
+
+ migrate!
+
+ user = create_user!(email: 'abc@1234')
+ user_details.create!(user_id: user.id, provisioned_by_group_id: namespace.id)
+
+ expect(UserDetail.find_by(user_id: user.id).password_last_changed_at).not_to be_nil
+ end
+
+ private
+
+ def create_user!(name: "Example User", email: "user@example.com", user_type: nil)
+ users.create!(
+ name: name,
+ email: email,
+ username: name,
+ projects_limit: 0,
+ user_type: user_type,
+ confirmed_at: Time.current
+ )
+ end
+end
diff --git a/spec/migrations/20221028022627_add_index_on_password_last_changed_at_to_user_details_spec.rb b/spec/migrations/20221028022627_add_index_on_password_last_changed_at_to_user_details_spec.rb
new file mode 100644
index 00000000000..5f8467f9307
--- /dev/null
+++ b/spec/migrations/20221028022627_add_index_on_password_last_changed_at_to_user_details_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe AddIndexOnPasswordLastChangedAtToUserDetails, :migration do
+ let(:index_name) { 'index_user_details_on_password_last_changed_at' }
+
+ it 'correctly migrates up and down' do
+ expect(subject).not_to be_index_exists_by_name(:user_details, index_name)
+
+ migrate!
+
+ expect(subject).to be_index_exists_by_name(:user_details, index_name)
+ end
+end
diff --git a/spec/migrations/20221101032521_add_default_preferred_language_to_application_settings_spec.rb b/spec/migrations/20221101032521_add_default_preferred_language_to_application_settings_spec.rb
new file mode 100644
index 00000000000..3ae4287f3c4
--- /dev/null
+++ b/spec/migrations/20221101032521_add_default_preferred_language_to_application_settings_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe AddDefaultPreferredLanguageToApplicationSettings do
+ let(:application_setting) { table(:application_settings).create! }
+
+ describe "#up" do
+ it 'allows to read default_preferred_language field' do
+ migrate!
+
+ expect(application_setting.attributes.keys).to include('default_preferred_language')
+ expect(application_setting.default_preferred_language).to eq 'en'
+ end
+ end
+
+ describe "#down" do
+ it 'deletes default_preferred_language field' do
+ migrate!
+ schema_migrate_down!
+
+ expect(application_setting.attributes.keys).not_to include('default_preferred_language')
+ end
+ end
+end
diff --git a/spec/migrations/20221101032600_add_text_limit_to_default_preferred_language_on_application_settings_spec.rb b/spec/migrations/20221101032600_add_text_limit_to_default_preferred_language_on_application_settings_spec.rb
new file mode 100644
index 00000000000..e0370e48db6
--- /dev/null
+++ b/spec/migrations/20221101032600_add_text_limit_to_default_preferred_language_on_application_settings_spec.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe AddTextLimitToDefaultPreferredLanguageOnApplicationSettings do
+ let(:application_setting) { table(:application_settings).create! }
+ let(:too_long_text) { SecureRandom.alphanumeric(described_class::MAXIMUM_LIMIT + 1) }
+
+ subject { application_setting.update_column(:default_preferred_language, too_long_text) }
+
+ describe "#up" do
+ it 'adds text limit to default_preferred_language' do
+ migrate!
+
+ expect { subject }.to raise_error ActiveRecord::StatementInvalid
+ end
+ end
+
+ describe "#down" do
+ it 'deletes text limit to default_preferred_language' do
+ migrate!
+ schema_migrate_down!
+
+ expect { subject }.not_to raise_error
+ end
+ end
+end
diff --git a/spec/migrations/20221102090940_create_next_ci_partitions_record_spec.rb b/spec/migrations/20221102090940_create_next_ci_partitions_record_spec.rb
new file mode 100644
index 00000000000..c55e4bcfba7
--- /dev/null
+++ b/spec/migrations/20221102090940_create_next_ci_partitions_record_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe CreateNextCiPartitionsRecord, migration: :gitlab_ci do
+ let(:migration) { described_class.new }
+ let(:partitions) { table(:ci_partitions) }
+
+ describe '#up' do
+ context 'when on sass' do
+ before do
+ allow(Gitlab).to receive(:com?).and_return(true)
+ end
+
+ it 'creates next partitions record and resets the sequence' do
+ expect { migrate! }
+ .to change { partitions.where(id: 101).any? }
+ .from(false).to(true)
+
+ expect { partitions.create! }.not_to raise_error
+ end
+ end
+
+ context 'when self-managed' do
+ before do
+ allow(Gitlab).to receive(:com?).and_return(false)
+ end
+
+ it 'does not create records' do
+ expect { migrate! }.not_to change(partitions, :count)
+ end
+ end
+ end
+
+ describe '#down' do
+ context 'when on sass' do
+ before do
+ allow(Gitlab).to receive(:com?).and_return(true)
+ end
+
+ it 'removes the record' do
+ migrate!
+
+ expect { migration.down }
+ .to change { partitions.where(id: 101).any? }
+ .from(true).to(false)
+ end
+ end
+
+ context 'when self-managed' do
+ before do
+ allow(Gitlab).to receive(:com?).and_return(true, false)
+ end
+
+ it 'does not remove the record' do
+ expect { migrate! }.to change(partitions, :count).by(1)
+
+ expect { migration.down }.not_to change(partitions, :count)
+ end
+ end
+ end
+end
diff --git a/spec/migrations/20221102090943_create_second_partition_for_builds_metadata_spec.rb b/spec/migrations/20221102090943_create_second_partition_for_builds_metadata_spec.rb
new file mode 100644
index 00000000000..99754d609ed
--- /dev/null
+++ b/spec/migrations/20221102090943_create_second_partition_for_builds_metadata_spec.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe CreateSecondPartitionForBuildsMetadata, :migration do
+ let(:migration) { described_class.new }
+ let(:partitions) { table(:ci_partitions) }
+
+ describe '#up' do
+ context 'when on sass' do
+ before do
+ allow(Gitlab).to receive(:com?).and_return(true)
+ end
+
+ it 'creates a new partition' do
+ expect { migrate! }.to change { partitions_count }.by(1)
+ end
+ end
+
+ context 'when self-managed' do
+ before do
+ allow(Gitlab).to receive(:com?).and_return(false)
+ end
+
+ it 'does not create the partition' do
+ expect { migrate! }.not_to change { partitions_count }
+ end
+ end
+ end
+
+ describe '#down' do
+ context 'when on sass' do
+ before do
+ allow(Gitlab).to receive(:com?).and_return(true)
+ end
+
+ it 'removes the partition' do
+ migrate!
+
+ expect { migration.down }.to change { partitions_count }.by(-1)
+ end
+ end
+
+ context 'when self-managed' do
+ before do
+ allow(Gitlab).to receive(:com?).and_return(false)
+ end
+
+ it 'does not change the partitions count' do
+ migrate!
+
+ expect { migration.down }.not_to change { partitions_count }
+ end
+ end
+ end
+
+ def partitions_count
+ Gitlab::Database::PostgresPartition.for_parent_table(:p_ci_builds_metadata).size
+ end
+end
diff --git a/spec/migrations/cleanup_vulnerability_state_transitions_with_same_from_state_to_state_spec.rb b/spec/migrations/cleanup_vulnerability_state_transitions_with_same_from_state_to_state_spec.rb
new file mode 100644
index 00000000000..92ece81ffc8
--- /dev/null
+++ b/spec/migrations/cleanup_vulnerability_state_transitions_with_same_from_state_to_state_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe CleanupVulnerabilityStateTransitionsWithSameFromStateToState, :migration do
+ let_it_be(:namespace) { table(:namespaces).create!(name: 'namespace', type: 'Group', path: 'namespace') }
+ let_it_be(:user) { table(:users).create!(email: 'author@example.com', username: 'author', projects_limit: 10) }
+ let_it_be(:project) do
+ table(:projects).create!(
+ path: 'project',
+ namespace_id: namespace.id,
+ project_namespace_id: namespace.id
+ )
+ end
+
+ let_it_be(:vulnerability) do
+ table(:vulnerabilities).create!(
+ project_id: project.id,
+ author_id: user.id,
+ title: 'test',
+ severity: 7,
+ confidence: 7,
+ report_type: 0
+ )
+ end
+
+ let_it_be(:state_transitions) { table(:vulnerability_state_transitions) }
+
+ let!(:state_transition_with_no_state_change) do
+ state_transitions.create!(
+ vulnerability_id: vulnerability.id,
+ from_state: 2,
+ to_state: 2
+ )
+ end
+
+ let!(:state_transition_with_state_change) do
+ state_transitions.create!(
+ vulnerability_id: vulnerability.id,
+ from_state: 1,
+ to_state: 2
+ )
+ end
+
+ it 'deletes state transitions with no state change' do
+ expect { migrate! }.to change(state_transitions, :count).from(2).to(1)
+ end
+end
diff --git a/spec/migrations/delete_migrate_shared_vulnerability_scanners_spec.rb b/spec/migrations/delete_migrate_shared_vulnerability_scanners_spec.rb
new file mode 100644
index 00000000000..259b175cd19
--- /dev/null
+++ b/spec/migrations/delete_migrate_shared_vulnerability_scanners_spec.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+require_migration!
+
+RSpec.describe DeleteMigrateSharedVulnerabilityScanners, :migration do
+ let(:batched_background_migrations) { table(:batched_background_migrations) }
+ let(:batched_background_migration_jobs) { table(:batched_background_migration_jobs) }
+
+ let(:migration) do
+ batched_background_migrations.create!(created_at: Time.zone.now,
+ updated_at: Time.zone.now,
+ min_value: 1,
+ max_value: 1,
+ batch_size: described_class::BATCH_SIZE,
+ sub_batch_size: 100,
+ interval: 300,
+ status: 3,
+ job_class_name: described_class::MIGRATION,
+ batch_class_name: "PrimaryKeyBatchingStrategy",
+ table_name: described_class::TABLE_NAME,
+ column_name: described_class::BATCH_COLUMN,
+ job_arguments: [],
+ pause_ms: 100,
+ max_batch_size: 1000,
+ gitlab_schema: "gitlab_main")
+ end
+
+ let(:jobs) do
+ Array.new(10) do
+ batched_background_migration_jobs.create!(batched_background_migration_id: migration.id,
+ created_at: Time.zone.now,
+ updated_at: Time.zone.now,
+ min_value: 1,
+ max_value: 1,
+ batch_size: 1,
+ sub_batch_size: 1,
+ status: 0,
+ attempts: 0,
+ metrics: {},
+ pause_ms: 100)
+ end
+ end
+
+ describe "#up" do
+ it "deletes jobs" do
+ expect { migrate! }.to change(batched_background_migration_jobs, :count).from(jobs.count).to(0)
+ end
+
+ it "deletes the migration" do
+ expect { migrate! }.to change { batched_background_migrations.find_by(id: migration.id) }.from(migration).to(nil)
+ end
+
+ context "when background migration does not exist" do
+ before do
+ migration.destroy!
+ end
+
+ it "does not delete jobs" do
+ expect { migrate! }.not_to change(batched_background_migration_jobs, :count)
+ end
+
+ it "does not delete the migration" do
+ expect { migrate! }.not_to change { batched_background_migrations.find_by(id: migration.id) }
+ end
+ end
+ end
+end
diff --git a/spec/migrations/finalize_invalid_member_cleanup_spec.rb b/spec/migrations/finalize_invalid_member_cleanup_spec.rb
new file mode 100644
index 00000000000..a29a89c2396
--- /dev/null
+++ b/spec/migrations/finalize_invalid_member_cleanup_spec.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe FinalizeInvalidMemberCleanup, :migration do
+ let(:batched_migrations) { table(:batched_background_migrations) }
+
+ let_it_be(:migration) { described_class::MIGRATION }
+
+ describe '#up' do
+ shared_examples 'finalizes the migration' do
+ it 'finalizes the migration' do
+ allow_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationRunner) do |runner|
+ expect(runner).to receive(:finalize).with('DestroyInvalidMembers', :members, :id, [])
+ end
+ 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!(:destroy_invalid_member_migration) do
+ batched_migrations.create!(
+ job_class_name: 'DestroyInvalidMembers',
+ table_name: :members,
+ column_name: :id,
+ job_arguments: [],
+ interval: 2.minutes,
+ min_value: 1,
+ max_value: 2,
+ batch_size: 1000,
+ sub_batch_size: 200,
+ 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' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:status, :description) do
+ 0 | 'paused'
+ 1 | 'active'
+ 4 | 'failed'
+ 5 | 'finalizing'
+ end
+
+ with_them do
+ before do
+ destroy_invalid_member_migration.update!(status: status)
+ end
+
+ it_behaves_like 'finalizes the migration'
+ end
+ end
+ end
+ end
+end
diff --git a/spec/migrations/queue_backfill_user_details_fields_spec.rb b/spec/migrations/queue_backfill_user_details_fields_spec.rb
new file mode 100644
index 00000000000..388ac6d1bce
--- /dev/null
+++ b/spec/migrations/queue_backfill_user_details_fields_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueueBackfillUserDetailsFields do
+ let_it_be(:batched_migration) { described_class::MIGRATION }
+
+ it 'schedules a new batched migration' do
+ reversible_migration do |migration|
+ migration.before -> {
+ expect(batched_migration).not_to have_scheduled_batched_migration
+ }
+
+ migration.after -> {
+ expect(batched_migration).to have_scheduled_batched_migration(
+ table_name: :users,
+ column_name: :id,
+ interval: described_class::INTERVAL
+ )
+ }
+ end
+ end
+end
diff --git a/spec/migrations/queue_populate_projects_star_count_spec.rb b/spec/migrations/queue_populate_projects_star_count_spec.rb
new file mode 100644
index 00000000000..848136d8005
--- /dev/null
+++ b/spec/migrations/queue_populate_projects_star_count_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe QueuePopulateProjectsStarCount do
+ let_it_be(: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
+ )
+ }
+ end
+ end
+end
diff --git a/spec/migrations/recount_epic_cache_counts_spec.rb b/spec/migrations/recount_epic_cache_counts_spec.rb
new file mode 100644
index 00000000000..56aa96cb40c
--- /dev/null
+++ b/spec/migrations/recount_epic_cache_counts_spec.rb
@@ -0,0 +1,32 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe RecountEpicCacheCounts, :migration 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: :epics,
+ column_name: :id,
+ interval: described_class::DELAY_INTERVAL,
+ batch_size: described_class::BATCH_SIZE,
+ max_batch_size: described_class::MAX_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/reschedule_migrate_shared_vulnerability_scanners_spec.rb b/spec/migrations/reschedule_migrate_shared_vulnerability_scanners_spec.rb
new file mode 100644
index 00000000000..e8253f39c68
--- /dev/null
+++ b/spec/migrations/reschedule_migrate_shared_vulnerability_scanners_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+require_migration!
+
+RSpec.describe RescheduleMigrateSharedVulnerabilityScanners, :migration do
+ include Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers
+
+ def connection
+ ApplicationRecord.connection
+ end
+
+ describe "#up" do
+ before do
+ migrate!
+ end
+
+ it "schedules" do
+ expect(described_class::MIGRATION).to have_scheduled_batched_migration(
+ table_name: described_class::TABLE_NAME,
+ column_name: described_class::BATCH_COLUMN,
+ interval: described_class::DELAY_INTERVAL,
+ batch_size: described_class::BATCH_SIZE,
+ max_batch_size: described_class::BATCH_SIZE,
+ sub_batch_size: described_class::SUB_BATCH_SIZE,
+ gitlab_schema: :gitlab_main
+ )
+ end
+ end
+
+ describe '#down' do
+ before do
+ schema_migrate_down!
+ end
+
+ it "deletes" do
+ expect(described_class::MIGRATION).not_to have_scheduled_batched_migration
+ end
+ end
+end
diff --git a/spec/migrations/sanitize_confidential_note_todos_spec.rb b/spec/migrations/sanitize_confidential_note_todos_spec.rb
new file mode 100644
index 00000000000..00dece82cc1
--- /dev/null
+++ b/spec/migrations/sanitize_confidential_note_todos_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe SanitizeConfidentialNoteTodos 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: :notes,
+ column_name: :id,
+ interval: described_class::DELAY_INTERVAL,
+ batch_size: described_class::BATCH_SIZE,
+ max_batch_size: described_class::MAX_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/schedule_migrate_shared_vulnerability_scanners_spec.rb b/spec/migrations/schedule_migrate_shared_vulnerability_scanners_spec.rb
deleted file mode 100644
index f00d6568b67..00000000000
--- a/spec/migrations/schedule_migrate_shared_vulnerability_scanners_spec.rb
+++ /dev/null
@@ -1,59 +0,0 @@
-# frozen_string_literal: true
-
-require "spec_helper"
-
-require_migration!
-
-RSpec.describe ScheduleMigrateSharedVulnerabilityScanners, :migration do
- describe "#up" do
- before do
- migrate!
- end
-
- it "schedules" do
- expect(described_class::MIGRATION).to have_scheduled_batched_migration(
- table_name: described_class::TABLE_NAME,
- column_name: described_class::BATCH_COLUMN,
- interval: described_class::DELAY_INTERVAL,
- batch_size: described_class::BATCH_SIZE,
- max_batch_size: described_class::BATCH_SIZE,
- sub_batch_size: described_class::SUB_BATCH_SIZE,
- gitlab_schema: :gitlab_main
- )
- end
-
- describe "ID range" do
- let(:expected_range) do
- { min_value: described_class::BATCH_MIN_VALUE,
- max_value: described_class::BATCH_MAX_VALUE }
- end
-
- subject do
- Gitlab::Database::BackgroundMigration::BatchedMigration
- .for_configuration(:gitlab_main,
- described_class::MIGRATION,
- described_class::TABLE_NAME,
- described_class::BATCH_COLUMN,
- [])
- end
-
- it "is set" do
- # The `have_scheduled_batched_migration` matcher accepts the
- # `batch_min_value` and `batch_max_value` keywords. However the respective
- # column names are `min_value` and `max_value`. Hence the matcher cannot
- # be used in this case, as it asserts the wrong attributes.
- expect(subject).to all(have_attributes(expected_range))
- end
- end
- end
-
- describe '#down' do
- before do
- schema_migrate_down!
- end
-
- it "deletes" do
- expect(described_class::MIGRATION).not_to have_scheduled_batched_migration
- end
- end
-end
diff --git a/spec/migrations/set_email_confirmation_setting_from_send_user_confirmation_email_setting_spec.rb b/spec/migrations/set_email_confirmation_setting_from_send_user_confirmation_email_setting_spec.rb
new file mode 100644
index 00000000000..761c0ef2fdb
--- /dev/null
+++ b/spec/migrations/set_email_confirmation_setting_from_send_user_confirmation_email_setting_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe SetEmailConfirmationSettingFromSendUserConfirmationEmailSetting do
+ let(:migration) { described_class.new }
+ let(:application_settings_table) { table(:application_settings) }
+
+ describe '#up' do
+ context "when 'send_user_confirmation_email' is set to 'true'" do
+ it "updates 'email_confirmation_setting' to '2' (hard)" do
+ application_settings_table.create!(send_user_confirmation_email: true, email_confirmation_setting: 0)
+
+ migration.up
+
+ expect(application_settings_table.last.email_confirmation_setting).to eq 2
+ end
+ end
+
+ context "when 'send_user_confirmation_email' is set to 'false'" do
+ it "updates 'email_confirmation_setting' to '0' (off)" do
+ application_settings_table.create!(send_user_confirmation_email: false, email_confirmation_setting: 0)
+
+ migration.up
+
+ expect(application_settings_table.last.email_confirmation_setting).to eq 0
+ end
+ end
+ end
+
+ describe '#down' do
+ it "updates 'email_confirmation_setting' to default value: '0' (off)" do
+ application_settings_table.create!(send_user_confirmation_email: true, email_confirmation_setting: 2)
+
+ migration.down
+
+ expect(application_settings_table.last.email_confirmation_setting).to eq 0
+ end
+ end
+end
diff --git a/spec/migrations/sync_new_amount_used_for_ci_namespace_monthly_usages_spec.rb b/spec/migrations/sync_new_amount_used_for_ci_namespace_monthly_usages_spec.rb
new file mode 100644
index 00000000000..9a17f375f82
--- /dev/null
+++ b/spec/migrations/sync_new_amount_used_for_ci_namespace_monthly_usages_spec.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe SyncNewAmountUsedForCiNamespaceMonthlyUsages, migration: :gitlab_ci do
+ let(:namespace_usages) { table(:ci_namespace_monthly_usages) }
+
+ before do
+ # Disabling the trigger temporarily to allow records being created with out-of-sync
+ # `new_amount_used` and `amount_used`. This will simulate existing records before
+ # we add the trigger.
+ ActiveRecord::Base.connection
+ .execute("ALTER TABLE ci_namespace_monthly_usages DISABLE TRIGGER sync_namespaces_amount_used_columns")
+
+ this_month = Time.now.utc.beginning_of_month
+ last_month = 1.month.ago.utc.beginning_of_month
+ last_year = 1.year.ago.utc.beginning_of_month
+
+ namespace_usages.create!(namespace_id: 1, date: last_year)
+ namespace_usages.create!(namespace_id: 1, date: this_month, amount_used: 10, new_amount_used: 0)
+ namespace_usages.create!(namespace_id: 1, date: last_month, amount_used: 20, new_amount_used: 0)
+
+ namespace_usages.create!(namespace_id: 2, date: last_year)
+ namespace_usages.create!(namespace_id: 2, date: this_month, amount_used: 30, new_amount_used: 0)
+ namespace_usages.create!(namespace_id: 2, date: last_month, amount_used: 40, new_amount_used: 0)
+
+ ActiveRecord::Base.connection
+ .execute("ALTER TABLE ci_namespace_monthly_usages ENABLE TRIGGER sync_namespaces_amount_used_columns")
+ end
+
+ it 'updates `new_amount_used` with values from `amount_used`' do
+ expect(namespace_usages.where(new_amount_used: 0).count).to eq(6)
+
+ migrate!
+
+ expect(namespace_usages.where(new_amount_used: 0).count).to eq(2)
+ expect(namespace_usages.order(:id).pluck(:new_amount_used))
+ .to contain_exactly(0, 0, 10, 20, 30, 40)
+ end
+end
diff --git a/spec/migrations/sync_new_amount_used_for_ci_project_monthly_usages_spec.rb b/spec/migrations/sync_new_amount_used_for_ci_project_monthly_usages_spec.rb
new file mode 100644
index 00000000000..8d45f1107ea
--- /dev/null
+++ b/spec/migrations/sync_new_amount_used_for_ci_project_monthly_usages_spec.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+require_migration!
+
+RSpec.describe SyncNewAmountUsedForCiProjectMonthlyUsages, migration: :gitlab_ci do
+ let(:project_usages) { table(:ci_project_monthly_usages) }
+
+ before do
+ # Disabling the trigger temporarily to allow records being created with out-of-sync
+ # `new_amount_used` and `amount_used`. This will simulate existing records before
+ # we add the trigger.
+ ActiveRecord::Base.connection
+ .execute("ALTER TABLE ci_project_monthly_usages DISABLE TRIGGER sync_projects_amount_used_columns")
+
+ this_month = Time.now.utc.beginning_of_month
+ last_month = 1.month.ago.utc.beginning_of_month
+ last_year = 1.year.ago.utc.beginning_of_month
+
+ project_usages.create!(project_id: 1, date: last_year)
+ project_usages.create!(project_id: 1, date: this_month, amount_used: 10, new_amount_used: 0)
+ project_usages.create!(project_id: 1, date: last_month, amount_used: 20, new_amount_used: 0)
+
+ project_usages.create!(project_id: 2, date: last_year)
+ project_usages.create!(project_id: 2, date: this_month, amount_used: 30, new_amount_used: 0)
+ project_usages.create!(project_id: 2, date: last_month, amount_used: 40, new_amount_used: 0)
+
+ ActiveRecord::Base.connection
+ .execute("ALTER TABLE ci_project_monthly_usages ENABLE TRIGGER sync_projects_amount_used_columns")
+ end
+
+ it 'updates `new_amount_used` with values from `amount_used`' do
+ expect(project_usages.where(new_amount_used: 0).count).to eq(6)
+
+ migrate!
+
+ expect(project_usages.where(new_amount_used: 0).count).to eq(2)
+ expect(project_usages.order(:id).pluck(:new_amount_used))
+ .to contain_exactly(0, 0, 10, 20, 30, 40)
+ end
+end
diff --git a/spec/models/active_session_spec.rb b/spec/models/active_session_spec.rb
index 5d316f7cff2..3665f13015e 100644
--- a/spec/models/active_session_spec.rb
+++ b/spec/models/active_session_spec.rb
@@ -260,7 +260,7 @@ RSpec.describe ActiveSession, :clean_gitlab_redis_sessions do
redis.set("session:gitlab:#{rack_session.private_id}", '')
redis.set(session_key, serialized_session)
- redis.sadd(lookup_key, active_session_lookup_key)
+ redis.sadd?(lookup_key, active_session_lookup_key)
end
end
@@ -338,7 +338,7 @@ RSpec.describe ActiveSession, :clean_gitlab_redis_sessions do
session_private_id = Rack::Session::SessionId.new(session_public_id).private_id
active_session = ActiveSession.new(session_private_id: session_private_id)
redis.set(key_name(user.id, session_private_id), dump_session(active_session))
- redis.sadd(lookup_key, session_private_id)
+ redis.sadd?(lookup_key, session_private_id)
end
# setup for unrelated user
@@ -347,7 +347,7 @@ RSpec.describe ActiveSession, :clean_gitlab_redis_sessions do
active_session = ActiveSession.new(session_private_id: session_private_id)
redis.set(key_name(unrelated_user_id, session_private_id), dump_session(active_session))
- redis.sadd(described_class.lookup_key_name(unrelated_user_id), session_private_id)
+ redis.sadd?(described_class.lookup_key_name(unrelated_user_id), session_private_id)
end
end
@@ -372,7 +372,7 @@ RSpec.describe ActiveSession, :clean_gitlab_redis_sessions do
Gitlab::Redis::Sessions.with do |redis|
redis.set(key_name(user.id, impersonated_session_id),
dump_session(ActiveSession.new(session_id: Rack::Session::SessionId.new(impersonated_session_id), is_impersonated: true)))
- redis.sadd(lookup_key, impersonated_session_id)
+ redis.sadd?(lookup_key, impersonated_session_id)
end
expect { ActiveSession.destroy_all_but_current(user, request.session) }.to change { ActiveSession.session_ids_for_user(user.id).size }.from(3).to(2)
@@ -418,8 +418,7 @@ RSpec.describe ActiveSession, :clean_gitlab_redis_sessions do
it 'removes obsolete lookup entries' do
Gitlab::Redis::Sessions.with do |redis|
redis.set(session_key, '')
- redis.sadd(lookup_key, current_session_id)
- redis.sadd(lookup_key, '59822c7d9fcdfa03725eff41782ad97d')
+ redis.sadd(lookup_key, [current_session_id, '59822c7d9fcdfa03725eff41782ad97d'])
end
ActiveSession.cleanup(user)
@@ -445,7 +444,7 @@ RSpec.describe ActiveSession, :clean_gitlab_redis_sessions do
key_name(user.id, number),
dump_session(ActiveSession.new(session_id: number.to_s, updated_at: number.days.ago))
)
- redis.sadd(lookup_key, number.to_s)
+ redis.sadd?(lookup_key, number.to_s)
end
end
end
@@ -477,7 +476,7 @@ RSpec.describe ActiveSession, :clean_gitlab_redis_sessions do
it 'removes obsolete lookup entries even without active session' do
Gitlab::Redis::Sessions.with do |redis|
- redis.sadd(lookup_key, "#{max_number_of_sessions_plus_two + 1}")
+ redis.sadd?(lookup_key, (max_number_of_sessions_plus_two + 1).to_s)
end
ActiveSession.cleanup(user)
@@ -534,7 +533,7 @@ RSpec.describe ActiveSession, :clean_gitlab_redis_sessions do
key_name(user.id, number),
dump_session(ActiveSession.new(session_private_id: number.to_s, updated_at: number.days.ago))
)
- redis.sadd(lookup_key, number.to_s)
+ redis.sadd?(lookup_key, number.to_s)
end
end
end
@@ -601,11 +600,10 @@ RSpec.describe ActiveSession, :clean_gitlab_redis_sessions do
dump_session(ActiveSession.new(session_id: number.to_s, updated_at: number.days.ago))
)
- redis.sadd(lookup_key, number.to_s)
+ redis.sadd?(lookup_key, number.to_s)
end
- redis.sadd(lookup_key, (active_count + 1).to_s)
- redis.sadd(lookup_key, (active_count + 2).to_s)
+ redis.sadd?(lookup_key, [(active_count + 1).to_s, (active_count + 2).to_s])
end
end
diff --git a/spec/models/alert_management/http_integration_spec.rb b/spec/models/alert_management/http_integration_spec.rb
index f88a66a7c27..b453b3a82e0 100644
--- a/spec/models/alert_management/http_integration_spec.rb
+++ b/spec/models/alert_management/http_integration_spec.rb
@@ -13,6 +13,11 @@ RSpec.describe AlertManagement::HttpIntegration do
it { is_expected.to belong_to(:project) }
end
+ describe 'default values' do
+ it { expect(described_class.new.endpoint_identifier).to be_present }
+ it { expect(described_class.new(endpoint_identifier: 'test').endpoint_identifier).to eq('test') }
+ end
+
describe 'validations' do
it { is_expected.to validate_presence_of(:project) }
it { is_expected.to validate_presence_of(:name) }
@@ -124,10 +129,6 @@ RSpec.describe AlertManagement::HttpIntegration do
end
context 'when unsaved' do
- context 'when unassigned' do
- it_behaves_like 'valid token'
- end
-
context 'when assigned' do
include_context 'assign token', 'random_token'
diff --git a/spec/models/appearance_spec.rb b/spec/models/appearance_spec.rb
index 2817e177d28..9d84279a75e 100644
--- a/spec/models/appearance_spec.rb
+++ b/spec/models/appearance_spec.rb
@@ -10,6 +10,20 @@ RSpec.describe Appearance do
it { is_expected.to have_many(:uploads) }
+ describe 'default values' do
+ subject(:appearance) { described_class.new }
+
+ it { expect(appearance.title).to eq('') }
+ it { expect(appearance.description).to eq('') }
+ it { expect(appearance.new_project_guidelines).to eq('') }
+ it { expect(appearance.profile_image_guidelines).to eq('') }
+ it { expect(appearance.header_message).to eq('') }
+ it { expect(appearance.footer_message).to eq('') }
+ it { expect(appearance.message_background_color).to eq('#E75E40') }
+ it { expect(appearance.message_font_color).to eq('#FFFFFF') }
+ it { expect(appearance.email_header_and_footer_enabled).to eq(false) }
+ end
+
describe '#single_appearance_row' do
it 'adds an error when more than 1 row exists' do
create(:appearance)
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 77bb6b502b5..fd86a784b2d 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -17,6 +17,14 @@ RSpec.describe ApplicationSetting do
it { expect(setting.uuid).to be_present }
it { expect(setting).to have_db_column(:auto_devops_enabled) }
+ describe 'default values' do
+ subject(:setting) { described_class.new }
+
+ it { expect(setting.id).to eq(1) }
+ it { expect(setting.repository_storages_weighted).to eq({}) }
+ it { expect(setting.kroki_formats).to eq({}) }
+ end
+
describe 'validations' do
let(:http) { 'http://example.com' }
let(:https) { 'https://example.com' }
@@ -203,6 +211,9 @@ RSpec.describe ApplicationSetting do
it { is_expected.to allow_value([]).for(:valid_runner_registrars) }
it { is_expected.to allow_value(%w(project group)).for(:valid_runner_registrars) }
+ it { is_expected.to allow_value(http).for(:jira_connect_proxy_url) }
+ it { is_expected.to allow_value(https).for(:jira_connect_proxy_url) }
+
context 'when deactivate_dormant_users is enabled' do
before do
stub_application_setting(deactivate_dormant_users: true)
@@ -261,6 +272,7 @@ RSpec.describe ApplicationSetting do
end
it { is_expected.not_to allow_value('http://localhost:9000').for(:grafana_url) }
+ it { is_expected.not_to allow_value('http://localhost:9000').for(:jira_connect_proxy_url) }
end
context 'with invalid grafana URL' do
@@ -1121,6 +1133,11 @@ RSpec.describe ApplicationSetting do
it { is_expected.to validate_presence_of(:error_tracking_api_url) }
end
end
+
+ context 'for default_preferred_language' 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
end
context 'restrict creating duplicates' do
diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb
index b0bfdabe13c..8fdc9852f6e 100644
--- a/spec/models/broadcast_message_spec.rb
+++ b/spec/models/broadcast_message_spec.rb
@@ -27,6 +27,13 @@ RSpec.describe BroadcastMessage do
it { is_expected.to validate_inclusion_of(:target_access_levels).in_array(described_class::ALLOWED_TARGET_ACCESS_LEVELS) }
end
+ describe 'default values' do
+ subject(:message) { described_class.new }
+
+ it { expect(message.color).to eq('#E75E40') }
+ it { expect(message.font).to eq('#FFFFFF') }
+ end
+
shared_examples 'time constrainted' do |broadcast_type|
it 'returns message if time match' do
message = create(:broadcast_message, broadcast_type: broadcast_type)
diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb
index 44a6bec0130..df24c92149d 100644
--- a/spec/models/ci/bridge_spec.rb
+++ b/spec/models/ci/bridge_spec.rb
@@ -27,6 +27,8 @@ RSpec.describe Ci::Bridge do
it_behaves_like 'has ID tokens', :ci_bridge
+ it_behaves_like 'a retryable job'
+
it 'has one downstream pipeline' do
expect(bridge).to have_one(:sourced_pipeline)
expect(bridge).to have_one(:downstream_pipeline)
@@ -35,18 +37,8 @@ RSpec.describe Ci::Bridge do
describe '#retryable?' do
let(:bridge) { create(:ci_bridge, :success) }
- it 'returns true' do
- expect(bridge.retryable?).to eq(true)
- end
-
- context 'without ci_recreate_downstream_pipeline ff' do
- before do
- stub_feature_flags(ci_recreate_downstream_pipeline: false)
- end
-
- it 'returns false' do
- expect(bridge.retryable?).to eq(false)
- end
+ it 'returns false' do
+ expect(bridge.retryable?).to eq(false)
end
end
@@ -204,6 +196,8 @@ RSpec.describe Ci::Bridge do
end
describe '#downstream_variables' do
+ subject(:downstream_variables) { bridge.downstream_variables }
+
it 'returns variables that are going to be passed downstream' do
expect(bridge.downstream_variables)
.to include(key: 'BRIDGE', value: 'cross')
@@ -309,7 +303,7 @@ RSpec.describe Ci::Bridge do
end
context 'when the pipeline runs from a pipeline schedule' do
- let(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project ) }
+ let(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project) }
let(:pipeline) { create(:ci_pipeline, pipeline_schedule: pipeline_schedule) }
let(:options) do
@@ -328,6 +322,79 @@ RSpec.describe Ci::Bridge do
end
end
end
+
+ context 'when using raw variables' do
+ let(:options) do
+ {
+ trigger: {
+ project: 'my/project',
+ branch: 'master',
+ forward: { yaml_variables: true,
+ pipeline_variables: true }.compact
+ }
+ }
+ end
+
+ let(:yaml_variables) do
+ [
+ {
+ key: 'VAR6',
+ value: 'value6 $VAR1'
+ },
+ {
+ key: 'VAR7',
+ value: 'value7 $VAR1',
+ raw: true
+ }
+ ]
+ end
+
+ let(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project) }
+ let(:pipeline) { create(:ci_pipeline, pipeline_schedule: pipeline_schedule) }
+
+ before do
+ create(:ci_pipeline_variable, pipeline: pipeline, key: 'VAR1', value: 'value1')
+ create(:ci_pipeline_variable, pipeline: pipeline, key: 'VAR2', value: 'value2 $VAR1')
+ create(:ci_pipeline_variable, pipeline: pipeline, key: 'VAR3', value: 'value3 $VAR1', raw: true)
+
+ pipeline_schedule.variables.create!(key: 'VAR4', value: 'value4 $VAR1')
+ pipeline_schedule.variables.create!(key: 'VAR5', value: 'value5 $VAR1', raw: true)
+
+ bridge.yaml_variables.concat(yaml_variables)
+ end
+
+ it 'expands variables according to their raw attributes' do
+ expect(downstream_variables).to contain_exactly(
+ { key: 'BRIDGE', value: 'cross' },
+ { key: 'VAR1', value: 'value1' },
+ { key: 'VAR2', value: 'value2 value1' },
+ { key: 'VAR3', value: 'value3 $VAR1', raw: true },
+ { key: 'VAR4', value: 'value4 value1' },
+ { key: 'VAR5', value: 'value5 $VAR1', raw: true },
+ { key: 'VAR6', value: 'value6 value1' },
+ { key: 'VAR7', value: 'value7 $VAR1', raw: true }
+ )
+ end
+
+ context 'when the FF ci_raw_variables_in_yaml_config is disabled' do
+ before do
+ stub_feature_flags(ci_raw_variables_in_yaml_config: false)
+ end
+
+ it 'ignores the raw attribute' do
+ expect(downstream_variables).to contain_exactly(
+ { key: 'BRIDGE', value: 'cross' },
+ { key: 'VAR1', value: 'value1' },
+ { key: 'VAR2', value: 'value2 value1' },
+ { key: 'VAR3', value: 'value3 value1' },
+ { key: 'VAR4', value: 'value4 value1' },
+ { key: 'VAR5', value: 'value5 value1' },
+ { key: 'VAR6', value: 'value6 value1' },
+ { key: 'VAR7', value: 'value7 value1' }
+ )
+ end
+ end
+ end
end
describe 'metadata support' do
diff --git a/spec/models/ci/build_metadata_spec.rb b/spec/models/ci/build_metadata_spec.rb
index 16cff72db64..e728ce0f474 100644
--- a/spec/models/ci/build_metadata_spec.rb
+++ b/spec/models/ci/build_metadata_spec.rb
@@ -182,4 +182,36 @@ RSpec.describe Ci::BuildMetadata do
end
end
end
+
+ describe 'routing table switch' do
+ context 'with ff disabled' do
+ before do
+ stub_feature_flags(ci_partitioning_use_ci_builds_metadata_routing_table: false)
+ end
+
+ it 'uses the legacy table' do
+ expect(described_class.table_name).to eq('ci_builds_metadata')
+ end
+ end
+
+ context 'with ff enabled' do
+ before do
+ stub_feature_flags(ci_partitioning_use_ci_builds_metadata_routing_table: true)
+ end
+
+ it 'uses the routing table' do
+ expect(described_class.table_name).to eq('p_ci_builds_metadata')
+ end
+ end
+ end
+
+ context 'jsonb fields serialization' do
+ it 'changing other fields does not change config_options' do
+ expect { metadata.id = metadata.id }.not_to change(metadata, :changes)
+ end
+
+ it 'accessing config_options does not change it' do
+ expect { metadata.config_options }.not_to change(metadata, :changes)
+ end
+ end
end
diff --git a/spec/models/ci/build_runner_session_spec.rb b/spec/models/ci/build_runner_session_spec.rb
index ed5ed456d7b..9bb8a1bd626 100644
--- a/spec/models/ci/build_runner_session_spec.rb
+++ b/spec/models/ci/build_runner_session_spec.rb
@@ -72,7 +72,7 @@ RSpec.describe Ci::BuildRunnerSession, model: true do
let(:specification) { subject.service_specification(service: service, port: port, path: path, subprotocols: subprotocols) }
it 'returns service proxy url' do
- expect(specification[:url]).to eq "https://localhost/proxy/#{service}/#{port}/#{path}"
+ expect(specification[:url]).to eq "https://gitlab.example.com/proxy/#{service}/#{port}/#{path}"
end
it 'returns default service proxy websocket subprotocol' do
@@ -89,7 +89,7 @@ RSpec.describe Ci::BuildRunnerSession, model: true do
let(:port) { nil }
it 'uses the default port name' do
- expect(specification[:url]).to eq "https://localhost/proxy/#{service}/default_port/#{path}"
+ expect(specification[:url]).to eq "https://gitlab.example.com/proxy/#{service}/default_port/#{path}"
end
end
@@ -97,7 +97,7 @@ RSpec.describe Ci::BuildRunnerSession, model: true do
let(:service) { '' }
it 'uses the service name "build" as default' do
- expect(specification[:url]).to eq "https://localhost/proxy/build/#{port}/#{path}"
+ expect(specification[:url]).to eq "https://gitlab.example.com/proxy/build/#{port}/#{path}"
end
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 9713734e97a..813b4b3faa6 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -25,6 +25,7 @@ RSpec.describe Ci::Build do
it { is_expected.to have_many(:needs) }
it { is_expected.to have_many(:sourced_pipelines) }
+ it { is_expected.to have_one(:sourced_pipeline) }
it { is_expected.to have_many(:job_variables) }
it { is_expected.to have_many(:report_results) }
it { is_expected.to have_many(:pages_deployments) }
@@ -86,6 +87,8 @@ RSpec.describe Ci::Build do
it_behaves_like 'has ID tokens', :ci_build
+ it_behaves_like 'a retryable job'
+
describe '.manual_actions' do
let!(:manual_but_created) { create(:ci_build, :manual, status: :created, pipeline: pipeline) }
let!(:manual_but_succeeded) { create(:ci_build, :manual, status: :success, pipeline: pipeline) }
@@ -605,8 +608,8 @@ RSpec.describe Ci::Build do
end
end
- describe '#prevent_rollback_deployment?' do
- subject { build.prevent_rollback_deployment? }
+ describe '#outdated_deployment?' do
+ subject { build.outdated_deployment? }
let(:build) { create(:ci_build, :created, :with_deployment, project: project, environment: 'production') }
@@ -624,21 +627,33 @@ RSpec.describe Ci::Build do
it { expect(subject).to be_falsey }
end
- context 'when deployment cannot rollback' do
+ context 'when build is not an outdated deployment' do
before do
- expect(build.deployment).to receive(:older_than_last_successful_deployment?).and_return(false)
+ allow(build.deployment).to receive(:older_than_last_successful_deployment?).and_return(false)
end
it { expect(subject).to be_falsey }
end
- context 'when build can prevent rollback deployment' do
+ context 'when build is older than the latest deployment and still pending status' do
before do
- expect(build.deployment).to receive(:older_than_last_successful_deployment?).and_return(true)
+ allow(build.deployment).to receive(:older_than_last_successful_deployment?).and_return(true)
end
it { expect(subject).to be_truthy }
end
+
+ context 'when build is older than the latest deployment but succeeded once' do
+ let(:build) { create(:ci_build, :success, :with_deployment, project: project, environment: 'production') }
+
+ before do
+ allow(build.deployment).to receive(:older_than_last_successful_deployment?).and_return(true)
+ end
+
+ it 'returns false for allowing rollback' do
+ expect(subject).to be_falsey
+ end
+ end
end
describe '#schedulable?' do
@@ -1316,6 +1331,8 @@ RSpec.describe Ci::Build do
end
context 'hide build token' do
+ let_it_be(:build) { FactoryBot.build(:ci_build, pipeline: pipeline) }
+
let(:data) { "new #{build.token} data" }
it { is_expected.to match(/^new x+ data$/) }
@@ -1606,8 +1623,8 @@ RSpec.describe Ci::Build do
end
describe 'environment' do
- describe '#has_environment?' do
- subject { build.has_environment? }
+ describe '#has_environment_keyword?' do
+ subject { build.has_environment_keyword? }
context 'when environment is defined' do
before do
@@ -1751,7 +1768,7 @@ RSpec.describe Ci::Build do
context 'and start action is defined' do
before do
- build.update!(options: { environment: { action: 'start' } } )
+ build.update!(options: { environment: { action: 'start' } })
end
it { is_expected.to be_truthy }
@@ -1781,7 +1798,7 @@ RSpec.describe Ci::Build do
context 'and stop action is defined' do
before do
- build.update!(options: { environment: { action: 'stop' } } )
+ build.update!(options: { environment: { action: 'stop' } })
end
it { is_expected.to be_truthy }
@@ -2783,16 +2800,6 @@ RSpec.describe Ci::Build do
expect(environment_based_variables_collection).to be_empty
end
- context 'when ci_job_jwt feature flag is disabled' do
- before do
- stub_feature_flags(ci_job_jwt: false)
- end
-
- it 'CI_JOB_JWT is not included' do
- expect(subject.pluck(:key)).not_to include('CI_JOB_JWT')
- end
- end
-
context 'when CI_JOB_JWT generation fails' do
[
OpenSSL::PKey::RSAError,
@@ -3806,6 +3813,26 @@ RSpec.describe Ci::Build do
build.enqueue
end
+
+ it 'assigns the token' do
+ expect { build.enqueue }.to change(build, :token).from(nil).to(an_instance_of(String))
+ end
+
+ context 'with ci_assign_job_token_on_scheduling disabled' do
+ before do
+ stub_feature_flags(ci_assign_job_token_on_scheduling: false)
+ end
+
+ it 'assigns the token on creation' do
+ expect(build.token).to be_present
+ end
+
+ it 'does not change the token when enqueuing' do
+ expect { build.enqueue }.not_to change(build, :token)
+
+ expect(build).to be_pending
+ end
+ end
end
describe 'state transition: pending: :running' do
@@ -5083,6 +5110,60 @@ RSpec.describe Ci::Build do
context 'when CI_DEBUG_TRACE is not in variables' do
it { is_expected.to eq false }
end
+
+ context 'when CI_DEBUG_SERVICES=true is in variables' do
+ context 'when in instance variables' do
+ before do
+ create(:ci_instance_variable, key: 'CI_DEBUG_SERVICES', value: 'true')
+ end
+
+ it { is_expected.to eq true }
+ end
+
+ context 'when in group variables' do
+ before do
+ create(:ci_group_variable, key: 'CI_DEBUG_SERVICES', value: 'true', group: project.group)
+ end
+
+ it { is_expected.to eq true }
+ end
+
+ context 'when in pipeline variables' do
+ before do
+ create(:ci_pipeline_variable, key: 'CI_DEBUG_SERVICES', value: 'true', pipeline: pipeline)
+ end
+
+ it { is_expected.to eq true }
+ end
+
+ context 'when in project variables' do
+ before do
+ create(:ci_variable, key: 'CI_DEBUG_SERVICES', value: 'true', project: project)
+ end
+
+ it { is_expected.to eq true }
+ end
+
+ context 'when in job variables' do
+ before do
+ create(:ci_job_variable, key: 'CI_DEBUG_SERVICES', value: 'true', job: build)
+ end
+
+ it { is_expected.to eq true }
+ end
+
+ context 'when in yaml variables' do
+ before do
+ build.update!(yaml_variables: [{ key: :CI_DEBUG_SERVICES, value: 'true' }])
+ end
+
+ it { is_expected.to eq true }
+ end
+ end
+
+ context 'when CI_DEBUG_SERVICES is not in variables' do
+ it { is_expected.to eq false }
+ end
end
describe '#drop_with_exit_code!' do
diff --git a/spec/models/ci/build_trace_chunk_spec.rb b/spec/models/ci/build_trace_chunk_spec.rb
index e08fe196d65..3328ed62f15 100644
--- a/spec/models/ci/build_trace_chunk_spec.rb
+++ b/spec/models/ci/build_trace_chunk_spec.rb
@@ -29,6 +29,11 @@ RSpec.describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state, :clean_git
}[data_store]
end
+ describe 'default attributes' do
+ it { expect(described_class.new.data_store).to eq('redis_trace_chunks') }
+ it { expect(described_class.new(data_store: :fog).data_store).to eq('fog') }
+ end
+
describe 'chunk creation' do
let(:metrics) { spy('metrics') }
diff --git a/spec/models/ci/build_trace_spec.rb b/spec/models/ci/build_trace_spec.rb
index f2df4874b84..907b49dc180 100644
--- a/spec/models/ci/build_trace_spec.rb
+++ b/spec/models/ci/build_trace_spec.rb
@@ -38,9 +38,9 @@ RSpec.describe Ci::BuildTrace do
let(:data) { StringIO.new("UTF-8 dashes here: ───\nðŸ¤ðŸ¤ðŸ¤ðŸ¤\xF0\x9F\x90\n") }
it 'returns valid UTF-8 data', :aggregate_failures do
- expect(subject.lines[0]).to eq({ offset: 0, content: [{ text: 'UTF-8 dashes here: ───' }] } )
+ expect(subject.lines[0]).to eq({ offset: 0, content: [{ text: 'UTF-8 dashes here: ───' }] })
# Each of the dashes is 3 bytes, so we get 19 + 9 + 1 = 29
- expect(subject.lines[1]).to eq({ offset: 29, content: [{ text: 'ðŸ¤ðŸ¤ðŸ¤ðŸ¤ï¿½' }] } )
+ expect(subject.lines[1]).to eq({ offset: 29, content: [{ text: 'ðŸ¤ðŸ¤ðŸ¤ðŸ¤ï¿½' }] })
end
end
end
diff --git a/spec/models/ci/pipeline_metadata_spec.rb b/spec/models/ci/pipeline_metadata_spec.rb
index 0704cbc8ec1..977c90bcc2a 100644
--- a/spec/models/ci/pipeline_metadata_spec.rb
+++ b/spec/models/ci/pipeline_metadata_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Ci::PipelineMetadata do
it { is_expected.to belong_to(:pipeline) }
describe 'validations' do
- it { is_expected.to validate_length_of(:title).is_at_least(1).is_at_most(255) }
+ it { is_expected.to validate_length_of(:name).is_at_least(1).is_at_most(255) }
it { is_expected.to validate_presence_of(:project) }
it { is_expected.to validate_presence_of(:pipeline) }
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 42b5210a080..2c945898e61 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -50,7 +50,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
it { is_expected.to respond_to :git_author_full_text }
it { is_expected.to respond_to :short_sha }
it { is_expected.to delegate_method(:full_path).to(:project).with_prefix }
- it { is_expected.to delegate_method(:title).to(:pipeline_metadata).allow_nil }
+ it { is_expected.to delegate_method(:name).to(:pipeline_metadata).allow_nil }
describe 'validations' do
it { is_expected.to validate_presence_of(:sha) }
@@ -166,7 +166,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
it do
pipeline.status = from_status.to_s
- if from_status != to_status
+ if from_status != to_status || success_to_success?
expect(pipeline.set_status(to_status.to_s))
.to eq(true)
else
@@ -174,6 +174,12 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
.to eq(false), "loopback transitions are not allowed"
end
end
+
+ private
+
+ def success_to_success?
+ from_status == :success && to_status == :success
+ end
end
end
@@ -1601,7 +1607,8 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
describe 'track artifact report' do
- let(:pipeline) { create(:ci_pipeline, :running, :with_test_reports, status: :running, user: create(:user)) }
+ let_it_be(:user) { create(:user) }
+ let_it_be_with_reload(:pipeline) { create(:ci_pipeline, :running, :with_test_reports, :with_coverage_reports, status: :running, user: user) }
context 'when transitioning to completed status' do
%i[drop! skip! succeed! cancel!].each do |command|
@@ -1613,11 +1620,29 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
context 'when pipeline retried from failed to success', :clean_gitlab_redis_shared_state do
- let(:test_event_name) { 'i_testing_test_report_uploaded' }
+ let(:test_event_name_1) { 'i_testing_test_report_uploaded' }
+ let(:test_event_name_2) { 'i_testing_coverage_report_uploaded' }
let(:start_time) { 1.week.ago }
let(:end_time) { 1.week.from_now }
- it 'counts only one report' do
+ it 'counts only one test event report' do
+ expect(Ci::JobArtifacts::TrackArtifactReportWorker).to receive(:perform_async).with(pipeline.id).twice.and_call_original
+
+ Sidekiq::Testing.inline! do
+ pipeline.drop!
+ pipeline.run!
+ pipeline.succeed!
+ end
+
+ unique_pipeline_pass = Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(
+ event_names: test_event_name_1,
+ start_date: start_time,
+ end_date: end_time
+ )
+ expect(unique_pipeline_pass).to eq(1)
+ end
+
+ it 'counts only one coverage event report' do
expect(Ci::JobArtifacts::TrackArtifactReportWorker).to receive(:perform_async).with(pipeline.id).twice.and_call_original
Sidekiq::Testing.inline! do
@@ -1627,7 +1652,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
unique_pipeline_pass = Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(
- event_names: test_event_name,
+ event_names: test_event_name_2,
start_date: start_time,
end_date: end_time
)
@@ -4173,7 +4198,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
let(:pipeline) { create(:ci_pipeline) }
let!(:old_job) { create(:ci_build, name: 'rspec', retried: true, pipeline: pipeline) }
let!(:job_without_artifacts) { create(:ci_build, name: 'rspec', pipeline: pipeline) }
- let!(:expected_job) { create(:ci_build, :artifacts, name: 'rspec', pipeline: pipeline ) }
+ let!(:expected_job) { create(:ci_build, :artifacts, name: 'rspec', pipeline: pipeline) }
let!(:different_job) { create(:ci_build, name: 'deploy', pipeline: pipeline) }
subject { pipeline.find_job_with_archive_artifacts('rspec') }
diff --git a/spec/models/ci/processable_spec.rb b/spec/models/ci/processable_spec.rb
index a199111b1e3..e62e5f84a6d 100644
--- a/spec/models/ci/processable_spec.rb
+++ b/spec/models/ci/processable_spec.rb
@@ -52,7 +52,11 @@ RSpec.describe Ci::Processable do
let_it_be(:internal_job_variable) { create(:ci_job_variable, job: processable) }
- let(:clone_accessors) { ::Ci::Build.clone_accessors.without(::Ci::Build.extra_accessors) }
+ let(:clone_accessors) do
+ %i[pipeline project ref tag options name allow_failure stage stage_idx trigger_request yaml_variables
+ when environment coverage_regex description tag_list protected needs_attributes job_variables_attributes
+ resource_group scheduling_type ci_stage partition_id id_tokens]
+ end
let(:reject_accessors) do
%i[id status user token_encrypted coverage runner artifacts_expire_at
@@ -77,13 +81,14 @@ RSpec.describe Ci::Processable do
commit_id deployment erased_by_id project_id
runner_id tag_taggings taggings tags trigger_request_id
user_id auto_canceled_by_id retried failure_reason
- sourced_pipelines artifacts_file_store artifacts_metadata_store
+ sourced_pipelines sourced_pipeline artifacts_file_store artifacts_metadata_store
metadata 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
queuing_entry runtime_metadata trace_metadata
- dast_site_profile dast_scanner_profile stage_id].freeze
+ dast_site_profile dast_scanner_profile stage_id dast_site_profiles_build
+ dast_scanner_profiles_build].freeze
end
before_all do
@@ -177,10 +182,7 @@ RSpec.describe Ci::Processable do
Ci::Build.attribute_names.map(&:to_sym) +
Ci::Build.attribute_aliases.keys.map(&:to_sym) +
Ci::Build.reflect_on_all_associations.map(&:name) +
- [:tag_list, :needs_attributes, :job_variables_attributes, :id_tokens] -
- # ToDo: Move EE accessors to ee/
- ::Ci::Build.extra_accessors -
- [:dast_site_profiles_build, :dast_scanner_profiles_build]
+ [:tag_list, :needs_attributes, :job_variables_attributes, :id_tokens]
current_accessors.uniq!
@@ -284,12 +286,6 @@ RSpec.describe Ci::Processable do
end
end
- context 'when the processable is a bridge' do
- subject(:processable) { create(:ci_bridge, pipeline: pipeline) }
-
- it_behaves_like 'retryable processable'
- end
-
context 'when the processable is a build' do
subject(:processable) { create(:ci_build, pipeline: pipeline) }
diff --git a/spec/models/ci/secure_file_spec.rb b/spec/models/ci/secure_file_spec.rb
index 20f64d40865..4413bd8e98b 100644
--- a/spec/models/ci/secure_file_spec.rb
+++ b/spec/models/ci/secure_file_spec.rb
@@ -21,6 +21,15 @@ RSpec.describe Ci::SecureFile do
subject { build(:ci_secure_file, project: create(:project)) }
end
+ describe 'default attributes' do
+ before do
+ allow(Ci::SecureFileUploader).to receive(:default_store).and_return(5)
+ end
+
+ it { expect(described_class.new.file_store).to eq(5) }
+ it { expect(described_class.new(file_store: 3).file_store).to eq(3) }
+ end
+
describe 'validations' do
it { is_expected.to validate_presence_of(:checksum) }
it { is_expected.to validate_presence_of(:file_store) }
@@ -131,7 +140,7 @@ RSpec.describe Ci::SecureFile do
describe '#update_metadata!' do
it 'assigns the expected metadata when a parsable file is supplied' do
file = create(:ci_secure_file, name: 'file1.cer',
- file: CarrierWaveStringFile.new(fixture_file('ci_secure_files/sample.cer') ))
+ file: CarrierWaveStringFile.new(fixture_file('ci_secure_files/sample.cer')))
file.update_metadata!
expect(file.expires_at).to eq(DateTime.parse('2022-04-26 19:20:40'))
diff --git a/spec/models/ci/sources/pipeline_spec.rb b/spec/models/ci/sources/pipeline_spec.rb
index 732dd5c3df3..fdc1c111c40 100644
--- a/spec/models/ci/sources/pipeline_spec.rb
+++ b/spec/models/ci/sources/pipeline_spec.rb
@@ -20,14 +20,14 @@ RSpec.describe Ci::Sources::Pipeline do
context 'loose foreign key on ci_sources_pipelines.source_project_id' do
it_behaves_like 'cleanup by a loose foreign key' do
- let!(:parent) { create(:project) }
+ let!(:parent) { create(:project, namespace: create(:group)) }
let!(:model) { create(:ci_sources_pipeline, source_project: parent) }
end
end
context 'loose foreign key on ci_sources_pipelines.project_id' do
it_behaves_like 'cleanup by a loose foreign key' do
- let!(:parent) { create(:project) }
+ let!(:parent) { create(:project, namespace: create(:group)) }
let!(:model) { create(:ci_sources_pipeline, project: parent) }
end
end
diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb
index dd9af33a562..b392ab4ed11 100644
--- a/spec/models/ci/stage_spec.rb
+++ b/spec/models/ci/stage_spec.rb
@@ -389,7 +389,7 @@ RSpec.describe Ci::Stage, :models do
end
context 'without pipeline' do
- subject(:stage) { build(:ci_stage, pipeline: nil) }
+ subject(:stage) { build(:ci_stage, pipeline: nil, project: build_stubbed(:project)) }
it { is_expected.to validate_presence_of(:partition_id) }
diff --git a/spec/models/ci/trigger_request_spec.rb b/spec/models/ci/trigger_request_spec.rb
index 0d462741089..a6e8e8496ac 100644
--- a/spec/models/ci/trigger_request_spec.rb
+++ b/spec/models/ci/trigger_request_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe Ci::TriggerRequest do
describe 'validation' do
it 'be invalid if saving a variable' do
- trigger = build(:ci_trigger_request, variables: { TRIGGER_KEY_1: 'TRIGGER_VALUE_1' } )
+ trigger = build(:ci_trigger_request, variables: { TRIGGER_KEY_1: 'TRIGGER_VALUE_1' })
expect(trigger).not_to be_valid
end
diff --git a/spec/models/ci/unit_test_spec.rb b/spec/models/ci/unit_test_spec.rb
index b3180492a36..e35a4ce40da 100644
--- a/spec/models/ci/unit_test_spec.rb
+++ b/spec/models/ci/unit_test_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Ci::UnitTest do
it_behaves_like 'cleanup by a loose foreign key' do
- let!(:parent) { create(:project) }
+ let!(:parent) { create(:project, namespace: create(:group)) }
let!(:model) { create(:ci_unit_test, project: parent) }
end
diff --git a/spec/models/clusters/applications/cert_manager_spec.rb b/spec/models/clusters/applications/cert_manager_spec.rb
index 05ab8c4108e..427a99efadd 100644
--- a/spec/models/clusters/applications/cert_manager_spec.rb
+++ b/spec/models/clusters/applications/cert_manager_spec.rb
@@ -10,6 +10,11 @@ RSpec.describe Clusters::Applications::CertManager do
include_examples 'cluster application version specs', :clusters_applications_cert_manager
include_examples 'cluster application initial status specs'
+ describe 'default values' do
+ it { expect(cert_manager.version).to eq(described_class::VERSION) }
+ it { expect(cert_manager.email).to eq("admin@example.com") }
+ end
+
describe '#can_uninstall?' do
subject { cert_manager.can_uninstall? }
diff --git a/spec/models/clusters/applications/crossplane_spec.rb b/spec/models/clusters/applications/crossplane_spec.rb
index 7082576028b..d1abaa52c7f 100644
--- a/spec/models/clusters/applications/crossplane_spec.rb
+++ b/spec/models/clusters/applications/crossplane_spec.rb
@@ -14,6 +14,11 @@ RSpec.describe Clusters::Applications::Crossplane 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? }
diff --git a/spec/models/clusters/applications/helm_spec.rb b/spec/models/clusters/applications/helm_spec.rb
index 5212e321a55..1b8be92475a 100644
--- a/spec/models/clusters/applications/helm_spec.rb
+++ b/spec/models/clusters/applications/helm_spec.rb
@@ -5,6 +5,10 @@ require 'spec_helper'
RSpec.describe Clusters::Applications::Helm do
include_examples 'cluster application core specs', :clusters_applications_helm
+ describe 'default values' do
+ it { expect(subject.version).to eq(Gitlab::Kubernetes::Helm::V2::BaseCommand::HELM_VERSION) }
+ end
+
describe '.available' do
subject { described_class.available }
diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb
index e16d97c42d9..e5caa11452e 100644
--- a/spec/models/clusters/applications/ingress_spec.rb
+++ b/spec/models/clusters/applications/ingress_spec.rb
@@ -18,6 +18,11 @@ RSpec.describe Clusters::Applications::Ingress do
allow(ClusterWaitForIngressIpAddressWorker).to receive(:perform_async)
end
+ describe 'default values' do
+ it { expect(subject.ingress_type).to eq("nginx") }
+ it { expect(subject.version).to eq(described_class::VERSION) }
+ end
+
describe '#can_uninstall?' do
subject { ingress.can_uninstall? }
diff --git a/spec/models/clusters/applications/jupyter_spec.rb b/spec/models/clusters/applications/jupyter_spec.rb
index e7de2d24334..9336d2352f8 100644
--- a/spec/models/clusters/applications/jupyter_spec.rb
+++ b/spec/models/clusters/applications/jupyter_spec.rb
@@ -10,6 +10,10 @@ RSpec.describe Clusters::Applications::Jupyter do
it { is_expected.to belong_to(:oauth_application) }
+ describe 'default values' do
+ it { expect(subject.version).to eq(described_class::VERSION) }
+ end
+
describe '#can_uninstall?' do
let(:ingress) { create(:clusters_applications_ingress, :installed, external_hostname: 'localhost.localdomain') }
let(:jupyter) { create(:clusters_applications_jupyter, cluster: ingress.cluster) }
diff --git a/spec/models/clusters/applications/knative_spec.rb b/spec/models/clusters/applications/knative_spec.rb
index d0e470bfa42..3914450339a 100644
--- a/spec/models/clusters/applications/knative_spec.rb
+++ b/spec/models/clusters/applications/knative_spec.rb
@@ -21,6 +21,10 @@ RSpec.describe Clusters::Applications::Knative 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
+
describe 'when cloud run is enabled' do
let(:cluster) { create(:cluster, :provided_by_gcp, :cloud_run_enabled) }
let(:knative_cloud_run) { create(:clusters_applications_knative, cluster: cluster) }
diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb
index 549a273e2d7..15c3162270e 100644
--- a/spec/models/clusters/applications/prometheus_spec.rb
+++ b/spec/models/clusters/applications/prometheus_spec.rb
@@ -12,6 +12,13 @@ RSpec.describe Clusters::Applications::Prometheus do
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) }
@@ -130,7 +137,7 @@ RSpec.describe Clusters::Applications::Prometheus do
end
context 'with knative installed' do
- let(:knative) { create(:clusters_applications_knative, :updated ) }
+ let(:knative) { create(:clusters_applications_knative, :updated) }
let(:prometheus) { create(:clusters_applications_prometheus, cluster: knative.cluster) }
subject { prometheus.install_command }
@@ -161,7 +168,7 @@ RSpec.describe Clusters::Applications::Prometheus do
end
describe '#predelete' do
- let(:knative) { create(:clusters_applications_knative, :updated ) }
+ let(:knative) { create(:clusters_applications_knative, :updated) }
let(:prometheus) { create(:clusters_applications_prometheus, cluster: knative.cluster) }
subject { prometheus.uninstall_command.predelete }
diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb
index 8f02161843b..04b5ae9641d 100644
--- a/spec/models/clusters/applications/runner_spec.rb
+++ b/spec/models/clusters/applications/runner_spec.rb
@@ -13,6 +13,10 @@ RSpec.describe Clusters::Applications::Runner do
it { is_expected.to belong_to(:runner) }
+ describe 'default values' do
+ it { expect(subject.version).to eq(described_class::VERSION) }
+ end
+
describe '#can_uninstall?' do
let(:gitlab_runner) { create(:clusters_applications_runner, runner: ci_runner) }
diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb
index 73cd7bb9075..be64d72e031 100644
--- a/spec/models/clusters/cluster_spec.rb
+++ b/spec/models/clusters/cluster_spec.rb
@@ -49,6 +49,10 @@ RSpec.describe Clusters::Cluster, :use_clean_rails_memory_store_caching do
it { is_expected.to respond_to :project }
it { is_expected.to be_namespace_per_environment }
+ describe 'default values' do
+ it { expect(subject.helm_major_version).to eq(3) }
+ end
+
it_behaves_like 'it has loose foreign keys' do
let(:factory_name) { :cluster }
end
diff --git a/spec/models/clusters/integrations/prometheus_spec.rb b/spec/models/clusters/integrations/prometheus_spec.rb
index 90e99aefdce..d6d1105cdb1 100644
--- a/spec/models/clusters/integrations/prometheus_spec.rb
+++ b/spec/models/clusters/integrations/prometheus_spec.rb
@@ -15,6 +15,16 @@ RSpec.describe Clusters::Integrations::Prometheus do
it { is_expected.not_to allow_value(nil).for(:enabled) }
end
+ describe 'default values' do
+ subject(:integration) { build(:clusters_integrations_prometheus) }
+
+ before do
+ allow(SecureRandom).to receive(:hex).and_return('randomtoken')
+ end
+
+ it { expect(integration.alert_manager_token).to eq('randomtoken') }
+ end
+
describe 'after_destroy' do
subject(:integration) { create(:clusters_integrations_prometheus, cluster: cluster, enabled: true) }
diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb
index 4ac2fd022ba..b280275c2e5 100644
--- a/spec/models/clusters/platforms/kubernetes_spec.rb
+++ b/spec/models/clusters/platforms/kubernetes_spec.rb
@@ -21,6 +21,12 @@ RSpec.describe Clusters::Platforms::Kubernetes do
it_behaves_like 'having unique enum values'
+ describe 'default values' do
+ let(:kubernetes) { create(:cluster_platform_kubernetes) }
+
+ it { expect(kubernetes.authorization_type).to eq("rbac") }
+ end
+
describe 'before_validation' do
let(:kubernetes) { create(:cluster_platform_kubernetes, :configured, namespace: namespace) }
@@ -427,6 +433,55 @@ RSpec.describe Clusters::Platforms::Kubernetes do
let(:cluster) { create(:cluster, :project, platform_kubernetes: service) }
include_examples 'successful deployment request'
+
+ context 'when reading ingress raises NoMethodError' do
+ before do
+ allow_next_instance_of(Gitlab::Kubernetes::KubeClient) do |kube_client|
+ allow(kube_client).to receive(:get_pods).with(namespace: namespace).and_return([])
+ allow(kube_client).to receive(:get_deployments).with(namespace: namespace).and_return([])
+ allow(kube_client).to receive(:get_ingresses).with(namespace: namespace).and_raise(NoMethodError)
+ end
+ end
+
+ context 'when version request succeeds' do
+ before do
+ stub_server_min_version(min_server_version)
+ end
+
+ context 'when server min version is < 23' do
+ let(:min_server_version) { "18" }
+
+ it 'does not raise error', :unlimited_max_formatted_output_length do
+ expect { subject }.not_to raise_error
+ end
+
+ it 'returns empty array for the K8s component keys' do
+ expect(subject).to include({ pods: [], deployments: [], ingresses: [] })
+ end
+ end
+
+ context 'when server min version is >= 23' do
+ let(:min_server_version) { "23" }
+
+ it 'does raise error' do
+ expect { subject }.to raise_error(NoMethodError)
+ end
+ end
+ end
+
+ context 'when the version request fails' do
+ before do
+ stub_server_min_version_failed_request
+ end
+
+ it "tracks error and returns empty arrays" do
+ expect(Gitlab::ErrorTracking)
+ .to receive(:track_exception).with(kind_of(Clusters::Platforms::Kubernetes::FailedVersionCheckError))
+
+ expect(subject).to include({ pods: [], deployments: [], ingresses: [] })
+ end
+ end
+ end
end
context 'on a group level cluster' do
@@ -452,7 +507,7 @@ RSpec.describe Clusters::Platforms::Kubernetes do
context 'when there are ignored K8s connections errors' do
described_class::IGNORED_CONNECTION_EXCEPTIONS.each do |exception|
- context "#{exception}" do
+ context exception.to_s do
before do
exception_args = ['arg1']
exception_args.push('arg2', 'arg3') if exception.name == 'Kubeclient::HttpError'
diff --git a/spec/models/clusters/providers/aws_spec.rb b/spec/models/clusters/providers/aws_spec.rb
index 3b4a48cc5be..2afed663edf 100644
--- a/spec/models/clusters/providers/aws_spec.rb
+++ b/spec/models/clusters/providers/aws_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe Clusters::Providers::Aws do
include_examples 'provider status', :cluster_provider_aws
- describe 'default_value_for' do
+ describe 'default values' do
let(:provider) { build(:cluster_provider_aws) }
it "sets default values" do
diff --git a/spec/models/clusters/providers/gcp_spec.rb b/spec/models/clusters/providers/gcp_spec.rb
index ad9ada04875..a1f00069937 100644
--- a/spec/models/clusters/providers/gcp_spec.rb
+++ b/spec/models/clusters/providers/gcp_spec.rb
@@ -8,13 +8,14 @@ RSpec.describe Clusters::Providers::Gcp do
include_examples 'provider status', :cluster_provider_gcp
- describe 'default_value_for' do
+ describe 'default values' do
let(:gcp) { build(:cluster_provider_gcp) }
it "has default value" do
expect(gcp.zone).to eq('us-central1-a')
expect(gcp.num_nodes).to eq(3)
expect(gcp.machine_type).to eq('n1-standard-2')
+ expect(gcp.cloud_run).to eq(false)
end
end
diff --git a/spec/models/commit_signatures/gpg_signature_spec.rb b/spec/models/commit_signatures/gpg_signature_spec.rb
index 605ad725dd7..1ffaaeba396 100644
--- a/spec/models/commit_signatures/gpg_signature_spec.rb
+++ b/spec/models/commit_signatures/gpg_signature_spec.rb
@@ -85,4 +85,10 @@ RSpec.describe CommitSignatures::GpgSignature do
end
end
end
+
+ describe '#user' do
+ it 'retrieves the gpg_key user' do
+ expect(signature.user).to eq(gpg_key.user)
+ end
+ end
end
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index adbd20b6730..704203ed29c 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -32,6 +32,7 @@ RSpec.describe CommitStatus do
it { is_expected.to respond_to :failed? }
it { is_expected.to respond_to :running? }
it { is_expected.to respond_to :pending? }
+ it { is_expected.not_to be_retried }
describe '#author' do
subject { commit_status.author }
diff --git a/spec/models/concerns/bulk_insert_safe_spec.rb b/spec/models/concerns/bulk_insert_safe_spec.rb
index 569dc3a3a3e..577004c2cf6 100644
--- a/spec/models/concerns/bulk_insert_safe_spec.rb
+++ b/spec/models/concerns/bulk_insert_safe_spec.rb
@@ -73,9 +73,9 @@ RSpec.describe BulkInsertSafe do
key: Settings.attr_encrypted_db_key_base_32,
insecure_mode: false
- default_value_for :enum_value, 'case_1'
- default_value_for :sha_value, '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12'
- default_value_for :jsonb_value, { "key" => "value" }
+ attribute :enum_value, default: 'case_1'
+ attribute :sha_value, default: '2fd4e1c67a2d28fced849ee1bb76e7391b93eb12'
+ attribute :jsonb_value, default: -> { { "key" => "value" } }
def self.name
'BulkInsertItem'
diff --git a/spec/models/concerns/ci/has_variable_spec.rb b/spec/models/concerns/ci/has_variable_spec.rb
index bf699119a37..861d8f3b974 100644
--- a/spec/models/concerns/ci/has_variable_spec.rb
+++ b/spec/models/concerns/ci/has_variable_spec.rb
@@ -84,6 +84,7 @@ RSpec.describe Ci::HasVariable do
key: subject.key,
value: subject.value,
public: false,
+ raw: false,
masked: false
}
end
diff --git a/spec/models/concerns/ci/partitionable/switch_spec.rb b/spec/models/concerns/ci/partitionable/switch_spec.rb
new file mode 100644
index 00000000000..d955ad223f8
--- /dev/null
+++ b/spec/models/concerns/ci/partitionable/switch_spec.rb
@@ -0,0 +1,316 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::Partitionable::Switch, :aggregate_failures do
+ let(:model) do
+ Class.new(Ci::ApplicationRecord) do
+ self.primary_key = :id
+ self.table_name = :_test_ci_jobs_metadata
+ self.sequence_name = :_test_ci_jobs_metadata_id_seq
+
+ def self.name
+ 'TestSwitchJobMetadata'
+ end
+ end
+ end
+
+ let(:table_rollout_flag) { :ci_partitioning_use_test_routing_table }
+
+ let(:partitioned_model) { model::Partitioned }
+
+ let(:jobs_model) do
+ Class.new(Ci::ApplicationRecord) do
+ self.primary_key = :id
+ self.table_name = :_test_ci_jobs
+
+ def self.name
+ 'TestSwitchJob'
+ end
+ end
+ end
+
+ before do
+ allow(ActiveSupport::DescendantsTracker).to receive(:store_inherited)
+
+ create_tables(<<~SQL)
+ CREATE TABLE _test_ci_jobs_metadata(
+ id serial NOT NULL PRIMARY KEY,
+ job_id int,
+ partition_id int NOT NULL DEFAULT 1,
+ expanded_environment_name text);
+
+ CREATE TABLE _test_p_ci_jobs_metadata (
+ LIKE _test_ci_jobs_metadata INCLUDING DEFAULTS
+ ) PARTITION BY LIST(partition_id);
+
+ ALTER TABLE _test_p_ci_jobs_metadata
+ ADD CONSTRAINT _test_p_ci_jobs_metadata_id_partition_id
+ UNIQUE (id, partition_id);
+
+ ALTER TABLE _test_p_ci_jobs_metadata
+ ATTACH PARTITION _test_ci_jobs_metadata FOR VALUES IN (1);
+
+ CREATE TABLE _test_ci_jobs(id serial NOT NULL PRIMARY KEY);
+ SQL
+
+ stub_const('Ci::Partitionable::Testing::PARTITIONABLE_MODELS', [model.name])
+
+ model.include(Ci::Partitionable)
+
+ model.partitionable scope: ->(r) { 1 },
+ through: { table: :_test_p_ci_jobs_metadata, flag: table_rollout_flag }
+
+ model.belongs_to :job, anonymous_class: jobs_model
+
+ jobs_model.has_one :metadata, anonymous_class: model,
+ foreign_key: :job_id, inverse_of: :job,
+ dependent: :destroy
+
+ allow(Feature::Definition).to receive(:get).and_call_original
+ allow(Feature::Definition).to receive(:get).with(table_rollout_flag)
+ .and_return(
+ Feature::Definition.new("development/#{table_rollout_flag}.yml",
+ { type: 'development', name: table_rollout_flag }
+ )
+ )
+ end
+
+ it { expect(model).not_to be_routing_class }
+
+ it { expect(partitioned_model).to be_routing_class }
+
+ it { expect(partitioned_model.table_name).to eq('_test_p_ci_jobs_metadata') }
+
+ it { expect(partitioned_model.quoted_table_name).to eq('"_test_p_ci_jobs_metadata"') }
+
+ it { expect(partitioned_model.arel_table.name).to eq('_test_p_ci_jobs_metadata') }
+
+ it { expect(partitioned_model.sequence_name).to eq('_test_ci_jobs_metadata_id_seq') }
+
+ context 'when switching the tables' do
+ before do
+ stub_feature_flags(table_rollout_flag => false)
+ end
+
+ %i[table_name quoted_table_name arel_table predicate_builder].each do |name|
+ it "switches #{name} to routing table and rollbacks" do
+ old_value = model.public_send(name)
+ routing_value = partitioned_model.public_send(name)
+
+ expect(old_value).not_to eq(routing_value)
+
+ expect { stub_feature_flags(table_rollout_flag => true) }
+ .to change(model, name).from(old_value).to(routing_value)
+
+ expect { stub_feature_flags(table_rollout_flag => false) }
+ .to change(model, name).from(routing_value).to(old_value)
+ end
+ end
+
+ it 'can switch aggregate methods' do
+ rollout_and_rollback_flag(
+ -> { expect(sql { model.count }).to all match(/FROM "_test_ci_jobs_metadata"/) },
+ -> { expect(sql { model.count }).to all match(/FROM "_test_p_ci_jobs_metadata"/) }
+ )
+ end
+
+ it 'can switch reads' do
+ rollout_and_rollback_flag(
+ -> { expect(sql { model.last }).to all match(/FROM "_test_ci_jobs_metadata"/) },
+ -> { expect(sql { model.last }).to all match(/FROM "_test_p_ci_jobs_metadata"/) }
+ )
+ end
+
+ it 'can switch inserts' do
+ rollout_and_rollback_flag(
+ -> {
+ expect(sql(filter: /INSERT/) { model.create! })
+ .to all match(/INSERT INTO "_test_ci_jobs_metadata"/)
+ },
+ -> {
+ expect(sql(filter: /INSERT/) { model.create! })
+ .to all match(/INSERT INTO "_test_p_ci_jobs_metadata"/)
+ }
+ )
+ end
+
+ it 'can switch deletes' do
+ 3.times { model.create! }
+
+ rollout_and_rollback_flag(
+ -> {
+ expect(sql(filter: /DELETE/) { model.last.destroy! })
+ .to all match(/DELETE FROM "_test_ci_jobs_metadata"/)
+ },
+ -> {
+ expect(sql(filter: /DELETE/) { model.last.destroy! })
+ .to all match(/DELETE FROM "_test_p_ci_jobs_metadata"/)
+ }
+ )
+ end
+
+ context 'with associations' do
+ let(:job) { jobs_model.create! }
+
+ it 'reads' do
+ model.create!(job_id: job.id)
+
+ rollout_and_rollback_flag(
+ -> {
+ expect(sql(filter: /jobs_metadata/) { jobs_model.find(job.id).metadata })
+ .to all match(/FROM "_test_ci_jobs_metadata"/)
+ },
+ -> {
+ expect(sql(filter: /jobs_metadata/) { jobs_model.find(job.id).metadata })
+ .to all match(/FROM "_test_p_ci_jobs_metadata"/)
+ }
+ )
+ end
+
+ it 'writes' do
+ rollout_and_rollback_flag(
+ -> {
+ expect(sql(filter: /INSERT .* jobs_metadata/) { jobs_model.find(job.id).create_metadata! })
+ .to all match(/INSERT INTO "_test_ci_jobs_metadata"/)
+ },
+ -> {
+ expect(sql(filter: /INSERT .* jobs_metadata/) { jobs_model.find(job.id).create_metadata! })
+ .to all match(/INSERT INTO "_test_p_ci_jobs_metadata"/)
+ }
+ )
+ end
+
+ it 'deletes' do
+ 3.times do
+ job = jobs_model.create!
+ job.create_metadata!
+ end
+
+ rollout_and_rollback_flag(
+ -> {
+ expect(sql(filter: /DELETE .* jobs_metadata/) { jobs_model.last.destroy! })
+ .to all match(/DELETE FROM "_test_ci_jobs_metadata"/)
+ },
+ -> {
+ expect(sql(filter: /DELETE .* jobs_metadata/) { jobs_model.last.destroy! })
+ .to all match(/DELETE FROM "_test_p_ci_jobs_metadata"/)
+ }
+ )
+ end
+
+ it 'can switch joins from jobs' do
+ rollout_and_rollback_flag(
+ -> {
+ expect(sql { jobs_model.joins(:metadata).last })
+ .to all match(/INNER JOIN "_test_ci_jobs_metadata"/)
+ },
+ -> {
+ expect(sql { jobs_model.joins(:metadata).last })
+ .to all match(/INNER JOIN "_test_p_ci_jobs_metadata"/)
+ }
+ )
+ end
+
+ it 'can switch joins from metadata' do
+ rollout_and_rollback_flag(
+ -> {
+ expect(sql { model.joins(:job).last })
+ .to all match(/FROM "_test_ci_jobs_metadata" INNER JOIN "_test_ci_jobs"/)
+ },
+ -> {
+ expect(sql { model.joins(:job).last })
+ .to all match(/FROM "_test_p_ci_jobs_metadata" INNER JOIN "_test_ci_jobs"/)
+ }
+ )
+ end
+
+ it 'preloads' do
+ job = jobs_model.create!
+ job.create_metadata!
+
+ rollout_and_rollback_flag(
+ -> {
+ expect(sql(filter: /jobs_metadata/) { jobs_model.preload(:metadata).last })
+ .to all match(/FROM "_test_ci_jobs_metadata"/)
+ },
+ -> {
+ expect(sql(filter: /jobs_metadata/) { jobs_model.preload(:metadata).last })
+ .to all match(/FROM "_test_p_ci_jobs_metadata"/)
+ }
+ )
+ end
+
+ context 'with nested attributes' do
+ before do
+ jobs_model.accepts_nested_attributes_for :metadata
+ end
+
+ it 'writes' do
+ attrs = { metadata_attributes: { expanded_environment_name: 'test_env_name' } }
+
+ rollout_and_rollback_flag(
+ -> {
+ expect(sql(filter: /INSERT .* jobs_metadata/) { jobs_model.create!(attrs) })
+ .to all match(/INSERT INTO "_test_ci_jobs_metadata" .* 'test_env_name'/)
+ },
+ -> {
+ expect(sql(filter: /INSERT .* jobs_metadata/) { jobs_model.create!(attrs) })
+ .to all match(/INSERT INTO "_test_p_ci_jobs_metadata" .* 'test_env_name'/)
+ }
+ )
+ end
+ end
+ end
+ end
+
+ context 'with safe request store', :request_store do
+ it 'changing the flag to true does not affect the current request' do
+ stub_feature_flags(table_rollout_flag => false)
+
+ expect(model.table_name).to eq('_test_ci_jobs_metadata')
+
+ stub_feature_flags(table_rollout_flag => true)
+
+ expect(model.table_name).to eq('_test_ci_jobs_metadata')
+ end
+
+ it 'changing the flag to false does not affect the current request' do
+ stub_feature_flags(table_rollout_flag => true)
+
+ expect(model.table_name).to eq('_test_p_ci_jobs_metadata')
+
+ stub_feature_flags(table_rollout_flag => false)
+
+ expect(model.table_name).to eq('_test_p_ci_jobs_metadata')
+ end
+ end
+
+ def rollout_and_rollback_flag(old, new)
+ # Load class and SQL statements cache
+ old.call
+
+ stub_feature_flags(table_rollout_flag => true)
+
+ # Test switch
+ new.call
+
+ stub_feature_flags(table_rollout_flag => false)
+
+ # Test that it can switch back in the same process
+ old.call
+ end
+
+ def create_tables(table_sql)
+ Ci::ApplicationRecord.connection.execute(table_sql)
+ end
+
+ def sql(filter: nil, &block)
+ result = ActiveRecord::QueryRecorder.new(&block)
+ result = result.log
+
+ return result unless filter
+
+ result.select { |statement| statement.match?(filter) }
+ end
+end
diff --git a/spec/models/concerns/ci/partitionable_spec.rb b/spec/models/concerns/ci/partitionable_spec.rb
index d53501ccc3d..f3d33c971c7 100644
--- a/spec/models/concerns/ci/partitionable_spec.rb
+++ b/spec/models/concerns/ci/partitionable_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
RSpec.describe Ci::Partitionable do
- describe 'partitionable models inclusion' do
- let(:ci_model) { Class.new(Ci::ApplicationRecord) }
+ let(:ci_model) { Class.new(Ci::ApplicationRecord) }
+ describe 'partitionable models inclusion' do
subject { ci_model.include(described_class) }
it 'raises an exception' do
@@ -23,4 +23,21 @@ RSpec.describe Ci::Partitionable do
end
end
end
+
+ context 'with through options' do
+ before do
+ allow(ActiveSupport::DescendantsTracker).to receive(:store_inherited)
+ stub_const("#{described_class}::Testing::PARTITIONABLE_MODELS", [ci_model.name])
+
+ ci_model.include(described_class)
+ ci_model.partitionable scope: ->(r) { 1 },
+ through: { table: :_test_table_name, flag: :some_flag }
+ end
+
+ it { expect(ci_model.routing_table_name).to eq(:_test_table_name) }
+
+ it { expect(ci_model.routing_table_name_flag).to eq(:some_flag) }
+
+ it { expect(ci_model.ancestors).to include(described_class::Switch) }
+ end
end
diff --git a/spec/models/concerns/encrypted_user_password_spec.rb b/spec/models/concerns/encrypted_user_password_spec.rb
new file mode 100644
index 00000000000..b6447313967
--- /dev/null
+++ b/spec/models/concerns/encrypted_user_password_spec.rb
@@ -0,0 +1,138 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe User do
+ describe '#authenticatable_salt' do
+ let(:user) { build(:user, encrypted_password: encrypted_password) }
+
+ subject(:authenticatable_salt) { user.authenticatable_salt }
+
+ context 'when password is stored in BCrypt format' do
+ let(:encrypted_password) { '$2a$10$AvwDCyF/8HnlAv./UkAZx.vAlKRS89yNElP38FzdgOmVaSaiDL7xm' }
+
+ it 'returns the first 30 characters of the encrypted_password' do
+ expect(authenticatable_salt).to eq(user.encrypted_password[0, 29])
+ end
+ end
+
+ context 'when password is stored in PBKDF2 format' do
+ let(:encrypted_password) { '$pbkdf2-sha512$20000$rKbYsScsDdk$iwWBewXmrkD2fFfaG1SDcMIvl9gvEo3fBWUAfiqyVceTlw/DYgKBByHzf45pF5Qn59R4R.NQHsFpvZB4qlsYmw' } # rubocop:disable Layout/LineLength
+
+ it 'uses the decoded password salt' do
+ expect(authenticatable_salt).to eq('aca6d8b1272c0dd9')
+ end
+
+ it 'does not use the first 30 characters of the encrypted_password' do
+ expect(authenticatable_salt).not_to eq(encrypted_password[0, 29])
+ end
+ end
+
+ context 'when the encrypted_password is an unknown type' do
+ let(:encrypted_password) { '$argon2i$v=19$m=512,t=4,p=2$eM+ZMyYkpDRGaI3xXmuNcQ$c5DeJg3eb5dskVt1mDdxfw' }
+
+ it 'returns the first 30 characters of the encrypted_password' do
+ expect(authenticatable_salt).to eq(encrypted_password[0, 29])
+ end
+ end
+ end
+
+ describe '#valid_password?' do
+ subject(:validate_password) { user.valid_password?(password) }
+
+ let(:user) { build(:user, encrypted_password: encrypted_password) }
+ let(:password) { described_class.random_password }
+
+ shared_examples 'password validation fails when the password is encrypted using an unsupported method' do
+ let(:encrypted_password) { '$argon2i$v=19$m=512,t=4,p=2$eM+ZMyYkpDRGaI3xXmuNcQ$c5DeJg3eb5dskVt1mDdxfw' }
+
+ it { is_expected.to eq(false) }
+ end
+
+ context 'when the default encryption method is BCrypt' do
+ it_behaves_like 'password validation fails when the password is encrypted using an unsupported method'
+
+ context 'when the user password PBKDF2+SHA512' do
+ let(:encrypted_password) do
+ Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512.digest(
+ password, 20_000, Devise.friendly_token[0, 16])
+ end
+
+ it { is_expected.to eq(true) }
+
+ it 're-encrypts the password as BCrypt' do
+ expect(user.encrypted_password).to start_with('$pbkdf2-sha512$')
+
+ validate_password
+
+ expect(user.encrypted_password).to start_with('$2a$')
+ end
+ end
+ end
+
+ context 'when the default encryption method is PBKDF2+SHA512 and the user password is BCrypt', :fips_mode do
+ it_behaves_like 'password validation fails when the password is encrypted using an unsupported method'
+
+ context 'when the user password BCrypt' do
+ let(:encrypted_password) { Devise::Encryptor.digest(described_class, password) }
+
+ it { is_expected.to eq(true) }
+
+ it 're-encrypts the password as PBKDF2+SHA512' do
+ expect(user.encrypted_password).to start_with('$2a$')
+
+ validate_password
+
+ expect(user.reload.encrypted_password).to start_with('$pbkdf2-sha512$')
+ end
+ end
+ end
+ end
+
+ describe '#password=' do
+ let(:user) { build(:user) }
+ let(:password) { described_class.random_password }
+
+ def compare_bcrypt_password(user, password)
+ Devise::Encryptor.compare(described_class, user.encrypted_password, password)
+ end
+
+ def compare_pbkdf2_password(user, password)
+ Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512.compare(user.encrypted_password, password)
+ end
+
+ context 'when FIPS mode is enabled', :fips_mode do
+ it 'calls PBKDF2 digest and not the default Devise encryptor' do
+ expect(Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512)
+ .to receive(:digest).at_least(:once).and_call_original
+ expect(Devise::Encryptor).not_to receive(:digest)
+
+ user.password = password
+ end
+
+ it 'saves the password in PBKDF2 format' do
+ user.password = password
+ user.save!
+
+ expect(compare_pbkdf2_password(user, password)).to eq(true)
+ expect { compare_bcrypt_password(user, password) }.to raise_error(::BCrypt::Errors::InvalidHash)
+ end
+ end
+
+ it 'calls default Devise encryptor and not the PBKDF2 encryptor' do
+ expect(Devise::Encryptor).to receive(:digest).at_least(:once).and_call_original
+ expect(Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512).not_to receive(:digest)
+
+ user.password = password
+ end
+
+ it 'saves the password in BCrypt format' do
+ user.password = password
+ user.save!
+
+ expect { compare_pbkdf2_password(user, password) }
+ .to raise_error Devise::Pbkdf2Encryptable::Encryptors::InvalidHash
+ expect(compare_bcrypt_password(user, password)).to eq(true)
+ end
+ end
+end
diff --git a/spec/models/concerns/file_store_mounter_spec.rb b/spec/models/concerns/file_store_mounter_spec.rb
new file mode 100644
index 00000000000..459f3d35668
--- /dev/null
+++ b/spec/models/concerns/file_store_mounter_spec.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe FileStoreMounter, :aggregate_failures do
+ let(:uploader_class) do
+ Class.new do
+ def object_store
+ :object_store
+ end
+ end
+ end
+
+ let(:test_class) { Class.new { include(FileStoreMounter) } }
+
+ let(:uploader_instance) { uploader_class.new }
+
+ describe '.mount_file_store_uploader' do
+ using RSpec::Parameterized::TableSyntax
+
+ subject(:mount_file_store_uploader) do
+ test_class.mount_file_store_uploader uploader_class, skip_store_file: skip_store_file, file_field: file_field
+ end
+
+ where(:skip_store_file, :file_field) do
+ true | :file
+ false | :file
+ false | :signed_file
+ true | :signed_file
+ end
+
+ with_them do
+ it 'defines instance methods and registers a callback' do
+ expect(test_class).to receive(:mount_uploader).with(file_field, uploader_class)
+ expect(test_class).to receive(:define_method).with("update_#{file_field}_store")
+ expect(test_class).to receive(:define_method).with("store_#{file_field}_now!")
+
+ if skip_store_file
+ expect(test_class).to receive(:skip_callback).with(:save, :after, "store_#{file_field}!".to_sym)
+ expect(test_class).not_to receive(:after_save)
+ else
+ expect(test_class).not_to receive(:skip_callback)
+ expect(test_class)
+ .to receive(:after_save)
+ .with("update_#{file_field}_store".to_sym, if: "saved_change_to_#{file_field}?".to_sym)
+ end
+
+ mount_file_store_uploader
+ end
+ end
+
+ context 'with an unknown file_field' do
+ let(:skip_store_file) { false }
+ let(:file_field) { 'unknown' }
+
+ it do
+ expect { mount_file_store_uploader }.to raise_error(ArgumentError, 'file_field not allowed: unknown')
+ end
+ end
+ end
+
+ context 'with an instance' do
+ let(:instance) { test_class.new }
+
+ before do
+ allow(test_class).to receive(:mount_uploader)
+ allow(test_class).to receive(:after_save)
+ test_class.mount_file_store_uploader uploader_class
+ end
+
+ describe '#update_file_store' do
+ subject(:update_file_store) { instance.update_file_store }
+
+ it 'calls update column' do
+ expect(instance).to receive(:file).and_return(uploader_instance)
+ expect(instance).to receive(:update_column).with('file_store', :object_store)
+
+ update_file_store
+ end
+ end
+
+ describe '#store_file_now!' do
+ subject(:store_file_now!) { instance.store_file_now! }
+
+ it 'calls the dynamic functions' do
+ expect(instance).to receive(:store_file!)
+ expect(instance).to receive(:update_file_store)
+
+ store_file_now!
+ 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 a6a0e074589..b2ea7b22dea 100644
--- a/spec/models/concerns/has_user_type_spec.rb
+++ b/spec/models/concerns/has_user_type_spec.rb
@@ -88,5 +88,47 @@ RSpec.describe User do
end
end
end
+
+ describe '#redacted_name(viewing_user)' do
+ let_it_be(:viewing_user) { human }
+
+ subject { observed_user.redacted_name(viewing_user) }
+
+ context 'when user is not a project bot' do
+ let(:observed_user) { support_bot }
+
+ it { is_expected.to eq(support_bot.name) }
+ end
+
+ context 'when user is a project_bot' do
+ let(:observed_user) { project_bot }
+
+ context 'when groups are present and user can :read_group' do
+ let_it_be(:group) { create(:group) }
+
+ before do
+ group.add_developer(observed_user)
+ group.add_developer(viewing_user)
+ end
+
+ it { is_expected.to eq(observed_user.name) }
+ end
+
+ context 'when user can :read_project' do
+ let_it_be(:project) { create(:project) }
+
+ before do
+ project.add_developer(observed_user)
+ project.add_developer(viewing_user)
+ end
+
+ it { is_expected.to eq(observed_user.name) }
+ end
+
+ context 'when requester does not have permissions to read project_bot name' do
+ it { is_expected.to eq('****') }
+ end
+ end
+ end
end
end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 8842a36f40a..e553e34ab51 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -337,31 +337,6 @@ RSpec.describe Issuable do
it { expect(MergeRequest.to_ability_name).to eq("merge_request") }
end
- describe "#today?" do
- it "returns true when created today" do
- # Avoid timezone differences and just return exactly what we want
- allow(Date).to receive(:today).and_return(issue.created_at.to_date)
- expect(issue.today?).to be_truthy
- end
-
- it "returns false when not created today" do
- allow(Date).to receive(:today).and_return(Date.yesterday)
- expect(issue.today?).to be_falsey
- end
- end
-
- describe "#new?" do
- it "returns false when created 30 hours ago" do
- allow(issue).to receive(:created_at).and_return(Time.current - 30.hours)
- expect(issue.new?).to be_falsey
- end
-
- it "returns true when created 20 hours ago" do
- allow(issue).to receive(:created_at).and_return(Time.current - 20.hours)
- expect(issue.new?).to be_truthy
- end
- end
-
describe "#sort_by_attribute" do
let(:project) { create(:project) }
@@ -1055,6 +1030,22 @@ RSpec.describe Issuable do
end
end
+ describe '#supports_confidentiality?' do
+ where(:issuable_type, :supports_confidentiality) do
+ :issue | true
+ :incident | true
+ :merge_request | false
+ end
+
+ with_them do
+ let(:issuable) { build_stubbed(issuable_type) }
+
+ subject { issuable.supports_confidentiality? }
+
+ it { is_expected.to eq(supports_confidentiality) }
+ end
+ end
+
describe '#severity' do
subject { issuable.severity }
diff --git a/spec/models/concerns/pg_full_text_searchable_spec.rb b/spec/models/concerns/pg_full_text_searchable_spec.rb
index 3e42a3504ac..98b44a2eec2 100644
--- a/spec/models/concerns/pg_full_text_searchable_spec.rb
+++ b/spec/models/concerns/pg_full_text_searchable_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe PgFullTextSearchable do
- let(:project) { create(:project) }
+ let(:project) { build(:project) }
let(:model_class) do
Class.new(ActiveRecord::Base) do
@@ -76,7 +76,7 @@ RSpec.describe PgFullTextSearchable do
end
describe '.pg_full_text_search' do
- let(:english) { model_class.create!(project: project, title: 'title', description: 'something english') }
+ let(:english) { model_class.create!(project: project, title: 'title', description: 'something description english') }
let(:with_accent) { model_class.create!(project: project, title: 'Jürgen', description: 'Ærøskøbing') }
let(:japanese) { model_class.create!(project: project, title: '日本語 title', description: 'another english description') }
@@ -90,8 +90,19 @@ RSpec.describe PgFullTextSearchable do
expect(model_class.pg_full_text_search('title english')).to contain_exactly(english, japanese)
end
+ it 'searches specified columns only' do
+ matching_object = model_class.create!(project: project, title: 'english', description: 'some description')
+ matching_object.update_search_data!
+
+ expect(model_class.pg_full_text_search('english', matched_columns: %w(title))).to contain_exactly(matching_object)
+ end
+
+ it 'uses prefix matching' do
+ expect(model_class.pg_full_text_search('tit eng')).to contain_exactly(english, japanese)
+ end
+
it 'searches for exact term with quotes' do
- expect(model_class.pg_full_text_search('"something english"')).to contain_exactly(english)
+ expect(model_class.pg_full_text_search('"description english"')).to contain_exactly(english)
end
it 'ignores accents' do
@@ -113,6 +124,27 @@ RSpec.describe PgFullTextSearchable do
expect(model_class.pg_full_text_search('gopher://gitlab.com/gitlab-org/gitlab')).to contain_exactly(with_url)
end
end
+
+ context 'when search term is a path with underscores' do
+ let(:path) { 'browser_ui/5_package/package_registry/maven/maven_group_level_spec.rb' }
+ let(:with_underscore) { model_class.create!(project: project, title: 'issue with path', description: "some #{path} other text") }
+
+ it 'allows searching by the path' do
+ with_underscore.update_search_data!
+
+ expect(model_class.pg_full_text_search(path)).to contain_exactly(with_underscore)
+ end
+ end
+
+ context 'when text has numbers preceded by a dash' do
+ let(:with_dash) { model_class.create!(project: project, title: 'issue with dash', description: 'ABC-123') }
+
+ it 'allows searching by numbers only' do
+ with_dash.update_search_data!
+
+ expect(model_class.pg_full_text_search('123')).to contain_exactly(with_dash)
+ end
+ end
end
describe '#update_search_data!' do
diff --git a/spec/models/concerns/project_features_compatibility_spec.rb b/spec/models/concerns/project_features_compatibility_spec.rb
index 89f34834aa4..f168bedc8eb 100644
--- a/spec/models/concerns/project_features_compatibility_spec.rb
+++ b/spec/models/concerns/project_features_compatibility_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe ProjectFeaturesCompatibility do
let(:features) do
features_enabled + %w(
repository pages operations container_registry package_registry environments feature_flags releases
- monitor
+ monitor infrastructure
)
end
diff --git a/spec/models/concerns/sha_attribute_spec.rb b/spec/models/concerns/sha_attribute_spec.rb
index 790e6936803..fca94b50fee 100644
--- a/spec/models/concerns/sha_attribute_spec.rb
+++ b/spec/models/concerns/sha_attribute_spec.rb
@@ -72,9 +72,10 @@ RSpec.describe ShaAttribute do
end
it 'validates column type' do
- if expected_error == :no_error
+ case expected_error
+ when :no_error
expect { load_schema! }.not_to raise_error
- elsif expected_error == :sha_mismatch_error
+ when :sha_mismatch_error
expect { load_schema! }.to raise_error(
described_class::ShaAttributeTypeMismatchError,
/sha_attribute.*#{column_name}.* should be a :binary column/
@@ -89,9 +90,10 @@ RSpec.describe ShaAttribute do
end
it 'validates column type' do
- if expected_error == :no_error
+ case expected_error
+ when :no_error
expect { load_schema! }.not_to raise_error
- elsif expected_error == :sha_mismatch_error
+ when :sha_mismatch_error
expect { load_schema! }.to raise_error(
described_class::Sha256AttributeTypeMismatchError,
/sha256_attribute.*#{column_name}.* should be a :binary column/
diff --git a/spec/models/concerns/subquery_spec.rb b/spec/models/concerns/subquery_spec.rb
new file mode 100644
index 00000000000..95487fd8c2d
--- /dev/null
+++ b/spec/models/concerns/subquery_spec.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Subquery do
+ let_it_be(:projects) { create_list :project, 3 }
+ let_it_be(:project_ids) { projects.map(&:id) }
+ let(:relation) { Project.where(id: projects) }
+
+ subject { relation.subquery(:id) }
+
+ shared_examples 'subquery as array values' do
+ specify { is_expected.to match_array project_ids }
+ specify { expect { subject }.not_to make_queries }
+ end
+
+ shared_examples 'subquery as relation' do
+ it { is_expected.to be_a ActiveRecord::Relation }
+ specify { expect { subject.load }.to make_queries }
+ end
+
+ shared_context 'when array size exceeds max_limit' do
+ subject { relation.subquery(:id, max_limit: 1) }
+ end
+
+ context 'when relation is not loaded' do
+ it_behaves_like 'subquery as relation'
+
+ context 'when array size exceeds max_limit' do
+ include_context 'when array size exceeds max_limit'
+
+ it_behaves_like 'subquery as relation'
+ end
+ end
+
+ context 'when relation is loaded' do
+ before do
+ relation.load
+ end
+
+ it_behaves_like 'subquery as array values'
+
+ context 'when array size exceeds max_limit' do
+ include_context 'when array size exceeds max_limit'
+
+ it_behaves_like 'subquery as relation'
+ end
+
+ context 'with a select' do
+ let(:relation) { Project.where(id: projects).select(:id) }
+
+ it_behaves_like 'subquery as array values'
+
+ context 'and querying with an unloaded column' do
+ subject { relation.subquery(:namespace_id) }
+
+ it { expect { subject }.to raise_error(ActiveModel::MissingAttributeError) }
+ end
+ end
+ end
+end
diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb
index e8db83b7144..e53fdafe3b1 100644
--- a/spec/models/concerns/token_authenticatable_spec.rb
+++ b/spec/models/concerns/token_authenticatable_spec.rb
@@ -214,19 +214,15 @@ end
RSpec.describe Ci::Build, 'TokenAuthenticatable' do
let(:token_field) { :token }
- let(:build) { FactoryBot.build(:ci_build) }
+ let(:build) { FactoryBot.build(:ci_build, :created) }
it_behaves_like 'TokenAuthenticatable'
describe 'generating new token' do
context 'token is not generated yet' do
describe 'token field accessor' do
- it 'makes it possible to access token' do
- expect(build.token).to be_nil
-
- build.save!
-
- expect(build.token).to be_present
+ it 'does not generate a token when saving a build' do
+ expect { build.save! }.not_to change(build, :token).from(nil)
end
end
diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb
index 0033e9bbd08..9af53bae204 100644
--- a/spec/models/container_repository_spec.rb
+++ b/spec/models/container_repository_spec.rb
@@ -871,6 +871,28 @@ RSpec.describe ContainerRepository, :aggregate_failures do
end
end
+ describe '#set_delete_ongoing_status', :freeze_time do
+ let_it_be(:repository) { create(:container_repository) }
+
+ subject { repository.set_delete_ongoing_status }
+
+ it 'updates deletion status attributes' do
+ expect { subject }.to change(repository, :status).from(nil).to('delete_ongoing')
+ .and change(repository, :delete_started_at).from(nil).to(Time.zone.now)
+ end
+ end
+
+ describe '#set_delete_scheduled_status' do
+ let_it_be(:repository) { create(:container_repository, :status_delete_ongoing, delete_started_at: 3.minutes.ago) }
+
+ subject { repository.set_delete_scheduled_status }
+
+ it 'updates delete attributes' do
+ expect { subject }.to change(repository, :status).from('delete_ongoing').to('delete_scheduled')
+ .and change(repository, :delete_started_at).to(nil)
+ end
+ end
+
context 'registry migration' do
before do
allow(repository.gitlab_api_client).to receive(:supports_gitlab_api?).and_return(true)
@@ -1274,6 +1296,16 @@ RSpec.describe ContainerRepository, :aggregate_failures do
it { is_expected.to contain_exactly(repository1, repository3) }
end
+ describe '.with_stale_delete_at' do
+ let_it_be(:repository1) { create(:container_repository, delete_started_at: 1.day.ago) }
+ let_it_be(:repository2) { create(:container_repository, delete_started_at: 25.minutes.ago) }
+ let_it_be(:repository3) { create(:container_repository, delete_started_at: 1.week.ago) }
+
+ subject { described_class.with_stale_delete_at(27.minutes.ago) }
+
+ it { is_expected.to contain_exactly(repository1, repository3) }
+ end
+
describe '.waiting_for_cleanup' do
let_it_be(:repository_cleanup_scheduled) { create(:container_repository, :cleanup_scheduled) }
let_it_be(:repository_cleanup_unfinished) { create(:container_repository, :cleanup_unfinished) }
diff --git a/spec/models/dependency_proxy/group_setting_spec.rb b/spec/models/dependency_proxy/group_setting_spec.rb
index c4c4a877d50..4da1fe42ff2 100644
--- a/spec/models/dependency_proxy/group_setting_spec.rb
+++ b/spec/models/dependency_proxy/group_setting_spec.rb
@@ -7,6 +7,11 @@ RSpec.describe DependencyProxy::GroupSetting, type: :model do
it { is_expected.to belong_to(:group) }
end
+ describe 'default values' do
+ it { is_expected.to be_enabled }
+ it { expect(described_class.new(enabled: false)).not_to be_enabled }
+ end
+
describe 'validations' do
it { is_expected.to validate_presence_of(:group) }
end
diff --git a/spec/models/deploy_token_spec.rb b/spec/models/deploy_token_spec.rb
index 635326eeadc..04763accc42 100644
--- a/spec/models/deploy_token_spec.rb
+++ b/spec/models/deploy_token_spec.rb
@@ -427,7 +427,7 @@ RSpec.describe DeployToken do
end
describe '.gitlab_deploy_token' do
- let(:project) { create(:project ) }
+ let(:project) { create(:project) }
subject { project.deploy_tokens.gitlab_deploy_token }
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index b91d836f82f..daa65f528e9 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -388,16 +388,31 @@ RSpec.describe Deployment do
end
context 'when deployment is behind current deployment' do
+ let_it_be(:commits) { project.repository.commits('master', limit: 2) }
+
let!(:deployment) do
- create(:deployment, :success, project: project, environment: environment, finished_at: 1.year.ago)
+ create(:deployment, :success, project: project, environment: environment,
+ finished_at: 1.year.ago, sha: commits[0].sha)
end
let!(:last_deployment) do
- create(:deployment, :success, project: project, environment: environment)
+ create(:deployment, :success, project: project, environment: environment, sha: commits[1].sha)
end
it { is_expected.to be_truthy }
end
+
+ context 'when deployment is the same sha as the current deployment' do
+ let!(:deployment) do
+ create(:deployment, :success, project: project, environment: environment, finished_at: 1.year.ago)
+ end
+
+ let!(:last_deployment) do
+ create(:deployment, :success, project: project, environment: environment, sha: deployment.sha)
+ end
+
+ it { is_expected.to be_falsey }
+ end
end
describe '#success?' do
@@ -1323,9 +1338,12 @@ RSpec.describe Deployment do
subject { deployment.tags }
it 'will return tags related to this deployment' do
- expect(project.repository).to receive(:tag_names_contains).with(deployment.sha, limit: 100).and_return(['test'])
+ expect(project.repository).to receive(:refs_by_oid).with(oid: deployment.sha,
+ limit: 100,
+ ref_patterns: [Gitlab::Git::TAG_REF_PREFIX])
+ .and_return(["#{Gitlab::Git::TAG_REF_PREFIX}test"])
- is_expected.to match_array(['test'])
+ is_expected.to match_array(['refs/tags/test'])
end
end
diff --git a/spec/models/diff_discussion_spec.rb b/spec/models/diff_discussion_spec.rb
index 7a57f895b8a..fdfc4ec7cc4 100644
--- a/spec/models/diff_discussion_spec.rb
+++ b/spec/models/diff_discussion_spec.rb
@@ -128,7 +128,7 @@ RSpec.describe DiffDiscussion do
end
describe '#cache_key' do
- let(:notes_sha) { Digest::SHA1.hexdigest("#{diff_note.post_processed_cache_key}") }
+ let(:notes_sha) { Digest::SHA1.hexdigest(diff_note.post_processed_cache_key.to_s) }
let(:position_sha) { Digest::SHA1.hexdigest(diff_note.position.to_json) }
it 'returns the cache key with the position sha' do
diff --git a/spec/models/diff_viewer/server_side_spec.rb b/spec/models/diff_viewer/server_side_spec.rb
index db0814af422..8990aa94b47 100644
--- a/spec/models/diff_viewer/server_side_spec.rb
+++ b/spec/models/diff_viewer/server_side_spec.rb
@@ -16,34 +16,6 @@ RSpec.describe DiffViewer::ServerSide do
subject { viewer_class.new(diff_file) }
- describe '#prepare!' do
- before do
- stub_feature_flags(disable_load_entire_blob_for_diff_viewer: feature_flag_enabled)
- end
-
- context 'when the disable_load_entire_blob_for_diff_viewer flag is disabled' do
- let(:feature_flag_enabled) { false }
-
- it 'loads all diff file data' do
- subject
- expect(diff_file).to receive_message_chain(:old_blob, :load_all_data!)
- expect(diff_file).to receive_message_chain(:new_blob, :load_all_data!)
- subject.prepare!
- end
- end
-
- context 'when the disable_load_entire_blob_for_diff_viewer flag is enabled' do
- let(:feature_flag_enabled) { true }
-
- it 'does not load file data' do
- subject
- expect(diff_file).not_to receive(:old_blob)
- expect(diff_file).not_to receive(:new_blob)
- subject.prepare!
- end
- end
- end
-
describe '#render_error' do
context 'when the diff file is stored externally' do
before do
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index a442856d993..8a3d43f58e0 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -884,8 +884,8 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
describe '#actions_for' do
let(:deployment) { create(:deployment, :success, environment: environment) }
let(:pipeline) { deployment.deployable.pipeline }
- let!(:review_action) { create(:ci_build, :manual, name: 'review-apps', pipeline: pipeline, environment: 'review/$CI_COMMIT_REF_NAME' ) }
- let!(:production_action) { create(:ci_build, :manual, name: 'production', pipeline: pipeline, environment: 'production' ) }
+ let!(:review_action) { create(:ci_build, :manual, name: 'review-apps', pipeline: pipeline, environment: 'review/$CI_COMMIT_REF_NAME') }
+ let!(:production_action) { create(:ci_build, :manual, name: 'production', pipeline: pipeline, environment: 'production') }
it 'returns a list of actions with matching environment' do
expect(environment.actions_for('review/master')).to contain_exactly(review_action)
diff --git a/spec/models/environment_status_spec.rb b/spec/models/environment_status_spec.rb
index a9aa5698ebb..2f1edf9ab94 100644
--- a/spec/models/environment_status_spec.rb
+++ b/spec/models/environment_status_spec.rb
@@ -37,7 +37,7 @@ RSpec.describe EnvironmentStatus do
context 'multiple deployments' do
it {
- new_deployment = create(:deployment, :succeed, environment: deployment.environment, sha: deployment.sha )
+ new_deployment = create(:deployment, :succeed, environment: deployment.environment, sha: deployment.sha)
is_expected.to eq(new_deployment)
}
end
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 30e73d84cfb..d48f6f7f3e4 100644
--- a/spec/models/error_tracking/project_error_tracking_setting_spec.rb
+++ b/spec/models/error_tracking/project_error_tracking_setting_spec.rb
@@ -187,39 +187,11 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do
end
end
- describe '#reactive_cache_limit_enabled?' do
- subject { setting.reactive_cache_limit_enabled? }
-
- it { is_expected.to eq(true) }
-
- context 'when feature flag disabled' do
- before do
- stub_feature_flags(error_tracking_sentry_limit: false)
- end
-
- it { is_expected.to eq(false) }
- end
- end
-
describe '#sentry_client' do
subject { setting.sentry_client }
it { is_expected.to be_a(ErrorTracking::SentryClient) }
it { is_expected.to have_attributes(url: setting.api_url, token: setting.token) }
-
- describe '#validate_size_guarded_by_feature_flag?' do
- subject { setting.sentry_client.validate_size_guarded_by_feature_flag? }
-
- it { is_expected.to eq(true) }
-
- context 'when feature flag disabled' do
- before do
- stub_feature_flags(error_tracking_sentry_limit: false)
- end
-
- it { is_expected.to eq(false) }
- end
- end
end
describe '#list_sentry_issues' do
diff --git a/spec/models/event_collection_spec.rb b/spec/models/event_collection_spec.rb
index 67b58c7bf6f..40b7930f02b 100644
--- a/spec/models/event_collection_spec.rb
+++ b/spec/models/event_collection_spec.rb
@@ -5,175 +5,165 @@ require 'spec_helper'
RSpec.describe EventCollection do
include DesignManagementTestHelpers
- shared_examples 'EventCollection examples' do
- describe '#to_a' do
- let_it_be(:group) { create(:group) }
- let_it_be(:project) { create(:project_empty_repo, group: group) }
- let_it_be(:projects) { Project.where(id: project.id) }
- let_it_be(:user) { create(:user) }
- let_it_be(:merge_request) { create(:merge_request) }
-
- before do
- enable_design_management
- end
+ describe '#to_a' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project_empty_repo, group: group) }
+ let_it_be(:projects) { Project.where(id: project.id) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:merge_request) { create(:merge_request) }
- context 'with project events' do
- let_it_be(:push_event_payloads) do
- Array.new(9) do
- create(:push_event_payload,
- event: create(:push_event, project: project, author: user))
- end
- end
+ before do
+ enable_design_management
+ end
- let_it_be(:merge_request_events) { create_list(:event, 10, :merged, project: project, target: merge_request) }
- let_it_be(:closed_issue_event) { create(:closed_issue_event, project: project, author: user) }
- let_it_be(:wiki_page_event) { create(:wiki_page_event, project: project) }
- let_it_be(:design_event) { create(:design_event, project: project) }
-
- let(:push_events) { push_event_payloads.map(&:event) }
-
- it 'returns an Array of all event types when no filter is passed', :aggregate_failures do
- most_recent_20_events = [
- wiki_page_event,
- design_event,
- closed_issue_event,
- *push_events,
- *merge_request_events
- ].sort_by(&:id).reverse.take(20)
- events = described_class.new(projects).to_a
-
- expect(events).to be_an_instance_of(Array)
- expect(events).to match_array(most_recent_20_events)
+ context 'with project events' do
+ let_it_be(:push_event_payloads) do
+ Array.new(9) do
+ create(:push_event_payload,
+ event: create(:push_event, project: project, author: user))
end
+ end
- it 'includes the wiki page events when using to_a' do
- events = described_class.new(projects).to_a
+ let_it_be(:merge_request_events) { create_list(:event, 10, :merged, project: project, target: merge_request) }
+ let_it_be(:closed_issue_event) { create(:closed_issue_event, project: project, author: user) }
+ let_it_be(:wiki_page_event) { create(:wiki_page_event, project: project) }
+ let_it_be(:design_event) { create(:design_event, project: project) }
+
+ let(:push_events) { push_event_payloads.map(&:event) }
+
+ it 'returns an Array of all event types when no filter is passed', :aggregate_failures do
+ most_recent_20_events = [
+ wiki_page_event,
+ design_event,
+ closed_issue_event,
+ *push_events,
+ *merge_request_events
+ ].sort_by(&:id).reverse.take(20)
+ events = described_class.new(projects).to_a
+
+ expect(events).to be_an_instance_of(Array)
+ expect(events).to match_array(most_recent_20_events)
+ end
- expect(events).to include(wiki_page_event)
- end
+ it 'includes the wiki page events when using to_a' do
+ events = described_class.new(projects).to_a
- it 'includes the design events' do
- collection = described_class.new(projects)
+ expect(events).to include(wiki_page_event)
+ end
- expect(collection.to_a).to include(design_event)
- expect(collection.all_project_events).to include(design_event)
- end
+ it 'includes the design events' do
+ collection = described_class.new(projects)
- it 'includes the wiki page events when using all_project_events' do
- events = described_class.new(projects).all_project_events
+ expect(collection.to_a).to include(design_event)
+ expect(collection.all_project_events).to include(design_event)
+ end
- expect(events).to include(wiki_page_event)
- end
+ it 'includes the wiki page events when using all_project_events' do
+ events = described_class.new(projects).all_project_events
- it 'applies a limit to the number of events' do
- events = described_class.new(projects).to_a
+ expect(events).to include(wiki_page_event)
+ end
- expect(events.length).to eq(20)
- end
+ it 'applies a limit to the number of events' do
+ events = described_class.new(projects).to_a
- it 'can paginate through events' do
- events = described_class.new(projects, limit: 5, offset: 15).to_a
+ expect(events.length).to eq(20)
+ end
- expect(events.length).to eq(5)
- end
+ it 'can paginate through events' do
+ events = described_class.new(projects, limit: 5, offset: 15).to_a
- it 'returns an empty Array when crossing the maximum page number' do
- events = described_class.new(projects, limit: 1, offset: 15).to_a
+ expect(events.length).to eq(5)
+ end
- expect(events).to be_empty
- end
+ it 'returns an empty Array when crossing the maximum page number' do
+ events = described_class.new(projects, limit: 1, offset: 15).to_a
- it 'allows filtering of events using an EventFilter, returning single item' do
- filter = EventFilter.new(EventFilter::ISSUE)
- events = described_class.new(projects, filter: filter).to_a
+ expect(events).to be_empty
+ end
- expect(events).to contain_exactly(closed_issue_event)
- end
+ it 'allows filtering of events using an EventFilter, returning single item' do
+ filter = EventFilter.new(EventFilter::ISSUE)
+ events = described_class.new(projects, filter: filter).to_a
- it 'allows filtering of events using an EventFilter, returning several items' do
- filter = EventFilter.new(EventFilter::MERGED)
- events = described_class.new(projects, filter: filter).to_a
+ expect(events).to contain_exactly(closed_issue_event)
+ end
- expect(events).to match_array(merge_request_events)
- end
+ it 'allows filtering of events using an EventFilter, returning several items' do
+ filter = EventFilter.new(EventFilter::MERGED)
+ events = described_class.new(projects, filter: filter).to_a
- it 'allows filtering of events using an EventFilter, returning pushes' do
- filter = EventFilter.new(EventFilter::PUSH)
- events = described_class.new(projects, filter: filter).to_a
+ expect(events).to match_array(merge_request_events)
+ end
- expect(events).to match_array(push_events)
- end
+ it 'allows filtering of events using an EventFilter, returning pushes' do
+ filter = EventFilter.new(EventFilter::PUSH)
+ events = described_class.new(projects, filter: filter).to_a
+
+ expect(events).to match_array(push_events)
end
+ end
- context 'with group events' do
- let(:groups) { group.self_and_descendants.public_or_visible_to_user(user) }
- let(:subject) { described_class.new(projects, groups: groups).to_a }
+ context 'with group events' do
+ let(:groups) { group.self_and_descendants.public_or_visible_to_user(user) }
+ let(:subject) { described_class.new(projects, groups: groups).to_a }
- it 'includes also group events' do
- subgroup = create(:group, parent: group)
- event1 = create(:event, project: project, author: user)
- event2 = create(:event, project: nil, group: group, author: user)
- event3 = create(:event, project: nil, group: subgroup, author: user)
+ it 'includes also group events' do
+ subgroup = create(:group, parent: group)
+ event1 = create(:event, project: project, author: user)
+ event2 = create(:event, project: nil, group: group, author: user)
+ event3 = create(:event, project: nil, group: subgroup, author: user)
- expect(subject).to eq([event3, event2, event1])
- end
+ expect(subject).to eq([event3, event2, event1])
+ end
- it 'does not include events from inaccessible groups' do
- subgroup = create(:group, :private, parent: group)
- event1 = create(:event, project: nil, group: group, author: user)
- create(:event, project: nil, group: subgroup, author: user)
+ it 'does not include events from inaccessible groups' do
+ subgroup = create(:group, :private, parent: group)
+ event1 = create(:event, project: nil, group: group, author: user)
+ create(:event, project: nil, group: subgroup, author: user)
- expect(subject).to match_array([event1])
- end
+ expect(subject).to match_array([event1])
+ end
- context 'pagination through events' do
- let_it_be(:project_events) { create_list(:event, 10, project: project) }
- let_it_be(:group_events) { create_list(:event, 10, group: group, author: user) }
+ context 'with pagination through events' do
+ let_it_be(:project_events) { create_list(:event, 10, project: project) }
+ let_it_be(:group_events) { create_list(:event, 10, group: group, author: user) }
- let(:subject) { described_class.new(projects, limit: 10, offset: 5, groups: groups).to_a }
+ let(:subject) { described_class.new(projects, limit: 10, offset: 5, groups: groups).to_a }
- it 'returns recent groups and projects events' do
- recent_events_with_offset = (project_events[5..] + group_events[..4]).reverse
+ it 'returns recent groups and projects events' do
+ recent_events_with_offset = (project_events[5..] + group_events[..4]).reverse
- expect(subject).to eq(recent_events_with_offset)
- end
+ expect(subject).to eq(recent_events_with_offset)
end
+ end
- context 'project exclusive event types' do
- using RSpec::Parameterized::TableSyntax
+ context 'with project exclusive event types' do
+ using RSpec::Parameterized::TableSyntax
- where(:filter, :event) do
- EventFilter::PUSH | lazy { create(:push_event, project: project) }
- EventFilter::MERGED | lazy { create(:event, :merged, project: project, target: merge_request) }
- EventFilter::TEAM | lazy { create(:event, :joined, project: project) }
- EventFilter::ISSUE | lazy { create(:closed_issue_event, project: project) }
- EventFilter::DESIGNS | lazy { create(:design_event, project: project) }
- end
+ where(:filter, :event) do
+ EventFilter::PUSH | lazy { create(:push_event, project: project) }
+ EventFilter::MERGED | lazy { create(:event, :merged, project: project, target: merge_request) }
+ EventFilter::TEAM | lazy { create(:event, :joined, project: project) }
+ EventFilter::ISSUE | lazy { create(:closed_issue_event, project: project) }
+ EventFilter::DESIGNS | lazy { create(:design_event, project: project) }
+ end
- with_them do
- let(:subject) do
- described_class.new(projects, groups: Group.where(id: group.id), filter: EventFilter.new(filter))
- end
+ with_them do
+ let(:subject) do
+ described_class.new(projects, groups: Group.where(id: group.id), filter: EventFilter.new(filter))
+ end
- it "queries only project events" do
- expected_event = event # Forcing lazy evaluation
- expect(subject).to receive(:project_events).with(no_args).and_call_original
- expect(subject).not_to receive(:group_events)
+ it "queries only project events" do
+ expected_event = event # Forcing lazy evaluation
+ expect(subject).to receive(:project_events).with(no_args).and_call_original
+ expect(subject).not_to receive(:group_events)
- expect(subject.to_a).to match_array(expected_event)
- end
+ expect(subject.to_a).to match_array(expected_event)
end
end
end
end
- end
-
- context 'when the optimized_project_and_group_activity_queries FF is on' do
- before do
- stub_feature_flags(optimized_project_and_group_activity_queries: true)
- end
-
- it_behaves_like 'EventCollection examples'
it 'returns no events if no projects are passed' do
events = described_class.new(Project.none).to_a
@@ -181,12 +171,4 @@ RSpec.describe EventCollection do
expect(events).to be_empty
end
end
-
- context 'when the optimized_project_and_group_activity_queries FF is off' do
- before do
- stub_feature_flags(optimized_project_and_group_activity_queries: false)
- end
-
- it_behaves_like 'EventCollection examples'
- end
end
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index 9700852e567..9579c4c2d27 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe Event do
describe 'after_create :set_last_repository_updated_at' do
context 'with a push event' do
it 'updates the project last_repository_updated_at and updated_at' do
- project.touch(:last_repository_updated_at, time: 1.year.ago) # rubocop: disable Rails/SkipsModelValidations
+ project.touch(:last_repository_updated_at, time: 1.year.ago)
event = create_push_event(project, project.first_owner)
@@ -431,8 +431,6 @@ RSpec.describe Event do
include_examples 'visibility examples' do
let(:visibility) { visible_to_none_except(:member) }
end
-
- include_examples 'visible to author', true
end
context 'private project' do
@@ -866,7 +864,7 @@ RSpec.describe Event do
end
it 'updates the project' do
- project.touch(:last_activity_at, time: 1.year.ago) # rubocop: disable Rails/SkipsModelValidations
+ project.touch(:last_activity_at, time: 1.year.ago)
event = create_push_event(project, project.first_owner)
@@ -882,7 +880,7 @@ RSpec.describe Event do
"project:#{project.id}")
end
- project.touch(:last_activity_at, time: 1.year.ago) # rubocop: disable Rails/SkipsModelValidations
+ project.touch(:last_activity_at, time: 1.year.ago)
create_push_event(project, project.first_owner)
end
diff --git a/spec/models/experiment_spec.rb b/spec/models/experiment_spec.rb
deleted file mode 100644
index de6ce3ba053..00000000000
--- a/spec/models/experiment_spec.rb
+++ /dev/null
@@ -1,428 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Experiment do
- include AfterNextHelpers
-
- subject { build(:experiment) }
-
- describe 'associations' do
- it { is_expected.to have_many(:experiment_users) }
- it { is_expected.to have_many(:experiment_subjects) }
- end
-
- describe 'validations' do
- 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(255) }
- end
-
- describe '.add_user' do
- let_it_be(:experiment_name) { :experiment_key }
- let_it_be(:user) { 'a user' }
- let_it_be(:group) { 'a group' }
- let_it_be(:context) { { a: 42 } }
-
- subject(:add_user) { described_class.add_user(experiment_name, group, user, context) }
-
- context 'when an experiment with the provided name does not exist' do
- it 'creates a new experiment record' do
- allow_next_instance_of(described_class) do |experiment|
- allow(experiment).to receive(:record_user_and_group).with(user, group, context)
- end
- expect { add_user }.to change(described_class, :count).by(1)
- end
-
- it 'forwards the user, group_type, and context to the instance' do
- expect_next_instance_of(described_class) do |experiment|
- expect(experiment).to receive(:record_user_and_group).with(user, group, context)
- end
- add_user
- end
- end
-
- context 'when an experiment with the provided name already exists' do
- let_it_be(:experiment) { create(:experiment, name: experiment_name) }
-
- it 'does not create a new experiment record' do
- allow_next_found_instance_of(described_class) do |experiment|
- allow(experiment).to receive(:record_user_and_group).with(user, group, context)
- end
- expect { add_user }.not_to change(described_class, :count)
- end
-
- it 'forwards the user, group_type, and context to the instance' do
- expect_next_found_instance_of(described_class) do |experiment|
- expect(experiment).to receive(:record_user_and_group).with(user, group, context)
- end
- add_user
- end
- end
-
- it 'works without the optional context argument' do
- allow_next_instance_of(described_class) do |experiment|
- expect(experiment).to receive(:record_user_and_group).with(user, group, {})
- end
-
- expect { described_class.add_user(experiment_name, group, user) }.not_to raise_error
- end
- end
-
- describe '.add_group' do
- let_it_be(:experiment_name) { :experiment_key }
- let_it_be(:variant) { :control }
- let_it_be(:group) { build(:group) }
-
- subject(:add_group) { described_class.add_group(experiment_name, variant: variant, group: group) }
-
- context 'when an experiment with the provided name does not exist' do
- it 'creates a new experiment record' do
- allow_next(described_class, name: :experiment_key)
- .to receive(:record_subject_and_variant!).with(group, variant)
-
- expect { add_group }.to change(described_class, :count).by(1)
- end
- end
-
- context 'when an experiment with the provided name already exists' do
- before do
- create(:experiment, name: experiment_name)
- end
-
- it 'does not create a new experiment record' do
- expect { add_group }.not_to change(described_class, :count)
- end
- end
- end
-
- describe '.record_conversion_event' do
- let_it_be(:user) { build(:user) }
- let_it_be(:context) { { a: 42 } }
-
- let(:experiment_key) { :test_experiment }
-
- subject(:record_conversion_event) { described_class.record_conversion_event(experiment_key, user, context) }
-
- context 'when no matching experiment exists' do
- it 'creates the experiment and uses it' do
- expect_next_instance_of(described_class) do |experiment|
- expect(experiment).to receive(:record_conversion_event_for_user)
- end
- expect { record_conversion_event }.to change { described_class.count }.by(1)
- end
-
- context 'but we are unable to successfully create one' do
- let(:experiment_key) { nil }
-
- it 'raises a RecordInvalid error' do
- expect { record_conversion_event }.to raise_error(ActiveRecord::RecordInvalid)
- end
- end
- end
-
- context 'when a matching experiment already exists' do
- before do
- create(:experiment, name: experiment_key)
- end
-
- it 'sends record_conversion_event_for_user to the experiment instance' do
- expect_next_found_instance_of(described_class) do |experiment|
- expect(experiment).to receive(:record_conversion_event_for_user).with(user, context)
- end
- record_conversion_event
- end
- end
- end
-
- shared_examples 'experiment user with context' do
- let_it_be(:context) { { a: 42, 'b' => 34, 'c': { c1: 100, c2: 'c2', e: :e }, d: [1, 3] } }
- let_it_be(:initial_expected_context) { { 'a' => 42, 'b' => 34, 'c' => { 'c1' => 100, 'c2' => 'c2', 'e' => 'e' }, 'd' => [1, 3] } }
-
- before do
- subject
- experiment.record_user_and_group(user, :experimental, {})
- end
-
- it 'has an initial context with stringified keys' do
- expect(ExperimentUser.last.context).to eq(initial_expected_context)
- end
-
- context 'when updated' do
- before do
- subject
- experiment.record_user_and_group(user, :experimental, new_context)
- end
-
- context 'with an empty context' do
- let_it_be(:new_context) { {} }
-
- it 'keeps the initial context' do
- expect(ExperimentUser.last.context).to eq(initial_expected_context)
- end
- end
-
- context 'with string keys' do
- let_it_be(:new_context) { { f: :some_symbol } }
-
- it 'adds new symbols stringified' do
- expected_context = initial_expected_context.merge('f' => 'some_symbol')
- expect(ExperimentUser.last.context).to eq(expected_context)
- end
- end
-
- context 'with atomic values or array values' do
- let_it_be(:new_context) { { b: 97, d: [99] } }
-
- it 'overrides the values' do
- expected_context = { 'a' => 42, 'b' => 97, 'c' => { 'c1' => 100, 'c2' => 'c2', 'e' => 'e' }, 'd' => [99] }
- expect(ExperimentUser.last.context).to eq(expected_context)
- end
- end
-
- context 'with nested hashes' do
- let_it_be(:new_context) { { c: { g: 107 } } }
-
- it 'inserts nested additional values in the same keys' do
- expected_context = initial_expected_context.deep_merge('c' => { 'g' => 107 })
- expect(ExperimentUser.last.context).to eq(expected_context)
- end
- end
- end
- end
-
- describe '#record_conversion_event_for_user' do
- let_it_be(:user) { create(:user) }
- let_it_be(:experiment) { create(:experiment) }
- let_it_be(:context) { { a: 42 } }
-
- subject { experiment.record_conversion_event_for_user(user, context) }
-
- context 'when no existing experiment_user record exists for the given user' do
- it 'does not update or create an experiment_user record' do
- expect { subject }.not_to change { ExperimentUser.all.to_a }
- end
- end
-
- context 'when an existing experiment_user exists for the given user' do
- context 'but it has already been converted' do
- let!(:experiment_user) { create(:experiment_user, experiment: experiment, user: user, converted_at: 2.days.ago) }
-
- it 'does not update the converted_at value' do
- expect { subject }.not_to change { experiment_user.converted_at }
- end
-
- it_behaves_like 'experiment user with context' do
- before do
- experiment.record_user_and_group(user, :experimental, context)
- end
- end
- end
-
- context 'and it has not yet been converted' do
- let(:experiment_user) { create(:experiment_user, experiment: experiment, user: user) }
-
- it 'updates the converted_at value' do
- expect { subject }.to change { experiment_user.reload.converted_at }
- end
-
- it_behaves_like 'experiment user with context' do
- before do
- experiment.record_user_and_group(user, :experimental, context)
- end
- end
- end
- end
- end
-
- describe '#record_conversion_event_for_subject' do
- let_it_be(:user) { create(:user) }
- let_it_be(:experiment) { create(:experiment) }
- let_it_be(:context) { { a: 42 } }
-
- subject(:record_conversion) { experiment.record_conversion_event_for_subject(user, context) }
-
- context 'when no existing experiment_subject record exists for the given user' do
- it 'does not update or create an experiment_subject record' do
- expect { record_conversion }.not_to change { ExperimentSubject.all.to_a }
- end
- end
-
- context 'when an existing experiment_subject exists for the given user' do
- context 'but it has already been converted' do
- let(:experiment_subject) { create(:experiment_subject, experiment: experiment, user: user, converted_at: 2.days.ago) }
-
- it 'does not update the converted_at value' do
- expect { record_conversion }.not_to change { experiment_subject.converted_at }
- end
- end
-
- context 'and it has not yet been converted' do
- let(:experiment_subject) { create(:experiment_subject, experiment: experiment, user: user) }
-
- it 'updates the converted_at value' do
- expect { record_conversion }.to change { experiment_subject.reload.converted_at }
- end
- end
-
- context 'with no existing context' do
- let(:experiment_subject) { create(:experiment_subject, experiment: experiment, user: user) }
-
- it 'updates the context' do
- expect { record_conversion }.to change { experiment_subject.reload.context }.to('a' => 42)
- end
- end
-
- context 'with an existing context' do
- let(:experiment_subject) { create(:experiment_subject, experiment: experiment, user: user, converted_at: 2.days.ago, context: { b: 1 } ) }
-
- it 'merges the context' do
- expect { record_conversion }.to change { experiment_subject.reload.context }.to('a' => 42, 'b' => 1)
- end
- end
- end
- end
-
- describe '#record_subject_and_variant!' do
- let_it_be(:subject_to_record) { create(:group) }
- let_it_be(:variant) { :control }
- let_it_be(:experiment) { create(:experiment) }
-
- subject(:record_subject_and_variant!) { experiment.record_subject_and_variant!(subject_to_record, variant) }
-
- context 'when no existing experiment_subject record exists for the given subject' do
- it 'creates an experiment_subject record' do
- expect { record_subject_and_variant! }.to change(ExperimentSubject, :count).by(1)
- expect(ExperimentSubject.last.variant).to eq(variant.to_s)
- end
- end
-
- context 'when an existing experiment_subject exists for the given subject' do
- let_it_be(:experiment_subject) do
- create(:experiment_subject, experiment: experiment, namespace: subject_to_record, user: nil, variant: :experimental)
- end
-
- context 'when it belongs to the same variant' do
- let(:variant) { :experimental }
-
- it 'does not initiate a transaction' do
- expect(Experiment.connection).not_to receive(:transaction)
-
- subject
- end
- end
-
- context 'but it belonged to a different variant' do
- it 'updates the variant value' do
- expect { record_subject_and_variant! }.to change { experiment_subject.reload.variant }.to('control')
- end
- end
- end
-
- describe 'providing a subject to record' do
- context 'when given a group as subject' do
- it 'saves the namespace as the experiment subject' do
- expect(record_subject_and_variant!.namespace).to eq(subject_to_record)
- end
- end
-
- context 'when given a users namespace as subject' do
- let_it_be(:subject_to_record) { build(:namespace) }
-
- it 'saves the namespace as the experiment_subject' do
- expect(record_subject_and_variant!.namespace).to eq(subject_to_record)
- end
- end
-
- context 'when given a user as subject' do
- let_it_be(:subject_to_record) { build(:user) }
-
- it 'saves the user as experiment_subject user' do
- expect(record_subject_and_variant!.user).to eq(subject_to_record)
- end
- end
-
- context 'when given a project as subject' do
- let_it_be(:subject_to_record) { build(:project) }
-
- it 'saves the project as experiment_subject user' do
- expect(record_subject_and_variant!.project).to eq(subject_to_record)
- end
- end
-
- context 'when given no subject' do
- let_it_be(:subject_to_record) { nil }
-
- it 'raises an error' do
- expect { record_subject_and_variant! }.to raise_error('Incompatible subject provided!')
- end
- end
-
- context 'when given an incompatible subject' do
- let_it_be(:subject_to_record) { build(:ci_build) }
-
- it 'raises an error' do
- expect { record_subject_and_variant! }.to raise_error('Incompatible subject provided!')
- end
- end
- end
- end
-
- describe '#record_user_and_group' do
- let_it_be(:experiment) { create(:experiment) }
- let_it_be(:user) { create(:user) }
- let_it_be(:group) { :control }
- let_it_be(:context) { { a: 42 } }
-
- subject { experiment.record_user_and_group(user, group, context) }
-
- context 'when an experiment_user does not yet exist for the given user' do
- it 'creates a new experiment_user record' do
- expect { subject }.to change(ExperimentUser, :count).by(1)
- end
-
- it 'assigns the correct group_type to the experiment_user' do
- subject
-
- expect(ExperimentUser.last.group_type).to eq('control')
- end
-
- it 'adds the correct context to the experiment_user' do
- subject
-
- expect(ExperimentUser.last.context).to eq({ 'a' => 42 })
- end
- end
-
- context 'when an experiment_user already exists for the given user' do
- before do
- # Create an existing experiment_user for this experiment and the :control group
- experiment.record_user_and_group(user, :control)
- end
-
- it 'does not create a new experiment_user record' do
- expect { subject }.not_to change(ExperimentUser, :count)
- end
-
- context 'when group type or context did not change' do
- let(:context) { {} }
-
- it 'does not initiate a transaction' do
- expect(Experiment.connection).not_to receive(:transaction)
-
- subject
- end
- end
-
- context 'but the group_type and context has changed' do
- let(:group) { :experimental }
-
- it 'updates the existing experiment_user record with group_type' do
- expect { subject }.to change { ExperimentUser.last.group_type }
- end
- end
-
- it_behaves_like 'experiment user with context'
- end
- end
-end
diff --git a/spec/models/experiment_subject_spec.rb b/spec/models/experiment_subject_spec.rb
deleted file mode 100644
index d86dc3cbf65..00000000000
--- a/spec/models/experiment_subject_spec.rb
+++ /dev/null
@@ -1,72 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ExperimentSubject, type: :model do
- describe 'associations' do
- it { is_expected.to belong_to(:experiment) }
- it { is_expected.to belong_to(:user) }
- it { is_expected.to belong_to(:namespace) }
- it { is_expected.to belong_to(:project) }
- end
-
- describe 'validations' do
- it { is_expected.to validate_presence_of(:experiment) }
-
- describe 'must_have_one_subject_present' do
- let(:experiment_subject) { build(:experiment_subject, user: nil, namespace: nil, project: nil) }
- let(:error_message) { 'Must have exactly one of User, Namespace, or Project.' }
-
- it 'fails when no subject is present' do
- expect(experiment_subject).not_to be_valid
- expect(experiment_subject.errors[:base]).to include(error_message)
- end
-
- it 'passes when user subject is present' do
- experiment_subject.user = build(:user)
- expect(experiment_subject).to be_valid
- end
-
- it 'passes when namespace subject is present' do
- experiment_subject.namespace = build(:group)
- expect(experiment_subject).to be_valid
- end
-
- it 'passes when project subject is present' do
- experiment_subject.project = build(:project)
- expect(experiment_subject).to be_valid
- end
-
- it 'fails when more than one subject is present', :aggregate_failures do
- # two subjects
- experiment_subject.user = build(:user)
- experiment_subject.namespace = build(:group)
- expect(experiment_subject).not_to be_valid
- expect(experiment_subject.errors[:base]).to include(error_message)
-
- # three subjects
- experiment_subject.project = build(:project)
- expect(experiment_subject).not_to be_valid
- expect(experiment_subject.errors[:base]).to include(error_message)
- end
- end
- end
-
- describe '.valid_subject?' do
- subject(:valid_subject?) { described_class.valid_subject?(subject_class.new) }
-
- context 'when passing a Group, Namespace, User or Project' do
- [Group, Namespace, User, Project].each do |subject_class|
- let(:subject_class) { subject_class }
-
- it { is_expected.to be(true) }
- end
- end
-
- context 'when passing another object' do
- let(:subject_class) { Issue }
-
- it { is_expected.to be(false) }
- end
- end
-end
diff --git a/spec/models/experiment_user_spec.rb b/spec/models/experiment_user_spec.rb
deleted file mode 100644
index 9201529b145..00000000000
--- a/spec/models/experiment_user_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ExperimentUser do
- describe 'Associations' do
- it { is_expected.to belong_to(:experiment) }
- it { is_expected.to belong_to(:user) }
- end
-
- describe 'Validations' do
- it { is_expected.to validate_presence_of(:group_type) }
- end
-end
diff --git a/spec/models/exported_protected_branch_spec.rb b/spec/models/exported_protected_branch_spec.rb
index 7886a522741..9f862de6ff8 100644
--- a/spec/models/exported_protected_branch_spec.rb
+++ b/spec/models/exported_protected_branch_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe ExportedProtectedBranch do
it 'returns the correct push access levels' do
exported_branch = create(:exported_protected_branch, :developers_can_push)
deploy_key = create(:deploy_key)
- create(:deploy_keys_project, :write_access, project: exported_branch.project, deploy_key: deploy_key )
+ create(:deploy_keys_project, :write_access, project: exported_branch.project, deploy_key: deploy_key)
create(:protected_branch_push_access_level, protected_branch: exported_branch, deploy_key: deploy_key)
dev_push_access_level = exported_branch.push_access_levels.first
diff --git a/spec/models/factories_spec.rb b/spec/models/factories_spec.rb
index c931c96bafd..65b993cca7f 100644
--- a/spec/models/factories_spec.rb
+++ b/spec/models/factories_spec.rb
@@ -2,59 +2,100 @@
require 'spec_helper'
-RSpec.describe 'factories' do
+# `:saas` is used to test `gitlab_subscription` factory.
+# It's not available on FOSS but also this very factory is not.
+RSpec.describe 'factories', :saas do
include Database::DatabaseHelpers
+ # Used in `skipped` and indicates whether to skip any traits including the
+ # plain factory.
+ any = Object.new
+
# https://gitlab.com/groups/gitlab-org/-/epics/5464 tracks the remaining
- # skipped traits.
+ # skipped factories or traits.
#
# Consider adding a code comment if a trait cannot produce a valid object.
- def skipped_traits
- [
- [:audit_event, :unauthenticated],
- [:ci_build_trace_chunk, :fog_with_data],
- [:ci_job_artifact, :remote_store],
- [:ci_job_artifact, :raw],
- [:ci_job_artifact, :gzip],
- [:ci_job_artifact, :correct_checksum],
- [:environment, :non_playable],
- [:composer_cache_file, :object_storage],
- [:debian_project_component_file, :object_storage],
- [:debian_project_distribution, :object_storage],
- [:debian_file_metadatum, :unknown],
- [:issue_customer_relations_contact, :for_contact],
- [:issue_customer_relations_contact, :for_issue],
- [:package_file, :object_storage],
- [:rpm_repository_file, :object_storage],
- [:pages_domain, :without_certificate],
- [:pages_domain, :without_key],
- [:pages_domain, :with_missing_chain],
- [:pages_domain, :with_trusted_chain],
- [:pages_domain, :with_trusted_expired_chain],
- [:pages_domain, :explicit_ecdsa],
- [:project_member, :blocked],
- [:remote_mirror, :ssh],
- [:user_preference, :only_comments],
- [:ci_pipeline_artifact, :remote_store]
- ]
- end
+ skipped = [
+ [:audit_event, :unauthenticated],
+ [:ci_build_trace_chunk, :fog_with_data],
+ [:ci_job_artifact, :remote_store],
+ [:ci_job_artifact, :raw],
+ [:ci_job_artifact, :gzip],
+ [:ci_job_artifact, :correct_checksum],
+ [:dependency_proxy_blob, :remote_store],
+ [:environment, :non_playable],
+ [:composer_cache_file, :object_storage],
+ [:debian_project_component_file, :object_storage],
+ [:debian_project_distribution, :object_storage],
+ [:debian_file_metadatum, :unknown],
+ [:issue_customer_relations_contact, :for_contact],
+ [:issue_customer_relations_contact, :for_issue],
+ [:package_file, :object_storage],
+ [:rpm_repository_file, :object_storage],
+ [:pages_domain, :without_certificate],
+ [:pages_domain, :without_key],
+ [:pages_domain, :with_missing_chain],
+ [:pages_domain, :with_trusted_chain],
+ [:pages_domain, :with_trusted_expired_chain],
+ [:pages_domain, :explicit_ecdsa],
+ [:project_member, :blocked],
+ [:remote_mirror, :ssh],
+ [:user_preference, :only_comments],
+ [:ci_pipeline_artifact, :remote_store],
+ # EE
+ [:dast_profile, :with_dast_site_validation],
+ [:ee_ci_build, :dependency_scanning_report],
+ [:ee_ci_build, :license_scan_v1],
+ [:ee_ci_job_artifact, :v1],
+ [:ee_ci_job_artifact, :v1_1],
+ [:ee_ci_job_artifact, :v2],
+ [:ee_ci_job_artifact, :v2_1],
+ [:geo_ci_secure_file_state, any],
+ [:geo_dependency_proxy_blob_state, any],
+ [:geo_event_log, :geo_event],
+ [:geo_job_artifact_state, any],
+ [:geo_lfs_object_state, any],
+ [:geo_pages_deployment_state, any],
+ [:geo_upload_state, any],
+ [:geo_ci_secure_file_state, any],
+ [:lfs_object, :checksum_failure],
+ [:lfs_object, :checksummed],
+ [:merge_request, :blocked],
+ [:merge_request_diff, :verification_failed],
+ [:merge_request_diff, :verification_succeeded],
+ [:package_file, :verification_failed],
+ [:package_file, :verification_succeeded],
+ [:project, :with_vulnerabilities],
+ [:scan_execution_policy, :with_schedule_and_agent],
+ [:vulnerability, :with_cluster_image_scanning_finding],
+ [:vulnerability, :with_findings],
+ [:vulnerability_export, :finished]
+ ].freeze
shared_examples 'factory' do |factory|
+ skip_any = skipped.include?([factory.name, any])
+
describe "#{factory.name} factory" do
it 'does not raise error when built' do
+ # We use `skip` here because using `build` mostly work even if
+ # factories break when creating them.
+ skip 'Factory skipped linting due to legacy error' if skip_any
+
expect { build(factory.name) }.not_to raise_error
end
it 'does not raise error when created' do
+ pending 'Factory skipped linting due to legacy error' if skip_any
+
expect { create(factory.name) }.not_to raise_error # rubocop:disable Rails/SaveBang
end
factory.definition.defined_traits.map(&:name).each do |trait_name|
+ skip_trait = skip_any || skipped.include?([factory.name, trait_name.to_sym])
+
describe "linting :#{trait_name} trait" do
it 'does not raise error when created' do
- if skipped_traits.include?([factory.name, trait_name.to_sym])
- pending("Trait skipped linting due to legacy error")
- end
+ pending 'Trait skipped linting due to legacy error' if skip_trait
expect { create(factory.name, trait_name) }.not_to raise_error
end
@@ -71,6 +112,7 @@ RSpec.describe 'factories' do
# is being mutated.
skip_factory_defaults = %i[
ci_job_token_project_scope_link
+ ci_subscriptions_project
evidence
exported_protected_branch
fork_network_member
@@ -78,22 +120,27 @@ RSpec.describe 'factories' do
import_state
issue_customer_relations_contact
member_task
+ merge_request_block
milestone_release
namespace
project_namespace
project_repository
+ project_security_setting
prometheus_alert
prometheus_alert_event
prometheus_metric
protected_branch
protected_branch_merge_access_level
protected_branch_push_access_level
+ protected_branch_unprotect_access_level
protected_tag
+ protected_tag_create_access_level
release
release_link
self_managed_prometheus_alert_event
shard
users_star_project
+ vulnerabilities_finding_identifier
wiki_page
wiki_page_meta
].to_set.freeze
@@ -110,6 +157,27 @@ RSpec.describe 'factories' do
without_fd, with_fd = FactoryBot.factories
.partition { |factory| skip_factory_defaults.include?(factory.name) }
+ # Some EE models check licensed features so stub them.
+ shared_context 'with licensed features' do
+ licensed_features = %i[
+ board_milestone_lists
+ board_assignee_lists
+ ].index_with(true)
+
+ if Gitlab.jh?
+ licensed_features.merge! %i[
+ dingtalk_integration
+ feishu_bot_integration
+ ].index_with(true)
+ end
+
+ before do
+ stub_licensed_features(licensed_features)
+ end
+ end
+
+ include_context 'with licensed features' if Gitlab.ee?
+
context 'with factory defaults', factory_default: :keep do
let_it_be(:namespace) { create_default(:namespace).freeze }
let_it_be(:project) { create_default(:project, :repository).freeze }
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 68c2d1d3995..6ba450b6d57 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -40,6 +40,7 @@ RSpec.describe Group do
it { is_expected.to have_many(:bulk_import_exports).class_name('BulkImports::Export') }
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) }
it { is_expected.to have_one(:crm_settings) }
it { is_expected.to have_one(:group_feature) }
it { is_expected.to have_one(:harbor_integration) }
@@ -98,6 +99,15 @@ RSpec.describe Group do
expect(group).to be_valid
end
+
+ it 'does not allow a subgroup to have the same name as an existing subgroup' do
+ sub_group1 = create(:group, parent: group, name: "SG", path: 'api')
+ sub_group2 = described_class.new(parent: group, name: "SG", path: 'api2')
+
+ expect(sub_group1).to be_valid
+ expect(sub_group2).not_to be_valid
+ expect(sub_group2.errors.full_messages.to_sentence).to eq('Name has already been taken')
+ end
end
end
@@ -1058,28 +1068,45 @@ RSpec.describe Group do
end
context 'with owners from a parent' do
- before do
- parent_group = create(:group)
- create(:group_member, :owner, group: parent_group)
- group.update!(parent: parent_group)
+ context 'when top-level group' do
+ it { expect(group.last_owner?(@members[:owner])).to be_truthy }
+
+ context 'with group sharing' do
+ let!(:subgroup) { create(:group, parent: group) }
+
+ before do
+ create(:group_group_link, :owner, shared_group: group, shared_with_group: subgroup)
+ create(:group_member, :owner, group: subgroup)
+ end
+
+ it { expect(group.last_owner?(@members[:owner])).to be_truthy }
+ end
end
- it { expect(group.last_owner?(@members[:owner])).to be_falsy }
+ context 'when subgroup' do
+ let!(:subgroup) { create(:group, parent: group) }
+
+ it { expect(subgroup.last_owner?(@members[:owner])).to be_truthy }
+
+ context 'with two owners' do
+ before do
+ create(:group_member, :owner, group: group)
+ end
+
+ it { expect(subgroup.last_owner?(@members[:owner])).to be_falsey }
+ end
+ end
end
end
describe '#member_last_blocked_owner?' do
- let_it_be(:blocked_user) { create(:user, :blocked) }
+ let!(:blocked_user) { create(:user, :blocked) }
- let(:member) { blocked_user.group_members.last }
-
- before do
- group.add_member(blocked_user, GroupMember::OWNER)
- end
+ let!(:member) { group.add_member(blocked_user, GroupMember::OWNER) }
context 'when last_blocked_owner is set' do
before do
- expect(group).not_to receive(:members_with_parents)
+ expect(group).not_to receive(:member_owners_excluding_project_bots)
end
it 'returns true' do
@@ -1106,6 +1133,14 @@ RSpec.describe Group do
it { expect(group.member_last_blocked_owner?(member)).to be(false) }
end
+ context 'with another active project_bot owner' do
+ before do
+ group.add_member(create(:user, :project_bot), GroupMember::OWNER)
+ end
+
+ it { expect(group.member_last_blocked_owner?(member)).to be(true) }
+ end
+
context 'with 2 blocked owners' do
before do
group.add_member(create(:user, :blocked), GroupMember::OWNER)
@@ -1115,13 +1150,36 @@ RSpec.describe Group do
end
context 'with owners from a parent' do
- before do
- parent_group = create(:group)
- create(:group_member, :owner, group: parent_group)
- group.update!(parent: parent_group)
+ context 'when top-level group' do
+ it { expect(group.member_last_blocked_owner?(member)).to be(true) }
+
+ context 'with group sharing' do
+ let!(:subgroup) { create(:group, parent: group) }
+
+ before do
+ create(:group_group_link, :owner, shared_group: group, shared_with_group: subgroup)
+ create(:group_member, :owner, group: subgroup)
+ end
+
+ it { expect(group.member_last_blocked_owner?(member)).to be(true) }
+ end
end
- it { expect(group.member_last_blocked_owner?(member)).to be(false) }
+ context 'when subgroup' do
+ let!(:subgroup) { create(:group, :nested) }
+
+ let!(:member) { subgroup.add_member(blocked_user, GroupMember::OWNER) }
+
+ it { expect(subgroup.member_last_blocked_owner?(member)).to be(true) }
+
+ context 'with two owners' do
+ before do
+ create(:group_member, :owner, group: subgroup.parent)
+ end
+
+ it { expect(subgroup.member_last_blocked_owner?(member)).to be(false) }
+ end
+ end
end
end
end
@@ -1174,58 +1232,63 @@ RSpec.describe Group do
end
end
- describe '#all_owners_excluding_project_bots' do
+ describe '#member_owners_excluding_project_bots' do
let_it_be(:user) { create(:user) }
- context 'when there is only one owner' do
- let!(:owner) do
- group.add_member(user, GroupMember::OWNER)
- end
+ let!(:member_owner) do
+ group.add_member(user, GroupMember::OWNER)
+ end
- it 'returns the owner' do
- expect(group.all_owners_excluding_project_bots).to contain_exactly(owner)
- end
+ it 'returns the member-owners' do
+ expect(group.member_owners_excluding_project_bots).to contain_exactly(member_owner)
+ end
- context 'and there is also a project_bot owner' do
- before do
- group.add_member(create(:user, :project_bot), GroupMember::OWNER)
- end
+ context 'there is also a project_bot owner' do
+ before do
+ group.add_member(create(:user, :project_bot), GroupMember::OWNER)
+ end
- it 'returns only the human owner' do
- expect(group.all_owners_excluding_project_bots).to contain_exactly(owner)
- end
+ it 'returns only the human member-owners' do
+ expect(group.member_owners_excluding_project_bots).to contain_exactly(member_owner)
end
end
- context 'when there are multiple owners' do
- let_it_be(:user_2) { create(:user) }
+ context 'with owners from a parent' do
+ context 'when top-level group' do
+ context 'with group sharing' do
+ let!(:subgroup) { create(:group, parent: group) }
- let!(:owner) do
- group.add_member(user, GroupMember::OWNER)
- end
+ before do
+ create(:group_group_link, :owner, shared_group: group, shared_with_group: subgroup)
+ subgroup.add_member(user, GroupMember::OWNER)
+ end
- let!(:owner2) do
- group.add_member(user_2, GroupMember::OWNER)
+ it 'returns only direct member-owners' do
+ expect(group.member_owners_excluding_project_bots).to contain_exactly(member_owner)
+ end
+ end
end
- it 'returns both owners' do
- expect(group.all_owners_excluding_project_bots).to contain_exactly(owner, owner2)
- end
+ context 'when subgroup' do
+ let!(:subgroup) { create(:group, parent: group) }
- context 'and there is also a project_bot owner' do
- before do
- group.add_member(create(:user, :project_bot), GroupMember::OWNER)
+ let_it_be(:user_2) { create(:user) }
+
+ let!(:member_owner_2) do
+ subgroup.add_member(user_2, GroupMember::OWNER)
end
- it 'returns only the human owners' do
- expect(group.all_owners_excluding_project_bots).to contain_exactly(owner, owner2)
+ it 'returns member-owners including parents' do
+ expect(subgroup.member_owners_excluding_project_bots).to contain_exactly(member_owner, member_owner_2)
end
end
end
context 'when there are no owners' do
- it 'returns false' do
- expect(group.all_owners_excluding_project_bots).to be_empty
+ let_it_be(:empty_group) { create(:group) }
+
+ it 'returns an empty result' do
+ expect(empty_group.member_owners_excluding_project_bots).to be_empty
end
end
end
@@ -2405,23 +2468,6 @@ RSpec.describe Group do
end
end
- describe '.groups_including_descendants_by' do
- let_it_be(:parent_group1) { create(:group) }
- let_it_be(:parent_group2) { create(:group) }
- let_it_be(:extra_group) { create(:group) }
- let_it_be(:child_group1) { create(:group, parent: parent_group1) }
- let_it_be(:child_group2) { create(:group, parent: parent_group1) }
- let_it_be(:child_group3) { create(:group, parent: parent_group2) }
-
- subject { described_class.groups_including_descendants_by([parent_group2.id, parent_group1.id]) }
-
- shared_examples 'returns the expected groups for a group and its descendants' do
- specify { is_expected.to contain_exactly(parent_group1, parent_group2, child_group1, child_group2, child_group3) }
- end
-
- it_behaves_like 'returns the expected groups for a group and its descendants'
- end
-
describe '.preset_root_ancestor_for' do
let_it_be(:rootgroup, reload: true) { create(:group) }
let_it_be(:subgroup, reload: true) { create(:group, parent: rootgroup) }
@@ -2555,7 +2601,7 @@ RSpec.describe Group do
end
context 'when parent does not allow' do
- let_it_be(:parent, reload: true) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false ) }
+ let_it_be(:parent, reload: true) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false) }
let_it_be(:group, reload: true) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent: parent) }
it 'raises exception' do
diff --git a/spec/models/hooks/active_hook_filter_spec.rb b/spec/models/hooks/active_hook_filter_spec.rb
index 1f693ce9fde..47c0fbdb106 100644
--- a/spec/models/hooks/active_hook_filter_spec.rb
+++ b/spec/models/hooks/active_hook_filter_spec.rb
@@ -6,65 +6,102 @@ RSpec.describe ActiveHookFilter do
subject(:filter) { described_class.new(hook) }
describe '#matches?' do
- context 'for push event hooks' do
+ using RSpec::Parameterized::TableSyntax
+
+ context 'for various types of branch_filter' do
let(:hook) do
- create(:project_hook, push_events: true, push_events_branch_filter: branch_filter)
+ build(:project_hook, push_events: true, issues_events: true)
end
- context 'branch filter is specified' do
- let(:branch_filter) { 'master' }
+ where(:branch_filter_strategy, :branch_filter, :ref, :expected_matches?) do
+ 'all_branches' | 'master' | 'refs/heads/master' | true
+ 'all_branches' | '' | 'refs/heads/master' | true
+ 'all_branches' | nil | 'refs/heads/master' | true
+ 'all_branches' | '.*' | 'refs/heads/master' | true
+ 'wildcard' | 'master' | 'refs/heads/master' | true
+ 'wildcard' | 'master' | 'refs/heads/my_branch' | false
+ 'wildcard' | 'features/*' | 'refs/heads/features/my-branch' | true
+ 'wildcard' | 'features/*' | 'refs/heads/features/my-branch/something' | true
+ 'wildcard' | 'features/*' | 'refs/heads/master' | false
+ 'wildcard' | nil | 'refs/heads/master' | true
+ 'wildcard' | '' | 'refs/heads/master' | true
+ 'regex' | 'master' | 'refs/heads/master' | true
+ 'regex' | 'master' | 'refs/heads/my_branch' | false
+ 'regex' | 'features/*' | 'refs/heads/xxxx/features/my-branch' | true
+ 'regex' | 'features/*' | 'refs/heads/features/' | true
+ 'regex' | 'features/*' | 'refs/heads/features' | true
+ 'regex' | 'features/.*' | 'refs/heads/features/my-branch' | true
+ 'regex' | 'features/.*' | 'refs/heads/features/my-branch/something' | true
+ 'regex' | 'features/.*' | 'refs/heads/master' | false
+ 'regex' | '(feature|dev)' | 'refs/heads/feature' | true
+ 'regex' | '(feature|dev)' | 'refs/heads/dev' | true
+ 'regex' | '(feature|dev)' | 'refs/heads/master' | false
+ 'regex' | nil | 'refs/heads/master' | true
+ 'regex' | '' | 'refs/heads/master' | true
+ end
- it 'returns true if branch matches' do
- expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be true
+ with_them do
+ before do
+ hook.assign_attributes(
+ push_events_branch_filter: branch_filter,
+ branch_filter_strategy: branch_filter_strategy
+ )
end
- it 'returns false if branch does not match' do
- expect(filter.matches?(:push_hooks, { ref: 'refs/heads/my_branch' })).to be false
- end
+ it { expect(filter.matches?(:push_hooks, { ref: ref })).to be expected_matches? }
+ it { expect(filter.matches?(:issues_events, { ref: ref })).to be true }
+ end
- it 'returns false if ref is nil' do
- expect(filter.matches?(:push_hooks, {})).to be false
+ context 'when the branch filter is a invalid regex' do
+ let(:hook) do
+ build(
+ :project_hook,
+ push_events: true,
+ push_events_branch_filter: 'master',
+ branch_filter_strategy: 'regex'
+ )
end
- context 'branch filter contains wildcard' do
- let(:branch_filter) { 'features/*' }
-
- it 'returns true if branch matches' do
- expect(filter.matches?(:push_hooks, { ref: 'refs/heads/features/my-branch' })).to be true
- expect(filter.matches?(:push_hooks, { ref: 'refs/heads/features/my-branch/something' })).to be true
- end
-
- it 'returns false if branch does not match' do
- expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be false
- end
+ before do
+ allow(hook).to receive(:push_events_branch_filter).and_return("invalid-regex[")
end
- end
- context 'branch filter is not specified' do
- let(:branch_filter) { nil }
-
- it 'returns true' do
- expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be true
- end
+ it { expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be false }
end
- context 'branch filter is empty string' do
- let(:branch_filter) { '' }
+ context 'when the branch filter is not properly set to nil' do
+ let(:hook) do
+ build(
+ :project_hook,
+ push_events: true,
+ branch_filter_strategy: 'all_branches'
+ )
+ end
- it 'acts like branch is not specified' do
- expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be true
+ before do
+ allow(hook).to receive(:push_events_branch_filter).and_return("master")
end
+
+ it { expect(filter.matches?(:push_hooks, { ref: 'refs/heads/feature1' })).to be true }
end
end
- context 'for non-push-events hooks' do
- let(:hook) do
- create(:project_hook, issues_events: true, push_events: false, push_events_branch_filter: '')
+ context 'when feature flag is disabled' do
+ before do
+ stub_feature_flags(enhanced_webhook_support_regex: false)
end
- it 'returns true as branch filters are not yet supported for these' do
- expect(filter.matches?(:issues_events, { ref: 'refs/heads/master' })).to be true
+ let(:hook) do
+ build(
+ :project_hook,
+ push_events: true,
+ push_events_branch_filter: '(master)',
+ branch_filter_strategy: 'regex'
+ )
end
+
+ it { expect(filter.matches?(:push_hooks, { ref: 'refs/heads/master' })).to be false }
+ it { expect(filter.matches?(:push_hooks, { ref: 'refs/heads/(master)' })).to be true }
end
end
end
diff --git a/spec/models/hooks/project_hook_spec.rb b/spec/models/hooks/project_hook_spec.rb
index 923a6f92424..3d8c377ab21 100644
--- a/spec/models/hooks/project_hook_spec.rb
+++ b/spec/models/hooks/project_hook_spec.rb
@@ -12,14 +12,14 @@ RSpec.describe ProjectHook do
end
it_behaves_like 'includes Limitable concern' do
- subject { build(:project_hook, project: create(:project)) }
+ subject { build(:project_hook) }
end
describe '.for_projects' do
it 'finds related project hooks' do
- hook_a = create(:project_hook)
- hook_b = create(:project_hook)
- hook_c = create(:project_hook)
+ hook_a = create(:project_hook, project: build(:project))
+ hook_b = create(:project_hook, project: build(:project))
+ hook_c = create(:project_hook, project: build(:project))
expect(described_class.for_projects([hook_a.project, hook_b.project]))
.to contain_exactly(hook_a, hook_b)
@@ -30,16 +30,18 @@ RSpec.describe ProjectHook do
describe '.push_hooks' do
it 'returns hooks for push events only' do
- hook = create(:project_hook, push_events: true)
- create(:project_hook, push_events: false)
+ project = build(:project)
+ hook = create(:project_hook, project: project, push_events: true)
+ create(:project_hook, project: project, push_events: false)
expect(described_class.push_hooks).to eq([hook])
end
end
describe '.tag_push_hooks' do
it 'returns hooks for tag push events only' do
- hook = create(:project_hook, tag_push_events: true)
- create(:project_hook, tag_push_events: false)
+ project = build(:project)
+ hook = create(:project_hook, project: project, tag_push_events: true)
+ create(:project_hook, project: project, tag_push_events: false)
expect(described_class.tag_push_hooks).to eq([hook])
end
end
@@ -65,7 +67,7 @@ RSpec.describe ProjectHook do
end
describe '#update_last_failure', :clean_gitlab_redis_shared_state do
- let_it_be(:hook) { create(:project_hook) }
+ let(:hook) { build(:project_hook) }
it 'is a method of this class' do
expect { hook.update_last_failure }.not_to raise_error
diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb
index f4786083b75..ba94730b1dd 100644
--- a/spec/models/hooks/system_hook_spec.rb
+++ b/spec/models/hooks/system_hook_spec.rb
@@ -4,7 +4,7 @@ require "spec_helper"
RSpec.describe SystemHook do
context 'default attributes' do
- let(:system_hook) { build(:system_hook) }
+ let(:system_hook) { described_class.new }
it 'sets defined default parameters' do
attrs = {
@@ -32,10 +32,10 @@ RSpec.describe SystemHook do
end
describe "execute", :sidekiq_might_not_need_inline do
- let(:system_hook) { create(:system_hook) }
- let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace) }
- let(:group) { create(:group) }
+ let_it_be(:system_hook) { create(:system_hook) }
+ let_it_be(:user) { create(:user) }
+ let(:project) { build(:project, namespace: user.namespace) }
+ let(:group) { build(:group) }
let(:params) do
{ name: 'John Doe', username: 'jduser', email: 'jg@example.com', password: User.random_password }
end
@@ -145,6 +145,7 @@ RSpec.describe SystemHook do
end
it 'group member update hook' do
+ group = create(:group)
group.add_guest(user)
group.add_maintainer(user)
diff --git a/spec/models/hooks/web_hook_log_spec.rb b/spec/models/hooks/web_hook_log_spec.rb
index 3441dfda7d6..fafca144cae 100644
--- a/spec/models/hooks/web_hook_log_spec.rb
+++ b/spec/models/hooks/web_hook_log_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe WebHookLog do
it { is_expected.to validate_presence_of(:web_hook) }
describe '.recent' do
- let(:hook) { create(:project_hook) }
+ let(:hook) { build(:project_hook) }
it 'does not return web hook logs that are too old' do
create(:web_hook_log, web_hook: hook, created_at: 10.days.ago)
@@ -30,8 +30,10 @@ RSpec.describe WebHookLog do
end
describe '#save' do
+ let(:hook) { build(:project_hook) }
+
context 'with basic auth credentials' do
- let(:web_hook_log) { build(:web_hook_log, url: 'http://test:123@example.com') }
+ let(:web_hook_log) { build(:web_hook_log, web_hook: hook, url: 'http://test:123@example.com') }
subject { web_hook_log.save! }
@@ -45,9 +47,9 @@ RSpec.describe WebHookLog do
end
context "with users' emails" do
- let(:author) { create(:user) }
- let(:user) { create(:user) }
- let(:web_hook_log) { create(:web_hook_log, request_data: data) }
+ let(:author) { build(:user) }
+ let(:user) { build(:user) }
+ let(:web_hook_log) { create(:web_hook_log, web_hook: hook, request_data: data) }
let(:data) do
{
user: {
@@ -93,11 +95,12 @@ RSpec.describe WebHookLog do
end
describe '.delete_batch_for' do
- let(:hook) { create(:project_hook) }
+ let_it_be(:hook) { build(:project_hook) }
+ let_it_be(:hook2) { build(:project_hook) }
- before do
+ before_all do
create_list(:web_hook_log, 3, web_hook: hook)
- create_list(:web_hook_log, 3)
+ create_list(:web_hook_log, 3, web_hook: hook2)
end
subject { described_class.delete_batch_for(hook, batch_size: batch_size) }
diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb
index da8c10b67a6..db854670cc3 100644
--- a/spec/models/hooks/web_hook_spec.rb
+++ b/spec/models/hooks/web_hook_spec.rb
@@ -34,6 +34,11 @@ RSpec.describe WebHook do
it { is_expected.to allow_value({ 'x' => ('a' * 100) }).for(:url_variables) }
it { is_expected.to allow_value({ 'foo' => 'bar', 'bar' => 'baz' }).for(:url_variables) }
it { is_expected.to allow_value((1..20).to_h { ["k#{_1}", 'value'] }).for(:url_variables) }
+ it { is_expected.to allow_value({ 'MY-TOKEN' => 'bar' }).for(:url_variables) }
+ it { is_expected.to allow_value({ 'my_secr3t-token' => 'bar' }).for(:url_variables) }
+ it { is_expected.to allow_value({ 'x-y-z' => 'bar' }).for(:url_variables) }
+ it { is_expected.to allow_value({ 'x_y_z' => 'bar' }).for(:url_variables) }
+ it { is_expected.to allow_value({ 'f.o.o' => 'bar' }).for(:url_variables) }
it { is_expected.not_to allow_value([]).for(:url_variables) }
it { is_expected.not_to allow_value({ 'foo' => 1 }).for(:url_variables) }
@@ -45,6 +50,10 @@ RSpec.describe WebHook do
it { is_expected.not_to allow_value({ '' => 'foo' }).for(:url_variables) }
it { is_expected.not_to allow_value({ '1foo' => 'foo' }).for(:url_variables) }
it { is_expected.not_to allow_value((1..21).to_h { ["k#{_1}", 'value'] }).for(:url_variables) }
+ it { is_expected.not_to allow_value({ 'MY--TOKEN' => 'foo' }).for(:url_variables) }
+ it { is_expected.not_to allow_value({ 'MY__SECRET' => 'foo' }).for(:url_variables) }
+ it { is_expected.not_to allow_value({ 'x-_y' => 'foo' }).for(:url_variables) }
+ it { is_expected.not_to allow_value({ 'x..y' => 'foo' }).for(:url_variables) }
end
describe 'url' do
@@ -83,7 +92,7 @@ RSpec.describe WebHook do
subject { hook }
before do
- hook.url_variables = { 'one' => 'a', 'two' => 'b' }
+ hook.url_variables = { 'one' => 'a', 'two' => 'b', 'url' => 'http://example.com' }
end
it { is_expected.to allow_value('http://example.com').for(:url) }
@@ -92,6 +101,8 @@ RSpec.describe WebHook do
it { is_expected.to allow_value('http://example.com/{two}').for(:url) }
it { is_expected.to allow_value('http://user:s3cret@example.com/{two}').for(:url) }
it { is_expected.to allow_value('http://{one}:{two}@example.com').for(:url) }
+ it { is_expected.to allow_value('http://{one}').for(:url) }
+ it { is_expected.to allow_value('{url}').for(:url) }
it { is_expected.not_to allow_value('http://example.com/{one}/{two}/{three}').for(:url) }
it { is_expected.not_to allow_value('http://example.com/{foo}').for(:url) }
@@ -113,24 +124,81 @@ RSpec.describe WebHook do
end
describe 'push_events_branch_filter' do
- it { is_expected.to allow_values("good_branch_name", "another/good-branch_name").for(:push_events_branch_filter) }
- it { is_expected.to allow_values("").for(:push_events_branch_filter) }
- it { is_expected.not_to allow_values("bad branch name", "bad~branchname").for(:push_events_branch_filter) }
-
- it 'gets rid of whitespace' do
- hook.push_events_branch_filter = ' branch '
- hook.save!
+ before do
+ subject.branch_filter_strategy = strategy
+ end
+
+ context 'with "all branches" strategy' do
+ let(:strategy) { 'all_branches' }
+
+ it {
+ is_expected.to allow_values(
+ "good_branch_name",
+ "another/good-branch_name",
+ "good branch name",
+ "good~branchname",
+ "good_branchname(",
+ "good_branchname[",
+ ""
+ ).for(:push_events_branch_filter)
+ }
+ end
+
+ context 'with "wildcard" strategy' do
+ let(:strategy) { 'wildcard' }
+
+ it {
+ is_expected.to allow_values(
+ "good_branch_name",
+ "another/good-branch_name",
+ "good_branch_name(",
+ ""
+ ).for(:push_events_branch_filter)
+ }
+
+ it {
+ is_expected.not_to allow_values(
+ "bad branch name",
+ "bad~branchname",
+ "bad_branch_name["
+ ).for(:push_events_branch_filter)
+ }
+
+ it 'gets rid of whitespace' do
+ hook.push_events_branch_filter = ' branch '
+ hook.save!
+
+ expect(hook.push_events_branch_filter).to eq('branch')
+ end
- expect(hook.push_events_branch_filter).to eq('branch')
+ it 'stores whitespace only as empty' do
+ hook.push_events_branch_filter = ' '
+ hook.save!
+ expect(hook.push_events_branch_filter).to eq('')
+ end
end
- it 'stores whitespace only as empty' do
- hook.push_events_branch_filter = ' '
- hook.save!
+ context 'with "regex" strategy' do
+ let(:strategy) { 'regex' }
- expect(hook.push_events_branch_filter).to eq('')
+ it {
+ is_expected.to allow_values(
+ "good_branch_name",
+ "another/good-branch_name",
+ "good branch name",
+ "good~branch~name",
+ ""
+ ).for(:push_events_branch_filter)
+ }
+
+ it { is_expected.not_to allow_values("bad_branch_name(", "bad_branch_name[").for(:push_events_branch_filter) }
end
end
+
+ it "only consider these branch filter strategies are valid" do
+ expected_valid_types = %w[all_branches regex wildcard]
+ expect(described_class.branch_filter_strategies.keys).to contain_exactly(*expected_valid_types)
+ end
end
describe 'encrypted attributes' do
@@ -141,7 +209,7 @@ RSpec.describe WebHook do
describe '.web_hooks_disable_failed?' do
it 'returns true when feature is enabled for parent' do
- second_hook = build(:project_hook, project: create(:project))
+ second_hook = build(:project_hook)
stub_feature_flags(web_hooks_disable_failed: [false, second_hook.project])
expect(described_class.web_hooks_disable_failed?(hook)).to eq(false)
@@ -242,7 +310,7 @@ RSpec.describe WebHook do
end
describe '#executable?' do
- let(:web_hook) { create(:project_hook, project: project) }
+ let_it_be_with_reload(:web_hook) { create(:project_hook, project: project) }
where(:recent_failures, :not_until, :executable) do
[
@@ -389,7 +457,7 @@ RSpec.describe WebHook do
end
end
- describe 'backoff!' do
+ describe '#backoff!' do
context 'when we have not backed off before' do
it 'does not disable the hook' do
expect { hook.backoff! }.not_to change(hook, :executable?).from(true)
@@ -400,6 +468,26 @@ RSpec.describe WebHook do
end
end
+ context 'when the recent failure value is the max value of a smallint' do
+ before do
+ hook.update!(recent_failures: 32767, disabled_until: 1.hour.ago)
+ end
+
+ it 'reduces to MAX_FAILURES' do
+ expect { hook.backoff! }.to change(hook, :recent_failures).to(described_class::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)
+ end
+
+ it 'does not change recent_failures' do
+ expect { hook.backoff! }.not_to change(hook, :recent_failures)
+ end
+ end
+
context 'when we have exhausted the grace period' do
before do
hook.update!(recent_failures: described_class::FAILURE_THRESHOLD)
@@ -459,11 +547,21 @@ RSpec.describe WebHook do
end
end
- describe 'failed!' do
+ describe '#failed!' do
it 'increments the failure count' do
expect { hook.failed! }.to change(hook, :recent_failures).by(1)
end
+ context 'when the recent failure value is the max value of a smallint' do
+ before do
+ hook.update!(recent_failures: 32767)
+ end
+
+ it 'does not change recent_failures' do
+ expect { hook.failed! }.not_to change(hook, :recent_failures)
+ end
+ end
+
it 'does not update the hook if the the failure count exceeds the maximum value' do
hook.recent_failures = described_class::MAX_FAILURES
@@ -670,4 +768,14 @@ RSpec.describe WebHook do
expect { described_class.new.update_last_failure }.not_to raise_error
end
end
+
+ describe '#masked_token' do
+ it { expect(hook.masked_token).to be_nil }
+
+ context 'with a token' do
+ let(:hook) { build(:project_hook, :token, project: project) }
+
+ it { expect(hook.masked_token).to eq described_class::SECRET_MASK }
+ end
+ end
end
diff --git a/spec/models/incident_management/timeline_event_spec.rb b/spec/models/incident_management/timeline_event_spec.rb
index d288cc1a75d..036f5affb87 100644
--- a/spec/models/incident_management/timeline_event_spec.rb
+++ b/spec/models/incident_management/timeline_event_spec.rb
@@ -27,6 +27,7 @@ RSpec.describe IncidentManagement::TimelineEvent do
it { is_expected.to validate_presence_of(:project) }
it { is_expected.to validate_presence_of(:incident) }
it { is_expected.to validate_presence_of(:note) }
+ it { is_expected.to validate_length_of(:note).is_at_most(280).on(:user_input) }
it { is_expected.to validate_length_of(:note).is_at_most(10_000) }
it { is_expected.to validate_length_of(:note_html).is_at_most(10_000) }
it { is_expected.to validate_presence_of(:occurred_at) }
diff --git a/spec/models/incident_management/timeline_event_tag_spec.rb b/spec/models/incident_management/timeline_event_tag_spec.rb
index cff8ad8469f..1ec4fa30fb5 100644
--- a/spec/models/incident_management/timeline_event_tag_spec.rb
+++ b/spec/models/incident_management/timeline_event_tag_spec.rb
@@ -18,11 +18,46 @@ RSpec.describe IncidentManagement::TimelineEventTag do
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_length_of(:name).is_at_most(255) }
- it { is_expected.to validate_uniqueness_of(:name).scoped_to([:project_id]) }
+ it { is_expected.to validate_uniqueness_of(:name).scoped_to([:project_id]).ignoring_case_sensitivity }
it { is_expected.to allow_value('Test tag 1').for(:name) }
it { is_expected.not_to allow_value('Test tag, 1').for(:name) }
it { is_expected.not_to allow_value('').for(:name) }
it { is_expected.not_to allow_value('s' * 256).for(:name) }
end
+
+ describe '.pluck_names' do
+ it 'returns the names of the tags' do
+ tag1 = create(:incident_management_timeline_event_tag)
+ tag2 = create(:incident_management_timeline_event_tag)
+
+ expect(described_class.pluck_names).to contain_exactly(tag1.name, tag2.name)
+ end
+ end
+
+ describe 'constants' do
+ it { expect(described_class::START_TIME_TAG_NAME).to eq('Start time') }
+ it { expect(described_class::END_TIME_TAG_NAME).to eq('End time') }
+ end
+
+ describe '#by_names scope' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:project2) { create(:project) }
+ let_it_be(:tag1) { create(:incident_management_timeline_event_tag, name: 'Test tag 1', project: project) }
+ let_it_be(:tag2) { create(:incident_management_timeline_event_tag, name: 'Test tag 2', project: project) }
+ let_it_be(:tag3) { create(:incident_management_timeline_event_tag, name: 'Test tag 3', project: project2) }
+
+ it 'returns two matching tags' do
+ expect(described_class.by_names(['Test tag 1', 'Test tag 2'])).to contain_exactly(tag1, tag2)
+ end
+
+ it 'returns tags on the project' do
+ expect(project2.incident_management_timeline_event_tags.by_names(['Test tag 1',
+ 'Test tag 3'])).to contain_exactly(tag3)
+ end
+
+ it 'returns one matching tag with case insensitive' do
+ expect(described_class.by_names(['tESt tAg 2'])).to contain_exactly(tag2)
+ end
+ end
end
diff --git a/spec/models/instance_metadata_spec.rb b/spec/models/instance_metadata_spec.rb
index 5fc073c392d..46fd165e065 100644
--- a/spec/models/instance_metadata_spec.rb
+++ b/spec/models/instance_metadata_spec.rb
@@ -9,7 +9,8 @@ RSpec.describe InstanceMetadata do
expect(subject).to have_attributes(
version: Gitlab::VERSION,
revision: Gitlab.revision,
- kas: kind_of(::InstanceMetadata::Kas)
+ kas: kind_of(::InstanceMetadata::Kas),
+ enterprise: Gitlab.ee?
)
end
end
diff --git a/spec/models/integration_spec.rb b/spec/models/integration_spec.rb
index baa3443b4c5..4938e1797af 100644
--- a/spec/models/integration_spec.rb
+++ b/spec/models/integration_spec.rb
@@ -15,6 +15,23 @@ RSpec.describe Integration do
it { is_expected.to have_one(:jira_tracker_data).autosave(true).inverse_of(:integration).with_foreign_key(:integration_id).class_name('Integrations::JiraTrackerData') }
end
+ describe 'default values' do
+ it { is_expected.to be_alert_events }
+ it { is_expected.to be_commit_events }
+ it { is_expected.to be_confidential_issues_events }
+ it { is_expected.to be_confidential_note_events }
+ it { is_expected.to be_issues_events }
+ it { is_expected.to be_job_events }
+ it { is_expected.to be_merge_requests_events }
+ it { is_expected.to be_note_events }
+ it { is_expected.to be_pipeline_events }
+ it { is_expected.to be_push_events }
+ it { is_expected.to be_tag_push_events }
+ it { is_expected.to be_wiki_page_events }
+ it { is_expected.not_to be_active }
+ it { expect(subject.category).to eq(:common) }
+ end
+
describe 'validations' do
it { is_expected.to validate_presence_of(:type) }
it { is_expected.to validate_exclusion_of(:type).in_array(described_class::BASE_CLASSES) }
@@ -60,10 +77,10 @@ RSpec.describe Integration do
describe 'Scopes' do
describe '.third_party_wikis' do
- let!(:integration1) { create(:jira_integration) }
- let!(:integration2) { create(:redmine_integration) }
- let!(:integration3) { create(:confluence_integration) }
- let!(:integration4) { create(:shimo_integration) }
+ let!(:integration1) { create(:jira_integration, project: project) }
+ let!(:integration2) { create(:redmine_integration, project: project) }
+ let!(:integration3) { create(:confluence_integration, project: project) }
+ let!(:integration4) { create(:shimo_integration, project: project) }
it 'returns the right group integration' do
expect(described_class.third_party_wikis).to contain_exactly(integration3, integration4)
@@ -89,7 +106,7 @@ RSpec.describe Integration do
end
describe '.by_type' do
- let!(:integration1) { create(:jira_integration) }
+ let!(:integration1) { create(:jira_integration, project: project) }
let!(:integration2) { create(:jira_integration) }
let!(:integration3) { create(:redmine_integration) }
@@ -110,7 +127,7 @@ RSpec.describe Integration do
describe '.for_group' do
let!(:integration1) { create(:jira_integration, project_id: nil, group_id: group.id) }
- let!(:integration2) { create(:jira_integration) }
+ let!(:integration2) { create(:jira_integration, project: project) }
it 'returns the right group integration' do
expect(described_class.for_group(group)).to contain_exactly(integration1)
@@ -217,9 +234,19 @@ RSpec.describe Integration do
end
end
+ describe '#chat?' do
+ it 'is true when integration is chat integration' do
+ expect(build(:mattermost_integration).chat?).to eq(true)
+ end
+
+ it 'is false when integration is not chat integration' do
+ expect(build(:integration).chat?).to eq(false)
+ end
+ end
+
describe '.find_or_initialize_non_project_specific_integration' do
let!(:integration_1) { create(:jira_integration, project_id: nil, group_id: group.id) }
- let!(:integration_2) { create(:jira_integration) }
+ let!(:integration_2) { create(:jira_integration, project: project) }
it 'returns the right integration' do
expect(Integration.find_or_initialize_non_project_specific_integration('jira', group_id: group))
@@ -374,7 +401,7 @@ RSpec.describe Integration do
context 'when data is stored in properties' do
let(:properties) { data_params }
let!(:integration) do
- create(:jira_integration, :without_properties_callback, properties: properties.merge(additional: 'something'))
+ create(:jira_integration, :without_properties_callback, project: project, properties: properties.merge(additional: 'something'))
end
it_behaves_like 'integration creation from an integration'
@@ -382,7 +409,7 @@ RSpec.describe Integration do
context 'when data are stored in separated fields' do
let(:integration) do
- create(:jira_integration, data_params.merge(properties: {}))
+ create(:jira_integration, data_params.merge(properties: {}, project: project))
end
it_behaves_like 'integration creation from an integration'
@@ -391,7 +418,7 @@ RSpec.describe Integration do
context 'when data are stored in both properties and separated fields' do
let(:properties) { data_params }
let(:integration) do
- create(:jira_integration, :without_properties_callback, active: true, properties: properties).tap do |integration|
+ create(:jira_integration, :without_properties_callback, project: project, active: true, properties: properties).tap do |integration|
create(:jira_tracker_data, data_params.merge(integration: integration))
end
end
@@ -1233,11 +1260,11 @@ RSpec.describe Integration do
describe '#attributes' do
it 'does not include properties' do
- expect(create(:integration).attributes).not_to have_key('properties')
+ expect(build(:integration, project: project).attributes).not_to have_key('properties')
end
it 'can be used in assign_attributes without nullifying properties' do
- record = create(:integration, :instance, properties: { url: generate(:url) })
+ record = build(:integration, :instance, properties: { url: generate(:url) })
attrs = record.attributes
@@ -1246,7 +1273,7 @@ RSpec.describe Integration do
end
describe '#dup' do
- let(:original) { create(:integration, properties: { one: 1, two: 2, three: 3 }) }
+ let(:original) { build(:integration, project: project, properties: { one: 1, two: 2, three: 3 }) }
it 'results in distinct ciphertexts, but identical properties' do
copy = original.dup
@@ -1259,7 +1286,7 @@ RSpec.describe Integration do
end
context 'when the model supports data-fields' do
- let(:original) { create(:jira_integration, username: generate(:username), url: generate(:url)) }
+ let(:original) { build(:jira_integration, project: project, username: generate(:username), url: generate(:url)) }
it 'creates distinct but identical data-fields' do
copy = original.dup
diff --git a/spec/models/integrations/assembla_spec.rb b/spec/models/integrations/assembla_spec.rb
index 960dfea3dc4..e9f4274952d 100644
--- a/spec/models/integrations/assembla_spec.rb
+++ b/spec/models/integrations/assembla_spec.rb
@@ -5,6 +5,10 @@ require 'spec_helper'
RSpec.describe Integrations::Assembla do
include StubRequests
+ it_behaves_like Integrations::ResetSecretFields do
+ let(:integration) { described_class.new }
+ end
+
describe "Execute" do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
diff --git a/spec/models/integrations/bamboo_spec.rb b/spec/models/integrations/bamboo_spec.rb
index e92226d109f..1d2c90dad51 100644
--- a/spec/models/integrations/bamboo_spec.rb
+++ b/spec/models/integrations/bamboo_spec.rb
@@ -23,6 +23,10 @@ RSpec.describe Integrations::Bamboo, :use_clean_rails_memory_store_caching do
)
end
+ it_behaves_like Integrations::BaseCi
+
+ it_behaves_like Integrations::ResetSecretFields
+
include_context Integrations::EnableSslVerification
describe 'Validations' do
@@ -77,48 +81,6 @@ RSpec.describe Integrations::Bamboo, :use_clean_rails_memory_store_caching do
end
end
- describe 'Callbacks' do
- describe 'before_validation :reset_password' do
- context 'when a password was previously set' do
- it 'resets password if url changed' do
- integration.bamboo_url = 'http://gitlab1.com'
-
- expect(integration).not_to be_valid
- expect(integration.password).to be_nil
- end
-
- it 'does not reset password if username changed' do
- integration.username = 'some_name'
-
- expect(integration).to be_valid
- expect(integration.password).to eq('password')
- end
-
- it "does not reset password if new url is set together with password, even if it's the same password" do
- integration.bamboo_url = 'http://gitlab_edited.com'
- integration.password = 'password'
-
- expect(integration).to be_valid
- expect(integration.password).to eq('password')
- expect(integration.bamboo_url).to eq('http://gitlab_edited.com')
- end
- end
-
- it 'saves password if new url is set together with password when no password was previously set' do
- integration.password = nil
-
- integration.bamboo_url = 'http://gitlab_edited.com'
- integration.password = 'password'
- integration.save!
-
- expect(integration.reload).to have_attributes(
- bamboo_url: 'http://gitlab_edited.com',
- password: 'password'
- )
- end
- end
- end
-
describe '#execute' do
it 'runs update and build action' do
stub_update_and_build_request
diff --git a/spec/models/integrations/base_chat_notification_spec.rb b/spec/models/integrations/base_chat_notification_spec.rb
index eb503e501d6..b959ead2cae 100644
--- a/spec/models/integrations/base_chat_notification_spec.rb
+++ b/spec/models/integrations/base_chat_notification_spec.rb
@@ -3,11 +3,15 @@
require 'spec_helper'
RSpec.describe Integrations::BaseChatNotification do
+ describe 'default values' do
+ it { expect(subject.category).to eq(:chat) }
+ end
+
describe 'validations' do
before do
allow(subject).to receive(:activated?).and_return(true)
allow(subject).to receive(:default_channel_placeholder).and_return('placeholder')
- allow(subject).to receive(:webhook_placeholder).and_return('placeholder')
+ allow(subject).to receive(:webhook_help).and_return('help')
end
it { is_expected.to validate_presence_of :webhook }
@@ -19,7 +23,7 @@ RSpec.describe Integrations::BaseChatNotification do
let_it_be(:project) { create(:project, :repository) }
- let(:user) { create(:user) }
+ let(:user) { build_stubbed(:user) }
let(:webhook_url) { 'https://example.gitlab.com/' }
let(:data) { Gitlab::DataBuilder::Push.build_sample(subject.project, user) }
@@ -44,7 +48,7 @@ RSpec.describe Integrations::BaseChatNotification do
context 'with an empty repository' do
it 'returns true' do
- subject.project = create(:project, :empty_repo)
+ subject.project = build_stubbed(:project, :empty_repo)
expect(chat_integration).to receive(:notify).and_return(true)
expect(chat_integration.execute(data)).to be true
@@ -61,9 +65,9 @@ RSpec.describe Integrations::BaseChatNotification do
end
context 'when the data object has a label' do
- let_it_be(:label) { create(:label, name: 'Bug') }
- let_it_be(:label_2) { create(:label, name: 'Community contribution') }
- let_it_be(:label_3) { create(:label, name: 'Backend') }
+ let_it_be(:label) { create(:label, project: project, name: 'Bug') }
+ let_it_be(:label_2) { create(:label, project: project, name: 'Community contribution') }
+ let_it_be(:label_3) { create(:label, project: project, name: 'Backend') }
let_it_be(:issue) { create(:labeled_issue, project: project, labels: [label, label_2, label_3]) }
let_it_be(:note) { create(:note, noteable: issue, project: project) }
@@ -93,7 +97,7 @@ RSpec.describe Integrations::BaseChatNotification do
it_behaves_like 'notifies the chat integration'
context 'MergeRequest events' do
- let(:data) { create(:merge_request, labels: [label]).to_hook_data(user) }
+ let(:data) { build_stubbed(:merge_request, source_project: project, labels: [label]).to_hook_data(user) }
it_behaves_like 'notifies the chat integration'
end
@@ -280,9 +284,9 @@ RSpec.describe Integrations::BaseChatNotification do
end
end
- describe '#webhook_placeholder' do
+ describe '#webhook_help' do
it 'raises an error' do
- expect { subject.webhook_placeholder }.to raise_error(NotImplementedError)
+ expect { subject.webhook_help }.to raise_error(NotImplementedError)
end
end
diff --git a/spec/models/integrations/base_issue_tracker_spec.rb b/spec/models/integrations/base_issue_tracker_spec.rb
index 37f7d99717c..e1a764cd7cb 100644
--- a/spec/models/integrations/base_issue_tracker_spec.rb
+++ b/spec/models/integrations/base_issue_tracker_spec.rb
@@ -7,6 +7,10 @@ RSpec.describe Integrations::BaseIssueTracker do
let_it_be_with_refind(:project) { create :project }
+ describe 'default values' do
+ it { expect(subject.category).to eq(:issue_tracker) }
+ end
+
describe 'Validations' do
describe 'only one issue tracker per project' do
before do
diff --git a/spec/models/integrations/base_third_party_wiki_spec.rb b/spec/models/integrations/base_third_party_wiki_spec.rb
index 11e044c2a18..dbead636cb9 100644
--- a/spec/models/integrations/base_third_party_wiki_spec.rb
+++ b/spec/models/integrations/base_third_party_wiki_spec.rb
@@ -3,6 +3,10 @@
require 'spec_helper'
RSpec.describe Integrations::BaseThirdPartyWiki do
+ describe 'default values' do
+ it { expect(subject.category).to eq(:third_party_wiki) }
+ end
+
describe 'Validations' do
let_it_be_with_reload(:project) { create(:project) }
diff --git a/spec/models/integrations/buildkite_spec.rb b/spec/models/integrations/buildkite_spec.rb
index c720dc6d418..5f62c68bd2b 100644
--- a/spec/models/integrations/buildkite_spec.rb
+++ b/spec/models/integrations/buildkite_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Integrations::Buildkite, :use_clean_rails_memory_store_caching do
include ReactiveCachingHelpers
include StubRequests
- let(:project) { create(:project) }
+ let_it_be(:project) { create(:project) }
subject(:integration) do
described_class.create!(
@@ -18,6 +18,10 @@ RSpec.describe Integrations::Buildkite, :use_clean_rails_memory_store_caching do
)
end
+ it_behaves_like Integrations::BaseCi
+
+ it_behaves_like Integrations::ResetSecretFields
+
it_behaves_like Integrations::HasWebHook do
let(:hook_url) { 'https://webhook.buildkite.com/deliver/{webhook_token}' }
end
diff --git a/spec/models/integrations/campfire_spec.rb b/spec/models/integrations/campfire_spec.rb
index a6bcd22b6f6..ae923cd38fc 100644
--- a/spec/models/integrations/campfire_spec.rb
+++ b/spec/models/integrations/campfire_spec.rb
@@ -34,8 +34,8 @@ RSpec.describe Integrations::Campfire do
end
describe "#execute" do
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository) }
+ let(:user) { build_stubbed(:user) }
+ let(:project) { build_stubbed(:project, :repository) }
before do
@campfire_integration = described_class.new
diff --git a/spec/models/integrations/chat_message/pipeline_message_spec.rb b/spec/models/integrations/chat_message/pipeline_message_spec.rb
index a63cc0b6d83..f3388853b37 100644
--- a/spec/models/integrations/chat_message/pipeline_message_spec.rb
+++ b/spec/models/integrations/chat_message/pipeline_message_spec.rb
@@ -44,13 +44,18 @@ RSpec.describe Integrations::ChatMessage::PipelineMessage do
before do
test_commit = double("A test commit", committer: args[:user], title: "A test commit message")
- test_project = double("A test project", commit_by: test_commit, name: args[:project][:name], web_url: args[:project][:web_url])
+ test_project = build(:project, name: args[:project][:name])
+
+ allow(test_project).to receive(:commit_by).and_return(test_commit)
+ allow(test_project).to receive(:web_url).and_return(args[:project][:web_url])
allow(test_project).to receive(:avatar_url).with(no_args).and_return("/avatar")
allow(test_project).to receive(:avatar_url).with(only_path: false).and_return(args[:project][:avatar_url])
allow(Project).to receive(:find) { test_project }
- test_pipeline = double("A test pipeline",
- has_yaml_errors?: has_yaml_errors, yaml_errors: "yaml error description here")
+ test_pipeline = build(:ci_empty_pipeline, name: 'Build pipeline')
+
+ allow(test_pipeline).to receive(:has_yaml_errors?).and_return(has_yaml_errors)
+ allow(test_pipeline).to receive(:yaml_errors).and_return("yaml error description here")
allow(Ci::Pipeline).to receive(:find) { test_pipeline }
allow(Gitlab::UrlBuilder).to receive(:build).with(test_commit).and_return("http://example.com/commit")
@@ -69,6 +74,24 @@ RSpec.describe Integrations::ChatMessage::PipelineMessage do
)
end
+ it 'returns pipeline name' do
+ name_field = subject.attachments.first[:fields].find { |a| a[:title] == 'Pipeline name' }
+
+ expect(name_field[:value]).to eq('Build pipeline')
+ end
+
+ context 'when pipeline_name feature flag is disabled' do
+ before do
+ stub_feature_flags(pipeline_name: false)
+ end
+
+ it 'does not return pipeline name' do
+ name_field = subject.attachments.first[:fields].find { |a| a[:title] == 'Pipeline name' }
+
+ expect(name_field).to be nil
+ end
+ end
+
context "when the pipeline failed" do
before do
args[:object_attributes][:status] = 'failed'
@@ -204,8 +227,8 @@ RSpec.describe Integrations::ChatMessage::PipelineMessage do
expect(subject.attachments.first[:title_link]).to eq("http://example.gitlab.com/-/pipelines/123")
end
- it "returns two attachment fields" do
- expect(subject.attachments.first[:fields].count).to eq(2)
+ it "returns three attachment fields" do
+ expect(subject.attachments.first[:fields].count).to eq(3)
end
it "returns the commit message as the attachment's second field property" do
@@ -232,8 +255,8 @@ RSpec.describe Integrations::ChatMessage::PipelineMessage do
]
end
- it "returns four attachment fields" do
- expect(subject.attachments.first[:fields].count).to eq(4)
+ it "returns five attachment fields" do
+ expect(subject.attachments.first[:fields].count).to eq(5)
end
it "returns the stage name and link to the 'Failed jobs' tab on the pipeline's page as the attachment's third field property" do
@@ -337,8 +360,8 @@ RSpec.describe Integrations::ChatMessage::PipelineMessage do
context "when the CI config file contains a YAML error" do
let(:has_yaml_errors) { true }
- it "returns three attachment fields" do
- expect(subject.attachments.first[:fields].count).to eq(3)
+ it "returns four attachment fields" do
+ expect(subject.attachments.first[:fields].count).to eq(4)
end
it "returns the YAML error deatils as the attachment's third field property" do
diff --git a/spec/models/integrations/confluence_spec.rb b/spec/models/integrations/confluence_spec.rb
index e2f9316bc95..999a532527d 100644
--- a/spec/models/integrations/confluence_spec.rb
+++ b/spec/models/integrations/confluence_spec.rb
@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe Integrations::Confluence do
+ let_it_be(:project) { create(:project) }
+
describe 'Validations' do
before do
subject.active = active
@@ -40,7 +42,6 @@ RSpec.describe Integrations::Confluence do
describe '#help' do
it 'can correctly return a link to the project wiki when active' do
- project = create(:project)
subject.project = project
subject.active = true
@@ -62,8 +63,6 @@ RSpec.describe Integrations::Confluence do
end
describe 'Caching has_confluence on project_settings' do
- let(:project) { create(:project) }
-
subject { project.project_setting.has_confluence? }
it 'sets the property to true when integration is active' do
diff --git a/spec/models/integrations/datadog_spec.rb b/spec/models/integrations/datadog_spec.rb
index 71a5bbc4db1..65ecd9bee83 100644
--- a/spec/models/integrations/datadog_spec.rb
+++ b/spec/models/integrations/datadog_spec.rb
@@ -73,7 +73,15 @@ RSpec.describe Integrations::Datadog do
it { is_expected.to validate_presence_of(:datadog_site) }
it { is_expected.not_to validate_presence_of(:api_url) }
+ it { is_expected.to allow_value('data-dog-hq.com').for(:datadog_site) }
+ it { is_expected.to allow_value('dataDOG.com').for(:datadog_site) }
it { is_expected.not_to allow_value('datadog hq.com').for(:datadog_site) }
+ it { is_expected.not_to allow_value('-datadoghq.com').for(:datadog_site) }
+ it { is_expected.not_to allow_value('.datadoghq.com').for(:datadog_site) }
+ it { is_expected.not_to allow_value('datadoghq.com_').for(:datadog_site) }
+ it { is_expected.not_to allow_value('data-dog').for(:datadog_site) }
+ it { is_expected.not_to allow_value('datadoghq.com-').for(:datadog_site) }
+ it { is_expected.not_to allow_value('datadoghq.com.').for(:datadog_site) }
end
context 'with custom api_url' do
diff --git a/spec/models/integrations/discord_spec.rb b/spec/models/integrations/discord_spec.rb
index eb90acc73be..138a56d1872 100644
--- a/spec/models/integrations/discord_spec.rb
+++ b/spec/models/integrations/discord_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe Integrations::Discord do
let_it_be(:project) { create(:project, :repository) }
- let(:user) { create(:user) }
+ let(:user) { build_stubbed(:user) }
let(:webhook_url) { "https://example.gitlab.com/" }
let(:sample_data) do
Gitlab::DataBuilder::Push.build_sample(project, user)
diff --git a/spec/models/integrations/drone_ci_spec.rb b/spec/models/integrations/drone_ci_spec.rb
index f3203a6e69d..6ff6888e0d3 100644
--- a/spec/models/integrations/drone_ci_spec.rb
+++ b/spec/models/integrations/drone_ci_spec.rb
@@ -7,6 +7,10 @@ RSpec.describe Integrations::DroneCi, :use_clean_rails_memory_store_caching do
subject(:integration) { described_class.new }
+ let_it_be(:project) { create(:project, :repository, name: 'project') }
+
+ it_behaves_like Integrations::BaseCi
+
it_behaves_like Integrations::ResetSecretFields do
let(:integration) { subject }
end
@@ -43,7 +47,6 @@ RSpec.describe Integrations::DroneCi, :use_clean_rails_memory_store_caching do
)
end
- let(:project) { create(:project, :repository, name: 'project') }
let(:path) { project.full_path }
let(:drone_url) { 'http://drone.example.com' }
let(:sha) { '2ab7834c' }
@@ -192,7 +195,7 @@ RSpec.describe Integrations::DroneCi, :use_clean_rails_memory_store_caching do
describe "execute" do
include_context :drone_ci_integration
- let(:user) { create(:user, username: 'username') }
+ let(:user) { build(:user, username: 'username') }
let(:push_sample_data) do
Gitlab::DataBuilder::Push.build_sample(project, user)
end
diff --git a/spec/models/integrations/emails_on_push_spec.rb b/spec/models/integrations/emails_on_push_spec.rb
index 15aa105e379..b3fe6bf9506 100644
--- a/spec/models/integrations/emails_on_push_spec.rb
+++ b/spec/models/integrations/emails_on_push_spec.rb
@@ -87,8 +87,8 @@ RSpec.describe Integrations::EmailsOnPush do
end
describe '#execute' do
+ let_it_be(:project) { create(:project, :repository) }
let(:push_data) { { object_kind: 'push' } }
- let(:project) { create(:project, :repository) }
let(:integration) { create(:emails_on_push_integration, project: project) }
let(:recipients) { 'test@gitlab.com' }
diff --git a/spec/models/integrations/hangouts_chat_spec.rb b/spec/models/integrations/hangouts_chat_spec.rb
index 828bcdf5d8f..288478b494e 100644
--- a/spec/models/integrations/hangouts_chat_spec.rb
+++ b/spec/models/integrations/hangouts_chat_spec.rb
@@ -46,7 +46,7 @@ RSpec.describe Integrations::HangoutsChat do
end
context 'with issue events' do
- let(:issues_sample_data) { create(:issue).to_hook_data(user) }
+ let(:issues_sample_data) { create(:issue, project: project).to_hook_data(user) }
it "adds thread key for issue events" do
expect(chat_integration.execute(issues_sample_data)).to be(true)
@@ -58,7 +58,7 @@ RSpec.describe Integrations::HangoutsChat do
end
context 'with merge events' do
- let(:merge_sample_data) { create(:merge_request).to_hook_data(user) }
+ let(:merge_sample_data) { create(:merge_request, source_project: project).to_hook_data(user) }
it "adds thread key for merge events" do
expect(chat_integration.execute(merge_sample_data)).to be(true)
@@ -71,7 +71,7 @@ RSpec.describe Integrations::HangoutsChat do
context 'with wiki page events' do
let(:wiki_page_sample_data) do
- Gitlab::DataBuilder::WikiPage.build(create(:wiki_page, message: 'foo'), user, 'create')
+ Gitlab::DataBuilder::WikiPage.build(create(:wiki_page, project: project, message: 'foo'), user, 'create')
end
it "adds thread key for wiki page events" do
diff --git a/spec/models/integrations/harbor_spec.rb b/spec/models/integrations/harbor_spec.rb
index 9ab37a92e89..b4580028112 100644
--- a/spec/models/integrations/harbor_spec.rb
+++ b/spec/models/integrations/harbor_spec.rb
@@ -70,7 +70,7 @@ RSpec.describe Integrations::Harbor do
end
context 'ci variables' do
- let(:harbor_integration) { create(:harbor_integration) }
+ let(:harbor_integration) { build_stubbed(:harbor_integration) }
it 'returns vars when harbor_integration is activated' do
ci_vars = [
@@ -85,9 +85,12 @@ RSpec.describe Integrations::Harbor do
expect(harbor_integration.ci_variables).to match_array(ci_vars)
end
- it 'returns [] when harbor_integration is inactive' do
- harbor_integration.update!(active: false)
- expect(harbor_integration.ci_variables).to match_array([])
+ context 'when harbor_integration is inactive' do
+ let(:harbor_integration) { build_stubbed(:harbor_integration, active: false) }
+
+ it 'returns []' do
+ expect(harbor_integration.ci_variables).to match_array([])
+ end
end
context 'with robot username' do
diff --git a/spec/models/integrations/jenkins_spec.rb b/spec/models/integrations/jenkins_spec.rb
index 200de1305e2..0264982f0dc 100644
--- a/spec/models/integrations/jenkins_spec.rb
+++ b/spec/models/integrations/jenkins_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Integrations::Jenkins do
- let(:project) { create(:project) }
+ let_it_be(:project) { create(:project) }
let(:jenkins_integration) { described_class.new(jenkins_params) }
let(:jenkins_url) { 'http://jenkins.example.com/' }
let(:jenkins_hook_url) { jenkins_url + 'project/my_project' }
@@ -23,6 +23,12 @@ RSpec.describe Integrations::Jenkins do
}
end
+ it_behaves_like Integrations::BaseCi
+
+ it_behaves_like Integrations::ResetSecretFields do
+ let(:integration) { jenkins_integration }
+ end
+
include_context Integrations::EnableSslVerification do
let(:integration) { jenkins_integration }
end
@@ -38,7 +44,7 @@ RSpec.describe Integrations::Jenkins do
expect(jenkins_integration.tag_push_events).to eq(false)
end
- describe 'username validation' do
+ describe 'Validations' do
let(:jenkins_integration) do
described_class.create!(
active: active,
@@ -57,28 +63,44 @@ RSpec.describe Integrations::Jenkins do
context 'when the integration is active' do
let(:active) { true }
- context 'when password was not touched' do
- before do
- allow(subject).to receive(:password_touched?).and_return(false)
+ describe '#username' do
+ context 'when password was not touched' do
+ before do
+ allow(subject).to receive(:password_touched?).and_return(false)
+ end
+
+ it { is_expected.not_to validate_presence_of :username }
end
- it { is_expected.not_to validate_presence_of :username }
- end
+ context 'when password was touched' do
+ before do
+ allow(subject).to receive(:password_touched?).and_return(true)
+ end
- context 'when password was touched' do
- before do
- allow(subject).to receive(:password_touched?).and_return(true)
+ it { is_expected.to validate_presence_of :username }
end
- it { is_expected.to validate_presence_of :username }
+ context 'when password is blank' do
+ it 'does not validate the username' do
+ expect(subject).not_to validate_presence_of :username
+
+ subject.password = ''
+ subject.save!
+ end
+ end
end
- context 'when password is blank' do
- it 'does not validate the username' do
- expect(subject).not_to validate_presence_of :username
+ describe '#password' do
+ it 'does not validate the presence of password if username is nil' do
+ subject.username = nil
+
+ expect(subject).not_to validate_presence_of(:password)
+ end
+
+ it 'validates the presence of password if username is present' do
+ subject.username = 'john'
- subject.password = ''
- subject.save!
+ expect(subject).to validate_presence_of(:password)
end
end
end
@@ -87,6 +109,7 @@ RSpec.describe Integrations::Jenkins do
let(:active) { false }
it { is_expected.not_to validate_presence_of :username }
+ it { is_expected.not_to validate_presence_of :password }
end
end
@@ -144,8 +167,7 @@ RSpec.describe Integrations::Jenkins do
describe '#test' do
it 'returns the right status' do
- user = create(:user, username: 'username')
- project = create(:project, name: 'project')
+ user = build(:user, username: 'username')
push_sample_data = Gitlab::DataBuilder::Push.build_sample(project, user)
jenkins_integration = described_class.create!(jenkins_params)
stub_request(:post, jenkins_hook_url).with(headers: { 'Authorization' => jenkins_authorization })
@@ -157,9 +179,9 @@ RSpec.describe Integrations::Jenkins do
end
describe '#execute' do
- let(:user) { create(:user, username: 'username') }
- let(:namespace) { create(:group, :private) }
- let(:project) { create(:project, :private, name: 'project', namespace: namespace) }
+ let(:user) { build(:user, username: 'username') }
+ let_it_be(:namespace) { create(:group, :private) }
+ let_it_be(:project) { create(:project, :private, name: 'project', namespace: namespace) }
let(:push_sample_data) { Gitlab::DataBuilder::Push.build_sample(project, user) }
let(:jenkins_integration) { described_class.create!(jenkins_params) }
@@ -191,82 +213,4 @@ RSpec.describe Integrations::Jenkins do
).to have_been_made.once
end
end
-
- describe 'Stored password invalidation' do
- let(:project) { create(:project) }
-
- context 'when a password was previously set' do
- let(:jenkins_integration) do
- described_class.create!(
- project: project,
- properties: {
- jenkins_url: 'http://jenkins.example.com/',
- username: 'jenkins',
- password: 'password'
- }
- )
- end
-
- it 'resets password if url changed' do
- jenkins_integration.jenkins_url = 'http://jenkins-edited.example.com/'
- jenkins_integration.valid?
-
- expect(jenkins_integration.password).to be_nil
- end
-
- it 'resets password if username is blank' do
- jenkins_integration.username = ''
- jenkins_integration.valid?
-
- expect(jenkins_integration.password).to be_nil
- end
-
- it 'does not reset password if username changed' do
- jenkins_integration.username = 'some_name'
- jenkins_integration.valid?
-
- expect(jenkins_integration.password).to eq('password')
- end
-
- it 'does not reset password if new url is set together with password, even if it\'s the same password' do
- jenkins_integration.jenkins_url = 'http://jenkins_edited.example.com/'
- jenkins_integration.password = 'password'
- jenkins_integration.valid?
-
- expect(jenkins_integration.password).to eq('password')
- expect(jenkins_integration.jenkins_url).to eq('http://jenkins_edited.example.com/')
- end
-
- it 'resets password if url changed, even if setter called multiple times' do
- jenkins_integration.jenkins_url = 'http://jenkins1.example.com/'
- jenkins_integration.jenkins_url = 'http://jenkins1.example.com/'
- jenkins_integration.valid?
-
- expect(jenkins_integration.password).to be_nil
- end
- end
-
- context 'when no password was previously set' do
- let(:jenkins_integration) do
- described_class.create!(
- project: create(:project),
- properties: {
- jenkins_url: 'http://jenkins.example.com/',
- username: 'jenkins'
- }
- )
- end
-
- it 'saves password if new url is set together with password' do
- jenkins_integration.jenkins_url = 'http://jenkins_edited.example.com/'
- jenkins_integration.password = 'password'
- jenkins_integration.save!
-
- expect(jenkins_integration.reload).to have_attributes(
- jenkins_url: 'http://jenkins_edited.example.com/',
- password: 'password'
- )
- end
- end
- end
end
diff --git a/spec/models/integrations/jira_spec.rb b/spec/models/integrations/jira_spec.rb
index 9f928442b28..819dad9d46d 100644
--- a/spec/models/integrations/jira_spec.rb
+++ b/spec/models/integrations/jira_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe Integrations::Jira do
end
before do
- WebMock.stub_request(:get, /serverInfo/).to_return(body: server_info_results.to_json )
+ WebMock.stub_request(:get, /serverInfo/).to_return(body: server_info_results.to_json)
end
it_behaves_like Integrations::ResetSecretFields do
@@ -162,7 +162,7 @@ RSpec.describe Integrations::Jira do
end
describe '#fields' do
- let(:integration) { create(:jira_integration) }
+ let(:integration) { jira_integration }
subject(:fields) { integration.fields }
@@ -172,7 +172,7 @@ RSpec.describe Integrations::Jira do
end
describe '#sections' do
- let(:integration) { create(:jira_integration) }
+ let(:integration) { jira_integration }
subject(:sections) { integration.sections.map { |s| s[:type] } }
@@ -332,28 +332,7 @@ RSpec.describe Integrations::Jira do
# we need to make sure we are able to read both from properties and jira_tracker_data table
# TODO: change this as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
context 'overriding properties' do
- let(:access_params) do
- { url: url, api_url: api_url, username: username, password: password,
- jira_issue_transition_id: transition_id }
- end
-
- let(:data_params) do
- {
- url: url, api_url: api_url,
- username: username, password: password,
- jira_issue_transition_id: transition_id
- }
- end
-
shared_examples 'handles jira fields' do
- let(:data_params) do
- {
- url: url, api_url: api_url,
- username: username, password: password,
- jira_issue_transition_id: transition_id
- }
- end
-
context 'reading data' do
it 'reads data correctly' do
expect(integration.url).to eq(url)
@@ -449,32 +428,40 @@ RSpec.describe Integrations::Jira do
end
# this will be removed as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
- context 'when data are stored in properties' do
- let(:properties) { data_params }
- let!(:integration) do
- create(:jira_integration, :without_properties_callback, properties: properties.merge(additional: 'something'))
+ context 'with properties' do
+ let(:data_params) do
+ {
+ url: url, api_url: api_url,
+ username: username, password: password,
+ jira_issue_transition_id: transition_id
+ }
end
- it_behaves_like 'handles jira fields'
- end
+ context 'when data are stored in properties' do
+ let(:integration) do
+ create(:jira_integration, :without_properties_callback, project: project, properties: data_params.merge(additional: 'something'))
+ end
- context 'when data are stored in separated fields' do
- let(:integration) do
- create(:jira_integration, data_params.merge(properties: {}))
+ it_behaves_like 'handles jira fields'
end
- it_behaves_like 'handles jira fields'
- end
-
- context 'when data are stored in both properties and separated fields' do
- let(:properties) { data_params }
- let(:integration) do
- create(:jira_integration, :without_properties_callback, properties: properties).tap do |integration|
- create(:jira_tracker_data, data_params.merge(integration: integration))
+ context 'when data are stored in separated fields' do
+ let(:integration) do
+ create(:jira_integration, data_params.merge(properties: {}, project: project))
end
+
+ it_behaves_like 'handles jira fields'
end
- it_behaves_like 'handles jira fields'
+ context 'when data are stored in both properties and separated fields' do
+ let(:integration) do
+ create(:jira_integration, :without_properties_callback, properties: data_params, project: project).tap do |integration|
+ create(:jira_tracker_data, data_params.merge(integration: integration))
+ end
+ end
+
+ it_behaves_like 'handles jira fields'
+ end
end
end
@@ -872,7 +859,7 @@ RSpec.describe Integrations::Jira do
end
context 'when resource is a merge request' do
- let(:resource) { create(:merge_request) }
+ let_it_be(:resource) { create(:merge_request, source_project: project) }
let(:commit_id) { resource.diff_head_sha }
it_behaves_like 'close_issue'
@@ -1084,7 +1071,7 @@ RSpec.describe Integrations::Jira do
end
it 'removes trailing slashes from url' do
- integration = described_class.new(url: 'http://jira.test.com/path/')
+ integration = described_class.new(url: 'http://jira.test.com/path/', project: project)
expect(integration.url).to eq('http://jira.test.com/path')
end
@@ -1105,7 +1092,7 @@ RSpec.describe Integrations::Jira do
end
context 'generating external URLs' do
- let(:integration) { described_class.new(url: 'http://jira.test.com/path/') }
+ let(:integration) { described_class.new(url: 'http://jira.test.com/path/', project: project) }
describe '#web_url' do
it 'handles paths, slashes, and query string' do
diff --git a/spec/models/integrations/mattermost_slash_commands_spec.rb b/spec/models/integrations/mattermost_slash_commands_spec.rb
index b6abe00469b..070adb9ba93 100644
--- a/spec/models/integrations/mattermost_slash_commands_spec.rb
+++ b/spec/models/integrations/mattermost_slash_commands_spec.rb
@@ -6,9 +6,9 @@ RSpec.describe Integrations::MattermostSlashCommands do
it_behaves_like Integrations::BaseSlashCommands
describe 'Mattermost API' do
- let(:project) { create(:project) }
+ let_it_be_with_reload(:project) { create(:project) }
let(:integration) { project.build_mattermost_slash_commands_integration }
- let(:user) { create(:user) }
+ let(:user) { build_stubbed(:user) }
before do
session = ::Mattermost::Session.new(nil)
diff --git a/spec/models/integrations/microsoft_teams_spec.rb b/spec/models/integrations/microsoft_teams_spec.rb
index b6de2bb7176..c61cc732372 100644
--- a/spec/models/integrations/microsoft_teams_spec.rb
+++ b/spec/models/integrations/microsoft_teams_spec.rb
@@ -17,35 +17,8 @@ RSpec.describe Integrations::MicrosoftTeams do
let(:chat_integration) { described_class.new }
let(:webhook_url) { 'https://example.gitlab.com/' }
- describe 'Validations' do
- context 'when integration is active' do
- before do
- subject.active = true
- end
-
- it { is_expected.to validate_presence_of(:webhook) }
-
- it_behaves_like 'issue tracker integration URL attribute', :webhook
- end
-
- context 'when integration is inactive' do
- before do
- subject.active = false
- end
-
- it { is_expected.not_to validate_presence_of(:webhook) }
- end
- end
-
- describe '.supported_events' do
- it 'does not support deployment_events' do
- expect(described_class.supported_events).not_to include('deployment')
- end
- end
-
describe "#execute" do
- let(:user) { create(:user) }
-
+ let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository, :wiki_repo) }
before do
@@ -145,8 +118,8 @@ RSpec.describe Integrations::MicrosoftTeams do
end
describe "Note events" do
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository, creator: user) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository, creator: user) }
before do
allow(chat_integration).to receive_messages(
@@ -221,8 +194,7 @@ RSpec.describe Integrations::MicrosoftTeams do
end
describe 'Pipeline events' do
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository) }
+ let_it_be_with_reload(:project) { create(:project, :repository) }
let(:pipeline) do
create(:ci_pipeline,
diff --git a/spec/models/integrations/mock_ci_spec.rb b/spec/models/integrations/mock_ci_spec.rb
index d29c63b3a97..83954812bfe 100644
--- a/spec/models/integrations/mock_ci_spec.rb
+++ b/spec/models/integrations/mock_ci_spec.rb
@@ -7,6 +7,8 @@ RSpec.describe Integrations::MockCi do
subject(:integration) { described_class.new(project: project, mock_service_url: generate(:url)) }
+ it_behaves_like Integrations::BaseCi
+
include_context Integrations::EnableSslVerification
describe '#commit_status' do
diff --git a/spec/models/integrations/packagist_spec.rb b/spec/models/integrations/packagist_spec.rb
index e078debd126..e00de0f7418 100644
--- a/spec/models/integrations/packagist_spec.rb
+++ b/spec/models/integrations/packagist_spec.rb
@@ -3,50 +3,76 @@
require 'spec_helper'
RSpec.describe Integrations::Packagist do
- let(:packagist_params) do
- {
- active: true,
- project: project,
- properties: {
- username: packagist_username,
- token: packagist_token,
- server: packagist_server
- }
- }
- end
-
- let(:packagist_hook_url) do
- "#{packagist_server}/api/update-package?username=#{packagist_username}&apiToken=#{packagist_token}"
- end
-
- let(:packagist_token) { 'verySecret' }
- let(:packagist_username) { 'theUser' }
- let(:packagist_server) { 'https://packagist.example.com' }
- let(:project) { create(:project) }
-
it_behaves_like Integrations::HasWebHook do
- let(:integration) { described_class.new(packagist_params) }
- let(:hook_url) { "#{packagist_server}/api/update-package?username={username}&apiToken={token}" }
+ let_it_be(:project) { create(:project) }
+
+ let(:integration) { build(:packagist_integration, project: project) }
+ let(:hook_url) { "#{integration.server}/api/update-package?username={username}&apiToken={token}" }
end
it_behaves_like Integrations::ResetSecretFields do
- let(:integration) { described_class.new(packagist_params) }
+ let(:integration) { build(:packagist_integration) }
end
describe '#execute' do
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository) }
- let(:push_sample_data) { Gitlab::DataBuilder::Push.build_sample(project, user) }
- let(:packagist_integration) { described_class.create!(packagist_params) }
+ let(:project) { build(:project) }
+ let(:integration) { build(:packagist_integration, project: project) }
+
+ let(:packagist_hook_url) do
+ "#{integration.server}/api/update-package?username=#{integration.username}&apiToken=#{integration.token}"
+ end
before do
stub_request(:post, packagist_hook_url)
end
it 'calls Packagist API' do
- packagist_integration.execute(push_sample_data)
+ user = create(:user)
+ push_sample_data = Gitlab::DataBuilder::Push.build_sample(project, user)
+ integration.execute(push_sample_data)
expect(a_request(:post, packagist_hook_url)).to have_been_made.once
end
end
+
+ describe '#test' do
+ let(:integration) { build(:packagist_integration) }
+ let(:test_data) { { foo: 'bar' } }
+
+ subject(:result) { integration.test(test_data) }
+
+ context 'when test request executes without errors' do
+ before do
+ allow(integration).to receive(:execute).with(test_data).and_return(
+ ServiceResponse.success(message: 'success message', payload: { http_status: http_status })
+ )
+ end
+
+ context 'when response is a 200' do
+ let(:http_status) { 200 }
+
+ it 'return failure result' do
+ is_expected.to eq(success: false, result: 'success message')
+ end
+ end
+
+ context 'when response is a 202' do
+ let(:http_status) { 202 }
+
+ it 'return success result' do
+ is_expected.to eq(success: true, result: 'success message')
+ end
+ end
+ end
+
+ context 'when test request executes with errors' do
+ before do
+ allow(integration).to receive(:execute).with(test_data).and_raise(StandardError, 'error message')
+ end
+
+ it 'return failure result' do
+ is_expected.to eq(success: false, result: 'error message')
+ end
+ end
+ end
end
diff --git a/spec/models/integrations/pipelines_email_spec.rb b/spec/models/integrations/pipelines_email_spec.rb
index d70f104b965..37a3849a768 100644
--- a/spec/models/integrations/pipelines_email_spec.rb
+++ b/spec/models/integrations/pipelines_email_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Integrations::PipelinesEmail, :mailer do
)
end
- let(:project) { create(:project, :repository) }
+ let_it_be_with_reload(:project) { create(:project, :repository) }
let(:recipients) { 'test@gitlab.com' }
let(:receivers) { [recipients] }
diff --git a/spec/models/integrations/prometheus_spec.rb b/spec/models/integrations/prometheus_spec.rb
index 3971511872b..3c3850854b3 100644
--- a/spec/models/integrations/prometheus_spec.rb
+++ b/spec/models/integrations/prometheus_spec.rb
@@ -12,6 +12,8 @@ RSpec.describe Integrations::Prometheus, :use_clean_rails_memory_store_caching,
let(:integration) { project.prometheus_integration }
+ it_behaves_like Integrations::BaseMonitoring
+
context 'redirects' do
it 'does not follow redirects' do
redirect_to = 'https://redirected.example.com'
@@ -217,7 +219,7 @@ RSpec.describe Integrations::Prometheus, :use_clean_rails_memory_store_caching,
expect(integration.prometheus_client).to be_nil
end
- context 'with self monitoring project and internal Prometheus URL' do
+ context 'with self-monitoring project and internal Prometheus URL' do
before do
stub_application_setting(allow_local_requests_from_web_hooks_and_services: false)
stub_application_setting(self_monitoring_project_id: project.id)
@@ -308,7 +310,7 @@ RSpec.describe Integrations::Prometheus, :use_clean_rails_memory_store_caching,
end
context 'cluster belongs to project' do
- let(:cluster) { create(:cluster, projects: [project]) }
+ let_it_be(:cluster) { create(:cluster, projects: [project]) }
it 'returns true' do
expect(integration.prometheus_available?).to be(true)
@@ -319,7 +321,7 @@ RSpec.describe Integrations::Prometheus, :use_clean_rails_memory_store_caching,
let_it_be(:group) { create(:group) }
let(:project) { create(:project, :with_prometheus_integration, group: group) }
- let(:cluster) { create(:cluster_for_group, groups: [group]) }
+ let_it_be(:cluster) { create(:cluster_for_group, groups: [group]) }
it 'returns true' do
expect(integration.prometheus_available?).to be(true)
diff --git a/spec/models/integrations/pushover_spec.rb b/spec/models/integrations/pushover_spec.rb
index 716a00c5bcf..8286fd20669 100644
--- a/spec/models/integrations/pushover_spec.rb
+++ b/spec/models/integrations/pushover_spec.rb
@@ -29,8 +29,8 @@ RSpec.describe Integrations::Pushover do
describe 'Execute' do
let(:pushover) { described_class.new }
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository) }
+ let(:user) { build_stubbed(:user) }
+ let(:project) { build_stubbed(:project, :repository) }
let(:sample_data) do
Gitlab::DataBuilder::Push.build_sample(project, user)
end
diff --git a/spec/models/integrations/shimo_spec.rb b/spec/models/integrations/shimo_spec.rb
index 41f3f3c0c16..be626012ab2 100644
--- a/spec/models/integrations/shimo_spec.rb
+++ b/spec/models/integrations/shimo_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe ::Integrations::Shimo do
describe '#fields' do
- let(:shimo_integration) { create(:shimo_integration) }
+ let(:shimo_integration) { build(:shimo_integration) }
it 'returns custom fields' do
expect(shimo_integration.fields.pluck(:name)).to eq(%w[external_wiki_url])
@@ -12,7 +12,7 @@ RSpec.describe ::Integrations::Shimo do
end
describe '#create' do
- let(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project, :repository) }
let(:external_wiki_url) { 'https://shimo.example.com/desktop' }
let(:params) { { active: true, project: project, external_wiki_url: external_wiki_url } }
@@ -40,7 +40,7 @@ RSpec.describe ::Integrations::Shimo do
end
describe 'Caching has_shimo on project_settings' do
- let(:project) { create(:project) }
+ let_it_be(:project) { create(:project) }
subject { project.project_setting.has_shimo? }
diff --git a/spec/models/integrations/slack_slash_commands_spec.rb b/spec/models/integrations/slack_slash_commands_spec.rb
index ff89d2c6a40..22cbaa777cd 100644
--- a/spec/models/integrations/slack_slash_commands_spec.rb
+++ b/spec/models/integrations/slack_slash_commands_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe Integrations::SlackSlashCommands do
describe '#trigger' do
context 'when an auth url is generated' do
- let(:project) { create(:project) }
+ let_it_be(:project) { create(:project) }
let(:params) do
{
team_domain: 'http://domain.tld',
diff --git a/spec/models/integrations/slack_spec.rb b/spec/models/integrations/slack_spec.rb
index ed282f1d39d..a12bc7f4831 100644
--- a/spec/models/integrations/slack_spec.rb
+++ b/spec/models/integrations/slack_spec.rb
@@ -3,142 +3,6 @@
require 'spec_helper'
RSpec.describe Integrations::Slack do
- it_behaves_like Integrations::SlackMattermostNotifier, "Slack"
-
- describe '#execute' do
- let(:slack_integration) { create(:integrations_slack, branches_to_be_notified: 'all', project_id: project.id) }
- let(:project) { create_default(:project, :repository, :wiki_repo) }
-
- before do
- stub_request(:post, slack_integration.webhook)
- end
-
- it 'uses only known events', :aggregate_failures do
- described_class::SUPPORTED_EVENTS_FOR_USAGE_LOG.each do |action|
- expect(Gitlab::UsageDataCounters::HLLRedisCounter.known_event?("i_ecosystem_slack_service_#{action}_notification")).to be true
- end
- end
-
- context 'hook data includes a user object' do
- let_it_be(:user) { create_default(:user) }
-
- shared_examples 'increases the usage data counter' do |event_name|
- subject(:execute) { slack_integration.execute(data) }
-
- it 'increases the usage data counter' do
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event).with(event_name, values: user.id).and_call_original
-
- execute
- end
-
- it_behaves_like 'Snowplow event tracking' do
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
- let(:category) { 'Integrations::Slack' }
- let(:action) { 'perform_integrations_action' }
- let(:namespace) { project.namespace }
- let(:label) { 'redis_hll_counters.ecosystem.ecosystem_total_unique_counts_monthly' }
- let(:property) { event_name }
- end
- end
-
- context 'event is not supported for usage log' do
- let_it_be(:pipeline) { create(:ci_pipeline) }
-
- let(:data) { Gitlab::DataBuilder::Pipeline.build(pipeline) }
-
- it 'does not increase the usage data counter' do
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event).with('i_ecosystem_slack_service_pipeline_notification', values: user.id)
-
- slack_integration.execute(data)
- end
- end
-
- context 'issue notification' do
- let_it_be(:issue) { create(:issue) }
-
- let(:data) { issue.to_hook_data(user) }
-
- it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_issue_notification'
- end
-
- context 'push notification' do
- let(:data) { Gitlab::DataBuilder::Push.build_sample(project, user) }
-
- it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_push_notification'
- end
-
- context 'deployment notification' do
- let_it_be(:deployment) { create(:deployment, user: user) }
-
- let(:data) { Gitlab::DataBuilder::Deployment.build(deployment, deployment.status, Time.current) }
-
- it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_deployment_notification'
- end
-
- context 'wiki_page notification' do
- let(:wiki_page) { create(:wiki_page, wiki: project.wiki, message: 'user created page: Awesome wiki_page') }
-
- let(:data) { Gitlab::DataBuilder::WikiPage.build(wiki_page, user, 'create') }
-
- before do
- # Skip this method that is not relevant to this test to prevent having
- # to update project which is frozen
- allow(project.wiki).to receive(:after_wiki_activity)
- end
-
- it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_wiki_page_notification'
- end
-
- context 'merge_request notification' do
- let_it_be(:merge_request) { create(:merge_request) }
-
- let(:data) { merge_request.to_hook_data(user) }
-
- it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_merge_request_notification'
- end
-
- context 'note notification' do
- let_it_be(:issue_note) { create(:note_on_issue, note: 'issue note') }
-
- let(:data) { Gitlab::DataBuilder::Note.build(issue_note, user) }
-
- it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_note_notification'
- end
-
- context 'tag_push notification' do
- let(:oldrev) { Gitlab::Git::BLANK_SHA }
- let(:newrev) { '8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b' } # gitlab-test: git rev-parse refs/tags/v1.1.0
- let(:ref) { 'refs/tags/v1.1.0' }
- let(:data) { Git::TagHooksService.new(project, user, change: { oldrev: oldrev, newrev: newrev, ref: ref }).send(:push_data) }
-
- it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_tag_push_notification'
- end
-
- context 'confidential note notification' do
- let_it_be(:confidential_issue_note) { create(:note_on_issue, note: 'issue note', confidential: true) }
-
- let(:data) { Gitlab::DataBuilder::Note.build(confidential_issue_note, user) }
-
- it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_confidential_note_notification'
- end
-
- context 'confidential issue notification' do
- let_it_be(:issue) { create(:issue, confidential: true) }
-
- let(:data) { issue.to_hook_data(user) }
-
- it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_confidential_issue_notification'
- end
- end
-
- context 'hook data does not include a user' do
- let(:data) { Gitlab::DataBuilder::Pipeline.build(create(:ci_pipeline)) }
-
- it 'does not increase the usage data counter' do
- expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
-
- slack_integration.execute(data)
- end
- end
- end
+ it_behaves_like Integrations::SlackMattermostNotifier, 'Slack'
+ it_behaves_like Integrations::BaseSlackNotification, factory: :integrations_slack
end
diff --git a/spec/models/integrations/teamcity_spec.rb b/spec/models/integrations/teamcity_spec.rb
index da559264c1e..e32088a2f79 100644
--- a/spec/models/integrations/teamcity_spec.rb
+++ b/spec/models/integrations/teamcity_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe Integrations::Teamcity, :use_clean_rails_memory_store_caching do
let(:teamcity_url) { 'https://gitlab.teamcity.com' }
let(:teamcity_full_url) { 'https://gitlab.teamcity.com/httpAuth/app/rest/builds/branch:unspecified:any,revision:123' }
- let(:project) { create(:project) }
+ let_it_be(:project) { create(:project) }
subject(:integration) do
described_class.create!(
@@ -22,6 +22,10 @@ RSpec.describe Integrations::Teamcity, :use_clean_rails_memory_store_caching do
)
end
+ it_behaves_like Integrations::BaseCi
+
+ it_behaves_like Integrations::ResetSecretFields
+
include_context Integrations::EnableSslVerification do
describe '#enable_ssl_verification' do
before do
@@ -120,50 +124,6 @@ RSpec.describe Integrations::Teamcity, :use_clean_rails_memory_store_caching do
end
end
- describe 'Callbacks' do
- let(:teamcity_integration) { integration }
-
- describe 'before_validation :reset_password' do
- context 'when a password was previously set' do
- it 'resets password if url changed' do
- teamcity_integration.teamcity_url = 'http://gitlab1.com'
- teamcity_integration.valid?
-
- expect(teamcity_integration.password).to be_nil
- end
-
- it 'does not reset password if username changed' do
- teamcity_integration.username = 'some_name'
- teamcity_integration.valid?
-
- expect(teamcity_integration.password).to eq('password')
- end
-
- it "does not reset password if new url is set together with password, even if it's the same password" do
- teamcity_integration.teamcity_url = 'http://gitlab_edited.com'
- teamcity_integration.password = 'password'
- teamcity_integration.valid?
-
- expect(teamcity_integration.password).to eq('password')
- expect(teamcity_integration.teamcity_url).to eq('http://gitlab_edited.com')
- end
- end
-
- it 'saves password if new url is set together with password when no password was previously set' do
- teamcity_integration.password = nil
-
- teamcity_integration.teamcity_url = 'http://gitlab_edited.com'
- teamcity_integration.password = 'password'
- teamcity_integration.save!
-
- expect(teamcity_integration.reload).to have_attributes(
- teamcity_url: 'http://gitlab_edited.com',
- password: 'password'
- )
- end
- end
- end
-
describe '#build_page' do
it 'returns the contents of the reactive cache' do
stub_reactive_cache(integration, { build_page: 'foo' }, 'sha', 'ref')
diff --git a/spec/models/integrations/zentao_spec.rb b/spec/models/integrations/zentao_spec.rb
index 1a32453819d..2fa4df0e900 100644
--- a/spec/models/integrations/zentao_spec.rb
+++ b/spec/models/integrations/zentao_spec.rb
@@ -7,15 +7,14 @@ RSpec.describe Integrations::Zentao do
let(:api_url) { 'https://jihudemo.zentao.net' }
let(:api_token) { 'ZENTAO_TOKEN' }
let(:zentao_product_xid) { '3' }
- let(:zentao_integration) { create(:zentao_integration) }
+ let(:zentao_integration) { build(:zentao_integration, project: project) }
+ let_it_be(:project) { create(:project, :repository) }
it_behaves_like Integrations::ResetSecretFields do
let(:integration) { zentao_integration }
end
describe 'set_default_data' do
- let(:project) { create(:project, :repository) }
-
context 'when gitlab.yml was initialized' do
it 'is prepopulated with the settings' do
settings = {
@@ -35,7 +34,6 @@ RSpec.describe Integrations::Zentao do
end
describe '#create' do
- let(:project) { create(:project, :repository) }
let(:params) do
{
project: project,
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index e7b2212ebff..aea8bdaf343 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -25,6 +25,7 @@ RSpec.describe Issue do
it { is_expected.to have_many(:design_versions) }
it { is_expected.to have_one(:sentry_issue) }
it { is_expected.to have_one(:alert_management_alert) }
+ it { is_expected.to have_many(:alert_management_alerts) }
it { is_expected.to have_many(:resource_milestone_events) }
it { is_expected.to have_many(:resource_state_events) }
it { is_expected.to have_and_belong_to_many(:prometheus_alert_events) }
@@ -654,7 +655,7 @@ RSpec.describe Issue do
let_it_be(:authorized_issue_a) { create(:issue, project: authorized_project) }
let_it_be(:authorized_issue_b) { create(:issue, project: authorized_project) }
let_it_be(:authorized_issue_c) { create(:issue, project: authorized_project2) }
- let_it_be(:authorized_incident_a) { create(:incident, project: authorized_project ) }
+ let_it_be(:authorized_incident_a) { create(:incident, project: authorized_project) }
let_it_be(:unauthorized_issue) { create(:issue, project: unauthorized_project) }
@@ -863,7 +864,7 @@ RSpec.describe Issue do
describe '.to_branch_name' do
it 'parameterizes arguments and joins with dashes' do
- expect(described_class.to_branch_name(123, 'foo bar', '!@#$%', 'f!o@o#b$a%r^')).to eq('123-foo-bar-f-o-o-b-a-r')
+ expect(described_class.to_branch_name(123, 'foo bar!@#$%f!o@o#b$a%r^')).to eq('123-foo-bar-f-o-o-b-a-r')
end
it 'preserves the case in the first argument' do
@@ -871,7 +872,7 @@ RSpec.describe Issue do
end
it 'truncates branch name to at most 100 characters' do
- expect(described_class.to_branch_name('a' * 101)).to eq('a' * 100)
+ expect(described_class.to_branch_name('a' * 101, 'a')).to eq('a' * 100)
end
it 'truncates dangling parts of the branch name' do
@@ -883,6 +884,13 @@ RSpec.describe Issue do
# 100 characters would've got us "999-lorem...lacus-custom-fri".
expect(branch_name).to eq('999-lorem-ipsum-dolor-sit-amet-consectetur-adipiscing-elit-mauris-sit-amet-ipsum-id-lacus-custom')
end
+
+ it 'takes issue branch template into account' do
+ project = create(:project)
+ project.project_setting.update!(issue_branch_template: 'feature-%{id}-%{title}')
+
+ expect(described_class.to_branch_name(123, 'issue title', project: project)).to eq('feature-123-issue-title')
+ end
end
describe '#to_branch_name' do
@@ -1785,4 +1793,22 @@ RSpec.describe Issue do
end
end
end
+
+ describe '#full_search' do
+ context 'when searching non-english terms' do
+ [
+ 'abc 中文語',
+ '中文語cn',
+ '中文語',
+ 'Привет'
+ ].each do |term|
+ it 'adds extra where clause to match partial index' do
+ expect(described_class.full_search(term).to_sql).to include(
+ "AND (issues.title NOT SIMILAR TO '[\\u0000-\\u02FF\\u1E00-\\u1EFF\\u2070-\\u218F]*' " \
+ "OR issues.description NOT SIMILAR TO '[\\u0000-\\u02FF\\u1E00-\\u1EFF\\u2070-\\u218F]*')"
+ )
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/jira_connect_installation_spec.rb b/spec/models/jira_connect_installation_spec.rb
index e57d3e78a4e..09a4a7a488c 100644
--- a/spec/models/jira_connect_installation_spec.rb
+++ b/spec/models/jira_connect_installation_spec.rb
@@ -71,7 +71,7 @@ RSpec.describe JiraConnectInstallation do
end
describe '#oauth_authorization_url' do
- let_it_be(:installation) { create(:jira_connect_installation) }
+ let(:installation) { build(:jira_connect_installation) }
subject { installation.oauth_authorization_url }
@@ -82,7 +82,7 @@ RSpec.describe JiraConnectInstallation do
it { is_expected.to eq('http://test.host') }
context 'with instance_url' do
- let_it_be(:installation) { create(:jira_connect_installation, instance_url: 'https://gitlab.example.com') }
+ let(:installation) { build(:jira_connect_installation, instance_url: 'https://gitlab.example.com') }
it { is_expected.to eq('https://gitlab.example.com') }
@@ -97,42 +97,42 @@ RSpec.describe JiraConnectInstallation do
end
describe 'audience_url' do
- let_it_be(:installation) { create(:jira_connect_installation) }
+ let(:installation) { build(:jira_connect_installation) }
subject(:audience) { installation.audience_url }
it { is_expected.to eq(nil) }
context 'when proxy installation' do
- let_it_be(:installation) { create(:jira_connect_installation, instance_url: 'https://example.com') }
+ let(:installation) { build(:jira_connect_installation, instance_url: 'https://example.com') }
it { is_expected.to eq('https://example.com/-/jira_connect') }
end
end
describe 'audience_installed_event_url' do
- let_it_be(:installation) { create(:jira_connect_installation) }
+ let(:installation) { build(:jira_connect_installation) }
subject(:audience) { installation.audience_installed_event_url }
it { is_expected.to eq(nil) }
context 'when proxy installation' do
- let_it_be(:installation) { create(:jira_connect_installation, instance_url: 'https://example.com') }
+ let(:installation) { build(:jira_connect_installation, instance_url: 'https://example.com') }
it { is_expected.to eq('https://example.com/-/jira_connect/events/installed') }
end
end
describe 'proxy?' do
- let_it_be(:installation) { create(:jira_connect_installation) }
+ let(:installation) { build(:jira_connect_installation) }
subject { installation.proxy? }
it { is_expected.to eq(false) }
context 'when instance_url is present' do
- let_it_be(:installation) { create(:jira_connect_installation, instance_url: 'https://example.com') }
+ let(:installation) { build(:jira_connect_installation, instance_url: 'https://example.com') }
it { is_expected.to eq(true) }
end
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index 04df8ecc882..2ecd10cccc6 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -7,6 +7,12 @@ RSpec.describe Member do
using RSpec::Parameterized::TableSyntax
+ describe 'default values' do
+ subject(:member) { build(:project_member) }
+
+ it { expect(member.notification_level).to eq(NotificationSetting.levels[:global]) }
+ end
+
describe 'Associations' do
it { is_expected.to belong_to(:user) }
it { is_expected.to belong_to(:member_namespace) }
@@ -213,7 +219,7 @@ RSpec.describe Member do
describe 'Scopes & finders' do
let_it_be(:project) { create(:project, :public) }
let_it_be(:group) { create(:group) }
- let_it_be(:blocked_pending_approval_user) { create(:user, :blocked_pending_approval ) }
+ let_it_be(:blocked_pending_approval_user) { create(:user, :blocked_pending_approval) }
let_it_be(:blocked_pending_approval_project_member) { create(:project_member, :invited, :developer, project: project, invite_email: blocked_pending_approval_user.email) }
let_it_be(:awaiting_group_member) { create(:group_member, :awaiting, group: group) }
let_it_be(:awaiting_project_member) { create(:project_member, :awaiting, project: project) }
diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb
index 363830d21dd..77bc6d9753f 100644
--- a/spec/models/members/group_member_spec.rb
+++ b/spec/models/members/group_member_spec.rb
@@ -3,6 +3,12 @@
require 'spec_helper'
RSpec.describe GroupMember do
+ describe 'default values' do
+ subject(:goup_member) { build(:group_member) }
+
+ it { expect(goup_member.source_type).to eq(described_class::SOURCE_TYPE) }
+ end
+
context 'scopes' do
let_it_be(:user_1) { create(:user) }
let_it_be(:user_2) { create(:user) }
diff --git a/spec/models/members/last_group_owner_assigner_spec.rb b/spec/models/members/last_group_owner_assigner_spec.rb
index 429cf4190cf..a0a829221de 100644
--- a/spec/models/members/last_group_owner_assigner_spec.rb
+++ b/spec/models/members/last_group_owner_assigner_spec.rb
@@ -7,14 +7,10 @@ RSpec.describe LastGroupOwnerAssigner do
let_it_be(:user, reload: true) { create(:user) }
let_it_be(:group) { create(:group) }
- let(:group_member) { user.members.last }
+ let!(:group_member) { group.add_owner(user) }
subject(:assigner) { described_class.new(group, [group_member]) }
- before do
- group.add_owner(user)
- end
-
it "avoids extra database queries utilizing memoization", :aggregate_failures do
control = ActiveRecord::QueryRecorder.new { assigner.execute }
count_queries = control.occurrences_by_line_method.first[1][:occurrences].find_all { |i| i.include?('SELECT COUNT') }
@@ -56,6 +52,40 @@ RSpec.describe LastGroupOwnerAssigner do
.from(nil).to(false)
end
end
+
+ context 'with owners from a parent' do
+ context 'when top-level group' do
+ context 'with group sharing' do
+ let!(:subgroup) { create(:group, parent: group) }
+
+ before do
+ create(:group_group_link, :owner, shared_group: group, shared_with_group: subgroup)
+ create(:group_member, :owner, group: subgroup)
+ end
+
+ specify do
+ expect { assigner.execute }.to change(group_member, :last_owner)
+ .from(nil).to(true)
+ .and change(group_member, :last_blocked_owner)
+ .from(nil).to(false)
+ end
+ end
+ end
+
+ context 'when subgroup' do
+ let!(:subgroup) { create(:group, parent: group) }
+ let!(:group_member_2) { subgroup.add_owner(user) }
+
+ subject(:assigner) { described_class.new(subgroup, [group_member_2]) }
+
+ specify do
+ expect { assigner.execute }.to change(group_member_2, :last_owner)
+ .from(nil).to(false)
+ .and change(group_member_2, :last_blocked_owner)
+ .from(nil).to(false)
+ end
+ end
+ end
end
context "when there are blocked owners" do
@@ -93,6 +123,54 @@ RSpec.describe LastGroupOwnerAssigner do
.from(nil).to(false)
end
end
+
+ context 'with owners from a parent' do
+ context 'when top-level group' do
+ context 'with group sharing' do
+ let!(:subgroup) { create(:group, parent: group) }
+
+ before do
+ create(:group_group_link, :owner, shared_group: group, shared_with_group: subgroup)
+ create(:group_member, :owner, group: subgroup)
+ end
+
+ specify do
+ expect { assigner.execute }.to change(group_member, :last_owner)
+ .from(nil).to(false)
+ .and change(group_member, :last_blocked_owner)
+ .from(nil).to(true)
+ end
+ end
+ end
+
+ context 'when subgroup' do
+ let!(:subgroup) { create(:group, :nested) }
+
+ let!(:group_member) { subgroup.add_owner(user) }
+
+ subject(:assigner) { described_class.new(subgroup, [group_member]) }
+
+ specify do
+ expect { assigner.execute }.to change(group_member, :last_owner)
+ .from(nil).to(false)
+ .and change(group_member, :last_blocked_owner)
+ .from(nil).to(true)
+ end
+
+ context 'with two owners' do
+ before do
+ create(:group_member, :owner, group: subgroup.parent)
+ end
+
+ specify do
+ expect { assigner.execute }.to change(group_member, :last_owner)
+ .from(nil).to(false)
+ .and change(group_member, :last_blocked_owner)
+ .from(nil).to(false)
+ end
+ end
+ end
+ end
end
context 'when there are bot members' do
diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb
index ad6f3ca5428..e56c6b38992 100644
--- a/spec/models/members/project_member_spec.rb
+++ b/spec/models/members/project_member_spec.rb
@@ -13,6 +13,10 @@ RSpec.describe ProjectMember do
it { is_expected.to validate_inclusion_of(:access_level).in_array(Gitlab::Access.values) }
end
+ describe 'default values' do
+ it { expect(described_class.new.source_type).to eq('Project') }
+ end
+
describe 'delegations' do
it { is_expected.to delegate_method(:namespace_id).to(:project) }
end
diff --git a/spec/models/merge_request_diff_file_spec.rb b/spec/models/merge_request_diff_file_spec.rb
index f107a56c1b6..7e127caa649 100644
--- a/spec/models/merge_request_diff_file_spec.rb
+++ b/spec/models/merge_request_diff_file_spec.rb
@@ -203,16 +203,6 @@ RSpec.describe MergeRequestDiffFile do
end
end
- context 'when externally_stored_diffs_caching_export feature flag is disabled' do
- it 'calls #diff' do
- stub_feature_flags(externally_stored_diffs_caching_export: false)
-
- expect(file).to receive(:diff)
-
- file.utf8_diff
- end
- end
-
context 'when diff is not stored externally' do
it 'calls #diff' do
expect(file).to receive(:diff)
diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb
index e9e8bd9bfea..22fed716897 100644
--- a/spec/models/merge_request_diff_spec.rb
+++ b/spec/models/merge_request_diff_spec.rb
@@ -1097,6 +1097,19 @@ RSpec.describe MergeRequestDiff do
it 'returns a non-empty CommitCollection' do
expect(mr.merge_request_diff.commits.commits.size).to be > 0
end
+
+ context 'with a page' do
+ it 'returns a limited number of commits for page' do
+ expect(mr.merge_request_diff.commits(limit: 1, page: 1).map(&:sha)).to eq(
+ %w[
+ b83d6e391c22777fca1ed3012fce84f633d7fed0
+ ])
+ expect(mr.merge_request_diff.commits(limit: 1, page: 2).map(&:sha)).to eq(
+ %w[
+ 498214de67004b1da3d820901307bed2a68a8ef6
+ ])
+ end
+ end
end
describe '.latest_diff_for_merge_requests' do
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 32518b867cb..cf4f58f558c 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -232,10 +232,6 @@ RSpec.describe MergeRequest, factory_default: :keep do
end
context 'for branch' do
- before do
- stub_feature_flags(stricter_mr_branch_name: false)
- end
-
where(:branch_name, :valid) do
'foo' | true
'foo:bar' | false
@@ -278,6 +274,34 @@ RSpec.describe MergeRequest, factory_default: :keep do
end
describe 'callbacks' do
+ describe '#ensure_merge_request_diff' do
+ let(:merge_request) { build(:merge_request) }
+
+ context 'when async_merge_request_diff_creation is true' do
+ before do
+ merge_request.skip_ensure_merge_request_diff = true
+ end
+
+ it 'does not create a merge_request_diff after create' do
+ merge_request.save!
+
+ expect(merge_request.merge_request_diff).to be_empty
+ end
+ end
+
+ context 'when async_merge_request_diff_creation is false' do
+ before do
+ merge_request.skip_ensure_merge_request_diff = false
+ end
+
+ it 'creates merge_request_diff after create' do
+ merge_request.save!
+
+ expect(merge_request.merge_request_diff).not_to be_empty
+ end
+ end
+ end
+
describe '#ensure_merge_request_metrics' do
let(:merge_request) { create(:merge_request) }
@@ -3228,14 +3252,6 @@ RSpec.describe MergeRequest, factory_default: :keep do
describe '#mergeable_state?' do
it_behaves_like 'for mergeable_state'
-
- context 'when merge state caching is off' do
- before do
- stub_feature_flags(mergeability_caching: false)
- end
-
- it_behaves_like 'for mergeable_state'
- end
end
describe "#public_merge_status" do
@@ -4213,14 +4229,6 @@ RSpec.describe MergeRequest, factory_default: :keep do
transition!
end
-
- context 'when trigger_mr_subscription_on_merge_status_change is disabled' do
- before do
- stub_feature_flags(trigger_mr_subscription_on_merge_status_change: false)
- end
-
- it_behaves_like 'transition not triggering mergeRequestMergeStatusUpdated GraphQL subscription'
- end
end
shared_examples 'for an invalid state transition' do
@@ -4984,6 +4992,19 @@ RSpec.describe MergeRequest, factory_default: :keep do
expect(subject.commits.size).to eq(29)
end
end
+
+ context 'with a page' do
+ it 'returns a limited number of commits for page' do
+ expect(subject.commits(limit: 1, page: 1).map(&:sha)).to eq(
+ %w[
+ b83d6e391c22777fca1ed3012fce84f633d7fed0
+ ])
+ expect(subject.commits(limit: 1, page: 2).map(&:sha)).to eq(
+ %w[
+ 498214de67004b1da3d820901307bed2a68a8ef6
+ ])
+ end
+ end
end
context 'new merge request' do
@@ -5114,17 +5135,7 @@ RSpec.describe MergeRequest, factory_default: :keep do
end
it 'returns false' do
- expect(merge_request.diffable_merge_ref?).to eq(true)
- end
-
- context 'display_merge_conflicts_in_diff is disabled' do
- before do
- stub_feature_flags(display_merge_conflicts_in_diff: false)
- end
-
- it 'returns false' do
- expect(merge_request.diffable_merge_ref?).to eq(false)
- end
+ expect(merge_request.diffable_merge_ref?).to eq(false)
end
end
end
diff --git a/spec/models/metrics/dashboard/annotation_spec.rb b/spec/models/metrics/dashboard/annotation_spec.rb
index 4b7492016f3..9b8601e4052 100644
--- a/spec/models/metrics/dashboard/annotation_spec.rb
+++ b/spec/models/metrics/dashboard/annotation_spec.rb
@@ -63,7 +63,7 @@ RSpec.describe Metrics::Dashboard::Annotation do
end
context 'annotation with shared ownership' do
- subject { build(:metrics_dashboard_annotation, :with_cluster, environment: build(:environment) ) }
+ subject { build(:metrics_dashboard_annotation, :with_cluster, environment: build(:environment)) }
it 'reports error about both shared ownership' do
subject.valid?
diff --git a/spec/models/ml/candidate_metric_spec.rb b/spec/models/ml/candidate_metric_spec.rb
index 5ee6030fb8e..9f9a6e8e3ba 100644
--- a/spec/models/ml/candidate_metric_spec.rb
+++ b/spec/models/ml/candidate_metric_spec.rb
@@ -6,4 +6,17 @@ RSpec.describe Ml::CandidateMetric do
describe 'associations' do
it { is_expected.to belong_to(:candidate) }
end
+
+ describe 'scope :latest' do
+ let_it_be(:candidate) { create(:ml_candidates) }
+ let!(:metric1) { create(:ml_candidate_metrics, candidate: candidate) }
+ let!(:metric2) { create(:ml_candidate_metrics, candidate: candidate ) }
+ let!(:metric3) { create(:ml_candidate_metrics, name: metric1.name, candidate: candidate) }
+
+ subject { described_class.latest }
+
+ it 'fetches only the last metric for the name' do
+ expect(subject).to match_array([metric2, metric3] )
+ end
+ end
end
diff --git a/spec/models/ml/candidate_spec.rb b/spec/models/ml/candidate_spec.rb
index 3bf1e80a152..b35496363fe 100644
--- a/spec/models/ml/candidate_spec.rb
+++ b/spec/models/ml/candidate_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe Ml::Candidate, factory_default: :keep do
- let_it_be(:candidate) { create_default(:ml_candidates, :with_metrics_and_params) }
+ let_it_be(:candidate) { create(:ml_candidates, :with_metrics_and_params) }
describe 'associations' do
it { is_expected.to belong_to(:experiment) }
@@ -12,10 +12,14 @@ RSpec.describe Ml::Candidate, factory_default: :keep do
it { is_expected.to have_many(:metrics) }
end
- describe '#new' do
- it 'iid is not null' do
- expect(candidate.iid).not_to be_nil
- end
+ describe '.artifact_root' do
+ subject { candidate.artifact_root }
+
+ it { is_expected.to eq("/ml_candidate_#{candidate.iid}/-/") }
+ end
+
+ describe 'default values' do
+ it { expect(described_class.new.iid).to be_present }
end
describe '#by_project_id_and_iid' do
@@ -40,4 +44,26 @@ RSpec.describe Ml::Candidate, factory_default: :keep do
it { is_expected.to be_nil }
end
end
+
+ describe "#latest_metrics" do
+ let_it_be(:candidate2) { create(:ml_candidates, experiment: candidate.experiment) }
+ let!(:metric1) { create(:ml_candidate_metrics, candidate: candidate2) }
+ let!(:metric2) { create(:ml_candidate_metrics, candidate: candidate2 ) }
+ let!(:metric3) { create(:ml_candidate_metrics, name: metric1.name, candidate: candidate2) }
+
+ subject { candidate2.latest_metrics }
+
+ it 'fetches only the last metric for the name' do
+ expect(subject).to match_array([metric2, metric3] )
+ end
+ end
+
+ describe "#including_metrics_and_params" do
+ subject { described_class.including_metrics_and_params.find_by(id: candidate.id) }
+
+ it 'loads latest metrics and params', :aggregate_failures do
+ expect(subject.association_cached?(:latest_metrics)).to be(true)
+ expect(subject.association_cached?(:params)).to be(true)
+ end
+ end
end
diff --git a/spec/models/namespace_setting_spec.rb b/spec/models/namespace_setting_spec.rb
index a4446bfedd1..17c49e13c85 100644
--- a/spec/models/namespace_setting_spec.rb
+++ b/spec/models/namespace_setting_spec.rb
@@ -106,7 +106,7 @@ RSpec.describe NamespaceSetting, type: :model do
describe '#prevent_sharing_groups_outside_hierarchy' do
let(:settings) { create(:namespace_settings, prevent_sharing_groups_outside_hierarchy: true) }
- let!(:group) { create(:group, parent: parent, namespace_settings: settings ) }
+ let!(:group) { create(:group, parent: parent, namespace_settings: settings) }
subject(:group_sharing_setting) { settings.prevent_sharing_groups_outside_hierarchy }
@@ -133,7 +133,7 @@ RSpec.describe NamespaceSetting, type: :model do
context 'when :show_diff_preview_in_email is false' do
it 'returns false' do
settings = create(:namespace_settings, show_diff_preview_in_email: false)
- group = create(:group, namespace_settings: settings )
+ group = create(:group, namespace_settings: settings)
expect(group.show_diff_preview_in_email?).to be_falsey
end
@@ -142,7 +142,7 @@ RSpec.describe NamespaceSetting, type: :model do
context 'when :show_diff_preview_in_email is true' do
it 'returns true' do
settings = create(:namespace_settings, show_diff_preview_in_email: true)
- group = create(:group, namespace_settings: settings )
+ group = create(:group, namespace_settings: settings)
expect(group.show_diff_preview_in_email?).to be_truthy
end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index c6d028af22d..0516d446945 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -1623,7 +1623,7 @@ RSpec.describe Namespace do
describe '#share_with_group_lock with subgroups' do
context 'when creating a subgroup' do
- let(:subgroup) { create(:group, parent: root_group ) }
+ let(:subgroup) { create(:group, parent: root_group) }
context 'under a parent with "Share with group lock" enabled' do
let(:root_group) { create(:group, share_with_group_lock: true) }
@@ -1644,7 +1644,7 @@ RSpec.describe Namespace do
context 'when enabling the parent group "Share with group lock"' do
let(:root_group) { create(:group) }
- let!(:subgroup) { create(:group, parent: root_group ) }
+ let!(:subgroup) { create(:group, parent: root_group) }
it 'the subgroup "Share with group lock" becomes enabled' do
root_group.update!(share_with_group_lock: true)
@@ -1657,7 +1657,7 @@ RSpec.describe Namespace do
let(:root_group) { create(:group, share_with_group_lock: true) }
context 'and the subgroup "Share with group lock" is enabled' do
- let(:subgroup) { create(:group, parent: root_group, share_with_group_lock: true ) }
+ let(:subgroup) { create(:group, parent: root_group, share_with_group_lock: true) }
it 'the subgroup "Share with group lock" does not change' do
root_group.update!(share_with_group_lock: false)
@@ -1667,7 +1667,7 @@ RSpec.describe Namespace do
end
context 'but the subgroup "Share with group lock" is disabled' do
- let(:subgroup) { create(:group, parent: root_group ) }
+ let(:subgroup) { create(:group, parent: root_group) }
it 'the subgroup "Share with group lock" does not change' do
root_group.update!(share_with_group_lock: false)
@@ -1682,7 +1682,7 @@ RSpec.describe Namespace do
let(:root_group) { create(:group, share_with_group_lock: true) }
context 'when the subgroup "Share with group lock" is enabled' do
- let(:subgroup) { create(:group, share_with_group_lock: true ) }
+ let(:subgroup) { create(:group, share_with_group_lock: true) }
it 'the subgroup "Share with group lock" does not change' do
subgroup.parent = root_group
@@ -1708,7 +1708,7 @@ RSpec.describe Namespace do
let(:root_group) { create(:group) }
context 'when the subgroup "Share with group lock" is enabled' do
- let(:subgroup) { create(:group, share_with_group_lock: true ) }
+ let(:subgroup) { create(:group, share_with_group_lock: true) }
it 'the subgroup "Share with group lock" does not change' do
subgroup.parent = root_group
@@ -1826,7 +1826,7 @@ RSpec.describe Namespace do
group.update!(parent: parent)
- expect(group.full_path_before_last_save).to eq("#{group.path_before_last_save}")
+ expect(group.full_path_before_last_save).to eq(group.path_before_last_save.to_s)
end
end
@@ -2356,7 +2356,7 @@ RSpec.describe Namespace do
end
end
- describe 'storage_enforcement_date' do
+ describe 'storage_enforcement_date', :freeze_time do
let_it_be(:namespace) { create(:group) }
before do
@@ -2364,7 +2364,7 @@ RSpec.describe Namespace do
end
it 'returns correct date' do
- expect(namespace.storage_enforcement_date).to eql(Date.new(2022, 10, 19))
+ expect(namespace.storage_enforcement_date).to eql(3.months.from_now.to_date)
end
context 'when :storage_banner_bypass_date_check is enabled' do
@@ -2372,7 +2372,7 @@ RSpec.describe Namespace do
stub_feature_flags(namespace_storage_limit_bypass_date_check: true)
end
- it 'returns the current date', :freeze_time do
+ it 'returns the current date' do
expect(namespace.storage_enforcement_date).to eq(Date.current)
end
end
diff --git a/spec/models/network/graph_spec.rb b/spec/models/network/graph_spec.rb
index a393aace39c..16894bf28f1 100644
--- a/spec/models/network/graph_spec.rb
+++ b/spec/models/network/graph_spec.rb
@@ -6,10 +6,24 @@ RSpec.describe Network::Graph do
let(:project) { create(:project, :repository) }
let!(:note_on_commit) { create(:note_on_commit, project: project) }
- it '#initialize' do
- graph = described_class.new(project, 'refs/heads/master', project.repository.commit, nil)
+ describe '#initialize' do
+ let(:graph) do
+ described_class.new(project, 'refs/heads/master', project.repository.commit, nil)
+ end
+
+ it 'has initialized' do
+ expect(graph).to be_a(described_class)
+ end
- expect(graph.notes).to eq( { note_on_commit.commit_id => 1 } )
+ context 'when disable_network_graph_note_counts is disabled' do
+ before do
+ stub_feature_flags(disable_network_graph_notes_count: false)
+ end
+
+ it 'initializes the notes hash' do
+ expect(graph.notes).to eq({ note_on_commit.commit_id => 1 })
+ end
+ end
end
describe '#commits' do
@@ -19,7 +33,7 @@ RSpec.describe Network::Graph do
commits = graph.commits
expect(commits).not_to be_empty
- expect(commits).to all( be_kind_of(Network::Commit) )
+ expect(commits).to all(be_kind_of(Network::Commit))
end
it 'sorts commits by commit date (descending)' do
@@ -42,7 +56,7 @@ RSpec.describe Network::Graph do
parent_indexes = commit.parent_ids.map { |parent_id| commit_ids.find_index(parent_id) }.compact
# All parents of the current commit should appear after it
- expect(parent_indexes).to all( be > index )
+ expect(parent_indexes).to all(be > index)
end
end
end
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 1b44da75c40..7c71080d63e 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -23,6 +23,10 @@ RSpec.describe Note do
it { is_expected.to include_module(Sortable) }
end
+ describe 'default values' do
+ it { expect(described_class.new).not_to be_system }
+ end
+
describe 'validation' do
it { is_expected.to validate_length_of(:note).is_at_most(1_000_000) }
it { is_expected.to validate_presence_of(:note) }
@@ -1619,70 +1623,6 @@ RSpec.describe Note do
end
end
- describe '#noteable_assignee_or_author?' do
- let(:user) { create(:user) }
- let(:noteable) { create(:issue) }
- let(:note) { create(:note, project: noteable.project, noteable: noteable) }
-
- subject { note.noteable_assignee_or_author?(user) }
-
- shared_examples 'assignee check' do
- context 'when the provided user is one of the assignees' do
- before do
- note.noteable.update!(assignees: [user, create(:user)])
- end
-
- it 'returns true' do
- expect(subject).to be_truthy
- end
- end
- end
-
- shared_examples 'author check' do
- context 'when the provided user is the author' do
- before do
- note.noteable.update!(author: user)
- end
-
- it 'returns true' do
- expect(subject).to be_truthy
- end
- end
-
- context 'when the provided user is neither author nor assignee' do
- it 'returns true' do
- expect(subject).to be_falsey
- end
- end
- end
-
- context 'when user is nil' do
- let(:user) { nil }
-
- it 'returns false' do
- expect(subject).to be_falsey
- end
- end
-
- context 'when noteable is an issue' do
- it_behaves_like 'author check'
- it_behaves_like 'assignee check'
- end
-
- context 'when noteable is a merge request' do
- let(:noteable) { create(:merge_request) }
-
- it_behaves_like 'author check'
- it_behaves_like 'assignee check'
- end
-
- context 'when noteable is a snippet' do
- let(:noteable) { create(:personal_snippet) }
-
- it_behaves_like 'author check'
- end
- end
-
describe 'banzai_render_context' do
let(:project) { build(:project_empty_repo) }
diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb
index cc601fb30c2..730a9045d7f 100644
--- a/spec/models/notification_setting_spec.rb
+++ b/spec/models/notification_setting_spec.rb
@@ -5,6 +5,12 @@ require 'spec_helper'
RSpec.describe NotificationSetting do
it_behaves_like 'having unique enum values'
+ describe 'default values' do
+ subject(:notification_setting) { build(:notification_setting) }
+
+ it { expect(notification_setting.level).to eq('global') }
+ end
+
describe "Associations" do
it { is_expected.to belong_to(:user) }
it { is_expected.to belong_to(:source) }
diff --git a/spec/models/oauth_access_token_spec.rb b/spec/models/oauth_access_token_spec.rb
index a4540ac95bc..92e1ae8ac60 100644
--- a/spec/models/oauth_access_token_spec.rb
+++ b/spec/models/oauth_access_token_spec.rb
@@ -46,42 +46,11 @@ RSpec.describe OauthAccessToken do
expect(described_class.by_token(plaintext_token)).to be_a(OauthAccessToken)
end
end
-
- context 'when hash_oauth_secrets is disabled' do
- let(:hashed_token) { create(:oauth_access_token, application_id: app_one.id) }
-
- before do
- hashed_token
- stub_feature_flags(hash_oauth_tokens: false)
- end
-
- it 'stores the token in plaintext' do
- expect(token.token).to eq(token.plaintext_token)
- end
-
- it 'finds a token by plaintext token' do
- expect(described_class.by_token(token.plaintext_token)).to be_a(OauthAccessToken)
- end
-
- it 'does not find a token that was previously stored as hashed' do
- expect(described_class.by_token(hashed_token.plaintext_token)).to be_nil
- end
- end
end
describe '.matching_token_for' do
it 'does not find existing tokens' do
expect(described_class.matching_token_for(app_one, token.resource_owner, token.scopes)).to be_nil
end
-
- context 'when hash oauth tokens is disabled' do
- before do
- stub_feature_flags(hash_oauth_tokens: false)
- end
-
- it 'finds an existing token' do
- expect(described_class.matching_token_for(app_one, token.resource_owner, token.scopes)).to be_present
- end
- end
end
end
diff --git a/spec/models/operations/feature_flag_spec.rb b/spec/models/operations/feature_flag_spec.rb
index 85a475f5c53..dd1ff95a16d 100644
--- a/spec/models/operations/feature_flag_spec.rb
+++ b/spec/models/operations/feature_flag_spec.rb
@@ -16,6 +16,11 @@ RSpec.describe Operations::FeatureFlag do
it { is_expected.to have_many(:strategies) }
end
+ describe 'default values' do
+ it { expect(described_class.new).to be_active }
+ it { expect(described_class.new.version).to eq('new_version_flag') }
+ end
+
describe '.reference_pattern' do
subject { described_class.reference_pattern }
diff --git a/spec/models/packages/package_file_spec.rb b/spec/models/packages/package_file_spec.rb
index 9554fc3bb1b..c665f738ead 100644
--- a/spec/models/packages/package_file_spec.rb
+++ b/spec/models/packages/package_file_spec.rb
@@ -314,7 +314,7 @@ RSpec.describe Packages::PackageFile, type: :model do
# to `1`.
expect(package_file)
.to receive(:update_column)
- .with(:file_store, ::Packages::PackageFileUploader::Store::LOCAL)
+ .with('file_store', ::Packages::PackageFileUploader::Store::LOCAL)
expect { subject }.to change { package_file.size }.from(nil).to(3513)
end
diff --git a/spec/models/packages/package_spec.rb b/spec/models/packages/package_spec.rb
index 0edb04224a3..241c585099c 100644
--- a/spec/models/packages/package_spec.rb
+++ b/spec/models/packages/package_spec.rb
@@ -969,12 +969,12 @@ RSpec.describe Packages::Package, type: :model do
end
context 'sorting' do
- let_it_be(:project) { create(:project, name: 'aaa' ) }
- let_it_be(:project2) { create(:project, name: 'bbb' ) }
- let_it_be(:package1) { create(:package, project: project ) }
- let_it_be(:package2) { create(:package, project: project2 ) }
- let_it_be(:package3) { create(:package, project: project2 ) }
- let_it_be(:package4) { create(:package, project: project ) }
+ let_it_be(:project) { create(:project, name: 'aaa') }
+ let_it_be(:project2) { create(:project, name: 'bbb') }
+ let_it_be(:package1) { create(:package, project: project) }
+ let_it_be(:package2) { create(:package, project: project2) }
+ let_it_be(:package3) { create(:package, project: project2) }
+ let_it_be(:package4) { create(:package, project: project) }
it 'orders packages by their projects name ascending' do
expect(Packages::Package.order_project_name).to eq([package1, package4, package2, package3])
diff --git a/spec/models/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb
index 463ec904e9a..e5f2e849a0a 100644
--- a/spec/models/pages_domain_spec.rb
+++ b/spec/models/pages_domain_spec.rb
@@ -209,6 +209,10 @@ RSpec.describe PagesDomain do
expect(subject.wildcard).to eq(false)
end
+ it 'defaults auto_ssl_enabled to false' do
+ expect(subject.auto_ssl_enabled).to eq(false)
+ end
+
it 'defaults scope to project' do
expect(subject.scope).to eq('project')
end
diff --git a/spec/models/personal_access_token_spec.rb b/spec/models/personal_access_token_spec.rb
index 67e7d444d25..9d4c53f8d55 100644
--- a/spec/models/personal_access_token_spec.rb
+++ b/spec/models/personal_access_token_spec.rb
@@ -108,7 +108,7 @@ RSpec.describe PersonalAccessToken do
describe '.last_used_before' do
context 'last_used_*' do
let_it_be(:date) { DateTime.new(2022, 01, 01) }
- let_it_be(:token) { create(:personal_access_token, last_used_at: date ) }
+ let_it_be(:token) { create(:personal_access_token, last_used_at: date) }
# This token should never occur in the following tests and indicates that filtering was done correctly with it
let_it_be(:never_used_token) { create(:personal_access_token) }
@@ -194,47 +194,6 @@ RSpec.describe PersonalAccessToken do
end
end
- describe 'Redis storage' do
- let(:user_id) { 123 }
- let(:token) { 'KS3wegQYXBLYhQsciwsj' }
-
- context 'reading encrypted data' do
- before do
- subject.redis_store!(user_id, token)
- end
-
- it 'returns stored data' do
- expect(subject.redis_getdel(user_id)).to eq(token)
- end
- end
-
- context 'reading unencrypted data' do
- before do
- Gitlab::Redis::SharedState.with do |redis|
- redis.set(described_class.redis_shared_state_key(user_id),
- token,
- ex: PersonalAccessToken::REDIS_EXPIRY_TIME)
- end
- end
-
- it 'returns stored data unmodified' do
- expect(subject.redis_getdel(user_id)).to eq(token)
- end
- end
-
- context 'after deletion' do
- before do
- subject.redis_store!(user_id, token)
-
- expect(subject.redis_getdel(user_id)).to eq(token)
- end
-
- it 'token is removed' do
- expect(subject.redis_getdel(user_id)).to be_nil
- end
- end
- end
-
context "validations" do
let(:personal_access_token) { build(:personal_access_token) }
@@ -365,7 +324,7 @@ RSpec.describe PersonalAccessToken do
describe '.simple_sorts' do
it 'includes overridden keys' do
- expect(described_class.simple_sorts.keys).to include(*%w(expires_at_asc expires_at_desc expires_at_asc_id_desc))
+ expect(described_class.simple_sorts.keys).to include(*%w(expires_at_asc_id_desc))
end
end
@@ -373,18 +332,6 @@ RSpec.describe PersonalAccessToken do
let_it_be(:earlier_token) { create(:personal_access_token, expires_at: 2.days.ago) }
let_it_be(:later_token) { create(:personal_access_token, expires_at: 1.day.ago) }
- describe '.order_expires_at_asc' do
- it 'returns ordered list in asc order of expiry date' do
- expect(described_class.order_expires_at_asc).to match [earlier_token, later_token]
- end
- end
-
- describe '.order_expires_at_desc' do
- it 'returns ordered list in desc order of expiry date' do
- expect(described_class.order_expires_at_desc).to match [later_token, earlier_token]
- end
- end
-
describe '.order_expires_at_asc_id_desc' do
let_it_be(:earlier_token_2) { create(:personal_access_token, expires_at: 2.days.ago) }
diff --git a/spec/models/preloaders/labels_preloader_spec.rb b/spec/models/preloaders/labels_preloader_spec.rb
index 86e64d114c7..07f148a0a6c 100644
--- a/spec/models/preloaders/labels_preloader_spec.rb
+++ b/spec/models/preloaders/labels_preloader_spec.rb
@@ -40,10 +40,11 @@ RSpec.describe Preloaders::LabelsPreloader do
def access_data(labels)
labels.each do |label|
- if label.is_a?(ProjectLabel)
+ case label
+ when ProjectLabel
label.project.project_feature
label.lazy_subscription(user, label.project)
- elsif label.is_a?(GroupLabel)
+ when GroupLabel
label.group.route
label.lazy_subscription(user)
end
diff --git a/spec/models/preloaders/project_root_ancestor_preloader_spec.rb b/spec/models/preloaders/project_root_ancestor_preloader_spec.rb
index bb0de24abe5..2462e305597 100644
--- a/spec/models/preloaders/project_root_ancestor_preloader_spec.rb
+++ b/spec/models/preloaders/project_root_ancestor_preloader_spec.rb
@@ -63,6 +63,14 @@ RSpec.describe Preloaders::ProjectRootAncestorPreloader do
it_behaves_like 'executes N matching DB queries', 0, :full_path
end
+
+ context 'when projects are an array and not an ActiveRecord::Relation' do
+ before do
+ described_class.new(projects, :namespace, additional_preloads).execute
+ end
+
+ it_behaves_like 'executes N matching DB queries', 4
+ end
end
context 'when the preloader is not used' do
diff --git a/spec/models/preloaders/user_max_access_level_in_projects_preloader_spec.rb b/spec/models/preloaders/user_max_access_level_in_projects_preloader_spec.rb
index 7411bc95147..1cfeeac49cd 100644
--- a/spec/models/preloaders/user_max_access_level_in_projects_preloader_spec.rb
+++ b/spec/models/preloaders/user_max_access_level_in_projects_preloader_spec.rb
@@ -28,34 +28,58 @@ RSpec.describe Preloaders::UserMaxAccessLevelInProjectsPreloader do
end
end
- describe '#execute', :request_store do
+ shared_examples '#execute' do
let(:projects_arg) { projects }
- before do
- Preloaders::UserMaxAccessLevelInProjectsPreloader.new(projects_arg, user).execute
- end
-
- it 'avoids N+1 queries' do
- expect { query }.not_to make_queries
- end
-
- context 'when projects is an array of IDs' do
- let(:projects_arg) { projects.map(&:id) }
+ context 'when user is present' do
+ before do
+ Preloaders::UserMaxAccessLevelInProjectsPreloader.new(projects_arg, user).execute
+ end
it 'avoids N+1 queries' do
expect { query }.not_to make_queries
end
+
+ context 'when projects is an array of IDs' do
+ let(:projects_arg) { projects.map(&:id) }
+
+ it 'avoids N+1 queries' do
+ expect { query }.not_to make_queries
+ end
+ end
+
+ # Test for handling of SQL table name clashes.
+ context 'when projects is a relation including project_authorizations' do
+ let(:projects_arg) do
+ Project.where(id: ProjectAuthorization.where(project_id: projects).select(:project_id))
+ end
+
+ it 'avoids N+1 queries' do
+ expect { query }.not_to make_queries
+ end
+ end
end
- # Test for handling of SQL table name clashes.
- context 'when projects is a relation including project_authorizations' do
- let(:projects_arg) do
- Project.where(id: ProjectAuthorization.where(project_id: projects).select(:project_id))
+ context 'when user is not present' do
+ before do
+ Preloaders::UserMaxAccessLevelInProjectsPreloader.new(projects_arg, nil).execute
end
- it 'avoids N+1 queries' do
- expect { query }.not_to make_queries
+ it 'does not avoid N+1 queries' do
+ expect { query }.to make_queries
+ end
+ end
+ end
+
+ describe '#execute', :request_store do
+ include_examples '#execute'
+
+ context 'when projects_preloader_fix is disabled' do
+ before do
+ stub_feature_flags(projects_preloader_fix: false)
end
+
+ include_examples '#execute'
end
end
end
diff --git a/spec/models/project_authorization_spec.rb b/spec/models/project_authorization_spec.rb
index 55fe28ceb6f..df89e97a41f 100644
--- a/spec/models/project_authorization_spec.rb
+++ b/spec/models/project_authorization_spec.rb
@@ -86,6 +86,25 @@ RSpec.describe ProjectAuthorization do
end
end
+ shared_examples_for 'does not log any detail' do
+ it 'does not log any detail' do
+ expect(Gitlab::AppLogger).not_to receive(:info)
+
+ execute
+ end
+ end
+
+ shared_examples_for 'logs the detail' do
+ it 'logs the detail' do
+ expect(Gitlab::AppLogger).to receive(:info).with(
+ entire_size: 3,
+ message: 'Project authorizations refresh performed with delay'
+ )
+
+ execute
+ end
+ end
+
describe '.insert_all_in_batches' do
let_it_be(:user) { create(:user) }
let_it_be(:project_1) { create(:project) }
@@ -100,6 +119,8 @@ RSpec.describe ProjectAuthorization do
]
end
+ subject(:execute) { described_class.insert_all_in_batches(attributes, per_batch_size) }
+
before do
# Configure as if a replica database is enabled
allow(::Gitlab::Database::LoadBalancing).to receive(:primary_only?).and_return(false)
@@ -110,7 +131,7 @@ RSpec.describe ProjectAuthorization do
specify do
expect(described_class).not_to receive(:sleep)
- described_class.insert_all_in_batches(attributes, per_batch_size)
+ execute
expect(user.project_authorizations.pluck(:user_id, :project_id, :access_level)).to match_array(attributes.map(&:values))
end
@@ -123,11 +144,13 @@ RSpec.describe ProjectAuthorization do
expect(described_class).to receive(:insert_all).twice.and_call_original
expect(described_class).to receive(:sleep).twice
- described_class.insert_all_in_batches(attributes, per_batch_size)
+ execute
expect(user.project_authorizations.pluck(:user_id, :project_id, :access_level)).to match_array(attributes.map(&:values))
end
+ it_behaves_like 'logs the detail'
+
context 'when the GitLab installation does not have a replica database configured' do
before do
# Configure as if a replica database is not enabled
@@ -135,6 +158,7 @@ RSpec.describe ProjectAuthorization do
end
it_behaves_like 'inserts the rows in batches, as per the `per_batch` size, without a delay between each batch'
+ it_behaves_like 'does not log any detail'
end
end
@@ -142,6 +166,7 @@ RSpec.describe ProjectAuthorization do
let(:per_batch_size) { 5 }
it_behaves_like 'inserts the rows in batches, as per the `per_batch` size, without a delay between each batch'
+ it_behaves_like 'does not log any detail'
end
end
@@ -154,6 +179,14 @@ RSpec.describe ProjectAuthorization do
let(:user_ids) { [user_1.id, user_2.id, user_3.id] }
+ subject(:execute) do
+ described_class.delete_all_in_batches_for_project(
+ project: project,
+ user_ids: user_ids,
+ per_batch: per_batch_size
+ )
+ end
+
before do
# Configure as if a replica database is enabled
allow(::Gitlab::Database::LoadBalancing).to receive(:primary_only?).and_return(false)
@@ -171,11 +204,7 @@ RSpec.describe ProjectAuthorization do
specify do
expect(described_class).not_to receive(:sleep)
- described_class.delete_all_in_batches_for_project(
- project: project,
- user_ids: user_ids,
- per_batch: per_batch_size
- )
+ execute
expect(project.project_authorizations.pluck(:user_id)).not_to include(*user_ids)
end
@@ -187,15 +216,13 @@ RSpec.describe ProjectAuthorization do
it 'removes the project authorizations of the specified users in the current project, with a delay between each batch' do
expect(described_class).to receive(:sleep).twice
- described_class.delete_all_in_batches_for_project(
- project: project,
- user_ids: user_ids,
- per_batch: per_batch_size
- )
+ execute
expect(project.project_authorizations.pluck(:user_id)).not_to include(*user_ids)
end
+ it_behaves_like 'logs the detail'
+
context 'when the GitLab installation does not have a replica database configured' do
before do
# Configure as if a replica database is not enabled
@@ -203,6 +230,7 @@ RSpec.describe ProjectAuthorization do
end
it_behaves_like 'removes the project authorizations of the specified users in the current project, without a delay between each batch'
+ it_behaves_like 'does not log any detail'
end
end
@@ -210,6 +238,7 @@ RSpec.describe ProjectAuthorization do
let(:per_batch_size) { 5 }
it_behaves_like 'removes the project authorizations of the specified users in the current project, without a delay between each batch'
+ it_behaves_like 'does not log any detail'
end
end
@@ -222,6 +251,14 @@ RSpec.describe ProjectAuthorization do
let(:project_ids) { [project_1.id, project_2.id, project_3.id] }
+ subject(:execute) do
+ described_class.delete_all_in_batches_for_user(
+ user: user,
+ project_ids: project_ids,
+ per_batch: per_batch_size
+ )
+ end
+
before do
# Configure as if a replica database is enabled
allow(::Gitlab::Database::LoadBalancing).to receive(:primary_only?).and_return(false)
@@ -239,11 +276,7 @@ RSpec.describe ProjectAuthorization do
specify do
expect(described_class).not_to receive(:sleep)
- described_class.delete_all_in_batches_for_user(
- user: user,
- project_ids: project_ids,
- per_batch: per_batch_size
- )
+ execute
expect(user.project_authorizations.pluck(:project_id)).not_to include(*project_ids)
end
@@ -255,15 +288,13 @@ RSpec.describe ProjectAuthorization do
it 'removes the project authorizations of the specified projects from the current user, with a delay between each batch' do
expect(described_class).to receive(:sleep).twice
- described_class.delete_all_in_batches_for_user(
- user: user,
- project_ids: project_ids,
- per_batch: per_batch_size
- )
+ execute
expect(user.project_authorizations.pluck(:project_id)).not_to include(*project_ids)
end
+ it_behaves_like 'logs the detail'
+
context 'when the GitLab installation does not have a replica database configured' do
before do
# Configure as if a replica database is not enabled
@@ -271,6 +302,7 @@ RSpec.describe ProjectAuthorization do
end
it_behaves_like 'removes the project authorizations of the specified projects from the current user, without a delay between each batch'
+ it_behaves_like 'does not log any detail'
end
end
@@ -278,6 +310,7 @@ RSpec.describe ProjectAuthorization do
let(:per_batch_size) { 5 }
it_behaves_like 'removes the project authorizations of the specified projects from the current user, without a delay between each batch'
+ it_behaves_like 'does not log any detail'
end
end
end
diff --git a/spec/models/project_ci_cd_setting_spec.rb b/spec/models/project_ci_cd_setting_spec.rb
index 406485d8cc8..5a32e103e0f 100644
--- a/spec/models/project_ci_cd_setting_spec.rb
+++ b/spec/models/project_ci_cd_setting_spec.rb
@@ -21,6 +21,12 @@ RSpec.describe ProjectCiCdSetting do
end
end
+ describe '#separated_caches' do
+ it 'is true by default' do
+ expect(described_class.new.separated_caches).to be_truthy
+ end
+ end
+
describe '#default_git_depth' do
let(:default_value) { described_class::DEFAULT_GIT_DEPTH }
diff --git a/spec/models/project_setting_spec.rb b/spec/models/project_setting_spec.rb
index 5730ca58e9e..94a2e2fe3f9 100644
--- a/spec/models/project_setting_spec.rb
+++ b/spec/models/project_setting_spec.rb
@@ -6,6 +6,10 @@ RSpec.describe ProjectSetting, type: :model do
using RSpec::Parameterized::TableSyntax
it { is_expected.to belong_to(:project) }
+ describe 'default values' do
+ it { expect(subject.legacy_open_source_license_available).to be_truthy }
+ end
+
describe 'scopes' do
let_it_be(:project_1) { create(:project) }
let_it_be(:project_2) { create(:project) }
@@ -20,6 +24,7 @@ RSpec.describe ProjectSetting, type: :model do
describe 'validations' do
it { is_expected.not_to allow_value(nil).for(:target_platforms) }
it { is_expected.to allow_value([]).for(:target_platforms) }
+ it { is_expected.to validate_length_of(:issue_branch_template).is_at_most(255) }
it { is_expected.not_to allow_value(nil).for(:suggested_reviewers_enabled) }
it { is_expected.to allow_value(true).for(:suggested_reviewers_enabled) }
@@ -70,7 +75,7 @@ RSpec.describe ProjectSetting, type: :model do
describe '#show_diff_preview_in_email?' do
context 'when a project is a top-level namespace' do
- let(:project_settings ) { create(:project_setting, show_diff_preview_in_email: false) }
+ let(:project_settings) { create(:project_setting, show_diff_preview_in_email: false) }
let(:project) { create(:project, project_setting: project_settings) }
context 'when show_diff_preview_in_email is disabled' do
@@ -80,7 +85,7 @@ RSpec.describe ProjectSetting, type: :model do
end
context 'when show_diff_preview_in_email is enabled' do
- let(:project_settings ) { create(:project_setting, show_diff_preview_in_email: true) }
+ let(:project_settings) { create(:project_setting, show_diff_preview_in_email: true) }
it 'returns true' do
settings = create(:project_setting, show_diff_preview_in_email: true)
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 75887e49dc9..8cccc9ad83e 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -38,6 +38,7 @@ RSpec.describe Project, factory_default: :keep do
it { is_expected.to have_many(:hooks) }
it { is_expected.to have_many(:protected_branches) }
it { is_expected.to have_many(:exported_protected_branches) }
+ it { is_expected.to have_one(:wiki_repository).class_name('Projects::WikiRepository').inverse_of(:project) }
it { is_expected.to have_one(:slack_integration) }
it { is_expected.to have_one(:microsoft_teams_integration) }
it { is_expected.to have_one(:mattermost_integration) }
@@ -597,7 +598,7 @@ RSpec.describe Project, factory_default: :keep do
end
it 'contains errors related to the project being deleted' do
- expect(new_project.errors.full_messages.first).to eq(_('The project is still being deleted. Please try again later.'))
+ expect(new_project.errors.full_messages).to include(_('The project is still being deleted. Please try again later.'))
end
end
@@ -862,6 +863,7 @@ RSpec.describe Project, factory_default: :keep do
it { is_expected.to delegate_method(:environments_access_level).to(:project_feature) }
it { is_expected.to delegate_method(:feature_flags_access_level).to(:project_feature) }
it { is_expected.to delegate_method(:releases_access_level).to(:project_feature) }
+ it { is_expected.to delegate_method(:infrastructure_access_level).to(:project_feature) }
it { is_expected.to delegate_method(:maven_package_requests_forwarding).to(:namespace) }
it { is_expected.to delegate_method(:pypi_package_requests_forwarding).to(:namespace) }
it { is_expected.to delegate_method(:npm_package_requests_forwarding).to(:namespace) }
@@ -1352,7 +1354,7 @@ RSpec.describe Project, factory_default: :keep do
end
end
- describe '#open_issues_count', :aggregate_failures do
+ describe '#open_issues_count' do
let(:project) { build(:project) }
it 'provides the issue count' do
@@ -1657,6 +1659,33 @@ RSpec.describe Project, factory_default: :keep do
expect(project.reload.star_count).to eq(0)
end
+ it 'does not count stars from blocked users' do
+ user1 = create(:user)
+ user2 = create(:user)
+ project = create(:project, :public)
+
+ expect(project.star_count).to eq(0)
+
+ user1.toggle_star(project)
+ expect(project.reload.star_count).to eq(1)
+
+ user2.toggle_star(project)
+ project.reload
+ expect(project.reload.star_count).to eq(2)
+
+ user1.block
+ project.reload
+ expect(project.reload.star_count).to eq(1)
+
+ user2.block
+ project.reload
+ expect(project.reload.star_count).to eq(0)
+
+ user1.activate
+ project.reload
+ expect(project.reload.star_count).to eq(1)
+ end
+
it 'counts stars on the right project' do
user = create(:user)
project1 = create(:project, :public)
@@ -2981,44 +3010,6 @@ RSpec.describe Project, factory_default: :keep do
end
end
- describe '#uses_external_project_ci_config?' do
- subject(:uses_external_project_ci_config) { project.uses_external_project_ci_config? }
-
- let(:project) { build(:project) }
-
- context 'when ci_config_path is configured with external project' do
- before do
- project.ci_config_path = '.gitlab-ci.yml@hello/world'
- end
-
- it { is_expected.to eq(true) }
- end
-
- context 'when ci_config_path is nil' do
- before do
- project.ci_config_path = nil
- end
-
- it { is_expected.to eq(false) }
- end
-
- context 'when ci_config_path is configured with a file in the project' do
- before do
- project.ci_config_path = 'hello/world/gitlab-ci.yml'
- end
-
- it { is_expected.to eq(false) }
- end
-
- context 'when ci_config_path is configured with remote file' do
- before do
- project.ci_config_path = 'https://example.org/file.yml'
- end
-
- it { is_expected.to eq(false) }
- end
- end
-
describe '#latest_successful_build_for_ref' do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:pipeline) { create_pipeline(project) }
@@ -4507,7 +4498,7 @@ RSpec.describe Project, factory_default: :keep do
project_2 = create(:project, :public, :merge_requests_disabled)
project_3 = create(:project, :public, :issues_disabled)
project_4 = create(:project, :public)
- project_4.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE, merge_requests_access_level: ProjectFeature::PRIVATE )
+ project_4.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE, merge_requests_access_level: ProjectFeature::PRIVATE)
project_ids = described_class.ids_with_issuables_available_for(user).pluck(:id)
@@ -5798,7 +5789,7 @@ RSpec.describe Project, factory_default: :keep do
end
describe '#has_active_integrations?' do
- let_it_be(:project) { create(:project) }
+ let_it_be_with_refind(:project) { create(:project) }
it { expect(project.has_active_integrations?).to eq(false) }
@@ -5808,6 +5799,20 @@ RSpec.describe Project, factory_default: :keep do
expect(project.has_active_integrations?(:merge_request_hooks)).to eq(false)
expect(project.has_active_integrations?).to eq(true)
end
+
+ it 'caches matching integrations' do
+ create(:custom_issue_tracker_integration, push_events: true, merge_requests_events: false, project: project)
+
+ expect(project.has_active_integrations?(:merge_request_hooks)).to eq(false)
+ expect(project.has_active_integrations?).to eq(true)
+
+ count = ActiveRecord::QueryRecorder.new do
+ expect(project.has_active_integrations?(:merge_request_hooks)).to eq(false)
+ expect(project.has_active_integrations?).to eq(true)
+ end.count
+
+ expect(count).to eq(0)
+ end
end
describe '#badges' do
@@ -7074,7 +7079,7 @@ RSpec.describe Project, factory_default: :keep do
subject { project.self_monitoring? }
- context 'when the project is instance self monitoring' do
+ context 'when the project is instance self-monitoring' do
before do
stub_application_setting(self_monitoring_project_id: project.id)
end
@@ -7082,7 +7087,7 @@ RSpec.describe Project, factory_default: :keep do
it { is_expected.to be true }
end
- context 'when the project is not self monitoring' do
+ context 'when the project is not self-monitoring' do
it { is_expected.to be false }
end
end
@@ -7124,7 +7129,7 @@ RSpec.describe Project, factory_default: :keep do
describe '#export_in_progress?' do
let(:project) { build(:project) }
- let!(:project_export_job ) { create(:project_export_job, project: project) }
+ let!(:project_export_job) { create(:project_export_job, project: project) }
context 'when project export is enqueued' do
it { expect(project.export_in_progress?).to be false }
@@ -7149,7 +7154,7 @@ RSpec.describe Project, factory_default: :keep do
describe '#export_status' do
let(:project) { build(:project) }
- let!(:project_export_job ) { create(:project_export_job, project: project) }
+ let!(:project_export_job) { create(:project_export_job, project: project) }
context 'when project export is enqueued' do
it { expect(project.export_status).to eq :queued }
@@ -7173,7 +7178,7 @@ RSpec.describe Project, factory_default: :keep do
end
context 'when project export is being regenerated' do
- let!(:new_project_export_job ) { create(:project_export_job, project: project) }
+ let!(:new_project_export_job) { create(:project_export_job, project: project) }
before do
finish_job(project_export_job)
@@ -7475,15 +7480,6 @@ RSpec.describe Project, factory_default: :keep do
end
end
- describe '#ci_config_external_project' do
- subject(:ci_config_external_project) { project.ci_config_external_project }
-
- let(:other_project) { create(:project) }
- let(:project) { build(:project, ci_config_path: ".gitlab-ci.yml@#{other_project.full_path}") }
-
- it { is_expected.to eq(other_project) }
- end
-
describe '#enabled_group_deploy_keys' do
let_it_be(:project) { create(:project) }
diff --git a/spec/models/projects/wiki_repository_spec.rb b/spec/models/projects/wiki_repository_spec.rb
new file mode 100644
index 00000000000..6868e1f5fb9
--- /dev/null
+++ b/spec/models/projects/wiki_repository_spec.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::WikiRepository do
+ subject { described_class.new(project: build(:project)) }
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:project).inverse_of(:wiki_repository) }
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:project) }
+ it { is_expected.to validate_uniqueness_of(:project) }
+ end
+end
diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb
index b88367b9ca2..b623d534f29 100644
--- a/spec/models/protected_branch_spec.rb
+++ b/spec/models/protected_branch_spec.rb
@@ -7,11 +7,54 @@ RSpec.describe ProtectedBranch do
describe 'Associations' do
it { is_expected.to belong_to(:project) }
+ it { is_expected.to belong_to(:group) }
end
describe 'Validation' do
- it { is_expected.to validate_presence_of(:project) }
it { is_expected.to validate_presence_of(:name) }
+
+ describe '#validate_either_project_or_top_group' do
+ context 'when protected branch does not have project or group association' do
+ it 'validate failed' do
+ subject.assign_attributes(project: nil, group: nil)
+ subject.validate
+
+ expect(subject.errors).to include(:base)
+ end
+ end
+
+ context 'when protected branch is associated with both project and group' do
+ it 'validate failed' do
+ subject.assign_attributes(project: build(:project), group: build(:group))
+ subject.validate
+
+ expect(subject.errors).to include(:base)
+ end
+ end
+
+ context 'when protected branch is associated with a subgroup' do
+ it 'validate failed' do
+ subject.assign_attributes(project: nil, group: build(:group, :nested))
+ subject.validate
+
+ expect(subject.errors).to include(:base)
+ end
+ end
+ end
+ end
+
+ describe 'set a group' do
+ context 'when associated with group' do
+ it 'create successfully' do
+ expect { subject.group = build(:group) }.not_to raise_error
+ end
+ end
+
+ context 'when associated with other namespace' do
+ it 'create failed with `ActiveRecord::AssociationTypeMismatch`' do
+ expect { subject.group = build(:namespace) }.to raise_error(ActiveRecord::AssociationTypeMismatch)
+ end
+ end
end
describe "#matches?" do
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 6fbf69ec23a..93872bcd827 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -4,7 +4,6 @@ require 'spec_helper'
RSpec.describe Repository do
include RepoHelpers
- include GitHelpers
TestBlob = Struct.new(:path)
@@ -463,7 +462,7 @@ RSpec.describe Repository do
repository.delete_branch(branch)
expect(subject).not_to be_empty
- expect(subject).to all( be_a(::Commit) )
+ expect(subject).to all(be_a(::Commit))
expect(subject.size).to eq(1)
end
end
@@ -482,7 +481,7 @@ RSpec.describe Repository do
end
it 'returns only Commit instances' do
- expect(subject).to all( be_a(Commit) )
+ expect(subject).to all(be_a(Commit))
end
context 'when some commits are not found ' do
@@ -2978,7 +2977,7 @@ RSpec.describe Repository do
it 'returns false for invalid commit IDs' do
expect(repository.ancestor?(commit.id, Gitlab::Git::BLANK_SHA)).to eq(false)
- expect(repository.ancestor?( Gitlab::Git::BLANK_SHA, commit.id)).to eq(false)
+ expect(repository.ancestor?(Gitlab::Git::BLANK_SHA, commit.id)).to eq(false)
end
end
diff --git a/spec/models/serverless/domain_cluster_spec.rb b/spec/models/serverless/domain_cluster_spec.rb
index fdae0483c19..487385c62c1 100644
--- a/spec/models/serverless/domain_cluster_spec.rb
+++ b/spec/models/serverless/domain_cluster_spec.rb
@@ -5,6 +5,16 @@ 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) }
diff --git a/spec/models/spam_log_spec.rb b/spec/models/spam_log_spec.rb
index a40c7c5c892..564710b31d0 100644
--- a/spec/models/spam_log_spec.rb
+++ b/spec/models/spam_log_spec.rb
@@ -21,37 +21,18 @@ RSpec.describe SpamLog do
end
context 'when admin mode is enabled', :enable_admin_mode do
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- it 'initiates user removal', :sidekiq_inline do
- spam_log = build(:spam_log)
- user = spam_log.user
-
- perform_enqueued_jobs do
- spam_log.remove_user(deleted_by: admin)
- end
-
- expect(
- Users::GhostUserMigration.where(user: user,
- initiator_user: admin)
- ).to be_exists
- end
- end
+ it 'initiates user removal', :sidekiq_inline do
+ spam_log = build(:spam_log)
+ user = spam_log.user
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
+ perform_enqueued_jobs do
+ spam_log.remove_user(deleted_by: admin)
end
- it 'removes the user', :sidekiq_inline do
- spam_log = build(:spam_log)
- user = spam_log.user
-
- perform_enqueued_jobs do
- spam_log.remove_user(deleted_by: admin)
- end
-
- expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound)
- end
+ expect(
+ Users::GhostUserMigration.where(user: user,
+ initiator_user: admin)
+ ).to be_exists
end
end
diff --git a/spec/models/terraform/state_spec.rb b/spec/models/terraform/state_spec.rb
index a484952bfe9..533e6e4bd7b 100644
--- a/spec/models/terraform/state_spec.rb
+++ b/spec/models/terraform/state_spec.rb
@@ -10,6 +10,12 @@ RSpec.describe Terraform::State do
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to validate_presence_of(:project_id) }
+ it { is_expected.to validate_presence_of(:uuid) }
+
+ describe 'default values' do
+ it { expect(described_class.new.uuid).to be_present }
+ it { expect(described_class.new(uuid: 'test').uuid).to eq('test') }
+ end
describe 'scopes' do
describe '.ordered_by_name' do
diff --git a/spec/models/terraform/state_version_spec.rb b/spec/models/terraform/state_version_spec.rb
index 22b1397f30a..477041117cb 100644
--- a/spec/models/terraform/state_version_spec.rb
+++ b/spec/models/terraform/state_version_spec.rb
@@ -10,6 +10,15 @@ RSpec.describe Terraform::StateVersion do
it { is_expected.to belong_to(:created_by_user).class_name('User').optional }
it { is_expected.to belong_to(:build).class_name('Ci::Build').optional }
+ describe 'default attributes' do
+ before do
+ allow(Terraform::StateUploader).to receive(:default_store).and_return(5)
+ end
+
+ it { expect(described_class.new.file_store).to eq(5) }
+ it { expect(described_class.new(file_store: 3).file_store).to eq(3) }
+ end
+
describe 'scopes' do
describe '.ordered_by_version_desc' do
let(:terraform_state) { create(:terraform_state) }
diff --git a/spec/models/time_tracking/timelog_category_spec.rb b/spec/models/time_tracking/timelog_category_spec.rb
index d8b938e9d68..ac2fb651134 100644
--- a/spec/models/time_tracking/timelog_category_spec.rb
+++ b/spec/models/time_tracking/timelog_category_spec.rb
@@ -7,6 +7,10 @@ RSpec.describe TimeTracking::TimelogCategory, type: :model do
it { is_expected.to belong_to(:namespace).with_foreign_key('namespace_id') }
end
+ describe 'default values' do
+ it { expect(described_class.new.color).to eq(described_class::DEFAULT_COLOR) }
+ end
+
describe 'validations' do
subject { create(:timelog_category) }
diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb
index 18b0cb36cc6..23ba0be2fbc 100644
--- a/spec/models/todo_spec.rb
+++ b/spec/models/todo_spec.rb
@@ -498,7 +498,7 @@ RSpec.describe Todo do
describe '.for_internal_notes' do
it 'returns todos created from internal notes' do
- internal_note = create(:note, confidential: true )
+ internal_note = create(:note, confidential: true)
todo = create(:todo, note: internal_note)
create(:todo)
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 8ebf3d70165..7207ee0b172 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -144,6 +144,7 @@ RSpec.describe User do
it { is_expected.to have_many(:callouts).class_name('Users::Callout') }
it { is_expected.to have_many(:group_callouts).class_name('Users::GroupCallout') }
it { is_expected.to have_many(:project_callouts).class_name('Users::ProjectCallout') }
+ it { is_expected.to have_many(:created_projects).dependent(:nullify).class_name('Project') }
describe '#user_detail' do
it 'does not persist `user_detail` by default' do
@@ -2481,6 +2482,30 @@ RSpec.describe User do
end
end
+ describe 'starred_projects' do
+ let_it_be(:project) { create(:project) }
+
+ before do
+ user.toggle_star(project)
+ end
+
+ context 'when blocking a user' do
+ let_it_be(:user) { create(:user) }
+
+ it 'decrements star count of project' do
+ expect { user.block }.to change { project.reload.star_count }.by(-1)
+ end
+ end
+
+ context 'when activating a user' do
+ let_it_be(:user) { create(:user, :blocked) }
+
+ it 'increments star count of project' do
+ expect { user.activate }.to change { project.reload.star_count }.by(1)
+ end
+ end
+ end
+
describe '.instance_access_request_approvers_to_be_notified' do
let_it_be(:admin_issue_board_list) { create_list(:user, 12, :admin, :with_sign_ins) }
@@ -3031,6 +3056,10 @@ RSpec.describe User do
it 'returns no matches for nil' do
expect(described_class.search(nil)).to be_empty
end
+
+ it 'returns no matches for an array' do
+ expect(described_class.search(%w[the test])).to be_empty
+ end
end
describe '.user_search_minimum_char_limit' do
@@ -6157,172 +6186,28 @@ RSpec.describe User do
end
end
- describe '#authenticatable_salt' do
- let(:user) { create(:user) }
-
- subject(:authenticatable_salt) { user.authenticatable_salt }
-
- it 'uses password_salt' do
- expect(authenticatable_salt).to eq(user.password_salt)
- end
-
- context 'when the encrypted_password is an unknown type' do
- let(:encrypted_password) { '$argon2i$v=19$m=512,t=4,p=2$eM+ZMyYkpDRGaI3xXmuNcQ$c5DeJg3eb5dskVt1mDdxfw' }
-
- before do
- user.update_attribute(:encrypted_password, encrypted_password)
- end
-
- it 'returns the first 30 characters of the encrypted_password' do
- expect(authenticatable_salt).to eq(encrypted_password[0, 29])
- end
- end
-
- context 'when pbkdf2_password_encryption is disabled' do
- before do
- stub_feature_flags(pbkdf2_password_encryption: false)
- end
-
- it 'returns the first 30 characters of the encrypted_password' do
- expect(authenticatable_salt).to eq(user.encrypted_password[0, 29])
- end
- end
- end
-
- def compare_pbkdf2_password(user, password)
- Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512.compare(user.encrypted_password, password)
- end
-
describe '#valid_password?' do
subject(:validate_password) { user.valid_password?(password) }
- context 'user with password not in disallowed list' do
- let(:user) { create(:user) }
- let(:password) { user.password }
-
- it { is_expected.to be_truthy }
-
- context 'using a wrong password' do
- let(:password) { 'WRONG PASSWORD' }
-
- it { is_expected.to be_falsey }
- end
-
- context 'when pbkdf2_sha512_encryption is disabled and the user password is pbkdf2+sha512' do
- it 'does not validate correctly' do
- user # Create the user while the feature is enabled
- stub_feature_flags(pbkdf2_password_encryption: false)
-
- expect(validate_password).to be_falsey
- end
- end
- end
-
context 'user with disallowed password' do
let(:user) { create(:user, :disallowed_password) }
let(:password) { user.password }
- it { is_expected.to be_falsey }
-
- context 'using a wrong password' do
- let(:password) { 'WRONG PASSWORD' }
-
- it { is_expected.to be_falsey }
- end
- end
-
- context 'user with a bcrypt password hash' do
- # Manually set a 'known' encrypted password
- let(:password) { User.random_password }
- let(:encrypted_password) { Devise::Encryptor.digest(User, password) }
- let(:user) { create(:user, encrypted_password: encrypted_password) }
-
- shared_examples 'not re-encrypting with PBKDF2' do
- it 'does not re-encrypt with PBKDF2' do
- validate_password
-
- expect(user.reload.encrypted_password).to eq(encrypted_password)
- end
- end
-
- context 'using the wrong password' do
- # password 'WRONG PASSWORD' will not match the bcrypt hash
- let(:password) { 'WRONG PASSWORD' }
- let(:encrypted_password) { Devise::Encryptor.digest(User, User.random_password) }
-
- it { is_expected.to be_falsey }
-
- it_behaves_like 'not re-encrypting with PBKDF2'
-
- context 'when pbkdf2_password_encryption is disabled' do
- before do
- stub_feature_flags(pbkdf2_password_encryption: false)
- end
-
- it { is_expected.to be_falsey }
-
- it_behaves_like 'not re-encrypting with PBKDF2'
- end
- end
-
- context 'using the correct password' do
- it { is_expected.to be_truthy }
-
- it 'validates the password and re-encrypts with PBKDF2' do
- validate_password
-
- current_encrypted_password = user.reload.encrypted_password
-
- expect(compare_pbkdf2_password(user, password)).to eq(true)
- expect { ::BCrypt::Password.new(current_encrypted_password) }
- .to raise_error(::BCrypt::Errors::InvalidHash)
- end
-
- context 'when pbkdf2_password_encryption is disabled' do
- before do
- stub_feature_flags(pbkdf2_password_encryption: false)
- end
-
- it { is_expected.to be_truthy }
-
- it_behaves_like 'not re-encrypting with PBKDF2'
- end
-
- context 'when pbkdf2_password_encryption_write is disabled' do
- before do
- stub_feature_flags(pbkdf2_password_encryption_write: false)
- end
-
- it { is_expected.to be_truthy }
-
- it_behaves_like 'not re-encrypting with PBKDF2'
- end
- end
+ it { is_expected.to eq(false) }
end
- context 'user with password hash that is neither PBKDF2 nor BCrypt' do
- # Manually calculated User.random_password
- let(:password) { "gg_w215TmVXGWSt7RJKXwYTVz886f6SDM3zvzztaJf2mX9ttUE8gRkNJSbWyWRLqxz4LFzxBekPe75ydDcGauE9wqg-acKMRT-WpSYjTm1Rdx-tnssE7CQByJcnxwWNH" }
- # Created with https://argon2.online/ using 'aaaaaaaa' as the salt
- let(:encrypted_password) { "$argon2i$v=19$m=512,t=4,p=2$YWFhYWFhYWE$PvJscKO5XRlevcgRReUg6w" }
- let(:user) { create(:user, encrypted_password: encrypted_password) }
-
- it { is_expected.to be_falsey }
-
- context 'when pbkdf2_password_encryption is disabled' do
- before do
- stub_feature_flags(pbkdf2_password_encryption: false)
- end
+ context 'using a wrong password' do
+ let(:user) { create(:user) }
+ let(:password) { 'WRONG PASSWORD' }
- it { is_expected.to be_falsey }
- end
+ it { is_expected.to eq(false) }
end
context 'user with autogenerated_password' do
let(:user) { build_stubbed(:user, password_automatically_set: true) }
let(:password) { user.password }
- it { is_expected.to be_falsey }
+ it { is_expected.to eq(false) }
end
end
@@ -6377,95 +6262,6 @@ RSpec.describe User do
end
end
- # These entire test section can be removed once the :pbkdf2_password_encryption feature flag is removed.
- describe '#password=' do
- let(:user) { create(:user) }
- let(:password) { User.random_password }
-
- def compare_bcrypt_password(user, password)
- Devise::Encryptor.compare(User, user.encrypted_password, password)
- end
-
- context 'when pbkdf2_password_encryption is enabled' do
- it 'calls PBKDF2 digest and not the default Devise encryptor' do
- expect(Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512).to receive(:digest).at_least(:once).and_call_original
- expect(Devise::Encryptor).not_to receive(:digest)
-
- user.password = password
- end
-
- it 'saves the password in PBKDF2 format' do
- user.password = password
- user.save!
-
- expect(compare_pbkdf2_password(user, password)).to eq(true)
- expect { compare_bcrypt_password(user, password) }.to raise_error(::BCrypt::Errors::InvalidHash)
- end
-
- context 'when pbkdf2_password_encryption_write is disabled' do
- before do
- stub_feature_flags(pbkdf2_password_encryption_write: false)
- end
-
- it 'calls default Devise encryptor and not the PBKDF2 encryptor' do
- expect(Devise::Encryptor).to receive(:digest).at_least(:once).and_call_original
- expect(Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512).not_to receive(:digest)
-
- user.password = password
- end
- end
- end
-
- context 'when pbkdf2_password_encryption is disabled' do
- before do
- stub_feature_flags(pbkdf2_password_encryption: false)
- end
-
- it 'calls default Devise encryptor and not the PBKDF2 encryptor' do
- expect(Devise::Encryptor).to receive(:digest).at_least(:once).and_call_original
- expect(Devise::Pbkdf2Encryptable::Encryptors::Pbkdf2Sha512).not_to receive(:digest)
-
- user.password = password
- end
-
- it 'saves the password in BCrypt format' do
- user.password = password
- user.save!
-
- expect { compare_pbkdf2_password(user, password) }.to raise_error Devise::Pbkdf2Encryptable::Encryptors::InvalidHash
- expect(compare_bcrypt_password(user, password)).to eq(true)
- end
- end
- end
-
- describe '#password_strategy' do
- let(:user) { create(:user, encrypted_password: encrypted_password) }
-
- context 'with a PBKDF2+SHA512 encrypted password' do
- let(:encrypted_password) { '$pbkdf2-sha512$20000$boHGAw0hEyI$DBA67J7zNZebyzLtLk2X9wRDbmj1LNKVGnZLYyz6PGrIDGIl45fl/BPH0y1TPZnV90A20i.fD9C3G9Bp8jzzOA' }
-
- it 'extracts the correct strategy', :aggregate_failures do
- expect(user.password_strategy).to eq(:pbkdf2_sha512)
- end
- end
-
- context 'with a BCrypt encrypted password' do
- let(:encrypted_password) { '$2a$10$xLTxCKOa75IU4RQGqqOrTuZOgZdJEzfSzjG6ZSEi/C31TB/yLZYpi' }
-
- it 'extracts the correct strategy', :aggregate_failures do
- expect(user.password_strategy).to eq(:bcrypt)
- end
- end
-
- context 'with an unknown encrypted password' do
- let(:encrypted_password) { '$pbkdf2-sha256$6400$.6UI/S.nXIk8jcbdHx3Fhg$98jZicV16ODfEsEZeYPGHU3kbrUrvUEXOPimVSQDD44' }
-
- it 'returns unknown strategy' do
- expect(user.password_strategy).to eq(:unknown)
- end
- end
- end
-
describe '#password_expired?' do
let(:user) { build(:user, password_expires_at: password_expires_at) }
diff --git a/spec/models/users/calloutable_spec.rb b/spec/models/users/calloutable_spec.rb
index 791fe1c1bc4..7e186445c1b 100644
--- a/spec/models/users/calloutable_spec.rb
+++ b/spec/models/users/calloutable_spec.rb
@@ -15,8 +15,8 @@ RSpec.describe Users::Calloutable do
describe '#dismissed_after?' do
let(:some_feature_name) { Users::Callout.feature_names.keys.second }
- let(:callout_dismissed_month_ago) { create(:callout, feature_name: some_feature_name, dismissed_at: 1.month.ago ) }
- let(:callout_dismissed_day_ago) { create(:callout, feature_name: some_feature_name, dismissed_at: 1.day.ago ) }
+ let(:callout_dismissed_month_ago) { create(:callout, feature_name: some_feature_name, dismissed_at: 1.month.ago) }
+ let(:callout_dismissed_day_ago) { create(:callout, feature_name: some_feature_name, dismissed_at: 1.day.ago) }
it 'returns whether a callout dismissed after specified date' do
expect(callout_dismissed_month_ago.dismissed_after?(15.days.ago)).to eq(false)
diff --git a/spec/models/users/ghost_user_migration_spec.rb b/spec/models/users/ghost_user_migration_spec.rb
index d4a0657c3be..a0b2af6175a 100644
--- a/spec/models/users/ghost_user_migration_spec.rb
+++ b/spec/models/users/ghost_user_migration_spec.rb
@@ -8,7 +8,18 @@ RSpec.describe Users::GhostUserMigration do
it { is_expected.to belong_to(:initiator_user) }
end
- describe 'validation' do
+ describe 'validations' do
it { is_expected.to validate_presence_of(:user_id) }
end
+
+ describe 'scopes' do
+ describe '.consume_order' do
+ let!(:ghost_user_migration_1) { create(:ghost_user_migration, consume_after: Time.current) }
+ let!(:ghost_user_migration_2) { create(:ghost_user_migration, consume_after: 5.minutes.ago) }
+
+ subject { described_class.consume_order.to_a }
+
+ it { is_expected.to eq([ghost_user_migration_2, ghost_user_migration_1]) }
+ end
+ end
end
diff --git a/spec/models/users/namespace_commit_email_spec.rb b/spec/models/users/namespace_commit_email_spec.rb
new file mode 100644
index 00000000000..696dac25f9b
--- /dev/null
+++ b/spec/models/users/namespace_commit_email_spec.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Users::NamespaceCommitEmail, type: :model do
+ subject { build(:namespace_commit_email) }
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:user) }
+ it { is_expected.to belong_to(:namespace) }
+ it { is_expected.to belong_to(:email) }
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:user) }
+ it { is_expected.to validate_presence_of(:namespace) }
+ it { is_expected.to validate_presence_of(:email) }
+ end
+
+ it { is_expected.to be_valid }
+end
diff --git a/spec/models/users_star_project_spec.rb b/spec/models/users_star_project_spec.rb
index e41519a2b69..60ec108f77d 100644
--- a/spec/models/users_star_project_spec.rb
+++ b/spec/models/users_star_project_spec.rb
@@ -3,5 +3,85 @@
require 'spec_helper'
RSpec.describe UsersStarProject, type: :model do
+ let_it_be(:project1) { create(:project) }
+ let_it_be(:project2) { create(:project) }
+ let_it_be(:user_active) { create(:user, state: 'active', name: 'user2', private_profile: true) }
+ let_it_be(:user_blocked) { create(:user, state: 'blocked', name: 'user1') }
+
it { is_expected.to belong_to(:project).touch(false) }
+
+ describe 'scopes' do
+ let_it_be(:users_star_project1) { create(:users_star_project, project: project1, user: user_active) }
+ let_it_be(:users_star_project2) { create(:users_star_project, project: project2, user: user_blocked) }
+
+ describe '.all' do
+ it 'returns all records' do
+ expect(described_class.all).to contain_exactly(users_star_project1, users_star_project2)
+ end
+ end
+
+ describe '.with_active_user' do
+ it 'returns only records of active users' do
+ expect(described_class.with_active_user).to contain_exactly(users_star_project1)
+ end
+ end
+
+ describe '.order_user_name_asc' do
+ it 'sorts records by ascending user name' do
+ expect(described_class.order_user_name_asc).to eq([users_star_project2, users_star_project1])
+ end
+ end
+
+ describe '.order_user_name_desc' do
+ it 'sorts records by descending user name' do
+ expect(described_class.order_user_name_desc).to eq([users_star_project1, users_star_project2])
+ end
+ end
+
+ describe '.by_project' do
+ it 'returns only records of given project' do
+ expect(described_class.by_project(project2)).to contain_exactly(users_star_project2)
+ end
+ end
+
+ describe '.with_public_profile' do
+ it 'returns only records of users with public profile' do
+ expect(described_class.with_public_profile).to contain_exactly(users_star_project2)
+ end
+ end
+ end
+
+ describe 'star count hooks' do
+ context 'on after_create' do
+ context 'if user is active' do
+ it 'increments star count of project' do
+ expect { user_active.toggle_star(project1) }.to change { project1.reload.star_count }.by(1)
+ end
+ end
+
+ context 'if user is not active' do
+ it 'does not increment star count of project' do
+ expect { user_blocked.toggle_star(project1) }.not_to change { project1.reload.star_count }
+ end
+ end
+ end
+
+ context 'on after_destory' do
+ context 'if user is active' do
+ let_it_be(:users_star_project) { create(:users_star_project, project: project2, user: user_active) }
+
+ it 'decrements star count of project' do
+ expect { users_star_project.destroy! }.to change { project2.reload.star_count }.by(-1)
+ end
+ end
+
+ context 'if user is not active' do
+ let_it_be(:users_star_project) { create(:users_star_project, project: project2, user: user_blocked) }
+
+ it 'does not decrement star count of project' do
+ expect { users_star_project.destroy! }.not_to change { project2.reload.star_count }
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/work_items/type_spec.rb b/spec/models/work_items/type_spec.rb
index e41df7f0f61..6685720778a 100644
--- a/spec/models/work_items/type_spec.rb
+++ b/spec/models/work_items/type_spec.rb
@@ -35,10 +35,10 @@ RSpec.describe WorkItems::Type do
it 'deletes type but not unrelated issues' do
type = create(:work_item_type)
- expect(WorkItems::Type.count).to eq(6)
+ expect(WorkItems::Type.count).to eq(8)
expect { type.destroy! }.not_to change(Issue, :count)
- expect(WorkItems::Type.count).to eq(5)
+ expect(WorkItems::Type.count).to eq(7)
end
end
@@ -69,7 +69,8 @@ RSpec.describe WorkItems::Type do
::WorkItems::Widgets::Hierarchy,
::WorkItems::Widgets::Labels,
::WorkItems::Widgets::Assignees,
- ::WorkItems::Widgets::StartAndDueDate
+ ::WorkItems::Widgets::StartAndDueDate,
+ ::WorkItems::Widgets::Milestone
)
end
end
diff --git a/spec/models/work_items/widgets/hierarchy_spec.rb b/spec/models/work_items/widgets/hierarchy_spec.rb
index cd528772710..c847f2694fe 100644
--- a/spec/models/work_items/widgets/hierarchy_spec.rb
+++ b/spec/models/work_items/widgets/hierarchy_spec.rb
@@ -26,22 +26,6 @@ RSpec.describe WorkItems::Widgets::Hierarchy do
subject { described_class.new(parent_link.work_item).parent }
it { is_expected.to eq(parent_link.work_item_parent) }
-
- context 'when work_items flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it { is_expected.to be_nil }
- end
-
- context 'when work_items flag is enabled for the parent group' do
- before do
- stub_feature_flags(work_items: group)
- end
-
- it { is_expected.to eq(parent_link.work_item_parent) }
- end
end
describe '#children' do
@@ -51,21 +35,5 @@ RSpec.describe WorkItems::Widgets::Hierarchy do
subject { described_class.new(work_item_parent).children }
it { is_expected.to contain_exactly(parent_link1.work_item, parent_link2.work_item) }
-
- context 'when work_items flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it { is_expected.to be_empty }
- end
-
- context 'when work_items flag is enabled for the parent group' do
- before do
- stub_feature_flags(work_items: group)
- end
-
- it { is_expected.to contain_exactly(parent_link1.work_item, parent_link2.work_item) }
- end
end
end
diff --git a/spec/models/work_items/widgets/milestone_spec.rb b/spec/models/work_items/widgets/milestone_spec.rb
new file mode 100644
index 00000000000..7b2d661df29
--- /dev/null
+++ b/spec/models/work_items/widgets/milestone_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WorkItems::Widgets::Milestone do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:milestone) { create(:milestone, project: project) }
+ let_it_be(:work_item) { create(:work_item, :issue, project: project, milestone: milestone) }
+
+ describe '.type' do
+ subject { described_class.type }
+
+ it { is_expected.to eq(:milestone) }
+ end
+
+ describe '#type' do
+ subject { described_class.new(work_item).type }
+
+ it { is_expected.to eq(:milestone) }
+ end
+
+ describe '#milestone' do
+ subject { described_class.new(work_item).milestone }
+
+ it { is_expected.to eq(work_item.milestone) }
+ end
+end
diff --git a/spec/policies/global_policy_spec.rb b/spec/policies/global_policy_spec.rb
index da0427420e4..4a8855f1da7 100644
--- a/spec/policies/global_policy_spec.rb
+++ b/spec/policies/global_policy_spec.rb
@@ -591,34 +591,4 @@ RSpec.describe GlobalPolicy do
it { is_expected.not_to be_allowed(:log_in) }
end
end
-
- describe 'delete runners' do
- context 'when anonymous' do
- let(:current_user) { nil }
-
- it { is_expected.not_to be_allowed(:delete_runners) }
- end
-
- context 'regular user' do
- it { is_expected.not_to be_allowed(:delete_runners) }
- end
-
- context 'when external' do
- let(:current_user) { build(:user, :external) }
-
- it { is_expected.not_to be_allowed(:delete_runners) }
- end
-
- context 'admin user' do
- let_it_be(:current_user) { create(:user, :admin) }
-
- context 'when admin mode is enabled', :enable_admin_mode do
- it { is_expected.to be_allowed(:delete_runners) }
- end
-
- context 'when admin mode is disabled' do
- it { is_expected.to be_disallowed(:delete_runners) }
- end
- end
- end
end
diff --git a/spec/policies/group_member_policy_spec.rb b/spec/policies/group_member_policy_spec.rb
index 27ce683861c..6ae5e43def4 100644
--- a/spec/policies/group_member_policy_spec.rb
+++ b/spec/policies/group_member_policy_spec.rb
@@ -83,6 +83,31 @@ RSpec.describe GroupMemberPolicy do
specify { expect_allowed(:read_group) }
end
+ context 'for access requests' do
+ let_it_be(:group) { create(:group, :public) }
+ let_it_be(:user) { create(:user) }
+
+ let(:current_user) { user }
+
+ context 'for own access request' do
+ let(:membership) { create(:group_member, :access_request, group: group, user: user) }
+
+ specify { expect_allowed(:withdraw_member_access_request) }
+ end
+
+ context "for another user's access request" do
+ let(:membership) { create(:group_member, :access_request, group: group, user: create(:user)) }
+
+ specify { expect_disallowed(:withdraw_member_access_request) }
+ end
+
+ context 'for own, valid membership' do
+ let(:membership) { create(:group_member, :developer, group: group, user: user) }
+
+ specify { expect_disallowed(:withdraw_member_access_request) }
+ end
+ end
+
context 'with bot user' do
let(:current_user) { create(:user, :project_bot) }
@@ -100,74 +125,83 @@ RSpec.describe GroupMemberPolicy do
specify { expect_disallowed(:read_group, :destroy_project_bot_member) }
end
- context 'with one owner' do
+ context 'with owner' do
let(:current_user) { owner }
- specify { expect_disallowed(*member_related_permissions) }
- specify { expect_allowed(:read_group) }
- end
+ context 'with group with one owner' do
+ specify { expect_disallowed(*member_related_permissions) }
+ specify { expect_allowed(:read_group) }
+ end
- context 'with one blocked owner' do
- let(:owner) { create(:user, :blocked) }
- let(:current_user) { owner }
+ context 'with group with bot user owner' do
+ before do
+ group.add_owner(create(:user, :project_bot))
+ end
- specify { expect_disallowed(*member_related_permissions) }
- specify { expect_disallowed(:read_group) }
- end
+ specify { expect_disallowed(*member_related_permissions) }
+ end
- context 'with more than one owner' do
- let(:current_user) { owner }
+ context 'with group with more than one owner' do
+ before do
+ group.add_owner(create(:user))
+ end
- before do
- group.add_owner(create(:user))
+ specify { expect_allowed(*member_related_permissions) }
+ specify { expect_disallowed(:destroy_project_bot_member) }
end
- specify { expect_allowed(*member_related_permissions) }
- specify { expect_disallowed(:destroy_project_bot_member) }
- end
+ context 'with group with owners from a parent' do
+ context 'when top-level group' do
+ context 'with group sharing' do
+ let!(:subgroup) { create(:group, :private, parent: group) }
- context 'with the group parent' do
- let(:current_user) { create :user }
- let(:subgroup) { create(:group, :private, parent: group) }
+ before do
+ create(:group_group_link, :owner, shared_group: group, shared_with_group: subgroup)
+ create(:group_member, :owner, group: subgroup)
+ end
- before do
- group.add_owner(owner)
- subgroup.add_owner(current_user)
- end
+ specify { expect_disallowed(*member_related_permissions) }
+ specify { expect_allowed(:read_group) }
+ end
+ end
- it do
- expect_allowed(:destroy_group_member)
- expect_allowed(:update_group_member)
- end
- end
+ context 'when subgroup' do
+ let(:current_user) { create :user }
- context 'without group parent' do
- let(:current_user) { create :user }
- let(:subgroup) { create(:group, :private) }
+ let!(:subgroup) { create(:group, :private, parent: group) }
- before do
- subgroup.add_owner(current_user)
- end
+ before do
+ subgroup.add_owner(current_user)
+ end
- it do
- expect_disallowed(:destroy_group_member)
- expect_disallowed(:update_group_member)
+ specify { expect_allowed(*member_related_permissions) }
+ specify { expect_allowed(:read_group) }
+ end
end
end
- context 'without group parent with two owners' do
- let(:current_user) { create :user }
- let(:other_user) { create :user }
- let(:subgroup) { create(:group, :private) }
+ context 'with blocked owner' do
+ let(:owner) { create(:user, :blocked) }
+ let(:current_user) { owner }
- before do
- subgroup.add_owner(current_user)
- subgroup.add_owner(other_user)
+ specify { expect_disallowed(*member_related_permissions) }
+ specify { expect_disallowed(:read_group) }
+
+ context 'with group with bot user owner' do
+ before do
+ group.add_owner(create(:user, :project_bot))
+ end
+
+ specify { expect_disallowed(*member_related_permissions) }
+ specify { expect_disallowed(:read_group) }
end
- it do
- expect_allowed(:destroy_group_member)
- expect_allowed(:update_group_member)
+ context 'with group with more than one blocked owner' do
+ before do
+ group.add_owner(create(:user, :blocked))
+ end
+
+ specify { expect_allowed(:destroy_group_member) }
end
end
end
diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb
index c65933c5208..60acacac814 100644
--- a/spec/policies/group_policy_spec.rb
+++ b/spec/policies/group_policy_spec.rb
@@ -258,6 +258,19 @@ RSpec.describe GroupPolicy do
it_behaves_like 'deploy token does not get confused with user' do
let(:user_id) { migration_bot.id }
end
+
+ context 'with no user' do
+ let(:current_user) { nil }
+
+ it :aggregate_failures do
+ expect_disallowed(:read_resource_access_tokens, :destroy_resource_access_tokens)
+ expect_disallowed(*guest_permissions)
+ expect_disallowed(*reporter_permissions)
+ expect_disallowed(*developer_permissions)
+ expect_disallowed(*maintainer_permissions)
+ expect_disallowed(*owner_permissions)
+ end
+ end
end
describe 'private nested group use the highest access level from the group and inherited permissions' do
diff --git a/spec/policies/issuable_policy_spec.rb b/spec/policies/issuable_policy_spec.rb
index 2bedcf60539..c8c322b02db 100644
--- a/spec/policies/issuable_policy_spec.rb
+++ b/spec/policies/issuable_policy_spec.rb
@@ -31,8 +31,8 @@ RSpec.describe IssuablePolicy, models: true do
expect(policies).to be_allowed(:resolve_note)
end
- it 'allows reading internal notes' do
- expect(policies).to be_allowed(:read_internal_note)
+ it 'does not allow reading internal notes' do
+ expect(policies).to be_disallowed(:read_internal_note)
end
context 'when user is able to read project' do
@@ -94,8 +94,8 @@ RSpec.describe IssuablePolicy, models: true do
let(:issue) { create(:issue, project: project, assignees: [user]) }
let(:policies) { described_class.new(user, issue) }
- it 'allows reading internal notes' do
- expect(policies).to be_allowed(:read_internal_note)
+ it 'does not allow reading internal notes' do
+ expect(policies).to be_disallowed(:read_internal_note)
end
end
diff --git a/spec/policies/note_policy_spec.rb b/spec/policies/note_policy_spec.rb
index eeaa77a4589..6a261b4ff5b 100644
--- a/spec/policies/note_policy_spec.rb
+++ b/spec/policies/note_policy_spec.rb
@@ -309,42 +309,41 @@ RSpec.describe NotePolicy do
shared_examples_for 'confidential notes permissions' do
it 'does not allow non members to read confidential notes and replies' do
- expect(permissions(non_member, confidential_note)).to be_disallowed(:read_note, :admin_note, :reposition_note, :resolve_note, :award_emoji)
+ expect(permissions(non_member, confidential_note)).to be_disallowed(:read_note, :admin_note, :reposition_note, :resolve_note, :award_emoji, :mark_note_as_confidential)
end
it 'does not allow guests to read confidential notes and replies' do
- expect(permissions(guest, confidential_note)).to be_disallowed(:read_note, :admin_note, :reposition_note, :resolve_note, :award_emoji)
+ expect(permissions(guest, confidential_note)).to be_disallowed(:read_note, :admin_note, :reposition_note, :resolve_note, :award_emoji, :mark_note_as_confidential)
end
it 'allows reporter to read all notes but not resolve and admin them' do
- expect(permissions(reporter, confidential_note)).to be_allowed(:read_note, :award_emoji)
+ expect(permissions(reporter, confidential_note)).to be_allowed(:read_note, :award_emoji, :mark_note_as_confidential)
expect(permissions(reporter, confidential_note)).to be_disallowed(:admin_note, :reposition_note, :resolve_note)
end
it 'allows developer to read and resolve all notes' do
- expect(permissions(developer, confidential_note)).to be_allowed(:read_note, :award_emoji, :resolve_note)
+ expect(permissions(developer, confidential_note)).to be_allowed(:read_note, :award_emoji, :resolve_note, :mark_note_as_confidential)
expect(permissions(developer, confidential_note)).to be_disallowed(:admin_note, :reposition_note)
end
it 'allows maintainers to read all notes and admin them' do
- expect(permissions(maintainer, confidential_note)).to be_allowed(:read_note, :admin_note, :reposition_note, :resolve_note, :award_emoji)
+ expect(permissions(maintainer, confidential_note)).to be_allowed(:read_note, :admin_note, :reposition_note, :resolve_note, :award_emoji, :mark_note_as_confidential)
end
context 'when admin mode is enabled', :enable_admin_mode do
it 'allows admins to read all notes and admin them' do
- expect(permissions(admin, confidential_note)).to be_allowed(:read_note, :admin_note, :reposition_note, :resolve_note, :award_emoji)
+ expect(permissions(admin, confidential_note)).to be_allowed(:read_note, :admin_note, :reposition_note, :resolve_note, :award_emoji, :mark_note_as_confidential)
end
end
context 'when admin mode is disabled' do
it 'does not allow non members to read confidential notes and replies' do
- expect(permissions(admin, confidential_note)).to be_disallowed(:read_note, :admin_note, :reposition_note, :resolve_note, :award_emoji)
+ expect(permissions(admin, confidential_note)).to be_disallowed(:read_note, :admin_note, :reposition_note, :resolve_note, :award_emoji, :mark_note_as_confidential)
end
end
- it 'allows noteable author to read and resolve all notes' do
- expect(permissions(author, confidential_note)).to be_allowed(:read_note, :resolve_note, :award_emoji)
- expect(permissions(author, confidential_note)).to be_disallowed(:admin_note, :reposition_note)
+ it 'disallows noteable author to read and resolve all notes' do
+ expect(permissions(author, confidential_note)).to be_disallowed(:read_note, :resolve_note, :award_emoji, :mark_note_as_confidential, :admin_note, :reposition_note)
end
end
@@ -354,9 +353,8 @@ RSpec.describe NotePolicy do
it_behaves_like 'confidential notes permissions'
- it 'allows noteable assignees to read all notes' do
- expect(permissions(assignee, confidential_note)).to be_allowed(:read_note, :award_emoji)
- expect(permissions(assignee, confidential_note)).to be_disallowed(:admin_note, :reposition_note, :resolve_note)
+ it 'disallows noteable assignees to read all notes' do
+ expect(permissions(assignee, confidential_note)).to be_disallowed(:read_note, :award_emoji, :mark_note_as_confidential, :admin_note, :reposition_note, :resolve_note)
end
end
end
diff --git a/spec/policies/project_member_policy_spec.rb b/spec/policies/project_member_policy_spec.rb
index b19ab71fcb5..d7c155b39f5 100644
--- a/spec/policies/project_member_policy_spec.rb
+++ b/spec/policies/project_member_policy_spec.rb
@@ -4,13 +4,14 @@ require 'spec_helper'
RSpec.describe ProjectMemberPolicy do
let(:project) { create(:project) }
- let(:maintainer_user) { create(:user) }
+ let(:maintainer) { create(:user) }
let(:member) { create(:project_member, project: project, user: member_user) }
+ let(:current_user) { maintainer }
- subject { described_class.new(maintainer_user, member) }
+ subject { described_class.new(current_user, member) }
before do
- create(:project_member, :maintainer, project: project, user: maintainer_user)
+ create(:project_member, :maintainer, project: project, user: maintainer)
end
context 'with regular member' do
@@ -40,4 +41,29 @@ RSpec.describe ProjectMemberPolicy do
it { is_expected.not_to be_allowed(:update_project_member) }
it { is_expected.not_to be_allowed(:destroy_project_member) }
end
+
+ context 'for access requests' do
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:user) { create(:user) }
+
+ let(:current_user) { user }
+
+ context 'for own access request' do
+ let(:member) { create(:project_member, :access_request, project: project, user: user) }
+
+ specify { expect_allowed(:withdraw_member_access_request) }
+ end
+
+ context "for another user's access request" do
+ let(:member) { create(:project_member, :access_request, project: project, user: create(:user)) }
+
+ specify { expect_disallowed(:withdraw_member_access_request) }
+ end
+
+ context 'for own, valid membership' do
+ let(:member) { create(:project_member, :developer, project: project, user: user) }
+
+ specify { expect_disallowed(:withdraw_member_access_request) }
+ end
+ end
end
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index 40ee2e662b2..973ed66b8d8 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -323,7 +323,7 @@ RSpec.describe ProjectPolicy do
:create_environment, :read_environment, :update_environment, :admin_environment, :destroy_environment,
:create_cluster, :read_cluster, :update_cluster, :admin_cluster,
:create_deployment, :read_deployment, :update_deployment, :admin_deployment, :destroy_deployment,
- :destroy_release, :download_code, :build_download_code
+ :download_code, :build_download_code
]
end
@@ -533,6 +533,41 @@ RSpec.describe ProjectPolicy do
end
end
+ context 'with timeline event tags' do
+ context 'when user is member of the project' do
+ it 'allows access to timeline event tags' do
+ expect(described_class.new(owner, project)).to be_allowed(:read_incident_management_timeline_event_tag)
+ expect(described_class.new(developer, project)).to be_allowed(:read_incident_management_timeline_event_tag)
+ expect(described_class.new(guest, project)).to be_allowed(:read_incident_management_timeline_event_tag)
+ expect(described_class.new(admin, project)).to be_allowed(:read_incident_management_timeline_event_tag)
+ end
+ end
+
+ context 'when user is a maintainer/owner' do
+ it 'allows to create timeline event tags' do
+ expect(described_class.new(maintainer, project)).to be_allowed(:admin_incident_management_timeline_event_tag)
+ expect(described_class.new(owner, project)).to be_allowed(:admin_incident_management_timeline_event_tag)
+ end
+ end
+
+ context 'when user is a developer/guest/reporter' do
+ it 'disallows creation' do
+ expect(described_class.new(developer, project)).to be_disallowed(:admin_incident_management_timeline_event_tag)
+ expect(described_class.new(guest, project)).to be_disallowed(:admin_incident_management_timeline_event_tag)
+ expect(described_class.new(reporter, project)).to be_disallowed(:admin_incident_management_timeline_event_tag)
+ end
+ end
+
+ context 'when user is not a member of the project' do
+ let(:project) { private_project }
+
+ it 'disallows access to the timeline event tags' do
+ expect(described_class.new(non_member, project)).to be_disallowed(:read_incident_management_timeline_event_tag)
+ expect(described_class.new(non_member, project)).to be_disallowed(:admin_incident_management_timeline_event_tag)
+ end
+ end
+ end
+
context 'reading a project' do
it 'allows access when a user has read access to the repo' do
expect(described_class.new(owner, project)).to be_allowed(:read_project)
@@ -629,17 +664,7 @@ RSpec.describe ProjectPolicy do
context 'when user is member of the project' do
let(:current_user) { developer }
- context 'when work_items feature flag is enabled' do
- it { expect_allowed(:create_task) }
- end
-
- context 'when work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it { expect_disallowed(:create_task) }
- end
+ it { expect_allowed(:create_task) }
end
end
@@ -2299,6 +2324,74 @@ RSpec.describe ProjectPolicy do
end
end
+ describe 'infrastructure feature' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:guest_permissions) { [] }
+
+ let(:developer_permissions) do
+ guest_permissions + [:read_terraform_state, :read_pod_logs, :read_prometheus]
+ end
+
+ let(:maintainer_permissions) do
+ developer_permissions + [:create_cluster, :read_cluster, :update_cluster, :admin_cluster, :admin_terraform_state, :admin_project_google_cloud]
+ end
+
+ where(:project_visibility, :access_level, :role, :allowed) do
+ :public | ProjectFeature::ENABLED | :maintainer | true
+ :public | ProjectFeature::ENABLED | :developer | true
+ :public | ProjectFeature::ENABLED | :guest | true
+ :public | ProjectFeature::ENABLED | :anonymous | true
+ :public | ProjectFeature::PRIVATE | :maintainer | true
+ :public | ProjectFeature::PRIVATE | :developer | true
+ :public | ProjectFeature::PRIVATE | :guest | true
+ :public | ProjectFeature::PRIVATE | :anonymous | false
+ :public | ProjectFeature::DISABLED | :maintainer | false
+ :public | ProjectFeature::DISABLED | :developer | false
+ :public | ProjectFeature::DISABLED | :guest | false
+ :public | ProjectFeature::DISABLED | :anonymous | false
+ :internal | ProjectFeature::ENABLED | :maintainer | true
+ :internal | ProjectFeature::ENABLED | :developer | true
+ :internal | ProjectFeature::ENABLED | :guest | true
+ :internal | ProjectFeature::ENABLED | :anonymous | false
+ :internal | ProjectFeature::PRIVATE | :maintainer | true
+ :internal | ProjectFeature::PRIVATE | :developer | true
+ :internal | ProjectFeature::PRIVATE | :guest | true
+ :internal | ProjectFeature::PRIVATE | :anonymous | false
+ :internal | ProjectFeature::DISABLED | :maintainer | false
+ :internal | ProjectFeature::DISABLED | :developer | false
+ :internal | ProjectFeature::DISABLED | :guest | false
+ :internal | ProjectFeature::DISABLED | :anonymous | false
+ :private | ProjectFeature::ENABLED | :maintainer | true
+ :private | ProjectFeature::ENABLED | :developer | true
+ :private | ProjectFeature::ENABLED | :guest | true
+ :private | ProjectFeature::ENABLED | :anonymous | false
+ :private | ProjectFeature::PRIVATE | :maintainer | true
+ :private | ProjectFeature::PRIVATE | :developer | true
+ :private | ProjectFeature::PRIVATE | :guest | true
+ :private | ProjectFeature::PRIVATE | :anonymous | false
+ :private | ProjectFeature::DISABLED | :maintainer | false
+ :private | ProjectFeature::DISABLED | :developer | false
+ :private | ProjectFeature::DISABLED | :guest | false
+ :private | ProjectFeature::DISABLED | :anonymous | false
+ end
+
+ with_them do
+ let(:current_user) { user_subject(role) }
+ let(:project) { project_subject(project_visibility) }
+
+ it 'allows/disallows the abilities based on the infrastructure access level' do
+ project.project_feature.update!(infrastructure_access_level: access_level)
+
+ if allowed
+ expect_allowed(*permissions_abilities(role))
+ else
+ expect_disallowed(*permissions_abilities(role))
+ end
+ end
+ end
+ end
+
describe 'access_security_and_compliance' do
context 'when the "Security & Compliance" is enabled' do
before do
@@ -2791,6 +2884,27 @@ RSpec.describe ProjectPolicy do
end
end
+ describe 'read_code' do
+ let(:current_user) { create(:user) }
+
+ before do
+ allow(subject).to receive(:allowed?).and_call_original
+ allow(subject).to receive(:allowed?).with(:download_code).and_return(can_download_code)
+ end
+
+ context 'when the current_user can download_code' do
+ let(:can_download_code) { true }
+
+ it { expect_allowed(:read_code) }
+ end
+
+ context 'when the current_user cannot download_code' do
+ let(:can_download_code) { false }
+
+ it { expect_disallowed(:read_code) }
+ end
+ end
+
private
def project_subject(project_type)
diff --git a/spec/policies/user_policy_spec.rb b/spec/policies/user_policy_spec.rb
index b800e7dbc43..d02a94b810e 100644
--- a/spec/policies/user_policy_spec.rb
+++ b/spec/policies/user_policy_spec.rb
@@ -84,6 +84,50 @@ RSpec.describe UserPolicy do
end
end
+ describe "reading a user's associations count" do
+ context 'when current_user is not an admin' do
+ context 'fetching their own data' do
+ subject { described_class.new(current_user, current_user) }
+
+ context 'when current_user is not blocked' do
+ it { is_expected.to be_allowed(:get_user_associations_count ) }
+ end
+
+ context 'when current_user is blocked' do
+ let(:current_user) { create(:user, :blocked) }
+
+ it { is_expected.not_to be_allowed(:get_user_associations_count) }
+ end
+ end
+
+ context "fetching a different user's data" do
+ it { is_expected.not_to be_allowed(:get_user_associations_count) }
+ end
+ end
+
+ context 'when current_user is an admin' do
+ let(:current_user) { admin }
+
+ context 'fetching their own data', :enable_admin_mode do
+ subject { described_class.new(current_user, current_user) }
+
+ context 'when current_user is not blocked' do
+ it { is_expected.to be_allowed(:get_user_associations_count ) }
+ end
+
+ context 'when current_user is blocked' do
+ let(:current_user) { create(:admin, :blocked) }
+
+ it { is_expected.not_to be_allowed(:get_user_associations_count) }
+ end
+ end
+
+ context "fetching a different user's data", :enable_admin_mode do
+ it { is_expected.to be_allowed(:get_user_associations_count) }
+ end
+ end
+ end
+
shared_examples 'changing a user' do |ability|
context "when a regular user tries to destroy another regular user" do
it { is_expected.not_to be_allowed(ability) }
diff --git a/spec/presenters/blob_presenter_spec.rb b/spec/presenters/blob_presenter_spec.rb
index 498b2a32a0e..88dafb7ea1f 100644
--- a/spec/presenters/blob_presenter_spec.rb
+++ b/spec/presenters/blob_presenter_spec.rb
@@ -252,6 +252,18 @@ RSpec.describe BlobPresenter do
end
end
+ describe '#highlight_and_trim' do
+ let(:git_blob) { blob.__getobj__ }
+
+ it 'returns trimmed content for longer line' do
+ trimmed_lines = git_blob.data.split("\n").map { |line| line[0, 55] }.join("\n")
+
+ expect(Gitlab::Highlight).to receive(:highlight).with('files/ruby/regex.rb', "#{trimmed_lines}\n", plain: nil, language: 'ruby', context: { ellipsis_svg: "svg_icon", ellipsis_indexes: [21, 26, 49] })
+
+ presenter.highlight_and_trim(ellipsis_svg: "svg_icon", trim_length: 55)
+ end
+ end
+
describe '#blob_language' do
subject { presenter.blob_language }
diff --git a/spec/presenters/ci/build_runner_presenter_spec.rb b/spec/presenters/ci/build_runner_presenter_spec.rb
index 396fe7843ba..952de121cc4 100644
--- a/spec/presenters/ci/build_runner_presenter_spec.rb
+++ b/spec/presenters/ci/build_runner_presenter_spec.rb
@@ -325,7 +325,7 @@ RSpec.describe Ci::BuildRunnerPresenter do
is_expected.to eq(presenter.variables.to_runner_variables)
end
- context 'when there are variables to expand' do
+ context 'when there is a file variable to expand' do
before_all do
create(:ci_variable, project: project,
key: 'regular_var',
@@ -353,23 +353,50 @@ RSpec.describe Ci::BuildRunnerPresenter do
it 'logs file_variable_is_referenced_in_another_variable' do
expect(Gitlab::AppJsonLogger).to receive(:info).with(
event: 'file_variable_is_referenced_in_another_variable',
- project_id: project.id
+ project_id: project.id,
+ variable: 'file_var'
).once
runner_variables
end
+ end
+
+ 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')
+ end
+
+ it 'returns expanded variables without expanding raws' do
+ expect(runner_variables).to include(
+ { key: 'regular_var', value: 'value 1',
+ public: false, masked: false },
+ { key: 'raw_var', value: 'value 2',
+ public: false, masked: false, raw: true },
+ { key: 'var_with_variables', value: 'value 3 and value 1 and $raw_var and $undefined_var',
+ public: false, masked: false }
+ )
+ end
- context 'when the FF ci_stop_expanding_file_vars_for_runners is disabled' do
+ context 'when the FF ci_raw_variables_in_yaml_config is disabled' do
before do
- stub_feature_flags(ci_stop_expanding_file_vars_for_runners: false)
+ stub_feature_flags(ci_raw_variables_in_yaml_config: false)
end
- it 'returns variables with expanded' do
+ it 'returns expanded variables' do
expect(runner_variables).to include(
{ key: 'regular_var', value: 'value 1',
public: false, masked: false },
- { key: 'file_var', value: 'value 2',
- public: false, masked: false, file: true },
+ { key: 'raw_var', value: 'value 2',
+ public: false, masked: false, raw: true },
{ key: 'var_with_variables', value: 'value 3 and value 1 and value 2 and $undefined_var',
public: false, masked: false }
)
diff --git a/spec/presenters/ci/pipeline_presenter_spec.rb b/spec/presenters/ci/pipeline_presenter_spec.rb
index 4539c3d06f6..7f4c8120e17 100644
--- a/spec/presenters/ci/pipeline_presenter_spec.rb
+++ b/spec/presenters/ci/pipeline_presenter_spec.rb
@@ -90,12 +90,12 @@ RSpec.describe Ci::PipelinePresenter do
end
end
- describe '#name' do
+ describe '#event_type_name' do
before do
allow(pipeline).to receive(:merge_request_event_type) { event_type }
end
- subject { presenter.name }
+ subject { presenter.event_type_name }
context 'for a detached merge request pipeline' do
let(:event_type) { :detached }
diff --git a/spec/presenters/deployments/deployment_presenter_spec.rb b/spec/presenters/deployments/deployment_presenter_spec.rb
index 689451677f4..51da7b9fd12 100644
--- a/spec/presenters/deployments/deployment_presenter_spec.rb
+++ b/spec/presenters/deployments/deployment_presenter_spec.rb
@@ -8,7 +8,7 @@ RSpec.describe Deployments::DeploymentPresenter do
describe '#tags' do
it do
- expect(deployment).to receive(:tags).and_return(['test'])
+ expect(deployment).to receive(:tags).and_return(['refs/tags/test'])
expect(presenter.tags).to eq([{ name: 'test', path: 'tags/test' }])
end
end
diff --git a/spec/presenters/issue_presenter_spec.rb b/spec/presenters/issue_presenter_spec.rb
index e17ae218cd3..df43b0279dd 100644
--- a/spec/presenters/issue_presenter_spec.rb
+++ b/spec/presenters/issue_presenter_spec.rb
@@ -26,20 +26,20 @@ RSpec.describe IssuePresenter do
context 'when issue type is task' do
let(:presented_issue) { task }
- context 'when work_items feature flag is enabled' 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 '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
- context 'when work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it 'returns an issue url for the task' do
- expect(presenter.web_url).to eq("http://localhost/#{group.name}/#{project.name}/-/issues/#{presented_issue.iid}")
- 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)
+ )
end
end
end
@@ -66,20 +66,20 @@ RSpec.describe IssuePresenter do
context 'when issue type is task' do
let(:presented_issue) { task }
- context 'when work_items feature flag is enabled' 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 '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
- context 'when work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it 'returns an issue path for the task' do
- expect(presenter.issue_path).to eq("/#{group.name}/#{project.name}/-/issues/#{presented_issue.iid}")
- 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)
+ )
end
end
end
diff --git a/spec/presenters/packages/npm/package_presenter_spec.rb b/spec/presenters/packages/npm/package_presenter_spec.rb
index 8b99e6d8605..4fa469c7cd2 100644
--- a/spec/presenters/packages/npm/package_presenter_spec.rb
+++ b/spec/presenters/packages/npm/package_presenter_spec.rb
@@ -86,10 +86,10 @@ RSpec.describe ::Packages::Npm::PackagePresenter do
it 'avoids N+1 database queries' do
check_n_plus_one(:versions) do
create_list(:npm_package, 5, project: project, name: package_name).each do |npm_package|
- if has_dependencies
- ::Packages::DependencyLink.dependency_types.keys.each do |dependency_type|
- create(:packages_dependency_link, package: npm_package, dependency_type: dependency_type)
- end
+ next unless has_dependencies
+
+ ::Packages::DependencyLink.dependency_types.keys.each do |dependency_type|
+ create(:packages_dependency_link, package: npm_package, dependency_type: dependency_type)
end
end
end
diff --git a/spec/presenters/project_presenter_spec.rb b/spec/presenters/project_presenter_spec.rb
index 832deee6186..c32cc87afbb 100644
--- a/spec/presenters/project_presenter_spec.rb
+++ b/spec/presenters/project_presenter_spec.rb
@@ -104,7 +104,7 @@ RSpec.describe ProjectPresenter do
expect(release).to be_truthy
expect(presenter.releases_anchor_data).to have_attributes(
is_link: true,
- label: a_string_including("#{project.releases.count}"),
+ label: a_string_including(project.releases.count.to_s),
link: presenter.project_releases_path(project)
)
end
@@ -295,7 +295,7 @@ RSpec.describe ProjectPresenter do
expect(release).to be_truthy
expect(presenter.releases_anchor_data).to have_attributes(
is_link: true,
- label: a_string_including("#{project.releases.count}"),
+ label: a_string_including(project.releases.count.to_s),
link: presenter.project_releases_path(project)
)
end
@@ -329,7 +329,7 @@ RSpec.describe ProjectPresenter do
it 'returns branches data' do
expect(presenter.branches_anchor_data).to have_attributes(
is_link: true,
- label: a_string_including("#{project.repository.branches.size}"),
+ label: a_string_including(project.repository.branches.size.to_s),
link: presenter.project_branches_path(project)
)
end
@@ -339,7 +339,7 @@ RSpec.describe ProjectPresenter do
it 'returns tags data' do
expect(presenter.tags_anchor_data).to have_attributes(
is_link: true,
- label: a_string_including("#{project.repository.tags.size}"),
+ label: a_string_including(project.repository.tags.size.to_s),
link: presenter.project_tags_path(project)
)
end
diff --git a/spec/rack_servers/configs/config.ru b/spec/rack_servers/configs/config.ru
index 63daeb9eec5..c832ee9b6ff 100644
--- a/spec/rack_servers/configs/config.ru
+++ b/spec/rack_servers/configs/config.ru
@@ -2,7 +2,7 @@
app = proc do |env|
if env['REQUEST_METHOD'] == 'GET'
- [200, {}, ["#{Process.pid}"]]
+ [200, {}, [Process.pid.to_s]]
else
Process.kill(env['QUERY_STRING'], Process.pid)
[200, {}, ['Bye!']]
diff --git a/spec/requests/admin/broadcast_messages_controller_spec.rb b/spec/requests/admin/broadcast_messages_controller_spec.rb
index 9101370d42d..eb29092845c 100644
--- a/spec/requests/admin/broadcast_messages_controller_spec.rb
+++ b/spec/requests/admin/broadcast_messages_controller_spec.rb
@@ -3,10 +3,25 @@
require 'spec_helper'
RSpec.describe Admin::BroadcastMessagesController, :enable_admin_mode do
+ let(:broadcast_message) { build(:broadcast_message) }
+ let(:broadcast_message_params) { broadcast_message.as_json(root: true, only: [:message, :starts_at, :ends_at]) }
+
+ let_it_be(:invalid_broadcast_message) { { broadcast_message: { message: '' } } }
+ let_it_be(:test_message) { 'you owe me a new acorn' }
+
before do
sign_in(create(:admin))
end
+ describe 'GET #index' do
+ it 'renders index template' do
+ get admin_broadcast_messages_path
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(response.body).to render_template(:index)
+ end
+ end
+
describe 'POST /preview' do
it 'renders preview partial' do
post preview_admin_broadcast_messages_path, params: { broadcast_message: { message: "Hello, world!" } }
@@ -15,4 +30,78 @@ RSpec.describe Admin::BroadcastMessagesController, :enable_admin_mode do
expect(response.body).to render_template(:_preview)
end
end
+
+ describe 'POST #create' do
+ context 'when format json' do
+ it 'persists the message and returns ok on success' do
+ post admin_broadcast_messages_path(format: :json), params: broadcast_message_params
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(Gitlab::Json.parse(response.body)['message']).to eq(broadcast_message.message)
+ end
+
+ it 'does not persist the message on failure' do
+ post admin_broadcast_messages_path(format: :json), params: invalid_broadcast_message
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(Gitlab::Json.parse(response.body)['errors']).to be_present
+ end
+ end
+
+ context 'when format html' do
+ it 'persists the message and redirects to broadcast_messages on success' do
+ post admin_broadcast_messages_path(format: :html), params: broadcast_message_params
+ expect(response).to redirect_to(admin_broadcast_messages_path)
+ end
+
+ it 'does not persist and renders the index page on failure' do
+ post admin_broadcast_messages_path(format: :html), params: invalid_broadcast_message
+ expect(response.body).to render_template(:index)
+ end
+ end
+ end
+
+ describe 'PATCH #update' do
+ context 'when format json' do
+ it 'persists the message and returns ok on success' do
+ broadcast_message.save!
+ patch admin_broadcast_message_path(format: :json, id: broadcast_message.id), params: {
+ broadcast_message: { message: test_message }
+ }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(Gitlab::Json.parse(response.body)['message']).to eq(test_message)
+ end
+
+ it 'does not persist the message on failure' do
+ broadcast_message.message = test_message
+ broadcast_message.save!
+ patch admin_broadcast_message_path(format: :json, id: broadcast_message.id), params: {
+ broadcast_message: { message: '' }
+ }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(Gitlab::Json.parse(response.body)['errors']).to be_present
+ end
+ end
+
+ context 'when format html' do
+ it 'persists the message and redirects to broadcast_messages on success' do
+ broadcast_message.save!
+ patch admin_broadcast_message_path(id: broadcast_message.id), params: {
+ broadcast_message: { message: test_message }
+ }
+
+ expect(response).to redirect_to(admin_broadcast_messages_path)
+ end
+
+ it 'does not persist and renders the edit page on failure' do
+ broadcast_message.message = test_message
+ broadcast_message.save!
+ patch admin_broadcast_message_path(id: broadcast_message.id), params: {
+ **invalid_broadcast_message
+ }
+
+ expect(response.body).to render_template(:edit)
+ 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 f89964411f8..4bdc44cb583 100644
--- a/spec/requests/api/admin/ci/variables_spec.rb
+++ b/spec/requests/api/admin/ci/variables_spec.rb
@@ -71,7 +71,8 @@ RSpec.describe ::API::Admin::Ci::Variables do
key: 'TEST_VARIABLE_2',
value: 'PROTECTED_VALUE_2',
protected: true,
- masked: true
+ masked: true,
+ raw: true
}
end.to change { ::Ci::InstanceVariable.count }.by(1)
@@ -80,9 +81,19 @@ RSpec.describe ::API::Admin::Ci::Variables do
expect(json_response['value']).to eq('PROTECTED_VALUE_2')
expect(json_response['protected']).to be_truthy
expect(json_response['masked']).to be_truthy
+ expect(json_response['raw']).to be_truthy
expect(json_response['variable_type']).to eq('env_var')
end
+ it 'masks the new value when logging' do
+ masked_params = { 'key' => 'VAR_KEY', 'value' => '[FILTERED]', 'protected' => 'true', 'masked' => 'true' }
+
+ expect(::API::API::LOGGER).to receive(:info).with(include(params: include(masked_params)))
+
+ post api("/admin/ci/variables", user),
+ 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),
@@ -98,6 +109,7 @@ RSpec.describe ::API::Admin::Ci::Variables do
expect(json_response['value']).to eq('VALUE_2')
expect(json_response['protected']).to be_falsey
expect(json_response['masked']).to be_falsey
+ expect(json_response['raw']).to be_falsey
expect(json_response['variable_type']).to eq('file')
end
@@ -153,7 +165,8 @@ RSpec.describe ::API::Admin::Ci::Variables do
variable_type: 'file',
value: 'VALUE_1_UP',
protected: true,
- masked: true
+ masked: true,
+ raw: true
}
expect(response).to have_gitlab_http_status(:ok)
@@ -161,6 +174,16 @@ RSpec.describe ::API::Admin::Ci::Variables do
expect(variable.reload).to be_protected
expect(json_response['variable_type']).to eq('file')
expect(json_response['masked']).to be_truthy
+ expect(json_response['raw']).to be_truthy
+ end
+
+ it 'masks the new value when logging' do
+ masked_params = { 'value' => '[FILTERED]', 'protected' => 'true', 'masked' => 'true' }
+
+ expect(::API::API::LOGGER).to receive(:info).with(include(params: include(masked_params)))
+
+ put api("/admin/ci/variables/#{variable.key}", admin),
+ params: { value: 'SENSITIVE', protected: true, masked: true }
end
it 'responds with 404 Not Found if requesting non-existing variable' do
diff --git a/spec/requests/api/alert_management_alerts_spec.rb b/spec/requests/api/alert_management_alerts_spec.rb
index 99293e5ae95..680a3883387 100644
--- a/spec/requests/api/alert_management_alerts_spec.rb
+++ b/spec/requests/api/alert_management_alerts_spec.rb
@@ -140,7 +140,7 @@ RSpec.describe API::AlertManagementAlerts do
project.send("add_#{user_role}", user)
end
- it_behaves_like "#{params[:expected_status]}"
+ it_behaves_like params[:expected_status].to_s
end
context 'file size too large' do
@@ -245,7 +245,7 @@ RSpec.describe API::AlertManagementAlerts do
project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) unless public_project
end
- it_behaves_like "#{params[:expected_status]}"
+ it_behaves_like params[:expected_status].to_s
end
end
@@ -293,7 +293,7 @@ RSpec.describe API::AlertManagementAlerts do
project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) unless public_project
end
- it_behaves_like "#{params[:expected_status]}"
+ it_behaves_like params[:expected_status].to_s
end
context 'when user has access' do
@@ -368,7 +368,7 @@ RSpec.describe API::AlertManagementAlerts do
project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) unless public_project
end
- it_behaves_like "#{params[:expected_status]}"
+ it_behaves_like params[:expected_status].to_s
end
context 'when user has access' do
diff --git a/spec/requests/api/boards_spec.rb b/spec/requests/api/boards_spec.rb
index 817e1324c7c..4d7256a1f03 100644
--- a/spec/requests/api/boards_spec.rb
+++ b/spec/requests/api/boards_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe API::Boards do
let_it_be(:non_member) { create(:user) }
let_it_be(:guest) { create(:user) }
let_it_be(:admin) { create(:user, :admin) }
- let_it_be(:board_parent, reload: true) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) }
+ let_it_be(:board_parent, reload: true) { create(:project, :public, creator_id: user.id, namespace: user.namespace) }
let_it_be(:dev_label) do
create(:label, title: 'Development', color: '#FFAABB', project: board_parent)
@@ -97,7 +97,7 @@ RSpec.describe API::Boards do
describe "POST /groups/:id/boards/:board_id/lists" do
let_it_be(:group) { create(:group) }
- let_it_be(:board_parent) { create(:group, parent: group ) }
+ let_it_be(:board_parent) { create(:group, parent: group) }
let(:url) { "/groups/#{board_parent.id}/boards/#{board.id}/lists" }
let_it_be(:board) { create(:board, group: board_parent) }
diff --git a/spec/requests/api/ci/job_artifacts_spec.rb b/spec/requests/api/ci/job_artifacts_spec.rb
index 2bf242f06ed..da9eb6b2216 100644
--- a/spec/requests/api/ci/job_artifacts_spec.rb
+++ b/spec/requests/api/ci/job_artifacts_spec.rb
@@ -389,8 +389,7 @@ RSpec.describe API::Ci::JobArtifacts do
end
end
- context 'when Google CDN is enabled' do
- let(:cdn_enabled) { true }
+ context 'when Google CDN is configured' do
let(:cdn_config) do
{
'provider' => 'Google',
@@ -401,7 +400,6 @@ RSpec.describe API::Ci::JobArtifacts do
end
before do
- stub_feature_flags(ci_job_artifacts_cdn: cdn_enabled)
stub_object_storage_uploader(config: Gitlab.config.artifacts.object_store,
uploader: JobArtifactUploader,
proxy_download: proxy_download,
@@ -418,18 +416,6 @@ RSpec.describe API::Ci::JobArtifacts do
expect(response.redirect_url).to start_with("https://cdn.example.org/#{artifact.file.path}")
end
-
- context 'when ci_job_artifacts_cdn feature flag is disabled' do
- let(:cdn_enabled) { false }
-
- it 'returns the file remote URL' do
- expect(Gitlab::ApplicationContext).to receive(:push).with(artifact_used_cdn: false).and_call_original
-
- subject
-
- expect(response).to redirect_to(artifact.file.url)
- end
- end
end
context 'authorized user' do
diff --git a/spec/requests/api/ci/jobs_spec.rb b/spec/requests/api/ci/jobs_spec.rb
index 0e17db516f4..c1b7461f444 100644
--- a/spec/requests/api/ci/jobs_spec.rb
+++ b/spec/requests/api/ci/jobs_spec.rb
@@ -606,6 +606,32 @@ RSpec.describe API::Ci::Jobs do
end
end
end
+
+ context 'when ci_debug_services is set to true' do
+ before_all do
+ create(:ci_instance_variable, key: 'CI_DEBUG_SERVICES', value: true)
+ end
+
+ where(:public_builds, :user_project_role, :expected_status) do
+ true | 'developer' | :ok
+ true | 'guest' | :forbidden
+ false | 'developer' | :ok
+ false | 'guest' | :forbidden
+ end
+
+ with_them do
+ before do
+ project.update!(public_builds: public_builds)
+ project.add_role(user, user_project_role)
+
+ get api("/projects/#{project.id}/jobs/#{job.id}/trace", api_user)
+ end
+
+ it 'renders successfully to authorized users' do
+ expect(response).to have_gitlab_http_status(expected_status)
+ end
+ end
+ end
end
describe 'POST /projects/:id/jobs/:job_id/cancel' do
diff --git a/spec/requests/api/ci/pipelines_spec.rb b/spec/requests/api/ci/pipelines_spec.rb
index 697fe16e222..c9d06f37c8b 100644
--- a/spec/requests/api/ci/pipelines_spec.rb
+++ b/spec/requests/api/ci/pipelines_spec.rb
@@ -940,7 +940,12 @@ RSpec.describe API::Ci::Pipelines do
subject
expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to contain_exactly({ "variable_type" => "env_var", "key" => "foo", "value" => "bar" })
+ expect(json_response).to contain_exactly({
+ "variable_type" => "env_var",
+ "key" => "foo",
+ "value" => "bar",
+ "raw" => false
+ })
end
end
end
@@ -961,7 +966,12 @@ RSpec.describe API::Ci::Pipelines do
subject
expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to contain_exactly({ "variable_type" => "env_var", "key" => "foo", "value" => "bar" })
+ expect(json_response).to contain_exactly({
+ "variable_type" => "env_var",
+ "key" => "foo",
+ "value" => "bar",
+ "raw" => false
+ })
end
end
diff --git a/spec/requests/api/ci/resource_groups_spec.rb b/spec/requests/api/ci/resource_groups_spec.rb
index 87df71f6096..2a67a3e4322 100644
--- a/spec/requests/api/ci/resource_groups_spec.rb
+++ b/spec/requests/api/ci/resource_groups_spec.rb
@@ -56,6 +56,31 @@ RSpec.describe API::Ci::ResourceGroups do
expect(Time.parse(json_response['updated_at'])).to be_like_time(resource_group.updated_at)
end
+ context 'when resource group key contains multiple dots' do
+ let!(:resource_group) { create(:ci_resource_group, project: project, key: 'test..test') }
+
+ it 'returns the resource group', :aggregate_failures do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['id']).to eq(resource_group.id)
+ expect(json_response['key']).to eq(resource_group.key)
+ end
+ end
+
+ context 'when resource group key contains a slash' do
+ let!(:resource_group) { create(:ci_resource_group, project: project, key: 'test/test') }
+ let(:key) { 'test%2Ftest' }
+
+ it 'returns the resource group', :aggregate_failures do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['id']).to eq(resource_group.id)
+ expect(json_response['key']).to eq(resource_group.key)
+ end
+ end
+
context 'when user is reporter' do
let(:user) { reporter }
@@ -98,6 +123,25 @@ RSpec.describe API::Ci::ResourceGroups do
expect(json_response[0]['status']).to eq(upcoming_processable.status)
end
+ context 'when resource group key contains a slash' do
+ let_it_be(:resource_group) { create(:ci_resource_group, project: project, key: 'test/test') }
+ let_it_be(:upcoming_processable) do
+ create(:ci_processable,
+ :waiting_for_resource,
+ resource_group: resource_group)
+ end
+
+ let(:key) { 'test%2Ftest' }
+
+ it 'returns the resource group', :aggregate_failures do
+ subject
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response[0]['id']).to eq(upcoming_processable.id)
+ expect(json_response[0]['name']).to eq(upcoming_processable.name)
+ end
+ end
+
context 'when user is reporter' do
let(:user) { reporter }
diff --git a/spec/requests/api/ci/runner/jobs_artifacts_spec.rb b/spec/requests/api/ci/runner/jobs_artifacts_spec.rb
index cd8c3dd2806..9af0541bd2c 100644
--- a/spec/requests/api/ci/runner/jobs_artifacts_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_artifacts_spec.rb
@@ -238,7 +238,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
context 'authorization token is invalid' do
it 'responds with forbidden' do
- authorize_artifacts(token: 'invalid', filesize: 100 )
+ authorize_artifacts(token: 'invalid', filesize: 100)
expect(response).to have_gitlab_http_status(:forbidden)
end
@@ -881,11 +881,11 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end
end
- shared_examples 'forbidden request' do
- it 'responds with forbidden' do
+ shared_examples 'unauthorized request' do
+ it 'responds with unauthorized' do
download_artifact
- expect(response).to have_gitlab_http_status(:forbidden)
+ expect(response).to have_gitlab_http_status(:unauthorized)
end
end
@@ -899,7 +899,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
job.success!
end
- it_behaves_like 'successful artifact download'
+ it_behaves_like 'unauthorized request'
end
end
@@ -916,7 +916,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
dependent_job.success!
end
- it_behaves_like 'forbidden request'
+ it_behaves_like 'unauthorized request'
end
end
@@ -942,7 +942,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
let(:token) { ci_build.token }
- it_behaves_like 'forbidden request'
+ it_behaves_like 'unauthorized request'
end
context 'when using a token from a cross pipeline build' do
@@ -981,19 +981,23 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
let!(:unrelated_ci_build) { create(:ci_build, :running, user: create(:user)) }
let(:token) { unrelated_ci_build.token }
- it_behaves_like 'forbidden request'
+ it 'responds with forbidden' do
+ download_artifact
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
end
context 'when using runnners token' do
let(:token) { job.project.runners_token }
- it_behaves_like 'forbidden request'
+ it_behaves_like 'unauthorized request'
end
context 'when using an invalid token' do
let(:token) { 'invalid-token' }
- it_behaves_like 'forbidden request'
+ it_behaves_like 'unauthorized request'
end
end
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 d4f734e7bdd..1cb4cc93ea5 100644
--- a/spec/requests/api/ci/runner/jobs_request_post_spec.rb
+++ b/spec/requests/api/ci/runner/jobs_request_post_spec.rb
@@ -462,7 +462,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
request_job info: { 'config' => { 'gpus' => 'all', 'ignored' => 'hello' } }
expect(response).to have_gitlab_http_status(:created)
- expect(runner.reload.config).to eq( { 'gpus' => 'all' } )
+ expect(runner.reload.config).to eq({ 'gpus' => 'all' })
end
it "sets the runner's ip_address" do
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 e1dc347f8dd..b8e4370fd46 100644
--- a/spec/requests/api/ci/runners_reset_registration_token_spec.rb
+++ b/spec/requests/api/ci/runners_reset_registration_token_spec.rb
@@ -118,7 +118,7 @@ RSpec.describe API::Ci::Runners do
end
include_context 'when authorized', 'group' do
- let_it_be(:user) { create_default(:group_member, :owner, user: create(:user), group: group ).user }
+ let_it_be(:user) { create_default(:group_member, :owner, user: create(:user), group: group).user }
def get_token
group.reload.runners_token
diff --git a/spec/requests/api/ci/runners_spec.rb b/spec/requests/api/ci/runners_spec.rb
index 69f26d3f257..dd9894f2972 100644
--- a/spec/requests/api/ci/runners_spec.rb
+++ b/spec/requests/api/ci/runners_spec.rb
@@ -399,7 +399,7 @@ RSpec.describe API::Ci::Runners do
it 'unrelated runner attribute on an existing runner with too many tags' 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}" } )
+ existing_invalid_shared_runner = build(:ci_runner, :instance, tag_list: (1..::Ci::Runner::TAG_LIST_MAX_LENGTH + 1).map { |i| "tag#{i}" })
existing_invalid_shared_runner.save!(validate: false)
active = existing_invalid_shared_runner.active
diff --git a/spec/requests/api/ci/secure_files_spec.rb b/spec/requests/api/ci/secure_files_spec.rb
index 0b8116d5e20..b0bca6e9125 100644
--- a/spec/requests/api/ci/secure_files_spec.rb
+++ b/spec/requests/api/ci/secure_files_spec.rb
@@ -143,6 +143,18 @@ RSpec.describe API::Ci::SecureFiles do
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['name']).to eq(secure_file.name)
+ expect(json_response['expires_at']).to be nil
+ expect(json_response['metadata']).to be nil
+ end
+
+ it 'returns project secure file details with metadata when supported' do
+ secure_file_with_metadata = create(:ci_secure_file_with_metadata, project: project)
+ get api("/projects/#{project.id}/secure_files/#{secure_file_with_metadata.id}", maintainer)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['name']).to eq(secure_file_with_metadata.name)
+ expect(json_response['expires_at']).to eq('2022-04-26T19:20:40.000Z')
+ expect(json_response['metadata'].keys).to match_array(%w[id issuer subject expires_at])
end
it 'responds with 404 Not Found if requesting non-existing secure file' do
diff --git a/spec/requests/api/ci/triggers_spec.rb b/spec/requests/api/ci/triggers_spec.rb
index 953dcb8a483..f9b7880a4c4 100644
--- a/spec/requests/api/ci/triggers_spec.rb
+++ b/spec/requests/api/ci/triggers_spec.rb
@@ -81,7 +81,7 @@ RSpec.describe API::Ci::Triggers do
end
it 'validates variables needs to be a map of key-valued strings' do
- post api("/projects/#{project.id}/trigger/pipeline"), params: options.merge(variables: { key: %w(1 2) }, ref: 'master')
+ post api("/projects/#{project.id}/trigger/pipeline"), params: options.merge(variables: { 'TRIGGER_KEY' => %w(1 2) }, ref: 'master')
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']).to eq('variables needs to be a map of key-valued strings')
diff --git a/spec/requests/api/ci/variables_spec.rb b/spec/requests/api/ci/variables_spec.rb
index 74ed8c1551d..cafb841995d 100644
--- a/spec/requests/api/ci/variables_spec.rb
+++ b/spec/requests/api/ci/variables_spec.rb
@@ -46,6 +46,7 @@ RSpec.describe API::Ci::Variables do
expect(json_response['value']).to eq(variable.value)
expect(json_response['protected']).to eq(variable.protected?)
expect(json_response['masked']).to eq(variable.masked?)
+ expect(json_response['raw']).to eq(variable.raw?)
expect(json_response['variable_type']).to eq('env_var')
end
@@ -115,7 +116,7 @@ RSpec.describe API::Ci::Variables do
context 'authorized user with proper permissions' do
it 'creates variable' do
expect do
- post api("/projects/#{project.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', protected: true, masked: true }
+ post api("/projects/#{project.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', protected: true, masked: true, raw: true }
end.to change { project.variables.count }.by(1)
expect(response).to have_gitlab_http_status(:created)
@@ -123,12 +124,22 @@ RSpec.describe API::Ci::Variables do
expect(json_response['value']).to eq('PROTECTED_VALUE_2')
expect(json_response['protected']).to be_truthy
expect(json_response['masked']).to be_truthy
+ expect(json_response['raw']).to be_truthy
expect(json_response['variable_type']).to eq('env_var')
end
+ it 'masks the new value when logging' do
+ masked_params = { 'key' => 'VAR_KEY', 'value' => '[FILTERED]', 'protected' => 'true', 'masked' => 'true' }
+
+ expect(::API::API::LOGGER).to receive(:info).with(include(params: include(masked_params)))
+
+ post api("/projects/#{project.id}/variables", user),
+ params: { key: 'VAR_KEY', value: 'SENSITIVE', protected: true, masked: true }
+ end
+
it 'creates variable with optional attributes' do
expect do
- post api("/projects/#{project.id}/variables", user), params: { variable_type: 'file', key: 'TEST_VARIABLE_2', value: 'VALUE_2' }
+ post api("/projects/#{project.id}/variables", user), params: { variable_type: 'file', key: 'TEST_VARIABLE_2', value: 'VALUE_2' }
end.to change { project.variables.count }.by(1)
expect(response).to have_gitlab_http_status(:created)
@@ -136,6 +147,7 @@ RSpec.describe API::Ci::Variables do
expect(json_response['value']).to eq('VALUE_2')
expect(json_response['protected']).to be_falsey
expect(json_response['masked']).to be_falsey
+ expect(json_response['raw']).to be_falsey
expect(json_response['variable_type']).to eq('file')
end
@@ -206,6 +218,15 @@ RSpec.describe API::Ci::Variables do
expect(updated_variable.variable_type).to eq('file')
end
+ it 'masks the new value when logging' do
+ masked_params = { 'value' => '[FILTERED]', 'protected' => 'true' }
+
+ expect(::API::API::LOGGER).to receive(:info).with(include(params: include(masked_params)))
+
+ put api("/projects/#{project.id}/variables/#{variable.key}", user),
+ params: { value: 'SENSITIVE', protected: true }
+ end
+
it 'responds with 404 Not Found if requesting non-existing variable' do
put api("/projects/#{project.id}/variables/non_existing_variable", user)
diff --git a/spec/requests/api/clusters/agent_tokens_spec.rb b/spec/requests/api/clusters/agent_tokens_spec.rb
index 2dca21ca6f1..a33bef53b14 100644
--- a/spec/requests/api/clusters/agent_tokens_spec.rb
+++ b/spec/requests/api/clusters/agent_tokens_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe API::Clusters::AgentTokens do
let_it_be(:agent) { create(:cluster_agent) }
let_it_be(:agent_token_one) { create(:cluster_agent_token, agent: agent) }
- let_it_be(:agent_token_two) { create(:cluster_agent_token, agent: agent) }
+ let_it_be(:revoked_agent_token) { create(:cluster_agent_token, :revoked, agent: agent) }
let_it_be(:project) { agent.project }
let_it_be(:user) { agent.created_by_user }
let_it_be(:unauthorized_user) { create(:user) }
@@ -17,7 +17,7 @@ RSpec.describe API::Clusters::AgentTokens do
describe 'GET /projects/:id/cluster_agents/:agent_id/tokens' do
context 'with authorized user' do
- it 'returns tokens' do
+ it 'returns tokens regardless of status' do
get api("/projects/#{project.id}/cluster_agents/#{agent.id}/tokens", user)
aggregate_failures "testing response" do
@@ -27,10 +27,16 @@ RSpec.describe API::Clusters::AgentTokens do
expect(json_response.count).to eq(2)
expect(json_response.first['name']).to eq(agent_token_one.name)
expect(json_response.first['agent_id']).to eq(agent.id)
- expect(json_response.second['name']).to eq(agent_token_two.name)
+ expect(json_response.second['name']).to eq(revoked_agent_token.name)
expect(json_response.second['agent_id']).to eq(agent.id)
end
end
+
+ it 'returns a not_found error if agent_id does not exist' do
+ get api("/projects/#{project.id}/cluster_agents/#{non_existing_record_id}/tokens", user)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
end
context 'with unauthorized user' do
diff --git a/spec/requests/api/dependency_proxy_spec.rb b/spec/requests/api/dependency_proxy_spec.rb
index a8617fcb0bf..7af4ed08cb8 100644
--- a/spec/requests/api/dependency_proxy_spec.rb
+++ b/spec/requests/api/dependency_proxy_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe API::DependencyProxy, api: true do
let_it_be(:user) { create(:user) }
- let_it_be(:blob) { create(:dependency_proxy_blob ) }
+ let_it_be(:blob) { create(:dependency_proxy_blob) }
let_it_be(:group, reload: true) { blob.group }
before do
diff --git a/spec/requests/api/deployments_spec.rb b/spec/requests/api/deployments_spec.rb
index 24e0e5d3180..8124080abea 100644
--- a/spec/requests/api/deployments_spec.rb
+++ b/spec/requests/api/deployments_spec.rb
@@ -201,7 +201,7 @@ RSpec.describe API::Deployments do
}
)
- expect(response).to have_gitlab_http_status(:internal_server_error)
+ expect(response).to have_gitlab_http_status(:bad_request)
end
it 'links any merged merge requests to the deployment', :sidekiq_inline do
@@ -325,7 +325,7 @@ RSpec.describe API::Deployments do
context 'as non member' do
it 'returns a 404 status code' do
post(
- api( "/projects/#{project.id}/deployments", non_member),
+ api("/projects/#{project.id}/deployments", non_member),
params: {
environment: 'production',
sha: '123',
diff --git a/spec/requests/api/features_spec.rb b/spec/requests/api/features_spec.rb
index d0334cf6dd2..85dafef569d 100644
--- a/spec/requests/api/features_spec.rb
+++ b/spec/requests/api/features_spec.rb
@@ -193,7 +193,7 @@ RSpec.describe API::Features, stub_feature_flags: false do
'state' => 'conditional',
'gates' => [
{ 'key' => 'boolean', 'value' => false },
- { 'key' => 'actors', 'value' => ["#{actor.class}:#{actor.id}"] }
+ { 'key' => 'actors', 'value' => [actor.flipper_id] }
],
'definition' => known_feature_flag_definition_hash
)
@@ -269,6 +269,20 @@ RSpec.describe API::Features, stub_feature_flags: false do
end
end
+ context 'when enabling for a repository by path' do
+ context 'when the repository exists' do
+ it_behaves_like 'enables the flag for the actor', :repository do
+ let_it_be(:actor) { create(:project).repository }
+ end
+ end
+
+ context 'when the repository does not exist' do
+ it_behaves_like 'does not enable the flag', :repository do
+ let(:actor_path) { 'not/a/repository' }
+ end
+ end
+ end
+
context 'with multiple users' do
let_it_be(:users) { create_list(:user, 3) }
@@ -361,6 +375,29 @@ RSpec.describe API::Features, stub_feature_flags: false do
end
end
+ context 'with multiple repository' do
+ let_it_be(:projects) { create_list(:project, 3) }
+
+ it_behaves_like 'creates an enabled feature for the specified entries' do
+ let(:gate_params) { { repository: projects.map { |p| p.repository.full_path }.join(',') } }
+ let(:expected_gate_params) { projects.map { |p| p.repository.flipper_id } }
+ end
+
+ context 'when empty value exists between comma' do
+ it_behaves_like 'creates an enabled feature for the specified entries' do
+ let(:gate_params) { { repository: "#{projects.first.repository.full_path},,,," } }
+ let(:expected_gate_params) { projects.first.repository.flipper_id }
+ end
+ end
+
+ context 'when one of the projects does not exist' do
+ it_behaves_like 'does not enable the flag', :project do
+ let(:actor_path) { "#{projects.first.repository.full_path},inexistent-entry" }
+ let(:expected_inexistent_path) { "inexistent-entry" }
+ end
+ end
+ end
+
it 'creates a feature with the given percentage of time if passed an integer' do
post api("/features/#{feature_name}", admin), params: { value: '50' }
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index e95a626b4aa..d4d3aace204 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe API::Files do
let_it_be(:inherited_reporter) { create(:user) }
let_it_be(:inherited_developer) { create(:user) }
- let!(:project) { create(:project, :repository, namespace: user.namespace ) }
+ let!(:project) { create(:project, :repository, namespace: user.namespace) }
let(:guest) { create(:user) { |u| project.add_guest(u) } }
let(:file_path) { 'files%2Fruby%2Fpopen%2Erb' }
let(:file_name) { 'popen.rb' }
@@ -935,7 +935,7 @@ RSpec.describe API::Files do
end
context 'and the repo is empty' do
- let!(:project) { create(:project_empty_repo, namespace: user.namespace ) }
+ let!(:project) { create(:project_empty_repo, namespace: user.namespace) }
it_behaves_like 'creates a new file in the project repo' do
let(:current_user) { user }
@@ -1253,4 +1253,35 @@ RSpec.describe API::Files do
expect(json_response['content']).to eq(put_params[:content])
end
end
+
+ describe 'POST /projects/:id/repository/files with text encoding' do
+ let(:file_path) { 'test%2Etext' }
+ let(:put_params) do
+ {
+ branch: 'master',
+ content: 'test',
+ commit_message: 'Text file',
+ encoding: 'text'
+ }
+ end
+
+ let(:get_params) do
+ {
+ ref: 'master'
+ }
+ end
+
+ before do
+ post api(route(file_path), user), params: put_params
+ end
+
+ it 'returns base64-encoded text file' do
+ get api(route(file_path), user), params: get_params
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response['file_path']).to eq(CGI.unescape(file_path))
+ expect(json_response['file_name']).to eq(CGI.unescape(file_path))
+ expect(Base64.decode64(json_response['content'])).to eq("test")
+ end
+ end
end
diff --git a/spec/requests/api/go_proxy_spec.rb b/spec/requests/api/go_proxy_spec.rb
index 7c44fddc303..5498ed6df13 100644
--- a/spec/requests/api/go_proxy_spec.rb
+++ b/spec/requests/api/go_proxy_spec.rb
@@ -16,12 +16,12 @@ RSpec.describe API::GoProxy do
let_it_be(:modules) do
commits = [
- create(:go_module_commit, :files, project: project, tag: 'v1.0.0', files: { 'README.md' => 'Hi' } ),
- create(:go_module_commit, :module, project: project, tag: 'v1.0.1' ),
- create(:go_module_commit, :package, project: project, tag: 'v1.0.2', path: 'pkg' ),
- create(:go_module_commit, :module, project: project, tag: 'v1.0.3', name: 'mod' ),
- create(:go_module_commit, :files, project: project, files: { 'y.go' => "package a\n" } ),
- create(:go_module_commit, :module, project: project, name: 'v2' ),
+ create(:go_module_commit, :files, project: project, tag: 'v1.0.0', files: { 'README.md' => 'Hi' }),
+ create(:go_module_commit, :module, project: project, tag: 'v1.0.1'),
+ create(:go_module_commit, :package, project: project, tag: 'v1.0.2', path: 'pkg'),
+ create(:go_module_commit, :module, project: project, tag: 'v1.0.3', name: 'mod'),
+ create(:go_module_commit, :files, project: project, files: { 'y.go' => "package a\n" }),
+ create(:go_module_commit, :module, project: project, name: 'v2'),
create(:go_module_commit, :files, project: project, tag: 'v2.0.0', files: { 'v2/x.go' => "package a\n" })
]
@@ -288,10 +288,10 @@ RSpec.describe API::GoProxy do
let_it_be(:base) { "#{Settings.build_gitlab_go_url}/#{project.full_path}" }
let_it_be(:modules) do
- create(:go_module_commit, :files, project: project, files: { 'a.go' => "package\a" } )
+ create(:go_module_commit, :files, project: project, files: { 'a.go' => "package\a" })
create(:go_module_commit, :files, project: project, tag: 'v1.0.0', files: { 'go.mod' => "module not/a/real/module\n" })
- create(:go_module_commit, :files, project: project, files: { 'v2/a.go' => "package a\n" } )
- create(:go_module_commit, :files, project: project, tag: 'v2.0.0', files: { 'v2/go.mod' => "module #{base}\n" } )
+ create(:go_module_commit, :files, project: project, files: { 'v2/a.go' => "package a\n" })
+ create(:go_module_commit, :files, project: project, tag: 'v2.0.0', files: { 'v2/go.mod' => "module #{base}\n" })
end
describe 'GET /projects/:id/packages/go/*module_name/@v/list' do
@@ -406,6 +406,19 @@ RSpec.describe API::GoProxy do
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
+
+ context 'with access to package registry for everyone' do
+ let_it_be(:user) { nil }
+
+ before do
+ project.reload.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC)
+ end
+
+ it_behaves_like 'a module version list resource', 'v1.0.1', 'v1.0.2', 'v1.0.3'
+ it_behaves_like 'a module version information resource', 'v1.0.1'
+ it_behaves_like 'a module file resource', 'v1.0.1'
+ it_behaves_like 'a module archive resource', 'v1.0.1', ['README.md', 'go.mod', 'a.go']
+ end
end
context 'with a public project' do
diff --git a/spec/requests/api/graphql/boards/board_list_issues_query_spec.rb b/spec/requests/api/graphql/boards/board_list_issues_query_spec.rb
index 484ddc3469b..9bed720c815 100644
--- a/spec/requests/api/graphql/boards/board_list_issues_query_spec.rb
+++ b/spec/requests/api/graphql/boards/board_list_issues_query_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe 'get board lists' do
let_it_be(:user) { create(:user) }
let_it_be(:unauth_user) { create(:user) }
- let_it_be(:project) { create(:project, creator_id: user.id, namespace: user.namespace ) }
+ let_it_be(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
let_it_be(:group) { create(:group, :private) }
let_it_be(:project_label) { create(:label, project: project, name: 'Development') }
let_it_be(:project_label2) { create(:label, project: project, name: 'Testing') }
@@ -21,6 +21,7 @@ RSpec.describe 'get board lists' do
let(:board_data) { graphql_data[board_parent_type]['boards']['nodes'][0] }
let(:lists_data) { board_data['lists']['nodes'][0] }
let(:issues_data) { lists_data['issues']['nodes'] }
+ let(:issue_params) { { filters: { label_name: label2.title, confidential: confidential }, first: 3 } }
def query(list_params = params)
graphql_query_for(
@@ -31,7 +32,7 @@ RSpec.describe 'get board lists' do
nodes {
lists {
nodes {
- issues(filters: {labelName: "#{label2.title}", confidential: #{confidential}}, first: 3) {
+ issues(#{attributes_to_graphql(issue_params)}) {
count
nodes {
#{all_graphql_fields_for('issues'.classify)}
@@ -77,18 +78,23 @@ RSpec.describe 'get board lists' do
end
context 'when user can read the board' do
- before do
+ before_all do
board_parent.add_reporter(user)
- post_graphql(query("id: \"#{global_id_of(label_list)}\""), current_user: user)
end
+ subject { post_graphql(query("id: \"#{global_id_of(label_list)}\""), current_user: user) }
+
it 'can access the issues', :aggregate_failures do
+ subject
+
# ties for relative positions are broken by id in ascending order by default
expect(issue_titles).to eq([issue2.title, issue1.title, issue3.title])
expect(issue_relative_positions).not_to include(nil)
end
it 'does not set the relative positions of the issues not being returned', :aggregate_failures do
+ subject
+
expect(issue_id).not_to include(issue6.id)
expect(issue3.relative_position).to be_nil
end
@@ -97,10 +103,36 @@ RSpec.describe 'get board lists' do
let(:confidential) { true }
it 'returns matching issue' do
+ subject
+
expect(issue_titles).to match_array([issue7.title])
expect(issue_relative_positions).not_to include(nil)
end
end
+
+ context 'when filtering by a unioned argument' do
+ let(:another_user) { create(:user) }
+ let(:issue_params) { { filters: { or: { assignee_usernames: [user.username, another_user.username] } } } }
+
+ it 'returns correctly filtered issues' do
+ issue1.assignee_ids = user.id
+ issue2.assignee_ids = another_user.id
+
+ subject
+
+ expect(issue_id).to contain_exactly(issue1.to_gid.to_s, issue2.to_gid.to_s)
+ end
+
+ context 'when feature flag is disabled' do
+ it 'returns an error' do
+ stub_feature_flags(or_issuable_queries: false)
+
+ subject
+
+ expect_graphql_errors_to_include("'or' arguments are only allowed when the `or_issuable_queries` feature flag is enabled.")
+ end
+ end
+ end
end
end
diff --git a/spec/requests/api/graphql/boards/board_lists_query_spec.rb b/spec/requests/api/graphql/boards/board_lists_query_spec.rb
index 6fe2e41cf35..ad7df5c9344 100644
--- a/spec/requests/api/graphql/boards/board_lists_query_spec.rb
+++ b/spec/requests/api/graphql/boards/board_lists_query_spec.rb
@@ -49,7 +49,7 @@ RSpec.describe 'get board lists' do
end
shared_examples 'group and project board lists query' do
- let!(:board) { create(:board, resource_parent: board_parent) }
+ let_it_be(:board) { create(:board, resource_parent: board_parent) }
context 'when the user does not have access to the board' do
it 'returns nil' do
@@ -107,16 +107,20 @@ RSpec.describe 'get board lists' do
end
context 'when querying for a single list' do
+ let_it_be(:label_list) { create(:list, board: board, label: label, position: 10) }
+ let_it_be(:issues) do
+ [
+ create(:issue, project: project, labels: [label, label2]),
+ create(:issue, project: project, labels: [label, label2], confidential: true),
+ create(:issue, project: project, labels: [label])
+ ]
+ end
+
before do
board_parent.add_reporter(user)
end
it 'returns the correct list with issue count for matching issue filters' do
- label_list = create(:list, board: board, label: label, position: 10)
- create(:issue, project: project, labels: [label, label2])
- create(:issue, project: project, labels: [label, label2], confidential: true)
- create(:issue, project: project, labels: [label])
-
post_graphql(
query(
id: global_id_of(label_list),
@@ -131,21 +135,56 @@ RSpec.describe 'get board lists' do
expect(list_node['issuesCount']).to eq 1
end
end
+
+ context 'when filtering by a unioned argument' do
+ let_it_be(:another_user) { create(:user) }
+
+ it 'returns correctly filtered issues' do
+ issues[0].assignee_ids = user.id
+ issues[1].assignee_ids = another_user.id
+
+ post_graphql(
+ query(
+ id: global_id_of(label_list),
+ issueFilters: { or: { assignee_usernames: [user.username, another_user.username] } }
+ ), current_user: user
+ )
+
+ expect(lists_data[0]['node']['issuesCount']).to eq 2
+ end
+
+ context 'when feature flag is disabled' do
+ it 'returns an error' do
+ stub_feature_flags(or_issuable_queries: false)
+
+ post_graphql(
+ query(
+ id: global_id_of(label_list),
+ issueFilters: { or: { assignee_usernames: [user.username, another_user.username] } }
+ ), current_user: user
+ )
+
+ expect_graphql_errors_to_include(
+ "'or' arguments are only allowed when the `or_issuable_queries` feature flag is enabled."
+ )
+ end
+ end
+ end
end
end
describe 'for a project' do
- let(:board_parent) { project }
- let(:label) { project_label }
- let(:label2) { project_label2 }
+ let_it_be(:board_parent) { project }
+ let_it_be(:label) { project_label }
+ let_it_be(:label2) { project_label2 }
it_behaves_like 'group and project board lists query'
end
describe 'for a group' do
- let(:board_parent) { group }
- let(:label) { group_label }
- let(:label2) { group_label2 }
+ let_it_be(:board_parent) { group }
+ let_it_be(:label) { group_label }
+ let_it_be(:label2) { group_label2 }
before do
allow(board_parent).to receive(:multiple_issue_boards_available?).and_return(false)
diff --git a/spec/requests/api/graphql/ci/jobs_spec.rb b/spec/requests/api/graphql/ci/jobs_spec.rb
index 47e3221c567..a161c5c98ed 100644
--- a/spec/requests/api/graphql/ci/jobs_spec.rb
+++ b/spec/requests/api/graphql/ci/jobs_spec.rb
@@ -109,7 +109,7 @@ RSpec.describe 'Query.project.pipeline' do
'name' => 'docker 1 2',
'needs' => { 'nodes' => [] },
'previousStageJobsOrNeeds' => { 'nodes' => [
- a_hash_including( 'name' => 'my test job' )
+ a_hash_including('name' => 'my test job')
] }
),
a_hash_including(
@@ -129,7 +129,7 @@ RSpec.describe 'Query.project.pipeline' do
'name' => 'rspec 2 2',
'needs' => { 'nodes' => [a_hash_including('name' => 'my test job')] },
'previousStageJobsOrNeeds' => { 'nodes' => [
- a_hash_including('name' => 'my test job' )
+ a_hash_including('name' => 'my test job')
] }
)
)
diff --git a/spec/requests/api/graphql/ci/pipelines_spec.rb b/spec/requests/api/graphql/ci/pipelines_spec.rb
index f471a152603..948704e8770 100644
--- a/spec/requests/api/graphql/ci/pipelines_spec.rb
+++ b/spec/requests/api/graphql/ci/pipelines_spec.rb
@@ -419,7 +419,7 @@ RSpec.describe 'Query.project(fullPath).pipelines' do
end
before do
- create(:ci_sources_pipeline, source_pipeline: upstream_pipeline, pipeline: pipeline )
+ create(:ci_sources_pipeline, source_pipeline: upstream_pipeline, pipeline: pipeline)
post_graphql(query, current_user: user)
end
@@ -441,10 +441,10 @@ RSpec.describe 'Query.project(fullPath).pipelines' do
pipeline_2 = create(:ci_pipeline, project: project, user: user)
upstream_pipeline_2 = create(:ci_pipeline, project: upstream_project, user: user)
- create(:ci_sources_pipeline, source_pipeline: upstream_pipeline_2, pipeline: pipeline_2 )
+ create(:ci_sources_pipeline, source_pipeline: upstream_pipeline_2, pipeline: pipeline_2)
pipeline_3 = create(:ci_pipeline, project: project, user: user)
upstream_pipeline_3 = create(:ci_pipeline, project: upstream_project, user: user)
- create(:ci_sources_pipeline, source_pipeline: upstream_pipeline_3, pipeline: pipeline_3 )
+ create(:ci_sources_pipeline, source_pipeline: upstream_pipeline_3, pipeline: pipeline_3)
expect do
post_graphql(query, current_user: second_user)
diff --git a/spec/requests/api/graphql/ci/runner_spec.rb b/spec/requests/api/graphql/ci/runner_spec.rb
index bd90753f9ad..94c0a3c41bd 100644
--- a/spec/requests/api/graphql/ci/runner_spec.rb
+++ b/spec/requests/api/graphql/ci/runner_spec.rb
@@ -104,7 +104,8 @@ RSpec.describe 'Query.runner(id)' do
'userPermissions' => {
'readRunner' => true,
'updateRunner' => true,
- 'deleteRunner' => true
+ 'deleteRunner' => true,
+ 'assignRunner' => true
}
)
expect(runner_data['tagList']).to match_array runner.tag_list
diff --git a/spec/requests/api/graphql/group/work_item_types_spec.rb b/spec/requests/api/graphql/group/work_item_types_spec.rb
index d6b0673e4f8..35090e2a89f 100644
--- a/spec/requests/api/graphql/group/work_item_types_spec.rb
+++ b/spec/requests/api/graphql/group/work_item_types_spec.rb
@@ -57,15 +57,4 @@ RSpec.describe 'getting a list of work item types for a group' do
expect(graphql_data).to eq('group' => nil)
end
end
-
- context 'when the work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- post_graphql(query, current_user: current_user)
- end
-
- it 'returns null' do
- expect(graphql_data.dig('group', 'workItemTypes')).to be_nil
- end
- end
end
diff --git a/spec/requests/api/graphql/issues_spec.rb b/spec/requests/api/graphql/issues_spec.rb
new file mode 100644
index 00000000000..8838ad78f72
--- /dev/null
+++ b/spec/requests/api/graphql/issues_spec.rb
@@ -0,0 +1,117 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'getting an issue list at root level' do
+ include GraphqlHelpers
+
+ let_it_be(:developer) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:group1) { create(:group).tap { |group| group.add_developer(developer) } }
+ let_it_be(:group2) { create(:group).tap { |group| group.add_developer(developer) } }
+ let_it_be(:project_a) { create(:project, :repository, :public, group: group1) }
+ let_it_be(:project_b) { create(:project, :repository, :private, group: group1) }
+ let_it_be(:project_c) { create(:project, :repository, :public, group: group2) }
+ let_it_be(:project_d) { create(:project, :repository, :private, group: group2) }
+ let_it_be(:early_milestone) { create(:milestone, project: project_d, due_date: 10.days.from_now) }
+ let_it_be(:late_milestone) { create(:milestone, project: project_c, due_date: 30.days.from_now) }
+ let_it_be(:priority1) { create(:label, project: project_c, priority: 1) }
+ let_it_be(:priority2) { create(:label, project: project_d, priority: 5) }
+ let_it_be(:priority3) { create(:label, project: project_a, priority: 10) }
+
+ let_it_be(:issue_a) { create(:issue, project: project_a, labels: [priority3]) }
+ let_it_be(:issue_b) { create(:issue, :with_alert, project: project_b, discussion_locked: true) }
+ let_it_be(:issue_c) do
+ create(
+ :issue,
+ project: project_c,
+ title: 'title matching issue plus',
+ labels: [priority1],
+ milestone: late_milestone
+ )
+ end
+
+ let_it_be(:issue_d) { create(:issue, :with_alert, project: project_d, discussion_locked: true, labels: [priority2]) }
+ let_it_be(:issue_e) { create(:issue, project: project_d, milestone: early_milestone) }
+
+ let(:issue_filter_params) { {} }
+
+ let(:fields) do
+ <<~QUERY
+ nodes {
+ #{all_graphql_fields_for('issues'.classify)}
+ }
+ QUERY
+ end
+
+ before_all do
+ group2.add_reporter(reporter)
+ end
+
+ context 'when the root_level_issues_query feature flag is disabled' do
+ before do
+ stub_feature_flags(root_level_issues_query: false)
+ end
+
+ it 'the field returns null' do
+ post_graphql(query, current_user: developer)
+
+ expect(graphql_data).to eq('issues' => nil)
+ end
+ end
+
+ it_behaves_like 'graphql issue list request spec' do
+ subject(:post_query) { post_graphql(query, current_user: current_user) }
+
+ let(:current_user) { developer }
+ let(:another_user) { reporter }
+ let(:issues_data) { graphql_data['issues']['nodes'] }
+ let(:issue_ids) { graphql_dig_at(issues_data, :id) }
+
+ # filters
+ let(:expected_negated_assignee_issues) { [issue_b, issue_c, issue_d, issue_e] }
+ let(:expected_unioned_assignee_issues) { [issue_a, issue_c] }
+ let(:voted_issues) { [issue_a, issue_c] }
+ let(:no_award_issues) { [issue_b, issue_d, issue_e] }
+ let(:locked_discussion_issues) { [issue_b, issue_d] }
+ let(:unlocked_discussion_issues) { [issue_a, issue_c, issue_e] }
+ let(:search_title_term) { 'matching issue' }
+ let(:title_search_issue) { issue_c }
+
+ # sorting
+ let(:data_path) { [:issues] }
+ let(:expected_severity_sorted_asc) { [issue_c, issue_a, issue_b, issue_e, issue_d] }
+ let(:expected_priority_sorted_asc) { [issue_e, issue_c, issue_d, issue_a, issue_b] }
+ let(:expected_priority_sorted_desc) { [issue_c, issue_e, issue_a, issue_d, issue_b] }
+
+ before_all do
+ issue_a.assignee_ids = developer.id
+ issue_c.assignee_ids = reporter.id
+
+ create(:award_emoji, :upvote, user: developer, awardable: issue_a)
+ create(:award_emoji, :upvote, user: developer, awardable: issue_c)
+
+ # severity sorting
+ create(:issuable_severity, issue: issue_a, severity: :unknown)
+ create(:issuable_severity, issue: issue_b, severity: :low)
+ create(:issuable_severity, issue: issue_d, severity: :critical)
+ create(:issuable_severity, issue: issue_e, severity: :high)
+ end
+
+ def pagination_query(params)
+ graphql_query_for(
+ :issues,
+ params,
+ "#{page_info} nodes { id }"
+ )
+ end
+ end
+
+ def query(params = issue_filter_params)
+ graphql_query_for(
+ :issues,
+ params,
+ fields
+ )
+ end
+end
diff --git a/spec/requests/api/graphql/metadata_query_spec.rb b/spec/requests/api/graphql/metadata_query_spec.rb
index 840bd7c018c..435e1b5b596 100644
--- a/spec/requests/api/graphql/metadata_query_spec.rb
+++ b/spec/requests/api/graphql/metadata_query_spec.rb
@@ -17,7 +17,8 @@ RSpec.describe 'getting project information' do
'enabled' => Gitlab::Kas.enabled?,
'version' => expected_kas_version,
'externalUrl' => expected_kas_external_url
- }
+ },
+ 'enterprise' => Gitlab.ee?
}
}
end
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 7cd39f93ae7..e81621209fb 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/remove_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe 'Removing an AwardEmoji' do
end
def create_award_emoji(user)
- create(:award_emoji, name: emoji_name, awardable: awardable, user: user )
+ create(:award_emoji, name: emoji_name, awardable: awardable, user: user)
end
shared_examples 'a mutation that does not destroy an AwardEmoji' do
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 7ddffa1ab0a..b151da72b55 100644
--- a/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
+++ b/spec/requests/api/graphql/mutations/award_emojis/toggle_spec.rb
@@ -32,7 +32,7 @@ RSpec.describe 'Toggling an AwardEmoji' do
end
def create_award_emoji(user)
- create(:award_emoji, name: emoji_name, awardable: awardable, user: user )
+ create(:award_emoji, name: emoji_name, awardable: awardable, user: user)
end
context 'when the user has permission' do
diff --git a/spec/requests/api/graphql/mutations/ci/pipeline_schedule_take_ownership_spec.rb b/spec/requests/api/graphql/mutations/ci/pipeline_schedule_take_ownership_spec.rb
new file mode 100644
index 00000000000..8dfbf20d00b
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/ci/pipeline_schedule_take_ownership_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'PipelineScheduleTakeOwnership' do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:owner) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: owner) }
+
+ let(:mutation) do
+ graphql_mutation(
+ :pipeline_schedule_take_ownership,
+ { id: pipeline_schedule_id },
+ <<-QL
+ errors
+ QL
+ )
+ end
+
+ let(:pipeline_schedule_id) { pipeline_schedule.to_global_id.to_s }
+
+ before_all do
+ project.add_maintainer(user)
+ end
+
+ it 'returns an error if the user is not allowed to take ownership of the schedule' do
+ post_graphql_mutation(mutation, current_user: create(:user))
+
+ expect(graphql_errors).not_to be_empty
+ end
+
+ it 'takes ownership of the schedule' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(graphql_errors).to be_nil
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb b/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb
index 6818ba33e74..54e63df96a6 100644
--- a/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb
+++ b/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb
@@ -87,7 +87,7 @@ RSpec.describe 'RunnersRegistrationTokenReset' do
include_context('when unauthorized', 'group')
include_context 'when authorized', 'group' do
- let_it_be(:user) { create_default(:group_member, :owner, user: create(:user), group: group ).user }
+ let_it_be(:user) { create_default(:group_member, :owner, user: create(:user), group: group).user }
def get_token
group.reload.runners_token
diff --git a/spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb b/spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb
index c4121cfed42..5a27d39ecbc 100644
--- a/spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb
+++ b/spec/requests/api/graphql/mutations/container_repository/destroy_spec.rb
@@ -33,11 +33,11 @@ RSpec.describe 'Destroying a container repository' do
end
shared_examples 'destroying the container repository' do
- it 'destroy the container repository' do
+ it 'marks the container repository as delete_scheduled' do
expect(::Packages::CreateEventService)
.to receive(:new).with(nil, user, event_name: :delete_repository, scope: :container).and_call_original
expect(DeleteContainerRepositoryWorker)
- .to receive(:perform_async).with(user.id, container_repository.id)
+ .not_to receive(:perform_async)
expect { subject }.to change { ::Packages::Event.count }.by(1)
@@ -80,6 +80,25 @@ RSpec.describe 'Destroying a container repository' do
it_behaves_like params[:shared_examples_name]
end
+
+ context 'with container_registry_delete_repository_with_cron_worker disabled' do
+ before do
+ project.add_maintainer(user)
+ stub_feature_flags(container_registry_delete_repository_with_cron_worker: false)
+ end
+
+ it 'enqueues a removal job' do
+ expect(::Packages::CreateEventService)
+ .to receive(:new).with(nil, user, event_name: :delete_repository, scope: :container).and_call_original
+ expect(DeleteContainerRepositoryWorker)
+ .to receive(:perform_async).with(user.id, container_repository.id)
+
+ expect { subject }.to change { ::Packages::Event.count }.by(1)
+
+ expect(container_repository_mutation_response).to match_schema('graphql/container_repository')
+ expect(container_repository_mutation_response['status']).to eq('DELETE_SCHEDULED')
+ end
+ end
end
context 'with invalid id' do
diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb
index 923e12a3c06..fc3b666dd3d 100644
--- a/spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/create_spec.rb
@@ -10,8 +10,16 @@ RSpec.describe 'Creating an incident timeline event' do
let_it_be(:incident) { create(:incident, project: project) }
let_it_be(:event_occurred_at) { Time.current }
let_it_be(:note) { 'demo note' }
+ let_it_be(:tag1) { create(:incident_management_timeline_event_tag, project: project, name: 'Tag 1') }
+ let_it_be(:tag2) { create(:incident_management_timeline_event_tag, project: project, name: 'Tag 2') }
+
+ let(:input) do
+ { incident_id: incident.to_global_id.to_s,
+ note: note,
+ occurred_at: event_occurred_at,
+ timeline_event_tag_names: [tag1.name] }
+ end
- let(:input) { { incident_id: incident.to_global_id.to_s, note: note, occurred_at: event_occurred_at } }
let(:mutation) do
graphql_mutation(:timeline_event_create, input) do
<<~QL
@@ -22,6 +30,7 @@ RSpec.describe 'Creating an incident timeline event' do
author { id username }
incident { id title }
note
+ timelineEventTags { nodes { name } }
editable
action
occurredAt
@@ -57,4 +66,25 @@ RSpec.describe 'Creating an incident timeline event' do
'occurredAt' => event_occurred_at.iso8601
)
end
+
+ context 'when note is more than 280 characters long' do
+ let_it_be(:note) { 'n' * 281 }
+
+ it_behaves_like 'timeline event mutation responds with validation error',
+ error_message: 'Timeline text is too long (maximum is 280 characters)'
+ end
+
+ context 'when timeline event tags are passed' do
+ it 'creates incident timeline event with tags', :aggregate_failures do
+ post_graphql_mutation(mutation, current_user: user)
+
+ timeline_event_response = mutation_response['timelineEvent']
+ tag_names = timeline_event_response['timelineEventTags']['nodes']
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(timeline_event_response).to include(
+ 'timelineEventTags' => { 'nodes' => tag_names }
+ )
+ end
+ end
end
diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
index 85eaec90f47..62eeecb3fb7 100644
--- a/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
+++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/promote_from_note_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe 'Promote an incident timeline event from a comment' do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
let_it_be(:incident) { create(:incident, project: project) }
- let_it_be(:comment) { create(:note, project: project, noteable: incident) }
+ let_it_be(:comment) { create(:note, project: project, noteable: incident, note: 'a' * 281) }
let(:input) { { note_id: comment.to_global_id.to_s } }
let(:mutation) do
diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb
index 1c4439cec6f..542d51b990f 100644
--- a/spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event/update_spec.rb
@@ -13,11 +13,12 @@ RSpec.describe 'Updating an incident timeline event' do
end
let(:occurred_at) { 1.minute.ago.iso8601 }
+ let(:note) { 'Updated note' }
let(:variables) do
{
id: timeline_event.to_global_id.to_s,
- note: 'Updated note',
+ note: note,
occurred_at: occurred_at
}
end
@@ -70,11 +71,18 @@ RSpec.describe 'Updating an incident timeline event' do
'id' => incident.to_global_id.to_s,
'title' => incident.title
},
- 'note' => 'Updated note',
+ 'note' => note,
'noteHtml' => timeline_event.note_html,
'occurredAt' => occurred_at,
'createdAt' => timeline_event.created_at.iso8601,
'updatedAt' => timeline_event.updated_at.iso8601
)
end
+
+ context 'when note is more than 280 characters long' do
+ let(:note) { 'n' * 281 }
+
+ it_behaves_like 'timeline event mutation responds with validation error',
+ error_message: 'Timeline text is too long (maximum is 280 characters)'
+ end
end
diff --git a/spec/requests/api/graphql/mutations/incident_management/timeline_event_tag/create_spec.rb b/spec/requests/api/graphql/mutations/incident_management/timeline_event_tag/create_spec.rb
new file mode 100644
index 00000000000..7476499d9da
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/incident_management/timeline_event_tag/create_spec.rb
@@ -0,0 +1,57 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Creating a timeline event tag' do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:name) { 'Test tag 1' }
+
+ let(:input) { { project_path: project.full_path, name: name } }
+ let(:mutation) do
+ graphql_mutation(:timeline_event_tag_create, input) do
+ <<~QL
+ clientMutationId
+ errors
+ timelineEventTag {
+ id
+ name
+ }
+ QL
+ end
+ end
+
+ let(:mutation_response) { graphql_mutation_response(:timeline_event_tag_create) }
+
+ context 'when user has permissions to create timeline event tag' do
+ before do
+ project.add_maintainer(user)
+ end
+
+ it 'creates timeline event tag', :aggregate_failures do
+ post_graphql_mutation(mutation, current_user: user)
+
+ timeline_event_tag_response = mutation_response['timelineEventTag']
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(timeline_event_tag_response).to include(
+ 'name' => name
+ )
+ end
+ end
+
+ context 'when user does not have permissions to create timeline event tag' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'raises error' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(mutation_response).to be_nil
+ expect_graphql_errors_to_include(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/mutations/issues/create_spec.rb b/spec/requests/api/graphql/mutations/issues/create_spec.rb
index 9345735afe4..a489b7424e8 100644
--- a/spec/requests/api/graphql/mutations/issues/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/issues/create_spec.rb
@@ -58,34 +58,15 @@ RSpec.describe 'Create an issue' do
input['type'] = 'TASK'
end
- context 'when work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
+ it 'creates an issue with TASK type' do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+ end.to change(Issue, :count).by(1)
- it 'creates an issue with the default ISSUE type' do
- expect do
- post_graphql_mutation(mutation, current_user: current_user)
- end.to change(Issue, :count).by(1)
+ created_issue = Issue.last
- created_issue = Issue.last
-
- expect(created_issue.work_item_type.base_type).to eq('issue')
- expect(created_issue.issue_type).to eq('issue')
- end
- end
-
- context 'when work_items feature flag is enabled' do
- it 'creates an issue with TASK type' do
- expect do
- post_graphql_mutation(mutation, current_user: current_user)
- end.to change(Issue, :count).by(1)
-
- created_issue = Issue.last
-
- expect(created_issue.work_item_type.base_type).to eq('task')
- expect(created_issue.issue_type).to eq('task')
- end
+ expect(created_issue.work_item_type.base_type).to eq('task')
+ expect(created_issue.issue_type).to eq('task')
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 e7f4917ddde..c6a980b5cef 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
@@ -71,19 +71,5 @@ RSpec.describe "Create a work item from a task in a work item's description" do
it_behaves_like 'has spam protection' do
let(:mutation_class) { ::Mutations::WorkItems::CreateFromTask }
end
-
- context 'when the work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it 'does nothing and returns and error' do
- expect do
- post_graphql_mutation(mutation, current_user: current_user)
- end.to not_change(WorkItem, :count)
-
- expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
- end
- end
end
end
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 8233821053f..be3917316c3 100644
--- a/spec/requests/api/graphql/mutations/work_items/create_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/create_spec.rb
@@ -154,17 +154,65 @@ RSpec.describe 'Create a work item' do
end
end
- context 'when the work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
+ context 'with milestone widget input' do
+ let(:widgets_response) { mutation_response['workItem']['widgets'] }
+ let(:fields) do
+ <<~FIELDS
+ workItem {
+ widgets {
+ type
+ ... on WorkItemWidgetMilestone {
+ milestone {
+ id
+ }
+ }
+ }
+ }
+ errors
+ FIELDS
end
- it 'does not create the work item and returns an error' do
- expect do
- post_graphql_mutation(mutation, current_user: current_user)
- end.to not_change(WorkItem, :count)
+ let(:mutation) { graphql_mutation(:workItemCreate, input.merge('projectPath' => project.full_path), fields) }
- expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
+ context 'when setting milestone on work item creation' do
+ let_it_be(:project_milestone) { create(:milestone, project: project) }
+ let_it_be(:group_milestone) { create(:milestone, project: project) }
+
+ 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 }
+ }
+ end
+
+ shared_examples "work item's milestone is set" do
+ it "sets the work item's milestone" 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(
+ {
+ 'type' => 'MILESTONE',
+ 'milestone' => { 'id' => milestone.to_global_id.to_s }
+ }
+ )
+ end
+ end
+
+ context 'when assigning a project milestone' do
+ it_behaves_like "work item's milestone is set" do
+ let(:milestone) { project_milestone }
+ end
+ end
+
+ context 'when assigning a group milestone' do
+ it_behaves_like "work item's milestone is set" do
+ let(:milestone) { group_milestone }
+ end
+ end
end
end
end
diff --git a/spec/requests/api/graphql/mutations/work_items/delete_spec.rb b/spec/requests/api/graphql/mutations/work_items/delete_spec.rb
index 14c8b757a57..0a84225a7ab 100644
--- a/spec/requests/api/graphql/mutations/work_items/delete_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/delete_spec.rb
@@ -31,19 +31,5 @@ RSpec.describe 'Delete a work item' do
expect(response).to have_gitlab_http_status(:success)
expect(mutation_response['project']).to include('id' => work_item.project.to_global_id.to_s)
end
-
- context 'when the work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it 'does not delete the work item' do
- expect do
- post_graphql_mutation(mutation, current_user: current_user)
- end.to not_change(WorkItem, :count)
-
- expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
- end
- end
end
end
diff --git a/spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb b/spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb
index e576d0ee7ef..c44939c8d54 100644
--- a/spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/delete_task_spec.rb
@@ -75,19 +75,5 @@ RSpec.describe "Delete a task in a work item's description" do
expect(mutation_response['errors']).to contain_exactly('Stale work item. Check lock version')
end
end
-
- context 'when the work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it 'does nothing and returns and error' do
- expect do
- post_graphql_mutation(mutation, current_user: current_user)
- end.to not_change(WorkItem, :count)
-
- expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
- end
- 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 6b0129c457f..96736457f26 100644
--- a/spec/requests/api/graphql/mutations/work_items/update_spec.rb
+++ b/spec/requests/api/graphql/mutations/work_items/update_spec.rb
@@ -5,8 +5,11 @@ require 'spec_helper'
RSpec.describe 'Update a work item' do
include GraphqlHelpers
- let_it_be(:project) { create(:project) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
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(:work_item_event) { 'CLOSE' }
@@ -543,6 +546,91 @@ RSpec.describe 'Update a work item' do
end
end
+ context 'when updating milestone' do
+ let_it_be(:project_milestone) { create(:milestone, project: project) }
+ let_it_be(:group_milestone) { create(:milestone, project: project) }
+
+ let(:input) { { 'milestoneWidget' => { 'milestoneId' => new_milestone&.to_global_id&.to_s } } }
+
+ let(:fields) do
+ <<~FIELDS
+ workItem {
+ widgets {
+ type
+ ... on WorkItemWidgetMilestone {
+ milestone {
+ id
+ }
+ }
+ }
+ }
+ errors
+ FIELDS
+ end
+
+ shared_examples "work item's milestone is updated" do
+ it "updates the work item's milestone" do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ work_item.reload
+ end.to change(work_item, :milestone).from(old_milestone).to(new_milestone)
+
+ expect(response).to have_gitlab_http_status(:success)
+ end
+ end
+
+ shared_examples "work item's milestone is not updated" do
+ it "ignores the update request" do
+ expect do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ work_item.reload
+ end.to not_change(work_item, :milestone)
+
+ expect(response).to have_gitlab_http_status(:success)
+ end
+ end
+
+ context 'when user cannot set work item metadata' do
+ let(:current_user) { guest }
+ let(:old_milestone) { nil }
+
+ it_behaves_like "work item's milestone is not updated" do
+ let(:new_milestone) { project_milestone }
+ end
+ end
+
+ context 'when user can set work item metadata' do
+ let(:current_user) { reporter }
+
+ context 'when assigning a project milestone' do
+ it_behaves_like "work item's milestone is updated" do
+ let(:old_milestone) { nil }
+ let(:new_milestone) { project_milestone }
+ end
+ end
+
+ context 'when assigning a group milestone' do
+ it_behaves_like "work item's milestone is updated" do
+ let(:old_milestone) { nil }
+ let(:new_milestone) { group_milestone }
+ end
+ end
+
+ context "when unsetting the work item's milestone" do
+ it_behaves_like "work item's milestone is updated" do
+ let(:old_milestone) { group_milestone }
+ let(:new_milestone) { nil }
+
+ before do
+ work_item.update!(milestone: old_milestone)
+ 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, name: 'some_test_case_name') }
let_it_be(:work_item) { create(:work_item, work_item_type: test_case, project: project) }
@@ -556,20 +644,5 @@ RSpec.describe 'Update a work item' do
it_behaves_like 'a mutation that returns top-level errors',
errors: ["Following widget keys are not supported by some_test_case_name type: [:hierarchy_widget]"]
end
-
- context 'when the work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it 'does not update the work item and returns and error' do
- expect do
- post_graphql_mutation(mutation, current_user: current_user)
- work_item.reload
- end.to not_change(work_item, :title)
-
- expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
- end
- end
end
end
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 32468a46ace..55285be5a5d 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
@@ -74,22 +74,6 @@ RSpec.describe 'Update a work item task' do
it_behaves_like 'has spam protection' do
let(:mutation_class) { ::Mutations::WorkItems::UpdateTask }
end
-
- context 'when the work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it 'does not update the task item and returns and error' do
- expect do
- post_graphql_mutation(mutation, current_user: current_user)
- work_item.reload
- task.reload
- end.to not_change(task, :title)
-
- expect(mutation_response['errors']).to contain_exactly('`work_items` feature flag disabled for this project')
- end
- end
end
context 'when user does not have permissions to update a work item' do
diff --git a/spec/requests/api/graphql/packages/package_spec.rb b/spec/requests/api/graphql/packages/package_spec.rb
index e9f82d66775..02a3206f587 100644
--- a/spec/requests/api/graphql/packages/package_spec.rb
+++ b/spec/requests/api/graphql/packages/package_spec.rb
@@ -206,5 +206,25 @@ RSpec.describe 'package details' do
expect(graphql_data_at(:package, :composer_config_repository_url)).to eq("localhost/#{group.id}")
end
end
+
+ context 'web_path' do
+ before do
+ subject
+ end
+
+ it 'returns web_path correctly' do
+ expect(graphql_data_at(:package, :_links, :web_path)).to eq("/#{project.full_path}/-/packages/#{composer_package.id}")
+ end
+
+ context 'with terraform module' do
+ let_it_be(:terraform_package) { create(:terraform_module_package, project: project) }
+
+ let(:package_global_id) { global_id_of(terraform_package) }
+
+ it 'returns web_path correctly' do
+ expect(graphql_data_at(:package, :_links, :web_path)).to eq("/#{project.full_path}/-/infrastructure_registry/#{terraform_package.id}")
+ end
+ end
+ end
end
end
diff --git a/spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb b/spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb
index cb5006ec8e4..a80f683ea93 100644
--- a/spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb
+++ b/spec/requests/api/graphql/project/branch_protections/merge_access_levels_spec.rb
@@ -3,107 +3,5 @@
require 'spec_helper'
RSpec.describe 'getting merge access levels for a branch protection' do
- include GraphqlHelpers
-
- let_it_be(:current_user) { create(:user) }
-
- let(:merge_access_level_data) { merge_access_levels_data[0] }
-
- let(:merge_access_levels_data) do
- graphql_data_at('project',
- 'branchRules',
- 'nodes',
- 0,
- 'branchProtection',
- 'mergeAccessLevels',
- 'nodes')
- end
-
- let(:project) { protected_branch.project }
-
- let(:merge_access_levels_count) { protected_branch.merge_access_levels.size }
-
- let(:variables) { { path: project.full_path } }
-
- let(:fields) { all_graphql_fields_for('MergeAccessLevel') }
-
- let(:query) do
- <<~GQL
- query($path: ID!) {
- project(fullPath: $path) {
- branchRules(first: 1) {
- nodes {
- branchProtection {
- mergeAccessLevels {
- nodes {
- #{fields}
- }
- }
- }
- }
- }
- }
- }
- GQL
- end
-
- context 'when the user does not have read_protected_branch abilities' do
- let_it_be(:protected_branch) { create(:protected_branch) }
-
- before do
- project.add_guest(current_user)
- post_graphql(query, current_user: current_user, variables: variables)
- end
-
- it_behaves_like 'a working graphql query'
-
- it { expect(merge_access_levels_data).not_to be_present }
- end
-
- shared_examples 'merge access request' do
- let(:merge_access) { protected_branch.merge_access_levels.first }
-
- before do
- project.add_maintainer(current_user)
- post_graphql(query, current_user: current_user, variables: variables)
- end
-
- it_behaves_like 'a working graphql query'
-
- it 'returns all merge access levels' do
- expect(merge_access_levels_data.size).to eq(merge_access_levels_count)
- end
-
- it 'includes access_level' do
- expect(merge_access_level_data['accessLevel'])
- .to eq(merge_access.access_level)
- end
-
- it 'includes access_level_description' do
- expect(merge_access_level_data['accessLevelDescription'])
- .to eq(merge_access.humanize)
- end
- end
-
- context 'when the user does have read_protected_branch abilities' do
- let(:merge_access) { protected_branch.merge_access_levels.first }
-
- context 'when no one has access' do
- let_it_be(:protected_branch) { create(:protected_branch, :no_one_can_merge) }
-
- it_behaves_like 'merge access request'
- end
-
- context 'when developers have access' do
- let_it_be(:protected_branch) { create(:protected_branch, :developers_can_merge) }
-
- it_behaves_like 'merge access request'
- end
-
- context 'when maintainers have access' do
- let_it_be(:protected_branch) { create(:protected_branch, :maintainers_can_merge) }
-
- it_behaves_like 'merge access request'
- end
- end
+ include_examples 'perform graphql requests for AccessLevel type objects', :merge
end
diff --git a/spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb b/spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb
index 59f9c7d61cb..cfdaf1096c3 100644
--- a/spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb
+++ b/spec/requests/api/graphql/project/branch_protections/push_access_levels_spec.rb
@@ -3,107 +3,5 @@
require 'spec_helper'
RSpec.describe 'getting push access levels for a branch protection' do
- include GraphqlHelpers
-
- let_it_be(:current_user) { create(:user) }
-
- let(:push_access_level_data) { push_access_levels_data[0] }
-
- let(:push_access_levels_data) do
- graphql_data_at('project',
- 'branchRules',
- 'nodes',
- 0,
- 'branchProtection',
- 'pushAccessLevels',
- 'nodes')
- end
-
- let(:project) { protected_branch.project }
-
- let(:push_access_levels_count) { protected_branch.push_access_levels.size }
-
- let(:variables) { { path: project.full_path } }
-
- let(:fields) { all_graphql_fields_for('PushAccessLevel'.classify) }
-
- let(:query) do
- <<~GQL
- query($path: ID!) {
- project(fullPath: $path) {
- branchRules(first: 1) {
- nodes {
- branchProtection {
- pushAccessLevels {
- nodes {
- #{fields}
- }
- }
- }
- }
- }
- }
- }
- GQL
- end
-
- context 'when the user does not have read_protected_branch abilities' do
- let_it_be(:protected_branch) { create(:protected_branch) }
-
- before do
- project.add_guest(current_user)
- post_graphql(query, current_user: current_user, variables: variables)
- end
-
- it_behaves_like 'a working graphql query'
-
- it { expect(push_access_levels_data).not_to be_present }
- end
-
- shared_examples 'push access request' do
- let(:push_access) { protected_branch.push_access_levels.first }
-
- before do
- project.add_maintainer(current_user)
- post_graphql(query, current_user: current_user, variables: variables)
- end
-
- it_behaves_like 'a working graphql query'
-
- it 'returns all push access levels' do
- expect(push_access_levels_data.size).to eq(push_access_levels_count)
- end
-
- it 'includes access_level' do
- expect(push_access_level_data['accessLevel'])
- .to eq(push_access.access_level)
- end
-
- it 'includes access_level_description' do
- expect(push_access_level_data['accessLevelDescription'])
- .to eq(push_access.humanize)
- end
- end
-
- context 'when the user does have read_protected_branch abilities' do
- let(:push_access) { protected_branch.push_access_levels.first }
-
- context 'when no one has access' do
- let_it_be(:protected_branch) { create(:protected_branch, :no_one_can_push) }
-
- it_behaves_like 'push access request'
- end
-
- context 'when developers have access' do
- let_it_be(:protected_branch) { create(:protected_branch, :developers_can_push) }
-
- it_behaves_like 'push access request'
- end
-
- context 'when maintainers have access' do
- let_it_be(:protected_branch) { create(:protected_branch, :maintainers_can_push) }
-
- it_behaves_like 'push access request'
- end
- end
+ include_examples 'perform graphql requests for AccessLevel type objects', :push
end
diff --git a/spec/requests/api/graphql/project/branch_rules_spec.rb b/spec/requests/api/graphql/project/branch_rules_spec.rb
index 1aaf0e9edc7..ed866305445 100644
--- a/spec/requests/api/graphql/project/branch_rules_spec.rb
+++ b/spec/requests/api/graphql/project/branch_rules_spec.rb
@@ -7,10 +7,9 @@ RSpec.describe 'getting list of branch rules for a project' do
let_it_be(:project) { create(:project, :repository, :public) }
let_it_be(:current_user) { create(:user) }
- let_it_be(:branch_name_a) { 'branch_name_a' }
- let_it_be(:branch_name_b) { 'wildcard-*' }
+ let_it_be(:branch_name_a) { TestEnv::BRANCH_SHA.each_key.first }
+ let_it_be(:branch_name_b) { 'diff-*' }
let_it_be(:branch_rules) { [branch_rule_a, branch_rule_b] }
-
let_it_be(:branch_rule_a) do
create(:protected_branch, project: project, name: branch_name_a)
end
@@ -21,7 +20,6 @@ RSpec.describe 'getting list of branch rules for a project' do
let(:branch_rules_data) { graphql_data_at('project', 'branchRules', 'edges') }
let(:variables) { { path: project.full_path } }
- # fields must use let as the all_graphql_fields_for also configures some spies
let(:fields) { all_graphql_fields_for('BranchRule') }
let(:query) do
<<~GQL
@@ -60,49 +58,124 @@ RSpec.describe 'getting list of branch rules for a project' do
context 'when the user does have read_protected_branch abilities' do
before do
project.add_maintainer(current_user)
- post_graphql(query, current_user: current_user, variables: variables)
end
- it_behaves_like 'a working graphql query'
+ describe 'queries' do
+ before do
+ # rubocop:disable RSpec/AnyInstanceOf
+ allow_any_instance_of(User).to receive(:update_tracked_fields!)
+ allow_any_instance_of(Users::ActivityService).to receive(:execute)
+ # rubocop:enable RSpec/AnyInstanceOf
+ allow_next_instance_of(Resolvers::ProjectResolver) do |resolver|
+ allow(resolver).to receive(:resolve)
+ .with(full_path: project.full_path)
+ .and_return(project)
+ end
+ allow(project.repository).to receive(:branch_names).and_call_original
+ allow(project.repository.gitaly_ref_client).to receive(:branch_names).and_call_original
+ end
+
+ it 'matching_branches_count avoids N+1 queries' do
+ query = <<~GQL
+ query($path: ID!) {
+ project(fullPath: $path) {
+ branchRules {
+ nodes {
+ matchingBranchesCount
+ }
+ }
+ }
+ }
+ GQL
+
+ control = ActiveRecord::QueryRecorder.new do
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ # Verify the response includes the field
+ expect_n_matching_branches_count_fields(2)
+
+ create(:protected_branch, project: project)
+ create(:protected_branch, name: '*', project: project)
+
+ expect do
+ post_graphql(query, current_user: current_user, variables: variables)
+ end.not_to exceed_all_query_limit(control)
+
+ expect(project.repository).to have_received(:branch_names).at_least(2).times
+ expect(project.repository.gitaly_ref_client).to have_received(:branch_names).once
- it 'returns branch rules data' do
- expect(branch_rules_data.dig(0, 'node', 'name')).to be_present
- expect(branch_rules_data.dig(0, 'node', 'isDefault')).to be(true).or be(false)
- expect(branch_rules_data.dig(0, 'node', 'branchProtection')).to be_present
- expect(branch_rules_data.dig(0, 'node', 'createdAt')).to be_present
- expect(branch_rules_data.dig(0, 'node', 'updatedAt')).to be_present
-
- expect(branch_rules_data.dig(1, 'node', 'name')).to be_present
- expect(branch_rules_data.dig(1, 'node', 'isDefault')).to be(true).or be(false)
- expect(branch_rules_data.dig(1, 'node', 'branchProtection')).to be_present
- expect(branch_rules_data.dig(1, 'node', 'createdAt')).to be_present
- expect(branch_rules_data.dig(1, 'node', 'updatedAt')).to be_present
+ expect_n_matching_branches_count_fields(4)
+ end
+
+ def expect_n_matching_branches_count_fields(count)
+ branch_rule_nodes = graphql_data_at('project', 'branchRules', 'nodes')
+ expect(branch_rule_nodes.count).to eq(count)
+ branch_rule_nodes.each do |node|
+ expect(node['matchingBranchesCount']).to be_present
+ end
+ end
end
- context 'when limiting the number of results' do
- let(:branch_rule_limit) { 1 }
- let(:variables) { { path: project.full_path, n: branch_rule_limit } }
- let(:next_variables) do
- { path: project.full_path, n: branch_rule_limit, cursor: last_cursor }
+ describe 'response' do
+ before do
+ post_graphql(query, current_user: current_user, variables: variables)
end
it_behaves_like 'a working graphql query'
- it 'returns pagination information' do
- expect(branch_rules_data.size).to eq(branch_rule_limit)
- expect(has_next_page).to be_truthy
- expect(has_prev_page).to be_falsey
- post_graphql(query, current_user: current_user, variables: next_variables)
- expect(branch_rules_data.size).to eq(branch_rule_limit)
- expect(has_next_page).to be_falsey
- expect(has_prev_page).to be_truthy
+ it 'includes all fields', :aggregate_failures do
+ # Responses will be sorted alphabetically. Branch names for this spec
+ # come from an external constant so we check which is first
+ br_a_idx = branch_name_a < branch_name_b ? 0 : 1
+ br_b_idx = 1 - br_a_idx
+
+ branch_rule_a_data = branch_rules_data.dig(br_a_idx, 'node')
+ branch_rule_b_data = branch_rules_data.dig(br_b_idx, 'node')
+
+ expect(branch_rule_a_data['name']).to eq(branch_name_a)
+ expect(branch_rule_a_data['isDefault']).to be(true).or be(false)
+ expect(branch_rule_a_data['branchProtection']).to be_present
+ expect(branch_rule_a_data['matchingBranchesCount']).to eq(1)
+ expect(branch_rule_a_data['createdAt']).to be_present
+ expect(branch_rule_a_data['updatedAt']).to be_present
+
+ wildcard_count = TestEnv::BRANCH_SHA.keys.count do |branch_name|
+ branch_name.starts_with?('diff-')
+ end
+ expect(branch_rule_b_data['name']).to eq(branch_name_b)
+ expect(branch_rule_b_data['isDefault']).to be(true).or be(false)
+ expect(branch_rule_b_data['branchProtection']).to be_present
+ expect(branch_rule_b_data['matchingBranchesCount']).to eq(wildcard_count)
+ expect(branch_rule_b_data['createdAt']).to be_present
+ expect(branch_rule_b_data['updatedAt']).to be_present
end
- context 'when no limit is provided' do
- let(:branch_rule_limit) { nil }
+ context 'when limiting the number of results' do
+ let(:branch_rule_limit) { 1 }
+ let(:variables) { { path: project.full_path, n: branch_rule_limit } }
+ let(:next_variables) do
+ { path: project.full_path, n: branch_rule_limit, cursor: last_cursor }
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns pagination information' do
+ expect(branch_rules_data.size).to eq(branch_rule_limit)
+ expect(has_next_page).to be_truthy
+ expect(has_prev_page).to be_falsey
+ post_graphql(query, current_user: current_user, variables: next_variables)
+ expect(branch_rules_data.size).to eq(branch_rule_limit)
+ expect(has_next_page).to be_falsey
+ expect(has_prev_page).to be_truthy
+ end
+
+ context 'when no limit is provided' do
+ let(:branch_rule_limit) { nil }
- it 'returns all branch_rules' do
- expect(branch_rules_data.size).to eq(branch_rules.size)
+ it 'returns all branch_rules' do
+ expect(branch_rules_data.size).to eq(branch_rules.size)
+ end
end
end
end
diff --git a/spec/requests/api/graphql/project/incident_management/timeline_events_spec.rb b/spec/requests/api/graphql/project/incident_management/timeline_events_spec.rb
index bcbb1f11d43..544d2d7bd95 100644
--- a/spec/requests/api/graphql/project/incident_management/timeline_events_spec.rb
+++ b/spec/requests/api/graphql/project/incident_management/timeline_events_spec.rb
@@ -48,6 +48,7 @@ RSpec.describe 'getting incident timeline events' do
note
noteHtml
promotedFromNote { id body }
+ timelineEventTags { nodes { name } }
editable
action
occurredAt
@@ -100,6 +101,7 @@ RSpec.describe 'getting incident timeline events' do
'id' => promoted_from_note.to_global_id.to_s,
'body' => promoted_from_note.note
},
+ 'timelineEventTags' => { 'nodes' => [] },
'editable' => true,
'action' => timeline_event.action,
'occurredAt' => timeline_event.occurred_at.iso8601,
@@ -108,6 +110,47 @@ RSpec.describe 'getting incident timeline events' do
)
end
+ context 'when timelineEvent tags are linked' do
+ let_it_be(:tag1) { create(:incident_management_timeline_event_tag, project: project, name: 'Tag 1') }
+ let_it_be(:tag2) { create(:incident_management_timeline_event_tag, project: project, name: 'Tag 2') }
+ let_it_be(:timeline_event_tag_link) do
+ create(:incident_management_timeline_event_tag_link,
+ timeline_event: timeline_event,
+ timeline_event_tag: tag1)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns the set tags' do
+ expect(timeline_events.first['timelineEventTags']['nodes'].first['name']).to eq(tag1.name)
+ end
+
+ context 'when different timeline events are loaded' do
+ it 'avoids N+1 queries' do
+ control = ActiveRecord::QueryRecorder.new do
+ post_graphql(query, current_user: current_user)
+ end
+
+ new_event = create(:incident_management_timeline_event,
+ incident: incident,
+ project: project,
+ updated_by_user: updated_by_user,
+ promoted_from_note: promoted_from_note,
+ note: "Referencing #{issue.to_reference(full: true)} - Full URL #{issue_url}"
+ )
+
+ create(:incident_management_timeline_event_tag_link,
+ timeline_event: new_event,
+ timeline_event_tag: tag2
+ )
+
+ expect(incident.incident_management_timeline_events.length).to eq(3)
+ expect(post_graphql(query, current_user: current_user)).not_to exceed_query_limit(control)
+ expect(timeline_events.count).to eq(3)
+ end
+ end
+ end
+
context 'when filtering by id' do
let(:params) { { incident_id: incident.to_global_id.to_s, id: timeline_event.to_global_id.to_s } }
diff --git a/spec/requests/api/graphql/project/issues_spec.rb b/spec/requests/api/graphql/project/issues_spec.rb
index 3b8beb4f798..214165cb171 100644
--- a/spec/requests/api/graphql/project/issues_spec.rb
+++ b/spec/requests/api/graphql/project/issues_spec.rb
@@ -8,84 +8,74 @@ RSpec.describe 'getting an issue list for a project' do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, :repository, :public, group: group) }
let_it_be(:current_user) { create(:user) }
- let_it_be(:issue_a, reload: true) { create(:issue, project: project, discussion_locked: true) }
- let_it_be(:issue_b, reload: true) { create(:issue, :with_alert, project: project) }
- let_it_be(:issues, reload: true) { [issue_a, issue_b] }
+ let_it_be(:another_user) { create(:user).tap { |u| group.add_reporter(u) } }
+ let_it_be(:early_milestone) { create(:milestone, project: project, due_date: 10.days.from_now) }
+ let_it_be(:late_milestone) { create(:milestone, project: project, due_date: 30.days.from_now) }
+ let_it_be(:priority1) { create(:label, project: project, priority: 1) }
+ let_it_be(:priority2) { create(:label, project: project, priority: 5) }
+ let_it_be(:priority3) { create(:label, project: project, priority: 10) }
+
+ let_it_be(:issue_a, reload: true) { create(:issue, project: project, discussion_locked: true, labels: [priority3]) }
+ let_it_be(:issue_b, reload: true) { create(:issue, :with_alert, project: project, title: 'title matching issue i') }
+ let_it_be(:issue_c) { create(:issue, project: project, labels: [priority1], milestone: late_milestone) }
+ let_it_be(:issue_d) { create(:issue, project: project, labels: [priority2]) }
+ let_it_be(:issue_e) { create(:issue, project: project, milestone: early_milestone) }
+ let_it_be(:issues, reload: true) { [issue_a, issue_b, issue_c, issue_d, issue_e] }
let(:issue_a_gid) { issue_a.to_global_id.to_s }
let(:issue_b_gid) { issue_b.to_global_id.to_s }
- let(:issues_data) { graphql_data['project']['issues']['edges'] }
+ let(:issues_data) { graphql_data['project']['issues']['nodes'] }
let(:issue_filter_params) { {} }
let(:fields) do
<<~QUERY
- edges {
- node {
- #{all_graphql_fields_for('issues'.classify)}
- }
+ nodes {
+ #{all_graphql_fields_for('issues'.classify)}
}
QUERY
end
- it_behaves_like 'a working graphql query' do
- before do
- post_graphql(query, current_user: current_user)
- end
- end
-
- it 'includes a web_url' do
- post_graphql(query, current_user: current_user)
-
- expect(issues_data[0]['node']['webUrl']).to be_present
- end
-
- it 'includes discussion locked' do
- post_graphql(query, current_user: current_user)
-
- expect(issues_data[0]['node']['discussionLocked']).to eq(false)
- expect(issues_data[1]['node']['discussionLocked']).to eq(true)
- end
-
- context 'when both assignee_username filters are provided' do
- let(:issue_filter_params) { { assignee_username: current_user.username, assignee_usernames: [current_user.username] } }
-
- it 'returns a mutually exclusive param error' do
- post_graphql(query, current_user: current_user)
-
- expect_graphql_errors_to_include('only one of [assigneeUsernames, assigneeUsername] arguments is allowed at the same time.')
- end
- end
-
- context 'filtering by my_reaction_emoji' do
- using RSpec::Parameterized::TableSyntax
-
- let_it_be(:upvote_award) { create(:award_emoji, :upvote, user: current_user, awardable: issue_a) }
-
- where(:value, :gids) do
- 'thumbsup' | lazy { [issue_a_gid] }
- 'ANY' | lazy { [issue_a_gid] }
- 'any' | lazy { [issue_a_gid] }
- 'AnY' | lazy { [issue_a_gid] }
- 'NONE' | lazy { [issue_b_gid] }
- 'thumbsdown' | lazy { [] }
+ # All new specs should be added to the shared example if the change also
+ # affects the `issues` query at the root level of the API.
+ # Shared example also used in spec/requests/api/graphql/issues_spec.rb
+ it_behaves_like 'graphql issue list request spec' do
+ subject(:post_query) { post_graphql(query, current_user: current_user) }
+
+ # filters
+ let(:expected_negated_assignee_issues) { [issue_b, issue_c, issue_d, issue_e] }
+ let(:expected_unioned_assignee_issues) { [issue_a, issue_b] }
+ let(:voted_issues) { [issue_a] }
+ let(:no_award_issues) { [issue_b, issue_c, issue_d, issue_e] }
+ let(:locked_discussion_issues) { [issue_a] }
+ let(:unlocked_discussion_issues) { [issue_b, issue_c, issue_d, issue_e] }
+ let(:search_title_term) { 'matching issue' }
+ let(:title_search_issue) { issue_b }
+
+ # sorting
+ let(:data_path) { [:project, :issues] }
+ let(:expected_severity_sorted_asc) { [issue_c, issue_a, issue_b, issue_e, issue_d] }
+ let(:expected_priority_sorted_asc) { [issue_e, issue_c, issue_d, issue_a, issue_b] }
+ let(:expected_priority_sorted_desc) { [issue_c, issue_e, issue_a, issue_d, issue_b] }
+
+ before_all do
+ issue_a.assignee_ids = current_user.id
+ issue_b.assignee_ids = another_user.id
+
+ create(:award_emoji, :upvote, user: current_user, awardable: issue_a)
+
+ # severity sorting
+ create(:issuable_severity, issue: issue_a, severity: :unknown)
+ create(:issuable_severity, issue: issue_b, severity: :low)
+ create(:issuable_severity, issue: issue_d, severity: :critical)
+ create(:issuable_severity, issue: issue_e, severity: :high)
end
- with_them do
- let(:issue_filter_params) { { my_reaction_emoji: value } }
-
- it 'returns correctly filtered issues' do
- post_graphql(query, current_user: current_user)
-
- expect(issues_ids).to eq(gids)
- end
- end
- end
-
- context 'when filtering by search' do
- it_behaves_like 'query with a search term' do
- let(:issuable_data) { issues_data }
- let(:user) { current_user }
- let_it_be(:issuable) { create(:issue, project: project, description: 'bar') }
+ def pagination_query(params)
+ graphql_query_for(
+ :project,
+ { full_path: project.full_path },
+ query_graphql_field(:issues, params, "#{page_info} nodes { id }")
+ )
end
end
@@ -155,10 +145,10 @@ RSpec.describe 'getting an issue list for a project' do
it 'returns issues without confidential issues' do
post_graphql(query, current_user: current_user)
- expect(issues_data.size).to eq(2)
+ expect(issues_data.size).to eq(5)
issues_data.each do |issue|
- expect(issue.dig('node', 'confidential')).to eq(false)
+ expect(issue['confidential']).to eq(false)
end
end
@@ -178,7 +168,7 @@ RSpec.describe 'getting an issue list for a project' do
it 'returns correctly filtered issues' do
post_graphql(query, current_user: current_user)
- expect(issues_ids).to contain_exactly(issue_a_gid, issue_b_gid)
+ expect(issue_ids).to match_array(issues.map { |i| i.to_gid.to_s })
end
end
end
@@ -191,13 +181,13 @@ RSpec.describe 'getting an issue list for a project' do
it 'returns issues with confidential issues' do
post_graphql(query, current_user: current_user)
- expect(issues_data.size).to eq(3)
+ expect(issues_data.size).to eq(6)
confidentials = issues_data.map do |issue|
- issue.dig('node', 'confidential')
+ issue['confidential']
end
- expect(confidentials).to eq([true, false, false])
+ expect(confidentials).to contain_exactly(true, false, false, false, false, false)
end
context 'filtering for confidential issues' do
@@ -206,7 +196,7 @@ RSpec.describe 'getting an issue list for a project' do
it 'returns correctly filtered issues' do
post_graphql(query, current_user: current_user)
- expect(issues_ids).to contain_exactly(confidential_issue_gid)
+ expect(issue_ids).to contain_exactly(confidential_issue_gid)
end
end
@@ -216,7 +206,7 @@ RSpec.describe 'getting an issue list for a project' do
it 'returns correctly filtered issues' do
post_graphql(query, current_user: current_user)
- expect(issues_ids).to contain_exactly(issue_a_gid, issue_b_gid)
+ expect(issue_ids).to match_array([issue_a, issue_b, issue_c, issue_d, issue_e].map { |i| i.to_gid.to_s })
end
end
end
@@ -238,37 +228,7 @@ RSpec.describe 'getting an issue list for a project' do
data.map { |issue| issue['iid'].to_i }
end
- context 'when sorting by severity' do
- let_it_be(:severty_issue1) { create(:issue, project: sort_project) }
- let_it_be(:severty_issue2) { create(:issue, project: sort_project) }
- let_it_be(:severty_issue3) { create(:issue, project: sort_project) }
- let_it_be(:severty_issue4) { create(:issue, project: sort_project) }
- let_it_be(:severty_issue5) { create(:issue, project: sort_project) }
-
- before(:all) do
- create(:issuable_severity, issue: severty_issue1, severity: :unknown)
- create(:issuable_severity, issue: severty_issue2, severity: :low)
- create(:issuable_severity, issue: severty_issue4, severity: :critical)
- create(:issuable_severity, issue: severty_issue5, severity: :high)
- end
-
- context 'when ascending' do
- it_behaves_like 'sorted paginated query' do
- let(:sort_param) { :SEVERITY_ASC }
- let(:first_param) { 2 }
- let(:all_records) { [severty_issue3.iid, severty_issue1.iid, severty_issue2.iid, severty_issue5.iid, severty_issue4.iid] }
- end
- end
-
- context 'when descending' do
- it_behaves_like 'sorted paginated query' do
- let(:sort_param) { :SEVERITY_DESC }
- let(:first_param) { 2 }
- let(:all_records) { [severty_issue4.iid, severty_issue5.iid, severty_issue2.iid, severty_issue1.iid, severty_issue3.iid] }
- end
- end
- end
-
+ # rubocop:disable RSpec/MultipleMemoizedHelpers
context 'when sorting by due date' do
let_it_be(:due_issue1) { create(:issue, project: sort_project, due_date: 3.days.from_now) }
let_it_be(:due_issue2) { create(:issue, project: sort_project, due_date: nil) }
@@ -314,41 +274,6 @@ RSpec.describe 'getting an issue list for a project' do
end
end
- context 'when sorting by priority' do
- let_it_be(:on_project) { { project: sort_project } }
- let_it_be(:early_milestone) { create(:milestone, **on_project, due_date: 10.days.from_now) }
- let_it_be(:late_milestone) { create(:milestone, **on_project, due_date: 30.days.from_now) }
- let_it_be(:priority_1) { create(:label, **on_project, priority: 1) }
- let_it_be(:priority_2) { create(:label, **on_project, priority: 5) }
- let_it_be(:priority_issue1) { create(:issue, **on_project, labels: [priority_1], milestone: late_milestone) }
- let_it_be(:priority_issue2) { create(:issue, **on_project, labels: [priority_2]) }
- let_it_be(:priority_issue3) { create(:issue, **on_project, milestone: early_milestone) }
- let_it_be(:priority_issue4) { create(:issue, **on_project) }
-
- context 'when ascending' do
- it_behaves_like 'sorted paginated query' do
- let(:sort_param) { :PRIORITY_ASC }
- let(:first_param) { 2 }
- let(:all_records) do
- [
- priority_issue3.iid, priority_issue1.iid,
- priority_issue2.iid, priority_issue4.iid
- ]
- end
- end
- end
-
- context 'when descending' do
- it_behaves_like 'sorted paginated query' do
- let(:sort_param) { :PRIORITY_DESC }
- let(:first_param) { 2 }
- let(:all_records) do
- [priority_issue1.iid, priority_issue3.iid, priority_issue2.iid, priority_issue4.iid]
- end
- end
- end
- end
-
context 'when sorting by label priority' do
let_it_be(:label1) { create(:label, project: sort_project, priority: 1) }
let_it_be(:label2) { create(:label, project: sort_project, priority: 5) }
@@ -374,6 +299,7 @@ RSpec.describe 'getting an issue list for a project' do
end
end
end
+ # rubocop:enable RSpec/MultipleMemoizedHelpers
context 'when sorting by milestone due date' do
let_it_be(:early_milestone) { create(:milestone, project: sort_project, due_date: 10.days.from_now) }
@@ -403,14 +329,17 @@ RSpec.describe 'getting an issue list for a project' do
context 'when fetching alert management alert' do
let(:fields) do
<<~QUERY
- edges {
- node {
+ nodes {
iid
alertManagementAlert {
title
}
+ alertManagementAlerts {
+ nodes {
+ title
+ }
+ }
}
- }
QUERY
end
@@ -430,11 +359,22 @@ RSpec.describe 'getting an issue list for a project' do
it 'returns the alert data' do
post_graphql(query, current_user: current_user)
- alert_titles = issues_data.map { |issue| issue.dig('node', 'alertManagementAlert', 'title') }
+ alert_titles = issues_data.map { |issue| issue.dig('alertManagementAlert', 'title') }
expected_titles = issues.map { |issue| issue.alert_management_alert&.title }
expect(alert_titles).to contain_exactly(*expected_titles)
end
+
+ it 'returns the alerts data' do
+ post_graphql(query, current_user: current_user)
+
+ alert_titles = issues_data.map { |issue| issue.dig('alertManagementAlerts', 'nodes') }
+ expected_titles = issues.map do |issue|
+ issue.alert_management_alerts.map { |alert| { 'title' => alert.title } }
+ end
+
+ expect(alert_titles).to contain_exactly(*expected_titles)
+ end
end
context 'when fetching customer_relations_contacts' do
@@ -469,13 +409,11 @@ RSpec.describe 'getting an issue list for a project' do
context 'when fetching labels' do
let(:fields) do
<<~QUERY
- edges {
- node {
- id
- labels {
- nodes {
- id
- }
+ nodes {
+ id
+ labels {
+ nodes {
+ id
}
}
}
@@ -491,8 +429,8 @@ RSpec.describe 'getting an issue list for a project' do
end
def response_label_ids(response_data)
- response_data.map do |edge|
- edge['node']['labels']['nodes'].map { |u| u['id'] }
+ response_data.map do |node|
+ node['labels']['nodes'].map { |u| u['id'] }
end.flatten
end
@@ -502,7 +440,7 @@ RSpec.describe 'getting an issue list for a project' do
it 'avoids N+1 queries', :aggregate_failures do
control = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) }
- expect(issues_data.count).to eq(2)
+ expect(issues_data.count).to eq(5)
expect(response_label_ids(issues_data)).to match_array(labels_as_global_ids(issues))
new_issues = issues + [create(:issue, project: project, labels: [create(:label, project: project)])]
@@ -510,8 +448,8 @@ RSpec.describe 'getting an issue list for a project' do
expect { post_graphql(query, current_user: current_user) }.not_to exceed_query_limit(control)
# graphql_data is memoized (see spec/support/helpers/graphql_helpers.rb)
# so we have to parse the body ourselves the second time
- issues_data = Gitlab::Json.parse(response.body)['data']['project']['issues']['edges']
- expect(issues_data.count).to eq(3)
+ issues_data = Gitlab::Json.parse(response.body)['data']['project']['issues']['nodes']
+ expect(issues_data.count).to eq(6)
expect(response_label_ids(issues_data)).to match_array(labels_as_global_ids(new_issues))
end
end
@@ -519,13 +457,11 @@ RSpec.describe 'getting an issue list for a project' do
context 'when fetching assignees' do
let(:fields) do
<<~QUERY
- edges {
- node {
- id
- assignees {
- nodes {
- id
- }
+ nodes {
+ id
+ assignees {
+ nodes {
+ id
}
}
}
@@ -541,8 +477,8 @@ RSpec.describe 'getting an issue list for a project' do
end
def response_assignee_ids(response_data)
- response_data.map do |edge|
- edge['node']['assignees']['nodes'].map { |node| node['id'] }
+ response_data.map do |node|
+ node['assignees']['nodes'].map { |node| node['id'] }
end.flatten
end
@@ -552,7 +488,7 @@ RSpec.describe 'getting an issue list for a project' do
it 'avoids N+1 queries', :aggregate_failures do
control = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) }
- expect(issues_data.count).to eq(2)
+ expect(issues_data.count).to eq(5)
expect(response_assignee_ids(issues_data)).to match_array(assignees_as_global_ids(issues))
new_issues = issues + [create(:issue, project: project, assignees: [create(:user)])]
@@ -560,8 +496,8 @@ RSpec.describe 'getting an issue list for a project' do
expect { post_graphql(query, current_user: current_user) }.not_to exceed_query_limit(control)
# graphql_data is memoized (see spec/support/helpers/graphql_helpers.rb)
# so we have to parse the body ourselves the second time
- issues_data = Gitlab::Json.parse(response.body)['data']['project']['issues']['edges']
- expect(issues_data.count).to eq(3)
+ issues_data = Gitlab::Json.parse(response.body)['data']['project']['issues']['nodes']
+ expect(issues_data.count).to eq(6)
expect(response_assignee_ids(issues_data)).to match_array(assignees_as_global_ids(new_issues))
end
end
@@ -572,11 +508,9 @@ RSpec.describe 'getting an issue list for a project' do
let(:statuses) { issue_data.to_h { |issue| [issue['iid'], issue['escalationStatus']] } }
let(:fields) do
<<~QUERY
- edges {
- node {
- id
- escalationStatus
- }
+ nodes {
+ id
+ escalationStatus
}
QUERY
end
@@ -588,9 +522,9 @@ RSpec.describe 'getting an issue list for a project' do
it 'returns the escalation status values' do
post_graphql(query, current_user: current_user)
- statuses = issues_data.map { |issue| issue.dig('node', 'escalationStatus') }
+ statuses = issues_data.map { |issue| issue['escalationStatus'] }
- expect(statuses).to contain_exactly(escalation_status.status_name.upcase.to_s, nil)
+ expect(statuses).to contain_exactly(escalation_status.status_name.upcase.to_s, nil, nil, nil, nil)
end
it 'avoids N+1 queries', :aggregate_failures do
@@ -726,8 +660,8 @@ RSpec.describe 'getting an issue list for a project' do
end
end
- def issues_ids
- graphql_dig_at(issues_data, :node, :id)
+ def issue_ids
+ graphql_dig_at(issues_data, :id)
end
def query(params = issue_filter_params)
diff --git a/spec/requests/api/graphql/project/languages_spec.rb b/spec/requests/api/graphql/project/languages_spec.rb
new file mode 100644
index 00000000000..6ef500cde41
--- /dev/null
+++ b/spec/requests/api/graphql/project/languages_spec.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Project.languages' do
+ include GraphqlHelpers
+
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:query) do
+ %(
+ query {
+ project(fullPath: "#{project.full_path}") {
+ languages {
+ name
+ share
+ color
+ }
+ }
+ }
+ )
+ end
+
+ let_it_be(:test_languages) do
+ [{ value: 66.69, label: "Ruby", color: "#701516", highlight: "#701516" },
+ { value: 22.98, label: "JavaScript", color: "#f1e05a", highlight: "#f1e05a" },
+ { value: 7.91, label: "HTML", color: "#e34c26", highlight: "#e34c26" },
+ { value: 2.42, label: "CoffeeScript", color: "#244776", highlight: "#244776" }]
+ end
+
+ let_it_be(:expected_languages) do
+ test_languages.map { |lang| { 'name' => lang[:label], 'share' => lang[:value], 'color' => lang[:color] } }
+ end
+
+ before do
+ allow(project.repository).to receive(:languages).and_return(test_languages)
+ end
+
+ context "when the languages haven't been detected yet" do
+ it 'returns expected languages on second request as detection is done asynchronously', :sidekiq_inline do
+ post_graphql(query, current_user: user)
+
+ expect(graphql_data_at(:project, :languages)).to eq([])
+
+ post_graphql(query, current_user: user)
+
+ expect(graphql_data_at(:project, :languages)).to eq(expected_languages)
+ end
+ end
+
+ context 'when the languages were detected before' do
+ before do
+ Projects::DetectRepositoryLanguagesService.new(project, project.first_owner).execute
+ end
+
+ it 'returns repository languages' do
+ post_graphql(query, current_user: user)
+
+ expect(graphql_data_at(:project, :languages)).to eq(expected_languages)
+ end
+ end
+end
diff --git a/spec/requests/api/graphql/project/tree/tree_spec.rb b/spec/requests/api/graphql/project/tree/tree_spec.rb
index 25e878a5b1a..e63e0d3dd04 100644
--- a/spec/requests/api/graphql/project/tree/tree_spec.rb
+++ b/spec/requests/api/graphql/project/tree/tree_spec.rb
@@ -4,7 +4,8 @@ require 'spec_helper'
RSpec.describe 'getting a tree in a project' do
include GraphqlHelpers
- let(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project, :repository) }
+
let(:current_user) { project.first_owner }
let(:path) { "" }
let(:ref) { "master" }
@@ -82,6 +83,89 @@ RSpec.describe 'getting a tree in a project' do
end
end
+ context 'when the ref points to a gpg-signed commit with a user' do
+ let_it_be(:name) { GpgHelpers::User1.names.first }
+ let_it_be(:email) { GpgHelpers::User1.emails.first }
+ let_it_be(:current_user) { create(:user, name: name, email: email).tap { |user| project.add_owner(user) } }
+ let_it_be(:gpg_key) { create(:gpg_key, user: current_user, key: GpgHelpers::User1.public_key) }
+
+ let(:ref) { GpgHelpers::SIGNED_AND_AUTHORED_SHA }
+ let(:fields) do
+ <<~QUERY
+ tree(path:"#{path}", ref:"#{ref}") {
+ lastCommit {
+ signature {
+ ... on GpgSignature {
+ #{all_graphql_fields_for('GpgSignature'.classify, max_depth: 2)}
+ }
+ }
+ }
+ }
+ QUERY
+ end
+
+ before do
+ post_graphql(query, current_user: current_user)
+ end
+
+ it 'returns the expected signature data' do
+ signature = graphql_data['project']['repository']['tree']['lastCommit']['signature']
+ expect(signature['commitSha']).to eq(ref)
+ expect(signature['user']['id']).to eq("gid://gitlab/User/#{current_user.id}")
+ expect(signature['gpgKeyUserName']).to eq(name)
+ expect(signature['gpgKeyUserEmail']).to eq(email)
+ expect(signature['verificationStatus']).to eq('VERIFIED')
+ expect(signature['project']['id']).to eq("gid://gitlab/Project/#{project.id}")
+ end
+ end
+
+ context 'when the ref points to a X.509-signed commit' do
+ let_it_be(:email) { X509Helpers::User1.certificate_email }
+ let_it_be(:current_user) { create(:user, email: email).tap { |user| project.add_owner(user) } }
+
+ let(:ref) { X509Helpers::User1.commit }
+ let(:fields) do
+ <<~QUERY
+ tree(path:"#{path}", ref:"#{ref}") {
+ lastCommit {
+ signature {
+ ... on X509Signature {
+ #{all_graphql_fields_for('X509Signature'.classify, max_depth: 2)}
+ }
+ }
+ }
+ }
+ QUERY
+ end
+
+ before do
+ store = OpenSSL::X509::Store.new
+ store.add_cert(OpenSSL::X509::Certificate.new(X509Helpers::User1.trust_cert))
+ allow(OpenSSL::X509::Store).to receive(:new).and_return(store)
+ post_graphql(query, current_user: current_user)
+ end
+
+ it 'returns the expected signature data' do
+ signature = graphql_data['project']['repository']['tree']['lastCommit']['signature']
+ expect(signature['commitSha']).to eq(ref)
+ expect(signature['verificationStatus']).to eq('VERIFIED')
+ expect(signature['project']['id']).to eq("gid://gitlab/Project/#{project.id}")
+ end
+
+ it 'returns expected certificate data' do
+ signature = graphql_data['project']['repository']['tree']['lastCommit']['signature']
+ certificate = signature['x509Certificate']
+ expect(certificate['certificateStatus']).to eq('good')
+ expect(certificate['email']).to eq(X509Helpers::User1.certificate_email)
+ expect(certificate['id']).to be_present
+ expect(certificate['serialNumber']).to eq(X509Helpers::User1.certificate_serial.to_s)
+ expect(certificate['subject']).to eq(X509Helpers::User1.certificate_subject)
+ expect(certificate['subjectKeyIdentifier']).to eq(X509Helpers::User1.certificate_subject_key_identifier)
+ expect(certificate['createdAt']).to be_present
+ expect(certificate['updatedAt']).to be_present
+ end
+ end
+
context 'when current user is nil' do
it 'returns empty project' do
post_graphql(query, current_user: nil)
diff --git a/spec/requests/api/graphql/project/work_item_types_spec.rb b/spec/requests/api/graphql/project/work_item_types_spec.rb
index 157961c3f66..3d30baab816 100644
--- a/spec/requests/api/graphql/project/work_item_types_spec.rb
+++ b/spec/requests/api/graphql/project/work_item_types_spec.rb
@@ -57,15 +57,4 @@ RSpec.describe 'getting a list of work item types for a project' do
expect(graphql_data).to eq('project' => nil)
end
end
-
- context 'when the work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- post_graphql(query, current_user: current_user)
- end
-
- it 'returns null' do
- expect(graphql_data.dig('project', 'workItemTypes')).to be_nil
- end
- end
end
diff --git a/spec/requests/api/graphql/project/work_items_spec.rb b/spec/requests/api/graphql/project/work_items_spec.rb
index e82f6ad24a2..6d20799c9ec 100644
--- a/spec/requests/api/graphql/project/work_items_spec.rb
+++ b/spec/requests/api/graphql/project/work_items_spec.rb
@@ -10,6 +10,8 @@ RSpec.describe 'getting a work item list for a project' do
let_it_be(:current_user) { create(:user) }
let_it_be(:label1) { create(:label, project: project) }
let_it_be(:label2) { create(:label, project: project) }
+ let_it_be(:milestone1) { create(:milestone, project: project) }
+ let_it_be(:milestone2) { create(:milestone, project: project) }
let_it_be(:item1) { create(:work_item, project: project, discussion_locked: true, title: 'item1', labels: [label1]) }
let_it_be(:item2) do
@@ -19,7 +21,8 @@ RSpec.describe 'getting a work item list for a project' do
title: 'item2',
last_edited_by: current_user,
last_edited_at: 1.day.ago,
- labels: [label2]
+ labels: [label2],
+ milestone: milestone1
)
end
@@ -55,7 +58,8 @@ RSpec.describe 'getting a work item list for a project' do
:last_edited_by_user,
last_edited_at: 1.week.ago,
project: project,
- labels: [label1, label2]
+ labels: [label1, label2],
+ milestone: milestone2
)
expect_graphql_errors_to_be_empty
@@ -94,6 +98,11 @@ RSpec.describe 'getting a work item list for a project' do
labels { nodes { id } }
allowsScopedLabels
}
+ ... on WorkItemWidgetMilestone {
+ milestone {
+ id
+ }
+ }
}
}
GRAPHQL
@@ -121,18 +130,6 @@ RSpec.describe 'getting a work item list for a project' do
end
end
- context 'when work_items flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it 'returns an empty list' do
- post_graphql(query)
-
- expect(items_data).to eq([])
- end
- end
-
it 'returns only items visible to user' do
post_graphql(query, current_user: current_user)
diff --git a/spec/requests/api/graphql/work_item_spec.rb b/spec/requests/api/graphql/work_item_spec.rb
index 2105e479ed2..a55de6adfb2 100644
--- a/spec/requests/api/graphql/work_item_spec.rb
+++ b/spec/requests/api/graphql/work_item_spec.rb
@@ -298,6 +298,40 @@ RSpec.describe 'Query.work_item(id)' do
)
end
end
+
+ describe 'milestone widget' do
+ let_it_be(:milestone) { create(:milestone, project: project) }
+
+ let(:work_item) { create(:work_item, project: project, milestone: milestone) }
+
+ let(:work_item_fields) do
+ <<~GRAPHQL
+ id
+ widgets {
+ type
+ ... on WorkItemWidgetMilestone {
+ milestone {
+ id
+ }
+ }
+ }
+ 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' => 'MILESTONE',
+ 'milestone' => {
+ 'id' => work_item.milestone.to_gid.to_s
+ }
+ )
+ )
+ )
+ end
+ end
end
context 'when an Issue Global ID is provided' do
@@ -323,16 +357,4 @@ RSpec.describe 'Query.work_item(id)' do
)
end
end
-
- context 'when the work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it 'returns nil' do
- post_graphql(query)
-
- expect(work_item_data).to be_nil
- end
- end
end
diff --git a/spec/requests/api/group_boards_spec.rb b/spec/requests/api/group_boards_spec.rb
index 6ce8b766807..cc110aa4017 100644
--- a/spec/requests/api/group_boards_spec.rb
+++ b/spec/requests/api/group_boards_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe API::GroupBoards do
board_parent.add_owner(user)
end
- let_it_be(:project) { create(:project, :public, namespace: board_parent ) }
+ let_it_be(:project) { create(:project, :public, namespace: board_parent) }
let_it_be(:dev_label) do
create(:group_label, title: 'Development', color: '#FFAABB', group: board_parent)
diff --git a/spec/requests/api/group_container_repositories_spec.rb b/spec/requests/api/group_container_repositories_spec.rb
index 413c37eaed9..82daab0e5e8 100644
--- a/spec/requests/api/group_container_repositories_spec.rb
+++ b/spec/requests/api/group_container_repositories_spec.rb
@@ -57,5 +57,13 @@ RSpec.describe API::GroupContainerRepositories do
expect(response).to have_gitlab_http_status(:not_found)
end
end
+
+ context 'with URL-encoded path of the group' do
+ let(:url) { "/groups/#{group.full_path}/registry/repositories" }
+
+ it_behaves_like 'rejected container repository access', :guest, :forbidden
+ it_behaves_like 'rejected container repository access', :anonymous, :not_found
+ it_behaves_like 'returns repositories for allowed users', :reporter
+ end
end
end
diff --git a/spec/requests/api/group_variables_spec.rb b/spec/requests/api/group_variables_spec.rb
index 4fed7dd7624..a07a8ae4292 100644
--- a/spec/requests/api/group_variables_spec.rb
+++ b/spec/requests/api/group_variables_spec.rb
@@ -90,7 +90,7 @@ RSpec.describe API::GroupVariables do
it 'creates variable' do
expect do
- post api("/groups/#{group.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', protected: true, masked: true }
+ post api("/groups/#{group.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', protected: true, masked: true, raw: true }
end.to change { group.variables.count }.by(1)
expect(response).to have_gitlab_http_status(:created)
@@ -100,6 +100,16 @@ RSpec.describe API::GroupVariables do
expect(json_response['masked']).to be_truthy
expect(json_response['variable_type']).to eq('env_var')
expect(json_response['environment_scope']).to eq('*')
+ expect(json_response['raw']).to be_truthy
+ end
+
+ it 'masks the new value when logging' do
+ masked_params = { 'key' => 'VAR_KEY', 'value' => '[FILTERED]', 'protected' => 'true', 'masked' => 'true' }
+
+ expect(::API::API::LOGGER).to receive(:info).with(include(params: include(masked_params)))
+
+ post api("/groups/#{group.id}/variables", user),
+ params: { key: 'VAR_KEY', value: 'SENSITIVE', protected: true, masked: true }
end
it 'creates variable with optional attributes' do
@@ -112,6 +122,7 @@ RSpec.describe API::GroupVariables do
expect(json_response['value']).to eq('VALUE_2')
expect(json_response['protected']).to be_falsey
expect(json_response['masked']).to be_falsey
+ expect(json_response['raw']).to be_falsey
expect(json_response['variable_type']).to eq('file')
expect(json_response['environment_scope']).to eq('*')
end
@@ -152,7 +163,7 @@ RSpec.describe API::GroupVariables do
initial_variable = group.variables.reload.first
value_before = initial_variable.value
- put api("/groups/#{group.id}/variables/#{variable.key}", user), params: { variable_type: 'file', value: 'VALUE_1_UP', protected: true, masked: true }
+ put api("/groups/#{group.id}/variables/#{variable.key}", user), params: { variable_type: 'file', value: 'VALUE_1_UP', protected: true, masked: true, raw: true }
updated_variable = group.variables.reload.first
@@ -162,6 +173,16 @@ RSpec.describe API::GroupVariables do
expect(updated_variable).to be_protected
expect(json_response['variable_type']).to eq('file')
expect(json_response['masked']).to be_truthy
+ expect(json_response['raw']).to be_truthy
+ end
+
+ it 'masks the new value when logging' do
+ masked_params = { 'value' => '[FILTERED]', 'protected' => 'true', 'masked' => 'true' }
+
+ expect(::API::API::LOGGER).to receive(:info).with(include(params: include(masked_params)))
+
+ put api("/groups/#{group.id}/variables/#{variable.key}", user),
+ params: { value: 'SENSITIVE', protected: true, masked: true }
end
it 'responds with 404 Not Found if requesting non-existing variable' do
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 02d29601ceb..ce6140d8da8 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -91,11 +91,8 @@ RSpec.describe API::Groups do
.to satisfy_one { |group| group['name'] == group1.name }
end
- it 'avoids N+1 queries' do
- # Establish baseline
- get api("/groups", admin)
-
- control = ActiveRecord::QueryRecorder.new do
+ it 'avoids N+1 queries', :use_sql_query_cache do
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
get api("/groups", admin)
end
@@ -103,7 +100,7 @@ RSpec.describe API::Groups do
expect do
get api("/groups", admin)
- end.not_to exceed_query_limit(control)
+ end.not_to exceed_all_query_limit(control)
end
context 'when statistics are requested' do
@@ -1230,10 +1227,7 @@ RSpec.describe API::Groups do
group1.reload
end
- it "only looks up root ancestor once and returns projects including those in subgroups" do
- expect(Namespace).to receive(:find_by).with(id: group1.id.to_s).once.and_call_original # For the group sent in the API call
- expect(Namespace).to receive(:joins).with(start_with('INNER JOIN (SELECT id, traversal_ids[1]')).once.and_call_original # All-in-one root_ancestor query
-
+ it "returns projects including those in subgroups" do
get api("/groups/#{group1.id}/projects", user1), params: { include_subgroups: true }
expect(response).to have_gitlab_http_status(:ok)
@@ -1241,6 +1235,18 @@ RSpec.describe API::Groups do
expect(json_response).to be_an(Array)
expect(json_response.length).to eq(6)
end
+
+ it 'avoids N+1 queries', :use_sql_query_cache do
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ get api("/groups/#{group1.id}/projects", user1), params: { include_subgroups: true }
+ end
+
+ create_list(:project, 2, :public, namespace: group1)
+
+ expect do
+ get api("/groups/#{group1.id}/projects", user1), params: { include_subgroups: true }
+ end.not_to exceed_all_query_limit(control.count)
+ end
end
context 'when include_ancestor_groups is true' do
diff --git a/spec/requests/api/import_github_spec.rb b/spec/requests/api/import_github_spec.rb
index 015a09d41ab..4f95295c14d 100644
--- a/spec/requests/api/import_github_spec.rb
+++ b/spec/requests/api/import_github_spec.rb
@@ -89,6 +89,18 @@ RSpec.describe API::ImportGithub do
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
+
+ context 'when unauthenticated user' do
+ it 'returns 403 response' do
+ post api("/import/github"), params: {
+ target_namespace: user.namespace_path,
+ personal_access_token: token,
+ repo_id: non_existing_record_id
+ }
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
end
describe "POST /import/github/cancel" do
@@ -127,5 +139,15 @@ RSpec.describe API::ImportGithub do
expect(json_response['message']).to eq('The import cannot be canceled because it is finished')
end
end
+
+ context 'when unauthenticated user' do
+ it 'returns 403 response' do
+ post api("/import/github/cancel"), params: {
+ project_id: project.id
+ }
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
end
end
diff --git a/spec/requests/api/internal/kubernetes_spec.rb b/spec/requests/api/internal/kubernetes_spec.rb
index 67d8a18dfd8..3c6604cf409 100644
--- a/spec/requests/api/internal/kubernetes_spec.rb
+++ b/spec/requests/api/internal/kubernetes_spec.rb
@@ -69,48 +69,6 @@ RSpec.describe API::Internal::Kubernetes do
context 'is authenticated for an agent' do
let!(:agent_token) { create(:cluster_agent_token) }
- # Todo: Remove gitops_sync_count and k8s_api_proxy_request_count in the next milestone
- # https://gitlab.com/gitlab-org/gitlab/-/issues/369489
- # We're only keeping it for backwards compatibility until KAS is released
- # using `counts:` instead
- context 'deprecated events' do
- it 'returns no_content for valid events' do
- send_request(params: { gitops_sync_count: 10, k8s_api_proxy_request_count: 5 })
-
- expect(response).to have_gitlab_http_status(:no_content)
- end
-
- it 'returns no_content for counts of zero' do
- send_request(params: { gitops_sync_count: 0, k8s_api_proxy_request_count: 0 })
-
- expect(response).to have_gitlab_http_status(:no_content)
- end
-
- it 'returns 400 for non number' do
- send_request(params: { gitops_sync_count: 'string', k8s_api_proxy_request_count: 1 })
-
- expect(response).to have_gitlab_http_status(:bad_request)
- end
-
- it 'returns 400 for negative number' do
- send_request(params: { gitops_sync_count: -1, k8s_api_proxy_request_count: 1 })
-
- expect(response).to have_gitlab_http_status(:bad_request)
- end
-
- it 'tracks events' do
- counters = { gitops_sync_count: 10, k8s_api_proxy_request_count: 5 }
- expected_counters = {
- kubernetes_agent_gitops_sync: counters[:gitops_sync_count],
- kubernetes_agent_k8s_api_proxy_request: counters[:k8s_api_proxy_request_count]
- }
-
- send_request(params: counters)
-
- expect(Gitlab::UsageDataCounters::KubernetesAgentCounter.totals).to eq(expected_counters)
- end
- end
-
it 'returns no_content for valid events' do
counters = { gitops_sync: 10, k8s_api_proxy_request: 5 }
unique_counters = { agent_users_using_ci_tunnel: [10] }
diff --git a/spec/requests/api/invitations_spec.rb b/spec/requests/api/invitations_spec.rb
index a795b49c44e..c07d2e11363 100644
--- a/spec/requests/api/invitations_spec.rb
+++ b/spec/requests/api/invitations_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe API::Invitations do
let_it_be(:maintainer) { create(:user, username: 'maintainer_user') }
+ let_it_be(:maintainer2) { create(:user, username: 'user-with-maintainer-role') }
let_it_be(:developer) { create(:user) }
let_it_be(:access_requester) { create(:user) }
let_it_be(:stranger) { create(:user) }
@@ -31,8 +32,8 @@ RSpec.describe API::Invitations do
api("/#{source.model_name.plural}/#{source.id}/invitations", user)
end
- def invite_member_by_email(source, source_type, email, created_by)
- create(:"#{source_type}_member", invite_token: '123', invite_email: email, source: source, user: nil, created_by: created_by)
+ def invite_member_by_email(source, source_type, email, created_by, access_level: :developer)
+ create(:"#{source_type}_member", access_level, invite_token: '123', invite_email: email, source: source, user: nil, created_by: created_by)
end
shared_examples 'POST /:source_type/:id/invitations' do |source_type|
@@ -44,15 +45,42 @@ RSpec.describe API::Invitations do
end
end
- context 'when authenticated as a non-member or member with insufficient rights' do
- %i[access_requester stranger developer].each do |type|
- context "as a #{type}" do
- it 'returns 403' do
- user = public_send(type)
+ context 'when authenticated as a non-member or member with insufficient membership management rights' do
+ context 'when the user does not have rights to manage members' do
+ %i[access_requester stranger developer].each do |type|
+ context "as a #{type}" do
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ post invitations_url(source, public_send(type)),
+ params: { email: email, access_level: Member::MAINTAINER }
+ end
+ end
+ end
+ end
+ end
+
+ context 'when the user has the rights to manage members but tries to manage members with a higher access level' do
+ let(:maintainer) { maintainer2 }
- post invitations_url(source, user), params: { email: email, access_level: Member::MAINTAINER }
+ before do
+ source.add_maintainer(maintainer)
+ end
- expect(response).to have_gitlab_http_status(:forbidden)
+ context 'when an invitee is added as OWNER' do
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ post invitations_url(source, maintainer),
+ params: { email: email, access_level: Member::OWNER }
+ end
+ end
+ end
+
+ context 'when an access_requester is added as OWNER' do
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ post invitations_url(source, maintainer),
+ params: { user_id: access_requester.email, access_level: Member::OWNER }
+ end
end
end
end
@@ -348,6 +376,14 @@ RSpec.describe API::Invitations do
it 'returns 400 when the email list is not a valid format' do
post invitations_url(source, maintainer),
+ params: { email: %w[email1@example.com not-an-email], access_level: Member::MAINTAINER }
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response['error']).to eq('email contains an invalid email address')
+ end
+
+ it 'returns 400 when the comma-separated email list is not a valid format' do
+ post invitations_url(source, maintainer),
params: { email: 'email1@example.com,not-an-email', access_level: Member::MAINTAINER }
expect(response).to have_gitlab_http_status(:bad_request)
@@ -495,14 +531,12 @@ RSpec.describe API::Invitations do
end
end
- %i[developer access_requester stranger].each do |type|
- context "when authenticated as a #{type}" do
- it 'returns 403' do
- user = public_send(type)
-
- get invitations_url(source, user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ %i[access_requester stranger developer].each do |type|
+ context "as a #{type}" do
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ get invitations_url(source, public_send(type))
+ end
end
end
end
@@ -573,14 +607,14 @@ RSpec.describe API::Invitations do
end
context 'when authenticated as a non-member or member with insufficient rights' do
- %i[access_requester stranger].each do |type|
- context "as a #{type}" do
- it 'returns 403' do
- user = public_send(type)
-
- delete invite_api(source, user, invite.invite_email)
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ context 'when the user does not have rights to manage members' do
+ %i[access_requester stranger].each do |type|
+ context "as a #{type}" do
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ delete invite_api(source, public_send(type), invite.invite_email)
+ end
+ end
end
end
end
@@ -604,6 +638,23 @@ RSpec.describe API::Invitations do
expect(response).to have_gitlab_http_status(:no_content)
end.to change { source.members.count }.by(-1)
end
+
+ context 'when MAINTAINER tries to remove invitation of an OWNER' do
+ let_it_be(:maintainer) { maintainer2 }
+ let!(:owner_invite) do
+ invite_member_by_email(source, source_type, 'owner@owner.com', developer, access_level: :owner)
+ end
+
+ before do
+ source.add_maintainer(maintainer)
+ end
+
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ delete invite_api(source, maintainer, owner_invite.invite_email)
+ end
+ end
+ end
end
it 'returns 404 if member does not exist' do
@@ -651,14 +702,15 @@ RSpec.describe API::Invitations do
end
context 'when authenticated as a non-member or member with insufficient rights' do
- %i[access_requester stranger].each do |type|
- context "as a #{type}" do
- it 'returns 403' do
- user = public_send(type)
-
- put update_api(source, user, invite.invite_email), params: { access_level: Member::MAINTAINER }
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ context 'when the user does not have rights to manage members' do
+ %i[access_requester stranger].each do |type|
+ context "as a #{type}" do
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ put update_api(source, public_send(type), invite.invite_email),
+ params: { access_level: Member::MAINTAINER }
+ end
+ end
end
end
end
@@ -673,6 +725,21 @@ RSpec.describe API::Invitations do
expect(json_response['access_level']).to eq(Member::MAINTAINER)
expect(invite.reload.access_level).to eq(Member::MAINTAINER)
end
+
+ context 'MAINTAINER tries to update access level to OWNER' do
+ let_it_be(:maintainer) { maintainer2 }
+
+ before do
+ source.add_maintainer(maintainer)
+ end
+
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ put update_api(source, maintainer, invite.invite_email),
+ params: { access_level: Member::OWNER }
+ end
+ end
+ end
end
it 'returns 409 if member does not exist' do
diff --git a/spec/requests/api/issues/issues_spec.rb b/spec/requests/api/issues/issues_spec.rb
index f5c73846173..0e20b2133db 100644
--- a/spec/requests/api/issues/issues_spec.rb
+++ b/spec/requests/api/issues/issues_spec.rb
@@ -92,7 +92,7 @@ RSpec.describe API::Issues do
describe 'GET /issues/:id' do
context 'when unauthorized' do
it 'returns unauthorized' do
- get api("/issues/#{issue.id}" )
+ get api("/issues/#{issue.id}")
expect(response).to have_gitlab_http_status(:unauthorized)
end
@@ -101,7 +101,7 @@ RSpec.describe API::Issues do
context 'when authorized' do
context 'as a normal user' do
it 'returns forbidden' do
- get api("/issues/#{issue.id}", user )
+ get api("/issues/#{issue.id}", user)
expect(response).to have_gitlab_http_status(:forbidden)
end
diff --git a/spec/requests/api/issues/post_projects_issues_spec.rb b/spec/requests/api/issues/post_projects_issues_spec.rb
index 3883eb01391..deaf7be96ab 100644
--- a/spec/requests/api/issues/post_projects_issues_spec.rb
+++ b/spec/requests/api/issues/post_projects_issues_spec.rb
@@ -473,8 +473,8 @@ RSpec.describe API::Issues do
end
describe '/projects/:id/issues/:issue_iid/move' 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 ) }
+ 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
post api("/projects/#{project.id}/issues/#{issue.iid}/move", user),
diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb
index c1217292d5c..97ab90c9776 100644
--- a/spec/requests/api/labels_spec.rb
+++ b/spec/requests/api/labels_spec.rb
@@ -234,7 +234,7 @@ RSpec.describe API::Labels do
before do
create(:labeled_issue, project: project, labels: [group_label], author: user)
create(:labeled_issue, project: project, labels: [label1], author: user, state: :closed)
- create(:labeled_merge_request, labels: [priority_label], author: user, source_project: project )
+ create(:labeled_merge_request, labels: [priority_label], author: user, source_project: project)
end
it 'includes counts in the response' do
diff --git a/spec/requests/api/markdown_spec.rb b/spec/requests/api/markdown_spec.rb
index 3e702b05bc9..6239ac4e749 100644
--- a/spec/requests/api/markdown_spec.rb
+++ b/spec/requests/api/markdown_spec.rb
@@ -193,7 +193,7 @@ RSpec.describe API::Markdown do
end
let(:issue) { create(:issue, project: public_project, title: 'Team only title') }
- let(:text) { "#{issue.to_reference}" }
+ let(:text) { issue.to_reference.to_s }
let(:params) { { text: text, gfm: true, project: public_project.full_path } }
shared_examples 'user without proper access' do
diff --git a/spec/requests/api/maven_packages_spec.rb b/spec/requests/api/maven_packages_spec.rb
index d771c1e2dcc..ac8c4aacdf2 100644
--- a/spec/requests/api/maven_packages_spec.rb
+++ b/spec/requests/api/maven_packages_spec.rb
@@ -720,6 +720,16 @@ RSpec.describe API::MavenPackages do
expect(response).to have_gitlab_http_status(:not_found)
end
+ context 'with access to package registry for everyone' do
+ subject { download_file(file_name: package_file.file_name) }
+
+ before do
+ project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC)
+ end
+
+ it_behaves_like 'successfully returning the file'
+ end
+
it_behaves_like 'downloads with a job token'
it_behaves_like 'downloads with a deploy token'
diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb
index 9df9c75b020..69be574f38a 100644
--- a/spec/requests/api/members_spec.rb
+++ b/spec/requests/api/members_spec.rb
@@ -270,39 +270,42 @@ RSpec.describe API::Members do
end
end
- context 'when authenticated as a non-member or member with insufficient rights' do
- %i[access_requester stranger developer].each do |type|
- context "as a #{type}" do
- it 'returns 403' do
- user = public_send(type)
- post api("/#{source_type.pluralize}/#{source.id}/members", user),
- params: { user_id: access_requester.id, access_level: Member::MAINTAINER }
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ context 'when authenticated as a non-member or member with insufficient membership management rights' do
+ context 'when the user does not have rights to manage members' do
+ %i[access_requester stranger developer].each do |type|
+ context "as a #{type}" do
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ post api("/#{source_type.pluralize}/#{source.id}/members", public_send(type)),
+ params: { user_id: access_requester.id, access_level: Member::MAINTAINER }
+ end
+ end
end
end
+ end
- context 'adding a member of higher access level' do
- before do
- # the other 'maintainer' is in fact an owner of the group!
- source.add_maintainer(maintainer2)
- end
+ context 'when the user has the rights to manage members but tries to manage members with a higher access level' do
+ # the other 'maintainer' is in fact an owner of the group!
+ let(:maintainer) { maintainer2 }
- context 'when an access requester' do
- it 'is not successful' do
- post api("/#{source_type.pluralize}/#{source.id}/members", maintainer2),
- params: { user_id: access_requester.id, access_level: Member::OWNER }
+ before do
+ source.add_maintainer(maintainer)
+ end
- expect(response).to have_gitlab_http_status(:forbidden)
+ context 'when an access requester is added as OWNER' do
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ post api("/#{source_type.pluralize}/#{source.id}/members", maintainer),
+ params: { user_id: access_requester.id, access_level: Member::OWNER }
end
end
+ end
- context 'when a totally new user' do
- it 'is not successful' do
- post api("/#{source_type.pluralize}/#{source.id}/members", maintainer2),
+ context 'when a totally new user is added as OWNER' do
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ post api("/#{source_type.pluralize}/#{source.id}/members", maintainer),
params: { user_id: stranger.id, access_level: Member::OWNER }
-
- expect(response).to have_gitlab_http_status(:forbidden)
end
end
end
@@ -561,27 +564,31 @@ RSpec.describe API::Members do
context 'when authenticated as a non-member or member with insufficient rights' do
%i[access_requester stranger developer].each do |type|
context "as a #{type}" do
- it 'returns 403' do
- user = public_send(type)
- put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", user),
- params: { access_level: Member::MAINTAINER }
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", public_send(type)),
+ params: { access_level: Member::MAINTAINER }
+ end
end
end
end
context 'as a maintainer updating a member to one with higher access level than themselves' do
+ # the other 'maintainer' is in fact an owner of the group!
+ let(:maintainer) { maintainer2 }
+
before do
# the other 'maintainer' is in fact an owner of the group!
source.add_maintainer(maintainer2)
end
- it 'returns 403' do
- put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", maintainer2),
- params: { access_level: Member::OWNER }
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ context 'updating a member to OWNER' do
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ put api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", maintainer),
+ params: { access_level: Member::OWNER }
+ end
+ end
end
end
end
@@ -600,18 +607,19 @@ RSpec.describe API::Members do
context 'when updating a member with higher access level' do
let(:owner) { create(:user) }
+ # the other 'maintainer' is in fact an owner of the group!
+ let(:maintainer) { maintainer2 }
before do
source.add_owner(owner)
- # the other 'maintainer' is in fact an owner of the group!
- source.add_maintainer(maintainer2)
+ source.add_maintainer(maintainer)
end
- it 'returns 403' do
- put api("/#{source_type.pluralize}/#{source.id}/members/#{owner.id}", maintainer2),
- params: { access_level: Member::DEVELOPER }
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ put api("/#{source_type.pluralize}/#{source.id}/members/#{owner.id}", maintainer),
+ params: { access_level: Member::OWNER }
+ end
end
end
end
@@ -676,11 +684,10 @@ RSpec.describe API::Members do
context 'when authenticated as a non-member or member with insufficient rights' do
%i[access_requester stranger].each do |type|
context "as a #{type}" do
- it 'returns 403' do
- user = public_send(type)
- delete api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", user)
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ delete api("/#{source_type.pluralize}/#{source.id}/members/#{developer.id}", public_send(type))
+ end
end
end
end
@@ -709,18 +716,18 @@ RSpec.describe API::Members do
context 'when attempting to delete a member with higher access level' do
let(:owner) { create(:user) }
+ # the other 'maintainer' is in fact an owner of the group!
+ let(:maintainer) { maintainer2 }
before do
source.add_owner(owner)
- # the other 'maintainer' is in fact an owner of the group!
- source.add_maintainer(maintainer2)
+ source.add_maintainer(maintainer)
end
- it 'returns 403' do
- delete api("/#{source_type.pluralize}/#{source.id}/members/#{owner.id}", maintainer2),
- params: { access_level: Member::DEVELOPER }
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ delete api("/#{source_type.pluralize}/#{source.id}/members/#{owner.id}", maintainer)
+ end
end
end
@@ -799,11 +806,11 @@ RSpec.describe API::Members do
end
context 'adding owner to project' do
- it 'returns 403' do
- post api("/projects/#{project.id}/members", maintainer),
- params: { user_id: stranger.id, access_level: Member::OWNER }
-
- expect(response).to have_gitlab_http_status(:forbidden)
+ it_behaves_like 'a 403 response when user does not have rights to manage members of a specific access level' do
+ let(:route) do
+ post api("/projects/#{project.id}/members", maintainer),
+ params: { user_id: access_requester.id, access_level: Member::OWNER }
+ end
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index d593e369d27..eea223485ce 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -3022,7 +3022,7 @@ RSpec.describe API::MergeRequests do
describe "PUT /projects/:id/merge_requests/:merge_request_iid" do
context 'updates force_remove_source_branch properly' do
it 'sets to false' do
- merge_request.update!(merge_params: { 'force_remove_source_branch' => true } )
+ merge_request.update!(merge_params: { 'force_remove_source_branch' => true })
expect(merge_request.force_remove_source_branch?).to be_truthy
@@ -3034,7 +3034,7 @@ RSpec.describe API::MergeRequests do
end
it 'sets to true' do
- merge_request.update!(merge_params: { 'force_remove_source_branch' => false } )
+ merge_request.update!(merge_params: { 'force_remove_source_branch' => false })
expect(merge_request.force_remove_source_branch?).to be false
@@ -3279,7 +3279,7 @@ RSpec.describe API::MergeRequests do
end
it 'when removing labels, only removes those specified' do
- put api_base, params: { remove_labels: "#{label.title}" }
+ put api_base, params: { remove_labels: label.title.to_s }
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['labels']).to eq([label2.title])
diff --git a/spec/requests/api/metrics/dashboard/annotations_spec.rb b/spec/requests/api/metrics/dashboard/annotations_spec.rb
index 5e64ac7d481..a09596f167d 100644
--- a/spec/requests/api/metrics/dashboard/annotations_spec.rb
+++ b/spec/requests/api/metrics/dashboard/annotations_spec.rb
@@ -64,7 +64,7 @@ RSpec.describe API::Metrics::Dashboard::Annotations do
{
'starting_at' => starting_at.to_time,
'ending_at' => ending_at.to_time,
- "#{source_type}" => source,
+ source_type.to_s => source,
'dashboard_path' => dashboard_unescaped,
'description' => params[:description]
}
diff --git a/spec/requests/api/ml/mlflow_spec.rb b/spec/requests/api/ml/mlflow_spec.rb
index 09e9359c0b3..9448f009742 100644
--- a/spec/requests/api/ml/mlflow_spec.rb
+++ b/spec/requests/api/ml/mlflow_spec.rb
@@ -253,7 +253,7 @@ RSpec.describe API::Ml::Mlflow do
it 'creates the experiment', :aggregate_failures do
expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to include('experiment_id' )
+ expect(json_response).to include('experiment_id')
end
describe 'Error States' do
@@ -295,7 +295,6 @@ RSpec.describe API::Ml::Mlflow do
'experiment_id' => params[:experiment_id],
'user_id' => current_user.id.to_s,
'start_time' => params[:start_time],
- 'artifact_uri' => 'not_implemented',
'status' => "RUNNING",
'lifecycle_stage' => "active"
}
@@ -339,7 +338,7 @@ RSpec.describe API::Ml::Mlflow do
'experiment_id' => candidate.experiment.iid.to_s,
'user_id' => candidate.user.id.to_s,
'start_time' => candidate.start_time,
- 'artifact_uri' => 'not_implemented',
+ 'artifact_uri' => "http://www.example.com/api/v4/projects/#{project_id}/packages/generic/ml_candidate_#{candidate.iid}/-/",
'status' => "RUNNING",
'lifecycle_stage' => "active"
}
@@ -378,7 +377,7 @@ RSpec.describe API::Ml::Mlflow do
'user_id' => candidate.user.id.to_s,
'start_time' => candidate.start_time,
'end_time' => params[:end_time],
- 'artifact_uri' => 'not_implemented',
+ 'artifact_uri' => "http://www.example.com/api/v4/projects/#{project_id}/packages/generic/ml_candidate_#{candidate.iid}/-/",
'status' => 'FAILED',
'lifecycle_stage' => 'active'
}
diff --git a/spec/requests/api/npm_project_packages_spec.rb b/spec/requests/api/npm_project_packages_spec.rb
index bdcd6e7278d..373327787a2 100644
--- a/spec/requests/api/npm_project_packages_spec.rb
+++ b/spec/requests/api/npm_project_packages_spec.rb
@@ -5,16 +5,29 @@ require 'spec_helper'
RSpec.describe API::NpmProjectPackages do
include_context 'npm api setup'
- describe 'GET /api/v4/projects/:id/packages/npm/*package_name' do
- it_behaves_like 'handling get metadata requests', scope: :project do
- let(:url) { api("/projects/#{project.id}/packages/npm/#{package_name}") }
+ shared_examples 'accept get request on private project with access to package registry for everyone' do
+ subject { get(url) }
+
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC)
end
+
+ it_behaves_like 'returning response status', :ok
+ end
+
+ describe 'GET /api/v4/projects/:id/packages/npm/*package_name' do
+ let(:url) { api("/projects/#{project.id}/packages/npm/#{package_name}") }
+
+ it_behaves_like 'handling get metadata requests', scope: :project
+ it_behaves_like 'accept get request on private project with access to package registry for everyone'
end
describe 'GET /api/v4/projects/:id/packages/npm/-/package/*package_name/dist-tags' do
- it_behaves_like 'handling get dist tags requests', scope: :project do
- let(:url) { api("/projects/#{project.id}/packages/npm/-/package/#{package_name}/dist-tags") }
- end
+ let(:url) { api("/projects/#{project.id}/packages/npm/-/package/#{package_name}/dist-tags") }
+
+ it_behaves_like 'handling get dist tags requests', scope: :project
+ it_behaves_like 'accept get request on private project with access to package registry for everyone'
end
describe 'PUT /api/v4/projects/:id/packages/npm/-/package/*package_name/dist-tags/:tag' do
@@ -108,6 +121,14 @@ RSpec.describe API::NpmProjectPackages do
expect(response).to have_gitlab_http_status(:forbidden)
end
end
+
+ context 'with access to package registry for everyone' do
+ before do
+ project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC)
+ end
+
+ it_behaves_like 'successfully downloads the file'
+ end
end
context 'internal project' do
diff --git a/spec/requests/api/pages/pages_spec.rb b/spec/requests/api/pages/pages_spec.rb
index 7d44ff533aa..4a94bf90205 100644
--- a/spec/requests/api/pages/pages_spec.rb
+++ b/spec/requests/api/pages/pages_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe API::Pages do
end
it 'removes the pages' do
- delete api("/projects/#{project.id}/pages", admin )
+ delete api("/projects/#{project.id}/pages", admin)
expect(project.reload.pages_metadatum.deployed?).to be(false)
end
diff --git a/spec/requests/api/personal_access_tokens_spec.rb b/spec/requests/api/personal_access_tokens_spec.rb
index 31c4e8803e3..1fa2ad6ebfa 100644
--- a/spec/requests/api/personal_access_tokens_spec.rb
+++ b/spec/requests/api/personal_access_tokens_spec.rb
@@ -18,9 +18,10 @@ RSpec.describe API::PersonalAccessTokens do
it "status, count and result as expected" do
subject
- if status == :bad_request
+ case status
+ when :bad_request
expect(json_response).to eq(result)
- elsif status == :ok
+ when :ok
expect(map_id(json_response)).to a_collection_containing_exactly(*result)
end
@@ -87,7 +88,7 @@ RSpec.describe API::PersonalAccessTokens do
end
context 'filter with created parameter' do
- let_it_be(:token1) { create(:personal_access_token, created_at: DateTime.new(2022, 01, 01, 12, 30, 25) ) }
+ let_it_be(:token1) { create(:personal_access_token, created_at: DateTime.new(2022, 01, 01, 12, 30, 25)) }
context 'test created_before' do
where(:created_at, :status, :result_count, :result) do
@@ -121,7 +122,7 @@ RSpec.describe API::PersonalAccessTokens do
end
context 'filter with last_used parameter' do
- let_it_be(:token1) { create(:personal_access_token, last_used_at: DateTime.new(2022, 01, 01, 12, 30, 25) ) }
+ let_it_be(:token1) { create(:personal_access_token, last_used_at: DateTime.new(2022, 01, 01, 12, 30, 25)) }
let_it_be(:never_used_token) { create(:personal_access_token) }
context 'test last_used_before' do
@@ -209,13 +210,13 @@ RSpec.describe API::PersonalAccessTokens do
expect(response).to have_gitlab_http_status(status)
- expect(json_response.map { |pat| pat['id'] } ).to include(*result) if status == :ok
+ expect(json_response.map { |pat| pat['id'] }).to include(*result) if status == :ok
end
end
end
context 'filter last_used_before and last_used_after combined is valid' do
- let_it_be(:token1) { create(:personal_access_token, last_used_at: DateTime.new(2022, 01, 02) ) }
+ let_it_be(:token1) { create(:personal_access_token, last_used_at: DateTime.new(2022, 01, 02)) }
where(:last_used_before, :last_used_after, :status, :result) do
'2022-01-02' | '2022-01-02' | :ok | lazy { [token1.id] }
@@ -232,7 +233,7 @@ RSpec.describe API::PersonalAccessTokens do
expect(response).to have_gitlab_http_status(status)
- expect(json_response.map { |pat| pat['id'] } ).to include(*result) if status == :ok
+ expect(json_response.map { |pat| pat['id'] }).to include(*result) if status == :ok
end
end
end
@@ -304,7 +305,7 @@ RSpec.describe API::PersonalAccessTokens do
# Here it is only tested whether PATs to which the user has no access right are excluded from the filter function.
context 'filter with created parameter' do
let_it_be(:token1) do
- create(:personal_access_token, created_at: DateTime.new(2022, 01, 02, 12, 30, 25), user: current_user )
+ create(:personal_access_token, created_at: DateTime.new(2022, 01, 02, 12, 30, 25), user: current_user)
end
let_it_be(:token2) { create(:personal_access_token, created_at: DateTime.new(2022, 01, 02, 12, 30, 25)) }
@@ -332,7 +333,7 @@ RSpec.describe API::PersonalAccessTokens do
create(:personal_access_token, last_used_at: DateTime.new(2022, 01, 01, 12, 30, 25), user: current_user)
end
- let_it_be(:token2) { create(:personal_access_token, last_used_at: DateTime.new(2022, 01, 01, 12, 30, 25) ) }
+ let_it_be(:token2) { create(:personal_access_token, last_used_at: DateTime.new(2022, 01, 01, 12, 30, 25)) }
let_it_be(:never_used_token) { create(:personal_access_token) }
let_it_be(:status) { :ok }
diff --git a/spec/requests/api/project_attributes.yml b/spec/requests/api/project_attributes.yml
index 0b4a96896d6..2ff4cd72f1e 100644
--- a/spec/requests/api/project_attributes.yml
+++ b/spec/requests/api/project_attributes.yml
@@ -162,6 +162,7 @@ project_setting:
- show_diff_preview_in_email
- suggested_reviewers_enabled
- jitsu_key
+ - mirror_branch_regex
build_service_desk_setting: # service_desk_setting
unexposed_attributes:
diff --git a/spec/requests/api/project_container_repositories_spec.rb b/spec/requests/api/project_container_repositories_spec.rb
index 506e60d19a6..52ec06d76a9 100644
--- a/spec/requests/api/project_container_repositories_spec.rb
+++ b/spec/requests/api/project_container_repositories_spec.rb
@@ -138,14 +138,26 @@ RSpec.describe API::ProjectContainerRepositories do
context 'for maintainer' do
let(:api_user) { maintainer }
- it 'schedules removal of repository' do
- expect(DeleteContainerRepositoryWorker).to receive(:perform_async)
- .with(maintainer.id, root_repository.id)
-
- subject
+ it 'marks the repository as delete_scheduled' do
+ expect(DeleteContainerRepositoryWorker).not_to receive(:perform_async)
+ expect { subject }.to change { root_repository.reload.status }.from(nil).to('delete_scheduled')
expect(response).to have_gitlab_http_status(:accepted)
end
+
+ context 'with container_registry_delete_repository_with_cron_worker disabled' do
+ before do
+ stub_feature_flags(container_registry_delete_repository_with_cron_worker: false)
+ end
+
+ it 'schedules removal of repository' do
+ expect(DeleteContainerRepositoryWorker).to receive(:perform_async)
+ .with(maintainer.id, root_repository.id)
+ expect { subject }.to change { root_repository.reload.status }.from(nil).to('delete_scheduled')
+
+ expect(response).to have_gitlab_http_status(:accepted)
+ end
+ end
end
end
end
diff --git a/spec/requests/api/project_import_spec.rb b/spec/requests/api/project_import_spec.rb
index 401db766589..05fe55b06a1 100644
--- a/spec/requests/api/project_import_spec.rb
+++ b/spec/requests/api/project_import_spec.rb
@@ -47,7 +47,7 @@ RSpec.describe API::ProjectImport, :aggregate_failures do
it 'executes a limited number of queries' do
control_count = ActiveRecord::QueryRecorder.new { subject }.count
- expect(control_count).to be <= 110
+ expect(control_count).to be <= 111
end
it 'schedules an import using a namespace' do
@@ -215,7 +215,7 @@ RSpec.describe API::ProjectImport, :aggregate_failures do
subject
expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response['message']).to eq('Name has already been taken')
+ expect(json_response['message']).to eq('Project namespace name has already been taken')
end
context 'when param overwrite is true' do
diff --git a/spec/requests/api/project_milestones_spec.rb b/spec/requests/api/project_milestones_spec.rb
index b23fb86a9de..8294ca143d3 100644
--- a/spec/requests/api/project_milestones_spec.rb
+++ b/spec/requests/api/project_milestones_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe API::ProjectMilestones do
let_it_be(:user) { create(:user) }
- let_it_be_with_reload(:project) { create(:project, namespace: user.namespace ) }
+ 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" }
diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb
index 6e2dd6e76a9..1d255f7c1d8 100644
--- a/spec/requests/api/project_snippets_spec.rb
+++ b/spec/requests/api/project_snippets_spec.rb
@@ -89,7 +89,7 @@ RSpec.describe API::ProjectSnippets do
expect(json_response['title']).to eq(snippet.title)
expect(json_response['description']).to eq(snippet.description)
expect(json_response['file_name']).to eq(snippet.file_name_on_repo)
- expect(json_response['files']).to eq(snippet.blobs.map { |blob| snippet_blob_file(blob) } )
+ expect(json_response['files']).to eq(snippet.blobs.map { |blob| snippet_blob_file(blob) })
expect(json_response['ssh_url_to_repo']).to eq(snippet.ssh_url_to_repo)
expect(json_response['http_url_to_repo']).to eq(snippet.http_url_to_repo)
end
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 38f7d6e3eba..3831e8e1dfe 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -169,10 +169,8 @@ RSpec.describe API::Projects do
shared_examples_for 'projects response without N + 1 queries' do |threshold|
let(:additional_project) { create(:project, :public) }
- it 'avoids N + 1 queries' do
- get api('/projects', current_user)
-
- control = ActiveRecord::QueryRecorder.new do
+ it 'avoids N + 1 queries', :use_sql_query_cache do
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
get api('/projects', current_user)
end
@@ -180,7 +178,7 @@ RSpec.describe API::Projects do
expect do
get api('/projects', current_user)
- end.not_to exceed_query_limit(control).with_threshold(threshold)
+ end.not_to exceed_all_query_limit(control).with_threshold(threshold)
end
end
@@ -209,16 +207,28 @@ RSpec.describe API::Projects do
let(:current_user) { user }
end
- it 'includes container_registry_access_level', :aggregate_failures do
- project.project_feature.update!(container_registry_access_level: ProjectFeature::DISABLED)
+ shared_examples 'includes container_registry_access_level', :aggregate_failures do
+ it do
+ project.project_feature.update!(container_registry_access_level: ProjectFeature::DISABLED)
- get api('/projects', user)
- project_response = json_response.find { |p| p['id'] == project.id }
+ get api('/projects', user)
+ project_response = json_response.find { |p| p['id'] == project.id }
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to be_an Array
- expect(project_response['container_registry_access_level']).to eq('disabled')
- expect(project_response['container_registry_enabled']).to eq(false)
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_an Array
+ expect(project_response['container_registry_access_level']).to eq('disabled')
+ expect(project_response['container_registry_enabled']).to eq(false)
+ end
+ end
+
+ include_examples 'includes container_registry_access_level'
+
+ context 'when projects_preloader_fix is disabled' do
+ before do
+ stub_feature_flags(projects_preloader_fix: false)
+ end
+
+ include_examples 'includes container_registry_access_level'
end
it 'includes releases_access_level', :aggregate_failures do
@@ -1055,7 +1065,7 @@ RSpec.describe API::Projects do
let_it_be(:admin) { create(:admin) }
- it 'avoids N+1 queries' do
+ it 'avoids N+1 queries', :use_sql_query_cache do
get api('/projects', admin)
base_project = create(:project, :public, namespace: admin.namespace)
@@ -1063,7 +1073,7 @@ RSpec.describe API::Projects do
fork_project1 = fork_project(base_project, admin, namespace: create(:user).namespace)
fork_project2 = fork_project(fork_project1, admin, namespace: create(:user).namespace)
- control = ActiveRecord::QueryRecorder.new do
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
get api('/projects', admin)
end
@@ -3428,18 +3438,6 @@ RSpec.describe API::Projects do
end
context 'when authenticated as project owner' do
- it 'updates name' do
- project_param = { name: 'bar' }
-
- put api("/projects/#{project.id}", user), params: project_param
-
- expect(response).to have_gitlab_http_status(:ok)
-
- project_param.each_pair do |k, v|
- expect(json_response[k.to_s]).to eq(v)
- end
- end
-
it 'updates visibility_level' do
project_param = { visibility: 'public' }
@@ -3797,10 +3795,16 @@ RSpec.describe API::Projects do
expect(json_response['message']['path']).to eq(['has already been taken'])
end
- it 'does not update name' do
+ it 'updates name' do
project_param = { name: 'bar' }
- put api("/projects/#{project3.id}", user4), params: project_param
- expect(response).to have_gitlab_http_status(:forbidden)
+
+ put api("/projects/#{project.id}", user), params: project_param
+
+ expect(response).to have_gitlab_http_status(:ok)
+
+ project_param.each_pair do |k, v|
+ expect(json_response[k.to_s]).to eq(v)
+ end
end
it 'does not update visibility_level' do
diff --git a/spec/requests/api/protected_branches_spec.rb b/spec/requests/api/protected_branches_spec.rb
index 9f10eb1bb9f..b46859a0e70 100644
--- a/spec/requests/api/protected_branches_spec.rb
+++ b/spec/requests/api/protected_branches_spec.rb
@@ -29,8 +29,7 @@ RSpec.describe API::ProtectedBranches do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
-
+ expect(response).to match_response_schema('protected_branches')
protected_branch_names = json_response.map { |x| x['name'] }
expect(protected_branch_names).to match_array(expected_branch_names)
end
@@ -71,6 +70,7 @@ RSpec.describe API::ProtectedBranches do
get api(route, user)
expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('protected_branch')
expect(json_response['name']).to eq(branch_name)
expect(json_response['allow_force_push']).to eq(false)
expect(json_response['push_access_levels'][0]['access_level']).to eq(::Gitlab::Access::MAINTAINER)
@@ -130,6 +130,7 @@ RSpec.describe API::ProtectedBranches do
post post_endpoint, params: { name: branch_name }
expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('protected_branch')
expect(json_response['name']).to eq(branch_name)
expect(json_response['allow_force_push']).to eq(false)
expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER)
@@ -140,6 +141,7 @@ RSpec.describe API::ProtectedBranches do
post post_endpoint, params: { name: branch_name, push_access_level: 30 }
expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('protected_branch')
expect(json_response['name']).to eq(branch_name)
expect(json_response['allow_force_push']).to eq(false)
expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::DEVELOPER)
@@ -150,6 +152,7 @@ RSpec.describe API::ProtectedBranches do
post post_endpoint, params: { name: branch_name, merge_access_level: 30 }
expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('protected_branch')
expect(json_response['name']).to eq(branch_name)
expect(json_response['allow_force_push']).to eq(false)
expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER)
@@ -160,6 +163,7 @@ RSpec.describe API::ProtectedBranches do
post post_endpoint, params: { name: branch_name, push_access_level: 30, merge_access_level: 30 }
expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('protected_branch')
expect(json_response['name']).to eq(branch_name)
expect(json_response['allow_force_push']).to eq(false)
expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::DEVELOPER)
@@ -170,6 +174,7 @@ RSpec.describe API::ProtectedBranches do
post post_endpoint, params: { name: branch_name, push_access_level: 0 }
expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('protected_branch')
expect(json_response['name']).to eq(branch_name)
expect(json_response['allow_force_push']).to eq(false)
expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::NO_ACCESS)
@@ -180,6 +185,7 @@ RSpec.describe API::ProtectedBranches do
post post_endpoint, params: { name: branch_name, merge_access_level: 0 }
expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('protected_branch')
expect(json_response['name']).to eq(branch_name)
expect(json_response['allow_force_push']).to eq(false)
expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER)
@@ -190,6 +196,7 @@ RSpec.describe API::ProtectedBranches do
post post_endpoint, params: { name: branch_name, push_access_level: 0, merge_access_level: 0 }
expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('protected_branch')
expect(json_response['name']).to eq(branch_name)
expect(json_response['allow_force_push']).to eq(false)
expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::NO_ACCESS)
@@ -200,6 +207,7 @@ RSpec.describe API::ProtectedBranches do
post post_endpoint, params: { name: branch_name, allow_force_push: true }
expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('protected_branch')
expect(json_response['name']).to eq(branch_name)
expect(json_response['allow_force_push']).to eq(true)
expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER)
@@ -246,6 +254,49 @@ RSpec.describe API::ProtectedBranches do
end
end
+ describe 'PATCH /projects/:id/protected_branches/:name' do
+ let(:route) { "/projects/#{project.id}/protected_branches/#{branch_name}" }
+
+ context 'when authenticated as a maintainer' do
+ let(:user) { maintainer }
+
+ it "updates a single branch" do
+ expect do
+ patch api(route, user), params: { allow_force_push: true }
+ end.to change { protected_branch.reload.allow_force_push }.from(false).to(true)
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
+
+ context 'when returned protected branch is invalid' do
+ let(:user) { maintainer }
+
+ before do
+ allow_next_found_instance_of(ProtectedBranch) do |instance|
+ allow(instance).to receive(:valid?).and_return(false)
+ end
+ end
+
+ it "returns a 422" do
+ expect do
+ patch api(route, user), params: { allow_force_push: true }
+ end.not_to change { protected_branch.reload.allow_force_push }
+
+ expect(response).to have_gitlab_http_status(:unprocessable_entity)
+ end
+ end
+
+ context 'when authenticated as a guest' do
+ let(:user) { guest }
+
+ it "returns a 403 error" do
+ patch api(route, user), params: { allow_force_push: true }
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+ end
+
describe "DELETE /projects/:id/protected_branches/unprotect/:branch" do
let(:user) { maintainer }
let(:delete_endpoint) { api("/projects/#{project.id}/protected_branches/#{branch_name}", user) }
diff --git a/spec/requests/api/protected_tags_spec.rb b/spec/requests/api/protected_tags_spec.rb
index 84b7df86f31..f1db39ac204 100644
--- a/spec/requests/api/protected_tags_spec.rb
+++ b/spec/requests/api/protected_tags_spec.rb
@@ -22,7 +22,7 @@ RSpec.describe API::ProtectedTags do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
- expect(json_response).to be_an Array
+ expect(response).to match_response_schema('protected_tags')
protected_tag_names = json_response.map { |x| x['name'] }
expected_tags_names = project.protected_tags.map { |x| x['name'] }
@@ -57,6 +57,7 @@ RSpec.describe API::ProtectedTags do
get api(route, user)
expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to match_response_schema('protected_tag')
expect(json_response['name']).to eq(tag_name)
expect(json_response['create_access_levels'][0]['access_level']).to eq(::Gitlab::Access::MAINTAINER)
end
@@ -108,6 +109,7 @@ RSpec.describe API::ProtectedTags do
post api("/projects/#{project.id}/protected_tags", user), params: { name: tag_name }
expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('protected_tag')
expect(json_response['name']).to eq(tag_name)
expect(json_response['create_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER)
end
@@ -117,6 +119,7 @@ RSpec.describe API::ProtectedTags do
params: { name: tag_name, create_access_level: 30 }
expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('protected_tag')
expect(json_response['name']).to eq(tag_name)
expect(json_response['create_access_levels'][0]['access_level']).to eq(Gitlab::Access::DEVELOPER)
end
@@ -126,6 +129,7 @@ RSpec.describe API::ProtectedTags do
params: { name: tag_name, create_access_level: 0 }
expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('protected_tag')
expect(json_response['name']).to eq(tag_name)
expect(json_response['create_access_levels'][0]['access_level']).to eq(Gitlab::Access::NO_ACCESS)
end
@@ -142,6 +146,7 @@ RSpec.describe API::ProtectedTags do
post api("/projects/#{project2.id}/protected_tags", user), params: { name: protected_name }
expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('protected_tag')
expect(json_response['name']).to eq(protected_name)
end
@@ -152,6 +157,7 @@ RSpec.describe API::ProtectedTags do
post api("/projects/#{project.id}/protected_tags", user), params: { name: tag_name }
expect(response).to have_gitlab_http_status(:created)
+ expect(response).to match_response_schema('protected_tag')
expect(json_response['name']).to eq(tag_name)
expect(json_response['create_access_levels'][0]['access_level']).to eq(Gitlab::Access::MAINTAINER)
end
diff --git a/spec/requests/api/pypi_packages_spec.rb b/spec/requests/api/pypi_packages_spec.rb
index 6c130bb4963..12091158a02 100644
--- a/spec/requests/api/pypi_packages_spec.rb
+++ b/spec/requests/api/pypi_packages_spec.rb
@@ -69,6 +69,7 @@ RSpec.describe API::PypiPackages do
it_behaves_like 'rejects PyPI access with unknown project id'
it_behaves_like 'deploy token for package GET requests'
it_behaves_like 'job token for package GET requests'
+ it_behaves_like 'allow access for everyone with public package_registry_access_level'
context 'with project path as id' do
let(:url) { "/projects/#{CGI.escape(project.full_path)}/packages/pypi/simple" }
@@ -130,6 +131,7 @@ RSpec.describe API::PypiPackages do
it_behaves_like 'rejects PyPI access with unknown project id'
it_behaves_like 'deploy token for package GET requests'
it_behaves_like 'job token for package GET requests'
+ it_behaves_like 'allow access for everyone with public package_registry_access_level'
context 'with project path as id' do
let(:url) { "/projects/#{CGI.escape(project.full_path)}/packages/pypi/simple/#{package.name}" }
@@ -377,6 +379,7 @@ RSpec.describe API::PypiPackages do
it_behaves_like 'pypi file download endpoint'
it_behaves_like 'rejects PyPI access with unknown project id'
+ it_behaves_like 'allow access for everyone with public package_registry_access_level'
end
end
end
diff --git a/spec/requests/api/release/links_spec.rb b/spec/requests/api/release/links_spec.rb
index 57b2e005929..38166c5ce97 100644
--- a/spec/requests/api/release/links_spec.rb
+++ b/spec/requests/api/release/links_spec.rb
@@ -81,24 +81,20 @@ RSpec.describe API::Release::Links do
end
context 'when project is public' do
- let(:project) { create(:project, :repository, :public) }
+ before do
+ project.update!(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+ end
it 'allows the request' do
get api("/projects/#{project.id}/releases/v0.1/assets/links", non_project_member)
expect(response).to have_gitlab_http_status(:ok)
end
- end
-
- context 'when project is public and the repository is private' do
- let(:project) { create(:project, :repository, :public, :repository_private) }
-
- it_behaves_like '403 response' do
- let(:request) { get api("/projects/#{project.id}/releases/v0.1/assets/links", non_project_member) }
- end
- context 'when the release does not exists' do
- let!(:release) {}
+ context 'and the releases are private' do
+ before do
+ project.project_feature.update!(releases_access_level: ProjectFeature::PRIVATE)
+ end
it_behaves_like '403 response' do
let(:request) { get api("/projects/#{project.id}/releases/v0.1/assets/links", non_project_member) }
diff --git a/spec/requests/api/resource_access_tokens_spec.rb b/spec/requests/api/resource_access_tokens_spec.rb
index d9a12e7e148..24efac3128d 100644
--- a/spec/requests/api/resource_access_tokens_spec.rb
+++ b/spec/requests/api/resource_access_tokens_spec.rb
@@ -243,65 +243,33 @@ RSpec.describe API::ResourceAccessTokens do
end
context "when the user has valid permissions" do
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- it "deletes the #{source_type} access token from the #{source_type}" do
- delete_token
-
- expect(response).to have_gitlab_http_status(:no_content)
- expect(
- Users::GhostUserMigration.where(user: project_bot,
- initiator_user: user)
- ).to be_exists
- end
-
- context "when using #{source_type} access token to DELETE other #{source_type} access token" do
- let_it_be(:other_project_bot) { create(:user, :project_bot) }
- let_it_be(:other_token) { create(:personal_access_token, user: other_project_bot) }
- let_it_be(:token_id) { other_token.id }
-
- before do
- resource.add_maintainer(other_project_bot)
- end
-
- it "deletes the #{source_type} access token from the #{source_type}" do
- delete_token
+ it "deletes the #{source_type} access token from the #{source_type}" do
+ delete_token
- expect(response).to have_gitlab_http_status(:no_content)
- expect(
- Users::GhostUserMigration.where(user: other_project_bot,
- initiator_user: user)
- ).to be_exists
- end
- end
+ expect(response).to have_gitlab_http_status(:no_content)
+ expect(
+ Users::GhostUserMigration.where(user: project_bot,
+ initiator_user: user)
+ ).to be_exists
end
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
+ context "when using #{source_type} access token to DELETE other #{source_type} access token" do
+ let_it_be(:other_project_bot) { create(:user, :project_bot) }
+ let_it_be(:other_token) { create(:personal_access_token, user: other_project_bot) }
+ let_it_be(:token_id) { other_token.id }
+
before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
+ resource.add_maintainer(other_project_bot)
end
it "deletes the #{source_type} access token from the #{source_type}" do
delete_token
expect(response).to have_gitlab_http_status(:no_content)
- expect(User.exists?(project_bot.id)).to be_falsy
- end
-
- context "when using #{source_type} access token to DELETE other #{source_type} access token" do
- let_it_be(:other_project_bot) { create(:user, :project_bot) }
- let_it_be(:other_token) { create(:personal_access_token, user: other_project_bot) }
- let_it_be(:token_id) { other_token.id }
-
- before do
- resource.add_maintainer(other_project_bot)
- end
-
- it "deletes the #{source_type} access token from the #{source_type}" do
- delete_token
-
- expect(response).to have_gitlab_http_status(:no_content)
- expect(User.exists?(other_project_bot.id)).to be_falsy
- end
+ expect(
+ Users::GhostUserMigration.where(user: other_project_bot,
+ initiator_user: user)
+ ).to be_exists
end
end
@@ -416,6 +384,41 @@ RSpec.describe API::ResourceAccessTokens do
expect(response.body).to include("scopes is missing")
end
end
+
+ context "when using invalid 'scopes'" do
+ let_it_be(:params) do
+ {
+ name: "test",
+ scopes: ["test"],
+ expires_at: 5.days.from_now
+ }
+ end
+
+ it "does not create a #{source_type} access token with invalid 'scopes'", :aggregate_failures do
+ create_token
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(response.body).to include("scopes does not have a valid value")
+ end
+ end
+
+ context "when using invalid 'access_level'" do
+ let_it_be(:params) do
+ {
+ name: "test",
+ scopes: ["api"],
+ expires_at: 5.days.from_now,
+ access_level: Gitlab::Access::NO_ACCESS
+ }
+ end
+
+ it "does not create a #{source_type} access token with invalid 'access_level'", :aggregate_failures do
+ create_token
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(response.body).to include("access_level does not have a valid value")
+ end
+ end
end
context "when trying to create a token in a different #{source_type}" do
diff --git a/spec/requests/api/rpm_project_packages_spec.rb b/spec/requests/api/rpm_project_packages_spec.rb
index 6a646c26fd2..68511795c94 100644
--- a/spec/requests/api/rpm_project_packages_spec.rb
+++ b/spec/requests/api/rpm_project_packages_spec.rb
@@ -9,7 +9,8 @@ RSpec.describe API::RpmProjectPackages do
using RSpec::Parameterized::TableSyntax
- let_it_be_with_reload(:project) { create(:project, :public) }
+ let_it_be(:group) { create(:group, :public) }
+ let_it_be_with_reload(:project) { create(:project, :public, group: group) }
let_it_be(:user) { create(:user) }
let_it_be(:personal_access_token) { create(:personal_access_token, user: user) }
let_it_be(:deploy_token) { create(:deploy_token, read_package_registry: true, write_package_registry: true) }
@@ -36,7 +37,7 @@ RSpec.describe API::RpmProjectPackages do
it_behaves_like 'returning response status', status
end
- shared_examples 'a deploy token for RPM requests' do
+ shared_examples 'a deploy token for RPM requests' do |success_status = :not_found|
context 'with deploy token headers' do
before do
project.update_column(:visibility_level, Gitlab::VisibilityLevel::PRIVATE)
@@ -45,7 +46,7 @@ RSpec.describe API::RpmProjectPackages do
let(:headers) { basic_auth_header(deploy_token.username, deploy_token.token) }
context 'when token is valid' do
- it_behaves_like 'returning response status', :not_found
+ it_behaves_like 'returning response status', success_status
end
context 'when token is invalid' do
@@ -56,7 +57,7 @@ RSpec.describe API::RpmProjectPackages do
end
end
- shared_examples 'a job token for RPM requests' do
+ shared_examples 'a job token for RPM requests' do |success_status = :not_found|
context 'with job token headers' do
let(:headers) { basic_auth_header(::Gitlab::Auth::CI_JOB_USER, job.token) }
@@ -66,7 +67,7 @@ RSpec.describe API::RpmProjectPackages do
end
context 'with valid token' do
- it_behaves_like 'returning response status', :not_found
+ it_behaves_like 'returning response status', success_status
end
context 'with invalid token' do
@@ -83,10 +84,10 @@ RSpec.describe API::RpmProjectPackages do
end
end
- shared_examples 'a user token for RPM requests' do
+ shared_examples 'a user token for RPM requests' do |success_status = :not_found|
context 'with valid project' do
where(:visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
- 'PUBLIC' | :developer | true | true | 'process rpm packages upload/download' | :not_found
+ 'PUBLIC' | :developer | true | true | 'process rpm packages upload/download' | success_status
'PUBLIC' | :guest | true | true | 'process rpm packages upload/download' | :forbidden
'PUBLIC' | :developer | true | false | 'rejects rpm packages access' | :unauthorized
'PUBLIC' | :guest | true | false | 'rejects rpm packages access' | :unauthorized
@@ -95,7 +96,7 @@ RSpec.describe API::RpmProjectPackages do
'PUBLIC' | :developer | false | false | 'rejects rpm packages access' | :unauthorized
'PUBLIC' | :guest | false | false | 'rejects rpm packages access' | :unauthorized
'PUBLIC' | :anonymous | false | true | 'process rpm packages upload/download' | :unauthorized
- 'PRIVATE' | :developer | true | true | 'process rpm packages upload/download' | :not_found
+ 'PRIVATE' | :developer | true | true | 'process rpm packages upload/download' | success_status
'PRIVATE' | :guest | true | true | 'rejects rpm packages access' | :forbidden
'PRIVATE' | :developer | true | false | 'rejects rpm packages access' | :unauthorized
'PRIVATE' | :guest | true | false | 'rejects rpm packages access' | :unauthorized
@@ -123,26 +124,31 @@ RSpec.describe API::RpmProjectPackages do
end
describe 'GET /api/v4/projects/:project_id/packages/rpm/repodata/:filename' do
- let(:url) { "/projects/#{project.id}/packages/rpm/repodata/#{package_name}" }
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: user } }
+ let(:repository_file) { create(:rpm_repository_file, project: project) }
+ let(:url) { "/projects/#{project.id}/packages/rpm/repodata/#{repository_file.file_name}" }
subject { get api(url), headers: headers }
- it_behaves_like 'a job token for RPM requests'
- it_behaves_like 'a deploy token for RPM requests'
- it_behaves_like 'a user token for RPM requests'
+ it_behaves_like 'a job token for RPM requests', :success
+ it_behaves_like 'a deploy token for RPM requests', :success
+ it_behaves_like 'a user token for RPM requests', :success
end
describe 'GET /api/v4/projects/:id/packages/rpm/:package_file_id/:filename' do
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: group } }
let(:url) { "/projects/#{project.id}/packages/rpm/#{package_file_id}/#{package_name}" }
subject { get api(url), headers: headers }
+ it_behaves_like 'a package tracking event', described_class.name, 'pull_package'
it_behaves_like 'a job token for RPM requests'
it_behaves_like 'a deploy token for RPM requests'
it_behaves_like 'a user token for RPM requests'
end
describe 'POST /api/v4/projects/:project_id/packages/rpm' do
+ let(:snowplow_gitlab_standard_context) { { project: project, namespace: group, user: user } }
let(:url) { "/projects/#{project.id}/packages/rpm" }
let(:file_upload) { fixture_file_upload('spec/fixtures/packages/rpm/hello-0.0.1-1.fc29.x86_64.rpm') }
@@ -150,25 +156,25 @@ RSpec.describe API::RpmProjectPackages do
context 'with user token' do
context 'with valid project' do
- where(:visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status) do
- 'PUBLIC' | :developer | true | true | 'process rpm packages upload/download' | :not_found
- 'PUBLIC' | :guest | true | true | 'rejects rpm packages access' | :forbidden
- 'PUBLIC' | :developer | true | false | 'rejects rpm packages access' | :unauthorized
- 'PUBLIC' | :guest | true | false | 'rejects rpm packages access' | :unauthorized
- 'PUBLIC' | :developer | false | true | 'rejects rpm packages access' | :not_found
- 'PUBLIC' | :guest | false | true | 'rejects rpm packages access' | :not_found
- 'PUBLIC' | :developer | false | false | 'rejects rpm packages access' | :unauthorized
- 'PUBLIC' | :guest | false | false | 'rejects rpm packages access' | :unauthorized
- 'PUBLIC' | :anonymous | false | true | 'rejects rpm packages access' | :unauthorized
- 'PRIVATE' | :developer | true | true | 'process rpm packages upload/download' | :not_found
- 'PRIVATE' | :guest | true | true | 'rejects rpm packages access' | :forbidden
- 'PRIVATE' | :developer | true | false | 'rejects rpm packages access' | :unauthorized
- 'PRIVATE' | :guest | true | false | 'rejects rpm packages access' | :unauthorized
- 'PRIVATE' | :developer | false | true | 'rejects rpm packages access' | :not_found
- 'PRIVATE' | :guest | false | true | 'rejects rpm packages access' | :not_found
- 'PRIVATE' | :developer | false | false | 'rejects rpm packages access' | :unauthorized
- 'PRIVATE' | :guest | false | false | 'rejects rpm packages access' | :unauthorized
- 'PRIVATE' | :anonymous | false | true | 'rejects rpm packages access' | :unauthorized
+ where(:visibility_level, :user_role, :member, :user_token, :shared_examples_name, :expected_status, :tracked) do
+ 'PUBLIC' | :developer | true | true | 'process rpm packages upload/download' | :not_found | true
+ 'PUBLIC' | :guest | true | true | 'rejects rpm packages access' | :forbidden | false
+ 'PUBLIC' | :developer | true | false | 'rejects rpm packages access' | :unauthorized | false
+ 'PUBLIC' | :guest | true | false | 'rejects rpm packages access' | :unauthorized | false
+ 'PUBLIC' | :developer | false | true | 'rejects rpm packages access' | :not_found | false
+ 'PUBLIC' | :guest | false | true | 'rejects rpm packages access' | :not_found | false
+ 'PUBLIC' | :developer | false | false | 'rejects rpm packages access' | :unauthorized | false
+ 'PUBLIC' | :guest | false | false | 'rejects rpm packages access' | :unauthorized | false
+ 'PUBLIC' | :anonymous | false | true | 'rejects rpm packages access' | :unauthorized | false
+ 'PRIVATE' | :developer | true | true | 'process rpm packages upload/download' | :not_found | true
+ 'PRIVATE' | :guest | true | true | 'rejects rpm packages access' | :forbidden | false
+ 'PRIVATE' | :developer | true | false | 'rejects rpm packages access' | :unauthorized | false
+ 'PRIVATE' | :guest | true | false | 'rejects rpm packages access' | :unauthorized | false
+ 'PRIVATE' | :developer | false | true | 'rejects rpm packages access' | :not_found | false
+ 'PRIVATE' | :guest | false | true | 'rejects rpm packages access' | :not_found | false
+ 'PRIVATE' | :developer | false | false | 'rejects rpm packages access' | :unauthorized | false
+ 'PRIVATE' | :guest | false | false | 'rejects rpm packages access' | :unauthorized | false
+ 'PRIVATE' | :anonymous | false | true | 'rejects rpm packages access' | :unauthorized | false
end
with_them do
@@ -180,6 +186,8 @@ RSpec.describe API::RpmProjectPackages do
project.send("add_#{user_role}", user) if member && user_role != :anonymous
end
+ tracking_example = params[:tracked] ? 'a package tracking event' : 'not a package tracking event'
+ it_behaves_like tracking_example, described_class.name, 'push_package'
it_behaves_like params[:shared_examples_name], params[:expected_status]
end
end
diff --git a/spec/requests/api/rubygem_packages_spec.rb b/spec/requests/api/rubygem_packages_spec.rb
index f0408d94137..a7d461781b8 100644
--- a/spec/requests/api/rubygem_packages_spec.rb
+++ b/spec/requests/api/rubygem_packages_spec.rb
@@ -325,9 +325,10 @@ RSpec.describe API::RubygemPackages do
let(:headers) { user_headers.merge(workhorse_headers) }
let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: snowplow_user } }
let(:snowplow_user) do
- if token_type == :deploy_token
+ case token_type
+ when :deploy_token
deploy_token
- elsif token_type == :job_token
+ when :job_token
job.user
else
user
diff --git a/spec/requests/api/search_spec.rb b/spec/requests/api/search_spec.rb
index 05f38aff6ab..60acf6b71dd 100644
--- a/spec/requests/api/search_spec.rb
+++ b/spec/requests/api/search_spec.rb
@@ -29,6 +29,19 @@ RSpec.describe API::Search do
end
end
+ shared_examples 'apdex recorded' do |scope:, level:, search: ''|
+ it 'increments the custom search sli apdex' do
+ expect(Gitlab::Metrics::GlobalSearchSlis).to receive(:record_apdex).with(
+ elapsed: a_kind_of(Numeric),
+ search_scope: scope,
+ search_type: 'basic',
+ search_level: level
+ )
+
+ get api(endpoint, user), params: { scope: scope, search: search }
+ end
+ end
+
shared_examples 'orderable by created_at' do |scope:|
it 'allows ordering results by created_at asc' do
get api(endpoint, user), params: { scope: scope, search: 'sortable', order_by: 'created_at', sort: 'asc' }
@@ -172,6 +185,8 @@ RSpec.describe API::Search do
it_behaves_like 'pagination', scope: :projects
it_behaves_like 'ping counters', scope: :projects
+
+ it_behaves_like 'apdex recorded', scope: 'projects', level: 'global'
end
context 'for issues scope' do
@@ -186,6 +201,8 @@ RSpec.describe API::Search do
it_behaves_like 'ping counters', scope: :issues
+ it_behaves_like 'apdex recorded', scope: 'issues', level: 'global'
+
it_behaves_like 'issues orderable by created_at'
describe 'pagination' do
@@ -248,6 +265,8 @@ RSpec.describe API::Search do
it_behaves_like 'ping counters', scope: :merge_requests
+ it_behaves_like 'apdex recorded', scope: 'merge_requests', level: 'global'
+
it_behaves_like 'merge_requests orderable by created_at'
describe 'pagination' do
@@ -293,6 +312,8 @@ RSpec.describe API::Search do
it_behaves_like 'ping counters', scope: :milestones
+ it_behaves_like 'apdex recorded', scope: 'milestones', level: 'global'
+
describe 'pagination' do
before do
create(:milestone, project: project, title: 'another milestone')
@@ -330,6 +351,8 @@ RSpec.describe API::Search do
it_behaves_like 'pagination', scope: :users
it_behaves_like 'ping counters', scope: :users
+
+ it_behaves_like 'apdex recorded', scope: 'users', level: 'global'
end
context 'for snippet_titles scope' do
@@ -343,6 +366,8 @@ RSpec.describe API::Search do
it_behaves_like 'ping counters', scope: :snippet_titles
+ it_behaves_like 'apdex recorded', scope: 'snippet_titles', level: 'global'
+
describe 'pagination' do
before do
create(:snippet, :public, title: 'another snippet', content: 'snippet content')
@@ -352,17 +377,6 @@ RSpec.describe API::Search do
end
end
- it 'increments the custom search sli apdex' do
- expect(Gitlab::Metrics::GlobalSearchSlis).to receive(:record_apdex).with(
- elapsed: a_kind_of(Numeric),
- search_scope: 'issues',
- search_type: 'basic',
- search_level: 'global'
- )
-
- get api(endpoint, user), params: { scope: 'issues', search: 'john doe' }
- end
-
it 'increments the custom search sli error rate with error false if no error occurred' do
expect(Gitlab::Metrics::GlobalSearchSlis).to receive(:record_error_rate).with(
error: false,
@@ -466,6 +480,8 @@ RSpec.describe API::Search do
it_behaves_like 'pagination', scope: :projects
it_behaves_like 'ping counters', scope: :projects
+
+ it_behaves_like 'apdex recorded', scope: 'projects', level: 'group'
end
context 'for issues scope' do
@@ -479,6 +495,8 @@ RSpec.describe API::Search do
it_behaves_like 'ping counters', scope: :issues
+ it_behaves_like 'apdex recorded', scope: 'issues', level: 'group'
+
it_behaves_like 'issues orderable by created_at'
describe 'pagination' do
@@ -501,6 +519,8 @@ RSpec.describe API::Search do
it_behaves_like 'ping counters', scope: :merge_requests
+ it_behaves_like 'apdex recorded', scope: 'merge_requests', level: 'group'
+
it_behaves_like 'merge_requests orderable by created_at'
describe 'pagination' do
@@ -523,6 +543,8 @@ RSpec.describe API::Search do
it_behaves_like 'ping counters', scope: :milestones
+ it_behaves_like 'apdex recorded', scope: 'milestones', level: 'group'
+
describe 'pagination' do
before do
create(:milestone, project: project, title: 'another milestone')
@@ -556,6 +578,8 @@ RSpec.describe API::Search do
it_behaves_like 'ping counters', scope: :users
+ it_behaves_like 'apdex recorded', scope: 'users', level: 'group'
+
describe 'pagination' do
before do
create(:group_member, :developer, group: group)
@@ -645,6 +669,8 @@ RSpec.describe API::Search do
it_behaves_like 'issues orderable by created_at'
+ it_behaves_like 'apdex recorded', scope: 'issues', level: 'project'
+
describe 'pagination' do
before do
create(:issue, project: project, title: 'another issue')
@@ -677,6 +703,8 @@ RSpec.describe API::Search do
it_behaves_like 'merge_requests orderable by created_at'
+ it_behaves_like 'apdex recorded', scope: 'merge_requests', level: 'project'
+
describe 'pagination' do
before do
create(:merge_request, source_project: repo_project, title: 'another mr', target_branch: 'another_branch')
@@ -700,6 +728,8 @@ RSpec.describe API::Search do
it_behaves_like 'ping counters', scope: :milestones
+ it_behaves_like 'apdex recorded', scope: 'milestones', level: 'project'
+
describe 'pagination' do
before do
create(:milestone, project: project, title: 'another milestone')
@@ -737,6 +767,8 @@ RSpec.describe API::Search do
it_behaves_like 'ping counters', scope: :users
+ it_behaves_like 'apdex recorded', scope: 'users', level: 'project'
+
describe 'pagination' do
before do
create(:project_member, :developer, project: project)
@@ -757,6 +789,8 @@ RSpec.describe API::Search do
it_behaves_like 'ping counters', scope: :notes
+ it_behaves_like 'apdex recorded', scope: 'notes', level: 'project'
+
describe 'pagination' do
before do
mr = create(:merge_request, source_project: project, target_branch: 'another_branch')
@@ -780,6 +814,8 @@ RSpec.describe API::Search do
it_behaves_like 'ping counters', scope: :wiki_blobs
+ it_behaves_like 'apdex recorded', scope: 'wiki_blobs', level: 'project'
+
describe 'pagination' do
before do
create(:wiki_page, wiki: wiki, title: 'home 2', content: 'Another page')
@@ -802,6 +838,8 @@ RSpec.describe API::Search do
it_behaves_like 'ping counters', scope: :commits
+ it_behaves_like 'apdex recorded', scope: 'commits', level: 'project'
+
describe 'pipeline visibility' do
shared_examples 'pipeline information visible' do
it 'contains status and last_pipeline' do
@@ -899,6 +937,8 @@ RSpec.describe API::Search do
end
it_behaves_like 'response is correct', schema: 'public_api/v4/commits_details'
+
+ it_behaves_like 'apdex recorded', scope: 'commits', level: 'project'
end
context 'for blobs scope' do
@@ -914,6 +954,8 @@ RSpec.describe API::Search do
it_behaves_like 'ping counters', scope: :blobs
+ it_behaves_like 'apdex recorded', scope: 'blobs', level: 'project'
+
context 'filters' do
it 'by filename' do
get api(endpoint, user), params: { scope: 'blobs', search: 'mon filename:PROCESS.md' }
diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb
index 031bcb612f4..9408d1cc248 100644
--- a/spec/requests/api/snippets_spec.rb
+++ b/spec/requests/api/snippets_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe API::Snippets, factory_default: :keep do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
- expect(json_response.map { |snippet| snippet['id'] } ).to contain_exactly(
+ expect(json_response.map { |snippet| snippet['id'] }).to contain_exactly(
public_snippet.id,
internal_snippet.id,
private_snippet.id)
@@ -75,7 +75,7 @@ RSpec.describe API::Snippets, factory_default: :keep do
it 'returns snippets available for user in given time range' do
get api(path, personal_access_token: user_token)
- expect(json_response.map { |snippet| snippet['id'] } ).to contain_exactly(
+ expect(json_response.map { |snippet| snippet['id'] }).to contain_exactly(
private_snippet_in_time_range1.id,
private_snippet_in_time_range2.id)
end
@@ -99,10 +99,10 @@ RSpec.describe API::Snippets, factory_default: :keep do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response).to be_an Array
- expect(json_response.map { |snippet| snippet['id'] } ).to contain_exactly(
+ expect(json_response.map { |snippet| snippet['id'] }).to contain_exactly(
public_snippet.id,
public_snippet_other.id)
- expect(json_response.map { |snippet| snippet['web_url'] } ).to contain_exactly(
+ expect(json_response.map { |snippet| snippet['web_url'] }).to contain_exactly(
"http://localhost/-/snippets/#{public_snippet.id}",
"http://localhost/-/snippets/#{public_snippet_other.id}")
expect(json_response[0]['files'].first).to eq snippet_blob_file(public_snippet_other.blobs.first)
@@ -126,7 +126,7 @@ RSpec.describe API::Snippets, factory_default: :keep do
it 'returns public snippets available to user in given time range' do
get api(path, personal_access_token: user_token)
- expect(json_response.map { |snippet| snippet['id'] } ).to contain_exactly(
+ expect(json_response.map { |snippet| snippet['id'] }).to contain_exactly(
public_snippet_in_time_range.id)
end
end
diff --git a/spec/requests/api/submodules_spec.rb b/spec/requests/api/submodules_spec.rb
index 6b141d6d036..9840476ca27 100644
--- a/spec/requests/api/submodules_spec.rb
+++ b/spec/requests/api/submodules_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe API::Submodules do
let(:user) { create(:user) }
- let!(:project) { create(:project, :repository, namespace: user.namespace ) }
+ let!(:project) { create(:project, :repository, namespace: user.namespace) }
let(:guest) { create(:user) { |u| project.add_guest(u) } }
let(:submodule) { 'six' }
let(:commit_sha) { 'e25eda1fece24ac7a03624ed1320f82396f35bd8' }
diff --git a/spec/requests/api/suggestions_spec.rb b/spec/requests/api/suggestions_spec.rb
index 2393a268693..dfc5d169af6 100644
--- a/spec/requests/api/suggestions_spec.rb
+++ b/spec/requests/api/suggestions_spec.rb
@@ -91,7 +91,7 @@ RSpec.describe API::Suggestions do
end
context 'when suggestion is not found' do
- let(:url) { "/suggestions/foo-123/apply" }
+ let(:url) { "/suggestions/9999/apply" }
it 'renders a not found error and returns json content' do
project.add_maintainer(user)
@@ -103,6 +103,19 @@ RSpec.describe API::Suggestions do
end
end
+ context 'when suggestion ID is not valid' do
+ let(:url) { "/suggestions/foo-123/apply" }
+
+ it 'renders a not found error and returns json content' do
+ project.add_maintainer(user)
+
+ put api(url, user)
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+ expect(json_response).to eq({ 'error' => 'id is invalid' })
+ end
+ end
+
context 'when unauthorized' do
it 'renders a forbidden error and returns json content' do
project.add_reporter(user)
diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb
index c635d73efe3..3f2ca2a0938 100644
--- a/spec/requests/api/tags_spec.rb
+++ b/spec/requests/api/tags_spec.rb
@@ -71,7 +71,7 @@ RSpec.describe API::Tags do
context 'searching' do
it 'only returns searched tags' do
- get api("#{route}", user), params: { search: 'v1.1.0' }
+ get api(route.to_s, user), params: { search: 'v1.1.0' }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
diff --git a/spec/requests/api/terraform/modules/v1/packages_spec.rb b/spec/requests/api/terraform/modules/v1/packages_spec.rb
index dff44a45de4..ae61017f5bb 100644
--- a/spec/requests/api/terraform/modules/v1/packages_spec.rb
+++ b/spec/requests/api/terraform/modules/v1/packages_spec.rb
@@ -585,9 +585,10 @@ RSpec.describe API::Terraform::Modules::V1::Packages do
let(:headers) { user_headers.merge(workhorse_headers) }
let(:snowplow_gitlab_standard_context) { { project: project, namespace: project.namespace, user: snowplow_user } }
let(:snowplow_user) do
- if token_type == :deploy_token
+ case token_type
+ when :deploy_token
deploy_token
- elsif token_type == :job_token
+ when :job_token
job.user
else
user
diff --git a/spec/requests/api/terraform/state_spec.rb b/spec/requests/api/terraform/state_spec.rb
index e8458db4a4d..38b08b4e214 100644
--- a/spec/requests/api/terraform/state_spec.rb
+++ b/spec/requests/api/terraform/state_spec.rb
@@ -46,26 +46,19 @@ RSpec.describe API::Terraform::State, :snowplow do
let(:expected_value) { instance_of(Integer) }
end
- it 'tracks Snowplow event' do
- request
-
- expect_snowplow_event(
- category: described_class.to_s,
- action: 'p_terraform_state_api_unique_users',
- namespace: project.namespace.reload,
- user: current_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
- request
-
- expect_no_snowplow_event
+ 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' }
+ let(:namespace) { project.namespace.reload }
+ let(:user) { current_user }
+ let(:context) do
+ payload = Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll,
+ event: 'p_terraform_state_api_unique_users').to_context
+ [Gitlab::Json.dump(payload)]
end
end
end
@@ -318,7 +311,7 @@ RSpec.describe API::Terraform::State, :snowplow do
Version: '0.1',
Operation: 'OperationTypePlan',
Info: '',
- Who: "#{current_user.username}",
+ Who: current_user.username.to_s,
Created: Time.now.utc.iso8601(6),
Path: ''
}
@@ -365,7 +358,7 @@ RSpec.describe API::Terraform::State, :snowplow do
Version: '0.1',
Operation: 'OperationTypePlan',
Info: '',
- Who: "#{current_user.username}",
+ Who: current_user.username.to_s,
Created: Time.now.utc.iso8601(6),
Path: ''
}
diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb
index 0fcb6412a2d..7a626ee4d29 100644
--- a/spec/requests/api/todos_spec.rb
+++ b/spec/requests/api/todos_spec.rb
@@ -231,7 +231,7 @@ RSpec.describe API::Todos do
create(:on_commit_todo, project: new_todo.project, author: author_1, user: john_doe, target: merge_request_3)
create(:todo, project: new_todo.project, author: author_2, user: john_doe, target: merge_request_3)
- expect { get api('/todos', john_doe) }.not_to exceed_query_limit(control1).with_threshold(4)
+ expect { get api('/todos', john_doe) }.not_to exceed_query_limit(control1).with_threshold(5)
control2 = ActiveRecord::QueryRecorder.new { get api('/todos', john_doe) }
create_issue_todo_for(john_doe)
diff --git a/spec/requests/api/unleash_spec.rb b/spec/requests/api/unleash_spec.rb
index 51c567309b7..4d382f91023 100644
--- a/spec/requests/api/unleash_spec.rb
+++ b/spec/requests/api/unleash_spec.rb
@@ -202,18 +202,6 @@ RSpec.describe API::Unleash do
3.times { get api(features_url), params: params, headers: headers }
end
-
- context 'when cache_unleash_client_api is disabled' do
- before do
- stub_feature_flags(cache_unleash_client_api: false)
- end
-
- it 'serializes feature flags every time' do
- expect(::API::Entities::UnleashFeature).to receive(:represent).exactly(5).times
-
- 5.times { get api(features_url), params: params, headers: headers }
- end
- end
end
context 'with version 2 feature flags' do
diff --git a/spec/requests/api/user_counts_spec.rb b/spec/requests/api/user_counts_spec.rb
index ab2aa87d1b7..369ae49de08 100644
--- a/spec/requests/api/user_counts_spec.rb
+++ b/spec/requests/api/user_counts_spec.rb
@@ -26,24 +26,22 @@ RSpec.describe API::UserCounts do
expect(json_response['assigned_issues']).to eq(1)
end
- context 'merge requests' do
- it 'returns assigned MR counts for current user' do
- get api('/user_counts', user)
+ it 'returns assigned MR counts for current user' do
+ get api('/user_counts', user)
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to be_a Hash
- expect(json_response['merge_requests']).to eq(1)
- end
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_a Hash
+ expect(json_response['merge_requests']).to eq(1)
+ end
- it 'updates the mr count when a new mr is assigned' do
- create(:merge_request, source_project: project, author: user, assignees: [user])
+ it 'updates the mr count when a new mr is assigned' do
+ create(:merge_request, source_project: project, author: user, assignees: [user])
- get api('/user_counts', user)
+ get api('/user_counts', user)
- expect(response).to have_gitlab_http_status(:ok)
- expect(json_response).to be_a Hash
- expect(json_response['merge_requests']).to eq(2)
- end
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_a Hash
+ expect(json_response['merge_requests']).to eq(2)
end
it 'returns pending todo counts for current_user' do
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 1b0a27e78e3..6688a998a1a 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -1291,6 +1291,20 @@ RSpec.describe API::Users do
.to eq([Gitlab::PathRegex.namespace_format_message])
end
+ it 'tracks weak password errors' do
+ attributes = attributes_for(:user).merge({ password: "password" })
+ post api('/users', admin), params: attributes
+
+ expect(json_response['message']['password'])
+ .to eq(['must not contain commonly used combinations of words and letters'])
+ expect_snowplow_event(
+ category: 'Gitlab::Tracking::Helpers::WeakPasswordErrorEvent',
+ action: 'track_weak_password_error',
+ controller: 'API::Users',
+ method: 'create'
+ )
+ end
+
it "is not available for non admin users" do
post api("/users", user), params: attributes_for(:user)
expect(response).to have_gitlab_http_status(:forbidden)
@@ -1492,6 +1506,21 @@ RSpec.describe API::Users do
.not_to have_enqueued_mail(DeviseMailer, :password_change)
end
end
+
+ context 'with a weak password' do
+ it 'tracks weak password errors' do
+ update_password(user, admin, "password")
+
+ expect(json_response['message']['password'])
+ .to eq(['must not contain commonly used combinations of words and letters'])
+ expect_snowplow_event(
+ category: 'Gitlab::Tracking::Helpers::WeakPasswordErrorEvent',
+ action: 'track_weak_password_error',
+ controller: 'API::Users',
+ method: 'update'
+ )
+ end
+ end
end
it "updates user with new bio" do
@@ -2535,32 +2564,12 @@ RSpec.describe API::Users do
describe "DELETE /users/:id" do
let_it_be(:issue) { create(:issue, author: user) }
- context 'user deletion' do
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- it "deletes user", :sidekiq_inline do
- perform_enqueued_jobs { delete api("/users/#{user.id}", admin) }
-
- expect(response).to have_gitlab_http_status(:no_content)
- expect(Users::GhostUserMigration.where(user: user,
- initiator_user: admin)).to be_exists
- end
- end
-
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
- end
-
- it "deletes user", :sidekiq_inline do
- namespace_id = user.namespace.id
-
- perform_enqueued_jobs { delete api("/users/#{user.id}", admin) }
+ it "deletes user", :sidekiq_inline do
+ perform_enqueued_jobs { delete api("/users/#{user.id}", admin) }
- expect(response).to have_gitlab_http_status(:no_content)
- expect { User.find(user.id) }.to raise_error ActiveRecord::RecordNotFound
- expect { Namespace.find(namespace_id) }.to raise_error ActiveRecord::RecordNotFound
- end
- end
+ expect(response).to have_gitlab_http_status(:no_content)
+ expect(Users::GhostUserMigration.where(user: user,
+ initiator_user: admin)).to be_exists
end
context "sole owner of a group" do
@@ -2624,55 +2633,26 @@ RSpec.describe API::Users do
expect(response).to have_gitlab_http_status(:not_found)
end
- context 'hard delete' do
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- context "hard delete disabled" do
- it "moves contributions to the ghost user", :sidekiq_might_not_need_inline do
- perform_enqueued_jobs { delete api("/users/#{user.id}", admin) }
-
- expect(response).to have_gitlab_http_status(:no_content)
- expect(issue.reload).to be_persisted
- expect(Users::GhostUserMigration.where(user: user,
- initiator_user: admin,
- hard_delete: false)).to be_exists
- end
- end
-
- context "hard delete enabled" do
- it "removes contributions", :sidekiq_might_not_need_inline do
- perform_enqueued_jobs { delete api("/users/#{user.id}?hard_delete=true", admin) }
+ context "hard delete disabled" do
+ it "moves contributions to the ghost user", :sidekiq_might_not_need_inline do
+ perform_enqueued_jobs { delete api("/users/#{user.id}", admin) }
- expect(response).to have_gitlab_http_status(:no_content)
- expect(Users::GhostUserMigration.where(user: user,
- initiator_user: admin,
- hard_delete: true)).to be_exists
- end
- end
+ expect(response).to have_gitlab_http_status(:no_content)
+ expect(issue.reload).to be_persisted
+ expect(Users::GhostUserMigration.where(user: user,
+ initiator_user: admin,
+ hard_delete: false)).to be_exists
end
+ end
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
- end
-
- context "hard delete disabled" do
- it "moves contributions to the ghost user", :sidekiq_might_not_need_inline do
- perform_enqueued_jobs { delete api("/users/#{user.id}", admin) }
-
- expect(response).to have_gitlab_http_status(:no_content)
- expect(issue.reload).to be_persisted
- expect(issue.author.ghost?).to be_truthy
- end
- end
-
- context "hard delete enabled" do
- it "removes contributions", :sidekiq_might_not_need_inline do
- perform_enqueued_jobs { delete api("/users/#{user.id}?hard_delete=true", admin) }
+ context "hard delete enabled" do
+ it "removes contributions", :sidekiq_might_not_need_inline do
+ perform_enqueued_jobs { delete api("/users/#{user.id}?hard_delete=true", admin) }
- expect(response).to have_gitlab_http_status(:no_content)
- expect(Issue.exists?(issue.id)).to be_falsy
- end
- end
+ expect(response).to have_gitlab_http_status(:no_content)
+ expect(Users::GhostUserMigration.where(user: user,
+ initiator_user: admin,
+ hard_delete: true)).to be_exists
end
end
end
@@ -4395,6 +4375,74 @@ RSpec.describe API::Users do
end
end
+ describe 'GET /users/:id/associations_count' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :public, group: group) }
+ let(:associations) do
+ {
+ groups_count: 1,
+ projects_count: 1,
+ issues_count: 2,
+ merge_requests_count: 1
+ }.as_json
+ end
+
+ before :all do
+ group.add_member(user, Gitlab::Access::OWNER)
+ project.add_member(user, Gitlab::Access::OWNER)
+ create(:merge_request, source_project: project, source_branch: "my-personal-branch-1", author: user)
+ create_list(:issue, 2, project: project, author: user)
+ end
+
+ context 'as an unauthorized user' do
+ it 'returns 401 unauthorized' do
+ get api("/users/#{user.id}/associations_count", nil)
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ context 'as a non-admin user' do
+ context 'with a different user id' do
+ it 'returns 403 Forbidden' do
+ get api("/users/#{omniauth_user.id}/associations_count", user)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'with the current user id' do
+ it 'returns valid JSON response' do
+ get api("/users/#{user.id}/associations_count", user)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_a Hash
+ expect(json_response).to match(associations)
+ end
+ end
+ end
+
+ context 'as an admin user' do
+ context 'with invalid user id' do
+ it 'returns 404 User Not Found' do
+ get api("/users/#{non_existing_record_id}/associations_count", admin)
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'with valid user id' do
+ it 'returns valid JSON response' do
+ get api("/users/#{user.id}/associations_count", admin)
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_a Hash
+ expect(json_response).to match(associations)
+ end
+ end
+ end
+ end
+
it_behaves_like 'custom attributes endpoints', 'users' do
let(:attributable) { user }
let(:other_attributable) { admin }
diff --git a/spec/requests/groups/observability_controller_spec.rb b/spec/requests/groups/observability_controller_spec.rb
index 9be013d4385..a08231fe939 100644
--- a/spec/requests/groups/observability_controller_spec.rb
+++ b/spec/requests/groups/observability_controller_spec.rb
@@ -8,23 +8,16 @@ RSpec.describe Groups::ObservabilityController do
let_it_be(:group) { create(:group) }
let_it_be(:user) { create(:user) }
- subject do
- get group_observability_index_path(group)
- response
- end
+ let(:observability_url) { Gitlab::Observability.observability_url }
+ let(:expected_observability_path) { "/" }
- describe 'GET #index' do
- context 'when user is not authenticated' do
- it 'returns 404' do
- expect(subject).to have_gitlab_http_status(:not_found)
- end
+ shared_examples 'observability route request' do
+ subject do
+ get path
+ response
end
- context 'when observability url is missing' do
- before do
- allow(described_class).to receive(:observability_url).and_return("")
- end
-
+ context 'when user is not authenticated' do
it 'returns 404' do
expect(subject).to have_gitlab_http_status(:not_found)
end
@@ -46,6 +39,16 @@ RSpec.describe Groups::ObservabilityController do
group.add_developer(user)
end
+ context 'when observability url is missing' do
+ before do
+ allow(Gitlab::Observability).to receive(:observability_url).and_return("")
+ end
+
+ it 'returns 404' do
+ expect(subject).to have_gitlab_http_status(:not_found)
+ end
+ end
+
it 'returns 200' do
expect(subject).to have_gitlab_http_status(:ok)
end
@@ -55,135 +58,112 @@ RSpec.describe Groups::ObservabilityController do
expect(subject).to render_template("layouts/fullscreen")
expect(subject).not_to render_template('layouts/nav/breadcrumbs')
expect(subject).to render_template("nav/sidebar/_group")
+ expect(subject).to render_template("groups/observability/observability")
end
- describe 'iframe' do
- subject do
- get group_observability_index_path(group)
- Nokogiri::HTML.parse(response.body).at_css('iframe#observability-ui-iframe')
- end
-
- it 'sets the iframe src to the proper URL' do
- expect(subject.attributes['src'].value).to eq("https://observe.gitlab.com/-/#{group.id}")
- end
-
- it 'when the env is staging, sets the iframe src to the proper URL' do
- stub_config_setting(url: Gitlab::Saas.staging_com_url)
- expect(subject.attributes['src'].value).to eq("https://staging.observe.gitlab.com/-/#{group.id}")
- end
-
- it 'overrides the iframe src url if specified by OVERRIDE_OBSERVABILITY_URL env' do
- stub_env('OVERRIDE_OBSERVABILITY_URL', 'http://foo.test')
-
- expect(subject.attributes['src'].value).to eq("http://foo.test/-/#{group.id}")
- end
+ it 'renders the js-observability-app element correctly' do
+ element = Nokogiri::HTML.parse(subject.body).at_css('#js-observability-app')
+ expect(element.attributes['data-observability-iframe-src'].value).to eq(expected_observability_path)
end
+ end
+ end
- describe 'CSP' do
- before do
- setup_existing_csp_for_controller(described_class, csp)
- end
+ describe 'GET #dashboards' do
+ let(:path) { group_observability_dashboards_path(group) }
+ let(:expected_observability_path) { "#{observability_url}/#{group.id}/" }
- subject do
- get group_observability_index_path(group)
- response.headers['Content-Security-Policy']
- end
+ it_behaves_like 'observability route request'
+ end
- context 'when there is no CSP config' do
- let(:csp) { ActionDispatch::ContentSecurityPolicy.new }
+ describe 'GET #manage' do
+ let(:path) { group_observability_manage_path(group) }
+ let(:expected_observability_path) { "#{observability_url}/#{group.id}/dashboards" }
- it 'does not add any csp header' do
- expect(subject).to be_blank
- end
- end
+ it_behaves_like 'observability route request'
+ end
- context 'when frame-src exists in the CSP config' do
- let(:csp) do
- ActionDispatch::ContentSecurityPolicy.new do |p|
- p.frame_src 'https://something.test'
- end
- end
+ describe 'GET #explore' do
+ let(:path) { group_observability_explore_path(group) }
+ let(:expected_observability_path) { "#{observability_url}/#{group.id}/explore" }
- it 'appends the proper url to frame-src CSP directives' do
- expect(subject).to include(
- "frame-src https://something.test https://observe.gitlab.com 'self'")
- end
+ it_behaves_like 'observability route request'
+ end
- it 'appends the proper url to frame-src CSP directives when Gilab.staging?' do
- stub_config_setting(url: Gitlab::Saas.staging_com_url)
+ describe 'CSP' do
+ before do
+ setup_csp_for_controller(described_class, csp)
+ end
- expect(subject).to include(
- "frame-src https://something.test https://staging.observe.gitlab.com 'self'")
- end
+ subject do
+ get group_observability_dashboards_path(group)
+ response.headers['Content-Security-Policy']
+ end
- it 'appends the proper url to frame-src CSP directives when OVERRIDE_OBSERVABILITY_URL is specified' do
- stub_env('OVERRIDE_OBSERVABILITY_URL', 'http://foo.test')
+ context 'when there is no CSP config' do
+ let(:csp) { ActionDispatch::ContentSecurityPolicy.new }
- expect(subject).to include(
- "frame-src https://something.test http://foo.test 'self'")
- end
- end
+ it 'does not add any csp header' do
+ expect(subject).to be_blank
+ end
+ end
- context 'when self is already present in the policy' do
- let(:csp) do
- ActionDispatch::ContentSecurityPolicy.new do |p|
- p.frame_src "'self'"
- end
- end
-
- it 'does not append self again' do
- expect(subject).to include(
- "frame-src 'self' https://observe.gitlab.com;")
- end
+ context 'when frame-src exists in the CSP config' do
+ let(:csp) do
+ ActionDispatch::ContentSecurityPolicy.new do |p|
+ p.frame_src 'https://something.test'
end
+ end
- context 'when default-src exists in the CSP config' do
- let(:csp) do
- ActionDispatch::ContentSecurityPolicy.new do |p|
- p.default_src 'https://something.test'
- end
- end
+ it 'appends the proper url to frame-src CSP directives' do
+ expect(subject).to include(
+ "frame-src https://something.test #{observability_url} 'self'")
+ end
+ end
- it 'does not change default-src' do
- expect(subject).to include(
- "default-src https://something.test;")
- end
+ context 'when self is already present in the policy' do
+ let(:csp) do
+ ActionDispatch::ContentSecurityPolicy.new do |p|
+ p.frame_src "'self'"
+ end
+ end
- it 'appends the proper url to frame-src CSP directives' do
- expect(subject).to include(
- "frame-src https://something.test https://observe.gitlab.com 'self'")
- end
+ it 'does not append self again' do
+ expect(subject).to include(
+ "frame-src 'self' #{observability_url};")
+ end
+ end
- it 'appends the proper url to frame-src CSP directives when Gilab.staging?' do
- stub_config_setting(url: Gitlab::Saas.staging_com_url)
+ context 'when default-src exists in the CSP config' do
+ let(:csp) do
+ ActionDispatch::ContentSecurityPolicy.new do |p|
+ p.default_src 'https://something.test'
+ end
+ end
- expect(subject).to include(
- "frame-src https://something.test https://staging.observe.gitlab.com 'self'")
- end
+ it 'does not change default-src' do
+ expect(subject).to include(
+ "default-src https://something.test;")
+ end
- it 'appends the proper url to frame-src CSP directives when OVERRIDE_OBSERVABILITY_URL is specified' do
- stub_env('OVERRIDE_OBSERVABILITY_URL', 'http://foo.test')
+ it 'appends the proper url to frame-src CSP directives' do
+ expect(subject).to include(
+ "frame-src https://something.test #{observability_url} 'self'")
+ end
+ end
- expect(subject).to include(
- "frame-src https://something.test http://foo.test 'self'")
- end
+ context 'when frame-src and default-src exist in the CSP config' do
+ let(:csp) do
+ ActionDispatch::ContentSecurityPolicy.new do |p|
+ p.default_src 'https://something_default.test'
+ p.frame_src 'https://something.test'
end
+ end
- context 'when frame-src and default-src exist in the CSP config' do
- let(:csp) do
- ActionDispatch::ContentSecurityPolicy.new do |p|
- p.default_src 'https://something_default.test'
- p.frame_src 'https://something.test'
- end
- end
-
- it 'appends to frame-src CSP directives' do
- expect(subject).to include(
- "frame-src https://something.test https://observe.gitlab.com 'self'")
- expect(subject).to include(
- "default-src https://something_default.test")
- end
- end
+ it 'appends to frame-src CSP directives' do
+ expect(subject).to include(
+ "frame-src https://something.test #{observability_url} 'self'")
+ expect(subject).to include(
+ "default-src https://something_default.test")
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 cf728b3935f..6b150e0acb6 100644
--- a/spec/requests/groups/settings/access_tokens_controller_spec.rb
+++ b/spec/requests/groups/settings/access_tokens_controller_spec.rb
@@ -5,11 +5,11 @@ require 'spec_helper'
RSpec.describe Groups::Settings::AccessTokensController do
let_it_be(:user) { create(:user) }
let_it_be(:resource) { create(:group) }
- let_it_be(:bot_user) { create(:user, :project_bot) }
+ let_it_be(:access_token_user) { create(:user, :project_bot) }
before_all do
resource.add_owner(user)
- resource.add_maintainer(bot_user)
+ resource.add_maintainer(access_token_user)
end
before do
@@ -27,13 +27,24 @@ RSpec.describe Groups::Settings::AccessTokensController do
end
describe 'GET /:namespace/-/settings/access_tokens' do
- subject do
+ let(:get_access_tokens) do
get group_settings_access_tokens_path(resource)
response
end
+ let(:get_access_tokens_json) do
+ get group_settings_access_tokens_path(resource), params: { format: :json }
+ response
+ end
+
+ subject(:get_access_tokens_with_page) do
+ get group_settings_access_tokens_path(resource), params: { page: 1 }
+ response
+ end
+
it_behaves_like 'feature unavailable'
it_behaves_like 'GET resource access tokens available'
+ it_behaves_like 'GET access tokens are paginated and ordered'
end
describe 'POST /:namespace/-/settings/access_tokens' do
@@ -77,7 +88,7 @@ RSpec.describe Groups::Settings::AccessTokensController do
end
describe 'PUT /:namespace/-/settings/access_tokens/:id', :sidekiq_inline do
- let(:resource_access_token) { create(:personal_access_token, user: bot_user) }
+ let(:resource_access_token) { create(:personal_access_token, user: access_token_user) }
subject do
put revoke_group_settings_access_token_path(resource, resource_access_token)
@@ -89,17 +100,17 @@ RSpec.describe Groups::Settings::AccessTokensController do
end
describe '#index' do
- let_it_be(:resource_access_tokens) { create_list(:personal_access_token, 3, user: bot_user) }
+ let_it_be(:resource_access_tokens) { create_list(:personal_access_token, 3, user: access_token_user) }
before do
get group_settings_access_tokens_path(resource)
end
it 'includes details of the active group access tokens' do
- active_resource_access_tokens =
+ active_access_tokens =
::GroupAccessTokenSerializer.new.represent(resource_access_tokens.reverse, group: resource)
- expect(assigns(:active_resource_access_tokens).to_json).to eq(active_resource_access_tokens.to_json)
+ expect(assigns(:active_access_tokens).to_json).to eq(active_access_tokens.to_json)
end
end
end
diff --git a/spec/requests/jira_connect/cors_preflight_checks_controller_spec.rb b/spec/requests/jira_connect/cors_preflight_checks_controller_spec.rb
new file mode 100644
index 00000000000..d441a8575d0
--- /dev/null
+++ b/spec/requests/jira_connect/cors_preflight_checks_controller_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe JiraConnect::CorsPreflightChecksController do
+ shared_examples 'allows cross-origin requests on self managed' do
+ it 'renders not found' do
+ options path
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(response.headers['Access-Control-Allow-Origin']).to be_nil
+ end
+
+ context 'with jira_connect_proxy_url setting' do
+ before do
+ stub_application_setting(jira_connect_proxy_url: 'https://gitlab.com')
+
+ options path, headers: { 'Origin' => 'http://notgitlab.com' }
+ end
+
+ it 'returns 200' do
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'responds with access-control-allow headers', :aggregate_failures do
+ expect(response.headers['Access-Control-Allow-Origin']).to eq 'https://gitlab.com'
+ expect(response.headers['Access-Control-Allow-Methods']).to eq allowed_methods
+ expect(response.headers['Access-Control-Allow-Credentials']).to be_nil
+ end
+
+ context 'when on GitLab.com' do
+ before do
+ allow(Gitlab).to receive(:com?).and_return(true)
+ end
+
+ it 'renders not found' do
+ options path
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ expect(response.headers['Access-Control-Allow-Origin']).to be_nil
+ end
+ end
+ end
+ end
+
+ describe 'OPTIONS /-/jira_connect/oauth_application_id' do
+ let(:allowed_methods) { 'GET, OPTIONS' }
+ let(:path) { '/-/jira_connect/oauth_application_id' }
+
+ it_behaves_like 'allows cross-origin requests on self managed'
+ end
+
+ describe 'OPTIONS /-/jira_connect/subscriptions/:id' do
+ let(:allowed_methods) { 'DELETE, OPTIONS' }
+ let(:path) { '/-/jira_connect/subscriptions/123' }
+
+ it_behaves_like 'allows cross-origin requests on self managed'
+ end
+end
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 b0c2eaec4e2..1d772e973ff 100644
--- a/spec/requests/jira_connect/oauth_application_ids_controller_spec.rb
+++ b/spec/requests/jira_connect/oauth_application_ids_controller_spec.rb
@@ -3,42 +3,12 @@
require 'spec_helper'
RSpec.describe JiraConnect::OauthApplicationIdsController do
- describe 'OPTIONS /-/jira_connect/oauth_application_id' do
- before do
- stub_application_setting(jira_connect_application_key: '123456')
-
- options '/-/jira_connect/oauth_application_id', headers: { 'Origin' => 'http://notgitlab.com' }
- end
-
- it 'returns 200' do
- expect(response).to have_gitlab_http_status(:ok)
- end
-
- it 'allows cross-origin requests', :aggregate_failures do
- expect(response.headers['Access-Control-Allow-Origin']).to eq '*'
- expect(response.headers['Access-Control-Allow-Methods']).to eq 'GET, OPTIONS'
- expect(response.headers['Access-Control-Allow-Credentials']).to be_nil
- end
-
- context 'on GitLab.com' do
- before do
- allow(Gitlab).to receive(:com?).and_return(true)
- end
-
- it 'renders not found' do
- options '/-/jira_connect/oauth_application_id'
-
- expect(response).to have_gitlab_http_status(:not_found)
- expect(response.headers['Access-Control-Allow-Origin']).not_to eq '*'
- end
- end
- end
-
describe 'GET /-/jira_connect/oauth_application_id' do
let(:cors_request_headers) { { 'Origin' => 'http://notgitlab.com' } }
before do
stub_application_setting(jira_connect_application_key: '123456')
+ stub_application_setting(jira_connect_proxy_url: 'https://gitlab.com')
end
it 'renders the jira connect application id' do
@@ -51,7 +21,7 @@ RSpec.describe JiraConnect::OauthApplicationIdsController do
it 'allows cross-origin requests', :aggregate_failures do
get '/-/jira_connect/oauth_application_id', headers: cors_request_headers
- expect(response.headers['Access-Control-Allow-Origin']).to eq '*'
+ expect(response.headers['Access-Control-Allow-Origin']).to eq 'https://gitlab.com'
expect(response.headers['Access-Control-Allow-Methods']).to eq 'GET, OPTIONS'
expect(response.headers['Access-Control-Allow-Credentials']).to be_nil
end
diff --git a/spec/requests/jira_connect/subscriptions_controller_spec.rb b/spec/requests/jira_connect/subscriptions_controller_spec.rb
index f407ea09250..b5f3ab916a4 100644
--- a/spec/requests/jira_connect/subscriptions_controller_spec.rb
+++ b/spec/requests/jira_connect/subscriptions_controller_spec.rb
@@ -5,36 +5,70 @@ require 'spec_helper'
RSpec.describe JiraConnect::SubscriptionsController do
describe 'GET /-/jira_connect/subscriptions' do
let_it_be(:installation) { create(:jira_connect_installation, instance_url: 'http://self-managed-gitlab.com') }
-
let(:qsh) do
Atlassian::Jwt.create_query_string_hash('https://gitlab.test/subscriptions', 'GET', 'https://gitlab.test')
end
let(:jwt) { Atlassian::Jwt.encode({ iss: installation.client_key, qsh: qsh }, installation.shared_secret) }
+ let(:cors_request_headers) { { 'Origin' => 'http://notgitlab.com' } }
+ let(:path) { '/-/jira_connect/subscriptions' }
+ let(:params) { { jwt: jwt } }
+
+ before do
+ stub_application_setting(jira_connect_proxy_url: 'https://gitlab.com')
+ end
subject(:content_security_policy) do
- get '/-/jira_connect/subscriptions', params: { jwt: jwt }
+ get path, params: params
response.headers['Content-Security-Policy']
end
it { is_expected.to include('http://self-managed-gitlab.com/-/jira_connect/') }
it { is_expected.to include('http://self-managed-gitlab.com/api/') }
+ it { is_expected.to include('http://self-managed-gitlab.com/oauth/') }
context 'with no self-managed instance configured' do
let_it_be(:installation) { create(:jira_connect_installation, instance_url: '') }
it { is_expected.not_to include('http://self-managed-gitlab.com/-/jira_connect/') }
it { is_expected.not_to include('http://self-managed-gitlab.com/api/') }
+ it { is_expected.not_to include('http://self-managed-gitlab.com/oauth/') }
end
- context 'with jira_connect_oauth_self_managed feature disabled' do
+ context 'with jira_connect_oauth_self_managed_setting feature disabled' do
before do
- stub_feature_flags(jira_connect_oauth_self_managed: false)
+ stub_feature_flags(jira_connect_oauth_self_managed_setting: false)
end
it { is_expected.not_to include('http://self-managed-gitlab.com/-/jira_connect/') }
it { is_expected.not_to include('http://self-managed-gitlab.com/api/') }
+ it { is_expected.not_to include('http://self-managed-gitlab.com/oauth/') }
+ end
+ end
+
+ describe 'DELETE /-/jira_connect/subscriptions/:id' do
+ let_it_be(:installation) { create(:jira_connect_installation, instance_url: 'http://self-managed-gitlab.com') }
+ let_it_be(:subscription) { create(:jira_connect_subscription, installation: installation) }
+
+ let(:qsh) do
+ Atlassian::Jwt.create_query_string_hash('https://gitlab.test/subscriptions', 'GET', 'https://gitlab.test')
+ end
+
+ let(:jwt) { Atlassian::Jwt.encode({ iss: installation.client_key, qsh: qsh }, installation.shared_secret) }
+ let(:cors_request_headers) { { 'Origin' => 'http://notgitlab.com' } }
+ let(:params) { { jwt: jwt, format: :json } }
+
+ before do
+ stub_application_setting(jira_connect_proxy_url: 'https://gitlab.com')
+ end
+
+ it 'allows cross-origin requests', :aggregate_failures do
+ delete "/-/jira_connect/subscriptions/#{subscription.id}", params: params, headers: cors_request_headers
+
+ expect(response.headers['Access-Control-Allow-Origin']).to eq 'https://gitlab.com'
+ expect(response.headers['Access-Control-Allow-Methods']).to eq 'DELETE, OPTIONS'
+ expect(response.headers['Access-Control-Allow-Credentials']).to be_nil
end
end
end
diff --git a/spec/requests/oauth/tokens_controller_spec.rb b/spec/requests/oauth/tokens_controller_spec.rb
index e4cb28cc42b..507489d92cf 100644
--- a/spec/requests/oauth/tokens_controller_spec.rb
+++ b/spec/requests/oauth/tokens_controller_spec.rb
@@ -7,6 +7,7 @@ RSpec.describe Oauth::TokensController do
let(:other_headers) { {} }
let(:headers) { cors_request_headers.merge(other_headers) }
let(:allowed_methods) { 'POST, OPTIONS' }
+ let(:authorization_methods) { %w[Authorization X-CSRF-Token X-Requested-With] }
shared_examples 'cross-origin POST request' do
it 'allows cross-origin requests' do
@@ -25,7 +26,7 @@ RSpec.describe Oauth::TokensController do
it 'allows cross-origin requests' do
expect(response.headers['Access-Control-Allow-Origin']).to eq '*'
expect(response.headers['Access-Control-Allow-Methods']).to eq allowed_methods
- expect(response.headers['Access-Control-Allow-Headers']).to eq 'Authorization'
+ expect(response.headers['Access-Control-Allow-Headers']).to eq authorization_methods
expect(response.headers['Access-Control-Allow-Credentials']).to be_nil
end
end
@@ -39,7 +40,7 @@ RSpec.describe Oauth::TokensController do
end
describe 'OPTIONS /oauth/token' do
- let(:other_headers) { { 'Access-Control-Request-Headers' => 'Authorization', 'Access-Control-Request-Method' => 'POST' } }
+ let(:other_headers) { { 'Access-Control-Request-Headers' => authorization_methods, 'Access-Control-Request-Method' => 'POST' } }
before do
options '/oauth/token', headers: headers
@@ -63,7 +64,7 @@ RSpec.describe Oauth::TokensController do
end
describe 'OPTIONS /oauth/revoke' do
- let(:other_headers) { { 'Access-Control-Request-Headers' => 'Authorization', 'Access-Control-Request-Method' => 'POST' } }
+ let(:other_headers) { { 'Access-Control-Request-Headers' => authorization_methods, 'Access-Control-Request-Method' => 'POST' } }
before do
options '/oauth/revoke', headers: headers
diff --git a/spec/requests/product_analytics/collector_app_attack_spec.rb b/spec/requests/product_analytics/collector_app_attack_spec.rb
deleted file mode 100644
index 6f86e39c295..00000000000
--- a/spec/requests/product_analytics/collector_app_attack_spec.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'ProductAnalytics::CollectorApp throttle' do
- include RackAttackSpecHelpers
-
- include_context 'rack attack cache store'
-
- let(:project1) { create(:project) }
- let(:project2) { create(:project) }
-
- before do
- allow(ProductAnalyticsEvent).to receive(:create).and_return(true)
- end
-
- context 'per application id' do
- let(:params) do
- {
- aid: project1.id,
- eid: SecureRandom.uuid
- }
- end
-
- it 'throttles the endpoint' do
- # Allow requests under the rate limit.
- 100.times do
- expect_ok { get '/-/collector/i', params: params }
- end
-
- # Ensure its not related to ip address
- random_next_ip
-
- # Reject request over the limit
- expect_rejection { get '/-/collector/i', params: params }
-
- # But allows request for different aid
- expect_ok { get '/-/collector/i', params: params.merge(aid: project2.id) }
- end
- end
-end
diff --git a/spec/requests/product_analytics/collector_app_spec.rb b/spec/requests/product_analytics/collector_app_spec.rb
deleted file mode 100644
index 0d55d167a6f..00000000000
--- a/spec/requests/product_analytics/collector_app_spec.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'ProductAnalytics::CollectorApp' do
- let_it_be(:project) { create(:project) }
-
- let(:params) { {} }
- let(:raw_event) { Gitlab::Json.parse(fixture_file('product_analytics/event.json')) }
-
- subject { get '/-/collector/i', params: params }
-
- RSpec.shared_examples 'not found' do
- it 'repond with 404' do
- expect { subject }.not_to change { ProductAnalyticsEvent.count }
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
- end
-
- context 'correct event params' do
- let(:params) { raw_event.merge(aid: project.id) }
-
- it 'repond with 200' do
- expect { subject }.to change { ProductAnalyticsEvent.count }.by(1)
-
- expect(response).to have_gitlab_http_status(:ok)
- end
-
- context 'feature disabled' do
- before do
- stub_feature_flags(product_analytics: false)
- end
-
- it_behaves_like 'not found'
- end
- end
-
- context 'empty event params' do
- it_behaves_like 'not found'
- end
-
- context 'invalid project id in params' do
- let(:params) do
- {
- aid: '-1',
- p: 'web',
- tna: 'sp',
- tv: 'js-2.14.0',
- eid: SecureRandom.uuid,
- duid: SecureRandom.uuid,
- sid: SecureRandom.uuid
- }
- end
-
- it_behaves_like 'not found'
- end
-end
diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb
index 65540f86d34..370febf82ff 100644
--- a/spec/requests/projects/cycle_analytics_events_spec.rb
+++ b/spec/requests/projects/cycle_analytics_events_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe 'value stream analytics events' do
let(:project) { create(:project, :repository, public_builds: false) }
let(:issue) { create(:issue, project: project, created_at: 2.days.ago) }
- describe 'GET /:namespace/:project/value_stream_analytics/events/issues' do
+ describe 'GET /:namespace/:project/value_stream_analytics/events/issues', :sidekiq_inline do
let(:first_issue_iid) { project.issues.sort_by_attribute(:created_desc).pick(:iid).to_s }
let(:first_mr_iid) { project.merge_requests.sort_by_attribute(:created_desc).pick(:iid).to_s }
@@ -65,7 +65,7 @@ RSpec.describe 'value stream analytics events' do
expect(json_response['events'].first['iid']).to eq(first_mr_iid)
end
- it 'lists the staging events', :sidekiq_inline do
+ it 'lists the staging events' do
get project_cycle_analytics_staging_path(project, format: :json)
expect(json_response['events']).not_to be_empty
diff --git a/spec/requests/projects/google_cloud/deployments_controller_spec.rb b/spec/requests/projects/google_cloud/deployments_controller_spec.rb
index ad6a3912e0b..c777e8c1f69 100644
--- a/spec/requests/projects/google_cloud/deployments_controller_spec.rb
+++ b/spec/requests/projects/google_cloud/deployments_controller_spec.rb
@@ -83,7 +83,7 @@ RSpec.describe Projects::GoogleCloud::DeploymentsController do
end
it 'renders template' do
- get "#{project_google_cloud_deployments_path(project)}"
+ get project_google_cloud_deployments_path(project).to_s
expect(response).to render_template(:index)
@@ -98,7 +98,7 @@ RSpec.describe Projects::GoogleCloud::DeploymentsController do
end
describe 'Authorized GET project/-/google_cloud/deployments/cloud_run', :snowplow do
- let_it_be(:url) { "#{project_google_cloud_deployments_cloud_run_path(project)}" }
+ let_it_be(:url) { project_google_cloud_deployments_cloud_run_path(project).to_s }
before do
sign_in(user_maintainer)
@@ -188,7 +188,7 @@ RSpec.describe Projects::GoogleCloud::DeploymentsController do
end
describe 'Authorized GET project/-/google_cloud/deployments/cloud_storage', :snowplow do
- let_it_be(:url) { "#{project_google_cloud_deployments_cloud_storage_path(project)}" }
+ let_it_be(:url) { project_google_cloud_deployments_cloud_storage_path(project).to_s }
before do
allow_next_instance_of(GoogleApi::CloudPlatform::Client) do |client|
diff --git a/spec/requests/projects/google_cloud/service_accounts_controller_spec.rb b/spec/requests/projects/google_cloud/service_accounts_controller_spec.rb
index 133c6f9153d..d91e5a4f068 100644
--- a/spec/requests/projects/google_cloud/service_accounts_controller_spec.rb
+++ b/spec/requests/projects/google_cloud/service_accounts_controller_spec.rb
@@ -6,7 +6,7 @@ RSpec.describe Projects::GoogleCloud::ServiceAccountsController do
let_it_be(:project) { create(:project, :public) }
describe 'GET index', :snowplow do
- let_it_be(:url) { "#{project_google_cloud_service_accounts_path(project)}" }
+ let_it_be(:url) { project_google_cloud_service_accounts_path(project).to_s }
let_it_be(:user_guest) { create(:user) }
let_it_be(:user_developer) { create(:user) }
diff --git a/spec/requests/projects/issue_links_controller_spec.rb b/spec/requests/projects/issue_links_controller_spec.rb
index 81fd1adb1fd..e5f40625cfa 100644
--- a/spec/requests/projects/issue_links_controller_spec.rb
+++ b/spec/requests/projects/issue_links_controller_spec.rb
@@ -28,12 +28,28 @@ RSpec.describe Projects::IssueLinksController do
context 'when linked issue is a task' do
let(:issue_b) { create :issue, :task, project: project }
- it 'returns a work item path for the linked task' do
+ 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)
expect(json_response.count).to eq(1)
expect(json_response.first).to include(
- 'path' => project_work_items_path(issue_b.project, issue_b.id),
+ 'path' => project_work_items_path(issue_b.project, issue_b.iid, iid_path: true),
'type' => 'TASK'
)
end
diff --git a/spec/requests/projects/merge_requests/context_commit_diffs_spec.rb b/spec/requests/projects/merge_requests/context_commit_diffs_spec.rb
index c859e91e21a..ec65e8cf11e 100644
--- a/spec/requests/projects/merge_requests/context_commit_diffs_spec.rb
+++ b/spec/requests/projects/merge_requests/context_commit_diffs_spec.rb
@@ -35,7 +35,7 @@ RSpec.describe 'Merge Requests Context Commit Diffs' do
commit: nil,
diff_view: :inline,
merge_ref_head_diff: nil,
- allow_tree_conflicts: true,
+ merge_conflicts_in_diff: true,
pagination_data: {
total_pages: nil
}.merge(pagination_data)
diff --git a/spec/requests/projects/merge_requests/diffs_spec.rb b/spec/requests/projects/merge_requests/diffs_spec.rb
index 9f0b9a9cb1b..12990b54617 100644
--- a/spec/requests/projects/merge_requests/diffs_spec.rb
+++ b/spec/requests/projects/merge_requests/diffs_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe 'Merge Requests Diffs' do
commit: nil,
diff_view: :inline,
merge_ref_head_diff: nil,
- allow_tree_conflicts: true,
+ merge_conflicts_in_diff: true,
pagination_data: {
total_pages: nil
}.merge(pagination_data)
@@ -80,6 +80,20 @@ RSpec.describe 'Merge Requests Diffs' do
expect(response).to have_gitlab_http_status(:not_modified)
end
+ context 'with check_etags_diffs_batch_before_write_cache flag turned off' do
+ before do
+ stub_feature_flags(check_etags_diffs_batch_before_write_cache: false)
+ end
+
+ it 'does not serialize diffs' do
+ expect(PaginatedDiffSerializer).not_to receive(:new)
+
+ go(headers: headers, page: 0, per_page: 5)
+
+ expect(response).to have_gitlab_http_status(:not_modified)
+ end
+ end
+
context 'with the different user' do
let(:another_user) { create(:user) }
let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch }
@@ -114,7 +128,7 @@ RSpec.describe 'Merge Requests Diffs' do
context 'with disabled display_merge_conflicts_in_diff feature' do
let(:collection) { Gitlab::Diff::FileCollection::MergeRequestDiffBatch }
- let(:expected_options) { collection_arguments(total_pages: 20).merge(allow_tree_conflicts: false) }
+ let(:expected_options) { collection_arguments(total_pages: 20).merge(merge_conflicts_in_diff: false) }
before do
stub_feature_flags(display_merge_conflicts_in_diff: false)
diff --git a/spec/requests/projects/ml/experiments_controller_spec.rb b/spec/requests/projects/ml/experiments_controller_spec.rb
new file mode 100644
index 00000000000..67a2fe47dc8
--- /dev/null
+++ b/spec/requests/projects/ml/experiments_controller_spec.rb
@@ -0,0 +1,100 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Projects::Ml::ExperimentsController do
+ let_it_be(:project_with_feature) { create(:project, :repository) }
+ let_it_be(:user) { project_with_feature.first_owner }
+ let_it_be(:project_without_feature) do
+ create(:project, :repository).tap { |p| p.add_developer(user) }
+ end
+
+ let_it_be(:experiment) do
+ create(:ml_experiments, project: project_with_feature, user: user).tap do |e|
+ create(:ml_candidates, experiment: e, user: user)
+ end
+ end
+
+ let(:params) { basic_params }
+ let(:ff_value) { true }
+ let(:threshold) { 4 }
+ let(:project) { project_with_feature }
+ let(:basic_params) { { namespace_id: project.namespace.to_param, project_id: project } }
+
+ before do
+ stub_feature_flags(ml_experiment_tracking: false)
+ stub_feature_flags(ml_experiment_tracking: project_with_feature) if ff_value
+
+ sign_in(user)
+ end
+
+ shared_examples '404 if feature flag disabled' do
+ context 'when :ml_experiment_tracking disabled' do
+ let(:ff_value) { false }
+
+ it 'is 404' do
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+
+ describe 'GET index' do
+ before do
+ list_experiments
+ end
+
+ it 'renders the template' do
+ expect(response).to render_template('projects/ml/experiments/index')
+ end
+
+ it 'does not perform N+1 sql queries' do
+ control_count = ActiveRecord::QueryRecorder.new { list_experiments }
+
+ create_list(:ml_experiments, 2, project: project, user: user)
+
+ expect { list_experiments }.not_to exceed_all_query_limit(control_count).with_threshold(threshold)
+ end
+
+ context 'when :ml_experiment_tracking is disabled for the project' do
+ let(:project) { project_without_feature }
+
+ it 'responds with a 404' do
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ it_behaves_like '404 if feature flag disabled'
+ end
+
+ describe 'GET show' do
+ let(:params) { basic_params.merge(id: experiment.iid) }
+
+ before do
+ show_experiment
+ end
+
+ it 'renders the template' do
+ expect(response).to render_template('projects/ml/experiments/show')
+ end
+
+ it 'does not perform N+1 sql queries' do
+ control_count = ActiveRecord::QueryRecorder.new { show_experiment }
+
+ create_list(:ml_candidates, 2, :with_metrics_and_params, experiment: experiment)
+
+ expect { show_experiment }.not_to exceed_all_query_limit(control_count).with_threshold(threshold)
+ end
+
+ it_behaves_like '404 if feature flag disabled'
+ end
+
+ private
+
+ def show_experiment
+ get project_ml_experiment_path(project, experiment.iid), params: params
+ end
+
+ def list_experiments
+ get project_ml_experiments_path(project), params: params
+ 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 48114834c65..17389cdcce7 100644
--- a/spec/requests/projects/settings/access_tokens_controller_spec.rb
+++ b/spec/requests/projects/settings/access_tokens_controller_spec.rb
@@ -6,11 +6,11 @@ RSpec.describe Projects::Settings::AccessTokensController do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:resource) { create(:project, group: group) }
- let_it_be(:bot_user) { create(:user, :project_bot) }
+ let_it_be(:access_token_user) { create(:user, :project_bot) }
before_all do
resource.add_maintainer(user)
- resource.add_maintainer(bot_user)
+ resource.add_maintainer(access_token_user)
end
before do
@@ -28,13 +28,24 @@ RSpec.describe Projects::Settings::AccessTokensController do
end
describe 'GET /:namespace/:project/-/settings/access_tokens' do
- subject do
+ let(:get_access_tokens) do
get project_settings_access_tokens_path(resource)
response
end
+ let(:get_access_tokens_json) do
+ get project_settings_access_tokens_path(resource), params: { format: :json }
+ response
+ end
+
+ subject(:get_access_tokens_with_page) do
+ get project_settings_access_tokens_path(resource), params: { page: 1 }
+ response
+ end
+
it_behaves_like 'feature unavailable'
it_behaves_like 'GET resource access tokens available'
+ it_behaves_like 'GET access tokens are paginated and ordered'
end
describe 'POST /:namespace/:project/-/settings/access_tokens' do
@@ -78,7 +89,7 @@ RSpec.describe Projects::Settings::AccessTokensController do
end
describe 'PUT /:namespace/:project/-/settings/access_tokens/:id', :sidekiq_inline do
- let(:resource_access_token) { create(:personal_access_token, user: bot_user) }
+ let(:resource_access_token) { create(:personal_access_token, user: access_token_user) }
subject do
put revoke_project_settings_access_token_path(resource, resource_access_token)
@@ -90,17 +101,17 @@ RSpec.describe Projects::Settings::AccessTokensController do
end
describe '#index' do
- let_it_be(:resource_access_tokens) { create_list(:personal_access_token, 3, user: bot_user) }
+ let_it_be(:resource_access_tokens) { create_list(:personal_access_token, 3, user: access_token_user) }
before do
get project_settings_access_tokens_path(resource)
end
it 'includes details of the active project access tokens' do
- active_resource_access_tokens =
+ active_access_tokens =
::ProjectAccessTokenSerializer.new.represent(resource_access_tokens.reverse, project: resource)
- expect(assigns(:active_resource_access_tokens).to_json).to eq(active_resource_access_tokens.to_json)
+ expect(assigns(:active_access_tokens).to_json).to eq(active_access_tokens.to_json)
end
end
end
diff --git a/spec/requests/projects/work_items_spec.rb b/spec/requests/projects/work_items_spec.rb
index e6365a3824a..4d7acc73d4f 100644
--- a/spec/requests/projects/work_items_spec.rb
+++ b/spec/requests/projects/work_items_spec.rb
@@ -15,24 +15,10 @@ RSpec.describe 'Work Items' do
sign_in(developer)
end
- context 'when the work_items feature flag is enabled' do
- it 'renders index' do
- get project_work_items_url(work_item.project, work_items_path: work_item.id)
+ it 'renders index' do
+ get project_work_items_url(work_item.project, work_items_path: work_item.id)
- expect(response).to have_gitlab_http_status(:ok)
- end
- end
-
- context 'when the work_items feature flag is disabled' do
- before do
- stub_feature_flags(work_items: false)
- end
-
- it 'returns 404' do
- get project_work_items_url(work_item.project, work_items_path: work_item.id)
-
- expect(response).to have_gitlab_http_status(:not_found)
- end
+ expect(response).to have_gitlab_http_status(:ok)
end
end
end
diff --git a/spec/requests/search_controller_spec.rb b/spec/requests/search_controller_spec.rb
index 93a2fecab74..613732c19ea 100644
--- a/spec/requests/search_controller_spec.rb
+++ b/spec/requests/search_controller_spec.rb
@@ -103,13 +103,17 @@ RSpec.describe SearchController, type: :request do
expect(response).not_to redirect_to(project_commit_path(project, sha))
end
- it 'does not redirect if user cannot download_code from project' do
- allow(Ability).to receive(:allowed?).and_call_original
- allow(Ability).to receive(:allowed?).with(user, :download_code, project).and_return(false)
+ context 'when user cannot read_code' do
+ before do
+ allow(Ability).to receive(:allowed?).and_call_original
+ allow(Ability).to receive(:allowed?).with(user, :read_code, project).and_return(false)
+ end
- send_search_request({ search: sha, project_id: project.id })
+ it 'does not redirect' do
+ send_search_request({ search: sha, project_id: project.id })
- expect(response).not_to redirect_to(project_commit_path(project, sha))
+ expect(response).not_to redirect_to(project_commit_path(project, sha))
+ end
end
it 'does not redirect if commit sha not found in project' do
diff --git a/spec/requests/self_monitoring_project_spec.rb b/spec/requests/self_monitoring_project_spec.rb
index f7227f71b05..64c5f94657d 100644
--- a/spec/requests/self_monitoring_project_spec.rb
+++ b/spec/requests/self_monitoring_project_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe 'Self-Monitoring project requests' do
login_as(admin)
end
- context 'when the self monitoring project is created' do
+ context 'when the self-monitoring project is created' do
let(:status_api) { status_create_self_monitoring_project_admin_application_settings_path }
it_behaves_like 'triggers async worker, returns sidekiq job_id with response accepted'
@@ -41,7 +41,7 @@ RSpec.describe 'Self-Monitoring project requests' do
login_as(admin)
end
- context 'when the self monitoring project is being created' do
+ context 'when the self-monitoring project is being created' do
it_behaves_like 'handles invalid job_id'
context 'when job is in progress' do
@@ -121,7 +121,7 @@ RSpec.describe 'Self-Monitoring project requests' do
login_as(admin)
end
- context 'when the self monitoring project is deleted' do
+ context 'when the self-monitoring project is deleted' do
let(:status_api) { status_delete_self_monitoring_project_admin_application_settings_path }
it_behaves_like 'triggers async worker, returns sidekiq job_id with response accepted'
@@ -145,7 +145,7 @@ RSpec.describe 'Self-Monitoring project requests' do
login_as(admin)
end
- context 'when the self monitoring project is being deleted' do
+ context 'when the self-monitoring project is being deleted' do
it_behaves_like 'handles invalid job_id'
context 'when job is in progress' do
diff --git a/spec/requests/verifies_with_email_spec.rb b/spec/requests/verifies_with_email_spec.rb
index e8d3e94bd0e..34fda1cce4d 100644
--- a/spec/requests/verifies_with_email_spec.rb
+++ b/spec/requests/verifies_with_email_spec.rb
@@ -30,6 +30,97 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
end
end
+ shared_examples_for 'rate limited' do
+ it 'redirects to the login form and shows an alert message' do
+ expect(response).to redirect_to(new_user_session_path)
+ expect(flash[:alert])
+ .to eq(s_('IdentityVerification|Maximum login attempts exceeded. Wait 10 minutes and try again.'))
+ end
+ end
+
+ 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')
+ else
+ expect(response).to redirect_to(root_path)
+ end
+ end
+ end
+
+ shared_examples_for 'verifying with email' do
+ context 'when rate limited' do
+ before do
+ allow(Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
+ sign_in
+ end
+
+ it_behaves_like 'rate limited'
+ end
+
+ context 'when the user already has an unlock_token set' do
+ before do
+ user.update!(unlock_token: 'token')
+ sign_in
+ end
+
+ it_behaves_like 'prompt for email verification'
+ end
+
+ context 'when the user is already locked' do
+ before do
+ user.update!(locked_at: Time.current)
+ perform_enqueued_jobs { sign_in }
+ end
+
+ it_behaves_like 'send verification instructions'
+ it_behaves_like 'prompt for email verification'
+ end
+
+ context 'when the user is signing in from an unknown ip address' do
+ before do
+ allow(AuthenticationEvent)
+ .to receive(:initial_login_or_known_ip_address?)
+ .and_return(false)
+ perform_enqueued_jobs { sign_in }
+ end
+
+ it_behaves_like 'send verification instructions'
+ it_behaves_like 'prompt for email verification'
+ end
+ end
+
+ shared_examples_for 'not verifying with email' do
+ context 'when rate limited' do
+ before do
+ allow(Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
+ sign_in
+ end
+
+ it_behaves_like 'two factor prompt or successful login'
+ end
+
+ context 'when the user already has an unlock_token set' do
+ before do
+ user.update!(unlock_token: 'token')
+ sign_in
+ end
+
+ it_behaves_like 'two factor prompt or successful login'
+ end
+
+ context 'when the user is signing in from an unknown ip address' do
+ before do
+ allow(AuthenticationEvent)
+ .to receive(:initial_login_or_known_ip_address?)
+ .and_return(false)
+ sign_in
+ end
+
+ it_behaves_like 'two factor prompt or successful login'
+ end
+ end
+
describe 'verify_with_email' do
context 'when user is locked and a verification_user_id session variable exists' do
before do
@@ -99,69 +190,34 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
end
context 'when signing in with a valid password' do
- let(:sign_in) { post(user_session_path(user: { login: user.username, password: user.password })) }
+ let(:headers) { {} }
+ let(:sign_in) do
+ post user_session_path, params: { user: { login: user.username, password: user.password } }, headers: headers
+ end
+
+ it_behaves_like 'not verifying with email'
context 'when the feature flag is toggled on' do
before do
stub_feature_flags(require_email_verification: user)
end
- context 'when rate limited' do
- before do
- allow(Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
- sign_in
- end
+ it_behaves_like 'verifying with email'
- it 'redirects to the login form and shows an alert message' do
- expect(response).to redirect_to(new_user_session_path)
- expect(flash[:alert])
- .to eq(s_('IdentityVerification|Maximum login attempts exceeded. Wait 10 minutes and try again.'))
- end
- end
-
- context 'when the user already has an unlock_token set' do
+ context 'when 2FA is enabled' do
before do
- user.update!(unlock_token: 'token')
- sign_in
+ user.update!(otp_required_for_login: true)
end
- it_behaves_like 'prompt for email verification'
+ it_behaves_like 'not verifying with email'
end
- context 'when the user is already locked' do
+ context 'when request is not from a QA user' do
before do
- user.update!(locked_at: Time.current)
- perform_enqueued_jobs { sign_in }
+ allow(Gitlab::Qa).to receive(:request?).and_return(false)
end
- it_behaves_like 'send verification instructions'
- it_behaves_like 'prompt for email verification'
- end
-
- context 'when the user is signing in from an unknown ip address' do
- before do
- allow(AuthenticationEvent)
- .to receive(:initial_login_or_known_ip_address?)
- .and_return(false)
-
- perform_enqueued_jobs { sign_in }
- end
-
- it_behaves_like 'send verification instructions'
- it_behaves_like 'prompt for email verification'
- end
- end
-
- context 'when the feature flag is toggled off' do
- let(:another_user) { build(:user) }
-
- before do
- stub_feature_flags(require_email_verification: another_user)
- sign_in
- end
-
- it 'redirects to the root path' do
- expect(response).to redirect_to(root_path)
+ it_behaves_like 'verifying with email'
end
end
end
diff --git a/spec/routing/group_routing_spec.rb b/spec/routing/group_routing_spec.rb
index ae69b222280..68e619e5246 100644
--- a/spec/routing/group_routing_spec.rb
+++ b/spec/routing/group_routing_spec.rb
@@ -72,8 +72,16 @@ RSpec.shared_examples 'groups routing' do
expect(get("groups/#{group_path}/-/harbor/repositories/test/artifacts/test/tags")).to route_to('groups/harbor/tags#index', group_id: group_path, repository_id: 'test', artifact_id: 'test')
end
- it 'routes to the observability controller' do
- expect(get("groups/#{group_path}/-/observability")).to route_to('groups/observability#index', group_id: group_path)
+ it 'routes to the observability controller dashboards method' do
+ expect(get("groups/#{group_path}/-/observability/dashboards")).to route_to('groups/observability#dashboards', group_id: group_path)
+ end
+
+ it 'routes to the observability controller explore method' do
+ expect(get("groups/#{group_path}/-/observability/explore")).to route_to('groups/observability#explore', group_id: group_path)
+ end
+
+ it 'routes to the observability controller manage method' do
+ expect(get("groups/#{group_path}/-/observability/manage")).to route_to('groups/observability#manage', group_id: group_path)
end
end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 875a54de3d1..42196a7d8af 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -548,7 +548,7 @@ RSpec.describe 'project routing' do
method: :get },
{ controller: 'projects/find_file', action: 'show',
namespace_id: 'gitlab', project_id: 'gitlabhq',
- id: "#{newline_file}" })
+ id: newline_file.to_s })
end
it 'to #list' do
@@ -559,7 +559,7 @@ RSpec.describe 'project routing' do
method: :get },
{ controller: 'projects/find_file', action: 'list',
namespace_id: 'gitlab', project_id: 'gitlabhq',
- id: "#{newline_file}" })
+ id: newline_file.to_s })
end
it_behaves_like 'redirecting a legacy path', "/gitlab/gitlabhq/find_file", "/gitlab/gitlabhq/-/find_file"
diff --git a/spec/rubocop/cop/api/ensure_string_detail_spec.rb b/spec/rubocop/cop/api/ensure_string_detail_spec.rb
new file mode 100644
index 00000000000..d4f68711e78
--- /dev/null
+++ b/spec/rubocop/cop/api/ensure_string_detail_spec.rb
@@ -0,0 +1,136 @@
+# frozen_string_literal: true
+
+require 'rubocop_spec_helper'
+require_relative '../../../../rubocop/cop/api/ensure_string_detail'
+
+RSpec.describe RuboCop::Cop::API::EnsureStringDetail do
+ context "when in_api? == true" do
+ before do
+ allow(cop).to receive(:in_api?).and_return(true)
+ end
+
+ context "when detail field uses a string" do
+ it "does not add an offense" do
+ expect_no_offenses(<<~CODE)
+ class SomeAPI
+ resource :projects do
+ desc 'Some API thing related to a project' do
+ detail "foo bar"
+ end
+ end
+ end
+ CODE
+ end
+ end
+
+ context "when detail field uses interpolation in a string" do
+ it "does not add an offense" do
+ baz = "bat"
+
+ expect_no_offenses(<<~CODE)
+ class SomeAPI
+ resource :projects do
+ desc 'Some API thing related to a project' do
+ detail "foo bar #{baz}"
+ end
+ end
+ end
+ CODE
+ end
+ end
+
+ context "when detail field uses a multiline string" do
+ it "does not add an offense" do
+ expect_no_offenses(<<~CODE)
+ class SomeAPI
+ resource :projects do
+ desc 'Some API thing related to a project' do
+ detail "foo bar"\
+ "baz bat"
+ end
+ end
+ end
+ CODE
+ end
+ end
+
+ context "when detail field uses a constant" do
+ it "does not add an offense" do
+ pending
+
+ expect_no_offenses(<<~CODE)
+ class SomeAPI
+ resource :projects do
+ DESCRIPTION = 'A string'
+
+ desc 'Some API thing related to a project' do
+ detail DESCRIPTION
+ end
+ end
+ end
+ CODE
+ end
+ end
+
+ context "when detail field uses a HEREDOC string" do
+ it "does not add an offense" do
+ expect_no_offenses(<<~CODE)
+ class SomeAPI
+ resource :projects do
+ desc 'Some API thing related to a project' do
+ detail <<~END
+ foo bar
+ baz bat
+ END
+ end
+ end
+ end
+ CODE
+ end
+ end
+
+ context "when detail field uses an array" do
+ it "adds an offense" do
+ expect_offense(<<~CODE)
+ class SomeAPI
+ resource :projects do
+ desc 'Some API thing related to a project' do
+ something 'else'
+ detail ["foo", "bar"]
+ ^^^^^^^^^^^^^^^^^^^^^ Only String objects are permitted in API detail field.
+ end
+ end
+ end
+ CODE
+ end
+ end
+
+ context "when detail field is outside of desc block" do
+ it "does not add an offense" do
+ expect_no_offenses(<<~CODE)
+ class Foo
+ detail ["foo", "bar"]
+ end
+ CODE
+ end
+ end
+ end
+
+ context "when in_api? == false" do
+ before do
+ allow(cop).to receive(:in_api?).and_return(false)
+ end
+
+ it "does not add an offense" do
+ expect_no_offenses(<<~CODE)
+ class SomeAPI
+ resource :projects do
+ desc 'Some API thing related to a project' do
+ detail ["foo", "bar"]
+ end
+ end
+ end
+ CODE
+ end
+ end
+end
diff --git a/spec/rubocop/cop/gitlab/duplicate_spec_location_spec.rb b/spec/rubocop/cop/gitlab/duplicate_spec_location_spec.rb
deleted file mode 100644
index 0a121a495c9..00000000000
--- a/spec/rubocop/cop/gitlab/duplicate_spec_location_spec.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-# frozen_string_literal: true
-
-require 'rubocop_spec_helper'
-
-require_relative '../../../../rubocop/cop/gitlab/duplicate_spec_location'
-
-RSpec.describe RuboCop::Cop::Gitlab::DuplicateSpecLocation, type: :rubocop_rspec do
- let(:rails_root) { '../../../../' }
-
- def full_path(path)
- File.expand_path(File.join(rails_root, path), __dir__)
- end
-
- context 'Non-EE spec file' do
- it 'registers no offenses' do
- expect_no_offenses(<<~SOURCE, full_path('spec/foo_spec.rb'))
- describe 'Foo' do
- end
- SOURCE
- end
- end
-
- context 'Non-EE application file' do
- it 'registers no offenses' do
- expect_no_offenses(<<~SOURCE, full_path('app/models/blog_post.rb'))
- class BlogPost
- end
- SOURCE
- end
- end
-
- context 'EE application file' do
- it 'registers no offenses' do
- expect_no_offenses(<<~SOURCE, full_path('ee/app/models/blog_post.rb'))
- class BlogPost
- end
- SOURCE
- end
- end
-
- context 'EE spec file for EE only code' do
- let(:spec_file_path) { full_path('ee/spec/controllers/foo_spec.rb') }
-
- it 'registers no offenses' do
- expect_no_offenses(<<~SOURCE, spec_file_path)
- describe 'Foo' do
- end
- SOURCE
- end
-
- context 'there is a duplicate file' do
- before do
- allow(File).to receive(:exist?).and_call_original
-
- allow(File).to receive(:exist?)
- .with(full_path('ee/spec/controllers/ee/foo_spec.rb'))
- .and_return(true)
- end
-
- it 'marks the describe as offending' do
- expect_offense(<<~SOURCE, spec_file_path)
- describe 'Foo' do
- ^^^^^^^^^^^^^^ Duplicate spec location in `ee/spec/controllers/ee/foo_spec.rb`.
- end
- SOURCE
- end
- end
- end
-
- context 'EE spec file for EE extension' do
- let(:spec_file_path) { full_path('ee/spec/controllers/ee/foo_spec.rb') }
-
- it 'registers no offenses' do
- expect_no_offenses(<<~SOURCE, spec_file_path)
- describe 'Foo' do
- end
- SOURCE
- end
-
- context 'there is a duplicate file' do
- before do
- allow(File).to receive(:exist?).and_call_original
-
- allow(File).to receive(:exist?)
- .with(full_path('ee/spec/controllers/foo_spec.rb'))
- .and_return(true)
- end
-
- it 'marks the describe as offending' do
- expect_offense(<<~SOURCE, spec_file_path)
- describe 'Foo' do
- ^^^^^^^^^^^^^^ Duplicate spec location in `ee/spec/controllers/foo_spec.rb`.
- end
- SOURCE
- end
- end
- end
-end
diff --git a/spec/rubocop/cop/gitlab/json_spec.rb b/spec/rubocop/cop/gitlab/json_spec.rb
index e4ec107747d..70f63a78dd1 100644
--- a/spec/rubocop/cop/gitlab/json_spec.rb
+++ b/spec/rubocop/cop/gitlab/json_spec.rb
@@ -5,12 +5,41 @@ require_relative '../../../../rubocop/cop/gitlab/json'
RSpec.describe RuboCop::Cop::Gitlab::Json do
context 'when ::JSON is called' do
- it 'registers an offense' do
+ it 'registers an offense and autocorrects' do
expect_offense(<<~RUBY)
class Foo
def bar
JSON.parse('{ "foo": "bar" }')
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid calling `JSON` directly. [...]
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `Gitlab::Json` over calling `JSON` directly. [...]
+ end
+ end
+ RUBY
+
+ expect_correction(<<~RUBY)
+ class Foo
+ def bar
+ Gitlab::Json.parse('{ "foo": "bar" }')
+ end
+ end
+ RUBY
+ end
+ end
+
+ context 'when ::JSON is called in EE' do
+ it 'registers an offense and autocorrects' do
+ expect_offense(<<~RUBY, '/path/to/ee/foo.rb')
+ class Foo
+ def bar
+ JSON.parse('{ "foo": "bar" }')
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `Gitlab::Json` over calling `JSON` directly. [...]
+ end
+ end
+ RUBY
+
+ expect_correction(<<~RUBY)
+ class Foo
+ def bar
+ ::Gitlab::Json.parse('{ "foo": "bar" }')
end
end
RUBY
@@ -18,12 +47,20 @@ RSpec.describe RuboCop::Cop::Gitlab::Json do
end
context 'when ActiveSupport::JSON is called' do
- it 'registers an offense' do
+ it 'registers an offense and autocorrects' do
expect_offense(<<~RUBY)
class Foo
def bar
ActiveSupport::JSON.parse('{ "foo": "bar" }')
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid calling `JSON` directly. [...]
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `Gitlab::Json` over calling `JSON` directly. [...]
+ end
+ end
+ RUBY
+
+ expect_correction(<<~RUBY)
+ class Foo
+ def bar
+ Gitlab::Json.parse('{ "foo": "bar" }')
end
end
RUBY
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 a3c9ae8916e..6e60889f737 100644
--- a/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb
+++ b/spec/rubocop/cop/gitlab/mark_used_feature_flags_spec.rb
@@ -194,6 +194,10 @@ RSpec.describe RuboCop::Cop::Gitlab::MarkUsedFeatureFlags do
include_examples 'sets flag as used', 'FEATURE_FLAG = :foo', 'foo'
end
+ describe 'ROUTING_FEATURE_FLAG = :foo' do
+ include_examples 'sets flag as used', 'ROUTING_FEATURE_FLAG = :foo', 'foo'
+ end
+
describe 'Worker `data_consistency` method' do
include_examples 'sets flag as used', 'data_consistency :delayed, feature_flag: :foo', 'foo'
include_examples 'does not set any flags as used', 'data_consistency :delayed'
diff --git a/spec/rubocop/cop/gitlab/rspec/avoid_setup_spec.rb b/spec/rubocop/cop/gitlab/rspec/avoid_setup_spec.rb
new file mode 100644
index 00000000000..f9226649f65
--- /dev/null
+++ b/spec/rubocop/cop/gitlab/rspec/avoid_setup_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'rubocop_spec_helper'
+
+require_relative '../../../../../rubocop/cop/gitlab/rspec/avoid_setup'
+
+RSpec.describe RuboCop::Cop::Gitlab::RSpec::AvoidSetup do
+ context 'when calling let_it_be' do
+ let(:source) do
+ <<~SRC
+ let_it_be(:user) { create(:user) }
+ ^^^^^^^^^^^^^^^^ Avoid the use of `let_it_be` [...]
+ SRC
+ end
+
+ it 'registers an offense' do
+ expect_offense(source)
+ end
+ end
+
+ context 'without readability issues' do
+ let(:source) do
+ <<~SRC
+ it 'registers the user and sends them to a project listing page' do
+ user_signs_up
+
+ expect_to_see_account_confirmation_page
+ end
+ SRC
+ end
+
+ it 'does not register an offense' do
+ expect_no_offenses(source)
+ end
+ end
+end
diff --git a/spec/rubocop/cop/graphql/enum_names_spec.rb b/spec/rubocop/cop/graphql/enum_names_spec.rb
new file mode 100644
index 00000000000..f45df068381
--- /dev/null
+++ b/spec/rubocop/cop/graphql/enum_names_spec.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+require 'rubocop_spec_helper'
+require_relative '../../../../rubocop/cop/graphql/enum_names'
+
+RSpec.describe RuboCop::Cop::Graphql::EnumNames do
+ describe 'class name' do
+ it 'adds an offense when class name does not end with `Enum`' do
+ expect_offense(<<~ENUM)
+ module Types
+ class Fake < BaseEnum
+ ^^^^ #{described_class::CLASS_NAME_SUFFIX_MSG}
+ graphql_name 'Fake'
+ end
+ end
+ ENUM
+ end
+ end
+
+ describe 'graphql_name' do
+ it 'adds an offense when `graphql_name` is not set' do
+ expect_offense(<<~ENUM)
+ module Types
+ class FakeEnum < BaseEnum
+ ^^^^^^^^^^^^^^^^^^^^^^^^^ #{described_class::GRAPHQL_NAME_MISSING_MSG}
+ end
+ end
+ ENUM
+ end
+
+ it 'adds no offense when `declarative_enum` is used' do
+ expect_no_offenses(<<~ENUM)
+ module Types
+ class FakeEnum < BaseEnum
+ declarative_enum ::FakeModule::FakeDeclarativeEnum
+ end
+ end
+ ENUM
+ end
+
+ it 'adds an offense when `graphql_name` includes `enum`' do
+ expect_offense(<<~ENUM)
+ module Types
+ class FakeEnum < BaseEnum
+ graphql_name 'FakeEnum'
+ ^^^^^^^^^^ #{described_class::GRAPHQL_NAME_WITH_ENUM_MSG}
+ end
+ end
+ ENUM
+ end
+ end
+end
diff --git a/spec/rubocop/cop/graphql/enum_values_spec.rb b/spec/rubocop/cop/graphql/enum_values_spec.rb
new file mode 100644
index 00000000000..5609c86d9ec
--- /dev/null
+++ b/spec/rubocop/cop/graphql/enum_values_spec.rb
@@ -0,0 +1,79 @@
+# frozen_string_literal: true
+
+require 'rubocop_spec_helper'
+require_relative '../../../../rubocop/cop/graphql/enum_values'
+
+RSpec.describe RuboCop::Cop::Graphql::EnumValues do
+ it 'adds an offense when enum value is not uppercase' do
+ expect_offense(<<~ENUM)
+ module Types
+ class FakeEnum < BaseEnum
+ graphql_name 'Fake'
+
+ value 'downcase', description: "Downcase."
+ ^^^^^^^^^^ #{described_class::MSG}
+ end
+ end
+ ENUM
+ end
+
+ context 'when values are set dynamically' do
+ it 'adds an offense when enum value is set without `:upcase`' do
+ expect_offense(<<~ENUM)
+ VALUES = ['FOO', 'bar']
+
+ module Types
+ class FakeEnum < BaseEnum
+ graphql_name 'Fake'
+
+ VALUES.each do |val|
+ value val, description: "Dynamic value."
+ ^^^ #{described_class::MSG}
+ end
+ end
+ end
+ ENUM
+ end
+
+ it 'adds no offense when enum value is deprecated' do
+ expect_no_offenses(<<~ENUM)
+ module Types
+ class FakeEnum < BaseEnum
+ graphql_name 'Fake'
+
+ value 'foo', deprecated: { reason: 'Use something else' }
+ end
+ end
+ ENUM
+ end
+
+ it 'adds no offense when enum value is uppercased literally' do
+ expect_no_offenses(<<~'ENUM')
+ module Types
+ class FakeEnum < BaseEnum
+ graphql_name 'Fake'
+
+ value 'FOO'
+ end
+ end
+ ENUM
+ end
+
+ it 'adds no offense when enum value is calling upcased' do
+ expect_no_offenses(<<~'ENUM')
+ VALUES = ['FOO', 'bar']
+
+ module Types
+ class FakeEnum < BaseEnum
+ graphql_name 'Fake'
+
+ VALUES.each do |val|
+ value val.underscore.upcase, description: "Dynamic value."
+ value "#{field.upcase.tr(' ', '_')}_ASC"
+ end
+ end
+ end
+ ENUM
+ end
+ end
+end
diff --git a/spec/rubocop/cop/migration/schema_addition_methods_no_post_spec.rb b/spec/rubocop/cop/migration/schema_addition_methods_no_post_spec.rb
new file mode 100644
index 00000000000..fb087269e2d
--- /dev/null
+++ b/spec/rubocop/cop/migration/schema_addition_methods_no_post_spec.rb
@@ -0,0 +1,24 @@
+# frozen_string_literal: true
+
+require 'rubocop_spec_helper'
+require_relative '../../../../rubocop/cop/migration/schema_addition_methods_no_post'
+
+RSpec.describe RuboCop::Cop::Migration::SchemaAdditionMethodsNoPost do
+ before do
+ allow(cop).to receive(:time_enforced?).and_return true
+ end
+
+ it "does not allow 'add_column' to be called" do
+ expect_offense(<<~CODE)
+ add_column
+ ^^^^^^^^^^ #{described_class::MSG}
+ CODE
+ end
+
+ it "does not allow 'create_table' to be called" do
+ expect_offense(<<~CODE)
+ create_table
+ ^^^^^^^^^^^^ #{described_class::MSG}
+ CODE
+ end
+end
diff --git a/spec/rubocop/cop/rake/require_spec.rb b/spec/rubocop/cop/rake/require_spec.rb
new file mode 100644
index 00000000000..bb8c6a1f063
--- /dev/null
+++ b/spec/rubocop/cop/rake/require_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require 'rubocop_spec_helper'
+
+require_relative '../../../../rubocop/cop/rake/require'
+
+RSpec.describe RuboCop::Cop::Rake::Require do
+ let(:msg) { described_class::MSG }
+
+ it 'registers an offenses for require methods' do
+ expect_offense(<<~RUBY)
+ require 'json'
+ ^^^^^^^^^^^^^^ #{msg}
+ require_relative 'gitlab/json'
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #{msg}
+ RUBY
+ end
+
+ it 'does not register offense inside `task` definition' do
+ expect_no_offenses(<<~RUBY)
+ task :parse do
+ require 'json'
+ end
+
+ namespace :some do
+ task parse: :env do
+ require_relative 'gitlab/json'
+ end
+ end
+ RUBY
+ end
+
+ it 'does not register offense inside a block definition' do
+ expect_no_offenses(<<~RUBY)
+ RSpec::Core::RakeTask.new(:parse_json) do |t, args|
+ require 'json'
+ end
+ RUBY
+ end
+
+ it 'does not register offense inside a method definition' do
+ expect_no_offenses(<<~RUBY)
+ def load_deps
+ require 'json'
+ end
+
+ task :parse do
+ load_deps
+ end
+ RUBY
+ end
+
+ it 'does not register offense when require task related files' do
+ expect_no_offenses(<<~RUBY)
+ require 'rubocop/rake_tasks'
+ require 'gettext_i18n_rails/tasks'
+ require_relative '../../rubocop/check_graceful_task'
+ RUBY
+ end
+end
diff --git a/spec/rubocop/cop/rspec/duplicate_spec_location_spec.rb b/spec/rubocop/cop/rspec/duplicate_spec_location_spec.rb
new file mode 100644
index 00000000000..f209ae81661
--- /dev/null
+++ b/spec/rubocop/cop/rspec/duplicate_spec_location_spec.rb
@@ -0,0 +1,98 @@
+# frozen_string_literal: true
+
+require 'rubocop_spec_helper'
+
+require_relative '../../../../rubocop/cop/rspec/duplicate_spec_location'
+
+RSpec.describe RuboCop::Cop::RSpec::DuplicateSpecLocation do
+ let(:rails_root) { '../../../../' }
+
+ def full_path(path)
+ File.expand_path(File.join(rails_root, path), __dir__)
+ end
+
+ context 'for a non-EE spec file' do
+ it 'registers no offenses' do
+ expect_no_offenses(<<~SOURCE, full_path('spec/foo_spec.rb'))
+ describe 'Foo' do
+ end
+ SOURCE
+ end
+ end
+
+ context 'for a non-EE application file' do
+ it 'registers no offenses' do
+ expect_no_offenses(<<~SOURCE, full_path('app/models/blog_post.rb'))
+ class BlogPost
+ end
+ SOURCE
+ end
+ end
+
+ context 'for an EE application file' do
+ it 'registers no offenses' do
+ expect_no_offenses(<<~SOURCE, full_path('ee/app/models/blog_post.rb'))
+ class BlogPost
+ end
+ SOURCE
+ end
+ end
+
+ context 'for an EE spec file for EE only code' do
+ let(:spec_file_path) { full_path('ee/spec/controllers/foo_spec.rb') }
+
+ it 'registers no offenses' do
+ expect_no_offenses(<<~SOURCE, spec_file_path)
+ describe 'Foo' do
+ end
+ SOURCE
+ end
+
+ context 'when there is a duplicate file' do
+ before do
+ allow(File).to receive(:exist?).and_call_original
+
+ allow(File).to receive(:exist?)
+ .with(full_path('ee/spec/controllers/ee/foo_spec.rb'))
+ .and_return(true)
+ end
+
+ it 'marks the describe as offending' do
+ expect_offense(<<~SOURCE, spec_file_path)
+ describe 'Foo' do
+ ^^^^^^^^^^^^^^ Duplicate spec location in `ee/spec/controllers/ee/foo_spec.rb`.
+ end
+ SOURCE
+ end
+ end
+ end
+
+ context 'for an EE spec file for EE extension' do
+ let(:spec_file_path) { full_path('ee/spec/controllers/ee/foo_spec.rb') }
+
+ it 'registers no offenses' do
+ expect_no_offenses(<<~SOURCE, spec_file_path)
+ describe 'Foo' do
+ end
+ SOURCE
+ end
+
+ context 'when there is a duplicate file' do
+ before do
+ allow(File).to receive(:exist?).and_call_original
+
+ allow(File).to receive(:exist?)
+ .with(full_path('ee/spec/controllers/foo_spec.rb'))
+ .and_return(true)
+ end
+
+ it 'marks the describe as offending' do
+ expect_offense(<<~SOURCE, spec_file_path)
+ describe 'Foo' do
+ ^^^^^^^^^^^^^^ Duplicate spec location in `ee/spec/controllers/foo_spec.rb`.
+ end
+ SOURCE
+ end
+ end
+ end
+end
diff --git a/spec/rubocop/cop/rspec/factory_bot/strategy_in_callback_spec.rb b/spec/rubocop/cop/rspec/factory_bot/strategy_in_callback_spec.rb
new file mode 100644
index 00000000000..9dcfebc7c1d
--- /dev/null
+++ b/spec/rubocop/cop/rspec/factory_bot/strategy_in_callback_spec.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+require 'rubocop_spec_helper'
+
+require_relative '../../../../../rubocop/cop/rspec/factory_bot/strategy_in_callback'
+
+RSpec.describe RuboCop::Cop::RSpec::FactoryBot::StrategyInCallback do
+ shared_examples 'an offensive factory call' do |namespace|
+ described_class::FORBIDDEN_METHODS.each do |forbidden_method|
+ namespaced_forbidden_method = "#{namespace}#{forbidden_method}(:ci_job_artifact, :archive)"
+
+ it "registers an offence for multiple #{namespaced_forbidden_method} calls" do
+ expect_offense(<<-RUBY)
+ FactoryBot.define do
+ factory :ci_build, class: 'Ci::Build', parent: :ci_processable do
+ trait :artifacts do
+ before(:create) do
+ #{namespaced_forbidden_method}
+ #{'^' * namespaced_forbidden_method.size} Prefer inline `association` over `#{forbidden_method}`. See https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#factories
+ end
+
+ after(:create) do |build|
+ #{namespaced_forbidden_method}
+ #{'^' * namespaced_forbidden_method.size} Prefer inline `association` over `#{forbidden_method}`. See https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#factories
+ #{namespaced_forbidden_method}
+ #{'^' * namespaced_forbidden_method.size} Prefer inline `association` over `#{forbidden_method}`. See https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#factories
+ end
+ end
+ end
+ end
+ RUBY
+ end
+
+ it "registers an offense for #{namespaced_forbidden_method} when is a send node" do
+ expect_offense(<<-RUBY)
+ FactoryBot.define do
+ factory :ci_build, class: 'Ci::Build', parent: :ci_processable do
+ trait :artifacts do
+ after(:create) do |build|
+ #{namespaced_forbidden_method}
+ #{'^' * namespaced_forbidden_method.size} Prefer inline `association` over `#{forbidden_method}`. See https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#factories
+ end
+ end
+ end
+ end
+ RUBY
+ end
+
+ it "registers an offense for #{namespaced_forbidden_method} when is assigned" do
+ expect_offense(<<-RUBY)
+ FactoryBot.define do
+ factory :ci_build, class: 'Ci::Build', parent: :ci_processable do
+ trait :artifacts do
+ after(:create) do |build|
+ ci_build = #{namespaced_forbidden_method}
+ #{'^' * namespaced_forbidden_method.size} Prefer inline `association` over `#{forbidden_method}`. See https://docs.gitlab.com/ee/development/testing_guide/best_practices.html#factories
+
+ ci_build
+ end
+ end
+ end
+ end
+ RUBY
+ end
+ end
+ end
+
+ it_behaves_like 'an offensive factory call', ''
+ it_behaves_like 'an offensive factory call', 'FactoryBot.'
+ it_behaves_like 'an offensive factory call', '::FactoryBot.'
+end
diff --git a/spec/rubocop/migration_helpers_spec.rb b/spec/rubocop/migration_helpers_spec.rb
index 997d4071c29..6e6c3a7a0b9 100644
--- a/spec/rubocop/migration_helpers_spec.rb
+++ b/spec/rubocop/migration_helpers_spec.rb
@@ -52,4 +52,21 @@ RSpec.describe RuboCop::MigrationHelpers do
it { expect(fake_cop.version(node)).to eq(20200210184420) }
end
+
+ describe '#time_enforced?' do
+ before do
+ allow(fake_cop).to receive(:name).and_return("TestCop")
+ allow(fake_cop).to receive(:config).and_return(double(for_cop: { 'EnforcedSince' => 20221018000000 }))
+ end
+
+ where(:name, :expected) do
+ '/gitlab/db/post_migrate/20200210184420_create_operations_scopes_table.rb' | false
+ '/gitlab/db/post_migrate/20220210184420_create_fake_table.rb' | false
+ '/gitlab/db/post_migrate/20221019184420_add_id_to_reports_table.rb' | true
+ end
+
+ with_them do
+ it { expect(fake_cop.time_enforced?(node)).to eq(expected) }
+ end
+ end
end
diff --git a/spec/rubocop_spec_helper.rb b/spec/rubocop_spec_helper.rb
index cf747132ec1..d57461960f2 100644
--- a/spec/rubocop_spec_helper.rb
+++ b/spec/rubocop_spec_helper.rb
@@ -12,10 +12,7 @@ require_relative './support/shared_contexts/rubocop_default_rspec_language_confi
RSpec.configure do |config|
config.define_derived_metadata(file_path: %r{spec/rubocop}) do |metadata|
- # TODO: move DuplicateSpecLocation cop to RSpec::DuplicateSpecLocation
- unless metadata[:type] == :rubocop_rspec
- metadata[:type] = :rubocop
- end
+ metadata[:type] = :rubocop
end
config.define_derived_metadata(file_path: %r{spec/rubocop/cop/rspec}) do |metadata|
diff --git a/spec/scripts/failed_tests_spec.rb b/spec/scripts/failed_tests_spec.rb
index 92eae75b3be..b99fd991c55 100644
--- a/spec/scripts/failed_tests_spec.rb
+++ b/spec/scripts/failed_tests_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper'
+require 'fast_spec_helper'
require_relative '../../scripts/failed_tests'
RSpec.describe FailedTests do
diff --git a/spec/scripts/lib/glfm/update_example_snapshots_spec.rb b/spec/scripts/lib/glfm/update_example_snapshots_spec.rb
index c97226c1a2d..58e016b6d68 100644
--- a/spec/scripts/lib/glfm/update_example_snapshots_spec.rb
+++ b/spec/scripts/lib/glfm/update_example_snapshots_spec.rb
@@ -32,8 +32,8 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
subject { described_class.new }
# GLFM input files
- let(:glfm_spec_txt_path) { described_class::GLFM_SPEC_TXT_PATH }
- let(:glfm_spec_txt_local_io) { StringIO.new(glfm_spec_txt_contents) }
+ let(:es_snapshot_spec_md_path) { described_class::ES_SNAPSHOT_SPEC_MD_PATH }
+ let(:es_snapshot_spec_md_local_io) { StringIO.new(es_snapshot_spec_md_contents) }
let(:glfm_example_status_yml_path) { described_class::GLFM_EXAMPLE_STATUS_YML_PATH }
let(:glfm_example_metadata_yml_path) { described_class::GLFM_EXAMPLE_METADATA_YML_PATH }
let(:glfm_example_normalizations_yml_path) { described_class::GLFM_EXAMPLE_NORMALIZATIONS_YML_PATH }
@@ -53,16 +53,11 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
# Internal tempfiles
let(:static_html_tempfile_path) { Tempfile.new.path }
- let(:glfm_spec_txt_contents) do
+ let(:es_snapshot_spec_md_contents) do
<<~MARKDOWN
---
title: GitLab Flavored Markdown Spec
...
-
- # Introduction
-
- GLFM intro text...
-
# Inlines
## Strong
@@ -96,7 +91,7 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
### Another H3
This is a second consecutive third-level heading. It exists to drive full code coverage
- for this scenario, although it doesn't (yet) exist in the actual spec.txt.
+ for this scenario, although it doesn't (yet) exist in the actual snapshot_spec.md.
## An H2 with all disabled examples
@@ -243,12 +238,6 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
.
<p><a href="project-wikis-test-file">project-wikis-test-file</a></p>
````````````````````````````````
-
- <!-- END TESTS -->
-
- # Appendix
-
- Appendix text.
MARKDOWN
end
@@ -305,11 +294,11 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
---
01_00_00__obsolete_entry_to_be_deleted__001:
canonical: |
- This entry is no longer exists in the spec.txt, so it will be deleted.
+ This entry is no longer exists in the snapshot_spec.md, so it will be deleted.
static: |-
- This entry is no longer exists in the spec.txt, so it will be deleted.
+ This entry is no longer exists in the snapshot_spec.md, so it will be deleted.
wysiwyg: |-
- This entry is no longer exists in the spec.txt, so it will be deleted.
+ This entry is no longer exists in the snapshot_spec.md, so it will be deleted.
02_01_00__inlines__strong__001:
canonical: |
This entry is existing, but not skipped, so it will be overwritten.
@@ -332,7 +321,7 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
---
01_00_00__obsolete_entry_to_be_deleted__001: |-
{
- "obsolete": "This entry is no longer exists in the spec.txt, and is not skipped, so it will be deleted."
+ "obsolete": "This entry is no longer exists in the snapshot_spec.md, and is not skipped, so it will be deleted."
}
02_01_00__inlines__strong__001: |-
{
@@ -370,7 +359,7 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
# actual network and filesystem I/O during the spec run.
# input files
- allow(File).to receive(:open).with(glfm_spec_txt_path) { glfm_spec_txt_local_io }
+ allow(File).to receive(:open).with(es_snapshot_spec_md_path) { es_snapshot_spec_md_local_io }
allow(File).to receive(:open).with(glfm_example_status_yml_path) do
StringIO.new(glfm_example_status_yml_contents)
end
@@ -454,43 +443,43 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
<<~YAML
---
02_01_00__inlines__strong__001:
- spec_txt_example_position: 1
+ spec_example_position: 1
source_specification: commonmark
02_01_00__inlines__strong__002:
- spec_txt_example_position: 2
+ spec_example_position: 2
source_specification: github
02_03_00__inlines__strikethrough_extension__001:
- spec_txt_example_position: 4
+ spec_example_position: 4
source_specification: github
03_01_00__first_gitlab_specific_section_with_examples__strong_but_with_two_asterisks__001:
- spec_txt_example_position: 5
+ spec_example_position: 5
source_specification: gitlab
03_02_01__first_gitlab_specific_section_with_examples__h2_which_contains_an_h3__example_in_an_h3__001:
- spec_txt_example_position: 6
+ spec_example_position: 6
source_specification: gitlab
04_01_00__second_gitlab_specific_section_with_examples__strong_but_with_html__001:
- spec_txt_example_position: 7
+ spec_example_position: 7
source_specification: gitlab
05_01_00__third_gitlab_specific_section_with_skipped_examples__strong_but_skipped__001:
- spec_txt_example_position: 8
+ spec_example_position: 8
source_specification: gitlab
05_02_00__third_gitlab_specific_section_with_skipped_examples__strong_but_manually_modified_and_skipped__001:
- spec_txt_example_position: 9
+ spec_example_position: 9
source_specification: gitlab
06_01_00__api_request_overrides__group_upload_link__001:
- spec_txt_example_position: 10
+ spec_example_position: 10
source_specification: gitlab
06_02_00__api_request_overrides__project_repo_link__001:
- spec_txt_example_position: 11
+ spec_example_position: 11
source_specification: gitlab
06_03_00__api_request_overrides__project_snippet_ref__001:
- spec_txt_example_position: 12
+ spec_example_position: 12
source_specification: gitlab
06_04_00__api_request_overrides__personal_snippet_ref__001:
- spec_txt_example_position: 13
+ spec_example_position: 13
source_specification: gitlab
06_05_00__api_request_overrides__project_wiki_link__001:
- spec_txt_example_position: 14
+ spec_example_position: 14
source_specification: gitlab
YAML
end
@@ -696,7 +685,7 @@ RSpec.describe Glfm::UpdateExampleSnapshots, '#process' do
canonical: |
<p><a href="projects-test-file">projects-test-file</a></p>
static: |-
- <p data-sourcepos="1:1-1:40" dir="auto"><a href="/glfm_group/glfm_project/-/blob/master/projects-test-file">projects-test-file</a></p>
+ <p data-sourcepos="1:1-1:40" dir="auto"><a href="/glfm_group/glfm_project/-/blob/master/projects-test-file" class="gfm">projects-test-file</a></p>
wysiwyg: |-
<p><a target="_blank" rel="noopener noreferrer nofollow" href="projects-test-file">projects-test-file</a></p>
06_03_00__api_request_overrides__project_snippet_ref__001:
diff --git a/spec/scripts/lib/glfm/update_specification_spec.rb b/spec/scripts/lib/glfm/update_specification_spec.rb
index 852b2b580e6..ccf1a8fd26a 100644
--- a/spec/scripts/lib/glfm/update_specification_spec.rb
+++ b/spec/scripts/lib/glfm/update_specification_spec.rb
@@ -37,18 +37,44 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
let(:ghfm_spec_md_path) { described_class::GHFM_SPEC_MD_PATH }
let(:ghfm_spec_txt_local_io) { StringIO.new(ghfm_spec_txt_contents) }
- let(:glfm_intro_md_path) { described_class::GLFM_INTRO_MD_PATH }
- let(:glfm_intro_md_io) { StringIO.new(glfm_intro_md_contents) }
- let(:glfm_official_specification_examples_md_path) { described_class::GLFM_OFFICIAL_SPECIFICATION_EXAMPLES_MD_PATH }
- let(:glfm_official_specification_examples_md_io) { StringIO.new(glfm_official_specification_examples_md_contents) }
- let(:glfm_internal_extension_examples_md_path) { described_class::GLFM_INTERNAL_EXTENSION_EXAMPLES_MD_PATH }
- let(:glfm_internal_extension_examples_md_io) { StringIO.new(glfm_internal_extension_examples_md_contents) }
+ let(:glfm_official_specification_md_path) { described_class::GLFM_OFFICIAL_SPECIFICATION_MD_PATH }
+ let(:glfm_official_specification_md_io) { StringIO.new(glfm_official_specification_md_contents) }
+ let(:glfm_internal_extensions_md_path) { described_class::GLFM_INTERNAL_EXTENSIONS_MD_PATH }
+ let(:glfm_internal_extensions_md_io) { StringIO.new(glfm_internal_extensions_md_contents) }
let(:glfm_spec_txt_path) { described_class::GLFM_SPEC_TXT_PATH }
let(:glfm_spec_txt_io) { StringIO.new }
let(:glfm_spec_html_path) { described_class::GLFM_SPEC_HTML_PATH }
let(:glfm_spec_html_io) { StringIO.new }
+ let(:es_snapshot_spec_md_path) { described_class::ES_SNAPSHOT_SPEC_MD_PATH }
+ let(:es_snapshot_spec_md_io) { StringIO.new }
+ let(:es_snapshot_spec_html_path) { described_class::ES_SNAPSHOT_SPEC_HTML_PATH }
+ let(:es_snapshot_spec_html_io) { StringIO.new }
let(:markdown_tempfile_io) { StringIO.new }
+ let(:ghfm_spec_txt_examples) do
+ <<~MARKDOWN
+ # Section with Examples
+
+ ## Emphasis and Strong
+
+ ```````````````````````````````` example
+ _EMPHASIS LINE 1_
+ _EMPHASIS LINE 2_
+ .
+ <p><em>EMPHASIS LINE 1</em>
+ <em>EMPHASIS LINE 2</em></p>
+ ````````````````````````````````
+
+ ```````````````````````````````` example
+ __STRONG!__
+ .
+ <p><strong>STRONG!</strong></p>
+ ````````````````````````````````
+
+ End of last GitHub examples section.
+ MARKDOWN
+ end
+
let(:ghfm_spec_txt_contents) do
<<~MARKDOWN
---
@@ -60,22 +86,9 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
# Introduction
- ## What is GitHub Flavored Markdown?
-
- It's like GLFM, but with an H.
-
- # Section with Examples
-
- ## Strong
-
- ```````````````````````````````` example
- __bold__
- .
- <p><strong>bold</strong></p>
- ````````````````````````````````
-
- End of last GitHub examples section.
+ GHFM Intro.
+ #{ghfm_spec_txt_examples}
<!-- END TESTS -->
# Appendix
@@ -84,26 +97,28 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
MARKDOWN
end
- let(:glfm_intro_md_contents) do
- # language=Markdown
+ let(:glfm_official_specification_md_examples) do
<<~MARKDOWN
- # Introduction
-
- ## What is GitLab Flavored Markdown?
+ # Official Specification Section with Examples
- Intro text about GitLab Flavored Markdown.
+ Some examples.
MARKDOWN
end
- let(:glfm_official_specification_examples_md_contents) do
+ let(:glfm_official_specification_md_contents) do
<<~MARKDOWN
- # Official Specification Section with Examples
+ # GLFM Introduction
- Some examples.
+ GLFM intro text.
+
+ <!-- BEGIN TESTS -->
+ #{glfm_official_specification_md_examples}
+ <!-- END TESTS -->
+ # Non-example official content
MARKDOWN
end
- let(:glfm_internal_extension_examples_md_contents) do
+ let(:glfm_internal_extensions_md_examples) do
<<~MARKDOWN
# Internal Extension Section with Examples
@@ -111,10 +126,19 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
MARKDOWN
end
+ let(:glfm_internal_extensions_md_contents) do
+ <<~MARKDOWN
+ # Non-example internal content
+ <!-- BEGIN TESTS -->
+ #{glfm_internal_extensions_md_examples}
+ <!-- END TESTS -->
+ # More non-example internal content
+ MARKDOWN
+ end
+
before do
# Mock default ENV var values
- allow(ENV).to receive(:[]).with('UPDATE_GHFM_SPEC_MD').and_return(nil)
- allow(ENV).to receive(:[]).and_call_original
+ stub_env('UPDATE_GHFM_SPEC_MD')
# We mock out the URI and local file IO objects with real StringIO, instead of just mock
# objects. This gives better and more realistic coverage, while still avoiding
@@ -124,17 +148,18 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
allow(URI).to receive(:parse).with(ghfm_spec_txt_uri).and_return(ghfm_spec_txt_uri_parsed)
allow(ghfm_spec_txt_uri_parsed).to receive(:open).and_return(ghfm_spec_txt_uri_io)
allow(File).to receive(:open).with(ghfm_spec_md_path) { ghfm_spec_txt_local_io }
- allow(File).to receive(:open).with(glfm_intro_md_path) { glfm_intro_md_io }
- allow(File).to receive(:open).with(glfm_official_specification_examples_md_path) do
- glfm_official_specification_examples_md_io
+ allow(File).to receive(:open).with(glfm_official_specification_md_path) do
+ glfm_official_specification_md_io
end
- allow(File).to receive(:open).with(glfm_internal_extension_examples_md_path) do
- glfm_internal_extension_examples_md_io
+ allow(File).to receive(:open).with(glfm_internal_extensions_md_path) do
+ glfm_internal_extensions_md_io
end
# output files
allow(File).to receive(:open).with(glfm_spec_txt_path, 'w') { glfm_spec_txt_io }
allow(File).to receive(:open).with(glfm_spec_html_path, 'w') { glfm_spec_html_io }
+ allow(File).to receive(:open).with(es_snapshot_spec_md_path, 'w') { es_snapshot_spec_md_io }
+ allow(File).to receive(:open).with(es_snapshot_spec_html_path, 'w') { es_snapshot_spec_html_io }
# Allow normal opening of Tempfile files created during script execution.
tempfile_basenames = [
@@ -166,7 +191,7 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
let(:ghfm_spec_txt_local_io) { StringIO.new }
before do
- allow(ENV).to receive(:[]).with('UPDATE_GHFM_SPEC_MD').and_return('true')
+ stub_env('UPDATE_GHFM_SPEC_MD', 'true')
allow(File).to receive(:open).with(ghfm_spec_md_path, 'w') { ghfm_spec_txt_local_io }
end
@@ -217,90 +242,121 @@ RSpec.describe Glfm::UpdateSpecification, '#process' do
end
end
- describe 'writing GLFM spec.txt' do
- let(:glfm_contents) { reread_io(glfm_spec_txt_io) }
+ describe 'writing output_spec/spec.txt' do
+ let(:glfm_spec_txt_contents) { reread_io(glfm_spec_txt_io) }
before do
subject.process(skip_spec_html_generation: true)
end
- it 'replaces the header text with the GitLab version' do
- expect(glfm_contents).not_to match(/GitHub Flavored Markdown Spec/m)
- expect(glfm_contents).not_to match(/^version: \d\.\d/m)
- expect(glfm_contents).not_to match(/^date: /m)
- expect(glfm_contents).not_to match(/^license: /m)
- expect(glfm_contents).to match(/#{Regexp.escape(described_class::GLFM_SPEC_TXT_HEADER)}\n/mo)
+ it 'includes only the header and official examples' do
+ expected = described_class::GLFM_SPEC_TXT_HEADER + glfm_official_specification_md_contents
+ expect(glfm_spec_txt_contents).to eq(expected)
end
+ end
- it 'replaces the intro section with the GitLab version' do
- expect(glfm_contents).not_to match(/What is GitHub Flavored Markdown/m)
- expect(glfm_contents).to match(/#{Regexp.escape(glfm_intro_md_contents)}/m)
- end
-
- it 'inserts the GitLab official spec and internal extension examples sections before the appendix section' do
- expected = <<~MARKDOWN
- End of last GitHub examples section.
-
- # Official Specification Section with Examples
-
- Some examples.
+ describe 'writing output_example_snapshots/snapshot_spec.md' do
+ let(:es_snapshot_spec_md_contents) { reread_io(es_snapshot_spec_md_io) }
- # Internal Extension Section with Examples
+ before do
+ subject.process(skip_spec_html_generation: true)
+ end
- Some examples.
+ it 'replaces the header text with the GitLab version' do
+ expect(es_snapshot_spec_md_contents).not_to match(/GitHub Flavored Markdown Spec/m)
+ expect(es_snapshot_spec_md_contents).not_to match(/^version: \d\.\d/m)
+ expect(es_snapshot_spec_md_contents).not_to match(/^date: /m)
- <!-- END TESTS -->
+ expect(es_snapshot_spec_md_contents).to match(/#{Regexp.escape(described_class::GLFM_SPEC_TXT_HEADER)}/mo)
+ end
- # Appendix
- MARKDOWN
- expect(glfm_contents).to match(/#{Regexp.escape(expected)}/m)
+ it 'includes header and all examples', :unlimited_max_formatted_output_length do
+ # rubocop:disable Style/StringConcatenation (string contatenation is more readable)
+ expected = described_class::GLFM_SPEC_TXT_HEADER +
+ ghfm_spec_txt_examples +
+ "\n" +
+ glfm_official_specification_md_examples +
+ "\n\n" + # NOTE: We want a blank line between the official and internal examples
+ glfm_internal_extensions_md_examples +
+ "\n"
+ # rubocop:enable Style/StringConcatenation
+ expect(es_snapshot_spec_md_contents).to eq(expected)
end
end
- describe 'writing GLFM spec.html' do
- let(:glfm_contents) { reread_io(glfm_spec_html_io) }
+ # rubocop:disable RSpec/MultipleMemoizedHelpers
+ describe 'writing output html files' do
+ let(:spec_html_contents) { reread_io(glfm_spec_html_io) }
+ let(:snapshot_spec_html_contents) { reread_io(es_snapshot_spec_html_io) }
before do
subject.process
end
- it 'renders HTML from spec.txt', :unlimited_max_formatted_output_length do
- expected = <<~HTML
+ it 'renders expected HTML', :unlimited_max_formatted_output_length do
+ # NOTE: We do assertions for both output HTML files in this same `it` example block,
+ # because calling a full `subject.process` without `skip_spec_html_generation: true`
+ # is very slow, and want to avoid doing it twice.
+
+ expected_spec_html = <<~RENDERED_HTML
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="1:1-4:3" lang="yaml" class="code highlight js-syntax-highlight language-yaml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="yaml"><span class="na">title</span><span class="pi">:</span> <span class="s">GitLab Flavored Markdown (GLFM) Spec</span></span>
+ <span id="LC2" class="line" lang="yaml"><span class="na">version</span><span class="pi">:</span> <span class="s">alpha</span></span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <h1 data-sourcepos="5:1-5:19" dir="auto">
+ <a id="user-content-glfm-introduction" class="anchor" href="#glfm-introduction" aria-hidden="true"></a>GLFM Introduction</h1>
+ <p data-sourcepos="7:1-7:16" dir="auto">GLFM intro text.</p>
+
+ <h1 data-sourcepos="10:1-10:46" dir="auto">
+ <a id="user-content-official-specification-section-with-examples" class="anchor" href="#official-specification-section-with-examples" aria-hidden="true"></a>Official Specification Section with Examples</h1>
+ <p data-sourcepos="12:1-12:14" dir="auto">Some examples.</p>
+
+ <h1 data-sourcepos="15:1-15:30" dir="auto">
+ <a id="user-content-non-example-official-content" class="anchor" href="#non-example-official-content" aria-hidden="true"></a>Non-example official content</h1>
+ RENDERED_HTML
+ expect(spec_html_contents).to be == expected_spec_html
+
+ expected_snapshot_spec_html = <<~RENDERED_HTML
<div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="1:1-4:3" class="code highlight js-syntax-highlight language-yaml" lang="yaml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="yaml"><span class="na">title</span><span class="pi">:</span> <span class="s">GitLab Flavored Markdown (GLFM) Spec</span></span>
+ <pre data-sourcepos="1:1-4:3" lang="yaml" class="code highlight js-syntax-highlight language-yaml" data-lang-params="frontmatter" v-pre="true"><code><span id="LC1" class="line" lang="yaml"><span class="na">title</span><span class="pi">:</span> <span class="s">GitLab Flavored Markdown (GLFM) Spec</span></span>
<span id="LC2" class="line" lang="yaml"><span class="na">version</span><span class="pi">:</span> <span class="s">alpha</span></span></code></pre>
<copy-code></copy-code>
</div>
- <h1 data-sourcepos="6:1-6:14" dir="auto">
- <a id="user-content-introduction" class="anchor" href="#introduction" aria-hidden="true"></a>Introduction</h1>
- <h2 data-sourcepos="8:1-8:36" dir="auto">
- <a id="user-content-what-is-gitlab-flavored-markdown" class="anchor" href="#what-is-gitlab-flavored-markdown" aria-hidden="true"></a>What is GitLab Flavored Markdown?</h2>
- <p data-sourcepos="10:1-10:42" dir="auto">Intro text about GitLab Flavored Markdown.</p>
- <h1 data-sourcepos="12:1-12:23" dir="auto">
+ <h1 data-sourcepos="5:1-5:23" dir="auto">
<a id="user-content-section-with-examples" class="anchor" href="#section-with-examples" aria-hidden="true"></a>Section with Examples</h1>
- <h2 data-sourcepos="14:1-14:9" dir="auto">
- <a id="user-content-strong" class="anchor" href="#strong" aria-hidden="true"></a>Strong</h2>
+ <h2 data-sourcepos="7:1-7:22" dir="auto">
+ <a id="user-content-emphasis-and-strong" class="anchor" href="#emphasis-and-strong" aria-hidden="true"></a>Emphasis and Strong</h2>
<div class="gl-relative markdown-code-block js-markdown-code">
- <pre data-sourcepos="16:1-20:32" class="code highlight js-syntax-highlight language-plaintext" lang="plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__bold__</span>
- <span id="LC2" class="line" lang="plaintext">.</span>
- <span id="LC3" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;bold&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+ <pre data-sourcepos="9:1-12:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">_EMPHASIS LINE 1_</span>
+ <span id="LC2" class="line" lang="plaintext">_EMPHASIS LINE 2_</span></code></pre>
<copy-code></copy-code>
</div>
- <p data-sourcepos="22:1-22:36" dir="auto">End of last GitHub examples section.</p>
- <h1 data-sourcepos="24:1-24:46" dir="auto">
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="14:1-17:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;em&gt;EMPHASIS LINE 1&lt;/em&gt;</span>
+ <span id="LC2" class="line" lang="plaintext">&lt;em&gt;EMPHASIS LINE 2&lt;/em&gt;&lt;/p&gt;</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="19:1-21:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="example" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">__STRONG!__</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <div class="gl-relative markdown-code-block js-markdown-code">
+ <pre data-sourcepos="23:1-25:32" lang="plaintext" class="code highlight js-syntax-highlight language-plaintext" data-canonical-lang="" v-pre="true"><code><span id="LC1" class="line" lang="plaintext">&lt;p&gt;&lt;strong&gt;STRONG!&lt;/strong&gt;&lt;/p&gt;</span></code></pre>
+ <copy-code></copy-code>
+ </div>
+ <p data-sourcepos="27:1-27:36" dir="auto">End of last GitHub examples section.</p>
+ <h1 data-sourcepos="29:1-29:46" dir="auto">
<a id="user-content-official-specification-section-with-examples" class="anchor" href="#official-specification-section-with-examples" aria-hidden="true"></a>Official Specification Section with Examples</h1>
- <p data-sourcepos="26:1-26:14" dir="auto">Some examples.</p>
- <h1 data-sourcepos="28:1-28:42" dir="auto">
+ <p data-sourcepos="31:1-31:14" dir="auto">Some examples.</p>
+ <h1 data-sourcepos="34:1-34:42" dir="auto">
<a id="user-content-internal-extension-section-with-examples" class="anchor" href="#internal-extension-section-with-examples" aria-hidden="true"></a>Internal Extension Section with Examples</h1>
- <p data-sourcepos="30:1-30:14" dir="auto">Some examples.</p>
-
- <h1 data-sourcepos="34:1-34:10" dir="auto">
- <a id="user-content-appendix" class="anchor" href="#appendix" aria-hidden="true"></a>Appendix</h1>
- <p data-sourcepos="36:1-36:14" dir="auto">Appendix text.</p>
- HTML
- expect(glfm_contents).to be == expected
+ <p data-sourcepos="36:1-36:14" dir="auto">Some examples.</p>
+ RENDERED_HTML
+ expect(snapshot_spec_html_contents).to be == expected_snapshot_spec_html
end
end
+ # rubocop:enable RSpec/MultipleMemoizedHelpers
def reread_io(io)
# Reset the io StringIO to the beginning position of the buffer
diff --git a/spec/scripts/lib/glfm/verify_all_generated_files_are_up_to_date_spec.rb b/spec/scripts/lib/glfm/verify_all_generated_files_are_up_to_date_spec.rb
index fca037c9ff3..c678565fe90 100644
--- a/spec/scripts/lib/glfm/verify_all_generated_files_are_up_to_date_spec.rb
+++ b/spec/scripts/lib/glfm/verify_all_generated_files_are_up_to_date_spec.rb
@@ -9,8 +9,8 @@ require_relative '../../../../scripts/lib/glfm/verify_all_generated_files_are_up
RSpec.describe Glfm::VerifyAllGeneratedFilesAreUpToDate, '#process' do
subject { described_class.new }
- let(:output_path) { described_class::GLFM_SPEC_OUTPUT_PATH }
- let(:snapshots_path) { described_class::EXAMPLE_SNAPSHOTS_PATH }
+ let(:output_path) { described_class::GLFM_OUTPUT_SPEC_PATH }
+ let(:snapshots_path) { described_class::ES_OUTPUT_EXAMPLE_SNAPSHOTS_PATH }
let(:verify_cmd) { "git status --porcelain #{output_path} #{snapshots_path}" }
before do
@@ -52,10 +52,13 @@ RSpec.describe Glfm::VerifyAllGeneratedFilesAreUpToDate, '#process' do
before do
# Simulate a clean repo, then simulate changes to generated files
allow(subject).to receive(:run_external_cmd).twice.with(verify_cmd).and_return('', "M #{snapshots_path}")
+ allow(subject).to receive(:run_external_cmd).with('git diff')
+ allow(subject).to receive(:warn).and_call_original
end
it 'raises an error', :unlimited_max_formatted_output_length do
- expect { subject.process }.to raise_error(/following files were modified.*#{snapshots_path}/m)
+ expect(subject).to receive(:warn).with(/following files were modified.*#{snapshots_path}/m)
+ expect { subject.process }.to raise_error(/The generated files are not up to date/)
end
end
end
diff --git a/spec/scripts/pipeline_test_report_builder_spec.rb b/spec/scripts/pipeline_test_report_builder_spec.rb
index 198cdefc530..b51b4dc4887 100644
--- a/spec/scripts/pipeline_test_report_builder_spec.rb
+++ b/spec/scripts/pipeline_test_report_builder_spec.rb
@@ -1,6 +1,6 @@
# frozen_string_literal: true
-require 'spec_helper'
+require 'fast_spec_helper'
require_relative '../../scripts/pipeline_test_report_builder'
RSpec.describe PipelineTestReportBuilder do
diff --git a/spec/serializers/ci/pipeline_entity_spec.rb b/spec/serializers/ci/pipeline_entity_spec.rb
index 808dc38f653..ff364918b4f 100644
--- a/spec/serializers/ci/pipeline_entity_spec.rb
+++ b/spec/serializers/ci/pipeline_entity_spec.rb
@@ -15,12 +15,13 @@ RSpec.describe Ci::PipelineEntity do
subject { entity.as_json }
context 'when pipeline is empty' do
- let(:pipeline) { create(:ci_empty_pipeline) }
+ let(:pipeline) { create(:ci_empty_pipeline, name: 'Build pipeline') }
it 'contains required fields' do
expect(subject).to include :id, :iid, :user, :path, :coverage, :source
expect(subject).to include :ref, :commit
expect(subject).to include :updated_at, :created_at
+ expect(subject[:name]).to eq('Build pipeline')
end
it 'excludes coverage data when disabled' do
@@ -31,10 +32,15 @@ RSpec.describe Ci::PipelineEntity do
end
it 'contains details' do
+ allow(pipeline).to receive(:merge_request_event_type).and_return(:merged_result)
+
expect(subject).to include :details
expect(subject[:details])
- .to include :duration, :finished_at, :name
+ .to include :duration, :finished_at, :name, :event_type_name
expect(subject[:details][:status]).to include :icon, :favicon, :text, :label, :tooltip
+
+ expect(subject[:details][:event_type_name]).to eq('Merged result pipeline')
+ expect(subject[:details][:name]).to eq('Merged result pipeline')
end
it 'contains flags' do
@@ -43,6 +49,16 @@ RSpec.describe Ci::PipelineEntity do
.to include :stuck, :auto_devops, :yaml_errors,
:retryable, :cancelable, :merge_request
end
+
+ context 'when pipeline_name feature flag is disabled' do
+ before do
+ stub_feature_flags(pipeline_name: false)
+ end
+
+ it 'does not return name' do
+ is_expected.not_to include(:name)
+ end
+ end
end
context 'when default branch not protected' do
diff --git a/spec/serializers/codequality_degradation_entity_spec.rb b/spec/serializers/codequality_degradation_entity_spec.rb
index f56420bfdbd..0390e232fd5 100644
--- a/spec/serializers/codequality_degradation_entity_spec.rb
+++ b/spec/serializers/codequality_degradation_entity_spec.rb
@@ -17,6 +17,7 @@ RSpec.describe CodequalityDegradationEntity do
expect(subject[:severity]).to eq("major")
expect(subject[:file_path]).to eq("file_a.rb")
expect(subject[:line]).to eq(10)
+ expect(subject[:web_url]).to eq("http://localhost/root/test-project/-/blob/f572d396fae9206628714fb2ce00f72e94f2258f/file_a.rb#L10")
end
end
@@ -28,6 +29,7 @@ RSpec.describe CodequalityDegradationEntity do
expect(subject[:severity]).to eq("minor")
expect(subject[:file_path]).to eq("file_b.rb")
expect(subject[:line]).to eq(10)
+ expect(subject[:web_url]).to eq("http://localhost/root/test-project/-/blob/f572d396fae9206628714fb2ce00f72e94f2258f/file_b.rb#L10")
end
end
@@ -43,6 +45,7 @@ RSpec.describe CodequalityDegradationEntity do
expect(subject[:severity]).to eq("minor")
expect(subject[:file_path]).to eq("file_b.rb")
expect(subject[:line]).to eq(10)
+ expect(subject[:web_url]).to eq("http://localhost/root/test-project/-/blob/f572d396fae9206628714fb2ce00f72e94f2258f/file_b.rb#L10")
end
end
end
diff --git a/spec/serializers/diff_file_entity_spec.rb b/spec/serializers/diff_file_entity_spec.rb
index 48099cb1fdf..fbb45162136 100644
--- a/spec/serializers/diff_file_entity_spec.rb
+++ b/spec/serializers/diff_file_entity_spec.rb
@@ -80,47 +80,13 @@ RSpec.describe DiffFileEntity do
end
end
- describe '#is_fully_expanded' do
- context 'file with a conflict' do
- let(:options) { { conflicts: { diff_file.new_path => double(diff_lines_for_serializer: [], conflict_type: :both_modified) } } }
-
- it 'returns false' do
- expect(diff_file).not_to receive(:fully_expanded?)
- expect(subject[:is_fully_expanded]).to eq(false)
- end
- end
- end
-
describe '#highlighted_diff_lines' do
- context 'file without a conflict' do
- let(:options) { { conflicts: {} } }
+ let(:options) { { conflicts: {} } }
- it 'calls diff_lines_for_serializer on diff_file' do
- # #diff_lines_for_serializer gets called in #fully_expanded? as well so we expect twice
- expect(diff_file).to receive(:diff_lines_for_serializer).twice.and_return([])
- expect(subject[:highlighted_diff_lines]).to eq([])
- end
- end
-
- context 'file with a conflict' do
- let(:conflict_file) { instance_double(Gitlab::Conflict::File, conflict_type: :both_modified) }
- let(:options) { { conflicts: { diff_file.new_path => conflict_file } } }
-
- it 'calls diff_lines_for_serializer on matching conflict file' do
- expect(conflict_file).to receive(:diff_lines_for_serializer).and_return([])
- expect(subject[:highlighted_diff_lines]).to eq([])
- end
-
- context 'when Gitlab::Git::Conflict::Parser::UnmergeableFile gets raised' do
- before do
- allow(conflict_file).to receive(:diff_lines_for_serializer).and_raise(Gitlab::Git::Conflict::Parser::UnmergeableFile)
- end
-
- it 'falls back to diff_file diff_lines_for_serializer' do
- expect(diff_file).to receive(:diff_lines_for_serializer).and_return([])
- expect(subject[:highlighted_diff_lines]).to eq([])
- end
- end
+ it 'calls diff_lines_for_serializer on diff_file' do
+ # #diff_lines_for_serializer gets called in #fully_expanded? as well so we expect twice
+ expect(diff_file).to receive(:diff_lines_for_serializer).twice.and_return([])
+ expect(subject[:highlighted_diff_lines]).to eq([])
end
end
diff --git a/spec/serializers/diffs_entity_spec.rb b/spec/serializers/diffs_entity_spec.rb
index 72777bde30c..ba40d538ccb 100644
--- a/spec/serializers/diffs_entity_spec.rb
+++ b/spec/serializers/diffs_entity_spec.rb
@@ -9,13 +9,13 @@ RSpec.describe DiffsEntity do
let(:request) { EntityRequest.new(project: project, current_user: user) }
let(:merge_request_diffs) { merge_request.merge_request_diffs }
- let(:allow_tree_conflicts) { false }
+ let(:merge_conflicts_in_diff) { false }
let(:options) do
{
request: request,
merge_request: merge_request,
merge_request_diffs: merge_request_diffs,
- allow_tree_conflicts: allow_tree_conflicts
+ merge_conflicts_in_diff: merge_conflicts_in_diff
}
end
@@ -87,60 +87,39 @@ RSpec.describe DiffsEntity do
end
end
- context 'when there are conflicts' do
+ describe 'diff_files' do
let(:diff_files) { merge_request_diffs.first.diffs.diff_files }
- let(:diff_file_with_conflict) { diff_files.to_a.last }
- let(:diff_file_without_conflict) { diff_files.to_a[-2] }
- let(:resolvable_conflicts) { true }
- let(:conflict_file) { double(path: diff_file_with_conflict.new_path, conflict_type: :both_modified) }
- let(:conflicts) { double(conflicts: double(files: [conflict_file]), can_be_resolved_in_ui?: resolvable_conflicts) }
+ it 'serializes diff files using DiffFileEntity' do
+ expect(DiffFileEntity)
+ .to receive(:represent)
+ .with(
+ diff_files,
+ hash_including(options.merge(conflicts: nil))
+ )
- let(:merge_ref_head_diff) { true }
- let(:options) { super().merge(merge_ref_head_diff: merge_ref_head_diff) }
-
- before do
- allow(merge_request).to receive(:cannot_be_merged?).and_return(true)
- allow(MergeRequests::Conflicts::ListService).to receive(:new).and_return(conflicts)
- end
-
- it 'conflicts are highlighted' do
- expect(conflict_file).to receive(:diff_lines_for_serializer)
- expect(diff_file_with_conflict).not_to receive(:diff_lines_for_serializer)
- expect(diff_file_without_conflict).to receive(:diff_lines_for_serializer).twice # for highlighted_diff_lines and is_fully_expanded
-
- subject
- end
-
- context 'merge ref head diff is not chosen to be displayed' do
- let(:merge_ref_head_diff) { false }
-
- it 'conflicts are not calculated' do
- expect(MergeRequests::Conflicts::ListService).not_to receive(:new)
- end
+ subject[:diff_files]
end
- context 'when conflicts cannot be resolved' do
- let(:resolvable_conflicts) { false }
+ context 'when merge_conflicts_in_diff is true' do
+ let(:conflict_file) { double(path: diff_files.first.new_path, conflict_type: :both_modified) }
+ let(:conflicts) { double(conflicts: double(files: [conflict_file]), can_be_resolved_in_ui?: false) }
+ let(:merge_conflicts_in_diff) { true }
- it 'conflicts are not highlighted' do
- expect(conflict_file).not_to receive(:diff_lines_for_serializer)
- expect(diff_file_with_conflict).to receive(:diff_lines_for_serializer).twice # for highlighted_diff_lines and is_fully_expanded
- expect(diff_file_without_conflict).to receive(:diff_lines_for_serializer).twice # for highlighted_diff_lines and is_fully_expanded
-
- subject
+ before do
+ allow(merge_request).to receive(:cannot_be_merged?).and_return(true)
+ allow(MergeRequests::Conflicts::ListService).to receive(:new).and_return(conflicts)
end
- context 'when allow_tree_conflicts is set to true' do
- let(:allow_tree_conflicts) { true }
-
- it 'conflicts are still highlighted' do
- expect(conflict_file).to receive(:diff_lines_for_serializer)
- expect(diff_file_with_conflict).not_to receive(:diff_lines_for_serializer)
- expect(diff_file_without_conflict).to receive(:diff_lines_for_serializer).twice # for highlighted_diff_lines and is_fully_expanded
+ it 'serializes diff files with conflicts' do
+ expect(DiffFileEntity)
+ .to receive(:represent)
+ .with(
+ diff_files,
+ hash_including(options.merge(conflicts: { conflict_file.path => conflict_file }))
+ )
- subject
- end
+ subject[:diff_files]
end
end
end
diff --git a/spec/serializers/diffs_metadata_entity_spec.rb b/spec/serializers/diffs_metadata_entity_spec.rb
index 0e3d808aaac..04db576ffb5 100644
--- a/spec/serializers/diffs_metadata_entity_spec.rb
+++ b/spec/serializers/diffs_metadata_entity_spec.rb
@@ -9,6 +9,7 @@ RSpec.describe DiffsMetadataEntity do
let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) }
let(:merge_request_diffs) { merge_request.merge_request_diffs }
let(:merge_request_diff) { merge_request_diffs.last }
+ let(:merge_conflicts_in_diff) { false }
let(:options) { {} }
let(:entity) do
@@ -17,7 +18,8 @@ RSpec.describe DiffsMetadataEntity do
options.merge(
request: request,
merge_request: merge_request,
- merge_request_diffs: merge_request_diffs
+ merge_request_diffs: merge_request_diffs,
+ merge_conflicts_in_diff: merge_conflicts_in_diff
)
)
end
@@ -54,49 +56,36 @@ RSpec.describe DiffsMetadataEntity do
end
end
- it 'returns diff files metadata' do
- payload = DiffFileMetadataEntity.represent(raw_diff_files).as_json
+ it 'serializes diff files metadata using DiffFileMetadataEntity' do
+ expect(DiffFileMetadataEntity)
+ .to receive(:represent)
+ .with(
+ raw_diff_files,
+ hash_including(options.merge(conflicts: nil))
+ )
- expect(subject[:diff_files]).to eq(payload)
+ subject[:diff_files]
end
- context 'when merge_ref_head_diff and allow_tree_conflicts options are set' do
+ context 'when merge_conflicts_in_diff is true' do
let(:conflict_file) { double(path: raw_diff_files.first.new_path, conflict_type: :both_modified) }
let(:conflicts) { double(conflicts: double(files: [conflict_file]), can_be_resolved_in_ui?: false) }
+ let(:merge_conflicts_in_diff) { true }
before do
allow(merge_request).to receive(:cannot_be_merged?).and_return(true)
allow(MergeRequests::Conflicts::ListService).to receive(:new).and_return(conflicts)
end
- context 'when merge_ref_head_diff is true and allow_tree_conflicts is false' do
- let(:options) { { merge_ref_head_diff: true, allow_tree_conflicts: false } }
+ it 'serializes diff files with conflicts' do
+ expect(DiffFileMetadataEntity)
+ .to receive(:represent)
+ .with(
+ raw_diff_files,
+ hash_including(options.merge(conflicts: { conflict_file.path => conflict_file }))
+ )
- it 'returns diff files metadata without conflicts' do
- payload = DiffFileMetadataEntity.represent(raw_diff_files).as_json
-
- expect(subject[:diff_files]).to eq(payload)
- end
- end
-
- context 'when merge_ref_head_diff is false and allow_tree_conflicts is true' do
- let(:options) { { merge_ref_head_diff: false, allow_tree_conflicts: true } }
-
- it 'returns diff files metadata without conflicts' do
- payload = DiffFileMetadataEntity.represent(raw_diff_files).as_json
-
- expect(subject[:diff_files]).to eq(payload)
- end
- end
-
- context 'when merge_ref_head_diff and allow_tree_conflicts are true' do
- let(:options) { { merge_ref_head_diff: true, allow_tree_conflicts: true } }
-
- it 'returns diff files metadata with conflicts' do
- payload = DiffFileMetadataEntity.represent(raw_diff_files, conflicts: { conflict_file.path => conflict_file }).as_json
-
- expect(subject[:diff_files]).to eq(payload)
- end
+ subject[:diff_files]
end
end
end
diff --git a/spec/serializers/integrations/event_entity_spec.rb b/spec/serializers/integrations/event_entity_spec.rb
index 07281248f5b..1b72b5d290c 100644
--- a/spec/serializers/integrations/event_entity_spec.rb
+++ b/spec/serializers/integrations/event_entity_spec.rb
@@ -35,6 +35,7 @@ RSpec.describe Integrations::EventEntity do
expect(subject[:value]).to eq(false)
expect(subject[:field][:name]).to eq('note_channel')
expect(subject[:field][:value]).to eq('note-channel')
+ expect(subject[:field][:placeholder]).to eq('#general, #development')
end
end
end
diff --git a/spec/serializers/integrations/field_entity_spec.rb b/spec/serializers/integrations/field_entity_spec.rb
index 7af17cf6df6..4212a1ee6a2 100644
--- a/spec/serializers/integrations/field_entity_spec.rb
+++ b/spec/serializers/integrations/field_entity_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe Integrations::FieldEntity do
describe '#as_json' do
context 'with Jira integration' do
- let(:integration) { create(:jira_integration) }
+ let(:integration) { build(:jira_integration) }
context 'with field with type text' do
let(:field) { integration_field('username') }
@@ -59,7 +59,7 @@ RSpec.describe Integrations::FieldEntity do
end
context 'with EmailsOnPush integration' do
- let(:integration) { create(:emails_on_push_integration, send_from_committer_email: '1') }
+ let(:integration) { build(:emails_on_push_integration, send_from_committer_email: '1') }
context 'with field with type checkbox' do
let(:field) { integration_field('send_from_committer_email') }
@@ -111,6 +111,36 @@ RSpec.describe Integrations::FieldEntity do
end
end
end
+
+ context 'with chat integration' do
+ let(:integration) { build(:mattermost_integration) }
+ let(:field) { integration_field('webhook') }
+
+ it 'exposes correct attributes but masks webhook' do
+ expected_hash = {
+ section: nil,
+ type: 'text',
+ name: 'webhook',
+ title: nil,
+ placeholder: nil,
+ help: 'http://mattermost.example.com/hooks/',
+ required: true,
+ choices: nil,
+ value: '************',
+ checkbox_label: nil
+ }
+
+ is_expected.to eq(expected_hash)
+ end
+
+ context 'when webhook was not set' do
+ let(:integration) { build(:mattermost_integration, webhook: nil) }
+
+ it 'does not show the masked webhook' do
+ expect(subject[:value]).to be_nil
+ end
+ end
+ end
end
def integration_field(name)
diff --git a/spec/serializers/issue_board_entity_spec.rb b/spec/serializers/issue_board_entity_spec.rb
index 7a6a496912f..0c9c8f05e17 100644
--- a/spec/serializers/issue_board_entity_spec.rb
+++ b/spec/serializers/issue_board_entity_spec.rb
@@ -57,8 +57,18 @@ RSpec.describe IssueBoardEntity do
context 'when issue is of type task' do
let(:resource) { create(:issue, :task, project: project) }
- it 'has a work item path' do
- expect(subject[:real_path]).to eq(project_work_items_path(project, resource.id))
+ 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
end
end
diff --git a/spec/serializers/issue_entity_spec.rb b/spec/serializers/issue_entity_spec.rb
index 25e9e8c17e2..6161d4d7ec2 100644
--- a/spec/serializers/issue_entity_spec.rb
+++ b/spec/serializers/issue_entity_spec.rb
@@ -17,9 +17,19 @@ RSpec.describe IssueEntity do
context 'when issue is of type task' do
let(:resource) { create(:issue, :task, project: project) }
- # 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))
+ 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
+
+ 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
end
end
diff --git a/spec/serializers/linked_project_issue_entity_spec.rb b/spec/serializers/linked_project_issue_entity_spec.rb
index c4646754f16..523b89921b6 100644
--- a/spec/serializers/linked_project_issue_entity_spec.rb
+++ b/spec/serializers/linked_project_issue_entity_spec.rb
@@ -51,8 +51,20 @@ RSpec.describe LinkedProjectIssueEntity do
related_issue.update!(issue_type: :task, work_item_type: WorkItems::Type.default_by_type(:task))
end
- it 'returns a work items path' do
- expect(serialized_entity).to include(path: project_work_items_path(related_issue.project, related_issue.id))
+ 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)
+ )
end
end
end
diff --git a/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb b/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb
index e9c1fe23855..702c6d9fe98 100644
--- a/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb
+++ b/spec/serializers/merge_request_poll_cached_widget_entity_spec.rb
@@ -184,22 +184,6 @@ RSpec.describe MergeRequestPollCachedWidgetEntity do
end
end
- describe 'auto merge' do
- context 'when auto merge is enabled' do
- let(:resource) { create(:merge_request, :merge_when_pipeline_succeeds) }
-
- it 'returns auto merge related information' do
- expect(subject[:auto_merge_enabled]).to be_truthy
- end
- end
-
- context 'when auto merge is not enabled' do
- it 'returns auto merge related information' do
- expect(subject[:auto_merge_enabled]).to be_falsy
- end
- end
- end
-
describe 'squash defaults for projects' do
where(:squash_option, :value, :default, :readonly) do
'always' | true | true | true
diff --git a/spec/serializers/merge_request_poll_widget_entity_spec.rb b/spec/serializers/merge_request_poll_widget_entity_spec.rb
index 59ffba0e7a9..418f629a301 100644
--- a/spec/serializers/merge_request_poll_widget_entity_spec.rb
+++ b/spec/serializers/merge_request_poll_widget_entity_spec.rb
@@ -184,10 +184,4 @@ RSpec.describe MergeRequestPollWidgetEntity do
end
end
end
-
- describe '#mergeable_discussions_state?' do
- it 'returns mergeable discussions state' do
- expect(subject[:mergeable_discussions_state]).to eq(true)
- end
- end
end
diff --git a/spec/serializers/merge_requests/pipeline_entity_spec.rb b/spec/serializers/merge_requests/pipeline_entity_spec.rb
index ee99ab2e7dd..a8f4fc44f10 100644
--- a/spec/serializers/merge_requests/pipeline_entity_spec.rb
+++ b/spec/serializers/merge_requests/pipeline_entity_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe MergeRequests::PipelineEntity do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
- let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project, name: 'Build pipeline') }
let(:request) { double('request') }
@@ -25,15 +25,20 @@ RSpec.describe MergeRequests::PipelineEntity do
describe '#as_json' do
it 'contains required fields' do
+ allow(pipeline).to receive(:merge_request_event_type).and_return(:merged_result)
+
is_expected.to include(
:id, :path, :active, :coverage, :ref, :commit, :details,
- :flags, :triggered, :triggered_by
+ :flags, :triggered, :triggered_by, :name
)
expect(subject[:commit]).to include(:short_id, :commit_path)
expect(subject[:ref]).to include(:branch)
- expect(subject[:details]).to include(:artifacts, :name, :status, :stages, :finished_at)
+ expect(subject[:details]).to include(:artifacts, :name, :event_type_name, :status, :stages, :finished_at)
expect(subject[:details][:status]).to include(:icon, :favicon, :text, :label, :tooltip)
expect(subject[:flags]).to include(:merge_request_pipeline)
+
+ expect(subject[:details][:event_type_name]).to eq('Merged result pipeline')
+ expect(subject[:details][:name]).to eq('Merged result pipeline')
end
it 'returns presented coverage' do
@@ -46,5 +51,15 @@ RSpec.describe MergeRequests::PipelineEntity do
expect(entity.as_json).not_to include(:coverage)
end
+
+ context 'when pipeline_name feature flag is disabled' do
+ before do
+ stub_feature_flags(pipeline_name: false)
+ end
+
+ it 'does not return name' do
+ is_expected.not_to include(:name)
+ end
+ end
end
end
diff --git a/spec/serializers/paginated_diff_entity_spec.rb b/spec/serializers/paginated_diff_entity_spec.rb
index 9d4456c11d6..3d77beb9abc 100644
--- a/spec/serializers/paginated_diff_entity_spec.rb
+++ b/spec/serializers/paginated_diff_entity_spec.rb
@@ -7,13 +7,13 @@ RSpec.describe PaginatedDiffEntity do
let(:request) { double('request', current_user: user) }
let(:merge_request) { create(:merge_request) }
let(:diff_batch) { merge_request.merge_request_diff.diffs_in_batch(2, 3, diff_options: nil) }
- let(:allow_tree_conflicts) { false }
+ let(:merge_conflicts_in_diff) { false }
let(:options) do
{
request: request,
merge_request: merge_request,
pagination_data: diff_batch.pagination_data,
- allow_tree_conflicts: allow_tree_conflicts
+ merge_conflicts_in_diff: merge_conflicts_in_diff
}
end
@@ -29,61 +29,39 @@ RSpec.describe PaginatedDiffEntity do
expect(subject[:pagination]).to eq(total_pages: 20)
end
- context 'when there are conflicts' do
- let(:diff_batch) { merge_request.merge_request_diff.diffs_in_batch(7, 3, diff_options: nil) }
- let(:diff_files) { diff_batch.diff_files.to_a }
- let(:diff_file_with_conflict) { diff_files.last }
- let(:diff_file_without_conflict) { diff_files.first }
+ describe 'diff_files' do
+ let(:diff_files) { diff_batch.diff_files(sorted: true) }
- let(:resolvable_conflicts) { true }
- let(:conflict_file) { double(path: diff_file_with_conflict.new_path, conflict_type: :both_modified) }
- let(:conflicts) { double(conflicts: double(files: [conflict_file]), can_be_resolved_in_ui?: resolvable_conflicts) }
+ it 'serializes diff files using DiffFileEntity' do
+ expect(DiffFileEntity)
+ .to receive(:represent)
+ .with(
+ diff_files,
+ hash_including(options.merge(conflicts: nil))
+ )
- let(:merge_ref_head_diff) { true }
- let(:options) { super().merge(merge_ref_head_diff: merge_ref_head_diff) }
-
- before do
- allow(merge_request).to receive(:cannot_be_merged?).and_return(true)
- allow(MergeRequests::Conflicts::ListService).to receive(:new).and_return(conflicts)
- end
-
- it 'conflicts are highlighted' do
- expect(conflict_file).to receive(:diff_lines_for_serializer)
- expect(diff_file_with_conflict).not_to receive(:diff_lines_for_serializer)
- expect(diff_file_without_conflict).to receive(:diff_lines_for_serializer).twice # for highlighted_diff_lines and is_fully_expanded
-
- subject
- end
-
- context 'merge ref head diff is not chosen to be displayed' do
- let(:merge_ref_head_diff) { false }
-
- it 'conflicts are not calculated' do
- expect(MergeRequests::Conflicts::ListService).not_to receive(:new)
- end
+ subject[:diff_files]
end
- context 'when conflicts cannot be resolved' do
- let(:resolvable_conflicts) { false }
+ context 'when merge_conflicts_in_diff is true' do
+ let(:conflict_file) { double(path: diff_files.first.new_path, conflict_type: :both_modified) }
+ let(:conflicts) { double(conflicts: double(files: [conflict_file]), can_be_resolved_in_ui?: false) }
+ let(:merge_conflicts_in_diff) { true }
- it 'conflicts are not highlighted' do
- expect(conflict_file).not_to receive(:diff_lines_for_serializer)
- expect(diff_file_with_conflict).to receive(:diff_lines_for_serializer).twice # for highlighted_diff_lines and is_fully_expanded
- expect(diff_file_without_conflict).to receive(:diff_lines_for_serializer).twice # for highlighted_diff_lines and is_fully_expanded
-
- subject
+ before do
+ allow(merge_request).to receive(:cannot_be_merged?).and_return(true)
+ allow(MergeRequests::Conflicts::ListService).to receive(:new).and_return(conflicts)
end
- context 'when allow_tree_conflicts is set to true' do
- let(:allow_tree_conflicts) { true }
-
- it 'conflicts are still highlighted' do
- expect(conflict_file).to receive(:diff_lines_for_serializer)
- expect(diff_file_with_conflict).not_to receive(:diff_lines_for_serializer)
- expect(diff_file_without_conflict).to receive(:diff_lines_for_serializer).twice # for highlighted_diff_lines and is_fully_expanded
+ it 'serializes diff files with conflicts' do
+ expect(DiffFileEntity)
+ .to receive(:represent)
+ .with(
+ diff_files,
+ hash_including(options.merge(conflicts: { conflict_file.path => conflict_file }))
+ )
- subject
- end
+ subject[:diff_files]
end
end
end
diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb
index 4d9bdc4bb17..9caaeb3450b 100644
--- a/spec/serializers/pipeline_serializer_spec.rb
+++ b/spec/serializers/pipeline_serializer_spec.rb
@@ -163,10 +163,8 @@ RSpec.describe PipelineSerializer do
context 'with different refs' do
before do
- # rubocop:disable Rails/SkipsModelValidations
Ci::Pipeline.update_all(%(ref = 'feature-' || id))
Ci::Build.update_all(%(ref = 'feature-' || stage_id))
- # rubocop:enable Rails/SkipsModelValidations
end
it 'verifies number of queries', :request_store do
@@ -240,6 +238,7 @@ RSpec.describe PipelineSerializer do
create(:ci_empty_pipeline,
project: project,
status: status,
+ name: 'Build pipeline',
ref: 'feature').tap do |pipeline|
Ci::Build::AVAILABLE_STATUSES.each do |build_status|
create_build(pipeline, status, build_status)
diff --git a/spec/serializers/remote_mirror_entity_spec.rb b/spec/serializers/remote_mirror_entity_spec.rb
index 4cbf87e4d67..c6290e15995 100644
--- a/spec/serializers/remote_mirror_entity_spec.rb
+++ b/spec/serializers/remote_mirror_entity_spec.rb
@@ -3,8 +3,7 @@
require 'spec_helper'
RSpec.describe RemoteMirrorEntity do
- let(:project) { create(:project, :repository, :remote_mirror, url: "https://test:password@gitlab.com") }
- let(:remote_mirror) { project.remote_mirrors.first }
+ let(:remote_mirror) { build_stubbed(:remote_mirror, url: "https://test:password@gitlab.com") }
let(:entity) { described_class.new(remote_mirror) }
subject { entity.as_json }
diff --git a/spec/services/admin/set_feature_flag_service_spec.rb b/spec/services/admin/set_feature_flag_service_spec.rb
index 6fa806644c9..9a9c5545e23 100644
--- a/spec/services/admin/set_feature_flag_service_spec.rb
+++ b/spec/services/admin/set_feature_flag_service_spec.rb
@@ -130,6 +130,15 @@ RSpec.describe Admin::SetFeatureFlagService do
end
end
+ context 'when enabling for a repository' do
+ let(:params) { { value: 'true', repository: project.repository.full_path } }
+
+ it 'enables the feature flag' do
+ expect(Feature).to receive(:enable).with(feature_name, project.repository)
+ expect(subject).to be_success
+ end
+ end
+
context 'when enabling for a user actor and a feature group' do
let(:params) { { value: 'true', user: user.username, feature_group: 'perf_team' } }
let(:feature_group) { Feature.group('perf_team') }
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 73d185283b6..676f55be28a 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
@@ -225,7 +225,7 @@ RSpec.describe AutoMerge::MergeWhenPipelineSucceedsService do
let!(:build) do
create(:ci_build, :created, pipeline: pipeline, ref: ref,
- name: 'build', ci_stage: build_stage )
+ name: 'build', ci_stage: build_stage)
end
let!(:test) do
diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb
index 72027911e51..1959710bb0c 100644
--- a/spec/services/boards/issues/list_service_spec.rb
+++ b/spec/services/boards/issues/list_service_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe Boards::Issues::ListService do
let_it_be(:opened_issue1) { create(:labeled_issue, project: project, milestone: m1, title: 'Issue 1', labels: [bug]) }
let_it_be(:opened_issue2) { create(:labeled_issue, project: project, milestone: m2, title: 'Issue 2', labels: [p2]) }
- let_it_be(:reopened_issue1) { create(:issue, :opened, project: project, title: 'Reopened Issue 1' ) }
+ let_it_be(:reopened_issue1) { create(:issue, :opened, project: project, title: 'Reopened Issue 1') }
let_it_be(:list1_issue1) { create(:labeled_issue, project: project, milestone: m1, labels: [p2, development]) }
let_it_be(:list1_issue2) { create(:labeled_issue, project: project, milestone: m2, labels: [development]) }
@@ -110,7 +110,7 @@ RSpec.describe Boards::Issues::ListService do
let!(:opened_issue1) { create(:labeled_issue, project: project, milestone: m1, title: 'Issue 1', labels: [bug]) }
let!(:opened_issue2) { create(:labeled_issue, project: project, milestone: m2, title: 'Issue 2', labels: [p2, p2_project]) }
let!(:opened_issue3) { create(:labeled_issue, project: project_archived, milestone: m1, title: 'Issue 3', labels: [bug]) }
- let!(:reopened_issue1) { create(:issue, state: 'opened', project: project, title: 'Reopened Issue 1', closed_at: Time.current ) }
+ let!(:reopened_issue1) { create(:issue, state: 'opened', project: project, title: 'Reopened Issue 1', closed_at: Time.current) }
let!(:list1_issue1) { create(:labeled_issue, project: project, milestone: m1, labels: [p2, p2_project, development]) }
let!(:list1_issue2) { create(:labeled_issue, project: project, milestone: m2, labels: [development]) }
diff --git a/spec/services/branches/create_service_spec.rb b/spec/services/branches/create_service_spec.rb
index 26cc1a0665e..19a32aafa38 100644
--- a/spec/services/branches/create_service_spec.rb
+++ b/spec/services/branches/create_service_spec.rb
@@ -56,17 +56,6 @@ RSpec.describe Branches::CreateService, :use_clean_rails_redis_caching do
end
end
- context 'when an ambiguous branch name is provided' do
- let(:branches) { { 'ambiguous/test' => 'master', 'ambiguous' => 'master' } }
-
- it 'returns an error that branch could not be created' do
- err_msg = 'Failed to create branch \'ambiguous\': 13:reference is ambiguous.'
-
- expect(subject[:status]).to eq(:error)
- expect(subject[:message]).to match_array([err_msg])
- end
- end
-
context 'when PreReceiveError exception' do
let(:branches) { { 'error' => 'master' } }
@@ -184,18 +173,6 @@ RSpec.describe Branches::CreateService, :use_clean_rails_redis_caching do
end
end
- context 'when an ambiguous branch name is provided' do
- it 'returns an error that branch could not be created' do
- err_msg = 'Failed to create branch \'feature\': 13:reference is ambiguous.'
-
- service.execute('feature/widget', 'master')
- result = service.execute('feature', 'master')
-
- expect(result[:status]).to eq(:error)
- expect(result[:message]).to eq(err_msg)
- end
- end
-
it 'logs and returns an error if there is a PreReceiveError exception' do
error_message = 'pre receive error'
raw_message = "GitLab: #{error_message}"
diff --git a/spec/services/bulk_imports/create_pipeline_trackers_service_spec.rb b/spec/services/bulk_imports/create_pipeline_trackers_service_spec.rb
index 0de962328c5..5a7852fc32f 100644
--- a/spec/services/bulk_imports/create_pipeline_trackers_service_spec.rb
+++ b/spec/services/bulk_imports/create_pipeline_trackers_service_spec.rb
@@ -77,6 +77,8 @@ RSpec.describe BulkImports::CreatePipelineTrackersService do
message: 'Pipeline skipped as source instance version not compatible with pipeline',
bulk_import_entity_id: entity.id,
bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
importer: 'gitlab_migration',
pipeline_name: 'PipelineClass4',
minimum_source_version: '15.1.0',
@@ -88,6 +90,8 @@ RSpec.describe BulkImports::CreatePipelineTrackersService do
message: 'Pipeline skipped as source instance version not compatible with pipeline',
bulk_import_entity_id: entity.id,
bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
importer: 'gitlab_migration',
pipeline_name: 'PipelineClass5',
minimum_source_version: '16.0.0',
diff --git a/spec/services/ci/after_requeue_job_service_spec.rb b/spec/services/ci/after_requeue_job_service_spec.rb
index 1f692bdb71a..e6f46fb9ebe 100644
--- a/spec/services/ci/after_requeue_job_service_spec.rb
+++ b/spec/services/ci/after_requeue_job_service_spec.rb
@@ -120,26 +120,6 @@ RSpec.describe Ci::AfterRequeueJobService, :sidekiq_inline do
)
end
- context 'when the FF ci_requeue_with_dag_object_hierarchy is disabled' do
- before do
- stub_feature_flags(ci_requeue_with_dag_object_hierarchy: false)
- end
-
- it 'marks subsequent skipped jobs as processable but leaves a3 created' do
- execute_after_requeue_service(a1)
-
- check_jobs_statuses(
- a1: 'pending',
- a2: 'created',
- a3: 'skipped',
- b1: 'success',
- b2: 'created',
- c1: 'created',
- c2: 'created'
- )
- end
- end
-
context 'when executed by a different user than the original owner' do
let(:retryer) { create(:user).tap { |u| project.add_maintainer(u) } }
let(:service) { described_class.new(project, retryer) }
@@ -312,22 +292,6 @@ RSpec.describe Ci::AfterRequeueJobService, :sidekiq_inline do
c: 'created'
)
end
-
- context 'when the FF ci_requeue_with_dag_object_hierarchy is disabled' do
- before do
- stub_feature_flags(ci_requeue_with_dag_object_hierarchy: false)
- end
-
- it 'marks the next subsequent skipped job as processable but leaves c skipped' do
- execute_after_requeue_service(a)
-
- check_jobs_statuses(
- a: 'pending',
- b: 'created',
- c: 'skipped'
- )
- end
- end
end
private
diff --git a/spec/services/ci/compare_test_reports_service_spec.rb b/spec/services/ci/compare_test_reports_service_spec.rb
index 6d3df0f5383..f259072fe87 100644
--- a/spec/services/ci/compare_test_reports_service_spec.rb
+++ b/spec/services/ci/compare_test_reports_service_spec.rb
@@ -41,7 +41,7 @@ RSpec.describe Ci::CompareTestReportsService do
it 'returns a parsed TestReports success status and failure on the individual suite' do
expect(comparison[:status]).to eq(:parsed)
expect(comparison.dig(:data, 'status')).to eq('success')
- expect(comparison.dig(:data, 'suites', 0, 'status') ).to eq('error')
+ expect(comparison.dig(:data, 'suites', 0, 'status')).to eq('error')
end
end
diff --git a/spec/services/ci/create_pipeline_service/partitioning_spec.rb b/spec/services/ci/create_pipeline_service/partitioning_spec.rb
index 43fbb74ede4..f34d103d965 100644
--- a/spec/services/ci/create_pipeline_service/partitioning_spec.rb
+++ b/spec/services/ci/create_pipeline_service/partitioning_spec.rb
@@ -2,7 +2,8 @@
require 'spec_helper'
-RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, :aggregate_failures do
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, :aggregate_failures,
+:ci_partitionable do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
@@ -31,7 +32,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
end
let(:pipeline) { service.execute(:push).payload }
- let(:current_partition_id) { 123 }
+ let(:current_partition_id) { ci_testing_partition_id }
before do
stub_ci_pipeline_yaml_file(config)
diff --git a/spec/services/ci/create_pipeline_service/rules_spec.rb b/spec/services/ci/create_pipeline_service/rules_spec.rb
index c737b8cc329..5fdefb2b306 100644
--- a/spec/services/ci/create_pipeline_service/rules_spec.rb
+++ b/spec/services/ci/create_pipeline_service/rules_spec.rb
@@ -1425,5 +1425,43 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
it_behaves_like 'comparing file changes with workflow rules'
end
end
+
+ context 'workflow name with rules' do
+ let(:ref) { 'refs/heads/feature' }
+
+ let(:variables) do
+ [{ key: 'SOME_VARIABLE', secret_value: 'SOME_VAL' }]
+ end
+
+ let(:pipeline) do
+ execute_service do |pipeline|
+ pipeline.variables.build(variables)
+ end.payload
+ end
+
+ let(:config) do
+ <<-EOY
+ workflow:
+ name: '$PIPELINE_NAME $SOME_VARIABLE'
+ rules:
+ - if: $CI_COMMIT_REF_NAME =~ /master/
+ variables:
+ PIPELINE_NAME: 'Name 1'
+ - if: $CI_COMMIT_REF_NAME =~ /feature/
+ variables:
+ PIPELINE_NAME: 'Name 2'
+
+ job:
+ stage: test
+ script: echo 'hello'
+ EOY
+ end
+
+ it 'substitutes variables in pipeline name' do
+ expect(response).not_to be_error
+ expect(pipeline).to be_persisted
+ expect(pipeline.name).to eq('Name 2 SOME_VAL')
+ end
+ end
end
end
diff --git a/spec/services/ci/create_pipeline_service/variables_spec.rb b/spec/services/ci/create_pipeline_service/variables_spec.rb
new file mode 100644
index 00000000000..e9e0cf2c6e0
--- /dev/null
+++ b/spec/services/ci/create_pipeline_service/variables_spec.rb
@@ -0,0 +1,136 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { project.first_owner }
+
+ let(:service) { described_class.new(project, user, { ref: 'master' }) }
+ let(:pipeline) { service.execute(:push).payload }
+
+ before do
+ stub_ci_pipeline_yaml_file(config)
+ end
+
+ context 'when using variables' do
+ context 'when variables have expand: true/false' do
+ let(:config) do
+ <<-YAML
+ variables:
+ VAR7:
+ value: "value 7 $CI_PIPELINE_ID"
+ expand: false
+ VAR8:
+ value: "value 8 $CI_PIPELINE_ID"
+ expand: false
+
+ rspec:
+ script: rspec
+ variables:
+ VAR1: "JOBID-$CI_JOB_ID"
+ VAR2: "PIPELINEID-$CI_PIPELINE_ID and $VAR1"
+ VAR3:
+ value: "PIPELINEID-$CI_PIPELINE_ID and $VAR1"
+ expand: false
+ VAR4:
+ value: "JOBID-$CI_JOB_ID"
+ expand: false
+ VAR5: "PIPELINEID-$CI_PIPELINE_ID and $VAR4"
+ VAR6:
+ value: "PIPELINEID-$CI_PIPELINE_ID and $VAR4"
+ expand: false
+ VAR7: "overridden value 7 $CI_PIPELINE_ID"
+ YAML
+ end
+
+ let(:rspec) { find_job('rspec') }
+
+ it 'creates the pipeline with a job that has variable expanded according to "expand"' do
+ expect(pipeline).to be_created_successfully
+
+ expect(Ci::BuildRunnerPresenter.new(rspec).runner_variables).to include(
+ { key: 'VAR1', value: "JOBID-#{rspec.id}", public: true, masked: false },
+ { key: 'VAR2', value: "PIPELINEID-#{pipeline.id} and JOBID-#{rspec.id}", public: true, masked: false },
+ { key: 'VAR3', value: "PIPELINEID-$CI_PIPELINE_ID and $VAR1", public: true, masked: false, raw: true },
+ { key: 'VAR4', value: "JOBID-$CI_JOB_ID", public: true, masked: false, raw: true },
+ { key: 'VAR5', value: "PIPELINEID-#{pipeline.id} and $VAR4", public: true, masked: false },
+ { key: 'VAR6', value: "PIPELINEID-$CI_PIPELINE_ID and $VAR4", public: true, masked: false, raw: true },
+ { key: 'VAR7', value: "overridden value 7 #{pipeline.id}", public: true, masked: false },
+ { key: 'VAR8', value: "value 8 $CI_PIPELINE_ID", public: true, masked: false, raw: true }
+ )
+ end
+
+ context 'when the FF ci_raw_variables_in_yaml_config is disabled' do
+ before do
+ stub_feature_flags(ci_raw_variables_in_yaml_config: false)
+ end
+
+ it 'creates the pipeline with a job that has all variables expanded' do
+ expect(pipeline).to be_created_successfully
+
+ expect(Ci::BuildRunnerPresenter.new(rspec).runner_variables).to include(
+ { key: 'VAR1', value: "JOBID-#{rspec.id}", public: true, masked: false },
+ { key: 'VAR2', value: "PIPELINEID-#{pipeline.id} and JOBID-#{rspec.id}", public: true, masked: false },
+ { key: 'VAR3', value: "PIPELINEID-#{pipeline.id} and JOBID-#{rspec.id}", public: true, masked: false },
+ { key: 'VAR4', value: "JOBID-#{rspec.id}", public: true, masked: false },
+ { key: 'VAR5', value: "PIPELINEID-#{pipeline.id} and JOBID-#{rspec.id}", public: true, masked: false },
+ { key: 'VAR6', value: "PIPELINEID-#{pipeline.id} and JOBID-#{rspec.id}", public: true, masked: false },
+ { key: 'VAR7', value: "overridden value 7 #{pipeline.id}", public: true, masked: false },
+ { key: 'VAR8', value: "value 8 #{pipeline.id}", public: true, masked: false }
+ )
+ end
+ end
+ end
+
+ context 'when trigger variables have expand: true/false' do
+ let(:config) do
+ <<-YAML
+ child:
+ variables:
+ VAR1: "PROJECTID-$CI_PROJECT_ID"
+ VAR2: "PIPELINEID-$CI_PIPELINE_ID and $VAR1"
+ VAR3:
+ value: "PIPELINEID-$CI_PIPELINE_ID and $VAR1"
+ expand: false
+ trigger:
+ include: child.yml
+ YAML
+ end
+
+ let(:child) { find_job('child') }
+
+ it 'creates the pipeline with a trigger job that has downstream_variables expanded according to "expand"' do
+ expect(pipeline).to be_created_successfully
+
+ expect(child.downstream_variables).to include(
+ { key: 'VAR1', value: "PROJECTID-#{project.id}" },
+ { key: 'VAR2', value: "PIPELINEID-#{pipeline.id} and PROJECTID-$CI_PROJECT_ID" },
+ { key: 'VAR3', value: "PIPELINEID-$CI_PIPELINE_ID and $VAR1", raw: true }
+ )
+ end
+
+ context 'when the FF ci_raw_variables_in_yaml_config is disabled' do
+ before do
+ stub_feature_flags(ci_raw_variables_in_yaml_config: false)
+ end
+
+ it 'creates the pipeline with a job that has all variables expanded' do
+ expect(pipeline).to be_created_successfully
+
+ expect(child.downstream_variables).to include(
+ { key: 'VAR1', value: "PROJECTID-#{project.id}" },
+ { key: 'VAR2', value: "PIPELINEID-#{pipeline.id} and PROJECTID-$CI_PROJECT_ID" },
+ { key: 'VAR3', value: "PIPELINEID-#{pipeline.id} and PROJECTID-$CI_PROJECT_ID" }
+ )
+ end
+ end
+ end
+ end
+
+ private
+
+ def find_job(name)
+ pipeline.processables.find { |job| job.name == name }
+ end
+end
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index 458692ba1c0..67c13649c6f 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -135,7 +135,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
execute_service
expect(histogram).to have_received(:observe)
- .with({ source: 'push' }, 5)
+ .with({ source: 'push', plan: project.actual_plan_name }, 5)
end
it 'tracks included template usage' do
@@ -1867,49 +1867,4 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes
end
end
end
-
- describe '#execute!' do
- subject { service.execute!(*args) }
-
- let(:service) { described_class.new(project, user, ref: ref_name) }
- let(:args) { [:push] }
-
- context 'when user has a permission to create a pipeline' do
- let(:user) { create(:user) }
-
- before do
- project.add_developer(user)
- end
-
- it 'does not raise an error' do
- expect { subject }.not_to raise_error
- end
-
- it 'creates a pipeline' do
- expect { subject }.to change { Ci::Pipeline.count }.by(1)
- end
- end
-
- context 'when user does not have a permission to create a pipeline' do
- let(:user) { create(:user) }
-
- it 'raises an error' do
- expect { subject }
- .to raise_error(described_class::CreateError)
- .with_message('Insufficient permissions to create a new pipeline')
- end
- end
-
- context 'when a user with permissions has been blocked' do
- before do
- user.block!
- end
-
- it 'raises an error' do
- expect { subject }
- .to raise_error(described_class::CreateError)
- .with_message('Insufficient permissions to create a new pipeline')
- 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 030ba84951e..5df590a1b78 100644
--- a/spec/services/ci/job_artifacts/create_service_spec.rb
+++ b/spec/services/ci/job_artifacts/create_service_spec.rb
@@ -181,8 +181,8 @@ RSpec.describe Ci::JobArtifacts::CreateService do
end
end
- context 'with job partitioning' do
- let(:pipeline) { create(:ci_pipeline, project: project, partition_id: 123) }
+ context 'with job partitioning', :ci_partitionable do
+ let(:pipeline) { create(:ci_pipeline, project: project, partition_id: ci_testing_partition_id) }
let(:job) { create(:ci_build, pipeline: pipeline) }
it 'sets partition_id on artifacts' do
@@ -190,7 +190,7 @@ RSpec.describe Ci::JobArtifacts::CreateService do
artifacts_partitions = job.job_artifacts.map(&:partition_id).uniq
- expect(artifacts_partitions).to eq([123])
+ expect(artifacts_partitions).to eq([ci_testing_partition_id])
end
end
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 54d1cacc068..79920dcb2c7 100644
--- a/spec/services/ci/job_artifacts/destroy_batch_service_spec.rb
+++ b/spec/services/ci/job_artifacts/destroy_batch_service_spec.rb
@@ -60,10 +60,9 @@ RSpec.describe Ci::JobArtifacts::DestroyBatchService do
execute
end
- it 'preserves trace artifacts and removes any timestamp' do
+ it 'preserves trace artifacts' do
expect { subject }
- .to change { trace_artifact.reload.expire_at }.from(trace_artifact.expire_at).to(nil)
- .and not_change { Ci::JobArtifact.exists?(trace_artifact.id) }
+ .to not_change { Ci::JobArtifact.exists?(trace_artifact.id) }
end
context 'when artifact belongs to a project that is undergoing stats refresh' do
@@ -277,81 +276,5 @@ RSpec.describe Ci::JobArtifacts::DestroyBatchService do
is_expected.to eq(destroyed_artifacts_count: 0, statistics_updates: {}, status: :success)
end
end
-
- context 'with artifacts that has backfilled expire_at' do
- let!(:created_on_00_30_45_minutes_on_21_22_23) do
- [
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-21 00:00:00.000')),
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-21 01:30:00.000')),
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-22 12:00:00.000')),
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-22 12:30:00.000')),
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-23 23:00:00.000')),
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-23 23:30:00.000')),
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-23 06:45:00.000'))
- ]
- end
-
- let!(:created_close_to_00_or_30_minutes) do
- [
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-21 00:00:00.001')),
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-21 00:30:00.999'))
- ]
- end
-
- let!(:created_on_00_or_30_minutes_on_other_dates) do
- [
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-01 00:00:00.000')),
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-19 12:00:00.000')),
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-24 23:30:00.000'))
- ]
- end
-
- let!(:created_at_other_times) do
- [
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-19 00:00:00.000')),
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-19 00:30:00.000')),
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-24 00:00:00.000')),
- create(:ci_job_artifact, expire_at: Time.zone.parse('2022-01-24 00:30:00.000'))
- ]
- end
-
- let(:artifacts_to_keep) { created_on_00_30_45_minutes_on_21_22_23 }
- let(:artifacts_to_delete) { created_close_to_00_or_30_minutes + created_on_00_or_30_minutes_on_other_dates + created_at_other_times }
- let(:all_artifacts) { artifacts_to_keep + artifacts_to_delete }
-
- let(:artifacts) { Ci::JobArtifact.where(id: all_artifacts.map(&:id)) }
-
- it 'deletes job artifacts that do not have expire_at on 00, 30 or 45 minute of 21, 22, 23 of the month' do
- expect { subject }.to change { Ci::JobArtifact.count }.by(artifacts_to_delete.size * -1)
- end
-
- it 'keeps job artifacts that have expire_at on 00, 30 or 45 minute of 21, 22, 23 of the month' do
- expect { subject }.not_to change { Ci::JobArtifact.where(id: artifacts_to_keep.map(&:id)).count }
- end
-
- it 'removes expire_at on job artifacts that have expire_at on 00, 30 or 45 minute of 21, 22, 23 of the month' do
- subject
-
- expect(artifacts_to_keep.all? { |artifact| artifact.reload.expire_at.nil? }).to be(true)
- end
-
- context 'when feature flag is disabled' do
- before do
- stub_feature_flags(ci_detect_wrongly_expired_artifacts: false)
- end
-
- it 'deletes all job artifacts' do
- expect { subject }.to change { Ci::JobArtifact.count }.by(all_artifacts.size * -1)
- end
- end
-
- context 'when fix_expire_at is false' do
- let(:service) { described_class.new(artifacts, pick_up_at: Time.current, fix_expire_at: false) }
-
- it 'deletes all job artifacts' do
- expect { subject }.to change { Ci::JobArtifact.count }.by(all_artifacts.size * -1)
- end
- end
- end
end
end
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 6d9fc4c8e34..d4d56825e1f 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
@@ -9,7 +9,9 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportService do
let_it_be(:user1) { create(:user) }
let_it_be(:user2) { create(:user) }
- let(:test_event_name) { 'i_testing_test_report_uploaded' }
+ let(:test_event_name_1) { 'i_testing_test_report_uploaded' }
+ let(:test_event_name_2) { 'i_testing_coverage_report_uploaded' }
+
let(:counter) { Gitlab::UsageDataCounters::HLLRedisCounter }
let(:start_time) { 1.week.ago }
let(:end_time) { 1.week.from_now }
@@ -25,15 +27,15 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportService do
end
end
- it 'tracks the event using HLLRedisCounter' do
- allow(Gitlab::UsageDataCounters::HLLRedisCounter)
+ it 'tracks the test event using HLLRedisCounter' do
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.to receive(:track_event)
- .with(test_event_name, values: user1.id)
+ .with(test_event_name_1, values: user1.id)
.and_call_original
expect { track_artifact_report }
.to change {
- counter.unique_events(event_names: test_event_name,
+ counter.unique_events(event_names: test_event_name_1,
start_date: start_time,
end_date: end_time)
}
@@ -44,12 +46,20 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportService do
context 'when pipeline does not have test reports' do
let_it_be(:pipeline) { create(:ci_empty_pipeline) }
- it 'does not track the event' do
+ it 'does not track the test event' do
track_artifact_report
expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.not_to receive(:track_event)
- .with(anything, test_event_name)
+ .with(anything, test_event_name_1)
+ end
+
+ it 'does not track the coverage test event' do
+ track_artifact_report
+
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter)
+ .not_to receive(:track_event)
+ .with(anything, test_event_name_2)
end
end
@@ -57,15 +67,15 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportService do
let_it_be(:pipeline1) { create(:ci_pipeline, :with_test_reports, project: project, user: user1) }
let_it_be(:pipeline2) { create(:ci_pipeline, :with_test_reports, project: project, user: user1) }
- it 'tracks all pipelines using HLLRedisCounter by one user_id' do
- allow(Gitlab::UsageDataCounters::HLLRedisCounter)
+ it 'tracks all pipelines using HLLRedisCounter by one user_id for the test event' do
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.to receive(:track_event)
- .with(test_event_name, values: user1.id)
+ .with(test_event_name_1, values: user1.id)
.and_call_original
- allow(Gitlab::UsageDataCounters::HLLRedisCounter)
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.to receive(:track_event)
- .with(test_event_name, values: user1.id)
+ .with(test_event_name_1, values: user1.id)
.and_call_original
expect do
@@ -73,7 +83,7 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportService do
described_class.new.execute(pipeline2)
end
.to change {
- counter.unique_events(event_names: test_event_name,
+ counter.unique_events(event_names: test_event_name_1,
start_date: start_time,
end_date: end_time)
}
@@ -85,25 +95,92 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportService do
let_it_be(:pipeline1) { create(:ci_pipeline, :with_test_reports, project: project, user: user1) }
let_it_be(:pipeline2) { create(:ci_pipeline, :with_test_reports, project: project, user: user2) }
- it 'tracks all pipelines using HLLRedisCounter by multiple users' do
- allow(Gitlab::UsageDataCounters::HLLRedisCounter)
+ it 'tracks all pipelines using HLLRedisCounter by multiple users for test reports' do
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter)
+ .to receive(:track_event)
+ .with(test_event_name_1, values: user1.id)
+ .and_call_original
+
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter)
+ .to receive(:track_event)
+ .with(test_event_name_1, values: user2.id)
+ .and_call_original
+
+ expect do
+ described_class.new.execute(pipeline1)
+ described_class.new.execute(pipeline2)
+ end
+ .to change {
+ counter.unique_events(event_names: test_event_name_1,
+ start_date: start_time,
+ end_date: end_time)
+ }
+ .by 2
+ end
+ end
+
+ context 'when pipeline has coverage test reports' do
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user1) }
+
+ before do
+ 2.times do
+ pipeline.builds << build(:ci_build, :coverage_reports, pipeline: pipeline, project: pipeline.project)
+ end
+ end
+
+ it 'tracks the coverage test event using HLLRedisCounter' do
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.to receive(:track_event)
- .with(test_event_name, values: user1.id)
+ .with(test_event_name_2, values: user1.id)
.and_call_original
- allow(Gitlab::UsageDataCounters::HLLRedisCounter)
+ expect { track_artifact_report }
+ .to change {
+ counter.unique_events(event_names: test_event_name_2,
+ start_date: start_time,
+ end_date: end_time)
+ }
+ .by 1
+ end
+ end
+
+ context 'when a single user started multiple pipelines with coverage reports' do
+ let_it_be(:pipeline1) { create(:ci_pipeline, :with_coverage_reports, project: project, user: user1) }
+ let_it_be(:pipeline2) { create(:ci_pipeline, :with_coverage_reports, project: project, user: user1) }
+
+ it 'tracks all pipelines using HLLRedisCounter by one user_id for the coverage test event' do
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.to receive(:track_event)
- .with(test_event_name, values: user1.id)
+ .with(test_event_name_2, values: user1.id)
+ .twice
.and_call_original
- allow(Gitlab::UsageDataCounters::HLLRedisCounter)
- .to receive(:track_event)
- .with(test_event_name, values: user2.id)
- .and_call_original
+ expect do
+ described_class.new.execute(pipeline1)
+ described_class.new.execute(pipeline2)
+ end
+ .to change {
+ counter.unique_events(event_names: test_event_name_2,
+ start_date: start_time,
+ end_date: end_time)
+ }
+ .by 1
+ end
+ end
+
+ context 'when multiple users started multiple pipelines with coverage test reports' do
+ let_it_be(:pipeline1) { create(:ci_pipeline, :with_coverage_reports, project: project, user: user1) }
+ let_it_be(:pipeline2) { create(:ci_pipeline, :with_coverage_reports, project: project, user: user2) }
+
+ it 'tracks all pipelines using HLLRedisCounter by multiple users for coverage test reports' do
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter)
+ .to receive(:track_event)
+ .with(test_event_name_2, values: user1.id)
+ .and_call_original
- allow(Gitlab::UsageDataCounters::HLLRedisCounter)
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter)
.to receive(:track_event)
- .with(test_event_name, values: user2.id)
+ .with(test_event_name_2, values: user2.id)
.and_call_original
expect do
@@ -111,7 +188,7 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportService do
described_class.new.execute(pipeline2)
end
.to change {
- counter.unique_events(event_names: test_event_name,
+ counter.unique_events(event_names: test_event_name_2,
start_date: start_time,
end_date: end_time)
}
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 7578afa7c50..d0aa1ba4c6c 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
@@ -104,7 +104,7 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection
describe '#processing_processables' do
it 'returns processables marked as processing' do
- expect(collection.processing_processables.map { |processable| processable[:id] } )
+ expect(collection.processing_processables.map { |processable| processable[:id] })
.to contain_exactly(build_a.id, build_b.id, test_a.id, test_b.id, deploy.id)
end
end
diff --git a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
index 06bb6d39fe5..1fbefc1fa22 100644
--- a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
+++ b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
@@ -25,7 +25,7 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService do
check_expectation(test_file.dig('init', 'expect'), "init")
test_file['transitions'].each_with_index do |transition, idx|
- event_on_jobs(transition['event'], transition['jobs'])
+ process_events(transition)
Sidekiq::Worker.drain_all # ensure that all async jobs are executed
check_expectation(transition['expect'], "transition:#{idx}")
end
@@ -48,20 +48,37 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService do
}
end
+ def process_events(transition)
+ if transition['jobs']
+ event_on_jobs(transition['event'], transition['jobs'])
+ else
+ event_on_pipeline(transition['event'])
+ end
+ end
+
def event_on_jobs(event, job_names)
statuses = pipeline.latest_statuses.by_name(job_names).to_a
expect(statuses.count).to eq(job_names.count) # ensure that we have the same counts
statuses.each do |status|
- if event == 'play'
+ case event
+ when 'play'
status.play(user)
- elsif event == 'retry'
+ when 'retry'
::Ci::RetryJobService.new(project, user).execute(status)
else
status.public_send("#{event}!")
end
end
end
+
+ def event_on_pipeline(event)
+ if event == 'retry'
+ pipeline.retry_failed(user)
+ else
+ pipeline.public_send("#{event}!")
+ end
+ end
end
end
diff --git a/spec/services/ci/pipeline_processing/test_cases/stage_one_test_succeeds_one_manual_test_fails_and_retry_manual_build.yml b/spec/services/ci/pipeline_processing/test_cases/stage_one_test_succeeds_one_manual_test_fails_and_retry_manual_build.yml
new file mode 100644
index 00000000000..a50fe56f8d4
--- /dev/null
+++ b/spec/services/ci/pipeline_processing/test_cases/stage_one_test_succeeds_one_manual_test_fails_and_retry_manual_build.yml
@@ -0,0 +1,54 @@
+config:
+ test1:
+ script: exit 0
+
+ test2:
+ when: manual
+ script: exit 1
+
+init:
+ expect:
+ pipeline: pending
+ stages:
+ test: pending
+ jobs:
+ test1: pending
+ test2: manual
+
+transitions:
+ - event: success
+ jobs: [test1]
+ expect:
+ pipeline: success
+ stages:
+ test: success
+ jobs:
+ test1: success
+ test2: manual
+ - event: play
+ jobs: [test2]
+ expect:
+ pipeline: running
+ stages:
+ test: running
+ jobs:
+ test1: success
+ test2: pending
+ - event: drop
+ jobs: [test2]
+ expect:
+ pipeline: success
+ stages:
+ test: success
+ jobs:
+ test1: success
+ test2: failed
+ - event: retry
+ jobs: [test2]
+ expect:
+ pipeline: running
+ stages:
+ test: running
+ jobs:
+ test1: success
+ test2: pending
diff --git a/spec/services/ci/pipeline_processing/test_cases/stage_one_test_succeeds_one_manual_test_fails_and_retry_pipeline.yml b/spec/services/ci/pipeline_processing/test_cases/stage_one_test_succeeds_one_manual_test_fails_and_retry_pipeline.yml
new file mode 100644
index 00000000000..a6112a95a12
--- /dev/null
+++ b/spec/services/ci/pipeline_processing/test_cases/stage_one_test_succeeds_one_manual_test_fails_and_retry_pipeline.yml
@@ -0,0 +1,53 @@
+config:
+ test1:
+ script: exit 0
+
+ test2:
+ when: manual
+ script: exit 1
+
+init:
+ expect:
+ pipeline: pending
+ stages:
+ test: pending
+ jobs:
+ test1: pending
+ test2: manual
+
+transitions:
+ - event: success
+ jobs: [test1]
+ expect:
+ pipeline: success
+ stages:
+ test: success
+ jobs:
+ test1: success
+ test2: manual
+ - event: play
+ jobs: [test2]
+ expect:
+ pipeline: running
+ stages:
+ test: running
+ jobs:
+ test1: success
+ test2: pending
+ - event: drop
+ jobs: [test2]
+ expect:
+ pipeline: success
+ stages:
+ test: success
+ jobs:
+ test1: success
+ test2: failed
+ - event: retry
+ expect:
+ pipeline: success
+ stages:
+ test: success
+ jobs:
+ test1: success
+ test2: manual
diff --git a/spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb b/spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb
new file mode 100644
index 00000000000..9a3aad20d89
--- /dev/null
+++ b/spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb
@@ -0,0 +1,63 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::PipelineSchedules::TakeOwnershipService do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:owner) { create(:user) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: owner) }
+
+ before_all do
+ project.add_maintainer(user)
+ project.add_maintainer(owner)
+ project.add_reporter(reporter)
+ end
+
+ describe '#execute' do
+ context 'when user does not have permission' do
+ subject(:service) { described_class.new(pipeline_schedule, reporter) }
+
+ it 'returns ServiceResponse.error' do
+ result = service.execute
+
+ expect(result).to be_a(ServiceResponse)
+ expect(result.error?).to be(true)
+ expect(result.message).to eq(_('Failed to change the owner'))
+ end
+ end
+
+ context 'when user has permission' do
+ subject(:service) { described_class.new(pipeline_schedule, user) }
+
+ it 'returns ServiceResponse.success' do
+ result = service.execute
+
+ expect(result).to be_a(ServiceResponse)
+ expect(result.success?).to be(true)
+ expect(result.payload).to eq(pipeline_schedule)
+ end
+
+ context 'when schedule update fails' do
+ subject(:service) { described_class.new(pipeline_schedule, owner) }
+
+ before do
+ allow(pipeline_schedule).to receive(:update).and_return(false)
+
+ errors = ActiveModel::Errors.new(pipeline_schedule)
+ errors.add(:base, 'An error occurred')
+ allow(pipeline_schedule).to receive(:errors).and_return(errors)
+ end
+
+ it 'returns ServiceResponse.error' do
+ result = service.execute
+
+ expect(result).to be_a(ServiceResponse)
+ expect(result.error?).to be(true)
+ expect(result.message).to eq(['An error occurred'])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/ci/play_build_service_spec.rb b/spec/services/ci/play_build_service_spec.rb
index 85ef8b60af4..fc07801b672 100644
--- a/spec/services/ci/play_build_service_spec.rb
+++ b/spec/services/ci/play_build_service_spec.rb
@@ -87,11 +87,15 @@ RSpec.describe Ci::PlayBuildService, '#execute' do
expect(build.reload.job_variables.map(&:key)).to contain_exactly('first', 'second')
end
- context 'when variables are invalid' do
+ context 'and variables are invalid' do
let(:job_variables) { [{}] }
- it 'raises an error' do
- expect { subject }.to raise_error(ActiveRecord::RecordInvalid)
+ it 'resets the attributes of the build' do
+ build.update!(job_variables_attributes: [{ key: 'old', value: 'old variable' }])
+
+ subject
+
+ expect(build.job_variables.map(&:key)).to contain_exactly('old')
end
end
diff --git a/spec/services/ci/process_build_service_spec.rb b/spec/services/ci/process_build_service_spec.rb
index 2fcb4ce73ff..9301098b083 100644
--- a/spec/services/ci/process_build_service_spec.rb
+++ b/spec/services/ci/process_build_service_spec.rb
@@ -2,147 +2,118 @@
require 'spec_helper'
RSpec.describe Ci::ProcessBuildService, '#execute' do
- let(:user) { create(:user) }
- let(:project) { create(:project) }
+ using RSpec::Parameterized::TableSyntax
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:pipeline) { create(:ci_pipeline, ref: 'master', project: project) }
subject { described_class.new(project, user).execute(build, current_status) }
- before do
+ before_all do
project.add_maintainer(user)
end
- context 'when build has on_success option' do
- let(:build) { create(:ci_build, :created, when: :on_success, user: user, project: project) }
-
- context 'when current status is success' do
- let(:current_status) { 'success' }
-
- it 'changes the build status' do
- expect { subject }.to change { build.status }.to('pending')
- end
- end
-
- context 'when current status is skipped' do
- let(:current_status) { 'skipped' }
-
- it 'changes the build status' do
- expect { subject }.to change { build.status }.to('pending')
- end
- end
-
- context 'when current status is failed' do
- let(:current_status) { 'failed' }
-
- it 'does not change the build status' do
- expect { subject }.to change { build.status }.to('skipped')
- end
+ shared_context 'with enqueue_immediately set' do
+ before do
+ build.set_enqueue_immediately!
end
end
- context 'when build has on_failure option' do
- let(:build) { create(:ci_build, :created, when: :on_failure, user: user, project: project) }
-
- context 'when current status is success' do
- let(:current_status) { 'success' }
-
- it 'changes the build status' do
- expect { subject }.to change { build.status }.to('skipped')
- end
- end
-
- context 'when current status is failed' do
- let(:current_status) { 'failed' }
-
- it 'does not change the build status' do
- expect { subject }.to change { build.status }.to('pending')
- end
+ shared_context 'with ci_retry_job_fix disabled' do
+ before do
+ stub_feature_flags(ci_retry_job_fix: false)
end
end
- context 'when build has always option' do
- let(:build) { create(:ci_build, :created, when: :always, user: user, project: project) }
-
- context 'when current status is success' do
- let(:current_status) { 'success' }
-
- it 'changes the build status' do
- expect { subject }.to change { build.status }.to('pending')
- end
+ context 'for single build' do
+ let!(:build) { create(:ci_build, *[trait].compact, :created, **conditions, pipeline: pipeline) }
+
+ where(:trait, :conditions, :current_status, :after_status, :retry_after_status, :retry_disabled_after_status) do
+ nil | { when: :on_success } | 'success' | 'pending' | 'pending' | 'pending'
+ nil | { when: :on_success } | 'skipped' | 'pending' | 'pending' | 'pending'
+ nil | { when: :on_success } | 'failed' | 'skipped' | 'skipped' | 'skipped'
+ nil | { when: :on_failure } | 'success' | 'skipped' | 'skipped' | 'skipped'
+ nil | { when: :on_failure } | 'skipped' | 'skipped' | 'skipped' | 'skipped'
+ nil | { when: :on_failure } | 'failed' | 'pending' | 'pending' | 'pending'
+ nil | { when: :always } | 'success' | 'pending' | 'pending' | 'pending'
+ nil | { when: :always } | 'skipped' | 'pending' | 'pending' | 'pending'
+ nil | { when: :always } | 'failed' | 'pending' | 'pending' | 'pending'
+ :actionable | { when: :manual } | 'success' | 'manual' | 'pending' | 'manual'
+ :actionable | { when: :manual } | 'skipped' | 'manual' | 'pending' | 'manual'
+ :actionable | { when: :manual } | 'failed' | 'skipped' | 'skipped' | 'skipped'
+ :schedulable | { when: :delayed } | 'success' | 'scheduled' | 'pending' | 'scheduled'
+ :schedulable | { when: :delayed } | 'skipped' | 'scheduled' | 'pending' | 'scheduled'
+ :schedulable | { when: :delayed } | 'failed' | 'skipped' | 'skipped' | 'skipped'
end
- context 'when current status is failed' do
- let(:current_status) { 'failed' }
-
- it 'does not change the build status' do
- expect { subject }.to change { build.status }.to('pending')
+ with_them do
+ it 'updates the job status to after_status' do
+ expect { subject }.to change { build.status }.to(after_status)
end
- end
- end
-
- context 'when build has manual option' do
- let(:build) { create(:ci_build, :created, :actionable, user: user, project: project) }
- context 'when current status is success' do
- let(:current_status) { 'success' }
+ context 'when build is set to enqueue immediately' do
+ include_context 'with enqueue_immediately set'
- it 'changes the build status' do
- expect { subject }.to change { build.status }.to('manual')
- end
- end
+ it 'updates the job status to retry_after_status' do
+ expect { subject }.to change { build.status }.to(retry_after_status)
+ end
- context 'when current status is failed' do
- let(:current_status) { 'failed' }
+ context 'when feature flag ci_retry_job_fix is disabled' do
+ include_context 'with ci_retry_job_fix disabled'
- it 'does not change the build status' do
- expect { subject }.to change { build.status }.to('skipped')
+ it "updates the job status to retry_disabled_after_status" do
+ expect { subject }.to change { build.status }.to(retry_disabled_after_status)
+ end
+ end
end
end
end
- context 'when build has delayed option' do
- before do
- allow(Ci::BuildScheduleWorker).to receive(:perform_at) {}
+ context 'when build is scheduled with DAG' do
+ let!(:build) do
+ create(
+ :ci_build,
+ *[trait].compact,
+ :dependent,
+ :created,
+ when: build_when,
+ pipeline: pipeline,
+ needed: other_build
+ )
end
- let(:build) { create(:ci_build, :created, :schedulable, user: user, project: project) }
-
- context 'when current status is success' do
- let(:current_status) { 'success' }
+ let!(:other_build) { create(:ci_build, :created, when: :on_success, pipeline: pipeline) }
- it 'changes the build status' do
- expect { subject }.to change { build.status }.to('scheduled')
- end
+ where(:trait, :build_when, :current_status, :after_status, :retry_after_status, :retry_disabled_after_status) do
+ nil | :on_success | 'success' | 'pending' | 'pending' | 'pending'
+ nil | :on_success | 'skipped' | 'skipped' | 'skipped' | 'skipped'
+ nil | :manual | 'success' | 'manual' | 'pending' | 'manual'
+ nil | :manual | 'skipped' | 'skipped' | 'skipped' | 'skipped'
+ nil | :delayed | 'success' | 'manual' | 'pending' | 'manual'
+ nil | :delayed | 'skipped' | 'skipped' | 'skipped' | 'skipped'
+ :schedulable | :delayed | 'success' | 'scheduled' | 'pending' | 'scheduled'
+ :schedulable | :delayed | 'skipped' | 'skipped' | 'skipped' | 'skipped'
end
- context 'when current status is failed' do
- let(:current_status) { 'failed' }
-
- it 'does not change the build status' do
- expect { subject }.to change { build.status }.to('skipped')
+ with_them do
+ it 'updates the job status to after_status' do
+ expect { subject }.to change { build.status }.to(after_status)
end
- end
- end
- context 'when build is scheduled with DAG' do
- using RSpec::Parameterized::TableSyntax
+ context 'when build is set to enqueue immediately' do
+ include_context 'with enqueue_immediately set'
- let(:pipeline) { create(:ci_pipeline, ref: 'master', project: project) }
- let!(:build) { create(:ci_build, :created, when: build_when, pipeline: pipeline, scheduling_type: :dag) }
- let!(:other_build) { create(:ci_build, :created, when: :on_success, pipeline: pipeline) }
- let!(:build_on_other_build) { create(:ci_build_need, build: build, name: other_build.name) }
-
- where(:build_when, :current_status, :after_status) do
- :on_success | 'success' | 'pending'
- :on_success | 'skipped' | 'skipped'
- :manual | 'success' | 'manual'
- :manual | 'skipped' | 'skipped'
- :delayed | 'success' | 'manual'
- :delayed | 'skipped' | 'skipped'
- end
+ it 'updates the job status to retry_after_status' do
+ expect { subject }.to change { build.status }.to(retry_after_status)
+ end
- with_them do
- it 'proceeds the build' do
- expect { subject }.to change { build.status }.to(after_status)
+ context 'when feature flag ci_retry_job_fix is disabled' do
+ include_context 'with ci_retry_job_fix disabled'
+
+ it "updates the job status to retry_disabled_after_status" do
+ expect { subject }.to change { build.status }.to(retry_disabled_after_status)
+ end
+ end
end
end
end
diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb
index e2e760b9812..f40f5cc5a62 100644
--- a/spec/services/ci/register_job_service_spec.rb
+++ b/spec/services/ci/register_job_service_spec.rb
@@ -14,25 +14,29 @@ module Ci
let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) }
describe '#execute' do
- context 'checks database loadbalancing stickiness' do
- subject { described_class.new(shared_runner).execute }
+ subject { described_class.new(shared_runner).execute }
+ context 'checks database loadbalancing stickiness' do
before do
project.update!(shared_runners_enabled: false)
end
- it 'result is valid if replica did caught-up' do
+ it 'result is valid if replica did caught-up', :aggregate_failures do
expect(ApplicationRecord.sticking).to receive(:all_caught_up?)
.with(:runner, shared_runner.id) { true }
expect(subject).to be_valid
+ expect(subject.build).to be_nil
+ expect(subject.build_json).to be_nil
end
- it 'result is invalid if replica did not caught-up' do
+ 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(subject).not_to be_valid
+ expect(subject.build).to be_nil
+ expect(subject.build_json).to be_nil
end
end
@@ -954,6 +958,7 @@ module Ci
expect(result).not_to be_valid
expect(result.build).to be_nil
+ expect(result.build_json).to be_nil
end
end
diff --git a/spec/services/ci/retry_job_service_spec.rb b/spec/services/ci/retry_job_service_spec.rb
index 69f19c5acf2..540e700efa6 100644
--- a/spec/services/ci/retry_job_service_spec.rb
+++ b/spec/services/ci/retry_job_service_spec.rb
@@ -3,6 +3,7 @@
require 'spec_helper'
RSpec.describe Ci::RetryJobService do
+ using RSpec::Parameterized::TableSyntax
let_it_be(:reporter) { create(:user) }
let_it_be(:developer) { create(:user) }
let_it_be(:project) { create(:project, :repository) }
@@ -11,11 +12,11 @@ RSpec.describe Ci::RetryJobService do
end
let_it_be(:stage) do
- create(:ci_stage, project: project,
- pipeline: pipeline,
- name: 'test')
+ create(:ci_stage, pipeline: pipeline, name: 'test')
end
+ let_it_be(:deploy_stage) { create(:ci_stage, pipeline: pipeline, name: 'deploy', position: stage.position + 1) }
+
let(:job_variables_attributes) { [{ key: 'MANUAL_VAR', value: 'manual test var' }] }
let(:user) { developer }
@@ -26,24 +27,11 @@ RSpec.describe Ci::RetryJobService do
project.add_reporter(reporter)
end
- shared_context 'retryable bridge' do
- let_it_be(:downstream_project) { create(:project, :repository) }
-
- let_it_be_with_refind(:job) do
- create(:ci_bridge, :success,
- pipeline: pipeline, downstream: downstream_project, description: 'a trigger job', ci_stage: stage
- )
- end
-
- let_it_be(:job_to_clone) { job }
-
- before do
- job.update!(retried: false)
+ shared_context 'retryable build' do
+ let_it_be_with_reload(:job) do
+ create(:ci_build, :success, pipeline: pipeline, ci_stage: stage)
end
- end
- shared_context 'retryable build' do
- let_it_be_with_refind(:job) { create(:ci_build, :success, pipeline: pipeline, ci_stage: stage) }
let_it_be(:another_pipeline) { create(:ci_empty_pipeline, project: project) }
let_it_be(:job_to_clone) do
@@ -60,6 +48,12 @@ RSpec.describe Ci::RetryJobService do
end
end
+ shared_context 'with ci_retry_job_fix disabled' do
+ before do
+ stub_feature_flags(ci_retry_job_fix: false)
+ end
+ end
+
shared_examples_for 'clones the job' do
let(:job) { job_to_clone }
@@ -87,8 +81,7 @@ RSpec.describe Ci::RetryJobService do
context 'when the job has needs' do
before do
- create(:ci_build_need, build: job, name: 'build1')
- create(:ci_build_need, build: job, name: 'build2')
+ create_list(:ci_build_need, 2, build: job)
end
it 'bulk inserts all the needs' do
@@ -123,16 +116,12 @@ RSpec.describe Ci::RetryJobService do
end
context 'when there are subsequent processables that are skipped' do
- let_it_be(:stage) { create(:ci_stage, pipeline: pipeline, name: 'deploy') }
-
let!(:subsequent_build) do
- create(:ci_build, :skipped, stage_idx: 2,
- pipeline: pipeline,
- ci_stage: stage)
+ create(:ci_build, :skipped, pipeline: pipeline, ci_stage: deploy_stage)
end
let!(:subsequent_bridge) do
- create(:ci_bridge, :skipped, stage_idx: 2, pipeline: pipeline, ci_stage: stage)
+ create(:ci_bridge, :skipped, pipeline: pipeline, ci_stage: deploy_stage)
end
it 'resumes pipeline processing in the subsequent stage' do
@@ -152,10 +141,9 @@ RSpec.describe Ci::RetryJobService do
end
context 'when the pipeline has other jobs' do
- let!(:stage2) { create(:ci_stage, project: project, pipeline: pipeline, name: 'deploy') }
- let!(:build2) { create(:ci_build, pipeline: pipeline, ci_stage: stage ) }
- let!(:deploy) { create(:ci_build, pipeline: pipeline, ci_stage: stage2) }
- let!(:deploy_needs_build2) { create(:ci_build_need, build: deploy, name: build2.name) }
+ let!(:other_test_build) { create(:ci_build, pipeline: pipeline, ci_stage: stage) }
+ let!(:deploy) { create(:ci_build, pipeline: pipeline, ci_stage: deploy_stage) }
+ let!(:deploy_needs_build2) { create(:ci_build_need, build: deploy, name: other_test_build.name) }
context 'when job has a nil scheduling_type' do
before do
@@ -166,7 +154,7 @@ RSpec.describe Ci::RetryJobService do
it 'populates scheduling_type of processables' do
expect(new_job.scheduling_type).to eq('stage')
expect(job.reload.scheduling_type).to eq('stage')
- expect(build2.reload.scheduling_type).to eq('stage')
+ expect(other_test_build.reload.scheduling_type).to eq('stage')
expect(deploy.reload.scheduling_type).to eq('dag')
end
end
@@ -193,6 +181,13 @@ RSpec.describe Ci::RetryJobService do
end
end
+ shared_examples_for 'checks enqueue_immediately?' do
+ it "returns enqueue_immediately" do
+ subject
+ expect(new_job.enqueue_immediately?).to eq enqueue_immediately
+ end
+ end
+
describe '#clone!' do
let(:new_job) { service.clone!(job) }
@@ -200,20 +195,6 @@ RSpec.describe Ci::RetryJobService do
expect { service.clone!(create(:ci_build).present) }.to raise_error(TypeError)
end
- context 'when the job to be cloned is a bridge' do
- include_context 'retryable bridge'
-
- it_behaves_like 'clones the job'
-
- context 'when given variables' do
- let(:new_job) { service.clone!(job, variables: job_variables_attributes) }
-
- it 'does not give variables to the new bridge' do
- expect { new_job }.not_to raise_error
- end
- end
- end
-
context 'when the job to be cloned is a build' do
include_context 'retryable build'
@@ -224,7 +205,7 @@ RSpec.describe Ci::RetryJobService do
context 'when a build with a deployment is retried' do
let!(:job) do
create(:ci_build, :with_deployment, :deploy_to_production,
- pipeline: pipeline, ci_stage: stage, project: project)
+ pipeline: pipeline, ci_stage: stage)
end
it 'creates a new deployment' do
@@ -247,7 +228,6 @@ RSpec.describe Ci::RetryJobService do
options: { environment: { name: environment_name } },
pipeline: pipeline,
ci_stage: stage,
- project: project,
user: other_developer)
end
@@ -282,24 +262,44 @@ RSpec.describe Ci::RetryJobService do
end
end
end
- end
- describe '#execute' do
- let(:new_job) { service.execute(job)[:job] }
+ context 'when enqueue_if_actionable is provided' do
+ let!(:job) do
+ create(:ci_build, *[trait].compact, :failed, pipeline: pipeline, ci_stage: stage)
+ end
- context 'when the job to be retried is a bridge' do
- include_context 'retryable bridge'
+ let(:new_job) { subject }
- it_behaves_like 'retries the job'
+ subject { service.clone!(job, enqueue_if_actionable: enqueue_if_actionable) }
- context 'when given variables' do
- let(:new_job) { service.clone!(job, variables: job_variables_attributes) }
+ where(:enqueue_if_actionable, :trait, :enqueue_immediately) do
+ true | nil | false
+ true | :manual | true
+ true | :expired_scheduled | true
+
+ false | nil | false
+ false | :manual | false
+ false | :expired_scheduled | false
+ end
+
+ with_them do
+ it_behaves_like 'checks enqueue_immediately?'
- it 'does not give variables to the new bridge' do
- expect { new_job }.not_to raise_error
+ context 'when feature flag is disabled' do
+ include_context 'with ci_retry_job_fix disabled'
+
+ it_behaves_like 'checks enqueue_immediately?' do
+ let(:enqueue_immediately) { false }
+ end
end
end
end
+ end
+
+ describe '#execute' do
+ let(:new_job) { subject[:job] }
+
+ subject { service.execute(job) }
context 'when the job to be retried is a build' do
include_context 'retryable build'
@@ -307,24 +307,18 @@ RSpec.describe Ci::RetryJobService do
it_behaves_like 'retries the job'
context 'when there are subsequent jobs that are skipped' do
- let_it_be(:stage) { create(:ci_stage, pipeline: pipeline, name: 'deploy') }
-
let!(:subsequent_build) do
- create(:ci_build, :skipped, stage_idx: 2,
- pipeline: pipeline,
- stage_id: stage.id)
+ create(:ci_build, :skipped, pipeline: pipeline, ci_stage: deploy_stage)
end
let!(:subsequent_bridge) do
- create(:ci_bridge, :skipped, stage_idx: 2,
- pipeline: pipeline,
- stage_id: stage.id)
+ create(:ci_bridge, :skipped, pipeline: pipeline, ci_stage: deploy_stage)
end
it 'does not cause an N+1 when updating the job ownership' do
control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) { service.execute(job) }.count
- create_list(:ci_build, 2, :skipped, stage_idx: job.stage_idx + 1, pipeline: pipeline, stage_id: stage.id)
+ create_list(:ci_build, 2, :skipped, pipeline: pipeline, ci_stage: deploy_stage)
expect { service.execute(job) }.not_to exceed_all_query_limit(control_count)
end
@@ -352,5 +346,161 @@ RSpec.describe Ci::RetryJobService do
end
end
end
+
+ context 'when job being retried has jobs in previous stages' do
+ let!(:job) do
+ create(
+ :ci_build,
+ :failed,
+ name: 'deploy_a',
+ pipeline: pipeline,
+ ci_stage: deploy_stage
+ )
+ end
+
+ before do
+ create(
+ :ci_build,
+ previous_stage_job_status,
+ name: 'test_a',
+ pipeline: pipeline,
+ ci_stage: stage
+ )
+ end
+
+ where(:previous_stage_job_status, :after_status) do
+ :created | 'created'
+ :pending | 'created'
+ :running | 'created'
+ :manual | 'created'
+ :scheduled | 'created'
+ :success | 'pending'
+ :failed | 'skipped'
+ :skipped | 'pending'
+ end
+
+ with_them do
+ it 'updates the new job status to after_status' do
+ expect(subject).to be_success
+ expect(new_job.status).to eq after_status
+ end
+
+ context 'when feature flag is disabled' do
+ include_context 'with ci_retry_job_fix disabled'
+
+ it 'enqueues the new job' do
+ expect(subject).to be_success
+ expect(new_job).to be_pending
+ end
+ end
+ end
+ end
+
+ context 'when job being retried has DAG dependencies' do
+ let!(:job) do
+ create(
+ :ci_build,
+ :failed,
+ :dependent,
+ name: 'deploy_a',
+ pipeline: pipeline,
+ ci_stage: deploy_stage,
+ needed: dependency
+ )
+ end
+
+ let(:dependency) do
+ create(
+ :ci_build,
+ dag_dependency_status,
+ name: 'test_a',
+ pipeline: pipeline,
+ ci_stage: stage
+ )
+ end
+
+ where(:dag_dependency_status, :after_status) do
+ :created | 'created'
+ :pending | 'created'
+ :running | 'created'
+ :manual | 'created'
+ :scheduled | 'created'
+ :success | 'pending'
+ :failed | 'skipped'
+ :skipped | 'skipped'
+ end
+
+ with_them do
+ it 'updates the new job status to after_status' do
+ expect(subject).to be_success
+ expect(new_job.status).to eq after_status
+ end
+
+ context 'when feature flag is disabled' do
+ include_context 'with ci_retry_job_fix disabled'
+
+ it 'enqueues the new job' do
+ expect(subject).to be_success
+ expect(new_job).to be_pending
+ end
+ end
+ end
+ end
+
+ context 'when there are other manual/scheduled jobs' do
+ let_it_be(:test_manual_build) do
+ create(:ci_build, :manual, pipeline: pipeline, ci_stage: stage)
+ end
+
+ let_it_be(:subsequent_manual_build) do
+ create(:ci_build, :manual, pipeline: pipeline, ci_stage: deploy_stage)
+ end
+
+ let_it_be(:test_scheduled_build) do
+ create(:ci_build, :scheduled, pipeline: pipeline, ci_stage: stage)
+ end
+
+ let_it_be(:subsequent_scheduled_build) do
+ create(:ci_build, :scheduled, pipeline: pipeline, ci_stage: deploy_stage)
+ end
+
+ let!(:job) do
+ create(:ci_build, *[trait].compact, :failed, pipeline: pipeline, ci_stage: stage)
+ end
+
+ where(:trait, :enqueue_immediately) do
+ nil | false
+ :manual | true
+ :expired_scheduled | true
+ end
+
+ with_them do
+ it 'retries the given job but not the other manual/scheduled jobs' do
+ expect { subject }
+ .to change { Ci::Build.count }.by(1)
+ .and not_change { test_manual_build.reload.status }
+ .and not_change { subsequent_manual_build.reload.status }
+ .and not_change { test_scheduled_build.reload.status }
+ .and not_change { subsequent_scheduled_build.reload.status }
+
+ expect(new_job).to be_pending
+ end
+
+ it_behaves_like 'checks enqueue_immediately?'
+
+ context 'when feature flag is disabled' do
+ include_context 'with ci_retry_job_fix disabled'
+
+ it 'enqueues the new job' do
+ expect(subject).to be_success
+ expect(new_job).to be_pending
+ end
+
+ it_behaves_like 'checks enqueue_immediately?' do
+ let(:enqueue_immediately) { false }
+ end
+ end
+ end
+ end
end
end
diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb
index 96437290ae3..77345096537 100644
--- a/spec/services/ci/retry_pipeline_service_spec.rb
+++ b/spec/services/ci/retry_pipeline_service_spec.rb
@@ -5,14 +5,16 @@ require 'spec_helper'
RSpec.describe Ci::RetryPipelineService, '#execute' do
include ProjectForksHelper
- let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let_it_be_with_refind(:user) { create(:user) }
+ let_it_be_with_refind(:project) { create(:project) }
+
let(:pipeline) { create(:ci_pipeline, project: project) }
- let(:service) { described_class.new(project, user) }
let(:build_stage) { create(:ci_stage, name: 'build', position: 0, pipeline: pipeline) }
let(:test_stage) { create(:ci_stage, name: 'test', position: 1, pipeline: pipeline) }
let(:deploy_stage) { create(:ci_stage, name: 'deploy', position: 2, pipeline: pipeline) }
+ subject(:service) { described_class.new(project, user) }
+
context 'when user has full ability to modify pipeline' do
before do
project.add_developer(user)
@@ -272,6 +274,21 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
expect(pipeline.reload).to be_running
end
end
+
+ context 'when there is a failed manual action' do
+ before do
+ create_build('rspec', :success, build_stage)
+ create_build('manual-rspec', :failed, build_stage, when: :manual, allow_failure: true)
+ end
+
+ it 'processes the manual action' do
+ service.execute(pipeline)
+
+ expect(build('rspec')).to be_success
+ expect(build('manual-rspec')).to be_manual
+ expect(pipeline.reload).to be_success
+ end
+ end
end
it 'closes all todos about failed jobs for pipeline' do
diff --git a/spec/services/ci/runners/bulk_delete_runners_service_spec.rb b/spec/services/ci/runners/bulk_delete_runners_service_spec.rb
index 8e9fc4e3012..fa8af1100df 100644
--- a/spec/services/ci/runners/bulk_delete_runners_service_spec.rb
+++ b/spec/services/ci/runners/bulk_delete_runners_service_spec.rb
@@ -5,78 +5,180 @@ require 'spec_helper'
RSpec.describe ::Ci::Runners::BulkDeleteRunnersService, '#execute' do
subject(:execute) { described_class.new(**service_args).execute }
- let(:service_args) { { runners: runners_arg } }
+ let_it_be(:admin_user) { create(:user, :admin) }
+ let_it_be_with_refind(:owner_user) { create(:user) } # discard memoized ci_owned_runners
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, group: group) }
+
+ let(:user) {}
+ let(:service_args) { { runners: runners_arg, current_user: user } }
let(:runners_arg) {}
context 'with runners specified' do
let!(:instance_runner) { create(:ci_runner) }
- let!(:group_runner) { create(:ci_runner, :group) }
- let!(:project_runner) { create(:ci_runner, :project) }
+ let!(:group_runner) { create(:ci_runner, :group, groups: [group]) }
+ let!(:project_runner) { create(:ci_runner, :project, projects: [project]) }
shared_examples 'a service deleting runners in bulk' do
+ let!(:expected_deleted_ids) { expected_deleted_runners.map(&:id) }
+
it 'destroys runners', :aggregate_failures do
- expect { subject }.to change { Ci::Runner.count }.by(-2)
+ expect { execute }.to change { Ci::Runner.count }.by(-expected_deleted_ids.count)
is_expected.to be_success
- expect(execute.payload).to eq({ deleted_count: 2, deleted_ids: [instance_runner.id, project_runner.id] })
- expect(instance_runner[:errors]).to be_nil
- expect(project_runner[:errors]).to be_nil
+ expect(execute.payload).to eq(
+ {
+ deleted_count: expected_deleted_ids.count,
+ deleted_ids: expected_deleted_ids,
+ errors: []
+ })
expect { project_runner.runner_projects.first.reload }.to raise_error(ActiveRecord::RecordNotFound)
- expect { group_runner.reload }.not_to raise_error
- expect { instance_runner.reload }.to raise_error(ActiveRecord::RecordNotFound)
- expect { project_runner.reload }.to raise_error(ActiveRecord::RecordNotFound)
+ expected_deleted_runners.each do |deleted_runner|
+ expect(deleted_runner[:errors]).to be_nil
+ expect { deleted_runner.reload }.to raise_error(ActiveRecord::RecordNotFound)
+ end
end
- context 'with some runners already deleted' do
+ context 'with too many runners specified' do
before do
- instance_runner.destroy!
+ stub_const("#{described_class}::RUNNER_LIMIT", 1)
end
- let(:runners_arg) { [instance_runner.id, project_runner.id] }
-
- it 'destroys runners and returns only deleted runners', :aggregate_failures do
- expect { subject }.to change { Ci::Runner.count }.by(-1)
+ it 'deletes only first RUNNER_LIMIT runners', :aggregate_failures do
+ expect { execute }.to change { Ci::Runner.count }.by(-1)
is_expected.to be_success
- expect(execute.payload).to eq({ deleted_count: 1, deleted_ids: [project_runner.id] })
- expect(instance_runner[:errors]).to be_nil
- expect(project_runner[:errors]).to be_nil
- expect { project_runner.reload }.to raise_error(ActiveRecord::RecordNotFound)
+ expect(execute.payload).to eq(
+ {
+ deleted_count: 1,
+ deleted_ids: expected_deleted_ids.take(1),
+ errors: ["Can only delete up to 1 runners per call. Ignored the remaining runner(s)."]
+ })
end
end
+ end
- context 'with too many runners specified' do
+ context 'when the user cannot delete runners' do
+ let(:runners_arg) { Ci::Runner.all }
+
+ context 'when user is not group owner' do
before do
- stub_const("#{described_class}::RUNNER_LIMIT", 1)
+ group.add_developer(user)
end
- it 'deletes only first RUNNER_LIMIT runners' do
- expect { subject }.to change { Ci::Runner.count }.by(-1)
+ let(:user) { create(:user) }
- is_expected.to be_success
- expect(execute.payload).to eq({ deleted_count: 1, deleted_ids: [instance_runner.id] })
+ it 'does not delete any runner and returns error', :aggregate_failures do
+ expect { execute }.not_to change { Ci::Runner.count }
+ expect(execute[:errors]).to match_array("User does not have permission to delete any of the runners")
end
end
- end
- context 'with runners specified as relation' do
- let(:runners_arg) { Ci::Runner.not_group_type }
+ context 'when user is not part of the group' do
+ let(:user) { create(:user) }
- include_examples 'a service deleting runners in bulk'
+ it 'does not delete any runner and returns error', :aggregate_failures do
+ expect { execute }.not_to change { Ci::Runner.count }
+ expect(execute[:errors]).to match_array("User does not have permission to delete any of the runners")
+ end
+ end
end
- context 'with runners specified as array of IDs' do
- let(:runners_arg) { Ci::Runner.not_group_type.ids }
+ context 'when the user can delete runners' do
+ context 'when user is an admin', :enable_admin_mode do
+ include_examples 'a service deleting runners in bulk' do
+ let(:runners_arg) { Ci::Runner.all }
+ let!(:expected_deleted_runners) { [instance_runner, group_runner, project_runner] }
+ let(:user) { admin_user }
+ end
+
+ context 'with a runner already deleted' do
+ before do
+ group_runner.destroy!
+ end
+
+ include_examples 'a service deleting runners in bulk' do
+ let(:runners_arg) { Ci::Runner.all }
+ let!(:expected_deleted_runners) { [instance_runner, project_runner] }
+ let(:user) { admin_user }
+ end
+ end
+
+ context 'when deleting a single runner' do
+ let(:runners_arg) { Ci::Runner.all }
+
+ it 'avoids N+1 cached queries', :use_sql_query_cache, :request_store do
+ # Run this once to establish a baseline
+ control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
+ execute
+ end
+
+ additional_runners = 1
+
+ create_list(:ci_runner, 1 + additional_runners, :instance)
+ create_list(:ci_runner, 1 + additional_runners, :group, groups: [group])
+ create_list(:ci_runner, 1 + additional_runners, :project, projects: [project])
+
+ service = described_class.new(runners: runners_arg, current_user: user)
+
+ # Base cost per runner is:
+ # - 1 `SELECT * FROM "taggings"` query
+ # - 1 `SAVEPOINT` query
+ # - 1 `DELETE FROM "ci_runners"` query
+ # - 1 `RELEASE SAVEPOINT` query
+ # Project runners have an additional query:
+ # - 1 `DELETE FROM "ci_runner_projects"` query, given the call to `destroy_all`
+ instance_runner_cost = 4
+ group_runner_cost = 4
+ project_runner_cost = 5
+ expect { service.execute }
+ .not_to exceed_all_query_limit(control_count)
+ .with_threshold(additional_runners * (instance_runner_cost + group_runner_cost + project_runner_cost))
+ end
+ end
+ end
- include_examples 'a service deleting runners in bulk'
+ context 'when user is group owner' do
+ before do
+ group.add_owner(user)
+ end
+
+ include_examples 'a service deleting runners in bulk' do
+ let(:runners_arg) { Ci::Runner.not_instance_type }
+ let!(:expected_deleted_runners) { [group_runner, project_runner] }
+ let(:user) { owner_user }
+ end
+
+ context 'with a runner non-authorised to be deleted' do
+ let(:runners_arg) { Ci::Runner.all }
+ let!(:expected_deleted_runners) { [project_runner] }
+ let(:user) { owner_user }
+
+ it 'destroys only authorised runners', :aggregate_failures do
+ allow(Ability).to receive(:allowed?).and_call_original
+ expect(Ability).to receive(:allowed?).with(user, :delete_runner, instance_runner).and_return(false)
+
+ expect { execute }.to change { Ci::Runner.count }.by(-2)
+
+ is_expected.to be_success
+ expect(execute.payload).to eq(
+ {
+ deleted_count: 2,
+ deleted_ids: [group_runner.id, project_runner.id],
+ errors: ["User does not have permission to delete runner(s) ##{instance_runner.id}"]
+ })
+ end
+ end
+ end
end
context 'with no arguments specified' do
let(:runners_arg) { nil }
+ let(:user) { owner_user }
it 'returns 0 deleted runners' do
is_expected.to be_success
- expect(execute.payload).to eq({ deleted_count: 0, deleted_ids: [] })
+ expect(execute.payload).to eq({ deleted_count: 0, deleted_ids: [], errors: [] })
end
end
end
diff --git a/spec/services/ci/runners/set_runner_associated_projects_service_spec.rb b/spec/services/ci/runners/set_runner_associated_projects_service_spec.rb
index 1f44612947b..e5cba80d567 100644
--- a/spec/services/ci/runners/set_runner_associated_projects_service_spec.rb
+++ b/spec/services/ci/runners/set_runner_associated_projects_service_spec.rb
@@ -67,6 +67,19 @@ RSpec.describe ::Ci::Runners::SetRunnerAssociatedProjectsService, '#execute' do
expect(runner.projects.ids).to match_array([owner_project.id] + project_ids)
end
end
+
+ context 'when disassociating all projects' do
+ let(:project_ids) { [] }
+
+ it 'reassigns associated projects and returns success response' do
+ expect(execute).to be_success
+
+ runner.reload
+
+ expect(runner.owner_project).to eq(owner_project)
+ expect(runner.projects.ids).to contain_exactly(owner_project.id)
+ end
+ end
end
context 'with failing assign_to requests' do
diff --git a/spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb b/spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb
deleted file mode 100644
index 605d9e67ab6..00000000000
--- a/spec/services/clusters/applications/check_ingress_ip_address_service_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Applications::CheckIngressIpAddressService do
- include ExclusiveLeaseHelpers
-
- let(:application) { create(:clusters_applications_ingress, :installed) }
- let(:service) { described_class.new(application) }
- let(:kubeclient) { double(::Kubeclient::Client, get_service: kube_service) }
- let(:lease_key) { "check_ingress_ip_address_service:#{application.id}" }
-
- let(:ingress) do
- [
- {
- ip: '111.222.111.222',
- hostname: 'localhost.localdomain'
- }
- ]
- end
-
- let(:kube_service) do
- ::Kubeclient::Resource.new(
- {
- status: {
- loadBalancer: {
- ingress: ingress
- }
- }
- }
- )
- end
-
- subject { service.execute }
-
- before do
- stub_exclusive_lease(lease_key, timeout: 15.seconds.to_i)
- allow(application.cluster).to receive(:kubeclient).and_return(kubeclient)
- end
-
- include_examples 'check ingress ip executions', :clusters_applications_ingress
-
- include_examples 'check ingress ip executions', :clusters_applications_knative
-end
diff --git a/spec/services/clusters/applications/check_installation_progress_service_spec.rb b/spec/services/clusters/applications/check_installation_progress_service_spec.rb
deleted file mode 100644
index 698804ff6af..00000000000
--- a/spec/services/clusters/applications/check_installation_progress_service_spec.rb
+++ /dev/null
@@ -1,204 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Applications::CheckInstallationProgressService, '#execute' do
- RESCHEDULE_PHASES = Gitlab::Kubernetes::Pod::PHASES - [Gitlab::Kubernetes::Pod::SUCCEEDED, Gitlab::Kubernetes::Pod::FAILED].freeze
-
- let(:application) { create(:clusters_applications_helm, :installing) }
- let(:service) { described_class.new(application) }
- let(:phase) { Gitlab::Kubernetes::Pod::UNKNOWN }
- let(:errors) { nil }
-
- shared_examples 'a not yet terminated installation' do |a_phase|
- let(:phase) { a_phase }
-
- before do
- expect(service).to receive(:pod_phase).once.and_return(phase)
- end
-
- context "when phase is #{a_phase}" do
- context 'when not timed_out' do
- it 'reschedule a new check' do
- expect(ClusterWaitForAppInstallationWorker).to receive(:perform_in).once
- expect(service).not_to receive(:remove_installation_pod)
-
- expect do
- service.execute
-
- application.reload
- end.not_to change(application, :status)
-
- expect(application.status_reason).to be_nil
- end
- end
- end
- end
-
- shared_examples 'error handling' do
- context 'when installation raises a Kubeclient::HttpError' do
- let(:cluster) { create(:cluster, :provided_by_user, :project) }
- let(:logger) { service.send(:logger) }
- let(:error) { Kubeclient::HttpError.new(401, 'Unauthorized', nil) }
-
- before do
- application.update!(cluster: cluster)
-
- expect(service).to receive(:pod_phase).and_raise(error)
- end
-
- include_examples 'logs kubernetes errors' do
- let(:error_name) { 'Kubeclient::HttpError' }
- let(:error_message) { 'Unauthorized' }
- let(:error_code) { 401 }
- end
-
- it 'shows the response code from the error' do
- service.execute
-
- expect(application).to be_errored.or(be_update_errored)
- expect(application.status_reason).to eq('Kubernetes error: 401')
- end
- end
- end
-
- before do
- allow(service).to receive(:installation_errors).and_return(errors)
- allow(service).to receive(:remove_installation_pod).and_return(nil)
- end
-
- context 'when application is updating' do
- let(:application) { create(:clusters_applications_helm, :updating) }
-
- include_examples 'error handling'
-
- RESCHEDULE_PHASES.each { |phase| it_behaves_like 'a not yet terminated installation', phase }
-
- context 'when installation POD succeeded' do
- let(:phase) { Gitlab::Kubernetes::Pod::SUCCEEDED }
-
- before do
- expect(service).to receive(:pod_phase).once.and_return(phase)
- end
-
- it 'removes the installation POD' do
- expect(service).to receive(:remove_installation_pod).once
-
- service.execute
- end
-
- it 'make the application installed' do
- expect(ClusterWaitForAppInstallationWorker).not_to receive(:perform_in)
-
- service.execute
-
- expect(application).to be_updated
- expect(application.status_reason).to be_nil
- end
- end
-
- context 'when installation POD failed' do
- let(:phase) { Gitlab::Kubernetes::Pod::FAILED }
- let(:errors) { 'test installation failed' }
-
- before do
- expect(service).to receive(:pod_phase).once.and_return(phase)
- end
-
- it 'make the application errored' do
- service.execute
-
- expect(application).to be_update_errored
- expect(application.status_reason).to eq('Operation failed. Check pod logs for install-helm for more details.')
- end
- end
-
- context 'when timed out' do
- let(:application) { create(:clusters_applications_helm, :timed_out, :updating) }
-
- before do
- expect(service).to receive(:pod_phase).once.and_return(phase)
- end
-
- it 'make the application errored' do
- expect(ClusterWaitForAppInstallationWorker).not_to receive(:perform_in)
-
- service.execute
-
- expect(application).to be_update_errored
- expect(application.status_reason).to eq('Operation timed out. Check pod logs for install-helm for more details.')
- end
- end
- end
-
- context 'when application is installing' do
- include_examples 'error handling'
-
- RESCHEDULE_PHASES.each { |phase| it_behaves_like 'a not yet terminated installation', phase }
-
- context 'when installation POD succeeded' do
- let(:phase) { Gitlab::Kubernetes::Pod::SUCCEEDED }
-
- before do
- expect(service).to receive(:pod_phase).once.and_return(phase)
- end
-
- it 'removes the installation POD' do
- expect_next_instance_of(Gitlab::Kubernetes::Helm::API) do |instance|
- expect(instance).to receive(:delete_pod!).with(kind_of(String)).once
- end
- expect(service).to receive(:remove_installation_pod).and_call_original
-
- service.execute
- end
-
- it 'make the application installed' do
- expect(ClusterWaitForAppInstallationWorker).not_to receive(:perform_in)
-
- service.execute
-
- expect(application).to be_installed
- expect(application.status_reason).to be_nil
- end
-
- it 'tracks application install', :snowplow do
- service.execute
-
- expect_snowplow_event(category: 'cluster:applications', action: 'cluster_application_helm_installed')
- end
- end
-
- context 'when installation POD failed' do
- let(:phase) { Gitlab::Kubernetes::Pod::FAILED }
- let(:errors) { 'test installation failed' }
-
- before do
- expect(service).to receive(:pod_phase).once.and_return(phase)
- end
-
- it 'make the application errored' do
- service.execute
-
- expect(application).to be_errored
- expect(application.status_reason).to eq('Operation failed. Check pod logs for install-helm for more details.')
- end
- end
-
- context 'when timed out' do
- let(:application) { create(:clusters_applications_helm, :timed_out) }
-
- before do
- expect(service).to receive(:pod_phase).once.and_return(phase)
- end
-
- it 'make the application errored' do
- expect(ClusterWaitForAppInstallationWorker).not_to receive(:perform_in)
-
- service.execute
-
- expect(application).to be_errored
- expect(application.status_reason).to eq('Operation timed out. Check pod logs for install-helm for more details.')
- end
- end
- end
-end
diff --git a/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb b/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb
deleted file mode 100644
index 4b8893429cf..00000000000
--- a/spec/services/clusters/applications/check_uninstall_progress_service_spec.rb
+++ /dev/null
@@ -1,155 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Applications::CheckUninstallProgressService do
- reschedule_phases = Gitlab::Kubernetes::Pod::PHASES - [Gitlab::Kubernetes::Pod::SUCCEEDED, Gitlab::Kubernetes::Pod::FAILED].freeze
-
- let(:application) { create(:clusters_applications_prometheus, :uninstalling) }
- let(:service) { described_class.new(application) }
- let(:phase) { Gitlab::Kubernetes::Pod::UNKNOWN }
- let(:errors) { nil }
- let(:worker_class) { Clusters::Applications::WaitForUninstallAppWorker }
-
- before do
- allow(service).to receive(:installation_errors).and_return(errors)
- allow(service).to receive(:remove_installation_pod)
- end
-
- shared_examples 'a not yet terminated installation' do |a_phase|
- let(:phase) { a_phase }
-
- before do
- expect(service).to receive(:pod_phase).once.and_return(phase)
- end
-
- context "when phase is #{a_phase}" do
- context 'when not timed_out' do
- it 'reschedule a new check' do
- expect(worker_class).to receive(:perform_in).once
- expect(service).not_to receive(:remove_installation_pod)
-
- expect do
- service.execute
-
- application.reload
- end.not_to change(application, :status)
-
- expect(application.status_reason).to be_nil
- end
- end
- end
- end
-
- context 'when application is uninstalling' do
- reschedule_phases.each { |phase| it_behaves_like 'a not yet terminated installation', phase }
-
- context 'when installation POD succeeded' do
- let(:phase) { Gitlab::Kubernetes::Pod::SUCCEEDED }
-
- before do
- expect_next_instance_of(Gitlab::Kubernetes::Helm::API) do |instance|
- expect(instance).to receive(:delete_pod!).with(kind_of(String)).once
- end
- expect(service).to receive(:pod_phase).once.and_return(phase)
- end
-
- it 'removes the installation POD' do
- expect(service).to receive(:remove_uninstallation_pod).and_call_original
-
- service.execute
- end
-
- it 'runs application post_uninstall' do
- expect(application).to receive(:post_uninstall).and_call_original
-
- service.execute
- end
-
- it 'destroys the application' do
- expect(worker_class).not_to receive(:perform_in)
-
- service.execute
-
- expect(application).to be_destroyed
- end
-
- context 'an error occurs while destroying' do
- before do
- expect(application).to receive(:destroy!).once.and_raise("destroy failed")
- end
-
- it 'still removes the installation POD' do
- expect(service).to receive(:remove_uninstallation_pod).and_call_original
-
- service.execute
- end
-
- it 'makes the application uninstall_errored' do
- service.execute
-
- expect(application).to be_uninstall_errored
- expect(application.status_reason).to eq('Application uninstalled but failed to destroy: destroy failed')
- end
- end
- end
-
- context 'when installation POD failed' do
- let(:phase) { Gitlab::Kubernetes::Pod::FAILED }
- let(:errors) { 'test installation failed' }
-
- before do
- expect(service).to receive(:pod_phase).once.and_return(phase)
- end
-
- it 'make the application errored' do
- service.execute
-
- expect(application).to be_uninstall_errored
- expect(application.status_reason).to eq('Operation failed. Check pod logs for uninstall-prometheus for more details.')
- end
- end
-
- context 'when timed out' do
- let(:application) { create(:clusters_applications_prometheus, :timed_out, :uninstalling) }
-
- before do
- expect(service).to receive(:pod_phase).once.and_return(phase)
- end
-
- it 'make the application errored' do
- expect(worker_class).not_to receive(:perform_in)
-
- service.execute
-
- expect(application).to be_uninstall_errored
- expect(application.status_reason).to eq('Operation timed out. Check pod logs for uninstall-prometheus for more details.')
- end
- end
-
- context 'when installation raises a Kubeclient::HttpError' do
- let(:cluster) { create(:cluster, :provided_by_user, :project) }
- let(:logger) { service.send(:logger) }
- let(:error) { Kubeclient::HttpError.new(401, 'Unauthorized', nil) }
-
- before do
- application.update!(cluster: cluster)
-
- expect(service).to receive(:pod_phase).and_raise(error)
- end
-
- include_examples 'logs kubernetes errors' do
- let(:error_name) { 'Kubeclient::HttpError' }
- let(:error_message) { 'Unauthorized' }
- let(:error_code) { 401 }
- end
-
- it 'shows the response code from the error' do
- service.execute
-
- expect(application).to be_uninstall_errored
- expect(application.status_reason).to eq('Kubernetes error: 401')
- end
- end
- end
-end
diff --git a/spec/services/clusters/applications/check_upgrade_progress_service_spec.rb b/spec/services/clusters/applications/check_upgrade_progress_service_spec.rb
deleted file mode 100644
index dbde8cec9b9..00000000000
--- a/spec/services/clusters/applications/check_upgrade_progress_service_spec.rb
+++ /dev/null
@@ -1,94 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Applications::CheckUpgradeProgressService do
- reschedule_phashes = ::Gitlab::Kubernetes::Pod::PHASES -
- [::Gitlab::Kubernetes::Pod::SUCCEEDED, ::Gitlab::Kubernetes::Pod::FAILED, ::Gitlab].freeze
-
- let(:application) { create(:clusters_applications_prometheus, :updating) }
- let(:service) { described_class.new(application) }
- let(:phase) { ::Gitlab::Kubernetes::Pod::UNKNOWN }
- let(:errors) { nil }
-
- shared_examples 'a terminated upgrade' do
- it 'removes the POD' do
- expect(service).to receive(:remove_pod).once
-
- service.execute
- end
- end
-
- shared_examples 'a not yet terminated upgrade' do |a_phase|
- let(:phase) { a_phase }
-
- context "when phase is #{a_phase}" do
- context 'when not timed out' do
- it 'reschedule a new check' do
- expect(::ClusterWaitForAppUpdateWorker).to receive(:perform_in).once
- expect(service).not_to receive(:remove_pod)
-
- service.execute
-
- expect(application).to be_updating
- expect(application.status_reason).to be_nil
- end
- end
-
- context 'when timed out' do
- let(:application) { create(:clusters_applications_prometheus, :timed_out, :updating) }
-
- it_behaves_like 'a terminated upgrade'
-
- it 'make the application update errored' do
- expect(::ClusterWaitForAppUpdateWorker).not_to receive(:perform_in)
-
- service.execute
-
- expect(application).to be_update_errored
- expect(application.status_reason).to eq("Update timed out")
- end
- end
- end
- end
-
- before do
- allow(service).to receive(:phase).once.and_return(phase)
-
- allow(service).to receive(:errors).and_return(errors)
- allow(service).to receive(:remove_pod).and_return(nil)
- end
-
- describe '#execute' do
- context 'when upgrade pod succeeded' do
- let(:phase) { ::Gitlab::Kubernetes::Pod::SUCCEEDED }
-
- it_behaves_like 'a terminated upgrade'
-
- it 'make the application upgraded' do
- expect(::ClusterWaitForAppUpdateWorker).not_to receive(:perform_in)
-
- service.execute
-
- expect(application).to be_updated
- expect(application.status_reason).to be_nil
- end
- end
-
- context 'when upgrade pod failed' do
- let(:phase) { ::Gitlab::Kubernetes::Pod::FAILED }
- let(:errors) { 'test installation failed' }
-
- it_behaves_like 'a terminated upgrade'
-
- it 'make the application update errored' do
- service.execute
-
- expect(application).to be_update_errored
- expect(application.status_reason).to eq(errors)
- end
- end
-
- reschedule_phashes.each { |phase| it_behaves_like 'a not yet terminated upgrade', phase }
- end
-end
diff --git a/spec/services/clusters/applications/create_service_spec.rb b/spec/services/clusters/applications/create_service_spec.rb
deleted file mode 100644
index 00a67a9b2ef..00000000000
--- a/spec/services/clusters/applications/create_service_spec.rb
+++ /dev/null
@@ -1,279 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Applications::CreateService do
- include TestRequestHelpers
-
- let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
- let(:user) { create(:user) }
- let(:params) { { application: 'ingress' } }
- let(:service) { described_class.new(cluster, user, params) }
-
- describe '#execute' do
- before do
- allow(ClusterInstallAppWorker).to receive(:perform_async)
- allow(ClusterUpgradeAppWorker).to receive(:perform_async)
- end
-
- subject { service.execute(test_request) }
-
- it 'creates an application' do
- expect do
- subject
-
- cluster.reload
- end.to change(cluster, :application_ingress)
- end
-
- context 'application already installed' do
- let!(:application) { create(:clusters_applications_ingress, :installed, cluster: cluster) }
-
- it 'does not create a new application' do
- expect do
- subject
- end.not_to change(Clusters::Applications::Ingress, :count)
- end
-
- it 'schedules an upgrade for the application' do
- expect(ClusterUpgradeAppWorker).to receive(:perform_async)
-
- subject
- end
- end
-
- context 'known applications' do
- context 'ingress application' do
- let(:params) do
- {
- application: 'ingress'
- }
- end
-
- before do
- expect_any_instance_of(Clusters::Applications::Ingress)
- .to receive(:make_scheduled!)
- .and_call_original
- end
-
- it 'creates the application' do
- expect do
- subject
-
- cluster.reload
- end.to change(cluster, :application_ingress)
- end
- end
-
- context 'cert manager application' do
- let(:params) do
- {
- application: 'cert_manager',
- email: 'test@example.com'
- }
- end
-
- before do
- expect_any_instance_of(Clusters::Applications::CertManager)
- .to receive(:make_scheduled!)
- .and_call_original
- end
-
- it 'creates the application' do
- expect do
- subject
-
- cluster.reload
- end.to change(cluster, :application_cert_manager)
- end
-
- it 'sets the email' do
- expect(subject.email).to eq('test@example.com')
- end
- end
-
- context 'jupyter application' do
- let(:params) do
- {
- application: 'jupyter',
- hostname: 'example.com'
- }
- end
-
- before do
- create(:clusters_applications_ingress, :installed, external_ip: "127.0.0.0", cluster: cluster)
- expect_any_instance_of(Clusters::Applications::Jupyter)
- .to receive(:make_scheduled!)
- .and_call_original
- end
-
- it 'creates the application' do
- expect do
- subject
-
- cluster.reload
- end.to change(cluster, :application_jupyter)
- end
-
- it 'sets the hostname' do
- expect(subject.hostname).to eq('example.com')
- end
-
- it 'sets the oauth_application' do
- expect(subject.oauth_application).to be_present
- end
- end
-
- context 'knative application' do
- let(:params) do
- {
- application: 'knative',
- hostname: 'example.com',
- pages_domain_id: domain.id
- }
- end
-
- let(:domain) { create(:pages_domain, :instance_serverless) }
- let(:associate_domain_service) { double('AssociateDomainService') }
-
- before do
- expect_any_instance_of(Clusters::Applications::Knative)
- .to receive(:make_scheduled!)
- .and_call_original
- end
-
- it 'creates the application' do
- expect do
- subject
-
- cluster.reload
- end.to change(cluster, :application_knative)
- end
-
- it 'sets the hostname' do
- expect(subject.hostname).to eq('example.com')
- end
-
- it 'executes AssociateDomainService' do
- expect(Serverless::AssociateDomainService).to receive(:new) do |knative, args|
- expect(knative).to be_a(Clusters::Applications::Knative)
- expect(args[:pages_domain_id]).to eq(params[:pages_domain_id])
- expect(args[:creator]).to eq(user)
-
- associate_domain_service
- end
-
- expect(associate_domain_service).to receive(:execute)
-
- subject
- end
- end
- end
-
- context 'invalid application' do
- let(:params) { { application: 'non-existent' } }
-
- it 'raises an error' do
- expect { subject }.to raise_error(Clusters::Applications::CreateService::InvalidApplicationError)
- end
- end
-
- context 'group cluster' do
- let(:cluster) { create(:cluster, :provided_by_gcp, :group) }
-
- using RSpec::Parameterized::TableSyntax
-
- where(:application, :association, :allowed, :pre_create_ingress) do
- 'ingress' | :application_ingress | true | false
- 'runner' | :application_runner | true | false
- 'prometheus' | :application_prometheus | true | false
- 'jupyter' | :application_jupyter | true | true
- end
-
- with_them do
- before do
- klass = "Clusters::Applications::#{application.titleize}"
- allow_any_instance_of(klass.constantize).to receive(:make_scheduled!).and_call_original
- create(:clusters_applications_ingress, :installed, cluster: cluster, external_hostname: 'example.com') if pre_create_ingress
- end
-
- let(:params) { { application: application } }
-
- it 'executes for each application' do
- if allowed
- expect do
- subject
-
- cluster.reload
- end.to change(cluster, association)
- else
- expect { subject }.to raise_error(Clusters::Applications::CreateService::InvalidApplicationError)
- end
- end
- end
- end
-
- context 'when application is installable' do
- shared_examples 'installable applications' do
- it 'makes the application scheduled' do
- expect do
- subject
- end.to change { Clusters::Applications::Ingress.with_status(:scheduled).count }.by(1)
- end
-
- it 'schedules an install via worker' do
- expect(ClusterInstallAppWorker)
- .to receive(:perform_async)
- .with(*worker_arguments)
- .once
-
- subject
- end
- end
-
- context 'when application is associated with a cluster' do
- let(:application) { create(:clusters_applications_ingress, :installable, cluster: cluster) }
- let(:worker_arguments) { [application.name, application.id] }
-
- it_behaves_like 'installable applications'
- end
-
- context 'when application is not associated with a cluster' do
- let(:worker_arguments) { [params[:application], kind_of(Numeric)] }
-
- it_behaves_like 'installable applications'
- end
- end
-
- context 'when installation is already in progress' do
- let!(:application) { create(:clusters_applications_ingress, :installing, cluster: cluster) }
-
- it 'raises an exception' do
- expect { subject }
- .to raise_exception(StateMachines::InvalidTransition)
- .and not_change(application.class.with_status(:scheduled), :count)
- end
-
- it 'does not schedule a cluster worker' do
- expect(ClusterInstallAppWorker).not_to receive(:perform_async)
- end
- end
-
- context 'when application is installed' do
- %i(installed updated).each do |status|
- let(:application) { create(:clusters_applications_ingress, status, cluster: cluster) }
-
- it 'schedules an upgrade via worker' do
- expect(ClusterUpgradeAppWorker)
- .to receive(:perform_async)
- .with(application.name, application.id)
- .once
-
- subject
-
- expect(application.reload).to be_scheduled
- end
- end
- end
- end
-end
diff --git a/spec/services/clusters/applications/patch_service_spec.rb b/spec/services/clusters/applications/patch_service_spec.rb
deleted file mode 100644
index 281da62b80b..00000000000
--- a/spec/services/clusters/applications/patch_service_spec.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Applications::PatchService do
- describe '#execute' do
- let(:application) { create(:clusters_applications_knative, :scheduled) }
- let!(:update_command) { application.update_command }
- let(:service) { described_class.new(application) }
- let(:helm_client) { instance_double(Gitlab::Kubernetes::Helm::API) }
-
- before do
- allow(service).to receive(:update_command).and_return(update_command)
- allow(service).to receive(:helm_api).and_return(helm_client)
- end
-
- context 'when there are no errors' do
- before do
- expect(helm_client).to receive(:update).with(update_command)
- allow(ClusterWaitForAppInstallationWorker).to receive(:perform_in).and_return(nil)
- end
-
- it 'make the application updating' do
- expect(application.cluster).not_to be_nil
- service.execute
-
- expect(application).to be_updating
- end
-
- it 'schedule async installation status check' do
- expect(ClusterWaitForAppInstallationWorker).to receive(:perform_in).once
-
- service.execute
- end
- end
-
- context 'when kubernetes cluster communication fails' do
- let(:error) { Kubeclient::HttpError.new(500, 'system failure', nil) }
-
- before do
- expect(helm_client).to receive(:update).with(update_command).and_raise(error)
- end
-
- include_examples 'logs kubernetes errors' do
- let(:error_name) { 'Kubeclient::HttpError' }
- let(:error_message) { 'system failure' }
- let(:error_code) { 500 }
- end
-
- it 'make the application errored' do
- service.execute
-
- expect(application).to be_update_errored
- expect(application.status_reason).to eq(_('Kubernetes error: %{error_code}') % { error_code: 500 })
- end
- end
-
- context 'a non kubernetes error happens' do
- let(:application) { create(:clusters_applications_knative, :scheduled) }
- let(:error) { StandardError.new('something bad happened') }
-
- include_examples 'logs kubernetes errors' do
- let(:error_name) { 'StandardError' }
- let(:error_message) { 'something bad happened' }
- let(:error_code) { nil }
- end
-
- before do
- expect(helm_client).to receive(:update).with(update_command).and_raise(error)
- end
-
- it 'make the application errored' do
- service.execute
-
- expect(application).to be_update_errored
- expect(application.status_reason).to eq(_('Failed to update.'))
- end
- end
- end
-end
diff --git a/spec/services/clusters/applications/prometheus_update_service_spec.rb b/spec/services/clusters/applications/prometheus_update_service_spec.rb
deleted file mode 100644
index 615bfc44045..00000000000
--- a/spec/services/clusters/applications/prometheus_update_service_spec.rb
+++ /dev/null
@@ -1,111 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Applications::PrometheusUpdateService do
- describe '#execute' do
- let(:project) { create(:project) }
- let(:environment) { create(:environment, project: project) }
- let(:cluster) { create(:cluster, :provided_by_user, :with_installed_helm, projects: [project]) }
- let(:application) { create(:clusters_applications_prometheus, :installed, cluster: cluster) }
- let(:empty_alerts_values_update_yaml) { "---\nalertmanager:\n enabled: false\nserverFiles:\n alerts: {}\n" }
- let(:helm_client) { instance_double(::Gitlab::Kubernetes::Helm::API) }
-
- subject(:service) { described_class.new(application, project) }
-
- context 'when prometheus is a Clusters::Integrations::Prometheus' do
- let(:application) { create(:clusters_integrations_prometheus, cluster: cluster) }
-
- it 'raises NotImplementedError' do
- expect { service.execute }.to raise_error(NotImplementedError)
- end
- end
-
- context 'when prometheus is externally installed' do
- let(:application) { create(:clusters_applications_prometheus, :externally_installed, cluster: cluster) }
-
- it 'raises NotImplementedError' do
- expect { service.execute }.to raise_error(NotImplementedError)
- end
- end
-
- context 'when prometheus is a Clusters::Applications::Prometheus' do
- let!(:patch_command) { application.patch_command(empty_alerts_values_update_yaml) }
-
- before do
- allow(service).to receive(:patch_command).with(empty_alerts_values_update_yaml).and_return(patch_command)
- allow(service).to receive(:helm_api).and_return(helm_client)
- end
-
- context 'when there are no errors' do
- before do
- expect(helm_client).to receive(:update).with(patch_command)
-
- allow(::ClusterWaitForAppUpdateWorker)
- .to receive(:perform_in)
- .and_return(nil)
- end
-
- it 'make the application updating' do
- expect(application.cluster).not_to be_nil
-
- service.execute
-
- expect(application).to be_updating
- end
-
- it 'updates current config' do
- prometheus_config_service = spy(:prometheus_config_service)
-
- expect(Clusters::Applications::PrometheusConfigService)
- .to receive(:new)
- .with(project, cluster, application)
- .and_return(prometheus_config_service)
-
- expect(prometheus_config_service)
- .to receive(:execute)
- .and_return(YAML.safe_load(empty_alerts_values_update_yaml))
-
- service.execute
- end
-
- it 'schedules async update status check' do
- expect(::ClusterWaitForAppUpdateWorker).to receive(:perform_in).once
-
- service.execute
- end
- end
-
- context 'when k8s cluster communication fails' do
- before do
- error = ::Kubeclient::HttpError.new(500, 'system failure', nil)
- allow(helm_client).to receive(:update).and_raise(error)
- end
-
- it 'make the application update errored' do
- service.execute
-
- expect(application).to be_update_errored
- expect(application.status_reason).to match(/kubernetes error:/i)
- end
- end
-
- context 'when application cannot be persisted' do
- let(:application) { build(:clusters_applications_prometheus, :installed) }
-
- before do
- allow(application).to receive(:make_updating!).once
- .and_raise(ActiveRecord::RecordInvalid.new(application))
- end
-
- it 'make the application update errored' do
- expect(helm_client).not_to receive(:update)
-
- service.execute
-
- expect(application).to be_update_errored
- end
- end
- end
- end
-end
diff --git a/spec/services/clusters/applications/update_service_spec.rb b/spec/services/clusters/applications/update_service_spec.rb
deleted file mode 100644
index 4c05a12a4a1..00000000000
--- a/spec/services/clusters/applications/update_service_spec.rb
+++ /dev/null
@@ -1,91 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Applications::UpdateService do
- include TestRequestHelpers
-
- let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
- let(:user) { create(:user) }
- let(:params) { { application: 'knative', hostname: 'update.example.com', pages_domain_id: domain.id } }
- let(:service) { described_class.new(cluster, user, params) }
- let(:domain) { create(:pages_domain, :instance_serverless) }
-
- subject { service.execute(test_request) }
-
- describe '#execute' do
- before do
- allow(ClusterPatchAppWorker).to receive(:perform_async)
- end
-
- context 'application is not installed' do
- it 'raises Clusters::Applications::BaseService::InvalidApplicationError' do
- expect(ClusterPatchAppWorker).not_to receive(:perform_async)
-
- expect { subject }
- .to raise_exception { Clusters::Applications::BaseService::InvalidApplicationError }
- .and not_change { Clusters::Applications::Knative.count }
- .and not_change { Clusters::Applications::Knative.with_status(:scheduled).count }
- end
- end
-
- context 'application is installed' do
- context 'application is schedulable' do
- let!(:application) do
- create(:clusters_applications_knative, status: 3, cluster: cluster)
- end
-
- it 'updates the application data' do
- expect do
- subject
- end.to change { application.reload.hostname }.to(params[:hostname])
- end
-
- it 'makes application scheduled!' do
- subject
-
- expect(application.reload).to be_scheduled
- end
-
- it 'schedules ClusterPatchAppWorker' do
- expect(ClusterPatchAppWorker).to receive(:perform_async)
-
- subject
- end
-
- context 'knative application' do
- let(:associate_domain_service) { double('AssociateDomainService') }
-
- it 'executes AssociateDomainService' do
- expect(Serverless::AssociateDomainService).to receive(:new) do |knative, args|
- expect(knative.id).to eq(application.id)
- expect(args[:pages_domain_id]).to eq(params[:pages_domain_id])
- expect(args[:creator]).to eq(user)
-
- associate_domain_service
- end
-
- expect(associate_domain_service).to receive(:execute)
-
- subject
- end
- end
- end
-
- context 'application is not schedulable' do
- let!(:application) do
- create(:clusters_applications_knative, status: 4, cluster: cluster)
- end
-
- it 'raises StateMachines::InvalidTransition' do
- expect(ClusterPatchAppWorker).not_to receive(:perform_async)
-
- expect { subject }
- .to raise_exception { StateMachines::InvalidTransition }
- .and not_change { application.reload.hostname }
- .and not_change { Clusters::Applications::Knative.with_status(:scheduled).count }
- end
- end
- end
- end
-end
diff --git a/spec/services/clusters/gcp/provision_service_spec.rb b/spec/services/clusters/gcp/provision_service_spec.rb
index c5778db6001..c8b7f628e5b 100644
--- a/spec/services/clusters/gcp/provision_service_spec.rb
+++ b/spec/services/clusters/gcp/provision_service_spec.rb
@@ -42,7 +42,7 @@ RSpec.describe Clusters::Gcp::ProvisionService do
gcp_project_id, zone,
{
"status": 'unexpected'
- } )
+ })
end
it_behaves_like 'error'
diff --git a/spec/services/clusters/gcp/verify_provision_status_service_spec.rb b/spec/services/clusters/gcp/verify_provision_status_service_spec.rb
index ccb4b3b6c15..ffe4516c02b 100644
--- a/spec/services/clusters/gcp/verify_provision_status_service_spec.rb
+++ b/spec/services/clusters/gcp/verify_provision_status_service_spec.rb
@@ -44,7 +44,7 @@ RSpec.describe Clusters::Gcp::VerifyProvisionStatusService do
{
"status": 'RUNNING',
"startTime": 1.minute.ago.strftime("%FT%TZ")
- } )
+ })
end
it_behaves_like 'continue_creation'
@@ -56,7 +56,7 @@ RSpec.describe Clusters::Gcp::VerifyProvisionStatusService do
{
"status": 'RUNNING',
"startTime": 30.minutes.ago.strftime("%FT%TZ")
- } )
+ })
end
it_behaves_like 'error'
@@ -70,7 +70,7 @@ RSpec.describe Clusters::Gcp::VerifyProvisionStatusService do
{
"status": 'PENDING',
"startTime": 1.minute.ago.strftime("%FT%TZ")
- } )
+ })
end
it_behaves_like 'continue_creation'
@@ -82,7 +82,7 @@ RSpec.describe Clusters::Gcp::VerifyProvisionStatusService do
gcp_project_id, zone, operation_id,
{
"status": 'DONE'
- } )
+ })
end
it_behaves_like 'finalize_creation'
@@ -94,7 +94,7 @@ RSpec.describe Clusters::Gcp::VerifyProvisionStatusService do
gcp_project_id, zone, operation_id,
{
"status": 'unexpected'
- } )
+ })
end
it_behaves_like 'error'
diff --git a/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb b/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb
deleted file mode 100644
index f26177a56d0..00000000000
--- a/spec/services/clusters/kubernetes/configure_istio_ingress_service_spec.rb
+++ /dev/null
@@ -1,223 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Kubernetes::ConfigureIstioIngressService, '#execute' do
- include KubernetesHelpers
-
- let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
- let(:api_url) { 'https://kubernetes.example.com' }
- let(:project) { cluster.project }
- let(:environment) { create(:environment, project: project) }
- let(:cluster_project) { cluster.cluster_project }
- let(:namespace) { "#{project.name}-#{project.id}-#{environment.slug}" }
- let(:kubeclient) { cluster.kubeclient }
-
- subject do
- described_class.new(
- cluster: cluster
- ).execute
- end
-
- before do
- stub_kubeclient_discover_istio(api_url)
- stub_kubeclient_create_secret(api_url, namespace: namespace)
- stub_kubeclient_put_secret(api_url, "#{namespace}-token", namespace: namespace)
-
- stub_kubeclient_get_secret(
- api_url,
- metadata_name: "#{namespace}-token",
- token: Base64.encode64('sample-token'),
- namespace: namespace
- )
-
- stub_kubeclient_get_secret(
- api_url,
- metadata_name: 'istio-ingressgateway-ca-certs',
- namespace: 'istio-system'
- )
-
- stub_kubeclient_get_secret(
- api_url,
- metadata_name: 'istio-ingressgateway-certs',
- namespace: 'istio-system'
- )
-
- stub_kubeclient_put_secret(api_url, 'istio-ingressgateway-ca-certs', namespace: 'istio-system')
- stub_kubeclient_put_secret(api_url, 'istio-ingressgateway-certs', namespace: 'istio-system')
- stub_kubeclient_get_gateway(api_url, 'knative-ingress-gateway', namespace: 'knative-serving')
- stub_kubeclient_put_gateway(api_url, 'knative-ingress-gateway', namespace: 'knative-serving')
- end
-
- context 'without a serverless_domain_cluster' do
- it 'configures gateway to use PASSTHROUGH' do
- subject
-
- expect(WebMock).to have_requested(:put, api_url + '/apis/networking.istio.io/v1alpha3/namespaces/knative-serving/gateways/knative-ingress-gateway').with(
- body: hash_including(
- apiVersion: "networking.istio.io/v1alpha3",
- kind: "Gateway",
- metadata: {
- generation: 1,
- labels: {
- "networking.knative.dev/ingress-provider" => "istio",
- "serving.knative.dev/release" => "v0.7.0"
- },
- name: "knative-ingress-gateway",
- namespace: "knative-serving",
- selfLink: "/apis/networking.istio.io/v1alpha3/namespaces/knative-serving/gateways/knative-ingress-gateway"
- },
- spec: {
- selector: {
- istio: "ingressgateway"
- },
- servers: [
- {
- hosts: ["*"],
- port: {
- name: "http",
- number: 80,
- protocol: "HTTP"
- }
- },
- {
- hosts: ["*"],
- port: {
- name: "https",
- number: 443,
- protocol: "HTTPS"
- },
- tls: {
- mode: "PASSTHROUGH"
- }
- }
- ]
- }
- )
- )
- end
- end
-
- context 'with a serverless_domain_cluster' do
- let(:serverless_domain_cluster) { create(:serverless_domain_cluster) }
- let(:certificate) { OpenSSL::X509::Certificate.new(serverless_domain_cluster.certificate) }
-
- before do
- cluster.application_knative = serverless_domain_cluster.knative
- end
-
- it 'configures certificates' do
- subject
-
- expect(serverless_domain_cluster.reload.key).not_to be_blank
- expect(serverless_domain_cluster.reload.certificate).not_to be_blank
-
- expect(certificate.subject.to_s).to include(serverless_domain_cluster.knative.hostname)
-
- expect(certificate.not_before).to be_within(1.minute).of(Time.current)
- expect(certificate.not_after).to be_within(1.minute).of(Time.current + 1000.years)
-
- expect(WebMock).to have_requested(:put, api_url + '/api/v1/namespaces/istio-system/secrets/istio-ingressgateway-ca-certs').with(
- body: hash_including(
- metadata: {
- name: 'istio-ingressgateway-ca-certs',
- namespace: 'istio-system'
- },
- type: 'Opaque'
- )
- )
-
- expect(WebMock).to have_requested(:put, api_url + '/api/v1/namespaces/istio-system/secrets/istio-ingressgateway-certs').with(
- body: hash_including(
- metadata: {
- name: 'istio-ingressgateway-certs',
- namespace: 'istio-system'
- },
- type: 'kubernetes.io/tls'
- )
- )
- end
-
- it 'configures gateway to use MUTUAL' do
- subject
-
- expect(WebMock).to have_requested(:put, api_url + '/apis/networking.istio.io/v1alpha3/namespaces/knative-serving/gateways/knative-ingress-gateway').with(
- body: {
- apiVersion: "networking.istio.io/v1alpha3",
- kind: "Gateway",
- metadata: {
- generation: 1,
- labels: {
- "networking.knative.dev/ingress-provider" => "istio",
- "serving.knative.dev/release" => "v0.7.0"
- },
- name: "knative-ingress-gateway",
- namespace: "knative-serving",
- selfLink: "/apis/networking.istio.io/v1alpha3/namespaces/knative-serving/gateways/knative-ingress-gateway"
- },
- spec: {
- selector: {
- istio: "ingressgateway"
- },
- servers: [
- {
- hosts: ["*"],
- port: {
- name: "http",
- number: 80,
- protocol: "HTTP"
- }
- },
- {
- hosts: ["*"],
- port: {
- name: "https",
- number: 443,
- protocol: "HTTPS"
- },
- tls: {
- mode: "MUTUAL",
- privateKey: "/etc/istio/ingressgateway-certs/tls.key",
- serverCertificate: "/etc/istio/ingressgateway-certs/tls.crt",
- caCertificates: "/etc/istio/ingressgateway-ca-certs/cert.pem"
- }
- }
- ]
- }
- }
- )
- end
- end
-
- context 'when there is an error' do
- before do
- cluster.application_knative = create(:clusters_applications_knative)
-
- allow_next_instance_of(described_class) do |instance|
- allow(instance).to receive(:configure_passthrough).and_raise(error)
- end
- end
-
- context 'Kubeclient::HttpError' do
- let(:error) { Kubeclient::HttpError.new(404, nil, nil) }
-
- it 'puts Knative into an errored state' do
- subject
-
- expect(cluster.application_knative).to be_errored
- expect(cluster.application_knative.status_reason).to eq('Kubernetes error: 404')
- end
- end
-
- context 'StandardError' do
- let(:error) { RuntimeError.new('something went wrong') }
-
- it 'puts Knative into an errored state' do
- subject
-
- expect(cluster.application_knative).to be_errored
- expect(cluster.application_knative.status_reason).to eq('Failed to update.')
- end
- end
- end
-end
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 064f9e42e96..37478a0bcd9 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
@@ -166,7 +166,7 @@ RSpec.describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do
expect(WebMock).to have_requested(:put, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings/#{role_binding_name}").with(
body: hash_including(
- metadata: { name: "gitlab-#{namespace}", namespace: "#{namespace}" },
+ metadata: { name: "gitlab-#{namespace}", namespace: namespace.to_s },
roleRef: {
apiGroup: 'rbac.authorization.k8s.io',
kind: 'ClusterRole',
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 607d67d8efe..470c6eb9e03 100644
--- a/spec/services/dependency_proxy/find_cached_manifest_service_spec.rb
+++ b/spec/services/dependency_proxy/find_cached_manifest_service_spec.rb
@@ -39,6 +39,14 @@ RSpec.describe DependencyProxy::FindCachedManifestService do
end
end
+ shared_examples 'returning an error' do
+ it 'returns an error', :aggregate_failures do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:http_status]).to eq(503)
+ expect(subject[:message]).to eq('Failed to download the manifest from the external registry')
+ end
+ end
+
context 'when no manifest exists' do
let_it_be(:image) { 'new-image' }
@@ -101,7 +109,7 @@ RSpec.describe DependencyProxy::FindCachedManifestService do
it_behaves_like 'returning no manifest'
end
- context 'failed connection' do
+ context 'when the connection fails' do
before do
expect(DependencyProxy::HeadManifestService).to receive(:new).and_raise(Net::OpenTimeout)
end
@@ -111,12 +119,24 @@ RSpec.describe DependencyProxy::FindCachedManifestService do
context 'and no manifest is cached' do
let_it_be(:image) { 'new-image' }
- it 'returns an error', :aggregate_failures do
- expect(subject[:status]).to eq(:error)
- expect(subject[:http_status]).to eq(503)
- expect(subject[:message]).to eq('Failed to download the manifest from the external registry')
+ it_behaves_like 'returning an error'
+ end
+ end
+
+ context 'when the connection is successful but with error in result' do
+ before do
+ allow_next_instance_of(DependencyProxy::HeadManifestService) do |service|
+ allow(service).to receive(:execute).and_return(status: :error, http_status: 401, message: "Not found")
end
end
+
+ it_behaves_like 'using the cached manifest'
+
+ context 'and no manifest is cached' do
+ let_it_be(:image) { 'new-image' }
+
+ it_behaves_like 'returning no manifest'
+ end
end
end
end
diff --git a/spec/services/deployments/create_for_build_service_spec.rb b/spec/services/deployments/create_for_build_service_spec.rb
index a2e1acadcc1..3748df87d99 100644
--- a/spec/services/deployments/create_for_build_service_spec.rb
+++ b/spec/services/deployments/create_for_build_service_spec.rb
@@ -30,7 +30,9 @@ RSpec.describe Deployments::CreateForBuildService do
context 'when creation failure occures' do
before do
- allow(build).to receive(:create_deployment!) { raise ActiveRecord::RecordInvalid }
+ allow_next_instance_of(Deployment) do |deployment|
+ allow(deployment).to receive(:save!) { raise ActiveRecord::RecordInvalid }
+ end
end
it 'trackes the exception' do
@@ -79,5 +81,88 @@ RSpec.describe Deployments::CreateForBuildService do
expect { subject }.not_to change { Deployment.count }
end
end
+
+ context 'when build has environment attribute' do
+ let!(:build) do
+ create(:ci_build, environment: 'production', project: project,
+ options: { environment: { name: 'production', **kubernetes_options } })
+ end
+
+ let!(:environment) { create(:environment, project: project, name: build.expanded_environment_name) }
+
+ let(:kubernetes_options) { {} }
+
+ it 'returns a deployment object with environment' do
+ expect(subject).to be_a(Deployment)
+ expect(subject.iid).to be_present
+ expect(subject.environment.name).to eq('production')
+ expect(subject.cluster).to be_nil
+ expect(subject.deployment_cluster).to be_nil
+ end
+
+ context 'when environment has deployment platform' do
+ let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project], managed: managed_cluster) }
+ let(:managed_cluster) { true }
+
+ it 'sets the cluster and deployment_cluster' do
+ expect(subject.cluster).to eq(cluster) # until we stop double writing in 12.9: https://gitlab.com/gitlab-org/gitlab/issues/202628
+ expect(subject.deployment_cluster.cluster).to eq(cluster)
+ end
+
+ context 'when a custom namespace is given' do
+ let(:kubernetes_options) { { kubernetes: { namespace: 'the-custom-namespace' } } }
+
+ context 'when cluster is managed' do
+ it 'does not set the custom namespace' do
+ expect(subject.deployment_cluster.kubernetes_namespace).not_to eq('the-custom-namespace')
+ end
+ end
+
+ context 'when cluster is not managed' do
+ let(:managed_cluster) { false }
+
+ it 'sets the custom namespace' do
+ expect(subject.deployment_cluster.kubernetes_namespace).to eq('the-custom-namespace')
+ end
+ end
+ end
+ end
+
+ context 'when build already has deployment' do
+ let!(:build) { create(:ci_build, :with_deployment, project: project, environment: 'production') }
+ let!(:environment) {}
+
+ it 'returns the persisted deployment' do
+ expect { subject }.not_to change { Deployment.count }
+
+ is_expected.to eq(build.deployment)
+ end
+ end
+ end
+
+ context 'when build does not start environment' do
+ where(:action) do
+ %w[stop prepare verify access]
+ end
+
+ with_them do
+ let!(:build) do
+ create(:ci_build, environment: 'production', project: project,
+ options: { environment: { name: 'production', action: action } })
+ end
+
+ it 'returns nothing' do
+ is_expected.to be_nil
+ end
+ end
+ end
+
+ context 'when build does not have environment attribute' do
+ let!(:build) { create(:ci_build, project: project) }
+
+ it 'returns nothing' do
+ is_expected.to be_nil
+ end
+ end
end
end
diff --git a/spec/services/environments/create_for_build_service_spec.rb b/spec/services/environments/create_for_build_service_spec.rb
new file mode 100644
index 00000000000..721822f355b
--- /dev/null
+++ b/spec/services/environments/create_for_build_service_spec.rb
@@ -0,0 +1,304 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Environments::CreateForBuildService do
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+
+ let!(:job) { build(:ci_build, project: project, pipeline: pipeline, **attributes) }
+ let(:service) { described_class.new }
+ let(:merge_request) {}
+
+ describe '#execute' do
+ subject { service.execute(job, merge_request: merge_request) }
+
+ shared_examples_for 'returning a correct environment' do
+ let(:expected_auto_stop_in_seconds) do
+ ChronicDuration.parse(expected_auto_stop_in).seconds if expected_auto_stop_in
+ end
+
+ it 'returns a persisted environment object' do
+ freeze_time do
+ expect { subject }.to change { Environment.count }.by(1)
+
+ expect(subject).to be_a(Environment)
+ expect(subject).to be_persisted
+ expect(subject.project).to eq(project)
+ expect(subject.name).to eq(expected_environment_name)
+ expect(subject.auto_stop_in).to eq(expected_auto_stop_in_seconds)
+ end
+ end
+
+ context 'when environment has already existed' do
+ let!(:environment) do
+ create(:environment,
+ project: project,
+ name: expected_environment_name
+ ).tap do |env|
+ env.auto_stop_in = expected_auto_stop_in
+ end
+ end
+
+ it 'returns the existing environment object' do
+ expect { subject }.not_to change { Environment.count }
+ expect { subject }.not_to change { environment.auto_stop_at }
+
+ expect(subject).to be_persisted
+ expect(subject).to eq(environment)
+ end
+ end
+ end
+
+ context 'when job has environment name attribute' do
+ let(:environment_name) { 'production' }
+ let(:expected_environment_name) { 'production' }
+ let(:expected_auto_stop_in) { nil }
+
+ let(:attributes) do
+ {
+ environment: environment_name,
+ options: { environment: { name: environment_name } }
+ }
+ end
+
+ it_behaves_like 'returning a correct environment'
+
+ context 'and job environment also has an auto_stop_in attribute' do
+ let(:environment_auto_stop_in) { '5 minutes' }
+ let(:expected_auto_stop_in) { '5 minutes' }
+
+ let(:attributes) do
+ {
+ environment: environment_name,
+ options: {
+ environment: {
+ name: environment_name,
+ auto_stop_in: environment_auto_stop_in
+ }
+ }
+ }
+ end
+
+ it_behaves_like 'returning a correct environment'
+ end
+
+ context 'and job environment has an auto_stop_in variable attribute' do
+ let(:environment_auto_stop_in) { '10 minutes' }
+ let(:expected_auto_stop_in) { '10 minutes' }
+
+ let(:attributes) do
+ {
+ environment: environment_name,
+ options: {
+ environment: {
+ name: environment_name,
+ auto_stop_in: '$TTL'
+ }
+ },
+ yaml_variables: [
+ { key: "TTL", value: environment_auto_stop_in, public: true }
+ ]
+ }
+ end
+
+ it_behaves_like 'returning a correct environment'
+ end
+ end
+
+ context 'when job has deployment tier attribute' do
+ let(:attributes) do
+ {
+ environment: 'customer-portal',
+ options: {
+ environment: {
+ name: 'customer-portal',
+ deployment_tier: deployment_tier
+ }
+ }
+ }
+ end
+
+ let(:deployment_tier) { 'production' }
+
+ context 'when environment has not been created yet' do
+ it 'sets the specified deployment tier' do
+ is_expected.to be_production
+ end
+
+ context 'when deployment tier is staging' do
+ let(:deployment_tier) { 'staging' }
+
+ it 'sets the specified deployment tier' do
+ is_expected.to be_staging
+ end
+ end
+
+ context 'when deployment tier is unknown' do
+ let(:deployment_tier) { 'unknown' }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(ArgumentError, "'unknown' is not a valid tier")
+ end
+ end
+ end
+
+ context 'when environment has already been created' do
+ before do
+ create(:environment, project: project, name: 'customer-portal', tier: :staging)
+ end
+
+ it 'does not overwrite the specified deployment tier' do
+ # This is to be updated when a deployment succeeded i.e. Deployments::UpdateEnvironmentService.
+ is_expected.to be_staging
+ end
+ end
+ end
+
+ context 'when job starts a review app' do
+ let(:environment_name) { 'review/$CI_COMMIT_REF_NAME' }
+ let(:expected_environment_name) { "review/#{job.ref}" }
+ let(:expected_auto_stop_in) { nil }
+
+ let(:attributes) do
+ {
+ environment: environment_name,
+ options: { environment: { name: environment_name } }
+ }
+ end
+
+ it_behaves_like 'returning a correct environment'
+ end
+
+ context 'when job stops a review app' do
+ let(:environment_name) { 'review/$CI_COMMIT_REF_NAME' }
+ let(:expected_environment_name) { "review/#{job.ref}" }
+ let(:expected_auto_stop_in) { nil }
+
+ let(:attributes) do
+ {
+ environment: environment_name,
+ options: { environment: { name: environment_name, action: 'stop' } }
+ }
+ end
+
+ it_behaves_like 'returning a correct environment'
+ end
+
+ context 'when merge_request is provided' do
+ let(:environment_name) { 'development' }
+ let(:attributes) { { environment: environment_name, options: { environment: { name: environment_name } } } }
+ let(:merge_request) { create(:merge_request, source_project: project) }
+ let(:seed) { described_class.new(job, merge_request: merge_request) }
+
+ context 'and environment does not exist' do
+ let(:environment_name) { 'review/$CI_COMMIT_REF_NAME' }
+
+ it 'creates an environment associated with the merge request' do
+ expect { subject }.to change { Environment.count }.by(1)
+
+ expect(subject.merge_request).to eq(merge_request)
+ end
+ end
+
+ context 'and environment already exists' do
+ before do
+ create(:environment, project: project, name: environment_name)
+ end
+
+ it 'does not change the merge request associated with the environment' do
+ expect { subject }.not_to change { Environment.count }
+
+ expect(subject.merge_request).to be_nil
+ end
+ end
+ end
+
+ context 'when a pipeline contains a deployment job' do
+ let!(:job) { build(:ci_build, :start_review_app, project: project) }
+
+ context 'and the environment does not exist' do
+ it 'creates the environment specified by the job' do
+ expect { subject }.to change { Environment.count }.by(1)
+
+ expect(environment).to be_present
+ expect(job.persisted_environment.name).to eq('review/master')
+ expect(job.metadata.expanded_environment_name).to eq('review/master')
+ end
+
+ context 'and the pipeline is for a merge request' do
+ let(:merge_request) { create(:merge_request, source_project: project) }
+
+ it 'associates the environment with the merge request' do
+ expect { subject }.to change { Environment.count }.by(1)
+
+ expect(environment.merge_request).to eq(merge_request)
+ end
+ end
+ end
+
+ context 'when an environment already exists' do
+ before do
+ create(:environment, project: project, name: 'review/master')
+ end
+
+ it 'ensures environment existence for the job' do
+ expect { subject }.not_to change { Environment.count }
+
+ expect(environment).to be_present
+ expect(job.persisted_environment.name).to eq('review/master')
+ expect(job.metadata.expanded_environment_name).to eq('review/master')
+ end
+
+ context 'and the pipeline is for a merge request' do
+ let(:merge_request) { create(:merge_request, source_project: project) }
+
+ it 'does not associate the environment with the merge request' do
+ expect { subject }.not_to change { Environment.count }
+
+ expect(environment.merge_request).to be_nil
+ end
+ end
+ end
+
+ context 'when an environment name contains an invalid character' do
+ before do
+ job.pipeline = build(:ci_pipeline, ref: '!!!', project: project)
+ end
+
+ it 'sets the failure status' do
+ expect { subject }.not_to change { Environment.count }
+
+ expect(job).to be_failed
+ expect(job).to be_environment_creation_failure
+ expect(job.persisted_environment).to be_nil
+ end
+ end
+ end
+
+ context 'when a pipeline contains a teardown job' do
+ let!(:job) { build(:ci_build, :stop_review_app, project: project) }
+
+ it 'ensures environment existence for the job' do
+ expect { subject }.to change { Environment.count }.by(1)
+
+ expect(environment).to be_present
+ expect(job.persisted_environment.name).to eq('review/master')
+ expect(job.metadata.expanded_environment_name).to eq('review/master')
+ end
+ end
+
+ context 'when a pipeline does not contain a deployment job' do
+ let!(:job) { build(:ci_build, project: project) }
+
+ it 'does not create any environments' do
+ expect { subject }.not_to change { Environment.count }
+ end
+ end
+
+ def environment
+ project.environments.find_by_name('review/master')
+ end
+ end
+end
diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb
index 06f0eb1efbc..c3ae062a4b2 100644
--- a/spec/services/event_create_service_spec.rb
+++ b/spec/services/event_create_service_spec.rb
@@ -20,33 +20,6 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
end
end
- shared_examples 'Snowplow event' do
- let(:label) { nil }
-
- it 'is not emitted if FF is disabled' do
- stub_feature_flags(feature_flag_name => false)
-
- subject
-
- expect_no_snowplow_event
- end
-
- it 'is emitted' do
- params = {
- category: category,
- action: action,
- namespace: namespace,
- user: user,
- project: project,
- label: label
- }.compact
-
- subject
-
- expect_snowplow_event(**params)
- end
- end
-
describe 'Issues' do
describe '#open_issue' do
let(:issue) { create(:issue) }
@@ -95,14 +68,17 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
let(:event_action) { Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION }
end
- it_behaves_like 'Snowplow event' do
- let(:category) { Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION.to_s }
- let(:label) { 'merge_requests_users' }
- let(:action) { 'create' }
+ 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) { 'usage_activity_by_stage_monthly.create.merge_requests_users' }
let(:namespace) { project.namespace }
let(:project) { merge_request.project }
let(:user) { merge_request.author }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
+ let(:context) do
+ [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: 'merge_requests_users').to_context]
+ end
end
end
@@ -121,14 +97,17 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
let(:event_action) { Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION }
end
- it_behaves_like 'Snowplow event' do
- let(:category) { Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION.to_s }
- let(:label) { 'merge_requests_users' }
- let(:action) { 'close' }
+ 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) { 'usage_activity_by_stage_monthly.create.merge_requests_users' }
let(:namespace) { project.namespace }
let(:project) { merge_request.project }
let(:user) { merge_request.author }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
+ let(:context) do
+ [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: 'merge_requests_users').to_context]
+ end
end
end
@@ -147,14 +126,17 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
let(:event_action) { Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION }
end
- it_behaves_like 'Snowplow event' do
- let(:category) { Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION.to_s }
- let(:label) { 'merge_requests_users' }
- let(:action) { 'merge' }
+ 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) { 'usage_activity_by_stage_monthly.create.merge_requests_users' }
let(:namespace) { project.namespace }
let(:project) { merge_request.project }
let(:user) { merge_request.author }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
+ let(:context) do
+ [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: 'merge_requests_users').to_context]
+ end
end
end
@@ -330,11 +312,16 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
let(:event_action) { Gitlab::UsageDataCounters::TrackUniqueEvents::PUSH_ACTION }
end
- it_behaves_like 'Snowplow event' do
+ it_behaves_like 'Snowplow event tracking with RedisHLL context' do
let(:category) { described_class.to_s }
- let(:action) { 'action_active_users_project_repo' }
+ let(:action) { :push }
let(:namespace) { project.namespace }
let(:feature_flag_name) { :route_hll_to_snowplow }
+ let(:label) { 'usage_activity_by_stage_monthly.create.action_monthly_active_users_project_repo' }
+ let(:context) do
+ [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll,
+ event: 'action_active_users_project_repo').to_context]
+ end
end
end
@@ -355,11 +342,16 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
let(:event_action) { Gitlab::UsageDataCounters::TrackUniqueEvents::PUSH_ACTION }
end
- it_behaves_like 'Snowplow event' do
+ it_behaves_like 'Snowplow event tracking with RedisHLL context' do
let(:category) { described_class.to_s }
- let(:action) { 'action_active_users_project_repo' }
+ let(:action) { :push }
let(:namespace) { project.namespace }
let(:feature_flag_name) { :route_hll_to_snowplow }
+ let(:label) { 'usage_activity_by_stage_monthly.create.action_monthly_active_users_project_repo' }
+ let(:context) do
+ [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll,
+ event: 'action_active_users_project_repo').to_context]
+ end
end
end
@@ -495,7 +487,7 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
stub_feature_flags(route_hll_to_snowplow_phase2: false)
end
- it 'doesnt emit snowwplow events', :snowplow do
+ it 'doesnt emit snowplow events', :snowplow do
subject
expect_no_snowplow_event
@@ -518,19 +510,22 @@ RSpec.describe EventCreateService, :clean_gitlab_redis_cache, :clean_gitlab_redi
end
context 'when it is a diff note' do
- it_behaves_like "it records the event in the event counter" do
- let(:note) { create(:diff_note_on_merge_request) }
- end
+ let(:note) { create(:diff_note_on_merge_request) }
- it_behaves_like 'Snowplow event' do
+ 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) { Gitlab::UsageDataCounters::TrackUniqueEvents::MERGE_REQUEST_ACTION.to_s }
- let(:label) { 'merge_requests_users' }
- let(:action) { 'comment' }
- let(:project) { note.project }
+ let(:category) { described_class.name }
+ let(:action) { 'commented' }
+ let(:label) { 'usage_activity_by_stage_monthly.create.merge_requests_users' }
let(:namespace) { project.namespace }
- let(:feature_flag_name) { :route_hll_to_snowplow_phase2 }
+ let(:project) { note.project }
let(:user) { author }
+ let(:context) do
+ [Gitlab::Tracking::ServicePingContext.new(data_source: :redis_hll, event: 'merge_requests_users').to_context]
+ end
end
end
diff --git a/spec/services/git/base_hooks_service_spec.rb b/spec/services/git/base_hooks_service_spec.rb
index a8d753ff124..5afd7b30ab0 100644
--- a/spec/services/git/base_hooks_service_spec.rb
+++ b/spec/services/git/base_hooks_service_spec.rb
@@ -4,10 +4,10 @@ require 'spec_helper'
RSpec.describe Git::BaseHooksService do
include RepoHelpers
- include GitHelpers
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, :repository) }
+
let(:oldrev) { Gitlab::Git::BLANK_SHA }
let(:newrev) { "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b" } # gitlab-test: git rev-parse refs/tags/v1.1.0
let(:ref) { 'refs/tags/v1.1.0' }
@@ -150,11 +150,16 @@ RSpec.describe Git::BaseHooksService do
end
shared_examples 'creates pipeline with params and expected variables' do
+ let(:pipeline_service) { double(execute: service_response) }
+ let(:service_response) { double(error?: false, payload: pipeline, message: "Error") }
+ let(:pipeline) { double(persisted?: true) }
+
it 'calls the create pipeline service' do
expect(Ci::CreatePipelineService)
.to receive(:new)
.with(project, user, pipeline_params)
- .and_return(double(execute!: true))
+ .and_return(pipeline_service)
+ expect(subject).not_to receive(:log_pipeline_errors)
subject.execute
end
@@ -239,4 +244,85 @@ RSpec.describe Git::BaseHooksService do
it_behaves_like 'creates pipeline with params and expected variables'
end
end
+
+ describe "Pipeline creation" do
+ let(:pipeline_params) do
+ {
+ after: newrev,
+ before: oldrev,
+ checkout_sha: checkout_sha,
+ push_options: push_options,
+ ref: ref,
+ variables_attributes: variables_attributes
+ }
+ end
+
+ let(:pipeline_service) { double(execute: service_response) }
+ let(:push_options) { {} }
+ let(:variables_attributes) { [] }
+
+ context "when the pipeline is persisted" do
+ let(:pipeline) { double(persisted?: true) }
+
+ context "and there are no errors" do
+ let(:service_response) { double(error?: false, payload: pipeline, message: "Error") }
+
+ it "returns success" do
+ expect(Ci::CreatePipelineService)
+ .to receive(:new)
+ .with(project, user, pipeline_params)
+ .and_return(pipeline_service)
+
+ expect(subject.execute[:status]).to eq(:success)
+ end
+ end
+
+ context "and there are errors" do
+ let(:service_response) { double(error?: true, payload: pipeline, message: "Error") }
+
+ it "does not log errors and returns success" do
+ # This behaviour is due to the save_on_errors: true setting that is the default in the execute method.
+ expect(Ci::CreatePipelineService)
+ .to receive(:new)
+ .with(project, user, pipeline_params)
+ .and_return(pipeline_service)
+ expect(subject).not_to receive(:log_pipeline_errors).with(service_response.message)
+
+ expect(subject.execute[:status]).to eq(:success)
+ end
+ end
+ end
+
+ context "when the pipeline wasn't persisted" do
+ let(:pipeline) { double(persisted?: false) }
+
+ context "and there are no errors" do
+ let(:service_response) { double(error?: false, payload: pipeline, message: nil) }
+
+ it "returns success" do
+ expect(Ci::CreatePipelineService)
+ .to receive(:new)
+ .with(project, user, pipeline_params)
+ .and_return(pipeline_service)
+ expect(subject).to receive(:log_pipeline_errors).with(service_response.message)
+
+ expect(subject.execute[:status]).to eq(:success)
+ end
+ end
+
+ context "and there are errors" do
+ let(:service_response) { double(error?: true, payload: pipeline, message: "Error") }
+
+ it "logs errors and returns success" do
+ expect(Ci::CreatePipelineService)
+ .to receive(:new)
+ .with(project, user, pipeline_params)
+ .and_return(pipeline_service)
+ expect(subject).to receive(:log_pipeline_errors).with(service_response.message)
+
+ expect(subject.execute[:status]).to eq(:success)
+ end
+ end
+ end
+ end
end
diff --git a/spec/services/git/tag_push_service_spec.rb b/spec/services/git/tag_push_service_spec.rb
index 87dbf79a245..597254d46fa 100644
--- a/spec/services/git/tag_push_service_spec.rb
+++ b/spec/services/git/tag_push_service_spec.rb
@@ -4,7 +4,6 @@ require 'spec_helper'
RSpec.describe Git::TagPushService do
include RepoHelpers
- include GitHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
diff --git a/spec/services/google_cloud/generate_pipeline_service_spec.rb b/spec/services/google_cloud/generate_pipeline_service_spec.rb
index 75494f229b5..a78d8ff6661 100644
--- a/spec/services/google_cloud/generate_pipeline_service_spec.rb
+++ b/spec/services/google_cloud/generate_pipeline_service_spec.rb
@@ -67,7 +67,7 @@ RSpec.describe GoogleCloud::GeneratePipelineService do
let_it_be(:service_params) { { action: GoogleCloud::GeneratePipelineService::ACTION_DEPLOY_TO_CLOUD_RUN } }
let_it_be(:service) { described_class.new(project, maintainer, service_params) }
- before do
+ before_all do
project.add_maintainer(maintainer)
file_name = '.gitlab-ci.yml'
@@ -103,6 +103,15 @@ EOF
expect(pipeline[:include]).to be_present
expect(gitlab_ci_yml).to include('https://gitlab.com/gitlab-org/incubation-engineering/five-minute-production/library/-/raw/main/gcp/cloud-run.gitlab-ci.yml')
end
+
+ it 'stringifies keys from the existing pipelines' do
+ response = service.execute
+
+ branch_name = response[:branch_name]
+ gitlab_ci_yml = project.repository.gitlab_ci_yml_for(branch_name)
+
+ expect(YAML.safe_load(gitlab_ci_yml).keys).to eq(%w[stages build-java test-java include])
+ end
end
describe 'when there is an existing pipeline with `deploy` stage' do
diff --git a/spec/services/groups/create_service_spec.rb b/spec/services/groups/create_service_spec.rb
index 0a8164c9ca3..0425ba3e631 100644
--- a/spec/services/groups/create_service_spec.rb
+++ b/spec/services/groups/create_service_spec.rb
@@ -271,33 +271,4 @@ RSpec.describe Groups::CreateService, '#execute' do
end
end
end
-
- describe 'logged_out_marketing_header experiment', :experiment do
- let(:service) { described_class.new(user, group_params) }
-
- subject { service.execute }
-
- before do
- stub_experiments(logged_out_marketing_header: :candidate)
- end
-
- it 'tracks signed_up event' do
- expect(experiment(:logged_out_marketing_header)).to track(
- :namespace_created,
- namespace: an_instance_of(Group)
- ).on_next_instance.with_context(actor: user)
-
- subject
- end
-
- context 'when group has not been persisted' do
- let(:service) { described_class.new(user, group_params.merge(name: '<script>alert("Attack!")</script>')) }
-
- it 'does not track signed_up event' do
- expect(experiment(:logged_out_marketing_header)).not_to track(:namespace_created)
-
- subject
- end
- end
- end
end
diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb
index 36e868fa5f1..f2dbb69f855 100644
--- a/spec/services/groups/destroy_service_spec.rb
+++ b/spec/services/groups/destroy_service_spec.rb
@@ -36,37 +36,17 @@ RSpec.describe Groups::DestroyService do
end
context 'bot tokens', :sidekiq_inline do
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- it 'initiates group bot removal', :aggregate_failures do
- bot = create(:user, :project_bot)
- group.add_developer(bot)
- create(:personal_access_token, user: bot)
-
- destroy_group(group, user, async)
-
- expect(
- Users::GhostUserMigration.where(user: bot,
- initiator_user: user)
- ).to be_exists
- end
- end
-
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
- end
-
- it 'removes group bot', :aggregate_failures do
- bot = create(:user, :project_bot)
- group.add_developer(bot)
- token = create(:personal_access_token, user: bot)
+ it 'initiates group bot removal', :aggregate_failures do
+ bot = create(:user, :project_bot)
+ group.add_developer(bot)
+ create(:personal_access_token, user: bot)
- destroy_group(group, user, async)
+ destroy_group(group, user, async)
- expect(PersonalAccessToken.find_by(id: token.id)).to be_nil
- expect(User.find_by(id: bot.id)).to be_nil
- expect(User.find_by(id: user.id)).not_to be_nil
- end
+ expect(
+ Users::GhostUserMigration.where(user: bot,
+ initiator_user: user)
+ ).to be_exists
end
end
@@ -146,7 +126,7 @@ RSpec.describe Groups::DestroyService do
end
expect { destroy_group(group, user, false) }
- .to raise_error(Groups::DestroyService::DestroyError, "Project #{project.id} can't be deleted" )
+ .to raise_error(Groups::DestroyService::DestroyError, "Project #{project.id} can't be deleted")
end
end
diff --git a/spec/services/groups/transfer_service_spec.rb b/spec/services/groups/transfer_service_spec.rb
index b543661e9a0..3cf2c875341 100644
--- a/spec/services/groups/transfer_service_spec.rb
+++ b/spec/services/groups/transfer_service_spec.rb
@@ -200,7 +200,7 @@ RSpec.describe Groups::TransferService, :sidekiq_inline do
let_it_be(:project2) { create(:project, :private, namespace: group) }
it_behaves_like 'project namespace path is in sync with project path' do
- let(:group_full_path) { "#{group.path}" }
+ let(:group_full_path) { group.path.to_s }
let(:projects_with_project_namespace) { [project1, project2] }
end
end
@@ -274,7 +274,7 @@ RSpec.describe Groups::TransferService, :sidekiq_inline do
end
it_behaves_like 'project namespace path is in sync with project path' do
- let(:group_full_path) { "#{new_parent_group.full_path}" }
+ let(:group_full_path) { new_parent_group.full_path.to_s }
let(:projects_with_project_namespace) { [project] }
end
end
diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb
index 5c87b9ac8bb..c758d3d5477 100644
--- a/spec/services/groups/update_service_spec.rb
+++ b/spec/services/groups/update_service_spec.rb
@@ -101,6 +101,15 @@ RSpec.describe Groups::UpdateService do
expect(public_group.reload.name).to eq('new-name')
end
end
+
+ context 'when the path does not change' do
+ let(:params) { { name: 'new-name', path: public_group.path } }
+
+ it 'allows the update' do
+ expect(subject).to be true
+ expect(public_group.reload.name).to eq('new-name')
+ end
+ end
end
context 'within subgroup' do
diff --git a/spec/services/groups/update_shared_runners_service_spec.rb b/spec/services/groups/update_shared_runners_service_spec.rb
index 6e938984052..98eccedeace 100644
--- a/spec/services/groups/update_shared_runners_service_spec.rb
+++ b/spec/services/groups/update_shared_runners_service_spec.rb
@@ -127,7 +127,7 @@ RSpec.describe Groups::UpdateSharedRunnersService do
end
context 'when parent does not allow' do
- let_it_be(:parent) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false ) }
+ let_it_be(:parent) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false) }
let_it_be(:group) { create(:group, :shared_runners_disabled, allow_descendants_override_disabled_shared_runners: false, parent: parent) }
it 'results error' do
diff --git a/spec/services/import/fogbugz_service_spec.rb b/spec/services/import/fogbugz_service_spec.rb
index 7b86c5c45b0..027d0240a7a 100644
--- a/spec/services/import/fogbugz_service_spec.rb
+++ b/spec/services/import/fogbugz_service_spec.rb
@@ -119,7 +119,7 @@ RSpec.describe Import::FogbugzService do
let(:error_messages_array) { instance_double(Array, join: "something went wrong") }
let(:errors_double) { instance_double(ActiveModel::Errors, full_messages: error_messages_array, :[] => nil) }
let(:project_double) { instance_double(Project, persisted?: false, errors: errors_double) }
- let(:project_creator) { instance_double(Gitlab::FogbugzImport::ProjectCreator, execute: project_double ) }
+ let(:project_creator) { instance_double(Gitlab::FogbugzImport::ProjectCreator, execute: project_double) }
before do
allow(Gitlab::FogbugzImport::ProjectCreator).to receive(:new).and_return(project_creator)
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 28af6219812..3c788138157 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
@@ -3,7 +3,7 @@
require 'spec_helper'
RSpec.describe ::Import::GitlabProjects::FileAcquisitionStrategies::FileUpload, :aggregate_failures do
- let(:file) { UploadedFile.new( File.join('spec', 'features', 'projects', 'import_export', 'test_project_export.tar.gz') ) }
+ let(:file) { UploadedFile.new(File.join('spec', 'features', 'projects', 'import_export', 'test_project_export.tar.gz')) }
describe 'validation' do
it 'validates presence of file' 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
new file mode 100644
index 00000000000..c1b993ce3d9
--- /dev/null
+++ b/spec/services/incident_management/timeline_event_tags/create_service_spec.rb
@@ -0,0 +1,71 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe IncidentManagement::TimelineEventTags::CreateService 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) }
+
+ let(:current_user) { user_with_permissions }
+ let(:args) { { 'name': 'Test tag 1', 'project_path': project.full_path } }
+
+ let(:service) { described_class.new(project, current_user, args) }
+
+ before do
+ project.add_maintainer(user_with_permissions)
+ project.add_developer(user_without_permissions)
+ end
+
+ describe '#execute' do
+ shared_examples 'error response' do |message|
+ it 'has an informative message' do
+ expect(execute).to be_error
+ expect(execute.message).to eq(message)
+ end
+ end
+
+ shared_examples 'success response' do
+ it 'has timeline event tag' do
+ expect(execute).to be_success
+
+ result = execute.payload[:timeline_event_tag]
+ expect(result).to be_a(::IncidentManagement::TimelineEventTag)
+ expect(result.name).to eq(args[:name])
+ expect(result.project).to eq(project)
+ end
+ end
+
+ subject(:execute) { service.execute }
+
+ context 'when current user is nil' do
+ let(:current_user) { nil }
+
+ it_behaves_like 'error response',
+ 'You have insufficient permissions to manage timeline event tags for this project'
+ end
+
+ context 'when user does not have permissions to create tags' do
+ let(:current_user) { user_without_permissions }
+
+ it_behaves_like 'error response',
+ 'You have insufficient permissions to manage timeline event tags for this project'
+ end
+
+ context 'when error occurs during creation' do
+ let(:args) { {} }
+
+ it_behaves_like 'error response', "Name can't be blank and Name is invalid"
+ end
+
+ context 'when user has permissions' do
+ it_behaves_like 'success response'
+
+ it 'creates database record' do
+ expect { execute }.to change {
+ ::IncidentManagement::TimelineEventTag.where(project_id: project.id).count
+ }.by(1)
+ end
+ end
+ end
+end
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 a7f448c825f..b10862a78b5 100644
--- a/spec/services/incident_management/timeline_events/create_service_spec.rb
+++ b/spec/services/incident_management/timeline_events/create_service_spec.rb
@@ -8,6 +8,9 @@ RSpec.describe IncidentManagement::TimelineEvents::CreateService do
let_it_be(:project) { create(:project) }
let_it_be_with_refind(:incident) { create(:incident, project: project) }
let_it_be(:comment) { create(:note, project: project, noteable: incident) }
+ let_it_be(:timeline_event_tag) do
+ create(:incident_management_timeline_event_tag, name: 'Test tag 1', project: project)
+ end
let(:args) do
{
@@ -134,6 +137,67 @@ RSpec.describe IncidentManagement::TimelineEvents::CreateService do
end
end
+ context 'when timeline event tag names are passed' do
+ let(:args) do
+ {
+ note: 'note',
+ occurred_at: Time.current,
+ action: 'new comment',
+ promoted_from_note: comment,
+ timeline_event_tag_names: ['Test tag 1']
+ }
+ end
+
+ it_behaves_like 'success response'
+
+ it 'matches the tag name' do
+ result = execute.payload[:timeline_event]
+ expect(result.timeline_event_tags.first).to eq(timeline_event_tag)
+ end
+
+ context 'when predefined tags are passed' do
+ let(:args) do
+ {
+ note: 'note',
+ occurred_at: Time.current,
+ action: 'new comment',
+ promoted_from_note: comment,
+ timeline_event_tag_names: ['start time', 'end time']
+ }
+ end
+
+ it_behaves_like 'success response'
+
+ it 'matches the two tags on the event and creates on project' do
+ result = execute.payload[:timeline_event]
+
+ expect(result.timeline_event_tags.count).to eq(2)
+ expect(result.timeline_event_tags.by_names(['Start time', 'End time']).pluck_names)
+ .to match_array(['Start time', 'End time'])
+ expect(project.incident_management_timeline_event_tags.pluck_names)
+ .to include('Start time', 'End time')
+ end
+ end
+
+ context 'when invalid tag names are passed' do
+ let(:args) do
+ {
+ note: 'note',
+ occurred_at: Time.current,
+ action: 'new comment',
+ promoted_from_note: comment,
+ timeline_event_tag_names: ['some other time']
+ }
+ end
+
+ it_behaves_like 'error response', "Following tags don't exist: [\"some other time\"]"
+
+ it 'does not create timeline event' do
+ expect { execute }.not_to change(IncidentManagement::TimelineEvent, :count)
+ end
+ end
+ end
+
context 'with editable param' do
let(:args) do
{
@@ -161,6 +225,38 @@ RSpec.describe IncidentManagement::TimelineEvents::CreateService do
it 'successfully creates a database record', :aggregate_failures do
expect { execute }.to change { ::IncidentManagement::TimelineEvent.count }.by(1)
end
+
+ context 'when note is more than 280 characters long' do
+ let(:args) do
+ {
+ note: 'a' * 281,
+ occurred_at: Time.current,
+ action: 'new comment',
+ promoted_from_note: comment,
+ auto_created: auto_created
+ }
+ end
+
+ let(:auto_created) { false }
+
+ context 'when was not promoted from note' do
+ let(:comment) { nil }
+
+ context 'when auto_created is true' do
+ let(:auto_created) { true }
+
+ it_behaves_like 'success response'
+ end
+
+ context 'when auto_created is false' do
+ it_behaves_like 'error response', 'Timeline text is too long (maximum is 280 characters)'
+ end
+ end
+
+ context 'when promoted from note' do
+ it_behaves_like 'success response'
+ end
+ end
end
describe 'automatically created timeline events' do
@@ -229,6 +325,17 @@ RSpec.describe IncidentManagement::TimelineEvents::CreateService do
it_behaves_like 'successfully created timeline event'
end
+ describe '.change_severity' do
+ subject(:execute) { described_class.change_severity(incident, current_user) }
+
+ let_it_be(:severity) { create(:issuable_severity, severity: :critical, issue: incident) }
+
+ let(:expected_note) { "@#{current_user.username} changed the incident severity to **Critical - S1**" }
+ let(:expected_action) { 'severity' }
+
+ it_behaves_like 'successfully created timeline event'
+ end
+
describe '.change_labels' do
subject(:execute) do
described_class.change_labels(incident, current_user, added_labels: added, removed_labels: removed)
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 5d8518cf2ef..2373a73e108 100644
--- a/spec/services/incident_management/timeline_events/update_service_spec.rb
+++ b/spec/services/incident_management/timeline_events/update_service_spec.rb
@@ -87,6 +87,12 @@ RSpec.describe IncidentManagement::TimelineEvents::UpdateService do
it_behaves_like 'error response', "Timeline text can't be blank"
end
+ context 'when note is more than 280 characters long' do
+ let(:params) { { note: 'n' * 281, occurred_at: occurred_at } }
+
+ it_behaves_like 'error response', 'Timeline text is too long (maximum is 280 characters)'
+ end
+
context 'when occurred_at is nil' do
let(:params) { { note: 'Updated note' } }
diff --git a/spec/services/issuable/discussions_list_service_spec.rb b/spec/services/issuable/discussions_list_service_spec.rb
new file mode 100644
index 00000000000..2ce47f42a72
--- /dev/null
+++ b/spec/services/issuable/discussions_list_service_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Issuable::DiscussionsListService 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) }
+ let_it_be(:milestone) { create(:milestone, project: project) }
+ let_it_be(:label) { create(:label, project: project) }
+
+ let(:finder_params_for_issuable) { {} }
+
+ subject(:discussions_service) { described_class.new(current_user, issuable, finder_params_for_issuable) }
+
+ describe 'fetching notes for issue' do
+ let_it_be(:issuable) { create(:issue, project: project) }
+
+ it_behaves_like 'listing issuable discussions', :guest, 1, 7
+ end
+
+ describe 'fetching notes for merge requests' do
+ let_it_be(:issuable) { create(:merge_request, source_project: project, target_project: project) }
+
+ it_behaves_like 'listing issuable discussions', :reporter, 0, 6
+ end
+end
diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb
index e88fe1b42f0..ef92b6984d5 100644
--- a/spec/services/issues/close_service_spec.rb
+++ b/spec/services/issues/close_service_spec.rb
@@ -397,9 +397,26 @@ RSpec.describe Issues::CloseService do
end
context 'when issue is not confidential' do
+ let(:expected_payload) do
+ include(
+ event_type: 'issue',
+ object_kind: 'issue',
+ changes: {
+ closed_at: { current: kind_of(Time), previous: nil },
+ state_id: { current: 2, previous: 1 },
+ updated_at: { current: kind_of(Time), previous: kind_of(Time) }
+ },
+ object_attributes: include(
+ closed_at: kind_of(Time),
+ state: 'closed',
+ action: 'close'
+ )
+ )
+ end
+
it 'executes issue hooks' do
- expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :issue_hooks)
- expect(project).to receive(:execute_integrations).with(an_instance_of(Hash), :issue_hooks)
+ expect(project).to receive(:execute_hooks).with(expected_payload, :issue_hooks)
+ expect(project).to receive(:execute_integrations).with(expected_payload, :issue_hooks)
described_class.new(project: project, current_user: user).close_issue(issue)
end
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index 5fe4c693451..5ddf91e167e 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -391,22 +391,61 @@ RSpec.describe Issues::CreateService do
end
end
- it 'executes issue hooks when issue is not confidential' do
- opts = { title: 'Title', description: 'Description', confidential: false }
+ describe 'executing hooks' do
+ let(:opts) { { title: 'Title', description: 'Description' } }
+ let(:expected_payload) do
+ include(
+ event_type: 'issue',
+ object_kind: 'issue',
+ changes: {
+ author_id: { current: user.id, previous: nil },
+ created_at: { current: kind_of(Time), previous: nil },
+ description: { current: opts[:description], previous: nil },
+ id: { current: kind_of(Integer), previous: nil },
+ iid: { current: kind_of(Integer), previous: nil },
+ project_id: { current: project.id, previous: nil },
+ title: { current: opts[:title], previous: nil },
+ updated_at: { current: kind_of(Time), previous: nil }
+ },
+ object_attributes: include(
+ opts.merge(
+ author_id: user.id,
+ project_id: project.id
+ )
+ )
+ )
+ end
+
+ it 'executes issue hooks' do
+ expect(project).to receive(:execute_hooks).with(expected_payload, :issue_hooks)
+ expect(project).to receive(:execute_integrations).with(expected_payload, :issue_hooks)
- expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :issue_hooks)
- expect(project).to receive(:execute_integrations).with(an_instance_of(Hash), :issue_hooks)
+ described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute
+ end
- described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute
- end
+ context 'when issue is confidential' do
+ let(:expected_payload) do
+ include(
+ event_type: 'confidential_issue',
+ object_kind: 'issue',
+ changes: include(
+ confidential: { current: true, previous: false }
+ ),
+ object_attributes: include(confidential: true)
+ )
+ end
- it 'executes confidential issue hooks when issue is confidential' do
- opts = { title: 'Title', description: 'Description', confidential: true }
+ before do
+ opts[:confidential] = true
+ end
- expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :confidential_issue_hooks)
- expect(project).to receive(:execute_integrations).with(an_instance_of(Hash), :confidential_issue_hooks)
+ it 'executes confidential issue hooks' do
+ expect(project).to receive(:execute_hooks).with(expected_payload, :confidential_issue_hooks)
+ expect(project).to receive(:execute_integrations).with(expected_payload, :confidential_issue_hooks)
- described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute
+ described_class.new(project: project, current_user: user, params: opts, spam_params: spam_params).execute
+ end
+ end
end
context 'after_save callback to store_mentions' do
diff --git a/spec/services/issues/export_csv_service_spec.rb b/spec/services/issues/export_csv_service_spec.rb
index d04480bec18..66d017464bf 100644
--- a/spec/services/issues/export_csv_service_spec.rb
+++ b/spec/services/issues/export_csv_service_spec.rb
@@ -185,7 +185,7 @@ RSpec.describe Issues::ExportCsvService do
labeled_rows = csv.select { |entry| labeled_issues.map(&:iid).include?(entry['Issue ID'].to_i) }
expect(labeled_rows.count).to eq(2)
- expect(labeled_rows.map { |entry| entry['Labels'] }).to all( eq("Feature,Idea") )
+ expect(labeled_rows.map { |entry| entry['Labels'] }).to all(eq("Feature,Idea"))
end
end
end
diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb
index 23180f75eb3..655c5085fdc 100644
--- a/spec/services/issues/move_service_spec.rb
+++ b/spec/services/issues/move_service_spec.rb
@@ -228,18 +228,48 @@ RSpec.describe Issues::MoveService do
end
context 'project issue hooks' do
- let!(:hook) { create(:project_hook, project: old_project, issues_events: true) }
+ let_it_be(:old_project_hook) { create(:project_hook, project: old_project, issues_events: true) }
+ let_it_be(:new_project_hook) { create(:project_hook, project: new_project, issues_events: true) }
+
+ let(:expected_new_project_hook_payload) do
+ hash_including(
+ event_type: 'issue',
+ object_kind: 'issue',
+ object_attributes: include(
+ project_id: new_project.id,
+ state: 'opened',
+ action: 'open'
+ )
+ )
+ end
+
+ let(:expected_old_project_hook_payload) do
+ hash_including(
+ event_type: 'issue',
+ object_kind: 'issue',
+ changes: {
+ state_id: { current: 2, previous: 1 },
+ closed_at: { current: kind_of(Time), previous: nil },
+ updated_at: { current: kind_of(Time), previous: kind_of(Time) }
+ },
+ object_attributes: include(
+ id: old_issue.id,
+ closed_at: kind_of(Time),
+ state: 'closed',
+ action: 'close'
+ )
+ )
+ end
- it 'executes project issue hooks' do
- allow_next_instance_of(WebHookService) do |instance|
- allow(instance).to receive(:execute)
+ it 'executes project issue hooks for both projects' do
+ expect_next_instance_of(WebHookService, new_project_hook, expected_new_project_hook_payload, 'issue_hooks') do |service|
+ expect(service).to receive(:async_execute).once
+ end
+ expect_next_instance_of(WebHookService, old_project_hook, expected_old_project_hook_payload, 'issue_hooks') do |service|
+ expect(service).to receive(:async_execute).once
end
- # Ideally, we'd test that `WebHookWorker.jobs.size` increased by 1,
- # but since the entire spec run takes place in a transaction, we never
- # actually get to the `after_commit` hook that queues these jobs.
- expect { move_service.execute(old_issue, new_project) }
- .not_to raise_error # Sidekiq::Worker::EnqueueFromTransactionError
+ move_service.execute(old_issue, new_project)
end
end
diff --git a/spec/services/issues/relative_position_rebalancing_service_spec.rb b/spec/services/issues/relative_position_rebalancing_service_spec.rb
index 37a94e1d6a2..27c0394ac8b 100644
--- a/spec/services/issues/relative_position_rebalancing_service_spec.rb
+++ b/spec/services/issues/relative_position_rebalancing_service_spec.rb
@@ -34,10 +34,6 @@ RSpec.describe Issues::RelativePositionRebalancingService, :clean_gitlab_redis_s
end
end
- before do
- stub_feature_flags(issue_rebalancing_with_retry: false)
- end
-
def issues_in_position_order
project.reload.issues.order_by_relative_position.to_a
end
@@ -97,8 +93,12 @@ RSpec.describe Issues::RelativePositionRebalancingService, :clean_gitlab_redis_s
it 'resumes a started rebalance even if there are already too many rebalances running' do
Gitlab::Redis::SharedState.with do |redis|
- redis.sadd("gitlab:issues-position-rebalances:running_rebalances", "#{::Gitlab::Issues::Rebalancing::State::PROJECT}/#{project.id}")
- redis.sadd("gitlab:issues-position-rebalances:running_rebalances", "1/100")
+ redis.sadd("gitlab:issues-position-rebalances:running_rebalances",
+ [
+ "#{::Gitlab::Issues::Rebalancing::State::PROJECT}/#{project.id}",
+ "1/100"
+ ]
+ )
end
caching = service.send(:caching)
diff --git a/spec/services/issues/reopen_service_spec.rb b/spec/services/issues/reopen_service_spec.rb
index 477b44f4c2c..6013826f9b1 100644
--- a/spec/services/issues/reopen_service_spec.rb
+++ b/spec/services/issues/reopen_service_spec.rb
@@ -85,9 +85,25 @@ RSpec.describe Issues::ReopenService do
end
context 'when issue is not confidential' do
+ let(:expected_payload) do
+ include(
+ event_type: 'issue',
+ object_kind: 'issue',
+ changes: {
+ closed_at: { current: nil, previous: kind_of(Time) },
+ state_id: { current: 1, previous: 2 },
+ updated_at: { current: kind_of(Time), previous: kind_of(Time) }
+ },
+ object_attributes: include(
+ state: 'opened',
+ action: 'reopen'
+ )
+ )
+ end
+
it 'executes issue hooks' do
- expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :issue_hooks)
- expect(project).to receive(:execute_integrations).with(an_instance_of(Hash), :issue_hooks)
+ expect(project).to receive(:execute_hooks).with(expected_payload, :issue_hooks)
+ expect(project).to receive(:execute_integrations).with(expected_payload, :issue_hooks)
execute
end
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 20b1a1f58bb..f1ee62fd589 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -104,10 +104,33 @@ RSpec.describe Issues::UpdateService, :mailer do
expect(issue.issue_customer_relations_contacts.last.contact).to eq contact
end
- it 'updates issue milestone when passing `milestone` param' do
- update_issue(milestone: milestone)
+ context 'when updating milestone' do
+ before do
+ update_issue({ milestone: nil })
+ end
- expect(issue.milestone).to eq milestone
+ it 'updates issue milestone when passing `milestone` param' do
+ expect { update_issue({ milestone: milestone }) }
+ .to change(issue, :milestone).to(milestone).from(nil)
+ end
+
+ it "triggers 'issuableMilestoneUpdated'" do
+ expect(GraphqlTriggers).to receive(:issuable_milestone_updated).with(issue).and_call_original
+
+ update_issue({ milestone: milestone })
+ end
+
+ context 'when milestone remains unchanged' do
+ before do
+ update_issue({ title: 'abc', milestone: milestone })
+ end
+
+ it "does not trigger 'issuableMilestoneUpdated'" do
+ expect(GraphqlTriggers).not_to receive(:issuable_milestone_updated)
+
+ update_issue({ milestone: milestone })
+ end
+ end
end
context 'when sentry identifier is given' do
@@ -520,7 +543,7 @@ RSpec.describe Issues::UpdateService, :mailer do
end
end
- context 'when decription is not changed' do
+ context 'when description is not changed' do
it 'does not trigger GraphQL description updated subscription' do
expect(GraphqlTriggers).not_to receive(:issuable_description_updated)
@@ -1379,7 +1402,7 @@ RSpec.describe Issues::UpdateService, :mailer do
end
end
- include_examples 'issuable update service' do
+ it_behaves_like 'issuable update service' do
let(:open_issuable) { issue }
let(:closed_issuable) { create(:closed_issue, project: project) }
end
diff --git a/spec/services/labels/promote_service_spec.rb b/spec/services/labels/promote_service_spec.rb
index a10aaa14030..3af6cf4c8f4 100644
--- a/spec/services/labels/promote_service_spec.rb
+++ b/spec/services/labels/promote_service_spec.rb
@@ -171,7 +171,7 @@ RSpec.describe Labels::PromoteService do
end
context 'when there is an existing identical group label' do
- let!(:existing_group_label) { create(:group_label, group: group_1, title: project_label_1_1.title ) }
+ let!(:existing_group_label) { create(:group_label, group: group_1, title: project_label_1_1.title) }
it 'uses the existing group label' do
expect { service.execute(project_label_1_1) }
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
new file mode 100644
index 00000000000..1824f822ba8
--- /dev/null
+++ b/spec/services/loose_foreign_keys/process_deleted_records_service_spec.rb
@@ -0,0 +1,198 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe LooseForeignKeys::ProcessDeletedRecordsService do
+ include MigrationsHelpers
+
+ def create_table_structure
+ migration = ActiveRecord::Migration.new.extend(Gitlab::Database::MigrationHelpers::LooseForeignKeyHelpers)
+
+ migration.create_table :_test_loose_fk_parent_table_1
+ migration.create_table :_test_loose_fk_parent_table_2
+
+ migration.create_table :_test_loose_fk_child_table_1_1 do |t|
+ t.bigint :parent_id
+ end
+
+ migration.create_table :_test_loose_fk_child_table_1_2 do |t|
+ t.bigint :parent_id_with_different_column
+ end
+
+ migration.create_table :_test_loose_fk_child_table_2_1 do |t|
+ t.bigint :parent_id
+ end
+
+ migration.track_record_deletions(:_test_loose_fk_parent_table_1)
+ migration.track_record_deletions(:_test_loose_fk_parent_table_2)
+ end
+
+ let(:all_loose_foreign_key_definitions) do
+ {
+ '_test_loose_fk_parent_table_1' => [
+ ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(
+ '_test_loose_fk_child_table_1_1',
+ '_test_loose_fk_parent_table_1',
+ {
+ column: 'parent_id',
+ on_delete: :async_delete,
+ gitlab_schema: :gitlab_main
+ }
+ ),
+ ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(
+ '_test_loose_fk_child_table_1_2',
+ '_test_loose_fk_parent_table_1',
+ {
+ column: 'parent_id_with_different_column',
+ on_delete: :async_nullify,
+ gitlab_schema: :gitlab_main
+ }
+ )
+ ],
+ '_test_loose_fk_parent_table_2' => [
+ ActiveRecord::ConnectionAdapters::ForeignKeyDefinition.new(
+ '_test_loose_fk_child_table_2_1',
+ '_test_loose_fk_parent_table_2',
+ {
+ column: 'parent_id',
+ on_delete: :async_delete,
+ gitlab_schema: :gitlab_main
+ }
+ )
+ ]
+ }
+ end
+
+ let(:connection) { ::ApplicationRecord.connection }
+
+ let(:loose_fk_parent_table_1) { table(:_test_loose_fk_parent_table_1) }
+ let(:loose_fk_parent_table_2) { table(:_test_loose_fk_parent_table_2) }
+ let(:loose_fk_child_table_1_1) { table(:_test_loose_fk_child_table_1_1) }
+ let(:loose_fk_child_table_1_2) { table(:_test_loose_fk_child_table_1_2) }
+ let(:loose_fk_child_table_2_1) { table(:_test_loose_fk_child_table_2_1) }
+
+ before(:all) do
+ create_table_structure
+ end
+
+ after(:all) do
+ migration = ActiveRecord::Migration.new
+
+ migration.drop_table :_test_loose_fk_parent_table_1
+ migration.drop_table :_test_loose_fk_parent_table_2
+ migration.drop_table :_test_loose_fk_child_table_1_1
+ migration.drop_table :_test_loose_fk_child_table_1_2
+ migration.drop_table :_test_loose_fk_child_table_2_1
+ end
+
+ before do
+ allow(Gitlab::Database::LooseForeignKeys).to receive(:definitions_by_table)
+ .and_return(all_loose_foreign_key_definitions)
+
+ parent_record_1 = loose_fk_parent_table_1.create!
+ loose_fk_child_table_1_1.create!(parent_id: parent_record_1.id)
+ loose_fk_child_table_1_2.create!(parent_id_with_different_column: parent_record_1.id)
+
+ parent_record_2 = loose_fk_parent_table_1.create!
+ 2.times { loose_fk_child_table_1_1.create!(parent_id: parent_record_2.id) }
+ 3.times { loose_fk_child_table_1_2.create!(parent_id_with_different_column: parent_record_2.id) }
+
+ parent_record_3 = loose_fk_parent_table_2.create!
+ 5.times { loose_fk_child_table_2_1.create!(parent_id: parent_record_3.id) }
+
+ loose_fk_parent_table_1.delete_all
+ loose_fk_parent_table_2.delete_all
+ end
+
+ describe '#execute' do
+ def execute
+ ::Gitlab::Database::SharedModel.using_connection(connection) do
+ described_class.new(connection: connection).execute
+ end
+ end
+
+ it 'cleans up all rows' do
+ execute
+
+ expect(loose_fk_child_table_1_1.count).to eq(0)
+ expect(loose_fk_child_table_1_2.where(parent_id_with_different_column: nil).count).to eq(4)
+ expect(loose_fk_child_table_2_1.count).to eq(0)
+ end
+
+ it 'returns stats for records cleaned up' do
+ stats = execute
+
+ expect(stats[:delete_count]).to eq(8)
+ expect(stats[:update_count]).to eq(4)
+ end
+
+ it 'records the Apdex as success: true' do
+ expect(::Gitlab::Metrics::LooseForeignKeysSlis).to receive(:record_apdex)
+ .with(success: true, db_config_name: 'main')
+
+ execute
+ end
+
+ it 'records the error rate as error: false' do
+ expect(::Gitlab::Metrics::LooseForeignKeysSlis).to receive(:record_error_rate)
+ .with(error: false, db_config_name: 'main')
+
+ execute
+ end
+
+ context 'when the amount of records to clean up exceeds BATCH_SIZE' do
+ before do
+ stub_const('LooseForeignKeys::CleanupWorker::BATCH_SIZE', 2)
+ end
+
+ it 'cleans up everything over multiple batches' do
+ expect(LooseForeignKeys::BatchCleanerService).to receive(:new).exactly(:twice).and_call_original
+
+ execute
+
+ expect(loose_fk_child_table_1_1.count).to eq(0)
+ expect(loose_fk_child_table_1_2.where(parent_id_with_different_column: nil).count).to eq(4)
+ expect(loose_fk_child_table_2_1.count).to eq(0)
+ end
+ end
+
+ context 'when the amount of records to clean up exceeds the total MAX_DELETES' do
+ def count_deletable_rows
+ loose_fk_child_table_1_1.count + loose_fk_child_table_2_1.count
+ end
+
+ before do
+ stub_const('LooseForeignKeys::ModificationTracker::MAX_DELETES', 2)
+ stub_const('LooseForeignKeys::CleanerService::DELETE_LIMIT', 1)
+ end
+
+ it 'cleans up MAX_DELETES and leaves the rest for the next run' do
+ expect { execute }.to change { count_deletable_rows }.by(-2)
+ expect(count_deletable_rows).to be > 0
+ end
+
+ it 'records the Apdex as success: false' do
+ expect(::Gitlab::Metrics::LooseForeignKeysSlis).to receive(:record_apdex)
+ .with(success: false, db_config_name: 'main')
+
+ execute
+ end
+ end
+
+ context 'when cleanup raises an error' do
+ before do
+ expect_next_instance_of(::LooseForeignKeys::BatchCleanerService) do |service|
+ allow(service).to receive(:execute).and_raise("Something broke")
+ end
+ end
+
+ it 'records the error rate as error: true and does not increment apdex' do
+ expect(::Gitlab::Metrics::LooseForeignKeysSlis).to receive(:record_error_rate)
+ .with(error: true, db_config_name: 'main')
+ expect(::Gitlab::Metrics::LooseForeignKeysSlis).not_to receive(:record_apdex)
+
+ expect { execute }.to raise_error("Something broke")
+ end
+ end
+ end
+end
diff --git a/spec/services/markup/rendering_service_spec.rb b/spec/services/markup/rendering_service_spec.rb
new file mode 100644
index 00000000000..a5711a8cbc4
--- /dev/null
+++ b/spec/services/markup/rendering_service_spec.rb
@@ -0,0 +1,163 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Markup::RenderingService do
+ describe '#execute' do
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) do
+ user = create(:user, username: 'gfm')
+ project.add_maintainer(user)
+ user
+ end
+
+ let_it_be(:context) { { project: project } }
+ let_it_be(:postprocess_context) { { current_user: user } }
+
+ let(:file_name) { nil }
+ let(:text) { 'Noël' }
+
+ subject do
+ described_class
+ .new(text, file_name: file_name, context: context, postprocess_context: postprocess_context)
+ .execute
+ end
+
+ context 'when text is missing' do
+ let(:text) { nil }
+
+ it 'returns an empty string' do
+ is_expected.to eq('')
+ end
+ end
+
+ context 'when file_name is missing' do
+ it 'returns html (rendered by Banzai)' do
+ expected_html = '<p data-sourcepos="1:1-1:5" dir="auto">Noël</p>'
+
+ expect(Banzai).to receive(:render).with(text, context) { expected_html }
+
+ is_expected.to eq(expected_html)
+ end
+ end
+
+ context 'when postprocess_context is missing' do
+ let(:file_name) { 'foo.txt' }
+ let(:postprocess_context) { nil }
+
+ it 'returns html (rendered by Banzai)' do
+ expected_html = '<pre class="plain-readme">Noël</pre>'
+
+ expect(Banzai).not_to receive(:post_process) { expected_html }
+
+ is_expected.to eq(expected_html)
+ end
+ end
+
+ context 'when rendered context is present' do
+ let(:rendered) { 'rendered text' }
+ let(:file_name) { 'foo.md' }
+
+ it 'returns an empty string' do
+ context[:rendered] = rendered
+
+ is_expected.to eq(rendered)
+ end
+ end
+
+ context 'when file is a markdown file' do
+ let(:file_name) { 'foo.md' }
+
+ it 'returns html (rendered by Banzai)' do
+ expected_html = '<p data-sourcepos="1:1-1:5" dir="auto">Noël</p>'
+
+ expect(Banzai).to receive(:render).with(text, context) { expected_html }
+
+ is_expected.to eq(expected_html)
+ end
+
+ context 'when renderer returns an error' do
+ before do
+ allow(Banzai).to receive(:render).and_raise(StandardError, "An error")
+ end
+
+ it 'returns html (rendered by ActionView:TextHelper)' do
+ is_expected.to eq('<p>Noël</p>')
+ end
+
+ it 'logs the error' do
+ expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
+ instance_of(StandardError),
+ project_id: context[:project].id, file_name: 'foo.md'
+ )
+
+ subject
+ end
+ end
+ end
+
+ context 'when file is asciidoc file' do
+ let(:file_name) { 'foo.adoc' }
+
+ it 'returns html (rendered by Gitlab::Asciidoc)' do
+ expected_html = "<div>\n<p>Noël</p>\n</div>"
+
+ expect(Gitlab::Asciidoc).to receive(:render).with(text, context) { expected_html }
+
+ is_expected.to eq(expected_html)
+ end
+ end
+
+ context 'when file is a regular text file' do
+ let(:file_name) { 'foo.txt' }
+
+ it 'returns html (rendered by ActionView::TagHelper)' do
+ is_expected.to eq('<pre class="plain-readme">Noël</pre>')
+ end
+ end
+
+ context 'when file has an unknown type' do
+ let(:file_name) { 'foo.tex' }
+
+ it 'returns html (rendered by Gitlab::OtherMarkup)' do
+ expected_html = 'Noël'
+
+ expect(Gitlab::OtherMarkup).to receive(:render).with(file_name, text, context) { expected_html }
+
+ is_expected.to eq(expected_html)
+ end
+ end
+
+ context 'when rendering takes too long' do
+ let(:file_name) { 'foo.bar' }
+
+ before do
+ stub_const("Markup::RenderingService::RENDER_TIMEOUT", 0.1)
+ allow(Gitlab::OtherMarkup).to receive(:render) do
+ sleep(0.2)
+ text
+ end
+ end
+
+ it 'times out' do
+ expect(Gitlab::RenderTimeout).to receive(:timeout).and_call_original
+ expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
+ instance_of(Timeout::Error),
+ project_id: context[:project].id, file_name: file_name
+ )
+
+ is_expected.to eq("<p>#{text}</p>")
+ end
+
+ context 'when markup_rendering_timeout is disabled' do
+ it 'waits until the execution completes' do
+ stub_feature_flags(markup_rendering_timeout: false)
+
+ expect(Gitlab::RenderTimeout).not_to receive(:timeout)
+
+ is_expected.to eq(text)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb
index 8559c02be57..d0f009f1321 100644
--- a/spec/services/members/destroy_service_spec.rb
+++ b/spec/services/members/destroy_service_spec.rb
@@ -77,7 +77,7 @@ RSpec.describe Members::DestroyService do
end
end
- shared_examples 'a service destroying an access requester' do
+ shared_examples 'a service destroying an access request of another user' do
it_behaves_like 'a service destroying a member'
it 'calls Member#after_decline_request' do
@@ -85,12 +85,16 @@ RSpec.describe Members::DestroyService do
described_class.new(current_user).execute(member, **opts)
end
+ end
+
+ shared_examples 'a service destroying an access request of self' do
+ it_behaves_like 'a service destroying a member'
context 'when current user is the member' do
it 'does not call Member#after_decline_request' do
expect_any_instance_of(NotificationService).not_to receive(:decline_access_request).with(member)
- described_class.new(member_user).execute(member, **opts)
+ described_class.new(current_user).execute(member, **opts)
end
end
end
@@ -277,11 +281,24 @@ RSpec.describe Members::DestroyService do
group.add_owner(current_user)
end
- it_behaves_like 'a service destroying an access requester' do
+ it_behaves_like 'a service destroying an access request of another user' do
+ let(:member) { group_project.requesters.find_by(user_id: member_user.id) }
+ end
+
+ it_behaves_like 'a service destroying an access request of another user' do
+ let(:member) { group.requesters.find_by(user_id: member_user.id) }
+ end
+ end
+
+ context 'on withdrawing their own access request' do
+ let(:opts) { { skip_subresources: true } }
+ let(:current_user) { member_user }
+
+ it_behaves_like 'a service destroying an access request of self' do
let(:member) { group_project.requesters.find_by(user_id: member_user.id) }
end
- it_behaves_like 'a service destroying an access requester' do
+ it_behaves_like 'a service destroying an access request of self' do
let(:member) { group.requesters.find_by(user_id: member_user.id) }
end
end
diff --git a/spec/services/members/invite_service_spec.rb b/spec/services/members/invite_service_spec.rb
index 6dbe161ee02..23d4d671afc 100644
--- a/spec/services/members/invite_service_spec.rb
+++ b/spec/services/members/invite_service_spec.rb
@@ -12,7 +12,7 @@ RSpec.describe Members::InviteService, :aggregate_failures, :clean_gitlab_redis_
let(:params) { {} }
let(:base_params) { { access_level: Gitlab::Access::GUEST, source: project, invite_source: '_invite_source_' } }
- subject(:result) { described_class.new(user, base_params.merge(params) ).execute }
+ subject(:result) { described_class.new(user, base_params.merge(params)).execute }
context 'when there is a valid member invited' do
let(:params) { { email: 'email@example.org' } }
@@ -393,7 +393,7 @@ RSpec.describe Members::InviteService, :aggregate_failures, :clean_gitlab_redis_
context 'when email is already a member with a user on the project' do
let!(:existing_member) { create(:project_member, :guest, project: project) }
- let(:params) { { email: "#{existing_member.user.email}", access_level: ProjectMember::MAINTAINER } }
+ let(:params) { { email: existing_member.user.email.to_s, access_level: ProjectMember::MAINTAINER } }
it 'allows re-invite of an already invited email and updates the access_level' do
expect { result }.not_to change(ProjectMember, :count)
@@ -403,7 +403,7 @@ RSpec.describe Members::InviteService, :aggregate_failures, :clean_gitlab_redis_
context 'when email belongs to an existing user as a confirmed secondary email' do
let(:secondary_email) { create(:email, :confirmed, email: 'secondary@example.com', user: existing_member.user) }
- let(:params) { { email: "#{secondary_email.email}" } }
+ let(:params) { { email: secondary_email.email.to_s } }
it 'allows re-invite to an already invited email' do
expect_to_create_members(count: 0)
diff --git a/spec/services/members/update_service_spec.rb b/spec/services/members/update_service_spec.rb
index f919d6d1516..eb8fae03c39 100644
--- a/spec/services/members/update_service_spec.rb
+++ b/spec/services/members/update_service_spec.rb
@@ -3,18 +3,34 @@
require 'spec_helper'
RSpec.describe Members::UpdateService do
- let(:project) { create(:project, :public) }
- let(:group) { create(:group, :public) }
- let(:current_user) { create(:user) }
- let(:member_user) { create(:user) }
- let(:permission) { :update }
- let(:member) { source.members_and_requesters.find_by!(user_id: member_user.id) }
- let(:access_level) { Gitlab::Access::MAINTAINER }
- let(:params) do
- { access_level: access_level }
+ let_it_be(:project) { create(:project, :public) }
+ let_it_be(:group) { create(:group, :public) }
+ let_it_be(:current_user) { create(:user) }
+ let_it_be(:member_user1) { create(:user) }
+ let_it_be(:member_user2) { create(:user) }
+ let_it_be(:member_users) { [member_user1, member_user2] }
+ let_it_be(:permission) { :update }
+ let_it_be(:access_level) { Gitlab::Access::MAINTAINER }
+ let(:members) { source.members_and_requesters.where(user_id: member_users).to_a }
+ let(:update_service) { described_class.new(current_user, params) }
+ let(:params) { { access_level: access_level } }
+ let(:updated_members) do
+ result = subject
+ Array.wrap(result[:members] || result[:member])
end
- subject { described_class.new(current_user, params).execute(member, permission: permission) }
+ before do
+ member_users.first.tap do |member_user|
+ expires_at = 10.days.from_now
+ project.add_member(member_user, Gitlab::Access::DEVELOPER, expires_at: expires_at)
+ group.add_member(member_user, Gitlab::Access::DEVELOPER, expires_at: expires_at)
+ end
+
+ member_users[1..].each do |member_user|
+ project.add_developer(member_user)
+ group.add_developer(member_user)
+ end
+ end
shared_examples 'a service raising Gitlab::Access::AccessDeniedError' do
it 'raises Gitlab::Access::AccessDeniedError' do
@@ -23,164 +39,326 @@ RSpec.describe Members::UpdateService do
end
end
- shared_examples 'a service updating a member' do
- it 'updates the member' do
- expect(TodosDestroyer::EntityLeaveWorker).not_to receive(:perform_in).with(Todo::WAIT_FOR_DELETE, member.user_id, member.source_id, source.class.name)
+ shared_examples 'current user cannot update the given members' do
+ it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
+ let_it_be(:source) { project }
+ end
+
+ it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
+ let_it_be(:source) { group }
+ end
+ end
+
+ shared_examples 'returns error status when params are invalid' do
+ let_it_be(:params) { { expires_at: 2.days.ago } }
- updated_member = subject.fetch(:member)
+ specify do
+ expect(subject[:status]).to eq(:error)
+ end
+ end
- expect(updated_member).to be_valid
- expect(updated_member.access_level).to eq(access_level)
+ shared_examples 'a service updating members' do
+ it 'updates the members' do
+ new_access_levels = updated_members.map(&:access_level)
+
+ expect(updated_members).not_to be_empty
+ expect(updated_members).to all(be_valid)
+ expect(new_access_levels).to all(be access_level)
end
it 'returns success status' do
- result = subject.fetch(:status)
+ expect(subject.fetch(:status)).to eq(:success)
+ end
- expect(result).to eq(:success)
+ it 'invokes after_execute with correct args' do
+ members.each do |member|
+ expect(update_service).to receive(:after_execute).with(
+ action: permission,
+ old_access_level: member.human_access,
+ old_expiry: member.expires_at,
+ member: member
+ )
+ end
+
+ subject
end
- context 'when member is downgraded to guest' do
- shared_examples 'schedules to delete confidential todos' do
- it do
- expect(TodosDestroyer::EntityLeaveWorker).to receive(:perform_in).with(Todo::WAIT_FOR_DELETE, member.user_id, member.source_id, source.class.name).once
+ it 'authorization update callback is triggered' do
+ expect(members).to all(receive(:refresh_member_authorized_projects).once)
- updated_member = subject.fetch(:member)
+ subject
+ end
+
+ it 'does not enqueues todos for deletion' do
+ members.each do |member|
+ expect(TodosDestroyer::EntityLeaveWorker)
+ .not_to receive(:perform_in).with(Todo::WAIT_FOR_DELETE, member.user_id, member.source_id, source.class.name)
+ end
- expect(updated_member).to be_valid
- expect(updated_member.access_level).to eq(Gitlab::Access::GUEST)
+ subject
+ end
+
+ context 'when members are downgraded to guest' do
+ shared_examples 'schedules to delete confidential todos' do
+ it do
+ members.each do |member|
+ expect(TodosDestroyer::EntityLeaveWorker)
+ .to receive(:perform_in)
+ .with(Todo::WAIT_FOR_DELETE, member.user_id, member.source_id, source.class.name).once
+ end
+
+ new_access_levels = updated_members.map(&:access_level)
+ expect(updated_members).to all(be_valid)
+ expect(new_access_levels).to all(be Gitlab::Access::GUEST)
end
end
context 'with Gitlab::Access::GUEST level as a string' do
- let(:params) { { access_level: Gitlab::Access::GUEST.to_s } }
+ let_it_be(:params) { { access_level: Gitlab::Access::GUEST.to_s } }
it_behaves_like 'schedules to delete confidential todos'
end
context 'with Gitlab::Access::GUEST level as an integer' do
- let(:params) { { access_level: Gitlab::Access::GUEST } }
+ let_it_be(:params) { { access_level: Gitlab::Access::GUEST } }
it_behaves_like 'schedules to delete confidential todos'
end
end
context 'when access_level is invalid' do
- let(:params) { { access_level: 'invalid' } }
+ let_it_be(:params) { { access_level: 'invalid' } }
it 'raises an error' do
- expect { described_class.new(current_user, params) }.to raise_error(ArgumentError, 'invalid value for Integer(): "invalid"')
+ expect { described_class.new(current_user, params) }
+ .to raise_error(ArgumentError, 'invalid value for Integer(): "invalid"')
end
end
- context 'when member is not valid' do
- let(:params) { { expires_at: 2.days.ago } }
+ context 'when members update results in no change' do
+ let(:params) { { access_level: members.first.access_level } }
- it 'returns error status' do
- result = subject
+ it 'does not invoke update! and post_update' do
+ expect(update_service).not_to receive(:save!)
+ expect(update_service).not_to receive(:post_update)
- expect(result[:status]).to eq(:error)
+ expect(subject[:status]).to eq(:success)
end
- end
- end
-
- before do
- project.add_developer(member_user)
- group.add_developer(member_user)
- end
- context 'when current user cannot update the given member' do
- it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
- let(:source) { project }
- end
+ it 'authorization update callback is not triggered' do
+ members.each { |member| expect(member).not_to receive(:refresh_member_authorized_projects) }
- it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
- let(:source) { group }
+ subject
+ end
end
end
- context 'when current user can update the given member' do
+ shared_examples 'updating a project' do
+ let_it_be(:group_project) { create(:project, group: create(:group)) }
+ let_it_be(:source) { group_project }
+
before do
- project.add_maintainer(current_user)
- group.add_owner(current_user)
+ member_users.each { |member_user| group_project.add_developer(member_user) }
end
- it_behaves_like 'a service updating a member' do
- let(:source) { project }
- end
+ context 'as a project maintainer' do
+ before do
+ group_project.add_maintainer(current_user)
+ end
- it_behaves_like 'a service updating a member' do
- let(:source) { group }
- end
- end
+ it_behaves_like 'a service updating members'
- context 'in a project' do
- let_it_be(:group_project) { create(:project, group: create(:group)) }
+ context 'when member update results in an error' do
+ it_behaves_like 'a service returning an error'
+ end
- let(:source) { group_project }
+ context 'and updating members to OWNER' do
+ it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
+ let_it_be(:access_level) { Gitlab::Access::OWNER }
+ end
+ end
- context 'a project maintainer' do
- before do
- group_project.add_maintainer(current_user)
+ context 'and updating themselves to OWNER' do
+ let(:members) { source.members_and_requesters.find_by!(user_id: current_user.id) }
+
+ it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
+ let_it_be(:access_level) { Gitlab::Access::OWNER }
+ end
end
- context 'cannot update a member to OWNER' do
+ context 'and downgrading members from OWNER' do
before do
- group_project.add_developer(member_user)
+ member_users.each { |member_user| group_project.add_owner(member_user) }
end
it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
- let(:access_level) { Gitlab::Access::OWNER }
+ let_it_be(:access_level) { Gitlab::Access::MAINTAINER }
end
end
+ end
- context 'cannot update themselves to OWNER' do
- let(:member) { source.members_and_requesters.find_by!(user_id: current_user.id) }
+ context 'when current_user is considered an owner in the project via inheritance' do
+ before do
+ group_project.group.add_owner(current_user)
+ end
+ context 'and can update members to OWNER' do
before do
- group_project.add_developer(member_user)
+ member_users.each { |member_user| group_project.add_developer(member_user) }
end
- it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
- let(:access_level) { Gitlab::Access::OWNER }
+ it_behaves_like 'a service updating members' do
+ let_it_be(:access_level) { Gitlab::Access::OWNER }
end
end
- context 'cannot downgrade a member from OWNER' do
+ context 'and can downgrade members from OWNER' do
before do
- group_project.add_owner(member_user)
+ member_users.each { |member_user| group_project.add_owner(member_user) }
end
- it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
- let(:access_level) { Gitlab::Access::MAINTAINER }
+ it_behaves_like 'a service updating members' do
+ let_it_be(:access_level) { Gitlab::Access::MAINTAINER }
end
end
end
+ end
+
+ shared_examples 'updating a group' do
+ let_it_be(:source) { group }
+
+ before do
+ group.add_owner(current_user)
+ end
+
+ it_behaves_like 'a service updating members'
+
+ context 'when member update results in an error' do
+ it_behaves_like 'a service returning an error'
+ end
+
+ context 'when group members expiration date is updated' do
+ let_it_be(:params) { { expires_at: 20.days.from_now } }
+ let(:notification_service) { instance_double(NotificationService) }
- context 'owners' do
before do
- # so that `current_user` is considered an `OWNER` in the project via inheritance.
- group_project.group.add_owner(current_user)
+ allow(NotificationService).to receive(:new).and_return(notification_service)
end
- context 'can update a member to OWNER' do
- before do
- group_project.add_developer(member_user)
+ it 'emails the users that their group membership expiry has changed' do
+ members.each do |member|
+ expect(notification_service).to receive(:updated_group_member_expiration).with(member)
end
- it_behaves_like 'a service updating a member' do
- let(:access_level) { Gitlab::Access::OWNER }
- end
+ subject
end
+ end
+ end
- context 'can downgrade a member from OWNER' do
- before do
- group_project.add_owner(member_user)
+ context 'when :bulk_update_membership_roles feature flag is disabled' do
+ let(:member) { source.members_and_requesters.find_by!(user_id: member_user1.id) }
+ let(:members) { [member] }
+
+ subject { update_service.execute(member, permission: permission) }
+
+ shared_examples 'a service returning an error' do
+ before do
+ allow(member).to receive(:save) do
+ member.errors.add(:user_id)
+ member.errors.add(:access_level)
end
+ .and_return(false)
+ end
+
+ it_behaves_like 'returns error status when params are invalid'
+
+ it 'returns the error' do
+ response = subject
+
+ expect(response[:status]).to eq(:error)
+ expect(response[:message]).to eq('User is invalid and Access level is invalid')
+ end
+ end
+
+ before do
+ stub_feature_flags(bulk_update_membership_roles: false)
+ end
+
+ it_behaves_like 'current user cannot update the given members'
+ it_behaves_like 'updating a project'
+ it_behaves_like 'updating a group'
+ end
+
+ subject { update_service.execute(members, permission: permission) }
+
+ shared_examples 'a service returning an error' do
+ it_behaves_like 'returns error status when params are invalid'
- it_behaves_like 'a service updating a member' do
- let(:access_level) { Gitlab::Access::MAINTAINER }
+ context 'when a member update results in invalid record' do
+ let(:member2) { members.second }
+
+ before do
+ allow(member2).to receive(:save!) do
+ member2.errors.add(:user_id)
+ member2.errors.add(:access_level)
+ end.and_raise(ActiveRecord::RecordInvalid)
+ end
+
+ it 'returns the error' do
+ response = subject
+
+ expect(response[:status]).to eq(:error)
+ expect(response[:message]).to eq('User is invalid and Access level is invalid')
+ end
+
+ it 'rollbacks back the entire update' do
+ old_access_levels = members.pluck(:access_level)
+
+ subject
+
+ expect(members.each(&:reset).pluck(:access_level)).to eq(old_access_levels)
+ end
+ end
+ end
+
+ it_behaves_like 'current user cannot update the given members'
+ it_behaves_like 'updating a project'
+ it_behaves_like 'updating a group'
+
+ context 'with a single member' do
+ let(:member) { create(:group_member, group: group) }
+ let(:members) { member }
+
+ before do
+ group.add_owner(current_user)
+ end
+
+ it 'returns the correct response' do
+ expect(subject[:member]).to eq(member)
+ end
+ end
+
+ context 'when current user is an admin', :enable_admin_mode do
+ let_it_be(:current_user) { create(:admin) }
+ let_it_be(:source) { group }
+
+ context 'when all owners are being downgraded' do
+ before do
+ member_users.each { |member_user| group.add_owner(member_user) }
+ end
+
+ it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError'
+ end
+
+ context 'when all blocked owners are being downgraded' do
+ before do
+ member_users.each do |member_user|
+ group.add_owner(member_user)
+ member_user.block
end
end
+
+ it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError'
end
end
end
diff --git a/spec/services/merge_requests/approval_service_spec.rb b/spec/services/merge_requests/approval_service_spec.rb
index 0846ec7f50e..da6492aca95 100644
--- a/spec/services/merge_requests/approval_service_spec.rb
+++ b/spec/services/merge_requests/approval_service_spec.rb
@@ -33,9 +33,17 @@ RSpec.describe MergeRequests::ApprovalService do
service.execute(merge_request)
end
+ it_behaves_like 'does not trigger GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { service.execute(merge_request) }
+ end
+
it 'does not publish MergeRequests::ApprovedEvent' do
expect { service.execute(merge_request) }.not_to publish_event(MergeRequests::ApprovedEvent)
end
+
+ it_behaves_like 'does not trigger GraphQL subscription mergeRequestReviewersUpdated' do
+ let(:action) { service.execute(merge_request) }
+ end
end
context 'with an already approved MR' do
@@ -46,6 +54,14 @@ RSpec.describe MergeRequests::ApprovalService do
it 'does not create an approval' do
expect { service.execute(merge_request) }.not_to change { merge_request.approvals.size }
end
+
+ it_behaves_like 'does not trigger GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { service.execute(merge_request) }
+ end
+
+ it_behaves_like 'does not trigger GraphQL subscription mergeRequestReviewersUpdated' do
+ let(:action) { service.execute(merge_request) }
+ end
end
context 'with valid approval' do
@@ -67,6 +83,14 @@ RSpec.describe MergeRequests::ApprovalService do
.to publish_event(MergeRequests::ApprovedEvent)
.with(current_user_id: user.id, merge_request_id: merge_request.id)
end
+
+ it_behaves_like 'triggers GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { service.execute(merge_request) }
+ end
+
+ it_behaves_like 'triggers GraphQL subscription mergeRequestReviewersUpdated' do
+ let(:action) { service.execute(merge_request) }
+ end
end
context 'user cannot update the merge request' do
@@ -77,6 +101,14 @@ RSpec.describe MergeRequests::ApprovalService do
it 'does not update approvals' do
expect { service.execute(merge_request) }.not_to change { merge_request.approvals.size }
end
+
+ it_behaves_like 'does not trigger GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { service.execute(merge_request) }
+ end
+
+ it_behaves_like 'does not trigger GraphQL subscription mergeRequestReviewersUpdated' do
+ let(:action) { service.execute(merge_request) }
+ end
end
end
end
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
index 6a6f01e6a95..4f27ff30da7 100644
--- a/spec/services/merge_requests/build_service_spec.rb
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -93,7 +93,7 @@ RSpec.describe MergeRequests::BuildService do
shared_examples 'with a Default.md template' do
let(:files) { { '.gitlab/merge_request_templates/Default.md' => 'Default template contents' } }
- let(:project) { create(:project, :custom_repo, files: files ) }
+ let(:project) { create(:project, :custom_repo, files: files) }
it 'the template description is preferred' do
expect(merge_request.description).to eq('Default template contents')
@@ -306,7 +306,7 @@ RSpec.describe MergeRequests::BuildService do
context 'a Default.md template is defined' do
let(:files) { { '.gitlab/merge_request_templates/Default.md' => 'Default template contents' } }
- let(:project) { create(:project, :custom_repo, files: files ) }
+ let(:project) { create(:project, :custom_repo, files: files) }
it 'appends the closing description to a Default.md template' do
expected_description = ['Default template contents', closing_message].compact.join("\n\n")
@@ -386,7 +386,7 @@ RSpec.describe MergeRequests::BuildService do
context 'a Default.md template is defined' do
let(:files) { { '.gitlab/merge_request_templates/Default.md' => 'Default template contents' } }
- let(:project) { create(:project, :custom_repo, files: files ) }
+ let(:project) { create(:project, :custom_repo, files: files) }
it 'keeps the description from the initial params' do
expect(merge_request.description).to eq(description)
@@ -425,7 +425,7 @@ RSpec.describe MergeRequests::BuildService do
context 'a Default.md template is defined' do
let(:files) { { '.gitlab/merge_request_templates/Default.md' => 'Default template contents' } }
- let(:project) { create(:project, :custom_repo, files: files ) }
+ let(:project) { create(:project, :custom_repo, files: files) }
it 'appends the closing description to a Default.md template' do
expected_description = ['Default template contents', closing_message].compact.join("\n\n")
@@ -486,7 +486,7 @@ RSpec.describe MergeRequests::BuildService do
context 'a Default.md template is defined' do
let(:files) { { '.gitlab/merge_request_templates/Default.md' => 'Default template contents' } }
- let(:project) { create(:project, :custom_repo, files: files ) }
+ let(:project) { create(:project, :custom_repo, files: files) }
it 'appends the closing description to a Default.md template' do
expected_description = ['Default template contents', closing_message].compact.join("\n\n")
@@ -715,7 +715,7 @@ RSpec.describe MergeRequests::BuildService do
context 'when a Default template is found' do
context 'when its contents cannot be retrieved' do
let(:files) { { '.gitlab/merge_request_templates/OtherTemplate.md' => 'Other template contents' } }
- let(:project) { create(:project, :custom_repo, files: files ) }
+ let(:project) { create(:project, :custom_repo, files: files) }
it 'does not modify the merge request description' do
allow(TemplateFinder).to receive(:all_template_names).and_return({
@@ -732,7 +732,7 @@ RSpec.describe MergeRequests::BuildService do
context 'when its contents can be retrieved' do
let(:files) { { '.gitlab/merge_request_templates/Default.md' => 'Default template contents' } }
- let(:project) { create(:project, :custom_repo, files: files ) }
+ let(:project) { create(:project, :custom_repo, files: files) }
it 'modifies the merge request description' do
merge_request.description = nil
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index 0bc8258af42..da8e8d944d6 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -336,6 +336,12 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do
it_behaves_like 'reviewer_ids filter' do
let(:execute) { service.execute }
end
+
+ context 'when called in a transaction' do
+ it 'does not raise an error' do
+ expect { MergeRequest.transaction { described_class.new(project: project, current_user: user, params: opts).execute } }.not_to raise_error
+ end
+ end
end
it_behaves_like 'issuable record that supports quick actions' do
@@ -495,15 +501,40 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do
project.add_developer(user)
end
- it 'creates the merge request', :sidekiq_might_not_need_inline do
- expect_next_instance_of(MergeRequest) do |instance|
- expect(instance).to receive(:eager_fetch_ref!).and_call_original
+ context 'when async_merge_request_diff_creation is enabled' do
+ before do
+ stub_feature_flags(async_merge_request_diff_creation: true)
end
- merge_request = described_class.new(project: project, current_user: user, params: opts).execute
+ it 'creates the merge request', :sidekiq_inline do
+ expect_next_instance_of(MergeRequest) do |instance|
+ expect(instance).not_to receive(:eager_fetch_ref!)
+ end
- expect(merge_request).to be_persisted
- expect(merge_request.iid).to be > 0
+ merge_request = described_class.new(project: project, current_user: user, params: opts).execute
+
+ expect(merge_request).to be_persisted
+ expect(merge_request.iid).to be > 0
+ expect(merge_request.merge_request_diff).not_to be_empty
+ end
+ end
+
+ context 'when async_merge_request_diff_creation is disabled' do
+ before do
+ stub_feature_flags(async_merge_request_diff_creation: false)
+ end
+
+ it 'creates the merge request' do
+ expect_next_instance_of(MergeRequest) do |instance|
+ expect(instance).to receive(:eager_fetch_ref!).and_call_original
+ end
+
+ merge_request = described_class.new(project: project, current_user: user, params: opts).execute
+
+ expect(merge_request).to be_persisted
+ expect(merge_request.iid).to be > 0
+ expect(merge_request.merge_request_diff).not_to be_empty
+ end
end
it 'does not create the merge request when the target project is archived' do
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 cf34923795e..c56b38bccc1 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 do
+RSpec.describe MergeRequests::Mergeability::RunChecksService, :clean_gitlab_redis_cache do
subject(:run_checks) { described_class.new(merge_request: merge_request, params: {}) }
describe '#execute' do
@@ -104,18 +104,6 @@ RSpec.describe MergeRequests::Mergeability::RunChecksService do
expect(execute.success?).to eq(true)
end
end
-
- context 'when mergeability_caching is turned off' do
- before do
- stub_feature_flags(mergeability_caching: false)
- end
-
- it 'does not call the results store' do
- expect(Gitlab::MergeRequests::Mergeability::ResultsStore).not_to receive(:new)
-
- expect(execute.success?).to eq(true)
- end
- end
end
end
@@ -161,11 +149,11 @@ RSpec.describe MergeRequests::Mergeability::RunChecksService do
let_it_be(:merge_request) { create(:merge_request) }
context 'when the execute method has been executed' do
- before do
- run_checks.execute
- end
-
context 'when all the checks succeed' do
+ before do
+ run_checks.execute
+ end
+
it 'returns nil' do
expect(failure_reason).to eq(nil)
end
diff --git a/spec/services/merge_requests/mergeability_check_service_spec.rb b/spec/services/merge_requests/mergeability_check_service_spec.rb
index c24b83e21a6..ee23238314e 100644
--- a/spec/services/merge_requests/mergeability_check_service_spec.rb
+++ b/spec/services/merge_requests/mergeability_check_service_spec.rb
@@ -190,14 +190,6 @@ RSpec.describe MergeRequests::MergeabilityCheckService, :clean_gitlab_redis_shar
target_branch: 'conflict-start')
end
- it 'does not change the merge ref HEAD' do
- expect(merge_request.merge_ref_head).to be_nil
-
- subject
-
- expect(merge_request.reload.merge_ref_head).not_to be_nil
- end
-
it 'returns ServiceResponse.error and keeps merge status as cannot_be_merged' do
result = subject
@@ -351,27 +343,5 @@ RSpec.describe MergeRequests::MergeabilityCheckService, :clean_gitlab_redis_shar
end
end
end
-
- context 'merge with conflicts' do
- it 'calls MergeToRefService with true allow_conflicts param' do
- expect(MergeRequests::MergeToRefService).to receive(:new)
- .with(project: project, current_user: merge_request.author, params: { allow_conflicts: true }).and_call_original
-
- subject
- end
-
- context 'when display_merge_conflicts_in_diff is disabled' do
- before do
- stub_feature_flags(display_merge_conflicts_in_diff: false)
- end
-
- it 'calls MergeToRefService with false allow_conflicts param' do
- expect(MergeRequests::MergeToRefService).to receive(:new)
- .with(project: project, current_user: merge_request.author, params: { allow_conflicts: false }).and_call_original
-
- subject
- end
- end
- end
end
end
diff --git a/spec/services/merge_requests/remove_approval_service_spec.rb b/spec/services/merge_requests/remove_approval_service_spec.rb
index 5a319e90a68..7b38f0d1c45 100644
--- a/spec/services/merge_requests/remove_approval_service_spec.rb
+++ b/spec/services/merge_requests/remove_approval_service_spec.rb
@@ -45,6 +45,14 @@ RSpec.describe MergeRequests::RemoveApprovalService do
execute!
end
+
+ it_behaves_like 'triggers GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { execute! }
+ end
+
+ it_behaves_like 'triggers GraphQL subscription mergeRequestReviewersUpdated' do
+ let(:action) { execute! }
+ end
end
context 'with a user who has not approved' do
@@ -61,6 +69,14 @@ RSpec.describe MergeRequests::RemoveApprovalService do
execute!
end
+
+ it_behaves_like 'does not trigger GraphQL subscription mergeRequestMergeStatusUpdated' do
+ let(:action) { execute! }
+ end
+
+ it_behaves_like 'does not trigger GraphQL subscription mergeRequestReviewersUpdated' do
+ let(:action) { execute! }
+ end
end
end
end
diff --git a/spec/services/merge_requests/squash_service_spec.rb b/spec/services/merge_requests/squash_service_spec.rb
index 9210242a11e..471bb03f18c 100644
--- a/spec/services/merge_requests/squash_service_spec.rb
+++ b/spec/services/merge_requests/squash_service_spec.rb
@@ -3,8 +3,6 @@
require 'spec_helper'
RSpec.describe MergeRequests::SquashService do
- include GitHelpers
-
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) }
@@ -109,11 +107,10 @@ RSpec.describe MergeRequests::SquashService do
end
it 'has the same diff as the merge request, but a different SHA' do
- rugged = rugged_repo(project.repository)
- mr_diff = rugged.diff(merge_request.diff_base_sha, merge_request.diff_head_sha)
- squash_diff = rugged.diff(merge_request.diff_start_sha, squash_sha)
+ mr_diff = project.repository.diff(merge_request.diff_base_sha, merge_request.diff_head_sha)
+ squash_diff = project.repository.diff(merge_request.diff_start_sha, squash_sha)
- expect(squash_diff.patch.length).to eq(mr_diff.patch.length)
+ expect(squash_diff.size).to eq(mr_diff.size)
expect(squash_commit.sha).not_to eq(merge_request.diff_head_sha)
end
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index 1d67574b06d..da78f86c7c8 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -794,7 +794,7 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
end
it "does not try to mark as unchecked if it's already unchecked" do
- expect(merge_request).to receive(:unchecked?).and_return(true)
+ allow(merge_request).to receive(:unchecked?).twice.and_return(true)
expect(merge_request).not_to receive(:mark_as_unchecked)
update_merge_request({ target_branch: "target" })
@@ -1148,7 +1148,7 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
end
end
- include_examples 'issuable update service' do
+ it_behaves_like 'issuable update service' do
let(:open_issuable) { merge_request }
let(:closed_issuable) { create(:closed_merge_request, source_project: project) }
end
diff --git a/spec/services/milestones/transfer_service_spec.rb b/spec/services/milestones/transfer_service_spec.rb
index b15d90d685c..de02226661c 100644
--- a/spec/services/milestones/transfer_service_spec.rb
+++ b/spec/services/milestones/transfer_service_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Milestones::TransferService do
let(:new_group) { create(:group) }
let(:old_group) { create(:group) }
let(:project) { create(:project, namespace: old_group) }
- let(:group_milestone) { create(:milestone, group: old_group) }
+ let(:group_milestone) { create(:milestone, :closed, group: old_group) }
let(:group_milestone2) { create(:milestone, group: old_group) }
let(:project_milestone) { create(:milestone, project: project) }
let!(:issue_with_group_milestone) { create(:issue, project: project, milestone: group_milestone) }
@@ -38,6 +38,7 @@ RSpec.describe Milestones::TransferService do
expect(new_milestone).not_to eq(group_milestone)
expect(new_milestone.title).to eq(group_milestone.title)
expect(new_milestone.project_milestone?).to be_truthy
+ expect(new_milestone.state).to eq("closed")
end
context 'when milestone is from an ancestor group' do
@@ -88,6 +89,7 @@ RSpec.describe Milestones::TransferService do
expect(new_milestone).not_to eq(group_milestone)
expect(new_milestone.title).to eq(group_milestone.title)
expect(new_milestone.project_milestone?).to be_truthy
+ expect(new_milestone.state).to eq("closed")
end
it 'does not apply new project milestone to issuables with project milestone' do
diff --git a/spec/services/namespaces/statistics_refresher_service_spec.rb b/spec/services/namespaces/statistics_refresher_service_spec.rb
index d3379e843ec..2d5f9235bd4 100644
--- a/spec/services/namespaces/statistics_refresher_service_spec.rb
+++ b/spec/services/namespaces/statistics_refresher_service_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Namespaces::StatisticsRefresherService, '#execute' do
let(:group) { create(:group) }
+ let(:subgroup) { create(:group, parent: group) }
let(:projects) { create_list(:project, 5, namespace: group) }
let(:service) { described_class.new }
@@ -23,6 +24,14 @@ RSpec.describe Namespaces::StatisticsRefresherService, '#execute' do
service.execute(group)
end
+
+ context 'when given a subgroup' do
+ it 'does not create statistics for the subgroup' do
+ service.execute(subgroup)
+
+ expect(subgroup.reload.root_storage_statistics).not_to be_present
+ end
+ end
end
context 'with a root storage statistics relation', :sidekiq_might_not_need_inline do
@@ -43,6 +52,16 @@ RSpec.describe Namespaces::StatisticsRefresherService, '#execute' do
service.execute(group)
end
+
+ context 'when given a subgroup' do
+ it "recalculates the root namespace's statistics" do
+ expect(Namespace::RootStorageStatistics)
+ .to receive(:safe_find_or_create_by!).with({ namespace_id: group.id })
+ .and_return(group.root_storage_statistics)
+
+ service.execute(subgroup)
+ end
+ end
end
context 'when something goes wrong' do
diff --git a/spec/services/notes/build_service_spec.rb b/spec/services/notes/build_service_spec.rb
index c25895d2efa..67d8b37f809 100644
--- a/spec/services/notes/build_service_spec.rb
+++ b/spec/services/notes/build_service_spec.rb
@@ -189,13 +189,13 @@ RSpec.describe Notes::BuildService do
context 'issuable author' do
let(:user) { noteable_author }
- it_behaves_like 'user allowed to set comment as confidential'
+ it_behaves_like 'user not allowed to set comment as confidential'
end
context 'issuable assignee' do
let(:user) { issuable_assignee }
- it_behaves_like 'user allowed to set comment as confidential'
+ it_behaves_like 'user not allowed to set comment as confidential'
end
context 'admin' do
@@ -265,13 +265,13 @@ RSpec.describe Notes::BuildService do
context 'with noteable author' do
let(:user) { note.noteable.author }
- it_behaves_like 'confidential set to `true`'
+ it_behaves_like 'returns `Discussion to reply to cannot be found` error'
end
context 'with noteable assignee' do
let(:user) { issuable_assignee }
- it_behaves_like 'confidential set to `true`'
+ it_behaves_like 'returns `Discussion to reply to cannot be found` error'
end
context 'with guest access' do
diff --git a/spec/services/notes/update_service_spec.rb b/spec/services/notes/update_service_spec.rb
index 989ca7b8df1..05703ac548d 100644
--- a/spec/services/notes/update_service_spec.rb
+++ b/spec/services/notes/update_service_spec.rb
@@ -245,7 +245,7 @@ RSpec.describe Notes::UpdateService do
context 'for a personal snippet' do
let_it_be(:snippet) { create(:personal_snippet, :public) }
- let(:note) { create(:note, project: nil, noteable: snippet, author: user, note: "Note on a snippet with reference #{issue.to_reference}" ) }
+ let(:note) { create(:note, project: nil, noteable: snippet, author: user, note: "Note on a snippet with reference #{issue.to_reference}") }
it 'does not create todos' do
expect { update_note({ note: "Mentioning user #{user2}" }) }.not_to change { note.todos.count }
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 8fbf023cda0..7857bd2263f 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -211,6 +211,23 @@ RSpec.describe NotificationService, :mailer do
it_behaves_like 'participating by assignee notification'
end
+ describe '.permitted_actions' do
+ it 'includes public methods' do
+ expect(described_class.permitted_actions).to include(:access_token_created)
+ end
+
+ it 'excludes EXCLUDED_ACTIONS' do
+ described_class::EXCLUDED_ACTIONS.each do |action|
+ expect(described_class.permitted_actions).not_to include(action)
+ end
+ end
+
+ it 'excludes protected and private methods' do
+ expect(described_class.permitted_actions).not_to include(:new_resource_email)
+ expect(described_class.permitted_actions).not_to include(:approve_mr_email)
+ end
+ end
+
describe '#async' do
let(:async) { notification.async }
diff --git a/spec/services/packages/composer/composer_json_service_spec.rb b/spec/services/packages/composer/composer_json_service_spec.rb
index 378016a6ffb..d2187688c4c 100644
--- a/spec/services/packages/composer/composer_json_service_spec.rb
+++ b/spec/services/packages/composer/composer_json_service_spec.rb
@@ -9,7 +9,7 @@ RSpec.describe Packages::Composer::ComposerJsonService do
subject { described_class.new(project, target).execute }
context 'with an existing file' do
- let(:project) { create(:project, :custom_repo, files: { 'composer.json' => json } ) }
+ let(:project) { create(:project, :custom_repo, files: { 'composer.json' => json }) }
context 'with a valid file' do
let(:json) { '{ "name": "package-name"}' }
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 39c6feb5d12..70c2bbad87a 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
@@ -65,6 +65,23 @@ RSpec.describe ::Packages::Maven::Metadata::CreateVersionsXmlService do
let(:versions_in_database) { versions_in_xml + additional_versions }
it_behaves_like 'returning an xml with versions in the database'
+
+ context 'with an xml without a release version' do
+ let(:version_release) { nil }
+
+ it_behaves_like 'returning an xml with versions in the database'
+
+ it 'logs a warn with the reason' do
+ expect(Gitlab::AppJsonLogger).to receive(:warn).with(
+ message: 'A malformed metadata file has been encountered',
+ reason: 'Missing release tag',
+ project_id: package.project_id,
+ package_id: package.id
+ )
+
+ subject
+ end
+ end
end
end
diff --git a/spec/services/packages/npm/create_package_service_spec.rb b/spec/services/packages/npm/create_package_service_spec.rb
index a3e59913918..ef8cdf2e8ab 100644
--- a/spec/services/packages/npm/create_package_service_spec.rb
+++ b/spec/services/packages/npm/create_package_service_spec.rb
@@ -148,7 +148,7 @@ RSpec.describe Packages::Npm::CreatePackageService do
end
context 'when file size is faked by setting the attachment length param to a lower size' do
- let(:params) { super().deep_merge!( { _attachments: { "#{package_name}-#{version}.tgz" => { data: encoded_package_data, length: 1 } } }) }
+ let(:params) { super().deep_merge!({ _attachments: { "#{package_name}-#{version}.tgz" => { data: encoded_package_data, length: 1 } } }) }
# TODO (technical debt): Extract the package size calculation outside the service and add separate specs for it.
# Right now we have several contexts here to test the calculation's different scenarios.
@@ -193,7 +193,7 @@ RSpec.describe Packages::Npm::CreatePackageService do
end
context 'with empty versions' do
- let(:params) { super().merge!({ versions: {} } ) }
+ let(:params) { super().merge!({ versions: {} }) }
it { expect(subject[:http_status]).to eq 400 }
it { expect(subject[:message]).to eq 'Version is empty.' }
diff --git a/spec/services/packages/rpm/repository_metadata/base_builder_spec.rb b/spec/services/packages/rpm/repository_metadata/base_builder_spec.rb
deleted file mode 100644
index 524c224177b..00000000000
--- a/spec/services/packages/rpm/repository_metadata/base_builder_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-# frozen_string_literal: true
-require 'spec_helper'
-
-RSpec.describe Packages::Rpm::RepositoryMetadata::BaseBuilder do
- describe '#execute' do
- subject { described_class.new(xml: xml, data: data).execute }
-
- let(:xml) { nil }
- let(:data) { {} }
-
- before do
- stub_const("#{described_class}::ROOT_TAG", 'test')
- stub_const("#{described_class}::ROOT_ATTRIBUTES", { foo1: 'bar1', foo2: 'bar2' })
- end
-
- it 'generate valid xml' do
- result = Nokogiri::XML::Document.parse(subject)
-
- expect(result.children.count).to eq(1)
- expect(result.children.first.attributes.count).to eq(2)
- expect(result.children.first.attributes['foo1'].value).to eq('bar1')
- expect(result.children.first.attributes['foo2'].value).to eq('bar2')
- end
-
- context 'when call with parameters' do
- let(:xml) { 'test' }
-
- it 'raise NotImplementedError' do
- expect { subject }.to raise_error NotImplementedError
- end
- end
- end
-end
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
new file mode 100644
index 00000000000..d93d6ab9fcb
--- /dev/null
+++ b/spec/services/packages/rpm/repository_metadata/build_filelist_xml_service_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Packages::Rpm::RepositoryMetadata::BuildFilelistXmlService do
+ describe '#execute' do
+ subject { described_class.new(data).execute }
+
+ include_context 'with rpm package data'
+
+ let(:data) { xml_update_params }
+ let(:file_xpath) { "//package/file" }
+
+ it 'adds all file nodes' do
+ result = subject
+
+ expect(result.xpath(file_xpath).count).to eq(data[:files].count)
+ end
+
+ describe 'setting type attribute' do
+ context 'when all files are directories' do
+ let(:dirs) do
+ 3.times.map { generate_directory } # rubocop:disable Performance/TimesMap
+ end
+
+ let(:files) do
+ 5.times.map { FFaker::Filesystem.file_name(dirs.sample) } # rubocop:disable Performance/TimesMap
+ end
+
+ let(:data) do
+ {
+ directories: dirs.map { "#{_1}/" }, # Add trailing slash as in original package
+ files: dirs + files
+ }
+ end
+
+ it 'set dir type attribute for directories only' do
+ result = subject
+
+ result.xpath(file_xpath).each do |tag|
+ if dirs.include?(tag.content)
+ expect(tag.attributes['type']&.value).to eq('dir')
+ else
+ expect(tag.attributes['type']).to be_nil
+ end
+ end
+ end
+ end
+
+ def generate_directory
+ FFaker::Lorem.words(3).join('/')
+ end
+ end
+ end
+end
diff --git a/spec/services/packages/rpm/repository_metadata/build_filelist_xml_spec.rb b/spec/services/packages/rpm/repository_metadata/build_filelist_xml_spec.rb
deleted file mode 100644
index 2feb44c7c1b..00000000000
--- a/spec/services/packages/rpm/repository_metadata/build_filelist_xml_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-require 'spec_helper'
-
-RSpec.describe Packages::Rpm::RepositoryMetadata::BuildFilelistXml do
- describe '#execute' do
- subject { described_class.new.execute }
-
- context "when generate empty xml" do
- let(:expected_xml) do
- <<~XML
- <?xml version="1.0" encoding="UTF-8"?>
- <filelists xmlns="http://linux.duke.edu/metadata/filelists" packages="0"/>
- XML
- end
-
- it 'generate expected xml' do
- expect(subject).to eq(expected_xml)
- end
- end
- end
-end
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
new file mode 100644
index 00000000000..201f9e67ce9
--- /dev/null
+++ b/spec/services/packages/rpm/repository_metadata/build_other_xml_service_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Packages::Rpm::RepositoryMetadata::BuildOtherXmlService do
+ describe '#execute' do
+ subject { described_class.new(data).execute }
+
+ include_context 'with rpm package data'
+
+ let(:data) { xml_update_params }
+ let(:changelog_xpath) { "//package/changelog" }
+
+ it 'adds all changelog nodes' do
+ result = subject
+
+ expect(result.xpath(changelog_xpath).count).to eq(data[:changelogs].count)
+ end
+
+ it 'set required date attribute' do
+ result = subject
+
+ data[:changelogs].each do |changelog|
+ expect(result.at("#{changelog_xpath}[@date=\"#{changelog[:changelogtime]}\"]")).not_to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/services/packages/rpm/repository_metadata/build_other_xml_spec.rb b/spec/services/packages/rpm/repository_metadata/build_other_xml_spec.rb
deleted file mode 100644
index 823aa18808a..00000000000
--- a/spec/services/packages/rpm/repository_metadata/build_other_xml_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-require 'spec_helper'
-
-RSpec.describe Packages::Rpm::RepositoryMetadata::BuildOtherXml do
- describe '#execute' do
- subject { described_class.new.execute }
-
- context "when generate empty xml" do
- let(:expected_xml) do
- <<~XML
- <?xml version="1.0" encoding="UTF-8"?>
- <otherdata xmlns="http://linux.duke.edu/metadata/other" packages="0"/>
- XML
- end
-
- it 'generate expected xml' do
- expect(subject).to eq(expected_xml)
- end
- end
- end
-end
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
new file mode 100644
index 00000000000..9bbfa5c9863
--- /dev/null
+++ b/spec/services/packages/rpm/repository_metadata/build_primary_xml_service_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Packages::Rpm::RepositoryMetadata::BuildPrimaryXmlService do
+ describe '#execute' do
+ subject { described_class.new(data).execute }
+
+ include_context 'with rpm package data'
+
+ let(:data) { xml_update_params }
+ let(:required_text_only_attributes) { %i[description summary arch name] }
+
+ it 'adds node with required_text_only_attributes' do
+ result = subject
+
+ required_text_only_attributes.each do |attribute|
+ expect(
+ result.at("//package/#{attribute}").text
+ ).to eq(data[attribute])
+ end
+ end
+ end
+end
diff --git a/spec/services/packages/rpm/repository_metadata/build_primary_xml_spec.rb b/spec/services/packages/rpm/repository_metadata/build_primary_xml_spec.rb
deleted file mode 100644
index 147d5862a71..00000000000
--- a/spec/services/packages/rpm/repository_metadata/build_primary_xml_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# frozen_string_literal: true
-require 'spec_helper'
-
-RSpec.describe Packages::Rpm::RepositoryMetadata::BuildPrimaryXml do
- describe '#execute' do
- subject { described_class.new(xml: xml, data: data).execute }
-
- let(:empty_xml) do
- <<~XML
- <?xml version="1.0" encoding="UTF-8"?>
- <metadata xmlns="http://linux.duke.edu/metadata/common" xmlns:rpm="http://linux.duke.edu/metadata/rpm" packages="0"/>
- XML
- end
-
- it_behaves_like 'handling rpm xml file'
-
- context 'when updating existing xml' do
- include_context 'with rpm package data'
-
- let(:xml) { empty_xml }
- let(:data) { xml_update_params }
- let(:required_text_only_attributes) { %i[description summary arch name] }
-
- it 'adds node with required_text_only_attributes' do
- result = Nokogiri::XML::Document.parse(subject).remove_namespaces!
-
- required_text_only_attributes.each do |attribute|
- expect(
- result.at("//#{described_class::ROOT_TAG}/package/#{attribute}").text
- ).to eq(data[attribute])
- end
- end
- end
- end
-end
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
new file mode 100644
index 00000000000..cf28301fa2c
--- /dev/null
+++ b/spec/services/packages/rpm/repository_metadata/build_repomd_xml_service_spec.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Packages::Rpm::RepositoryMetadata::BuildRepomdXmlService do
+ describe '#execute' do
+ subject { described_class.new(data).execute }
+
+ let(:data) do
+ {
+ filelists: {
+ checksum: { type: "sha256", value: "123" },
+ 'open-checksum': { type: "sha256", value: "123" },
+ location: { href: "repodata/123-filelists.xml.gz" },
+ timestamp: { value: 1644602784 },
+ size: { value: 11111 },
+ 'open-size': { value: 11111 }
+ },
+ primary: {
+ checksum: { type: "sha256", value: "234" },
+ 'open-checksum': { type: "sha256", value: "234" },
+ location: { href: "repodata/234-primary.xml.gz" },
+ timestamp: { value: 1644602784 },
+ size: { value: 22222 },
+ 'open-size': { value: 22222 }
+ },
+ other: {
+ checksum: { type: "sha256", value: "345" },
+ 'open-checksum': { type: "sha256", value: "345" },
+ location: { href: "repodata/345-other.xml.gz" },
+ timestamp: { value: 1644602784 },
+ size: { value: 33333 },
+ 'open-size': { value: 33333 }
+ }
+ }
+ end
+
+ let(:creation_timestamp) { 111111 }
+
+ before do
+ allow(Time).to receive(:now).and_return(creation_timestamp)
+ end
+
+ it 'generate valid xml' do
+ # Have one root attribute
+ result = Nokogiri::XML::Document.parse(subject)
+ expect(result.children.count).to eq(1)
+
+ # Root attribute name is 'repomd'
+ root = result.children.first
+ expect(root.name).to eq('repomd')
+
+ # Have the same count of 'data' tags as count of keys in 'data'
+ expect(result.css('data').count).to eq(data.count)
+ end
+
+ it 'has all data info' do
+ result = Nokogiri::XML::Document.parse(subject).remove_namespaces!
+
+ data.each do |tag_name, tag_attributes|
+ tag_attributes.each_key do |key|
+ expect(result.at("//repomd/data[@type=\"#{tag_name}\"]/#{key}")).not_to be_nil
+ end
+ end
+ end
+
+ context 'when data values has unexpected keys' do
+ let(:data) do
+ {
+ filelists: described_class::ALLOWED_DATA_VALUE_KEYS.each_with_object({}) do |key, result|
+ result[:"#{key}-wrong"] = { value: 'value' }
+ end
+ }
+ end
+
+ it 'ignores wrong keys' do
+ result = Nokogiri::XML::Document.parse(subject).remove_namespaces!
+
+ data.each do |tag_name, tag_attributes|
+ tag_attributes.each_key do |key|
+ expect(result.at("//repomd/data[@type=\"#{tag_name}\"]/#{key}")).to be_nil
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/packages/rpm/repository_metadata/build_repomd_xml_spec.rb b/spec/services/packages/rpm/repository_metadata/build_repomd_xml_spec.rb
deleted file mode 100644
index 0843a983b7e..00000000000
--- a/spec/services/packages/rpm/repository_metadata/build_repomd_xml_spec.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-# frozen_string_literal: true
-require 'spec_helper'
-
-RSpec.describe Packages::Rpm::RepositoryMetadata::BuildRepomdXml do
- describe '#execute' do
- subject { described_class.new(data).execute }
-
- let(:data) do
- {
- filelists: {
- checksum: { type: "sha256", value: "123" },
- 'open-checksum': { type: "sha256", value: "123" },
- location: { href: "repodata/123-filelists.xml.gz" },
- timestamp: { value: 1644602784 },
- size: { value: 11111 },
- 'open-size': { value: 11111 }
- },
- primary: {
- checksum: { type: "sha256", value: "234" },
- 'open-checksum': { type: "sha256", value: "234" },
- location: { href: "repodata/234-primary.xml.gz" },
- timestamp: { value: 1644602784 },
- size: { value: 22222 },
- 'open-size': { value: 22222 }
- },
- other: {
- checksum: { type: "sha256", value: "345" },
- 'open-checksum': { type: "sha256", value: "345" },
- location: { href: "repodata/345-other.xml.gz" },
- timestamp: { value: 1644602784 },
- size: { value: 33333 },
- 'open-size': { value: 33333 }
- }
- }
- end
-
- let(:creation_timestamp) { 111111 }
-
- before do
- allow(Time).to receive(:now).and_return(creation_timestamp)
- end
-
- it 'generate valid xml' do
- # Have one root attribute
- result = Nokogiri::XML::Document.parse(subject)
- expect(result.children.count).to eq(1)
-
- # Root attribute name is 'repomd'
- root = result.children.first
- expect(root.name).to eq('repomd')
-
- # Have the same count of 'data' tags as count of keys in 'data'
- expect(result.css('data').count).to eq(data.count)
- end
-
- it 'has all data info' do
- result = Nokogiri::XML::Document.parse(subject).remove_namespaces!
-
- data.each do |tag_name, tag_attributes|
- tag_attributes.each_key do |key|
- expect(result.at("//repomd/data[@type=\"#{tag_name}\"]/#{key}")).not_to be_nil
- end
- end
- end
-
- context 'when data values has unexpected keys' do
- let(:data) do
- {
- filelists: described_class::ALLOWED_DATA_VALUE_KEYS.each_with_object({}) do |key, result|
- result[:"#{key}-wrong"] = { value: 'value' }
- end
- }
- end
-
- it 'ignores wrong keys' do
- result = Nokogiri::XML::Document.parse(subject).remove_namespaces!
-
- data.each do |tag_name, tag_attributes|
- tag_attributes.each_key do |key|
- expect(result.at("//repomd/data[@type=\"#{tag_name}\"]/#{key}")).to be_nil
- end
- end
- end
- end
- end
-end
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
new file mode 100644
index 00000000000..e351392ba1c
--- /dev/null
+++ b/spec/services/packages/rpm/repository_metadata/update_xml_service_spec.rb
@@ -0,0 +1,177 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Packages::Rpm::RepositoryMetadata::UpdateXmlService do
+ describe '#execute' do
+ subject { described_class.new(filename: filename, xml: xml, data: data).execute }
+
+ let(:xml) { nil }
+ let(:data) { nil }
+
+ shared_examples 'handling not implemented xml filename' do
+ let(:filename) { :not_implemented_yet }
+ let(:empty_xml) { '' }
+
+ it 'raise error' do
+ expect { subject }.to raise_error(ArgumentError)
+ end
+ end
+
+ shared_context 'with primary xml file data' do
+ let(:filename) { :primary }
+ let(:empty_xml) do
+ <<~XML
+ <?xml version="1.0" encoding="UTF-8"?>
+ <metadata xmlns="http://linux.duke.edu/metadata/common" xmlns:rpm="http://linux.duke.edu/metadata/rpm" packages="0"/>
+ XML
+ end
+ end
+
+ shared_context 'with other xml file data' do
+ let(:filename) { :other }
+ let(:empty_xml) do
+ <<~XML
+ <?xml version="1.0" encoding="UTF-8"?>
+ <otherdata xmlns="http://linux.duke.edu/metadata/other" packages="0"/>
+ XML
+ end
+ end
+
+ shared_context 'with filelist xml file data' do
+ let(:filename) { :filelist }
+ let(:empty_xml) do
+ <<~XML
+ <?xml version="1.0" encoding="UTF-8"?>
+ <filelists xmlns="http://linux.duke.edu/metadata/filelists" packages="0"/>
+ XML
+ end
+ end
+
+ context 'when building empty xml' do
+ shared_examples 'generating empty xml' do
+ it 'generate expected xml' do
+ expect(subject).to eq(empty_xml)
+ end
+ end
+
+ it_behaves_like 'handling not implemented xml filename'
+
+ context "for 'primary' xml file" do
+ include_context 'with primary xml file data'
+
+ it_behaves_like 'generating empty xml'
+ end
+
+ context "for 'other' xml file" do
+ include_context 'with other xml file data'
+
+ it_behaves_like 'generating empty xml'
+ end
+
+ context "for 'filelist' xml file" do
+ include_context 'with filelist xml file data'
+
+ it_behaves_like 'generating empty xml'
+ end
+ end
+
+ context 'when updating xml file' do
+ include_context 'with rpm package data'
+
+ let(:xml) { empty_xml }
+ let(:data) { xml_update_params }
+ let(:builder_class) { described_class::BUILDERS[filename] }
+
+ shared_examples 'updating rpm xml file' do
+ context 'when updating existing xml' do
+ shared_examples 'changing root tag attribute' do
+ it "increment previous 'packages' value by 1" do
+ previous_value = Nokogiri::XML(xml).at(builder_class::ROOT_TAG).attributes["packages"].value.to_i
+ new_value = Nokogiri::XML(subject).at(builder_class::ROOT_TAG).attributes["packages"].value.to_i
+
+ expect(previous_value + 1).to eq(new_value)
+ end
+ end
+
+ it 'generate valid xml add expected xml node to existing xml' do
+ # Have one root attribute
+ result = Nokogiri::XML::Document.parse(subject).remove_namespaces!
+ expect(result.children.count).to eq(1)
+
+ # Root node has 1 child with generated node
+ expect(result.xpath("//#{builder_class::ROOT_TAG}/package").count).to eq(1)
+ end
+
+ context 'when empty xml' do
+ it_behaves_like 'changing root tag attribute'
+ end
+
+ context 'when xml has children' do
+ context "when node with given 'pkgid' does not exist yet" do
+ let(:uniq_node_data) do
+ xml_update_params.tap do |data|
+ data[:pkgid] = SecureRandom.uuid
+ end
+ end
+
+ let(:xml) { build_xml_from(uniq_node_data) }
+
+ it 'has children nodes' do
+ existing_xml = Nokogiri::XML::Document.parse(xml).remove_namespaces!
+ expect(existing_xml.xpath('//package').count).to eq(1)
+ end
+
+ it_behaves_like 'changing root tag attribute'
+ end
+
+ context "when node with given 'pkgid' already exist" do
+ let(:existing_node_data) do
+ existing_data = data.dup
+ existing_data[:name] = FFaker::Lorem.word
+ existing_data
+ end
+
+ let(:xml) { build_xml_from(existing_node_data) }
+
+ it 'has children nodes' do
+ existing_xml = Nokogiri::XML::Document.parse(xml).remove_namespaces!
+ expect(existing_xml.xpath('//package').count).to eq(1)
+ end
+
+ it 'replace existing node with new data' do
+ existing_xml = Nokogiri::XML::Document.parse(xml).remove_namespaces!
+ result = Nokogiri::XML::Document.parse(subject).remove_namespaces!
+ expect(result.xpath('//package').count).to eq(1)
+ expect(result.xpath('//package').first.to_xml).not_to eq(existing_xml.xpath('//package').first.to_xml)
+ end
+ end
+
+ def build_xml_from(data)
+ described_class.new(filename: filename, xml: empty_xml, data: data).execute
+ end
+ end
+ end
+ end
+
+ it_behaves_like 'handling not implemented xml filename'
+
+ context "for 'primary' xml file" do
+ include_context 'with primary xml file data'
+
+ it_behaves_like 'updating rpm xml file'
+ end
+
+ context "for 'other' xml file" do
+ include_context 'with other xml file data'
+
+ it_behaves_like 'updating rpm xml file'
+ end
+
+ context "for 'filelist' xml file" do
+ include_context 'with filelist xml file data'
+
+ it_behaves_like 'updating rpm xml file'
+ end
+ end
+ end
+end
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 65da1976dc2..eb8d94ebfa5 100644
--- a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
+++ b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb
@@ -3,8 +3,6 @@
require 'spec_helper'
RSpec.describe Projects::HashedStorage::MigrateRepositoryService do
- include GitHelpers
-
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/lfs_pointers/lfs_download_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb
index b67b4d64c1d..6c7164c5e06 100644
--- a/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb
+++ b/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb
@@ -126,7 +126,7 @@ RSpec.describe Projects::LfsPointers::LfsDownloadService do
let(:redirect_link) { 'http://external-link' }
before do
- stub_full_request(download_link).to_return(status: 301, body: 'You are being redirected', headers: { 'Location' => redirect_link } )
+ stub_full_request(download_link).to_return(status: 301, body: 'You are being redirected', headers: { 'Location' => redirect_link })
stub_full_request(redirect_link).to_return(body: lfs_content)
end
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 0f766ebd0ec..b580d3d8772 100644
--- a/spec/services/projects/move_users_star_projects_service_spec.rb
+++ b/spec/services/projects/move_users_star_projects_service_spec.rb
@@ -15,6 +15,9 @@ RSpec.describe Projects::MoveUsersStarProjectsService do
end
it 'moves the user\'s stars from one project to another' do
+ project_with_stars.reload
+ target_project.reload
+
expect(project_with_stars.users_star_projects.count).to eq 2
expect(project_with_stars.star_count).to eq 2
expect(target_project.users_star_projects.count).to eq 0
@@ -34,6 +37,8 @@ RSpec.describe Projects::MoveUsersStarProjectsService do
allow(subject).to receive(:success).and_raise(StandardError)
expect { subject.execute(project_with_stars) }.to raise_error(StandardError)
+ project_with_stars.reload
+ target_project.reload
expect(project_with_stars.users_star_projects.count).to eq 2
expect(project_with_stars.star_count).to eq 2
diff --git a/spec/services/projects/prometheus/alerts/notify_service_spec.rb b/spec/services/projects/prometheus/alerts/notify_service_spec.rb
index 7bf6dfd0fd8..43d23023d83 100644
--- a/spec/services/projects/prometheus/alerts/notify_service_spec.rb
+++ b/spec/services/projects/prometheus/alerts/notify_service_spec.rb
@@ -244,9 +244,10 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
end
shared_examples 'process truncated alerts' do
- it 'returns 200 but skips processing and logs a warning', :aggregate_failures do
+ it 'returns 201 but skips processing and logs a warning', :aggregate_failures do
expect(subject).to be_success
- expect(subject.payload[:alerts].size).to eq(max_alerts)
+ expect(subject.payload).to eq({})
+ expect(subject.http_status).to eq(:created)
expect(Gitlab::AppLogger)
.to have_received(:warn)
.with(
@@ -260,9 +261,10 @@ RSpec.describe Projects::Prometheus::Alerts::NotifyService do
end
shared_examples 'process all alerts' do
- it 'returns 200 and process alerts without warnings', :aggregate_failures do
+ it 'returns 201 and process alerts without warnings', :aggregate_failures do
expect(subject).to be_success
- expect(subject.payload[:alerts].size).to eq(2)
+ expect(subject.payload).to eq({})
+ expect(subject.http_status).to eq(:created)
expect(Gitlab::AppLogger).not_to have_received(:warn)
end
end
diff --git a/spec/services/protected_branches/api_service_spec.rb b/spec/services/protected_branches/api_service_spec.rb
new file mode 100644
index 00000000000..94484f5a7b9
--- /dev/null
+++ b/spec/services/protected_branches/api_service_spec.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ProtectedBranches::ApiService do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user, maintainer_projects: [project]) }
+
+ it 'creates a protected branch with prefilled defaults' do
+ expect(::ProtectedBranches::CreateService).to receive(:new).with(
+ project, user, hash_including(
+ push_access_levels_attributes: [{ access_level: Gitlab::Access::MAINTAINER }],
+ merge_access_levels_attributes: [{ access_level: Gitlab::Access::MAINTAINER }]
+ )
+ ).and_call_original
+
+ expect(described_class.new(project, user, { name: 'new name' }).create).to be_valid
+ end
+
+ it 'updates a protected branch without prefilled defaults' do
+ protected_branch = create(:protected_branch, project: project, allow_force_push: true)
+
+ expect(::ProtectedBranches::UpdateService).to receive(:new).with(
+ project, user, hash_including(
+ push_access_levels_attributes: [],
+ merge_access_levels_attributes: []
+ )
+ ).and_call_original
+
+ expect do
+ expect(described_class.new(project, user, { name: 'new name' }).update(protected_branch)).to be_valid
+ end.not_to change { protected_branch.reload.allow_force_push }
+ end
+end
diff --git a/spec/services/protected_branches/cache_service_spec.rb b/spec/services/protected_branches/cache_service_spec.rb
index 00d1e8b5457..d7a3258160b 100644
--- a/spec/services/protected_branches/cache_service_spec.rb
+++ b/spec/services/protected_branches/cache_service_spec.rb
@@ -111,5 +111,16 @@ RSpec.describe ProtectedBranches::CacheService, :clean_gitlab_redis_cache do
expect(service.fetch('not-found') { true }).to eq(true)
end
end
+
+ describe 'metrics' do
+ it 'records hit ratio metrics' do
+ expect_next_instance_of(Gitlab::Cache::Metrics) do |metrics|
+ expect(metrics).to receive(:increment_cache_miss).once
+ expect(metrics).to receive(:increment_cache_hit).exactly(4).times
+ end
+
+ 5.times { service.fetch('main') { true } }
+ end
+ end
end
# rubocop:enable Style/RedundantFetchBlock
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index a43f3bc55bf..f9c16c84121 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -1450,6 +1450,11 @@ RSpec.describe QuickActions::InterpretService do
let(:issuable) { issue }
end
+ it_behaves_like 'estimate command' do
+ let(:content) { '/estimate_time 1h' }
+ let(:issuable) { issue }
+ end
+
it_behaves_like 'failed command' do
let(:content) { '/estimate' }
let(:issuable) { issue }
@@ -1470,6 +1475,11 @@ RSpec.describe QuickActions::InterpretService do
let(:issuable) { issue }
end
+ it_behaves_like 'spend command' do
+ let(:content) { '/spend_time 1h' }
+ let(:issuable) { issue }
+ end
+
it_behaves_like 'spend command with negative time' do
let(:content) { '/spend -120m' }
let(:issuable) { issue }
@@ -1537,6 +1547,11 @@ RSpec.describe QuickActions::InterpretService do
let(:issuable) { issue }
end
+ it_behaves_like 'remove_estimate command' do
+ let(:content) { '/remove_time_estimate' }
+ let(:issuable) { issue }
+ end
+
it_behaves_like 'remove_time_spent command' do
let(:content) { '/remove_time_spent' }
let(:issuable) { issue }
diff --git a/spec/services/resource_access_tokens/revoke_service_spec.rb b/spec/services/resource_access_tokens/revoke_service_spec.rb
index 8f89696cc55..28f173f1bc7 100644
--- a/spec/services/resource_access_tokens/revoke_service_spec.rb
+++ b/spec/services/resource_access_tokens/revoke_service_spec.rb
@@ -29,35 +29,13 @@ RSpec.describe ResourceAccessTokens::RevokeService do
expect(resource.reload.users).not_to include(resource_bot)
end
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- it 'initiates user removal' do
- subject
-
- expect(
- Users::GhostUserMigration.where(user: resource_bot,
- initiator_user: user)
- ).to be_exists
- end
- end
-
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
- end
-
- it 'transfer issuables of bot user to ghost user' do
- issue = create(:issue, author: resource_bot)
-
- subject
-
- expect(issue.reload.author.ghost?).to be true
- end
-
- it 'deletes project bot user' do
- subject
+ it 'initiates user removal' do
+ subject
- expect(User.exists?(resource_bot.id)).to be_falsy
- end
+ expect(
+ Users::GhostUserMigration.where(user: resource_bot,
+ initiator_user: user)
+ ).to be_exists
end
it 'logs the event' do
diff --git a/spec/services/resource_events/change_milestone_service_spec.rb b/spec/services/resource_events/change_milestone_service_spec.rb
index ed234376381..425d5b19907 100644
--- a/spec/services/resource_events/change_milestone_service_spec.rb
+++ b/spec/services/resource_events/change_milestone_service_spec.rb
@@ -14,4 +14,35 @@ RSpec.describe ResourceEvents::ChangeMilestoneService do
let_it_be(:resource) { create(issuable) } # rubocop:disable Rails/SaveBang
end
end
+
+ describe 'events tracking' do
+ let_it_be(:user) { create(:user) }
+
+ let(:resource) { create(resource_type, milestone: timebox, project: timebox.project) }
+
+ subject(:service_instance) { described_class.new(resource, user, old_milestone: nil) }
+
+ context 'when the resource is a work item' do
+ let(:resource_type) { :work_item }
+
+ it 'tracks work item usage data counters' do
+ expect(Gitlab::UsageDataCounters::WorkItemActivityUniqueCounter)
+ .to receive(:track_work_item_milestone_changed_action)
+ .with(author: user)
+
+ service_instance.execute
+ end
+ end
+
+ context 'when the resource is not a work item' do
+ let(:resource_type) { :issue }
+
+ it 'does not track work item usage data counters' do
+ expect(Gitlab::UsageDataCounters::WorkItemActivityUniqueCounter)
+ .not_to receive(:track_work_item_milestone_changed_action)
+
+ service_instance.execute
+ end
+ end
+ end
end
diff --git a/spec/services/resource_events/change_state_service_spec.rb b/spec/services/resource_events/change_state_service_spec.rb
index 255ee9eca57..b679943073c 100644
--- a/spec/services/resource_events/change_state_service_spec.rb
+++ b/spec/services/resource_events/change_state_service_spec.rb
@@ -18,10 +18,11 @@ RSpec.describe ResourceEvents::ChangeStateService do
event = resource.resource_state_events.last
- if resource.is_a?(Issue)
+ case resource
+ when Issue
expect(event.issue).to eq(resource)
expect(event.merge_request).to be_nil
- elsif resource.is_a?(MergeRequest)
+ when MergeRequest
expect(event.issue).to be_nil
expect(event.merge_request).to eq(resource)
end
@@ -91,10 +92,11 @@ RSpec.describe ResourceEvents::ChangeStateService do
end
def expect_event_source(event, source)
- if source.is_a?(MergeRequest)
+ case source
+ when MergeRequest
expect(event.source_commit).to be_nil
expect(event.source_merge_request).to eq(source)
- elsif source.is_a?(Commit)
+ when Commit
expect(event.source_commit).to eq(source.id)
expect(event.source_merge_request).to be_nil
else
diff --git a/spec/services/search/group_service_spec.rb b/spec/services/search/group_service_spec.rb
index 152d0700cc1..c9bfa7cb7b4 100644
--- a/spec/services/search/group_service_spec.rb
+++ b/spec/services/search/group_service_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe Search::GroupService do
# These projects shouldn't be found
let!(:outside_project) { create(:project, :public, name: "Outside #{term}") }
- let!(:private_project) { create(:project, :private, namespace: nested_group, name: "Private #{term}" ) }
+ let!(:private_project) { create(:project, :private, namespace: nested_group, name: "Private #{term}") }
let!(:other_project) { create(:project, :public, namespace: nested_group, name: term.reverse) }
# These projects should be found
diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb
index 5edea13afa4..26def474b88 100644
--- a/spec/services/search_service_spec.rb
+++ b/spec/services/search_service_spec.rb
@@ -399,159 +399,7 @@ RSpec.describe SearchService do
end
end
- context 'redacting search results' do
- let(:search) { 'anything' }
-
- subject(:result) { search_service.search_objects }
-
- shared_examples "redaction limits N+1 queries" do |limit:|
- it 'does not exceed the query limit' do
- # issuing the query to remove the data loading call
- unredacted_results.to_a
-
- # only the calls from the redaction are left
- query = ActiveRecord::QueryRecorder.new { result }
-
- # these are the project authorization calls, which are not preloaded
- expect(query.count).to be <= limit
- end
- end
-
- def found_blob(project)
- Gitlab::Search::FoundBlob.new(project: project)
- end
-
- def found_wiki_page(project)
- Gitlab::Search::FoundWikiPage.new(found_blob(project))
- end
-
- before do
- expect(search_service)
- .to receive(:search_results)
- .and_return(double('search results', objects: unredacted_results))
- end
-
- def ar_relation(klass, *objects)
- klass.id_in(objects.map(&:id))
- end
-
- def kaminari_array(*objects)
- Kaminari.paginate_array(objects).page(1).per(20)
- end
-
- context 'issues' do
- let(:readable) { create(:issue, project: accessible_project) }
- let(:unreadable) { create(:issue, project: inaccessible_project) }
- let(:unredacted_results) { ar_relation(Issue, readable, unreadable) }
- let(:scope) { 'issues' }
-
- it 'redacts the inaccessible issue' do
- expect(result).to contain_exactly(readable)
- end
- end
-
- context 'notes' do
- let(:readable) { create(:note_on_commit, project: accessible_project) }
- let(:unreadable) { create(:note_on_commit, project: inaccessible_project) }
- let(:unredacted_results) { ar_relation(Note, readable, unreadable) }
- let(:scope) { 'notes' }
-
- it 'redacts the inaccessible note' do
- expect(result).to contain_exactly(readable)
- end
- end
-
- context 'merge_requests' do
- let(:readable) { create(:merge_request, source_project: accessible_project, author: user) }
- let(:unreadable) { create(:merge_request, source_project: inaccessible_project) }
- let(:unredacted_results) { ar_relation(MergeRequest, readable, unreadable) }
- let(:scope) { 'merge_requests' }
-
- it 'redacts the inaccessible merge request' do
- expect(result).to contain_exactly(readable)
- end
-
- context 'with :with_api_entity_associations' do
- let(:unredacted_results) { ar_relation(MergeRequest.with_api_entity_associations, readable, unreadable) }
-
- it_behaves_like "redaction limits N+1 queries", limit: 8
- end
- end
-
- context 'project repository blobs' do
- let(:readable) { found_blob(accessible_project) }
- let(:unreadable) { found_blob(inaccessible_project) }
- let(:unredacted_results) { kaminari_array(readable, unreadable) }
- let(:scope) { 'blobs' }
-
- it 'redacts the inaccessible blob' do
- expect(result).to contain_exactly(readable)
- end
- end
-
- context 'project wiki blobs' do
- let(:readable) { found_wiki_page(accessible_project) }
- let(:unreadable) { found_wiki_page(inaccessible_project) }
- let(:unredacted_results) { kaminari_array(readable, unreadable) }
- let(:scope) { 'wiki_blobs' }
-
- it 'redacts the inaccessible blob' do
- expect(result).to contain_exactly(readable)
- end
- end
-
- context 'project snippets' do
- let(:readable) { create(:project_snippet, project: accessible_project) }
- let(:unreadable) { create(:project_snippet, project: inaccessible_project) }
- let(:unredacted_results) { ar_relation(ProjectSnippet, readable, unreadable) }
- let(:scope) { 'snippet_titles' }
-
- it 'redacts the inaccessible snippet' do
- expect(result).to contain_exactly(readable)
- end
-
- context 'with :with_api_entity_associations' do
- it_behaves_like "redaction limits N+1 queries", limit: 14
- end
- end
-
- context 'personal snippets' do
- let(:readable) { create(:personal_snippet, :private, author: user) }
- let(:unreadable) { create(:personal_snippet, :private) }
- let(:unredacted_results) { ar_relation(PersonalSnippet, readable, unreadable) }
- let(:scope) { 'snippet_titles' }
-
- it 'redacts the inaccessible snippet' do
- expect(result).to contain_exactly(readable)
- end
-
- context 'with :with_api_entity_associations' do
- it_behaves_like "redaction limits N+1 queries", limit: 4
- end
- end
-
- context 'commits' do
- let(:readable) { accessible_project.commit }
- let(:unreadable) { inaccessible_project.commit }
- let(:unredacted_results) { kaminari_array(readable, unreadable) }
- let(:scope) { 'commits' }
-
- it 'redacts the inaccessible commit' do
- expect(result).to contain_exactly(readable)
- end
- end
-
- context 'users' do
- let(:other_user) { create(:user) }
- let(:unredacted_results) { ar_relation(User, user, other_user) }
- let(:scope) { 'users' }
-
- it 'passes the users through' do
- # Users are always visible to everyone
- expect(result).to contain_exactly(user, other_user)
- end
- end
- end
+ it_behaves_like 'a redacted search results'
end
describe '#valid_request?' do
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 7a004e2915c..9211beb76f8 100644
--- a/spec/services/security/ci_configuration/sast_parser_service_spec.rb
+++ b/spec/services/security/ci_configuration/sast_parser_service_spec.rb
@@ -11,9 +11,9 @@ RSpec.describe Security::CiConfiguration::SastParserService do
let(:sast_excluded_paths) { configuration['global'][1] }
let(:sast_pipeline_stage) { configuration['pipeline'][0] }
let(:sast_search_max_depth) { configuration['pipeline'][1] }
- let(:bandit) { configuration['analyzers'][0] }
- let(:brakeman) { configuration['analyzers'][1] }
+ let(:brakeman) { configuration['analyzers'][0] }
let(:sast_brakeman_level) { brakeman['variables'][0] }
+ let(:semgrep) { configuration['analyzers'][1] }
let(:secure_analyzers_prefix) { '$CI_TEMPLATE_REGISTRY_HOST/security-products' }
it 'parses the configuration for SAST' do
@@ -34,7 +34,7 @@ RSpec.describe Security::CiConfiguration::SastParserService do
expect(sast_pipeline_stage['value']).to eql('our_custom_security_stage')
expect(sast_search_max_depth['value']).to eql('8')
expect(brakeman['enabled']).to be(false)
- expect(bandit['enabled']).to be(true)
+ expect(semgrep['enabled']).to be(true)
expect(sast_brakeman_level['value']).to eql('2')
end
@@ -43,7 +43,7 @@ RSpec.describe Security::CiConfiguration::SastParserService do
allow(project.repository).to receive(:blob_data_at).and_return(gitlab_ci_yml_excluded_analyzers_content)
expect(brakeman['enabled']).to be(false)
- expect(bandit['enabled']).to be(true)
+ expect(semgrep['enabled']).to be(true)
end
end
end
diff --git a/spec/services/security/merge_reports_service_spec.rb b/spec/services/security/merge_reports_service_spec.rb
index e61977297c5..8415ed8a22f 100644
--- a/spec/services/security/merge_reports_service_spec.rb
+++ b/spec/services/security/merge_reports_service_spec.rb
@@ -219,10 +219,10 @@ RSpec.describe Security::MergeReportsService, '#execute' do
let(:finding_id_1) { build(:ci_reports_security_finding, identifiers: [identifier_bandit, identifier_cve], scanner: bandit_scanner, report_type: :sast) }
let(:finding_id_2) { build(:ci_reports_security_finding, identifiers: [identifier_cve], scanner: semgrep_scanner, report_type: :sast) }
- let(:finding_id_3) { build(:ci_reports_security_finding, identifiers: [identifier_semgrep], scanner: semgrep_scanner, report_type: :sast ) }
+ let(:finding_id_3) { build(:ci_reports_security_finding, identifiers: [identifier_semgrep], scanner: semgrep_scanner, report_type: :sast) }
let(:bandit_report) do
- build( :ci_reports_security_report,
+ build(:ci_reports_security_report,
type: :sast,
scanners: [bandit_scanner],
findings: [finding_id_1],
diff --git a/spec/services/system_notes/issuables_service_spec.rb b/spec/services/system_notes/issuables_service_spec.rb
index b2ccd9dba52..3263e410d3c 100644
--- a/spec/services/system_notes/issuables_service_spec.rb
+++ b/spec/services/system_notes/issuables_service_spec.rb
@@ -175,7 +175,7 @@ RSpec.describe ::SystemNotes::IssuablesService do
it 'builds a correct phrase when one reviewer removed from a set' do
expect(build_note([reviewer, reviewer1, reviewer2], [reviewer, reviewer1])).to(
- eq( "removed review request for @#{reviewer2.username}")
+ eq("removed review request for @#{reviewer2.username}")
)
end
@@ -681,7 +681,7 @@ RSpec.describe ::SystemNotes::IssuablesService do
it 'tracks usage' do
expect(Gitlab::UsageDataCounters::IssueActivityUniqueCounter)
- .to receive(:track_issue_cloned_action).with(author: author, project: project )
+ .to receive(:track_issue_cloned_action).with(author: author, project: project)
subject
end
diff --git a/spec/services/tags/create_service_spec.rb b/spec/services/tags/create_service_spec.rb
index b1c6623308e..bbf6fe62959 100644
--- a/spec/services/tags/create_service_spec.rb
+++ b/spec/services/tags/create_service_spec.rb
@@ -27,6 +27,26 @@ RSpec.describe Tags::CreateService do
end
end
+ context 'when tag_name is empty' do
+ it 'returns an error' do
+ response = service.execute('', 'foo', 'Foo')
+
+ expect(response[:status]).to eq(:error)
+ expect(response[:http_status]).to eq(400)
+ expect(response[:message]).to eq('Tag name invalid')
+ end
+ end
+
+ context 'when target is empty' do
+ it 'returns an error' do
+ response = service.execute('v1.1.0', '', 'Foo')
+
+ expect(response[:status]).to eq(:error)
+ expect(response[:http_status]).to eq(400)
+ expect(response[:message]).to eq('Target is empty')
+ end
+ end
+
context 'when tag already exists' do
it 'returns an error' do
expect(repository).to receive(:add_tag)
diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb
index 45a8268043f..774a6ddcfb3 100644
--- a/spec/services/todo_service_spec.rb
+++ b/spec/services/todo_service_spec.rb
@@ -1037,7 +1037,7 @@ RSpec.describe TodoService do
let_it_be(:noteable) { create(:issue, project: project) }
let(:note) { create(:note, project: project, note: mentions, noteable: noteable) }
- let(:addressed_note) { create(:note, project: project, note: "#{directly_addressed}", noteable: noteable) }
+ let(:addressed_note) { create(:note, project: project, note: directly_addressed.to_s, noteable: noteable) }
it 'creates a todo for each valid mentioned user not included in skip_users' do
service.update_note(note, author, skip_users)
diff --git a/spec/services/todos/destroy/entity_leave_service_spec.rb b/spec/services/todos/destroy/entity_leave_service_spec.rb
index 225e7933d79..9d5ed70e9ef 100644
--- a/spec/services/todos/destroy/entity_leave_service_spec.rb
+++ b/spec/services/todos/destroy/entity_leave_service_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
let!(:todo_issue_user) { create(:todo, user: user, target: issue, project: project) }
let!(:todo_issue_c_user) { create(:todo, user: user, target: issue_c, project: project) }
let!(:todo_issue_c_user2) { create(:todo, user: user2, target: issue_c, project: project) }
- let(:internal_note) { create(:note, noteable: issue, project: project, confidential: true ) }
+ let(:internal_note) { create(:note, noteable: issue, project: project, confidential: true) }
let!(:todo_for_internal_note) do
create(:todo, user: user, target: issue, project: project, note: internal_note)
end
@@ -28,7 +28,7 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
set_access(group, user, group_access) if group_access
end
- it "#{params[:method].to_s.humanize(capitalize: false)}" do
+ it params[:method].to_s.humanize(capitalize: false) do
send(method_name)
end
end
@@ -250,7 +250,7 @@ RSpec.describe Todos::Destroy::EntityLeaveService do
let!(:todo_subproject_user2) { create(:todo, user: user2, project: subproject) }
let!(:todo_subpgroup_user2) { create(:todo, user: user2, group: subgroup) }
let!(:todo_parent_group_user) { create(:todo, user: user, group: parent_group) }
- let(:subproject_internal_note) { create(:note, noteable: issue, project: project, confidential: true ) }
+ let(:subproject_internal_note) { create(:note, noteable: issue, project: project, confidential: true) }
let!(:todo_for_internal_subproject_note) do
create(:todo, user: user, target: issue, project: project, note: subproject_internal_note)
end
diff --git a/spec/services/topics/merge_service_spec.rb b/spec/services/topics/merge_service_spec.rb
index eef31817aa8..98247250a61 100644
--- a/spec/services/topics/merge_service_spec.rb
+++ b/spec/services/topics/merge_service_spec.rb
@@ -5,10 +5,10 @@ require 'spec_helper'
RSpec.describe Topics::MergeService 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 ) }
- let_it_be(:project_2) { create(:project, :private, topic_list: source_topic.name ) }
- let_it_be(:project_3) { create(:project, :public, topic_list: target_topic.name ) }
- let_it_be(:project_4) { create(:project, :public, topic_list: [source_topic.name, target_topic.name] ) }
+ let_it_be(:project_1) { create(:project, :public, topic_list: source_topic.name) }
+ let_it_be(:project_2) { create(:project, :private, topic_list: source_topic.name) }
+ let_it_be(:project_3) { create(:project, :public, topic_list: target_topic.name) }
+ let_it_be(:project_4) { create(:project, :public, topic_list: [source_topic.name, target_topic.name]) }
subject { described_class.new(source_topic, target_topic).execute }
diff --git a/spec/services/users/approve_service_spec.rb b/spec/services/users/approve_service_spec.rb
index 078dde546c9..34eb5b18ff6 100644
--- a/spec/services/users/approve_service_spec.rb
+++ b/spec/services/users/approve_service_spec.rb
@@ -67,7 +67,7 @@ RSpec.describe Users::ApproveService do
subject
- expect(Gitlab::AppLogger).to have_received(:info).with(message: "User instance access request approved", user: "#{user.username}", email: "#{user.email}", approved_by: "#{current_user.username}", ip_address: "#{current_user.current_sign_in_ip}")
+ expect(Gitlab::AppLogger).to have_received(:info).with(message: "User instance access request approved", user: user.username.to_s, email: user.email.to_s, approved_by: current_user.username.to_s, ip_address: current_user.current_sign_in_ip.to_s)
end
it 'emails the user on approval' do
diff --git a/spec/services/users/ban_service_spec.rb b/spec/services/users/ban_service_spec.rb
index 79f3cbeb46d..3f9c7ebf067 100644
--- a/spec/services/users/ban_service_spec.rb
+++ b/spec/services/users/ban_service_spec.rb
@@ -34,7 +34,7 @@ RSpec.describe Users::BanService do
end
it 'logs ban in application logs' do
- expect(Gitlab::AppLogger).to receive(:info).with(message: "User ban", user: "#{user.username}", email: "#{user.email}", ban_by: "#{current_user.username}", ip_address: "#{current_user.current_sign_in_ip}")
+ expect(Gitlab::AppLogger).to receive(:info).with(message: "User ban", user: user.username.to_s, email: user.email.to_s, ban_by: current_user.username.to_s, ip_address: current_user.current_sign_in_ip.to_s)
ban_user
end
diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb
index 03e1811c8a5..18ad946b289 100644
--- a/spec/services/users/destroy_service_spec.rb
+++ b/spec/services/users/destroy_service_spec.rb
@@ -10,546 +10,250 @@ RSpec.describe Users::DestroyService do
let(:service) { described_class.new(admin) }
let(:gitlab_shell) { Gitlab::Shell.new }
- shared_examples 'pre-migrate clean-up' do
- describe "Deletes a user and all their personal projects", :enable_admin_mode do
- context 'no options are given' do
- it 'will delete the personal project' do
- expect_next_instance_of(Projects::DestroyService) do |destroy_service|
- expect(destroy_service).to receive(:execute).once.and_return(true)
- end
-
- service.execute(user)
- end
+ describe "Initiates user deletion and deletes all their personal projects", :enable_admin_mode do
+ context 'no options are given' do
+ it 'creates GhostUserMigration record to handle migration in a worker' do
+ expect { service.execute(user) }
+ .to(
+ change do
+ Users::GhostUserMigration.where(user: user,
+ initiator_user: admin)
+ .exists?
+ end.from(false).to(true))
end
- context 'personal projects in pending_delete' do
- before do
- project.pending_delete = true
- project.save!
+ it 'will delete the personal project' do
+ expect_next_instance_of(Projects::DestroyService) do |destroy_service|
+ expect(destroy_service).to receive(:execute).once.and_return(true)
end
- it 'destroys a personal project in pending_delete' do
- expect_next_instance_of(Projects::DestroyService) do |destroy_service|
- expect(destroy_service).to receive(:execute).once.and_return(true)
- end
-
- service.execute(user)
- end
+ service.execute(user)
end
+ end
- context "solo owned groups present" do
- let(:solo_owned) { create(:group) }
- let(:member) { create(:group_member) }
- let(:user) { member.user }
-
- before do
- solo_owned.group_members = [member]
- end
-
- it 'returns the user with attached errors' do
- expect(service.execute(user)).to be(user)
- expect(user.errors.full_messages).to(
- contain_exactly('You must transfer ownership or delete groups before you can remove user'))
- end
-
- it 'does not delete the user, nor the group' do
- service.execute(user)
-
- expect(User.find(user.id)).to eq user
- expect(Group.find(solo_owned.id)).to eq solo_owned
- end
+ context 'personal projects in pending_delete' do
+ before do
+ project.pending_delete = true
+ project.save!
end
- context "deletions with solo owned groups" do
- let(:solo_owned) { create(:group) }
- let(:member) { create(:group_member) }
- let(:user) { member.user }
-
- before do
- solo_owned.group_members = [member]
- service.execute(user, delete_solo_owned_groups: true)
+ it 'destroys a personal project in pending_delete' do
+ expect_next_instance_of(Projects::DestroyService) do |destroy_service|
+ expect(destroy_service).to receive(:execute).once.and_return(true)
end
- it 'deletes solo owned groups' do
- expect { Group.find(solo_owned.id) }.to raise_error(ActiveRecord::RecordNotFound)
- end
+ service.execute(user)
end
+ end
- context 'deletions with inherited group owners' do
- let(:group) { create(:group, :nested) }
- let(:user) { create(:user) }
- let(:inherited_owner) { create(:user) }
-
- before do
- group.parent.add_owner(inherited_owner)
- group.add_owner(user)
+ context "solo owned groups present" do
+ let(:solo_owned) { create(:group) }
+ let(:member) { create(:group_member) }
+ let(:user) { member.user }
- service.execute(user, delete_solo_owned_groups: true)
- end
-
- it 'does not delete the group' do
- expect(Group.exists?(id: group)).to be_truthy
- end
+ before do
+ solo_owned.group_members = [member]
end
- describe "user personal's repository removal" do
- context 'storages' do
- before do
- perform_enqueued_jobs { service.execute(user) }
- end
-
- context 'legacy storage' do
- let!(:project) { create(:project, :empty_repo, :legacy_storage, namespace: user.namespace) }
-
- it 'removes repository' do
- expect(
- gitlab_shell.repository_exists?(project.repository_storage,
- "#{project.disk_path}.git")
- ).to be_falsey
- end
- end
-
- context 'hashed storage' do
- let!(:project) { create(:project, :empty_repo, namespace: user.namespace) }
-
- it 'removes repository' do
- expect(
- gitlab_shell.repository_exists?(project.repository_storage,
- "#{project.disk_path}.git")
- ).to be_falsey
- end
- end
- end
-
- context 'repository removal status is taken into account' do
- it 'raises exception' do
- expect_next_instance_of(::Projects::DestroyService) do |destroy_service|
- expect(destroy_service).to receive(:execute).and_return(false)
- end
-
- expect { service.execute(user) }
- .to raise_error(Users::DestroyService::DestroyError,
- "Project #{project.id} can't be deleted" )
- end
- end
+ it 'returns the user with attached errors' do
+ expect(service.execute(user)).to be(user)
+ expect(user.errors.full_messages).to(
+ contain_exactly('You must transfer ownership or delete groups before you can remove user'))
end
- describe "calls the before/after callbacks" do
- it 'of project_members' do
- expect_any_instance_of(ProjectMember).to receive(:run_callbacks).with(:find).once
- expect_any_instance_of(ProjectMember).to receive(:run_callbacks).with(:initialize).once
- expect_any_instance_of(ProjectMember).to receive(:run_callbacks).with(:destroy).once
-
- service.execute(user)
- end
-
- it 'of group_members' do
- group_member = create(:group_member)
- group_member.group.group_members.create!(user: user, access_level: 40)
+ it 'does not delete the user, nor the group' do
+ service.execute(user)
- expect_any_instance_of(GroupMember).to receive(:run_callbacks).with(:find).once
- expect_any_instance_of(GroupMember).to receive(:run_callbacks).with(:initialize).once
- expect_any_instance_of(GroupMember).to receive(:run_callbacks).with(:destroy).once
-
- service.execute(user)
- end
+ expect(User.find(user.id)).to eq user
+ expect(Group.find(solo_owned.id)).to eq solo_owned
end
end
- end
-
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
- end
-
- include_examples 'pre-migrate clean-up'
-
- describe "Deletes a user and all their personal projects", :enable_admin_mode do
- context 'no options are given' do
- it 'deletes the user' do
- user_data = service.execute(user)
- expect(user_data['email']).to eq(user.email)
- expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound)
- expect { Namespace.find(namespace.id) }.to raise_error(ActiveRecord::RecordNotFound)
- end
-
- it 'deletes user associations in batches' do
- expect(user).to receive(:destroy_dependent_associations_in_batches)
+ context "deletions with solo owned groups" do
+ let(:solo_owned) { create(:group) }
+ let(:member) { create(:group_member) }
+ let(:user) { member.user }
- service.execute(user)
- end
-
- it 'does not include snippets when deleting in batches' do
- expect(user).to receive(:destroy_dependent_associations_in_batches).with({ exclude: [:snippets] })
-
- service.execute(user)
- end
-
- it 'calls the bulk snippet destroy service for the user personal snippets' do
- repo1 = create(:personal_snippet, :repository, author: user).snippet_repository
- repo2 = create(:project_snippet, :repository, project: project, author: user).snippet_repository
-
- aggregate_failures do
- expect(gitlab_shell.repository_exists?(repo1.shard_name, repo1.disk_path + '.git')).to be_truthy
- expect(gitlab_shell.repository_exists?(repo2.shard_name, repo2.disk_path + '.git')).to be_truthy
- end
-
- # Call made when destroying user personal projects
- expect(Snippets::BulkDestroyService).to receive(:new)
- .with(admin, project.snippets).and_call_original
-
- # Call to remove user personal snippets and for
- # project snippets where projects are not user personal
- # ones
- expect(Snippets::BulkDestroyService).to receive(:new)
- .with(admin, user.snippets.only_personal_snippets).and_call_original
-
- service.execute(user)
-
- aggregate_failures do
- expect(gitlab_shell.repository_exists?(repo1.shard_name, repo1.disk_path + '.git')).to be_falsey
- expect(gitlab_shell.repository_exists?(repo2.shard_name, repo2.disk_path + '.git')).to be_falsey
- end
- end
-
- it 'calls the bulk snippet destroy service with hard delete option if it is present' do
- # this avoids getting into Projects::DestroyService as it would
- # call Snippets::BulkDestroyService first!
- allow(user).to receive(:personal_projects).and_return([])
-
- expect_next_instance_of(Snippets::BulkDestroyService) do |bulk_destroy_service|
- expect(bulk_destroy_service).to receive(:execute).with({ skip_authorization: true }).and_call_original
- end
-
- service.execute(user, { hard_delete: true })
- end
-
- it 'does not delete project snippets that the user is the author of' do
- repo = create(:project_snippet, :repository, author: user).snippet_repository
- service.execute(user)
- expect(gitlab_shell.repository_exists?(repo.shard_name, repo.disk_path + '.git')).to be_truthy
- expect(User.ghost.snippets).to include(repo.snippet)
- end
-
- context 'when an error is raised deleting snippets' do
- it 'does not delete user' do
- snippet = create(:personal_snippet, :repository, author: user)
-
- bulk_service = double
- allow(Snippets::BulkDestroyService).to receive(:new).and_call_original
- allow(Snippets::BulkDestroyService).to receive(:new).with(admin, user.snippets).and_return(bulk_service)
- allow(bulk_service).to receive(:execute).and_return(ServiceResponse.error(message: 'foo'))
-
- aggregate_failures do
- expect { service.execute(user) }
- .to raise_error(Users::DestroyService::DestroyError, 'foo' )
- expect(snippet.reload).not_to be_nil
- expect(
- gitlab_shell.repository_exists?(snippet.repository_storage,
- snippet.disk_path + '.git')
- ).to be_truthy
- end
- end
- end
+ before do
+ solo_owned.group_members = [member]
+ service.execute(user, delete_solo_owned_groups: true)
end
- context 'projects in pending_delete' do
- before do
- project.pending_delete = true
- project.save!
- end
-
- it 'destroys a project in pending_delete' do
- expect_next_instance_of(Projects::DestroyService) do |destroy_service|
- expect(destroy_service).to receive(:execute).once.and_return(true)
- end
-
- service.execute(user)
-
- expect { Project.find(project.id) }.to raise_error(ActiveRecord::RecordNotFound)
- end
+ it 'deletes solo owned groups' do
+ expect { Group.find(solo_owned.id) }.to raise_error(ActiveRecord::RecordNotFound)
end
+ end
- context "a deleted user's issues" do
- let(:project) { create(:project) }
-
- before do
- project.add_developer(user)
- end
-
- context "for an issue the user was assigned to" do
- let!(:issue) { create(:issue, project: project, assignees: [user]) }
-
- before do
- service.execute(user)
- end
+ context 'deletions with inherited group owners' do
+ let(:group) { create(:group, :nested) }
+ let(:user) { create(:user) }
+ let(:inherited_owner) { create(:user) }
- it 'does not delete issues the user is assigned to' do
- expect(Issue.find_by_id(issue.id)).to be_present
- end
+ before do
+ group.parent.add_owner(inherited_owner)
+ group.add_owner(user)
- it 'migrates the issue so that it is "Unassigned"' do
- migrated_issue = Issue.find_by_id(issue.id)
-
- expect(migrated_issue.assignees).to be_empty
- end
- end
+ service.execute(user, delete_solo_owned_groups: true)
end
- context "a deleted user's merge_requests" do
- let(:project) { create(:project, :repository) }
+ it 'does not delete the group' do
+ expect(Group.exists?(id: group)).to be_truthy
+ end
+ end
+ describe "user personal's repository removal" do
+ context 'storages' do
before do
- project.add_developer(user)
+ perform_enqueued_jobs { service.execute(user) }
end
- context "for an merge request the user was assigned to" do
- let!(:merge_request) { create(:merge_request, source_project: project, assignees: [user]) }
+ context 'legacy storage' do
+ let!(:project) { create(:project, :empty_repo, :legacy_storage, namespace: user.namespace) }
- before do
- service.execute(user)
- end
-
- it 'does not delete merge requests the user is assigned to' do
- expect(MergeRequest.find_by_id(merge_request.id)).to be_present
- end
-
- it 'migrates the merge request so that it is "Unassigned"' do
- migrated_merge_request = MergeRequest.find_by_id(merge_request.id)
-
- expect(migrated_merge_request.assignees).to be_empty
+ it 'removes repository' do
+ expect(
+ gitlab_shell.repository_exists?(project.repository_storage,
+ "#{project.disk_path}.git")
+ ).to be_falsey
end
end
- end
-
- context 'migrating associated records' do
- let!(:issue) { create(:issue, author: user) }
- it 'delegates to the `MigrateToGhostUser` service to move associated records to the ghost user' do
- expect_any_instance_of(Users::MigrateToGhostUserService).to receive(:execute).once.and_call_original
+ context 'hashed storage' do
+ let!(:project) { create(:project, :empty_repo, namespace: user.namespace) }
- service.execute(user)
-
- expect(issue.reload.author).to be_ghost
- end
-
- context 'when hard_delete option is given' do
- it 'will not ghost certain records' do
- expect_any_instance_of(Users::MigrateToGhostUserService).to receive(:execute).once.and_call_original
-
- service.execute(user, hard_delete: true)
-
- expect(Issue.exists?(issue.id)).to be_falsy
+ it 'removes repository' do
+ expect(
+ gitlab_shell.repository_exists?(project.repository_storage,
+ "#{project.disk_path}.git")
+ ).to be_falsey
end
end
end
- end
-
- describe "Deletion permission checks" do
- it 'does not delete the user when user is not an admin' do
- other_user = create(:user)
-
- expect { described_class.new(other_user).execute(user) }.to raise_error(Gitlab::Access::AccessDeniedError)
- expect(User.exists?(user.id)).to be(true)
- end
-
- context 'when admin mode is enabled', :enable_admin_mode do
- it 'allows admins to delete anyone' do
- described_class.new(admin).execute(user)
-
- expect(User.exists?(user.id)).to be(false)
- end
- end
- context 'when admin mode is disabled' do
- it 'disallows admins to delete anyone' do
- expect { described_class.new(admin).execute(user) }.to raise_error(Gitlab::Access::AccessDeniedError)
+ context 'repository removal status is taken into account' do
+ it 'raises exception' do
+ expect_next_instance_of(::Projects::DestroyService) do |destroy_service|
+ expect(destroy_service).to receive(:execute).and_return(false)
+ end
- expect(User.exists?(user.id)).to be(true)
+ expect { service.execute(user) }
+ .to raise_error(Users::DestroyService::DestroyError,
+ "Project #{project.id} can't be deleted")
end
end
-
- it 'allows users to delete their own account' do
- described_class.new(user).execute(user)
-
- expect(User.exists?(user.id)).to be(false)
- end
-
- it 'allows user to be deleted if skip_authorization: true' do
- other_user = create(:user)
-
- described_class.new(user).execute(other_user, skip_authorization: true)
-
- expect(User.exists?(other_user.id)).to be(false)
- end
end
- context 'batched nullify' do
- let(:other_user) { create(:user) }
+ describe "calls the before/after callbacks" do
+ it 'of project_members' do
+ expect_any_instance_of(ProjectMember).to receive(:run_callbacks).with(:find).once
+ expect_any_instance_of(ProjectMember).to receive(:run_callbacks).with(:initialize).once
+ expect_any_instance_of(ProjectMember).to receive(:run_callbacks).with(:destroy).once
- # rubocop:disable Layout/LineLength
- def nullify_in_batches_regexp(table, column, user, batch_size: 100)
- %r{^UPDATE "#{table}" SET "#{column}" = NULL WHERE "#{table}"."id" IN \(SELECT "#{table}"."id" FROM "#{table}" WHERE "#{table}"."#{column}" = #{user.id} LIMIT #{batch_size}\)}
+ service.execute(user)
end
- def delete_in_batches_regexps(table, column, user, items, batch_size: 1000)
- select_query = %r{^SELECT "#{table}".* FROM "#{table}" WHERE "#{table}"."#{column}" = #{user.id}.*ORDER BY "#{table}"."id" ASC LIMIT #{batch_size}}
-
- [select_query] + items.map { |item| %r{^DELETE FROM "#{table}" WHERE "#{table}"."id" = #{item.id}} }
- end
- # rubocop:enable Layout/LineLength
+ it 'of group_members' do
+ group_member = create(:group_member)
+ group_member.group.group_members.create!(user: user, access_level: 40)
- it 'nullifies related associations in batches' do
- expect(other_user).to receive(:nullify_dependent_associations_in_batches).and_call_original
+ expect_any_instance_of(GroupMember).to receive(:run_callbacks).with(:find).once
+ expect_any_instance_of(GroupMember).to receive(:run_callbacks).with(:initialize).once
+ expect_any_instance_of(GroupMember).to receive(:run_callbacks).with(:destroy).once
- described_class.new(user).execute(other_user, skip_authorization: true)
+ service.execute(user)
end
+ end
- it 'nullifies issues and resource associations', :aggregate_failures do
- issue = create(:issue, closed_by: other_user, updated_by: other_user)
- resource_label_event = create(:resource_label_event, user: other_user)
- resource_state_event = create(:resource_state_event, user: other_user)
- todos = create_list(:todo, 2, project: issue.project, user: other_user, author: other_user, target: issue)
- event = create(:event, project: issue.project, author: other_user)
+ describe 'prometheus metrics', :prometheus do
+ context 'scheduled records' do
+ context 'with a single record' do
+ it 'updates the scheduled records gauge' do
+ service.execute(user)
- query_recorder = ActiveRecord::QueryRecorder.new do
- described_class.new(user).execute(other_user, skip_authorization: true)
+ gauge = Gitlab::Metrics.registry.get(:gitlab_ghost_user_migration_scheduled_records_total)
+ expect(gauge.get).to eq(1)
+ end
end
- issue.reload
- resource_label_event.reload
- resource_state_event.reload
-
- expect(issue.closed_by).to be_nil
- expect(issue.updated_by).to be_nil
- expect(resource_label_event.user).to be_nil
- expect(resource_state_event.user).to be_nil
- expect(other_user.authored_todos).to be_empty
- expect(other_user.todos).to be_empty
- expect(other_user.authored_events).to be_empty
-
- expected_queries = [
- nullify_in_batches_regexp(:issues, :updated_by_id, other_user),
- nullify_in_batches_regexp(:issues, :closed_by_id, other_user),
- nullify_in_batches_regexp(:resource_label_events, :user_id, other_user),
- nullify_in_batches_regexp(:resource_state_events, :user_id, other_user)
- ]
-
- expected_queries += delete_in_batches_regexps(:todos, :user_id, other_user, todos)
- expected_queries += delete_in_batches_regexps(:todos, :author_id, other_user, todos)
- expected_queries += delete_in_batches_regexps(:events, :author_id, other_user, [event])
-
- expect(query_recorder.log).to include(*expected_queries)
- end
+ context 'with approximate count due to large number of records' do
+ it 'updates the scheduled records gauge' do
+ allow(Users::GhostUserMigration)
+ .to(receive_message_chain(:limit, :count).and_return(1001))
+ allow(Users::GhostUserMigration).to(receive(:minimum)).and_return(42)
+ allow(Users::GhostUserMigration).to(receive(:maximum)).and_return(9042)
- it 'nullifies merge request associations', :aggregate_failures do
- merge_request = create(:merge_request, source_project: project, target_project: project,
- assignee: other_user, updated_by: other_user, merge_user: other_user)
- merge_request.metrics.update!(merged_by: other_user, latest_closed_by: other_user)
- merge_request.reviewers = [other_user]
- merge_request.assignees = [other_user]
+ service.execute(user)
- query_recorder = ActiveRecord::QueryRecorder.new do
- described_class.new(user).execute(other_user, skip_authorization: true)
+ gauge = Gitlab::Metrics.registry.get(:gitlab_ghost_user_migration_scheduled_records_total)
+ expect(gauge.get).to eq(9000)
+ end
end
-
- merge_request.reload
-
- expect(merge_request.updated_by).to be_nil
- expect(merge_request.assignee).to be_nil
- expect(merge_request.assignee_id).to be_nil
- expect(merge_request.metrics.merged_by).to be_nil
- expect(merge_request.metrics.latest_closed_by).to be_nil
- expect(merge_request.reviewers).to be_empty
- expect(merge_request.assignees).to be_empty
-
- expected_queries = [
- nullify_in_batches_regexp(:merge_requests, :updated_by_id, other_user),
- nullify_in_batches_regexp(:merge_requests, :assignee_id, other_user),
- nullify_in_batches_regexp(:merge_request_metrics, :merged_by_id, other_user),
- nullify_in_batches_regexp(:merge_request_metrics, :latest_closed_by_id, other_user)
- ]
-
- expected_queries += delete_in_batches_regexps(:merge_request_assignees, :user_id, other_user,
- merge_request.assignees)
- expected_queries += delete_in_batches_regexps(:merge_request_reviewers, :user_id, other_user,
- merge_request.reviewers)
-
- expect(query_recorder.log).to include(*expected_queries)
end
- end
- end
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- include_examples 'pre-migrate clean-up'
+ context 'lag' do
+ it 'update the lag gauge', :freeze_time do
+ create(:ghost_user_migration, created_at: 10.minutes.ago)
- describe "Deletes a user and all their personal projects", :enable_admin_mode do
- context 'no options are given' do
- it 'creates GhostUserMigration record to handle migration in a worker' do
- expect { service.execute(user) }
- .to(
- change do
- Users::GhostUserMigration.where(user: user,
- initiator_user: admin)
- .exists?
- end.from(false).to(true))
+ service.execute(user)
+
+ gauge = Gitlab::Metrics.registry.get(:gitlab_ghost_user_migration_lag_seconds)
+ expect(gauge.get).to eq(600)
end
end
end
+ end
- describe "Deletion permission checks" do
- it 'does not delete the user when user is not an admin' do
- other_user = create(:user)
-
- expect { described_class.new(other_user).execute(user) }.to raise_error(Gitlab::Access::AccessDeniedError)
-
- expect(Users::GhostUserMigration).not_to be_exists
- end
-
- context 'when admin mode is enabled', :enable_admin_mode do
- it 'allows admins to delete anyone' do
- expect { described_class.new(admin).execute(user) }
- .to(
- change do
- Users::GhostUserMigration.where(user: user,
- initiator_user: admin)
- .exists?
- end.from(false).to(true))
- end
- end
+ describe "Deletion permission checks" do
+ it 'does not delete the user when user is not an admin' do
+ other_user = create(:user)
- context 'when admin mode is disabled' do
- it 'disallows admins to delete anyone' do
- expect { described_class.new(admin).execute(user) }.to raise_error(Gitlab::Access::AccessDeniedError)
+ expect { described_class.new(other_user).execute(user) }.to raise_error(Gitlab::Access::AccessDeniedError)
- expect(Users::GhostUserMigration).not_to be_exists
- end
- end
+ expect(Users::GhostUserMigration).not_to be_exists
+ end
- it 'allows users to delete their own account' do
- expect { described_class.new(user).execute(user) }
+ context 'when admin mode is enabled', :enable_admin_mode do
+ it 'allows admins to delete anyone' do
+ expect { described_class.new(admin).execute(user) }
.to(
change do
Users::GhostUserMigration.where(user: user,
- initiator_user: user)
+ initiator_user: admin)
.exists?
end.from(false).to(true))
end
+ end
- it 'allows user to be deleted if skip_authorization: true' do
- other_user = create(:user)
+ context 'when admin mode is disabled' do
+ it 'disallows admins to delete anyone' do
+ expect { described_class.new(admin).execute(user) }.to raise_error(Gitlab::Access::AccessDeniedError)
+
+ expect(Users::GhostUserMigration).not_to be_exists
+ end
+ end
- expect do
- described_class.new(user)
- .execute(other_user, skip_authorization: true)
- end.to(
+ it 'allows users to delete their own account' do
+ expect { described_class.new(user).execute(user) }
+ .to(
change do
- Users::GhostUserMigration.where(user: other_user,
- initiator_user: user )
+ Users::GhostUserMigration.where(user: user,
+ initiator_user: user)
.exists?
end.from(false).to(true))
- end
+ end
+
+ it 'allows user to be deleted if skip_authorization: true' do
+ other_user = create(:user)
+
+ expect do
+ described_class.new(user)
+ .execute(other_user, skip_authorization: true)
+ end.to(
+ change do
+ Users::GhostUserMigration.where(user: other_user,
+ initiator_user: user )
+ .exists?
+ end.from(false).to(true))
end
end
end
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 7366b1646b9..107ff82016c 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
@@ -27,5 +27,34 @@ RSpec.describe Users::MigrateRecordsToGhostUserInBatchesService do
service.execute
end
+
+ it 'process jobs ordered by the consume_after timestamp' do
+ older_ghost_user_migration = create(:ghost_user_migration, user: create(:user),
+ consume_after: 5.minutes.ago)
+
+ # setup execution tracker to only allow a single job to be processed
+ allow_next_instance_of(::Gitlab::Utils::ExecutionTracker) do |tracker|
+ allow(tracker).to receive(:over_limit?).and_return(false, true)
+ end
+
+ expect(Users::MigrateRecordsToGhostUserService).to(
+ receive(:new).with(older_ghost_user_migration.user,
+ older_ghost_user_migration.initiator_user,
+ any_args)
+ ).and_call_original
+
+ service.execute
+ end
+
+ it 'reschedules job in case of an error', :freeze_time do
+ expect_next_instance_of(Users::MigrateRecordsToGhostUserService) do |service|
+ expect(service).to(receive(:execute)).and_raise(ActiveRecord::QueryCanceled)
+ end
+ expect(Gitlab::ErrorTracking).to receive(:track_exception)
+
+ expect { service.execute }.to(
+ change { ghost_user_migration.reload.consume_after }
+ .to(30.minutes.from_now))
+ end
end
end
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 766be51ae13..6082c7bd10e 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
@@ -146,24 +146,106 @@ RSpec.describe Users::MigrateRecordsToGhostUserService do
end
context 'for batched nullify' do
+ # rubocop:disable Layout/LineLength
+ def nullify_in_batches_regexp(table, column, user, batch_size: 100)
+ %r{^UPDATE "#{table}" SET "#{column}" = NULL WHERE "#{table}"."id" IN \(SELECT "#{table}"."id" FROM "#{table}" WHERE "#{table}"."#{column}" = #{user.id} LIMIT #{batch_size}\)}
+ end
+
+ def delete_in_batches_regexps(table, column, user, items, batch_size: 1000)
+ select_query = %r{^SELECT "#{table}".* FROM "#{table}" WHERE "#{table}"."#{column}" = #{user.id}.*ORDER BY "#{table}"."id" ASC LIMIT #{batch_size}}
+
+ [select_query] + items.map { |item| %r{^DELETE FROM "#{table}" WHERE "#{table}"."id" = #{item.id}} }
+ end
+ # rubocop:enable Layout/LineLength
+
it 'nullifies related associations in batches' do
expect(user).to receive(:nullify_dependent_associations_in_batches).and_call_original
service.execute
end
- it 'nullifies last_updated_issues, closed_issues, resource_label_events' do
+ it 'nullifies associations marked as `dependent: :nullify` and'\
+ 'destroys the associations marked as `dependent: :destroy`, in batches', :aggregate_failures do
+ # associations to be nullified
issue = create(:issue, closed_by: user, updated_by: user)
resource_label_event = create(:resource_label_event, user: user)
+ resource_state_event = create(:resource_state_event, user: user)
+ created_project = create(:project, creator: user)
- service.execute
+ # associations to be destroyed
+ todos = create_list(:todo, 2, project: issue.project, user: user, author: user, target: issue)
+ event = create(:event, project: issue.project, author: user)
+
+ query_recorder = ActiveRecord::QueryRecorder.new do
+ service.execute
+ end
issue.reload
resource_label_event.reload
+ resource_state_event.reload
+ created_project.reload
expect(issue.closed_by).to be_nil
- expect(issue.updated_by).to be_nil
- expect(resource_label_event.user).to be_nil
+ expect(issue.updated_by_id).to be_nil
+ expect(resource_label_event.user_id).to be_nil
+ expect(resource_state_event.user_id).to be_nil
+ expect(created_project.creator_id).to be_nil
+ expect(user.authored_todos).to be_empty
+ expect(user.todos).to be_empty
+ expect(user.authored_events).to be_empty
+
+ expected_queries = [
+ nullify_in_batches_regexp(:issues, :updated_by_id, user),
+ nullify_in_batches_regexp(:issues, :closed_by_id, user),
+ nullify_in_batches_regexp(:resource_label_events, :user_id, user),
+ nullify_in_batches_regexp(:resource_state_events, :user_id, user),
+ nullify_in_batches_regexp(:projects, :creator_id, user)
+ ]
+
+ expected_queries += delete_in_batches_regexps(:todos, :user_id, user, todos)
+ expected_queries += delete_in_batches_regexps(:todos, :author_id, user, todos)
+ expected_queries += delete_in_batches_regexps(:events, :author_id, user, [event])
+
+ expect(query_recorder.log).to include(*expected_queries)
+ end
+
+ it 'nullifies merge request associations', :aggregate_failures do
+ merge_request = create(:merge_request, source_project: project,
+ target_project: project,
+ assignee: user,
+ updated_by: user,
+ merge_user: user)
+ merge_request.metrics.update!(merged_by: user, latest_closed_by: user)
+ merge_request.reviewers = [user]
+ merge_request.assignees = [user]
+
+ query_recorder = ActiveRecord::QueryRecorder.new do
+ service.execute
+ end
+
+ merge_request.reload
+
+ expect(merge_request.updated_by).to be_nil
+ expect(merge_request.assignee).to be_nil
+ expect(merge_request.assignee_id).to be_nil
+ expect(merge_request.metrics.merged_by).to be_nil
+ expect(merge_request.metrics.latest_closed_by).to be_nil
+ expect(merge_request.reviewers).to be_empty
+ expect(merge_request.assignees).to be_empty
+
+ expected_queries = [
+ nullify_in_batches_regexp(:merge_requests, :updated_by_id, user),
+ nullify_in_batches_regexp(:merge_requests, :assignee_id, user),
+ nullify_in_batches_regexp(:merge_request_metrics, :merged_by_id, user),
+ nullify_in_batches_regexp(:merge_request_metrics, :latest_closed_by_id, user)
+ ]
+
+ expected_queries += delete_in_batches_regexps(:merge_request_assignees, :user_id, user,
+ merge_request.assignees)
+ expected_queries += delete_in_batches_regexps(:merge_request_reviewers, :user_id, user,
+ merge_request.reviewers)
+
+ expect(query_recorder.log).to include(*expected_queries)
end
end
@@ -235,7 +317,7 @@ RSpec.describe Users::MigrateRecordsToGhostUserService do
aggregate_failures do
expect { service.execute }.to(
- raise_error(Users::MigrateRecordsToGhostUserService::DestroyError, 'foo' ))
+ raise_error(Users::MigrateRecordsToGhostUserService::DestroyError, 'foo'))
expect(snippet.reload).not_to be_nil
expect(
gitlab_shell.repository_exists?(snippet.repository_storage,
diff --git a/spec/services/users/migrate_to_ghost_user_service_spec.rb b/spec/services/users/migrate_to_ghost_user_service_spec.rb
deleted file mode 100644
index 073ebaae5b0..00000000000
--- a/spec/services/users/migrate_to_ghost_user_service_spec.rb
+++ /dev/null
@@ -1,97 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Users::MigrateToGhostUserService do
- let!(:user) { create(:user) }
- let!(:project) { create(:project, :repository) }
- let(:service) { described_class.new(user) }
- let(:always_ghost) { false }
-
- context "migrating a user's associated records to the ghost user" do
- context 'issues' do
- context 'deleted user is present as both author and edited_user' do
- include_examples "migrating a deleted user's associated records to the ghost user", Issue, [:author, :last_edited_by] do
- let(:created_record) do
- create(:issue, project: project, author: user, last_edited_by: user)
- end
- end
- end
-
- context 'deleted user is present only as edited_user' do
- include_examples "migrating a deleted user's associated records to the ghost user", Issue, [:last_edited_by] do
- let(:created_record) { create(:issue, project: project, author: create(:user), last_edited_by: user) }
- end
- end
- end
-
- context 'merge requests' do
- context 'deleted user is present as both author and merge_user' do
- include_examples "migrating a deleted user's associated records to the ghost user", MergeRequest, [:author, :merge_user] do
- let(:created_record) { create(:merge_request, source_project: project, author: user, merge_user: user, target_branch: "first") }
- end
- end
-
- context 'deleted user is present only as both merge_user' do
- include_examples "migrating a deleted user's associated records to the ghost user", MergeRequest, [:merge_user] do
- let(:created_record) { create(:merge_request, source_project: project, merge_user: user, target_branch: "first") }
- end
- end
- end
-
- context 'notes' do
- include_examples "migrating a deleted user's associated records to the ghost user", Note do
- let(:created_record) { create(:note, project: project, author: user) }
- end
- end
-
- context 'abuse reports' do
- include_examples "migrating a deleted user's associated records to the ghost user", AbuseReport do
- let(:created_record) { create(:abuse_report, reporter: user, user: create(:user)) }
- end
- end
-
- context 'award emoji' do
- include_examples "migrating a deleted user's associated records to the ghost user", AwardEmoji, [:user] do
- let(:created_record) { create(:award_emoji, user: user) }
-
- context "when the awardable already has an award emoji of the same name assigned to the ghost user" do
- let(:awardable) { create(:issue) }
- let!(:existing_award_emoji) { create(:award_emoji, user: User.ghost, name: "thumbsup", awardable: awardable) }
- let!(:award_emoji) { create(:award_emoji, user: user, name: "thumbsup", awardable: awardable) }
-
- it "migrates the award emoji regardless" do
- service.execute
-
- migrated_record = AwardEmoji.find_by_id(award_emoji.id)
-
- expect(migrated_record.user).to eq(User.ghost)
- end
-
- it "does not leave the migrated award emoji in an invalid state" do
- service.execute
-
- migrated_record = AwardEmoji.find_by_id(award_emoji.id)
-
- expect(migrated_record).to be_valid
- end
- end
- end
- end
-
- context 'snippets' do
- include_examples "migrating a deleted user's associated records to the ghost user", Snippet do
- let(:created_record) { create(:snippet, project: project, author: user) }
- end
- end
-
- context 'reviews' do
- let!(:user) { create(:user) }
- let(:service) { described_class.new(user) }
-
- include_examples "migrating a deleted user's associated records to the ghost user", Review, [:author] do
- let(:created_record) { create(:review, author: user) }
- end
- end
- end
-end
diff --git a/spec/services/users/reject_service_spec.rb b/spec/services/users/reject_service_spec.rb
index abff6b1e023..37d003c5dac 100644
--- a/spec/services/users/reject_service_spec.rb
+++ b/spec/services/users/reject_service_spec.rb
@@ -35,29 +35,14 @@ RSpec.describe Users::RejectService do
context 'success' do
context 'when the executor user is an admin in admin mode', :enable_admin_mode do
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- it 'initiates user removal', :sidekiq_inline do
- subject
-
- expect(subject[:status]).to eq(:success)
- expect(
- Users::GhostUserMigration.where(user: user,
- initiator_user: current_user)
- ).to be_exists
- end
- end
-
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
- end
-
- it 'deletes the user', :sidekiq_inline do
- subject
+ it 'initiates user removal', :sidekiq_inline do
+ subject
- expect(subject[:status]).to eq(:success)
- expect { User.find(user.id) }.to raise_error(ActiveRecord::RecordNotFound)
- end
+ expect(subject[:status]).to eq(:success)
+ expect(
+ Users::GhostUserMigration.where(user: user,
+ initiator_user: current_user)
+ ).to be_exists
end
it 'emails the user on rejection' do
@@ -73,7 +58,7 @@ RSpec.describe Users::RejectService do
subject
- expect(Gitlab::AppLogger).to have_received(:info).with(message: "User instance access request rejected", user: "#{user.username}", email: "#{user.email}", rejected_by: "#{current_user.username}", ip_address: "#{current_user.current_sign_in_ip}")
+ expect(Gitlab::AppLogger).to have_received(:info).with(message: "User instance access request rejected", user: user.username.to_s, email: user.email.to_s, rejected_by: current_user.username.to_s, ip_address: current_user.current_sign_in_ip.to_s)
end
end
end
diff --git a/spec/services/users/unban_service_spec.rb b/spec/services/users/unban_service_spec.rb
index d536baafdcc..3dcb8450e7b 100644
--- a/spec/services/users/unban_service_spec.rb
+++ b/spec/services/users/unban_service_spec.rb
@@ -38,7 +38,7 @@ RSpec.describe Users::UnbanService do
end
it 'logs unban in application logs' do
- expect(Gitlab::AppLogger).to receive(:info).with(message: "User unban", user: "#{user.username}", email: "#{user.email}", unban_by: "#{current_user.username}", ip_address: "#{current_user.current_sign_in_ip}")
+ expect(Gitlab::AppLogger).to receive(:info).with(message: "User unban", user: user.username.to_s, email: user.email.to_s, unban_by: current_user.username.to_s, ip_address: current_user.current_sign_in_ip.to_s)
unban_user
end
diff --git a/spec/services/web_hook_service_spec.rb b/spec/services/web_hook_service_spec.rb
index 551c3dbcc82..c081b20d95f 100644
--- a/spec/services/web_hook_service_spec.rb
+++ b/spec/services/web_hook_service_spec.rb
@@ -175,22 +175,6 @@ RSpec.describe WebHookService, :request_store, :clean_gitlab_redis_shared_state
).once
end
- context 'when webhooks_gitlab_instance_header flag is disabled' do
- before do
- stub_feature_flags(webhooks_gitlab_instance_header: false)
- end
-
- it 'excludes the X-Gitlab-Instance header' do
- stub_full_request(project_hook.url, method: :post)
-
- service_instance.execute
-
- expect(WebMock).to have_requested(:post, stubbed_hostname(project_hook.url)).with(
- headers: headers.except('X-Gitlab-Instance')
- ).once
- end
- end
-
context 'when the data is a Gitlab::DataBuilder::Pipeline' do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:data) { ::Gitlab::DataBuilder::Pipeline.new(pipeline) }
@@ -245,7 +229,7 @@ RSpec.describe WebHookService, :request_store, :clean_gitlab_redis_shared_state
it 'does not execute disabled hooks' do
allow(service_instance).to receive(:disabled?).and_return(true)
- expect(service_instance.execute).to eq({ status: :error, message: 'Hook disabled' })
+ expect(service_instance.execute).to have_attributes(status: :error, message: 'Hook disabled')
end
it 'executes and registers the hook with the recursion detection', :aggregate_failures do
@@ -317,7 +301,8 @@ RSpec.describe WebHookService, :request_store, :clean_gitlab_redis_shared_state
project_hook.enable!
stub_full_request(project_hook.url, method: :post).to_raise(exception)
- expect(service_instance.execute).to eq({ status: :error, message: exception.to_s })
+
+ expect(service_instance.execute).to have_attributes(status: :error, message: exception.to_s)
expect { service_instance.execute }.not_to raise_error
end
end
@@ -326,7 +311,10 @@ RSpec.describe WebHookService, :request_store, :clean_gitlab_redis_shared_state
let_it_be(:project_hook) { create(:project_hook, url: 'http://server.com/my path/') }
it 'handles exceptions' do
- expect(service_instance.execute).to eq(status: :error, message: 'bad URI(is not URI?): "http://server.com/my path/"')
+ expect(service_instance.execute).to have_attributes(
+ status: :error,
+ message: 'bad URI(is not URI?): "http://server.com/my path/"'
+ )
expect { service_instance.execute }.not_to raise_error
end
end
@@ -335,20 +323,31 @@ RSpec.describe WebHookService, :request_store, :clean_gitlab_redis_shared_state
it 'does not perform the request' do
stub_const("#{described_class}::REQUEST_BODY_SIZE_LIMIT", 10.bytes)
- expect(service_instance.execute).to eq({ status: :error, message: "Gitlab::Json::LimitedEncoder::LimitExceeded" })
+ expect(service_instance.execute).to have_attributes(
+ status: :error,
+ message: 'Gitlab::Json::LimitedEncoder::LimitExceeded'
+ )
end
end
it 'handles 200 status code' do
stub_full_request(project_hook.url, method: :post).to_return(status: 200, body: 'Success')
- expect(service_instance.execute).to include({ status: :success, http_status: 200, message: 'Success' })
+ expect(service_instance.execute).to have_attributes(
+ status: :success,
+ payload: { http_status: 200 },
+ message: 'Success'
+ )
end
it 'handles 2xx status codes' do
stub_full_request(project_hook.url, method: :post).to_return(status: 201, body: 'Success')
- expect(service_instance.execute).to include({ status: :success, http_status: 201, message: 'Success' })
+ expect(service_instance.execute).to have_attributes(
+ status: :success,
+ payload: { http_status: 201 },
+ message: 'Success'
+ )
end
context 'execution logging' do
diff --git a/spec/services/work_items/create_service_spec.rb b/spec/services/work_items/create_service_spec.rb
index c0bcf9b606d..1bd7e15db67 100644
--- a/spec/services/work_items/create_service_spec.rb
+++ b/spec/services/work_items/create_service_spec.rb
@@ -179,16 +179,6 @@ RSpec.describe WorkItems::CreateService do
let(:error_message) { 'only Issue and Incident can be parent of Task.' }
end
end
-
- context 'when hierarchy feature flag is disabled' do
- before do
- stub_feature_flags(work_items_hierarchy: false)
- end
-
- it_behaves_like 'fails creating work item and returns errors' do
- let(:error_message) { '`work_items_hierarchy` feature flag disabled for this project' }
- end
- end
end
context 'when user cannot admin parent link' do
diff --git a/spec/services/work_items/update_service_spec.rb b/spec/services/work_items/update_service_spec.rb
index 1761d1104dd..68efb4c220b 100644
--- a/spec/services/work_items/update_service_spec.rb
+++ b/spec/services/work_items/update_service_spec.rb
@@ -311,6 +311,34 @@ RSpec.describe WorkItems::UpdateService do
end
end
end
+
+ context 'for milestone widget' do
+ let_it_be(:milestone) { create(:milestone, project: project) }
+
+ let(:widget_params) { { milestone_widget: { milestone_id: milestone.id } } }
+
+ context 'when milestone is updated' do
+ it "triggers 'issuableMilestoneUpdated'" do
+ expect(work_item.milestone).to eq(nil)
+ expect(GraphqlTriggers).to receive(:issuable_milestone_updated).with(work_item).and_call_original
+
+ update_work_item
+ end
+ end
+
+ context 'when milestone remains unchanged' do
+ before do
+ update_work_item
+ end
+
+ it "does not trigger 'issuableMilestoneUpdated'" do
+ expect(work_item.milestone).to eq(milestone)
+ expect(GraphqlTriggers).not_to receive(:issuable_milestone_updated)
+
+ update_work_item
+ end
+ end
+ end
end
describe 'label updates' do
diff --git a/spec/services/work_items/widgets/hierarchy_service/update_service_spec.rb b/spec/services/work_items/widgets/hierarchy_service/update_service_spec.rb
index 9a425d5308c..1b8c4c5f15f 100644
--- a/spec/services/work_items/widgets/hierarchy_service/update_service_spec.rb
+++ b/spec/services/work_items/widgets/hierarchy_service/update_service_spec.rb
@@ -42,18 +42,6 @@ RSpec.describe WorkItems::Widgets::HierarchyService::UpdateService do
let_it_be(:child_work_item3) { create(:work_item, :task, project: project) }
let_it_be(:child_work_item4) { create(:work_item, :task, project: project) }
- context 'when work_items_hierarchy feature flag is disabled' do
- let(:params) { { children: [child_work_item4] } }
-
- before do
- stub_feature_flags(work_items_hierarchy: false)
- end
-
- it_behaves_like 'raises a WidgetError' do
- let(:message) { '`work_items_hierarchy` feature flag disabled for this project' }
- end
- end
-
context 'when user has insufficient permissions to link work items' do
let(:params) { { children: [child_work_item4] } }
@@ -105,16 +93,6 @@ RSpec.describe WorkItems::Widgets::HierarchyService::UpdateService do
let(:params) { { parent: parent_work_item } }
- context 'when work_items_hierarchy feature flag is disabled' do
- before do
- stub_feature_flags(work_items_hierarchy: false)
- end
-
- it_behaves_like 'raises a WidgetError' do
- let(:message) { '`work_items_hierarchy` feature flag disabled for this project' }
- end
- end
-
context 'when user has insufficient permissions to link work items' do
it_behaves_like 'raises a WidgetError' do
let(:message) { not_found_error }
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
new file mode 100644
index 00000000000..3f90784b703
--- /dev/null
+++ b/spec/services/work_items/widgets/milestone_service/create_service_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WorkItems::Widgets::MilestoneService::CreateService 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) }
+ let_it_be(:group_milestone) { create(:milestone, group: group) }
+ let_it_be(:guest) { create(:user) }
+
+ let(:current_user) { guest }
+ let(:work_item) { build(:work_item, project: project, updated_at: 1.day.ago) }
+ let(:widget) { work_item.widgets.find { |widget| widget.is_a?(WorkItems::Widgets::Milestone) } }
+ let(:service) { described_class.new(widget: widget, current_user: current_user) }
+
+ before do
+ project.add_guest(guest)
+ end
+
+ describe '#before_create_callback' do
+ it_behaves_like "setting work item's milestone" do
+ subject(:execute_callback) do
+ service.before_create_callback(params: params)
+ end
+ end
+ end
+end
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
new file mode 100644
index 00000000000..f3a7fc156b9
--- /dev/null
+++ b/spec/services/work_items/widgets/milestone_service/update_service_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WorkItems::Widgets::MilestoneService::UpdateService 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) }
+ let_it_be(:group_milestone) { create(:milestone, group: group) }
+ let_it_be(:reporter) { create(:user) }
+ let_it_be(:guest) { create(:user) }
+
+ let(:work_item) { create(:work_item, project: project, updated_at: 1.day.ago) }
+ let(:widget) { work_item.widgets.find { |widget| widget.is_a?(WorkItems::Widgets::Milestone) } }
+ let(:service) { described_class.new(widget: widget, current_user: current_user) }
+
+ before do
+ project.add_reporter(reporter)
+ project.add_guest(guest)
+ end
+
+ describe '#before_update_callback' do
+ context 'when current user is not allowed to set work item metadata' do
+ let(:current_user) { guest }
+ let(:params) { { milestone_id: group_milestone.id } }
+
+ it "does not set the work item's milestone" do
+ expect { service.before_update_callback(params: params) }
+ .to not_change(work_item, :milestone)
+ end
+ end
+
+ context "when current user is allowed to set work item metadata" do
+ let(:current_user) { reporter }
+
+ it_behaves_like "setting work item's milestone" do
+ subject(:execute_callback) do
+ service.before_update_callback(params: params)
+ end
+ end
+
+ context 'when unsetting a milestone' do
+ let(:params) { { milestone_id: nil } }
+
+ before do
+ work_item.update!(milestone: project_milestone)
+ end
+
+ it "sets the work item's milestone" do
+ expect { service.before_update_callback(params: params) }
+ .to change(work_item, :milestone)
+ .from(project_milestone)
+ .to(nil)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/x509_certificate_revoke_service_spec.rb b/spec/services/x509_certificate_revoke_service_spec.rb
index adad3281c13..ff5d2dc058b 100644
--- a/spec/services/x509_certificate_revoke_service_spec.rb
+++ b/spec/services/x509_certificate_revoke_service_spec.rb
@@ -5,11 +5,11 @@ require 'spec_helper'
RSpec.describe X509CertificateRevokeService do
describe '#execute' do
let(:service) { described_class.new }
- let!(:x509_signature_1) { create(:x509_commit_signature, x509_certificate: x509_certificate, verification_status: :verified ) }
- let!(:x509_signature_2) { create(:x509_commit_signature, x509_certificate: x509_certificate, verification_status: :verified ) }
+ let!(:x509_signature_1) { create(:x509_commit_signature, x509_certificate: x509_certificate, verification_status: :verified) }
+ let!(:x509_signature_2) { create(:x509_commit_signature, x509_certificate: x509_certificate, verification_status: :verified) }
context 'for revoked certificates' do
- let(:x509_certificate) { create(:x509_certificate, certificate_status: :revoked ) }
+ let(:x509_certificate) { create(:x509_certificate, certificate_status: :revoked) }
it 'update all commit signatures' do
expect do
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 8a1fa486bde..8e73073e68b 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -65,7 +65,6 @@ require_relative('../jh/spec/spec_helper') if Gitlab.jh?
# Requires helpers, and shared contexts/examples first since they're used in other support files
# Load these first since they may be required by other helpers
-require Rails.root.join("spec/support/helpers/git_helpers.rb")
require Rails.root.join("spec/support/helpers/stub_requests.rb")
# Then the rest
@@ -145,7 +144,7 @@ RSpec.configure do |config|
config.include NextInstanceOf
config.include TestEnv
config.include FileReadHelpers
- config.include Database::MultipleDatabases
+ config.include Database::MultipleDatabasesHelpers
config.include Database::WithoutCheckConstraint
config.include Devise::Test::ControllerHelpers, type: :controller
config.include Devise::Test::ControllerHelpers, type: :view
@@ -256,10 +255,6 @@ RSpec.configure do |config|
# The survey popover can block the diffs causing specs to fail
stub_feature_flags(mr_experience_survey: false)
- # Merge request widget GraphQL requests are disabled in the tests
- # for now whilst we migrate as much as we can over the GraphQL
- # stub_feature_flags(merge_request_widget_graphql: false)
-
# Using FortiAuthenticator as OTP provider is disabled by default in
# tests, until we introduce it in user settings
stub_feature_flags(forti_authenticator: false)
@@ -311,6 +306,10 @@ RSpec.configure do |config|
# See https://docs.gitlab.com/ee/development/feature_flags/#selectively-disable-by-actor
stub_feature_flags(legacy_merge_request_state_check_for_merged_result_pipelines: false)
+ # Disable the `vue_issues_dashboard` feature flag in specs as we migrate the issues
+ # dashboard page to Vue. https://gitlab.com/gitlab-org/gitlab/-/issues/379025
+ stub_feature_flags(vue_issues_dashboard: false)
+
allow(Gitlab::GitalyClient).to receive(:can_use_disk?).and_return(enable_rugged)
else
unstub_all_feature_flags
diff --git a/spec/support/database/multiple_databases.rb b/spec/support/database/multiple_databases.rb
deleted file mode 100644
index b6341c2caec..00000000000
--- a/spec/support/database/multiple_databases.rb
+++ /dev/null
@@ -1,161 +0,0 @@
-# frozen_string_literal: true
-
-module Database
- module MultipleDatabases
- def skip_if_multiple_databases_not_setup
- skip 'Skipping because multiple databases not set up' unless Gitlab::Database.has_config?(:ci)
- end
-
- def skip_if_multiple_databases_are_setup
- skip 'Skipping because multiple databases are set up' if Gitlab::Database.has_config?(:ci)
- end
-
- def reconfigure_db_connection(name: nil, config_hash: {}, model: ActiveRecord::Base, config_model: nil)
- db_config = (config_model || model).connection_db_config
-
- new_db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new(
- db_config.env_name,
- name ? name.to_s : db_config.name,
- db_config.configuration_hash.merge(config_hash)
- )
-
- model.establish_connection(new_db_config)
- end
-
- def ensure_schema_and_empty_tables
- # Ensure all schemas for both databases are migrated back
- Gitlab::Database.database_base_models.each do |_, base_model|
- with_reestablished_active_record_base do
- reconfigure_db_connection(
- model: ActiveRecord::Base,
- config_model: base_model
- )
-
- delete_from_all_tables!(except: deletion_except_tables)
- schema_migrate_up!
- end
- end
-
- # ActiveRecord::Base.clear_all_connections! disconnects and clears attribute methods
- # Force a refresh to avoid schema failures.
- reset_column_in_all_models
- refresh_attribute_methods
- end
-
- # The usage of this method switches temporarily used `connection_handler`
- # allowing full manipulation of ActiveRecord::Base connections without
- # having side effects like:
- # - misaligned transactions since this is managed by `BeforeAllAdapter`
- # - removal of primary connections
- #
- # The execution within a block ensures safe cleanup of all allocated resources.
- #
- # rubocop:disable Database/MultipleDatabases
- def with_reestablished_active_record_base(reconnect: true)
- connection_classes = ActiveRecord::Base.connection_handler.connection_pool_names.map(&:constantize).to_h do |klass|
- [klass, klass.connection_db_config]
- end
-
- original_handler = ActiveRecord::Base.connection_handler
- new_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
- ActiveRecord::Base.connection_handler = new_handler
-
- if reconnect
- connection_classes.each { |klass, db_config| klass.establish_connection(db_config) }
- end
-
- yield
- ensure
- ActiveRecord::Base.connection_handler = original_handler
- new_handler&.clear_all_connections!
- end
- # rubocop:enable Database/MultipleDatabases
-
- def with_added_ci_connection
- if Gitlab::Database.has_config?(:ci)
- # No need to add a ci: connection if we already have one
- yield
- else
- with_reestablished_active_record_base(reconnect: true) do
- reconfigure_db_connection(
- name: :ci,
- model: Ci::ApplicationRecord,
- config_model: ActiveRecord::Base
- )
-
- yield
-
- # Cleanup connection_specification_name for Ci::ApplicationRecord
- Ci::ApplicationRecord.remove_connection
- end
- end
- end
- end
-
- module ActiveRecordBaseEstablishConnection
- def establish_connection(*args)
- # rubocop:disable Database/MultipleDatabases
- if connected? && connection&.transaction_open? && ActiveRecord::Base.connection_handler == ActiveRecord::Base.default_connection_handler
- raise "Cannot re-establish '#{self}.establish_connection' within an open transaction (#{connection&.open_transactions.to_i}). " \
- "Use `with_reestablished_active_record_base` instead or add `:reestablished_active_record_base` to rspec context."
- end
- # rubocop:enable Database/MultipleDatabases
-
- super
- end
- end
-end
-
-RSpec.configure do |config|
- # Ensure database versions are memoized to prevent query counts from
- # being affected by version checks. Note that
- # Gitlab::Database.check_postgres_version_and_print_warning is called
- # at startup, but that generates its own
- # `Gitlab::Database::Reflection` so the result is not memoized by
- # callers of `ApplicationRecord.database.version`, such as
- # `Gitlab::Database::AsWithMaterialized.materialized_supported?`.
- # TODO This can be removed once https://gitlab.com/gitlab-org/gitlab/-/issues/325639 is completed.
- [ApplicationRecord, ::Ci::ApplicationRecord].each { |record| record.database.version }
-
- config.around(:each, :reestablished_active_record_base) do |example|
- with_reestablished_active_record_base(reconnect: example.metadata.fetch(:reconnect, true)) do
- example.run
- end
- end
-
- config.around(:each, :add_ci_connection) do |example|
- with_added_ci_connection do
- example.run
- end
- end
-
- config.append_after(:context, :migration) do
- recreate_databases_and_seed_if_needed || ensure_schema_and_empty_tables
- end
-
- config.around(:each, :migration) do |example|
- self.class.use_transactional_tests = false
-
- migration_schema = example.metadata[:migration]
- migration_schema = :gitlab_main if migration_schema == true
- base_model = Gitlab::Database.schemas_to_base_models.fetch(migration_schema).first
-
- # Migration require an `ActiveRecord::Base` to point to desired database
- if base_model != ActiveRecord::Base
- with_reestablished_active_record_base do
- reconfigure_db_connection(
- model: ActiveRecord::Base,
- config_model: base_model
- )
-
- example.run
- end
- else
- example.run
- end
-
- self.class.use_transactional_tests = true
- end
-end
-
-ActiveRecord::Base.singleton_class.prepend(::Database::ActiveRecordBaseEstablishConnection) # rubocop:disable Database/MultipleDatabases
diff --git a/spec/support/database/query_recorder.rb b/spec/support/database/query_recorder.rb
new file mode 100644
index 00000000000..1050120e528
--- /dev/null
+++ b/spec/support/database/query_recorder.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+RSpec.configure do |config|
+ # Truncate the query_recorder log file before starting the suite
+ config.before(:suite) do
+ log_path = Rails.root.join(Gitlab::Database::QueryAnalyzers::QueryRecorder::LOG_FILE)
+ File.write(log_path, '') if File.exist?(log_path)
+ end
+end
diff --git a/spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb b/spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb
index e02bf66507a..e9a13f7bf63 100644
--- a/spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb
+++ b/spec/support/gitlab/usage/metrics_instrumentation_shared_examples.rb
@@ -10,8 +10,8 @@ RSpec.shared_examples 'a correct instrumented metric value' do |params|
end
before do
- if described_class.respond_to?(:relation) && described_class.relation.respond_to?(:connection)
- allow(described_class.relation.connection).to receive(:transaction_open?).and_return(false)
+ if metric.respond_to?(:relation, true) && metric.send(:relation).respond_to?(:connection)
+ allow(metric.send(:relation).connection).to receive(:transaction_open?).and_return(false)
end
end
diff --git a/spec/support/google_api/cloud_platform_helpers.rb b/spec/support/google_api/cloud_platform_helpers.rb
index 840f948e377..b9752577c76 100644
--- a/spec/support/google_api/cloud_platform_helpers.rb
+++ b/spec/support/google_api/cloud_platform_helpers.rb
@@ -157,7 +157,7 @@ module GoogleApi
def cloud_platform_projects_billing_info_body(project_id, billing_enabled)
{
"name": "projects/#{project_id}/billingInfo",
- "projectId": "#{project_id}",
+ "projectId": project_id.to_s,
"billingAccountName": "account-name",
"billingEnabled": billing_enabled
}
diff --git a/spec/support/helpers/bare_repo_operations.rb b/spec/support/helpers/bare_repo_operations.rb
deleted file mode 100644
index e29e12a15f6..00000000000
--- a/spec/support/helpers/bare_repo_operations.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# frozen_string_literal: true
-
-require 'zlib'
-
-class BareRepoOperations
- include Gitlab::Popen
-
- def initialize(path_to_repo)
- @path_to_repo = path_to_repo
- end
-
- def commit_tree(tree_id, msg, parent: Gitlab::Git::EMPTY_TREE_ID)
- commit_tree_args = ['commit-tree', tree_id, '-m', msg]
- commit_tree_args += ['-p', parent] unless parent == Gitlab::Git::EMPTY_TREE_ID
- commit_id = execute(commit_tree_args)
-
- commit_id[0]
- end
-
- private
-
- def execute(args, allow_failure: false)
- output, status = popen(base_args + args, nil) do |stdin|
- yield stdin if block_given?
- end
-
- unless status == 0
- if allow_failure
- return []
- else
- raise "Got a non-zero exit code while calling out `#{args.join(' ')}`: #{output}"
- end
- end
-
- output.split("\n")
- end
-
- def base_args
- [
- Gitlab.config.git.bin_path,
- "--git-dir=#{@path_to_repo}"
- ]
- end
-end
diff --git a/spec/support/helpers/ci/template_helpers.rb b/spec/support/helpers/ci/template_helpers.rb
index 2e9b6f748cd..2cdd242ac22 100644
--- a/spec/support/helpers/ci/template_helpers.rb
+++ b/spec/support/helpers/ci/template_helpers.rb
@@ -5,6 +5,51 @@ module Ci
def template_registry_host
'registry.gitlab.com'
end
+
+ def public_image_exist?(registry, repository, image)
+ public_image_manifest(registry, repository, image).present?
+ end
+
+ def public_image_manifest(registry, repository, reference)
+ token = public_image_repository_token(registry, repository)
+
+ response = with_net_connect_allowed do
+ Gitlab::HTTP.get(image_manifest_url(registry, repository, reference),
+ headers: { 'Authorization' => "Bearer #{token}" })
+ end
+
+ return unless response.success?
+
+ Gitlab::Json.parse(response.body)
+ end
+
+ def public_image_repository_token(registry, repository)
+ @public_image_repository_tokens ||= {}
+ @public_image_repository_tokens[[registry, repository]] ||=
+ begin
+ response = with_net_connect_allowed do
+ Gitlab::HTTP.get(image_manifest_url(registry, repository, 'latest'))
+ end
+
+ return unless response.unauthorized?
+
+ www_authenticate = response.headers['www-authenticate']
+ return unless www_authenticate
+
+ realm, service, scope = www_authenticate.split(',').map { |s| s[/\w+="(.*)"/, 1] }
+ token_response = with_net_connect_allowed do
+ Gitlab::HTTP.get(realm, query: { service: service, scope: scope })
+ end
+
+ return unless token_response.success?
+
+ token_response['token']
+ end
+ end
+
+ def image_manifest_url(registry, repository, reference)
+ "#{registry}/v2/#{repository}/manifests/#{reference}"
+ end
end
end
diff --git a/spec/support/helpers/content_security_policy_helpers.rb b/spec/support/helpers/content_security_policy_helpers.rb
index c9f15e65c74..230075ead70 100644
--- a/spec/support/helpers/content_security_policy_helpers.rb
+++ b/spec/support/helpers/content_security_policy_helpers.rb
@@ -1,20 +1,14 @@
# frozen_string_literal: true
module ContentSecurityPolicyHelpers
- # Expecting 2 calls to current_content_security_policy by default, once for
- # the call that's being tested and once for the call in ApplicationController
- def setup_csp_for_controller(controller_class, times = 2)
+ # Expecting 2 calls to current_content_security_policy by default:
+ # 1. call that's being tested
+ # 2. call in ApplicationController
+ def setup_csp_for_controller(controller_class, csp = ActionDispatch::ContentSecurityPolicy.new, times: 2)
expect_next_instance_of(controller_class) do |controller|
- expect(controller).to receive(:current_content_security_policy)
- .and_return(ActionDispatch::ContentSecurityPolicy.new).exactly(times).times
- end
- end
-
- # Expecting 2 calls to current_content_security_policy by default, once for
- # the call that's being tested and once for the call in ApplicationController
- def setup_existing_csp_for_controller(controller_class, csp, times = 2)
- expect_next_instance_of(controller_class) do |controller|
- expect(controller).to receive(:current_content_security_policy).and_return(csp).exactly(times).times
+ expect(controller)
+ .to receive(:current_content_security_policy).exactly(times).times
+ .and_return(csp)
end
end
end
diff --git a/spec/support/helpers/database/multiple_databases_helpers.rb b/spec/support/helpers/database/multiple_databases_helpers.rb
new file mode 100644
index 00000000000..16f5168ca29
--- /dev/null
+++ b/spec/support/helpers/database/multiple_databases_helpers.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+module Database
+ module MultipleDatabasesHelpers
+ def skip_if_multiple_databases_not_setup
+ skip 'Skipping because multiple databases not set up' unless Gitlab::Database.has_config?(:ci)
+ end
+
+ def skip_if_multiple_databases_are_setup
+ skip 'Skipping because multiple databases are set up' if Gitlab::Database.has_config?(:ci)
+ end
+
+ def reconfigure_db_connection(name: nil, config_hash: {}, model: ActiveRecord::Base, config_model: nil)
+ db_config = (config_model || model).connection_db_config
+
+ new_db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new(
+ db_config.env_name,
+ name ? name.to_s : db_config.name,
+ db_config.configuration_hash.merge(config_hash)
+ )
+
+ model.establish_connection(new_db_config)
+ end
+
+ def ensure_schema_and_empty_tables
+ # Ensure all schemas for both databases are migrated back
+ Gitlab::Database.database_base_models.each do |_, base_model|
+ with_reestablished_active_record_base do
+ reconfigure_db_connection(
+ model: ActiveRecord::Base,
+ config_model: base_model
+ )
+
+ delete_from_all_tables!(except: deletion_except_tables)
+ schema_migrate_up!
+ end
+ end
+
+ # ActiveRecord::Base.clear_all_connections! disconnects and clears attribute methods
+ # Force a refresh to avoid schema failures.
+ reset_column_in_all_models
+ refresh_attribute_methods
+ end
+
+ # The usage of this method switches temporarily used `connection_handler`
+ # allowing full manipulation of ActiveRecord::Base connections without
+ # having side effects like:
+ # - misaligned transactions since this is managed by `BeforeAllAdapter`
+ # - removal of primary connections
+ #
+ # The execution within a block ensures safe cleanup of all allocated resources.
+ #
+ # rubocop:disable Database/MultipleDatabases
+ def with_reestablished_active_record_base(reconnect: true)
+ connection_classes = ActiveRecord::Base
+ .connection_handler
+ .connection_pool_names
+ .map(&:constantize)
+ .index_with(&:connection_db_config)
+
+ original_handler = ActiveRecord::Base.connection_handler
+ new_handler = ActiveRecord::ConnectionAdapters::ConnectionHandler.new
+ ActiveRecord::Base.connection_handler = new_handler
+
+ connection_classes.each { |klass, db_config| klass.establish_connection(db_config) } if reconnect
+
+ yield
+ ensure
+ ActiveRecord::Base.connection_handler = original_handler
+ new_handler&.clear_all_connections!
+ end
+ # rubocop:enable Database/MultipleDatabases
+
+ def with_added_ci_connection
+ if Gitlab::Database.has_config?(:ci)
+ # No need to add a ci: connection if we already have one
+ yield
+ else
+ with_reestablished_active_record_base(reconnect: true) do
+ reconfigure_db_connection(
+ name: :ci,
+ model: Ci::ApplicationRecord,
+ config_model: ActiveRecord::Base
+ )
+
+ yield
+
+ # Cleanup connection_specification_name for Ci::ApplicationRecord
+ Ci::ApplicationRecord.remove_connection
+ end
+ end
+ end
+ end
+
+ module ActiveRecordBaseEstablishConnection
+ def establish_connection(*args)
+ # rubocop:disable Database/MultipleDatabases
+ if connected? &&
+ connection&.transaction_open? &&
+ ActiveRecord::Base.connection_handler == ActiveRecord::Base.default_connection_handler
+ raise "Cannot re-establish '#{self}.establish_connection' within an open transaction " \
+ "(#{connection&.open_transactions.to_i}). Use `with_reestablished_active_record_base` " \
+ "instead or add `:reestablished_active_record_base` to rspec context."
+ end
+ # rubocop:enable Database/MultipleDatabases
+
+ super
+ end
+ end
+end
+
+ActiveRecord::Base.singleton_class.prepend(::Database::ActiveRecordBaseEstablishConnection) # rubocop:disable Database/MultipleDatabases
diff --git a/spec/support/helpers/features/access_token_helpers.rb b/spec/support/helpers/features/access_token_helpers.rb
new file mode 100644
index 00000000000..f4bdb70c160
--- /dev/null
+++ b/spec/support/helpers/features/access_token_helpers.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+module Spec
+ module Support
+ module Helpers
+ module AccessTokenHelpers
+ def active_access_tokens
+ find("[data-testid='active-tokens']")
+ end
+
+ def created_access_token
+ within('[data-testid=access-token-section]') do
+ find('[data-testid=toggle-visibility-button]').click
+ find_field('new-access-token').value
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/support/helpers/features/releases_helpers.rb b/spec/support/helpers/features/releases_helpers.rb
index 9cce9c4882d..a24b99bbe61 100644
--- a/spec/support/helpers/features/releases_helpers.rb
+++ b/spec/support/helpers/features/releases_helpers.rb
@@ -39,7 +39,7 @@ module Spec
wait_for_all_requests
- click_button("#{branch_name}")
+ click_button(branch_name.to_s)
end
end
diff --git a/spec/support/helpers/filter_spec_helper.rb b/spec/support/helpers/filter_spec_helper.rb
index ca844b33ba8..7beed9c7755 100644
--- a/spec/support/helpers/filter_spec_helper.rb
+++ b/spec/support/helpers/filter_spec_helper.rb
@@ -90,10 +90,11 @@ module FilterSpecHelper
#
# Returns a String
def invalidate_reference(reference)
- if reference =~ /\A(.+)?[^\d]\d+\z/
+ case reference
+ when /\A(.+)?[^\d]\d+\z/
# Integer-based reference with optional project prefix
reference.gsub(/\d+\z/) { |i| i.to_i + 10_000 }
- elsif reference =~ /\A(.+@)?(\h{7,40}\z)/
+ when /\A(.+@)?(\h{7,40}\z)/
# SHA-based reference with optional prefix
reference.gsub(/\h{7,40}\z/) { |v| v.reverse }
else
diff --git a/spec/support/helpers/filtered_search_helpers.rb b/spec/support/helpers/filtered_search_helpers.rb
index 93122ca3d0c..677cea7b804 100644
--- a/spec/support/helpers/filtered_search_helpers.rb
+++ b/spec/support/helpers/filtered_search_helpers.rb
@@ -254,6 +254,10 @@ module FilteredSearchHelpers
expect(page).to have_css '.gl-filtered-search-token', text: "Assignee = #{value}"
end
+ def expect_unioned_assignee_token(value)
+ expect(page).to have_css '.gl-filtered-search-token', text: "Assignee is one of #{value}"
+ end
+
def expect_author_token(value)
expect(page).to have_css '.gl-filtered-search-token', text: "Author = #{value}"
end
diff --git a/spec/support/helpers/full_name_helper.rb b/spec/support/helpers/full_name_helper.rb
new file mode 100644
index 00000000000..a41c0da74d4
--- /dev/null
+++ b/spec/support/helpers/full_name_helper.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module FullNameHelper
+ def full_name(first_name, last_name)
+ "#{first_name} #{last_name}"
+ end
+end
+
+FullNameHelper.prepend_mod
diff --git a/spec/support/helpers/git_helpers.rb b/spec/support/helpers/git_helpers.rb
deleted file mode 100644
index 72bba419116..00000000000
--- a/spec/support/helpers/git_helpers.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-module GitHelpers
- def rugged_repo(repository)
- path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- File.join(TestEnv.repos_path, repository.disk_path + '.git')
- end
-
- Rugged::Repository.new(path)
- end
-end
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index b2fc6ae3286..bd0efc96bd8 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -378,7 +378,7 @@ module GraphqlHelpers
def field_with_params(name, attributes = {})
namerized = GraphqlHelpers.fieldnamerize(name.to_s)
- return "#{namerized}" if attributes.blank?
+ return namerized.to_s if attributes.blank?
field_params = if attributes.is_a?(Hash)
"(#{attributes_to_graphql(attributes)})"
diff --git a/spec/support/helpers/kubernetes_helpers.rb b/spec/support/helpers/kubernetes_helpers.rb
index 912e7d24b25..72524453f34 100644
--- a/spec/support/helpers/kubernetes_helpers.rb
+++ b/spec/support/helpers/kubernetes_helpers.rb
@@ -142,6 +142,29 @@ module KubernetesHelpers
WebMock.stub_request(method, ingresses_url).to_return(response)
end
+ def stub_server_min_version_failed_request
+ WebMock.stub_request(:get, service.api_url + '/version').to_return(
+ status: [500, "Internal Server Error"],
+ body: {}.to_json)
+ end
+
+ def stub_server_min_version(min_version)
+ response = kube_response({
+ "major": "1", # not used, just added here to be a bit more realistic purposes
+ "minor": min_version.to_s
+ })
+
+ WebMock.stub_request( :get, service.api_url + '/version')
+ .with(
+ headers: {
+ 'Accept' => '*/*',
+ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
+ 'Authorization' => 'Bearer aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
+ 'User-Agent' => 'Ruby'
+ })
+ .to_return(response)
+ end
+
def stub_kubeclient_knative_services(options = {})
namespace_path = options[:namespace].present? ? "namespaces/#{options[:namespace]}/" : ""
@@ -537,7 +560,7 @@ module KubernetesHelpers
},
"spec" => {
"containers" => [
- { "name" => "#{container_name}" },
+ { "name" => container_name.to_s },
{ "name" => "#{container_name}-1" }
]
},
diff --git a/spec/support/helpers/navbar_structure_helper.rb b/spec/support/helpers/navbar_structure_helper.rb
index b44552d6479..e1ed3ffacec 100644
--- a/spec/support/helpers/navbar_structure_helper.rb
+++ b/spec/support/helpers/navbar_structure_helper.rb
@@ -90,7 +90,11 @@ module NavbarStructureHelper
_('Kubernetes'),
new_nav_item: {
nav_item: _('Observability'),
- nav_sub_items: []
+ nav_sub_items: [
+ _('Dashboards'),
+ _('Explore'),
+ _('Manage Dashboards')
+ ]
}
)
end
diff --git a/spec/support/helpers/reference_parser_helpers.rb b/spec/support/helpers/reference_parser_helpers.rb
index b9796ebbe62..370dedabd9b 100644
--- a/spec/support/helpers/reference_parser_helpers.rb
+++ b/spec/support/helpers/reference_parser_helpers.rb
@@ -12,14 +12,14 @@ module ReferenceParserHelpers
end
RSpec.shared_examples 'no project N+1 queries' do
- it 'avoids N+1 queries in #nodes_visible_to_user' do
+ it 'avoids N+1 queries in #nodes_visible_to_user', :use_sql_query_cache do
context = Banzai::RenderContext.new(project, user)
request = lambda do |links|
described_class.new(context).nodes_visible_to_user(user, links)
end
- control = ActiveRecord::QueryRecorder.new { request.call(control_links) }
+ control = ActiveRecord::QueryRecorder.new(skip_cached: false) { request.call(control_links) }
create(:group_member, group: project.group) if project.group
create(:project_member, project: project)
diff --git a/spec/support/helpers/search_helpers.rb b/spec/support/helpers/search_helpers.rb
index 581ef07752e..7d0f8c09933 100644
--- a/spec/support/helpers/search_helpers.rb
+++ b/spec/support/helpers/search_helpers.rb
@@ -33,13 +33,13 @@ module SearchHelpers
end
def select_search_scope(scope)
- page.within '.search-filter' do
+ page.within '[data-testid="search-filter"]' do
click_link scope
end
end
def has_search_scope?(scope)
- page.within '.search-filter' do
+ page.within '[data-testid="search-filter"]' do
has_link?(scope)
end
end
diff --git a/spec/support/helpers/stub_configuration.rb b/spec/support/helpers/stub_configuration.rb
index f41457d2420..24c768258a1 100644
--- a/spec/support/helpers/stub_configuration.rb
+++ b/spec/support/helpers/stub_configuration.rb
@@ -38,6 +38,10 @@ module StubConfiguration
allow(Rails.application.routes).to receive(:default_url_options).and_return(url_options)
end
+ def stub_dependency_proxy_setting(messages)
+ allow(Gitlab.config.dependency_proxy).to receive_messages(to_settings(messages))
+ end
+
def stub_gravatar_setting(messages)
allow(Gitlab.config.gravatar).to receive_messages(to_settings(messages))
end
diff --git a/spec/support/helpers/stub_feature_flags.rb b/spec/support/helpers/stub_feature_flags.rb
index f1654e55b7e..e301e29afc2 100644
--- a/spec/support/helpers/stub_feature_flags.rb
+++ b/spec/support/helpers/stub_feature_flags.rb
@@ -37,6 +37,10 @@ module StubFeatureFlags
# Enable `ci_live_trace` feature flag only on the specified projects.
def stub_feature_flags(features)
features.each do |feature_name, actors|
+ unless Feature::Definition.get(feature_name)
+ ActiveSupport::Deprecation.warn "Invalid Feature Flag #{feature_name} stubbed"
+ end
+
# Remove feature flag overwrite
feature = Feature.get(feature_name) # rubocop:disable Gitlab/AvoidFeatureGet
feature.remove
diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb
index c58353558df..e1b461cf37e 100644
--- a/spec/support/helpers/test_env.rb
+++ b/spec/support/helpers/test_env.rb
@@ -11,6 +11,8 @@ module TestEnv
# When developing the seed repository, comment out the branch you will modify.
BRANCH_SHA = {
'signed-commits' => 'c7794c1',
+ 'gpg-signed' => '8a852d5',
+ 'x509-signed' => 'a4df3c8',
'not-merged-branch' => 'b83d6e3',
'branch-merged' => '498214d',
'empty-branch' => '7efb185',
@@ -43,7 +45,7 @@ module TestEnv
'video' => '8879059',
'crlf-diff' => '5938907',
'conflict-start' => '824be60',
- 'conflict-resolvable' => '1450cd6',
+ 'conflict-resolvable' => '1450cd639e0bc6721eb02800169e464f212cde06',
'conflict-binary-file' => '259a6fb',
'conflict-contains-conflict-markers' => '78a3086',
'conflict-missing-side' => 'eb227b3',
@@ -282,15 +284,30 @@ module TestEnv
unless File.directory?(repo_path)
start = Time.now
system(*%W(#{Gitlab.config.git.bin_path} clone --quiet -- #{clone_url} #{repo_path}))
- system(*%W(#{Gitlab.config.git.bin_path} -C #{repo_path} remote remove origin))
puts "==> #{repo_path} set up in #{Time.now - start} seconds...\n"
end
- set_repo_refs(repo_path, refs)
+ create_bundle = !File.file?(repo_bundle_path)
- unless File.file?(repo_bundle_path)
+ unless set_repo_refs(repo_path, refs)
+ # Prefer not to fetch over the network. Only fetch when we have failed to
+ # set all the required local branches. This would happen when a new
+ # branch is added to BRANCH_SHA, in which case we want to update
+ # everything.
+ unless system(*%W(#{Gitlab.config.git.bin_path} -C #{repo_path} fetch origin))
+ raise 'Could not fetch test seed repository.'
+ end
+
+ unless set_repo_refs(repo_path, refs)
+ raise "Could not update test seed repository, please delete #{repo_path} and try again"
+ end
+
+ create_bundle = true
+ end
+
+ if create_bundle
start = Time.now
- system(git_env, *%W(#{Gitlab.config.git.bin_path} -C #{repo_path} bundle create #{repo_bundle_path} --all))
+ system(git_env, *%W(#{Gitlab.config.git.bin_path} -C #{repo_path} bundle create #{repo_bundle_path} --exclude refs/remotes/* --all))
puts "==> #{repo_bundle_path} generated in #{Time.now - start} seconds...\n"
end
end
@@ -392,20 +409,13 @@ module TestEnv
end
def set_repo_refs(repo_path, branch_sha)
- instructions = branch_sha.map { |branch, sha| "update refs/heads/#{branch}\x00#{sha}\x00" }.join("\x00") << "\x00"
- update_refs = %W(#{Gitlab.config.git.bin_path} update-ref --stdin -z)
- reset = proc do
- Dir.chdir(repo_path) do
- IO.popen(update_refs, "w") { |io| io.write(instructions) }
- $?.success?
+ IO.popen(%W[#{Gitlab.config.git.bin_path} -C #{repo_path} update-ref --stdin -z], "w") do |io|
+ branch_sha.each do |branch, sha|
+ io.write("update refs/heads/#{branch}\x00#{sha}\x00\x00")
end
end
- # Try to reset without fetching to avoid using the network.
- unless reset.call
- raise 'Could not fetch test seed repository.' unless system(*%W(#{Gitlab.config.git.bin_path} -C #{repo_path} fetch origin))
- raise "Could not update test seed repository, please delete #{repo_path} and try again" unless reset.call
- end
+ $?.success?
end
def component_timed_setup(component, install_dir:, version:, task:, fresh_install: true, task_args: [])
diff --git a/spec/support/helpers/usage_data_helpers.rb b/spec/support/helpers/usage_data_helpers.rb
index b4f0cbd8527..92a946db337 100644
--- a/spec/support/helpers/usage_data_helpers.rb
+++ b/spec/support/helpers/usage_data_helpers.rb
@@ -67,24 +67,12 @@ module UsageDataHelpers
projects_with_repositories_enabled
projects_with_error_tracking_enabled
projects_with_enabled_alert_integrations
- projects_with_expiration_policy_enabled
- projects_with_expiration_policy_enabled_with_keep_n_unset
- projects_with_expiration_policy_enabled_with_keep_n_set_to_1
- projects_with_expiration_policy_enabled_with_keep_n_set_to_5
- projects_with_expiration_policy_enabled_with_keep_n_set_to_10
- projects_with_expiration_policy_enabled_with_keep_n_set_to_25
- projects_with_expiration_policy_enabled_with_keep_n_set_to_50
projects_with_expiration_policy_enabled_with_older_than_unset
projects_with_expiration_policy_enabled_with_older_than_set_to_7d
projects_with_expiration_policy_enabled_with_older_than_set_to_14d
projects_with_expiration_policy_enabled_with_older_than_set_to_30d
projects_with_expiration_policy_enabled_with_older_than_set_to_60d
projects_with_expiration_policy_enabled_with_older_than_set_to_90d
- projects_with_expiration_policy_enabled_with_cadence_set_to_1d
- projects_with_expiration_policy_enabled_with_cadence_set_to_7d
- projects_with_expiration_policy_enabled_with_cadence_set_to_14d
- projects_with_expiration_policy_enabled_with_cadence_set_to_1month
- projects_with_expiration_policy_enabled_with_cadence_set_to_3month
projects_with_terraform_reports
projects_with_terraform_states
pages_domains
diff --git a/spec/support/matchers/exceed_query_limit.rb b/spec/support/matchers/exceed_query_limit.rb
index bfcaf9552b3..6d7658b7c33 100644
--- a/spec/support/matchers/exceed_query_limit.rb
+++ b/spec/support/matchers/exceed_query_limit.rb
@@ -333,7 +333,7 @@ RSpec::Matchers.define :issue_same_number_of_queries_as do
or_fewer_msg = "or fewer" if @or_fewer
threshold_msg = "(+/- #{threshold})" unless threshold == 0
- ["#{expected_count}", or_fewer_msg, threshold_msg].compact.join(' ')
+ [expected_count.to_s, or_fewer_msg, threshold_msg].compact.join(' ')
end
def skip_cached
diff --git a/spec/support/matchers/graphql_matchers.rb b/spec/support/matchers/graphql_matchers.rb
index db7d4269945..155a6dba52c 100644
--- a/spec/support/matchers/graphql_matchers.rb
+++ b/spec/support/matchers/graphql_matchers.rb
@@ -169,7 +169,11 @@ RSpec::Matchers.define :have_graphql_type do |expected, opts = {}|
include GraphQLTypeHelpers
match do |object|
- expect(object.type).to eq(nullified(expected, opts[:null]))
+ if object.type.list?
+ expect(object.type.unwrap).to eq(nullified(expected, opts[:null]))
+ else
+ expect(object.type).to eq(nullified(expected, opts[:null]))
+ end
end
failure_message do |object|
diff --git a/spec/support/migration.rb b/spec/support/migration.rb
index 490aa836d74..2a69630a29a 100644
--- a/spec/support/migration.rb
+++ b/spec/support/migration.rb
@@ -16,14 +16,42 @@ RSpec.configure do |config|
schema_migrate_down!
end
+ config.after(:context, :migration) do
+ Gitlab::CurrentSettings.clear_in_memory_application_settings!
+ end
+
+ config.append_after(:context, :migration) do
+ recreate_databases_and_seed_if_needed || ensure_schema_and_empty_tables
+ end
+
+ config.around(:each, :migration) do |example|
+ self.class.use_transactional_tests = false
+
+ migration_schema = example.metadata[:migration]
+ migration_schema = :gitlab_main if migration_schema == true
+ base_model = Gitlab::Database.schemas_to_base_models.fetch(migration_schema).first
+
+ # Migration require an `ActiveRecord::Base` to point to desired database
+ if base_model != ActiveRecord::Base
+ with_reestablished_active_record_base do
+ reconfigure_db_connection(
+ model: ActiveRecord::Base,
+ config_model: base_model
+ )
+
+ example.run
+ end
+ else
+ example.run
+ end
+
+ self.class.use_transactional_tests = true
+ end
+
# Each example may call `migrate!`, so we must ensure we are migrated down every time
config.before(:each, :migration) do
use_fake_application_settings
schema_migrate_down!
end
-
- config.after(:context, :migration) do
- Gitlab::CurrentSettings.clear_in_memory_application_settings!
- end
end
diff --git a/spec/support/models/ci/partitioning_testing/cascade_check.rb b/spec/support/models/ci/partitioning_testing/cascade_check.rb
new file mode 100644
index 00000000000..f553a47ef4f
--- /dev/null
+++ b/spec/support/models/ci/partitioning_testing/cascade_check.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module PartitioningTesting
+ module CascadeCheck
+ extend ActiveSupport::Concern
+
+ included do
+ after_create :check_partition_cascade_value
+ end
+
+ def check_partition_cascade_value
+ raise 'Partition value not found' unless partition_scope_value
+
+ return if partition_id == partition_scope_value
+
+ raise "partition_id was expected to equal #{partition_scope_value} but it was #{partition_id}."
+ end
+ end
+end
+
+Ci::Partitionable::Testing::PARTITIONABLE_MODELS.each do |klass|
+ next if klass == 'Ci::Pipeline'
+
+ model = klass.safe_constantize
+
+ model.include(PartitioningTesting::CascadeCheck)
+end
diff --git a/spec/support/models/ci/partitioning_testing/partition_identifiers.rb b/spec/support/models/ci/partitioning_testing/partition_identifiers.rb
new file mode 100644
index 00000000000..aa091095fb6
--- /dev/null
+++ b/spec/support/models/ci/partitioning_testing/partition_identifiers.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module Ci
+ module PartitioningTesting
+ module PartitionIdentifiers
+ module_function
+
+ def ci_testing_partition_id
+ 99999
+ end
+ end
+ end
+end
diff --git a/spec/support/models/ci/partitioning_testing/rspec_hooks.rb b/spec/support/models/ci/partitioning_testing/rspec_hooks.rb
new file mode 100644
index 00000000000..39b15ba8721
--- /dev/null
+++ b/spec/support/models/ci/partitioning_testing/rspec_hooks.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+RSpec.configure do |config|
+ config.include Ci::PartitioningTesting::PartitionIdentifiers
+
+ config.around(:each, :ci_partitionable) do |example|
+ Ci::PartitioningTesting::SchemaHelpers.with_routing_tables do
+ example.run
+ end
+ end
+
+ config.before(:all) do
+ Ci::PartitioningTesting::SchemaHelpers.setup
+ end
+
+ config.after(:all) do
+ Ci::PartitioningTesting::SchemaHelpers.teardown
+ end
+end
diff --git a/spec/support/models/ci/partitioning_testing/schema_helpers.rb b/spec/support/models/ci/partitioning_testing/schema_helpers.rb
new file mode 100644
index 00000000000..712178710da
--- /dev/null
+++ b/spec/support/models/ci/partitioning_testing/schema_helpers.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+
+module Ci
+ module PartitioningTesting
+ module SchemaHelpers
+ DEFAULT_PARTITION = 100
+
+ module_function
+
+ def with_routing_tables
+ Ci::BuildMetadata.table_name = :p_ci_builds_metadata
+ yield
+ ensure
+ Ci::BuildMetadata.table_name = :ci_builds_metadata
+ end
+
+ # We're dropping the default values here to ensure that the application code
+ # populates the `partition_id` value and it's not falling back on the
+ # database default one. We should be able to clean this up after
+ # partitioning the tables and substituting the routing table in the model:
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/377822
+ #
+ def setup(connection: Ci::ApplicationRecord.connection)
+ each_partitionable_table do |table_name|
+ change_column_default(table_name, from: DEFAULT_PARTITION, to: nil, connection: connection)
+ change_column_default("p_#{table_name}", from: DEFAULT_PARTITION, to: nil, connection: connection)
+ create_test_partition(table_name, connection: connection)
+ end
+ end
+
+ def teardown(connection: Ci::ApplicationRecord.connection)
+ each_partitionable_table do |table_name|
+ drop_test_partition(table_name, connection: connection)
+ change_column_default(table_name, from: nil, to: DEFAULT_PARTITION, connection: connection)
+ change_column_default("p_#{table_name}", from: nil, to: DEFAULT_PARTITION, connection: connection)
+ end
+ end
+
+ def each_partitionable_table
+ ::Ci::Partitionable::Testing::PARTITIONABLE_MODELS.each do |klass|
+ model = klass.safe_constantize
+ table_name = model.table_name.delete_prefix('p_')
+
+ yield(table_name)
+
+ model.reset_column_information if model.connected?
+ end
+ end
+
+ def change_column_default(table_name, from:, to:, connection:)
+ return unless table_available?(table_name, connection: connection)
+
+ connection.change_column_default(table_name, :partition_id, from: from, to: to)
+ end
+
+ def create_test_partition(table_name, connection:)
+ return unless table_available?("p_#{table_name}", connection: connection)
+
+ drop_test_partition(table_name, connection: connection)
+
+ connection.execute(<<~SQL)
+ CREATE TABLE #{full_partition_name(table_name)}
+ PARTITION OF p_#{table_name}
+ FOR VALUES IN (#{PartitioningTesting::PartitionIdentifiers.ci_testing_partition_id});
+ SQL
+ end
+
+ def drop_test_partition(table_name, connection:)
+ return unless table_available?(table_name, connection: connection)
+
+ connection.execute(<<~SQL)
+ DROP TABLE IF EXISTS #{full_partition_name(table_name)};
+ SQL
+ end
+
+ def table_available?(table_name, connection:)
+ connection.table_exists?(table_name) &&
+ connection.column_exists?(table_name, :partition_id)
+ end
+
+ def full_partition_name(table_name)
+ "#{Gitlab::Database::DYNAMIC_PARTITIONS_SCHEMA}._test_gitlab_#{table_name}_partition"
+ end
+ end
+ end
+end
diff --git a/spec/support/models/partitionable_check.rb b/spec/support/models/partitionable_check.rb
deleted file mode 100644
index 2c09c1b3408..00000000000
--- a/spec/support/models/partitionable_check.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# frozen_string_literal: true
-
-module PartitioningTesting
- module CascadeCheck
- extend ActiveSupport::Concern
-
- included do
- after_create :check_partition_cascade_value
- end
-
- def check_partition_cascade_value
- raise 'Partition value not found' unless partition_scope_value
- raise 'Default value detected' if partition_id == 100
-
- return if partition_id == partition_scope_value
-
- raise "partition_id was expected to equal #{partition_scope_value} but it was #{partition_id}."
- end
- end
-
- module DefaultPartitionValue
- extend ActiveSupport::Concern
-
- class_methods do
- def current_partition_value
- current = super
-
- if current == 100
- 54321
- else
- current
- end
- end
- end
- end
-end
-
-Ci::Partitionable::Testing::PARTITIONABLE_MODELS.each do |klass|
- model = klass.safe_constantize
-
- if klass == 'Ci::Pipeline'
- model.prepend(PartitioningTesting::DefaultPartitionValue)
- else
- model.include(PartitioningTesting::CascadeCheck)
- end
-end
diff --git a/spec/support/multiple_databases.rb b/spec/support/multiple_databases.rb
new file mode 100644
index 00000000000..616cf00269c
--- /dev/null
+++ b/spec/support/multiple_databases.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+RSpec.configure do |config|
+ # Ensure database versions are memoized to prevent query counts from
+ # being affected by version checks. Note that
+ # Gitlab::Database.check_postgres_version_and_print_warning is called
+ # at startup, but that generates its own
+ # `Gitlab::Database::Reflection` so the result is not memoized by
+ # callers of `ApplicationRecord.database.version`, such as
+ # `Gitlab::Database::AsWithMaterialized.materialized_supported?`.
+ # TODO This can be removed once https://gitlab.com/gitlab-org/gitlab/-/issues/325639 is completed.
+ [ApplicationRecord, ::Ci::ApplicationRecord].each { |record| record.database.version }
+
+ config.around(:each, :reestablished_active_record_base) do |example|
+ with_reestablished_active_record_base(reconnect: example.metadata.fetch(:reconnect, true)) do
+ example.run
+ end
+ end
+
+ config.around(:each, :add_ci_connection) do |example|
+ with_added_ci_connection do
+ example.run
+ end
+ end
+end
diff --git a/spec/support/rate_limiter.rb b/spec/support/rate_limiter.rb
new file mode 100644
index 00000000000..525d593c293
--- /dev/null
+++ b/spec/support/rate_limiter.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+RSpec.configure do |config|
+ config.before(:each, :disable_rate_limiter) do
+ allow(Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(false)
+ end
+end
diff --git a/spec/support/redis.rb b/spec/support/redis.rb
index d00d6562966..6d313c8aa16 100644
--- a/spec/support/redis.rb
+++ b/spec/support/redis.rb
@@ -19,4 +19,10 @@ RSpec.configure do |config|
public_send("redis_#{underscored_name}_cleanup!")
end
end
+
+ config.before(:suite) do
+ Gitlab::Redis::ALL_CLASSES.each do |instance_class|
+ instance_class.with(&:flushdb)
+ end
+ end
end
diff --git a/spec/support/rspec.rb b/spec/support/rspec.rb
index 6795d2f6d2a..71dfc3fd5a3 100644
--- a/spec/support/rspec.rb
+++ b/spec/support/rspec.rb
@@ -11,6 +11,9 @@ require_relative "helpers/fast_rails_root"
RSpec::Expectations.configuration.on_potential_false_positives = :raise
RSpec.configure do |config|
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/379686
+ config.threadsafe = false
+
# Re-run failures locally with `--only-failures`
config.example_status_persistence_file_path = ENV.fetch('RSPEC_LAST_RUN_RESULTS_FILE', './spec/examples.txt')
diff --git a/spec/support/rspec_order_todo.yml b/spec/support/rspec_order_todo.yml
index 30220b04fa2..67b7023f1ff 100644
--- a/spec/support/rspec_order_todo.yml
+++ b/spec/support/rspec_order_todo.yml
@@ -997,7 +997,6 @@
- './ee/spec/graphql/types/vulnerability_severity_enum_spec.rb'
- './ee/spec/graphql/types/vulnerability_sort_enum_spec.rb'
- './ee/spec/graphql/types/vulnerability_state_enum_spec.rb'
-- './ee/spec/graphql/types/vulnerability_type_spec.rb'
- './ee/spec/graphql/types/vulnerable_dependency_type_spec.rb'
- './ee/spec/graphql/types/vulnerable_kubernetes_resource_type_spec.rb'
- './ee/spec/graphql/types/vulnerable_package_type_spec.rb'
@@ -1870,7 +1869,6 @@
- './ee/spec/models/ee/ci/secure_file_spec.rb'
- './ee/spec/models/ee/clusters/agent_spec.rb'
- './ee/spec/models/ee/description_version_spec.rb'
-- './ee/spec/models/ee/event_collection_spec.rb'
- './ee/spec/models/ee/event_spec.rb'
- './ee/spec/models/ee/gpg_key_spec.rb'
- './ee/spec/models/ee/group_group_link_spec.rb'
@@ -3223,7 +3221,6 @@
- './ee/spec/services/security/security_orchestration_policies/sync_opened_merge_requests_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/validate_policy_service_spec.rb'
-- './ee/spec/services/security/store_findings_metadata_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'
@@ -3379,7 +3376,6 @@
- './ee/spec/views/registrations/welcome/continuous_onboarding_getting_started.html.haml_spec.rb'
- './ee/spec/views/registrations/welcome/show.html.haml_spec.rb'
- './ee/spec/views/search/_category.html.haml_spec.rb'
-- './ee/spec/views/shared/access_tokens/_table.html.haml_spec.rb'
- './ee/spec/views/shared/billings/_billing_plan_actions.html.haml_spec.rb'
- './ee/spec/views/shared/billings/_billing_plan.html.haml_spec.rb'
- './ee/spec/views/shared/billings/_billing_plans.html.haml_spec.rb'
@@ -4091,7 +4087,6 @@
- './spec/features/incidents/user_creates_new_incident_spec.rb'
- './spec/features/incidents/user_filters_incidents_by_status_spec.rb'
- './spec/features/incidents/user_searches_incidents_spec.rb'
-- './spec/features/incidents/user_views_incident_spec.rb'
- './spec/features/invites_spec.rb'
- './spec/features/issuables/issuable_list_spec.rb'
- './spec/features/issuables/markdown_references/internal_references_spec.rb'
@@ -5873,14 +5868,6 @@
- './spec/lib/error_tracking/collector/payload_validator_spec.rb'
- './spec/lib/error_tracking/collector/sentry_auth_parser_spec.rb'
- './spec/lib/error_tracking/collector/sentry_request_parser_spec.rb'
-- './spec/lib/error_tracking/sentry_client/api_urls_spec.rb'
-- './spec/lib/error_tracking/sentry_client/event_spec.rb'
-- './spec/lib/error_tracking/sentry_client/issue_link_spec.rb'
-- './spec/lib/error_tracking/sentry_client/issue_spec.rb'
-- './spec/lib/error_tracking/sentry_client/pagination_parser_spec.rb'
-- './spec/lib/error_tracking/sentry_client/projects_spec.rb'
-- './spec/lib/error_tracking/sentry_client/repo_spec.rb'
-- './spec/lib/error_tracking/sentry_client_spec.rb'
- './spec/lib/error_tracking/stacktrace_builder_spec.rb'
- './spec/lib/event_filter_spec.rb'
- './spec/lib/expand_variables_spec.rb'
@@ -8400,7 +8387,6 @@
- './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/event_spec.rb'
- './spec/models/experiment_spec.rb'
- './spec/models/experiment_subject_spec.rb'
@@ -9464,16 +9450,6 @@
- './spec/routing/projects/security/configuration_controller_routing_spec.rb'
- './spec/routing/routing_spec.rb'
- './spec/routing/uploads_routing_spec.rb'
-- './spec/scripts/changed-feature-flags_spec.rb'
-- './spec/scripts/determine-qa-tests_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/update_example_snapshots_spec.rb'
-- './spec/scripts/lib/glfm/update_specification_spec.rb'
-- './spec/scripts/pipeline_test_report_builder_spec.rb'
-- './spec/scripts/setup/find_jh_branch_spec.rb'
-- './spec/scripts/trigger-build_spec.rb'
- './spec/serializers/accessibility_error_entity_spec.rb'
- './spec/serializers/accessibility_reports_comparer_entity_spec.rb'
- './spec/serializers/accessibility_reports_comparer_serializer_spec.rb'
@@ -10082,7 +10058,6 @@
- './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'
@@ -10768,7 +10743,6 @@
- './spec/views/registrations/welcome/show.html.haml_spec.rb'
- './spec/views/search/_results.html.haml_spec.rb'
- './spec/views/search/show.html.haml_spec.rb'
-- './spec/views/shared/access_tokens/_table.html.haml_spec.rb'
- './spec/views/shared/deploy_tokens/_form.html.haml_spec.rb'
- './spec/views/shared/groups/_dropdown.html.haml_spec.rb'
- './spec/views/shared/issuable/_sidebar.html.haml_spec.rb'
@@ -10922,7 +10896,6 @@
- './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/experiments/record_conversion_event_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'
diff --git a/spec/support/services/issuable_update_service_shared_examples.rb b/spec/support/services/issuable_update_service_shared_examples.rb
index 94061b140f4..b85c3904127 100644
--- a/spec/support/services/issuable_update_service_shared_examples.rb
+++ b/spec/support/services/issuable_update_service_shared_examples.rb
@@ -6,18 +6,48 @@ RSpec.shared_examples 'issuable update service' do
end
context 'changing state' do
- before do
- expect(project).to receive(:execute_hooks).once
- end
+ let(:hook_event) { :"#{closed_issuable.class.name.underscore.to_sym}_hooks" }
context 'to reopened' do
- it 'executes hooks only once' do
+ let(:expected_payload) do
+ include(
+ changes: include(
+ state_id: { current: 1, previous: 2 },
+ updated_at: { current: kind_of(Time), previous: kind_of(Time) }
+ ),
+ object_attributes: include(
+ state: 'opened',
+ action: 'reopen'
+ )
+ )
+ end
+
+ it 'executes hooks' do
+ expect(project).to receive(:execute_hooks).with(expected_payload, hook_event)
+ expect(project).to receive(:execute_integrations).with(expected_payload, hook_event)
+
described_class.new(project: project, current_user: user, params: { state_event: 'reopen' }).execute(closed_issuable)
end
end
context 'to closed' do
- it 'executes hooks only once' do
+ let(:expected_payload) do
+ include(
+ changes: include(
+ state_id: { current: 2, previous: 1 },
+ updated_at: { current: kind_of(Time), previous: kind_of(Time) }
+ ),
+ object_attributes: include(
+ state: 'closed',
+ action: 'close'
+ )
+ )
+ end
+
+ it 'executes hooks' do
+ expect(project).to receive(:execute_hooks).with(expected_payload, hook_event)
+ expect(project).to receive(:execute_integrations).with(expected_payload, hook_event)
+
described_class.new(project: project, current_user: user, params: { state_event: 'close' }).execute(open_issuable)
end
end
diff --git a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb
index 1e291a90163..ae98ce689e3 100644
--- a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb
+++ b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb
@@ -57,7 +57,7 @@ RSpec.shared_examples "migrating a deleted user's associated records to the ghos
context "race conditions" do
context "when #{record_class_name} migration fails and is rolled back" do
before do
- expect_any_instance_of(ActiveRecord::Associations::CollectionProxy)
+ allow_any_instance_of(ActiveRecord::Associations::CollectionProxy)
.to receive(:update_all).and_raise(ActiveRecord::StatementTimeout)
end
@@ -68,6 +68,7 @@ RSpec.shared_examples "migrating a deleted user's associated records to the ghos
end
it "doesn't unblock a previously-blocked user" do
+ expect(user.starred_projects).to receive(:update_all).and_call_original
user.block
expect { service.execute }.to raise_error(ActiveRecord::StatementTimeout)
diff --git a/spec/support/shared_contexts/container_repositories_shared_context.rb b/spec/support/shared_contexts/container_repositories_shared_context.rb
index a74b09d38bd..c3040a77517 100644
--- a/spec/support/shared_contexts/container_repositories_shared_context.rb
+++ b/spec/support/shared_contexts/container_repositories_shared_context.rb
@@ -14,7 +14,6 @@ RSpec.shared_context 'importable repositories' do
before do
stub_application_setting(container_registry_import_created_before: 1.day.ago)
stub_feature_flags(
- container_registry_phase_2_deny_list: false,
container_registry_migration_limit_gitlab_org: false,
container_registry_migration_phase2_all_plans: false
)
diff --git a/spec/support/shared_contexts/graphql/resolvers/runners_resolver_shared_context.rb b/spec/support/shared_contexts/graphql/resolvers/runners_resolver_shared_context.rb
index aa857cfdb70..1480b5f98e7 100644
--- a/spec/support/shared_contexts/graphql/resolvers/runners_resolver_shared_context.rb
+++ b/spec/support/shared_contexts/graphql/resolvers/runners_resolver_shared_context.rb
@@ -17,6 +17,6 @@ RSpec.shared_context 'runners resolver setup' do
end
let_it_be(:group_runner) { create(:ci_runner, :group, groups: [group], token: 'mnopqr', description: 'group runner', contacted_at: 2.seconds.ago) }
- let_it_be(:subgroup_runner) { create(:ci_runner, :group, groups: [subgroup], token: 'mnopqr', description: 'subgroup runner', contacted_at: 1.second.ago) }
+ let_it_be(:subgroup_runner) { create(:ci_runner, :group, groups: [subgroup], token: '123456', description: 'subgroup runner', contacted_at: 1.second.ago) }
let_it_be(:instance_runner) { create(:ci_runner, :instance, description: 'shared runner', token: 'stuvxz', contacted_at: 2.minutes.ago, tag_list: %w(instance_runner active_runner)) }
end
diff --git a/spec/support/shared_contexts/jobs/handling_retried_jobs_shared_context.rb b/spec/support/shared_contexts/jobs/handling_retried_jobs_shared_context.rb
new file mode 100644
index 00000000000..428eff77373
--- /dev/null
+++ b/spec/support/shared_contexts/jobs/handling_retried_jobs_shared_context.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'when handling retried jobs' do |url|
+ let(:set_name) { 'retry' }
+ # Account for Sidekiq retry jitter
+ # https://github.com/mperham/sidekiq/blob/3575ccb44c688dd08bfbfd937696260b12c622fb/lib/sidekiq/job_retry.rb#L217
+ let(:schedule_jitter) { 10 }
+
+ # Try to mimic as closely as possible what Sidekiq will actually
+ # do to retry a job.
+ def retry_in(klass, time, args = 0)
+ message = Gitlab::Json.generate(
+ 'class' => klass.name,
+ 'args' => [args],
+ 'retry' => true
+ )
+
+ allow(klass).to receive(:sidekiq_retry_in_block).and_return(proc { time.to_i })
+
+ begin
+ Sidekiq::JobRetry.new(Sidekiq).local(klass, message, klass.queue) { raise 'boom' }
+ rescue Sidekiq::JobRetry::Skip
+ # Sidekiq scheduled the retry
+ end
+ end
+end
diff --git a/spec/support/shared_contexts/lib/sbom/package_url_shared_contexts.rb b/spec/support/shared_contexts/lib/sbom/package_url_shared_contexts.rb
new file mode 100644
index 00000000000..263cf9f5e19
--- /dev/null
+++ b/spec/support/shared_contexts/lib/sbom/package_url_shared_contexts.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'oj'
+
+def parameterized_test_matrix(invalid: false)
+ test_cases_path = File.join(
+ File.expand_path(__dir__), '..', '..', '..', '..', 'fixtures', 'lib', 'sbom', 'package-url-test-cases.json')
+ test_cases = Gitlab::Json.parse(File.read(test_cases_path))
+
+ test_cases.filter { _1.delete('is_invalid') == invalid }.each_with_object({}) do |test_case, memo|
+ description = test_case.delete('description')
+ memo[description] = test_case.symbolize_keys
+ end
+end
+
+RSpec.shared_context 'with valid purl examples' do
+ where do
+ parameterized_test_matrix(invalid: false)
+ end
+end
+
+RSpec.shared_context 'with invalid purl examples' do
+ where do
+ parameterized_test_matrix(invalid: true)
+ end
+end
diff --git a/spec/support/shared_contexts/navbar_structure_context.rb b/spec/support/shared_contexts/navbar_structure_context.rb
index 064e40287be..af35a5ff068 100644
--- a/spec/support/shared_contexts/navbar_structure_context.rb
+++ b/spec/support/shared_contexts/navbar_structure_context.rb
@@ -67,8 +67,8 @@ RSpec.shared_context 'project navbar structure' do
{
nav_item: _('Deployments'),
nav_sub_items: [
- _('Feature Flags'),
_('Environments'),
+ _('Feature Flags'),
_('Releases')
]
},
@@ -85,8 +85,7 @@ RSpec.shared_context 'project navbar structure' do
_('Metrics'),
_('Error Tracking'),
_('Alerts'),
- _('Incidents'),
- _('Product Analytics')
+ _('Incidents')
]
},
{
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 bb1b794c2b6..a6226fe903b 100644
--- a/spec/support/shared_contexts/policies/group_policy_shared_context.rb
+++ b/spec/support/shared_contexts/policies/group_policy_shared_context.rb
@@ -76,6 +76,7 @@ RSpec.shared_context 'GroupPolicy context' do
register_group_runners
read_billing
edit_billing
+ admin_member_access_request
]
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 fc7255a4a20..6e2caa853f8 100644
--- a/spec/support/shared_contexts/policies/project_policy_shared_context.rb
+++ b/spec/support/shared_contexts/policies/project_policy_shared_context.rb
@@ -68,7 +68,7 @@ RSpec.shared_context 'ProjectPolicy context' do
admin_project admin_project_member admin_snippet admin_terraform_state
admin_wiki create_deploy_token destroy_deploy_token
push_to_delete_protected_branch read_deploy_token update_snippet
- destroy_upload
+ destroy_upload admin_member_access_request rename_project
]
end
@@ -83,7 +83,7 @@ RSpec.shared_context 'ProjectPolicy context' do
let(:base_owner_permissions) do
%i[
archive_project change_namespace change_visibility_level destroy_issue
- destroy_merge_request manage_owners remove_fork_project remove_project rename_project
+ destroy_merge_request manage_owners remove_fork_project remove_project
set_issue_created_at set_issue_iid set_issue_updated_at
set_note_created_at
]
diff --git a/spec/support/shared_contexts/policies/project_policy_table_shared_context.rb b/spec/support/shared_contexts/policies/project_policy_table_shared_context.rb
index b18ce14eba6..d9ea7bc7f82 100644
--- a/spec/support/shared_contexts/policies/project_policy_table_shared_context.rb
+++ b/spec/support/shared_contexts/policies/project_policy_table_shared_context.rb
@@ -126,6 +126,63 @@ RSpec.shared_context 'ProjectPolicyTable context' do
end
# This table is based on permission_table_for_guest_feature_access,
+ # but takes into account note confidentiality. It is required on the context
+ # to have one regular note and one confidential note.
+ #
+ # project_level, :feature_access_level, :membership, :admin_mode, :expected_count
+ def permission_table_for_notes_feature_access
+ :public | :enabled | :admin | true | 2
+ :public | :enabled | :admin | false | 1
+ :public | :enabled | :reporter | nil | 2
+ :public | :enabled | :guest | nil | 1
+ :public | :enabled | :non_member | nil | 1
+ :public | :enabled | :anonymous | nil | 1
+
+ :public | :private | :admin | true | 2
+ :public | :private | :admin | false | 0
+ :public | :private | :reporter | nil | 2
+ :public | :private | :guest | nil | 1
+ :public | :private | :non_member | nil | 0
+ :public | :private | :anonymous | nil | 0
+
+ :public | :disabled | :reporter | nil | 0
+ :public | :disabled | :guest | nil | 0
+ :public | :disabled | :non_member | nil | 0
+ :public | :disabled | :anonymous | nil | 0
+
+ :internal | :enabled | :admin | true | 2
+ :internal | :enabled | :admin | false | 1
+ :internal | :enabled | :reporter | nil | 2
+ :internal | :enabled | :guest | nil | 1
+ :internal | :enabled | :non_member | nil | 1
+ :internal | :enabled | :anonymous | nil | 0
+
+ :internal | :private | :admin | true | 2
+ :internal | :private | :admin | false | 0
+ :internal | :private | :reporter | nil | 2
+ :internal | :private | :guest | nil | 1
+ :internal | :private | :non_member | nil | 0
+ :internal | :private | :anonymous | nil | 0
+
+ :internal | :disabled | :reporter | nil | 0
+ :internal | :disabled | :guest | nil | 0
+ :internal | :disabled | :non_member | nil | 0
+ :internal | :disabled | :anonymous | nil | 0
+
+ :private | :private | :admin | true | 2
+ :private | :private | :admin | false | 0
+ :private | :private | :reporter | nil | 2
+ :private | :private | :guest | nil | 1
+ :private | :private | :non_member | nil | 0
+ :private | :private | :anonymous | nil | 0
+
+ :private | :disabled | :reporter | nil | 0
+ :private | :disabled | :guest | nil | 0
+ :private | :disabled | :non_member | nil | 0
+ :private | :disabled | :anonymous | nil | 0
+ end
+
+ # This table is based on permission_table_for_guest_feature_access,
# but with a slight twist.
# Some features can be hidden away to GUEST, when project is private.
# (see ProjectFeature::PRIVATE_FEATURES_MIN_ACCESS_LEVEL_FOR_PRIVATE_PROJECT)
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 fa048b76e18..7df4b7635d3 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
@@ -3,6 +3,7 @@
RSpec.shared_examples 'multiple issue boards' do
context 'authorized user' do
before do
+ stub_feature_flags(apollo_boards: false)
parent.add_maintainer(user)
login_as(user)
@@ -121,6 +122,7 @@ RSpec.shared_examples 'multiple issue boards' do
context 'unauthorized user' do
before do
+ stub_feature_flags(apollo_boards: false)
visit boards_path
wait_for_requests
end
diff --git a/spec/support/shared_examples/bulk_imports/common/pipelines/wiki_pipeline_examples.rb b/spec/support/shared_examples/bulk_imports/common/pipelines/wiki_pipeline_examples.rb
index cd4432af4ed..a9edf18d562 100644
--- a/spec/support/shared_examples/bulk_imports/common/pipelines/wiki_pipeline_examples.rb
+++ b/spec/support/shared_examples/bulk_imports/common/pipelines/wiki_pipeline_examples.rb
@@ -35,7 +35,7 @@ RSpec.shared_examples 'wiki pipeline imports a wiki for an entity' do
it 'does not import wiki' do
expect(subject).to receive(:source_wiki_exists?).and_return(false)
- expect(parent.wiki).not_to receive(:ensure_repository)
+ expect(parent.wiki).not_to receive(:create_wiki_repository)
expect(parent.wiki.repository).not_to receive(:ensure_repository)
expect { subject.run }.not_to raise_error
@@ -75,7 +75,7 @@ RSpec.shared_examples 'wiki pipeline imports a wiki for an entity' do
describe 'unsuccessful response' do
shared_examples 'does not raise an error' do
it 'does not raise an error' do
- expect(parent.wiki).not_to receive(:ensure_repository)
+ expect(parent.wiki).not_to receive(:create_wiki_repository)
expect(parent.wiki.repository).not_to receive(:ensure_repository)
expect { subject.run }.not_to raise_error
diff --git a/spec/support/shared_examples/ci/retryable_shared_examples.rb b/spec/support/shared_examples/ci/retryable_shared_examples.rb
new file mode 100644
index 00000000000..4622dbe4e31
--- /dev/null
+++ b/spec/support/shared_examples/ci/retryable_shared_examples.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'a retryable job' do
+ describe '#enqueue_immediately?' do
+ it 'defaults to false' do
+ expect(subject.enqueue_immediately?).to eq(false)
+ end
+ end
+
+ describe '#set_enqueue_immediately!' do
+ it 'changes #enqueue_immediately? to true' do
+ expect { subject.set_enqueue_immediately! }
+ .to change(subject, :enqueue_immediately?).from(false).to(true)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/controllers/preferred_language_switcher_shared_examples.rb b/spec/support/shared_examples/controllers/preferred_language_switcher_shared_examples.rb
new file mode 100644
index 00000000000..74456e62eb8
--- /dev/null
+++ b/spec/support/shared_examples/controllers/preferred_language_switcher_shared_examples.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'switches to user preferred language' do |msg_id_example|
+ context 'with preferred_language in cookies' do
+ render_views
+ let(:user_preferred_language) { 'zh_CN' }
+
+ subject { get :new }
+
+ before do
+ cookies['preferred_language'] = user_preferred_language
+ end
+
+ it 'renders new template with cookies preferred language' do
+ expect(subject).to render_template(:new)
+ expect(response).to have_gitlab_http_status(:ok)
+
+ expected_text = Gitlab::I18n.with_locale(user_preferred_language) { _(msg_id_example) }
+ expect(response.body).to include(expected_text)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/features/access_tokens_shared_examples.rb b/spec/support/shared_examples/features/access_tokens_shared_examples.rb
index cd255abd7a8..32a7b32ac72 100644
--- a/spec/support/shared_examples/features/access_tokens_shared_examples.rb
+++ b/spec/support/shared_examples/features/access_tokens_shared_examples.rb
@@ -9,13 +9,7 @@ RSpec.shared_examples 'resource access tokens missing access rights' do
end
RSpec.shared_examples 'resource access tokens creation' do |resource_type|
- def active_resource_access_tokens
- find("[data-testid='active-tokens']")
- end
-
- def created_resource_access_token
- find_field('new-access-token').value
- end
+ include Spec::Support::Helpers::AccessTokenHelpers
it 'allows creation of an access token', :aggregate_failures do
name = 'My access token'
@@ -34,12 +28,12 @@ RSpec.shared_examples 'resource access tokens creation' do |resource_type|
click_on "Create #{resource_type} access token"
- expect(active_resource_access_tokens).to have_text(name)
- expect(active_resource_access_tokens).to have_text('in')
- expect(active_resource_access_tokens).to have_text('read_api')
- expect(active_resource_access_tokens).to have_text('read_repository')
- expect(active_resource_access_tokens).to have_text('Guest')
- expect(created_resource_access_token).not_to be_empty
+ expect(active_access_tokens).to have_text(name)
+ expect(active_access_tokens).to have_text('in')
+ expect(active_access_tokens).to have_text('read_api')
+ expect(active_access_tokens).to have_text('read_repository')
+ expect(active_access_tokens).to have_text('Guest')
+ expect(created_access_token).to match(/[\w-]{20}/)
end
end
@@ -105,14 +99,14 @@ RSpec.shared_examples 'resource access tokens creation disallowed' do |error_mes
end
RSpec.shared_examples 'active resource access tokens' do
- def active_resource_access_tokens
+ def active_access_tokens
find("[data-testid='active-tokens']")
end
it 'shows active access tokens' do
visit resource_settings_access_tokens_path
- expect(active_resource_access_tokens).to have_text(resource_access_token.name)
+ expect(active_access_tokens).to have_text(resource_access_token.name)
end
context 'when User#time_display_relative is false' do
@@ -123,13 +117,13 @@ RSpec.shared_examples 'active resource access tokens' do
it 'shows absolute times for expires_at' do
visit resource_settings_access_tokens_path
- expect(active_resource_access_tokens).to have_text(PersonalAccessToken.last.expires_at.strftime('%b %-d'))
+ expect(active_access_tokens).to have_text(PersonalAccessToken.last.expires_at.strftime('%b %-d'))
end
end
end
RSpec.shared_examples 'inactive resource access tokens' do |no_active_tokens_text|
- def active_resource_access_tokens
+ def active_access_tokens
find("[data-testid='active-tokens']")
end
@@ -137,14 +131,14 @@ RSpec.shared_examples 'inactive resource access tokens' do |no_active_tokens_tex
visit resource_settings_access_tokens_path
accept_gl_confirm(button_text: 'Revoke') { click_on 'Revoke' }
- expect(active_resource_access_tokens).to have_text(no_active_tokens_text)
+ expect(active_access_tokens).to have_text(no_active_tokens_text)
end
it 'removes expired tokens from active section' do
resource_access_token.update!(expires_at: 5.days.ago)
visit resource_settings_access_tokens_path
- expect(active_resource_access_tokens).to have_text(no_active_tokens_text)
+ expect(active_access_tokens).to have_text(no_active_tokens_text)
end
context 'when resource access token creation is not allowed' do
@@ -156,7 +150,7 @@ RSpec.shared_examples 'inactive resource access tokens' do |no_active_tokens_tex
visit resource_settings_access_tokens_path
accept_gl_confirm(button_text: 'Revoke') { click_on 'Revoke' }
- expect(active_resource_access_tokens).to have_text(no_active_tokens_text)
+ expect(active_access_tokens).to have_text(no_active_tokens_text)
end
end
end
diff --git a/spec/support/shared_examples/features/confidential_notes_shared_examples.rb b/spec/support/shared_examples/features/confidential_notes_shared_examples.rb
new file mode 100644
index 00000000000..289da025af6
--- /dev/null
+++ b/spec/support/shared_examples/features/confidential_notes_shared_examples.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.shared_examples 'confidential notes on issuables' do
+ include Spec::Support::Helpers::Features::NotesHelpers
+
+ context 'when user does not have permissions' do
+ it 'does not show confidential note checkbox' do
+ issuable_parent.add_guest(user)
+ sign_in(user)
+ visit(issuable_path)
+
+ page.within('.new-note') do
+ expect(page).not_to have_selector('[data-testid="internal-note-checkbox"]')
+ end
+ end
+ end
+
+ context 'when user has permissions' do
+ it 'creates confidential note' do
+ issuable_parent.add_reporter(user)
+ sign_in(user)
+ visit(issuable_path)
+
+ find('[data-testid="internal-note-checkbox"]').click
+ add_note('Confidential note')
+
+ page.within('.note-header') do
+ expect(page).to have_selector('[data-testid="internal-note-indicator"]')
+ end
+ end
+ 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 7863548e7f3..f01e3c88dad 100644
--- a/spec/support/shared_examples/features/content_editor_shared_examples.rb
+++ b/spec/support/shared_examples/features/content_editor_shared_examples.rb
@@ -313,5 +313,21 @@ RSpec.shared_examples 'edits content using the content editor' do
expect(page).not_to have_css(suggestions_dropdown)
end
+
+ it 'scrolls selected item into view when navigating with keyboard' do
+ type_in_content_editor ':'
+
+ expect(find(suggestions_dropdown)).to have_text('hundred points symbol')
+
+ expect(dropdown_scroll_top).to be 0
+
+ send_keys :arrow_up
+
+ expect(dropdown_scroll_top).to be > 100
+ end
+
+ def dropdown_scroll_top
+ evaluate_script("document.querySelector('#{suggestions_dropdown} .gl-new-dropdown-inner').scrollTop")
+ end
end
end
diff --git a/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb b/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb
index 456175e7113..2cfe353d5d7 100644
--- a/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb
+++ b/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb
@@ -21,15 +21,10 @@ RSpec.shared_examples 'a creatable merge request' do
expect(page).to have_content user.name
end
- click_button 'Milestone'
- page.within '.issue-milestone' do
- click_link milestone.title
- end
-
+ click_button 'Select milestone'
+ click_button milestone.title
expect(find('input[name="merge_request[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
- page.within '.js-milestone-select' do
- expect(page).to have_content milestone.title
- end
+ expect(page).to have_button milestone.title
click_button 'Labels'
page.within '.dropdown-menu-labels' do
diff --git a/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb b/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb
index 2fff4137934..ea6d1655694 100644
--- a/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb
+++ b/spec/support/shared_examples/features/editable_merge_request_shared_examples.rb
@@ -20,14 +20,10 @@ RSpec.shared_examples 'an editable merge request' do
expect(page).to have_content user.name
end
- click_button 'Milestone'
- page.within '.issue-milestone' do
- click_link milestone.title
- end
+ click_button 'Select milestone'
+ click_button milestone.title
expect(find('input[name="merge_request[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
- page.within '.js-milestone-select' do
- expect(page).to have_content milestone.title
- end
+ expect(page).to have_button milestone.title
click_button 'Labels'
page.within '.dropdown-menu-labels' do
diff --git a/spec/support/shared_examples/features/packages_shared_examples.rb b/spec/support/shared_examples/features/packages_shared_examples.rb
index 7aad5e2de80..f09cf0613a1 100644
--- a/spec/support/shared_examples/features/packages_shared_examples.rb
+++ b/spec/support/shared_examples/features/packages_shared_examples.rb
@@ -14,7 +14,7 @@ RSpec.shared_examples 'packages list' do |check_project_name: false|
end
def package_table_row(index)
- page.all("#{packages_table_selector} > [data-testid=\"package-row\"]")[index].text
+ page.all("#{packages_table_selector} [data-testid=\"package-row\"]")[index].text
end
end
diff --git a/spec/support/shared_examples/features/runners_shared_examples.rb b/spec/support/shared_examples/features/runners_shared_examples.rb
index 1d4af944187..a7bc19da45f 100644
--- a/spec/support/shared_examples/features/runners_shared_examples.rb
+++ b/spec/support/shared_examples/features/runners_shared_examples.rb
@@ -1,8 +1,8 @@
# frozen_string_literal: true
RSpec.shared_examples 'shows and resets runner registration token' do
- include Spec::Support::Helpers::ModalHelpers
include Spec::Support::Helpers::Features::RunnersHelpers
+ include Spec::Support::Helpers::ModalHelpers
before do
click_on dropdown_text
@@ -146,6 +146,23 @@ RSpec.shared_examples 'pauses, resumes and deletes a runner' do
end
end
+RSpec.shared_examples 'deletes runners in bulk' do
+ describe 'when selecting all for deletion', :js do
+ before do
+ check s_('Runners|Select all')
+ click_button s_('Runners|Delete selected')
+
+ within_modal do
+ click_on "Permanently delete #{runner_count} runners"
+ end
+
+ wait_for_requests
+ end
+
+ it_behaves_like 'shows no runners registered'
+ end
+end
+
RSpec.shared_examples 'filters by tag' do
it 'shows correct runner when tag matches' do
expect(page).to have_content found_runner
diff --git a/spec/support/shared_examples/features/search/redacted_search_results_shared_examples.rb b/spec/support/shared_examples/features/search/redacted_search_results_shared_examples.rb
new file mode 100644
index 00000000000..4d242d0e719
--- /dev/null
+++ b/spec/support/shared_examples/features/search/redacted_search_results_shared_examples.rb
@@ -0,0 +1,304 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'a redacted search results' do
+ let_it_be(:user) { create(:user) }
+
+ let_it_be(:accessible_group) { create(:group, :private) }
+ let_it_be(:accessible_project) { create(:project, :repository, :private, name: 'accessible_project') }
+
+ let_it_be(:group_member) { create(:group_member, group: accessible_group, user: user) }
+
+ let_it_be(:inaccessible_group) { create(:group, :private) }
+ let_it_be(:inaccessible_project) { create(:project, :repository, :private, name: 'inaccessible_project') }
+
+ let(:search) { 'anything' }
+
+ subject(:result) { search_service.search_objects }
+
+ def found_blob(project)
+ Gitlab::Search::FoundBlob.new(project: project)
+ end
+
+ def found_wiki_page(project)
+ Gitlab::Search::FoundWikiPage.new(found_blob(project))
+ end
+
+ def ar_relation(klass, *objects)
+ klass.id_in(objects.map(&:id))
+ end
+
+ def kaminari_array(*objects)
+ Kaminari.paginate_array(objects).page(1).per(20)
+ end
+
+ before do
+ accessible_project.add_maintainer(user)
+
+ allow(search_service)
+ .to receive_message_chain(:search_results, :objects)
+ .and_return(unredacted_results)
+ end
+
+ context 'for issues' do
+ let(:readable) { create(:issue, project: accessible_project) }
+ let(:unreadable) { create(:issue, project: inaccessible_project) }
+ let(:unredacted_results) { ar_relation(Issue, readable, unreadable) }
+ let(:scope) { 'issues' }
+
+ it 'redacts the inaccessible issue' do
+ expect(search_service.send(:logger))
+ .to receive(:error)
+ .with(hash_including(
+ message: "redacted_search_results",
+ current_user_id: user.id,
+ query: search,
+ filtered: array_including(
+ [
+ { class_name: 'Issue', id: unreadable.id, ability: :read_issue }
+ ])))
+
+ expect(result).to contain_exactly(readable)
+ end
+ end
+
+ context 'for notes' do
+ let(:readable_merge_request) do
+ create(:merge_request_with_diffs, target_project: accessible_project, source_project: accessible_project)
+ end
+
+ let(:readable_note_on_commit) { create(:note_on_commit, project: accessible_project) }
+ let(:readable_diff_note) { create(:diff_note_on_commit, project: accessible_project) }
+ let(:readable_note_on_mr) do
+ create(:discussion_note_on_merge_request, noteable: readable_merge_request, project: accessible_project)
+ end
+
+ let(:readable_diff_note_on_mr) do
+ create(:diff_note_on_merge_request, noteable: readable_merge_request, project: accessible_project)
+ end
+
+ let(:readable_note_on_project_snippet) do
+ create(:note_on_project_snippet, noteable: readable_merge_request, project: accessible_project)
+ end
+
+ let(:unreadable_merge_request) do
+ create(:merge_request_with_diffs, target_project: inaccessible_project, source_project: inaccessible_project)
+ end
+
+ let(:unreadable_note_on_commit) { create(:note_on_commit, project: inaccessible_project) }
+ let(:unreadable_diff_note) { create(:diff_note_on_commit, project: inaccessible_project) }
+ let(:unreadable_note_on_mr) do
+ create(:discussion_note_on_merge_request, noteable: unreadable_merge_request, project: inaccessible_project)
+ end
+
+ let(:unreadable_note_on_project_snippet) do
+ create(:note_on_project_snippet, noteable: unreadable_merge_request, project: inaccessible_project)
+ end
+
+ let(:unredacted_results) do
+ ar_relation(Note,
+ readable_note_on_commit,
+ readable_diff_note,
+ readable_note_on_mr,
+ readable_diff_note_on_mr,
+ readable_note_on_project_snippet,
+ unreadable_note_on_commit,
+ unreadable_diff_note,
+ unreadable_note_on_mr,
+ unreadable_note_on_project_snippet)
+ end
+
+ let(:scope) { 'notes' }
+
+ it 'redacts the inaccessible notes' do
+ expect(search_service.send(:logger))
+ .to receive(:error)
+ .with(hash_including(
+ message: "redacted_search_results",
+ current_user_id: user.id,
+ query: search,
+ filtered: array_including(
+ [
+ { class_name: 'Note', id: unreadable_note_on_commit.id, ability: :read_note },
+ { class_name: 'DiffNote', id: unreadable_diff_note.id, ability: :read_note },
+ { class_name: 'DiscussionNote', id: unreadable_note_on_mr.id, ability: :read_note },
+ { class_name: 'Note', id: unreadable_note_on_project_snippet.id, ability: :read_note }
+ ])))
+
+ expect(result).to contain_exactly(readable_note_on_commit,
+ readable_diff_note,
+ readable_note_on_mr,
+ readable_diff_note_on_mr,
+ readable_note_on_project_snippet)
+ end
+ end
+
+ context 'for merge_requests' do
+ let(:readable) { create(:merge_request, source_project: accessible_project) }
+ let(:unreadable) { create(:merge_request, source_project: inaccessible_project) }
+ let(:unredacted_results) { ar_relation(MergeRequest, readable, unreadable) }
+ let(:scope) { 'merge_requests' }
+
+ it 'redacts the inaccessible merge request' do
+ expect(search_service.send(:logger))
+ .to receive(:error)
+ .with(hash_including(
+ message: "redacted_search_results",
+ current_user_id: user.id,
+ query: search,
+ filtered: array_including(
+ [
+ { class_name: 'MergeRequest', id: unreadable.id, ability: :read_merge_request }
+ ])))
+
+ expect(result).to contain_exactly(readable)
+ end
+
+ context 'with :with_api_entity_associations' do
+ let(:unredacted_results) { ar_relation(MergeRequest.with_api_entity_associations, readable, unreadable) }
+
+ it_behaves_like "redaction limits N+1 queries", limit: 8
+ end
+ end
+
+ context 'for blobs' do
+ let(:readable) { found_blob(accessible_project) }
+ let(:unreadable) { found_blob(inaccessible_project) }
+ let(:unredacted_results) { kaminari_array(readable, unreadable) }
+ let(:scope) { 'blobs' }
+
+ it 'redacts the inaccessible blob' do
+ expect(search_service.send(:logger))
+ .to receive(:error)
+ .with(hash_including(
+ message: "redacted_search_results",
+ current_user_id: user.id,
+ query: search,
+ filtered: array_including(
+ [
+ { class_name: 'Gitlab::Search::FoundBlob', id: unreadable.id, ability: :read_blob }
+ ])))
+
+ expect(result).to contain_exactly(readable)
+ end
+ end
+
+ context 'for wiki blobs' do
+ let(:readable) { found_wiki_page(accessible_project) }
+ let(:unreadable) { found_wiki_page(inaccessible_project) }
+ let(:unredacted_results) { kaminari_array(readable, unreadable) }
+ let(:scope) { 'wiki_blobs' }
+
+ it 'redacts the inaccessible blob' do
+ expect(search_service.send(:logger))
+ .to receive(:error)
+ .with(hash_including(
+ message: "redacted_search_results",
+ current_user_id: user.id,
+ query: search,
+ filtered: array_including(
+ [
+ { class_name: 'Gitlab::Search::FoundWikiPage', id: unreadable.id, ability: :read_wiki_page }
+ ])))
+
+ expect(result).to contain_exactly(readable)
+ end
+ end
+
+ context 'for project snippets' do
+ let(:readable) { create(:project_snippet, project: accessible_project) }
+ let(:unreadable) { create(:project_snippet, project: inaccessible_project) }
+ let(:unredacted_results) { ar_relation(ProjectSnippet, readable, unreadable) }
+ let(:scope) { 'snippet_titles' }
+
+ it 'redacts the inaccessible snippet' do
+ expect(search_service.send(:logger))
+ .to receive(:error)
+ .with(hash_including(
+ message: "redacted_search_results",
+ current_user_id: user.id,
+ query: search,
+ filtered: array_including(
+ [
+ { class_name: 'ProjectSnippet', id: unreadable.id, ability: :read_snippet }
+ ])))
+
+ expect(result).to contain_exactly(readable)
+ end
+
+ context 'with :with_api_entity_associations' do
+ it_behaves_like "redaction limits N+1 queries", limit: 14
+ end
+ end
+
+ context 'for personal snippets' do
+ let(:readable) { create(:personal_snippet, :private, author: user) }
+ let(:unreadable) { create(:personal_snippet, :private) }
+ let(:unredacted_results) { ar_relation(PersonalSnippet, readable, unreadable) }
+ let(:scope) { 'snippet_titles' }
+
+ it 'redacts the inaccessible snippet' do
+ expect(search_service.send(:logger))
+ .to receive(:error)
+ .with(hash_including(
+ message: "redacted_search_results",
+ current_user_id: user.id,
+ query: search,
+ filtered: array_including(
+ [
+ { class_name: 'PersonalSnippet', id: unreadable.id, ability: :read_snippet }
+ ])))
+
+ expect(result).to contain_exactly(readable)
+ end
+
+ context 'with :with_api_entity_associations' do
+ it_behaves_like "redaction limits N+1 queries", limit: 4
+ end
+ end
+
+ context 'for commits' do
+ let(:readable) { accessible_project.commit }
+ let(:unreadable) { inaccessible_project.commit }
+ let(:unredacted_results) { kaminari_array(readable, unreadable) }
+ let(:scope) { 'commits' }
+
+ it 'redacts the inaccessible commit' do
+ expect(search_service.send(:logger))
+ .to receive(:error)
+ .with(hash_including(
+ message: "redacted_search_results",
+ current_user_id: user.id,
+ query: search,
+ filtered: array_including(
+ [
+ { class_name: 'Commit', id: unreadable.id, ability: :read_commit }
+ ])))
+
+ expect(result).to contain_exactly(readable)
+ end
+ end
+
+ context 'for users' do
+ let(:other_user) { create(:user) }
+ let(:unredacted_results) { ar_relation(User, user, other_user) }
+ let(:scope) { 'users' }
+
+ it 'passes the users through' do
+ # Users are always visible to everyone
+ expect(result).to contain_exactly(user, other_user)
+ end
+ end
+end
+
+RSpec.shared_examples "redaction limits N+1 queries" do |limit:|
+ it 'does not exceed the query limit' do
+ # issuing the query to remove the data loading call
+ unredacted_results.to_a
+
+ # only the calls from the redaction are left
+ query = ActiveRecord::QueryRecorder.new { result }
+
+ # these are the project authorization calls, which are not preloaded
+ expect(query.count).to be <= limit
+ end
+end
diff --git a/spec/support/shared_examples/features/search/search_timeouts_shared_examples.rb b/spec/support/shared_examples/features/search/search_timeouts_shared_examples.rb
index 84dc2b20ddc..cc74c977064 100644
--- a/spec/support/shared_examples/features/search/search_timeouts_shared_examples.rb
+++ b/spec/support/shared_examples/features/search/search_timeouts_shared_examples.rb
@@ -1,23 +1,23 @@
# frozen_string_literal: true
RSpec.shared_examples 'search timeouts' do |scope|
+ let(:additional_params) { {} }
+
context 'when search times out' do
before do
- stub_feature_flags(search_page_vertical_nav: false)
allow_next_instance_of(SearchService) do |service|
allow(service).to receive(:search_objects).and_raise(ActiveRecord::QueryCanceled)
end
- visit(search_path(search: 'test', scope: scope))
+ visit(search_path(search: 'test', scope: scope, **additional_params))
end
it 'renders timeout information' do
- # expect(page).to have_content('This endpoint has been requested too many times.')
expect(page).to have_content('Your search timed out')
end
it 'sets tab count to 0' do
- expect(page.find('.search-filter .active')).to have_text('0')
+ expect(page.find('[data-testid="search-filter"] .active')).to have_text('0')
end
end
end
diff --git a/spec/support/shared_examples/features/variable_list_shared_examples.rb b/spec/support/shared_examples/features/variable_list_shared_examples.rb
index d1e5046a39e..f0b72cfaee3 100644
--- a/spec/support/shared_examples/features/variable_list_shared_examples.rb
+++ b/spec/support/shared_examples/features/variable_list_shared_examples.rb
@@ -31,8 +31,8 @@ RSpec.shared_examples 'variable list' do |is_admin|
wait_for_requests
page.within('[data-testid="ci-variable-table"]') do
- expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]').text).to eq('key')
- expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Protected"] svg[data-testid="mobile-issue-close-icon"]')).to be_present
+ expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Key')}']").text).to eq('key')
+ expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Options')}']")).to have_content(s_('CiVariables|Protected'))
end
end
@@ -46,26 +46,26 @@ RSpec.shared_examples 'variable list' do |is_admin|
wait_for_requests
page.within('[data-testid="ci-variable-table"]') do
- expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Key"]').text).to eq('key')
- expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Masked"] svg[data-testid="close-icon"]')).to be_present
+ expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Key')}']").text).to eq('key')
+ expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Options')}']")).not_to have_content(s_('CiVariables|Masked'))
end
end
it 'reveals and hides variables' do
page.within('[data-testid="ci-variable-table"]') do
expect(first('.js-ci-variable-row td[data-label="Key"]').text).to eq(variable.key)
- expect(page).to have_content('*' * 17)
+ expect(page).to have_content('*' * 5)
click_button('Reveal value')
expect(first('.js-ci-variable-row td[data-label="Key"]').text).to eq(variable.key)
expect(first('.js-ci-variable-row td[data-label="Value"]').text).to eq(variable.value)
- expect(page).not_to have_content('*' * 17)
+ expect(page).not_to have_content('*' * 5)
click_button('Hide value')
expect(first('.js-ci-variable-row td[data-label="Key"]').text).to eq(variable.key)
- expect(page).to have_content('*' * 17)
+ expect(page).to have_content('*' * 5)
end
end
@@ -116,7 +116,8 @@ RSpec.shared_examples 'variable list' do |is_admin|
wait_for_requests
page.within('[data-testid="ci-variable-table"]') do
- expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Masked"] svg[data-testid="close-icon"]')).to be_present
+ expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Options')}']")).to have_content(s_('CiVariables|Protected'))
+ expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Options')}']")).not_to have_content(s_('CiVariables|Masked'))
end
end
@@ -144,7 +145,7 @@ RSpec.shared_examples 'variable list' do |is_admin|
end
page.within('[data-testid="ci-variable-table"]') do
- expect(find('.js-ci-variable-row:nth-child(1) td[data-label="Masked"] svg[data-testid="mobile-issue-close-icon"]')).to be_present
+ expect(find(".js-ci-variable-row:nth-child(1) td[data-label='#{s_('CiVariables|Options')}']")).to have_content(s_('CiVariables|Masked'))
end
end
diff --git a/spec/support/shared_examples/finders/issues_finder_shared_examples.rb b/spec/support/shared_examples/finders/issues_finder_shared_examples.rb
index f62c9c00006..8b3a344a841 100644
--- a/spec/support/shared_examples/finders/issues_finder_shared_examples.rb
+++ b/spec/support/shared_examples/finders/issues_finder_shared_examples.rb
@@ -585,7 +585,7 @@ RSpec.shared_examples 'issues or work items finder' do |factory, execute_context
end
context 'when full-text search is disabled' do
- let(:search_term) { 'somet' }
+ let(:search_term) { 'ometh' }
before do
stub_feature_flags(issues_full_text_search: false)
diff --git a/spec/support/shared_examples/graphql/mutations/incident_management/timeline_events_shared_examples.rb b/spec/support/shared_examples/graphql/mutations/incident_management/timeline_events_shared_examples.rb
new file mode 100644
index 00000000000..fbfd1af2601
--- /dev/null
+++ b/spec/support/shared_examples/graphql/mutations/incident_management/timeline_events_shared_examples.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'timeline event mutation responds with validation error' do |error_message:|
+ it 'responds with a validation error' do
+ post_graphql_mutation(mutation, current_user: user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['errors']).to match_array([error_message])
+ end
+end
diff --git a/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb b/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb
index 0aa3bf8944f..bdd4dbfe209 100644
--- a/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/notes_creation_shared_examples.rb
@@ -78,7 +78,7 @@ RSpec.shared_examples 'a Note mutation when there are rate limit validation erro
context 'when the user is in the allowlist' do
before do
- stub_application_setting(notes_create_limit_allowlist: ["#{current_user.username}"])
+ stub_application_setting(notes_create_limit_allowlist: [current_user.username.to_s])
end
it_behaves_like 'a Note mutation that creates a Note'
diff --git a/spec/support/shared_examples/graphql/resolvers/packages_resolvers_shared_examples.rb b/spec/support/shared_examples/graphql/resolvers/packages_resolvers_shared_examples.rb
index 3017f62a7c9..aadc061f175 100644
--- a/spec/support/shared_examples/graphql/resolvers/packages_resolvers_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/resolvers/packages_resolvers_shared_examples.rb
@@ -25,7 +25,7 @@ RSpec.shared_examples 'group and projects packages resolver' do
end
%w[CREATED_DESC NAME_DESC VERSION_DESC TYPE_ASC].each do |order|
- context "#{order}" do
+ context order.to_s do
let(:args) { { sort: order } }
it { is_expected.to eq([maven_package, conan_package]) }
@@ -33,7 +33,7 @@ RSpec.shared_examples 'group and projects packages resolver' do
end
%w[CREATED_ASC NAME_ASC VERSION_ASC TYPE_DESC].each do |order|
- context "#{order}" do
+ context order.to_s do
let(:args) { { sort: order } }
it { is_expected.to eq([conan_package, maven_package]) }
diff --git a/spec/support/shared_examples/graphql/types/gitlab_style_deprecations_shared_examples.rb b/spec/support/shared_examples/graphql/types/gitlab_style_deprecations_shared_examples.rb
index 2d7da9f9f00..67576a18c80 100644
--- a/spec/support/shared_examples/graphql/types/gitlab_style_deprecations_shared_examples.rb
+++ b/spec/support/shared_examples/graphql/types/gitlab_style_deprecations_shared_examples.rb
@@ -86,4 +86,25 @@ RSpec.shared_examples 'Gitlab-style deprecations' do
eq("`alpha` and `deprecated` arguments cannot be passed at the same time")
)
end
+
+ describe 'visible?' do
+ let(:ctx) { {} }
+
+ it 'defaults to true' do
+ expect(subject).to be_visible(ctx)
+ end
+
+ context 'when subject is deprecated' do
+ let(:arguments) { { deprecated: { milestone: '1.10', reason: :renamed } } }
+
+ it 'defaults to true' do
+ expect(subject(arguments)).to be_visible(ctx)
+ end
+
+ it 'returns false if `remove_deprecated` is true in context' do
+ ctx = { remove_deprecated: true }
+ expect(subject(arguments)).not_to be_visible(ctx)
+ end
+ end
+ end
end
diff --git a/spec/support/shared_examples/lib/cache_helpers_shared_examples.rb b/spec/support/shared_examples/lib/cache_helpers_shared_examples.rb
index 2e00abe2f8e..6cdd7954b5f 100644
--- a/spec/support/shared_examples/lib/cache_helpers_shared_examples.rb
+++ b/spec/support/shared_examples/lib/cache_helpers_shared_examples.rb
@@ -129,6 +129,7 @@ RSpec.shared_examples_for 'collection cache helper' do
before do
allow(::Gitlab::Metrics::WebTransaction).to receive(:current).and_return(transaction)
allow(transaction).to receive(:increment)
+ allow(Gitlab::ApplicationContext).to receive(:current_context_attribute).with(any_args).and_call_original
allow(Gitlab::ApplicationContext).to receive(:current_context_attribute).with(:caller_id).and_return(caller_id)
end
diff --git a/spec/support/shared_examples/lib/email/email_shared_examples.rb b/spec/support/shared_examples/lib/email/email_shared_examples.rb
new file mode 100644
index 00000000000..26655a71fec
--- /dev/null
+++ b/spec/support/shared_examples/lib/email/email_shared_examples.rb
@@ -0,0 +1,140 @@
+# frozen_string_literal: true
+
+# Set the particular setting as a key-value pair
+# Setting method is different depending on klass and must be defined in the calling spec
+def stub_email_setting(key_value_pairs)
+ case setting_name
+ when :incoming_email
+ stub_incoming_email_setting(key_value_pairs)
+ when :service_desk_email
+ stub_service_desk_email_setting(key_value_pairs)
+ end
+end
+
+RSpec.shared_examples_for 'enabled? method for email' do
+ using RSpec::Parameterized::TableSyntax
+
+ subject { described_class.enabled? }
+
+ where(:value, :address, :result) do
+ false | nil | false
+ false | 'replies+%{key}@example.com' | false
+ true | nil | false
+ true | 'replies+%{key}@example.com' | true
+ end
+
+ with_them do
+ before do
+ stub_email_setting(enabled: value)
+ stub_email_setting(address: address)
+ end
+
+ it { is_expected.to eq result }
+ end
+end
+
+RSpec.shared_examples_for 'supports_wildcard? method for email' do
+ subject { described_class.supports_wildcard? }
+
+ before do
+ stub_incoming_email_setting(address: value)
+ end
+
+ context 'when address contains the wildcard placeholder' do
+ let(:value) { 'replies+%{key}@example.com' }
+
+ it 'confirms that wildcard is supported' do
+ expect(subject).to be_truthy
+ end
+ end
+
+ context "when address doesn't contain the wildcard placeholder" do
+ let(:value) { 'replies@example.com' }
+
+ it 'returns that wildcard is not supported' do
+ expect(subject).to be_falsey
+ end
+ end
+
+ context 'when address is nil' do
+ let(:value) { nil }
+
+ it 'returns that wildcard is not supported' do
+ expect(subject).to be_falsey
+ end
+ end
+end
+
+RSpec.shared_examples_for 'unsubscribe_address method for email' do
+ before do
+ stub_incoming_email_setting(address: 'replies+%{key}@example.com')
+ end
+
+ it 'returns the address with interpolated reply key and unsubscribe suffix' do
+ expect(described_class.unsubscribe_address('key'))
+ .to eq("replies+key#{Gitlab::Email::Common::UNSUBSCRIBE_SUFFIX}@example.com")
+ end
+end
+
+RSpec.shared_examples_for 'key_from_fallback_message_id method for email' do
+ it 'returns reply key' do
+ expect(described_class.key_from_fallback_message_id('reply-key@localhost')).to eq('key')
+ end
+end
+
+RSpec.shared_examples_for 'supports_issue_creation? method for email' do
+ using RSpec::Parameterized::TableSyntax
+
+ subject { described_class.supports_issue_creation? }
+
+ where(:enabled_value, :supports_wildcard_value, :result) do
+ false | false | false
+ false | true | false
+ true | false | false
+ true | true | true
+ end
+
+ with_them do
+ before do
+ allow(described_class).to receive(:enabled?).and_return(enabled_value)
+ allow(described_class).to receive(:supports_wildcard?).and_return(supports_wildcard_value)
+ end
+
+ it { is_expected.to eq result }
+ end
+end
+
+RSpec.shared_examples_for 'reply_address method for email' do
+ before do
+ stub_incoming_email_setting(address: "replies+%{key}@example.com")
+ end
+
+ it "returns the address with an interpolated reply key" do
+ expect(described_class.reply_address("key")).to eq("replies+key@example.com")
+ end
+end
+
+RSpec.shared_examples_for 'scan_fallback_references method for email' do
+ let(:references) do
+ '<issue_1@localhost>' \
+ ' <reply-59d8df8370b7e95c5a49fbf86aeb2c93@localhost>' \
+ ',<exchange@microsoft.com>'
+ end
+
+ it 'returns reply key' do
+ expect(described_class.scan_fallback_references(references))
+ .to eq(%w[issue_1@localhost
+ reply-59d8df8370b7e95c5a49fbf86aeb2c93@localhost
+ exchange@microsoft.com])
+ end
+end
+
+RSpec.shared_examples_for 'common email methods' do
+ it_behaves_like 'enabled? method for email'
+ it_behaves_like 'supports_wildcard? method for email'
+ it_behaves_like 'key_from_fallback_message_id method for email'
+ it_behaves_like 'supports_issue_creation? method for email'
+ it_behaves_like 'reply_address method for email'
+ it_behaves_like 'unsubscribe_address method for email'
+ it_behaves_like 'scan_fallback_references method for email'
+end
diff --git a/spec/support/shared_examples/lib/gitlab/database/reestablished_connection_stack_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/database/reestablished_connection_stack_shared_examples.rb
index d14216ec5ff..22b4f9f583c 100644
--- a/spec/support/shared_examples/lib/gitlab/database/reestablished_connection_stack_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/database/reestablished_connection_stack_shared_examples.rb
@@ -3,9 +3,6 @@
RSpec.shared_context 'reconfigures connection stack' do |db_config_name|
before do
skip_if_multiple_databases_not_setup
-
- # Due to lib/gitlab/database/load_balancing/configuration.rb:92 requiring RequestStore
- # we cannot use stub_feature_flags(force_no_sharing_primary_model: true)
Gitlab::Database.database_base_models.each do |_, model_class|
allow(model_class.load_balancer.configuration).to receive(:use_dedicated_connection?).and_return(true)
end
diff --git a/spec/support/shared_examples/lib/gitlab/event_store_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/event_store_shared_examples.rb
index db2f2f2d0f0..e97b9ad969f 100644
--- a/spec/support/shared_examples/lib/gitlab/event_store_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/event_store_shared_examples.rb
@@ -15,6 +15,16 @@ RSpec.shared_examples 'subscribes to event' do
it_behaves_like 'an idempotent worker'
end
+RSpec.shared_examples 'ignores the published event' do
+ include AfterNextHelpers
+
+ it 'does not consume the published event', :sidekiq_inline do
+ expect_next(described_class).not_to receive(:handle_event)
+
+ ::Gitlab::EventStore.publish(event)
+ end
+end
+
def consume_event(subscriber:, event:)
subscriber.new.perform(event.class.name, event.data)
end
diff --git a/spec/support/shared_examples/lib/gitlab/experimentation_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/experimentation_shared_examples.rb
deleted file mode 100644
index fdca326dbea..00000000000
--- a/spec/support/shared_examples/lib/gitlab/experimentation_shared_examples.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.shared_examples 'tracks assignment and records the subject' do |experiment, subject_type|
- before do
- stub_experiments(experiment => true)
- end
-
- it 'tracks the assignment', :experiment do
- expect(experiment(experiment))
- .to track(:assignment)
- .with_context(subject_type => subject)
- .on_next_instance
-
- action
- end
-
- it 'records the subject' do
- expect(Experiment).to receive(:add_subject).with(experiment.to_s, variant: anything, subject: subject)
-
- action
- end
-end
diff --git a/spec/support/shared_examples/lib/gitlab/gitaly_client_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/gitaly_client_shared_examples.rb
new file mode 100644
index 00000000000..f26b9a4a7bd
--- /dev/null
+++ b/spec/support/shared_examples/lib/gitlab/gitaly_client_shared_examples.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+def raw_repo_without_container(repository)
+ Gitlab::Git::Repository.new(repository.shard,
+ "#{repository.disk_path}.git",
+ repository.repo_type.identifier_for_container(repository.container),
+ repository.container.full_path)
+end
+
+RSpec.shared_examples 'Gitaly feature flag actors are inferred from repository' do
+ it 'captures correct actors' do
+ service.repository_actor = repository
+
+ expect(service.repository_actor.flipper_id).to eql(repository.flipper_id)
+
+ if expected_project.nil?
+ expect(service.project_actor).to be(nil)
+ else
+ expect(service.project_actor.flipper_id).to eql(expected_project.flipper_id)
+ end
+
+ if expected_group.nil?
+ expect(service.group_actor).to be(nil)
+ else
+ expect(service.group_actor.flipper_id).to eql(expected_group.flipper_id)
+ end
+ end
+
+ it 'does not issues SQL queries after the first invocation' do
+ service.repository_actor = repository
+
+ service.repository_actor
+ service.project_actor
+ service.group_actor
+
+ recorder = ActiveRecord::QueryRecorder.new do
+ 3.times do
+ service.repository_actor
+ service.project_actor
+ service.group_actor
+ end
+ end
+
+ expect(recorder.count).to be(0)
+ end
+end
diff --git a/spec/support/shared_examples/lib/gitlab/template/template_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/template/template_shared_examples.rb
index 4b4a7f4ce9d..a2a4c57d62e 100644
--- a/spec/support/shared_examples/lib/gitlab/template/template_shared_examples.rb
+++ b/spec/support/shared_examples/lib/gitlab/template/template_shared_examples.rb
@@ -52,7 +52,7 @@ RSpec.shared_examples 'acts as branch pipeline' do |jobs|
context 'when branch pipeline' do
let(:pipeline_branch) { default_branch }
let(:service) { Ci::CreatePipelineService.new(project, user, ref: pipeline_branch) }
- let(:pipeline) { service.execute!(:push).payload }
+ let(:pipeline) { service.execute(:push).payload }
it 'includes a job' do
expect(pipeline.builds.pluck(:name)).to match_array(jobs)
diff --git a/spec/support/shared_examples/lib/sentry/client_shared_examples.rb b/spec/support/shared_examples/lib/sentry/client_shared_examples.rb
index 71b32005c55..e0b411e1e2a 100644
--- a/spec/support/shared_examples/lib/sentry/client_shared_examples.rb
+++ b/spec/support/shared_examples/lib/sentry/client_shared_examples.rb
@@ -78,8 +78,8 @@ end
# Expects to following variables:
# - subject
# - sentry_api_response
-# - sentry_url, token - only if enabled_by_default: false
-RSpec.shared_examples 'Sentry API response size limit' do |enabled_by_default: false|
+# - sentry_url, token
+RSpec.shared_examples 'Sentry API response size limit' do
let(:invalid_deep_size) { instance_double(Gitlab::Utils::DeepSize, valid?: false) }
before do
@@ -89,35 +89,8 @@ RSpec.shared_examples 'Sentry API response size limit' do |enabled_by_default: f
.and_return(invalid_deep_size)
end
- if enabled_by_default
- it 'raises an exception when response is too large' do
- expect { subject }.to raise_error(ErrorTracking::SentryClient::ResponseInvalidSizeError,
- 'Sentry API response is too big. Limit is 1 MB.')
- end
- else
- context 'when guarded by feature flag' do
- let(:client) do
- ErrorTracking::SentryClient.new(sentry_url, token, validate_size_guarded_by_feature_flag: feature_flag)
- end
-
- context 'with feature flag enabled' do
- let(:feature_flag) { true }
-
- it 'raises an exception when response is too large' do
- expect { subject }.to raise_error(ErrorTracking::SentryClient::ResponseInvalidSizeError,
- 'Sentry API response is too big. Limit is 1 MB.')
- end
- end
-
- context 'with feature flag disabled' do
- let(:feature_flag) { false }
-
- it 'does not check the limit and thus not raise' do
- expect { subject }.not_to raise_error
-
- expect(Gitlab::Utils::DeepSize).not_to have_received(:new)
- end
- end
- end
+ it 'raises an exception when response is too large' do
+ expect { subject }.to raise_error(ErrorTracking::SentryClient::ResponseInvalidSizeError,
+ 'Sentry API response is too big. Limit is 1 MB.')
end
end
diff --git a/spec/support/shared_examples/mailers/notify_shared_examples.rb b/spec/support/shared_examples/mailers/notify_shared_examples.rb
index 20ed380fb18..919311adc96 100644
--- a/spec/support/shared_examples/mailers/notify_shared_examples.rb
+++ b/spec/support/shared_examples/mailers/notify_shared_examples.rb
@@ -44,12 +44,12 @@ end
RSpec.shared_examples 'an email with X-GitLab headers containing IDs' do
it 'has X-GitLab-*-ID header' do
- is_expected.to have_header "X-GitLab-#{model.class.name}-ID", "#{model.id}"
+ is_expected.to have_header "X-GitLab-#{model.class.name}-ID", model.id.to_s
end
it 'has X-GitLab-*-IID header if model has iid defined' do
if model.respond_to?(:iid)
- is_expected.to have_header "X-GitLab-#{model.class.name}-IID", "#{model.iid}"
+ is_expected.to have_header "X-GitLab-#{model.class.name}-IID", model.iid.to_s
else
expect(subject.header["X-GitLab-#{model.class.name}-IID"]).to eq nil
end
diff --git a/spec/support/shared_examples/metrics/active_record_subscriber_shared_examples.rb b/spec/support/shared_examples/metrics/active_record_subscriber_shared_examples.rb
index 3f187a7e9e4..ef4b08c7865 100644
--- a/spec/support/shared_examples/metrics/active_record_subscriber_shared_examples.rb
+++ b/spec/support/shared_examples/metrics/active_record_subscriber_shared_examples.rb
@@ -37,7 +37,8 @@ RSpec.shared_examples 'store ActiveRecord info in RequestStore' do |db_role|
Gitlab::WithRequestStore.with_request_store do
subscriber.sql(event)
- expected = if db_role == :primary
+ expected = case db_role
+ when :primary
transform_hash(expected_payload_defaults, {
db_count: record_query ? 1 : 0,
db_write_count: record_write_query ? 1 : 0,
@@ -53,7 +54,7 @@ RSpec.shared_examples 'store ActiveRecord info in RequestStore' do |db_role|
db_primary_wal_cached_count: record_wal_query && record_cached_query ? 1 : 0,
"db_#{db_config_name}_wal_cached_count": record_wal_query && record_cached_query ? 1 : 0
})
- elsif db_role == :replica
+ when :replica
transform_hash(expected_payload_defaults, {
db_count: record_query ? 1 : 0,
db_write_count: record_write_query ? 1 : 0,
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
new file mode 100644
index 00000000000..f0581333b28
--- /dev/null
+++ b/spec/support/shared_examples/models/concerns/integrations/base_slack_notification_shared_examples.rb
@@ -0,0 +1,150 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples Integrations::BaseSlackNotification do |factory:|
+ describe '#execute' do
+ let_it_be(:project) { create(:project, :repository, :wiki_repo) }
+ let_it_be(:integration) { create(factory, branches_to_be_notified: 'all', project: project) }
+
+ before do
+ stub_request(:post, integration.webhook)
+ end
+
+ it 'uses only known events', :aggregate_failures do
+ described_class::SUPPORTED_EVENTS_FOR_USAGE_LOG.each do |action|
+ expect(
+ Gitlab::UsageDataCounters::HLLRedisCounter.known_event?("i_ecosystem_slack_service_#{action}_notification")
+ ).to be true
+ end
+ end
+
+ context 'when hook data includes a user object' do
+ let_it_be(:user) { create_default(:user) }
+
+ shared_examples 'increases the usage data counter' do |event_name|
+ subject(:execute) { integration.execute(data) }
+
+ it 'increases the usage data counter' do
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter)
+ .to receive(:track_event).with(event_name, values: user.id).and_call_original
+
+ execute
+ end
+
+ it_behaves_like 'Snowplow event tracking' 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 }
+ let(:label) { 'redis_hll_counters.ecosystem.ecosystem_total_unique_counts_monthly' }
+ let(:property) { event_name }
+ end
+ end
+
+ context 'when event is not supported for usage log' do
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+
+ let(:data) { Gitlab::DataBuilder::Pipeline.build(pipeline) }
+
+ it 'does not increase the usage data counter' do
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter)
+ .not_to receive(:track_event).with('i_ecosystem_slack_service_pipeline_notification', values: user.id)
+
+ integration.execute(data)
+ end
+ end
+
+ context 'for issue notification' do
+ let_it_be(:issue) { create(:issue, project: project) }
+
+ let(:data) { issue.to_hook_data(user) }
+
+ it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_issue_notification'
+ end
+
+ context 'for push notification' do
+ let(:data) { Gitlab::DataBuilder::Push.build_sample(project, user) }
+
+ it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_push_notification'
+ end
+
+ context 'for deployment notification' do
+ let_it_be(:deployment) { create(:deployment, project: project, user: user) }
+
+ let(:data) { Gitlab::DataBuilder::Deployment.build(deployment, deployment.status, Time.current) }
+
+ it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_deployment_notification'
+ end
+
+ context 'for wiki_page notification' do
+ let_it_be(:wiki_page) do
+ create(:wiki_page, wiki: project.wiki, message: 'user created page: Awesome wiki_page')
+ end
+
+ let(:data) { Gitlab::DataBuilder::WikiPage.build(wiki_page, user, 'create') }
+
+ before do
+ # Skip this method that is not relevant to this test to prevent having
+ # to update project which is frozen
+ allow(project.wiki).to receive(:after_wiki_activity)
+ end
+
+ it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_wiki_page_notification'
+ end
+
+ context 'for merge_request notification' do
+ let_it_be(:merge_request) { create(:merge_request, source_project: project) }
+
+ let(:data) { merge_request.to_hook_data(user) }
+
+ it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_merge_request_notification'
+ end
+
+ context 'for note notification' do
+ let_it_be(:issue_note) { create(:note_on_issue, project: project, note: 'issue note') }
+
+ let(:data) { Gitlab::DataBuilder::Note.build(issue_note, user) }
+
+ it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_note_notification'
+ end
+
+ context 'for tag_push notification' do
+ let(:oldrev) { Gitlab::Git::BLANK_SHA }
+ let(:newrev) { '8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b' } # gitlab-test: git rev-parse refs/tags/v1.1.0
+ let(:ref) { 'refs/tags/v1.1.0' }
+ let(:data) do
+ Git::TagHooksService.new(project, user, change: { oldrev: oldrev, newrev: newrev, ref: ref }).send(:push_data)
+ end
+
+ it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_tag_push_notification'
+ end
+
+ context 'for confidential note notification' do
+ let_it_be(:confidential_issue_note) do
+ create(:note_on_issue, project: project, note: 'issue note', confidential: true)
+ end
+
+ let(:data) { Gitlab::DataBuilder::Note.build(confidential_issue_note, user) }
+
+ it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_confidential_note_notification'
+ end
+
+ context 'for confidential issue notification' do
+ let_it_be(:issue) { create(:issue, project: project, confidential: true) }
+
+ let(:data) { issue.to_hook_data(user) }
+
+ it_behaves_like 'increases the usage data counter', 'i_ecosystem_slack_service_confidential_issue_notification'
+ end
+ end
+
+ context 'when hook data does not include a user' do
+ let(:data) { Gitlab::DataBuilder::Pipeline.build(create(:ci_pipeline, project: project)) }
+
+ it 'does not increase the usage data counter' do
+ expect(Gitlab::UsageDataCounters::HLLRedisCounter).not_to receive(:track_event)
+
+ integration.execute(data)
+ end
+ end
+ end
+end
diff --git a/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb b/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb
index 7512a9f2855..974fc8f402a 100644
--- a/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/integrations/slack_mattermost_notifier_shared_examples.rb
@@ -152,7 +152,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name
end
context 'issue events' do
- let_it_be(:issue) { create(:issue) }
+ let_it_be(:issue) { create(:issue, project: project) }
let(:data) { issue.to_hook_data(user) }
@@ -192,7 +192,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name
end
context 'merge request events' do
- let_it_be(:merge_request) { create(:merge_request) }
+ let_it_be(:merge_request) { create(:merge_request, source_project: project) }
let(:data) { merge_request.to_hook_data(user) }
@@ -210,7 +210,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name
end
context 'wiki page events' do
- let_it_be(:wiki_page) { create(:wiki_page, wiki: project.wiki, message: 'user created page: Awesome wiki_page') }
+ let_it_be(:wiki_page) { create(:wiki_page, wiki: project.wiki, project: project, message: 'user created page: Awesome wiki_page') }
let(:data) { Gitlab::DataBuilder::WikiPage.build(wiki_page, user, 'create') }
@@ -228,7 +228,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name
end
context 'deployment events' do
- let_it_be(:deployment) { create(:deployment) }
+ let_it_be(:deployment) { create(:deployment, project: project) }
let(:data) { Gitlab::DataBuilder::Deployment.build(deployment, 'created', Time.current) }
@@ -275,8 +275,8 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name
end
describe 'Push events' do
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository, creator: user) }
+ let_it_be(:user) { create(:user) }
+ let_it_be_with_reload(:project) { create(:project, :repository, creator: user) }
before do
allow(chat_integration).to receive_messages(
@@ -327,7 +327,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name
end
context 'on a protected branch' do
- before do
+ before(:all) do
create(:protected_branch, :create_branch_on_repository, project: project, name: 'a-protected-branch')
end
@@ -369,7 +369,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name
end
context 'on a protected branch with protected branches defined using wildcards' do
- before do
+ before(:all) do
create(:protected_branch, :create_branch_on_repository, repository_branch_name: '1-stable', project: project, name: '*-stable')
end
@@ -450,8 +450,8 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name
end
describe 'Note events' do
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository, creator: user) }
+ let_it_be(:user) { create(:user) }
+ let_it_be_with_reload(:project) { create(:project, :repository, creator: user) }
before do
allow(chat_integration).to receive_messages(
@@ -519,8 +519,8 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name
end
describe 'Pipeline events' do
- let(:user) { create(:user) }
- let(:project) { create(:project, :repository, creator: user) }
+ let_it_be(:user) { create(:user) }
+ let_it_be_with_reload(:project) { create(:project, :repository, creator: user) }
let(:pipeline) do
create(:ci_pipeline,
project: project, status: status,
@@ -582,7 +582,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name
end
context 'on a protected branch' do
- before do
+ before(:all) do
create(:protected_branch, :create_branch_on_repository, project: project, name: 'a-protected-branch')
end
@@ -612,7 +612,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name
end
context 'on a protected branch with protected branches defined usin wildcards' do
- before do
+ before(:all) do
create(:protected_branch, :create_branch_on_repository, repository_branch_name: '1-stable', project: project, name: '*-stable')
end
@@ -673,7 +673,7 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name
let_it_be(:user) { create(:user) }
let_it_be_with_reload(:project) { create(:project, :repository, creator: user) }
- let(:deployment) do
+ let_it_be(:deployment) do
create(:deployment, :success, project: project, sha: project.commit.sha, ref: project.default_branch)
end
@@ -692,11 +692,11 @@ RSpec.shared_examples Integrations::SlackMattermostNotifier do |integration_name
it_behaves_like "triggered #{integration_name} integration", event_type: "deployment"
context 'on a protected branch' do
- before do
+ before(:all) do
create(:protected_branch, :create_branch_on_repository, project: project, name: 'a-protected-branch')
end
- let(:deployment) do
+ let_it_be(:deployment) do
create(:deployment, :success, project: project, sha: project.commit.sha, ref: 'a-protected-branch')
end
diff --git a/spec/support/shared_examples/models/concerns/limitable_shared_examples.rb b/spec/support/shared_examples/models/concerns/limitable_shared_examples.rb
index 3d393e6dcb5..c6d6e00c781 100644
--- a/spec/support/shared_examples/models/concerns/limitable_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/limitable_shared_examples.rb
@@ -2,7 +2,7 @@
RSpec.shared_examples 'includes Limitable concern' do
describe '#exceeds_limits?' do
- let(:plan_limits) { create(:plan_limits, :default_plan) }
+ let_it_be_with_reload(:plan_limits) { create(:plan_limits, :default_plan) }
context 'without plan limits configured' do
it { expect(subject.exceeds_limits?).to eq false }
@@ -26,7 +26,7 @@ RSpec.shared_examples 'includes Limitable concern' do
end
describe 'validations' do
- let(:plan_limits) { create(:plan_limits, :default_plan) }
+ let_it_be_with_reload(:plan_limits) { create(:plan_limits, :default_plan) }
it { is_expected.to be_a(Limitable) }
diff --git a/spec/support/shared_examples/models/concerns/ttl_expirable_shared_examples.rb b/spec/support/shared_examples/models/concerns/ttl_expirable_shared_examples.rb
index 174b8609337..ac34ee32c6d 100644
--- a/spec/support/shared_examples/models/concerns/ttl_expirable_shared_examples.rb
+++ b/spec/support/shared_examples/models/concerns/ttl_expirable_shared_examples.rb
@@ -7,6 +7,11 @@ RSpec.shared_examples 'ttl_expirable' do
it_behaves_like 'having unique enum values'
+ describe 'default values', :freeze_time do
+ it { expect(described_class.new.read_at).to be_like_time(Time.zone.now) }
+ it { expect(described_class.new(read_at: 1.day.ago).read_at).to be_like_time(1.day.ago) }
+ end
+
describe 'validations' do
it { is_expected.to validate_presence_of(:status) }
end
@@ -38,7 +43,7 @@ RSpec.shared_examples 'ttl_expirable' do
end
end
- describe '#read', :freeze_time do
+ describe '#read!', :freeze_time do
let_it_be(:old_read_at) { 1.day.ago }
let_it_be(:item1) { create(class_symbol, read_at: old_read_at) }
diff --git a/spec/support/shared_examples/models/integrations/base_ci_shared_examples.rb b/spec/support/shared_examples/models/integrations/base_ci_shared_examples.rb
new file mode 100644
index 00000000000..08fab45e41b
--- /dev/null
+++ b/spec/support/shared_examples/models/integrations/base_ci_shared_examples.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples Integrations::BaseCi do
+ describe 'default values' do
+ it { expect(subject.category).to eq(:ci) }
+ end
+end
diff --git a/spec/support/shared_examples/models/integrations/base_monitoring_shared_examples.rb b/spec/support/shared_examples/models/integrations/base_monitoring_shared_examples.rb
new file mode 100644
index 00000000000..5d7e7633a23
--- /dev/null
+++ b/spec/support/shared_examples/models/integrations/base_monitoring_shared_examples.rb
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples Integrations::BaseMonitoring do
+ describe 'default values' do
+ it { expect(subject.category).to eq(:monitoring) }
+ 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 e35ac9c0d0d..7dfdd24177e 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
@@ -6,6 +6,10 @@ RSpec.shared_examples Integrations::BaseSlashCommands do
it { is_expected.to have_many :chat_names }
end
+ describe 'default values' do
+ it { expect(subject.category).to eq(:chat) }
+ end
+
describe '#valid_token?' do
subject { described_class.new }
diff --git a/spec/support/shared_examples/models/integrations/has_web_hook_shared_examples.rb b/spec/support/shared_examples/models/integrations/has_web_hook_shared_examples.rb
index 31ec25249d7..a764d47d7c0 100644
--- a/spec/support/shared_examples/models/integrations/has_web_hook_shared_examples.rb
+++ b/spec/support/shared_examples/models/integrations/has_web_hook_shared_examples.rb
@@ -38,7 +38,7 @@ RSpec.shared_examples Integrations::HasWebHook do
end
describe '#url_variables' do
- it 'returns a string' do
+ it 'returns a hash' do
expect(integration.url_variables).to be_a(Hash)
end
end
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 23026167b19..5be0f6349ea 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
@@ -199,7 +199,7 @@ RSpec.shared_examples 'Debian Component File' do |container_type, can_freeze|
expect(component_file)
.to receive(:update_column)
- .with(:file_store, ::Packages::PackageFileUploader::Store::LOCAL)
+ .with('file_store', ::Packages::PackageFileUploader::Store::LOCAL)
.and_call_original
expect { subject }.to change { component_file.size }.from(nil).to(74)
diff --git a/spec/support/shared_examples/models/wiki_shared_examples.rb b/spec/support/shared_examples/models/wiki_shared_examples.rb
index b1aa90449e1..7e69a6663d5 100644
--- a/spec/support/shared_examples/models/wiki_shared_examples.rb
+++ b/spec/support/shared_examples/models/wiki_shared_examples.rb
@@ -161,9 +161,10 @@ RSpec.shared_examples 'wiki model' do
let(:wiki_pages) { subject.list_pages }
before do
- subject.create_page('index', 'This is an index')
+ # The order is intentional
subject.create_page('index2', 'This is an index2')
- subject.create_page('an index3', 'This is an index3')
+ subject.create_page('index', 'This is an index')
+ subject.create_page('index3', 'This is an index3')
end
it 'returns an array of WikiPage instances' do
@@ -183,13 +184,47 @@ RSpec.shared_examples 'wiki model' do
context 'with limit option' do
it 'returns limited set of pages' do
- expect(subject.list_pages(limit: 1).count).to eq(1)
+ expect(
+ subject.list_pages(limit: 1).map(&:title)
+ ).to eql(%w[index])
+ end
+
+ it 'returns all set of pages if limit is more than the total pages' do
+ expect(subject.list_pages(limit: 4).count).to eq(3)
+ end
+
+ it 'returns all set of pages if limit is 0' do
+ expect(subject.list_pages(limit: 0).count).to eq(3)
+ end
+ end
+
+ context 'with offset option' do
+ it 'returns offset-ed set of pages' do
+ expect(
+ subject.list_pages(offset: 1).map(&:title)
+ ).to eq(%w[index2 index3])
+
+ expect(
+ subject.list_pages(offset: 2).map(&:title)
+ ).to eq(["index3"])
+ expect(subject.list_pages(offset: 3).count).to eq(0)
+ expect(subject.list_pages(offset: 4).count).to eq(0)
+ end
+
+ it 'returns all set of pages if offset is 0' do
+ expect(subject.list_pages(offset: 0).count).to eq(3)
+ end
+
+ it 'can combines with limit' do
+ expect(
+ subject.list_pages(offset: 1, limit: 1).map(&:title)
+ ).to eq(["index2"])
end
end
context 'with sorting options' do
it 'returns pages sorted by title by default' do
- pages = ['an index3', 'index', 'index2']
+ pages = %w[index index2 index3]
expect(subject.list_pages.map(&:title)).to eq(pages)
expect(subject.list_pages(direction: 'desc').map(&:title)).to eq(pages.reverse)
@@ -200,24 +235,14 @@ RSpec.shared_examples 'wiki model' do
let(:pages) { subject.list_pages(load_content: true) }
it 'loads WikiPage content' do
- expect(pages.first.content).to eq('This is an index3')
- expect(pages.second.content).to eq('This is an index')
- expect(pages.third.content).to eq('This is an index2')
+ expect(pages.first.content).to eq('This is an index')
+ expect(pages.second.content).to eq('This is an index2')
+ expect(pages.third.content).to eq('This is an index3')
end
end
end
- context 'list pages with legacy wiki rpcs' do
- before do
- stub_feature_flags(wiki_list_page_with_normal_repository_rpcs: false)
- end
-
- it_behaves_like 'wiki model #list_pages'
- end
-
- context 'list pages with normal repository rpcs' do
- it_behaves_like 'wiki model #list_pages'
- end
+ it_behaves_like 'wiki model #list_pages'
end
describe '#sidebar_entries' do
@@ -821,29 +846,6 @@ RSpec.shared_examples 'wiki model' do
end
end
- describe '#ensure_repository' do
- context 'if the repository exists' do
- it 'does not create the repository' do
- expect(subject.repository.exists?).to eq(true)
- expect(subject.repository.raw).not_to receive(:create_repository)
-
- subject.ensure_repository
- end
- end
-
- context 'if the repository does not exist' do
- let(:wiki_container) { wiki_container_without_repo }
-
- it 'creates the repository' do
- expect(subject.repository.exists?).to eq(false)
-
- subject.ensure_repository
-
- expect(subject.repository.exists?).to eq(true)
- end
- end
- end
-
describe '#hook_attrs' do
it 'returns a hash with values' do
expect(subject.hook_attrs).to be_a Hash
diff --git a/spec/support/shared_examples/quick_actions/issuable/max_issuable_examples.rb b/spec/support/shared_examples/quick_actions/issuable/max_issuable_examples.rb
index e725de8ad31..f5431b29ee2 100644
--- a/spec/support/shared_examples/quick_actions/issuable/max_issuable_examples.rb
+++ b/spec/support/shared_examples/quick_actions/issuable/max_issuable_examples.rb
@@ -12,49 +12,60 @@ RSpec.shared_examples 'does not exceed the issuable size limit' do
project.add_maintainer(user3)
end
- context 'when feature flag is turned on' do
- context "when the number of users of issuable does exceed the limit" do
- before do
- stub_const("Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS", 2)
+ context "when the number of users of issuable does exceed the limit" do
+ before do
+ stub_const("Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS", 2)
+ end
+
+ it 'will not add more than the allowed number of users' do
+ allow_next_instance_of(update_service) do |service|
+ expect(service).not_to receive(:execute)
end
- it 'will not add more than the allowed number of users' do
- allow_next_instance_of(update_service) do |service|
- expect(service).not_to receive(:execute)
- end
+ note = described_class.new(project, user, opts.merge(
+ note: note_text,
+ noteable_type: noteable_type,
+ noteable_id: issuable.id,
+ confidential: false
+ )).execute
- note = described_class.new(project, user, opts.merge(
- note: note_text,
- noteable_type: noteable_type,
- noteable_id: issuable.id,
- confidential: false
- )).execute
+ expect(note.errors[:validation]).to match_array([validation_message])
+ end
+ end
- expect(note.errors[:validation]).to match_array([validation_message])
- end
+ context "when the number of users does not exceed the limit" do
+ before do
+ stub_const("Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS", 6)
end
- context "when the number of users does not exceed the limit" do
- before do
- stub_const("Issuable::MAX_NUMBER_OF_ASSIGNEES_OR_REVIEWERS", 6)
+ it 'calls execute and does not return an error' do
+ allow_next_instance_of(update_service) do |service|
+ expect(service).to receive(:execute).and_call_original
end
- it 'calls execute and does not return an error' do
- allow_next_instance_of(update_service) do |service|
- expect(service).to receive(:execute).and_call_original
- end
-
- note = described_class.new(project, user, opts.merge(
- note: note_text,
- noteable_type: noteable_type,
- noteable_id: issuable.id,
- confidential: false
- )).execute
+ note = described_class.new(project, user, opts.merge(
+ note: note_text,
+ noteable_type: noteable_type,
+ noteable_id: issuable.id,
+ confidential: false
+ )).execute
- expect(note.errors[:validation]).to be_empty
- end
+ expect(note.errors[:validation]).to be_empty
end
end
+end
+
+RSpec.shared_examples 'does not exceed the issuable size limit with ff off' do
+ let(:user1) { create(:user) }
+ let(:user2) { create(:user) }
+ let(:user3) { create(:user) }
+
+ before do
+ project.add_maintainer(user)
+ project.add_maintainer(user1)
+ project.add_maintainer(user2)
+ project.add_maintainer(user3)
+ end
context 'when feature flag is off' do
before do
diff --git a/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb b/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb
index 59e641e2af6..2170025824f 100644
--- a/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb
+++ b/spec/support/shared_examples/requests/access_tokens_controller_shared_examples.rb
@@ -1,21 +1,98 @@
# frozen_string_literal: true
RSpec.shared_examples 'GET resource access tokens available' do
- let_it_be(:active_resource_access_token) { create(:personal_access_token, user: bot_user) }
+ let_it_be(:active_resource_access_token) { create(:personal_access_token, user: access_token_user) }
- it 'retrieves active resource access tokens' do
- subject
+ it 'retrieves active access tokens' do
+ get_access_tokens
- token_entities = assigns(:active_resource_access_tokens)
+ token_entities = assigns(:active_access_tokens)
expect(token_entities.length).to eq(1)
expect(token_entities[0][:name]).to eq(active_resource_access_token.name)
end
it 'lists all available scopes' do
- subject
+ get_access_tokens
expect(assigns(:scopes)).to eq(Gitlab::Auth.resource_bot_scopes)
end
+
+ it 'returns for json response' do
+ get_access_tokens_json
+
+ expect(json_response.count).to eq(1)
+ end
+end
+
+RSpec.shared_examples 'GET access tokens are paginated and ordered' do
+ before do
+ create(:personal_access_token, user: access_token_user)
+ end
+
+ context "when multiple access tokens are returned" do
+ before do
+ allow(Kaminari.config).to receive(:default_per_page).and_return(1)
+ create(:personal_access_token, user: access_token_user)
+ end
+
+ it "returns paginated response", :aggregate_failures do
+ get_access_tokens_with_page
+ expect(assigns(:active_access_tokens).count).to eq(1)
+
+ expect_header('X-Per-Page', '1')
+ expect_header('X-Page', '1')
+ expect_header('X-Next-Page', '2')
+ expect_header('X-Total', '2')
+ end
+ end
+
+ context "when access_token_pagination feature flag is disabled" do
+ before do
+ stub_feature_flags(access_token_pagination: false)
+ create(:personal_access_token, user: access_token_user)
+ end
+
+ it "returns all tokens in system" do
+ get_access_tokens_with_page
+ expect(assigns(:active_access_tokens).count).to eq(2)
+ end
+ end
+
+ context "when tokens returned are ordered" do
+ let(:expires_1_day_from_now) { 1.day.from_now.to_date }
+ let(:expires_2_day_from_now) { 2.days.from_now.to_date }
+
+ before do
+ create(:personal_access_token, user: access_token_user, name: "Token1", expires_at: expires_1_day_from_now)
+ create(:personal_access_token, user: access_token_user, name: "Token2", expires_at: expires_2_day_from_now)
+ end
+
+ it "orders token list ascending on expires_at" do
+ get_access_tokens
+
+ first_token = assigns(:active_access_tokens).first.as_json
+ expect(first_token['name']).to eq("Token1")
+ expect(first_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
+ end
+
+ it "orders tokens on id in case token has same expires_at" do
+ create(:personal_access_token, user: access_token_user, name: "Token3", expires_at: expires_1_day_from_now)
+
+ get_access_tokens
+
+ first_token = assigns(:active_access_tokens).first.as_json
+ expect(first_token['name']).to eq("Token3")
+ expect(first_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
+
+ second_token = assigns(:active_access_tokens).second.as_json
+ expect(second_token['name']).to eq("Token1")
+ expect(second_token['expires_at']).to eq(expires_1_day_from_now.strftime("%Y-%m-%d"))
+ end
+ end
+
+ def expect_header(header_name, header_val)
+ expect(response.headers[header_name]).to eq(header_val)
+ end
end
RSpec.shared_examples 'POST resource access tokens available' do
@@ -83,7 +160,7 @@ end
RSpec.shared_examples 'PUT resource access tokens available' do
it 'calls delete user worker' do
- expect(DeleteUserWorker).to receive(:perform_async).with(user.id, bot_user.id, skip_authorization: true)
+ expect(DeleteUserWorker).to receive(:perform_async).with(user.id, access_token_user.id, skip_authorization: true)
subject
end
@@ -91,34 +168,12 @@ RSpec.shared_examples 'PUT resource access tokens available' do
it 'removes membership of bot user' do
subject
- expect(resource.reload.bots).not_to include(bot_user)
+ expect(resource.reload.bots).not_to include(access_token_user)
end
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- it 'creates GhostUserMigration records to handle migration in a worker' do
- expect { subject }.to(
- change { Users::GhostUserMigration.count }.from(0).to(1))
- end
- end
-
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
- end
-
- it 'converts issuables of the bot user to ghost user' do
- issue = create(:issue, author: bot_user)
-
- subject
-
- expect(issue.reload.author.ghost?).to be true
- end
-
- it 'deletes project bot user' do
- subject
-
- expect(User.exists?(bot_user.id)).to be_falsy
- end
+ it 'creates GhostUserMigration records to handle migration in a worker' do
+ expect { subject }.to(
+ change { Users::GhostUserMigration.count }.from(0).to(1))
end
context 'when unsuccessful' do
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 32562aef8d2..f577e2ad323 100644
--- a/spec/support/shared_examples/requests/api/discussions_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/discussions_shared_examples.rb
@@ -15,7 +15,7 @@ RSpec.shared_examples 'with cross-reference system notes' do
new_merge_request.project.add_developer(user)
hidden_merge_request = create(:merge_request)
- new_cross_reference = "test commit #{hidden_merge_request.project.commit}"
+ new_cross_reference = "test commit #{hidden_merge_request.project.commit.to_reference(project)}"
new_note = create(:system_note, noteable: merge_request, project: project, note: new_cross_reference)
create(:system_note_metadata, note: new_note, action: 'cross_reference')
end
diff --git a/spec/support/shared_examples/requests/api/graphql/issuable_search_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/issuable_search_shared_examples.rb
index 22805cf7aed..bb492425fd7 100644
--- a/spec/support/shared_examples/requests/api/graphql/issuable_search_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/graphql/issuable_search_shared_examples.rb
@@ -1,13 +1,15 @@
# frozen_string_literal: true
# Requires `query(params)` , `user`, `issuable_data` and `issuable` bindings
-RSpec.shared_examples 'query with a search term' do
+RSpec.shared_examples 'query with a search term' do |fields = [:DESCRIPTION]|
+ let(:search_term) { 'bar' }
+ let(:ids) { graphql_dig_at(issuable_data, :node, :id) }
+
it 'returns only matching issuables' do
- filter_params = { search: 'bar', in: [:DESCRIPTION] }
+ filter_params = { search: search_term, in: fields }
graphql_query = query(filter_params)
post_graphql(graphql_query, current_user: user)
- ids = graphql_dig_at(issuable_data, :node, :id)
expect(ids).to contain_exactly(issuable.to_global_id.to_s)
end
diff --git a/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb
new file mode 100644
index 00000000000..5469fd80a4f
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/graphql/issue_list_shared_examples.rb
@@ -0,0 +1,170 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'graphql issue list request spec' do
+ it_behaves_like 'a working graphql query' do
+ before do
+ post_query
+ end
+ end
+
+ describe 'filters' do
+ context 'when filtering by assignees' do
+ context 'when both assignee_username filters are provided' do
+ let(:issue_filter_params) do
+ { assignee_username: current_user.username, assignee_usernames: [current_user.username] }
+ end
+
+ it 'returns a mutually exclusive param error' do
+ post_query
+
+ expect_graphql_errors_to_include(
+ 'only one of [assigneeUsernames, assigneeUsername] arguments is allowed at the same time.'
+ )
+ end
+ end
+
+ context 'when filtering by a negated argument' do
+ let(:issue_filter_params) { { not: { assignee_usernames: [current_user.username] } } }
+
+ it 'returns correctly filtered issues' do
+ post_query
+
+ expect(issue_ids).to match_array(expected_negated_assignee_issues.map { |i| i.to_gid.to_s })
+ end
+ end
+ end
+
+ context 'when filtering by unioned arguments' do
+ let(:issue_filter_params) { { or: { assignee_usernames: [current_user.username, another_user.username] } } }
+
+ it 'returns correctly filtered issues' do
+ post_query
+
+ expect(issue_ids).to match_array(expected_unioned_assignee_issues.map { |i| i.to_gid.to_s })
+ end
+
+ context 'when argument is blank' do
+ let(:issue_filter_params) { { or: {} } }
+
+ it 'does not raise an error' do
+ post_query
+
+ expect_graphql_errors_to_be_empty
+ end
+ end
+
+ context 'when feature flag is disabled' do
+ it 'returns an error' do
+ stub_feature_flags(or_issuable_queries: false)
+
+ post_query
+
+ expect_graphql_errors_to_include(
+ "'or' arguments are only allowed when the `or_issuable_queries` feature flag is enabled."
+ )
+ end
+ end
+ end
+
+ context 'when filtering by a blank negated argument' do
+ let(:issue_filter_params) { { not: {} } }
+
+ it 'does not raise an error' do
+ post_query
+
+ expect_graphql_errors_to_be_empty
+ end
+ end
+
+ context 'when filtering by reaction emoji' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:value, :issue_list) do
+ 'thumbsup' | lazy { voted_issues }
+ 'ANY' | lazy { voted_issues }
+ 'any' | lazy { voted_issues }
+ 'AnY' | lazy { voted_issues }
+ 'NONE' | lazy { no_award_issues }
+ 'thumbsdown' | lazy { [] }
+ end
+
+ with_them do
+ let(:issue_filter_params) { { my_reaction_emoji: value } }
+ let(:gids) { to_gid_list(issue_list) }
+
+ it 'returns correctly filtered issues' do
+ post_query
+
+ expect(issue_ids).to match_array(gids)
+ end
+ end
+ end
+
+ context 'when filtering by search' do
+ it_behaves_like 'query with a search term', [:TITLE] do
+ let(:search_term) { search_title_term }
+ let(:issuable_data) { issues_data }
+ let(:user) { current_user }
+ let(:issuable) { title_search_issue }
+ let(:ids) { issue_ids }
+ end
+ end
+ end
+
+ describe 'sorting and pagination' do
+ context 'when sorting by severity' do
+ context 'when ascending' do
+ it_behaves_like 'sorted paginated query' do
+ let(:sort_param) { :SEVERITY_ASC }
+ let(:first_param) { 2 }
+ let(:all_records) { to_gid_list(expected_severity_sorted_asc) }
+ end
+ end
+
+ context 'when descending' do
+ it_behaves_like 'sorted paginated query' do
+ let(:sort_param) { :SEVERITY_DESC }
+ let(:first_param) { 2 }
+ let(:all_records) { to_gid_list(expected_severity_sorted_asc.reverse) }
+ end
+ end
+ end
+
+ context 'when sorting by priority' do
+ context 'when ascending' do
+ it_behaves_like 'sorted paginated query' do
+ let(:sort_param) { :PRIORITY_ASC }
+ let(:first_param) { 2 }
+ let(:all_records) { to_gid_list(expected_priority_sorted_asc) }
+ end
+ end
+
+ context 'when descending' do
+ it_behaves_like 'sorted paginated query' do
+ let(:sort_param) { :PRIORITY_DESC }
+ let(:first_param) { 2 }
+ let(:all_records) { to_gid_list(expected_priority_sorted_desc) }
+ end
+ end
+ end
+ end
+
+ it 'includes a web_url' do
+ post_query
+
+ expect(issues_data[0]['webUrl']).to be_present
+ end
+
+ it 'includes discussion locked' do
+ post_query
+
+ expect(issues_data).to contain_exactly(
+ *locked_discussion_issues.map { |i| hash_including('id' => i.to_gid.to_s, 'discussionLocked' => true) },
+ *unlocked_discussion_issues.map { |i| hash_including('id' => i.to_gid.to_s, 'discussionLocked' => false) }
+ )
+ end
+
+ def to_gid_list(instance_list)
+ instance_list.map { |instance| instance.to_gid.to_s }
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb b/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb
index 1b609915f32..fb4aacfd7a9 100644
--- a/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/graphql/packages/group_and_project_packages_list_shared_examples.rb
@@ -114,7 +114,7 @@ RSpec.shared_examples 'group and project packages query' do
end
[:CREATED_ASC, :NAME_ASC, :VERSION_ASC, :TYPE_ASC, :CREATED_DESC, :NAME_DESC, :VERSION_DESC, :TYPE_DESC].each do |order|
- context "#{order}" do
+ context order.to_s do
let(:sorted_packages) { packages_order_map.fetch(order) }
it_behaves_like 'sorted paginated query' do
diff --git a/spec/support/shared_examples/requests/api/graphql/projects/branch_protections/access_level_request_examples.rb b/spec/support/shared_examples/requests/api/graphql/projects/branch_protections/access_level_request_examples.rb
new file mode 100644
index 00000000000..54cc13fac94
--- /dev/null
+++ b/spec/support/shared_examples/requests/api/graphql/projects/branch_protections/access_level_request_examples.rb
@@ -0,0 +1,77 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'perform graphql requests for AccessLevel type objects' do |access_level_kind|
+ include GraphqlHelpers
+
+ let_it_be(:project) { create(:project) }
+ let_it_be(:current_user) { create(:user, maintainer_projects: [project]) }
+ let_it_be(:variables) { { path: project.full_path } }
+
+ let(:fields) { all_graphql_fields_for("#{access_level_kind.to_s.classify}AccessLevel", max_depth: 2) }
+ let(:access_levels) { protected_branch.public_send("#{access_level_kind}_access_levels") }
+ let(:access_levels_count) { access_levels.size }
+ let(:maintainer_access_level) { access_levels.for_role.first }
+ let(:maintainer_access_level_data) { access_levels_data.first }
+ let(:access_levels_data) do
+ graphql_data_at('project',
+ 'branchRules',
+ 'nodes',
+ 0,
+ 'branchProtection',
+ "#{access_level_kind.to_s.camelize(:lower)}AccessLevels",
+ 'nodes')
+ end
+
+ let(:query) do
+ <<~GQL
+ query($path: ID!) {
+ project(fullPath: $path) {
+ branchRules(first: 1) {
+ nodes {
+ branchProtection {
+ #{access_level_kind.to_s.camelize(:lower)}AccessLevels {
+ nodes {
+ #{fields}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ GQL
+ end
+
+ context 'when request AccessLevel type objects as a guest user' do
+ let_it_be(:protected_branch) { create(:protected_branch, project: project) }
+
+ before do
+ project.add_guest(current_user)
+
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it { expect(access_levels_data).not_to be_present }
+ end
+
+ context 'when request AccessLevel type objects as a maintainer' do
+ let_it_be(:protected_branch) do
+ create(:protected_branch, "maintainers_can_#{access_level_kind}", project: project)
+ end
+
+ before do
+ post_graphql(query, current_user: current_user, variables: variables)
+ end
+
+ it_behaves_like 'a working graphql query'
+
+ it 'returns all the access level attributes' do
+ expect(maintainer_access_level_data['accessLevel']).to eq(maintainer_access_level.access_level)
+ expect(maintainer_access_level_data['accessLevelDescription']).to eq(maintainer_access_level.humanize)
+ expect(maintainer_access_level_data.dig('group', 'name')).to be_nil
+ expect(maintainer_access_level_data.dig('user', 'name')).to be_nil
+ end
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/issues_shared_examples.rb b/spec/support/shared_examples/requests/api/issues_shared_examples.rb
index 991dbced02d..6328fb9cd8a 100644
--- a/spec/support/shared_examples/requests/api/issues_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/issues_shared_examples.rb
@@ -37,7 +37,7 @@ RSpec.shared_examples 'labeled issues with labels and label_name params' do
context 'negation' do
context 'array of labeled issues when all labels match with negation' do
- let(:params) { { labels: "#{label.title},#{label_b.title}", not: { labels: "#{label_c.title}" } } }
+ let(:params) { { labels: "#{label.title},#{label_b.title}", not: { labels: label_c.title.to_s } } }
it_behaves_like 'returns negated label names'
end
diff --git a/spec/support/shared_examples/requests/api/members_shared_examples.rb b/spec/support/shared_examples/requests/api/members_shared_examples.rb
index fce75c29971..9136f60eb93 100644
--- a/spec/support/shared_examples/requests/api/members_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/members_shared_examples.rb
@@ -11,3 +11,11 @@ RSpec.shared_examples 'a 404 response when source is private' do
expect(response).to have_gitlab_http_status(:not_found)
end
end
+
+RSpec.shared_examples 'a 403 response when user does not have rights to manage members of a specific access level' do
+ it 'returns 403' do
+ route
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+end
diff --git a/spec/support/shared_examples/requests/api/multiple_and_scoped_issue_boards_shared_examples.rb b/spec/support/shared_examples/requests/api/multiple_and_scoped_issue_boards_shared_examples.rb
index fa111ca5811..d749479544d 100644
--- a/spec/support/shared_examples/requests/api/multiple_and_scoped_issue_boards_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/multiple_and_scoped_issue_boards_shared_examples.rb
@@ -5,6 +5,7 @@ RSpec.shared_examples 'multiple and scoped issue boards' do |route_definition|
context 'multiple issue boards' do
before do
+ stub_feature_flags(apollo_boards: false)
board_parent.add_reporter(user)
stub_licensed_features(multiple_group_issue_boards: true)
end
diff --git a/spec/support/shared_examples/requests/api/notes_shared_examples.rb b/spec/support/shared_examples/requests/api/notes_shared_examples.rb
index 8479493911b..11f9565989f 100644
--- a/spec/support/shared_examples/requests/api/notes_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/notes_shared_examples.rb
@@ -179,7 +179,8 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
end
end
- if parent_type == 'projects'
+ case parent_type
+ when 'projects'
context 'by a project owner' do
let(:user) { project.first_owner }
@@ -211,7 +212,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
expect(Time.parse(json_response['updated_at'])).to be_like_time(creation_time)
end
end
- elsif parent_type == 'groups'
+ when 'groups'
context 'by a group owner' do
it 'sets the creation time on the new note' do
post api("/#{parent_type}/#{parent.id}/#{noteable_type}/#{noteable[id_name]}/notes", user), params: params
@@ -288,7 +289,7 @@ RSpec.shared_examples 'noteable API' do |parent_type, noteable_type, id_name|
end
it 'allows user in allow-list to create notes' do
- stub_application_setting(notes_create_limit_allowlist: ["#{user.username}"])
+ stub_application_setting(notes_create_limit_allowlist: [user.username.to_s])
subject
expect(response).to have_gitlab_http_status(:created)
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 11e19d8d067..a9b44015206 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
@@ -221,6 +221,27 @@ RSpec.shared_examples 'rejects PyPI access with unknown group id' do
end
end
+RSpec.shared_examples 'allow access for everyone with public package_registry_access_level' do
+ context 'with private project but public access to package registry' do
+ before do
+ project.update_column(:visibility_level, Gitlab::VisibilityLevel::PRIVATE)
+ project.project_feature.update!(package_registry_access_level: ProjectFeature::PUBLIC)
+ end
+
+ context 'as non-member user' do
+ let(:headers) { basic_auth_header(user.username, personal_access_token.token) }
+
+ it_behaves_like 'returning response status', :success
+ end
+
+ context 'as anonymous' do
+ let(:headers) { {} }
+
+ it_behaves_like 'returning response status', :success
+ end
+ end
+end
+
RSpec.shared_examples 'pypi simple API endpoint' do
using RSpec::Parameterized::TableSyntax
diff --git a/spec/support/shared_examples/requests/api/terraform/modules/v1/packages_shared_examples.rb b/spec/support/shared_examples/requests/api/terraform/modules/v1/packages_shared_examples.rb
index 544a0ed8fdd..bdff2c65691 100644
--- a/spec/support/shared_examples/requests/api/terraform/modules/v1/packages_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/terraform/modules/v1/packages_shared_examples.rb
@@ -63,9 +63,9 @@ RSpec.shared_examples 'redirects to version download' do |user_type, status, add
it 'returns a valid response' do
subject
- expect(request.url).to include 'module-1/system/download'
+ expect(request.url).to include "#{package.name}/download"
expect(response.headers).to include 'Location'
- expect(response.headers['Location']).to include 'module-1/system/1.0.1/download'
+ expect(response.headers['Location']).to include "#{package.name}/1.0.1/download"
end
end
end
diff --git a/spec/support/shared_examples/services/alert_management_shared_examples.rb b/spec/support/shared_examples/services/alert_management_shared_examples.rb
index 571cb7dc03d..b46ace1824a 100644
--- a/spec/support/shared_examples/services/alert_management_shared_examples.rb
+++ b/spec/support/shared_examples/services/alert_management_shared_examples.rb
@@ -72,8 +72,8 @@ RSpec.shared_examples 'processes one firing and one resolved prometheus alerts'
.and change(Note, :count).by(1)
expect(subject).to be_success
- expect(subject.payload[:alerts]).to all(be_a_kind_of(AlertManagement::Alert))
- expect(subject.payload[:alerts].size).to eq(1)
+ expect(subject.payload).to eq({})
+ expect(subject.http_status).to eq(:created)
end
it_behaves_like 'processes incident issues'
diff --git a/spec/support/shared_examples/services/base_rpm_service_shared_examples.rb b/spec/support/shared_examples/services/base_rpm_service_shared_examples.rb
deleted file mode 100644
index c9520852a5b..00000000000
--- a/spec/support/shared_examples/services/base_rpm_service_shared_examples.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.shared_examples 'handling rpm xml file' do
- include_context 'with rpm package data'
-
- let(:xml) { nil }
- let(:data) { {} }
-
- context 'when generate empty xml' do
- it 'generate expected xml' do
- expect(subject).to eq(empty_xml)
- end
- end
-
- context 'when updating existing xml' do
- let(:xml) { empty_xml }
- let(:data) { xml_update_params }
-
- shared_examples 'changing root tag attribute' do
- it "increment previous 'packages' value by 1" do
- previous_value = Nokogiri::XML(xml).at(described_class::ROOT_TAG).attributes["packages"].value.to_i
- new_value = Nokogiri::XML(subject).at(described_class::ROOT_TAG).attributes["packages"].value.to_i
-
- expect(previous_value + 1).to eq(new_value)
- end
- end
-
- it 'generate valid xml add expected xml node to existing xml' do
- # Have one root attribute
- result = Nokogiri::XML::Document.parse(subject).remove_namespaces!
- expect(result.children.count).to eq(1)
-
- # Root node has 1 child with generated node
- expect(result.xpath("//#{described_class::ROOT_TAG}/package").count).to eq(1)
- end
-
- context 'when empty xml' do
- it_behaves_like 'changing root tag attribute'
- end
-
- context 'when xml has children' do
- let(:xml) { described_class.new(xml: empty_xml, data: data).execute }
-
- it 'has children nodes' do
- result = Nokogiri::XML::Document.parse(xml).remove_namespaces!
- expect(result.children.count).to be > 0
- end
-
- it_behaves_like 'changing root tag attribute'
- end
- end
-end
diff --git a/spec/support/shared_examples/services/issuable/discussions_list_shared_examples.rb b/spec/support/shared_examples/services/issuable/discussions_list_shared_examples.rb
new file mode 100644
index 00000000000..c38ca6a3bf0
--- /dev/null
+++ b/spec/support/shared_examples/services/issuable/discussions_list_shared_examples.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'listing issuable discussions' do |user_role, internal_discussion_count, total_discussions_count|
+ before_all do
+ create_notes(issuable, "some user comment")
+ end
+
+ context 'when user cannot read issue' do
+ it "returns no notes" do
+ expect(discussions_service.execute).to be_empty
+ end
+ end
+
+ context 'when user can read issuable' do
+ before do
+ group.add_developer(current_user)
+ end
+
+ context 'with paginated results' do
+ let(:finder_params_for_issuable) { { per_page: 2 } }
+ let(:next_page_cursor) { { cursor: discussions_service.paginator.cursor_for_next_page } }
+
+ it "returns next page notes" do
+ next_page_discussions_service = described_class.new(current_user, issuable,
+ finder_params_for_issuable.merge(next_page_cursor))
+ discussions = next_page_discussions_service.execute
+
+ expect(discussions.count).to eq(2)
+ expect(discussions.first.notes.map(&:note)).to match_array(["added #{label.to_reference} label"])
+ expect(discussions.second.notes.map(&:note)).to match_array(["removed #{label.to_reference} label"])
+ end
+ end
+
+ # confidential notes are currently available only on issues and epics
+ context 'and cannot read confidential notes' do
+ before do
+ group.add_member(current_user, user_role)
+ end
+
+ it "returns non confidential notes" do
+ discussions = discussions_service.execute
+
+ non_conf_discussion_count = total_discussions_count - internal_discussion_count
+ expect(discussions.count).to eq(non_conf_discussion_count)
+ expect(discussions.count { |disc| disc.notes.any?(&:confidential) }).to eq(0)
+ expect(discussions.count { |disc| !disc.notes.any?(&:confidential) }).to eq(non_conf_discussion_count)
+ end
+ end
+
+ # confidential notes are currently available only on issues and epics
+ context 'and can read confidential notes' do
+ it "returns all notes" do
+ discussions = discussions_service.execute
+
+ expect(discussions.count).to eq(total_discussions_count)
+ expect(discussions.count { |disc| disc.notes.any?(&:confidential) }).to eq(internal_discussion_count)
+ non_conf_discussion_count = total_discussions_count - internal_discussion_count
+ expect(discussions.count { |disc| !disc.notes.any?(&:confidential) }).to eq(non_conf_discussion_count)
+ end
+ end
+
+ context 'and system notes only' do
+ let(:finder_params_for_issuable) { { notes_filter: UserPreference::NOTES_FILTERS[:only_activity] } }
+
+ it "returns system notes" do
+ discussions = discussions_service.execute
+
+ expect(discussions.count { |disc| disc.notes.any?(&:system) }).to be > 0
+ expect(discussions.count { |disc| !disc.notes.any?(&:system) }).to eq(0)
+ end
+ end
+
+ context 'and user comments only' do
+ let(:finder_params_for_issuable) { { notes_filter: UserPreference::NOTES_FILTERS[:only_comments] } }
+
+ it "returns user comments" do
+ discussions = discussions_service.execute
+
+ expect(discussions.count { |disc| disc.notes.any?(&:system) }).to eq(0)
+ expect(discussions.count { |disc| !disc.notes.any?(&:system) }).to be > 0
+ end
+ end
+ end
+end
+
+def create_notes(issuable, note_body)
+ assoc_name = issuable.to_ability_name
+
+ create(:note, system: true, project: issuable.project, noteable: issuable)
+
+ first_discussion = create(:discussion_note_on_issue, noteable: issuable, project: issuable.project, note: note_body)
+ create(:note,
+ discussion_id: first_discussion.discussion_id, noteable: issuable,
+ project: issuable.project, note: "reply on #{note_body}")
+
+ create(:resource_label_event, user: current_user, "#{assoc_name}": issuable, label: label, action: 'add')
+ create(:resource_label_event, user: current_user, "#{assoc_name}": issuable, label: label, action: 'remove')
+
+ unless issuable.is_a?(Epic)
+ create(:resource_milestone_event, "#{assoc_name}": issuable, milestone: milestone, action: 'add')
+ create(:resource_milestone_event, "#{assoc_name}": issuable, milestone: milestone, action: 'remove')
+ end
+
+ # confidential notes are currently available only on issues and epics
+ return unless issuable.is_a?(Issue) || issuable.is_a?(Epic)
+
+ first_internal_discussion = create(:discussion_note_on_issue, :confidential,
+ noteable: issuable, project: issuable.project, note: "confidential #{note_body}")
+ create(:note, :confidential,
+ discussion_id: first_internal_discussion.discussion_id, noteable: issuable,
+ project: issuable.project, note: "reply on confidential #{note_body}")
+end
diff --git a/spec/support/shared_examples/services/merge_status_updated_trigger_shared_examples.rb b/spec/support/shared_examples/services/merge_status_updated_trigger_shared_examples.rb
new file mode 100644
index 00000000000..97e3b0a44a7
--- /dev/null
+++ b/spec/support/shared_examples/services/merge_status_updated_trigger_shared_examples.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'triggers GraphQL subscription mergeRequestMergeStatusUpdated' do
+ specify do
+ expect(GraphqlTriggers).to receive(:merge_request_merge_status_updated).with(merge_request)
+
+ action
+ end
+end
+
+RSpec.shared_examples 'does not trigger GraphQL subscription mergeRequestMergeStatusUpdated' do
+ specify do
+ expect(GraphqlTriggers).not_to receive(:merge_request_merge_status_updated)
+
+ action
+ end
+end
diff --git a/spec/support/shared_examples/services/users/dismiss_user_callout_service_shared_examples.rb b/spec/support/shared_examples/services/users/dismiss_user_callout_service_shared_examples.rb
index 09820593cdb..46a1f4b6598 100644
--- a/spec/support/shared_examples/services/users/dismiss_user_callout_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/users/dismiss_user_callout_service_shared_examples.rb
@@ -20,7 +20,7 @@ RSpec.shared_examples_for 'dismissing user callout' do |model|
old_time = 1.day.ago
new_time = Time.current
attributes = params.merge(dismissed_at: old_time, user: user)
- existing_callout = create("#{model.name.split('::').last.underscore}".to_sym, attributes)
+ existing_callout = create(model.name.split('::').last.underscore.to_s.to_sym, attributes)
expect { execute }.to change { existing_callout.reload.dismissed_at }.from(old_time).to(new_time)
end
diff --git a/spec/support/shared_examples/services/work_items/widgets/milestone_service_shared_examples.rb b/spec/support/shared_examples/services/work_items/widgets/milestone_service_shared_examples.rb
new file mode 100644
index 00000000000..ac17915c15a
--- /dev/null
+++ b/spec/support/shared_examples/services/work_items/widgets/milestone_service_shared_examples.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples "setting work item's milestone" do
+ context "when 'milestone' param does not exist" do
+ let(:params) { {} }
+
+ it "does not set the work item's milestone" do
+ expect { execute_callback }.to not_change(work_item, :milestone)
+ end
+ end
+
+ context "when 'milestone' is not in the work item's project's hierarchy" do
+ let(:another_group_milestone) { create(:milestone, group: create(:group)) }
+ let(:params) { { milestone_id: another_group_milestone.id } }
+
+ it "does not set the work item's milestone" do
+ expect { execute_callback }.to not_change(work_item, :milestone)
+ end
+ end
+
+ context 'when assigning a group milestone' do
+ let(:params) { { milestone_id: group_milestone.id } }
+
+ it "sets the work item's milestone" do
+ expect { execute_callback }
+ .to change(work_item, :milestone)
+ .from(nil)
+ .to(group_milestone)
+ end
+ end
+
+ context 'when assigning a project milestone' do
+ let(:params) { { milestone_id: project_milestone.id } }
+
+ it "sets the work item's milestone" do
+ expect { execute_callback }
+ .to change(work_item, :milestone)
+ .from(nil)
+ .to(project_milestone)
+ end
+ end
+end
diff --git a/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb b/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb
index 3c977e62a10..af56f8ffac7 100644
--- a/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb
+++ b/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb
@@ -26,9 +26,10 @@ RSpec.shared_examples "migrates" do |to_store:, from_store: nil|
expect(subject).to be_an(CarrierWave::Uploader::Base)
expect(subject).to be_a(ObjectStorage::Concern)
- if from == described_class::Store::REMOTE
+ case from
+ when described_class::Store::REMOTE
expect(subject.file).to be_a(CarrierWave::Storage::Fog::File)
- elsif from == described_class::Store::LOCAL
+ when described_class::Store::LOCAL
expect(subject.file).to be_a(CarrierWave::SanitizedFile)
else
raise 'Unexpected file type'
diff --git a/spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb b/spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb
index 3ba5f080a01..0be55fd2a3e 100644
--- a/spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb
+++ b/spec/support/shared_examples/workers/batched_background_migration_worker_shared_examples.rb
@@ -137,8 +137,12 @@ RSpec.shared_examples 'it runs batched background migration jobs' do |tracking_d
let(:lease_timeout) { 15.minutes }
let(:lease_key) { described_class.name.demodulize.underscore }
let(:interval_variance) { described_class::INTERVAL_VARIANCE }
+ let(:migration_id) { 123 }
let(:migration) do
- build(:batched_background_migration, :active, interval: job_interval, table_name: table_name)
+ build(
+ :batched_background_migration, :active,
+ id: migration_id, interval: job_interval, table_name: table_name
+ )
end
before do
@@ -150,45 +154,6 @@ RSpec.shared_examples 'it runs batched background migration jobs' do |tracking_d
allow(migration).to receive(:reload)
end
- context 'when the reloaded migration is no longer active' do
- it 'does not run the migration' do
- expect_to_obtain_exclusive_lease(lease_key, timeout: lease_timeout)
-
- expect(migration).to receive(:reload)
- expect(migration).to receive(:active?).and_return(false)
-
- expect(worker).not_to receive(:run_active_migration)
-
- worker.perform
- end
- end
-
- context 'when the interval has not elapsed' do
- it 'does not run the migration' do
- expect_to_obtain_exclusive_lease(lease_key, timeout: lease_timeout)
-
- expect(migration).to receive(:interval_elapsed?).with(variance: interval_variance).and_return(false)
-
- expect(worker).not_to receive(:run_active_migration)
-
- worker.perform
- end
- end
-
- context 'when the reloaded migration is still active and the interval has elapsed' do
- it 'runs the migration' do
- expect_to_obtain_exclusive_lease(lease_key, timeout: lease_timeout)
-
- expect_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationRunner) do |instance|
- expect(instance).to receive(:run_migration_job).with(migration)
- end
-
- expect(worker).to receive(:run_active_migration).and_call_original
-
- worker.perform
- end
- end
-
context 'when the calculated timeout is less than the minimum allowed' do
let(:minimum_timeout) { described_class::MINIMUM_LEASE_TIMEOUT }
let(:job_interval) { 2.minutes }
@@ -196,8 +161,8 @@ RSpec.shared_examples 'it runs batched background migration jobs' do |tracking_d
it 'sets the lease timeout to the minimum value' do
expect_to_obtain_exclusive_lease(lease_key, timeout: minimum_timeout)
- expect_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationRunner) do |instance|
- expect(instance).to receive(:run_migration_job).with(migration)
+ expect_next_instance_of(Database::BatchedBackgroundMigration::ExecutionWorker) do |worker|
+ expect(worker).to receive(:perform).with(tracking_database, migration_id)
end
expect(worker).to receive(:run_active_migration).and_call_original
@@ -217,10 +182,13 @@ RSpec.shared_examples 'it runs batched background migration jobs' do |tracking_d
expect { worker.perform }.to raise_error(RuntimeError, 'I broke')
end
- it 'receives the correct connection' do
+ it 'delegetes the execution to ExecutionWorker' do
base_model = Gitlab::Database.database_base_models[tracking_database]
expect(Gitlab::Database::SharedModel).to receive(:using_connection).with(base_model.connection).and_yield
+ expect_next_instance_of(Database::BatchedBackgroundMigration::ExecutionWorker) do |worker|
+ expect(worker).to receive(:perform).with(tracking_database, migration_id)
+ end
worker.perform
end
@@ -236,10 +204,10 @@ RSpec.shared_examples 'it runs batched background migration jobs' do |tracking_d
let(:migration_class) do
Class.new(Gitlab::BackgroundMigration::BatchedMigrationJob) do
job_arguments :matching_status
+ operation_name :update_all
def perform
each_sub_batch(
- operation_name: :update_all,
batching_scope: -> (relation) { relation.where(status: matching_status) }
) do |sub_batch|
sub_batch.update_all(some_column: 0)
diff --git a/spec/support/sidekiq_middleware.rb b/spec/support/sidekiq_middleware.rb
index cbd6163d46b..73f43487d7c 100644
--- a/spec/support/sidekiq_middleware.rb
+++ b/spec/support/sidekiq_middleware.rb
@@ -6,6 +6,15 @@ require 'sidekiq/testing'
module SidekiqMiddleware
def with_sidekiq_server_middleware(&block)
Sidekiq::Testing.server_middleware.clear
+
+ if Gem::Version.new(Sidekiq::VERSION) != Gem::Version.new('6.5.7')
+ raise 'New version of sidekiq detected, please remove this line'
+ end
+
+ # This line is a workaround for a Sidekiq bug that is already fixed in v7.0.0
+ # https://github.com/mperham/sidekiq/commit/1b83a152786ed382f07fff12d2608534f1e3c922
+ Sidekiq::Testing.server_middleware.instance_variable_set(:@config, Sidekiq)
+
Sidekiq::Testing.server_middleware(&block)
ensure
Sidekiq::Testing.server_middleware.clear
diff --git a/spec/support/webmock.rb b/spec/support/webmock.rb
index f952f7f0985..b9bd3f82f65 100644
--- a/spec/support/webmock.rb
+++ b/spec/support/webmock.rb
@@ -15,6 +15,13 @@ def webmock_allowed_hosts
end.compact.uniq
end
+def with_net_connect_allowed
+ WebMock.allow_net_connect!
+ yield
+ensure
+ webmock_enable!
+end
+
# This prevents Selenium/WebMock from spawning thousands of connections
# while waiting for an element to appear via Capybara's find:
# https://github.com/teamcapybara/capybara/issues/2322#issuecomment-619321520
diff --git a/spec/support_specs/database/multiple_databases_helpers_spec.rb b/spec/support_specs/database/multiple_databases_helpers_spec.rb
new file mode 100644
index 00000000000..eb0e980d376
--- /dev/null
+++ b/spec/support_specs/database/multiple_databases_helpers_spec.rb
@@ -0,0 +1,121 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Database::MultipleDatabasesHelpers' do
+ let(:query) do
+ <<~SQL
+ WITH cte AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (SELECT 1) SELECT 1;
+ SQL
+ end
+
+ it 'preloads database version for ApplicationRecord' do
+ counts = ActiveRecord::QueryRecorder
+ .new { ApplicationRecord.connection.execute(query) }
+ .count
+
+ expect(counts).to eq(1)
+ end
+
+ it 'preloads database version for Ci::ApplicationRecord' do
+ counts = ActiveRecord::QueryRecorder
+ .new { Ci::ApplicationRecord.connection.execute(query) }
+ .count
+
+ expect(counts).to eq(1)
+ end
+
+ describe '.with_reestablished_active_record_base' do
+ context 'when doing establish_connection' do
+ context 'on ActiveRecord::Base' do
+ it 'raises exception' do
+ expect { ActiveRecord::Base.establish_connection(:main) }.to raise_error /Cannot re-establish/ # rubocop: disable Database/EstablishConnection
+ end
+
+ context 'when using with_reestablished_active_record_base' do
+ it 'does not raise exception' do
+ with_reestablished_active_record_base do
+ expect { ActiveRecord::Base.establish_connection(:main) }.not_to raise_error # rubocop: disable Database/EstablishConnection
+ end
+ end
+ end
+ end
+
+ context 'on Ci::ApplicationRecord' do
+ before do
+ skip_if_multiple_databases_not_setup
+ end
+
+ it 'raises exception' do
+ expect { Ci::ApplicationRecord.establish_connection(:ci) }.to raise_error /Cannot re-establish/ # rubocop: disable Database/EstablishConnection
+ end
+
+ context 'when using with_reestablished_active_record_base' do
+ it 'does not raise exception' do
+ with_reestablished_active_record_base do
+ expect { Ci::ApplicationRecord.establish_connection(:main) }.not_to raise_error # rubocop: disable Database/EstablishConnection
+ end
+ end
+ end
+ end
+ end
+
+ context 'when trying to access connection' do
+ context 'when reconnect is true' do
+ it 'does not raise exception' do
+ with_reestablished_active_record_base(reconnect: true) do
+ expect { ApplicationRecord.connection.execute("SELECT 1") }.not_to raise_error
+ end
+ end
+ end
+
+ context 'when reconnect is false' do
+ it 'does raise exception' do
+ with_reestablished_active_record_base(reconnect: false) do
+ expect { ApplicationRecord.connection.execute("SELECT 1") }
+ .to raise_error(ActiveRecord::ConnectionNotEstablished)
+ end
+ end
+ end
+ end
+ end
+
+ describe '.with_added_ci_connection' do
+ context 'when only a single database is setup' do
+ before do
+ skip_if_multiple_databases_are_setup
+ end
+
+ it 'connects Ci::ApplicationRecord to the main database for the duration of the block', :aggregate_failures do
+ main_database = current_database(ActiveRecord::Base)
+ original_database = current_database(Ci::ApplicationRecord)
+
+ with_added_ci_connection do
+ expect(current_database(Ci::ApplicationRecord)).to eq(main_database)
+ end
+
+ expect(current_database(Ci::ApplicationRecord)).to eq(original_database)
+ end
+ end
+
+ context 'when multiple databases are setup' do
+ before do
+ skip_if_multiple_databases_not_setup
+ end
+
+ it 'does not mock the original Ci::ApplicationRecord connection', :aggregate_failures do
+ original_database = current_database(Ci::ApplicationRecord)
+
+ with_added_ci_connection do
+ expect(current_database(Ci::ApplicationRecord)).to eq(original_database)
+ end
+
+ expect(current_database(Ci::ApplicationRecord)).to eq(original_database)
+ end
+ end
+
+ def current_database(connection_class)
+ connection_class.retrieve_connection.execute('select current_database()').first
+ end
+ end
+end
diff --git a/spec/support_specs/database/multiple_databases_spec.rb b/spec/support_specs/database/multiple_databases_spec.rb
deleted file mode 100644
index 0b019462077..00000000000
--- a/spec/support_specs/database/multiple_databases_spec.rb
+++ /dev/null
@@ -1,120 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'Database::MultipleDatabases' do
- let(:query) do
- <<~SQL
- WITH cte AS #{Gitlab::Database::AsWithMaterialized.materialized_if_supported} (SELECT 1) SELECT 1;
- SQL
- end
-
- it 'preloads database version for ApplicationRecord' do
- counts = ActiveRecord::QueryRecorder
- .new { ApplicationRecord.connection.execute(query) }
- .count
-
- expect(counts).to eq(1)
- end
-
- it 'preloads database version for Ci::ApplicationRecord' do
- counts = ActiveRecord::QueryRecorder
- .new { Ci::ApplicationRecord.connection.execute(query) }
- .count
-
- expect(counts).to eq(1)
- end
-
- describe '.with_reestablished_active_record_base' do
- context 'when doing establish_connection' do
- context 'on ActiveRecord::Base' do
- it 'raises exception' do
- expect { ActiveRecord::Base.establish_connection(:main) }.to raise_error /Cannot re-establish/ # rubocop: disable Database/EstablishConnection
- end
-
- context 'when using with_reestablished_active_record_base' do
- it 'does not raise exception' do
- with_reestablished_active_record_base do
- expect { ActiveRecord::Base.establish_connection(:main) }.not_to raise_error # rubocop: disable Database/EstablishConnection
- end
- end
- end
- end
-
- context 'on Ci::ApplicationRecord' do
- before do
- skip_if_multiple_databases_not_setup
- end
-
- it 'raises exception' do
- expect { Ci::ApplicationRecord.establish_connection(:ci) }.to raise_error /Cannot re-establish/ # rubocop: disable Database/EstablishConnection
- end
-
- context 'when using with_reestablished_active_record_base' do
- it 'does not raise exception' do
- with_reestablished_active_record_base do
- expect { Ci::ApplicationRecord.establish_connection(:main) }.not_to raise_error # rubocop: disable Database/EstablishConnection
- end
- end
- end
- end
- end
-
- context 'when trying to access connection' do
- context 'when reconnect is true' do
- it 'does not raise exception' do
- with_reestablished_active_record_base(reconnect: true) do
- expect { ApplicationRecord.connection.execute("SELECT 1") }.not_to raise_error
- end
- end
- end
-
- context 'when reconnect is false' do
- it 'does raise exception' do
- with_reestablished_active_record_base(reconnect: false) do
- expect { ApplicationRecord.connection.execute("SELECT 1") }.to raise_error(ActiveRecord::ConnectionNotEstablished)
- end
- end
- end
- end
- end
-
- describe '.with_added_ci_connection' do
- context 'when only a single database is setup' do
- before do
- skip_if_multiple_databases_are_setup
- end
-
- it 'connects Ci::ApplicationRecord to the main database for the duration of the block', :aggregate_failures do
- main_database = current_database(ActiveRecord::Base)
- original_database = current_database(Ci::ApplicationRecord)
-
- with_added_ci_connection do
- expect(current_database(Ci::ApplicationRecord)).to eq(main_database)
- end
-
- expect(current_database(Ci::ApplicationRecord)).to eq(original_database)
- end
- end
-
- context 'when multiple databases are setup' do
- before do
- skip_if_multiple_databases_not_setup
- end
-
- it 'does not mock the original Ci::ApplicationRecord connection', :aggregate_failures do
- original_database = current_database(Ci::ApplicationRecord)
-
- with_added_ci_connection do
- expect(current_database(Ci::ApplicationRecord)).to eq(original_database)
- end
-
- expect(current_database(Ci::ApplicationRecord)).to eq(original_database)
- end
- end
-
- def current_database(connection_class)
- connection_class.retrieve_connection.execute('select current_database()').first
- end
- end
-end
diff --git a/spec/support_specs/graphql/arguments_spec.rb b/spec/support_specs/graphql/arguments_spec.rb
index 925af1ab79c..925f8c15d68 100644
--- a/spec/support_specs/graphql/arguments_spec.rb
+++ b/spec/support_specs/graphql/arguments_spec.rb
@@ -6,14 +6,14 @@ RSpec.describe Graphql::Arguments do
it 'returns a blank string if the arguments are blank' do
args = described_class.new({})
- expect("#{args}").to be_blank
+ expect(args.to_s).to be_blank
end
it 'returns a serialized arguments if the arguments are not blank' do
units = described_class.new({ temp: :CELSIUS, time: :MINUTES })
args = described_class.new({ temp: 180, time: 45, units: units })
- expect("#{args}").to eq('temp: 180, time: 45, units: {temp: CELSIUS, time: MINUTES}')
+ expect(args.to_s).to eq('temp: 180, time: 45, units: {temp: CELSIUS, time: MINUTES}')
end
it 'supports merge with +' do
diff --git a/spec/tasks/gitlab/sidekiq_rake_spec.rb b/spec/tasks/gitlab/sidekiq_rake_spec.rb
index 75f904389e2..0e5111c90a1 100644
--- a/spec/tasks/gitlab/sidekiq_rake_spec.rb
+++ b/spec/tasks/gitlab/sidekiq_rake_spec.rb
@@ -9,7 +9,10 @@ RSpec.describe 'sidekiq.rake', :aggregate_failures, :silence_stdout do
stub_warn_user_is_not_gitlab
end
+ let(:migrator) { ::Gitlab::SidekiqMigrateJobs.new(mappings, logger: Logger.new($stdout)) }
+
shared_examples 'migration rake task' do
+ let(:mappings) { {} }
it 'runs the migrator with a mapping of workers to queues' do
test_routes = [
['urgency=high', 'default'],
@@ -17,20 +20,17 @@ RSpec.describe 'sidekiq.rake', :aggregate_failures, :silence_stdout do
]
test_router = ::Gitlab::SidekiqConfig::WorkerRouter.new(test_routes)
- migrator = ::Gitlab::SidekiqMigrateJobs.new(sidekiq_set, logger: Logger.new($stdout))
allow(::Gitlab::SidekiqConfig::WorkerRouter)
.to receive(:global).and_return(test_router)
expect(::Gitlab::SidekiqMigrateJobs)
- .to receive(:new).with(sidekiq_set, logger: an_instance_of(Logger)).and_return(migrator)
+ .to receive(:new).with(a_hash_including('PostReceive' => 'default',
+ 'MergeWorker' => 'default',
+ 'DeleteDiffFilesWorker' => 'delete_diff_files'),
+ logger: an_instance_of(Logger)).and_return(migrator)
- expect(migrator)
- .to receive(:execute)
- .with(a_hash_including('PostReceive' => 'default',
- 'MergeWorker' => 'default',
- 'DeleteDiffFilesWorker' => 'delete_diff_files'))
- .and_call_original
+ expect(migrator).to receive(:migrate_set).with(sidekiq_set).and_call_original
run_rake_task("gitlab:sidekiq:migrate_jobs:#{sidekiq_set}")
@@ -50,4 +50,30 @@ RSpec.describe 'sidekiq.rake', :aggregate_failures, :silence_stdout do
it_behaves_like 'migration rake task'
end
+
+ describe 'gitlab:sidekiq:migrate_jobs:queued rake task' do
+ let(:mappings) { { 'PostReceive' => 'default' } }
+
+ it 'runs the migrator with a mapping of workers to queues' do
+ test_routes = [
+ ['*', 'default']
+ ]
+
+ test_router = ::Gitlab::SidekiqConfig::WorkerRouter.new(test_routes)
+
+ allow(::Gitlab::SidekiqConfig::WorkerRouter)
+ .to receive(:global).and_return(test_router)
+
+ expect(::Gitlab::SidekiqMigrateJobs)
+ .to receive(:new).with(a_hash_including('PostReceive' => 'default',
+ 'MergeWorker' => 'default'),
+ logger: an_instance_of(Logger)).and_return(migrator)
+
+ expect(migrator).to receive(:migrate_queues).and_call_original
+
+ run_rake_task("gitlab:sidekiq:migrate_jobs:queued")
+
+ expect($stdout.string).to include('List of queues based on routing rules: ["default"]')
+ end
+ end
end
diff --git a/spec/tasks/gitlab/update_templates_rake_spec.rb b/spec/tasks/gitlab/update_templates_rake_spec.rb
index 7eccdf22a1f..85da490f718 100644
--- a/spec/tasks/gitlab/update_templates_rake_spec.rb
+++ b/spec/tasks/gitlab/update_templates_rake_spec.rb
@@ -4,6 +4,7 @@ require 'rake_helper'
RSpec.describe 'gitlab:update_project_templates rake task', :silence_stdout do
let!(:tmpdir) { Dir.mktmpdir }
+ let(:template) { Gitlab::ProjectTemplate.find(:rails) }
before do
Rake.application.rake_require 'tasks/gitlab/update_templates'
@@ -14,7 +15,7 @@ RSpec.describe 'gitlab:update_project_templates rake task', :silence_stdout do
.and_return(Pathname.new(tmpdir))
# Gitlab::HTTP resolves the domain to an IP prior to WebMock taking effect, hence the wildcard
- stub_request(:get, %r{^https://.*/api/v4/projects/gitlab-org%2Fproject-templates%2Frails/repository/commits\?page=1&per_page=1})
+ stub_request(:get, %r{^https://.*/api/v4/projects/#{template.uri_encoded_project_path}/repository/commits\?page=1&per_page=1})
.to_return(
status: 200,
body: [{ id: '67812735b83cb42710f22dc98d73d42c8bf4d907' }].to_json,
@@ -27,8 +28,8 @@ RSpec.describe 'gitlab:update_project_templates rake task', :silence_stdout do
end
it 'updates valid project templates' do
- expect { run_rake_task('gitlab:update_project_templates', ['rails']) }
+ expect { run_rake_task('gitlab:update_project_templates', [template.name]) }
.to change { Dir.entries(tmpdir) }
- .by(['rails.tar.gz'])
+ .by(["#{template.name}.tar.gz"])
end
end
diff --git a/spec/tooling/danger/project_helper_spec.rb b/spec/tooling/danger/project_helper_spec.rb
index 6793a4b8de3..f9ad9ed13c2 100644
--- a/spec/tooling/danger/project_helper_spec.rb
+++ b/spec/tooling/danger/project_helper_spec.rb
@@ -33,6 +33,12 @@ RSpec.describe Tooling::Danger::ProjectHelper do
where(:path, :expected_categories) do
'glfm_specification/example_snapshots/prosemirror_json.yml' | [:frontend]
'glfm_specification/input/glfm_anything.yml' | [:frontend, :backend]
+
+ 'doc/api/graphql/reference/index.md' | [:docs, :backend]
+ 'doc/api/graphql/reference/some_other_file.txt' | [:docs, :backend]
+ 'doc/api/openapi/openapi.yaml' | [:docs, :backend]
+ 'doc/api/openapi/any_other_file.yaml' | [:docs, :backend]
+
'usage_data.rb' | [:database, :backend, :product_intelligence]
'doc/foo.md' | [:docs]
'CONTRIBUTING.md' | [:docs]
diff --git a/spec/tooling/lib/tooling/find_codeowners_spec.rb b/spec/tooling/lib/tooling/find_codeowners_spec.rb
index 5f6f83ab2c7..e75793b69c6 100644
--- a/spec/tooling/lib/tooling/find_codeowners_spec.rb
+++ b/spec/tooling/lib/tooling/find_codeowners_spec.rb
@@ -63,7 +63,7 @@ RSpec.describe Tooling::FindCodeowners do
}
},
'[Compliance]': {
- '@gitlab-org/manage/compliance': {
+ '@gitlab-org/govern/compliance': {
entries: %w[
/ee/app/services/audit_events/build_service.rb
],
@@ -115,7 +115,7 @@ RSpec.describe Tooling::FindCodeowners do
it 'retains the array and expands the patterns for the compliance group' do
compliance = subject.load_definitions.dig(
:'[Compliance]',
- :'@gitlab-org/manage/compliance')
+ :'@gitlab-org/govern/compliance')
expect(compliance).to eq(
entries: %w[
diff --git a/spec/tooling/lib/tooling/helm3_client_spec.rb b/spec/tooling/lib/tooling/helm3_client_spec.rb
index 41c51ec5754..52d1b5a1567 100644
--- a/spec/tooling/lib/tooling/helm3_client_spec.rb
+++ b/spec/tooling/lib/tooling/helm3_client_spec.rb
@@ -35,7 +35,7 @@ RSpec.describe Tooling::Helm3Client do
describe '#releases' do
it 'raises an error if the Helm command fails' do
expect(Gitlab::Popen).to receive(:popen_with_detail)
- .with([%(helm list --namespace "#{namespace}" --max 256 --offset 0 --output json)])
+ .with([%(helm list --max 256 --offset 0 --output json)])
.and_return(Gitlab::Popen::Result.new([], '', '', double(success?: false)))
expect { subject.releases.to_a }.to raise_error(described_class::CommandFailedError)
@@ -43,7 +43,7 @@ RSpec.describe Tooling::Helm3Client do
it 'calls helm list with default arguments' do
expect(Gitlab::Popen).to receive(:popen_with_detail)
- .with([%(helm list --namespace "#{namespace}" --max 256 --offset 0 --output json)])
+ .with([%(helm list --max 256 --offset 0 --output json)])
.and_return(Gitlab::Popen::Result.new([], '', '', double(success?: true)))
subject.releases.to_a
@@ -51,7 +51,7 @@ RSpec.describe Tooling::Helm3Client do
it 'calls helm list with extra arguments' do
expect(Gitlab::Popen).to receive(:popen_with_detail)
- .with([%(helm list --namespace "#{namespace}" --max 256 --offset 0 --output json --deployed)])
+ .with([%(helm list --max 256 --offset 0 --output json --deployed)])
.and_return(Gitlab::Popen::Result.new([], '', '', double(success?: true)))
subject.releases(args: ['--deployed']).to_a
@@ -59,7 +59,7 @@ RSpec.describe Tooling::Helm3Client do
it 'returns a list of Release objects' do
expect(Gitlab::Popen).to receive(:popen_with_detail)
- .with([%(helm list --namespace "#{namespace}" --max 256 --offset 0 --output json --deployed)])
+ .with([%(helm list --max 256 --offset 0 --output json --deployed)])
.and_return(Gitlab::Popen::Result.new([], raw_helm_list_page2, '', double(success?: true)))
expect(Gitlab::Popen).to receive(:popen_with_detail).ordered
.and_return(Gitlab::Popen::Result.new([], raw_helm_list_empty, '', double(success?: true)))
@@ -80,13 +80,13 @@ RSpec.describe Tooling::Helm3Client do
it 'automatically paginates releases' do
expect(Gitlab::Popen).to receive(:popen_with_detail).ordered
- .with([%(helm list --namespace "#{namespace}" --max 256 --offset 0 --output json)])
+ .with([%(helm list --max 256 --offset 0 --output json)])
.and_return(Gitlab::Popen::Result.new([], raw_helm_list_page1, '', double(success?: true)))
expect(Gitlab::Popen).to receive(:popen_with_detail).ordered
- .with([%(helm list --namespace "#{namespace}" --max 256 --offset 256 --output json)])
+ .with([%(helm list --max 256 --offset 256 --output json)])
.and_return(Gitlab::Popen::Result.new([], raw_helm_list_page2, '', double(success?: true)))
expect(Gitlab::Popen).to receive(:popen_with_detail).ordered
- .with([%(helm list --namespace "#{namespace}" --max 256 --offset 512 --output json)])
+ .with([%(helm list --max 256 --offset 512 --output json)])
.and_return(Gitlab::Popen::Result.new([], raw_helm_list_empty, '', double(success?: true)))
releases = subject.releases.to_a
@@ -98,7 +98,7 @@ RSpec.describe Tooling::Helm3Client do
describe '#delete' do
it 'raises an error if the Helm command fails' do
expect(Gitlab::Popen).to receive(:popen_with_detail)
- .with([%(helm uninstall --namespace "#{namespace}" #{release_name})])
+ .with([%(helm uninstall #{release_name})])
.and_return(Gitlab::Popen::Result.new([], '', '', double(success?: false)))
expect { subject.delete(release_name: release_name) }.to raise_error(described_class::CommandFailedError)
@@ -106,7 +106,7 @@ RSpec.describe Tooling::Helm3Client do
it 'calls helm uninstall with default arguments' do
expect(Gitlab::Popen).to receive(:popen_with_detail)
- .with([%(helm uninstall --namespace "#{namespace}" #{release_name})])
+ .with([%(helm uninstall #{release_name})])
.and_return(Gitlab::Popen::Result.new([], '', '', double(success?: true)))
expect(subject.delete(release_name: release_name)).to eq('')
@@ -117,16 +117,16 @@ RSpec.describe Tooling::Helm3Client do
it 'raises an error if the Helm command fails' do
expect(Gitlab::Popen).to receive(:popen_with_detail)
- .with([%(helm uninstall --namespace "#{namespace}" #{release_name.join(' ')})])
- .and_return(Gitlab::Popen::Result.new([], '', '', double(success?: false)))
+ .with([%(helm uninstall #{release_name.join(' ')})])
+ .and_return(Gitlab::Popen::Result.new([], '', '', double(success?: false)))
expect { subject.delete(release_name: release_name) }.to raise_error(described_class::CommandFailedError)
end
it 'calls helm uninstall with multiple release names' do
expect(Gitlab::Popen).to receive(:popen_with_detail)
- .with([%(helm uninstall --namespace "#{namespace}" #{release_name.join(' ')})])
- .and_return(Gitlab::Popen::Result.new([], '', '', double(success?: true)))
+ .with([%(helm uninstall #{release_name.join(' ')})])
+ .and_return(Gitlab::Popen::Result.new([], '', '', double(success?: true)))
expect(subject.delete(release_name: release_name)).to eq('')
end
diff --git a/spec/tooling/rspec_flaky/example_spec.rb b/spec/tooling/rspec_flaky/example_spec.rb
index 8ff280fd855..d001ed32444 100644
--- a/spec/tooling/rspec_flaky/example_spec.rb
+++ b/spec/tooling/rspec_flaky/example_spec.rb
@@ -9,7 +9,8 @@ RSpec.describe RspecFlaky::Example do
metadata: {
file_path: 'spec/foo/bar_spec.rb',
line_number: 2,
- full_description: 'hello world'
+ full_description: 'hello world',
+ feature_category: :feature_category
},
execution_result: double(status: 'passed', exception: 'BOOM!'),
attempts: 1
@@ -89,4 +90,10 @@ RSpec.describe RspecFlaky::Example do
expect(subject.exception).to eq(rspec_example.execution_result.exception)
end
end
+
+ describe '#feature_category' do
+ it 'returns the metadata[:feature_category] of the RSpec::Core::Example' do
+ expect(subject.feature_category).to eq(rspec_example.metadata[:feature_category])
+ end
+ end
end
diff --git a/spec/tooling/rspec_flaky/flaky_example_spec.rb b/spec/tooling/rspec_flaky/flaky_example_spec.rb
index 03436ee1cbd..511f3286f56 100644
--- a/spec/tooling/rspec_flaky/flaky_example_spec.rb
+++ b/spec/tooling/rspec_flaky/flaky_example_spec.rb
@@ -9,30 +9,14 @@ RSpec.describe RspecFlaky::FlakyExample, :aggregate_failures do
include ActiveSupport::Testing::TimeHelpers
include StubENV
- let(:flaky_example_attrs) do
+ let(:example_attrs) do
{
example_id: 'spec/foo/bar_spec.rb:2',
file: 'spec/foo/bar_spec.rb',
line: 2,
description: 'hello world',
- first_flaky_at: 1234,
- last_flaky_at: 2345,
- last_flaky_job: 'https://gitlab.com/gitlab-org/gitlab-foss/-/jobs/12',
last_attempts_count: 2,
- flaky_reports: 1
- }
- end
-
- let(:example_attrs) do
- {
- uid: 'abc123',
- example_id: flaky_example_attrs[:example_id],
- file: flaky_example_attrs[:file],
- line: flaky_example_attrs[:line],
- description: flaky_example_attrs[:description],
- status: 'passed',
- exception: 'BOOM!',
- attempts: flaky_example_attrs[:last_attempts_count]
+ feature_category: :feature_category
}
end
@@ -48,18 +32,19 @@ RSpec.describe RspecFlaky::FlakyExample, :aggregate_failures do
it 'returns valid attributes' do
attrs = flaky_example.to_h
- expect(attrs[:uid]).to eq(flaky_example_attrs[:uid])
- expect(attrs[:file]).to eq(flaky_example_attrs[:file])
- expect(attrs[:line]).to eq(flaky_example_attrs[:line])
- expect(attrs[:description]).to eq(flaky_example_attrs[:description])
+ expect(attrs[:uid]).to eq(example_attrs[:uid])
+ expect(attrs[:file]).to eq(example_attrs[:file])
+ expect(attrs[:line]).to eq(example_attrs[:line])
+ expect(attrs[:description]).to eq(example_attrs[:description])
+ expect(attrs[:feature_category]).to eq(example_attrs[:feature_category])
expect(attrs[:first_flaky_at]).to eq(expected_first_flaky_at)
expect(attrs[:last_flaky_at]).to eq(expected_last_flaky_at)
- expect(attrs[:last_attempts_count]).to eq(flaky_example_attrs[:last_attempts_count])
+ expect(attrs[:last_attempts_count]).to eq(example_attrs[:last_attempts_count])
expect(attrs[:flaky_reports]).to eq(expected_flaky_reports)
end
end
- context 'when given an Example hash' do
+ context 'when given an Example.to_h' do
it_behaves_like 'a valid FlakyExample instance' do
let(:args) { example_attrs }
let(:expected_first_flaky_at) { Time.now }
@@ -67,18 +52,9 @@ RSpec.describe RspecFlaky::FlakyExample, :aggregate_failures do
let(:expected_flaky_reports) { 0 }
end
end
-
- context 'when given a FlakyExample hash' do
- it_behaves_like 'a valid FlakyExample instance' do
- let(:args) { flaky_example_attrs }
- let(:expected_flaky_reports) { flaky_example_attrs[:flaky_reports] }
- let(:expected_first_flaky_at) { flaky_example_attrs[:first_flaky_at] }
- let(:expected_last_flaky_at) { flaky_example_attrs[:last_flaky_at] }
- end
- end
end
- describe '#update_flakiness!' do
+ describe '#update!' do
shared_examples 'an up-to-date FlakyExample instance' do
let(:flaky_example) { described_class.new(args) }
@@ -86,18 +62,18 @@ RSpec.describe RspecFlaky::FlakyExample, :aggregate_failures do
args[:first_flaky_at] = nil
freeze_time do
- flaky_example.update_flakiness!
+ flaky_example.update!(example_attrs)
expect(flaky_example.to_h[:first_flaky_at]).to eq(Time.now)
end
end
it 'maintains the first_flaky_at if exists' do
- flaky_example.update_flakiness!
+ flaky_example.update!(example_attrs)
expected_first_flaky_at = flaky_example.to_h[:first_flaky_at]
travel_to(Time.now + 42) do
- flaky_example.update_flakiness!
+ flaky_example.update!(example_attrs)
expect(flaky_example.to_h[:first_flaky_at]).to eq(expected_first_flaky_at)
end
end
@@ -105,7 +81,7 @@ RSpec.describe RspecFlaky::FlakyExample, :aggregate_failures do
it 'updates the last_flaky_at' do
travel_to(Time.now + 42) do
the_future = Time.now
- flaky_example.update_flakiness!
+ flaky_example.update!(example_attrs)
expect(flaky_example.to_h[:last_flaky_at]).to eq(the_future)
end
@@ -114,16 +90,15 @@ RSpec.describe RspecFlaky::FlakyExample, :aggregate_failures do
it 'updates the flaky_reports' do
expected_flaky_reports = flaky_example.to_h[:first_flaky_at] ? flaky_example.to_h[:flaky_reports] + 1 : 1
- expect { flaky_example.update_flakiness! }.to change { flaky_example.to_h[:flaky_reports] }.by(1)
+ expect { flaky_example.update!(example_attrs) }.to change { flaky_example.to_h[:flaky_reports] }.by(1)
expect(flaky_example.to_h[:flaky_reports]).to eq(expected_flaky_reports)
end
- context 'when passed a :last_attempts_count' do
- it 'updates the last_attempts_count' do
- flaky_example.update_flakiness!(last_attempts_count: 42)
+ it 'updates the last_attempts_count' do
+ example_attrs[:last_attempts_count] = 42
+ flaky_example.update!(example_attrs)
- expect(flaky_example.to_h[:last_attempts_count]).to eq(42)
- end
+ expect(flaky_example.to_h[:last_attempts_count]).to eq(42)
end
context 'when run on the CI' do
@@ -134,7 +109,7 @@ RSpec.describe RspecFlaky::FlakyExample, :aggregate_failures do
end
it 'updates the last_flaky_job' do
- flaky_example.update_flakiness!
+ flaky_example.update!(example_attrs)
expect(flaky_example.to_h[:last_flaky_job]).to eq(job_url)
end
@@ -146,12 +121,6 @@ RSpec.describe RspecFlaky::FlakyExample, :aggregate_failures do
let(:args) { example_attrs }
end
end
-
- context 'when given a FlakyExample hash' do
- it_behaves_like 'an up-to-date FlakyExample instance' do
- let(:args) { flaky_example_attrs }
- end
- end
end
describe '#to_h', :freeze_time do
@@ -160,7 +129,7 @@ RSpec.describe RspecFlaky::FlakyExample, :aggregate_failures do
it 'returns a valid hash' do
flaky_example = described_class.new(args)
- final_hash = flaky_example_attrs.merge(additional_attrs)
+ final_hash = example_attrs.merge(additional_attrs)
expect(flaky_example.to_h).to eq(final_hash)
end
@@ -175,11 +144,5 @@ RSpec.describe RspecFlaky::FlakyExample, :aggregate_failures do
end
end
end
-
- context 'when given a FlakyExample hash' do
- let(:args) { flaky_example_attrs }
-
- it_behaves_like 'a valid FlakyExample hash'
- end
end
end
diff --git a/spec/tooling/rspec_flaky/flaky_examples_collection_spec.rb b/spec/tooling/rspec_flaky/flaky_examples_collection_spec.rb
index e5f985c9596..9d75c97febe 100644
--- a/spec/tooling/rspec_flaky/flaky_examples_collection_spec.rb
+++ b/spec/tooling/rspec_flaky/flaky_examples_collection_spec.rb
@@ -20,6 +20,7 @@ RSpec.describe RspecFlaky::FlakyExamplesCollection, :aggregate_failures, :freeze
last_flaky_at: Time.now,
last_flaky_job: nil,
flaky_reports: 0,
+ feature_category: nil,
last_attempts_count: nil
},
b: {
@@ -28,6 +29,7 @@ RSpec.describe RspecFlaky::FlakyExamplesCollection, :aggregate_failures, :freeze
last_flaky_at: Time.now,
last_flaky_job: nil,
flaky_reports: 0,
+ feature_category: nil,
last_attempts_count: nil
}
}
@@ -69,6 +71,7 @@ RSpec.describe RspecFlaky::FlakyExamplesCollection, :aggregate_failures, :freeze
last_flaky_at: Time.now,
last_flaky_job: nil,
flaky_reports: 0,
+ feature_category: nil,
last_attempts_count: nil
})
end
diff --git a/spec/tooling/rspec_flaky/listener_spec.rb b/spec/tooling/rspec_flaky/listener_spec.rb
index 62bbe53cac1..0bbd6454969 100644
--- a/spec/tooling/rspec_flaky/listener_spec.rb
+++ b/spec/tooling/rspec_flaky/listener_spec.rb
@@ -128,6 +128,7 @@ RSpec.describe RspecFlaky::Listener, :aggregate_failures do
first_flaky_at: 1234,
last_attempts_count: 2,
flaky_reports: 2,
+ feature_category: nil,
last_flaky_job: nil
}
end
@@ -154,6 +155,7 @@ RSpec.describe RspecFlaky::Listener, :aggregate_failures do
description: 'hello GitLab',
last_attempts_count: 2,
flaky_reports: 1,
+ feature_category: nil,
last_flaky_job: nil
}
end
diff --git a/spec/tooling/rspec_flaky/report_spec.rb b/spec/tooling/rspec_flaky/report_spec.rb
index ffd0cd987aa..e7365c1e150 100644
--- a/spec/tooling/rspec_flaky/report_spec.rb
+++ b/spec/tooling/rspec_flaky/report_spec.rb
@@ -26,6 +26,7 @@ RSpec.describe RspecFlaky::Report, :aggregate_failures, :freeze_time do
last_flaky_at: 4321,
last_attempts_count: 3,
flaky_reports: 1,
+ feature_category: 'feature_category',
last_flaky_job: nil
}
}
diff --git a/spec/uploaders/job_artifact_uploader_spec.rb b/spec/uploaders/job_artifact_uploader_spec.rb
index a7fd040837f..d7c9ef7e0d5 100644
--- a/spec/uploaders/job_artifact_uploader_spec.rb
+++ b/spec/uploaders/job_artifact_uploader_spec.rb
@@ -26,7 +26,7 @@ RSpec.describe JobArtifactUploader do
describe '#cdn_enabled_url' do
it 'returns URL and false' do
- result = uploader.cdn_enabled_url(nil, '127.0.0.1')
+ result = uploader.cdn_enabled_url('127.0.0.1')
expect(result.used_cdn).to be false
end
diff --git a/spec/uploaders/object_storage/cdn/google_cdn_spec.rb b/spec/uploaders/object_storage/cdn/google_cdn_spec.rb
index 8e209dabddc..96755b7292b 100644
--- a/spec/uploaders/object_storage/cdn/google_cdn_spec.rb
+++ b/spec/uploaders/object_storage/cdn/google_cdn_spec.rb
@@ -92,26 +92,52 @@ RSpec.describe ObjectStorage::CDN::GoogleCDN,
end
end
- describe '#signed_url' do
+ describe '#signed_url', :freeze_time do
let(:path) { '/path/to/file.txt' }
+ let(:expiration) { (Time.current + 10.minutes).utc.to_i }
+ let(:cdn_query_params) { "Expires=#{expiration}&KeyName=#{key_name}" }
- it 'returns a valid signed URL' do
- url = subject.signed_url(path)
-
+ def verify_signature(url, unsigned_url)
expect(url).to start_with("#{options[:url]}#{path}")
uri = Addressable::URI.parse(url)
- parsed_query = Rack::Utils.parse_nested_query(uri.query)
- signature = parsed_query.delete('Signature')
+ query = uri.query_values
+ signature = query['Signature']
- signed_url = "#{options[:url]}#{path}?Expires=#{parsed_query['Expires']}&KeyName=#{key_name}"
- computed_signature = OpenSSL::HMAC.digest('SHA1', key, signed_url)
+ computed_signature = OpenSSL::HMAC.digest('SHA1', key, unsigned_url)
aggregate_failures do
- expect(parsed_query['Expires'].to_i).to be > 0
- expect(parsed_query['KeyName']).to eq(key_name)
+ expect(query['Expires'].to_i).to be > 0
+ expect(query['KeyName']).to eq(key_name)
expect(signature).to eq(Base64.urlsafe_encode64(computed_signature))
end
end
+
+ context 'with default query parameters' do
+ let(:url) { subject.signed_url(path) }
+ let(:unsigned_url) { "#{options[:url]}#{path}?#{cdn_query_params}" }
+
+ it 'returns a valid signed URL' do
+ verify_signature(url, unsigned_url)
+ end
+ end
+
+ context 'with nil query parameters' do
+ let(:url) { subject.signed_url(path, params: nil) }
+ let(:unsigned_url) { "#{options[:url]}#{path}?#{cdn_query_params}" }
+
+ it 'returns a valid signed URL' do
+ verify_signature(url, unsigned_url)
+ end
+ end
+
+ context 'with extra query parameters' do
+ let(:url) { subject.signed_url(path, params: { 'response-content-type' => 'text/plain' }) }
+ let(:unsigned_url) { "#{options[:url]}#{path}?response-content-type=text%2Fplain&#{cdn_query_params}" }
+
+ it 'returns a valid signed URL' do
+ verify_signature(url, unsigned_url)
+ end
+ end
end
end
diff --git a/spec/uploaders/object_storage/cdn_spec.rb b/spec/uploaders/object_storage/cdn_spec.rb
index f99450b274f..2a447921a19 100644
--- a/spec/uploaders/object_storage/cdn_spec.rb
+++ b/spec/uploaders/object_storage/cdn_spec.rb
@@ -44,30 +44,13 @@ RSpec.describe ObjectStorage::CDN do
end
describe '#cdn_enabled_url' do
- context 'with ci_job_artifacts_cdn feature flag disabled' do
- before do
- stub_feature_flags(ci_job_artifacts_cdn: false)
- end
-
- it 'calls #url' do
- expect(subject).to receive(:url).and_call_original
- expect(subject).not_to receive(:cdn_signed_url)
-
- result = subject.cdn_enabled_url(project, public_ip)
-
- expect(result.used_cdn).to be false
- end
- end
+ it 'calls #cdn_signed_url' do
+ expect(subject).not_to receive(:url)
+ expect(subject).to receive(:cdn_signed_url).and_call_original
- context 'with ci_job_artifacts_cdn feature flag enabled' do
- it 'calls #cdn_signed_url' do
- expect(subject).not_to receive(:url)
- expect(subject).to receive(:cdn_signed_url).and_call_original
+ result = subject.cdn_enabled_url(public_ip)
- result = subject.cdn_enabled_url(project, public_ip)
-
- expect(result.used_cdn).to be true
- end
+ expect(result.used_cdn).to be true
end
end
diff --git a/spec/validators/branch_filter_validator_spec.rb b/spec/validators/branch_filter_validator_spec.rb
deleted file mode 100644
index 2d869fa674d..00000000000
--- a/spec/validators/branch_filter_validator_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe BranchFilterValidator do
- let(:validator) { described_class.new(attributes: [:push_events_branch_filter]) }
- let(:hook) { build(:project_hook) }
-
- describe '#validates_each' do
- it 'allows valid branch names' do
- validator.validate_each(hook, :push_events_branch_filter, +"good_branch_name")
- validator.validate_each(hook, :push_events_branch_filter, +"another/good_branch_name")
- expect(hook.errors.empty?).to be true
- end
-
- it 'disallows bad branch names' do
- validator.validate_each(hook, :push_events_branch_filter, +"bad branch~name")
- expect(hook.errors[:push_events_branch_filter].empty?).to be false
- end
-
- it 'allows wildcards' do
- validator.validate_each(hook, :push_events_branch_filter, +"features/*")
- validator.validate_each(hook, :push_events_branch_filter, +"features/*/bla")
- validator.validate_each(hook, :push_events_branch_filter, +"*-stable")
- expect(hook.errors.empty?).to be true
- end
-
- it 'gets rid of whitespace' do
- filter = +' master '
- validator.validate_each(hook, :push_events_branch_filter, filter)
-
- expect(filter).to eq 'master'
- end
-
- # Branch names can be quite long but in practice aren't over 255 so 4000 should
- # be enough space for a list of branch names but we can increase if needed.
- it 'limits length to 4000 chars' do
- filter = 'a' * 4001
- validator.validate_each(hook, :push_events_branch_filter, filter)
-
- expect(hook.errors[:push_events_branch_filter].empty?).to be false
- end
- end
-end
diff --git a/spec/validators/web_hooks/wildcard_branch_filter_validator_spec.rb b/spec/validators/web_hooks/wildcard_branch_filter_validator_spec.rb
new file mode 100644
index 00000000000..7f29e1df007
--- /dev/null
+++ b/spec/validators/web_hooks/wildcard_branch_filter_validator_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe WebHooks::WildcardBranchFilterValidator do
+ let(:validator) { described_class.new(attributes: [:push_events_branch_filter]) }
+ let(:hook) { build(:project_hook) }
+
+ describe '#validates_each' do
+ it 'allows valid branch names' do
+ validator.validate_each(hook, :push_events_branch_filter, +"good_branch_name")
+ validator.validate_each(hook, :push_events_branch_filter, +"another/good_branch_name")
+ expect(hook.errors.empty?).to be true
+ end
+
+ it 'disallows bad branch names' do
+ validator.validate_each(hook, :push_events_branch_filter, +"bad branch~name")
+ expect(hook.errors[:push_events_branch_filter].empty?).to be false
+ end
+
+ it 'allows wildcards' do
+ validator.validate_each(hook, :push_events_branch_filter, +"features/*")
+ validator.validate_each(hook, :push_events_branch_filter, +"features/*/bla")
+ validator.validate_each(hook, :push_events_branch_filter, +"*-stable")
+ expect(hook.errors.empty?).to be true
+ end
+
+ it 'gets rid of whitespace' do
+ filter = +' master '
+ validator.validate_each(hook, :push_events_branch_filter, filter)
+
+ expect(filter).to eq 'master'
+ end
+
+ # Branch names can be quite long but in practice aren't over 255 so 4000 should
+ # be enough space for a list of branch names but we can increase if needed.
+ it 'limits length to 4000 chars' do
+ filter = 'a' * 4001
+ validator.validate_each(hook, :push_events_branch_filter, filter)
+
+ expect(hook.errors[:push_events_branch_filter].empty?).to be false
+ end
+ end
+end
diff --git a/spec/views/admin/application_settings/_jira_connect.html.haml_spec.rb b/spec/views/admin/application_settings/_jira_connect.html.haml_spec.rb
new file mode 100644
index 00000000000..7cfc2db5a41
--- /dev/null
+++ b/spec/views/admin/application_settings/_jira_connect.html.haml_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'admin/application_settings/_jira_connect.html.haml' do
+ let_it_be(:admin) { create(:admin) }
+ let(:application_setting) { build(:application_setting) }
+
+ before do
+ assign(:application_setting, application_setting)
+ allow(view).to receive(:expanded).and_return(true)
+ end
+
+ it 'renders the application ID field' do
+ render
+ expect(rendered).to have_field('Jira Connect Application ID', type: 'text')
+ end
+
+ it 'renders the asymmetric jwt cdn url field' do
+ render
+ expect(rendered).to have_field('Jira Connect Proxy URL', type: 'text')
+ end
+end
diff --git a/spec/views/admin/application_settings/general.html.haml_spec.rb b/spec/views/admin/application_settings/general.html.haml_spec.rb
index c7d156cde39..a8c7bec36e3 100644
--- a/spec/views/admin/application_settings/general.html.haml_spec.rb
+++ b/spec/views/admin/application_settings/general.html.haml_spec.rb
@@ -69,19 +69,19 @@ RSpec.describe 'admin/application_settings/general.html.haml' do
end
end
- describe 'jira connect application key' do
- it 'shows the jira connect application key section' do
+ describe 'jira connect settings' do
+ it 'shows the jira connect settings section' do
render
expect(rendered).to have_css('#js-jira_connect-settings')
end
- context 'when the jira_connect_oauth feature flag is disabled' do
+ context 'when the jira_connect_oauth_self_managed_setting feature flag is disabled' do
before do
- stub_feature_flags(jira_connect_oauth: false)
+ stub_feature_flags(jira_connect_oauth_self_managed_setting: false)
end
- it 'does not show the jira connect application key section' do
+ it 'does not show the jira connect settings section' do
render
expect(rendered).not_to have_css('#js-jira_connect-settings')
diff --git a/spec/views/admin/dashboard/index.html.haml_spec.rb b/spec/views/admin/dashboard/index.html.haml_spec.rb
index 9f1ff960444..6e06af92232 100644
--- a/spec/views/admin/dashboard/index.html.haml_spec.rb
+++ b/spec/views/admin/dashboard/index.html.haml_spec.rb
@@ -60,7 +60,7 @@ RSpec.describe 'admin/dashboard/index.html.haml' do
end
it 'renders the version check badge' do
- expect(rendered).to have_selector('.js-gitlab-version-check')
+ expect(rendered).to have_selector('.js-gitlab-version-check-badge')
end
end
diff --git a/spec/views/devise/confirmations/almost_there.html.haml_spec.rb b/spec/views/devise/confirmations/almost_there.html.haml_spec.rb
new file mode 100644
index 00000000000..c091efe9295
--- /dev/null
+++ b/spec/views/devise/confirmations/almost_there.html.haml_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'devise/confirmations/almost_there' do
+ describe 'confirmations text' do
+ subject { render(template: 'devise/confirmations/almost_there') }
+
+ before do
+ allow(view).to receive(:params).and_return(email: email)
+ end
+
+ context 'when correct email' do
+ let(:email) { 'ã“ã‚“ã«ã¡ã¯@test' }
+
+ specify do
+ subject
+
+ expect(rendered).to have_content(
+ "Please check your email (#{email}) to confirm your account"
+ )
+ end
+ end
+
+ context 'when random text' do
+ let(:email) { 'random text' }
+
+ specify do
+ subject
+
+ expect(rendered).to have_content(
+ 'Please check your email to confirm your account'
+ )
+ end
+ end
+ end
+end
diff --git a/spec/views/events/event/_common.html.haml_spec.rb b/spec/views/events/event/_common.html.haml_spec.rb
index ad8e5c2ef77..2160245fb63 100644
--- a/spec/views/events/event/_common.html.haml_spec.rb
+++ b/spec/views/events/event/_common.html.haml_spec.rb
@@ -18,9 +18,22 @@ RSpec.describe 'events/event/_common.html.haml' do
create(:event, :created, project: project, target: work_item, target_type: 'WorkItem', author: user)
end
- it 'renders the correct url' 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)
+ 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.id}"
+ work_item.reference_link_text, href: "/#{project.full_path}/-/work_items/#{work_item.iid}?iid_path=true"
)
end
diff --git a/spec/views/groups/observability.html.haml_spec.rb b/spec/views/groups/observability.html.haml_spec.rb
deleted file mode 100644
index db280d5a2ba..00000000000
--- a/spec/views/groups/observability.html.haml_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'groups/observability/index' do
- let_it_be(:iframe_url) { "foo.test" }
-
- before do
- assign(:observability_iframe_src, iframe_url)
- end
-
- it 'renders as expected' do
- render
- page = Capybara.string(rendered)
- iframe = page.find('iframe#observability-ui-iframe')
- expect(iframe['src']).to eq(iframe_url)
- end
-end
diff --git a/spec/views/groups/observability/observability.html.haml_spec.rb b/spec/views/groups/observability/observability.html.haml_spec.rb
new file mode 100644
index 00000000000..0561737cb39
--- /dev/null
+++ b/spec/views/groups/observability/observability.html.haml_spec.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'groups/observability/observability.html.haml' do
+ let(:iframe_url) { "foo.test" }
+
+ before do
+ allow(view).to receive(:observability_iframe_src).and_return(iframe_url)
+ end
+
+ it 'renders as expected' do
+ render
+ page = Capybara.string(rendered)
+ div = page.find('#js-observability-app')
+ expect(div['data-observability-iframe-src']).to eq(iframe_url)
+ end
+end
diff --git a/spec/views/layouts/header/_gitlab_version.html.haml_spec.rb b/spec/views/layouts/header/_gitlab_version.html.haml_spec.rb
index 2f423c72ca6..4f1dcf54216 100644
--- a/spec/views/layouts/header/_gitlab_version.html.haml_spec.rb
+++ b/spec/views/layouts/header/_gitlab_version.html.haml_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe 'layouts/header/_gitlab_version' do
end
it 'renders the version check badge' do
- expect(rendered).to have_selector('.js-gitlab-version-check')
+ expect(rendered).to have_selector('.js-gitlab-version-check-badge')
end
it 'renders the container as a link' do
@@ -18,5 +18,20 @@ RSpec.describe 'layouts/header/_gitlab_version' do
'a[data-testid="gitlab-version-container"][href="/help/update/index"]'
)
end
+
+ it 'renders the container with correct data-tracking attributes' do
+ expect(rendered).to have_selector(
+ 'a[data-testid="gitlab-version-container"][data-track-action="click_link"]'
+ )
+
+ expect(rendered).to have_selector(
+ 'a[data-testid="gitlab-version-container"][data-track-label="version_help_dropdown"]'
+ )
+
+ expect(rendered).to have_selector(
+ 'a[data-testid="gitlab-version-container"]' \
+ "[data-track-property=\"#{Gitlab.version_info.major}.#{Gitlab.version_info.minor}\"]"
+ )
+ end
end
end
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 e7d9a8a4708..d0d220fed66 100644
--- a/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
+++ b/spec/views/layouts/nav/sidebar/_project.html.haml_spec.rb
@@ -472,24 +472,6 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
end
end
end
-
- describe 'Product Analytics' do
- it 'has a link to the product analytics page' do
- render
-
- expect(rendered).to have_link('Product Analytics', href: project_product_analytics_path(project))
- end
-
- describe 'when feature flag :product_analytics is disabled' do
- it 'does not have a link to the feature flags page' do
- stub_feature_flags(product_analytics: false)
-
- render
-
- expect(rendered).not_to have_link('Product Analytics')
- end
- end
- end
end
describe 'Infrastructure' do
diff --git a/spec/views/projects/artifacts/_artifact.html.haml_spec.rb b/spec/views/projects/artifacts/_artifact.html.haml_spec.rb
deleted file mode 100644
index 5d930d6b0f2..00000000000
--- a/spec/views/projects/artifacts/_artifact.html.haml_spec.rb
+++ /dev/null
@@ -1,85 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe "projects/artifacts/_artifact.html.haml" do
- let(:project) { create(:project) }
-
- describe 'delete button' do
- before do
- create(:ci_build, :artifacts, project: project)
-
- allow(view).to receive(:current_user).and_return(user)
- assign(:project, project)
- end
-
- context 'with admin' do
- let(:user) { build(:admin) }
-
- context 'when admin mode is enabled', :enable_admin_mode do
- it 'has a delete button' do
- render_partial
-
- expect(rendered).to have_link('Delete artifacts', href: project_artifact_path(project, project.job_artifacts.first))
- end
- end
-
- context 'when admin mode is disabled' do
- it 'has no delete button' do
- project.add_reporter(user)
- render_partial
-
- expect(rendered).not_to have_link('Delete artifacts')
- end
- end
- end
-
- context 'with owner' do
- let(:user) { create(:user) }
- let(:project) { build(:project, namespace: user.namespace) }
-
- it 'has a delete button' do
- render_partial
-
- expect(rendered).to have_link('Delete artifacts', href: project_artifact_path(project, project.job_artifacts.first))
- end
- end
-
- context 'with master' do
- let(:user) { create(:user) }
-
- it 'has a delete button' do
- allow_any_instance_of(ProjectTeam).to receive(:max_member_access).and_return(Gitlab::Access::MAINTAINER)
- render_partial
-
- expect(rendered).to have_link('Delete artifacts', href: project_artifact_path(project, project.job_artifacts.first))
- end
- end
-
- context 'with developer' do
- let(:user) { build(:user) }
-
- it 'has no delete button' do
- project.add_developer(user)
- render_partial
-
- expect(rendered).not_to have_link('Delete artifacts')
- end
- end
-
- context 'with reporter' do
- let(:user) { build(:user) }
-
- it 'has no delete button' do
- project.add_reporter(user)
- render_partial
-
- expect(rendered).not_to have_link('Delete artifacts')
- end
- end
- end
-
- def render_partial
- render partial: 'projects/artifacts/artifact', collection: project.job_artifacts, as: :artifact
- end
-end
diff --git a/spec/views/projects/commit/_commit_box.html.haml_spec.rb b/spec/views/projects/commit/_commit_box.html.haml_spec.rb
index c503e085d02..4335a0901ae 100644
--- a/spec/views/projects/commit/_commit_box.html.haml_spec.rb
+++ b/spec/views/projects/commit/_commit_box.html.haml_spec.rb
@@ -17,7 +17,7 @@ RSpec.describe 'projects/commit/_commit_box.html.haml' do
it 'shows the commit SHA' do
render
- expect(rendered).to have_text("#{Commit.truncate_sha(project.commit.sha)}")
+ expect(rendered).to have_text(Commit.truncate_sha(project.commit.sha).to_s)
end
context 'when there is a pipeline present' do
diff --git a/spec/views/projects/commit/show.html.haml_spec.rb b/spec/views/projects/commit/show.html.haml_spec.rb
index 59182f6e757..4d5c987ce37 100644
--- a/spec/views/projects/commit/show.html.haml_spec.rb
+++ b/spec/views/projects/commit/show.html.haml_spec.rb
@@ -67,5 +67,13 @@ RSpec.describe 'projects/commit/show.html.haml' do
expect(rendered).to have_content("This commit is part of merge request")
expect(rendered).to have_link(merge_request.to_reference, href: merge_request_url)
end
+
+ context 'when merge request is nil' do
+ let(:merge_request) { nil }
+
+ it 'renders the page' do
+ expect { rendered }.not_to raise_error
+ end
+ end
end
end
diff --git a/spec/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml_spec.rb b/spec/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml_spec.rb
index 416f4253e1b..99339e956cc 100644
--- a/spec/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml_spec.rb
+++ b/spec/views/projects/merge_requests/_close_reopen_draft_report_toggle.html.haml_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe 'projects/merge_requests/_close_reopen_draft_report_toggle.html.h
render
- expect(rendered).to have_css('li', class: 'js-sidebar-subscriptions-entry-point')
+ expect(rendered).to have_css('li', class: 'js-sidebar-subscriptions-widget-root')
end
end
@@ -27,7 +27,7 @@ RSpec.describe 'projects/merge_requests/_close_reopen_draft_report_toggle.html.h
it 'is not present' do
render
- expect(rendered).not_to have_css('li', class: 'js-sidebar-subscriptions-entry-point')
+ expect(rendered).not_to have_css('li', class: 'js-sidebar-subscriptions-widget-root')
end
end
end
diff --git a/spec/views/projects/merge_requests/_commits.html.haml_spec.rb b/spec/views/projects/merge_requests/_commits.html.haml_spec.rb
index f0273c1716f..90ee6638142 100644
--- a/spec/views/projects/merge_requests/_commits.html.haml_spec.rb
+++ b/spec/views/projects/merge_requests/_commits.html.haml_spec.rb
@@ -39,16 +39,4 @@ RSpec.describe 'projects/merge_requests/_commits.html.haml', :sidekiq_might_not_
expect(rendered).to have_css('.gpg-status-box')
end
-
- context 'when there are hidden commits' do
- before do
- assign(:hidden_commit_count, 1)
- end
-
- it 'shows notice about omitted commits' do
- render
-
- expect(rendered).to match(/1 additional commit has been omitted to prevent performance issues/)
- end
- end
end
diff --git a/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb b/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb
index 038a94fe7c3..feb82e6a2b2 100644
--- a/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb
+++ b/spec/views/projects/merge_requests/creations/_new_submit.html.haml_spec.rb
@@ -35,17 +35,4 @@ RSpec.describe 'projects/merge_requests/creations/_new_submit.html.haml' do
expect(rendered).not_to have_text('Builds')
end
end
-
- context 'when there are hidden commits' do
- before do
- assign(:pipelines, Ci::Pipeline.none)
- assign(:hidden_commit_count, 2)
- end
-
- it 'shows notice about omitted commits' do
- render
-
- expect(rendered).to match(/2 additional commits have been omitted to prevent performance issues/)
- end
- end
end
diff --git a/spec/views/projects/merge_requests/edit.html.haml_spec.rb b/spec/views/projects/merge_requests/edit.html.haml_spec.rb
index 215d404e395..75956160c0a 100644
--- a/spec/views/projects/merge_requests/edit.html.haml_spec.rb
+++ b/spec/views/projects/merge_requests/edit.html.haml_spec.rb
@@ -45,7 +45,7 @@ RSpec.describe 'projects/merge_requests/edit.html.haml' do
expect(rendered).to have_field('merge_request[title]')
expect(rendered).to have_field('merge_request[description]')
expect(rendered).to have_selector('input[name="merge_request[label_ids][]"]', visible: false)
- expect(rendered).to have_selector('#merge_request_milestone_id', visible: false)
+ expect(rendered).to have_selector('.js-milestone-dropdown-root')
expect(rendered).not_to have_selector('#merge_request_target_branch', visible: false)
end
end
@@ -57,7 +57,7 @@ RSpec.describe 'projects/merge_requests/edit.html.haml' do
expect(rendered).to have_field('merge_request[title]')
expect(rendered).to have_field('merge_request[description]')
expect(rendered).to have_selector('input[name="merge_request[label_ids][]"]', visible: false)
- expect(rendered).to have_selector('#merge_request_milestone_id', visible: false)
+ expect(rendered).to have_selector('.js-milestone-dropdown-root')
expect(rendered).to have_selector('#merge_request_target_branch', visible: false)
end
end
diff --git a/spec/views/search/show.html.haml_spec.rb b/spec/views/search/show.html.haml_spec.rb
index 565dadd64fe..5f9c6c65a08 100644
--- a/spec/views/search/show.html.haml_spec.rb
+++ b/spec/views/search/show.html.haml_spec.rb
@@ -11,10 +11,10 @@ RSpec.describe 'search/show' do
stub_template "search/_results.html.haml" => 'Results Partial'
end
- context 'feature flag enabled' do
+ context 'search_page_vertical_nav feature flag enabled' do
before do
- allow(self).to receive(:current_user).and_return(user)
- @search_term = search_term
+ allow(view).to receive(:current_user) { user }
+ assign(:search_term, search_term)
render
end
@@ -29,11 +29,11 @@ RSpec.describe 'search/show' do
end
end
- context 'feature flag disabled' do
+ context 'search_page_vertical_nav feature flag disabled' do
before do
stub_feature_flags(search_page_vertical_nav: false)
- @search_term = search_term
+ assign(:search_term, search_term)
render
end
diff --git a/spec/views/shared/access_tokens/_table.html.haml_spec.rb b/spec/views/shared/access_tokens/_table.html.haml_spec.rb
deleted file mode 100644
index 74de9e12d04..00000000000
--- a/spec/views/shared/access_tokens/_table.html.haml_spec.rb
+++ /dev/null
@@ -1,151 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'shared/access_tokens/_table.html.haml' do
- let(:type) { 'token' }
- let(:type_plural) { 'tokens' }
- let(:empty_message) { nil }
- let(:impersonation) { false }
-
- let_it_be(:user) { create(:user) }
- let_it_be(:tokens) { [create(:personal_access_token, user: user)] }
- let_it_be(:resource) { false }
-
- before do
- if resource
- resource.add_maintainer(user)
- end
-
- # Forcibly removing scopes from one token as it's not possible to do with the current modal on creation
- # But the check exists in the template (it may be there for legacy reasons), so we should test the outcome
- if tokens.size > 1
- tokens[1].scopes = []
- end
-
- locals = {
- type: type,
- type_plural: type_plural,
- active_tokens: tokens,
- resource: resource,
- impersonation: impersonation,
- revoke_route_helper: ->(token) { 'path/' }
- }
-
- if empty_message
- locals[:no_active_tokens_message] = empty_message
- end
-
- render partial: 'shared/access_tokens/table', locals: locals
- end
-
- context 'if personal' do
- it 'does not show non-personal content', :aggregate_failures do
- expect(rendered).not_to have_content 'To see all the user\'s personal access tokens you must impersonate them first.'
- expect(rendered).not_to have_selector 'th', text: 'Role'
- end
- end
-
- context 'if impersonation' do
- let(:impersonation) { true }
-
- it 'shows the impersonation content', :aggregate_failures do
- expect(rendered).to have_content 'To see all the user\'s personal access tokens you must impersonate them first.'
-
- expect(rendered).not_to have_content 'Personal access tokens are not revoked upon expiration.'
- expect(rendered).not_to have_selector 'th', text: 'Role'
- end
- end
-
- context 'if resource is project' do
- let_it_be(:resource) { create(:project) }
-
- it 'shows the project content', :aggregate_failures do
- expect(rendered).to have_selector 'th', text: 'Role'
- expect(rendered).to have_selector 'td', text: 'Maintainer'
-
- expect(rendered).not_to have_content 'Personal access tokens are not revoked upon expiration.'
- expect(rendered).not_to have_content 'To see all the user\'s personal access tokens you must impersonate them first.'
- end
- end
-
- context 'if resource is group' do
- let_it_be(:resource) { create(:group) }
-
- it 'shows the group content', :aggregate_failures do
- expect(rendered).to have_selector 'th', text: 'Role'
- expect(rendered).to have_selector 'td', text: 'Maintainer'
-
- expect(rendered).not_to have_content 'Personal access tokens are not revoked upon expiration.'
- expect(rendered).not_to have_content 'To see all the user\'s personal access tokens you must impersonate them first.'
- end
- end
-
- context 'without tokens' do
- let_it_be(:tokens) { [] }
-
- it 'has the correct content', :aggregate_failures do
- expect(rendered).to have_content 'Active tokens (0)'
- expect(rendered).to have_content 'This user has no active tokens.'
- end
-
- context 'with a custom empty text' do
- let(:empty_message) { 'Custom empty message' }
-
- it 'shows the custom empty text' do
- expect(rendered).to have_content empty_message
- end
- end
- end
-
- context 'with tokens' do
- let_it_be(:tokens) do
- [
- create(:personal_access_token, user: user, name: 'Access token', last_used_at: 4.days.from_now, expires_at: nil, scopes: [:read_api, :read_user]),
- create(:personal_access_token, user: user, expires_at: 1.day.from_now, scopes: [:read_api, :read_user])
- ]
- end
-
- let_it_be(:expired_token) { build(:personal_access_token, name: "Expired token", expires_at: 2.days.ago).tap { |t| t.save!(validate: false) } }
-
- it 'has the correct content', :aggregate_failures do
- # Heading content
- expect(rendered).to have_content 'Active tokens (2)'
-
- # Table headers
- expect(rendered).to have_selector 'th', text: 'Token name'
- expect(rendered).to have_selector 'th', text: 'Scopes'
- expect(rendered).to have_selector 'th', text: 'Created'
- expect(rendered).to have_selector 'th', text: 'Last Used'
- expect(rendered).to have_selector 'th', text: 'Expires'
-
- # Table contents
- expect(rendered).to have_content 'Access token'
- expect(rendered).not_to have_content 'Expired token'
- expect(rendered).to have_content 'read_api, read_user'
- expect(rendered).to have_content 'no scopes selected'
- expect(rendered).to have_content Time.now.to_date.to_s(:medium)
- expect(rendered).to have_content l(4.days.from_now, format: "%b %d, %Y")
-
- # Revoke buttons
- expect(rendered).to have_link 'Revoke', href: 'path/', class: 'btn-danger-secondary', count: 1
- expect(rendered).to have_link 'Revoke', href: 'path/', count: 2
- end
-
- context 'without the last used time' do
- let_it_be(:tokens) { [create(:personal_access_token, user: user, expires_at: 5.days.ago)] }
-
- it 'shows the last used empty text' do
- expect(rendered).to have_content 'Never'
- end
- end
-
- context 'without expired at' do
- let_it_be(:tokens) { [create(:personal_access_token, user: user, expires_at: nil, last_used_at: 1.day.ago)] }
-
- it 'shows the expired at empty text' do
- expect(rendered).to have_content 'Never'
- end
- end
- end
-end
diff --git a/spec/views/shared/deploy_tokens/_form.html.haml_spec.rb b/spec/views/shared/deploy_tokens/_form.html.haml_spec.rb
deleted file mode 100644
index 74ad0ccb77a..00000000000
--- a/spec/views/shared/deploy_tokens/_form.html.haml_spec.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe 'shared/deploy_tokens/_form.html.haml' do
- using RSpec::Parameterized::TableSyntax
-
- let_it_be(:user) { create(:user) }
- let_it_be(:token) { build(:deploy_token) }
-
- RSpec.shared_examples "display deploy token settings" do |role, shows_package_registry_permissions|
- before do
- subject.add_member(user, role)
- allow(view).to receive(:current_user).and_return(user)
- stub_config(packages: { enabled: packages_enabled })
- end
-
- it "correctly renders the form" do
- render 'shared/deploy_tokens/form', token: token, group_or_project: subject
-
- if shows_package_registry_permissions
- expect(rendered).to have_content('Allows read-only access to the package registry.')
- else
- expect(rendered).not_to have_content('Allows read-only access to the package registry.')
- end
- end
- end
-
- context "when the subject is a project" do
- let_it_be(:subject, refind: true) { create(:project, :private) }
-
- where(:packages_enabled, :feature_enabled, :role, :shows_package_registry_permissions) do
- true | true | :maintainer | true
- false | true | :maintainer | false
- true | false | :maintainer | false
- false | false | :maintainer | false
- end
-
- with_them do
- before do
- subject.update!(packages_enabled: feature_enabled)
- end
-
- it_behaves_like 'display deploy token settings', params[:role], params[:shows_package_registry_permissions]
- end
- end
-
- context "when the subject is a group" do
- let_it_be(:subject, refind: true) { create(:group, :private) }
-
- where(:packages_enabled, :role, :shows_package_registry_permissions) do
- true | :owner | true
- false | :owner | false
- true | :maintainer | true
- false | :maintainer | false
- end
-
- with_them do
- it_behaves_like 'display deploy token settings', params[:role], params[:shows_package_registry_permissions]
- end
- end
-end
diff --git a/spec/views/shared/issuable/_sidebar.html.haml_spec.rb b/spec/views/shared/issuable/_sidebar.html.haml_spec.rb
index 43a723dbb2c..31f79c25073 100644
--- a/spec/views/shared/issuable/_sidebar.html.haml_spec.rb
+++ b/spec/views/shared/issuable/_sidebar.html.haml_spec.rb
@@ -43,7 +43,7 @@ RSpec.describe 'shared/issuable/_sidebar.html.haml' do
it 'is expected not to be shown' do
create(:contact, group: group)
- expect(rendered).not_to have_css('#js-issue-crm-contacts')
+ expect(rendered).not_to have_css('.js-sidebar-crm-contacts-root')
end
end
@@ -51,7 +51,7 @@ RSpec.describe 'shared/issuable/_sidebar.html.haml' do
it 'is expected not to be shown' do
group.add_developer(user)
- expect(rendered).not_to have_css('#js-issue-crm-contacts')
+ expect(rendered).not_to have_css('.js-sidebar-crm-contacts-root')
end
end
@@ -60,7 +60,7 @@ RSpec.describe 'shared/issuable/_sidebar.html.haml' do
create(:contact, group: group)
group.add_developer(user)
- expect(rendered).to have_css('#js-issue-crm-contacts')
+ expect(rendered).to have_css('.js-sidebar-crm-contacts-root')
end
end
end
diff --git a/spec/workers/bulk_imports/entity_worker_spec.rb b/spec/workers/bulk_imports/entity_worker_spec.rb
index 0fcdbccc304..e3f0ee65205 100644
--- a/spec/workers/bulk_imports/entity_worker_spec.rb
+++ b/spec/workers/bulk_imports/entity_worker_spec.rb
@@ -39,8 +39,11 @@ RSpec.describe BulkImports::EntityWorker do
hash_including(
'bulk_import_entity_id' => entity.id,
'bulk_import_id' => entity.bulk_import_id,
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path,
'current_stage' => nil,
'message' => 'Stage starting',
+ 'source_version' => entity.bulk_import.source_version_info.to_s,
'importer' => 'gitlab_migration'
)
)
@@ -71,7 +74,10 @@ RSpec.describe BulkImports::EntityWorker do
hash_including(
'bulk_import_entity_id' => entity.id,
'bulk_import_id' => entity.bulk_import_id,
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path,
'current_stage' => nil,
+ 'source_version' => entity.bulk_import.source_version_info.to_s,
'importer' => 'gitlab_migration'
)
)
@@ -82,9 +88,15 @@ RSpec.describe BulkImports::EntityWorker do
hash_including(
'bulk_import_entity_id' => entity.id,
'bulk_import_id' => entity.bulk_import_id,
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path,
'current_stage' => nil,
- 'message' => 'Error!',
- 'importer' => 'gitlab_migration'
+ 'message' => 'Entity failed',
+ 'exception.backtrace' => anything,
+ 'exception.class' => 'StandardError',
+ 'exception.message' => 'Error!',
+ 'importer' => 'gitlab_migration',
+ 'source_version' => entity.bulk_import.source_version_info.to_s
)
)
end
@@ -95,6 +107,9 @@ RSpec.describe BulkImports::EntityWorker do
exception,
bulk_import_entity_id: entity.id,
bulk_import_id: entity.bulk_import_id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
+ source_version: entity.bulk_import.source_version_info.to_s,
importer: 'gitlab_migration'
)
@@ -112,8 +127,11 @@ RSpec.describe BulkImports::EntityWorker do
hash_including(
'bulk_import_entity_id' => entity.id,
'bulk_import_id' => entity.bulk_import_id,
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path,
'current_stage' => 0,
'message' => 'Stage running',
+ 'source_version' => entity.bulk_import.source_version_info.to_s,
'importer' => 'gitlab_migration'
)
)
@@ -142,7 +160,10 @@ RSpec.describe BulkImports::EntityWorker do
hash_including(
'bulk_import_entity_id' => entity.id,
'bulk_import_id' => entity.bulk_import_id,
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path,
'current_stage' => 0,
+ 'source_version' => entity.bulk_import.source_version_info.to_s,
'importer' => 'gitlab_migration'
)
)
diff --git a/spec/workers/bulk_imports/export_request_worker_spec.rb b/spec/workers/bulk_imports/export_request_worker_spec.rb
index 597eed3a9b9..7eb8150fb2e 100644
--- a/spec/workers/bulk_imports/export_request_worker_spec.rb
+++ b/spec/workers/bulk_imports/export_request_worker_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe BulkImports::ExportRequestWorker do
end
shared_examples 'requests relations export for api resource' do
- include_examples 'an idempotent worker' do
+ it_behaves_like 'an idempotent worker' do
it 'requests relations export & schedules entity worker' do
expect_next_instance_of(BulkImports::Clients::HTTP) do |client|
expect(client).to receive(:post).with(expected).twice
@@ -44,18 +44,22 @@ RSpec.describe BulkImports::ExportRequestWorker do
it 'logs retry request and reenqueues' do
allow(exception).to receive(:retriable?).twice.and_return(true)
- expect(Gitlab::Import::Logger).to receive(:error).with(
- hash_including(
- 'bulk_import_entity_id' => entity.id,
- 'pipeline_class' => 'ExportRequestWorker',
- 'exception_class' => 'BulkImports::NetworkError',
- 'exception_message' => 'Export error',
- 'bulk_import_id' => bulk_import.id,
- 'bulk_import_entity_type' => entity.source_type,
- 'importer' => 'gitlab_migration',
- 'message' => 'Retrying export request'
- )
- ).twice
+ expect_next_instance_of(Gitlab::Import::Logger) do |logger|
+ expect(logger).to receive(:error).with(
+ a_hash_including(
+ 'bulk_import_entity_id' => entity.id,
+ 'bulk_import_id' => entity.bulk_import_id,
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path,
+ 'exception.backtrace' => anything,
+ 'exception.class' => 'BulkImports::NetworkError',
+ 'exception.message' => 'Export error',
+ 'message' => 'Retrying export request',
+ 'importer' => 'gitlab_migration',
+ 'source_version' => entity.bulk_import.source_version_info.to_s
+ )
+ ).twice
+ end
expect(described_class).to receive(:perform_in).twice.with(2.seconds, entity.id)
@@ -65,18 +69,24 @@ RSpec.describe BulkImports::ExportRequestWorker do
context 'when error is not retriable' do
it 'logs export failure and marks entity as failed' do
- expect(Gitlab::Import::Logger).to receive(:error).with(
- hash_including(
- 'bulk_import_entity_id' => entity.id,
- 'pipeline_class' => 'ExportRequestWorker',
- 'exception_class' => 'BulkImports::NetworkError',
- 'exception_message' => 'Export error',
- 'correlation_id_value' => anything,
- 'bulk_import_id' => bulk_import.id,
- 'bulk_import_entity_type' => entity.source_type,
- 'importer' => 'gitlab_migration'
- )
- ).twice
+ allow(exception).to receive(:retriable?).twice.and_return(false)
+
+ expect_next_instance_of(Gitlab::Import::Logger) do |logger|
+ expect(logger).to receive(:error).with(
+ a_hash_including(
+ 'bulk_import_entity_id' => entity.id,
+ 'bulk_import_id' => entity.bulk_import_id,
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path,
+ 'exception.backtrace' => anything,
+ 'exception.class' => 'BulkImports::NetworkError',
+ 'exception.message' => 'Export error',
+ 'message' => "Request to export #{entity.source_type} failed",
+ 'importer' => 'gitlab_migration',
+ 'source_version' => entity.bulk_import.source_version_info.to_s
+ )
+ ).twice
+ end
perform_multiple(job_args)
@@ -119,25 +129,30 @@ RSpec.describe BulkImports::ExportRequestWorker do
let(:entity_source_id) { 'invalid' }
it 'logs the error & requests relations export using full path url' do
+ allow(BulkImports::EntityWorker).to receive(:perform_async)
+
expect_next_instance_of(BulkImports::Clients::HTTP) do |client|
expect(client).to receive(:post).with(full_path_url).twice
end
entity.update!(source_xid: nil)
- expect(Gitlab::Import::Logger).to receive(:error).with(
- a_hash_including(
- 'message' => 'Failed to fetch source entity id',
- 'bulk_import_entity_id' => entity.id,
- 'pipeline_class' => 'ExportRequestWorker',
- 'exception_class' => 'NoMethodError',
- 'exception_message' => "undefined method `model_id' for nil:NilClass",
- 'correlation_id_value' => anything,
- 'bulk_import_id' => bulk_import.id,
- 'bulk_import_entity_type' => entity.source_type,
- 'importer' => 'gitlab_migration'
- )
- ).twice
+ expect_next_instance_of(Gitlab::Import::Logger) do |logger|
+ expect(logger).to receive(:error).with(
+ a_hash_including(
+ 'bulk_import_entity_id' => entity.id,
+ 'bulk_import_id' => entity.bulk_import_id,
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path,
+ 'exception.backtrace' => anything,
+ 'exception.class' => 'NoMethodError',
+ 'exception.message' => "undefined method `model_id' for nil:NilClass",
+ 'message' => 'Failed to fetch source entity id',
+ 'importer' => 'gitlab_migration',
+ 'source_version' => entity.bulk_import.source_version_info.to_s
+ )
+ ).twice
+ end
perform_multiple(job_args)
@@ -153,7 +168,7 @@ RSpec.describe BulkImports::ExportRequestWorker do
let(:expected) { "/groups/#{entity.source_xid}/export_relations" }
let(:full_path_url) { '/groups/foo%2Fbar/export_relations' }
- include_examples 'requests relations export for api resource'
+ it_behaves_like 'requests relations export for api resource'
end
context 'when entity is project' do
@@ -161,7 +176,7 @@ RSpec.describe BulkImports::ExportRequestWorker do
let(:expected) { "/projects/#{entity.source_xid}/export_relations" }
let(:full_path_url) { '/projects/foo%2Fbar/export_relations' }
- include_examples 'requests relations export for api resource'
+ it_behaves_like 'requests relations export for api resource'
end
end
end
diff --git a/spec/workers/bulk_imports/pipeline_worker_spec.rb b/spec/workers/bulk_imports/pipeline_worker_spec.rb
index ee65775f170..23fbc5688ec 100644
--- a/spec/workers/bulk_imports/pipeline_worker_spec.rb
+++ b/spec/workers/bulk_imports/pipeline_worker_spec.rb
@@ -37,9 +37,10 @@ RSpec.describe BulkImports::PipelineWorker do
.with(
hash_including(
'pipeline_name' => 'FakePipeline',
- 'bulk_import_entity_id' => entity.id,
'bulk_import_id' => entity.bulk_import_id,
- 'importer' => 'gitlab_migration'
+ 'bulk_import_entity_id' => entity.id,
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path
)
)
end
@@ -87,8 +88,10 @@ RSpec.describe BulkImports::PipelineWorker do
'pipeline_tracker_id' => pipeline_tracker.id,
'bulk_import_entity_id' => entity.id,
'bulk_import_id' => entity.bulk_import_id,
- 'message' => 'Unstarted pipeline not found',
- 'importer' => 'gitlab_migration'
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path,
+ 'source_version' => entity.bulk_import.source_version_info.to_s,
+ 'message' => 'Unstarted pipeline not found'
)
)
end
@@ -126,7 +129,13 @@ RSpec.describe BulkImports::PipelineWorker do
'pipeline_name' => 'FakePipeline',
'bulk_import_entity_id' => entity.id,
'bulk_import_id' => entity.bulk_import_id,
- 'message' => 'Error!',
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path,
+ 'class' => 'BulkImports::PipelineWorker',
+ 'exception.backtrace' => anything,
+ 'exception.message' => 'Error!',
+ 'message' => 'Pipeline failed',
+ 'source_version' => entity.bulk_import.source_version_info.to_s,
'importer' => 'gitlab_migration'
)
)
@@ -137,9 +146,12 @@ RSpec.describe BulkImports::PipelineWorker do
.with(
instance_of(StandardError),
bulk_import_entity_id: entity.id,
- bulk_import_id: entity.bulk_import_id,
+ bulk_import_id: entity.bulk_import.id,
+ bulk_import_entity_type: entity.source_type,
+ source_full_path: entity.source_full_path,
pipeline_name: pipeline_tracker.pipeline_name,
- importer: 'gitlab_migration'
+ importer: 'gitlab_migration',
+ source_version: entity.bulk_import.source_version_info.to_s
)
expect(BulkImports::EntityWorker)
@@ -188,8 +200,9 @@ RSpec.describe BulkImports::PipelineWorker do
'pipeline_name' => 'FakePipeline',
'bulk_import_entity_id' => entity.id,
'bulk_import_id' => entity.bulk_import_id,
- 'message' => 'Skipping pipeline due to failed entity',
- 'importer' => 'gitlab_migration'
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path,
+ 'message' => 'Skipping pipeline due to failed entity'
)
)
end
@@ -237,7 +250,8 @@ RSpec.describe BulkImports::PipelineWorker do
'pipeline_name' => 'FakePipeline',
'bulk_import_entity_id' => entity.id,
'bulk_import_id' => entity.bulk_import_id,
- 'importer' => 'gitlab_migration'
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path
)
)
end
@@ -361,9 +375,16 @@ RSpec.describe BulkImports::PipelineWorker do
hash_including(
'pipeline_name' => 'NdjsonPipeline',
'bulk_import_entity_id' => entity.id,
- 'message' => 'Pipeline timeout',
'bulk_import_id' => entity.bulk_import_id,
- 'importer' => 'gitlab_migration'
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path,
+ 'class' => 'BulkImports::PipelineWorker',
+ 'exception.backtrace' => anything,
+ 'exception.class' => 'BulkImports::Pipeline::ExpiredError',
+ 'exception.message' => 'Pipeline timeout',
+ 'importer' => 'gitlab_migration',
+ 'message' => 'Pipeline failed',
+ 'source_version' => entity.bulk_import.source_version_info.to_s
)
)
end
@@ -390,9 +411,14 @@ RSpec.describe BulkImports::PipelineWorker do
hash_including(
'pipeline_name' => 'NdjsonPipeline',
'bulk_import_entity_id' => entity.id,
- 'message' => 'Export from source instance failed: Error!',
'bulk_import_id' => entity.bulk_import_id,
- 'importer' => 'gitlab_migration'
+ 'bulk_import_entity_type' => entity.source_type,
+ 'source_full_path' => entity.source_full_path,
+ 'exception.backtrace' => anything,
+ 'exception.class' => 'BulkImports::Pipeline::FailedError',
+ 'exception.message' => 'Export from source instance failed: Error!',
+ 'importer' => 'gitlab_migration',
+ 'source_version' => entity.bulk_import.source_version_info.to_s
)
)
end
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 e18539cc6e3..0d4b8243050 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
@@ -8,7 +8,10 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportWorker do
let_it_be(:project) { create(:project, group: group) }
let_it_be(:user) { create(:user) }
- let_it_be(:pipeline) { create(:ci_pipeline, :with_test_reports, project: project, user: user) }
+ let_it_be(:pipeline) do
+ create(:ci_pipeline, :with_test_reports, :with_coverage_reports,
+ project: project, user: user)
+ end
subject(:perform) { described_class.new.perform(pipeline_id) }
@@ -25,17 +28,29 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportWorker do
it_behaves_like 'an idempotent worker' do
let(:job_args) { pipeline_id }
- let(:test_event_name) { 'i_testing_test_report_uploaded' }
+ let(:test_event_name_1) { 'i_testing_test_report_uploaded' }
+ let(:test_event_name_2) { 'i_testing_coverage_report_uploaded' }
let(:start_time) { 1.week.ago }
let(:end_time) { 1.week.from_now }
subject(:idempotent_perform) { perform_multiple(pipeline_id, exec_times: 2) }
- it 'does not try to increment again' do
+ it 'does not try to increment again for the test event' do
+ idempotent_perform
+
+ unique_pipeline_pass = Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(
+ event_names: test_event_name_1,
+ start_date: start_time,
+ end_date: end_time
+ )
+ expect(unique_pipeline_pass).to eq(1)
+ end
+
+ it 'does not try to increment again for the coverage event' do
idempotent_perform
unique_pipeline_pass = Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(
- event_names: test_event_name,
+ event_names: test_event_name_2,
start_date: start_time,
end_date: end_time
)
diff --git a/spec/workers/cluster_configure_istio_worker_spec.rb b/spec/workers/cluster_configure_istio_worker_spec.rb
deleted file mode 100644
index 5d949fde973..00000000000
--- a/spec/workers/cluster_configure_istio_worker_spec.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ClusterConfigureIstioWorker do
- describe '#perform' do
- shared_examples 'configure istio service' do
- it 'configures istio' do
- expect_any_instance_of(Clusters::Kubernetes::ConfigureIstioIngressService).to receive(:execute)
-
- described_class.new.perform(cluster.id)
- end
- end
-
- context 'when provider type is gcp' do
- let(:cluster) { create(:cluster, :project, :provided_by_gcp) }
-
- it_behaves_like 'configure istio service'
- end
-
- context 'when provider type is aws' do
- let(:cluster) { create(:cluster, :project, :provided_by_aws) }
-
- it_behaves_like 'configure istio service'
- end
-
- context 'when provider type is user' do
- let(:cluster) { create(:cluster, :project, :provided_by_user) }
-
- it_behaves_like 'configure istio service'
- end
-
- context 'when cluster does not exist' do
- it 'does not provision a cluster' do
- expect_any_instance_of(Clusters::Kubernetes::ConfigureIstioIngressService).not_to receive(:execute)
-
- described_class.new.perform(123)
- end
- end
- end
-end
diff --git a/spec/workers/cluster_update_app_worker_spec.rb b/spec/workers/cluster_update_app_worker_spec.rb
deleted file mode 100644
index 8f61ee17162..00000000000
--- a/spec/workers/cluster_update_app_worker_spec.rb
+++ /dev/null
@@ -1,112 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ClusterUpdateAppWorker do
- include ExclusiveLeaseHelpers
-
- let_it_be(:project) { create(:project) }
-
- let(:prometheus_update_service) { spy }
-
- subject { described_class.new }
-
- around do |example|
- freeze_time { example.run }
- end
-
- before do
- allow(::Clusters::Applications::PrometheusUpdateService).to receive(:new).and_return(prometheus_update_service)
- end
-
- describe '#perform' do
- context 'when the application last_update_started_at is higher than the time the job was scheduled in' do
- it 'does nothing' do
- application = create(:clusters_applications_prometheus, :updated, last_update_started_at: Time.current)
-
- expect(prometheus_update_service).not_to receive(:execute)
-
- expect(subject.perform(application.name, application.id, project.id, Time.current - 5.minutes)).to be_nil
- end
- end
-
- context 'when another worker is already running' do
- it 'returns nil' do
- application = create(:clusters_applications_prometheus, :updating)
-
- expect(subject.perform(application.name, application.id, project.id, Time.current)).to be_nil
- end
- end
-
- it 'executes PrometheusUpdateService' do
- application = create(:clusters_applications_prometheus, :installed)
-
- expect(prometheus_update_service).to receive(:execute)
-
- subject.perform(application.name, application.id, project.id, Time.current)
- end
-
- context 'application is externally installed' do
- it 'does not execute PrometheusUpdateService' do
- application = create(:clusters_applications_prometheus, :externally_installed)
-
- expect(prometheus_update_service).not_to receive(:execute)
-
- subject.perform(application.name, application.id, project.id, Time.current)
- end
- end
-
- context 'with exclusive lease' do
- let_it_be(:user) { create(:user) }
-
- let(:application) { create(:clusters_applications_prometheus, :installed) }
- let(:lease_key) { "#{described_class.name.underscore}-#{application.id}" }
-
- before do
- # update_highest_role uses exclusive key too:
- allow(Gitlab::ExclusiveLease).to receive(:new).and_call_original
- stub_exclusive_lease_taken(lease_key)
- end
-
- it 'does not allow same app to be updated concurrently by same project' do
- expect(Clusters::Applications::PrometheusUpdateService).not_to receive(:new)
-
- subject.perform(application.name, application.id, project.id, Time.current)
- end
-
- it 'does not allow same app to be updated concurrently by different project', :aggregate_failures do
- project1 = create(:project, namespace: create(:namespace, owner: user))
-
- expect(Clusters::Applications::PrometheusUpdateService).not_to receive(:new)
-
- subject.perform(application.name, application.id, project1.id, Time.current)
- end
-
- it 'allows different app to be updated concurrently by same project' do
- application2 = create(:clusters_applications_prometheus, :installed)
- lease_key2 = "#{described_class.name.underscore}-#{application2.id}"
-
- stub_exclusive_lease(lease_key2)
-
- expect(Clusters::Applications::PrometheusUpdateService).to receive(:new)
- .with(application2, project)
-
- subject.perform(application2.name, application2.id, project.id, Time.current)
- end
-
- it 'allows different app to be updated by different project', :aggregate_failures do
- application2 = create(:clusters_applications_prometheus, :installed)
- lease_key2 = "#{described_class.name.underscore}-#{application2.id}"
-
- project2 = create(:project, namespace: create(:namespace, owner: user))
-
- stub_exclusive_lease(lease_key2)
-
- expect(Clusters::Applications::PrometheusUpdateService).to receive(:new)
- .with(application2, project2)
-
- subject.perform(application2.name, application2.id, project2.id, Time.current)
- end
- end
- end
-end
diff --git a/spec/workers/cluster_wait_for_app_update_worker_spec.rb b/spec/workers/cluster_wait_for_app_update_worker_spec.rb
deleted file mode 100644
index b7f7622a0e6..00000000000
--- a/spec/workers/cluster_wait_for_app_update_worker_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ClusterWaitForAppUpdateWorker do
- let(:check_upgrade_progress_service) { spy }
-
- before do
- allow(::Clusters::Applications::CheckUpgradeProgressService).to receive(:new).and_return(check_upgrade_progress_service)
- end
-
- it 'runs CheckUpgradeProgressService when application is found' do
- application = create(:clusters_applications_prometheus)
-
- expect(check_upgrade_progress_service).to receive(:execute)
-
- subject.perform(application.name, application.id)
- end
-
- it 'does not run CheckUpgradeProgressService when application is not found' do
- expect(check_upgrade_progress_service).not_to receive(:execute)
-
- expect do
- subject.perform("prometheus", -1)
- end.to raise_error(ActiveRecord::RecordNotFound)
- end
-end
diff --git a/spec/workers/cluster_wait_for_ingress_ip_address_worker_spec.rb b/spec/workers/cluster_wait_for_ingress_ip_address_worker_spec.rb
deleted file mode 100644
index 7a42c988a92..00000000000
--- a/spec/workers/cluster_wait_for_ingress_ip_address_worker_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ClusterWaitForIngressIpAddressWorker do
- describe '#perform' do
- let(:service) { instance_double(Clusters::Applications::CheckIngressIpAddressService, execute: true) }
- let(:application) { instance_double(Clusters::Applications::Ingress) }
- let(:worker) { described_class.new }
-
- before do
- allow(worker)
- .to receive(:find_application)
- .with('ingress', 117)
- .and_yield(application)
-
- allow(Clusters::Applications::CheckIngressIpAddressService)
- .to receive(:new)
- .with(application)
- .and_return(service)
-
- allow(described_class)
- .to receive(:perform_in)
- end
-
- it 'finds the application and calls CheckIngressIpAddressService#execute' do
- worker.perform('ingress', 117)
-
- expect(service).to have_received(:execute)
- end
- end
-end
diff --git a/spec/workers/clusters/applications/wait_for_uninstall_app_worker_spec.rb b/spec/workers/clusters/applications/wait_for_uninstall_app_worker_spec.rb
deleted file mode 100644
index d1dd1cd738b..00000000000
--- a/spec/workers/clusters/applications/wait_for_uninstall_app_worker_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Clusters::Applications::WaitForUninstallAppWorker, '#perform' do
- let(:app) { create(:clusters_applications_helm) }
- let(:app_name) { app.name }
- let(:app_id) { app.id }
-
- subject { described_class.new.perform(app_name, app_id) }
-
- context 'when app exists' do
- let(:service) { instance_double(Clusters::Applications::CheckUninstallProgressService) }
-
- it 'calls the check service' do
- expect(Clusters::Applications::CheckUninstallProgressService).to receive(:new).with(app).and_return(service)
- expect(service).to receive(:execute).once
-
- subject
- end
- end
-
- context 'when app does not exist' do
- let(:app_id) { 0 }
-
- it 'does not call the check service' do
- expect(Clusters::Applications::CheckUninstallProgressService).not_to receive(:new)
-
- expect { subject }.to raise_error(ActiveRecord::RecordNotFound)
- end
- end
-end
diff --git a/spec/workers/concerns/reenqueuer_spec.rb b/spec/workers/concerns/reenqueuer_spec.rb
index 56db2239bb1..e7287b55af2 100644
--- a/spec/workers/concerns/reenqueuer_spec.rb
+++ b/spec/workers/concerns/reenqueuer_spec.rb
@@ -121,14 +121,7 @@ RSpec.describe Reenqueuer::ReenqueuerSleeper do
# Unit test ensure_minimum_duration
describe '#ensure_minimum_duration' do
around do |example|
- # Allow Timecop.travel without the block form
- Timecop.safe_mode = false
-
- Timecop.freeze do
- example.run
- end
-
- Timecop.safe_mode = true
+ freeze_time { example.run }
end
let(:minimum_duration) { 4.seconds }
@@ -140,31 +133,31 @@ RSpec.describe Reenqueuer::ReenqueuerSleeper do
expect(dummy).to receive(:sleep).with(a_value_within(0.01).of(time_left))
dummy.ensure_minimum_duration(minimum_duration) do
- Timecop.travel(minimum_duration - time_left)
+ travel(minimum_duration - time_left)
end
end
end
context 'when the block completes just before the minimum duration' do
- let(:time_left) { 0.1.seconds }
+ let(:time_left) { 1.second }
it 'sleeps until the minimum duration' do
expect(dummy).to receive(:sleep).with(a_value_within(0.01).of(time_left))
dummy.ensure_minimum_duration(minimum_duration) do
- Timecop.travel(minimum_duration - time_left)
+ travel(minimum_duration - time_left)
end
end
end
context 'when the block completes just after the minimum duration' do
- let(:time_over) { 0.1.seconds }
+ let(:time_over) { 1.second }
it 'does not sleep' do
expect(dummy).not_to receive(:sleep)
dummy.ensure_minimum_duration(minimum_duration) do
- Timecop.travel(minimum_duration + time_over)
+ travel(minimum_duration + time_over)
end
end
end
@@ -176,7 +169,7 @@ RSpec.describe Reenqueuer::ReenqueuerSleeper do
expect(dummy).not_to receive(:sleep)
dummy.ensure_minimum_duration(minimum_duration) do
- Timecop.travel(minimum_duration + time_over)
+ travel(minimum_duration + time_over)
end
end
end
diff --git a/spec/workers/container_registry/cleanup_worker_spec.rb b/spec/workers/container_registry/cleanup_worker_spec.rb
new file mode 100644
index 00000000000..ffcb421ce1e
--- /dev/null
+++ b/spec/workers/container_registry/cleanup_worker_spec.rb
@@ -0,0 +1,81 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ContainerRegistry::CleanupWorker, :aggregate_failures do
+ let(:worker) { described_class.new }
+
+ describe '#perform' do
+ let_it_be_with_reload(:container_repository) { create(:container_repository) }
+
+ subject(:perform) { worker.perform }
+
+ context 'with no delete scheduled container repositories' do
+ it "doesn't enqueue delete container repository jobs" do
+ expect(ContainerRegistry::DeleteContainerRepositoryWorker).not_to receive(:perform_with_capacity)
+
+ perform
+ end
+ end
+
+ context 'with delete scheduled container repositories' do
+ before do
+ container_repository.delete_scheduled!
+ end
+
+ it 'enqueues delete container repository jobs' do
+ expect(ContainerRegistry::DeleteContainerRepositoryWorker).to receive(:perform_with_capacity)
+
+ perform
+ end
+ end
+
+ context 'with stale delete ongoing container repositories' do
+ let(:delete_started_at) { (described_class::STALE_DELETE_THRESHOLD + 5.minutes).ago }
+
+ before do
+ container_repository.update!(status: :delete_ongoing, delete_started_at: delete_started_at)
+ end
+
+ it 'resets them and enqueue delete container repository jobs' do
+ expect(ContainerRegistry::DeleteContainerRepositoryWorker).to receive(:perform_with_capacity)
+
+ expect { perform }
+ .to change { container_repository.reload.status }.from('delete_ongoing').to('delete_scheduled')
+ .and change { container_repository.reload.delete_started_at }.to(nil)
+ end
+ end
+
+ context 'for counts logging' do
+ let_it_be(:delete_started_at) { (described_class::STALE_DELETE_THRESHOLD + 5.minutes).ago }
+ let_it_be(:stale_delete_container_repository) do
+ create(:container_repository, :status_delete_ongoing, delete_started_at: delete_started_at)
+ end
+
+ before do
+ container_repository.delete_scheduled!
+ end
+
+ it 'logs the counts' do
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:delete_scheduled_container_repositories_count, 1)
+ expect(worker).to receive(:log_extra_metadata_on_done).with(:stale_delete_container_repositories_count, 1)
+
+ perform
+ end
+ end
+
+ context 'with container_registry_delete_repository_with_cron_worker disabled' do
+ before do
+ stub_feature_flags(container_registry_delete_repository_with_cron_worker: false)
+ end
+
+ it 'does not run' do
+ expect(worker).not_to receive(:reset_stale_deletes)
+ expect(worker).not_to receive(:enqueue_delete_container_repository_jobs)
+ expect(worker).not_to receive(:log_counts)
+
+ subject
+ end
+ end
+ end
+end
diff --git a/spec/workers/container_registry/delete_container_repository_worker_spec.rb b/spec/workers/container_registry/delete_container_repository_worker_spec.rb
new file mode 100644
index 00000000000..381e0cc164c
--- /dev/null
+++ b/spec/workers/container_registry/delete_container_repository_worker_spec.rb
@@ -0,0 +1,146 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe ContainerRegistry::DeleteContainerRepositoryWorker, :aggregate_failures do
+ let_it_be_with_reload(:container_repository) { create(:container_repository) }
+ let_it_be(:second_container_repository) { create(:container_repository) }
+
+ let(:worker) { described_class.new }
+
+ describe '#perform_work' do
+ subject(:perform_work) { worker.perform_work }
+
+ context 'with no work to do - no container repositories pending deletion' do
+ it 'will not delete any container repository' do
+ expect(::Projects::ContainerRepository::CleanupTagsService).not_to receive(:new)
+
+ expect { perform_work }.to not_change { ContainerRepository.count }
+ end
+ end
+
+ context 'with work to do' do
+ let(:tags_count) { 0 }
+ let(:cleanup_tags_service_response) { { status: :success, original_size: 100, deleted_size: 0 } }
+ let(:cleanup_tags_service_double) do
+ instance_double('Projects::ContainerRepository::CleanupTagsService', execute: cleanup_tags_service_response)
+ end
+
+ before do
+ container_repository.delete_scheduled!
+ allow(Projects::ContainerRepository::CleanupTagsService)
+ .to receive(:new)
+ .with(container_repository: container_repository, params: described_class::CLEANUP_TAGS_SERVICE_PARAMS)
+ .and_return(cleanup_tags_service_double)
+ end
+
+ it 'picks and destroys the delete scheduled container repository' do
+ expect_next_pending_destruction_container_repository do |repo|
+ expect_logs_on(repo, tags_size_before_delete: 100, deleted_tags_size: 0)
+ expect(repo).to receive(:destroy!).and_call_original
+ end
+ perform_work
+ expect(ContainerRepository.all).to contain_exactly(second_container_repository)
+ end
+
+ context 'with an error during the tags cleanup' do
+ let(:cleanup_tags_service_response) { { status: :error, original_size: 100, deleted_size: 0 } }
+
+ it 'does not delete the container repository' do
+ expect_next_pending_destruction_container_repository do |repo|
+ expect_logs_on(repo, tags_size_before_delete: 100, deleted_tags_size: 0)
+ expect(repo).to receive(:set_delete_scheduled_status).and_call_original
+ expect(repo).not_to receive(:destroy!)
+ end
+ expect { perform_work }.to not_change(ContainerRepository, :count)
+ .and not_change { container_repository.reload.status }
+ expect(container_repository.delete_started_at).to eq(nil)
+ end
+ end
+
+ context 'with an error during the destroy' do
+ it 'does not delete the container repository' do
+ expect_next_pending_destruction_container_repository do |repo|
+ expect_logs_on(repo, tags_size_before_delete: 100, deleted_tags_size: 0)
+ expect(repo).to receive(:destroy!).and_raise('Error!')
+ expect(repo).to receive(:set_delete_scheduled_status).and_call_original
+ end
+
+ expect(::Gitlab::ErrorTracking).to receive(:log_exception)
+ .with(instance_of(RuntimeError), class: described_class.name)
+ expect { perform_work }.to not_change(ContainerRepository, :count)
+ .and not_change { container_repository.reload.status }
+ expect(container_repository.delete_started_at).to eq(nil)
+ end
+ end
+
+ context 'with tags left to destroy' do
+ let(:tags_count) { 10 }
+
+ it 'does not delete the container repository' do
+ expect_next_pending_destruction_container_repository do |repo|
+ expect(repo).not_to receive(:destroy!)
+ expect(repo).to receive(:set_delete_scheduled_status).and_call_original
+ end
+
+ expect { perform_work }.to not_change(ContainerRepository, :count)
+ .and not_change { container_repository.reload.status }
+ expect(container_repository.delete_started_at).to eq(nil)
+ end
+ end
+
+ context 'with no tags on the container repository' do
+ let(:tags_count) { 0 }
+ let(:cleanup_tags_service_response) { { status: :success, original_size: 0, deleted_size: 0 } }
+
+ it 'picks and destroys the delete scheduled container repository' do
+ expect_next_pending_destruction_container_repository do |repo|
+ expect_logs_on(repo, tags_size_before_delete: 0, deleted_tags_size: 0)
+ expect(repo).to receive(:destroy!).and_call_original
+ end
+ perform_work
+ expect(ContainerRepository.all).to contain_exactly(second_container_repository)
+ end
+ end
+
+ def expect_next_pending_destruction_container_repository
+ original_method = ContainerRepository.method(:next_pending_destruction)
+ expect(ContainerRepository).to receive(:next_pending_destruction).with(order_by: nil) do
+ original_method.call(order_by: nil).tap do |repo|
+ allow(repo).to receive(:tags_count).and_return(tags_count)
+ expect(repo).to receive(:set_delete_ongoing_status).and_call_original
+ yield repo
+ end
+ end
+ end
+
+ def expect_logs_on(container_repository, tags_size_before_delete:, deleted_tags_size:)
+ payload = {
+ project_id: container_repository.project.id,
+ container_repository_id: container_repository.id,
+ container_repository_path: container_repository.path,
+ tags_size_before_delete: tags_size_before_delete,
+ deleted_tags_size: deleted_tags_size
+ }
+ expect(worker.logger).to receive(:info).with(worker.structured_payload(payload))
+ .and_call_original
+ end
+ end
+ end
+
+ describe '#max_running_jobs' do
+ subject { worker.max_running_jobs }
+
+ it { is_expected.to eq(described_class::MAX_CAPACITY) }
+ end
+
+ describe '#remaining_work_count' do
+ let_it_be(:delete_scheduled_container_repositories) do
+ create_list(:container_repository, described_class::MAX_CAPACITY + 2, :status_delete_scheduled)
+ end
+
+ subject { worker.remaining_work_count }
+
+ it { is_expected.to eq(described_class::MAX_CAPACITY + 1) }
+ end
+end
diff --git a/spec/workers/database/batched_background_migration/execution_worker_spec.rb b/spec/workers/database/batched_background_migration/execution_worker_spec.rb
new file mode 100644
index 00000000000..9a850a98f2f
--- /dev/null
+++ b/spec/workers/database/batched_background_migration/execution_worker_spec.rb
@@ -0,0 +1,141 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Database::BatchedBackgroundMigration::ExecutionWorker, :clean_gitlab_redis_shared_state do
+ include ExclusiveLeaseHelpers
+
+ describe '#perform' do
+ let(:database_name) { Gitlab::Database::MAIN_DATABASE_NAME.to_sym }
+ let(:base_model) { Gitlab::Database.database_base_models[database_name] }
+ let(:table_name) { :events }
+ let(:job_interval) { 5.minutes }
+ let(:lease_timeout) { job_interval * described_class::LEASE_TIMEOUT_MULTIPLIER }
+ let(:interval_variance) { described_class::INTERVAL_VARIANCE }
+
+ subject(:worker) { described_class.new }
+
+ context 'when the feature flag is disabled' do
+ let(:migration) do
+ create(:batched_background_migration, :active, interval: job_interval, table_name: table_name)
+ end
+
+ before do
+ stub_feature_flags(execute_batched_migrations_on_schedule: false)
+ end
+
+ it 'does nothing' do
+ expect(Gitlab::Database::BackgroundMigration::BatchedMigration).not_to receive(:find_executable)
+ expect(worker).not_to receive(:run_migration_job)
+
+ worker.perform(database_name, migration.id)
+ end
+ end
+
+ context 'when the feature flag is enabled' do
+ before do
+ stub_feature_flags(execute_batched_migrations_on_schedule: true)
+ end
+
+ context 'when the provided database is sharing config' do
+ before do
+ skip_if_multiple_databases_not_setup
+ end
+
+ it 'does nothing' do
+ ci_model = Gitlab::Database.database_base_models['ci']
+ expect(Gitlab::Database).to receive(:db_config_share_with)
+ .with(ci_model.connection_db_config).and_return('main')
+
+ expect(Gitlab::Database::BackgroundMigration::BatchedMigration).not_to receive(:find_executable)
+ expect(worker).not_to receive(:run_migration_job)
+
+ worker.perform(:ci, 123)
+ end
+ end
+
+ context 'when migration does not exist' do
+ it 'does nothing' do
+ expect(worker).not_to receive(:run_migration_job)
+
+ worker.perform(database_name, non_existing_record_id)
+ end
+ end
+
+ context 'when migration exist' do
+ let(:migration) do
+ create(:batched_background_migration, :active, interval: job_interval, table_name: table_name)
+ end
+
+ before do
+ allow(Gitlab::Database::BackgroundMigration::BatchedMigration).to receive(:find_executable)
+ .with(migration.id, connection: base_model.connection)
+ .and_return(migration)
+ end
+
+ context 'when the migration is no longer active' do
+ it 'does not run the migration' do
+ expect(Gitlab::Database::SharedModel).to receive(:using_connection).with(base_model.connection).and_yield
+
+ expect(migration).to receive(:active?).and_return(false)
+
+ expect(worker).not_to receive(:run_migration_job)
+
+ worker.perform(database_name, migration.id)
+ end
+ end
+
+ context 'when the interval has not elapsed' do
+ it 'does not run the migration' do
+ expect(Gitlab::Database::SharedModel).to receive(:using_connection).with(base_model.connection).and_yield
+ expect(migration).to receive(:interval_elapsed?).with(variance: interval_variance).and_return(false)
+ expect(worker).not_to receive(:run_migration_job)
+
+ worker.perform(database_name, migration.id)
+ end
+ end
+
+ context 'when the migration is still active and the interval has elapsed' do
+ let(:table_name_lease_key) do
+ "#{described_class.name.underscore}:database_name:#{database_name}:" \
+ "table_name:#{table_name}"
+ end
+
+ context 'when can not obtain lease on the table name' do
+ it 'does nothing' do
+ stub_exclusive_lease_taken(table_name_lease_key, timeout: lease_timeout)
+
+ expect(worker).not_to receive(:run_migration_job)
+
+ worker.perform(database_name, migration.id)
+ end
+ end
+
+ it 'always cleans up the exclusive lease' do
+ expect_to_obtain_exclusive_lease(table_name_lease_key, 'uuid-table-name', timeout: lease_timeout)
+ expect_to_cancel_exclusive_lease(table_name_lease_key, 'uuid-table-name')
+
+ expect(worker).to receive(:run_migration_job).and_raise(RuntimeError, 'I broke')
+
+ expect { worker.perform(database_name, migration.id) }.to raise_error(RuntimeError, 'I broke')
+ end
+
+ it 'runs the migration' do
+ expect(Gitlab::Database::SharedModel).to receive(:using_connection).with(base_model.connection).and_yield
+
+ expect_next_instance_of(Gitlab::Database::BackgroundMigration::BatchedMigrationRunner) do |instance|
+ expect(instance).to receive(:run_migration_job).with(migration)
+ end
+
+ expect_to_obtain_exclusive_lease(table_name_lease_key, 'uuid-table-name', timeout: lease_timeout)
+ expect_to_cancel_exclusive_lease(table_name_lease_key, 'uuid-table-name')
+
+ expect(worker).to receive(:run_migration_job).and_call_original
+
+ worker.perform(database_name, migration.id)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb
index 322f516fbeb..e705ca28e54 100644
--- a/spec/workers/every_sidekiq_worker_spec.rb
+++ b/spec/workers/every_sidekiq_worker_spec.rb
@@ -188,6 +188,7 @@ RSpec.describe 'Every Sidekiq worker' do
'Clusters::Cleanup::ProjectNamespaceWorker' => 3,
'Clusters::Cleanup::ServiceAccountWorker' => 3,
'ContainerExpirationPolicies::CleanupContainerRepositoryWorker' => 0,
+ 'ContainerRegistry::DeleteContainerRepositoryWorker' => 0,
'CreateCommitSignatureWorker' => 3,
'CreateGithubWebhookWorker' => 3,
'CreateNoteDiffFileWorker' => 3,
@@ -269,6 +270,7 @@ RSpec.describe 'Every Sidekiq worker' do
'Gitlab::GithubImport::ImportProtectedBranchWorker' => 5,
'Gitlab::GithubImport::ImportPullRequestMergedByWorker' => 5,
'Gitlab::GithubImport::ImportPullRequestReviewWorker' => 5,
+ 'Gitlab::GithubImport::PullRequests::ImportReviewRequestWorker' => 5,
'Gitlab::GithubImport::ImportPullRequestWorker' => 5,
'Gitlab::GithubImport::RefreshImportJidWorker' => 5,
'Gitlab::GithubImport::Stage::FinishImportWorker' => 5,
@@ -280,6 +282,7 @@ RSpec.describe 'Every Sidekiq worker' do
'Gitlab::GithubImport::Stage::ImportProtectedBranchesWorker' => 5,
'Gitlab::GithubImport::Stage::ImportNotesWorker' => 5,
'Gitlab::GithubImport::Stage::ImportPullRequestsMergedByWorker' => 5,
+ 'Gitlab::GithubImport::Stage::ImportPullRequestsReviewRequestsWorker' => 5,
'Gitlab::GithubImport::Stage::ImportPullRequestsReviewsWorker' => 5,
'Gitlab::GithubImport::Stage::ImportPullRequestsWorker' => 5,
'Gitlab::GithubImport::Stage::ImportRepositoryWorker' => 5,
@@ -339,6 +342,7 @@ RSpec.describe 'Every Sidekiq worker' do
'MergeRequests::AssigneesChangeWorker' => 3,
'MergeRequests::CreatePipelineWorker' => 3,
'MergeRequests::DeleteSourceBranchWorker' => 3,
+ 'MergeRequests::FetchSuggestedReviewersWorker' => 3,
'MergeRequests::HandleAssigneesChangeWorker' => 3,
'MergeRequests::ResolveTodosWorker' => 3,
'MergeRequests::SyncCodeOwnerApprovalRulesWorker' => 3,
@@ -398,6 +402,7 @@ RSpec.describe 'Every Sidekiq worker' do
'Projects::ScheduleBulkRepositoryShardMovesWorker' => 3,
'Projects::UpdateRepositoryStorageWorker' => 3,
'Projects::RefreshBuildArtifactsSizeStatisticsWorker' => 0,
+ 'Projects::RegisterSuggestedReviewersProjectWorker' => 3,
'PropagateIntegrationGroupWorker' => 3,
'PropagateIntegrationInheritDescendantWorker' => 3,
'PropagateIntegrationInheritWorker' => 3,
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
new file mode 100644
index 00000000000..fdcbfb18beb
--- /dev/null
+++ b/spec/workers/gitlab/github_import/pull_requests/import_review_request_worker_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::GithubImport::PullRequests::ImportReviewRequestWorker do
+ subject(:worker) { described_class.new }
+
+ describe '#import' do
+ let(:import_state) { build_stubbed(:import_state, :started) }
+
+ let(:project) do
+ instance_double('Project', full_path: 'foo/bar', id: 1, import_state: import_state)
+ end
+
+ let(:client) { instance_double('Gitlab::GithubImport::Client') }
+ let(:importer) { instance_double('Gitlab::GithubImport::Importer::IssueEventImporter') }
+
+ let(:review_request_hash) do
+ {
+ 'merge_request_id' => 6501124486,
+ 'users' => [
+ { 'id' => 4, 'login' => 'alice' },
+ { 'id' => 5, 'login' => 'bob' }
+ ]
+ }
+ end
+
+ it 'imports an pull request review requests' do
+ expect(Gitlab::GithubImport::Importer::PullRequests::ReviewRequestImporter)
+ .to receive(:new)
+ .with(
+ an_instance_of(Gitlab::GithubImport::Representation::PullRequests::ReviewRequests),
+ project,
+ client
+ )
+ .and_return(importer)
+
+ expect(importer).to receive(:execute)
+
+ expect(Gitlab::GithubImport::ObjectCounter)
+ .to receive(:increment).with(project, :pull_request_review_request, :imported)
+
+ worker.import(project, client, review_request_hash)
+ end
+ end
+end
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 6fcb5db2a54..5d6dcdc10ee 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
@@ -27,7 +27,7 @@ RSpec.describe Gitlab::GithubImport::Stage::ImportPullRequestsMergedByWorker do
expect(Gitlab::GithubImport::AdvanceStageWorker)
.to receive(:perform_async)
- .with(project.id, { '123' => 2 }, :pull_request_reviews)
+ .with(project.id, { '123' => 2 }, :pull_request_review_requests)
worker.import(client, project)
end
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
new file mode 100644
index 00000000000..151de9bdffc
--- /dev/null
+++ b/spec/workers/gitlab/github_import/stage/import_pull_requests_review_requests_worker_spec.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::GithubImport::Stage::ImportPullRequestsReviewRequestsWorker do
+ subject(:worker) { described_class.new }
+
+ let(:project) { instance_double(Project, id: 1, import_state: import_state) }
+ let(:import_state) { instance_double(ProjectImportState, refresh_jid_expiration: true) }
+ let(:client) { instance_double(Gitlab::GithubImport::Client) }
+ let(:importer) { instance_double(Gitlab::GithubImport::Importer::PullRequests::ReviewRequestsImporter) }
+ let(:waiter) { Gitlab::JobWaiter.new(2, '123') }
+
+ describe '#import' do
+ it 'imports all PR review requests' do
+ expect(Gitlab::GithubImport::Importer::PullRequests::ReviewRequestsImporter)
+ .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_request_reviews)
+
+ worker.import(client, project)
+ end
+ end
+end
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 75d4d2dff2e..18a70273219 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
@@ -23,8 +23,7 @@ RSpec.describe Gitlab::GithubImport::Stage::ImportPullRequestsReviewsWorker do
.to receive(:execute)
.and_return(waiter)
- expect(import_state)
- .to receive(:refresh_jid_expiration)
+ expect(import_state).to receive(:refresh_jid_expiration)
expect(Gitlab::GithubImport::AdvanceStageWorker)
.to receive(:perform_async)
diff --git a/spec/workers/gitlab_shell_worker_spec.rb b/spec/workers/gitlab_shell_worker_spec.rb
index c46ef87333a..a5419291d35 100644
--- a/spec/workers/gitlab_shell_worker_spec.rb
+++ b/spec/workers/gitlab_shell_worker_spec.rb
@@ -2,37 +2,45 @@
require 'spec_helper'
-RSpec.describe GitlabShellWorker do
- let(:worker) { described_class.new }
-
+RSpec.describe GitlabShellWorker, :sidekiq_inline do
describe '#perform' do
- describe '#add_key' do
- it 'delegates to Gitlab::AuthorizedKeys' do
- expect_next_instance_of(Gitlab::AuthorizedKeys) do |instance|
- expect(instance).to receive(:add_key).with('foo', 'bar')
+ Gitlab::Shell::PERMITTED_ACTIONS.each do |action|
+ describe "with the #{action} action" do
+ it 'forwards the message to Gitlab::Shell' do
+ expect_next_instance_of(Gitlab::Shell) do |instance|
+ expect(instance).to respond_to(action)
+ expect(instance).to receive(action).with('foo', 'bar')
+ end
+
+ described_class.perform_async(action, 'foo', 'bar')
end
-
- worker.perform('add_key', 'foo', 'bar')
end
end
- describe '#remove_key' do
- it 'delegates to Gitlab::AuthorizedKeys' do
- expect_next_instance_of(Gitlab::AuthorizedKeys) do |instance|
- expect(instance).to receive(:remove_key).with('foo', 'bar')
+ describe 'all other commands' do
+ context 'when verify_gitlab_shell_worker_method_names is enabled' do
+ it 'raises ArgumentError' do
+ allow_next_instance_of(described_class) do |job_instance|
+ expect(job_instance).not_to receive(:gitlab_shell)
+ end
+
+ expect { described_class.perform_async('foo', 'bar', 'baz') }
+ .to raise_error(ArgumentError, 'foo not allowed for GitlabShellWorker')
end
-
- worker.perform('remove_key', 'foo', 'bar')
end
- end
- describe 'all other commands' do
- it 'delegates them to Gitlab::Shell' do
- expect_next_instance_of(Gitlab::Shell) do |instance|
- expect(instance).to receive(:foo).with('bar', 'baz')
+ context 'when verify_gitlab_shell_worker_method_names is disabled' do
+ before do
+ stub_feature_flags(verify_gitlab_shell_worker_method_names: false)
end
- worker.perform('foo', 'bar', 'baz')
+ it 'forwards the message to Gitlab::Shell' do
+ expect_next_instance_of(Gitlab::Shell) do |instance|
+ expect(instance).to receive('foo').with('bar', 'baz')
+ end
+
+ described_class.perform_async('foo', 'bar', 'baz')
+ end
end
end
end
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 bda6f729759..4d6e6610a92 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
@@ -14,28 +14,41 @@ RSpec.describe IncidentManagement::AddSeveritySystemNoteWorker do
subject(:perform) { described_class.new.perform(incident_id, user_id) }
- shared_examples 'does not add a system note' do
+ shared_examples 'does not add anything' do
it 'does not change incident notes count' do
expect { perform }.not_to change { incident.notes.count }
end
+
+ it 'does not create a timeline event' do
+ expect(IncidentManagement::TimelineEvents::CreateService).not_to receive(:change_severity)
+ perform
+ end
end
context 'when incident and user exist' do
it 'creates a system note' do
expect { perform }.to change { incident.notes.where(author: user).count }.by(1)
end
+
+ it 'creates a timeline event' do
+ expect(IncidentManagement::TimelineEvents::CreateService)
+ .to receive(:change_severity)
+ .with(incident, user)
+ .and_call_original
+ perform
+ end
end
context 'when incident does not exist' do
let(:incident_id) { -1 }
- it_behaves_like 'does not add a system note'
+ it_behaves_like 'does not add anything'
end
context 'when incident_id is nil' do
let(:incident_id) { nil }
- it_behaves_like 'does not add a system note'
+ it_behaves_like 'does not add anything'
end
context 'when issue is not an incident' do
@@ -43,19 +56,19 @@ RSpec.describe IncidentManagement::AddSeveritySystemNoteWorker do
let(:incident_id) { issue.id }
- it_behaves_like 'does not add a system note'
+ it_behaves_like 'does not add anything'
end
context 'when user does not exist' do
let(:user_id) { -1 }
- it_behaves_like 'does not add a system note'
+ it_behaves_like 'does not add anything'
end
context 'when user_id is nil' do
let(:user_id) { nil }
- it_behaves_like 'does not add a system note'
+ it_behaves_like 'does not add anything'
end
end
end
diff --git a/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb b/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb
index 77190dc49d9..09d58a1189e 100644
--- a/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb
+++ b/spec/workers/loose_foreign_keys/cleanup_worker_spec.rb
@@ -105,9 +105,10 @@ RSpec.describe LooseForeignKeys::CleanupWorker do
def perform_for(db:)
time = Time.current.midnight
- if db == :main
+ case db
+ when :main
time += 2.minutes
- elsif db == :ci
+ when :ci
time += 3.minutes
end
@@ -124,37 +125,6 @@ RSpec.describe LooseForeignKeys::CleanupWorker do
expect(loose_fk_child_table_2_1.count).to eq(0)
end
- context 'when deleting in batches' do
- before do
- stub_const('LooseForeignKeys::CleanupWorker::BATCH_SIZE', 2)
- end
-
- it 'cleans up all rows' do
- expect(LooseForeignKeys::BatchCleanerService).to receive(:new).exactly(:twice).and_call_original
-
- perform_for(db: :main)
-
- expect(loose_fk_child_table_1_1.count).to eq(0)
- expect(loose_fk_child_table_1_2.where(parent_id_with_different_column: nil).count).to eq(4)
- expect(loose_fk_child_table_2_1.count).to eq(0)
- end
- end
-
- context 'when the deleted rows count limit have been reached' do
- def count_deletable_rows
- loose_fk_child_table_1_1.count + loose_fk_child_table_2_1.count
- end
-
- before do
- stub_const('LooseForeignKeys::ModificationTracker::MAX_DELETES', 2)
- stub_const('LooseForeignKeys::CleanerService::DELETE_LIMIT', 1)
- end
-
- it 'cleans up 2 rows' do
- expect { perform_for(db: :main) }.to change { count_deletable_rows }.by(-2)
- end
- end
-
describe 'multi-database support' do
where(:current_minute, :configured_base_models, :expected_connection_model) do
2 | { main: 'ActiveRecord::Base', ci: 'Ci::ApplicationRecord' } | 'ActiveRecord::Base'
diff --git a/spec/workers/mail_scheduler/notification_service_worker_spec.rb b/spec/workers/mail_scheduler/notification_service_worker_spec.rb
index ff4a1646d09..3c17025c152 100644
--- a/spec/workers/mail_scheduler/notification_service_worker_spec.rb
+++ b/spec/workers/mail_scheduler/notification_service_worker_spec.rb
@@ -42,9 +42,42 @@ RSpec.describe MailScheduler::NotificationServiceWorker do
end
end
- context 'when the method is not a public method' do
- it 'raises NoMethodError' do
- expect { worker.perform('notifiable?', *serialize(key)) }.to raise_error(NoMethodError)
+ context 'when the method is allowed' do
+ it 'calls the method on NotificationService' do
+ NotificationService.permitted_actions.each do |action|
+ expect(worker.notification_service).to receive(action).with(key)
+
+ worker.perform(action, *serialize(key))
+ end
+ end
+ end
+
+ context 'when the method is not allowed' do
+ context 'when verify_mail_scheduler_notification_service_worker_method_names is enabled' do
+ it 'raises ArgumentError' do
+ expect(worker.notification_service).not_to receive(:async)
+ expect(worker.notification_service).not_to receive(:foo)
+
+ expect { worker.perform('async', *serialize(key)) }
+ .to raise_error(ArgumentError, 'async not allowed for MailScheduler::NotificationServiceWorker')
+
+ expect { worker.perform('foo', *serialize(key)) }
+ .to raise_error(ArgumentError, 'foo not allowed for MailScheduler::NotificationServiceWorker')
+ end
+ end
+
+ context 'when verify_mail_scheduler_notification_service_worker_method_names is disabled' do
+ before do
+ stub_feature_flags(verify_mail_scheduler_notification_service_worker_method_names: false)
+ end
+
+ it 'forwards the argument to the service' do
+ expect(worker.notification_service).to receive(:async)
+ expect(worker.notification_service).to receive(:foo)
+
+ worker.perform('async', *serialize(key))
+ worker.perform('foo', *serialize(key))
+ end
end
end
end
diff --git a/spec/workers/merge_requests/delete_branch_worker_spec.rb b/spec/workers/merge_requests/delete_branch_worker_spec.rb
new file mode 100644
index 00000000000..80ca8c061f5
--- /dev/null
+++ b/spec/workers/merge_requests/delete_branch_worker_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe MergeRequests::DeleteBranchWorker do
+ let_it_be(:merge_request) { create(:merge_request) }
+ let_it_be(:user) { create(:user) }
+
+ let(:branch) { merge_request.source_branch }
+ let(:sha) { merge_request.source_branch_sha }
+ let(:retarget_branch) { true }
+ let(:worker) { described_class.new }
+
+ describe '#perform' do
+ context 'with a non-existing merge request' do
+ it 'does nothing' do
+ expect(::Branches::DeleteService).not_to receive(:new)
+ worker.perform(non_existing_record_id, user.id, branch, retarget_branch)
+ end
+ end
+
+ context 'with a non-existing user' do
+ it 'does nothing' do
+ expect(::Branches::DeleteService).not_to receive(:new)
+
+ worker.perform(merge_request.id, non_existing_record_id, branch, retarget_branch)
+ end
+ end
+
+ context 'with existing user and merge request' do
+ it 'calls service to delete source branch' do
+ expect_next_instance_of(::Branches::DeleteService) do |instance|
+ expect(instance).to receive(:execute).with(branch)
+ end
+
+ worker.perform(merge_request.id, user.id, branch, retarget_branch)
+ end
+
+ context 'when retarget branch param is true' do
+ it 'calls the retarget chain service' do
+ expect_next_instance_of(::MergeRequests::RetargetChainService) do |instance|
+ expect(instance).to receive(:execute).with(merge_request)
+ end
+
+ worker.perform(merge_request.id, user.id, branch, retarget_branch)
+ end
+ end
+
+ context 'when retarget branch param is false' do
+ let(:retarget_branch) { false }
+
+ it 'does not call the retarget chain service' do
+ expect(::MergeRequests::RetargetChainService).not_to receive(:new)
+
+ worker.perform(merge_request.id, user.id, branch, retarget_branch)
+ end
+ end
+ end
+
+ it_behaves_like 'an idempotent worker' do
+ let(:merge_request) { create(:merge_request) }
+ let(:job_args) { [merge_request.id, sha, user.id, true] }
+ end
+ end
+end
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 fe677103fd0..2935d3ef5dc 100644
--- a/spec/workers/merge_requests/delete_source_branch_worker_spec.rb
+++ b/spec/workers/merge_requests/delete_source_branch_worker_spec.rb
@@ -10,96 +10,116 @@ RSpec.describe MergeRequests::DeleteSourceBranchWorker do
let(:worker) { described_class.new }
describe '#perform' do
- context 'with a non-existing merge request' do
- it 'does nothing' do
- expect(::Branches::DeleteService).not_to receive(:new)
- expect(::MergeRequests::RetargetChainService).not_to receive(:new)
+ context 'when the add_delete_branch_worker feature flag is enabled' do
+ context 'with a non-existing merge request' do
+ it 'does nothing' do
+ expect(::MergeRequests::DeleteBranchWorker).not_to receive(:perform_async)
- worker.perform(non_existing_record_id, sha, user.id)
+ worker.perform(non_existing_record_id, sha, user.id)
+ end
end
- end
- context 'with a non-existing user' do
- it 'does nothing' do
- expect(::Branches::DeleteService).not_to receive(:new)
- expect(::MergeRequests::RetargetChainService).not_to receive(:new)
+ context 'with a non-existing user' do
+ it 'does nothing' do
+ expect(::MergeRequests::DeleteBranchWorker).not_to receive(:perform_async)
- worker.perform(merge_request.id, sha, non_existing_record_id)
+ worker.perform(merge_request.id, sha, non_existing_record_id)
+ end
end
- end
- context 'with existing user and merge request' do
- it 'calls service to delete source branch' do
- expect_next_instance_of(::Branches::DeleteService) do |instance|
- expect(instance).to receive(:execute).with(merge_request.source_branch)
+ context 'with existing user and merge request' do
+ it 'creates a new delete branch worker async' do
+ expect(::MergeRequests::DeleteBranchWorker).to receive(:perform_async).with(merge_request.id, user.id,
+ merge_request.source_branch, true)
+
+ worker.perform(merge_request.id, sha, user.id)
end
- worker.perform(merge_request.id, sha, user.id)
- end
+ context 'source branch sha does not match' do
+ it 'does nothing' do
+ expect(::MergeRequests::DeleteBranchWorker).not_to receive(:perform_async)
- it 'calls service to try retarget merge requests' do
- expect_next_instance_of(::MergeRequests::RetargetChainService) do |instance|
- expect(instance).to receive(:execute).with(merge_request)
+ worker.perform(merge_request.id, 'new-source-branch-sha', user.id)
+ end
end
+ end
- worker.perform(merge_request.id, sha, user.id)
+ it_behaves_like 'an idempotent worker' do
+ let(:merge_request) { create(:merge_request) }
+ let(:job_args) { [merge_request.id, sha, user.id] }
+ end
+ end
+
+ context 'when the add_delete_branch_worker feature flag is disabled' do
+ before do
+ stub_feature_flags(add_delete_branch_worker: false)
end
- context 'source branch sha does not match' do
+ context 'with a non-existing merge request' do
it 'does nothing' do
expect(::Branches::DeleteService).not_to receive(:new)
expect(::MergeRequests::RetargetChainService).not_to receive(:new)
- worker.perform(merge_request.id, 'new-source-branch-sha', user.id)
+ worker.perform(non_existing_record_id, sha, user.id)
end
end
- context 'when delete service returns an error' do
- let(:service_result) { ServiceResponse.error(message: 'placeholder') }
+ context 'with a non-existing user' do
+ it 'does nothing' do
+ expect(::Branches::DeleteService).not_to receive(:new)
+ expect(::MergeRequests::RetargetChainService).not_to receive(:new)
+
+ worker.perform(merge_request.id, sha, non_existing_record_id)
+ end
+ end
- it 'tracks the exception' do
+ context 'with existing user and merge request' do
+ it 'calls service to delete source branch' do
expect_next_instance_of(::Branches::DeleteService) do |instance|
- expect(instance).to receive(:execute).with(merge_request.source_branch).and_return(service_result)
+ expect(instance).to receive(:execute).with(merge_request.source_branch)
end
- expect(service_result).to receive(:track_exception).and_call_original
+ worker.perform(merge_request.id, sha, user.id)
+ end
+
+ it 'calls service to try retarget merge requests' do
+ expect_next_instance_of(::MergeRequests::RetargetChainService) do |instance|
+ expect(instance).to receive(:execute).with(merge_request)
+ end
worker.perform(merge_request.id, sha, user.id)
end
- context 'when track_delete_source_errors is disabled' do
- before do
- stub_feature_flags(track_delete_source_errors: false)
+ context 'source branch sha does not match' do
+ it 'does nothing' do
+ expect(::Branches::DeleteService).not_to receive(:new)
+ expect(::MergeRequests::RetargetChainService).not_to receive(:new)
+
+ worker.perform(merge_request.id, 'new-source-branch-sha', user.id)
end
+ end
+
+ context 'when delete service returns an error' do
+ let(:service_result) { ServiceResponse.error(message: 'placeholder') }
- it 'does not track the exception' do
+ it 'still retargets the merge request' do
expect_next_instance_of(::Branches::DeleteService) do |instance|
expect(instance).to receive(:execute).with(merge_request.source_branch).and_return(service_result)
end
- expect(service_result).not_to receive(:track_exception)
+ expect_next_instance_of(::MergeRequests::RetargetChainService) do |instance|
+ expect(instance).to receive(:execute).with(merge_request)
+ end
worker.perform(merge_request.id, sha, user.id)
end
end
-
- it 'still retargets the merge request' do
- expect_next_instance_of(::Branches::DeleteService) do |instance|
- expect(instance).to receive(:execute).with(merge_request.source_branch).and_return(service_result)
- end
-
- expect_next_instance_of(::MergeRequests::RetargetChainService) do |instance|
- expect(instance).to receive(:execute).with(merge_request)
- end
-
- worker.perform(merge_request.id, sha, user.id)
- end
end
- end
- it_behaves_like 'an idempotent worker' do
- let(:merge_request) { create(:merge_request) }
- let(:job_args) { [merge_request.id, sha, user.id] }
+ it_behaves_like 'an idempotent worker' do
+ let(:merge_request) { create(:merge_request) }
+ let(:job_args) { [merge_request.id, sha, user.id] }
+ end
end
end
end
diff --git a/spec/workers/namespaces/root_statistics_worker_spec.rb b/spec/workers/namespaces/root_statistics_worker_spec.rb
index 7b774da0bdc..30854415405 100644
--- a/spec/workers/namespaces/root_statistics_worker_spec.rb
+++ b/spec/workers/namespaces/root_statistics_worker_spec.rb
@@ -89,4 +89,17 @@ RSpec.describe Namespaces::RootStatisticsWorker, '#perform' do
.not_to change { Namespace::AggregationSchedule.count }
end
end
+
+ it_behaves_like 'worker with data consistency',
+ described_class,
+ feature_flag: :root_statistics_worker_read_replica,
+ data_consistency: :sticky
+
+ it 'has the `until_executed` deduplicate strategy' do
+ expect(described_class.get_deduplicate_strategy).to eq(:until_executed)
+ end
+
+ it 'has an option to reschedule once if deduplicated' do
+ expect(described_class.get_deduplication_options).to include({ if_deduplicated: :reschedule_once })
+ end
end
diff --git a/spec/workers/pages/invalidate_domain_cache_worker_spec.rb b/spec/workers/pages/invalidate_domain_cache_worker_spec.rb
index b9c27c54fa1..c786d4658d4 100644
--- a/spec/workers/pages/invalidate_domain_cache_worker_spec.rb
+++ b/spec/workers/pages/invalidate_domain_cache_worker_spec.rb
@@ -4,9 +4,9 @@ require 'spec_helper'
RSpec.describe Pages::InvalidateDomainCacheWorker do
shared_examples 'clears caches with' do |event_class:, event_data:, caches:|
- let(:event) do
- event_class.new(data: event_data)
- end
+ include AfterNextHelpers
+
+ let(:event) { event_class.new(data: event_data) }
subject { consume_event(subscriber: described_class, event: event) }
@@ -14,9 +14,8 @@ RSpec.describe Pages::InvalidateDomainCacheWorker do
it 'clears the cache with Gitlab::Pages::CacheControl' do
caches.each do |cache|
- expect_next_instance_of(Gitlab::Pages::CacheControl, type: cache[:type], id: cache[:id]) do |cache_control|
- expect(cache_control).to receive(:clear_cache)
- end
+ expect_next(Gitlab::Pages::CacheControl, type: cache[:type], id: cache[:id])
+ .to receive(:clear_cache)
end
subject
@@ -181,19 +180,17 @@ RSpec.describe Pages::InvalidateDomainCacheWorker do
]
end
- it 'does not clear the cache when the attributes is not pages related' do
- event = Projects::ProjectAttributesChangedEvent.new(
- data: {
- project_id: 1,
- namespace_id: 2,
- root_namespace_id: 3,
- attributes: ['unknown']
- }
- )
-
- expect(described_class).not_to receive(:clear_cache)
-
- ::Gitlab::EventStore.publish(event)
+ it_behaves_like 'ignores the published event' do
+ let(:event) do
+ Projects::ProjectAttributesChangedEvent.new(
+ data: {
+ project_id: 1,
+ namespace_id: 2,
+ root_namespace_id: 3,
+ attributes: ['unknown']
+ }
+ )
+ end
end
end
@@ -204,26 +201,24 @@ RSpec.describe Pages::InvalidateDomainCacheWorker do
project_id: 1,
namespace_id: 2,
root_namespace_id: 3,
- features: ["pages_access_level"]
+ features: ['pages_access_level']
},
caches: [
{ type: :project, id: 1 },
{ type: :namespace, id: 3 }
]
- it 'does not clear the cache when the features is not pages related' do
- event = Projects::ProjectFeaturesChangedEvent.new(
- data: {
- project_id: 1,
- namespace_id: 2,
- root_namespace_id: 3,
- features: ['unknown']
- }
- )
-
- expect(described_class).not_to receive(:clear_cache)
-
- ::Gitlab::EventStore.publish(event)
+ it_behaves_like 'ignores the published event' do
+ let(:event) do
+ Projects::ProjectFeaturesChangedEvent.new(
+ data: {
+ project_id: 1,
+ namespace_id: 2,
+ root_namespace_id: 3,
+ features: ['unknown']
+ }
+ )
+ end
end
end
diff --git a/spec/workers/pages_worker_spec.rb b/spec/workers/pages_worker_spec.rb
index ad714d8d11e..f0d29037fa4 100644
--- a/spec/workers/pages_worker_spec.rb
+++ b/spec/workers/pages_worker_spec.rb
@@ -3,14 +3,26 @@
require 'spec_helper'
RSpec.describe PagesWorker, :sidekiq_inline do
- let(:project) { create(:project) }
- let(:ci_build) { create(:ci_build, project: project) }
+ let_it_be(:ci_build) { create(:ci_build) }
- it 'calls UpdatePagesService' do
- expect_next_instance_of(Projects::UpdatePagesService, project, ci_build) do |service|
- expect(service).to receive(:execute)
+ context 'when called with the deploy action' do
+ it 'calls UpdatePagesService' do
+ expect_next_instance_of(Projects::UpdatePagesService, ci_build.project, ci_build) do |service|
+ expect(service).to receive(:execute)
+ end
+
+ described_class.perform_async(:deploy, ci_build.id)
end
+ end
- described_class.perform_async(:deploy, ci_build.id)
+ context 'when called with any other action' do
+ it 'does nothing' do
+ expect_next_instance_of(described_class) do |job_class|
+ expect(job_class).not_to receive(:foo)
+ expect(job_class).not_to receive(:deploy)
+ end
+
+ described_class.perform_async(:foo)
+ end
end
end
diff --git a/spec/workers/projects/after_import_worker_spec.rb b/spec/workers/projects/after_import_worker_spec.rb
index a14b2443173..85d15c89b0a 100644
--- a/spec/workers/projects/after_import_worker_spec.rb
+++ b/spec/workers/projects/after_import_worker_spec.rb
@@ -3,8 +3,6 @@
require 'spec_helper'
RSpec.describe Projects::AfterImportWorker do
- include GitHelpers
-
subject { worker.perform(project.id) }
let(: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 3158ac9fa27..732dc540fb7 100644
--- a/spec/workers/projects/post_creation_worker_spec.rb
+++ b/spec/workers/projects/post_creation_worker_spec.rb
@@ -81,6 +81,40 @@ RSpec.describe Projects::PostCreationWorker do
end
end
end
+
+ describe 'Incident timeline event tags' do
+ context 'when project is nil' do
+ let(:job_args) { [nil] }
+
+ it 'does not create event tags' do
+ expect { subject }.not_to change { IncidentManagement::TimelineEventTag.count }
+ end
+ end
+
+ context 'when project is created', :aggregate_failures do
+ it 'creates tags for the project' do
+ expect { subject }.to change { IncidentManagement::TimelineEventTag.count }.by(2)
+
+ expect(project.incident_management_timeline_event_tags.pluck_names).to match_array(
+ [
+ ::IncidentManagement::TimelineEventTag::START_TIME_TAG_NAME,
+ ::IncidentManagement::TimelineEventTag::END_TIME_TAG_NAME
+ ]
+ )
+ end
+
+ it 'raises error if record creation fails' do
+ allow_next_instance_of(IncidentManagement::TimelineEventTag) do |tag|
+ allow(tag).to receive(:valid?).and_return(false)
+ end
+
+ expect(Gitlab::ErrorTracking).to receive(:track_exception).with(an_instance_of(ActiveRecord::RecordInvalid), include(extra: { project_id: a_kind_of(Integer) })).twice
+ subject
+
+ expect(project.incident_management_timeline_event_tags).to be_empty
+ end
+ end
+ end
end
end
end
diff --git a/spec/workers/remove_expired_members_worker_spec.rb b/spec/workers/remove_expired_members_worker_spec.rb
index 44b8fa21be4..062a9bcfa83 100644
--- a/spec/workers/remove_expired_members_worker_spec.rb
+++ b/spec/workers/remove_expired_members_worker_spec.rb
@@ -56,27 +56,13 @@ RSpec.describe RemoveExpiredMembersWorker do
expect(Member.find_by(user_id: expired_project_bot.id)).to be_nil
end
- context 'when user_destroy_with_limited_execution_time_worker is enabled' do
- it 'initiates project bot removal' do
- worker.perform
-
- expect(
- Users::GhostUserMigration.where(user: expired_project_bot,
- initiator_user: nil)
- ).to be_exists
- end
- end
-
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
- end
-
- it 'deletes expired project bot' do
- worker.perform
+ it 'initiates project bot removal' do
+ worker.perform
- expect(User.exists?(expired_project_bot.id)).to be(false)
- end
+ expect(
+ Users::GhostUserMigration.where(user: expired_project_bot,
+ initiator_user: nil)
+ ).to be_exists
end
end
diff --git a/spec/workers/repository_check/single_repository_worker_spec.rb b/spec/workers/repository_check/single_repository_worker_spec.rb
index dbb24cc047e..b8db262598b 100644
--- a/spec/workers/repository_check/single_repository_worker_spec.rb
+++ b/spec/workers/repository_check/single_repository_worker_spec.rb
@@ -6,12 +6,18 @@ require 'fileutils'
RSpec.describe RepositoryCheck::SingleRepositoryWorker do
subject(:worker) { described_class.new }
+ before do
+ allow(::Gitlab::Git::Repository).to receive(:new).and_call_original
+ end
+
it 'skips when the project has no push events' do
project = create(:project, :repository, :wiki_disabled)
project.events.destroy_all # rubocop: disable Cop/DestroyAll
- break_project(project)
- expect(worker).not_to receive(:git_fsck)
+ repository = instance_double(::Gitlab::Git::Repository)
+ allow(::Gitlab::Git::Repository).to receive(:new)
+ .with(project.repository_storage, "#{project.disk_path}.git", anything, anything, container: project)
+ .and_return(repository)
worker.perform(project.id)
@@ -21,7 +27,12 @@ RSpec.describe RepositoryCheck::SingleRepositoryWorker do
it 'fails when the project has push events and a broken repository' do
project = create(:project, :repository)
create_push_event(project)
- break_project(project)
+
+ repository = project.repository.raw
+ expect(repository).to receive(:fsck).and_raise(::Gitlab::Git::Repository::GitError)
+ expect(::Gitlab::Git::Repository).to receive(:new)
+ .with(project.repository_storage, "#{project.disk_path}.git", anything, anything, container: project)
+ .and_return(repository)
worker.perform(project.id)
@@ -32,7 +43,11 @@ RSpec.describe RepositoryCheck::SingleRepositoryWorker do
project = create(:project, :repository, :wiki_disabled)
create_push_event(project)
- expect(worker).to receive(:git_fsck).and_call_original
+ repository = project.repository.raw
+ expect(repository).to receive(:fsck).and_call_original
+ expect(::Gitlab::Git::Repository).to receive(:new)
+ .with(project.repository_storage, "#{project.disk_path}.git", anything, anything, container: project)
+ .and_return(repository)
expect do
worker.perform(project.id)
@@ -50,7 +65,12 @@ RSpec.describe RepositoryCheck::SingleRepositoryWorker do
worker.perform(project.id)
expect(project.reload.last_repository_check_failed).to eq(false)
- break_wiki(project)
+ repository = project.wiki.repository.raw
+ expect(repository).to receive(:fsck).and_raise(::Gitlab::Git::Repository::GitError)
+ expect(::Gitlab::Git::Repository).to receive(:new)
+ .with(project.repository_storage, "#{project.disk_path}.wiki.git", anything, anything, container: project.wiki)
+ .and_return(repository)
+
worker.perform(project.id)
expect(project.reload.last_repository_check_failed).to eq(true)
@@ -59,7 +79,10 @@ RSpec.describe RepositoryCheck::SingleRepositoryWorker do
it 'skips wikis when disabled' do
project = create(:project, :wiki_disabled)
# Make sure the test would fail if the wiki repo was checked
- break_wiki(project)
+ repository = instance_double(::Gitlab::Git::Repository)
+ allow(::Gitlab::Git::Repository).to receive(:new)
+ .with(project.repository_storage, "#{project.disk_path}.wiki.git", anything, anything, container: project)
+ .and_return(repository)
subject.perform(project.id)
@@ -88,31 +111,4 @@ RSpec.describe RepositoryCheck::SingleRepositoryWorker do
def create_push_event(project)
project.events.create!(action: :pushed, author_id: create(:user).id)
end
-
- def break_wiki(project)
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- break_repo(wiki_path(project))
- end
- end
-
- def wiki_path(project)
- project.wiki.repository.path_to_repo
- end
-
- def break_project(project)
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- break_repo(project.repository.path_to_repo)
- end
- end
-
- def break_repo(repo)
- # Create or replace blob ffffffffffffffffffffffffffffffffffffffff with an empty file
- # This will make the repo invalid, _and_ 'git init' cannot fix it.
- path = File.join(repo, 'objects', 'ff')
- file = File.join(path, 'ffffffffffffffffffffffffffffffffffffff')
-
- FileUtils.mkdir_p(path)
- FileUtils.rm_f(file)
- FileUtils.touch(file)
- end
end
diff --git a/spec/workers/repository_import_worker_spec.rb b/spec/workers/repository_import_worker_spec.rb
index 82d975cb85a..1dc77fbf83f 100644
--- a/spec/workers/repository_import_worker_spec.rb
+++ b/spec/workers/repository_import_worker_spec.rb
@@ -46,36 +46,24 @@ RSpec.describe RepositoryImportWorker do
end
context 'when the import has failed' do
- it 'hide the credentials that were used in the import URL' do
- error = %q{remote: Not Found fatal: repository 'https://user:pass@test.com/root/repoC.git/' not found }
+ it 'updates the error on Import/Export & hides credentials from import URL' do
+ import_url = 'https://user:pass@test.com/root/repoC.git/'
+ error = "#{import_url} not found"
import_state.update!(jid: '123')
- expect_next_instance_of(Projects::ImportService) do |instance|
- expect(instance).to receive(:execute).and_return({ status: :error, message: error })
- end
-
- expect do
- subject.perform(project.id)
- end.to raise_error(RuntimeError, error)
- expect(import_state.reload.jid).not_to be_nil
- expect(import_state.status).to eq('failed')
- end
-
- it 'updates the error on Import/Export' do
- error = %q{remote: Not Found fatal: repository 'https://user:pass@test.com/root/repoC.git/' not found }
-
project.update!(import_type: 'gitlab_project')
- import_state.update!(jid: '123')
+
expect_next_instance_of(Projects::ImportService) do |instance|
- expect(instance).to receive(:execute).and_return({ status: :error, message: error })
+ expect(instance).to receive(:track_start_import).and_raise(StandardError, error)
end
- expect do
- subject.perform(project.id)
- end.to raise_error(RuntimeError, error)
+ expect { subject.perform(project.id) }.not_to raise_error
- expect(import_state.reload.last_error).not_to be_nil
+ import_state.reload
+ expect(import_state.jid).to eq('123')
expect(import_state.status).to eq('failed')
+ expect(import_state.last_error).to include("[FILTERED] not found")
+ expect(import_state.last_error).not_to include(import_url)
end
end
diff --git a/spec/workers/run_pipeline_schedule_worker_spec.rb b/spec/workers/run_pipeline_schedule_worker_spec.rb
index 10c22b736d2..5fa7c5d64db 100644
--- a/spec/workers/run_pipeline_schedule_worker_spec.rb
+++ b/spec/workers/run_pipeline_schedule_worker_spec.rb
@@ -42,14 +42,42 @@ RSpec.describe RunPipelineScheduleWorker do
end
end
- context 'when everything is ok' do
- let(:create_pipeline_service) { instance_double(Ci::CreatePipelineService) }
+ describe "#run_pipeline_schedule" do
+ let(:create_pipeline_service) { instance_double(Ci::CreatePipelineService, execute: service_response) }
+ let(:service_response) { instance_double(ServiceResponse, payload: pipeline, error?: false) }
- it 'calls the Service' do
+ before do
expect(Ci::CreatePipelineService).to receive(:new).with(project, user, ref: pipeline_schedule.ref).and_return(create_pipeline_service)
- expect(create_pipeline_service).to receive(:execute!).with(:schedule, ignore_skip_ci: true, save_on_errors: false, schedule: pipeline_schedule)
- worker.perform(pipeline_schedule.id, user.id)
+ expect(create_pipeline_service).to receive(:execute).with(:schedule, ignore_skip_ci: true, save_on_errors: false, schedule: pipeline_schedule).and_return(service_response)
+ end
+
+ context "when pipeline is persisted" do
+ let(:pipeline) { instance_double(Ci::Pipeline, persisted?: true) }
+
+ it "returns the service response" do
+ expect(worker.perform(pipeline_schedule.id, user.id)).to eq(service_response)
+ end
+
+ it "does not log errors" do
+ expect(worker).not_to receive(:log_extra_metadata_on_done)
+
+ expect(worker.perform(pipeline_schedule.id, user.id)).to eq(service_response)
+ end
+ end
+
+ context "when pipeline was not persisted" do
+ let(:service_response) { instance_double(ServiceResponse, error?: true, message: "Error", payload: pipeline) }
+ let(:pipeline) { instance_double(Ci::Pipeline, persisted?: false) }
+
+ it "logs a pipeline creation error" do
+ expect(worker)
+ .to receive(:log_extra_metadata_on_done)
+ .with(:pipeline_creation_error, service_response.message)
+ .and_call_original
+
+ expect(worker.perform(pipeline_schedule.id, user.id)).to eq(service_response.message)
+ end
end
end
@@ -82,20 +110,5 @@ RSpec.describe RunPipelineScheduleWorker do
worker.perform(pipeline_schedule.id, user.id)
end
end
-
- context 'when pipeline cannot be created' do
- before do
- allow(Ci::CreatePipelineService).to receive(:new) { raise Ci::CreatePipelineService::CreateError }
- end
-
- it 'logging a pipeline error' do
- expect(worker)
- .to receive(:log_extra_metadata_on_done)
- .with(:pipeline_creation_error, an_instance_of(Ci::CreatePipelineService::CreateError))
- .and_call_original
-
- worker.perform(pipeline_schedule.id, user.id)
- end
- end
end
end
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 f42033fdb9c..7c585542e30 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
@@ -38,16 +38,4 @@ RSpec.describe Users::MigrateRecordsToGhostUserInBatchesWorker do
expect(issue.last_edited_by).to eq(User.ghost)
end
end
-
- context 'when user_destroy_with_limited_execution_time_worker is disabled' do
- before do
- stub_feature_flags(user_destroy_with_limited_execution_time_worker: false)
- end
-
- it 'does not execute the service' do
- expect(Users::MigrateRecordsToGhostUserInBatchesService).not_to receive(:new)
-
- worker.perform
- end
- end
end
diff --git a/storybook/config/webpack.config.js b/storybook/config/webpack.config.js
index 51aaa1e18a6..a10ae0887ff 100644
--- a/storybook/config/webpack.config.js
+++ b/storybook/config/webpack.config.js
@@ -9,6 +9,12 @@ const IS_EE = require('../../config/helpers/is_ee_env');
const IS_JH = require('../../config/helpers/is_jh_env');
const gitlabWebpackConfig = require('../../config/webpack.config');
+const ROOT_PATH = path.resolve(__dirname, '..', '..');
+const EMPTY_VUE_COMPONENT_PATH = path.join(
+ ROOT_PATH,
+ 'app/assets/javascripts/vue_shared/components/empty_component.js',
+);
+
const buildIncludePaths = (nodeSassIncludePaths, previouslyResolvedPath) => {
const includePaths = [];
if (path.isAbsolute(previouslyResolvedPath)) {
@@ -144,6 +150,22 @@ module.exports = function storybookWebpackConfig({ config }) {
// Silence webpack warnings about moment/pikaday not being able to resolve.
config.plugins.push(new webpack.IgnorePlugin(/moment/, /pikaday/));
+ if (!IS_EE) {
+ config.plugins.push(
+ new webpack.NormalModuleReplacementPlugin(/^ee_component\/(.*)\.vue/, (resource) => {
+ resource.request = EMPTY_VUE_COMPONENT_PATH;
+ }),
+ );
+ }
+
+ if (!IS_JH) {
+ config.plugins.push(
+ new webpack.NormalModuleReplacementPlugin(/^jh_component\/(.*)\.vue/, (resource) => {
+ resource.request = EMPTY_VUE_COMPONENT_PATH;
+ }),
+ );
+ }
+
const baseIntegrationTestHelpersPath = 'spec/frontend_integration/test_helpers';
// Add any missing aliases from the main GitLab webpack config
diff --git a/tests.yml b/tests.yml
index c530ec30416..76ebb05eddb 100644
--- a/tests.yml
+++ b/tests.yml
@@ -75,3 +75,8 @@ mapping:
- source: ee/app/mailers/ee/preview/.+\.rb
test: spec/mailers/previews_spec.rb
+ ## GLFM spec and config files for CE and EE should map to respective markdown snapshot specs
+ - source: glfm_specification/.+
+ test: spec/requests/api/markdown_snapshot_spec.rb
+ - source: glfm_specification/.+
+ test: ee/spec/requests/api/markdown_snapshot_spec.rb
diff --git a/tooling/config/CODEOWNERS.yml b/tooling/config/CODEOWNERS.yml
index 0fb336f3857..ed712f18956 100644
--- a/tooling/config/CODEOWNERS.yml
+++ b/tooling/config/CODEOWNERS.yml
@@ -53,11 +53,14 @@
- '/app/finders/ci/auth_job_finder.rb'
- '/ee/config/metrics/'
- '/lib/gitlab/conan_token.rb'
+ - 'token_access/'
+ - 'pipelines/'
+ - 'ci/runner/'
patterns:
- '%{keyword}'
'[Compliance]':
- '@gitlab-org/manage/compliance':
+ '@gitlab-org/govern/compliance':
entries:
- '/ee/app/services/audit_events/build_service.rb'
- '/ee/spec/services/audit_events/custom_audit_event_service_spec.rb'
diff --git a/tooling/danger/project_helper.rb b/tooling/danger/project_helper.rb
index e98ae156246..a69d9049035 100644
--- a/tooling/danger/project_helper.rb
+++ b/tooling/danger/project_helper.rb
@@ -21,6 +21,10 @@ module Tooling
%r{\Aglfm_specification/.+prosemirror_json\.yml} => [:frontend],
%r{\Aglfm_specification/.+\.yml} => [:frontend, :backend],
+ # API auto generated doc files and schema (must come before generic docs regex)
+ %r{\Adoc/api/graphql/reference/} => [:docs, :backend],
+ %r{\Adoc/api/openapi/.*\.yaml\z} => [:docs, :backend],
+
[%r{usage_data\.rb}, %r{^(\+|-).*\s+(count|distinct_count|estimate_batch_distinct_count)\(.*\)(.*)$}] => [:database, :backend, :product_intelligence],
%r{\A((ee|jh)/)?config/feature_flags/} => :feature_flag,
@@ -166,9 +170,6 @@ module Tooling
%r{\A((ee|jh)/)?changelogs/} => :none,
%r{\Alocale/gitlab\.pot\z} => :none,
- # GraphQL auto generated doc files and schema
- %r{\Adoc/api/graphql/reference/} => :backend,
-
# Fallbacks in case the above patterns miss anything
%r{\.rb\z} => :backend,
%r{(
diff --git a/tooling/lib/tooling/helm3_client.rb b/tooling/lib/tooling/helm3_client.rb
index 82ebe3f51dc..d83dbeac76b 100644
--- a/tooling/lib/tooling/helm3_client.rb
+++ b/tooling/lib/tooling/helm3_client.rb
@@ -37,7 +37,6 @@ module Tooling
def delete(release_name:)
run_command([
'uninstall',
- %(--namespace "#{namespace}"),
release_name
])
end
@@ -60,7 +59,6 @@ module Tooling
def raw_releases(page, args = [])
command = [
'list',
- %(--namespace "#{namespace}"),
%(--max #{PAGINATION_SIZE}),
%(--offset #{PAGINATION_SIZE * page}),
%(--output json),
diff --git a/tooling/rspec_flaky/example.rb b/tooling/rspec_flaky/example.rb
index e6c2f838194..8f369c99c5b 100644
--- a/tooling/rspec_flaky/example.rb
+++ b/tooling/rspec_flaky/example.rb
@@ -38,13 +38,18 @@ module RspecFlaky
rspec_example.respond_to?(:attempts) ? rspec_example.attempts : 1
end
+ def feature_category
+ metadata[:feature_category]
+ end
+
def to_h
{
example_id: example_id,
file: file,
line: line,
description: description,
- last_attempts_count: attempts
+ last_attempts_count: attempts,
+ feature_category: feature_category
}
end
diff --git a/tooling/rspec_flaky/flaky_example.rb b/tooling/rspec_flaky/flaky_example.rb
index 299fcb567fc..3ce48ce1cd3 100644
--- a/tooling/rspec_flaky/flaky_example.rb
+++ b/tooling/rspec_flaky/flaky_example.rb
@@ -13,6 +13,7 @@ module RspecFlaky
last_flaky_job
last_attempts_count
flaky_reports
+ feature_category
].freeze
# This represents a flaky RSpec example and is mainly meant to be saved in a JSON file
@@ -23,7 +24,8 @@ module RspecFlaky
last_flaky_at: Time.now,
last_flaky_job: nil,
last_attempts_count: example_hash[:attempts],
- flaky_reports: 0
+ flaky_reports: 0,
+ feature_category: example_hash[:feature_category]
}.merge(example_hash.slice(*ALLOWED_ATTRIBUTES))
%i[first_flaky_at last_flaky_at].each do |attr|
@@ -31,11 +33,15 @@ module RspecFlaky
end
end
- def update_flakiness!(last_attempts_count: nil)
+ def update!(example_hash)
+ attributes[:file] = example_hash[:file]
+ attributes[:line] = example_hash[:line]
+ attributes[:description] = example_hash[:description]
attributes[:first_flaky_at] ||= Time.now
attributes[:last_flaky_at] = Time.now
attributes[:flaky_reports] += 1
- attributes[:last_attempts_count] = last_attempts_count if last_attempts_count
+ attributes[:feature_category] = example_hash[:feature_category]
+ attributes[:last_attempts_count] = example_hash[:last_attempts_count] if example_hash[:last_attempts_count]
if ENV['CI_JOB_URL']
attributes[:last_flaky_job] = "#{ENV['CI_JOB_URL']}"
diff --git a/tooling/rspec_flaky/listener.rb b/tooling/rspec_flaky/listener.rb
index 9b20eefc2f0..3431d814a8a 100644
--- a/tooling/rspec_flaky/listener.rb
+++ b/tooling/rspec_flaky/listener.rb
@@ -27,7 +27,7 @@ module RspecFlaky
return unless current_example.attempts > 1
flaky_example = suite_flaky_examples.fetch(current_example.uid) { RspecFlaky::FlakyExample.new(current_example.to_h) }
- flaky_example.update_flakiness!(last_attempts_count: current_example.attempts)
+ flaky_example.update!(current_example.to_h)
flaky_examples[current_example.uid] = flaky_example
end
diff --git a/vendor/gems/bundler-checksum/lib/bundler/checksum.rb b/vendor/gems/bundler-checksum/lib/bundler/checksum.rb
index c8d78eba111..40c42644964 100644
--- a/vendor/gems/bundler-checksum/lib/bundler/checksum.rb
+++ b/vendor/gems/bundler-checksum/lib/bundler/checksum.rb
@@ -19,7 +19,8 @@ module Bundler
cached_checksum = fetch_checksum_from_file(spec)
if cached_checksum.nil?
- raise SecurityError, "Cached checksum for #{spec.full_name} not found. Please (re-)generate Gemfile.checksum"
+ raise SecurityError, "Cached checksum for #{spec.full_name} not found. Please (re-)generate Gemfile.checksum with " \
+ "`bundle exec bundler-checksum init`. See https://docs.gitlab.com/ee/development/gemfile.html#updating-the-checksum-file."
end
validate_file_checksum(cached_checksum)
diff --git a/vendor/gems/ipynbdiff/lib/transformer.rb b/vendor/gems/ipynbdiff/lib/transformer.rb
index 1b2c63bb35c..9e666a20aa5 100644
--- a/vendor/gems/ipynbdiff/lib/transformer.rb
+++ b/vendor/gems/ipynbdiff/lib/transformer.rb
@@ -27,7 +27,7 @@ module IpynbDiff
def validate_notebook(notebook)
notebook_json = Oj::Parser.usual.parse(notebook)
- return notebook_json if notebook_json.key?('cells')
+ return notebook_json if notebook_json&.key?('cells')
raise InvalidNotebookError
rescue EncodingError, Oj::ParseError, JSON::ParserError
diff --git a/vendor/gems/ipynbdiff/spec/transformer_spec.rb b/vendor/gems/ipynbdiff/spec/transformer_spec.rb
index c5873906ca9..660d0a2bd79 100644
--- a/vendor/gems/ipynbdiff/spec/transformer_spec.rb
+++ b/vendor/gems/ipynbdiff/spec/transformer_spec.rb
@@ -102,5 +102,16 @@ describe IpynbDiff::Transformer do
end
end
end
+
+ context 'when notebook can not be parsed' do
+ it 'raises error' do
+ notebook = '{"cells":[]}'
+ allow(Oj::Parser.usual).to receive(:parse).and_return(nil)
+
+ expect do
+ IpynbDiff::Transformer.new.transform(notebook)
+ end.to raise_error(IpynbDiff::InvalidNotebookError)
+ end
+ end
end
end
diff --git a/vendor/project_templates/cluster_management.tar.gz b/vendor/project_templates/cluster_management.tar.gz
index b7c44a4770d..f36d7de462e 100644
--- a/vendor/project_templates/cluster_management.tar.gz
+++ b/vendor/project_templates/cluster_management.tar.gz
Binary files differ
diff --git a/workhorse/config.toml.example b/workhorse/config.toml.example
index 1457e20ed88..6cbd6ca5f74 100644
--- a/workhorse/config.toml.example
+++ b/workhorse/config.toml.example
@@ -7,16 +7,23 @@
URL = "unix:/home/git/gitlab/redis/redis.socket"
[object_storage]
- provider = "AWS" # Allowed options: AWS, AzureRM
+ provider = "AWS" # Allowed options: AWS, AzureRM, Google
[object_storage.s3]
aws_access_key_id = "YOUR AWS ACCESS KEY"
aws_secret_access_key = "YOUR AWS SECRET ACCESS KEY"
-[object_store.azurerm]
+[object_storage.azurerm]
azure_storage_account_name = "YOUR ACCOUNT NAME"
azure_storage_access_key = "YOUR ACCOUNT KEY"
+[object_storage.google]
+ google_application_default = true # if the application default should be used
+ google_json_key_string = '''
+ JSON KEY STRING
+ '''
+ google_json_key_location = "PATH TO JSON KEY FILE"
+
[image_resizer]
max_scaler_procs = 4 # Recommendation: CPUs / 2
max_filesize = 250000
diff --git a/workhorse/go.mod b/workhorse/go.mod
index ec78a85e413..51adab831c2 100644
--- a/workhorse/go.mod
+++ b/workhorse/go.mod
@@ -1,13 +1,13 @@
module gitlab.com/gitlab-org/gitlab/workhorse
-go 1.17
+go 1.18
require (
- github.com/Azure/azure-storage-blob-go v0.14.0
- github.com/BurntSushi/toml v1.2.0
+ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1
+ github.com/BurntSushi/toml v1.2.1
github.com/FZambia/sentinel v1.1.1
github.com/alecthomas/chroma/v2 v2.3.0
- github.com/aws/aws-sdk-go v1.44.116
+ github.com/aws/aws-sdk-go v1.44.136
github.com/disintegration/imaging v1.6.2
github.com/getsentry/raven-go v0.2.0
github.com/golang-jwt/jwt/v4 v4.4.2
@@ -17,22 +17,23 @@ require (
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-20220627085814-c3ac35da23b2
+ github.com/johannesboyne/gofakes3 v0.0.0-20221110173912-32fb85c5aed6
github.com/jpillora/backoff v1.0.0
github.com/mitchellh/copystructure v1.2.0
- github.com/prometheus/client_golang v1.13.0
+ github.com/prometheus/client_golang v1.14.0
github.com/rafaeljusto/redigomock/v3 v3.1.1
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.0
- gitlab.com/gitlab-org/gitaly/v15 v15.4.2
+ github.com/stretchr/testify v1.8.1
+ gitlab.com/gitlab-org/gitaly/v15 v15.5.1
gitlab.com/gitlab-org/golang-archive-zip v0.1.1
- gitlab.com/gitlab-org/labkit v1.16.0
- gocloud.dev v0.26.0
+ gitlab.com/gitlab-org/labkit v1.16.1
+ gocloud.dev v0.27.0
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
- golang.org/x/net v0.0.0-20220722155237-a158d28d115b
+ golang.org/x/net v0.1.0
+ golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c
golang.org/x/tools v0.1.12
google.golang.org/grpc v1.50.1
google.golang.org/protobuf v1.28.1
@@ -40,22 +41,23 @@ require (
)
require (
- cloud.google.com/go v0.100.2 // indirect
- cloud.google.com/go/compute v1.5.0 // indirect
- cloud.google.com/go/monitoring v1.4.0 // indirect
+ cloud.google.com/go v0.103.0 // indirect
+ cloud.google.com/go/compute v1.7.0 // indirect
+ cloud.google.com/go/iam v0.3.0 // indirect
+ cloud.google.com/go/monitoring v1.5.0 // indirect
cloud.google.com/go/profiler v0.1.0 // indirect
+ cloud.google.com/go/storage v1.24.0 // indirect
cloud.google.com/go/trace v1.2.0 // indirect
- contrib.go.opencensus.io/exporter/stackdriver v0.13.10 // indirect
- github.com/Azure/azure-pipeline-go v0.2.3 // indirect
+ contrib.go.opencensus.io/exporter/stackdriver v0.13.13 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/azcore v1.1.1 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0 // indirect
+ github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
- github.com/Azure/go-autorest/autorest v0.11.22 // indirect
- github.com/Azure/go-autorest/autorest/adal v0.9.17 // indirect
- github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
- github.com/Azure/go-autorest/logger v0.2.1 // indirect
- github.com/Azure/go-autorest/tracing v0.6.0 // indirect
+ github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
+ github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0 // 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.0 // indirect
+ github.com/Microsoft/go-winio v0.5.1 // indirect
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
github.com/beevik/ntp v0.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
@@ -67,30 +69,33 @@ require (
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/go-ole/go-ole v1.2.4 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
+ github.com/golang-jwt/jwt v3.2.1+incompatible // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
- github.com/google/go-cmp v0.5.8 // indirect
- github.com/google/pprof v0.0.0-20210804190019-f964ff605595 // indirect
+ github.com/google/go-cmp v0.5.9 // indirect
+ github.com/google/pprof v0.0.0-20220608213341-c488b8fa1db3 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/google/wire v0.5.0 // indirect
- github.com/googleapis/gax-go/v2 v2.2.0 // indirect
+ github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect
+ github.com/googleapis/gax-go/v2 v2.4.0 // indirect
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
github.com/hashicorp/yamux v0.1.1 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jtolds/gls v4.20.0+incompatible // indirect
- github.com/kr/text v0.2.0 // indirect
+ 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/mattn/go-ieproxy v0.0.6 // indirect
- github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
+ github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // 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
github.com/philhofer/fwd v1.1.1 // indirect
+ github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/prometheus/client_model v0.2.0 // indirect
+ github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect
+ github.com/prometheus/prometheus v0.37.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
@@ -105,15 +110,14 @@ require (
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/exp/typeparams v0.0.0-20220218215828-6cf2b201936e // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
- golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
- golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
- golang.org/x/text v0.3.8 // indirect
- golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
- golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
- google.golang.org/api v0.74.0 // indirect
+ golang.org/x/sys v0.1.0 // indirect
+ golang.org/x/text v0.4.0 // indirect
+ golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
+ golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
+ google.golang.org/api v0.91.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
- google.golang.org/genproto v0.0.0-20220401170504-314d38edb7de // indirect
+ google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78 // 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 67392ede877..bf0c7df390d 100644
--- a/workhorse/go.sum
+++ b/workhorse/go.sum
@@ -1,3 +1,5 @@
+bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
+bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM=
cloud.google.com/go v0.16.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
@@ -16,7 +18,6 @@ cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOY
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
-cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
@@ -31,8 +32,11 @@ cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW
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 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y=
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.103.0 h1:YXtxp9ymmZjlGzxV7VrYQ8aaQuAgcqxSy6YhDX4I458=
+cloud.google.com/go v0.103.0/go.mod h1:vwLx1nqLrzLX/fpwSMOXmFIqBOyHsvHbnAdbGSJ+mKk=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@@ -40,95 +44,108 @@ cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUM
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
-cloud.google.com/go/compute v1.2.0/go.mod h1:xlogom/6gr8RJGBe7nT2eGsQYAFUbbv8dbC29qE3Xmw=
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
-cloud.google.com/go/compute v1.5.0 h1:b1zWmYuuHz7gO9kDcM/EpHGr06UgsYNRpNJzI2kFiLM=
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
+cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
+cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
+cloud.google.com/go/compute v1.7.0 h1:v/k9Eueb8aAJ0vZuxKMrgm6kPhCLZU9HxFU+AFDs9Uk=
+cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
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/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/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c=
-cloud.google.com/go/iam v0.1.1/go.mod h1:CKqrcnI/suGpybEHxZ7BMehL0oA4LpdyJdUlTl9jVMw=
cloud.google.com/go/iam v0.3.0 h1:exkAomrVUuzx9kWFI1wm3KI0uoDeUFPB4kKGzx6x+Gc=
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
-cloud.google.com/go/kms v1.1.0/go.mod h1:WdbppnCDMDpOvoYBMn1+gNmOeEoZYqAv+HeuKARGCXI=
cloud.google.com/go/kms v1.4.0/go.mod h1:fajBHndQ+6ubNw6Ss2sSd+SWvjL26RNo/dr7uxsnnOA=
cloud.google.com/go/monitoring v1.1.0/go.mod h1:L81pzz7HKn14QCMaCs6NTQkdBnE87TElyanS95vIcl4=
-cloud.google.com/go/monitoring v1.4.0 h1:05+IuNMbh40hbxcqQ4SnynbwZbLG1Wc9dysIJxnfv7U=
-cloud.google.com/go/monitoring v1.4.0/go.mod h1:y6xnxfwI3hTFWOdkOaD7nfJVlwuC3/mS/5kvtT131p4=
+cloud.google.com/go/monitoring v1.5.0 h1:ZltYv8e69fJVga7RTthUBGdx4+Pwz6GRF1V3zylERl4=
+cloud.google.com/go/monitoring v1.5.0/go.mod h1:/o9y8NYX5j91JjD/JvGLYbi86kL11OjyJXq2XziLJu4=
cloud.google.com/go/profiler v0.1.0 h1:MG/rxKC1MztRfEWMGYKFISxyZak5hNh29f0A/z2tvWk=
cloud.google.com/go/profiler v0.1.0/go.mod h1:D7S7LV/zKbRWkOzYL1b5xytpqt8Ikd/v/yvf1/Tx2pQ=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
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.19.0/go.mod h1:/O9kmSe9bb9KRnIAWkzmqhPjHo6LtzGOBYd/kr06XSs=
-cloud.google.com/go/secretmanager v1.3.0/go.mod h1:+oLTkouyiYiabAQNugCeTS3PAArGiMJuBqvJnJsyH+U=
+cloud.google.com/go/pubsub v1.24.0/go.mod h1:rWv09Te1SsRpRGPiWOMDKraMQTJyJps4MkUCoMGUgqw=
+cloud.google.com/go/secretmanager v1.5.0/go.mod h1:5C9kM+RwSpkURNovKySkNvGQLUaOgyoR5W0RUx2SyHQ=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
-cloud.google.com/go/storage v1.21.0 h1:HwnT2u2D309SFDHQII6m18HlrCi3jAXhUMTLOWXYH14=
-cloud.google.com/go/storage v1.21.0/go.mod h1:XmRlxkgPjlBONznT2dDUU/5XlpU2OjMnKuqnZI01LAA=
-cloud.google.com/go/trace v0.1.0/go.mod h1:wxEwsoeRVPbeSkt7ZC9nWCgmoKQRAoySN7XHW2AmI7g=
+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.24.0 h1:a4N0gIkx83uoVFGz8B2eAV3OhN90QoWF5OZWLKl39ig=
+cloud.google.com/go/storage v1.24.0/go.mod h1:3xrJEFMXBsQLgxwThyjuD3aYlroL0TMRec1ypGUQ0KE=
cloud.google.com/go/trace v1.0.0/go.mod h1:4iErSByzxkyHWzzlAj63/Gmjz0NH1ASqhJguHpGcr6A=
cloud.google.com/go/trace v1.2.0 h1:oIaB4KahkIUOpLSAAjEJ8y2desbjY/x/RfP4O3KAtTI=
cloud.google.com/go/trace v1.2.0/go.mod h1:Wc8y/uYyOhPy12KEnXG9XGrvfMz5F5SrYecQlbW1rwM=
+code.cloudfoundry.org/clock v0.0.0-20180518195852-02e53af36e6c/go.mod h1:QD9Lzhd/ux6eNQVUDVRJX/RKTigpewimNYBi7ivZKY8=
contrib.go.opencensus.io/exporter/aws v0.0.0-20200617204711-c478e41e60e9/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA=
-contrib.go.opencensus.io/exporter/stackdriver v0.13.8/go.mod h1:huNtlWx75MwO7qMs0KrMxPZXzNNWebav1Sq/pm02JdQ=
-contrib.go.opencensus.io/exporter/stackdriver v0.13.10 h1:a9+GZPUe+ONKUwULjlEOucMMG0qfSCCenlji0Nhqbys=
-contrib.go.opencensus.io/exporter/stackdriver v0.13.10/go.mod h1:I5htMbyta491eUxufwwZPQdcKvvgzMB4O9ni41YnIM8=
+contrib.go.opencensus.io/exporter/stackdriver v0.13.13 h1:3KLhsPyyFp1pfZPicg8e1VMSeztIyWm+aE+iZQ8b9Kg=
+contrib.go.opencensus.io/exporter/stackdriver v0.13.13/go.mod h1:5pSSGY0Bhuk7waTHuDf4aQ8D2DrhgETRo9fy6k3Xlzc=
contrib.go.opencensus.io/integrations/ocsql v0.1.7/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
-github.com/Azure/azure-amqp-common-go/v3 v3.2.1/go.mod h1:O6X1iYHP7s2x7NjUKsXVhkwWrQhxrd+d8/3rRadj4CI=
-github.com/Azure/azure-amqp-common-go/v3 v3.2.2/go.mod h1:O6X1iYHP7s2x7NjUKsXVhkwWrQhxrd+d8/3rRadj4CI=
-github.com/Azure/azure-pipeline-go v0.2.3 h1:7U9HBg1JFK3jHl5qmo4CTZKFTVgMwdFHMVtCdfBE21U=
-github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
-github.com/Azure/azure-sdk-for-go v51.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go v59.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg=
+github.com/Azure/azure-amqp-common-go/v3 v3.2.3/go.mod h1:7rPmbSfszeovxGfc5fSAXE4ehlXQZHpMja2OtxC2Tas=
+github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/azure-sdk-for-go v63.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/azure-sdk-for-go v65.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+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 v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw=
+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 h1:tz19qLF65vuu2ibfTqGVJxG/zZAI27NEIIbvAOQwYbw=
+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/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0 h1:Yoicul8bnVdQrhDMTHxdEckRGX01XvwXDHUT9zYZ3k0=
+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/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8=
-github.com/Azure/azure-service-bus-go v0.11.5/go.mod h1:MI6ge2CuQWBVq+ly456MY7XqNLJip5LO1iSFodbNLbU=
-github.com/Azure/azure-storage-blob-go v0.14.0 h1:1BCg74AmVdYwO3dlKwtFU1V0wU2PZdREkXvAmZJRUlM=
-github.com/Azure/azure-storage-blob-go v0.14.0/go.mod h1:SMqIBi+SuiQH32bvyjngEewEeXoPfKMgWlBDaYf6fck=
-github.com/Azure/go-amqp v0.16.0/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg=
-github.com/Azure/go-amqp v0.16.4/go.mod h1:9YJ3RhxRT1gquYnzpZO1vcYMMpAdJT+QEg6fwmw9Zlg=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0 h1:jp0dGvZ7ZK0mgqnTSClMxa5xuRL7NZgHameVYF6BurY=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w=
+github.com/Azure/azure-sdk-for-go/sdk/messaging/azservicebus v1.0.2/go.mod h1:LH9XQnMr2ZYxQdVdCrzLO9mxeDyrDFa6wbSI3x5zCZk=
+github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1 h1:QSdcrd/UFJv6Bp/CfoVf2SrENpFn9P6Yh8yb+xNhYMM=
+github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.1/go.mod h1:eZ4g6GUvXiGulfIbbhh1Xr4XwUYaYaWMqzGD/284wCA=
+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-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=
+github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+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.19/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
-github.com/Azure/go-autorest/autorest v0.11.22 h1:bXiQwDjrRmBQOE67bwlvUKAC1EU1yZTPQ38c+bstZws=
-github.com/Azure/go-autorest/autorest v0.11.22/go.mod h1:BAWYUWGPEtKPzjVkp0Q6an0MJcJDsoh5Z1BFAEFs4Xs=
+github.com/Azure/go-autorest/autorest v0.11.24/go.mod h1:G6kyRlFnTuSbEYkQGawPfsCswgme4iYf6rfSKUDzbCc=
+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.14/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
-github.com/Azure/go-autorest/autorest/adal v0.9.17 h1:esOPl2dhcz9P3jqBSJ8tPGEj2EqzPPT6zfyuloiogKY=
-github.com/Azure/go-autorest/autorest/adal v0.9.17/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ=
-github.com/Azure/go-autorest/autorest/azure/auth v0.5.9 h1:Y2CgdzitFDsdMwYMzf9LIZWrrTFysqbRc7b94XVVJ78=
-github.com/Azure/go-autorest/autorest/azure/auth v0.5.9/go.mod h1:hg3/1yw0Bq87O3KvvnJoAh34/0zbP7SFizX/qN5JvjU=
-github.com/Azure/go-autorest/autorest/azure/cli v0.4.2 h1:dMOmEJfkLKW/7JsokJqkyoYSgmR08hi9KrhjZb+JALY=
-github.com/Azure/go-autorest/autorest/azure/cli v0.4.2/go.mod h1:7qkJkT+j6b+hIpzMOwPChJhTqS8VbsqqgULzMNRugoM=
-github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
+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/azure/auth v0.5.11/go.mod h1:84w/uV8E37feW2NCJ08uT9VBfjfUHpgLVnG2InYD6cg=
+github.com/Azure/go-autorest/autorest/azure/cli v0.4.5/go.mod h1:ADQAXrkgm7acgWVUNamOgh8YNrv4p27l3Wc55oVfpzg=
+github.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
-github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
+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=
+github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU=
+github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk=
github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=
github.com/Azure/go-autorest/autorest/validation v0.3.1/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
-github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg=
+github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
-github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
+github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0 h1:WVsrXCnHlDDX8ls+tootqRE87/hL9S/g4ewig9RsD/c=
+github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
-github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
-github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
+github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
+github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
-github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
-github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo=
+github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/datadog-go v4.4.0+incompatible h1:R7WqXWP4fIOAqWJtUKmSfuc7eDsBT58k9AY5WSHVosk=
github.com/DataDog/datadog-go v4.4.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
github.com/DataDog/gostackparse v0.5.0/go.mod h1:lTfqcJKqS9KnXQGnyQMCugq3u1FP6UZMfWR0aitKFMM=
@@ -136,122 +153,185 @@ 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.29.0/go.mod h1:spvB9eLJH9dutlbPSRmHvSXXHOwGRyeXh1jVdquA2G8=
+github.com/GoogleCloudPlatform/cloudsql-proxy v1.31.2/go.mod h1:qR6jVnZTKDCW3j+fC9mOEPHm++1nKDMkqbbkD6KNsfo=
github.com/HdrHistogram/hdrhistogram-go v1.1.1 h1:cJXY5VLMHgejurPjZH6Fo9rIwRGLefBGdiaENZALqrg=
-github.com/HdrHistogram/hdrhistogram-go v1.1.1/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
-github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
-github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
-github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
+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/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
+github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
+github.com/Microsoft/go-winio v0.4.16-0.20201130162521-d1ffc52c7331/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
-github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU=
-github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.4.17-0.20210211115548-6eac466e5fa3/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.4.17-0.20210324224401-5516f17a5958/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.4.17/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
+github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
+github.com/Microsoft/hcsshim v0.8.7-0.20190325164909-8abdbb8205e4/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
+github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ=
+github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg38RRsjT5y8=
+github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
+github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
+github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
+github.com/Microsoft/hcsshim v0.8.20/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
+github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
+github.com/Microsoft/hcsshim v0.8.23/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
+github.com/Microsoft/hcsshim v0.9.2/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc=
+github.com/Microsoft/hcsshim/test v0.0.0-20201218223536-d3e5debf77da/go.mod h1:5hlzMzRKMLyo42nCZ9oml8AdTlq/0cvIaBv6tK1RehU=
+github.com/Microsoft/hcsshim/test v0.0.0-20210227013316-43a75bb4edd3/go.mod h1:mw7qgWloBUl75W/gVH3cQszUg1+gUITj7D6NY7ywVnY=
+github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/ProtonMail/go-crypto v0.0.0-20220824120805-4b6e5c587895/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8=
-github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
+github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
+github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
+github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
-github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
-github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
-github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
+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/alecthomas/chroma/v2 v2.3.0 h1:83xfxrnjv8eK+Cf8qZDzNo3PPF9IbTWHs7z28GY6D0U=
github.com/alecthomas/chroma/v2 v2.3.0/go.mod h1:mZxeWZlxP2Dy+/8cBob2PYd8O2DwNAzave5AY7A2eQw=
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
-github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
-github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
+github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
+github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
+github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
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-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/avast/retry-go v2.4.2+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
-github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
+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.17.4/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
+github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go v1.38.35/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
+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.116 h1:NpLIhcvLWXJZAEwvPj3TDHeqp7DleK6ZUVYyW01WNHY=
-github.com/aws/aws-sdk-go v1.44.116/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
-github.com/aws/aws-sdk-go-v2 v1.16.2 h1:fqlCk6Iy3bnCumtrLz9r3mJ/2gUT0pJ0wLFVIdWh+JA=
-github.com/aws/aws-sdk-go-v2 v1.16.2/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1 h1:SdK4Ppk5IzLs64ZMvr6MrSficMtjY2oS0WOORXTlxwU=
-github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1/go.mod h1:n8Bs1ElDD2wJ9kCRTczA83gYbBmjSwZp3umc6zF4EeM=
-github.com/aws/aws-sdk-go-v2/config v1.15.3 h1:5AlQD0jhVXlGzwo+VORKiUuogkG7pQcLJNzIzK7eodw=
-github.com/aws/aws-sdk-go-v2/config v1.15.3/go.mod h1:9YL3v07Xc/ohTsxFXzan9ZpFpdTOFl4X65BAKYaz8jg=
-github.com/aws/aws-sdk-go-v2/credentials v1.11.2 h1:RQQ5fzclAKJyY5TvF+fkjJEwzK4hnxQCLOu5JXzDmQo=
-github.com/aws/aws-sdk-go-v2/credentials v1.11.2/go.mod h1:j8YsY9TXTm31k4eFhspiQicfXPLZ0gYXA50i4gxPE8g=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.3 h1:LWPg5zjHV9oz/myQr4wMs0gi4CjnDN/ILmyZUFYXZsU=
-github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.3/go.mod h1:uk1vhHHERfSVCUnqSqz8O48LBYDSC+k6brng09jcMOk=
-github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.3 h1:ir7iEq78s4txFGgwcLqD6q9IIPzTQNRJXulJd9h/zQo=
-github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.3/go.mod h1:0dHuD2HZZSiwfJSy1FO5bX1hQ1TxVV1QXXjpn3XUE44=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.9 h1:onz/VaaxZ7Z4V+WIN9Txly9XLTmoOh1oJ8XcAC3pako=
-github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.9/go.mod h1:AnVH5pvai0pAF4lXRq0bmhbes1u9R8wTE+g+183bZNM=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.3 h1:9stUQR/u2KXU6HkFJYlqnZEjBnbgrVbG6I5HN09xZh0=
-github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.3/go.mod h1:ssOhaLpRlh88H3UmEcsBoVKq309quMvm3Ds8e9d4eJM=
-github.com/aws/aws-sdk-go-v2/internal/ini v1.3.10 h1:by9P+oy3P/CwggN4ClnW2D4oL91QV7pBzBICi1chZvQ=
-github.com/aws/aws-sdk-go-v2/internal/ini v1.3.10/go.mod h1:8DcYQcz0+ZJaSxANlHIsbbi6S+zMwjwdDqwW3r9AzaE=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1 h1:T4pFel53bkHjL2mMo+4DKE6r6AuoZnM0fg7k1/ratr4=
-github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1/go.mod h1:GeUru+8VzrTXV/83XyMJ80KpH8xO89VPoUileyNQ+tc=
-github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.3 h1:I0dcwWitE752hVSMrsLCxqNQ+UdEp3nACx2bYNMQq+k=
-github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.3/go.mod h1:Seb8KNmD6kVTjwRjVEgOT5hPin6sq+v4C2ycJQDwuH8=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.3 h1:Gh1Gpyh01Yvn7ilO/b/hr01WgNpaszfbKMUgqM186xQ=
-github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.3/go.mod h1:wlY6SVjuwvh3TVRpTqdy4I1JpBFLX4UGeKZdWntaocw=
-github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.3 h1:BKjwCJPnANbkwQ8vzSbaZDKawwagDubrH/z/c0X+kbQ=
-github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.3/go.mod h1:Bm/v2IaN6rZ+Op7zX+bOUMdL4fsrYZiD0dsjLhNKwZc=
-github.com/aws/aws-sdk-go-v2/service/kms v1.16.3/go.mod h1:QuiHPBqlOFCi4LqdSskYYAWpQlx3PKmohy+rE2F+o5g=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.26.3 h1:rMPtwA7zzkSQZhhz9U3/SoIDz/NZ7Q+iRn4EIO8rSyU=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.26.3/go.mod h1:g1qvDuRsJY+XghsV6zg00Z4KJ7DtFFCx8fJD2a491Ak=
-github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.4/go.mod h1:PJc8s+lxyU8rrre0/4a0pn2wgwiDvOEzoOjcJUBr67o=
-github.com/aws/aws-sdk-go-v2/service/sns v1.17.4/go.mod h1:kElt+uCcXxcqFyc+bQqZPFD9DME/eC6oHBXvFzQ9Bcw=
-github.com/aws/aws-sdk-go-v2/service/sqs v1.18.3/go.mod h1:skmQo0UPvsjsuYYSYMVmrPc1HWCbHUJyrCEp+ZaLzqM=
-github.com/aws/aws-sdk-go-v2/service/ssm v1.24.1/go.mod h1:NR/xoKjdbRJ+qx0pMR4mI+N/H1I1ynHwXnO6FowXJc0=
-github.com/aws/aws-sdk-go-v2/service/sso v1.11.3 h1:frW4ikGcxfAEDfmQqWgMLp+F1n4nRo9sF39OcIb5BkQ=
-github.com/aws/aws-sdk-go-v2/service/sso v1.11.3/go.mod h1:7UQ/e69kU7LDPtY40OyoHYgRmgfGM4mgsLYtcObdveU=
-github.com/aws/aws-sdk-go-v2/service/sts v1.16.3 h1:cJGRyzCSVwZC7zZZ1xbx9m32UnrKydRYhOvcD1NYP9Q=
-github.com/aws/aws-sdk-go-v2/service/sts v1.16.3/go.mod h1:bfBj0iVmsUyUg4weDB4NxktD9rDGeKSVWnjTnwbx9b8=
-github.com/aws/smithy-go v1.11.2 h1:eG/N+CcUMAvsdffgMvjMKwfyDzIkjM6pfxMJ8Mzc6mE=
-github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM=
-github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
+github.com/aws/aws-sdk-go v1.44.45/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
+github.com/aws/aws-sdk-go v1.44.68/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
+github.com/aws/aws-sdk-go v1.44.136 h1:J1KJJssa8pjU8jETYUxwRS37KTcxjACfKd9GK8t+5ZU=
+github.com/aws/aws-sdk-go v1.44.136/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.16.8 h1:gOe9UPR98XSf7oEJCcojYg+N2/jCRm4DdeIsP85pIyQ=
+github.com/aws/aws-sdk-go-v2 v1.16.8/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3 h1:S/ZBwevQkr7gv5YxONYpGQxlMFFYSRfz3RMcjsC9Qhk=
+github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3/go.mod h1:gNsR5CaXKmQSSzrmGxmwmct/r+ZBfbxorAuXYsj/M5Y=
+github.com/aws/aws-sdk-go-v2/config v1.15.15 h1:yBV+J7Au5KZwOIrIYhYkTGJbifZPCkAnCFSvGsF3ui8=
+github.com/aws/aws-sdk-go-v2/config v1.15.15/go.mod h1:A1Lzyy/o21I5/s2FbyX5AevQfSVXpvvIDCoVFD0BC4E=
+github.com/aws/aws-sdk-go-v2/credentials v1.12.10 h1:7gGcMQePejwiKoDWjB9cWnpfVdnz/e5JwJFuT6OrroI=
+github.com/aws/aws-sdk-go-v2/credentials v1.12.10/go.mod h1:g5eIM5XRs/OzIIK81QMBl+dAuDyoLN0VYaLP+tBqEOk=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.9 h1:hz8tc+OW17YqxyFFPSkvfSikbqWcyyHRyPVSTzC0+aI=
+github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.9/go.mod h1:KDCCm4ONIdHtUloDcFvK2+vshZvx4Zmj7UMDfusuz5s=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.21 h1:bpiKFJ9aC0xTVpygSRRRL/YHC1JZ+pHQHENATHuoiwo=
+github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.21/go.mod h1:iIYPrQ2rYfZiB/iADYlhj9HHZ9TTi6PqKQPAqygohbE=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.15 h1:bx5F2mr6H6FC7zNIQoDoUr8wEKnvmwRncujT3FYRtic=
+github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.15/go.mod h1:pWrr2OoHlT7M/Pd2y4HV3gJyPb3qj5qMmnPkKSNPYK4=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.9 h1:5sbyznZC2TeFpa4fvtpvpcGbzeXEEs1l1Jo51ynUNsQ=
+github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.9/go.mod h1:08tUpeSGN33QKSO7fwxXczNfiwCpbj+GxK6XKwqWVv0=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.3.16 h1:f0ySVcmQhwmzn7zQozd8wBM3yuGBfzdpsOaKQ0/Epzw=
+github.com/aws/aws-sdk-go-v2/internal/ini v1.3.16/go.mod h1:CYmI+7x03jjJih8kBEEFKRQc40UjUokT0k7GbvrhhTc=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.6 h1:3L8pcjvgaSOs0zzZcMKzxDSkYKEpwJ2dNVDdxm68jAY=
+github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.6/go.mod h1:O7Oc4peGZDEKlddivslfYFvAbgzvl/GH3J8j3JIGBXc=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.3 h1:4n4KCtv5SUoT5Er5XV41huuzrCqepxlW3SDI9qHQebc=
+github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.3/go.mod h1:gkb2qADY+OHaGLKNTYxMaQNacfeyQpZ4csDTQMeFmcw=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.10 h1:7LJcuRalaLw+GYQTMGmVUl4opg2HrDZkvn/L3KvIQfw=
+github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.10/go.mod h1:Qks+dxK3O+Z2deAhNo6cJ8ls1bam3tUGUAcgxQP1c70=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.9 h1:sHfDuhbOuuWSIAEDd3pma6p0JgUcR2iePxtCE8gfCxQ=
+github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.9/go.mod h1:yQowTpvdZkFVuHrLBXmczat4W+WJKg/PafBZnGBLga0=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.9 h1:sJdKvydGYDML9LTFcp6qq6Z5fIjN0Rdq2Gvw1hUg8tc=
+github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.9/go.mod h1:Rc5+wn2k8gFSi3V1Ch4mhxOzjMh+bYSXVFfVaqowQOY=
+github.com/aws/aws-sdk-go-v2/service/kms v1.18.1/go.mod h1:4PZMUkc9rXHWGVB5J9vKaZy3D7Nai79ORworQ3ASMiM=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.27.2 h1:NvzGue25jKnuAsh6yQ+TZ4ResMcnp49AWgWGm2L4b5o=
+github.com/aws/aws-sdk-go-v2/service/s3 v1.27.2/go.mod h1:u+566cosFI+d+motIz3USXEh6sN8Nq4GrNXSg2RXVMo=
+github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.14/go.mod h1:xakbH8KMsQQKqzX87uyyzTHshc/0/Df8bsTneTS5pFU=
+github.com/aws/aws-sdk-go-v2/service/sns v1.17.10/go.mod h1:uITsRNVMeCB3MkWpXxXw0eDz8pW4TYLzj+eyQtbhSxM=
+github.com/aws/aws-sdk-go-v2/service/sqs v1.19.1/go.mod h1:A94o564Gj+Yn+7QO1eLFeI7UVv3riy/YBFOfICVqFvU=
+github.com/aws/aws-sdk-go-v2/service/ssm v1.27.6/go.mod h1:fiFzQgj4xNOg4/wqmAiPvzgDMXPD+cUEplX/CYn+0j0=
+github.com/aws/aws-sdk-go-v2/service/sso v1.11.13 h1:DQpf+al+aWozOEmVEdml67qkVZ6vdtGUi71BZZWw40k=
+github.com/aws/aws-sdk-go-v2/service/sso v1.11.13/go.mod h1:d7ptRksDDgvXaUvxyHZ9SYh+iMDymm94JbVcgvSYSzU=
+github.com/aws/aws-sdk-go-v2/service/sts v1.16.10 h1:7tquJrhjYz2EsCBvA9VTl+sBAAh1bv7h/sGASdZOGGo=
+github.com/aws/aws-sdk-go-v2/service/sts v1.16.10/go.mod h1:cftkHYN6tCDNfkSasAmclSfl4l7cySoay8vz7p/ce0E=
+github.com/aws/smithy-go v1.12.0 h1:gXpeZel/jPoWQ7OEmLIgCUnhkFftqNfwWUwAHSlp1v0=
+github.com/aws/smithy-go v1.12.0/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/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=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
+github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
+github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
+github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
+github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/bradfitz/gomemcache v0.0.0-20170208213004-1952afaa557d/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
-github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
+github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
+github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
+github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
+github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
+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/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/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.3.0 h1:t/LhUZLVitR1Ow2YOnduCsavhwFUklBMoGVYUCqmCqk=
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
+github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s=
github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
-github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
+github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
+github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/cilium/ebpf v0.0.0-20200110133405-4032b1d8aae3/go.mod h1:MA5e5Lr8slmEg9bt0VpxxWqJlO4iwu3FBdHUzV7wQVg=
+github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLIdUjrmSXlK9pkrsDlLHbO8jiB8X8JnOc=
+github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
+github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
+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/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=
-github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
github.com/cloudflare/tableflip v1.2.3 h1:8I+B99QnnEWPHOY3fWipwVKxS70LGgUsslG7CSfmHMw=
-github.com/cloudflare/tableflip v1.2.3/go.mod h1:P4gRehmV6Z2bY5ao5ml9Pd8u6kuEnlB37pUFMmv7j2E=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
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=
@@ -261,46 +341,189 @@ github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWH
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/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
-github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
-github.com/containerd/cgroups v1.0.4/go.mod h1:nLNQtsF7Sl2HxNebu77i1R0oDlhiTG+kO4JTrUzo6IA=
+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=
+github.com/containerd/aufs v1.0.0/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU=
+github.com/containerd/btrfs v0.0.0-20201111183144-404b9149801e/go.mod h1:jg2QkJcsabfHugurUvvPhS3E08Oxiuh5W/g1ybB4e0E=
+github.com/containerd/btrfs v0.0.0-20210316141732-918d888fb676/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss=
+github.com/containerd/btrfs v1.0.0/go.mod h1:zMcX3qkXTAi9GI50+0HOeuV8LU2ryCE/V2vG/ZBiTss=
+github.com/containerd/cgroups v0.0.0-20190717030353-c4b9ac5c7601/go.mod h1:X9rLEHIqSf/wfK8NsPqxJmeZgW4pcfzdXITDrUSJ6uI=
+github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
+github.com/containerd/cgroups v0.0.0-20200531161412-0dbf7f05ba59/go.mod h1:pA0z1pT8KYB3TCXK/ocprsh7MAkoW8bZVzPdih9snmM=
+github.com/containerd/cgroups v0.0.0-20200710171044-318312a37340/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
+github.com/containerd/cgroups v0.0.0-20200824123100-0b889c03f102/go.mod h1:s5q4SojHctfxANBDvMeIaIovkq29IP48TKAxnhYRxvo=
+github.com/containerd/cgroups v0.0.0-20210114181951-8a68de567b68/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE=
+github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU=
+github.com/containerd/cgroups v1.0.3/go.mod h1:/ofk34relqNjSGyqPrmEULrO4Sc8LJhvJmWbUCUKqj8=
+github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
+github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
+github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
+github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
+github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=
+github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
+github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.1-0.20191213020239-082f7e3aed57/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.3.2/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.0-beta.2.0.20200729163537-40b22ef07410/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.1/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.3/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.4.9/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/containerd/containerd v1.5.0-beta.1/go.mod h1:5HfvG1V2FsKesEGQ17k5/T7V960Tmcumvqn8Mc+pCYQ=
+github.com/containerd/containerd v1.5.0-beta.3/go.mod h1:/wr9AVtEM7x9c+n0+stptlo/uBBoBORwEx6ardVcmKU=
+github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09ZvgqEq8EfBp/m3lcVZIvPHhI=
+github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
+github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
+github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
+github.com/containerd/containerd v1.5.8/go.mod h1:YdFSv5bTFLpG2HIYmfqDpSYYTDX+mc5qtSuYx1YUb/s=
+github.com/containerd/containerd v1.6.1/go.mod h1:1nJz5xCZPusx6jJU8Frfct988y0NpumIq9ODB0kLtoE=
+github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/containerd/continuity v0.0.0-20190815185530-f2a389ac0a02/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/containerd/continuity v0.0.0-20191127005431-f65d91d395eb/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
+github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe/go.mod h1:cECdGN1O8G9bgKTlLhuPJimka6Xb/Gg7vYzCTNVxhvo=
+github.com/containerd/continuity v0.0.0-20201208142359-180525291bb7/go.mod h1:kR3BEg7bDFaEddKm54WSmrol1fKWDU1nKYkgrcgZT7Y=
+github.com/containerd/continuity v0.0.0-20210208174643-50096c924a4e/go.mod h1:EXlVlkqNba9rJe3j7w3Xa924itAMLgZH4UD/Q4PExuQ=
+github.com/containerd/continuity v0.1.0/go.mod h1:ICJu0PwR54nI0yPEnJ6jcS+J7CZAUXrLh8lPo2knzsM=
+github.com/containerd/continuity v0.2.2/go.mod h1:pWygW9u7LtS1o4N/Tn0FoCFDIXZ7rxcMX7HX1Dmibvk=
+github.com/containerd/fifo v0.0.0-20180307165137-3d5202aec260/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
+github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv3Kuk8dQz2ZQXpnv/UZZUHUCL7pnLehbXgQI=
+github.com/containerd/fifo v0.0.0-20200410184934-f15a3290365b/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
+github.com/containerd/fifo v0.0.0-20201026212402-0724c46b320c/go.mod h1:jPQ2IAeZRCYxpS/Cm1495vGFww6ecHmMk1YJH2Q5ln0=
+github.com/containerd/fifo v0.0.0-20210316144830-115abcc95a1d/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
+github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4=
+github.com/containerd/go-cni v1.0.1/go.mod h1:+vUpYxKvAF72G9i1WoDOiPGRtQpqsNW/ZHtSlv++smU=
+github.com/containerd/go-cni v1.0.2/go.mod h1:nrNABBHzu0ZwCug9Ije8hL2xBCYh/pjfMb1aZGrrohk=
+github.com/containerd/go-cni v1.1.0/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA=
+github.com/containerd/go-cni v1.1.3/go.mod h1:Rflh2EJ/++BA2/vY5ao3K6WJRR/bZKsX123aPk+kUtA=
+github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
+github.com/containerd/go-runc v0.0.0-20190911050354-e029b79d8cda/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0=
+github.com/containerd/go-runc v0.0.0-20200220073739-7016d3ce2328/go.mod h1:PpyHrqVs8FTi9vpyHwPwiNEGaACDxT/N/pLcvMSRA9g=
+github.com/containerd/go-runc v0.0.0-20201020171139-16b287bc67d0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok=
+github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok=
+github.com/containerd/imgcrypt v1.0.1/go.mod h1:mdd8cEPW7TPgNG4FpuP3sGBiQ7Yi/zak9TYCG3juvb0=
+github.com/containerd/imgcrypt v1.0.4-0.20210301171431-0ae5c75f59ba/go.mod h1:6TNsg0ctmizkrOgXRNQjAPFWpMYRWuiB6dSF4Pfa5SA=
+github.com/containerd/imgcrypt v1.1.1-0.20210312161619-7ed62a527887/go.mod h1:5AZJNI6sLHJljKuI9IHnw1pWqo/F0nGDOuR9zgTs7ow=
+github.com/containerd/imgcrypt v1.1.1/go.mod h1:xpLnwiQmEUJPvQoAapeb2SNCxz7Xr6PJrXQb0Dpc4ms=
+github.com/containerd/imgcrypt v1.1.3/go.mod h1:/TPA1GIDXMzbj01yd8pIbQiLdQxed5ue1wb8bP7PQu4=
+github.com/containerd/nri v0.0.0-20201007170849-eb1350a75164/go.mod h1:+2wGSDGFYfE5+So4M5syatU0N0f0LbWpuqyMi4/BE8c=
+github.com/containerd/nri v0.0.0-20210316161719-dbaa18c31c14/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
+github.com/containerd/nri v0.1.0/go.mod h1:lmxnXF6oMkbqs39FiCt1s0R2HSMhcLel9vNL3m4AaeY=
+github.com/containerd/stargz-snapshotter/estargz v0.4.1/go.mod h1:x7Q9dg9QYb4+ELgxmo4gBUeJB0tl5dqH1Sdz0nJU1QM=
+github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
+github.com/containerd/ttrpc v0.0.0-20190828172938-92c8520ef9f8/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o=
+github.com/containerd/ttrpc v0.0.0-20191028202541-4f1b8fe65a5c/go.mod h1:LPm1u0xBw8r8NOKoOdNMeVHSawSsltak+Ihv+etqsE8=
+github.com/containerd/ttrpc v1.0.1/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
+github.com/containerd/ttrpc v1.0.2/go.mod h1:UAxOpgT9ziI0gJrmKvgcZivgxOp8iFPSk8httJEt98Y=
+github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ=
+github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc=
+github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk=
+github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg=
+github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s=
+github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw=
+github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y=
+github.com/containerd/zfs v0.0.0-20210315114300-dde8f0fda960/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
+github.com/containerd/zfs v0.0.0-20210324211415-d5c4544f0433/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
+github.com/containerd/zfs v1.0.0/go.mod h1:m+m51S1DvAP6r3FcmYCp54bQ34pyOwTieQDNRIRHsFY=
+github.com/containernetworking/cni v0.7.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/cni v0.8.0/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/cni v0.8.1/go.mod h1:LGwApLUm2FpoOfxTDEeq8T9ipbpZ61X79hmU3w8FmsY=
+github.com/containernetworking/cni v1.0.1/go.mod h1:AKuhXbN5EzmD4yTNtfSsX3tPcmtrBI6QcRV0NiNt15Y=
+github.com/containernetworking/plugins v0.8.6/go.mod h1:qnw5mN19D8fIwkqW7oHHYDHVlzhJpcY6TQxn/fUyDDM=
+github.com/containernetworking/plugins v0.9.1/go.mod h1:xP/idU2ldlzN6m4p5LmGiwRDjeJr6FLK6vuiUwoH7P8=
+github.com/containernetworking/plugins v1.0.1/go.mod h1:QHCfGpaTwYTbbH+nZXKVTxNBDZcxSOplJT5ico8/FLE=
+github.com/containers/ocicrypt v1.0.1/go.mod h1:MeJDzk1RJHv89LjsH0Sp5KTY3ZYkjXO/C+bKAeWFIrc=
+github.com/containers/ocicrypt v1.1.0/go.mod h1:b8AOe0YR67uU8OqfVNcznfFpAzu3rdgUV4GP9qXPfu4=
+github.com/containers/ocicrypt v1.1.1/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
+github.com/containers/ocicrypt v1.1.2/go.mod h1:Dm55fwWm1YZAjYRaJ94z2mfZikIyIN4B0oB3dj3jFxY=
+github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-iptables v0.4.5/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
+github.com/coreos/go-iptables v0.5.0/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
+github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
+github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20161114122254-48702e0da86b/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd/v22 v22.0.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
+github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
+github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
+github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
+github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
+github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
+github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
+github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
-github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU=
+github.com/denisenkom/go-mssqldb v0.12.2/go.mod h1:lnIw1mZukFRZDJYQ0Pb833QS2IaC3l5HkEfra2LJ+sk=
+github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA=
+github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0=
github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY=
-github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
-github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
-github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc/go.mod h1:c9O8+fpSOX1DM8cPNSkX/qsBWdkD4yd2dpciOWQjpBw=
-github.com/dgryski/go-minhash v0.0.0-20170608043002-7fe510aff544/go.mod h1:VBi0XHpFy0xiMySf6YpVbRqrupW4RprJ5QTyN+XvGSM=
-github.com/dgryski/go-spooky v0.0.0-20170606183049-ed3d087f40e2/go.mod h1:hgHYKsoIw7S/hlWtP7wD1wZ7SX1jPTtKko5X9jrOgPQ=
-github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
-github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
+github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dgryski/go-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.81.0/go.mod h1:BPCqvwbjbGqxuUnIKB4EvS/AX7IDnNmt5fwvIkWo+ew=
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
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=
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
+github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
+github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
+github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
+github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+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/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.17+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=
+github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
+github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI=
+github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
+github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/dpotapov/go-spnego v0.0.0-20210315154721-298b63a54430/go.mod h1:AVSs/gZKt1bOd2AhkhbS7Qh56Hv7klde22yXVbwYJhc=
-github.com/dpotapov/go-spnego v0.0.0-20220426193508-b7f82e4507db/go.mod h1:AVSs/gZKt1bOd2AhkhbS7Qh56Hv7klde22yXVbwYJhc=
+github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
+github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
+github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
-github.com/ekzhu/minhash-lsh v0.0.0-20171225071031-5c06ee8586a1/go.mod h1:yEtCVi+QamvzjEH4U/m6ZGkALIkF2xfQnFp0BcKmIOk=
-github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
+github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
+github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
+github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
+github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
+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/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
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=
@@ -309,96 +532,170 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
+github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
+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/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
+github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
+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/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
-github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
-github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
+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.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/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/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/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 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
+github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
+github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
+github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/garyburd/redigo v1.1.1-0.20170914051019-70e1b1943d4f/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
-github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
+github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
-github.com/getsentry/sentry-go v0.13.0/go.mod h1:EOsfu5ZdvKPfeHYV6pTVQnsjfp30+XA7//UooKNumH0=
+github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
-github.com/gin-gonic/gin v1.7.3/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
-github.com/git-lfs/git-lfs/v3 v3.2.0/go.mod h1:GZZO3jw2Yn3/1KFV4nRoXUzH+yPzGypIdTeQpkzxEvQ=
-github.com/git-lfs/gitobj/v2 v2.1.0/go.mod h1:q6aqxl6Uu3gWsip5GEKpw+7459F97er8COmU45ncAxw=
-github.com/git-lfs/go-netrc v0.0.0-20210914205454-f0c862dd687a/go.mod h1:70O4NAtvWn1jW8V8V+OKrJJYcxDLTmIozfi2fmSz5SI=
-github.com/git-lfs/pktline v0.0.0-20210330133718-06e9096e2825/go.mod h1:fenKRzpXDjNpsIBhuhUzvjCKlDjKam0boRAenTE0Q6A=
-github.com/git-lfs/wildmatch/v2 v2.0.1/go.mod h1:EVqonpk9mXbREP3N8UkwoWdrF249uHpCUo5CPXY81gw=
-github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
-github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
-github.com/go-enry/go-enry/v2 v2.8.2/go.mod h1:GVzIiAytiS5uT/QiuakK7TF1u4xDab87Y8V5EJRpsIQ=
-github.com/go-enry/go-license-detector/v4 v4.3.0/go.mod h1:HaM4wdNxSlz/9Gw0uVOKSQS5JVFqf2Pk8xUPEn6bldI=
-github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4=
-github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
-github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
-github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
-github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
-github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
-github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
-github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM=
-github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
-github.com/go-gorp/gorp/v3 v3.0.2/go.mod h1:BJ3q1ejpV8cVALtcXvXaXyTOlMmJhWDxTmncaR6rwBY=
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/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=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
-github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
+github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
+github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
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/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/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=
+github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
+github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
+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/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g=
+github.com/go-openapi/runtime v0.23.1/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk=
+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/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=
+github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
+github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+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/validate v0.21.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-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
-github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+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.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
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/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs=
-github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY=
-github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc=
+github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/go-zookeeper/zk v1.0.2/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
+github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0=
+github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY=
+github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg=
+github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
+github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
+github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs=
+github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
+github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI=
+github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk=
+github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28=
+github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo=
+github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk=
+github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw=
+github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360=
+github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg=
+github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE=
+github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8=
+github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
+github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc=
+github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
+github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4=
+github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ=
+github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0=
+github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
+github.com/goccy/go-yaml v1.9.5/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA=
+github.com/godbus/dbus v0.0.0-20151105175453-c7fdd8b5cd55/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
+github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
+github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
+github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
-github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE=
+github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+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/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=
+github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
-github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
-github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
+github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c=
+github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
-github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
github.com/golang-jwt/jwt/v4 v4.4.2/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.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8=
-github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
+github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
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=
+github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -434,13 +731,17 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx
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/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=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
+github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.8.8/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
+github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
github.com/google/go-cmp v0.1.1-0.20171103154506-982329095285/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@@ -455,14 +756,18 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
-github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/go-replayers/grpcreplay v1.1.0 h1:S5+I3zYyZ+GQz68OfbURDdt/+cSMqCK1wrvNx7WBzTE=
github.com/google/go-replayers/grpcreplay v1.1.0/go.mod h1:qzAvJ8/wi57zq7gWqaE6AwLM6miiXUQwP1S+I9icmhk=
github.com/google/go-replayers/httpreplay v1.1.1 h1:H91sIMlt1NZzN7R+/ASswyouLJfW0WLW7fhyUFvDEkY=
github.com/google/go-replayers/httpreplay v1.1.1/go.mod h1:gN9GeLIs7l6NUoVaSSnv2RiqK1NiwAmD0MrKeC9IIks=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@@ -482,7 +787,6 @@ github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210125172800-10e9aeb4a998/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
@@ -490,54 +794,101 @@ github.com/google/pprof v0.0.0-20210506205249-923b5ab0fc1a/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20210804190019-f964ff605595 h1:uNrRgpnKjTfxu4qHaZAAs3eKTYV1EzGF3dAykpnxgDE=
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-20220608213341-c488b8fa1db3 h1:mpL/HvfIgIejhVwAfxBQkwEjlhP5o0O9RAeTAjpwzxc=
+github.com/google/pprof v0.0.0-20220608213341-c488b8fa1db3/go.mod h1:gSuNB+gJaOiQKLEZ+q+PK9Mq3SOzhRcw2GsGS/FhYDk=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
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=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU=
+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 h1:zO8WHNx/MYiAKJ3d5spxZXZE6KHmIQGQcAzwUzV7qQw=
+github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
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=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
-github.com/googleapis/gax-go/v2 v2.2.0 h1:s7jOdKSaksJVOxE0Y/S32otcfiP+UQ0cL8/GTKaONwE=
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
+github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
+github.com/googleapis/gax-go/v2 v2.4.0 h1:dS9eYAjhrE2RjmzYw2XAPvcXfmcQLtFEQWn0CR82awk=
+github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
+github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
+github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
+github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
+github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
+github.com/gophercloud/gophercloud v0.24.0/go.mod h1:Q8fZtyi5zZxPS/j9aj3sSxtvj41AdQMDwyo1myduD5c=
+github.com/gophercloud/gophercloud v0.25.0/go.mod h1:Q8fZtyi5zZxPS/j9aj3sSxtvj41AdQMDwyo1myduD5c=
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/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/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+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/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=
+github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
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/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=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw=
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.10.2/go.mod h1:chrfS3YoLAlKTRE5cFWvCbt8uGAjshktT4PveTUpsFQ=
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/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.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0=
+github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ=
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/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=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
+github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
+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-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-msgpack v0.5.3/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=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
+github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
+github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
+github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
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-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/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=
@@ -547,27 +898,36 @@ github.com/hashicorp/hcl v0.0.0-20170914154624-68e816d1c783/go.mod h1:oZtUIOe8dh
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.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
+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-20220629141207-c2428e1673ec/go.mod h1:jP79oXjopTyH6E8LF0CEMq67STgrlmBRIyijA0tuR5o=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
+github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
-github.com/hhatto/gorst v0.0.0-20181029133204-ca9f730cac5b/go.mod h1:HmaZGXHdSwQh1jnUlBGN2BeEYOHACLVGzYOXCbsLvxY=
-github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/hetznercloud/hcloud-go v1.33.1/go.mod h1:XX/TQub3ge0yWR2yHWmnDVIrB+MQbda1pHxkUmDlUME=
+github.com/hetznercloud/hcloud-go v1.35.0/go.mod h1:mepQwR6va27S3UQthaEPGS86jtzSY9xWL1e9dyxXpgA=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
+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=
-github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
+github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
+github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
-github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
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/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
-github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
-github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk=
-github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
-github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
+github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/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.0/go.mod h1:Ox3W0iiEz0GHnfY9e5LmAxwklsxguuNFEUSu0gVRTME=
+github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
+github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
@@ -577,8 +937,7 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU
github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o=
github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY=
github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
-github.com/jackc/pgconn v1.11.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI=
-github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI=
+github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
@@ -591,151 +950,155 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
-github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
-github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
+github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM=
-github.com/jackc/pgtype v1.10.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
-github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
+github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs=
-github.com/jackc/pgx/v4 v4.15.0/go.mod h1:D/zyOyXiaM1TmVWnOM18p0xdDtdakRBa0RsVGI3U3bw=
-github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw=
+github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
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.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
-github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
-github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
-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/jdkato/prose v1.1.0/go.mod h1:jkF0lkxaX5PFSlk9l4Gh9Y+T57TqUZziWT7uZbW5ADg=
-github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
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.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/johannesboyne/gofakes3 v0.0.0-20220627085814-c3ac35da23b2 h1:V5q1Mx2WTE5coXLG2QpkRZ7LsJvgkedm6Ib4AwC1Lfg=
-github.com/johannesboyne/gofakes3 v0.0.0-20220627085814-c3ac35da23b2/go.mod h1:LIAXxPvcUXwOcTIj9LSNSUpE9/eMHalTWxsP/kmWxQI=
+github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
+github.com/johannesboyne/gofakes3 v0.0.0-20221110173912-32fb85c5aed6 h1:eQGUsj2LcsLzfrHY1noKDSU7h+c9/rw9pQPwbQ9g1jQ=
+github.com/johannesboyne/gofakes3 v0.0.0-20221110173912-32fb85c5aed6/go.mod h1:LIAXxPvcUXwOcTIj9LSNSUpE9/eMHalTWxsP/kmWxQI=
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=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
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=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
-github.com/jteeuwen/go-bindata v3.0.8-0.20180305030458-6025e8de665b+incompatible/go.mod h1:JVvhzYOiGBnFSYRyV00iY8q7/0PThjIYav1p9h5dmKs=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
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.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
-github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8=
-github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE=
-github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
-github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro=
-github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
-github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
-github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
-github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+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=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
-github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
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.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
+github.com/kolo/xmlrpc v0.0.0-20201022064351-38db28db192b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kortschak/utter v1.0.1/go.mod h1:vSmSjbyrlKjjsL71193LmzBOKgwePk9DH6uFaWHIInc=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
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 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
+github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
-github.com/labstack/echo/v4 v4.5.0/go.mod h1:czIriw4a0C1dFun+ObrXp7ok03xON0N1awStJ6ArI7Y=
-github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
-github.com/leonelquinteros/gotext v1.5.0/go.mod h1:OCiUVHuhP9LGFBQ1oAmdtNCHJCiHiQA8lf4nAifHkr0=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
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.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/libgit2/git2go/v33 v33.0.9/go.mod h1:KdpqkU+6+++4oHna/MIOgx4GCQ92IPCdpVRMRI80J+4=
+github.com/lib/pq v1.10.6/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.8.0/go.mod h1:heqhl91D8QTPVm2k9qZHP78zzbOdTFLXE9NJc3bcc50=
+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-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.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
-github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc=
-github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI=
+github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+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=
+github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
+github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
+github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.0.10-0.20170816031813-ad5389df28cd/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
-github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
-github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
-github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
-github.com/mattn/go-ieproxy v0.0.3/go.mod h1:6ZpRmhBaYuBX1U2za+9rC9iCGLsSp2tftelZne7CPko=
-github.com/mattn/go-ieproxy v0.0.6 h1:tVDlituRyeHMMkHpGpUu8CJG+hxPMwbYCkIUK2PUCbo=
-github.com/mattn/go-ieproxy v0.0.6/go.mod h1:6ZpRmhBaYuBX1U2za+9rC9iCGLsSp2tftelZne7CPko=
+github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.2/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
+github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
+github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
-github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI=
-github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
-github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
-github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
-github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
+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/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
+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/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/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.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
+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/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.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4=
-github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
+github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
+github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
@@ -744,121 +1107,254 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh
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.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
-github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc=
+github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
+github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
+github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
+github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
+github.com/moby/sys/signal v0.6.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg=
+github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
+github.com/moby/sys/symlink v0.2.0/go.mod h1:7uZVF2dqJjG/NsClqul95CqKOBRQyYSNnJ6BMgR/gFs=
+github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
+github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
+github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
-github.com/montanaflynn/stats v0.0.0-20151014174947-eeaced052adb/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
-github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
+github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
+github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
+github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
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/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
-github.com/neurosnap/sentences v1.0.6/go.mod h1:pg1IapvYpWCJJm/Etxeh0+gtMf1rI1STY9S7eUCPbDc=
+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=
github.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOEiwQ68=
-github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
-github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0/go.mod h1:F/7q8/HZz+TXjlsoZQQKVYvXTZaFH4QRa3y+j1p7MS0=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY=
+github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
+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.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+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=
-github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
+github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+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.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
+github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
+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=
+github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v1.0.0-rc1.0.20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/image-spec v1.0.2-0.20211117181255-693428a734f5/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
+github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
+github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
+github.com/opencontainers/runc v1.1.0/go.mod h1:Tj1hFw6eFWp/o33uxGf5yF2BX5yz2Z6iptFpuvbbKqc=
+github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.3-0.20200929063507-e6143ca7d51d/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
+github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
+github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
+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/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
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/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
+github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
+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/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
+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-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
-github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
-github.com/pkg/errors v0.0.0-20170505043639-c605e284fe17/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4 h1:Qj1ukM4GlMWXNdMBuXcXfz/Kw9s1qm0CLY32QxuSImI=
+github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
-github.com/poy/onpar v0.0.0-20190519213022-ee068f8ea4d1/go.mod h1:nSbFQvMj97ZyhFRSJYtut+msi4sOY6zJDGCdSc+/rZU=
+github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
+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/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.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
-github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU=
-github.com/prometheus/client_golang v1.13.0/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.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
+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=
+github.com/prometheus/common v0.29.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
+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/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=
+github.com/prometheus/exporter-toolkit v0.7.1/go.mod h1:ZUBIj498ePooX9t/2xtDjeQYwvRpiPP2lh5u4iblj2g=
+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=
+github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
+github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
+github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
+github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
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.37.0 h1:LgnE+97wnUK/qcmk5oHIqieJEKwhZtaSidyKpUyeats=
+github.com/prometheus/prometheus v0.37.0/go.mod h1:egARUgz+K93zwqsVIAneFlLZefyGOON44WyAp4Xqbbk=
+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/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=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+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.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
+github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
+github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
+github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
-github.com/rubenv/sql-migrate v1.1.2/go.mod h1:/7TZymwxN8VWumcIxw1jjHEcR1djpdkMHQPT4FWdnbQ=
-github.com/rubyist/tracerx v0.0.0-20170927163412-787959303086/go.mod h1:YpdgDXpumPB/+EGmGTYHeiW/0QVFRzBYTNFaxWfPDk4=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8=
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/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
+github.com/scaleway/scaleway-sdk-go v1.0.0-beta.9/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=
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a h1:iLcLb5Fwwz7g/DLK89F+uQBDeAhHhwdzB5fSlVdhGcM=
github.com/sebest/xff v0.0.0-20210106013422-671bd2870b3a/go.mod h1:wozgYq9WEBQBaIJe4YZ0qTSFAMxmcwBhQH0fO0R34Z0=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
+github.com/seccomp/libseccomp-golang v0.9.2-0.20210429002308-3879420cc921/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
github.com/shabbyrobe/gocovmerge v0.0.0-20180507124511-f6ea450bfb63/go.mod h1:n+VKSARF5y/tS9XFSP7vWDfS+GUC5vs/YT7M5XDTUEM=
github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500 h1:WnNuhiq+FOY3jNj6JXFT+eLN3CQ/oPIsDPRanvwsmbI=
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/shogo82148/go-shuffle v0.0.0-20170808115208-59829097ff3b/go.mod h1:2htx6lmL0NGLHlO8ZCf+lQBGBHIbEujyywxJArf+2Yc=
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/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
+github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
+github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
@@ -869,107 +1365,201 @@ github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVs
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
+github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hgR6gDIPg=
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
+github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v0.0.0-20170901052352-ee1bd8ee15a1/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+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/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/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 v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
+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=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
-github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
-github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
-github.com/ssgelm/cookiejarparser v1.0.1/go.mod h1:DUfC0mpjIzlDN7DzKjXpHj0qMI5m9VrZuz3wSlI+OEI=
+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/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/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=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
-github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
-github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+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/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
+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=
+github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I=
+github.com/tedsuo/ifrit v0.0.0-20180802180643-bea94bb476cc/go.mod h1:eyZnKCc955uh98WQvzOm0dgAeLnf2O0Rz0LPoC5ze+0=
+github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tinylib/msgp v1.1.2 h1:gWmO7n0Ys2RBEb7GPYB9Ujq8Mk5p2U08lRnmMcGy6BQ=
github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tklauser/go-sysconf v0.3.4 h1:HT8SVixZd3IzLdfs/xlpq0jeSfTX57g1v6wB1EuzV7M=
github.com/tklauser/go-sysconf v0.3.4/go.mod h1:Cl2c8ZRWfHD5IrfHo9VN+FX9kCFjIOyVklgXycLB6ek=
github.com/tklauser/numcpus v0.2.1 h1:ct88eFm+Q7m2ZfXJdan1xYoXKlmwsfP+k88q05KvlZc=
github.com/tklauser/numcpus v0.2.1/go.mod h1:9aU+wOc6WjUIZEwWMP62PL/41d65P+iks1gBkr4QyP8=
-github.com/uber/jaeger-client-go v2.29.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
+github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
+github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
-github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
-github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
-github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w=
-github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
-github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
-github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
-github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4=
-github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
+github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
+github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
+github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
+github.com/vishvananda/netlink v1.1.1-0.20210330154013-f5de75959ad5/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
+github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmFBXmLKZu9Nxj3WKYEafiSqer2rnvPr0en9UNpI=
+github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
+github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
+github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
+github.com/vultr/govultr/v2 v2.17.2/go.mod h1:ZFOKGWmgjytfyjeyAdhQlSWwTjh2ig+X49cAp50dzXI=
+github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
+github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
+github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
+github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
+github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
-github.com/xeipuuv/gojsonschema v0.0.0-20170210233622-6b67b3fab74d/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
-github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
-github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
-github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
-github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
+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=
-github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
-gitlab.com/gitlab-org/gitaly/v15 v15.4.2 h1:evAILjEjT7M+pegcbP4QsViK4Hkt1I1IwJAr5AQjbdY=
-gitlab.com/gitlab-org/gitaly/v15 v15.4.2/go.mod h1:anANn2UwrECvFOEvLx8DkXYYDQ6g3+jmv0kP2VDYm70=
+gitlab.com/gitlab-org/gitaly/v15 v15.5.1 h1:EbkAYAeTLllJzX3N3Sy3ZcmKtBzI5OovT5c5MWI16Bo=
+gitlab.com/gitlab-org/gitaly/v15 v15.5.1/go.mod h1:G5q5H6OYMSEDnKXsQoYTzI+ysCTfM4Of2z0v6xeHtRY=
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.16.0 h1:Vm3NAMZ8RqAunXlvPWby3GJ2R35vsYGP6Uu0YjyMIlY=
-gitlab.com/gitlab-org/labkit v1.16.0/go.mod h1:bcxc4ZpAC+WyACgyKl7FcvT2XXAbl8CrzN6UY+w8cMc=
+gitlab.com/gitlab-org/labkit v1.16.1 h1:J+HmNVR5bvPfrv9/fgKICFis2nmEugRXHMeRPvsVZUg=
+gitlab.com/gitlab-org/labkit v1.16.1/go.mod h1:tzZLVHeb0/Jrm9fPFdYuCrKmrYjfjEA0NmuLPXvvM+0=
+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/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
+go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
+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=
+go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg=
+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.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=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
-go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
+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.32.0/go.mod h1:5eCOqeGphOyz6TsY3ZDNjE33SM/TFAK3RGuCL2naTgY=
+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.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
+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.7.0/go.mod h1:M1hVZHNxcbkAlcvrOMlpQ4YOO3Awf+4N2dxkZL3xm04=
+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.7.0/go.mod h1:ceUgdyfNv4h4gLxHR0WNfDiiVmZFodZhZSbOLhpxqXE=
+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.7.0/go.mod h1:E+/KKhwOSw8yoPxSSuUHG6vKppkvhN+S1Jc7Nib3k3o=
+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.7.0/go.mod h1:aFXT9Ng2seM9eizF+LfKiyPBGy8xIZKwhusC1gIu3hA=
+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.30.0/go.mod h1:/ShZ7+TS4dHzDFmfi1kSXMhMVubNoP0oIaBp70J6UXU=
+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.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU=
+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=
+go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk=
+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.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=
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=
+go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
+go.opentelemetry.io/proto/otlp v0.16.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
@@ -977,9 +1567,11 @@ go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
+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/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
-go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
+go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
@@ -991,41 +1583,42 @@ 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.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
-gocloud.dev v0.26.0 h1:4rM/SVL0lLs+rhC0Gmc+gt/82DBpb7nbpIZKXXnfMXg=
-gocloud.dev v0.26.0/go.mod h1:mkUgejbnbLotorqDyvedJO20XcZNTynmSeVSQS9btVg=
+gocloud.dev v0.27.0 h1:j0WTUsnKTxCsWO7y8T+YCiBZUmLl9w/WIowqAY3yo0g=
+gocloud.dev v0.27.0/go.mod h1:YlYKhYsY5/1JdHGWQDkAuqkezVKowu7qbe9aIeUF6p0=
+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=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
+golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+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-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/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-20201016220609-9e8e0b390897/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-20210322153248-0c34fe9e7dc2/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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/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-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-20220214200702-86341886e292/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-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-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=
@@ -1035,11 +1628,8 @@ 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-20200331195152-e8c3332aa8e5 h1:FR+oGxGfbQu1d+jglI3rCkjAjUnhRSZcUxr+DqlDLNo=
-golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
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=
@@ -1070,31 +1660,37 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
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 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
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=
+golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
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-20190310074541-c10a0554eabf/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-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -1105,36 +1701,49 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
-golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
+golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
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-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211008194852-3b03d305991f/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-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220401154927-543a649e0bdd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
+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-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-20220802222814-0bcc04d9c69b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
+golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
+golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
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=
@@ -1144,11 +1753,9 @@ golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4Iltr
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210126194326-f9ce19ea3013/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210427180440-81ed05c6b58c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
@@ -1157,13 +1764,19 @@ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ
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 h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
+golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
+golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
+golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
+golang.org/x/oauth2 v0.0.0-20220628200809-02e64fa58f26/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
+golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c h1:q3gFqPqH7NVofKo3c3yETAP//pPI+G5mvB7qqj1Y5kY=
+golang.org/x/oauth2 v0.0.0-20220722155238-128564f6959c/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
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=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1179,35 +1792,56 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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-20181205085412-a5c9d58dba9a/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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/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=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190522044717-8097e1b27ff5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190812073006-9eafafc0a87e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+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=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200120151820-655fe14d7479/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1215,28 +1849,43 @@ golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200728102440-3e129f6d46b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200817155316-9781c653f443/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200922070232-aee5d888a860/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201117170446-d9b008d0a637/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201202213521-69691e467435/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210217105451-b926d437f341/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210503080704-8803ae5d1324/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1247,31 +1896,47 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220330033206-e17cdc41300f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
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.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
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=
@@ -1281,44 +1946,58 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
-golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
+golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
+golang.org/x/text v0.4.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=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U=
golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
+golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181221001348-537d06c36207/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=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190829051458-42f498d34c4d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -1334,35 +2013,39 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200221224223-e1da425f72fd/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
+golang.org/x/tools v0.0.0-20200916195026-c9a70fc28ce3/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
-golang.org/x/tools v0.1.11-0.20220513221640-090b14e8501f/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
+golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+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.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1370,14 +2053,14 @@ golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
-gonum.org/v1/gonum v0.7.0/go.mod h1:L02bwd0sqlsvRv41G7wGWFCsVNZFv/k1xzGIxeANHGM=
-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=
+golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=
+golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
+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=
@@ -1396,11 +2079,9 @@ google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSr
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
-google.golang.org/api v0.37.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
-google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
google.golang.org/api v0.46.0/go.mod h1:ceL4oozhkAiTID8XMmJBsIxID/9wMXJVVFXPg4ylg3I=
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
@@ -1414,16 +2095,21 @@ google.golang.org/api v0.58.0/go.mod h1:cAbP2FsxoGVNwtgNAmmn3y5G1TWAiVYRmg4yku3l
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.64.0/go.mod h1:931CdxA8Rm4t6zqTFGSsgwbAEZ2+GMYurbndwSimebM=
-google.golang.org/api v0.66.0/go.mod h1:I1dmXYpX7HGwz/ejRxwQp2qj5bFAz93HiCU1C1oYd9M=
google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g=
-google.golang.org/api v0.68.0/go.mod h1:sOM8pTpwgflXRhz+oC8H2Dr+UcbMqkPPWNJo88Q7TH8=
-google.golang.org/api v0.69.0/go.mod h1:boanBiw+h5c3s+tBPgEzLDRHfFLWV0qXxRHz3ws7C80=
google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
-google.golang.org/api v0.74.0 h1:ExR2D+5TYIrMphWgs5JCgwRhEDlPDXXrLwHHMgPHTXE=
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
+google.golang.org/api v0.75.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.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
+google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g=
+google.golang.org/api v0.86.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
+google.golang.org/api v0.90.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
+google.golang.org/api v0.91.0 h1:731+JzuwaJoZXRQGmPoBiV+SrsAfUaIkdMCWTcQNPyA=
+google.golang.org/api v0.91.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
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=
@@ -1431,12 +2117,14 @@ google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk=
google.golang.org/genproto v0.0.0-20170918111702-1e559d0a00ee/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
@@ -1446,6 +2134,7 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200117163144-32f20d992d24/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
@@ -1460,21 +2149,23 @@ google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
@@ -1503,28 +2194,42 @@ google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ6
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=
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20211223182754-3ac035c7e7cb/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20220111164026-67b88f271998/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20220114231437-d2e6a121cae0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20220201184016-50beb8ab5c44/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20220204002441-d6cc3cc0770e/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
-google.golang.org/genproto v0.0.0-20220211171837-173942840c17/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
-google.golang.org/genproto v0.0.0-20220216160803-4663080d8bc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
-google.golang.org/genproto v0.0.0-20220401170504-314d38edb7de h1:9Ti5SG2U4cAcluryUo/sFay3TQKoxiFMfaT0pbizU7k=
-google.golang.org/genproto v0.0.0-20220401170504-314d38edb7de/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220329172620-7be39ac1afc7/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
+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=
+google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
+google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
+google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
+google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78 h1:QntLWYqZeuBtJkth3m/6DLznnI0AHJr+AgJXvVh/izw=
+google.golang.org/genproto v0.0.0-20220802133213-ce4fa296bf78/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=
+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=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
@@ -1547,9 +2252,14 @@ google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnD
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
+google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
+google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
-google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
+google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
+google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY=
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
@@ -1571,24 +2281,35 @@ google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175
google.golang.org/protobuf v1.28.1/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=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
+gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
-gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+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.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
-gopkg.in/neurosnap/sentences.v1 v1.0.6/go.mod h1:YlK+SN+fLQZj+kY3r8DkGDhDr91+S3JmTb5LSxFRQo0=
+gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+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/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=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -1598,11 +2319,16 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
-gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
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=
@@ -1612,8 +2338,80 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.3.3 h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA=
honnef.co/go/tools v0.3.3/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw=
-nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
+k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo=
+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.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg=
+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.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM=
+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=
+k8s.io/apiserver v0.22.5/go.mod h1:s2WbtgZAkTKt679sYtSudEQrTGWUSQAPe6MupLnlmaQ=
+k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y=
+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.24.2/go.mod h1:zg4Xaoo+umDsfCWr4fCnmLEtQXyCNXCvJuSsglNcV30=
+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=
+k8s.io/component-base v0.20.6/go.mod h1:6f1MPBAeI+mvuts3sIdtpjljHWBQ2cIy38oBIWMYnrM=
+k8s.io/component-base v0.22.5/go.mod h1:VK3I+TjuF9eaa+Ln67dKxhGar5ynVbwnGrUiNF4MqCI=
+k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM=
+k8s.io/cri-api v0.20.1/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
+k8s.io/cri-api v0.20.4/go.mod h1:2JRbKt+BFLTjtrILYVqQK5jqhI+XNdF6UiGMgczeBCI=
+k8s.io/cri-api v0.20.6/go.mod h1:ew44AjNXwyn1s0U4xCKGodU7J1HzBeZ1MpGrpa5r8Yc=
+k8s.io/cri-api v0.23.1/go.mod h1:REJE3PSU0h/LOV1APBrupxrEJqnoxZC8KWzkBUHwrK4=
+k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
+k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
+k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
+k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
+k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
+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.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/klog/v2 v2.70.0/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-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk=
+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-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+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=
+sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
+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-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=
+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=
+sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
+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/workhorse/internal/config/config.go b/workhorse/internal/config/config.go
index 3ce88f449a9..1d52a4cc934 100644
--- a/workhorse/internal/config/config.go
+++ b/workhorse/internal/config/config.go
@@ -1,17 +1,22 @@
package config
import (
+ "context"
+ "fmt"
"math"
"net/url"
+ "os"
"runtime"
"strings"
"time"
- "github.com/Azure/azure-storage-blob-go/azblob"
+ "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
"github.com/BurntSushi/toml"
- "gitlab.com/gitlab-org/labkit/log"
"gocloud.dev/blob"
"gocloud.dev/blob/azureblob"
+ "gocloud.dev/blob/gcsblob"
+ "gocloud.dev/gcp"
+ "golang.org/x/oauth2/google"
)
type TomlURL struct {
@@ -37,8 +42,9 @@ func (d *TomlDuration) UnmarshalText(text []byte) error {
type ObjectStorageCredentials struct {
Provider string
- S3Credentials S3Credentials `toml:"s3"`
- AzureCredentials AzureCredentials `toml:"azurerm"`
+ S3Credentials S3Credentials `toml:"s3"`
+ AzureCredentials AzureCredentials `toml:"azurerm"`
+ GoogleCredentials GoogleCredentials `toml:"google"`
}
type ObjectStorageConfig struct {
@@ -69,6 +75,12 @@ type AzureCredentials struct {
AccountKey string `toml:"azure_storage_access_key"`
}
+type GoogleCredentials struct {
+ ApplicationDefault bool `toml:"google_application_default"`
+ JSONKeyString string `toml:"google_json_key_string"`
+ JSONKeyLocation string `toml:"google_json_key_location"`
+}
+
type RedisConfig struct {
URL TomlURL
Sentinel []TomlURL
@@ -143,27 +155,80 @@ func (c *Config) RegisterGoCloudURLOpeners() error {
creds := c.ObjectStorageCredentials
if strings.EqualFold(creds.Provider, "AzureRM") && creds.AzureCredentials.AccountName != "" && creds.AzureCredentials.AccountKey != "" {
- accountName := azureblob.AccountName(creds.AzureCredentials.AccountName)
- accountKey := azureblob.AccountKey(creds.AzureCredentials.AccountKey)
+ urlOpener, err := creds.AzureCredentials.getURLOpener()
+ if err != nil {
+ return err
+ }
+ c.ObjectStorageConfig.URLMux.RegisterBucket(azureblob.Scheme, urlOpener)
+ }
- credential, err := azureblob.NewCredential(accountName, accountKey)
+ if strings.EqualFold(creds.Provider, "Google") && (creds.GoogleCredentials.JSONKeyLocation != "" || creds.GoogleCredentials.JSONKeyString != "" || creds.GoogleCredentials.ApplicationDefault) {
+ urlOpener, err := creds.GoogleCredentials.getURLOpener()
if err != nil {
- log.WithError(err).Error("error creating Azure credentials")
return err
}
+ c.ObjectStorageConfig.URLMux.RegisterBucket(gcsblob.Scheme, urlOpener)
+ }
- pipeline := azureblob.NewPipeline(credential, azblob.PipelineOptions{})
+ return nil
+}
+
+func (creds *AzureCredentials) getURLOpener() (*azureblob.URLOpener, error) {
+ serviceURLOptions := azureblob.ServiceURLOptions{
+ AccountName: creds.AccountName,
+ }
- azureURLOpener := &azureURLOpener{
- &azureblob.URLOpener{
- AccountName: accountName,
- Pipeline: pipeline,
- Options: azureblob.Options{Credential: credential},
- },
+ clientFunc := func(svcURL azureblob.ServiceURL) (*azblob.ServiceClient, error) {
+ sharedKeyCred, err := azblob.NewSharedKeyCredential(creds.AccountName, creds.AccountKey)
+ if err != nil {
+ return nil, fmt.Errorf("error creating Azure credentials: %w", err)
}
+ return azblob.NewServiceClientWithSharedKey(string(svcURL), sharedKeyCred, &azblob.ClientOptions{})
+ }
+
+ return &azureblob.URLOpener{
+ MakeClient: clientFunc,
+ ServiceURLOptions: serviceURLOptions,
+ }, nil
+}
- c.ObjectStorageConfig.URLMux.RegisterBucket(azureblob.Scheme, azureURLOpener)
+func (creds *GoogleCredentials) getURLOpener() (*gcsblob.URLOpener, error) {
+ ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) // lint:allow context.Background
+ defer cancel()
+
+ gcpCredentials, err := creds.getGCPCredentials(ctx)
+ if err != nil {
+ return nil, err
}
- return nil
+ client, err := gcp.NewHTTPClient(
+ gcp.DefaultTransport(),
+ gcp.CredentialsTokenSource(gcpCredentials),
+ )
+ if err != nil {
+ return nil, fmt.Errorf("error creating Google HTTP client: %w", err)
+ }
+
+ return &gcsblob.URLOpener{
+ Client: client,
+ }, nil
+}
+
+func (creds *GoogleCredentials) getGCPCredentials(ctx context.Context) (*google.Credentials, error) {
+ const gcpCredentialsScope = "https://www.googleapis.com/auth/devstorage.read_write"
+ if creds.ApplicationDefault {
+ return gcp.DefaultCredentials(ctx)
+ }
+
+ if creds.JSONKeyLocation != "" {
+ b, err := os.ReadFile(creds.JSONKeyLocation)
+ if err != nil {
+ return nil, fmt.Errorf("error reading Google json key location: %w", err)
+ }
+
+ return google.CredentialsFromJSON(ctx, b, gcpCredentialsScope)
+ }
+
+ b := []byte(creds.JSONKeyString)
+ return google.CredentialsFromJSON(ctx, b, gcpCredentialsScope)
}
diff --git a/workhorse/internal/config/config_test.go b/workhorse/internal/config/config_test.go
index 102b29a0813..e7b8462a4a7 100644
--- a/workhorse/internal/config/config_test.go
+++ b/workhorse/internal/config/config_test.go
@@ -1,6 +1,8 @@
package config
import (
+ "os"
+ "path/filepath"
"testing"
"github.com/stretchr/testify/require"
@@ -15,6 +17,34 @@ azure_storage_account_name = "azuretester"
azure_storage_access_key = "deadbeef"
`
+const googleConfigWithKeyLocation = `
+[object_storage]
+provider = "Google"
+
+[object_storage.google]
+google_json_key_location = "../../testdata/google_dummy_credentials.json"
+`
+
+const googleConfigWithKeyString = `
+[object_storage]
+provider = "Google"
+
+[object_storage.google]
+google_json_key_string = """
+{
+ "type": "service_account"
+}
+"""
+`
+
+const googleConfigWithApplicationDefault = `
+[object_storage]
+provider = "Google"
+
+[object_storage.google]
+google_application_default = true
+`
+
func TestLoadEmptyConfig(t *testing.T) {
config := ``
@@ -55,12 +85,10 @@ aws_secret_access_key = "gdk-minio"
require.Equal(t, expected, cfg.ObjectStorageCredentials)
}
-func TestRegisterGoCloudURLOpeners(t *testing.T) {
+func TestRegisterGoCloudAzureURLOpeners(t *testing.T) {
cfg, err := LoadConfig(azureConfig)
require.NoError(t, err)
- require.NotNil(t, cfg.ObjectStorageCredentials, "Expected object storage credentials")
-
expected := ObjectStorageCredentials{
Provider: "AzureRM",
AzureCredentials: AzureCredentials{
@@ -70,13 +98,68 @@ func TestRegisterGoCloudURLOpeners(t *testing.T) {
}
require.Equal(t, expected, cfg.ObjectStorageCredentials)
- require.Nil(t, cfg.ObjectStorageConfig.URLMux)
+ testRegisterGoCloudURLOpener(t, cfg, "azblob")
+}
- require.NoError(t, cfg.RegisterGoCloudURLOpeners())
- require.NotNil(t, cfg.ObjectStorageConfig.URLMux)
+func TestRegisterGoCloudGoogleURLOpenersWithJSONKeyLocation(t *testing.T) {
+ cfg, err := LoadConfig(googleConfigWithKeyLocation)
+ require.NoError(t, err)
+
+ expected := ObjectStorageCredentials{
+ Provider: "Google",
+ GoogleCredentials: GoogleCredentials{
+ JSONKeyLocation: "../../testdata/google_dummy_credentials.json",
+ },
+ }
+
+ require.Equal(t, expected, cfg.ObjectStorageCredentials)
+ testRegisterGoCloudURLOpener(t, cfg, "gs")
+}
- require.True(t, cfg.ObjectStorageConfig.URLMux.ValidBucketScheme("azblob"))
- require.Equal(t, []string{"azblob"}, cfg.ObjectStorageConfig.URLMux.BucketSchemes())
+func TestRegisterGoCloudGoogleURLOpenersWithJSONKeyString(t *testing.T) {
+ cfg, err := LoadConfig(googleConfigWithKeyString)
+ require.NoError(t, err)
+
+ expected := ObjectStorageCredentials{
+ Provider: "Google",
+ GoogleCredentials: GoogleCredentials{
+ JSONKeyString: `{
+ "type": "service_account"
+}
+`,
+ },
+ }
+
+ require.Equal(t, expected, cfg.ObjectStorageCredentials)
+ testRegisterGoCloudURLOpener(t, cfg, "gs")
+}
+
+func TestRegisterGoCloudGoogleURLOpenersWithApplicationDefault(t *testing.T) {
+ cfg, err := LoadConfig(googleConfigWithApplicationDefault)
+ require.NoError(t, err)
+
+ expected := ObjectStorageCredentials{
+ Provider: "Google",
+ GoogleCredentials: GoogleCredentials{
+ ApplicationDefault: true,
+ },
+ }
+
+ require.Equal(t, expected, cfg.ObjectStorageCredentials)
+
+ path, err := filepath.Abs("../../testdata/google_dummy_credentials.json")
+ require.NoError(t, err)
+
+ os.Setenv("GOOGLE_APPLICATION_CREDENTIALS", path)
+ defer os.Unsetenv("GOOGLE_APPLICATION_CREDENTIALS")
+
+ testRegisterGoCloudURLOpener(t, cfg, "gs")
+}
+
+func testRegisterGoCloudURLOpener(t *testing.T, cfg *Config, bucketScheme string) {
+ t.Helper()
+ require.NoError(t, cfg.RegisterGoCloudURLOpeners())
+ require.Equal(t, []string{bucketScheme}, cfg.ObjectStorageConfig.URLMux.BucketSchemes())
}
func TestLoadImageResizerConfig(t *testing.T) {
diff --git a/workhorse/internal/config/url_openers.go b/workhorse/internal/config/url_openers.go
deleted file mode 100644
index d3c96ee9eef..00000000000
--- a/workhorse/internal/config/url_openers.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package config
-
-import (
- "context"
- "fmt"
- "net/url"
-
- "gocloud.dev/blob"
- "gocloud.dev/blob/azureblob"
-)
-
-// This code can be removed once https://github.com/google/go-cloud/pull/2851 is merged.
-
-// URLOpener opens Azure URLs like "azblob://mybucket".
-//
-// The URL host is used as the bucket name.
-//
-// The following query options are supported:
-// - domain: The domain name used to access the Azure Blob storage (e.g. blob.core.windows.net)
-type azureURLOpener struct {
- *azureblob.URLOpener
-}
-
-func (o *azureURLOpener) OpenBucketURL(ctx context.Context, u *url.URL) (*blob.Bucket, error) {
- opts := new(azureblob.Options)
- *opts = o.Options
-
- err := setOptionsFromURLParams(u.Query(), opts)
- if err != nil {
- return nil, err
- }
- return azureblob.OpenBucket(ctx, o.Pipeline, o.AccountName, u.Host, opts)
-}
-
-func setOptionsFromURLParams(q url.Values, opts *azureblob.Options) error {
- for param, values := range q {
- if len(values) > 1 {
- return fmt.Errorf("multiple values of %v not allowed", param)
- }
-
- value := values[0]
- switch param {
- case "domain":
- opts.StorageDomain = azureblob.StorageDomain(value)
- default:
- return fmt.Errorf("unknown query parameter %q", param)
- }
- }
-
- return nil
-}
diff --git a/workhorse/internal/config/url_openers_test.go b/workhorse/internal/config/url_openers_test.go
deleted file mode 100644
index 6a851cacbb8..00000000000
--- a/workhorse/internal/config/url_openers_test.go
+++ /dev/null
@@ -1,117 +0,0 @@
-package config
-
-import (
- "context"
- "net/url"
- "testing"
-
- "github.com/stretchr/testify/require"
- "gocloud.dev/blob/azureblob"
-)
-
-func TestURLOpeners(t *testing.T) {
- cfg, err := LoadConfig(azureConfig)
- require.NoError(t, err)
-
- require.NotNil(t, cfg.ObjectStorageCredentials, "Expected object storage credentials")
-
- require.NoError(t, cfg.RegisterGoCloudURLOpeners())
- require.NotNil(t, cfg.ObjectStorageConfig.URLMux)
-
- tests := []struct {
- url string
- valid bool
- }{
-
- {
- url: "azblob://container/object",
- valid: true,
- },
- {
- url: "azblob://container/object?domain=core.windows.net",
- valid: true,
- },
- {
- url: "azblob://container/object?domain=core.windows.net&domain=test",
- valid: false,
- },
- {
- url: "azblob://container/object?param=value",
- valid: false,
- },
- {
- url: "s3://bucket/object",
- valid: false,
- },
- }
-
- for _, test := range tests {
- t.Run(test.url, func(t *testing.T) {
- ctx := context.Background()
- url, err := url.Parse(test.url)
- require.NoError(t, err)
-
- bucket, err := cfg.ObjectStorageConfig.URLMux.OpenBucketURL(ctx, url)
- if bucket != nil {
- defer bucket.Close()
- }
-
- if test.valid {
- require.NotNil(t, bucket)
- require.NoError(t, err)
- } else {
- require.Error(t, err)
- }
- })
- }
-}
-
-func TestTestURLOpenersForParams(t *testing.T) {
- tests := []struct {
- name string
- currOpts azureblob.Options
- query url.Values
- wantOpts azureblob.Options
- wantErr bool
- }{
- {
- name: "InvalidParam",
- query: url.Values{
- "foo": {"bar"},
- },
- wantErr: true,
- },
- {
- name: "StorageDomain",
- query: url.Values{
- "domain": {"blob.core.usgovcloudapi.net"},
- },
- wantOpts: azureblob.Options{StorageDomain: "blob.core.usgovcloudapi.net"},
- },
- {
- name: "duplicate StorageDomain",
- query: url.Values{
- "domain": {"blob.core.usgovcloudapi.net", "blob.core.windows.net"},
- },
- wantErr: true,
- },
- }
-
- for _, test := range tests {
- t.Run(test.name, func(t *testing.T) {
- o := &azureURLOpener{
- URLOpener: &azureblob.URLOpener{
- Options: test.currOpts,
- },
- }
- err := setOptionsFromURLParams(test.query, &o.Options)
-
- if test.wantErr {
- require.NotNil(t, err)
- } else {
- require.Nil(t, err)
- require.Equal(t, test.wantOpts, o.Options)
- }
- })
- }
-}
diff --git a/workhorse/internal/upload/artifacts_store_test.go b/workhorse/internal/upload/artifacts_store_test.go
index edba13d38ae..4ebf4c86180 100644
--- a/workhorse/internal/upload/artifacts_store_test.go
+++ b/workhorse/internal/upload/artifacts_store_test.go
@@ -226,7 +226,7 @@ func TestUploadHandlerSendingToExternalStorageAndSupportRequestTimeout(t *testin
RemoteObject: api.RemoteObject{
StoreURL: storeServer.URL + "/url/put",
ID: "store-id",
- Timeout: 0.001,
+ Timeout: 0.1,
},
}
diff --git a/workhorse/internal/upload/destination/objectstore/gocloud_object.go b/workhorse/internal/upload/destination/objectstore/gocloud_object.go
index 38545086994..2c7282e8e96 100644
--- a/workhorse/internal/upload/destination/objectstore/gocloud_object.go
+++ b/workhorse/internal/upload/destination/objectstore/gocloud_object.go
@@ -42,10 +42,15 @@ func NewGoCloudObject(p *GoCloudObjectParams) (*GoCloudObject, error) {
return o, nil
}
+const ChunkSize = 5 * 1024 * 1024
+
func (o *GoCloudObject) Upload(ctx context.Context, r io.Reader) error {
defer o.bucket.Close()
- writer, err := o.bucket.NewWriter(ctx, o.objectName, nil)
+ writerOptions := &blob.WriterOptions{
+ BufferSize: ChunkSize,
+ }
+ writer, err := o.bucket.NewWriter(ctx, o.objectName, writerOptions)
if err != nil {
log.ContextLogger(ctx).WithError(err).Error("error creating GoCloud bucket")
return err
diff --git a/workhorse/internal/upstream/routes.go b/workhorse/internal/upstream/routes.go
index 08e3ef8c9f1..c47053ad682 100644
--- a/workhorse/internal/upstream/routes.go
+++ b/workhorse/internal/upstream/routes.go
@@ -52,6 +52,7 @@ const (
geoGitProjectPattern = `^/[^-].+\.git/` // Prevent matching routes like /-/push_from_secondary
projectPattern = `^/([^/]+/){1,}[^/]+/`
apiProjectPattern = apiPattern + `v4/projects/[^/]+` // API: Projects can be encoded via group%2Fsubgroup%2Fproject
+ apiGroupPattern = apiPattern + `v4/groups/[^/]+`
apiTopicPattern = apiPattern + `v4/topics`
snippetUploadPattern = `^/uploads/personal_snippet`
userUploadPattern = `^/uploads/user`
@@ -303,6 +304,7 @@ func configureRoutes(u *upstream) {
// we need to declare each routes until we have fixed all the routes on the rails codebase.
// Overall status can be seen at https://gitlab.com/groups/gitlab-org/-/epics/1802#current-status
u.route("POST", apiProjectPattern+`/wikis/attachments\z`, tempfileMultipartProxy),
+ u.route("POST", apiGroupPattern+`/wikis/attachments\z`, tempfileMultipartProxy),
u.route("POST", apiPattern+`graphql\z`, tempfileMultipartProxy),
u.route("POST", apiTopicPattern, tempfileMultipartProxy),
u.route("PUT", apiTopicPattern, tempfileMultipartProxy),
diff --git a/workhorse/testdata/google_dummy_credentials.json b/workhorse/testdata/google_dummy_credentials.json
new file mode 100644
index 00000000000..b92a792f27f
--- /dev/null
+++ b/workhorse/testdata/google_dummy_credentials.json
@@ -0,0 +1,12 @@
+{
+ "type": "service_account",
+ "project_id": "test",
+ "private_key_id": "test",
+ "private_key": "-----BEGIN PRIVATE KEY-----\ntest\n-----END PRIVATE KEY-----\n",
+ "client_email": "test@test.iam.gserviceaccount.com",
+ "client_id": "1234567890",
+ "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/test.iam.gserviceaccount.com"
+} \ No newline at end of file
diff --git a/workhorse/upload_test.go b/workhorse/upload_test.go
index c7e5888cec9..22abed25928 100644
--- a/workhorse/upload_test.go
+++ b/workhorse/upload_test.go
@@ -138,6 +138,8 @@ func TestAcceleratedUpload(t *testing.T) {
{"POST", `/api/v4/groups`, false},
{"PUT", `/api/v4/groups/5`, false},
{"PUT", `/api/v4/groups/group%2Fsubgroup`, false},
+ {"POST", `/api/v4/groups/1/wikis/attachments`, false},
+ {"POST", `/api/v4/groups/my%2Fsubgroup/wikis/attachments`, false},
{"POST", `/api/v4/users`, false},
{"PUT", `/api/v4/users/42`, false},
{"PUT", "/api/v4/projects/9001/packages/nuget/v1/files", true},
diff --git a/yarn.lock b/yarn.lock
index 1d8029ca500..1a2f200dd15 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -20,6 +20,48 @@
dependencies:
"@jridgewell/trace-mapping" "^0.3.0"
+"@apidevtools/json-schema-ref-parser@9.0.6":
+ version "9.0.6"
+ resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.6.tgz#5d9000a3ac1fd25404da886da6b266adcd99cf1c"
+ integrity sha512-M3YgsLjI0lZxvrpeGVk9Ap032W6TPQkH6pRAZz81Ac3WUNF79VQooAFnp8umjvVzUmD93NkogxEwbSce7qMsUg==
+ dependencies:
+ "@jsdevtools/ono" "^7.1.3"
+ call-me-maybe "^1.0.1"
+ js-yaml "^3.13.1"
+
+"@apidevtools/openapi-schemas@^2.1.0":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz#9fa08017fb59d80538812f03fc7cac5992caaa17"
+ integrity sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ==
+
+"@apidevtools/swagger-cli@4.0.4":
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/@apidevtools/swagger-cli/-/swagger-cli-4.0.4.tgz#c645c291f56e4add583111aca9edeee23d60fa10"
+ integrity sha512-hdDT3B6GLVovCsRZYDi3+wMcB1HfetTU20l2DC8zD3iFRNMC6QNAZG5fo/6PYeHWBEv7ri4MvnlKodhNB0nt7g==
+ dependencies:
+ "@apidevtools/swagger-parser" "^10.0.1"
+ chalk "^4.1.0"
+ js-yaml "^3.14.0"
+ yargs "^15.4.1"
+
+"@apidevtools/swagger-methods@^3.0.2":
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz#b789a362e055b0340d04712eafe7027ddc1ac267"
+ integrity sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==
+
+"@apidevtools/swagger-parser@^10.0.1":
+ version "10.1.0"
+ resolved "https://registry.yarnpkg.com/@apidevtools/swagger-parser/-/swagger-parser-10.1.0.tgz#a987d71e5be61feb623203be0c96e5985b192ab6"
+ integrity sha512-9Kt7EuS/7WbMAUv2gSziqjvxwDbFSg3Xeyfuj5laUODX8o/k/CpsAKiQ8W7/R88eXFTMbJYg6+7uAmOWNKmwnw==
+ dependencies:
+ "@apidevtools/json-schema-ref-parser" "9.0.6"
+ "@apidevtools/openapi-schemas" "^2.1.0"
+ "@apidevtools/swagger-methods" "^3.0.2"
+ "@jsdevtools/ono" "^7.1.3"
+ ajv "^8.6.3"
+ ajv-draft-04 "^1.0.0"
+ call-me-maybe "^1.0.1"
+
"@apollo/client@^3.5.10":
version "3.5.10"
resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.5.10.tgz#43463108a6e07ae602cca0afc420805a19339a71"
@@ -1066,19 +1108,19 @@
stylelint-declaration-strict-value "1.8.0"
stylelint-scss "4.2.0"
-"@gitlab/svgs@3.5.0":
- version "3.5.0"
- resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.5.0.tgz#226240b7aa93db986f4c6f7738ca2a1846b5234d"
- integrity sha512-/djPsJzUY7i/FaydRVt3ZyXiFf5HGNo1rg2mfLn1EpXvT4zc2ag5ECwnYcPb97KgqFCJX6Tk+Ndu8Wh3GoOW1g==
+"@gitlab/svgs@3.8.0":
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.8.0.tgz#bc7fa51e345e26cff56fdff629ea439adfa1e0cb"
+ integrity sha512-DUWeG2Vx+1ntZ/1GT6S36ZOtXvM5Wm02MtDRrQS4GuOX4rkTeG9aoutSJuwQ2h9BNtxl0U/jkf5GVBxacj18XA==
-"@gitlab/ui@46.1.0":
- version "46.1.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-46.1.0.tgz#df5918dfcf76ee444ad587f325d55555e8001de7"
- integrity sha512-11zdly3bDWRqlbPo5kmhoDzcJ0n16kuhuxk2U4N8TMfHXgu6vUYp5NgjPrxzZRHlNVXsYiz7cAqifbr56fxTPg==
+"@gitlab/ui@49.10.0":
+ version "49.10.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-49.10.0.tgz#54715c18d3e06f313b572c5b9b807622f7a35b19"
+ integrity sha512-hBkU5TIdc2bzqe4P2X/BZXgQQQa+Sp4A5eWiKK+FVuCx5l1To2q4EyHHPMn292AJx7Y23qM2jP4GMphbs2wtDg==
dependencies:
"@popperjs/core" "^2.11.2"
bootstrap-vue "2.20.1"
- dompurify "^2.4.0"
+ dompurify "^2.4.1"
echarts "^5.3.2"
iframe-resizer "^4.3.2"
lodash "^4.17.20"
@@ -1090,12 +1132,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/visual-review-tools/-/visual-review-tools-1.7.3.tgz#9ea641146436da388ffbad25d7f2abe0df52c235"
integrity sha512-NMV++7Ew1FSBDN1xiZaauU9tfeSfgDHcOLpn+8bGpP+O5orUPm2Eu66R5eC5gkjBPaXosNAxNWtriee+aFk4+g==
-"@gitlab/web-ide@0.0.1-dev-20220815034418":
- version "0.0.1-dev-20220815034418"
- resolved "https://registry.yarnpkg.com/@gitlab/web-ide/-/web-ide-0.0.1-dev-20220815034418.tgz#c4c4f72d6ffe1ba18fdfc452b30d10ff7cde0550"
- integrity sha512-cYTMAXfc+B549euU+IDHgFK0Rjwa5SNjs4coBJOD4eoZVvPd3YtHbArqqzmdO71SYjCqV1Bl4v0Jy4UnOJgcjQ==
- dependencies:
- mustache "^4.2.0"
+"@gitlab/web-ide@0.0.1-dev-20221114183058":
+ version "0.0.1-dev-20221114183058"
+ resolved "https://registry.yarnpkg.com/@gitlab/web-ide/-/web-ide-0.0.1-dev-20221114183058.tgz#0b6e38900cf6986027919a6f7dd2166a7d9016e7"
+ integrity sha512-M+IfbTGVPBtOfJrEkoNHEomhPoDrFFkuPFIHC1X5G0ixbXdep4UPX3jIAT/3TrOM331nrcZKX7fDMw6wn9jQnw==
"@graphql-eslint/eslint-plugin@3.12.0":
version "3.12.0"
@@ -1270,10 +1310,10 @@
resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.0.tgz#0eee6373e11418bfe0b5638f654df7a4ca6a3950"
integrity sha512-wYn6r8zVZyQJ6rQaALBEln5B1pzxb9shV5Ef97kTvn6yVGrqyXVnDqnU24MXnFubR+rZjBY9NWuxX3FB2sTsjg==
-"@humanwhocodes/config-array@^0.10.5":
- version "0.10.5"
- resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.10.5.tgz#bb679745224745fff1e9a41961c1d45a49f81c04"
- integrity sha512-XVVDtp+dVvRxMoxSiSfasYaG02VEe1qH5cKgMQJWhol6HwzbcqoCMJi8dAGoYAO57jhUyhI6cWuRiTcRaDaYug==
+"@humanwhocodes/config-array@^0.11.6":
+ version "0.11.6"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.6.tgz#6a51d603a3aaf8d4cf45b42b3f2ac9318a4adc4b"
+ integrity sha512-jJr+hPTJYKyDILJfhNSHsjiwXYf26Flsz8DvNndOsHs5pwSnpGUEy8yzF0JYhCEvTDdV2vuOK5tt8BVhwO5/hg==
dependencies:
"@humanwhocodes/object-schema" "^1.2.1"
debug "^4.1.1"
@@ -1522,6 +1562,11 @@
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
+"@jsdevtools/ono@^7.1.3":
+ version "7.1.3"
+ resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796"
+ integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==
+
"@leichtgewicht/ip-codec@^2.0.1":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.3.tgz#0300943770e04231041a51bd39f0439b5c7ab4f0"
@@ -1550,7 +1595,7 @@
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
-"@nodelib/fs.walk@^1.2.3":
+"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8":
version "1.2.8"
resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
@@ -1660,10 +1705,10 @@
dependencies:
"@sinonjs/commons" "^1.7.0"
-"@sourcegraph/code-host-integration@0.0.60":
- version "0.0.60"
- resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.60.tgz#2043877fabb7eb986fcb61b67ee480afbb29f4f0"
- integrity sha512-T+MvM8SUF7daA279hyQgwmva3J5LvPqwgQ/mWwxdVshehOQIPLUd310I0c6x6nZ0F/x4UjDWgRWzAqy6NLwV1w==
+"@sourcegraph/code-host-integration@0.0.84":
+ version "0.0.84"
+ resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.84.tgz#680f5eadde4d05c1dfccb32e14b0a7e58365ebad"
+ integrity sha512-xHaplY49vBHeXggcc0K3LNQ0VebKy3BwCSokXGxqHDaRJ8JmUwp/DyZX1RFp0Rx/UR6OPXQXKyfVqFcz/UlkUw==
"@testing-library/dom@^7.16.2":
version "7.24.5"
@@ -1776,6 +1821,11 @@
resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.0.0-beta.29.tgz#d017d216c0fd1962c266f6f61a335093f9749862"
integrity sha512-q92jYcsT5bPhvuQaB0h44Z9r+Ii22tDYo082KMVnR4+tknHT/3xx+p4JC8KHjh+/5W8Quyafqy6mS8L8VX0zsQ==
+"@tiptap/extension-highlight@^2.0.0-beta.35":
+ version "2.0.0-beta.199"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.0.0-beta.199.tgz#e814555b2bf45dd578f5255f1460b867eb395e57"
+ integrity sha512-tMRL2VTBK99q3UKf+uyM/t5LZJU1ZNHADo3drMYA6BXETjx5WzCBe0qyExZtUGMsWv5bop+Her82r5CKSxFqnQ==
+
"@tiptap/extension-history@^2.0.0-beta.25":
version "2.0.0-beta.25"
resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.0.0-beta.25.tgz#756d8e82e8873278e567b460c67445f71563b797"
@@ -2598,6 +2648,11 @@ aggregate-error@^3.0.0:
clean-stack "^2.0.0"
indent-string "^4.0.0"
+ajv-draft-04@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz#3b64761b268ba0b9e668f0b41ba53fce0ad77fc8"
+ integrity sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==
+
ajv-errors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.0.tgz#ecf021fa108fd17dfb5e6b383f2dd233e31ffc59"
@@ -2632,10 +2687,10 @@ ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.4, ajv@^6.12.5:
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
-ajv@^8.0.0, ajv@^8.0.1, ajv@^8.10.0, ajv@^8.8.0:
- version "8.10.0"
- resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.10.0.tgz#e573f719bd3af069017e3b66538ab968d040e54d"
- integrity sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==
+ajv@^8.0.0, ajv@^8.0.1, ajv@^8.10.0, ajv@^8.6.3, ajv@^8.8.0:
+ version "8.11.0"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f"
+ integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==
dependencies:
fast-deep-equal "^3.1.1"
json-schema-traverse "^1.0.0"
@@ -3336,6 +3391,11 @@ call-bind@^1.0.0, call-bind@^1.0.2:
function-bind "^1.1.1"
get-intrinsic "^1.0.2"
+call-me-maybe@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
+ integrity sha512-wCyFsDQkKPwwF8BDwOiWNx/9K45L/hvggQiDbve+viMNMQnWhrlYIuBk09offfwCRtCO9P6XwUttufzU11WCVw==
+
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
@@ -3350,7 +3410,7 @@ camelcase-keys@^6.2.2:
map-obj "^4.0.0"
quick-lru "^4.0.1"
-camelcase@^5.2.0, camelcase@^5.3.1:
+camelcase@^5.0.0, camelcase@^5.2.0, camelcase@^5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
@@ -3521,6 +3581,15 @@ clipboard@^2.0.8:
select "^1.1.2"
tiny-emitter "^2.0.0"
+cliui@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1"
+ integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.0"
+ wrap-ansi "^6.2.0"
+
cliui@^7.0.2:
version "7.0.4"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
@@ -3837,10 +3906,10 @@ core-js-pure@^3.0.0:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813"
integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==
-core-js@^3.25.5:
- version "3.25.5"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.25.5.tgz#e86f651a2ca8a0237a5f064c2fe56cef89646e27"
- integrity sha512-nbm6eZSjm+ZuBQxCUPQKQCoUEfFOXjUZ8dTTyikyKaWrTYmAVbykQfwsKE5dBK88u3QCkCrzsx/PPlKfhsvgpw==
+core-js@^3.26.1:
+ version "3.26.1"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.26.1.tgz#7a9816dabd9ee846c1c0fe0e8fcad68f3709134e"
+ integrity sha512-21491RRQVzUn0GGM9Z1Jrpr6PNPxPi+Za8OM9q4tksTSnlbXXGKK1nXNg/QvwFYettXvSX6zWKCtHHfjN4puyA==
core-util-is@~1.0.0:
version "1.0.3"
@@ -4923,10 +4992,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.0:
- version "2.4.0"
- resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.0.tgz#c9c88390f024c2823332615c9e20a453cf3825dd"
- integrity sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA==
+dompurify@^2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.4.1.tgz#f9cb1a275fde9af6f2d0a2644ef648dd6847b631"
+ integrity sha512-ewwFzHzrrneRjxzmK6oVz/rZn9VWspGFRDb4/rRtIsM1n36t9AKma/ye8syCpcw+XJ25kOK/hOG7t1j2I2yBqA==
domutils@^2.5.2, domutils@^2.6.0:
version "2.6.0"
@@ -5504,14 +5573,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.25.0:
- version "8.25.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.25.0.tgz#00eb962f50962165d0c4ee3327708315eaa8058b"
- integrity sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==
+eslint@8.26.0:
+ version "8.26.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.26.0.tgz#2bcc8836e6c424c4ac26a5674a70d44d84f2181d"
+ integrity sha512-kzJkpaw1Bfwheq4VXUezFriD1GxszX6dUekM7Z3aC2o4hju+tsR/XyTC3RcoSD7jmy9VkPU3+N6YjVU2e96Oyg==
dependencies:
"@eslint/eslintrc" "^1.3.3"
- "@humanwhocodes/config-array" "^0.10.5"
+ "@humanwhocodes/config-array" "^0.11.6"
"@humanwhocodes/module-importer" "^1.0.1"
+ "@nodelib/fs.walk" "^1.2.8"
ajv "^6.10.0"
chalk "^4.0.0"
cross-spawn "^7.0.2"
@@ -5527,14 +5597,14 @@ eslint@8.25.0:
fast-deep-equal "^3.1.3"
file-entry-cache "^6.0.1"
find-up "^5.0.0"
- glob-parent "^6.0.1"
+ glob-parent "^6.0.2"
globals "^13.15.0"
- globby "^11.1.0"
grapheme-splitter "^1.0.4"
ignore "^5.2.0"
import-fresh "^3.0.0"
imurmurhash "^0.1.4"
is-glob "^4.0.0"
+ is-path-inside "^3.0.3"
js-sdsl "^4.1.4"
js-yaml "^4.1.0"
json-stable-stringify-without-jsonify "^1.0.1"
@@ -6092,7 +6162,7 @@ gensync@^1.0.0-beta.2:
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
-get-caller-file@^2.0.5:
+get-caller-file@^2.0.1, get-caller-file@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
@@ -6171,7 +6241,7 @@ glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@~5.1.2:
dependencies:
is-glob "^4.0.1"
-glob-parent@^6.0.1:
+glob-parent@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
@@ -7051,6 +7121,11 @@ is-number@^7.0.0:
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+is-path-inside@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+ integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
+
is-plain-obj@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
@@ -7491,11 +7566,6 @@ jest-pnp-resolver@^1.2.2:
resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c"
integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==
-jest-raw-loader@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/jest-raw-loader/-/jest-raw-loader-1.0.1.tgz#ce9f56d54650f157c4a7d16d224ba5d613bcd626"
- integrity sha1-zp9W1UZQ8VfEp9FtIkul1hO81iY=
-
jest-regex-util@^27.5.1:
version "27.5.1"
resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95"
@@ -7713,7 +7783,7 @@ js-sdsl@^4.1.4:
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
-js-yaml@^3.13.1:
+js-yaml@^3.13.1, js-yaml@^3.14.0:
version "3.14.1"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
@@ -9140,11 +9210,6 @@ multicast-dns@^7.2.4:
dns-packet "^5.2.2"
thunky "^1.0.2"
-mustache@^4.2.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64"
- integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==
-
nanoid@^3.3.4:
version "3.3.4"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
@@ -10491,6 +10556,11 @@ require-from-string@^2.0.2:
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
+require-main-filename@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
+ integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
+
require-package-name@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9"
@@ -10825,6 +10895,11 @@ serve-static@1.14.2:
parseurl "~1.3.3"
send "0.17.2"
+set-blocking@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
+ integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==
+
set-value@^2.0.0, set-value@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
@@ -11418,6 +11493,13 @@ svg-tags@^1.0.0:
resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=
+swagger-cli@^4.0.4:
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/swagger-cli/-/swagger-cli-4.0.4.tgz#c3f0b94277073c776b9bcc3ae7507b372f3ff414"
+ integrity sha512-Cp8YYuLny3RJFQ4CvOBTaqmOOgYsem52dPx1xM5S4EUWFblIh2Q8atppMZvXKUr1e9xH5RwipYpmdUzdPcxWcA==
+ dependencies:
+ "@apidevtools/swagger-cli" "4.0.4"
+
swagger-ui-dist@4.12.0:
version "4.12.0"
resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-4.12.0.tgz#986d90f05e81fb9db3ca40372278a5d8ce71db3a"
@@ -12570,6 +12652,11 @@ which-boxed-primitive@^1.0.2:
is-string "^1.0.5"
is-symbol "^1.0.3"
+which-module@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
+ integrity sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==
+
which@^1.2.9, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
@@ -12609,6 +12696,15 @@ worker-loader@^2.0.0:
loader-utils "^1.0.0"
schema-utils "^0.4.0"
+wrap-ansi@^6.2.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
+ integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
wrap-ansi@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
@@ -12724,11 +12820,36 @@ yaml@^2.0.0, yaml@^2.0.0-10:
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.1.tgz#1e06fb4ca46e60d9da07e4f786ea370ed3c3cfec"
integrity sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw==
+yargs-parser@^18.1.2:
+ version "18.1.3"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0"
+ integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==
+ dependencies:
+ camelcase "^5.0.0"
+ decamelize "^1.2.0"
+
yargs-parser@^20.2.2, yargs-parser@^20.2.3:
version "20.2.9"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
+yargs@^15.4.1:
+ version "15.4.1"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8"
+ integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==
+ dependencies:
+ cliui "^6.0.0"
+ decamelize "^1.2.0"
+ find-up "^4.1.0"
+ get-caller-file "^2.0.1"
+ require-directory "^2.1.1"
+ require-main-filename "^2.0.0"
+ set-blocking "^2.0.0"
+ string-width "^4.2.0"
+ which-module "^2.0.0"
+ y18n "^4.0.0"
+ yargs-parser "^18.1.2"
+
yargs@^16.2.0:
version "16.2.0"
resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"